diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34977ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +.idea \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..18f48b1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +sudo: false +language: node_js +node_js: + - "node" +install: npm install +script: + - npm test + - gulp +cache: + directories: + - node_modules diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..c37e7f3 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,93 @@ +AUTHORS +------- + +There have been many authors who have contributed to SIS, and it is +difficult to compile a complete and accurate list of everyone. I am +fairly sure the list below is incomplete. If you know anyone missing from +this list or think changes need to be made, please send more information. + +Wendell Baker + sis/{bdd_ucb,ntbdd} +Robert K. Brayton + Professor +Andrea Casotto + sis/octio +Abhijit Ghosh + sis/power +Paul Gutwin + sis/delay +Heather Harkness + sis/speed +David Harrison + port, sis/{list,util} +Jonathan I. Kamens + sis/util +Kenneth S. Kundert + sis/linsolv +Tom Laidig + options +Luciano Lavagno + sis/pld +Bill Lin + jedi +David E. Long + sis/bdd_cmu +Hi-Keung Tony Ma + sis/{maxflow,stg} +Abdul A. Malik + sis/minimize +Sharad Malik + sis/order +Patrick McGeer + sis/speed +Jose' Monteiro + sis/power +Cho Moon + sis/{genlib,map} +Rajeev Murgai + sis/pld +A. Richard Newton + Professor +Antony P.-C. Ng + sis/seqbdd +Yoshihito Nishizaki + sis/pld +Roberto Rambaldi + blif2vst, vst2blif +June Rho + stamina +Richard Rudell + espresso, sis/{genlib,lsort,util}, utility +Alexander Saldanha + sis/enc +Alberto Sangiovanni-Vincentelli + Professor +Hamid Savoj + sis/sis_lib/help/sis.1 +Ellen M. Sentovich + sis/util +Narendra Shenoy + sis/{pld,timing} +Thomas R. Shiple + sis/{bdd_cmu,bdd_ucb,ntbdd,order,var_set} +Kanwar Jit Singh + sis/{maxflow,octio,speed} +Henry Spencer + espresso/getopt.c, sis/util/getopt.c +Rick L. Spickelmier + sis/util +Paul R. Stephan + sis/atpg, xsis +Colin Stevens + sis/sis_lib/help/sis.1 +Gitanjali M. Swamy + sis/bdd_cmu +Herve' Touati + sis/{bdd_ucb,map,ntbdd,order,retime,seqbdd,var_set} +Tiziano Villa + nova, sred +Huey-Yih Wang + sis/extract +Carol Wawrukiewicz + sis/sis_lib/help/sis.1 + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..f57b80e --- /dev/null +++ b/COPYING @@ -0,0 +1,36 @@ +Copyright (c) 1994-2005 The Regents of the University of California. +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research and non-profit purposes, +without fee, and without a written agreement is hereby granted, +provided that the above copyright notice, this paragraph and the +following three paragraphs appear in all copies. + +Permission to incorporate this software into commercial products may +be obtained by contacting the University of California. + Brian Donohue + Contracts Administrator + 6701 San Pablo Avenue #218 + Berkeley, CA 94720-5600 + (510) 642-3128 + donohue@uclink.berkeley.edu + +This software program and documentation are copyrighted by The Regents +of the University of California. The software program and +documentation are supplied "as is", without any accompanying services +from The Regents. The Regents does not warrant that the operation of +the program will be uninterrupted or error-free. The end-user +understands that the program was developed for research purposes and +is advised not to rely exclusively on the program for any reason. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND +ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF +CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" +BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..52d9dd4 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,28 @@ +ChangeLog +--------- + +2005-03-18 Release 1.3.6 +2005-03-08 Added proper but still incomplete AUTHORS list +2005-03-07 Added support for CUDD 2.4.0 +2005-03-07 Fixed configure to do subdirs correctly +2005-03-07 Some compile warnings cleaned up + +2004-05-05 Release 1.3.5 +2004-05-05 Added sis_lib/.misrc (Ken McMillan/Ellen Sentovich) +2004-05-05 Fixed bug in eliminate (Ken McMillan/Ellen Sentovich) + +2004-03-27 Release 1.3.4 +2004-03-27 Fixed for Cygwin + +2004-03-16 Release 1.3.3 +2004-03-16 Fixed fclose of null FILE * in power +2004-03-11 Now uses autoconf/automake + +2004-02-18 Release 1.3.2 +2004-02-18 Mac OSX compilation fixes + +2004-02-11 Release 1.3.1 +2004-02-11 Copyright notice added +2004-02-09 Fixes to ease compilation + +2004-02-08 Release 1.3 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..77afa5b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2018 Blackrock Digital LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..cb236e5 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = doc port utility options blif2vst vst2blif espresso sis \ + jedi nova sred stamina xsis + +dist_pkgdata_DATA = AUTHORS COPYING README diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..363db1e --- /dev/null +++ b/Makefile.in @@ -0,0 +1,593 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = . +DIST_COMMON = README $(am__configure_deps) $(dist_pkgdata_DATA) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/config.h.in $(top_srcdir)/configure AUTHORS COPYING \ + ChangeLog install-sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno configure.status.lineno +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +am__installdirs = "$(DESTDIR)$(pkgdatadir)" +dist_pkgdataDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_pkgdata_DATA) +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +SUBDIRS = doc port utility options blif2vst vst2blif espresso sis \ + jedi nova sred stamina xsis + +dist_pkgdata_DATA = AUTHORS COPYING README +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps'; \ + cd $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: $(am__configure_deps) + cd $(top_srcdir) && $(AUTOHEADER) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +uninstall-info-am: +install-dist_pkgdataDATA: $(dist_pkgdata_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgdatadir)" || $(mkdir_p) "$(DESTDIR)$(pkgdatadir)" + @list='$(dist_pkgdata_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_pkgdataDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgdatadir)/$$f'"; \ + $(dist_pkgdataDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgdatadir)/$$f"; \ + done + +uninstall-dist_pkgdataDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgdata_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgdatadir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgdatadir)/$$f"; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || mkdir "$(distdir)/$$subdir" \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="../$(top_distdir)" \ + distdir="../$(distdir)/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + $(AMTAR) chof - $(distdir) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + $(AMTAR) chof - $(distdir) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(AMTAR) xf - ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(AMTAR) xf - ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(pkgdatadir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-dist_pkgdataDATA + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-dist_pkgdataDATA uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \ + check-am clean clean-generic clean-recursive ctags \ + ctags-recursive dist dist-all dist-bzip2 dist-gzip dist-shar \ + dist-tarZ dist-zip distcheck distclean distclean-generic \ + distclean-hdr distclean-recursive distclean-tags \ + distcleancheck distdir distuninstallcheck dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_pkgdataDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-generic \ + mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-dist_pkgdataDATA \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/README b/README new file mode 100644 index 0000000..c641868 --- /dev/null +++ b/README @@ -0,0 +1,110 @@ +README +------ + +This is SIS 1.3, an unofficial release of SIS, the logic synthesis system +from UC Berkeley. SIS is no longer supported, but there are still many +people still interested in this software, hence this release. + +If you have not already done so, please have a look at MVSIS, a successor +to SIS, at: + http://www-cad.eecs.berkeley.edu/Respep/Research/mvsis/ + +While MVSIS does not have all the functionality of SIS at this time, +it is both actively maintained and continually growing, and is very +suitable for research and development of core synthesis algorithms. + +The primary features added on top of SIS 1.2 are: + - a configure system based on autoconf, making building and installing + the software simpler + - various patches to allow compilation under Linux (glibc 2.2/2.3) + - Automated integration of CUDD when available + + +Systems/Portability +------------------- + +Testing is extremely limited due to lack of resources, but various +versions of SIS 1.3 have been successfully built on: + - Linux Intel x86 (Redhat 8.0/9.0, Debian 3.0, glibc 2.2/2.3) + - Mac OSX + - Windows (NT with Cygwin) + +Some other platforms should be okay with little or no modifications. +However, SIS is old software, and may not build or run correctly on +modern systems. If you have patches to get things to build on other +platforms, or can help in the porting process (either by providing +debugging help, or providing access to a suitable machine), this would +be greatly appreciated. + + +Requirements +------------ + +You will need the following software to build SIS. Tested versions +are indicated in parentheses. Other versions may or may not work. + - GNU gcc (3.2.2) + - GNU make (3.79.1) + + +Build/Installation +------------------ + +Make sure your current working directory is the one which contains +this README file and the configure script, and type: + ./configure --prefix= + make + make install + +The target install directory will be created if it does not already exist. +You should specify a location where you have write access for the install +directory. The source directories can be deleted after the install, +if desired. For this reason, it is recommended to make the install +directory a different directory than where the sources are located. + +You can still run the executables from the build directories without +doing a "make install", but some minor things will not work correctly +(e.g. the "help" command). + +By default, debugging symbols in the binaries and libraries are not +removed. If you would like to remove debugging symbols for faster/smaller +executables, instead of "make install" use: + make install-strip + +Note that this only strips the executables which are installed; the +temporary files created inside the build tree remain unstripped, and +the installed library libsis.a is not stripped. To strip libsis.a, +use the command: + strip -g libsis.a + +The utility xsis requires use of the X Window libraries. Normally this +is automatically detected with configure, but sometimes the test fails. +You can disable compilation of xsis by adding --without-x to the +configure options: + ./configure --without-x + +To get a full list of the options used by the configure script, use +the command: + ./configure --help + + +CUDD +---- + +SIS can be configured to use the optional University of Colorado BDD +package (CUDD). First obtain CUDD from: + http://vlsi.colorado.edu/~fabio/ + +Untar the CUDD sources in some convenient directory, then use the +--with-cudd option for configure: + ./configure --with-cudd= + +Then build and install SIS as normal. This has been tested with CUDD +2.4.0. + + +Contact +------- + +Bug reports, patches, questions and comments are welcome. Please send +correspondence to: + diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..ef78a4e --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,650 @@ +# generated automatically by aclocal 1.8.3 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +# Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# -*- Autoconf -*- +# Copyright (C) 2002, 2003 Free Software Foundation, Inc. +# Generated from amversion.in; do not edit by hand. + +# 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 + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.8"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.8.3])]) + +# AM_AUX_DIR_EXPAND + +# Copyright (C) 2001, 2003 Free Software Foundation, Inc. + +# 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. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003 Free Software Foundation, Inc. + +# 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. + +# serial 6 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]) +fi])]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc. + +# 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. + +# serial 7 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# This macro actually does too much some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. + +# 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. + +# serial 11 + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_MISSING_PROG(AMTAR, tar) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl + +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. + +# Copyright (C) 2001, 2003 Free Software Foundation, Inc. + +# 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. + +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# -*- Autoconf -*- +# Copyright (C) 2003 Free Software Foundation, Inc. + +# 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. + +# serial 1 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + + +# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. + +# 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. + +# serial 4 + +# AM_PROG_LEX +# ----------- +# Autoconf leaves LEX=: if lex or flex can't be found. Change that to a +# "missing" invocation, for better error output. +AC_DEFUN([AM_PROG_LEX], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AM_MISSING_HAS_RUN])dnl +AC_REQUIRE([AC_PROG_LEX])dnl +if test "$LEX" = :; then + LEX=${am_missing_run}flex +fi]) + +# -*- Autoconf -*- + + +# Copyright (C) 1997, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + +# 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. + +# serial 3 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. + +# Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +# 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. + +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +# +# We cannot accept any implementation of `mkdir' that recognizes `-p'. +# Some implementations (such as Solaris 8's) are not thread-safe: if a +# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' +# concurrently, both version can detect that a/ is missing, but only +# one can create it and the other will error out. Consequently we +# restrict ourselves to GNU make (using the --version option ensures +# this.) +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # Keeping the `.' argument allows $(mkdir_p) to be used without + # argument. Indeed, we sometimes output rules like + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. + # (`test -n '$(somedir)' && $(mkdir_p) $(somedir)' is a more + # expensive solution, as it forces Make to start a sub-shell.) + mkdir_p='mkdir -p -- .' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + +# 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. + +# serial 2 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# +# Check to make sure that the build environment is sane. +# + +# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc. + +# 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. + +# serial 3 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# AM_PROG_INSTALL_STRIP + +# Copyright (C) 2001, 2003 Free Software Foundation, Inc. + +# 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. + +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + diff --git a/blif2vst/Makefile.am b/blif2vst/Makefile.am new file mode 100644 index 0000000..19d5c3b --- /dev/null +++ b/blif2vst/Makefile.am @@ -0,0 +1,4 @@ +bin_PROGRAMS = blif2vst +blif2vst_SOURCES = blif2vst.c + +EXTRA_DIST = hff.blif hff.v test.genlib diff --git a/blif2vst/Makefile.in b/blif2vst/Makefile.in new file mode 100644 index 0000000..65f6aed --- /dev/null +++ b/blif2vst/Makefile.in @@ -0,0 +1,388 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(blif2vst_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = blif2vst$(EXEEXT) +subdir = blif2vst +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_blif2vst_OBJECTS = blif2vst.$(OBJEXT) +blif2vst_OBJECTS = $(am_blif2vst_OBJECTS) +blif2vst_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(blif2vst_SOURCES) +DIST_SOURCES = $(blif2vst_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +blif2vst_SOURCES = blif2vst.c +EXTRA_DIST = hff.blif hff.v test.genlib +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps blif2vst/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps blif2vst/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +blif2vst$(EXEEXT): $(blif2vst_OBJECTS) $(blif2vst_DEPENDENCIES) + @rm -f blif2vst$(EXEEXT) + $(LINK) $(blif2vst_LDFLAGS) $(blif2vst_OBJECTS) $(blif2vst_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/blif2vst/blif2vst.c b/blif2vst/blif2vst.c new file mode 100644 index 0000000..ac61d02 --- /dev/null +++ b/blif2vst/blif2vst.c @@ -0,0 +1,1566 @@ +/* + * $Header: /users/pchong/CVS/sis/blif2vst/blif2vst.c,v 1.1.1.1 2004/02/07 10:13:56 pchong Exp $ + * $Source: /users/pchong/CVS/sis/blif2vst/blif2vst.c,v $ + * $Log: blif2vst.c,v $ + * Revision 1.1.1.1 2004/02/07 10:13:56 pchong + * imported + * + * Revision 1.10 1994/06/14 15:47:29 archiadm + * error in: printf of output vectors + * + * Revision 1.9 1994/06/11 16:06:05 archiadm + * update 11/6 + * + * Revision 1.8 1994/05/23 21:14:20 archiadm + * new improvements + * + * Revision 1.8 1994/05/20 18:05:11 archiadm + * new improvements + * + * Revision 1.7 1994/05/09 10:17:39 archiadm + * minor bug fixes + * + * Revision 1.6 1994/05/06 15:45:13 Rob + * bug fix in the initial help, id has been added + * + * Revision 1.5 1994/05/04 20:56:25 Rob + * First released version + * + * Revision 1.4 1994/05/04 09:14:19 Rob + * Fixed the library parser and the blif file parser + * + * + * Blif2Vst version 0.0 + * BY RAMBALDI rOBERTO. + * Apr. 6 1994. + */ + + +#include +#include +#include +#include +#include + + +#define MAXTOKENLEN 256 +#define MAXNAMELEN 32 + + +/* ASCII seq: ( ) * + , : ; < = > * + * code 40 41 42 43 44 58 59 60 61 62 */ +#define isBLK(c) ( (((c)=='\t') || ((c)==' ') || ((c)=='\r')) ) +#define isREM(c) ( ((c)=='#') ) +#define isDQ(c) ( ((c)=='"') ) +#define isCNT(c) ( ((c)=='\\') ) +#define isEOL(c) ( ((c)=='\n') ) +#define isSTK(c) ( ((c)=='(') || ((c)==')') || isEOL(c) || ((c)=='=')) + +/* structure that contains all the info extracted from the library * + * All the pins, input, outp[ut and clock (if needed) * + * This because SIS should be case sensitive and VHDL is case * + * insensitive, so we must keep the library's names of gates and * + * pins. In the future this may be useful for further checks that * + * in this version are not performed. */ + + +#ifndef DATE +#define DATE "Nodate"; +#endif +static char rcsid[] = "$Id: blif2vst.c,v 1.1.1.1 2004/02/07 10:13:56 pchong Exp $"; +static char build_date[] = DATE; + + +struct Ports{ + char name[MAXNAMELEN]; +}; + +struct Cell { + char name[MAXNAMELEN]; + int npins; + char used; + struct Ports *formals; + struct Cell *next; +}; + +struct Instance { + struct Cell *what; + struct Ports *actuals; + struct Instance *next; +}; + + +/* list of formal names, is used in GetPort when multiple * + * definition are given, as a,b,c : IN BIT; */ +struct TMPstruct { + char name[MAXNAMELEN]; + int num; + struct TMPstruct *next; +}; + +struct BITstruct { + char name[MAXNAMELEN+10]; + struct BITstruct *next; +}; + +struct VECTstruct { + char name[MAXNAMELEN]; + int start; + int end; + char dir; + struct VECTstruct *next; +}; + +struct TYPEterms { + struct BITstruct *BITs; + struct VECTstruct *VECTs; +}; + +struct MODELstruct { + char name[MAXNAMELEN]; + struct TYPEterms *Inputs; + struct TYPEterms *Outputs; + struct TYPEterms *Internals; + struct Instance *Net; + struct MODELstruct *next; +}; + + + + +FILE *In; +FILE *Out; +int line; /* line parsed */ + +struct Cell *LIBRARY; +char VDD[MAXNAMELEN]={ 0 },VSS[MAXNAMELEN]={ 0 }; +char DEBUG; +char ADDPOWER; +char INSTANCE; + +#if defined(linux) +void AddBIT(struct BITstruct **,char *); +#endif + + +/*[]-------==[ Procedures to exit or to display warnings ]==---------------[]*/ + + +/* -=[ CloseAll ]=- * + * Closes all the files and flushes the memory * + * */ +void CloseAll() +{ + + if (In!=stdin) (void)fclose(In); + if (Out!=stdout) (void)fclose(Out); + +} + + +/* -=[ Error ]=- * + * Displays an error message, and then exits * + * * + * Input : * + * msg = message to printout before exiting */ +void Error(Msg) +char *Msg; +{ + (void)fprintf(stderr,"*** Error : %s\n",Msg); + CloseAll(); + exit(1); +} + + +/* -=[ Warning ]=- * + * Puts a message on stderr, writes the current * + * line and then sends the current token back * + * * + * Inputs : * + * name = message */ +void Warning(name) +char *name; +{ + if (DEBUG) (void)fprintf(stderr,"*parse warning* Line %u : %s\n",line,name); + +} + + +/* -=[ SyntaxError ]=- * + * sends to stderr a message and then exits * + * * + * Input : * + * name = message to print * + * obj = token that generates the error */ +void SyntaxError(msg,obj) +char *msg; +char *obj; +{ + + (void)fprintf(stderr,"\n*Error* Line %u : %s\n",line,msg); + (void)fprintf(stderr,"*Error* Line %u : object of the error : %s\n",line,obj); + Error("Could not continue!"); + +} + + +/*[]-------==[ General Procedures ]==--------------------------------------[]*/ + + +/* -=[ KwrdCmp ]=- * + * Compares two strings, it is case-insensitive, * + * it also skips initial and final duouble-quote * + * * + * Input : * + * name = first string, tipically the token * + * keywrd = second string, tipically a keyword * + * Output : * + * char = 1 if the strings match * + * 0 if they do not match */ +char KwrdCmp(name,keywrd) +char *name; +char *keywrd; +{ + int t; + int len; + char *n; + + len=strlen(name); + if (*name=='"') { + n=name+1; + len-=2; + } else { + n=name; + } + if ( len != (strlen(keywrd))) return 0; + if (!len) return 0; + /* if length 0 exit */ + for(t=0; (tnext) + if ( KwrdCmp(ptr->name,name) ) return ptr; + + (void)fprintf(stderr,"Instance %s not found in library!\n",name); + Error("could not continue"); + return (struct Cell *)NULL; +} + + +void ReleaseBit(ptr) +struct BITstruct *ptr; +{ + struct BITstruct *tmp; + struct BITstruct *ptr2; + + ptr2=ptr; + while(ptr2!=NULL){ + tmp=ptr2->next; + free((char *)ptr2); + ptr2=tmp; + } +} + + +struct Cell *NewCell(name,ports) +char *name; +struct BITstruct *ports; +{ + struct Cell *tmp; + struct BITstruct *Bptr; + struct Ports *Pptr; + unsigned int j; + int num; + + if ( (tmp=(struct Cell *)calloc(1,sizeof(struct Cell)))== NULL ) { + Error("Allocation Error or not enought memory !"); + } + + if (ports!=NULL){ + j=1; + Bptr=ports; + while(Bptr->next!=NULL){ + j++; Bptr=Bptr->next; + } + num=j; + + if ( (tmp->formals=(struct Ports *)calloc(1,j*sizeof(struct Ports)))==NULL){ + Error("Allocation Error or not enought memory !"); + } + (void)strcpy(tmp->name,name); + tmp->npins=j; + tmp->next=NULL; + + Bptr=ports; + Pptr=tmp->formals; + j=0; + while(Bptr!=NULL){ + if (j>num) Error("__NewCell error ..."); + (void)strcpy(Pptr->name,Bptr->name); + Bptr=Bptr->next; + Pptr++; j++; + } + ReleaseBit(ports); + } else { + tmp->formals=NULL; + } + return tmp; +} + + + +struct Instance *NewInstance(cell) +struct Cell *cell; +{ + struct Instance *tmp; + unsigned i; + + if ( (tmp=(struct Instance *)calloc(1,sizeof(struct Instance)))== NULL ) { + Error("Allocation Error or not enought memory !"); + } + if (cell!=NULL){ + i=cell->npins*sizeof(struct Ports); + if ( (tmp->actuals=(struct Ports *)calloc(1,i))==NULL){ + Error("Allocation Error or not enought memory !"); + } + } else { + tmp->actuals=NULL; + } + tmp->what=cell; + tmp->next=NULL; + + return tmp; +} + + +struct TYPEterms *NewTYPE() +{ + struct TYPEterms *TYPEptr; + + TYPEptr=(struct TYPEterms *)calloc(1,sizeof(struct TYPEterms)); + TYPEptr->BITs=(struct BITstruct *)calloc(1,sizeof(struct BITstruct)); + TYPEptr->VECTs=(struct VECTstruct *)calloc(1,sizeof(struct VECTstruct)); + if ( (TYPEptr==NULL) || (TYPEptr->BITs==NULL) || (TYPEptr->VECTs==NULL) ) { + Error("Allocation Error or not enought memory !"); + } + return TYPEptr; +} + +struct MODELstruct *NewModel() +{ + struct MODELstruct *LocModel; + + if ((LocModel=(struct MODELstruct *)calloc(1,sizeof (struct MODELstruct))) ==NULL) { + Error("Not enought memory or allocation error"); + } + + LocModel->Inputs=NewTYPE(); + LocModel->Outputs=NewTYPE(); + LocModel->Internals=NewTYPE(); + LocModel->Net=NewInstance((struct Cell *)NULL); + + return LocModel; +} + + +void AddVECT(VECTptr,name,a,b) +struct VECTstruct **VECTptr; +char *name; +int a; +int b; +{ + (*VECTptr)->next=(struct VECTstruct *)calloc(1,sizeof(struct VECTstruct)); + if ( (*VECTptr)->next==NULL) { + Error("Allocation Error or not enought memory !"); + } + (*VECTptr)=(*VECTptr)->next; + (void)strcpy((*VECTptr)->name,name); + (*VECTptr)->start=a; + (*VECTptr)->end=b; + (*VECTptr)->next=NULL; +} + +void AddBIT(BITptr,name) +struct BITstruct **BITptr; +char *name; +{ + + (*BITptr)->next=(struct BITstruct *)calloc(1,sizeof(struct BITstruct)); + if ( (*BITptr)->next==NULL) { + Error("Allocation Error or not enought memory !"); + } + (*BITptr)=(*BITptr)->next; + (void)strcpy((*BITptr)->name,name); + (*BITptr)->next=NULL; +} + +/* +void AddTMP(TMPptr) +struct TMPstruct **TMPptr; +{ + + (*TMPptr)->next=(struct TMPstruct *)calloc(1,sizeof(struct TMPstruct)); + if ( (*TMPptr)->next==NULL) { + Error("Allocation Error or not enough memory !"); + } + (*TMPptr)=(*TMPptr)->next; + +} +*/ + +struct BITstruct *IsHere(name,ptr) +char *name; +struct BITstruct *ptr; +{ + struct BITstruct *BITptr; + + BITptr=ptr; + while(BITptr->next!=NULL){ + BITptr=BITptr->next; + if (KwrdCmp(name,BITptr->name)) return BITptr; + } + return (struct BITstruct *)NULL; +} + +/* +struct BITstruct *IsKnown(name,model) +char *name; +struct MODELstruct *model; +{ + struct BITstruct *ptr; + + if ( (ptr=IsHere(name,(model->Inputs)->BITs))!=NULL ) return ptr; + if ( (ptr=IsHere(name,(model->Outputs)->BITs))!=NULL ) return ptr; + if ( (ptr=IsHere(name,(model->Internals)->BITs))!=NULL ) return ptr; + return (struct BITstruct *)NULL; + +} +*/ + + + + +/* -=[ GetToken ]=- * + * * + * Output : * + * tok = filled with the new token */ +void GetToken(tok) +char *tok; +{ + enum states { tZERO, tLONG, tEOF, tSTRING, tCONT, tREM }; + static enum states next; + static char init=0; + static char sentback; + static char TOKEN[MAXTOKENLEN]; + static char str; + char ready; + int num; + char *t; + char c; + + if (!init){ + sentback=0; + init=1; + next=tZERO; + str=0; + line=0; + } + + t=&(TOKEN[0]); + num=0; + str=0; + + do{ + if (sentback){ + c=sentback; + } else { + c=fgetc(In); + if (c=='\n') line++; + } + if (feof(In)) next=tEOF; + ready=0; + sentback='\0'; + + switch (next) { + case tZERO: +#if defined(DBG) + (void)fprintf(stderr,"\n> ZERO, c=%c token=%s",c,TOKEN); +#endif + if isBLK(c) { + next=tZERO; + } else { + if isSTK(c) { + *t=c; t++; + next=tZERO; + ready=1; + } else { + if isREM(c) { + num=0; + next=tREM; + } else { + if isCNT(c) { + next=tCONT; + } else { + num=0; + next=tLONG; + ready=0; + sentback=c; + } + } + } + } + break; + case tLONG: + if (DEBUG) (void)fprintf(stderr,"\n-> LONG, c=%c token=%s",c,TOKEN); + if (isBLK(c) || isSTK(c)) { + sentback=c; + ready=1; + next=tZERO; + } else { + if isDQ(c) { + ready=1; + next=tSTRING; + } else { + if isREM(c) { + ready=1; + next=tREM; + } else { + if isCNT(c) { + ready=1; + sentback=c; + } else { + *t=c; + t++; + num++; + next=tLONG; + if ( (ready=(num>=MAXTOKENLEN-1)) ) + (void)fprintf(stderr,"Sorry, exeeded max name len of %u",num+1); + } + } + } + } + break; + case tSTRING: +#if defined(DBG) + (void)fprintf(stderr,"\n--> STRING, c=%c token=%s",c,TOKEN); +#endif + if (!str) { + *t='"'; t++; num++; + str=1; + } + *t=c; t++; num++; + if (c=='"') { /* last dblquote */ + ready=1; + next=tZERO; + break; + } + next=tSTRING; + if ( (ready=(num>=MAXTOKENLEN-1)) ) + (void)fprintf(stderr,"Sorry, exeeded max name len of %u",num+1); + break; + case tREM: + if (DEBUG) (void)fprintf(stderr,"\n---> REM, c=%c token=%s",c,TOKEN); + next=tREM; + if isEOL(c) { + sentback=c; /* in this case EOL must be given to the caller */ + next = tZERO; + } + break; + case tCONT: +#if defined(DBG) + (void)fprintf(stderr,"\n----> CONT, c=%c token=%s",c,TOKEN); +#endif + if isEOL(c) { + sentback=0; /* EOL must be skipped */ + next = tZERO; + } else { + next=tCONT; + } + break; + case tEOF: +#if defined(DBG) + (void)fprintf(stderr,"\n-----> EOF, c=%c token=%s",c,TOKEN); +#endif + next=tEOF; + ready=1; + sentback=c; + *t=c; + break; + default : +#if defined(DBG) + (void)fprintf(stderr,"\n-------> DEFAULT, c=%c token=%s",c,TOKEN); +#endif + next=tZERO; + } + } while(!ready); + *t='\0'; + (void)strcpy(tok,&(TOKEN[0])); +} + + +void PrintGates(cell) +struct Cell *cell; +{ + struct Ports *ptr; + int j; + + while(cell->next!=NULL){ + cell=cell->next; + if (DEBUG) (void)fprintf(stderr,"Cell name: %s, num pins : %d\n",cell->name,cell->npins); + ptr=cell->formals; + for(j=0; jnpins; j++, ptr++){ + if (DEBUG) (void)fprintf(stderr,"\tpin %d : %s\n",j,ptr->name); + } + } +} + +/*[]------------------[]*/ + +/* -=[ GetLibToken ]=- * + * Tokenizer to scan the library file * + * * + * Input : * + * Lib = library file * + * Output : * + * tok = filled with the new token */ +void GetLibToken(Lib,tok) +FILE *Lib; +char *tok; +{ + enum states { tZERO, tLONG, tEOF, tSTRING, tREM }; + static enum states next; + static char init=0; + static char sentback; + static char TOKEN[MAXTOKENLEN]; + static char str; + char ready; + int num; + char *t; + char c; + + if (!init){ + sentback=0; + init=1; + next=tZERO; + str=0; + } + + t=&(TOKEN[0]); + num=0; + str=0; + + do{ + if (sentback){ + c=sentback; + } else { + c=fgetc(Lib); + } + if (feof(Lib)) next=tEOF; + ready=0; + sentback='\0'; + + switch (next) { + case tZERO: + if ((c==' ') || (c=='\r') || (c=='\t')){ + next=tZERO; + } else { + if (c=='#') { + next=tREM; + } else { + if ( ((c>=0x27) && (c<=0x2b)) || (c=='=') || (c==';') || (c=='\n') || (c=='!')){ + *t=c; t++; + next=tZERO; + ready=1; + } else { + if (c=='"') { + num=0; + next=tSTRING; + } else { + num=0; + next=tLONG; + ready=0; + sentback=c; + } + } + } + } + break; + case tLONG: + if ((c==' ') || (c=='\r') || (c=='\t')){ + ready=1; + next=tZERO; + } else { + if ( ((c>=0x27) && (c<=0x2b)) || (c=='=') || (c==';') || (c=='\n') || (c=='!')){ + next=tZERO; + ready=1; + sentback=c; + } else { + if (c=='"') { + ready=1; + next=tSTRING; + } else { + if (c=='#') { + ready=1; + next=tREM; + } else { + *t=c; + t++; num++; + next=tLONG; + if ( (ready=(num>=MAXTOKENLEN-1)) ) + (void)fprintf(stderr,"Sorry, exeeded max name len of %u",num+1); + } + } + } + + } + break; + case tSTRING: + if (!str) { + *t='"'; t++; num++; + if(DEBUG) (void)fprintf(stderr,"<%c>\n",c); + str=1; + } + *t=c; t++; num++; + if (c=='"') { /* last dblquote */ + ready=1; + next=tZERO; + if (DEBUG) fprintf(stderr,"STRING : %s\n",TOKEN); + break; + } + next=tSTRING; + if ( (ready=(num>=MAXTOKENLEN-1)) ) + (void)fprintf(stderr,"Sorry, exeeded max name len of %u",num+1); + break; + case tEOF: + next=tEOF; + ready=1; + sentback=c; + *t=c; + if (DEBUG) (void)fprintf(stderr,"EOF\n"); + break; + case tREM: + next=tREM; + if (c=='\n'){ + sentback=c; + next=tZERO; + } + break; + default : + next=tZERO; + } + } while(!ready); + *t='\0'; + (void)strcpy(tok,&(TOKEN[0])); +} + + +/* -=[ ScanLibrary ]=- * + * Scans the library to get the names of the cells * + * the output pins and the clock signals of latches * + * * + * Input : * + * LibName = the name of library file */ +struct Cell *ScanLibrary(LibName) +char *LibName; +{ + enum states { sZERO, sPIN, sCLOCK, sADDCELL } next; + FILE *Lib; + struct Cell *cell; + struct Cell first; + struct BITstruct *tmpBIT; + struct BITstruct firstBIT; + char LocalToken[MAXTOKENLEN]; + char tmp[MAXNAMELEN]; + char name[MAXNAMELEN]; + char latch; + char *s; + + + if ((Lib=fopen(LibName,"rt"))==NULL) + Error("Couldn't open library file"); + + + first.next=NewCell("dummy",(struct BITstruct *)NULL); + firstBIT.name[0]='\0'; firstBIT.next=NULL; + cell=first.next; + s=&(LocalToken[0]); + latch=0; next=sZERO; + (void)fseek(Lib,0L,SEEK_SET); + tmpBIT=&firstBIT; + do { + GetLibToken(Lib,s); + switch (next) { + case sZERO: + next=sZERO; + if (KwrdCmp(s,"GATE")) { + latch=0; + GetLibToken(Lib,s); + (void)strcpy(name,s); + GetLibToken(Lib,s); /* area */ + next=sPIN; + if (DEBUG) (void)fprintf(stderr,"Gate name: %s\n",name); + } else { + if (KwrdCmp(s,"LATCH")) { + latch=1; + GetLibToken(Lib,s); + (void)strcpy(name,s); + GetLibToken(Lib,s); /* area */ + next=sPIN; + if (DEBUG) (void)fprintf(stderr,"Latch name: %s\n",name); + } + } + break; + case sPIN: + if ( !( ((*s>=0x27) && (*s<=0x2b)) || (*s=='=') || (*s=='!')|| (*s==';')) ){ + (void)strncpy(tmp,s,5); + if (KwrdCmp(tmp,"CONST") && !isalpha(*(s+6))) + /* if the expression has a constant value we must */ + /* skip it, because there are no inputs */ + break; + /* it's an operand so get its name */ + if (DEBUG) (void)fprintf(stderr,"\tpin read : %s\n",s); + if (IsHere(s,&firstBIT)==NULL) { + if (DEBUG) (void)fprintf(stderr,"\tunknown pin : %s\n",s); + AddBIT(&tmpBIT,s); + } + } + if (*s==';') { + if (latch) { + next=sCLOCK; + } else { + next=sADDCELL; + } + } else { + next=sPIN; + } + break; + case sCLOCK: + if (KwrdCmp(s,"CONTROL")){ + GetLibToken(Lib,s); + if (DEBUG) (void)fprintf(stderr,"\tpin : %s\n",s); + AddBIT(&tmpBIT,s); + next=sADDCELL; + } else { + next=sCLOCK; + } + break; + case sADDCELL: + if (DEBUG) (void)fprintf(stderr,"\tadding cell to library\n"); + cell->next=NewCell(name,firstBIT.next); + tmpBIT=&firstBIT; firstBIT.next=NULL; + cell=cell->next; + next=sZERO; + break; + } + } while (!feof(Lib)); + + if ((first.next)->next==NULL) { + (void)sprintf("Library file %s does *NOT* contains gates !",LibName); + Error("could not continue with an empy library"); + } + if (DEBUG) (void)fprintf(stderr,"eond of lib"); + PrintGates(first.next); + return first.next; +} + + +/* -=[ CheckArgs ]=- * + * Gets the options from the command line, open * + * the input and output file and read params from * + * the library file. * + * * + * Input : * + * argc,argv = usual cmdline arcguments */ +void CheckArgs(argc,argv) +int argc; +char **argv; +{ + char *s; + char c; + char help; + + extern char *optarg; + extern int optind; + + s=&( argv[0][strlen(argv[0])-1] ); + while( (s>= &(argv[0][0])) && (*s!='/') ) { s--; } + (void)fprintf(stderr,"\t\t Blif Converter v1.0\n"); + (void)fprintf(stderr,"\t\t by Roberto Rambaldi\n"); + (void)fprintf(stderr,"\t\tD.E.I.S. Universita' di Bologna\n\n"); + help=0; ADDPOWER=0; INSTANCE=1; + while( (c=getopt(argc,argv,"s:S:d:D:IihHvVnN$") )>0 ){ + switch (toupper(c)) { + case 'I': + INSTANCE=0; + break; + case 'S': + (void)strncpy(VSS,optarg,MAXNAMELEN); + break; + case 'D': + (void)strncpy(VDD,optarg,MAXNAMELEN); + break; + case 'V': + DEBUG=1; + break; + case 'H': + help=1; + break; + case 'N': + ADDPOWER=1; + break; + case '$': + help=1; + (void)fprintf(stderr,"\n\tID = %s\n",rcsid); + (void)fprintf(stderr,"\tCompiled on %s\n\n",build_date); + break; + default: + (void)fprintf(stderr,"\t *** unknown options"); + help=1; + break; + } + } + + if (!help) { + if (optind>=argc) { + if (!help) (void)fprintf(stderr,"No Library file specified\n\n"); + help=1; + } else { + LIBRARY=ScanLibrary(argv[optind]); + if (++optind>=argc){ + In=stdin; Out=stdout; + } else { + if ((In=fopen(argv[optind],"rt"))==NULL) Error("Couldn't read input file"); + if (++optind>=argc) { Out=stdout; } + else if ((Out=fopen(argv[optind],"wt"))==NULL) Error("Could'n make opuput file"); + } + } + + if (!ADDPOWER) { + VDD[0]='\0'; VSS[0]='\0'; + } else { + if (VDD[0]=='\0') (void)strcpy(VDD,"vdd"); + if (VSS[0]=='\0') (void)strcpy(VSS,"vss"); + } + } + + if (help) { + (void)fprintf(stderr,"\tUsage: %s [options] [infile [outfile]]\n",s); + (void)fprintf(stderr,"\t if outfile is not given will be used stdout, if also\n"); + (void)fprintf(stderr,"\t infile is not given will be used stdin instead.\n"); + (void)fprintf(stderr,"\t\t is the name of the library file to use\n"); + (void)fprintf(stderr,"\tOptions :\n\t-s \t will be used for VSS net\n"); + (void)fprintf(stderr,"\t-i \t\t skip instance names\n"); + (void)fprintf(stderr,"\t-d \t will be used for VDD net\n"); + (void)fprintf(stderr,"\t-n\t\t no VSS or VDD to skip.\n"); + (void)fprintf(stderr,"\t-h\t\t prints these lines"); + (void)fprintf(stderr,"\n\tIf no VDD or VSS nets are given VDD and VSS will be used\n"); + exit(0); + } +} + + + +/* -=[ DecNumber ]=- * + * checks if a token is a decimal number * + * * + * Input : * + * string = token to check * + * Output : * + * int = converted integer, or 0 if the string * + * is not a number * + * REMMARK : strtol() can be used... */ +int DecNumber(string) +char *string; +{ + char *s; + + for(s=string; *s!='\0'; s++) + if (!isdigit(*s)) { + SyntaxError("Expected decimal integer number",string); + } + return atoi(string); +} + +/* -=[ GetSignals ]=- */ + +void GetSignals(TYPEptr) +struct TYPEterms *TYPEptr; +{ + enum states { sZERO, sWAIT, sNUM, sEND } next; + char *w; + char LocalToken[MAXTOKENLEN]; + char name[MAXNAMELEN]; + char tmp[MAXNAMELEN+10]; + struct BITstruct *BITptr; + struct VECTstruct *VECTptr; + char Token; + int num; + + w=&(LocalToken[0]); + + BITptr=TYPEptr->BITs; + VECTptr=TYPEptr->VECTs; + + while(BITptr->next!=NULL) { +/* (void)fprintf(stderr,".. b) element used : %s, skip...\n",BITptr->name); */ + BITptr=BITptr->next; } + while(VECTptr->next!=NULL) { +/* (void)fprintf(stderr,".. v) element used : %s, skip...\n",VECTptr->name); */ + VECTptr=VECTptr->next; } + + next = sZERO; + Token=1; + + do { + if (Token) GetToken(w); + else Token=1; + if ((*w=='\n') && (next!=sWAIT)) break; + if (DEBUG) (void)fprintf(stderr,"next = %u\n",next); + switch (next) { + case sZERO: + if (*w=='[') { + *(w+strlen(w)-1)='\0'; + (void)sprintf(name,"intrnl%s",w+1); + } else { + (void)strcpy(name,w); + } + if (DEBUG) (void)fprintf(stderr,"element name : %s\n",name); + next=sWAIT; + break; + case sWAIT: + if (DEBUG) (void)fprintf(stderr,"--sWAIT-- tok <%s>\n",w); + if (*w=='(') { + /* is a vector */ + next=sNUM; + } else { + /* it was a BIT type */ + if (DEBUG) (void)fprintf(stderr,"\t\t--> bit, added\n"); + AddBIT(&BITptr,name); + Token=0; + next=sZERO; + } + break; + case sNUM: + if (DEBUG) (void)fprintf(stderr,"\t\t is a vector, element number :%s\n",w); + num=DecNumber(w); + AddVECT(&VECTptr,name,num,num); + (void)sprintf(tmp,"%s(%u)",name,num); + AddBIT(&BITptr,tmp); + next=sEND; + break; + case sEND: + if (*w!=')') { + Warning("closing ) expected !"); + Token=0; + } + next=sZERO; + break; + } + if (DEBUG) (void)fprintf(stderr,"next = %u\n",next); + } while(!feof(In)); + +} + + +void OrderVectors(VECTptr) +struct VECTstruct *VECTptr; +{ + struct VECTstruct *actual; + struct VECTstruct *ptr; + struct VECTstruct *tmp; + struct VECTstruct *prev; + int dir; + int last; + + actual=VECTptr; + while (actual->next!=NULL) { + actual=actual->next; + last=actual->start; +/* (void)fprintf(stderr,"vector under test : %s\n",actual->name); */ + dir=0; + prev=actual; + ptr=actual->next; + while (ptr!=NULL) { +/* (void)fprintf(stderr,"analizing element name = %s number = %u\n",ptr->name,ptr->end); */ + if (!strcmp(ptr->name,actual->name)) { + /* same name, so ptr belogns to the vector of actual */ + if (ptr->end>actual->end) { + actual->end=ptr->end; + } else { + if (ptr->startstart) { + actual->start=ptr->start; + } + } + if (ptr->end>last) dir++; + else { + if (ptr->end==last) { + Error("Two elements of an i/o vector with the same number not allowed!"); + } else dir--; + } + /* release memory */ + tmp=ptr->next; +/* (void)fprintf(stderr,"deleting element @%p, actual=%p ..->next=%p\n",ptr,actual,actual->next); */ + if (ptr==actual->next) { +/* (void)fprintf(stderr,"updating actual's next"); */ + actual->next=tmp; + } + free((char *)ptr); + ptr=tmp; + prev->next=tmp; + } else { + prev=ptr; + ptr=ptr->next; + } + } + actual->dir=dir>0; + } +} + + + +void PrintSignals(Model) +struct MODELstruct *Model; +{ + struct BITstruct *BITptr; + struct VECTstruct *VECTptr; + + BITptr=(Model->Inputs)->BITs; + if (DEBUG) (void)fprintf(stderr,"\nINPUTS, BIT:"); + while(BITptr->next!=NULL){ + BITptr=BITptr->next; + if (DEBUG) (void)fprintf(stderr,"\t%s",BITptr->name); + } + + BITptr=(Model->Outputs)->BITs; + if (DEBUG) (void)fprintf(stderr,"\nOUTPUTS, BIT:"); + while(BITptr->next!=NULL){ + BITptr=BITptr->next; + if (DEBUG) (void)fprintf(stderr,"\t%s",BITptr->name); + } + + + VECTptr=(Model->Inputs)->VECTs; + if (DEBUG) (void)fprintf(stderr,"\nINPUTS, VECT:"); + while(VECTptr->next!=NULL){ + VECTptr=VECTptr->next; + if (VECTptr->dir) if (DEBUG) (void)fprintf(stderr,"\t%s [%d..%d]",VECTptr->name,VECTptr->start,VECTptr->end); + else if (DEBUG) (void)fprintf(stderr,"\t%s [%d..%d]",VECTptr->name,VECTptr->end,VECTptr->start); + } + + VECTptr=(Model->Outputs)->VECTs; + if (DEBUG) (void)fprintf(stderr,"\nOUTPUTS, VECT:"); + while(VECTptr->next!=NULL){ + VECTptr=VECTptr->next; + if (VECTptr->dir) if (DEBUG) (void)fprintf(stderr,"\t%s [%d..%d]",VECTptr->name,VECTptr->start,VECTptr->end); + else if (DEBUG) (void)fprintf(stderr,"\t%s [%d..%d]",VECTptr->name,VECTptr->end,VECTptr->start); + } + if (DEBUG) (void)fprintf(stderr,"\n"); +} + + +void PrintNet(cell) +struct Instance *cell; +{ + struct Ports *ptr1; + struct Ports *ptr2; + int j; + + while(cell->next!=NULL){ + cell=cell->next; + if (DEBUG) (void)fprintf(stderr,"Inst. connected to name: %s, num pins : %d\n",(cell->what)->name,(cell->what)->npins); + ptr1=cell->actuals; + ptr2=(cell->what)->formals; + for(j=0; j<(cell->what)->npins; j++, ptr1++, ptr2++){ + if (DEBUG) (void)fprintf(stderr,"\tpin %d : %s -> %s\n",j,ptr2->name,ptr1->name); + } + } +} + +struct Instance *GetNames(name,type,Model) +char *name; +char type; +struct MODELstruct *Model; +{ + enum states { sZERO, saWAIT, saNUM, saEND, sEQUAL, + saNAME, sfWAIT, sfNUM, sfEND, sADDINSTANCE } next; + struct Ports *Fptr; + struct Ports *Aptr; + struct Instance *Inst; + struct Cell *cell; + struct BITstruct *Bptr; + char *w; + char LocalToken[MAXTOKENLEN]; + char FORMname[MAXNAMELEN]; + char ACTname[MAXNAMELEN]; + char tmp[MAXNAMELEN+10]; + char Token; + int num; + int j; + int exit; + + w=&(LocalToken[0]); + next = sZERO; + Token=1; + exit=1; + + if (DEBUG) (void)fprintf(stderr,"Parsing instance with gate %s\n",name); + cell=WhatGate(name); + cell->used=1; + Inst=NewInstance(cell); + + Bptr=(Model->Internals)->BITs; + while(Bptr->next!=NULL){ + Bptr=Bptr->next; + } + + do { + if (Token) GetToken(w); + else Token=1; + if (*w=='\n') { + exit=0; + if (next!=sADDINSTANCE) { + Warning("--------> Unexpected end of line!"); + next=sADDINSTANCE; + } + } + switch (next) { + case sZERO: + if (*w=='[') { + *(w+strlen(w)-1)='\0'; + (void)sprintf(FORMname,"intrnl%s",w+1); + } else { + (void)strcpy(FORMname,w); + } + if (DEBUG) (void)fprintf(stderr,"formal element name : %s\n",FORMname); + next=sfWAIT; + break; + case sfWAIT: + if (*w=='(') { + /* is a vector */ + next=sfNUM; + } else { + /* it was a BIT type */ + Token=0; + next=sEQUAL; + } + break; + case sfNUM: + if (DEBUG) (void)fprintf(stderr,"\t\t is a vector, element number :%s\n",w); + num=DecNumber(w); + (void)sprintf(tmp,"%s(%u)",FORMname,num); + (void)strcpy(FORMname,tmp); + next=sfEND; + break; + case sfEND: + if (*w!=')') { + Warning("Closing ) expected !"); + Token=0; + } + next=sEQUAL; + break; + case sEQUAL: + next=saNAME; + if (*w!='=') { + if (type) { + if (DEBUG) (void)fprintf(stderr,"clock signal\n"); + (void)strcpy(ACTname,FORMname); + FORMname[0]='\0'; + next=sADDINSTANCE; + } else { + Warning("Expexted '=' !"); + next=saNAME; + } + Token=0; + } + break; + case saNAME: + if (*w=='[') { + *(w+strlen(w)-1)='\0'; + (void)sprintf(ACTname,"intrnl%s",w+1); + } else { + (void)strcpy(ACTname,w); + } + if (DEBUG) (void)fprintf(stderr,"actual element name : %s\n",ACTname); + next=saWAIT; + break; + case saWAIT: + if (*w=='(') { + /* is a vector */ + next=saNUM; + } else { + /* it was a BIT type */ + Token=0; + next=sADDINSTANCE; + } + break; + case saNUM: + if (DEBUG) (void)fprintf(stderr,"\t\t is a vector, element number :%s\n",w); + num=DecNumber(w); + (void)sprintf(tmp,"%s(%u)",ACTname,num); + (void)strcpy(ACTname,tmp); + next=saEND; + break; + case saEND: + if (*w!=')') { + Warning("Closing ) expected !"); + Token=0; + } + next=sADDINSTANCE; + break; + case sADDINSTANCE: + if ( (IsHere(ACTname,(Model->Inputs)->BITs)==NULL) && + (IsHere(ACTname,(Model->Outputs)->BITs)==NULL) && + (IsHere(ACTname,(Model->Internals)->BITs)==NULL) ) { + AddBIT(&Bptr,ACTname); + if (DEBUG) (void)fprintf(stderr,"\tadded to internals\n"); + } + Aptr=Inst->actuals; + Fptr=cell->formals; + j=0; next=sZERO; + Token=0; + if (DEBUG) (void)fprintf(stderr,"\tparsed pin : %s, %s\n",FORMname,ACTname); + if (FORMname[0]!='\0') { + while(jnpins){ + if (KwrdCmp(Fptr->name,FORMname)){ + (void)strcpy(Aptr->name,ACTname); + break; + } + Fptr++; + Aptr++; + j++; + } + } else { + Aptr+=cell->npins-1; + (void)strcpy(Aptr->name,ACTname); + break; + } + } + } while(exit); + return Inst; +} + + + + + + +void PrintVST(Model) +struct MODELstruct *Model; +{ + struct Cell *Cptr; + struct Instance *Iptr; + struct Ports *Fptr; + struct BITstruct *Bptr; + struct VECTstruct *Vptr; + struct Ports *Aptr; + int j; + int i; + char init; + + (void)fprintf(Out,"--[]--------------------------------------[]--\n"); + (void)fprintf(Out,"-- | File created by Blif2Sls v1.0 | --\n"); + (void)fprintf(Out,"-- | | --\n"); + (void)fprintf(Out,"-- | by Roberto Rambaldi | --\n"); + (void)fprintf(Out,"-- | D.E.I.S. Universita' di Bologna | --\n"); + (void)fprintf(Out,"--[]--------------------------------------[]--\n\n"); + + (void)fprintf(Out,"\n\nENTITY %s IS\n PORT(\n",Model->name); + Bptr=(Model->Inputs)->BITs; + init=0; + while(Bptr->next!=NULL){ + Bptr=Bptr->next; + if ( (Bptr->name)[strlen(Bptr->name)-1]!=')' ) { + if (init) (void)fputs(" ;\n",Out); + else init=1; + (void)fprintf(Out,"\t%s\t: in BIT",Bptr->name); + } + } + + Bptr=(Model->Outputs)->BITs; + while(Bptr->next!=NULL){ + Bptr=Bptr->next; + if ( (Bptr->name)[strlen(Bptr->name)-1]!=')' ) { + if (init) (void)fputs(" ;\n",Out); + else init=1; + (void)fprintf(Out,"\t%s\t: out BIT",Bptr->name); + } + } + + Vptr=(Model->Inputs)->VECTs; + while(Vptr->next!=NULL){ + Vptr=Vptr->next; + if (init) (void)fputs(" ;\n",Out); + else init=1; + if (Vptr->dir) (void)fprintf(Out,"\t%s\t: in BIT_VECTOR(%d to %d)",Vptr->name,Vptr->start,Vptr->end); + else (void)fprintf(Out,"\t%s\t: in BIT_VECTOR(%d downto %d)",Vptr->name,Vptr->end,Vptr->start); + } + + Vptr=(Model->Outputs)->VECTs; + while(Vptr->next!=NULL){ + Vptr=Vptr->next; + if (init) (void)fputs(" ;\n",Out); + else init=1; + if (Vptr->dir) (void)fprintf(Out,"\t%s\t: out BIT_VECTOR(%d to %d)",Vptr->name,Vptr->start,Vptr->end); + else (void)fprintf(Out,"\t%s\t: out BIT_VECTOR(%d downto %d)",Vptr->name,Vptr->end,Vptr->start); + + } + if (ADDPOWER) { + (void)fprintf(Out," ;\n\t%s\t : in BIT;\n\t%s\t : in BIT",VSS,VDD); + } + + (void)fprintf(Out," );\nEND %s;\n\n\nARCHITECTURE structural_from_SIS OF %s IS\n",Model->name,Model->name); + + + Cptr=LIBRARY; + while(Cptr->next!=NULL) { + Cptr=Cptr->next; + if (Cptr->used) { + (void)fprintf(Out," COMPONENT %s\n PORT (\n",Cptr->name); + Fptr=Cptr->formals; + (void)fprintf(Out,"\t%s\t: out BIT",Fptr->name); + for(j=1, Fptr++; jnpins; j++, Fptr++){ + (void)fprintf(Out," ;\n\t%s\t: in BIT",Fptr->name); + } + if (ADDPOWER) { + (void)fprintf(Out," ;\n\t%s\t: in BIT ;\n\t%s\t: in BIT",VSS,VDD); + } + (void)fprintf(Out," );\n END COMPONENT;\n\n"); + } + } + + Bptr=(Model->Internals)->BITs; + init=0; + while(Bptr->next!=NULL){ + Bptr=Bptr->next; + (void)fprintf(Out,"SIGNAL %s\t: BIT ;\n",Bptr->name); + } + + (void)fputs("BEGIN\n",Out); + + j=0; + Iptr=Model->Net; + while(Iptr->next!=NULL){ + Iptr=Iptr->next; + (void)fprintf(Out," inst%d : %s\n PORT MAP (\n",j,(Iptr->what)->name); + j++; + Aptr=Iptr->actuals; + Fptr=(Iptr->what)->formals; + for(i=0; i<(Iptr->what)->npins-1; i++, Aptr++, Fptr++){ + (void)fprintf(Out,"\t%s => %s,\n",Fptr->name,Aptr->name); + } + if (ADDPOWER) { + (void)fprintf(Out,"\t%s => %s,\n\t%s => %s,\n\t%s => %s);\n\n",Fptr->name,Aptr->name,VSS,VSS,VDD,VDD); + } else { + (void)fprintf(Out,"\t%s => %s);\n\n",Fptr->name,Aptr->name); + } + } + (void)fputs("\nEND structural_from_SIS;\n",Out); + +} + + +/* -=[ PARSE FILE ]=- */ +void ParseFile() +{ + char *w; + char LocalToken[MAXTOKENLEN]; + struct MODELstruct *LocModel; + struct Instance *Net; + + + w=&(LocalToken[0]); + LocModel=NewModel(); + + if (DEBUG) (void)fprintf(stderr,"start of parsing\n"); + do { + GetToken(w); + } while (strcmp(w,".model")); + + + GetToken(w); + (void)strcpy(LocModel->name,w); + do { + do GetToken(w); while(*w=='\n'); + if ( (!strcmp(w,".inputs")) || (!strcmp(w,".clock")) ) { + GetSignals(LocModel->Inputs); + } else { + if ( !strcmp(w,".outputs") ) { + GetSignals(LocModel->Outputs); + } else break; + } + } while (!feof(In)); + + PrintSignals(LocModel); + + OrderVectors((LocModel->Inputs)->VECTs); + OrderVectors((LocModel->Outputs)->VECTs); + + PrintSignals(LocModel); + + Net=LocModel->Net; + do { + if (!strcmp(w,".gate")) { + GetToken(w); + Net->next=GetNames(w,0,LocModel); + Net=Net->next; + } else { + if (!strcmp(w,".mlatch")) { + GetToken(w); + Net->next=GetNames(w,1,LocModel); + Net=Net->next; + } else { + if (!strcmp(w,".end")){ + PrintNet(LocModel->Net); + if (DEBUG) (void)fprintf(stderr,"fine"); + break; + } else { + /* SyntaxError("Unknown keyword",w); */ + } + } + } + do GetToken(w); while(*w=='\n'); + } while (!feof(In)); + PrintVST(LocModel); + +} + +/* -=[ main ]=- */ +int main(argc,argv) +int argc; +char **argv; +{ + + CheckArgs(argc,argv); + + ParseFile(); + + CloseAll(); + + return 0; +} + + + diff --git a/blif2vst/hff.blif b/blif2vst/hff.blif new file mode 100644 index 0000000..a2d011a --- /dev/null +++ b/blif2vst/hff.blif @@ -0,0 +1,24 @@ +# File created by vst2blif ver 1.0 +# by Roberto Rambaldi +# D.E.I.S. Universita' di Bologna +.model hff + +.inputs d ck cln prn +.outputs q qn + +.gate inv1x a=d O=dn +.gate nand2 a=ck b=d O=a +.gate nand2 a=ck b=dn O=an +.gate nand2 a=a b=prn O=bt +.gate nand2 a=an b=cln O=bnt +.gate nand2 a=b b=iqn O=iq +.gate nand2 a=bn b=iqd O=iqn +.gate inv1x a=iq O=qt +.gate inv1x a=qt O=q +.gate inv1x a=iqn O=qn +.gate inv1x a=bt O=b +.gate inv1x a=bnt O=bn +.mlatch dlatch D=iq Q=iqd c1 3 +.gate one O=c1 + +.end diff --git a/blif2vst/hff.v b/blif2vst/hff.v new file mode 100644 index 0000000..74885f2 --- /dev/null +++ b/blif2vst/hff.v @@ -0,0 +1,60 @@ +entity hff is +port ( + d :in bit ; + ck :in bit ; + cln :in bit ; + prn :in bit ; + q :out bit ; + qn :out bit) ; +end hff; + +architecture structural of hff is + +signal dn,a,an,b,bn,iq,iqn,qt,bt,bnt,iqd,c1:bit; + +component nand2 +port (a,b:in bit; o:out bit); +end component; + +component inv1x +port (a:in bit; o:out bit); +end component; + +component dlatch +port (CLOCK,D:in bit; Q:out bit); +end component; + +component one +port (O:out bit); +end component; + +begin + u0: inv1x + port map (a=>d,o=>dn); + u1: nand2 + port map (a=>ck,b=>d,o=>a); + u2: nand2 + port map (a=>ck,b=>dn,o=>an); + u3: nand2 + port map (a=>a,b=>prn,o=>bt); + u4: nand2 + port map (a=>an,b=>cln,o=>bnt); + u5: nand2 + port map (a=>b,b=>iqn,o=>iq); + u6: nand2 + port map (a=>bn,b=>iqd,o=>iqn); + u7: inv1x + port map (a=>iq,o=>qt); + u8: inv1x + port map (a=>qt,o=>q); + u9: inv1x + port map (a=>iqn,o=>qn); + u10: inv1x + port map (a=>bt,o=>b); + u11: inv1x + port map (a=>bnt,o=>bn); + u12: dlatch + port map (CLOCK=>c1,Q=>iqd,D=>iq); + u13: one + port map (O=>c1); +end structural; diff --git a/blif2vst/test.genlib b/blif2vst/test.genlib new file mode 100644 index 0000000..8254dac --- /dev/null +++ b/blif2vst/test.genlib @@ -0,0 +1,171 @@ + GATE inv1x 928.00 O = ! a; + PIN a INV 0.0514 999.0 0.4200 4.7100 0.4200 3.6000 + + GATE inv2x 928.00 O = ! a; + PIN a INV 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 + + GATE inv4x 1392.00 O = ! a; + PIN a INV 0.1897 999.0 0.2300 1.0800 0.2700 0.8500 + + GATE xor 2320.00 O = ((!a * b) + (a * !b)); + PIN a UNKNOWN 0.1442 999.0 1.7700 5.2300 0.9600 4.6400 + PIN b UNKNOWN 0.1381 999.0 1.9400 4.6500 1.1400 5.2200 + + GATE xnor 2320.00 O = ((!a * !b) + (a * b)); + PIN a UNKNOWN 0.1502 999.0 1.1100 4.8600 1.0700 3.3900 + PIN b UNKNOWN 0.1352 999.0 1.5500 4.8700 1.0700 3.3900 + + GATE nand2 1392.00 O = ! (a * b); + PIN a INV 0.0777 999.0 0.6400 4.0900 0.4000 2.5700 + PIN b INV 0.0716 999.0 0.4600 4.1000 0.3700 2.5700 + + GATE nand3 1856.00 O = ! (a * b * c); + PIN a INV 0.1000 999.0 0.8900 3.6000 0.5100 2.4900 + PIN b INV 0.0828 999.0 0.7100 4.1100 0.4200 2.5000 + PIN c INV 0.0777 999.0 0.5600 4.3900 0.3500 2.4900 + + GATE nand4 2320.00 O = ! (a * b * c * d); + PIN a INV 0.1030 999.0 1.2700 3.6200 0.6700 2.3900 + PIN b INV 0.0980 999.0 1.0900 3.6100 0.6100 2.3900 + PIN c INV 0.0980 999.0 0.8200 3.6200 0.5500 2.4000 + PIN d INV 0.1050 999.0 0.5800 3.6200 0.3800 2.3900 + + GATE nor2 1392.00 O = ! (a + b); + PIN a INV 0.0736 999.0 0.3300 3.6400 0.4500 3.6400 + PIN b INV 0.0968 999.0 0.5000 3.6400 0.7000 3.6600 + + GATE nor3 1856.00 O = ! (a + b + c); + PIN a INV 0.0856 999.0 0.8400 5.0400 1.3000 3.4500 + PIN b INV 0.0806 999.0 0.7800 5.0300 1.1400 3.4300 + PIN c INV 0.0826 999.0 0.5200 5.0300 0.8400 3.4400 + + GATE nor4 2320.00 O = ! (a + b + c + d); + PIN a INV 0.0887 999.0 0.4100 5.9100 1.1600 3.2000 + PIN b INV 0.0867 999.0 0.8500 5.9100 1.5300 3.1800 + PIN c INV 0.0867 999.0 1.1100 5.9200 1.7500 3.1900 + PIN d INV 0.0887 999.0 1.2700 5.9100 1.9400 3.2000 + + GATE aoi21 1856.00 O = ! ((a1 * a2) + b); + PIN a1 INV 0.1029 999.0 0.7500 3.5200 0.6700 2.5300 + PIN a2 INV 0.0908 999.0 0.6700 3.6400 0.6200 2.5200 + PIN b INV 0.1110 999.0 0.5800 3.6400 0.2100 1.2800 + + GATE aoi31 2320.00 O = ! ((a1 * a2 * a3) + b); + PIN a1 INV 0.1009 999.0 0.9100 4.0400 0.8100 2.8600 + PIN a2 INV 0.1049 999.0 1.0500 3.9300 0.8700 2.8700 + PIN a3 INV 0.1059 999.0 1.1500 3.9400 0.9400 2.8600 + PIN b INV 0.0979 999.0 0.8900 4.0600 0.2500 1.2800 + + GATE aoi22 2320.00 O = ! ((a1 * a2) + (b1 * b2)); + PIN a1 INV 0.1019 999.0 0.9200 3.4600 0.9400 2.7900 + PIN a2 INV 0.0908 999.0 0.8400 3.6400 0.8500 2.7900 + PIN b1 INV 0.0958 999.0 0.6100 3.6400 0.4900 2.9300 + PIN b2 INV 0.0988 999.0 0.7000 3.6400 0.5400 2.9300 + + GATE aoi32 2784.00 O = ! ((a1 * a2 * a3) + (b1 * b2)); + PIN a1 INV 0.1029 999.0 1.0600 3.8100 0.9600 2.9100 + PIN a2 INV 0.1009 999.0 1.2000 3.8100 1.0300 2.9000 + PIN a3 INV 0.1060 999.0 1.2900 3.6900 1.0600 2.9100 + PIN b1 INV 0.0979 999.0 0.9100 3.8100 0.4300 2.1200 + PIN b2 INV 0.1049 999.0 0.7800 3.5900 0.4300 2.1200 + + GATE aoi33 3248.00 O = ! ((a1 * a2 * a3) + (b1 * b2 * b3)); + PIN a1 INV 0.1029 999.0 1.3300 3.9100 1.3000 2.9100 + PIN a2 INV 0.1029 999.0 1.4600 3.8400 1.4100 2.9100 + PIN a3 INV 0.1120 999.0 1.4700 3.6500 1.4100 2.9100 + PIN b1 INV 0.1029 999.0 1.1100 3.5900 0.7600 2.9000 + PIN b2 INV 0.0949 999.0 1.0400 3.9100 0.6800 2.9100 + PIN b3 INV 0.1039 999.0 0.8400 3.5800 0.6400 2.9000 + + GATE aoi211 2320.00 O = ! ((a1 * a2) + b + c); + PIN a1 INV 0.1039 999.0 1.1200 4.8100 1.0300 2.3800 + PIN a2 INV 0.1090 999.0 1.2900 4.8100 1.0300 2.3800 + PIN b INV 0.1080 999.0 1.0400 4.8300 0.5200 1.4000 + PIN c INV 0.1008 999.0 0.6800 4.8300 0.5100 1.7900 + + GATE aoi221 2784.00 O = ! ((a1 * a2) + (b1 * b2) + c); + PIN a1 INV 0.1089 999.0 1.4800 4.4300 1.3300 2.7800 + PIN a2 INV 0.0948 999.0 1.4200 4.5600 1.4000 2.7500 + PIN b1 INV 0.1029 999.0 0.7600 4.4700 0.7900 2.8900 + PIN b2 INV 0.1049 999.0 0.7300 4.5800 0.7800 2.9100 + PIN c INV 0.1110 999.0 1.3900 4.5600 0.7000 1.5100 + + GATE aoi222 3712.00 O = ! ((a1 * a2) + (b1 * b2) + (c1 * c2) ); + PIN a1 INV 0.1019 999.0 1.7700 4.5800 1.5600 2.9500 + PIN a2 INV 0.0958 999.0 1.7300 4.6900 1.6000 2.9300 + PIN b1 INV 0.1039 999.0 1.3400 4.6800 1.2100 2.9200 + PIN b2 INV 0.1039 999.0 1.5000 4.6900 1.2200 2.9200 + PIN c1 INV 0.0958 999.0 0.9200 4.6700 0.8100 2.9200 + PIN c2 INV 0.1039 999.0 0.7700 4.4700 0.7600 2.9200 + + GATE oai21 1856.00 O = ! ( (a1 + a2) * b); + PIN a1 INV 0.1019 999.0 0.6900 3.9400 0.5300 2.4700 + PIN a2 INV 0.0979 999.0 0.8700 3.9300 0.6300 2.4700 + PIN b INV 0.0998 999.0 0.3700 2.0500 0.5700 2.5100 + + GATE oai31 2320.00 O = ! ( (a1 + a2 + a3) * b); + PIN a1 INV 0.1089 999.0 1.2700 4.7100 1.0300 2.4300 + PIN a2 INV 0.1049 999.0 1.1100 4.7100 1.0400 2.5700 + PIN a3 INV 0.1090 999.0 0.8500 4.7100 0.6900 2.3800 + PIN b INV 0.1059 999.0 0.3800 1.8600 0.8100 2.7300 + + GATE oai22 2320.00 O = ! ( (a1 + a2) * (b1 + b2)); + PIN a1 INV 0.1009 999.0 1.1000 4.0600 0.9000 2.5000 + PIN a2 INV 0.1029 999.0 0.9900 4.0600 0.6800 2.3600 + PIN b1 INV 0.0958 999.0 0.6900 3.6600 0.7400 2.5300 + PIN b2 INV 0.1039 999.0 0.6100 3.6600 0.5600 2.0600 + + GATE oai32 2784.00 O = ! ( (a1 + a2 + a3) * (b1 + b2)); + PIN a1 INV 0.1130 999.0 1.3900 4.4600 1.0400 2.4600 + PIN a2 INV 0.1069 999.0 1.2500 4.4600 1.0900 2.6300 + PIN a3 INV 0.1140 999.0 0.9900 4.4600 0.7400 2.4200 + PIN b1 INV 0.1059 999.0 0.5800 3.2000 0.7900 2.7100 + PIN b2 INV 0.1130 999.0 0.6800 3.2100 0.8300 2.3400 + + GATE oai33 3248.00 O = ! ( (a1 + a2 + a3) * (b1 + b2 + b3)); + PIN a1 INV 0.1170 999.0 1.5800 4.3000 1.4800 2.4700 + PIN a2 INV 0.1089 999.0 1.5000 4.3100 1.4200 2.6300 + PIN a3 INV 0.1079 999.0 1.2400 4.3100 1.1700 2.6500 + PIN b1 INV 0.1170 999.0 0.8000 4.3000 0.8200 2.2700 + PIN b2 INV 0.1089 999.0 0.0000 4.3000 1.1700 2.6400 + PIN b3 INV 0.1109 999.0 1.1300 4.3100 1.3500 2.6500 + + GATE oai211 2320.00 O = ! ( (a1 + a2) * b * c); + PIN a1 INV 0.1070 999.0 1.1200 4.1700 0.5900 2.3100 + PIN a2 INV 0.1131 999.0 1.3000 4.1600 0.7900 2.3600 + PIN b INV 0.1050 999.0 0.5100 2.1300 0.6900 2.4000 + PIN c INV 0.1050 999.0 0.5000 2.4600 0.5200 2.4100 + + GATE oai221 2784.00 O = ! ( (a1 + a2) * (b1 + b2) * c); + PIN a1 INV 0.1039 999.0 1.5800 4.1700 1.1100 2.4700 + PIN a2 INV 0.1050 999.0 1.4800 4.1700 0.8600 2.3600 + PIN b1 INV 0.1080 999.0 0.9400 4.0300 0.8100 2.5000 + PIN b2 INV 0.1060 999.0 0.7600 4.0300 0.6400 2.5000 + PIN c INV 0.1019 999.0 0.7800 2.2800 0.9000 2.5400 + + GATE oai222 3248.00 O = ! ( (a1 + a2) * (b1 + b2) * (c1 + c2)); + PIN a1 INV 0.1161 999.0 1.7700 3.7500 1.2100 2.4700 + PIN a2 INV 0.1110 999.0 1.6200 3.7500 1.1300 2.4800 + PIN b1 INV 0.1009 999.0 1.1700 3.5800 1.0700 2.4800 + PIN b2 INV 0.1191 999.0 1.3500 3.5800 1.1000 2.3500 + PIN c1 INV 0.1060 999.0 0.9900 3.5900 0.9300 2.4900 + PIN c2 INV 0.1140 999.0 0.8200 3.5800 0.7900 2.4800 + +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; + +# D-type latches and flip-flops are necessary for sequential +# technology mapping. +# WARNING: area and delay parameters are arbitrary. +LATCH dff 4640.00 Q = D; +PIN D NONINV 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +SEQ Q ANY RISING_EDGE +CONTROL CLOCK 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +CONSTRAINT D 0.1 0.1 + +LATCH dlatch 3712.00 Q = D; +PIN D NONINV 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +SEQ Q ANY ACTIVE_HIGH +CONTROL CLOCK 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +CONSTRAINT D 0.1 0.1 + diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..9c349b9 --- /dev/null +++ b/config.h.in @@ -0,0 +1,98 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_DIRENT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `memcpy' function. */ +#undef HAVE_MEMCPY + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +#undef HAVE_NDIR_H + +/* Define to 1 if you have the `pclose' function. */ +#undef HAVE_PCLOSE + +/* Define to 1 if you have the `popen' function. */ +#undef HAVE_POPEN + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_DIR_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const diff --git a/configure b/configure new file mode 100755 index 0000000..d71d28f --- /dev/null +++ b/configure @@ -0,0 +1,6245 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for SIS 1.3.6. +# +# Report bugs to . +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +# +# +# Copyright (c) 1994-2005 The Regents of the University of California. +# All Rights Reserved. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for educational, research and non-profit purposes, +# without fee, and without a written agreement is hereby granted, +# provided that the above copyright notice, this paragraph and the +# following three paragraphs appear in all copies. +# +# Permission to incorporate this software into commercial products may +# be obtained by contacting the University of California. +# Brian Donohue +# Contracts Administrator +# 6701 San Pablo Avenue #218 +# Berkeley, CA 94720-5600 +# (510) 642-3128 +# donohue@uclink.berkeley.edu +# +# This software program and documentation are copyrighted by The Regents +# of the University of California. The software program and +# documentation are supplied "as is", without any accompanying services +# from The Regents. The Regents does not warrant that the operation of +# the program will be uninterrupted or error-free. The end-user +# understands that the program was developed for research purposes and +# is advised not to rely exclusively on the program for any reason. +# +# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +# INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND +# ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF +# CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" +# BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE +# MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +# +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; 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 + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# 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 + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + 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 + + ;; + 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 + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # 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 sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# 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'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='SIS' +PACKAGE_TARNAME='sis' +PACKAGE_VERSION='1.3.6' +PACKAGE_STRING='SIS 1.3.6' +PACKAGE_BUGREPORT='pchong@ic.eecs.berkeley.edu' + +ac_unique_file="sis/node/node.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO AMTAR install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT YACC LEX LEXLIB LEX_OUTPUT_ROOT LN_S RANLIB ac_ct_RANLIB CPP EGREP SIS_COND_X_TRUE SIS_COND_X_FALSE SIS_COND_CMUBDD_TRUE SIS_COND_CMUBDD_FALSE SIS_COND_UCBBDD_TRUE SIS_COND_UCBBDD_FALSE SIS_COND_CUDD_TRUE SIS_COND_CUDD_FALSE SIS_X_INCLUDES SIS_X_LIBRARIES SIS_CUDDDIR SIS_DOCDIR SIS_HISTDIR SIS_SISLIBDIR LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# 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. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +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 + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -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 | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$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 ;; + + -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 ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + 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 ;; + + -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_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=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 ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + 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'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +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 + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + 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 + + +# 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 its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + 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 + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# 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 SIS 1.3.6 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 \`..'] + +_ACEOF + + cat <<_ACEOF +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] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --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] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +X features: + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of SIS 1.3.6:";; + esac + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-cudd=CUDD_DIR directory with CUDD sources (default: none) + --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 + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +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 +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style 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 + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +SIS configure 1.3.6 +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. + + +Copyright (c) 1994-2005 The Regents of the University of California. +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research and non-profit purposes, +without fee, and without a written agreement is hereby granted, +provided that the above copyright notice, this paragraph and the +following three paragraphs appear in all copies. + +Permission to incorporate this software into commercial products may +be obtained by contacting the University of California. + Brian Donohue + Contracts Administrator + 6701 San Pablo Avenue #218 + Berkeley, CA 94720-5600 + (510) 642-3128 + donohue@uclink.berkeley.edu + +This software program and documentation are copyrighted by The Regents +of the University of California. The software program and +documentation are supplied "as is", without any accompanying services +from The Regents. The Regents does not warrant that the operation of +the program will be uninterrupted or error-free. The end-user +understands that the program was developed for research purposes and +is advised not to rely exclusively on the program for any reason. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND +ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF +CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" +BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by SIS $as_me 1.3.6, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +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` +hostinfo = `(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=. + echo "PATH: $as_dir" +done + +} >&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_sep= +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=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$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 + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export 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: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >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 + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + 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. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +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 `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; 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,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +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 + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`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. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +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 + + + + + + + + + + + + + + + + + + + + + + + + + + + +am__api_version="1.8" +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $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 + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# 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. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_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 + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +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. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$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' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # Keeping the `.' argument allows $(mkdir_p) to be used without + # argument. Indeed, we sometimes output rules like + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. + # (`test -n '$(somedir)' && $(mkdir_p) $(somedir)' is a more + # expensive solution, as it forces Make to start a sub-shell.) + mkdir_p='mkdir -p -- .' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='sis' + VERSION='1.3.6' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. + + + + + ac_config_headers="$ac_config_headers config.h" + + + +# Configuration options. + +enable_cmubdd="yes" +# UCB BDD package breaks power package. +#AC_ARG_ENABLE([ucbbdd], AC_HELP_STRING([--enable-ucbbdd], +# [use UCB BDD package (default: no)]), , [enable_ucbbdd="no"]) + +# Check whether --with-cudd or --without-cudd was given. +if test "${with_cudd+set}" = set; then + withval="$with_cudd" + +else + with_cudd="" +fi; + +# Check configuration consistency. + +if test "$with_cudd" ; then + as_ac_File=`echo "ac_cv_file_"$with_cudd/cudd/cuddInt.h"" | $as_tr_sh` +echo "$as_me:$LINENO: checking for \"$with_cudd/cudd/cuddInt.h\"" >&5 +echo $ECHO_N "checking for \"$with_cudd/cudd/cuddInt.h\"... $ECHO_C" >&6 +if eval "test \"\${$as_ac_File+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + test "$cross_compiling" = yes && + { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 +echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} + { (exit 1); exit 1; }; } +if test -r ""$with_cudd/cudd/cuddInt.h""; then + eval "$as_ac_File=yes" +else + eval "$as_ac_File=no" +fi +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_File'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_File'}'`" >&6 +if test `eval echo '${'$as_ac_File'}'` = yes; then + : +else + { { echo "$as_me:$LINENO: error: cannot find cudd/cuddInt.h in \"$with_cudd\" +use --with-cudd=CUDD_DIR with the correct CUDD source directory" >&5 +echo "$as_me: error: cannot find cudd/cuddInt.h in \"$with_cudd\" +use --with-cudd=CUDD_DIR with the correct CUDD source directory" >&2;} + { (exit 1); exit 1; }; } +fi + + enable_ucbbdd="no" + enable_cmubdd="no" +fi +if test "$enable_ucbbdd" = "yes" ; then + enable_cmubdd="no" +fi + +# Checks for programs. + +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 +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 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}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 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +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 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +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 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_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" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +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 + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + 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 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out 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. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; 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 | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$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 +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* 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 -std1 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 -std1. */ +int osf4_cc_array ['\x00' == 0 ? 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 +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +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 + +for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_YACC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_YACC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + echo "$as_me:$LINENO: result: $YACC" >&5 +echo "${ECHO_T}$YACC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + + +for ac_prog in flex lex +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_LEX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # 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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LEX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +LEX=$ac_cv_prog_LEX +if test -n "$LEX"; then + echo "$as_me:$LINENO: result: $LEX" >&5 +echo "${ECHO_T}$LEX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$LEX" && break +done +test -n "$LEX" || LEX=":" + +if test -z "$LEXLIB" +then + echo "$as_me:$LINENO: checking for yywrap in -lfl" >&5 +echo $ECHO_N "checking for yywrap in -lfl... $ECHO_C" >&6 +if test "${ac_cv_lib_fl_yywrap+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lfl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char yywrap (); +int +main () +{ +yywrap (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_fl_yywrap=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_fl_yywrap=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_fl_yywrap" >&5 +echo "${ECHO_T}$ac_cv_lib_fl_yywrap" >&6 +if test $ac_cv_lib_fl_yywrap = yes; then + LEXLIB="-lfl" +else + echo "$as_me:$LINENO: checking for yywrap in -ll" >&5 +echo $ECHO_N "checking for yywrap in -ll... $ECHO_C" >&6 +if test "${ac_cv_lib_l_yywrap+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ll $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char yywrap (); +int +main () +{ +yywrap (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_l_yywrap=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_l_yywrap=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_l_yywrap" >&5 +echo "${ECHO_T}$ac_cv_lib_l_yywrap" >&6 +if test $ac_cv_lib_l_yywrap = yes; then + LEXLIB="-ll" +fi + +fi + +fi + +if test "x$LEX" != "x:"; then + echo "$as_me:$LINENO: checking lex output file root" >&5 +echo $ECHO_N "checking lex output file root... $ECHO_C" >&6 +if test "${ac_cv_prog_lex_root+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # The minimal lex program is just a single line: %%. But some broken lexes +# (Solaris, I think it was) want two %% lines, so accommodate them. +cat >conftest.l <<_ACEOF +%% +%% +_ACEOF +{ (eval echo "$as_me:$LINENO: \"$LEX conftest.l\"") >&5 + (eval $LEX conftest.l) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5 +echo "$as_me: error: cannot find output from $LEX; giving up" >&2;} + { (exit 1); exit 1; }; } +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5 +echo "${ECHO_T}$ac_cv_prog_lex_root" >&6 +rm -f conftest.l +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5 +echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6 +if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c +ac_save_LIBS=$LIBS +LIBS="$LIBS $LEXLIB" +cat >conftest.$ac_ext <<_ACEOF +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_lex_yytext_pointer=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_save_LIBS +rm -f "${LEX_OUTPUT_ROOT}.c" + +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5 +echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6 +if test $ac_cv_prog_lex_yytext_pointer = yes; then + +cat >>confdefs.h <<\_ACEOF +#define YYTEXT_POINTER 1 +_ACEOF + +fi + +fi +if test "$LEX" = :; then + LEX=${am_missing_run}flex +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. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_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 + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +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. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$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' + +echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6 +fi + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +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 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}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 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +# Checks for libraries. + +#AC_CHECK_LIB([m], [sqrt]) + +# Checks for header files. + +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 +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f 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 +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +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 + + +echo "$as_me:$LINENO: checking for X" >&5 +echo $ECHO_N "checking for X... $ECHO_C" >&6 + + +# Check whether --with-x or --without-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 + if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then + # Both variables are already set. + have_x=yes + else + if test "${ac_cv_have_x+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 -fr conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + # Make sure to not put "make" in the Imakefile rules, since we grep it out. + cat >Imakefile <<'_ACEOF' +acfindx: + @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' +_ACEOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl; 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) ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /lib) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -fr 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/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/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 Intrinsic.h. + # First, try using that file with no special directory specified. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # We can compile using X headers with no special include directory. +ac_x_includes= +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Intrinsic.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi +rm -f conftest.err 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="-lXt $LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +XtMalloc (0) + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +LIBS=$ac_save_LIBS +for ac_dir in `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; do + if test -r $ac_dir/libXt.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +if test "$ac_x_includes" = no || test "$ac_x_libraries" = no; then + # Didn't find X anywhere. Cache the known absence of X. + ac_cv_have_x="have_x=no" +else + # 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" +fi +fi + + fi + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + echo "$as_me:$LINENO: result: $have_x" >&5 +echo "${ECHO_T}$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" + echo "$as_me:$LINENO: result: libraries $x_libraries, headers $x_includes" >&5 +echo "${ECHO_T}libraries $x_libraries, headers $x_includes" >&6 +fi + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f 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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#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)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + + + + + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + as_ac_Header=`echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5 +echo $ECHO_N "checking for $ac_hdr that defines DIR... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include <$ac_hdr> + +int +main () +{ +if ((DIR *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 +_ACEOF + +ac_header_dirent=$ac_hdr; break +fi + +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then + echo "$as_me:$LINENO: checking for library containing opendir" >&5 +echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6 +if test "${ac_cv_search_opendir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_opendir=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_opendir" = no; then + for ac_lib in dir; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 +echo "${ECHO_T}$ac_cv_search_opendir" >&6 +if test "$ac_cv_search_opendir" != no; then + test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS" + +fi + +else + echo "$as_me:$LINENO: checking for library containing opendir" >&5 +echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6 +if test "${ac_cv_search_opendir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_opendir=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_opendir" = no; then + for ac_lib in x; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 +echo "${ECHO_T}$ac_cv_search_opendir" >&6 +if test "$ac_cv_search_opendir" != no; then + test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS" + +fi + +fi + +echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5 +echo $ECHO_N "checking for sys/wait.h that is POSIX.1 compatible... $ECHO_C" >&6 +if test "${ac_cv_header_sys_wait_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +int +main () +{ + int s; + wait (&s); + s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_sys_wait_h=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_sys_wait_h=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_wait_h" >&6 +if test $ac_cv_header_sys_wait_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SYS_WAIT_H 1 +_ACEOF + +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=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to pchong@ic.eecs.berkeley.edu ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +#AC_CHECK_HEADERS([fcntl.h limits.h memory.h sgtty.h stddef.h \ +# strings.h sys/file.h sys/ioctl.h sys/param.h sys/time.h termio.h \ +# termios.h]) + +# Checks for typedefs, structures, and compiler characteristics. + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + + +# Checks for library functions. + +echo "$as_me:$LINENO: checking return type of signal handlers" >&5 +echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6 +if test "${ac_cv_type_signal+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#ifdef signal +# undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_signal=void +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_signal=int +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 +echo "${ECHO_T}$ac_cv_type_signal" >&6 + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + + + + + + + +for ac_func in memcpy memset pclose popen strchr strrchr +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* 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_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +# Generate variables. + + + +if test -z "$no_x"; then + SIS_COND_X_TRUE= + SIS_COND_X_FALSE='#' +else + SIS_COND_X_TRUE='#' + SIS_COND_X_FALSE= +fi + + + +if test "$enable_cmubdd" = "yes"; then + SIS_COND_CMUBDD_TRUE= + SIS_COND_CMUBDD_FALSE='#' +else + SIS_COND_CMUBDD_TRUE='#' + SIS_COND_CMUBDD_FALSE= +fi + + + +if test "$enable_ucbbdd" = "yes"; then + SIS_COND_UCBBDD_TRUE= + SIS_COND_UCBBDD_FALSE='#' +else + SIS_COND_UCBBDD_TRUE='#' + SIS_COND_UCBBDD_FALSE= +fi + + + +if test "$with_cudd"; then + SIS_COND_CUDD_TRUE= + SIS_COND_CUDD_FALSE='#' +else + SIS_COND_CUDD_TRUE='#' + SIS_COND_CUDD_FALSE= +fi + + +SIS_X_INCLUDES="$x_includes" + +SIS_X_LIBRARIES="$x_libraries" + +SIS_CUDDDIR="$with_cudd" + + +SIS_DOCDIR="$datadir/$PACKAGE/doc" + +SIS_HISTDIR="$datadir/$PACKAGE/historical" + +SIS_SISLIBDIR="$datadir/$PACKAGE/sis_lib" + + +# Generate output. + + ac_config_files="$ac_config_files Makefile blif2vst/Makefile doc/Makefile espresso/Makefile espresso/examples/Makefile jedi/Makefile nova/Makefile options/Makefile port/Makefile sis/Makefile sis/array/Makefile sis/astg/Makefile sis/atpg/Makefile sis/avl/Makefile sis/bdd_cmu/Makefile sis/bdd_cmu/bdd_cmu/Makefile sis/bdd_cmu/bdd_port/Makefile sis/bdd_cmu/mem/Makefile sis/bdd_cudd/Makefile sis/bdd_ucb/Makefile sis/clock/Makefile sis/command/Makefile sis/decomp/Makefile sis/delay/Makefile sis/doc/Makefile sis/enc/Makefile sis/error/Makefile sis/espresso/Makefile sis/extract/Makefile sis/factor/Makefile sis/gcd/Makefile sis/genlib/Makefile sis/graph/Makefile sis/graphics/Makefile sis/include/Makefile sis/io/Makefile sis/latch/Makefile sis/linsolv/Makefile sis/list/Makefile sis/lsort/Makefile sis/main/Makefile sis/map/Makefile sis/maxflow/Makefile sis/mincov/Makefile sis/minimize/Makefile sis/network/Makefile sis/node/Makefile sis/ntbdd/Makefile sis/octio/Makefile sis/order/Makefile sis/phase/Makefile sis/pld/Makefile sis/power/Makefile sis/resub/Makefile sis/retime/Makefile sis/seqbdd/Makefile sis/sim/Makefile sis/simplify/Makefile sis/sis_lib/Makefile sis/sis_lib/help/Makefile sis/sparse/Makefile sis/speed/Makefile sis/st/Makefile sis/stg/Makefile sis/test/Makefile sis/timing/Makefile sis/util/Makefile sis/var_set/Makefile sred/Makefile stamina/Makefile stamina/hash/Makefile stamina/mimi/Makefile utility/Makefile vst2blif/Makefile xsis/Makefile" + +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, don't put newlines in cache variables' values. +# 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. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *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 \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + 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}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ 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[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${SIS_COND_X_TRUE}" && test -z "${SIS_COND_X_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"SIS_COND_X\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"SIS_COND_X\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${SIS_COND_CMUBDD_TRUE}" && test -z "${SIS_COND_CMUBDD_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"SIS_COND_CMUBDD\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"SIS_COND_CMUBDD\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${SIS_COND_UCBBDD_TRUE}" && test -z "${SIS_COND_UCBBDD_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"SIS_COND_UCBBDD\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"SIS_COND_UCBBDD\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${SIS_COND_CUDD_TRUE}" && test -z "${SIS_COND_CUDD_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"SIS_COND_CUDD\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"SIS_COND_CUDD\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $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} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; 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 + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# 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 + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + 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 + + ;; + 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 + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # 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 sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# 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'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by SIS $as_me 1.3.6, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet 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 + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +SIS config.status 1.3.6 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +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=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + 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 +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "blif2vst/Makefile" ) CONFIG_FILES="$CONFIG_FILES blif2vst/Makefile" ;; + "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "espresso/Makefile" ) CONFIG_FILES="$CONFIG_FILES espresso/Makefile" ;; + "espresso/examples/Makefile" ) CONFIG_FILES="$CONFIG_FILES espresso/examples/Makefile" ;; + "jedi/Makefile" ) CONFIG_FILES="$CONFIG_FILES jedi/Makefile" ;; + "nova/Makefile" ) CONFIG_FILES="$CONFIG_FILES nova/Makefile" ;; + "options/Makefile" ) CONFIG_FILES="$CONFIG_FILES options/Makefile" ;; + "port/Makefile" ) CONFIG_FILES="$CONFIG_FILES port/Makefile" ;; + "sis/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/Makefile" ;; + "sis/array/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/array/Makefile" ;; + "sis/astg/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/astg/Makefile" ;; + "sis/atpg/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/atpg/Makefile" ;; + "sis/avl/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/avl/Makefile" ;; + "sis/bdd_cmu/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/bdd_cmu/Makefile" ;; + "sis/bdd_cmu/bdd_cmu/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/bdd_cmu/bdd_cmu/Makefile" ;; + "sis/bdd_cmu/bdd_port/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/bdd_cmu/bdd_port/Makefile" ;; + "sis/bdd_cmu/mem/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/bdd_cmu/mem/Makefile" ;; + "sis/bdd_cudd/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/bdd_cudd/Makefile" ;; + "sis/bdd_ucb/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/bdd_ucb/Makefile" ;; + "sis/clock/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/clock/Makefile" ;; + "sis/command/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/command/Makefile" ;; + "sis/decomp/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/decomp/Makefile" ;; + "sis/delay/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/delay/Makefile" ;; + "sis/doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/doc/Makefile" ;; + "sis/enc/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/enc/Makefile" ;; + "sis/error/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/error/Makefile" ;; + "sis/espresso/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/espresso/Makefile" ;; + "sis/extract/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/extract/Makefile" ;; + "sis/factor/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/factor/Makefile" ;; + "sis/gcd/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/gcd/Makefile" ;; + "sis/genlib/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/genlib/Makefile" ;; + "sis/graph/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/graph/Makefile" ;; + "sis/graphics/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/graphics/Makefile" ;; + "sis/include/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/include/Makefile" ;; + "sis/io/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/io/Makefile" ;; + "sis/latch/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/latch/Makefile" ;; + "sis/linsolv/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/linsolv/Makefile" ;; + "sis/list/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/list/Makefile" ;; + "sis/lsort/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/lsort/Makefile" ;; + "sis/main/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/main/Makefile" ;; + "sis/map/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/map/Makefile" ;; + "sis/maxflow/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/maxflow/Makefile" ;; + "sis/mincov/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/mincov/Makefile" ;; + "sis/minimize/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/minimize/Makefile" ;; + "sis/network/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/network/Makefile" ;; + "sis/node/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/node/Makefile" ;; + "sis/ntbdd/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/ntbdd/Makefile" ;; + "sis/octio/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/octio/Makefile" ;; + "sis/order/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/order/Makefile" ;; + "sis/phase/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/phase/Makefile" ;; + "sis/pld/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/pld/Makefile" ;; + "sis/power/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/power/Makefile" ;; + "sis/resub/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/resub/Makefile" ;; + "sis/retime/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/retime/Makefile" ;; + "sis/seqbdd/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/seqbdd/Makefile" ;; + "sis/sim/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/sim/Makefile" ;; + "sis/simplify/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/simplify/Makefile" ;; + "sis/sis_lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/sis_lib/Makefile" ;; + "sis/sis_lib/help/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/sis_lib/help/Makefile" ;; + "sis/sparse/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/sparse/Makefile" ;; + "sis/speed/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/speed/Makefile" ;; + "sis/st/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/st/Makefile" ;; + "sis/stg/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/stg/Makefile" ;; + "sis/test/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/test/Makefile" ;; + "sis/timing/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/timing/Makefile" ;; + "sis/util/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/util/Makefile" ;; + "sis/var_set/Makefile" ) CONFIG_FILES="$CONFIG_FILES sis/var_set/Makefile" ;; + "sred/Makefile" ) CONFIG_FILES="$CONFIG_FILES sred/Makefile" ;; + "stamina/Makefile" ) CONFIG_FILES="$CONFIG_FILES stamina/Makefile" ;; + "stamina/hash/Makefile" ) CONFIG_FILES="$CONFIG_FILES stamina/hash/Makefile" ;; + "stamina/mimi/Makefile" ) CONFIG_FILES="$CONFIG_FILES stamina/mimi/Makefile" ;; + "utility/Makefile" ) CONFIG_FILES="$CONFIG_FILES utility/Makefile" ;; + "vst2blif/Makefile" ) CONFIG_FILES="$CONFIG_FILES vst2blif/Makefile" ;; + "xsis/Makefile" ) CONFIG_FILES="$CONFIG_FILES xsis/Makefile" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + 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 + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CYGPATH_W@,$CYGPATH_W,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@AMTAR@,$AMTAR,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@mkdir_p@,$mkdir_p,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@am__leading_dot@,$am__leading_dot,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@YACC@,$YACC,;t t +s,@LEX@,$LEX,;t t +s,@LEXLIB@,$LEXLIB,;t t +s,@LEX_OUTPUT_ROOT@,$LEX_OUTPUT_ROOT,;t t +s,@LN_S@,$LN_S,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@SIS_COND_X_TRUE@,$SIS_COND_X_TRUE,;t t +s,@SIS_COND_X_FALSE@,$SIS_COND_X_FALSE,;t t +s,@SIS_COND_CMUBDD_TRUE@,$SIS_COND_CMUBDD_TRUE,;t t +s,@SIS_COND_CMUBDD_FALSE@,$SIS_COND_CMUBDD_FALSE,;t t +s,@SIS_COND_UCBBDD_TRUE@,$SIS_COND_UCBBDD_TRUE,;t t +s,@SIS_COND_UCBBDD_FALSE@,$SIS_COND_UCBBDD_FALSE,;t t +s,@SIS_COND_CUDD_TRUE@,$SIS_COND_CUDD_TRUE,;t t +s,@SIS_COND_CUDD_FALSE@,$SIS_COND_CUDD_FALSE,;t t +s,@SIS_X_INCLUDES@,$SIS_X_INCLUDES,;t t +s,@SIS_X_LIBRARIES@,$SIS_X_LIBRARIES,;t t +s,@SIS_CUDDDIR@,$SIS_CUDDDIR,;t t +s,@SIS_DOCDIR@,$SIS_DOCDIR,;t t +s,@SIS_HISTDIR@,$SIS_HISTDIR,;t t +s,@SIS_SISLIBDIR@,$SIS_SISLIBDIR,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # 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. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;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,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # 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. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +# Compute $ac_file's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $ac_file | $ac_file:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null || +$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X$ac_file : 'X\(//\)[^/]' \| \ + X$ac_file : 'X\(//\)$' \| \ + X$ac_file : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X$ac_file | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'`/stamp-h$_am_stamp_count +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# 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 || { (exit 1); exit 1; } +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..b56992a --- /dev/null +++ b/configure.ac @@ -0,0 +1,196 @@ +# Initialization. + +AC_PREREQ([2.5]) +AC_INIT([SIS], [1.3.6], [pchong@ic.eecs.berkeley.edu]) +AM_INIT_AUTOMAKE([foreign no-dependencies]) +AC_CONFIG_SRCDIR([sis/node/node.c]) +AM_CONFIG_HEADER([config.h]) +AC_COPYRIGHT([ +Copyright (c) 1994-2005 The Regents of the University of California. +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research and non-profit purposes, +without fee, and without a written agreement is hereby granted, +provided that the above copyright notice, this paragraph and the +following three paragraphs appear in all copies. + +Permission to incorporate this software into commercial products may +be obtained by contacting the University of California. + Brian Donohue + Contracts Administrator + 6701 San Pablo Avenue #218 + Berkeley, CA 94720-5600 + (510) 642-3128 + donohue@uclink.berkeley.edu + +This software program and documentation are copyrighted by The Regents +of the University of California. The software program and +documentation are supplied "as is", without any accompanying services +from The Regents. The Regents does not warrant that the operation of +the program will be uninterrupted or error-free. The end-user +understands that the program was developed for research purposes and +is advised not to rely exclusively on the program for any reason. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND +ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF +CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" +BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +]) + +# Configuration options. + +enable_cmubdd="yes" +# UCB BDD package breaks power package. +#AC_ARG_ENABLE([ucbbdd], AC_HELP_STRING([--enable-ucbbdd], +# [use UCB BDD package (default: no)]), , [enable_ucbbdd="no"]) +AC_ARG_WITH([cudd], AC_HELP_STRING([--with-cudd=CUDD_DIR], + [directory with CUDD sources (default: none)]), , [with_cudd=""]) + +# Check configuration consistency. + +if test "$with_cudd" ; then + AC_CHECK_FILE(["$with_cudd/cudd/cuddInt.h"], , + AC_MSG_ERROR([cannot find cudd/cuddInt.h in "$with_cudd" +use --with-cudd=CUDD_DIR with the correct CUDD source directory])) + enable_ucbbdd="no" + enable_cmubdd="no" +fi +if test "$enable_ucbbdd" = "yes" ; then + enable_cmubdd="no" +fi + +# Checks for programs. + +AC_LANG([C]) +AC_PROG_CC +AC_PROG_YACC +AM_PROG_LEX +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_RANLIB + +# Checks for libraries. + +#AC_CHECK_LIB([m], [sqrt]) + +# Checks for header files. + +AC_PATH_X +AC_HEADER_STDC +AC_HEADER_DIRENT +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([unistd.h]) +#AC_CHECK_HEADERS([fcntl.h limits.h memory.h sgtty.h stddef.h \ +# strings.h sys/file.h sys/ioctl.h sys/param.h sys/time.h termio.h \ +# termios.h]) + +# Checks for typedefs, structures, and compiler characteristics. + +AC_C_CONST + +# Checks for library functions. + +AC_TYPE_SIGNAL +AC_CHECK_FUNCS([memcpy memset pclose popen strchr strrchr]) + +# Generate variables. + +AM_CONDITIONAL([SIS_COND_X], [test -z "$no_x"]) +AM_CONDITIONAL([SIS_COND_CMUBDD], [test "$enable_cmubdd" = "yes"]) +AM_CONDITIONAL([SIS_COND_UCBBDD], [test "$enable_ucbbdd" = "yes"]) +AM_CONDITIONAL([SIS_COND_CUDD], [test "$with_cudd"]) + +AC_SUBST([SIS_X_INCLUDES], ["$x_includes"]) +AC_SUBST([SIS_X_LIBRARIES], ["$x_libraries"]) +AC_SUBST([SIS_CUDDDIR], ["$with_cudd"]) + +AC_SUBST([SIS_DOCDIR], ["$datadir/$PACKAGE/doc"]) +AC_SUBST([SIS_HISTDIR], ["$datadir/$PACKAGE/historical"]) +AC_SUBST([SIS_SISLIBDIR], ["$datadir/$PACKAGE/sis_lib"]) + +# Generate output. + +AC_CONFIG_FILES([Makefile + blif2vst/Makefile + doc/Makefile + espresso/Makefile + espresso/examples/Makefile + jedi/Makefile + nova/Makefile + options/Makefile + port/Makefile + sis/Makefile + sis/array/Makefile + sis/astg/Makefile + sis/atpg/Makefile + sis/avl/Makefile + sis/bdd_cmu/Makefile + sis/bdd_cmu/bdd_cmu/Makefile + sis/bdd_cmu/bdd_port/Makefile + sis/bdd_cmu/mem/Makefile + sis/bdd_cudd/Makefile + sis/bdd_ucb/Makefile + sis/clock/Makefile + sis/command/Makefile + sis/decomp/Makefile + sis/delay/Makefile + sis/doc/Makefile + sis/enc/Makefile + sis/error/Makefile + sis/espresso/Makefile + sis/extract/Makefile + sis/factor/Makefile + sis/gcd/Makefile + sis/genlib/Makefile + sis/graph/Makefile + sis/graphics/Makefile + sis/include/Makefile + sis/io/Makefile + sis/latch/Makefile + sis/linsolv/Makefile + sis/list/Makefile + sis/lsort/Makefile + sis/main/Makefile + sis/map/Makefile + sis/maxflow/Makefile + sis/mincov/Makefile + sis/minimize/Makefile + sis/network/Makefile + sis/node/Makefile + sis/ntbdd/Makefile + sis/octio/Makefile + sis/order/Makefile + sis/phase/Makefile + sis/pld/Makefile + sis/power/Makefile + sis/resub/Makefile + sis/retime/Makefile + sis/seqbdd/Makefile + sis/sim/Makefile + sis/simplify/Makefile + sis/sis_lib/Makefile + sis/sis_lib/help/Makefile + sis/sparse/Makefile + sis/speed/Makefile + sis/st/Makefile + sis/stg/Makefile + sis/test/Makefile + sis/timing/Makefile + sis/util/Makefile + sis/var_set/Makefile + sred/Makefile + stamina/Makefile + stamina/hash/Makefile + stamina/mimi/Makefile + utility/Makefile + vst2blif/Makefile + xsis/Makefile]) +AC_OUTPUT diff --git a/doc/BUGS b/doc/BUGS new file mode 100644 index 0000000..a0670bd --- /dev/null +++ b/doc/BUGS @@ -0,0 +1,124 @@ +(1) simulate + There is just the matter of the simulate command inside SIS... I +believe there is an inconsistency between the simulation of the STG and the +network when the network has a clock input and the STG does not. + + One might also modify the input to the simulate command to allow for +input values like "r" and "f" to be specified for the clock. The reason +for doing so is to handle the simulation of multi-phase circuits. We +might want to update the state-vector for those latches whose type +(rising/falling) is consistent with the specified value for the clock signal +(r/f). Does this seem like a reasonable thing to do ? + +Example of inconsistent simulation.... +UC Berkeley, SIS Release 1.1 (compiled 29-Nov-93 at 2:39 PM) +sis<2> rl a.blif +Warning: network `bbara.kiss2', node "in_0" does not fanout +Warning: network `bbara.kiss2', node "in_1" does not fanout +Warning: network `bbara.kiss2', node "in_2" does not fanout +Warning: network `bbara.kiss2', node "in_3" does not fanout +Warning: network `bbara.kiss2', node "out_0" is not driven (zero assumed) +Warning: network `bbara.kiss2', node "out_1" is not driven (zero assumed) +Warning: network `bbara.kiss2', node "clk" does not fanout +sis<3> sa jedi +Running jedi, written by Bill Lin, UC Berkeley +sis<5> sim 0 0 0 0 0 + +Network simulation: +Outputs: 0 0 +Next state: 1010 +simulate stg: stg has 4 inputs; 5 values were supplied. +usage: simulate [-s] [-i] in1 in2 in3 ... + +It might be easy to fix. However, when I tried it here I ran into a lot +of problems. One can talk about it to find out what is the best fix... +The problem that is likely to arise, is to simulate the STG when the +state assignment is not done. In that case, the STG does have 4 inputs. + +(2) +All these things came out from the sis project that my students did +this year. Nothing is really urgent. One area that is not very strong in +sis is the simulation capability. One simple way to make it a lot better +would be to provide a command, say print_value, that prints the values +of nodes in a list. This would allow one to inspect internal signals, +and, from my understanding of sis, would be relatively cheap to +implement. + +(3) +#define ST_PTRHASH(x,size) ((int)((unsigned)(x)>>2)%size) + +line 16 in st.c should be + +#define ST_PTRHASH(x,size) ((int)((unsigned)(x)>>3)%size) + +on the alpha to account for ptr size of 8 instead of 4. +So a #ifdef for the alpha case should be added + +(4) +Another nice feature would be to have read_pla have and option +like the -Dmany of espresso. + +(5) +Hi Ellen. Here are some details on the problem I have been having +with the sis atpg command. I have not found any smaller examples which +reproduce this strange behavior. I have no time to look into this +further for a couple of weeks. When is this version of sis scheduled +to be released? + +--------------------------------------------------------------------- +Results using SIS Development Version (compiled 11-May-94 at 2:22 PM), +with the command "atpg -v 1" + +/users/stephan/bm/c38417.blif: + + cad (mips): hangs after about 20 minutes CPU, using 66MB + Last message printed is: + 0 faults remaining + + theseus (alpha): hangs after about 9 minutes CPU, using 87MB + Last message printed is: + 0 faults remaining + + susie (alpha): crashes after about 5 minutes CPU, out of + memory (with 250MB limit). + Last message printed is: + 1987 faults remaining + S_A_0: NODE: I23020 INPUT: g11906 + out of memory allocating 25856 bytes + +/users/stephan/bm/c38584.blif: + + fjord (mips): hangs after about 10 minutes CPU, using 47MB + Last message printed is: + 0 faults remaining + + susie (alpha): crashes after about 6 minutes CPU, out of + memory (with 250MB limit). About 280 faults remaining. + +If sis makes it to the message "0 faults remaining", it seems to hang there +using CPU time without any noticeable change in memory usage for as long as +I let it run (I let one run for an additional 110 CPU minutes). + +(6) + What happens when I use the routine bdd_compose() to replace a +variable, "v", by a function "g" that also depends on the variable "v'. + bdd_compose(f, v, g); + If "g" also depends on the BDD varaiable "v", then I seem to be +getting quite bogus results. I suspect this since some verification task +fails on what are equivalent machines. + + However, if I fist perform a substitution of a variable "u" for +the variable "v" in "f" and then do bdd_compose() the exact same code +works. + bdd_substitute(f, v, u); /*"g" is independent of "u" */ + bdd_compose(f, u, g); + +I was wondering if this is a "bug" or something that should be documented +in the BDD documentation or flagged somehow... + + There is no rush since the workaround works for me... +-kj + +(7) + - xsis exits when _speed_plot buttons are clicked + also _speed_plot -H (I will try the old version) diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..bf51f29 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,4 @@ +histdir = @SIS_HISTDIR@ +dist_hist_DATA = BUGS RELEASE-NOTES SIS_paper.ps SPEC TODO + +EXTRA_DIST = README.INSTALL README.inst diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 0000000..adde5b9 --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,313 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = doc +DIST_COMMON = $(dist_hist_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in TODO +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +am__installdirs = "$(DESTDIR)$(histdir)" +dist_histDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_hist_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +histdir = @SIS_HISTDIR@ +dist_hist_DATA = BUGS RELEASE-NOTES SIS_paper.ps SPEC TODO +EXTRA_DIST = README.INSTALL README.inst +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps doc/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps doc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +install-dist_histDATA: $(dist_hist_DATA) + @$(NORMAL_INSTALL) + test -z "$(histdir)" || $(mkdir_p) "$(DESTDIR)$(histdir)" + @list='$(dist_hist_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_histDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(histdir)/$$f'"; \ + $(dist_histDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(histdir)/$$f"; \ + done + +uninstall-dist_histDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_hist_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(histdir)/$$f'"; \ + rm -f "$(DESTDIR)$(histdir)/$$f"; \ + done +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(histdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_histDATA + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_histDATA uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-dist_histDATA install-exec install-exec-am \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am uninstall uninstall-am uninstall-dist_histDATA \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/doc/README.INSTALL b/doc/README.INSTALL new file mode 100644 index 0000000..534fb6f --- /dev/null +++ b/doc/README.INSTALL @@ -0,0 +1,111 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/doc/README.INSTALL,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:56 $ + * + */ + +*** README file containing INSTALLATION NOTES *** + +*** SIS is free to the public via anonymous ftp, or on tape for a + small fee through the ILP office. PLEASE DO NOT REDISTRIBUTE + SIS in any other manner. *** + +This file contains information about REQUIREMENTS, INSTALLING SIS, +RUNNING SIS, GETTING HELP, and sending COMMENTS TO THE AUTHORS. + +Information about this release of SIS is contained in the file +RELEASE-NOTES-1.2. + +REQUIREMENTS: + +To compile xsis, MIT X11R4 or X11R5 is needed. xsis is based on the +X Toolkit and Athena widget set. If you don't have this, just comment +out the xsis lines in the Makefile. All other sis programs will work +without it. + +INSTALLING SIS: + +SIS is distributed via a single file called sis-1.2.tar.Z. +First uncompress it, then extract the files (the directory +you do this in should have at least 22 MBytes): + +uncompress sis-1.2.tar.Z +tar xf sis-1.2.tar + +You will now have a directory containing all the source code +used in SIS. + +If you do not have the Berkeley OctTools, you will be able to +run everything except the read_oct and write_oct commands in +SIS. If you do not have X11-R4, you will be able to run everything +except the program xsis, which is a front-end graphical interface +to sis. To compile all programs, only the top level Makefile needs +to be edited. + +If you have the Berkeley OctTools: + +Copy the file Makefile.oct to Makefile. Edit the Makefile, +changing the CAD variable to the directory where the OctTools +are installed (the compiler will need CAD/include and CAD/lib). +Set the MACHINE variable to be the machine on which you are compiling +(e.g. mips, vax, rs6000, sun4), set SRCDIR variable to the current +directory, and set the X11 variable to the directory where the X11-R4 +source is (the compiler will need X11/include, X11/include/Xaw, and +X11/lib). If you have any trouble compiling the octio package, +try compiling SIS as though you didn't have the OctTools (see next +section). + +If you do not have the Berkeley OctTools: + +Copy the file Makefile.nooct to Makefile. Edit the Makefile, +setting the variables MACHINE, SRCDIR, and X11 as above. + +Compiling jedi on the RS6000: + +To compile jedi on the RS6000, add -lbsd to the LDFLAGS variable +in the Makefile for jedi (jedi/Makefile). + +Compilint xsis on SUN4: + +To compile xsis on sun4 machines, change the LIBS2 line in the +Makefile to read: +LIBS2 = -L$(X11)/lib -lXaw -Bstatic -lXmu -Bdynamic -lXt -lXext -lX11 -lm + +To compile all the tools, type "make -i" in the top level directory. + +This distribution contains sis, nova (state assignment), jedi +(state assignment), stamina (state minimization, from June Rho +at University of Colorado, Boulder), espresso, xsis (a front-end +graphical interface to sis) and several stripped down packages +from the OctTools (options, port, and utility) that are needed +for some of the programs listed above. + +RUNNING SIS: + +To run sis, with the associated tools, add SIS/bin to your path, +where SIS is the path to this directory. + +GETTING HELP: + +A paper describing the capabilities of sis with some examples of its +use is contained in this directory in postscript format. The file +is SIS_paper.ps. + +The man page for SIS is in sis/sis_lib/help/sis.1. Run-time help can +be obtained by typing "help" while in sis, which will list all +of the available commands. Help for each command can be obtained +by typing "help command_name" while in sis. + +Release notes for this version of SIS are contained in the file +RELEASE-NOTES-1.2. + +COMMENTS TO THE AUTHORS: + +All bugs, feature suggestions, etc should be mailed to +sis@eecs.Berkeley.EDU. + +1 July 1994 Ellen M. Sentovich diff --git a/doc/README.inst b/doc/README.inst new file mode 100644 index 0000000..b0c05ee --- /dev/null +++ b/doc/README.inst @@ -0,0 +1,33 @@ +This is the development version of SIS. + +Makefile is for making a SIS release. It should be run after +the most recent versions of all files have been checked in with +a release name and checked out again (e.g. cd src/sis/atpg; +ci -u -f -n'Rel_name' -m'Release 1.1 of SIS' RCS/*). The release rule +tars the source to a new place, removes all unnecessary stuff, +tars a file and compresses it. +[Note: when sis was put into RCS, 1/9/91, the directories espresso, +jedi, and nova had an RCS directory put in, but no files were checked +in to save space. If and when these files are modified, do the +following sequence inside each direcotry: ci *; rcs -U RCS/*; co RCS/*; +Then edit, and run ci -u files.] +[The directory ex has no RCS control. All the libraries (sis_lib/*.genlib) +and scripts have no RCS control, but this may change. Man pages +(sis_lib/help/*.1) have RCS control.] +[xsis is mostly controlled by Paul Stephan. When the rest of SIS +was put into RCS, all the xsis files were checked in with the symbolic +name Rel1_1] + +TODO is probably only a partial list of things that need to be done. + +ex has combinational and sequential benchmark circuits. + +include has the header files for all SIS packages. + +man has the sis.1 man page and the man pages for the programs +distributed with sis. + +sis_lib has all the sis library stuff. + +src has the source for everything distributed with sis: nova, stamina, jedi, +sis itself, etc. diff --git a/doc/RELEASE-NOTES b/doc/RELEASE-NOTES new file mode 100644 index 0000000..9382de2 --- /dev/null +++ b/doc/RELEASE-NOTES @@ -0,0 +1,103 @@ +*** RELEASE-NOTES-1.3 file containing Release Notes for SIS-1.3 *** + +*** SIS is free to the public via anonymous ftp, or on tape for a + small fee through the ILP office. PLEASE DO NOT REDISTRIBUTE + SIS in any other manner. *** + +RELEASE NOTES FOR SIS 1.3 +------------------------- + +This file contains the following information: + +GENERAL DESCRIPTION OF SIS +DESCRIPTION OF DOCUMENTATION +SUMMARY OF NEW FEATURES FOR SIS 1.3 +RECOMMENDED USE OF SIS + +GENERAL DESCRIPTION OF SIS + +sis is an interactive program for the synthesis of both synchronous +and asynchronous sequential circuits. The input can be given in state +table format or as logical equations (for synchronous circuits), or +as a signal transition graph (for asynchronous circuits); a target +technology library is given in genlib format. The output is a netlist +of gates in the target technology. + +The system includes various capabilities that are controlled interactively +by the user. These include state minimization, state assignment, +optimization for area and delay using retiming, optimization using +standard algebraic and Boolean combinational techniques from MISII, +performance optimization using restructuring, and technology mapping +for optimal area and delay. Redundancy removal and 100% testability +are provided for combinational and scan-path circuits. Formal verification +is available for both combinational and sequential circuits, even for +circuits with different state encodings. + +This distribution contains sis, nova (state assignment), jedi (state +assignment), stamina (state minimization, from June Rho at University of +Colorado, Boulder), sred (state minimization), espresso, blif2vst (mapped +BLIF to structural VHDL translator), vst2blif (structural VHDL to BLIF +translator), xsis (a front-end graphical interface to sis) and several stripped +down packages from the OctTools (options, port, and utility) that are needed +for some of the programs listed above. + +xsis is a graphical interface to sis based on the Athena widget set. +This program provides support for the new command in sis, plot_blif. +(The command plot is no longer available.) It is portable under the +MIT distribution of X11R4 and works with sis versions 1.1 and later. + +To run xsis, first set up the environment variable SIS as instructed +in the README file, then type "xsis". xsis runs a copy of sis as a +child process. After reading in a network, the "plot_blif" command +can be used to plot the network on the screen. For more information, +see the xsis man page, xsis/xsis.1. + +xsis is useful for learning to use sis because the user can plot the +network on the screen to track the changes made to the network during +synthesis, and xsis has a nice graphical help mechanism. +Many circuit examples of all types (combinational, sequential, asynchronous, +etc) can be found in the sis/ex directory. + +DOCUMENTATION + +A paper describing the capabilities of sis with some examples of its +use is contained in this directory in postscript format. The file +is SIS_paper.ps. The paper contains examples showing how to use sis, +and is a good starting point for new users. Note that it describes +SIS release 1.1. This file (RELEASE-NOTES-1.3) contains the updates +for SIS-1.3. + +The man page for sis is in sis/sis_lib/help/sis.1. Run-time help can +be obtained by typing "help" while in sis, which will list all +of the available commands. Help for each command can be obtained +by typing "help command_name" while in sis. + +A description of the BLIF format is in sis/doc/blif.tex, and +a description of the specification that state assignment and +state minimization programs should conform to is in sis/doc/SPEC. + +Each package has a package.doc file describing the exported +functions for that package. + +This file provides an overview of sis-1.3. + +SUMMARY OF NEW FEATURES FOR SIS 1.3 + +RECOMMENDED USE OF SIS + +Several script files are provided with the SIS distribution. +script, script.boolean, and script.algebraic were provided with +MIS, and do combinational optimization. script.rugged calls more +aggressive optimization routines (fx, full_simplify) to do combinational +optimization. It is the recommended script for optimization; EXCEPT +note that many of the routines used in that script use BDDs, which +can be very costly in terms of CPU time and memory for some circuits. +script.delay is an entire script (optimization to mapped netlist) +targeted for minimal delay of the final implementation. It uses new +routines for delay optimization such as reduce_depth (for speed up +before mapping) and fanout optimization with area recovery (part of +the map package). + +Ellen M. Sentovich +UC Berkeley +15 July 1994 diff --git a/doc/SIS_paper.ps b/doc/SIS_paper.ps new file mode 100644 index 0000000..6987a28 Binary files /dev/null and b/doc/SIS_paper.ps differ diff --git a/doc/SPEC b/doc/SPEC new file mode 100644 index 0000000..fadb481 --- /dev/null +++ b/doc/SPEC @@ -0,0 +1,115 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/doc/SPEC,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:56 $ + * + */ +********************* state assignment program format ************* + +Format for State Assignment Programs to follow for incorporation in SIS: + +1) State Assignment Program Requirements + + - The input format is the enhanced KISS2 format (KISS2 with the + added construct .r symbolic name to indicate the reset state). + Input should be taken from stdin. + + - The output format is the enhanced BLIF format. Output should be + directed to stdout. The output information must contain the + resulting encoding (via the .code construct). A multi-level + network may be specified in the output BLIF, in which case the order + of the inputs (in the .inputs command) must correspond to the + order of the bits in the encoding. If no multi-level network is + specified, one is created using the state transition graph and + the encoding. + + - All options are specified on the command line. There is a package + available called the "options" package for making it easy for + the programmer to handle command-line options. The following + options are to be provided by each state assignment program: + + -e : with an argument, indicates the encoding algorithm to be used + -e h : indicates that a one-hot encoding is to be generated + -e r : indicates that random encoding is to be generated. + -n # : # indicates the number of random encodings that are + generated -- the best is selected. + -i : with an integer argument indicates the number of bits to + use in the symbolic input encoding + -s : with an integer argument indicates the number of bits to + use in the symbolic state encoding + -o : with an integer argument indicates the number of bits to + use in the symbolic state encoding + -h : returns a usage message (the options package returns a + usage message when optUsage() is called) + -v : verbose mode -- prints out information about the encoding + process. Information should be printed to stderr only. + + The -e option MUST be used to indicate the encoding algorithm + used. One-hot and random encodings don't have to be provided + by the state assignment program, but if they are, they must + be specified by -e h and -e r respectively. Similarly, the + number of encoding bits doesn't have to be an option to the + program, but if it is, it must be specified with -i for the input + bits, -s for the state bits, and -o for the output bits. + The -h option must be provided. + + - Any temporarily created files should be created in /tmp, not + in the current directory, since the user may not have write + permission in the current directory. There is command called + mktemp that can be used to obtain an unused temporary filename. + This package should be used to avoid naming a file the same + name as an existing file in /tmp. Any temporarily created + files should be removed immediately. An example follows: + + FILE *file; + char buffer[] = "/tmp/SISXXXXXX"; + + mktemp(buffer); + file = fopen(buffer, "w+"); + unlink(buffer); + + /* write information to the file */ + + fflush(file); + rewind(file); + fscanf(file, "%s", string); + fclose(file); + + This example creates a temporary file name with the mktemp + command, opens the file for both reading and writing, then + unlinks the file (which ensures that the file is removed even + if the program fails). The file is then read by first executing + fflush (which ensures that all buffered data that may not have + been written to the file yet is written), rewinding + the file pointer to the beginning of the file, and reading. + Finally, the file is closed when it is no longer needed. + + - A non-zero exit code should be returned if there is an error + during execution, and a 0 exit code returned if no error occurs. + The program must finish with a call to exit (rather than a call + to return). + + - The errors encountered by the program should be sent to stderr + rather than stdout. + + - Any programs the state assignment program calls (i.e. espresso) + should be documented in the manual page. The programs that are + called should be standard, released versions. Any calls to external + programs should not be hard-wired to a particular path in the + code (instead, a variable should be passed down from the top-level + Makefile to the code indicating a path in which to find the + program; or better, a system call should be used, assuming that + the program can be found in the user's path). + +2) General Requirements + + - All programs should be lint-free and contain a manual page + (.1 file). + + - The Makefile for the program should be compliant with the octtools + Makefiles. The program create-octtools-makefile can be used to + create a Makefile with the proper format. + diff --git a/doc/TODO b/doc/TODO new file mode 100644 index 0000000..3d22fc7 --- /dev/null +++ b/doc/TODO @@ -0,0 +1,176 @@ +SIS accepts networks with no real outputs and no real inputs - +this shouldn't happen. + +read_kiss should allow and store multiple reset states. if the reset +state is omitted, how should this be interpreted? + +look over the sim package. Lots of new changes were made in the new MIS. +Does anything need to be changed for SIS? Look especially at interpret.c. + +Add network acyclic commands. + +verify_fsm doesn't take into account the external don't care set. + +unresolved bug reports: + +**** +If your network has latches of type "UNKNOWN" with the control node set, +write_blif will write out a corrupted blif file. The format for a latch is: + +.latch out in type control + +if type is unknown, you end up with + +.latch out in control + +and read_blif tries to interpret control as a type and fails.... + +I think the solution should be: + +write_blif not work on networks with latches of unknown type +(and with a set control node) + +or + +write_blif should write out the type as 'un' and read_blif should +understand this. +**** +**** +Intel Wish List for SIS (from Tzvi) +----------------------- + +SIS will be applied one level above combinational logic - logic +plus registers. May need different levels of abstraction: one for +timing analysis and one for optimization. + +1. Transparent latches: a) delay analysis (Rumin), b) retiming + (clock cycle determination is the only place Leiserson uses the + edge-triggered property) + Retiming for transparent latches can be done (possibly) by + specifying a clock cycle (50MHz, eg), moving latches, and + checking feasibility. + +2. In SIS we also need a global clocking scheme and information about + when each latch is clocked (done). + +3. Technology mapping (need a separate file for timing constraints). + +4. Retiming and resynthesis - for area and performance. + +5. FSM: capability of zooming into an FSM and extracting a subcircuit + (Pranav - identify a subckt, be able to read it in and write it out) + +Also from Tzvi +-------------- + +1. There is a problem with using kiss as an FSM input. What if the + users wants to specify conditions under which to move to a next + state, and then say, otherwise (else), go to the reset state? This + is currently not possible without enumerating the remaining possiblities. + Alberto suggested that PEG or MEG be used - this is a slightly higher + level language that takes care of this problem. + +2. Tzvi wants the latches printed in the print command. The latches + should be printed in some easily-readable way. + +In SIS should we be doing for general chip analysis or target a +technology? These capabilities are needed inside SIS and in the +specification. + +Narendra is working on transparent latches: retiming and Rumin analysis. +Sharad is working on retiming for minimum register count (done). + +From Boulder Workshop +--------------------- + +1. (Fabio Somenzi) Can we retain and manipulate decomposed FSM + structures? + +2. (Gary Hachtel) After doing state minimization, can we verify that the + state-minimized machine is equivalent to the original machine? Should + the state minimization program provide a map of states in the original + machine to states in the minimized machine? + +3. (Wayne Wolfe) Can we manipulate an STG's logic implementation in which + the states are symbolic? (state = multi-valued variable instead of + encoding states) (MIS-MV? BLIF-MV? SIS-MV?) + +4. (Gaetano Borriello) Wish List: + a. multiple clocks, each with their own cycle time + (not just a single multi-phase clocks) + b. "special elements" + generic delay elements (could be a buffer, could be for asynchronous + design) + tristate latch + synchronizers, arbiters + c. multiple-output, multiple-input elements + arbiters + ECL gates + Q, Q bar in latches + + (We eventually need a "black box" element that has several terminals. + What information does it provide to the system? Delays from each input + pin to each output pin? It could be implemented in a similar way to + the latch - po's and pi's which separate it from the rest of the logic. + MIS won't touch it this way.) + +Bell Labs Wish List +------------------- + +1. Must have verification +2. Must handle different clocking schemes +3. Test vectors should be maintained/updated across operations + (i.e. retiming) + +Richard Newton +-------------- + +1. Need to rethink the REPRESENTATION used in SIS (may want hierarchy, + may want to leave parts of the design untouched - it all boils down + to a representation issue) (how do we connect several machines + together?) + +2. Designer will ALWAYS want to interact - can never have a black box + synthesis/optimization tool. + +3. Richard is willing to discuss and help with this. + +General +------- + +1. Do we need a method for representing a negative latch for r and r? + It seems like we should store this information somehow in our own + data structure. + +2. Does retiming need exported routines? For what purpose? + +3. Don't cares - need to save and use don't care information when moving + from an stg to a network. + +4. MIS "forces" outputs. If there are no real po's then MIS forces the + latch inputs to be also real po's. Is this correct? + +5. Are we going to share latches as much as possible at the outputs? + Or at least provide routines for counting the minimum number of + latches? What does the retimed network return? + +6. Or we going to be able to mark "not to be touched" nodes and subcircuits? + +7. Need a SIS policy, then design a library consistent with the policy. + +8. Timing analysis tools should interact with synthesis tools, can't just + optimize for area and thing about timing afterwards. To have + meaningful timing-driven synthesis need to consider timing at all + stages - e.g. during algebraic substitution + +9. delete_latch needs to return a status if deleting the latch would + create a cycle. + +10. Latch package needs the following: latch_min_count (returns the + minimum # of latches, sharing at the outputs), latch_min_convert + (converts the network to configuration with the minimum # of latches) + (the minimum configuration is not necessarily maintained, hence these + functions should be provided). + +11. The hummingbird project should really be pushed. The digital stuff + needs to be pushed along. diff --git a/espresso/Makefile.am b/espresso/Makefile.am new file mode 100644 index 0000000..ad423f9 --- /dev/null +++ b/espresso/Makefile.am @@ -0,0 +1,15 @@ +AM_CPPFLAGS = -I$(top_srcdir)/utility -I$(top_srcdir)/port +LDADD = ../utility/libutility.a + +SUBDIRS = examples + +bin_PROGRAMS = espresso +espresso_SOURCES = cofactor.c cols.c compl.c contain.c cubestr.c \ + cvrin.c cvrm.c cvrmisc.c cvrout.c dominate.c equiv.c espresso.c \ + essen.c exact.c expand.c gasp.c getopt.c gimpel.c globals.c hack.c \ + indep.c irred.c main.c map.c matrix.c mincov.c opo.c pair.c part.c \ + primes.c reduce.c rows.c set.c setc.c sharp.c sminterf.c solution.c \ + sparse.c unate.c verify.c espresso.h main.h mincov.h mincov_int.h \ + sparse.h sparse_int.h +dist_man1_MANS = espresso.1 +dist_man5_MANS = espresso.5 pla.5 diff --git a/espresso/Makefile.in b/espresso/Makefile.in new file mode 100644 index 0000000..e8936e7 --- /dev/null +++ b/espresso/Makefile.in @@ -0,0 +1,606 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(espresso_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = espresso$(EXEEXT) +subdir = espresso +DIST_COMMON = $(dist_man1_MANS) $(dist_man5_MANS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_espresso_OBJECTS = cofactor.$(OBJEXT) cols.$(OBJEXT) \ + compl.$(OBJEXT) contain.$(OBJEXT) cubestr.$(OBJEXT) \ + cvrin.$(OBJEXT) cvrm.$(OBJEXT) cvrmisc.$(OBJEXT) \ + cvrout.$(OBJEXT) dominate.$(OBJEXT) equiv.$(OBJEXT) \ + espresso.$(OBJEXT) essen.$(OBJEXT) exact.$(OBJEXT) \ + expand.$(OBJEXT) gasp.$(OBJEXT) getopt.$(OBJEXT) \ + gimpel.$(OBJEXT) globals.$(OBJEXT) hack.$(OBJEXT) \ + indep.$(OBJEXT) irred.$(OBJEXT) main.$(OBJEXT) map.$(OBJEXT) \ + matrix.$(OBJEXT) mincov.$(OBJEXT) opo.$(OBJEXT) pair.$(OBJEXT) \ + part.$(OBJEXT) primes.$(OBJEXT) reduce.$(OBJEXT) \ + rows.$(OBJEXT) set.$(OBJEXT) setc.$(OBJEXT) sharp.$(OBJEXT) \ + sminterf.$(OBJEXT) solution.$(OBJEXT) sparse.$(OBJEXT) \ + unate.$(OBJEXT) verify.$(OBJEXT) +espresso_OBJECTS = $(am_espresso_OBJECTS) +espresso_LDADD = $(LDADD) +espresso_DEPENDENCIES = ../utility/libutility.a +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(espresso_SOURCES) +DIST_SOURCES = $(espresso_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +man1dir = $(mandir)/man1 +man5dir = $(mandir)/man5 +NROFF = nroff +MANS = $(dist_man1_MANS) $(dist_man5_MANS) +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I$(top_srcdir)/utility -I$(top_srcdir)/port +LDADD = ../utility/libutility.a +SUBDIRS = examples +espresso_SOURCES = cofactor.c cols.c compl.c contain.c cubestr.c \ + cvrin.c cvrm.c cvrmisc.c cvrout.c dominate.c equiv.c espresso.c \ + essen.c exact.c expand.c gasp.c getopt.c gimpel.c globals.c hack.c \ + indep.c irred.c main.c map.c matrix.c mincov.c opo.c pair.c part.c \ + primes.c reduce.c rows.c set.c setc.c sharp.c sminterf.c solution.c \ + sparse.c unate.c verify.c espresso.h main.h mincov.h mincov_int.h \ + sparse.h sparse_int.h + +dist_man1_MANS = espresso.1 +dist_man5_MANS = espresso.5 pla.5 +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps espresso/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps espresso/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +espresso$(EXEEXT): $(espresso_OBJECTS) $(espresso_DEPENDENCIES) + @rm -f espresso$(EXEEXT) + $(LINK) $(espresso_LDFLAGS) $(espresso_OBJECTS) $(espresso_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done +install-man5: $(man5_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man5dir)" || $(mkdir_p) "$(DESTDIR)$(man5dir)" + @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 5*) ;; \ + *) ext='5' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \ + done +uninstall-man5: + @$(NORMAL_UNINSTALL) + @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 5*) ;; \ + *) ext='5' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man5dir)/$$inst"; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || mkdir "$(distdir)/$$subdir" \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="../$(top_distdir)" \ + distdir="../$(distdir)/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(PROGRAMS) $(MANS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-man + +install-exec-am: install-binPROGRAMS + +install-info: install-info-recursive + +install-man: install-man1 install-man5 + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am uninstall-man + +uninstall-info: uninstall-info-recursive + +uninstall-man: uninstall-man1 uninstall-man5 + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-binPROGRAMS clean-generic clean-recursive ctags \ + ctags-recursive distclean distclean-compile distclean-generic \ + distclean-recursive distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-man1 \ + install-man5 install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-binPROGRAMS uninstall-info-am \ + uninstall-man uninstall-man1 uninstall-man5 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/espresso/cofactor.c b/espresso/cofactor.c new file mode 100644 index 0000000..6067f95 --- /dev/null +++ b/espresso/cofactor.c @@ -0,0 +1,382 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/cofactor.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:56 $ + * + */ +#include "espresso.h" + +/* + The cofactor of a cover against a cube "c" is a cover formed by the + cofactor of each cube in the cover against c. The cofactor of two + cubes is null if they are distance 1 or more apart. If they are + distance zero apart, the cofactor is the restriction of the cube + to the minterms of c. + + The cube list contains the following information: + + T[0] = pointer to a cube identifying the variables that have + been cofactored against + T[1] = pointer to just beyond the sentinel (i.e., T[n] in this case) + T[2] + . + . = pointers to cubes + . + T[n-2] + T[n-1] = NULL pointer (sentinel) + + + Cofactoring involves repeated application of "cdist0" to check if a + cube of the cover intersects the cofactored cube. This can be + slow, especially for the recursive descent of the espresso + routines. Therefore, a special cofactor routine "scofactor" is + provided which assumes the cofactor is only in a single variable. +*/ + + +/* cofactor -- compute the cofactor of a cover with respect to a cube */ +pcube *cofactor(T, c) +IN pcube *T; +IN register pcube c; +{ + pcube temp = cube.temp[0], *Tc_save, *Tc, *T1; + register pcube p; + int listlen; + + listlen = CUBELISTSIZE(T) + 5; + + /* Allocate a new list of cube pointers (max size is previous size) */ + Tc_save = Tc = ALLOC(pcube, listlen); + + /* pass on which variables have been cofactored against */ + *Tc++ = set_or(new_cube(), T[0], set_diff(temp, cube.fullset, c)); + Tc++; + + /* Loop for each cube in the list, determine suitability, and save */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (p != c) { + +#ifdef NO_INLINE + if (! cdist0(p, c)) goto false; +#else + {register int w,last;register unsigned int x;if((last=cube.inword)!=-1) + {x=p[last]&c[last];if(~(x|x>>1)&cube.inmask)goto false;for(w=1;w>1)&DISJOINT)goto false;}}}{register int w,var,last; + register pcube mask;for(var=cube.num_binary_vars;var= 0; i--) + count[i] = 0; + } + + /* Count the number of zeros in each column */ + { register int i, *cnt; + register unsigned int val; + register pcube p, cof = T[0], full = cube.fullset; + for(T1 = T+2; (p = *T1++) != NULL; ) + for(i = LOOP(p); i > 0; i--) + if (val = full[i] & ~ (p[i] | cof[i])) { + cnt = count + ((i-1) << LOGBPI); +#if BPI == 32 + if (val & 0xFF000000) { + if (val & 0x80000000) cnt[31]++; + if (val & 0x40000000) cnt[30]++; + if (val & 0x20000000) cnt[29]++; + if (val & 0x10000000) cnt[28]++; + if (val & 0x08000000) cnt[27]++; + if (val & 0x04000000) cnt[26]++; + if (val & 0x02000000) cnt[25]++; + if (val & 0x01000000) cnt[24]++; + } + if (val & 0x00FF0000) { + if (val & 0x00800000) cnt[23]++; + if (val & 0x00400000) cnt[22]++; + if (val & 0x00200000) cnt[21]++; + if (val & 0x00100000) cnt[20]++; + if (val & 0x00080000) cnt[19]++; + if (val & 0x00040000) cnt[18]++; + if (val & 0x00020000) cnt[17]++; + if (val & 0x00010000) cnt[16]++; + } +#endif + if (val & 0xFF00) { + if (val & 0x8000) cnt[15]++; + if (val & 0x4000) cnt[14]++; + if (val & 0x2000) cnt[13]++; + if (val & 0x1000) cnt[12]++; + if (val & 0x0800) cnt[11]++; + if (val & 0x0400) cnt[10]++; + if (val & 0x0200) cnt[ 9]++; + if (val & 0x0100) cnt[ 8]++; + } + if (val & 0x00FF) { + if (val & 0x0080) cnt[ 7]++; + if (val & 0x0040) cnt[ 6]++; + if (val & 0x0020) cnt[ 5]++; + if (val & 0x0010) cnt[ 4]++; + if (val & 0x0008) cnt[ 3]++; + if (val & 0x0004) cnt[ 2]++; + if (val & 0x0002) cnt[ 1]++; + if (val & 0x0001) cnt[ 0]++; + } + } + } + + /* + * Perform counts for each variable: + * cdata.var_zeros[var] = number of zeros in the variable + * cdata.parts_active[var] = number of active parts for each variable + * cdata.vars_active = number of variables which are active + * cdata.vars_unate = number of variables which are active and unate + * + * best -- the variable which is best for splitting based on: + * mostactive -- most # active parts in any variable + * mostzero -- most # zeros in any variable + * mostbalanced -- minimum over the maximum # zeros / part / variable + */ + + { register int var, i, lastbit, active, maxactive; + int best = -1, mostactive = 0, mostzero = 0, mostbalanced = 32000; + cdata.vars_unate = cdata.vars_active = 0; + + for(var = 0; var < cube.num_vars; var++) { + if (var < cube.num_binary_vars) { /* special hack for binary vars */ + i = count[var*2]; + lastbit = count[var*2 + 1]; + active = (i > 0) + (lastbit > 0); + cdata.var_zeros[var] = i + lastbit; + maxactive = MAX(i, lastbit); + } else { + maxactive = active = cdata.var_zeros[var] = 0; + lastbit = cube.last_part[var]; + for(i = cube.first_part[var]; i <= lastbit; i++) { + cdata.var_zeros[var] += count[i]; + active += (count[i] > 0); + if (active > maxactive) maxactive = active; + } + } + + /* first priority is to maximize the number of active parts */ + /* for binary case, this will usually select the output first */ + if (active > mostactive) + best = var, mostactive = active, mostzero = cdata.var_zeros[best], + mostbalanced = maxactive; + else if (active == mostactive) + /* secondary condition is to maximize the number zeros */ + /* for binary variables, this is the same as minimum # of 2's */ + if (cdata.var_zeros[var] > mostzero) + best = var, mostzero = cdata.var_zeros[best], + mostbalanced = maxactive; + else if (cdata.var_zeros[var] == mostzero) + /* third condition is to pick a balanced variable */ + /* for binary vars, this means roughly equal # 0's and 1's */ + if (maxactive < mostbalanced) + best = var, mostbalanced = maxactive; + + cdata.parts_active[var] = active; + cdata.is_unate[var] = (active == 1); + cdata.vars_active += (active > 0); + cdata.vars_unate += (active == 1); + } + cdata.best = best; + } +} + +int binate_split_select(T, cleft, cright, debug_flag) +IN pcube *T; +IN register pcube cleft, cright; +IN int debug_flag; +{ + int best = cdata.best; + register int i, lastbit = cube.last_part[best], halfbit = 0; + register pcube cof=T[0]; + + /* Create the cubes to cofactor against */ + (void) set_diff(cleft, cube.fullset, cube.var_mask[best]); + (void) set_diff(cright, cube.fullset, cube.var_mask[best]); + for(i = cube.first_part[best]; i <= lastbit; i++) + if (! is_in_set(cof,i)) + halfbit++; + for(i = cube.first_part[best], halfbit = halfbit/2; halfbit > 0; i++) + if (! is_in_set(cof,i)) + halfbit--, set_insert(cleft, i); + for(; i <= lastbit; i++) + if (! is_in_set(cof,i)) + set_insert(cright, i); + + if (debug & debug_flag) { + (void) printf("BINATE_SPLIT_SELECT: split against %d\n", best); + if (verbose_debug) + (void) printf("cl=%s\ncr=%s\n", pc1(cleft), pc2(cright)); + } + return best; +} + + +pcube *cube1list(A) +pcover A; +{ + register pcube last, p, *plist, *list; + + list = plist = ALLOC(pcube, A->count + 3); + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + *plist++ = NULL; /* sentinel */ + list[1] = (pcube) plist; + return list; +} + + +pcube *cube2list(A, B) +pcover A, B; +{ + register pcube last, p, *plist, *list; + + list = plist = ALLOC(pcube, A->count + B->count + 3); + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + foreach_set(B, last, p) { + *plist++ = p; + } + *plist++ = NULL; + list[1] = (pcube) plist; + return list; +} + + +pcube *cube3list(A, B, C) +pcover A, B, C; +{ + register pcube last, p, *plist, *list; + + plist = ALLOC(pcube, A->count + B->count + C->count + 3); + list = plist; + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + foreach_set(B, last, p) { + *plist++ = p; + } + foreach_set(C, last, p) { + *plist++ = p; + } + *plist++ = NULL; + list[1] = (pcube) plist; + return list; +} + + +pcover cubeunlist(A1) +pcube *A1; +{ + register int i; + register pcube p, pdest, cof = A1[0]; + register pcover A; + + A = new_cover(CUBELISTSIZE(A1)); + for(i = 2; (p = A1[i]) != NULL; i++) { + pdest = GETSET(A, i-2); + INLINEset_or(pdest, p, cof); + } + A->count = CUBELISTSIZE(A1); + return A; +} + +simplify_cubelist(T) +pcube *T; +{ + register pcube *Tdest; + register int i, ncubes; + + (void) set_copy(cube.temp[0], T[0]); /* retrieve cofactor */ + + ncubes = CUBELISTSIZE(T); + qsort((char *) (T+2), ncubes, sizeof(pset), (int (*)()) d1_order); + + Tdest = T+2; + /* *Tdest++ = T[2]; */ + for(i = 3; i < ncubes; i++) { + if (d1_order(&T[i-1], &T[i]) != 0) { + *Tdest++ = T[i]; + } + } + + *Tdest++ = NULL; /* sentinel */ + Tdest[1] = (pcube) Tdest; /* save pointer to last */ +} diff --git a/espresso/cols.c b/espresso/cols.c new file mode 100644 index 0000000..5d0e7df --- /dev/null +++ b/espresso/cols.c @@ -0,0 +1,314 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/cols.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "port.h" +#include "sparse_int.h" + + +/* + * allocate a new col vector + */ +sm_col * +sm_col_alloc() +{ + register sm_col *pcol; + +#ifdef FAST_AND_LOOSE + if (sm_col_freelist == NIL(sm_col)) { + pcol = ALLOC(sm_col, 1); + } else { + pcol = sm_col_freelist; + sm_col_freelist = pcol->next_col; + } +#else + pcol = ALLOC(sm_col, 1); +#endif + + pcol->col_num = 0; + pcol->length = 0; + pcol->first_row = pcol->last_row = NIL(sm_element); + pcol->next_col = pcol->prev_col = NIL(sm_col); + pcol->flag = 0; + pcol->user_word = NIL(char); /* for our user ... */ + return pcol; +} + + +/* + * free a col vector -- for FAST_AND_LOOSE, this is real cheap for cols; + * however, freeing a rowumn must still walk down the rowumn discarding + * the elements one-by-one; that is the only use for the extra '-DCOLS' + * compile flag ... + */ +void +sm_col_free(pcol) +register sm_col *pcol; +{ +#if defined(FAST_AND_LOOSE) && ! defined(COLS) + if (pcol->first_row != NIL(sm_element)) { + /* Add the linked list of col items to the free list */ + pcol->last_row->next_row = sm_element_freelist; + sm_element_freelist = pcol->first_row; + } + + /* Add the col to the free list of cols */ + pcol->next_col = sm_col_freelist; + sm_col_freelist = pcol; +#else + register sm_element *p, *pnext; + + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; + sm_element_free(p); + } + FREE(pcol); +#endif +} + + +/* + * duplicate an existing col + */ +sm_col * +sm_col_dup(pcol) +register sm_col *pcol; +{ + register sm_col *pnew; + register sm_element *p; + + pnew = sm_col_alloc(); + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) sm_col_insert(pnew, p->row_num); + } + return pnew; +} + + +/* + * insert an element into a col vector + */ +sm_element * +sm_col_insert(pcol, row) +register sm_col *pcol; +register int row; +{ + register sm_element *test, *element; + + /* get a new item, save its address */ + sm_element_alloc(element); + test = element; + sorted_insert(sm_element, pcol->first_row, pcol->last_row, pcol->length, + next_row, prev_row, row_num, row, test); + + /* if item was not used, free it */ + if (element != test) { + sm_element_free(element); + } + + /* either way, return the current new value */ + return test; +} + + +/* + * remove an element from a col vector + */ +void +sm_col_remove(pcol, row) +register sm_col *pcol; +register int row; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0 && p->row_num < row; p = p->next_row) + ; + if (p != 0 && p->row_num == row) { + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + sm_element_free(p); + } +} + + +/* + * find an element (if it is in the col vector) + */ +sm_element * +sm_col_find(pcol, row) +sm_col *pcol; +int row; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0 && p->row_num < row; p = p->next_row) + ; + if (p != 0 && p->row_num == row) { + return p; + } else { + return NIL(sm_element); + } +} + +/* + * return 1 if col p2 contains col p1; 0 otherwise + */ +int +sm_col_contains(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + while (q1 != 0) { + if (q2 == 0 || q1->row_num < q2->row_num) { + return 0; + } else if (q1->row_num == q2->row_num) { + q1 = q1->next_row; + q2 = q2->next_row; + } else { + q2 = q2->next_row; + } + } + return 1; +} + + +/* + * return 1 if col p1 and col p2 share an element in common + */ +int +sm_col_intersects(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + if (q1 == 0 || q2 == 0) return 0; + for(;;) { + if (q1->row_num < q2->row_num) { + if ((q1 = q1->next_row) == 0) { + return 0; + } + } else if (q1->row_num > q2->row_num) { + if ((q2 = q2->next_row) == 0) { + return 0; + } + } else { + return 1; + } + } +} + + +/* + * compare two cols, lexical ordering + */ +int +sm_col_compare(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + while(q1 != 0 && q2 != 0) { + if (q1->row_num != q2->row_num) { + return q1->row_num - q2->row_num; + } + q1 = q1->next_row; + q2 = q2->next_row; + } + + if (q1 != 0) { + return 1; + } else if (q2 != 0) { + return -1; + } else { + return 0; + } +} + + +/* + * return the intersection + */ +sm_col * +sm_col_and(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + register sm_col *result; + + result = sm_col_alloc(); + q1 = p1->first_row; + q2 = p2->first_row; + if (q1 == 0 || q2 == 0) return result; + for(;;) { + if (q1->row_num < q2->row_num) { + if ((q1 = q1->next_row) == 0) { + return result; + } + } else if (q1->row_num > q2->row_num) { + if ((q2 = q2->next_row) == 0) { + return result; + } + } else { + (void) sm_col_insert(result, q1->row_num); + if ((q1 = q1->next_row) == 0) { + return result; + } + if ((q2 = q2->next_row) == 0) { + return result; + } + } + } +} + +int +sm_col_hash(pcol, modulus) +sm_col *pcol; +int modulus; +{ + register int sum; + register sm_element *p; + + sum = 0; + for(p = pcol->first_row; p != 0; p = p->next_row) { + sum = (sum*17 + p->row_num) % modulus; + } + return sum; +} + +/* + * remove an element from a col vector (given a pointer to the element) + */ +void +sm_col_remove_element(pcol, p) +register sm_col *pcol; +register sm_element *p; +{ + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + sm_element_free(p); +} + + +void +sm_col_print(fp, pcol) +FILE *fp; +sm_col *pcol; +{ + sm_element *p; + + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) fprintf(fp, " %d", p->row_num); + } +} diff --git a/espresso/compl.c b/espresso/compl.c new file mode 100644 index 0000000..315635e --- /dev/null +++ b/espresso/compl.c @@ -0,0 +1,680 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/compl.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + * module: compl.c + * purpose: compute the complement of a multiple-valued function + * + * The "unate recursive paradigm" is used. After a set of special + * cases are examined, the function is split on the "most active + * variable". These two halves are complemented recursively, and then + * the results are merged. + * + * Changes (from Version 2.1 to Version 2.2) + * 1. Minor bug in compl_lifting -- cubes in the left half were + * not marked as active, so that when merging a leaf from the left + * hand side, the active flags were essentially random. This led + * to minor impredictability problem, but never affected the + * accuracy of the results. + */ + +#include "espresso.h" + +#define USE_COMPL_LIFT 0 +#define USE_COMPL_LIFT_ONSET 1 +#define USE_COMPL_LIFT_ONSET_COMPLEX 2 +#define NO_LIFTING 3 + +static bool compl_special_cases(); +static pcover compl_merge(); +static void compl_d1merge(); +static pcover compl_cube(); +static void compl_lift(); +static void compl_lift_onset(); +static void compl_lift_onset_complex(); +static bool simp_comp_special_cases(); +static bool simplify_special_cases(); + + +/* complement -- compute the complement of T */ +pcover complement(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tbar, Tl, Tr; + int lifting; + static int compl_level = 0; + + if (debug & COMPL) + debug_print(T, "COMPLEMENT", compl_level++); + + if (compl_special_cases(T, &Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + Tl = complement(scofactor(T, cl, best)); + Tr = complement(scofactor(T, cr, best)); + + if (Tr->count*Tl->count > (Tr->count+Tl->count)*CUBELISTSIZE(T)) { + lifting = USE_COMPL_LIFT_ONSET; + } else { + lifting = USE_COMPL_LIFT; + } + Tbar = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) + debug1_print(Tbar, "exit COMPLEMENT", --compl_level); + return Tbar; +} + +static bool compl_special_cases(T, Tbar) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tbar; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcover A, ceil_compl; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tbar = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tbar = compl_cube(set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies complement is null) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tbar = new_cover(0); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + ceil_compl = compl_cube(ceil); + (void) set_or(cof, cof, set_diff(ceil, cube.fullset, ceil)); + set_free(ceil); + *Tbar = sf_append(complement(T), ceil_compl); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tbar = new_cover(0); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = map_cover_to_unate(T); + free_cubelist(T); + A = unate_compl(A); + *Tbar = map_unate_to_cover(A); + sf_free(A); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +/* + * compl_merge -- merge the two cofactors around the splitting + * variable + * + * The merge operation involves intersecting each cube of the left + * cofactor with cl, and intersecting each cube of the right cofactor + * with cr. The union of these two covers is the merged result. + * + * In order to reduce the number of cubes, a distance-1 merge is + * performed (note that two cubes can only combine distance-1 in the + * splitting variable). Also, a simple expand is performed in the + * splitting variable (simple implies the covering check for the + * expansion is not full containment, but single-cube containment). + */ + +static pcover compl_merge(T1, L, R, cl, cr, var, lifting) +pcube *T1; /* Original ON-set */ +pcover L, R; /* Complement from each recursion branch */ +register pcube cl, cr; /* cubes used for cofactoring */ +int var; /* splitting variable */ +int lifting; /* whether to perform lifting or not */ +{ + register pcube p, last, pt; + pcover T, Tbar; + pcube *L1, *R1; + + if (debug & COMPL) { + (void) printf("compl_merge: left %d, right %d\n", L->count, R->count); + (void) printf("%s (cl)\n%s (cr)\nLeft is\n", pc1(cl), pc2(cr)); + cprint(L); + (void) printf("Right is\n"); + cprint(R); + } + + /* Intersect each cube with the cofactored cube */ + foreach_set(L, last, p) { + INLINEset_and(p, p, cl); + SET(p, ACTIVE); + } + foreach_set(R, last, p) { + INLINEset_and(p, p, cr); + SET(p, ACTIVE); + } + + /* Sort the arrays for a distance-1 merge */ + (void) set_copy(cube.temp[0], cube.var_mask[var]); + qsort((char *) (L1 = sf_list(L)), L->count, sizeof(pset), (int (*)()) d1_order); + qsort((char *) (R1 = sf_list(R)), R->count, sizeof(pset), (int (*)()) d1_order); + + /* Perform distance-1 merge */ + compl_d1merge(L1, R1); + + /* Perform lifting */ + switch(lifting) { + case USE_COMPL_LIFT_ONSET: + T = cubeunlist(T1); + compl_lift_onset(L1, T, cr, var); + compl_lift_onset(R1, T, cl, var); + free_cover(T); + break; + case USE_COMPL_LIFT_ONSET_COMPLEX: + T = cubeunlist(T1); + compl_lift_onset_complex(L1, T, var); + compl_lift_onset_complex(R1, T, var); + free_cover(T); + break; + case USE_COMPL_LIFT: + compl_lift(L1, R1, cr, var); + compl_lift(R1, L1, cl, var); + break; + case NO_LIFTING: + break; + default: + ; + } + FREE(L1); + FREE(R1); + + /* Re-create the merged cover */ + Tbar = new_cover(L->count + R->count); + pt = Tbar->data; + foreach_set(L, last, p) { + INLINEset_copy(pt, p); + Tbar->count++; + pt += Tbar->wsize; + } + foreach_active_set(R, last, p) { + INLINEset_copy(pt, p); + Tbar->count++; + pt += Tbar->wsize; + } + + if (debug & COMPL) { + (void) printf("Result %d\n", Tbar->count); + if (verbose_debug) + cprint(Tbar); + } + + free_cover(L); + free_cover(R); + return Tbar; +} + +/* + * compl_lift_simple -- expand in the splitting variable using single + * cube containment against the other recursion branch to check + * validity of the expansion, and expanding all (or none) of the + * splitting variable. + */ +static void compl_lift(A1, B1, bcube, var) +pcube *A1, *B1, bcube; +int var; +{ + register pcube a, b, *B2, lift=cube.temp[4], liftor=cube.temp[5]; + pcube mask = cube.var_mask[var]; + + (void) set_and(liftor, bcube, mask); + + /* for each cube in the first array ... */ + for(; (a = *A1++) != NULL; ) { + if (TESTP(a, ACTIVE)) { + + /* create a lift of this cube in the merging coord */ + (void) set_merge(lift, bcube, a, mask); + + /* for each cube in the second array */ + for(B2 = B1; (b = *B2++) != NULL; ) { + INLINEsetp_implies(lift, b, /* when_false => */ continue); + /* when_true => fall through to next statement */ + + /* cube of A1 was contained by some cube of B1, so raise */ + INLINEset_or(a, a, liftor); + break; + } + } + } +} + + + +/* + * compl_lift_onset -- expand in the splitting variable using a + * distance-1 check against the original on-set; expand all (or + * none) of the splitting variable. Each cube of A1 is expanded + * against the original on-set T. + */ +static void compl_lift_onset(A1, T, bcube, var) +pcube *A1; +pcover T; +pcube bcube; +int var; +{ + register pcube a, last, p, lift=cube.temp[4], mask=cube.var_mask[var]; + + /* for each active cube from one branch of the complement */ + for(; (a = *A1++) != NULL; ) { + if (TESTP(a, ACTIVE)) { + + /* create a lift of this cube in the merging coord */ + INLINEset_and(lift, bcube, mask); /* isolate parts to raise */ + INLINEset_or(lift, a, lift); /* raise these parts in a */ + + /* for each cube in the ON-set, check for intersection */ + foreach_set(T, last, p) { + if (cdist0(p, lift)) { + goto nolift; + } + } + INLINEset_copy(a, lift); /* save the raising */ + SET(a, ACTIVE); +nolift : ; + } + } +} + +/* + * compl_lift_complex -- expand in the splitting variable, but expand all + * parts which can possibly expand. + * T is the original ON-set + * A1 is either the left or right cofactor + */ +static void compl_lift_onset_complex(A1, T, var) +pcube *A1; /* array of pointers to new result */ +pcover T; /* original ON-set */ +int var; /* which variable we split on */ +{ + register int dist; + register pcube last, p, a, xlower; + + /* for each cube in the complement */ + xlower = new_cube(); + for(; (a = *A1++) != NULL; ) { + + if (TESTP(a, ACTIVE)) { + + /* Find which parts of the splitting variable are forced low */ + INLINEset_clear(xlower, cube.size); + foreach_set(T, last, p) { + if ((dist = cdist01(p, a)) < 2) { + if (dist == 0) { + fatal("compl: ON-set and OFF-set are not orthogonal"); + } else { + (void) force_lower(xlower, p, a); + } + } + } + + (void) set_diff(xlower, cube.var_mask[var], xlower); + (void) set_or(a, a, xlower); + free_cube(xlower); + } + } +} + + + +/* + * compl_d1merge -- distance-1 merge in the splitting variable + */ +static void compl_d1merge(L1, R1) +register pcube *L1, *R1; +{ + register pcube pl, pr; + + /* Find equal cubes between the two cofactors */ + for(pl = *L1, pr = *R1; (pl != NULL) && (pr != NULL); ) + switch (d1_order(L1, R1)) { + case 1: + pr = *(++R1); break; /* advance right pointer */ + case -1: + pl = *(++L1); break; /* advance left pointer */ + case 0: + RESET(pr, ACTIVE); + INLINEset_or(pl, pl, pr); + pr = *(++R1); + default: + ; + } +} + + + +/* compl_cube -- return the complement of a single cube (De Morgan's law) */ +static pcover compl_cube(p) +register pcube p; +{ + register pcube diff=cube.temp[7], pdest, mask, full=cube.fullset; + int var; + pcover R; + + /* Allocate worst-case size cover (to avoid checking overflow) */ + R = new_cover(cube.num_vars); + + /* Compute bit-wise complement of the cube */ + INLINEset_diff(diff, full, p); + + for(var = 0; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + /* If the bit-wise complement is not empty in var ... */ + if (! setp_disjoint(diff, mask)) { + pdest = GETSET(R, R->count++); + INLINEset_merge(pdest, diff, full, mask); + } + } + return R; +} + +/* simp_comp -- quick simplification of T */ +void simp_comp(T, Tnew, Tbar) +pcube *T; /* T will be disposed of */ +pcover *Tnew; +pcover *Tbar; +{ + register pcube cl, cr; + register int best; + pcover Tl, Tr, Tlbar, Trbar; + int lifting; + static int simplify_level = 0; + + if (debug & COMPL) + debug_print(T, "SIMPCOMP", simplify_level++); + + if (simp_comp_special_cases(T, Tnew, Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + simp_comp(scofactor(T, cl, best), &Tl, &Tlbar); + simp_comp(scofactor(T, cr, best), &Tr, &Trbar); + + lifting = USE_COMPL_LIFT; + *Tnew = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + lifting = USE_COMPL_LIFT; + *Tbar = compl_merge(T, Tlbar, Trbar, cl, cr, best, lifting); + + /* All of this work for nothing ? Let's hope not ... */ + if ((*Tnew)->count > CUBELISTSIZE(T)) { + sf_free(*Tnew); + *Tnew = cubeunlist(T); + } + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) { + debug1_print(*Tnew, "exit SIMPCOMP (new)", simplify_level); + debug1_print(*Tbar, "exit SIMPCOMP (compl)", simplify_level); + simplify_level--; + } +} + +static bool simp_comp_special_cases(T, Tnew, Tbar) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +pcover *Tbar; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover (function is empty) */ + if (T[2] == NULL) { + *Tnew = new_cover(1); + *Tbar = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + (void) set_or(cof, cof, T[2]); + *Tnew = sf_addset(new_cover(1), cof); + *Tbar = compl_cube(cof); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + *Tbar = new_cover(1); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + set_free(p); + simp_comp(T, Tnew, Tbar); + + /* Adjust the ON-set */ + A = *Tnew; + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + + /* Compute the new complement */ + *Tbar = sf_append(*Tbar, compl_cube(ceil)); + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + *Tbar = new_cover(1); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + /* Make the cover minimum by single-cube containment */ + A = cubeunlist(T); + *Tnew = sf_contain(A); + + /* Now form a minimum representation of the complement */ + A = map_cover_to_unate(T); + A = unate_compl(A); + *Tbar = map_unate_to_cover(A); + sf_free(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +/* simplify -- quick simplification of T */ +pcover simplify(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tbar, Tl, Tr; + int lifting; + static int simplify_level = 0; + + if (debug & COMPL) { + debug_print(T, "SIMPLIFY", simplify_level++); + } + + if (simplify_special_cases(T, &Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + Tl = simplify(scofactor(T, cl, best)); + Tr = simplify(scofactor(T, cr, best)); + + lifting = USE_COMPL_LIFT; + Tbar = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + /* All of this work for nothing ? Let's hope not ... */ + if (Tbar->count > CUBELISTSIZE(T)) { + sf_free(Tbar); + Tbar = cubeunlist(T); + } + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) { + debug1_print(Tbar, "exit SIMPLIFY", --simplify_level); + } + return Tbar; +} + +static bool simplify_special_cases(T, Tnew) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tnew = new_cover(0); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tnew = sf_addset(new_cover(1), set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + free_cube(p); + + A = simplify(T); + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + *Tnew = A; + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = cubeunlist(T); + *Tnew = sf_contain(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} diff --git a/espresso/contain.c b/espresso/contain.c new file mode 100644 index 0000000..8771aff --- /dev/null +++ b/espresso/contain.c @@ -0,0 +1,441 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/contain.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + contain.c -- set containment routines + + These are complex routines for performing containment over a + family of sets, but they have the advantage of being much faster + than a straightforward n*n routine. + + First the cubes are sorted by size, and as a secondary key they are + sorted so that if two cubes are equal they end up adjacent. We can + than quickly remove equal cubes from further consideration by + comparing each cube to its neighbor. Finally, because the cubes + are sorted by size, we need only check cubes which are larger (or + smaller) than a given cube for containment. +*/ + +#include "espresso.h" + + +/* + sf_contain -- perform containment on a set family (delete sets which + are contained by some larger set in the family). No assumptions are + made about A, and the result will be returned in decreasing order of + set size. +*/ +pset_family sf_contain(A) +INOUT pset_family A; /* disposes of A */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort into descending order */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + cnt = rm_contain(A1); /* remove contained sets */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_rev_contain -- perform containment on a set family (delete sets which + contain some smaller set in the family). No assumptions are made about + A, and the result will be returned in increasing order of set size +*/ +pset_family sf_rev_contain(A) +INOUT pset_family A; /* disposes of A */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, ascend); /* sort into ascending order */ + cnt = rm_equal(A1, ascend); /* remove duplicates */ + cnt = rm_rev_contain(A1); /* remove containing sets */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_ind_contain -- perform containment on a set family (delete sets which + are contained by some larger set in the family). No assumptions are + made about A, and the result will be returned in decreasing order of + set size. Also maintains a set of row_indices to track which rows + disappear and how the rows end up permuted. +*/ +pset_family sf_ind_contain(A, row_indices) +INOUT pset_family A; /* disposes of A */ +INOUT int *row_indices; /* updated with the new values */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort into descending order */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + cnt = rm_contain(A1); /* remove contained sets */ + R = sf_ind_unlist(A1, cnt, A->sf_size, row_indices, A->data); + sf_free(A); + return R; +} + + +/* sf_dupl -- delete duplicate sets in a set family */ +pset_family sf_dupl(A) +INOUT pset_family A; /* disposes of A */ +{ + register int cnt; + register pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort the set family */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_union -- form the contained union of two set families (delete + sets which are contained by some larger set in the family). A and + B are assumed already sorted in decreasing order of set size (and + the SIZE field is assumed to contain the set size), and the result + will be returned sorted likewise. +*/ +pset_family sf_union(A, B) +INOUT pset_family A, B; /* disposes of A and B */ +{ + int cnt; + pset_family R; + pset *A1 = sf_list(A), *B1 = sf_list(B), *E1; + + E1 = ALLOC(pset, MAX(A->count, B->count) + 1); + cnt = rm2_equal(A1, B1, E1, descend); + cnt += rm2_contain(A1, B1) + rm2_contain(B1, A1); + R = sf_merge(A1, B1, E1, cnt, A->sf_size); + sf_free(A); sf_free(B); + return R; +} + + +/* + dist_merge -- consider all sets to be "or"-ed with "mask" and then + delete duplicates from the set family. +*/ +pset_family dist_merge(A, mask) +INOUT pset_family A; /* disposes of A */ +IN pset mask; /* defines variables to mask out */ +{ + pset *A1; + int cnt; + pset_family R; + + (void) set_copy(cube.temp[0], mask); + A1 = sf_sort(A, d1_order); + cnt = d1_rm_equal(A1, d1_order); + R = sf_unlist(A1, cnt, A->sf_size); + sf_free(A); + return R; +} + + +/* + d1merge -- perform an efficient distance-1 merge of cubes of A +*/ +pset_family d1merge(A, var) +INOUT pset_family A; /* disposes of A */ +IN int var; +{ + return dist_merge(A, cube.var_mask[var]); +} + + + +/* d1_rm_equal -- distance-1 merge (merge cubes which are equal under a mask) */ +int d1_rm_equal(A1, compare) +register pset *A1; /* array of set pointers */ +int (*compare)(); /* comparison function */ +{ + register int i, j, dest; + + dest = 0; + if (A1[0] != (pcube) NULL) { + for(i = 0, j = 1; A1[j] != (pcube) NULL; j++) + if ( (*compare)(&A1[i], &A1[j]) == 0) { + /* if sets are equal (under the mask) merge them */ + (void) set_or(A1[i], A1[i], A1[j]); + } else { + /* sets are unequal, so save the set i */ + A1[dest++] = A1[i]; + i = j; + } + A1[dest++] = A1[i]; + } + A1[dest] = (pcube) NULL; + return dest; +} + + +/* rm_equal -- scan a sorted array of set pointers for duplicate sets */ +int rm_equal(A1, compare) +INOUT pset *A1; /* updated in place */ +IN int (*compare)(); +{ + register pset *p, *pdest = A1; + + if (*A1 != NULL) { /* If more than one set */ + for(p = A1+1; *p != NULL; p++) + if ((*compare)(p, p-1) != 0) + *pdest++ = *(p-1); + *pdest++ = *(p-1); + *pdest = NULL; + } + return pdest - A1; +} + + +/* rm_contain -- perform containment over a sorted array of set pointers */ +int rm_contain(A1) +INOUT pset *A1; /* updated in place */ +{ + register pset *pa, *pb, *pcheck, a, b; + pset *pdest = A1; + int last_size = -1; + + /* Loop for all cubes of A1 */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* Update the check pointer if the size has changed */ + if (SIZE(a) != last_size) + last_size = SIZE(a), pcheck = pdest; + for(pb = A1; pb != pcheck; ) { + b = *pb++; + INLINEsetp_implies(a, b, /* when_false => */ continue); + goto lnext1; + } + /* set a was not contained by some larger set, so save it */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; + return pdest - A1; +} + + +/* rm_rev_contain -- perform rcontainment over a sorted array of set pointers */ +int rm_rev_contain(A1) +INOUT pset *A1; /* updated in place */ +{ + register pset *pa, *pb, *pcheck, a, b; + pset *pdest = A1; + int last_size = -1; + + /* Loop for all cubes of A1 */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* Update the check pointer if the size has changed */ + if (SIZE(a) != last_size) + last_size = SIZE(a), pcheck = pdest; + for(pb = A1; pb != pcheck; ) { + b = *pb++; + INLINEsetp_implies(b, a, /* when_false => */ continue); + goto lnext1; + } + /* the set a did not contain some smaller set, so save it */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; + return pdest - A1; +} + + +/* rm2_equal -- check two sorted arrays of set pointers for equal cubes */ +int rm2_equal(A1, B1, E1, compare) +INOUT register pset *A1, *B1; /* updated in place */ +OUT pset *E1; +IN int (*compare)(); +{ + register pset *pda = A1, *pdb = B1, *pde = E1; + + /* Walk through the arrays advancing pointer to larger cube */ + for(; *A1 != NULL && *B1 != NULL; ) + switch((*compare)(A1, B1)) { + case -1: /* "a" comes before "b" */ + *pda++ = *A1++; break; + case 0: /* equal cubes */ + *pde++ = *A1++; B1++; break; + case 1: /* "a" is to follow "b" */ + *pdb++ = *B1++; break; + } + + /* Finish moving down the pointers of A and B */ + while (*A1 != NULL) + *pda++ = *A1++; + while (*B1 != NULL) + *pdb++ = *B1++; + *pda = *pdb = *pde = NULL; + + return pde - E1; +} + + +/* rm2_contain -- perform containment between two arrays of set pointers */ +int rm2_contain(A1, B1) +INOUT pset *A1; /* updated in place */ +IN pset *B1; /* unchanged */ +{ + register pset *pa, *pb, a, b, *pdest = A1; + + /* for each set in the first array ... */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* for each set in the second array which is larger ... */ + for(pb = B1; (b = *pb++) != NULL && SIZE(b) > SIZE(a); ) { + INLINEsetp_implies(a, b, /* when_false => */ continue); + /* set was contained in some set of B, so don't save pointer */ + goto lnext1; + } + /* set wasn't contained in any set of B, so save the pointer */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; /* sentinel */ + return pdest - A1; /* # elements in A1 */ +} + + + +/* sf_sort -- sort the sets of A */ +pset *sf_sort(A, compare) +IN pset_family A; +IN int (*compare)(); +{ + register pset p, last, *pdest, *A1; + + /* Create a single array pointing to each cube of A */ + pdest = A1 = ALLOC(pset, A->count + 1); + foreach_set(A, last, p) { + PUTSIZE(p, set_ord(p)); /* compute the set size */ + *pdest++ = p; /* save the pointer */ + } + *pdest = NULL; /* Sentinel -- never seen by sort */ + + /* Sort cubes by size */ + qsort((char *) A1, A->count, sizeof(pset), compare); + return A1; +} + + +/* sf_list -- make a list of pointers to the sets in a set family */ +pset *sf_list(A) +IN register pset_family A; +{ + register pset p, last, *pdest, *A1; + + /* Create a single array pointing to each cube of A */ + pdest = A1 = ALLOC(pset, A->count + 1); + foreach_set(A, last, p) + *pdest++ = p; /* save the pointer */ + *pdest = NULL; /* Sentinel */ + return A1; +} + + +/* sf_unlist -- make a set family out of a list of pointers to sets */ +pset_family sf_unlist(A1, totcnt, size) +IN pset *A1; +IN int totcnt, size; +{ + register pset pr, p, *pa; + pset_family R = sf_new(totcnt, size); + + R->count = totcnt; + for(pr = R->data, pa = A1; (p = *pa++) != NULL; pr += R->wsize) + INLINEset_copy(pr, p); + FREE(A1); + return R; +} + + +/* sf_ind_unlist -- make a set family out of a list of pointers to sets */ +pset_family sf_ind_unlist(A1, totcnt, size, row_indices, pfirst) +IN pset *A1; +IN int totcnt, size; +INOUT int *row_indices; +IN register pset pfirst; +{ + register pset pr, p, *pa; + register int i, *new_row_indices; + pset_family R = sf_new(totcnt, size); + + R->count = totcnt; + new_row_indices = ALLOC(int, totcnt); + for(pr = R->data, pa = A1, i=0; (p = *pa++) != NULL; pr += R->wsize, i++) { + INLINEset_copy(pr, p); + new_row_indices[i] = row_indices[(p - pfirst)/R->wsize]; + } + for(i = 0; i < totcnt; i++) + row_indices[i] = new_row_indices[i]; + FREE(new_row_indices); + FREE(A1); + return R; +} + + +/* sf_merge -- merge three sorted lists of set pointers */ +pset_family sf_merge(A1, B1, E1, totcnt, size) +INOUT pset *A1, *B1, *E1; /* will be disposed of */ +IN int totcnt, size; +{ + register pset pr, ps, *pmin, *pmid, *pmax; + pset_family R; + pset *temp[3], *swap; + int i, j, n; + + /* Allocate the result set_family */ + R = sf_new(totcnt, size); + R->count = totcnt; + pr = R->data; + + /* Quick bubble sort to order the top member of the three arrays */ + n = 3; temp[0] = A1; temp[1] = B1; temp[2] = E1; + for(i = 0; i < n-1; i++) + for(j = i+1; j < n; j++) + if (desc1(*temp[i], *temp[j]) > 0) { + swap = temp[j]; + temp[j] = temp[i]; + temp[i] = swap; + } + pmin = temp[0]; pmid = temp[1]; pmax = temp[2]; + + /* Save the minimum element, then update pmin, pmid, pmax */ + while (*pmin != (pset) NULL) { + ps = *pmin++; + INLINEset_copy(pr, ps); + pr += R->wsize; + if (desc1(*pmin, *pmax) > 0) { + swap = pmax; pmax = pmin; pmin = pmid; pmid = swap; + } else if (desc1(*pmin, *pmid) > 0) { + swap = pmin; pmin = pmid; pmid = swap; + } + } + + FREE(A1); + FREE(B1); + FREE(E1); + return R; +} diff --git a/espresso/cubestr.c b/espresso/cubestr.c new file mode 100644 index 0000000..f2c6eec --- /dev/null +++ b/espresso/cubestr.c @@ -0,0 +1,152 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/cubestr.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + Module: cubestr.c -- routines for managing the global cube structure +*/ + +#include "espresso.h" + +/* + cube_setup -- assume that the fields "num_vars", "num_binary_vars", and + part_size[num_binary_vars .. num_vars-1] are setup, and initialize the + rest of cube and cdata. + + If a part_size is < 0, then the field size is abs(part_size) and the + field read from the input is symbolic. +*/ +void cube_setup() +{ + register int i, var; + register pcube p; + + if (cube.num_binary_vars < 0 || cube.num_vars < cube.num_binary_vars) + fatal("cube size is silly, error in .i/.o or .mv"); + + cube.num_mv_vars = cube.num_vars - cube.num_binary_vars; + cube.output = cube.num_mv_vars > 0 ? cube.num_vars - 1 : -1; + + cube.size = 0; + cube.first_part = ALLOC(int, cube.num_vars); + cube.last_part = ALLOC(int, cube.num_vars); + cube.first_word = ALLOC(int, cube.num_vars); + cube.last_word = ALLOC(int, cube.num_vars); + for(var = 0; var < cube.num_vars; var++) { + if (var < cube.num_binary_vars) + cube.part_size[var] = 2; + cube.first_part[var] = cube.size; + cube.first_word[var] = WHICH_WORD(cube.size); + cube.size += ABS(cube.part_size[var]); + cube.last_part[var] = cube.size - 1; + cube.last_word[var] = WHICH_WORD(cube.size - 1); + } + + cube.var_mask = ALLOC(pset, cube.num_vars); + cube.sparse = ALLOC(int, cube.num_vars); + cube.binary_mask = new_cube(); + cube.mv_mask = new_cube(); + for(var = 0; var < cube.num_vars; var++) { + p = cube.var_mask[var] = new_cube(); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + set_insert(p, i); + if (var < cube.num_binary_vars) { + INLINEset_or(cube.binary_mask, cube.binary_mask, p); + cube.sparse[var] = 0; + } else { + INLINEset_or(cube.mv_mask, cube.mv_mask, p); + cube.sparse[var] = 1; + } + } + if (cube.num_binary_vars == 0) + cube.inword = -1; + else { + cube.inword = cube.last_word[cube.num_binary_vars - 1]; + cube.inmask = cube.binary_mask[cube.inword] & DISJOINT; + } + + cube.temp = ALLOC(pset, CUBE_TEMP); + for(i = 0; i < CUBE_TEMP; i++) + cube.temp[i] = new_cube(); + cube.fullset = set_fill(new_cube(), cube.size); + cube.emptyset = new_cube(); + + cdata.part_zeros = ALLOC(int, cube.size); + cdata.var_zeros = ALLOC(int, cube.num_vars); + cdata.parts_active = ALLOC(int, cube.num_vars); + cdata.is_unate = ALLOC(int, cube.num_vars); +} + +/* + setdown_cube -- free memory allocated for the cube/cdata structs + (free's all but the part_size array) + + (I wanted to call this cube_setdown, but that violates the 8-character + external routine limit on the IBM !) +*/ +void setdown_cube() +{ + register int i, var; + + FREE(cube.first_part); + FREE(cube.last_part); + FREE(cube.first_word); + FREE(cube.last_word); + FREE(cube.sparse); + + free_cube(cube.binary_mask); + free_cube(cube.mv_mask); + free_cube(cube.fullset); + free_cube(cube.emptyset); + for(var = 0; var < cube.num_vars; var++) + free_cube(cube.var_mask[var]); + FREE(cube.var_mask); + + for(i = 0; i < CUBE_TEMP; i++) + free_cube(cube.temp[i]); + FREE(cube.temp); + + FREE(cdata.part_zeros); + FREE(cdata.var_zeros); + FREE(cdata.parts_active); + FREE(cdata.is_unate); + + cube.first_part = cube.last_part = (int *) NULL; + cube.first_word = cube.last_word = (int *) NULL; + cube.sparse = (int *) NULL; + cube.binary_mask = cube.mv_mask = (pcube) NULL; + cube.fullset = cube.emptyset = (pcube) NULL; + cube.var_mask = cube.temp = (pcube *) NULL; + + cdata.part_zeros = cdata.var_zeros = cdata.parts_active = (int *) NULL; + cdata.is_unate = (bool *) NULL; +} + + +void save_cube_struct() +{ + temp_cube_save = cube; /* structure copy ! */ + temp_cdata_save = cdata; /* "" */ + + cube.first_part = cube.last_part = (int *) NULL; + cube.first_word = cube.last_word = (int *) NULL; + cube.part_size = (int *) NULL; + cube.binary_mask = cube.mv_mask = (pcube) NULL; + cube.fullset = cube.emptyset = (pcube) NULL; + cube.var_mask = cube.temp = (pcube *) NULL; + + cdata.part_zeros = cdata.var_zeros = cdata.parts_active = (int *) NULL; + cdata.is_unate = (bool *) NULL; +} + + +void restore_cube_struct() +{ + cube = temp_cube_save; /* structure copy ! */ + cdata = temp_cdata_save; /* "" */ +} diff --git a/espresso/cvrin.c b/espresso/cvrin.c new file mode 100644 index 0000000..7d8190a --- /dev/null +++ b/espresso/cvrin.c @@ -0,0 +1,810 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/cvrin.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + module: cvrin.c + purpose: cube and cover input routines +*/ + +#include "espresso.h" + +static bool line_length_error; +static int lineno; + +void skip_line(fpin, fpout, echo) +register FILE *fpin, *fpout; +register bool echo; +{ + register int ch; + while ((ch=getc(fpin)) != EOF && ch != '\n') + if (echo) + putc(ch, fpout); + if (echo) + putc('\n', fpout); + lineno++; +} + +char *get_word(fp, word) +register FILE *fp; +register char *word; +{ + register int ch, i = 0; + while ((ch = getc(fp)) != EOF && isspace(ch)) + ; + word[i++] = ch; + while ((ch = getc(fp)) != EOF && ! isspace(ch)) + word[i++] = ch; + word[i++] = '\0'; + return word; +} + +/* + * Yes, I know this routine is a mess + */ +void read_cube(fp, PLA) +register FILE *fp; +pPLA PLA; +{ + register int var, i; + pcube cf = cube.temp[0], cr = cube.temp[1], cd = cube.temp[2]; + bool savef = FALSE, saved = FALSE, saver = FALSE; + char token[256]; /* for kiss read hack */ + int varx, first, last, offset; /* for kiss read hack */ + + set_clear(cf, cube.size); + + /* Loop and read binary variables */ + for(var = 0; var < cube.num_binary_vars; var++) + switch(getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + (void) fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + lineno++; + var--; + break; + case ' ': case '|': case '\t': + var--; + break; + case '2': case '-': + set_insert(cf, var*2+1); + case '0': + set_insert(cf, var*2); + break; + case '1': + set_insert(cf, var*2+1); + break; + case '?': + break; + default: + goto bad_char; + } + + + /* Loop for the all but one of the multiple-valued variables */ + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) + + /* Read a symbolic multiple-valued variable */ + if (cube.part_size[var] < 0) { + (void) fscanf(fp, "%s", token); + if (equal(token, "-") || equal(token, "ANY")) { + if (kiss && var == cube.num_vars - 2) { + /* leave it empty */ + } else { + /* make it full */ + set_or(cf, cf, cube.var_mask[var]); + } + } else if (equal(token, "~")) { + ; + /* leave it empty ... (?) */ + } else { + if (kiss && var == cube.num_vars - 2) + varx = var - 1, offset = ABS(cube.part_size[var-1]); + else + varx = var, offset = 0; + /* Find the symbolic label in the label table */ + first = cube.first_part[varx]; + last = cube.last_part[varx]; + for(i = first; i <= last; i++) + if (PLA->label[i] == (char *) NULL) { + PLA->label[i] = util_strsav(token); /* add new label */ + set_insert(cf, i+offset); + break; + } else if (equal(PLA->label[i], token)) { + set_insert(cf, i+offset); /* use column i */ + break; + } + if (i > last) { + (void) fprintf(stderr, +"declared size of variable %d (counting from variable 0) is too small\n", var); + exit(-1); + } + } + + } else for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + switch (getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + (void) fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + lineno++; + i--; + break; + case ' ': case '|': case '\t': + i--; + break; + case '1': + set_insert(cf, i); + case '0': + break; + default: + goto bad_char; + } + + /* Loop for last multiple-valued variable */ + if (kiss) { + saver = savef = TRUE; + (void) set_xor(cr, cf, cube.var_mask[cube.num_vars - 2]); + } else + set_copy(cr, cf); + set_copy(cd, cf); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + switch (getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + (void) fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + lineno++; + i--; + break; + case ' ': case '|': case '\t': + i--; + break; + case '4': case '1': + if (PLA->pla_type & F_type) + set_insert(cf, i), savef = TRUE; + break; + case '3': case '0': + if (PLA->pla_type & R_type) + set_insert(cr, i), saver = TRUE; + break; + case '2': case '-': + if (PLA->pla_type & D_type) + set_insert(cd, i), saved = TRUE; + case '~': + break; + default: + goto bad_char; + } + if (savef) PLA->F = sf_addset(PLA->F, cf); + if (saved) PLA->D = sf_addset(PLA->D, cd); + if (saver) PLA->R = sf_addset(PLA->R, cr); + return; + +bad_char: + (void) fprintf(stderr, "(warning): input line #%d ignored\n", lineno); + skip_line(fp, stdout, TRUE); + return; +} +void parse_pla(fp, PLA) +IN FILE *fp; +INOUT pPLA PLA; +{ + int i, var, ch, np, last; + char word[256]; + + lineno = 1; + line_length_error = FALSE; + +loop: + switch(ch = getc(fp)) { + case EOF: + return; + + case '\n': + lineno++; + + case ' ': case '\t': case '\f': case '\r': + break; + + case '#': + (void) ungetc(ch, fp); + skip_line(fp, stdout, echo_comments); + break; + + case '.': + /* .i gives the cube input size (binary-functions only) */ + if (equal(get_word(fp, word), "i")) { + if (cube.fullset != NULL) { + (void) fprintf(stderr, "extra .i ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (fscanf(fp, "%d", &cube.num_binary_vars) != 1) + fatal("error reading .i"); + cube.num_vars = cube.num_binary_vars + 1; + cube.part_size = ALLOC(int, cube.num_vars); + } + + /* .o gives the cube output size (binary-functions only) */ + } else if (equal(word, "o")) { + if (cube.fullset != NULL) { + (void) fprintf(stderr, "extra .o ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (cube.part_size == NULL) + fatal(".o cannot appear before .i"); + if (fscanf(fp, "%d", &(cube.part_size[cube.num_vars-1]))!=1) + fatal("error reading .o"); + cube_setup(); + PLA_labels(PLA); + } + + /* .mv gives the cube size for a multiple-valued function */ + } else if (equal(word, "mv")) { + if (cube.fullset != NULL) { + (void) fprintf(stderr, "extra .mv ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (cube.part_size != NULL) + fatal("cannot mix .i and .mv"); + if (fscanf(fp,"%d %d", + &cube.num_vars,&cube.num_binary_vars) != 2) + fatal("error reading .mv"); + if (cube.num_binary_vars < 0) +fatal("num_binary_vars (second field of .mv) cannot be negative"); + if (cube.num_vars < cube.num_binary_vars) + fatal( +"num_vars (1st field of .mv) must exceed num_binary_vars (2nd field of .mv)"); + cube.part_size = ALLOC(int, cube.num_vars); + for(var=cube.num_binary_vars; var < cube.num_vars; var++) + if (fscanf(fp, "%d", &(cube.part_size[var])) != 1) + fatal("error reading .mv"); + cube_setup(); + PLA_labels(PLA); + } + + /* .p gives the number of product terms -- we ignore it */ + } else if (equal(word, "p")) + (void) fscanf(fp, "%d", &np); + /* .e and .end specify the end of the file */ + else if (equal(word, "e") || equal(word,"end")) { + if (cube.fullset == NULL) { + /* fatal("unknown PLA size, need .i/.o or .mv");*/ + } else if (PLA->F == NULL) { + PLA->F = new_cover(10); + PLA->D = new_cover(10); + PLA->R = new_cover(10); + } + return; + } + /* .kiss turns on the kiss-hack option */ + else if (equal(word, "kiss")) + kiss = TRUE; + + /* .type specifies a logical type for the PLA */ + else if (equal(word, "type")) { + (void) get_word(fp, word); + for(i = 0; pla_types[i].key != 0; i++) + if (equal(pla_types[i].key + 1, word)) { + PLA->pla_type = pla_types[i].value; + break; + } + if (pla_types[i].key == 0) + fatal("unknown type in .type command"); + + /* parse the labels */ + } else if (equal(word, "ilb")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .ilb or .ob"); + if (PLA->label == NULL) + PLA_labels(PLA); + for(var = 0; var < cube.num_binary_vars; var++) { + (void) get_word(fp, word); + i = cube.first_part[var]; + PLA->label[i+1] = util_strsav(word); + PLA->label[i] = ALLOC(char, strlen(word) + 6); + (void) sprintf(PLA->label[i], "%s.bar", word); + } + } else if (equal(word, "ob")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .ilb or .ob"); + if (PLA->label == NULL) + PLA_labels(PLA); + var = cube.num_vars - 1; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + (void) get_word(fp, word); + PLA->label[i] = util_strsav(word); + } + /* .label assigns labels to multiple-valued variables */ + } else if (equal(word, "label")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .label"); + if (PLA->label == NULL) + PLA_labels(PLA); + if (fscanf(fp, "var=%d", &var) != 1) + fatal("Error reading labels"); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + (void) get_word(fp, word); + PLA->label[i] = util_strsav(word); + } + + } else if (equal(word, "symbolic")) { + symbolic_t *newlist, *p1; + if (read_symbolic(fp, PLA, word, &newlist)) { + if (PLA->symbolic == NIL(symbolic_t)) { + PLA->symbolic = newlist; + } else { + for(p1=PLA->symbolic;p1->next!=NIL(symbolic_t); + p1=p1->next){ + } + p1->next = newlist; + } + } else { + fatal("error reading .symbolic"); + } + + } else if (equal(word, "symbolic-output")) { + symbolic_t *newlist, *p1; + if (read_symbolic(fp, PLA, word, &newlist)) { + if (PLA->symbolic_output == NIL(symbolic_t)) { + PLA->symbolic_output = newlist; + } else { + for(p1=PLA->symbolic_output;p1->next!=NIL(symbolic_t); + p1=p1->next){ + } + p1->next = newlist; + } + } else { + fatal("error reading .symbolic-output"); + } + + /* .phase allows a choice of output phases */ + } else if (equal(word, "phase")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .phase"); + if (PLA->phase != NULL) { + (void) fprintf(stderr, "extra .phase ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + do ch = getc(fp); while (ch == ' ' || ch == '\t'); + (void) ungetc(ch, fp); + PLA->phase = set_save(cube.fullset); + last = cube.last_part[cube.num_vars - 1]; + for(i=cube.first_part[cube.num_vars - 1]; i <= last; i++) + if ((ch = getc(fp)) == '0') + set_remove(PLA->phase, i); + else if (ch != '1') + fatal("only 0 or 1 allowed in phase description"); + } + + /* .pair allows for bit-pairing input variables */ + } else if (equal(word, "pair")) { + int j; + if (PLA->pair != NULL) { + (void) fprintf(stderr, "extra .pair ignored\n"); + } else { + ppair pair; + PLA->pair = pair = ALLOC(pair_t, 1); + if (fscanf(fp, "%d", &(pair->cnt)) != 1) + fatal("syntax error in .pair"); + pair->var1 = ALLOC(int, pair->cnt); + pair->var2 = ALLOC(int, pair->cnt); + for(i = 0; i < pair->cnt; i++) { + (void) get_word(fp, word); + if (word[0] == '(') (void) strcpy(word, word+1); + if (label_index(PLA, word, &var, &j)) { + pair->var1[i] = var+1; + } else { + fatal("syntax error in .pair"); + } + + (void) get_word(fp, word); + if (word[strlen(word)-1] == ')') { + word[strlen(word)-1]='\0'; + } + if (label_index(PLA, word, &var, &j)) { + pair->var2[i] = var+1; + } else { + fatal("syntax error in .pair"); + } + } + } + + } else { + if (echo_unknown_commands) + printf("%c%s ", ch, word); + skip_line(fp, stdout, echo_unknown_commands); + } + break; + default: + (void) ungetc(ch, fp); + if (cube.fullset == NULL) { +/* fatal("unknown PLA size, need .i/.o or .mv");*/ + if (echo_comments) + putchar('#'); + skip_line(fp, stdout, echo_comments); + break; + } + if (PLA->F == NULL) { + PLA->F = new_cover(10); + PLA->D = new_cover(10); + PLA->R = new_cover(10); + } + read_cube(fp, PLA); + } + goto loop; +} +/* + read_pla -- read a PLA from a file + + Input stops when ".e" is encountered in the input file, or upon reaching + end of file. + + Returns the PLA in the variable PLA after massaging the "symbolic" + representation into a positional cube notation of the ON-set, OFF-set, + and the DC-set. + + needs_dcset and needs_offset control the computation of the OFF-set + and DC-set (i.e., if either needs to be computed, then it will be + computed via complement only if the corresponding option is TRUE.) + pla_type specifies the interpretation to be used when reading the + PLA. + + The phase of the output functions is adjusted according to the + global option "pos" or according to an imbedded .phase option in + the input file. Note that either phase option implies that the + OFF-set be computed regardless of whether the caller needs it + explicitly or not. + + Bit pairing of the binary variables is performed according to an + imbedded .pair option in the input file. + + The global cube structure also reflects the sizes of the PLA which + was just read. If these fields have already been set, then any + subsequent PLA must conform to these sizes. + + The global flags trace and summary control the output produced + during the read. + + Returns a status code as a result: + EOF (-1) : End of file reached before any data was read + > 0 : Operation successful +*/ + +int read_pla(fp, needs_dcset, needs_offset, pla_type, PLA_return) +IN FILE *fp; +IN bool needs_dcset, needs_offset; +IN int pla_type; +OUT pPLA *PLA_return; +{ + pPLA PLA; + int i, second, third; + long time; + cost_t cost; + + /* Allocate and initialize the PLA structure */ + PLA = *PLA_return = new_PLA(); + PLA->pla_type = pla_type; + + /* Read the pla */ + time = ptime(); + parse_pla(fp, PLA); + + /* Check for nothing on the file -- implies reached EOF */ + if (PLA->F == NULL) { + return EOF; + } + + /* This hack merges the next-state field with the outputs */ + for(i = 0; i < cube.num_vars; i++) { + cube.part_size[i] = ABS(cube.part_size[i]); + } + if (kiss) { + third = cube.num_vars - 3; + second = cube.num_vars - 2; + if (cube.part_size[third] != cube.part_size[second]) { + (void) fprintf(stderr," with .kiss option, third to last and second\n"); + (void) fprintf(stderr, "to last variables must be the same size.\n"); + return EOF; + } + for(i = 0; i < cube.part_size[second]; i++) { + PLA->label[i + cube.first_part[second]] = + util_strsav(PLA->label[i + cube.first_part[third]]); + } + cube.part_size[second] += cube.part_size[cube.num_vars-1]; + cube.num_vars--; + setdown_cube(); + cube_setup(); + } + + if (trace) { + totals(time, READ_TIME, PLA->F, &cost); + } + + /* Decide how to break PLA into ON-set, OFF-set and DC-set */ + time = ptime(); + if (pos || PLA->phase != NULL || PLA->symbolic_output != NIL(symbolic_t)) { + needs_offset = TRUE; + } + if (needs_offset && (PLA->pla_type==F_type || PLA->pla_type==FD_type)) { + free_cover(PLA->R); + PLA->R = complement(cube2list(PLA->F, PLA->D)); + } else if (needs_dcset && PLA->pla_type == FR_type) { + pcover X; + free_cover(PLA->D); + /* hack, why not? */ + X = d1merge(sf_join(PLA->F, PLA->R), cube.num_vars - 1); + PLA->D = complement(cube1list(X)); + free_cover(X); + } else if (PLA->pla_type == R_type || PLA->pla_type == DR_type) { + free_cover(PLA->F); + PLA->F = complement(cube2list(PLA->D, PLA->R)); + } + + if (trace) { + totals(time, COMPL_TIME, PLA->R, &cost); + } + + /* Check for phase rearrangement of the functions */ + if (pos) { + pcover onset = PLA->F; + PLA->F = PLA->R; + PLA->R = onset; + PLA->phase = new_cube(); + set_diff(PLA->phase, cube.fullset, cube.var_mask[cube.num_vars-1]); + } else if (PLA->phase != NULL) { + (void) set_phase(PLA); + } + + /* Setup minimization for two-bit decoders */ + if (PLA->pair != (ppair) NULL) { + set_pair(PLA); + } + + if (PLA->symbolic != NIL(symbolic_t)) { + EXEC(map_symbolic(PLA), "MAP-INPUT ", PLA->F); + } + if (PLA->symbolic_output != NIL(symbolic_t)) { + EXEC(map_output_symbolic(PLA), "MAP-OUTPUT ", PLA->F); + if (needs_offset) { + free_cover(PLA->R); +EXECUTE(PLA->R=complement(cube2list(PLA->F,PLA->D)), COMPL_TIME, PLA->R, cost); + } + } + + return 1; +} + +void PLA_summary(PLA) +pPLA PLA; +{ + int var, i; + symbolic_list_t *p2; + symbolic_t *p1; + + printf("# PLA is %s", PLA->filename); + if (cube.num_binary_vars == cube.num_vars - 1) + printf(" with %d inputs and %d outputs\n", + cube.num_binary_vars, cube.part_size[cube.num_vars - 1]); + else { + printf(" with %d variables (%d binary, mv sizes", + cube.num_vars, cube.num_binary_vars); + for(var = cube.num_binary_vars; var < cube.num_vars; var++) + printf(" %d", cube.part_size[var]); + printf(")\n"); + } + printf("# ON-set cost is %s\n", print_cost(PLA->F)); + printf("# OFF-set cost is %s\n", print_cost(PLA->R)); + printf("# DC-set cost is %s\n", print_cost(PLA->D)); + if (PLA->phase != NULL) + printf("# phase is %s\n", pc1(PLA->phase)); + if (PLA->pair != NULL) { + printf("# two-bit decoders:"); + for(i = 0; i < PLA->pair->cnt; i++) + printf(" (%d %d)", PLA->pair->var1[i], PLA->pair->var2[i]); + printf("\n"); + } + if (PLA->symbolic != NIL(symbolic_t)) { + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + printf("# symbolic: "); + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + printf(" %d", p2->variable); + } + printf("\n"); + } + } + if (PLA->symbolic_output != NIL(symbolic_t)) { + for(p1 = PLA->symbolic_output; p1 != NIL(symbolic_t); p1 = p1->next) { + printf("# output symbolic: "); + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + printf(" %d", p2->pos); + } + printf("\n"); + } + } + (void) fflush(stdout); +} + + +pPLA new_PLA() +{ + pPLA PLA; + + PLA = ALLOC(PLA_t, 1); + PLA->F = PLA->D = PLA->R = (pcover) NULL; + PLA->phase = (pcube) NULL; + PLA->pair = (ppair) NULL; + PLA->label = (char **) NULL; + PLA->filename = (char *) NULL; + PLA->pla_type = 0; + PLA->symbolic = NIL(symbolic_t); + PLA->symbolic_output = NIL(symbolic_t); + return PLA; +} + + +PLA_labels(PLA) +pPLA PLA; +{ + int i; + + PLA->label = ALLOC(char *, cube.size); + for(i = 0; i < cube.size; i++) + PLA->label[i] = (char *) NULL; +} + + +void free_PLA(PLA) +pPLA PLA; +{ + symbolic_list_t *p2, *p2next; + symbolic_t *p1, *p1next; + int i; + + if (PLA->F != (pcover) NULL) + free_cover(PLA->F); + if (PLA->R != (pcover) NULL) + free_cover(PLA->R); + if (PLA->D != (pcover) NULL) + free_cover(PLA->D); + if (PLA->phase != (pcube) NULL) + free_cube(PLA->phase); + if (PLA->pair != (ppair) NULL) { + FREE(PLA->pair->var1); + FREE(PLA->pair->var2); + FREE(PLA->pair); + } + if (PLA->label != NULL) { + for(i = 0; i < cube.size; i++) + if (PLA->label[i] != NULL) + FREE(PLA->label[i]); + FREE(PLA->label); + } + if (PLA->filename != NULL) { + FREE(PLA->filename); + } + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1next) { + for(p2 = p1->symbolic_list; p2 != NIL(symbolic_list_t); p2 = p2next) { + p2next = p2->next; + FREE(p2); + } + p1next = p1->next; + FREE(p1); + } + PLA->symbolic = NIL(symbolic_t); + for(p1 = PLA->symbolic_output; p1 != NIL(symbolic_t); p1 = p1next) { + for(p2 = p1->symbolic_list; p2 != NIL(symbolic_list_t); p2 = p2next) { + p2next = p2->next; + FREE(p2); + } + p1next = p1->next; + FREE(p1); + } + PLA->symbolic_output = NIL(symbolic_t); + FREE(PLA); +} + + +int read_symbolic(fp, PLA, word, retval) +FILE *fp; +pPLA PLA; +char *word; /* scratch string for words */ +symbolic_t **retval; +{ + symbolic_list_t *listp, *prev_listp; + symbolic_label_t *labelp, *prev_labelp; + symbolic_t *newlist; + int i, var; + + newlist = ALLOC(symbolic_t, 1); + newlist->next = NIL(symbolic_t); + newlist->symbolic_list = NIL(symbolic_list_t); + newlist->symbolic_list_length = 0; + newlist->symbolic_label = NIL(symbolic_label_t); + newlist->symbolic_label_length = 0; + prev_listp = NIL(symbolic_list_t); + prev_labelp = NIL(symbolic_label_t); + + for(;;) { + (void) get_word(fp, word); + if (equal(word, ";")) + break; + if (label_index(PLA, word, &var, &i)) { + listp = ALLOC(symbolic_list_t, 1); + listp->variable = var; + listp->pos = i; + listp->next = NIL(symbolic_list_t); + if (prev_listp == NIL(symbolic_list_t)) { + newlist->symbolic_list = listp; + } else { + prev_listp->next = listp; + } + prev_listp = listp; + newlist->symbolic_list_length++; + } else { + return FALSE; + } + } + + for(;;) { + (void) get_word(fp, word); + if (equal(word, ";")) + break; + labelp = ALLOC(symbolic_label_t, 1); + labelp->label = util_strsav(word); + labelp->next = NIL(symbolic_label_t); + if (prev_labelp == NIL(symbolic_label_t)) { + newlist->symbolic_label = labelp; + } else { + prev_labelp->next = labelp; + } + prev_labelp = labelp; + newlist->symbolic_label_length++; + } + + *retval = newlist; + return TRUE; +} + + +int label_index(PLA, word, varp, ip) +pPLA PLA; +char *word; +int *varp; +int *ip; +{ + int var, i; + + if (PLA->label == NIL(char *) || PLA->label[0] == NIL(char)) { + if (sscanf(word, "%d", varp) == 1) { + *ip = *varp; + return TRUE; + } + } else { + for(var = 0; var < cube.num_vars; var++) { + for(i = 0; i < cube.part_size[var]; i++) { + if (equal(PLA->label[cube.first_part[var]+i], word)) { + *varp = var; + *ip = i; + return TRUE; + } + } + } + } + return FALSE; +} diff --git a/espresso/cvrm.c b/espresso/cvrm.c new file mode 100644 index 0000000..9191dfc --- /dev/null +++ b/espresso/cvrm.c @@ -0,0 +1,539 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/cvrm.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + module: cvrm.c + Purpose: miscellaneous cover manipulation + a) verify two covers are equal, check consistency of a cover + b) unravel a multiple-valued cover into minterms + c) sort covers +*/ + +#include "espresso.h" + + +static void cb_unravel(c, start, end, startbase, B1) +IN register pcube c; +IN int start, end; +IN pcube startbase; +INOUT pcover B1; +{ + pcube base = cube.temp[0], p, last; + int expansion, place, skip, var, size, offset; + register int i, j, k, n; + + /* Determine how many cubes it will blow up into, and create a mask + for those parts that have only a single coordinate + */ + expansion = 1; + (void) set_copy(base, startbase); + for(var = start; var <= end; var++) { + if ((size = set_dist(c, cube.var_mask[var])) < 2) { + (void) set_or(base, base, cube.var_mask[var]); + } else { + expansion *= size; + } + } + (void) set_and(base, c, base); + + /* Add the unravelled sets starting at the last element of B1 */ + offset = B1->count; + B1->count += expansion; + foreach_remaining_set(B1, last, GETSET(B1, offset-1), p) { + INLINEset_copy(p, base); + } + + place = expansion; + for(var = start; var <= end; var++) { + if ((size = set_dist(c, cube.var_mask[var])) > 1) { + skip = place; + place = place / size; + n = 0; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (is_in_set(c, i)) { + for(j = n; j < expansion; j += skip) { + for(k = 0; k < place; k++) { + p = GETSET(B1, j+k+offset); + (void) set_insert(p, i); + } + } + n += place; + } + } + } + } +} + + +pcover unravel_range(B, start, end) +IN pcover B; +IN int start, end; +{ + pcover B1; + int var, total_size, expansion, size; + register pcube p, last, startbase = cube.temp[1]; + + /* Create the starting base for those variables not being unravelled */ + (void) set_copy(startbase, cube.emptyset); + for(var = 0; var < start; var++) + (void) set_or(startbase, startbase, cube.var_mask[var]); + for(var = end+1; var < cube.num_vars; var++) + (void) set_or(startbase, startbase, cube.var_mask[var]); + + /* Determine how many cubes it will blow up into */ + total_size = 0; + foreach_set(B, last, p) { + expansion = 1; + for(var = start; var <= end; var++) + if ((size = set_dist(p, cube.var_mask[var])) >= 2) + if ((expansion *= size) > 1000000) + fatal("unreasonable expansion in unravel"); + total_size += expansion; + } + + /* We can now allocate a cover of exactly the correct size */ + B1 = new_cover(total_size); + foreach_set(B, last, p) { + cb_unravel(p, start, end, startbase, B1); + } + free_cover(B); + return B1; +} + + +pcover unravel(B, start) +IN pcover B; +IN int start; +{ + return unravel_range(B, start, cube.num_vars-1); +} + +/* lex_sort -- sort cubes in a standard lexical fashion */ +pcover lex_sort(T) +pcover T; +{ + pcover T1 = sf_unlist(sf_sort(T, lex_order), T->count, T->sf_size); + free_cover(T); + return T1; +} + + +/* size_sort -- sort cubes by their size */ +pcover size_sort(T) +pcover T; +{ + pcover T1 = sf_unlist(sf_sort(T, descend), T->count, T->sf_size); + free_cover(T); + return T1; +} + + +/* mini_sort -- sort cubes according to the heuristics of mini */ +pcover mini_sort(F, compare) +pcover F; +int (*compare)(); +{ + register int *count, cnt, n = cube.size, i; + register pcube p, last; + pcover F_sorted; + pcube *F1; + + /* Perform a column sum over the set family */ + count = sf_count(F); + + /* weight is "inner product of the cube and the column sums" */ + foreach_set(F, last, p) { + cnt = 0; + for(i = 0; i < n; i++) + if (is_in_set(p, i)) + cnt += count[i]; + PUTSIZE(p, cnt); + } + FREE(count); + + /* use qsort to sort the array */ + qsort((char *) (F1 = sf_list(F)), F->count, sizeof(pcube), compare); + F_sorted = sf_unlist(F1, F->count, F->sf_size); + free_cover(F); + + return F_sorted; +} + + +/* sort_reduce -- Espresso strategy for ordering the cubes before reduction */ +pcover sort_reduce(T) +IN pcover T; +{ + register pcube p, last, largest = NULL; + register int bestsize = -1, size, n = cube.num_vars; + pcover T_sorted; + pcube *T1; + + if (T->count == 0) + return T; + + /* find largest cube */ + foreach_set(T, last, p) + if ((size = set_ord(p)) > bestsize) + largest = p, bestsize = size; + + foreach_set(T, last, p) + PUTSIZE(p, ((n - cdist(largest,p)) << 7) + MIN(set_ord(p),127)); + + qsort((char *) (T1 = sf_list(T)), T->count, sizeof(pcube), (int (*)()) descend); + T_sorted = sf_unlist(T1, T->count, T->sf_size); + free_cover(T); + + return T_sorted; +} + +pcover random_order(F) +register pcover F; +{ + pset temp; + register int i, k; +#ifdef RANDOM + long random(); +#endif + + temp = set_new(F->sf_size); + for(i = F->count - 1; i > 0; i--) { + /* Choose a random number between 0 and i */ +#ifdef RANDOM + k = random() % i; +#else + /* this is not meant to be really used; just provides an easy + "out" if random() and srandom() aren't around + */ + k = (i*23 + 997) % i; +#endif + /* swap sets i and k */ + (void) set_copy(temp, GETSET(F, k)); + (void) set_copy(GETSET(F, k), GETSET(F, i)); + (void) set_copy(GETSET(F, i), temp); + } + set_free(temp); + return F; +} + +/* + * cubelist_partition -- take a cubelist T and see if it has any components; + * if so, return cubelist's of the two partitions A and B; the return value + * is the size of the partition; if not, A and B + * are undefined and the return value is 0 + */ +int cubelist_partition(T, A, B, comp_debug) +pcube *T; /* a list of cubes */ +pcube **A, **B; /* cubelist of partition and remainder */ +unsigned int comp_debug; +{ + register pcube *T1, p, seed, cof; + pcube *A1, *B1; + bool change; + int count, numcube; + + numcube = CUBELISTSIZE(T); + + /* Mark all cubes -- covered cubes belong to the partition */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + RESET(p, COVERED); + } + + /* + * Extract a partition from the cubelist T; start with the first cube as a + * seed, and then pull in all cubes which share a variable with the seed; + * iterate until no new cubes are brought into the partition. + */ + seed = set_save(T[2]); + cof = T[0]; + SET(T[2], COVERED); + count = 1; + + do { + change = FALSE; + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (! TESTP(p, COVERED) && ccommon(p, seed, cof)) { + INLINEset_and(seed, seed, p); + SET(p, COVERED); + change = TRUE; + count++; + } + + } + } while (change); + + set_free(seed); + + if (comp_debug) { + (void) printf("COMPONENT_REDUCTION: split into %d %d\n", + count, numcube - count); + } + + if (count != numcube) { + /* Allocate and setup the cubelist's for the two partitions */ + *A = A1 = ALLOC(pcube, numcube+3); + *B = B1 = ALLOC(pcube, numcube+3); + (*A)[0] = set_save(T[0]); + (*B)[0] = set_save(T[0]); + A1 = *A + 2; + B1 = *B + 2; + + /* Loop over the cubes in T and distribute to A and B */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (TESTP(p, COVERED)) { + *A1++ = p; + } else { + *B1++ = p; + } + } + + /* Stuff needed at the end of the cubelist's */ + *A1++ = NULL; + (*A)[1] = (pcube) A1; + *B1++ = NULL; + (*B)[1] = (pcube) B1; + } + + return numcube - count; +} + +/* + * quick cofactor against a single output function + */ +pcover cof_output(T, i) +pcover T; +register int i; +{ + pcover T1; + register pcube p, last, pdest, mask; + + mask = cube.var_mask[cube.output]; + T1 = new_cover(T->count); + foreach_set(T, last, p) { + if (is_in_set(p, i)) { + pdest = GETSET(T1, T1->count++); + INLINEset_or(pdest, p, mask); + RESET(pdest, PRIME); + } + } + return T1; +} + + +/* + * quick intersection against a single output function + */ +pcover uncof_output(T, i) +pcover T; +int i; +{ + register pcube p, last, mask; + + if (T == NULL) { + return T; + } + + mask = cube.var_mask[cube.output]; + foreach_set(T, last, p) { + INLINEset_diff(p, p, mask); + set_insert(p, i); + } + return T; +} + + +/* + * A generic routine to perform an operation for each output function + * + * func() is called with a PLA for each output function (with the output + * part effectively removed). + * func1() is called after reforming the equivalent output function + * + * Each function returns TRUE if process is to continue + */ +foreach_output_function(PLA, func, func1) +pPLA PLA; +int (*func)(); +int (*func1)(); +{ + pPLA PLA1; + int i; + + /* Loop for each output function */ + for(i = 0; i < cube.part_size[cube.output]; i++) { + + /* cofactor on the output part */ + PLA1 = new_PLA(); + PLA1->F = cof_output(PLA->F, i + cube.first_part[cube.output]); + PLA1->R = cof_output(PLA->R, i + cube.first_part[cube.output]); + PLA1->D = cof_output(PLA->D, i + cube.first_part[cube.output]); + + /* Call a routine to do something with the cover */ + if ((*func)(PLA1, i) == 0) { + free_PLA(PLA1); + return; + } + + /* intersect with the particular output part again */ + PLA1->F = uncof_output(PLA1->F, i + cube.first_part[cube.output]); + PLA1->R = uncof_output(PLA1->R, i + cube.first_part[cube.output]); + PLA1->D = uncof_output(PLA1->D, i + cube.first_part[cube.output]); + + /* Call a routine to do something with the final result */ + if ((*func1)(PLA1, i) == 0) { + free_PLA(PLA1); + return; + } + + /* Cleanup for next go-around */ + free_PLA(PLA1); + + + } +} + +static pcover Fmin; +static pcube phase; + +/* + * minimize each output function individually + */ +void so_espresso(PLA, strategy) +pPLA PLA; +int strategy; +{ + Fmin = new_cover(PLA->F->count); + if (strategy == 0) { + foreach_output_function(PLA, so_do_espresso, so_save); + } else { + foreach_output_function(PLA, so_do_exact, so_save); + } + sf_free(PLA->F); + PLA->F = Fmin; +} + + +/* + * minimize each output function, choose function or complement based on the + * one with the fewer number of terms + */ +void so_both_espresso(PLA, strategy) +pPLA PLA; +int strategy; +{ + phase = set_save(cube.fullset); + Fmin = new_cover(PLA->F->count); + if (strategy == 0) { + foreach_output_function(PLA, so_both_do_espresso, so_both_save); + } else { + foreach_output_function(PLA, so_both_do_exact, so_both_save); + } + sf_free(PLA->F); + PLA->F = Fmin; + PLA->phase = phase; +} + + +int so_do_espresso(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + skip_make_sparse = 1; + (void) sprintf(word, "ESPRESSO-POS(%d)", i); + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), word, PLA->F); + return 1; +} + + +int so_do_exact(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + skip_make_sparse = 1; + (void) sprintf(word, "EXACT-POS(%d)", i); + EXEC_S(PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1), word, PLA->F); + return 1; +} + + +/*ARGSUSED*/ +int so_save(PLA, i) +pPLA PLA; +int i; +{ + Fmin = sf_append(Fmin, PLA->F); /* disposes of PLA->F */ + PLA->F = NULL; + return 1; +} + + +int so_both_do_espresso(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + (void) sprintf(word, "ESPRESSO-POS(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), word, PLA->F); + + /* minimize the single-output function (off-set) */ + (void) sprintf(word, "ESPRESSO-NEG(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->R = espresso(PLA->R, PLA->D, PLA->F), word, PLA->R); + + return 1; +} + + +int so_both_do_exact(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + (void) sprintf(word, "EXACT-POS(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1), word, PLA->F); + + /* minimize the single-output function (off-set) */ + (void) sprintf(word, "EXACT-NEG(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->R = minimize_exact(PLA->R, PLA->D, PLA->F, 1), word, PLA->R); + + return 1; +} + + +int so_both_save(PLA, i) +pPLA PLA; +int i; +{ + if (PLA->F->count > PLA->R->count) { + sf_free(PLA->F); + PLA->F = PLA->R; + PLA->R = NULL; + i += cube.first_part[cube.output]; + set_remove(phase, i); + } else { + sf_free(PLA->R); + PLA->R = NULL; + } + Fmin = sf_append(Fmin, PLA->F); + PLA->F = NULL; + return 1; +} diff --git a/espresso/cvrmisc.c b/espresso/cvrmisc.c new file mode 100644 index 0000000..b3639ab --- /dev/null +++ b/espresso/cvrmisc.c @@ -0,0 +1,142 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/cvrmisc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +#include "espresso.h" + + +/* cost -- compute the cost of a cover */ +void cover_cost(F, cost) +IN pcover F; +INOUT pcost cost; +{ + register pcube p, last; + pcube *T; + int var; + + /* use the routine used by cofactor to decide splitting variables */ + massive_count(T = cube1list(F)); + free_cubelist(T); + + cost->cubes = F->count; + cost->total = cost->in = cost->out = cost->mv = cost->primes = 0; + + /* Count transistors (zeros) for each binary variable (inputs) */ + for(var = 0; var < cube.num_binary_vars; var++) + cost->in += cdata.var_zeros[var]; + + /* Count transistors for each mv variable based on sparse/dense */ + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) + if (cube.sparse[var]) + cost->mv += F->count * cube.part_size[var] - cdata.var_zeros[var]; + else + cost->mv += cdata.var_zeros[var]; + + /* Count the transistors (ones) for the output variable */ + if (cube.num_binary_vars != cube.num_vars) { + var = cube.num_vars - 1; + cost->out = F->count * cube.part_size[var] - cdata.var_zeros[var]; + } + + /* Count the number of nonprime cubes */ + foreach_set(F, last, p) + cost->primes += TESTP(p, PRIME) != 0; + + /* Count the total number of literals */ + cost->total = cost->in + cost->out + cost->mv; +} + + +/* fmt_cost -- return a string which reports the "cost" of a cover */ +char *fmt_cost(cost) +IN pcost cost; +{ + static char s[200]; + + if (cube.num_binary_vars == cube.num_vars - 1) + (void) sprintf(s, "c=%d(%d) in=%d out=%d tot=%d", + cost->cubes, cost->cubes - cost->primes, cost->in, + cost->out, cost->total); + else + (void) sprintf(s, "c=%d(%d) in=%d mv=%d out=%d", + cost->cubes, cost->cubes - cost->primes, cost->in, + cost->mv, cost->out); + return s; +} + + +char *print_cost(F) +IN pcover F; +{ + cost_t cost; + cover_cost(F, &cost); + return fmt_cost(&cost); +} + + +/* copy_cost -- copy a cost function from s to d */ +void copy_cost(s, d) +pcost s, d; +{ + d->cubes = s->cubes; + d->in = s->in; + d->out = s->out; + d->mv = s->mv; + d->total = s->total; + d->primes = s->primes; +} + + +/* size_stamp -- print single line giving the size of a cover */ +void size_stamp(T, name) +IN pcover T; +IN char *name; +{ + (void) printf("# %s\tCost is %s\n", name, print_cost(T)); + (void) fflush(stdout); +} + + +/* print_trace -- print a line reporting size and time after a function */ +void print_trace(T, name, time) +pcover T; +char *name; +long time; +{ + (void) printf("# %s\tTime was %s, cost is %s\n", + name, print_time(time), print_cost(T)); + (void) fflush(stdout); +} + + +/* totals -- add time spent in the function into the totals */ +void totals(time, i, T, cost) +long time; +int i; +pcover T; +pcost cost; +{ + time = ptime() - time; + total_time[i] += time; + total_calls[i]++; + cover_cost(T, cost); + if (trace) { + (void) printf("# %s\tTime was %s, cost is %s\n", + total_name[i], print_time(time), fmt_cost(cost)); + (void) fflush(stdout); + } +} + + +/* fatal -- report fatal error message and take a dive */ +void fatal(s) +char *s; +{ + (void) fprintf(stderr, "espresso: %s\n", s); + exit(1); +} diff --git a/espresso/cvrout.c b/espresso/cvrout.c new file mode 100644 index 0000000..fc09ed6 --- /dev/null +++ b/espresso/cvrout.c @@ -0,0 +1,597 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/cvrout.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + module: cvrout.c + purpose: cube and cover output routines +*/ + +#include "espresso.h" + +void fprint_pla(fp, PLA, output_type) +INOUT FILE *fp; +IN pPLA PLA; +IN int output_type; +{ + int num; + register pcube last, p; + + if ((output_type & CONSTRAINTS_type) != 0) { + output_symbolic_constraints(fp, PLA, 0); + output_type &= ~ CONSTRAINTS_type; + if (output_type == 0) { + return; + } + } + + if ((output_type & SYMBOLIC_CONSTRAINTS_type) != 0) { + output_symbolic_constraints(fp, PLA, 1); + output_type &= ~ SYMBOLIC_CONSTRAINTS_type; + if (output_type == 0) { + return; + } + } + + if (output_type == PLEASURE_type) { + pls_output(PLA); + } else if (output_type == EQNTOTT_type) { + eqn_output(PLA); + } else if (output_type == KISS_type) { + kiss_output(fp, PLA); + } else { + fpr_header(fp, PLA, output_type); + + num = 0; + if (output_type & F_type) num += (PLA->F)->count; + if (output_type & D_type) num += (PLA->D)->count; + if (output_type & R_type) num += (PLA->R)->count; + (void) fprintf(fp, ".p %d\n", num); + + /* quick patch 01/17/85 to support TPLA ! */ + if (output_type == F_type) { + foreach_set(PLA->F, last, p) { + print_cube(fp, p, "01"); + } + (void) fprintf(fp, ".e\n"); + } else { + if (output_type & F_type) { + foreach_set(PLA->F, last, p) { + print_cube(fp, p, "~1"); + } + } + if (output_type & D_type) { + foreach_set(PLA->D, last, p) { + print_cube(fp, p, "~2"); + } + } + if (output_type & R_type) { + foreach_set(PLA->R, last, p) { + print_cube(fp, p, "~0"); + } + } + (void) fprintf(fp, ".end\n"); + } + } +} + +void fpr_header(fp, PLA, output_type) +FILE *fp; +pPLA PLA; +int output_type; +{ + register int i, var; + int first, last; + + /* .type keyword gives logical type */ + if (output_type != F_type) { + (void) fprintf(fp, ".type "); + if (output_type & F_type) putc('f', fp); + if (output_type & D_type) putc('d', fp); + if (output_type & R_type) putc('r', fp); + putc('\n', fp); + } + + /* Check for binary or multiple-valued labels */ + if (cube.num_mv_vars <= 1) { + (void) fprintf(fp, ".i %d\n", cube.num_binary_vars); + if (cube.output != -1) + (void) fprintf(fp, ".o %d\n", cube.part_size[cube.output]); + } else { + (void) fprintf(fp, ".mv %d %d", cube.num_vars, cube.num_binary_vars); + for(var = cube.num_binary_vars; var < cube.num_vars; var++) + (void) fprintf(fp, " %d", cube.part_size[var]); + (void) fprintf(fp, "\n"); + } + + /* binary valued labels */ + if (PLA->label != NIL(char *) && PLA->label[1] != NIL(char) + && cube.num_binary_vars > 0) { + (void) fprintf(fp, ".ilb"); + for(var = 0; var < cube.num_binary_vars; var++) + (void) fprintf(fp, " %s", INLABEL(var)); + putc('\n', fp); + } + + /* output-part (last multiple-valued variable) labels */ + if (PLA->label != NIL(char *) && + PLA->label[cube.first_part[cube.output]] != NIL(char) + && cube.output != -1) { + (void) fprintf(fp, ".ob"); + for(i = 0; i < cube.part_size[cube.output]; i++) + (void) fprintf(fp, " %s", OUTLABEL(i)); + putc('\n', fp); + } + + /* multiple-valued labels */ + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) { + first = cube.first_part[var]; + last = cube.last_part[var]; + if (PLA->label != NULL && PLA->label[first] != NULL) { + (void) fprintf(fp, ".label var=%d", var); + for(i = first; i <= last; i++) { + (void) fprintf(fp, " %s", PLA->label[i]); + } + putc('\n', fp); + } + } + + if (PLA->phase != (pcube) NULL) { + first = cube.first_part[cube.output]; + last = cube.last_part[cube.output]; + (void) fprintf(fp, "#.phase "); + for(i = first; i <= last; i++) + putc(is_in_set(PLA->phase,i) ? '1' : '0', fp); + (void) fprintf(fp, "\n"); + } +} + +void pls_output(PLA) +IN pPLA PLA; +{ + register pcube last, p; + + (void) printf(".option unmerged\n"); + makeup_labels(PLA); + pls_label(PLA, stdout); + pls_group(PLA, stdout); + (void) printf(".p %d\n", PLA->F->count); + foreach_set(PLA->F, last, p) { + print_expanded_cube(stdout, p, PLA->phase); + } + (void) printf(".end\n"); +} + + +void pls_group(PLA, fp) +pPLA PLA; +FILE *fp; +{ + int var, i, col, len; + + (void) fprintf(fp, "\n.group"); + col = 6; + for(var = 0; var < cube.num_vars-1; var++) { + (void) fprintf(fp, " ("), col += 2; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + len = strlen(PLA->label[i]); + if (col + len > 75) + (void) fprintf(fp, " \\\n"), col = 0; + else if (i != 0) + putc(' ', fp), col += 1; + (void) fprintf(fp, "%s", PLA->label[i]), col += len; + } + (void) fprintf(fp, ")"), col += 1; + } + (void) fprintf(fp, "\n"); +} + + +void pls_label(PLA, fp) +pPLA PLA; +FILE *fp; +{ + int var, i, col, len; + + (void) fprintf(fp, ".label"); + col = 6; + for(var = 0; var < cube.num_vars; var++) + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + len = strlen(PLA->label[i]); + if (col + len > 75) + (void) fprintf(fp, " \\\n"), col = 0; + else + putc(' ', fp), col += 1; + (void) fprintf(fp, "%s", PLA->label[i]), col += len; + } +} + + + +/* + eqntott output mode -- output algebraic equations +*/ +void eqn_output(PLA) +pPLA PLA; +{ + register pcube p, last; + register int i, var, col, len; + int x; + bool firstand, firstor; + + if (cube.output == -1) + fatal("Cannot have no-output function for EQNTOTT output mode"); + if (cube.num_mv_vars != 1) + fatal("Must have binary-valued function for EQNTOTT output mode"); + makeup_labels(PLA); + + /* Write a single equation for each output */ + for(i = 0; i < cube.part_size[cube.output]; i++) { + (void) printf("%s = ", OUTLABEL(i)); + col = strlen(OUTLABEL(i)) + 3; + firstor = TRUE; + + /* Write product terms for each cube in this output */ + foreach_set(PLA->F, last, p) + if (is_in_set(p, i + cube.first_part[cube.output])) { + if (firstor) + (void) printf("("), col += 1; + else + (void) printf(" | ("), col += 4; + firstor = FALSE; + firstand = TRUE; + + /* print out a product term */ + for(var = 0; var < cube.num_binary_vars; var++) + if ((x=GETINPUT(p, var)) != DASH) { + len = strlen(INLABEL(var)); + if (col+len > 72) + (void) printf("\n "), col = 4; + if (! firstand) + (void) printf("&"), col += 1; + firstand = FALSE; + if (x == ZERO) + (void) printf("!"), col += 1; + (void) printf("%s", INLABEL(var)), col += len; + } + (void) printf(")"), col += 1; + } + (void) printf(";\n\n"); + } +} + + +char *fmt_cube(c, out_map, s) +register pcube c; +register char *out_map, *s; +{ + register int i, var, last, len = 0; + + for(var = 0; var < cube.num_binary_vars; var++) { + s[len++] = "?01-" [GETINPUT(c, var)]; + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + s[len++] = ' '; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + s[len++] = "01" [is_in_set(c, i) != 0]; + } + } + if (cube.output != -1) { + last = cube.last_part[cube.output]; + s[len++] = ' '; + for(i = cube.first_part[cube.output]; i <= last; i++) { + s[len++] = out_map [is_in_set(c, i) != 0]; + } + } + s[len] = '\0'; + return s; +} + + +void print_cube(fp, c, out_map) +register FILE *fp; +register pcube c; +register char *out_map; +{ + register int i, var, ch; + int last; + + for(var = 0; var < cube.num_binary_vars; var++) { + ch = "?01-" [GETINPUT(c, var)]; + putc(ch, fp); + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "01" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + if (cube.output != -1) { + last = cube.last_part[cube.output]; + putc(' ', fp); + for(i = cube.first_part[cube.output]; i <= last; i++) { + ch = out_map [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + putc('\n', fp); +} + + +void print_expanded_cube(fp, c, phase) +register FILE *fp; +register pcube c; +pcube phase; +{ + register int i, var, ch; + char *out_map; + + for(var = 0; var < cube.num_binary_vars; var++) { + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "~1" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "1~" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + if (cube.output != -1) { + var = cube.num_vars - 1; + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (phase == (pcube) NULL || is_in_set(phase, i)) { + out_map = "~1"; + } else { + out_map = "~0"; + } + ch = out_map[is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + putc('\n', fp); +} + + +char *pc1(c) pcube c; +{static char s1[256];return fmt_cube(c, "01", s1);} +char *pc2(c) pcube c; +{static char s2[256];return fmt_cube(c, "01", s2);} + + +void debug_print(T, name, level) +pcube *T; +char *name; +int level; +{ + register pcube *T1, p, temp; + register int cnt; + + cnt = CUBELISTSIZE(T); + temp = new_cube(); + if (verbose_debug && level == 0) + (void) printf("\n"); + (void) printf("%s[%d]: ord(T)=%d\n", name, level, cnt); + if (verbose_debug) { + (void) printf("cofactor=%s\n", pc1(T[0])); + for(T1 = T+2, cnt = 1; (p = *T1++) != (pcube) NULL; cnt++) + (void) printf("%4d. %s\n", cnt, pc1(set_or(temp, p, T[0]))); + } + free_cube(temp); +} + + +void debug1_print(T, name, num) +pcover T; +char *name; +int num; +{ + register int cnt = 1; + register pcube p, last; + + if (verbose_debug && num == 0) + (void) printf("\n"); + (void) printf("%s[%d]: ord(T)=%d\n", name, num, T->count); + if (verbose_debug) + foreach_set(T, last, p) + (void) printf("%4d. %s\n", cnt++, pc1(p)); +} + + +void cprint(T) +pcover T; +{ + register pcube p, last; + + foreach_set(T, last, p) + (void) printf("%s\n", pc1(p)); +} + + +int makeup_labels(PLA) +pPLA PLA; +{ + int var, i, ind; + + if (PLA->label == (char **) NULL) + PLA_labels(PLA); + + for(var = 0; var < cube.num_vars; var++) + for(i = 0; i < cube.part_size[var]; i++) { + ind = cube.first_part[var] + i; + if (PLA->label[ind] == (char *) NULL) { + PLA->label[ind] = ALLOC(char, 15); + if (var < cube.num_binary_vars) + if ((i % 2) == 0) + (void) sprintf(PLA->label[ind], "v%d.bar", var); + else + (void) sprintf(PLA->label[ind], "v%d", var); + else + (void) sprintf(PLA->label[ind], "v%d.%d", var, i); + } + } +} + + +kiss_output(fp, PLA) +FILE *fp; +pPLA PLA; +{ + register pset last, p; + + foreach_set(PLA->F, last, p) { + kiss_print_cube(fp, PLA, p, "~1"); + } + foreach_set(PLA->D, last, p) { + kiss_print_cube(fp, PLA, p, "~2"); + } +} + + +kiss_print_cube(fp, PLA, p, out_string) +FILE *fp; +pPLA PLA; +pcube p; +char *out_string; +{ + register int i, var; + int part, x; + + for(var = 0; var < cube.num_binary_vars; var++) { + x = "?01-" [GETINPUT(p, var)]; + putc(x, fp); + } + + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + putc(' ', fp); + if (setp_implies(cube.var_mask[var], p)) { + putc('-', fp); + } else { + part = -1; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (is_in_set(p, i)) { + if (part != -1) { + fatal("more than 1 part in a symbolic variable\n"); + } + part = i; + } + } + if (part == -1) { + putc('~', fp); /* no parts, hope its an output ... */ + } else { + (void) fputs(PLA->label[part], fp); + } + } + } + + if ((var = cube.output) != -1) { + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + x = out_string [is_in_set(p, i) != 0]; + putc(x, fp); + } + } + + putc('\n', fp); +} + +output_symbolic_constraints(fp, PLA, output_symbolic) +FILE *fp; +pPLA PLA; +int output_symbolic; +{ + pset_family A; + register int i, j; + int size, var, npermute, *permute, *weight, noweight; + + if ((cube.num_vars - cube.num_binary_vars) <= 1) { + return; + } + makeup_labels(PLA); + + for(var=cube.num_binary_vars; var < cube.num_vars-1; var++) { + + /* pull out the columns for variable "var" */ + npermute = cube.part_size[var]; + permute = ALLOC(int, npermute); + for(i=0; i < npermute; i++) { + permute[i] = cube.first_part[var] + i; + } + A = sf_permute(sf_save(PLA->F), permute, npermute); + FREE(permute); + + + /* Delete the singletons and the full sets */ + noweight = 0; + for(i = 0; i < A->count; i++) { + size = set_ord(GETSET(A,i)); + if (size == 1 || size == A->sf_size) { + sf_delset(A, i--); + noweight++; + } + } + + + /* Count how many times each is duplicated */ + weight = ALLOC(int, A->count); + for(i = 0; i < A->count; i++) { + RESET(GETSET(A, i), COVERED); + } + for(i = 0; i < A->count; i++) { + weight[i] = 0; + if (! TESTP(GETSET(A,i), COVERED)) { + weight[i] = 1; + for(j = i+1; j < A->count; j++) { + if (setp_equal(GETSET(A,i), GETSET(A,j))) { + weight[i]++; + SET(GETSET(A,j), COVERED); + } + } + } + } + + + /* Print out the contraints */ + if (! output_symbolic) { + (void) fprintf(fp, + "# Symbolic constraints for variable %d (Numeric form)\n", var); + (void) fprintf(fp, "# unconstrained weight = %d\n", noweight); + (void) fprintf(fp, "num_codes=%d\n", cube.part_size[var]); + for(i = 0; i < A->count; i++) { + if (weight[i] > 0) { + (void) fprintf(fp, "weight=%d: ", weight[i]); + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(GETSET(A,i), j)) { + (void) fprintf(fp, " %d", j); + } + } + (void) fprintf(fp, "\n"); + } + } + } else { + (void) fprintf(fp, + "# Symbolic constraints for variable %d (Symbolic form)\n", var); + for(i = 0; i < A->count; i++) { + if (weight[i] > 0) { + (void) fprintf(fp, "# w=%d: (", weight[i]); + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(GETSET(A,i), j)) { + (void) fprintf(fp, " %s", + PLA->label[cube.first_part[var]+j]); + } + } + (void) fprintf(fp, " )\n"); + } + } + FREE(weight); + } + } +} diff --git a/espresso/dominate.c b/espresso/dominate.c new file mode 100644 index 0000000..ca35719 --- /dev/null +++ b/espresso/dominate.c @@ -0,0 +1,98 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/dominate.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "mincov_int.h" + + +int +sm_row_dominance(A) +sm_matrix *A; +{ + register sm_row *prow, *prow1; + register sm_col *pcol, *least_col; + register sm_element *p, *pnext; + int rowcnt; + + rowcnt = A->nrows; + + /* Check each row against all other rows */ + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + + /* Among all columns with a 1 in this row, choose smallest */ + least_col = sm_get_col(A, prow->first_col->col_num); + for(p = prow->first_col->next_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + if (pcol->length < least_col->length) { + least_col = pcol; + } + } + + /* Only check for containment against rows in this column */ + for(p = least_col->first_row; p != 0; p = pnext) { + pnext = p->next_row; + + prow1 = sm_get_row(A, p->row_num); + if ((prow1->length > prow->length) || + (prow1->length == prow->length && + prow1->row_num > prow->row_num)) { + if (sm_row_contains(prow, prow1)) { + sm_delrow(A, prow1->row_num); + } + } + } + } + + return rowcnt - A->nrows; +} + +int +sm_col_dominance(A, weight) +sm_matrix *A; +int *weight; +{ + register sm_row *prow; + register sm_col *pcol, *pcol1; + register sm_element *p; + sm_row *least_row; + sm_col *next_col; + int colcnt; + + colcnt = A->ncols; + + /* Check each column against all other columns */ + for(pcol = A->first_col; pcol != 0; pcol = next_col) { + next_col = pcol->next_col; + + /* Check all rows to find the one with fewest elements */ + least_row = sm_get_row(A, pcol->first_row->row_num); + for(p = pcol->first_row->next_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + if (prow->length < least_row->length) { + least_row = prow; + } + } + + /* Only check for containment against columns in this row */ + for(p = least_row->first_col; p != 0; p = p->next_col) { + pcol1 = sm_get_col(A, p->col_num); + if (weight != 0 && weight[pcol1->col_num] > weight[pcol->col_num]) + continue; + if ((pcol1->length > pcol->length) || + (pcol1->length == pcol->length && + pcol1->col_num > pcol->col_num)) { + if (sm_col_contains(pcol, pcol1)) { + sm_delcol(A, pcol->col_num); + break; + } + } + } + } + + return colcnt - A->ncols; +} diff --git a/espresso/equiv.c b/espresso/equiv.c new file mode 100644 index 0000000..ce72fa4 --- /dev/null +++ b/espresso/equiv.c @@ -0,0 +1,94 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/equiv.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +#include "espresso.h" + + +find_equiv_outputs(PLA) +pPLA PLA; +{ + int i, j, ipart, jpart, some_equiv; + pcover *R, *F; + + some_equiv = FALSE; + + makeup_labels(PLA); + + F = ALLOC(pcover, cube.part_size[cube.output]); + R = ALLOC(pcover, cube.part_size[cube.output]); + + for(i = 0; i < cube.part_size[cube.output]; i++) { + ipart = cube.first_part[cube.output] + i; + R[i] = cof_output(PLA->R, ipart); + F[i] = complement(cube1list(R[i])); + } + + for(i = 0; i < cube.part_size[cube.output]-1; i++) { + for(j = i+1; j < cube.part_size[cube.output]; j++) { + ipart = cube.first_part[cube.output] + i; + jpart = cube.first_part[cube.output] + j; + + if (check_equiv(F[i], F[j])) { + (void) printf("# Outputs %d and %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(F[i], R[j])) { + (void) printf("# Outputs %d and NOT %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(R[i], F[j])) { + (void) printf("# Outputs NOT %d and %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(R[i], R[j])) { + (void) printf("# Outputs NOT %d and NOT %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } + } + } + + if (! some_equiv) { + (void) printf("# No outputs are equivalent\n"); + } + + for(i = 0; i < cube.part_size[cube.output]; i++) { + free_cover(F[i]); + free_cover(R[i]); + } + FREE(F); + FREE(R); +} + + + +int check_equiv(f1, f2) +pcover f1, f2; +{ + register pcube *f1list, *f2list; + register pcube p, last; + + f1list = cube1list(f1); + foreach_set(f2, last, p) { + if (! cube_is_covered(f1list, p)) { + return FALSE; + } + } + free_cubelist(f1list); + + f2list = cube1list(f2); + foreach_set(f1, last, p) { + if (! cube_is_covered(f2list, p)) { + return FALSE; + } + } + free_cubelist(f2list); + + return TRUE; +} diff --git a/espresso/espresso.1 b/espresso/espresso.1 new file mode 100644 index 0000000..563bef5 --- /dev/null +++ b/espresso/espresso.1 @@ -0,0 +1,294 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/espresso/espresso.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:13:59 $ +.\" * +.\" +.TH ESPRESSO 1OCTTOOLS "31 January 1988" +.SH NAME +espresso \- Boolean Minimization +.SH SYNOPSIS +.B espresso +[\fIoptions\fR] [\fIfile\fR] +.SH DESCRIPTION +.PP +.I Espresso +takes as input a two-level representation of a +two-valued (or multiple-valued) Boolean function, and produces a +minimal equivalent representation. The algorithms used are new and +represent an advance in both speed and optimality of solution in +heuristic Boolean minimization. +.PP +.I Espresso +reads the \fIfile\fR provided (or standard input if no files +are specified), performs the minimization, and writes the minimized result to +standard output. +.I Espresso +automatically verifies that the minimized function +is equivalent to the original function. +Options allow for using an exact minimization algorithm, for +choosing an optimal phase assignment for the output functions, and +for choosing an optimal assignment of the inputs to input decoders. +.PP +The default input and output file formats are compatible with the +Berkeley standard format for the physical description of a \s-1PLA\s0. The +input format is described in detail in espresso(5). Note that the +input file is a \fIlogical\fR representation of +a set of Boolean equations, and hence the input format differs +slightly from that described in pla(5) (which provides for the \fIphysical\fR +representation of a \s-1PLA\s0). +The input and output formats +have been expanded to allow for multiple-valued logic +functions, and to allow for the specification of the +don't-care set which will be used in the minimization. +.PP +A complete list of the command line options is given below. +Be warned that many of the command line options are not intended +for general use. +.TP 10 +.B -d +Enables debugging. +Useful only for those familiar with the algorithms used. +.TP 10 +.B -Dcheck +Checks that the function is a partition of the +entire space (i.e., that the \s-1ON\s0-set, \s-1OFF\s0-set +and \s-1DC\s0-set are +pairwise disjoint, and that their union is the Universe). +.ne 4 +.TP 10 +.B -Dd1merge +Performs a quick distance-1 merge on the input +file. This is useful when the input file +is very large (e.g., a truth table with more than 1000 terms) because +distance-1 merge is O(n log n) rather than the \s-1EXPAND\s0 +step of Espresso which is +O(n * n). The output should then be run through +Espresso to complete the minimization. A range of variables to +be merged can also be specified using +.B -rn-m +(the default is to merge over all variables). +.ne 4 +.TP 10 +.B -Decho +Echoes the function to standard output. +This can be used to get the complement of a function when +combined with \fB-o\fP. +.ne 4 +.TP 10 +.B -Dequiv +Identify output variables which are equivalent. Takes into account +the don't-care set and checks for equivalence of both the \s-1ON\s0-set +and \s-1OFF\s0-set. +.TP 10 +.B -Dexact +Exact minimization algorithm (guarantees minimum number of +product terms, and heuristically minimizes number of literals). +Potentially expensive. +.ne 4 +.TP 10 +.B -Dmany +Reads and minimizes PLA's until end-of-file is detected. PLA's in +the same file are separated by \fI.e\fP. +.ne 4 +.TP 10 +.B -Dmap +Draw the Karnaugh maps for a binary-valued function. +.ne 4 +.TP 10 +.B -Dmapdc +Derive from the binary-valued variable \fIDONT_\|CARE\fP a don't-care set, +and then delete this variable. +All input conditions for which an output changes when \fIDONT_\|CARE\fP +changes define the don't-care conditions for that output. +This is a hack to support don't-cares from high-level languages without +a notion of don't-cares. +.ne 4 +.TP 10 +.B -Dopo +Perform output phase optimization (i.e., determine which +functions to complement to reduce the number of +terms needed to implement the function). After choosing an +assignment of phases for the outputs, the function is minimized. +A simple algorithm is used which may become very expensive for +a large number of outputs (e.g., more than 40). +.TP 10 +.B -Dopoall +Minimize the function with all possible phase assignments. +A range of outputs to cycle through can be given with +.B -rn-m +(the default is to use all outputs). +The option +.B -S1 +will perform an exact minimization for each phase assignment. +Be warned that opoall requires an exponential number of minimizations ! +.TP 10 +.B -Dpair +Choose an assignment of the inputs to two-bit decoders, and +minimize the function. The function MUST be minimized first to +achieve good results. There are actually 4 different algorithms, +of increasing cost, which may be selected with +.BR -S1 , +.BR -S2 , +or +.BR -S3 . +The default is +.B -S0 +which seems to give the best results for the cost. +.TP 10 +.B -Dpairall +Minimize the function with all possible assignments of inputs to +two-bit decoders. +The option +.B -S1 +will perform an exact minimization for each assignment of inputs +to decoders, and the option +.B -S2 +will perform an output-phase assignment for each assignment of +inputs to decoders. +Be warned that pairall requires an exponential number of minimizations ! +.TP 10 +.B -Dseparate +Remove the don't-care set from the \s-1ON\s0-set of the function. +.TP 10 +.B -Dso +Minimize each function one at a time as a single-output function. +Terms will not be shared among the functions. +The option +.B -S1 +will perform an exact minimization for each single-output function. +.TP 10 +.B -Dso_both +Minimize each function one at a time as a single-output function, but +choose the function or its complement based on which has fewer terms. +The option +.B -S1 +will perform an exact minimization for each single-output function and +its complement to determine which has fewer terms. +.TP 10 +.B -Dstats +Provide simple statistics on the size of the function. +.TP 10 +.B -Dverify +Checks for Boolean equivalence of two PLA's. Reads two filenames +from the command line, each containing a single PLA. +.TP 10 +.B -DPLAverify +Checks for Boolean equivalence of two PLA's by first permuting the +columns based on the user supplied variable names. Reads two +filenames from the command line. +.TP 10 +.B -eeat +Normally comments are echoed from the input file to the output file. +This options discards any comments in the input file. +.TP 10 +.B -efast +Stop after the first \s-1EXPAND\s0 and \s-1IRREDUNDANT\s0 operations +(i.e., do not iterate over the solution). +.TP 10 +.B -ekiss +Sets up a \fIkiss\fR-style minimization problem. This is a hack. +.TP 10 +.B -eness +Essential primes will not be detected. +.TP 10 +.B -enirr +The result will not necessarily be made irredundant in the final step +which removes redundant literals. +.TP 10 +.B -enunwrap +The \s-1ON\s0-set will not be unwrapped before beginning the minimization. +.TP 10 +.B -eonset +Recompute the \s-1ON\s0-set before the minimization. Useful when the +\s-1PLA\s0 has a large number of product terms (e.g., an exhaustive +list of minterms). +.TP 10 +.B -epos +Swaps the \s-1ON\s0-set and \s-1OFF\s0-set of the function after +reading the function. This can be used to minimize the \s-1OFF\s0-set +of a function. \fI.phase\fR (see espresso(5)) +in the input file can also specify an arbitrary choice of output phases. +.TP 10 +.B -estrong +Uses the alternate strategy \s-1SUPER_\|GASP\s0 (as a replacement +for \s-1LAST_\ GASP\s0) which is +more expensive, but occasionally provides better results. +.TP 10 +.B -o[type] +Selects the output format. By default, only the \s-1ON\s0-set (i.e., +type f) is output after the minimization. [type] can be one of \fBf\fR, +\fBd\fR, \fBr\fR, \fBfd\fR, \fBdr\fR, \fBfr\fR, or \fBfdr\fR to select +any combination of the \s-1ON\s0-set (f), the \s-1OFF\s0-set (r) or the +\s-1DC\s0-set (d). [type] may also be \fBeqntott\fR to output algebraic +equations acceptable to +.IR eqntott (1OCTTOOLS), +or \fBpleasure\fR to output an +unmerged \s-1PLA\s0 (with the \fI.label\fR and \fI.group\fR keywords) +acceptable to +.IR pleasure (1OCTTOOLS). +.TP 10 +.B -s +Will provide a short summary of the execution of the program including +the initial cost of the function, the final cost, and the computer +resources used. +.TP 10 +.B -t +Will produce a trace showing the execution of the program. After each +main step of the algorithm, a single line is printed which reports the +processor time used, and the current cost of the function. +.TP 10 +.B -x +Suppress printing of the solution. +.TP 10 +.B -v [type] +Specifies verbose debugging detail. Not generally useful. +.SH DIAGNOSTICS +Espresso will issue a warning message +if a product term spans more than one line. Usually this is an +indication that the number of inputs or outputs of the function +is specified incorrectly. +.SH "SEE ALSO" +kiss(1OCTTOOLS), pleasure(1OCTTOOLS), pla(5OCTTOOLS), espresso(5OCTTOOLS) +.LP +R. Brayton, G. Hachtel, C. McMullen, and A. Sangiovanni-Vincentelli, +\fILogic Minimization Algorithms for VLSI Synthesis\fR, +Kluwer Academic Publishers, 1984. +.LP +R. Rudell, A. Sangiovanni-Vincentelli, +"Espresso-MV: Algorithms for Multiple-Valued Logic Minimization," +\fIProc. Cust. Int. Circ. Conf.\fR, Portland, May 1985. +.LP +R. Rudell, "Multiple-Valued Minimization for PLA Synthesis," +Master's Report, University of California, Berkeley, June 1986. +.LP +R. Rudell, A. Sangiovanni-Vincentelli, +"Exact Minimization of Multiple-Valued Functions for PLA Optimization", +\fIInt. Conf. Comp. Aid. Des.\fP, Santa Clara, November 1986. +.SH AUTHOR +Please direct any questions or comments to: +.nf +Richard Rudell +205 Cory Hall +Dept. of EECS +University of California +Berkeley, California 94720 +.fi +.LP +Arpanet mail address is rudell@ic.Berkeley.EDU. +.SH COMMENTS +Default is to pass comments and unrecognized options from the input file +to standard output (sometimes this isn't what you want). +.LP +It is no longer possible to specify the type on the command line. +.LP +There are a lot of options, but typical use doesn't need them. +.LP +This manual page refers to Version 2.3 of Espresso. The major change from +Version 2.2 to Version 2.3 is the addition of a fast sparse-matrix +covering algorithm for the \fB-Dexact\fP mode. +.LP +The -Dopo option becomes very slow for many outputs (> 20). diff --git a/espresso/espresso.5 b/espresso/espresso.5 new file mode 100644 index 0000000..f168d09 --- /dev/null +++ b/espresso/espresso.5 @@ -0,0 +1,469 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/espresso/espresso.5,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:13:59 $ +.\" * +.\" +.TH ESPRESSO 5OCTTOOLS "22 August 1986" +.SH NAME +espresso \- input file format for espresso(1OCTTOOLS) +.SH DESCRIPTION +\fIEspresso\fR accepts as input a two-level description of a Boolean +function. This is described as a character matrix with keywords +embedded in the input to specify the size of the matrix and +the logical format of the input function. +Programs exist to translate a set of equations into +this format (e.g., eqntott(1OCTTOOLS), bdsyn(1OCTTOOLS), eqntopla(1OCTTOOLS)). +This manual page refers to Version 2.3 of \fIEspresso\fP. +.PP +Comments are allowed within the input by placing a +pound sign (#) as the first character on a line. +Comments and unrecognized keywords are passed +directly from the input file to standard output. Any white-space +(blanks, tabs, etc.), except when used as a delimiter in an embedded +command, is ignored. It is generally assumed that the \s-1PLA\s0 is specified +such that each row of the \s-1PLA\s0 fits on a single line in the input file. +.SH KEYWORDS +The following keywords are recognized by \fIespresso\fR. +The list shows +the probable order of the keywords in a \s-1PLA\s0 description. +[d] denotes a decimal number and [s] denotes a +text string. The minimum required set of +keywords is \fB.i\fP and \fB.o\fP for binary-valued +functions, or \fB.mv\fP for multiple-valued functions. +.TP 12 +.B .i [d] +Specifies the number of input variables. +.TP 12 +.B .o [d] +Specifies the number of output functions. +.TP 12 +.B ".mv [num_\|var] [num_\|binary_\|var] [d1] . . . [dn]" +Specifies the number of variables (num_\|var), the number of binary variables +(num_\|binary_\|var), +and the size of each of the multiple-valued variables (d1 through dn). +.TP 12 +.B ".ilb [s1] [s2] . . . [sn]" +Gives the names of the binary valued variables. +This must come after \fB.i\fP and \fB.o\fP (or after \fB.mv\fP). +There must be as many tokens following the keyword as there +are input variables. +.TP 12 +.B ".ob [s1] [s2] . . . [sn]" +Gives the names of the output functions. +This must come after \fB.i\fP and \fB.o\fP (or after \fB.mv\fP). +There must be as many tokens following the keyword as there +are output variables. +.TP 12 +.B .label var=[d] [s1] [s2] ... +Specifies the names of the parts of a multiple-valued variable. +This must come after \fB.mv\fP. +There must be as many tokens following the keyword as there +are parts for this variable. Note that the variables are numbered +starting from 0. +.TP 12 +.B .type [s] +Sets the logical interpretation of the character matrix as +described below under "Logical Description of a \s-1PLA\s0". This keyword +must come before any product terms. +[s] is one of f, r, fd, fr, dr, or fdr. +.TP 12 +.B .phase [s] +[s] is a string of as many 0's or 1's as there are output +functions. It specifies which polarity of each output function +should be used for the minimization (a 1 specifies that the +\s-1ON\s0-set of the corresponding output function should be used, and +a 0 specifies that the \s-1OFF\s0-set of the corresponding output function +should be minimized). +.TP 12 +.B .pair [d] +Specifies the number of pairs of variables which will be paired together +using two-bit decoders. +The rest of the +line contains pairs of numbers which specify the binary variables +of the \s-1PLA\s0 which +will be paired together. The binary variables are numbered +starting with 0. The \s-1PLA\s0 will be reshaped so that any unpaired binary +variables occupy the leftmost part of the array, then the paired +multiple-valued columns, and finally any multiple-valued variables. +If the labels have been specified using \fB.ilb\fP, then the variable +names may be used instead of the column number. +.TP 12 +.B ".symbolic [s0] [s1] . . . [sn] ; [t0] [t1] . . . [tm] ;" +Specifies that the binary-valued variables named [s0] thru [sn] are to be +considered as a single multiple-valued variable. +Variable [s0] is considered the most significant bit, [s1] the next +most significant, and [sn] is the least significant bit. +This creates a variable +with 2**n parts corresponding to the decodes of the binary-valued variables. +The keywords [t0] thru [tm] provide the labels for each decode of +[s0] thru [sn]. ([t0] corresponds to a value of 00...00, +[t1] is the value 00...01, etc.). +The binary-variables may be +identified by column number, or by variable name when \fB.ilb\fP is used. +The binary-variables are removed from the function after the +multiple-valued variable is created. +.TP 12 +.B ".symbolic-output [s0] [s1] . . . [sn] ; [t0] [t1] . . . [tm] ;" +Specifies that the output functions [s0] ... [sn] are to be considered +as a single symbolic output. This creates 2**n more output variables +corresponding to the possible values of the outputs. +The outputs may be identified by number (starting from 0), +or by variable name when \fB.ob\fP is used. +The outputs are removed from the function after the new +set of outputs is created. +.TP 12 +.B .kiss +Sets up for a \fIkiss\fR-style minimization. +.TP 12 +.B .p [d] +Specifies the number of product terms. The product terms (one per line) +follow immediately after this keyword. Actually, this line is ignored, +and the ".e", ".end", +or the end of the file indicate the end of the input description. +.TP 12 +.B .e (.end) +Optionally marks the end of the \s-1PLA\s0 description. +.sp 2 +.SH "LOGICAL DESCRIPTION OF A PLA" +When we speak of the \s-1ON\s0-set of a +Boolean function, we mean those minterms which +imply the function value is a 1. +Likewise, the \s-1OFF\s0-set are those terms +which imply the function is a 0, and the \s-1DC\s0-set (don't care set) +are those terms for which the function is unspecified. +A function is +completely described by providing +its \s-1ON\s0-set, \s-1OFF\s0-set and \s-1DC\s0-set. +Note that all minterms lie in the union of the \s-1ON\s0-set, \s-1OFF\s0-set +and \s-1DC\s0-set, and +that the \s-1ON\s0-set, \s-1OFF\s0-set and \s-1DC\s0-set share no minterms. +.PP +The purpose of the +.I espresso +minimization program is to find a logically +equivalent set of product-terms to +represent the \s-1ON\s0-set and optionally minterms +which lie in the \s-1DC\s0-set, without containing any minterms of the \s-1OFF\s0-set. +.PP +A Boolean function +can be described in one of the +following ways: +.IP 1) +By providing the \s-1ON\s0-set. In this case, +.I espresso +computes the \s-1OFF\s0-set as the complement of the \s-1ON\s0-set and the \s-1DC\s0-set is empty. +This is indicated with the keyword \fB.type f\fR +in the input file. +.IP 2) +By providing the \s-1ON\s0-set and \s-1DC\s0-set. In this case, +.I espresso +computes the \s-1OFF\s0-set as the complement of the union +of the \s-1ON\s0-set and the \s-1DC\s0-set. If any minterm belongs to both the +\s-1ON\s0-set and \s-1DC\s0-set, then it is considered a don't care and may be removed +from the \s-1ON\s0-set during the minimization process. +This is indicated with the keyword \fB.type fd\fR +in the input file. +.IP 3) +By providing the \s-1ON\s0-set and \s-1OFF\s0-set. In this case, +.I espresso +computes the \s-1DC\s0-set as the complement of the union +of the \s-1ON\s0-set and the \s-1OFF\s0-set. It is an error for +any minterm to belong to both the \s-1ON\s0-set and \s-1OFF\s0-set. +This error may not be detected during the +minimization, but it can be checked +with the subprogram "-Dcheck" which will +check the consistency of a function. +This is indicated with the keyword \fB.type fr\fR in the input file. +.IP 4) +By providing the \s-1ON\s0-set, \s-1OFF\s0-set and \s-1DC\s0-set. +This is indicated with the keyword \fB.type fdr\fR +in the input file. +.PP +If at all possible, +.I espresso +should be given the \s-1DC\s0-set (either +implicitly or explicitly) in order to improve the results of the +minimization. +.PP +A term is represented by a "cube" which can be considered either +a compact representation of an algebraic product term which implies +the function value is a 1, +or as a representation of a row in a \s-1PLA\s0 which +implements the term. +A cube has an input part which corresponds to the input plane of +a \s-1PLA\s0, and an output part which corresponds to the output plane +of a \s-1PLA\s0 (for the multiple-valued case, see below). +.sp 1 +.SH "SYMBOLS IN THE PLA MATRIX AND THEIR INTERPRETATION" +.PP +Each position in the input plane corresponds to an input variable +where a 0 implies the corresponding input literal appears +complemented in the product term, a 1 implies the input literal +appears uncomplemented in the product term, and - +implies the input literal does not appear in the product term. +.PP +With type \fIf\fR, for each output, +a \fB1\fR means this product term belongs to the \s-1ON\s0-set, and +a \fB0\fR or \fB\-\fR means this product term has no meaning for the value +of this function. +This type corresponds to an actual \s-1PLA\s0 where +only the \s-1ON\s0-set is actually implemented. +.PP +With type \fIfd\fR (the default), for each output, +a \fB1\fR means this product term belongs to the \s-1ON\s0-set, +a \fB0\fR means this product term +has no meaning for the value of this function, +and a \fB\-\fR implies this product term belongs to the \s-1DC\s0-set. +.PP +With type \fIfr\fR, for each output, +a \fB1\fR means this product term belongs to the \s-1ON\s0-set, +a \fB0\fR means this product term belongs to the \s-1OFF\s0-set, +and a \fB\-\fR means this product term has no meaning for the value +of this function. +.PP +With type \fIfdr\fR, for each output, +a \fB1\fR means this product term belongs to the \s-1ON\s0-set, +a \fB0\fR means this product term belongs to the \s-1OFF\s0-set, +a \fB\-\fR means this product term belongs to the \s-1DC\s0-set, +and a \fB~\fR implies this product term has no meaning for the value of this +function. +.PP +Note that regardless of the type of \s-1PLA\s0, +a \fB~\fR implies the product term has no meaning for the value of this +function. \fB2\fR is allowed as a synonym for \fB\-\fR, \fB4\fR is allowed +for \fB1\fR, and \fB3\fR is allowed for \fB~\fR. +.PP +.SH "MULTIPLE-VALUED FUNCTIONS" +Espresso will also minimize multiple-valued Boolean functions. There +can be an arbitrary number of multiple-valued variables, and each can be +of a different size. If there are also binary-valued variables, they +should be given as the first variables on the line (for ease of description). +Of course, it is always possible to place them anywhere on the +line as a two-valued multiple-valued variable. +The function size is described by the +embedded option \fB.mv\fR rather than \fB.i\fR and \fB.o\fR. +.PP +A multiple-output binary function with \fIni\fR +inputs and \fIno\fR outputs would be specified as \fB.mv\fP \fIni+1 ni no\fP. +.B .mv +cannot be used with +either \fB.i\fP or \fB.o\fP \- use one or the other +to specify the function size. +.PP +The binary variables are given as described above. Each of the +multiple-valued variables are given as a bit-vector of \fB0\fR and \fB1\fR +which have their usual meaning for multiple-valued functions. +The last multiple-valued variable (also called the output) +is interpreted as described above for the output (to split the +function into an \s-1ON\s0-set, \s-1OFF\s0-set and \s-1DC\s0-set). +A vertical bar \fB|\fR may be used to separate the multiple-valued +fields in the input file. +.PP +If the size of the multiple-valued field is less than zero, than +a symbolic field is interpreted from the input file. The absolute value +of the size specifies the maximum number of unique symbolic labels which +are expected in this column. The symbolic labels are white-space +delimited strings of characters. +.PP +To perform a \fIkiss\fR-style encoding problem, the keyword \fB.kiss\fR +should be included in the file. +The third to last variable on the +input file must be the symbolic "present state", and the second to last +variable +must be the "next state". As always, the last variable is the output. +The symbolic "next state" will be hacked to be actually part of the output. +.bp +.SH EXAMPLE #1 +A two-bit adder which takes in two 2-bit operands and produces a 3-bit +result can be described completely in minterms as: +.sp +.nf +.cs R 22 + # 2-bit by 2-bit binary adder (with no carry input) + .i 4 + .o 3 + 0000 000 + 0001 001 + 0010 010 + 0011 011 + 0100 001 + 0101 010 + 0110 011 + 0111 100 + 1000 010 + 1001 011 + 1010 100 + 1011 101 + 1100 011 + 1101 100 + 1110 101 + 1111 110 +.cs R +.fi +.sp +.LP +It is also possible to specify some extra options, such as: +.sp +.cs R 22 +.nf + # 2-bit by 2-bit binary adder (with no carry input) + .i 4 + .o 3 + .ilb a1 a0 b1 b0 + .ob s2 s1 s0 + .pair 2 (a1 b1) (a0 b0) + .phase 011 + 0000 000 + 0001 001 + 0010 010 + . + . + . + 1111 110 + .e +.fi +.cs R +.sp +.LP +The option \fI.pair\fR indicates that the first binary-valued +variable should be paired with the third binary-valued variable, and +that the second variable should be paired with the fourth variable. +The function will then be mapped into an equivalent multiple-valued +minimization problem. +.sp +The option \fI.phase\fR indicates that the positive-phase +should be used for the second and third outputs, and that +the negative phase should be used for the first output. +.bp +.SH EXAMPLE #2 +This example shows a description of a multiple-valued function +with 5 binary variables and 3 multiple-valued variables +(8 variables total) +where the multiple-valued variables have sizes of 4 27 and 10 +(note that the last multiple-valued variable is the "output" +and also encodes the \s-1ON\s0-set, \s-1DC\s0-set and \s-1OFF\s0-set information). +.sp 1 +.cs R 22 +.nf + .mv 8 5 4 27 10 + .ilb in1 in2 in3 in4 in5 + .label var=5 part1 part2 part3 part4 + .label var=6 a b c d e f g h i j k l m n + o p q r s t u v w x y z a1 + .label var=7 out1 out2 out3 out4 out5 out6 + out7 out8 out9 out10 + 0-010|1000|100000000000000000000000000|0010000000 + 10-10|1000|010000000000000000000000000|1000000000 + 0-111|1000|001000000000000000000000000|0001000000 + 0-10-|1000|000100000000000000000000000|0001000000 + 00000|1000|000010000000000000000000000|1000000000 + 00010|1000|000001000000000000000000000|0010000000 + 01001|1000|000000100000000000000000000|0000000010 + 0101-|1000|000000010000000000000000000|0000000000 + 0-0-0|1000|000000001000000000000000000|1000000000 + 10000|1000|000000000100000000000000000|0000000000 + 11100|1000|000000000010000000000000000|0010000000 + 10-10|1000|000000000001000000000000000|0000000000 + 11111|1000|000000000000100000000000000|0010000000 + . + . + . + 11111|0001|000000000000000000000000001|0000000000 +.cs R +.bp +.SH EXAMPLE #3 +This example shows a description of a multiple-valued function setup +for \fIkiss\fR-style minimization. +There are +5 binary variables, 2 symbolic variables (the present-state and +the next-state of the FSM) and the output (8 variables total). +.sp 1 +.cs R 22 +.nf + .mv 8 5 -10 -10 6 + .ilb io1 io0 init swr mack + .ob wait minit mrd sack mwr dli + .type fr + .kiss + --1-- - init0 110000 + --1-- init0 init0 110000 + --0-- init0 init1 110000 + --00- init1 init1 110000 + --01- init1 init2 110001 + --0-- init2 init4 110100 + --01- init4 init4 110100 + --00- init4 iowait 000000 + 0000- iowait iowait 000000 + 1000- iowait init1 110000 + 01000 iowait read0 101000 + 11000 iowait write0 100010 + 01001 iowait rmack 100000 + 11001 iowait wmack 100000 + --01- iowait init2 110001 + --0-0 rmack rmack 100000 + --0-1 rmack read0 101000 + --0-0 wmack wmack 100000 + --0-1 wmack write0 100010 + --0-- read0 read1 101001 + --0-- read1 iowait 000000 + --0-- write0 iowait 000000 +.cs R +.bp +.SH EXAMPLE 4 +This example shows the use of the \fB.symbolic\fP keyword to +setup a multiple-valued minimization problem. +.sp 1 +.cs R 26 +.nf + .i 15 + .o 4 + .ilb SeqActive<0> CacheOp<6> CacheOp<5> CacheOp<4> + CacheOp<3> CacheOp<2> CacheOp<1> CacheOp<0> + userKernel<0> Protection<1> Protection<0> + cacheState<1> cacheState<0> PageDirty<0> + WriteCycleIn<0> + + .ob CacheBusy<0> dataMayBeValid<0> dataIsValid<0> + WriteCycleOut<0> + + .symbolic CacheOp<6> CacheOp<5> CacheOp<4> CacheOp<3> + CacheOp<2> CacheOp<1> CacheOp<0> ; + FET NA PHY_FET PR32 PRE_FET PW32 RA32 RD32 + RD64 RDCACHE RFO32 RFO64 TS32 WR32 WR64 WRCACHE ; + + .symbolic Protection<1> Protection<0> ; + PROT_KRO_UNA PROT_KRW_UNA PROT_KRW_URO PROT_KRW_URW ; + + .symbolic cacheState<1> cacheState<0> ; + CS_Invalid CS_OwnPrivate CS_OwnShared CS_UnOwned ; + + .p 22 + 0000001--010110 0001 + 0000001-1-00110 0001 + 00001011-01011- 0100 + 000010111-0011- 0100 + 0000--001--01-- 0100 + 0000-10--0-1--- 0100 + 0000-10-1--1--- 0100 + 00000-0--0-1--- 0100 + 00000-0-1--1--- 0100 + 0000-10--0--1-- 0100 + 0000-10-1---1-- 0100 + 00000-0--0--1-- 0100 + 00000-0-1---1-- 0100 + ---1----------- 1000 + --1------------ 1000 + -1------------- 1000 + 1-------------- 1000 + -------0------- 1000 + ----1---------- 1000 + -----0--------- 1000 + ------0-------- 1000 + --------------1 1110 + .e +.fi +.cs R diff --git a/espresso/espresso.c b/espresso/espresso.c new file mode 100644 index 0000000..ea5920f --- /dev/null +++ b/espresso/espresso.c @@ -0,0 +1,139 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/espresso.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + * Module: espresso.c + * Purpose: The main espresso algorithm + * + * Returns a minimized version of the ON-set of a function + * + * The following global variables affect the operation of Espresso: + * + * MISCELLANEOUS: + * trace + * print trace information as the minimization progresses + * + * remove_essential + * remove essential primes + * + * single_expand + * if true, stop after first expand/irredundant + * + * LAST_GASP or SUPER_GASP strategy: + * use_super_gasp + * uses the super_gasp strategy rather than last_gasp + * + * SETUP strategy: + * recompute_onset + * recompute onset using the complement before starting + * + * unwrap_onset + * unwrap the function output part before first expand + * + * MAKE_SPARSE strategy: + * force_irredundant + * iterates make_sparse to force a minimal solution (used + * indirectly by make_sparse) + * + * skip_make_sparse + * skip the make_sparse step (used by opo only) + */ + +#include "espresso.h" + +pcover espresso(F, D1, R) +pcover F, D1, R; +{ + pcover E, D, Fsave; + pset last, p; + cost_t cost, best_cost; + +begin: + Fsave = sf_save(F); /* save original function */ + D = sf_save(D1); /* make a scratch copy of D */ + + /* Setup has always been a problem */ + if (recompute_onset) { + EXEC(E = simplify(cube1list(F)), "SIMPLIFY ", E); + free_cover(F); + F = E; + } + cover_cost(F, &cost); + if (unwrap_onset && (cube.part_size[cube.num_vars - 1] > 1) + && (cost.out != cost.cubes*cube.part_size[cube.num_vars-1]) + && (cost.out < 5000)) + EXEC(F = sf_contain(unravel(F, cube.num_vars - 1)), "SETUP ", F); + + /* Initial expand and irredundant */ + foreach_set(F, last, p) { + RESET(p, PRIME); + } + EXECUTE(F = expand(F, R, FALSE), EXPAND_TIME, F, cost); + EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); + + if (! single_expand) { + if (remove_essential) { + EXECUTE(E = essential(&F, &D), ESSEN_TIME, E, cost); + } else { + E = new_cover(0); + } + + cover_cost(F, &cost); + do { + + /* Repeat inner loop until solution becomes "stable" */ + do { + copy_cost(&cost, &best_cost); + EXECUTE(F = reduce(F, D), REDUCE_TIME, F, cost); + EXECUTE(F = expand(F, R, FALSE), EXPAND_TIME, F, cost); + EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); + } while (cost.cubes < best_cost.cubes); + + /* Perturb solution to see if we can continue to iterate */ + copy_cost(&cost, &best_cost); + if (use_super_gasp) { + F = super_gasp(F, D, R, &cost); + if (cost.cubes >= best_cost.cubes) + break; + } else { + F = last_gasp(F, D, R, &cost); + } + + } while (cost.cubes < best_cost.cubes || + (cost.cubes == best_cost.cubes && cost.total < best_cost.total)); + + /* Append the essential cubes to F */ + F = sf_append(F, E); /* disposes of E */ + if (trace) size_stamp(F, "ADJUST "); + } + + /* Free the D which we used */ + free_cover(D); + + /* Attempt to make the PLA matrix sparse */ + if (! skip_make_sparse) { + F = make_sparse(F, D1, R); + } + + /* + * Check to make sure function is actually smaller !! + * This can only happen because of the initial unravel. If we fail, + * then run the whole thing again without the unravel. + */ + if (Fsave->count < F->count) { + free_cover(F); + F = Fsave; + unwrap_onset = FALSE; + goto begin; + } else { + free_cover(Fsave); + } + + return F; +} diff --git a/espresso/espresso.h b/espresso/espresso.h new file mode 100644 index 0000000..29f634a --- /dev/null +++ b/espresso/espresso.h @@ -0,0 +1,779 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/espresso.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:56 $ + * + */ +/* + * espresso.h -- header file for Espresso-mv + */ + +#include "port.h" +#include "utility.h" +#include "sparse.h" +#include "mincov.h" + +#define ptime() util_cpu_time() +#define print_time(t) util_print_time(t) + +#ifdef IBM_WATC +#define void int +#include "short.h" +#endif + +#ifdef IBMPC /* set default options for IBM/PC */ +#define NO_INLINE +#define BPI 16 +#endif + +/*-----THIS USED TO BE set.h----- */ + +/* + * set.h -- definitions for packed arrays of bits + * + * This header file describes the data structures which comprise a + * facility for efficiently implementing packed arrays of bits + * (otherwise known as sets, cf. Pascal). + * + * A set is a vector of bits and is implemented here as an array of + * unsigned integers. The low order bits of set[0] give the index of + * the last word of set data. The higher order bits of set[0] are + * used to store data associated with the set. The set data is + * contained in elements set[1] ... set[LOOP(set)] as a packed bit + * array. + * + * A family of sets is a two-dimensional matrix of bits and is + * implemented with the data type "set_family". + * + * BPI == 32 and BPI == 16 have been tested and work. + */ + + +/* Define host machine characteristics of "unsigned int" */ +#ifndef BPI +#define BPI 32 /* # bits per integer */ +#endif + +#if BPI == 32 +#define LOGBPI 5 /* log(BPI)/log(2) */ +#else +#define LOGBPI 4 /* log(BPI)/log(2) */ +#endif + +/* Define the set type */ +typedef unsigned int *pset; + +/* Define the set family type -- an array of sets */ +typedef struct set_family { + int wsize; /* Size of each set in 'ints' */ + int sf_size; /* User declared set size */ + int capacity; /* Number of sets allocated */ + int count; /* The number of sets in the family */ + int active_count; /* Number of "active" sets */ + pset data; /* Pointer to the set data */ + struct set_family *next; /* For garbage collection */ +} set_family_t, *pset_family; + +/* Macros to set and test single elements */ +#define WHICH_WORD(element) (((element) >> LOGBPI) + 1) +#define WHICH_BIT(element) ((element) & (BPI-1)) + +/* # of ints needed to allocate a set with "size" elements */ +#if BPI == 32 +#define SET_SIZE(size) ((size) <= BPI ? 2 : (WHICH_WORD((size)-1) + 1)) +#else +#define SET_SIZE(size) ((size) <= BPI ? 3 : (WHICH_WORD((size)-1) + 2)) +#endif + +/* + * Three fields are maintained in the first word of the set + * LOOP is the index of the last word used for set data + * LOOPCOPY is the index of the last word in the set + * SIZE is available for general use (e.g., recording # elements in set) + * NELEM retrieves the number of elements in the set + */ +#define LOOP(set) (set[0] & 0x03ff) +#define PUTLOOP(set, i) (set[0] &= ~0x03ff, set[0] |= (i)) +#if BPI == 32 +#define LOOPCOPY(set) LOOP(set) +#define SIZE(set) (set[0] >> 16) +#define PUTSIZE(set, size) (set[0] &= 0xffff, set[0] |= ((size) << 16)) +#else +#define LOOPCOPY(set) (LOOP(set) + 1) +#define SIZE(set) (set[LOOP(set)+1]) +#define PUTSIZE(set, size) ((set[LOOP(set)+1]) = (size)) +#endif + +#define NELEM(set) (BPI * LOOP(set)) +#define LOOPINIT(size) ((size <= BPI) ? 1 : WHICH_WORD((size)-1)) + +/* + * FLAGS store general information about the set + */ +#define SET(set, flag) (set[0] |= (flag)) +#define RESET(set, flag) (set[0] &= ~ (flag)) +#define TESTP(set, flag) (set[0] & (flag)) + +/* Flag definitions are ... */ +#define PRIME 0x8000 /* cube is prime */ +#define NONESSEN 0x4000 /* cube cannot be essential prime */ +#define ACTIVE 0x2000 /* cube is still active */ +#define REDUND 0x1000 /* cube is redundant(at this point) */ +#define COVERED 0x0800 /* cube has been covered */ +#define RELESSEN 0x0400 /* cube is relatively essential */ + +/* Most efficient way to look at all members of a set family */ +#define foreach_set(R, last, p)\ + for(p=R->data,last=p+R->count*R->wsize;pwsize) +#define foreach_remaining_set(R, last, pfirst, p)\ + for(p=pfirst+R->wsize,last=R->data+R->count*R->wsize;pwsize) +#define foreach_active_set(R, last, p)\ + foreach_set(R,last,p) if (TESTP(p, ACTIVE)) + +/* Another way that also keeps the index of the current set member in i */ +#define foreachi_set(R, i, p)\ + for(p=R->data,i=0;icount;p+=R->wsize,i++) +#define foreachi_active_set(R, i, p)\ + foreachi_set(R,i,p) if (TESTP(p, ACTIVE)) + +/* Looping over all elements in a set: + * foreach_set_element(pset p, int i, unsigned val, int base) { + * . + * . + * . + * } + */ +#define foreach_set_element(p, i, val, base) \ + for(i = LOOP(p); i > 0; ) \ + for(val = p[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) \ + if (val & 1) + +/* Return a pointer to a given member of a set family */ +#define GETSET(family, index) ((family)->data + (family)->wsize * (index)) + +/* Allocate and deallocate sets */ +#define set_new(size) set_clear(ALLOC(unsigned int, SET_SIZE(size)), size) +#define set_full(size) set_fill(ALLOC(unsigned int, SET_SIZE(size)), size) +#define set_save(r) set_copy(ALLOC(unsigned int, SET_SIZE(NELEM(r))), r) +#define set_free(r) FREE(r) + +/* Check for set membership, remove set element and insert set element */ +#define is_in_set(set, e) (set[WHICH_WORD(e)] & (1 << WHICH_BIT(e))) +#define set_remove(set, e) (set[WHICH_WORD(e)] &= ~ (1 << WHICH_BIT(e))) +#define set_insert(set, e) (set[WHICH_WORD(e)] |= 1 << WHICH_BIT(e)) + +/* Inline code substitution for those places that REALLY need it on a VAX */ +#ifdef NO_INLINE +#define INLINEset_copy(r, a) (void) set_copy(r,a) +#define INLINEset_clear(r, size) (void) set_clear(r, size) +#define INLINEset_fill(r, size) (void) set_fill(r, size) +#define INLINEset_and(r, a, b) (void) set_and(r, a, b) +#define INLINEset_or(r, a, b) (void) set_or(r, a, b) +#define INLINEset_diff(r, a, b) (void) set_diff(r, a, b) +#define INLINEset_ndiff(r, a, b, f) (void) set_ndiff(r, a, b, f) +#define INLINEset_xor(r, a, b) (void) set_xor(r, a, b) +#define INLINEset_xnor(r, a, b, f) (void) set_xnor(r, a, b, f) +#define INLINEset_merge(r, a, b, mask) (void) set_merge(r, a, b, mask) +#define INLINEsetp_implies(a, b, when_false) \ + if (! setp_implies(a,b)) when_false +#define INLINEsetp_disjoint(a, b, when_false) \ + if (! setp_disjoint(a,b)) when_false +#define INLINEsetp_equal(a, b, when_false) \ + if (! setp_equal(a,b)) when_false + +#else + +#define INLINEset_copy(r, a)\ + {register int i_=LOOPCOPY(a); do r[i_]=a[i_]; while (--i_>=0);} +#define INLINEset_clear(r, size)\ + {register int i_=LOOPINIT(size); *r=i_; do r[i_] = 0; while (--i_ > 0);} +#define INLINEset_fill(r, size)\ + {register int i_=LOOPINIT(size); *r=i_; \ + r[i_]=((unsigned int)(~0))>>(i_*BPI-size); while(--i_>0) r[i_]=~0;} +#define INLINEset_and(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] & b[i_]; while (--i_>0);} +#define INLINEset_or(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] | b[i_]; while (--i_>0);} +#define INLINEset_diff(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] & ~ b[i_]; while (--i_>0);} +#define INLINEset_ndiff(r, a, b, fullset)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = fullset[i_] & (a[i_] | ~ b[i_]); while (--i_>0);} +#ifdef IBM_WATC +#define INLINEset_xor(r, a, b) (void) set_xor(r, a, b) +#define INLINEset_xnor(r, a, b, f) (void) set_xnor(r, a, b, f) +#else +#define INLINEset_xor(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] ^ b[i_]; while (--i_>0);} +#define INLINEset_xnor(r, a, b, fullset)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = fullset[i_] & ~ (a[i_] ^ b[i_]); while (--i_>0);} +#endif +#define INLINEset_merge(r, a, b, mask)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = (a[i_]&mask[i_]) | (b[i_]&~mask[i_]); while (--i_>0);} +#define INLINEsetp_implies(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]&~b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} +#define INLINEsetp_disjoint(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]&b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} +#define INLINEsetp_equal(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]!=b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} + +#endif + +#if BPI == 32 +#define count_ones(v)\ + (bit_count[v & 255] + bit_count[(v >> 8) & 255]\ + + bit_count[(v >> 16) & 255] + bit_count[(v >> 24) & 255]) +#else +#define count_ones(v) (bit_count[v & 255] + bit_count[(v >> 8) & 255]) +#endif + +/* Table for efficient bit counting */ +extern int bit_count[256]; +/*----- END OF set.h ----- */ + +/* Define a boolean type */ +#define bool int +#define FALSE 0 +#define TRUE 1 +#define MAYBE 2 +#define print_bool(x) ((x) == 0 ? "FALSE" : ((x) == 1 ? "TRUE" : "MAYBE")) + +/* Map many cube/cover types/routines into equivalent set types/routines */ +#define pcube pset +#define new_cube() set_new(cube.size) +#define free_cube(r) set_free(r) +#define pcover pset_family +#define new_cover(i) sf_new(i, cube.size) +#define free_cover(r) sf_free(r) +#define free_cubelist(T) FREE(T[0]); FREE(T); + + +/* cost_t describes the cost of a cover */ +typedef struct cost_struct { + int cubes; /* number of cubes in the cover */ + int in; /* transistor count, binary-valued variables */ + int out; /* transistor count, output part */ + int mv; /* transistor count, multiple-valued vars */ + int total; /* total number of transistors */ + int primes; /* number of prime cubes */ +} cost_t, *pcost; + + +/* pair_t describes bit-paired variables */ +typedef struct pair_struct { + int cnt; + int *var1; + int *var2; +} pair_t, *ppair; + + +/* symbolic_list_t describes a single ".symbolic" line */ +typedef struct symbolic_list_struct { + int variable; + int pos; + struct symbolic_list_struct *next; +} symbolic_list_t; + + +/* symbolic_list_t describes a single ".symbolic" line */ +typedef struct symbolic_label_struct { + char *label; + struct symbolic_label_struct *next; +} symbolic_label_t; + + +/* symbolic_t describes a linked list of ".symbolic" lines */ +typedef struct symbolic_struct { + symbolic_list_t *symbolic_list; /* linked list of items */ + int symbolic_list_length; /* length of symbolic_list list */ + symbolic_label_t *symbolic_label; /* linked list of new names */ + int symbolic_label_length; /* length of symbolic_label list */ + struct symbolic_struct *next; +} symbolic_t; + + +/* PLA_t stores the logical representation of a PLA */ +typedef struct { + pcover F, D, R; /* on-set, off-set and dc-set */ + char *filename; /* filename */ + int pla_type; /* logical PLA format */ + pcube phase; /* phase to split into on-set and off-set */ + ppair pair; /* how to pair variables */ + char **label; /* labels for the columns */ + symbolic_t *symbolic; /* allow binary->symbolic mapping */ + symbolic_t *symbolic_output;/* allow symbolic output mapping */ +} PLA_t, *pPLA; + +#define equal(a,b) (strcmp(a,b) == 0) + +/* This is a hack which I wish I hadn't done, but too painful to change */ +#define CUBELISTSIZE(T) (((pcube *) T[1] - T) - 3) + +/* For documentation purposes */ +#define IN +#define OUT +#define INOUT + +/* The pla_type field describes the input and output format of the PLA */ +#define F_type 1 +#define D_type 2 +#define R_type 4 +#define PLEASURE_type 8 /* output format */ +#define EQNTOTT_type 16 /* output format algebraic eqns */ +#define KISS_type 128 /* output format kiss */ +#define CONSTRAINTS_type 256 /* output the constraints (numeric) */ +#define SYMBOLIC_CONSTRAINTS_type 512 /* output the constraints (symbolic) */ +#define FD_type (F_type | D_type) +#define FR_type (F_type | R_type) +#define DR_type (D_type | R_type) +#define FDR_type (F_type | D_type | R_type) + +/* Definitions for the debug variable */ +#define COMPL 0x0001 +#define ESSEN 0x0002 +#define EXPAND 0x0004 +#define EXPAND1 0x0008 +#define GASP 0x0010 +#define IRRED 0x0020 +#define REDUCE 0x0040 +#define REDUCE1 0x0080 +#define SPARSE 0x0100 +#define TAUT 0x0200 +#define EXACT 0x0400 +#define MINCOV 0x0800 +#define MINCOV1 0x1000 +#define SHARP 0x2000 +#define IRRED1 0x4000 + +#define VERSION\ + "UC Berkeley, Espresso Version #2.3, Release date 01/31/88" + +/* Define constants used for recording program statistics */ +#define TIME_COUNT 16 +#define READ_TIME 0 +#define COMPL_TIME 1 +#define ONSET_TIME 2 +#define ESSEN_TIME 3 +#define EXPAND_TIME 4 +#define IRRED_TIME 5 +#define REDUCE_TIME 6 +#define GEXPAND_TIME 7 +#define GIRRED_TIME 8 +#define GREDUCE_TIME 9 +#define PRIMES_TIME 10 +#define MINCOV_TIME 11 +#define MV_REDUCE_TIME 12 +#define RAISE_IN_TIME 13 +#define VERIFY_TIME 14 +#define WRITE_TIME 15 + + +/* For those who like to think about PLAs, macros to get at inputs/outputs */ +#define NUMINPUTS cube.num_binary_vars +#define NUMOUTPUTS cube.part_size[cube.num_vars - 1] + +#define POSITIVE_PHASE(pos)\ + (is_in_set(PLA->phase, cube.first_part[cube.output]+pos) != 0) + +#define INLABEL(var) PLA->label[cube.first_part[var] + 1] +#define OUTLABEL(pos) PLA->label[cube.first_part[cube.output] + pos] + +#define GETINPUT(c, pos)\ + ((c[WHICH_WORD(2*pos)] >> WHICH_BIT(2*pos)) & 3) +#define GETOUTPUT(c, pos)\ + (is_in_set(c, cube.first_part[cube.output] + pos) != 0) + +#define PUTINPUT(c, pos, value)\ + c[WHICH_WORD(2*pos)] = (c[WHICH_WORD(2*pos)] & ~(3 << WHICH_BIT(2*pos)))\ + | (value << WHICH_BIT(2*pos)) +#define PUTOUTPUT(c, pos, value)\ + c[WHICH_WORD(pos)] = (c[WHICH_WORD(pos)] & ~(1 << WHICH_BIT(pos)))\ + | (value << WHICH_BIT(pos)) + +#define TWO 3 +#define DASH 3 +#define ONE 2 +#define ZERO 1 + + +#define EXEC(fct, name, S)\ + {long t=ptime();fct;if(trace)print_trace(S,name,ptime()-t);} +#define EXEC_S(fct, name, S)\ + {long t=ptime();fct;if(summary)print_trace(S,name,ptime()-t);} +#define EXECUTE(fct,i,S,cost)\ + {long t=ptime();fct;totals(t,i,S,&(cost));} + +/* + * Global Variable Declarations + */ + +extern unsigned int debug; /* debug parameter */ +extern bool verbose_debug; /* -v: whether to print a lot */ +extern char *total_name[TIME_COUNT]; /* basic function names */ +extern long total_time[TIME_COUNT]; /* time spent in basic fcts */ +extern int total_calls[TIME_COUNT]; /* # calls to each fct */ + +extern bool echo_comments; /* turned off by -eat option */ +extern bool echo_unknown_commands; /* always true ?? */ +extern bool force_irredundant; /* -nirr command line option */ +extern bool skip_make_sparse; +extern bool kiss; /* -kiss command line option */ +extern bool pos; /* -pos command line option */ +extern bool print_solution; /* -x command line option */ +extern bool recompute_onset; /* -onset command line option */ +extern bool remove_essential; /* -ness command line option */ +extern bool single_expand; /* -fast command line option */ +extern bool summary; /* -s command line option */ +extern bool trace; /* -t command line option */ +extern bool unwrap_onset; /* -nunwrap command line option */ +extern bool use_random_order; /* -random command line option */ +extern bool use_super_gasp; /* -strong command line option */ +extern char *filename; /* filename PLA was read from */ +extern bool debug_exact_minimization; /* dumps info for -do exact */ + + +/* + * pla_types are the input and output types for reading/writing a PLA + */ +struct pla_types_struct { + char *key; + int value; +}; + + +/* + * The cube structure is a global structure which contains information + * on how a set maps into a cube -- i.e., number of parts per variable, + * number of variables, etc. Also, many fields are pre-computed to + * speed up various primitive operations. + */ +#define CUBE_TEMP 10 + +struct cube_struct { + int size; /* set size of a cube */ + int num_vars; /* number of variables in a cube */ + int num_binary_vars; /* number of binary variables */ + int *first_part; /* first element of each variable */ + int *last_part; /* first element of each variable */ + int *part_size; /* number of elements in each variable */ + int *first_word; /* first word for each variable */ + int *last_word; /* last word for each variable */ + pset binary_mask; /* Mask to extract binary variables */ + pset mv_mask; /* mask to get mv parts */ + pset *var_mask; /* mask to extract a variable */ + pset *temp; /* an array of temporary sets */ + pset fullset; /* a full cube */ + pset emptyset; /* an empty cube */ + unsigned int inmask; /* mask to get odd word of binary part */ + int inword; /* which word number for above */ + int *sparse; /* should this variable be sparse? */ + int num_mv_vars; /* number of multiple-valued variables */ + int output; /* which variable is "output" (-1 if none) */ +}; + +struct cdata_struct { + int *part_zeros; /* count of zeros for each element */ + int *var_zeros; /* count of zeros for each variable */ + int *parts_active; /* number of "active" parts for each var */ + bool *is_unate; /* indicates given var is unate */ + int vars_active; /* number of "active" variables */ + int vars_unate; /* number of unate variables */ + int best; /* best "binate" variable */ +}; + + +extern struct pla_types_struct pla_types[]; +extern struct cube_struct cube, temp_cube_save; +extern struct cdata_struct cdata, temp_cdata_save; + +#ifdef lint +#define DISJOINT 0x5555 +#else +#if BPI == 32 +#define DISJOINT 0x55555555 +#else +#define DISJOINT 0x5555 +#endif +#endif + +/* function declarations */ + +/* cofactor.c */ extern int binate_split_select(); +/* cofactor.c */ extern pcover cubeunlist(); +/* cofactor.c */ extern pcube *cofactor(); +/* cofactor.c */ extern pcube *cube1list(); +/* cofactor.c */ extern pcube *cube2list(); +/* cofactor.c */ extern pcube *cube3list(); +/* cofactor.c */ extern pcube *scofactor(); +/* cofactor.c */ extern void massive_count(); +/* compl.c */ extern pcover complement(); +/* compl.c */ extern pcover simplify(); +/* compl.c */ extern void simp_comp(); +/* contain.c */ extern int d1_rm_equal(); +/* contain.c */ extern int rm2_contain(); +/* contain.c */ extern int rm2_equal(); +/* contain.c */ extern int rm_contain(); +/* contain.c */ extern int rm_equal(); +/* contain.c */ extern int rm_rev_contain(); +/* contain.c */ extern pset *sf_list(); +/* contain.c */ extern pset *sf_sort(); +/* contain.c */ extern pset_family d1merge(); +/* contain.c */ extern pset_family dist_merge(); +/* contain.c */ extern pset_family sf_contain(); +/* contain.c */ extern pset_family sf_dupl(); +/* contain.c */ extern pset_family sf_ind_contain(); +/* contain.c */ extern pset_family sf_ind_unlist(); +/* contain.c */ extern pset_family sf_merge(); +/* contain.c */ extern pset_family sf_rev_contain(); +/* contain.c */ extern pset_family sf_union(); +/* contain.c */ extern pset_family sf_unlist(); +/* cubestr.c */ extern void cube_setup(); +/* cubestr.c */ extern void restore_cube_struct(); +/* cubestr.c */ extern void save_cube_struct(); +/* cubestr.c */ extern void setdown_cube(); +/* cvrin.c */ extern PLA_labels(); +/* cvrin.c */ extern char *get_word(); +/* cvrin.c */ extern int label_index(); +/* cvrin.c */ extern int read_pla(); +/* cvrin.c */ extern int read_symbolic(); +/* cvrin.c */ extern pPLA new_PLA(); +/* cvrin.c */ extern void PLA_summary(); +/* cvrin.c */ extern void free_PLA(); +/* cvrin.c */ extern void parse_pla(); +/* cvrin.c */ extern void read_cube(); +/* cvrin.c */ extern void skip_line(); +/* cvrm.c */ extern foreach_output_function(); +/* cvrm.c */ extern int cubelist_partition(); +/* cvrm.c */ extern int so_both_do_espresso(); +/* cvrm.c */ extern int so_both_do_exact(); +/* cvrm.c */ extern int so_both_save(); +/* cvrm.c */ extern int so_do_espresso(); +/* cvrm.c */ extern int so_do_exact(); +/* cvrm.c */ extern int so_save(); +/* cvrm.c */ extern pcover cof_output(); +/* cvrm.c */ extern pcover lex_sort(); +/* cvrm.c */ extern pcover mini_sort(); +/* cvrm.c */ extern pcover random_order(); +/* cvrm.c */ extern pcover size_sort(); +/* cvrm.c */ extern pcover sort_reduce(); +/* cvrm.c */ extern pcover uncof_output(); +/* cvrm.c */ extern pcover unravel(); +/* cvrm.c */ extern pcover unravel_range(); +/* cvrm.c */ extern void so_both_espresso(); +/* cvrm.c */ extern void so_espresso(); +/* cvrmisc.c */ extern char *fmt_cost(); +/* cvrmisc.c */ extern char *print_cost(); +/* cvrmisc.c */ extern char *strsav(); +/* cvrmisc.c */ extern void copy_cost(); +/* cvrmisc.c */ extern void cover_cost(); +/* cvrmisc.c */ extern void fatal(); +/* cvrmisc.c */ extern void print_trace(); +/* cvrmisc.c */ extern void size_stamp(); +/* cvrmisc.c */ extern void totals(); +/* cvrout.c */ extern char *fmt_cube(); +/* cvrout.c */ extern char *fmt_expanded_cube(); +/* cvrout.c */ extern char *pc1(); +/* cvrout.c */ extern char *pc2(); +/* cvrout.c */ extern char *pc3(); +/* cvrout.c */ extern int makeup_labels(); +/* cvrout.c */ extern kiss_output(); +/* cvrout.c */ extern kiss_print_cube(); +/* cvrout.c */ extern output_symbolic_constraints(); +/* cvrout.c */ extern void cprint(); +/* cvrout.c */ extern void debug1_print(); +/* cvrout.c */ extern void debug_print(); +/* cvrout.c */ extern void eqn_output(); +/* cvrout.c */ extern void fpr_header(); +/* cvrout.c */ extern void fprint_pla(); +/* cvrout.c */ extern void pls_group(); +/* cvrout.c */ extern void pls_label(); +/* cvrout.c */ extern void pls_output(); +/* cvrout.c */ extern void print_cube(); +/* cvrout.c */ extern void print_expanded_cube(); +/* cvrout.c */ extern void sf_debug_print(); +/* equiv.c */ extern find_equiv_outputs(); +/* equiv.c */ extern int check_equiv(); +/* espresso.c */ extern pcover espresso(); +/* essen.c */ extern bool essen_cube(); +/* essen.c */ extern pcover cb_consensus(); +/* essen.c */ extern pcover cb_consensus_dist0(); +/* essen.c */ extern pcover essential(); +/* exact.c */ extern pcover minimize_exact(); +/* exact.c */ extern pcover minimize_exact_literals(); +/* expand.c */ extern bool feasibly_covered(); +/* expand.c */ extern int most_frequent(); +/* expand.c */ extern pcover all_primes(); +/* expand.c */ extern pcover expand(); +/* expand.c */ extern pcover find_all_primes(); +/* expand.c */ extern void elim_lowering(); +/* expand.c */ extern void essen_parts(); +/* expand.c */ extern void essen_raising(); +/* expand.c */ extern void expand1(); +/* expand.c */ extern void mincov(); +/* expand.c */ extern void select_feasible(); +/* expand.c */ extern void setup_BB_CC(); +/* gasp.c */ extern pcover expand_gasp(); +/* gasp.c */ extern pcover irred_gasp(); +/* gasp.c */ extern pcover last_gasp(); +/* gasp.c */ extern pcover super_gasp(); +/* gasp.c */ extern void expand1_gasp(); +/* getopt.c */ extern int getopt(); +/* hack.c */ extern find_dc_inputs(); +/* hack.c */ extern find_inputs(); +/* hack.c */ extern form_bitvector(); +/* hack.c */ extern map_dcset(); +/* hack.c */ extern map_output_symbolic(); +/* hack.c */ extern map_symbolic(); +/* hack.c */ extern pcover map_symbolic_cover(); +/* hack.c */ extern symbolic_hack_labels(); +/* irred.c */ extern bool cube_is_covered(); +/* irred.c */ extern bool taut_special_cases(); +/* irred.c */ extern bool tautology(); +/* irred.c */ extern pcover irredundant(); +/* irred.c */ extern void mark_irredundant(); +/* irred.c */ extern void irred_split_cover(); +/* irred.c */ extern sm_matrix *irred_derive_table(); +/* map.c */ extern pset minterms(); +/* map.c */ extern void explode(); +/* map.c */ extern void map(); +/* opo.c */ extern output_phase_setup(); +/* opo.c */ extern pPLA set_phase(); +/* opo.c */ extern pcover opo(); +/* opo.c */ extern pcube find_phase(); +/* opo.c */ extern pset_family find_covers(); +/* opo.c */ extern pset_family form_cover_table(); +/* opo.c */ extern pset_family opo_leaf(); +/* opo.c */ extern pset_family opo_recur(); +/* opo.c */ extern void opoall(); +/* opo.c */ extern void phase_assignment(); +/* opo.c */ extern void repeated_phase_assignment(); +/* pair.c */ extern generate_all_pairs(); +/* pair.c */ extern int **find_pairing_cost(); +/* pair.c */ extern int find_best_cost(); +/* pair.c */ extern int greedy_best_cost(); +/* pair.c */ extern int minimize_pair(); +/* pair.c */ extern int pair_free(); +/* pair.c */ extern pair_all(); +/* pair.c */ extern pcover delvar(); +/* pair.c */ extern pcover pairvar(); +/* pair.c */ extern ppair pair_best_cost(); +/* pair.c */ extern ppair pair_new(); +/* pair.c */ extern ppair pair_save(); +/* pair.c */ extern print_pair(); +/* pair.c */ extern void find_optimal_pairing(); +/* pair.c */ extern void set_pair(); +/* pair.c */ extern void set_pair1(); +/* primes.c */ extern pcover primes_consensus(); +/* reduce.c */ extern bool sccc_special_cases(); +/* reduce.c */ extern pcover reduce(); +/* reduce.c */ extern pcube reduce_cube(); +/* reduce.c */ extern pcube sccc(); +/* reduce.c */ extern pcube sccc_cube(); +/* reduce.c */ extern pcube sccc_merge(); +/* set.c */ extern bool set_andp(); +/* set.c */ extern bool set_orp(); +/* set.c */ extern bool setp_disjoint(); +/* set.c */ extern bool setp_empty(); +/* set.c */ extern bool setp_equal(); +/* set.c */ extern bool setp_full(); +/* set.c */ extern bool setp_implies(); +/* set.c */ extern char *pbv1(); +/* set.c */ extern char *ps1(); +/* set.c */ extern int *sf_count(); +/* set.c */ extern int *sf_count_restricted(); +/* set.c */ extern int bit_index(); +/* set.c */ extern int set_dist(); +/* set.c */ extern int set_ord(); +/* set.c */ extern void set_adjcnt(); +/* set.c */ extern pset set_and(); +/* set.c */ extern pset set_clear(); +/* set.c */ extern pset set_copy(); +/* set.c */ extern pset set_diff(); +/* set.c */ extern pset set_fill(); +/* set.c */ extern pset set_merge(); +/* set.c */ extern pset set_or(); +/* set.c */ extern pset set_xor(); +/* set.c */ extern pset sf_and(); +/* set.c */ extern pset sf_or(); +/* set.c */ extern pset_family sf_active(); +/* set.c */ extern pset_family sf_addcol(); +/* set.c */ extern pset_family sf_addset(); +/* set.c */ extern pset_family sf_append(); +/* set.c */ extern pset_family sf_bm_read(); +/* set.c */ extern pset_family sf_compress(); +/* set.c */ extern pset_family sf_copy(); +/* set.c */ extern pset_family sf_copy_col(); +/* set.c */ extern pset_family sf_delc(); +/* set.c */ extern pset_family sf_delcol(); +/* set.c */ extern pset_family sf_inactive(); +/* set.c */ extern pset_family sf_join(); +/* set.c */ extern pset_family sf_new(); +/* set.c */ extern pset_family sf_permute(); +/* set.c */ extern pset_family sf_read(); +/* set.c */ extern pset_family sf_save(); +/* set.c */ extern pset_family sf_transpose(); +/* set.c */ extern void set_write(); +/* set.c */ extern void sf_bm_print(); +/* set.c */ extern void sf_cleanup(); +/* set.c */ extern void sf_delset(); +/* set.c */ extern void sf_free(); +/* set.c */ extern void sf_print(); +/* set.c */ extern void sf_write(); +/* setc.c */ extern bool ccommon(); +/* setc.c */ extern bool cdist0(); +/* setc.c */ extern bool full_row(); +/* setc.c */ extern int ascend(); +/* setc.c */ extern int cactive(); +/* setc.c */ extern int cdist(); +/* setc.c */ extern int cdist01(); +/* setc.c */ extern int cvolume(); +/* setc.c */ extern int d1_order(); +/* setc.c */ extern int d1_order_size(); +/* setc.c */ extern int desc1(); +/* setc.c */ extern int descend(); +/* setc.c */ extern int lex_order(); +/* setc.c */ extern int lex_order1(); +/* setc.c */ extern pset force_lower(); +/* setc.c */ extern void consensus(); +/* sharp.c */ extern pcover cb1_dsharp(); +/* sharp.c */ extern pcover cb_dsharp(); +/* sharp.c */ extern pcover cb_recur_dsharp(); +/* sharp.c */ extern pcover cb_recur_sharp(); +/* sharp.c */ extern pcover cb_sharp(); +/* sharp.c */ extern pcover cv_dsharp(); +/* sharp.c */ extern pcover cv_intersect(); +/* sharp.c */ extern pcover cv_sharp(); +/* sharp.c */ extern pcover dsharp(); +/* sharp.c */ extern pcover make_disjoint(); +/* sharp.c */ extern pcover sharp(); +/* sminterf.c */pset do_sm_minimum_cover(); +/* sparse.c */ extern pcover make_sparse(); +/* sparse.c */ extern pcover mv_reduce(); +#if !defined(__osf__) && !defined(__STDC__) && !defined(__hpux) +/* ucbqsort.c */ extern qsort(); +#endif +/* ucbqsort.c */ extern qst(); +/* unate.c */ extern pcover find_all_minimal_covers_petrick(); +/* unate.c */ extern pcover map_cover_to_unate(); +/* unate.c */ extern pcover map_unate_to_cover(); +/* unate.c */ extern pset_family exact_minimum_cover(); +/* unate.c */ extern pset_family gen_primes(); +/* unate.c */ extern pset_family unate_compl(); +/* unate.c */ extern pset_family unate_complement(); +/* unate.c */ extern pset_family unate_intersect(); +/* verify.c */ extern PLA_permute(); +/* verify.c */ extern bool PLA_verify(); +/* verify.c */ extern bool check_consistency(); +/* verify.c */ extern bool verify(); diff --git a/espresso/essen.c b/espresso/essen.c new file mode 100644 index 0000000..360ed85 --- /dev/null +++ b/espresso/essen.c @@ -0,0 +1,179 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/essen.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + module: essen.c + purpose: Find essential primes in a multiple-valued function +*/ + +#include "espresso.h" + +/* + essential -- return a cover consisting of the cubes of F which are + essential prime implicants (with respect to F u D); Further, remove + these cubes from the ON-set F, and add them to the OFF-set D. + + Sometimes EXPAND can determine that a cube is not an essential prime. + If so, it will set the "NONESSEN" flag in the cube. + + We count on IRREDUNDANT to have set the flag RELESSEN to indicate + that a prime was relatively essential (i.e., covers some minterm + not contained in any other prime in the current cover), or to have + reset the flag to indicate that a prime was relatively redundant + (i.e., all minterms covered by other primes in the current cover). + Of course, after executing irredundant, all of the primes in the + cover are relatively essential, but we can mark the primes which + were redundant at the start of irredundant and avoid an extra check + on these primes for essentiality. +*/ + +pcover essential(Fp, Dp) +IN pcover *Fp, *Dp; +{ + register pcube last, p; + pcover E, F = *Fp, D = *Dp; + + /* set all cubes in F active */ + (void) sf_active(F); + + /* Might as well start out with some cubes in E */ + E = new_cover(10); + + foreach_set(F, last, p) { + /* don't test a prime which EXPAND says is nonessential */ + if (! TESTP(p, NONESSEN)) { + /* only test a prime which was relatively essential */ + if (TESTP(p, RELESSEN)) { + /* Check essentiality */ + if (essen_cube(F, D, p)) { + if (debug & ESSEN) + printf("ESSENTIAL: %s\n", pc1(p)); + E = sf_addset(E, p); + RESET(p, ACTIVE); + F->active_count--; + } + } + } + } + + *Fp = sf_inactive(F); /* delete the inactive cubes from F */ + *Dp = sf_join(D, E); /* add the essentials to D */ + sf_free(D); + return E; +} + +/* + essen_cube -- check if a single cube is essential or not + + The prime c is essential iff + + consensus((F u D) # c, c) u D + + does not contain c. +*/ +bool essen_cube(F, D, c) +IN pcover F, D; +IN pcube c; +{ + pcover H, FD; + pcube *H1; + bool essen; + + /* Append F and D together, and take the sharp-consensus with c */ + FD = sf_join(F, D); + H = cb_consensus(FD, c); + free_cover(FD); + + /* Add the don't care set, and see if this covers c */ + H1 = cube2list(H, D); + essen = ! cube_is_covered(H1, c); + free_cubelist(H1); + + free_cover(H); + return essen; +} + + +/* + * cb_consensus -- compute consensus(T # c, c) + */ +pcover cb_consensus(T, c) +register pcover T; +register pcube c; +{ + register pcube temp, last, p; + register pcover R; + + R = new_cover(T->count*2); + temp = new_cube(); + foreach_set(T, last, p) { + if (p != c) { + switch (cdist01(p, c)) { + case 0: + /* distance-0 needs special care */ + R = cb_consensus_dist0(R, p, c); + break; + + case 1: + /* distance-1 is easy because no sharping required */ + consensus(temp, p, c); + R = sf_addset(R, temp); + break; + } + } + } + set_free(temp); + return R; +} + + +/* + * form the sharp-consensus for p and c when they intersect + * What we are forming is consensus(p # c, c). + */ +pcover cb_consensus_dist0(R, p, c) +pcover R; +register pcube p, c; +{ + int var; + bool got_one; + register pcube temp, mask; + register pcube p_diff_c=cube.temp[0], p_and_c=cube.temp[1]; + + /* If c contains p, then this gives us no information for essential test */ + if (setp_implies(p, c)) { + return R; + } + + /* For the multiple-valued variables */ + temp = new_cube(); + got_one = FALSE; + INLINEset_diff(p_diff_c, p, c); + INLINEset_and(p_and_c, p, c); + + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + /* Check if c(var) is contained in p(var) -- if so, no news */ + mask = cube.var_mask[var]; + if (! setp_disjoint(p_diff_c, mask)) { + INLINEset_merge(temp, c, p_and_c, mask); + R = sf_addset(R, temp); + got_one = TRUE; + } + } + + /* if no cube so far, add one for the intersection */ + if (! got_one && cube.num_binary_vars > 0) { + /* Add a single cube for the intersection of p and c */ + INLINEset_and(temp, p, c); + R = sf_addset(R, temp); + } + + set_free(temp); + return R; +} diff --git a/espresso/exact.c b/espresso/exact.c new file mode 100644 index 0000000..b791ba9 --- /dev/null +++ b/espresso/exact.c @@ -0,0 +1,181 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/exact.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +#include "espresso.h" + + +static void dump_irredundant(); +static pcover do_minimize(); + + +/* + * minimize_exact -- main entry point for exact minimization + * + * Global flags which affect this routine are: + * + * debug + * skip_make_sparse + */ + +pcover +minimize_exact(F, D, R, exact_cover) +pcover F, D, R; +int exact_cover; +{ + return do_minimize(F, D, R, exact_cover, /*weighted*/ 0); +} + + +pcover +minimize_exact_literals(F, D, R, exact_cover) +pcover F, D, R; +int exact_cover; +{ + return do_minimize(F, D, R, exact_cover, /*weighted*/ 1); +} + + + +static pcover +do_minimize(F, D, R, exact_cover, weighted) +pcover F, D, R; +int exact_cover; +int weighted; +{ + pcover newF, E, Rt, Rp; + pset p, last; + int heur, level, *weights, i; + sm_matrix *table; + sm_row *cover; + sm_element *pe; + int debug_save = debug; + + if (debug & EXACT) { + debug |= (IRRED | MINCOV); + } +#if defined(sun) || defined(bsd4_2) /* hack ... */ + if (debug & MINCOV) { + setlinebuf(stdout); + } +#endif + level = (debug & MINCOV) ? 4 : 0; + heur = ! exact_cover; + + /* Generate all prime implicants */ + EXEC(F = primes_consensus(cube2list(F, D)), "PRIMES ", F); + + /* Setup the prime implicant table */ + EXEC(irred_split_cover(F, D, &E, &Rt, &Rp), "ESSENTIALS ", E); + EXEC(table = irred_derive_table(D, E, Rp), "PI-TABLE ", Rp); + + /* Solve either a weighted or nonweighted covering problem */ + if (weighted) { + /* correct only for all 2-valued variables */ + weights = ALLOC(int, F->count); + foreach_set(Rp, last, p) { + weights[SIZE(p)] = cube.size - set_ord(p); + /* We have added the 0's in the output part instead of the 1's. + This loop corrects the literal count. */ + for (i = cube.first_part[cube.output]; + i <= cube.last_part[cube.output]; i++) { + is_in_set(p, i) ? weights[SIZE(p)]++ : weights[SIZE(p)]--; + } + } + } else { + weights = NIL(int); + } + EXEC(cover=sm_minimum_cover(table,weights,heur,level), "MINCOV ", F); + if (weights != 0) { + FREE(weights); + } + + if (debug & EXACT) { + dump_irredundant(E, Rt, Rp, table); + } + + /* Form the result cover */ + newF = new_cover(100); + foreach_set(E, last, p) { + newF = sf_addset(newF, p); + } + sm_foreach_row_element(cover, pe) { + newF = sf_addset(newF, GETSET(F, pe->col_num)); + } + + free_cover(E); + free_cover(Rt); + free_cover(Rp); + sm_free(table); + sm_row_free(cover); + free_cover(F); + + /* Attempt to make the results more sparse */ + debug &= ~ (IRRED | SHARP | MINCOV); + if (! skip_make_sparse && R != 0) { + newF = make_sparse(newF, D, R); + } + + debug = debug_save; + return newF; +} + +static void +dump_irredundant(E, Rt, Rp, table) +pcover E, Rt, Rp; +sm_matrix *table; +{ + FILE *fp_pi_table, *fp_primes; + pPLA PLA; + pset last, p; + char *file; + + if (filename == 0 || strcmp(filename, "(stdin)") == 0) { + fp_pi_table = fp_primes = stdout; + } else { + file = ALLOC(char, strlen(filename)+20); + (void) sprintf(file, "%s.primes", filename); + if ((fp_primes = fopen(file, "w")) == NULL) { + (void) fprintf(stderr, "espresso: Unable to open %s\n", file); + fp_primes = stdout; + } + (void) sprintf(file, "%s.pi", filename); + if ((fp_pi_table = fopen(file, "w")) == NULL) { + (void) fprintf(stderr, "espresso: Unable to open %s\n", file); + fp_pi_table = stdout; + } + FREE(file); + } + + PLA = new_PLA(); + PLA_labels(PLA); + + fpr_header(fp_primes, PLA, F_type); + free_PLA(PLA); + + (void) fprintf(fp_primes, "# Essential primes are\n"); + foreach_set(E, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + (void) fprintf(fp_primes, "# Totally redundant primes are\n"); + foreach_set(Rt, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + (void) fprintf(fp_primes, "# Partially redundant primes are\n"); + foreach_set(Rp, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + if (fp_primes != stdout) { + (void) fclose(fp_primes); + } + + sm_write(fp_pi_table, table); + if (fp_pi_table != stdout) { + (void) fclose(fp_pi_table); + } +} diff --git a/espresso/examples/Makefile.am b/espresso/examples/Makefile.am new file mode 100644 index 0000000..7e8edd8 --- /dev/null +++ b/espresso/examples/Makefile.am @@ -0,0 +1,33 @@ +pkgdatadir = $(datadir)/$(PACKAGE)/espresso_examples +nobase_dist_pkgdata_DATA = a2.pair fsm.pla \ + indust/accpla indust/al2 indust/alcom indust/alu1 \ + indust/alu2 indust/alu3 indust/amd indust/apla indust/b10 indust/b11 \ + indust/b12 indust/b2 indust/b3 indust/b4 indust/b7 indust/b9 \ + indust/bc0 indust/bca indust/bcb indust/bcc indust/bcd indust/br1 \ + indust/br2 indust/chkn indust/clpl indust/cps indust/dc1 indust/dc2 \ + indust/dekoder indust/dk17 indust/dk27 indust/dk48 indust/ex4 \ + indust/ex5 indust/ex7 indust/exep indust/exp indust/exps indust/gary \ + indust/ibm indust/in0 indust/in1 indust/in2 indust/in3 indust/in4 \ + indust/in5 indust/in6 indust/in7 indust/inc indust/intb indust/jbp \ + indust/lin.rom indust/luc indust/m1 indust/m2 indust/m3 indust/m4 \ + indust/mainpla indust/mark1 indust/max1024 indust/max128 indust/max46 \ + indust/max512 indust/misg indust/mish indust/misj indust/mp2d \ + indust/newapla indust/newapla1 indust/newapla2 indust/newbyte \ + indust/newcond indust/newcpla1 indust/newcpla2 indust/newcwp \ + indust/newill indust/newtag indust/newtpla indust/newtpla1 \ + indust/newtpla2 indust/newxcpla1 indust/opa indust/p82 indust/pdc \ + indust/pope.rom indust/prom1 indust/prom2 indust/risc indust/ryy6 \ + indust/sex indust/shift indust/signet indust/soar.pla indust/spla \ + indust/sqn indust/t1 indust/t2 indust/t3 indust/t4 indust/ti \ + indust/tms indust/ts10 indust/vg2 indust/vtx1 indust/wim indust/x1dn \ + indust/x2dn indust/x6dn indust/x7dn indust/x9dn indust/xparc \ + math/Z5xp1 math/Z9sym math/add6 math/addm4 math/adr4 math/bcd.div3 \ + math/co14 math/dist math/f51m math/l8err math/life math/log8mod \ + math/m181 math/mlp4 math/radd math/rckl math/rd53 math/rd73 math/root \ + math/sqr6 math/sym10 math/tial math/z4 \ + random/bench random/bench1 random/ex1010 random/exam random/fout \ + random/p1 random/p3 random/test1 random/test2 random/test3 \ + random/test4 \ + doc/book.list doc/book.pla doc/info.doc doc/info.ms doc/info.old.ms \ + doc/man.pla doc/man1a.list doc/man1b.list doc/man1u.list doc/other.pla \ + doc/random.stats diff --git a/espresso/examples/Makefile.in b/espresso/examples/Makefile.in new file mode 100644 index 0000000..e945bcc --- /dev/null +++ b/espresso/examples/Makefile.in @@ -0,0 +1,352 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = espresso/examples +DIST_COMMON = $(nobase_dist_pkgdata_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +am__installdirs = "$(DESTDIR)$(pkgdatadir)" +nobase_dist_pkgdataDATA_INSTALL = $(install_sh_DATA) +DATA = $(nobase_dist_pkgdata_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = $(datadir)/$(PACKAGE)/espresso_examples +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +nobase_dist_pkgdata_DATA = a2.pair fsm.pla \ + indust/accpla indust/al2 indust/alcom indust/alu1 \ + indust/alu2 indust/alu3 indust/amd indust/apla indust/b10 indust/b11 \ + indust/b12 indust/b2 indust/b3 indust/b4 indust/b7 indust/b9 \ + indust/bc0 indust/bca indust/bcb indust/bcc indust/bcd indust/br1 \ + indust/br2 indust/chkn indust/clpl indust/cps indust/dc1 indust/dc2 \ + indust/dekoder indust/dk17 indust/dk27 indust/dk48 indust/ex4 \ + indust/ex5 indust/ex7 indust/exep indust/exp indust/exps indust/gary \ + indust/ibm indust/in0 indust/in1 indust/in2 indust/in3 indust/in4 \ + indust/in5 indust/in6 indust/in7 indust/inc indust/intb indust/jbp \ + indust/lin.rom indust/luc indust/m1 indust/m2 indust/m3 indust/m4 \ + indust/mainpla indust/mark1 indust/max1024 indust/max128 indust/max46 \ + indust/max512 indust/misg indust/mish indust/misj indust/mp2d \ + indust/newapla indust/newapla1 indust/newapla2 indust/newbyte \ + indust/newcond indust/newcpla1 indust/newcpla2 indust/newcwp \ + indust/newill indust/newtag indust/newtpla indust/newtpla1 \ + indust/newtpla2 indust/newxcpla1 indust/opa indust/p82 indust/pdc \ + indust/pope.rom indust/prom1 indust/prom2 indust/risc indust/ryy6 \ + indust/sex indust/shift indust/signet indust/soar.pla indust/spla \ + indust/sqn indust/t1 indust/t2 indust/t3 indust/t4 indust/ti \ + indust/tms indust/ts10 indust/vg2 indust/vtx1 indust/wim indust/x1dn \ + indust/x2dn indust/x6dn indust/x7dn indust/x9dn indust/xparc \ + math/Z5xp1 math/Z9sym math/add6 math/addm4 math/adr4 math/bcd.div3 \ + math/co14 math/dist math/f51m math/l8err math/life math/log8mod \ + math/m181 math/mlp4 math/radd math/rckl math/rd53 math/rd73 math/root \ + math/sqr6 math/sym10 math/tial math/z4 \ + random/bench random/bench1 random/ex1010 random/exam random/fout \ + random/p1 random/p3 random/test1 random/test2 random/test3 \ + random/test4 \ + doc/book.list doc/book.pla doc/info.doc doc/info.ms doc/info.old.ms \ + doc/man.pla doc/man1a.list doc/man1b.list doc/man1u.list doc/other.pla \ + doc/random.stats + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps espresso/examples/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps espresso/examples/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +install-nobase_dist_pkgdataDATA: $(nobase_dist_pkgdata_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgdatadir)" || $(mkdir_p) "$(DESTDIR)$(pkgdatadir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + list='$(nobase_dist_pkgdata_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; \ + echo " $(nobase_dist_pkgdataDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgdatadir)/$$f'"; \ + $(nobase_dist_pkgdataDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgdatadir)/$$f"; \ + done + +uninstall-nobase_dist_pkgdataDATA: + @$(NORMAL_UNINSTALL) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + list='$(nobase_dist_pkgdata_DATA)'; for p in $$list; do \ + case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; \ + echo " rm -f '$(DESTDIR)$(pkgdatadir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgdatadir)/$$f"; \ + done +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + $(mkdir_p) $(distdir)/doc $(distdir)/indust $(distdir)/math $(distdir)/random + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(pkgdatadir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-nobase_dist_pkgdataDATA + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-nobase_dist_pkgdataDATA + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-nobase_dist_pkgdataDATA install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am uninstall uninstall-am uninstall-info-am \ + uninstall-nobase_dist_pkgdataDATA + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/espresso/examples/a2.pair b/espresso/examples/a2.pair new file mode 100644 index 0000000..0e4d860 --- /dev/null +++ b/espresso/examples/a2.pair @@ -0,0 +1,25 @@ +# 2-bit by 2-bit binary adder (with no carry input) +.i 4 +.o 3 +.ilb a1 a0 b1 b0 +.ob s2 s1 s0 +.phase 011 +.pair 2 (a1 a0) (b1 b0) +.p 16 +0000 000 +0001 001 +0010 010 +0011 011 +0100 001 +0101 010 +0110 011 +0111 100 +1000 010 +1001 011 +1010 100 +1011 101 +1100 011 +1101 100 +1110 101 +1111 110 +.e diff --git a/espresso/examples/doc/book.list b/espresso/examples/doc/book.list new file mode 100644 index 0000000..b9c0b12 --- /dev/null +++ b/espresso/examples/doc/book.list @@ -0,0 +1,56 @@ +Z5xp1 +Z9sym +add6 +adr4 +alu1 +alu2 +alu3 +apla +bc0 +bca +bcb +bcc +bcd +chkn +co14 +cps +dc1 +dc2 +dist +dk17 +dk27 +dk48 +exep +f51m +gary +in0 +in1 +in2 +in3 +in4 +in5 +in6 +in7 +jbp +misg +mish +mlp4 +opa +radd +rckl +rd53 +rd73 +risc +root +sqn +sqr6 +ti +tial +vg2 +wim +x1dn +x2dn +x6dn +x7dn +x9dn +z4 diff --git a/espresso/examples/doc/book.pla b/espresso/examples/doc/book.pla new file mode 100644 index 0000000..a2667a0 --- /dev/null +++ b/espresso/examples/doc/book.pla @@ -0,0 +1,31 @@ +This directory contains the 56 test cases reported in the monograph +"Espresso-II Logic Minimization Algorithms for VLSI Synthesis" + +The filenames correspond one-to-one with Table 7.1 on page 165. + + add6 6 bit adder (reduced starting position) + adr4 4 bit adder (minterms) + alu1 1st stage of 3-stage decomposition of TTL part # 74181 + alu2 2nd stage of 3-stage decomposition of TTL part # 74181 + alu3 3rd stage of 3-stage decomposition of TTL part # 74181 + co14 4-color problem (with dc-set should yield 4 terms) + dist f(x,y) = sqrt(x*x+y*y) for two 4-bit arguments + f51m f(x) = 5*x+1 mod 256 for 8-bit argument + mlp4 4 bit multiplier (minterms) + radd 4 bit adder (reduced starting position) + rckl f(x) = length of longest consecutive string of ones, 32-bit argument + rd53 5 unary bits (unweighted) "reduced" to 3 binary bits (weighted) + rd73 7 unary bits "reduced" to 3 binary bits + risc Control PLA from the Berkeley RISC microprocessor + root f(x) = sqrt(x) for 8-bit argument + sqr6 f(x) = x*x for 6-bit argument + tial TTL part #74181 (4-bit multifunction ALU) + wim BCD to 7-segment LED decoder + z4 3-bit adder with carry input + Z5xp1 f(x) = 5*x+1 for 7-bit argument + Z9sym f(x) = 1 iff x has 3,4,5 or 6 ones in binary expansion (9-bit arg.) + + +The remaining control functions are examples drawn from industrial +logic designs, which, for proprietary reasons, are not described in +detail. diff --git a/espresso/examples/doc/info.doc b/espresso/examples/doc/info.doc new file mode 100644 index 0000000..f50fe83 --- /dev/null +++ b/espresso/examples/doc/info.doc @@ -0,0 +1,396 @@ + + + + + + + Berkeley PLA Test Set Results + June 5, 1986 +(revised January 30, 1988) + + These tables present the results of Boolean minimiza- +tion for the 145 PLA's in the Berkeley PLA test set. The +cost function is assumed to be minimum number of terms with +only a secondary concern given to the number of literals. +Each example is classified as one of 3 types: + + ___________________________________________________ + |__t_y_p_e___|________________d_e_s_c_r_i_p_t_i_o_n_________________| + | _i_n_d_u_s_t| example donated from actual chip designs| + | _m_a_t_h | mathematical function | + | _r_a_n_d_o_m| randomly generated example | + |________|___________________________________________| + + + + Each example also belongs to one of 5 categories, which +measures the relative difficulty of the problem: +_____________________________________________________________________ +| class | description | +_|__________|__________________________________________________________| +|_t_r_i_v_i_a_l | minimum solution consists of essential prime implicants| +|_n_o_n_c_y_c_l_i_c| the covering problem contains no cyclic constraints | +|_c_y_c_l_i_c-_s | the covering problem contains cyclic constraints, | +| | and the covering problem has been solved | +|_c_y_c_l_i_c-_u_s| the covering problem contains cyclic constraints, | +| | and the covering problem as not been solved | +_|__p__r__i__m__e__s____|__u_n_a_b_l_e__t_o__e_n_u_m_e_r_a_t_e__a_l_l__p_r_i_m_e__i_m_p_l_i_c_a_n_t_s_________________| + + +These classifications were determined by using the exact +minimization algorithms of Espresso-MV as well as the exact +minimization algorithm of McBoole. The classifications of +_c_y_c_l_i_c-_u_s and _p_r_i_m_e_s are dependent on the exact minimization +algorithms which were used. For example, although we know +the minimum solution for _Z_9_s_y_m and _i_b_m (by methods not +involving the use of an exact minimization algorithm) these +examples are still classified as _c_y_c_l_i_c-_u_s and _p_r_i_m_e_s +respectively because the exact minimization algorithm was +unable to determine the minimum solution. (Note 1/28/88: +_Z_9_S_Y_M has been moved to _c_y_c_l_i_c-_s because a new covering +algorithm has directly derived the minimum solution.) + + For each example, we first give the number of inputs, +the number of outputs, and the number of terms in the ini- +tial representation of the function. If the number of terms +is marked by *, then there is a don't-care set specified for +the function (which is not counted in the initial number of +terms). + + We then present the number of prime implicants (when + + + + January 30, 1988 + + + + + + - 2 - + + +known), the number of essential primes, and the minimum +solution (when known). When the minimum solution is not +known for the class _c_y_c_l_i_c-_u_s a lower bound (as determined +by the covering algorithm of Espresso-MV) and an upper bound +(the best solution we've seen) are given. For the class +_p_r_i_m_e_s, the lower bound is merely the number of essential +prime implicants, and the upper bound is the best solution +we've seen. For the examples _e_x_1_0_1_0 and _e_x_a_m the best +results have been reported by the authors Prestol-II, and we +have not seen or verified the results. + + These tables also present the results for Espresso-MV +in both its normal mode (Esp.) and its _s_t_r_o_n_g mode (Esp. +(s)). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + January 30, 1988 + + + + + + - 3 - + + +_____________________________________________________________________________________ +| name | in/out terms | type class | # # | minimum | Esp. Esp. | +_||__________||________________||___________________||_p_r_i_m_e_s___e_s_s_e_n_.__||_s_o_l_u_t_i_o_n__||_______(_s_)____|| +|alu1 | 12/8 19| indust trivial | 780 19 | 19 | 19 19 | +|bcd.div3 | 4/4 * 9| math trivial | 13 9 | 9 | 9 9 | +|clpl | 11/5 20| indust trivial | 143 20 | 20 | 20 20 | +|co14 | 14/1 14| math trivial | 14 14 | 14 | 14 14 | +|max46 | 9/1 46| indust trivial | 49 46 | 46 | 46 46 | +|newapla2 | 6/7 7| indust trivial | 7 7 | 7 | 7 7 | +|newbyte | 5/8 8| indust trivial | 8 8 | 8 | 8 8 | +|newtag | 8/1 8| indust trivial | 8 8 | 8 | 8 8 | +|ryy6 | 16/1 112| indust trivial | 112 112 | 112 | 112 112 | +_|__________|________________|___________________|________________|__________|_____________| +|add6 | 12/7 1092| math noncyclic| 8568 153 | 355 | 355 355 | +|adr4 | 8/5 255| math noncyclic| 397 35 | 75 | 75 75 | +|al2 | 16/47 103| indust noncyclic| 9179 16 | 66 | 66 66 | +|alcom | 15/38 47| indust noncyclic| 4657 16 | 40 | 40 40 | +|alu2 | 10/8 * 87| indust noncyclic| 434 36 | 68 | 68 68 | +|alu3 | 10/8 * 68| indust noncyclic| 540 27 | 64 | 66 64 | +|apla | 10/12 * 112| indust noncyclic| 201 0 | 25 | 25 25 | +|b4 | 33/23 * 54| indust noncyclic| 6455 40 | 54 | 54 54 | +|b11 | 8/31 * 74| indust noncyclic| 44 22 | 27 | 27 27 | +|b2 | 16/17 110| indust noncyclic| 928 54 | 104 | 106 104 | +|b7 | 8/31 * 74| indust noncyclic| 44 22 | 27 | 27 27 | +|b9 | 16/5 123| indust noncyclic| 3002 48 | 119 | 119 119 | +|bc0 | 26/11 419| indust noncyclic| 6596 37 | 177 | 178 177 | +|bca | 26/46 * 301| indust noncyclic| 305 144 | 180 | 180 180 | +|bcb | 26/39 * 299| indust noncyclic| 255 137 | 155 | 156 155 | +|bcd | 26/38 * 243| indust noncyclic| 172 100 | 117 | 117 117 | +|br1 | 12/8 34| indust noncyclic| 29 17 | 19 | 19 19 | +|br2 | 12/8 35| indust noncyclic| 27 9 | 13 | 13 13 | +|dc1 | 4/7 15| indust noncyclic| 22 3 | 9 | 9 9 | +|dc2 | 8/7 58| indust noncyclic| 173 18 | 39 | 39 39 | +|dk17 | 10/11 * 57| indust noncyclic| 111 0 | 18 | 18 18 | +|ex7 | 16/5 123| indust noncyclic| 3002 48 | 119 | 119 119 | +|exep | 30/63 * 149| indust noncyclic| 558 82 | 108 | 108 108 | +|exp | 8/18 * 89| indust noncyclic| 238 30 | 56 | 59 56 | +|in1 | 16/17 110| indust noncyclic| 928 54 | 104 | 106 104 | +|in3 | 35/29 75| indust noncyclic| 1114 44 | 74 | 74 74 | +|in5 | 24/14 62| indust noncyclic| 1067 53 | 62 | 62 62 | +|in6 | 33/23 54| indust noncyclic| 6174 40 | 54 | 54 54 | +|in7 | 26/10 84| indust noncyclic| 2112 31 | 54 | 54 54 | +|life | 9/1 140| math noncyclic| 224 56 | 84 | 84 84 | +|luc | 8/27 27| indust noncyclic| 190 14 | 26 | 26 26 | +|m1 | 6/12 32| indust noncyclic| 59 6 | 19 | 19 19 | +|newapla | 12/10 17| indust noncyclic| 113 9 | 17 | 17 17 | +|newapla1 | 12/7 10| indust noncyclic| 31 9 | 10 | 10 10 | +|newcond | 11/2 31| indust noncyclic| 72 18 | 31 | 31 31 | +|newcpla2 | 7/10 19| indust noncyclic| 38 14 | 19 | 19 19 | +|newcwp | 4/5 11| indust noncyclic| 23 7 | 11 | 11 11 | +|newtpla | 15/5 23| indust noncyclic| 40 16 | 23 | 23 23 | +|newtpla1 | 10/2 4| indust noncyclic| 6 3 | 4 | 4 4 | +|newtpla2 | 10/4 9| indust noncyclic| 23 4 | 9 | 9 9 | +|newxcpla1| 9/23 40| indust noncyclic| 191 18 | 39 | 39 39 | +_|p_1_________|___8_/_1_8_____*__8_9__|_r_a_n_d_o_m___n_o_n_c_y_c_l_i_c__|___2_8_7______2_5____|______5_4___|___5_5____5_4____| + + + January 30, 1988 + + + + + + - 4 - + + +_____________________________________________________________________________________ +| name | in/out terms | type class | # # | minimum | Esp. Esp. | +_||__________||________________||___________________||_p_r_i_m_e_s___e_s_s_e_n_.__||_s_o_l_u_t_i_o_n__||_______(_s_)____|| +|p3 | 8/14 * 66| random noncyclic| 185 22 | 39 | 39 39 | +|p82 | 5/14 24| indust noncyclic| 48 16 | 21 | 21 21 | +|prom1 | 9/40 502| indust noncyclic| 9326 182 | 472 | 472 472 | +|radd | 8/5 120| math noncyclic| 397 35 | 75 | 75 75 | +|rckl | 32/7 96| math noncyclic| 302 6 | 32 | 32 32 | +|rd53 | 5/3 31| math noncyclic| 51 21 | 31 | 31 31 | +|rd73 | 7/3 147| math noncyclic| 211 106 | 127 | 127 127 | +|risc | 8/31 74| indust noncyclic| 46 22 | 28 | 28 28 | +|sex | 9/14 23| indust noncyclic| 99 13 | 21 | 21 21 | +|sqn | 7/3 84| indust noncyclic| 75 23 | 38 | 38 38 | +|t2 | 17/16 * 128| indust noncyclic| 233 25 | 52 | 53 53 | +|t3 | 12/8 148| indust noncyclic| 42 30 | 33 | 33 33 | +|t4 | 12/8 * 38| indust noncyclic| 174 0 | 16 | 16 16 | +|vg2 | 25/8 110| indust noncyclic| 1188 100 | 110 | 110 110 | +|vtx1 | 27/6 110| indust noncyclic| 1220 100 | 110 | 110 110 | +|x1dn | 27/6 112| indust noncyclic| 1220 100 | 110 | 110 110 | +|x9dn | 27/7 120| indust noncyclic| 1272 110 | 120 | 120 120 | +|z4 | 7/4 127| math noncyclic| 167 35 | 59 | 59 59 | +_|__________|________________|___________________|________________|__________|_____________| +|Z5xp1 | 7/10 128| math cyclic-s | 390 8 | 63 | 63 64 | +|Z9sym | 9/1 420| math cyclic-s | 1680 0 | 84 | 85 84 | +|addm4 | 9/8 480| math cyclic-s | 1122 24 | 189 | 200 192 | +|amd | 14/24 171| indust cyclic-s | 457 32 | 66 | 66 66 | +|b10 | 15/11 * 135| indust cyclic-s | 938 51 | 100 | 100 100 | +|b12 | 15/9 431| indust cyclic-s | 1490 2 | 41 | 42 41 | +|b3 | 32/20 * 234| indust cyclic-s | 3056 123 | 210 | 211 211 | +|bcc | 26/45 * 245| indust cyclic-s | 237 119 | 137 | 137 137 | +|bench | 6/8 * 31| random cyclic-s | 391 0 | 16 | 18 17 | +|chkn | 29/7 153| indust cyclic-s | 671 86 | 140 | 140 140 | +|cps | 24/109 654| indust cyclic-s | 2487 57 | 157 | 163 159 | +|dekoder | 4/7 * 10| indust cyclic-s | 26 3 | 9 | 9 9 | +|dist | 8/5 255| math cyclic-s | 401 23 | 120 | 121 121 | +|dk27 | 9/9 * 20| indust cyclic-s | 82 0 | 10 | 10 10 | +|dk48 | 15/17 * 42| indust cyclic-s | 157 0 | 21 | 22 22 | +|exps | 8/38 * 196| indust cyclic-s | 852 56 | 132 | 134 133 | +|f51m | 8/8 255| math cyclic-s | 561 13 | 76 | 77 76 | +|fout | 6/10 * 61| random cyclic-s | 436 2 | 40 | 44 42 | +|gary | 15/11 214| indust cyclic-s | 706 60 | 107 | 107 107 | +|in0 | 15/11 135| indust cyclic-s | 706 60 | 107 | 107 107 | +|in2 | 19/10 137| indust cyclic-s | 666 85 | 134 | 136 134 | +|in4 | 32/20 234| indust cyclic-s | 3076 118 | 211 | 212 212 | +|inc | 7/9 * 34| indust cyclic-s | 124 12 | 29 | 30 29 | +|intb | 15/7 664| indust cyclic-s | 6522 186 | 629 | 629 629 | +|l8err | 8/8 * 253| math cyclic-s | 142 15 | 50 | 51 51 | +|lin.rom | 7/36 128| indust cyclic-s | 1087 8 | 128 | 128 128 | +|log8mod | 8/5 46| math cyclic-s | 105 13 | 38 | 38 38 | +|m181 | 15/9 430| math cyclic-s | 1636 2 | 41 | 42 41 | +|m2 | 8/16 96| indust cyclic-s | 243 7 | 47 | 47 47 | +|m3 | 8/16 128| indust cyclic-s | 344 4 | 62 | 65 63 | +|m4 | 8/16 256| indust cyclic-s | 670 11 | 101 | 107 104 | +|mark1 | 20/31 * 23| indust cyclic-s | 208 1 | 19 | 19 19 | +_|m_a_x_1_2_8_____|___7_/_2_4______1_2_8__|_i_n_d_u_s_t___c_y_c_l_i_c_-_s___|___4_6_9_______6____|______7_8___|___8_2____7_9____| + + + January 30, 1988 + + + + + + - 5 - + + +_____________________________________________________________________________________ +| name | in/out terms | type class | # # | minimum | Esp. Esp. | +_||__________||________________||___________________||_p_r_i_m_e_s___e_s_s_e_n_.__||_s_o_l_u_t_i_o_n__||_______(_s_)____|| +|max512 | 9/6 512| indust cyclic-s | 535 20 | 133 | 142 137 | +|mlp4 | 8/8 225| math cyclic-s | 606 12 | 121 | 128 127 | +|mp2d | 14/14 123| indust cyclic-s | 469 13 | 30 | 31 31 | +|newcpla1 | 9/16 38| indust cyclic-s | 170 22 | 38 | 38 38 | +|newill | 8/1 8| indust cyclic-s | 11 5 | 8 | 8 8 | +|opa | 17/69 342| indust cyclic-s | 477 22 | 77 | 79 79 | +|pope.rom | 6/48 64| indust cyclic-s | 593 12 | 59 | 62 59 | +|root | 8/5 255| math cyclic-s | 152 9 | 57 | 57 57 | +|spla | 16/46 * 2296| indust cyclic-s | 4972 33 | 248 | 262 260 | +|sqr6 | 6/12 63| math cyclic-s | 205 3 | 47 | 49 49 | +|sym10 | 10/1 837| math cyclic-s | 3150 0 | 210 | 210 210 | +|test1 | 8/10 * 209| random cyclic-s | 2407 0 | 110 | 123 115 | +|tial | 14/8 640| math cyclic-s | 7145 220 | 575 | 579 579 | +|tms | 8/16 30| indust cyclic-s | 162 13 | 30 | 30 30 | +|wim | 4/7 * 10| indust cyclic-s | 25 3 | 9 | 9 9 | +|x6dn | 39/5 121| indust cyclic-s | 916 60 | 81 | 81 81 | +_|__________|________________|___________________|________________|__________|_____________| +|bench1 | 9/9 * 285| random cyclic-us| 5972 0 | 111/125 | 136 128 | +|ex5 | 8/63 256| indust cyclic-us| 2532 28 | 62/67 | 74 72 | +|exam | 10/10 * 410| random cyclic-us| 4955 0 | 54/63 | 67 66 | +|max1024 | 10/6 1024| indust cyclic-us| 1278 14 | 249/261 | 274 267 | +|prom2 | 9/21 287| indust cyclic-us| 2635 9 | 276/287 | 287 287 | +|t1 | 21/23 796| indust cyclic-us| 15135 7 | 7/102 | 102 102 | +_|t_e_s_t_4______|___8_/_3_0____*__2_5_6__|_r_a_n_d_o_m___c_y_c_l_i_c_-_u_s__|__6_1_3_9_______0____|___0_/_1_0_4___|__1_2_2___1_0_4____| +|accpla | 50/69 183| indust primes | ? 97 | 97/175 | 175 175 | +|ex1010 | 10/10 * 810| random primes | ? 0 | 0/246 | 283 264 | +|ex4 | 128/28 620| indust primes | ? 138 | 138/279 | 279 279 | +|ibm | 48/17 173| indust primes | ? 172 | 173/173 | 173 173 | +|jbp | 36/57 166| indust primes | ? 0 | 0/122 | 122 122 | +|mainpla | 27/54 181| indust primes | ? 29 | 29/172 | 172 172 | +|misg | 56/23 75| indust primes | ? 3 | 3/69 | 69 69 | +|mish | 94/43 91| indust primes | ? 3 | 3/82 | 82 82 | +|misj | 35/14 48| indust primes | ? 13 | 13/35 | 35 35 | +|pdc | 16/40 * 2406| indust primes | ? 2 | 2/100 | 125 121 | +|shift | 19/16 100| indust primes | ? 100 | 100/100 | 100 100 | +|signet | 39/8 124| indust primes | ? 104 | 104/119 | 119 119 | +|soar.pla | 83/94 529| indust primes | ? 2 | 2/352 | 352 352 | +|test2 | 11/35 * 1999| random primes | ? 0 | 0/995 | 1105 | +|test3 | 10/35 * 1003| random primes | ? 0 | 0/491 | 543 491 | +|ti | 47/72 241| indust primes | ? 46 | 46/213 | 213 213 | +|ts10 | 22/16 128| indust primes | ? 128 | 128/128 | 128 128 | +|x2dn | 82/56 112| indust primes | ? 2 | 2/104 | 104 104 | +|x7dn | 66/15 622| indust primes | ? 378 | 378/538 | 538 538 | +|xparc | 41/73 551| indust primes | ? 140 | 140/254 | 254 254 | +_|__________|________________|___________________|________________|__________|_____________| + + + + + + + + + + January 30, 1988 + + + + + + - 6 - + + +New results: 7 of the previous 14 cyclic-unsolved examples +have been solved using a new covering algorithm. For refer- +ence, here are the results as given in the previous report +dated June 5, 1986: + +___________________________________________________________________________________ +| name | in/out terms | type class | # # | minimum | Esp. Esp. | +_|________|________________|___________________|_p_r_i_m_e_s___e_s_s_e_n_.__|_s_o_l_u_t_i_o_n__|_______(_s_)____| +|Z9sym | 9/1 420| math cyclic-us| 1680 0 | 84/84 | 85 84 | +|b4 | 33/23 * 54| indust cyclic-us| 6455 40 | 40/54 | 54 54 | +|bc0 | 26/11 419| indust cyclic-us| 6596 37 | 37/177 | 178 177 | +|lin.rom| 7/36 128| indust cyclic-us| 1087 8 | 125/128 | 128 128 | +|spla | 16/46 * 2296| indust cyclic-us| 4972 33 | 33/251 | 262 260 | +|test1 | 8/10 * 209| random cyclic-us| 2407 0 | 103/111 | 123 115 | +|tial | 14/8 640| math cyclic-us| 7145 220 | 220/575 | 579 579 | +_|________|________________|___________________|________________|__________|_____________| + + + Also, several of the lower-bounds for the cyclic-us +examples have been improved. The new results for examples +ex5, exam, max1024, and prom2 are due to Kong-Ngai Wong, +MIMOS, Malaysia. I have discredited the upper-bound result +for exam given by Marc Bartholomeus because I was unable to +duplicate his result using his program. For reference, here +are the previously reported results: +__________________________________________________________________________________ +| | | | # # | minimum | Esp. Esp. | +| name | in/out terms| type class | primes essen.| solution| (s) | +_|________|_______________|___________________|________________|__________|_____________| +|bench1 | 9/9 * 285| random cyclic-us| 5972 0 | 111/126 | 136 128 | +|ex5 | 8/63 256| indust cyclic-us| 2532 28 | 59/67 | 74 72 | +|exam | 10/10 * 410| random cyclic-us| 4955 0 | 52/59 | 67 66 | +|max1024| 10/6 1024| indust cyclic-us| 1278 14 | 239/267 | 274 267 | +|prom2 | 9/21 287| indust cyclic-us| 2635 9 | 274/287 | 287 287 | +|t1 | 21/23 796| indust cyclic-us| 15135 7 | 7/102 | 102 102 | +_|t_e_s_t_4____|___8_/_3_0___*__2_5_6__|_r_a_n_d_o_m___c_y_c_l_i_c_-_u_s__|__6_1_3_9_______0____|___0_/_1_0_4___|_1_2_2____1_0_4____| + + + + + + + + + + + + + + + + + + + + + + January 30, 1988 + + diff --git a/espresso/examples/doc/info.ms b/espresso/examples/doc/info.ms new file mode 100644 index 0000000..40881c5 --- /dev/null +++ b/espresso/examples/doc/info.ms @@ -0,0 +1,285 @@ +.sz +2 +.ce 3 +\fBBerkeley PLA Test Set Results\fP +\fBJune 5, 1986\fP +\fB(revised January 30, 1988)\fP +.sz -2 +.PP +These tables present the results of Boolean minimization +for the 145 PLA's in the Berkeley PLA test set. The cost +function is assumed to be minimum number of terms with only +a secondary concern given to the number of literals. +Each example is classified as one of 3 types: +.TS +center box; +c|c +l|l. +type description +_ +\fIindust\fP example donated from actual chip designs +\fImath\fP mathematical function +\fIrandom\fP randomly generated example +.TE +.PP +.sp +Each example also belongs to one of 5 categories, which +measures the relative difficulty of the problem: +.TS +center box; +c|c +l|l. +class description +_ +\fItrivial\fP minimum solution consists of essential prime implicants +\fInoncyclic\fP the covering problem contains no cyclic constraints +\fIcyclic-s\fP the covering problem contains cyclic constraints, + and the covering problem has been solved +\fIcyclic-us\fP the covering problem contains cyclic constraints, + and the covering problem as not been solved +\fIprimes\fP unable to enumerate all prime implicants +.TE +.sp +These classifications were determined by using the exact minimization +algorithms of Espresso-MV as well as the exact minimization algorithm +of McBoole. The classifications of \fIcyclic-us\fP +and \fIprimes\fP are dependent on the exact +minimization algorithms which were used. +For example, +although we know the minimum solution for \fIZ9sym\fP and \fIibm\fP (by methods +not involving the use of an exact minimization algorithm) +these examples are still classified as \fIcyclic-us\fP +and \fIprimes\fP respectively +because the exact minimization algorithm was unable +to determine the minimum solution. +(Note 1/28/88: \fIZ9SYM\fP has been moved to \fIcyclic-s\fP because +the new covering algorithm has directly derived the minimum solution.) +.PP +For each example, we first give the number of inputs, the number of +outputs, and the number of terms in the initial representation of +the function. If the number of terms is marked by *, then there +is a don't-care set specified for the function (which is not counted +in the initial number of terms). +.PP +We then present the number of prime implicants (when known), +the number of essential primes, and the minimum solution (when known). +When the minimum solution is not known for the class \fIcyclic-us\fP +a lower bound (as determined by the covering algorithm of +Espresso-MV) and an upper bound (the best solution we've seen) +are given. For the class \fIprimes\fP, the lower bound is merely +the number of essential prime implicants, +and the upper bound is the best solution we've seen. +For the examples \fIex1010\fP and \fIexam\fP the best results have +been reported by the authors Prestol-II, and we have not seen or +verified the results. In fact, I am beginning to have my doubts as +to the validity of these results. +.PP +These tables also present the results for Espresso-MV in both its normal +mode (Esp.) and its \fIstrong\fP mode (Esp. (s)). +.PP +.bp +.TS H +center box; +c2|c2 c2|c2 c2|c2 c2|c2|c2 c2 +^ |^ ^ |^ ^ |c c |c |c c +l |r r |l l |n n |n |n n. +name in/out terms type class # # minimum Esp. Esp. + primes essen. solution (s) +_ +.TH +alu1 12/8 19 indust trivial 780 19 19 19 19 +bcd.div3 4/4 * 9 math trivial 13 9 9 9 9 +clpl 11/5 20 indust trivial 143 20 20 20 20 +co14 14/1 14 math trivial 14 14 14 14 14 +max46 9/1 46 indust trivial 49 46 46 46 46 +newapla2 6/7 7 indust trivial 7 7 7 7 7 +newbyte 5/8 8 indust trivial 8 8 8 8 8 +newtag 8/1 8 indust trivial 8 8 8 8 8 +ryy6 16/1 112 indust trivial 112 112 112 112 112 +_ +add6 12/7 1092 math noncyclic 8568 153 355 355 355 +adr4 8/5 255 math noncyclic 397 35 75 75 75 +al2 16/47 103 indust noncyclic 9179 16 66 66 66 +alcom 15/38 47 indust noncyclic 4657 16 40 40 40 +alu2 10/8 * 87 indust noncyclic 434 36 68 68 68 +alu3 10/8 * 68 indust noncyclic 540 27 64 66 64 +apla 10/12 * 112 indust noncyclic 201 0 25 25 25 +b4 33/23 * 54 indust noncyclic 6455 40 54 54 54 +b11 8/31 * 74 indust noncyclic 44 22 27 27 27 +b2 16/17 110 indust noncyclic 928 54 104 106 104 +b7 8/31 * 74 indust noncyclic 44 22 27 27 27 +b9 16/5 123 indust noncyclic 3002 48 119 119 119 +bc0 26/11 419 indust noncyclic 6596 37 177 178 177 +bca 26/46 * 301 indust noncyclic 305 144 180 180 180 +bcb 26/39 * 299 indust noncyclic 255 137 155 156 155 +bcd 26/38 * 243 indust noncyclic 172 100 117 117 117 +br1 12/8 34 indust noncyclic 29 17 19 19 19 +br2 12/8 35 indust noncyclic 27 9 13 13 13 +dc1 4/7 15 indust noncyclic 22 3 9 9 9 +dc2 8/7 58 indust noncyclic 173 18 39 39 39 +dk17 10/11 * 57 indust noncyclic 111 0 18 18 18 +ex7 16/5 123 indust noncyclic 3002 48 119 119 119 +exep 30/63 * 149 indust noncyclic 558 82 108 108 108 +exp 8/18 * 89 indust noncyclic 238 30 56 59 56 +in1 16/17 110 indust noncyclic 928 54 104 106 104 +in3 35/29 75 indust noncyclic 1114 44 74 74 74 +in5 24/14 62 indust noncyclic 1067 53 62 62 62 +in6 33/23 54 indust noncyclic 6174 40 54 54 54 +in7 26/10 84 indust noncyclic 2112 31 54 54 54 +life 9/1 140 math noncyclic 224 56 84 84 84 +luc 8/27 27 indust noncyclic 190 14 26 26 26 +m1 6/12 32 indust noncyclic 59 6 19 19 19 +newapla 12/10 17 indust noncyclic 113 9 17 17 17 +newapla1 12/7 10 indust noncyclic 31 9 10 10 10 +newcond 11/2 31 indust noncyclic 72 18 31 31 31 +newcpla2 7/10 19 indust noncyclic 38 14 19 19 19 +newcwp 4/5 11 indust noncyclic 23 7 11 11 11 +newtpla 15/5 23 indust noncyclic 40 16 23 23 23 +newtpla1 10/2 4 indust noncyclic 6 3 4 4 4 +newtpla2 10/4 9 indust noncyclic 23 4 9 9 9 +newxcpla1 9/23 40 indust noncyclic 191 18 39 39 39 +p1 8/18 * 89 random noncyclic 287 25 54 55 54 +p3 8/14 * 66 random noncyclic 185 22 39 39 39 +p82 5/14 24 indust noncyclic 48 16 21 21 21 +prom1 9/40 502 indust noncyclic 9326 182 472 472 472 +radd 8/5 120 math noncyclic 397 35 75 75 75 +rckl 32/7 96 math noncyclic 302 6 32 32 32 +rd53 5/3 31 math noncyclic 51 21 31 31 31 +rd73 7/3 147 math noncyclic 211 106 127 127 127 +risc 8/31 74 indust noncyclic 46 22 28 28 28 +sex 9/14 23 indust noncyclic 99 13 21 21 21 +sqn 7/3 84 indust noncyclic 75 23 38 38 38 +t2 17/16 * 128 indust noncyclic 233 25 52 53 53 +t3 12/8 148 indust noncyclic 42 30 33 33 33 +t4 12/8 * 38 indust noncyclic 174 0 16 16 16 +vg2 25/8 110 indust noncyclic 1188 100 110 110 110 +vtx1 27/6 110 indust noncyclic 1220 100 110 110 110 +x1dn 27/6 112 indust noncyclic 1220 100 110 110 110 +x9dn 27/7 120 indust noncyclic 1272 110 120 120 120 +z4 7/4 127 math noncyclic 167 35 59 59 59 +_ +Z5xp1 7/10 128 math cyclic-s 390 8 63 63 64 +Z9sym 9/1 420 math cyclic-s 1680 0 84 85 84 +addm4 9/8 480 math cyclic-s 1122 24 189 200 192 +amd 14/24 171 indust cyclic-s 457 32 66 66 66 +b10 15/11 * 135 indust cyclic-s 938 51 100 100 100 +b12 15/9 431 indust cyclic-s 1490 2 41 42 41 +b3 32/20 * 234 indust cyclic-s 3056 123 210 211 211 +bcc 26/45 * 245 indust cyclic-s 237 119 137 137 137 +bench 6/8 * 31 random cyclic-s 391 0 16 18 17 +chkn 29/7 153 indust cyclic-s 671 86 140 140 140 +cps 24/109 654 indust cyclic-s 2487 57 157 163 159 +dekoder 4/7 * 10 indust cyclic-s 26 3 9 9 9 +dist 8/5 255 math cyclic-s 401 23 120 121 121 +dk27 9/9 * 20 indust cyclic-s 82 0 10 10 10 +dk48 15/17 * 42 indust cyclic-s 157 0 21 22 22 +exps 8/38 * 196 indust cyclic-s 852 56 132 134 133 +f51m 8/8 255 math cyclic-s 561 13 76 77 76 +fout 6/10 * 61 random cyclic-s 436 2 40 44 42 +gary 15/11 214 indust cyclic-s 706 60 107 107 107 +in0 15/11 135 indust cyclic-s 706 60 107 107 107 +in2 19/10 137 indust cyclic-s 666 85 134 136 134 +in4 32/20 234 indust cyclic-s 3076 118 211 212 212 +inc 7/9 * 34 indust cyclic-s 124 12 29 30 29 +intb 15/7 664 indust cyclic-s 6522 186 629 629 629 +l8err 8/8 * 253 math cyclic-s 142 15 50 51 51 +lin.rom 7/36 128 indust cyclic-s 1087 8 128 128 128 +log8mod 8/5 46 math cyclic-s 105 13 38 38 38 +m181 15/9 430 math cyclic-s 1636 2 41 42 41 +m2 8/16 96 indust cyclic-s 243 7 47 47 47 +m3 8/16 128 indust cyclic-s 344 4 62 65 63 +m4 8/16 256 indust cyclic-s 670 11 101 107 104 +mark1 20/31 * 23 indust cyclic-s 208 1 19 19 19 +max128 7/24 128 indust cyclic-s 469 6 78 82 79 +max512 9/6 512 indust cyclic-s 535 20 133 142 137 +mlp4 8/8 225 math cyclic-s 606 12 121 128 127 +mp2d 14/14 123 indust cyclic-s 469 13 30 31 31 +newcpla1 9/16 38 indust cyclic-s 170 22 38 38 38 +newill 8/1 8 indust cyclic-s 11 5 8 8 8 +opa 17/69 342 indust cyclic-s 477 22 77 79 79 +pope.rom 6/48 64 indust cyclic-s 593 12 59 62 59 +root 8/5 255 math cyclic-s 152 9 57 57 57 +spla 16/46 * 2296 indust cyclic-s 4972 33 248 262 260 +sqr6 6/12 63 math cyclic-s 205 3 47 49 49 +sym10 10/1 837 math cyclic-s 3150 0 210 210 210 +t1 21/23 796 indust cyclic-s 15135 7 100 102 102 +test1 8/10 * 209 random cyclic-s 2407 0 110 123 115 +tial 14/8 640 math cyclic-s 7145 220 575 579 579 +tms 8/16 30 indust cyclic-s 162 13 30 30 30 +wim 4/7 * 10 indust cyclic-s 25 3 9 9 9 +x6dn 39/5 121 indust cyclic-s 916 60 81 81 81 +_ +bench1 9/9 * 285 random cyclic-us 5972 0 111/125 136 128 +ex5 8/63 256 indust cyclic-us 2532 28 62/67 74 72 +exam 10/10 * 410 random cyclic-us 4955 0 54/63 67 66 +max1024 10/6 1024 indust cyclic-us 1278 14 249/261 274 267 +prom2 9/21 287 indust cyclic-us 2635 9 276/287 287 287 +test4 8/30 * 256 random cyclic-us 6139 0 0/104 122 104 +_ +accpla 50/69 183 indust primes ? 97 97/175 175 175 +ex1010 10/10 * 810 random primes ? 0 0/246 283 264 +ex4 128/28 620 indust primes ? 138 138/279 279 279 +ibm 48/17 173 indust primes ? 172 173/173 173 173 +jbp 36/57 166 indust primes ? 0 0/122 122 122 +mainpla 27/54 181 indust primes ? 29 29/172 172 172 +misg 56/23 75 indust primes ? 3 3/69 69 69 +mish 94/43 91 indust primes ? 3 3/82 82 82 +misj 35/14 48 indust primes ? 13 13/35 35 35 +pdc 16/40 * 2406 indust primes ? 2 2/100 125 121 +shift 19/16 100 indust primes ? 100 100/100 100 100 +signet 39/8 124 indust primes ? 104 104/119 119 119 +soar.pla 83/94 529 indust primes ? 2 2/352 352 352 +test2 11/35 * 1999 random primes ? 0 0/995 1105 +test3 10/35 * 1003 random primes ? 0 0/491 543 491 +ti 47/72 241 indust primes ? 46 46/213 213 213 +ts10 22/16 128 indust primes ? 128 128/128 128 128 +x2dn 82/56 112 indust primes ? 2 2/104 104 104 +x7dn 66/15 622 indust primes ? 378 378/538 538 538 +xparc 41/73 551 indust primes ? 140 140/254 254 254 +.TE +.bp +New results: 8 of the previous 14 cyclic-unsolved examples have been solved +using the new covering algorithm in Espresso Version 2.3. +For reference, here are the results as +given in the previous report dated June 5, 1986: +.TS +center box; +c2|c2 c2|c2 c2|c2 c2|c2|c2 c2 +^ |^ ^ |^ ^ |c c |c |c c +l |r r |l l |n n |n |n n. +name in/out terms type class # # minimum Esp. Esp. + primes essen. solution (s) +_ +Z9sym 9/1 420 math cyclic-us 1680 0 84/84 85 84 +b4 33/23 * 54 indust cyclic-us 6455 40 40/54 54 54 +bc0 26/11 419 indust cyclic-us 6596 37 37/177 178 177 +lin.rom 7/36 128 indust cyclic-us 1087 8 125/128 128 128 +spla 16/46 * 2296 indust cyclic-us 4972 33 33/251 262 260 +t1 21/23 796 indust cyclic-us 15135 7 7/102 102 102 +test1 8/10 * 209 random cyclic-us 2407 0 103/111 123 115 +tial 14/8 640 math cyclic-us 7145 220 220/575 579 579 +.TE +.PP +Also, several of the lower-bounds for the \fBcyclic-us\fP examples have +been improved. +The new results for examples ex5, exam, max1024, and prom2 are due +to Kong-Ngai Wong, MIMOS, Malaysia. +I have discredited the upper-bound result for exam given by Marc +Bartholomeus because I was unable to duplicate his result using +his program. +For reference, here are the previously reported results: +.TS +center box; +c2|c2 c2|c2 c2|c2 c2|c2|c2 c2 +^ |^ ^ |^ ^ |c c |c |c c +l |r r |l l |n n |n |n n. +name in/out terms type class # # minimum Esp. Esp. + primes essen. solution (s) +_ +bench1 9/9 * 285 random cyclic-us 5972 0 111/126 136 128 +ex5 8/63 256 indust cyclic-us 2532 28 59/67 74 72 +exam 10/10 * 410 random cyclic-us 4955 0 52/59 67 66 +max1024 10/6 1024 indust cyclic-us 1278 14 239/267 274 267 +prom2 9/21 287 indust cyclic-us 2635 9 274/287 287 287 +t1 21/23 796 indust cyclic-us 15135 7 7/102 102 102 +test4 8/30 * 256 random cyclic-us 6139 0 0/104 122 104 +.TE diff --git a/espresso/examples/doc/info.old.ms b/espresso/examples/doc/info.old.ms new file mode 100644 index 0000000..e3c8166 --- /dev/null +++ b/espresso/examples/doc/info.old.ms @@ -0,0 +1,233 @@ +.sz +2 +.ce 2 +\fBBerkeley PLA Test Set Results\fP +\fBJune 5, 1986\fP +.sz -2 +.PP +These tables present the results of Boolean minimization +for the 145 PLA's in the Berkeley PLA test set. The cost +function is assumed to be minimum number of terms with only +a secondary concern given to the number of literals. +Each example is classified as one of 3 types: +.TS +center box; +c|c +l|l. +type description +_ +\fIindust\fP example donated from actual chip designs +\fImath\fP mathematical function +\fIrandom\fP randomly generated example +.TE +.PP +.sp +Each example also belongs to one of 5 categories, which +measures the relative difficulty of the problem: +.TS +center box; +c|c +l|l. +class description +_ +\fItrivial\fP minimum solution consists of essential prime implicants +\fInoncyclic\fP the covering problem contains no cyclic constraints +\fIcyclic-s\fP the covering problem contains cyclic constraints, + and the covering problem has been solved +\fIcyclic-us\fP the covering problem contains cyclic constraints, + and the covering problem as not been solved +\fIprimes\fP unable to enumerate all prime implicants +.TE +.sp +These classifications were determined by using the exact minimization +algorithms of Espresso-MV as well as the exact minimization algorithm +of McBoole. The classifications of \fIcyclic-us\fP +and \fIprimes\fP are dependent on the exact +minimization algorithms which were used. +For example, +although we know the minimum solution for \fIZ9sym\fP and \fIibm\fP (by methods +not involving the use of an exact minimization algorithm) +these examples are still classified as \fIcyclic-us\fP +and \fIprimes\fP respectively +because the exact minimization algorithm was unable +to determine the minimum solution. +.PP +For each example, we first give the number of inputs, the number of +outputs, and the number of terms in the initial representation of +the function. If the number of terms is marked by *, then there +is a don't-care set specified for the function (which is not counted +in the initial number of terms). +.PP +We then present the number of prime implicants (when known), +the number of essential primes, and the minimum solution (when known). +When the minimum solution is not known for the class \fIcyclic-us\fP +a lower bound (as determined by the covering algorithm of +Espresso-MV) and an upper bound (the best solution we've seen) +are given. For the class \fIprimes\fP, the lower bound is merely +the number of essential prime implicants, +and the upper bound is the best solution we've seen. +For the examples \fIex1010\fP and \fIexam\fP the best results have +been reported by the authors Prestol-II, and we have not seen or +verified the results. +.PP +These tables also present the results for Espresso-MV in both its normal +mode (Esp.) and its \fIstrong\fP mode (Esp. (s)). +.bp +.TS H +center box; +c2|c2 c2|c2 c2|c2 c2|c2|c2 c2 +^ |^ ^ |^ ^ |c c |c |c c +l |r r |l l |n n |n |n n. +name in/out terms type class # # minimum Esp. Esp. + primes essen. solution (s) +_ +.TH +alu1 12/8 19 indust trivial 780 19 19 19 19 +bcd.div3 4/4 * 9 math trivial 13 9 9 9 9 +clpl 11/5 20 indust trivial 143 20 20 20 20 +co14 14/1 14 math trivial 14 14 14 14 14 +max46 9/1 46 indust trivial 49 46 46 46 46 +newapla2 6/7 7 indust trivial 7 7 7 7 7 +newbyte 5/8 8 indust trivial 8 8 8 8 8 +newtag 8/1 8 indust trivial 8 8 8 8 8 +ryy6 16/1 112 indust trivial 112 112 112 112 112 +_ +add6 12/7 1092 math noncyclic 8568 153 355 355 355 +adr4 8/5 255 math noncyclic 397 35 75 75 75 +al2 16/47 103 indust noncyclic 9179 16 66 66 66 +alcom 15/38 47 indust noncyclic 4657 16 40 40 40 +alu2 10/8 * 87 indust noncyclic 434 36 68 68 68 +alu3 10/8 * 68 indust noncyclic 540 27 64 66 64 +apla 10/12 * 112 indust noncyclic 201 0 25 25 25 +b11 8/31 * 74 indust noncyclic 44 22 27 27 27 +b2 16/17 110 indust noncyclic 928 54 104 106 104 +b7 8/31 * 74 indust noncyclic 44 22 27 27 27 +b9 16/5 123 indust noncyclic 3002 48 119 119 119 +bca 26/46 * 301 indust noncyclic 305 144 180 180 180 +bcb 26/39 * 299 indust noncyclic 255 137 155 156 155 +bcd 26/38 * 243 indust noncyclic 172 100 117 117 117 +br1 12/8 34 indust noncyclic 29 17 19 19 19 +br2 12/8 35 indust noncyclic 27 9 13 13 13 +dc1 4/7 15 indust noncyclic 22 3 9 9 9 +dc2 8/7 58 indust noncyclic 173 18 39 39 39 +dk17 10/11 * 57 indust noncyclic 111 0 18 18 18 +ex7 16/5 123 indust noncyclic 3002 48 119 119 119 +exep 30/63 * 149 indust noncyclic 558 82 108 108 108 +exp 8/18 * 89 indust noncyclic 238 30 56 59 56 +in1 16/17 110 indust noncyclic 928 54 104 106 104 +in3 35/29 75 indust noncyclic 1114 44 74 74 74 +in5 24/14 62 indust noncyclic 1067 53 62 62 62 +in6 33/23 54 indust noncyclic 6174 40 54 54 54 +in7 26/10 84 indust noncyclic 2112 31 54 54 54 +life 9/1 140 math noncyclic 224 56 84 84 84 +luc 8/27 27 indust noncyclic 190 14 26 26 26 +m1 6/12 32 indust noncyclic 59 6 19 19 19 +newapla 12/10 17 indust noncyclic 113 9 17 17 17 +newapla1 12/7 10 indust noncyclic 31 9 10 10 10 +newcond 11/2 31 indust noncyclic 72 18 31 31 31 +newcpla2 7/10 19 indust noncyclic 38 14 19 19 19 +newcwp 4/5 11 indust noncyclic 23 7 11 11 11 +newtpla 15/5 23 indust noncyclic 40 16 23 23 23 +newtpla1 10/2 4 indust noncyclic 6 3 4 4 4 +newtpla2 10/4 9 indust noncyclic 23 4 9 9 9 +newxcpla1 9/23 40 indust noncyclic 191 18 39 39 39 +p1 8/18 * 89 random noncyclic 287 25 54 55 54 +p3 8/14 * 66 random noncyclic 185 22 39 39 39 +p82 5/14 24 indust noncyclic 48 16 21 21 21 +prom1 9/40 502 indust noncyclic 9326 182 472 472 472 +radd 8/5 120 math noncyclic 397 35 75 75 75 +rckl 32/7 96 math noncyclic 302 6 32 32 32 +rd53 5/3 31 math noncyclic 51 21 31 31 31 +rd73 7/3 147 math noncyclic 211 106 127 127 127 +risc 8/31 74 indust noncyclic 46 22 28 28 28 +sex 9/14 23 indust noncyclic 99 13 21 21 21 +sqn 7/3 84 indust noncyclic 75 23 38 38 38 +t2 17/16 * 128 indust noncyclic 233 25 52 53 53 +t3 12/8 148 indust noncyclic 42 30 33 33 33 +t4 12/8 * 38 indust noncyclic 174 0 16 16 16 +vg2 25/8 110 indust noncyclic 1188 100 110 110 110 +vtx1 27/6 110 indust noncyclic 1220 100 110 110 110 +x1dn 27/6 112 indust noncyclic 1220 100 110 110 110 +x9dn 27/7 120 indust noncyclic 1272 110 120 120 120 +z4 7/4 127 math noncyclic 167 35 59 59 59 +_ +Z5xp1 7/10 128 math cyclic-s 390 8 63 63 64 +addm4 9/8 480 math cyclic-s 1122 24 189 200 192 +amd 14/24 171 indust cyclic-s 457 32 66 66 66 +b10 15/11 * 135 indust cyclic-s 938 51 100 100 100 +b12 15/9 431 indust cyclic-s 1490 2 41 42 41 +b3 32/20 * 234 indust cyclic-s 3056 123 210 211 211 +bcc 26/45 * 245 indust cyclic-s 237 119 137 137 137 +bench 6/8 * 31 random cyclic-s 391 0 16 18 17 +chkn 29/7 153 indust cyclic-s 671 86 140 140 140 +cps 24/109 654 indust cyclic-s 2487 57 157 163 159 +dekoder 4/7 * 10 indust cyclic-s 26 3 9 9 9 +dist 8/5 255 math cyclic-s 401 23 120 121 121 +dk27 9/9 * 20 indust cyclic-s 82 0 10 10 10 +dk48 15/17 * 42 indust cyclic-s 157 0 21 22 22 +exps 8/38 * 196 indust cyclic-s 852 56 132 134 133 +f51m 8/8 255 math cyclic-s 561 13 76 77 76 +fout 6/10 * 61 random cyclic-s 436 2 40 44 42 +gary 15/11 214 indust cyclic-s 706 60 107 107 107 +in0 15/11 135 indust cyclic-s 706 60 107 107 107 +in2 19/10 137 indust cyclic-s 666 85 134 136 134 +in4 32/20 234 indust cyclic-s 3076 118 211 212 212 +inc 7/9 * 34 indust cyclic-s 124 12 29 30 29 +intb 15/7 664 indust cyc?ic-s 6522 186 629 629 629 +l8err 8/8 * 253 math cyclic-s 142 15 50 51 51 +log8mod 8/5 46 math cyclic-s 105 13 38 38 38 +m181 15/9 430 math cyclic-s 1636 2 41 42 41 +m2 8/16 96 indust cyclic-s 243 7 47 47 47 +m3 8/16 128 indust cyclic-s 344 4 62 65 63 +m4 8/16 256 indust cyclic-s 670 11 101 107 104 +mark1 20/31 * 23 indust cyclic-s 208 1 19 19 19 +max128 7/24 128 indust cyclic-s 469 6 78 82 79 +max512 9/6 512 indust cyclic-s 535 20 133 142 137 +mlp4 8/8 225 math cyclic-s 606 12 121 128 127 +mp2d 14/14 123 indust cyclic-s 469 13 30 31 31 +newcpla1 9/16 38 indust cyclic-s 170 22 38 38 38 +newill 8/1 8 indust cyclic-s 11 5 8 8 8 +opa 17/69 342 indust cyclic-s 477 22 77 79 79 +pope.rom 6/48 64 indust cyclic-s 593 12 59 62 59 +root 8/5 255 math cyclic-s 152 9 57 57 57 +sqr6 6/12 63 math cyclic-s 205 3 47 49 49 +sym10 10/1 837 math cyclic-s 3150 0 210 210 210 +tms 8/16 30 indust cyclic-s 162 13 30 30 30 +wim 4/7 * 10 indust cyclic-s 25 3 9 9 9 +x6dn 39/5 121 indust cyclic-s 916 60 81 81 81 +_ +Z9sym 9/1 420 math cyclic-us 1680 0 84/84 85 84 +b4 33/23 * 54 indust cyclic-us 6455 40 40/54 54 54 +bc0 26/11 419 indust cyclic-us 6596 37 37/177 178 177 +bench1 9/9 * 285 random cyclic-us 5972 0 111/126 136 128 +ex5 8/63 256 indust cyclic-us 2532 28 59/67 74 72 +exam 10/10 * 410 random cyclic-us 4955 0 52/59 67 66 +lin.rom 7/36 128 indust cyclic-us 1087 8 125/128 128 128 +max1024 10/6 1024 indust cyclic-us 1278 14 239/267 274 267 +prom2 9/21 287 indust cyclic-us 2635 9 274/287 287 287 +spla 16/46 * 2296 indust cyclic-us 4972 33 33/251 262 260 +t1 21/23 796 indust cyclic-us 15135 7 7/102 102 102 +test1 8/10 * 209 random cyclic-us 2407 0 103/111 123 115 +test4 8/30 * 256 random cyclic-us 6139 0 0/104 122 104 +tial 14/8 640 math cyclic-us 7145 220 220/575 579 579 +_ +accpla 50/69 183 indust primes ? 97 97/175 175 175 +ex1010 10/10 * 810 random primes ? 0 0/246 283 264 +ex4 128/28 620 indust primes ? 138 138/279 279 279 +ibm 48/17 173 indust primes ? 172 173/173 173 173 +jbp 36/57 166 indust primes ? 0 0/122 122 122 +mainpla 27/54 181 indust primes ? 29 29/172 172 172 +misg 56/23 75 indust primes ? 3 3/69 69 69 +mish 94/43 91 indust primes ? 3 3/82 82 82 +misj 35/14 48 indust primes ? 13 13/35 35 35 +pdc 16/40 * 2406 indust primes ? 2 2/100 125 121 +shift 19/16 100 indust primes ? 100 100/100 100 100 +signet 39/8 124 indust primes ? 104 104/119 119 119 +soar.pla 83/94 529 indust primes ? 2 2/352 352 352 +test2 11/35 * 1999 random primes ? 0 0/995 1105 +test3 10/35 * 1003 random primes ? 0 0/491 543 491 +ti 47/72 241 indust primes ? 46 46/213 213 213 +ts10 22/16 128 indust primes ? 128 128/128 128 128 +x2dn 82/56 112 indust primes ? 2 2/104 104 104 +x7dn 66/15 622 indust primes ? 378 378/538 538 538 +xparc 41/73 551 indust primes ? 140 140/254 254 254 +.TE diff --git a/espresso/examples/doc/man.pla b/espresso/examples/doc/man.pla new file mode 100644 index 0000000..4fe8e84 --- /dev/null +++ b/espresso/examples/doc/man.pla @@ -0,0 +1,63 @@ +These examples are from University of Leuven (Hugo De Man): + +Filename Table Comments + +adr4 ad4 1a 4-bit adder +al2 (dat) 16/47 +alcom (dat) 15/40 +b10 b10 1a +b11 8/31 +b12 b12 1a +b2 b2 1a +b3 b3 1a has DC ?? +b4 b4 1a +b5 b5 1a same as sqn from book.pla +b7 b7 1a +b9 b9 1a +bench ben 1b +bench1 be1 1b also known as ben1 +bench2 8/18 looks like 1b (idential to p1 == ph1)!! +br1 (dat) 12/8 also known as bra1 +br2 (dat) 12/8 also known as bra2 +dekoder dek 1a +ex1010 ex1 1b also known as ex1010 +exam exa 1b +exp exp 1a +exps sim 1a also known as siem +fout fot 1b +ibm ibm 1a +in 47/72 same as ti from book.pla +inc (dat) 7/9 +luc luc 1a +m1 mi1 1a also known as mit1 +m181 15/9 +m2 mi2 1a also known as mit2 +m3 mi3 1a also known as mit3 +m4 mi4 1a also known as mit4 +mp2d mp2 1a +p1 ph1 1b also known as phi1 +p2 8/18 looks like 1b (idential to p1 == ph1)!! +p3 ph3 1b also known as phi3 +p4 empty?? +p82 (dat) 5/14 +pdc (dat) pro 1a also known as pro1 +prom1 9/40 also known as rom1 +prom2 9/21 also known as rom2 +sex (dat) 9/14 +shift shi 1a +sym10 sy1 1b also known as sym1 +sym9 sy9 1b +t1 te1 1a +t2 te2 1a +t3 te3 1a +t4 te4 1a +test1 8/10 looks like 1b, also known as tes1 +test2 11/35 looks like 1b +test3 10/35 looks like 1b, also known as tes3 +test4 8/30 looks like 1b + +I seem to be missing the following from Bartholomeus' PhD Thesis: + boo5 5/5 32 terms + boot 7/10 128 terms + pla7 6/48 593 terms + pro2 16/40 2400 terms diff --git a/espresso/examples/doc/man1a.list b/espresso/examples/doc/man1a.list new file mode 100644 index 0000000..30c8a00 --- /dev/null +++ b/espresso/examples/doc/man1a.list @@ -0,0 +1 @@ +adr4 b10 b12 b2 b3 b4 b5 b7 b9 dekoder exp exps ibm luc m1 m2 m3 m4 mp2d pdc shift t1 t2 t3 t4 diff --git a/espresso/examples/doc/man1b.list b/espresso/examples/doc/man1b.list new file mode 100644 index 0000000..8ef8ddd --- /dev/null +++ b/espresso/examples/doc/man1b.list @@ -0,0 +1 @@ +bench bench1 ex1010 exam fout p1 p3 sym10 sym9 test1 test2 test3 test4 diff --git a/espresso/examples/doc/man1u.list b/espresso/examples/doc/man1u.list new file mode 100644 index 0000000..b06c233 --- /dev/null +++ b/espresso/examples/doc/man1u.list @@ -0,0 +1 @@ +al2 alcom b11 br1 br2 inc m181 p82 prom1 prom2 sex diff --git a/espresso/examples/doc/other.pla b/espresso/examples/doc/other.pla new file mode 100644 index 0000000..c14ecc3 --- /dev/null +++ b/espresso/examples/doc/other.pla @@ -0,0 +1,42 @@ +accpla one of the Bellmac PLAs from Jean Dussault, Bell Labs +addm4 function: adder/multiplier +c1orig soar pla from Chris Marino -- before column permutation +c1perm soar pla from Chris Marino -- after column permutation +clpl from Brayton, IBM +dk14.mv mv version of dk machine +dk14s DK machine FSM minimization with input encoding +dk15.mv mv version of dk machine +dk15s DK machine FSM minimization with input encoding +dk16.mv mv version of dk machine +dk16s DK machine FSM minimization with input encoding +dk17.mv mv version of dk machine +dk17s DK machine FSM minimization with input encoding +dk27.mv mv version of dk machine +dk27s DK machine FSM minimization with input encoding +dk512.mv mv version of dk machine +dk512s DK machine FSM minimization with input encoding +ex4 example 4 ? source unknown +ex5 example 5 ? source unknown +ex7 example 7 ? source unknown +intb from Brayton, IBM +iofsm FSM machine -- OPUS iofsm +iofsm.mv mv version of above +m4pair 4-bit multiplier -- paired variables +mainpla one of the Bellmac PLAs -- from Jean Dussault +mark1 FSM machine -- from Geiger, CMU +mark1.mv mv version of above +max.rom ROM from Berkeley DSP group (Max Hauser) +mfsm FSM machine (already encoded) +mfsm.mv FSM machine, mv version, for encoding +misj from Brayton, IBM +pope.rom ROM from Berkeley DSP group (Steve Pope) +rwei.pla from Ruey-Sing Wei -- PLA test patterns +ryy6 from Brayton, IBM +signet example ? source unknown +simple simple FSM +simple.mv mv version of above +spam1 example taken from spam paper DAC +ts10 from Brayton, IBM +vtx1 from Brayton, IBM +x1 Control logic, source priviledged +x2 Control logic, source priviledged diff --git a/espresso/examples/doc/random.stats b/espresso/examples/doc/random.stats new file mode 100644 index 0000000..45c5436 --- /dev/null +++ b/espresso/examples/doc/random.stats @@ -0,0 +1,11 @@ +bench 22.07 9.38 68.55 +bench1 22.45 9.31 68.24 +ex1010 15.33 14.37 70.30 +exam 7.11 6.10 86.79 +fout 28.75 29.84 41.41 +p1 16.60 6.45 76.95 +p3 14.03 6.33 79.63 +test1 35.66 14.26 50.08 +test2 19.40 9.94 70.67 +test3 19.28 9.89 70.83 +test4 8.79 19.74 71.47 diff --git a/espresso/examples/fsm.pla b/espresso/examples/fsm.pla new file mode 100644 index 0000000..5c5fd58 --- /dev/null +++ b/espresso/examples/fsm.pla @@ -0,0 +1,23 @@ +.i 5 +.o 7 +.ilb c<0> ts<0> tl<0> presentState<1> presentState<0> +.ob hl<1> hl<0> fl<1> fl<0> st<0> nextState<1> nextState<0> +.symbolic presentState<1> presentState<0> ; ; +.symbolic-output nextState<1> nextState<0> ; ; +.p 15 +---10 1000000 +----1 0100000 +---01 0010000 +----0 0001000 +0--11 0000100 +--111 0000100 +1-100 0000100 +-1-10 0000100 +-1-01 0000100 +---10 0000010 +1-1-0 0000010 +1-01- 0000010 +---11 0000001 +-1-1- 0000001 +-0--1 0000001 +.e diff --git a/espresso/examples/indust/accpla b/espresso/examples/indust/accpla new file mode 100644 index 0000000..b343eb9 --- /dev/null +++ b/espresso/examples/indust/accpla @@ -0,0 +1,368 @@ +.i 50 +.o 69 +----------------------------1--------------------- +0000000000000011111110000011 10101000000010000101111000000010000101000 +---------------------000000----------------------- +0000000000000001111000000000 00000000000000000000000000000000000000000 +---------------------000100----------------------- +0000000000000001111100000000 00000000000000000000000000000000000000000 +---------------------000000-01-------------------- +0000000000000000000000000000 00000100000000000000000000000000000000000 +------0000--------1---------0--------------------- +0000000000001100000000000000 00000000000000000000000000000000000000000 +------0000--------1---------0---------0----------- +0000000000000000000000000000 00000000000000000000000000000000001000000 +------00-0------------------0---------0----------- +0000000000000000000000000000 00000000000000000000000000010010000000000 +------1011---------------------------------------- +0000000000000000000000000000 00001000000000000000000000000000000000000 +------1011--------1---------0--------------------- +0000000000011100000000000000 00000000000000000000000000000000000000000 +------1011------------------0---------0----------- +0000000000000000000000000000 00000000000000000000000000010010000000000 +------1011--------1---------0---------0----------- +0000000000000000000000000000 00000000000000000000000000000000001000000 +------0001------------------0---------0----------- +0000000000000000000000000000 00000000000000000000000000010010000000000 +------0001---------1--------0--------------------- +0000000000101100000000000000 00000000000000000000000000000000000000000 +------0001---------1--------0---------0----------- +0000000000000000000000000000 00000000000000000000000000000000001000000 +------0010------------------0--------------------- +0000000000001000000000000000 00000000000000000000000000000000000000000 +------010010----------------0--------0------------ +0000000000101000000000000010 10000000000000000000000000000000000000000 +------010001----------------0--------0------------ +0000000000101000000000000011 10000000000000000000000000000000000000000 +------010001-------------------------1------------ +0000000000000000000000000011 10000000000000000000000000000000000000000 +------0100--------1---------0--------1------------ +0000000000000000000001000000 00000000000000000000010000000000000000000 +------0100----1010-------------------1------------ +0000000000000000000000000000 00000000000000000000100000000000000000000 +------010010-------------------------1------------ +0000000000000000000000000010 10000000000000000000000000000000000000000 +------0100----1001-------------------1------------ +0000000000000000000000000000 00000000000000000000100000000000000000000 +------0101-----------001010----------------------- +0000000000000001111000000000 00000000000000000000000000000000000000000 +------0101----------0001010-01-------------------- +0000000000000000000000000000 00000100000000000000000000000000000000000 +------0110------------------0--------------------- +0000000000000000000000000000 00000000000000100000000000000000000000000 +-------110------------------0--------------------0 +0000000000001000000000000000 00000000000000000000000000000000010001000 +-------110------------------0--------------------1 +0000000000001000000000000000 00000000000000000000000000000000000000000 +-------110------------------0---------0----------- +0000000000000000000000000000 00000000000000000000000000011010000000000 +------0111------------------0---------0----------- +0000000000001000000010000000 00000000000000000000000010010010000000000 +------1001------------------0--------------------- +0000000000010100000000000000 00000000000000000000000000000000000000000 +------1001----------1-------0--------------------- +0000000000000000000000000000 00001100000000000000000000000000000000000 +------1010------------------0--------1------------ +1000000000000010000000000000 00000010000010100000000000000000000000010 +------1101------------------0--------1------------ +1000000000000010000000000000 00000010000010000000000000000000000000010 +------1000------------------0--------0------------ +0000000000000000000000000000 00000100000000000000000000000000000000000 +------1-00------------------0--------1------------ +1000000000000010000000000000 00000010000010000000000000000000000000010 +------1-0010-------------------------------------- +0000000000000000000000000010 10000000000000000000000000000000000000000 +------1-0001-------------------------------------- +0000000000000000000000000011 10000000000000000000000000000000000000000 +------1-00------------------0--------0------------ +0000000000101000000000000000 00000000000000000000000000000000000000000 +10--00-------------------------------------------- +0000000000000010000000000000 00000000000010000000000000000000000000000 +10--00--------------------------------1----------- +0000000000000000000100000000 00000000000000000000111000000000000000000 +10--00------------------------100----------------- +0000000000000000000100000000 00000000000000000000000000000000000000000 +10--00---------------000101---100----------------- +0000000000000001111000000000 00000000000000000000000000000000000000000 +10--00---------------000101-01100-----0----------- +0000000000000000000000000000 00000100000000000000000000000000000000000 +10--00----------------------0-01------0----------- +0000000000000000000000000000 00000000010000000000000000000000000000000 +10--00----------------------0-100-----0----------- +0000000000000000000000000000 00000000010000000000000000000000000000000 +10--00----------------------0-000-----0----------- +0000000000000000000000111000 00000000010000000000001000000010000100000 +10--00----------------------0-000-----0------1---- +0000000000000000000000000000 00000000000000000000000000000000010000000 +10--00----01----------------0-000-----0----------- +0000000000000000000100000000 00000000000000000000000000000000000000000 +10--00----01------------------000-----0------1---- +0000000000000000000001000011 10000000000000000000000000000000000000000 +10--00----00----------------0-000-----0----------- +0010100000000000000000000000 00000000000000000000110000000000000000000 +10--00----------------------0-001-----0----------- +0000000000000000000100000000 00000000010000000000000000000000000000000 +10--00----------------------0-111-----0----------- +0000000000000000000100000000 00000000010000000000000000000000000000000 +10--00----00----------------0-111--0-00------0---1 +0101000000000000000000010100 00000000000000000000000000000010010100000 +10--00----00----------------0-111--0-00------0---0 +0111100010000000000000111100 00000000000000000000000010000010010100000 +10--00----00----------------0-111--1000------0---1 +0101000000000000000000010000 00000000000000000000000000000010010100000 +10--00----00----------------0-111--1000------0---0 +0111100001000000000000011100 00000000000000000000000010000010010100000 +10--00----01----------------0-111--0-00------0---1 +0101000000000000000000010000 00000000000000000000000000000010010100000 +10--00----01----------------0-111--0-00------0---0 +0111100001000000000000011100 00000000000000000000000010000010010100000 +10--00----00-0--------------0-001-1-000------0---1 +0101000000000000000000010000 00000000000000000000000000000010010100000 +10--00----00-0--------------0-001-1-000------0---0 +0111100001000000000000011100 00000000000000000000000010000010010100000 +10--00----01-0--------------0-001--0-00------0---1 +0101000000000000000000010000 00000000000000000000000000000010010100000 +10--00----01-0--------------0-001--0-00------0---0 +0111100001000000000000011100 00000000000000000000000010000010010100000 +10--00----00-0--------------0-001-0--00------0---1 +0101000000000000000000010100 00000000000000000000000000000010010100000 +10--00----00-0--------------0-001-0--00------0---0 +0111100001000000000000011100 00000000000000000000000010000010010100000 +10--00----------------------0-110-----0----------- +0000000000000000000000000000 00000000010000000000000000000000000000000 +10--00---------------001011-0-110-----0----------- +0111100111000001111110100000 00000000000000000000000010000010000100000 +10--001111----1111---101000-0-110-----0----------- +0000001011000001111100000000 00000000000000000000000000000000000000000 +10--00---------------001000-0-110-----0--------0-- +0111110000000000000000000000 00000000000000000000000000000000000000000 +10--00---------------001000---110-----0--------1-- +0000000000000001111100000000 00000000000000000000000000000000000000000 +10--00---------------001000-0-1101----0--------1-- +0101000000000000000000010111 10000000000000000000000000000011010001000 +10--00---------------001001-0-110-----0----------- +0011000000000001111100111111 10000000000000000000000000000100000001000 +10--00---------------001001-01110-----0----------- +0000000000000000000000000000 00011000000000000000000000000000000000000 +10--00---------------010100-0-110-----0----------- +0000000000000001111100000000 00000000000000000000000000000010100100000 +10--00---------------001110---110-----0--------1-- +0000000000000001111100000000 00000000000000000000000000000000000000000 +10--00---------------001110-0-110-----0--------0-- +0111110000000000000000000000 00000000000000000000000000000000000000000 +10--00---------------001110-0-1101----0--------1-- +0111100110000000000000011011 10000000000000000000110010000010000101000 +10--00---------------010000-0-110-----0----------- +0111100011000001111100111111 10000000000000101100110010001010010101000 +10--00----------------00111-0-110-----0-------0--- +0111100110000000000010100100 00000001000001000000000010000010000100000 +10--00---------------100111---110-----0-------0--- +0000000000000000000100000000 00000000000000000000000000000000000000000 +10--00---------------001111-0-110-----0----------- +0111100110000001111110100000 00000000000001000000000110000010000100000 +10--00---------------01110--0-110-----0----------- +0111100110000001111110100000 00000000000001000000000110000010000100000 +10--00---------------011100-0-110-----0----------- +0000001110000000000000000000 00000000000000000000000000000000000000000 +10--00---------------011000-0-110-----0----------- +0111101111000001111110100000 00000000000000000000000110000010000100000 +10--00---------------01-001-0-110-----0----------- +0000000000000001111100000000 00000000000000000000110000001010000100000 +10--00---------------010001-0-110-----0----------- +0000000000000000000000000000 00000000000000101100000000000000000000000 +10--00---------------01-001-0-110-----0----------0 +0111100011000000000000111111 10000000000000000000000010000000010001000 +10--00---------------011010-0-110-----0--------0-- +0111110000000000000000000000 00000000000000000000000000000000000000000 +10--00---------------011010---110-----0--------1-- +0000000000000001111100000000 00000000000000000000000000000000000000000 +10--00---------------011010-0-1101----0--------1-- +0111100011000000000000111111 10000000000000000000110010001010010101000 +10--00---------------01-110-0-110-----0----------- +0101000000000001111100010111 10100000000000000000110000000010010101000 +10--00---------------000011-0-110-----0----------- +0101000000000001111100010111 10100000000000000000110000000010010101000 +10--00---------------010101-0-110-----0--------0-- +0111110000000000000000000000 00000000000000000000000000000000000000000 +10--00---------------010101---110-----0--------1-- +0000000000000001111100000000 00000000000000000000000000000000000000000 +10--00---------------010101-0-1101----0--------1-- +0101000000000000000000010111 10000000000000000000000000000010010101000 +10--00---------------000001-0-110-----0----------- +0111100101000001111110100000 00000000101100000000000010000010000000000 +10--00----------------00110-0-110-----0----------- +0010000000000000000110001000 00000001000001000000000010000010000100000 +10--00---------------100110-0-110-----0----------- +0110100100000000000000000000 00000000000000000000000000000000000000000 +10--00---------------01-011-0-110-----0----------- +0000000000000001111100001000 00000000000001100000000000000000000000000 +10--00---------------01-011-01110-----0----------- +0000000000000000000000000000 00011000000000000000000000000000000000000 +10--00---------------001100-0-110-----0----------- +0110100100000001111110001000 00000000000001100000000010000010000100000 +10--00---------------001101-0-110-----0----------- +0110100100000001111110001000 00000000000000100011000010000010000100000 +10--00---------------010011-0-110-----010-0------- +0110100100000000000000000000 00000000000000000000000000000010000100000 +10--00---------------010011-0-110-----011-0------- +0101010000000000000000000000 00000000000000000000000000000000000000000 +10--00---------------010011-0-110-----010-1------- +0100100000000000000000000000 00000000000000000000000000000000000000000 +10--00---------------010011-0-110-----011-1------- +0100010000000000000000000000 00000000000000000000000000000000000000000 +10--00---------------010011-0-110-----00---------- +0101100000000000000000000000 00000000000000000000000000000000000000000 +10--00---------------01101110-110-----0-0--------- +0100100000000000000010000000 00000000000000000000000010000010000100000 +10--00---------------01101110-110-----0-1--------- +0100000000000000000010000000 00000000000000000000000010000010000100000 +10--00---------------01101100-110-----01---------- +0110100100000000000010000000 00000000000000000000000010000010000100000 +10--00---------------01101100-110-----00---------- +0101010000000000000010000000 00000000000000000000000010000010000100000 +10--00------0---------------0-101-----0----------- +0111100111000000000000101000 00000000000000000000000010000010000100000 +10--00------0--------010001-0-101-----0----------- +0000000000000000000000000000 00000000000000101100000000000000000000000 +10--00------1-----------------101-----0----------- +0000000000000001111100000000 00000000000000000000000000000000000000000 +10--00------1---------------0-101-----0------1---- +0000000000000000000001000000 00000000000000000000000000000000000000000 +10--00------1--------011011-01101-----0----------- +0000000000000000000000000000 00011000000000000000000000000000000000000 +10--00------1--------011011-0-101-----0----------- +0000000000000000000000001000 00000000000001100000000000000000000000000 +10--00------1--------01101110-101-----0----------- +0011100000000000000000000000 00000000000000000000000000000000000000000 +10--00------1--------01101100-101-----01---------- +0110100100000000000000000000 00000000000000000000000000000000000000000 +10--00------1--------01101100-101-----00---------- +0101010000000000000000000000 00000000000000000000000000000000000000000 +10--00------1--------01110--0-101-----0----------- +0111100110000000000000100000 00000000000001000000000100000000000000000 +10--00------1--------001011-0-101-----0----------- +0111100111000000000000100000 00000000000000000000000000000000000000000 +10--00------1--------01-001-0-101-----0----------0 +0111100011000000000000111111 10000000000000000000110000000000000000000 +10--00------1--------01-001-0-101-----0----------1 +0000010000000000000000000000 00100000000000000000110000000000000000000 +10--00------1--------010001-0-101-----0----1------ +0000000000000000000000000000 00000000000000100000000000000000000000000 +10--00------1--------011000-0-101-----0----------- +0111101111000000000000100000 00000000000001000000000100000000000000000 +110101----------------------0--------------------- +0010010000000000000000000000 00000000000000000000000000000000000000000 +110110-------------------------------------------- +0000000000000000000100000000 00000000000000000000000000000000000000000 +111111----------------------0--------------------- +0111110000000000000000000000 00000000000000000000000000000000000000000 +0---------------------------0--------------------- +0111110000000000000000000000 00000000000000000000000000000000000000000 +101011----00----------------0--------------------- +0100110000000000000000000010 10000000000000000000000000000000001000000 +101100----01--101-----------0--------------------- +0000000000101000000000000011 10000000000000000000000000000000000000000 +101100----------------------0--------------1------ +0000000000000000000000000000 00000000000000100000000000000000000000000 +100001--------0111----------0--------------------- +0000000000000000000000000000 00000000000000000000000100000000000000000 +100001----------------------0--------------1------ +0000000000000000000000000000 00000000000000100000000000000000000000000 +100001------0---------------0--------------------- +0001010000000000000000000000 00000000000000000000000001000000000000100 +100001------1---------------0--------------------- +0001010000000000000000000000 00000000000000000000000000100000000000100 +100001----00---000-------------------------------- +0000000000000000000000000010 10000000000000000000000000000000000000000 +100001----01---000-------------------------------- +0000000000000000000000000001 10000000000000000000000000000000000000000 +111010--------0101----------0--------------------- +0001110000000000000000000000 00000000000000000000000000000000000000000 +111010------0---------------0--------------------- +0001000000000000000000000000 00000000000000000000000001000000000000000 +111010------1---------------0--------------------- +0001000000000000000000000000 00100000000000000000000000100000000000000 +11101---------0111----------0--------------------- +0000000000000000000000000000 00000000000000000000000100000000000000000 +11101-----------------------0--------------1------ +0000000000000000000000000000 00000000000000100000000000000000000000000 +111000----------------------0--------------------- +0001100000000000000000000000 01100000000000000000000000000000000000101 +111000----------------------0--------------1------ +0000000000000000000000000000 00000000000000100000000000000000000000000 +111001----------------------0--------------------- +0000110000100010000000000000 00000000000000000000000000000000000000001 +111001---------------01-001-0--------------------- +0000000000100100000000000000 00000000000000000000000000000000000000000 +111001----------------------0--------------1------ +0000000000000000000000000000 00000000000000100000000000000000000000000 +111011----------------------0--------------------- +0110110000000000000000000000 00000000000000000000000000000000000000101 +100100----------------------0--------------1------ +0000000000000000000000000000 00000000000000100100000000000000000000000 +100100--------011-----------0--------------------- +0000000000110100000000000000 00000001000000000000000000000000000000001 +100100--------0111----------0--------------------- +0000000000000000000000000000 00000000000000000000000100000000000000000 +100100--------0000--0-------0--------------------- +0000000000111100000000000000 00000000000000000000000000000000000000001 +100100--------0000----------0-------------------0- +0000000000000000000000000000 00000000000000000000000000000100000000000 +100100--------0000--1-------0--------------------- +0000000000010000000000000000 00000000000000000000000000000000000000001 +100100--------1000----------0----------------0---- +0000000000111000000000000000 00000000000000000000000000000000000000001 +100100--------1000----------0----------------1---- +0000000000000000000000000000 00000000000000000000000000000000000000001 +100100--------1001----------0--------------------- +0000000000000100000000000000 00000000000000000000000000000000000000001 +100101------0---------------0--------------------- +0110010000000000000000000000 00000000000000100000000001000000000000100 +100101------1---------------0--------------------- +0110010000000000000000000000 00000000000000100000000000100000000000100 +100110------0---------------0--------------------- +0110000000000000000000000000 00000000000000110000000011000000000000000 +100110------1---------------0--------------------- +0110000000000000000000000000 00100000000000110000000010100000000000000 +100110----------------------0---------------0----- +0000000000000000000000000000 00000000000000000000000000000010000010000 +100111----------------------0--------------------- +0101110000000000000000000000 00000000000000110000000001000000000000101 +100111----------------------0---------------1----- +0000000000000000000000000000 00000000000000000001000000000100000000000 +101000----------------------0--------------------- +0000000000011000000000000000 00000000000000100000000001000000000000001 +101001----------------------0---------01-0-------- +0110100100000010000000000000 00000000000000100000000000000000000000000 +101001----------------------0---------01-1-------- +0100100000000000000000000000 00000000000000100000000000000000000000000 +101001----------------------0---------1----------- +0000000000000010000000000000 00000000000010100000000000000000000000000 +101001----------------------0---------00---------- +0101100000000000000000000000 00000000000000100000000000000000000000000 +101010----------------------0----------1---------- +0110100100000010000000000000 00000000000000100000000000000000000000000 +101010----------------------0----------0---------- +0101100000000000000000000000 00000000000000100000000000000000000000000 +101101----------------------0--------------------- +0101010000000000000000000000 00000000000000100000000000000000000000000 +101110----------------------0--------------------- +0100100000000000000000000000 00000000000000100000000000000000000000000 +101111----------------------0--------------------- +0011110000000000000000000000 00000000000000100000000000000000000000000 +110000----------------------0----------1-0-------- +0110100100000010000000000000 00000000000000100000000000000000000000000 +110000----------------------0----------1-1-------- +0101010000000000000000000000 00000000000000100000000000000000000000000 +110000----------------------0----------0---------- +0101100000000000000000000000 00000000000000100000000000000000000000000 +110001----------------------0--------------------- +0100100000000000000000000000 00000000000000100000000000000000000000000 +110111----------------------0--------------------- +0110100100000010000000000000 00000000000000100000000000000000000000000 +110011----------------------0--------------------- +0111100011000010000000000011 10000000000000000000000010000000010001000 +111100----------------------0--------------------- +0100110000000000000000000000 00000000000000000000000000000000000000000 +111100----------------------0--------------1------ +0000000000000000000000000000 00000000000000100000000000000000000000000 diff --git a/espresso/examples/indust/al2 b/espresso/examples/indust/al2 new file mode 100644 index 0000000..11acefe --- /dev/null +++ b/espresso/examples/indust/al2 @@ -0,0 +1,105 @@ +.i 16 +.o 47 +00001-----------|10000000000000000000000000000000000000000000000 +0000-1----------|10000000000000000000000000000000000000000000000 +------1---------|10000000000000000000000000000000000000000000000 +00011-0---------|01000000000000000000000000000000000000000000000 +0001-10---------|01000000000000000000000000000000000000000000000 +00101-0---------|00100000000000000000000000000000000000000000000 +0010-10---------|00100000000000000000000000000000000000000000000 +00111-0---------|00010000000000000000000000000000000000000000000 +0011-10---------|00010000000000000000000000000000000000000000000 +01001-0---------|00001000000000000000000000000000000000000000000 +0100-10---------|00001000000000000000000000000000000000000000000 +01011-0---------|00000100000000000000000000000000000000000000000 +0101-10---------|00000100000000000000000000000000000000000000000 +01101-0---------|00000010000000000000000000000000000000000000000 +0110-10---------|00000010000000000000000000000000000000000000000 +01111-0---------|00000001000000000000000000000000000000000000000 +0111-10---------|00000001000000000000000000000000000000000000000 +-------10001----|00000000100000000000000000000000000000000000000 +01001-0---------|00000000010000000000000000000000000000000000000 +0100-10---------|00000000010000000000000000000000000000000000000 +01011-0---------|00000000010000000000000000000000000000000000000 +0101-10---------|00000000010000000000000000000000000000000000000 +00101-0---------|00000000001000000000000000000000000000000000000 +0010-10---------|00000000001000000000000000000000000000000000000 +00111-0---------|00000000001000000000000000000000000000000000000 +0011-10---------|00000000001000000000000000000000000000000000000 +01101-0---------|00000000001000000000000000000000000000000000000 +0110-10---------|00000000001000000000000000000000000000000000000 +00101-0---------|00000000000100000000000000000000000000000000000 +0010-10---------|00000000000100000000000000000000000000000000000 +00111-0---------|00000000000100000000000000000000000000000000000 +0011-10---------|00000000000100000000000000000000000000000000000 +01001-0---------|00000000000100000000000000000000000000000000000 +0100-10---------|00000000000100000000000000000000000000000000000 +01011-0---------|00000000000100000000000000000000000000000000000 +0101-10---------|00000000000100000000000000000000000000000000000 +-------10001----|00000000000100000000000000000000000000000000000 +00011-0---------|00000000000010000000000000000000000000000000000 +0001-10---------|00000000000010000000000000000000000000000000000 +00111-0---------|00000000000010000000000000000000000000000000000 +0011-10---------|00000000000010000000000000000000000000000000000 +01011-0---------|00000000000010000000000000000000000000000000000 +0101-10---------|00000000000010000000000000000000000000000000000 +00011-0---------|00000000000001000000000000000000000000000000000 +0001-10---------|00000000000001000000000000000000000000000000000 +00101-0---------|00000000000001000000000000000000000000000000000 +0010-10---------|00000000000001000000000000000000000000000000000 +00111-0---------|00000000000001000000000000000000000000000000000 +0011-10---------|00000000000001000000000000000000000000000000000 +01001-0---------|00000000000001000000000000000000000000000000000 +0100-10---------|00000000000001000000000000000000000000000000000 +01011-0---------|00000000000001000000000000000000000000000000000 +0101-10---------|00000000000001000000000000000000000000000000000 +01101-0---------|00000000000000100000000000000000000000000000000 +0110-10---------|00000000000000100000000000000000000000000000000 +------------0000|00000000000000010000000000000000000000000000000 +------------0001|00000000000000001000000000000000000000000000000 +------------0010|00000000000000000100000000000000000000000000000 +------------0011|00000000000000000010000000000000000000000000000 +------------0100|00000000000000000001000000000000000000000000000 +------------0101|00000000000000000000100000000000000000000000000 +------------0110|00000000000000000000010000000000000000000000000 +------------0111|00000000000000000000001000000000000000000000000 +------------1000|00000000000000000000000100000000000000000000000 +------------1001|00000000000000000000000010000000000000000000000 +------------1010|00000000000000000000000001000000000000000000000 +------------1011|00000000000000000000000000100000000000000000000 +------------1100|00000000000000000000000000010000000000000000000 +------------1101|00000000000000000000000000001000000000000000000 +------------1110|00000000000000000000000000000100000000000000000 +------------1111|00000000000000000000000000000010000000000000000 +----1---0000----|00000000000000000000000000000001000000000000000 +-----1--0000----|00000000000000000000000000000001000000000000000 +----1---0001----|00000000000000000000000000000000100000000000000 +-----1--0001----|00000000000000000000000000000000100000000000000 +----1---0010----|00000000000000000000000000000000010000000000000 +-----1--0010----|00000000000000000000000000000000010000000000000 +----1---0011----|00000000000000000000000000000000001000000000000 +-----1--0011----|00000000000000000000000000000000001000000000000 +----1---0100----|00000000000000000000000000000000000100000000000 +-----1--0100----|00000000000000000000000000000000000100000000000 +----1---0101----|00000000000000000000000000000000000010000000000 +-----1--0101----|00000000000000000000000000000000000010000000000 +----1---0110----|00000000000000000000000000000000000001000000000 +-----1--0110----|00000000000000000000000000000000000001000000000 +----1---0111----|00000000000000000000000000000000000000100000000 +-----1--0111----|00000000000000000000000000000000000000100000000 +----1---1000----|00000000000000000000000000000000000000010000000 +-----1--1000----|00000000000000000000000000000000000000010000000 +----1---1001----|00000000000000000000000000000000000000001000000 +-----1--1001----|00000000000000000000000000000000000000001000000 +----1---1010----|00000000000000000000000000000000000000000100000 +-----1--1010----|00000000000000000000000000000000000000000100000 +----1---1011----|00000000000000000000000000000000000000000010000 +-----1--1011----|00000000000000000000000000000000000000000010000 +----1---1100----|00000000000000000000000000000000000000000001000 +-----1--1100----|00000000000000000000000000000000000000000001000 +----1---1101----|00000000000000000000000000000000000000000000100 +-----1--1101----|00000000000000000000000000000000000000000000100 +----1---1110----|00000000000000000000000000000000000000000000010 +-----1--1110----|00000000000000000000000000000000000000000000010 +----1---1111----|00000000000000000000000000000000000000000000001 +-----1--1111----|00000000000000000000000000000000000000000000001 diff --git a/espresso/examples/indust/alcom b/espresso/examples/indust/alcom new file mode 100644 index 0000000..dddced6 --- /dev/null +++ b/espresso/examples/indust/alcom @@ -0,0 +1,49 @@ +.i 15 +.o 38 +10010----------|10000000000000000000000000000000000000 +10110----------|10100000000000000000000000000000000000 +01010----------|01000000000000000000000000000000000000 +11010----------|01001000000000000000000000000000000000 +00110----------|00100000000000000000000000000000000000 +01110----------|00100000000000000000000000000000000000 +1---0----------|00010000000000000000000000000000000000 +01--0----------|00010100000000000000000000000000000000 +00100----------|00010000000000000000000000000000000000 +00000----------|00010100000000000000000000000000000000 +1----11--------|00010000000000000000000000000000000000 +10--0----------|00000100000000000000000000000000000000 +111-0----------|00000100000000000000000000000000000000 +11000----------|00000100000000000000000000000000000000 +001-0----------|00000100000000000000000000000000000000 +-------0000----|00000010000000000000000000000000000000 +-------0001----|00000001000000000000000000000000000000 +-------0010----|00000000100000000000000000000000000000 +-------0011----|00000000010000000000000000000000000000 +-------0101----|00000000001000000000000000000000000000 +-------0100----|00000000000100000000000000000000000000 +-------0111----|00000000000010000000000000000000000000 +-------1000----|00000000000001000000000000000000000000 +-------1001----|00000000000000100000000000000000000000 +-------1010----|00000000000000010000000000000000000000 +-------1011----|00000000000000001000000000000000000000 +-------1100----|00000000000000000100000000000000000000 +-------1101----|00000000000000000010000000000000000000 +-------1110----|00000000000000000001000000000000000000 +-------1111----|00000000000000000000100000000000000000 +---1-------0000|00000000000000000000010000000000000000 +---1-------0001|00000000000000000000001000000000000000 +---1-------0010|00000000000000000000000100000000000000 +---1-------0011|00000000000000000000000010000000000000 +---1-------0100|00000000000000000000000001000000000000 +---1-------0101|00000000000000000000000000100000000000 +---1-------0110|00000000000000000000000000010000000000 +---1-------0111|00000000000000000000000000001000000000 +---1-------1000|00000000000000000000000000000100000000 +---1-------1001|00000000000000000000000000000010000000 +---1-------1010|00000000000000000000000000000001000000 +---1-------1011|00000000000000000000000000000000100000 +---1-------1100|00000000000000000000000000000000010000 +-------0110----|00000000000000000000000000000000001000 +---1-------1101|00000000000000000000000000000000000100 +---1-------1110|00000000000000000000000000000000000010 +---1-------1111|00000000000000000000000000000000000001 diff --git a/espresso/examples/indust/alu1 b/espresso/examples/indust/alu1 new file mode 100644 index 0000000..ea938a9 --- /dev/null +++ b/espresso/examples/indust/alu1 @@ -0,0 +1,21 @@ +.i 12 +.o 8 +----1------0 10000000 +----0-----0- 10000000 +0----------- 10000000 +-----1-----0 01000000 +-----0----0- 01000000 +-0---------- 01000000 +------1----0 00100000 +------0---0- 00100000 +--0--------- 00100000 +-------1---0 00010000 +-------0--0- 00010000 +---0-------- 00010000 +0---1---0--- 00001000 +0---0----0-- 00001000 +-0---1--0--- 00000100 +-0---0---0-- 00000100 +--0---1-0--- 00000010 +--0---0--0-- 00000010 +---0---10--- 00000001 diff --git a/espresso/examples/indust/alu2 b/espresso/examples/indust/alu2 new file mode 100644 index 0000000..b31c87a --- /dev/null +++ b/espresso/examples/indust/alu2 @@ -0,0 +1,93 @@ +.i 10 +.o 8 +0-0---0--- 10000000 +-10---0--- 10000000 +0-1---1--- 10000000 +-11---1--- 10000000 +101---0--- 10000000 +0--0--00-- 01000000 +--00--00-- 01000000 +0--1--01-- 01000000 +--01--01-- 01000000 +-110---0-- 01000000 +-111---1-- 01000000 +-011--10-- 01000000 +1011---0-- 01000000 +0---0-000- 00100000 +--0-0-000- 00100000 +0---1-001- 00100000 +--0-1-001- 00100000 +-1110---0- 00100000 +-1111---1- 00100000 +-1-10-0-0- 00100000 +-1-11-0-1- 00100000 +--100--00- 00100000 +--101--01- 00100000 +10111---0- 00100000 +-0111-1-0- 00100000 +-0-11-010- 00100000 +-100000000 00010000 +-101000100 00010000 +-110001000 00010000 +-111001100 00010000 +-100100010 00010000 +-101100110 00010000 +-110101010 00010000 +-111101110 00010000 +0-00000000 00010000 +-100010001 00010000 +-101010101 00010000 +-110011001 00010000 +-111011101 00010000 +-100110011 00010000 +-101110111 00010000 +-110111011 00010000 +-111111111 00010000 +0-00010001 00010000 +0000110010 00010000 +0001110100 00010000 +0011111000 00010000 +1011110000 00010000 +---------1 00001000 +----0---1- 00001000 +-----1--1- 00001000 +---0---1-- 00001000 +----11-1-- 00001000 +---1111--- 00001000 +1-1111---- 00001000 +-11110---0 00000100 +-11111---1 00000100 +-1-1100--0 00000100 +-1-1110--1 00000100 +-11-10-0-0 00000100 +-11-11-0-1 00000100 +-1--1000-0 00000100 +-1--1100-1 00000100 +0----00000 00000100 +--0--00000 00000100 +0----10001 00000100 +--0--10001 00000100 +--1100--00 00000100 +--1101--01 00000100 +---1000-00 00000100 +---1010-01 00000100 +--10-0-000 00000100 +--10-1-001 00000100 +-01-11-010 00000100 +-0--110010 00000100 +101111---0 00000100 +-011111--0 00000100 +-0-11101-0 00000100 +---110---0 00000010 +----10-0-0 00000010 +---0---000 00000010 +------0000 00000010 +---10---00 00000010 +--0------- 00000001 +---0------ 00000001 +----0----- 00000001 +-----0---- 00000001 +--0---1--- 22222222 +---0---1-- 22222222 +----0---1- 22222222 +-----0---1 22222222 diff --git a/espresso/examples/indust/alu3 b/espresso/examples/indust/alu3 new file mode 100644 index 0000000..78e364c --- /dev/null +++ b/espresso/examples/indust/alu3 @@ -0,0 +1,74 @@ +.i 10 +.o 8 +0000-1--10 00010000 +000-11-100 00010000 +00-1111000 00010000 +0-0000---- 00010000 +0-000----1 00010000 +0-0------- 10000000 +0--0--0--- 01000000 +0---1-000- 00100000 +0----10000 00000100 +0-----01-- 01000000 +0-----1--- 10000000 +10110----- 00100000 +101110---- 00000100 +1011110000 00010000 +10111----1 00000100 +1011---0-- 01000000 +1011----1- 00100000 +101---0--- 10000000 +1-1111---- 00001000 +-0-10-1--- 00100000 +-0-1101--- 00000100 +-0-11-1--1 00000100 +-0-1--10-- 01000000 +-0-1--1-1- 00100000 +-0--0--1-- 00100000 +-0--10-1-- 00000100 +-0--1--1-1 00000100 +-0---0--1- 00000100 +-0-----11- 00100000 +-0------11 00000100 +-10000---- 00010000 +-1000----1 00010000 +-100-0--1- 00010000 +-100----11 00010000 +-10-00-1-- 00010000 +-10-0--1-1 00010000 +-10--0-11- 00010000 +-10----111 00010000 +-10------- 10000000 +-1-0001--- 00010000 +-1-00-1--1 00010000 +-1-0-01-1- 00010000 +-1-0--1-11 00010000 +-1-0------ 01000000 +-1--0011-- 00010000 +-1--0-11-1 00010000 +-1--1---0- 00100000 +-1---0111- 00010000 +-1---1---0 00000100 +-1----1111 00010000 +-1----1--- 10000000 +-1-----1-- 01000000 +--00------ 01000000 +--0-1--00- 00100000 +--0--1-000 00000100 +--0---1--- 22222222 +--0----1-- 01000000 +--1111---- 00000001 +---01---0- 00100000 +---0-1--00 00000100 +---0---1-- 22222222 +---0----00 00000010 +---1111--- 00001000 +----01---0 00000100 +----0---1- 22222222 +----0----0 00000010 +----11-1-- 00001000 +-----0---1 22222222 +-----0---- 00000010 +-----1--1- 00001000 +------0000 00000010 +---------1 00001000 diff --git a/espresso/examples/indust/amd b/espresso/examples/indust/amd new file mode 100644 index 0000000..95eacef --- /dev/null +++ b/espresso/examples/indust/amd @@ -0,0 +1,193 @@ +.i 14 +.o 24 +---0----- 00000 00000 0000000000000000000 +---100--0 00000 00101 1000000000000011000 +---1-1--- 00000 00000 0000000000000000000 +---110--0 00000 00000 1000000000000000000 +---100--1 00000 10001 1000000101000100001 +-----0--- 10100 11001 0000010101000110001 +---110--1 00000 10001 1000000101000100001 +-----00-- 10001 10001 0000000101000100001 +-----1--- 10100 00000 0000000000000000000 +-----00-- 10011 11001 0000000101000110001 +-----10-- 10001 00000 0000000000000000000 +-----01-- 10001 00001 0000000000000000001 +-----10-- 10011 00000 0000000000000000000 +----001-- 10011 01001 0000000000000010001 +---0-11-- 10001 11110 0000000110000100001 +------00- 10000 00000 0000000000000000000 +---0-11-- 10011 11110 0000000110000100001 +----101-- 10011 11100 0000000000000000001 +------00- 10010 00000 0000000000000000000 +---1-11-- 10001 01110 0000000110000100001 +------00- 01111 00000 0000000000000000000 +0----010- 10000 00001 0000000000000000001 +------01- 10000 00000 0010000000000000000 +---1-11-- 10011 01110 0000000110000100001 +------00- 00111 00000 0000000000000000000 +0---0010- 10010 01001 0000000000000010001 +------01- 10010 00000 0010000000000000000 +------00- 01110 00000 0000000000000000000 +-0-0--10- 01111 11110 0000000000000000001 +------01- 01111 00000 0010000000000000000 +0----011- 10000 00001 0010000000000000001 +---0-110- 10000 11110 0000000110000100001 +1---0010- 10000 11000 0000001000010110101 +0----010- 00111 11100 0000000000000000001 +------01- 00111 00000 0010000000000000000 +0---0011- 10010 01001 0010000000000010001 +---0-110- 10010 11110 0000000110000100001 +1-0-0010- 10010 10100 0000011000001110101 +0---1010- 10010 11100 0000000000000000001 +-0----10- 01110 01110 0000000000000000001 +------01- 01110 00000 0010000000000000000 +-0-0--11- 01111 11110 0010000000000000001 +-1----10- 01111 10110 0000000000000000000 +-0-1--10- 01111 01110 0000000000000000001 +---0-111- 10000 11110 0010000110000100001 +1---0011- 10000 11000 0010001000010110101 +---1-110- 10000 01110 0000000110000100001 +1---1010- 10000 01000 0000001000010100101 +------00- 00011 00000 0000000000000000000 +0----011- 00111 11100 0010000000000000001 +---0-110- 00111 11110 0000000110000100001 +1-0--010- 00111 00100 0000001000001100101 +---0-111- 10010 11110 0010000110000100001 +1-0-0011- 10010 10100 0010011000001110101 +0---1011- 10010 11100 0010000000000000001 +---1-110- 10010 01110 0000000110000100001 +1-1-0010- 10010 10100 0100011000001110101 +1-0-1010- 10010 01100 0000011000001100101 +------00- 00101 00000 0000000000000000000 +-0----11- 01110 01110 0010000000000000001 +-1----10- 01110 00110 0000000000000000000 +-1----11- 01111 10110 0010000000000000000 +-0-1--11- 01111 01110 0010000000000000001 +------0-- 01101 00000 0001000000000000000 +---1-111- 10000 01110 0010000110000100001 +1---1011- 10000 01000 0010001000010100101 +------00- 00010 00000 0000000000000000000 +0----010- 00011 11000 0000000000000010101 +------01- 00011 00000 0010000000000000000 +---0-111- 00111 11110 0010000110000100001 +1-0--011- 00111 00100 0010001000001100101 +---1-110- 00111 01110 0000000110000100001 +1-1--010- 00111 00100 0100001000001100101 +------00- 00100 00000 0000000000000000000 +---1-111- 10010 01110 0010000110000100001 +1-1-0011- 10010 10100 0110011000001110101 +1-0-1011- 10010 01100 0010011000001100101 +1-1-1010- 10010 01100 0100011000001100101 +------00- 00110 00000 0000000000000000000 +0----010- 00101 10100 0000000000000010101 +------01- 00101 00000 0010000000000000000 +-1----11- 01110 00110 0010000000000000000 +----000-0 01100 00101 1000000000000011000 +------1-- 01101 10110 0000000000000000000 +0----010- 00010 01000 0000000000000000101 +------01- 00010 00000 0010000000000000000 +0----011- 00011 11000 0010000000000010101 +---0-110- 00011 11110 0000000110000100001 +1---0010- 00011 10000 0000010000100110101 +---1-111- 00111 01110 0010000110000100001 +1-1--011- 00111 00100 0110001000001100101 +0----010- 00100 00100 0000000000000000101 +------01- 00100 00000 0010000000000000000 +1-1-1011- 10010 01100 0110011000001100101 +0----010- 00110 01100 0000000000000000101 +------01- 00110 00000 0010000000000000000 +0----011- 00101 10100 0010000000000010101 +---0-110- 00101 11110 0000000110000100001 +1-0-0010- 00101 10100 0000010000001110101 +------1-- 01100 00110 0000000000000000000 +-----10-- 01100 00000 0000000000000000000 +----100-0 01100 00000 1000000000000000000 +----000-1 01100 10001 1000000101000100001 +0----011- 00010 01000 0010000000000000101 +---0-110- 00010 11110 0000000110000100001 +1----010- 00010 00100 0000000000100100101 +---0-111- 00011 11110 0010000110000100001 +1---0011- 00011 10000 0010010000100110101 +---1-110- 00011 01110 0000000110000100001 +1---1010- 00011 01100 0000010000100100101 +------00- 00001 00000 0000000000000000000 +0----011- 00100 00100 0010000000000000101 +---0-110- 00100 11110 0000000110000100001 +1----010- 00100 10010 0000000000000000111 +0----011- 00110 01100 0010000000000000101 +---0-110- 00110 11110 0000000110000100001 +1-0--010- 00110 00100 0000000000001100101 +---0-111- 00101 11110 0010000110000100001 +1-0-0011- 00101 10100 0010010000001110101 +---1-110- 00101 01110 0000000110000100001 +1-1-0010- 00101 10100 0100010000001110101 +1-0-1010- 00101 01100 0000010000001100101 +----100-1 01100 10001 1000000101000100001 +---0-111- 00010 11110 0010000110000100001 +1----011- 00010 00100 0010000000100100101 +---1-110- 00010 01110 0000000110000100001 +---1-111- 00011 01110 0010000110000100001 +1---1011- 00011 01100 0010010000100100101 +0----010- 00001 10000 0000000000000010101 +------01- 00001 00000 0010000000000000000 +---0-111- 00100 11110 0010000110000100001 +1----011- 00100 10010 0010000000000000111 +---1-110- 00100 01110 0000000110000100001 +------00- 01001 00000 0000000000000000000 +---0-111- 00110 11110 0010000110000100001 +1-0--011- 00110 00100 0010000000001100101 +---1-110- 00110 01110 0000000110000100001 +1-1--010- 00110 00100 0100000000001100101 +---1-111- 00101 01110 0010000110000100001 +1-1-0011- 00101 10100 0110010000001110101 +1-0-1011- 00101 01100 0010010000001100101 +1-1-1010- 00101 01100 0100010000001100101 +---1-111- 00010 01110 0010000110000100001 +0----011- 00001 10000 0010000000000010101 +---0-110- 00001 11110 0000000110000100001 +1-0-0010- 00001 10100 0000010000001110101 +---1-111- 00100 01110 0010000110000100001 +0----010- 01001 10010 0000000000000000111 +------01- 01001 00000 0010000000000000000 +---1-111- 00110 01110 0010000110000100001 +1-1--011- 00110 00100 0110000000001100101 +1-1-1011- 00101 01100 0110010000001100101 +---0-111- 00001 11110 0010000110000100001 +1-0-0011- 00001 10100 0010010000001110101 +---1-110- 00001 01110 0000000110000100001 +1-1-0010- 00001 10100 0100010000001110101 +1-0-1010- 00001 01100 0000010000001100101 +0----011- 01001 10010 0010000000000000111 +---0-110- 01001 11110 0000000110000100001 +1----010- 01001 00010 0000000000000000111 +---1-111- 00001 01110 0010000110000100001 +1-1-0011- 00001 10100 0110010000001110101 +1-0-1011- 00001 01100 0010010000001100101 +1-1-1010- 00001 01100 0100010000001100101 +---0-111- 01001 11110 0010000110000100001 +1----011- 01001 00010 0010000000000000111 +---1-110- 01001 01110 0000000110000100001 +------00- 01000 00000 0000000000000000000 +1-1-1011- 00001 01100 0110010000001100101 +---1-111- 01001 01110 0010000110000100001 +0----010- 01000 00010 0000000000000000111 +------01- 01000 00000 0010000000000000000 +0----011- 01000 00010 0010000000000000111 +---0-110- 01000 11110 0000000110000100001 +1----010- 01000 01010 0000000001000100001 +---0-111- 01000 11110 0010000110000100001 +1----011- 01000 01010 0010000001000100001 +---1-110- 01000 01110 0000000110000100001 +------00- 01010 00000 0000000000000000000 +---1-111- 01000 01110 0010000110000100001 +0----010- 01010 01010 0000000000000000001 +------01- 01010 00000 0010000000000000000 +0----011- 01010 01010 0010000000000000001 +---0-110- 01010 11110 0000000110000100001 +1----010- 01010 11010 0000000000000000000 +---0-111- 01010 11110 0010000110000100001 +1----011- 01010 11010 0010000000000000000 +---1-110- 01010 01110 0000000110000100001 +------0-- 01011 00000 0000100000000000000 +---1-111- 01010 01110 0010000110000100001 +------1-- 01011 11010 0000000000000000000 diff --git a/espresso/examples/indust/apla b/espresso/examples/indust/apla new file mode 100644 index 0000000..3dfbdcd --- /dev/null +++ b/espresso/examples/indust/apla @@ -0,0 +1,136 @@ +.i 10 +.o 12 +0100000000 100000000000 +0000100000 100000000000 +0000010000 100000000000 +1000000000 001000000000 +0010000000 001000000000 +0001000000 001000000000 +0000001000 001000000000 +1000000000 000000000010 +0001000000 000000000010 +0100000000 000000001001 +0000100000 000000001001 +0000010000 000000001001 +0010000000 000000010010 +0000001000 000000010010 +0100000001 010000000000 +0000100001 010000000000 +0000010001 010000000000 +1000000001 000100000000 +0010000001 000100000000 +0001000001 000100000000 +0000001001 000100000000 +1000000001 000000000010 +0001000001 000000000010 +0100000001 000000001001 +0000100001 000000001001 +0000010001 000000001001 +0010000001 000000010010 +0000001001 000000010010 +0000100010 100000000000 +0000010010 100000000000 +0000001010 100000000000 +1000000010 001000000000 +0100000010 001000000000 +0010000010 001000000000 +0001000010 001000000000 +0100000010 000000000100 +0001000010 000000000100 +1000000010 000000001010 +0010000010 000000001010 +0000100010 000000010001 +0000010010 000000010001 +0000001010 000000010001 +0000100011 100000000000 +0000010011 100000000000 +0000001011 100000000000 +1000000011 000100000000 +0010000011 000100000000 +0100000011 000010000000 +0001000011 000010000000 +0100000011 000000000100 +0001000011 000000000100 +1000000011 000000001010 +0010000011 000000001010 +0000100011 000000010101 +0000010011 000000010101 +0000001011 000000010101 +0100000100 010000000000 +0000100100 010000000000 +1000000100 001000000000 +0010000100 001000000000 +0001000100 001000000000 +0000010100 001000000000 +0000001100 001000000000 +0100000100 000000000101 +0000100100 000000000101 +1000000100 000000001000 +0010000100 000000001000 +0001000100 000000010100 +0000010100 000000010100 +0000001100 000000010100 +0100000101 100000000000 +0000100101 100000000000 +1000000101 000010000000 +0010000101 000010000000 +0001000101 000010000000 +0000010101 000010000000 +0000001101 000010000000 +1000000101 000000000010 +0001000101 000000000010 +0100000101 000000000101 +0000100101 000000000101 +0010000101 000000010010 +0000001101 000000010010 +0000010101 000000010100 +0100000110 100000000000 +0000100110 010000000000 +0000010110 010000000000 +0000001110 010000000000 +1000000110 000010000000 +0010000110 000010000000 +0001000110 000010000000 +0100000110 000000000001 +1000000110 000000001010 +0010000110 000000001010 +0000100110 000000010001 +0000010110 000000010001 +0000001110 000000010001 +0001000110 000000010100 +0100000111 010000000000 +0000100111 010000000000 +0000010111 010000000000 +0000001111 010000000000 +1000000111 000001000000 +0010000111 000001000000 +0001000111 000000100000 +0100000111 000000000001 +1000000111 000000001000 +0010000111 000000001000 +0001000111 000000010000 +0000100111 000000010101 +0000010111 000000010101 +0000001111 000000010101 +11-------- 222222222222 +1-1------- 222222222222 +1--1------ 222222222222 +1---1----- 222222222222 +1----1---- 222222222222 +1-----1--- 222222222222 +0000000--- 222222222222 +-11------- 222222222222 +-1-1------ 222222222222 +-1--1----- 222222222222 +-1---1---- 222222222222 +-1----1--- 222222222222 +--11------ 222222222222 +--1-1----- 222222222222 +--1--1---- 222222222222 +--1---1--- 222222222222 +---11----- 222222222222 +---1-1---- 222222222222 +---1--1--- 222222222222 +----11---- 222222222222 +----1-1--- 222222222222 +-----11--- 222222222222 diff --git a/espresso/examples/indust/b10 b/espresso/examples/indust/b10 new file mode 100644 index 0000000..d1b81cd --- /dev/null +++ b/espresso/examples/indust/b10 @@ -0,0 +1,140 @@ +.i 15 +.o 11 +00---0---00000- -01---01000 +00---100-00000- -1100101010 +00---101-00000- -1100101011 +000--110-00000- -1001000000 +000-0111-00000- -1001000000 +00011111-00000- -1001000000 +001--111-00000- -1000000000 +010------00000- -1010100000 +01110000-00000- -1000000110 +01110111-00000- -1000000110 +01110-01-00000- -1000010110 +0111001--00000- -1000010110 +011101-0-00000- -1000010110 +01111----00000- -1000010110 +100000-0-00000- -0100001000 +10000001-00000- -0100001001 +10000011-00000- -0100001001 +1000-1---00000- -0100101000 +100010---00000- -0100001000 +10010----00000- -1010000000 +1001100--00000- -1000000000 +10011010-00000- -1000010011 +10011011-00000- -1000000000 +100111---00000- -1000000000 +101000---00000- -1100000010 +1010-1---00000- -1100000000 +1010101--00000- -1100000000 +10101000-00000- -1100101010 +10101001-00000- -1100101011 +10110----00000- -1110001010 +10111----00000- -1110001011 +1100000--00000- -0100001000 +1100-010-00000- -1000011011 +1100-011-00000- -1000010000 +1100010--00000- -0000001000 +11000110-00000- -0100001000 +11000111-00000- -0100001001 +11001000-00000- -1000000010 +11001001-00000- -1000000000 +11001100-00000- -1000010000 +11001010-00000- -1000011010 +1100111--00000- -1000010000 +11011----00000- -0000001000 +110100---00000- -0100001110 +1101010--00000- -1000001010 +1101011--00000- -1100000000 +1110000--00000- -1000010110 +11100010-00000- -1000010110 +11100011-00000- -1000010110 +111001---00000- -1100001010 +1110100--00000- -1000010010 +11101010-00000- -1000010011 +11101011-00000- -1000010110 +-11011---00000- -1100000000 +1111-10--00000- -1000100000 +111110---00000- -1000100000 +11110110-00000- -0100000001 +11110111-00000- -0100000001 +1111111--00000- -0100001110 +0110100--00000- -1000000000 +0110101--00000- -0000001000 +01100000-00000- -1000001011 +01100010-00000- -1000001011 +01100001-00000- -0000001001 +01100011-00000- -0000001001 +11000----000010 -1010101010 +01000----000010 -1010100110 +10000----000010 -1010100010 +00000---0000010 -1010101010 +00000---1000010 -1010100010 +--001----00001- -1000000000 +1101-----00001- -1010100000 +0101-----00001- -1010100110 +1001-----00001- -1010100010 +0001----000001- -1010100000 +0001----100001- -1010100010 +111------00001- -1010000000 +011------00001- -1010000110 +101------00001- -1010000010 +001-----000001- -1010000000 +001-----100001- -1010000010 +11000----000011 -1010101011 +01000----000011 -1010100111 +10000----000011 -1010100011 +00000---0000011 -1010101011 +00000---1000011 -1010100011 +--01-----011101 -0000010000 +--10-----011101 -0000010000 +11-------11110- -1010100000 +01-------11110- -1010100110 +10-------11110- -1010100010 +00------011110- -1010100000 +00------111110- -1010100110 +11-------110000 -1011000000 +01-------110000 -1011000110 +10-------110000 -1011000010 +00------0110000 -1011000000 +00------1110000 -1011000010 +11--------10001 -1010101010 +01--------10001 -1010100110 +1000------10001 -1010100010 +00------0-10001 -1010101010 +00------1-10001 -1010100010 +11--------10010 -1011101011 +01--------10010 -1011100111 +10--------10010 -1011100011 +00------0-10010 -1011101011 +00------1-10010 -1011100011 +11--------10011 -1011101011 +01--------10011 -1011100111 +10--------10011 -1011100011 +00------0-10011 -1011101011 +00------1-10011 -1011100011 +----------00100 -0000000100 +----------00101 -0000000100 +----------00110 -0000000101 +----------00111 -0000000101 +-----------1000 -0000000000 +-----------1001 -0000001010 +-----------1010 -0000001011 +-----------1011 -0000001011 +----------01100 -0000001100 +----------01101 -0000001100 +----------01110 -0000001101 +----------01111 -0000001101 +----------1010- -0000000000 +----------10110 -0000001111 +----------10111 -0000001111 +----------1111- -0000000000 +000000---10000- -0000001000 +0000010--10000- -1000010000 +00000110-10000- -1000000000 +00000111-10000- -0000001000 +00001----10000- -1000001000 +0001-----10000- -1000001000 +001------10000- -1000001000 +01-------10000- -1000001000 +1--------10000- -1000001000 diff --git a/espresso/examples/indust/b11 b/espresso/examples/indust/b11 new file mode 100644 index 0000000..1b4473a --- /dev/null +++ b/espresso/examples/indust/b11 @@ -0,0 +1,76 @@ +.i 8 +.o 31 +00000--- -000010000000001000100000000000 +00001--- -000010000000001000000000000000 +0001---- -000010000000001000010000000000 +--1-0--- -000000000000000100000000000000 +0010-0-- -000000110000000000000000000000 +--100--- -000000000000000100000000000000 +--10---- -000000000000000100000000000000 +--1----- -000000000000000100000000000000 +0010-1-- -000000100000000000000000000010 +--1-1--- -000000000000000100000000000000 +--101--- -000000000000000100000000000000 +--11---- -000000000000000100000000000000 +001100-- -000001010000000000000000000000 +--110--- -000000000000000100000000000000 +001101-- -011001000000000000000000000000 +--111--- -000000000000000100000000000000 +00111--- -100001010000000000000000000000 +-1-0---- -000000000000000100000000000000 +-1------ -000000000000000100000000000000 +-1--0--- -000000000000000100000000000000 +-1-00--- -000000000000000100000000000000 +010000-- -100000000111010000000000000100 +0100010- -100000000110110000000000000100 +0100011- -000000000011010000000000000100 +-1--1--- -000000000000000100000000000000 +-1-01--- -000000000000000100000000000000 +01001--- -000000000010110000000000000100 +-1-1---- -000000000000000100000000000000 +-1-10--- -000000000000000100000000000000 +0101---- -000000000000010000000000000100 +-1-11--- -000000000000000100000000000000 +01100--- -001000001000000000000000000100 +-11----- -000000000000000100000000000000 +-11-0--- -000000000000000100000000000000 +-110---- -000000000000000100000000000000 +01101--- -001000001000000000000000000100 +-11-1--- -000000000000000100000000000000 +0111---- -001000001000000000000000000100 +-111---- -000000000000000100000000000000 +1--00--- -000000000000000100000000000000 +1------- -000000000000000100000000000000 +1---0--- -000000000000000100000000000000 +1--0---- -000000000000000100000000000000 +100000-- -000000000000000000000001000000 +100000-1 -000100000000000000000000000000 +100001-- -000000000000000100000001101000 +100001-1 -000100000000000000000000000000 +1--01--- -000000000000000100000000000000 +1---1--- -000000000000000100000000000000 +1--1---- -000000000000000100000000000000 +1--10--- -000000000000000100000000000000 +100100-- -000100000000000000000110000000 +100101-- -000100000000000100000110101000 +1--11--- -000000000000000100000000000000 +10011--- -000000000000000000000000010000 +101000-- -000010000000000001000000000000 +1-1-0--- -000000000000000100000000000000 +1-10---- -000000000000000100000000000000 +1-1----- -000000000000000100000000000000 +101001-- -000010000000000010000000000000 +1-1-1--- -000000000000000100000000000000 +101010-- -000010000000000001000000000000 +101011-- -000010000000000010000000000000 +1-11---- -000000000000000100000000000000 +10110--- -000010000000000000000000000001 +10111--- -000010000000000000000000000000 +11--0--- -000000000000000100000000000000 +1100---- -001100000000000000000100000000 +11-0---- -000000000000000100000000000000 +11------ -000000000000000100000000000000 +11--1--- -000000000000000100000000000000 +1101---- -000000000000000000000000010000 +11-1---- -000000000000000100000000000000 +111----- -000000000000000100001000001000 diff --git a/espresso/examples/indust/b12 b/espresso/examples/indust/b12 new file mode 100644 index 0000000..ca923e9 --- /dev/null +++ b/espresso/examples/indust/b12 @@ -0,0 +1,433 @@ +.i 15 +.o 9 +-------00------ 000010000 +-0-0----0------ 000000010 +-------------0- 000001000 +0--0----------- 000000001 +---0----0------ 000000010 +-----------00-- 000100000 +--------0--0--- 000010000 +-------0-0----- 000010000 +-------0----0-- 000100000 +--00----0------ 000000010 +0------0------- 000010000 +0--------0----- 000000001 +0----------0--- 000010000 +-000----0------ 000000010 +---------0-0--- 000010000 +------------1-- 000001000 +0-----------1-- 000000001 +---------01---- 000000001 +----------1---- 000001011 +--------0-1---- 000000010 +-0--------1---- 000000010 +00-0---00-1---- 001000000 +-0------0-1---- 000000010 +-00-------1---- 000000010 +-00-----0-1---- 000000010 +--00----0-1---- 000000010 +--00------1---- 000000010 +--0-----0-1---- 000000010 +--0-------1---- 000000010 +-0-0------1---- 000000010 +---0----0-1---- 000000010 +-0-0----0-1---- 000000010 +-000------1---- 000000010 +---0------1---- 000000011 +-0-0---00-1---- 001000000 +00-0------1---- 001000000 +00-0----0-1---- 001000000 +0---------1---- 000000001 +00-0---0--1---- 001000000 +----------1-1-- 000000001 +00-0-----1----- 001000000 +-0------01----- 000000010 +-0-0---001----- 001000000 +-00-----01----- 000000010 +---0-----1----- 000000001 +00-0---001----- 001000000 +00-----0010---- 001000000 +00-0---0-10---- 001000100 +00-----0-10---- 001000000 +00-0---0-1----- 001000000 +--0-----01----- 000000010 +--------01----- 000000010 +-0-0---0010---- 001000100 +--00---0010---- 000000100 +-0-----0010---- 001000000 +0-00---0-10---- 000000100 +0--0---0-10---0 000000100 +00-0----010---- 001000000 +00-0----01----- 001000000 +---0---0010---0 000000100 +00-0-----10---- 001000000 +---------1--1-- 000000001 +--0-----011---- 000000010 +-00------11---- 000000010 +-0-------11---- 000000010 +---------11---- 000000011 +--0------11---- 000000010 +-0------011---- 000000010 +--------011---- 000000010 +0------1------- 000000001 +00-0---1------- 001000000 +00-0---1--0---- 001000000 +00-0---10------ 001000000 +00-0---10-0---- 001000000 +-0-0---1------- 000000010 +-0-0---10------ 000000010 +-00----1------- 000000010 +-00----10------ 000000010 +-------1-0----- 000000001 +-------1---0--- 000010000 +-------10------ 000000010 +---0---1------- 000000011 +---0---10------ 000000010 +-------1------- 000001011 +--0----1------- 000000010 +--0----10------ 000000010 +--00---1------- 000000010 +--00---10------ 000000010 +-0-----1------- 000000010 +-0-----10------ 000000010 +-000---1------- 000000010 +-------1----1-- 000000001 +-------1--1---- 000000011 +-------10-1---- 000000010 +-00----1--1---- 000000010 +-0-----10-1---- 000000010 +-0-----1--1---- 000000010 +--0----1--1---- 000000010 +-0-0---1--1---- 000000010 +---0---1--1---- 000000010 +--00---1--1---- 000000010 +---0---10-1---- 000000010 +--0----10-1---- 000000010 +-00----1-1----- 000000010 +-------101----- 000000010 +--0----1-1----- 000000010 +-0-----101----- 000000010 +--0----101----- 000000010 +-------1-1----- 000000011 +-0-----1-1----- 000000010 +-------1-11---- 000000010 +-------1011---- 000000010 +-0-----1-11---- 000000010 +--0----1-11---- 000000010 +00-1---0-00---- 000000100 +0--1---0-00---0 000000100 +---1---0000---0 000000100 +0-01---0-00---- 000000100 +--01---0000---- 000000100 +-0-1---0000---- 000000100 +-001------1---- 000000010 +-0-1------1---- 000000010 +-0-1----0-1---- 000000010 +---1------1---- 000000010 +--01----0-1---- 000000010 +---1----0-1---- 000000010 +--01------1---- 000000010 +--01----01----- 000000010 +---1----01----- 000000010 +-0-1----01----- 000000010 +-001-----1----- 000000010 +---1----011---- 000000010 +--01-----11---- 000000010 +---1-----11---- 000000010 +-0-1-----11---- 000000010 +-0-1---1------- 000000010 +--01---1------- 000000010 +-001---1------- 000000010 +---1---1------- 000000010 +-0-1---10------ 000000010 +---1---10------ 000000010 +--01---10------ 000000010 +--01---1--1---- 000000010 +---1---10-1---- 000000010 +---1---1--1---- 000000010 +-0-1---1--1---- 000000010 +--01---1-1----- 000000010 +-0-1---1-1----- 000000010 +---1---1-1----- 000000010 +---1---101----- 000000010 +---1---1-11---- 000000010 +--10---00------ 001000000 +001----0--0---- 001000100 +--1----0000---0 000000100 +--1----00-0---0 000000100 +--1----00-0---- 001000000 +--1----00------ 001000000 +0010----0-0---- 001000000 +--1-----0------ 000000010 +0010---0------- 001000000 +-01-----0------ 000000010 +0010----------- 001000000 +0-10---00------ 001000000 +0010---0--0---- 001000100 +001----0------- 001000000 +0-10---0--0---0 000000100 +0-10---0--0---- 001000000 +-01----00------ 001000000 +0-10---0------- 001000000 +001-----0-0---- 001000000 +-01----00-0---- 001000100 +-01----0000---- 000000100 +-010---00------ 001000000 +001-----0------ 001000000 +-010---00-0---- 001000100 +0-10----0-0---- 001000000 +001-------0---- 001000000 +0-10----0------ 001000000 +001----00-0---- 001000000 +001----00------ 001000000 +0-10------0---- 001000000 +0010---00------ 001000000 +0-10----------- 001000000 +001----0-00---- 000000100 +001------------ 001000000 +0-1----0--0---0 000000100 +0010------0---- 001000000 +0010----0------ 001000000 +--10---00-0---0 000000100 +--10---00-0---- 001000000 +0-1------------ 001000001 +0-1-------0---- 001000000 +0-1-----0------ 001000000 +0-1-----0-0---- 001000000 +0-1----00-0---- 001000000 +0-1----0------- 001000000 +0-1----00------ 001000000 +0-1----0-00---0 000000100 +0-1----0--0---- 001000000 +0010---0--1---- 001000000 +--1-------1---- 000000011 +0-1----0--1---- 001000000 +-01-------1---- 000000010 +--1-----0-1---- 000000010 +001-----0-1---- 001000000 +--1----00-1---- 001000000 +0-10------1---- 001000000 +--10---00-1---- 001000000 +001-------1---- 001000000 +0-1----00-1---- 001000000 +0-1-----0-1---- 001000000 +0010----0-1---- 001000000 +-01----00-1---- 001000000 +0010------1---- 001000000 +001----00-1---- 001000000 +0-1-------1---- 001000000 +0-10----0-1---- 001000000 +001----0--1---- 001000000 +-010---00-1---- 001000000 +0-10---0--1---- 001000000 +0-10---00-1---- 001000000 +-01-----0-1---- 000000010 +0-1----0-10---- 001000000 +0-1----0-10---0 000000100 +0010-----1----- 001000000 +-01----0010---- 001000100 +-01----001----- 001000000 +--10---0010---- 001000000 +0-1-----010---- 001000000 +0-1-----01----- 001000000 +0-1----001----- 001000000 +0-1------10---- 001000000 +0-1------1----- 001000000 +0-1----0010---- 001000000 +--10---001----- 001000000 +001----0-10---- 001000100 +001----001----- 001000000 +--1----0010---0 000000100 +0-10---0-1----- 001000000 +--1----0010---- 001000000 +0-10---0-10---- 001000000 +--1----001----- 001000000 +0-10---001----- 001000000 +001----0-1----- 001000000 +001-----010---- 001000000 +0010----01----- 001000000 +0-10-----1----- 001000000 +0-10-----10---- 001000000 +001------1----- 001000000 +001------10---- 001000000 +-010---001----- 001000000 +0-10----01----- 001000000 +0-10----010---- 001000000 +--1------1----- 000000001 +001-----01----- 001000000 +0010---0-1----- 001000000 +0-1----0-1----- 001000000 +0-1----10------ 001000000 +0-1----1--0---- 001000000 +0-1----1------- 001000000 +--1----1------- 000000011 +0010---10------ 001000000 +001----1--0---- 001000000 +0-10---1------- 001000000 +0-10---1--0---- 001000000 +0-1----10-0---- 001000000 +0-10---10------ 001000000 +001----10------ 001000000 +0-10---10-0---- 001000000 +-01----10------ 000000010 +0010---1------- 001000000 +001----10-0---- 001000000 +-01----1------- 000000010 +001----1------- 001000000 +--1----10------ 000000010 +--1----10-1---- 000000010 +--1----1--1---- 000000010 +-01----1--1---- 000000010 +001-1---------- 010000000 +0-1-10--------- 010000000 +0-1-1-0-------- 010000000 +0011----------- 010000000 +--11---00-0---0 000000100 +0-110---------- 100000000 +0-11--0-------- 010000000 +--11----0------ 000000010 +-011---00-0---- 000000100 +0-11-0--------- 010000000 +-011----0------ 000000010 +0011---0--0---- 000000100 +0-11---0--0---0 000000100 +-011------1---- 000000010 +--11----0-1---- 000000010 +--11------1---- 000000010 +--11---1------- 000000010 +--11---10------ 000000010 +-011---1------- 000000010 +--11---1--1---- 000000010 +0-1101--------- 100000000 +00111---------- 010000000 +0-1110--------- 010000000 +0-111-0-------- 010000000 +0100---0--0---- 000000100 +010----0-00---- 000000100 +-100---00-0---- 000000100 +-10----00-0---- 000000100 +-1-0---00-0---0 000000100 +010----0--0---- 000000100 +01-----0-00---0 000000100 +-10----0000---- 000000100 +01-----0--0---0 000000100 +-1-----0000---0 000000100 +01------------- 000000001 +-1-----00-0---0 000000100 +-10-----0------ 000000010 +-1------0------ 000000010 +01-0---0--0---0 000000100 +-1------0-1---- 000000010 +-1--------1---- 000000011 +-10-----0-1---- 000000010 +-10-------1---- 000000010 +-1-------1----- 000000001 +-10----0010---- 000000100 +-1-----0010---0 000000100 +010----0-10---- 000000100 +01-----0-10---0 000000100 +-1-----10------ 000000010 +-1-----1------- 000000011 +-10----10------ 000000010 +-10----1------- 000000010 +-10----1--1---- 000000010 +-1-----10-1---- 000000010 +-1-----1--1---- 000000010 +01-1--0-------- 010000000 +-101---00-0---- 000000100 +01-1-0--------- 010000000 +-101----0------ 000000010 +-1-1----0------ 000000010 +-1-1---00-0---0 000000100 +01-1---0--0---0 000000100 +0101---0--0---- 000000100 +01010---------- 100000000 +0101----------- 110000000 +01-10---------- 100000000 +-101------1---- 000000010 +-1-1------1---- 000000010 +-1-1----0-1---- 000000010 +-101---1------- 000000010 +-1-1---1------- 000000010 +-1-1---10------ 000000010 +-1-1---1--1---- 000000010 +01-101--------- 100000000 +01-1-1--------- 100000000 +01-11-0-------- 010000000 +01-110--------- 010000000 +01011---------- 010000000 +0110------0---- 001000000 +011----0--0---0 000000100 +-110---00-0---- 001000000 +011-----0-0---- 001000000 +0110----------- 001000000 +011----00------ 001000000 +-11----00-0---- 001000000 +011-----0------ 001000000 +011------------ 001000000 +011----00-0---- 001000000 +011-0---------- 100000000 +0110---00------ 001000000 +-11----00-0---0 000000100 +011-------0---- 001000000 +0110---0--0---- 001000000 +0110---0------- 001000000 +-110---00------ 001000000 +011----0--0---- 001000000 +0110----0-0---- 001000000 +0110----0------ 001000000 +011----0------- 001000000 +-11----00------ 001000000 +0110------1---- 001000000 +0110---0--1---- 001000000 +011-----0-1---- 001000000 +011----00-1---- 001000000 +011----0--1---- 001000000 +0110----0-1---- 001000000 +-110---00-1---- 001000000 +-11----00-1---- 001000000 +011-------1---- 001000000 +011----0-10---- 001000000 +011------10---- 001000000 +011----001----- 001000000 +011------1----- 001000000 +011-----010---- 001000000 +011----0-1----- 001000000 +011-----01----- 001000000 +-110---001----- 001000000 +-11----0010---- 001000000 +0110---0-1----- 001000000 +0110-----1----- 001000000 +0110----01----- 001000000 +-11----001----- 001000000 +011----1------- 001000000 +011----10------ 001000000 +011----1--0---- 001000000 +0110---10------ 001000000 +0110---1------- 001000000 +011----10-0---- 001000000 +011--1--------- 100000000 +011-01--------- 100000000 +011-1-0-------- 010000000 +011-10--------- 010000000 +0111-0--------- 010000000 +0111--0-------- 010000000 +01110---------- 100000000 +0111-1--------- 100000000 +011101--------- 100000000 +1-------------- 000001000 +1------0------- 000100000 +1----------0--- 000100000 +1--0---0010---- 000000100 +1--1---0000---- 000000100 +1-10---00-0---- 000000100 +1-1----0000---- 000000100 +1-1----00-0---- 000000100 +1-1----0010---- 000000100 +1-11---00-0---- 000000100 +11-0---00-0---- 000000100 +11-----00-0---- 000000100 +11-----0000---- 000000100 +11-----0010---- 000000100 +11-1---00-0---- 000000100 +111----00-0---- 000000100 diff --git a/espresso/examples/indust/b2 b/espresso/examples/indust/b2 new file mode 100644 index 0000000..b6ec1d6 --- /dev/null +++ b/espresso/examples/indust/b2 @@ -0,0 +1,112 @@ +.i 16 +.o 17 +----00----00-00- 11101111111111111 +0----1----1100-0 11111010000010011 +01--110-11011110 10110001101000110 +01--010-1-011110 01111001000110101 +-----111--1100-0 11111010000010011 +----------101110 11101111111111111 +0---11-01-010000 10010001101010110 +01--110-10011110 10110001101001000 +----11111-010000 10011001101010110 +10--------1010-1 11011111111111111 +0---110---010000 10010001101010110 +0-----010-110000 11111010000010011 +----1-----000110 11111001101101001 +--------1-100110 11111010100100101 +----1-----001000 11111010000010001 +1---------101000 11111010101101001 +----000011011000 01111001000011101 +----100011011000 11111001110001101 +0---100100111000 11111001101000100 +----1-----000100 11111001101101100 +----1-----001010 11111010010001110 +0---010---010011 01111001000011101 +-----0----011100 11111001100110001 +00--0-----000010 11111001001111000 +----1-----0000-- 01111001001000010 +----100001010111 11001001101010110 +01--110-1-0100-0 10110001101010110 +----1-----000111 11111010001010111 +0---11-01-010011 10000001101010110 +----1-----001011 11111010010000101 +0---110---010011 10000001101010110 +0---------101001 11111010000010001 +-----0----011101 11111001100101110 +0---010---010000 01111001000011101 +----0--10-101101 11111001001000010 +----1-----101101 11111001001000110 +0---00010-11100- 01111001000011101 +----11111-010011 10001001101010110 +----0-0001101101 11111001000110101 +----0--111101101 11111001000100010 +----0-----000--0 11101111111111111 +----0-----0010-- 11101111111111111 +----000001-10111 01111001000011101 +----0--110101101 11111001000111100 +----100010010101 11111001101010101 +----100001110111 11001001110100001 +00--1110-0011001 10100001100010100 +----000010010101 01111001000011101 +----------101111 01111111111111111 +----1-----000101 11111001101110101 +0---000-0111100- 01111001000011111 +0---10000111100- 11001001110100101 +00--1110-1011001 11100001100010010 +0---100100111001 11111001101000001 +-------10110011- 11111010100100101 +----1-0---001001 11111010010011110 +0---10010111100- 11111001100111110 +--------0-010010 01111001000110101 +----------10-100 11110111111111111 +0---011---011001 01111001000011101 +----0001-1100000 01111001000011001 +----00011-100000 01111001000011001 +-----1111-11000- 11111010000010011 +0----1--1-11000- 11111010000010011 +0---0111--01-001 01111001000011101 +01--011---01-001 01111001000011101 +----100111100000 11111001010110100 +0---10011110000- 11111001010110100 +----100110100000 11111001010110011 +0---10011010000- 11111001010110011 +0---0001-110000- 01111001000011001 +0---00011-10000- 01111001000011001 +0---10010110000- 11111001100111110 +----100101100000 11111001100111110 +0-----001-1100-0 11111010000010011 +0-----00-11100-0 11111010000010011 +----------101100 10010111111111111 +----------10010- 11011111111111111 +----0-----010010 01111001000110101 +------1---010010 01111001000110101 +-0--------010010 01111001000110101 +-----0----010010 01111001000110101 +0---01--1-010011 01111001000011101 +----01111-010011 01111001000011101 +0---------10001- 11111001001100111 +0---------100011 11111001001100010 +10--------00001- 01111001001000010 +-0--------000011 01111001001000010 +----------10101- 10110111111111111 +----------101011 10000111111111111 +----0--010101101 11111001000110111 +----00-010101101 11111001000110110 +0---1111-101-001 11111001101000110 +01--111--101-001 11111001101000110 +0---1111-001-001 10111001101001000 +01--111--001-001 10111001101001000 +0-0-1111-001110- 10111001101001000 +010-111--001110- 10111001101001000 +0-0-1111-101110- 11111001101000110 +010-111--101110- 11111001101000110 +0-0-0111--01110- 01111001000011101 +010-011---01110- 01111001000011101 +-0----1---001001 01111001000110101 +----1-1---001001 01111001000110101 +0----10-1-1100-- 11111010000010011 +0----10---11000- 11111010000010011 +0---01--1-010000 01111001000011101 +----01111-010000 01111001000011101 +-----1----000-01 01111001001000010 +-----1----0001-1 01111001001000010 diff --git a/espresso/examples/indust/b3 b/espresso/examples/indust/b3 new file mode 100644 index 0000000..5a9e188 --- /dev/null +++ b/espresso/examples/indust/b3 @@ -0,0 +1,236 @@ +.i 32 +.o 20 +-1------------------------------ -0111100000000000000 +10------1--------------1-------- -0000000000000010000 +10---------------------1-1------ -0000000000000010000 +10---------------------1---0---- -0000000000000010000 +101--0-1-----------------0-0---- -0100010000000000000 +101--0-------------------0-0-0-- -0100010000000000000 +101--0-----------------0-0-0---- -0100010000000000000 +1010-1-------------------0-0---- -0100010000000000000 +101--0-1-1---------------0-0---- -0000000000000100000 +101--0---1---------------0-0-0-- -0000000000000100000 +101--0---1-------------0-0-0---- -0000000000000100000 +1010-1---1---------------0-0---- -0000000000000100000 +-0-1-1-------------------0-0---0 -1100000000000000000 +-0-1-1-1-----------------0-0---- -1100000000000000000 +-00100-------------------0-0---0 -1100000000000000000 +-00100-1-----------------0-0---- -1100000000000000000 +-001000------------------0-0---- -1100000000000000000 +-0-1-1----------0-00-----0-0---0 -0000000010000000000 +-0-1-1-1--------0-00-----0-0---- -0000000010000000000 +-00100----------0-00-----0-0---0 -0000000010000000000 +-00100-1--------0-00-----0-0---- -0000000010000000000 +-001000---------0-00-----0-0---- -0000000010000000000 +-0-1-1----------0-0000---0-0---0 -0000000000000100000 +-0-1-1-1--------0-0000---0-0---- -0000000000000100000 +-00100----------0-0000---0-0---0 -0000000000000100000 +-00100-1--------0-0000---0-0---- -0000000000000100000 +-001000---------0-0000---0-0---- -0000000000000100000 +00-1-1---------00001-----0-0---0 -0000000010000000000 +00-1-1-1-------00001-----0-0---- -0000000010000000000 +000100---------00001-----0-0---0 -0000000010000000000 +000100-1-------00001-----0-0---- -0000000010000000000 +0001000--------00001-----0-0---- -0000000010000000000 +00-1-1---------0000100---0-0---0 -0000000000000100000 +00-1-1-1-------0000100---0-0---- -0000000000000100000 +000100---------0000100---0-0---0 -0000000000000100000 +000100-1-------0000100---0-0---- -0000000000000100000 +0001000--------0000100---0-0---- -0000000000000100000 +00-1-1---------10001-----0-0---0 -0000000000010100000 +00-1-1-1-------10001-----0-0---- -0000000000010100000 +000100---------10001-----0-0---0 -0000000000010100000 +000100-1-------10001-----0-0---- -0000000000010100000 +0001000--------10001-----0-0---- -0000000000010100000 +00-1-1----------0010-----0-0---0 -0000000000000100000 +00-1-1-1--------0010-----0-0---- -0000000000000100000 +000100----------0010-----0-0---0 -0000000000000100000 +000100-1--------0010-----0-0---- -0000000000000100000 +0001000---------0010-----0-0---- -0000000000000100000 +00-1-1----------0011-----0-0---0 -0000000000100100000 +00-1-1-1--------0011-----0-0---- -0000000000100100000 +000100----------0011-----0-0---0 -0000000000100100000 +000100-1--------0011-----0-0---- -0000000000100100000 +0001000---------0011-----0-0---- -0000000000100100000 +-0-1-1----------0110-----0-0---0 -0000000000000100000 +-0-1-1-1--------0110-----0-0---- -0000000000000100000 +-00100----------0110-----0-0---0 -0000000000000100000 +-00100-1--------0110-----0-0---- -0000000000000100000 +-001000---------0110-----0-0---- -0000000000000100000 +00-1-1----------1010-----0-0---0 -0000000000000100000 +00-1-1-1--------1010-----0-0---- -0000000000000100000 +000100----------1010-----0-0---0 -0000000000000100000 +000100-1--------1010-----0-0---- -0000000000000100000 +0001000---------1010-----0-0---- -0000000000000100000 +10--10-1-----------------0-0---- -0100000001000100000 +10--10-------------------0-0--0- -0100000001000100000 +10--10-----------------0-0-0---- -0100000001000100000 +10-011-------------------0-0---- -0100000001000100000 +10--10-1---0-------------0-0---- -0000000100000100000 +10--10-----0-------------0-0--0- -0000000100000100000 +10--10-----0-----------0-0-0---- -0000000100000100000 +10-011-----0-------------0-0---- -0000000100000100000 +10-1-----1------0-0000---0-1---- -1000000010000100000 +10-1-----1------0110-----0-1---- -1000000000000100000 +10--1-----------0-0000---0-1---- -1000000010000100000 +10--1-----------0110-----0-1---- -1000000000000100000 +101--0-11----------------0-1---- -0100010000000000000 +101--0--1----------------0-1-0-- -0100010000000000000 +101--0--1--------------0-0-1---- -0100010000000000000 +1010-1--1----------------0-1---- -0100010000000000000 +101--0-111---------------0-1---- -0000000000000100000 +101--0--11---------------0-1-0-- -0000000000000100000 +101--0--11-------------0-0-1---- -0000000000000100000 +1010-1--11---------------0-1---- -0000000000000100000 +10--10-11----------------0-1---- -0100000001000100000 +10--10--1----------------0-1--0- -0100000001000100000 +10--10--1--------------0-0-1---- -0100000001000100000 +10-011--1----------------0-1---- -0100000001000100000 +10--10-11--0-------------0-1---- -0000000100000100000 +10--10--1--0-------------0-1--0- -0000000100000100000 +10--10--1--0-----------0-0-1---- -0000000100000100000 +10-011--1--0-------------0-1---- -0000000100000100000 +101--0-0---------------1-0-0-1-- -0000001000001000001 +101--0-0-1-------------1-0-0-1-- -0100000000000000000 +101--0-0--1-000--------1-0-0-1-- -0000000000000100000 +-0-1-1-0-----------------0-0---1 -0001000000001000000 +-0010010-----------------0-0---1 -0001000000001000000 +-0-1-1-0--------0-00000--0-0---1 -0100000000000000000 +-0010010--------0-00000--0-0---1 -0100000000000000000 +00-1-1-0-------00001000--0-0---1 -0100000000000000000 +00010010-------00001000--0-0---1 -0100000000000000000 +00-1-1-0-------10001-----0-0---1 -0100000000000000000 +00010010-------10001-----0-0---1 -0100000000000000000 +00-1-1-0--------001------0-0---1 -0100000000000000000 +00010010--------001------0-0---1 -0100000000000000000 +-0-1-1-0--------0110-----0-0---1 -0100000000000000000 +-0010010--------0110-----0-0---1 -0100000000000000000 +00-1-1-0--------1010-----0-0---1 -0100000000000000000 +00010010--------1010-----0-0---1 -0100000000000000000 +10--10-0---------------1-0-0--1- -0100000000001000001 +-0000--------------------0-0---- -0100000000000000000 +101--0-1-----------------1000--- -0100010000000000000 +101--0-------------------10000-- -0100010000000000000 +101--0-----------------0-1000--- -0100010000000000000 +1010-1-------------------1000--- -0100010000000000000 +101--0-1-1---------------1000--- -0000000000000100000 +101--0---1---------------10000-- -0000000000000100000 +101--0---1-------------0-1000--- -0000000000000100000 +1010-1---1---------------1000--- -0000000000000100000 +-0-1-1-------------------1000--0 -1100000000000000000 +-0-1-1-1-----------------1000--- -1100000000000000000 +-00100-------------------1000--0 -1100000000000000000 +-00100-1-----------------1000--- -1100000000000000000 +-001000------------------1000--- -1100000000000000000 +-0-1-1----------0-00-----1000--0 -0000000010000000000 +-0-1-1-1--------0-00-----1000--- -0000000010000000000 +-00100----------0-00-----1000--0 -0000000010000000000 +-00100-1--------0-00-----1000--- -0000000010000000000 +-001000---------0-00-----1000--- -0000000010000000000 +-0-1-1----------0-0000---1000--0 -0000000000000100000 +-0-1-1-1--------0-0000---1000--- -0000000000000100000 +-00100----------0-0000---1000--0 -0000000000000100000 +-00100-1--------0-0000---1000--- -0000000000000100000 +-001000---------0-0000---1000--- -0000000000000100000 +00-1-1---------00001-----1000--0 -0000000010000000000 +00-1-1-1-------00001-----1000--- -0000000010000000000 +000100---------00001-----1000--0 -0000000010000000000 +000100-1-------00001-----1000--- -0000000010000000000 +0001000--------00001-----1000--- -0000000010000000000 +00-1-1---------0000100---1000--0 -0000000000000100000 +00-1-1-1-------0000100---1000--- -0000000000000100000 +000100---------0000100---1000--0 -0000000000000100000 +000100-1-------0000100---1000--- -0000000000000100000 +0001000--------0000100---1000--- -0000000000000100000 +00-1-1---------10001-----1000--0 -0000000000010100000 +00-1-1-1-------10001-----1000--- -0000000000010100000 +000100---------10001-----1000--0 -0000000000010100000 +000100-1-------10001-----1000--- -0000000000010100000 +0001000--------10001-----1000--- -0000000000010100000 +00-1-1----------0010-----1000--0 -0000000000000100000 +00-1-1-1--------0010-----1000--- -0000000000000100000 +000100----------0010-----1000--0 -0000000000000100000 +000100-1--------0010-----1000--- -0000000000000100000 +0001000---------0010-----1000--- -0000000000000100000 +00-1-1----------0011-----1000--0 -0000000000100100000 +00-1-1-1--------0011-----1000--- -0000000000100100000 +000100----------0011-----1000--0 -0000000000100100000 +000100-1--------0011-----1000--- -0000000000100100000 +0001000---------0011-----1000--- -0000000000100100000 +-0-1-1----------0110-----1000--0 -0000000000000100000 +-0-1-1-1--------0110-----1000--- -0000000000000100000 +-00100----------0110-----1000--0 -0000000000000100000 +-00100-1--------0110-----1000--- -0000000000000100000 +-001000---------0110-----1000--- -0000000000000100000 +00-1-1----------1010-----1000--0 -0000000000000100000 +00-1-1-1--------1010-----1000--- -0000000000000100000 +000100----------1010-----1000--0 -0000000000000100000 +000100-1--------1010-----1000--- -0000000000000100000 +0001000---------1010-----1000--- -0000000000000100000 +10--10-1-----------------1000--- -0100000001000100000 +10--10-------------------1000-0- -0100000001000100000 +10--10-----------------0-1000--- -0100000001000100000 +10-011-------------------1000--- -0100000001000100000 +10--10-1---0-------------1000--- -0000000100000100000 +10--10-----0-------------1000-0- -0000000100000100000 +10--10-----0-----------0-1000--- -0000000100000100000 +10-011-----0-------------1000--- -0000000100000100000 +00010-10-------00001000--0-0---1 -0101000000001000000 +00010-10-------00001001--0-0---1 -0101000010001001100 +00010-10-------00001010--0-0---1 -0001000010001101100 +00010-10-------00001011--0-0---1 -0001000010001001101 +00010-10-------00001100--0-0---1 -0001000010001001101 +00010-10-------00001101--0-0---1 -0001000010001001110 +00010-10-------00001110--0-0---1 -0001000010001001110 +00010-10-------00001111--0-0---1 -0001000010001001111 +-0010-10--------0-00000--0-0---1 -0101000000001000000 +00010-10--------0-00001--0-0---1 -0101000010001001100 +00010-10--------0-00010--0-0---1 -0001000010001101100 +00010-10--------0-00011--0-0---1 -0001000010001001101 +00010-10--------0-00100--0-0---1 -0001000010001001101 +00010-10--------0-00101--0-0---1 -0001000010001001110 +00010-10--------0-00110--0-0---1 -0001000010001001110 +00010-10--------0-00111--0-0---1 -0001000010001001111 +00-1-1-0-------00001000--0-0---1 -0101000000001000000 +00-1-1-0-------00001001--0-0---1 -0101000010001001100 +00-1-1-0-------00001010--0-0---1 -0001000010001101100 +00-1-1-0-------00001011--0-0---1 -0001000010001001101 +00-1-1-0-------00001100--0-0---1 -0001000010001001101 +00-1-1-0-------00001101--0-0---1 -0001000010001001110 +00-1-1-0-------00001110--0-0---1 -0001000010001001110 +00-1-1-0-------00001111--0-0---1 -0001000010001001111 +-0-1-1-0--------0-00000--0-0---1 -0101000000001000000 +00-1-1-0--------0-00001--0-0---1 -0101000010001001100 +00-1-1-0--------0-00010--0-0---1 -0001000010001101100 +00-1-1-0--------0-00011--0-0---1 -0001000010001001101 +00-1-1-0--------0-00100--0-0---1 -0001000010001001101 +00-1-1-0--------0-00101--0-0---1 -0001000010001001110 +00-1-1-0--------0-00110--0-0---1 -0001000010001001110 +00-1-1-0--------0-00111--0-0---1 -0001000010001001111 +101-----01---------------0-1---- -0110000000001000000 +101-----0-1-000----------0-1---- -0110000100001000100 +101-----0-1-001----------0-1---- -0010000100001100100 +101-----0-1-010----------0-1---- -0010000100001000101 +101-----0-1-011----------0-1---- -0010000100001000101 +101-----0-1-100----------0-1---- -0010000100001000110 +101-----0-1-101----------0-1---- -0010000100001000110 +101-----0-1-110----------0-1---- -0010000100001000111 +101-----0-1-111----------0-1---- -0010000100001000111 +10--1---0----------------0-1---- -0100100000000000000 +10------1----------------0-1---- -0100000000000000000 +10----------------------01000--- -0100000000001000000 +10----------------------01001--- -0100000100001000100 +10----------------------01010--- -0000000100001100100 +10----------------------01011--- -0000000100001000101 +10----------------------01100--- -0000000100001000101 +10----------------------01101--- -0000000100001000110 +10----------------------01110--- -0000000100001000110 +10----------------------01111--- -0000000100001000111 +00----------------------11000--- -0100000000001000000 +00----------------------11001--- -0100000010001001100 +00----------------------11010--- -0000000010001101100 +00----------------------11011--- -0000000010001001101 +00----------------------11100--- -0000000010001001101 +00----------------------11101--- -0000000010001001110 +00----------------------11110--- -0000000010001001110 +00----------------------11111--- -0000000000000001000 diff --git a/espresso/examples/indust/b4 b/espresso/examples/indust/b4 new file mode 100644 index 0000000..2009e6e --- /dev/null +++ b/espresso/examples/indust/b4 @@ -0,0 +1,56 @@ +.i 33 +.o 23 +1------1------------------------- -0001000111100100011010 +0---0---------------------------1 -0100000000000000000000 +01--------------------1-----1-10- -1000000000000000000000 +0--------------00--------------1- -1000000000000000000000 +0--------0100-01010---------0-1-- -0000010011001000000000 +0--1------------------------000-- -0010000000000000000011 +0--------0100--0101---------0-1-- -0000001100110000000000 +0--1------------------------010-- -0011000000000000000001 +------01-0100--1000---------0-1-- -0000000010100000000000 +0--------10-0------111------011-- -0000100000000000000110 +0-----0--0100--0010---------0-1-- -0000001000001000000000 +---1----------------------10----- -0000000000000000001000 +0--------1110------1-1------011-- -0000100000000000000110 +0--------0111--------1------011-- -0000100000000000000110 +0--------1111------11-------011-- -0000100000000000000101 +0----1--------------------------- -0000000000000000100000 +---0-----------------------1----- -0000000000000000001000 +0---------------------1-----1-1-- -0000000000000000100000 +01----1--0011--001-----1----0-1-- -0000001000000000000000 +01-------0011--0011----1------1-- -0000000000010000000000 +01----0-00011--0011----1----0-1-- -0000001000001000000000 +01----1--0011--1-00---1-----0-1-- -0000000000100000000000 +0--------1011------111------011-- -0000100000000000000111 +01-------0011--0000----1----0-1-- -0000001000000000000000 +1------0------------------------- -0001000110011100011010 +01-------------0101---1-----1-1-- -0000000100100000000000 +-1-----------------------1--11--- -0000000000000100000000 +01-----------1--------0-1---11--- -0000000000000010000000 +0--------0100---------------0-1-- -0000100000000000011000 +0--------0010---------------0-1-- -0000100000000000000101 +0--------1101---------------0-1-- -0000100000000000000110 +01----01-------1000----1----1-1-- -0000010000000000000000 +01----0--------0010----1----1-1-- -0000011000000000000000 +01--------------010----1----1-1-- -0000000000001000000000 +01------------01010----1----1-1-- -0000010000000000000000 +01-------------0101----1----1-1-- -0000001000010000000000 +01-------------0011----1----1-1-- -0000000000011000000000 +-1-------------10-0---1-----1-1-- -0000000010000000000000 +-1----01-------1000---1-----1-1-- -0000000001100000000000 +-1-------------1100---1-----1-1-- -0000000110000000000000 +01----0--------0010---1-----1-1-- -0000000001000000000000 +01------------01010---1-----1-1-- -0000000001000000000000 +-1-----1-0011--0000---1-----0-1-- -0000000000100000000000 +01----1--0011---000---1-----0-1-- -0000000000100000000000 +---0------------------------010-- -0000000000000000000010 +--1-------------------------000-- -0000000000000000000010 +--------------------------11----- -0000000000000000010000 +---0----------------------1------ -0000000000000000010000 +0--------10-1------111------011-- -0000100000000000000101 +0--------1-00------111------011-- -0000100000000000000101 +01----------------------1---11--0 -0100000000000000000000 +01----------------------1---11--- -0000000000000101000000 +01----0-10011--1100---1-----0-1-- -0000000010100000000000 +-1-------0011--1100---1-------1-- -0000000100000000000000 diff --git a/espresso/examples/indust/b7 b/espresso/examples/indust/b7 new file mode 100644 index 0000000..1b4473a --- /dev/null +++ b/espresso/examples/indust/b7 @@ -0,0 +1,76 @@ +.i 8 +.o 31 +00000--- -000010000000001000100000000000 +00001--- -000010000000001000000000000000 +0001---- -000010000000001000010000000000 +--1-0--- -000000000000000100000000000000 +0010-0-- -000000110000000000000000000000 +--100--- -000000000000000100000000000000 +--10---- -000000000000000100000000000000 +--1----- -000000000000000100000000000000 +0010-1-- -000000100000000000000000000010 +--1-1--- -000000000000000100000000000000 +--101--- -000000000000000100000000000000 +--11---- -000000000000000100000000000000 +001100-- -000001010000000000000000000000 +--110--- -000000000000000100000000000000 +001101-- -011001000000000000000000000000 +--111--- -000000000000000100000000000000 +00111--- -100001010000000000000000000000 +-1-0---- -000000000000000100000000000000 +-1------ -000000000000000100000000000000 +-1--0--- -000000000000000100000000000000 +-1-00--- -000000000000000100000000000000 +010000-- -100000000111010000000000000100 +0100010- -100000000110110000000000000100 +0100011- -000000000011010000000000000100 +-1--1--- -000000000000000100000000000000 +-1-01--- -000000000000000100000000000000 +01001--- -000000000010110000000000000100 +-1-1---- -000000000000000100000000000000 +-1-10--- -000000000000000100000000000000 +0101---- -000000000000010000000000000100 +-1-11--- -000000000000000100000000000000 +01100--- -001000001000000000000000000100 +-11----- -000000000000000100000000000000 +-11-0--- -000000000000000100000000000000 +-110---- -000000000000000100000000000000 +01101--- -001000001000000000000000000100 +-11-1--- -000000000000000100000000000000 +0111---- -001000001000000000000000000100 +-111---- -000000000000000100000000000000 +1--00--- -000000000000000100000000000000 +1------- -000000000000000100000000000000 +1---0--- -000000000000000100000000000000 +1--0---- -000000000000000100000000000000 +100000-- -000000000000000000000001000000 +100000-1 -000100000000000000000000000000 +100001-- -000000000000000100000001101000 +100001-1 -000100000000000000000000000000 +1--01--- -000000000000000100000000000000 +1---1--- -000000000000000100000000000000 +1--1---- -000000000000000100000000000000 +1--10--- -000000000000000100000000000000 +100100-- -000100000000000000000110000000 +100101-- -000100000000000100000110101000 +1--11--- -000000000000000100000000000000 +10011--- -000000000000000000000000010000 +101000-- -000010000000000001000000000000 +1-1-0--- -000000000000000100000000000000 +1-10---- -000000000000000100000000000000 +1-1----- -000000000000000100000000000000 +101001-- -000010000000000010000000000000 +1-1-1--- -000000000000000100000000000000 +101010-- -000010000000000001000000000000 +101011-- -000010000000000010000000000000 +1-11---- -000000000000000100000000000000 +10110--- -000010000000000000000000000001 +10111--- -000010000000000000000000000000 +11--0--- -000000000000000100000000000000 +1100---- -001100000000000000000100000000 +11-0---- -000000000000000100000000000000 +11------ -000000000000000100000000000000 +11--1--- -000000000000000100000000000000 +1101---- -000000000000000000000000010000 +11-1---- -000000000000000100000000000000 +111----- -000000000000000100001000001000 diff --git a/espresso/examples/indust/b9 b/espresso/examples/indust/b9 new file mode 100644 index 0000000..d37ca2f --- /dev/null +++ b/espresso/examples/indust/b9 @@ -0,0 +1,125 @@ +.i 16 +.o 5 +-----------1---1 00001 +----001----1---- 00010 +----001---1----- 00100 +----001--1------ 01000 +----001-1------- 10000 +----010--------1 00010 +----010-------1- 00100 +----010------1-- 01000 +----010-----1--- 10000 +----011----1---1 00010 +----011---1---1- 00100 +----011--1---1-- 01000 +----011-1---1--- 10000 +----101----0---1 00010 +----101---0---1- 00100 +----101--0---1-- 01000 +----101-0---1--- 10000 +----101----1---0 00010 +----101---1---0- 00100 +----101--1---0-- 01000 +----101-1---0--- 10000 +----11-0--0000-1 00010 +--0-11----00---1 00010 +----11-0-0-00-01 00010 +----11-00-00-0-1 00010 +0---11--0-00-0-1 00010 +----11-000-0--01 00010 +----11-00000---1 00010 +----11-0---00001 00010 +-0--11---000---1 00010 +-0--11---0-0--01 00010 +0---11-----00001 00010 +----11-00--0-001 00010 +0---11--0--0-001 00010 +--0-11-----0--01 00010 +0---11---0000--1 00010 +-0--11-----0-001 00010 +0---11----0000-1 00010 +----11-0-0000--1 00010 +0---11---0-00-01 00010 +0---11--00-0--01 00010 +-0--11----00-0-1 00010 +0---11--0000---1 00010 +----11-0-00-0-1- 00100 +----11-0000---1- 00100 +0---11--0-0--01- 00100 +0---11--000---1- 00100 +----11-0--0-001- 00100 +----11-00-0--01- 00100 +-0--11---00---1- 00100 +-0--11----0--01- 00100 +0---11----0-001- 00100 +0---11---00-0-1- 00100 +0---11---0--01-- 01000 +----11-000---1-- 01000 +----11-0-0--01-- 01000 +0---11--00---1-- 01000 +----11-00---1--- 10000 +--0-11-----1--00 00010 +----11-00-01-0-0 00010 +----11-000-1--00 00010 +----11-00001---0 00010 +-0--11---0-1--00 00010 +-0--11---001---0 00010 +-0--11----01-0-0 00010 +0---11-----10000 00010 +0---11----0100-0 00010 +0---11---0-10-00 00010 +-0--11-----1-000 00010 +0---11---0010--0 00010 +----11-0---10000 00010 +0---11--0--1-000 00010 +0---11--0-01-0-0 00010 +0---11--00-1--00 00010 +0---11--0001---0 00010 +----11-0--0100-0 00010 +----11-0-0-10-00 00010 +----11-0-0010--0 00010 +--0-11----01---0 00010 +----11-00--1-000 00010 +0---11--0-1--00- 00100 +-0--11---01---0- 00100 +0---11---01-0-0- 00100 +-0--11----1--00- 00100 +----11-0-01-0-0- 00100 +0---11----1-000- 00100 +0---11--001---0- 00100 +----11-00-1--00- 00100 +----11-0001---0- 00100 +----11-0--1-000- 00100 +----11----10--10 00010 +----11----11--11 00010 +0---11---1--00-- 01000 +----11-0-1--00-- 01000 +----11-001---0-- 01000 +0---11--01---0-- 01000 +----11---10--10- 00100 +----11---11--11- 00100 +----11-01---0--- 10000 +----11--10--10-- 01000 +----11--11--11-- 01000 +----11-10---0--- 10000 +----11-11---1--- 10000 +---1------1---1- 00001 +---1100--------- 00010 +--1-100--------- 00100 +--1-11---1-0-1-0 00010 +--1-11---1-1-1-1 00010 +--11-----1---1-- 00001 +-1--100--------- 01000 +-1--11--1-0-1-0- 00100 +-1--11--1-1-1-1- 00100 +-11-11--1--01--0 00010 +-11-11--1--11--1 00010 +-111----1---1--- 00001 +1---100--------- 10000 +1---11-1-0---0-- 01000 +1---11-1-1---1-- 01000 +1-11---1-------- 00001 +11--11-1--0---0- 00100 +11--11-1--1---1- 00100 +111-11-1---0---0 00010 +111-11-1---1---1 00010 diff --git a/espresso/examples/indust/bc0 b/espresso/examples/indust/bc0 new file mode 100644 index 0000000..ad3074c --- /dev/null +++ b/espresso/examples/indust/bc0 @@ -0,0 +1,481 @@ +.i 26 +.o 11 +1111---------------------- 00010101000 +1110---------------------- 10111011011 +110111--------------1----- 00110001101 +110111--------------0----- 00000000000 +110110--------------1----- 00110001101 +110110--------------0----- 00000000000 +11010-------1-10---------- 00000101100 +11010-------0-10---------- 00000101110 +11010---000-1------------- 00000101100 +11010---000-0------------- 00000101110 +11010--1--1-1--1---------- 00000101100 +11010--1--1-1-0----------- 00000101100 +11010--1--1-0--1---------- 00000101110 +11010--1--1-0-0----------- 00000101110 +11010--1-1--1--1---------- 00000101100 +11010--1-1--1-0----------- 00000101100 +11010--1-1--0--1---------- 00000101110 +11010--1-1--0-0----------- 00000101110 +11010--11---1--1---------- 00000101100 +11010--11---1-0----------- 00000101100 +11010--11---0--1---------- 00000101110 +11010--11---0-0----------- 00000101110 +11010-1---1-1--1---------- 00000101100 +11010-1---1-1-0----------- 00000101100 +11010-1---1-0--1---------- 00000101110 +11010-1---1-0-0----------- 00000101110 +11010-1--1--1--1---------- 00000101100 +11010-1--1--1-0----------- 00000101100 +11010-1--1--0--1---------- 00000101110 +11010-1--1--0-0----------- 00000101110 +11010-1-1---1--1---------- 00000101100 +11010-1-1---1-0----------- 00000101100 +11010-1-1---0--1---------- 00000101110 +11010-1-1---0-0----------- 00000101110 +110101----1-1--1---------- 00000101100 +110101----1-1-0----------- 00000101100 +110101----1-0--1---------- 00000101110 +110101----1-0-0----------- 00000101110 +110101---1--1--1---------- 00000101100 +110101---1--1-0----------- 00000101100 +110101---1--0--1---------- 00000101110 +110101---1--0-0----------- 00000101110 +110101--1---1--1---------- 00000101100 +110101--1---1-0----------- 00000101100 +110101--1---0--1---------- 00000101110 +110101--1---0-0----------- 00000101110 +11010000----1------------- 00000101100 +11010000----0------------- 00000101110 +11001--------111---------- 00010110111 +11001--------110----1----- 00110001101 +11001--------110----0----- 00000000000 +11001--------101---------- 00000110111 +11001--------100---------- 00000010111 +11001--------0------1----- 00110001101 +11001--------0------0----- 00000000000 +11000---------------1----- 00110001101 +11000---------------0----- 00000000000 +10111-------1--0----1----- 00110001101 +10111-------1--0----0----- 00000000000 +10111-------1-0-----1----- 00110001101 +10111-------1-0-----0----- 00000000000 +10111-----111111---------- 10110011100 +10111-----111011---------- 10110011100 +10111-----110--0---------- 10110010110 +10111-----1101-1---------- 10110010110 +10111-----1100------------ 10110010110 +10111-----101111---------- 10010011100 +10111-----101011---------- 10010011100 +10111-----100--0---------- 10010010110 +10111-----1001-1---------- 10010010110 +10111-----1000------------ 10010010110 +10111-----011111--1------- 11110011100 +10111-----011111--0------- 11110011100 +10111-----011011--1------- 11110011100 +10111-----011011--0------- 11110011100 +10111-----010--0--1------- 11110010110 +10111-----010--0--0------- 11110010110 +10111-----0101-1--1------- 11110010110 +10111-----0101-1--0------- 11110010110 +10111-----0100----1------- 11110010110 +10111-----0100----0------- 11110010110 +10111-----001111--1------- 11000011100 +10111-----001111--0------- 11100011100 +10111-----001011--1------- 11000011100 +10111-----001011--0------- 11100011100 +10111-----000--0--1------- 11000010110 +10111-----000--0--0------- 11100010110 +10111-----0001-1--1------- 11000010110 +10111-----0001-1--0------- 11100010110 +10111-----0000----1------- 11000010110 +10111-----0000----0------- 11100010110 +10110-----111111---------- 11011011101 +10110-----111110---------- 11011011100 +10110-----111101---------- 11011011111 +10110-----111100---------- 11011011110 +10110-----111011---------- 11011011001 +10110-----111010---------- 11011011000 +10110-----111001---------- 11011011011 +10110-----111000---------- 11011011010 +10110-----110111---------- 11011011101 +10110-----110110---------- 11011011100 +10110-----110101---------- 11011011111 +10110-----110100---------- 11011011110 +10110-----110011---------- 11011011001 +10110-----110010---------- 11011011000 +10110-----110001---------- 11011011011 +10110-----110000---------- 11011011010 +10110-----101111---------- 11011011101 +10110-----101110---------- 11011011100 +10110-----101101---------- 11011011111 +10110-----101100---------- 11011011110 +10110-----101011---------- 11011011001 +10110-----101010---------- 11011011000 +10110-----101001---------- 11011011011 +10110-----101000---------- 11011011010 +10110-----100111---------- 11011011101 +10110-----100110---------- 11011011100 +10110-----100101---------- 11011011111 +10110-----100100---------- 11011011110 +10110-----100011---------- 11011011001 +10110-----100010---------- 11011011000 +10110-----100001---------- 11011011011 +10110-----100000---------- 11011011010 +10110-----011111---------- 11011011101 +10110-----011110---------- 11011011100 +10110-----011101---------- 11011011111 +10110-----011100---------- 11011011110 +10110-----011011---------- 11011011001 +10110-----011010---------- 11011011000 +10110-----011001---------- 11011011011 +10110-----011000---------- 11011011010 +10110-----010111---------- 11011011101 +10110-----010110---------- 11011011100 +10110-----010101---------- 11011011111 +10110-----010100---------- 11011011110 +10110-----010011---------- 11011011001 +10110-----010010---------- 11011011000 +10110-----010001---------- 11011011011 +10110-----010000---------- 11011011010 +10110-----001111---------- 11011011101 +10110-----001110---------- 11011011100 +10110-----001101---------- 11011011111 +10110-----001100---------- 11011011110 +10110-----001011---------- 11011011001 +10110-----001010---------- 11011011000 +10110-----001001---------- 11011011011 +10110-----001000---------- 11011011010 +10110-----000111---------- 11011011101 +10110-----000110---------- 11011011100 +10110-----000101---------- 11011011111 +10110-----000100---------- 11011011110 +10110-----000011---------- 11011011001 +10110-----000010---------- 11011011000 +10110-----000001---------- 11011011011 +10110-----000000---------- 11011011010 +10101--0------------------ 00010011100 +10101-0------------------- 00010011100 +10101111------------------ 00011010100 +101010-------------------- 00010011100 +10100----------11--------- 00110001100 +10100--------1--1--------- 00110001100 +10100--------1100---1----- 00110001101 +10100--------1100---0----- 00000000000 +10100--------1000---1----- 00110001101 +10100--------1000---0----- 00000000000 +10100--------0110---1----- 00110001101 +10100--------0110---0----- 00000000000 +10100-------11100---1----- 00110001101 +10100-------11100---0----- 00000000000 +10100-------10-0----1----- 00110001101 +10100-------10-0----0----- 00000000000 +10100-------0---1--------- 00110001100 +10100-------01100---1----- 00110001101 +10100-------01100---0----- 00000000000 +10100-------00100---1----- 00110001101 +10100-------00100---0----- 00000000000 +10100-----11-0010--------- 10110011000 +10100-----1111110--------- 10110010110 +10100-----1111010--------- 10110010110 +10100-----1101110--------- 10110011100 +10100-----1101010--------- 10110011100 +10100-----1100000--------- 10110011100 +10100-----10-0010--------- 10000011000 +10100-----1011110--------- 10010010110 +10100-----1011010--------- 10010010110 +10100-----1001110--------- 10010011100 +10100-----1001010--------- 10010011100 +10100-----1000000--------- 10010011100 +10100-----01-0010-1------- 11110011000 +10100-----01-0010-0------- 11110011000 +10100-----0111110-1------- 11110010110 +10100-----0111110-0------- 11110010110 +10100-----0111010-1------- 11110010110 +10100-----0111010-0------- 11110010110 +10100-----0101110-1------- 11110011100 +10100-----0101110-0------- 11110011100 +10100-----0101010-1------- 11110011100 +10100-----0101010-0------- 11110011100 +10100-----0100000-1------- 11110011100 +10100-----0100000-0------- 11110011100 +10100-----00-0010-1------- 11000011000 +10100-----00-0010-0------- 11100011000 +10100-----0011110-1------- 11000010110 +10100-----0011110-0------- 11100010110 +10100-----0011010-1------- 11000010110 +10100-----0011010-0------- 11100010110 +10100-----0001110-1------- 11000011100 +10100-----0001110-0------- 11100011100 +10100-----0001010-1------- 11000011100 +10100-----0001010-0------- 11100011100 +10100-----0000000-1------- 11000011100 +10100-----0000000-0------- 11100011100 +10011-10--------1--------- 00110001100 +10011-01--------1--------- 00110001100 +10011111------------------ 00110001001 +10011110--------0--------- 00101000111 +1001110---------1--------- 00110001100 +1001110-------0-0---1----- 00110001101 +1001110------0--0---1----- 00110001101 +1001110-----0---0---1----- 00110001101 +1001110----111110---1----- 00110001101 +1001110----0----0---1----- 00110001101 +10011101------0-0---0----- 00000000000 +10011101-----0--0---0----- 00000000000 +10011101----0---0---0----- 00000000000 +10011101---111110---0----- 00000000000 +10011101---111100--------- 00111100101 +10011101---0----0---0----- 00000000000 +10011100------0-0---0----- 00000000000 +10011100-----0--0---0----- 00000000000 +10011100----0---0---0----- 00000000000 +10011100---111110---0----- 00000000000 +10011100---111100--------- 00111100001 +10011100---0----0---0----- 00000000000 +10011011------------------ 00101110000 +10011010111-0---0---1----- 00110001101 +10011010111-0---0---0----- 00000000000 +10011010111111110--------- 00101101011 +10011010111111100--------- 00101100011 +100110101111110-0---1----- 00110001101 +100110101111110-0---0----- 00000000000 +100110101111101-0---1----- 00110001101 +100110101111101-0---0----- 00000000000 +10011010111110010--------- 00100010000 +10011010111110000--------- 00100010010 +100110101110----0---1----- 00110001101 +100110101110----0---0----- 00000000000 +10011010110-----0--------- 00111111101 +10011010101---100--------- 01111100011 +10011010101--1110--------- 01111000011 +10011010101--1010--------- 01111001010 +100110101011--000--------- 01111110010 +100110101011-0110--------- 01111011011 +100110101011-0010--------- 01111010010 +100110101010--000--------- 01111100010 +100110101010-0110--------- 01111001011 +100110101010-0010--------- 01111000010 +10011010100----10--------- 00110111001 +10011010100----00--------- 00110111000 +100110100-------0--------- 00100001011 +10011001--------0--------- 00111110011 +10011000------------1----- 00110001101 +10011000------------0----- 00000000000 +10010-------00111--------- 00110001100 +10010------11--1-1-------- 10111011001 +10010------11--1-0-------- 10111011111 +10010------11-1--1-------- 10111011001 +10010------11-1--0-------- 10111011111 +10010------11100-1-------- 01011011101 +10010------11100-0-------- 01011011101 +10010------110---1-------- 10111011001 +10010------110---0-------- 10111011111 +10010------10-0--1-------- 11110010110 +10010------10-0--0-------- 11110010110 +10010------101---1-------- 11110010110 +10010------101---0-------- 11110010110 +10010------10010-1-------- 11110011100 +10010------10010-0-------- 11110011100 +10010------01--1-1-------- 10111011000 +10010------01--1-0-------- 10111011110 +10010------01-1--1-------- 10111011000 +10010------01-1--0-------- 10111011110 +10010------01100-1-------- 01011011010 +10010------01100-0-------- 01011011010 +10010------010---1-------- 10111011000 +10010------010---0-------- 10111011110 +10010------00-0--1-------- 11100010110 +10010------00-0--0-------- 11100010110 +10010------001---1-------- 11100010110 +10010------001---0-------- 11100010110 +10010------00010-1-------- 11100011100 +10010------00010-0-------- 11100011100 +10010--0---10--101-------- 11110010110 +10010--0---10--100-------- 11110010110 +10010--0---00--101-------- 11100010110 +10010--0---00--100-------- 11100010110 +10010-0----10--101-------- 11110010110 +10010-0----10--100-------- 11110010110 +10010-0----00--101-------- 11100010110 +10010-0----00--100-------- 11100010110 +10010111----00110--------- 00110001011 +100100-----10--101-------- 11110010110 +100100-----10--100-------- 11110010110 +100100-----00--101-------- 11100010110 +100100-----00--100-------- 11100010110 +10001------1--11---------- 01011100000 +10001------1-1------------ 01011100000 +10001------11010---------- 00010100100 +10001------11001---------- 00010100010 +10001------11000---------- 00000011001 +10001------10010---------- 00010001010 +10001------10001---------- 00010101111 +10001------10000---------- 00000011110 +10001------01-------1----- 00110001101 +10001------01-------0----- 00000000000 +10001------00--1----1----- 00110001101 +10001------00--1----0----- 00000000000 +10001------00-10----1----- 00110001101 +10001------00-10----0----- 00000000000 +10001------00-0-----1----- 00110001101 +10001------00-0-----0----- 00000000000 +10000------11-1----------- 01011100000 +10000------111------------ 01011100000 +10000------11001---------- 00010100100 +10000------11000---------- 00101000111 +10000------10-------1----- 00110001101 +10000------10-------0----- 00000000000 +10000------0--00----1----- 00110001101 +10000------0--00----0----- 00000000000 +10000------0-1-11--------- 00110001100 +10000------0-00-----1----- 00110001101 +10000------0-00-----0----- 00000000000 +10000------011-0----1----- 00110001101 +10000------011-0----0----- 00000000000 +10000------011110---1----- 00110001101 +10000------011110---0----- 00000000000 +10000------0101-1--------- 00110001100 +10000------010110---1----- 00110001101 +10000------010110---0----- 00000000000 +10000------010100--------- 00001101001 +10000------0011-1--------- 00110001100 +10000------001110---1----- 00110001101 +10000------001110---0----- 00000000000 +10000------001100--------- 01010010010 +10000------00011----1----- 00110001101 +10000------00011----0----- 00000000000 +10000------00010----1----- 00110001101 +10000------00010----0----- 00000000000 +10000-11---011010--------- 01011110001 +10000-11---001010--------- 01011110001 +10000-10---011010--------- 01011110001 +10000-10---001010--------- 01011110001 +10000-01---011010--------- 01011110001 +10000-01---001010--------- 01011110001 +10000-00---011010--------- 01011110001 +10000-00---001010--------- 01011110001 +0111-----------0----1----- 00110001101 +0111-----------0----0----- 00000000000 +0111----------0-----1----- 00110001101 +0111----------0-----0----- 00000000000 +0111------11--11---------- 10110011100 +0111------01--11---1------ 11110011100 +0111------01--11---0------ 11110011100 +0111------00--11---1------ 11000011110 +0111------00--11---0------ 11100111110 +01111-----10--11---------- 10010011100 +01110-----10--11---------- 10010011100 +01101----------0----1----- 00110001101 +01101----------0----0----- 00000000000 +01101---------0-----1----- 00110001101 +01101---------0-----0----- 00000000000 +01101-----11--11---------- 10110011100 +01101-----10--11---------- 10010011100 +01101-----01--11---1------ 11110011100 +01101-----01--11---0------ 11110011100 +01101-----00--11---1------ 11000011110 +01101-----00--11---0------ 11100111110 +01100--------------------- 00011001000 +01011-----1--------------- 11110011100 +01011-----0--------------- 11100011100 +01010---------1-----1----- 00110001101 +01010---------1-----0----- 00000000000 +01010---------0-----1----- 00110001101 +01010---------0-----0----- 00000000000 +01001---------------1----- 00110001101 +01001---------------0----- 00000000000 +01000--------------------- 01001110010 +0011------11--0----------- 10110010110 +0011------11-1-0---------- 10110010110 +0011------11-0-1---------- 10110010110 +0011------11-010---------- 10110010110 +0011------1111------------ 10110010110 +0011------110111---------- 10110011100 +0011------01--0---1------- 11110010110 +0011------01--0---0------- 11110010110 +0011------01-1-0--1------- 11110010110 +0011------01-1-0--0------- 11110010110 +0011------01-0-1--1------- 11110010110 +0011------01-0-1--0------- 11110010110 +0011------01-010--1------- 11110010110 +0011------01-010--0------- 11110010110 +0011------0111----1------- 11110010110 +0011------0111----0------- 11110010110 +0011------010111--1------- 11110011100 +0011------010111--0------- 11110011100 +0011------00--0---1------- 11000010110 +0011------00--0---0------- 11100010110 +0011------00-1-0--1------- 11000010110 +0011------00-1-0--0------- 11100010110 +0011------00-0-1--1------- 11000010110 +0011------00-0-1--0------- 11100010110 +0011------00-010--1------- 11000010110 +0011------00-010--0------- 11100010110 +0011------0011----1------- 11000010110 +0011------0011----0------- 11100010110 +0011------000111--1------- 11000011100 +0011------000111--0------- 11100011100 +00111-----10--0----------- 10010010110 +00111-----10-1-0---------- 10010010110 +00111-----10-0-1---------- 10010010110 +00111-----10-010---------- 10010010110 +00111-----1011------------ 10010010110 +00111-----100111---------- 10010011100 +00110-----10--0----------- 10010010110 +00110-----10-1-0---------- 10010010110 +00110-----10-0-1---------- 10010010110 +00110-----10-010---------- 10010010110 +00110-----1011------------ 10010010110 +00110-----100111---------- 10010011100 +00101----------0----1----- 00110001101 +00101----------0----0----- 00000000000 +00101---------0-----1----- 00110001101 +00101---------0-----0----- 00000000000 +00101--------0------1----- 00110001101 +00101--------0------0----- 00000000000 +00101-------1-------1----- 00110001101 +00101-------1-------0----- 00000000000 +00101-------0111----1----- 00110001101 +00101-------0111----0----- 00000000000 +00100---------------1----- 00110001101 +00100---------------0----- 00000000000 +00011-----1--------------- 11110010110 +00011-----0--------------- 11100010110 +00010--------110----1----- 00110001101 +00010--------110----0----- 00000000000 +00010-------1-10----1----- 00110001101 +00010-------1-10----0----- 00000000000 +00010-------1-01----1----- 00110001101 +00010-------1-01----0----- 00000000000 +00010-------0101----1----- 00110001101 +00010-------0101----0----- 00000000000 +00010-------00------1----- 00110001101 +00010-------00------0----- 00000000000 +00010-----11-111---------- 10110010110 +00010-----11-100---------- 10110010110 +00010-----111-11---------- 10110010110 +00010-----111-00---------- 10110010110 +00010-----10-111---------- 10010010110 +00010-----10-100---------- 10010010110 +00010-----101-11---------- 10010010110 +00010-----101-00---------- 10010010110 +00010-----01-111--1------- 11110010110 +00010-----01-111--0------- 11110010110 +00010-----01-100--1------- 11110010110 +00010-----01-100--0------- 11110010110 +00010-----011-11--1------- 11110010110 +00010-----011-11--0------- 11110010110 +00010-----011-00--1------- 11110010110 +00010-----011-00--0------- 11110010110 +00010-----00-111--1------- 11000010110 +00010-----00-111--0------- 11100010110 +00010-----00-100--1------- 11000010110 +00010-----00-100--0------- 11100010110 +00010-----001-11--1------- 11000010110 +00010-----001-11--0------- 11100010110 +00010-----001-00--1------- 11000010110 +00010-----001-00--0------- 11100010110 +00001--------------------- 00010100100 +00000--------------------- 00011011001 diff --git a/espresso/examples/indust/bca b/espresso/examples/indust/bca new file mode 100644 index 0000000..6f5b05b --- /dev/null +++ b/espresso/examples/indust/bca @@ -0,0 +1,303 @@ +.i 26 +.o 46 +00110001101-----------0000 0000102222222221000000000000001000000000000000 +00110001100-----------0000 0000102222222221000000000000001000000000000000 +00000000000-----------0000 0110000000000000000100000000001000001000000000 +10110010110-----------0000 0000110201112220100010101100001010100010000100 +10010010110-----------0000 0000110201112220100010101100001010100010000100 +10110011000-----------0000 0000110201112220100010101100001000000000000000 +10110011100-----------0000 0000110201112220100010101100001000000000000000 +10000011000-----------0000 0000110201112220100010101100001000000000000000 +10010011100-----------0000 0000110201112220100010101100001000000000000000 +11110010110-----------0000 0000000000000000000000000000001000000000000000 +11110011000-----------0000 0000000000000000000000000000001000000000000000 +11110011100-----------0000 0000000000000000000000000000001000000000000000 +11100010110-----------0000 0000000000000000000000000000001000000000000000 +11100011000-----------0000 0000000000000000000000000000001000000000000000 +11100011100-----------0000 0000000000000000000000000000001000000000000000 +11100111110-----------0000 0000000000000000000000000000001000000000000000 +11000010110-----------0000 0000000000000000000000000000001000000000000000 +11000011000-----------0000 0000000000000000000000000000001000000000000000 +11000011100-----------0000 0000000000000000000000000000001000000000000000 +11000011110-----------0000 0000000000000000000000000000001000000000000000 +01011011101-----------0000 0000000000000000000000000000001000000000000000 +01011011010-----------0000 0000000000000000000000000000001000000000000000 +00011011001-----------0000 0000000000000000000000000000001000000000000000 +00101110000-----------0000 0000000000000000000000000000001000000000000000 +00010001010-----------0000 0000000000000000000000000000001000000000000000 +11011011101-----------0000 0000110201112220100100000000001000000000000000 +11011011100-----------0000 0000110201112220100100000000001000000000000000 +11011011111-----------0000 0000110201112220100100000000001000000000000000 +11011011110-----------0000 0000110201112220100100000000001000000000000000 +11011011001-----------0000 0000110201112220100100000000001000000000000000 +11011011000-----------0000 0000110201112220100100000000001000000000000000 +11011011011-----------0000 0000110201112220100100000000001000000000000000 +11011011010-----------0000 0000110201112220100100000000001000000000000000 +00010011100-----------0000 0000110201112220100100000000001000000000000000 +01011100000-----------0000 0000000000000000000000000010001000000000000000 +00010101000-----------0000 0000000000000000000000000010001000000000000000 +00010100100-----------0000 0000000000000000000000000010001000000000000000 +00000011110-----------0000 0000000000000000000000000010001000000000000000 +00000101100-----------0000 0000000000000000000000000001001001100000000000 +00000101110-----------0000 0000000000000000000000000001001001100000000000 +01001110010-----------0000 0000000000000000000000000001001001100000000000 +00101000111-----------0000 0000010000101000000000010010111100000000100000 +00010110111-----------0000 0000000000000000000000000000001000011100000000 +00000010111-----------0000 0000000000000000000000000000001000011100000000 +00000110111-----------0000 0000000000000000000000000000001000011100000000 +01010010010-----------0000 0000000000000000000000000000001000011100000000 +00010101111-----------0000 0000000000000000000000000000001000011100000000 +00110111001-----------0000 0000000000000000000000000000001000011100000000 +00110111000-----------0000 0000000000000000000000000000001000011100000000 +00100010000-----------0000 0000000000000000000000000000001000011100000000 +00100010010-----------0000 0000000000000000000000000000001000011100000000 +00111111101-----------0000 0000000000000000000000000000001000011100000000 +00100001011-----------0000 0000000000000000000000000000001000011100000000 +00111100001-----------0000 0000000000000000000000000000001000011100000000 +00111100101-----------0000 0000000000000000000000000000001000011100000000 +10111011111-----------0000 0000102222222220000000000000001000000000000000 +10111011110-----------0000 0000102222222220000000000000001000000000000000 +10111011001-----------0000 0000102222222220000000000000001000000000000000 +10111011000-----------0000 0000102222222220000000000000001000000000000000 +00011010100-----------0000 0000110201112221010101000000111000000000000000 +00011001000-----------0000 0000110201112221010101000000111000000000000000 +00010100010-----------0000 0000102222222220000000011000111000100000000010 +01011110001-----------0000 0000102222222220100000101000001100100000000000 +00101101011-----------0000 0000010000010110000000010000001000000000000000 +00101100011-----------0000 0000010000010110000000010000001000000000000000 +01111001010-----------0000 1010010001000000000000000000001000001100000000 +01111011011-----------0000 1010010001000000000000000000001000001100000000 +01111001011-----------0000 1010010001000000000000000000001000001100000000 +01111010010-----------0000 1010010001000000000000000000001000001100000000 +01111000010-----------0000 1010010001000000000000000000001000001100000000 +01111000011-----------0000 1010010001000000000000000000001000001100000000 +01111110010-----------0000 1010010001000000000000000000001000001100000000 +01111100010-----------0000 1010010001000000000000000000001000001100000000 +01111100011-----------0000 1010010001000000000000000000001000001100000000 +00110001011-----------0000 0000010000100000000000010000001000000000000001 +00110001001-----------0000 0000010000100000000000010000001000000000000001 +00111110011-----------0000 0000010000110000000000010000001000011100000000 +00000011001-----------0000 0000010000100100000000010010001000011000000000 +00001101001-----------0000 0000010000100100000000010010001000011000000000 +10111011011-----------0000 0000102222222221010100000000001000000000000000 +00110001101-----------0001 0000000000000000000000000000001000000000000000 +00110001100-----------0001 0000000000000000000000000000001000000000000000 +01011100000-----------0001 0000000000000000000000000000001000000000000000 +00010110111-----------0001 0000000000000000000000000000001000000000000000 +00000010111-----------0001 0000000000000000000000000000001000000000000000 +00000110111-----------0001 0000000000000000000000000000001000000000000000 +00010101000-----------0001 0000000000000000000000000000001000000000000000 +10111011111-----------0001 0000000000000000000000000000001000000000000000 +10111011001-----------0001 0000000000000000000000000000001000000000000000 +00010100100-----------0001 0000000000000000000000000000001000000000000000 +00010100010-----------0001 0000000000000000000000000000001000000000000000 +01010010010-----------0001 0000000000000000000000000000001000000000000000 +00010101111-----------0001 0000000000000000000000000000001000000000000000 +00110111001-----------0001 0000000000000000000000000000001000000000000000 +00110111000-----------0001 0000000000000000000000000000001000000000000000 +00100010000-----------0001 0000000000000000000000000000001000000000000000 +00100010010-----------0001 0000000000000000000000000000001000000000000000 +00111100001-----------0001 0000000000000000000000000000001000000000000000 +00111100101-----------0001 0000000000000000000000000000001000000000000000 +00111110011-----------0001 0000000000000000000000000000001000000000000000 +10111011011-----------0001 0000000000000000000000000000001000000000000000 +00101110000-----------0001 0000000000000000000000000000001000000000000000 +00000000000-----------0001 0000010000101000000000010010011000000000000000 +10110010110-----------0001 0000102222222220001001000000001000000000000000 +10110011000-----------0001 0000102222222220001001000000001000000000000000 +10110011100-----------0001 0000102222222220001001000000001000000000000000 +10010010110-----------0001 0000102222222220001001000000001000000000000000 +10000011000-----------0001 0000102222222220001001000000001000000000000000 +10010011100-----------0001 0000102222222220001001000000001000000000000000 +11110010110-----------0001 0000000000000000000000000010001000000000000001 +11110011000-----------0001 0000000000000000000000000010001000000000000001 +11110011100-----------0001 0000000000000000000000000010001000000000000001 +11100010110-----------0001 0000000000000000000000000000001000000000000001 +11100011000-----------0001 0000000000000000000000000000001000000000000001 +11100011100-----------0001 0000000000000000000000000000001000000000000001 +11100111110-----------0001 0000000000000000000000000000001000000000000001 +11000010110-----------0001 0000000000000000000000000000001000000000000001 +11000011000-----------0001 0000000000000000000000000000001000000000000001 +11000011100-----------0001 0000000000000000000000000000001000000000000001 +11000011110-----------0001 0000000000000000000000000000001000000000000001 +00101101011-----------0001 0000000000000000000000000000001000000000000001 +00101100011-----------0001 0000000000000000000000000000001000000000000001 +01111001010-----------0001 0000000000000000000000000000001000000000000001 +01111011011-----------0001 0000000000000000000000000000001000000000000001 +01111001011-----------0001 0000000000000000000000000000001000000000000001 +01111010010-----------0001 0000000000000000000000000000001000000000000001 +01111000010-----------0001 0000000000000000000000000000001000000000000001 +01111110010-----------0001 0000000000000000000000000000001000000000000001 +01111100010-----------0001 0000000000000000000000000000001000000000000001 +11011011101-----------0001 0000010100000000000000001100001000000000000000 +11011011100-----------0001 0000010010000000000000001100001000000000000000 +11011011111-----------0001 0000010001000000000000001100001000000000000000 +11011011110-----------0001 0000010000100000000000001100001000000000000000 +11011011001-----------0001 0000010000010000000000001100001000000000000000 +11011011000-----------0001 0000010000001000000000001100001000000000000000 +11011011011-----------0001 0000010000000100000000001100001000000000000000 +11011011010-----------0001 0000010000000010000000001100001000000000000000 +00000101100--------0--0001 0000102222222220100110101000001100000000000000 +00000101100--------1--0001 0000000000000000000000000000001000011000000000 +00000101110--------1--0001 0000000000000000000000000000001000011000000000 +00000101110--------0--0001 0000102222222220100100101000001100000000000000 +01011011101-----------0001 0000102222222220001000001000001000001100000000 +01011011010-----------0001 0000102222222220001010000000001011100010000000 +00011011001-----------0001 0000102222222220001010000000001011100010000000 +10111011110-----------0001 0000000000000000101000001000001000001100000000 +10111011000-----------0001 0000000000000000101000001000001000001100000000 +00011010100-----------0001 0000000000000000000000000000001100011000000000 +00010011100-----------0001 0000000000000000000000000000001100011000000000 +00011001000-----------0001 0000000000000000000000000000001100011000000000 +01111000011-----------0001 0000000000000000000000010100001000000000000001 +01111100011-----------0001 0000000000000000000000010100001000000000000001 +00111111101-----------0001 0000110211102221101000000000001000000000000000 +00100001011-----------0001 0000102222222220010000011001011100100000000010 +00110001011-----------0001 0000102222222221010001000001101000000000000000 +00110001001-----------0001 0000102222222221010001000001101000000000000000 +00000011001-----------0001 0000000000000000000000000010011000000000000000 +01001110010-----------0001 0000110201112221010100000000111000000000000000 +00001101001-----------0001 0000010000100110000000010010001000000000000000 +00000011110-----------0001 0000102222222220111000000000001000000000000000 +00000000000-----------0010 0000102222222221100000000000001000000000000000 +10110010110-----------0010 0000102222222220100100000000001100000000000000 +10110011100-----------0010 0000102222222220100100000000001100000000000000 +10010010110-----------0010 0000102222222220100100000000001100000000000000 +10010011100-----------0010 0000102222222220100100000000001100000000000000 +10110011000-----------0010 0000000000000000000000000000001000000000000000 +10000011000-----------0010 0000000000000000000000000000001000000000000000 +11110011000-----------0010 0000000000000000000000000000001000000000000000 +11011011101-----------0010 0000000000000000000000000000001000000000000000 +11011011100-----------0010 0000000000000000000000000000001000000000000000 +11011011111-----------0010 0000000000000000000000000000001000000000000000 +11011011110-----------0010 0000000000000000000000000000001000000000000000 +11011011001-----------0010 0000000000000000000000000000001000000000000000 +11011011000-----------0010 0000000000000000000000000000001000000000000000 +11011011011-----------0010 0000000000000000000000000000001000000000000000 +11011011010-----------0010 0000000000000000000000000000001000000000000000 +00000101100-----------0010 0000000000000000000000000000001000000000000000 +00000101110-----------0010 0000000000000000000000000000001000000000000000 +00010110111-----------0010 0000000000000000000000000000001000000000000000 +00000010111-----------0010 0000000000000000000000000000001000000000000000 +00000110111-----------0010 0000000000000000000000000000001000000000000000 +00000011110-----------0010 0000000000000000000000000000001000000000000000 +11100010110-----------0010 0000102222222220001010101000001010100010000100 +11000010110-----------0010 0000102222222220001010101000001010100010000100 +11100011000-----------0010 0000102222222220001010101000001000000000000000 +11100011100-----------0010 0000102222222220001010101000001000000000000000 +11100111110-----------0010 0000102222222220001010101000001000000000000000 +11000011000-----------0010 0000102222222220001010101000001000000000000000 +11000011100-----------0010 0000102222222220001010101000001000000000000000 +11000011110-----------0010 0000102222222220001010101000001000000000000000 +01011011010-----------0010 0000000000000000000000000000001100011000000000 +00011011001-----------0010 0000000000000000000000000000001100011000000000 +00101101011-----------0010 0000001011111110000000000001111000000000000000 +00101100011-----------0010 0000102222222220000000000001111000000000000000 +00110111001-----------0010 0001010101001000000000100110001000000000000000 +00110111000-----------0010 0001010101001000000000100110001000000000000000 +01111001010-----------0010 0000102222222220100010000000001011100010000000 +01111011011-----------0010 0000102222222220100010000000001010000010001000 +01111001011-----------0010 0000102222222220100010000000001010000010000000 +01111010010-----------0010 0000102222222220100010000000001010100010001000 +01111000010-----------0010 0000102222222220100010000000001010100010000000 +01111000011-----------0010 0000102222222220100010000000001010100010000000 +01111110010-----------0010 0000102222222220010010000000001010100010001000 +01111100010-----------0010 0000102222222220010010000000001010100010000000 +01111100011-----------0010 0000102222222220010010000000001010100010000000 +00111111101-----------0010 0000102222222220001000100000001000000000000000 +00110001011-----------0010 0000102222222220111000000001111000000000000000 +00110001001-----------0010 0000102222222220111000000001111000000000000000 +01001110010-----------0010 0000000000000000000000000010011100011000000000 +00101110000--------0--0010 0000102222222221101000000001011100000000000000 +00101110000--------1--0010 0000000000000000000000000000001000011100000000 +00000000000-----------0011 0000102222222221101000000000001000000000000000 +10110011000-----------0011 0000102222222220100100000000001000000000000000 +10000011000-----------0011 0000102222222220100100000000001000000000000000 +11110011000-----------0011 0000102222222220100100000000001000000000000000 +11100011000-----------0011 0000102222222220100100000000001000000000000000 +11000011000-----------0011 0000102222222220100100000000001000000000000000 +11100010110-----------0011 0000102222222220100100000000001100000000000000 +11100011100-----------0011 0000102222222220100100000000001100000000000000 +11100111110-----------0011 0000102222222220100100000000001100000000000000 +11000010110-----------0011 0000102222222220100100000000001100000000000000 +11000011100-----------0011 0000102222222220100100000000001100000000000000 +11000011110-----------0011 0000102222222220100100000000001100000000000000 +11011011101-----------0011 0001110001000000011000000000001000000000000010 +11011011100-----------0011 0001110001000000011000000000001000000000000010 +11011011111-----------0011 0001110001000000011000000000001000000000000010 +11011011110-----------0011 0001110001000000011000000000001000000000000010 +11011011001-----------0011 0001110001000000011000000000001000000000000010 +11011011000-----------0011 0001110001000000011000000000001000000000000010 +11011011011-----------0011 0001110001000000011000000000001000000000000010 +11011011010-----------0011 0001110001000000011000000000001000000000000010 +00101101011-----------0011 0000102222222220111000000000001000000000000000 +00101100011-----------0011 0000102222222220111000000000001000000000000000 +00110111001-----------0011 0000000000000000000000000000001000000000000000 +00110111000-----------0011 0000000000000000000000000000001000000000000000 +00111111101-----------0011 0000000000000000000000000000001000000000000000 +00101110000-----------0011 0000000000000000000000000000001000000000000000 +01111001010-----------0011 0000102222222220010010000000001010100011000000 +01111001011-----------0011 0000102222222220010010000000001010100011000000 +01111000010-----------0011 0000102222222220010010000000001010100011000000 +01111000011-----------0011 0000102222222220010010000000001010100011000000 +01111011011-----------0011 0000102222222220010010000000001010100011001000 +01111010010-----------0011 0000102222222220010010000000001010100011001000 +01111110010-----------0011 0000102222222220100010000000001010100011001000 +01111100010-----------0011 0000102222222220100010000000001010100011000000 +01111100011-----------0011 0000102222222220100010000000001010100011000000 +00110001011-----------0011 0000010000101000000000010010011100000000000000 +00110001001-----------0011 0000010000101000000000010010011100000000000000 +00000000000-----------0100 0000102222222220101010000000001100000000000000 +10110011000-----------0100 0000001111111000000001000000001000000000000000 +10000011000-----------0100 0000001111111000000001000000001000000000000000 +11110011000-----------0100 0000001111111000000001000000001000000000000000 +11100011000-----------0100 0000001111111000000001000000001000000000000000 +11000011000-----------0100 0000001111111000000001000000001000000000000000 +11011011101-----------0100 0000000000000000000000000000001000000000000000 +11011011100-----------0100 0000000000000000000000000000001000000000000000 +11011011111-----------0100 0000000000000000000000000000001000000000000000 +11011011110-----------0100 0000000000000000000000000000001000000000000000 +11011011001-----------0100 0000000000000000000000000000001000000000000000 +11011011000-----------0100 0000000000000000000000000000001000000000000000 +11011011011-----------0100 0000000000000000000000000000001000000000000000 +11011011010-----------0100 0000000000000000000000000000001000000000000000 +00110111001-----------0100 0000000000000000000000000000001000000000000000 +00110111000-----------0100 0000000000000000000000000000001000000000000000 +00101101011-----------0100 0000102222222220100000001100001000000000000000 +00101100011-----------0100 0000102222222220100000001100001000000000000000 +01111001010-----------0100 0000000000000000000000000000001000011100000000 +01111011011-----------0100 0000000000000000000000000000001000011100000000 +01111001011-----------0100 0000000000000000000000000000001000011100000000 +01111010010-----------0100 0000000000000000000000000000001000011100000000 +01111000010-----------0100 0000000000000000000000000000001000011100000000 +01111000011-----------0100 0000000000000000000000000000001000011100000000 +01111110010-----------0100 0000000000000000000000000000001000011100000000 +01111100010-----------0100 0000000000000000000000000000001000011100000000 +01111100011-----------0100 0000000000000000000000000000001000011100000000 +10110011000-----------0101 0000102222222221010001000001101000000000000000 +10000011000-----------0101 0000102222222221010001000001101000000000000000 +11110011000-----------0101 0000102222222221010001000001101000000000000000 +11100011000-----------0101 0000102222222221010001000001101000000000000000 +11000011000-----------0101 0000102222222221010001000001101000000000000000 +00101101011-----------0101 0000000000000000000000000000001000000000000000 +00101100011-----------0101 0000000000000000000000000000001000000000000000 +01111001010-----------0101 0000000000000000000000000000001000000000000000 +01111011011-----------0101 0000000000000000000000000000001000000000000000 +01111001011-----------0101 0000000000000000000000000000001000000000000000 +01111010010-----------0101 0000000000000000000000000000001000000000000000 +01111000010-----------0101 0000000000000000000000000000001000000000000000 +01111000011-----------0101 0000000000000000000000000000001000000000000000 +01111110010-----------0101 0000000000000000000000000000001000000000000000 +01111100010-----------0101 0000000000000000000000000000001000000000000000 +01111100011-----------0101 0000000000000000000000000000001000000000000000 +10110011000-----------0110 0000102222222220100000000011011000000000110000 +10000011000-----------0110 0000102222222220100000000011011000000000110000 +11110011000-----------0110 0000102222222220100000000011011000000000110000 +11100011000-----------0110 0000102222222220100000000011011000000000110000 +11000011000-----------0110 0000102222222220100000000011011000000000110000 +00101101011-----------0110 0001110000000010100000100101011000000000000000 +00101100011-----------0110 0001110000000010100000100101011000000000000000 +00101101011--------0--0111 0000000000000000000000000000001100000000000000 +00101100011--------0--0111 0000000000000000000000000000001100000000000000 +00101101011--------1--0111 0000000000000000000000000000001100011100000000 +00101100011--------1--0111 0000000000000000000000000000001100011100000000 diff --git a/espresso/examples/indust/bcb b/espresso/examples/indust/bcb new file mode 100644 index 0000000..2b0d700 --- /dev/null +++ b/espresso/examples/indust/bcb @@ -0,0 +1,301 @@ +.i 26 +.o 39 +00110001101-----------0000 000101010101000000000000100001000000000 +00110001100-----------0000 000101010110010000000000100001000000000 +00000000000-----------0000 000001000011100000000010000001001000000 +10110010110-----------0000 000000000000000000000000000001001000000 +10110011000-----------0000 000000000000000000000000000001001000000 +10110011100-----------0000 000000000000000000000000000001001000000 +10010010110-----------0000 000000000000000000000000000001001000000 +10000011000-----------0000 000000000000000000000000000001001000000 +10010011100-----------0000 000000000000000000000000000001001000000 +11110010110-----------0000 000000000000000000000000000001001000000 +11110011000-----------0000 000000000000000000000000000001001000000 +11110011100-----------0000 000000000000000000000000000001001000000 +11100010110-----------0000 000000000000000000000000000001001000000 +11100011000-----------0000 000000000000000000000000000001001000000 +11100011100-----------0000 000000000000000000000000000001001000000 +11100111110-----------0000 000000000000000000000000000001001000000 +11000010110-----------0000 000000000000000000000000000001001000000 +11000011000-----------0000 000000000000000000000000000001001000000 +11000011100-----------0000 000000000000000000000000000001001000000 +11000011110-----------0000 000000000000000000000000000001001000000 +11011011101-----------0000 000000000000000000000000000001001000000 +11011011100-----------0000 000000000000000000000000000001001000000 +11011011111-----------0000 000000000000000000000000000001001000000 +11011011110-----------0000 000000000000000000000000000001001000000 +11011011001-----------0000 000000000000000000000000000001001000000 +11011011000-----------0000 000000000000000000000000000001001000000 +11011011011-----------0000 000000000000000000000000000001001000000 +11011011010-----------0000 000000000000000000000000000001001000000 +01011011101-----------0000 000000000000000000000000000001001000000 +01011011010-----------0000 000000000000000000000000000001001000000 +10111011111-----------0000 000000000000000000000000000001001000000 +10111011110-----------0000 000000000000000000000000000001001000000 +10111011001-----------0000 000000000000000000000000000001001000000 +10111011000-----------0000 000000000000000000000000000001001000000 +01011100000-----------0000 000010222222222010010000000001001000000 +00010101000-----------0000 000010222222222010010000000001001000000 +00010100100-----------0000 000010222222222010010000000001001000000 +00000101100-----------0000 000000000000000000000000010001000000000 +00000101110-----------0000 000000000000000000000000010001000000000 +00101000111-----------0000 000000000000000000000000001101100000000 +00010110111-----------0000 000000000000000000000000000101000000000 +00000010111-----------0000 000000000000000000000000000101000000000 +00000110111-----------0000 000000000000000000000000000101000000000 +00011011001-----------0000 000000000000000000000000000001000000000 +00011010100-----------0000 000000000000000000000000000001000000000 +00010011100-----------0000 000000000000000000000000000001000000000 +01010010010-----------0000 000000000000000000000000000001000000000 +00011001000-----------0000 000000000000000000000000000001000000000 +10111011011-----------0000 000000000000000000000000000001000000000 +00010100010-----------0000 000000000000000000000000000001000110000 +01011110001-----------0000 000000000000000000000000000001100110000 +00010101111-----------0000 000010222222222011100000001001001000000 +00101101011-----------0000 000010222222222110100000001011000000000 +00101100011-----------0000 000010222222222110100000001011000000000 +00110111001-----------0000 000010222222222001010010000001000000000 +00110111000-----------0000 000010222222222001010010000001000000000 +00100010000-----------0000 000010222222222110000000000001000000000 +00100010010-----------0000 000010222222222110000000000001000000000 +00101110000-----------0000 000010222222222110000000000001000000000 +01111001010-----------0000 000010222222222001000010000001000000000 +01111011011-----------0000 000010222222222001000010000001000000000 +01111001011-----------0000 000010222222222001000010000001000000000 +01111010010-----------0000 000010222222222001000010000001000000000 +01111000010-----------0000 000010222222222001000010000001000000000 +01111000011-----------0000 000010222222222001000010000001000000000 +01111110010-----------0000 000010222222222001000010000001000000000 +01111100010-----------0000 000010222222222001000010000001000000000 +01111100011-----------0000 000010222222222001000010000001000000000 +00111111101-----------0000 000010222222222010000000000001000000000 +00100001011-----------0000 000010222222222001010010000001001000000 +00111100001-----------0000 000010222222222011100000000001000000000 +00111100101-----------0000 000010222222222011100000000001000000000 +00110001011-----------0000 000000000000000000000010100001000000000 +00110001001-----------0000 000000000000000000000010100001000000000 +00111110011-----------0000 000000000000000000000000001101000000000 +00000011001-----------0000 000000000000000000000000000111000000000 +01001110010-----------0000 000010222222222001101000011101000001100 +00001101001-----------0000 000000000000000000000000001011000000000 +00000011110-----------0000 000011010000222010000001100001000000000 +00010001010-----------0000 000111100110000001101000001001000100010 +00110001101-----------0001 000000000000000000000000000001000000000 +00110001100-----------0001 000000000000000000000000000001000000000 +01011011101-----------0001 000000000000000000000000000001000000000 +10111011111-----------0001 000000000000000000000000000001000000000 +10111011110-----------0001 000000000000000000000000000001000000000 +10111011001-----------0001 000000000000000000000000000001000000000 +10111011000-----------0001 000000000000000000000000000001000000000 +01010010010-----------0001 000000000000000000000000000001000000000 +00010101111-----------0001 000000000000000000000000000001000000000 +00110111001-----------0001 000000000000000000000000000001000000000 +00110111000-----------0001 000000000000000000000000000001000000000 +00100010000-----------0001 000000000000000000000000000001000000000 +00100010010-----------0001 000000000000000000000000000001000000000 +00111100001-----------0001 000000000000000000000000000001000000000 +00111100101-----------0001 000000000000000000000000000001000000000 +00111110011-----------0001 000000000000000000000000000001000000000 +00000011001-----------0001 000000000000000000000000000001000000000 +10111011011-----------0001 000000000000000000000000000001000000000 +01001110010-----------0001 000000000000000000000000000001000000000 +00101110000-----------0001 000000000000000000000000000001000000000 +00000000000-----------0001 000000000000000000000000000101000000000 +00010110111-----------0001 000000000000000000000000000101000000000 +00000010111-----------0001 000000000000000000000000000101000000000 +00000110111-----------0001 000000000000000000000000000101000000000 +10110010110-----------0001 000011011100222000010000000001000000000 +10110011000-----------0001 000011011100222000010000000001000000000 +10110011100-----------0001 000011011100222000010000000001000000000 +10010010110-----------0001 000011011100222000010000010011000000000 +10000011000-----------0001 000011011100222000010000010011000000000 +10010011100-----------0001 000011011100222000010000010011000000000 +11110010110-----------0001 000010222222222010010000000001000000000 +11110011000-----------0001 000010222222222010010000000001000000000 +11110011100-----------0001 000010222222222010010000000001000000000 +11100010110-----------0001 000011010011222010110011000001000000010 +11100011000-----------0001 000011010011222010110011000001000000010 +11100011100-----------0001 000011010011222010110011000001000000010 +11100111110-----------0001 000011010011222010110011000001000000010 +11000010110-----------0001 011011020111222010110011000001000000010 +11000011000-----------0001 011011020111222010110011000001000000010 +11000011100-----------0001 011011020111222010110011000001000000010 +11000011110-----------0001 011011020111222010110011000001000000010 +11011011101-----------0001 000000000000000000000000000001000000001 +11011011100-----------0001 000000000000000000000000000001000000001 +11011011111-----------0001 000000000000000000000000000001000000001 +11011011110-----------0001 000000000000000000000000000001000000001 +11011011001-----------0001 000000000000000000000000000001000000001 +11011011000-----------0001 000000000000000000000000000001000000001 +11011011011-----------0001 000000000000000000000000000001000000001 +11011011010-----------0001 000000000000000000000000000001000000001 +01011011010-----------0001 000000000000000000000000000001000000001 +00011011001-----------0001 000000000000000000000000000001000000001 +01011100000-----------0001 000110222222222000101000001001000100000 +00010100100-----------0001 000110222222222000101000001001000100000 +00010100010-----------0001 000110222222222000101000001001000100000 +00000101100--------0--0001 000000000000000000000000000001111000000 +00000101110--------0--0001 000000000000000000000000000001111000000 +00000101100--------1--0001 000000000000000000000000000001001000000 +00000101110--------1--0001 000000000000000000000000000001001000000 +00010101000-----------0001 000110222222222000101000000001000100000 +00011010100-----------0001 000000000000000000000000000001100000000 +00010011100-----------0001 000000000000000000000000000001100000000 +00011001000-----------0001 000000000000000000000000000001100000000 +00101101011-----------0001 000010222222222010000001000001000000000 +00101100011-----------0001 000010222222222010000001000001000000000 +01111001010-----------0001 110010222222222110000011000001000000010 +01111011011-----------0001 110010222222222110000011000001000000010 +01111001011-----------0001 110010222222222110000011000001000000010 +01111010010-----------0001 110010222222222110000011000001000000010 +01111000010-----------0001 110010222222222110000011000001000000010 +01111000011-----------0001 110010222222222110000011000001000000010 +01111110010-----------0001 110010222222222110000011000001000000010 +01111100010-----------0001 110010222222222110000011000001000000010 +01111100011-----------0001 110010222222222110000011000001000000010 +00111111101-----------0001 000000111100111000000001100001000000000 +00100001011-----------0001 110000000000000000000000000001100000000 +00110001011-----------0001 000000000000000000000000010011000000000 +00110001001-----------0001 000000000000000000000000010011000000000 +00001101001-----------0001 000000000000000000000000001011000100000 +00000011110-----------0001 000000100110000000000000000001000000000 +00000000000-----------0010 000101000000100000000100110011000000000 +10110010110-----------0010 000000000000000000000000000001100000001 +10010010110-----------0010 000000000000000000000000000001100000001 +10110011000-----------0010 000000000000000000000000000001000000000 +10000011000-----------0010 000000000000000000000000000001000000000 +11110011000-----------0010 000000000000000000000000000001000000000 +00000101100-----------0010 000000000000000000000000000001000000000 +00000101110-----------0010 000000000000000000000000000001000000000 +00110111001-----------0010 000000000000000000000000000001000000000 +00110111000-----------0010 000000000000000000000000000001000000000 +00111111101-----------0010 000000000000000000000000000001000000000 +00000011110-----------0010 000000000000000000000000000001000000000 +10110011100-----------0010 000000000000000000000000000001100000000 +10010011100-----------0010 000000000000000000000000000001100000000 +01011011010-----------0010 000000000000000000000000000001100000000 +00011011001-----------0010 000000000000000000000000000001100000000 +01001110010-----------0010 000000000000000000000000000001100000000 +11100010110-----------0010 000011011100222000010001100001000000000 +11100011000-----------0010 000011011100222000010001100001000000000 +11100011100-----------0010 000011011100222000010001100001000000000 +11100111110-----------0010 000011011100222000010001100001000000000 +11000010110-----------0010 000011011100222000010001100001000000000 +11000011000-----------0010 000011011100222000010001100001000000000 +11000011100-----------0010 000011011100222000010001100001000000000 +11000011110-----------0010 000011011100222000010001100001000000000 +11011011101-----------0010 000111000010000000100011000001000000000 +11011011100-----------0010 000111000010000000100011000001000000000 +11011011111-----------0010 000111000010000000100011000001000000000 +11011011110-----------0010 000111000010000000100011000001000000000 +11011011001-----------0010 000111000010000000100011000001000000000 +11011011000-----------0010 000111000010000000100011000001000000000 +11011011011-----------0010 000111000010000000100011000001000000000 +11011011010-----------0010 000111000010000000100011000001000000000 +00010110111-----------0010 000010222222222010010001100001000000000 +00000010111-----------0010 000010222222222010000001100001011000000 +00000110111-----------0010 000010222222222010000001100001011000000 +00101101011-----------0010 000000100111101000000100001101000000000 +00101100011-----------0010 000000100111101000000100001101000000000 +01111001010-----------0010 000000000000000000000000000001000000001 +01111011011-----------0010 000000000000000000000000000001000000001 +01111001011-----------0010 000000000000000000000000000001000000001 +01111010010-----------0010 000000000000000000000000000001000000001 +01111000010-----------0010 000000000000000000000000000001000000001 +01111000011-----------0010 000000000000000000000000000001000000001 +01111110010-----------0010 000000000000000000000000000001000000001 +01111100010-----------0010 000000000000000000000000000001000000001 +01111100011-----------0010 000000000000000000000000000001000000001 +00110001011-----------0010 000000111111100000001000001101000000000 +00110001001-----------0010 000000111111100000001000001101000000000 +00101110000--------0--0010 000000100111101000000100001111100000000 +00101110000--------1--0010 000000000000000000000000000001000000000 +00000000000-----------0011 000101010110001000000100000001000000000 +10110011000-----------0011 000001000011100000000010000001000010000 +10000011000-----------0011 000001000011100000000010000001000010000 +11110011000-----------0011 000001000011100000000010000001000010000 +11100011000-----------0011 000001000011100000000010000001000010000 +11000011000-----------0011 000001000011100000000010000001000010000 +11100010110-----------0011 000000000000000000000000000001100000001 +11000010110-----------0011 000000000000000000000000000001100000001 +11100011100-----------0011 000000000000000000000000000001100000000 +11100111110-----------0011 000000000000000000000000000001100000000 +11000011100-----------0011 000000000000000000000000000001100000000 +11000011110-----------0011 000000000000000000000000000001100000000 +11011011101-----------0011 000000000000000000000000000001000000000 +11011011100-----------0011 000000000000000000000000000001000000000 +11011011111-----------0011 000000000000000000000000000001000000000 +11011011110-----------0011 000000000000000000000000000001000000000 +11011011001-----------0011 000000000000000000000000000001000000000 +11011011000-----------0011 000000000000000000000000000001000000000 +11011011011-----------0011 000000000000000000000000000001000000000 +11011011010-----------0011 000000000000000000000000000001000000000 +00111111101-----------0011 000000000000000000000000000001000000000 +00101110000-----------0011 000000000000000000000000000001000000000 +00101101011-----------0011 000101000000010000000110000001000000000 +00101100011-----------0011 000101000000010000000110000001000000000 +00110111001-----------0011 000010222222222001100100100001000000010 +00110111000-----------0011 000010222222222001100100100001000000010 +01111001010-----------0011 000000000000000000000000000001000000001 +01111011011-----------0011 000000000000000000000000000001000000001 +01111001011-----------0011 000000000000000000000000000001000000001 +01111010010-----------0011 000000000000000000000000000001000000001 +01111000010-----------0011 000000000000000000000000000001000000001 +01111000011-----------0011 000000000000000000000000000001000000001 +01111110010-----------0011 000001000000100000000000000001000000001 +01111100010-----------0011 000001000000100000000000000001000000001 +01111100011-----------0011 000001000000100000000000000001000000001 +00110001011-----------0011 000001000001010000000011001101100000000 +00110001001-----------0011 000001000001010000000011001101100000000 +00000000000-----------0100 000000000000000000000000000001100000000 +10110011000-----------0100 000000000000000000000000010011000000000 +10000011000-----------0100 000000000000000000000000010011000000000 +11110011000-----------0100 000000000000000000000000010011000000000 +11100011000-----------0100 000000000000000000000000010011000000000 +11000011000-----------0100 000000000000000000000000010011000000000 +11011011101-----------0100 000000000000000000000000000001000000000 +11011011100-----------0100 000000000000000000000000000001000000000 +11011011111-----------0100 000000000000000000000000000001000000000 +11011011110-----------0100 000000000000000000000000000001000000000 +11011011001-----------0100 000000000000000000000000000001000000000 +11011011000-----------0100 000000000000000000000000000001000000000 +11011011011-----------0100 000000000000000000000000000001000000000 +11011011010-----------0100 000000000000000000000000000001000000000 +01111001010-----------0100 000000000000000000000000000001000000000 +01111011011-----------0100 000000000000000000000000000001000000000 +01111001011-----------0100 000000000000000000000000000001000000000 +01111010010-----------0100 000000000000000000000000000001000000000 +01111000010-----------0100 000000000000000000000000000001000000000 +01111000011-----------0100 000000000000000000000000000001000000000 +01111110010-----------0100 000000000000000000000000000001000000000 +01111100010-----------0100 000000000000000000000000000001000000000 +01111100011-----------0100 000000000000000000000000000001000000000 +00101101011-----------0100 000000000000000000000000010001000000000 +00101100011-----------0100 000000000000000000000000010001000000000 +00110111001-----------0100 000000000000000000000000010011000100000 +00110111000-----------0100 000000000000000000000000010011000100000 +10110011000-----------0101 000001000001010000000011010011000000000 +10000011000-----------0101 000001000001010000000011010011000000000 +11110011000-----------0101 000001000001010000000011010011000000000 +11100011000-----------0101 000001000001010000000011010011000000000 +11000011000-----------0101 000001000001010000000011010011000000000 +00101101011-----------0101 000010222222222010000110001011000000000 +00101100011-----------0101 000010222222222010000110001011000000000 +01111001010-----------0101 000000000000000000000000000001000000000 +01111011011-----------0101 000000000000000000000000000001000000000 +01111001011-----------0101 000000000000000000000000000001000000000 +01111010010-----------0101 000000000000000000000000000001000000000 +01111000010-----------0101 000000000000000000000000000001000000000 +01111000011-----------0101 000000000000000000000000000001000000000 +01111110010-----------0101 000000000000000000000000000001000000000 +01111100010-----------0101 000000000000000000000000000001000000000 +01111100011-----------0101 000000000000000000000000000001000000000 +10110011000-----------0110 000000000010111000000010000001000000000 +10000011000-----------0110 000000000010111000000010000001000000000 +11110011000-----------0110 000000000010111000000010000001000000000 +11100011000-----------0110 000000000010111000000010000001000000000 +11000011000-----------0110 000000000010111000000010000001000000000 +00101101011-----------0110 000000000000000000000000010001000000000 +00101100011-----------0110 000000000000000000000000010001000000000 +00101101011-----------0111 000010222222222010000000100001100000000 +00101100011-----------0111 000010222222222010000000100001100000000 diff --git a/espresso/examples/indust/bcc b/espresso/examples/indust/bcc new file mode 100644 index 0000000..ffac043 --- /dev/null +++ b/espresso/examples/indust/bcc @@ -0,0 +1,247 @@ +.i 26 +.o 45 +00110001101-----------0000 000000000000000000000000000001000000000000000 +00110001100-----------0000 000000000000000000000000000001000000000000000 +11011011101-----------0000 000000000000000000000000000001000000000000000 +11011011100-----------0000 000000000000000000000000000001000000000000000 +11011011111-----------0000 000000000000000000000000000001000000000000000 +11011011110-----------0000 000000000000000000000000000001000000000000000 +11011011001-----------0000 000000000000000000000000000001000000000000000 +11011011000-----------0000 000000000000000000000000000001000000000000000 +11011011011-----------0000 000000000000000000000000000001000000000000000 +11011011010-----------0000 000000000000000000000000000001000000000000000 +00010110111-----------0000 000000000000000000000000000001000000000000000 +00000010111-----------0000 000000000000000000000000000001000000000000000 +00000110111-----------0000 000000000000000000000000000001000000000000000 +01010010010-----------0000 000000000000000000000000000001000000000000000 +10111011011-----------0000 000000000000000000000000000001000000000000000 +01001110010-----------0000 000000000000000000000000000001000000000000000 +00000000000-----------0000 000000000000000000000000001101000000000000001 +10110010110-----------0000 000102222222220101001011000001000000000000010 +10110011000-----------0000 000102222222220101001011000001000000000000010 +10110011100-----------0000 000102222222220101001011000001000000000000010 +10010010110-----------0000 000102222222220101001011000001000000000000010 +10000011000-----------0000 000102222222220101001011000001000000000000010 +10010011100-----------0000 000102222222220101001011000001000000000000010 +11110010110-----------0000 000102222222220001010101000001010100010000100 +11110011000-----------0000 000102222222220001010101000001000000000000000 +11110011100-----------0000 000102222222220001010101000001000000000000000 +11100010110-----------0000 000102222222220001010101000001010100010000000 +11100011000-----------0000 000102222222220001010101000001010100010000000 +11100011100-----------0000 000102222222220001010101000001010100010000000 +11000010110-----------0000 000102222222220001010101000001010100010000000 +11000011000-----------0000 000102222222220001010101000001010100010000000 +11000011100-----------0000 000102222222220001010101000001010100010000000 +11100111110-----------0000 000102222222220001010101000001010000010000000 +11000011110-----------0000 000102222222220001010101000001010000010000000 +01011100000-----------0000 000000000000000000000000000001000011000000000 +00010101000-----------0000 000000000000000000000000000001000011000000000 +00010100100-----------0000 000000000000000000000000000001000011000000000 +00000101100-----------0000 000102222222220100010001100111000000000000000 +00000101110-----------0000 000102222222220100010001100111000000000000000 +01011011101-----------0000 000102222222221010001000000111000000000000000 +01011011010-----------0000 000102222222221010001000000111000000000000000 +10111011111-----------0000 000102222222220010000001000001000001100000000 +10111011110-----------0000 000102222222220010010000000001011100010000000 +10111011001-----------0000 000102222222220001000001000001000001100000000 +10111011000-----------0000 000102222222220001010000000001011100010000000 +00011011001-----------0000 000102222222221010001000001101000000000000000 +00011010100-----------0000 000000000000000000000000000001000000000000001 +00010011100-----------0000 000000000000000000000000000001000000000000001 +00010100010-----------0000 000102222222220011000001100001000000000000000 +00010101111-----------0000 000001111111000000001000000001000000000000000 +00101101011-----------0000 000000010000000000000000010111000000000110000 +00101100011-----------0000 000000110000000000000000010111000000000110000 +00110111001-----------0000 110000000000000000000000000001000000000000000 +00110111000-----------0000 110000000000000000000000000001000000000000000 +00100001011-----------0000 110000000000000000000000000001000000000000000 +00100010000-----------0000 001010000100000000000100100001000000000000000 +00100010010-----------0000 000001111011110000000100100001000000000000000 +01111001010-----------0000 000000000000000000000000001101000011000000000 +01111011011-----------0000 000000000000000000000000001101000011000000000 +01111001011-----------0000 000000000000000000000000001101000011000000000 +01111010010-----------0000 000000000000000000000000001101000011000000000 +01111000010-----------0000 000000000000000000000000001101000011000000000 +01111000011-----------0000 000000000000000000000000001101000011000000000 +01111110010-----------0000 000000000000000000000000001101000011000000000 +01111100010-----------0000 000000000000000000000000001101000011000000000 +01111100011-----------0000 000000000000000000000000001101000011000000000 +00111111101-----------0000 000000000110000000100000000001000000000000000 +00111100001-----------0000 000001111011110000000110000001000000000000000 +00111100101-----------0000 001010000100000000000110000001000000000000000 +00110001011-----------0000 000010001010000000010000000001010100010000000 +00111110011-----------0000 000102222222221111001000000001000000000000000 +00000011001-----------0000 000000000000000000000000010011000000000000000 +00010001010-----------0000 000000000000000000000000010011000000000000000 +00011001000-----------0000 000000000000000000000000010011000000000000001 +00001101001-----------0000 000102222222221100000000010011000000000000000 +00000011110-----------0000 000001000000000000000000000001000000000000000 +00101110000-----------0000 000000000100000000000000010111000000000110000 +00110001001-----------0000 000010000100000000010000000001010100010000000 +00110001101-----------0001 000000000000000000000000000001000000000000000 +00110001100-----------0001 000000000000000000000000000001000000000000000 +00000101100-----------0001 000000000000000000000000000001000000000000000 +00000101110-----------0001 000000000000000000000000000001000000000000000 +00010100100-----------0001 000000000000000000000000000001000000000000000 +00111111101-----------0001 000000000000000000000000000001000000000000000 +00101110000-----------0001 000000000000000000000000000001000000000000000 +00000000000-----------0001 000102222222221001001000001101000000000000000 +10110010110-----------0001 000000000000000000000000000111000011000000000 +10110011000-----------0001 000000000000000000000000000111000011000000000 +10110011100-----------0001 000000000000000000000000000111000011000000000 +10010010110-----------0001 000000000000000000000000000111000011000000000 +10000011000-----------0001 000000000000000000000000000111000011000000000 +10010011100-----------0001 000000000000000000000000000111000011000000000 +11110010110-----------0001 000000000000000000000000000001100011000000000 +11110011100-----------0001 000000000000000000000000000001100011000000000 +01011011101-----------0001 000000000000000000000000000001100011000000000 +10111011111-----------0001 000000000000000000000000000001100011000000000 +10111011110-----------0001 000000000000000000000000000001100011000000000 +10111011001-----------0001 000000000000000000000000000001100011000000000 +10111011000-----------0001 000000000000000000000000000001100011000000000 +10111011011-----------0001 000000000000000000000000000001100011000000000 +11110011000-----------0001 000000000000000000000000000001000011000000000 +11100010110-----------0001 000000000000000000000000000001000011000000000 +11100011000-----------0001 000000000000000000000000000001000011000000000 +11100011100-----------0001 000000000000000000000000000001000011000000000 +11100111110-----------0001 000000000000000000000000000001000011000000000 +11000010110-----------0001 000000000000000000000000000001000011000000000 +11000011000-----------0001 000000000000000000000000000001000011000000000 +11000011100-----------0001 000000000000000000000000000001000011000000000 +11000011110-----------0001 000000000000000000000000000001000011000000000 +00110111001-----------0001 000000000000000000000000000001000011000000000 +00110111000-----------0001 000000000000000000000000000001000011000000000 +11011011101-----------0001 000110211112220101100000000001000000000000000 +11011011100-----------0001 000110211112220101100000000001000000000000000 +11011011111-----------0001 000110211112220101100000000001000000000000000 +11011011110-----------0001 000110211112220101100000000001000000000000000 +11011011001-----------0001 000110211112220101100000000001000000000000000 +11011011000-----------0001 000110211112220101100000000001000000000000000 +11011011011-----------0001 000110211112220101100000000001000000000000000 +11011011010-----------0001 000110211112220101100000000001000000000000000 +01011100000-----------0001 000000000000000000000000010011000000000000000 +00010101000-----------0001 000000000000000000000000010011000000000000000 +00010100010-----------0001 000000000000000000000000010011000000000000000 +00001101001-----------0001 000000000000000000000000010011000000000000000 +00010110111-----------0001 000102222222220010000000000001000000000000000 +00000010111-----------0001 000102222222220010000000000001000000000000000 +00000110111-----------0001 000102222222220010000000000001000000000000000 +01011011010-----------0001 000102222222220101000001000001000001100000000 +00011011001-----------0001 000102222222220101000001000001000001100000000 +00101101011-----------0001 000000000000000000000000001101001000000000000 +00101100011-----------0001 000000000000000000000000001101001000000000000 +01111001010-----------0001 000001111110110000000100100001000000000000000 +01111011011-----------0001 000001111110110000000100100001000000000000000 +01111001011-----------0001 000001111110110000000100100001000000000000000 +01111010010-----------0001 000001111110110000000100100001000000000000000 +01111000010-----------0001 000001111110110000000100100001000000000000000 +01111000011-----------0001 000001111110110000000100100001000000000000000 +01111110010-----------0001 000001111110110000000011000001000000000000010 +01111100010-----------0001 000001111110110000000011000001000000000000010 +01111100011-----------0001 000001111110110000000011000001000000000000010 +00110001011-----------0001 000110111002220101110000001111000000000000000 +00110001001-----------0001 000110111002220101110000001111000000000000000 +01001110010-----------0001 000000000000000000000000000001000000000000001 +00000011110-----------0001 000001001001110000000000000001000000000000000 +00000000000-----------0010 000010000100000000010000000001010100010000000 +10110011000-----------0010 000000000000000000000000000001000000000000000 +10000011000-----------0010 000000000000000000000000000001000000000000000 +11110011000-----------0010 000000000000000000000000000001000000000000000 +11100010110-----------0010 000000000000000000000000000001000000000000000 +11100011000-----------0010 000000000000000000000000000001000000000000000 +11100011100-----------0010 000000000000000000000000000001000000000000000 +11100111110-----------0010 000000000000000000000000000001000000000000000 +11000010110-----------0010 000000000000000000000000000001000000000000000 +11000011000-----------0010 000000000000000000000000000001000000000000000 +11000011100-----------0010 000000000000000000000000000001000000000000000 +11000011110-----------0010 000000000000000000000000000001000000000000000 +00111111101-----------0010 000000000000000000000000000001000000000000000 +00110001011-----------0010 000000000000000000000000000001000000000000000 +00101110000-----------0010 000000000000000000000000000001000000000000000 +00110001001-----------0010 000000000000000000000000000001000000000000000 +11011011101-----------0010 001002222222220000000000000001001100000000000 +11011011100-----------0010 001002222222220000000000000001001100000000000 +11011011111-----------0010 001002222222220000000000000001001100000000000 +11011011110-----------0010 001002222222220000000000000001001100000000000 +11011011001-----------0010 001002222222220000000000000001001100000000000 +11011011000-----------0010 001002222222220000000000000001001100000000000 +11011011011-----------0010 001002222222220000000000000001001100000000000 +11011011010-----------0010 001002222222220000000000000001001100000000000 +00010110111-----------0010 000000000000000000000000000001100000000000000 +00000110111-----------0010 000000000000000000000000000001100000000000000 +00000010111--------0--0010 000000000000000000000000000001100000000000000 +00000010111--------1--0010 000011111111110000100000000001100000000000000 +00101101011-----------0010 000102222222220000000101000001000000000000000 +00101100011-----------0010 000102222222220000000101000001000000000000000 +00110111001-----------0010 000000000000000000000000000001010100010000000 +00110111000-----------0010 000102222222220100000101000001010100011000000 +01111001010-----------0010 000102222222220011000100100001000000000000010 +01111011011-----------0010 000102222222220011000100100001000000000000010 +01111001011-----------0010 000102222222220011000100100001000000000000010 +01111010010-----------0010 000102222222220011000100100001000000000000010 +01111000010-----------0010 000102222222220011000100100001000000000000010 +01111000011-----------0010 000102222222220011000100100001000000000000010 +01111110010-----------0010 000102222222220011000100100001000000000000010 +01111100010-----------0010 000102222222220011000100100001000000000000010 +01111100011-----------0010 000102222222220011000100100001000000000000010 +00000000000-----------0011 000010000010100000000011000001000000000000001 +10110011000-----------0011 000000000000000000000000000001000000000000000 +10000011000-----------0011 000000000000000000000000000001000000000000000 +11110011000-----------0011 000000000000000000000000000001000000000000000 +11100011000-----------0011 000000000000000000000000000001000000000000000 +11000011000-----------0011 000000000000000000000000000001000000000000000 +00110111001-----------0011 000000000000000000000000000001000000000000000 +00110111000-----------0011 000000000000000000000000000001000000000000000 +11011011101-----------0011 000102222222220001000101000001010100011001000 +11011011100-----------0011 000102222222220001000101000001010100011001000 +11011011111-----------0011 000102222222220001000101000001010100011001000 +11011011110-----------0011 000102222222220001000101000001010100011001000 +11011011001-----------0011 000102222222220001000101000001010100011001000 +11011011000-----------0011 000102222222220001000101000001010100011001000 +11011011011-----------0011 000102222222220001000101000001010100011001000 +11011011010-----------0011 000102222222220001000101000001010100011001000 +00101101011-----------0011 000010000001100000010000001111010100011000000 +00101100011-----------0011 000010000001100000010000001111010100011000000 +01111001010-----------0011 000102222222220011000100100001000000000000010 +01111011011-----------0011 000102222222220011000100100001000000000000010 +01111001011-----------0011 000102222222220011000100100001000000000000010 +01111010010-----------0011 000102222222220011000100100001000000000000010 +01111000010-----------0011 000102222222220011000100100001000000000000010 +01111000011-----------0011 000102222222220011000100100001000000000000010 +01111110010-----------0011 000102222222220011000100100001000000000000010 +01111100010-----------0011 000102222222220011000100100001000000000000010 +01111100011-----------0011 000102222222220011000100100001000000000000010 +10110011000-----------0100 000010000101000000000010000001000000000000000 +10000011000-----------0100 000010000101000000000010000001000000000000000 +11110011000-----------0100 000010000101000000000010000001000000000000000 +11100011000-----------0100 000010000101000000000010000001000000000000000 +11000011000-----------0100 000010000101000000000010000001000000000000000 +00101101011-----------0100 000102222222220100000010101101000000000000000 +00101100011-----------0100 000102222222220100000010101101000000000000000 +00110111001-----------0100 000000000000000000000000000001000000000000000 +00110111000-----------0100 000000000000000000000000000001000000000000000 +01111001010-----------0100 000000000000000000000000000001000000000000000 +01111011011-----------0100 000000000000000000000000000001000000000000000 +01111001011-----------0100 000000000000000000000000000001000000000000000 +01111010010-----------0100 000000000000000000000000000001000000000000000 +01111000010-----------0100 000000000000000000000000000001000000000000000 +01111000011-----------0100 000000000000000000000000000001000000000000000 +01111110010-----------0100 000000000000000000000000000001000000000000000 +01111100010-----------0100 000000000000000000000000000001000000000000000 +01111100011-----------0100 000000000000000000000000000001000000000000000 +10110011000-----------0101 000000000000000000000000000111000000000000000 +10000011000-----------0101 000000000000000000000000000111000000000000000 +11110011000-----------0101 000000000000000000000000000111000000000000000 +11100011000-----------0101 000000000000000000000000000111000000000000000 +11000011000-----------0101 000000000000000000000000000111000000000000000 +00101101011-----------0101 000010000011100000000010010001000000000000000 +00101100011-----------0101 000010000011100000000010010001000000000000000 +10110011000-----------0110 000000000000000000000000001011100000000000000 +10000011000-----------0110 000000000000000000000000001011100000000000000 +11110011000-----------0110 000000000000000000000000001011100000000000000 +11100011000-----------0110 000000000000000000000000001011100000000000000 +11000011000-----------0110 000000000000000000000000001011100000000000000 +00101101011--------0--0110 000000000000000000000000000001000000000000000 +00101100011--------0--0110 000000000000000000000000000001000000000000000 +00101101011--------1--0110 000102222222220010000001000001000000000000000 +00101100011--------1--0110 000102222222220010000001000001000000000000000 diff --git a/espresso/examples/indust/bcd b/espresso/examples/indust/bcd new file mode 100644 index 0000000..144bb56 --- /dev/null +++ b/espresso/examples/indust/bcd @@ -0,0 +1,245 @@ +.i 26 +.o 38 +00110001101-----------0000 00000000000000000000000000010000000000 +00110001100-----------0000 00000000000000000000000000010000000000 +10110010110-----------0000 00000000000000000000000000010000000000 +10110011000-----------0000 00000000000000000000000000010000000000 +10110011100-----------0000 00000000000000000000000000010000000000 +10010010110-----------0000 00000000000000000000000000010000000000 +10000011000-----------0000 00000000000000000000000000010000000000 +10010011100-----------0000 00000000000000000000000000010000000000 +01011100000-----------0000 00000000000000000000000000010000000000 +00010101000-----------0000 00000000000000000000000000010000000000 +10111011111-----------0000 00000000000000000000000000010000000000 +10111011001-----------0000 00000000000000000000000000010000000000 +00010100100-----------0000 00000000000000000000000000010000000000 +00010100010-----------0000 00000000000000000000000000010000000000 +00111111101-----------0000 00000000000000000000000000010000000000 +01001110010-----------0000 00000000000000000000000000010000000000 +00010001010-----------0000 00000000000000000000000000010000000000 +00000000000-----------0000 01022222222201110010000001010000000000 +11110010110-----------0000 01101110022200001000011000010000000000 +11110011000-----------0000 01101110022200001000011000010000000000 +11110011100-----------0000 01101110022200001000011000010000000000 +11100010110-----------0000 01101110022200001000011000010000000000 +11100011000-----------0000 01101110022200001000011000010000000000 +11100011100-----------0000 01101110022200001000011000010000000000 +11100111110-----------0000 01101110022200001000011000010000000000 +11000010110-----------0000 01101110022200001000011000010000000000 +11000011000-----------0000 01101110022200001000011000010000000000 +11000011100-----------0000 01101110022200001000011000010000000000 +11000011110-----------0000 01101110022200001000011000010000000000 +11011011101-----------0000 01022222222200010100000000010110001100 +11011011100-----------0000 01022222222200010100000000010110001100 +11011011111-----------0000 01022222222200010100000000010110001100 +11011011110-----------0000 01022222222200010100000000010110001100 +11011011001-----------0000 01022222222200010100000000010110001100 +11011011000-----------0000 01022222222200010100000000010110001100 +11011011011-----------0000 01022222222200010100000000010110001100 +11011011010-----------0000 01022222222200010100000000010110001100 +00000101100-----------0000 00000000000000000000000100010000000000 +00000101110-----------0000 00000000000000000000000100010000000000 +00010110111-----------0000 00000000000000000000000001010000000000 +00000010111-----------0000 00000000000000000000000001010000000000 +00000110111-----------0000 00000000000000000000000001010000000000 +01011011101-----------0000 00000000000000000000000100110000000001 +01011011010-----------0000 00000000000000000000000100110000000001 +00011011001-----------0000 00000000000000000000000100110000000001 +10111011110-----------0000 00000000000000000000000000010000000001 +10111011000-----------0000 00000000000000000000000000010000000001 +00011010100-----------0000 01022222222200010000010000010000110000 +00010011100-----------0000 01022222222200010000010000010000110000 +00011001000-----------0000 01022222222200010000010000010000110000 +10111011011-----------0000 01022222222200010000010000010000110000 +01010010010-----------0000 00000000000000000000000100110001000000 +00010101111-----------0000 00000000000000000000000100110001000000 +00101101011-----------0000 00100001010000000000100100010000000000 +00101100011-----------0000 00100001010000000000100100010000000000 +00110111001-----------0000 01022222222200100100000011010010000000 +00110111000-----------0000 01022222222200100100000011010010000000 +00100010000-----------0000 00000000000000000000000000010001000000 +00100010010-----------0000 00000000000000000000000000010001000000 +00111100001-----------0000 00000000000000000000000000010001000000 +00111100101-----------0000 00000000000000000000000000010001000000 +01111001010-----------0000 01101001122210111000000100010000100000 +01111011011-----------0000 01101001122210111000000100010000100000 +01111001011-----------0000 01101001122210111000000100010000100000 +01111010010-----------0000 01101001122210111000000100010000100000 +01111000010-----------0000 01101001122210111000000100010000100000 +01111000011-----------0000 01101001122210111000000100010000100000 +01111110010-----------0000 01101001122210111000000100010000100000 +01111100010-----------0000 01101001122210111000000100010000100000 +01111100011-----------0000 01101001122210111000000100010000100000 +00100001011-----------0000 00000000000000000000000000010001100000 +00110001011-----------0000 00000000000000000000000011110000000001 +00110001001-----------0000 00000000000000000000000011110000000001 +00111110011-----------0000 01022222222200000000101100110001000000 +00000011001-----------0000 11110011000000100010000010010001000000 +00001101001-----------0000 10100100000000000001001010010000000000 +00000011110-----------0000 00010010100000000000011000010000000000 +00101110000-----------0000 00100000101100000000100000010000000000 +00110001101-----------0001 00000000000000000000000000010000000000 +00110001100-----------0001 00000000000000000000000000010000000000 +00000000000-----------0001 00000000000000000000000000010000000000 +11110011000-----------0001 00000000000000000000000000010000000000 +11100010110-----------0001 00000000000000000000000000010000000000 +11100011000-----------0001 00000000000000000000000000010000000000 +11100011100-----------0001 00000000000000000000000000010000000000 +11100111110-----------0001 00000000000000000000000000010000000000 +11000010110-----------0001 00000000000000000000000000010000000000 +11000011000-----------0001 00000000000000000000000000010000000000 +11000011100-----------0001 00000000000000000000000000010000000000 +11000011110-----------0001 00000000000000000000000000010000000000 +11011011101-----------0001 00000000000000000000000000010000000000 +11011011100-----------0001 00000000000000000000000000010000000000 +11011011111-----------0001 00000000000000000000000000010000000000 +11011011110-----------0001 00000000000000000000000000010000000000 +11011011001-----------0001 00000000000000000000000000010000000000 +11011011000-----------0001 00000000000000000000000000010000000000 +11011011011-----------0001 00000000000000000000000000010000000000 +11011011010-----------0001 00000000000000000000000000010000000000 +01011100000-----------0001 00000000000000000000000000010000000000 +00010101000-----------0001 00000000000000000000000000010000000000 +01011011010-----------0001 00000000000000000000000000010000000000 +00011011001-----------0001 00000000000000000000000000010000000000 +00010100100-----------0001 00000000000000000000000000010000000000 +00010100010-----------0001 00000000000000000000000000010000000000 +01111001010-----------0001 00000000000000000000000000010000000000 +01111011011-----------0001 00000000000000000000000000010000000000 +01111001011-----------0001 00000000000000000000000000010000000000 +01111010010-----------0001 00000000000000000000000000010000000000 +01111000010-----------0001 00000000000000000000000000010000000000 +01111000011-----------0001 00000000000000000000000000010000000000 +01111110010-----------0001 00000000000000000000000000010000000000 +01111100010-----------0001 00000000000000000000000000010000000000 +01111100011-----------0001 00000000000000000000000000010000000000 +00111111101-----------0001 00000000000000000000000000010000000000 +00110001011-----------0001 00000000000000000000000000010000000000 +00001101001-----------0001 00000000000000000000000000010000000000 +00110001001-----------0001 00000000000000000000000000010000000000 +10110010110-----------0001 00000000000000000000000100010000000000 +10110011000-----------0001 00000000000000000000000100010000000000 +10110011100-----------0001 00000000000000000000000100010000000000 +10010010110-----------0001 00000000000000000000000100010000000000 +10000011000-----------0001 00000000000000000000000100010000000000 +10010011100-----------0001 00000000000000000000000100010000000000 +11110010110-----------0001 00000000000000000000000000011000000001 +11110011100-----------0001 00000000000000000000000000011000000000 +01011011101-----------0001 00000000000000000000000000011000000000 +10111011111-----------0001 00000000000000000000000000011000000000 +10111011110-----------0001 00000000000000000000000000011000000000 +10111011001-----------0001 00000000000000000000000000011000000000 +10111011000-----------0001 00000000000000000000000000011000000000 +10111011011-----------0001 00000000000000000000000000011000000000 +00000101100-----------0001 00000000000000000000000000010001000000 +00000101110-----------0001 00000000000000000000000000010001000000 +00010110111-----------0001 10111111000000000000110000010000000010 +00000010111-----------0001 00000001111100000000110000010000000000 +00000110111-----------0001 00000001111100000000110000010000000000 +00101101011-----------0001 01022222222211010000000100010000000000 +00101100011-----------0001 01022222222211010000000100010000000000 +00110111001-----------0001 01022222222211000000110000010000000010 +00110111000-----------0001 01022222222211000000110000010000000010 +01001110010----------00001 01022222222200010000010100110000110000 +01001110010----------10001 00000000000000000010000000010000110000 +00000011110-----------0001 01022222222200100001100000010001000000 +00101110000-----------0001 00101000000000000000000000010000000000 +00000000000-----------0010 00000000000000000000000000010000000000 +11011011101-----------0010 00000000000000000000000000010000000000 +11011011100-----------0010 00000000000000000000000000010000000000 +11011011111-----------0010 00000000000000000000000000010000000000 +11011011110-----------0010 00000000000000000000000000010000000000 +11011011001-----------0010 00000000000000000000000000010000000000 +11011011000-----------0010 00000000000000000000000000010000000000 +11011011011-----------0010 00000000000000000000000000010000000000 +11011011010-----------0010 00000000000000000000000000010000000000 +00101101011-----------0010 00000000000000000000000000010000000000 +00101100011-----------0010 00000000000000000000000000010000000000 +01111001010-----------0010 00000000000000000000000000010000000000 +01111011011-----------0010 00000000000000000000000000010000000000 +01111001011-----------0010 00000000000000000000000000010000000000 +01111010010-----------0010 00000000000000000000000000010000000000 +01111000010-----------0010 00000000000000000000000000010000000000 +01111000011-----------0010 00000000000000000000000000010000000000 +01111110010-----------0010 00000000000000000000000000010000000000 +01111100010-----------0010 00000000000000000000000000010000000000 +01111100011-----------0010 00000000000000000000000000010000000000 +00110001011-----------0010 00000000000000000000000000010000000000 +00110001001-----------0010 00000000000000000000000000010000000000 +10110011000-----------0010 00000000000000000000000100010000000000 +10000011000-----------0010 00000000000000000000000100010000000000 +11110011000-----------0010 00000000000000000000000100010000000000 +11100010110-----------0010 00000000000000000000000100010000000000 +11100011000-----------0010 00000000000000000000000100010000000000 +11100011100-----------0010 00000000000000000000000100010000000000 +11100111110-----------0010 00000000000000000000000100010000000000 +11000010110-----------0010 00000000000000000000000100010000000000 +11000011000-----------0010 00000000000000000000000100010000000000 +11000011100-----------0010 00000000000000000000000100010000000000 +11000011110-----------0010 00000000000000000000000100010000000000 +00010110111-----------0010 00000000000000000000000000011001010000 +00000010111-----------0010 00000000000000000000000000011001010000 +00000110111-----------0010 00000000000000000000000000011001010000 +00110111001-----------0010 00000000000000000000000000010000000001 +00110111000-----------0010 00000000000000000000000000010000000001 +00111111101-----------0010 00000000000000000000000000010001000000 +00101110000-----------0010 00000000000000000000000000010001000000 +00000000000-----------0011 00000000000000000000000000010000000000 +00110111000-----------0011 00000000000000000000000000010000000000 +01111001010-----------0011 00000000000000000000000000010000000000 +01111011011-----------0011 00000000000000000000000000010000000000 +01111001011-----------0011 00000000000000000000000000010000000000 +01111010010-----------0011 00000000000000000000000000010000000000 +01111000010-----------0011 00000000000000000000000000010000000000 +01111000011-----------0011 00000000000000000000000000010000000000 +01111110010-----------0011 00000000000000000000000000010000000000 +01111100010-----------0011 00000000000000000000000000010000000000 +01111100011-----------0011 00000000000000000000000000010000000000 +10110011000-----------0011 01022222222201110000000011010000000000 +10000011000-----------0011 01022222222201110000000011010000000000 +11110011000-----------0011 01022222222201110000000011010000000000 +11100011000-----------0011 01022222222201110000000011010000000000 +11000011000-----------0011 01022222222201110000000011010000000000 +11011011101-----------0011 00000000000000000000000000010001000001 +11011011100-----------0011 00000000000000000000000000010001000001 +11011011111-----------0011 00000000000000000000000000010001000001 +11011011110-----------0011 00000000000000000000000000010001000001 +11011011001-----------0011 00000000000000000000000000010001000001 +11011011000-----------0011 00000000000000000000000000010001000001 +11011011011-----------0011 00000000000000000000000000010001000001 +11011011010-----------0011 00000000000000000000000000010001000001 +00101101011-----------0011 00000000000000000000000000010000000001 +00101100011-----------0011 00000000000000000000000000010000000001 +00110111001-----------0011 01022222222201010010000000010000000000 +10110011000-----------0100 00000000000000000000000000010000000000 +10000011000-----------0100 00000000000000000000000000010000000000 +11110011000-----------0100 00000000000000000000000000010000000000 +11100011000-----------0100 00000000000000000000000000010000000000 +11000011000-----------0100 00000000000000000000000000010000000000 +00110111001-----------0100 00000000000000000000000000010000000000 +00110111000-----------0100 00000000000000000000000000010000000000 +00101101011-----------0100 00100000001000000000100100010000000000 +00101100011-----------0100 00100000001000000000100100010000000000 +01111001010-----------0100 01022222222200010000101000010001000000 +01111011011-----------0100 01022222222200010000101000010001000000 +01111001011-----------0100 01022222222200010000101000010001000000 +01111010010-----------0100 01022222222200010000101000010001000000 +01111000010-----------0100 01022222222200010000101000010001000000 +01111000011-----------0100 01022222222200010000101000010001000000 +01111110010-----------0100 01022222222200010000101000010001000000 +01111100010-----------0100 01022222222200010000101000010001000000 +01111100011-----------0100 01022222222200010000101000010001000000 +10110011000-----------0101 00100001010000000000000100010000000000 +10000011000-----------0101 00100001010000000000000100010000000000 +11110011000-----------0101 00100001010000000000000100010000000000 +11100011000-----------0101 00100001010000000000000100010000000000 +11000011000-----------0101 00100001010000000000000100010000000000 +00101101011-----------0101 00000000000000000000000000010000000000 +00101100011-----------0101 00000000000000000000000000010000000000 +10110011000-----------0110 00000000000000000000000000011000000000 +10000011000-----------0110 00000000000000000000000000011000000000 +11110011000-----------0110 00000000000000000000000000011000000000 +11100011000-----------0110 00000000000000000000000000011000000000 +11000011000-----------0110 00000000000000000000000000011000000000 +00101101011-----------0110 00000000000000000000000000010000000000 +00101100011-----------0110 00000000000000000000000000010000000000 diff --git a/espresso/examples/indust/br1 b/espresso/examples/indust/br1 new file mode 100644 index 0000000..9029b38 --- /dev/null +++ b/espresso/examples/indust/br1 @@ -0,0 +1,36 @@ +.i 12 +.o 8 +110001000100 10101101 +110001000110 10101101 +110001011100 10001110 +110001011101 01000000 +110001011110 10001000 +110001011111 01000100 +110011000100 10101011 +110011000110 10101011 +110011011100 10001100 +110011011101 10110000 +110101000100 10101001 +110101000110 10101001 +110111000100 10100111 +110111000110 10100111 +110111011100 10001100 +110111011101 10110000 +111001000100 10100101 +111001000110 10100101 +111001011100 10000010 +111001011110 10000010 +111010111100 10110000 +111011000100 10100011 +111011000110 10100011 +111101000100 10100000 +111101000100 10100000 +111101011100 10001110 +111101011110 10001110 +111110111100 01000000 +111110111110 01000100 +111111010000 10101111 +111111010010 10101111 +111111010100 10000110 +111111010110 10000110 +111111111100 01000000 diff --git a/espresso/examples/indust/br2 b/espresso/examples/indust/br2 new file mode 100644 index 0000000..f7cd97b --- /dev/null +++ b/espresso/examples/indust/br2 @@ -0,0 +1,37 @@ +.i 12 +.o 8 +100001001100 11000101 +100001001110 11000101 +100011001100 11000011 +100011001110 11000011 +100101001100 11000001 +100101001110 11000001 +100111001100 11001111 +100111001110 11001111 +101001001100 11001101 +101001001110 11001101 +101001111100 10001010 +101001111101 10001010 +101001111110 10001010 +101001111111 10001010 +101011001100 11001011 +101011001110 11001011 +101101001100 11001001 +101101001110 11001001 +101101111100 10001000 +101101111101 10001000 +101101111110 10001000 +101101111111 10001000 +101110110100 10001110 +101110110101 10001110 +101110110110 10001110 +101110110111 10001110 +101111001100 11001000 +101111001110 11001000 +101111011100 11001000 +101111011110 11001000 +101111011101 10111000 +101111110000 00101000 +101111110001 00101000 +101111111100 10001000 +101111111110 11000111 diff --git a/espresso/examples/indust/chkn b/espresso/examples/indust/chkn new file mode 100644 index 0000000..cf00927 --- /dev/null +++ b/espresso/examples/indust/chkn @@ -0,0 +1,155 @@ +.i 29 +.o 7 +--1-0------11111100000010---- 1000000 +--1-0------1111110000001--0-- 1000000 +----0------010-1------------- 1000000 +----0------01--10------------ 1000000 +--0-0------1111110000001--1-- 0100000 +----0------01--01------------ 0100000 +----0------0--001------------ 0100000 +--010------111111000011000--- 0010000 +--010------11111100001100-0-- 0010000 +---10------1111110000110000-- 0010000 +---10------101101------------ 0010000 +--110------1011-1------------ 0010000 +---10------10011------------- 0010000 +--110------011011------------ 0010000 +--110------00010------------- 0010000 +--110------0001-1------------ 0010000 +---10------00-001------------ 0010000 +--110------00100------------- 0010000 +----0-1---111111100001000-0-- 0001000 +--1-0-1---1111111000010-0-0-- 0001000 +----0-1---11111110000100-10-- 0001000 +----0--1--11111--000010011--- 0001000 +----01----111-1--000010011--- 0001000 +----0--1--11111--0000101011-- 0001000 +----0--1--11111--00001000-0-- 0001000 +--1-0--1--11111--000010-0---- 0001000 +----01----111-1--0000101011-- 0001000 +----01----111-1--00001000-0-- 0001000 +--1-01----111-1--000010-0---- 0001000 +--1-0--1--11111--0000100--0-- 0001000 +--1-0-1---111111100000-10---- 0001000 +--1-0-1---111111100000-1--0-- 0001000 +--0-0-1---11111110000001----- 0001000 +--0-0-1---111111100000-1-0--- 0001000 +----0-1---111111100000-10-0-- 0001000 +--1-0--1--11111--0000011--0-- 0001000 +--1-01---0111-1--00000-10---- 0001000 +--1-01---0111-1--00000-1--0-- 0001000 +--1-01----111-1--0000011--0-- 0001000 +--0-0--1--11111--00000110---- 0001000 +--0-0--1--11111--0000011-0--- 0001000 +--0-0--1--11111--0000001--0-- 0001000 +--0-01----111-1--0000011-0--- 0001000 +--0-01---0111-1--0000001----- 0001000 +----01----111-1--00000110---- 0001000 +----0--1--11111--000001100--- 0001000 +----0-1---1111111000001010--- 0001000 +----0-1---111111100000101-0-- 0001000 +--0-0--1--11111--0000010110-- 0001000 +----01---0111-1--000001010--- 0001000 +----01---0111-1--00000101-1-- 0001000 +--1-0-1---11111110000000-01-- 0001000 +--1-0-1---111111100000001-1-- 0001000 +--1-01----111-1--00000001-1-- 0001000 +--0-01----111-1--0000000001-- 0001000 +--1-0--1--11111-10000000-01-- 0001000 +--0-0--1--11111-1000000001--- 0001000 +--0-0--1--11111-10000000-11-- 0001000 +--0-0--1--11111--00000-0000-- 0001000 +--1-01----111-1--00000-0110-- 0001000 +--0-0-1---1111111000001--00-- 0001000 +--0-01----111-1--000001-000-- 0001000 +--0-0-1---1111111000000-01--- 0001000 +--0-0-1---1111111000000--11-- 0001000 +--1-01----111-1--0000-0011--- 0001000 +----01----111-1--0000-00111-- 0001000 +----0--1--11111--0000-00000-- 0001000 +--1-0--1--11111-10000-0011--- 0001000 +--1-01---0111-1--0000-0-001-- 0001000 +--0-0-1---11111110000-01011-- 0001000 +----0--1--11100-------------- 0001000 +----0--1--111--0------------- 0001000 +----0--1--1-1--00------------ 0001000 +----01----111--0------------- 0001000 +----01---01-1--0------------- 0001000 +----0--1--111---0------------ 0001000 +----01----1110--------------- 0001000 +----01----111---0------------ 0001000 +----01---01-10--------------- 0001000 +----01---01-1---0------------ 0001000 +----01---011010-------------- 0001000 +----0---1-110000------------- 0001000 +----0-1---10011-0------------ 0001000 +----01----10011-------------- 0001000 +----0--1--10011-------------- 0001000 +----0--1--100001------------- 0001000 +----01---0100-0-1------------ 0001000 +----0--1--100-011------------ 0001000 +----01----1001-11------------ 0001000 +----01----1-01110------------ 0001000 +----0--1--1-00010------------ 0001000 +-------1--1-----------------1 0001000 +-------1--1----------------1- 0001000 +----01---010--110------------ 0001000 +----01---010-001------------- 0001000 +----0--1--1--1100------------ 0001000 +1---0------11111100000101-0-- 0000100 +1---0------111111000001010--- 0000100 +1---0----0-11111100000101---- 0000100 +1-0-0------1111110000010-00-- 0000100 +1---0------10--0------------- 0000100 +1---0------10-0-------------- 0000100 +1---0------101--0------------ 0000100 +1---0----0-000110------------ 0000100 +-1000------1-1111000011000--- 0000010 +-1000------1-111100001100-0-- 0000010 +-1-00------1-11110000110000-- 0000010 +-1--0------1-111100000010---- 0000010 +-10-0------1-11110000-011---- 0000010 +-1--0------1-11110000-011-0-- 0000010 +-1-00------1011-1------------ 0000010 +-1--0------101111------------ 0000010 +-1-00------10011------------- 0000010 +-1--0------0--001------------ 0000010 +-1--0------0-100------------- 0000010 +-1--0------0-010------------- 0000010 +-1--0------0-01-1------------ 0000010 +-1--0------01-0-------------- 0000010 +-1--0------01---0------------ 0000010 +-1--0------01--0------------- 0000010 +-----------1--1--000011000--- 0000001 +--1--------1--1--000010-0---- 0000001 +--1--------1--1--000010---0-- 0000001 +--1--------1--1--0000100-1--- 0000001 +--0--------1--1--000010-11--- 0000001 +-----------1--1--00001000-0-- 0000001 +--0--------1--1--00001-00-0-- 0000001 +--1--------1--1--00000-1--0-- 0000001 +--1--------1--1--00000-011--- 0000001 +--1--------1--1--00000-01-1-- 0000001 +--0--------1--1--000001--00-- 0000001 +--0--------1--1--000000-0---- 0000001 +--0--------1--1--000000--11-- 0000001 +--0--------1--1--0000001----- 0000001 +--0--------1--1--00000-1-0--- 0000001 +-----------1--1--00000101---- 0000001 +-----------1--1--00000-10---- 0000001 +-----------1--1--000000-00--- 0000001 +-----------10---------------- 0000001 +-----------1-0--------------- 0000001 +-----------1---0------------- 0000001 +-----------1----0------------ 0000001 +--0--------1--1--0000-011---- 0000001 +--0--------1--1--0000-01-11-- 0000001 +-----------01-0-------------- 0000001 +----1------------------------ 0000001 +------------10--------------- 0000001 +------------1--0------------- 0000001 +------------1---0------------ 0000001 +------------0-1-------------- 0000001 +------------0---1------------ 0000001 +-------------1-0------------- 0000001 +-------------0-1------------- 0000001 diff --git a/espresso/examples/indust/clpl b/espresso/examples/indust/clpl new file mode 100644 index 0000000..0c1bcc4 --- /dev/null +++ b/espresso/examples/indust/clpl @@ -0,0 +1,22 @@ +.i 11 +.o 5 +-1--------- 10000 +---1--1---- 10000 +--1--11---- 10000 +1---111---- 10000 +---1------- 01000 +--1--1----- 01000 +1---11----- 01000 +--1-------- 00100 +1---1------ 00100 +----------1 00010 +-------1-1- 00010 +-1------11- 00010 +---1--1-11- 00010 +--1--11-11- 00010 +1---111-11- 00010 +-------1--- 00001 +-1------1-- 00001 +---1--1-1-- 00001 +--1--11-1-- 00001 +1---111-1-- 00001 diff --git a/espresso/examples/indust/cps b/espresso/examples/indust/cps new file mode 100644 index 0000000..3e8efcf --- /dev/null +++ b/espresso/examples/indust/cps @@ -0,0 +1,1310 @@ +.i 24 +.o 109 +-1--0--1111--00001011-0- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111--0000101-10- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +11110--1111--0000000111- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +01000--1111--0000000111- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111--0000000000- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--00001011-1- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--111--0----------- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--111-0------------ 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0-01011-1----------- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10011------------ 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--100-11----------- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--100-00----------- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10-111----------- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--011011----------- 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--00111------------ 10000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1----0----------- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--100-------------- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10-0------------- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10--0------------ 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1--10------------ 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1-01------------- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1-1-0------------ 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1-0-1------------ 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---0-110----------- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--00111------------ 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---00011----------- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--001011----------- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1--000001010-- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--000001-10-- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1--000001-100- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--00000101--- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--000001--00- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--000001100-- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--00000110-1- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--000001101-- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1--0000000111- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--000000011-- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--000000000-- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--00000000-0- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1--0000000010- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--0000101010- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--0000110010- 01000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---10-------------- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01--0------------ 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-0--1----------- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01---0----------- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0----0-01----------- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1010------------- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--101--0----------- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-001------------ 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-100------------ 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-010------------ 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0-1101-0------------ 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10-010----------- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--001011----------- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1110000001--0- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-111000000-010- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-111000000--10- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-11100000-10-0- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1110000-011-0- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-111000001100-- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-11100000110-1- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-111000001101-- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-111000001011-- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-111000001-000- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1110000110010- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1110000000001- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-01-0--11-11100000-0111- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +--100--11-1110000000111- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +01-10--11-111000000011-- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1010--11-111000000011-- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +11-00--11-111000000011-- 00100000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--111100----------- 00010000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--111000----------- 00001000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--101101----------- 00000100000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--000110----------- 00000010000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000110010- 00000001000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000110001- 00000000100000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000110001- 00000000010000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000110000- 00000000001000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000110000- 00000000000100000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000101010- 00000000000010000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000011111- 00000000000001000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000011010- 00000000000000100000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000011000- 00000000000000010000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000000111- 00000000000000001000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000000110- 00000000000000000100000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000000010- 00000000000000000010000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000000010- 00000000000000000001000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000000001- 00000000000000000000100000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000000000- 00000000000000000000010000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000000000- 00000000000000000000001000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------110----------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------11----1------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------11---1-------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------11--1--------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------11-1---------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +--------0-11------------ 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------11-----1------ 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------11------0----- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------11-------1---- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------11----------1- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--------11------------ 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------11--------0--- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----------11---------0-- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +---------011------------ 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +---------0-11----------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +---------1101----------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +---------0-00----------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +--------1--0------------ 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----1------------------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-------0---------------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +--------1-0------------- 00000000000000000000000100000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11--0------------ 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--111--0----------- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1101------------- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--110--1----------- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--0000101-10- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--00-11-1--0000110010- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--00001011--- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1--00001011-0- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--000001110-- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1--0000011100- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--00000111-1- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--000001-111- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--000001100-- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--00000110-1- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--000001101-- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--00-11-1--000001-000- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1--00000110-0- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00-11-1--0000001--0- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--00-11-1--0000001---- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00-11-1--00000010--- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--0000000110- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--00-11-1--0000000-01- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1--0000000000- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1-1110----------- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--00111------------ 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00-0-100------------ 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00-010-------------- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00-0-01------------- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00-0-0--1----------- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00-0-0-1------------ 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00-01---0----------- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00-00-0-1----------- 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00--1--0------------ 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----00---011------------ 00000000000000000000000010000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0100--1111110000000111- 00000000000000000000000001000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +0-100--1111110000000111- 00000000000000000000000001000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +11010--1111110000000111- 00000000000000000000000001000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0-10--1111110000000111- 00000000000000000000000000100000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +0--10--1111110000000111- 00000000000000000000000000100000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +11-00--1111110000000111- 00000000000000000000000000100000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----01-0-0-1------------ 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----01-01--0------------ 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----01-0-0--1----------- 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----01-0-01------------- 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----01-01---0----------- 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----01-0-100------------ 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----01--0011------------ 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----01-001011----------- 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----01-1111110000001--0- 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--01-1111110000110010- 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--01-1111110000010000- 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--01-1111110000000001- 00000000000000000000000000010000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---10-1------------ 00000000000000000000000000001000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01--0------------ 00000000000000000000000000001000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---10--0----------- 00000000000000000000000000001000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01---0----------- 00000000000000000000000000001000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1010------------- 00000000000000000000000000001000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10-010----------- 00000000000000000000000000001000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--101--0----------- 00000000000000000000000000001000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--101-0------------ 00000000000000000000000000001000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--00-0-1----------- 00000000000000000000000000001000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-0110----------- 00000000000000000000000000001000000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--101111----------- 00000000000000000000000000000100000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10000------------ 00000000000000000000000000000100000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1000-1----------- 00000000000000000000000000000100000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--011011----------- 00000000000000000000000000000100000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--111010----------- 00000000000000000000000000000010000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--111001----------- 00000000000000000000000000000010000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10011------------ 00000000000000000000000000000010000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11111100000010--- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111110000001--0- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000001---- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11111100000-1100- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11111100000-10-1- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111100000-10--- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111100000-1-0-- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111100000-1--1- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111100000101--- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--111111000001010-- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000000-01- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--111111000001--00- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--111111000000-010- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--001000----------- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--00010------------ 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0001-1----------- 00000000000000000000000000000001000000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111100001011-0- 00000000000000000000000000000000100000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11010------------ 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1101-1----------- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +1---0--1101------------- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-111000001101-- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-11100000110-1- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1110000000010- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +11--0--11-1110000000-10- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1110000101100- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1110000010111- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-01-0--11-11100000-0111- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +1---0--11-111000001101-- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1110000011010- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--110-11----------- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +1---0--110-1------------ 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--101110----------- 00000000000000000000000000000000010000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000011010- 00000000000000000000000000000000001000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-01-0--1111110000000111- 00000000000000000000000000000000001000000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000011001- 00000000000000000000000000000000000100000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000000010- 00000000000000000000000000000000000100000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--111111000001101-- 00000000000000000000000000000000000100000000000000 +00000000000000000000000000000000000000000000000000000000000 +-01-0--1111110000000111- 00000000000000000000000000000000000100000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111110000011010- 00000000000000000000000000000000000100000000000000 +00000000000000000000000000000000000000000000000000000000000 +--100--1111110000000111- 00000000000000000000000000000000000100000000000000 +00000000000000000000000000000000000000000000000000000000000 +0-1-0--1111110000000111- 00000000000000000000000000000000000100000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1101-0----------- 00000000000000000000000000000000000100000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11010------------ 00000000000000000000000000000000000100000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--110011----------- 00000000000000000000000000000000000100000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1110000011011- 00000000000000000000000000000000000010000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1110000101100- 00000000000000000000000000000000000010000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1110000010111- 00000000000000000000000000000000000010000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--110111----------- 00000000000000000000000000000000000010000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--101110----------- 00000000000000000000000000000000000010000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-0-1------------ 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01--0------------ 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-0--1----------- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-01------------- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01---0----------- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-100------------ 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---1000------------ 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---100-0----------- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--001011----------- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0-1101101----------- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111110000001--0- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11111100000-1000- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--111111000001-000- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000-01110- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--111111000000-010- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000110010- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000000001- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +01--0--111111000000-110- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +110-0--1111110000000111- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +-1010--1111110000000111- 00000000000000000000000000000000000001000000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--111-0------------ 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1101------------- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1-100001011-0- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1-10000101-10- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1-100001011-1- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1-1000010110-- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1-1000001-100- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1-1000001010-- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1-100000101-1- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1-1000001101-- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-1-10000011011- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +-11-0--11-1-10000000111- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +01-00--11-1-10000000111- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1-100000000-0- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +11--0--11-1-10000000-10- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +-0010--11-1-100000-0111- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0-01011-1----------- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--100-11----------- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--100-00----------- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10-11------------ 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1-01-0----------- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--011011----------- 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---0111------------ 00000000000000000000000000000000000000100000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1--010----------- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01--10----------- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--010-1------------ 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-001------------ 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-0-10----------- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---11-10----------- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--101-0------------ 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1-1-01----------- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--011-0------------ 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-100------------ 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-010------------ 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---1000------------ 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10--01----------- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1010------------- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--00111------------ 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1001-1----------- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--001011----------- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11111-0000001--0- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11111-00000-1-00- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11111-0000-011-0- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11111-0000-01-10- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11111-0000-01110- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-00001011-1- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11111-000000-000- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-000001-000- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-000000-010- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11111-000000000-- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-0000011101- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +01--0--11111-000000-110- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-0000110010- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-0000010110- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +--010--11111-0000000111- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +110-0--11111-0000000111- 00000000000000000000000000000000000000010000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01--0------------ 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--010-------------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01---0----------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01-0------------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-0-1------------ 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---11-10----------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---1-010----------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---11-01----------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---1000------------ 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--100-0------------ 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10-00------------ 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10--00----------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0-110--0------------ 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1010------------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10-0-0----------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0---0-001----------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-01-1----------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10-111----------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--001011----------- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11111-0000001--0- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11111-00000-10-0- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11111-000001010-- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11111-000001-100- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-000001-101- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-00000101-0- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-000001-000- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-0000-01110- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-000000-010- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11111-0000000001- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +01--0--11111-000000-110- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111-0000110010- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-10-0--11111-0000000111- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +-01-0--11111-0000000111- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +11-10--11111-0000000111- 00000000000000000000000000000000000000001000000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1101------------- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-11100000110-1- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11-1110000000010- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1110000101100- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11-1110000010111- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +-01-0--11-11100000-0111- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +----0--11-111000001101-- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +--100--11-1110000000111- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +0-1-0--11-1110000000111- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +----0--110-11----------- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +----0--101110----------- 00000000000000000000000000000000000000000100000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--0000110010- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--000001110-- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111--000001100-- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--000001101-- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--0000010110- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--0000001--0- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--0000-011-0- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--00001011--- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--0000000111- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111--000000011-- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111--000000000-- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111--000000-0-0- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--000000-010- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--00000-10-0- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--00000-1-00- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1011-1----------- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10011------------ 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1-110------------ 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01--0------------ 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--010-------------- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--01-0------------- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0--001----------- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-0--1----------- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0---1---0----------- 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0---1-10------------ 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0---1001------------ 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +----0---11-0------------ 00000000000000000000000000000000000000000010000000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000010000- 00000000000000000000000000000000000000000001000000 +00000000000000000000000000000000000000000000000000000000000 +----0--10000------------ 00000000000000000000000000000000000000000001000000 +00000000000000000000000000000000000000000000000000000000000 +----0--1000-0----------- 00000000000000000000000000000000000000000001000000 +00000000000000000000000000000000000000000000000000000000000 +----0---1---0----------- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--01--0------------ 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--010-------------- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--01-0------------- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--0-0--1----------- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0---1-10------------ 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0---11-0------------ 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--1-00-0----------- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--0--001----------- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--10000------------ 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--1-1100----------- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--001011----------- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--101111----------- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--0000001--0- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--0000-011-0- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--00000-10-0- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--00000-1-00- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--00001011--- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--000000-010- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--000011000-- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--00001100-0- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--000001101-- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--000001-000- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--0000000111- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111--000000011-- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111--0000000001- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111--0000010110- 00000000000000000000000000000000000000000000100000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--111111000010101-- 00000000000000000000000000000000000000000000010000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111100001000--- 00000000000000000000000000000000000000000000010000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000100-1-- 00000000000000000000000000000000000000000000010000 +00000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000-00000- 00000000000000000000000000000000000000000000010000 +00000000000000000000000000000000000000000000000000000000000 +----0--111111000010-0-1- 00000000000000000000000000000000000000000000010000 +00000000000000000000000000000000000000000000000000000000000 +----0--1111110000100-11- 00000000000000000000000000000000000000000000010000 +00000000000000000000000000000000000000000000000000000000000 +----0--0011------------- 00000000000000000000000000000000000000000000010000 +00000000000000000000000000000000000000000000000000000000000 +-1--0--1111110000011001- 00000000000000000000000000000000000000000000001000 +00000000000000000000000000000000000000000000000000000000000 +----0--110011----------- 00000000000000000000000000000000000000000000001000 +00000000000000000000000000000000000000000000000000000000000 +----0--11111100000010--- 00000000000000000000000000000000000000000000000100 +00000000000000000000000000000000000000000000000000000000000 +-1--0--101111----------- 00000000000000000000000000000000000000000000000100 +00000000000000000000000000000000000000000000000000000000000 +-1--0--011011----------- 00000000000000000000000000000000000000000000000100 +00000000000000000000000000000000000000000000000000000000000 +-1--0--0001-1----------- 00000000000000000000000000000000000000000000000100 +00000000000000000000000000000000000000000000000000000000000 +----0--0-0001----------- 00000000000000000000000000000000000000000000000100 +00000000000000000000000000000000000000000000000000000000000 +-0--0--11111100001011-1- 00000000000000000000000000000000000000000000000010 +00000000000000000000000000000000000000000000000000000000000 +-1--0--11111100001011-0- 00000000000000000000000000000000000000000000000001 +00000000000000000000000000000000000000000000000000000000000 +----0--101111----------- 00000000000000000000000000000000000000000000000000 +10000000000000000000000000000000000000000000000000000000000 +----0--1-11110000001--0- 00000000000000000000000000000000000000000000000000 +10000000000000000000000000000000000000000000000000000000000 +----0--1-11110000-011-0- 00000000000000000000000000000000000000000000000000 +10000000000000000000000000000000000000000000000000000000000 +-0--0--1-111100001011--- 00000000000000000000000000000000000000000000000000 +10000000000000000000000000000000000000000000000000000000000 +----0--01--0------------ 00000000000000000000000000000000000000000000000000 +10000000000000000000000000000000000000000000000000000000000 +----0--010-------------- 00000000000000000000000000000000000000000000000000 +10000000000000000000000000000000000000000000000000000000000 +----0--01---0----------- 00000000000000000000000000000000000000000000000000 +10000000000000000000000000000000000000000000000000000000000 +----0--01-0------------- 00000000000000000000000000000000000000000000000000 +10000000000000000000000000000000000000000000000000000000000 +----0--0-01-1----------- 00000000000000000000000000000000000000000000000000 +10000000000000000000000000000000000000000000000000000000000 +----0--010-11----------- 00000000000000000000000000000000000000000000000000 +01000000000000000000000000000000000000000000000000000000000 +----0--01--00----------- 00000000000000000000000000000000000000000000000000 +01000000000000000000000000000000000000000000000000000000000 +-0--0--1111110000110010- 00000000000000000000000000000000000000000000000000 +00100000000000000000000000000000000000000000000000000000000 +----0--11111100000010--- 00000000000000000000000000000000000000000000000000 +00100000000000000000000000000000000000000000000000000000000 +-1--0--101111----------- 00000000000000000000000000000000000000000000000000 +00100000000000000000000000000000000000000000000000000000000 +-1--0--011011----------- 00000000000000000000000000000000000000000000000000 +00100000000000000000000000000000000000000000000000000000000 +-1--0--0001-1----------- 00000000000000000000000000000000000000000000000000 +00100000000000000000000000000000000000000000000000000000000 +----0--0-0001----------- 00000000000000000000000000000000000000000000000000 +00100000000000000000000000000000000000000000000000000000000 +----0--101111----------- 00000000000000000000000000000000000000000000000000 +00010000000000000000000000000000000000000000000000000000000 +----0--1-11110000001--0- 00000000000000000000000000000000000000000000000000 +00010000000000000000000000000000000000000000000000000000000 +----0--1-11110000-011-0- 00000000000000000000000000000000000000000000000000 +00010000000000000000000000000000000000000000000000000000000 +-0--0--1-111100001011--- 00000000000000000000000000000000000000000000000000 +00010000000000000000000000000000000000000000000000000000000 +----0--01--0------------ 00000000000000000000000000000000000000000000000000 +00010000000000000000000000000000000000000000000000000000000 +----0--010-------------- 00000000000000000000000000000000000000000000000000 +00010000000000000000000000000000000000000000000000000000000 +----0--01---0----------- 00000000000000000000000000000000000000000000000000 +00010000000000000000000000000000000000000000000000000000000 +----0--01-0------------- 00000000000000000000000000000000000000000000000000 +00010000000000000000000000000000000000000000000000000000000 +----0--0-01-1----------- 00000000000000000000000000000000000000000000000000 +00010000000000000000000000000000000000000000000000000000000 +----0--0--001----------- 00000000000000000000000000000000000000000000000000 +00010000000000000000000000000000000000000000000000000000000 +-0--0--1111110000110010- 00000000000000000000000000000000000000000000000000 +00001000000000000000000000000000000000000000000000000000000 +----0--11111100001011-0- 00000000000000000000000000000000000000000000000000 +00001000000000000000000000000000000000000000000000000000000 +-0--0--11111100001011--- 00000000000000000000000000000000000000000000000000 +00001000000000000000000000000000000000000000000000000000000 +----0--01--0------------ 00000000000000000000000000000000000000000000000000 +00001000000000000000000000000000000000000000000000000000000 +----0--0--001----------- 00000000000000000000000000000000000000000000000000 +00001000000000000000000000000000000000000000000000000000000 +----0--01---0----------- 00000000000000000000000000000000000000000000000000 +00001000000000000000000000000000000000000000000000000000000 +----0--010-------------- 00000000000000000000000000000000000000000000000000 +00001000000000000000000000000000000000000000000000000000000 +-1--0--1111110000101-10- 00000000000000000000000000000000000000000000000000 +00000100000000000000000000000000000000000000000000000000000 +-0--0--11111100001011--- 00000000000000000000000000000000000000000000000000 +00000100000000000000000000000000000000000000000000000000000 +-0--0--111111000010-11-- 00000000000000000000000000000000000000000000000000 +00000100000000000000000000000000000000000000000000000000000 +----0--11111100001011-0- 00000000000000000000000000000000000000000000000000 +00000100000000000000000000000000000000000000000000000000000 +----0--0011-0----------- 00000000000000000000000000000000000000000000000000 +00000100000000000000000000000000000000000000000000000000000 +-1--0--111111000010101-- 00000000000000000000000000000000000000000000000000 +00000010000000000000000000000000000000000000000000000000000 +-0--0--111111000010-11-- 00000000000000000000000000000000000000000000000000 +00000010000000000000000000000000000000000000000000000000000 +-0--0--1111110000100-1-- 00000000000000000000000000000000000000000000000000 +00000010000000000000000000000000000000000000000000000000000 +-0--0--111111000010--11- 00000000000000000000000000000000000000000000000000 +00000010000000000000000000000000000000000000000000000000000 +----0--111111000010-011- 00000000000000000000000000000000000000000000000000 +00000010000000000000000000000000000000000000000000000000000 +----0--1111110000100-11- 00000000000000000000000000000000000000000000000000 +00000010000000000000000000000000000000000000000000000000000 +-1--0--1111110000100-11- 00000000000000000000000000000000000000000000000000 +00000001000000000000000000000000000000000000000000000000000 +-1--0--111111000010-0-1- 00000000000000000000000000000000000000000000000000 +00000001000000000000000000000000000000000000000000000000000 +-1--0--1111110000101-10- 00000000000000000000000000000000000000000000000000 +00000001000000000000000000000000000000000000000000000000000 +-0--0--11111100001011--- 00000000000000000000000000000000000000000000000000 +00000001000000000000000000000000000000000000000000000000000 +-0--0--111111000010-11-- 00000000000000000000000000000000000000000000000000 +00000001000000000000000000000000000000000000000000000000000 +----0--11111100001011-0- 00000000000000000000000000000000000000000000000000 +00000001000000000000000000000000000000000000000000000000000 +----0--0011------------- 00000000000000000000000000000000000000000000000000 +00000001000000000000000000000000000000000000000000000000000 +-0--0--111111000010011-- 00000000000000000000000000000000000000000000000000 +00000000100000000000000000000000000000000000000000000000000 +-1--0--1111110000110000- 00000000000000000000000000000000000000000000000000 +00000000010000000000000000000000000000000000000000000000000 +----0--11111100000011-0- 00000000000000000000000000000000000000000000000000 +00000000010000000000000000000000000000000000000000000000000 +-0--0--11111100000011--- 00000000000000000000000000000000000000000000000000 +00000000010000000000000000000000000000000000000000000000000 +----0--0-1001----------- 00000000000000000000000000000000000000000000000000 +00000000010000000000000000000000000000000000000000000000000 +----0--011-0------------ 00000000000000000000000000000000000000000000000000 +00000000010000000000000000000000000000000000000000000000000 +----0--011--0----------- 00000000000000000000000000000000000000000000000000 +00000000010000000000000000000000000000000000000000000000000 +----0--0110------------- 00000000000000000000000000000000000000000000000000 +00000000010000000000000000000000000000000000000000000000000 +----0--0001-1----------- 00000000000000000000000000000000000000000000000000 +00000000010000000000000000000000000000000000000000000000000 +-0--0--111111000010-001- 00000000000000000000000000000000000000000000000000 +00000000001000000000000000000000000000000000000000000000000 +-0--0--111111000010000-- 00000000000000000000000000000000000000000000000000 +00000000001000000000000000000000000000000000000000000000000 +----0--1111110000101100- 00000000000000000000000000000000000000000000000000 +00000000000100000000000000000000000000000000000000000000000 +-0--0--111111000010110-- 00000000000000000000000000000000000000000000000000 +00000000000100000000000000000000000000000000000000000000000 +-1--0--111111000010-001- 00000000000000000000000000000000000000000000000000 +00000000000010000000000000000000000000000000000000000000000 +-0--0--111111000010001-- 00000000000000000000000000000000000000000000000000 +00000000000001000000000000000000000000000000000000000000000 +-0--0--111111000010-011- 00000000000000000000000000000000000000000000000000 +00000000000001000000000000000000000000000000000000000000000 +-1--0--111111000010-011- 00000000000000000000000000000000000000000000000000 +00000000000000100000000000000000000000000000000000000000000 +-1--0--1111110000100-11- 00000000000000000000000000000000000000000000000000 +00000000000000100000000000000000000000000000000000000000000 +----0--101111----------- 00000000000000000000000000000000000000000000000000 +00000000000000010000000000000000000000000000000000000000000 +----0--1-111100000011-0- 00000000000000000000000000000000000000000000000000 +00000000000000010000000000000000000000000000000000000000000 +-0--0--1-111100000011--- 00000000000000000000000000000000000000000000000000 +00000000000000010000000000000000000000000000000000000000000 +-1--0--1-11110000-011-0- 00000000000000000000000000000000000000000000000000 +00000000000000010000000000000000000000000000000000000000000 +-0--0--1-11110000-011-1- 00000000000000000000000000000000000000000000000000 +00000000000000010000000000000000000000000000000000000000000 +----0--0-1001----------- 00000000000000000000000000000000000000000000000000 +00000000000000010000000000000000000000000000000000000000000 +----0--011-0------------ 00000000000000000000000000000000000000000000000000 +00000000000000010000000000000000000000000000000000000000000 +----0--011--0----------- 00000000000000000000000000000000000000000000000000 +00000000000000010000000000000000000000000000000000000000000 +----0--0110------------- 00000000000000000000000000000000000000000000000000 +00000000000000010000000000000000000000000000000000000000000 +----0--0001-1----------- 00000000000000000000000000000000000000000000000000 +00000000000000010000000000000000000000000000000000000000000 +-1--0--1111110000110000- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +-1--0--1111110000100-11- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +-1--0--111111000010-0-1- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +-1--0--1111110000101-10- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +-0--0--111111000010-11-- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +----0--1111110000-011-0- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +-0--0--1111110000-011--- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +----0--011-0------------ 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +----0--011--0----------- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +----0--0110------------- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +----0--0011------------- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +----0--0-1-01----------- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +----0--00-1-1----------- 00000000000000000000000000000000000000000000000000 +00000000000000001000000000000000000000000000000000000000000 +-0--0--111111000010-0-1- 00000000000000000000000000000000000000000000000000 +00000000000000000100000000000000000000000000000000000000000 +-0--0--11111100001000--- 00000000000000000000000000000000000000000000000000 +00000000000000000100000000000000000000000000000000000000000 +-1--0--1111110000101010- 00000000000000000000000000000000000000000000000000 +00000000000000000010000000000000000000000000000000000000000 +----0--00111------------ 00000000000000000000000000000000000000000000000000 +00000000000000000010000000000000000000000000000000000000000 +----0--11111100001011-0- 00000000000000000000000000000000000000000000000000 +00000000000000000001000000000000000000000000000000000000000 +----0--11111100001010-1- 00000000000000000000000000000000000000000000000000 +00000000000000000001000000000000000000000000000000000000000 +-0--0--1111110000000000- 00000000000000000000000000000000000000000000000000 +00000000000000000001000000000000000000000000000000000000000 +-0--0--11111100001000--- 00000000000000000000000000000000000000000000000000 +00000000000000000000100000000000000000000000000000000000000 +----0--11111100001000-1- 00000000000000000000000000000000000000000000000000 +00000000000000000000100000000000000000000000000000000000000 +-0--0--11111100000011--- 00000000000000000000000000000000000000000000000000 +00000000000000000000100000000000000000000000000000000000000 +----0--011--0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000100000000000000000000000000000000000000 +----0--111111000010011-- 00000000000000000000000000000000000000000000000000 +00000000000000000000010000000000000000000000000000000000000 +-0--0--11111100001011-0- 00000000000000000000000000000000000000000000000000 +00000000000000000000001000000000000000000000000000000000000 +----0--111111000000101-- 00000000000000000000000000000000000000000000000000 +00000000000000000000001000000000000000000000000000000000000 +----0--1111110000001-10- 00000000000000000000000000000000000000000000000000 +00000000000000000000001000000000000000000000000000000000000 +-0--0--1111110000001-1-- 00000000000000000000000000000000000000000000000000 +00000000000000000000001000000000000000000000000000000000000 +----0--0-0111----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000001000000000000000000000000000000000000 +----0--01-10------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000001000000000000000000000000000000000000 +----0--0-0100----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000001000000000000000000000000000000000000 +----0--01-1-0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000001000000000000000000000000000000000000 +----0--11-1-0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--11-10------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--111-0------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--111--0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--11001------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--1-0010----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--001011----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--000011----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-0--0--1111--000011000-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-0--0--1111--000001110-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--1111--0000011100- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-1--0--1111--000001100-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-1--0--1111--00000110-0- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-0--0--1111--000001101-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-0--0--1111--000001-000- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--1111--0000000111- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-1--0--1111--000000011-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-0--0--1111--000000000-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-0--0--1111--00000000-0- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--1111--0000000010- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +----0--1111--0000000001- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-0--0--1111--0000010110- 00000000000000000000000000000000000000000000000000 +00000000000000000000000100000000000000000000000000000000000 +-1--0--11-1110000011011- 00000000000000000000000000000000000000000000000000 +00000000000000000000000010000000000000000000000000000000000 +-0--0--11-1110000010111- 00000000000000000000000000000000000000000000000000 +00000000000000000000000010000000000000000000000000000000000 +----0--110111----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000010000000000000000000000000000000000 +----0--101110----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000010000000000000000000000000000000000 +-1--0--111111000010101-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000001000000000000000000000000000000000 +-0--0--11111100001000--- 00000000000000000000000000000000000000000000000000 +00000000000000000000000001000000000000000000000000000000000 +-0--0--1111110000100-1-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000001000000000000000000000000000000000 +----0--111111000010-0-1- 00000000000000000000000000000000000000000000000000 +00000000000000000000000001000000000000000000000000000000000 +----0--1111110000100-11- 00000000000000000000000000000000000000000000000000 +00000000000000000000000001000000000000000000000000000000000 +----0--0011------------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000001000000000000000000000000000000000 +----0--1111110000000111- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000100000000000000000000000000000000 +-0--0--11111-000001110-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000010000000000000000000000000000000 +-0--0--11111-000001101-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000010000000000000000000000000000000 +----0--11111-00000110-0- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000010000000000000000000000000000000 +----0--11111-0000011-00- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000010000000000000000000000000000000 +----0--110-0------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000010000000000000000000000000000000 +----0--11---0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000010000000000000000000000000000000 +-0--0--111111000001101-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000001000000000000000000000000000000 +----0--1111110000011000- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000001000000000000000000000000000000 +-0--0--1111110000011-11- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000001000000000000000000000000000000 +----0--1111110000000111- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000001000000000000000000000000000000 +-1--0--111111000000011-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000001000000000000000000000000000000 +-0--0--1111110000000010- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000001000000000000000000000000000000 +----0--110-0------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000001000000000000000000000000000000 +----0--110--0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000001000000000000000000000000000000 +-0--0--111111000001101-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000100000000000000000000000000000 +----0--11111100000110-0- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000100000000000000000000000000000 +----0--110-0------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000100000000000000000000000000000 +----0--110--0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000100000000000000000000000000000 +-0--0--111111000001101-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000010000000000000000000000000000 +----0--11111100000110-0- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000010000000000000000000000000000 +-1--0--1111110000000110- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000010000000000000000000000000000 +----0--110-0------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000010000000000000000000000000000 +----0--110--0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000010000000000000000000000000000 +-0--0--111111000001101-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000001000000000000000000000000000 +----0--11111100000110-0- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000001000000000000000000000000000 +----0--11000------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000001000000000000000000000000000 +----0--110--0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000001000000000000000000000000000 +----0--1101------------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000100000000000000000000000000 +----0--110-0------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000100000000000000000000000000 +----0--11---0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000100000000000000000000000000 +-0--0--11-11-000001110-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000100000000000000000000000000 +----0--11-11-000001101-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000100000000000000000000000000 +----0--11-11-00000110-0- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000100000000000000000000000000 +----0--11-11-0000011-00- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000100000000000000000000000000 +-0--0--111111000001101-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000010000000000000000000000000 +----0--1111110000011000- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000010000000000000000000000000 +-0--0--1111110000000010- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000010000000000000000000000000 +----0--110-0------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000010000000000000000000000000 +----0--110--0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000010000000000000000000000000 +-0--0--1111110000100--1- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000001000000000000000000000000 +----0--111111000010-0-1- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000001000000000000000000000000 +----0--1111110000100-11- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000001000000000000000000000000 +----0--11111100001011-0- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000001000000000000000000000000 +-0--0--1111110000011111- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000001000000000000000000000000 +----0--10000------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000100000000000000000000000 +-1--0--11111100000101-0- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000010000000000000000000000 +----0--1111110000010100- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000010000000000000000000000 +----0--10100------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000010000000000000000000000 +----0--101-01----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000010000000000000000000000 +----0--10010------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000010000000000000000000000 +----0--100011----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000010000000000000000000000 +-1--0--11111100000101-1- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000001000000000000000000000 +----0--1111110000010101- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000001000000000000000000000 +-0--0--1111110000010000- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000001000000000000000000000 +----0--101101----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000001000000000000000000000 +----0--10000------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000001000000000000000000000 +----0--1000-0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000001000000000000000000000 +-1--0--111111000001010-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000100000000000000000000 +-0--0--1111110000010000- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000100000000000000000000 +----0--10000------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000100000000000000000000 +----0--1000-0----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000100000000000000000000 +-0---------------------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000010000000000000000000 +----1------------------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000010000000000000000000 +-------0---------------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000010000000000000000000 +--------1--------------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000010000000000000000000 +---------11------------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000010000000000000000000 +----------11------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000010000000000000000000 +-0--0--1111110000010111- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000001000000000000000000 +----0--101110----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000001000000000000000000 +-1--0--111111000001011-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000100000000000000000 +----0--10011------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000010000000000000000 +----0--011011----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000001000000000000000 +----0--0001-1----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000001000000000000000 +-----------------------1 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000100000000000000 +----0--0011------------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000010000000000000 +----0--101111----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000001000000000000 +----0--110010----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000100000000000 +----0--111110----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000010000000000 +----0--11-101----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000010000000000 +----0--001011----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000001000000000 +----0--01--10----------- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000100000000 +----0--010-1------------ 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000100000000 +-0--0--111111000010111-- 00000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000010000000 diff --git a/espresso/examples/indust/dc1 b/espresso/examples/indust/dc1 new file mode 100644 index 0000000..e7e3dd1 --- /dev/null +++ b/espresso/examples/indust/dc1 @@ -0,0 +1,17 @@ +.i 4 +.o 7 +0100 0000010 +0101 0000100 +0111 0000010 +01-1 0010000 +001- 0011100 +0-00 1000000 +100- 1011000 +010- 1001000 +01-0 1000000 +-000 0110100 +0-10 0101100 +0--1 0000001 +01-- 0000001 +00-- 0000010 +-00- 0000011 diff --git a/espresso/examples/indust/dc2 b/espresso/examples/indust/dc2 new file mode 100644 index 0000000..d380a1d --- /dev/null +++ b/espresso/examples/indust/dc2 @@ -0,0 +1,60 @@ +.i 8 +.o 7 +0111000- 0000110 +0111010- 0000010 +0111100- 0001110 +1000001- 0000010 +1000011- 0000010 +1001000- 0000010 +1001010- 0011110 +1001100- 0100010 +0000001- 0000010 +0001001- 0000100 +0000011- 0000010 +0010100- 0001100 +0011011- 0000100 +0001000- 0000010 +0101001- 0001100 +0001010- 0001110 +0110100- 1000100 +0111011- 0000100 +0001100- 0010010 +1001001- 0000100 +0000100- 0001000 +0010001- 0000010 +0010011- 0000010 +0011000- 0011110 +0111001- 0001000 +0011010- 0000010 +1000100- 0001000 +0011100- 0100110 +0001011- 0010000 +0100001- 0000010 +0100100- 0010000 +0100011- 0000010 +0101000- 0000010 +0011001- 0100000 +0101010- 0001110 +0101100- 0000010 +1001011- 0100000 +0110001- 0000010 +0110011- 0000010 +011101-- 0001000 +100100-- 0011000 +000001-- 0000100 +001000-- 0000100 +010001-- 0001100 +001101-- 0100000 +011000-- 0111100 +011001-- 1000000 +100001-- 0000100 +000100-- 0001000 +001001-- 0001000 +010000-- 0001000 +1000---- 1010000 +0100---- 0100000 +0111---- 1000000 +1001---- 1000000 +0010---- 0010000 +0101---- 0110000 +-------1 0000001 diff --git a/espresso/examples/indust/dekoder b/espresso/examples/indust/dekoder new file mode 100644 index 0000000..40b6ed2 --- /dev/null +++ b/espresso/examples/indust/dekoder @@ -0,0 +1,20 @@ +.i 4 +.o 7 +.p 16 +0000 1111 110 +0001 0110 000 +0010 1101 101 +0011 1111 001 +0100 0110 011 +0101 1011 011 +0110 1011 111 +0111 1110 000 +1000 1111 111 +1001 1111 011 +1010 ---- --- +1011 ---- --- +1100 ---- --- +1101 ---- --- +1110 ---- --- +1111 ---- --- +.e diff --git a/espresso/examples/indust/dk17 b/espresso/examples/indust/dk17 new file mode 100644 index 0000000..3f211c7 --- /dev/null +++ b/espresso/examples/indust/dk17 @@ -0,0 +1,95 @@ +.i 10 +.o 11 +1000000000 10000000000 +0010000000 10000000000 +0100000000 00100000000 +0000100000 00100000000 +0001000000 00010000000 +0000001000 00010000000 +0000000100 00010000000 +0000010000 00000010000 +0100000000 00000000000 +0000100000 00000000000 +0000010000 00000000000 +1000000000 00000000001 +0010000000 00000000001 +0000001000 00000000010 +0001000000 00000000100 +0000000100 00000000100 +0010000001 10000000000 +0000001001 10000000000 +1000000001 00010000000 +0100000001 00010000000 +0000100001 00010000000 +0001000001 00001000000 +0000000101 00001000000 +0000010001 00000001000 +0100000001 00000000000 +0000100001 00000000000 +0000010001 00000000000 +1000000001 00000000010 +0001000001 00000000100 +0000000101 00000000100 +0010000001 00000000101 +0000001001 00000000101 +1000000010 01000000000 +0010000010 01000000000 +0100000010 00100000000 +0000100010 00100000000 +0000010010 00100000000 +0000000110 00100000000 +0001000010 00010000000 +0000001010 00001000000 +1000000010 00000000001 +0010000010 00000000001 +0100000010 00000000010 +0001000010 00000000010 +0000100010 00000000010 +0000010010 00000000010 +0000001010 00000000010 +0000000110 00000000010 +0010000011 01000000000 +0000001011 01000000000 +0000100011 00100000000 +0000010011 00100000000 +0000000111 00100000000 +1000000011 00001000000 +0001000011 00001000000 +0100000011 00000100000 +0100000011 00000000000 +1000000011 00000000010 +0001000011 00000000010 +0000100011 00000000100 +0000010011 00000000100 +0000000111 00000000100 +0010000011 00000000101 +0000001011 00000000101 +11-------- 22222222222 +1-1------- 22222222222 +1--1------ 22222222222 +1---1----- 22222222222 +1----1---- 22222222222 +1-----1--- 22222222222 +1------1-- 22222222222 +00000000-- 22222222222 +-11------- 22222222222 +-1-1------ 22222222222 +-1--1----- 22222222222 +-1---1---- 22222222222 +-1----1--- 22222222222 +-1-----1-- 22222222222 +--11------ 22222222222 +--1-1----- 22222222222 +--1--1---- 22222222222 +--1---1--- 22222222222 +--1----1-- 22222222222 +---11----- 22222222222 +---1-1---- 22222222222 +---1--1--- 22222222222 +---1---1-- 22222222222 +----11---- 22222222222 +----1-1--- 22222222222 +----1--1-- 22222222222 +-----11--- 22222222222 +-----1-1-- 22222222222 +------11-- 22222222222 diff --git a/espresso/examples/indust/dk27 b/espresso/examples/indust/dk27 new file mode 100644 index 0000000..c808de3 --- /dev/null +++ b/espresso/examples/indust/dk27 @@ -0,0 +1,54 @@ +.i 9 +.o 9 +001000010 100000000 +000010010 100000000 +100000010 001000000 +000100010 001000000 +010000010 000010000 +000001010 000010000 +000000110 000010000 +100000010 000000000 +010000010 000000000 +000100010 000000000 +000001010 000000000 +000000110 000000000 +001000010 000000001 +000010010 000000010 +001000001 010000000 +000010001 010000000 +000100001 001000000 +000000101 001000000 +100000001 000100000 +010000001 000001000 +000001001 000000100 +100000001 000000000 +010000001 000000000 +000001001 000000000 +001000001 000000001 +000100001 000000010 +000010001 000000010 +000000101 000000010 +11------- 222222222 +1-1------ 222222222 +1--1----- 222222222 +1---1---- 222222222 +1----1--- 222222222 +1-----1-- 222222222 +0000000-- 222222222 +-11------ 222222222 +-1-1----- 222222222 +-1--1---- 222222222 +-1---1--- 222222222 +-1----1-- 222222222 +--11----- 222222222 +--1-1---- 222222222 +--1--1--- 222222222 +--1---1-- 222222222 +---11---- 222222222 +---1-1--- 222222222 +---1--1-- 222222222 +----11--- 222222222 +----1-1-- 222222222 +-----11-- 222222222 +-------11 222222222 +-------00 222222222 diff --git a/espresso/examples/indust/dk48 b/espresso/examples/indust/dk48 new file mode 100644 index 0000000..b991883 --- /dev/null +++ b/espresso/examples/indust/dk48 @@ -0,0 +1,150 @@ +.i 15 +.o 17 +000000100000000 10000000000000000 +000000000010000 00100000000000000 +000000000001000 00100000000000000 +000000000100000 00010000000000000 +000000000000010 00010000000000000 +010000000000000 00001000000000000 +000001000000000 00001000000000000 +000000010000000 00001000000000000 +100000000000000 00000010000000000 +000100000000000 00000010000000000 +000000000000100 00000010000000000 +001000000000000 00000000010000000 +000000001000000 00000000010000000 +000010000000000 00000000000010000 +100000000000000 00000000000000000 +010000000000000 00000000000000000 +001000000000000 00000000000000000 +000100000000000 00000000000000000 +000010000000000 00000000000000000 +000001000000000 00000000000000000 +000000010000000 00000000000000000 +000000001000000 00000000000000000 +000000100000000 00000000000000001 +000000000100000 00000000000000010 +000000000010000 00000000000000010 +000000000001000 00000000000000100 +000000000000100 00000000000000100 +000000000000010 00000000000000100 +000000100000001 01000000000000000 +000001000000001 00100000000000000 +000000010000001 00100000000000000 +000000001000001 00100000000000000 +000000000001001 00100000000000000 +010000000000001 00010000000000000 +000000000100001 00001000000000000 +000000000000011 00001000000000000 +000000000010001 00000100000000000 +000000000000101 00000001000000000 +100000000000001 00000000100000000 +001000000000001 00000000001000000 +000100000000001 00000000000100000 +000010000000001 00000000000001000 +100000000000001 00000000000000000 +010000000000001 00000000000000000 +001000000000001 00000000000000000 +000100000000001 00000000000000000 +000010000000001 00000000000000000 +000001000000001 00000000000000000 +000000100000001 00000000000000001 +000000010000001 00000000000000001 +000000001000001 00000000000000001 +000000000001001 00000000000000001 +000000000100001 00000000000000010 +000000000010001 00000000000000010 +000000000000101 00000000000000100 +000000000000011 00000000000000100 +11------------- 22222222222222222 +1-1------------ 22222222222222222 +1--1----------- 22222222222222222 +1---1---------- 22222222222222222 +1----1--------- 22222222222222222 +1-----1-------- 22222222222222222 +1------1------- 22222222222222222 +1-------1------ 22222222222222222 +1--------1----- 22222222222222222 +1---------1---- 22222222222222222 +1----------1--- 22222222222222222 +1-----------1-- 22222222222222222 +1------------1- 22222222222222222 +00000000000000- 22222222222222222 +-11------------ 22222222222222222 +-1-1----------- 22222222222222222 +-1--1---------- 22222222222222222 +-1---1--------- 22222222222222222 +-1----1-------- 22222222222222222 +-1-----1------- 22222222222222222 +-1------1------ 22222222222222222 +-1-------1----- 22222222222222222 +-1--------1---- 22222222222222222 +-1---------1--- 22222222222222222 +-1----------1-- 22222222222222222 +-1-----------1- 22222222222222222 +--11----------- 22222222222222222 +--1-1---------- 22222222222222222 +--1--1--------- 22222222222222222 +--1---1-------- 22222222222222222 +--1----1------- 22222222222222222 +--1-----1------ 22222222222222222 +--1------1----- 22222222222222222 +--1-------1---- 22222222222222222 +--1--------1--- 22222222222222222 +--1---------1-- 22222222222222222 +--1----------1- 22222222222222222 +---11---------- 22222222222222222 +---1-1--------- 22222222222222222 +---1--1-------- 22222222222222222 +---1---1------- 22222222222222222 +---1----1------ 22222222222222222 +---1-----1----- 22222222222222222 +---1------1---- 22222222222222222 +---1-------1--- 22222222222222222 +---1--------1-- 22222222222222222 +---1---------1- 22222222222222222 +----11--------- 22222222222222222 +----1-1-------- 22222222222222222 +----1--1------- 22222222222222222 +----1---1------ 22222222222222222 +----1----1----- 22222222222222222 +----1-----1---- 22222222222222222 +----1------1--- 22222222222222222 +----1-------1-- 22222222222222222 +----1--------1- 22222222222222222 +-----11-------- 22222222222222222 +-----1-1------- 22222222222222222 +-----1--1------ 22222222222222222 +-----1---1----- 22222222222222222 +-----1----1---- 22222222222222222 +-----1-----1--- 22222222222222222 +-----1------1-- 22222222222222222 +-----1-------1- 22222222222222222 +------11------- 22222222222222222 +------1-1------ 22222222222222222 +------1--1----- 22222222222222222 +------1---1---- 22222222222222222 +------1----1--- 22222222222222222 +------1-----1-- 22222222222222222 +------1------1- 22222222222222222 +-------11------ 22222222222222222 +-------1-1----- 22222222222222222 +-------1--1---- 22222222222222222 +-------1---1--- 22222222222222222 +-------1----1-- 22222222222222222 +-------1-----1- 22222222222222222 +--------11----- 22222222222222222 +--------1-1---- 22222222222222222 +--------1--1--- 22222222222222222 +--------1---1-- 22222222222222222 +--------1----1- 22222222222222222 +---------11---- 22222222222222222 +---------1-1--- 22222222222222222 +---------1--1-- 22222222222222222 +---------1---1- 22222222222222222 +----------11--- 22222222222222222 +----------1-1-- 22222222222222222 +----------1--1- 22222222222222222 +-----------11-- 22222222222222222 +-----------1-1- 22222222222222222 +------------11- 22222222222222222 diff --git a/espresso/examples/indust/ex4 b/espresso/examples/indust/ex4 new file mode 100644 index 0000000..a15d02c --- /dev/null +++ b/espresso/examples/indust/ex4 @@ -0,0 +1,1862 @@ +.i 128 +.o 28 +----------------------------------------------0-------0------------- +--1-------0-------0-------1--------------------------------- +0000000000000010000000000000 +---------------------------------------------0-------0-------------- +-1-------0-------0-------1---------------------------------- +0000000000000100000000000000 +----------------------------------------0-------0---------------1--- +----0-------0-------1--------------------------------------- +0000000010000000000000000000 +----------------------------------------------0-------0-------1----- +--1-------0-------0----------------------------------------- +0000000000000010000000000000 +---------------------------------------------0-------0-------1------ +-1-------0-------0------------------------------------------ +0000000000000100000000000000 +----------------------------------------0-------0-------1-------1--- +----0-------0----------------------------------------------- +0000000010000000000000000000 +--------------------------------------0-------1-------0------------- +------------------------------------------------------------ +0000001000000000000000000000 +--------------0-------------------------------1--------------------- +----------0------------------------------------------------- +0000001000000000000000000000 +------0---------------------------------------1-------1------------- +----------1-------0----------------------------------------- +0000001000000000000000000000 +----------------------0-----------------------1-------1------------- +----------1-------1-------------------------------0--------- +0000001000000000000000000000 +----------------------0-----------------------1-------1------------- +----------1-------1-----------------------0----------------- +0000001000000000000000000000 +--------------------------------------0-------1-------1------------- +----------1-------1-------0--------------------------------- +0000001000000000000000000000 +----------------------------------------------1-------1------------- +--0-------1-------1-------0--------------------------------- +0000001000000000000000000000 +----------------------------------------------1-------1-------0----- +--0-------1-------1----------------------------------------- +0000001000000000000000000000 +--------------------------------------0-------1-------1-------0----- +----------1-------1----------------------------------------- +0000001000000000000000000000 +--------------0-------------------------------1-------1------------- +----------1-------1-------------------------------0--------- +0000001000000000000000000000 +--------------0-------------------------------1-------1------------- +----------1-------1-----------------------0----------------- +0000001000000000000000000000 +------0---------------------------------------1-------1------------- +--1-------1-------1-------1-------0------------------------- +0000001000000000000000000000 +------0---------------------------------------1-------1------------- +--1-------1-------1-------1-----------------------0--------- +0000001000000000000000000000 +------0---------------------------------------1-------1------------- +--1-------1-------1-------1-------------------------------0- +0000001000000000000000000000 +------0---------------------------------------1-------1------------- +--1-------1-------1-------1---------------0----------------- +0000001000000000000000000000 +------0---------------------------------------1-------1-------1----- +--1-------1-------1---------------------------------------0- +0000001000000000000000000000 +------0---------------------------------------1-------1-------1----- +--1-------1-------1---------------0------------------------- +0000001000000000000000000000 +------0---------------------------------------1-------1-------1----- +--1-------1-------1-----------------------0----------------- +0000001000000000000000000000 +------0---------------------------------------1-------1-------1----- +--1-------1-------1-------------------------------0--------- +0000001000000000000000000000 +-------------------------------------0-------1-------0-------------- +------------------------------------------------------------ +0000010000000000000000000000 +-------------0-------------------------------1---------------------- +---------0-------------------------------------------------- +0000010000000000000000000000 +-----0---------------------------------------1-------1-------------- +---------1-------0------------------------------------------ +0000010000000000000000000000 +---------------------------------------------1-------1-------0------ +-0-------1-------1------------------------------------------ +0000010000000000000000000000 +---------------------0-----------------------1-------1-------------- +---------1-------1-------------------------------0---------- +0000010000000000000000000000 +---------------------0-----------------------1-------1-------------- +---------1-------1-----------------------0------------------ +0000010000000000000000000000 +-------------------------------------0-------1-------1-------0------ +---------1-------1------------------------------------------ +0000010000000000000000000000 +-------------------------------------0-------1-------1-------------- +---------1-------1-------0---------------------------------- +0000010000000000000000000000 +-------------0-------------------------------1-------1-------------- +---------1-------1-------------------------------0---------- +0000010000000000000000000000 +---------------------------------------------1-------1-------------- +-0-------1-------1-------0---------------------------------- +0000010000000000000000000000 +-------------0-------------------------------1-------1-------------- +---------1-------1-----------------------0------------------ +0000010000000000000000000000 +-----0---------------------------------------1-------1-------------- +-1-------1-------1-------1-----------------------0---------- +0000010000000000000000000000 +-----0---------------------------------------1-------1-------------- +-1-------1-------1-------1-------0-------------------------- +0000010000000000000000000000 +-----0---------------------------------------1-------1-------------- +-1-------1-------1-------1-------------------------------0-- +0000010000000000000000000000 +-----0---------------------------------------1-------1-------------- +-1-------1-------1-------1---------------0------------------ +0000010000000000000000000000 +-----0---------------------------------------1-------1-------1------ +-1-------1-------1-------------------------------0---------- +0000010000000000000000000000 +-----0---------------------------------------1-------1-------1------ +-1-------1-------1-----------------------0------------------ +0000010000000000000000000000 +-----0---------------------------------------1-------1-------1------ +-1-------1-------1---------------0-------------------------- +0000010000000000000000000000 +-----0---------------------------------------1-------1-------1------ +-1-------1-------1---------------------------------------0-- +0000010000000000000000000000 +------------0-------------------------------1----------------------- +--------0--------------------------------------------------- +0000100000000000000000000000 +------------------------------------0-------1-------0--------------- +------------------------------------------------------------ +0000100000000000000000000000 +----0---------------------------------------1-------1--------------- +--------1-------0------------------------------------------- +0000100000000000000000000000 +-----------------------------------0-------1-------0---------------- +------------------------------------------------------------ +0001000000000000000000000000 +-----------0-------------------------------1------------------------ +-------0---------------------------------------------------- +0001000000000000000000000000 +---0---------------------------------------1-------1---------------- +-------1-------0-------------------------------------------- +0001000000000000000000000000 +----------0-------------------------------1------------------------- +------0----------------------------------------------------- +0010000000000000000000000000 +----------------------------------0-------1-------0----------------- +------------------------------------------------------------ +0010000000000000000000000000 +--0---------------------------------------1-------1----------------- +------1-------0--------------------------------------------- +0010000000000000000000000000 +---------0-------------------------------1-------------------------- +-----0------------------------------------------------------ +0100000000000000000000000000 +---------------------------------0-------1-------0------------------ +------------------------------------------------------------ +0100000000000000000000000000 +-0---------------------------------------1-------1------------------ +-----1-------0---------------------------------------------- +0100000000000000000000000000 +--------------------------------0-------1-------0------------------- +------------------------------------------------------------ +1000000000000000000000000000 +--------0-------------------------------1--------------------------- +----0------------------------------------------------------- +1000000000000000000000000000 +0---------------------------------------1-------1------------------- +----1-------0----------------------------------------------- +1000000000000000000000000000 +--------------------------------------1-------0-------0------------- +----------0-------0-------1--------------------------------- +0000000000000010000000000000 +--------------------------------------1-------0-------0-------1----- +----------0-------0----------------------------------------- +0000000000000010000000000000 +--------------------------------------1-------0-------1------------- +------------------------------------------------------------ +0000000000000010000000000000 +----------------------0---------------1-------1--------------------- +--0-------1------------------------------------------------- +0000001000000000000000000000 +------0-------------------------------1-------1-------1------------- +------------------0----------------------------------------- +0000001000000000000000000000 +----------------------0---------------1-------1-------1------------- +--0--------------------------------------------------------- +0000001000000000000000000000 +------0-------------------------------1-------1-------1------------- +----------1-------1-------1-------0------------------------- +0000001000000000000000000000 +------0-------------------------------1-------1-------1------------- +----------1-------1-------1-----------------------0--------- +0000001000000000000000000000 +------0-------------------------------1-------1-------1------------- +----------1-------1-------1---------------0----------------- +0000001000000000000000000000 +------0-------------------------------1-------1-------1------------- +----------1-------1-------1-------------------------------0- +0000001000000000000000000000 +------0-------------------------------1-------1-------1-------1----- +----------1-------1---------------------------------------0- +0000001000000000000000000000 +------0-------------------------------1-------1-------1-------1----- +----------1-------1-----------------------0----------------- +0000001000000000000000000000 +------0-------------------------------1-------1-------1-------1----- +----------1-------1-------------------------------0--------- +0000001000000000000000000000 +------0-------------------------------1-------1-------1-------1----- +----------1-------1---------------0------------------------- +0000001000000000000000000000 +-------------------------------------1-------0-------0-------------- +---------0-------0-------1---------------------------------- +0000000000000100000000000000 +-------------------------------------1-------0-------0-------1------ +---------0-------0------------------------------------------ +0000000000000100000000000000 +-------------------------------------1-------0-------1-------------- +------------------------------------------------------------ +0000000000000100000000000000 +---------------------0---------------1-------1---------------------- +-0-------1-------------------------------------------------- +0000010000000000000000000000 +-----0-------------------------------1-------1-------1-------------- +-----------------0------------------------------------------ +0000010000000000000000000000 +---------------------0---------------1-------1-------1-------------- +-0---------------------------------------------------------- +0000010000000000000000000000 +-----0-------------------------------1-------1-------1-------------- +---------1-------1-------1-------------------------------0-- +0000010000000000000000000000 +-----0-------------------------------1-------1-------1-------------- +---------1-------1-------1-----------------------0---------- +0000010000000000000000000000 +-----0-------------------------------1-------1-------1-------------- +---------1-------1-------1-------0-------------------------- +0000010000000000000000000000 +-----0-------------------------------1-------1-------1-------------- +---------1-------1-------1---------------0------------------ +0000010000000000000000000000 +-----0-------------------------------1-------1-------1-------1------ +---------1-------1-------------------------------0---------- +0000010000000000000000000000 +-----0-------------------------------1-------1-------1-------1------ +---------1-------1---------------------------------------0-- +0000010000000000000000000000 +-----0-------------------------------1-------1-------1-------1------ +---------1-------1---------------0-------------------------- +0000010000000000000000000000 +-----0-------------------------------1-------1-------1-------1------ +---------1-------1-----------------------0------------------ +0000010000000000000000000000 +------------------------------------1-------0-------1--------------- +------------------------------------------------------------ +0000000000001000000000000000 +--------------------0---------------1-------1----------------------- +0-------1--------------------------------------------------- +0000100000000000000000000000 +--------------------0---------------1-------1-------1--------------- +0----------------------------------------------------------- +0000100000000000000000000000 +----0-------------------------------1-------1-------1--------------- +----------------0------------------------------------------- +0000100000000000000000000000 +-----------------------------------1-------0-------1---------------- +------------------------------------------------------------ +0000000000010000000000000000 +-------------------0---------------1-------1-----------------------0 +-------1---------------------------------------------------- +0001000000000000000000000000 +-------------------0---------------1-------1-------1---------------0 +------------------------------------------------------------ +0001000000000000000000000000 +---0-------------------------------1-------1-------1---------------- +---------------0-------------------------------------------- +0001000000000000000000000000 +----------------------------------1-------0-------1----------------- +------------------------------------------------------------ +0000000000100000000000000000 +------------------0---------------1-------1-----------------------0- +------1----------------------------------------------------- +0010000000000000000000000000 +------------------0---------------1-------1-------1---------------0- +------------------------------------------------------------ +0010000000000000000000000000 +--0-------------------------------1-------1-------1----------------- +--------------0--------------------------------------------- +0010000000000000000000000000 +---------------------------------1-------0-------1------------------ +------------------------------------------------------------ +0000000001000000000000000000 +-----------------0---------------1-------1-----------------------0-- +-----1------------------------------------------------------ +0100000000000000000000000000 +-----------------0---------------1-------1-------1---------------0-- +------------------------------------------------------------ +0100000000000000000000000000 +-0-------------------------------1-------1-------1------------------ +-------------0---------------------------------------------- +0100000000000000000000000000 +--------------------------------1-------0-------0------------------- +----0-------0-------1--------------------------------------- +0000000010000000000000000000 +--------------------------------1-------0-------0-------1----------- +----0-------0----------------------------------------------- +0000000010000000000000000000 +--------------------------------1-------0-------1------------------- +------------------------------------------------------------ +0000000010000000000000000000 +----------------0---------------1-------1-----------------------0--- +----1------------------------------------------------------- +1000000000000000000000000000 +----------------0---------------1-------1-------1---------------0--- +------------------------------------------------------------ +1000000000000000000000000000 +0-------------------------------1-------1-------1------------------- +------------0----------------------------------------------- +1000000000000000000000000000 +--------------0---------------1---------------0-------0------------- +----------0-------0-------0-------------------------------1- +0000000000000010000000000000 +----------------------0-------1---------------0-------0-------0----- +----------0-------0---------------------------------------1- +0000000000000010000000000000 +--------------0---------------1---------------0-------0-------0----- +----------0-------0---------------------------------------1- +0000000000000010000000000000 +----------------------0-------1---------------0-------0------------- +----------0-------0-------0-------------------------------1- +0000000000000010000000000000 +----------------------0-------1---------------0-------0-------0----- +----------0-------0-------------------------------1--------- +0000000000000010000000000000 +--------------0---------------1---------------0-------0-------0----- +----------0-------0-------------------------------1--------- +0000000000000010000000000000 +----------------------0-------1---------------0-------0------------- +----------0-------0-------0-----------------------1--------- +0000000000000010000000000000 +--------------0---------------1---------------0-------0------------- +----------0-------0-------0-----------------------1--------- +0000000000000010000000000000 +----------------------0-------1---------------0-------0-------0----- +----------0-------0-----------------------1----------------- +0000000000000010000000000000 +----------------------0-------1---------------0-------0------------- +----------0-------0-------0---------------1----------------- +0000000000000010000000000000 +--------------0---------------1---------------0-------0------------- +----------0-------0-------0---------------1----------------- +0000000000000010000000000000 +--------------0---------------1---------------0-------0-------0----- +----------0-------0-----------------------1----------------- +0000000000000010000000000000 +--------------0---------------1---------------0-------0-------0----- +----------0-------0---------------1------------------------- +0000000000000010000000000000 +----------------------0-------1---------------0-------0------------- +----------0-------0-------0-------1------------------------- +0000000000000010000000000000 +----------------------0-------1---------------0-------0-------0----- +----------0-------0---------------1------------------------- +0000000000000010000000000000 +--------------0---------------1---------------0-------0------------- +----------0-------0-------0-------1------------------------- +0000000000000010000000000000 +----------------------0-------1---------------0-------0-------0----- +--1-------0-------0----------------------------------------- +0000000000000010000000000000 +----------------------0-------1---------------0-------0------------- +--1-------0-------0-------0--------------------------------- +0000000000000010000000000000 +--------------0---------------1---------------0-------0------------- +--1-------0-------0-------0--------------------------------- +0000000000000010000000000000 +--------------0---------------1---------------0-------0-------0----- +--1-------0-------0----------------------------------------- +0000000000000010000000000000 +--------------0---------------1-------1-------0-------0-------0----- +----------0-------0----------------------------------------- +0000000000000010000000000000 +----------------------0-------1-------1-------0-------0-------0----- +----------0-------0----------------------------------------- +0000000000000010000000000000 +--------------0---------------1-------1-------0-------0------------- +----------0-------0-------0--------------------------------- +0000000000000010000000000000 +----------------------0-------1-------1-------0-------0------------- +----------0-------0-------0--------------------------------- +0000000000000010000000000000 +-------------0---------------1---------------0-------0-------------- +---------0-------0-------0-------------------------------1-- +0000000000000100000000000000 +-------------0---------------1---------------0-------0-------0------ +---------0-------0---------------------------------------1-- +0000000000000100000000000000 +---------------------0-------1---------------0-------0-------0------ +---------0-------0---------------------------------------1-- +0000000000000100000000000000 +---------------------0-------1---------------0-------0-------------- +---------0-------0-------0-------------------------------1-- +0000000000000100000000000000 +---------------------0-------1---------------0-------0-------0------ +---------0-------0-------------------------------1---------- +0000000000000100000000000000 +-------------0---------------1---------------0-------0-------------- +---------0-------0-------0-----------------------1---------- +0000000000000100000000000000 +---------------------0-------1---------------0-------0-------------- +---------0-------0-------0-----------------------1---------- +0000000000000100000000000000 +-------------0---------------1---------------0-------0-------0------ +---------0-------0-------------------------------1---------- +0000000000000100000000000000 +-------------0---------------1---------------0-------0-------------- +---------0-------0-------0---------------1------------------ +0000000000000100000000000000 +---------------------0-------1---------------0-------0-------0------ +---------0-------0-----------------------1------------------ +0000000000000100000000000000 +-------------0---------------1---------------0-------0-------0------ +---------0-------0-----------------------1------------------ +0000000000000100000000000000 +---------------------0-------1---------------0-------0-------------- +---------0-------0-------0---------------1------------------ +0000000000000100000000000000 +-------------0---------------1---------------0-------0-------------- +---------0-------0-------0-------1-------------------------- +0000000000000100000000000000 +-------------0---------------1---------------0-------0-------0------ +---------0-------0---------------1-------------------------- +0000000000000100000000000000 +---------------------0-------1---------------0-------0-------------- +---------0-------0-------0-------1-------------------------- +0000000000000100000000000000 +---------------------0-------1---------------0-------0-------0------ +---------0-------0---------------1-------------------------- +0000000000000100000000000000 +-------------0---------------1---------------0-------0-------0------ +-1-------0-------0------------------------------------------ +0000000000000100000000000000 +---------------------0-------1---------------0-------0-------0------ +-1-------0-------0------------------------------------------ +0000000000000100000000000000 +-------------0---------------1---------------0-------0-------------- +-1-------0-------0-------0---------------------------------- +0000000000000100000000000000 +---------------------0-------1---------------0-------0-------------- +-1-------0-------0-------0---------------------------------- +0000000000000100000000000000 +-------------0---------------1-------1-------0-------0-------0------ +---------0-------0------------------------------------------ +0000000000000100000000000000 +---------------------0-------1-------1-------0-------0-------0------ +---------0-------0------------------------------------------ +0000000000000100000000000000 +-------------0---------------1-------1-------0-------0-------------- +---------0-------0-------0---------------------------------- +0000000000000100000000000000 +---------------------0-------1-------1-------0-------0-------------- +---------0-------0-------0---------------------------------- +0000000000000100000000000000 +--------0---------------1---------------0-------0------------------- +----0-------0-------0-------------------------------1------- +0000000010000000000000000000 +----------------0-------1---------------0-------0-------0----------- +----0-------0---------------------------------------1------- +0000000010000000000000000000 +--------0---------------1---------------0-------0-------0----------- +----0-------0---------------------------------------1------- +0000000010000000000000000000 +----------------0-------1---------------0-------0------------------- +----0-------0-------0-------------------------------1------- +0000000010000000000000000000 +----------------0-------1---------------0-------0------------------- +----0-------0-------0-----------------------1--------------- +0000000010000000000000000000 +--------0---------------1---------------0-------0-------0----------- +----0-------0-------------------------------1--------------- +0000000010000000000000000000 +--------0---------------1---------------0-------0------------------- +----0-------0-------0-----------------------1--------------- +0000000010000000000000000000 +----------------0-------1---------------0-------0-------0----------- +----0-------0-------------------------------1--------------- +0000000010000000000000000000 +--------0---------------1---------------0-------0------------------- +----0-------0-------0---------------1----------------------- +0000000010000000000000000000 +----------------0-------1---------------0-------0-------0----------- +----0-------0-----------------------1----------------------- +0000000010000000000000000000 +----------------0-------1---------------0-------0------------------- +----0-------0-------0---------------1----------------------- +0000000010000000000000000000 +--------0---------------1---------------0-------0-------0----------- +----0-------0-----------------------1----------------------- +0000000010000000000000000000 +----------------0-------1---------------0-------0-------0----------- +----0-------0---------------1------------------------------- +0000000010000000000000000000 +--------0---------------1---------------0-------0-------0----------- +----0-------0---------------1------------------------------- +0000000010000000000000000000 +--------0---------------1---------------0-------0------------------- +----0-------0-------0-------1------------------------------- +0000000010000000000000000000 +----------------0-------1---------------0-------0------------------- +----0-------0-------0-------1------------------------------- +0000000010000000000000000000 +--------0---------------1---------------0-------0---------------1--- +----0-------0-------0--------------------------------------- +0000000010000000000000000000 +----------------0-------1---------------0-------0-------0-------1--- +----0-------0----------------------------------------------- +0000000010000000000000000000 +----------------0-------1---------------0-------0---------------1--- +----0-------0-------0--------------------------------------- +0000000010000000000000000000 +--------0---------------1---------------0-------0-------0-------1--- +----0-------0----------------------------------------------- +0000000010000000000000000000 +--------0---------------1-------1-------0-------0------------------- +----0-------0-------0--------------------------------------- +0000000010000000000000000000 +----------------0-------1-------1-------0-------0-------0----------- +----0-------0----------------------------------------------- +0000000010000000000000000000 +----------------0-------1-------1-------0-------0------------------- +----0-------0-------0--------------------------------------- +0000000010000000000000000000 +--------0---------------1-------1-------0-------0-------0----------- +----0-------0----------------------------------------------- +0000000010000000000000000000 +----------------------1-----------------------0-------0------------- +----------0-------0-------------------------------1--------- +0000000000000010000000000000 +----------------------1-----------------------0-------0------------- +----------0-------0-----------------------1----------------- +0000000000000010000000000000 +--------------0-------1-----------------------0-------0------------- +--1--------------------------------------------------------- +0000000000000010000000000000 +--------------0-------1-----------------------0--------------------- +--1-------0------------------------------------------------- +0000000000000010000000000000 +----------------------1---------------0-------0--------------------- +--1-------0------------------------------------------------- +0000000000000010000000000000 +----------------------1---------------0-------0-------0------------- +--1--------------------------------------------------------- +0000000000000010000000000000 +------0---------------1-----------------------1-------1------------- +----------1-------1-------0-----------------------1--------- +0000001000000000000000000000 +------0---------------1-----------------------1-------1-------0----- +----------1-------1-------------------------------1--------- +0000001000000000000000000000 +------0---------------1-------0---------------1-------1------------- +----------1-------1-------------------------------1--------- +0000001000000000000000000000 +------0---------------1-----------------------1-------1------------- +----------1-------1-------------------------------1-------0- +0000001000000000000000000000 +------0---------------1-----------------------1-------1-------0----- +----------1-------1-----------------------1----------------- +0000001000000000000000000000 +------0---------------1-------0---------------1-------1------------- +----------1-------1-----------------------1----------------- +0000001000000000000000000000 +------0---------------1-----------------------1-------1------------- +----------1-------1-------0---------------1----------------- +0000001000000000000000000000 +------0---------------1-----------------------1-------1------------- +----------1-------1-----------------------1---------------0- +0000001000000000000000000000 +----------------------1-------0---------------1-------1------------- +--0-------1-------1-------1--------------------------------- +0000001000000000000000000000 +----------------------1-------0---------------1-------1------------- +----------1-------1-------1---------------0----------------- +0000001000000000000000000000 +----------------------1-------0-------0-------1-------1------------- +----------1-------1-------1--------------------------------- +0000001000000000000000000000 +----------------------1-------0---------------1-------1------------- +----------1-------1-------1-------------------------------0- +0000001000000000000000000000 +------0---------------1-------0---------------1-------1------------- +----------1-------1-------1--------------------------------- +0000001000000000000000000000 +----------------------1-------0---------------1-------1------------- +----------1-------1-------1-----------------------0--------- +0000001000000000000000000000 +----------------------1-------0---------------1-------1------------- +----------1-------1-------1-------0------------------------- +0000001000000000000000000000 +------0---------------1-----------------------1-------1------------- +--1-------1-------1-----------------------0----------------- +0000001000000000000000000000 +------0---------------1-----------------------1-------1------------- +--1-------1-------1-------------------------------0--------- +0000001000000000000000000000 +------0---------------1-----------------------1-------1-------0----- +--1-------1-------1----------------------------------------- +0000001000000000000000000000 +------0---------------1-------0---------------1-------1------------- +--1-------1-------1----------------------------------------- +0000001000000000000000000000 +------0---------------1-----------------------1-------1------------- +--1-------1-------1-------0--------------------------------- +0000001000000000000000000000 +------0---------------1-----------------------1-------1------------- +--1-------1-------1---------------------------------------0- +0000001000000000000000000000 +------0---------------1-----------------------1-------1------------- +--1-------1-------1---------------0------------------------- +0000001000000000000000000000 +------0---------------1-------0---------------1-------1-------1----- +----------1-------1----------------------------------------- +0000001000000000000000000000 +----------------------1-------0---------------1-------1-------1----- +----------1-------1---------------------------------------0- +0000001000000000000000000000 +----------------------1-------0-------0-------1-------1-------1----- +----------1-------1----------------------------------------- +0000001000000000000000000000 +----------------------1-------0---------------1-------1-------1----- +----------1-------1-------------------------------0--------- +0000001000000000000000000000 +----------------------1-------0---------------1-------1-------1----- +----------1-------1---------------0------------------------- +0000001000000000000000000000 +----------------------1-------0---------------1-------1-------1----- +----------1-------1-----------------------0----------------- +0000001000000000000000000000 +----------------------1-------0---------------1-------1-------1----- +--0-------1-------1----------------------------------------- +0000001000000000000000000000 +------0---------------1---------------1-------1-------1------------- +----------1-------1---------------0------------------------- +0000001000000000000000000000 +------0---------------1---------------1-------1-------1------------- +----------1-------1-------------------------------0--------- +0000001000000000000000000000 +------0---------------1-------0-------1-------1-------1------------- +----------1-------1----------------------------------------- +0000001000000000000000000000 +------0---------------1---------------1-------1-------1-------0----- +----------1-------1----------------------------------------- +0000001000000000000000000000 +------0---------------1---------------1-------1-------1------------- +----------1-------1-----------------------0----------------- +0000001000000000000000000000 +------0---------------1---------------1-------1-------1------------- +----------1-------1-------0--------------------------------- +0000001000000000000000000000 +------0---------------1---------------1-------1-------1------------- +----------1-------1---------------------------------------0- +0000001000000000000000000000 +---------------------1-----------------------0-------0-------------- +---------0-------0-------------------------------1---------- +0000000000000100000000000000 +---------------------1-----------------------0-------0-------------- +---------0-------0-----------------------1------------------ +0000000000000100000000000000 +-------------0-------1-----------------------0-------0-------------- +-1---------------------------------------------------------- +0000000000000100000000000000 +---------------------1---------------0-------0-------0-------------- +-1---------------------------------------------------------- +0000000000000100000000000000 +-------------0-------1-----------------------0---------------------- +-1-------0-------------------------------------------------- +0000000000000100000000000000 +---------------------1---------------0-------0---------------------- +-1-------0-------------------------------------------------- +0000000000000100000000000000 +-----0---------------1-----------------------1-------1-------------- +---------1-------1-------------------------------1-------0-- +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------------- +---------1-------1-------0-----------------------1---------- +0000010000000000000000000000 +-----0---------------1-------0---------------1-------1-------------- +---------1-------1-------------------------------1---------- +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------0------ +---------1-------1-------------------------------1---------- +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------------- +---------1-------1-----------------------1---------------0-- +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------0------ +---------1-------1-----------------------1------------------ +0000010000000000000000000000 +-----0---------------1-------0---------------1-------1-------------- +---------1-------1-----------------------1------------------ +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------------- +---------1-------1-------0---------------1------------------ +0000010000000000000000000000 +---------------------1-------0---------------1-------1-------------- +-0-------1-------1-------1---------------------------------- +0000010000000000000000000000 +---------------------1-------0---------------1-------1-------------- +---------1-------1-------1---------------0------------------ +0000010000000000000000000000 +---------------------1-------0---------------1-------1-------------- +---------1-------1-------1-------------------------------0-- +0000010000000000000000000000 +-----0---------------1-------0---------------1-------1-------------- +---------1-------1-------1---------------------------------- +0000010000000000000000000000 +---------------------1-------0---------------1-------1-------------- +---------1-------1-------1-------0-------------------------- +0000010000000000000000000000 +---------------------1-------0---------------1-------1-------------- +---------1-------1-------1-----------------------0---------- +0000010000000000000000000000 +---------------------1-------0-------0-------1-------1-------------- +---------1-------1-------1---------------------------------- +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------0------ +-1-------1-------1------------------------------------------ +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------------- +-1-------1-------1---------------------------------------0-- +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------------- +-1-------1-------1-------0---------------------------------- +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------------- +-1-------1-------1-------------------------------0---------- +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------------- +-1-------1-------1-----------------------0------------------ +0000010000000000000000000000 +-----0---------------1-------0---------------1-------1-------------- +-1-------1-------1------------------------------------------ +0000010000000000000000000000 +-----0---------------1-----------------------1-------1-------------- +-1-------1-------1---------------0-------------------------- +0000010000000000000000000000 +---------------------1-------0---------------1-------1-------1------ +---------1-------1-----------------------0------------------ +0000010000000000000000000000 +---------------------1-------0---------------1-------1-------1------ +-0-------1-------1------------------------------------------ +0000010000000000000000000000 +---------------------1-------0---------------1-------1-------1------ +---------1-------1---------------0-------------------------- +0000010000000000000000000000 +-----0---------------1-------0---------------1-------1-------1------ +---------1-------1------------------------------------------ +0000010000000000000000000000 +---------------------1-------0-------0-------1-------1-------1------ +---------1-------1------------------------------------------ +0000010000000000000000000000 +---------------------1-------0---------------1-------1-------1------ +---------1-------1-------------------------------0---------- +0000010000000000000000000000 +---------------------1-------0---------------1-------1-------1------ +---------1-------1---------------------------------------0-- +0000010000000000000000000000 +-----0---------------1---------------1-------1-------1-------------- +---------1-------1---------------------------------------0-- +0000010000000000000000000000 +-----0---------------1---------------1-------1-------1-------------- +---------1-------1-------------------------------0---------- +0000010000000000000000000000 +-----0---------------1-------0-------1-------1-------1-------------- +---------1-------1------------------------------------------ +0000010000000000000000000000 +-----0---------------1---------------1-------1-------1-------------- +---------1-------1-----------------------0------------------ +0000010000000000000000000000 +-----0---------------1---------------1-------1-------1-------------- +---------1-------1-------0---------------------------------- +0000010000000000000000000000 +-----0---------------1---------------1-------1-------1-------------- +---------1-------1---------------0-------------------------- +0000010000000000000000000000 +-----0---------------1---------------1-------1-------1-------0------ +---------1-------1------------------------------------------ +0000010000000000000000000000 +--------------------1---------------0-------0----------------------- +1-------0--------------------------------------------------- +0000000000001000000000000000 +------------0-------1-----------------------0----------------------- +1-------0--------------------------------------------------- +0000000000001000000000000000 +--------------------1---------------0-------0-------0--------------- +1----------------------------------------------------------- +0000000000001000000000000000 +------------0-------1-----------------------0-------0--------------- +1----------------------------------------------------------- +0000000000001000000000000000 +-------------------1---------------0-------0-----------------------1 +-------0---------------------------------------------------- +0000000000010000000000000000 +-------------------1---------------0-------0-------0---------------1 +------------------------------------------------------------ +0000000000010000000000000000 +-----------0-------1-----------------------0-----------------------1 +-------0---------------------------------------------------- +0000000000010000000000000000 +-----------0-------1-----------------------0-------0---------------1 +------------------------------------------------------------ +0000000000010000000000000000 +----------0-------1-----------------------0-----------------------1- +------0----------------------------------------------------- +0000000000100000000000000000 +------------------1---------------0-------0-------0---------------1- +------------------------------------------------------------ +0000000000100000000000000000 +------------------1---------------0-------0-----------------------1- +------0----------------------------------------------------- +0000000000100000000000000000 +----------0-------1-----------------------0-------0---------------1- +------------------------------------------------------------ +0000000000100000000000000000 +-----------------1---------------0-------0-----------------------1-- +-----0------------------------------------------------------ +0000000001000000000000000000 +-----------------1---------------0-------0-------0---------------1-- +------------------------------------------------------------ +0000000001000000000000000000 +---------0-------1-----------------------0-----------------------1-- +-----0------------------------------------------------------ +0000000001000000000000000000 +---------0-------1-----------------------0-------0---------------1-- +------------------------------------------------------------ +0000000001000000000000000000 +----------------1-----------------------0-------0------------------- +----0-------0-------------------------------1--------------- +0000000010000000000000000000 +----------------1-----------------------0-------0------------------- +----0-------0-----------------------1----------------------- +0000000010000000000000000000 +----------------1---------------0-------0-------0---------------1--- +------------------------------------------------------------ +0000000010000000000000000000 +----------------1---------------0-------0-----------------------1--- +----0------------------------------------------------------- +0000000010000000000000000000 +--------0-------1-----------------------0-------0---------------1--- +------------------------------------------------------------ +0000000010000000000000000000 +--------0-------1-----------------------0-----------------------1--- +----0------------------------------------------------------- +0000000010000000000000000000 +--------------1-------------------------------0-------0------------- +----------0-------0-------------------------------1--------- +0000000000000010000000000000 +--------------1-------------------------------0-------0------------- +----------0-------0-----------------------1----------------- +0000000000000010000000000000 +--------------1-------------------------------0--------------------- +----------1------------------------------------------------- +0000000000000010000000000000 +--------------1-------0-----------------------1--------------------- +--0-------1------------------------------------------------- +0000001000000000000000000000 +------0-------1-------------------------------1--------------------- +----------1-------0----------------------------------------- +0000001000000000000000000000 +--------------1-------0-----------------------1-------1------------- +--0--------------------------------------------------------- +0000001000000000000000000000 +------0-------1-------------------------------1-------1-------0----- +----------1-------1-------------------------------1--------- +0000001000000000000000000000 +------0-------1-------------------------------1-------1------------- +----------1-------1-------------------------------1-------0- +0000001000000000000000000000 +------0-------1-------------------------------1-------1------------- +----------1-------1-------0-----------------------1--------- +0000001000000000000000000000 +------0-------1---------------0---------------1-------1------------- +----------1-------1-------------------------------1--------- +0000001000000000000000000000 +------0-------1-------------------------------1-------1-------0----- +----------1-------1-----------------------1----------------- +0000001000000000000000000000 +------0-------1---------------0---------------1-------1------------- +----------1-------1-----------------------1----------------- +0000001000000000000000000000 +------0-------1-------------------------------1-------1------------- +----------1-------1-----------------------1---------------0- +0000001000000000000000000000 +------0-------1-------------------------------1-------1------------- +----------1-------1-------0---------------1----------------- +0000001000000000000000000000 +--------------1---------------0---------------1-------1------------- +----------1-------1-------1-----------------------0--------- +0000001000000000000000000000 +--------------1---------------0---------------1-------1------------- +----------1-------1-------1-------------------------------0- +0000001000000000000000000000 +--------------1---------------0-------0-------1-------1------------- +----------1-------1-------1--------------------------------- +0000001000000000000000000000 +------0-------1---------------0---------------1-------1------------- +----------1-------1-------1--------------------------------- +0000001000000000000000000000 +--------------1---------------0---------------1-------1------------- +--0-------1-------1-------1--------------------------------- +0000001000000000000000000000 +--------------1---------------0---------------1-------1------------- +----------1-------1-------1-------0------------------------- +0000001000000000000000000000 +--------------1---------------0---------------1-------1------------- +----------1-------1-------1---------------0----------------- +0000001000000000000000000000 +------0-------1-------------------------------1-------1-------0----- +--1-------1-------1----------------------------------------- +0000001000000000000000000000 +------0-------1-------------------------------1-------1------------- +--1-------1-------1-------0--------------------------------- +0000001000000000000000000000 +------0-------1---------------0---------------1-------1------------- +--1-------1-------1----------------------------------------- +0000001000000000000000000000 +------0-------1-------------------------------1-------1------------- +--1-------1-------1---------------0------------------------- +0000001000000000000000000000 +------0-------1-------------------------------1-------1------------- +--1-------1-------1---------------------------------------0- +0000001000000000000000000000 +------0-------1-------------------------------1-------1------------- +--1-------1-------1-----------------------0----------------- +0000001000000000000000000000 +------0-------1-------------------------------1-------1------------- +--1-------1-------1-------------------------------0--------- +0000001000000000000000000000 +--------------1---------------0---------------1-------1-------1----- +----------1-------1---------------0------------------------- +0000001000000000000000000000 +--------------1---------------0---------------1-------1-------1----- +--0-------1-------1----------------------------------------- +0000001000000000000000000000 +--------------1---------------0---------------1-------1-------1----- +----------1-------1---------------------------------------0- +0000001000000000000000000000 +--------------1---------------0-------0-------1-------1-------1----- +----------1-------1----------------------------------------- +0000001000000000000000000000 +------0-------1---------------0---------------1-------1-------1----- +----------1-------1----------------------------------------- +0000001000000000000000000000 +--------------1---------------0---------------1-------1-------1----- +----------1-------1-------------------------------0--------- +0000001000000000000000000000 +--------------1---------------0---------------1-------1-------1----- +----------1-------1-----------------------0----------------- +0000001000000000000000000000 +------0-------1-----------------------1-------1--------------------- +------------------0----------------------------------------- +0000001000000000000000000000 +------0-------1-----------------------1-------1-------1------------- +----------1-------1-----------------------0----------------- +0000001000000000000000000000 +------0-------1-----------------------1-------1-------1------------- +----------1-------1-------------------------------0--------- +0000001000000000000000000000 +------0-------1-----------------------1-------1-------1------------- +----------1-------1-------0--------------------------------- +0000001000000000000000000000 +------0-------1-----------------------1-------1-------1-------0----- +----------1-------1----------------------------------------- +0000001000000000000000000000 +------0-------1-----------------------1-------1-------1------------- +----------1-------1---------------0------------------------- +0000001000000000000000000000 +------0-------1---------------0-------1-------1-------1------------- +----------1-------1----------------------------------------- +0000001000000000000000000000 +------0-------1-----------------------1-------1-------1------------- +----------1-------1---------------------------------------0- +0000001000000000000000000000 +-------------1-------------------------------0-------0-------------- +---------0-------0-------------------------------1---------- +0000000000000100000000000000 +-------------1-------------------------------0-------0-------------- +---------0-------0-----------------------1------------------ +0000000000000100000000000000 +-------------1-------------------------------0---------------------- +---------1-------------------------------------------------- +0000000000000100000000000000 +-------------1-------0-----------------------1---------------------- +-0-------1-------------------------------------------------- +0000010000000000000000000000 +-----0-------1-------------------------------1---------------------- +---------1-------0------------------------------------------ +0000010000000000000000000000 +-------------1-------0-----------------------1-------1-------------- +-0---------------------------------------------------------- +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------------- +---------1-------1-------0-----------------------1---------- +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------------- +---------1-------1-------------------------------1-------0-- +0000010000000000000000000000 +-----0-------1---------------0---------------1-------1-------------- +---------1-------1-------------------------------1---------- +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------0------ +---------1-------1-------------------------------1---------- +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------------- +---------1-------1-------0---------------1------------------ +0000010000000000000000000000 +-----0-------1---------------0---------------1-------1-------------- +---------1-------1-----------------------1------------------ +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------------- +---------1-------1-----------------------1---------------0-- +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------0------ +---------1-------1-----------------------1------------------ +0000010000000000000000000000 +-----0-------1---------------0---------------1-------1-------------- +---------1-------1-------1---------------------------------- +0000010000000000000000000000 +-------------1---------------0---------------1-------1-------------- +---------1-------1-------1-------------------------------0-- +0000010000000000000000000000 +-------------1---------------0---------------1-------1-------------- +-0-------1-------1-------1---------------------------------- +0000010000000000000000000000 +-------------1---------------0-------0-------1-------1-------------- +---------1-------1-------1---------------------------------- +0000010000000000000000000000 +-------------1---------------0---------------1-------1-------------- +---------1-------1-------1-----------------------0---------- +0000010000000000000000000000 +-------------1---------------0---------------1-------1-------------- +---------1-------1-------1---------------0------------------ +0000010000000000000000000000 +-------------1---------------0---------------1-------1-------------- +---------1-------1-------1-------0-------------------------- +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------------- +-1-------1-------1-----------------------0------------------ +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------------- +-1-------1-------1-------------------------------0---------- +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------------- +-1-------1-------1---------------0-------------------------- +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------------- +-1-------1-------1-------0---------------------------------- +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------------- +-1-------1-------1---------------------------------------0-- +0000010000000000000000000000 +-----0-------1-------------------------------1-------1-------0------ +-1-------1-------1------------------------------------------ +0000010000000000000000000000 +-----0-------1---------------0---------------1-------1-------------- +-1-------1-------1------------------------------------------ +0000010000000000000000000000 +-------------1---------------0---------------1-------1-------1------ +-0-------1-------1------------------------------------------ +0000010000000000000000000000 +-------------1---------------0---------------1-------1-------1------ +---------1-------1---------------------------------------0-- +0000010000000000000000000000 +-------------1---------------0---------------1-------1-------1------ +---------1-------1-------------------------------0---------- +0000010000000000000000000000 +-------------1---------------0-------0-------1-------1-------1------ +---------1-------1------------------------------------------ +0000010000000000000000000000 +-------------1---------------0---------------1-------1-------1------ +---------1-------1-----------------------0------------------ +0000010000000000000000000000 +-------------1---------------0---------------1-------1-------1------ +---------1-------1---------------0-------------------------- +0000010000000000000000000000 +-----0-------1---------------0---------------1-------1-------1------ +---------1-------1------------------------------------------ +0000010000000000000000000000 +-----0-------1-----------------------1-------1---------------------- +-----------------0------------------------------------------ +0000010000000000000000000000 +-----0-------1-----------------------1-------1-------1-------------- +---------1-------1-------0---------------------------------- +0000010000000000000000000000 +-----0-------1-----------------------1-------1-------1-------------- +---------1-------1---------------0-------------------------- +0000010000000000000000000000 +-----0-------1---------------0-------1-------1-------1-------------- +---------1-------1------------------------------------------ +0000010000000000000000000000 +-----0-------1-----------------------1-------1-------1-------------- +---------1-------1-----------------------0------------------ +0000010000000000000000000000 +-----0-------1-----------------------1-------1-------1-------0------ +---------1-------1------------------------------------------ +0000010000000000000000000000 +-----0-------1-----------------------1-------1-------1-------------- +---------1-------1-------------------------------0---------- +0000010000000000000000000000 +-----0-------1-----------------------1-------1-------1-------------- +---------1-------1---------------------------------------0-- +0000010000000000000000000000 +------------1-------------------------------0----------------------- +--------1--------------------------------------------------- +0000000000001000000000000000 +------------1-------0-----------------------1----------------------- +0-------1--------------------------------------------------- +0000100000000000000000000000 +----0-------1-------------------------------1----------------------- +--------1-------0------------------------------------------- +0000100000000000000000000000 +------------1-------0-----------------------1-------1--------------- +0----------------------------------------------------------- +0000100000000000000000000000 +----0-------1-----------------------1-------1----------------------- +----------------0------------------------------------------- +0000100000000000000000000000 +-----------1-------------------------------0------------------------ +-------1---------------------------------------------------- +0000000000010000000000000000 +---0-------1-------------------------------1------------------------ +-------1-------0-------------------------------------------- +0001000000000000000000000000 +-----------1-------0-----------------------1-----------------------0 +-------1---------------------------------------------------- +0001000000000000000000000000 +-----------1-------0-----------------------1-------1---------------0 +------------------------------------------------------------ +0001000000000000000000000000 +---0-------1-----------------------1-------1------------------------ +---------------0-------------------------------------------- +0001000000000000000000000000 +----------1-------------------------------0------------------------- +------1----------------------------------------------------- +0000000000100000000000000000 +--0-------1-------------------------------1------------------------- +------1-------0--------------------------------------------- +0010000000000000000000000000 +----------1-------0-----------------------1-----------------------0- +------1----------------------------------------------------- +0010000000000000000000000000 +----------1-------0-----------------------1-------1---------------0- +------------------------------------------------------------ +0010000000000000000000000000 +--0-------1-----------------------1-------1------------------------- +--------------0--------------------------------------------- +0010000000000000000000000000 +---------1-------------------------------0-------------------------- +-----1------------------------------------------------------ +0000000001000000000000000000 +---------1-------0-----------------------1-----------------------0-- +-----1------------------------------------------------------ +0100000000000000000000000000 +-0-------1-------------------------------1-------------------------- +-----1-------0---------------------------------------------- +0100000000000000000000000000 +---------1-------0-----------------------1-------1---------------0-- +------------------------------------------------------------ +0100000000000000000000000000 +-0-------1-----------------------1-------1-------------------------- +-------------0---------------------------------------------- +0100000000000000000000000000 +--------1-------------------------------0-------0------------------- +----0-------0-------------------------------1--------------- +0000000010000000000000000000 +--------1-------------------------------0-------0------------------- +----0-------0-----------------------1----------------------- +0000000010000000000000000000 +--------1-------------------------------0--------------------------- +----1------------------------------------------------------- +0000000010000000000000000000 +--------1-------0-----------------------1-----------------------0--- +----1------------------------------------------------------- +1000000000000000000000000000 +0-------1-------------------------------1--------------------------- +----1-------0----------------------------------------------- +1000000000000000000000000000 +--------1-------0-----------------------1-------1---------------0--- +------------------------------------------------------------ +1000000000000000000000000000 +0-------1-----------------------1-------1--------------------------- +------------0----------------------------------------------- +1000000000000000000000000000 +------1---------------------------------------0-------0-------0----- +--0-------0-------0---------------------------------------1- +0000000000000010000000000000 +------1-------0-----------------------0-------0-------0------------- +----------0-------0---------------------------------------1- +0000000000000010000000000000 +------1-------0-------------------------------0-------0------------- +----------0-------0-------------------------------0-------1- +0000000000000010000000000000 +------1---------------0-----------------------0-------0------------- +----------0-------0-----------------------0---------------1- +0000000000000010000000000000 +------1---------------0-----------------------0-------0------------- +----------0-------0-------------------------------0-------1- +0000000000000010000000000000 +------1-------0-------------------------------0-------0------------- +--0-------0-------0---------------------------------------1- +0000000000000010000000000000 +------1---------------0-----------------------0-------0------------- +--0-------0-------0---------------------------------------1- +0000000000000010000000000000 +------1-------0-------------------------------0-------0------------- +----------0-------0-----------------------0---------------1- +0000000000000010000000000000 +------1-------------------------------0-------0-------0-------0----- +----------0-------0---------------------------------------1- +0000000000000010000000000000 +------1---------------------------------------0-------0------------- +--0-------0-------0-------0-------------------------------1- +0000000000000010000000000000 +------1---------------0---------------0-------0-------0------------- +----------0-------0---------------------------------------1- +0000000000000010000000000000 +------1-------------------------------0-------0-------0------------- +----------0-------0-------0-------------------------------1- +0000000000000010000000000000 +------1-------0-------------------------------0-------0------------- +--0-------0-------0-------------------------------1--------- +0000000000000010000000000000 +------1-------------------------------0-------0-------0------------- +----------0-------0-------0-----------------------1--------- +0000000000000010000000000000 +------1-------------------------------0-------0-------0-------0----- +----------0-------0-------------------------------1--------- +0000000000000010000000000000 +------1-------0-----------------------0-------0-------0------------- +----------0-------0-------------------------------1--------- +0000000000000010000000000000 +------1---------------0---------------0-------0-------0------------- +----------0-------0-------------------------------1--------- +0000000000000010000000000000 +------1---------------0-----------------------0-------0------------- +--0-------0-------0-------------------------------1--------- +0000000000000010000000000000 +------1---------------------------------------0-------0-------0----- +--0-------0-------0-------------------------------1--------- +0000000000000010000000000000 +------1---------------------------------------0-------0------------- +--0-------0-------0-------0-----------------------1--------- +0000000000000010000000000000 +------1-------0-------------------------------0-------0------------- +--0-------0-------0-----------------------1----------------- +0000000000000010000000000000 +------1---------------------------------------0-------0------------- +--0-------0-------0-------0---------------1----------------- +0000000000000010000000000000 +------1-------------------------------0-------0-------0-------0----- +----------0-------0-----------------------1----------------- +0000000000000010000000000000 +------1---------------0-----------------------0-------0------------- +--0-------0-------0-----------------------1----------------- +0000000000000010000000000000 +------1-------0-----------------------0-------0-------0------------- +----------0-------0-----------------------1----------------- +0000000000000010000000000000 +------1-------------------------------0-------0-------0------------- +----------0-------0-------0---------------1----------------- +0000000000000010000000000000 +------1---------------------------------------0-------0-------0----- +--0-------0-------0-----------------------1----------------- +0000000000000010000000000000 +------1---------------0---------------0-------0-------0------------- +----------0-------0-----------------------1----------------- +0000000000000010000000000000 +------1-------------------------------0-------0-------0-------0----- +----------0-------0---------------1------------------------- +0000000000000010000000000000 +------1-------0-----------------------0-------0-------0------------- +----------0-------0---------------1------------------------- +0000000000000010000000000000 +------1-------------------------------0-------0-------0------------- +----------0-------0-------0-------1------------------------- +0000000000000010000000000000 +------1---------------0---------------0-------0-------0------------- +----------0-------0---------------1------------------------- +0000000000000010000000000000 +------1---------------0-----------------------0-------0------------- +--0-------0-------0---------------1------------------------- +0000000000000010000000000000 +------1---------------------------------------0-------0-------0----- +--0-------0-------0---------------1------------------------- +0000000000000010000000000000 +------1---------------------------------------0-------0------------- +--0-------0-------0-------0-------1------------------------- +0000000000000010000000000000 +------1-------0-------------------------------0-------0------------- +--0-------0-------0---------------1------------------------- +0000000000000010000000000000 +------1-------0-----------------------0-------0-------0------------- +----------0-------0-------1--------------------------------- +0000000000000010000000000000 +------1-------0-------------------------------0-------0------------- +--0-------0-------0-------1--------------------------------- +0000000000000010000000000000 +------1-------0-------------------------------0-------0------------- +----------0-------0-------1---------------0----------------- +0000000000000010000000000000 +------1---------------0-----------------------0-------0------------- +--0-------0-------0-------1--------------------------------- +0000000000000010000000000000 +------1---------------0-----------------------0-------0------------- +----------0-------0-------1---------------0----------------- +0000000000000010000000000000 +------1---------------0---------------0-------0-------0------------- +----------0-------0-------1--------------------------------- +0000000000000010000000000000 +------1---------------0-----------------------0-------0------------- +----------0-------0-------1-----------------------0--------- +0000000000000010000000000000 +------1-------0-------------------------------0-------0------------- +----------0-------0-------1-----------------------0--------- +0000000000000010000000000000 +------1---------------------------------------0-------0------------- +----------0-------1----------------------------------------- +0000000000000010000000000000 +------1-------------------------------0-------0-------0------------- +------------------1----------------------------------------- +0000000000000010000000000000 +------1-------0-------------------------------0--------------------- +----------0-------1----------------------------------------- +0000000000000010000000000000 +------1-------0-----------------------0-------0--------------------- +------------------1----------------------------------------- +0000000000000010000000000000 +------1---------------0---------------0-------0-------0-------1----- +----------0-------0----------------------------------------- +0000000000000010000000000000 +------1---------------0-----------------------0-------0-------1----- +--0-------0-------0----------------------------------------- +0000000000000010000000000000 +------1-------0-------------------------------0-------0-------1----- +----------0-------0-----------------------0----------------- +0000000000000010000000000000 +------1-------0-------------------------------0-------0-------1----- +----------0-------0-------------------------------0--------- +0000000000000010000000000000 +------1-------0-------------------------------0-------0-------1----- +--0-------0-------0----------------------------------------- +0000000000000010000000000000 +------1-------0-----------------------0-------0-------0-------1----- +----------0-------0----------------------------------------- +0000000000000010000000000000 +------1---------------0-----------------------0-------0-------1----- +----------0-------0-----------------------0----------------- +0000000000000010000000000000 +------1---------------0-----------------------0-------0-------1----- +----------0-------0-------------------------------0--------- +0000000000000010000000000000 +------1---------------0-------1---------------0-------0-------0----- +----------0-------0----------------------------------------- +0000000000000010000000000000 +------1---------------0-------1---------------0-------0------------- +--0-------0-------0----------------------------------------- +0000000000000010000000000000 +------1---------------0-------1---------------0-------0------------- +----------0-------0-------0--------------------------------- +0000000000000010000000000000 +------1---------------0-------1---------------0-------0------------- +----------0-------0-----------------------0----------------- +0000000000000010000000000000 +------1---------------0-------1---------------0-------0------------- +----------0-------0-------------------------------0--------- +0000000000000010000000000000 +------1-------0---------------1---------------0-------0-------0----- +----------0-------0----------------------------------------- +0000000000000010000000000000 +------1-------0---------------1---------------0-------0------------- +----------0-------0-------0--------------------------------- +0000000000000010000000000000 +------1-------0---------------1---------------0-------0------------- +----------0-------0-----------------------0----------------- +0000000000000010000000000000 +------1-------0---------------1---------------0-------0------------- +----------0-------0-------------------------------0--------- +0000000000000010000000000000 +------1-------0---------------1-------0-------0-------0------------- +----------0-------0----------------------------------------- +0000000000000010000000000000 +------1-------0---------------1---------------0-------0------------- +--0-------0-------0----------------------------------------- +0000000000000010000000000000 +------1---------------0-------1-------0-------0-------0------------- +----------0-------0----------------------------------------- +0000000000000010000000000000 +-----1---------------------------------------0-------0-------------- +-0-------0-------0-------0-------------------------------1-- +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------------- +---------0-------0-------------------------------0-------1-- +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------------- +---------0-------0-----------------------0---------------1-- +0000000000000100000000000000 +-----1-------0-----------------------0-------0-------0-------------- +---------0-------0---------------------------------------1-- +0000000000000100000000000000 +-----1---------------------------------------0-------0-------0------ +-0-------0-------0---------------------------------------1-- +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------------- +---------0-------0-------------------------------0-------1-- +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------------- +-0-------0-------0---------------------------------------1-- +0000000000000100000000000000 +-----1-------------------------------0-------0-------0-------0------ +---------0-------0---------------------------------------1-- +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------------- +-0-------0-------0---------------------------------------1-- +0000000000000100000000000000 +-----1---------------0---------------0-------0-------0-------------- +---------0-------0---------------------------------------1-- +0000000000000100000000000000 +-----1-------------------------------0-------0-------0-------------- +---------0-------0-------0-------------------------------1-- +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------------- +---------0-------0-----------------------0---------------1-- +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------------- +-0-------0-------0-------------------------------1---------- +0000000000000100000000000000 +-----1---------------------------------------0-------0-------0------ +-0-------0-------0-------------------------------1---------- +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------------- +-0-------0-------0-------------------------------1---------- +0000000000000100000000000000 +-----1---------------------------------------0-------0-------------- +-0-------0-------0-------0-----------------------1---------- +0000000000000100000000000000 +-----1-------0-----------------------0-------0-------0-------------- +---------0-------0-------------------------------1---------- +0000000000000100000000000000 +-----1-------------------------------0-------0-------0-------------- +---------0-------0-------0-----------------------1---------- +0000000000000100000000000000 +-----1---------------0---------------0-------0-------0-------------- +---------0-------0-------------------------------1---------- +0000000000000100000000000000 +-----1-------------------------------0-------0-------0-------0------ +---------0-------0-------------------------------1---------- +0000000000000100000000000000 +-----1-------------------------------0-------0-------0-------0------ +---------0-------0-----------------------1------------------ +0000000000000100000000000000 +-----1-------------------------------0-------0-------0-------------- +---------0-------0-------0---------------1------------------ +0000000000000100000000000000 +-----1---------------------------------------0-------0-------0------ +-0-------0-------0-----------------------1------------------ +0000000000000100000000000000 +-----1---------------------------------------0-------0-------------- +-0-------0-------0-------0---------------1------------------ +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------------- +-0-------0-------0-----------------------1------------------ +0000000000000100000000000000 +-----1-------0-----------------------0-------0-------0-------------- +---------0-------0-----------------------1------------------ +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------------- +-0-------0-------0-----------------------1------------------ +0000000000000100000000000000 +-----1---------------0---------------0-------0-------0-------------- +---------0-------0-----------------------1------------------ +0000000000000100000000000000 +-----1---------------------------------------0-------0-------------- +-0-------0-------0-------0-------1-------------------------- +0000000000000100000000000000 +-----1---------------0---------------0-------0-------0-------------- +---------0-------0---------------1-------------------------- +0000000000000100000000000000 +-----1-------------------------------0-------0-------0-------0------ +---------0-------0---------------1-------------------------- +0000000000000100000000000000 +-----1---------------------------------------0-------0-------0------ +-0-------0-------0---------------1-------------------------- +0000000000000100000000000000 +-----1-------------------------------0-------0-------0-------------- +---------0-------0-------0-------1-------------------------- +0000000000000100000000000000 +-----1-------0-----------------------0-------0-------0-------------- +---------0-------0---------------1-------------------------- +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------------- +-0-------0-------0---------------1-------------------------- +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------------- +-0-------0-------0---------------1-------------------------- +0000000000000100000000000000 +-----1---------------0---------------0-------0-------0-------------- +---------0-------0-------1---------------------------------- +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------------- +---------0-------0-------1---------------0------------------ +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------------- +---------0-------0-------1---------------0------------------ +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------------- +---------0-------0-------1-----------------------0---------- +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------------- +---------0-------0-------1-----------------------0---------- +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------------- +-0-------0-------0-------1---------------------------------- +0000000000000100000000000000 +-----1-------0-----------------------0-------0-------0-------------- +---------0-------0-------1---------------------------------- +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------------- +-0-------0-------0-------1---------------------------------- +0000000000000100000000000000 +-----1-------0-----------------------0-------0---------------------- +-----------------1------------------------------------------ +0000000000000100000000000000 +-----1---------------------------------------0-------0-------------- +---------0-------1------------------------------------------ +0000000000000100000000000000 +-----1-------------------------------0-------0-------0-------------- +-----------------1------------------------------------------ +0000000000000100000000000000 +-----1-------0-------------------------------0---------------------- +---------0-------1------------------------------------------ +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------1------ +---------0-------0-----------------------0------------------ +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------1------ +-0-------0-------0------------------------------------------ +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------1------ +---------0-------0-----------------------0------------------ +0000000000000100000000000000 +-----1-------0-----------------------0-------0-------0-------1------ +---------0-------0------------------------------------------ +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------1------ +-0-------0-------0------------------------------------------ +0000000000000100000000000000 +-----1---------------0-----------------------0-------0-------1------ +---------0-------0-------------------------------0---------- +0000000000000100000000000000 +-----1---------------0---------------0-------0-------0-------1------ +---------0-------0------------------------------------------ +0000000000000100000000000000 +-----1-------0-------------------------------0-------0-------1------ +---------0-------0-------------------------------0---------- +0000000000000100000000000000 +-----1---------------0-------1-------0-------0-------0-------------- +---------0-------0------------------------------------------ +0000000000000100000000000000 +-----1---------------0-------1---------------0-------0-------------- +---------0-------0-----------------------0------------------ +0000000000000100000000000000 +-----1---------------0-------1---------------0-------0-------------- +---------0-------0-------------------------------0---------- +0000000000000100000000000000 +-----1---------------0-------1---------------0-------0-------------- +---------0-------0-------0---------------------------------- +0000000000000100000000000000 +-----1-------0---------------1-------0-------0-------0-------------- +---------0-------0------------------------------------------ +0000000000000100000000000000 +-----1---------------0-------1---------------0-------0-------------- +-0-------0-------0------------------------------------------ +0000000000000100000000000000 +-----1---------------0-------1---------------0-------0-------0------ +---------0-------0------------------------------------------ +0000000000000100000000000000 +-----1-------0---------------1---------------0-------0-------------- +---------0-------0-------------------------------0---------- +0000000000000100000000000000 +-----1-------0---------------1---------------0-------0-------------- +---------0-------0-----------------------0------------------ +0000000000000100000000000000 +-----1-------0---------------1---------------0-------0-------------- +---------0-------0-------0---------------------------------- +0000000000000100000000000000 +-----1-------0---------------1---------------0-------0-------------- +-0-------0-------0------------------------------------------ +0000000000000100000000000000 +-----1-------0---------------1---------------0-------0-------0------ +---------0-------0------------------------------------------ +0000000000000100000000000000 +----1-------------------------------0-------0-------0--------------- +----------------1------------------------------------------- +0000000000001000000000000000 +----1---------------------------------------0-------0--------------- +--------0-------1------------------------------------------- +0000000000001000000000000000 +----1-------0-------------------------------0----------------------- +--------0-------1------------------------------------------- +0000000000001000000000000000 +----1-------0-----------------------0-------0----------------------- +----------------1------------------------------------------- +0000000000001000000000000000 +---1---------------------------------------0-------0---------------- +-------0-------1-------------------------------------------- +0000000000010000000000000000 +---1-------0-----------------------0-------0------------------------ +---------------1-------------------------------------------- +0000000000010000000000000000 +---1-------------------------------0-------0-------0---------------- +---------------1-------------------------------------------- +0000000000010000000000000000 +---1-------0-------------------------------0------------------------ +-------0-------1-------------------------------------------- +0000000000010000000000000000 +--1---------------------------------------0-------0----------------- +------0-------1--------------------------------------------- +0000000000100000000000000000 +--1-------0-----------------------0-------0------------------------- +--------------1--------------------------------------------- +0000000000100000000000000000 +--1-------------------------------0-------0-------0----------------- +--------------1--------------------------------------------- +0000000000100000000000000000 +--1-------0-------------------------------0------------------------- +------0-------1--------------------------------------------- +0000000000100000000000000000 +-1-------------------------------0-------0-------0------------------ +-------------1---------------------------------------------- +0000000001000000000000000000 +-1---------------------------------------0-------0------------------ +-----0-------1---------------------------------------------- +0000000001000000000000000000 +-1-------0-------------------------------0-------------------------- +-----0-------1---------------------------------------------- +0000000001000000000000000000 +-1-------0-----------------------0-------0-------------------------- +-------------1---------------------------------------------- +0000000001000000000000000000 +1---------------------------------------0-------0---------------0--- +----0-------0-------0-------------------------------1------- +0000000010000000000000000000 +1---------------------------------------0-------0-------0-------0--- +----0-------0---------------------------------------1------- +0000000010000000000000000000 +1-------0-----------------------0-------0-------0------------------- +----0-------0---------------------------------------1------- +0000000010000000000000000000 +1---------------0---------------0-------0-------0------------------- +----0-------0---------------------------------------1------- +0000000010000000000000000000 +1---------------0-----------------------0-------0------------------- +----0-------0-----------------------0---------------1------- +0000000010000000000000000000 +1---------------0-----------------------0-------0------------------- +----0-------0-------------------------------0-------1------- +0000000010000000000000000000 +1-------0-------------------------------0-------0---------------0--- +----0-------0---------------------------------------1------- +0000000010000000000000000000 +1-------------------------------0-------0-------0------------------- +----0-------0-------0-------------------------------1------- +0000000010000000000000000000 +1-------0-------------------------------0-------0------------------- +----0-------0-----------------------0---------------1------- +0000000010000000000000000000 +1-------0-------------------------------0-------0------------------- +----0-------0-------------------------------0-------1------- +0000000010000000000000000000 +1-------------------------------0-------0-------0-------0----------- +----0-------0---------------------------------------1------- +0000000010000000000000000000 +1---------------0-----------------------0-------0---------------0--- +----0-------0---------------------------------------1------- +0000000010000000000000000000 +1-------------------------------0-------0-------0------------------- +----0-------0-------0-----------------------1--------------- +0000000010000000000000000000 +1-------0-----------------------0-------0-------0------------------- +----0-------0-------------------------------1--------------- +0000000010000000000000000000 +1-------0-------------------------------0-------0---------------0--- +----0-------0-------------------------------1--------------- +0000000010000000000000000000 +1---------------0---------------0-------0-------0------------------- +----0-------0-------------------------------1--------------- +0000000010000000000000000000 +1-------------------------------0-------0-------0-------0----------- +----0-------0-------------------------------1--------------- +0000000010000000000000000000 +1---------------0-----------------------0-------0---------------0--- +----0-------0-------------------------------1--------------- +0000000010000000000000000000 +1---------------------------------------0-------0-------0-------0--- +----0-------0-------------------------------1--------------- +0000000010000000000000000000 +1---------------------------------------0-------0---------------0--- +----0-------0-------0-----------------------1--------------- +0000000010000000000000000000 +1-------------------------------0-------0-------0-------0----------- +----0-------0-----------------------1----------------------- +0000000010000000000000000000 +1-------------------------------0-------0-------0------------------- +----0-------0-------0---------------1----------------------- +0000000010000000000000000000 +1---------------------------------------0-------0-------0-------0--- +----0-------0-----------------------1----------------------- +0000000010000000000000000000 +1---------------0-----------------------0-------0---------------0--- +----0-------0-----------------------1----------------------- +0000000010000000000000000000 +1---------------------------------------0-------0---------------0--- +----0-------0-------0---------------1----------------------- +0000000010000000000000000000 +1---------------0---------------0-------0-------0------------------- +----0-------0-----------------------1----------------------- +0000000010000000000000000000 +1-------0-----------------------0-------0-------0------------------- +----0-------0-----------------------1----------------------- +0000000010000000000000000000 +1-------0-------------------------------0-------0---------------0--- +----0-------0-----------------------1----------------------- +0000000010000000000000000000 +1-------------------------------0-------0-------0------------------- +----0-------0-------0-------1------------------------------- +0000000010000000000000000000 +1-------------------------------0-------0-------0-------0----------- +----0-------0---------------1------------------------------- +0000000010000000000000000000 +1---------------0-----------------------0-------0---------------0--- +----0-------0---------------1------------------------------- +0000000010000000000000000000 +1---------------------------------------0-------0-------0-------0--- +----0-------0---------------1------------------------------- +0000000010000000000000000000 +1-------0-----------------------0-------0-------0------------------- +----0-------0---------------1------------------------------- +0000000010000000000000000000 +1---------------0---------------0-------0-------0------------------- +----0-------0---------------1------------------------------- +0000000010000000000000000000 +1-------0-------------------------------0-------0---------------0--- +----0-------0---------------1------------------------------- +0000000010000000000000000000 +1---------------------------------------0-------0---------------0--- +----0-------0-------0-------1------------------------------- +0000000010000000000000000000 +1---------------0-----------------------0-------0---------------0--- +----0-------0-------1--------------------------------------- +0000000010000000000000000000 +1---------------0-----------------------0-------0------------------- +----0-------0-------1-----------------------0--------------- +0000000010000000000000000000 +1---------------0-----------------------0-------0------------------- +----0-------0-------1---------------0----------------------- +0000000010000000000000000000 +1-------0-----------------------0-------0-------0------------------- +----0-------0-------1--------------------------------------- +0000000010000000000000000000 +1---------------0---------------0-------0-------0------------------- +----0-------0-------1--------------------------------------- +0000000010000000000000000000 +1-------0-------------------------------0-------0------------------- +----0-------0-------1-----------------------0--------------- +0000000010000000000000000000 +1-------0-------------------------------0-------0------------------- +----0-------0-------1---------------0----------------------- +0000000010000000000000000000 +1-------0-------------------------------0-------0---------------0--- +----0-------0-------1--------------------------------------- +0000000010000000000000000000 +1-------0-------------------------------0--------------------------- +----0-------1----------------------------------------------- +0000000010000000000000000000 +1-------------------------------0-------0-------0------------------- +------------1----------------------------------------------- +0000000010000000000000000000 +1---------------------------------------0-------0------------------- +----0-------1----------------------------------------------- +0000000010000000000000000000 +1-------0-----------------------0-------0--------------------------- +------------1----------------------------------------------- +0000000010000000000000000000 +1-------0-------------------------------0-------0-------1----------- +----0-------0-------------------------------0--------------- +0000000010000000000000000000 +1-------0-----------------------0-------0-------0-------1----------- +----0-------0----------------------------------------------- +0000000010000000000000000000 +1-------0-------------------------------0-------0-------1----------- +----0-------0-----------------------0----------------------- +0000000010000000000000000000 +1-------0-------------------------------0-------0-------1-------0--- +----0-------0----------------------------------------------- +0000000010000000000000000000 +1---------------0---------------0-------0-------0-------1----------- +----0-------0----------------------------------------------- +0000000010000000000000000000 +1---------------0-----------------------0-------0-------1-------0--- +----0-------0----------------------------------------------- +0000000010000000000000000000 +1---------------0-----------------------0-------0-------1----------- +----0-------0-----------------------0----------------------- +0000000010000000000000000000 +1---------------0-----------------------0-------0-------1----------- +----0-------0-------------------------------0--------------- +0000000010000000000000000000 +1---------------0-------1---------------0-------0---------------0--- +----0-------0----------------------------------------------- +0000000010000000000000000000 +1---------------0-------1---------------0-------0-------0----------- +----0-------0----------------------------------------------- +0000000010000000000000000000 +1---------------0-------1---------------0-------0------------------- +----0-------0-----------------------0----------------------- +0000000010000000000000000000 +1---------------0-------1---------------0-------0------------------- +----0-------0-------------------------------0--------------- +0000000010000000000000000000 +1---------------0-------1-------0-------0-------0------------------- +----0-------0----------------------------------------------- +0000000010000000000000000000 +1---------------0-------1---------------0-------0------------------- +----0-------0-------0--------------------------------------- +0000000010000000000000000000 +1-------0---------------1---------------0-------0------------------- +----0-------0-------------------------------0--------------- +0000000010000000000000000000 +1-------0---------------1-------0-------0-------0------------------- +----0-------0----------------------------------------------- +0000000010000000000000000000 +1-------0---------------1---------------0-------0------------------- +----0-------0-----------------------0----------------------- +0000000010000000000000000000 +1-------0---------------1---------------0-------0------------------- +----0-------0-------0--------------------------------------- +0000000010000000000000000000 +1-------0---------------1---------------0-------0---------------0--- +----0-------0----------------------------------------------- +0000000010000000000000000000 +1-------0---------------1---------------0-------0-------0----------- +----0-------0----------------------------------------------- +0000000010000000000000000000 diff --git a/espresso/examples/indust/ex5 b/espresso/examples/indust/ex5 new file mode 100644 index 0000000..7f04d01 --- /dev/null +++ b/espresso/examples/indust/ex5 @@ -0,0 +1,258 @@ +.i 8 +.o 63 +00000000 110000000000000000000000000000011111111111111111111111111111111 +00000001 100000000000000000000000000001011111111111111111111111111111111 +00000010 000000000000000000000000100000010111110101101111111111111111111 +00000011 000000000000000000000000000000011111111111111010110111111110111 +00000100 001000000000000000000000000000011111111111001111111111111111111 +00000101 000000000000000000000000000000011111111111111111111111111111111 +00000110 000001000000000000000000000000011111111111111111111111111111111 +00000111 000000000000000000000000000000011111111111111111111110111111011 +00001000 010000000000000000010000000000011110111101100111111111111111111 +00001001 000000000000000000010000000000011110111101100111111111111111111 +00001010 000000000000000000010000000000011110111101100111111111111111111 +00001011 000000000000000000010000000000011110111101100111111111111111111 +00001100 000000000000000000010000000000001110111101100111111111111111111 +00001101 000000000000000000010000000000001110111101100111111111111111111 +00001110 000000000000000000010000000000001110111101100111111111111111111 +00001111 000000000000000000010000000000001110111101100111111111111111111 +00010000 110000000000000000000000000000011111111111111111011001111111111 +00010001 100000000000000000000000000000011111111111111111011001111111111 +00010010 000010000000000000000000000000011111101111111111111111111111111 +00010011 000000000000000000000000000000011111111111111010110111111100111 +00010100 000100000000000000000001000000011101111011001111111111111111111 +00010101 000000000000000000000001000000011111111111111111111111111111111 +00010110 000001000000000000000001000000011111111111111111111111111111111 +00010111 000000000000000000000001000000011111111111111111011111011111111 +00011000 010000000000000000000000000000011111111111111111011001111111111 +00011001 000000000000000000000000000000011111111111111111011001111111111 +00011010 000000000000000000000000000000011111111111111111011001111111111 +00011011 000000000000000000000000000000011111111111111111011001111111111 +00011100 000000000000000000000001000000011111111111111111011001111111111 +00011101 000000000000000000000001000000011111111111111111011001111111111 +00011110 000000000000000000000001000000011111111111111111011001111111111 +00011111 000000000000000000000001000000011111111111111111011001111111111 +00100000 110000000000000000000000000000011111111111111111101101111111111 +00100001 100000000000000000000000000000011111111111111111101101111111111 +00100010 000000000000000000000000000000011101011111111111111111111111111 +00100011 000000000100000000000000000000011111111111111111111111111110111 +00100100 001000000000000000000000000000011111111111001111111111111111111 +00100101 000000000000000000000000000000011111111111111111111111111111111 +00100110 000001000000000000000000000000011111111111111111111111111111111 +00100111 000000000000000000000000000000011111111111111111111111010111111 +00101000 010000000000000000000000000000011111111111111111101101111111111 +00101001 000000000000000000000000000000011111111111111111101101111111111 +00101010 000000000000000000000000000000011111111111111111101101111111111 +00101011 000000000000000000000000000000011111111111111111101101111111111 +00101100 000000000000000000000000000000011111111111111111101101111111111 +00101101 000000000000000000000000000000011111111111111111101101111111111 +00101110 000000000000000000000000000000011111111111111111101101111111111 +00101111 000000000000000000000000000000011111111111111111101101111111111 +00110000 110000100000000000000000000000011111111111111111101001111111111 +00110001 100000100000000000000000000000011111111111111111101001111111111 +00110010 000010000000000000000000000000011111101111111111111111111111111 +00110011 000000000000000000000000000000011111111111111111111111111111111 +00110100 000100000000000000000000000000011101111011001111111111111111111 +00110101 000000000000000000000000000000011111111111111111111111111111111 +00110110 000001000000000000000000000000011111111111111111111111111111111 +00110111 000000000000000000000000000000011111111111111111111110111011011 +00111000 010000000000000000100000000000010111110101101111111111111111111 +00111001 000000000000000000100000000000010111110101101111111111111111111 +00111010 000000000000000000100000000000010111110101101111111111111111111 +00111011 000000000000000000100000000000010111110101101111111111111111111 +00111100 000000000000000000000000000000000110110101101111111111111111111 +00111101 000000000000000000000000000000000110110101101111111111111111111 +00111110 000000000000000000000000000000000110110101101111111111111111111 +00111111 000000000000000000000000000000000110110101101111111111111111111 +01000000 110000000000000000000000000000011111111111111101111111001011111 +01000001 100000000000000000000000000000011111111111111101111111001011111 +01000010 000000000000000000000000010000011111111111111111111111111111111 +01000011 000000000000000000000000000000011111111111111101110111111010111 +01000100 001000000000000000000000000000011111111111001111111111111111111 +01000101 000000000000000000000000000000011111111111111111111111111111111 +01000110 000001000000000000000000000000011111111111111111111111111111111 +01000111 000000010000000000000000000000011111111111111111111110111111111 +01001000 010000000000000000000000000000011111111111111101111111001011111 +01001001 000000000000000000000000000000011111111111111101111111001011111 +01001010 000000000000000000000000000000011111111111111101111111001011111 +01001011 000000000000000000000000000000011111111111111101111111001011111 +01001100 000000000000000000000000000000011111111111111101111111001011111 +01001101 000000000000000000000000000000011111111111111101111111001011111 +01001110 000000000000000000000000000000011111111111111101111111001011111 +01001111 000000000000000000000000000000011111111111111101111111001011111 +01010000 110000000000000000000000000000011111111111111111111110100111111 +01010001 100000000000000000000000000000011111111111111111111110100111111 +01010010 000010000000000000000000000000011111101111111111111111111111111 +01010011 000000000000000000000000000000011111111111111111110111110110111 +01010100 000100000000000000000000000000011101111011001111111111111111111 +01010101 000000000000000000000000000000011111111111111111111111111111111 +01010110 000001000000000000000000000000011111111111111111111111111111111 +01010111 000000000000010000000000000000011111111111111111111111011111111 +01011000 010000000000000000000000000000011111111111111111111110100111111 +01011001 000000000000000000000000000000011111111111111111111110100111111 +01011010 000000000000000000000000000000011111111111111111111110100111111 +01011011 000000000000000000000000000000011111111111111111111110100111111 +01011100 000000000000000000000000000000011111111111111111111110100111111 +01011101 000000000000000000000000000000011111111111111111111110100111111 +01011110 000000000000000000000000000000011111111111111111111110100111111 +01011111 000000000000000000000000000000011111111111111111111110100111111 +01100000 110000000000000000000000000000011111111111111010111110101111111 +01100001 100000000000000000000000000000011111111111111010111110101111111 +01100010 000000000000000000000000000100011111111111111111111111111111111 +01100011 000000000000000000000000000000011111111111111111111111111111111 +01100100 001000000000000000000000000000011111111111001111111111111111111 +01100101 000000000000000000000000000000011111111111111111111111111111111 +01100110 000001000000000000000000000000011111111111111111111111111111111 +01100111 000000000010000000000000000000011111111111111111111111010011111 +01101000 010000000000000000000000000000011111111111111010111110101111111 +01101001 000000000000000000000000000000011111111111111010111110101111111 +01101010 000000000000000000000000000000011111111111111010111110101111111 +01101011 000000000000000000000000000000011111111111111010111110101111111 +01101100 000000000000000000000000000000011111111111111010111110101111111 +01101101 000000000000000000000000000000011111111111111010111110101111111 +01101110 000000000000000000000000000000011111111111111010111110101111111 +01101111 000000000000000000000000000000011111111111111010111110101111111 +01110000 110000000000000000000000000000011111111111111010111111001101111 +01110001 100000000000000000000000000000011111111111111010111111001101111 +01110010 000010000000000000000000000000011111101111111111111111111111111 +01110011 000000000000000000000000000000011111111111111111111111111111111 +01110100 000100000000000000000000000000011101111011001111111111111111111 +01110101 000000000000000000000000000000011111111111111111111111111111111 +01110110 000001000000000000000000000000011111111111111111111111111111111 +01110111 000000000010000100000000000000011111111111111111111111010011111 +01111000 010000000000000000000000000000011111111111111010111111001101111 +01111001 000000000000000000000000000000011111111111111010111111001101111 +01111010 000000000000000000000000000000011111111111111010111111001101111 +01111011 000000000000000000000000000000011111111111111010111111001101111 +01111100 000000000000000000000000000000011111111111111010111111001101111 +01111101 000000000000000000000000000000011111111111111010111111001101111 +01111110 000000000000000000000000000000011111111111111010111111001101111 +01111111 000000000000000000000000000000011111111111111010111111001101111 +10000000 110000000000000000001000000000001111111101100111111111111111111 +10000001 100000000000000000001000000000001111111101100111111111111111111 +10000010 000000000000000000000000000000011111111111111111111111111111111 +10000011 000000000000000000000010000000011101111011001111111111111111111 +10000100 001000000000000000000000000000011111111111001111111111111111111 +10000101 000000000000000000000000000000011111111111111111111111111111111 +10000110 000001000000000000000000000000011111111111111111111111111111111 +10000111 000000000000000000000000000000011111111111111111111110111111111 +10001000 010000000000000001000000000000011101010111101111111111111111111 +10001001 000000000000000001000000000000011101010111101111111111111111111 +10001010 000000000000000001000000000000011101010111101111111111111111111 +10001011 000000000000000001000000000000011101010111101111111111111111111 +10001100 000000000000000000000000000000000110110101101111111111111111111 +10001101 000000000000000000000000000000000110110101101111111111111111111 +10001110 000000000000000000000000000000000110110101101111111111111111111 +10001111 000000000000000000000000000000000110110101101111111111111111111 +10010000 110000000000000000000100000000000111110101101111111111111111111 +10010001 100000000000000000000100000000000111110101101111111111111111111 +10010010 000010000000000000000000000000011111101111111111111111111111111 +10010011 000000000000000000000010000000011101111011001111111111111111111 +10010100 000100000000000000000000000000011101101010001111111111111111111 +10010101 000000000000000000000000000000011111101110111111111111111111111 +10010110 000001000000000000000000000000011111101110111111111111111111111 +10010111 000000000000001000000000000000011111101110111111111111111111111 +10011000 010000000000000001000000000000011101010111101111111111111111111 +10011001 000000000000000001000000000000011101010111101111111111111111111 +10011010 000000000000000001000000000000011101010111101111111111111111111 +10011011 000000000000000001000000000000011101010111101111111111111111111 +10011100 000000000000000000000000000000000110100100101111111111111111111 +10011101 000000000000000000000000000000000110100100101111111111111111111 +10011110 000000000000000000000000000000000110100100101111111111111111111 +10011111 000000000000000000000000000000000110100100101111111111111111111 +10100000 110000000000000000000000000000011111111111111111111101111111111 +10100001 100000000000000000000000000000011111111111111111111101111111111 +10100010 000000000000000000000000000000011111111111111111111111111111111 +10100011 000000000000000000000000001000011011111101101111111111111111111 +10100100 001000000000000000000000000000011111111111001111111111111111111 +10100101 000000000000000000000000000000011111111111111111111111111111111 +10100110 000001000000000000000000000000011111111111111111111111111111111 +10100111 000000000000100000000000000000011111111111111111111111111111111 +10101000 010000000000000000000000000000011111111111111111111101111111111 +10101001 000000000000000000000000000000011111111111111111111101111111111 +10101010 000000000000000000000000000000011111111111111111111101111111111 +10101011 000000000000000000000000000000011111111111111111111101111111111 +10101100 000000000000000000000000000000011111111111111111111101111111111 +10101101 000000000000000000000000000000011111111111111111111101111111111 +10101110 000000000000000000000000000000011111111111111111111101111111111 +10101111 000000000000000000000000000000011111111111111111111101111111111 +10110000 110000000000000000000000000000011111111111111111111111111110101 +10110001 100000000000000000000000000000011111111111111111111111111110101 +10110010 000010000000000000000000000000011111101111111111111111111111111 +10110011 000000000000000000000000000010011011111111001111111111111111111 +10110100 000100000000000000000000000000011101111011001111111111111111111 +10110101 000000000000000000000000000000011111111111111111111111111111111 +10110110 000001000000000000000000000000011111111111111111111111111111111 +10110111 000000000000000000000000000000011111111111111111111111111111111 +10111000 010000000000000000000000000000011111111111111111111111111110101 +10111001 000000000000000000000000000000011111111111111111111111111110101 +10111010 000000000000000000000000000000011111111111111111111111111110101 +10111011 000000000000000000000000000000011111111111111111111111111110101 +10111100 000000000000000000000000000000011111111111111111111111111110101 +10111101 000000000000000000000000000000011111111111111111111111111110101 +10111110 000000000000000000000000000000011111111111111111111111111110101 +10111111 000000000000000000000000000000011111111111111111111111111110101 +11000000 110000000000000000000000000000011111101110111111111001111111110 +11000001 100000000000000000000000000000011111101110111111111001111111110 +11000010 000000000000000000000000000000011111101110111111111111111111111 +11000011 000000000000000000000000000000011111101110111111111111111111111 +11000100 001000000000000000000000000000011111101110001111111111111111111 +11000101 000000000000000000000000000000011111101110111111111111111111111 +11000110 000001000000000000000000000000011111101110111111111111111111111 +11000111 000000000001000000000000000000011111101110111111111011011111111 +11001000 010000000000000000000000000000011111101110111111111001111111010 +11001001 000000000000000000000000000000011111101110111111111001111111010 +11001010 000000000000000000000000000000011111101110111111111001111111010 +11001011 000000000000000000000000000000011111101110111111111001111111010 +11001100 000000000000000000000000000000011111101110111111111001111111010 +11001101 000000000000000000000000000000011111101110111111111001111111010 +11001110 000000000000000000000000000000011111101110111111111001111111010 +11001111 000000000000000000000000000000011111101110111111111001111111010 +11010000 110000000000000000000000000000011111111111111111111110101011111 +11010001 100000000000000000000000000000011111111111111111111110101011111 +11010010 000010000000000000000000000000011111101111111111111111111111111 +11010011 000000000000000000000000000000011111111111111111110111111010111 +11010100 000100000000000000000000000000011101111011001111111111111111111 +11010101 000000000000000000000000000000011111111111111111111111111111111 +11010110 000001000000000000000000000000011111111111111111111111111111111 +11010111 000000000000000010000000000000011111111111111111111111111111111 +11011000 010000000000000000000000000000011111111111111111111110101011111 +11011001 000000000000000000000000000000011111111111111111111110101011111 +11011010 000000000000000000000000000000011111111111111111111110101011111 +11011011 000000000000000000000000000000011111111111111111111110101011111 +11011100 000000000000000000000000000000011111111111111111111110101011111 +11011101 000000000000000000000000000000011111111111111111111110101011111 +11011110 000000000000000000000000000000011111111111111111111110101011111 +11011111 000000000000000000000000000000011111111111111111111110101011111 +11100000 110000000000000000000000000000011111111111111111111001111110110 +11100001 100000000000000000000000000000011111111111111111111001111110110 +11100010 000000000000000000000000000000011111111111111111111111111111111 +11100011 000000000000000000000000001000111011111101101111111111111111111 +11100100 001000000000000000000000000000011111111111001111111111111111111 +11100101 000000000000000000000000000000011111111111111111111111111111111 +11100110 000001000000000000000000000000011111111111111111111111111111111 +11100111 000000001000000000000000000000011011111111111111111111001111111 +11101000 010000000000000000000000000000011111111111111111111001111110010 +11101001 000000000000000000000000000000011111111111111111111001111110010 +11101010 000000000000000000000000000000011111111111111111111001111110010 +11101011 000000000000000000000000000000011111111111111111111001111110010 +11101100 000000000000000000000000000000011111111111111111111001111110010 +11101101 000000000000000000000000000000011111111111111111111001111110010 +11101110 000000000000000000000000000000011111111111111111111001111110010 +11101111 000000000000000000000000000000011111111111111111111001111110010 +11110000 110000000000000000000000000000011111111111111111111010111111111 +11110001 100000000000000000000000000000011111111111111111111010111111111 +11110010 000010000000000000000000000000011111101111111111111111111111111 +11110011 000000000000000000000000000000011111111111111111111111111111111 +11110100 000100000000000000000000000000011101111011001111111111111111111 +11110101 000000000000000000000000000000011111111111111111111111111111111 +11110110 000001000000000000000000000000011111111111111111111111111111111 +11110111 000000000000000000000000000000011011111111111110111110101101111 +11111000 010000000000000000000000000000011111111111111111111010111111111 +11111001 000000000000000000000000000000011111111111111111111010111111111 +11111010 000000000000000000000000000000011111111111111111111010111111111 +11111011 000000000000000000000000000000011111111111111111111010111111111 +11111100 000000000000000000000000000000011111111111111111111010111111111 +11111101 000000000000000000000000000000011111111111111111111010111111111 +11111110 000000000000000000000000000000011111111111111111111010111111111 +11111111 000000000000000000000000000000011111111111111111111010111111111 diff --git a/espresso/examples/indust/ex7 b/espresso/examples/indust/ex7 new file mode 100644 index 0000000..d37ca2f --- /dev/null +++ b/espresso/examples/indust/ex7 @@ -0,0 +1,125 @@ +.i 16 +.o 5 +-----------1---1 00001 +----001----1---- 00010 +----001---1----- 00100 +----001--1------ 01000 +----001-1------- 10000 +----010--------1 00010 +----010-------1- 00100 +----010------1-- 01000 +----010-----1--- 10000 +----011----1---1 00010 +----011---1---1- 00100 +----011--1---1-- 01000 +----011-1---1--- 10000 +----101----0---1 00010 +----101---0---1- 00100 +----101--0---1-- 01000 +----101-0---1--- 10000 +----101----1---0 00010 +----101---1---0- 00100 +----101--1---0-- 01000 +----101-1---0--- 10000 +----11-0--0000-1 00010 +--0-11----00---1 00010 +----11-0-0-00-01 00010 +----11-00-00-0-1 00010 +0---11--0-00-0-1 00010 +----11-000-0--01 00010 +----11-00000---1 00010 +----11-0---00001 00010 +-0--11---000---1 00010 +-0--11---0-0--01 00010 +0---11-----00001 00010 +----11-00--0-001 00010 +0---11--0--0-001 00010 +--0-11-----0--01 00010 +0---11---0000--1 00010 +-0--11-----0-001 00010 +0---11----0000-1 00010 +----11-0-0000--1 00010 +0---11---0-00-01 00010 +0---11--00-0--01 00010 +-0--11----00-0-1 00010 +0---11--0000---1 00010 +----11-0-00-0-1- 00100 +----11-0000---1- 00100 +0---11--0-0--01- 00100 +0---11--000---1- 00100 +----11-0--0-001- 00100 +----11-00-0--01- 00100 +-0--11---00---1- 00100 +-0--11----0--01- 00100 +0---11----0-001- 00100 +0---11---00-0-1- 00100 +0---11---0--01-- 01000 +----11-000---1-- 01000 +----11-0-0--01-- 01000 +0---11--00---1-- 01000 +----11-00---1--- 10000 +--0-11-----1--00 00010 +----11-00-01-0-0 00010 +----11-000-1--00 00010 +----11-00001---0 00010 +-0--11---0-1--00 00010 +-0--11---001---0 00010 +-0--11----01-0-0 00010 +0---11-----10000 00010 +0---11----0100-0 00010 +0---11---0-10-00 00010 +-0--11-----1-000 00010 +0---11---0010--0 00010 +----11-0---10000 00010 +0---11--0--1-000 00010 +0---11--0-01-0-0 00010 +0---11--00-1--00 00010 +0---11--0001---0 00010 +----11-0--0100-0 00010 +----11-0-0-10-00 00010 +----11-0-0010--0 00010 +--0-11----01---0 00010 +----11-00--1-000 00010 +0---11--0-1--00- 00100 +-0--11---01---0- 00100 +0---11---01-0-0- 00100 +-0--11----1--00- 00100 +----11-0-01-0-0- 00100 +0---11----1-000- 00100 +0---11--001---0- 00100 +----11-00-1--00- 00100 +----11-0001---0- 00100 +----11-0--1-000- 00100 +----11----10--10 00010 +----11----11--11 00010 +0---11---1--00-- 01000 +----11-0-1--00-- 01000 +----11-001---0-- 01000 +0---11--01---0-- 01000 +----11---10--10- 00100 +----11---11--11- 00100 +----11-01---0--- 10000 +----11--10--10-- 01000 +----11--11--11-- 01000 +----11-10---0--- 10000 +----11-11---1--- 10000 +---1------1---1- 00001 +---1100--------- 00010 +--1-100--------- 00100 +--1-11---1-0-1-0 00010 +--1-11---1-1-1-1 00010 +--11-----1---1-- 00001 +-1--100--------- 01000 +-1--11--1-0-1-0- 00100 +-1--11--1-1-1-1- 00100 +-11-11--1--01--0 00010 +-11-11--1--11--1 00010 +-111----1---1--- 00001 +1---100--------- 10000 +1---11-1-0---0-- 01000 +1---11-1-1---1-- 01000 +1-11---1-------- 00001 +11--11-1--0---0- 00100 +11--11-1--1---1- 00100 +111-11-1---0---0 00010 +111-11-1---1---1 00010 diff --git a/espresso/examples/indust/exep b/espresso/examples/indust/exep new file mode 100644 index 0000000..8429e48 --- /dev/null +++ b/espresso/examples/indust/exep @@ -0,0 +1,352 @@ +.i 30 +.o 63 +00010-------00---------------- 100000000000000000000000000000 +000000000000000000000000000000000 +00010-------0101-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +00010-------1-01-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +00010-------1-10-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +00010--------110-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +00100------------------------- 100000000000000000000000000000 +000000000000000000000000000000000 +00101-------0111-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +00101-------1----------------- 100000000000000000000000000000 +000000000000000000000000000000000 +00101--------0---------------- 100000000000000000000000000000 +000000000000000000000000000000000 +00101---------0--------------- 100000000000000000000000000000 +000000000000000000000000000000000 +00101----------0-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +01001------------------------- 100000000000000000000000000000 +000000000000000000000000000000000 +01010---------0--------------- 100000000000000000000000000000 +000000000000000000000000000000000 +01010---------1--------------- 100000000000000000000000000000 +000000000000000000000000000000000 +01101---------0--------------- 100000000000000000000000000000 +000000000000000000000000000000000 +01101----------0-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +0111----------0--------------- 100000000000000000000000000000 +000000000000000000000000000000000 +0111-----------0-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000-01---001010------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000-01---011010------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000-10---001010------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000-10---011010------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000-11---001010------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000-11---011010------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000------00010-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000------00011-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000------001110------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000------010100------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000------010110------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000------011110------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000------011-0-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000------0-00--------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000------0--00-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10000------10----------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10001------00-0--------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10001------00-10-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10001------00--1-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10001------01----------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10011000---------------------- 100000000000000000000000000000 +000000000000000000000000000000000 +1001101011101---0------------- 100000000000000000000000000000 +000000000000000000000000000000000 +1001101011110---0------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10011010111110110------------- 100000000000000000000000000000 +000000000000000000000000000000000 +100110101111101-0------------- 100000000000000000000000000000 +000000000000000000000000000000000 +100110101111110-0------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10011100------0-0------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10100-------00100------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10100-------01010------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10100-------01100-0----------- 100000000000000000000000000000 +000000000000000000000000000000000 +10100-------10-0-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10100-------11010------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10100-------11100-0----------- 100000000000000000000000000000 +000000000000000000000000000000000 +10100--------0110------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10100--------1000------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10100--------1100-1----------- 100000000000000000000000000000 +000000000000000000000000000000000 +10111-------01-1-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10111-------1-0--------------- 100000000000000000000000000000 +000000000000000000000000000000000 +10111-------1--0-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +11000------------------------- 100000000000000000000000000000 +000000000000000000000000000000000 +11001--------0---------------- 100000000000000000000000000000 +000000000000000000000000000000000 +11001--------110-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +11010000---------------------- 100000000000000000000000000000 +000000000000000000000000000000000 +11010---000------------------- 100000000000000000000000000000 +000000000000000000000000000000000 +11010---------10-------------- 100000000000000000000000000000 +000000000000000000000000000000000 +110110------------------------ 100000000000000000000000000000 +000000000000000000000000000000000 +110111------------------------ 100000000000000000000000000000 +000000000000000000000000000000000 +00000---------------1-1111-1-- 010000000000000000000000000000 +000000000000000000000000000000000 +01-00---------------1-1111-1-- 010000000000000000000000000000 +000000000000000000000000000000000 +10010-------10------1-1111-1-- 010000000000000000000000000000 +000000000000000000000000000000000 +10010-------1100----1-1111-1-- 010000000000000000000000000000 +000000000000000000000000000000000 +10010-------1-1-----1-1111-1-- 010000000000000000000000000000 +000000000000000000000000000000000 +10010-------1--1----1-1111-1-- 010000000000000000000000000000 +000000000000000000000000000000000 +10101---------------1-1111-1-- 010000000000000000000000000000 +000000000000000000000000000000000 +1110----------------1-1111-1-- 010000000000000000000000000000 +000000000000000000000000000000000 +00011---------------1-1---11-- 001000000000000000000000000000 +000000000000000000000000000000000 +0011--------11------1-1---11-- 001000000000000000000000000000 +000000000000000000000000000000000 +0011--------1-0-----1-1---11-- 001000000000000000000000000000 +000000000000000000000000000000000 +10010-------01------1-1---11-- 001000000000000000000000000000 +000000000000000000000000000000000 +10010-------0-0-----1-1---11-- 001000000000000000000000000000 +000000000000000000000000000000000 +10111-------1011----1-1---11-- 001000000000000000000000000000 +000000000000000000000000000000000 +0011--------01------1-1--11--1 000100000000000000000000000000 +000000000000000000000000000000000 +0011--------0-0-----1-1--11--1 000100000000000000000000000000 +000000000000000000000000000000000 +01011---------------1-1--11--1 000100000000000000000000000000 +000000000000000000000000000000000 +10010-------0010----1-1--11--1 000100000000000000000000000000 +000000000000000000000000000000000 +10111-------00------1-1-111--1 000010000000000000000000000000 +000000000000000000000000000000000 +10111-------0-10----1-1-111--1 000010000000000000000000000000 +000000000000000000000000000000000 +10111-------1111----1-1-111--1 000010000000000000000000000000 +000000000000000000000000000000000 +10000-01---011010--1--1---1-11 000001000000000000000000000000 +000000000000000000000000000000000 +10100-01----11010--1--1---1-11 000001000000000000000000000000 +000000000000000000000000000000000 +10000------11000----111-111--1 000000100000000000000000000000 +000000000000000000000000000000000 +10111-------0100----111-111--1 000000100000000000000000000000 +000000000000000000000000000000000 +11001--------11-----11-11-1-11 000000010000000000000000000000 +000000000000000000000000000000000 +11001--------1-1----11-11-1-11 000000010000000000000000000000 +000000000000000000000000000000000 +10000-11---011010----1111-1-11 000000001000000000000000000000 +000000000000000000000000000000000 +10100-11----11010----1111-1-11 000000001000000000000000000000 +000000000000000000000000000000000 +10000-00---011010----1111-1--1 000000000100000000000000000000 +000000000000000000000000000000000 +10100-00----11010----1111-1--1 000000000100000000000000000000 +000000000000000000000000000000000 +10000-10---011010-----11--1--1 000000000010000000000000000000 +000000000000000000000000000000000 +10100-10----11010-----11--1--1 000000000010000000000000000000 +000000000000000000000000000000000 +10011111-----------11111----1- 000000000001000000000000000000 +000000000000000000000000000000000 +11010-------1-00---1111-11-1-1 000000000000100000000000000000 +000000000000000000000000000000000 +11010-------1-01---1111-1--111 000000000000010000000000000000 +000000000000000000000000000000000 +00010-------1011---111-1--1-11 000000000000001000000000000000 +000000000000000000000000000000000 +00010-------1111---111-1---111 000000000000000100000000000000 +000000000000000000000000000000000 +1001101001------0--111----11-1 000000000000000010000000000000 +000000000000000000000000000000000 +1001101000------0--111-----1-1 000000000000000001000000000000 +000000000000000000000000000000000 +10111-------0101---11-1111--11 000000000000000000100000000000 +000000000000000000000000000000000 +00010-------1000---11-1---1-11 000000000000000000010000000000 +000000000000000000000000000000000 +00010-------1100---11-1-----11 000000000000000000001000000000 +000000000000000000000000000000000 +10100-------00010--11--1111111 000000000000000000000100000000 +000000000000000000000000000000000 +10010101----00110--11--1-1-1-- 000000000000000000000010000000 +000000000000000000000000000000000 +10111-------0111---11--1--11-- 000000000000000000000001000000 +000000000000000000000000000000000 +10010-11----00110--11---11-1-- 000000000000000000000000100000 +000000000000000000000000000000000 +10010--0----00110--11----1-1-- 000000000000000000000000010000 +000000000000000000000000000000000 +10100-01----01010--1-11---1--- 000000000000000000000000001000 +000000000000000000000000000000000 +11010-------0-01---1-1-111--1- 000000000000000000000000000100 +000000000000000000000000000000000 +11010-------1-1----1-1-11----1 000000000000000000000000000010 +000000000000000000000000000000000 +10100-00----01010--1-1-1--1--- 000000000000000000000000000001 +000000000000000000000000000000000 +11010-------0-00---1-1--11-11- 000000000000000000000000000000 +100000000000000000000000000000000 +11010-------0-11---1-1--1-1111 000000000000000000000000000000 +010000000000000000000000000000000 +10100-11----01010--1-1----1--1 000000000000000000000000000000 +001000000000000000000000000000000 +10100-10----01010--1--1---1--- 000000000000000000000000000000 +000100000000000000000000000000000 +01101-------0111-1-1---111111- 000000000000000000000000000000 +000010000000000000000000000000000 +01101-------0011-1-1---11-111- 000000000000000000000000000000 +000001000000000000000000000000000 +01101-------0111-0-1----11111- 000000000000000000000000000000 +000000100000000000000000000000000 +01101-------0011-0-1----1-111- 000000000000000000000000000000 +000000010000000000000000000000000 +01101-------1011---1-----1111- 000000000000000000000000000000 +000000001000000000000000000000000 +01101-------1111---1------111- 000000000000000000000000000000 +000000000100000000000000000000000 +00010-------0100----111---1111 000000000000000000000000000000 +000000000010000000000000000000000 +00010-------0111----11-1--1111 000000000000000000000000000000 +000000000001000000000000000000000 +10100-11----11110---1-1111111- 000000000000000000000000000000 +000000000000100000000000000000000 +10011011------------1-11111--1 000000000000000000000000000000 +000000000000010000000000000000000 +10100-------01110---1-1111-1-1 000000000000000000000000000000 +000000000000001000000000000000000 +10100-------00000---1-1111--1- 000000000000000000000000000000 +000000000000000100000000000000000 +100110101111111-0---1---111-1- 000000000000000000000000000000 +000000000000000010000000000000000 +0011---------011----1----11--1 000000000000000000000000000000 +000000000000000001000000000000000 +10100-------10010---1----1-11- 000000000000000000000000000000 +000000000000000000100000000000000 +10011110--------0---1----1--1- 000000000000000000000000000000 +000000000000000000010000000000000 +0011---------010----1-----1--- 000000000000000000000000000000 +000000000000000000001000000000000 +0111--------0111-1-----11111-- 000000000000000000000000000000 +000000000000000000000100000000000 +0111--------0011-1-----11-11-- 000000000000000000000000000000 +000000000000000000000010000000000 +01111-------1011-------1-111-- 000000000000000000000000000000 +000000000000000000000001000000000 +0111--------0111-0------1111-- 000000000000000000000000000000 +000000000000000000000000100000000 +0111--------0011-0------1-11-- 000000000000000000000000000000 +000000000000000000000000010000000 +01110-------1011---------111-- 000000000000000000000000000000 +000000000000000000000000001000000 +0111--------1111----------11-- 000000000000000000000000000000 +000000000000000000000000000100000 +10000-10---001010----------1-1 000000000000000000000000000000 +000000000000000000000000000010000 +10000-01---001010----------1-- 000000000000000000000000000000 +000000000000000000000000000001000 +10000-11---001010-----------1- 000000000000000000000000000000 +000000000000000000000000000000100 +10000-00---001010------------1 000000000000000000000000000000 +000000000000000000000000000000010 +00001------------------------- 222222222222222222222222222222 +222222222222222222222222222222222 +10-00------0-1-11------------- 222222222222222222222222222222 +222222222222222222222222222222222 +10000------00110-------------- 222222222222222222222222222222 +222222222222222222222222222222222 +10000-------101-1------------- 222222222222222222222222222222 +222222222222222222222222222222222 +1000-------11--1-------------- 222222222222222222222222222222 +222222222222222222222222222222222 +1000-------11-1--------------- 222222222222222222222222222222 +222222222222222222222222222222222 +1000-------111---------------- 222222222222222222222222222222 +222222222222222222222222222222222 +-0001------1------------------ 222222222222222222222222222222 +222222222222222222222222222222222 +10-10-------00111------------- 222222222222222222222222222222 +222222222222222222222222222222222 +1001-001----0011-------------- 222222222222222222222222222222 +222222222222222222222222222222222 +10011-01---------------------- 222222222222222222222222222222 +222222222222222222222222222222222 +10011-10--------1------------- 222222222222222222222222222222 +222222222222222222222222222222222 +1001101010-------------------- 222222222222222222222222222222 +222222222222222222222222222222222 +100110101-0------------------- 222222222222222222222222222222 +222222222222222222222222222222222 +100110101--00----------------- 222222222222222222222222222222 +222222222222222222222222222222222 +100-10101--1100--------------- 222222222222222222222222222222 +222222222222222222222222222222222 +1001110---------1------------- 222222222222222222222222222222 +222222222222222222222222222222222 +1001110-------1--------------- 222222222222222222222222222222 +222222222222222222222222222222222 +101-0-------0---1------------- 222222222222222222222222222222 +222222222222222222222222222222222 +101-0----------11------------- 222222222222222222222222222222 +222222222222222222222222222222222 +101-0--------1--1------------- 222222222222222222222222222222 +222222222222222222222222222222222 +101-0-0-----1111-------------- 222222222222222222222222222222 +222222222222222222222222222222222 +101-0--0----1111-------------- 222222222222222222222222222222 +222222222222222222222222222222222 +1-110------------------------- 222222222222222222222222222222 +222222222222222222222222222222222 +11001--------100-------------- 222222222222222222222222222222 +222222222222222222222222222222222 +1111-------------------------- 222222222222222222222222222222 +222222222222222222222222222222222 diff --git a/espresso/examples/indust/exp b/espresso/examples/indust/exp new file mode 100644 index 0000000..9ce093b --- /dev/null +++ b/espresso/examples/indust/exp @@ -0,0 +1,91 @@ +.i 8 +.o 18 +00000001 100001101--------0 +00000010 110000101-----1000 +00000011 110000111-----1000 +00000100 --------------1000 +00000101 --------------0100 +00000110 --------------0011 +00100001 100001101--------0 +00100010 110000101-----1000 +00100011 110000101-----1000 +00100100 110000111-----1000 +00100101 --------------1000 +00100110 --------------0100 +00100111 --------------0011 +01100001 100001101--------0 +01100010 110000101-----1000 +01100011 110000101-----1000 +01100100 110000101-----1000 +01100101 110000111-----1000 +01100110 --------------1000 +01100111 --------------0100 +01101000 --------------0011 +01000001 100001101--------0 +01000010 110000101-----1000 +01000011 110000101-----1000 +01000100 110000101-----1000 +01000101 110000101-----1000 +01000110 110000111-----1000 +01000111 --------------1000 +01001000 --------------0100 +01001001 --------------0011 +11000001 000001100--------0 +11000010 010000100-----1000 +11000011 010000110-----1000 +11000100 ---------100000000 +11000101 001001001010001000 +11000110 011000001001001000 +11000111 011000011-----1000 +11001000 --------------0100 +11001001 --------------0001 +11100001 000001100--------0 +11100010 010000100-----1000 +11100011 010000100-----1000 +11100100 010000110100000000 +11100101 000001001100000000 +11100110 010000001010001000 +11100111 010000001001001000 +11101000 010000001-----1000 +11101001 --------------1000 +11101010 --------------0100 +11101011 --------------0011 +10100001 000001100--------0 +10100010 010000100-----1000 +10100011 010000100-----1000 +10100100 010000100100010000 +10100101 010000110100010000 +10100110 000001000100010000 +10100111 010000000010011000 +10101000 010000000001011000 +10101001 010000000100010000 +10101010 010000010100010000 +10101011 001001001100010000 +10101100 011000001010011000 +10101101 011000001001011000 +10101110 011000001-----1000 +10101111 011000011-----1000 +10110000 --------------1000 +10110001 --------------0100 +10110010 --------------0001 +10000001 000001100--------0 +10000010 010000100-----1000 +10000011 010000100-----1000 +10000100 010000100100100000 +10000101 010000100100100000 +10000110 010000110100100000 +10000111 000001000100100000 +10001000 010000000010101000 +10001001 010000000001101000 +10001010 010000000100100000 +10001011 010000000100100000 +10001100 010000010100100000 +10001101 000001001100100000 +10001110 010000001010101000 +10001111 010000001001101000 +10010000 010000001-----1000 +10010001 010000001-----1000 +10010010 010000011-----1000 +10010011 --------------1000 +10010100 --------------0100 +10010101 --------------0011 diff --git a/espresso/examples/indust/exps b/espresso/examples/indust/exps new file mode 100644 index 0000000..1da4eb4 --- /dev/null +++ b/espresso/examples/indust/exps @@ -0,0 +1,198 @@ +.i 8 +.o 38 +00000000 100110000010000101001000100000---00111 +00000001 100110001110000101001000100000---00111 +00000010 100110001100000101001000100000---00111 +00000011 000100011000000101001000100000---01101 +00000100 000100000110001101001000100000---01101 +00000101 000100000110001000001000000000---01000 +00000110 000100000110001101001001100000---00101 +00000111 000100000000001000001100001000---01000 +00001000 000010001010001000000000001100---00000 +00001001 000010001100010101001000100100---00101 +00001010 000100000110110101001000100000---01101 +00001011 000100000110110000000000001000---01000 +00001100 000010001011010101001000100100---00101 +00001101 000100000000001000001100001000---01000 +00001110 000010001010001000000000001100---00000 +00001111 000010010010101101001000100100---00101 +00010000 000100011000001101001000100000---01101 +00010001 100110001100010101001000100000---00111 +00010010 100110010010101101001000100000---00111 +00010011 100110010011001101001000100000---00111 +00010100 110110000010000101001000100000---00011 +00010101 10011000001000010100000000101100000011 +00010110 110110001110000101001000100000---00011 +00010111 10011000111000010100000000101100000011 +00011000 110110001100000101001000100000---00011 +00011001 10011000110000010100000000101100000011 +00011010 000100000110000101000000000000---01001 +00011011 100110010010101101000000000000---00011 +00011100 110110001100010101001000100000---00011 +00011101 10011000110001010100000000101100000011 +00011110 110110010010101101001000100000---00011 +00011111 110110010011001101001000100000---00011 +00100000 10011001001010110100000000101100000011 +00100001 10011001001100110100000000101100000011 +00100010 010100000110000101001000100000---01001 +00100011 00010000011000010100000000101100001001 +00100100 000000000000000000100000000000---01001 +00101000 101110000010000101001000100000---00101 +00101001 10011000001000010100100010000000010101 +00101010 101110001110000101001000100000---00101 +00101011 10011000111000010100100010000000010101 +00101100 101110001100000101001000100000---00101 +00101101 10011000110000010100100010000000010101 +00101110 101110001100010101001000100000---00101 +00101111 10011000110001010100100010000000010101 +00110000 101110010010101101001000100000---00101 +00110001 10011001001010110100100010000000010101 +00110010 100100000110000101001000100000---00101 +00110011 001010001010000101001000100000---00101 +00110100 00001000101000010100100010000000010101 +00110101 000000000000000000010000000000---00101 +00110110 000010001010000101001000100100---00101 +00110111 000100000110000101001001100000---00101 +00111000 000000000000000101001000100000---00101 +00111001 000000000000001101001000100000---00101 +01000000 111110000010000101001000100000---00001 +01000001 11011000001000010100100010000000010001 +01000010 10111000001000010100000000101100000001 +01000011 10011000001000010100000000101100010001 +01000100 111110001110000101001000100000---00001 +01000101 11011000111000010100100010000000010001 +01000110 10111000111000010100000000101100000001 +01000111 10011000111000010100000000101100010001 +01001000 111110001100000101001000100000---00001 +01001001 11011000110000010100100010000000010001 +01001010 10111000110000010100000000101100000001 +01001011 10011000110000010100000000101100010001 +01001100 110100011000000101001000100000---00001 +01001101 00001001010000010100000000101100010001 +01001110 100100000110000101000000000000---00001 +01001111 00001000101000010100000000000000010001 +01010000 00001000101000011100000000101100110001 +01010001 00001000101000001100000000101101010001 +01010010 110100000110001101001000100000---00001 +01010011 00001000101000110100000000101100010001 +01010100 100100000110001000001000000000---00000 +01010101 010100000110001101001001100000---00001 +01010110 00001000101000100000100000000000010000 +01010111 00010000011000110100000100101100000001 +01011000 100100000000001000000110001000---00000 +01011001 000010001010001000000000001100---00000 +01011010 010010001100010101001000100100---00001 +01011011 00000000000000100000110000100000000000 +01011100 00001000101000100000100000010000000000 +01011101 00011000110001010100000100101100010001 +01011110 110100000110110101001000100000---00001 +01011111 00001000101101010100000000101100010001 +01100000 100100000110110000000000001000---00000 +01100001 010010001011010101001000100100---00001 +01100010 00001000101101000000100000000000010000 +01100011 00010000011011010100000100101100000001 +01100100 100100000000001000001100001000---00000 +01100101 000010001010001000000000001100---00000 +01100110 010010010010101101001000100100---00001 +01100111 00000000000000100000110000100000000000 +01101000 00001000101000100000100000010000000000 +01101001 00011001001100110100000100101100010001 +01101010 110100011000001101001000100000---00001 +01101011 00001001010000110100000000101100010001 +01101100 00001000101000010100000000101101110001 +01101101 00001000101000010100000000101110010001 +01101110 101110010010101101000000000000---00001 +01101111 10011001001010110100000000000000010001 +01110000 111110001100010101001000100000---00001 +01110001 11011000110001010100100010000000010001 +01110010 10111000110001010100000000101100000001 +01110011 10011000110001010100000000101100010001 +01110100 111110010010101101001000100000---00001 +01110101 11011001001010110100100010000000010001 +01110110 10111001001010110100000000101100000001 +01110111 10011001001010110100000000101100010001 +01111000 100100000110000000000000001000---00000 +01111001 001010000000000000001000000000---00000 +01111010 000101000000000000001011000000---00000 +01111011 000101000000000000001011000000---00000 +01111100 000101000000000000001011000000---00000 +01111101 000101000000000000001011000000---00000 +01111110 000101000000000000001011000000---00000 +01111111 000101000000000000001011000000---00000 +10000000 000101000000000000001011000000---00000 +10000001 000101000000000000001011000000---00000 +10000010 000101000000000000001011000000---00000 +10000011 000101000000000000001011000000---00000 +10000100 000101000000000000001011000000---00000 +10000101 000101000000000000001011000000---00000 +10000110 000101000000000000001011000000---00000 +10000111 000101000000000000001011000000---00000 +10001000 000101000000000000001011000000---00000 +10001001 000101000000000000001011000000---00000 +10001010 000101000000000000001011000000---00000 +10001011 000101000000000000001011000000---00000 +10001100 000101000000000000001011000000---00000 +10001101 000101000000000000001011000000---00000 +10001110 000101000000000000001011000000---00000 +10001111 000101000000000000001011000000---00000 +10010000 000101000000000000001011000000---00000 +10010001 000101000000000000001011000000---00000 +10010010 000101000000000000001011000000---00000 +10010011 000101000000000000001011000000---00000 +10010100 000101000000000000001011000000---00000 +10010101 000101000000000000001011000000---00000 +10010110 000101000000000000001011000000---00000 +10010111 000101000000000000001011000000---00000 +10011000 000101000000000000001011000000---00000 +10011001 000101000000000000001011000000---00000 +10011010 000100000110000101001001000000---00001 +10011011 100100000110000000000000001000---00000 +10011100 001010000000000000001000000000---00000 +10011101 000100010010101000001101000000---00000 +10011110 000100100000000000001101000000---00000 +10011111 000100100000000000001101000000---00000 +10100000 000100100000000000001101000000---00000 +10100001 000100100000000000001101000000---00000 +10100010 000100100000000000001101000000---00000 +10100011 000100100000000000001101000000---00000 +10100100 000100100000000000001101000000---00000 +10100101 000100100000000000001101000000---00000 +10100110 000100100000000000001101000000---00000 +10100111 000100100000000000001101000000---00000 +10101000 000100100000000000001101000000---00000 +10101001 000100100000000000001101000000---00000 +10101010 000100100000000000001101000000---00000 +10101011 000100100000000000001101000000---00000 +10101100 000100100000000000001101000000---00000 +10101101 000100100000000000001101000000---00000 +10101110 000100100000000000001101000000---00000 +10101111 000100100000000000001101000000---00000 +10110000 000100100000000000001101000000---00000 +10110001 000100100000000000001101000000---00000 +10110010 000100100000000000001101000000---00000 +10110011 000100100000000000001101000000---00000 +10110100 000100100000000000001101000000---00000 +10110101 000100100000000000001101000000---00000 +10110110 000100100000000000001101000000---00000 +10110111 000100100000000000001101000000---00000 +10111000 000100100000000000001101000000---00000 +10111001 000100100000000000001101000000---00000 +10111010 000100100000000000001101000000---00000 +10111011 000100100000000000001101000000---00000 +10111100 000100100000000000001101000000---00000 +10111101 000100100000000000001001000000---00000 +10111110 000100000000000000000101000000---00000 +10111111 000000000110000101001000000000---00001 +11000000 011010001010000101001000100000---00001 +11000001 01001000101000010100100010000000010001 +11000010 010000000000000000010000000000---00001 +10000011 010010001010000101001000100100---00001 +11000100 010100000110000101001001100000---00001 +11000101 10010000011000010100000000101100000001 +11000110 100000000000000000100000000000---00001 +11000111 010000000000000101001000100000---00001 +11001000 00000000000000010100000000101100000001 +10001001 010000000000001101001000100000---00001 +11001010 00000000000000110100000000101100000001 +10001011 000000000000000000000100010000---00001 +11001100 000000000000000000000000000000---00001 diff --git a/espresso/examples/indust/gary b/espresso/examples/indust/gary new file mode 100644 index 0000000..1eb1731 --- /dev/null +++ b/espresso/examples/indust/gary @@ -0,0 +1,216 @@ +.i 15 +.o 11 +-----------10-1 00000010101 +-----------101- 00000010110 +----------0-1-- 00000001000 +----------0-1-1 00000000001 +----------011-- 00000010000 +----------1011- 00000011110 +---------11110- 10101000000 +01-------11110- 00000001100 +10-------11110- 00000000100 +----------10010 00000000001 +----------1001- 10111000110 +-1-------10000- 10000010000 +00---0---00000- 01000010000 +010------00000- 10101000000 +---------0-001- 10000000000 +--1------0-001- 00100000000 +--01-----011101 00000100000 +--10-----011101 00000100000 +---------1100-0 10110000000 +10-------1100-0 00000000100 +--1------10000- 10000010000 +--01-----0-001- 00101000000 +---1-----10000- 10000010000 +00---100-00000- 11001010101 +00---101-00000- 11001010110 +01111----00000- 00000100000 +1000-1---00000- 01001010000 +10-10----0000-- 00100000000 +10110----00000- 00000010101 +10111----00000- 00100010110 +-11011---00000- 11000000000 +----1----10000- 10000010000 +000--110-00000- 10010000000 +110100---00000- 01000011100 +111001---00000- 11000010101 +1111-10--00000- 10001000000 +111110---00000- 10001000000 +--000----0-0010 00101000101 +000-011--00000- 10010000000 +1100-010-00000- 00000010110 +11-0-01--00000- 10000100000 +11001-1--00000- 10000100000 +1101010--00000- 10000010101 +1110-0---00000- 10000100100 +1111111--00000- 01000011101 +0-10-01---0000- 00000010000 +0000010--10000- 10000100000 +0001-11--00000- 10010000000 +0111-----0000-- 10000001100 +100000-1-00000- 00000000010 +10011010-00000- 00000100110 +10101000-00000- 00001010101 +11000111-00000- 00000000010 +110011-0-00000- 10000100000 +11-01010-00000- 00000000010 +1111011--00000- 01000000010 +01100010-00000- 00000000001 +01100001-00000- 00000000001 +011000---00000- 00000010010 +------11-10000- 00000010000 +11--------10001 10101010101 +01--------100-1 00000001000 +00------0-1-0-1 00000010000 +1-00000--00000- 01000000001 +1101011--00000- 11000000000 +----------0-11- 00000000010 +-----------0111 00000000001 +11--------1-01- 00000010000 +01--------10-1- 00000001000 +00------0-1-01- 00000010000 +0-------111110- 00000001100 +01-------1100-- 00000001100 +0---------10001 10101000101 +101------0--01- 00000000100 +011------0-001- 00000001100 +101------00000- 11000000000 +-0-1----10--01- 00000000100 +-01-----10--01- 00000000100 +01-1-----0-001- 00000001100 +--000----0-0011 00101000110 +--00------10001 10101000101 +-0------11100-0 00000000100 +10-1-----0--01- 00000000100 +11000----0--01- 00000010000 +10-1------0000- 10000000000 +1--------10000- 10000010000 +01--0----0-0-1- 00000001000 +-000-0---00000- 01000010000 +-1-0100---0000- 10000000000 +11011-----0000- 00000010000 +-01--1-1--0000- 10000000000 +-----0---10000- 00000010000 +111000---000-0- 00000001000 +00000---00--01- 00000010000 +1-1000---00000- 00000000100 +0111-1-0-00000- 00000100000 +110010-0-00000- 00000000101 +1-000-0---0000- 00000010000 +0111--01-00000- 00000100000 +0111-01--00000- 00000100000 +100000-0-00000- 00000000001 +1-110111-00000- 00000000001 +-----1-0-10000- 10000000000 +1110-011-000-0- 00000001000 +10101001-00000- 00001010110 +-11000-0-00000- 10000000100 +11-0011--00000- 01000010001 +-----------10-1 00000010101 +-----------101- 00000010110 +----------0-1-- 00000001000 +----------0-1-1 00000000001 +----------011-- 00000010000 +----------1011- 00000011110 +---------11110- 10101000000 +01-------11110- 00000001100 +10-------11110- 00000000100 +----------10010 00000000001 +----------1001- 10111000110 +-1-------10000- 10000010000 +00---0---00000- 01000010000 +010------00000- 10101000000 +---------0-001- 10000000000 +--1------0-001- 00100000000 +--01-----011101 00000100000 +--10-----011101 00000100000 +---------1100-0 10110000000 +10-------1100-0 00000000100 +--1------10000- 10000010000 +--01-----0-001- 00101000000 +---1-----10000- 10000010000 +00---100-00000- 11001010101 +00---101-00000- 11001010110 +01111----00000- 00000100000 +1000-1---00000- 01001010000 +10-10----0000-- 00100000000 +10110----00000- 00000010101 +10111----00000- 00100010110 +-11011---00000- 11000000000 +----1----10000- 10000010000 +000--110-00000- 10010000000 +110100---00000- 01000011100 +111001---00000- 11000010101 +1111-10--00000- 10001000000 +111110---00000- 10001000000 +--000----0-0010 00101000101 +000-011--00000- 10010000000 +1100-010-00000- 00000010110 +11-0-01--00000- 10000100000 +11001-1--00000- 10000100000 +1101010--00000- 10000010101 +1110-0---00000- 10000100100 +1111111--00000- 01000011101 +0-10-01---0000- 00000010000 +0000010--10000- 10000100000 +0001-11--00000- 10010000000 +0111-----0000-- 10000001100 +100000-1-00000- 00000000010 +10011010-00000- 00000100110 +10101000-00000- 00001010101 +11000111-00000- 00000000010 +110011-0-00000- 10000100000 +11-01010-00000- 00000000010 +1111011--00000- 01000000010 +01100010-00000- 00000000001 +01100001-00000- 00000000001 +011000---00000- 00000010010 +------11-10000- 00000010000 +11--------10001 10101010101 +01--------100-1 00000001000 +00------0-1-0-1 00000010000 +1-00000--00000- 01000000001 +1101011--00000- 11000000000 +----------0-11- 00000000010 +-----------0111 00000000001 +11--------1-01- 00000010000 +01--------10-1- 00000001000 +00------0-1-01- 00000010000 +0-------111110- 00000001100 +01-------1100-- 00000001100 +0---------10001 10101000101 +101------0--01- 00000000100 +011------0-001- 00000001100 +101------00000- 11000000000 +-0-1----10--01- 00000000100 +-01-----10--01- 00000000100 +01-1-----0-001- 00000001100 +--000----0-0011 00101000110 +--00------10001 10101000101 +-0------11100-0 00000000100 +10-1-----0--01- 00000000100 +11000----0--01- 00000010000 +10-1------0000- 10000000000 +1--------10000- 10000010000 +01--0----0-0-1- 00000001000 +-000-0---00000- 01000010000 +-1-0100---0000- 10000000000 +11011-----0000- 00000010000 +-01--1-1--0000- 10000000000 +-----0---10000- 00000010000 +111000---000-0- 00000001000 +00000---00--01- 00000010000 +1-1000---00000- 00000000100 +0111-1-0-00000- 00000100000 +110010-0-00000- 00000000101 +1-000-0---0000- 00000010000 +0111--01-00000- 00000100000 +0111-01--00000- 00000100000 +100000-0-00000- 00000000001 +1-110111-00000- 00000000001 +-----1-0-10000- 10000000000 +1110-011-000-0- 00000001000 +10101001-00000- 00001010110 +-11000-0-00000- 10000000100 +11-0011--00000- 01000010001 diff --git a/espresso/examples/indust/ibm b/espresso/examples/indust/ibm new file mode 100644 index 0000000..6d658c9 --- /dev/null +++ b/espresso/examples/indust/ibm @@ -0,0 +1,175 @@ +.i 48 +.o 17 +111110110--------------------------------------- 10000000000000000 +111-101101-------------------------------------- 10000000000000000 +--111111--01------------------------------------ 10000000000000000 +--1-111101-1------------------------------------ 10000000000000000 +--0111110---11---------------------------------- 10000000000000000 +--0-111101--11---------------------------------- 10000000000000000 +1111----------1--------------------------------- 10000000000000000 +111------1----1--------------------------------- 10000000000000000 +--0-----------11-------------------------------- 10000000000000000 +---0-----0----11-------------------------------- 10000000000000000 +--0--0110------1-------------------------------- 10000000000000000 +---0-01100-----1-------------------------------- 10000000000000000 +----01-10------1-------------------------------- 10000000000000000 +----0-110------1-------------------------------- 10000000000000000 +----0000-------1-------------------------------- 10000000000000000 +----00111-------0------------------------------- 10000000000000000 +--10111100--1----------------------------------- 10000000000000000 +--0100111---11--0------------------------------- 01000000000000000 +--0-001111--11--0------------------------------- 01000000000000000 +--1-001111-1----0------------------------------- 01000000000000000 +--1110110--1------------------------------------ 01000000000000000 +--1-101101-1------------------------------------ 01000000000000000 +--01--------111--------------------------------- 01000000000000000 +--0------1--111--------------------------------- 01000000000000000 +--11-------1--1--------------------------------- 01000000000000000 +--1------1-1--1--------------------------------- 01000000000000000 +--0--0110--------1------------------------------ 01000000000000000 +---0-01100-------1------------------------------ 01000000000000000 +--10001110--1---0------------------------------- 01000000000000000 +----0011---------1------------------------------ 01000000000000000 +--1100111--1----0------------------------------- 01000000000000000 +----01-10--------1------------------------------ 01000000000000000 +--10-----0--1-1--------------------------------- 01000000000000000 +0-------------1-0-1----------------------------- 00100000000000000 +-0------------1-0-1----------------------------- 00100000000000000 +0---1-110-------0-1----------------------------- 00100000000000000 +-0--1-110-------0-1----------------------------- 00100000000000000 +--0-----------1---1----------------------------- 00100000000000000 +---0-----0----1---1----------------------------- 00100000000000000 +--0-1-110---------1----------------------------- 00100000000000000 +---01-1100--------1----------------------------- 00100000000000000 +----0000----------1----------------------------- 00100000000000000 +----0011----------1----------------------------- 00100000000000000 +----01-10---------1----------------------------- 00100000000000000 +--------------1-1--1---------------------------- 00100000000000000 +----1-110-------1--1---------------------------- 00100000000000000 +0-------------1-0---1--------------------------- 00010000000000000 +-0------------1-0---1--------------------------- 00010000000000000 +0---1-110-------0---1--------------------------- 00010000000000000 +-0--1-110-------1---1--------------------------- 00010000000000000 +--0-----------1-----1--------------------------- 00010000000000000 +---0-----0----1-----1--------------------------- 00010000000000000 +--0-1-110-----------1--------------------------- 00010000000000000 +---01-1100----------1--------------------------- 00010000000000000 +----0000------------1--------------------------- 00010000000000000 +----0011------------1--------------------------- 00010000000000000 +----01-10-----------1--------------------------- 00010000000000000 +--------------1-1----1-------------------------- 00010000000000000 +----1-110-------1----1-------------------------- 00010000000000000 +0-------------1-0-----1------------------------- 00001000000000000 +-0------------1-0-----1------------------------- 00001000000000000 +0---1-110-------1-----1------------------------- 00001000000000000 +-0--1-110-------0-----1------------------------- 00001000000000000 +--0-----------1-------1------------------------- 00001000000000000 +---0-----0----1-------1------------------------- 00001000000000000 +--0-1-110-------------1------------------------- 00001000000000000 +---01-1100------------1------------------------- 00001000000000000 +----0000--------------1------------------------- 00001000000000000 +----0011--------------1------------------------- 00001000000000000 +----01-10-------------1------------------------- 00001000000000000 +--------------1-1------1------------------------ 00001000000000000 +----1-110-------1------1------------------------ 00001000000000000 +0-------------1-0-------1----------------------- 00000100000000000 +-0------------1-0-------1----------------------- 00000100000000000 +0---1-110-------0-------1----------------------- 00000100000000000 +-0--1-110-------0-------1----------------------- 00000100000000000 +--0-----------1---------1----------------------- 00000100000000000 +---0-----0----1---------1----------------------- 00000100000000000 +--0-1-110---------------1----------------------- 00000100000000000 +---01-1100--------------1----------------------- 00000100000000000 +----0000----------------1----------------------- 00000100000000000 +----0011----------------1----------------------- 00000100000000000 +----01-10---------------1----------------------- 00000100000000000 +--------------1-1--------1---------------------- 00000100000000000 +----1-110-------1--------1---------------------- 00000100000000000 +0-------------1-0---------1--------------------- 00000010000000000 +-0------------1-0---------1--------------------- 00000010000000000 +0---11-10-------0---------1--------------------- 00000010000000000 +-0--1-110-------0---------1--------------------- 00000010000000000 +--0-----------1-----------1--------------------- 00000010000000000 +---0-----0----1-----------1--------------------- 00000010000000000 +--0-1-110-----------------1--------------------- 00000010000000000 +---01-1100----------------1--------------------- 00000010000000000 +----0000------------------1--------------------- 00000010000000000 +----0011------------------1--------------------- 00000010000000000 +----00-10-----------------1--------------------- 00000010000000000 +--------------1-1----------1-------------------- 00000010000000000 +----1-110-------1----------1-------------------- 00000010000000000 +0-------------1-0-----------1------------------- 00000001000000000 +-0------------1-0-----------1------------------- 00000001000000000 +0---1-110-------0-----------1------------------- 00000001000000000 +-0--1-110-------0-----------1------------------- 00000001000000000 +--0-----------1-------------1------------------- 00000001000000000 +---0-----0----1-------------1------------------- 00000001000000000 +--0-1-110-------------------1------------------- 00000001000000000 +---01-1100------------------1------------------- 00000001000000000 +----0000--------------------1------------------- 00000001000000000 +----0011--------------------1------------------- 00000001000000000 +----01-10-------------------1------------------- 00000001000000000 +--------------1-1------------1------------------ 00000001000000000 +----1-110-------1------------1------------------ 00000001000000000 +--------------1-0-------------1----------------- 00000000100000000 +----1-110-------0-------------1----------------- 00000000100000000 +--------------1-1--------------1---------------- 00000000100000000 +----1-110-------1--------------1---------------- 00000000100000000 +----0001----------------------1----------------- 00000000100000000 +----01-10---------------------1----------------- 00000000100000000 +--------------1-0---------------1--------------- 00000000010000000 +----1-110-------0---------------1--------------- 00000000010000000 +--------------1-1----------------1-------------- 00000000010000000 +----1-110-------1----------------1-------------- 00000000010000000 +----0000------------------------1--------------- 00000000010000000 +----0011------------------------1--------------- 00000000010000000 +----01-10-----------------------1--------------- 00000000010000000 +--------------1-0-----------------1------------- 00000000001000000 +----1-110-------0-----------------1------------- 00000000001000000 +--------------1-1------------------1------------ 00000000001000000 +----1-110-------1------------------1------------ 00000000001000000 +----0000--------------------------1------------- 00000000001000000 +----0011--------------------------1------------- 00000000001000000 +----01-10-------------------------1------------- 00000000001000000 +--------------1-0-------------------1----------- 00000000000100000 +----1-110-------0-------------------1----------- 00000000000100000 +--------------1-1--------------------1---------- 00000000000100000 +----1-110-------1--------------------1---------- 00000000000100000 +----0000----------------------------1----------- 00000000000100000 +----0011----------------------------1----------- 00000000000100000 +----01-10---------------------------1----------- 00000000000100000 +--------------1-0---------------------1--------- 00000000000010000 +----1-110-------0---------------------1--------- 00000000000010000 +--------------1-1----------------------1-------- 00000000000010000 +----1-110-------1----------------------1-------- 00000000000010000 +----0000------------------------------1--------- 00000000000010000 +----0011------------------------------1--------- 00000000000010000 +----01-10-----------------------------1--------- 00000000000010000 +--------------1-0-----------------------1------- 00000000000001000 +----1-110-------0-----------------------1------- 00000000000001000 +--------------1-1------------------------1------ 00000000000001000 +----1-110-------1------------------------1------ 00000000000001000 +----0000--------------------------------1------- 00000000000001000 +----0011--------------------------------1------- 00000000000001000 +----01-10-------------------------------1------- 00000000000001000 +-----------1--1-0------------------------------- 00000000000000100 +----1-110-------0-------------------------1----- 00000000000000100 +--------------1-1--------------------------1---- 00000000000000100 +----1-110-------1--------------------------1---- 00000000000000100 +----0000----------------------------------1----- 00000000000000100 +----0011----------------------------------1----- 00000000000000100 +----01-10---------------------------------1----- 00000000000000100 +--------------1-0---------------------------1--- 00000000000000010 +----1-110-------0---------------------------1--- 00000000000000010 +--------------1-1----------------------------1-- 00000000000000010 +----1-110-------1----------------------------1-- 00000000000000010 +----0000------------------------------------1--- 00000000000000010 +----0011------------------------------------1--- 00000000000000010 +----01-10-----------------------------------1--- 00000000000000010 +--------------1-0-----------------------------1- 00000000000000001 +----1-110-------0-----------------------------1- 00000000000000001 +--------------1-1------------------------------1 00000000000000001 +----1-110-------1------------------------------1 00000000000000001 +----0000--------------------------------------1- 00000000000000001 +----0011--------------------------------------1- 00000000000000001 +----01-10-------------------------------------1- 00000000000000001 diff --git a/espresso/examples/indust/in0 b/espresso/examples/indust/in0 new file mode 100644 index 0000000..72214fc --- /dev/null +++ b/espresso/examples/indust/in0 @@ -0,0 +1,140 @@ +.i 15 +.o 11 +00---0---00000- 01000010000 +00---100-00000- 11001010101 +00---101-00000- 11001010110 +000--110-00000- 10010000000 +000-0111-00000- 10010000000 +00011111-00000- 10010000000 +001--111-00000- 10000000000 +010------00000- 10101000000 +01110000-00000- 10000001100 +01110111-00000- 10000001100 +01110-01-00000- 10000101100 +0111001--00000- 10000101100 +011101-0-00000- 10000101100 +01111----00000- 10000101100 +100000-0-00000- 01000010001 +10000001-00000- 01000010011 +10000011-00000- 01000010010 +1000-1---00000- 01001010000 +100010---00000- 01000010000 +10010----00000- 10100000000 +1001100--00000- 10000000000 +10011010-00000- 10000100110 +10011011-00000- 10000000000 +100111---00000- 10000000000 +101000---00000- 11000000100 +1010-1---00000- 11000000000 +1010101--00000- 11000000000 +10101000-00000- 11001010101 +10101001-00000- 11001010110 +10110----00000- 11100010101 +10111----00000- 11100010110 +1100000--00000- 01000010001 +1100-010-00000- 10000110110 +1100-011-00000- 10000100000 +1100010--00000- 00000010000 +11000110-00000- 01000010001 +11000111-00000- 01000010011 +11001000-00000- 10000000101 +11001001-00000- 10000000000 +11001100-00000- 10000100000 +11001010-00000- 10000110101 +1100111--00000- 10000100000 +11011----00000- 00000010000 +110100---00000- 01000011100 +1101010--00000- 10000010101 +1101011--00000- 11000000000 +1110000--00000- 10000101100 +11100010-00000- 10000101100 +11100011-00000- 10000101100 +111001---00000- 11000010101 +1110100--00000- 10000100100 +11101010-00000- 10000100110 +11101011-00000- 10000101100 +-11011---00000- 11000000000 +1111-10--00000- 10001000000 +111110---00000- 10001000000 +11110110-00000- 01000000010 +11110111-00000- 01000000011 +1111111--00000- 01000011101 +0110100--00000- 10000000000 +0110101--00000- 00000010000 +01100000-00000- 10000010110 +01100010-00000- 10000010111 +01100001-00000- 00000010011 +01100011-00000- 00000010010 +11000----000010 10101010101 +01000----000010 10101001101 +10000----000010 10101000101 +00000---0000010 10101010101 +00000---1000010 10101000101 +--001----00001- 10000000000 +1101-----00001- 10101000000 +0101-----00001- 10101001100 +1001-----00001- 10101000100 +0001----000001- 10101000000 +0001----100001- 10101000100 +111------00001- 10100000000 +011------00001- 10100001100 +101------00001- 10100000100 +001-----000001- 10100000000 +001-----100001- 10100000100 +11000----000011 10101010110 +01000----000011 10101001110 +10000----000011 10101000110 +00000---0000011 10101010110 +00000---1000011 10101000110 +--01-----011101 00000100000 +--10-----011101 00000100000 +11-------11110- 10101000000 +01-------11110- 10101001100 +10-------11110- 10101000100 +00------011110- 10101000000 +00------111110- 10101001100 +11-------110000 10110000000 +01-------110000 10110001100 +10-------110000 10110000100 +00------0110000 10110000000 +00------1110000 10110000100 +11--------10001 10101010101 +01--------10001 10101001101 +1000------10001 10101000101 +00------0-10001 10101010101 +00------1-10001 10101000101 +11--------10010 10111010111 +01--------10010 10111001111 +10--------10010 10111000111 +00------0-10010 10111010111 +00------1-10010 10111000111 +11--------10011 10111010110 +01--------10011 10111001110 +10--------10011 10111000110 +00------0-10011 10111010110 +00------1-10011 10111000110 +----------00100 00000001000 +----------00101 00000001001 +----------00110 00000001010 +----------00111 00000001011 +-----------1000 00000000000 +-----------1001 00000010101 +-----------1010 00000010110 +-----------1011 00000010111 +----------01100 00000011000 +----------01101 00000011001 +----------01110 00000011010 +----------01111 00000011011 +----------1010- 00000000000 +----------10110 00000011110 +----------10111 00000011111 +----------1111- 00000000000 +000000---10000- 00000010000 +0000010--10000- 10000100000 +00000110-10000- 10000000000 +00000111-10000- 00000010000 +00001----10000- 10000010000 +0001-----10000- 10000010000 +001------10000- 10000010000 +01-------10000- 10000010000 +1--------10000- 10000010000 diff --git a/espresso/examples/indust/in1 b/espresso/examples/indust/in1 new file mode 100644 index 0000000..f12deb9 --- /dev/null +++ b/espresso/examples/indust/in1 @@ -0,0 +1,112 @@ +.i 16 +.o 17 +----00----00-00- 11101111111111111 +0----1----1100-0 11111010000010011 +01--110-11011110 10110001101000110 +01--010-1-011110 01111001000110101 +-----111--1100-0 11111010000010011 +----------101110 11101111111111111 +0---11-01-010000 10010001101010110 +01--110-10011110 10110001101001000 +----11111-010000 10011001101010110 +10--------1010-1 11011111111111111 +0---110---010000 10010001101010110 +0-----010-110000 11111010000010011 +----1-----000110 11111001101101001 +--------1-100110 11111010100100101 +----1-----001000 11111010000010001 +1---------101000 11111010101101001 +----000011011000 01111001000011101 +----100011011000 11111001110001101 +0---100100111000 11111001101000100 +----1-----000100 11111001101101100 +----1-----001010 11111010010001110 +0---010---010011 01111001000011101 +-----0----011100 11111001100110001 +00--0-----000010 11111001001111000 +----1-----0000-- 01111001001000010 +----100001010111 11001001101010110 +01--110-1-0100-0 10110001101010110 +----1-----000111 11111010001010111 +0---11-01-010011 10000001101010110 +----1-----001011 11111010010000101 +0---110---010011 10000001101010110 +0---------101001 11111010000010001 +-----0----011101 11111001100101110 +0---010---010000 01111001000011101 +----0--10-101101 11111001001000010 +----1-----101101 11111001001000110 +0---00010-11100- 01111001000011101 +----11111-010011 10001001101010110 +----0-0001101101 11111001000110101 +----0--111101101 11111001000100010 +----0-----000--0 11101111111111111 +----0-----0010-- 11101111111111111 +----000001-10111 01111001000011101 +----0--110101101 11111001000111100 +----100010010101 11111001101010101 +----100001110111 11001001110100001 +00--1110-0011001 10100001100010100 +----000010010101 01111001000011101 +----------101111 01111111111111111 +----1-----000101 11111001101110101 +0---000-0111100- 01111001000011111 +0---10000111100- 11001001110100101 +00--1110-1011001 11100001100010010 +0---100100111001 11111001101000001 +-------10110011- 11111010100100101 +----1-0---001001 11111010010011110 +0---10010111100- 11111001100111110 +--------0-010010 01111001000110101 +----------10-100 11110111111111111 +0---011---011001 01111001000011101 +----0001-1100000 01111001000011001 +----00011-100000 01111001000011001 +-----1111-11000- 11111010000010011 +0----1--1-11000- 11111010000010011 +0---0111--01-001 01111001000011101 +01--011---01-001 01111001000011101 +----100111100000 11111001010110100 +0---10011110000- 11111001010110100 +----100110100000 11111001010110011 +0---10011010000- 11111001010110011 +0---0001-110000- 01111001000011001 +0---00011-10000- 01111001000011001 +0---10010110000- 11111001100111110 +----100101100000 11111001100111110 +0-----001-1100-0 11111010000010011 +0-----00-11100-0 11111010000010011 +----------101100 10010111111111111 +----------10010- 11011111111111111 +----0-----010010 01111001000110101 +------1---010010 01111001000110101 +-0--------010010 01111001000110101 +-----0----010010 01111001000110101 +0---01--1-010011 01111001000011101 +----01111-010011 01111001000011101 +0---------10001- 11111001001100111 +0---------100011 11111001001100010 +10--------00001- 01111001001000010 +-0--------000011 01111001001000010 +----------10101- 10110111111111111 +----------101011 10000111111111111 +----0--010101101 11111001000110111 +----00-010101101 11111001000110110 +0---1111-101-001 11111001101000110 +01--111--101-001 11111001101000110 +0---1111-001-001 10111001101001000 +01--111--001-001 10111001101001000 +0-0-1111-001110- 10111001101001000 +010-111--001110- 10111001101001000 +0-0-1111-101110- 11111001101000110 +010-111--101110- 11111001101000110 +0-0-0111--01110- 01111001000011101 +010-011---01110- 01111001000011101 +-0----1---001001 01111001000110101 +----1-1---001001 01111001000110101 +0----10-1-1100-- 11111010000010011 +0----10---11000- 11111010000010011 +0---01--1-010000 01111001000011101 +----01111-010000 01111001000011101 +-----1----000-01 01111001001000010 +-----1----0001-1 01111001001000010 diff --git a/espresso/examples/indust/in2 b/espresso/examples/indust/in2 new file mode 100644 index 0000000..ddf5f35 --- /dev/null +++ b/espresso/examples/indust/in2 @@ -0,0 +1,139 @@ +.i 19 +.o 10 +01-1-0----01-000000 0000010011 +0-----110-----10111 1000000011 +0---1-0011----00010 0000010001 +0--1--0011----00010 0010000000 +01-1-0----0-1000000 0000010001 +01--------101000000 1000001001 +0--1--0100----00010 0010000000 +0---1-0010----00010 0010001001 +0-----11------01100 0000001011 +0---1-0100-----0010 0000010001 +0---1-0111----00100 0000010011 +01-1-0----010100000 0000010100 +0------01-----01100 0000001011 +0--1--0111----00100 0010000000 +0-0---011-0---01100 1100000100 +01-1-0----001100000 0000010010 +0---1-1101----00111 0000010110 +0--1----------00100 0001001011 +0--1--1101----00111 0010000000 +01--------100-00000 1000101000 +0-----011-----10100 1000000100 +0-0---10000---0110- 1100000100 +01--10----0---00000 0001000000 +01-1-1----0---00--- 0001000000 +01-0------0---00000 0010000000 +011-------0---00000 0001000000 +--------------01000 0100000000 +0---1-1000-----0100 0000010011 +0--1--1000----00100 0010000000 +0---1-0110----00100 0010001011 +01---------11000000 0000000100 +0---1-1110-----0111 0000010110 +0-----1-------01011 0000001010 +0---1-0110-----0011 0000010010 +0--1--0110----00011 0010000000 +0--1----------001-1 0001001100 +0-----1-------10011 0000010010 +0-------11----01-11 0000001010 +0---1-1100----00111 0010001110 +0---1-1001----00101 0000010100 +0--1--1110----00111 0010000000 +0-----100-----10101 1000000101 +0--1----------00-11 0001001010 +0-----010-----10011 1000000011 +0---1-0101----00011 0000010010 +0--1--0101----00011 0010000000 +1------------------ 0100000000 +0------1------01101 0000001100 +0---1-1000----00101 0010001100 +0--1--0010----00001 0010000000 +0-----001-----10010 1000000010 +0---------1---01001 1000101000 +0-----1-------10010 0000010001 +0-0---01000---0101- 1100000010 +0-------11----01001 0000101000 +0---1-0000----00001 0010101000 +0-0---001-0---01010 1100000010 +0------11-----01-10 0000001001 +0-----1-------01010 0000001001 +0-1-----------01-10 0000001001 +0---1-0010-----0001 0000110000 +0---1-1100-----0110 0000010101 +0--1--1100----00110 0010000000 +0---1-1010----00110 0010001101 +0---1-1011----00110 0000010101 +0--1--1011----00110 0010000000 +0---1-1010-----0101 0000010100 +0--1----------00001 0001101000 +0-----101-----10110 1000000010 +0-----000-----10001 1000000001 +0-0---11000---0111- 1100000010 +0---1-0001----00001 0000110000 +0-0---101-0---01110 1100000010 +0--1--0001----00001 0010000000 +0-------11----011-1 0000001100 +0-----0-------10110 0000010001 +0-------------0111- 0000000100 +0-------1-----101-1 0000010100 +0-------------10-11 0000000010 +0--1--1001----00101 0010000000 +0-------------1011- 0000000100 +0---1-0100----00011 0010001010 +0--1--1010----00101 0010000000 +0---------1---01-10 0000001001 +01---1-----1-000000 0000001011 +01---1-----10100000 0000001100 +01---1-----01100000 0000001010 +0------0------01-11 0000001010 +0-------0-----10100 0000010011 +0------1------01001 0000101000 +0-------1-----10001 0000110000 +0--1-----------011- 0000000100 +0--1----------00-10 0001001001 +0------1------10-10 0000010001 +0-------0-----10-10 0000010001 +0------00-----01-10 0000001001 +0-------01----01-10 0000001001 +0-0---00-00---01001 1100000001 +0-0---000-0---01001 1100000001 +0-0---100-0---01101 1100000101 +0-0---10-00---01101 1100000101 +0-----0-------101-1 0000010100 +0------1------10101 0000010100 +0---------1---011-1 0000001100 +0-1-----------011-1 0000001100 +0-----1-------10001 0000110000 +0------1------10001 0000110000 +0-1-----------01001 0000101000 +0-----1-------01001 0000101000 +01-0--------1000000 0000001001 +01---1-----01000000 0000001001 +0-------1-----10-11 0000010010 +0------0------10-11 0000010010 +0-1-----------01100 0000001011 +0---------1---01100 0000001011 +01-0-------00-00000 0000101000 +01---1-----00-00000 0000101000 +0-0---010-0---01011 1100000011 +0-0---01-00---01011 1100000011 +0------0------10100 0000010011 +0-----1-------10100 0000010011 +0---------1---01-11 0000001010 +0-1-----------01-11 0000001010 +01--------101100000 0000001010 +01-0-------01100000 0000001010 +01--------110100000 0000001100 +01-0-------10100000 0000001100 +0-------01----01100 0000001011 +0-----0-0-----01100 0000001011 +0-0---11-00---01111 1100000011 +0-0---110-0---01111 1100000011 +0-------------01-11 0000000010 +0-----0-------011-1 0000001100 +01--------11-000000 0000001011 +01-0-------1-000000 0000001011 +0-----0-------01110 0000001001 +0---------1---01010 1000001001 diff --git a/espresso/examples/indust/in3 b/espresso/examples/indust/in3 new file mode 100644 index 0000000..c2912a4 --- /dev/null +++ b/espresso/examples/indust/in3 @@ -0,0 +1,77 @@ +.i 35 +.o 29 +0110--0000-------0---------0----000 01110000000000010010000000000 +0110----------0--00-----1--0----100 00001000000010110010100000001 +011010--------1--00-----1--0----100 00001000000010110010100000100 +0110--0000-------0---------1-----00 01110000000000010010000000000 +1100--0010-------0-------0-------00 10100000101011010000000000000 +0110--0--01------0---------------00 01110000000000010000000000000 +0110--0--1-------0---------------00 01110000000000010010000000000 +0110---01--------0---------------00 01110000000000010010000000000 +1100--1----------0---------------00 10100000101011011000000000000 +0110--1----------0---------------00 01110000000000010010000000000 +1100----11-----------------------00 10100000101011010000000000000 +0110----0------------------------00 00000000000000100000000000000 +0110----1--------0---------------00 00000000000010000000000000000 +1100-------------1--------1-1-----0 10100000101011010000000000000 +0110-------------1----------1-----0 00000000000000000010000000000 +0000------------------1-----------0 10100001101011000000000000000 +0110-------------1----------------0 01110000000010010000000000000 +0000----------------00------------1 00000000000000000000000100000 +1100------------------------------1 11010000000000100000001000000 +0110------------------------------1 00000100000000100011000000001 +1100-------------0---------------10 11010000000000100000001000000 +0110-------------0---------------10 00000100000000100011000000001 +010---------------------------1-0-- 00000000000000010000000000000 +010---000-------10---------0-10-1-- 00000000000000000000001000000 +0000--000--10-0010--010----0-11-1-- 00000000000000000000001000000 +0000--000--00-0-10--010----0-11-1-- 00000000000000000000001000000 +0000--000-----0010--1-0----0-11-1-- 00000000000000000000001000000 +0000--000--00-0-10--1-0----0-11-1-- 00000000000000000000001000000 +001---000-------10-----0---0--1-1-- 00000000000000000000001000000 +011011--------1--00-----1--0----100 00000100000000100011000000001 +0110-------------01-----1--0----100 00000100000000100011000000001 +01100---------1--00-----1--0----100 00000100000000100011000000001 +010---000------------------0----1-- 00000000000000000000000000001 +1010-------------------------110--- 00000000100010000000000000000 +010--------------------------00---- 01000000000000110000000001000 +010--------------------------10---- 01000000000000110000000010000 +1010--------------------------0---- 10100000101010000000000011000 +1011--------------------------0---- 10110000010010000000000010000 +1010----------1--0-0---------11---- 00000000000000000000001000000 +1010-------------------------11---- 10110000010000000000000000000 +1101------------------------------- 00000100000000100001000000011 +010---000---------------------1---- 00000100000000000000010000000 +101-------------------------------- 00000000100000010000000000000 +1011--------------------------1---- 11100000010000000000000000000 +010----0-------------------0--1---- 01100000010000100000000000000 +0000-----------------10------0----- 00000000000010010000100001000 +0000----------------100------0----- 00000000000010010000000001000 +1010-------------------------0----- 10100000001010000000000011000 +-00-------------------------------- 00000000000000100000000000000 +010-----1-------------------------- 00000000000010010000000000000 +-001---1--------1------------------ 00000000000000000000001000000 +-001------0------------------------ 00000100000000000001000000001 +1100--001--------0-------1--------- 11010000000000100000001000000 +101---1----------0----------------- 00000000000000001000000000000 +1000---0--0-----1------------------ 00000000000000000000001000000 +111----------------1--------------- 00000010000000100001000000001 +-001------1------------------------ 00010000000000010000000000000 +010-----0--------1----------------- 00000000000010000000000000000 +001-----0--------0----------------- 01000001001000110000000000000 +0111----01-------0----------------- 10000000000000110000000000000 +0111----00-------0----------------- 10000000000000110100000000000 +111--------------0-0--------------- 00000100000000100001000000001 +111--------------1-0--------------- 00000100000000100001000000011 +1100-------------1--------0-1------ 11010000000000100000000000000 +1100-------------1----------0------ 11010000000000100000000000000 +0111----0--------1----------------- 11000000000010010100000000000 +0111----1-------------------------- 11000000000010010100000000000 +0000----------------100------1----- 00100000000110010000000000000 +0000-----------------10------1----- 00100000000110010000000000000 +1000------1------------------------ 00000000000000000000001000000 +1000------------------------------- 00010000000000010000000000000 +001-----1--------0----------------- 01000001001010110000000000000 +001--------------1----------------- 01000001001010110000000000000 +010----1-------------------0--1---- 01100000010000110000000000000 +010------------------------1--1---- 01100000010000110000000000000 diff --git a/espresso/examples/indust/in4 b/espresso/examples/indust/in4 new file mode 100644 index 0000000..bfff039 --- /dev/null +++ b/espresso/examples/indust/in4 @@ -0,0 +1,236 @@ +.i 32 +.o 20 +-1 --- ---- ------ - ---- --- ------ --- 0 1111 00000 00 00 000000 +10 --- ---1 ------ - ---- --- 1----- --- 0 0000 00000 00 00 100000 +10 --- ---- ------ - ---- --- 1-1--- --- 0 0000 00000 00 00 100000 +10 --- ---- ------ - ---- --- 1---0- --- 0 0000 00000 00 00 100000 +10 1-- 0-1- ------ - ---- --- --0-0- --- 0 1000 10000 00 00 000000 +10 1-- 0--- ------ - ---- --- --0-0- 0-- 0 1000 10000 00 00 000000 +10 1-- 0--- ------ - ---- --- 0-0-0- --- 0 1000 10000 00 00 000000 +10 10- 1--- ------ - ---- --- --0-0- --- 0 1000 10000 00 00 000000 +10 1-- 0-1- 1----- - ---- --- --0-0- --- 0 0000 00000 00 01 000000 +10 1-- 0--- 1----- - ---- --- --0-0- 0-- 0 0000 00000 00 01 000000 +10 1-- 0--- 1----- - ---- --- 0-0-0- --- 0 0000 00000 00 01 000000 +10 10- 1--- 1----- - ---- --- --0-0- --- 0 0000 00000 00 01 000000 +-0 -1- 1--- ------ - ---- --- --0-0- --0 1 1000 00000 00 00 000000 +-0 -1- 1-1- ------ - ---- --- --0-0- --- 1 1000 00000 00 00 000000 +-0 010 0--- ------ - ---- --- --0-0- --0 1 1000 00000 00 00 000000 +-0 010 0-1- ------ - ---- --- --0-0- --- 1 1000 00000 00 00 000000 +-0 010 00-- ------ - ---- --- --0-0- --- 1 1000 00000 00 00 000000 +-0 -1- 1--- ------ - 0-00 --- --0-0- --0 0 0000 00010 00 00 000000 +-0 -1- 1-1- ------ - 0-00 --- --0-0- --- 0 0000 00010 00 00 000000 +-0 010 0--- ------ - 0-00 --- --0-0- --0 0 0000 00010 00 00 000000 +-0 010 0-1- ------ - 0-00 --- --0-0- --- 0 0000 00010 00 00 000000 +-0 010 00-- ------ - 0-00 --- --0-0- --- 0 0000 00010 00 00 000000 +-0 -1- 1--- ------ - 0-00 00- --0-0- --0 0 0000 00000 00 01 000000 +-0 -1- 1-1- ------ - 0-00 00- --0-0- --- 0 0000 00000 00 01 000000 +-0 010 0--- ------ - 0-00 00- --0-0- --0 0 0000 00000 00 01 000000 +-0 010 0-1- ------ - 0-00 00- --0-0- --- 0 0000 00000 00 01 000000 +-0 010 00-- ------ - 0-00 00- --0-0- --- 0 0000 00000 00 01 000000 +00 -1- 1--- ------ 0 0001 --- --0-0- --0 0 0000 00010 00 00 000000 +00 -1- 1-1- ------ 0 0001 --- --0-0- --- 0 0000 00010 00 00 000000 +00 010 0--- ------ 0 0001 --- --0-0- --0 0 0000 00010 00 00 000000 +00 010 0-1- ------ 0 0001 --- --0-0- --- 0 0000 00010 00 00 000000 +00 010 00-- ------ 0 0001 --- --0-0- --- 0 0000 00010 00 00 000000 +00 -1- 1--- ------ 0 0001 00- --0-0- --0 0 0000 00000 00 01 000000 +00 -1- 1-1- ------ 0 0001 00- --0-0- --- 0 0000 00000 00 01 000000 +00 010 0--- ------ 0 0001 00- --0-0- --0 0 0000 00000 00 01 000000 +00 010 0-1- ------ 0 0001 00- --0-0- --- 0 0000 00000 00 01 000000 +00 010 00-- ------ 0 0001 00- --0-0- --- 0 0000 00000 00 01 000000 +00 -1- 1--- ------ 1 0001 --- --0-0- --0 0 0000 00000 01 01 000000 +00 -1- 1-1- ------ 1 0001 --- --0-0- --- 0 0000 00000 01 01 000000 +00 010 0--- ------ 1 0001 --- --0-0- --0 0 0000 00000 01 01 000000 +00 010 0-1- ------ 1 0001 --- --0-0- --- 0 0000 00000 01 01 000000 +00 010 00-- ------ 1 0001 --- --0-0- --- 0 0000 00000 01 01 000000 +00 -1- 1--- ------ - 0010 --- --0-0- --0 0 0000 00000 00 01 000000 +00 -1- 1-1- ------ - 0010 --- --0-0- --- 0 0000 00000 00 01 000000 +00 010 0--- ------ - 0010 --- --0-0- --0 0 0000 00000 00 01 000000 +00 010 0-1- ------ - 0010 --- --0-0- --- 0 0000 00000 00 01 000000 +00 010 00-- ------ - 0010 --- --0-0- --- 0 0000 00000 00 01 000000 +00 -1- 1--- ------ - 0011 --- --0-0- --0 0 0000 00000 10 01 000000 +00 -1- 1-1- ------ - 0011 --- --0-0- --- 0 0000 00000 10 01 000000 +00 010 0--- ------ - 0011 --- --0-0- --0 0 0000 00000 10 01 000000 +00 010 0-1- ------ - 0011 --- --0-0- --- 0 0000 00000 10 01 000000 +00 010 00-- ------ - 0011 --- --0-0- --- 0 0000 00000 10 01 000000 +-0 -1- 1--- ------ - 0110 --- --0-0- --0 0 0000 00000 00 01 000000 +-0 -1- 1-1- ------ - 0110 --- --0-0- --- 0 0000 00000 00 01 000000 +-0 010 0--- ------ - 0110 --- --0-0- --0 0 0000 00000 00 01 000000 +-0 010 0-1- ------ - 0110 --- --0-0- --- 0 0000 00000 00 01 000000 +-0 010 00-- ------ - 0110 --- --0-0- --- 0 0000 00000 00 01 000000 +00 -1- 1--- ------ - 1010 --- --0-0- --0 0 0000 00000 00 01 000000 +00 -1- 1-1- ------ - 1010 --- --0-0- --- 0 0000 00000 00 01 000000 +00 010 0--- ------ - 1010 --- --0-0- --0 0 0000 00000 00 01 000000 +00 010 0-1- ------ - 1010 --- --0-0- --- 0 0000 00000 00 01 000000 +00 010 00-- ------ - 1010 --- --0-0- --- 0 0000 00000 00 01 000000 +10 --1 0-1- ------ - ---- --- --0-0- --- 0 1000 00001 00 01 000000 +10 --1 0--- ------ - ---- --- --0-0- -0- 0 1000 00001 00 01 000000 +10 --1 0--- ------ - ---- --- 0-0-0- --- 0 1000 00001 00 01 000000 +10 -01 1--- ------ - ---- --- --0-0- --- 0 1000 00001 00 01 000000 +10 --1 0-1- --0--- - ---- --- --0-0- --- 0 0000 00100 00 01 000000 +10 --1 0--- --0--- - ---- --- --0-0- -0- 0 0000 00100 00 01 000000 +10 --1 0--- --0--- - ---- --- 0-0-0- --- 0 0000 00100 00 01 000000 +10 -01 1--- --0--- - ---- --- --0-0- --- 0 0000 00100 00 01 000000 +10 -1- ---- 1----- - 0-00 00- --0-1- --- 1 0000 00010 00 01 000000 +10 -1- ---- 1----- - 0110 --- --0-1- --- 1 0000 00000 00 01 000000 +10 --1 ---- ------ - 0-00 00- --0-1- --- 1 0000 00010 00 01 000000 +10 --1 ---- ------ - 0110 --- --0-1- --- 1 0000 00000 00 01 000000 +10 1-- 0-11 ------ - ---- --- --0-1- --- 0 1000 10000 00 00 000000 +10 1-- 0--1 ------ - ---- --- --0-1- 0-- 0 1000 10000 00 00 000000 +10 1-- 0--1 ------ - ---- --- 0-0-1- --- 0 1000 10000 00 00 000000 +10 10- 1--1 ------ - ---- --- --0-1- --- 0 1000 10000 00 00 000000 +10 1-- 0-11 1----- - ---- --- --0-1- --- 0 0000 00000 00 01 000000 +10 1-- 0--1 1----- - ---- --- --0-1- 0-- 0 0000 00000 00 01 000000 +10 1-- 0--1 1----- - ---- --- 0-0-1- --- 0 0000 00000 00 01 000000 +10 10- 1--1 1----- - ---- --- --0-1- --- 0 0000 00000 00 01 000000 +10 --1 0-11 ------ - ---- --- --0-1- --- 0 1000 00001 00 01 000000 +10 --1 0--1 ------ - ---- --- --0-1- -0- 0 1000 00001 00 01 000000 +10 --1 0--1 ------ - ---- --- 0-0-1- --- 0 1000 00001 00 01 000000 +10 -01 1--1 ------ - ---- --- --0-1- --- 0 1000 00001 00 01 000000 +10 --1 0-11 --0--- - ---- --- --0-1- --- 0 0000 00100 00 01 000000 +10 --1 0--1 --0--- - ---- --- --0-1- -0- 0 0000 00100 00 01 000000 +10 --1 0--1 --0--- - ---- --- 0-0-1- --- 0 0000 00100 00 01 000000 +10 -01 1--1 --0--- - ---- --- --0-1- --- 0 0000 00100 00 01 000000 +10 1-- 0-0- ------ - ---- --- 1-0-0- 1-- 0 0000 01000 00 10 000010 +10 1-- 0-0- 1----- - ---- --- 1-0-0- 1-- 0 1000 00000 00 00 000000 +10 1-- 0-0- -1-000 - ---- --- 1-0-0- 1-- 0 0000 00000 00 01 000000 +-0 -1- 1-0- ------ - ---- --- --0-0- --1 0 0010 00000 00 10 000000 +-0 010 010- ------ - ---- --- --0-0- --1 0 0010 00000 00 10 000000 +-0 -1- 1-0- ------ - 0-00 000 --0-0- --1 0 1000 00000 00 00 000000 +-0 010 010- ------ - 0-00 000 --0-0- --1 0 1000 00000 00 00 000000 +00 -1- 1-0- ------ 0 0001 000 --0-0- --1 0 1000 00000 00 00 000000 +00 010 010- ------ 0 0001 000 --0-0- --1 0 1000 00000 00 00 000000 +00 -1- 1-0- ------ 1 0001 --- --0-0- --1 0 1000 00000 00 00 000000 +00 010 010- ------ 1 0001 --- --0-0- --1 0 1000 00000 00 00 000000 +00 -1- 1-0- ------ - 001- --- --0-0- --1 0 1000 00000 00 00 000000 +00 010 010- ------ - 001- --- --0-0- --1 0 1000 00000 00 00 000000 +-0 -1- 1-0- ------ - 0110 --- --0-0- --1 0 1000 00000 00 00 000000 +-0 010 010- ------ - 0110 --- --0-0- --1 0 1000 00000 00 00 000000 +00 -1- 1-0- ------ - 1010 --- --0-0- --1 0 1000 00000 00 00 000000 +00 010 010- ------ - 1010 --- --0-0- --1 0 1000 00000 00 00 000000 +10 --1 0-0- ------ - ---- --- 1-0-0- -1- 0 1000 00000 00 10 000010 +-0 000 ---- ------ - ---- --- --0-0- --- 0 1000 00000 00 00 000000 +10 1-- 0-1- ------ - ---- --- --1000 --- 0 1000 10000 00 00 000000 +10 1-- 0--- ------ - ---- --- --1000 0-- 0 1000 10000 00 00 000000 +10 1-- 0--- ------ - ---- --- 0-1000 --- 0 1000 10000 00 00 000000 +10 10- 1--- ------ - ---- --- --1000 --- 0 1000 10000 00 00 000000 +10 1-- 0-1- 1----- - ---- --- --1000 --- 0 0000 00000 00 01 000000 +10 1-- 0--- 1----- - ---- --- --1000 0-- 0 0000 00000 00 01 000000 +10 1-- 0--- 1----- - ---- --- 0-1000 --- 0 0000 00000 00 01 000000 +10 10- 1--- 1----- - ---- --- --1000 --- 0 0000 00000 00 01 000000 +-0 -1- 1--- ------ - ---- --- --1000 --0 1 1000 00000 00 00 000000 +-0 -1- 1-1- ------ - ---- --- --1000 --- 1 1000 00000 00 00 000000 +-0 010 0--- ------ - ---- --- --1000 --0 1 1000 00000 00 00 000000 +-0 010 0-1- ------ - ---- --- --1000 --- 1 1000 00000 00 00 000000 +-0 010 00-- ------ - ---- --- --1000 --- 1 1000 00000 00 00 000000 +-0 -1- 1--- ------ - 0-00 --- --1000 --0 0 0000 00010 00 00 000000 +-0 -1- 1-1- ------ - 0-00 --- --1000 --- 0 0000 00010 00 00 000000 +-0 010 0--- ------ - 0-00 --- --1000 --0 0 0000 00010 00 00 000000 +-0 010 0-1- ------ - 0-00 --- --1000 --- 0 0000 00010 00 00 000000 +-0 010 00-- ------ - 0-00 --- --1000 --- 0 0000 00010 00 00 000000 +-0 -1- 1--- ------ - 0-00 00- --1000 --0 0 0000 00000 00 01 000000 +-0 -1- 1-1- ------ - 0-00 00- --1000 --- 0 0000 00000 00 01 000000 +-0 010 0--- ------ - 0-00 00- --1000 --0 0 0000 00000 00 01 000000 +-0 010 0-1- ------ - 0-00 00- --1000 --- 0 0000 00000 00 01 000000 +-0 010 00-- ------ - 0-00 00- --1000 --- 0 0000 00000 00 01 000000 +00 -1- 1--- ------ 0 0001 --- --1000 --0 0 0000 00010 00 00 000000 +00 -1- 1-1- ------ 0 0001 --- --1000 --- 0 0000 00010 00 00 000000 +00 010 0--- ------ 0 0001 --- --1000 --0 0 0000 00010 00 00 000000 +00 010 0-1- ------ 0 0001 --- --1000 --- 0 0000 00010 00 00 000000 +00 010 00-- ------ 0 0001 --- --1000 --- 0 0000 00010 00 00 000000 +00 -1- 1--- ------ 0 0001 00- --1000 --0 0 0000 00000 00 01 000000 +00 -1- 1-1- ------ 0 0001 00- --1000 --- 0 0000 00000 00 01 000000 +00 010 0--- ------ 0 0001 00- --1000 --0 0 0000 00000 00 01 000000 +00 010 0-1- ------ 0 0001 00- --1000 --- 0 0000 00000 00 01 000000 +00 010 00-- ------ 0 0001 00- --1000 --- 0 0000 00000 00 01 000000 +00 -1- 1--- ------ 1 0001 --- --1000 --0 0 0000 00000 01 01 000000 +00 -1- 1-1- ------ 1 0001 --- --1000 --- 0 0000 00000 01 01 000000 +00 010 0--- ------ 1 0001 --- --1000 --0 0 0000 00000 01 01 000000 +00 010 0-1- ------ 1 0001 --- --1000 --- 0 0000 00000 01 01 000000 +00 010 00-- ------ 1 0001 --- --1000 --- 0 0000 00000 01 01 000000 +00 -1- 1--- ------ - 0010 --- --1000 --0 0 0000 00000 00 01 000000 +00 -1- 1-1- ------ - 0010 --- --1000 --- 0 0000 00000 00 01 000000 +00 010 0--- ------ - 0010 --- --1000 --0 0 0000 00000 00 01 000000 +00 010 0-1- ------ - 0010 --- --1000 --- 0 0000 00000 00 01 000000 +00 010 00-- ------ - 0010 --- --1000 --- 0 0000 00000 00 01 000000 +00 -1- 1--- ------ - 0011 --- --1000 --0 0 0000 00000 10 01 000000 +00 -1- 1-1- ------ - 0011 --- --1000 --- 0 0000 00000 10 01 000000 +00 010 0--- ------ - 0011 --- --1000 --0 0 0000 00000 10 01 000000 +00 010 0-1- ------ - 0011 --- --1000 --- 0 0000 00000 10 01 000000 +00 010 00-- ------ - 0011 --- --1000 --- 0 0000 00000 10 01 000000 +-0 -1- 1--- ------ - 0110 --- --1000 --0 0 0000 00000 00 01 000000 +-0 -1- 1-1- ------ - 0110 --- --1000 --- 0 0000 00000 00 01 000000 +-0 010 0--- ------ - 0110 --- --1000 --0 0 0000 00000 00 01 000000 +-0 010 0-1- ------ - 0110 --- --1000 --- 0 0000 00000 00 01 000000 +-0 010 00-- ------ - 0110 --- --1000 --- 0 0000 00000 00 01 000000 +00 -1- 1--- ------ - 1010 --- --1000 --0 0 0000 00000 00 01 000000 +00 -1- 1-1- ------ - 1010 --- --1000 --- 0 0000 00000 00 01 000000 +00 010 0--- ------ - 1010 --- --1000 --0 0 0000 00000 00 01 000000 +00 010 0-1- ------ - 1010 --- --1000 --- 0 0000 00000 00 01 000000 +00 010 00-- ------ - 1010 --- --1000 --- 0 0000 00000 00 01 000000 +10 --1 0-1- ------ - ---- --- --1000 --- 0 1000 00001 00 01 000000 +10 --1 0--- ------ - ---- --- --1000 -0- 0 1000 00001 00 01 000000 +10 --1 0--- ------ - ---- --- 0-1000 --- 0 1000 00001 00 01 000000 +10 -01 1--- ------ - ---- --- --1000 --- 0 1000 00001 00 01 000000 +10 --1 0-1- --0--- - ---- --- --1000 --- 0 0000 00100 00 01 000000 +10 --1 0--- --0--- - ---- --- --1000 -0- 0 0000 00100 00 01 000000 +10 --1 0--- --0--- - ---- --- 0-1000 --- 0 0000 00100 00 01 000000 +10 -01 1--- --0--- - ---- --- --1000 --- 0 0000 00100 00 01 000000 +00 010 -10- ------ 0 0001 000 --0-0- --1 0 1010 00000 00 10 000000 +00 010 -10- ------ 0 0001 001 --0-0- --1 0 1010 00010 00 10 011000 +00 010 -10- ------ 0 0001 010 --0-0- --1 0 0010 00010 00 11 011001 +00 010 -10- ------ 0 0001 011 --0-0- --1 0 0010 00010 00 10 011010 +00 010 -10- ------ 0 0001 100 --0-0- --1 0 0010 00010 00 10 011011 +00 010 -10- ------ 0 0001 101 --0-0- --1 0 0010 00010 00 10 011100 +00 010 -10- ------ 0 0001 110 --0-0- --1 0 0010 00010 00 10 011101 +00 010 -10- ------ 0 0001 111 --0-0- --1 0 0010 00010 00 10 011110 +-0 010 -10- ------ - 0-00 000 --0-0- --1 0 1010 00000 00 10 000000 +00 010 -10- ------ - 0-00 001 --0-0- --1 0 1010 00010 00 10 011000 +00 010 -10- ------ - 0-00 010 --0-0- --1 0 0010 00010 00 11 011001 +00 010 -10- ------ - 0-00 011 --0-0- --1 0 0010 00010 00 10 011010 +00 010 -10- ------ - 0-00 100 --0-0- --1 0 0010 00010 00 10 011011 +00 010 -10- ------ - 0-00 101 --0-0- --1 0 0010 00010 00 10 011100 +00 010 -10- ------ - 0-00 110 --0-0- --1 0 0010 00010 00 10 011101 +00 010 -10- ------ - 0-00 111 --0-0- --1 0 0010 00010 00 10 011110 +00 -1- 1-0- ------ 0 0001 000 --0-0- --1 0 1010 00000 00 10 000000 +00 -1- 1-0- ------ 0 0001 001 --0-0- --1 0 1010 00010 00 10 011000 +00 -1- 1-0- ------ 0 0001 010 --0-0- --1 0 0010 00010 00 11 011001 +00 -1- 1-0- ------ 0 0001 011 --0-0- --1 0 0010 00010 00 10 011010 +00 -1- 1-0- ------ 0 0001 100 --0-0- --1 0 0010 00010 00 10 011011 +00 -1- 1-0- ------ 0 0001 101 --0-0- --1 0 0010 00010 00 10 011100 +00 -1- 1-0- ------ 0 0001 110 --0-0- --1 0 0010 00010 00 10 011101 +00 -1- 1-0- ------ 0 0001 111 --0-0- --1 0 0010 00010 00 10 011110 +-0 -1- 1-0- ------ - 0-00 000 --0-0- --1 0 1010 00000 00 10 000000 +00 -1- 1-0- ------ - 0-00 001 --0-0- --1 0 1010 00010 00 10 011000 +00 -1- 1-0- ------ - 0-00 010 --0-0- --1 0 0010 00010 00 11 011001 +00 -1- 1-0- ------ - 0-00 011 --0-0- --1 0 0010 00010 00 10 011010 +00 -1- 1-0- ------ - 0-00 100 --0-0- --1 0 0010 00010 00 10 011011 +00 -1- 1-0- ------ - 0-00 101 --0-0- --1 0 0010 00010 00 10 011100 +00 -1- 1-0- ------ - 0-00 110 --0-0- --1 0 0010 00010 00 10 011101 +00 -1- 1-0- ------ - 0-00 111 --0-0- --1 0 0010 00010 00 10 011110 +10 1-- ---0 1----- - ---- --- --0-1- --- 0 1100 00000 00 10 000000 +10 1-- ---0 -1-000 - ---- --- --0-1- --- 0 1100 00100 00 10 001000 +10 1-- ---0 -1-001 - ---- --- --0-1- --- 0 0100 00100 00 11 001001 +10 1-- ---0 -1-010 - ---- --- --0-1- --- 0 0100 00100 00 10 001010 +10 1-- ---0 -1-011 - ---- --- --0-1- --- 0 0100 00100 00 10 001011 +10 1-- ---0 -1-100 - ---- --- --0-1- --- 0 0100 00100 00 10 001100 +10 1-- ---0 -1-101 - ---- --- --0-1- --- 0 0100 00100 00 10 001101 +10 1-- ---0 -1-110 - ---- --- --0-1- --- 0 0100 00100 00 10 001110 +10 1-- ---0 -1-111 - ---- --- --0-1- --- 0 0100 00100 00 10 001111 +10 --1 ---0 ------ - ---- --- --0-1- --- 0 1001 00000 00 00 000000 +10 --- ---1 ------ - ---- --- --0-1- --- 0 1000 00000 00 00 000000 +10 --- ---- ------ - ---- --- -01000 --- 0 1000 00000 00 10 000000 +10 --- ---- ------ - ---- --- -01001 --- 0 1000 00100 00 10 001000 +10 --- ---- ------ - ---- --- -01010 --- 0 0000 00100 00 11 001001 +10 --- ---- ------ - ---- --- -01011 --- 0 0000 00100 00 10 001010 +10 --- ---- ------ - ---- --- -01100 --- 0 0000 00100 00 10 001011 +10 --- ---- ------ - ---- --- -01101 --- 0 0000 00100 00 10 001100 +10 --- ---- ------ - ---- --- -01110 --- 0 0000 00100 00 10 001101 +10 --- ---- ------ - ---- --- -01111 --- 0 0000 00100 00 10 001110 +00 --- ---- ------ - ---- --- -11000 --- 0 1000 00000 00 10 000000 +00 --- ---- ------ - ---- --- -11001 --- 0 1000 00010 00 10 011000 +00 --- ---- ------ - ---- --- -11010 --- 0 0000 00010 00 11 011001 +00 --- ---- ------ - ---- --- -11011 --- 0 0000 00010 00 10 011010 +00 --- ---- ------ - ---- --- -11100 --- 0 0000 00010 00 10 011011 +00 --- ---- ------ - ---- --- -11101 --- 0 0000 00010 00 10 011100 +00 --- ---- ------ - ---- --- -11110 --- 0 0000 00010 00 10 011101 +00 --- ---- ------ - ---- --- -11111 --- 0 0000 00000 00 00 010000 diff --git a/espresso/examples/indust/in5 b/espresso/examples/indust/in5 new file mode 100644 index 0000000..ad94237 --- /dev/null +++ b/espresso/examples/indust/in5 @@ -0,0 +1,64 @@ +.i 24 +.o 14 +011--1-------1--0-0----1 00000000100000 +101-----1----1---------- 00000000000010 +100010-------10111------ 01001100010000 +0110-1-------1011-0----1 00000000010000 +1000--1------1---------- 01100010100000 +0111-1-------1111-0----1 00000000010000 +-------------0-----0100- 00100000000000 +1000----1----1---------- 00000010000000 +-------------0-----1110- 00010000000000 +-------------0-----0001- 01000000000000 +-------------0-----1101- 01000000000000 +1-00----1----1---------- 00000000100010 +-------------0-----1011- 00010000000000 +-001---1-0---1---------- 11100010100000 +-00110---0---11111------ 11001100010000 +011011-------1011------- 01010100010000 +1000-----1---1---------- 01100010000100 +001-10----1--101100----- 01000101011000 +100010-------101100----- 01000101010000 +1011----1--1-1---------- 00010000000000 +010-10----11-111100----- 11000101011000 +-00110---0---111100----- 11000101010000 +011111-------1-0-00----- 11110000100000 +-----0---------1-00----- 00000000000001 +0111-1-1-----1---00----- 11110000100000 +0110-11------1---00----- 01110000100000 +010-10----11-11111------ 11001100011000 +001-10----1--10111------ 01001100011000 +0111-1-1-----1-1-1------ 11010000010000 +0110-11------1-1-1------ 01010000010000 +011-11-------1-101------ 00100100010000 +010-10----11-1-0--0----- 11101000101000 +-00110---0---1-0--0----- 11101000100000 +------------1-----1----- 00001101000000 +0110-11------1-0-1------ 00110000010000 +011111-------101-1------ 10100100010000 +011-11-------100-00----- 01110000100000 +011111-------10--00----- 01110000100000 +011--1-------100--0----1 00000000100000 +011111-------1-1--0----- 10000100000000 +001-10----1--1--0------- 01101000101000 +100010-------1--0------- 01101000100000 +011-11-------1-001------ 00110000010000 +011-11-------100-1------ 00110000010000 +011111-------1-0-1------ 10110000010000 +0111-1-1-----1-0-1------ 10110000010000 +-00110---0---1-10-0----- 11101101100000 +-00110---0---101--0----- 11101101100000 +011-11-------1-10-0----- 00000100000000 +011-11-------1--000----- 01110000100000 +010-10----11-1-10-0----- 11101101101000 +010-10----11-101--0----- 11101101101000 +100010-------100-------- 01101000100000 +100010-------1-10------- 01101101100000 +001-10----1--100-------- 01101000101000 +001-10----1--1-10------- 01101101101000 +-------------0-----001-- 00100000000000 +-------------0-----0011- 10100000000000 +011111-------1-101------ 10100100010000 +011111-------1111-0----- 01010000010000 +0111-1-------1-0--0----1 00000000100000 +0111-1-------10---0----1 00000000100000 diff --git a/espresso/examples/indust/in6 b/espresso/examples/indust/in6 new file mode 100644 index 0000000..161e408 --- /dev/null +++ b/espresso/examples/indust/in6 @@ -0,0 +1,56 @@ +.i 33 +.o 23 +1------1------------------------- 00010001111001000110100 +0---0---------------------------1 01000000000000000000000 +01--------------------1-----1-10- 10000000000000000000000 +0--------------00--------------1- 10000000000000000000000 +0--------0100-01010---------0-1-- 00000100110010000000000 +0--1------------------------000-- 00100000000000000000110 +0--------0100--0101---------0-1-- 00000011001100000000000 +0--1------------------------010-- 00110000000000000000010 +------01-0100--1000---------0-1-- 00000000101000000000000 +0--------10-0------111------011-- 00001000000000000001100 +0-----0--0100--0010---------0-1-- 00000010000010000000000 +---1----------------------10----- 00000000000000000010000 +0--------1110------1-1------011-- 00001000000000000001100 +0--------0111--------1------011-- 00001000000000000001100 +0--------1111------11-------011-- 00001000000000000001011 +0----1--------------------------- 00000000000000001000000 +---0-----------------------1----- 00000000000000000010000 +0---------------------1-----1-1-- 00000000000000001000000 +01----1--0011--001-----1----0-1-- 00000010000000000000000 +01-------0011--0011----1------1-- 00000000000100000000000 +01----0-00011--0011----1----0-1-- 00000010000010000000000 +01----1--0011--1-00---1-----0-1-- 00000000001000000000000 +0--------1011------111------011-- 00001000000000000001110 +01-------0011--0000----1----0-1-- 00000010000000000000000 +1------0------------------------- 00010001100111000110100 +01-------------0101---1-----1-1-- 00000001001000000000000 +-1-----------------------1--11--- 00000000000001000000000 +01-----------1--------0-1---11--- 00000000000000100000000 +0--------0100---------------0-1-- 00001000000000000110000 +0--------0010---------------0-1-- 00001000000000000001010 +0--------1101---------------0-1-- 00001000000000000001100 +01----01-------1000----1----1-1-- 00000100000000000000000 +01----0--------0010----1----1-1-- 00000110000000000000000 +01--------------010----1----1-1-- 00000000000010000000000 +01------------01010----1----1-1-- 00000100000000000000000 +01-------------0101----1----1-1-- 00000010000100000000000 +01-------------0011----1----1-1-- 00000000000110000000000 +-1-------------10-0---1-----1-1-- 00000000100000000000000 +-1----01-------1000---1-----1-1-- 00000000011000000000000 +-1-------------1100---1-----1-1-- 00000001100000000000000 +01----0--------0010---1-----1-1-- 00000000010000000000000 +01------------01010---1-----1-1-- 00000000010000000000000 +-1-----1-0011--0000---1-----0-1-- 00000000001000000000000 +01----1--0011---000---1-----0-1-- 00000000001000000000000 +---0------------------------010-- 00000000000000000000100 +--1-------------------------000-- 00000000000000000000100 +--------------------------11----- 00000000000000000100000 +---0----------------------1------ 00000000000000000100000 +0--------10-1------111------011-- 00001000000000000001010 +0--------1-00------111------011-- 00001000000000000001010 +01----------------------1---11--0 01000000000000000000000 +01----------------------1---11--- 00000000000001010000000 +01----0-10011--1100---1-----0-1-- 00000000101000000000000 +-1-------0011--1100---1-------1-- 00000001000000000000000 diff --git a/espresso/examples/indust/in7 b/espresso/examples/indust/in7 new file mode 100644 index 0000000..4c6ad58 --- /dev/null +++ b/espresso/examples/indust/in7 @@ -0,0 +1,86 @@ +.i 26 +.o 10 +0---1----0000--0--01--0-0- 0010000000 +------------------1------1 0100000000 +0-----1--0000--0--01--0-0- 0011000000 +1--1-----------0--010-00-- 0000011000 +---------0000-----01---1-- 0000000010 +0----1---0000--0--01--0-0- 0010100000 +------------------1-0----0 0000010100 +--------------------1--1-- 0000010010 +0-1------------0--010-000- 0000011000 +-0-------1--------01---1-- 0000000010 +--1------0--------01---1-- 0000000010 +------------------1----1-1 0100010010 +0-1------------0--01--0-0- 0001100000 +-0-------1---------1-----1 0100000000 +--1------0---------1-----1 0100000000 +---------0000------1-----1 0100000000 +-------------------1---1-- 0000010000 +0------1-0000--0--01--0-0- 0011100000 +0-0------001---1--01--0-0- 0001000000 +--------0---------0-----1- 0100000000 +--------0----------0-----1 0100000000 +---0---------------0-----1 0100000000 +---0-----------------0--10 0100000000 +---0--------------00---1-- 0000010010 +0-0------01----1--010-0-0- 0000011000 +0-0------010---1--01--0-0- 0010100000 +0-----------------00---1-- 0000010010 +--------0---------00---1-- 0000010010 +0-----1--0000--0--010-000- 0000011000 +0------1-0000--0--010-000- 0000011000 +0---1----0000--0--010-000- 0000011000 +0----1---0000--0--010-000- 0000011000 +-------------------1-0--1- 0100000000 +------------------01----1- 0100000000 +0-0------0--1--1--010-0-0- 0000011000 +0-0------0001--1--01--0-0- 0011100000 +01-------1-----1--010-0-0- 0000011000 +01-------1-----1--01--0-0- 0001100000 +------------------0---11-- 0000010010 +---------------0--0----1-- 0000010010 +------------------1------0 0011000000 +-----------------11------0 0011100000 +0--------------------0--1- 0100000000 +--------0------------0--1- 0100000000 +0------------------0-----1 0100000000 +1------------------1-----1 0100000000 +---------------0---------1 0100000000 +----------------------1--1 0100000000 +0-0------0-1---1--01--0-0- 0010000000 +0-0------0-1---1--010-0-0- 0010011000 +---0--------------0-----1- 0100000000 +0-----------------0-----1- 0100000000 +1-----------------01---1-- 0000010010 +------------------01---11- 0100010010 +------------------0---1--- 0100000000 +-0-------1---------1-0---- 0100000000 +---------0000------1-0---- 0100000000 +1--1-----------0--01--0--- 0001100000 +--1------0---------1-0---- 0100000000 +---0---------------0-0---- 0100000000 +0------------------0-0---- 0100000000 +1--1----1------1--00--0--- 0001100000 +1--1----1------1--000-0--- 0001111000 +---------------0-----0---- 0100000000 +------------------1--0---- 0100000000 +--------0----------0-0---- 0100000000 +1------------------1-0---- 0100000000 +---------------0--0------- 0100000000 +--1------0--------01------ 0100000000 +-0-------1--------01------ 0100000000 +00-------1-----------0---- 0100000000 +---------0000-----01------ 0100000000 +0--------0000--------0---- 0100000000 +---------00001------------ 1000000000 +0-1------0-----------0---- 0100000000 +---------0000-11---------- 1000000000 +----------------1--------- 1000000000 +---------0001------------- 0000000001 +--------0---------00------ 0100000000 +0-----------------00------ 0100000000 +1--0-----------------0---- 0100000000 +1-------0------------0---- 0100000000 +---0--------------00------ 0100000000 +1-----------------01------ 0100000000 diff --git a/espresso/examples/indust/inc b/espresso/examples/indust/inc new file mode 100644 index 0000000..c94fe7c --- /dev/null +++ b/espresso/examples/indust/inc @@ -0,0 +1,36 @@ +.i 7 +.o 9 +00000--|000001000 +00001--|0001--010 +0001-0-|000110000 +0001-1-|001010--0 +0010-00|001010100 +0010-1-|0110101-0 +0010001|001110-00 +0010101|001010100 +0011-0-|001110000 +0011-10|0100100-0 +0011-11|0101100-0 +0100--1|1010--011 +0100-10|001010--1 +0100-00|010010001 +0101-01|010110001 +0101-1-|1001-00-1 +0101-00|010010001 +0110-10|0111-0--1 +0110-00|011010101 +01100-1|010110-01 +0110101|011010101 +0110111|0111-0--1 +0111--1|0111000-0 +0111--0|1000000-0 +1000--0|1000000-0 +10000-1|1001000-0 +10001-1|10100-010 +1001--1|1001000-0 +1001--0|0010-0-10 +1010-0-|101001000 +1010-1-|1011010-0 +1011-0-|101101000 +1011-1-|11000-0-0 +1100---|1100000-0 diff --git a/espresso/examples/indust/intb b/espresso/examples/indust/intb new file mode 100644 index 0000000..6cb6017 --- /dev/null +++ b/espresso/examples/indust/intb @@ -0,0 +1,666 @@ +.i 15 +.o 7 +---0----1111--- 1000000 +---0---0111---- 1000000 +---0--0-11-1--- 1000000 +---0--0011----- 1000000 +---0-0--1-11--- 1000000 +---0-0-01-1---- 1000000 +---0-00-1--1--- 1000000 +---0-0001------ 1000000 +--0-----0000--- 1000000 +--0----0000---- 1000000 +--0---0-00-0--- 1000000 +--0---0000----- 1000000 +--0--0--0-00--- 1000000 +--0--0-00-0---- 1000000 +--0--00-0--0--- 1000000 +--0--0000------ 1000000 +----0000------- 1000000 +--00----------- 1000000 +---00----111--- 1000000 +---00--0-11---- 1000000 +---00-0--1-1--- 1000000 +---00-00-1----- 1000000 +---000----11--- 1000000 +---000-0--1---- 1000000 +---0000----1--- 1000000 +--0-0----000--- 1000000 +--0-0--0-00---- 1000000 +--0-0-0--0-0--- 1000000 +--0-0-00-0----- 1000000 +--0-00----00--- 1000000 +--0-00-0--0---- 1000000 +--0-000----0--- 1000000 +1-------1111--- 0100000 +1---1----111--- 0100000 +1--1-1---111--- 0100000 +1-1--1---011--- 0100000 +1--1--1---11--- 0100000 +1----1--1-11--- 0100000 +1---11----11--- 0100000 +-1-1--1---10--- 0100000 +1------1111---- 0100000 +1---1--1-11---- 0100000 +1--1-1-1-11---- 0100000 +---1--11--1---- 0100000 +1----1-11-1---- 0100000 +1---11-1--1---- 0100000 +1-1---1---01--- 0100000 +-1-1-1---100--- 0100000 +-1------0000--- 0100000 +-1--1----000--- 0100000 +-11--1---000--- 0100000 +-11---1---00--- 0100000 +-1---1--0-00--- 0100000 +-1--11----00--- 0100000 +-1-----1000---- 0100000 +-1--1--1-00---- 0100000 +-11--1-1-00---- 0100000 +--1---11--0---- 0100000 +-1---1-10-0---- 0100000 +-1--11-1--0---- 0100000 +---1---1---1--- 0100000 +--1----1---0--- 0100000 +----1111------- 0100000 +11------------- 0100000 +1-----1-11-1--- 0100000 +1---1-1--1-1--- 0100000 +1--1-11--1-1--- 0100000 +1----11-1--1--- 0100000 +1---111----1--- 0100000 +1-----1111----- 0100000 +---1-111-1----- 0100000 +1---1-11-1----- 0100000 +1----1111------ 0100000 +-1----1-00-0--- 0100000 +-1--1-1--0-0--- 0100000 +-11--11--0-0--- 0100000 +-1---11-0--0--- 0100000 +-1--111----0--- 0100000 +-1----1100----- 0100000 +--1--111-0----- 0100000 +-1--1-11-0----- 0100000 +-1---1110------ 0100000 +1--1---11111-0- 0010000 +1--11--11111--- 0010000 +1--1--1111-1-0- 0010000 +1--11-1111-1--- 0010000 +-1-11--11001--- 0010000 +11-11--11--1--- 0010000 +1--1-1-11-11-0- 0010000 +1--111-11-11--- 0010000 +---111111--1--- 0010000 +1--1-1111--1-0- 0010000 +-1-1---10001-0- 0010000 +1--1-1-1-111--- 0010000 +-1-1-1-1-101--- 0010000 +---1-111-1-1--- 0010000 +---1--11--11--- 0010000 +---1---1---11-- 0010000 +11-1---1---1-0- 0010000 +1--11--1-111-0- 0010000 +1--11-11-1-1-0- 0010000 +1--111-1--11-0- 0010000 +---11111---1-0- 0010000 +---0---1111101- 0010000 +0--00--111110-- 0010000 +---0--0111-101- 0010000 +0--00-0111-10-- 0010000 +---0-0-11-1101- 0010000 +0--000-11-110-- 0010000 +---0-0011--101- 0010000 +0--000011--10-- 0010000 +-0-00--101110-- 0010000 +0--0-0-1-1110-- 0010000 +0--0-001-1-10-- 0010000 +-0-0-0-1-0110-- 0010000 +0--0--01--110-- 0010000 +-0-0--01--010-- 0010000 +---00--1-11101- 0010000 +---00-01-1-101- 0010000 +---000-1--1101- 0010000 +---00001---101- 0010000 +1-0----0000101- 0010000 +100-0--000010-- 0010000 +1-0---0000-101- 0010000 +100-0-0000-10-- 0010000 +1-0--0-00-0101- 0010000 +100-00-00-010-- 0010000 +10--00000--10-- 0010000 +1-0--0000--101- 0010000 +100--0-0-0010-- 0010000 +10---000-0-10-- 0010000 +10----00--010-- 0010000 +1---0000---101- 0010000 +1-0-0--0-00101- 0010000 +1-0-0-00-0-101- 0010000 +1-0-00-0--0101- 0010000 +01-----00001-0- 0010000 +011-1--00001--- 0010000 +01----1000-1-0- 0010000 +011-1-1000-1--- 0010000 +011--1-0-001--- 0010000 +0-1--110-0-1--- 0010000 +01--1--0-001-0- 0010000 +01--1-10-0-1-0- 0010000 +0-1---10--01--- 0010000 +0------0---11-- 0010000 +0---1110---1-0- 0010000 +01---1-00-01-0- 0010000 +011-11-00-01--- 0010000 +01--11-0--01-0- 0010000 +01---1100--1-0- 0010000 +0-1-11100--1--- 0010000 +1--0----111101- 0010000 +1--0--0-11-101- 0010000 +1--0-0--1-1101- 0010000 +1--0-00-1--101- 0010000 +10-00---01110-- 0010000 +10000---0--10-- 0010000 +10-0-0---0110-- 0010000 +1-00-------101- 0010000 +1--00----11101- 0010000 +1--00-0--1-101- 0010000 +1--000----1101- 0010000 +01-1-1---101--- 0010000 +0--1-11--1-1--- 0010000 +01-11---1001--- 0010000 +0--1--1---11--- 0010000 +0--1111-1--1--- 0010000 +1-1----11110-0- 0010000 +1-1-1--10110--- 0010000 +-11----10000-0- 0010000 +-11-1--10000--- 0010000 +-11---1100-0-0- 0010000 +-11-1-1100-0--- 0010000 +111-1--10--0--- 0010000 +-11--1-10-00-0- 0010000 +-11-11-10-00--- 0010000 +--1-11110--0--- 0010000 +-11--1110--0-0- 0010000 +1-1--1-1-010--- 0010000 +-11--1-1-000--- 0010000 +--1--111-0-0--- 0010000 +--1---11--00--- 0010000 +--1----1---01-- 0010000 +111----1---0-0- 0010000 +-11-1--1-000-0- 0010000 +-11-1-11-0-0-0- 0010000 +-11-11-1--00-0- 0010000 +--1-1111---0-0- 0010000 +0-0-0--110000-- 0010000 +--0----1000001- 0010000 +-00-0--100000-- 0010000 +--0---0100-001- 0010000 +-00-0-0100-00-- 0010000 +--0--0-10-0001- 0010000 +-00-00-10-000-- 0010000 +--0--0010--001- 0010000 +-00-00010--00-- 0010000 +0-0--0-1-1000-- 0010000 +-00--0-1-0000-- 0010000 +-00--001-0-00-- 0010000 +0-0---01--100-- 0010000 +-00---01--000-- 0010000 +--0-0--1-00001- 0010000 +--0-0-01-0-001- 0010000 +--0-00-1--0001- 0010000 +--0-0001---001- 0010000 +-1-0---0111001- 0010000 +01-00--011100-- 0010000 +-1-0--0011-001- 0010000 +01-00-0011-00-- 0010000 +-1-0-0-01-1001- 0010000 +01-000-01-100-- 0010000 +01--00001--00-- 0010000 +-1-0-0001--001- 0010000 +01-0-0-0-1100-- 0010000 +01---000-1-00-- 0010000 +01----00--100-- 0010000 +-1--0000---001- 0010000 +-1-00--0-11001- 0010000 +-1-00-00-1-001- 0010000 +-1-000-0--1001- 0010000 +10-----01110-0- 0010000 +10-11--01110--- 0010000 +10----1011-0-0- 0010000 +10-11-1011-0--- 0010000 +10-1-1-0-110--- 0010000 +-0-1-110-1-0--- 0010000 +10--1--0-110-0- 0010000 +10--1-10-1-0-0- 0010000 +-0-1--10--10--- 0010000 +-0-----0---01-- 0010000 +-0--1110---0-0- 0010000 +10---1-01-10-0- 0010000 +10-111-01-10--- 0010000 +10--11-0--10-0- 0010000 +10---1101--0-0- 0010000 +-0-111101--0--- 0010000 +010-0---10000-- 0010000 +01000---1--00-- 0010000 +-10-----000001- 0010000 +-10---0-00-001- 0010000 +-10--0--0-0001- 0010000 +-10--00-0--001- 0010000 +010--0---1000-- 0010000 +-100-------001- 0010000 +-10-0----00001- 0010000 +-10-0-0--0-001- 0010000 +-10-00----0001- 0010000 +101-1---0110--- 0010000 +101--1---010--- 0010000 +-01--11--0-0--- 0010000 +-01---1---00--- 0010000 +-01-111-0--0--- 0010000 +--11--11------- 0010000 +1-11-1-1--1---- 0010000 +-111-1-1--0---- 0010000 +1-111--1-11---- 0010000 +-1111--1-00---- 0010000 +11111--1------- 0010000 +0-000--11---0-- 0010000 +-0000--10---0-- 0010000 +0-00-0-1-1--0-- 0010000 +-000-0-1-0--0-- 0010000 +--00---1----01- 0010000 +1--1--1-111--0- 0001000 +1--11-1-111---- 0001000 +-1-11-1-101---- 0001000 +---1111-1-1---- 0001000 +1--1-11-1-1--0- 0001000 +-1-1--1-001--0- 0001000 +---1-11--11---- 0001000 +---1--1---1-1-- 0001000 +11-1--1---1--0- 0001000 +1--11-1--11--0- 0001000 +---1111---1--0- 0001000 +---0--1-111-01- 0001000 +0--00-1-111-0-- 0001000 +---0-01-1-1-01- 0001000 +0--0001-1-1-0-- 0001000 +-0-00-1-011-0-- 0001000 +0--0-01--11-0-- 0001000 +-0-0-01--01-0-- 0001000 +---00-1--11-01- 0001000 +---0001---1-01- 0001000 +1-0---0-001-01- 0001000 +100-0-0-001-0-- 0001000 +10--000-0-1-0-- 0001000 +1-0--00-0-1-01- 0001000 +10---00--01-0-- 0001000 +1---000---1-01- 0001000 +1-0-0-0--01-01- 0001000 +01----0-001--0- 0001000 +011-1-0-001---- 0001000 +01---10-0-1--0- 0001000 +0-1-110-0-1---- 0001000 +0-1--10--01---- 0001000 +0-----0---1-1-- 0001000 +0---110---1--0- 0001000 +01--1-0--01--0- 0001000 +1--0----111-01- 0001000 +1--0-0--1-1-01- 0001000 +10-00---011-0-- 0001000 +1-00------1-01- 0001000 +1--00----11-01- 0001000 +01-11---101---- 0001000 +0--111--1-1---- 0001000 +0--1-1---11---- 0001000 +1-1---1-110--0- 0001000 +1-1-1-1-010---- 0001000 +-11---1-000--0- 0001000 +-11-1-1-000---- 0001000 +--1-111-0-0---- 0001000 +-11--11-0-0--0- 0001000 +--1--11--00---- 0001000 +--1---1---0-1-- 0001000 +111---1---0--0- 0001000 +-11-1-1--00--0- 0001000 +--1-111---0--0- 0001000 +0-0-0-1-100-0-- 0001000 +--0---1-000-01- 0001000 +-00-0-1-000-0-- 0001000 +--0--01-0-0-01- 0001000 +-00-001-0-0-0-- 0001000 +0-0--01--10-0-- 0001000 +-00--01--00-0-- 0001000 +--0-0-1--00-01- 0001000 +--0-001---0-01- 0001000 +-1-0--0-110-01- 0001000 +01-00-0-110-0-- 0001000 +01--000-1-0-0-- 0001000 +-1-0-00-1-0-01- 0001000 +01---00--10-0-- 0001000 +-1--000---0-01- 0001000 +-1-00-0--10-01- 0001000 +10----0-110--0- 0001000 +10-11-0-110---- 0001000 +10---10-1-0--0- 0001000 +-0-1110-1-0---- 0001000 +-0-1-10--10---- 0001000 +-0----0---0-1-- 0001000 +-0--110---0--0- 0001000 +10--1-0--10--0- 0001000 +010-0---100-0-- 0001000 +-10-----000-01- 0001000 +-10--0--0-0-01- 0001000 +-100------0-01- 0001000 +-10-0----00-01- 0001000 +101-1---010---- 0001000 +-01-11--0-0---- 0001000 +-01--1---00---- 0001000 +--11-11-------- 0001000 +1-111-1--1----- 0001000 +-1111-1--0----- 0001000 +0-000-1-1---0-- 0001000 +-0000-1-0---0-- 0001000 +--00--1-----01- 0001000 +1--1-1--11---0- 0000100 +---111--11----- 0000100 +-1-1-1--01---0- 0000100 +---1-1---1--1-- 0000100 +---111---1---0- 0000100 +0--001--11--0-- 0000100 +---0-1--11--01- 0000100 +-0-001--01--0-- 0000100 +---001---1--01- 0000100 +1-0--0--01--01- 0000100 +10--00--01--0-- 0000100 +1---00---1--01- 0000100 +01---0--01---0- 0000100 +0-1-10--01----- 0000100 +0----0---1--1-- 0000100 +0---10---1---0- 0000100 +1--0----11--01- 0000100 +0--11---11----- 0000100 +1-1--1--10---0- 0000100 +-11--1--00---0- 0000100 +--1-11--00----- 0000100 +--1--1---0--1-- 0000100 +--1-11---0---0- 0000100 +0-0-01--10--0-- 0000100 +-00-01--00--0-- 0000100 +--0--1--00--01- 0000100 +--0-01---0--01- 0000100 +-1-0-0--10--01- 0000100 +01--00--10--0-- 0000100 +-1--00---0--01- 0000100 +10---0--10---0- 0000100 +-0-110--10----- 0000100 +-0---0---0--1-- 0000100 +-0--10---0---0- 0000100 +-10-----00--01- 0000100 +-01-1---00----- 0000100 +--1111--------- 0000100 +--00-1------01- 0000100 +---11---1---1-- 0000010 +---11---1----0- 0000010 +---01---1---01- 0000010 +--1-1---0---1-- 0000010 +--1-1---0----0- 0000010 +--0-1---0---01- 0000010 +1---0---1---01- 0000010 +0---0---1---1-- 0000010 +0---0---1----0- 0000010 +-1--0---0---01- 0000010 +-0--0---0---1-- 0000010 +-0--0---0----0- 0000010 +1--111-11111-01 0000001 +11-111-111-1-01 0000001 +10-111001101001 0000001 +01-111--1101-01 0000001 +0--1111-11-1-01 0000001 +---111-111-11-1 0000001 +---1111111-1-01 0000001 +-00111011100001 0000001 +0101110-1110001 0000001 +-0-111-011-01-1 0000001 +-0-1111011-0-01 0000001 +10-111-01110-01 0000001 +1-1111-11-1--01 0000001 +0-0110-11100001 0000001 +0-01100111-0001 0000001 +01-1100011-0001 0000001 +010110--1100001 0000001 +00-11010111--01 0000001 +-0-110-110-11-1 0000001 +-0-110111011-01 0000001 +100110-01001001 0000001 +10-1100010-1001 0000001 +-0-110111000001 0000001 +-0-110101010-01 0000001 +-001100110-0001 0000001 +-0-110-010-01-1 0000001 +00-1101-1-11-01 0000001 +0--11-1-1111-01 0000001 +0-111--111--1-1 0000001 +0-011-011110001 0000001 +0-1011101101011 0000001 +---011-11111011 0000001 +---0110111-1011 0000001 +---011111100011 0000001 +-1-011-01110011 0000001 +-1-0110011-0011 0000001 +-010111-1100011 0000001 +-1-010-11011011 0000001 +-1-0100110-1011 0000001 +011010101001011 0000001 +-1-010111000011 0000001 +-1-010-01010011 0000001 +-1-0100010-0011 0000001 +0-1011010011001 0000001 +1010110-0001001 0000001 +0-1-11-000-11-1 0000001 +0-1-111000-1-01 0000001 +011-11-00001-01 0000001 +-11-11-10000-01 0000001 +111-11-100-0-01 0000001 +011-11000010001 0000001 +101-11--0010-01 0000001 +-01-111-00-0-01 0000001 +--1-11-100-01-1 0000001 +--1-111100-0-01 0000001 +-11111-10-0--01 0000001 +0-1-10110111001 0000001 +0-1-10100101-01 0000001 +0-10100101-1001 0000001 +0-1-10-001-11-1 0000001 +0-1-10-101-01-1 0000001 +0-1-10110100-01 0000001 +011010-00110001 0000001 +011-100001-0001 0000001 +-01010-10011001 0000001 +-010100100-1001 0000001 +101-100000-1001 0000001 +101010--0011001 0000001 +001-1010000--01 0000001 +001-101-0-00-01 0000001 +-01-1-1-0000-01 0000001 +-0111--100--1-1 0000001 +-0101-010001001 0000001 +1-0-10110111011 0000001 +1-0-10-00101011 0000001 +1-0-100001-1011 0000001 +1-0-10-10100011 0000001 +1-0-100101-0011 0000001 +100110100110011 0000001 +--0-11110011011 0000001 +1-0-11-00001011 0000001 +1-0-110000-1011 0000001 +0-01111-0011011 0000001 +-00111100010011 0000001 +--0-11-10000011 0000001 +--0-110100-0011 0000001 +10111100--01001 0000001 +0-1111-----11-1 0000001 +0-11111----1-01 0000001 +011111----01-01 0000001 +01111100--10001 0000001 +-01111-----01-1 0000001 +-011111----0-01 0000001 +101111----10-01 0000001 +111111-1-----01 0000001 +--1111-1----1-1 0000001 +--111111-----01 0000001 +0011101------01 0000001 +0-111-1--1-1-01 0000001 +0-111-11-1---01 0000001 +-0111-1--0-0-01 0000001 +-0111-11-0---01 0000001 +1-001----1-1011 0000001 +1-001--1-1--011 0000001 +-1001----0-0011 0000001 +-1001--1-0--011 0000001 +--0011-1----011 0000001 +110010------011 0000001 +1-0011-----1011 0000001 +-10011-----0011 0000001 +1-1111-1--11-01 0000001 +0-111----1-11-1 0000001 +-11111-1--00-01 0000001 +-0111----0-01-1 0000001 +1-11001111--011 0000001 +10-100101110011 0000001 +1011001-11-0011 0000001 +11-00--0111-011 0000001 +11-00-0011--011 0000001 +11000---11--011 0000001 +1-0-00-11100011 0000001 +1-0-000111-0011 0000001 +1---00111111011 0000001 +1---000011-1011 0000001 +1-0-00-01101011 0000001 +1-0-01111011011 0000001 +1-0-01-01001011 0000001 +1-0-010010-1011 0000001 +100101101010011 0000001 +1-0-01-11000011 0000001 +1-0-010110-0011 0000001 +11--00111-11011 0000001 +11000---1--1011 0000001 +0-1-01-110-01-1 0000001 +0-1-01-010-11-1 0000001 +0-1-00-111-01-1 0000001 +0---00-011-11-1 0000001 +0--001-11111001 0000001 +0--0010111-1001 0000001 +0--001111100001 0000001 +01-001-01110001 0000001 +01-0010011-0001 0000001 +0-1001101101001 0000001 +0-01011-1011001 0000001 +0-0-01-11000001 0000001 +0-0-010110-0001 0000001 +01-0000110-1001 0000001 +01-000-11011001 0000001 +01--00111011001 0000001 +011-00101001001 0000001 +01-1001-1011001 0000001 +01--00111000001 0000001 +01-000-01010001 0000001 +01--000010-0001 0000001 +0111001110--001 0000001 +010-0---1000001 0000001 +010-0-0-10-0001 0000001 +01000--110--001 0000001 +010001--1--0001 0000001 +0-0001-11---001 0000001 +011001100101011 0000001 +-1-001-10111011 0000001 +-1-0010101-1011 0000001 +-1-001110100011 0000001 +-1-001-00110011 0000001 +-1-0010001-0011 0000001 +-111001100--011 0000001 +011-00100001011 0000001 +0111001-00-1011 0000001 +110-0--0000-011 0000001 +110-0-0000--011 0000001 +11000---00--011 0000001 +-1-000-10011011 0000001 +-1-0000100-1011 0000001 +-1--00110000011 0000001 +-1--000000-0011 0000001 +-1-000-00010011 0000001 +11--00110-00011 0000001 +11000---0--0011 0000001 +-0-101-101-11-1 0000001 +-0-101-001-01-1 0000001 +-0-100-100-11-1 0000001 +-0--00-000-01-1 0000001 +-0-001-10111001 0000001 +-0-0010101-1001 0000001 +-010011-0100001 0000001 +10--00110111001 0000001 +100-00-00101001 0000001 +10--000001-1001 0000001 +100-000101-0001 0000001 +100-00-10100001 0000001 +10--00110100001 0000001 +10-100100110001 0000001 +101-001-0100001 0000001 +1011001101--001 0000001 +10-00---0111001 0000001 +10-00-0-01-1001 0000001 +10000--101--001 0000001 +-00-01110011001 0000001 +-00-01-10000001 0000001 +-00-010100-0001 0000001 +100-01-00001001 0000001 +100-010000-1001 0000001 +-00101100010001 0000001 +-00001-10---001 0000001 +100001--0--1001 0000001 +11--0000----011 0000001 +11-000-0--1-011 0000001 +110001------011 0000001 +11110011----011 0000001 +110-00-0--0-011 0000001 +11000--1----011 0000001 +00--00-0----1-1 0000001 +00-10--0-1--1-1 0000001 +001-0--0-0--1-1 0000001 +00100110-10-001 0000001 +00010110-01-001 0000001 +11--0011-111011 0000001 +11-00----111011 0000001 +11-00-0--1-1011 0000001 +00-100---1-11-1 0000001 +11--0011-000011 0000001 +110-0----000011 0000001 +110-0-0--0-0011 0000001 +001-00---0-01-1 0000001 +1--0----1111011 0000001 +1--0--0-11-1011 0000001 +1--0--111100011 0000001 +1010--1-1100011 0000001 +11-0-0--1-11011 0000001 +11-0-00-1--1011 0000001 +00-1-0--1--11-1 0000001 +0--1----11-11-1 0000001 +-10---110011011 0000001 +0101--1-0011011 0000001 +-10-----0000011 0000001 +-10---0-00-0011 0000001 +110--0--0-00011 0000001 +110--00-0--0011 0000001 +001--0--0--01-1 0000001 +-01-----00-01-1 0000001 +1-00----11-1011 0000001 +1-00---111--011 0000001 +1-00-1--1--1011 0000001 +1-00-1-11---011 0000001 +0-11-1-11---1-1 0000001 +-100----00-0011 0000001 +-100---100--011 0000001 +-100-1--0--0011 0000001 +-100-1-10---011 0000001 +-011-1-10---1-1 0000001 +00-1-0-011--1-1 0000001 +11-0-0-0111-011 0000001 +11-0-00011--011 0000001 +001--0-000--1-1 0000001 +110--0-0000-011 0000001 +110--00000--011 0000001 diff --git a/espresso/examples/indust/jbp b/espresso/examples/indust/jbp new file mode 100644 index 0000000..dc24264 --- /dev/null +++ b/espresso/examples/indust/jbp @@ -0,0 +1,334 @@ +.i 36 +.o 57 +0001----1----111----1---------0---0- +000000000000000000010000000000000000000000000000000000000 +0001----1----111-------------1------ +000000000000000000010000000000000000000000000000000000000 +0010----1----111----1---------0---0- +000000000000000000010000000000000000000000000000000000000 +0010----1----111-------------1------ +000000000000000000010000000000000000000000000000000000000 +00------00----------1--------00---0- +000000000000000000000000000000000000000000000000000000100 +00------10110-------1--------00---0- +000000000000000000000000000000000000000000000001000000000 +00------1-011-----------------0----- +000000000010000000000000000000000000000000000000000000000 +00------1-0---------1--------00---0- +000000000000000000000000000000000000000000000000000000010 +00------1---1-------1--------00---0- +000000000000000000000000000000000000000000000000000000010 +00------1-----------1--------00---0- +000000000000000000000000000000000000000000000000000010000 +00-------1-0-0----------------0----- +000000001000000000000000000000000000000000000000000000000 +00-------1--10----------------0----- +000000001000000000000000000000000000000000000000000000000 +00-------1--11----------------0----- +000000000010000000000000000000000000000000000000000000000 +00-------1----------1--------00---0- +000000000000000000000000000000000000000000000000000010000 +00--------1--0----------------0----- +000000001000000000000000000000000000000000000000000000000 +00---------------------------0------ +000000000100000000000000000000000000000000000000000000000 +01-0----001-00------1--------00---0- +000000000000000000000000000000000000000000000000010000000 +01-0----001-10------1--------00---0- +000001000000001000000000000000000000000000000000000000000 +01-0----001--0------1--------00---0- +000000000000000000000000000000010000000100000000000000000 +01-0----0-1--0------1--------00---0- +001000000000000000000000000000000000000000000000000000000 +01-1----0000-0------1--------00---0- +000000000000000000000000000000000000000010000000000000000 +01-1----000110------1--------00---0- +000000000000100000000000000000000000000000000000000000000 +01-1----0001-0------1--------00---0- +000000000000000000100000000000000000000000000000000000000 +01-1----0001-0------1--------0----0- +000000000000000000000000000000100000000000000000000000001 +01-1----0011-0------1--------00---0- +000000000000001000000000000000000000000000000000000000000 +01-1----00-110------1--------0----0- +000000000000000000000000000000100000000000000000000000000 +01-1-----01100------1--------00---0- +010000000000000000000000000000000000000000000000000000000 +01-1-----0-1-0------1-------------0- +000000000000000000000000000000000000000000000000000100000 +01------000000------1--------00---0- +000000000000000000000000000000000000000000000000001000000 +01------000001------1--------00---01 +000000000000000000000000000000000000000000000010000000000 +01------000010------1--------00---0- +000000000000001000000000000000000000000000100000000000000 +01------000011------1--------00---00 +000000000000000000000000000000000000000000000010000000000 +01------0000-0------1--------00---0- +000000000000000000000000000000000000000000010000000000000 +01------000101---1--1--------00---0- +000000000000000000000000000000000000000000000010000000000 +01------000111---0--1--------00---0- +000000000000000000000000000000000000000000000010000000000 +01------001001----1-1--------00---0- +000000000000000000000000000000000000000000000010000000000 +01------001011----0-1--------00---0- +000000000000000000000000000000000000000000000010000000000 +01------001100------1--------00---0- +000000000000000000000000000000010000000000000000000000000 +01------01----------1--------00---0- +000000000000010000000000000000000000000000000000000000000 +01------0-0000------1--------00---0- +001000000000000000000000000000000000000000000000000000000 +01------0-1100------1--------00---0- +001000000000000000000000000000000000000000000000000000000 +01------10----------1--------00---0- +010000000000000001000000000000000000000000000000000000100 +01------10----------1-------------0- +000000000000000000000000000000000000000000000000000100000 +01------11----------1--------00---0- +000000000000000000000000000000000000000000001000000000000 +01-------1----------1--------00---0- +001000000000000000000000000000000000000000000000000000000 +0-------01----------1--------00---0- +001000000000000000000000000000000000001000000000000000000 +0-------10110-------1-------------0- +000000000000000000000000000000000000000000000000000100000 +0-------11110-------1--------00---0- +000000000000000000000000000000000000000000001000000000000 +0-----------11---------------0------ +000000000100000000000000000000000000000000000000000000000 +10------110111---------------00----- +000000000000000000000000000000000000000001000000000000000 +10------11011----1-----------00----- +000000000000000000000000000000000000000001000000000000000 +10------11011----------------00----- +000000100000000000000000000000000000000000000000000000000 +10-------1-0-1---------------00----- +000000100000000000000000000000000000000000000000000000000 +10-------1-0------------------0----- +000000000010000000000000000000000000000000000000000000000 +11-------100-1----------------0----- +000000001000000000000000000000000000000000000000000000000 +11-------1-0-0---------------00----- +000000010000000000000000000000000000000000000000000000000 +11-------1--10---------------00----- +000000010000000000000000000000000000000000000000000000000 +11-------1--10----------------0----- +000000000010000000000000000000000000000000000000000000000 +11-------1--11---1-----------00----- +000000000000000000000000000000000000000001000000000000000 +11--------1--0---------------00----- +000000010000000000000000000000000000000000000000000000000 +11--------1--1---1-----------00----- +000000000000000000000000000000000000000001000000000000000 +11---------------------------------- +000000000000000000000000000010000000000000000000000000000 +1-------01-11-----------------0----- +000000000010000000000000000000000000000000000000000000000 +1--------1-00-----------------0----- +000000000010000000000000000000000000000000000000000000000 +1--------1--11---------------00----- +000000100000000000000000000000000000000000000000000000000 +1---------0---------1--------00---0- +000000000000000000000000000000000000000000000001000000000 +1---------0---------1-------------0- +000000000000000000000000000000000000000000000000000100000 +1---------1--1---------------00----- +000000100000000000000000000000000000000000000000000000000 +1---------1-------------------0----- +000000000010000000000000000000000000000000000000000000000 +1-----------1-------1--------00---0- +000000000000000000000000000000000000000000000001000000000 +1-----------1-------1-------------0- +000000000000000000000000000000000000000000000000000100000 +1-------------------1--------00---0- +100000000000000000000000000000000000000000000100000000000 +-0-1---100-------------------------- +000000000000000000000010000000000000000000000000000000000 +-0-1---101-------------------------- +000000000000000000000000001000000000000000000000000000000 +-0--1--101-------------------------- +000000000000000000000000000100000000000000000000000000000 +-0---1-100-------------------------- +000000000000000000000000100000000000000000000000000000000 +-0---1-101-------------------------- +000000000000000000000000000010000000000000000000000000000 +-0----1100-------------------------- +000000000000000000000000010000000000000000000000000000000 +-0----1101-------------------------- +000000000000000000000000000001000000000000000000000000000 +-0-----0-1000----------------------- +000000000000000000000010000000000000000000000000000000000 +-0-----0-1001----------------------- +000000000000000000000001000000000000000000000000000000000 +-0-----0-1011----------------------- +000000000000000000000000010000000000000000000000000000000 +-0-----0-1100----------------------- +000000000000000000000000001000000000000000000000000000000 +-0-----0-1101----------------------- +000000000000000000000000000100000000000000000000000000000 +-0-----0-1110----------------------- +000000000000000000000000000010000000000000000000000000000 +-0-----0-1111----------------------- +000000000000000000000000000001000000000000000000000000000 +-0-----100000----------------------- +000000000000000000000000001111000000000000000000000000000 +-0-----101000----------------------- +000000000000000000000000010000000000000000000000000000000 +-0------01000----------------------- +000000000000000000000010000000000000000000000000000000000 +-0------110110----------------0----- +000000001000000000000000000000000000000000000000000000000 +-0------1-111-------1--------00---0- +000000000000000000000000000000000000000000000100000000000 +-0------1-----------1--------00---0- +100000000000000000000000000000000000000000000000000000000 +-0--------1--1----------------0----- +000000000010000000000000000000000000000000000000000000000 +-0-----------1---------------0------ +000000000100000000000000000000000000000000000000000000000 +-11--------------------------------- +000000000000000000000000000001000000000000000000000000000 +-1-0-----01-10------1-------------0- +000000000000000000000000000000000000000000000000000100000 +-1-----1---------------------------- +000000000000000000000001000000000000000000000000000000000 +-1------000010------1--------00---0- +000000000000000000000000000000000000000000000001000000000 +-1------110---------1--------00---0- +000000000000000000000000000000000000000000000001000000000 +-1------11--1-------1--------00---0- +000000000000000000000000000000000000000000000001000000000 +-1------1-0---------1-------------0- +000000000000000000000000000000000000000000000000000100000 +-1------1---1-------1-------------0- +000000000000000000000000000000000000000000000000000100000 +-1------1--------------------------- +000000000000000000000010000000000000000000000000000000000 +-1-------00010------1-------------0- +000000000000000000000000000000000000000000000000000100000 +-1-------10001----------------0----- +000000001000000000000000000000000000000000000000000000000 +-1-------1----------1--------00---0- +000000000000000000000000000000000000000000000100000000000 +-1-------1-------------------------- +000000000000000000000000100000000000000000000000000000000 +-1-----------1---------------------- +000000000000000000000000010000000000000000000000000000000 +-1------------1--------------------- +000000000000000000000000001000000000000000000000000000000 +-1-------------1-------------------- +000000000000000000000000000100000000000000000000000000000 +----1--100-------------------------- +000000000000000000000001000000000000000000000000000000000 +-------0-1010----------------------- +000000000000000000000000100000000000000000000000000000000 +-------0---1------------------1----- +000000000000000000100000000000000000000000000000000000000 +-------101000----------------------- +000000000000000000000001100000000000000000000000000000000 +-------1---0------------------1----- +000000000000100000100000000000000000000000000000000000000 +--------00011-----------------0----- +000000001000000000000000000000000000000000000000000000000 +--------100-1----------------00----- +000000010000000000000000000000000000000000000000000000000 +--------100-1-----------------0----- +000000000010000000000000000000000000000000000000000000000 +--------11111-------1--------00---0- +000000000000000000000000000000000000000000000001000000000 +--------11111-------1-------------0- +000000000000000000000000000000000000000000000000000100000 +--------11----------1--------00---0- +100000000000000000000000000000000000000000000000000000000 +---------0001----------------00----- +000000010000000000000000000000000000000000000000000000000 +---------0001-----------------0----- +000000000010000000000000000000000000000000000000000000000 +---------00------------------0------ +000000000100000000000000000000000000000000000000000000000 +---------10001----------------0----- +000000000010000000000000000000000000000000000000000000000 +---------1-0-----------------00----- +000000000001000000000000000000000000000000000000000000000 +---------1--1----------------00----- +000000000001000000000000000000000000000000000000000000000 +----------010----------------0------ +000000000100000000000000000000000000000000000000000000000 +----------1--1---------------0------ +000000000100000000000000000000000000000000000000000000000 +----------1------------------00----- +000000000001000000000000000000000000000000000000000000000 +-----------1-1---------------0------ +000000000100000000000000000000000000000000000000000000000 +----------------0--------1---------- +000000000000000000000100000000000000000000000000000000000 +----------------1--------1---------- +000010000000000000000000000000000000000000000000000000000 +-------------------1--------11------ +000000000000000100000000000000000000000000000000000000000 +---------------------0000-0011--01-- +000100000000000000000000000000000000000000000000000000000 +---------------------0001-0011--00-- +000100000000000000000000000000000000000000000000000000000 +---------------------001--0010--01-- +000100000000000000000000000000000000000000000000000000000 +---------------------01---0010--00-- +000100000000000000000000000000000000000000000000000000000 +---------------------01---0----1---- +000000000000000000000000000000000000100000000000000000000 +---------------------0-01-0----1---- +000000000000000000000000000000000000100000000000000000000 +---------------------0----00---10--- +000000000000000000000000000000000100000000000000000000000 +---------------------0----00----0--- +000000000000000000000000000000001000000000000000000000000 +---------------------1----0001--01-- +000100000000000000000000000000000000000000000000000000000 +---------------------1----0----10--- +000000000000000000000000000000000001000000000000000000000 +---------------------1----0-----0--- +000000000000000000000000000000000010000000000000000000000 +---------------------1-----0---10--- +000000000000000000000000000000000000010000000000000000000 +----------------------00--0----10--- +000000000000000000000000000000000001000000000000000000000 +----------------------00--0-----0--- +000000000000000000000000000000000010000000000000000000000 +----------------------01---0---10--- +000000000000000000000000000000000000010000000000000000000 +----------------------0-0--0---10--- +000000000000000000000000000000000000010000000000000000000 +--------------------------0101--00-- +000100000000000000000000000000000000000000000000000000000 +--------------------------01---10--- +000000000000000000000000000000000001000000000000000000000 +--------------------------01---1---- +000000000000000000000000000000000000100000000000000000000 +--------------------------01----0--- +000000000000000000000000000000000010000000000000000000000 +--------------------------1-00--01-- +000100000000000000000000000000000000000000000000000000000 +--------------------------1----10--- +000000000000000000000000000000000000010000000000000000000 +----------------------------000---1- +000000000000000010000000000000000000000000000000000000000 +----------------------------00--10-- +000100000000000000000000000000000000000000000000000000000 +----------------------------01------ +001000000000000000010000000000010000000000000000000001000 +----------------------------11------ +010000000000000000000000000000000000000000000000100000000 +-----------------------------01----- +000000000100000000000000000000000000000000000000000000000 +-----------------------------1------ +000000001010000000000000000000000000000000000000000100000 +------------------------------1----- +000000000000000000000000000000100000000000000000000100001 +-------------------------------0---- +000100000000000000000000000000001010000000000000000000000 +-------------------------------11--- +000000000000000000000000000000000000100000000000000000000 +-------------------------------1---- +000000000000000000001000000000000000000000000000000000000 diff --git a/espresso/examples/indust/lin.rom b/espresso/examples/indust/lin.rom new file mode 100644 index 0000000..e04decb --- /dev/null +++ b/espresso/examples/indust/lin.rom @@ -0,0 +1,131 @@ +.i 7 +.o 36 +0000000 000100110011001100110011001100111001 +1000000 101100010011001100110011001100111001 +0100000 101110110001001100110011001100111001 +1100000 100100111001001100110011001100111001 +0010000 000110011001001100110011001100111001 +1010000 000100110011100100110011001100111001 +0110000 101100010011100100110011001100111001 +1110000 101110110001100100110011001100111001 +0001000 000100111001100100110011001100111001 +1001000 000110011001100100110011001100111001 +0101000 001000110011001110010011001100111001 +1101000 111000010011001110010011001100111001 +0011000 110010010011001110010011001100111001 +1011000 010000111001001110010011001100111001 +0111000 010010011001001110010011001100111001 +1111000 111010111011000110010011001100111001 +0000100 111000010011100110010011001100111001 +1000100 110010010011100110010011001100111001 +0100100 000101101001100110010011001100111001 +1100100 001111001001100110010011001100111001 +0010100 101111101011101110110001001100111001 +1010100 101101000011001100111001001100111001 +0110100 000111000011001100111001001100111001 +1110100 010001101001001100111001001100111001 +0001100 111001001001001100111001001100111001 +1001100 111011101011000100111001001100111001 +0101100 110001100011100100111001001100111001 +1101100 000110010110100100111001001100111001 +0011100 001100111100100100111001001100111001 +1011100 101100011100100100111001001100111001 +0111100 100110011100100100111001001100111001 +1111100 010000110110001110011001001100111001 +0000010 010010010110001110011001001100111001 +1000010 111010110100001110011001001100111001 +0100010 101101001100001110011001001100111001 +1100010 000111001100001110011001001100111001 +0010010 000101100110100110011001001100111001 +1010010 111001000110100110011001001100111001 +0110010 111011100100100110011001001100111001 +1110010 010001101100100110011001001100111001 +0001010 000110011001110010011001001100111001 +1001010 001100110011011000110011100100111001 +0101010 101000010011011000110011100100111001 +1101010 110010010011011000110011100100111001 +0011010 010000111001011000110011100100111001 +1011010 001111001001011000110011100100111001 +0111010 101111101011010000110011100100111001 +1111010 110001100011110000110011100100111001 +0000110 010011000011110000110011100100111001 +1000110 011101111000110000110011100100111001 +0100110 101100011100110000110011100100111001 +1100110 100010011100110000110011100100111001 +0010110 010000110110011010010011100100111001 +1010110 011110000110011010010011100100111001 +0110110 101111100100011010010011100100111001 +1110110 100001101100011010010011100100111001 +0001110 010011001100011010010011100100111001 +1001110 011101110111110110000011100100111001 +0101110 101100010011100111000011100100111001 +1101110 010010010011100111000011100100111001 +0011110 010000111001100111000011100100111001 +1011110 101101001001100111000011100100111001 +0111110 101011101011101111100001100100111001 +1111110 010001100011001101101001100100111001 +0000001 011111010010001101101001100100111001 +1000001 101110110100001101101001100100111001 +0100001 110000111100001101101001100100111001 +1100001 010110001100001101101001100100111001 +0010001 101111101110000101101001100100111001 +1010001 111001000110100101101001100100111001 +0110001 010111010111100001101001100100111001 +1110001 001100111001110001101001100100111001 +0001001 111000011001110001101001100100111001 +1001001 110110001001110001101001100100111001 +0101001 000101100011011011001001100100111001 +1101001 111001000011011011001001100100111001 +0011001 111111110000011011001001100100111001 +1011001 000100111100011011001001100100111001 +0111001 011010011100011011001001100100111001 +1111001 111110101110010011001001100100111001 +0000101 000001100110110011001001100100111001 +1000101 011011000110110011001001100100111001 +0100101 101110110001100110011100100100111001 +1100101 100000111001100110011100100100111001 +0010101 010110001001100110011100100100111001 +1010101 101111101011101110111110101100011001 +0110101 110001100011001100110110001110011001 +1110101 000110010110001100110110001110011001 +0001101 101010110100001100110110001110011001 +1001101 110100101100001100110110001110011001 +0101101 000111001100001100110110001110011001 +1101101 111011101110000100110110001110011001 +0011101 100100110011110000110110001110011001 +1011101 010010010011110000110110001110011001 +0111101 111110100001110000110110001110011001 +1111101 100001101001110000110110001110011001 +0000011 010111011000110000110110001110011001 +1000011 101110111110111000010110001110011001 +0100011 010000110110011010010110001110011001 +1100011 001111000110011010010110001110011001 +0010011 111011100100011010010110001110011001 +1010011 000100111001001111000110001110011001 +0110011 011010011001001111000110001110011001 +1110011 111110101011000111000110001110011001 +0001011 000001100011100111000110001110011001 +1001011 111101010010100111000110001110011001 +0101011 100010010110100111000110001110011001 +1101011 010100101100100111000110001110011001 +0011011 101001001100100111000110001110011001 +1011011 010111011101100011000110001110011001 +0111011 001000110011011001101100001110011001 +1111011 110100100011011001101100001110011001 +0000111 000011000011011001101100001110011001 +1000111 111111110000011001101100001110011001 +0100111 000000111100011001101100001110011001 +1100111 011110001100011001101100001110011001 +0010111 100011001100011001101100001110011001 +1010111 010101110111110101111101001010011001 +0110111 101000010011100100111001011010011001 +1110111 010110000011100100111001011010011001 +0001111 001001101001100100111001011010011001 +1001111 110101111000100100111001011010011001 +0101111 001010011100100100111001011010011001 +1101111 101111101110101100011001011010011001 +0011111 010001100110001110011001011010011001 +1011111 101100010011011010011001011010011001 +0111111 010010010011011010011001011010011001 +1111111 101111100001011010011001011010011001 +.end diff --git a/espresso/examples/indust/luc b/espresso/examples/indust/luc new file mode 100644 index 0000000..79274b6 --- /dev/null +++ b/espresso/examples/indust/luc @@ -0,0 +1,29 @@ +.i 8 +.o 27 +000011-- 000000001111100000011100001 +000010-- 000000000111111011101010001 +000001-- 000000000111011011101010001 +000000-- 000010000111011111101010001 +00011--- 000010001111011111101010001 +000101-- 001101001111111011101010001 +00101--- 000111001101111001101000001 +0011---- 000000101101111101110100001 +0100---- 001100111111111001110100001 +11001--- 010000111110111011111100101 +11000-0- 000010111110111101111000101 +1101--0- 000001111110111101111000001 +1110110- 001111111111111001111000001 +1111---- 000000011011111011001010001 +100011-- 000000011111111011001010001 +100010-- 000000011111101000001000001 +10000--- 000010011111100000010100001 +1001---1 000000001111100000010100001 +11000-11 000010111110111101101000100 +1101--11 000001111110111101101000000 +11101110 101111111111111001101000010 +11000-10 000010111110111101111001100 +1101--10 000001111110111101110001000 +1110111- 101111111111111001110001000 +-----0-- 001000000000000000000000000 +-----0-- 000100000000000000000000000 +----11-- 000100000000000000000000000 diff --git a/espresso/examples/indust/m1 b/espresso/examples/indust/m1 new file mode 100644 index 0000000..e4defdb --- /dev/null +++ b/espresso/examples/indust/m1 @@ -0,0 +1,34 @@ +.i 6 +.o 12 +000000 111001111111 +000001 111001011001 +000010 111010010010 +000011 111010001110 +000100 111011001100 +000101 111011001010 +000110 111011001001 +000111 111100000111 +001000 111100000110 +001001 111100000110 +001010 111101000101 +001011 111101000100 +001100 111101000100 +001101 111101000011 +001110 111110000011 +001111 111110000011 +010000 111110000010 +010001 111110000010 +010010 111110000010 +010011 111110000010 +010100 111111000010 +010101 111111000001 +010110 111111000001 +010111 111111000001 +011000 111111000001 +011001 111111000001 +011010 111111000001 +011011 111111000001 +011100 111111000001 +011101 111111000001 +011110 111111000001 +011111 111111000001 diff --git a/espresso/examples/indust/m2 b/espresso/examples/indust/m2 new file mode 100644 index 0000000..933db8f --- /dev/null +++ b/espresso/examples/indust/m2 @@ -0,0 +1,98 @@ +.i 8 +.o 16 +00000000 1110111111111111 +00000001 1111000001001111 +00000010 1111000000111110 +00000011 1111000000110101 +00000100 1111000100101110 +00000101 1111000100101001 +00000110 1111001000100101 +00000111 1111001000100010 +00001000 1111001100011111 +00001001 1111001100011101 +00001010 1111010000011011 +00001011 1111010000011001 +00001100 1111010000010111 +00001101 1111010100010110 +00001110 1111010100010100 +00001111 1111010100010011 +00010000 1111011000010010 +00010001 1111011000010001 +00010010 1111011000010000 +00010011 1111011100001111 +00010100 1111011100001110 +00010101 1111011100001110 +00010110 1111100000001101 +00010111 1111100000001100 +00011000 1111100000001100 +00011001 1111100000001011 +00011010 1111100100001010 +00011011 1111100100001010 +00011100 1111100100001001 +00011101 1111100100001001 +00011110 1111101000001001 +00011111 1111101000001000 +00100000 1111101000001000 +00100001 1111101000000111 +00100010 1111101100000111 +00100011 1111101100000111 +00100100 1111101100000110 +00100101 1111101100000110 +00100110 1111101100000110 +00100111 1111101100000110 +00101000 1111110000000101 +00101001 1111110000000101 +00101010 1111110000000101 +00101011 1111110000000101 +00101100 1111110000000100 +00101101 1111110000000100 +00101110 1111110100000100 +00101111 1111110100000100 +00110000 1111110100000100 +00110001 1111110100000100 +00110010 1111110100000011 +00110011 1111110100000011 +00110100 1111110100000011 +00110101 1111110100000011 +00110110 1111110100000011 +00110111 1111111000000011 +00111000 1111111000000011 +00111001 1111111000000011 +00111010 1111111000000010 +00111011 1111111000000010 +00111100 1111111000000010 +00111101 1111111000000010 +00111110 1111111000000010 +00111111 1111111000000010 +01000000 1111111000000010 +01000001 1111111000000010 +01000010 1111111000000010 +01000011 1111111000000010 +01000100 1111111100000010 +01000101 1111111100000010 +01000110 1111111100000010 +01000111 1111111100000001 +01001000 1111111100000001 +01001001 1111111100000001 +01001010 1111111100000001 +01001011 1111111100000001 +01001100 1111111100000001 +01001101 1111111100000001 +01001110 1111111100000001 +01001111 1111111100000001 +01010000 1111111100000001 +01010001 1111111100000001 +01010010 1111111100000001 +01010011 1111111100000001 +01010100 1111111100000001 +01010101 1111111100000001 +01010110 1111111100000001 +01010111 1111111100000001 +01011000 1111111100000001 +01011001 1111111100000001 +01011010 1111111100000001 +01011011 1111111100000001 +01011100 1111111100000001 +01011101 1111111100000001 +01011110 1111111100000001 +01011111 1111111100000001 diff --git a/espresso/examples/indust/m3 b/espresso/examples/indust/m3 new file mode 100644 index 0000000..c352f16 --- /dev/null +++ b/espresso/examples/indust/m3 @@ -0,0 +1,130 @@ +.i 8 +.o 16 +00000000 1110101111111111 +00000001 1110101101101011 +00000010 1110110001010110 +00000011 1110110001001010 +00000100 1110110001000001 +00000101 1110110100111011 +00000110 1110110100110110 +00000111 1110111000110001 +00001000 1110111000101110 +00001001 1110111100101011 +00001010 1110111100101000 +00001011 1111000000100101 +00001100 1111000000100011 +00001101 1111000000100001 +00001110 1111000100011111 +00001111 1111000100011110 +00010000 1111001000011000 +00010001 1111001000011011 +00010010 1111001000011001 +00010011 1111001100011000 +00010100 1111001100010111 +00010101 1111001100010110 +00010110 1111010000010101 +00010111 1111010000010100 +00011000 1111010000010011 +00011001 1111010100010010 +00011010 1111010100010001 +00011011 1111010100010001 +00011100 1111010100010000 +00011101 1111011000001111 +00011110 1111011000001111 +00011111 1111011000001110 +00100000 1111011100001110 +00100001 1111011100001101 +00100010 1111011100001101 +00100011 1111011100001100 +00100100 1111011100001100 +00100101 1111100000001011 +00100110 1111100000001011 +00100111 1111100000001010 +00101000 1111100000001010 +00101001 1111100100001010 +00101010 1111100100001001 +00101011 1111100100001001 +00101100 1111100100001001 +00101101 1111101000001000 +00101110 1111101000001000 +00101111 1111101000001000 +00110000 1111101000000111 +00110001 1111101000000111 +00110010 1111101000000111 +00110011 1111101100000111 +00110100 1111101100000110 +00110101 1111101100000110 +00110110 1111101100000110 +00110111 1111101100000110 +00111000 1111101100000110 +00111001 1111101100000101 +00111010 1111110000000101 +00111011 1111110000000101 +00111100 1111110000000101 +00111101 1111110000000101 +00111110 1111110000000100 +00111111 1111110000000100 +01000000 1111110000000100 +01000001 1111110000000100 +01000010 1111110100000100 +01000011 1111110100000100 +01000100 1111110100000100 +01000101 1111110100000100 +01000110 1111110100000011 +01000111 1111110100000011 +01001000 1111110100000011 +01001001 1111110100000011 +01001010 1111110100000011 +01001011 1111110100000011 +01001100 1111110100000011 +01001101 1111111000000011 +01001110 1111111000000011 +01001111 1111111000000011 +01010000 1111111000000010 +01010001 1111111000000010 +01010010 1111111000000010 +01010011 1111111000000010 +01010100 1111111000000010 +01010101 1111111000000010 +01010110 1111111000000010 +01010111 1111111000000010 +01011000 1111111000000010 +01011001 1111111000000010 +01011010 1111111000000010 +01011011 1111111000000010 +01011100 1111111000000010 +01011101 1111111100000010 +01011110 1111111100000010 +01011111 1111111100000001 +01100000 1111111100000001 +01100001 1111111100000001 +01100010 1111111100000001 +01100011 1111111100000001 +01100100 1111111100000001 +01100101 1111111100000001 +01100110 1111111100000001 +01100111 1111111100000001 +01101000 1111111100000001 +01101001 1111111100000001 +01101010 1111111100000001 +01101011 1111111100000001 +01101100 1111111100000001 +01101101 1111111100000001 +01101110 1111111100000001 +01101111 1111111100000001 +01110000 1111111100000001 +01110001 1111111100000001 +01110010 1111111100000001 +01110011 1111111100000001 +01110100 1111111100000001 +01110101 1111111100000001 +01110110 1111111100000001 +01110111 1111111100000001 +01111000 1111111100000001 +01111001 1111111100000001 +01111010 1111111100000001 +01111011 1111111100000001 +01111100 1111111100000001 +01111101 1111111100000001 +01111110 1111111100000001 +01111111 1111111100000001 diff --git a/espresso/examples/indust/m4 b/espresso/examples/indust/m4 new file mode 100644 index 0000000..75be2d2 --- /dev/null +++ b/espresso/examples/indust/m4 @@ -0,0 +1,258 @@ +.i 8 +.o 16 +00000000 1101111011111111 +00000001 1101111011000010 +00000010 1101111110100000 +00000011 1101111110001100 +00000100 1110000001111111 +00000101 1110000001110100 +00000110 1110000101101011 +00000111 1110000101100100 +00001000 1110001001011110 +00001001 1110001001011001 +00001010 1110001001010100 +00001011 1110001101010000 +00001100 1110001101001100 +00001101 1110010001001001 +00001110 1110010001000101 +00001111 1110010101000010 +00010000 1110010101000000 +00010001 1110010100111101 +00010010 1110011000111011 +00010011 1110011000111001 +00010100 1110011100110111 +00010101 1110011100110101 +00010110 1110011100110011 +00010111 1110100000110001 +00011000 1110100000101111 +00011001 1110100100101110 +00011010 1110100100101100 +00011011 1110100100101011 +00011100 1110101000101010 +00011101 1110101000101000 +00011110 1110101000100111 +00011111 1110101100100110 +00100000 1110101100100101 +00100001 1110101100100100 +00100010 1110110000100011 +00100011 1110110000100010 +00100100 1110110000100001 +00100101 1110110100100000 +00100110 1110110100011111 +00100111 1110110100011110 +00101000 1110111000011101 +00101001 1110111000011100 +00101010 1110111000011100 +00101011 1110111100011011 +00101100 1110111100011010 +00101101 1110111100011010 +00101110 1111000000011001 +00101111 1111000000011000 +00110000 1111000000011000 +00110001 1111000000010111 +00110010 1111000100010110 +00110011 1111000100010110 +00110100 1111000100010101 +00110101 1111000100010101 +00110110 1111001000010100 +00110111 1111001000010100 +00111000 1111001000010011 +00111001 1111001000010011 +00111010 1111001100010010 +00111011 1111001100010010 +00111100 1111001100010001 +00111101 1111001100010001 +00111110 1111010000010001 +00111111 1111010000010000 +01000000 1111010000010000 +01000001 1111010000010000 +01000010 1111010000001111 +01000011 1111010100001111 +01000100 1111010100001110 +01000101 1111010100001110 +01000110 1111010100001110 +01000111 1111010100001101 +01001000 1111011000001101 +01001001 1111011000001101 +01001010 1111011000001101 +01001011 1111011000001100 +01001100 1111011000001100 +01001101 1111011100001100 +01001110 1111011100001011 +01001111 1111011100001011 +01010000 1111011100001011 +01010001 1111011100001011 +01010010 1111011100001010 +01010011 1111100000001010 +01010100 1111100000001010 +01010101 1111100000001010 +01010110 1111100000001010 +01010111 1111100000001001 +01011000 1111100000001001 +01011001 1111100000001001 +01011010 1111100100001001 +01011011 1111100100001001 +01011100 1111100100001000 +01011101 1111100100001000 +01011110 1111100100001000 +01011111 1111100100001000 +01100000 1111100100001000 +01100001 1111100100001000 +01100010 1111101000000111 +01100011 1111101000000111 +01100100 1111101000000111 +01100101 1111101000000111 +01100110 1111101000000111 +01100111 1111101000000111 +01101000 1111101000000110 +01101001 1111101000000110 +01101010 1111101100000110 +01101011 1111101100000110 +01101100 1111101100000110 +01101101 1111101100000110 +01101110 1111101100000110 +01101111 1111101100000110 +01110000 1111101100000101 +01110001 1111101100000101 +01110010 1111101100000101 +01110011 1111101100000101 +01110100 1111101100000101 +01110101 1111110000000101 +01110110 1111110000000101 +01110111 1111110000000101 +01111000 1111110000000101 +01111001 1111110000000100 +01111010 1111110000000100 +01111011 1111110000000100 +01111100 1111110000000100 +01111101 1111110000000100 +01111110 1111110000000100 +01111111 1111110000000100 +10000000 1111110000000100 +10000001 1111110000000100 +10000010 1111110100000100 +10000011 1111110100000100 +10000100 1111110100000100 +10000101 1111110100000011 +10000110 1111110100000011 +10000111 1111110100000011 +10001000 1111110100000011 +10001001 1111110100000011 +10001010 1111110100000011 +10001011 1111110100000011 +10001100 1111110100000011 +10001101 1111110100000011 +10001110 1111110100000011 +10001111 1111110100000011 +10010000 1111110100000011 +10010001 1111110100000011 +10010010 1111110100000011 +10010011 1111111000000011 +10010100 1111111000000011 +10010101 1111111000000011 +10010110 1111111000000010 +10010111 1111111000000010 +10011000 1111111000000010 +10011001 1111111000000010 +10011010 1111111000000010 +10011011 1111111000000010 +10011100 1111111000000010 +10011101 1111111000000010 +10011110 1111111000000010 +10011111 1111111000000010 +10100000 1111111000000010 +10100001 1111111000000010 +10100010 1111111000000010 +10100011 1111111000000010 +10100100 1111111000000010 +10100101 1111111000000010 +10100110 1111111000000010 +10100111 1111111000000010 +10101000 1111111000000010 +10101001 1111111000000010 +10101010 1111111000000010 +10101011 1111111000000010 +10101100 1111111000000010 +10101101 1111111100000010 +10101110 1111111100000001 +10101111 1111111100000001 +10110000 1111111100000001 +10110001 1111111100000001 +10110010 1111111100000001 +10110011 1111111100000001 +10110100 1111111100000001 +10110101 1111111100000001 +10110110 1111111100000001 +10110111 1111111100000001 +10111000 1111111100000001 +10111001 1111111100000001 +10111010 1111111100000001 +10111011 1111111100000001 +10111100 1111111100000001 +10111101 1111111100000001 +10111110 1111111100000001 +10111111 1111111100000001 +11000000 1111111100000001 +11000001 1111111100000001 +11000010 1111111100000001 +11000011 1111111100000001 +11000100 1111111100000001 +11000101 1111111100000001 +11000110 1111111100000001 +11000111 1111111100000001 +11001000 1111111100000001 +11001001 1111111100000001 +11001010 1111111100000001 +11001011 1111111100000001 +11001100 1111111100000001 +11001101 1111111100000001 +11001110 1111111100000001 +11001111 1111111100000001 +11010000 1111111100000001 +11010001 1111111100000001 +11010010 1111111100000001 +11010011 1111111100000001 +11010100 1111111100000001 +11010101 1111111100000001 +11010110 1111111100000001 +11010111 1111111100000001 +11011000 1111111100000001 +11011001 1111111100000001 +11011010 1111111100000001 +11011011 1111111100000001 +11011100 1111111100000001 +11011101 1111111100000001 +11011110 1111111100000001 +11011111 1111111100000001 +11100000 1111111100000001 +11100001 1111111100000001 +11100010 1111111100000001 +11100011 1111111100000001 +11100100 1111111100000001 +11100101 1111111100000001 +11100110 1111111100000001 +11100111 1111111100000001 +11101000 1111111100000001 +11101001 1111111100000001 +11101010 1111111100000001 +11101011 1111111100000001 +11101100 1111111100000001 +11101101 1111111100000001 +11101110 1111111100000001 +11101111 1111111100000001 +11110000 1111111100000001 +11110001 1111111100000001 +11110010 1111111100000001 +11110011 1111111100000001 +11110100 1111111100000001 +11110101 1111111100000001 +11110110 1111111100000001 +11110111 1111111100000001 +01111000 1111111100000001 +01111001 1111111100000001 +01111010 1111111100000001 +01111011 1111111100000001 +01111100 1111111100000001 +01111101 1111111100000001 +01111110 1111111100000001 +01111111 1111111100000001 diff --git a/espresso/examples/indust/mainpla b/espresso/examples/indust/mainpla new file mode 100644 index 0000000..b55af8d --- /dev/null +++ b/espresso/examples/indust/mainpla @@ -0,0 +1,367 @@ +# this is a tautology unless I remove a silly product term +.i 27 +.o 54 +000000--------1-----00--01- +100111000001111111111111111001001101111011111111111111 +111110--------1-----00---0- +110110111011001010011111110101110111111101111111111111 +111001--------1-----00--0-- +100111010000111111111111111001111111111111111111111111 +001011--00000110-0--00----- +110010111011001010000000110101110111010010111111111111 +001011110010111010--00----- +110011111011000000000101011101110111011111111111111111 +001011001011001-10--00----- +110111101001001010111111111111110011111101111111111111 +001011000100001--0--00----- +101011111011001010010101110101110011111110111111111111 +001011111011001--0--00----- +110111110011001110011111110101110011111101111111111111 +001011011011001--0--00----- +110111110011001101011111110101110011111101111111111111 +00101100----101-00--00----- +111001011101001010111001111001110011111111111111111111 +00101100----101-10--00----- +111110010001111111111111111111111011111111111111111111 +00101101----101-00--00----- +100001110101001101011111111111110011111101111111111111 +00101101----101-10--00----- +100001101011001010111111111111110011111101111111111111 +00101111----101--0--00----- +100001110101001110011111111111110011111101111111111111 +001011001010001-10--00----- +100001010011001010010111111111110011111011111111111111 +001011000011001--0--00----- +100001111101001011011111111110110011111101111111111111 +110101---1--001-----00----- +101100110111001010000000111111110111111110111111111111 +001101--1110001-----00----- +000101111001001010100000111111110111111111111111111111 +001101000110001-----00----- +000101001111000111001001111111111111111111011111111111 +001101001101001-----00----- +000101111011001010010101111111110111111110111111111111 +101000000010001-----00----- +000111010111000000111001111111111111111111011111111111 +101000001101001-----00----- +000110011001001010111001111111110111111111111111111111 +011000--1110001-----00----- +000111111011001010000001111111110111111110111111111111 +011000000100001-----00----- +000111100011001010111001111111110111111111111111111111 +111000000010001-----00----- +001000110111001010011001111001110111111110111111111111 +111000001101001-----00----- +001000011011001010011001111111110111111110111111111111 +000100--1110001-----00----- +001001111011001010000010111111110101111110111111111111 +000100000110001-----00----- +001001110111001010010011111111110101111010111111111111 +000100001101001-----00----- +001001111011001010000000111111110111111110111111111111 +000100000100001-----00----- +001001110111001010010101111111110101111110111111111111 +001100001101001-----00----- +001101010111000000010001111111111101111111011111111111 +111011--------1-0---00----- +010001011011001010111001111111110111111111111111111111 +111011--------1-1---00----- +111110111101001010111111111111110111111101111111111111 +101010--------1-----00----- +010110000101001010111001111111110111111111111111111111 +100111--------1-----001---- +011001101111001010111001111001110111111111111111111111 +010001--------1------------ +101111101101001100001001111111001101111111111111111111 +101001--------1------------ +101111000111001100001001111111001101111111111111111111 +000000--------10----00--11- +110100000001111111111111111001001100111111111111111111 +111110--------1-----00---1- +100001101101111000000001111001001101011111111101111111 +001011---1000110-0--00----- +110010111011111111111111110101110110110111111111111111 +001011--0001011000--00----- +101011111011111111111111110101110110111111111111111111 +001011--0001111000--00----- +101011010111111111111111110100110110111111111111111111 +001011111101001--01-00----- +110100001011111111111111111001111111111011111111111111 +0010110000010011111-00----- +110100010101111111111111111001111111011111111111111111 +010011--------11----00----- +110010010101111111111111111111111111101111111111111111 +110011---1110010----00----- +110000111011111111111111111111110110111111111111111111 +11001111001011101---00----- +110010000011001010100001111111110111011111111111111111 +001001--------1-----00-0--- +000000001011111111111111111111111111111111111111111110 +001101000001001-----00----- +000101101111001010011001111111110111111111111111111111 +011000000110001-----00----- +000111001110111111111111111111110110111111111111111111 +0110000011010010----00----- +000111110011111111111111111111110010111111111111111111 +000100000010001-----00----- +000000110111001010010011111111110111111010111111111111 +100100001101001-----00----- +001010110111001010010101111111110111111110111111111111 +010100001101001-----00----- +001100001001001110011001111111110111111111111111111111 +101100001101001-----00----- +000000110111001010011001111111110111111010111111111111 +111101--------1-----00----- +111110001011111111111111111111111111111111111101111111 +100001001001001-1---00----- +111110000001111111111111111111111101111111111111111111 +011111--------1-----00----- +011110000001111111111111111111111111111011111111111111 +100111--------1-----000---- +000000001011111111111111111111111111111011111111111111 +100110--------1-----00----- +101110001011111111111111110101111111111111111111111111 +011101--------1-----00----- +011010001011111111111111111111111111111111111111111111 +011001--------1-----00----- +100000001011111111111111111111111111111011111111111110 +010000--------1------------ +101010001011111111111111111111111111111111111110011111 +010101--------1------------ +100010001001111111111111111111111111111111111111000111 +101101--------1------------ +100101001001111111111111111111111111111111111110000111 +#--------------------------- +#111111111111111111111111111111111111111111111111111111 +001011-------111-0--00----- +110100010101111111111111111111111101011111111111111111 +001011000001001100--00----- +110100010101111111111111111111111101011111111111111111 +--------------0------------ +000000101101111000000001111001001101011111101100111111 +000101--------1-----00----- +011111101101111111111111111001111111111111111100111111 +001011001011001100--00----- +110100010101111111111111111111111101011111111111111111 +00101100100-0011-0--00----- +110100010101111111111111111111111101011111111111111111 +111000--1110001-----00----- +001000110111001010100000111111110111111111111111111111 +011011--------1-----00----- +011111110111001010100001111111110111111111111111111111 +00101100110-0011-0--00----- +110100010101111111111111111111111101011111111111111111 +001011--01010011-0--00----- +110100010101111111111111111111111101011111111111111111 +0010110000100010-0--00----- +101011001101001000011001110101110011111110111111111111 +001011000001001000--00----- +101011011111001010111001110101110111111111111111111111 +001011---11-0011-0--00----- +110100010101111111111111111111111101011111111111111111 +0010110000100011-0--00----- +110100010101111111111111111111111101011111111111111111 +001011001010001-00--00----- +100000001011111111111111111111111111111011111111111011 +001011010001011-10--00----- +100011001011111111111111111111111111111111111111111111 +001011--0001011111--00----- +110100010101111111111111111001111111011111111111111111 +001011110001011111--00----- +110100010101111111111111111001111111011111111111111111 +001011001011001000--00----- +110111110011111111111111110101110010111111111111111111 +001011--------1--1--00----- +111111111111111111111111111111111110111111111111111111 +101000--1110001-----00----- +000110110111001010000010111111110111111110111111111111 +101000000100001-----00----- +000110110111001010000010111111110111111110111111111111 +000000--------1-----00---0- +101000000001111111111111111001001101111111111111111111 +000111--------11----00----- +111000010101111111111111111111111111111111111111111111 +0010110011010010-0--00----- +101011010111111111111111110101110010111111111111111111 +001011--11100010-0--00----- +101011010111111111111111110101110010111111111111111111 +100100--1110001-----00----- +000000110111001010000001111111110111101010111111111111 +110101--0001-11-----00----- +101100110111001010111001111111110111101111111111111111 +000011---111001-----00----- +000000100101111111111111111111111111101011111111111111 +000011--0101001-----00----- +000000100101111111111111111111111111101011111111111111 +000000--------11----00--11- +000000010101111111111111111001001101111011111111111111 +1101010000010011----00----- +101011010101111111111111111111111111111111111111111111 +011010--------1-----00----- +000000110111001010011001111111110101111010111111111111 +110110--------1-----00----- +000000110111001010011001111111110101111010111111111111 +001101--0001-11-----00----- +000101000101001010011001111111110111111110111111111111 +001101000100001-----00----- +000101011111001010111001111111110111111111111111111111 +001011--01010010-0--00----- +110000111011111111111111110101110110110111111111111111 +001011---0100110-0--00----- +110000111011111111111111110101110110110111111111111111 +110101000010001-----00----- +000110001100111111111111111111110110111111111111111111 +101000000110001-----00----- +000110001110111111111111111111110111111111111111111111 +00101110------1--0--00----- +100000000001001000000001111111110111011111111111111111 +001011-11100001--0--00----- +100000000001001000000001111111110111011111111111111111 +111000000110001-----00----- +001000111011001010000010110101110111111110111111111111 +111000000100001-----00----- +001000111011001010000010111111110111111110111111111111 +001011-1-0-0001--0--00----- +100000000001001000000001111111110111011111111111111111 +001011-11010111--0--00----- +100000000001001000000001111111110111011111111111111111 +100100000110001-----00----- +001010111011001010000000110101110111111110111111111111 +100100000100001-----00----- +001010111011001010000000111111110111111110111111111111 +001011--0110011--0--00----- +100000000001001000000001111111110111011111111111111111 +001011-10001011-00--00----- +100000000001001000000001111111110111011111111111111111 +111111--------1-----00----- +100000001011111111111111111111111111111011101111111100 +000001--------1-----00----- +110101001011111111111111111111111111111011111111111100 +001011-101-0001--0--00----- +100000000001001000000001111111110111011111111111111111 +001011000000001--0--00----- +100000000001001000000001111111110111011111111111111111 +001101000010001-----00----- +000101001001001110011001111111110111111111111111111111 +100010--------1-----00----- +010101001011111111111111111111111111111111111111111111 +001011-100--001--0--00----- +100000000001001000000001111111110111011111111111111111 +001011-10110111--0--00----- +100000000001001000000001111111110111011111111111111111 +011111001010001-1---00----- +000000000001111111111111111111111111111011111011111111 +010110--------1-----00----- +011101100001111111111111111111111111111111111111111111 +001011-11001001--0--00----- +100000000001001000000001111111110111011111111111111111 +001011-1000-111--0--00----- +100000000001001000000001111111110111011111111111111111 +--------------1----01------ +000010001011111111111111111001111011011111111111011111 +101110--------1-----00----- +011011001011111111111111111111111111111111111111111111 +110011-------111----00----- +110011010101111111111111111111111111111111111111111111 +110011---1110011----00----- +110011010101111111111111111111111111111111111111111111 +--------------1----0-1----- +101001001011111111111111111001111011011111111111011111 +100101--------1------------ +101101001011111111111111111111111111111111111111011111 +000011------011-----00----- +000000100111111111111111111111111111101011111111111111 +000011--0100111-----00----- +000000100111111111111111111111111111101011111111111111 +0010110010010010-0--00----- +100001110011111111111111111001110010111111111111111111 +000111--------10----00----- +110011111011111111111111111111110110111111111111111111 +101000--0001--1-----00----- +000000110111001010011001111111110111111010111111111111 +0101000001-0001-----00----- +000000110111001010011001111111110111111010111111111111 +001011--11001110-0--00----- +111000111011111111111111001101110110111111111111111111 +100011--------10----00----- +111000111011111111111111111111110110111111111111111111 +0110000001100011-1--00----- +000110010101111111111111111111111101111111111111111111 +0110000011010011----00----- +000110010101111111111111111111111101111111111111111111 +010011--------10----00----- +000000110111111111111111111111110110101011111111111111 +1101010000010010----00----- +101100110111111111111111111111110110101111111111111111 +100001--------1-0---00----- +111110001011111111111111111111111111111111111111111111 +101011--------1-----00----- +111110001011111111111111111111111111111111111111111111 +0010110010000010-0--00----- +110010010111111111111111110100110110111111111111111111 +0010111------11--0--00----- +111111111111111111111111111110111110111111111111111111 +0010111101-1001--0--00----- +111111111111111111111111111110111110111111111111111111 +00101111111-001--0--00----- +111111111111111111111111111110111110111111111111111111 +0010110011000010-0--00----- +110010110001111111111111110101110110111111111111111111 +110011------1110----00----- +110010111011111111111111111111110110111111111111111111 +001011---0-01110-0--00----- +110011111011111111111111011101110110111111111111111111 +001011--01101110-0--00----- +110011111011111111111111011101110110111111111111111111 +011111000011001-----00----- +000000000001111111111111111111111111111011110101111111 +100011--------11----00----- +110001010101111111111111111111111111111111111111111111 +001011----11-110-0--00----- +110011111011111111111111101101110110110111111111111111 +001011--1110-110-0--00----- +110011111011111111111111101101110110110111111111111111 +0010110001100010-0--00----- +101100001001001110010011111001110011111111111111111111 +011000000010001-----00----- +101100001001001111111111111111111111111111111111111111 +001011--1001-110-0--00----- +110011111011111111111111101101110110110111111111111111 +001011---101-110-0--00----- +110011111011111111111111101101110110110111111111111111 +001011011101001--0--00----- +100110000001001100001001111111001111111111111111111111 +100001--------1-1---00----- +111110000001111111111111111111111111111111111111111111 +011111001011001-1---00----- +011110000001111111111111111111111111111111111111111111 +01111100----101-1---00----- +011110000001111111111111111111111111111111111111111111 +001011--01001110-0--00----- +110001111011111111111111001101110110110111111111111111 +001011---1110010-0--00----- +110011111011111111111111101101110110110111111111111111 +001011--0001011011--00----- +110010111011111111111111110101110110111111101111111111 +0010110000010010111-00----- +110010111011111111111111110101110110111111101111111111 +001011110001011011--00----- +110010111011111111111111110100110110111111101111111111 +001011--10000110-0--00----- +110010111011111111111111110101110110111111111111111111 +110011------0110----00----- +110000111011111111111111111111110110111111111111111111 +110011--01001110----00----- +110000111011111111111111111111110110111111111111111111 +001011000001001-110-00----- +100000001011111111111111111111111111111011101111111101 +001011111101001--00-00----- +100000001011111111111111111111111111111011111111111101 +111001--------1-----00--1-- +000000000001111111111111111111111111111011111111111111 +001001--------1-----00-1--- +000000000001111111111111111111111111111011111111111111 +011110--------1-----00----- +000000000001111111111111111111111101111011111111111111 +110001--------1-----00----- +100100000001111111111111111111111111111111111111111111 diff --git a/espresso/examples/indust/mark1 b/espresso/examples/indust/mark1 new file mode 100644 index 0000000..b66c167 --- /dev/null +++ b/espresso/examples/indust/mark1 @@ -0,0 +1,133 @@ +.i 20 +.o 31 +.p 129 +0------------------- 010000000000000-11---1-00------ +0----100000000000000 010000000000000-11---1-00------ +1----010000000000000 000100000000000-11---1-00------ +1----001000000000000 100000000000000-11---1-00------ +1----000100000000000 000010000000000101---1-01------ +1-111000010000000000 000000000000010-11---1-00------ +1-110000010000000000 000000000010000-11---1-00------ +1-10-000010000000000 000000000100000-11---1-00------ +1-011000010000000000 000000001000000-11---1-00------ +1-010000010000000000 000000010000000-11---1-00------ +1-001000010000000000 000000100000000-11---1-00------ +1-000000010000000000 000001000000000-11---1-00------ +1----000001000000000 0000000000000010011--1-00------ +1----000000100000000 00000000000000100100-0-00000011 +1----000000010000000 000000000000001001---1100------ +1----000000001000000 000000000000001010---1-00------ +1----000000000100000 000000000000001001---1010000101 +1----000000000010000 000000000001000-11---1-00100000 +10---000000000001000 000000000000010-11---1-00------ +11---000000000001000 000000000000100-11---1-00------ +1----000000000000100 000000000000010-110110-00------ +1----000000000000010 000000000000001-11---1-00------ +1----000000000000001 000100000000000-110110-00------ +-----000000000000000 ------------------------------- +-----11------------- ------------------------------- +-----1-1------------ ------------------------------- +-----1--1----------- ------------------------------- +-----1---1---------- ------------------------------- +-----1----1--------- ------------------------------- +-----1-----1-------- ------------------------------- +-----1------1------- ------------------------------- +-----1-------1------ ------------------------------- +-----1--------1----- ------------------------------- +-----1---------1---- ------------------------------- +-----1----------1--- ------------------------------- +-----1-----------1-- ------------------------------- +-----1------------1- ------------------------------- +-----1-------------1 ------------------------------- +------11------------ ------------------------------- +------1-1----------- ------------------------------- +------1--1---------- ------------------------------- +------1---1--------- ------------------------------- +------1----1-------- ------------------------------- +------1-----1------- ------------------------------- +------1------1------ ------------------------------- +------1-------1----- ------------------------------- +------1--------1---- ------------------------------- +------1---------1--- ------------------------------- +------1----------1-- ------------------------------- +------1-----------1- ------------------------------- +------1------------1 ------------------------------- +-------11----------- ------------------------------- +-------1-1---------- ------------------------------- +-------1--1--------- ------------------------------- +-------1---1-------- ------------------------------- +-------1----1------- ------------------------------- +-------1-----1------ ------------------------------- +-------1------1----- ------------------------------- +-------1-------1---- ------------------------------- +-------1--------1--- ------------------------------- +-------1---------1-- ------------------------------- +-------1----------1- ------------------------------- +-------1-----------1 ------------------------------- +--------11---------- ------------------------------- +--------1-1--------- ------------------------------- +--------1--1-------- ------------------------------- +--------1---1------- ------------------------------- +--------1----1------ ------------------------------- +--------1-----1----- ------------------------------- +--------1------1---- ------------------------------- +--------1-------1--- ------------------------------- +--------1--------1-- ------------------------------- +--------1---------1- ------------------------------- +--------1----------1 ------------------------------- +---------11--------- ------------------------------- +---------1-1-------- ------------------------------- +---------1--1------- ------------------------------- +---------1---1------ ------------------------------- +---------1----1----- ------------------------------- +---------1-----1---- ------------------------------- +---------1------1--- ------------------------------- +---------1-------1-- ------------------------------- +---------1--------1- ------------------------------- +---------1---------1 ------------------------------- +----------11-------- ------------------------------- +----------1-1------- ------------------------------- +----------1--1------ ------------------------------- +----------1---1----- ------------------------------- +----------1----1---- ------------------------------- +----------1-----1--- ------------------------------- +----------1------1-- ------------------------------- +----------1-------1- ------------------------------- +----------1--------1 ------------------------------- +-----------11------- ------------------------------- +-----------1-1------ ------------------------------- +-----------1--1----- ------------------------------- +-----------1---1---- ------------------------------- +-----------1----1--- ------------------------------- +-----------1-----1-- ------------------------------- +-----------1------1- ------------------------------- +-----------1-------1 ------------------------------- +------------11------ ------------------------------- +------------1-1----- ------------------------------- +------------1--1---- ------------------------------- +------------1---1--- ------------------------------- +------------1----1-- ------------------------------- +------------1-----1- ------------------------------- +------------1------1 ------------------------------- +-------------11----- ------------------------------- +-------------1-1---- ------------------------------- +-------------1--1--- ------------------------------- +-------------1---1-- ------------------------------- +-------------1----1- ------------------------------- +-------------1-----1 ------------------------------- +--------------11---- ------------------------------- +--------------1-1--- ------------------------------- +--------------1--1-- ------------------------------- +--------------1---1- ------------------------------- +--------------1----1 ------------------------------- +---------------11--- ------------------------------- +---------------1-1-- ------------------------------- +---------------1--1- ------------------------------- +---------------1---1 ------------------------------- +----------------11-- ------------------------------- +----------------1-1- ------------------------------- +----------------1--1 ------------------------------- +-----------------11- ------------------------------- +-----------------1-1 ------------------------------- +------------------11 ------------------------------- +.e diff --git a/espresso/examples/indust/max1024 b/espresso/examples/indust/max1024 new file mode 100644 index 0000000..05e8578 --- /dev/null +++ b/espresso/examples/indust/max1024 @@ -0,0 +1,1026 @@ +.i 10 +.o 6 +0000000000 000001 +0000000001 000001 +0000000010 000001 +0000000011 000001 +0000000100 000001 +0000000101 000001 +0000000110 000010 +0000000111 000010 +0000001000 000010 +0000001001 000010 +0000001010 000010 +0000001011 000010 +0000001100 000010 +0000001101 000010 +0000001110 000010 +0000001111 000010 +0000010000 000010 +0000010001 000010 +0000010010 000010 +0000010011 000010 +0000010100 000010 +0000010101 000010 +0000010110 000010 +0000010111 000010 +0000011000 000010 +0000011001 000010 +0000011010 000011 +0000011011 000011 +0000011100 000011 +0000011101 000011 +0000011110 000011 +0000011111 000011 +0000100000 000011 +0000100001 000011 +0000100010 000011 +0000100011 000011 +0000100100 000011 +0000100101 000011 +0000100110 000011 +0000100111 000011 +0000101000 000011 +0000101001 000011 +0000101010 000011 +0000101011 000100 +0000101100 000100 +0000101101 000100 +0000101110 000100 +0000101111 000100 +0000110000 000100 +0000110001 000100 +0000110010 000100 +0000110011 000100 +0000110100 000100 +0000110101 000100 +0000110110 000100 +0000110111 000100 +0000111000 000100 +0000111001 000101 +0000111010 000101 +0000111011 000101 +0000111100 000101 +0000111101 000101 +0000111110 000101 +0000111111 000101 +0001000000 000101 +0001000001 000101 +0001000010 000101 +0001000011 000101 +0001000100 000101 +0001000101 000101 +0001000110 000110 +0001000111 000110 +0001001000 000110 +0001001001 000110 +0001001010 000110 +0001001011 000110 +0001001100 000110 +0001001101 000110 +0001001110 000110 +0001001111 000110 +0001010000 000110 +0001010001 000111 +0001010010 000111 +0001010011 000111 +0001010100 000111 +0001010101 000111 +0001010110 000111 +0001010111 000111 +0001011000 000111 +0001011001 000111 +0001011010 000111 +0001011011 000111 +0001011100 001000 +0001011101 001000 +0001011110 001000 +0001011111 001000 +0001100000 001000 +0001100001 001000 +0001100010 001000 +0001100011 001000 +0001100100 001000 +0001100101 001001 +0001100110 001001 +0001100111 001001 +0001101000 001001 +0001101001 001001 +0001101010 001001 +0001101011 001001 +0001101100 001001 +0001101101 001001 +0001101110 001001 +0001101111 001010 +0001110000 001010 +0001110001 001010 +0001110010 001010 +0001110011 001010 +0001110100 001010 +0001110101 001010 +0001110110 001010 +0001110111 001011 +0001111000 001011 +0001111001 001011 +0001111010 001011 +0001111011 001011 +0001111100 001011 +0001111101 001011 +0001111110 001011 +0001111111 001011 +0010000000 001100 +0010000001 001100 +0010000010 001100 +0010000011 001100 +0010000100 001100 +0010000101 001100 +0010000110 001100 +0010000111 001101 +0010001000 001101 +0010001001 001101 +0010001010 001101 +0010001011 001101 +0010001100 001101 +0010001101 001101 +0010001110 001101 +0010001111 001110 +0010010000 001110 +0010010001 001110 +0010010010 001110 +0010010011 001110 +0010010100 001110 +0010010101 001110 +0010010110 001111 +0010010111 001111 +0010011000 001111 +0010011001 001111 +0010011010 001111 +0010011011 001111 +0010011100 001111 +0010011101 001111 +0010011110 010000 +0010011111 010000 +0010100000 010000 +0010100001 010000 +0010100010 010000 +0010100011 010000 +0010100100 010001 +0010100101 010001 +0010100110 010001 +0010100111 010001 +0010101000 010001 +0010101001 010001 +0010101010 010001 +0010101011 010010 +0010101100 010010 +0010101101 010010 +0010101110 010010 +0010101111 010010 +0010110000 010010 +0010110001 010010 +0010110010 010011 +0010110011 010011 +0010110100 010011 +0010110101 010011 +0010110110 010011 +0010110111 010011 +0010111000 010100 +0010111001 010100 +0010111010 010100 +0010111011 010100 +0010111100 010100 +0010111101 010100 +0010111110 010101 +0010111111 010101 +0011000000 010101 +0011000001 010101 +0011000010 010101 +0011000011 010101 +0011000100 010101 +0011000101 010110 +0011000110 010110 +0011000111 010110 +0011001000 010110 +0011001001 010110 +0011001010 010110 +0011001011 010111 +0011001100 010111 +0011001101 010111 +0011001110 010111 +0011001111 010111 +0011010000 010111 +0011010001 011000 +0011010010 011000 +0011010011 011000 +0011010100 011000 +0011010101 011000 +0011010110 011000 +0011010111 011001 +0011011000 011001 +0011011001 011001 +0011011010 011001 +0011011011 011001 +0011011100 011010 +0011011101 011010 +0011011110 011010 +0011011111 011010 +0011100000 011010 +0011100001 011010 +0011100010 011011 +0011100011 011011 +0011100100 011011 +0011100101 011011 +0011100110 011011 +0011100111 011011 +0011101000 011100 +0011101001 011100 +0011101010 011100 +0011101011 011100 +0011101100 011100 +0011101101 011101 +0011101110 011101 +0011101111 011101 +0011110000 011101 +0011110001 011101 +0011110010 011101 +0011110011 011110 +0011110100 011110 +0011110101 011110 +0011110110 011110 +0011110111 011110 +0011111000 011110 +0011111001 011111 +0011111010 011111 +0011111011 011111 +0011111100 011111 +0011111101 011111 +0011111110 100000 +0011111111 100000 +0100000000 100000 +0100000001 100000 +0100000010 100000 +0100000011 100000 +0100000100 100001 +0100000101 100001 +0100000110 100001 +0100000111 100001 +0100001000 100001 +0100001001 100010 +0100001010 100010 +0100001011 100010 +0100001100 100010 +0100001101 100010 +0100001110 100010 +0100001111 100011 +0100010000 100011 +0100010001 100011 +0100010010 100011 +0100010011 100011 +0100010100 100100 +0100010101 100100 +0100010110 100100 +0100010111 100100 +0100011000 100100 +0100011001 100100 +0100011010 100101 +0100011011 100101 +0100011100 100101 +0100011101 100101 +0100011110 100101 +0100011111 100110 +0100100000 100110 +0100100001 100110 +0100100010 100110 +0100100011 100110 +0100100100 100110 +0100100101 100111 +0100100110 100111 +0100100111 100111 +0100101000 100111 +0100101001 100111 +0100101010 101000 +0100101011 101000 +0100101100 101000 +0100101101 101000 +0100101110 101000 +0100101111 101000 +0100110000 101001 +0100110001 101001 +0100110010 101001 +0100110011 101001 +0100110100 101001 +0100110101 101010 +0100110110 101010 +0100110111 101010 +0100111000 101010 +0100111001 101010 +0100111010 101010 +0100111011 101011 +0100111100 101011 +0100111101 101011 +0100111110 101011 +0100111111 101011 +0101000000 101011 +0101000001 101100 +0101000010 101100 +0101000011 101100 +0101000100 101100 +0101000101 101100 +0101000110 101101 +0101000111 101101 +0101001000 101101 +0101001001 101101 +0101001010 101101 +0101001011 101101 +0101001100 101110 +0101001101 101110 +0101001110 101110 +0101001111 101110 +0101010000 101110 +0101010001 101110 +0101010010 101111 +0101010011 101111 +0101010100 101111 +0101010101 101111 +0101010110 101111 +0101010111 101111 +0101011000 110000 +0101011001 110000 +0101011010 110000 +0101011011 110000 +0101011100 110000 +0101011101 110000 +0101011110 110001 +0101011111 110001 +0101100000 110001 +0101100001 110001 +0101100010 110001 +0101100011 110001 +0101100100 110001 +0101100101 110010 +0101100110 110010 +0101100111 110010 +0101101000 110010 +0101101001 110010 +0101101010 110010 +0101101011 110011 +0101101100 110011 +0101101101 110011 +0101101110 110011 +0101101111 110011 +0101110000 110011 +0101110001 110011 +0101110010 110100 +0101110011 110100 +0101110100 110100 +0101110101 110100 +0101110110 110100 +0101110111 110100 +0101111000 110100 +0101111001 110101 +0101111010 110101 +0101111011 110101 +0101111100 110101 +0101111101 110101 +0101111110 110101 +0101111111 110101 +0110000000 110110 +0110000001 110110 +0110000010 110110 +0110000011 110110 +0110000100 110110 +0110000101 110110 +0110000110 110110 +0110000111 110111 +0110001000 110111 +0110001001 110111 +0110001010 110111 +0110001011 110111 +0110001100 110111 +0110001101 110111 +0110001110 110111 +0110001111 111000 +0110010000 111000 +0110010001 111000 +0110010010 111000 +0110010011 111000 +0110010100 111000 +0110010101 111000 +0110010110 111000 +0110010111 111001 +0110011000 111001 +0110011001 111001 +0110011010 111001 +0110011011 111001 +0110011100 111001 +0110011101 111001 +0110011110 111001 +0110011111 111001 +0110100000 111010 +0110100001 111010 +0110100010 111010 +0110100011 111010 +0110100100 111010 +0110100101 111010 +0110100110 111010 +0110100111 111010 +0110101000 111010 +0110101001 111011 +0110101010 111011 +0110101011 111011 +0110101100 111011 +0110101101 111011 +0110101110 111011 +0110101111 111011 +0110110000 111011 +0110110001 111011 +0110110010 111011 +0110110011 111011 +0110110100 111100 +0110110101 111100 +0110110110 111100 +0110110111 111100 +0110111000 111100 +0110111001 111100 +0110111010 111100 +0110111011 111100 +0110111100 111100 +0110111101 111100 +0110111110 111100 +0110111111 111100 +0111000000 111101 +0111000001 111101 +0111000010 111101 +0111000011 111101 +0111000100 111101 +0111000101 111101 +0111000110 111101 +0111000111 111101 +0111001000 111101 +0111001001 111101 +0111001010 111101 +0111001011 111101 +0111001100 111101 +0111001101 111101 +0111001110 111110 +0111001111 111110 +0111010000 111110 +0111010001 111110 +0111010010 111110 +0111010011 111110 +0111010100 111110 +0111010101 111110 +0111010110 111110 +0111010111 111110 +0111011000 111110 +0111011001 111110 +0111011010 111110 +0111011011 111110 +0111011100 111110 +0111011101 111110 +0111011110 111110 +0111011111 111110 +0111100000 111110 +0111100001 111110 +0111100010 111110 +0111100011 111111 +0111100100 111111 +0111100101 111111 +0111100110 111111 +0111100111 111111 +0111101000 111111 +0111101001 111111 +0111101010 111111 +0111101011 111111 +0111101100 111111 +0111101101 111111 +0111101110 111111 +0111101111 111111 +0111110000 111111 +0111110001 111111 +0111110010 111111 +0111110011 111111 +0111110100 111111 +0111110101 111111 +0111110110 111111 +0111110111 111111 +0111111000 111111 +0111111001 111111 +0111111010 111111 +0111111011 111111 +0111111100 111111 +0111111101 111111 +0111111110 111111 +0111111111 111111 +1000000000 111111 +1000000001 111111 +1000000010 111111 +1000000011 111111 +1000000100 111111 +1000000101 111111 +1000000110 111111 +1000000111 111111 +1000001000 111111 +1000001001 111111 +1000001010 111111 +1000001011 111111 +1000001100 111111 +1000001101 111111 +1000001110 111111 +1000001111 111111 +1000010000 111111 +1000010001 111111 +1000010010 111111 +1000010011 111111 +1000010100 111111 +1000010101 111111 +1000010110 111111 +1000010111 111111 +1000011000 111111 +1000011001 111111 +1000011010 111111 +1000011011 111111 +1000011100 111111 +1000011101 111110 +1000011110 111110 +1000011111 111110 +1000100000 111110 +1000100001 111110 +1000100010 111110 +1000100011 111110 +1000100100 111110 +1000100101 111110 +1000100110 111110 +1000100111 111110 +1000101000 111110 +1000101001 111110 +1000101010 111110 +1000101011 111110 +1000101100 111110 +1000101101 111110 +1000101110 111110 +1000101111 111110 +1000110000 111110 +1000110001 111110 +1000110010 111101 +1000110011 111101 +1000110100 111101 +1000110101 111101 +1000110110 111101 +1000110111 111101 +1000111000 111101 +1000111001 111101 +1000111010 111101 +1000111011 111101 +1000111100 111101 +1000111101 111101 +1000111110 111101 +1000111111 111101 +1001000000 111100 +1001000001 111100 +1001000010 111100 +1001000011 111100 +1001000100 111100 +1001000101 111100 +1001000110 111100 +1001000111 111100 +1001001000 111100 +1001001001 111100 +1001001010 111100 +1001001011 111100 +1001001100 111011 +1001001101 111011 +1001001110 111011 +1001001111 111011 +1001010000 111011 +1001010001 111011 +1001010010 111011 +1001010011 111011 +1001010100 111011 +1001010101 111011 +1001010110 111011 +1001010111 111010 +1001011000 111010 +1001011001 111010 +1001011010 111010 +1001011011 111010 +1001011100 111010 +1001011101 111010 +1001011110 111010 +1001011111 111010 +1001100000 111001 +1001100001 111001 +1001100010 111001 +1001100011 111001 +1001100100 111001 +1001100101 111001 +1001100110 111001 +1001100111 111001 +1001101000 111001 +1001101001 111000 +1001101010 111000 +1001101011 111000 +1001101100 111000 +1001101101 111000 +1001101110 111000 +1001101111 111000 +1001110000 111000 +1001110001 110111 +1001110010 110111 +1001110011 110111 +1001110100 110111 +1001110101 110111 +1001110110 110111 +1001110111 110111 +1001111000 110111 +1001111001 110110 +1001111010 110110 +1001111011 110110 +1001111100 110110 +1001111101 110110 +1001111110 110110 +1001111111 110110 +1010000000 110101 +1010000001 110101 +1010000010 110101 +1010000011 110101 +1010000100 110101 +1010000101 110101 +1010000110 110101 +1010000111 110100 +1010001000 110100 +1010001001 110100 +1010001010 110100 +1010001011 110100 +1010001100 110100 +1010001101 110100 +1010001110 110011 +1010001111 110011 +1010010000 110011 +1010010001 110011 +1010010010 110011 +1010010011 110011 +1010010100 110011 +1010010101 110010 +1010010110 110010 +1010010111 110010 +1010011000 110010 +1010011001 110010 +1010011010 110010 +1010011011 110001 +1010011100 110001 +1010011101 110001 +1010011110 110001 +1010011111 110001 +1010100000 110001 +1010100001 110001 +1010100010 110000 +1010100011 110000 +1010100100 110000 +1010100101 110000 +1010100110 110000 +1010100111 110000 +1010101000 101111 +1010101001 101111 +1010101010 101111 +1010101011 101111 +1010101100 101111 +1010101101 101111 +1010101110 101110 +1010101111 101110 +1010110000 101110 +1010110001 101110 +1010110010 101110 +1010110011 101110 +1010110100 101101 +1010110101 101101 +1010110110 101101 +1010110111 101101 +1010111000 101101 +1010111001 101101 +1010111010 101100 +1010111011 101100 +1010111100 101100 +1010111101 101100 +1010111110 101100 +1010111111 101011 +1011000000 101011 +1011000001 101011 +1011000010 101011 +1011000011 101011 +1011000100 101011 +1011000101 101010 +1011000110 101010 +1011000111 101010 +1011001000 101010 +1011001001 101010 +1011001010 101010 +1011001011 101001 +1011001100 101001 +1011001101 101001 +1011001110 101001 +1011001111 101001 +1011010000 101000 +1011010001 101000 +1011010010 101000 +1011010011 101000 +1011010100 101000 +1011010101 101000 +1011010110 100111 +1011010111 100111 +1011011000 100111 +1011011001 100111 +1011011010 100111 +1011011011 100110 +1011011100 100110 +1011011101 100110 +1011011110 100110 +1011011111 100110 +1011100000 100110 +1011100001 100101 +1011100010 100101 +1011100011 100101 +1011100100 100101 +1011100101 100101 +1011100110 100100 +1011100111 100100 +1011101000 100100 +1011101001 100100 +1011101010 100100 +1011101011 100100 +1011101100 100011 +1011101101 100011 +1011101110 100011 +1011101111 100011 +1011110000 100011 +1011110001 100010 +1011110010 100010 +1011110011 100010 +1011110100 100010 +1011110101 100010 +1011110110 100010 +1011110111 100001 +1011111000 100001 +1011111001 100001 +1011111010 100001 +1011111011 100001 +1011111100 100000 +1011111101 100000 +1011111110 100000 +1011111111 100000 +1100000000 100000 +1100000001 100000 +1100000010 011111 +1100000011 011111 +1100000100 011111 +1100000101 011111 +1100000110 011111 +1100000111 011110 +1100001000 011110 +1100001001 011110 +1100001010 011110 +1100001011 011110 +1100001100 011110 +1100001101 011101 +1100001110 011101 +1100001111 011101 +1100010000 011101 +1100010001 011101 +1100010010 011101 +1100010011 011100 +1100010100 011100 +1100010101 011100 +1100010110 011100 +1100010111 011100 +1100011000 011011 +1100011001 011011 +1100011010 011011 +1100011011 011011 +1100011100 011011 +1100011101 011011 +1100011110 011010 +1100011111 011010 +1100100000 011010 +1100100001 011010 +1100100010 011010 +1100100011 011010 +1100100100 011001 +1100100101 011001 +1100100110 011001 +1100100111 011001 +1100101000 011001 +1100101001 011000 +1100101010 011000 +1100101011 011000 +1100101100 011000 +1100101101 011000 +1100101110 011000 +1100101111 010111 +1100110000 010111 +1100110001 010111 +1100110010 010111 +1100110011 010111 +1100110100 010111 +1100110101 010110 +1100110110 010110 +1100110111 010110 +1100111000 010110 +1100111001 010110 +1100111010 010110 +1100111011 010101 +1100111100 010101 +1100111101 010101 +1100111110 010101 +1100111111 010101 +1101000000 010101 +1101000001 010101 +1101000010 010100 +1101000011 010100 +1101000100 010100 +1101000101 010100 +1101000110 010100 +1101000111 010100 +1101001000 010011 +1101001001 010011 +1101001010 010011 +1101001011 010011 +1101001100 010011 +1101001101 010011 +1101001110 010010 +1101001111 010010 +1101010000 010010 +1101010001 010010 +1101010010 010010 +1101010011 010010 +1101010100 010010 +1101010101 010001 +1101010110 010001 +1101010111 010001 +1101011000 010001 +1101011001 010001 +1101011010 010001 +1101011011 010001 +1101011100 010000 +1101011101 010000 +1101011110 010000 +1101011111 010000 +1101100000 010000 +1101100001 010000 +1101100010 001111 +1101100011 001111 +1101100100 001111 +1101100101 001111 +1101100110 001111 +1101100111 001111 +1101101000 001111 +1101101001 001111 +1101101010 001110 +1101101011 001110 +1101101100 001110 +1101101101 001110 +1101101110 001110 +1101101111 001110 +1101110000 001110 +1101110001 001101 +1101110010 001101 +1101110011 001101 +1101110100 001101 +1101110101 001101 +1101110110 001101 +1101110111 001101 +1101111000 001101 +1101111001 001100 +1101111010 001100 +1101111011 001100 +1101111100 001100 +1101111101 001100 +1101111110 001100 +1101111111 001100 +1110000000 001011 +1110000001 001011 +1110000010 001011 +1110000011 001011 +1110000100 001011 +1110000101 001011 +1110000110 001011 +1110000111 001011 +1110001000 001011 +1110001001 001010 +1110001010 001010 +1110001011 001010 +1110001100 001010 +1110001101 001010 +1110001110 001010 +1110001111 001010 +1110010000 001010 +1110010001 001001 +1110010010 001001 +1110010011 001001 +1110010100 001001 +1110010101 001001 +1110010110 001001 +1110010111 001001 +1110011000 001001 +1110011001 001001 +1110011010 001001 +1110011011 001000 +1110011100 001000 +1110011101 001000 +1110011110 001000 +1110011111 001000 +1110100000 001000 +1110100001 001000 +1110100010 001000 +1110100011 001000 +1110100100 000111 +1110100101 000111 +1110100110 000111 +1110100111 000111 +1110101000 000111 +1110101001 000111 +1110101010 000111 +1110101011 000111 +1110101100 000111 +1110101101 000111 +1110101110 000111 +1110101111 000110 +1110110000 000110 +1110110001 000110 +1110110010 000110 +1110110011 000110 +1110110100 000110 +1110110101 000110 +1110110110 000110 +1110110111 000110 +1110111000 000110 +1110111001 000110 +1110111010 000101 +1110111011 000101 +1110111100 000101 +1110111101 000101 +1110111110 000101 +1110111111 000101 +1111000000 000101 +1111000001 000101 +1111000010 000101 +1111000011 000101 +1111000100 000101 +1111000101 000101 +1111000110 000101 +1111000111 000100 +1111001000 000100 +1111001001 000100 +1111001010 000100 +1111001011 000100 +1111001100 000100 +1111001101 000100 +1111001110 000100 +1111001111 000100 +1111010000 000100 +1111010001 000100 +1111010010 000100 +1111010011 000100 +1111010100 000100 +1111010101 000011 +1111010110 000011 +1111010111 000011 +1111011000 000011 +1111011001 000011 +1111011010 000011 +1111011011 000011 +1111011100 000011 +1111011101 000011 +1111011110 000011 +1111011111 000011 +1111100000 000011 +1111100001 000011 +1111100010 000011 +1111100011 000011 +1111100100 000011 +1111100101 000011 +1111100110 000010 +1111100111 000010 +1111101000 000010 +1111101001 000010 +1111101010 000010 +1111101011 000010 +1111101100 000010 +1111101101 000010 +1111101110 000010 +1111101111 000010 +1111110000 000010 +1111110001 000010 +1111110010 000010 +1111110011 000010 +1111110100 000010 +1111110101 000010 +1111110110 000010 +1111110111 000010 +1111111000 000010 +1111111001 000010 +1111111010 000001 +1111111011 000001 +1111111100 000001 +1111111101 000001 +1111111110 000001 +1111111111 000001 diff --git a/espresso/examples/indust/max128 b/espresso/examples/indust/max128 new file mode 100644 index 0000000..25816ad --- /dev/null +++ b/espresso/examples/indust/max128 @@ -0,0 +1,130 @@ +.i 7 +.o 24 +0000000 000001100000100000111111 +0000001 000001100000100000111111 +0000010 000001011111100000111111 +0000011 000001011111100000111111 +0000100 000001011111100001111111 +0000101 000001011111100001111111 +0000110 000010011111100001111111 +0000111 000010011110100001111111 +0001000 000010011110100001111111 +0001001 000010011110100010111111 +0001010 000010011110100010111111 +0001011 000010011110100010111111 +0001100 000010011110100010111111 +0001101 000010011101100010111111 +0001110 000010011101100010111111 +0001111 000010011101100011111111 +0010000 000010011101100011111111 +0010001 000010011101100011111111 +0010010 000010011101100011111111 +0010011 000010011100100011111111 +0010100 000010011100100100111111 +0010101 000010011100100100111111 +0010110 000010011100100100111111 +0010111 000010011100100100111111 +0011000 000010011011100100111111 +0011001 000010011011100100111111 +0011010 000011011011100101111111 +0011011 000011011011100101111111 +0011100 000011011011100101111111 +0011101 000011011011100101111110 +0011110 000011011010100101111110 +0011111 000011011010100110111110 +0100000 000011011010100110111110 +0100001 000011011010100110111110 +0100010 000011011010100110111110 +0100011 000011011010100110111110 +0100100 000011011001100110111110 +0100101 000011011001100111111110 +0100110 000011011001100111111110 +0100111 000011011001100111111110 +0101000 000011011001100111111110 +0101001 000011011000100111111110 +0101010 000011011000101000111110 +0101011 000100011000101000111110 +0101100 000100011000101000111110 +0101101 000100011000101000111110 +0101110 000100011000101000111110 +0101111 000100010111101000111110 +0110000 000100010111101001111110 +0110001 000100010111101001111110 +0110010 000100010111101001111101 +0110011 000100010111101001111101 +0110100 000100010111101001111101 +0110101 000100010110101010111101 +0110110 000100010110101010111101 +0110111 000100010110101010111101 +0111000 000100010110101010111101 +0111001 000101010110101010111101 +0111010 000101010110101010111101 +0111011 000101010101101011111101 +0111100 000101010101101011111101 +0111101 000101010101101011111101 +0111110 000101010101101011111101 +0111111 000101010101101011111101 +1000000 000101010101101011111100 +1000001 000101010101101100111100 +1000010 000101010100101100111100 +1000011 000101010100101100111100 +1000100 000101010100101100111100 +1000101 000101010100101100111100 +1000110 000110010100101101111100 +1000111 000110010100101101111100 +1001000 000110010011101101111100 +1001001 000110010011101101111100 +1001010 000110010011101101111100 +1001011 000110010011101101111100 +1001100 000110010011101110111011 +1001101 000110010011101110111011 +1001110 000110010010101110111011 +1001111 000110010010101110111011 +1010000 000110010010101110111011 +1010001 000111010010101110111011 +1010010 000111010010101111111011 +1010011 000111010010101111111011 +1010100 000111010010101111111011 +1010101 000111010001101111111011 +1010110 000111010001101111111011 +1010111 000111010001101111111010 +1011000 000111010001110000111010 +1011001 000111010001110000111010 +1011010 000111010001110000111010 +1011011 000111010001110000111010 +1011100 001000010000110000111010 +1011101 001000010000110000111010 +1011110 001000010000110001111010 +1011111 001000010000110001111010 +1100000 001000010000110001111001 +1100001 001000010000110001111001 +1100010 001000001111110001111001 +1100011 001000001111110001111001 +1100100 001000001111110001111001 +1100101 001001001111110010111001 +1100110 001001001111110010111001 +1100111 001001001111110010111001 +1101000 001001001111110010111001 +1101001 001001001111110010111000 +1101010 001001001110110010111000 +1101011 001001001110110011111000 +1101100 001001001110110011111000 +1101101 001001001110110011111000 +1101110 001001001110110011111000 +1101111 001010001110110011111000 +1110000 001010001110110011111000 +1110001 001010001101110011110111 +1110010 001010001101110100110111 +1110011 001010001101110100110111 +1110100 001010001101110100110111 +1110101 001010001101110100110111 +1110110 001010001101110100110111 +1110111 001011001101110100110111 +1111000 001011001101110100110111 +1111001 001011001100110101110110 +1111010 001011001100110101110110 +1111011 001011001100110101110110 +1111100 001011001100110101110110 +1111101 001011001100110101110110 +1111110 001011001100110101110110 +1111111 001011001100110101110110 diff --git a/espresso/examples/indust/max46 b/espresso/examples/indust/max46 new file mode 100644 index 0000000..8d6cc80 --- /dev/null +++ b/espresso/examples/indust/max46 @@ -0,0 +1,50 @@ +.i 9 +.o 1 +.p 46 +-10000000 1 +101111001 1 +011111001 1 +010111000 1 +000111001 1 +100110000 1 +011101000 1 +101011000 1 +110110100 1 +0-1011100 1 +101-10010 1 +01-111110 1 +0-1010001 1 +110101001 1 +1001-0101 1 +011101101 1 +011110011 1 +100111011 1 +110-00000 1 +010110010 1 +-01100101 1 +101101011 1 +001110111 1 +11-000000 1 +010100100 1 +1000-0100 1 +101001100 1 +011100010 1 +100101010 1 +-00011010 1 +101011110 1 +101000001 1 +100001001 1 +111100011 1 +0-0101011 1 +001101111 1 +01001-110 1 +011000101 1 +011001011 1 +011010111 1 +1000-1111 1 +111001110 1 +1100-0111 1 +-01000110 1 +-1000-111 1 +00-000110 1 +.e diff --git a/espresso/examples/indust/max512 b/espresso/examples/indust/max512 new file mode 100644 index 0000000..8bd167e --- /dev/null +++ b/espresso/examples/indust/max512 @@ -0,0 +1,514 @@ +.i 9 +.o 6 +000000000 000001 +000000001 000001 +000000010 000001 +000000011 000001 +000000100 000001 +000000101 000001 +000000110 000010 +000000111 000010 +000001000 000010 +000001001 000010 +000001010 000010 +000001011 000010 +000001100 000010 +000001101 000010 +000001110 000010 +000001111 000010 +000010000 000010 +000010001 000010 +000010010 000010 +000010011 000010 +000010100 000010 +000010101 000010 +000010110 000010 +000010111 000010 +000011000 000010 +000011001 000010 +000011010 000011 +000011011 000011 +000011100 000011 +000011101 000011 +000011110 000011 +000011111 000011 +000100000 000011 +000100001 000011 +000100010 000011 +000100011 000011 +000100100 000011 +000100101 000011 +000100110 000011 +000100111 000011 +000101000 000011 +000101001 000011 +000101010 000011 +000101011 000100 +000101100 000100 +000101101 000100 +000101110 000100 +000101111 000100 +000110000 000100 +000110001 000100 +000110010 000100 +000110011 000100 +000110100 000100 +000110101 000100 +000110110 000100 +000110111 000100 +000111000 000100 +000111001 000101 +000111010 000101 +000111011 000101 +000111100 000101 +000111101 000101 +000111110 000101 +000111111 000101 +001000000 000101 +001000001 000101 +001000010 000101 +001000011 000101 +001000100 000101 +001000101 000101 +001000110 000110 +001000111 000110 +001001000 000110 +001001001 000110 +001001010 000110 +001001011 000110 +001001100 000110 +001001101 000110 +001001110 000110 +001001111 000110 +001010000 000110 +001010001 000111 +001010010 000111 +001010011 000111 +001010100 000111 +001010101 000111 +001010110 000111 +001010111 000111 +001011000 000111 +001011001 000111 +001011010 000111 +001011011 000111 +001011100 001000 +001011101 001000 +001011110 001000 +001011111 001000 +001100000 001000 +001100001 001000 +001100010 001000 +001100011 001000 +001100100 001000 +001100101 001001 +001100110 001001 +001100111 001001 +001101000 001001 +001101001 001001 +001101010 001001 +001101011 001001 +001101100 001001 +001101101 001001 +001101110 001001 +001101111 001010 +001110000 001010 +001110001 001010 +001110010 001010 +001110011 001010 +001110100 001010 +001110101 001010 +001110110 001010 +001110111 001011 +001111000 001011 +001111001 001011 +001111010 001011 +001111011 001011 +001111100 001011 +001111101 001011 +001111110 001011 +001111111 001011 +010000000 001100 +010000001 001100 +010000010 001100 +010000011 001100 +010000100 001100 +010000101 001100 +010000110 001100 +010000111 001101 +010001000 001101 +010001001 001101 +010001010 001101 +010001011 001101 +010001100 001101 +010001101 001101 +010001110 001101 +010001111 001110 +010010000 001110 +010010001 001110 +010010010 001110 +010010011 001110 +010010100 001110 +010010101 001110 +010010110 001111 +010010111 001111 +010011000 001111 +010011001 001111 +010011010 001111 +010011011 001111 +010011100 001111 +010011101 001111 +010011110 010000 +010011111 010000 +010100000 010000 +010100001 010000 +010100010 010000 +010100011 010000 +010100100 010001 +010100101 010001 +010100110 010001 +010100111 010001 +010101000 010001 +010101001 010001 +010101010 010001 +010101011 010010 +010101100 010010 +010101101 010010 +010101110 010010 +010101111 010010 +010110000 010010 +010110001 010010 +010110010 010011 +010110011 010011 +010110100 010011 +010110101 010011 +010110110 010011 +010110111 010011 +010111000 010100 +010111001 010100 +010111010 010100 +010111011 010100 +010111100 010100 +010111101 010100 +010111110 010101 +010111111 010101 +011000000 010101 +011000001 010101 +011000010 010101 +011000011 010101 +011000100 010101 +011000101 010110 +011000110 010110 +011000111 010110 +011001000 010110 +011001001 010110 +011001010 010110 +011001011 010111 +011001100 010111 +011001101 010111 +011001110 010111 +011001111 010111 +011010000 010111 +011010001 011000 +011010010 011000 +011010011 011000 +011010100 011000 +011010101 011000 +011010110 011000 +011010111 011001 +011011000 011001 +011011001 011001 +011011010 011001 +011011011 011001 +011011100 011010 +011011101 011010 +011011110 011010 +011011111 011010 +011100000 011010 +011100001 011010 +011100010 011011 +011100011 011011 +011100100 011011 +011100101 011011 +011100110 011011 +011100111 011011 +011101000 011100 +011101001 011100 +011101010 011100 +011101011 011100 +011101100 011100 +011101101 011101 +011101110 011101 +011101111 011101 +011110000 011101 +011110001 011101 +011110010 011101 +011110011 011110 +011110100 011110 +011110101 011110 +011110110 011110 +011110111 011110 +011111000 011110 +011111001 011111 +011111010 011111 +011111011 011111 +011111100 011111 +011111101 011111 +011111110 100000 +011111111 100000 +100000000 100000 +100000001 100000 +100000010 100000 +100000011 100000 +100000100 100001 +100000101 100001 +100000110 100001 +100000111 100001 +100001000 100001 +100001001 100010 +100001010 100010 +100001011 100010 +100001100 100010 +100001101 100010 +100001110 100010 +100001111 100011 +100010000 100011 +100010001 100011 +100010010 100011 +100010011 100011 +100010100 100100 +100010101 100100 +100010110 100100 +100010111 100100 +100011000 100100 +100011001 100100 +100011010 100101 +100011011 100101 +100011100 100101 +100011101 100101 +100011110 100101 +100011111 100110 +100100000 100110 +100100001 100110 +100100010 100110 +100100011 100110 +100100100 100110 +100100101 100111 +100100110 100111 +100100111 100111 +100101000 100111 +100101001 100111 +100101010 101000 +100101011 101000 +100101100 101000 +100101101 101000 +100101110 101000 +100101111 101000 +100110000 101001 +100110001 101001 +100110010 101001 +100110011 101001 +100110100 101001 +100110101 101010 +100110110 101010 +100110111 101010 +100111000 101010 +100111001 101010 +100111010 101010 +100111011 101011 +100111100 101011 +100111101 101011 +100111110 101011 +100111111 101011 +101000000 101011 +101000001 101100 +101000010 101100 +101000011 101100 +101000100 101100 +101000101 101100 +101000110 101101 +101000111 101101 +101001000 101101 +101001001 101101 +101001010 101101 +101001011 101101 +101001100 101110 +101001101 101110 +101001110 101110 +101001111 101110 +101010000 101110 +101010001 101110 +101010010 101111 +101010011 101111 +101010100 101111 +101010101 101111 +101010110 101111 +101010111 101111 +101011000 110000 +101011001 110000 +101011010 110000 +101011011 110000 +101011100 110000 +101011101 110000 +101011110 110001 +101011111 110001 +101100000 110001 +101100001 110001 +101100010 110001 +101100011 110001 +101100100 110001 +101100101 110010 +101100110 110010 +101100111 110010 +101101000 110010 +101101001 110010 +101101010 110010 +101101011 110011 +101101100 110011 +101101101 110011 +101101110 110011 +101101111 110011 +101110000 110011 +101110001 110011 +101110010 110100 +101110011 110100 +101110100 110100 +101110101 110100 +101110110 110100 +101110111 110100 +101111000 110100 +101111001 110101 +101111010 110101 +101111011 110101 +101111100 110101 +101111101 110101 +101111110 110101 +101111111 110101 +110000000 110110 +110000001 110110 +110000010 110110 +110000011 110110 +110000100 110110 +110000101 110110 +110000110 110110 +110000111 110111 +110001000 110111 +110001001 110111 +110001010 110111 +110001011 110111 +110001100 110111 +110001101 110111 +110001110 110111 +110001111 111000 +110010000 111000 +110010001 111000 +110010010 111000 +110010011 111000 +110010100 111000 +110010101 111000 +110010110 111000 +110010111 111001 +110011000 111001 +110011001 111001 +110011010 111001 +110011011 111001 +110011100 111001 +110011101 111001 +110011110 111001 +110011111 111001 +110100000 111010 +110100001 111010 +110100010 111010 +110100011 111010 +110100100 111010 +110100101 111010 +110100110 111010 +110100111 111010 +110101000 111010 +110101001 111011 +110101010 111011 +110101011 111011 +110101100 111011 +110101101 111011 +110101110 111011 +110101111 111011 +110110000 111011 +110110001 111011 +110110010 111011 +110110011 111011 +110110100 111100 +110110101 111100 +110110110 111100 +110110111 111100 +110111000 111100 +110111001 111100 +110111010 111100 +110111011 111100 +110111100 111100 +110111101 111100 +110111110 111100 +110111111 111100 +111000000 111101 +111000001 111101 +111000010 111101 +111000011 111101 +111000100 111101 +111000101 111101 +111000110 111101 +111000111 111101 +111001000 111101 +111001001 111101 +111001010 111101 +111001011 111101 +111001100 111101 +111001101 111101 +111001110 111110 +111001111 111110 +111010000 111110 +111010001 111110 +111010010 111110 +111010011 111110 +111010100 111110 +111010101 111110 +111010110 111110 +111010111 111110 +111011000 111110 +111011001 111110 +111011010 111110 +111011011 111110 +111011100 111110 +111011101 111110 +111011110 111110 +111011111 111110 +111100000 111110 +111100001 111110 +111100010 111110 +111100011 111111 +111100100 111111 +111100101 111111 +111100110 111111 +111100111 111111 +111101000 111111 +111101001 111111 +111101010 111111 +111101011 111111 +111101100 111111 +111101101 111111 +111101110 111111 +111101111 111111 +111110000 111111 +111110001 111111 +111110010 111111 +111110011 111111 +111110100 111111 +111110101 111111 +111110110 111111 +111110111 111111 +111111000 111111 +111111001 111111 +111111010 111111 +111111011 111111 +111111100 111111 +111111101 111111 +111111110 111111 +111111111 111111 diff --git a/espresso/examples/indust/misg b/espresso/examples/indust/misg new file mode 100644 index 0000000..5d10cdc --- /dev/null +++ b/espresso/examples/indust/misg @@ -0,0 +1,152 @@ +.i 56 +.o 23 +11------------------------------------------------------ +10000000000000000000000 +--11---------------------------------------------------- +10000000000000000000000 +----11-------------------------------------------------- +10000000000000000000000 +------11------------------------------------------------ +10000000000000000000000 +------------------------------------------------0------- +01000000000000000000000 +---------0---------------------------------------------- +00100000000000000000000 +----------1--------------------------------------------- +00100000000000000000000 +-----------1-1------------------------------------------ +00100000000000000000000 +--------0----------------------------------------------- +00010000000000000000000 +--------------0----------------------------------------- +00010000000000000000000 +---------------0---------------------------------------- +00001000000000000000000 +----------------0--------------------------------------- +00000100000000000000000 +-----------------0-------------------------------------- +00000010000000000000000 +------------0------------------------------------------- +00000001000000000000000 +----------1--------------------------------------------- +00000000100000000000000 +---------------------0---------------------------------- +00000000100000000000000 +----------------------0--------------------------------- +00000000100000000000000 +-------------------------------------------------0------ +00000000100000000000000 +-----------------------0-------------------------------- +00000000010000000000000 +------------------------0------------------------------- +00000000010000000000000 +------------------111----------------------------------- +00000000001000000000000 +--------------------------0----------------------------- +00000000000100000000000 +-------------------------0------------------------------ +00000000000100000000000 +----------------------------0--------------------------- +00000000000010000000000 +---------------------------1---------------------------- +00000000000010000000000 +-----------------1-------------------------------------- +00000000000010000000000 +-----------------------------0-------------------------- +00000000000001000000000 +---------------------------1---------------------------- +00000000000001000000000 +---------------------------1---------------------------- +00000000000000100000000 +-------------------------------------------------10----- +00000000000000100000000 +------------------------------1------------------------- +00000000000000010000000 +-------------------------------1------------------------ +00000000000000010000000 +---------------------------------------------------0---- +00000000000000001000000 +----------------------------------------------------0--- +00000000000000000100000 +-----------------------------------------0-------------- +00000000000000000010000 +------------------------------------------0------------- +00000000000000000010000 +----------------------------------------------0--------- +00000000000000000001000 +--------------------1------------1--------------------1- +00000000000000000001000 +--------------------------------0----------------------- +00000000000000000000100 +-----------------------------------------------0-------- +00000000000000000000100 +-------------------------------------------------0------ +00000000000000000000100 +----------------------------------0------------------0-- +00000000000000000000100 +-----------------------------------------------------00- +00000000000000000000100 +------------------------------------0-0-0--------------- +00000000000000000000100 +-----------------------------------0-0-0-------------0-- +00000000000000000000100 +-----------------------------------0-0--0------------0-- +00000000000000000000100 +-----------------------------------0--00-------------0-- +00000000000000000000100 +-----------------------------------0--0-0------------0-- +00000000000000000000100 +------------------------------------00-0-------------0-- +00000000000000000000100 +------------------------------------00--0------------0-- +00000000000000000000100 +------------------------------------0-00-------------0-- +00000000000000000000100 +----------------------------------0-0-0------0---------- +00000000000000000000100 +------------------------------------0-00-----0---------- +00000000000000000000100 +------------------------------------0-0------0--------0- +00000000000000000000100 +----------------------------------0-0---0---0----------- +00000000000000000000100 +------------------------------------00--0---0----------- +00000000000000000000100 +------------------------------------0---0---0---------0- +00000000000000000000100 +----------------------------------0-0-------00---------- +00000000000000000000100 +------------------------------------0-------00--------0- +00000000000000000000100 +----------------------------------0---0-0--0------------ +00000000000000000000100 +-----------------------------------0--0-0--0------------ +00000000000000000000100 +--------------------------------------0-0--0----------0- +00000000000000000000100 +----------------------------------0---0----0-0---------- +00000000000000000000100 +--------------------------------------0----0-0--------0- +00000000000000000000100 +----------------------------------0-----0--00----------- +00000000000000000000100 +----------------------------------------0--00---------0- +00000000000000000000100 +----------------------------------0--------000---------- +00000000000000000000100 +-------------------------------------------000--------0- +00000000000000000000100 +------------------------------------00-0----00---------- +00000000000000000000100 +-----------------------------------0--00---0-0---------- +00000000000000000000100 +-----------------------------------0-0--0--00----------- +00000000000000000000100 +-----------------------------------0-0-0---000---------- +00000000000000000000100 +-------------------------------------------------------0 +00000000000000000000010 +--------------------------------0----------------------- +00000000000000000000001 +--------------------1------------1--------------------1- +00000000000000000000001 diff --git a/espresso/examples/indust/mish b/espresso/examples/indust/mish new file mode 100644 index 0000000..d1fa170 --- /dev/null +++ b/espresso/examples/indust/mish @@ -0,0 +1,184 @@ +.i 94 +.o 43 +0------------------------------------------------------------------------- +-------------------- 1000000000000000000000000000000000000000000 +1-1110-------------------------------------------------------------------- +-------------------- 0100000000000000000000000000000000000000000 +1-1101-------------------------------------------------------------------- +-------------------- 0100000000000000000000000000000000000000000 +1-1011-------------------------------------------------------------------- +-------------------- 0100000000000000000000000000000000000000000 +1-1000-------------------------------------------------------------------- +-------------------- 0100000000000000000000000000000000000000000 +-0------------------------------------------------------------------------ +-------------------- 0100000000000000000000000000000000000000000 +---110-------------------------------------------------------------------- +-------------------- 0010000000000000000000000000000000000000000 +---101-------------------------------------------------------------------- +-------------------- 0010000000000000000000000000000000000000000 +---011-------------------------------------------------------------------- +-------------------- 0010000000000000000000000000000000000000000 +---000-------------------------------------------------------------------- +-------------------- 0010000000000000000000000000000000000000000 +------0------------------------------------------------------------------- +-------------------- 0001000000000000000000000000000000000000000 +-------0------------------------------------------------------------------ +-------------------- 0001000000000000000000000000000000000000000 +--------0----------------------------------------------------------------- +-------------------- 0001000000000000000000000000000000000000000 +---------0---------------------------------------------------------------- +-------------------- 0001000000000000000000000000000000000000000 +----------0--------------------------------------------------------------- +-------------------- 0001000000000000000000000000000000000000000 +-----------0-------------------------------------------------------------- +-------------------- 0000100000000000000000000000000000000000000 +------------01------------------------------------------------------------ +-------------------- 0000100000000000000000000000000000000000000 +--------------0----------------------------------------------------------- +-------------------- 0000010000000000000000000000000000000000000 +----------------0--------------------------------------------------------- +-------------------- 0000001000000000000000000000000000000000000 +-----------------0-------------------------------------------------------- +-------------------- 0000001000000000000000000000000000000000000 +------------------0------------------------------------------------------- +-------------------- 0000001000000000000000000000000000000000000 +-------------------0------------------------------------------------------ +-------------------- 0000001000000000000000000000000000000000000 +----------------------0--------------------------------------------------- +-------------------- 0000000100000000000000000000000000000000000 +---------------------1---------------------------------------------------- +-------------------- 0000000100000000000000000000000000000000000 +-----------------------0-------------------------------------------------- +-------------------- 0000000010000000000000000000000000000000000 +------------------------0------------------------------------------------- +-------------------- 0000000010000000000000000000000000000000000 +--------------------0----------------------------------------------------- +-------------------- 0000000001000000000000000000000000000000000 +----------------------------0--------------------------------------------- +-------------------- 0000000001000000000000000000000000000000000 +-----------------------1111----------------------------------------------- +-------------------- 0000000001000000000000000000000000000000000 +---------------------0---------------------------------------------------- +-------------------- 0000000000100000000000000000000000000000000 +-----------------------------0-------------------------------------------- +-------------------- 0000000000010000000000000000000000000000000 +-------------------------------1------------------------------------------ +-------------------- 0000000000001000000000000000000000000000000 +------------------------------1-111--------------------------------------- +-------------------- 0000000000001000000000000000000000000000000 +--------------------1--------------1-1------------------------------------ +-------------------- 0000000000000100000000000000000000000000000 +--------------------1--------------1-1------------------------------------ +-------------------- 0000000000000010000000000000000000000000000 +---------------0----1---------------1------------------------------------- +-------------------- 0000000000000010000000000000000000000000000 +--------------------1---------------1-0----------------------------------- +-------------------- 0000000000000010000000000000000000000000000 +--------------------1---------------1--0---------------------------------- +-------------------- 0000000000000010000000000000000000000000000 +--------------------1---------------1----0-------------------------------- +-------------------- 0000000000000010000000000000000000000000000 +------------------------------------------1---1--------------------------- +-------------------- 0000000000000001000000000000000000000000000 +--------------------------------------------1-1--------------------------- +-------------------- 0000000000000001000000000000000000000000000 +----------------------------------------0--------------------------------- +-------------------- 0000000000000000100000000000000000000000000 +---------------------------------------------0---------------------------- +-------------------- 0000000000000000010000000000000000000000000 +-------------------------------------------0------------------------------ +-------------------- 0000000000000000010000000000000000000000000 +---------------------------------0---------------------------------------- +-------------------- 0000000000000000010000000000000000000000000 +-----------------------------------------------0-------------------------- +-------------------- 0000000000000000010000000000000000000000000 +------------------------------------------------0------------------------- +-------------------- 0000000000000000001000000000000000000000000 +-------------------------------------------------0------------------------ +-------------------- 0000000000000000001000000000000000000000000 +--------------------------------------------------0----------------------- +-------------------- 0000000000000000001000000000000000000000000 +---------------------------------------------------0---------------------- +-------------------- 0000000000000000001000000000000000000000000 +----------------------------------------------------0--------------------- +-------------------- 0000000000000000001000000000000000000000000 +------------------------------------------------------0------------------- +-------------------- 0000000000000000000100000000000000000000000 +-------------------------------------------------------0------------------ +-------------------- 0000000000000000000100000000000000000000000 +--------------------------------------------------------0----------------- +-------------------- 0000000000000000000100000000000000000000000 +-----------------------------------------------------0-------------------- +-------------------- 0000000000000000000010000000000000000000000 +---------------------------------------------------------0---------------- +-------------------- 0000000000000000000010000000000000000000000 +--------------------------------------------------------------0----------- +-------------------- 0000000000000000000001000000000000000000000 +---------------------------------------------------------------0---------- +-------------------- 0000000000000000000001000000000000000000000 +----------------------------------------------------------------0--------- +-------------------- 0000000000000000000001000000000000000000000 +-----------------------------------------------------------------0-------- +-------------------- 0000000000000000000001000000000000000000000 +------------------------------------------------------------------0------- +-------------------- 0000000000000000000001000000000000000000000 +--------------------------------------------------------------------0----- +-------------------- 0000000000000000000000100000000000000000000 +------------0----------------------------------------------000-----1------ +-------------------- 0000000000000000000000100000000000000000000 +-----------------------------------------------------0-------------------- +-------------------- 0000000000000000000000010000000000000000000 +----------------------------------------------------------0--------------- +-------------------- 0000000000000000000000010000000000000000000 +---------------------------------------------------------------------0---- +-------------------- 0000000000000000000000010000000000000000000 +-----------0-------------------------------------------------------------- +-------------------- 0000000000000000000000001000000000000000000 +----------------------------------------------------------------------0--- +-------------------- 0000000000000000000000000100000000000000000 +-----------------------------------------------------------------------0-- +-------------------- 0000000000000000000000000100000000000000000 +------------------------------------------------------------------------0- +-------------------- 0000000000000000000000000100000000000000000 +-------------------------------------------------------------------------0 +-------------------- 0000000000000000000000000100000000000000000 +---------------------0---------------------------------------------------- +1-1----------------- 0000000000000000000000000010000000000000000 +-------------------------------------------------------------------------- +11-1---------------- 0000000000000000000000000010000000000000000 +-----------------------------------------------------1-------------------- +-------011---------- 0000000000000000000000000001000000000000000 +-----------------------------------------------------1-------------------- +--------110--------- 0000000000000000000000000001000000000000000 +---------------------------1-------------------------1-------------------- +-------------------- 0000000000000000000000000000100000000000000 +-----------------------------------------------------1-------------------- +-------011---------- 0000000000000000000000000000100000000000000 +-----------------------------------------------------1-------------------- +--------110--------- 0000000000000000000000000000100000000000000 +-------------------------------------------------------0------------------ +-------------------- 0000000000000000000000000000010000000000000 +-------------------------------------------------------------------------- +------0------------- 0000000000000000000000000000010000000000000 +-------------------------------------------------------------------------- +-----------0-------- 0000000000000000000000000000010000000000000 +-----------------------------------------------------0-------------------- +-------------------- 0000000000000000000000000000001000000000000 +-------------------------------------------------------------------------- +-----0-------------- 0000000000000000000000000000001000000000000 +-------------------------------------------------------------------------- +------------0------- 0000000000000000000000000000001000000000000 +-------------------------------------------------------------------------- +----0--------------- 0000000000000000000000000000000100000000000 +-------------------------------------------------------0------------------ +-------------------- 0000000000000000000000000000000100000000000 +-------------------------------------------------------------------------- +--------0----------- 0000000000000000000000000000000100000000000 +-------------------------------------------------------------------------- +-----------0-------- 0000000000000000000000000000000100000000000 +--------------------------------------0----------------------------------- +-------------------- 0000000000000000000000000000000010000000000 +---------------1-------------------------1-------------------------------- +-------------1111--- 0000000000000000000000000000000010000000000 +-------------------------------------------------------------------------- +-----------------111 0000000000000000000000000000000001000000000 diff --git a/espresso/examples/indust/misj b/espresso/examples/indust/misj new file mode 100644 index 0000000..38d69db --- /dev/null +++ b/espresso/examples/indust/misj @@ -0,0 +1,50 @@ +.i 35 +.o 14 +1111------------------------------- 10000000000000 +-----1-1--------------------------- 01000000000000 +-0-----11-------------------------- 01000000000000 +---0---11-------------------------- 01000000000000 +----0--11-------------------------- 01000000000000 +-------11------0------------------- 01000000000000 +-------11-------0------------------ 01000000000000 +-----0----------------------------- 00100000000000 +-------0--------------------------- 00010000000000 +-----0----0------------------------ 00010000000000 +-----0-----0----------------------- 00010000000000 +-------0--------------------------- 00001000000000 +-----0------0---------------------- 00001000000000 +-----0-------0--------------------- 00001000000000 +-----0--------0-------------------- 00001000000000 +-----------------0----------------- 00000100000000 +------------------0---------------- 00000100000000 +---------1------------------------- 00000010000000 +-------------------1--------------- 00000010000000 +--------------------1-------------- 00000010000000 +---------------0------------------- 00000001000000 +------0---------------------------- 00000000100000 +---------------------0------------- 00000000100000 +-----------------------1----------- 00000000010000 +-------------------------1--------- 00000000010000 +----------------------0------------ 00000000010000 +---------------------------0------- 00000000010000 +----------------------------0------ 00000000010000 +-----------------------------0----- 00000000010000 +------------------------------0---- 00000000010000 +-------------------------------0--- 00000000010000 +--------------------------------0-- 00000000010000 +---------------------------------0- 00000000010000 +--------------------------0-------- 00000000001000 +------------------------0---------- 00000000001000 +----------------------------------0 00000000001000 +----------------------0------------ 00000000001000 +---------------------------0------- 00000000001000 +----------------------------0------ 00000000001000 +------------------------------0---- 00000000001000 +-------------------------------0--- 00000000001000 +--------------------------------0-- 00000000001000 +---------------------------------0- 00000000001000 +-0-----11-------------------------- 00000000000100 +---0---11-------------------------- 00000000000100 +----0--11-------------------------- 00000000000100 +-------11------0------------------- 00000000000100 +-------11-------0------------------ 00000000000100 diff --git a/espresso/examples/indust/mp2d b/espresso/examples/indust/mp2d new file mode 100644 index 0000000..5834fc8 --- /dev/null +++ b/espresso/examples/indust/mp2d @@ -0,0 +1,125 @@ +.i 14 +.o 14 +0------------- 10000000000000 +11------------ 10000000000000 +100----------- 10000000000000 +1011---------- 11111100010000 +10100--------- 10000000000000 +101010-------- 10000000000000 +1010111------- 10000000000000 +10101100------ 10000000000000 +101011011----- 10000000000000 +1010110101---- 10000000000000 +10101101001--- 10000000000000 +0-----1------- 01110100000000 +0-----00------ 01110100000000 +0-----011----- 01110000000000 +0-----0101---- 01000000000000 +0-----01000--- 01000000000000 +111---1------- 01110100000000 +111---00------ 01110100000000 +111---011----- 01110000000000 +111---0101---- 01000000000000 +111---01000--- 01000000000000 +1101--1------- 01110100000000 +1101--00------ 01110100000000 +1101--011----- 01110000000000 +1101--0101---- 01000000000000 +1101--01000--- 01000000000000 +11001--------- 01110100111000 +11000-1------- 01110100000000 +11000-00------ 01110100000000 +11000-011----- 01110000000000 +11000-0101---- 01000000000000 +11000-01000--- 01000000000000 +1010--1------- 01110100000000 +1010--00------ 01110100000000 +1010--011----- 01110000000000 +1010--0101---- 01000000000000 +1010--01000--- 01000000000000 +1001--1------- 01110100000000 +1001--00------ 01110100000000 +1001--011----- 01110000000000 +1001--0101---- 01000000000000 +1001--01000--- 01000000000000 +10000--------- 01110101010000 +10001-1------- 01110100000000 +10001-00------ 01110100000000 +10001-011----- 01110000000000 +10001-0101---- 01000000000000 +10001-01000--- 01000000000000 +0-----0100---- 00110000000000 +0-----01011--- 00100000000000 +111---0100---- 00110000000000 +111---01011--- 00100000000000 +1101--0100---- 00110000000000 +1101--01011--- 00100000000000 +11000-0100---- 00110000000000 +11000-01011--- 00100000000000 +1010--0100---- 00110000000000 +1010--01011--- 00100000000000 +1001--0100---- 00110000000000 +1001--01011--- 00100000000000 +10001-0100---- 00110000000000 +10001-01011--- 00100000000000 +0--1---------- 00100000000000 +0--0-0-------- 00100000000000 +11-1---------- 00100000000000 +11-0-0-------- 00100000000000 +1001---------- 00100000000000 +1000-0-------- 00100000000000 +10101--------- 00100000000000 +101000-------- 00100000000000 +0-----01010--- 00010000000000 +111---01010--- 00010000000000 +1101--01010--- 00010000000000 +11000-01010--- 00010000000000 +1010--01010--- 00010000000000 +1001--01010--- 00010000000000 +10001-01010--- 00010000000000 +11001---100--- 00001000000000 +1011----100--- 00001000000000 +10000---100--- 00001000000000 +------1-100--- 00001000000000 +------00100--- 00001000000000 +0-----010----- 00000100000000 +0-----0111---- 00000100000000 +0-----01100--- 00000100000000 +111---010----- 00000100000000 +111---0111---- 00000100000000 +111---01100--- 00000100000000 +1101--010----- 00000100000000 +1101--0111---- 00000100000000 +1101--01100--- 00000100000000 +11000-010----- 00000100000000 +11000-0111---- 00000100000000 +11000-01100--- 00000100000000 +1010--010----- 00000100000000 +1010--0111---- 00000100000000 +1010--01100--- 00000100000000 +1001--010----- 00000100000000 +1001--0111---- 00000100000000 +1001--01100--- 00000100000000 +10001-010----- 00000100000000 +10001-0111---- 00000100000000 +10001-01100--- 00000100000000 +11001-01------ 00000010000000 +1011--01------ 00000010000000 +10000-01------ 00000010000000 +11001-11111--- 00000010000000 +1011--11111--- 00000010000000 +10000-11111--- 00000010000000 +------0------- 00000000010000 +------10------ 00000000010000 +------110----- 00000000010000 +------1110---- 00000000010000 +------11110--- 00000000010000 +00001--------- 00000000001000 +00110--------- 00000000001000 +00101--------- 00000000001000 +------11111010 00000000000110 +1------------- 00000000000001 +00------------ 00000000000001 +010----------- 00000000000001 +0110---------- 00000000000001 +01111--------- 00000000000001 diff --git a/espresso/examples/indust/newapla b/espresso/examples/indust/newapla new file mode 100644 index 0000000..b99af9f --- /dev/null +++ b/espresso/examples/indust/newapla @@ -0,0 +1,23 @@ +.i 12 +.o 10 +.ilb CPIPE1s<7> SRC1s<0> SRC1s<1> SRC1s<2> SRC1s<3> SRC1s<4> SRC1equalDST2 DSTvalid pbusDtoINA SRC2equal16 SRC2equalDST2 opc2load +.ob readRFaccessA1 readRFaccessB1 AIzero1 AIzeroforce busDtobusAa DSTtobusDa2 preadTBtoA preadSWPtoA pForwardtoINB preadPCtoA +.p 17 +--------1--- 0000010000 +1-------1--- 1100010000 +1------10010 0000010010 +1---1-110--0 0000110000 +11----11---0 0000010000 +1-1---110--0 0000110000 +1--1--11---0 0000010000 +1----0110--0 0000110000 +100001--0--- 1010000000 +110101--0--- 0000101000 +110001--0--- 0000100001 +100101--0--- 0000100100 +1------0---- 1100000000 +0----------- 0011000000 +1---------0- 0100000000 +1--------1-- 0100000000 +1-----0----- 1000000000 +.e diff --git a/espresso/examples/indust/newapla1 b/espresso/examples/indust/newapla1 new file mode 100644 index 0000000..77633d1 --- /dev/null +++ b/espresso/examples/indust/newapla1 @@ -0,0 +1,16 @@ +.i 12 +.o 7 +.ilb SRC1s<0> SRC1s<1> SRC1s<2> SRC1s<3> SRC1s<4> CPIPE1s<7> pbusDtoINA SRC2equal16 SRC2equalDST2 opc2load DSTvalid SRC1equalDST2 +.ob pbusStobusA pSHAtobusA pSHBtobusA preadPSWtoA preadCWPtoA LoadforwtoINB1 LoadforwtoINA1 +.p 10 +0110110----- 1000100 +1110110----- 1001000 +----010--111 0000001 +1100110----- 0100000 +0100110----- 0010000 +-1---10--111 0000001 +1----10--111 0000001 +-----100111- 0000010 +--1--10--111 0000001 +---1-10--111 0000001 +.e diff --git a/espresso/examples/indust/newapla2 b/espresso/examples/indust/newapla2 new file mode 100644 index 0000000..4da30de --- /dev/null +++ b/espresso/examples/indust/newapla2 @@ -0,0 +1,13 @@ +.i 6 +.o 7 +.ilb DST2s<0> DST2s<1> DST2s<2> DST2s<3> DST2s<4> DSTvalid +.ob writetoSHA1 writetoSHB1 writetoPSW1 writetoCWP1 pwritetoTB pwritetoSWP pwritetoPC +.p 7 +001011 0000010 +111011 0010000 +110011 1000000 +101011 0000100 +100011 0000001 +011011 0001000 +010011 0100000 +.e diff --git a/espresso/examples/indust/newbyte b/espresso/examples/indust/newbyte new file mode 100644 index 0000000..96391f7 --- /dev/null +++ b/espresso/examples/indust/newbyte @@ -0,0 +1,14 @@ +.i 5 +.o 8 +.ilb EX_INSpass byteEX s1 s0 phi3 +.ob ex3 ex2 ex1 ex0 ins3 ins2 ins1 ins0 +.p 8 +00001 00000001 +00011 00000010 +00101 00000100 +00111 00001000 +01001 00010000 +01011 00100000 +01101 01000000 +01111 10000000 +.e diff --git a/espresso/examples/indust/newcond b/espresso/examples/indust/newcond new file mode 100644 index 0000000..f60c082 --- /dev/null +++ b/espresso/examples/indust/newcond @@ -0,0 +1,37 @@ +.i 11 +.o 2 +.ilb cAin0 cselaluSUM caluZout cBIprocessedMSB cAIprocessedMSB cALUmsb cDST1s<0> cDST1s<1> cDST1s<2> cDST1s<3> cDST1s<4> +.ob pCONDvalid aluVout +.p 31 +---01101--0 10 +---10101--0 10 +-1-11-01-00 10 +-1-00-1-000 10 +-1001011--0 10 +-1010011--0 10 +-1-010110-0 10 +-1-100110-0 10 +-1000-1--00 10 +0--1010100- 10 +0--0110100- 10 +-100101100- 10 +-101001100- 10 +-1-001----- 01 +-1-110----- 01 +-1011-11001 10 +-0---101--0 10 +0--00-01001 10 +------10000 10 +-00--01--00 10 +--1---0-100 10 +-0----01-10 10 +-1011-11-10 10 +--0---10-00 10 +1-----11001 10 +--1---011-0 10 +0-1---01001 10 +-0---01-000 10 +---00-01-10 10 +00----01001 10 +-1-11-11010 10 +.e diff --git a/espresso/examples/indust/newcpla1 b/espresso/examples/indust/newcpla1 new file mode 100644 index 0000000..1ea31a1 --- /dev/null +++ b/espresso/examples/indust/newcpla1 @@ -0,0 +1,44 @@ +.i 9 +.o 16 +.ilb WAIT CPIPE1s<0> CPIPE1s<1> CPIPE1s<2> CPIPE1s<3> CPIPE1s<4> CPIPE1s<5> CPIPE1s<7> RESET +.ob changeCWP2t trap lastPCload pDATABUSintoLOADL enableINTS1 changeCWP1 PCtoMAL1 pALUtoMAL pPCIncr pALUtoPC DST2step1 PCstuffoncall1 SRC2smin1 DST1min1 CPIPE1flush CPIPE1load1 +.p 38 +0---100-0 0000000001000000 +0-0010110 0000000010000000 +00-100-10 0000000010000000 +00---0110 0000000010000000 +0-1100110 0000000010000000 +0---01010 0000000010000001 +0-1-0111- 0001000100000100 +01--0111- 0001000000000100 +0000--110 0000000010000000 +0--10111- 0011000100100100 +0------00 0000000001000001 +0-010-010 0000000010000000 +0-----00- 0011010100010000 +01--1001- 1000000100000000 +001011-1- 0000000000001000 +0-----10- 0011000100100000 +0--11111- 0010000100101000 +00---011- 0000001000000000 +0000--11- 0001001000000000 +0-001011- 0000001000000000 +0---0101- 0011001000100000 +0-110011- 0000001000000000 +00-100-1- 0010001000100000 +0-1-1111- 0000000100001000 +0-011-01- 0011000100100000 +0-11--01- 0011000000100000 +01---11-- 0000000100000000 +0-----1-- 0010000000100000 +00--1-0-- 0000000100000000 +0----0--0 0000000000000001 +01----0-- 0001000000000000 +0--0---1- 0010000000100000 +-101-0010 0000000000000010 +0-----0-0 0000000000000001 +---11001- 0000100000000000 +-1010001- 0100000000000000 +0----0--- 0001000000000000 +----10010 0000000000000010 +.e diff --git a/espresso/examples/indust/newcpla2 b/espresso/examples/indust/newcpla2 new file mode 100644 index 0000000..fa76eb0 --- /dev/null +++ b/espresso/examples/indust/newcpla2 @@ -0,0 +1,25 @@ +.i 7 +.o 10 +.ilb CPIPE2s<0> CPIPE2s<1> CPIPE2s<2> CPIPE2s<3> CPIPE2s<4> CPIPE2s<5> CPIPE2s<7> +.ob writeRFaccess2 lastPCtobusD1 busDtobusB2 busDtobusA2 DSTtobusD2 nillonreturn pLOADwrite opc2load DSTvalid pbusDtoINA +.p 19 +---0111 1000001010 +-1--111 0000000001 +--000-1 1000000010 +--1-111 0000000001 +1-01101 1000000010 +-----00 1111000000 +101000- 1111000000 +-001011 0011100000 +-110011 0011100000 +11--0-1 1000000010 +----011 1000000010 +0000111 0000000100 +-0111-1 0000000001 +11-1-01 1000000010 +1---111 0000000001 +-1-1001 1011110000 +---10-1 0000000010 +0---011 0011100000 +0--1101 0000000001 +.e diff --git a/espresso/examples/indust/newcwp b/espresso/examples/indust/newcwp new file mode 100644 index 0000000..62805de --- /dev/null +++ b/espresso/examples/indust/newcwp @@ -0,0 +1,17 @@ +.i 4 +.o 5 +.ilb CWP<6> CWP<5> CWP<4> changeCWP2 +.ob CWP+1<2> CWP+1<1> CWP+1<0> CWPm1<1> CWPm1<2> +.p 11 +101- 10001 +110- 10001 +111- 00011 +-001 10010 +--0- 00100 +-011 01000 +000- 10001 +-101 01000 +-000 01010 +-110 11000 +011- 10010 +.e diff --git a/espresso/examples/indust/newill b/espresso/examples/indust/newill new file mode 100644 index 0000000..1358a2c --- /dev/null +++ b/espresso/examples/indust/newill @@ -0,0 +1,14 @@ +.i 8 +.o 1 +.ilb CPIPE1s<9> CPIPE1s<0> CPIPE1s<1> CPIPE1s<2> CPIPE1s<3> CPIPE1s<4> CPIPE1s<5> CPIPE1s<7> +.ob pillegalopc +.p 8 +-1-11011 1 +-110-011 1 +-10-0011 1 +1------- 1 +---00001 1 +-11-1101 1 +-1-01101 1 +-11-0001 1 +.e diff --git a/espresso/examples/indust/newtag b/espresso/examples/indust/newtag new file mode 100644 index 0000000..ce48a19 --- /dev/null +++ b/espresso/examples/indust/newtag @@ -0,0 +1,14 @@ +.i 8 +.o 1 +.ilb busB<31> busA<31> busA<30> busB<30> busB<29> busA<29> busB<28> busA<28> +.ob ptagcompare +.p 8 +-0------ 1 +---1-00- 1 +---10-0- 1 +---1-0-0 1 +---10--0 1 +---100-- 1 +--1----- 1 +1------- 1 +.e diff --git a/espresso/examples/indust/newtpla b/espresso/examples/indust/newtpla new file mode 100644 index 0000000..67e72db --- /dev/null +++ b/espresso/examples/indust/newtpla @@ -0,0 +1,29 @@ +.i 15 +.o 5 +.ilb tagcompare tCPIPE1s<0> tCPIPE1s<1> tCPIPE1s<2> tCPIPE1s<3> tCPIPE1s<4> tCPIPE1s<5> tCPIPE1s<7> tbusA<31> tbusB<31> tbusB<30> tbusB<29> tbusB<28> tCPIPE1s<6> tCPIPE1s<8> +.ob GStrap trapinstr TAGtrap pov_unflow skipCONDenable +.p 23 +--001011-0---10 00100 +-0-0-011-0---10 00100 +--0010111----1- 00100 +-0-0-0111----1- 00100 +----0101-0---10 00100 +-00011010----1- 00100 +-0001101-00001- 10000 +00001101-----1- 10000 +--1-0101------- 01000 +--0111010----11 00100 +--01110101---1- 00100 +----01011----1- 00100 +--110011-0---10 00100 +---10101------- 01000 +----10011----1- 10000 +--01-10110---10 00100 +--1100111----1- 00100 +-0--0011-0---10 00100 +-1--0101------- 01000 +-0--00111----1- 00100 +-0000101------- 00001 +--001011-----1- 00010 +-0-01011-----1- 00010 +.e diff --git a/espresso/examples/indust/newtpla1 b/espresso/examples/indust/newtpla1 new file mode 100644 index 0000000..1467cb7 --- /dev/null +++ b/espresso/examples/indust/newtpla1 @@ -0,0 +1,10 @@ +.i 10 +.o 2 +.ilb CPIPE1s<6> CPIPE1s<0> CPIPE1s<1> CPIPE1s<2> CPIPE1s<3> CPIPE1s<4> CPIPE1s<5> CPIPE1s<7> AIprocessed<31> AIprocessed<30> +.ob shiftAbus31 shiftAbus30 +.p 4 +-01000111- 10 +00-000111- 01 +10100011-1 01 +10-000111- 10 +.e diff --git a/espresso/examples/indust/newtpla2 b/espresso/examples/indust/newtpla2 new file mode 100644 index 0000000..3b144ea --- /dev/null +++ b/espresso/examples/indust/newtpla2 @@ -0,0 +1,15 @@ +.i 10 +.o 4 +.ilb GStrap trapinstr datapagefINT winunderflow winoverflow SWI intTAGtrap illegalopc instrpagefINT IOINT +.ob TRAPreason3 TRAPreason2 TRAPreason1 TRAPreason0 +.p 9 +10000000-- 0111 +--100000-- 0101 +-1000000-- 0110 +0000000001 1001 +----1000-- 0011 +------10-- 0001 +-----100-- 0010 +000000001- 1000 +---10000-- 0100 +.e diff --git a/espresso/examples/indust/newxcpla1 b/espresso/examples/indust/newxcpla1 new file mode 100644 index 0000000..e25889f --- /dev/null +++ b/espresso/examples/indust/newxcpla1 @@ -0,0 +1,49 @@ +.i 9 +.o 23 +.ilb CPIPE1s<0> CPIPE1s<1> CPIPE1s<2> CPIPE1s<3> CPIPE1s<4> CPIPE1s<5> CPIPE1s<7> CPIPE1s<8> RESET +.ob selaluSUM aluCINbar1 aluselSR selaluAND selaluOR selaluXOR selBIbar storeSXT pbusLtoINB RD_WR predecodeEA pSTOREwrite pLOADLtobusL pSXTtobusL byteEX +.p 43 +--------1 00000000000000000010000 +---0--11- 00000000100001000000000 +---1111-- 10000000000010010000000 +---01---- 10000000010000010000000 +-----011- 00000000100001000000000 +01--1-1-- 00000010000000000000000 +1---111-- 00000010000000000000000 +--1-011-- 01000000010000001110000 +0--0-0--- 00000000000000000010000 +1--1-01-- 01000000000000000000000 +----0-11- 00000000100001000000000 +--1-111-- 00000010000000000000000 +000--11-- 01000000000000000010000 +1--10-1-- 11000000000000010000000 +1-000-1-- 11000000010000011110000 +-1-0-0--- 00000000000000000010000 +10------- 10000000000000010000000 +11--10--- 00000000000000000010000 +01011-1-0 00000000000000000001000 +-----0--- 10000000010000011100000 +--0101--- 10000000010000011110000 +0-01101-- 00000001000000000000000 +1-0-10--- 00000000000000000010000 +-011101-- 01000000001000000000000 +0101-11-- 00000010000000000000000 +0001101-- 01000001001000000000000 +------0-- 10000000110000011110000 +----001-- 01000000000000000000000 +0111101-0 00000000000000000000010 +0110011-- 00010000000000010000000 +1110011-- 00001000000000010000000 +-011101-0 01000000001000000000001 +-1-0111-0 00000000000000000000010 +---0101-- 00000010000000000010000 +--10111-0 00000000000000000000010 +0011011-- 00000000000000100000000 +0001111-- 00000000000100000000000 +0010011-- 00000100000000010000000 +1--1111-0 00000000000000000001000 +0001101-0 01000001001000000000100 +0-00011-- 01100000010000011110000 +1--0111-0 00000000000000000000010 +--11111-0 00000000000000000001000 +.e diff --git a/espresso/examples/indust/opa b/espresso/examples/indust/opa new file mode 100644 index 0000000..1fdee7d --- /dev/null +++ b/espresso/examples/indust/opa @@ -0,0 +1,686 @@ +.i 17 +.o 69 +011001----------- +100000000000000000000000000000000000000000000000000000000000000000000 +011100----------- +100000000000000000000000000000000000000000000000000000000000000000000 +01110-1---------- +100000000000000000000000000000000000000000000000000000000000000000000 +0100111---------- +100000000000000000000000000000000000000000000000000000000000000000000 +01-1001---------- +100000000000000000000000000000000000000000000000000000000000000000000 +0011-11------0--- +100000000000000000000000000000000000000000000000000000000000000000000 +00-111----------- +100000000000000000000000000000000000000000000000000000000000000000000 +00-1000---------- +100000000000000000000000000000000000000000000000000000000000000000000 +0--1110---------- +100000000000000000000000000000000000000000000000000000000000000000000 +011-0------------ +010000000000000000000000000000000000000000000000000000000000000000000 +011---0---------- +010000000000000000000000000000000000000000000000000000000000000000000 +01---0----------- +010000000000000000000000000000000000000000000000000000000000000000000 +000--1----------- +010000000000000000000000000000000000000000000000000000000000000000000 +000---1---------- +010000000000000000000000000000000000000000000000000000000000000000000 +00-1------------- +010000000000000000000000000000000000000000000000000000000000000000000 +00--1------------ +010000000000000000000000000000000000000000000000000000000000000000000 +0-1--0----------- +010000000000000000000000000000000000000000000000000000000000000000000 +0-11---10---0-000 +010000000000000000000000000000000000000000000000000000000000000000000 +0-11----01--0-000 +010000000000000000000000000000000000000000000000000000000000000000000 +0-001------------ +010000000000000000000000000000000000000000000000000000000000000000000 +0-00--1---------- +010000000000000000000000000000000000000000000000000000000000000000000 +0--10------------ +010000000000000000000000000000000000000000000000000000000000000000000 +0--1--0---------- +010000000000000000000000000000000000000000000000000000000000000000000 +01111-110---0-000 +001000000000000000000000000000000000000000000000000000000000000000000 +01111-1-01--0-000 +001000000000000000000000000000000000000000000000000000000000000000000 +01010-0---------- +001000000000000000000000000000000000000000000000000000000000000000000 +01-0-0----------- +001000000000000000000000000000000000000000000000000000000000000000000 +001--01---------- +001000000000000000000000000000000000000000000000000000000000000000000 +0000-1----------- +001000000000000000000000000000000000000000000000000000000000000000000 +0000--1---------- +001000000000000000000000000000000000000000000000000000000000000000000 +000-01----------- +001000000000000000000000000000000000000000000000000000000000000000000 +000-0-1---------- +001000000000000000000000000000000000000000000000000000000000000000000 +00-01------------ +001000000000000000000000000000000000000000000000000000000000000000000 +00-101-------1--- +001000000000000000000000000000000000000000000000000000000000000000000 +0---10----------- +001000000000000000000000000000000000000000000000000000000000000000000 +0--1010---------- +001000000000000000000000000000000000000000000000000000000000000000000 +0-10-0----------- +001000000000000000000000000000000000000000000000000000000000000000000 +0-0101----------- +001000000000000000000000000000000000000000000000000000000000000000000 +0-000-1---------- +001000000000000000000000000000000000000000000000000000000000000000000 +0--01-0---------- +001000000000000000000000000000000000000000000000000000000000000000000 +0011110---------- +000100000000000000000000000000000000000000000000000000000000000000000 +0001110---------- +000010000000000000000000000000000000000000000000000000000000000000000 +0101101---------- +000001000000000000000000000000000000000000000000000000000000000000000 +0101100---------- +000000100000000000000000000000000000000000000000000000000000000000000 +0111010---------- +000000010000000000000000000000000000000000000000000000000000000000000 +0011011---------- +000000001000000000000000000000000000000000000000000000000000000000000 +0100011---------- +000000000100000000000000000000000000000000000000000000000000000000000 +0110000---------- +000000000010000000000000000000000000000000000000000000000000000000000 +0111111110--0-000 +000000000001000000000000000000000000000000000000000000000000000000000 +0111111010--0-000 +000000000000100000000000000000000000000000000000000000000000000000000 +0111111000--0-000 +000000000000010000000000000000000000000000000000000000000000000000000 +01010-0---------- +000000000000001000000000000000000000000000000000000000000000000000000 +00010-1---------- +000000000000001000000000000000000000000000000000000000000000000000000 +00-1010---------- +000000000000001000000000000000000000000000000000000000000000000000000 +00-1001---------- +000000000000001000000000000000000000000000000000000000000000000000000 +0-0101----------- +000000000000001000000000000000000000000000000000000000000000000000000 +011001----------- +000000000000000100000000000000000000000000000000000000000000000000000 +0111-10---------- +000000000000000100000000000000000000000000000000000000000000000000000 +01100-----0------ +000000000000000100000000000000000000000000000000000000000000000000000 +0110--0---0------ +000000000000000100000000000000000000000000000000000000000000000000000 +011--0----0------ +000000000000000100000000000000000000000000000000000000000000000000000 +01-00-1---0------ +000000000000000100000000000000000000000000000000000000000000000000000 +01-0-0----0------ +000000000000000100000000000000000000000000000000000000000000000000000 +0000-1----0------ +000000000000000100000000000000000000000000000000000000000000000000000 +0000--1---0------ +000000000000000100000000000000000000000000000000000000000000000000000 +00-11------------ +000000000000000100000000000000000000000000000000000000000000000000000 +00--1-----0------ +000000000000000100000000000000000000000000000000000000000000000000000 +0-10-0----0------ +000000000000000100000000000000000000000000000000000000000000000000000 +0-1110----------- +000000000000000100000000000000000000000000000000000000000000000000000 +0-111-0---------- +000000000000000100000000000000000000000000000000000000000000000000000 +0-111--101--0-000 +000000000000000100000000000000000000000000000000000000000000000000000 +0-111--10-0-0-000 +000000000000000100000000000000000000000000000000000000000000000000000 +0-111---010-0-000 +000000000000000100000000000000000000000000000000000000000000000000000 +0--1110---------- +000000000000000100000000000000000000000000000000000000000000000000000 +0--1101---------- +000000000000000100000000000000000000000000000000000000000000000000000 +0--01-0---0------ +000000000000000100000000000000000000000000000000000000000000000000000 +01111111001-0-000 +000000000000000010000000000000000000000000000000000000000000000000000 +01111110011-0-000 +000000000000000010000000000000000000000000000000000000000000000000000 +011-00----1------ +000000000000000010000000000000000000000000000000000000000000000000000 +01-0-0----1------ +000000000000000010000000000000000000000000000000000000000000000000000 +0000-1----1------ +000000000000000010000000000000000000000000000000000000000000000000000 +0000--1---1------ +000000000000000010000000000000000000000000000000000000000000000000000 +00-01-----1------ +000000000000000010000000000000000000000000000000000000000000000000000 +0-10-0----1------ +000000000000000010000000000000000000000000000000000000000000000000000 +0-000-1---1------ +000000000000000010000000000000000000000000000000000000000000000000000 +0--01-0---1------ +000000000000000010000000000000000000000000000000000000000000000000000 +0110-00---------- +000000000000000001000000000000000000000000000000000000000000000000000 +01010-0---------- +000000000000000001000000000000000000000000000000000000000000000000000 +01--10----------- +000000000000000001000000000000000000000000000000000000000000000000000 +0000--1---------- +000000000000000001000000000000000000000000000000000000000000000000000 +00-101----------- +000000000000000001000000000000000000000000000000000000000000000000000 +00-01------------ +000000000000000001000000000000000000000000000000000000000000000000000 +0---100---------- +000000000000000001000000000000000000000000000000000000000000000000000 +0-0101----------- +000000000000000001000000000000000000000000000000000000000000000000000 +0-000-1---------- +000000000000000001000000000000000000000000000000000000000000000000000 +0--01-0---------- +000000000000000001000000000000000000000000000000000000000000000000000 +0--1010---------- +000000000000000001000000000000000000000000000000000000000000000000000 +0111011---------- +000000000000000000100000000000000000000000000000000000000000000000000 +0100111---------- +000000000000000000100000000000000000000000000000000000000000000000000 +00-100----------- +000000000000000000100000000000000000000000000000000000000000000000000 +0-01001---------- +000000000000000000100000000000000000000000000000000000000000000000000 +011100----------- +000000000000000000010000000000000000000000000000000000000000000000000 +0101110---------- +000000000000000000010000000000000000000000000000000000000000000000000 +0001111---------- +000000000000000000010000000000000000000000000000000000000000000000000 +0111110---------- +000000000000000000001000000000000000000000000000000000000000000000000 +0100000---------- +000000000000000000001000000000000000000000000000000000000000000000000 +00111-1---------- +000000000000000000001000000000000000000000000000000000000000000000000 +00-1101---------- +000000000000000000001000000000000000000000000000000000000000000000000 +011111110---0-000 +000000000000000000000100000000000000000000000000000000000000000000000 +0111111-01--0-000 +000000000000000000000100000000000000000000000000000000000000000000000 +001000----------- +000000000000000000000100000000000000000000000000000000000000000000000 +0000010---------- +000000000000000000000100000000000000000000000000000000000000000000000 +0-10001---------- +000000000000000000000100000000000000000000000000000000000000000000000 +0111010---------- +000000000000000000000010000000000000000000000000000000000000000000000 +01-1101---------- +000000000000000000000010000000000000000000000000000000000000000000000 +01-110-----1----- +000000000000000000000010000000000000000000000000000000000000000000000 +001110----------- +000000000000000000000010000000000000000000000000000000000000000000000 +0101101---------- +000000000000000000000001000000000000000000000000000000000000000000000 +001110----------- +000000000000000000000001000000000000000000000000000000000000000000000 +0-11100---------- +000000000000000000000001000000000000000000000000000000000000000000000 +0111010---------- +000000000000000000000000100000000000000000000000000000000000000000000 +0111101---------- +000000000000000000000000100000000000000000000000000000000000000000000 +011111110---0-000 +000000000000000000000000010000000000000000000000000000000000000000000 +0111111-01--0-000 +000000000000000000000000010000000000000000000000000000000000000000000 +01010-0---------- +000000000000000000000000010000000000000000000000000000000000000000000 +010--00---------- +000000000000000000000000010000000000000000000000000000000000000000000 +01-0-0----------- +000000000000000000000000010000000000000000000000000000000000000000000 +0000-1----------- +000000000000000000000000010000000000000000000000000000000000000000000 +0000--1---------- +000000000000000000000000010000000000000000000000000000000000000000000 +000-10----------- +000000000000000000000000010000000000000000000000000000000000000000000 +000-01----------- +000000000000000000000000010000000000000000000000000000000000000000000 +000-0-1---------- +000000000000000000000000010000000000000000000000000000000000000000000 +00-01------------ +000000000000000000000000010000000000000000000000000000000000000000000 +00-1010---------- +000000000000000000000000010000000000000000000000000000000000000000000 +00-101-------1--- +000000000000000000000000010000000000000000000000000000000000000000000 +00--001---------- +000000000000000000000000010000000000000000000000000000000000000000000 +0-10-0----------- +000000000000000000000000010000000000000000000000000000000000000000000 +0-0101----------- +000000000000000000000000010000000000000000000000000000000000000000000 +0-000-1---------- +000000000000000000000000010000000000000000000000000000000000000000000 +0--01-0---------- +000000000000000000000000010000000000000000000000000000000000000000000 +01110------------ +000000000000000000000000001000000000000000000000000000000000000000000 +0111-0----------- +000000000000000000000000001000000000000000000000000000000000000000000 +011-01----------- +000000000000000000000000001000000000000000000000000000000000000000000 +0100111---------- +000000000000000000000000001000000000000000000000000000000000000000000 +01-1-01---------- +000000000000000000000000001000000000000000000000000000000000000000000 +00111------------ +000000000000000000000000001000000000000000000000000000000000000000000 +0011-11------0--- +000000000000000000000000001000000000000000000000000000000000000000000 +00-111----------- +000000000000000000000000001000000000000000000000000000000000000000000 +00-1000---------- +000000000000000000000000001000000000000000000000000000000000000000000 +0-11-00---------- +000000000000000000000000001000000000000000000000000000000000000000000 +011111-10---0-000 +000000000000000000000000000100000000000000000000000000000000000000000 +011111--01--0-000 +000000000000000000000000000100000000000000000000000000000000000000000 +01100------------ +000000000000000000000000000100000000000000000000000000000000000000000 +0110--0---------- +000000000000000000000000000100000000000000000000000000000000000000000 +011-001---------- +000000000000000000000000000100000000000000000000000000000000000000000 +0101--0---------- +000000000000000000000000000100000000000000000000000000000000000000000 +010-1-0---------- +000000000000000000000000000100000000000000000000000000000000000000000 +01-0-0----------- +000000000000000000000000000100000000000000000000000000000000000000000 +01-00-1---------- +000000000000000000000000000100000000000000000000000000000000000000000 +01--110---------- +000000000000000000000000000100000000000000000000000000000000000000000 +0000-1----------- +000000000000000000000000000100000000000000000000000000000000000000000 +000---1---------- +000000000000000000000000000100000000000000000000000000000000000000000 +000-10----------- +000000000000000000000000000100000000000000000000000000000000000000000 +000-01----------- +000000000000000000000000000100000000000000000000000000000000000000000 +00-01------------ +000000000000000000000000000100000000000000000000000000000000000000000 +00-101----------- +000000000000000000000000000100000000000000000000000000000000000000000 +00-10-1---------- +000000000000000000000000000100000000000000000000000000000000000000000 +00-1-11---------- +000000000000000000000000000100000000000000000000000000000000000000000 +0-10-0----------- +000000000000000000000000000100000000000000000000000000000000000000000 +0-0101----------- +000000000000000000000000000100000000000000000000000000000000000000000 +011111-10---0-000 +000000000000000000000000000010000000000000000000000000000000000000000 +011111--01--0-000 +000000000000000000000000000010000000000000000000000000000000000000000 +011-110---------- +000000000000000000000000000010000000000000000000000000000000000000000 +0101--0---------- +000000000000000000000000000010000000000000000000000000000000000000000 +01-0-0----------- +000000000000000000000000000010000000000000000000000000000000000000000 +01-10-1---------- +000000000000000000000000000010000000000000000000000000000000000000000 +001-00----------- +000000000000000000000000000010000000000000000000000000000000000000000 +0001-0----------- +000000000000000000000000000010000000000000000000000000000000000000000 +0000-1----------- +000000000000000000000000000010000000000000000000000000000000000000000 +000---1---------- +000000000000000000000000000010000000000000000000000000000000000000000 +00-01------------ +000000000000000000000000000010000000000000000000000000000000000000000 +00-10-0---------- +000000000000000000000000000010000000000000000000000000000000000000000 +00-10--------1--- +000000000000000000000000000010000000000000000000000000000000000000000 +00--111---------- +000000000000000000000000000010000000000000000000000000000000000000000 +0-010------------ +000000000000000000000000000010000000000000000000000000000000000000000 +0-10-0----------- +000000000000000000000000000010000000000000000000000000000000000000000 +0-001------------ +000000000000000000000000000010000000000000000000000000000000000000000 +0-00--1---------- +000000000000000000000000000010000000000000000000000000000000000000000 +0--01-0---------- +000000000000000000000000000010000000000000000000000000000000000000000 +0111010---------- +000000000000000000000000000001000000000000000000000000000000000000000 +01-1101---------- +000000000000000000000000000001000000000000000000000000000000000000000 +0-1110----------- +000000000000000000000000000001000000000000000000000000000000000000000 +011001----------- +000000000000000000000000000000100000000000000000000000000000000000000 +011100----------- +000000000000000000000000000000100000000000000000000000000000000000000 +011-0-1---------- +000000000000000000000000000000100000000000000000000000000000000000000 +0100-0----------- +000000000000000000000000000000100000000000000000000000000000000000000 +0011-1----------- +000000000000000000000000000000100000000000000000000000000000000000000 +0010-0----------- +000000000000000000000000000000100000000000000000000000000000000000000 +0000-1----------- +000000000000000000000000000000100000000000000000000000000000000000000 +0000--1---------- +000000000000000000000000000000100000000000000000000000000000000000000 +00--1------------ +000000000000000000000000000000100000000000000000000000000000000000000 +0-1111--01--0-000 +000000000000000000000000000000100000000000000000000000000000000000000 +0-001------------ +000000000000000000000000000000100000000000000000000000000000000000000 +0-0-10----------- +000000000000000000000000000000100000000000000000000000000000000000000 +0---1-0---------- +000000000000000000000000000000100000000000000000000000000000000000000 +0--010----------- +000000000000000000000000000000100000000000000000000000000000000000000 +000100----------- +000000000000000000000000000000010000000000000000000000000000000000000 +0111111100--0-000 +000000000000000000000000000000010000000000000000000000000000000000000 +0-01000---------- +000000000000000000000000000000010000000000000000000000000000000000000 +0111011---------- +000000000000000000000000000000001000000000000000000000000000000000000 +0100-0----------- +000000000000000000000000000000001000000000000000000000000000000000000 +010--00---------- +000000000000000000000000000000001000000000000000000000000000000000000 +01-0-01---------- +000000000000000000000000000000001000000000000000000000000000000000000 +0011-10---------- +000000000000000000000000000000001000000000000000000000000000000000000 +0010-0----------- +000000000000000000000000000000001000000000000000000000000000000000000 +0001-0----------- +000000000000000000000000000000001000000000000000000000000000000000000 +0000-1----------- +000000000000000000000000000000001000000000000000000000000000000000000 +00--1------------ +000000000000000000000000000000001000000000000000000000000000000000000 +0-00--1---------- +000000000000000000000000000000001000000000000000000000000000000000000 +0-1111-10---0-000 +000000000000000000000000000000001000000000000000000000000000000000000 +0-1111-1-0--0-000 +000000000000000000000000000000001000000000000000000000000000000000000 +0-1111--01--0-000 +000000000000000000000000000000001000000000000000000000000000000000000 +0-001------------ +000000000000000000000000000000001000000000000000000000000000000000000 +0---1-0---------- +000000000000000000000000000000001000000000000000000000000000000000000 +0--010----------- +000000000000000000000000000000001000000000000000000000000000000000000 +0-1001----------- +000000000000000000000000000000000100000000000000000000000000000000000 +01111110-0--0-000 +000000000000000000000000000000000100000000000000000000000000000000000 +0111111001--0-000 +000000000000000000000000000000000010000000000000000000000000000000000 +0111011-----1---- +000000000000000000000000000000000010000000000000000000000000000000000 +01001-1-----1---- +000000000000000000000000000000000010000000000000000000000000000000000 +0010-0------1---- +000000000000000000000000000000000010000000000000000000000000000000000 +0000010-----1---- +000000000000000000000000000000000010000000000000000000000000000000000 +0000-01---------- +000000000000000000000000000000000010000000000000000000000000000000000 +0--010----------- +000000000000000000000000000000000010000000000000000000000000000000000 +0-10-01-----1---- +000000000000000000000000000000000010000000000000000000000000000000000 +0111011---------- +000000000000000000000000000000000001000000000000000000000000000000000 +0111-11001--0-000 +000000000000000000000000000000000001000000000000000000000000000000000 +0010-0----------- +000000000000000000000000000000000001000000000000000000000000000000000 +0000-10---------- +000000000000000000000000000000000001000000000000000000000000000000000 +00-01------------ +000000000000000000000000000000000001000000000000000000000000000000000 +0-10-01---------- +000000000000000000000000000000000001000000000000000000000000000000000 +0-001------------ +000000000000000000000000000000000001000000000000000000000000000000000 +0--010----------- +000000000000000000000000000000000001000000000000000000000000000000000 +0--01-0---------- +000000000000000000000000000000000001000000000000000000000000000000000 +01-010----------- +000000000000000000000000000000000000100000000000000000000000000000000 +01-01-0---------- +000000000000000000000000000000000000100000000000000000000000000000000 +0111111001--0-000 +000000000000000000000000000000000000010000000000000000000000000000000 +01-0101---------- +000000000000000000000000000000000000010000000000000000000000000000000 +00-01-0---------- +000000000000000000000000000000000000010000000000000000000000000000000 +0111011---------- +000000000000000000000000000000000000001000000000000000000000000000000 +0111-11001--0-000 +000000000000000000000000000000000000001000000000000000000000000000000 +0010-0----------- +000000000000000000000000000000000000001000000000000000000000000000000 +0000-1----------- +000000000000000000000000000000000000001000000000000000000000000000000 +0000--1---------- +000000000000000000000000000000000000001000000000000000000000000000000 +00-01------------ +000000000000000000000000000000000000001000000000000000000000000000000 +0-10-01---------- +000000000000000000000000000000000000001000000000000000000000000000000 +0-001------------ +000000000000000000000000000000000000001000000000000000000000000000000 +0--010----------- +000000000000000000000000000000000000001000000000000000000000000000000 +0--01-0---------- +000000000000000000000000000000000000001000000000000000000000000000000 +0111111001--0-000 +000000000000000000000000000000000000000100000000000000000000000000000 +0000--1---------- +000000000000000000000000000000000000000100000000000000000000000000000 +00-01------------ +000000000000000000000000000000000000000100000000000000000000000000000 +0--010----------- +000000000000000000000000000000000000000100000000000000000000000000000 +0--01-0---------- +000000000000000000000000000000000000000100000000000000000000000000000 +0111111010--0-000 +000000000000000000000000000000000000000010000000000000000000000000000 +0-10010---------- +000000000000000000000000000000000000000010000000000000000000000000000 +0111111010--0-000 +000000000000000000000000000000000000000001000000000000000000000000000 +0-1001----------- +000000000000000000000000000000000000000001000000000000000000000000000 +0111011---------- +000000000000000000000000000000000000000000100000000000000000000000000 +001000----------- +000000000000000000000000000000000000000000100000000000000000000000000 +0000-1----------- +000000000000000000000000000000000000000000100000000000000000000000000 +00-011----------- +000000000000000000000000000000000000000000100000000000000000000000000 +0-10001---------- +000000000000000000000000000000000000000000100000000000000000000000000 +0-0011----------- +000000000000000000000000000000000000000000100000000000000000000000000 +0--0110---------- +000000000000000000000000000000000000000000100000000000000000000000000 +0-1001----------- +000000000000000000000000000000000000000000010000000000000000000000000 +0-1001----------- +000000000000000000000000000000000000000000001000000000000000000000000 +011-011---------- +000000000000000000000000000000000000000000001000000000000000000000000 +00100------------ +000000000000000000000000000000000000000000001000000000000000000000000 +00-0-1----------- +000000000000000000000000000000000000000000001000000000000000000000000 +0-100-1---------- +000000000000000000000000000000000000000000001000000000000000000000000 +0-10-10---------- +000000000000000000000000000000000000000000001000000000000000000000000 +0-0011----------- +000000000000000000000000000000000000000000001000000000000000000000000 +011001----------- +000000000000000000000000000000000000000000000100000000000000000000000 +0111111010--0-000 +000000000000000000000000000000000000000000000010000000000000000000000 +001001----------- +000000000000000000000000000000000000000000000010000000000000000000000 +0010-10---------- +000000000000000000000000000000000000000000000010000000000000000000000 +0--0110---------- +000000000000000000000000000000000000000000000010000000000000000000000 +0111111010--0-000 +000000000000000000000000000000000000000000000001000000000000000000000 +0-1001----------- +000000000000000000000000000000000000000000000001000000000000000000000 +0010--0---------- +000000000000000000000000000000000000000000000001000000000000000000000 +01100-1---------- +000000000000000000000000000000000000000000000001000000000000000000000 +0-101-0---------- +000000000000000000000000000000000000000000000001000000000000000000000 +0-1010----------- +000000000000000000000000000000000000000000000001000000000000000000000 +00101------------ +000000000000000000000000000000000000000000000001000000000000000000000 +0010-1----------- +000000000000000000000000000000000000000000000001000000000000000000000 +0101-00---------- +000000000000000000000000000000000000000000000000100000000000000000000 +010000----------- +000000000000000000000000000000000000000000000000100000000000000000000 +01000-1---------- +000000000000000000000000000000000000000000000000100000000000000000000 +0011-10---------- +000000000000000000000000000000000000000000000000100000000000000000000 +00-11------------ +000000000000000000000000000000000000000000000000100000000000000000000 +0-1111-10---0-000 +000000000000000000000000000000000000000000000000100000000000000000000 +0-1111-1-0--0-000 +000000000000000000000000000000000000000000000000100000000000000000000 +0-1111--00--0-000 +000000000000000000000000000000000000000000000000100000000000000000000 +0-0110----------- +000000000000000000000000000000000000000000000000100000000000000000000 +0--11-0---------- +000000000000000000000000000000000000000000000000100000000000000000000 +00-11------------ +000000000000000000000000000000000000000000000000010000000000000000000 +0-1111-101--0-000 +000000000000000000000000000000000000000000000000010000000000000000000 +0--11-0---------- +000000000000000000000000000000000000000000000000010000000000000000000 +0111111101--0-000 +000000000000000000000000000000000000000000000000001000000000000000000 +00-110----------- +000000000000000000000000000000000000000000000000001000000000000000000 +0--1100---------- +000000000000000000000000000000000000000000000000001000000000000000000 +0111111101--0-000 +000000000000000000000000000000000000000000000000000100000000000000000 +000110----------- +000000000000000000000000000000000000000000000000000100000000000000000 +0--1100---------- +000000000000000000000000000000000000000000000000000100000000000000000 +00-11------------ +000000000000000000000000000000000000000000000000000010000000000000000 +0-1110----------- +000000000000000000000000000000000000000000000000000010000000000000000 +0-111--101--0-000 +000000000000000000000000000000000000000000000000000010000000000000000 +0--11-0---------- +000000000000000000000000000000000000000000000000000010000000000000000 +000100----------- +000000000000000000000000000000000000000000000000000001000000000000000 +0111111100--0-000 +000000000000000000000000000000000000000000000000000000100000000000000 +00010------------ +000000000000000000000000000000000000000000000000000000100000000000000 +00-100----------- +000000000000000000000000000000000000000000000000000000100000000000000 +00-10-1---------- +000000000000000000000000000000000000000000000000000000100000000000000 +0-0100----------- +000000000000000000000000000000000000000000000000000000100000000000000 +0111111100--0-000 +000000000000000000000000000000000000000000000000000000010000000000000 +01010------------ +000000000000000000000000000000000000000000000000000000010000000000000 +00110-1---------- +000000000000000000000000000000000000000000000000000000010000000000000 +00-100----------- +000000000000000000000000000000000000000000000000000000010000000000000 +0111111100--0-000 +000000000000000000000000000000000000000000000000000000001000000000000 +00010-1---------- +000000000000000000000000000000000000000000000000000000001000000000000 +00-100----------- +000000000000000000000000000000000000000000000000000000001000000000000 +0-01011---------- +000000000000000000000000000000000000000000000000000000001000000000000 +0-01000---------- +000000000000000000000000000000000000000000000000000000001000000000000 +00-100------1---- +000000000000000000000000000000000000000000000000000000000100000000000 +0-010-------1---- +000000000000000000000000000000000000000000000000000000000100000000000 +011100----------- +000000000000000000000000000000000000000000000000000000000010000000000 +0111011---------- +000000000000000000000000000000000000000000000000000000000001000000000 +0000010---------- +000000000000000000000000000000000000000000000000000000000001000000000 +0010000---------- +000000000000000000000000000000000000000000000000000000000001000000000 +0100111---------- +000000000000000000000000000000000000000000000000000000000000100000000 +0-10001---------- +000000000000000000000000000000000000000000000000000000000000100000000 diff --git a/espresso/examples/indust/p82 b/espresso/examples/indust/p82 new file mode 100644 index 0000000..bf15f78 --- /dev/null +++ b/espresso/examples/indust/p82 @@ -0,0 +1,26 @@ +.i 5 +.o 14 +00000|10000011000111 +00001|00000011001110 +00010|00000000011001 +00011|00001101100000 +00100|00000001000000 +00101|00000011100010 +00110|00000000000001 +00111|00001111100000 +01000|00000011100111 +01001|00000011110010 +01010|00101101000000 +01011|01001000100000 +01100|00000001100011 +01101|00000010000010 +01110|00000010100010 +01111|00000000000001 +10000|00001110100000 +10001|00000010100111 +10010|00000000010010 +10011|00001110000000 +10100|00000001000000 +10101|00000011000010 +10110|00000000000001 +10111|00011111000000 diff --git a/espresso/examples/indust/pdc b/espresso/examples/indust/pdc new file mode 100644 index 0000000..53b0157 --- /dev/null +++ b/espresso/examples/indust/pdc @@ -0,0 +1,2812 @@ +.i 16 +.o 40 +0000000000000000 0000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000001001100000 0000000001000000011010000000000000000000 +0000001001100101 0000010010000000011010000000000000000000 +0000001001101010 0001010000000000011010000000000000000000 +0000001001101111 0000100000000000011010000000000000000000 +0000001010100000 0000000001000000101010000000000000000000 +0000001010100101 0000010010000000101010000000000000000000 +0000001010101010 0001010000000000101010000000000000000000 +0000001010101111 0000100000000000101010000000000000000000 +0000001000100000 0000000001000000001010000000000000000000 +0000001000100101 0000010010000000001010000000000000000000 +0000001000101010 0001010000000000001010000000000000000000 +0000001000101111 0000100000000000001010000000000000000000 +0000001011100000 0000000001000000111010000000000000000000 +0000001011100101 0000010010000000111010000000000000000000 +0000001011101010 0001010000000000111010000000000000000000 +0000001011101111 0000100000000000111010000000000000000000 +0000001001010000 0000000001000000010110000000000000000000 +0000001001010101 0000010010000000010110000000000000000000 +0000001001011010 0001010000000000010110000000000000000000 +0000001001011111 0000100000000000010110000000000000000000 +0000001010010000 0000000001000000100110000000000000000000 +0000001010010101 0000010010000000100110000000000000000000 +0000001010011010 0001010000000000100110000000000000000000 +0000001010011111 0000100000000000100110000000000000000000 +0000001000010000 0000000001000000000110000000000000000000 +0000001000010101 0000010010000000000110000000000000000000 +0000001000011010 0001010000000000000110000000000000000000 +0000001000011111 0000100000000000000110000000000000000000 +0000001011010000 0000000001000000110110000000000000000000 +0000001011010101 0000010010000000110110000000000000000000 +0000001011011010 0001010000000000110110000000000000000000 +0000001011011111 0000100000000000110110000000000000000000 +0000001001000000 0000000001000000010010000000000000000000 +0000001001000101 0000010010000000010010000000000000000000 +0000001001001010 0001010000000000010010000000000000000000 +0000001001001111 0000100000000000010010000000000000000000 +0000001010000000 0000000001000000100010000000000000000000 +0000001010000101 0000010010000000100010000000000000000000 +0000001010001010 0001010000000000100010000000000000000000 +0000001010001111 0000100000000000100010000000000000000000 +0000001000000000 0000000001000000000010000000000000000000 +0000001000000101 0000010010000000000010000000000000000000 +0000001000001010 0001010000000000000010000000000000000000 +0000001000001111 0000100000000000000010000000000000000000 +0000001011000000 0000000001000000110010000000000000000000 +0000001011000101 0000010010000000110010000000000000000000 +0000001011001010 0001010000000000110010000000000000000000 +0000001011001111 0000100000000000110010000000000000000000 +0000001001110000 0000000001000000011110000000000000000000 +0000001001110101 0000010010000000011110000000000000000000 +0000001001111010 0001010000000000011110000000000000000000 +0000001001111111 0000100000000000011110000000000000000000 +0000001010110000 0000000001000000101110000000000000000000 +0000001010110101 0000010010000000101110000000000000000000 +0000001010111010 0001010000000000101110000000000000000000 +0000001010111111 0000100000000000101110000000000000000000 +0000001000110000 0000000001000000001110000000000000000000 +0000001000110101 0000010010000000001110000000000000000000 +0000001000111010 0001010000000000001110000000000000000000 +0000001000111111 0000100000000000001110000000000000000000 +0000001011110000 0000000001000000111110000000000000000000 +0000001011110101 0000010010000000111110000000000000000000 +0000001011111010 0001010000000000111110000000000000000000 +0000001011111111 0000100000000000111110000000000000000000 +0000001001100100 0000010011000000011010000000000000000000 +0000001001101000 0001010001000000011010000000000000000000 +0000001001101100 0000100001000000011010000000000000000000 +0000001001100001 0000010011000000011010000000000000000000 +0000001001101001 0001010010000000011010000000000000000000 +0000001001101101 0000110010000000011010000000000000000000 +0000001001100010 0001010001000000011010000000000000000000 +0000001001100110 0001010010000000011010000000000000000000 +0000001001101110 0001110000000000011010000000000000000000 +0000001001100011 0000100001000000011010000000000000000000 +0000001001100111 0000110010000000011010000000000000000000 +0000001001101011 0001110000000000011010000000000000000000 +0000001010100100 0000010011000000101010000000000000000000 +0000001010101000 0001010001000000101010000000000000000000 +0000001010101100 0000100001000000101010000000000000000000 +0000001010100001 0000010011000000101010000000000000000000 +0000001010101001 0001010010000000101010000000000000000000 +0000001010101101 0000110010000000101010000000000000000000 +0000001010100010 0001010001000000101010000000000000000000 +0000001010100110 0001010010000000101010000000000000000000 +0000001010101110 0001110000000000101010000000000000000000 +0000001010100011 0000100001000000101010000000000000000000 +0000001010100111 0000110010000000101010000000000000000000 +0000001010101011 0001110000000000101010000000000000000000 +0000001000100100 0000010011000000001010000000000000000000 +0000001000101000 0001010001000000001010000000000000000000 +0000001000101100 0000100001000000001010000000000000000000 +0000001000100001 0000010011000000001010000000000000000000 +0000001000101001 0001010010000000001010000000000000000000 +0000001000101101 0000110010000000001010000000000000000000 +0000001000100010 0001010001000000001010000000000000000000 +0000001000100110 0001010010000000001010000000000000000000 +0000001000101110 0001110000000000001010000000000000000000 +0000001000100011 0000100001000000001010000000000000000000 +0000001000100111 0000110010000000001010000000000000000000 +0000001000101011 0001110000000000001010000000000000000000 +0000001011100100 0000010011000000111010000000000000000000 +0000001011101000 0001010001000000111010000000000000000000 +0000001011101100 0000100001000000111010000000000000000000 +0000001011100001 0000010011000000111010000000000000000000 +0000001011101001 0001010010000000111010000000000000000000 +0000001011101101 0000110010000000111010000000000000000000 +0000001011100010 0001010001000000111010000000000000000000 +0000001011100110 0001010010000000111010000000000000000000 +0000001011101110 0001110000000000111010000000000000000000 +0000001011100011 0000100001000000111010000000000000000000 +0000001011100111 0000110010000000111010000000000000000000 +0000001011101011 0001110000000000111010000000000000000000 +0000001001010100 0000010011000000010110000000000000000000 +0000001001011000 0001010001000000010110000000000000000000 +0000001001011100 0000100001000000010110000000000000000000 +0000001001010001 0000010011000000010110000000000000000000 +0000001001011001 0001010010000000010110000000000000000000 +0000001001011101 0000110010000000010110000000000000000000 +0000001001010010 0001010001000000010110000000000000000000 +0000001001010110 0001010010000000010110000000000000000000 +0000001001011110 0001110000000000010110000000000000000000 +0000001001010011 0000100001000000010110000000000000000000 +0000001001010111 0000110010000000010110000000000000000000 +0000001001011011 0001110000000000010110000000000000000000 +0000001010010100 0000010011000000100110000000000000000000 +0000001010011000 0001010001000000100110000000000000000000 +0000001010011100 0000100001000000100110000000000000000000 +0000001010010001 0000010011000000100110000000000000000000 +0000001010011001 0001010010000000100110000000000000000000 +0000001010011101 0000110010000000100110000000000000000000 +0000001010010010 0001010001000000100110000000000000000000 +0000001010010110 0001010010000000100110000000000000000000 +0000001010011110 0001110000000000100110000000000000000000 +0000001010010011 0000100001000000100110000000000000000000 +0000001010010111 0000110010000000100110000000000000000000 +0000001010011011 0001110000000000100110000000000000000000 +0000001000010100 0000010011000000000110000000000000000000 +0000001000011000 0001010001000000000110000000000000000000 +0000001000011100 0000100001000000000110000000000000000000 +0000001000010001 0000010011000000000110000000000000000000 +0000001000011001 0001010010000000000110000000000000000000 +0000001000011101 0000110010000000000110000000000000000000 +0000001000010010 0001010001000000000110000000000000000000 +0000001000010110 0001010010000000000110000000000000000000 +0000001000011110 0001110000000000000110000000000000000000 +0000001000010011 0000100001000000000110000000000000000000 +0000001000010111 0000110010000000000110000000000000000000 +0000001000011011 0001110000000000000110000000000000000000 +0000001011010100 0000010011000000110110000000000000000000 +0000001011011000 0001010001000000110110000000000000000000 +0000001011011100 0000100001000000110110000000000000000000 +0000001011010001 0000010011000000110110000000000000000000 +0000001011011001 0001010010000000110110000000000000000000 +0000001011011101 0000110010000000110110000000000000000000 +0000001011010010 0001010001000000110110000000000000000000 +0000001011010110 0001010010000000110110000000000000000000 +0000001011011110 0001110000000000110110000000000000000000 +0000001011010011 0000100001000000110110000000000000000000 +0000001011010111 0000110010000000110110000000000000000000 +0000001011011011 0001110000000000110110000000000000000000 +0000001001000100 0000010011000000010010000000000000000000 +0000001001001000 0001010001000000010010000000000000000000 +0000001001001100 0000100001000000010010000000000000000000 +0000001001000001 0000010011000000010010000000000000000000 +0000001001001001 0001010010000000010010000000000000000000 +0000001001001101 0000110010000000010010000000000000000000 +0000001001000010 0001010001000000010010000000000000000000 +0000001001000110 0001010010000000010010000000000000000000 +0000001001001110 0001110000000000010010000000000000000000 +0000001001000011 0000100001000000010010000000000000000000 +0000001001000111 0000110010000000010010000000000000000000 +0000001001001011 0001110000000000010010000000000000000000 +0000001010000100 0000010011000000100010000000000000000000 +0000001010001000 0001010001000000100010000000000000000000 +0000001010001100 0000100001000000100010000000000000000000 +0000001010000001 0000010011000000100010000000000000000000 +0000001010001001 0001010010000000100010000000000000000000 +0000001010001101 0000110010000000100010000000000000000000 +0000001010000010 0001010001000000100010000000000000000000 +0000001010000110 0001010010000000100010000000000000000000 +0000001010001110 0001110000000000100010000000000000000000 +0000001010000011 0000100001000000100010000000000000000000 +0000001010000111 0000110010000000100010000000000000000000 +0000001010001011 0001110000000000100010000000000000000000 +0000001000000100 0000010011000000000010000000000000000000 +0000001000001000 0001010001000000000010000000000000000000 +0000001000001100 0000100001000000000010000000000000000000 +0000001000000001 0000010011000000000010000000000000000000 +0000001000001001 0001010010000000000010000000000000000000 +0000001000001101 0000110010000000000010000000000000000000 +0000001000000010 0001010001000000000010000000000000000000 +0000001000000110 0001010010000000000010000000000000000000 +0000001000001110 0001110000000000000010000000000000000000 +0000001000000011 0000100001000000000010000000000000000000 +0000001000000111 0000110010000000000010000000000000000000 +0000001000001011 0001110000000000000010000000000000000000 +0000001011000100 0000010011000000110010000000000000000000 +0000001011001000 0001010001000000110010000000000000000000 +0000001011001100 0000100001000000110010000000000000000000 +0000001011000001 0000010011000000110010000000000000000000 +0000001011001001 0001010010000000110010000000000000000000 +0000001011001101 0000110010000000110010000000000000000000 +0000001011000010 0001010001000000110010000000000000000000 +0000001011000110 0001010010000000110010000000000000000000 +0000001011001110 0001110000000000110010000000000000000000 +0000001011000011 0000100001000000110010000000000000000000 +0000001011000111 0000110010000000110010000000000000000000 +0000001011001011 0001110000000000110010000000000000000000 +0000001001110100 0000010011000000011110000000000000000000 +0000001001111000 0001010001000000011110000000000000000000 +0000001001111100 0000100001000000011110000000000000000000 +0000001001110001 0000010011000000011110000000000000000000 +0000001001111001 0001010010000000011110000000000000000000 +0000001001111101 0000110010000000011110000000000000000000 +0000001001110010 0001010001000000011110000000000000000000 +0000001001110110 0001010010000000011110000000000000000000 +0000001001111110 0001110000000000011110000000000000000000 +0000001001110011 0000100001000000011110000000000000000000 +0000001001110111 0000110010000000011110000000000000000000 +0000001001111011 0001110000000000011110000000000000000000 +0000001010110100 0000010011000000101110000000000000000000 +0000001010111000 0001010001000000101110000000000000000000 +0000001010111100 0000100001000000101110000000000000000000 +0000001010110001 0000010011000000101110000000000000000000 +0000001010111001 0001010010000000101110000000000000000000 +0000001010111101 0000110010000000101110000000000000000000 +0000001010110010 0001010001000000101110000000000000000000 +0000001010110110 0001010010000000101110000000000000000000 +0000001010111110 0001110000000000101110000000000000000000 +0000001010110011 0000100001000000101110000000000000000000 +0000001010110111 0000110010000000101110000000000000000000 +0000001010111011 0001110000000000101110000000000000000000 +0000001000110100 0000010011000000001110000000000000000000 +0000001000111000 0001010001000000001110000000000000000000 +0000001000111100 0000100001000000001110000000000000000000 +0000001000110001 0000010011000000001110000000000000000000 +0000001000111001 0001010010000000001110000000000000000000 +0000001000111101 0000110010000000001110000000000000000000 +0000001000110010 0001010001000000001110000000000000000000 +0000001000110110 0001010010000000001110000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000001000111110 0001110000000000001110000000000000000000 +0000001000110011 0000100001000000001110000000000000000000 +0000001000110111 0000110010000000001110000000000000000000 +0000001000111011 0001110000000000001110000000000000000000 +0000001011110100 0000010011000000111110000000000000000000 +0000001011111000 0001010001000000111110000000000000000000 +0000001011111100 0000100001000000111110000000000000000000 +0000001011110001 0000010011000000111110000000000000000000 +0000001011111001 0001010010000000111110000000000000000000 +0000001011111101 0000110010000000111110000000000000000000 +0000001011110010 0001010001000000111110000000000000000000 +0000001011110110 0001010010000000111110000000000000000000 +0000001011111110 0001110000000000111110000000000000000000 +0000001011110011 0000100001000000111110000000000000000000 +0000001011110111 0000110010000000111110000000000000000000 +0000001011111011 0001110000000000111110000000000000000000 +0000001101000000 0000000001010000010010000000000000000000 +0000001110000101 0000010010010000100010000000000000000000 +0000001100101010 0001010000010000001010000000000000000000 +0000001100011111 0000100000010000000110000000000000000000 +0000001101000101 0000010010010000010010000000000000000000 +0000001101001010 0001010000010000010010000000000000000000 +0000001101001111 0000100000010000010010000000000000000000 +0000001110000000 0000000001010000100010000000000000000000 +0000001110001010 0001010000010000100010000000000000000000 +0000001110001111 0000100000010000100010000000000000000000 +0000001100100000 0000000001010000001010000000000000000000 +0000001100100101 0000010010010000001010000000000000000000 +0000001100101111 0000100000010000001010000000000000000000 +0000001100010000 0000000001010000000110000000000000000000 +0000001100010101 0000010010010000000110000000000000000000 +0000001100011010 0001010000010000000110000000000000000000 +0000001101000100 0000010011010000010010000000000000000000 +0000001101001000 0001010001010000010010000000000000000000 +0000001101001100 0000100001010000010010000000000000000000 +0000001101000001 0000010011010000010010000000000000000000 +0000001101001001 0001010010010000010010000000000000000000 +0000001101001101 0000110010010000010010000000000000000000 +0000001101000010 0001010001010000010010000000000000000000 +0000001101000110 0001010010010000010010000000000000000000 +0000001101001110 0001110000010000010010000000000000000000 +0000001101000011 0000100001010000010010000000000000000000 +0000001101000111 0000110010010000010010000000000000000000 +0000001101001011 0001110000010000010010000000000000000000 +0000001110000100 0000010011010000100010000000000000000000 +0000001110001000 0001010001010000100010000000000000000000 +0000001110001100 0000100001010000100010000000000000000000 +0000001110000001 0000010011010000100010000000000000000000 +0000001110001001 0001010010010000100010000000000000000000 +0000001110001101 0000110010010000100010000000000000000000 +0000001110000010 0001010001010000100010000000000000000000 +0000001110000110 0001010010010000100010000000000000000000 +0000001110001110 0001110000010000100010000000000000000000 +0000001110000011 0000100001010000100010000000000000000000 +0000001110000111 0000110010010000100010000000000000000000 +0000001110001011 0001110000010000100010000000000000000000 +0000001100100100 0000010011010000001010000000000000000000 +0000001100101000 0001010001010000001010000000000000000000 +0000001100101100 0000100001010000001010000000000000000000 +0000001100100001 0000010011010000001010000000000000000000 +0000001100101001 0001010010010000001010000000000000000000 +0000001100101101 0000110010010000001010000000000000000000 +0000001100100010 0001010001010000001010000000000000000000 +0000001100100110 0001010010010000001010000000000000000000 +0000001100101110 0001110000010000001010000000000000000000 +0000001100100011 0000100001010000001010000000000000000000 +0000001100100111 0000110010010000001010000000000000000000 +0000001100101011 0001110000010000001010000000000000000000 +0000001100010100 0000010011010000000110000000000000000000 +0000001100011000 0001010001010000000110000000000000000000 +0000001100011100 0000100001010000000110000000000000000000 +0000001100010001 0000010011010000000110000000000000000000 +0000001100011001 0001010010010000000110000000000000000000 +0000001100011101 0000110010010000000110000000000000000000 +0000001100010010 0001010001010000000110000000000000000000 +0000001100010110 0001010010010000000110000000000000000000 +0000001100011110 0001110000010000000110000000000000000000 +0000001100010011 0000100001010000000110000000000000000000 +0000001100010111 0000110010010000000110000000000000000000 +0000001100011011 0001110000010000000110000000000000000000 +0000100001100000 0000000001001000011000000000000000000000 +0000100001100101 0000010010001000011000000000000000000000 +0000100001101010 0001010000001000011000000000000000000000 +0000100001101111 0000100000001000011000000000000000000000 +0000100010100000 0000000001001000101000000000000000000000 +0000100010100101 0000010010001000101000000000000000000000 +0000100010101010 0001010000001000101000000000000000000000 +0000100010101111 0000100000001000101000000000000000000000 +0000100000100000 0000000001001000001000000000000000000000 +0000100000100101 0000010010001000001000000000000000000000 +0000100000101010 0001010000001000001000000000000000000000 +0000100000101111 0000100000001000001000000000000000000000 +0000100011100000 0000000001001000111000000000000000000000 +0000100011100101 0000010010001000111000000000000000000000 +0000100011101010 0001010000001000111000000000000000000000 +0000100011101111 0000100000001000111000000000000000000000 +0000100001010000 0000000001001000010100000000000000000000 +0000100001010101 0000010010001000010100000000000000000000 +0000100001011010 0001010000001000010100000000000000000000 +0000100001011111 0000100000001000010100000000000000000000 +0000100010010000 0000000001001000100100000000000000000000 +0000100010010101 0000010010001000100100000000000000000000 +0000100010011010 0001010000001000100100000000000000000000 +0000100010011111 0000100000001000100100000000000000000000 +0000100000010000 0000000001001000000100000000000000000000 +0000100000010101 0000010010001000000100000000000000000000 +0000100000011010 0001010000001000000100000000000000000000 +0000100000011111 0000100000001000000100000000000000000000 +0000100011010000 0000000001001000110100000000000000000000 +0000100011010101 0000010010001000110100000000000000000000 +0000100011011010 0001010000001000110100000000000000000000 +0000100011011111 0000100000001000110100000000000000000000 +0000100001000000 0000000001001000010000000000000000000000 +0000100001000101 0000010010001000010000000000000000000000 +0000100001001010 0001010000001000010000000000000000000000 +0000100001001111 0000100000001000010000000000000000000000 +0000100010000000 0000000001001000100000000000000000000000 +0000100010000101 0000010010001000100000000000000000000000 +0000100010001010 0001010000001000100000000000000000000000 +0000100010001111 0000100000001000100000000000000000000000 +0000100000000000 0000000001001000000000000000000000000000 +0000100000000101 0000010010001000000000000000000000000000 +0000100000001010 0001010000001000000000000000000000000000 +0000100000001111 0000100000001000000000000000000000000000 +0000100011000000 0000000001001000110000000000000000000000 +0000100011000101 0000010010001000110000000000000000000000 +0000100011001010 0001010000001000110000000000000000000000 +0000100011001111 0000100000001000110000000000000000000000 +0000100001110000 0000000001001000011100000000000000000000 +0000100001110101 0000010010001000011100000000000000000000 +0000100001111010 0001010000001000011100000000000000000000 +0000100001111111 0000100000001000011100000000000000000000 +0000100010110000 0000000001001000101100000000000000000000 +0000100010110101 0000010010001000101100000000000000000000 +0000100010111010 0001010000001000101100000000000000000000 +0000100010111111 0000100000001000101100000000000000000000 +0000100000110000 0000000001001000001100000000000000000000 +0000100000110101 0000010010001000001100000000000000000000 +0000100000111010 0001010000001000001100000000000000000000 +0000100000111111 0000100000001000001100000000000000000000 +0000100011110000 0000000001001000111100000000000000000000 +0000100011110101 0000010010001000111100000000000000000000 +0000100011111010 0001010000001000111100000000000000000000 +0000100011111111 0000100000001000111100000000000000000000 +0000100001100100 0000010011001000011000000000000000000000 +0000100001101000 0001010001001000011000000000000000000000 +0000100001101100 0000100001001000011000000000000000000000 +0000100001100001 0000010011001000011000000000000000000000 +0000100001101001 0001010010001000011000000000000000000000 +0000100001101101 0000110010001000011000000000000000000000 +0000100001100010 0001010001001000011000000000000000000000 +0000100001100110 0001010010001000011000000000000000000000 +0000100001101110 0001110000001000011000000000000000000000 +0000100001100011 0000100001001000011000000000000000000000 +0000100001100111 0000110010001000011000000000000000000000 +0000100001101011 0001110000001000011000000000000000000000 +0000100010100100 0000010011001000101000000000000000000000 +0000100010101000 0001010001001000101000000000000000000000 +0000100010101100 0000100001001000101000000000000000000000 +0000100010100001 0000010011001000101000000000000000000000 +0000100010101001 0001010010001000101000000000000000000000 +0000100010101101 0000110010001000101000000000000000000000 +0000100010100010 0001010001001000101000000000000000000000 +0000100010100110 0001010010001000101000000000000000000000 +0000100010101110 0001110000001000101000000000000000000000 +0000100010100011 0000100001001000101000000000000000000000 +0000100010100111 0000110010001000101000000000000000000000 +0000100010101011 0001110000001000101000000000000000000000 +0000100000100100 0000010011001000001000000000000000000000 +0000100000101000 0001010001001000001000000000000000000000 +0000100000101100 0000100001001000001000000000000000000000 +0000100000100001 0000010011001000001000000000000000000000 +0000100000101001 0001010010001000001000000000000000000000 +0000100000101101 0000110010001000001000000000000000000000 +0000100000100010 0001010001001000001000000000000000000000 +0000100000100110 0001010010001000001000000000000000000000 +0000100000101110 0001110000001000001000000000000000000000 +0000100000100011 0000100001001000001000000000000000000000 +0000100000100111 0000110010001000001000000000000000000000 +0000100000101011 0001110000001000001000000000000000000000 +0000100011100100 0000010011001000111000000000000000000000 +0000100011101000 0001010001001000111000000000000000000000 +0000100011101100 0000100001001000111000000000000000000000 +0000100011100001 0000010011001000111000000000000000000000 +0000100011101001 0001010010001000111000000000000000000000 +0000100011101101 0000110010001000111000000000000000000000 +0000100011100010 0001010001001000111000000000000000000000 +0000100011100110 0001010010001000111000000000000000000000 +0000100011101110 0001110000001000111000000000000000000000 +0000100011100011 0000100001001000111000000000000000000000 +0000100011100111 0000110010001000111000000000000000000000 +0000100011101011 0001110000001000111000000000000000000000 +0000100001010100 0000010011001000010100000000000000000000 +0000100001011000 0001010001001000010100000000000000000000 +0000100001011100 0000100001001000010100000000000000000000 +0000100001010001 0000010011001000010100000000000000000000 +0000100001011001 0001010010001000010100000000000000000000 +0000100001011101 0000110010001000010100000000000000000000 +0000100001010010 0001010001001000010100000000000000000000 +0000100001010110 0001010010001000010100000000000000000000 +0000100001011110 0001110000001000010100000000000000000000 +0000100001010011 0000100001001000010100000000000000000000 +0000100001010111 0000110010001000010100000000000000000000 +0000100001011011 0001110000001000010100000000000000000000 +0000100010010100 0000010011001000100100000000000000000000 +0000100010011000 0001010001001000100100000000000000000000 +0000100010011100 0000100001001000100100000000000000000000 +0000100010010001 0000010011001000100100000000000000000000 +0000100010011001 0001010010001000100100000000000000000000 +0000100010011101 0000110010001000100100000000000000000000 +0000100010010010 0001010001001000100100000000000000000000 +0000100010010110 0001010010001000100100000000000000000000 +0000100010011110 0001110000001000100100000000000000000000 +0000100010010011 0000100001001000100100000000000000000000 +0000100010010111 0000110010001000100100000000000000000000 +0000100010011011 0001110000001000100100000000000000000000 +0000100000010100 0000010011001000000100000000000000000000 +0000100000011000 0001010001001000000100000000000000000000 +0000100000011100 0000100001001000000100000000000000000000 +0000100000010001 0000010011001000000100000000000000000000 +0000100000011001 0001010010001000000100000000000000000000 +0000100000011101 0000110010001000000100000000000000000000 +0000100000010010 0001010001001000000100000000000000000000 +0000100000010110 0001010010001000000100000000000000000000 +0000100000011110 0001110000001000000100000000000000000000 +0000100000010011 0000100001001000000100000000000000000000 +0000100000010111 0000110010001000000100000000000000000000 +0000100000011011 0001110000001000000100000000000000000000 +0000100011010100 0000010011001000110100000000000000000000 +0000100011011000 0001010001001000110100000000000000000000 +0000100011011100 0000100001001000110100000000000000000000 +0000100011010001 0000010011001000110100000000000000000000 +0000100011011001 0001010010001000110100000000000000000000 +0000100011011101 0000110010001000110100000000000000000000 +0000100011010010 0001010001001000110100000000000000000000 +0000100011010110 0001010010001000110100000000000000000000 +0000100011011110 0001110000001000110100000000000000000000 +0000100011010011 0000100001001000110100000000000000000000 +0000100011010111 0000110010001000110100000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000100011011011 0001110000001000110100000000000000000000 +0000100001000100 0000010011001000010000000000000000000000 +0000100001001000 0001010001001000010000000000000000000000 +0000100001001100 0000100001001000010000000000000000000000 +0000100001000001 0000010011001000010000000000000000000000 +0000100001001001 0001010010001000010000000000000000000000 +0000100001001101 0000110010001000010000000000000000000000 +0000100001000010 0001010001001000010000000000000000000000 +0000100001000110 0001010010001000010000000000000000000000 +0000100001001110 0001110000001000010000000000000000000000 +0000100001000011 0000100001001000010000000000000000000000 +0000100001000111 0000110010001000010000000000000000000000 +0000100001001011 0001110000001000010000000000000000000000 +0000100010000100 0000010011001000100000000000000000000000 +0000100010001000 0001010001001000100000000000000000000000 +0000100010001100 0000100001001000100000000000000000000000 +0000100010000001 0000010011001000100000000000000000000000 +0000100010001001 0001010010001000100000000000000000000000 +0000100010001101 0000110010001000100000000000000000000000 +0000100010000010 0001010001001000100000000000000000000000 +0000100010000110 0001010010001000100000000000000000000000 +0000100010001110 0001110000001000100000000000000000000000 +0000100010000011 0000100001001000100000000000000000000000 +0000100010000111 0000110010001000100000000000000000000000 +0000100010001011 0001110000001000100000000000000000000000 +0000100000000100 0000010011001000000000000000000000000000 +0000100000001000 0001010001001000000000000000000000000000 +0000100000001100 0000100001001000000000000000000000000000 +0000100000000001 0000010011001000000000000000000000000000 +0000100000001001 0001010010001000000000000000000000000000 +0000100000001101 0000110010001000000000000000000000000000 +0000100000000010 0001010001001000000000000000000000000000 +0000100000000110 0001010010001000000000000000000000000000 +0000100000001110 0001110000001000000000000000000000000000 +0000100000000011 0000100001001000000000000000000000000000 +0000100000000111 0000110010001000000000000000000000000000 +0000100000001011 0001110000001000000000000000000000000000 +0000100011000100 0000010011001000110000000000000000000000 +0000100011001000 0001010001001000110000000000000000000000 +0000100011001100 0000100001001000110000000000000000000000 +0000100011000001 0000010011001000110000000000000000000000 +0000100011001001 0001010010001000110000000000000000000000 +0000100011001101 0000110010001000110000000000000000000000 +0000100011000010 0001010001001000110000000000000000000000 +0000100011000110 0001010010001000110000000000000000000000 +0000100011001110 0001110000001000110000000000000000000000 +0000100011000011 0000100001001000110000000000000000000000 +0000100011000111 0000110010001000110000000000000000000000 +0000100011001011 0001110000001000110000000000000000000000 +0000100001110100 0000010011001000011100000000000000000000 +0000100001111000 0001010001001000011100000000000000000000 +0000100001111100 0000100001001000011100000000000000000000 +0000100001110001 0000010011001000011100000000000000000000 +0000100001111001 0001010010001000011100000000000000000000 +0000100001111101 0000110010001000011100000000000000000000 +0000100001110010 0001010001001000011100000000000000000000 +0000100001110110 0001010010001000011100000000000000000000 +0000100001111110 0001110000001000011100000000000000000000 +0000100001110011 0000100001001000011100000000000000000000 +0000100001110111 0000110010001000011100000000000000000000 +0000100001111011 0001110000001000011100000000000000000000 +0000100010110100 0000010011001000101100000000000000000000 +0000100010111000 0001010001001000101100000000000000000000 +0000100010111100 0000100001001000101100000000000000000000 +0000100010110001 0000010011001000101100000000000000000000 +0000100010111001 0001010010001000101100000000000000000000 +0000100010111101 0000110010001000101100000000000000000000 +0000100010110010 0001010001001000101100000000000000000000 +0000100010110110 0001010010001000101100000000000000000000 +0000100010111110 0001110000001000101100000000000000000000 +0000100010110011 0000100001001000101100000000000000000000 +0000100010110111 0000110010001000101100000000000000000000 +0000100010111011 0001110000001000101100000000000000000000 +0000100000110100 0000010011001000001100000000000000000000 +0000100000111000 0001010001001000001100000000000000000000 +0000100000111100 0000100001001000001100000000000000000000 +0000100000110001 0000010011001000001100000000000000000000 +0000100000111001 0001010010001000001100000000000000000000 +0000100000111101 0000110010001000001100000000000000000000 +0000100000110010 0001010001001000001100000000000000000000 +0000100000110110 0001010010001000001100000000000000000000 +0000100000111110 0001110000001000001100000000000000000000 +0000100000110011 0000100001001000001100000000000000000000 +0000100000110111 0000110010001000001100000000000000000000 +0000100000111011 0001110000001000001100000000000000000000 +0000100011110100 0000010011001000111100000000000000000000 +0000100011111000 0001010001001000111100000000000000000000 +0000100011111100 0000100001001000111100000000000000000000 +0000100011110001 0000010011001000111100000000000000000000 +0000100011111001 0001010010001000111100000000000000000000 +0000100011111101 0000110010001000111100000000000000000000 +0000100011110010 0001010001001000111100000000000000000000 +0000100011110110 0001010010001000111100000000000000000000 +0000100011111110 0001110000001000111100000000000000000000 +0000100011110011 0000100001001000111100000000000000000000 +0000100011110111 0000110010001000111100000000000000000000 +0000100011111011 0001110000001000111100000000000000000000 +0000100000000000 0000000001001000000000000000000000000000 +0000100000000101 0000010010001000000000000000000000000000 +0000100000001010 0001010000001000000000000000000000000000 +0000100000001111 0000100000001000000000000000000000000000 +0000100000000100 0000010011001000000000000000000000000000 +0000100000001000 0001010001001000000000000000000000000000 +0000100000001100 0000100001001000000000000000000000000000 +0000100000000001 0000010011001000000000000000000000000000 +0000100000001001 0001010010001000000000000000000000000000 +0000100000001101 0000110010001000000000000000000000000000 +0000100000000010 0001010001001000000000000000000000000000 +0000100000000110 0001010010001000000000000000000000000000 +0000100000001110 0001110000001000000000000000000000000000 +0000100000000011 0000100001001000000000000000000000000000 +0000100000000111 0000110010001000000000000000000000000000 +0000100000001011 0001110000001000000000000000000000000000 +0000010011101010 0001010000000000111011000000000000000000 +0000010011011111 0000100000000000110111000000000000000000 +0000010011100000 0000000001000000111011000000000000000000 +0000010011100101 0000010010000000111011000000000000000000 +0000010011101111 0000100000000000111011000000000000000000 +0000010011010000 0000000001000000110111000000000000000000 +0000010011010101 0000010010000000110111000000000000000000 +0000010011011010 0001010000000000110111000000000000000000 +0000010011100100 0000010011000000111011000000000000000000 +0000010011101000 0001010001000000111011000000000000000000 +0000010011101100 0000100001000000111011000000000000000000 +0000010011100001 0000010011000000111011000000000000000000 +0000010011101001 0001010010000000111011000000000000000000 +0000010011101101 0000110010000000111011000000000000000000 +0000010011100010 0001010001000000111011000000000000000000 +0000010011100110 0001010010000000111011000000000000000000 +0000010011101110 0001110000000000111011000000000000000000 +0000010011100011 0000100001000000111011000000000000000000 +0000010011100111 0000110010000000111011000000000000000000 +0000010011101011 0001110000000000111011000000000000000000 +0000010011010100 0000010011000000110111000000000000000000 +0000010011011000 0001010001000000110111000000000000000000 +0000010011011100 0000100001000000110111000000000000000000 +0000010011010001 0000010011000000110111000000000000000000 +0000010011011001 0001010010000000110111000000000000000000 +0000010011011101 0000110010000000110111000000000000000000 +0000010011010010 0001010001000000110111000000000000000000 +0000010011010110 0001010010000000110111000000000000000000 +0000010011011110 0001110000000000110111000000000000000000 +0000010011010011 0000100001000000110111000000000000000000 +0000010011010111 0000110010000000110111000000000000000000 +0000010011011011 0001110000000000110111000000000000000000 +0000001001110000 0000000001000000011110000000000000000000 +0000001010110101 0000010010000000101110000000000000000000 +0000001011101010 0001010000000000111010000000000000000000 +0000001011011111 0000100000000000110110000000000000000000 +0000001001110101 0000010010000000011110000000000000000000 +0000001001111010 0001010000000000011110000000000000000000 +0000001001111111 0000100000000000011110000000000000000000 +0000001010110000 0000000001000000101110000000000000000000 +0000001010111010 0001010000000000101110000000000000000000 +0000001010111111 0000100000000000101110000000000000000000 +0000001011100000 0000000001000000111010000000000000000000 +0000001011100101 0000010010000000111010000000000000000000 +0000001011101111 0000100000000000111010000000000000000000 +0000001011010000 0000000001000000110110000000000000000000 +0000001011010101 0000010010000000110110000000000000000000 +0000001011011010 0001010000000000110110000000000000000000 +0000001001110100 0000010011000000011110000000000000000000 +0000001001111000 0001010001000000011110000000000000000000 +0000001001111100 0000100001000000011110000000000000000000 +0000001001110001 0000010011000000011110000000000000000000 +0000001001111001 0001010010000000011110000000000000000000 +0000001001111101 0000110010000000011110000000000000000000 +0000001001110010 0001010001000000011110000000000000000000 +0000001001110110 0001010010000000011110000000000000000000 +0000001001111110 0001110000000000011110000000000000000000 +0000001001110011 0000100001000000011110000000000000000000 +0000001001110111 0000110010000000011110000000000000000000 +0000001001111011 0001110000000000011110000000000000000000 +0000001010110100 0000010011000000101110000000000000000000 +0000001010111000 0001010001000000101110000000000000000000 +0000001010111100 0000100001000000101110000000000000000000 +0000001010110001 0000010011000000101110000000000000000000 +0000001010111001 0001010010000000101110000000000000000000 +0000001010111101 0000110010000000101110000000000000000000 +0000001010110010 0001010001000000101110000000000000000000 +0000001010110110 0001010010000000101110000000000000000000 +0000001010111110 0001110000000000101110000000000000000000 +0000001010110011 0000100001000000101110000000000000000000 +0000001010110111 0000110010000000101110000000000000000000 +0000001010111011 0001110000000000101110000000000000000000 +0000001011100100 0000010011000000111010000000000000000000 +0000001011101000 0001010001000000111010000000000000000000 +0000001011101100 0000100001000000111010000000000000000000 +0000001011100001 0000010011000000111010000000000000000000 +0000001011101001 0001010010000000111010000000000000000000 +0000001011101101 0000110010000000111010000000000000000000 +0000001011100010 0001010001000000111010000000000000000000 +0000001011100110 0001010010000000111010000000000000000000 +0000001011101110 0001110000000000111010000000000000000000 +0000001011100011 0000100001000000111010000000000000000000 +0000001011100111 0000110010000000111010000000000000000000 +0000001011101011 0001110000000000111010000000000000000000 +0000001011010100 0000010011000000110110000000000000000000 +0000001011011000 0001010001000000110110000000000000000000 +0000001011011100 0000100001000000110110000000000000000000 +0000001011010001 0000010011000000110110000000000000000000 +0000001011011001 0001010010000000110110000000000000000000 +0000001011011101 0000110010000000110110000000000000000000 +0000001011010010 0001010001000000110110000000000000000000 +0000001011010110 0001010010000000110110000000000000000000 +0000001011011110 0001110000000000110110000000000000000000 +0000001011010011 0000100001000000110110000000000000000000 +0000001011010111 0000110010000000110110000000000000000000 +0000001011011011 0001110000000000110110000000000000000000 +0000100101000101 0000010010000100010000000000000000000000 +0000100101001010 0001010000000100010000000000000000000000 +0000100101001111 0000100000000100010000000000000000000000 +0000100110000000 0000000001000100100000000000000000000000 +0000100110001010 0001010000000100100000000000000000000000 +0000100110001111 0000100000000100100000000000000000000000 +0000100100100000 0000000001000100001000000000000000000000 +0000100100100101 0000010010000100001000000000000000000000 +0000100100101111 0000100000000100001000000000000000000000 +0000100100010000 0000000001000100000100000000000000000000 +0000100100010101 0000010010000100000100000000000000000000 +0000100100011010 0001010000000100000100000000000000000000 +0000100101001001 0001010010000100010000000000000000000000 +0000100101001101 0000110010000100010000000000000000000000 +0000100101000110 0001010010000100010000000000000000000000 +0000100101001110 0001110000000100010000000000000000000000 +0000100101000111 0000110010000100010000000000000000000000 +0000100101001011 0001110000000100010000000000000000000000 +0000100110001000 0001010001000100100000000000000000000000 +0000100110001100 0000100001000100100000000000000000000000 +0000100110000010 0001010001000100100000000000000000000000 +0000100110001110 0001110000000100100000000000000000000000 +0000100110000011 0000100001000100100000000000000000000000 +0000100110001011 0001110000000100100000000000000000000000 +0000100100100100 0000010011000100001000000000000000000000 +0000100100101100 0000100001000100001000000000000000000000 +0000100100100001 0000010011000100001000000000000000000000 +0000100100101101 0000110010000100001000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000100100100011 0000100001000100001000000000000000000000 +0000100100100111 0000110010000100001000000000000000000000 +0000100100010100 0000010011000100000100000000000000000000 +0000100100011000 0001010001000100000100000000000000000000 +0000100100010001 0000010011000100000100000000000000000000 +0000100100011001 0001010010000100000100000000000000000000 +0000100100010010 0001010001000100000100000000000000000000 +0000100100010110 0001010010000100000100000000000000000000 +0000111001101010 0001010000000000011000000010000000000000 +0000111010101010 0001010000000000101000000010000000000000 +0000111000101010 0001010000000000001000000010000000000000 +0000111011101010 0001010000000000111000000010000000000000 +0000111001011111 0000100000000000010100000010000000000000 +0000111010011111 0000100000000000100100000010000000000000 +0000111000011111 0000100000000000000100000010000000000000 +0000111011011111 0000100000000000110100000010000000000000 +0000111001101000 0001010001000000011000000010000000000000 +0000111001101001 0001010010000000011000000010000000000000 +0000111001100010 0001010001000000011000000010000000000000 +0000111001100110 0001010010000000011000000010000000000000 +0000111001101110 0001110000000000011000000010000000000000 +0000111001101011 0001110000000000011000000010000000000000 +0000111010101000 0001010001000000101000000010000000000000 +0000111010101001 0001010010000000101000000010000000000000 +0000111010100010 0001010001000000101000000010000000000000 +0000111010100110 0001010010000000101000000010000000000000 +0000111010101110 0001110000000000101000000010000000000000 +0000111010101011 0001110000000000101000000010000000000000 +0000111001011100 0000100001000000010100000010000000000000 +0000111001011101 0000110010000000010100000010000000000000 +0000111001011110 0001110000000000010100000010000000000000 +0000111001010011 0000100001000000010100000010000000000000 +0000111001010111 0000110010000000010100000010000000000000 +0000111001011011 0001110000000000010100000010000000000000 +0000111010011100 0000100001000000100100000010000000000000 +0000111010011101 0000110010000000100100000010000000000000 +0000111010011110 0001110000000000100100000010000000000000 +0000111010010011 0000100001000000100100000010000000000000 +0000111010010111 0000110010000000100100000010000000000000 +0000111010011011 0001110000000000100100000010000000000000 +0000110101100000 0000000001000000011000010100000000101000 +0000110101100101 0000010010000000011000010100000000101000 +0000110101101010 0001010000000000011000010100000000101000 +0000110101101111 0000100000000000011000010100000000101000 +0000110110100000 0000000001000000101000010100000000101000 +0000110110100101 0000010010000000101000010100000000101000 +0000110110101010 0001010000000000101000010100000000101000 +0000110110101111 0000100000000000101000010100000000101000 +0000110100100000 0000000001000000001000010100000000101000 +0000110100100101 0000010010000000001000010100000000101000 +0000110100101010 0001010000000000001000010100000000101000 +0000110100101111 0000100000000000001000010100000000101000 +0000110111100000 0000000001000000111000010100000000101000 +0000110111100101 0000010010000000111000010100000000101000 +0000110111101010 0001010000000000111000010100000000101000 +0000110111101111 0000100000000000111000010100000000101000 +0000110101010000 0000000001000000010100010100000000101000 +0000110101010101 0000010010000000010100010100000000101000 +0000110101011010 0001010000000000010100010100000000101000 +0000110101011111 0000100000000000010100010100000000101000 +0000110110010000 0000000001000000100100010100000000101000 +0000110110010101 0000010010000000100100010100000000101000 +0000110110011010 0001010000000000100100010100000000101000 +0000110110011111 0000100000000000100100010100000000101000 +0000110100010000 0000000001000000000100010100000000101000 +0000110100010101 0000010010000000000100010100000000101000 +0000110100011010 0001010000000000000100010100000000101000 +0000110100011111 0000100000000000000100010100000000101000 +0000110111010000 0000000001000000110100010100000000101000 +0000110111010101 0000010010000000110100010100000000101000 +0000110111011010 0001010000000000110100010100000000101000 +0000110111011111 0000100000000000110100010100000000101000 +0000110101000000 0000000001000000010000010100000000101000 +0000110101000101 0000010010000000010000010100000000101000 +0000110101001010 0001010000000000010000010100000000101000 +0000110101001111 0000100000000000010000010100000000101000 +0000110110000000 0000000001000000100000010100000000101000 +0000110110000101 0000010010000000100000010100000000101000 +0000110110001010 0001010000000000100000010100000000101000 +0000110110001111 0000100000000000100000010100000000101000 +0000110100000000 0000000001000000000000010100000000101000 +0000110100000101 0000010010000000000000010100000000101000 +0000110100001010 0001010000000000000000010100000000101000 +0000110100001111 0000100000000000000000010100000000101000 +0000110111000000 0000000001000000110000010100000000101000 +0000110111000101 0000010010000000110000010100000000101000 +0000110111001010 0001010000000000110000010100000000101000 +0000110111001111 0000100000000000110000010100000000101000 +0000110101110000 0000000001000000011100010100000000101000 +0000110101110101 0000010010000000011100010100000000101000 +0000110101111010 0001010000000000011100010100000000101000 +0000110101111111 0000100000000000011100010100000000101000 +0000110110110000 0000000001000000101100010100000000101000 +0000110110110101 0000010010000000101100010100000000101000 +0000110110111010 0001010000000000101100010100000000101000 +0000110110111111 0000100000000000101100010100000000101000 +0000110100110000 0000000001000000001100010100000000101000 +0000110100110101 0000010010000000001100010100000000101000 +0000110100111010 0001010000000000001100010100000000101000 +0000110100111111 0000100000000000001100010100000000101000 +0000110111110000 0000000001000000111100010100000000101000 +0000110111110101 0000010010000000111100010100000000101000 +0000110111111010 0001010000000000111100010100000000101000 +0000110111111111 0000100000000000111100010100000000101000 +0000110101100100 0000010011000000011000010100000000101000 +0000110101101000 0001010001000000011000010100000000101000 +0000110101101100 0000100001000000011000010100000000101000 +0000110101100001 0000010011000000011000010100000000101000 +0000110101101001 0001010010000000011000010100000000101000 +0000110101101101 0000110010000000011000010100000000101000 +0000110101100010 0001010001000000011000010100000000101000 +0000110101100110 0001010010000000011000010100000000101000 +0000110101101110 0001110000000000011000010100000000101000 +0000110101100011 0000100001000000011000010100000000101000 +0000110101100111 0000110010000000011000010100000000101000 +0000110101101011 0001110000000000011000010100000000101000 +0000110110100100 0000010011000000101000010100000000101000 +0000110110101000 0001010001000000101000010100000000101000 +0000110110101100 0000100001000000101000010100000000101000 +0000110110100001 0000010011000000101000010100000000101000 +0000110110101001 0001010010000000101000010100000000101000 +0000110110101101 0000110010000000101000010100000000101000 +0000110110100010 0001010001000000101000010100000000101000 +0000110110100110 0001010010000000101000010100000000101000 +0000110110101110 0001110000000000101000010100000000101000 +0000110110100011 0000100001000000101000010100000000101000 +0000110110100111 0000110010000000101000010100000000101000 +0000110110101011 0001110000000000101000010100000000101000 +0000110100100100 0000010011000000001000010100000000101000 +0000110100101000 0001010001000000001000010100000000101000 +0000110100101100 0000100001000000001000010100000000101000 +0000110100100001 0000010011000000001000010100000000101000 +0000110100101001 0001010010000000001000010100000000101000 +0000110100101101 0000110010000000001000010100000000101000 +0000110100100010 0001010001000000001000010100000000101000 +0000110100100110 0001010010000000001000010100000000101000 +0000110100101110 0001110000000000001000010100000000101000 +0000110100100011 0000100001000000001000010100000000101000 +0000110100100111 0000110010000000001000010100000000101000 +0000110100101011 0001110000000000001000010100000000101000 +0000110111100100 0000010011000000111000010100000000101000 +0000110111101000 0001010001000000111000010100000000101000 +0000110111101100 0000100001000000111000010100000000101000 +0000110111100001 0000010011000000111000010100000000101000 +0000110111101001 0001010010000000111000010100000000101000 +0000110111101101 0000110010000000111000010100000000101000 +0000110111100010 0001010001000000111000010100000000101000 +0000110111100110 0001010010000000111000010100000000101000 +0000110111101110 0001110000000000111000010100000000101000 +0000110111100011 0000100001000000111000010100000000101000 +0000110111100111 0000110010000000111000010100000000101000 +0000110111101011 0001110000000000111000010100000000101000 +0000110101010100 0000010011000000010100010100000000101000 +0000110101011000 0001010001000000010100010100000000101000 +0000110101011100 0000100001000000010100010100000000101000 +0000110101010001 0000010011000000010100010100000000101000 +0000110101011001 0001010010000000010100010100000000101000 +0000110101011101 0000110010000000010100010100000000101000 +0000110101010010 0001010001000000010100010100000000101000 +0000110101010110 0001010010000000010100010100000000101000 +0000110101011110 0001110000000000010100010100000000101000 +0000110101010011 0000100001000000010100010100000000101000 +0000110101010111 0000110010000000010100010100000000101000 +0000110101011011 0001110000000000010100010100000000101000 +0000110110010100 0000010011000000100100010100000000101000 +0000110110011000 0001010001000000100100010100000000101000 +0000110110011100 0000100001000000100100010100000000101000 +0000110110010001 0000010011000000100100010100000000101000 +0000110110011001 0001010010000000100100010100000000101000 +0000110110011101 0000110010000000100100010100000000101000 +0000110110010010 0001010001000000100100010100000000101000 +0000110110010110 0001010010000000100100010100000000101000 +0000110110011110 0001110000000000100100010100000000101000 +0000110110010011 0000100001000000100100010100000000101000 +0000110110010111 0000110010000000100100010100000000101000 +0000110110011011 0001110000000000100100010100000000101000 +0000110100010100 0000010011000000000100010100000000101000 +0000110100011000 0001010001000000000100010100000000101000 +0000110100011100 0000100001000000000100010100000000101000 +0000110100010001 0000010011000000000100010100000000101000 +0000110100011001 0001010010000000000100010100000000101000 +0000110100011101 0000110010000000000100010100000000101000 +0000110100010010 0001010001000000000100010100000000101000 +0000110100010110 0001010010000000000100010100000000101000 +0000110100011110 0001110000000000000100010100000000101000 +0000110100010011 0000100001000000000100010100000000101000 +0000110100010111 0000110010000000000100010100000000101000 +0000110100011011 0001110000000000000100010100000000101000 +0000110111010100 0000010011000000110100010100000000101000 +0000110111011000 0001010001000000110100010100000000101000 +0000110111011100 0000100001000000110100010100000000101000 +0000110111010001 0000010011000000110100010100000000101000 +0000110111011001 0001010010000000110100010100000000101000 +0000110111011101 0000110010000000110100010100000000101000 +0000110111010010 0001010001000000110100010100000000101000 +0000110111010110 0001010010000000110100010100000000101000 +0000110111011110 0001110000000000110100010100000000101000 +0000110111010011 0000100001000000110100010100000000101000 +0000110111010111 0000110010000000110100010100000000101000 +0000110111011011 0001110000000000110100010100000000101000 +0000110101000100 0000010011000000010000010100000000101000 +0000110101001000 0001010001000000010000010100000000101000 +0000110101001100 0000100001000000010000010100000000101000 +0000110101000001 0000010011000000010000010100000000101000 +0000110101001001 0001010010000000010000010100000000101000 +0000110101001101 0000110010000000010000010100000000101000 +0000110101000010 0001010001000000010000010100000000101000 +0000110101000110 0001010010000000010000010100000000101000 +0000110101001110 0001110000000000010000010100000000101000 +0000110101000011 0000100001000000010000010100000000101000 +0000110101000111 0000110010000000010000010100000000101000 +0000110101001011 0001110000000000010000010100000000101000 +0000110110000100 0000010011000000100000010100000000101000 +0000110110001000 0001010001000000100000010100000000101000 +0000110110001100 0000100001000000100000010100000000101000 +0000110110000001 0000010011000000100000010100000000101000 +0000110110001001 0001010010000000100000010100000000101000 +0000110110001101 0000110010000000100000010100000000101000 +0000110110000010 0001010001000000100000010100000000101000 +0000110110000110 0001010010000000100000010100000000101000 +0000110110001110 0001110000000000100000010100000000101000 +0000110110000011 0000100001000000100000010100000000101000 +0000110110000111 0000110010000000100000010100000000101000 +0000110110001011 0001110000000000100000010100000000101000 +0000110100000100 0000010011000000000000010100000000101000 +0000110100001000 0001010001000000000000010100000000101000 +0000110100001100 0000100001000000000000010100000000101000 +0000110100000001 0000010011000000000000010100000000101000 +0000110100001001 0001010010000000000000010100000000101000 +0000110100001101 0000110010000000000000010100000000101000 +0000110100000010 0001010001000000000000010100000000101000 +0000110100000110 0001010010000000000000010100000000101000 +0000110100001110 0001110000000000000000010100000000101000 +0000110100000011 0000100001000000000000010100000000101000 +0000110100000111 0000110010000000000000010100000000101000 +0000110100001011 0001110000000000000000010100000000101000 +0000110111000100 0000010011000000110000010100000000101000 +0000110111001000 0001010001000000110000010100000000101000 +0000110111001100 0000100001000000110000010100000000101000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000110111000001 0000010011000000110000010100000000101000 +0000110111001001 0001010010000000110000010100000000101000 +0000110111001101 0000110010000000110000010100000000101000 +0000110111000010 0001010001000000110000010100000000101000 +0000110111000110 0001010010000000110000010100000000101000 +0000110111001110 0001110000000000110000010100000000101000 +0000110111000011 0000100001000000110000010100000000101000 +0000110111000111 0000110010000000110000010100000000101000 +0000110111001011 0001110000000000110000010100000000101000 +0000110101110100 0000010011000000011100010100000000101000 +0000110101111000 0001010001000000011100010100000000101000 +0000110101111100 0000100001000000011100010100000000101000 +0000110101110001 0000010011000000011100010100000000101000 +0000110101111001 0001010010000000011100010100000000101000 +0000110101111101 0000110010000000011100010100000000101000 +0000110101110010 0001010001000000011100010100000000101000 +0000110101110110 0001010010000000011100010100000000101000 +0000110101111110 0001110000000000011100010100000000101000 +0000110101110011 0000100001000000011100010100000000101000 +0000110101110111 0000110010000000011100010100000000101000 +0000110101111011 0001110000000000011100010100000000101000 +0000110110110100 0000010011000000101100010100000000101000 +0000110110111000 0001010001000000101100010100000000101000 +0000110110111100 0000100001000000101100010100000000101000 +0000110110110001 0000010011000000101100010100000000101000 +0000110110111001 0001010010000000101100010100000000101000 +0000110110111101 0000110010000000101100010100000000101000 +0000110110110010 0001010001000000101100010100000000101000 +0000110110110110 0001010010000000101100010100000000101000 +0000110110111110 0001110000000000101100010100000000101000 +0000110110110011 0000100001000000101100010100000000101000 +0000110110110111 0000110010000000101100010100000000101000 +0000110110111011 0001110000000000101100010100000000101000 +0000110100110100 0000010011000000001100010100000000101000 +0000110100111000 0001010001000000001100010100000000101000 +0000110100111100 0000100001000000001100010100000000101000 +0000110100110001 0000010011000000001100010100000000101000 +0000110100111001 0001010010000000001100010100000000101000 +0000110100111101 0000110010000000001100010100000000101000 +0000110100110010 0001010001000000001100010100000000101000 +0000110100110110 0001010010000000001100010100000000101000 +0000110100111110 0001110000000000001100010100000000101000 +0000110100110011 0000100001000000001100010100000000101000 +0000110100110111 0000110010000000001100010100000000101000 +0000110100111011 0001110000000000001100010100000000101000 +0000110111110100 0000010011000000111100010100000000101000 +0000110111111000 0001010001000000111100010100000000101000 +0000110111111100 0000100001000000111100010100000000101000 +0000110111110001 0000010011000000111100010100000000101000 +0000110111111001 0001010010000000111100010100000000101000 +0000110111111101 0000110010000000111100010100000000101000 +0000110111110010 0001010001000000111100010100000000101000 +0000110111110110 0001010010000000111100010100000000101000 +0000110111111110 0001110000000000111100010100000000101000 +0000110111110011 0000100001000000111100010100000000101000 +0000110111110111 0000110010000000111100010100000000101000 +0000110111111011 0001110000000000111100010100000000101000 +0000010001000000 0000000001000000010011000000000000000000 +0000010010000101 0000010010000000100011000000000000000000 +0000010001000101 0000010010000000010011000000000000000000 +0000010001001010 0001010000000000010011000000000000000000 +0000010001001111 0000100000000000010011000000000000000000 +0000010010000000 0000000001000000100011000000000000000000 +0000010010001010 0001010000000000100011000000000000000000 +0000010010001111 0000100000000000100011000000000000000000 +0000010001000100 0000010011000000010011000000000000000000 +0000010001001000 0001010001000000010011000000000000000000 +0000010001001100 0000100001000000010011000000000000000000 +0000010001000001 0000010011000000010011000000000000000000 +0000010001001001 0001010010000000010011000000000000000000 +0000010001001101 0000110010000000010011000000000000000000 +0000010001000010 0001010001000000010011000000000000000000 +0000010001000110 0001010010000000010011000000000000000000 +0000010001001110 0001110000000000010011000000000000000000 +0000010001000011 0000100001000000010011000000000000000000 +0000010001000111 0000110010000000010011000000000000000000 +0000010001001011 0001110000000000010011000000000000000000 +0000010010000100 0000010011000000100011000000000000000000 +0000010010001000 0001010001000000100011000000000000000000 +0000010010001100 0000100001000000100011000000000000000000 +0000010010000001 0000010011000000100011000000000000000000 +0000010010001001 0001010010000000100011000000000000000000 +0000010010001101 0000110010000000100011000000000000000000 +0000010010000010 0001010001000000100011000000000000000000 +0000010010000110 0001010010000000100011000000000000000000 +0000010010001110 0001110000000000100011000000000000000000 +0000010010000011 0000100001000000100011000000000000000000 +0000010010000111 0000110010000000100011000000000000000000 +0000010010001011 0001110000000000100011000000000000000000 +000001010100---- 0001010000000000010011000000000000000000 +000001011000---- 0001010000000000100011000000000000000000 +0000010001100000 0000000001000000011011000000000000000000 +0000010001100101 0000010010000000011011000000000000000000 +0000010001101010 0001010000000000011011000000000000000000 +0000010001101111 0000100000000000011011000000000000000000 +0000010010100000 0000000001000000101011000000000000000000 +0000010010100101 0000010010000000101011000000000000000000 +0000010010101010 0001010000000000101011000000000000000000 +0000010010101111 0000100000000000101011000000000000000000 +0000010000100000 0000000001000000001011000000000000000000 +0000010000100101 0000010010000000001011000000000000000000 +0000010000101010 0001010000000000001011000000000000000000 +0000010000101111 0000100000000000001011000000000000000000 +0000010011100000 0000000001000000111011000000000000000000 +0000010011100101 0000010010000000111011000000000000000000 +0000010011101010 0001010000000000111011000000000000000000 +0000010011101111 0000100000000000111011000000000000000000 +0000010001010000 0000000001000000010111000000000000000000 +0000010001010101 0000010010000000010111000000000000000000 +0000010001011010 0001010000000000010111000000000000000000 +0000010001011111 0000100000000000010111000000000000000000 +0000010010010000 0000000001000000100111000000000000000000 +0000010010010101 0000010010000000100111000000000000000000 +0000010010011010 0001010000000000100111000000000000000000 +0000010010011111 0000100000000000100111000000000000000000 +0000010000010000 0000000001000000000111000000000000000000 +0000010000010101 0000010010000000000111000000000000000000 +0000010000011010 0001010000000000000111000000000000000000 +0000010000011111 0000100000000000000111000000000000000000 +0000010011010000 0000000001000000110111000000000000000000 +0000010011010101 0000010010000000110111000000000000000000 +0000010011011010 0001010000000000110111000000000000000000 +0000010011011111 0000100000000000110111000000000000000000 +0000010001000000 0000000001000000010011000000000000000000 +0000010001000101 0000010010000000010011000000000000000000 +0000010001001010 0001010000000000010011000000000000000000 +0000010001001111 0000100000000000010011000000000000000000 +0000010010000000 0000000001000000100011000000000000000000 +0000010010000101 0000010010000000100011000000000000000000 +0000010010001010 0001010000000000100011000000000000000000 +0000010010001111 0000100000000000100011000000000000000000 +0000010000000000 0000000001000000000011000000000000000000 +0000010000000101 0000010010000000000011000000000000000000 +0000010000001010 0001010000000000000011000000000000000000 +0000010000001111 0000100000000000000011000000000000000000 +0000010011000000 0000000001000000110011000000000000000000 +0000010011000101 0000010010000000110011000000000000000000 +0000010011001010 0001010000000000110011000000000000000000 +0000010011001111 0000100000000000110011000000000000000000 +0000010001110000 0000000001000000011111000000000000000000 +0000010001110101 0000010010000000011111000000000000000000 +0000010001111010 0001010000000000011111000000000000000000 +0000010001111111 0000100000000000011111000000000000000000 +0000010010110000 0000000001000000101111000000000000000000 +0000010010110101 0000010010000000101111000000000000000000 +0000010010111010 0001010000000000101111000000000000000000 +0000010010111111 0000100000000000101111000000000000000000 +0000010000110000 0000000001000000001111000000000000000000 +0000010000110101 0000010010000000001111000000000000000000 +0000010000111010 0001010000000000001111000000000000000000 +0000010000111111 0000100000000000001111000000000000000000 +0000010011110000 0000000001000000111111000000000000000000 +0000010011110101 0000010010000000111111000000000000000000 +0000010011111010 0001010000000000111111000000000000000000 +0000010011111111 0000100000000000111111000000000000000000 +0000010001100100 0000010011000000011011000000000000000000 +0000010001101000 0001010001000000011011000000000000000000 +0000010001101100 0000100001000000011011000000000000000000 +0000010001100001 0000010011000000011011000000000000000000 +0000010001101001 0001010010000000011011000000000000000000 +0000010001101101 0000110010000000011011000000000000000000 +0000010001100010 0001010001000000011011000000000000000000 +0000010001100110 0001010010000000011011000000000000000000 +0000010001101110 0001110000000000011011000000000000000000 +0000010001100011 0000100001000000011011000000000000000000 +0000010001100111 0000110010000000011011000000000000000000 +0000010001101011 0001110000000000011011000000000000000000 +0000010010100100 0000010011000000101011000000000000000000 +0000010010101000 0001010001000000101011000000000000000000 +0000010010101100 0000100001000000101011000000000000000000 +0000010010100001 0000010011000000101011000000000000000000 +0000010010101001 0001010010000000101011000000000000000000 +0000010010101101 0000110010000000101011000000000000000000 +0000010010100010 0001010001000000101011000000000000000000 +0000010010100110 0001010010000000101011000000000000000000 +0000010010101110 0001110000000000101011000000000000000000 +0000010010100011 0000100001000000101011000000000000000000 +0000010010100111 0000110010000000101011000000000000000000 +0000010010101011 0001110000000000101011000000000000000000 +0000010000100100 0000010011000000001011000000000000000000 +0000010000101000 0001010001000000001011000000000000000000 +0000010000101100 0000100001000000001011000000000000000000 +0000010000100001 0000010011000000001011000000000000000000 +0000010000101001 0001010010000000001011000000000000000000 +0000010000101101 0000110010000000001011000000000000000000 +0000010000100010 0001010001000000001011000000000000000000 +0000010000100110 0001010010000000001011000000000000000000 +0000010000101110 0001110000000000001011000000000000000000 +0000010000100011 0000100001000000001011000000000000000000 +0000010000100111 0000110010000000001011000000000000000000 +0000010000101011 0001110000000000001011000000000000000000 +0000010011100100 0000010011000000111011000000000000000000 +0000010011101000 0001010001000000111011000000000000000000 +0000010011101100 0000100001000000111011000000000000000000 +0000010011100001 0000010011000000111011000000000000000000 +0000010011101001 0001010010000000111011000000000000000000 +0000010011101101 0000110010000000111011000000000000000000 +0000010011100010 0001010001000000111011000000000000000000 +0000010011100110 0001010010000000111011000000000000000000 +0000010011101110 0001110000000000111011000000000000000000 +0000010011100011 0000100001000000111011000000000000000000 +0000010011100111 0000110010000000111011000000000000000000 +0000010011101011 0001110000000000111011000000000000000000 +0000010001010100 0000010011000000010111000000000000000000 +0000010001011000 0001010001000000010111000000000000000000 +0000010001011100 0000100001000000010111000000000000000000 +0000010001010001 0000010011000000010111000000000000000000 +0000010001011001 0001010010000000010111000000000000000000 +0000010001011101 0000110010000000010111000000000000000000 +0000010001010010 0001010001000000010111000000000000000000 +0000010001010110 0001010010000000010111000000000000000000 +0000010001011110 0001110000000000010111000000000000000000 +0000010001010011 0000100001000000010111000000000000000000 +0000010001010111 0000110010000000010111000000000000000000 +0000010001011011 0001110000000000010111000000000000000000 +0000010010010100 0000010011000000100111000000000000000000 +0000010010011000 0001010001000000100111000000000000000000 +0000010010011100 0000100001000000100111000000000000000000 +0000010010010001 0000010011000000100111000000000000000000 +0000010010011001 0001010010000000100111000000000000000000 +0000010010011101 0000110010000000100111000000000000000000 +0000010010010010 0001010001000000100111000000000000000000 +0000010010010110 0001010010000000100111000000000000000000 +0000010010011110 0001110000000000100111000000000000000000 +0000010010010011 0000100001000000100111000000000000000000 +0000010010010111 0000110010000000100111000000000000000000 +0000010010011011 0001110000000000100111000000000000000000 +0000010000010100 0000010011000000000111000000000000000000 +0000010000011000 0001010001000000000111000000000000000000 +0000010000011100 0000100001000000000111000000000000000000 +0000010000010001 0000010011000000000111000000000000000000 +0000010000011001 0001010010000000000111000000000000000000 +0000010000011101 0000110010000000000111000000000000000000 +0000010000010010 0001010001000000000111000000000000000000 +0000010000010110 0001010010000000000111000000000000000000 +0000010000011110 0001110000000000000111000000000000000000 +0000010000010011 0000100001000000000111000000000000000000 +0000010000010111 0000110010000000000111000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000010000011011 0001110000000000000111000000000000000000 +0000010011010100 0000010011000000110111000000000000000000 +0000010011011000 0001010001000000110111000000000000000000 +0000010011011100 0000100001000000110111000000000000000000 +0000010011010001 0000010011000000110111000000000000000000 +0000010011011001 0001010010000000110111000000000000000000 +0000010011011101 0000110010000000110111000000000000000000 +0000010011010010 0001010001000000110111000000000000000000 +0000010011010110 0001010010000000110111000000000000000000 +0000010011011110 0001110000000000110111000000000000000000 +0000010011010011 0000100001000000110111000000000000000000 +0000010011010111 0000110010000000110111000000000000000000 +0000010011011011 0001110000000000110111000000000000000000 +0000010001000100 0000010011000000010011000000000000000000 +0000010001001000 0001010001000000010011000000000000000000 +0000010001001100 0000100001000000010011000000000000000000 +0000010001000001 0000010011000000010011000000000000000000 +0000010001001001 0001010010000000010011000000000000000000 +0000010001001101 0000110010000000010011000000000000000000 +0000010001000010 0001010001000000010011000000000000000000 +0000010001000110 0001010010000000010011000000000000000000 +0000010001001110 0001110000000000010011000000000000000000 +0000010001000011 0000100001000000010011000000000000000000 +0000010001000111 0000110010000000010011000000000000000000 +0000010001001011 0001110000000000010011000000000000000000 +0000010010000100 0000010011000000100011000000000000000000 +0000010010001000 0001010001000000100011000000000000000000 +0000010010001100 0000100001000000100011000000000000000000 +0000010010000001 0000010011000000100011000000000000000000 +0000010010001001 0001010010000000100011000000000000000000 +0000010010001101 0000110010000000100011000000000000000000 +0000010010000010 0001010001000000100011000000000000000000 +0000010010000110 0001010010000000100011000000000000000000 +0000010010001110 0001110000000000100011000000000000000000 +0000010010000011 0000100001000000100011000000000000000000 +0000010010000111 0000110010000000100011000000000000000000 +0000010010001011 0001110000000000100011000000000000000000 +0000010000000100 0000010011000000000011000000000000000000 +0000010000001000 0001010001000000000011000000000000000000 +0000010000001100 0000100001000000000011000000000000000000 +0000010000000001 0000010011000000000011000000000000000000 +0000010000001001 0001010010000000000011000000000000000000 +0000010000001101 0000110010000000000011000000000000000000 +0000010000000010 0001010001000000000011000000000000000000 +0000010000000110 0001010010000000000011000000000000000000 +0000010000001110 0001110000000000000011000000000000000000 +0000010000000011 0000100001000000000011000000000000000000 +0000010000000111 0000110010000000000011000000000000000000 +0000010000001011 0001110000000000000011000000000000000000 +0000010011000100 0000010011000000110011000000000000000000 +0000010011001000 0001010001000000110011000000000000000000 +0000010011001100 0000100001000000110011000000000000000000 +0000010011000001 0000010011000000110011000000000000000000 +0000010011001001 0001010010000000110011000000000000000000 +0000010011001101 0000110010000000110011000000000000000000 +0000010011000010 0001010001000000110011000000000000000000 +0000010011000110 0001010010000000110011000000000000000000 +0000010011001110 0001110000000000110011000000000000000000 +0000010011000011 0000100001000000110011000000000000000000 +0000010011000111 0000110010000000110011000000000000000000 +0000010011001011 0001110000000000110011000000000000000000 +0000010001110100 0000010011000000011111000000000000000000 +0000010001111000 0001010001000000011111000000000000000000 +0000010001111100 0000100001000000011111000000000000000000 +0000010001110001 0000010011000000011111000000000000000000 +0000010001111001 0001010010000000011111000000000000000000 +0000010001111101 0000110010000000011111000000000000000000 +0000010001110010 0001010001000000011111000000000000000000 +0000010001110110 0001010010000000011111000000000000000000 +0000010001111110 0001110000000000011111000000000000000000 +0000010001110011 0000100001000000011111000000000000000000 +0000010001110111 0000110010000000011111000000000000000000 +0000010001111011 0001110000000000011111000000000000000000 +0000010010110100 0000010011000000101111000000000000000000 +0000010010111000 0001010001000000101111000000000000000000 +0000010010111100 0000100001000000101111000000000000000000 +0000010010110001 0000010011000000101111000000000000000000 +0000010010111001 0001010010000000101111000000000000000000 +0000010010111101 0000110010000000101111000000000000000000 +0000010010110010 0001010001000000101111000000000000000000 +0000010010110110 0001010010000000101111000000000000000000 +0000010010111110 0001110000000000101111000000000000000000 +0000010010110011 0000100001000000101111000000000000000000 +0000010010110111 0000110010000000101111000000000000000000 +0000010010111011 0001110000000000101111000000000000000000 +0000010000110100 0000010011000000001111000000000000000000 +0000010000111000 0001010001000000001111000000000000000000 +0000010000111100 0000100001000000001111000000000000000000 +0000010000110001 0000010011000000001111000000000000000000 +0000010000111001 0001010010000000001111000000000000000000 +0000010000111101 0000110010000000001111000000000000000000 +0000010000110010 0001010001000000001111000000000000000000 +0000010000110110 0001010010000000001111000000000000000000 +0000010000111110 0001110000000000001111000000000000000000 +0000010000110011 0000100001000000001111000000000000000000 +0000010000110111 0000110010000000001111000000000000000000 +0000010000111011 0001110000000000001111000000000000000000 +0000010011110100 0000010011000000111111000000000000000000 +0000010011111000 0001010001000000111111000000000000000000 +0000010011111100 0000100001000000111111000000000000000000 +0000010011110001 0000010011000000111111000000000000000000 +0000010011111001 0001010010000000111111000000000000000000 +0000010011111101 0000110010000000111111000000000000000000 +0000010011110010 0001010001000000111111000000000000000000 +0000010011110110 0001010010000000111111000000000000000000 +0000010011111110 0001110000000000111111000000000000000000 +0000010011110011 0000100001000000111111000000000000000000 +0000010011110111 0000110010000000111111000000000000000000 +0000010011111011 0001110000000000111111000000000000000000 +000001010110---- 0001010000000000011011000000000000000000 +000001011010---- 0001010000000000101011000000000000000000 +000001010101---- 0000100000000000010111000000000000000000 +000001011001---- 0000100000000000100111000000000000000000 +000001010100---- 0001010000000000010011000000000000000000 +000001011000---- 0001010000000000100011000000000000000000 +000001010111---- 0000100000000000011111000000000000000000 +000001011011---- 0000100000000000101111000000000000000000 +0000111101100000 0000000001100000011000010100000000101000 +0000111101100101 0000010010100000011000010100000000101000 +0000111101101010 0001010000100000011000010100000000101000 +0000111101101111 0000100000100000011000010100000000101000 +0000111110100000 0000000001100000101000010100000000101000 +0000111110100101 0000010010100000101000010100000000101000 +0000111110101010 0001010000100000101000010100000000101000 +0000111110101111 0000100000100000101000010100000000101000 +0000111100100000 0000000001100000001000010100000000101000 +0000111100100101 0000010010100000001000010100000000101000 +0000111100101010 0001010000100000001000010100000000101000 +0000111100101111 0000100000100000001000010100000000101000 +0000111111100000 0000000001100000111000010100000000101000 +0000111111100101 0000010010100000111000010100000000101000 +0000111111101010 0001010000100000111000010100000000101000 +0000111111101111 0000100000100000111000010100000000101000 +0000111101010000 0000000001100000010100010100000000101000 +0000111101010101 0000010010100000010100010100000000101000 +0000111101011010 0001010000100000010100010100000000101000 +0000111101011111 0000100000100000010100010100000000101000 +0000111110010000 0000000001100000100100010100000000101000 +0000111110010101 0000010010100000100100010100000000101000 +0000111110011010 0001010000100000100100010100000000101000 +0000111110011111 0000100000100000100100010100000000101000 +0000111100010000 0000000001100000000100010100000000101000 +0000111100010101 0000010010100000000100010100000000101000 +0000111100011010 0001010000100000000100010100000000101000 +0000111100011111 0000100000100000000100010100000000101000 +0000111111010000 0000000001100000110100010100000000101000 +0000111111010101 0000010010100000110100010100000000101000 +0000111111011010 0001010000100000110100010100000000101000 +0000111111011111 0000100000100000110100010100000000101000 +0000111101000000 0000000001100000010000010100000000101000 +0000111101000101 0000010010100000010000010100000000101000 +0000111101001010 0001010000100000010000010100000000101000 +0000111101001111 0000100000100000010000010100000000101000 +0000111110000000 0000000001100000100000010100000000101000 +0000111110000101 0000010010100000100000010100000000101000 +0000111110001010 0001010000100000100000010100000000101000 +0000111110001111 0000100000100000100000010100000000101000 +0000111100000000 0000000001100000000000010100000000101000 +0000111100000101 0000010010100000000000010100000000101000 +0000111100001010 0001010000100000000000010100000000101000 +0000111100001111 0000100000100000000000010100000000101000 +0000111111000000 0000000001100000110000010100000000101000 +0000111111000101 0000010010100000110000010100000000101000 +0000111111001010 0001010000100000110000010100000000101000 +0000111111001111 0000100000100000110000010100000000101000 +0000111101110000 0000000001100000011100010100000000101000 +0000111101110101 0000010010100000011100010100000000101000 +0000111101111010 0001010000100000011100010100000000101000 +0000111101111111 0000100000100000011100010100000000101000 +0000111110110000 0000000001100000101100010100000000101000 +0000111110110101 0000010010100000101100010100000000101000 +0000111110111010 0001010000100000101100010100000000101000 +0000111110111111 0000100000100000101100010100000000101000 +0000111100110000 0000000001100000001100010100000000101000 +0000111100110101 0000010010100000001100010100000000101000 +0000111100111010 0001010000100000001100010100000000101000 +0000111100111111 0000100000100000001100010100000000101000 +0000111111110000 0000000001100000111100010100000000101000 +0000111111110101 0000010010100000111100010100000000101000 +0000111111111010 0001010000100000111100010100000000101000 +0000111111111111 0000100000100000111100010100000000101000 +0000111101100100 0000010011100000011000010100000000101000 +0000111101101000 0001010001100000011000010100000000101000 +0000111101101100 0000100001100000011000010100000000101000 +0000111101100001 0000010011100000011000010100000000101000 +0000111101101001 0001010010100000011000010100000000101000 +0000111101101101 0000110010100000011000010100000000101000 +0000111101100010 0001010001100000011000010100000000101000 +0000111101100110 0001010010100000011000010100000000101000 +0000111101101110 0001110000100000011000010100000000101000 +0000111101100011 0000100001100000011000010100000000101000 +0000111101100111 0000110010100000011000010100000000101000 +0000111101101011 0001110000100000011000010100000000101000 +0000111110100100 0000010011100000101000010100000000101000 +0000111110101000 0001010001100000101000010100000000101000 +0000111110101100 0000100001100000101000010100000000101000 +0000111110100001 0000010011100000101000010100000000101000 +0000111110101001 0001010010100000101000010100000000101000 +0000111110101101 0000110010100000101000010100000000101000 +0000111110100010 0001010001100000101000010100000000101000 +0000111110100110 0001010010100000101000010100000000101000 +0000111110101110 0001110000100000101000010100000000101000 +0000111110100011 0000100001100000101000010100000000101000 +0000111110100111 0000110010100000101000010100000000101000 +0000111110101011 0001110000100000101000010100000000101000 +0000111100100100 0000010011100000001000010100000000101000 +0000111100101000 0001010001100000001000010100000000101000 +0000111100101100 0000100001100000001000010100000000101000 +0000111100100001 0000010011100000001000010100000000101000 +0000111100101001 0001010010100000001000010100000000101000 +0000111100101101 0000110010100000001000010100000000101000 +0000111100100010 0001010001100000001000010100000000101000 +0000111100100110 0001010010100000001000010100000000101000 +0000111100101110 0001110000100000001000010100000000101000 +0000111100100011 0000100001100000001000010100000000101000 +0000111100100111 0000110010100000001000010100000000101000 +0000111100101011 0001110000100000001000010100000000101000 +0000111111100100 0000010011100000111000010100000000101000 +0000111111101000 0001010001100000111000010100000000101000 +0000111111101100 0000100001100000111000010100000000101000 +0000111111100001 0000010011100000111000010100000000101000 +0000111111101001 0001010010100000111000010100000000101000 +0000111111101101 0000110010100000111000010100000000101000 +0000111111100010 0001010001100000111000010100000000101000 +0000111111100110 0001010010100000111000010100000000101000 +0000111111101110 0001110000100000111000010100000000101000 +0000111111100011 0000100001100000111000010100000000101000 +0000111111100111 0000110010100000111000010100000000101000 +0000111111101011 0001110000100000111000010100000000101000 +0000111101010100 0000010011100000010100010100000000101000 +0000111101011000 0001010001100000010100010100000000101000 +0000111101011100 0000100001100000010100010100000000101000 +0000111101010001 0000010011100000010100010100000000101000 +0000111101011001 0001010010100000010100010100000000101000 +0000111101011101 0000110010100000010100010100000000101000 +0000111101010010 0001010001100000010100010100000000101000 +0000111101010110 0001010010100000010100010100000000101000 +0000111101011110 0001110000100000010100010100000000101000 +0000111101010011 0000100001100000010100010100000000101000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000111101010111 0000110010100000010100010100000000101000 +0000111101011011 0001110000100000010100010100000000101000 +0000111110010100 0000010011100000100100010100000000101000 +0000111110011000 0001010001100000100100010100000000101000 +0000111110011100 0000100001100000100100010100000000101000 +0000111110010001 0000010011100000100100010100000000101000 +0000111110011001 0001010010100000100100010100000000101000 +0000111110011101 0000110010100000100100010100000000101000 +0000111110010010 0001010001100000100100010100000000101000 +0000111110010110 0001010010100000100100010100000000101000 +0000111110011110 0001110000100000100100010100000000101000 +0000111110010011 0000100001100000100100010100000000101000 +0000111110010111 0000110010100000100100010100000000101000 +0000111110011011 0001110000100000100100010100000000101000 +0000111100010100 0000010011100000000100010100000000101000 +0000111100011000 0001010001100000000100010100000000101000 +0000111100011100 0000100001100000000100010100000000101000 +0000111100010001 0000010011100000000100010100000000101000 +0000111100011001 0001010010100000000100010100000000101000 +0000111100011101 0000110010100000000100010100000000101000 +0000111100010010 0001010001100000000100010100000000101000 +0000111100010110 0001010010100000000100010100000000101000 +0000111100011110 0001110000100000000100010100000000101000 +0000111100010011 0000100001100000000100010100000000101000 +0000111100010111 0000110010100000000100010100000000101000 +0000111100011011 0001110000100000000100010100000000101000 +0000111111010100 0000010011100000110100010100000000101000 +0000111111011000 0001010001100000110100010100000000101000 +0000111111011100 0000100001100000110100010100000000101000 +0000111111010001 0000010011100000110100010100000000101000 +0000111111011001 0001010010100000110100010100000000101000 +0000111111011101 0000110010100000110100010100000000101000 +0000111111010010 0001010001100000110100010100000000101000 +0000111111010110 0001010010100000110100010100000000101000 +0000111111011110 0001110000100000110100010100000000101000 +0000111111010011 0000100001100000110100010100000000101000 +0000111111010111 0000110010100000110100010100000000101000 +0000111111011011 0001110000100000110100010100000000101000 +0000111101000100 0000010011100000010000010100000000101000 +0000111101001000 0001010001100000010000010100000000101000 +0000111101001100 0000100001100000010000010100000000101000 +0000111101000001 0000010011100000010000010100000000101000 +0000111101001001 0001010010100000010000010100000000101000 +0000111101001101 0000110010100000010000010100000000101000 +0000111101000010 0001010001100000010000010100000000101000 +0000111101000110 0001010010100000010000010100000000101000 +0000111101001110 0001110000100000010000010100000000101000 +0000111101000011 0000100001100000010000010100000000101000 +0000111101000111 0000110010100000010000010100000000101000 +0000111101001011 0001110000100000010000010100000000101000 +0000111110000100 0000010011100000100000010100000000101000 +0000111110001000 0001010001100000100000010100000000101000 +0000111110001100 0000100001100000100000010100000000101000 +0000111110000001 0000010011100000100000010100000000101000 +0000111110001001 0001010010100000100000010100000000101000 +0000111110001101 0000110010100000100000010100000000101000 +0000111110000010 0001010001100000100000010100000000101000 +0000111110000110 0001010010100000100000010100000000101000 +0000111110001110 0001110000100000100000010100000000101000 +0000111110000011 0000100001100000100000010100000000101000 +0000111110000111 0000110010100000100000010100000000101000 +0000111110001011 0001110000100000100000010100000000101000 +0000111100000100 0000010011100000000000010100000000101000 +0000111100001000 0001010001100000000000010100000000101000 +0000111100001100 0000100001100000000000010100000000101000 +0000111100000001 0000010011100000000000010100000000101000 +0000111100001001 0001010010100000000000010100000000101000 +0000111100001101 0000110010100000000000010100000000101000 +0000111100000010 0001010001100000000000010100000000101000 +0000111100000110 0001010010100000000000010100000000101000 +0000111100001110 0001110000100000000000010100000000101000 +0000111100000011 0000100001100000000000010100000000101000 +0000111100000111 0000110010100000000000010100000000101000 +0000111100001011 0001110000100000000000010100000000101000 +0000111111000100 0000010011100000110000010100000000101000 +0000111111001000 0001010001100000110000010100000000101000 +0000111111001100 0000100001100000110000010100000000101000 +0000111111000001 0000010011100000110000010100000000101000 +0000111111001001 0001010010100000110000010100000000101000 +0000111111001101 0000110010100000110000010100000000101000 +0000111111000010 0001010001100000110000010100000000101000 +0000111111000110 0001010010100000110000010100000000101000 +0000111111001110 0001110000100000110000010100000000101000 +0000111111000011 0000100001100000110000010100000000101000 +0000111111000111 0000110010100000110000010100000000101000 +0000111111001011 0001110000100000110000010100000000101000 +0000111101110100 0000010011100000011100010100000000101000 +0000111101111000 0001010001100000011100010100000000101000 +0000111101111100 0000100001100000011100010100000000101000 +0000111101110001 0000010011100000011100010100000000101000 +0000111101111001 0001010010100000011100010100000000101000 +0000111101111101 0000110010100000011100010100000000101000 +0000111101110010 0001010001100000011100010100000000101000 +0000111101110110 0001010010100000011100010100000000101000 +0000111101111110 0001110000100000011100010100000000101000 +0000111101110011 0000100001100000011100010100000000101000 +0000111101110111 0000110010100000011100010100000000101000 +0000111101111011 0001110000100000011100010100000000101000 +0000111110110100 0000010011100000101100010100000000101000 +0000111110111000 0001010001100000101100010100000000101000 +0000111110111100 0000100001100000101100010100000000101000 +0000111110110001 0000010011100000101100010100000000101000 +0000111110111001 0001010010100000101100010100000000101000 +0000111110111101 0000110010100000101100010100000000101000 +0000111110110010 0001010001100000101100010100000000101000 +0000111110110110 0001010010100000101100010100000000101000 +0000111110111110 0001110000100000101100010100000000101000 +0000111110110011 0000100001100000101100010100000000101000 +0000111110110111 0000110010100000101100010100000000101000 +0000111110111011 0001110000100000101100010100000000101000 +0000111100110100 0000010011100000001100010100000000101000 +0000111100111000 0001010001100000001100010100000000101000 +0000111100111100 0000100001100000001100010100000000101000 +0000111100110001 0000010011100000001100010100000000101000 +0000111100111001 0001010010100000001100010100000000101000 +0000111100111101 0000110010100000001100010100000000101000 +0000111100110010 0001010001100000001100010100000000101000 +0000111100110110 0001010010100000001100010100000000101000 +0000111100111110 0001110000100000001100010100000000101000 +0000111100110011 0000100001100000001100010100000000101000 +0000111100110111 0000110010100000001100010100000000101000 +0000111100111011 0001110000100000001100010100000000101000 +0000111111110100 0000010011100000111100010100000000101000 +0000111111111000 0001010001100000111100010100000000101000 +0000111111111100 0000100001100000111100010100000000101000 +0000111111110001 0000010011100000111100010100000000101000 +0000111111111001 0001010010100000111100010100000000101000 +0000111111111101 0000110010100000111100010100000000101000 +0000111111110010 0001010001100000111100010100000000101000 +0000111111110110 0001010010100000111100010100000000101000 +0000111111111110 0001110000100000111100010100000000101000 +0000111111110011 0000100001100000111100010100000000101000 +0000111111110111 0000110010100000111100010100000000101000 +0000111111111011 0001110000100000111100010100000000101000 +0000100101100000 0000000001000100011000000000000000000000 +0000100101100101 0000010010000100011000000000000000000000 +0000100101101010 0001010000000100011000000000000000000000 +0000100101101111 0000100000000100011000000000000000000000 +0000100110100000 0000000001000100101000000000000000000000 +0000100110100101 0000010010000100101000000000000000000000 +0000100110101010 0001010000000100101000000000000000000000 +0000100110101111 0000100000000100101000000000000000000000 +0000100100100000 0000000001000100001000000000000000000000 +0000100100100101 0000010010000100001000000000000000000000 +0000100100101010 0001010000000100001000000000000000000000 +0000100100101111 0000100000000100001000000000000000000000 +0000100111100000 0000000001000100111000000000000000000000 +0000100111100101 0000010010000100111000000000000000000000 +0000100111101010 0001010000000100111000000000000000000000 +0000100111101111 0000100000000100111000000000000000000000 +0000100101010000 0000000001000100010100000000000000000000 +0000100101010101 0000010010000100010100000000000000000000 +0000100101011010 0001010000000100010100000000000000000000 +0000100101011111 0000100000000100010100000000000000000000 +0000100110010000 0000000001000100100100000000000000000000 +0000100110010101 0000010010000100100100000000000000000000 +0000100110011010 0001010000000100100100000000000000000000 +0000100110011111 0000100000000100100100000000000000000000 +0000100100010000 0000000001000100000100000000000000000000 +0000100100010101 0000010010000100000100000000000000000000 +0000100100011010 0001010000000100000100000000000000000000 +0000100100011111 0000100000000100000100000000000000000000 +0000100111010000 0000000001000100110100000000000000000000 +0000100111010101 0000010010000100110100000000000000000000 +0000100111011010 0001010000000100110100000000000000000000 +0000100111011111 0000100000000100110100000000000000000000 +0000100101000000 0000000001000100010000000000000000000000 +0000100101000101 0000010010000100010000000000000000000000 +0000100101001010 0001010000000100010000000000000000000000 +0000100101001111 0000100000000100010000000000000000000000 +0000100110000000 0000000001000100100000000000000000000000 +0000100110000101 0000010010000100100000000000000000000000 +0000100110001010 0001010000000100100000000000000000000000 +0000100110001111 0000100000000100100000000000000000000000 +0000100100000000 0000000001000100000000000000000000000000 +0000100100000101 0000010010000100000000000000000000000000 +0000100100001010 0001010000000100000000000000000000000000 +0000100100001111 0000100000000100000000000000000000000000 +0000100111000000 0000000001000100110000000000000000000000 +0000100111000101 0000010010000100110000000000000000000000 +0000100111001010 0001010000000100110000000000000000000000 +0000100111001111 0000100000000100110000000000000000000000 +0000100101110000 0000000001000100011100000000000000000000 +0000100101110101 0000010010000100011100000000000000000000 +0000100101111010 0001010000000100011100000000000000000000 +0000100101111111 0000100000000100011100000000000000000000 +0000100110110000 0000000001000100101100000000000000000000 +0000100110110101 0000010010000100101100000000000000000000 +0000100110111010 0001010000000100101100000000000000000000 +0000100110111111 0000100000000100101100000000000000000000 +0000100100110000 0000000001000100001100000000000000000000 +0000100100110101 0000010010000100001100000000000000000000 +0000100100111010 0001010000000100001100000000000000000000 +0000100100111111 0000100000000100001100000000000000000000 +0000100111110000 0000000001000100111100000000000000000000 +0000100111110101 0000010010000100111100000000000000000000 +0000100111111010 0001010000000100111100000000000000000000 +0000100111111111 0000100000000100111100000000000000000000 +0000100101100100 0000010011000100011000000000000000000000 +0000100101101000 0001010001000100011000000000000000000000 +0000100101101100 0000100001000100011000000000000000000000 +0000100101100001 0000010011000100011000000000000000000000 +0000100101101001 0001010010000100011000000000000000000000 +0000100101101101 0000110010000100011000000000000000000000 +0000100101100010 0001010001000100011000000000000000000000 +0000100101100110 0001010010000100011000000000000000000000 +0000100101101110 0001110000000100011000000000000000000000 +0000100101100011 0000100001000100011000000000000000000000 +0000100101100111 0000110010000100011000000000000000000000 +0000100101101011 0001110000000100011000000000000000000000 +0000100110100100 0000010011000100101000000000000000000000 +0000100110101000 0001010001000100101000000000000000000000 +0000100110101100 0000100001000100101000000000000000000000 +0000100110100001 0000010011000100101000000000000000000000 +0000100110101001 0001010010000100101000000000000000000000 +0000100110101101 0000110010000100101000000000000000000000 +0000100110100010 0001010001000100101000000000000000000000 +0000100110100110 0001010010000100101000000000000000000000 +0000100110101110 0001110000000100101000000000000000000000 +0000100110100011 0000100001000100101000000000000000000000 +0000100110100111 0000110010000100101000000000000000000000 +0000100110101011 0001110000000100101000000000000000000000 +0000100100100100 0000010011000100001000000000000000000000 +0000100100101000 0001010001000100001000000000000000000000 +0000100100101100 0000100001000100001000000000000000000000 +0000100100100001 0000010011000100001000000000000000000000 +0000100100101001 0001010010000100001000000000000000000000 +0000100100101101 0000110010000100001000000000000000000000 +0000100100100010 0001010001000100001000000000000000000000 +0000100100100110 0001010010000100001000000000000000000000 +0000100100101110 0001110000000100001000000000000000000000 +0000100100100011 0000100001000100001000000000000000000000 +0000100100100111 0000110010000100001000000000000000000000 +0000100100101011 0001110000000100001000000000000000000000 +0000100111100100 0000010011000100111000000000000000000000 +0000100111101000 0001010001000100111000000000000000000000 +0000100111101100 0000100001000100111000000000000000000000 +0000100111100001 0000010011000100111000000000000000000000 +0000100111101001 0001010010000100111000000000000000000000 +0000100111101101 0000110010000100111000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000100111100010 0001010001000100111000000000000000000000 +0000100111100110 0001010010000100111000000000000000000000 +0000100111101110 0001110000000100111000000000000000000000 +0000100111100011 0000100001000100111000000000000000000000 +0000100111100111 0000110010000100111000000000000000000000 +0000100111101011 0001110000000100111000000000000000000000 +0000100101010100 0000010011000100010100000000000000000000 +0000100101011000 0001010001000100010100000000000000000000 +0000100101011100 0000100001000100010100000000000000000000 +0000100101010001 0000010011000100010100000000000000000000 +0000100101011001 0001010010000100010100000000000000000000 +0000100101011101 0000110010000100010100000000000000000000 +0000100101010010 0001010001000100010100000000000000000000 +0000100101010110 0001010010000100010100000000000000000000 +0000100101011110 0001110000000100010100000000000000000000 +0000100101010011 0000100001000100010100000000000000000000 +0000100101010111 0000110010000100010100000000000000000000 +0000100101011011 0001110000000100010100000000000000000000 +0000100110010100 0000010011000100100100000000000000000000 +0000100110011000 0001010001000100100100000000000000000000 +0000100110011100 0000100001000100100100000000000000000000 +0000100110010001 0000010011000100100100000000000000000000 +0000100110011001 0001010010000100100100000000000000000000 +0000100110011101 0000110010000100100100000000000000000000 +0000100110010010 0001010001000100100100000000000000000000 +0000100110010110 0001010010000100100100000000000000000000 +0000100110011110 0001110000000100100100000000000000000000 +0000100110010011 0000100001000100100100000000000000000000 +0000100110010111 0000110010000100100100000000000000000000 +0000100110011011 0001110000000100100100000000000000000000 +0000100100010100 0000010011000100000100000000000000000000 +0000100100011000 0001010001000100000100000000000000000000 +0000100100011100 0000100001000100000100000000000000000000 +0000100100010001 0000010011000100000100000000000000000000 +0000100100011001 0001010010000100000100000000000000000000 +0000100100011101 0000110010000100000100000000000000000000 +0000100100010010 0001010001000100000100000000000000000000 +0000100100010110 0001010010000100000100000000000000000000 +0000100100011110 0001110000000100000100000000000000000000 +0000100100010011 0000100001000100000100000000000000000000 +0000100100010111 0000110010000100000100000000000000000000 +0000100100011011 0001110000000100000100000000000000000000 +0000100111010100 0000010011000100110100000000000000000000 +0000100111011000 0001010001000100110100000000000000000000 +0000100111011100 0000100001000100110100000000000000000000 +0000100111010001 0000010011000100110100000000000000000000 +0000100111011001 0001010010000100110100000000000000000000 +0000100111011101 0000110010000100110100000000000000000000 +0000100111010010 0001010001000100110100000000000000000000 +0000100111010110 0001010010000100110100000000000000000000 +0000100111011110 0001110000000100110100000000000000000000 +0000100111010011 0000100001000100110100000000000000000000 +0000100111010111 0000110010000100110100000000000000000000 +0000100111011011 0001110000000100110100000000000000000000 +0000100101000100 0000010011000100010000000000000000000000 +0000100101001000 0001010001000100010000000000000000000000 +0000100101001100 0000100001000100010000000000000000000000 +0000100101000001 0000010011000100010000000000000000000000 +0000100101001001 0001010010000100010000000000000000000000 +0000100101001101 0000110010000100010000000000000000000000 +0000100101000010 0001010001000100010000000000000000000000 +0000100101000110 0001010010000100010000000000000000000000 +0000100101001110 0001110000000100010000000000000000000000 +0000100101000011 0000100001000100010000000000000000000000 +0000100101000111 0000110010000100010000000000000000000000 +0000100101001011 0001110000000100010000000000000000000000 +0000100110000100 0000010011000100100000000000000000000000 +0000100110001000 0001010001000100100000000000000000000000 +0000100110001100 0000100001000100100000000000000000000000 +0000100110000001 0000010011000100100000000000000000000000 +0000100110001001 0001010010000100100000000000000000000000 +0000100110001101 0000110010000100100000000000000000000000 +0000100110000010 0001010001000100100000000000000000000000 +0000100110000110 0001010010000100100000000000000000000000 +0000100110001110 0001110000000100100000000000000000000000 +0000100110000011 0000100001000100100000000000000000000000 +0000100110000111 0000110010000100100000000000000000000000 +0000100110001011 0001110000000100100000000000000000000000 +0000100100000100 0000010011000100000000000000000000000000 +0000100100001000 0001010001000100000000000000000000000000 +0000100100001100 0000100001000100000000000000000000000000 +0000100100000001 0000010011000100000000000000000000000000 +0000100100001001 0001010010000100000000000000000000000000 +0000100100001101 0000110010000100000000000000000000000000 +0000100100000010 0001010001000100000000000000000000000000 +0000100100000110 0001010010000100000000000000000000000000 +0000100100001110 0001110000000100000000000000000000000000 +0000100100000011 0000100001000100000000000000000000000000 +0000100100000111 0000110010000100000000000000000000000000 +0000100100001011 0001110000000100000000000000000000000000 +0000100111000100 0000010011000100110000000000000000000000 +0000100111001000 0001010001000100110000000000000000000000 +0000100111001100 0000100001000100110000000000000000000000 +0000100111000001 0000010011000100110000000000000000000000 +0000100111001001 0001010010000100110000000000000000000000 +0000100111001101 0000110010000100110000000000000000000000 +0000100111000010 0001010001000100110000000000000000000000 +0000100111000110 0001010010000100110000000000000000000000 +0000100111001110 0001110000000100110000000000000000000000 +0000100111000011 0000100001000100110000000000000000000000 +0000100111000111 0000110010000100110000000000000000000000 +0000100111001011 0001110000000100110000000000000000000000 +0000100101110100 0000010011000100011100000000000000000000 +0000100101111000 0001010001000100011100000000000000000000 +0000100101111100 0000100001000100011100000000000000000000 +0000100101110001 0000010011000100011100000000000000000000 +0000100101111001 0001010010000100011100000000000000000000 +0000100101111101 0000110010000100011100000000000000000000 +0000100101110010 0001010001000100011100000000000000000000 +0000100101110110 0001010010000100011100000000000000000000 +0000100101111110 0001110000000100011100000000000000000000 +0000100101110011 0000100001000100011100000000000000000000 +0000100101110111 0000110010000100011100000000000000000000 +0000100101111011 0001110000000100011100000000000000000000 +0000100110110100 0000010011000100101100000000000000000000 +0000100110111000 0001010001000100101100000000000000000000 +0000100110111100 0000100001000100101100000000000000000000 +0000100110110001 0000010011000100101100000000000000000000 +0000100110111001 0001010010000100101100000000000000000000 +0000100110111101 0000110010000100101100000000000000000000 +0000100110110010 0001010001000100101100000000000000000000 +0000100110110110 0001010010000100101100000000000000000000 +0000100110111110 0001110000000100101100000000000000000000 +0000100110110011 0000100001000100101100000000000000000000 +0000100110110111 0000110010000100101100000000000000000000 +0000100110111011 0001110000000100101100000000000000000000 +0000100100110100 0000010011000100001100000000000000000000 +0000100100111000 0001010001000100001100000000000000000000 +0000100100111100 0000100001000100001100000000000000000000 +0000100100110001 0000010011000100001100000000000000000000 +0000100100111001 0001010010000100001100000000000000000000 +0000100100111101 0000110010000100001100000000000000000000 +0000100100110010 0001010001000100001100000000000000000000 +0000100100110110 0001010010000100001100000000000000000000 +0000100100111110 0001110000000100001100000000000000000000 +0000100100110011 0000100001000100001100000000000000000000 +0000100100110111 0000110010000100001100000000000000000000 +0000100100111011 0001110000000100001100000000000000000000 +0000100111110100 0000010011000100111100000000000000000000 +0000100111111000 0001010001000100111100000000000000000000 +0000100111111100 0000100001000100111100000000000000000000 +0000100111110001 0000010011000100111100000000000000000000 +0000100111111001 0001010010000100111100000000000000000000 +0000100111111101 0000110010000100111100000000000000000000 +0000100111110010 0001010001000100111100000000000000000000 +0000100111110110 0001010010000100111100000000000000000000 +0000100111111110 0001110000000100111100000000000000000000 +0000100111110011 0000100001000100111100000000000000000000 +0000100111110111 0000110010000100111100000000000000000000 +0000100111111011 0001110000000100111100000000000000000000 +0000110001100010 0001010000100000011000100000000000000000 +0000110010100010 0001010000100000101000100000000000000000 +0000110001010010 0000100000100000010100100000000000000000 +0000110010010010 0000100000100000100100100000000000000000 +0000110001000010 0001010000100000010000100000000000000000 +0000110010000010 0001010000100000100000100000000000000000 +0000110001110010 0000100000100000011100100000000000000000 +0000110010110010 0000100000100000101100100000000000000000 +0000101101101011 0001010000000000011000100000000000000000 +0000101110101011 0001010000000000101000100000000000000000 +0000101101011011 0000100000000000010100100000000000000000 +0000101110011011 0000100000000000100100100000000000000000 +0000101101001011 0001010000000000010000100000000000000000 +0000101110001011 0001010000000000100000100000000000000000 +0000101101111011 0000100000000000011100100000000000000000 +0000101110111011 0000100000000000101100100000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011011-------- 0000000000000000000000000000100010000000 +01011111-------- 0000000000000000000000000000010010000000 +01011100-------- 0000000000000000000000010000000010001000 +01011001-------- 0000000000000000000000000000100000000010 +01011101-------- 0000000000000000000000000000010000000010 +01011010-------- 0000000000000000000000000000100000000001 +01011110-------- 0000000000000000000000000000010000000001 +01001001-------- 0100000010000000000000000000001010001000 +0100100000100001 0100000010000000000000000000101001001000 +0100100000100010 0100000010000000000000000000101000101000 +0100100000100100 0100000010000000000000000000101000011000 +0100100001000001 0100000010000000000000000000011001001000 +0100100001000010 0100000010000000000000000000011000101000 +0100100001000100 0100000010000000000000000000011000011000 +0100100001100001 0100000010000000000000010000000001001000 +0100100001100010 0100000010000000000000010000000000101000 +0100100001100100 0100000010000000000000010000000000011000 +01001000000----- 0100000010000000000000000000000001010000 +01001011-------- 0101000000000000000000000000001010001000 +0100101000100001 0101000000000000000000000000101001001000 +0100101000100010 0101000000000000000000000000101000101000 +0100101000100100 0101000000000000000000000000101000011000 +0100101001000001 0101000000000000000000000000011001001000 +0100101001000010 0101000000000000000000000000011000101000 +0100101001000100 0101000000000000000000000000011000011000 +0100101001100001 0101000000000000000000010000000001001000 +0100101001100010 0101000000000000000000010000000000101000 +0100101001100100 0101000000000000000000010000000000011000 +01001010000----- 0101000000000000000000000000000001100000 +01000001-------- 1000000100000000000000000000001010000100 +0100000000100001 1000000100000000000000000000101001000100 +0100000000100010 1000000100000000000000000000101000100100 +0100000000100100 1000000100000000000000000000101000010100 +0100000001000001 1000000100000000000000000000011001000100 +0100000001000010 1000000100000000000000000000011000100100 +0100000001000100 1000000100000000000000000000011000010100 +0100000001100001 1000000100000000000000010000000001000100 +0100000001100010 1000000100000000000000010000000000100100 +0100000001100100 1000000100000000000000010000000000010100 +01000000000----- 1000000100000000000000000000000100000100 +01000011-------- 1010000000000000000000000000001010000100 +0100001000100001 1010000000000000000000000000101001000100 +0100001000100010 1010000000000000000000000000101000100100 +0100001000100100 1010000000000000000000000000101000010100 +0100001001000001 1010000000000000000000000000011001000100 +0100001001000010 1010000000000000000000000000011000100100 +0100001001000100 1010000000000000000000000000011000010100 +0100001001100001 1010000000000000000000010000000001000100 +0100001001100010 1010000000000000000000010000000000100100 +0100001001100100 1010000000000000000000010000000000010100 +01000010000----- 1010000000000000000000000000000100000100 +0100000010000000 1000000100000000000000001000000000000000 +0100001010000000 1010000000000000000000001000000000000000 +0100110000100001 0000000000000000000000001000101001001000 +0100110000100010 0000000000000000000000001000101000101000 +0100110000100100 0000000000000000000000001000101000011000 +0100110001000001 0000000000000000000000001000011001001000 +0100110001000010 0000000000000000000000001000011000101000 +0100110001000100 0000000000000000000000001000011000011000 +0100110001100001 0000000000000000000000011000000001001000 +0100110001100010 0000000000000000000000011000000000101000 +0100110001100100 0000000000000000000000011000000000011000 +0100100011000000 0100000010000000000000000000000000000000 +0100101011000000 0101000000000000000000000000000000000000 +0100110111000000 0000000000000000000000000000000000000000 +0100011001100001 0000000000000000000000010000000001000100 +0100011001100010 0000000000000000000000010000000000100100 +0100011001100100 0000000000000000000000010000000000010100 +0100011000100001 0000000000000000000000000000101001000100 +0100011000100010 0000000000000000000000000000101000100100 +0100011000100100 0000000000000000000000000000101000010100 +0100011001000001 0000000000000000000000000000011001000100 +0100011001000010 0000000000000000000000000000011000100100 +0100011001000100 0000000000000000000000000000011000010100 +01000110000----- 0000000000000000000000000000000100000100 +0100100010100000 0100000010000000000000000000000000000000 +0100101010100000 0101000000000000000000000000000000000000 +0100011100100001 0000000000000000000000000000101001000100 +0100011100100010 0000000000000000000000000000101000100100 +0100011100100100 0000000000000000000000000000101000010100 +0100011101000001 0000000000000000000000000000011001000100 +0100011101000010 0000000000000000000000000000011000100100 +0100011101000100 0000000000000000000000000000011000010100 +0100000011000000 1000000100000000000000000000000000000000 +0100001011000000 1010000000000000000000000000000000000000 +0100111001100001 0000000000000000000000010000000001001000 +0100111001100010 0000000000000000000000010000000000101000 +0100111001100100 0000000000000000000000010000000000011000 +0100111000100001 0000000000000000000000000000101001001000 +0100111000100010 0000000000000000000000000000101000101000 +0100111000100100 0000000000000000000000000000101000011000 +0100111001000001 0000000000000000000000000000011001001000 +0100111001000010 0000000000000000000000000000011000101000 +0100111001000100 0000000000000000000000000000011000011000 +01001110000----- 0000000000000000000000000000000000100000 +0100000010100000 1000000100000000000000000000000000000000 +0100001010100000 1010000000000000000000000000000000000000 +0100111100100001 0000000000000000000000000000101001001000 +0100111100100010 0000000000000000000000000000101000101000 +0100111100100100 0000000000000000000000000000101000011000 +0100111101000001 0000000000000000000000000000011001001000 +0100111101000010 0000000000000000000000000000011000101000 +0100111101000100 0000000000000000000000000000011000011000 +01011000001----- 0000000000000000000000000000100100001000 +01011000010----- 0000000000000000000000000000010100001000 +01011000100----- 0000000000000000000000000000110100001000 +01010000001----- 0000000000000000000000000000100100000100 +01010000010----- 0000000000000000000000000000010100000100 +01010000100----- 0000000000000000000000000000110100000100 +01011011-------- 0000000000000000000000000000100010000000 +01011111-------- 0000000000000000000000000000010010000000 +01011100-------- 0000000000000000000000010000000010001000 +01010101000----- 0000000000000000000000000000000000000000 +01010110000----- 0000000000000000000000000000000000000000 +01011001-------- 0000000000000000000000000000100000000010 +01011101-------- 0000000000000000000000000000010000000010 +01011010-------- 0000000000000000000000000000100000000001 +01011110-------- 0000000000000000000000000000010000000001 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +10001000-------- 0100000010000011000000000000101001001000 +10001010-------- 0100000010000011000000000000101000101000 +10001001-------- 0100000010000011000000000000011001001000 +10001011-------- 0100000010000011000000000000011000101000 +10001100-------- 0101000000000011000000000000101001001000 +10001110-------- 0101000000000011000000000000101000101000 +10001101-------- 0101000000000011000000000000011001001000 +10001111-------- 0101000000000011000000000000011000101000 +10000000-------- 1000000100000011000000000000101001000100 +10000010-------- 1000000100000011000000000000101000100100 +10000001-------- 1000000100000011000000000000011001000100 +10000011-------- 1000000100000011000000000000011000100100 +10000100-------- 1010000000000011000000000000101001000100 +10000110-------- 1010000000000011000000000000101000100100 +10000101-------- 1010000000000011000000000000011001000100 +10000111-------- 1010000000000011000000000000011000100100 +1011------------ 0000000000000010000000000000000000000000 +0010000000000000 0000000000000001000000000000000000000000 +1011------------ 0000000000000010000000000000000000000000 +1011------------ 0000000000000010000000000000000000000000 +1011------------ 0000000000000010000000000000000000000000 +1011------------ 0000000000000010000000000000000000000000 +1011------------ 0000000000000010000000000000000000000000 +10101000-------- 0100000010000010000000000000101001001000 +10101010-------- 0100000010000010000000000000101000101000 +10101001-------- 0100000010000010000000000000011001001000 +10101011-------- 0100000010000010000000000000011000101000 +10101100-------- 0101000000000010000000000000101001001000 +10101110-------- 0101000000000010000000000000101000101000 +10101101-------- 0101000000000010000000000000011001001000 +10101111-------- 0101000000000010000000000000011000101000 +10100000-------- 1000000100000010000000000000101001000100 +10100010-------- 1000000100000010000000000000101000100100 +10100001-------- 1000000100000010000000000000011001000100 +10100011-------- 1000000100000010000000000000011000100100 +10100100-------- 1010000000000010000000000000101001000100 +10100110-------- 1010000000000010000000000000101000100100 +10100101-------- 1010000000000010000000000000011001000100 +10100111-------- 1010000000000010000000000000011000100100 +11000001-------- 0000000000000000000000000000000000000000 +11000010-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001010-------- 0000000000000000000000000000000000000000 +11001100-------- 0000000000000000000000000000000000000000 +0001------------ ------1--------0------------------------ +0010------------ ------0--------1------------------------ +0011------------ ------1--------1------------------------ +011------------- ------0--------1------------------------ +111------------- ---------------------------------------- +1101------------ ---------------------------------------- +1100111--------- ---------------------------------------- +11001101-------- ---------------------------------------- +11001011-------- ---------------------------------------- +11001000-------- ---------------------------------------- +11000011-------- ---------------------------------------- +11000000-------- ---------------------------------------- +1100010--------- ---------------------------------------- +11000110-------- ---------------------------------------- +0100010--------- ---------------------------------------- +010001111------- ---------------------------------------- +01000111011----- ---------------------------------------- +010001110101---- ---------------------------------------- +0100011101001--- ---------------------------------------- +010001110100011- ---------------------------------------- +0100011101000101 ---------------------------------------- +0100011101000011 ---------------------------------------- +0100011101000000 ---------------------------------------- +01000111000----- ---------------------------------------- +010001110011---- ---------------------------------------- +0100011100101--- ---------------------------------------- +010001110010011- ---------------------------------------- +0100011100100101 ---------------------------------------- +0100011100100011 ---------------------------------------- +0100011100100000 ---------------------------------------- +010001101------- ---------------------------------------- +010001100011---- ---------------------------------------- +0100011000101--- ---------------------------------------- +010001100010011- ---------------------------------------- +0100011000100101 ---------------------------------------- +0100011000100011 ---------------------------------------- +0100011000100000 ---------------------------------------- +010001100101---- ---------------------------------------- +0100011001001--- ---------------------------------------- +010001100100011- ---------------------------------------- +0100011001000101 ---------------------------------------- +0100011001000011 ---------------------------------------- +0100011001000000 ---------------------------------------- +010001100111---- ---------------------------------------- +0100011001101--- ---------------------------------------- +010001100110011- ---------------------------------------- +0100011001100101 ---------------------------------------- +0100011001100011 ---------------------------------------- +0100011001100000 ---------------------------------------- +01000010111----- ---------------------------------------- +010000101101---- ---------------------------------------- +0100001011001--- ---------------------------------------- +01000010110001-- ---------------------------------------- +010000101100001- ---------------------------------------- +0100001011000001 ---------------------------------------- +010000101011---- ---------------------------------------- +0100001010101--- ---------------------------------------- +01000010101001-- ---------------------------------------- +010000101010001- ---------------------------------------- +0100001010100001 ---------------------------------------- +010000101001---- ---------------------------------------- +0100001010001--- ---------------------------------------- +01000010100001-- ---------------------------------------- +010000101000001- ---------------------------------------- +0100001010000001 ---------------------------------------- +010000100111---- ---------------------------------------- +0100001001101--- ---------------------------------------- +010000100110011- ---------------------------------------- +0100001001100101 ---------------------------------------- +0100001001100011 ---------------------------------------- +0100001001100000 ---------------------------------------- +010000100101---- ---------------------------------------- +0100001001001--- ---------------------------------------- +010000100100011- ---------------------------------------- +0100001001000101 ---------------------------------------- +0100001001000011 ---------------------------------------- +0100001001000000 ---------------------------------------- +010000100011---- ---------------------------------------- +0100001000101--- ---------------------------------------- +010000100010011- ---------------------------------------- +0100001000100101 ---------------------------------------- +0100001000100011 ---------------------------------------- +0100001000100000 ---------------------------------------- +01000000111----- ---------------------------------------- +010000001101---- ---------------------------------------- +0100000011001--- ---------------------------------------- +01000000110001-- ---------------------------------------- +010000001100001- ---------------------------------------- +0100000011000001 ---------------------------------------- +010000001011---- ---------------------------------------- +0100000010101--- ---------------------------------------- +01000000101001-- ---------------------------------------- +010000001010001- ---------------------------------------- +0100000010100001 ---------------------------------------- +010000001001---- ---------------------------------------- +0100000010001--- ---------------------------------------- +01000000100001-- ---------------------------------------- +010000001000001- ---------------------------------------- +0100000010000001 ---------------------------------------- +010000000111---- ---------------------------------------- +0100000001101--- ---------------------------------------- +010000000110011- ---------------------------------------- +0100000001100101 ---------------------------------------- +0100000001100011 ---------------------------------------- +0100000001100000 ---------------------------------------- +010000000101---- ---------------------------------------- +0100000001001--- ---------------------------------------- +010000000100011- ---------------------------------------- +0100000001000101 ---------------------------------------- +0100000001000011 ---------------------------------------- +0100000001000000 ---------------------------------------- +010000000011---- ---------------------------------------- +0100000000101--- ---------------------------------------- +010000000010011- ---------------------------------------- +0100000000100101 ---------------------------------------- +0100000000100011 ---------------------------------------- +0100000000100000 ---------------------------------------- +010011111------- ---------------------------------------- +01001111011----- ---------------------------------------- +010011110101---- ---------------------------------------- +0100111101001--- ---------------------------------------- +010011110100011- ---------------------------------------- +0100111101000101 ---------------------------------------- +0100111101000011 ---------------------------------------- +0100111101000000 ---------------------------------------- +01001111000----- ---------------------------------------- +010011110011---- ---------------------------------------- +0100111100101--- ---------------------------------------- +010011110010011- ---------------------------------------- +0100111100100101 ---------------------------------------- +0100111100100011 ---------------------------------------- +0100111100100000 ---------------------------------------- +010011101------- ---------------------------------------- +010011100011---- ---------------------------------------- +0100111000101--- ---------------------------------------- +010011100010011- ---------------------------------------- +0100111000100101 ---------------------------------------- +0100111000100011 ---------------------------------------- +0100111000100000 ---------------------------------------- +010011100101---- ---------------------------------------- +0100111001001--- ---------------------------------------- +010011100100011- ---------------------------------------- +0100111001000101 ---------------------------------------- +0100111001000011 ---------------------------------------- +0100111001000000 ---------------------------------------- +010011100111---- ---------------------------------------- +0100111001101--- ---------------------------------------- +010011100110011- ---------------------------------------- +0100111001100101 ---------------------------------------- +0100111001100011 ---------------------------------------- +0100111001100000 ---------------------------------------- +010011010------- ---------------------------------------- +0100110110------ ---------------------------------------- +01001101111----- ---------------------------------------- +010011011101---- ---------------------------------------- +0100110111001--- ---------------------------------------- +01001101110001-- ---------------------------------------- +010011011100001- ---------------------------------------- +0100110111000001 ---------------------------------------- +010011001------- ---------------------------------------- +010011000111---- ---------------------------------------- +0100110001101--- ---------------------------------------- +010011000110011- ---------------------------------------- +0100110001100101 ---------------------------------------- +0100110001100011 ---------------------------------------- +0100110001100000 ---------------------------------------- +010011000101---- ---------------------------------------- +0100110001001--- ---------------------------------------- +010011000100011- ---------------------------------------- +0100110001000101 ---------------------------------------- +0100110001000011 ---------------------------------------- +0100110001000000 ---------------------------------------- +01001100000----- ---------------------------------------- +010011000011---- ---------------------------------------- +0100110000101--- ---------------------------------------- +010011000010011- ---------------------------------------- +0100110000100101 ---------------------------------------- +0100110000100011 ---------------------------------------- +0100110000100000 ---------------------------------------- +01001010100----- ---------------------------------------- +010010101011---- ---------------------------------------- +0100101010101--- ---------------------------------------- +01001010101001-- ---------------------------------------- +010010101010001- ---------------------------------------- +0100101010100001 ---------------------------------------- +01001010111----- ---------------------------------------- +010010101101---- ---------------------------------------- +0100101011001--- ---------------------------------------- +01001010110001-- ---------------------------------------- +010010101100001- ---------------------------------------- +0100101011000001 ---------------------------------------- +010010100111---- ---------------------------------------- +0100101001101--- ---------------------------------------- +010010100110011- ---------------------------------------- +0100101001100101 ---------------------------------------- +0100101001100011 ---------------------------------------- +0100101001100000 ---------------------------------------- +010010100101---- ---------------------------------------- +0100101001001--- ---------------------------------------- +010010100100011- ---------------------------------------- +0100101001000101 ---------------------------------------- +0100101001000011 ---------------------------------------- +0100101001000000 ---------------------------------------- +010010100011---- ---------------------------------------- +0100101000101--- ---------------------------------------- +010010100010011- ---------------------------------------- +0100101000100101 ---------------------------------------- +0100101000100011 ---------------------------------------- +0100101000100000 ---------------------------------------- +01001000100----- ---------------------------------------- +010010001011---- ---------------------------------------- +0100100010101--- ---------------------------------------- +01001000101001-- ---------------------------------------- +010010001010001- ---------------------------------------- +0100100010100001 ---------------------------------------- +01001000111----- ---------------------------------------- +010010001101---- ---------------------------------------- +0100100011001--- ---------------------------------------- +01001000110001-- ---------------------------------------- +010010001100001- ---------------------------------------- +0100100011000001 ---------------------------------------- +010010000111---- ---------------------------------------- +0100100001101--- ---------------------------------------- +010010000110011- ---------------------------------------- +0100100001100101 ---------------------------------------- +0100100001100011 ---------------------------------------- +0100100001100000 ---------------------------------------- +010010000101---- ---------------------------------------- +0100100001001--- ---------------------------------------- +010010000100011- ---------------------------------------- +0100100001000101 ---------------------------------------- +0100100001000011 ---------------------------------------- +0100100001000000 ---------------------------------------- +010010000011---- ---------------------------------------- +0100100000101--- ---------------------------------------- +010010000010011- ---------------------------------------- +0100100000100101 ---------------------------------------- +0100100000100011 ---------------------------------------- +0100100000100000 ---------------------------------------- +01010111-------- ---------------------------------------- +010101101------- ---------------------------------------- +0101011001------ ---------------------------------------- +01010110001----- ---------------------------------------- +01010100-------- ---------------------------------------- +010101011------- ---------------------------------------- +0101010101------ ---------------------------------------- +01010101001----- ---------------------------------------- +0101001--------- ---------------------------------------- +01010001-------- ---------------------------------------- +0101000011------ ---------------------------------------- +01010000101----- ---------------------------------------- +01010000011----- ---------------------------------------- +01010000000----- ---------------------------------------- +0101100011------ ---------------------------------------- +01011000101----- ---------------------------------------- +01011000011----- ---------------------------------------- +01011000000----- ---------------------------------------- +0000110011------ ---------------------------------------- +0000110010001--- ---------------------------------------- +00001100100001-- ---------------------------------------- +000011001000000- ---------------------------------------- +0000110010000011 ---------------------------------------- +0000110010011--- ---------------------------------------- +00001100100101-- ---------------------------------------- +000011001001000- ---------------------------------------- +0000110010010011 ---------------------------------------- +0000110010111--- ---------------------------------------- +00001100101101-- ---------------------------------------- +000011001011000- ---------------------------------------- +0000110010110011 ---------------------------------------- +0000110010101--- ---------------------------------------- +00001100101001-- ---------------------------------------- +000011001010000- ---------------------------------------- +0000110010100011 ---------------------------------------- +0000110000------ ---------------------------------------- +0000110001001--- ---------------------------------------- +00001100010001-- ---------------------------------------- +000011000100000- ---------------------------------------- +0000110001000011 ---------------------------------------- +0000110001011--- ---------------------------------------- +00001100010101-- ---------------------------------------- +000011000101000- ---------------------------------------- +0000110001010011 ---------------------------------------- +0000110001111--- ---------------------------------------- +00001100011101-- ---------------------------------------- +000011000111000- ---------------------------------------- +0000110001110011 ---------------------------------------- +0000110001101--- ---------------------------------------- +00001100011001-- ---------------------------------------- +000011000110000- ---------------------------------------- +0000110001100011 ---------------------------------------- +000011101100---- ---------------------------------------- +0000111011010--- ---------------------------------------- +00001110110110-- ---------------------------------------- +000011101101110- ---------------------------------------- +0000111011011110 ---------------------------------------- +000011101111---- ---------------------------------------- +0000111011100--- ---------------------------------------- +00001110111011-- ---------------------------------------- +000011101110100- ---------------------------------------- +0000111011101011 ---------------------------------------- +000011101000---- ---------------------------------------- +000011101001010- ---------------------------------------- +0000111010010110 ---------------------------------------- +000011101001000- ---------------------------------------- +0000111010010010 ---------------------------------------- +000011101001100- ---------------------------------------- +0000111010011010 ---------------------------------------- +000011101011---- ---------------------------------------- +000011101010010- ---------------------------------------- +0000111010100111 ---------------------------------------- +000011101010000- ---------------------------------------- +0000111010100011 ---------------------------------------- +000011101010110- ---------------------------------------- +0000111010101111 ---------------------------------------- +000011100000---- ---------------------------------------- +0000111000010--- ---------------------------------------- +00001110000110-- ---------------------------------------- +000011100001110- ---------------------------------------- +0000111000011110 ---------------------------------------- +000011100011---- ---------------------------------------- +0000111000100--- ---------------------------------------- +00001110001011-- ---------------------------------------- +000011100010100- ---------------------------------------- +0000111000101011 ---------------------------------------- +000011100100---- ---------------------------------------- +000011100101010- ---------------------------------------- +0000111001010110 ---------------------------------------- +000011100101000- ---------------------------------------- +0000111001010010 ---------------------------------------- +000011100101100- ---------------------------------------- +0000111001011010 ---------------------------------------- +000011100111---- ---------------------------------------- +000011100110010- ---------------------------------------- +0000111001100111 ---------------------------------------- +000011100110000- ---------------------------------------- +0000111001100011 ---------------------------------------- +000011100110110- ---------------------------------------- +0000111001101111 ---------------------------------------- +00001010-------- ---------------------------------------- +0000101111------ ---------------------------------------- +0000101110000--- ---------------------------------------- +00001011100011-- ---------------------------------------- +000010111000100- ---------------------------------------- +0000101110001010 ---------------------------------------- +0000101110010--- ---------------------------------------- +00001011100111-- ---------------------------------------- +000010111001100- ---------------------------------------- +0000101110011010 ---------------------------------------- +0000101110110--- ---------------------------------------- +00001011101111-- ---------------------------------------- +000010111011100- ---------------------------------------- +0000101110111010 ---------------------------------------- +0000101110100--- ---------------------------------------- +00001011101011-- ---------------------------------------- +000010111010100- ---------------------------------------- +0000101110101010 ---------------------------------------- +0000101100------ ---------------------------------------- +0000101101000--- ---------------------------------------- +00001011010011-- ---------------------------------------- +000010110100100- ---------------------------------------- +0000101101001010 ---------------------------------------- +0000101101010--- ---------------------------------------- +00001011010111-- ---------------------------------------- +000010110101100- ---------------------------------------- +0000101101011010 ---------------------------------------- +0000101101110--- ---------------------------------------- +00001011011111-- ---------------------------------------- +000010110111100- ---------------------------------------- +0000101101111010 ---------------------------------------- +0000101101100--- ---------------------------------------- +00001011011011-- ---------------------------------------- +000010110110100- ---------------------------------------- +0000101101101010 ---------------------------------------- +0000011--------- ---------------------------------------- +0000010111------ ---------------------------------------- +0000010100------ ---------------------------------------- +0000001111------ ---------------------------------------- +00000011101----- ---------------------------------------- +000000111001---- ---------------------------------------- +000000110000---- ---------------------------------------- +000000110011---- ---------------------------------------- +00000011011----- ---------------------------------------- +000000110101---- ---------------------------------------- +00000001-------- ---------------------------------------- +000000001------- ---------------------------------------- +0000000001------ ---------------------------------------- +00000000001----- ---------------------------------------- +000000000001---- ---------------------------------------- +0000000000001--- ---------------------------------------- +00000000000001-- ---------------------------------------- +000000000000001- ---------------------------------------- +0000000000000001 ---------------------------------------- diff --git a/espresso/examples/indust/pope.rom b/espresso/examples/indust/pope.rom new file mode 100644 index 0000000..1bb18fc --- /dev/null +++ b/espresso/examples/indust/pope.rom @@ -0,0 +1,66 @@ +.i 6 +.o 48 +000000 111111011100111000001101111011010111010111000110 +100000 111111011100111000001101111011010111010111000110 +010000 110101010000011000001101111011000111010111000111 +110000 101011001110010000001111111011010111000111000110 +001000 101110010100010000001111101001010010000111000110 +101000 110000010010010000000011111011010010000101000100 +011000 101100001101010000000000111011010010100111111110 +111000 111111011000101001101100111011010110110111000110 +000100 101110001100101001001100111011010110110111000110 +100100 111111011000011000001100111111010110110111000110 +010100 111111011100010000001111110010011100110111000010 +110100 101110010100010000001111111011011100110011000110 +001100 101111010110010000001111111011010110000111000110 +101100 101111010100011000001111111011010110000101000010 +011100 101111010100011000001100111011010010100010111100 +111100 101111001100011000001100111011010110110111000110 +000010 101110010100111000001100111011010110110111000110 +100010 101110010100011000000000111011010110110111000110 +010010 111111011100011000000000111011001100110111000010 +110010 111111011000011000001100111011011100110011000110 +001010 110100001100010000001111111011010110000101000100 +101010 110101001100010000001111111011010110000101011000 +011010 110001010100010000001111111011010110000010011110 +111010 111111011110010000001111111011010110000101000010 +000110 101110010100111000001111111011010010000101000100 +100110 111111011000001001110000111011010010001011000111 +010110 101101001100101001001111111011010110000011011010 +110110 110010010000011000001100111011010010001011000110 +001110 110000001100010000000011111011010011001111000110 +101110 111111011110110000001100111011010111010111000110 +011110 111111011000011000001100111011010111010111000110 +111110 110001001100010010001111111011010111010111000110 +000001 111111011100111000001101111011010111010111000110 +100001 110100010100111000001101111011010111010111000110 +010001 010000010000011000000001111011000111010111000111 +110001 011101010101010000000000111011010111000111000110 +001001 101101010100011000000100101011010010000111000110 +101001 011010001110110100001101111011010010000101000100 +011001 111111011100111000001101111011010010100111111110 +111001 111111011100111000001101111011010110110111000110 +000101 111111011100111000001101111011010110110111000110 +100101 111111011100111000001101111011010110110111000110 +010101 010000010100111000001101110011011100110111000010 +110101 110100010000011000001001111011011100110011000110 +001101 101101001110110000001110111011010110000111000110 +101101 111111011100111000001110111011010110000101000010 +011101 111111011100111000001110111011010010100010111100 +111101 111111011100111000001110111011010110110111000110 +000011 111111011100111000001110111011010110110111000110 +100011 110100010100111000001110111011010110110111000110 +010011 010000010000011000000010111011001100110111000010 +110011 110100010101010000001100111011011100110011000110 +001011 010000010100011000001000111011010110000101000100 +101011 111111011110110100001110111011010110000101011000 +011011 110100001100111000001110111011010110000010011110 +111011 111111011100111000001110111011010110000101000010 +000111 111111011100111000001110111011010010000101000100 +100111 111111011100111000001110111011010010001011000111 +010111 101101010100111000001110111011010110000011011010 +110111 011101110000011000000110111011010010001011000110 +001111 111111011110110000001101111011010011001111000110 +101111 010000001100111000001101111011010111010111000110 +011111 111111011100111000001101111011010111010111000110 +111111 111111011100111000001101111011010111010111000110 diff --git a/espresso/examples/indust/prom1 b/espresso/examples/indust/prom1 new file mode 100644 index 0000000..8f2f9c1 --- /dev/null +++ b/espresso/examples/indust/prom1 @@ -0,0 +1,504 @@ +.i 9 +.o 40 + 000000000 1000111111000000000000010001010000001010 + 000000001 1000111111000000000000010001010000001000 + 000000010 1011111111000000000000001001010000000000 + 000000011 1011111111000000000000001001010000000000 + 000000100 1011111111000000000000010001010000100110 + 000000101 1011111111000000000000010001010000100110 + 000000110 1011111111000000000000001001010000000000 + 000000111 1011111111000000000000001001010000000000 + 000001000 1010111111000000000000000001011101101000 + 000001001 1011111111000000010100100001010000000000 + 000001010 1011111111000000000000000001011101101011 + 000001011 1011110011000001010000000001011101101100 + 000001100 1011111100000001000100100001010000000000 + 000001101 1011110101000000000000000001011111110000 + 000001110 1011111111000001001000100001010000000000 + 000001111 1011111111001100000101100001010000000000 + 000010000 1011111111010010000110000001011101101000 + 000010001 1011111111000000100100100001011111110000 + 000010010 1011000011110001010000100001010001101111 + 000010011 1011101111001100100100100001011111100110 + 000010100 1011111111100010100100100001011111101100 + 000010101 1011111111000000100100100001011101101011 + 000010110 1011111111000000100100100001011101101100 + 000010111 1011111111000000000000010000100000011101 + 000011000 1011111111000000000000011001010010111111 + 000011001 1011111111000000000000000001011101101101 + 000011010 1011111111000000010010100001010000000000 + 000011011 1011111111000000000000010000010000011101 + 000011100 1011111111000000000000011001010101001000 + 000011101 1011001111010100010010100001010000000000 + 000011110 1011101111000000000000100001010000000000 + 000011111 1011111111000000000000011001000111010001 + 000100000 0011111111110000100010100001010001101000 + 000100001 1011001111110000010010100001010001000100 + 000100010 1011111111100010010010100001010000000000 + 000100011 1111101111000110000000010001000000100011 + 000100100 1011111111000000000000110001010000100100 + 000100101 1011111111000000000000010001010000100100 + 000100110 0011111111101000100100000001011111100111 + 000100111 1000111111100100100100000001011111101000 + 000101000 1011001111100010100100000001011111101001 + 000101001 1011110011001100100100000001011111101010 + 000101010 1011111100010010100100000001011111101011 + 000101011 1011111111000000000000000001011111101100 + 000101100 1011110000000001001000100001010000000000 + 000101101 1011110011001101100000100001010000000000 + 000101110 1011111111001100100100100001011111101100 + 000101111 1011111111011000100100100010001111100101 + 000110000 1011111111000000000000010010000010101000 + 000110001 1011110011011001010000000001011111100101 + 000110010 1011111100000001000100100001010000000000 + 000110011 1011110011001101100000100100000000000000 + 000110100 1011111100010011000010100010000000000000 + 000110101 1011001111001100010010100001010000000000 + 000110110 1011111111010011100000100001010000000000 + 000110111 1011110011100011010000010100000000111010 + 000111000 1011110011010011010000100001010000000000 + 000111001 1011111100100011000100100001010000000000 + 000111010 1011000111010010010010100001010000000000 + 000111011 1011011111001100010001100001010000000000 + 000111100 1011111011000000000000010000010000111111 + 000111101 1111011011001100010001100001010000000000 + 000111110 1111111111000000000000100000010000000000 + 000111111 1011111111110000100010100001010001000000 + 001000000 1011001111010010010010000001010100000000 + 001000001 1111111100000001000100100001010000000000 + 001000010 1111110011001100100100100001011110110000 + 001000011 1100111111110000010100100001010011110101 + 001000100 1001111010100010110000010000100001000100 + 001000101 1011111111000000000000000001011110110000 + 001000110 1011001111000000010010000001010100000000 + 001000111 1011111100000001000100100001010000000000 + 001001000 1011110011001100100100100001011110110000 + 001001001 1000111111110000010100100001010011110101 + 001001010 1001111010100010110000010000100001001010 + 001001011 1011111111000000000000000001011110110000 + 001001100 1011111111000001010000100001010000000000 + 001001101 1011111100001100000110000001011111100110 + 001001110 0011111111000000100010100001010000000000 + 001001111 1000111111101000010100100001010000000000 + 001010000 1011001111101000010010100001010000000000 + 001010001 1111111111001100100001100001010000000000 + 001010010 1011111111101000100100100001011111100110 + 001010011 1011011111110000010001100001010001110011 + 001010100 1011111111000000000000010000010001011000 + 001010101 1011111111001101000010000001011110111000 + 001010110 1011111111000001000100100001010000000000 + 001010111 1011111111001100100100100010001110111000 + 001011000 1001111111110000011000100001010001101111 + 001011001 1001111111110000011000100001010000111111 + 001011010 1011111111000000000000010000100010101000 + 001011011 0011111111110000100010100001010001111100 + 001011100 1011110011000000000000100001010000000000 + 001011101 1000111111110000010100100001010011011010 + 001011110 1011111100001101000100000001010100000000 + 001011111 1011001111000000010010100001010000000000 + 001100000 1011111111100011000010100001010000000000 + 001100001 1011110000100011001000100010000000000000 + 001100010 1101111111000000000000010000100001011110 + 001100011 1011111111001100100100100001011110110001 + 001100100 1000001111001100010010000001011101000110 + 001100101 1001011111000000010001100001010000000000 + 001100110 1011111111100100100100100001001101101000 + 001100111 1011001111110000010010100001010001101010 + 001101000 1000111111001100010100011001010010101111 + 001101001 1011111111000000000000010001000001111111 + 001101010 1011001111110000010010100001010010110010 + 001101011 1000111111001100010100011001010010101111 + 001101100 1011111111000000000000010001000001111111 + 001101101 1011111011000000000000100001010000000000 + 001101110 1011111011000000000000011001010010110101 + 001101111 1011001111110000010010100001010010110011 + 001110000 1011111111000000000000011001010010101111 + 001110001 1011111111000000000000010001000001111111 + 001110010 1011111111000000000000011001010010110101 + 001110011 1011001111110000010010100001010010110100 + 001110100 1011111111000000000000011001010010101111 + 001110101 1011111111000000000000010001000001111111 + 001110110 1011111111000000000000011001010010110101 + 001110111 1011001111110000010010100001010010110101 + 001111000 1011111111000000000000011001010010101111 + 001111001 1011111111000000000000010001000001111111 + 001111010 1011111111000000000000011001010010110101 + 001111011 1011001111110000010010100001010010110110 + 001111100 1011111111000000000000011001010010101111 + 001111101 1011111111000000000000010001000001111111 + 001111110 1011111111000000000000011001010010110101 + 001111111 1011111111000000000000000001011101101001 + 010000000 1011111100000001000100000001011110110001 + 010000001 1011110011000001010000100001010000000000 + 010000010 1011001111010010010010100001010000000000 + 010000011 1011111110000000000000100001010000000000 + 010000100 1000111110001100010100100001010000000000 + 010000101 1011111110000000000000100001010000000000 + 010000110 1001111111010010011000100001010000000000 + 010000111 1011111111000000000000010000100010010101 + 010001000 1000111111001100010100000001011101000111 + 010001001 1001111111000000011000100001010000000000 + 010001010 1011111111000000000000010000100010010101 + 010001011 1011111111000000000000000001011101101000 + 010001100 1000111111000000010100100001010000000000 + 010001101 1010111111000000000000100001010000000000 + 010001110 1011111111000000000000010000100010010101 + 010001111 1011011111001100010001100001010000000000 + 010010000 1011111111001100100100100000011101101001 + 010010001 1011001111010010010010100001010000000000 + 010010010 1011111110000000000000100001010000000000 + 010010011 1011111110000000000000100001010000000000 + 010010100 1011111111010010010010010001010010011101 + 010010101 1011111111000000100100100001011101101000 + 010010110 1011111111000000100100100001011101101001 + 010010111 1011111111000000000000000001011101101010 + 010011000 1011111100000001000100100001010000000000 + 010011001 1011001111010010010010100001010000000000 + 010011010 1000111111110000010100100001010011111001 + 010011011 1001111110000000000000010000100010011011 + 010011100 1011011111010010010001100001010000000000 + 010011101 1011111100100011000100000001011101001000 + 010011110 1011011111000000010001000001011101001000 + 010011111 1011111100000001000100100000010000000000 + 010100000 1011111111010010100100100001011101101010 + 010100001 1000111111110000010100100001010011111100 + 010100010 0011111111110000100010100001010010110110 + 010100011 1011001111110000010010100001010010110101 + 010100100 1011111111100010000000000001011000000000 + 010100101 1011111111000000100001100001010000000000 + 010100110 1011101111110000100010100001010011111111 + 010100111 1001111111000000000000010000100010100100 + 010101000 1011111111000000000000000001011111100111 + 010101001 0011111111000000100010000001011111101000 + 010101010 1000111111000000010100000001011111101001 + 010101011 1011001111000000010010000001011111101010 + 010101100 1011110011000001010000000001011111101011 + 010101101 1011111100000001000100100001010000000000 + 010101110 1011111111000000000000001001010000000000 + 010101111 1011111111100010000000000001011000000000 + 010110000 1011001111000000010010100001010000000000 + 010110001 1011111100100011000100100001010000000000 + 010110010 1011011111100100010001100001010000000000 + 010110011 1000111111010010010100100001010000000000 + 010110100 1011111111000000000000001001010000000000 + 010110101 1011111110000000000000100001010000000000 + 010110110 1011001111010010010010100001010000000000 + 010110111 1011111110000000000000100001010000000000 + 010111000 1011111111010010010010100001010000000000 + 010111001 1011011111001100010001100001010000000000 + 010111010 1011101111000000000000100001010000000000 + 010111011 1011111111000000000000001001000000000000 + 010111100 1011001111110000010010100001010000000001 + 010111101 1011111111100010100100100001011101101000 + 010111110 1011111111000000000000001001010000000000 + 010111111 1011111111000000000000000001011110111000 + 011000000 1011110000000001001000100001010000000000 + 011000001 1011111010000000100100100001011110111000 + 011000010 1011111010000000000000100001010000000000 + 011000011 1011111110001100100100100001011110111001 + 011000100 1011111111010010100100100001011110111010 + 011000101 1011001110110000010010100001010001101111 + 011000110 1011111111010010100100100001011110111011 + 011000111 1011111111000000100100100001011101101101 + 011001000 1011110011000000100100100001011110111100 + 011001001 1011111111000000100100100001011110111101 + 011001010 1011111111000000001100100001010000000000 + 011001011 1011110111000000100100100001011110111110 + 011001100 1011110111000000100100100001011110111111 + 011001101 1011111111001100100100100001011101101110 + 011001110 1011111111100010100100100001011110101111 + 011001111 1011111111000000000000000001011110101111 + 011010000 1011110011000001010000100001010000000000 + 011010001 1011111100110001000100100001010011111010 + 011010010 0011111111110000100010100001010011000000 + 011010011 1011111111001100000000000001011000000000 + 011010100 1011111111000000100001100001010000000000 + 011010101 1111111111000000001010010010000011010011 + 011010110 1011111111110001100000100001010000000101 + 011010111 1011111111001100100100100001011110101111 + 011011000 1011111111000000000000000001011111000011 + 011011001 1011110000000001001000000001011111000010 + 011011010 1011001111000000010010100001010000000000 + 011011011 1000111111100010010100100001010000000000 + 011011100 1011011111001100010001100001010000000000 + 011011101 1011111111000000000000010001000101000001 + 011011110 1011111111000000000000000001011111000100 + 011011111 1011111111000001000010100001010000000000 + 011100000 1011111111000000000000010010000101000001 + 011100001 1011111100001101000100000001011110111011 + 011100010 1011111111000001000010100001010000000000 + 011100011 1011111111000000000000010010000101000001 + 011100100 1011111111000000000000000001011110111001 + 011100101 1011001111000000010010100001010000000000 + 011100110 1011011111001100010001100001010000000000 + 011100111 1000111111000000000000010000010011111110 + 011101000 1011111111000000000000000001011111000001 + 011101001 1011001111000000010010100001010000000000 + 011101010 1011111100100011000100100001010000000000 + 011101011 1011011111100100010001100001010000000000 + 011101100 1011111111000000000000010001000101000001 + 011101101 1011111111000000000000000001011111000101 + 011101110 1011001111000000010010100001010000000000 + 011101111 1000111111100010010100000001011111000100 + 011110000 1011011111000000010001100001010000000000 + 011110001 1011111111000000000000010001000101000001 + 011110010 1011111111000000000000000001011110111010 + 011110011 1011001111000000010010100001010000000000 + 011110100 1011011111001100010001100001010000000000 + 011110101 1000111111000000000000010000010011111110 + 011110110 1011111111000000000000000001011111000110 + 011110111 1011001111000000010010100001010000000000 + 011111000 1011011111100100010001100001010000000000 + 011111001 1011111111000000000000010001000101000001 + 011111010 1000111111000000000000000001011111000000 + 011111011 1011001111000000010010100001010000000000 + 011111100 1011011111010010010001100001010000000000 + 011111101 1011111111000000000000010001000101000001 + 011111110 1001111111000000000000000001011101101101 + 011111111 1011111111000000010100100001010000000000 + 100000000 1011111111100100100100100001011101101101 + 100000001 1011111100001101000100000001011110111101 + 100000010 1011001111000000010010100001010000000000 + 100000011 1011011111001100010001100001010000000000 + 100000100 1011111111000000000000010001000100010001 + 100000101 1011111111000000000000000001011110111100 + 100000110 1011001111000000010010100001010000000000 + 100000111 1011111111100011000010100001010000000000 + 100001000 1011111111000000000000010010000100001111 + 100001001 1011111111100010100100100001011110111101 + 100001010 1011111111001100100100100001011110111100 + 100001011 1011111111000000000000000001011110111110 + 100001100 1011111111000000100100100001011110111111 + 100001101 1011111111100100100100100001011110111110 + 100001110 1011111111000000000000010001010100010001 + 100001111 1011111111001100100100100001011110111101 + 100010000 1011111111100100100100100001011110111111 + 100010001 1011111111000000000000000001011111000100 + 100010010 1011001111000000010010100001010000000000 + 100010011 1000111111100010010100000001011111000010 + 100010100 1011011111000000010001100001010000000000 + 100010101 1011111111000000000000010001000100100010 + 100010110 1011111100110001000100100001010011111010 + 100010111 1011111111010010100100100001011111000111 + 100011000 1011111100001101000100100001010000000000 + 100011001 1011111111100101000010100001010000000000 + 100011010 1011111110000000000000000001011111000010 + 100011011 1011001111000000010010100001010000000000 + 100011100 1011011111100100010001100001010000000000 + 100011101 1011111111100011000010100001010000000000 + 100011110 1011001111010010010010100001010000000000 + 100011111 1000111111110000010100100001010011111110 + 100100000 1011111111100100100100100001001111000111 + 100100001 1011111111000000000000010001010100101100 + 100100010 1011001111110000010010100001010000000110 + 100100011 1011111111100010100100100001011111000111 + 100100100 1011111111000000000000000001011111000010 + 100100101 1011001111000000010010100001010000000000 + 100100110 1011111111100011100000100001010000000000 + 100100111 1001111011100010011000100001010000000000 + 100101000 1011111111100101100000100001010000000000 + 100101001 1011001111001100010010100001010000000000 + 100101010 1000111111110000010100100001010000000010 + 100101011 1011111111100100100100100001001111000111 + 100101100 1011111111000000000000000001011101101110 + 100101101 1000111111000000010100100001010000000000 + 100101110 1010111111000000000000100001010000000000 + 100101111 1011110000100101001000100001010000000000 + 100110000 1011110111000000000000100001010000000000 + 100110001 1011111111010011010000100001010000000000 + 100110010 1011001111110000010010100001010011111001 + 100110011 1011011101000000000000010000010100110011 + 100110100 1011111111001101000010100001010000000000 + 100110101 1011111111110001000100100001010000000100 + 100110110 1011111110000000000000100001010000000000 + 100110111 1011111110000000000000100001010000000000 + 100111000 1011111110000000000000000001011111000111 + 100111001 1011111111000001000100000001011101101101 + 100111010 0011111111000000100010100001010000000000 + 100111011 1011110011101001010000100001010000000000 + 100111100 1011111111110000100010100001010011000111 + 100111101 1011111111010010100001100001010000000000 + 100111110 1011001111110001100000100001010000001000 + 100111111 1011111111000000000000010100000101000001 + 101000000 1011101111000000000000001001010000000000 + 101000001 1011001111000000000000000001011101101110 + 101000010 1011110000000001001000100001010000000000 + 101000011 1011111111110001000010100001010000111101 + 101000100 1011111111000000001100100001010000000000 + 101000101 1011111111001100100100100001011101101110 + 101000110 1011111111000000000000010010000011001111 + 101000111 1011101111000000000000001001010000000000 + 101001000 1011110011110001010000100001010011001000 + 101001001 0011111111110000100010100001010011010000 + 101001010 1000111111110000010100100001010011111100 + 101001011 1011111111001100000000000001011000000000 + 101001100 1011111100000001000100100001010000000000 + 101001101 1001111110000000000000010000100101001101 + 101001110 1000111111010010010100100001010000000000 + 101001111 1011101111110001000010100001010000001010 + 101010000 1000111111110000010100100010000000001010 + 101010001 1011111111100100100001100001010000000000 + 101010010 1111111111000000001100010001000101001010 + 101010011 1000111111110000010100100001010011100000 + 101010100 1011111111100100100100100001011111011000 + 101010101 1000111111000000100100100001011111011001 + 101010110 0001111111110000100010100001010000000001 + 101010111 1011111111100100100100100001011111100100 + 101011000 1011111111000000000000000001010100000000 + 101011001 1011110011000001010000100001010000000000 + 101011010 1011111111001100100100100001011111011010 + 101011011 1011111011101000100100100001011110101111 + 101011100 0011111011110000100010100001010011000111 + 101011101 1011111111001100100100100001011111011011 + 101011110 1011111111000000100100100001011111011100 + 101011111 1011111111000000100100100001011111100011 + 101100000 1011111111000000100100100001011111011101 + 101100001 1000111111000000100100100001011111011110 + 101100010 1001111111000000100100100001011111011111 + 101100011 1011111111100100100100100001011111100000 + 101100100 1011111111000000000000000001011111001000 + 101100101 1011111111000000100100100001011111000111 + 101100110 1011111111000000000000000001011111010000 + 101100111 1011110000000001001000100001010000000000 + 101101000 1011111111000000000000000001010100000000 + 101101001 1011001111000000010010000001011111011010 + 101101010 1000011111000000010001100001010000000000 + 101101011 1001111111100010100100100001011111000111 + 101101100 1011111100001101000100000001011111011101 + 101101101 1011111111000000010100100001010000000000 + 101101110 1011111111100100100100100001011111011101 + 101101111 1011111100010011000010000001011111000111 + 101110000 1011111111000000000011000001011111000111 + 101110001 1011111111000001010000010100000101101000 + 101110010 1011111111000000000000010010000101111001 + 101110011 1011001111000000000000000001011111100000 + 101110100 1011110000000001001000000001011101101101 + 101110101 1011111111000001100000100001010000000000 + 101110110 1011111111000000000000011100000111000011 + 101110111 1011111111000000000000010000010101101111 + 101111000 1011111111000000000000010001010110011001 + 101111001 1011001111000000000000000001011111100000 + 101111010 1011100000000001001000000001011110111110 + 101111011 1000111111000001100000000001011110111111 + 101111100 1011111111000001000010100001010000000000 + 101111101 1011111111000000000000010100000110000000 + 101111110 1011111111110001100000100001010000000001 + 101111111 1001111111000000000000010100000110000011 + 110000000 1011111111000000000000010010000110000110 + 110000001 1011111111110001000010100001010000000001 + 110000010 1001111111000000000000100010000000000000 + 110000011 1011111111000000000000000001011111011111 + 110000100 1011111111000000010100100001010000000000 + 110000101 1011111111100100100100100001011111011111 + 110000110 1000111111000000000000000001011111011110 + 110000111 1001111111000000010010100001010000000000 + 110001000 1011111111000110000000010000010110001101 + 110001001 1000111111110000010100100001010000000011 + 110001010 1011111111100010010100000001011111100011 + 110001011 1011111111000000010100000001011111011101 + 110001100 1001111111000000011000000001010100000000 + 110001101 1011111100000001000100000001011111011101 + 110001110 1011111111000000100100100001011111011110 + 110001111 1011111111100100100100100001011111100011 + 110010000 1011111100010011000010100010000000000000 + 110010001 1011111111000000000000000001011111011100 + 110010010 1011111111000001000100100001010000000000 + 110010011 1011111111010010100100100001011111011100 + 110010100 1011001111000000000000000001011111100000 + 110010101 1011110000000001001000000001011101101101 + 110010110 1011111111000001100000100001010000000000 + 110010111 1011111111000000000000011100000111000011 + 110011000 1011111111000110000000010000010101101001 + 110011001 1011001111110000010010100001010011111110 + 110011010 1011111111000000000000000001011111011111 + 110011011 1011111111000000010010100001010000000000 + 110011100 1011111111000000000000010001000110100001 + 110011101 1011001111110000010010100001010011111110 + 110011110 1011111111000000000000000001011101101101 + 110011111 1011111111000000010010100001010000000000 + 110100000 1011111111000000000000010001000110111011 + 110100001 1011111111000000000000000001011111100011 + 110100010 1011001111000000010010100001010000000000 + 110100011 1000111111100010010100000001011111011000 + 110100100 1011110011000001010000100001010000000000 + 110100101 1001111111001100011000100001010000000000 + 110100110 1011111111000000000000010000100110111011 + 110100111 1000111111100011100000100001010000000000 + 110101000 1011111111000000000000010100000110110001 + 110101001 1001111111000000000000000001011111011001 + 110101010 1011111111000000010100000001011111100100 + 110101011 1001111111000000011000100001010000000000 + 110101100 1011111111000000000000010000100110110001 + 110101101 1011111111000000000000000001011111100010 + 110101110 1000111111000000010100000001011111011100 + 110101111 1001111111000000011000100001010000000000 + 110110000 1011111111000000000000010000100110111001 + 110110001 1011111111000000000000000001011111100011 + 110110010 1011111111000000100100100001011111011000 + 110110011 1011111111000000000000000001011111011010 + 110110100 1011111111000000100100100001011101101011 + 110110101 1011111111000000000000000001011111100100 + 110110110 1011111111000000100100100001011101101100 + 110110111 1011111111000000000000000001011111011100 + 110111000 1011111111000000100100100001011111100010 + 110111001 1011111111000000000000000001011111100100 + 110111010 1011111111000000100100100001011111011001 + 110111011 1011110000110001001000100001010000000001 + 110111100 1011111111000000000000000001011110101111 + 110111101 0011111111000000100010000001011111100100 + 110111110 1011111111000001001000100001010000000000 + 110111111 1011111111110001000010100001010001000000 + 111000000 1011111111001100100100100001011111100100 + 111000001 1111111111000000000000010010000101011000 + 111000010 1011111111000000000000001001010000000000 + 111000011 1011001111010010100010000001011111000111 + 111000100 1100111111000000010100000001010100000000 + 111000101 1001111111000000011000000001010100000000 + 111000110 1011111111000000010100100001010000000000 + 111000111 1011111111100100100100100001011111000111 + 111001000 1011111111000000001001100001010000000000 + 111001001 1011111111010010100100100001011111100000 + 111001010 1011111111110000100010100001010000001000 + 111001011 1011101111000000000000000001011111011011 + 111001100 1000111111000000010100000001010100000000 + 111001101 1001111111000000011000000001010100000000 + 111001110 1011110000000001001000000001011111011011 + 111001111 1011110000000001001000100000100000000000 + 111010000 0011111111110000100010001001010011000111 + 111010001 0011111111110000100010100001010001101011 + 111010010 1011111111000000000000000001011111101110 + 111010011 1011111111000000100100100001011111101111 + 111010100 1011111111000000000000000001011111101101 + 111010101 1011111111000000100100100001011111101110 + 111010110 1011111111000000000000000001011101101011 + 111010111 1011111111000000100100100001011111101101 + 111011000 1011111111000000000000000001011111101111 + 111011001 1011001111000000010010000001011111101110 + 111011010 1000111111000000010100100001010000000000 + 111011011 1011011111100100010001000001011111101101 + 111011100 1011110000000001001000100001010000000000 + 111011101 1011111111100100010010010001000111100101 + 111011110 1011111111100100010010100001010000000000 + 111011111 1011111111100011100000100001010000000000 + 111100000 1011111111100010100001010100000111101011 + 111100001 1011110011010011010000100001010000000000 + 111100010 1011111111100101100000100001010000000000 + 111100011 1011111111010010100001010100000111101011 + 111100100 1011111111100100100001010001010111101011 + 111100101 1011111111100011100000100001010000000000 + 111100110 1011110011010011010000010100000111101000 + 111100111 1011111111100010100001010001010111101011 + 111101000 1011111111100101100000100001010000000000 + 111101001 1011111111100100100001010100000111101011 + 111101010 1011111111010010100001100001010000000000 + 111101011 1010100011010011010000100001010000000000 + 111101100 1011111111110001100000100001010000000001 + 111101101 1011111111000000000000010001000111110001 + 111101110 1011111111000000000000010000100111110001 + 111101111 1011111111000000000000010100000111110001 + 111110000 1011111111010010100001001001010000000000 + 111110001 1011111111000000000000001000010000000000 + 111110010 1011111111000000000000001000100000000000 + 111110011 1011011111000000000000100001010000000000 + 111110100 1011111111100010100001100100000000000000 + 111110101 1011111111000000000000001001010000000000 diff --git a/espresso/examples/indust/prom2 b/espresso/examples/indust/prom2 new file mode 100644 index 0000000..55aced2 --- /dev/null +++ b/espresso/examples/indust/prom2 @@ -0,0 +1,289 @@ +.i 9 +.o 21 +000000001 000000011111001010010 +000000010 100101100001011100101 +000000011 011010111101101101101 +000000100 011011000100001000101 +000000101 000000000111011110000 +000000110 100101001010110011011 +000000111 011010111100101010101 +000001000 011010101010111111001 +000001001 111111110000011010100 +000001010 100100110101110101111 +000001011 011010111010100100101 +000001100 011010010001011100011 +000001101 111111011010000000100 +000001110 100100100010100100101 +000001111 011010110111011011111 +000010000 011001110111100001100 +000010001 111111000100010001000 +000010010 100100010001000000100 +000010011 011010110011010000100 +000010100 011001011101001111111 +000010101 111110101111001101000 +000010110 100100000001001010001 +000010111 011010101110000010111 +000011000 011001000010101000100 +000011001 111110011010110101010 +000011010 100011110011000010000 +000011011 011010100111110011010 +000011100 011000100111101100111 +000011101 111110000111001010101 +000011110 100011100110101000011 +000011111 011010100000100010010 +000100000 011000001100011110000 +000100001 111101110100001101111 +000100010 100011011011111101110 +000100011 011010011000010000001 +000100100 010111110000111101010 +000100101 111101100001111111100 +000100110 100011010011000001110 +000100111 011010001110111101110 +000101000 010111010101001011111 +000101001 111101010000100000010 +000101010 100011001011110100101 +000101011 011010000100101011101 +000101100 010110111001001011000 +000101101 111100111111110000101 +000101110 100011000110010110010 +000101111 011001111001011010011 +000110000 010110011100111100000 +000110001 111100101111110001000 +000110010 100011000010100110000 +000110011 011001101101001011000 +000110100 010110000000100000000 +000110101 111100100000100001111 +000110110 100011000000100011110 +000110111 011001011111111110001 +000111000 010101100011111000101 +000111001 111100010010000011101 +000111010 100011000000001110101 +000111011 011001010001110101000 +000111100 010101000111000110101 +000111101 111100000100010110011 +000111110 100011000001100110001 +000111111 011001000010110000010 +001000000 010100101010001011101 +001000001 111011110111011010100 +001000010 100011000100101001011 +001000011 011000110010110001001 +001000100 010100001101001000111 +001000101 111011101011010000001 +001000110 100011001001010111011 +001000111 011000100001111000110 +001001000 010011101111111111100 +001001001 111011011111110111010 +001001010 100011001111101111000 +001001011 011000010000001000010 +001001100 010011010010110000110 +001001101 111011010101001111111 +001001110 100011010111101111000 +001001111 010111111101100000111 +001010000 010010110101011101111 +001010001 111011001011011010000 +001010010 100011100001010110001 +001010011 010111101010000011111 +001010100 010010011000001000010 +001010101 111011000010010101101 +001010110 100011101100100011000 +001010111 010111010101110010101 +001011000 010001111010110001001 +001011001 111010111010000010100 +001011010 100011111001010011111 +001011011 010111000000101110101 +001011100 010001011101011001101 +001011101 111010110010100000011 +001011110 100100000111100111001 +001011111 010110101010111001010 +001100000 010001000000000010111 +001100001 111010101011101111000 +001100010 100100010111011011001 +001100011 010110010100010011111 +001100100 010000100010101110010 +001100101 111010100101101110000 +001100110 100100101000101101110 +001100111 010101111101000000010 +001101000 010000000101011101000 +001101001 111010100000011101000 +001101010 100100111011011101000 +001101011 010101100101000000000 +001101100 001111101000010000010 +001101101 111010011011111011101 +001101110 100101001111100111000 +001101111 010101001100010100101 +001110000 001111001011001001000 +001110001 111010011000001001010 +001110010 100101100101001001100 +001110011 010100110010111111110 +001110100 001110101110001000101 +001110101 111010010101000101010 +001110110 100101111100000001111 +001110111 010100011001000011011 +001111000 001110010001010000001 +001111001 111010010010101111001 +001111010 100110010100001110001 +001111011 010011111110100001000 +001111100 001101110100100000110 +001111101 111010010001000110001 +001111110 100110101101101011100 +001111111 010011100011011010101 +010000000 001101010111111011101 +010000001 111010010000001001101 +010000010 100111001000010111101 +010000011 010011000111110010000 +010000100 001100111011100001110 +010000101 111010001111111000110 +010000110 100111100100001111110 +010000111 010010101011101001000 +010001000 001100011111010100001 +010001001 111010010000010010101 +010001010 101000000001010001001 +010001011 010010001111000001100 +010001100 001100000011010100000 +010001101 111010010001010110101 +010001110 101000011111011001010 +010001111 010001110001111101011 +010010000 001011100111100010001 +010010001 111010010011000011100 +010010010 101000111110100100111 +010010011 010001010100011110101 +010010100 001011001011111111111 +010010101 111010010101011000100 +010010110 101001011110110001001 +010010111 010000110110100111011 +010011000 001010110000101110000 +010011001 111010011000010100101 +010011010 101001111111111011010 +010011011 010000011000011001011 +010011100 001010010101101101011 +010011101 111010011011110110110 +010011110 101010100010000000001 +010011111 001111111001110110101 +010100000 001001111010111111010 +010100001 111010011111111101111 +010100010 101011000100111100100 +010100011 001111011011000001011 +010100100 001001100000100100010 +010100101 111010100100101000111 +010100110 101011101000101101100 +010100111 001110111011111011011 +010101000 001001000110011101011 +010101001 111010101001110110100 +010101010 101100001101001111101 +010101011 001110011100100110111 +010101100 001000101100101011011 +010101101 111010101111100101101 +010101110 101100110010011111111 +010101111 001101111101000101110 +010110000 001000010011001111010 +010110001 111010110101110101001 +010110010 101101011000011011000 +010110011 001101011101011010001 +010110100 000111111010001001110 +010110101 111010111100100011101 +010110110 101101111110111101100 +010110111 001100111101100110001 +010111000 000111100001011011101 +010111001 111011000011110000000 +010111010 101110100110000100011 +010111011 001100011101101011101 +010111100 000111001001000101101 +010111101 111011001011011000111 +010111110 101111001101101100001 +010111111 001011111101101100110 +011000000 000110110001001000011 +011000001 111011010011011100111 +011000010 101111110101110001011 +011000011 001011011101101011100 +011000100 000110011001100100111 +011000101 111011011011111010111 +011000110 110000011110010000111 +011000111 001010111101101010000 +011001000 000110000010011011011 +011001001 111011100100110001010 +011001010 110001000111000111001 +011001011 001010011101101010001 +011001100 000101101011101100110 +011001101 111011101101111110111 +011001110 110001110000010001000 +011001111 001001111101101101111 +011010000 000101010101011001100 +011010001 111011110111100010001 +011010010 110010011001101010110 +011010011 001001011101110111011 +011010100 000100111111100010010 +011010101 111100000001011001111 +011010110 110011000011010001100 +011010111 001000111110001000011 +011011000 000100101010000111101 +011011001 111100001011100100101 +011011010 110011101101000001101 +011011011 001000011110100011000 +011011100 000100010101001010000 +011011101 111100010110000000111 +011011110 110100010110110111110 +011011111 000111111111001001001 +011100000 000100000000101001111 +011100001 111100100000101101010 +011100010 110101000000110000101 +011100011 000111011111111100101 +011100100 000011101100100111100 +011100101 111100101011101000010 +011100110 110101101010101001000 +011100111 000111000000111111010 +011101000 000011011001000011110 +011101001 111100110110110000110 +011101010 110110010100011101110 +011101011 000110100010010011000 +011101100 000011000101111110100 +011101101 111101000010000101000 +011101110 110110111110001011100 +011101111 000110000011111001100 +011110000 000010110011011000100 +011110001 111101001101100011110 +011110010 110111100111101111000 +011110011 000101100101110100110 +011110100 000010100001010001101 +011110101 111101011001001011100 +011110110 111000010001000101011 +011110111 000101001000000110001 +011111000 000010001111101010101 +011111001 111101100100111011000 +011111010 111000111010001011011 +011111011 000100101010101111101 +011111100 000001111110100011011 +011111101 111101110000110000101 +011111110 111001100010111101111 +011111111 000100001101110010110 +100000000 000001101101111100011 +100000001 111101111100101011010 +100000010 111010001011011010001 +100000011 000011110001010001001 +100000100 000001011101110101101 +100000101 111110001000101001010 +100000110 111010110011011100111 +100000111 000011010101001100011 +100001000 000001001110001111010 +100001001 111110010100101001011 +100001010 111011011011000011100 +100001011 000010111001100101111 +100001100 000000111111001001100 +100001101 111110100000101010010 +100001110 111100000010001011000 +100001111 000010011110011111010 +100010000 000000110000100100011 +100010001 111110101100101010101 +100010010 111100101000110000111 +100010011 000010000011111001110 +100010100 000000100010100000000 +100010101 111110111000101001010 +100010110 111101001110110010100 +100010111 000001101001110110110 +100011000 000000010100111100011 +100011001 111111000100100100101 +100011010 111101110100001100111 +100011011 000001010000010111110 +100011100 000000000111111001011 +100011101 111111010000011011101 +100011110 111110011000111101111 +100011111 000000110111011101110 diff --git a/espresso/examples/indust/risc b/espresso/examples/indust/risc new file mode 100644 index 0000000..99225bb --- /dev/null +++ b/espresso/examples/indust/risc @@ -0,0 +1,76 @@ +.i 8 +.o 31 +00000--- 0000100000000010001000000000000 +00001--- 0000100000000010000000000000000 +0001---- 0000100000000010000100000000000 +--1-0--- 0000000000000001000000000000000 +0010-0-- 0000001100000000000000000000000 +--100--- 0000000000000001000000000000000 +--10---- 0000000000000001000000000000000 +--1----- 0000000000000001000000000000000 +0010-1-- 0000001000000000000000000000100 +--1-1--- 0000000000000001000000000000000 +--101--- 0000000000000001000000000000000 +--11---- 0000000000000001000000000000000 +001100-- 0000010100000000000000000000000 +--110--- 0000000000000001000000000000000 +001101-- 0110010000000000000000000000000 +--111--- 0000000000000001000000000000000 +00111--- 1000010100000000000000000000000 +-1-0---- 0000000000000001000000000000000 +-1------ 0000000000000001000000000000000 +-1--0--- 0000000000000001000000000000000 +-1-00--- 0000000000000001000000000000000 +010000-- 1000000001110100000000000001000 +0100010- 1000000001101100000000000001000 +0100011- 0000000000110100000000000001000 +-1--1--- 0000000000000001000000000000000 +-1-01--- 0000000000000001000000000000000 +01001--- 0000000000101100000000000001000 +-1-1---- 0000000000000001000000000000000 +-1-10--- 0000000000000001000000000000000 +0101---- 0000000000000100000000000001000 +-1-11--- 0000000000000001000000000000000 +01100--- 0010000010000000000000000001000 +-11----- 0000000000000001000000000000000 +-11-0--- 0000000000000001000000000000000 +-110---- 0000000000000001000000000000000 +01101--- 0010000010000000000000000001000 +-11-1--- 0000000000000001000000000000000 +0111---- 0010000010000000000000000001000 +-111---- 0000000000000001000000000000000 +1--00--- 0000000000000001000000000000000 +1------- 0000000000000001000000000000000 +1---0--- 0000000000000001000000000000000 +1--0---- 0000000000000001000000000000000 +100000-- 0000000000000000000000010000000 +100000-1 0001000000000000000000000000000 +100001-- 0000000000000001000000011010000 +100001-1 0001000000000000000000000000000 +1--01--- 0000000000000001000000000000000 +1---1--- 0000000000000001000000000000000 +1--1---- 0000000000000001000000000000000 +1--10--- 0000000000000001000000000000000 +100100-- 0001000000000000000001100000000 +100101-- 0001000000000001000001101010000 +1--11--- 0000000000000001000000000000000 +10011--- 0000000000000000000000000100000 +101000-- 0000100000000000010000000000001 +1-1-0--- 0000000000000001000000000000000 +1-10---- 0000000000000001000000000000000 +1-1----- 0000000000000001000000000000000 +101001-- 0000100000000000100000000000001 +1-1-1--- 0000000000000001000000000000000 +101010-- 0000100000000000010000000000000 +101011-- 0000100000000000100000000000000 +1-11---- 0000000000000001000000000000000 +10110--- 0000100000000000000000000000010 +10111--- 0000100000000000000000000000000 +11--0--- 0000000000000001000000000000000 +1100---- 0011000000000000000001000000000 +11-0---- 0000000000000001000000000000000 +11------ 0000000000000001000000000000000 +11--1--- 0000000000000001000000000000000 +1101---- 0000000000000000000000000100000 +11-1---- 0000000000000001000000000000000 +111----- 0000000000000001000010000010000 diff --git a/espresso/examples/indust/ryy6 b/espresso/examples/indust/ryy6 new file mode 100644 index 0000000..681eef0 --- /dev/null +++ b/espresso/examples/indust/ryy6 @@ -0,0 +1,114 @@ +.i 16 +.o 1 +-000--0-----0--- 1 +-000--0------0-- 1 +-000--0-------0- 1 +-000--0--------0 1 +-0-0--0--0--0--- 1 +-0-0--0--0---0-- 1 +-0-0--0--0----0- 1 +-0-0--0--0-----0 1 +-000-0------0--- 1 +-000-0-------0-- 1 +-000-0--------0- 1 +-000-0---------0 1 +-0-0-0---0--0--- 1 +-0-0-0---0---0-- 1 +-0-0-0---0----0- 1 +-0-0-0---0-----0 1 +-00-0-0-----0--- 1 +-00-0-0------0-- 1 +-00-0-0-------0- 1 +-00-0-0--------0 1 +-0--0-0--0--0--- 1 +-0--0-0--0---0-- 1 +-0--0-0--0----0- 1 +-0--0-0--0-----0 1 +-00-00------0--- 1 +-00-00-------0-- 1 +-00-00--------0- 1 +-00-00---------0 1 +-0--00---0--0--- 1 +-0--00---0---0-- 1 +-0--00---0----0- 1 +-0--00---0-----0 1 +0-00--0-----0--- 1 +0-00--0------0-- 1 +0-00--0-------0- 1 +0-00--0--------0 1 +0-00-0------0--- 1 +0-00-0-------0-- 1 +0-00-0--------0- 1 +0-00-0---------0 1 +0-0-0-0-----0--- 1 +0-0-0-0------0-- 1 +0-0-0-0-------0- 1 +0-0-0-0--------0 1 +0-0-00------0--- 1 +0-0-00-------0-- 1 +0-0-00--------0- 1 +0-0-00---------0 1 +-0-0--00---00--- 1 +-0-0--00---0-0-- 1 +-0-0--00---0--0- 1 +-0-0--00---0---0 1 +-0-0--00--0-0--- 1 +-0-0--00--0--0-- 1 +-0-0--00--0---0- 1 +-0-0--00--0----0 1 +-0-0--0-0--00--- 1 +-0-0--0-0--0-0-- 1 +-0-0--0-0--0--0- 1 +-0-0--0-0--0---0 1 +-0-0--0-0-0-0--- 1 +-0-0--0-0-0--0-- 1 +-0-0--0-0-0---0- 1 +-0-0--0-0-0----0 1 +-0-0-0-0---00--- 1 +-0-0-0-0---0-0-- 1 +-0-0-0-0---0--0- 1 +-0-0-0-0---0---0 1 +-0-0-0-0--0-0--- 1 +-0-0-0-0--0--0-- 1 +-0-0-0-0--0---0- 1 +-0-0-0-0--0----0 1 +-0-0-0--0--00--- 1 +-0-0-0--0--0-0-- 1 +-0-0-0--0--0--0- 1 +-0-0-0--0--0---0 1 +-0-0-0--0-0-0--- 1 +-0-0-0--0-0--0-- 1 +-0-0-0--0-0---0- 1 +-0-0-0--0-0----0 1 +-0--0-00---00--- 1 +-0--0-00---0-0-- 1 +-0--0-00---0--0- 1 +-0--0-00---0---0 1 +-0--0-00--0-0--- 1 +-0--0-00--0--0-- 1 +-0--0-00--0---0- 1 +-0--0-00--0----0 1 +-0--0-0-0--00--- 1 +-0--0-0-0--0-0-- 1 +-0--0-0-0--0--0- 1 +-0--0-0-0--0---0 1 +-0--0-0-0-0-0--- 1 +-0--0-0-0-0--0-- 1 +-0--0-0-0-0---0- 1 +-0--0-0-0-0----0 1 +-0--00-0---00--- 1 +-0--00-0---0-0-- 1 +-0--00-0---0--0- 1 +-0--00-0---0---0 1 +-0--00-0--0-0--- 1 +-0--00-0--0--0-- 1 +-0--00-0--0---0- 1 +-0--00-0--0----0 1 +-0--00--0--00--- 1 +-0--00--0--0-0-- 1 +-0--00--0--0--0- 1 +-0--00--0--0---0 1 +-0--00--0-0-0--- 1 +-0--00--0-0--0-- 1 +-0--00--0-0---0- 1 +-0--00--0-0----0 1 diff --git a/espresso/examples/indust/sex b/espresso/examples/indust/sex new file mode 100644 index 0000000..3fbe73a --- /dev/null +++ b/espresso/examples/indust/sex @@ -0,0 +1,25 @@ +.i 9 +.o 14 +1------00|10000011000000 +01----0--|00000010100000 +0-1---0--|00000000010000 +0-10--00-|00001000000000 +01-0--00-|00001000000000 +------100|00000011001001 +-----11-0|00100000000000 +--1---0-1|00000000010000 +-1----0-1|00000010100000 +----1-0--|00000100000000 +----010-1|00100000000000 +----00001|00000000001100 +------01-|00000100000010 +-00---0-0|00010000000000 +------11-|00001000000000 +-1-----1-|00000010100000 +--1----1-|00000000010000 +------1-1|00010000000000 +1-----10-|00000111000000 +01-0----1|00000010100000 +0-10----1|00000000010000 +0-10---01|01000000000000 +01-0---01|01000000000000 diff --git a/espresso/examples/indust/shift b/espresso/examples/indust/shift new file mode 100644 index 0000000..3e9c818 --- /dev/null +++ b/espresso/examples/indust/shift @@ -0,0 +1,102 @@ +.i 19 +.o 16 +0001--------------- 1000000000000000 +0011--------------- 1100000000000000 +0101--------------- 1110000000000000 +0111--------------- 1111000000000000 +1001--------------- 1111100000000000 +1011--------------- 1111110000000000 +1101--------------- 1111111000000000 +1111--------------- 1111111100000000 +000-1-------------- 0100000000000000 +000--1------------- 0010000000000000 +001-1-------------- 0010000000000000 +000---1------------ 0001000000000000 +001--1------------- 0001000000000000 +010-1-------------- 0001000000000000 +000----1----------- 0000100000000000 +001---1------------ 0000100000000000 +010--1------------- 0000100000000000 +011-1-------------- 0000100000000000 +000-----1---------- 0000010000000000 +001----1----------- 0000010000000000 +010---1------------ 0000010000000000 +011--1------------- 0000010000000000 +100-1-------------- 0000010000000000 +000------1--------- 0000001000000000 +001-----1---------- 0000001000000000 +010----1----------- 0000001000000000 +011---1------------ 0000001000000000 +100--1------------- 0000001000000000 +101-1-------------- 0000001000000000 +000-------1-------- 0000000100000000 +001------1--------- 0000000100000000 +010-----1---------- 0000000100000000 +011----1----------- 0000000100000000 +100---1------------ 0000000100000000 +101--1------------- 0000000100000000 +110-1-------------- 0000000100000000 +000--------1------- 0000000010000000 +001-------1-------- 0000000010000000 +010------1--------- 0000000010000000 +011-----1---------- 0000000010000000 +100----1----------- 0000000010000000 +101---1------------ 0000000010000000 +110--1------------- 0000000010000000 +111-1-------------- 0000000010000000 +000---------1------ 0000000001000000 +001--------1------- 0000000001000000 +010-------1-------- 0000000001000000 +011------1--------- 0000000001000000 +100-----1---------- 0000000001000000 +101----1----------- 0000000001000000 +110---1------------ 0000000001000000 +111--1------------- 0000000001000000 +000----------1----- 0000000000100000 +001---------1------ 0000000000100000 +010--------1------- 0000000000100000 +011-------1-------- 0000000000100000 +100------1--------- 0000000000100000 +101-----1---------- 0000000000100000 +110----1----------- 0000000000100000 +111---1------------ 0000000000100000 +000-----------1---- 0000000000010000 +001----------1----- 0000000000010000 +010---------1------ 0000000000010000 +011--------1------- 0000000000010000 +100-------1-------- 0000000000010000 +101------1--------- 0000000000010000 +110-----1---------- 0000000000010000 +111----1----------- 0000000000010000 +000------------1--- 0000000000001000 +001-----------1---- 0000000000001000 +010----------1----- 0000000000001000 +011---------1------ 0000000000001000 +100--------1------- 0000000000001000 +101-------1-------- 0000000000001000 +110------1--------- 0000000000001000 +111-----1---------- 0000000000001000 +000-------------1-- 0000000000000100 +001------------1--- 0000000000000100 +010-----------1---- 0000000000000100 +011----------1----- 0000000000000100 +100---------1------ 0000000000000100 +101--------1------- 0000000000000100 +110-------1-------- 0000000000000100 +111------1--------- 0000000000000100 +000--------------1- 0000000000000010 +001-------------1-- 0000000000000010 +010------------1--- 0000000000000010 +011-----------1---- 0000000000000010 +100----------1----- 0000000000000010 +101---------1------ 0000000000000010 +110--------1------- 0000000000000010 +111-------1-------- 0000000000000010 +000---------------1 0000000000000001 +001--------------1- 0000000000000001 +010-------------1-- 0000000000000001 +011------------1--- 0000000000000001 +100-----------1---- 0000000000000001 +101----------1----- 0000000000000001 +110---------1------ 0000000000000001 +111--------1------- 0000000000000001 diff --git a/espresso/examples/indust/signet b/espresso/examples/indust/signet new file mode 100644 index 0000000..bfe2131 --- /dev/null +++ b/espresso/examples/indust/signet @@ -0,0 +1,126 @@ +.i 39 +.o 8 +-------------------------------------11 00000001 +---0-----------------------1----------- 10000000 +--------------0------------1----------- 00100000 +--------0-------0-------1--1----------- 01000000 +------------------------1-1---------1-- 00000001 +---0--0---------------1---------------- 10000000 +--------------0-------10--------------- 00100000 +------0---------------11--------------- 01000000 +--------------0-------110-------------- 10000000 +-------------------1---01-1------------ 10000000 +-0---------------0-1---11-1------------ 00100000 +---0--0-----------1-----------------1-- 00000001 +------------------11----1-------------- 10000000 +-----------------1------1-1------0----- 00100000 +----------------01------1-1------------ 10000000 +---0-------------11--------------0----- 00100000 +----------------011-----1-------------- 10000000 +----------------1-------1-1------------ 10100000 +---0----------0-1-1-------------------- 10100000 +-0-0-----------1--------0-------------- 10000000 +---------------1--------1-----------1-- 00000001 +-0-------------1-0-1---01-------------- 00100000 +-0-------------1-0-1---11-------------- 01000000 +---------------101------1-------------- 10000000 +---------------1-1------1--------0----- 00100000 +---------------11-------1-------------- 10100000 +-0------------1--------0--1------------ 10000000 +--------------1--------1--1------------ 00100000 +-0------------1---11------------------- 10000000 +--------------1--11-----------0-------- 01000000 +--------------1--11-------------------- 10000000 +-0------0--1------------1-------------- 01000000 +--------0--1------------1----10-------- 01000000 +-0------0--1--1------------------------ 10000000 +-----------1--1--------1--------------- 10100000 +-0-0------1---0--01-------------------- 10000000 +----------1------1------1-1------1----- 01000000 +---0------1------11--------------1----- 01000000 +----------1---0-1----------1----------- 01000000 +----------1-----1-------1-1------------ 01000000 +---0------1---0-1-1-------------------- 01000000 +----------1----1-1------1--------1----- 01000000 +----------1----11-------1-------------- 01000000 +---0--0--1----------------------------- 00100000 +-0-0-----1------------------0---------- 01000000 +--------1-------0-------1--1----------- 00000100 +--------1-----1------------1----------- 00100000 +--------1-----1-------10--------------- 00100000 +---0--0-1--1--------------------------- 10100000 +------1---0----------------1----------- 00000010 +-0----1-0-----------------1------------ 10000000 +------1---0---------------1------------ 10100000 +------1-----0-------------1------------ 10100000 +------1---0-----------1---------------- 10100000 +------1---0-------1-------------------- 10100000 +------1----------01-0------------------ 10000000 +------1-----------1--1----------------- 10000000 +------1---0----1----------------------- 10100000 +------1-----0--1----------------------- 10100000 +----0-1----1-------------0------------- 10100000 +------1---1-----------11--------------- 01000000 +------1---1------11----------------1--- 00001000 +------1--10---------------------------- 10100000 +-0----1-011---------------------------- 10000000 +------1-1-----------------1------------ 00100000 +------1-1-1-1-------------1------------ 01000000 +------1-11----------------------------- 00100000 +------1-111---------------------------- 01000000 +----1-1----1-0------------------------- 10100000 +----1-1----10-------------------------- 10100000 +-0--1-1----111------------------------- 10000000 +-001------------------1---------------- 10000000 +-001--------------1-------------------- 10000000 +-0-1--------------10------------------- 01000000 +---1-----------1---------------1------- 01000000 +--11---------------1--1---------------- 01000000 +--11--------------1-------------------- 01000000 +--11-----------1----------------------- 01000000 +-1---------------0--0---1-1------------ 00100000 +-1--------------00------1-1------------ 10000000 +-1----------------------1-1------0----- 00100000 +-1--------------00--1---1-1------------ 00001000 +-1-0----------0--01-0------------------ 00100000 +-1-0----------0---1--------------0----- 00100000 +-1--------------001-----1-------------- 10000000 +-1--------------001-1---1-------------- 00001000 +-1-------------1--------1--------0----- 00100000 +-1-------------100------1-------------- 10000000 +-1-------------1-0--0---1-------------- 00100000 +-1-------------100--1---1-------------- 00001000 +-1------0-----1------------1--0-------- 01000000 +-1------------1------------1----------- 00100000 +-1------------1-----------1------------ 00100000 +-1------0-----1-------1-------0-------- 01000000 +-1------------1-------10--------------- 00100000 +-1------------1--01-------------------- 00010000 +-1------------1--01-0-------------1---- 00100000 +-1------------1---1-1------------0----- 00100000 +-1------------1--01-1------------------ 10000000 +-1------------1---1-1---------0-------- 01000000 +-1------------1---1-1------------1----- 01000000 +-1------------11----------------------- 01000000 +-1---------1------------1-------------- 10100000 +-1---------1--1------------------------ 00100000 +-1--------1------0--0---1-1-------0---- 01000000 +-1--------1-------------1-1------1----- 01000000 +-1-0------1------01-0-------------0---- 01000000 +-1-0------1---0---1--------------1----- 01000000 +-1--------1----1-0--0---1-------0------ 01000000 +-1--------1----1--------1--------1----- 01000000 +-1-0--0--1----------------------------- 10000000 +-1----1---1-----001-------------------- 00010000 +-1----1---1------01-1--------------1--- 00001000 +-1----1---1-1-------------1------------ 01000000 +-1----1---1-1--1----------------------- 01000000 +-1----1--11---------------------------- 01000000 +-1--1-1----111------------------------- 01000000 +-101--------------1------------1------- 00010000 +1--0--001------------------------------ 10100000 +10-0--01------------------------------- 01000000 +1---111-------------------------------- 10100000 +1001----------------------------------- 10000000 +1-11----------------------------------- 01000000 +11-0--01------------------------------- 10100000 diff --git a/espresso/examples/indust/soar.pla b/espresso/examples/indust/soar.pla new file mode 100644 index 0000000..b022c47 --- /dev/null +++ b/espresso/examples/indust/soar.pla @@ -0,0 +1,533 @@ +.i 83 +.o 94 +.p 529 +0---------------------------------------------------------------------------------- 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-00001----0------------------------------------------------------------------------ 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-00001------0---------------------------------------------------------------------- 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-00001---0-0----------------------------------------------------------------------- 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-0000111---0----------------------------------------------------------------------- 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-000011-0--0----------------------------------------------------------------------- 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-00001000--1----------------------------------------------------------------------- 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0---------------------------------------------------------------------------------- 0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1------------101-000--------------------------------------------------------------- 0010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1---------------1000--------------------------------------------------------------- 0010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-----------------0-00-------------------------------------------------------------- 0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +------------------000-------------------------------------------------------------- 0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0------------------00-------------------------------------------------------------- 0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1------------0111100--------------------------------------------------------------- 0000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1-------------1-0110--------------------------------------------------------------- 0000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1--------------10110--------------------------------------------------------------- 0000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1------------1--0110--------------------------------------------------------------- 0000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-------------11--10---------------------------------------------------------------- 0000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------00-0---------------------------------------------------------------- 0000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-------------000--1---------------------------------------------------------------- 0000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-------------1-0-10---------------------------------------------------------------- 0000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-------------0--0-0---------------------------------------------------------------- 0000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +--------------1-0-0---------------------------------------------------------------- 0000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +----------------010---------------------------------------------------------------- 0000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-----------------01---------------------------------------------------------------- 0000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0---------------------------------------------------------------------------------- 0000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +-------------------1--------------------------------------------------------------- 0000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1------------0001100--------------------------------------------------------------- 0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1------------01011-0--------------------------------------------------------------- 0000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1------------1--1110--------------------------------------------------------------- 0000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1--------------11110--------------------------------------------------------------- 0000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------0------------------------------------------------------------- 0000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------000----------------------------------------------------------- 0000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------110----------------------------------------------------------- 0000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------011----------------------------------------------------------- 0000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------101----------------------------------------------------------- 0000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------00-0---------------------------------------------------------- 0000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------11-0---------------------------------------------------------- 0000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------110----------------------------------------------------------- 0000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------001----------------------------------------------------------- 0000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------01-1---------------------------------------------------------- 0000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------10-1---------------------------------------------------------- 0000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------00------------------------------------------------------------ 0000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------11------------------------------------------------------------ 0000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------00-0---------------------------------------------------------- 0000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 +----------------------1-1---------------------------------------------------------- 0000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 +---------------------1--1---------------------------------------------------------- 0000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 +1------------1--011-0-------------------------------------------------------------- 0000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000 +1-------------1-011-0-------------------------------------------------------------- 0000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000 +1--------------1011-0-------------------------------------------------------------- 0000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000 +1------------0------0-------------------------------------------------------------- 0000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000 +1-------------1-----0-------------------------------------------------------------- 0000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000 +1--------------0----0-------------------------------------------------------------- 0000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000 +1---------------1---0-------------------------------------------------------------- 0000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000 +1----------------1--0-------------------------------------------------------------- 0000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000 +------------------1-0-------------------------------------------------------------- 0000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000 +-------110011---------------------------------------------------------------------- 0000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000 +-------001011---------------------------------------------------------------------- 0000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000 +-------1-1001---------------------------------------------------------------------- 0000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000 +------0---011---------------------------------------------------------------------- 0000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000 +------1---111---------------------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +-------1--111---------------------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +--------1-111---------------------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +-------0111-1---------------------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +------0--1101---------------------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +11------0-0-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-1-----0-0-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--1----0-0-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1---1---0-0-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1----0--0-0-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-------0-0-1-------------01------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +11-------10-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-1------10-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--1-----10-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1---1----10-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1----0---10-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--------10-1-------------01------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +11----11--0-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-1---11--0-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--1--11--0-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1---1-11--0-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1----011--0-1------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-----11--0-1-------------01------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +11----1--0-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-1---1--0-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--1--1--0-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1---1-1--0-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1----01--0-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-----1--0-11-------------01------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +11-----1-0-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-1----1-0-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--1---1-0-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1---1--1-0-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1----0-1-0-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1------1-0-11-------------01------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +11------10-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-1-----10-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--1----10-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1---1---10-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1----0--10-11------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-------10-11-------------01------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +11-------0011------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-1------0011------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--1-----0011------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1---1----0011------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1----0---0011------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--------0011-------------01------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +11----11-1-01------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-1---11-1-01------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--1--11-1-01------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1---1-11-1-01------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1----011-1-01------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-----11-1-01-------------01------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +11----1-01-01------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-1---1-01-01------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1--1--1-01-01------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1---1-1-01-01------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1----01-01-01------------1--------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +1-----1-01-01-------------01------------------------------------------------------- 0000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000 +-----------------0----------------------------------------------------------------- 0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000 +------------------0---------------------------------------------------------------- 0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000 +0---------------------------------------------------------------------------------- 0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000 +11----0000111------------1--------------------------------------------------------- 0000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000 +1-1---0000111------------1--------------------------------------------------------- 0000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000 +1--1--0000111------------1--------------------------------------------------------- 0000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000 +1---1-0000111------------1--------------------------------------------------------- 0000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000 +1----00000111------------1--------------------------------------------------------- 0000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000 +1-----0000111-------------01------------------------------------------------------- 0000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000 +0-----------------0-0-------------------------------------------------------------- 0000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000 +1-------------00101-0-------------------------------------------------------------- 0000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000 +1-------------11001-0-------------------------------------------------------------- 0000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000 +1------------000--1-0-------------------------------------------------------------- 0000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000 +1------------0-10-0-0-------------------------------------------------------------- 0000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000 +1---------------010-0-------------------------------------------------------------- 0000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000 +1------------0---01-0-------------------------------------------------------------- 0000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000 +----------------0------------------------------------------------------------------ 0000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000 +-----------------0----------------------------------------------------------------- 0000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000 +------------------0---------------------------------------------------------------- 0000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000 +0---------------------------------------------------------------------------------- 0000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000 +1-------------1-111-0-------------------------------------------------------------- 0000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000 +1------------01011--0-------------------------------------------------------------- 0000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000 +1--------------1111-0-------------------------------------------------------------- 0000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------001011-010-------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +----------------------------0--0011-010-------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------011101011--------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------110011-010-------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------01-1011010-------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------0111010-11-------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------0010111-1--------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +----------------------------00011010-1--------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +----------------------------0-0-011-010-------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +----------------------------0--00111-1--------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------1100111-1--------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +-------------------------------0101-010-------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +----------------------------0-0-0111-1--------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +-------------------------------01011-1--------------------------------------------- 0000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000 +-------------------------------------------10-------------------------------------- 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------------------10-0-------------------------------------- 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +---------------------------------------10-0-0-------------------------------------- 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +-------------------------------1--------0-0-001------------------------------------ 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +--------------------------------0-------0-0-001------------------------------------ 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +---------------------------------1------0-0-001------------------------------------ 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +----------------------------------0-----0-0-001------------------------------------ 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +----------------------------000---------0-0-001------------------------------------ 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +-------------------------------10011-1--0-0-0-------------------------------------- 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +----------------------------0001101--1--0-0-0--0----------------------------------- 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +----------------------------0001101-01--0-0-0---000-------------------------------- 0000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------------------1-00-------------------------------------- 0000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000 +------------------------------------------100-------------------------------------- 0000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000 +----------------------------1--0101----00--00-------------------------------------- 0000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------1-0101----00--00-------------------------------------- 0000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000 +------------------------------10101----00--00-------------------------------------- 0000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000 +-------------------------------10011-1-00--00-------------------------------------- 0000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000 +----------------------------0001101--1-00--00--0----------------------------------- 0000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000 +----------------------------0001101-01-00--00---000-------------------------------- 0000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000 +---------------------------------------1-0000-------------------------------------- 0000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000 +----------------------------------------10000-------------------------------------- 0000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000 +----------------------------1--0101------0000-------------------------------------- 0000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------1-0101------0000-------------------------------------- 0000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000 +------------------------------10101------0000-------------------------------------- 0000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000 +-------------------------------10011-1---0000-------------------------------------- 0000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000 +----------------------------0001101--1---0000--0----------------------------------- 0000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000 +----------------------------0001101-01---0000---000-------------------------------- 0000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000 +---------------------------------1-----0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +---------------------------------1-----000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------------0----0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------------0----000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------00------0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------00------000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +--------------------------------0--0---0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +--------------------------------0--0---000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------1-----0-0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------1-----0-000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +--------------------------------0----0-0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +--------------------------------0----0-000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------1--11------0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------1--11------000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-----------------------------1-11------0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-----------------------------1-11------000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +------------------------------111------0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +------------------------------111------000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------0000-------0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------0000-------000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------11---1--0000001-1----------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------11---1--000000-11----------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------11------0000001-11---------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------11------000000-111---------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------11------0000001-1-1--------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------11------000000-11-1--------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------11------0000001-1--1-------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +-------------------------------11------000000-11--1-------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------000------0-0000001------------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------000------0-000000-1------------------------------------ 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------000-1---1--0000001-1----------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------000-1---1--000000-11----------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------000-1------0000001-11---------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------000-1------000000-111---------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------000-1------0000001-1-1--------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------000-1------000000-11-1--------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------000-1------0000001-1--1-------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +----------------------------000-1------000000-11--1-------------------------------- 0000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +1----------------00---------------------------------------------------------------- 0000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000 +1------------1---0----------------------------------------------------------------- 0000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000 +1------------000--1---------------------------------------------------------------- 0000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000 +1------------1--1-0---------------------------------------------------------------- 0000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000 +1-------------0-1-0---------------------------------------------------------------- 0000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000 +1--------------1-0----------------------------------------------------------------- 0000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000 +1---------------00----------------------------------------------------------------- 0000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000 +---------------------------------------------------1110---------------------------- 0000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000 +---------------------------------------------------1001---------------------------- 0000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000 +1------------0-0001---------------------------------------------------------------- 0000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000 +-------001011---------------------------------------------------------------------- 0000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000 +------101000----------------------------------------------------------------------- 0000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000 +-------110011---------------------------------------------------------------------- 0000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000 +-------1-100----------------------------------------------------------------------- 0000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000 +------0---011---------------------------------------------------------------------- 0000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000 +-----------00---------------------------------------------------------------------- 0000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000 +110-01----0------------------------------------------------------------------------ 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-0101----0------------------------------------------------------------------------ 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-1-----0-0-1------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1---1---0-0-1------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1----0--0-0-1------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-1------10-1------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1---1----10-1------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1----0---10-1------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +110-01------0---------------------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-0101------0---------------------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +110-01---0-0----------------------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-0101---0-0----------------------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-1---11--0-1------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1---1-11--0-1------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1----011--0-1------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-1------0011------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1---1----0011------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1----0---0011------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +110-0111---0----------------------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-010111---0----------------------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +110-011-0--0----------------------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-01011-0--0----------------------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-1---11-1-01------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1---1-11-1-01------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1----011-1-01------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-1---1-01-01------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1---1-1-01-01------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1----01-01-01------------1--------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +110-01000--1----------------------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +1-0101000--1----------------------------------------------------------------------- 0000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000 +-------001011---------------------------------------------------------------------- 0000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000 +------101000----------------------------------------------------------------------- 0000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000 +-------110011---------------------------------------------------------------------- 0000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000 +-------1-100----------------------------------------------------------------------- 0000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000 +------0---011---------------------------------------------------------------------- 0000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000 +-----------00---------------------------------------------------------------------- 0000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000 +0-----------------0-0-------------------------------------------------------------- 0000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000 +1------------1--100-0-------------------------------------------------------------- 0000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000 +1--------------1100---------------------------------------------------------------- 0000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000 +1------------001101------------------------------------001------------------------- 0000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000 +1------------001101------------------------------------011------------------------- 0000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000 +1------------001101------------------------------------101------------------------- 0000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000 +1------------001101------------------------------------111------------------------- 0000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000 +1------------011101------------------------------------001------------------------- 0000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000 +1------------011101------------------------------------011------------------------- 0000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000 +1------------011101------------------------------------101------------------------- 0000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000 +1------------011101------------------------------------111------------------------- 0000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000 +-------------0------0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000 +--------------1-----0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000 +---------------0----0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000 +----------------1---0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000 +-----------------1--0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000 +------------------1-0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000 +0-------------------0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000 +------101000----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000 +-----------00---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000 +-------1-1001---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000 +--------------011-0-0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000 +---------------1-11-0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000 +-------------0--1-0-0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000 +-------------1---11-0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000 +----------------100-0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000 +--------------1--11-0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000 +0-------------------0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000 +----------------10000-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000 +0------------------00-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000 +----------------------------------------------------101---0-0100------------------- 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +----------------------------------------------------011---0-0100------------------- 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------1100----01100------------------- 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------1010----01100------------------- 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +----------------------------------------------------00----0-01001------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------111-----011001------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------111-----011-10------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------1100----011--0------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------1010----011--0------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------0------0-01001------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------100-----01--00------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------0--0----01--00------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------111------11010------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +----------------------------------------------------------0101001------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------1100-----110-0------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------1010-----110-0------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +-----------------------------------------------------------1011-0------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +----------------------------------------------------00------01-10------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +----------------------------------------------------101-----01--0------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +----------------------------------------------------011-----01--0------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------100------1-000------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +-----------------------------------------------------------010-00------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------0--0-----1-000------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------111------01-00------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +----------------------------------------------------------1-11001------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------0--1-----01--0------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +-----------------------------------------------------------10-100------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +---------------------------------------------------0--------01-10------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +------------------------------------------------------------10000------------------ 0000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000 +-------------000--1-0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000 +-------------1----0-0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000 +---------------1--0-0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000 +----------------0---0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000 +-----------------0--0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000 +0-------------------0-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000 +1-------0-0-1-------------01------------------------------------------------------- 0000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000 +1--------10-1-------------01------------------------------------------------------- 0000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000 +1-----11--0-1-------------01------------------------------------------------------- 0000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000 +1--------0011-------------01------------------------------------------------------- 0000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000 +1-----11-1-01-------------01------------------------------------------------------- 0000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000 +1-----1-01-01-------------01------------------------------------------------------- 0000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000 +1---------------111---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000 +---------0111---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000 +1-------------0010100-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000 +1-------------1100100-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000 +1-------------010-000-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000 +1------------000--100-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000 +1------------0-10-000-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000 +1---------------01000-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000 +1------------0---0100-------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000 +111001----0------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000 +111001------0---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000 +111001---0-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000 +11100111---0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000 +1110011-0--0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000 +111001000--1----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000 +101001----0------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000 +101001------0---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000 +101001---0-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000 +10100111---0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000 +1010011-0--0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000 +101001000--1----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000 +1------------000111---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000 +1---------------0------------------------------------------------1----------------- 0000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000 +1----------------0-----------------------------------------------1----------------- 0000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000 +1-----------------0----------------------------------------------1----------------- 0000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000 +----------------0------------------------------------------------1----------------- 0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000 +-----------------0-----------------------------------------------1----------------- 0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000 +------------------0----------------------------------------------1----------------- 0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000 +0---------------------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000 +-----------------0----------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000 +------------------0---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000 +0---------------------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000 +1-1101----0------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000 +1-1101------0---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000 +1-1101---0-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000 +1-110111---0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000 +1-11011-0--0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000 +1-1101000--1----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000 +1------------11-110---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000 +1------------11-000---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000 +1------------1-0110---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000 +1------------10-001---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000 +1------------1-1101---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000 +1------------110-01---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000 +1--------------0000---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000 +------------------------------------------------------------------1---------------- 0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000 +----------------------------0-01011--1--------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000 +-----------------------------001011--1--------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000 +101101----0------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000 +101101------0---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000 +101101---0-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000 +10110111---0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000 +1011011-0--0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000 +101101000--1----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000 +110001----0------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000 +110001------0---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000 +110001---0-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000 +11000111---0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000 +1100011-0--0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000 +110001000--1----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000 +111101----0------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000 +111101------0---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000 +111101---0-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000 +11110111---0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000 +1111011-0--0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000 +111101000--1----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000 +100101----0------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000 +100101------0---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000 +100101---0-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000 +10010111---0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000 +1001011-0--0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000 +100101000--1----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000 +110101----0------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000 +110101------0---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000 +110101---0-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000 +11010111---0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000 +1101011-0--0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000 +110101000--1----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000 +1------------00-110---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000 +1-------------01110---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000 +----------------------------------------------------------------------10-0--------- 0000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 +----------------------------------------------------------------------100---------- 0000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 +----------------------------------------------------------------------10--0-------- 0000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 +----------------------------------------------------------------------1-00--------- 0000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 +----------------------------------------------------------------------1-0-0-------- 0000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 +-------------------------------------------------------------------1--------------- 0000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 +--------------------------------------------------------------------0-------------- 0000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 +---------------------------------------------------------------------1------------- 0000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 +--------0-0-1--------------------------------------------------------------10001--- 0000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000 +---------10-1--------------------------------------------------------------10001--- 0000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000 +---------0-11--------------------------------------------------------------10001--- 0000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000 +------11--0-1--------------------------------------------------------------10001--- 0000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000 +------11-1-01--------------------------------------------------------------10001--- 0000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000 +------1-01-01--------------------------------------------------------------10001--- 0000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000 +--------0-0-1--------------------------------------------------------------00101--- 0000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000 +---------10-1--------------------------------------------------------------00101--- 0000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000 +---------0-11--------------------------------------------------------------00101--- 0000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000 +------11--0-1--------------------------------------------------------------00101--- 0000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000 +------11-1-01--------------------------------------------------------------00101--- 0000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000 +------1-01-01--------------------------------------------------------------00101--- 0000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000 +--------0-0-1--------------------------------------------------------------10101--- 0000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000 +---------10-1--------------------------------------------------------------10101--- 0000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000 +---------0-11--------------------------------------------------------------10101--- 0000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000 +------11--0-1--------------------------------------------------------------10101--- 0000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000 +------11-1-01--------------------------------------------------------------10101--- 0000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000 +------1-01-01--------------------------------------------------------------10101--- 0000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000 +1------------------------0--------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1-----------0---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1-----0--11------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1--------111----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1--------010----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1------0111------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1-----0-10-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1------010-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1-----1---111---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1------1--111---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1-------1-111---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +100001----------------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000 +1-------------------------1-------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1--------------------------0------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1-----------0---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1-----0--11------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1--------111----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1--------010----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1------0111------------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1-----0-10-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1------010-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1-----1---111---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1------1--111---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1-------1-111---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000 +1------------0101-1---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000 +1------------1---11---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000 +1---------------010---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000 +1--------------1-11---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000 +1------------01--1----------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000 +1------------011001---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000 +1------------111001---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000 +-------------10-------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000 +-------------1-0------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000 +-------------1--1------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000 +---------------01------------------------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000 +-----------------1----------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000 +------------------0---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000 +0---------------------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000 +1------------001001---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000 +1------------010001-------------------------------------------------------------1-1 0000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000 +1------------0-0001-------------------------------------------------------------01- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000 +1------------0-0001-------------------------------------------------------------11- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000 +1------------010001--------------------------------------------------------------1- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000 +----------------------------0000101------------------------------------------------ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000 +1------------0-0110---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000 +1------------101000---------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 +------11-1-0----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000 +------1-0110----------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000 +------1--00-1---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000 +--------000-1---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000 +-------1-10-1---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000 +---------0-11---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000 +----------011---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000 +-----------00---------------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000 +--------0-0-1--------------------------------------------------------------01101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000 +---------10-1--------------------------------------------------------------01101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000 +---------0-11--------------------------------------------------------------01101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000 +------11--0-1--------------------------------------------------------------01101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000 +------11-1-01--------------------------------------------------------------01101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000 +------1-01-01--------------------------------------------------------------01101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000 +--------0-0-1--------------------------------------------------------------11101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000 +---------10-1--------------------------------------------------------------11101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000 +---------0-11--------------------------------------------------------------11101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000 +------11--0-1--------------------------------------------------------------11101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000 +------11-1-01--------------------------------------------------------------11101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000 +------1-01-01--------------------------------------------------------------11101--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000 +--------0-0-1--------------------------------------------------------------11001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +---------10-1--------------------------------------------------------------11001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +---------0-11--------------------------------------------------------------11001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +------11--0-1--------------------------------------------------------------11001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +------11-1-01--------------------------------------------------------------11001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +------1-01-01--------------------------------------------------------------11001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100 +--------0-0-1--------------------------------------------------------------01001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010 +---------10-1--------------------------------------------------------------01001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010 +---------0-11--------------------------------------------------------------01001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010 +------11--0-1--------------------------------------------------------------01001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010 +------11-1-01--------------------------------------------------------------01001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010 +------1-01-01--------------------------------------------------------------01001--- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010 +1-------------011100--------------------------------------------------------------- 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +.e diff --git a/espresso/examples/indust/spla b/espresso/examples/indust/spla new file mode 100644 index 0000000..695a6cf --- /dev/null +++ b/espresso/examples/indust/spla @@ -0,0 +1,2309 @@ +.i 16 +.o 46 +0000000000000000 0000000000000000000000000000000000000000000000 +01011011-------- 0000000000000000000000000010000100000000000000 +01011111-------- 0000000000000000000000000001000100000000000000 +01011100-------- 0000000000000000000000000000000110000000000001 +01011001-------- 0000000000000000000000000110000000000000000000 +01011101-------- 0000000000000000000000000101000000000000000000 +01011010-------- 0000000000000000000000001010000000000000000000 +01011110-------- 0000000000000000000000001001000000000000000000 +01001001-------- 0000100000100000000000010000000110000000000000 +0100100000100001 0000100000100000000000010010100010000000000000 +0100100000100010 0000100000100000000000010010001010000000000000 +0100100000100100 0000100000100000000000010010010010000000000000 +0100100001000001 0000100000100000000000010001100010000000000000 +0100100001000010 0000100000100000000000010001001010000000000000 +0100100001000100 0000100000100000000000010001010010000000000000 +0100100001100001 0000100000100000000000000000100010000000000001 +0100100001100010 0000100000100000000000000000001010000000000001 +0100100001100100 0000100000100000000000000000010010000000000001 +01001011-------- 0000110000000000000000010000000110000000000000 +0100101000100001 0000110000000000000000010010100010000000000000 +0100101000100010 0000110000000000000000010010001010000000000000 +0100101000100100 0000110000000000000000010010010010000000000000 +0100101001000001 0000110000000000000000010001100010000000000000 +0100101001000010 0000110000000000000000010001001010000000000000 +0100101001000100 0000110000000000000000010001010010000000000000 +0100101001100001 0000110000000000000000000000100010000000000001 +0100101001100010 0000110000000000000000000000001010000000000001 +0100101001100100 0000110000000000000000000000010010000000000001 +01000001-------- 0001000000010000000000010000000101000000000000 +0100000000100001 0001000000010000000000010010100001000000000000 +0100000000100010 0001000000010000000000010010001001000000000000 +0100000000100100 0001000000010000000000010010010001000000000000 +0100000001000001 0001000000010000000000010001100001000000000000 +0100000001000010 0001000000010000000000010001001001000000000000 +0100000001000100 0001000000010000000000010001010001000000000000 +0100000001100001 0001000000010000000000000000100001000000000001 +0100000001100010 0001000000010000000000000000001001000000000001 +0100000001100100 0001000000010000000000000000010001000000000001 +01000011-------- 0001001000000000000000010000000101000000000000 +0100001000100001 0001001000000000000000010010100001000000000000 +0100001000100010 0001001000000000000000010010001001000000000000 +0100001000100100 0001001000000000000000010010010001000000000000 +0100001001000001 0001001000000000000000010001100001000000000000 +0100001001000010 0001001000000000000000010001001001000000000000 +0100001001000100 0001001000000000000000010001010001000000000000 +0100001001100001 0001001000000000000000000000100001000000000001 +0100001001100010 0001001000000000000000000000001001000000000001 +0100001001100100 0001001000000000000000000000010001000000000001 +0100000010000000 0001000000010000000000000000000000000000100000 +0100001010000000 0001001000000000000000000000000000000000100000 +0100110000100001 0000000000000000000000010010100010000000100000 +0100110000100010 0000000000000000000000010010001010000000100000 +0100110000100100 0000000000000000000000010010010010000000100000 +0100110001000001 0000000000000000000000010001100010000000100000 +0100110001000010 0000000000000000000000010001001010000000100000 +0100110001000100 0000000000000000000000010001010010000000100000 +0100110001100001 0000000000000000000000000000100010000000100001 +0100110001100010 0000000000000000000000000000001010000000100001 +0100110001100100 0000000000000000000000000000010010000000100001 +0100100011000000 0000100000100000000000000000000000000000000000 +0100101011000000 0000110000000000000000000000000000000000000000 +0100011001100001 0000000000000000000000000000100001000000000001 +0100011001100010 0000000000000000000000000000001001000000000001 +0100011001100100 0000000000000000000000000000010001000000000001 +0100011000100001 0000000000000000000000010010100001000000000000 +0100011000100010 0000000000000000000000010010001001000000000000 +0100011000100100 0000000000000000000000010010010001000000000000 +0100011001000001 0000000000000000000000010001100001000000000000 +0100011001000010 0000000000000000000000010001001001000000000000 +0100011001000100 0000000000000000000000010001010001000000000000 +0100100010100000 0000100000100000000001000000000000000000000000 +0100101010100000 0000110000000000000001000000000000000000000000 +0100011100100001 0000000000000000000001010010100001000000000000 +0100011100100010 0000000000000000000001010010001001000000000000 +0100011100100100 0000000000000000000001010010010001000000000000 +0100011101000001 0000000000000000000001010001100001000000000000 +0100011101000010 0000000000000000000001010001001001000000000000 +0100011101000100 0000000000000000000001010001010001000000000000 +0100000011000000 0001000000010000000000000000000000000000000000 +0100001011000000 0001001000000000000000000000000000000000000000 +0100111001100001 0000000000000000000000000000100010000000000001 +0100111001100010 0000000000000000000000000000001010000000000001 +0100111001100100 0000000000000000000000000000010010000000000001 +0100111000100001 0000000000000000000000010010100010000000000000 +0100111000100010 0000000000000000000000010010001010000000000000 +0100111000100100 0000000000000000000000010010010010000000000000 +0100111001000001 0000000000000000000000010001100010000000000000 +0100111001000010 0000000000000000000000010001001010000000000000 +0100111001000100 0000000000000000000000010001010010000000000000 +0100000010100000 0001000000010000000000100000000000000000000000 +0100001010100000 0001001000000000000000100000000000000000000000 +0100111100100001 0000000000000000000000110010100010000000000000 +0100111100100010 0000000000000000000000110010001010000000000000 +0100111100100100 0000000000000000000000110010010010000000000000 +0100111101000001 0000000000000000000000110001100010000000000000 +0100111101000010 0000000000000000000000110001001010000000000000 +0100111101000100 0000000000000000000000110001010010000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +10001000-------- 1100100000100000000000010010100010000000000000 +10001010-------- 1100100000100000000000010010001010000000000000 +10001001-------- 1100100000100000000000010001100010000000000000 +10001011-------- 1100100000100000000000010001001010000000000000 +10001100-------- 1100110000000000000000010010100010000000000000 +10001110-------- 1100110000000000000000010010001010000000000000 +10001101-------- 1100110000000000000000010001100010000000000000 +10001111-------- 1100110000000000000000010001001010000000000000 +10000000-------- 1101000000010000000000010010100001000000000000 +10000010-------- 1101000000010000000000010010001001000000000000 +10000001-------- 1101000000010000000000010001100001000000000000 +10000011-------- 1101000000010000000000010001001001000000000000 +10000100-------- 1101001000000000000000010010100001000000000000 +10000110-------- 1101001000000000000000010010001001000000000000 +10000101-------- 1101001000000000000000010001100001000000000000 +10000111-------- 1101001000000000000000010001001001000000000000 +1011------------ 1000000000000000000000000000000000000000000000 +0010000000000000 0100000000000000000000000000000000000000000000 +1011------------ 1000000000000000000000000000000000000000000000 +1011------------ 1000000000000000000000000000000000000000000000 +1011------------ 1000000000000000000000000000000000000000000000 +1011------------ 1000000000000000000000000000000000000000000000 +1011------------ 1000000000000000000000000000000000000000000000 +10101000-------- 1000100000100000000000010010100010000000000000 +10101010-------- 1000100000100000000000010010001010000000000000 +10101001-------- 1000100000100000000000010001100010000000000000 +10101011-------- 1000100000100000000000010001001010000000000000 +10101100-------- 1000110000000000000000010010100010000000000000 +10101110-------- 1000110000000000000000010010001010000000000000 +10101101-------- 1000110000000000000000010001100010000000000000 +10101111-------- 1000110000000000000000010001001010000000000000 +10100000-------- 1001000000010000000000010010100001000000000000 +10100010-------- 1001000000010000000000010010001001000000000000 +10100001-------- 1001000000010000000000010001100001000000000000 +10100011-------- 1001000000010000000000010001001001000000000000 +10100100-------- 1001001000000000000000010010100001000000000000 +10100110-------- 1001001000000000000000010010001001000000000000 +10100101-------- 1001001000000000000000010001100001000000000000 +10100111-------- 1001001000000000000000010001001001000000000000 +110010010000---- 0000000000000000000000000000000000000000000000 +0010110000000001 0100000000000000000000000000000000000000000000 +110010010000---- 0000000000000000000000000000000000000000000000 +110010010000---- 0000000000000000000000000000000000000000000000 +110010010000---- 0000000000000000000000000000000000000000000000 +110010010000---- 0000000000000000000000000000000000000000000000 +110010010000---- 0000000000000000000000000000000000000000000000 +110010010000---- 0000000000000000000000000000000000000000000000 +110010010000---- 0000000000000000000000000000000000000000000000 +110010100000---- 0000000000000000000000000000000000000000000000 +1100110000000000 0000000000000000000000000000000000000000000000 +1101010000000000 0000000000000000000100000000000000000000000000 +1101100000000000 0000000000000000000010000000000000000000000000 +110001110000---- 0000000000000000000000000000000000000000010000 +1100010000000000 1010000000000000000000000000000000000000000000 +1100010100000000 0110000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000000000000110000000000001 +110001110000---- 0000000000000000000000000000000000000000010000 +0000010001100000 0000000000001000000000000000000000001100000010 +0000010001100101 0000000001100000000000000000000000001100000010 +0000010001101010 0000010001000000000000000000000000001100000010 +0000010001101111 0000000100000000000000000000000000001100000010 +0000010010100000 0000000000001000000000000000000000010100000010 +0000010010100101 0000000001100000000000000000000000010100000010 +0000010010101010 0000010001000000000000000000000000010100000010 +0000010010101111 0000000100000000000000000000000000010100000010 +0000010000100000 0000000000001000000000000000000000000100000010 +0000010000100101 0000000001100000000000000000000000000100000010 +0000010000101010 0000010001000000000000000000000000000100000010 +0000010000101111 0000000100000000000000000000000000000100000010 +0000010011100000 0000000000001000000000000000000000011100000010 +0000010011100101 0000000001100000000000000000000000011100000010 +0000010011101010 0000010001000000000000000000000000011100000010 +0000010011101111 0000000100000000000000000000000000011100000010 +0000010001010000 0000000000001000000000000000000000001010000010 +0000010001010101 0000000001100000000000000000000000001010000010 +0000010001011010 0000010001000000000000000000000000001010000010 +0000010001011111 0000000100000000000000000000000000001010000010 +0000010010010000 0000000000001000000000000000000000010010000010 +0000010010010101 0000000001100000000000000000000000010010000010 +0000010010011010 0000010001000000000000000000000000010010000010 +0000010010011111 0000000100000000000000000000000000010010000010 +0000010000010000 0000000000001000000000000000000000000010000010 +0000010000010101 0000000001100000000000000000000000000010000010 +0000010000011010 0000010001000000000000000000000000000010000010 +0000010000011111 0000000100000000000000000000000000000010000010 +0000010011010000 0000000000001000000000000000000000011010000010 +0000010011010101 0000000001100000000000000000000000011010000010 +0000010011011010 0000010001000000000000000000000000011010000010 +0000010011011111 0000000100000000000000000000000000011010000010 +0000010001000000 0000000000001000000000000000000000001000000010 +0000010001000101 0000000001100000000000000000000000001000000010 +0000010001001010 0000010001000000000000000000000000001000000010 +0000010001001111 0000000100000000000000000000000000001000000010 +0000010010000000 0000000000001000000000000000000000010000000010 +0000010010000101 0000000001100000000000000000000000010000000010 +0000010010001010 0000010001000000000000000000000000010000000010 +0000010010001111 0000000100000000000000000000000000010000000010 +0000010000000000 0000000000001000000000000000000000000000000010 +0000010000000101 0000000001100000000000000000000000000000000010 +0000010000001010 0000010001000000000000000000000000000000000010 +0000010000001111 0000000100000000000000000000000000000000000010 +0000010011000000 0000000000001000000000000000000000011000000010 +0000010011000101 0000000001100000000000000000000000011000000010 +0000010011001010 0000010001000000000000000000000000011000000010 +0000010011001111 0000000100000000000000000000000000011000000010 +0000010001110000 0000000000001000000000000000000000001110000010 +0000010001110101 0000000001100000000000000000000000001110000010 +0000010001111010 0000010001000000000000000000000000001110000010 +0000010001111111 0000000100000000000000000000000000001110000010 +0000010010110000 0000000000001000000000000000000000010110000010 +0000010010110101 0000000001100000000000000000000000010110000010 +0000010010111010 0000010001000000000000000000000000010110000010 +0000010010111111 0000000100000000000000000000000000010110000010 +0000010000110000 0000000000001000000000000000000000000110000010 +0000010000110101 0000000001100000000000000000000000000110000010 +0000010000111010 0000010001000000000000000000000000000110000010 +0000010000111111 0000000100000000000000000000000000000110000010 +0000010011110000 0000000000001000000000000000000000011110000010 +0000010011110101 0000000001100000000000000000000000011110000010 +0000010011111010 0000010001000000000000000000000000011110000010 +0000010011111111 0000000100000000000000000000000000011110000010 +0000010001100100 0000000001101000000000000000000000001100000010 +0000010001101000 0000010001001000000000000000000000001100000010 +0000010001101100 0000000100001000000000000000000000001100000010 +0000010001100001 0000000001101000000000000000000000001100000010 +0000010001101001 0000010001100000000000000000000000001100000010 +0000010001101101 0000000101100000000000000000000000001100000010 +0000010001100010 0000010001001000000000000000000000001100000010 +0000010001100110 0000010001100000000000000000000000001100000010 +0000010001101110 0000010101000000000000000000000000001100000010 +0000010001100011 0000000100001000000000000000000000001100000010 +0000010001100111 0000000101100000000000000000000000001100000010 +0000010001101011 0000010101000000000000000000000000001100000010 +0000010010100100 0000000001101000000000000000000000010100000010 +0000010010101000 0000010001001000000000000000000000010100000010 +0000010010101100 0000000100001000000000000000000000010100000010 +0000010010100001 0000000001101000000000000000000000010100000010 +0000010010101001 0000010001100000000000000000000000010100000010 +0000010010101101 0000000101100000000000000000000000010100000010 +0000010010100010 0000010001001000000000000000000000010100000010 +0000010010100110 0000010001100000000000000000000000010100000010 +0000010010101110 0000010101000000000000000000000000010100000010 +0000010010100011 0000000100001000000000000000000000010100000010 +0000010010100111 0000000101100000000000000000000000010100000010 +0000010010101011 0000010101000000000000000000000000010100000010 +0000010000100100 0000000001101000000000000000000000000100000010 +0000010000101000 0000010001001000000000000000000000000100000010 +0000010000101100 0000000100001000000000000000000000000100000010 +0000010000100001 0000000001101000000000000000000000000100000010 +0000010000101001 0000010001100000000000000000000000000100000010 +0000010000101101 0000000101100000000000000000000000000100000010 +0000010000100010 0000010001001000000000000000000000000100000010 +0000010000100110 0000010001100000000000000000000000000100000010 +0000010000101110 0000010101000000000000000000000000000100000010 +0000010000100011 0000000100001000000000000000000000000100000010 +0000010000100111 0000000101100000000000000000000000000100000010 +0000010000101011 0000010101000000000000000000000000000100000010 +0000010011100100 0000000001101000000000000000000000011100000010 +0000010011101000 0000010001001000000000000000000000011100000010 +0000010011101100 0000000100001000000000000000000000011100000010 +0000010011100001 0000000001101000000000000000000000011100000010 +0000010011101001 0000010001100000000000000000000000011100000010 +0000010011101101 0000000101100000000000000000000000011100000010 +0000010011100010 0000010001001000000000000000000000011100000010 +0000010011100110 0000010001100000000000000000000000011100000010 +0000010011101110 0000010101000000000000000000000000011100000010 +0000010011100011 0000000100001000000000000000000000011100000010 +0000010011100111 0000000101100000000000000000000000011100000010 +0000010011101011 0000010101000000000000000000000000011100000010 +0000010001010100 0000000001101000000000000000000000001010000010 +0000010001011000 0000010001001000000000000000000000001010000010 +0000010001011100 0000000100001000000000000000000000001010000010 +0000010001010001 0000000001101000000000000000000000001010000010 +0000010001011001 0000010001100000000000000000000000001010000010 +0000010001011101 0000000101100000000000000000000000001010000010 +0000010001010010 0000010001001000000000000000000000001010000010 +0000010001010110 0000010001100000000000000000000000001010000010 +0000010001011110 0000010101000000000000000000000000001010000010 +0000010001010011 0000000100001000000000000000000000001010000010 +0000010001010111 0000000101100000000000000000000000001010000010 +0000010001011011 0000010101000000000000000000000000001010000010 +0000010010010100 0000000001101000000000000000000000010010000010 +0000010010011000 0000010001001000000000000000000000010010000010 +0000010010011100 0000000100001000000000000000000000010010000010 +0000010010010001 0000000001101000000000000000000000010010000010 +0000010010011001 0000010001100000000000000000000000010010000010 +0000010010011101 0000000101100000000000000000000000010010000010 +0000010010010010 0000010001001000000000000000000000010010000010 +0000010010010110 0000010001100000000000000000000000010010000010 +0000010010011110 0000010101000000000000000000000000010010000010 +0000010010010011 0000000100001000000000000000000000010010000010 +0000010010010111 0000000101100000000000000000000000010010000010 +0000010010011011 0000010101000000000000000000000000010010000010 +0000010000010100 0000000001101000000000000000000000000010000010 +0000010000011000 0000010001001000000000000000000000000010000010 +0000010000011100 0000000100001000000000000000000000000010000010 +0000010000010001 0000000001101000000000000000000000000010000010 +0000010000011001 0000010001100000000000000000000000000010000010 +0000010000011101 0000000101100000000000000000000000000010000010 +0000010000010010 0000010001001000000000000000000000000010000010 +0000010000010110 0000010001100000000000000000000000000010000010 +0000010000011110 0000010101000000000000000000000000000010000010 +0000010000010011 0000000100001000000000000000000000000010000010 +0000010000010111 0000000101100000000000000000000000000010000010 +0000010000011011 0000010101000000000000000000000000000010000010 +0000010011010100 0000000001101000000000000000000000011010000010 +0000010011011000 0000010001001000000000000000000000011010000010 +0000010011011100 0000000100001000000000000000000000011010000010 +0000010011010001 0000000001101000000000000000000000011010000010 +0000010011011001 0000010001100000000000000000000000011010000010 +0000010011011101 0000000101100000000000000000000000011010000010 +0000010011010010 0000010001001000000000000000000000011010000010 +0000010011010110 0000010001100000000000000000000000011010000010 +0000010011011110 0000010101000000000000000000000000011010000010 +0000010011010011 0000000100001000000000000000000000011010000010 +0000010011010111 0000000101100000000000000000000000011010000010 +0000010011011011 0000010101000000000000000000000000011010000010 +0000010001000100 0000000001101000000000000000000000001000000010 +0000010001001000 0000010001001000000000000000000000001000000010 +0000010001001100 0000000100001000000000000000000000001000000010 +0000010001000001 0000000001101000000000000000000000001000000010 +0000010001001001 0000010001100000000000000000000000001000000010 +0000010001001101 0000000101100000000000000000000000001000000010 +0000010001000010 0000010001001000000000000000000000001000000010 +0000010001000110 0000010001100000000000000000000000001000000010 +0000010001001110 0000010101000000000000000000000000001000000010 +0000010001000011 0000000100001000000000000000000000001000000010 +0000010001000111 0000000101100000000000000000000000001000000010 +0000010001001011 0000010101000000000000000000000000001000000010 +0000010010000100 0000000001101000000000000000000000010000000010 +0000010010001000 0000010001001000000000000000000000010000000010 +0000010010001100 0000000100001000000000000000000000010000000010 +0000010010000001 0000000001101000000000000000000000010000000010 +0000010010001001 0000010001100000000000000000000000010000000010 +0000010010001101 0000000101100000000000000000000000010000000010 +0000010010000010 0000010001001000000000000000000000010000000010 +0000010010000110 0000010001100000000000000000000000010000000010 +0000010010001110 0000010101000000000000000000000000010000000010 +0000010010000011 0000000100001000000000000000000000010000000010 +0000010010000111 0000000101100000000000000000000000010000000010 +0000010010001011 0000010101000000000000000000000000010000000010 +0000010000000100 0000000001101000000000000000000000000000000010 +0000010000001000 0000010001001000000000000000000000000000000010 +0000010000001100 0000000100001000000000000000000000000000000010 +0000010000000001 0000000001101000000000000000000000000000000010 +0000010000001001 0000010001100000000000000000000000000000000010 +0000010000001101 0000000101100000000000000000000000000000000010 +0000010000000010 0000010001001000000000000000000000000000000010 +0000010000000110 0000010001100000000000000000000000000000000010 +0000010000001110 0000010101000000000000000000000000000000000010 +0000010000000011 0000000100001000000000000000000000000000000010 +0000010000000111 0000000101100000000000000000000000000000000010 +0000010000001011 0000010101000000000000000000000000000000000010 +0000010011000100 0000000001101000000000000000000000011000000010 +0000010011001000 0000010001001000000000000000000000011000000010 +0000010011001100 0000000100001000000000000000000000011000000010 +0000010011000001 0000000001101000000000000000000000011000000010 +0000010011001001 0000010001100000000000000000000000011000000010 +0000010011001101 0000000101100000000000000000000000011000000010 +0000010011000010 0000010001001000000000000000000000011000000010 +0000010011000110 0000010001100000000000000000000000011000000010 +0000010011001110 0000010101000000000000000000000000011000000010 +0000010011000011 0000000100001000000000000000000000011000000010 +0000010011000111 0000000101100000000000000000000000011000000010 +0000010011001011 0000010101000000000000000000000000011000000010 +0000010001110100 0000000001101000000000000000000000001110000010 +0000010001111000 0000010001001000000000000000000000001110000010 +0000010001111100 0000000100001000000000000000000000001110000010 +0000010001110001 0000000001101000000000000000000000001110000010 +0000010001111001 0000010001100000000000000000000000001110000010 +0000010001111101 0000000101100000000000000000000000001110000010 +0000010001110010 0000010001001000000000000000000000001110000010 +0000010001110110 0000010001100000000000000000000000001110000010 +0000010001111110 0000010101000000000000000000000000001110000010 +0000010001110011 0000000100001000000000000000000000001110000010 +0000010001110111 0000000101100000000000000000000000001110000010 +0000010001111011 0000010101000000000000000000000000001110000010 +0000010010110100 0000000001101000000000000000000000010110000010 +0000010010111000 0000010001001000000000000000000000010110000010 +0000010010111100 0000000100001000000000000000000000010110000010 +0000010010110001 0000000001101000000000000000000000010110000010 +0000010010111001 0000010001100000000000000000000000010110000010 +0000010010111101 0000000101100000000000000000000000010110000010 +0000010010110010 0000010001001000000000000000000000010110000010 +0000010010110110 0000010001100000000000000000000000010110000010 +0000010010111110 0000010101000000000000000000000000010110000010 +0000010010110011 0000000100001000000000000000000000010110000010 +0000010010110111 0000000101100000000000000000000000010110000010 +0000010010111011 0000010101000000000000000000000000010110000010 +0000010000110100 0000000001101000000000000000000000000110000010 +0000010000111000 0000010001001000000000000000000000000110000010 +0000010000111100 0000000100001000000000000000000000000110000010 +0000010000110001 0000000001101000000000000000000000000110000010 +0000010000111001 0000010001100000000000000000000000000110000010 +0000010000111101 0000000101100000000000000000000000000110000010 +0000010000110010 0000010001001000000000000000000000000110000010 +0000010000110110 0000010001100000000000000000000000000110000010 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000000000000110000000000001 +110001110000---- 0000000000000000000000000000000000000000010000 +0000010000111110 0000010101000000000000000000000000000110000010 +0000010000110011 0000000100001000000000000000000000000110000010 +0000010000110111 0000000101100000000000000000000000000110000010 +0000010000111011 0000010101000000000000000000000000000110000010 +0000010011110100 0000000001101000000000000000000000011110000010 +0000010011111000 0000010001001000000000000000000000011110000010 +0000010011111100 0000000100001000000000000000000000011110000010 +0000010011110001 0000000001101000000000000000000000011110000010 +0000010011111001 0000010001100000000000000000000000011110000010 +0000010011111101 0000000101100000000000000000000000011110000010 +0000010011110010 0000010001001000000000000000000000011110000010 +0000010011110110 0000010001100000000000000000000000011110000010 +0000010011111110 0000010101000000000000000000000000011110000010 +0000010011110011 0000000100001000000000000000000000011110000010 +0000010011110111 0000000101100000000000000000000000011110000010 +0000010011111011 0000010101000000000000000000000000011110000010 +0000010101000000 0000000000001000100000000000000000001000000010 +0000010110000101 0000000001100000100000000000000000010000000010 +0000010100101010 0000010001000000100000000000000000000100000010 +0000010100011111 0000000100000000100000000000000000000010000010 +0000010101000101 0000000001100000100000000000000000001000000010 +0000010101001010 0000010001000000100000000000000000001000000010 +0000010101001111 0000000100000000100000000000000000001000000010 +0000010110000000 0000000000001000100000000000000000010000000010 +0000010110001010 0000010001000000100000000000000000010000000010 +0000010110001111 0000000100000000100000000000000000010000000010 +0000010100100000 0000000000001000100000000000000000000100000010 +0000010100100101 0000000001100000100000000000000000000100000010 +0000010100101111 0000000100000000100000000000000000000100000010 +0000010100010000 0000000000001000100000000000000000000010000010 +0000010100010101 0000000001100000100000000000000000000010000010 +0000010100011010 0000010001000000100000000000000000000010000010 +0000010101000100 0000000001101000100000000000000000001000000010 +0000010101001000 0000010001001000100000000000000000001000000010 +0000010101001100 0000000100001000100000000000000000001000000010 +0000010101000001 0000000001101000100000000000000000001000000010 +0000010101001001 0000010001100000100000000000000000001000000010 +0000010101001101 0000000101100000100000000000000000001000000010 +0000010101000010 0000010001001000100000000000000000001000000010 +0000010101000110 0000010001100000100000000000000000001000000010 +0000010101001110 0000010101000000100000000000000000001000000010 +0000010101000011 0000000100001000100000000000000000001000000010 +0000010101000111 0000000101100000100000000000000000001000000010 +0000010101001011 0000010101000000100000000000000000001000000010 +0000010110000100 0000000001101000100000000000000000010000000010 +0000010110001000 0000010001001000100000000000000000010000000010 +0000010110001100 0000000100001000100000000000000000010000000010 +0000010110000001 0000000001101000100000000000000000010000000010 +0000010110001001 0000010001100000100000000000000000010000000010 +0000010110001101 0000000101100000100000000000000000010000000010 +0000010110000010 0000010001001000100000000000000000010000000010 +0000010110000110 0000010001100000100000000000000000010000000010 +0000010110001110 0000010101000000100000000000000000010000000010 +0000010110000011 0000000100001000100000000000000000010000000010 +0000010110000111 0000000101100000100000000000000000010000000010 +0000010110001011 0000010101000000100000000000000000010000000010 +0000010100100100 0000000001101000100000000000000000000100000010 +0000010100101000 0000010001001000100000000000000000000100000010 +0000010100101100 0000000100001000100000000000000000000100000010 +0000010100100001 0000000001101000100000000000000000000100000010 +0000010100101001 0000010001100000100000000000000000000100000010 +0000010100101101 0000000101100000100000000000000000000100000010 +0000010100100010 0000010001001000100000000000000000000100000010 +0000010100100110 0000010001100000100000000000000000000100000010 +0000010100101110 0000010101000000100000000000000000000100000010 +0000010100100011 0000000100001000100000000000000000000100000010 +0000010100100111 0000000101100000100000000000000000000100000010 +0000010100101011 0000010101000000100000000000000000000100000010 +0000010100010100 0000000001101000100000000000000000000010000010 +0000010100011000 0000010001001000100000000000000000000010000010 +0000010100011100 0000000100001000100000000000000000000010000010 +0000010100010001 0000000001101000100000000000000000000010000010 +0000010100011001 0000010001100000100000000000000000000010000010 +0000010100011101 0000000101100000100000000000000000000010000010 +0000010100010010 0000010001001000100000000000000000000010000010 +0000010100010110 0000010001100000100000000000000000000010000010 +0000010100011110 0000010101000000100000000000000000000010000010 +0000010100010011 0000000100001000100000000000000000000010000010 +0000010100010111 0000000101100000100000000000000000000010000010 +0000010100011011 0000010101000000100000000000000000000010000010 +0000100001100000 0000000000001010000000000000000000001100000000 +0000100001100101 0000000001100010000000000000000000001100000000 +0000100001101010 0000010001000010000000000000000000001100000000 +0000100001101111 0000000100000010000000000000000000001100000000 +0000100010100000 0000000000001010000000000000000000010100000000 +0000100010100101 0000000001100010000000000000000000010100000000 +0000100010101010 0000010001000010000000000000000000010100000000 +0000100010101111 0000000100000010000000000000000000010100000000 +0000100000100000 0000000000001010000000000000000000000100000000 +0000100000100101 0000000001100010000000000000000000000100000000 +0000100000101010 0000010001000010000000000000000000000100000000 +0000100000101111 0000000100000010000000000000000000000100000000 +0000100011100000 0000000000001010000000000000000000011100000000 +0000100011100101 0000000001100010000000000000000000011100000000 +0000100011101010 0000010001000010000000000000000000011100000000 +0000100011101111 0000000100000010000000000000000000011100000000 +0000100001010000 0000000000001010000000000000000000001010000000 +0000100001010101 0000000001100010000000000000000000001010000000 +0000100001011010 0000010001000010000000000000000000001010000000 +0000100001011111 0000000100000010000000000000000000001010000000 +0000100010010000 0000000000001010000000000000000000010010000000 +0000100010010101 0000000001100010000000000000000000010010000000 +0000100010011010 0000010001000010000000000000000000010010000000 +0000100010011111 0000000100000010000000000000000000010010000000 +0000100000010000 0000000000001010000000000000000000000010000000 +0000100000010101 0000000001100010000000000000000000000010000000 +0000100000011010 0000010001000010000000000000000000000010000000 +0000100000011111 0000000100000010000000000000000000000010000000 +0000100011010000 0000000000001010000000000000000000011010000000 +0000100011010101 0000000001100010000000000000000000011010000000 +0000100011011010 0000010001000010000000000000000000011010000000 +0000100011011111 0000000100000010000000000000000000011010000000 +0000100001000000 0000000000001010000000000000000000001000000000 +0000100001000101 0000000001100010000000000000000000001000000000 +0000100001001010 0000010001000010000000000000000000001000000000 +0000100001001111 0000000100000010000000000000000000001000000000 +0000100010000000 0000000000001010000000000000000000010000000000 +0000100010000101 0000000001100010000000000000000000010000000000 +0000100010001010 0000010001000010000000000000000000010000000000 +0000100010001111 0000000100000010000000000000000000010000000000 +0000100000000000 0000000000001010000000000000000000000000000000 +0000100000000101 0000000001100010000000000000000000000000000000 +0000100000001010 0000010001000010000000000000000000000000000000 +0000100000001111 0000000100000010000000000000000000000000000000 +0000100011000000 0000000000001010000000000000000000011000000000 +0000100011000101 0000000001100010000000000000000000011000000000 +0000100011001010 0000010001000010000000000000000000011000000000 +0000100011001111 0000000100000010000000000000000000011000000000 +0000100001110000 0000000000001010000000000000000000001110000000 +0000100001110101 0000000001100010000000000000000000001110000000 +0000100001111010 0000010001000010000000000000000000001110000000 +0000100001111111 0000000100000010000000000000000000001110000000 +0000100010110000 0000000000001010000000000000000000010110000000 +0000100010110101 0000000001100010000000000000000000010110000000 +0000100010111010 0000010001000010000000000000000000010110000000 +0000100010111111 0000000100000010000000000000000000010110000000 +0000100000110000 0000000000001010000000000000000000000110000000 +0000100000110101 0000000001100010000000000000000000000110000000 +0000100000111010 0000010001000010000000000000000000000110000000 +0000100000111111 0000000100000010000000000000000000000110000000 +0000100011110000 0000000000001010000000000000000000011110000000 +0000100011110101 0000000001100010000000000000000000011110000000 +0000100011111010 0000010001000010000000000000000000011110000000 +0000100011111111 0000000100000010000000000000000000011110000000 +0000100001100100 0000000001101010000000000000000000001100000000 +0000100001101000 0000010001001010000000000000000000001100000000 +0000100001101100 0000000100001010000000000000000000001100000000 +0000100001100001 0000000001101010000000000000000000001100000000 +0000100001101001 0000010001100010000000000000000000001100000000 +0000100001101101 0000000101100010000000000000000000001100000000 +0000100001100010 0000010001001010000000000000000000001100000000 +0000100001100110 0000010001100010000000000000000000001100000000 +0000100001101110 0000010101000010000000000000000000001100000000 +0000100001100011 0000000100001010000000000000000000001100000000 +0000100001100111 0000000101100010000000000000000000001100000000 +0000100001101011 0000010101000010000000000000000000001100000000 +0000100010100100 0000000001101010000000000000000000010100000000 +0000100010101000 0000010001001010000000000000000000010100000000 +0000100010101100 0000000100001010000000000000000000010100000000 +0000100010100001 0000000001101010000000000000000000010100000000 +0000100010101001 0000010001100010000000000000000000010100000000 +0000100010101101 0000000101100010000000000000000000010100000000 +0000100010100010 0000010001001010000000000000000000010100000000 +0000100010100110 0000010001100010000000000000000000010100000000 +0000100010101110 0000010101000010000000000000000000010100000000 +0000100010100011 0000000100001010000000000000000000010100000000 +0000100010100111 0000000101100010000000000000000000010100000000 +0000100010101011 0000010101000010000000000000000000010100000000 +0000100000100100 0000000001101010000000000000000000000100000000 +0000100000101000 0000010001001010000000000000000000000100000000 +0000100000101100 0000000100001010000000000000000000000100000000 +0000100000100001 0000000001101010000000000000000000000100000000 +0000100000101001 0000010001100010000000000000000000000100000000 +0000100000101101 0000000101100010000000000000000000000100000000 +0000100000100010 0000010001001010000000000000000000000100000000 +0000100000100110 0000010001100010000000000000000000000100000000 +0000100000101110 0000010101000010000000000000000000000100000000 +0000100000100011 0000000100001010000000000000000000000100000000 +0000100000100111 0000000101100010000000000000000000000100000000 +0000100000101011 0000010101000010000000000000000000000100000000 +0000100011100100 0000000001101010000000000000000000011100000000 +0000100011101000 0000010001001010000000000000000000011100000000 +0000100011101100 0000000100001010000000000000000000011100000000 +0000100011100001 0000000001101010000000000000000000011100000000 +0000100011101001 0000010001100010000000000000000000011100000000 +0000100011101101 0000000101100010000000000000000000011100000000 +0000100011100010 0000010001001010000000000000000000011100000000 +0000100011100110 0000010001100010000000000000000000011100000000 +0000100011101110 0000010101000010000000000000000000011100000000 +0000100011100011 0000000100001010000000000000000000011100000000 +0000100011100111 0000000101100010000000000000000000011100000000 +0000100011101011 0000010101000010000000000000000000011100000000 +0000100001010100 0000000001101010000000000000000000001010000000 +0000100001011000 0000010001001010000000000000000000001010000000 +0000100001011100 0000000100001010000000000000000000001010000000 +0000100001010001 0000000001101010000000000000000000001010000000 +0000100001011001 0000010001100010000000000000000000001010000000 +0000100001011101 0000000101100010000000000000000000001010000000 +0000100001010010 0000010001001010000000000000000000001010000000 +0000100001010110 0000010001100010000000000000000000001010000000 +0000100001011110 0000010101000010000000000000000000001010000000 +0000100001010011 0000000100001010000000000000000000001010000000 +0000100001010111 0000000101100010000000000000000000001010000000 +0000100001011011 0000010101000010000000000000000000001010000000 +0000100010010100 0000000001101010000000000000000000010010000000 +0000100010011000 0000010001001010000000000000000000010010000000 +0000100010011100 0000000100001010000000000000000000010010000000 +0000100010010001 0000000001101010000000000000000000010010000000 +0000100010011001 0000010001100010000000000000000000010010000000 +0000100010011101 0000000101100010000000000000000000010010000000 +0000100010010010 0000010001001010000000000000000000010010000000 +0000100010010110 0000010001100010000000000000000000010010000000 +0000100010011110 0000010101000010000000000000000000010010000000 +0000100010010011 0000000100001010000000000000000000010010000000 +0000100010010111 0000000101100010000000000000000000010010000000 +0000100010011011 0000010101000010000000000000000000010010000000 +0000100000010100 0000000001101010000000000000000000000010000000 +0000100000011000 0000010001001010000000000000000000000010000000 +0000100000011100 0000000100001010000000000000000000000010000000 +0000100000010001 0000000001101010000000000000000000000010000000 +0000100000011001 0000010001100010000000000000000000000010000000 +0000100000011101 0000000101100010000000000000000000000010000000 +0000100000010010 0000010001001010000000000000000000000010000000 +0000100000010110 0000010001100010000000000000000000000010000000 +0000100000011110 0000010101000010000000000000000000000010000000 +0000100000010011 0000000100001010000000000000000000000010000000 +0000100000010111 0000000101100010000000000000000000000010000000 +0000100000011011 0000010101000010000000000000000000000010000000 +0000100011010100 0000000001101010000000000000000000011010000000 +0000100011011000 0000010001001010000000000000000000011010000000 +0000100011011100 0000000100001010000000000000000000011010000000 +0000100011010001 0000000001101010000000000000000000011010000000 +0000100011011001 0000010001100010000000000000000000011010000000 +0000100011011101 0000000101100010000000000000000000011010000000 +0000100011010010 0000010001001010000000000000000000011010000000 +0000100011010110 0000010001100010000000000000000000011010000000 +0000100011011110 0000010101000010000000000000000000011010000000 +0000100011010011 0000000100001010000000000000000000011010000000 +0000100011010111 0000000101100010000000000000000000011010000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000000000000110000000000001 +110001110000---- 0000000000000000000000000000000000000000010000 +0000100011011011 0000010101000010000000000000000000011010000000 +0000100001000100 0000000001101010000000000000000000001000000000 +0000100001001000 0000010001001010000000000000000000001000000000 +0000100001001100 0000000100001010000000000000000000001000000000 +0000100001000001 0000000001101010000000000000000000001000000000 +0000100001001001 0000010001100010000000000000000000001000000000 +0000100001001101 0000000101100010000000000000000000001000000000 +0000100001000010 0000010001001010000000000000000000001000000000 +0000100001000110 0000010001100010000000000000000000001000000000 +0000100001001110 0000010101000010000000000000000000001000000000 +0000100001000011 0000000100001010000000000000000000001000000000 +0000100001000111 0000000101100010000000000000000000001000000000 +0000100001001011 0000010101000010000000000000000000001000000000 +0000100010000100 0000000001101010000000000000000000010000000000 +0000100010001000 0000010001001010000000000000000000010000000000 +0000100010001100 0000000100001010000000000000000000010000000000 +0000100010000001 0000000001101010000000000000000000010000000000 +0000100010001001 0000010001100010000000000000000000010000000000 +0000100010001101 0000000101100010000000000000000000010000000000 +0000100010000010 0000010001001010000000000000000000010000000000 +0000100010000110 0000010001100010000000000000000000010000000000 +0000100010001110 0000010101000010000000000000000000010000000000 +0000100010000011 0000000100001010000000000000000000010000000000 +0000100010000111 0000000101100010000000000000000000010000000000 +0000100010001011 0000010101000010000000000000000000010000000000 +0000100000000100 0000000001101010000000000000000000000000000000 +0000100000001000 0000010001001010000000000000000000000000000000 +0000100000001100 0000000100001010000000000000000000000000000000 +0000100000000001 0000000001101010000000000000000000000000000000 +0000100000001001 0000010001100010000000000000000000000000000000 +0000100000001101 0000000101100010000000000000000000000000000000 +0000100000000010 0000010001001010000000000000000000000000000000 +0000100000000110 0000010001100010000000000000000000000000000000 +0000100000001110 0000010101000010000000000000000000000000000000 +0000100000000011 0000000100001010000000000000000000000000000000 +0000100000000111 0000000101100010000000000000000000000000000000 +0000100000001011 0000010101000010000000000000000000000000000000 +0000100011000100 0000000001101010000000000000000000011000000000 +0000100011001000 0000010001001010000000000000000000011000000000 +0000100011001100 0000000100001010000000000000000000011000000000 +0000100011000001 0000000001101010000000000000000000011000000000 +0000100011001001 0000010001100010000000000000000000011000000000 +0000100011001101 0000000101100010000000000000000000011000000000 +0000100011000010 0000010001001010000000000000000000011000000000 +0000100011000110 0000010001100010000000000000000000011000000000 +0000100011001110 0000010101000010000000000000000000011000000000 +0000100011000011 0000000100001010000000000000000000011000000000 +0000100011000111 0000000101100010000000000000000000011000000000 +0000100011001011 0000010101000010000000000000000000011000000000 +0000100001110100 0000000001101010000000000000000000001110000000 +0000100001111000 0000010001001010000000000000000000001110000000 +0000100001111100 0000000100001010000000000000000000001110000000 +0000100001110001 0000000001101010000000000000000000001110000000 +0000100001111001 0000010001100010000000000000000000001110000000 +0000100001111101 0000000101100010000000000000000000001110000000 +0000100001110010 0000010001001010000000000000000000001110000000 +0000100001110110 0000010001100010000000000000000000001110000000 +0000100001111110 0000010101000010000000000000000000001110000000 +0000100001110011 0000000100001010000000000000000000001110000000 +0000100001110111 0000000101100010000000000000000000001110000000 +0000100001111011 0000010101000010000000000000000000001110000000 +0000100010110100 0000000001101010000000000000000000010110000000 +0000100010111000 0000010001001010000000000000000000010110000000 +0000100010111100 0000000100001010000000000000000000010110000000 +0000100010110001 0000000001101010000000000000000000010110000000 +0000100010111001 0000010001100010000000000000000000010110000000 +0000100010111101 0000000101100010000000000000000000010110000000 +0000100010110010 0000010001001010000000000000000000010110000000 +0000100010110110 0000010001100010000000000000000000010110000000 +0000100010111110 0000010101000010000000000000000000010110000000 +0000100010110011 0000000100001010000000000000000000010110000000 +0000100010110111 0000000101100010000000000000000000010110000000 +0000100010111011 0000010101000010000000000000000000010110000000 +0000100000110100 0000000001101010000000000000000000000110000000 +0000100000111000 0000010001001010000000000000000000000110000000 +0000100000111100 0000000100001010000000000000000000000110000000 +0000100000110001 0000000001101010000000000000000000000110000000 +0000100000111001 0000010001100010000000000000000000000110000000 +0000100000111101 0000000101100010000000000000000000000110000000 +0000100000110010 0000010001001010000000000000000000000110000000 +0000100000110110 0000010001100010000000000000000000000110000000 +0000100000111110 0000010101000010000000000000000000000110000000 +0000100000110011 0000000100001010000000000000000000000110000000 +0000100000110111 0000000101100010000000000000000000000110000000 +0000100000111011 0000010101000010000000000000000000000110000000 +0000100011110100 0000000001101010000000000000000000011110000000 +0000100011111000 0000010001001010000000000000000000011110000000 +0000100011111100 0000000100001010000000000000000000011110000000 +0000100011110001 0000000001101010000000000000000000011110000000 +0000100011111001 0000010001100010000000000000000000011110000000 +0000100011111101 0000000101100010000000000000000000011110000000 +0000100011110010 0000010001001010000000000000000000011110000000 +0000100011110110 0000010001100010000000000000000000011110000000 +0000100011111110 0000010101000010000000000000000000011110000000 +0000100011110011 0000000100001010000000000000000000011110000000 +0000100011110111 0000000101100010000000000000000000011110000000 +0000100011111011 0000010101000010000000000000000000011110000000 +0000111001101010 0000010001000000000000000000000000001101000000 +0000111010101010 0000010001000000000000000000000000010101000000 +0000111000101010 0000010001000000000000000000000000000101000000 +0000111011101010 0000010001000000000000000000000000011101000000 +0000111001011111 0000000100000000000000000000000000001011000000 +0000111010011111 0000000100000000000000000000000000010011000000 +0000111000011111 0000000100000000000000000000000000000011000000 +0000111011011111 0000000100000000000000000000000000011011000000 +0000111001101010 0000010001000000000000000000000000001101000000 +0000111010101010 0000010001000000000000000000000000010101000000 +0000111000101010 0000010001000000000000000000000000000101000000 +0000111011101010 0000010001000000000000000000000000011101000000 +0000111001011111 0000000100000000000000000000000000001011000000 +0000111010011111 0000000100000000000000000000000000010011000000 +0000111000011111 0000000100000000000000000000000000000011000000 +0000111011011111 0000000100000000000000000000000000011011000000 +0000111001101000 0000010001001000000000000000000000001101000000 +0000111001101001 0000010001100000000000000000000000001101000000 +0000111001100010 0000010001001000000000000000000000001101000000 +0000111001100110 0000010001100000000000000000000000001101000000 +0000111001101110 0000010101000000000000000000000000001101000000 +0000111001101011 0000010101000000000000000000000000001101000000 +0000111010101000 0000010001001000000000000000000000010101000000 +0000111010101001 0000010001100000000000000000000000010101000000 +0000111010100010 0000010001001000000000000000000000010101000000 +0000111010100110 0000010001100000000000000000000000010101000000 +0000111010101110 0000010101000000000000000000000000010101000000 +0000111010101011 0000010101000000000000000000000000010101000000 +0000111000101000 0000010001001000000000000000000000000101000000 +0000111000101001 0000010001100000000000000000000000000101000000 +0000111000100010 0000010001001000000000000000000000000101000000 +0000111000100110 0000010001100000000000000000000000000101000000 +0000111000101110 0000010101000000000000000000000000000101000000 +0000111000101011 0000010101000000000000000000000000000101000000 +0000111011101000 0000010001001000000000000000000000011101000000 +0000111011101001 0000010001100000000000000000000000011101000000 +0000111011100010 0000010001001000000000000000000000011101000000 +0000111011100110 0000010001100000000000000000000000011101000000 +0000111011101110 0000010101000000000000000000000000011101000000 +0000111011101011 0000010101000000000000000000000000011101000000 +0000111001011100 0000000100001000000000000000000000001011000000 +0000111001011101 0000000101100000000000000000000000001011000000 +0000111001011110 0000010101000000000000000000000000001011000000 +0000111001010011 0000000100001000000000000000000000001011000000 +0000111001010111 0000000101100000000000000000000000001011000000 +0000111001011011 0000010101000000000000000000000000001011000000 +0000111010011100 0000000100001000000000000000000000010011000000 +0000111010011101 0000000101100000000000000000000000010011000000 +0000111010011110 0000010101000000000000000000000000010011000000 +0000111010010011 0000000100001000000000000000000000010011000000 +0000111010010111 0000000101100000000000000000000000010011000000 +0000111010011011 0000010101000000000000000000000000010011000000 +0000111000011100 0000000100001000000000000000000000000011000000 +0000111000011101 0000000101100000000000000000000000000011000000 +0000111000011110 0000010101000000000000000000000000000011000000 +0000111000010011 0000000100001000000000000000000000000011000000 +0000111000010111 0000000101100000000000000000000000000011000000 +0000111000011011 0000010101000000000000000000000000000011000000 +0000111011011100 0000000100001000000000000000000000011011000000 +0000111011011101 0000000101100000000000000000000000011011000000 +0000111011011110 0000010101000000000000000000000000011011000000 +0000111011010011 0000000100001000000000000000000000011011000000 +0000111011010111 0000000101100000000000000000000000011011000000 +0000111011011011 0000010101000000000000000000000000011011000000 +0000110101100000 0000000000001000000000000000001010101100000001 +0000110101100101 0000000001100000000000000000001010101100000001 +0000110101101010 0000010001000000000000000000001010101100000001 +0000110101101111 0000000100000000000000000000001010101100000001 +0000110110100000 0000000000001000000000000000001010110100000001 +0000110110100101 0000000001100000000000000000001010110100000001 +0000110110101010 0000010001000000000000000000001010110100000001 +0000110110101111 0000000100000000000000000000001010110100000001 +0000110100100000 0000000000001000000000000000001010100100000001 +0000110100100101 0000000001100000000000000000001010100100000001 +0000110100101010 0000010001000000000000000000001010100100000001 +0000110100101111 0000000100000000000000000000001010100100000001 +0000110111100000 0000000000001000000000000000001010111100000001 +0000110111100101 0000000001100000000000000000001010111100000001 +0000110111101010 0000010001000000000000000000001010111100000001 +0000110111101111 0000000100000000000000000000001010111100000001 +0000110101010000 0000000000001000000000000000001010101010000001 +0000110101010101 0000000001100000000000000000001010101010000001 +0000110101011010 0000010001000000000000000000001010101010000001 +0000110101011111 0000000100000000000000000000001010101010000001 +0000110110010000 0000000000001000000000000000001010110010000001 +0000110110010101 0000000001100000000000000000001010110010000001 +0000110110011010 0000010001000000000000000000001010110010000001 +0000110110011111 0000000100000000000000000000001010110010000001 +0000110100010000 0000000000001000000000000000001010100010000001 +0000110100010101 0000000001100000000000000000001010100010000001 +0000110100011010 0000010001000000000000000000001010100010000001 +0000110100011111 0000000100000000000000000000001010100010000001 +0000110111010000 0000000000001000000000000000001010111010000001 +0000110111010101 0000000001100000000000000000001010111010000001 +0000110111011010 0000010001000000000000000000001010111010000001 +0000110111011111 0000000100000000000000000000001010111010000001 +0000110101000000 0000000000001000000000000000001010101000000001 +0000110101000101 0000000001100000000000000000001010101000000001 +0000110101001010 0000010001000000000000000000001010101000000001 +0000110101001111 0000000100000000000000000000001010101000000001 +0000110110000000 0000000000001000000000000000001010110000000001 +0000110110000101 0000000001100000000000000000001010110000000001 +0000110110001010 0000010001000000000000000000001010110000000001 +0000110110001111 0000000100000000000000000000001010110000000001 +0000110100000000 0000000000001000000000000000001010100000000001 +0000110100000101 0000000001100000000000000000001010100000000001 +0000110100001010 0000010001000000000000000000001010100000000001 +0000110100001111 0000000100000000000000000000001010100000000001 +0000110111000000 0000000000001000000000000000001010111000000001 +0000110111000101 0000000001100000000000000000001010111000000001 +0000110111001010 0000010001000000000000000000001010111000000001 +0000110111001111 0000000100000000000000000000001010111000000001 +0000110101110000 0000000000001000000000000000001010101110000001 +0000110101110101 0000000001100000000000000000001010101110000001 +0000110101111010 0000010001000000000000000000001010101110000001 +0000110101111111 0000000100000000000000000000001010101110000001 +0000110110110000 0000000000001000000000000000001010110110000001 +0000110110110101 0000000001100000000000000000001010110110000001 +0000110110111010 0000010001000000000000000000001010110110000001 +0000110110111111 0000000100000000000000000000001010110110000001 +0000110100110000 0000000000001000000000000000001010100110000001 +0000110100110101 0000000001100000000000000000001010100110000001 +0000110100111010 0000010001000000000000000000001010100110000001 +0000110100111111 0000000100000000000000000000001010100110000001 +0000110111110000 0000000000001000000000000000001010111110000001 +0000110111110101 0000000001100000000000000000001010111110000001 +0000110111111010 0000010001000000000000000000001010111110000001 +0000110111111111 0000000100000000000000000000001010111110000001 +0000110101100100 0000000001101000000000000000001010101100000001 +0000110101101000 0000010001001000000000000000001010101100000001 +0000110101101100 0000000100001000000000000000001010101100000001 +0000110101100001 0000000001101000000000000000001010101100000001 +0000110101101001 0000010001100000000000000000001010101100000001 +0000110101101101 0000000101100000000000000000001010101100000001 +0000110101100010 0000010001001000000000000000001010101100000001 +0000110101100110 0000010001100000000000000000001010101100000001 +0000110101101110 0000010101000000000000000000001010101100000001 +0000110101100011 0000000100001000000000000000001010101100000001 +0000110101100111 0000000101100000000000000000001010101100000001 +0000110101101011 0000010101000000000000000000001010101100000001 +0000110110100100 0000000001101000000000000000001010110100000001 +0000110110101000 0000010001001000000000000000001010110100000001 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000000000000110000000000001 +110001110000---- 0000000000000000000000000000000000000000010000 +0000110110101100 0000000100001000000000000000001010110100000001 +0000110110100001 0000000001101000000000000000001010110100000001 +0000110110101001 0000010001100000000000000000001010110100000001 +0000110110101101 0000000101100000000000000000001010110100000001 +0000110110100010 0000010001001000000000000000001010110100000001 +0000110110100110 0000010001100000000000000000001010110100000001 +0000110110101110 0000010101000000000000000000001010110100000001 +0000110110100011 0000000100001000000000000000001010110100000001 +0000110110100111 0000000101100000000000000000001010110100000001 +0000110110101011 0000010101000000000000000000001010110100000001 +0000110100100100 0000000001101000000000000000001010100100000001 +0000110100101000 0000010001001000000000000000001010100100000001 +0000110100101100 0000000100001000000000000000001010100100000001 +0000110100100001 0000000001101000000000000000001010100100000001 +0000110100101001 0000010001100000000000000000001010100100000001 +0000110100101101 0000000101100000000000000000001010100100000001 +0000110100100010 0000010001001000000000000000001010100100000001 +0000110100100110 0000010001100000000000000000001010100100000001 +0000110100101110 0000010101000000000000000000001010100100000001 +0000110100100011 0000000100001000000000000000001010100100000001 +0000110100100111 0000000101100000000000000000001010100100000001 +0000110100101011 0000010101000000000000000000001010100100000001 +0000110111100100 0000000001101000000000000000001010111100000001 +0000110111101000 0000010001001000000000000000001010111100000001 +0000110111101100 0000000100001000000000000000001010111100000001 +0000110111100001 0000000001101000000000000000001010111100000001 +0000110111101001 0000010001100000000000000000001010111100000001 +0000110111101101 0000000101100000000000000000001010111100000001 +0000110111100010 0000010001001000000000000000001010111100000001 +0000110111100110 0000010001100000000000000000001010111100000001 +0000110111101110 0000010101000000000000000000001010111100000001 +0000110111100011 0000000100001000000000000000001010111100000001 +0000110111100111 0000000101100000000000000000001010111100000001 +0000110111101011 0000010101000000000000000000001010111100000001 +0000110101010100 0000000001101000000000000000001010101010000001 +0000110101011000 0000010001001000000000000000001010101010000001 +0000110101011100 0000000100001000000000000000001010101010000001 +0000110101010001 0000000001101000000000000000001010101010000001 +0000110101011001 0000010001100000000000000000001010101010000001 +0000110101011101 0000000101100000000000000000001010101010000001 +0000110101010010 0000010001001000000000000000001010101010000001 +0000110101010110 0000010001100000000000000000001010101010000001 +0000110101011110 0000010101000000000000000000001010101010000001 +0000110101010011 0000000100001000000000000000001010101010000001 +0000110101010111 0000000101100000000000000000001010101010000001 +0000110101011011 0000010101000000000000000000001010101010000001 +0000110110010100 0000000001101000000000000000001010110010000001 +0000110110011000 0000010001001000000000000000001010110010000001 +0000110110011100 0000000100001000000000000000001010110010000001 +0000110110010001 0000000001101000000000000000001010110010000001 +0000110110011001 0000010001100000000000000000001010110010000001 +0000110110011101 0000000101100000000000000000001010110010000001 +0000110110010010 0000010001001000000000000000001010110010000001 +0000110110010110 0000010001100000000000000000001010110010000001 +0000110110011110 0000010101000000000000000000001010110010000001 +0000110110010011 0000000100001000000000000000001010110010000001 +0000110110010111 0000000101100000000000000000001010110010000001 +0000110110011011 0000010101000000000000000000001010110010000001 +0000110100010100 0000000001101000000000000000001010100010000001 +0000110100011000 0000010001001000000000000000001010100010000001 +0000110100011100 0000000100001000000000000000001010100010000001 +0000110100010001 0000000001101000000000000000001010100010000001 +0000110100011001 0000010001100000000000000000001010100010000001 +0000110100011101 0000000101100000000000000000001010100010000001 +0000110100010010 0000010001001000000000000000001010100010000001 +0000110100010110 0000010001100000000000000000001010100010000001 +0000110100011110 0000010101000000000000000000001010100010000001 +0000110100010011 0000000100001000000000000000001010100010000001 +0000110100010111 0000000101100000000000000000001010100010000001 +0000110100011011 0000010101000000000000000000001010100010000001 +0000110111010100 0000000001101000000000000000001010111010000001 +0000110111011000 0000010001001000000000000000001010111010000001 +0000110111011100 0000000100001000000000000000001010111010000001 +0000110111010001 0000000001101000000000000000001010111010000001 +0000110111011001 0000010001100000000000000000001010111010000001 +0000110111011101 0000000101100000000000000000001010111010000001 +0000110111010010 0000010001001000000000000000001010111010000001 +0000110111010110 0000010001100000000000000000001010111010000001 +0000110111011110 0000010101000000000000000000001010111010000001 +0000110111010011 0000000100001000000000000000001010111010000001 +0000110111010111 0000000101100000000000000000001010111010000001 +0000110111011011 0000010101000000000000000000001010111010000001 +0000110101000100 0000000001101000000000000000001010101000000001 +0000110101001000 0000010001001000000000000000001010101000000001 +0000110101001100 0000000100001000000000000000001010101000000001 +0000110101000001 0000000001101000000000000000001010101000000001 +0000110101001001 0000010001100000000000000000001010101000000001 +0000110101001101 0000000101100000000000000000001010101000000001 +0000110101000010 0000010001001000000000000000001010101000000001 +0000110101000110 0000010001100000000000000000001010101000000001 +0000110101001110 0000010101000000000000000000001010101000000001 +0000110101000011 0000000100001000000000000000001010101000000001 +0000110101000111 0000000101100000000000000000001010101000000001 +0000110101001011 0000010101000000000000000000001010101000000001 +0000110110000100 0000000001101000000000000000001010110000000001 +0000110110001000 0000010001001000000000000000001010110000000001 +0000110110001100 0000000100001000000000000000001010110000000001 +0000110110000001 0000000001101000000000000000001010110000000001 +0000110110001001 0000010001100000000000000000001010110000000001 +0000110110001101 0000000101100000000000000000001010110000000001 +0000110110000010 0000010001001000000000000000001010110000000001 +0000110110000110 0000010001100000000000000000001010110000000001 +0000110110001110 0000010101000000000000000000001010110000000001 +0000110110000011 0000000100001000000000000000001010110000000001 +0000110110000111 0000000101100000000000000000001010110000000001 +0000110110001011 0000010101000000000000000000001010110000000001 +0000110100000100 0000000001101000000000000000001010100000000001 +0000110100001000 0000010001001000000000000000001010100000000001 +0000110100001100 0000000100001000000000000000001010100000000001 +0000110100000001 0000000001101000000000000000001010100000000001 +0000110100001001 0000010001100000000000000000001010100000000001 +0000110100001101 0000000101100000000000000000001010100000000001 +0000110100000010 0000010001001000000000000000001010100000000001 +0000110100000110 0000010001100000000000000000001010100000000001 +0000110100001110 0000010101000000000000000000001010100000000001 +0000110100000011 0000000100001000000000000000001010100000000001 +0000110100000111 0000000101100000000000000000001010100000000001 +0000110100001011 0000010101000000000000000000001010100000000001 +0000110111000100 0000000001101000000000000000001010111000000001 +0000110111001000 0000010001001000000000000000001010111000000001 +0000110111001100 0000000100001000000000000000001010111000000001 +0000110111000001 0000000001101000000000000000001010111000000001 +0000110111001001 0000010001100000000000000000001010111000000001 +0000110111001101 0000000101100000000000000000001010111000000001 +0000110111000010 0000010001001000000000000000001010111000000001 +0000110111000110 0000010001100000000000000000001010111000000001 +0000110111001110 0000010101000000000000000000001010111000000001 +0000110111000011 0000000100001000000000000000001010111000000001 +0000110111000111 0000000101100000000000000000001010111000000001 +0000110111001011 0000010101000000000000000000001010111000000001 +0000110101110100 0000000001101000000000000000001010101110000001 +0000110101111000 0000010001001000000000000000001010101110000001 +0000110101111100 0000000100001000000000000000001010101110000001 +0000110101110001 0000000001101000000000000000001010101110000001 +0000110101111001 0000010001100000000000000000001010101110000001 +0000110101111101 0000000101100000000000000000001010101110000001 +0000110101110010 0000010001001000000000000000001010101110000001 +0000110101110110 0000010001100000000000000000001010101110000001 +0000110101111110 0000010101000000000000000000001010101110000001 +0000110101110011 0000000100001000000000000000001010101110000001 +0000110101110111 0000000101100000000000000000001010101110000001 +0000110101111011 0000010101000000000000000000001010101110000001 +0000110110110100 0000000001101000000000000000001010110110000001 +0000110110111000 0000010001001000000000000000001010110110000001 +0000110110111100 0000000100001000000000000000001010110110000001 +0000110110110001 0000000001101000000000000000001010110110000001 +0000110110111001 0000010001100000000000000000001010110110000001 +0000110110111101 0000000101100000000000000000001010110110000001 +0000110110110010 0000010001001000000000000000001010110110000001 +0000110110110110 0000010001100000000000000000001010110110000001 +0000110110111110 0000010101000000000000000000001010110110000001 +0000110110110011 0000000100001000000000000000001010110110000001 +0000110110110111 0000000101100000000000000000001010110110000001 +0000110110111011 0000010101000000000000000000001010110110000001 +0000110100110100 0000000001101000000000000000001010100110000001 +0000110100111000 0000010001001000000000000000001010100110000001 +0000110100111100 0000000100001000000000000000001010100110000001 +0000110100110001 0000000001101000000000000000001010100110000001 +0000110100111001 0000010001100000000000000000001010100110000001 +0000110100111101 0000000101100000000000000000001010100110000001 +0000110100110010 0000010001001000000000000000001010100110000001 +0000110100110110 0000010001100000000000000000001010100110000001 +0000110100111110 0000010101000000000000000000001010100110000001 +0000110100110011 0000000100001000000000000000001010100110000001 +0000110100110111 0000000101100000000000000000001010100110000001 +0000110100111011 0000010101000000000000000000001010100110000001 +0000110111110100 0000000001101000000000000000001010111110000001 +0000110111111000 0000010001001000000000000000001010111110000001 +0000110111111100 0000000100001000000000000000001010111110000001 +0000110111110001 0000000001101000000000000000001010111110000001 +0000110111111001 0000010001100000000000000000001010111110000001 +0000110111111101 0000000101100000000000000000001010111110000001 +0000110111110010 0000010001001000000000000000001010111110000001 +0000110111110110 0000010001100000000000000000001010111110000001 +0000110111111110 0000010101000000000000000000001010111110000001 +0000110111110011 0000000100001000000000000000001010111110000001 +0000110111110111 0000000101100000000000000000001010111110000001 +0000110111111011 0000010101000000000000000000001010111110000001 +0000011101000000 0000000000001001000000000000000000001000000100 +0000011101000101 0000000001100001000000000000000000001000000100 +0000011101001010 0000010001000001000000000000000000001000000100 +0000011101001111 0000000100000001000000000000000000001000000100 +0000011110000000 0000000000001001000000000000000000010000000100 +0000011110000101 0000000001100001000000000000000000010000000100 +0000011110001010 0000010001000001000000000000000000010000000100 +0000011110001111 0000000100000001000000000000000000010000000100 +0000011100000000 0000000000001001000000000000000000000000000100 +0000011100000101 0000000001100001000000000000000000000000000100 +0000011100001010 0000010001000001000000000000000000000000000100 +0000011100001111 0000000100000001000000000000000000000000000100 +0000011111000000 0000000000001001000000000000000000011000000100 +0000011111000101 0000000001100001000000000000000000011000000100 +0000011111001010 0000010001000001000000000000000000011000000100 +0000011111001111 0000000100000001000000000000000000011000000100 +0000011101000100 0000000001101001000000000000000000001000000100 +0000011101001000 0000010001001001000000000000000000001000000100 +0000011101001100 0000000100001001000000000000000000001000000100 +0000011101000001 0000000001101001000000000000000000001000000100 +0000011101001001 0000010001100001000000000000000000001000000100 +0000011101001101 0000000101100001000000000000000000001000000100 +0000011101000010 0000010001001001000000000000000000001000000100 +0000011101000110 0000010001100001000000000000000000001000000100 +0000011101001110 0000010101000001000000000000000000001000000100 +0000011101000011 0000000100001001000000000000000000001000000100 +0000011101000111 0000000101100001000000000000000000001000000100 +0000011101001011 0000010101000001000000000000000000001000000100 +0000011110000100 0000000001101001000000000000000000010000000100 +0000011110001000 0000010001001001000000000000000000010000000100 +0000011110001100 0000000100001001000000000000000000010000000100 +0000011110000001 0000000001101001000000000000000000010000000100 +0000011110001001 0000010001100001000000000000000000010000000100 +0000011110001101 0000000101100001000000000000000000010000000100 +0000011110000010 0000010001001001000000000000000000010000000100 +0000011110000110 0000010001100001000000000000000000010000000100 +0000011110001110 0000010101000001000000000000000000010000000100 +0000011110000011 0000000100001001000000000000000000010000000100 +0000011110000111 0000000101100001000000000000000000010000000100 +0000011110001011 0000010101000001000000000000000000010000000100 +0000011100000100 0000000001101001000000000000000000000000000100 +0000011100001000 0000010001001001000000000000000000000000000100 +0000011100001100 0000000100001001000000000000000000000000000100 +0000011100000001 0000000001101001000000000000000000000000000100 +0000011100001001 0000010001100001000000000000000000000000000100 +0000011100001101 0000000101100001000000000000000000000000000100 +0000011100000010 0000010001001001000000000000000000000000000100 +0000011100000110 0000010001100001000000000000000000000000000100 +0000011100001110 0000010101000001000000000000000000000000000100 +0000011100000011 0000000100001001000000000000000000000000000100 +0000011100000111 0000000101100001000000000000000000000000000100 +0000011100001011 0000010101000001000000000000000000000000000100 +0000011111000100 0000000001101001000000000000000000011000000100 +0000011111001000 0000010001001001000000000000000000011000000100 +0000011111001100 0000000100001001000000000000000000011000000100 +0000011111000001 0000000001101001000000000000000000011000000100 +0000011111001001 0000010001100001000000000000000000011000000100 +0000011111001101 0000000101100001000000000000000000011000000100 +0000011111000010 0000010001001001000000000000000000011000000100 +0000011111000110 0000010001100001000000000000000000011000000100 +0000011111001110 0000010101000001000000000000000000011000000100 +0000011111000011 0000000100001001000000000000000000011000000100 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000000000000110000000000001 +110001110000---- 0000000000000000000000000000000000000000010000 +0000011111000111 0000000101100001000000000000000000011000000100 +0000011111001011 0000010101000001000000000000000000011000000100 +000000100110---- 0000010001000100000000000000000000001100001000 +000000101010---- 0000010001000100000000000000000000010100001000 +000000100101---- 0000000100000100000000000000000000001010001000 +000000101001---- 0000000100000100000000000000000000010010001000 +000000100010---- 0000010001000100000000000000000000000100001000 +000000100001---- 0000000100000100000000000000000000000010001000 +000000101110---- 0000010001000100000000000000000000011100001000 +000000101101---- 0000000100000100000000000000000000011010001000 +0000111101100000 0000000000001100000000000000001010101100000001 +0000111101100101 0000000001100100000000000000001010101100000001 +0000111101101010 0000010001000100000000000000001010101100000001 +0000111101101111 0000000100000100000000000000001010101100000001 +0000111110100000 0000000000001100000000000000001010110100000001 +0000111110100101 0000000001100100000000000000001010110100000001 +0000111110101010 0000010001000100000000000000001010110100000001 +0000111110101111 0000000100000100000000000000001010110100000001 +0000111100100000 0000000000001100000000000000001010100100000001 +0000111100100101 0000000001100100000000000000001010100100000001 +0000111100101010 0000010001000100000000000000001010100100000001 +0000111100101111 0000000100000100000000000000001010100100000001 +0000111111100000 0000000000001100000000000000001010111100000001 +0000111111100101 0000000001100100000000000000001010111100000001 +0000111111101010 0000010001000100000000000000001010111100000001 +0000111111101111 0000000100000100000000000000001010111100000001 +0000111101010000 0000000000001100000000000000001010101010000001 +0000111101010101 0000000001100100000000000000001010101010000001 +0000111101011010 0000010001000100000000000000001010101010000001 +0000111101011111 0000000100000100000000000000001010101010000001 +0000111110010000 0000000000001100000000000000001010110010000001 +0000111110010101 0000000001100100000000000000001010110010000001 +0000111110011010 0000010001000100000000000000001010110010000001 +0000111110011111 0000000100000100000000000000001010110010000001 +0000111100010000 0000000000001100000000000000001010100010000001 +0000111100010101 0000000001100100000000000000001010100010000001 +0000111100011010 0000010001000100000000000000001010100010000001 +0000111100011111 0000000100000100000000000000001010100010000001 +0000111111010000 0000000000001100000000000000001010111010000001 +0000111111010101 0000000001100100000000000000001010111010000001 +0000111111011010 0000010001000100000000000000001010111010000001 +0000111111011111 0000000100000100000000000000001010111010000001 +0000111101000000 0000000000001100000000000000001010101000000001 +0000111101000101 0000000001100100000000000000001010101000000001 +0000111101001010 0000010001000100000000000000001010101000000001 +0000111101001111 0000000100000100000000000000001010101000000001 +0000111110000000 0000000000001100000000000000001010110000000001 +0000111110000101 0000000001100100000000000000001010110000000001 +0000111110001010 0000010001000100000000000000001010110000000001 +0000111110001111 0000000100000100000000000000001010110000000001 +0000111100000000 0000000000001100000000000000001010100000000001 +0000111100000101 0000000001100100000000000000001010100000000001 +0000111100001010 0000010001000100000000000000001010100000000001 +0000111100001111 0000000100000100000000000000001010100000000001 +0000111111000000 0000000000001100000000000000001010111000000001 +0000111111000101 0000000001100100000000000000001010111000000001 +0000111111001010 0000010001000100000000000000001010111000000001 +0000111111001111 0000000100000100000000000000001010111000000001 +0000111101110000 0000000000001100000000000000001010101110000001 +0000111101110101 0000000001100100000000000000001010101110000001 +0000111101111010 0000010001000100000000000000001010101110000001 +0000111101111111 0000000100000100000000000000001010101110000001 +0000111110110000 0000000000001100000000000000001010110110000001 +0000111110110101 0000000001100100000000000000001010110110000001 +0000111110111010 0000010001000100000000000000001010110110000001 +0000111110111111 0000000100000100000000000000001010110110000001 +0000111100110000 0000000000001100000000000000001010100110000001 +0000111100110101 0000000001100100000000000000001010100110000001 +0000111100111010 0000010001000100000000000000001010100110000001 +0000111100111111 0000000100000100000000000000001010100110000001 +0000111111110000 0000000000001100000000000000001010111110000001 +0000111111110101 0000000001100100000000000000001010111110000001 +0000111111111010 0000010001000100000000000000001010111110000001 +0000111111111111 0000000100000100000000000000001010111110000001 +0000111101100100 0000000001101100000000000000001010101100000001 +0000111101101000 0000010001001100000000000000001010101100000001 +0000111101101100 0000000100001100000000000000001010101100000001 +0000111101100001 0000000001101100000000000000001010101100000001 +0000111101101001 0000010001100100000000000000001010101100000001 +0000111101101101 0000000101100100000000000000001010101100000001 +0000111101100010 0000010001001100000000000000001010101100000001 +0000111101100110 0000010001100100000000000000001010101100000001 +0000111101101110 0000010101000100000000000000001010101100000001 +0000111101100011 0000000100001100000000000000001010101100000001 +0000111101100111 0000000101100100000000000000001010101100000001 +0000111101101011 0000010101000100000000000000001010101100000001 +0000111110100100 0000000001101100000000000000001010110100000001 +0000111110101000 0000010001001100000000000000001010110100000001 +0000111110101100 0000000100001100000000000000001010110100000001 +0000111110100001 0000000001101100000000000000001010110100000001 +0000111110101001 0000010001100100000000000000001010110100000001 +0000111110101101 0000000101100100000000000000001010110100000001 +0000111110100010 0000010001001100000000000000001010110100000001 +0000111110100110 0000010001100100000000000000001010110100000001 +0000111110101110 0000010101000100000000000000001010110100000001 +0000111110100011 0000000100001100000000000000001010110100000001 +0000111110100111 0000000101100100000000000000001010110100000001 +0000111110101011 0000010101000100000000000000001010110100000001 +0000111100100100 0000000001101100000000000000001010100100000001 +0000111100101000 0000010001001100000000000000001010100100000001 +0000111100101100 0000000100001100000000000000001010100100000001 +0000111100100001 0000000001101100000000000000001010100100000001 +0000111100101001 0000010001100100000000000000001010100100000001 +0000111100101101 0000000101100100000000000000001010100100000001 +0000111100100010 0000010001001100000000000000001010100100000001 +0000111100100110 0000010001100100000000000000001010100100000001 +0000111100101110 0000010101000100000000000000001010100100000001 +0000111100100011 0000000100001100000000000000001010100100000001 +0000111100100111 0000000101100100000000000000001010100100000001 +0000111100101011 0000010101000100000000000000001010100100000001 +0000111111100100 0000000001101100000000000000001010111100000001 +0000111111101000 0000010001001100000000000000001010111100000001 +0000111111101100 0000000100001100000000000000001010111100000001 +0000111111100001 0000000001101100000000000000001010111100000001 +0000111111101001 0000010001100100000000000000001010111100000001 +0000111111101101 0000000101100100000000000000001010111100000001 +0000111111100010 0000010001001100000000000000001010111100000001 +0000111111100110 0000010001100100000000000000001010111100000001 +0000111111101110 0000010101000100000000000000001010111100000001 +0000111111100011 0000000100001100000000000000001010111100000001 +0000111111100111 0000000101100100000000000000001010111100000001 +0000111111101011 0000010101000100000000000000001010111100000001 +0000111101010100 0000000001101100000000000000001010101010000001 +0000111101011000 0000010001001100000000000000001010101010000001 +0000111101011100 0000000100001100000000000000001010101010000001 +0000111101010001 0000000001101100000000000000001010101010000001 +0000111101011001 0000010001100100000000000000001010101010000001 +0000111101011101 0000000101100100000000000000001010101010000001 +0000111101010010 0000010001001100000000000000001010101010000001 +0000111101010110 0000010001100100000000000000001010101010000001 +0000111101011110 0000010101000100000000000000001010101010000001 +0000111101010011 0000000100001100000000000000001010101010000001 +0000111101010111 0000000101100100000000000000001010101010000001 +0000111101011011 0000010101000100000000000000001010101010000001 +0000111110010100 0000000001101100000000000000001010110010000001 +0000111110011000 0000010001001100000000000000001010110010000001 +0000111110011100 0000000100001100000000000000001010110010000001 +0000111110010001 0000000001101100000000000000001010110010000001 +0000111110011001 0000010001100100000000000000001010110010000001 +0000111110011101 0000000101100100000000000000001010110010000001 +0000111110010010 0000010001001100000000000000001010110010000001 +0000111110010110 0000010001100100000000000000001010110010000001 +0000111110011110 0000010101000100000000000000001010110010000001 +0000111110010011 0000000100001100000000000000001010110010000001 +0000111110010111 0000000101100100000000000000001010110010000001 +0000111110011011 0000010101000100000000000000001010110010000001 +0000111100010100 0000000001101100000000000000001010100010000001 +0000111100011000 0000010001001100000000000000001010100010000001 +0000111100011100 0000000100001100000000000000001010100010000001 +0000111100010001 0000000001101100000000000000001010100010000001 +0000111100011001 0000010001100100000000000000001010100010000001 +0000111100011101 0000000101100100000000000000001010100010000001 +0000111100010010 0000010001001100000000000000001010100010000001 +0000111100010110 0000010001100100000000000000001010100010000001 +0000111100011110 0000010101000100000000000000001010100010000001 +0000111100010011 0000000100001100000000000000001010100010000001 +0000111100010111 0000000101100100000000000000001010100010000001 +0000111100011011 0000010101000100000000000000001010100010000001 +0000111111010100 0000000001101100000000000000001010111010000001 +0000111111011000 0000010001001100000000000000001010111010000001 +0000111111011100 0000000100001100000000000000001010111010000001 +0000111111010001 0000000001101100000000000000001010111010000001 +0000111111011001 0000010001100100000000000000001010111010000001 +0000111111011101 0000000101100100000000000000001010111010000001 +0000111111010010 0000010001001100000000000000001010111010000001 +0000111111010110 0000010001100100000000000000001010111010000001 +0000111111011110 0000010101000100000000000000001010111010000001 +0000111111010011 0000000100001100000000000000001010111010000001 +0000111111010111 0000000101100100000000000000001010111010000001 +0000111111011011 0000010101000100000000000000001010111010000001 +0000111101000100 0000000001101100000000000000001010101000000001 +0000111101001000 0000010001001100000000000000001010101000000001 +0000111101001100 0000000100001100000000000000001010101000000001 +0000111101000001 0000000001101100000000000000001010101000000001 +0000111101001001 0000010001100100000000000000001010101000000001 +0000111101001101 0000000101100100000000000000001010101000000001 +0000111101000010 0000010001001100000000000000001010101000000001 +0000111101000110 0000010001100100000000000000001010101000000001 +0000111101001110 0000010101000100000000000000001010101000000001 +0000111101000011 0000000100001100000000000000001010101000000001 +0000111101000111 0000000101100100000000000000001010101000000001 +0000111101001011 0000010101000100000000000000001010101000000001 +0000111110000100 0000000001101100000000000000001010110000000001 +0000111110001000 0000010001001100000000000000001010110000000001 +0000111110001100 0000000100001100000000000000001010110000000001 +0000111110000001 0000000001101100000000000000001010110000000001 +0000111110001001 0000010001100100000000000000001010110000000001 +0000111110001101 0000000101100100000000000000001010110000000001 +0000111110000010 0000010001001100000000000000001010110000000001 +0000111110000110 0000010001100100000000000000001010110000000001 +0000111110001110 0000010101000100000000000000001010110000000001 +0000111110000011 0000000100001100000000000000001010110000000001 +0000111110000111 0000000101100100000000000000001010110000000001 +0000111110001011 0000010101000100000000000000001010110000000001 +0000111100000100 0000000001101100000000000000001010100000000001 +0000111100001000 0000010001001100000000000000001010100000000001 +0000111100001100 0000000100001100000000000000001010100000000001 +0000111100000001 0000000001101100000000000000001010100000000001 +0000111100001001 0000010001100100000000000000001010100000000001 +0000111100001101 0000000101100100000000000000001010100000000001 +0000111100000010 0000010001001100000000000000001010100000000001 +0000111100000110 0000010001100100000000000000001010100000000001 +0000111100001110 0000010101000100000000000000001010100000000001 +0000111100000011 0000000100001100000000000000001010100000000001 +0000111100000111 0000000101100100000000000000001010100000000001 +0000111100001011 0000010101000100000000000000001010100000000001 +0000111111000100 0000000001101100000000000000001010111000000001 +0000111111001000 0000010001001100000000000000001010111000000001 +0000111111001100 0000000100001100000000000000001010111000000001 +0000111111000001 0000000001101100000000000000001010111000000001 +0000111111001001 0000010001100100000000000000001010111000000001 +0000111111001101 0000000101100100000000000000001010111000000001 +0000111111000010 0000010001001100000000000000001010111000000001 +0000111111000110 0000010001100100000000000000001010111000000001 +0000111111001110 0000010101000100000000000000001010111000000001 +0000111111000011 0000000100001100000000000000001010111000000001 +0000111111000111 0000000101100100000000000000001010111000000001 +0000111111001011 0000010101000100000000000000001010111000000001 +0000111101110100 0000000001101100000000000000001010101110000001 +0000111101111000 0000010001001100000000000000001010101110000001 +0000111101111100 0000000100001100000000000000001010101110000001 +0000111101110001 0000000001101100000000000000001010101110000001 +0000111101111001 0000010001100100000000000000001010101110000001 +0000111101111101 0000000101100100000000000000001010101110000001 +0000111101110010 0000010001001100000000000000001010101110000001 +0000111101110110 0000010001100100000000000000001010101110000001 +0000111101111110 0000010101000100000000000000001010101110000001 +0000111101110011 0000000100001100000000000000001010101110000001 +0000111101110111 0000000101100100000000000000001010101110000001 +0000111101111011 0000010101000100000000000000001010101110000001 +0000111110110100 0000000001101100000000000000001010110110000001 +0000111110111000 0000010001001100000000000000001010110110000001 +0000111110111100 0000000100001100000000000000001010110110000001 +0000111110110001 0000000001101100000000000000001010110110000001 +0000111110111001 0000010001100100000000000000001010110110000001 +0000111110111101 0000000101100100000000000000001010110110000001 +0000111110110010 0000010001001100000000000000001010110110000001 +0000111110110110 0000010001100100000000000000001010110110000001 +0000111110111110 0000010101000100000000000000001010110110000001 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000000000000110000000000001 +110001110000---- 0000000000000000000000000000000000000000010000 +0000111110110011 0000000100001100000000000000001010110110000001 +0000111110110111 0000000101100100000000000000001010110110000001 +0000111110111011 0000010101000100000000000000001010110110000001 +0000111100110100 0000000001101100000000000000001010100110000001 +0000111100111000 0000010001001100000000000000001010100110000001 +0000111100111100 0000000100001100000000000000001010100110000001 +0000111100110001 0000000001101100000000000000001010100110000001 +0000111100111001 0000010001100100000000000000001010100110000001 +0000111100111101 0000000101100100000000000000001010100110000001 +0000111100110010 0000010001001100000000000000001010100110000001 +0000111100110110 0000010001100100000000000000001010100110000001 +0000111100111110 0000010101000100000000000000001010100110000001 +0000111100110011 0000000100001100000000000000001010100110000001 +0000111100110111 0000000101100100000000000000001010100110000001 +0000111100111011 0000010101000100000000000000001010100110000001 +0000111111110100 0000000001101100000000000000001010111110000001 +0000111111111000 0000010001001100000000000000001010111110000001 +0000111111111100 0000000100001100000000000000001010111110000001 +0000111111110001 0000000001101100000000000000001010111110000001 +0000111111111001 0000010001100100000000000000001010111110000001 +0000111111111101 0000000101100100000000000000001010111110000001 +0000111111110010 0000010001001100000000000000001010111110000001 +0000111111110110 0000010001100100000000000000001010111110000001 +0000111111111110 0000010101000100000000000000001010111110000001 +0000111111110011 0000000100001100000000000000001010111110000001 +0000111111110111 0000000101100100000000000000001010111110000001 +0000111111111011 0000010101000100000000000000001010111110000001 +000000010110---- 0000010001000000000000000000000000001100001000 +000000011010---- 0000010001000000000000000000000000010100001000 +000000010101---- 0000000100000000000000000000000000001010001000 +000000011001---- 0000000100000000000000000000000000010010001000 +000000010010---- 0000010001000000000000000000000000000100001000 +000000010001---- 0000000100000000000000000000000000000010001000 +000000011110---- 0000010001000000000000000000000000011100001000 +000000011101---- 0000000100000000000000000000000000011010001000 +0000011001100000 0000000000001000000000000000000000001100000110 +0000011001100101 0000000001100000000000000000000000001100000110 +0000011001101010 0000010001000000000000000000000000001100000110 +0000011001101111 0000000100000000000000000000000000001100000110 +0000011010100000 0000000000001000000000000000000000010100000110 +0000011010100101 0000000001100000000000000000000000010100000110 +0000011010101010 0000010001000000000000000000000000010100000110 +0000011010101111 0000000100000000000000000000000000010100000110 +0000011000100000 0000000000001000000000000000000000000100000110 +0000011000100101 0000000001100000000000000000000000000100000110 +0000011000101010 0000010001000000000000000000000000000100000110 +0000011000101111 0000000100000000000000000000000000000100000110 +0000011011100000 0000000000001000000000000000000000011100000110 +0000011011100101 0000000001100000000000000000000000011100000110 +0000011011101010 0000010001000000000000000000000000011100000110 +0000011011101111 0000000100000000000000000000000000011100000110 +0000011001010000 0000000000001000000000000000000000001010000110 +0000011001010101 0000000001100000000000000000000000001010000110 +0000011001011010 0000010001000000000000000000000000001010000110 +0000011001011111 0000000100000000000000000000000000001010000110 +0000011010010000 0000000000001000000000000000000000010010000110 +0000011010010101 0000000001100000000000000000000000010010000110 +0000011010011010 0000010001000000000000000000000000010010000110 +0000011010011111 0000000100000000000000000000000000010010000110 +0000011000010000 0000000000001000000000000000000000000010000110 +0000011000010101 0000000001100000000000000000000000000010000110 +0000011000011010 0000010001000000000000000000000000000010000110 +0000011000011111 0000000100000000000000000000000000000010000110 +0000011011010000 0000000000001000000000000000000000011010000110 +0000011011010101 0000000001100000000000000000000000011010000110 +0000011011011010 0000010001000000000000000000000000011010000110 +0000011011011111 0000000100000000000000000000000000011010000110 +0000011001000000 0000000000001000000000000000000000001000000110 +0000011001000101 0000000001100000000000000000000000001000000110 +0000011001001010 0000010001000000000000000000000000001000000110 +0000011001001111 0000000100000000000000000000000000001000000110 +0000011010000000 0000000000001000000000000000000000010000000110 +0000011010000101 0000000001100000000000000000000000010000000110 +0000011010001010 0000010001000000000000000000000000010000000110 +0000011010001111 0000000100000000000000000000000000010000000110 +0000011000000000 0000000000001000000000000000000000000000000110 +0000011000000101 0000000001100000000000000000000000000000000110 +0000011000001010 0000010001000000000000000000000000000000000110 +0000011000001111 0000000100000000000000000000000000000000000110 +0000011011000000 0000000000001000000000000000000000011000000110 +0000011011000101 0000000001100000000000000000000000011000000110 +0000011011001010 0000010001000000000000000000000000011000000110 +0000011011001111 0000000100000000000000000000000000011000000110 +0000011001110000 0000000000001000000000000000000000001110000110 +0000011001110101 0000000001100000000000000000000000001110000110 +0000011001111010 0000010001000000000000000000000000001110000110 +0000011001111111 0000000100000000000000000000000000001110000110 +0000011010110000 0000000000001000000000000000000000010110000110 +0000011010110101 0000000001100000000000000000000000010110000110 +0000011010111010 0000010001000000000000000000000000010110000110 +0000011010111111 0000000100000000000000000000000000010110000110 +0000011000110000 0000000000001000000000000000000000000110000110 +0000011000110101 0000000001100000000000000000000000000110000110 +0000011000111010 0000010001000000000000000000000000000110000110 +0000011000111111 0000000100000000000000000000000000000110000110 +0000011011110000 0000000000001000000000000000000000011110000110 +0000011011110101 0000000001100000000000000000000000011110000110 +0000011011111010 0000010001000000000000000000000000011110000110 +0000011011111111 0000000100000000000000000000000000011110000110 +0000011001100100 0000000001101000000000000000000000001100000110 +0000011001101000 0000010001001000000000000000000000001100000110 +0000011001101100 0000000100001000000000000000000000001100000110 +0000011001100001 0000000001101000000000000000000000001100000110 +0000011001101001 0000010001100000000000000000000000001100000110 +0000011001101101 0000000101100000000000000000000000001100000110 +0000011001100010 0000010001001000000000000000000000001100000110 +0000011001100110 0000010001100000000000000000000000001100000110 +0000011001101110 0000010101000000000000000000000000001100000110 +0000011001100011 0000000100001000000000000000000000001100000110 +0000011001100111 0000000101100000000000000000000000001100000110 +0000011001101011 0000010101000000000000000000000000001100000110 +0000011010100100 0000000001101000000000000000000000010100000110 +0000011010101000 0000010001001000000000000000000000010100000110 +0000011010101100 0000000100001000000000000000000000010100000110 +0000011010100001 0000000001101000000000000000000000010100000110 +0000011010101001 0000010001100000000000000000000000010100000110 +0000011010101101 0000000101100000000000000000000000010100000110 +0000011010100010 0000010001001000000000000000000000010100000110 +0000011010100110 0000010001100000000000000000000000010100000110 +0000011010101110 0000010101000000000000000000000000010100000110 +0000011010100011 0000000100001000000000000000000000010100000110 +0000011010100111 0000000101100000000000000000000000010100000110 +0000011010101011 0000010101000000000000000000000000010100000110 +0000011000100100 0000000001101000000000000000000000000100000110 +0000011000101000 0000010001001000000000000000000000000100000110 +0000011000101100 0000000100001000000000000000000000000100000110 +0000011000100001 0000000001101000000000000000000000000100000110 +0000011000101001 0000010001100000000000000000000000000100000110 +0000011000101101 0000000101100000000000000000000000000100000110 +0000011000100010 0000010001001000000000000000000000000100000110 +0000011000100110 0000010001100000000000000000000000000100000110 +0000011000101110 0000010101000000000000000000000000000100000110 +0000011000100011 0000000100001000000000000000000000000100000110 +0000011000100111 0000000101100000000000000000000000000100000110 +0000011000101011 0000010101000000000000000000000000000100000110 +0000011011100100 0000000001101000000000000000000000011100000110 +0000011011101000 0000010001001000000000000000000000011100000110 +0000011011101100 0000000100001000000000000000000000011100000110 +0000011011100001 0000000001101000000000000000000000011100000110 +0000011011101001 0000010001100000000000000000000000011100000110 +0000011011101101 0000000101100000000000000000000000011100000110 +0000011011100010 0000010001001000000000000000000000011100000110 +0000011011100110 0000010001100000000000000000000000011100000110 +0000011011101110 0000010101000000000000000000000000011100000110 +0000011011100011 0000000100001000000000000000000000011100000110 +0000011011100111 0000000101100000000000000000000000011100000110 +0000011011101011 0000010101000000000000000000000000011100000110 +0000011001010100 0000000001101000000000000000000000001010000110 +0000011001011000 0000010001001000000000000000000000001010000110 +0000011001011100 0000000100001000000000000000000000001010000110 +0000011001010001 0000000001101000000000000000000000001010000110 +0000011001011001 0000010001100000000000000000000000001010000110 +0000011001011101 0000000101100000000000000000000000001010000110 +0000011001010010 0000010001001000000000000000000000001010000110 +0000011001010110 0000010001100000000000000000000000001010000110 +0000011001011110 0000010101000000000000000000000000001010000110 +0000011001010011 0000000100001000000000000000000000001010000110 +0000011001010111 0000000101100000000000000000000000001010000110 +0000011001011011 0000010101000000000000000000000000001010000110 +0000011010010100 0000000001101000000000000000000000010010000110 +0000011010011000 0000010001001000000000000000000000010010000110 +0000011010011100 0000000100001000000000000000000000010010000110 +0000011010010001 0000000001101000000000000000000000010010000110 +0000011010011001 0000010001100000000000000000000000010010000110 +0000011010011101 0000000101100000000000000000000000010010000110 +0000011010010010 0000010001001000000000000000000000010010000110 +0000011010010110 0000010001100000000000000000000000010010000110 +0000011010011110 0000010101000000000000000000000000010010000110 +0000011010010011 0000000100001000000000000000000000010010000110 +0000011010010111 0000000101100000000000000000000000010010000110 +0000011010011011 0000010101000000000000000000000000010010000110 +0000011000010100 0000000001101000000000000000000000000010000110 +0000011000011000 0000010001001000000000000000000000000010000110 +0000011000011100 0000000100001000000000000000000000000010000110 +0000011000010001 0000000001101000000000000000000000000010000110 +0000011000011001 0000010001100000000000000000000000000010000110 +0000011000011101 0000000101100000000000000000000000000010000110 +0000011000010010 0000010001001000000000000000000000000010000110 +0000011000010110 0000010001100000000000000000000000000010000110 +0000011000011110 0000010101000000000000000000000000000010000110 +0000011000010011 0000000100001000000000000000000000000010000110 +0000011000010111 0000000101100000000000000000000000000010000110 +0000011000011011 0000010101000000000000000000000000000010000110 +0000011011010100 0000000001101000000000000000000000011010000110 +0000011011011000 0000010001001000000000000000000000011010000110 +0000011011011100 0000000100001000000000000000000000011010000110 +0000011011010001 0000000001101000000000000000000000011010000110 +0000011011011001 0000010001100000000000000000000000011010000110 +0000011011011101 0000000101100000000000000000000000011010000110 +0000011011010010 0000010001001000000000000000000000011010000110 +0000011011010110 0000010001100000000000000000000000011010000110 +0000011011011110 0000010101000000000000000000000000011010000110 +0000011011010011 0000000100001000000000000000000000011010000110 +0000011011010111 0000000101100000000000000000000000011010000110 +0000011011011011 0000010101000000000000000000000000011010000110 +0000011001000100 0000000001101000000000000000000000001000000110 +0000011001001000 0000010001001000000000000000000000001000000110 +0000011001001100 0000000100001000000000000000000000001000000110 +0000011001000001 0000000001101000000000000000000000001000000110 +0000011001001001 0000010001100000000000000000000000001000000110 +0000011001001101 0000000101100000000000000000000000001000000110 +0000011001000010 0000010001001000000000000000000000001000000110 +0000011001000110 0000010001100000000000000000000000001000000110 +0000011001001110 0000010101000000000000000000000000001000000110 +0000011001000011 0000000100001000000000000000000000001000000110 +0000011001000111 0000000101100000000000000000000000001000000110 +0000011001001011 0000010101000000000000000000000000001000000110 +0000011010000100 0000000001101000000000000000000000010000000110 +0000011010001000 0000010001001000000000000000000000010000000110 +0000011010001100 0000000100001000000000000000000000010000000110 +0000011010000001 0000000001101000000000000000000000010000000110 +0000011010001001 0000010001100000000000000000000000010000000110 +0000011010001101 0000000101100000000000000000000000010000000110 +0000011010000010 0000010001001000000000000000000000010000000110 +0000011010000110 0000010001100000000000000000000000010000000110 +0000011010001110 0000010101000000000000000000000000010000000110 +0000011010000011 0000000100001000000000000000000000010000000110 +0000011010000111 0000000101100000000000000000000000010000000110 +0000011010001011 0000010101000000000000000000000000010000000110 +0000011000000100 0000000001101000000000000000000000000000000110 +0000011000001000 0000010001001000000000000000000000000000000110 +0000011000001100 0000000100001000000000000000000000000000000110 +0000011000000001 0000000001101000000000000000000000000000000110 +0000011000001001 0000010001100000000000000000000000000000000110 +0000011000001101 0000000101100000000000000000000000000000000110 +0000011000000010 0000010001001000000000000000000000000000000110 +0000011000000110 0000010001100000000000000000000000000000000110 +0000011000001110 0000010101000000000000000000000000000000000110 +0000011000000011 0000000100001000000000000000000000000000000110 +0000011000000111 0000000101100000000000000000000000000000000110 +0000011000001011 0000010101000000000000000000000000000000000110 +0000011011000100 0000000001101000000000000000000000011000000110 +0000011011001000 0000010001001000000000000000000000011000000110 +0000011011001100 0000000100001000000000000000000000011000000110 +0000011011000001 0000000001101000000000000000000000011000000110 +0000011011001001 0000010001100000000000000000000000011000000110 +0000011011001101 0000000101100000000000000000000000011000000110 +0000011011000010 0000010001001000000000000000000000011000000110 +0000011011000110 0000010001100000000000000000000000011000000110 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000000000000110000000000001 +110001110000---- 0000000000000000000000000000000000000000010000 +0000011011001110 0000010101000000000000000000000000011000000110 +0000011011000011 0000000100001000000000000000000000011000000110 +0000011011000111 0000000101100000000000000000000000011000000110 +0000011011001011 0000010101000000000000000000000000011000000110 +0000011001110100 0000000001101000000000000000000000001110000110 +0000011001111000 0000010001001000000000000000000000001110000110 +0000011001111100 0000000100001000000000000000000000001110000110 +0000011001110001 0000000001101000000000000000000000001110000110 +0000011001111001 0000010001100000000000000000000000001110000110 +0000011001111101 0000000101100000000000000000000000001110000110 +0000011001110010 0000010001001000000000000000000000001110000110 +0000011001110110 0000010001100000000000000000000000001110000110 +0000011001111110 0000010101000000000000000000000000001110000110 +0000011001110011 0000000100001000000000000000000000001110000110 +0000011001110111 0000000101100000000000000000000000001110000110 +0000011001111011 0000010101000000000000000000000000001110000110 +0000011010110100 0000000001101000000000000000000000010110000110 +0000011010111000 0000010001001000000000000000000000010110000110 +0000011010111100 0000000100001000000000000000000000010110000110 +0000011010110001 0000000001101000000000000000000000010110000110 +0000011010111001 0000010001100000000000000000000000010110000110 +0000011010111101 0000000101100000000000000000000000010110000110 +0000011010110010 0000010001001000000000000000000000010110000110 +0000011010110110 0000010001100000000000000000000000010110000110 +0000011010111110 0000010101000000000000000000000000010110000110 +0000011010110011 0000000100001000000000000000000000010110000110 +0000011010110111 0000000101100000000000000000000000010110000110 +0000011010111011 0000010101000000000000000000000000010110000110 +0000011000110100 0000000001101000000000000000000000000110000110 +0000011000111000 0000010001001000000000000000000000000110000110 +0000011000111100 0000000100001000000000000000000000000110000110 +0000011000110001 0000000001101000000000000000000000000110000110 +0000011000111001 0000010001100000000000000000000000000110000110 +0000011000111101 0000000101100000000000000000000000000110000110 +0000011000110010 0000010001001000000000000000000000000110000110 +0000011000110110 0000010001100000000000000000000000000110000110 +0000011000111110 0000010101000000000000000000000000000110000110 +0000011000110011 0000000100001000000000000000000000000110000110 +0000011000110111 0000000101100000000000000000000000000110000110 +0000011000111011 0000010101000000000000000000000000000110000110 +0000011011110100 0000000001101000000000000000000000011110000110 +0000011011111000 0000010001001000000000000000000000011110000110 +0000011011111100 0000000100001000000000000000000000011110000110 +0000011011110001 0000000001101000000000000000000000011110000110 +0000011011111001 0000010001100000000000000000000000011110000110 +0000011011111101 0000000101100000000000000000000000011110000110 +0000011011110010 0000010001001000000000000000000000011110000110 +0000011011110110 0000010001100000000000000000000000011110000110 +0000011011111110 0000010101000000000000000000000000011110000110 +0000011011110011 0000000100001000000000000000000000011110000110 +0000011011110111 0000000101100000000000000000000000011110000110 +0000011011111011 0000010101000000000000000000000000011110000110 +000000110110---- 0000000000001000000000000000000000001100000110 +000000111010---- 0000000001100000000000000000000000010100000110 +000000110101---- 0000000000001000000000000000000000001010000110 +000000111001---- 0000000001100000000000000000000000010010000110 +000000110100---- 0000000000001000000000000000000000001000000110 +000000111000---- 0000000001100000000000000000000000010000000110 +000000110111---- 0000000000001000000000000000000000001110000110 +000000111011---- 0000000001100000000000000000000000010110000110 +0000101101000000 0000000000001001000000000000000000001000000000 +0000101110000101 0000000001100001000000000000000000010000000000 +0000101101000101 0000000001100001000000000000000000001000000000 +0000101101001010 0000010001000001000000000000000000001000000000 +0000101101001111 0000000100000001000000000000000000001000000000 +0000101110000000 0000000000001001000000000000000000010000000000 +0000101110001010 0000010001000001000000000000000000010000000000 +0000101110001111 0000000100000001000000000000000000010000000000 +0000101101000100 0000000001101001000000000000000000001000000000 +0000101101001000 0000010001001001000000000000000000001000000000 +0000101101001100 0000000100001001000000000000000000001000000000 +0000101101000001 0000000001101001000000000000000000001000000000 +0000101101001001 0000010001100001000000000000000000001000000000 +0000101101001101 0000000101100001000000000000000000001000000000 +0000101101000010 0000010001001001000000000000000000001000000000 +0000101101000110 0000010001100001000000000000000000001000000000 +0000101101001110 0000010101000001000000000000000000001000000000 +0000101101000011 0000000100001001000000000000000000001000000000 +0000101101000111 0000000101100001000000000000000000001000000000 +0000101101001011 0000010101000001000000000000000000001000000000 +0000101110000100 0000000001101001000000000000000000010000000000 +0000101110001000 0000010001001001000000000000000000010000000000 +0000101110001100 0000000100001001000000000000000000010000000000 +0000101110000001 0000000001101001000000000000000000010000000000 +0000101110001001 0000010001100001000000000000000000010000000000 +0000101110001101 0000000101100001000000000000000000010000000000 +0000101110000010 0000010001001001000000000000000000010000000000 +0000101110000110 0000010001100001000000000000000000010000000000 +0000101110001110 0000010101000001000000000000000000010000000000 +0000101110000011 0000000100001001000000000000000000010000000000 +0000101110000111 0000000101100001000000000000000000010000000000 +0000101110001011 0000010101000001000000000000000000010000000000 +0000101001100000 0000000000001000001000000000000000001100000000 +0000101001100101 0000000001100000001000000000000000001100000000 +0000101001101010 0000010001000000001000000000000000001100000000 +0000101001101111 0000000100000000001000000000000000001100000000 +0000101010100000 0000000000001000001000000000000000010100000000 +0000101010100101 0000000001100000001000000000000000010100000000 +0000101010101010 0000010001000000001000000000000000010100000000 +0000101010101111 0000000100000000001000000000000000010100000000 +0000101000100000 0000000000001000001000000000000000000100000000 +0000101000100101 0000000001100000001000000000000000000100000000 +0000101000101010 0000010001000000001000000000000000000100000000 +0000101000101111 0000000100000000001000000000000000000100000000 +0000101011100000 0000000000001000001000000000000000011100000000 +0000101011100101 0000000001100000001000000000000000011100000000 +0000101011101010 0000010001000000001000000000000000011100000000 +0000101011101111 0000000100000000001000000000000000011100000000 +0000101001010000 0000000000001000001000000000000000001010000000 +0000101001010101 0000000001100000001000000000000000001010000000 +0000101001011010 0000010001000000001000000000000000001010000000 +0000101001011111 0000000100000000001000000000000000001010000000 +0000101010010000 0000000000001000001000000000000000010010000000 +0000101010010101 0000000001100000001000000000000000010010000000 +0000101010011010 0000010001000000001000000000000000010010000000 +0000101010011111 0000000100000000001000000000000000010010000000 +0000101000010000 0000000000001000001000000000000000000010000000 +0000101000010101 0000000001100000001000000000000000000010000000 +0000101000011010 0000010001000000001000000000000000000010000000 +0000101000011111 0000000100000000001000000000000000000010000000 +0000101011010000 0000000000001000001000000000000000011010000000 +0000101011010101 0000000001100000001000000000000000011010000000 +0000101011011010 0000010001000000001000000000000000011010000000 +0000101011011111 0000000100000000001000000000000000011010000000 +0000101001000000 0000000000001000001000000000000000001000000000 +0000101001000101 0000000001100000001000000000000000001000000000 +0000101001001010 0000010001000000001000000000000000001000000000 +0000101001001111 0000000100000000001000000000000000001000000000 +0000101010000000 0000000000001000001000000000000000010000000000 +0000101010000101 0000000001100000001000000000000000010000000000 +0000101010001010 0000010001000000001000000000000000010000000000 +0000101010001111 0000000100000000001000000000000000010000000000 +0000101000000000 0000000000001000001000000000000000000000000000 +0000101000000101 0000000001100000001000000000000000000000000000 +0000101000001010 0000010001000000001000000000000000000000000000 +0000101000001111 0000000100000000001000000000000000000000000000 +0000101011000000 0000000000001000001000000000000000011000000000 +0000101011000101 0000000001100000001000000000000000011000000000 +0000101011001010 0000010001000000001000000000000000011000000000 +0000101011001111 0000000100000000001000000000000000011000000000 +0000101001110000 0000000000001000001000000000000000001110000000 +0000101001110101 0000000001100000001000000000000000001110000000 +0000101001111010 0000010001000000001000000000000000001110000000 +0000101001111111 0000000100000000001000000000000000001110000000 +0000101010110000 0000000000001000001000000000000000010110000000 +0000101010110101 0000000001100000001000000000000000010110000000 +0000101010111010 0000010001000000001000000000000000010110000000 +0000101010111111 0000000100000000001000000000000000010110000000 +0000101000110000 0000000000001000001000000000000000000110000000 +0000101000110101 0000000001100000001000000000000000000110000000 +0000101000111010 0000010001000000001000000000000000000110000000 +0000101000111111 0000000100000000001000000000000000000110000000 +0000101011110000 0000000000001000001000000000000000011110000000 +0000101011110101 0000000001100000001000000000000000011110000000 +0000101011111010 0000010001000000001000000000000000011110000000 +0000101011111111 0000000100000000001000000000000000011110000000 +0000101001100100 0000000001101000001000000000000000001100000000 +0000101001101000 0000010001001000001000000000000000001100000000 +0000101001101100 0000000100001000001000000000000000001100000000 +0000101001100001 0000000001101000001000000000000000001100000000 +0000101001101001 0000010001100000001000000000000000001100000000 +0000101001101101 0000000101100000001000000000000000001100000000 +0000101001100010 0000010001001000001000000000000000001100000000 +0000101001100110 0000010001100000001000000000000000001100000000 +0000101001101110 0000010101000000001000000000000000001100000000 +0000101001100011 0000000100001000001000000000000000001100000000 +0000101001100111 0000000101100000001000000000000000001100000000 +0000101001101011 0000010101000000001000000000000000001100000000 +0000101010100100 0000000001101000001000000000000000010100000000 +0000101010101000 0000010001001000001000000000000000010100000000 +0000101010101100 0000000100001000001000000000000000010100000000 +0000101010100001 0000000001101000001000000000000000010100000000 +0000101010101001 0000010001100000001000000000000000010100000000 +0000101010101101 0000000101100000001000000000000000010100000000 +0000101010100010 0000010001001000001000000000000000010100000000 +0000101010100110 0000010001100000001000000000000000010100000000 +0000101010101110 0000010101000000001000000000000000010100000000 +0000101010100011 0000000100001000001000000000000000010100000000 +0000101010100111 0000000101100000001000000000000000010100000000 +0000101010101011 0000010101000000001000000000000000010100000000 +0000101000100100 0000000001101000001000000000000000000100000000 +0000101000101000 0000010001001000001000000000000000000100000000 +0000101000101100 0000000100001000001000000000000000000100000000 +0000101000100001 0000000001101000001000000000000000000100000000 +0000101000101001 0000010001100000001000000000000000000100000000 +0000101000101101 0000000101100000001000000000000000000100000000 +0000101000100010 0000010001001000001000000000000000000100000000 +0000101000100110 0000010001100000001000000000000000000100000000 +0000101000101110 0000010101000000001000000000000000000100000000 +0000101000100011 0000000100001000001000000000000000000100000000 +0000101000100111 0000000101100000001000000000000000000100000000 +0000101000101011 0000010101000000001000000000000000000100000000 +0000101011100100 0000000001101000001000000000000000011100000000 +0000101011101000 0000010001001000001000000000000000011100000000 +0000101011101100 0000000100001000001000000000000000011100000000 +0000101011100001 0000000001101000001000000000000000011100000000 +0000101011101001 0000010001100000001000000000000000011100000000 +0000101011101101 0000000101100000001000000000000000011100000000 +0000101011100010 0000010001001000001000000000000000011100000000 +0000101011100110 0000010001100000001000000000000000011100000000 +0000101011101110 0000010101000000001000000000000000011100000000 +0000101011100011 0000000100001000001000000000000000011100000000 +0000101011100111 0000000101100000001000000000000000011100000000 +0000101011101011 0000010101000000001000000000000000011100000000 +0000101001010100 0000000001101000001000000000000000001010000000 +0000101001011000 0000010001001000001000000000000000001010000000 +0000101001011100 0000000100001000001000000000000000001010000000 +0000101001010001 0000000001101000001000000000000000001010000000 +0000101001011001 0000010001100000001000000000000000001010000000 +0000101001011101 0000000101100000001000000000000000001010000000 +0000101001010010 0000010001001000001000000000000000001010000000 +0000101001010110 0000010001100000001000000000000000001010000000 +0000101001011110 0000010101000000001000000000000000001010000000 +0000101001010011 0000000100001000001000000000000000001010000000 +0000101001010111 0000000101100000001000000000000000001010000000 +0000101001011011 0000010101000000001000000000000000001010000000 +0000101010010100 0000000001101000001000000000000000010010000000 +0000101010011000 0000010001001000001000000000000000010010000000 +0000101010011100 0000000100001000001000000000000000010010000000 +0000101010010001 0000000001101000001000000000000000010010000000 +0000101010011001 0000010001100000001000000000000000010010000000 +0000101010011101 0000000101100000001000000000000000010010000000 +0000101010010010 0000010001001000001000000000000000010010000000 +0000101010010110 0000010001100000001000000000000000010010000000 +0000101010011110 0000010101000000001000000000000000010010000000 +0000101010010011 0000000100001000001000000000000000010010000000 +0000101010010111 0000000101100000001000000000000000010010000000 +0000101010011011 0000010101000000001000000000000000010010000000 +0000101000010100 0000000001101000001000000000000000000010000000 +0000101000011000 0000010001001000001000000000000000000010000000 +0000101000011100 0000000100001000001000000000000000000010000000 +0000101000010001 0000000001101000001000000000000000000010000000 +0000101000011001 0000010001100000001000000000000000000010000000 +0000101000011101 0000000101100000001000000000000000000010000000 +0000101000010010 0000010001001000001000000000000000000010000000 +0000101000010110 0000010001100000001000000000000000000010000000 +0000101000011110 0000010101000000001000000000000000000010000000 +0000101000010011 0000000100001000001000000000000000000010000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000000000000110000000000001 +110001110000---- 0000000000000000000000000000000000000000010000 +0000101000010111 0000000101100000001000000000000000000010000000 +0000101000011011 0000010101000000001000000000000000000010000000 +0000101011010100 0000000001101000001000000000000000011010000000 +0000101011011000 0000010001001000001000000000000000011010000000 +0000101011011100 0000000100001000001000000000000000011010000000 +0000101011010001 0000000001101000001000000000000000011010000000 +0000101011011001 0000010001100000001000000000000000011010000000 +0000101011011101 0000000101100000001000000000000000011010000000 +0000101011010010 0000010001001000001000000000000000011010000000 +0000101011010110 0000010001100000001000000000000000011010000000 +0000101011011110 0000010101000000001000000000000000011010000000 +0000101011010011 0000000100001000001000000000000000011010000000 +0000101011010111 0000000101100000001000000000000000011010000000 +0000101011011011 0000010101000000001000000000000000011010000000 +0000101001000100 0000000001101000001000000000000000001000000000 +0000101001001000 0000010001001000001000000000000000001000000000 +0000101001001100 0000000100001000001000000000000000001000000000 +0000101001000001 0000000001101000001000000000000000001000000000 +0000101001001001 0000010001100000001000000000000000001000000000 +0000101001001101 0000000101100000001000000000000000001000000000 +0000101001000010 0000010001001000001000000000000000001000000000 +0000101001000110 0000010001100000001000000000000000001000000000 +0000101001001110 0000010101000000001000000000000000001000000000 +0000101001000011 0000000100001000001000000000000000001000000000 +0000101001000111 0000000101100000001000000000000000001000000000 +0000101001001011 0000010101000000001000000000000000001000000000 +0000101010000100 0000000001101000001000000000000000010000000000 +0000101010001000 0000010001001000001000000000000000010000000000 +0000101010001100 0000000100001000001000000000000000010000000000 +0000101010000001 0000000001101000001000000000000000010000000000 +0000101010001001 0000010001100000001000000000000000010000000000 +0000101010001101 0000000101100000001000000000000000010000000000 +0000101010000010 0000010001001000001000000000000000010000000000 +0000101010000110 0000010001100000001000000000000000010000000000 +0000101010001110 0000010101000000001000000000000000010000000000 +0000101010000011 0000000100001000001000000000000000010000000000 +0000101010000111 0000000101100000001000000000000000010000000000 +0000101010001011 0000010101000000001000000000000000010000000000 +0000101000000100 0000000001101000001000000000000000000000000000 +0000101000001000 0000010001001000001000000000000000000000000000 +0000101000001100 0000000100001000001000000000000000000000000000 +0000101000000001 0000000001101000001000000000000000000000000000 +0000101000001001 0000010001100000001000000000000000000000000000 +0000101000001101 0000000101100000001000000000000000000000000000 +0000101000000010 0000010001001000001000000000000000000000000000 +0000101000000110 0000010001100000001000000000000000000000000000 +0000101000001110 0000010101000000001000000000000000000000000000 +0000101000000011 0000000100001000001000000000000000000000000000 +0000101000000111 0000000101100000001000000000000000000000000000 +0000101000001011 0000010101000000001000000000000000000000000000 +0000101011000100 0000000001101000001000000000000000011000000000 +0000101011001000 0000010001001000001000000000000000011000000000 +0000101011001100 0000000100001000001000000000000000011000000000 +0000101011000001 0000000001101000001000000000000000011000000000 +0000101011001001 0000010001100000001000000000000000011000000000 +0000101011001101 0000000101100000001000000000000000011000000000 +0000101011000010 0000010001001000001000000000000000011000000000 +0000101011000110 0000010001100000001000000000000000011000000000 +0000101011001110 0000010101000000001000000000000000011000000000 +0000101011000011 0000000100001000001000000000000000011000000000 +0000101011000111 0000000101100000001000000000000000011000000000 +0000101011001011 0000010101000000001000000000000000011000000000 +0000101001110100 0000000001101000001000000000000000001110000000 +0000101001111000 0000010001001000001000000000000000001110000000 +0000101001111100 0000000100001000001000000000000000001110000000 +0000101001110001 0000000001101000001000000000000000001110000000 +0000101001111001 0000010001100000001000000000000000001110000000 +0000101001111101 0000000101100000001000000000000000001110000000 +0000101001110010 0000010001001000001000000000000000001110000000 +0000101001110110 0000010001100000001000000000000000001110000000 +0000101001111110 0000010101000000001000000000000000001110000000 +0000101001110011 0000000100001000001000000000000000001110000000 +0000101001110111 0000000101100000001000000000000000001110000000 +0000101001111011 0000010101000000001000000000000000001110000000 +0000101010110100 0000000001101000001000000000000000010110000000 +0000101010111000 0000010001001000001000000000000000010110000000 +0000101010111100 0000000100001000001000000000000000010110000000 +0000101010110001 0000000001101000001000000000000000010110000000 +0000101010111001 0000010001100000001000000000000000010110000000 +0000101010111101 0000000101100000001000000000000000010110000000 +0000101010110010 0000010001001000001000000000000000010110000000 +0000101010110110 0000010001100000001000000000000000010110000000 +0000101010111110 0000010101000000001000000000000000010110000000 +0000101010110011 0000000100001000001000000000000000010110000000 +0000101010110111 0000000101100000001000000000000000010110000000 +0000101010111011 0000010101000000001000000000000000010110000000 +0000101000110100 0000000001101000001000000000000000000110000000 +0000101000111000 0000010001001000001000000000000000000110000000 +0000101000111100 0000000100001000001000000000000000000110000000 +0000101000110001 0000000001101000001000000000000000000110000000 +0000101000111001 0000010001100000001000000000000000000110000000 +0000101000111101 0000000101100000001000000000000000000110000000 +0000101000110010 0000010001001000001000000000000000000110000000 +0000101000110110 0000010001100000001000000000000000000110000000 +0000101000111110 0000010101000000001000000000000000000110000000 +0000101000110011 0000000100001000001000000000000000000110000000 +0000101000110111 0000000101100000001000000000000000000110000000 +0000101000111011 0000010101000000001000000000000000000110000000 +0000101011110100 0000000001101000001000000000000000011110000000 +0000101011111000 0000010001001000001000000000000000011110000000 +0000101011111100 0000000100001000001000000000000000011110000000 +0000101011110001 0000000001101000001000000000000000011110000000 +0000101011111001 0000010001100000001000000000000000011110000000 +0000101011111101 0000000101100000001000000000000000011110000000 +0000101011110010 0000010001001000001000000000000000011110000000 +0000101011110110 0000010001100000001000000000000000011110000000 +0000101011111110 0000010101000000001000000000000000011110000000 +0000101011110011 0000000100001000001000000000000000011110000000 +0000101011110111 0000000101100000001000000000000000011110000000 +0000101011111011 0000010101000000001000000000000000011110000000 +0000100101100000 0000000000001000010000000000000000001100000000 +0000100101100101 0000000001100000010000000000000000001100000000 +0000100101101010 0000010001000000010000000000000000001100000000 +0000100101101111 0000000100000000010000000000000000001100000000 +0000100110100000 0000000000001000010000000000000000010100000000 +0000100110100101 0000000001100000010000000000000000010100000000 +0000100110101010 0000010001000000010000000000000000010100000000 +0000100110101111 0000000100000000010000000000000000010100000000 +0000100100100000 0000000000001000010000000000000000000100000000 +0000100100100101 0000000001100000010000000000000000000100000000 +0000100100101010 0000010001000000010000000000000000000100000000 +0000100100101111 0000000100000000010000000000000000000100000000 +0000100111100000 0000000000001000010000000000000000011100000000 +0000100111100101 0000000001100000010000000000000000011100000000 +0000100111101010 0000010001000000010000000000000000011100000000 +0000100111101111 0000000100000000010000000000000000011100000000 +0000100101010000 0000000000001000010000000000000000001010000000 +0000100101010101 0000000001100000010000000000000000001010000000 +0000100101011010 0000010001000000010000000000000000001010000000 +0000100101011111 0000000100000000010000000000000000001010000000 +0000100110010000 0000000000001000010000000000000000010010000000 +0000100110010101 0000000001100000010000000000000000010010000000 +0000100110011010 0000010001000000010000000000000000010010000000 +0000100110011111 0000000100000000010000000000000000010010000000 +0000100100010000 0000000000001000010000000000000000000010000000 +0000100100010101 0000000001100000010000000000000000000010000000 +0000100100011010 0000010001000000010000000000000000000010000000 +0000100100011111 0000000100000000010000000000000000000010000000 +0000100111010000 0000000000001000010000000000000000011010000000 +0000100111010101 0000000001100000010000000000000000011010000000 +0000100111011010 0000010001000000010000000000000000011010000000 +0000100111011111 0000000100000000010000000000000000011010000000 +0000100101000000 0000000000001000010000000000000000001000000000 +0000100101000101 0000000001100000010000000000000000001000000000 +0000100101001010 0000010001000000010000000000000000001000000000 +0000100101001111 0000000100000000010000000000000000001000000000 +0000100110000000 0000000000001000010000000000000000010000000000 +0000100110000101 0000000001100000010000000000000000010000000000 +0000100110001010 0000010001000000010000000000000000010000000000 +0000100110001111 0000000100000000010000000000000000010000000000 +0000100100000000 0000000000001000010000000000000000000000000000 +0000100100000101 0000000001100000010000000000000000000000000000 +0000100100001010 0000010001000000010000000000000000000000000000 +0000100100001111 0000000100000000010000000000000000000000000000 +0000100111000000 0000000000001000010000000000000000011000000000 +0000100111000101 0000000001100000010000000000000000011000000000 +0000100111001010 0000010001000000010000000000000000011000000000 +0000100111001111 0000000100000000010000000000000000011000000000 +0000100101110000 0000000000001000010000000000000000001110000000 +0000100101110101 0000000001100000010000000000000000001110000000 +0000100101111010 0000010001000000010000000000000000001110000000 +0000100101111111 0000000100000000010000000000000000001110000000 +0000100110110000 0000000000001000010000000000000000010110000000 +0000100110110101 0000000001100000010000000000000000010110000000 +0000100110111010 0000010001000000010000000000000000010110000000 +0000100110111111 0000000100000000010000000000000000010110000000 +0000100100110000 0000000000001000010000000000000000000110000000 +0000100100110101 0000000001100000010000000000000000000110000000 +0000100100111010 0000010001000000010000000000000000000110000000 +0000100100111111 0000000100000000010000000000000000000110000000 +0000100111110000 0000000000001000010000000000000000011110000000 +0000100111110101 0000000001100000010000000000000000011110000000 +0000100111111010 0000010001000000010000000000000000011110000000 +0000100111111111 0000000100000000010000000000000000011110000000 +0000100101100100 0000000001101000010000000000000000001100000000 +0000100101101000 0000010001001000010000000000000000001100000000 +0000100101101100 0000000100001000010000000000000000001100000000 +0000100101100001 0000000001101000010000000000000000001100000000 +0000100101101001 0000010001100000010000000000000000001100000000 +0000100101101101 0000000101100000010000000000000000001100000000 +0000100101100010 0000010001001000010000000000000000001100000000 +0000100101100110 0000010001100000010000000000000000001100000000 +0000100101101110 0000010101000000010000000000000000001100000000 +0000100101100011 0000000100001000010000000000000000001100000000 +0000100101100111 0000000101100000010000000000000000001100000000 +0000100101101011 0000010101000000010000000000000000001100000000 +0000100110100100 0000000001101000010000000000000000010100000000 +0000100110101000 0000010001001000010000000000000000010100000000 +0000100110101100 0000000100001000010000000000000000010100000000 +0000100110100001 0000000001101000010000000000000000010100000000 +0000100110101001 0000010001100000010000000000000000010100000000 +0000100110101101 0000000101100000010000000000000000010100000000 +0000100110100010 0000010001001000010000000000000000010100000000 +0000100110100110 0000010001100000010000000000000000010100000000 +0000100110101110 0000010101000000010000000000000000010100000000 +0000100110100011 0000000100001000010000000000000000010100000000 +0000100110100111 0000000101100000010000000000000000010100000000 +0000100110101011 0000010101000000010000000000000000010100000000 +0000100100100100 0000000001101000010000000000000000000100000000 +0000100100101000 0000010001001000010000000000000000000100000000 +0000100100101100 0000000100001000010000000000000000000100000000 +0000100100100001 0000000001101000010000000000000000000100000000 +0000100100101001 0000010001100000010000000000000000000100000000 +0000100100101101 0000000101100000010000000000000000000100000000 +0000100100100010 0000010001001000010000000000000000000100000000 +0000100100100110 0000010001100000010000000000000000000100000000 +0000100100101110 0000010101000000010000000000000000000100000000 +0000100100100011 0000000100001000010000000000000000000100000000 +0000100100100111 0000000101100000010000000000000000000100000000 +0000100100101011 0000010101000000010000000000000000000100000000 +0000100111100100 0000000001101000010000000000000000011100000000 +0000100111101000 0000010001001000010000000000000000011100000000 +0000100111101100 0000000100001000010000000000000000011100000000 +0000100111100001 0000000001101000010000000000000000011100000000 +0000100111101001 0000010001100000010000000000000000011100000000 +0000100111101101 0000000101100000010000000000000000011100000000 +0000100111100010 0000010001001000010000000000000000011100000000 +0000100111100110 0000010001100000010000000000000000011100000000 +0000100111101110 0000010101000000010000000000000000011100000000 +0000100111100011 0000000100001000010000000000000000011100000000 +0000100111100111 0000000101100000010000000000000000011100000000 +0000100111101011 0000010101000000010000000000000000011100000000 +0000100101010100 0000000001101000010000000000000000001010000000 +0000100101011000 0000010001001000010000000000000000001010000000 +0000100101011100 0000000100001000010000000000000000001010000000 +0000100101010001 0000000001101000010000000000000000001010000000 +0000100101011001 0000010001100000010000000000000000001010000000 +0000100101011101 0000000101100000010000000000000000001010000000 +0000100101010010 0000010001001000010000000000000000001010000000 +0000100101010110 0000010001100000010000000000000000001010000000 +0000100101011110 0000010101000000010000000000000000001010000000 +0000100101010011 0000000100001000010000000000000000001010000000 +0000100101010111 0000000101100000010000000000000000001010000000 +0000100101011011 0000010101000000010000000000000000001010000000 +0000100110010100 0000000001101000010000000000000000010010000000 +0000100110011000 0000010001001000010000000000000000010010000000 +0000100110011100 0000000100001000010000000000000000010010000000 +0000100110010001 0000000001101000010000000000000000010010000000 +0000100110011001 0000010001100000010000000000000000010010000000 +0000100110011101 0000000101100000010000000000000000010010000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000000000000110000000000001 +110001110000---- 0000000000000000000000000000000000000000010000 +0000100110010010 0000010001001000010000000000000000010010000000 +0000100110010110 0000010001100000010000000000000000010010000000 +0000100110011110 0000010101000000010000000000000000010010000000 +0000100110010011 0000000100001000010000000000000000010010000000 +0000100110010111 0000000101100000010000000000000000010010000000 +0000100110011011 0000010101000000010000000000000000010010000000 +0000100100010100 0000000001101000010000000000000000000010000000 +0000100100011000 0000010001001000010000000000000000000010000000 +0000100100011100 0000000100001000010000000000000000000010000000 +0000100100010001 0000000001101000010000000000000000000010000000 +0000100100011001 0000010001100000010000000000000000000010000000 +0000100100011101 0000000101100000010000000000000000000010000000 +0000100100010010 0000010001001000010000000000000000000010000000 +0000100100010110 0000010001100000010000000000000000000010000000 +0000100100011110 0000010101000000010000000000000000000010000000 +0000100100010011 0000000100001000010000000000000000000010000000 +0000100100010111 0000000101100000010000000000000000000010000000 +0000100100011011 0000010101000000010000000000000000000010000000 +0000100111010100 0000000001101000010000000000000000011010000000 +0000100111011000 0000010001001000010000000000000000011010000000 +0000100111011100 0000000100001000010000000000000000011010000000 +0000100111010001 0000000001101000010000000000000000011010000000 +0000100111011001 0000010001100000010000000000000000011010000000 +0000100111011101 0000000101100000010000000000000000011010000000 +0000100111010010 0000010001001000010000000000000000011010000000 +0000100111010110 0000010001100000010000000000000000011010000000 +0000100111011110 0000010101000000010000000000000000011010000000 +0000100111010011 0000000100001000010000000000000000011010000000 +0000100111010111 0000000101100000010000000000000000011010000000 +0000100111011011 0000010101000000010000000000000000011010000000 +0000100101000100 0000000001101000010000000000000000001000000000 +0000100101001000 0000010001001000010000000000000000001000000000 +0000100101001100 0000000100001000010000000000000000001000000000 +0000100101000001 0000000001101000010000000000000000001000000000 +0000100101001001 0000010001100000010000000000000000001000000000 +0000100101001101 0000000101100000010000000000000000001000000000 +0000100101000010 0000010001001000010000000000000000001000000000 +0000100101000110 0000010001100000010000000000000000001000000000 +0000100101001110 0000010101000000010000000000000000001000000000 +0000100101000011 0000000100001000010000000000000000001000000000 +0000100101000111 0000000101100000010000000000000000001000000000 +0000100101001011 0000010101000000010000000000000000001000000000 +0000100110000100 0000000001101000010000000000000000010000000000 +0000100110001000 0000010001001000010000000000000000010000000000 +0000100110001100 0000000100001000010000000000000000010000000000 +0000100110000001 0000000001101000010000000000000000010000000000 +0000100110001001 0000010001100000010000000000000000010000000000 +0000100110001101 0000000101100000010000000000000000010000000000 +0000100110000010 0000010001001000010000000000000000010000000000 +0000100110000110 0000010001100000010000000000000000010000000000 +0000100110001110 0000010101000000010000000000000000010000000000 +0000100110000011 0000000100001000010000000000000000010000000000 +0000100110000111 0000000101100000010000000000000000010000000000 +0000100110001011 0000010101000000010000000000000000010000000000 +0000100100000100 0000000001101000010000000000000000000000000000 +0000100100001000 0000010001001000010000000000000000000000000000 +0000100100001100 0000000100001000010000000000000000000000000000 +0000100100000001 0000000001101000010000000000000000000000000000 +0000100100001001 0000010001100000010000000000000000000000000000 +0000100100001101 0000000101100000010000000000000000000000000000 +0000100100000010 0000010001001000010000000000000000000000000000 +0000100100000110 0000010001100000010000000000000000000000000000 +0000100100001110 0000010101000000010000000000000000000000000000 +0000100100000011 0000000100001000010000000000000000000000000000 +0000100100000111 0000000101100000010000000000000000000000000000 +0000100100001011 0000010101000000010000000000000000000000000000 +0000100111000100 0000000001101000010000000000000000011000000000 +0000100111001000 0000010001001000010000000000000000011000000000 +0000100111001100 0000000100001000010000000000000000011000000000 +0000100111000001 0000000001101000010000000000000000011000000000 +0000100111001001 0000010001100000010000000000000000011000000000 +0000100111001101 0000000101100000010000000000000000011000000000 +0000100111000010 0000010001001000010000000000000000011000000000 +0000100111000110 0000010001100000010000000000000000011000000000 +0000100111001110 0000010101000000010000000000000000011000000000 +0000100111000011 0000000100001000010000000000000000011000000000 +0000100111000111 0000000101100000010000000000000000011000000000 +0000100111001011 0000010101000000010000000000000000011000000000 +0000100101110100 0000000001101000010000000000000000001110000000 +0000100101111000 0000010001001000010000000000000000001110000000 +0000100101111100 0000000100001000010000000000000000001110000000 +0000100101110001 0000000001101000010000000000000000001110000000 +0000100101111001 0000010001100000010000000000000000001110000000 +0000100101111101 0000000101100000010000000000000000001110000000 +0000100101110010 0000010001001000010000000000000000001110000000 +0000100101110110 0000010001100000010000000000000000001110000000 +0000100101111110 0000010101000000010000000000000000001110000000 +0000100101110011 0000000100001000010000000000000000001110000000 +0000100101110111 0000000101100000010000000000000000001110000000 +0000100101111011 0000010101000000010000000000000000001110000000 +0000100110110100 0000000001101000010000000000000000010110000000 +0000100110111000 0000010001001000010000000000000000010110000000 +0000100110111100 0000000100001000010000000000000000010110000000 +0000100110110001 0000000001101000010000000000000000010110000000 +0000100110111001 0000010001100000010000000000000000010110000000 +0000100110111101 0000000101100000010000000000000000010110000000 +0000100110110010 0000010001001000010000000000000000010110000000 +0000100110110110 0000010001100000010000000000000000010110000000 +0000100110111110 0000010101000000010000000000000000010110000000 +0000100110110011 0000000100001000010000000000000000010110000000 +0000100110110111 0000000101100000010000000000000000010110000000 +0000100110111011 0000010101000000010000000000000000010110000000 +0000100100110100 0000000001101000010000000000000000000110000000 +0000100100111000 0000010001001000010000000000000000000110000000 +0000100100111100 0000000100001000010000000000000000000110000000 +0000100100110001 0000000001101000010000000000000000000110000000 +0000100100111001 0000010001100000010000000000000000000110000000 +0000100100111101 0000000101100000010000000000000000000110000000 +0000100100110010 0000010001001000010000000000000000000110000000 +0000100100110110 0000010001100000010000000000000000000110000000 +0000100100111110 0000010101000000010000000000000000000110000000 +0000100100110011 0000000100001000010000000000000000000110000000 +0000100100110111 0000000101100000010000000000000000000110000000 +0000100100111011 0000010101000000010000000000000000000110000000 +0000100111110100 0000000001101000010000000000000000011110000000 +0000100111111000 0000010001001000010000000000000000011110000000 +0000100111111100 0000000100001000010000000000000000011110000000 +0000100111110001 0000000001101000010000000000000000011110000000 +0000100111111001 0000010001100000010000000000000000011110000000 +0000100111111101 0000000101100000010000000000000000011110000000 +0000100111110010 0000010001001000010000000000000000011110000000 +0000100111110110 0000010001100000010000000000000000011110000000 +0000100111111110 0000010101000000010000000000000000011110000000 +0000100111110011 0000000100001000010000000000000000011110000000 +0000100111110111 0000000101100000010000000000000000011110000000 +0000100111111011 0000010101000000010000000000000000011110000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +1001------------ 1100000000000000000000000000000000000000000000 +0001------------ -0------1------------------------------------- +0010------------ -1------0------------------------------------- +0011------------ -1------1------------------------------------- +011------------- -1------0------------------------------------- diff --git a/espresso/examples/indust/sqn b/espresso/examples/indust/sqn new file mode 100644 index 0000000..36f644e --- /dev/null +++ b/espresso/examples/indust/sqn @@ -0,0 +1,98 @@ +.i 7 +.o 3 +0001100 010 +0001101 000 +0001110 000 +0001111 000 +0001000 011 +0001001 001 +0001010 000 +0001011 000 +0011100 100 +0011101 000 +0011110 000 +0011111 001 +0000100 101 +0000101 000 +0000110 001 +0000111 001 +0011000 110 +0011001 001 +0011010 001 +0011011 000 +0010100 111 +0010101 001 +0010110 001 +0010111 001 +0101100 010 +0101101 000 +0101110 010 +0101111 010 +0101000 011 +0101001 001 +0101010 010 +0101011 010 +0111100 010 +0111101 100 +0111110 010 +0111111 011 +0100000 010 +0100001 101 +0100010 011 +0100011 011 +0111000 011 +0111001 110 +0111010 011 +0111011 010 +0110000 011 +0110001 111 +0110010 011 +0110011 011 +1001100 100 +1001101 100 +1001110 000 +1001111 100 +1000100 101 +1000101 100 +1000110 001 +1000111 100 +1011100 100 +1011101 100 +1011110 010 +1011111 101 +1000000 100 +1000001 101 +1000010 011 +1000011 101 +1010100 101 +1010101 101 +1010110 110 +1010111 100 +1010000 101 +1010001 101 +1010010 111 +1010011 101 +1101000 110 +1101001 110 +1101010 110 +1101011 000 +1100100 111 +1100101 110 +1100110 110 +1100111 001 +1111000 110 +1111001 110 +1111010 111 +1111011 010 +1100000 110 +1100001 111 +1100010 111 +1100011 011 +1110100 111 +1110101 111 +1110110 110 +1110111 100 +1110000 111 +1110001 111 +1110010 111 +1110011 101 diff --git a/espresso/examples/indust/t1 b/espresso/examples/indust/t1 new file mode 100644 index 0000000..bc1c8bf --- /dev/null +++ b/espresso/examples/indust/t1 @@ -0,0 +1,867 @@ +.i 21 +.o 23 +001------------000000 00000010000000000000000 +0--1-----------000000 00000010000000000000000 +0--------------000000 00000001111000000000000 +1--------------000000 00000001111000000000000 +0--------------000000 00000000000100000000000 +1--------------000000 00000000000100000000000 +0--------------000000 00000100000000000000000 +1--------------000000 00000000000000000000000 +001------------000001 00000010000000000000000 +0--1-----------000001 00000010000000000000000 +0--------------000001 00000001111000000000000 +1--------------000001 00000001111000000000000 +0--------------000001 00000000000100000000000 +1--------------000001 00000000000100000000000 +0---0----------000001 00001000000000000000000 +0---1----------000001 00000100000000000000000 +1--------------000001 00000000000000000000000 +001------------000010 00000010000000000000000 +0--1-----------000010 00000010000000000000000 +0--------------000010 00000001111000000000000 +1--------------000010 00000001111000000000000 +0--------------000010 00000000000011110000000 +1--------------000010 00000000000011110000000 +-----0---------000010 00000000000000001000000 +-----1---------000010 00000000000000000100000 +0--------------000010 00000000000100000000000 +1--------------000010 00000000000100000000000 +0---0----------000010 00001100000000000000000 +0---1----------000010 00001000000000000000000 +1--------------000010 00000000000000000000000 +001------------000011 00000010000000000000000 +0--1-----------000011 00000010000000000000000 +0--------------000011 00000001111000000000000 +1--------------000011 00000001111000000000000 +0--------------000011 00000000000011110000000 +1--------------000011 00000000000011110000000 +-----0---------000011 00000000000000001000000 +-----1---------000011 00000000000000000100000 +0--------------000011 00000000000100000000000 +1--------------000011 00000000000100000000000 +0---0----------000011 00010000000000000000000 +0---1----------000011 00001100000000000000000 +1--------------000011 00000000000000000000000 +001------------000100 00000010000000000000000 +0--1-----------000100 00000010000000000000000 +0--------------000100 00000001111000000000000 +1--------------000100 00000001111000000000000 +0--------------000100 00000000000011110000000 +1--------------000100 00000000000011110000000 +-----0---------000100 00000000000000001000000 +-----1---------000100 00000000000000000100000 +0--------------000100 00000000000100000000000 +1--------------000100 00000000000100000000000 +0---0----------000100 00010100000000000000000 +0---1----------000100 00010000000000000000000 +1--------------000100 00000000000000000000000 +001------------000101 00000010000000000000000 +0--1-----------000101 00000010000000000000000 +0--------------000101 00000000000011110000000 +1--------------000101 00000000000011110000000 +-----0---------000101 00000000000000001000000 +-----1---------000101 00000000000000000100000 +0---0----------000101 00011000000000000000000 +0---1----------000101 00010100000000000000000 +1--------------000101 00000000000000000000000 +011------------000110 00000010000000000000000 +001------------000110 00000010000000000000000 +0--1-----------000110 00000010000000000000000 +0--------------000110 00000000000000000010000 +1--------------000110 00000000000000000010000 +0--------------000110 00000000000011110000000 +1--------------000110 00000000000011110000000 +-----0---------000110 00000000000000001000000 +-----1---------000110 00000000000000000100000 +0--------------000110 00000000000100000000000 +1--------------000110 00000000000100000000000 +0---0----------000110 00011100000000000000000 +0---1----------000110 00011000000000000000000 +1--------------000110 00000000000000000000000 +001------------000111 00000010000000000000000 +0--1-----------000111 00000010000000000000000 +0--------------000111 00000000000000000010000 +1--------------000111 00000000000000000010000 +0--------------000111 00000000000011110000000 +1--------------000111 00000000000011110000000 +-----0---------000111 00000000000000001000000 +-----1---------000111 00000000000000000100000 +0--------------000111 00000000000100000000000 +1--------------000111 00000000000100000000000 +0--00----------000111 00100000000000000000000 +0--10-0--------000111 01000000000000000000000 +0--10-10-------000111 11100000000000000000000 +0--10-11-------000111 10100000000000000000000 +0---1----------000111 00011100000000000000000 +1--------------000111 00000000000000000000000 +001------------001000 00000010000000000000000 +0--1-----------001000 00000010000000000000000 +0--------------001000 00000000000000000010000 +1--------------001000 00000000000000000010000 +0--------------001000 00000000000100000000000 +1--------------001000 00000000000100000000000 +0---0----------001000 00100100000000000000000 +1--------------001000 00000000000000000000000 +0---1----------001000 00100000000000000000000 +0--1-----------010000 00000010000000000000000 +0--------------010000 00000000000000000010000 +1--------------010000 00000000000000000010000 +--------00-----010000 00000001000000000000000 +--------01-----010000 00000000100000000000000 +--------10-----010000 00000000010000000000000 +--------11-----010000 00000000001000000000000 +0--------------010000 00000000000100000000000 +1--------------010000 00000000000100000000000 +0---0----------010000 01000100000000000000000 +1--------------010000 00000000000000000000000 +0---1----------010000 01000000000000000000000 +0--1-----------111000 00000010000000000000000 +0--------------111000 00000000000000000010000 +1--------------111000 00000000000000000010000 +---------0---1-111000 00000001111000000000000 +--------00-----111000 00000001000000000000000 +--------01-----111000 00000000100000000000000 +--------10-----111000 00000000010000000000000 +--------11-----111000 00000000001000000000000 +0--------------111000 00000000000000000000100 +1--------------111000 00000000000000000000100 +0--------------111000 00000000000100000000000 +1--------------111000 00000000000100000000000 +0---0----------111000 11100100000000000000000 +1--------------111000 00000000000000000000000 +0---1----------111000 11100000000000000000000 +0--1-----------101000 00000010000000000000000 +0--------------101000 00000000000000000010000 +1--------------101000 00000000000000000010000 +--------00-----101000 00000001000000000000000 +--------01-----101000 00000000100000000000000 +--------10-----101000 00000000010000000000000 +--------11-----101000 00000000001000000000000 +0--------------101000 00000000000100000000000 +1--------------101000 00000000000100000000000 +0---0----------101000 10100100000000000000000 +1--------------101000 00000000000000000000000 +0---1----------101000 10100000000000000000000 +001------------001001 00000010000000000000000 +0--1-----------001001 00000010000000000000000 +0--------------001001 00000000000000000010000 +1--------------001001 00000000000000000010000 +0--------------001001 00000000000100000000000 +1--------------001001 00000000000100000000000 +0---0----------001001 00101000000000000000000 +1--------------001001 00000000000000000000000 +0---1----------001001 00100100000000000000000 +001------------001010 00000010000000000000000 +0--1-----------001010 00000010000000000000000 +0--------------001010 00000000000000000010000 +1--------------001010 00000000000000000010000 +0--------------001010 00000000000100000000000 +1--------------001010 00000000000100000000000 +0---0----------001010 00101100000000000000000 +1--------------001010 00000000000000000000000 +0---1----------001010 00101000000000000000000 +001------------001011 00000010000000000000000 +0--1-----------001011 00000010000000000000000 +0--------------001011 00000000000000000010000 +1--------------001011 00000000000000000010000 +0--------------001011 00000000000100000000000 +1--------------001011 00000000000100000000000 +0---0----------001011 00110000000000000000000 +1--------------001011 00000000000000000000000 +0---1----------001011 00101100000000000000000 +001------------001100 00000010000000000000000 +0--1-----------001100 00000010000000000000000 +0--------------001100 00000000000000000010000 +1--------------001100 00000000000000000010000 +0--------------001100 00000000000100000000000 +1--------------001100 00000000000100000000000 +0---0----------001100 00110100000000000000000 +1--------------001100 00000000000000000000000 +0---1----------001100 00110000000000000000000 +001------------001101 00000010000000000000000 +0--1-----------001101 00000010000000000000000 +0--------------001101 00000000000000000010000 +1--------------001101 00000000000000000010000 +0--------------001101 00000000000100000000000 +1--------------001101 00000000000100000000000 +0---0----------001101 00111000000000000000000 +1--------------001101 00000000000000000000000 +0---1----------001101 00110100000000000000000 +001------------001110 00000010000000000000000 +0--1-----------001110 00000010000000000000000 +0--------------001110 00000000000100000000000 +1--------------001110 00000000000100000000000 +0---0----------001110 00111100000000000000000 +1--------------001110 00000000000000000000000 +0---1----------001110 00111000000000000000000 +001------------001111 00000010000000000000000 +0--1-----------001111 00000010000000000000000 +0--------------001111 00000000000100000000000 +1--------------001111 00000000000100000000000 +0---0----------001111 00000000000000000000000 +1--------------001111 00000000000000000000000 +0---1----------001111 00111100000000000000000 +0--1-----------010001 00000010000000000000000 +0--------------010001 00000000000000000010000 +1--------------010001 00000000000000000010000 +--------00-----010001 00000001000000000000000 +--------01-----010001 00000000100000000000000 +--------10-----010001 00000000010000000000000 +--------11-----010001 00000000001000000000000 +0--------------010001 00000000000100000000000 +1--------------010001 00000000000100000000000 +0---0----------010001 01001000000000000000000 +1--------------010001 00000000000000000000000 +0---1----------010001 01000100000000000000000 +0--1-----------010010 00000010000000000000000 +0--------------010010 00000000000000000010000 +1--------------010010 00000000000000000010000 +--------00-----010010 00000001000000000000000 +--------01-----010010 00000000100000000000000 +--------10-----010010 00000000010000000000000 +--------11-----010010 00000000001000000000000 +----------00---010010 00000000000010000000000 +----------01---010010 00000000000001000000000 +----------10---010010 00000000000000100000000 +----------11---010010 00000000000000010000000 +0--------------010010 00000000000000000001000 +1--------------010010 00000000000000000001000 +------------0--010010 00000000000000001000000 +------------1--010010 00000000000000000100000 +0--------------010010 00000000000100000000000 +1--------------010010 00000000000100000000000 +0---0----------010010 01001100000000000000000 +1--------------010010 00000000000000000000000 +0---1----------010010 01001000000000000000000 +0--1-----------010011 00000010000000000000000 +0--------------010011 00000000000000000010000 +1--------------010011 00000000000000000010000 +--------00-----010011 00000001000000000000000 +--------01-----010011 00000000100000000000000 +--------10-----010011 00000000010000000000000 +--------11-----010011 00000000001000000000000 +----------00---010011 00000000000010000000000 +----------01---010011 00000000000001000000000 +----------10---010011 00000000000000100000000 +----------11---010011 00000000000000010000000 +------------0--010011 00000000000000001000000 +------------1--010011 00000000000000000100000 +0--------------010011 00000000000000000001000 +1--------------010011 00000000000000000001000 +0--------------010011 00000000000100000000000 +1--------------010011 00000000000100000000000 +0---0----------010011 01010000000000000000000 +1--------------010011 00000000000000000000000 +0---1----------010011 01001100000000000000000 +0--1-----------010100 00000010000000000000000 +0--------------010100 00000000000000000010000 +1--------------010100 00000000000000000010000 +--------00-----010100 00000001000000000000000 +--------01-----010100 00000000100000000000000 +--------10-----010100 00000000010000000000000 +--------11-----010100 00000000001000000000000 +----------00---010100 00000000000010000000000 +----------01---010100 00000000000001000000000 +----------10---010100 00000000000000100000000 +----------11---010100 00000000000000010000000 +------------0--010100 00000000000000001000000 +------------1--010100 00000000000000000100000 +0--------------010100 00000000000000000001000 +1--------------010100 00000000000000000001000 +0--------------010100 00000000000100000000000 +1--------------010100 00000000000100000000000 +0---0----------010100 01010100000000000000000 +1--------------010100 00000000000000000000000 +0---1----------010100 01010000000000000000000 +0--1-----------010101 00000010000000000000000 +0--------------010101 00000000000000000010000 +1--------------010101 00000000000000000010000 +----------00---010101 00000000000010000000000 +----------01---010101 00000000000001000000000 +----------10---010101 00000000000000100000000 +----------11---010101 00000000000000010000000 +------------0--010101 00000000000000001000000 +------------1--010101 00000000000000000100000 +0--------------010101 00000000000000000001000 +1--------------010101 00000000000000000001000 +0--------------010101 00000000000100000000000 +1--------------010101 00000000000100000000000 +0---0----------010101 01011000000000000000000 +1--------------010101 00000000000000000000000 +0---1----------010101 01010100000000000000000 +0--1-----------010110 00000010000000000000000 +----------00---010110 00000000000010000000000 +----------01---010110 00000000000001000000000 +----------10---010110 00000000000000100000000 +----------11---010110 00000000000000010000000 +------------0--010110 00000000000000001000000 +------------1--010110 00000000000000000100000 +0--------------010110 00000000000100000000000 +1--------------010110 00000000000100000000000 +0---0----------010110 01011100000000000000000 +1--------------010110 00000000000000000000000 +0---1----------010110 01011000000000000000000 +----------00---010111 00000000000010000000000 +----------01---010111 00000000000001000000000 +----------10---010111 00000000000000100000000 +----------11---010111 00000000000000010000000 +------------0--010111 00000000000000001000000 +------------1--010111 00000000000000000100000 +0--------------010111 00000000000100000000000 +1--------------010111 00000000000100000000000 +0---0----------010111 00000000000000000000000 +1--------------010111 00000000000000000000000 +0---1----------010111 01011100000000000000000 +0--1-----------111001 00000010000000000000000 +0--------------111001 00000000000000000010000 +1--------------111001 00000000000000000010000 +---------0---1-111001 00000001111000000000000 +--------00-----111001 00000001000000000000000 +--------01-----111001 00000000100000000000000 +--------10-----111001 00000000010000000000000 +--------11-----111001 00000000001000000000000 +0--------------111001 00000000000000000000100 +1--------------111001 00000000000000000000100 +------------0-0111001 00000000000000000000010 +------------1-0111001 00000000000000000000001 +--------------1111001 00000000000000000000010 +--------------1111001 00000000000000000000001 +0--------------111001 00000000000100000000000 +1--------------111001 00000000000100000000000 +0---0----------111001 11101000000000000000000 +1--------------111001 00000000000000000000000 +0---1----------111001 11100100000000000000000 +0--1-----------111010 00000010000000000000000 +0--------------111010 00000000000000000010000 +1--------------111010 00000000000000000010000 +---------0---1-111010 00000001111000000000000 +--------00-----111010 00000001000000000000000 +--------01-----111010 00000000100000000000000 +--------10-----111010 00000000010000000000000 +--------11-----111010 00000000001000000000000 +---------0---1-111010 00000000000011110000000 +----------00---111010 00000000000010000000000 +----------01---111010 00000000000001000000000 +----------10---111010 00000000000000100000000 +----------11---111010 00000000000000010000000 +0--------------111010 00000000000000000000100 +1--------------111010 00000000000000000000100 +------------0-0111010 00000000000000000000010 +------------1-0111010 00000000000000000000001 +--------------1111010 00000000000000000000010 +--------------1111010 00000000000000000000001 +0--------------111010 00000000000100000000000 +1--------------111010 00000000000100000000000 +0---0----------111010 11101100000000000000000 +1--------------111010 00000000000000000000000 +0---1----------111010 11101000000000000000000 +0--1-----------111011 00000010000000000000000 +0--------------111011 00000000000000000010000 +1--------------111011 00000000000000000010000 +---------0---1-111011 00000001111000000000000 +--------00-----111011 00000001000000000000000 +--------01-----111011 00000000100000000000000 +--------10-----111011 00000000010000000000000 +--------11-----111011 00000000001000000000000 +---------0---1-111011 00000000000011110000000 +----------00---111011 00000000000010000000000 +----------01---111011 00000000000001000000000 +----------10---111011 00000000000000100000000 +----------11---111011 00000000000000010000000 +0--------------111011 00000000000000000000100 +1--------------111011 00000000000000000000100 +------------0-0111011 00000000000000000000010 +------------1-0111011 00000000000000000000001 +--------------1111011 00000000000000000000010 +--------------1111011 00000000000000000000001 +0--------------111011 00000000000100000000000 +1--------------111011 00000000000100000000000 +0---0----------111011 11110000000000000000000 +1--------------111011 00000000000000000000000 +0---1----------111011 11101100000000000000000 +0--1-----------111100 00000010000000000000000 +0--------------111100 00000000000000000010000 +1--------------111100 00000000000000000010000 +---------0---1-111100 00000001111000000000000 +--------00-----111100 00000001000000000000000 +--------01-----111100 00000000100000000000000 +--------10-----111100 00000000010000000000000 +--------11-----111100 00000000001000000000000 +---------0---1-111100 00000000000011110000000 +----------00---111100 00000000000010000000000 +----------01---111100 00000000000001000000000 +----------10---111100 00000000000000100000000 +----------11---111100 00000000000000010000000 +0--------------111100 00000000000000000000100 +1--------------111100 00000000000000000000100 +------------0-0111100 00000000000000000000010 +------------1-0111100 00000000000000000000001 +--------------1111100 00000000000000000000010 +--------------1111100 00000000000000000000001 +0--------------111100 00000000000100000000000 +1--------------111100 00000000000100000000000 +0---0----------111100 11110100000000000000000 +1--------------111100 00000000000000000000000 +0---1----------111100 11110000000000000000000 +0--1-----------111101 00000010000000000000000 +0--------------111101 00000000000000000010000 +1--------------111101 00000000000000000010000 +---------0---1-111101 00000000000011110000000 +----------00---111101 00000000000010000000000 +----------01---111101 00000000000001000000000 +----------10---111101 00000000000000100000000 +----------11---111101 00000000000000010000000 +0--------------111101 00000000000000000000100 +1--------------111101 00000000000000000000100 +------------0-0111101 00000000000000000000010 +------------1-0111101 00000000000000000000001 +--------------1111101 00000000000000000000010 +--------------1111101 00000000000000000000001 +0--------------111101 00000000000100000000000 +1--------------111101 00000000000100000000000 +0---0----------111101 11111000000000000000000 +1--------------111101 00000000000000000000000 +0---1----------111101 11110100000000000000000 +0--1-----------111110 00000010000000000000000 +---------0---1-111110 00000000000011110000000 +----------00---111110 00000000000010000000000 +----------01---111110 00000000000001000000000 +----------10---111110 00000000000000100000000 +----------11---111110 00000000000000010000000 +0--------------111110 00000000000100000000000 +1--------------111110 00000000000100000000000 +0--------------111110 00000000000000000000100 +1--------------111110 00000000000000000000100 +------------0-0111110 00000000000000000000010 +------------1-0111110 00000000000000000000001 +--------------1111110 00000000000000000000010 +--------------1111110 00000000000000000000001 +0---0----------111110 11111100000000000000000 +1--------------111110 00000000000000000000000 +0---1----------111110 11111000000000000000000 +---------0---1-111111 00000000000011110000000 +----------00---111111 00000000000010000000000 +----------01---111111 00000000000001000000000 +----------10---111111 00000000000000100000000 +----------11---111111 00000000000000010000000 +0--------------111111 00000000000100000000000 +1--------------111111 00000000000100000000000 +0---0----------111111 00000000000000000000000 +1--------------111111 00000000000000000000000 +0---1----------111111 11111100000000000000000 +0--1-----------101001 00000010000000000000000 +0--------------101001 00000000000000000010000 +1--------------101001 00000000000000000010000 +--------00-----101001 00000001000000000000000 +--------01-----101001 00000000100000000000000 +--------10-----101001 00000000010000000000000 +--------11-----101001 00000000001000000000000 +0--------------101001 00000000000100000000000 +1--------------101001 00000000000100000000000 +0---0----------101001 10101000000000000000000 +1--------------101001 00000000000000000000000 +0---1----------101001 10100100000000000000000 +0--1-----------101010 00000010000000000000000 +0--------------101010 00000000000000000010000 +1--------------101010 00000000000000000010000 +--------00-----101010 00000001000000000000000 +--------01-----101010 00000000100000000000000 +--------10-----101010 00000000010000000000000 +--------11-----101010 00000000001000000000000 +----------00---101010 00000000000010000000000 +----------01---101010 00000000000001000000000 +----------10---101010 00000000000000100000000 +----------11---101010 00000000000000010000000 +0--------------101010 00000000000000000001000 +1--------------101010 00000000000000000001000 +------------0--101010 00000000000000001000000 +------------1--101010 00000000000000000100000 +0--------------101010 00000000000100000000000 +1--------------101010 00000000000100000000000 +0---0----------101010 10101100000000000000000 +1--------------101010 00000000000000000000000 +0---1----------101010 10101000000000000000000 +0--1-----------101011 00000010000000000000000 +0--------------101011 00000000000000000010000 +1--------------101011 00000000000000000010000 +--------00-----101011 00000001000000000000000 +--------01-----101011 00000000100000000000000 +--------10-----101011 00000000010000000000000 +--------11-----101011 00000000001000000000000 +----------00---101011 00000000000010000000000 +----------01---101011 00000000000001000000000 +----------10---101011 00000000000000100000000 +----------11---101011 00000000000000010000000 +0--------------101011 00000000000000000001000 +1--------------101011 00000000000000000001000 +------------0--101011 00000000000000001000000 +------------1--101011 00000000000000000100000 +0--------------101011 00000000000100000000000 +1--------------101011 00000000000100000000000 +0---0----------101011 10110000000000000000000 +1--------------101011 00000000000000000000000 +0---1----------101011 10101100000000000000000 +0--1-----------101100 00000010000000000000000 +0--------------101100 00000000000000000010000 +1--------------101100 00000000000000000010000 +--------00-----101100 00000001000000000000000 +--------01-----101100 00000000100000000000000 +--------10-----101100 00000000010000000000000 +--------11-----101100 00000000001000000000000 +----------00---101100 00000000000010000000000 +----------01---101100 00000000000001000000000 +----------10---101100 00000000000000100000000 +----------11---101100 00000000000000010000000 +0--------------101100 00000000000000000001000 +1--------------101100 00000000000000000001000 +------------0--101100 00000000000000001000000 +------------1--101100 00000000000000000100000 +0--------------101100 00000000000100000000000 +1--------------101100 00000000000100000000000 +0---0----------101100 10110100000000000000000 +1--------------101100 00000000000000000000000 +0---1----------101100 10110000000000000000000 +0--1-----------101101 00000010000000000000000 +0--------------101101 00000000000000000010000 +1--------------101101 00000000000000000010000 +----------00---101101 00000000000010000000000 +----------01---101101 00000000000001000000000 +----------10---101101 00000000000000100000000 +----------11---101101 00000000000000010000000 +------------0--101101 00000000000000001000000 +------------1--101101 00000000000000000100000 +0--------------101101 00000000000000000001000 +1--------------101101 00000000000000000001000 +0--------------101101 00000000000100000000000 +1--------------101101 00000000000100000000000 +0---0----------101101 10111000000000000000000 +1--------------101101 00000000000000000000000 +0---1----------101101 10110100000000000000000 +0--1-----------101110 00000010000000000000000 +----------00---101110 00000000000010000000000 +----------01---101110 00000000000001000000000 +----------10---101110 00000000000000100000000 +----------11---101110 00000000000000010000000 +------------0--101110 00000000000000001000000 +------------1--101110 00000000000000000100000 +0--------------101110 00000000000100000000000 +1--------------101110 00000000000100000000000 +0---0----------101110 10111100000000000000000 +1--------------101110 00000000000000000000000 +0---1----------101110 10111000000000000000000 +0--1-----------101111 00000010000000000000000 +----------00---101111 00000000000010000000000 +----------01---101111 00000000000001000000000 +----------10---101111 00000000000000100000000 +----------11---101111 00000000000000010000000 +------------0--101111 00000000000000001000000 +------------1--101111 00000000000000000100000 +0--------------101111 00000000000100000000000 +1--------------101111 00000000000100000000000 +0---0----------101111 10000000000000000000000 +1--------------101111 00000000000000000000000 +0---1----------101111 10111100000000000000000 +0--1-----------100000 00000010000000000000000 +0--------------100000 00000001111000000000000 +1--------------100000 00000001111000000000000 +0--------------100000 00000000000100000000000 +1--------------100000 00000000000100000000000 +1--------------100000 00000000000000000000000 +0--------------100000 10000100000000000000000 +0--1-----------100001 00000010000000000000000 +0--------------100001 00000001111000000000000 +1--------------100001 00000001111000000000000 +0--------------100001 00000000000100000000000 +1--------------100001 00000000000100000000000 +0---0----------100001 10001000000000000000000 +1--------------100001 00000000000000000000000 +0---1----------100001 10000100000000000000000 +0--1-----------100010 00000010000000000000000 +0--------------100010 00000001111000000000000 +1--------------100010 00000001111000000000000 +0--------------100010 00000000000011110000000 +1--------------100010 00000000000011110000000 +-----0---------100010 00000000000000001000000 +-----1---------100010 00000000000000000100000 +0--------------100010 00000000000100000000000 +1--------------100010 00000000000100000000000 +0---0----------100010 10001100000000000000000 +1--------------100010 00000000000000000000000 +0---1----------100010 10001000000000000000000 +0--1-----------100011 00000010000000000000000 +0--------------100011 00000001111000000000000 +1--------------100011 00000001111000000000000 +0--------------100011 00000000000011110000000 +1--------------100011 00000000000011110000000 +-----0---------100011 00000000000000001000000 +-----1---------100011 00000000000000000100000 +0--------------100011 00000000000100000000000 +1--------------100011 00000000000100000000000 +0---0----------100011 10010000000000000000000 +1--------------100011 00000000000000000000000 +0---1----------100011 10001100000000000000000 +0--1-----------100100 00000010000000000000000 +0--------------100100 00000001111000000000000 +1--------------100100 00000001111000000000000 +0--------------100100 00000000000011110000000 +1--------------100100 00000000000011110000000 +-----0---------100100 00000000000000001000000 +-----1---------100100 00000000000000000100000 +0--------------100100 00000000000100000000000 +1--------------100100 00000000000100000000000 +0---0----------100100 10010100000000000000000 +1--------------100100 00000000000000000000000 +0---1----------100100 10010000000000000000000 +0--1-----------100101 00000010000000000000000 +0--------------100101 00000000000011110000000 +1--------------100101 00000000000011110000000 +-----0---------100101 00000000000000001000000 +-----1---------100101 00000000000000000100000 +0---0----------100101 10011000000000000000000 +1--------------100101 00000000000000000000000 +0---1----------100101 10010100000000000000000 +0--1-----------100110 00000010000000000000000 +0--------------100110 00000000000000000010000 +1--------------100110 00000000000000000010000 +0--------------100110 00000000000011110000000 +1--------------100110 00000000000011110000000 +-----0---------100110 00000000000000001000000 +-----1---------100110 00000000000000000100000 +0--------------100110 00000000000100000000000 +1--------------100110 00000000000100000000000 +0---0----------100110 10011100000000000000000 +1--------------100110 00000000000000000000000 +0---1----------100110 10011000000000000000000 +0--1-----------100111 00000010000000000000000 +0--------------100111 00000000000000000010000 +1--------------100111 00000000000000000010000 +0--------------100111 00000000000011110000000 +1--------------100111 00000000000011110000000 +-----0---------100111 00000000000000001000000 +-----1---------100111 00000000000000000100000 +0--------------100111 00000000000100000000000 +1--------------100111 00000000000100000000000 +0---0----------100111 11000000000000000000000 +1--------------100111 00000000000000000000000 +0---1----------100111 10011100000000000000000 +0--1-----------110000 00000010000000000000000 +0--------------110000 00000000000000000010000 +1--------------110000 00000000000000000010000 +---------0---1-110000 00000001111000000000000 +--------00-----110000 00000001000000000000000 +--------01-----110000 00000000100000000000000 +--------10-----110000 00000000010000000000000 +--------11-----110000 00000000001000000000000 +0--------------110000 00000000000000000000100 +1--------------110000 00000000000000000000100 +0--------------110000 00000000000100000000000 +1--------------110000 00000000000100000000000 +0---0----------110000 11000100000000000000000 +1--------------110000 00000000000000000000000 +0---1----------110000 11000000000000000000000 +0--1-----------110001 00000010000000000000000 +0--------------110001 00000000000000000010000 +1--------------110001 00000000000000000010000 +---------0---1-110001 00000001111000000000000 +--------00-----110001 00000001000000000000000 +--------01-----110001 00000000100000000000000 +--------10-----110001 00000000010000000000000 +--------11-----110001 00000000001000000000000 +0--------------110001 00000000000000000000100 +1--------------110001 00000000000000000000100 +------------0-0110001 00000000000000000000010 +------------1-0110001 00000000000000000000001 +--------------1110001 00000000000000000000010 +--------------1110001 00000000000000000000001 +0--------------110001 00000000000100000000000 +1--------------110001 00000000000100000000000 +0---0----------110001 11001000000000000000000 +1--------------110001 00000000000000000000000 +0---1----------110001 11000100000000000000000 +0--1-----------110010 00000010000000000000000 +0--------------110010 00000000000000000010000 +1--------------110010 00000000000000000010000 +---------0---1-110010 00000001111000000000000 +--------00-----110010 00000001000000000000000 +--------01-----110010 00000000100000000000000 +--------10-----110010 00000000010000000000000 +--------11-----110010 00000000001000000000000 +---------0---1-110010 00000000000011110000000 +----------00---110010 00000000000010000000000 +----------01---110010 00000000000001000000000 +----------10---110010 00000000000000100000000 +----------11---110010 00000000000000010000000 +0--------------110010 00000000000000000000100 +1--------------110010 00000000000000000000100 +------------0-0110010 00000000000000000000010 +------------1-0110010 00000000000000000000001 +--------------1110010 00000000000000000000010 +--------------1110010 00000000000000000000001 +0--------------110010 00000000000100000000000 +1--------------110010 00000000000100000000000 +0---0----------110010 11001100000000000000000 +1--------------110010 00000000000000000000000 +0---1----------110010 11001000000000000000000 +0--1-----------110011 00000010000000000000000 +0--------------110011 00000000000000000010000 +1--------------110011 00000000000000000010000 +---------0---1-110011 00000001111000000000000 +--------00-----110011 00000001000000000000000 +--------01-----110011 00000000100000000000000 +--------10-----110011 00000000010000000000000 +--------11-----110011 00000000001000000000000 +---------0---1-110011 00000000000011110000000 +----------00---110011 00000000000010000000000 +----------01---110011 00000000000001000000000 +----------10---110011 00000000000000100000000 +----------11---110011 00000000000000010000000 +0--------------110011 00000000000000000000100 +1--------------110011 00000000000000000000100 +------------0-0110011 00000000000000000000010 +------------1-0110011 00000000000000000000001 +--------------1110011 00000000000000000000010 +--------------1110011 00000000000000000000001 +0--------------110011 00000000000100000000000 +1--------------110011 00000000000100000000000 +0---0----------110011 11010000000000000000000 +1--------------110011 00000000000000000000000 +0---1----------110011 11001100000000000000000 +0--1-----------110100 00000010000000000000000 +0--------------110100 00000000000000000010000 +1--------------110100 00000000000000000010000 +---------0---1-110100 00000001111000000000000 +--------00-----110100 00000001000000000000000 +--------01-----110100 00000000100000000000000 +--------10-----110100 00000000010000000000000 +--------11-----110100 00000000001000000000000 +---------0---1-110100 00000000000011110000000 +----------00---110100 00000000000010000000000 +----------01---110100 00000000000001000000000 +----------10---110100 00000000000000100000000 +----------11---110100 00000000000000010000000 +0--------------110100 00000000000000000000100 +1--------------110100 00000000000000000000100 +------------0-0110100 00000000000000000000010 +------------1-0110100 00000000000000000000001 +--------------1110100 00000000000000000000010 +--------------1110100 00000000000000000000001 +0--------------110100 00000000000100000000000 +1--------------110100 00000000000100000000000 +0---0----------110100 11010100000000000000000 +1--------------110100 00000000000000000000000 +0---1----------110100 11010000000000000000000 +0--1-----------110101 00000010000000000000000 +0--------------110101 00000000000000000010000 +1--------------110101 00000000000000000010000 +---------0---1-110101 00000000000011110000000 +----------00---110101 00000000000010000000000 +----------01---110101 00000000000001000000000 +----------10---110101 00000000000000100000000 +----------11---110101 00000000000000010000000 +0--------------110101 00000000000100000000000 +1--------------110101 00000000000100000000000 +0--------------110101 00000000000000000000100 +1--------------110101 00000000000000000000100 +------------0-0110101 00000000000000000000010 +------------1-0110101 00000000000000000000001 +--------------1110101 00000000000000000000010 +--------------1110101 00000000000000000000001 +0---0----------110101 11011000000000000000000 +1--------------110101 00000000000000000000000 +0---1----------110101 11010100000000000000000 +0--1-----------110110 00000010000000000000000 +---------0---1-110110 00000000000011110000000 +----------00---110110 00000000000010000000000 +----------01---110110 00000000000001000000000 +----------10---110110 00000000000000100000000 +----------11---110110 00000000000000010000000 +0--------------110110 00000000000100000000000 +1--------------110110 00000000000100000000000 +0--------------110110 00000000000000000000100 +1--------------110110 00000000000000000000100 +------------0-0110110 00000000000000000000010 +------------1-0110110 00000000000000000000001 +--------------1110110 00000000000000000000010 +--------------1110110 00000000000000000000001 +0---0----------110110 11011100000000000000000 +1--------------110110 00000000000000000000000 +0---1----------110110 11011000000000000000000 +---------0---1-110111 00000000000011110000000 +----------00---110111 00000000000010000000000 +----------01---110111 00000000000001000000000 +----------10---110111 00000000000000100000000 +----------11---110111 00000000000000010000000 +0--------------110111 00000000000100000000000 +1--------------110111 00000000000100000000000 +0---0----------110111 00000000000000000000000 +1--------------110111 00000000000000000000000 +0---1----------110111 11011100000000000000000 +0--1-----------011000 00000010000000000000000 +001------------011000 00000010000000000000000 +0--------------011000 00000000000000000010000 +1--------------011000 00000000000000000010000 +0--------------011000 00000000000100000000000 +1--------------011000 00000000000100000000000 +0---0----------011000 01100100000000000000000 +1--------------011000 00000000000000000000000 +0---1----------011000 01100000000000000000000 +0--1-----------011001 00000010000000000000000 +001------------011001 00000010000000000000000 +0--------------011001 00000000000000000010000 +1--------------011001 00000000000000000010000 +0--------------011001 00000000000100000000000 +1--------------011001 00000000000100000000000 +0---0----------011001 01101000000000000000000 +1--------------011001 00000000000000000000000 +0---1----------011001 01100100000000000000000 +0--1-----------011010 00000010000000000000000 +001------------011010 00000010000000000000000 +0--------------011010 00000000000000000010000 +1--------------011010 00000000000000000010000 +0--------------011010 00000000000100000000000 +1--------------011010 00000000000100000000000 +0---0----------011010 01101100000000000000000 +1--------------011010 00000000000000000000000 +0---1----------011010 01101000000000000000000 +0--1-----------011011 00000010000000000000000 +001------------011011 00000010000000000000000 +0--------------011011 00000000000000000010000 +1--------------011011 00000000000000000010000 +0--------------011011 00000000000100000000000 +1--------------011011 00000000000100000000000 +0---0----------011011 01110000000000000000000 +1--------------011011 00000000000000000000000 +0---1----------011011 01101100000000000000000 +0--1-----------011100 00000010000000000000000 +001------------011100 00000010000000000000000 +0--------------011100 00000000000000000010000 +1--------------011100 00000000000000000010000 +0--------------011100 00000000000100000000000 +1--------------011100 00000000000100000000000 +0---0----------011100 01110100000000000000000 +1--------------011100 00000000000000000000000 +0---1----------011100 01110000000000000000000 +0--1-----------011101 00000010000000000000000 +001------------011101 00000010000000000000000 +0--------------011101 00000000000000000010000 +1--------------011101 00000000000000000010000 +0--------------011101 00000000000100000000000 +1--------------011101 00000000000100000000000 +0---0----------011101 01111000000000000000000 +1--------------011101 00000000000000000000000 +0---1----------011101 01110100000000000000000 +0--1-----------011110 00000010000000000000000 +001------------011110 00000010000000000000000 +0--------------011110 00000000000100000000000 +1--------------011110 00000000000100000000000 +0---0----------011110 01111100000000000000000 +1--------------011110 00000000000000000000000 +0---1----------011110 01111000000000000000000 +0--1-----------011111 00000010000000000000000 +001------------011111 00000010000000000000000 +0--------------011111 00000000000100000000000 +1--------------011111 00000000000100000000000 +0---0----------011111 00000000000000000000000 +1--------------011111 00000000000000000000000 +0---1----------011111 01111100000000000000000 diff --git a/espresso/examples/indust/t2 b/espresso/examples/indust/t2 new file mode 100644 index 0000000..ff58d8b --- /dev/null +++ b/espresso/examples/indust/t2 @@ -0,0 +1,303 @@ +.i 17 +.o 16 +00---------000000 0000000000000000 +0--00------000000 0000000000000000 +0--11------000000 0000000000000000 +01110-0----000000 0000000000000000 +011010-----000000 0000000000000000 +1----------000000 0000000000000000 +01010-0----000000 1000000000000000 +01-10-1----000000 1010000000000000 +010010-----000000 0100000000000000 +01-011-----000000 0000010000000000 +01--11-----000000 0000001000000000 +010--------000000 0000001000000000 +01-1--1----000000 0000001000000000 +01-1--1----000000 0000000100000000 +-------1---100000 0000000001000000 +0----------100000 0000001000000000 +1----------100000 0000000000000000 +0----------100000 1000010000000000 +0----------101000 0000000100000000 +0----------101000 0000001000000000 +1----------101000 0000000000000000 +0----------101000 1010010000000000 +-------1---010000 0000000001000000 +0----------010000 0000001000000000 +0----------010000 0100010000000000 +1----------010000 0000000000000000 +0----------000001 0000001000000000 +-------1---000001 0000000010000000 +-------0---000001 0000000001000000 +0----------000001 0000100000000000 +1----------000001 0000000000000000 +0----------000010 0000001000000000 +-------1---000010 0000000010000000 +-------0---000010 0000000001000000 +0----------000010 0000000000000000 +1----------000010 0000000000000000 +-------1---010001 0000000001000000 +0----------010001 0000001000000000 +0----------010001 0100100000000000 +1----------010001 0000000000000000 +0----------010010 0000001000000000 +0----------010010 0100110000000000 +1----------010010 0000000000000000 +0----------010011 0000001000000000 +0----------010011 0000000000100000 +1----------010011 0000000000100000 +0----------010011 0101000000000000 +1----------010011 0000000000000000 +0----------010100 0000000000100000 +1----------010100 0000000000100000 +0----------010100 0000001000000000 +0----------010100 0101010000000000 +1----------010100 0000000000000000 +0----------010101 0000000000100000 +1----------010101 0000000000100000 +0----------010101 0000001000000000 +0----------010101 0101100000000000 +1----------010101 0000000000000000 +0----------010110 0000000000100000 +1----------010110 0000000000100000 +0----------010110 0000001000000000 +0----------010110 0101110000000000 +1----------010110 0000000000000000 +0----------010111 0000000000100000 +1----------010111 0000000000100000 +0----------010111 0000000000010000 +1----------010111 0000000000010000 +0----------010111 0000001000000000 +0----------010111 0110000000000000 +1----------010111 0000000000000000 +0----------011000 0000001000000000 +0----------011000 0000000000100000 +1----------011000 0000000000100000 +0----------011000 0000000000010000 +1----------011000 0000000000010000 +0----------011000 0110010000000000 +1----------011000 0000000000000000 +0----------011001 0000001000000000 +0----------011001 0000000000100000 +1----------011001 0000000000100000 +0----------011001 0000000000010000 +1----------011001 0000000000010000 +0----------011001 0110100000000000 +1----------011001 0000000000000000 +0----------011010 0000001000000000 +0----------011010 0000000000100000 +1----------011010 0000000000100000 +0----------011010 0000000000010000 +1----------011010 0000000000010000 +0----------011010 0110110000000000 +1----------011010 0000000000000000 +0----------011011 0000001000000000 +0----------011011 0000000000100000 +1----------011011 0000000000100000 +0----------011011 0000000000010000 +1----------011011 0000000000010000 +-------0---011011 0000000001000000 +0----------011011 0111000000000000 +1----------011011 0000000000000000 +0----------011100 0000000000100000 +1----------011100 0000000000100000 +0----------011100 0000001000000000 +0----------011100 0000000000010000 +1----------011100 0000000000010000 +-------0---011100 0000000001000000 +1----------011100 0000000000000000 +0----------011100 0111010000000000 +0----------011101 0000000000100000 +1----------011101 0000000000100000 +0----------011101 0000001000000000 +0----------011101 0111100000000000 +1----------011101 0000000000000000 +0----------011110 0000001000000000 +0----------011110 0111110000000000 +1----------011110 0000000000000000 +0----------011111 0000001000000000 +0----------011111 0000000000000000 +1----------011111 0000000000000000 +-------1---100001 0000000001000000 +0----------100001 0000001000000000 +1----------100001 0000000000000000 +0----------100001 1000100000000000 +0----------100010 0000001000000000 +-------1---100010 0000000000001000 +-------10--100010 0000000000000100 +-------1-1-100010 0000000000000010 +0----------100010 1000110000000000 +1----------100010 0000000000000000 +0----------100011 0000001000000000 +-------1---100011 0000000000001000 +-------10--100011 0000000000000100 +-------1-1-100011 0000000000000010 +0----------100011 1001000000000000 +1----------100011 0000000000000000 +0----------100100 0000001000000000 +-------1---100100 0000000000001000 +-------10--100100 0000000000000100 +-------1-1-100100 0000000000000010 +0----------100100 1001010000000000 +1----------100100 0000000000000000 +-------0---100101 0000000001000000 +0----------100101 0000001000000000 +-------1---100101 0000000000001000 +-------10--100101 0000000000000100 +-------1-1-100101 0000000000000010 +0----------100101 1001100000000000 +1----------100101 0000000000000000 +-------0---100110 0000000001000000 +0----------100110 0000001000000000 +0----------100110 0000000000000000 +1----------100110 0000000000000000 +0----------101001 0000000100000000 +0----------101001 0000001000000000 +0----------101001 1010100000000000 +1----------101001 0000000000000000 +0----------101010 0000000100000000 +0----------101010 0000001000000000 +0----------101010 1010110000000000 +1----------101010 0000000000000000 +0----------101011 0000000100000000 +0----------101011 0000001000000000 +-------1---101011 0000000000000001 +0----------101011 0001000000000000 +1----------101011 0000000000000000 +0------1---000100 0000000000000000 +0------0--0000100 0000000000000000 +1----------000100 0000000000000000 +0------0--1000100 0001000000000000 +0----------000100 0000000100000000 +0----------100111 0000000000000000 +1----------100111 0000000000000000 +0----------100111 000000---------- +1----------100111 000000---------- +0----------000101 0000000000000000 +1----------000101 0000000000000000 +0----------000101 000000---------- +1----------000101 000000---------- +0----------000011 0000000000000000 +1----------000011 0000000000000000 +0----------000011 000000---------- +1----------000011 000000---------- +0----------111000 0000000000000000 +1----------111000 0000000000000000 +0----------111000 000000---------- +1----------111000 000000---------- +0----------110100 0000000000000000 +1----------110100 0000000000000000 +0----------110100 000000---------- +1----------110100 000000---------- +0----------111100 0000000000000000 +1----------111100 0000000000000000 +0----------111100 000000---------- +1----------111100 000000---------- +0----------110010 0000000000000000 +1----------110010 0000000000000000 +0----------110010 000000---------- +1----------110010 000000---------- +0----------111010 0000000000000000 +1----------111010 0000000000000000 +0----------111010 000000---------- +1----------111010 000000---------- +0----------110110 0000000000000000 +1----------110110 0000000000000000 +0----------110110 000000---------- +1----------110110 000000---------- +0----------111110 0000000000000000 +1----------111110 0000000000000000 +0----------111110 000000---------- +1----------111110 000000---------- +0----------110001 0000000000000000 +1----------110001 0000000000000000 +0----------110001 000000---------- +1----------110001 000000---------- +0----------111001 0000000000000000 +1----------111001 0000000000000000 +0----------111001 000000---------- +1----------111001 000000---------- +0----------110101 0000000000000000 +1----------110101 0000000000000000 +0----------110101 000000---------- +1----------110101 000000---------- +0----------111101 0000000000000000 +1----------111101 0000000000000000 +0----------111101 000000---------- +1----------111101 000000---------- +0----------110011 0000000000000000 +1----------110011 0000000000000000 +0----------110011 000000---------- +1----------110011 000000---------- +0----------111011 0000000000000000 +1----------111011 0000000000000000 +0----------111011 000000---------- +1----------111011 000000---------- +0----------110111 0000000000000000 +1----------110111 0000000000000000 +0----------110111 000000---------- +1----------110111 000000---------- +0----------111111 0000000000000000 +1----------111111 0000000000000000 +0----------111111 000000---------- +1----------111111 000000---------- +0----------110000 0000000000000000 +1----------110000 0000000000000000 +0----------110000 000000---------- +1----------110000 000000---------- +0----------101110 0000000000000000 +1----------101110 0000000000000000 +0----------101110 000000---------- +1----------101110 000000---------- +0----------101101 0000000000000000 +1----------101101 0000000000000000 +0----------101101 000000---------- +1----------101101 000000---------- +0----------101111 0000000000000000 +1----------101111 0000000000000000 +0----------101111 000000---------- +1----------101111 000000---------- +0----------101100 0000000000000000 +1----------101100 0000000000000000 +0----------101100 000000---------- +1----------101100 000000---------- +0----------001100 0000000000000000 +1----------001100 0000000000000000 +0----------001100 000000---------- +1----------001100 000000---------- +0----------001010 0000000000000000 +1----------001010 0000000000000000 +0----------001010 000000---------- +1----------001010 000000---------- +0----------001110 0000000000000000 +1----------001110 0000000000000000 +0----------001110 000000---------- +1----------001110 000000---------- +0----------001001 0000000000000000 +1----------001001 0000000000000000 +0----------001001 000000---------- +1----------001001 000000---------- +0----------001101 0000000000000000 +1----------001101 0000000000000000 +0----------001101 000000---------- +1----------001101 000000---------- +0----------001011 0000000000000000 +1----------001011 0000000000000000 +0----------001011 000000---------- +1----------001011 000000---------- +0----------001111 0000000000000000 +1----------001111 0000000000000000 +0----------001111 000000---------- +1----------001111 000000---------- +0----------001000 0000000000000000 +1----------001000 0000000000000000 +0----------001000 000000---------- +1----------001000 000000---------- +0----------000111 0000000000000000 +1----------000111 0000000000000000 +0----------000111 000000---------- +1----------000111 000000---------- +0----------000110 0000000000000000 +1----------000110 0000000000000000 +0----------000110 000000---------- +1----------000110 000000---------- diff --git a/espresso/examples/indust/t3 b/espresso/examples/indust/t3 new file mode 100644 index 0000000..f4442df --- /dev/null +++ b/espresso/examples/indust/t3 @@ -0,0 +1,154 @@ +.i 12 +.o 8 +0----------- 00000000 +1----------- 00000000 +00000------- 10000000 +000010000000 01000000 +000010000001 01000000 +000010000010 10000000 +000010000011 10000000 +000010000100 00100000 +000010000101 01000000 +000010000110 00100000 +000010000111 10000000 +000010001000 01000000 +000010001001 01000000 +000010001010 10000000 +000010001011 10000000 +000010001100 00100000 +000010001101 01000000 +000010001110 00100000 +000010001111 10000000 +000010010000 01000000 +000010010001 01000000 +000010010010 10000000 +000010010011 10000000 +000010010100 00100000 +000010010101 01000000 +000010010110 00100000 +000010010111 10000000 +000010011000 01000000 +000010011001 01000000 +000010011010 10000000 +000010011011 10000000 +000010011100 00100000 +000010011101 01000000 +000010011110 00100000 +000010011111 10000000 +000010100000 00010000 +000010100001 00010000 +000010100010 00010000 +000010100011 00010000 +000010100100 00100000 +000010100101 00100000 +000010100110 00100000 +000010100111 00100000 +000010101000 00010000 +000010101001 00010000 +000010101010 00010000 +000010101011 00010000 +000010101100 00010000 +000010101101 00010000 +000010101110 00010000 +000010101111 00010000 +000010110000 01000000 +000010110001 01000000 +000010110010 10000000 +000010110011 10000000 +000010110100 00100000 +000010110101 01000000 +000010110110 00100000 +000010110111 10000000 +000010111000 00010000 +000010111001 00010000 +000010111010 00010000 +000010111011 00010000 +000010111100 00010000 +000010111101 00010000 +000010111110 00010000 +000010111111 00010000 +000011000000 00100000 +000011000001 01000000 +000011000010 00100000 +000011000011 10000000 +000011000100 00100000 +000011000101 01000000 +000011000110 00100000 +000011000111 10000000 +000011001000 00100000 +000011001001 01000000 +000011001010 00100000 +000011001011 10000000 +000011001100 00100000 +000011001101 01000000 +000011001110 00100000 +000011001111 10000000 +000011010000 00100000 +000011010001 01000000 +000011010010 00100000 +000011010011 10000000 +000011010100 00100000 +000011010101 01000000 +000011010110 00100000 +000011010111 10000000 +000011011000 00100000 +000011011001 01000000 +000011011010 00100000 +000011011011 10000000 +000011011100 00100000 +000011011101 01000000 +000011011110 00100000 +000011011111 10000000 +000011100000 00100000 +000011100001 00100000 +000011100010 00100000 +000011100011 00100000 +000011100100 00100000 +000011100101 01000000 +000011100110 00100000 +000011100111 10000000 +000011101000 00010000 +000011101001 00010000 +000011101010 00010000 +000011101011 00010000 +000011101100 00010000 +000011101101 00010000 +000011101110 00010000 +000011101111 00010000 +000011110000 00100000 +000011110001 01000000 +000011110010 00100000 +000011110011 10000000 +000011110100 00100000 +000011110101 01000000 +000011110110 00100000 +000011110111 10000000 +000011111000 00010000 +000011111001 00010000 +000011111010 00010000 +000011111011 00010000 +000011111100 00010000 +000011111101 00010000 +000011111110 00010000 +000011111111 00010000 +0001-------- 00001000 +001--------- 00000100 +01---------- 00000010 +1-0-0--00--- 00010000 +1-0-0--01--- 00001000 +1-0-0--10--- 00000100 +1-0-0--11--- 00000010 +1-0-1--00--- 10000000 +1-0-1--01--- 00000001 +1-0-1--10--- 00100000 +1-0-1--11--- 01000000 +1-1-0--00--- 00010000 +1-1-0--01--- 00001000 +1-1-0--10--- 00010000 +1-1-0--11--- 00001000 +1-1-1--00--- 00000001 +1-1-1--01--- 00000001 +1-1-1--10--- 00000001 +1-1-1--11--- 00000001 +0----------- 00000000 +1----------- 00000000 diff --git a/espresso/examples/indust/t4 b/espresso/examples/indust/t4 new file mode 100644 index 0000000..159b624 --- /dev/null +++ b/espresso/examples/indust/t4 @@ -0,0 +1,518 @@ +.i 12 +.o 8 +0---00000000 00100011 +010-00100011 10000100 +00--00100011 10000100 +011-00100011 10001100 +1---00100011 00000000 +0---10000100 10000101 +1---10000100 00000000 +0---10000101 10000110 +1---10000101 00000000 +0---10000110 10000111 +1---10000110 00000000 +0---10000111 10000000 +1---10000111 00000000 +0---10000000 10000001 +1---10000000 00000000 +0---10000001 10000010 +1---10000001 00000000 +0---10000010 00100011 +1---10000010 00000000 +0---10001100 10001101 +1---10001100 00000000 +0---10001101 10001110 +1---10001101 00000000 +0---10001110 10001111 +1---10001110 00000000 +0---10001111 10001000 +1---10001111 00000000 +0---10001000 10001001 +1---10001000 00000000 +0---10001001 10001010 +1---10001001 00000000 +0---10001010 00101011 +1---10001010 00000000 +0--000101011 10001100 +0--100101011 11011100 +1---00101011 00000000 +0---11011100 10011101 +1---11011100 00000000 +0---11010100 10010101 +1---11010100 00000000 +0---10010101 11010110 +1---10010101 00000000 +0---11010110 10010111 +1---11010110 00000000 +0---10010111 11010000 +1---10010111 00000000 +0---11010000 10010001 +1---11010000 00000000 +0---10010001 11010010 +1---10010001 00000000 +0---11010010 10110011 +1---11010010 00000000 +0-0-10110011 11011100 +0-1-10110011 10000100 +1---10110011 00000000 +0---10011101 11011110 +1---10011101 00000000 +0---11011110 10011111 +1---11011110 00000000 +0---10011111 11011000 +1---10011111 00000000 +0---11011000 10011001 +1---11011000 00000000 +0---10011001 11011010 +1---10011001 00000000 +0---11011010 00111011 +1---11011010 00000000 +0-0-00111011 11010100 +1---00111011 00000000 +0-1-00111011 10000100 +1---11010011 00000000 +0---11010011 -------- +1---11010001 00000000 +0---11010001 -------- +1---11010111 00000000 +0---11010111 -------- +1---11010101 00000000 +0---11010101 -------- +1---11011011 00000000 +0---11011011 -------- +1---11011001 00000000 +0---11011001 -------- +1---11011111 00000000 +0---11011111 -------- +1---11011101 00000000 +0---11011101 -------- +1---10110010 00000000 +0---10110010 -------- +1---10011000 00000000 +0---10011000 -------- +1---10011110 00000000 +0---10011110 -------- +1---10011100 00000000 +0---10011100 -------- +1---10010000 00000000 +0---10010000 -------- +1---10010110 00000000 +0---10010110 -------- +1---10010100 00000000 +0---10010100 -------- +1---10001011 00000000 +0---10001011 -------- +1---10000011 00000000 +0---10000011 -------- +1---00111010 00000000 +0---00111010 -------- +1---00101010 00000000 +0---00101010 -------- +1---00100010 00000000 +0---00100010 -------- +1---00000001 00000000 +0---00000001 -------- +1---11110000 00000000 +0---11110000 -------- +1---11101000 00000000 +0---11101000 -------- +1---11111000 00000000 +0---11111000 -------- +1---11100100 00000000 +0---11100100 -------- +1---11110100 00000000 +0---11110100 -------- +1---11101100 00000000 +0---11101100 -------- +1---11111100 00000000 +0---11111100 -------- +1---11100010 00000000 +0---11100010 -------- +1---11110010 00000000 +0---11110010 -------- +1---11101010 00000000 +0---11101010 -------- +1---11111010 00000000 +0---11111010 -------- +1---11100110 00000000 +0---11100110 -------- +1---11110110 00000000 +0---11110110 -------- +1---11101110 00000000 +0---11101110 -------- +1---11111110 00000000 +0---11111110 -------- +1---11100001 00000000 +0---11100001 -------- +1---11110001 00000000 +0---11110001 -------- +1---11101001 00000000 +0---11101001 -------- +1---11111001 00000000 +0---11111001 -------- +1---11100101 00000000 +0---11100101 -------- +1---11110101 00000000 +0---11110101 -------- +1---11101101 00000000 +0---11101101 -------- +1---11111101 00000000 +0---11111101 -------- +1---11100011 00000000 +0---11100011 -------- +1---11110011 00000000 +0---11110011 -------- +1---11101011 00000000 +0---11101011 -------- +1---11111011 00000000 +0---11111011 -------- +1---11100111 00000000 +0---11100111 -------- +1---11110111 00000000 +0---11110111 -------- +1---11101111 00000000 +0---11101111 -------- +1---11111111 00000000 +0---11111111 -------- +1---11100000 00000000 +0---11100000 -------- +1---11001000 00000000 +0---11001000 -------- +1---11000100 00000000 +0---11000100 -------- +1---11001100 00000000 +0---11001100 -------- +1---11000010 00000000 +0---11000010 -------- +1---11001010 00000000 +0---11001010 -------- +1---11000110 00000000 +0---11000110 -------- +1---11001110 00000000 +0---11001110 -------- +1---11000001 00000000 +0---11000001 -------- +1---11001001 00000000 +0---11001001 -------- +1---11000101 00000000 +0---11000101 -------- +1---11001101 00000000 +0---11001101 -------- +1---11000011 00000000 +0---11000011 -------- +1---11001011 00000000 +0---11001011 -------- +1---11000111 00000000 +0---11000111 -------- +1---11001111 00000000 +0---11001111 -------- +1---11000000 00000000 +0---11000000 -------- +1---10101000 00000000 +0---10101000 -------- +1---10100100 00000000 +0---10100100 -------- +1---10101100 00000000 +0---10101100 -------- +1---10100010 00000000 +0---10100010 -------- +1---10101010 00000000 +0---10101010 -------- +1---10100110 00000000 +0---10100110 -------- +1---10101110 00000000 +0---10101110 -------- +1---10100001 00000000 +0---10100001 -------- +1---10101001 00000000 +0---10101001 -------- +1---10100101 00000000 +0---10100101 -------- +1---10101101 00000000 +0---10101101 -------- +1---10100011 00000000 +0---10100011 -------- +1---10101011 00000000 +0---10101011 -------- +1---10100111 00000000 +0---10100111 -------- +1---10101111 00000000 +0---10101111 -------- +1---10100000 00000000 +0---10100000 -------- +1---10111100 00000000 +0---10111100 -------- +1---10111010 00000000 +0---10111010 -------- +1---10111110 00000000 +0---10111110 -------- +1---10111001 00000000 +0---10111001 -------- +1---10111101 00000000 +0---10111101 -------- +1---10111011 00000000 +0---10111011 -------- +1---10111111 00000000 +0---10111111 -------- +1---10111000 00000000 +0---10111000 -------- +1---10110110 00000000 +0---10110110 -------- +1---10110101 00000000 +0---10110101 -------- +1---10110111 00000000 +0---10110111 -------- +1---10110100 00000000 +0---10110100 -------- +1---10110001 00000000 +0---10110001 -------- +1---10110000 00000000 +0---10110000 -------- +1---10011011 00000000 +0---10011011 -------- +1---10011010 00000000 +0---10011010 -------- +1---10010011 00000000 +0---10010011 -------- +1---10010010 00000000 +0---10010010 -------- +1---01100000 00000000 +0---01100000 -------- +1---01010000 00000000 +0---01010000 -------- +1---01110000 00000000 +0---01110000 -------- +1---01001000 00000000 +0---01001000 -------- +1---01101000 00000000 +0---01101000 -------- +1---01011000 00000000 +0---01011000 -------- +1---01111000 00000000 +0---01111000 -------- +1---01000100 00000000 +0---01000100 -------- +1---01100100 00000000 +0---01100100 -------- +1---01010100 00000000 +0---01010100 -------- +1---01110100 00000000 +0---01110100 -------- +1---01001100 00000000 +0---01001100 -------- +1---01101100 00000000 +0---01101100 -------- +1---01011100 00000000 +0---01011100 -------- +1---01111100 00000000 +0---01111100 -------- +1---01000010 00000000 +0---01000010 -------- +1---01100010 00000000 +0---01100010 -------- +1---01010010 00000000 +0---01010010 -------- +1---01110010 00000000 +0---01110010 -------- +1---01001010 00000000 +0---01001010 -------- +1---01101010 00000000 +0---01101010 -------- +1---01011010 00000000 +0---01011010 -------- +1---01111010 00000000 +0---01111010 -------- +1---01000110 00000000 +0---01000110 -------- +1---01100110 00000000 +0---01100110 -------- +1---01010110 00000000 +0---01010110 -------- +1---01110110 00000000 +0---01110110 -------- +1---01001110 00000000 +0---01001110 -------- +1---01101110 00000000 +0---01101110 -------- +1---01011110 00000000 +0---01011110 -------- +1---01111110 00000000 +0---01111110 -------- +1---01000001 00000000 +0---01000001 -------- +1---01100001 00000000 +0---01100001 -------- +1---01010001 00000000 +0---01010001 -------- +1---01110001 00000000 +0---01110001 -------- +1---01001001 00000000 +0---01001001 -------- +1---01101001 00000000 +0---01101001 -------- +1---01011001 00000000 +0---01011001 -------- +1---01111001 00000000 +0---01111001 -------- +1---01000101 00000000 +0---01000101 -------- +1---01100101 00000000 +0---01100101 -------- +1---01010101 00000000 +0---01010101 -------- +1---01110101 00000000 +0---01110101 -------- +1---01001101 00000000 +0---01001101 -------- +1---01101101 00000000 +0---01101101 -------- +1---01011101 00000000 +0---01011101 -------- +1---01111101 00000000 +0---01111101 -------- +1---01000011 00000000 +0---01000011 -------- +1---01100011 00000000 +0---01100011 -------- +1---01010011 00000000 +0---01010011 -------- +1---01110011 00000000 +0---01110011 -------- +1---01001011 00000000 +0---01001011 -------- +1---01101011 00000000 +0---01101011 -------- +1---01011011 00000000 +0---01011011 -------- +1---01111011 00000000 +0---01111011 -------- +1---01000111 00000000 +0---01000111 -------- +1---01100111 00000000 +0---01100111 -------- +1---01010111 00000000 +0---01010111 -------- +1---01110111 00000000 +0---01110111 -------- +1---01001111 00000000 +0---01001111 -------- +1---01101111 00000000 +0---01101111 -------- +1---01011111 00000000 +0---01011111 -------- +1---01111111 00000000 +0---01111111 -------- +1---01000000 00000000 +0---01000000 -------- +1---00110100 00000000 +0---00110100 -------- +1---00110010 00000000 +0---00110010 -------- +1---00110110 00000000 +0---00110110 -------- +1---00110001 00000000 +0---00110001 -------- +1---00110101 00000000 +0---00110101 -------- +1---00110011 00000000 +0---00110011 -------- +1---00110111 00000000 +0---00110111 -------- +1---00110000 00000000 +0---00110000 -------- +1---00111110 00000000 +0---00111110 -------- +1---00111101 00000000 +0---00111101 -------- +1---00111111 00000000 +0---00111111 -------- +1---00111100 00000000 +0---00111100 -------- +1---00111001 00000000 +0---00111001 -------- +1---00111000 00000000 +0---00111000 -------- +1---00101110 00000000 +0---00101110 -------- +1---00101101 00000000 +0---00101101 -------- +1---00101111 00000000 +0---00101111 -------- +1---00101100 00000000 +0---00101100 -------- +1---00101001 00000000 +0---00101001 -------- +1---00101000 00000000 +0---00101000 -------- +1---00100110 00000000 +0---00100110 -------- +1---00100101 00000000 +0---00100101 -------- +1---00100111 00000000 +0---00100111 -------- +1---00100100 00000000 +0---00100100 -------- +1---00100001 00000000 +0---00100001 -------- +1---00100000 00000000 +0---00100000 -------- +1---00011000 00000000 +0---00011000 -------- +1---00010100 00000000 +0---00010100 -------- +1---00011100 00000000 +0---00011100 -------- +1---00010010 00000000 +0---00010010 -------- +1---00011010 00000000 +0---00011010 -------- +1---00010110 00000000 +0---00010110 -------- +1---00011110 00000000 +0---00011110 -------- +1---00010001 00000000 +0---00010001 -------- +1---00011001 00000000 +0---00011001 -------- +1---00010101 00000000 +0---00010101 -------- +1---00011101 00000000 +0---00011101 -------- +1---00010011 00000000 +0---00010011 -------- +1---00011011 00000000 +0---00011011 -------- +1---00010111 00000000 +0---00010111 -------- +1---00011111 00000000 +0---00011111 -------- +1---00010000 00000000 +0---00010000 -------- +1---00001100 00000000 +0---00001100 -------- +1---00001010 00000000 +0---00001010 -------- +1---00001110 00000000 +0---00001110 -------- +1---00001001 00000000 +0---00001001 -------- +1---00001101 00000000 +0---00001101 -------- +1---00001011 00000000 +0---00001011 -------- +1---00001111 00000000 +0---00001111 -------- +1---00001000 00000000 +0---00001000 -------- +1---00000110 00000000 +0---00000110 -------- +1---00000101 00000000 +0---00000101 -------- +1---00000111 00000000 +0---00000111 -------- +1---00000100 00000000 +0---00000100 -------- +1---00000011 00000000 +0---00000011 -------- +1---00000010 00000000 +0---00000010 -------- diff --git a/espresso/examples/indust/ti b/espresso/examples/indust/ti new file mode 100644 index 0000000..e2aa563 --- /dev/null +++ b/espresso/examples/indust/ti @@ -0,0 +1,484 @@ +.i 47 +.o 72 +----1110-------------------------0-1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----111-0---------------------0----1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----11111---------------------0--0-1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----0110------------------------0--1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----011-0--------------------0-----1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----01111--------------------0--0--1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----1010------------------------00-1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----101-0--------------------00----1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----10111--------------------00-00-1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----0010------------------------0--1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----0010-------------------------0-1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----001-0---------------------0----1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----001-0--------------------0-----1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----00111--------------------0---0-1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----00111---------------------0--0-1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----00111---------------------0-0--1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----00111--------------------0--0--1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----11000---------------------0----1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----11000-----------------------0--1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----11000---------------------0----1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----11011---------------------0-0--1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----01000--------------------0-----1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----01000------------------------0-1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +----01011--------------------0---0-1--------001 +000001000000000000000000000000000000000000000000000000000000000000000000 +------------------------110--------1------110-1 +000000000000000000000000000000000000010101000000000100000000000000000000 +------------------------111--------1------110-1 +000000000000000000000000000000000000000000000010101100000000000000000000 +------------------------010--------1------110-1 +000000000000000000000000000000000000001011000000000100000000000000000000 +------------------------011--------1------110-1 +000000000000000000000000000000000000000000000001011100000000000000000000 +------------------------100--------1------110-1 +000000000000000000000000000000000000010011000000000100000000000000000000 +------------------------101--------1------110-1 +000000000000000000000000000000000000000000000010011100000000000000000000 +------------------------000--------1------110-1 +000000000000000000000000000000000000001101000000000100000000000000000000 +------------------------001--------1------110-1 +000000000000000000000000000000000000000000000001101100000000000000000000 +---------------------------10------1------110-1 +000000000000000000000000000000000000000000000000000000000010000100000000 +---------------------------00------1------110-1 +000000000000000000000000000000000000000000000000000000000010100000000000 +-----------------------111---------1--------111 +000000000000000000000000100000000000000000000000000000000000000000000000 +-----------------------011---------1--------111 +000000000000000000000000010000000000000000000000000000000000000000000000 +-----------------------101---------1--------111 +000000000000000000000000001000000000000000000000000000000000000000000000 +-----------------------001---------1--------111 +000000000000000000000000000100000000000000000000000000000000000000000000 +-----------------------110---------1--------111 +000000000000000000000000000000000000000000000010101000000000000000000000 +-----------------------010---------1--------111 +000000000000000000000000000000000000010101000000000000000000000000000000 +-----------------------100---------1--------111 +000000000000000000000000000010010000000000000000000000000000000000000000 +-----------------------000---------1--------111 +000000000000000000000000000010000000000000000000000000000000000000000000 +--------------------------111------1--------111 +000000000000000000001000000000000000000000000000000000000000000000000000 +--------------------------011------1--------111 +000000000000000000000100000000000000000000000000000000000000000000000000 +--------------------------101------1--------111 +000000000000000000000010000000000000000000000000000000000000000000000000 +--------------------------001------1--------111 +000000000000000000000001000000000000000000000000000000000000000000000000 +--------------------------110------1--------111 +000000000000000000000000000000000000000000000100000000000000000000000000 +--------------------------010------1--------111 +000000000000000000000000000000000000100000000000000000000000000000000000 +--------------------------100------1--------111 +000000000000000000000000000001100000000000000000000000000000000000000000 +--------------------------000------1--------111 +000000000000000000000000000001000000000000000000000000000000000000000000 +-------------------0---------------1---01---111 +000000001110111011000000000000000000000000000000000000000000000000000000 +-----------------------------------1------01000 +011110000000000000000000000000000000000000000000000000000000000000000000 +---------------------11------------1------00001 +000000110010111011000000000000000000000000000000000000000000000000000000 +----------0-----------0------------1------00001 +000000000010011111010000000000000000000000000000000110000000001000000010 +-------------1----11--0------------1------00001 +110010000000000000000000000000000000000000000000000010000000000000000000 +-------------0----11--0------------1------00001 +111000000000000000000000000000000000000000000000000000000000000000000000 +-------------------0--0------------1------00001 +110000110000000000000000000000000000000000000000000000000000000000000000 +------------------0---0------------1------00001 +110000110000000000000000000000000000000000000000000000000000000000000000 +--------------------0--------------10-----00001 +011000000000000000000000000000000000000000000000000010000000000000000000 +--------------------0--------------11-----00001 +001000000000000000000000000000000000000000000000000010000000000000000000 +--------------------111------------1------00001 +001000000000000000000000000000000000000000000000000010000000000000000000 +-------------------0-0-------------1------00001 +101010000000000000000000000000000000000000000000000000000000000000000000 +------------------0--0-------------1------00001 +101010000000000000000000000000000000000000000000000000000000000000000000 +------------------11-0-------------1------00001 +100100000000000000000000000000000000000000000000000010000000000000000000 +------------------00---------------1---00-11001 +000000010000000000000000000000000000000000000000000010000000000000000000 +-----------------------------------1---01-11001 +000000100000000000000000000000000000000000000000000010000000000000000000 +------------------10---------------1---00-11001 +000000100000000000000000000000000000000000000000000010000000000000000000 +-----------------------------------1-0----11001 +000000000100000000000000000000000000000000000000000010000000000000000000 +-----------------------------------1-10---11001 +000000000100000000000000000000000000000000000000000010000000000000000000 +-----------------------------------1--1---11001 +000000001000000000000000000000000000000000000000000010000000000000000000 +-----------------------------------1-11---11001 +000000000010110001000000000000000000000000000000000010000000000000000000 +-----------------------------------1-10---11001 +000000000010100111000000000000000000000000000000000010000000000000000000 +-----------------------------------1-01---11001 +000000000010011101000000000000000000000000000000000010000000000000000000 +---------------------------11------1------11001 +000000000000000000000000000000000000000000000000000010000001000000001000 +---------------------------01------1------11001 +000000000000000000000000000000000000000000000000000010000001000000000100 +--------------------0-------1------1------11001 +000000000000000000000000000000000000000000000000000010000000000011000000 +--------------------1-------1------1------11001 +000000000000000000000000000000000000000000000000000010000000000010100000 +------------------11111------------1------11001 +110110000000000000000000000000000000000000000000000010000000000000000000 +--------------------111------------1---11-11001 +110110000000000000000000000000000000000000000000000010000000000000000000 +------------------110--------------1------11001 +111000000000000000000000000000000000000000000000000010000000000000000000 +--------------------0--------------1---11-11001 +111000000000000000000000000000000000000000000000000010000000000000000000 +------------------0-0--------------10---0-11001 +011000000000000000000000000000000000000000000000000010000000000000000000 +-------------------00--------------10---0-11001 +011000000000000000000000000000000000000000000000000010000000000000000000 +-------------------00--------------10--0--11001 +011000000000000000000000000000000000000000000000000010000000000000000000 +------------------0-0--------------10--0--11001 +011000000000000000000000000000000000000000000000000010000000000000000000 +------------------0-0--------------11---0-11001 +001000000000000000000000000000000000000000000000000010000000000000000000 +-------------------00--------------11---0-11001 +001000000000000000000000000000000000000000000000000010000000000000000000 +-------------------00--------------11--0--11001 +001000000000000000000000000000000000000000000000000010000000000000000000 +------------------0-0--------------11--0--11001 +001000000000000000000000000000000000000000000000000010000000000000000000 +------------------0-1--------------1----0-11001 +001000000000000000000000000000000000000000000000000010000000000000000000 +-------------------01--------------1----0-11001 +001000000000000000000000000000000000000000000000000010000000000000000000 +-------------------01--------------1---0--11001 +001000000000000000000000000000000000000000000000000010000000000000000000 +------------------0-1--------------1---0--11001 +001000000000000000000000000000000000000000000000000010000000000000000000 +----000--------------11------------1------11000 +000000110010000000100000000000000000000000000000000000000000000000000000 +---1--1--------------11------------1-----111000 +000000110010000000100000000000000000000000000000000000000000000000000000 +---1-1---------------11------------1-----111000 +000000110010000000100000000000000000000000000000000000000000000000000000 +----000----1----------0------------1------11000 +000000110010000000100000000000000000000000000000000000000000000000000000 +---1--1----1----------0------------1-----111000 +000000110010000000100000000000000000000000000000000000000000000000000000 +---1-1-----1----------0------------1-----111000 +000000110010000000100000000000000000000000000000000000000000000000000000 +----111-1--------------------------1------11000 +000000110000000000000000000000000000000000010000000000000000000000000000 +----1110---------------------------1------11000 +000000110000000000000000000000000000000000010000000000000000000000000000 +----010-1--------------------------1------11000 +000000110000000000000000000000000000000000010000000000000000000000000000 +----0100---------------------------1------11000 +000000110000000000000000000000000000000000010000000000000000000000000000 +----001-1--------------------------1------11000 +000000110000000000000000000000000000000000010000000000000000000000000000 +----0010---------------------------1------11000 +000000110000000000000000000000000000000000010000000000000000000000000000 +----101-1-----------------------0--1------11000 +000000110000000000000000000000000000000000010000000000000000000000000000 +----1010------------------------0--1------11000 +000000110000000000000000000000000000000000010000000000000000000000000000 +----110-1--------------------------1------11000 +000000110000000000000000000000000000000000100000000000000000000000000000 +----1100---------------------------1------11000 +000000110000000000000000000000000000000000100000000000000000000000000000 +----0-1-1--------------------------1------11000 +000000110000000000000000000000000000000000100000000000000000000000000000 +----0-10---------------------------1------11000 +000000110000000000000000000000000000000000100000000000000000000000000000 +-----01-1--------------------------1------11000 +000000110000000000000000000000000000000000100000000000000000000000000000 +-----010---------------------------1------11000 +000000110000000000000000000000000000000000100000000000000000000000000000 +---------1-----------11------00----1-----011000 +000000110000000000000000000000000001000000000000000000000000000000000000 +----100--1-----------11------00----1------11000 +000000110000000000000000000000000001000000000000000000000000000000000000 +---------1-1----------0------00----1-----011000 +000000110000000000000000000000000001000000000000000000000000000000000000 +----100--1-1----------0------00----1------11000 +000000110000000000000000000000000001000000000000000000000000000000000000 +----11--0--------------------------1------11000 +000000110000000000000000000000000010000000000000000000000000000000000000 +----11-1---------------------------1------11000 +000000110000000000000000000000000010000000000000000000000000000000000000 +----001-0--------------------------1------11000 +000000110000000000000000000000000010000000000000000000000000000000000000 +----0011---------------------------1------11000 +000000110000000000000000000000000010000000000000000000000000000000000000 +----101-0--------------------0-----1------11000 +000000110000000000000000000000000010000000000000000000000000000000000000 +----1011---------------------0-----1------11000 +000000110000000000000000000000000010000000000000000000000000000000000000 +---------1-----------11------0-----1-----011000 +000000110000000000000000000000000010000000000000000000000000000000000000 +----100--1-----------11------0-----1------11000 +000000110000000000000000000000000010000000000000000000000000000000000000 +---------1-1----------0------0-----1-----011000 +000000110000000000000000000000000010000000000000000000000000000000000000 +----100--1-1----------0------0-----1------11000 +000000110000000000000000000000000010000000000000000000000000000000000000 +----100--0-----------11------------1------11000 +000000110000000000000000000010010000000000000000000000000000000000000000 +---------0-----------11------------1-----011000 +000000110000000000000000000010010000000000000000000000000000000000000000 +----100--0-1----------0------------1------11000 +000000110000000000000000000010010000000000000000000000000000000000000000 +---------0-1----------0------------1-----011000 +000000110000000000000000000010010000000000000000000000000000000000000000 +---------1-----------11------------1-----011000 +000000110000000000000000000000000100010101000000000000000000000000000000 +----100--1-----------11------------1------11000 +000000110000000000000000000000000100010101000000000000000000000000000000 +---------1-1----------0------------1-----011000 +000000110000000000000000000000000100010101000000000000000000000000000000 +----100--1-1----------0------------1------11000 +000000110000000000000000000000000100010101000000000000000000000000000000 +----01--0--------------------------1------11000 +000000110000000000000000000000000100000000000000000000000000000000000000 +----01-1---------------------------1------11000 +000000110000000000000000000000000100000000000000000000000000000000000000 +-----01-0--------------------------1------11000 +000000110000000000000000000000000100000000000000000000000000000000000000 +-----011---------------------------1------11000 +000000110000000000000000000000000100000000000000000000000000000000000000 +-----------0------01--0------------1------11000 +000000111110111011000000000000000000000000000000000000000000000000000000 +-----------0-------0--0------------1------11000 +000000110010101111000000000000000000000000000000000000000000000000000000 +---0--1-------------011------------10----111000 +011000110010111011000000000000000000000000000000000000000000000000000000 +---0-1--------------011------------10----111000 +011000110010111011000000000000000000000000000000000000000000000000000000 +-0-0----------------011------------10-----11000 +011000110010111011000000000000000000000000000000000000000000000000000000 +---0--1---------------0------------1-----111000 +011010110000000000000000000000000000000000000000000000000000000000000000 +---0-1----------------0------------1-----111000 +011010110000000000000000000000000000000000000000000000000000000000000000 +-0-0------------------0------------1------11000 +011010110000000000000000000000000000000000000000000000000000000000000000 +---0--1-------------011------------11----111000 +001000110010111011000000000000000000000000000000000000000000000000000000 +---0-1--------------011------------11----111000 +001000110010111011000000000000000000000000000000000000000000000000000000 +-0-0----------------011------------11-----11000 +001000110010111011000000000000000000000000000000000000000000000000000000 +---0--1-------------111------------1-----111000 +001000110010111011000000000000000000000000000000000000000000000000000000 +---0-1--------------111------------1-----111000 +001000110010111011000000000000000000000000000000000000000000000000000000 +-0-0----------------111------------1------11000 +001000110010111011000000000000000000000000000000000000000000000000000000 +-----00--------------11------------1------11000 +111010110000000000000000000000000000000000000000000110100000000000000011 +---1-----------------11------------1------11000 +111010110000000000000000000000000000000000000000000110100000000000000011 +-1-0-----------------11------------1-----011000 +111010110000000000000000000000000000000000000000000110100000000000000011 +-----00----1----------0------------1------11000 +111010110000000000000000000000000000000000000000000110100000000000000011 +---1-------1----------0------------1------11000 +111010110000000000000000000000000000000000000000000110100000000000000011 +-1-0-------1----------0------------1-----011000 +111010110000000000000000000000000000000000000000000110100000000000000011 +----000----0----------0------------1------11000 +000100110000000000000000000000000000000000000000000000000000000000000000 +---1-------0----------0------------1-----111000 +000100110000000000000000000000000000000000000000000000000000000000000000 +----100----0----------0------------1------11000 +000010110000000000000000000000000000000000000000000000000000000000000000 +---1-------0-----------------------1-----011000 +000010110000000000000000000000000000000000000000000000000000000000000000 +-1-0-------0-----------------------1-----011000 +000010110000000000000000000000000000000000000000000000000000000000000000 +----------------------------1------1------11011 +000000000000000000000000000000000000000000000000000000000001000000000000 +-----------------------------------1----0-11011 +000000100000000000000000000000000000000000000000000000000000000000000000 +-----------------------------------1---0--11011 +000000010000000000000000000000000000000000000000000000000000000000000000 +-----------------------------------1-0----11011 +000000000100000000000000000000000000000000000000000000000000000000000000 +-----------------------------------1--0---11011 +000000001000000000000000000000000000000000000000000000000000000000000000 +-----------------------------------1------11011 +011000000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------------1------00100 +110100000000000000000000000000000000000000000000000000001000000100000000 +-----------------------------------1------10100 +011010000000000000000000000000000000000000000000000000010100001010100000 +---------1--1----------------00----1------01100 +000000000000000000000000000000000001000000000000000000000000000000000000 +---------1--1----------------0-----1------01100 +000000000000000000000000000000000010000000000000000000000000000000000000 +---------1--1----------------------1------01100 +111010000000000000000000000000000100010101000000000110100000000000000011 +---------0--1----------------------1------01100 +111010000000000000000000000010010000000000000000000110100000000000000011 +------------0----------------------1------01100 +111010000010000000100000000000000000000000000000000110100000000000000011 +-----------------------------------1------11100 +011100111110111011000000000000000000000000000000000000000000000000000000 +--------------------------111------1------10001 +000000010000000000000000100000000000000000000000000000000000000000000000 +--------------------------011------1------10001 +000000010000000000000000010000000000000000000000000000000000000000000000 +--------------------------101------1------10001 +000000010000000000000000001000000000000000000000000000000000000000000000 +--------------------------001------1------10001 +000000010000000000000000000100000000000000000000000000000000000000000000 +--------------------------110------1------10001 +000000010000000000000000000000000000000000000010101000000000000000000000 +--------------------------010------1------10001 +000000010000000000000000000000000000010101000000000000000000000000000000 +--------------------------100------1------10001 +000000010000000000000000000010010000000000000000000000000000000000000000 +--------------------------000------1------10001 +000000010000000000000000000010000000000000000000000000000000000000000000 +-----------------------111---------1------10001 +000000010000000000001000000000000000000000000000000000000000000000000000 +-----------------------011---------1------10001 +000000010000000000000100000000000000000000000000000000000000000000000000 +-----------------------101---------1------10001 +000000010000000000000010000000000000000000000000000000000000000000000000 +-----------------------001---------1------10001 +000000010000000000000001000000000000000000000000000000000000000000000000 +-----------------------110---------1------10001 +000000010000000000000000000000000000000000000100000000000000000000000000 +-----------------------010---------1------10001 +000000010000000000000000000000000000100000000000000000000000000000000000 +-----------------------100---------1------10001 +000000010000000000000000000001100000000000000000000000000000000000000000 +-----------------------000---------1------10001 +000000010000000000000000000001000000000000000000000000000000000000000000 +-----------0-1-----1---------------1---00-10001 +000110011110111011000000000000000000000000000000000000000000000000000000 +-----------0-1-----0---------------1---01-10001 +000110010010101111000000000000000000000000000000000000000000000000000000 +-----------1-1-----1---------------1---00-10001 +110010010000000000000000000000000000000000000000000000000000000000000000 +-----------1-1---------------------1---01-10001 +110010010000000000000000000000000000000000000000000000000000000000000000 +-------------0-----1---------------1---00-10001 +011010010000000000000000000000000000000000000000000000000000000000000000 +-------------0---------------------1---01-10001 +011010010000000000000000000000000000000000000000000000000000000000000000 +-------------------0---------------1---00-10001 +011100010010101111000000000000000000000000000000000000000000000000000000 +-------------------0---------------1---01-00111 +000110001100000000000000000000000000000000000000000000000000000000000000 +-------------------1---------------1------00111 +110010000000000000000000000000000000000000000000000000000000000000000000 +-------------------0---------------1---11-00111 +110010000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------------1------01001 +111000000000000000000000000000000000000000000000000000000000000000000000 +-------------------0---------------1---01-10111 +000100001100000000000000000000000000000000000000000000000000000000000000 +-------------------1---------------1------10111 +101110000000000000000000000000000000000000000000000000000000000000000000 +-------------------0---------------1---11-10111 +101110000000000000000000000000000000000000000000000000000000000000000000 +-----------------------------------1------00010 +111010000010000000100000000000000000000000000000000110100000000000000011 +---------1-------------------00----1------10010 +000000000000000000000000000000000001000000000000000000000000000000000000 +---------1-------------------0-----1------10010 +000000000000000000000000000000000010000000000000000000000000000000000000 +---------1-------------------------1------10010 +111010000000000000000000000000000100010101000000000110100000000000000011 +---------0-------------------------1------10010 +111010000000000000000000000010010000000000000000000110100000000000000011 +-------------------0---------------1---01-01111 +000010001100000000000000000000000000000000000000000000000000000000000000 +-------------------1---------------1------01111 +101100000000000000000000000000000000000000000000000000000000000000000000 +-------------------0---------------1---11-01111 +101100000000000000000000000000000000000000000000000000000000000000000000 +--------------11-------------------1------01010 +000000000010101100100000000001100000000000000000000000000000000000000000 +--------------01-------------------1------01010 +000000000010101100100000000001000000000000000000000000000000000000000000 +--------------10-------------------1------01010 +000000000010101100100000000000000000100000000000000000000000000000000000 +--------------00-------------------1------01010 +000000000010101100100000000000000000000000000100000000000000000000000000 +-------------------0---------------1------01010 +101000000010101100100000000000000000000000000000000000000000000000000000 +-------------------1---------------1------01010 +100100000010101100100000000000000000000000000000000000000000000000000000 +-----------11----------------------1------11010 +000000000010010110100000000001100000000000000000000000000000000000000000 +-----------01----------------------1------11010 +000000000010010110100000000001000000000000000000000000000000000000000000 +-----------10----------------------1------11010 +000000000010010110100000000000000000100000000000000000000000000000000000 +-----------00----------------------1------11010 +000000000010010110100000000000000000000000000100000000000000000000000000 +------------------0----------------1------11010 +100110000010010110100000000000000000000000000000000000000000000000000000 +------------------1----------------1------11010 +100100000010010110100000000000000000000000000000000000000000000000000000 +----11-----------------------------1------00110 +100100000010000000100000000001100000000000000000000000000000000000000000 +----01-----------------------------1------00110 +100100000010000000100000000001000000000000000000000000000000000000000000 +----10-----------------------------1------00110 +100100000010000000100000000000000000100000000000000000000000000000000000 +----00-----------------------------1------00110 +100100000010000000100000000000000000000000000100000000000000000000000000 +----------------11-----------------1------10110 +111010000000000000000000000010010000000000000000000110100000000000000011 +----------------01-----------------1------10110 +111010000000000000000000000010000000000000000000000110100000000000000011 +----------------10-----------00----1------10110 +000000000000000000000000000000000001000000000000000000000000000000000000 +----------------10-----------0-----1------10110 +000000000000000000000000000000000010000000000000000000000000000000000000 +----------------10-----------------1------10110 +111010000000000000000000000000000100010101000000000110100000000000000011 +----------------00-----------------1------10110 +111010000000000000000000000000000000000000000010101110100000000000000011 +-----------------------------------0------01110 +100000000000000000000000000000001000100000000000000110100000000000000011 +-----------------------------0-----1------11110 +000000000000000000000000000000000010000000000000000000000000000000000000 +-----------------------------------1------11110 +111010000000000000000000000000000100000000000000000000000000000000000000 diff --git a/espresso/examples/indust/tms b/espresso/examples/indust/tms new file mode 100644 index 0000000..b0b4820 --- /dev/null +++ b/espresso/examples/indust/tms @@ -0,0 +1,32 @@ +.i 8 +.o 16 +00000010 0010101111101001# ynea +00000011 1011111111001000# tam +00000100 1011111111001100# tamza +00000110 0001101111011100# a6aac +00000111 0001101111010100# dan +00000201 0001101111011100# a8/10aac +00001000 0001111111001100# tka +00001001 0001111111101000# knez +00001110 0011101111000100# ia +00100000 1010111111000010# tamiy +00100001 0011011111001100# tma +00100010 0011011111001010# tmy +00100011 0010111111001100# tya +00100100 0011101111001010# tay +00100101 0011001111011100# amaac +00100110 0011011111101000# mnez +00100111 0011010111010100# saman +00101000 0011011111010100# imac +00101001 0011010111010000# alem +00101010 0011011101011100# dman +00101011 0010111111010010# iyc +00101100 0010111101011010# dyn +00101101 0011110111010100# cpaiz +00101110 1011011111001100# xma +00101111 0011111111001100# cla +00111022 0001011110101000# tbit1 +01002222 0001111111001010# tcy +01012222 0010111110101000# ynec +01102222 0110111111000010# tcmiy +01112222 0001110111010000# alec diff --git a/espresso/examples/indust/ts10 b/espresso/examples/indust/ts10 new file mode 100644 index 0000000..e58a1bd --- /dev/null +++ b/espresso/examples/indust/ts10 @@ -0,0 +1,130 @@ +.i 22 +.o 16 +---------1------111000 1000000000000000 +----------1-----110001 1000000000000000 +-----------1----101010 1000000000000000 +------------1---100011 1000000000000000 +-------------1--011100 1000000000000000 +--------------1-010101 1000000000000000 +---------------1001110 1000000000000000 +1---------------000111 1000000000000000 +----------1-----111000 0100000000000000 +-----------1----110001 0100000000000000 +------------1---101010 0100000000000000 +-------------1--100011 0100000000000000 +--------------1-011100 0100000000000000 +---------------1010101 0100000000000000 +1---------------001110 0100000000000000 +-1--------------000111 0100000000000000 +-----------1----111000 0010000000000000 +------------1---110001 0010000000000000 +-------------1--101010 0010000000000000 +--------------1-100011 0010000000000000 +---------------1011100 0010000000000000 +1---------------010101 0010000000000000 +-1--------------001110 0010000000000000 +--1-------------000111 0010000000000000 +------------1---111000 0001000000000000 +-------------1--110001 0001000000000000 +--------------1-101010 0001000000000000 +---------------1100011 0001000000000000 +1---------------011100 0001000000000000 +-1--------------010101 0001000000000000 +--1-------------001110 0001000000000000 +---1------------000111 0001000000000000 +-------------1--111000 0000100000000000 +--------------1-110001 0000100000000000 +---------------1101010 0000100000000000 +1---------------100011 0000100000000000 +-1--------------011100 0000100000000000 +--1-------------010101 0000100000000000 +---1------------001110 0000100000000000 +----1-----------000111 0000100000000000 +--------------1-111000 0000010000000000 +---------------1110001 0000010000000000 +1---------------101010 0000010000000000 +-1--------------100011 0000010000000000 +--1-------------011100 0000010000000000 +---1------------010101 0000010000000000 +----1-----------001110 0000010000000000 +-----1----------000111 0000010000000000 +---------------1111000 0000001000000000 +1---------------110001 0000001000000000 +-1--------------101010 0000001000000000 +--1-------------100011 0000001000000000 +---1------------011100 0000001000000000 +----1-----------010101 0000001000000000 +-----1----------001110 0000001000000000 +------1---------000111 0000001000000000 +1---------------111000 0000000100000000 +-1--------------110001 0000000100000000 +--1-------------101010 0000000100000000 +---1------------100011 0000000100000000 +----1-----------011100 0000000100000000 +-----1----------010101 0000000100000000 +------1---------001110 0000000100000000 +-------1--------000111 0000000100000000 +-1--------------111000 0000000010000000 +--1-------------110001 0000000010000000 +---1------------101010 0000000010000000 +----1-----------100011 0000000010000000 +-----1----------011100 0000000010000000 +------1---------010101 0000000010000000 +-------1--------001110 0000000010000000 +--------1-------000111 0000000010000000 +--1-------------111000 0000000001000000 +---1------------110001 0000000001000000 +----1-----------101010 0000000001000000 +-----1----------100011 0000000001000000 +------1---------011100 0000000001000000 +-------1--------010101 0000000001000000 +--------1-------001110 0000000001000000 +---------1------000111 0000000001000000 +---1------------111000 0000000000100000 +----1-----------110001 0000000000100000 +-----1----------101010 0000000000100000 +------1---------100011 0000000000100000 +-------1--------011100 0000000000100000 +--------1-------010101 0000000000100000 +---------1------001110 0000000000100000 +----------1-----000111 0000000000100000 +----1-----------111000 0000000000010000 +-----1----------110001 0000000000010000 +------1---------101010 0000000000010000 +-------1--------100011 0000000000010000 +--------1-------011100 0000000000010000 +---------1------010101 0000000000010000 +----------1-----001110 0000000000010000 +-----------1----000111 0000000000010000 +-----1----------111000 0000000000001000 +------1---------110001 0000000000001000 +-------1--------101010 0000000000001000 +--------1-------100011 0000000000001000 +---------1------011100 0000000000001000 +----------1-----010101 0000000000001000 +-----------1----001110 0000000000001000 +------------1---000111 0000000000001000 +------1---------111000 0000000000000100 +-------1--------110001 0000000000000100 +--------1-------101010 0000000000000100 +---------1------100011 0000000000000100 +----------1-----011100 0000000000000100 +-----------1----010101 0000000000000100 +------------1---001110 0000000000000100 +-------------1--000111 0000000000000100 +-------1--------111000 0000000000000010 +--------1-------110001 0000000000000010 +---------1------101010 0000000000000010 +----------1-----100011 0000000000000010 +-----------1----011100 0000000000000010 +------------1---010101 0000000000000010 +-------------1--001110 0000000000000010 +--------------1-000111 0000000000000010 +--------1-------111000 0000000000000001 +---------1------110001 0000000000000001 +----------1-----101010 0000000000000001 +-----------1----100011 0000000000000001 +------------1---011100 0000000000000001 +-------------1--010101 0000000000000001 +--------------1-001110 0000000000000001 +---------------1000111 0000000000000001 diff --git a/espresso/examples/indust/vg2 b/espresso/examples/indust/vg2 new file mode 100644 index 0000000..1b8eb31 --- /dev/null +++ b/espresso/examples/indust/vg2 @@ -0,0 +1,112 @@ +.i 25 +.o 8 +1-11--------------------- 10000000 +-111--------------------- 10000000 +00-----1----------------- 10000000 +--0-001------------------ 10000000 +110----1----------------- 10000000 +1-1-----1---------------- 01000000 +-11-----1---------------- 01000000 +00--------1-------------- 01000000 +--0-00---1--------------- 01000000 +110-------1-------------- 01000000 +1-1-----1--00--00000----- 00100000 +-11-----1--00--00000----- 00100000 +00--------100--00000----- 00100000 +1-11-------11--11111----- 00100000 +-111-------11--11111----- 00100000 +00-----1---11--11111----- 00100000 +--0-00---1-00--00000----- 00100000 +110-------100--00000----- 00100000 +--0-001----11--11111----- 00100000 +110----1---11--11111----- 00100000 +1-1-----1--00000000000000 00010000 +-11-----1--00000000000000 00010000 +00--------100000000000000 00010000 +1-11-------11111111111111 00010000 +-111-------11111111111111 00010000 +00-----1---11111111111111 00010000 +--0-00---1-00000000000000 00010000 +110-------100000000000000 00010000 +--0-001----11111111111111 00010000 +110----1---11111111111111 00010000 +1-1-----1---1------------ 00001000 +-11-----1---1------------ 00001000 +00--------1-1------------ 00001000 +1-11--------0------------ 00001000 +-111--------0------------ 00001000 +00-----1----0------------ 00001000 +--0-00---1--1------------ 00001000 +110-------1-1------------ 00001000 +1-1-----1--0-------1----- 00001000 +-11-----1--0-------1----- 00001000 +00--------10-------1----- 00001000 +--0-001-----0------------ 00001000 +110----1----0------------ 00001000 +1-11-------1-------0----- 00001000 +-111-------1-------0----- 00001000 +00-----1---1-------0----- 00001000 +--0-00---1-0-------1----- 00001000 +110-------10-------1----- 00001000 +1-1-----1--0-----10------ 00001000 +-11-----1--0-----10------ 00001000 +00--------10-----10------ 00001000 +--0-001----1-------0----- 00001000 +110----1---1-------0----- 00001000 +1-11-------1-----01------ 00001000 +-111-------1-----01------ 00001000 +00-----1---1-----01------ 00001000 +--0-00---1-0-----10------ 00001000 +110-------10-----10------ 00001000 +--0-001----1-----01------ 00001000 +110----1---1-----01------ 00001000 +1-1-----1------1--------- 00000100 +-11-----1------1--------- 00000100 +00--------1----1--------- 00000100 +1-11-----------0--------- 00000100 +-111-----------0--------- 00000100 +00-----1-------0--------- 00000100 +--0-00---1-----1--------- 00000100 +110-------1----1--------- 00000100 +1-1-----1-----0---------1 00000100 +-11-----1-----0---------1 00000100 +00--------1---0---------1 00000100 +--0-001--------0--------- 00000100 +110----1-------0--------- 00000100 +1-11----------1---------0 00000100 +-111----------1---------0 00000100 +00-----1------1---------0 00000100 +--0-00---1----0---------1 00000100 +110-------1---0---------1 00000100 +1-1-----1----00--------1- 00000100 +-11-----1----00--------1- 00000100 +00--------1--00--------1- 00000100 +--0-001-------1---------0 00000100 +110----1------1---------0 00000100 +1-11---------11--------0- 00000100 +-111---------11--------0- 00000100 +00-----1-----11--------0- 00000100 +--0-00---1---00--------1- 00000100 +110-------1--00--------1- 00000100 +1-1-----1----00------10-- 00000100 +-11-----1----00------10-- 00000100 +00--------1--00------10-- 00000100 +--0-001------11--------0- 00000100 +110----1-----11--------0- 00000100 +1-11---------11------01-- 00000100 +-111---------11------01-- 00000100 +00-----1-----11------01-- 00000100 +--0-00---1---00------10-- 00000100 +110-------1--00------10-- 00000100 +--0-001------11------01-- 00000100 +110----1-----11------01-- 00000100 +1-11-------11---1111----- 00000010 +-111-------11---1111----- 00000010 +00-----1---11---1111----- 00000010 +--0-001----11---1111----- 00000010 +110----1---11---1111----- 00000010 +1-1-----1--00---0000----- 00000001 +-11-----1--00---0000----- 00000001 +00--------100---0000----- 00000001 +--0-00---1-00---0000----- 00000001 +110-------100---0000----- 00000001 diff --git a/espresso/examples/indust/vtx1 b/espresso/examples/indust/vtx1 new file mode 100644 index 0000000..f3bd1b6 --- /dev/null +++ b/espresso/examples/indust/vtx1 @@ -0,0 +1,112 @@ +.i 27 +.o 6 +-1--0-11-------1----------- 100000 +-101--11-------1----------- 100000 +-1--0-1-1------1----------- 100000 +-101--1-1------1----------- 100000 +-0--1-11----1-------------- 100000 +-010--11----1-------------- 100000 +-0--1-1-1---1-------------- 100000 +-010--1-1---1-------------- 100000 +1-----11----1-------------- 100000 +0-----11-------1----------- 100000 +1-----1-1---1-------------- 100000 +0-----1-1------1----------- 100000 +-1--0-011----1------------- 100000 +-101--011----1------------- 100000 +-1--0-0---00--1------------ 100000 +-101--0---00--1------------ 100000 +-0--11011------------------ 100000 +-010-1011------------------ 100000 +-0--1-0--100--------------- 100000 +-010--0--100--------------- 100000 +1----1011------------------ 100000 +0-----011----1------------- 100000 +1-----0--100--------------- 100000 +0-----0---00--1------------ 100000 +-1--0--00----1------------- 100000 +-101---00----1------------- 100000 +-0--11-00------------------ 100000 +-010-1-00------------------ 100000 +1----1-00------------------ 100000 +0------00----1------------- 100000 +------11-------1-01-------- 010000 +------11-------1--101------ 010000 +------11-------1--1-101---- 010000 +------1-1------1-01-------- 010000 +------1-1------1--101------ 010000 +------1-1------1--1-101---- 010000 +------11----1----10-------- 010000 +------11----1-----010------ 010000 +------11----1-----0-010---- 010000 +------1-1---1----10-------- 010000 +------1-1---1-----010------ 010000 +------1-1---1-----0-010---- 010000 +------11----1---1---------- 010000 +------11-------10---------- 010000 +------1-1---1---1---------- 010000 +------1-1------10---------- 010000 +------011----1---01-------- 010000 +------011----1----101------ 010000 +------011----1----1-101---- 010000 +------0---00--1--01-------- 010000 +------0---00--1---101------ 010000 +------0---00--1---1-101---- 010000 +-----1011--------10-------- 010000 +-----1011---------010------ 010000 +-----1011---------0-010---- 010000 +------0--100-----10-------- 010000 +------0--100------010------ 010000 +------0--100------0-010---- 010000 +-----1011-------1---------- 010000 +------011----1--0---------- 010000 +------0--100----1---------- 010000 +------0---00--1-0---------- 010000 +-------00----1---01-------- 010000 +-------00----1----101------ 010000 +-------00----1----1-101---- 010000 +-----1-00--------10-------- 010000 +-----1-00---------010------ 010000 +-----1-00---------0-010---- 010000 +-----1-00-------1---------- 010000 +-------00----1--0---------- 010000 +11111-11-------11------1--- 001000 +11111-1-1------11------1--- 001000 +11111-011----1--1------1--- 001000 +11111-0---00--1-1------1--- 001000 +11111--00----1--1------1--- 001000 +00000-11----1---0------0--- 001000 +00000-1-1---1---0------0--- 001000 +000001011-------0------0--- 001000 +00000-0--100----0------0--- 001000 +000001-00-------0------0--- 001000 +11111-11-------1-------1--- 000100 +11111-1-1------1-------1--- 000100 +11111-011----1---------1--- 000100 +11111-0---00--1--------1--- 000100 +11111--00----1---------1--- 000100 +00000-11----1----------0--- 000010 +00000-1-1---1----------0--- 000010 +000001011--------------0--- 000010 +00000-0--100-----------0--- 000010 +000001-00--------------0--- 000010 +11111-11-------1111111110-1 000001 +11111-11-------111111111-01 000001 +11111-1-1------1111111110-1 000001 +11111-1-1------111111111-01 000001 +11111-011----1--111111110-1 000001 +11111-011----1--11111111-01 000001 +11111-0---00--1-111111110-1 000001 +11111-0---00--1-11111111-01 000001 +11111--00----1--111111110-1 000001 +11111--00----1--11111111-01 000001 +00000-11----1---000000000-0 000001 +00000-11----1---00000000-00 000001 +00000-1-1---1---000000000-0 000001 +00000-1-1---1---00000000-00 000001 +000001011-------000000000-0 000001 +000001011-------00000000-00 000001 +00000-0--100----000000000-0 000001 +00000-0--100----00000000-00 000001 +000001-00-------000000000-0 000001 +000001-00-------00000000-00 000001 diff --git a/espresso/examples/indust/wim b/espresso/examples/indust/wim new file mode 100644 index 0000000..c54401f --- /dev/null +++ b/espresso/examples/indust/wim @@ -0,0 +1,18 @@ +.i 4 +.o 7 +0000 1111011 +0001 0010010 +0010 1011101 +0011 1010111 +0100 1110110 +0101 1100111 +0110 1101111 +0111 1010110 +1000 1111111 +1001 1110111 +1010 2222222 +1011 2222222 +1100 2222222 +1101 2222222 +1110 2222222 +1111 2222222 diff --git a/espresso/examples/indust/x1dn b/espresso/examples/indust/x1dn new file mode 100644 index 0000000..098015c --- /dev/null +++ b/espresso/examples/indust/x1dn @@ -0,0 +1,114 @@ +.i 27 +.o 6 +11111-011----1--111111110-1 ~~~~~1 +11111--00----1--111111110-1 ~~~~~1 +11111-0---00--1-111111110-1 ~~~~~1 +11111-1-1------1111111110-1 ~~~~~1 +11111-11-------1111111110-1 ~~~~~1 +000001011-------000000000-0 ~~~~~1 +000001-00-------000000000-0 ~~~~~1 +00000-0--100----000000000-0 ~~~~~1 +00000-1-1---1---000000000-0 ~~~~~1 +00000-11----1---000000000-0 ~~~~~1 +11111-011----1--11111111-01 ~~~~~1 +11111--00----1--11111111-01 ~~~~~1 +11111-0---00--1-11111111-01 ~~~~~1 +11111-1-1------111111111-01 ~~~~~1 +11111-11-------111111111-01 ~~~~~1 +000001011-------00000000-00 ~~~~~1 +000001-00-------00000000-00 ~~~~~1 +00000-0--100----00000000-00 ~~~~~1 +00000-1-1---1---00000000-00 ~~~~~1 +00000-11----1---00000000-00 ~~~~~1 +00000-11----1----------0--- ~~~~1~ +00000-1-1---1----------0--- ~~~~1~ +00000-0--100-----------0--- ~~~~1~ +000001-00--------------0--- ~~~~1~ +000001011--------------0--- ~~~~1~ +11111-11-------1-------1--- ~~~1~~ +11111-1-1------1-------1--- ~~~1~~ +11111-0---00--1--------1--- ~~~1~~ +11111--00----1---------1--- ~~~1~~ +11111-011----1---------1--- ~~~1~~ +000001011-------0------0--- ~~1~~~ +000001-00-------0------0--- ~~1~~~ +00000-0--100----0------0--- ~~1~~~ +00000-1-1---1---0------0--- ~~1~~~ +00000-11----1---0------0--- ~~1~~~ +11111-011----1--1------1--- ~~1~~~ +11111--00----1--1------1--- ~~1~~~ +11111-0---00--1-1------1--- ~~1~~~ +11111-1-1------11------1--- ~~1~~~ +11111-11-------11------1--- ~~1~~~ +------011----1---01-------- ~1~~~~ +-------00----1---01-------- ~1~~~~ +------0---00--1--01-------- ~1~~~~ +------1-1------1-01-------- ~1~~~~ +------11-------1-01-------- ~1~~~~ +------011----1----101------ ~1~~~~ +-------00----1----101------ ~1~~~~ +------0---00--1---101------ ~1~~~~ +------1-1------1--101------ ~1~~~~ +------11-------1--101------ ~1~~~~ +------011----1----1-101---- ~1~~~~ +-------00----1----1-101---- ~1~~~~ +------0---00--1---1-101---- ~1~~~~ +------1-1------1--1-101---- ~1~~~~ +------11-------1--1-101---- ~1~~~~ +------011----1--0---------- ~1~~~~ +-------00----1--0---------- ~1~~~~ +------0---00--1-0---------- ~1~~~~ +------1-1------10---------- ~1~~~~ +------11-------10---------- ~1~~~~ +-----1011--------10-------- ~1~~~~ +-----1-00--------10-------- ~1~~~~ +------0--100-----10-------- ~1~~~~ +------1-1---1----10-------- ~1~~~~ +------11----1----10-------- ~1~~~~ +-----1011---------010------ ~1~~~~ +-----1-00---------010------ ~1~~~~ +------0--100------010------ ~1~~~~ +------1-1---1-----010------ ~1~~~~ +------11----1-----010------ ~1~~~~ +-----1011---------0-010---- ~1~~~~ +-----1-00---------0-010---- ~1~~~~ +------0--100------0-010---- ~1~~~~ +------1-1---1-----0-010---- ~1~~~~ +------11----1-----0-010---- ~1~~~~ +-----1011-------1---------- ~1~~~~ +-----1-00-------1---------- ~1~~~~ +------0--100----1---------- ~1~~~~ +------1-1---1---1---------- ~1~~~~ +------11----1---1---------- ~1~~~~ +0-----011----1------------- 1~~~~~ +0------00----1------------- 1~~~~~ +0-----0---00--1------------ 1~~~~~ +0-----1-1------1----------- 1~~~~~ +0-----11-------1----------- 1~~~~~ +-101--011----1------------- 1~~~~~ +-101---00----1------------- 1~~~~~ +-101--0---00--1------------ 1~~~~~ +-101--0---00--1------------ 1~~~~~ +-101--0---00--1------------ 1~~~~~ +-101--1-1------1----------- 1~~~~~ +-101--11-------1----------- 1~~~~~ +-1--0-011----1------------- 1~~~~~ +-1--0--00----1------------- 1~~~~~ +-1--0-0---00--1------------ 1~~~~~ +-1--0-1-1------1----------- 1~~~~~ +-1--0-11-------1----------- 1~~~~~ +1----1011------------------ 1~~~~~ +1----1-00------------------ 1~~~~~ +1-----0--100--------------- 1~~~~~ +1-----1-1---1-------------- 1~~~~~ +1-----11----1-------------- 1~~~~~ +-010-1011------------------ 1~~~~~ +-010-1-00------------------ 1~~~~~ +-010--0--100--------------- 1~~~~~ +-010--1-1---1-------------- 1~~~~~ +-010--11----1-------------- 1~~~~~ +-0--11011------------------ 1~~~~~ +-0--11-00------------------ 1~~~~~ +-0--1-0--100--------------- 1~~~~~ +-0--1-1-1---1-------------- 1~~~~~ +-0--1-11----1-------------- 1~~~~~ diff --git a/espresso/examples/indust/x2dn b/espresso/examples/indust/x2dn new file mode 100644 index 0000000..b409234 --- /dev/null +++ b/espresso/examples/indust/x2dn @@ -0,0 +1,226 @@ +.i 82 +.o 56 +-------------------------------------------------------------------------- +-1001-00 00000000000000000000000000000000000000000000000000000001 +-------------------------------------------------------------------------- +-1-1-100 00000000000000000000000000000000000000000000000000000001 +-------------------------------------------------------------------------- +-11--100 00000000000000000000000000000000000000000000000000000001 +--------------------------------------------------11---------------------- +-------- 00000000000000000000000000000000000000000000000000000010 +--------------------------------------------------1-------1--------------- +-------- 00000000000000000000000000000000000000000000000000000100 +---------------------------------------------------1------1--------------- +-------- 00000000000000000000000000000000000000000000000000000100 +--------------------------------------------------00--1------------------- +-------- 00000000000000000000000000000000000000000000000000001000 +--------------------------------------------------1---1------------------- +-------- 00000000000000000000000000000000000000000000000000001000 +---------------------------------------------------1--1------------------- +-------- 00000000000000000000000000000000000000000000000000001000 +------------------------------------------------1-1----------------------- +-------- 00000000000000000000000000000000000000000000000000010000 +------------------------------------------------1--1---------------------- +-------- 00000000000000000000000000000000000000000000000000010000 +-----------------------------------------------------------------------1-1 +1------- 00000000000000000000000000000000000000000000000000100000 +-----------------------------------------------------------------------11- +1------- 00000000000000000000000000000000000000000000000000100000 +----------------------------------------------------------------------1100 +-------- 00000000000000000000000000000000000000000000000000100000 +--------------------------------------------------00-----------------1---- +-------- 00000000000000000000000000000000000000000000000001000000 +------------------------------------------------0--------------------1---- +-------- 00000000000000000000000000000000000000000000000001000000 +------------------------------------------------1-1----------------11----- +-------- 00000000000000000000000000000000000000000000000001000000 +------------------------------------------------1--1---------------11----- +-------- 00000000000000000000000000000000000000000000000001000000 +-------------------------------------------------------------------11----- +-------- 00000000000000000000000000000000000000000000000010000000 +---------------------------0--0--0--0--0--0--0---11--------10000000------- +-------- 00000000000000000000000000000000000000000000000100000000 +---------------------------0--0--0--0--0--0--0---1-1-------10000000------- +-------- 00000000000000000000000000000000000000000000000100000000 +---------------------------0--0--0--0--0--0--0--00-----0--1-0000000------- +-------- 00000000000000000000000000000000000000000000000100000000 +---------------------------0--0--0--0--0--0--0----00-----1--0000000------- +-------- 00000000000000000000000000000000000000000000000100000000 +---------------------------0--0--0--0--0--0--0---011-----1--0000000------- +-------- 00000000000000000000000000000000000000000000000100000000 +---------------------------1--1--1--1--1--1--1---11-----1---1111111------- +-------- 00000000000000000000000000000000000000000000000100000000 +---------------------------1--1--1--1--1--1--1---1-1----1---1111111------- +-------- 00000000000000000000000000000000000000000000000100000000 +---------------------------1--1--1--1--1--1--1--00----10----1111111------- +-------- 00000000000000000000000000000000000000000000000100000000 +---------------------------1--1--1--1--1--1--1----00-1------1111111------- +-------- 00000000000000000000000000000000000000000000000100000000 +---------------------------1--1--1--1--1--1--1---011-1------1111111------- +-------- 00000000000000000000000000000000000000000000000100000000 +-------------------------------------------------11--------1-------------- +-------- 00000000000000000000000000000000000000000000001000000000 +-------------------------------------------------1-1-------1-------------- +-------- 00000000000000000000000000000000000000000000001000000000 +------------------------------------------------00-----0--1--------------- +-------- 00000000000000000000000000000000000000000000001000000000 +--------------------------------------------------00-----1---------------- +-------- 00000000000000000000000000000000000000000000001000000000 +-------------------------------------------------011-----1---------------- +-------- 00000000000000000000000000000000000000000000001000000000 +-------------------------------------------------11-----1----------------- +-------- 00000000000000000000000000000000000000000000010000000000 +-------------------------------------------------1-1----1----------------- +-------- 00000000000000000000000000000000000000000000010000000000 +------------------------------------------------00----10------------------ +-------- 00000000000000000000000000000000000000000000010000000000 +--------------------------------------------------00-1-------------------- +-------- 00000000000000000000000000000000000000000000010000000000 +-------------------------------------------------011-1-------------------- +-------- 00000000000000000000000000000000000000000000010000000000 +------------------------------------------------011-1--------------------- +-------- 00000000000000000000000000000000000000000000100000000000 +------------------------------------------------1-1--1-------------------- +-------- 00000000000000000000000000000000000000000000100000000000 +------------------------------------------------01-11--------------------- +-------- 00000000000000000000000000000000000000000000100000000000 +------------------------------------------------1--1-1-------------------- +-------- 00000000000000000000000000000000000000000000100000000000 +------------------------------------------------1100---------------------- +-------- 00000000000000000000000000000000000000000000100000000000 +---------------------------------------------010-------------------------- +-------- 00000000000000000000000000000000000000000001000000000000 +---------------------------------------------001-------------------------- +-------- 00000000000000000000000000000000000000000001000000000000 +---------------------------------------------111-------------------------- +-------- 00000000000000000000000000000000000000000001000000000000 +---------------------------------------------100-------------------------- +-------- 00000000000000000000000000000000000000000001000000000000 +------------------------------------------010----------------------------- +-------- 00000000000000000000000000000000000000000010000000000000 +------------------------------------------001----------------------------- +-------- 00000000000000000000000000000000000000000010000000000000 +------------------------------------------111----------------------------- +-------- 00000000000000000000000000000000000000000010000000000000 +------------------------------------------100----------------------------- +-------- 00000000000000000000000000000000000000000010000000000000 +---------------------------------------010-------------------------------- +-------- 00000000000000000000000000000000000000000100000000000000 +---------------------------------------001-------------------------------- +-------- 00000000000000000000000000000000000000000100000000000000 +---------------------------------------111-------------------------------- +-------- 00000000000000000000000000000000000000000100000000000000 +---------------------------------------100-------------------------------- +-------- 00000000000000000000000000000000000000000100000000000000 +------------------------------------010----------------------------------- +-------- 00000000000000000000000000000000000000001000000000000000 +------------------------------------001----------------------------------- +-------- 00000000000000000000000000000000000000001000000000000000 +------------------------------------111----------------------------------- +-------- 00000000000000000000000000000000000000001000000000000000 +------------------------------------100----------------------------------- +-------- 00000000000000000000000000000000000000001000000000000000 +---------------------------------010-------------------------------------- +-------- 00000000000000000000000000000000000000010000000000000000 +---------------------------------001-------------------------------------- +-------- 00000000000000000000000000000000000000010000000000000000 +---------------------------------111-------------------------------------- +-------- 00000000000000000000000000000000000000010000000000000000 +---------------------------------100-------------------------------------- +-------- 00000000000000000000000000000000000000010000000000000000 +------------------------------010----------------------------------------- +-------- 00000000000000000000000000000000000000100000000000000000 +------------------------------001----------------------------------------- +-------- 00000000000000000000000000000000000000100000000000000000 +------------------------------111----------------------------------------- +-------- 00000000000000000000000000000000000000100000000000000000 +------------------------------100----------------------------------------- +-------- 00000000000000000000000000000000000000100000000000000000 +---------------------------010-------------------------------------------- +-------- 00000000000000000000000000000000000001000000000000000000 +---------------------------001-------------------------------------------- +-------- 00000000000000000000000000000000000001000000000000000000 +---------------------------111-------------------------------------------- +-------- 00000000000000000000000000000000000001000000000000000000 +---------------------------100-------------------------------------------- +-------- 00000000000000000000000000000000000001000000000000000000 +-----------------------1--0----------------------------------------------- +-------- 00000000000000000000000000000000000010000000000000000000 +------------------------1-0----------------------------------------------- +-------- 00000000000000000000000000000000000010000000000000000000 +-----------------------000------------------------------------------------ +-------- 00000000000000000000000000000000000010000000000000000000 +--------------------10---------------------------------------------------- +-------- 00000000000000000000000000000000000100000000000000000000 +--------------------1-0--------------------------------------------------- +-------- 00000000000000000000000000000000000100000000000000000000 +-----------1-------------------------------------------------------------- +-------- 00000000000000000000000000000000001000000000000000000000 +-----------0-------------------------------------------------------------- +-------- 00000000000000000000000000000001000000000000000000000000 +----------0--------------------------------------------------------------- +-------- 00000000000000000000000000000001000000000000000000000000 +---------0---------------------------------------------------------------- +-------- 00000000000000000000000000000001000000000000000000000000 +---------01--------------------------------------------------------------- +-------- 00000000000000000000000001000000010000000000000000000000 +---------10--------------------------------------------------------------- +-------- 00000000000000000000000001000000100000000000000000000000 +---------1-0-------------------------------------------------------------- +-------- 00000000000000000000000001000000100000000000000000000000 +----------10-------------------------------------------------------------- +-------- 00000000000000000000000001000000010000000000000000000000 +---------00--------------------------------------------------------------- +-------- 00000000000000000000000010000000000000000000000000000000 +---------111-------------------------------------------------------------- +-------- 00000000000000000000100000110100000000000000000000000000 +-------------------1------------------------------------------------------ +-------- 00000000000000000001000000000000000000000000000000000000 +------------------1------------------------------------------------------- +-------- 00000000000000000010000000000000000000000000000000000000 +-----------------1-------------------------------------------------------- +-------- 00000000000000000100000000000000000000000000000000000000 +----------------1--------------------------------------------------------- +-------- 00000000000000001000000000000000000000000000000000000000 +---------------1---------------------------------------------------------- +-------- 00000000000000010000000000000000000000000000000000000000 +--------------1----------------------------------------------------------- +-------- 00000000000000100000000000000000000000000000000000000000 +-------------1------------------------------------------------------------ +-------- 00000000000001000000000000000000000000000000000000000000 +------------1------------------------------------------------------------- +-------- 00000000000010000000000000000000000000000000000000000000 +---01--------------------------------------------------------------------- +-------- 00000000010000000000000000000000000000000000000000000000 +----11-------------------------------------------------------------------- +-------- 00000000010000000000000000000000000000000000000000000000 +---0-1-------------------------------------------------------------------- +-------- 00000100000000000000000000000000000000000000000000000000 +---100-------------------------------------------------------------------- +-------- 00000100000000000000000000000000000000000000000000000000 +-----1-------------------------------------------------------------------- +-------- 00001000000000000000000000000000000000000000000000000000 +----0--------------------------------------------------------------------- +-------- 00001000100000000000000000000000000000000000000000000000 +---0---------------------------------------------------------------------- +-------- 00001000000000000000000000000000000000000000000000000000 +---1----0----------------------------------------------------------------- +-------- 00010000000000000000000000000000000000000000000000000000 +----1---0----------------------------------------------------------------- +-------- 00010000000000000000000000000000000000000000000000000000 +-----1--0----------------------------------------------------------------- +-------- 00010000000000000000000000000000000000000000000000000000 +00----1001---------------------------------------------------------------- +-------- 00100000000000000000000000000000000000000000000000000000 +00----100-1--------------------------------------------------------------- +-------- 00100000000000000000000000000000000000000000000000000000 +00----100--1-------------------------------------------------------------- +-------- 00100000000000000000000000000000000000000000000000000000 +0----1100----------------------------------------------------------------- +-------- 01000000000000000000000000000000000000000000000000000000 +0---1-100----------------------------------------------------------------- +-------- 01000000000000000000000000000000000000000000000000000000 +0--1--100----------------------------------------------------------------- +-------- 01000000000000000000000000000000000000000000000000000000 +001----------------------------------------------------------------------- +-------- 10000000000000000000000000000000000000000000000000000000 diff --git a/espresso/examples/indust/x6dn b/espresso/examples/indust/x6dn new file mode 100644 index 0000000..7e521c6 --- /dev/null +++ b/espresso/examples/indust/x6dn @@ -0,0 +1,123 @@ +.i 39 +.o 5 +011100--------1------------0--------1-- 00001 +011100--------1-------------0-------1-- 00001 +011100--------0---------------------1-- 00001 +010110--------0--0---1------------1---- 00001 +010110--------0-----11------------1---- 00001 +010011--------1-0-------------------1-- 00001 +010110--------1-------0---0-0---------- 00001 +010110--------1-------0---00----------- 00001 +010110--------1--------0--0-0---------- 00001 +010110--------1--------0--00----------- 00001 +010110--------1----0--0-----0---------- 00001 +010110--------1----0--0----0----------- 00001 +010110--------1----0---0----0---------- 00001 +010110--------1----0---0---0----------- 00001 +010110--------1------------11---------- 00001 +01-100--------1------------11---------- 00001 +011001--------1---------------------11- 00001 +011000--------1-11-1-----1------------- 00001 +011000--------1-00-0-----1------------- 00001 +111101--------0------------------------ 00001 +011010-------10-11--------------------- 00001 +011010-------10-01------------------1-- 00001 +-10100--------0------------------------ 00001 +010000111-00--------------------------- 00001 +010100--------1------------0----------- 00010 +010100--------1-------------0---------- 00010 +010100--------1------------11---------- 00010 +011001--------1--1-------------------0- 00010 +-11000--------0------------------------ 00010 +011101--------0-----1------------------ 00010 +011101--------0---0-------------------- 00010 +011101--------0--1--------------------- 00010 +11101---------0------------------------ 00010 +110-1---------0------------------------ 00010 +010000111-01--------------------------- 00010 +01000011-001--------------------------- 00010 +0100001110-0--------------------------- 00010 +010001--------0-----------------------1 00110 +010010--------1------------------------ 00100 +011001-------11--1-------------------0- 00101 +011011--------0----1----1----------1--- 00100 +011011--------0----1---0-----------1--- 00100 +011010--------0--0---111----------1---- 00101 +011010--------0--0--11------------1---- 00101 +011010--------0--00--1------------1---- 00101 +011010--------0--0-0-1------------1---- 00101 +011010--------0--0---011--------------- 00100 +011010-------10-11-1------------------- 00100 +-10000--------0----------------001----- 00100 +110000--------0----------------0-1----- 00100 +-10000--------0---------------0-01----- 00100 +110000--------0---------------0--1----- 00100 +-10000--------0--------------0--01----- 00100 +110000--------0--------------0---1----- 00100 +010000--------0-----------------1------ 00110 +010000111100--------------------------- 00100 +010111--------0----1---------------1--- 01000 +010110--------0--0-1-1------------1---- 01000 +010110--------0----111------------1---- 01000 +010110--------0--0---1------------0---- 01000 +010110--------0-----11------------0---- 01000 +010011--------1-1---------------------- 01000 +010110--------1-------11---0----------- 01000 +010110--------1-------11----0---------- 01000 +0101-0--------1----1-------11---------- 01100 +110000--------0--------------111-1----- 01010 +-10000--------0--------------11101----- 01010 +0100001111-0-1------------------------- 01101 +01000011110---------------------------- 01000 +010000111-11--------------------------- 01000 +01000011-011--------------------------- 01000 +010000111010-1------------------------- 01001 +111111--------1------------------------ 11111 +11110---------1--------1--------------- 11111 +11110---------1-------1---------------- 11111 +11110---------1-------00--------------- 11110 +011110--------0------------------------ 10000 +1111-0--------0-------1---------------- 11111 +1111-0--------0--------1--------------- 11111 +1111-0--------0-------00--------------- 11110 +-10110--------0------0----------------- 11110 +-10110--------0--1--0------------------ 11110 +11011---------0------------------------ 11100 +010110--------1----1---0--10----------- 11111 +010110--------1----1---0--1-0---------- 11111 +010110--------1----1--0---10----------- 11111 +010110--------1----1--0---1-0---------- 11111 +1101-0--------1------------------------ 11111 +11001---------1------------------------ 11111 +011000--------1-1--0------------------- 11111 +011000--------1--1-0------------------- 11111 +011000--------1-10--------------------- 11111 +011000--------1--0-1------------------- 11111 +011000--------1----------0------------- 11111 +011000--------1-01--------------------- 11111 +011000--------1-0--1------------------- 11111 +11100---------1------------------------ 11111 +011011--------0--------10-------------- 11111 +011111-------00--1----1---------------- 10000 +011111-------00--1-----1--------------- 10000 +111111--------0-------1---------------- 11111 +111111--------0--------1--------------- 11111 +111111--------0-------00--------------- 11110 +-11101--------0--01-0------------------ 11111 +011010--------0--0---00---------------- 11111 +011010--------0--0---0-0--------------- 11111 +011010--------0--0110-0---------------- 11111 +011010--------0--0110--0--------------- 11111 +011010-------00--1--------------------- 10010 +1110-0--------0------------------------ 11101 +11-101--------0------------------------ 11110 +110100--------0------------------------ 11110 +11-011--------0------------------------ 11101 +010010--------0-1---------------------- 11111 +110010--------0------------------------ 11101 +010000111-10-0------------------------- 10010 +01000011-010-0------------------------- 10010 +0100001100001-------------------------- 10001 +0100001101----------------------------- 11111 +01000010------------------------------- 11000 +11000---------------------------------- 11111 diff --git a/espresso/examples/indust/x7dn b/espresso/examples/indust/x7dn new file mode 100644 index 0000000..d1424da --- /dev/null +++ b/espresso/examples/indust/x7dn @@ -0,0 +1,1246 @@ +.i 66 +.o 15 +00-0--1-110---------------------------1--------------------------- +000000000000001 +00-1--1-110--------------------------1---------------------------- +000000000000001 +00----01-10---------------------------1--------------------------- +000000000000001 +00----0011----------------------------1--------------------------- +000000000000001 +00----0000----------------------------1--------------------------- +000000000000001 +00-01---------------------------------1--------------------------- +000000000000001 +00-11--------------------------------1---------------------------- +000000000000001 +1---1---------------------------------------------1--------------- +000000000000001 +1-----0000----------------------1--------100---------------------- +000000000000001 +1-----0000---------------------1----------01---------------------- +000000000000001 +1-----0000-------------------------------110------1--------------- +000000000000001 +1-----0000-------------------------------111--------------0000011- +000000000000001 +1-----0000-------------------------------111--------------100000-1 +000000000000001 +1-----11110---------------------------------------1--------------- +000000000000001 +1-----10110---------------------------------------101------------- +000000000000001 +1-----10110---------------------------------------011------------- +000000000000001 +1-----10110---------------------------------------0001------------ +000000000000001 +1-----10110---------------------------------------1101------------ +000000000000001 +1-----10110---------------------------------------1-00------------ +000000000000001 +1-----0011----------------------1--------------------------------- +000000000000001 +1-----01-10---------------------------------------101------------- +000000000000001 +1-----01-10---------------------------------------011------------- +000000000000001 +1-----01-10---------------------------------------0001------------ +000000000000001 +1-----01-10---------------------------------------1101------------ +000000000000001 +1-----01-10---------------------------------------1-00------------ +000000000000001 +-1--1---------------------------------------------1--------------- +000000000000001 +-1----0000----------------------1--------100---------------------- +000000000000001 +-1----0000---------------------1----------01---------------------- +000000000000001 +-1----0000-------------------------------110------1--------------- +000000000000001 +-1----0000-------------------------------111--------------0000011- +000000000000001 +-1----0000-------------------------------111--------------100000-1 +000000000000001 +-1----11110---------------------------------------1--------------- +000000000000001 +-1----10110---------------------------------------101------------- +000000000000001 +-1----10110---------------------------------------011------------- +000000000000001 +-1----10110---------------------------------------0001------------ +000000000000001 +-1----10110---------------------------------------1101------------ +000000000000001 +-1----10110---------------------------------------1-00------------ +000000000000001 +-1----0011----------------------1--------------------------------- +000000000000001 +-1----01-10---------------------------------------101------------- +000000000000001 +-1----01-10---------------------------------------011------------- +000000000000001 +-1----01-10---------------------------------------0001------------ +000000000000001 +-1----01-10---------------------------------------1101------------ +000000000000001 +-1----01-10---------------------------------------1-00------------ +000000000000001 +00-0--1-110-----------------------1------------------------------- +000000000000010 +00-1--1-110----------------------1-------------------------------- +000000000000010 +00----01-10-----------------------1------------------------------- +000000000000010 +00----0011------------------------1------------------------------- +000000000000010 +00----0000------------------------1------------------------------- +000000000000010 +00-01-----------------------------1------------------------------- +000000000000010 +00-11----------------------------1-------------------------------- +000000000000010 +1---1--------------------------------------------1---------------- +000000000000010 +1-----0000------------------1------------100---------------------- +000000000000010 +1-----0000-----------------1--------------01---------------------- +000000000000010 +1-----0000-------------------------------110-----1---------------- +000000000000010 +1-----0000-------------------------------111-------------1100000-- +000000000000010 +1-----11110--------------------------------------1---------------- +000000000000010 +1-----10110--------------------------------------1-01------------- +000000000000010 +1-----10110--------------------------------------10-1------------- +000000000000010 +1-----10110--------------------------------------0111------------- +000000000000010 +1-----10110--------------------------------------00001------------ +000000000000010 +1-----10110--------------------------------------11-01------------ +000000000000010 +1-----10110--------------------------------------1-101------------ +000000000000010 +1-----10110--------------------------------------1--00------------ +000000000000010 +1-----0011------------------1------------------------------------- +000000000000010 +1-----01-10--------------------------------------1-01------------- +000000000000010 +1-----01-10--------------------------------------10-1------------- +000000000000010 +1-----01-10--------------------------------------0111------------- +000000000000010 +1-----01-10--------------------------------------00001------------ +000000000000010 +1-----01-10--------------------------------------11-01------------ +000000000000010 +1-----01-10--------------------------------------1-101------------ +000000000000010 +1-----01-10--------------------------------------1--00------------ +000000000000010 +-1--1--------------------------------------------1---------------- +000000000000010 +-1----0000------------------1------------100---------------------- +000000000000010 +-1----0000-----------------1--------------01---------------------- +000000000000010 +-1----0000-------------------------------110-----1---------------- +000000000000010 +-1----0000-------------------------------111-------------1100000-- +000000000000010 +-1----11110--------------------------------------1---------------- +000000000000010 +-1----10110--------------------------------------1-01------------- +000000000000010 +-1----10110--------------------------------------10-1------------- +000000000000010 +-1----10110--------------------------------------0111------------- +000000000000010 +-1----10110--------------------------------------00001------------ +000000000000010 +-1----10110--------------------------------------11-01------------ +000000000000010 +-1----10110--------------------------------------1-101------------ +000000000000010 +-1----10110--------------------------------------1--00------------ +000000000000010 +-1----0011------------------1------------------------------------- +000000000000010 +-1----01-10--------------------------------------1-01------------- +000000000000010 +-1----01-10--------------------------------------10-1------------- +000000000000010 +-1----01-10--------------------------------------0111------------- +000000000000010 +-1----01-10--------------------------------------00001------------ +000000000000010 +-1----01-10--------------------------------------11-01------------ +000000000000010 +-1----01-10--------------------------------------1-101------------ +000000000000010 +-1----01-10--------------------------------------1--00------------ +000000000000010 +00-0--1-110-------------------1----------------------------------- +000000000000100 +00-1--1-110------------------1------------------------------------ +000000000000100 +00----01-10-------------------1----------------------------------- +000000000000100 +00----0011--------------------1----------------------------------- +000000000000100 +00----0000--------------------1----------------------------------- +000000000000100 +00-01-------------------------1----------------------------------- +000000000000100 +00-11------------------------1------------------------------------ +000000000000100 +1---1-------------------------------------------1----------------- +000000000000100 +1-----0000--------------1----------------100---------------------- +000000000000100 +1-----0000-------------1------------------01---------------------- +000000000000100 +1-----0000-------------------------------110----1----------------- +000000000000100 +1-----11110-------------------------------------1----------------- +000000000000100 +1-----10110-------------------------------------1--01------------- +000000000000100 +1-----10110-------------------------------------1-0-1------------- +000000000000100 +1-----10110-------------------------------------10--1------------- +000000000000100 +1-----10110-------------------------------------01111------------- +000000000000100 +1-----10110-------------------------------------000001------------ +000000000000100 +1-----10110-------------------------------------11--01------------ +000000000000100 +1-----10110-------------------------------------1-1-01------------ +000000000000100 +1-----10110-------------------------------------1--101------------ +000000000000100 +1-----10110-------------------------------------1---00------------ +000000000000100 +1-----0011--------------1----------------------------------------- +000000000000100 +1-----01-10-------------------------------------1--01------------- +000000000000100 +1-----01-10-------------------------------------1-0-1------------- +000000000000100 +1-----01-10-------------------------------------10--1------------- +000000000000100 +1-----01-10-------------------------------------01111------------- +000000000000100 +1-----01-10-------------------------------------000001------------ +000000000000100 +1-----01-10-------------------------------------11--01------------ +000000000000100 +1-----01-10-------------------------------------1-1-01------------ +000000000000100 +1-----01-10-------------------------------------1--101------------ +000000000000100 +1-----01-10-------------------------------------1---00------------ +000000000000100 +-1--1-------------------------------------------1----------------- +000000000000100 +-1----0000--------------1----------------100---------------------- +000000000000100 +-1----0000-------------1------------------01---------------------- +000000000000100 +-1----0000-------------------------------110----1----------------- +000000000000100 +-1----11110-------------------------------------1----------------- +000000000000100 +-1----10110-------------------------------------1--01------------- +000000000000100 +-1----10110-------------------------------------1-0-1------------- +000000000000100 +-1----10110-------------------------------------10--1------------- +000000000000100 +-1----10110-------------------------------------01111------------- +000000000000100 +-1----10110-------------------------------------000001------------ +000000000000100 +-1----10110-------------------------------------11--01------------ +000000000000100 +-1----10110-------------------------------------1-1-01------------ +000000000000100 +-1----10110-------------------------------------1--101------------ +000000000000100 +-1----10110-------------------------------------1---00------------ +000000000000100 +-1----0011--------------1----------------------------------------- +000000000000100 +-1----01-10-------------------------------------1--01------------- +000000000000100 +-1----01-10-------------------------------------1-0-1------------- +000000000000100 +-1----01-10-------------------------------------10--1------------- +000000000000100 +-1----01-10-------------------------------------01111------------- +000000000000100 +-1----01-10-------------------------------------000001------------ +000000000000100 +-1----01-10-------------------------------------11--01------------ +000000000000100 +-1----01-10-------------------------------------1-1-01------------ +000000000000100 +-1----01-10-------------------------------------1--101------------ +000000000000100 +-1----01-10-------------------------------------1---00------------ +000000000000100 +00-0--1-110---------------1--------------------------------------- +000000000001000 +00-1--1-110--------------1---------------------------------------- +000000000001000 +00----01-10---------------1--------------------------------------- +000000000001000 +00----0011----------------1--------------------------------------- +000000000001000 +00----0000----------------1--------------------------------------- +000000000001000 +00-01---------------------1--------------------------------------- +000000000001000 +00-11--------------------1---------------------------------------- +000000000001000 +1---1------------------------------------------1------------------ +000000000001000 +1-----0000----------1--------------------100---------------------- +000000000001000 +1-----0000---------1----------------------01---------------------- +000000000001000 +1-----0000-------------------------------110---1------------------ +000000000001000 +1-----11110------------------------------------1------------------ +000000000001000 +1-----10110------------------------------------1---01------------- +000000000001000 +1-----10110------------------------------------1--0-1------------- +000000000001000 +1-----10110------------------------------------1-0--1------------- +000000000001000 +1-----10110------------------------------------10---1------------- +000000000001000 +1-----10110------------------------------------011111------------- +000000000001000 +1-----10110------------------------------------0000001------------ +000000000001000 +1-----10110------------------------------------11---01------------ +000000000001000 +1-----10110------------------------------------1-1--01------------ +000000000001000 +1-----10110------------------------------------1--1-01------------ +000000000001000 +1-----10110------------------------------------1---101------------ +000000000001000 +1-----10110------------------------------------1----00------------ +000000000001000 +1-----0011----------1--------------------------------------------- +000000000001000 +1-----01-10------------------------------------1---01------------- +000000000001000 +1-----01-10------------------------------------1--0-1------------- +000000000001000 +1-----01-10------------------------------------1-0--1------------- +000000000001000 +1-----01-10------------------------------------10---1------------- +000000000001000 +1-----01-10------------------------------------011111------------- +000000000001000 +1-----01-10------------------------------------0000001------------ +000000000001000 +1-----01-10------------------------------------11---01------------ +000000000001000 +1-----01-10------------------------------------1-1--01------------ +000000000001000 +1-----01-10------------------------------------1--1-01------------ +000000000001000 +1-----01-10------------------------------------1---101------------ +000000000001000 +1-----01-10------------------------------------1----00------------ +000000000001000 +-1--1------------------------------------------1------------------ +000000000001000 +-1----0000----------1--------------------100---------------------- +000000000001000 +-1----0000---------1----------------------01---------------------- +000000000001000 +-1----0000-------------------------------110---1------------------ +000000000001000 +-1----11110------------------------------------1------------------ +000000000001000 +-1----10110------------------------------------1---01------------- +000000000001000 +-1----10110------------------------------------1--0-1------------- +000000000001000 +-1----10110------------------------------------1-0--1------------- +000000000001000 +-1----10110------------------------------------10---1------------- +000000000001000 +-1----10110------------------------------------011111------------- +000000000001000 +-1----10110------------------------------------0000001------------ +000000000001000 +-1----10110------------------------------------11---01------------ +000000000001000 +-1----10110------------------------------------1-1--01------------ +000000000001000 +-1----10110------------------------------------1--1-01------------ +000000000001000 +-1----10110------------------------------------1---101------------ +000000000001000 +-1----10110------------------------------------1----00------------ +000000000001000 +-1----0011----------1--------------------------------------------- +000000000001000 +-1----01-10------------------------------------1---01------------- +000000000001000 +-1----01-10------------------------------------1--0-1------------- +000000000001000 +-1----01-10------------------------------------1-0--1------------- +000000000001000 +-1----01-10------------------------------------10---1------------- +000000000001000 +-1----01-10------------------------------------011111------------- +000000000001000 +-1----01-10------------------------------------0000001------------ +000000000001000 +-1----01-10------------------------------------11---01------------ +000000000001000 +-1----01-10------------------------------------1-1--01------------ +000000000001000 +-1----01-10------------------------------------1--1-01------------ +000000000001000 +-1----01-10------------------------------------1---101------------ +000000000001000 +-1----01-10------------------------------------1----00------------ +000000000001000 +00-0--1-110-----------1------------------------------------------- +000000000010000 +00-1--1-110----------1-------------------------------------------- +000000000010000 +00----01-10-----------1------------------------------------------- +000000000010000 +00----0011------------1------------------------------------------- +000000000010000 +00----0000------------1------------------------------------------- +000000000010000 +00-01-----------------1------------------------------------------- +000000000010000 +00-11----------------1-------------------------------------------- +000000000010000 +1---1-----------------------------------------1------------------- +000000000010000 +1-----0000------1------------------------100---------------------- +000000000010000 +1-----0000---1----------------------------01---------------------- +000000000010000 +1-----0000-------------------------------110--1------------------- +000000000010000 +1-----11110-----------------------------------1------------------- +000000000010000 +1-----10110-----------------------------------1----01------------- +000000000010000 +1-----10110-----------------------------------1---0-1------------- +000000000010000 +1-----10110-----------------------------------1--0--1------------- +000000000010000 +1-----10110-----------------------------------1-0---1------------- +000000000010000 +1-----10110-----------------------------------10----1------------- +000000000010000 +1-----10110-----------------------------------0111111------------- +000000000010000 +1-----10110-----------------------------------00000001------------ +000000000010000 +1-----10110-----------------------------------11----01------------ +000000000010000 +1-----10110-----------------------------------1-1---01------------ +000000000010000 +1-----10110-----------------------------------1--1--01------------ +000000000010000 +1-----10110-----------------------------------1---1-01------------ +000000000010000 +1-----10110-----------------------------------1----101------------ +000000000010000 +1-----10110-----------------------------------1-----00------------ +000000000010000 +1-----0011------1------------------------------------------------- +000000000010000 +1-----01-10-----------------------------------1----01------------- +000000000010000 +1-----01-10-----------------------------------1---0-1------------- +000000000010000 +1-----01-10-----------------------------------1--0--1------------- +000000000010000 +1-----01-10-----------------------------------1-0---1------------- +000000000010000 +1-----01-10-----------------------------------10----1------------- +000000000010000 +1-----01-10-----------------------------------0111111------------- +000000000010000 +1-----01-10-----------------------------------00000001------------ +000000000010000 +1-----01-10-----------------------------------11----01------------ +000000000010000 +1-----01-10-----------------------------------1-1---01------------ +000000000010000 +1-----01-10-----------------------------------1--1--01------------ +000000000010000 +1-----01-10-----------------------------------1---1-01------------ +000000000010000 +1-----01-10-----------------------------------1----101------------ +000000000010000 +1-----01-10-----------------------------------1-----00------------ +000000000010000 +-1--1-----------------------------------------1------------------- +000000000010000 +-1----0000------1------------------------100---------------------- +000000000010000 +-1----0000---1----------------------------01---------------------- +000000000010000 +-1----0000-------------------------------110--1------------------- +000000000010000 +-1----11110-----------------------------------1------------------- +000000000010000 +-1----10110-----------------------------------1----01------------- +000000000010000 +-1----10110-----------------------------------1---0-1------------- +000000000010000 +-1----10110-----------------------------------1--0--1------------- +000000000010000 +-1----10110-----------------------------------1-0---1------------- +000000000010000 +-1----10110-----------------------------------10----1------------- +000000000010000 +-1----10110-----------------------------------0111111------------- +000000000010000 +-1----10110-----------------------------------00000001------------ +000000000010000 +-1----10110-----------------------------------11----01------------ +000000000010000 +-1----10110-----------------------------------1-1---01------------ +000000000010000 +-1----10110-----------------------------------1--1--01------------ +000000000010000 +-1----10110-----------------------------------1---1-01------------ +000000000010000 +-1----10110-----------------------------------1----101------------ +000000000010000 +-1----10110-----------------------------------1-----00------------ +000000000010000 +-1----0011------1------------------------------------------------- +000000000010000 +-1----01-10-----------------------------------1----01------------- +000000000010000 +-1----01-10-----------------------------------1---0-1------------- +000000000010000 +-1----01-10-----------------------------------1--0--1------------- +000000000010000 +-1----01-10-----------------------------------1-0---1------------- +000000000010000 +-1----01-10-----------------------------------10----1------------- +000000000010000 +-1----01-10-----------------------------------0111111------------- +000000000010000 +-1----01-10-----------------------------------00000001------------ +000000000010000 +-1----01-10-----------------------------------11----01------------ +000000000010000 +-1----01-10-----------------------------------1-1---01------------ +000000000010000 +-1----01-10-----------------------------------1--1--01------------ +000000000010000 +-1----01-10-----------------------------------1---1-01------------ +000000000010000 +-1----01-10-----------------------------------1----101------------ +000000000010000 +-1----01-10-----------------------------------1-----00------------ +000000000010000 +00-0--1-110-------1----------------------------------------------- +000000000100000 +00-1--1-110------1------------------------------------------------ +000000000100000 +00----01-10-------1----------------------------------------------- +000000000100000 +00----0011--------1----------------------------------------------- +000000000100000 +00----0000--------1----------------------------------------------- +000000000100000 +00-01-------------1----------------------------------------------- +000000000100000 +00-11------------1------------------------------------------------ +000000000100000 +1---1----------------------------------------1-------------------- +000000000100000 +1-----0000--------------------------------01----------1----------- +000000000100000 +1-----0000-------------------------------100-----------1---------- +000000000100000 +1-----0000-------------------------------110-1-------------------- +000000000100000 +1-----0011---------------------------------------------1---------- +000000000100000 +1-----01-10----------------------------------1-----01------------- +000000000100000 +1-----01-10----------------------------------1----0-1------------- +000000000100000 +1-----01-10----------------------------------1---0--1------------- +000000000100000 +1-----01-10----------------------------------1--0---1------------- +000000000100000 +1-----01-10----------------------------------1-0----1------------- +000000000100000 +1-----01-10----------------------------------10-----1------------- +000000000100000 +1-----01-10----------------------------------01111111------------- +000000000100000 +1-----01-10----------------------------------000000001------------ +000000000100000 +1-----01-10----------------------------------11-----01------------ +000000000100000 +1-----01-10----------------------------------1-1----01------------ +000000000100000 +1-----01-10----------------------------------1--1---01------------ +000000000100000 +1-----01-10----------------------------------1---1--01------------ +000000000100000 +1-----01-10----------------------------------1----1-01------------ +000000000100000 +1-----01-10----------------------------------1-----101------------ +000000000100000 +1-----01-10----------------------------------1------00------------ +000000000100000 +1-----11110----------------------------------1-------------------- +000000000100000 +1-----10110----------------------------------1-----01------------- +000000000100000 +1-----10110----------------------------------1----0-1------------- +000000000100000 +1-----10110----------------------------------1---0--1------------- +000000000100000 +1-----10110----------------------------------1--0---1------------- +000000000100000 +1-----10110----------------------------------1-0----1------------- +000000000100000 +1-----10110----------------------------------10-----1------------- +000000000100000 +1-----10110----------------------------------01111111------------- +000000000100000 +1-----10110----------------------------------000000001------------ +000000000100000 +1-----10110----------------------------------11-----01------------ +000000000100000 +1-----10110----------------------------------1-1----01------------ +000000000100000 +1-----10110----------------------------------1--1---01------------ +000000000100000 +1-----10110----------------------------------1---1--01------------ +000000000100000 +1-----10110----------------------------------1----1-01------------ +000000000100000 +1-----10110----------------------------------1-----101------------ +000000000100000 +1-----10110----------------------------------1------00------------ +000000000100000 +1--1--00111---------------------------------------------1--------- +000000000100000 +-1--1----------------------------------------1-------------------- +000000000100000 +-1----0000--------------------------------01----------1----------- +000000000100000 +-1----0000-------------------------------100-----------1---------- +000000000100000 +-1----0000-------------------------------110-1-------------------- +000000000100000 +-1----0011---------------------------------------------1---------- +000000000100000 +-1----01-10----------------------------------1-----01------------- +000000000100000 +-1----01-10----------------------------------1----0-1------------- +000000000100000 +-1----01-10----------------------------------1---0--1------------- +000000000100000 +-1----01-10----------------------------------1--0---1------------- +000000000100000 +-1----01-10----------------------------------1-0----1------------- +000000000100000 +-1----01-10----------------------------------10-----1------------- +000000000100000 +-1----01-10----------------------------------01111111------------- +000000000100000 +-1----01-10----------------------------------000000001------------ +000000000100000 +-1----01-10----------------------------------11-----01------------ +000000000100000 +-1----01-10----------------------------------1-1----01------------ +000000000100000 +-1----01-10----------------------------------1--1---01------------ +000000000100000 +-1----01-10----------------------------------1---1--01------------ +000000000100000 +-1----01-10----------------------------------1----1-01------------ +000000000100000 +-1----01-10----------------------------------1-----101------------ +000000000100000 +-1----01-10----------------------------------1------00------------ +000000000100000 +-1----11110----------------------------------1-------------------- +000000000100000 +-1----10110----------------------------------1-----01------------- +000000000100000 +-1----10110----------------------------------1----0-1------------- +000000000100000 +-1----10110----------------------------------1---0--1------------- +000000000100000 +-1----10110----------------------------------1--0---1------------- +000000000100000 +-1----10110----------------------------------1-0----1------------- +000000000100000 +-1----10110----------------------------------10-----1------------- +000000000100000 +-1----10110----------------------------------01111111------------- +000000000100000 +-1----10110----------------------------------000000001------------ +000000000100000 +-1----10110----------------------------------11-----01------------ +000000000100000 +-1----10110----------------------------------1-1----01------------ +000000000100000 +-1----10110----------------------------------1--1---01------------ +000000000100000 +-1----10110----------------------------------1---1--01------------ +000000000100000 +-1----10110----------------------------------1----1-01------------ +000000000100000 +-1----10110----------------------------------1-----101------------ +000000000100000 +-1----10110----------------------------------1------00------------ +000000000100000 +-1-1--00111---------------------------------------------1--------- +000000000100000 +00-0--1-110-1----------------------------------------------------- +000000001000000 +00-1--1-1101------------------------------------------------------ +000000001000000 +00----01-10-1----------------------------------------------------- +000000001000000 +00----0011--1----------------------------------------------------- +000000001000000 +00----0000--1----------------------------------------------------- +000000001000000 +00-01-------1----------------------------------------------------- +000000001000000 +00-11------1------------------------------------------------------ +000000001000000 +1---1----------------------------------1-------------------------- +000000001000000 +1-----0000------------------------------1-01---------------------- +000000001000000 +1-----0000-------------------------------1001--------------------- +000000001000000 +1-----0000-----------------------------1-110---------------------- +000000001000000 +1-----0011----------------------------------1--------------------- +000000001000000 +1-----01-10----------------------------1-----------01------------- +000000001000000 +1-----01-10----------------------------1----------0-1------------- +000000001000000 +1-----01-10----------------------------1---------0--1------------- +000000001000000 +1-----01-10----------------------------1--------0---1------------- +000000001000000 +1-----01-10----------------------------1-------0----1------------- +000000001000000 +1-----01-10----------------------------1------0-----1------------- +000000001000000 +1-----01-10----------------------------1-----0------1------------- +000000001000000 +1-----01-10----------------------------0-----11111111------------- +000000001000000 +1-----01-10----------------------------0-----000000001------------ +000000001000000 +1-----01-10----------------------------1-----1------01------------ +000000001000000 +1-----01-10----------------------------1------1-----01------------ +000000001000000 +1-----01-10----------------------------1-------1----01------------ +000000001000000 +1-----01-10----------------------------1--------1---01------------ +000000001000000 +1-----01-10----------------------------1---------1--01------------ +000000001000000 +1-----01-10----------------------------1----------1-01------------ +000000001000000 +1-----01-10----------------------------1-----------101------------ +000000001000000 +1-----01-10----------------------------1------------00------------ +000000001000000 +1-----11110----------------------------1-------------------------- +000000001000000 +1-----10110----------------------------1-----------01------------- +000000001000000 +1-----10110----------------------------1----------0-1------------- +000000001000000 +1-----10110----------------------------1---------0--1------------- +000000001000000 +1-----10110----------------------------1--------0---1------------- +000000001000000 +1-----10110----------------------------1-------0----1------------- +000000001000000 +1-----10110----------------------------1------0-----1------------- +000000001000000 +1-----10110----------------------------1-----0------1------------- +000000001000000 +1-----10110----------------------------0-----11111111------------- +000000001000000 +1-----10110----------------------------0-----000000001------------ +000000001000000 +1-----10110----------------------------1-----1------01------------ +000000001000000 +1-----10110----------------------------1------1-----01------------ +000000001000000 +1-----10110----------------------------1-------1----01------------ +000000001000000 +1-----10110----------------------------1--------1---01------------ +000000001000000 +1-----10110----------------------------1---------1--01------------ +000000001000000 +1-----10110----------------------------1----------1-01------------ +000000001000000 +1-----10110----------------------------1-----------101------------ +000000001000000 +1-----10110----------------------------1------------00------------ +000000001000000 +-1--1----------------------------------1-------------------------- +000000001000000 +-1----0000------------------------------1-01---------------------- +000000001000000 +-1----0000-------------------------------1001--------------------- +000000001000000 +-1----0000-----------------------------1-110---------------------- +000000001000000 +-1----0011----------------------------------1--------------------- +000000001000000 +-1----01-10----------------------------1-----------01------------- +000000001000000 +-1----01-10----------------------------1----------0-1------------- +000000001000000 +-1----01-10----------------------------1---------0--1------------- +000000001000000 +-1----01-10----------------------------1--------0---1------------- +000000001000000 +-1----01-10----------------------------1-------0----1------------- +000000001000000 +-1----01-10----------------------------1------0-----1------------- +000000001000000 +-1----01-10----------------------------1-----0------1------------- +000000001000000 +-1----01-10----------------------------0-----11111111------------- +000000001000000 +-1----01-10----------------------------0-----000000001------------ +000000001000000 +-1----01-10----------------------------1-----1------01------------ +000000001000000 +-1----01-10----------------------------1------1-----01------------ +000000001000000 +-1----01-10----------------------------1-------1----01------------ +000000001000000 +-1----01-10----------------------------1--------1---01------------ +000000001000000 +-1----01-10----------------------------1---------1--01------------ +000000001000000 +-1----01-10----------------------------1----------1-01------------ +000000001000000 +-1----01-10----------------------------1-----------101------------ +000000001000000 +-1----01-10----------------------------1------------00------------ +000000001000000 +-1----11110----------------------------1-------------------------- +000000001000000 +-1----10110----------------------------1-----------01------------- +000000001000000 +-1----10110----------------------------1----------0-1------------- +000000001000000 +-1----10110----------------------------1---------0--1------------- +000000001000000 +-1----10110----------------------------1--------0---1------------- +000000001000000 +-1----10110----------------------------1-------0----1------------- +000000001000000 +-1----10110----------------------------1------0-----1------------- +000000001000000 +-1----10110----------------------------1-----0------1------------- +000000001000000 +-1----10110----------------------------0-----11111111------------- +000000001000000 +-1----10110----------------------------0-----000000001------------ +000000001000000 +-1----10110----------------------------1-----1------01------------ +000000001000000 +-1----10110----------------------------1------1-----01------------ +000000001000000 +-1----10110----------------------------1-------1----01------------ +000000001000000 +-1----10110----------------------------1--------1---01------------ +000000001000000 +-1----10110----------------------------1---------1--01------------ +000000001000000 +-1----10110----------------------------1----------1-01------------ +000000001000000 +-1----10110----------------------------1-----------101------------ +000000001000000 +-1----10110----------------------------1------------00------------ +000000001000000 +00-0-11-110------------------------------------------------------- +000000010000000 +0011--1-110------------------------------------------------------- +000000010000000 +00---101-10------------------------------------------------------- +000000010000000 +00---10011-------------------------------------------------------- +000000010000000 +00---10000-------------------------------------------------------- +000000010000000 +00-011------------------------------------------------------------ +000000010000000 +00111------------------------------------------------------------- +000000010000000 +1--11--------------------------------1---------------------------- +000000010000000 +1--01---------------------------------1--------------------------- +000000010000000 +1-----0000----------------------------1--------------------------- +000000010000000 +1--1--1-110--------------------------1---------------------------- +000000010000000 +1--0--1-110---------------------------1--------------------------- +000000010000000 +1-----0011----------------------------1--------------------------- +000000010000000 +1-----01-10---------------------------1--------------------------- +000000010000000 +-1-11--------------------------------1---------------------------- +000000010000000 +-1-01---------------------------------1--------------------------- +000000010000000 +-1----0000----------------------------1--------------------------- +000000010000000 +-1-1--1-110--------------------------1---------------------------- +000000010000000 +-1-0--1-110---------------------------1--------------------------- +000000010000000 +-1----0011----------------------------1--------------------------- +000000010000000 +-1----01-10---------------------------1--------------------------- +000000010000000 +00----1-110---0--------------------1------------------------------ +000000100000000 +00-0--1-110---10-------------------1------------------------------ +000000100000000 +00-1--1-110-------------------------1----------------------------- +000000100000000 +00----01-10------------------------1------------------------------ +000000100000000 +00----0011-------------------------1------------------------------ +000000100000000 +00----0000-------------------------1------------------------------ +000000100000000 +00--1---------0--------------------1------------------------------ +000000100000000 +00-01---------10-------------------1------------------------------ +000000100000000 +00-11-------------------------------1----------------------------- +000000100000000 +1--11----------------------------1-------------------------------- +000000100000000 +1--01-----------------------------1------------------------------- +000000100000000 +1-----0000------------------------1------------------------------- +000000100000000 +1--1--1-110----------------------1-------------------------------- +000000100000000 +1--0--1-110-----------------------1------------------------------- +000000100000000 +1-----0011------------------------1------------------------------- +000000100000000 +1-----01-10-----------------------1------------------------------- +000000100000000 +-1-11----------------------------1-------------------------------- +000000100000000 +-1-01-----------------------------1------------------------------- +000000100000000 +-1----0000------------------------1------------------------------- +000000100000000 +-1-1--1-110----------------------1-------------------------------- +000000100000000 +-1-0--1-110-----------------------1------------------------------- +000000100000000 +-1----0011------------------------1------------------------------- +000000100000000 +-1----01-10-----------------------1------------------------------- +000000100000000 +00----1-110---0----------------1---------------------------------- +000001000000000 +00-0--1-110---10---------------1---------------------------------- +000001000000000 +00-1--1-110---------------------1--------------------------------- +000001000000000 +00----01-10--------------------1---------------------------------- +000001000000000 +00----0011---------------------1---------------------------------- +000001000000000 +00----0000---------------------1---------------------------------- +000001000000000 +00--1---------0----------------1---------------------------------- +000001000000000 +00-01---------10---------------1---------------------------------- +000001000000000 +00-11---------------------------1--------------------------------- +000001000000000 +1--11------------------------1------------------------------------ +000001000000000 +1--01-------------------------1----------------------------------- +000001000000000 +1-----0000--------------------1----------------------------------- +000001000000000 +1--1--1-110------------------1------------------------------------ +000001000000000 +1--0--1-110-------------------1----------------------------------- +000001000000000 +1-----0011--------------------1----------------------------------- +000001000000000 +1-----01-10-------------------1----------------------------------- +000001000000000 +-1-11------------------------1------------------------------------ +000001000000000 +-1-01-------------------------1----------------------------------- +000001000000000 +-1----0000--------------------1----------------------------------- +000001000000000 +-1-1--1-110------------------1------------------------------------ +000001000000000 +-1-0--1-110-------------------1----------------------------------- +000001000000000 +-1----0011--------------------1----------------------------------- +000001000000000 +-1----01-10-------------------1----------------------------------- +000001000000000 +00----1-110---0------------1-------------------------------------- +000010000000000 +00-0--1-110---10-----------1-------------------------------------- +000010000000000 +00-1--1-110-----------------1------------------------------------- +000010000000000 +00----01-10----------------1-------------------------------------- +000010000000000 +00----0011-----------------1-------------------------------------- +000010000000000 +00----0000-----------------1-------------------------------------- +000010000000000 +00--1---------0------------1-------------------------------------- +000010000000000 +00-01---------10-----------1-------------------------------------- +000010000000000 +00-11-----------------------1------------------------------------- +000010000000000 +1--11--------------------1---------------------------------------- +000010000000000 +1--01---------------------1--------------------------------------- +000010000000000 +1-----0000----------------1--------------------------------------- +000010000000000 +1--1--1-110--------------1---------------------------------------- +000010000000000 +1--0--1-110---------------1--------------------------------------- +000010000000000 +1-----0011----------------1--------------------------------------- +000010000000000 +1-----01-10---------------1--------------------------------------- +000010000000000 +-1-11--------------------1---------------------------------------- +000010000000000 +-1-01---------------------1--------------------------------------- +000010000000000 +-1----0000----------------1--------------------------------------- +000010000000000 +-1-1--1-110--------------1---------------------------------------- +000010000000000 +-1-0--1-110---------------1--------------------------------------- +000010000000000 +-1----0011----------------1--------------------------------------- +000010000000000 +-1----01-10---------------1--------------------------------------- +000010000000000 +00----1-110---0--------1------------------------------------------ +000100000000000 +00-0--1-110---10-------1------------------------------------------ +000100000000000 +00-1--1-110-------------1----------------------------------------- +000100000000000 +00----01-10------------1------------------------------------------ +000100000000000 +00----0011-------------1------------------------------------------ +000100000000000 +00----0000-------------1------------------------------------------ +000100000000000 +00--1---------0--------1------------------------------------------ +000100000000000 +00-01---------10-------1------------------------------------------ +000100000000000 +00-11-------------------1----------------------------------------- +000100000000000 +1--11----------------1-------------------------------------------- +000100000000000 +1--01-----------------1------------------------------------------- +000100000000000 +1-----0000------------1------------------------------------------- +000100000000000 +1--1--1-110----------1-------------------------------------------- +000100000000000 +1--0--1-110-----------1------------------------------------------- +000100000000000 +1-----0011------------1------------------------------------------- +000100000000000 +1-----01-10-----------1------------------------------------------- +000100000000000 +-1-11----------------1-------------------------------------------- +000100000000000 +-1-01-----------------1------------------------------------------- +000100000000000 +-1----0000------------1------------------------------------------- +000100000000000 +-1-1--1-110----------1-------------------------------------------- +000100000000000 +-1-0--1-110-----------1------------------------------------------- +000100000000000 +-1----0011------------1------------------------------------------- +000100000000000 +-1----01-10-----------1------------------------------------------- +000100000000000 +00----1-110---0----1---------------------------------------------- +001000000000000 +00-0--1-110---10---1---------------------------------------------- +001000000000000 +00-1--1-110---------1--------------------------------------------- +001000000000000 +00----01-10--------1---------------------------------------------- +001000000000000 +00----0011---------1---------------------------------------------- +001000000000000 +00----0000---------1---------------------------------------------- +001000000000000 +00--1---------0----1---------------------------------------------- +001000000000000 +00-01---------10---1---------------------------------------------- +001000000000000 +00-11---------------1--------------------------------------------- +001000000000000 +1--11------------1------------------------------------------------ +001000000000000 +1--01-------------1----------------------------------------------- +001000000000000 +1-----0000--------1----------------------------------------------- +001000000000000 +1--1--1-110------1------------------------------------------------ +001000000000000 +1--0--1-110-------1----------------------------------------------- +001000000000000 +1-----0011--------1----------------------------------------------- +001000000000000 +1-----01-10-------1----------------------------------------------- +001000000000000 +-1-11------------1------------------------------------------------ +001000000000000 +-1-01-------------1----------------------------------------------- +001000000000000 +-1----0000--------1----------------------------------------------- +001000000000000 +-1-1--1-110------1------------------------------------------------ +001000000000000 +-1-0--1-110-------1----------------------------------------------- +001000000000000 +-1----0011--------1----------------------------------------------- +001000000000000 +-1----01-10-------1----------------------------------------------- +001000000000000 +00----1-110--10--------------------------------------------------- +010000000000000 +00-0--1-110--110-------------------------------------------------- +010000000000000 +00-1--1-110-----1------------------------------------------------- +010000000000000 +00----01-10--1---------------------------------------------------- +010000000000000 +00----0011---1---------------------------------------------------- +010000000000000 +00----0000---1---------------------------------------------------- +010000000000000 +00--1--------10--------------------------------------------------- +010000000000000 +00-01--------110-------------------------------------------------- +010000000000000 +00-11-----------1------------------------------------------------- +010000000000000 +1--11------1------------------------------------------------------ +010000000000000 +1--01-------1----------------------------------------------------- +010000000000000 +1-----0000--1----------------------------------------------------- +010000000000000 +1--1--1-1101------------------------------------------------------ +010000000000000 +1--0--1-110-1----------------------------------------------------- +010000000000000 +1-----0011--1----------------------------------------------------- +010000000000000 +1-----01-10-1----------------------------------------------------- +010000000000000 +-1-11------1------------------------------------------------------ +010000000000000 +-1-01-------1----------------------------------------------------- +010000000000000 +-1----0000--1----------------------------------------------------- +010000000000000 +-1-1--1-1101------------------------------------------------------ +010000000000000 +-1-0--1-110-1----------------------------------------------------- +010000000000000 +-1----0011--1----------------------------------------------------- +010000000000000 +-1----01-10-1----------------------------------------------------- +010000000000000 +1-111------------------------------------------------------------- +100000000000000 +1--011------------------------------------------------------------ +100000000000000 +1----10000-------------------------------------------------------- +100000000000000 +1-11--1-110------------------------------------------------------- +100000000000000 +1--0-11-110------------------------------------------------------- +100000000000000 +1----10011-------------------------------------------------------- +100000000000000 +1----101-10------------------------------------------------------- +100000000000000 +-1111------------------------------------------------------------- +100000000000000 +-1-011------------------------------------------------------------ +100000000000000 +-1---10000-------------------------------------------------------- +100000000000000 +-111--1-110------------------------------------------------------- +100000000000000 +-1-0-11-110------------------------------------------------------- +100000000000000 +-1---10011-------------------------------------------------------- +100000000000000 +-1---101-10------------------------------------------------------- +100000000000000 diff --git a/espresso/examples/indust/x9dn b/espresso/examples/indust/x9dn new file mode 100644 index 0000000..92fad26 --- /dev/null +++ b/espresso/examples/indust/x9dn @@ -0,0 +1,122 @@ +.i 27 +.o 7 +000000-011----1--0--------- 0000001 +000000--00----1--0--------- 0000001 +000000-0---00--1-0--------- 0000001 +000000-1-1------10--------- 0000001 +000000-11-------10--------- 0000001 +1111111011-------1--------- 0000001 +1111111-00-------1--------- 0000001 +111111-0--100----1--------- 0000001 +111111-1-1---1---1--------- 0000001 +111111-11----1---1--------- 0000001 +000000-11-------10000000--0 0000010 +000000-1-1------10000000--0 0000010 +000000-0---00--1-0000000--0 0000010 +000000--00----1--0000000--0 0000010 +000000-011----1--0000000--0 0000010 +111111-11----1---1111111--1 0000010 +111111-1-1---1---1111111--1 0000010 +111111-0--100----1111111--1 0000010 +1111111-00-------1111111--1 0000010 +1111111011-------1111111--1 0000010 +1111111011-------11111110-1 0000100 +1111111-00-------11111110-1 0000100 +111111-0--100----11111110-1 0000100 +111111-1-1---1---11111110-1 0000100 +111111-11----1---11111110-1 0000100 +000000-011----1--00000000-0 0000100 +000000--00----1--00000000-0 0000100 +000000-0---00--1-00000000-0 0000100 +000000-1-1------100000000-0 0000100 +000000-11-------100000000-0 0000100 +1111111011-------1111111-01 0000100 +1111111-00-------1111111-01 0000100 +111111-0--100----1111111-01 0000100 +111111-1-1---1---1111111-01 0000100 +111111-11----1---1111111-01 0000100 +000000-011----1--0000000-00 0000100 +000000--00----1--0000000-00 0000100 +000000-0---00--1-0000000-00 0000100 +000000-1-1------10000000-00 0000100 +000000-11-------10000000-00 0000100 +-----01011----------------- 0001000 +-----01-00----------------- 0001000 +-----0-0--100-------------- 0001000 +-----0-1-1---1------------- 0001000 +-----0-11----1------------- 0001000 +-01-1-1011----------------- 0001000 +-01-1-1-00----------------- 0001000 +-01-1--0--100-------------- 0001000 +-01-1--1-1---1------------- 0001000 +-01-1--11----1------------- 0001000 +---01-1011----------------- 0001000 +---01-1-00----------------- 0001000 +---01--0--100-------------- 0001000 +---01--1-1---1------------- 0001000 +---01--11----1------------- 0001000 +-----1-011----1------------ 0001000 +-----1--00----1------------ 0001000 +-----1-0---00--1----------- 0001000 +-----1-1-1------1---------- 0001000 +-----1-11-------1---------- 0001000 +-10-0--011----1------------ 0001000 +-10-0---00----1------------ 0001000 +-10-0--0---00--1----------- 0001000 +-10-0--1-1------1---------- 0001000 +-10-0--11-------1---------- 0001000 +---10--011----1------------ 0001000 +---10---00----1------------ 0001000 +---10--0---00--1----------- 0001000 +---10--1-1------1---------- 0001000 +---10--11-------1---------- 0001000 +------1011--------01------- 0010000 +------1-00--------01------- 0010000 +-------0--100-----01------- 0010000 +-------1-1---1----01------- 0010000 +-------11----1----01------- 0010000 +------1011---------101----- 0010000 +------1-00---------101----- 0010000 +-------0--100------101----- 0010000 +-------1-1---1-----101----- 0010000 +-------11----1-----101----- 0010000 +------1011---------1-101--- 0010000 +------1-00---------1-101--- 0010000 +-------0--100------1-101--- 0010000 +-------1-1---1-----1-101--- 0010000 +-------11----1-----1-101--- 0010000 +------1011-------0--------- 0010000 +------1-00-------0--------- 0010000 +-------0--100----0--------- 0010000 +-------1-1---1---0--------- 0010000 +-------11----1---0--------- 0010000 +-------011----1---10------- 0010000 +--------00----1---10------- 0010000 +-------0---00--1--10------- 0010000 +-------1-1------1-10------- 0010000 +-------11-------1-10------- 0010000 +-------011----1----010----- 0010000 +--------00----1----010----- 0010000 +-------0---00--1---010----- 0010000 +-------1-1------1--010----- 0010000 +-------11-------1--010----- 0010000 +-------011----1----0-010--- 0010000 +--------00----1----0-010--- 0010000 +-------0---00--1---0-010--- 0010000 +-------1-1------1--0-010--- 0010000 +-------11-------1--0-010--- 0010000 +-------011----1--1--------- 0010000 +--------00----1--1--------- 0010000 +-------0---00--1-1--------- 0010000 +-------1-1------11--------- 0010000 +-------11-------11--------- 0010000 +000000-11-------1---------- 0100000 +000000-1-1------1---------- 0100000 +000000-0---00--1----------- 0100000 +000000--00----1------------ 0100000 +000000-011----1------------ 0100000 +111111-11----1------------- 1000000 +111111-1-1---1------------- 1000000 +111111-0--100-------------- 1000000 +1111111-00----------------- 1000000 +1111111011----------------- 1000000 diff --git a/espresso/examples/indust/xparc b/espresso/examples/indust/xparc new file mode 100644 index 0000000..26d949e --- /dev/null +++ b/espresso/examples/indust/xparc @@ -0,0 +1,1106 @@ +.i 41 +.o 73 +.p 551 +--------0010----------------------------- +0000000000000001001000101001110001111000000000000000000000000000000000000 +--------0011----------------------------- +0000000000000001001100101001110001111000000000000000000000000000000000000 +--------0101----------------------------- +0000000010010101001100101000110000011000000000010000000000000000000000010 +--------0100----------------------------- +0000000010010101001100101000110000011000000000010000000000000000000000010 +--------0110----------------------------- +0000000000000000100000101001010000100110000000000000000000000000000000001 +--------0111----------------------------- +0000000010010101101100101000110000011000000000010000000000000000000000000 +--------0000------------------------1---- +0000000000000000100000101001010000100110000000000000000000000000000000001 +000001--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000001--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000010--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000010--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000011--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000011--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000100--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000100--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000101--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000101--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000110--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000110--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000111--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +000111--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001000--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001000--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001001--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001001--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001010--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001010--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001011--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001011--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001100--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001100--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001101--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001101--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001110--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001110--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001111--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +001111--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +010000--000001010000----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +010000--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100100000000000000000000 +010001--000001011001----------------0---- +1000111100000000100010001111010000100110000000000100110000000000000000000 +010001--000001010000----------------0---- +0000000000000010000010000001010000100110000000000101000000000000000000000 +010010--000001011001----------------0---- +0000000000000010000010000001010000100110000000000101000000000000000000000 +100000--000001010000----------------0---- +0000000000000010000010001111010000100110000000000000000000000000000000000 +100000--000001011001----------------0---- +0000000000000010000010001111010000100110000000000000000000000000000000000 +000001--000001001111----------------0---- +1000001100000000100010000011010000100110000000000101100000000000000000000 +000001--000001010001----------------0---- +1000001100000000100010000011010000100110000000000101100000000000000000000 +000001--000001011000----------------0---- +1000001100000000100010000011010000100110000000000101111011000000000000000 +000010--000001011000----------------0---- +1000001100000000100010001111010000100110000000000110000000000000000000000 +000010--000001001111----------------0---- +1000001100000000100010001111010000100110000000000110001011000000000000000 +000010--000001010001----------------0---- +1000001100000000100010001111010000100110000000000110001011000000000000000 +000011--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000011--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000011--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000100--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000100--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000100--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000101--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000101--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000101--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000110--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000110--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000110--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000111--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000111--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +000111--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001000--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001000--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001000--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001001--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001001--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001001--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001010--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001010--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001010--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001011--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001011--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001011--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001100--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001100--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001100--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001101--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001101--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001101--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001110--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001110--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001110--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001111--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001111--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +001111--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010000--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010000--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010000--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010001--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010001--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010001--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010010--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010010--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010010--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010011--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010011--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010011--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010100--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010100--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010100--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010101--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010101--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010101--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010110--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010110--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010110--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010111--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010111--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +010111--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011000--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011000--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011000--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011001--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011001--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011001--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011010--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011010--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011010--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011011--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011011--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011011--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011100--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011100--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011100--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011101--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011101--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011101--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011110--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011110--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011110--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011111--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011111--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +011111--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +100000--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +100000--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +100000--000001010001----------------0---- +1000111100000000100010001111010000100110000000000110000000000000000000000 +100001--000001011000----------------0---- +1000111100000000100010001111010000100110000000000110100000000000000000000 +100001--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110100000000000000000000 +100001--000001001111----------------0---- +1000111100000000100010001111010000100110000000000110110000000000000000000 +100010--000001011000----------------0---- +1000111100000000100010001111010000100110000000000111000000000000000000000 +100010--000001001111----------------0---- +1000111100000000100010001111010000100110000000000111000000000000000000000 +100010--000001001111----------------0---- +1000111100000000100010001111010000100110000000000111000000000000000000000 +100011--000001011000----------------0---- +0000000000000000100010001101010000100110000000000101000000000000000000000 +100011--000001001111----------------0---- +0000000000000000100010001101010000100110000000000101000000000000000000000 +100011--000001001111----------------0---- +0000000000000000100010001101010000100110000000000101000000000000000000000 +100100--000001011000----------------0---- +1000110000000010000010001101010000100110010000000001100000000000000000000 +100100--000001001111----------------0---- +1000110000000010000010001101010000100110010000000001100000000000000000000 +100100--000001001111----------------0---- +1000110000000010000010001101010000100110010000000001100000000000000000000 +000001--00001000011011--------------0---- +0000000000000010000000101001010000100110000000000000000000000000000000000 +000001--00001000011001101--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000001--000010000110010-1--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000001--00001000011001110--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000001--000010000110011110-0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000001--00001000011001111-11--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000001--000010000110011111-0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000001--00001000011001101--1--------0---- +0000000100011100100000101001010000100110000010000000000000000000001010000 +000001--000010000110010-1--1--------0---- +0000000100011100100000101001010000100110000010000000000000000000001010000 +000001--00001000011001110--1--------0---- +0000000100011100100000101001010000100110000010000000000000000000001010000 +000001--00001000011001111-01--------0---- +0000000100011100100000101001010000100110000010000000000000000000001010000 +000001--00001000011001100--0--------0---- +0000000100011100100000101001010000100110000010000000000000000000001010000 +000001--000010000110010-0--0--------0---- +0000000100011100100000101001010000100110000010000000000000000000001010000 +000001--00001000011010-----0--------0---- +0000000100011100100000101001010000100110000010000000000000000000001010000 +000001--00001000011001100--1--------0---- +0000000100011100100000101001010000100110000011000000000000000000001010000 +000001--000010000110010-0--1--------0---- +0000000100011100100000101001010000100110000011000000000000000000001010000 +000001--00001000011010-----1--------0---- +0000000100011100100000101001010000100110000011000000000000000000001010000 +000010--00001000011001101--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--000010000110010-1--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--00001000011001110--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--000010000110011110-0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--00001000011001111-11--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--000010000110011111-0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--00001000011001101--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--000010000110010-1--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--00001000011001110--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--00001000011001111-01--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--00001000011001100--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--000010000110010-0--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--00001000011010-----0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--00001000011001100--1--------0---- +0000000100011000100000101001010000100110000010010000000000000000001010000 +000010--000010000110010-0--1--------0---- +0000000100011000100000101001010000100110000010010000000000000000001010000 +000010--00001000011010-----1--------0---- +0000000100011000100000101001010000100110000010010000000000000000001010000 +000011--00001000011001101--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--000010000110010-1--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--00001000011001110--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--000010000110011110-0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--00001000011001111-11--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--000010000110011111-0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--00001000011001101--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--000010000110010-1--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--00001000011001110--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--00001000011001111-01--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--00001000011001100--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--000010000110010-0--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--00001000011010-----0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--00001000011001100--1--------0---- +0000000100010100100000101001010000100110000010000000000000000000001010000 +000011--000010000110010-0--1--------0---- +0000000100010100100000101001010000100110000010000000000000000000001010000 +000011--00001000011010-----1--------0---- +0000000100010100100000101001010000100110000010000000000000000000001010000 +000100--00001000011001101--0--------0---- +0000000000000010000000101001010000100110010010100000000000000000000100000 +000100--000010000110010-1--0--------0---- +0000000000000010000010000001010000100110000010100000000000000000000100000 +000100--00001000011001110--0--------0---- +0000000000000010000010000001010000100110000010100000000000000000000100000 +000100--000010000110011110-0--------0---- +0000000000000010000010000001010000100110000010100000000000000000000100000 +000100--00001000011001111-11--------0---- +0000000000000000100010000001010000100110000010100000000000000000000100000 +000100--000010000110011111-0--------0---- +0000000000000000100010000001010000100110000010100000000000000000000100000 +000100--00001000011001101--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--000010000110010-1--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--00001000011001110--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--00001000011001111-01--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--00001000011001100--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--000010000110010-0--0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--00001000011010-----0--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--00001000011001100--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--000010000110010-0--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--00001000011010-----1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000101--00001000011001111-11--------0---- +0000000000000010000010000011010000100110000110110000000000000000000100000 +000101--000010000110011111-0--------0---- +0000000000000010000010000011010000100110000110110000000000000000000100000 +000101--00001000011001101--1--------0---- +0000000000000010000000101001010000100110011010100000000000000000000100000 +000101--00001000011001100--0--------0---- +0000000000000010000000101001010000100110011010100000000000000000000100000 +000101--000010000110010-1--1--------0---- +0000000000000000100010001111010000100110000010100000000000000000000100000 +000101--00001000011001110--1--------0---- +0000000000000000100010001111010000100110000010100000000000000000000100000 +000101--00001000011001111-01--------0---- +0000000000000010000010001111010000100110010010100000000000000000000100000 +000101--000010000110010-0--0--------0---- +0000000000000010000010001111010000100110010010100000000000000000000100000 +000101--00001000011010-----0--------0---- +0000000000000010000010001111010000100110010010100000000000000000001000000 +000101--00001000011001100--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000101--000010000110010-0--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000101--00001000011010-----1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000110--000010000110010-1--1--------0---- +0000000000000010000010000001010000100110000010110000000000000000000100000 +000110--00001000011001110--1--------0---- +0000000000000010000010000001010000100110000010110000000000000000000100000 +000110--00001000011001100--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000110--000010000110010-0--1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000110--00001000011010-----1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000111--00001000011001100--1--------0---- +0000000000000000100000101001010000100110011010100000000000000000000100000 +000111--000010000110010-0--1--------0---- +0000000000000000100010001011010000100110000010100000000000000000000100000 +000111--00001000011010-----1--------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +001000--00001000011001100--1--------0---- +0000000000000010000000101001010000100110011010100000000000000000000100000 +001000--000010000110010-0--1--------0---- +0000000000000010000010001101010000100110011010110000000000000000000100000 +001000--00001000011010-----1--------0---- +0000000000000000100010001011010000100110000010100000000000000000001000000 +001001--00001000011010-----1--------0---- +0000000000000010000010001101010000100110011010110000000000000000001000000 +000001--000010010011----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--000010010011----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--000010010011----------------0---- +0000000000000010000000101001010000100110010000000000000000000000000000000 +000001--000001010110----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--000001010110----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--000001010110----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--000001010110----------------0---- +0000000000000000001100101001010000100110010000000000000000000000000000000 +000001--000001010100----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--000001010100----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--000001010100----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--000001010100----------------0---- +0000000000000000101100101001010000100110010000000000000000000010000000100 +000001--000001010101----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000010--000001010101----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--000001010101----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--000001010101----------------0---- +0000000000000000101100101001010000100110000000000000000000000010000000100 +000001--000010000100----------------0---- +1000001100000000100000101001010000100110000000000011010001100000000000000 +000010--000010000100----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000011--000010000100----------------0---- +0000000000000000100000101001010000100110000000000000000000000000000000000 +000100--000010000100----------------0---- +1000110000000010000000101001010000100110000101001011000000000000010000000 +100000--000010000100----------------0---- +1000110100011110000000101001010000100110000101001011000000000000010010000 +000001--000001001100----------------0---- +0000000100011110000010000001010000100110000000000000000000001000000000000 +000000--1000------------------------0---- +0000000000000001001100101001010000100110000000000000000000000011000000000 +000000--1001------------------------0---- +0000000000000001001100101001010000100110000000000000000000000011000000000 +000000--1010------------------------0---- +0000000000000001001100101001010000100110000000000000000000000011000000000 +000000--1011------------------------0---- +0000000000000001001100101001010000100110000000000000000000000011000000000 +000000--0000------------------------0---0 +0000000000000000100000101001010000100110000000000000000000000000000000001 +000000--000010010000----------------0-1-1 +0000000000000000100000101001010000100110000000000000000000000000000000001 +000000--000001010011----------------0-1-1 +0000000000000000100000101001010000100110000000000000000000000000000000001 +000000--000001010010----------------0-1-1 +0000000000000000100000101001010000100110000000000000000000000000000000001 +000000--000010001100----------------0-1-1 +0000000000000000100000101001010000100110000000000000000000000000000000001 +000000--000010010000----------------0--11 +0000000000000000100000101001010000100110000000000000000000000000000000001 +000000--000001010011----------------0--11 +0000000000000000100000101001010000100110000000000000000000000000000000001 +000000--000001010010----------------0--11 +0000000000000000100000101001010000100110000000000000000000000000000000001 +000000--000010001100----------------0--11 +0000000000000000100000101001010000100110000000000000000000000000000000001 +000000--000010000101----------------0--11 +0000000000000000100000101001010000100110000000000000000000000000000000001 +000000--000010000101----------------010-1 +0000000000000001001100101001001001100110000000000000000000000011000000100 +000000--000010010000----------------01001 +0000000000000001001100101001010000101100100000000000000000000001000000000 +000000--000001010011----------------01001 +0000000000000001001100101001010000100000000000000000000000000001000000000 +000000--000001010010----------------01001 +0000000000000001001100101001010000100000000000000000000000000001000000000 +000000--000011111000----------------0---1 +1000000000000010000000101001010000100110010001011011010001010000000001000 +000000--000011111010----------------0---1 +1000000000000010000000101001010000100110010001011011010101010000000001000 +000000--000011111001----------------0---1 +1000000000000000010100101001010000100110010001011011010101010000000000100 +000000--000011111011----------------0---1 +1000000000000000010100101001010000100110010001011011010001010000000000100 +000000--000011010-------------------0---1 +0000000000000010000000101001010000100110000000000011011111010000000001000 +000000--000011011-------------------0---1 +0000000000000000010100101001010000100110000000000011011111010000000000100 +000000--00001101-------------1------0---1 +1000111000000000000000000000000000000000000000000000000000000000000000000 +000000--00001101-------------0------0---1 +1000000000000000000000000000000000000000000000000000000000000000000000000 +000000--00001101--------------1-00--0---1 +0000000000111100000000000000000000000000000000000000000000000000000000000 +000000--00001101--------------1-01--0---1 +0000000000111100000000000000000000000000000000000000000000000000000000000 +000000--00001101--------------1-10--0---1 +0000000000111100000000000000000000000000000000000000000000000000000000000 +000000--00001101--------------1-11-00---1 +0000000100000000000000000000000000000000000000000000000000000000000000000 +000000--00001101--------------1-11-10---1 +0000000100011100000000000000000000000000000000000000000000000000000000000 +000000--00001101--------------00----0---1 +0000000101111100000000000000000000000000000000000000000000000000000000000 +000000--00001101--------------01----0---1 +0000000001111100000000000000000000000000000000000000000000000000000000000 +000000--00001101------------1-------0---1 +0000000000000000000000000000000000000000010000000000000000000000000000000 +000000--00001101--------------1-111-0---1 +0000000000000000000000000000000000000000001000000000000000000000000000000 +000000--000001001110----------------0---1 +0000000000000010000000101001010000100110000000000000000000000000000000000 +000000--000010001000----------------0---1 +0000000000000010000000101001010000100110000000000000000000000000000000000 +000000--000011100010----------------0---1 +0000000000000010000000101001010000100110000000000000000000000000000000000 +000000--000000100010----------------0---1 +0000000000000010000000101001010000100110000000000000000000000000000000000 +000000--000010001001----------------0---1 +0000000000000000010100101001010000100110000000000000000000000000000000000 +000000--000011100011----------------0---1 +0000000000000000011100101001010000100110000000000000000000000000000000000 +000000--000000100001----------------0---1 +0000000000000000111100101001010000100110000000000000000000000000000000000 +000000--000001010110----------------0---1 +0000000100000000100001001001010000100110000000000000000000000000000000000 +000000--000010010000----------------00001 +0000000010011001100100101000110000101100100000010000000000000100000000000 +000000--000001010010----------------00001 +0000000010011001100100101000110000100110000000010000000000000100000000000 +000000--000001010011----------------00001 +0000000010011001100100101000110000100110000000010000000000000100100000000 +000000--000011100100----------------0---1 +0000000000000000011100101001010000100110000000000000000000000010000000100 +000000--000000100000----------------0---1 +0000000000000000111100101001010000100110000000000000000000000010000000100 +000000--000001010100----------------0---1 +0000000100000000100001001001010000100110000000000000000000000000000000000 +000000--000001010101----------------0---1 +0000000100000000100001001001010000100110000000000000000000000000010000000 +000000--000010000111----------------0---1 +1000000000000010000010000001010000100110000001001011000000000000011000000 +000000--000010001111----------------0---1 +1000000000000010000010000001010000100110000001001011000000000000010000000 +000000--000010010001----------------0---1 +1000000000000010000010000011010000100110000101001011000000000000010000000 +000000--00001010--------------------0---1 +1011000000000010000010000011010000100110000101001011000000000000010000000 +000000--000011100101----------------0---1 +0010000000000010000010000011010000100110000101101011000000000000010000000 +000000--000011110001----------------0---1 +1011111000000010000010111101010000100110000001001011000000000000010000000 +000000--000011110000----------------0---1 +0011111000000010000010111101010000100110000001001011000000000000010000000 +000000--000010000100----------------0---1 +1000110000000000100010000011010000100110000001001011000000000000010100000 +000000--000010001101----------------0---1 +1000000100011110000000101001010000100110011001001011000000000000011010000 +000000--000010010101----------------0---1 +1000000100011110000000101001010000100110011001001011000000000000010010000 +000000--000010010110----------------0---1 +1000111100000010000000101001010000100110011001001011000000000000010010000 +000000--000010001110----------------0---1 +1000111100000010000000101001010000100110010001001011000000000000010010000 +000000--00001011--------------------0---1 +1011000100000010000000101001010000100110001001001011000000000000010010000 +000000--000011110011----------------0---1 +1011111101111010000000101001010000100110000001001011000000000000010010000 +000000--000011110010----------------0---1 +0011111101111010000000101001010000100110000001001011000000000000010010000 +000000--000001001010----------------0---1 +0000000000000010000000101001010000100110010000000000000000000000000000000 +000000--000010000010----------------0---1 +0000000000000010000000101001010000100100100000000000000000000000000000000 +000000--000010000001----------------0---1 +0000000000000010000000101001011001100110000000000000000000000000000000000 +000000--000010000011----------------0---1 +0000000000000010000000101001010000101100100000000000000000000000000000000 +000000--000010000101----------------0--01 +0000000000000010000000101001001001100110000000000000000000000000000000000 +000000--000010000101----------------0-1-1 +0000000000000010000000101001001001100110000000000000000000000000000000000 +000000--000010000101----------------00--1 +0000000000000010000000101001001001100110000000000000000000000000000000000 +000000--000011100001----------------0---1 +0000000000000010000000101111010000100110000001101000000000000000000000000 +000000--000010001011----------------0---1 +0000000000000010000010000011010000100110000101001000000000000000000000000 +000000--000011100110----------------0---1 +0000000000000010000010000011010000100110000101101000000000000000000000000 +000000--000000100011----------------0---1 +0000000000000010000010000011010000100110000101111000000000000000000000000 +000000--000001000-------------------0---1 +0000000000100010000010000011010000100110000100000000000000000000000000000 +000000--00000110--------------------0---1 +0000000101100010000010000011010000100110000100000000000000000000000000000 +000000--00000111--------------------0---1 +0000000100000010000010110001010000100110001000000000000000000000000000000 +000000--000001001011----------------0---1 +0000000100000010000010000011010000100110000100000000000000000000000000000 +000000--000001001101----------------0---1 +0000000100000010000010001111010000100110010000000000000000000000000000000 +000000--000001001100----------------0---1 +0000000100000000100010001111010000100110000000000000000000000000000000000 +000000--000010010010----------------0---1 +0000000100000010000011110011010000100110001000000000000000000000000000000 +000000--000010010011----------------0---1 +0000000100000000100011110011010000100110000000000000000000000000000000000 +000000--000010001010----------------0---1 +0000000111100110000010000011010000100110000100000000000000000000000000000 +000000--000010001100----------------0-0-1 +0000000111100110000010000011010000100110000100011000000000000000000000000 +000000--000010001100----------------0--01 +0000000111100110000010000011010000100110000100011000000000000000000000000 +000000--000010000000----------------0---1 +1000000000000010000010000001010000100110000001001001101000000000000000000 +000000--000011100000----------------0---1 +1000000000000010000010000001010000100110000001101001101000000000000000000 +000000--000010010100----------------0---1 +1000000000000010000010000001010000100110000001001001111000000000000000000 +000000--000011100111----------------0---1 +1000000000000010000010000001010000100110000001100001010000000000000000000 +000000--000011101000----------------0---1 +1000000100000010000010000001010000100110000001100001010000000000000000000 +000000--000001001000----------------0---1 +1000111100000010000010001111010000100110010000000001101000000000000000000 +000000--000001010111----------------0---1 +1000111100000010000010001111010000100110010000000001111000000000000000000 +000000--000001010000----------------0---1 +1000000100011100100010001111010000100110000000000100000001100000000000000 +000000--000001011001----------------0---1 +1000000100011100100010001111010000100110000000000100010001100000000000000 +000000--000001001111----------------0---1 +1000110100011100100010000011010000100110000000000101010000000000000000000 +000000--000001010001----------------0---1 +1000110100011100100010000011010000100110000000000101010000000000000000000 +000000--000001011000----------------0---1 +1000110100011100100010000011010000100110000000000101010000000000000000000 +000000--00001000011011--------------0---1 +0000000000000000100000101001010000100110000011110000000000000000001010000 +000000--00001000011001101--0--------0---1 +0000000100000000100000101001010000100110000010000000000000000000001010000 +000000--000010000110010-1--0--------0---1 +0000000100000000100000101001010000100110000010000000000000000000001010000 +000000--00001000011001110--0--------0---1 +0000000100000000100000101001010000100110000010000000000000000000001010000 +000000--000010000110011110-0--------0---1 +0000000100000000100000101001010000100110000010000000000000000000001010000 +000000--00001000011001111-11--------0---1 +0000000100000000100000101001010000100110000010000000000000000000001010000 +000000--000010000110011111-0--------0---1 +0000000100000000100000101001010000100110000010000000000000000000001010000 +000000--00001000011001101--1--------0---1 +0000000100000000100000101001010000100110000010010000000000000000001010000 +000000--000010000110010-1--1--------0---1 +0000000100000000100000101001010000100110000010010000000000000000001010000 +000000--00001000011001110--1--------0---1 +0000000100000000100000101001010000100110000010010000000000000000001010000 +000000--00001000011001111-01--------0---1 +0000000100000000100000101001010000100110000010010000000000000000001010000 +000000--00001000011001100--0--------0---1 +0000000100000000100000101001010000100110000011000000000000000000001010000 +000000--000010000110010-0--0--------0---1 +0000000100000000100000101001010000100110000011000000000000000000001010000 +000000--00001000011010-----0--------0---1 +0000000100000000100000101001010000100110000011000000000000000000001010000 +000000--00001000011001100--1--------0---1 +0000000100000000100000101001010000100110000011010000000000000000001010000 +000000--000010000110010-0--1--------0---1 +0000000100000000100000101001010000100110000011010000000000000000001010000 +000000--00001000011010-----1--------0---1 +0000000100000000100000101001010000100110000011010000000000000000001010000 +000000--000001001001----------------0---1 +1000111100000010000000101001010000100110010000000011011001000000000000000 +000000--00001100------------0--0----0---1 +1011011000000010000000000001010000100110000000000000000000000000000000000 +000000--00001100------------0--1----0---1 +0011011000000010000000000001010000100110000000000000000000000000000000000 +000000--00001100--------00--1-------0---1 +0001011000000010000000000001010000100110000000000000000000000000000000000 +000000--00001100--------01--1-------0---1 +0001011000000010000000000001010000100110000000000000000000000000000000000 +000000--00001100--------10--1-------0---1 +0001011000000010000000000001010000100110000000000000000000000000000000000 +000000--00001100--------11-01-------0---1 +1000000000000010000000000001010000100110000000000000000000000000000000000 +000000--00001100--------11-11-------0---1 +1000111000000010000000000001010000100110000000000000000000000000000000000 +000000--00001100--------111-1-------0---1 +0000000000000000000000000000000000000000010000000000000000000000000000000 +000000--00001100--------------00----0---1 +0000000101111100000000000000000000000000000000000000000000000000000000000 +000000--00001100--------------01----0---1 +0000000001111100000000000000000000000000000000000000000000000000000000000 +000000--00001100--------------1-00--0---1 +0000000000111100000000000000000000000000000000000000000000000000000000000 +000000--00001100--------------1-01--0---1 +0000000000111100000000000000000000000000000000000000000000000000000000000 +000000--00001100--------------1-10--0---1 +0000000000111100000000000000000000000000000000000000000000000000000000000 +000000--00001100--------------1-11-00---1 +0000000100000000000000000000000000000000000000000000000000000000000000000 +000000--00001100--------------1-11-10---1 +0000000100011100000000000000000000000000000000000000000000000000000000000 +000000--00001100--------------1-111-0---1 +0000000000000000000000000000000000000000001000000000000000000000000000000 +000000--00001100-------------0-0----0---1 +0000000000000000000010110100000000000000000000000000000000000000000000000 +000000--00001100-------------0-1----0---1 +0000000000000000000000110100000000000000000000000000000000000000000000000 +000000--00001100----00-------1------0---1 +0000000000000000000000010100000000000000000000000000000000000000000000000 +000000--00001100----01-------1------0---1 +0000000000000000000000010100000000000000000000000000000000000000000000000 +000000--00001100----10-------1------0---1 +0000000000000000000000010100000000000000000000000000000000000000000000000 +000000--00001100----1100-----1------0---1 +0000000000000000000010000000000000000000000000000000000000000000000000000 +000000--00001100----1101-----1------0---1 +0000000000000000000010001110000000000000000000000000000000000000000000000 +000000--00001100----1110-----1------0---1 +0000000000000000000010000010000000000000000000000000000000000000000000000 +000000--00001100----1111-----1------0---1 +0000000000000000000010000010000000000000000100000000000000000000000000000 +000000--00001100--------------------0---1 +0000000000000000000000000000000000000000000000000010000000000000000000000 +000000--00001100011-----------------0---1 +0000000000000000000000000000000000000000000000000000001000000000000000000 +000000--00001100111-----------------0---1 +0000000000000000000000000000000000000000000000000000001010000000000000000 +000000--000011001000----------------0---1 +0000000000000000000000000000000000000000000000000011000000000000010000000 +000000--000011001001----------------0---1 +0000000000000000000000000000000000000000000000000000001001000000000000000 +000000--000000000000----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000000001----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000000010----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000000011----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000000100----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000000101----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000000110----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000000111----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000001000----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000001001----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000001010----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000001011----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000001100----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000001101----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000001110----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000001111----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000010000----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000010001----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000010010----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000010011----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000010100----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000010101----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000010110----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000010111----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000011000----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000011001----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000011010----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000011011----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000011100----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000011101----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000011110----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000011111----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000000100100----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000100100----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000100101----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000100101----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000100110----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000100110----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000100111----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000100111----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000101000----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000101000----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000101001----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000101001----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000101010----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000101010----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000101011----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000101011----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000101100----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000101100----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000101101----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000101101----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000101110----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000101110----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000101111----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000101111----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000110000----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000110000----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000110001----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000110001----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000110010----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000110010----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000110011----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000110011----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000110100----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000110100----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000110101----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000110101----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000110110----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000110110----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000110111----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000110111----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000111000----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000111000----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000111001----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000111001----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000111010----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000111010----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000111011----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000111011----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000111100----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000111100----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000111101----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000111101----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000111110----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000111110----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000000111111----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000000111111----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000001011010----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000001011011----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000001011100----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000001011101----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000001011110----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000001011111----------------0---1 +0000000000000001000100101001010000100110000000000000000000000010000000100 +000000--000010010111----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000010010111----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000010011000----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000010011000----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000010011001----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000010011001----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000010011010----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000010011010----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000010011011----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000010011011----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000010011100----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000010011100----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000010011101----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000010011101----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000010011110----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000010011110----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000010011111----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000010011111----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011101001----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011101001----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011101010----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011101010----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011101011----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011101011----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011101100----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011101100----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011101101----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011101101----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011101110----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011101110----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011101111----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011101111----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011110100----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011110100----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011110101----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011110101----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011110110----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011110110----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011110111----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011110111----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011111100----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011111100----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011111101----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011111101----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011111110----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011111110----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +000000--000011111111----------------0---1 +0000000000000000100010000011010000100110000001111000000000000000000000000 +000001--000011111111----------------0---1 +0000000000000001000100101001010000100110000100000000000000000010000000100 +.e diff --git a/espresso/examples/math/Z5xp1 b/espresso/examples/math/Z5xp1 new file mode 100644 index 0000000..081ffc7 --- /dev/null +++ b/espresso/examples/math/Z5xp1 @@ -0,0 +1,132 @@ +.i 7 +.o 10 +.p 128 +0000000 0000000001 +0000001 0000000110 +0000010 0000001011 +0000011 0000010000 +0000100 0000010101 +0000101 0000011010 +0000110 0000011111 +0000111 0000100100 +0001000 0000101001 +0001001 0000101110 +0001010 0000110011 +0001011 0000111000 +0001100 0000111101 +0001101 0001000010 +0001110 0001000111 +0001111 0001001100 +0010000 0001010001 +0010001 0001010110 +0010010 0001011011 +0010011 0001100000 +0010100 0001100101 +0010101 0001101010 +0010110 0001101111 +0010111 0001110100 +0011000 0001111001 +0011001 0001111110 +0011010 0010000011 +0011011 0010001000 +0011100 0010001101 +0011101 0010010010 +0011110 0010010111 +0011111 0010011100 +0100000 0010100001 +0100001 0010100110 +0100010 0010101011 +0100011 0010110000 +0100100 0010110101 +0100101 0010111010 +0100110 0010111111 +0100111 0011000100 +0101000 0011001001 +0101001 0011001110 +0101010 0011010011 +0101011 0011011000 +0101100 0011011101 +0101101 0011100010 +0101110 0011100111 +0101111 0011101100 +0110000 0011110001 +0110001 0011110110 +0110010 0011111011 +0110011 0100000000 +0110100 0100000101 +0110101 0100001010 +0110110 0100001111 +0110111 0100010100 +0111000 0100011001 +0111001 0100011110 +0111010 0100100011 +0111011 0100101000 +0111100 0100101101 +0111101 0100110010 +0111110 0100110111 +0111111 0100111100 +1000000 0101000001 +1000001 0101000110 +1000010 0101001011 +1000011 0101010000 +1000100 0101010101 +1000101 0101011010 +1000110 0101011111 +1000111 0101100100 +1001000 0101101001 +1001001 0101101110 +1001010 0101110011 +1001011 0101111000 +1001100 0101111101 +1001101 0110000010 +1001110 0110000111 +1001111 0110001100 +1010000 0110010001 +1010001 0110010110 +1010010 0110011011 +1010011 0110100000 +1010100 0110100101 +1010101 0110101010 +1010110 0110101111 +1010111 0110110100 +1011000 0110111001 +1011001 0110111110 +1011010 0111000011 +1011011 0111001000 +1011100 0111001101 +1011101 0111010010 +1011110 0111010111 +1011111 0111011100 +1100000 0111100001 +1100001 0111100110 +1100010 0111101011 +1100011 0111110000 +1100100 0111110101 +1100101 0111111010 +1100110 0111111111 +1100111 1000000100 +1101000 1000001001 +1101001 1000001110 +1101010 1000010011 +1101011 1000011000 +1101100 1000011101 +1101101 1000100010 +1101110 1000100111 +1101111 1000101100 +1110000 1000110001 +1110001 1000110110 +1110010 1000111011 +1110011 1001000000 +1110100 1001000101 +1110101 1001001010 +1110110 1001001111 +1110111 1001010100 +1111000 1001011001 +1111001 1001011110 +1111010 1001100011 +1111011 1001101000 +1111100 1001101101 +1111101 1001110010 +1111110 1001110111 +1111111 1001111100 +.e diff --git a/espresso/examples/math/Z9sym b/espresso/examples/math/Z9sym new file mode 100644 index 0000000..becb8ce --- /dev/null +++ b/espresso/examples/math/Z9sym @@ -0,0 +1,424 @@ +.i 9 +.o 1 +.p 420 +000000111|1 +000001011|1 +000001101|1 +000001110|1 +000001111|1 +000010011|1 +000010101|1 +000010110|1 +000010111|1 +000011001|1 +000011010|1 +000011011|1 +000011100|1 +000011101|1 +000011110|1 +000011111|1 +000100011|1 +000100101|1 +000100110|1 +000100111|1 +000101001|1 +000101010|1 +000101011|1 +000101100|1 +000101101|1 +000101110|1 +000101111|1 +000110001|1 +000110010|1 +000110011|1 +000110100|1 +000110101|1 +000110110|1 +000110111|1 +000111000|1 +000111001|1 +000111010|1 +000111011|1 +000111100|1 +000111101|1 +000111110|1 +000111111|1 +001000011|1 +001000101|1 +001000110|1 +001000111|1 +001001001|1 +001001010|1 +001001011|1 +001001100|1 +001001101|1 +001001110|1 +001001111|1 +001010001|1 +001010010|1 +001010011|1 +001010100|1 +001010101|1 +001010110|1 +001010111|1 +001011000|1 +001011001|1 +001011010|1 +001011011|1 +001011100|1 +001011101|1 +001011110|1 +001011111|1 +001100001|1 +001100010|1 +001100011|1 +001100100|1 +001100101|1 +001100110|1 +001100111|1 +001101000|1 +001101001|1 +001101010|1 +001101011|1 +001101100|1 +001101101|1 +001101110|1 +001101111|1 +001110000|1 +001110001|1 +001110010|1 +001110011|1 +001110100|1 +001110101|1 +001110110|1 +001110111|1 +001111000|1 +001111001|1 +001111010|1 +001111011|1 +001111100|1 +001111101|1 +001111110|1 +010000011|1 +010000101|1 +010000110|1 +010000111|1 +010001001|1 +010001010|1 +010001011|1 +010001100|1 +010001101|1 +010001110|1 +010001111|1 +010010001|1 +010010010|1 +010010011|1 +010010100|1 +010010101|1 +010010110|1 +010010111|1 +010011000|1 +010011001|1 +010011010|1 +010011011|1 +010011100|1 +010011101|1 +010011110|1 +010011111|1 +010100001|1 +010100010|1 +010100011|1 +010100100|1 +010100101|1 +010100110|1 +010100111|1 +010101000|1 +010101001|1 +010101010|1 +010101011|1 +010101100|1 +010101101|1 +010101110|1 +010101111|1 +010110000|1 +010110001|1 +010110010|1 +010110011|1 +010110100|1 +010110101|1 +010110110|1 +010110111|1 +010111000|1 +010111001|1 +010111010|1 +010111011|1 +010111100|1 +010111101|1 +010111110|1 +011000001|1 +011000010|1 +011000011|1 +011000100|1 +011000101|1 +011000110|1 +011000111|1 +011001000|1 +011001001|1 +011001010|1 +011001011|1 +011001100|1 +011001101|1 +011001110|1 +011001111|1 +011010000|1 +011010001|1 +011010010|1 +011010011|1 +011010100|1 +011010101|1 +011010110|1 +011010111|1 +011011000|1 +011011001|1 +011011010|1 +011011011|1 +011011100|1 +011011101|1 +011011110|1 +011100000|1 +011100001|1 +011100010|1 +011100011|1 +011100100|1 +011100101|1 +011100110|1 +011100111|1 +011101000|1 +011101001|1 +011101010|1 +011101011|1 +011101100|1 +011101101|1 +011101110|1 +011110000|1 +011110001|1 +011110010|1 +011110011|1 +011110100|1 +011110101|1 +011110110|1 +011111000|1 +011111001|1 +011111010|1 +011111100|1 +100000011|1 +100000101|1 +100000110|1 +100000111|1 +100001001|1 +100001010|1 +100001011|1 +100001100|1 +100001101|1 +100001110|1 +100001111|1 +100010001|1 +100010010|1 +100010011|1 +100010100|1 +100010101|1 +100010110|1 +100010111|1 +100011000|1 +100011001|1 +100011010|1 +100011011|1 +100011100|1 +100011101|1 +100011110|1 +100011111|1 +100100001|1 +100100010|1 +100100011|1 +100100100|1 +100100101|1 +100100110|1 +100100111|1 +100101000|1 +100101001|1 +100101010|1 +100101011|1 +100101100|1 +100101101|1 +100101110|1 +100101111|1 +100110000|1 +100110001|1 +100110010|1 +100110011|1 +100110100|1 +100110101|1 +100110110|1 +100110111|1 +100111000|1 +100111001|1 +100111010|1 +100111011|1 +100111100|1 +100111101|1 +100111110|1 +101000001|1 +101000010|1 +101000011|1 +101000100|1 +101000101|1 +101000110|1 +101000111|1 +101001000|1 +101001001|1 +101001010|1 +101001011|1 +101001100|1 +101001101|1 +101001110|1 +101001111|1 +101010000|1 +101010001|1 +101010010|1 +101010011|1 +101010100|1 +101010101|1 +101010110|1 +101010111|1 +101011000|1 +101011001|1 +101011010|1 +101011011|1 +101011100|1 +101011101|1 +101011110|1 +101100000|1 +101100001|1 +101100010|1 +101100011|1 +101100100|1 +101100101|1 +101100110|1 +101100111|1 +101101000|1 +101101001|1 +101101010|1 +101101011|1 +101101100|1 +101101101|1 +101101110|1 +101110000|1 +101110001|1 +101110010|1 +101110011|1 +101110100|1 +101110101|1 +101110110|1 +101111000|1 +101111001|1 +101111010|1 +101111100|1 +110000001|1 +110000010|1 +110000011|1 +110000100|1 +110000101|1 +110000110|1 +110000111|1 +110001000|1 +110001001|1 +110001010|1 +110001011|1 +110001100|1 +110001101|1 +110001110|1 +110001111|1 +110010000|1 +110010001|1 +110010010|1 +110010011|1 +110010100|1 +110010101|1 +110010110|1 +110010111|1 +110011000|1 +110011001|1 +110011010|1 +110011011|1 +110011100|1 +110011101|1 +110011110|1 +110100000|1 +110100001|1 +110100010|1 +110100011|1 +110100100|1 +110100101|1 +110100110|1 +110100111|1 +110101000|1 +110101001|1 +110101010|1 +110101011|1 +110101100|1 +110101101|1 +110101110|1 +110110000|1 +110110001|1 +110110010|1 +110110011|1 +110110100|1 +110110101|1 +110110110|1 +110111000|1 +110111001|1 +110111010|1 +110111100|1 +111000000|1 +111000001|1 +111000010|1 +111000011|1 +111000100|1 +111000101|1 +111000110|1 +111000111|1 +111001000|1 +111001001|1 +111001010|1 +111001011|1 +111001100|1 +111001101|1 +111001110|1 +111010000|1 +111010001|1 +111010010|1 +111010011|1 +111010100|1 +111010101|1 +111010110|1 +111011000|1 +111011001|1 +111011010|1 +111011100|1 +111100000|1 +111100001|1 +111100010|1 +111100011|1 +111100100|1 +111100101|1 +111100110|1 +111101000|1 +111101001|1 +111101010|1 +111101100|1 +111110000|1 +111110001|1 +111110010|1 +111110100|1 +111111000|1 +.e diff --git a/espresso/examples/math/add6 b/espresso/examples/math/add6 new file mode 100644 index 0000000..3625f02 --- /dev/null +++ b/espresso/examples/math/add6 @@ -0,0 +1,1094 @@ +.i 12 +.o 7 +1-----0----- 1000000 +0-----1----- 1000000 +-1----00---- 0100000 +-0----01---- 0100000 +01-----0---- 0100000 +00-----1---- 0100000 +10----10---- 0100000 +11----11---- 0100000 +--1---000--- 0010000 +--0---001--- 0010000 +-01---0-0--- 0010000 +-00---0-1--- 0010000 +0-1----00--- 0010000 +0-0----01--- 0010000 +001-----0--- 0010000 +000-----1--- 0010000 +-10---010--- 0010000 +-11---011--- 0010000 +010----10--- 0010000 +011----11--- 0010000 +101---100--- 0010000 +100---101--- 0010000 +1-0---110--- 0010000 +1-1---111--- 0010000 +110---1-0--- 0010000 +111---1-1--- 0010000 +---1--0000-- 0001000 +---0--0001-- 0001000 +--01--00-0-- 0001000 +--00--00-1-- 0001000 +-0-1--0-00-- 0001000 +-0-0--0-01-- 0001000 +-001--0--0-- 0001000 +-000--0--1-- 0001000 +0--1---000-- 0001000 +0--0---001-- 0001000 +0-01---0-0-- 0001000 +0-00---0-1-- 0001000 +00-1----00-- 0001000 +00-0----01-- 0001000 +0001-----0-- 0001000 +0000-----1-- 0001000 +--10--0010-- 0001000 +--11--0011-- 0001000 +-010--0-10-- 0001000 +-011--0-11-- 0001000 +0-10---010-- 0001000 +0-11---011-- 0001000 +0010----10-- 0001000 +0011----11-- 0001000 +-101--0100-- 0001000 +-100--0101-- 0001000 +0101---100-- 0001000 +0100---101-- 0001000 +-1-0--0110-- 0001000 +-1-1--0111-- 0001000 +-110--01-0-- 0001000 +-111--01-1-- 0001000 +01-0---110-- 0001000 +01-1---111-- 0001000 +0110---1-0-- 0001000 +0111---1-1-- 0001000 +10-1--1000-- 0001000 +10-0--1001-- 0001000 +1001--10-0-- 0001000 +1000--10-1-- 0001000 +1010--1010-- 0001000 +1011--1011-- 0001000 +1-01--1100-- 0001000 +1-00--1101-- 0001000 +1101--1-00-- 0001000 +1100--1-01-- 0001000 +1--0--1110-- 0001000 +1--1--1111-- 0001000 +1-10--11-0-- 0001000 +1-11--11-1-- 0001000 +11-0--1-10-- 0001000 +11-1--1-11-- 0001000 +1110--1--0-- 0001000 +1111--1--1-- 0001000 +----1-00000- 0000100 +----0-00001- 0000100 +---01-000-0- 0000100 +---00-000-1- 0000100 +--0-1-00-00- 0000100 +--0-0-00-01- 0000100 +--001-00--0- 0000100 +--000-00--1- 0000100 +-0--1-0-000- 0000100 +-0--0-0-001- 0000100 +-0-01-0-0-0- 0000100 +-0-00-0-0-1- 0000100 +-00-1-0--00- 0000100 +-00-0-0--01- 0000100 +-0001-0---0- 0000100 +-0000-0---1- 0000100 +0---1--0000- 0000100 +0---0--0001- 0000100 +0--01--00-0- 0000100 +0--00--00-1- 0000100 +0-0-1--0-00- 0000100 +0-0-0--0-01- 0000100 +0-001--0--0- 0000100 +0-000--0--1- 0000100 +00--1---000- 0000100 +00--0---001- 0000100 +00-01---0-0- 0000100 +00-00---0-1- 0000100 +000-1----00- 0000100 +000-0----01- 0000100 +00001-----0- 0000100 +00000-----1- 0000100 +---10-00010- 0000100 +---11-00011- 0000100 +--010-00-10- 0000100 +--011-00-11- 0000100 +-0-10-0-010- 0000100 +-0-11-0-011- 0000100 +-0010-0--10- 0000100 +-0011-0--11- 0000100 +0--10--0010- 0000100 +0--11--0011- 0000100 +0-010--0-10- 0000100 +0-011--0-11- 0000100 +00-10---010- 0000100 +00-11---011- 0000100 +00010----10- 0000100 +00011----11- 0000100 +--101-00100- 0000100 +--100-00101- 0000100 +-0101-0-100- 0000100 +-0100-0-101- 0000100 +0-101--0100- 0000100 +0-100--0101- 0000100 +00101---100- 0000100 +00100---101- 0000100 +--1-0-00110- 0000100 +--1-1-00111- 0000100 +--110-001-0- 0000100 +--111-001-1- 0000100 +-01-0-0-110- 0000100 +-01-1-0-111- 0000100 +-0110-0-1-0- 0000100 +-0111-0-1-1- 0000100 +0-1-0--0110- 0000100 +0-1-1--0111- 0000100 +0-110--01-0- 0000100 +0-111--01-1- 0000100 +001-0---110- 0000100 +001-1---111- 0000100 +00110---1-0- 0000100 +00111---1-1- 0000100 +-10-1-01000- 0000100 +-10-0-01001- 0000100 +-1001-010-0- 0000100 +-1000-010-1- 0000100 +010-1--1000- 0000100 +010-0--1001- 0000100 +01001--10-0- 0000100 +01000--10-1- 0000100 +-1010-01010- 0000100 +-1011-01011- 0000100 +01010--1010- 0000100 +01011--1011- 0000100 +-1-01-01100- 0000100 +-1-00-01101- 0000100 +-1101-01-00- 0000100 +-1100-01-01- 0000100 +01-01--1100- 0000100 +01-00--1101- 0000100 +01101--1-00- 0000100 +01100--1-01- 0000100 +-1--0-01110- 0000100 +-1--1-01111- 0000100 +-1-10-011-0- 0000100 +-1-11-011-1- 0000100 +-11-0-01-10- 0000100 +-11-1-01-11- 0000100 +-1110-01--0- 0000100 +-1111-01--1- 0000100 +01--0--1110- 0000100 +01--1--1111- 0000100 +01-10--11-0- 0000100 +01-11--11-1- 0000100 +011-0--1-10- 0000100 +011-1--1-11- 0000100 +01110--1--0- 0000100 +01111--1--1- 0000100 +10--1-10000- 0000100 +10--0-10001- 0000100 +10-01-100-0- 0000100 +10-00-100-1- 0000100 +100-1-10-00- 0000100 +100-0-10-01- 0000100 +10001-10--0- 0000100 +10000-10--1- 0000100 +10-10-10010- 0000100 +10-11-10011- 0000100 +10010-10-10- 0000100 +10011-10-11- 0000100 +10101-10100- 0000100 +10100-10101- 0000100 +101-0-10110- 0000100 +101-1-10111- 0000100 +10110-101-0- 0000100 +10111-101-1- 0000100 +1-0-1-11000- 0000100 +1-0-0-11001- 0000100 +1-001-110-0- 0000100 +1-000-110-1- 0000100 +110-1-1-000- 0000100 +110-0-1-001- 0000100 +11001-1-0-0- 0000100 +11000-1-0-1- 0000100 +1-010-11010- 0000100 +1-011-11011- 0000100 +11010-1-010- 0000100 +11011-1-011- 0000100 +1--01-11100- 0000100 +1--00-11101- 0000100 +1-101-11-00- 0000100 +1-100-11-01- 0000100 +11-01-1-100- 0000100 +11-00-1-101- 0000100 +11101-1--00- 0000100 +11100-1--01- 0000100 +1---0-11110- 0000100 +1---1-11111- 0000100 +1--10-111-0- 0000100 +1--11-111-1- 0000100 +1-1-0-11-10- 0000100 +1-1-1-11-11- 0000100 +1-110-11--0- 0000100 +1-111-11--1- 0000100 +11--0-1-110- 0000100 +11--1-1-111- 0000100 +11-10-1-1-0- 0000100 +11-11-1-1-1- 0000100 +111-0-1--10- 0000100 +111-1-1--11- 0000100 +11110-1---0- 0000100 +11111-1---1- 0000100 +-----1000000 0000010 +-----0000001 0000010 +----010000-0 0000010 +----000000-1 0000010 +---0-1000-00 0000010 +---0-0000-01 0000010 +---001000--0 0000010 +---000000--1 0000010 +--0--100-000 0000010 +--0--000-001 0000010 +--0-0100-0-0 0000010 +--0-0000-0-1 0000010 +--00-100--00 0000010 +--00-000--01 0000010 +--000100---0 0000010 +--000000---1 0000010 +-0---10-0000 0000010 +-0---00-0001 0000010 +-0--010-00-0 0000010 +-0--000-00-1 0000010 +-0-0-10-0-00 0000010 +-0-0-00-0-01 0000010 +-0-0010-0--0 0000010 +-0-0000-0--1 0000010 +-00--10--000 0000010 +-00--00--001 0000010 +-00-010--0-0 0000010 +-00-000--0-1 0000010 +-000-10---00 0000010 +-000-00---01 0000010 +-000010----0 0000010 +-000000----1 0000010 +0----1-00000 0000010 +0----0-00001 0000010 +0---01-000-0 0000010 +0---00-000-1 0000010 +0--0-1-00-00 0000010 +0--0-0-00-01 0000010 +0--001-00--0 0000010 +0--000-00--1 0000010 +0-0--1-0-000 0000010 +0-0--0-0-001 0000010 +0-0-01-0-0-0 0000010 +0-0-00-0-0-1 0000010 +0-00-1-0--00 0000010 +0-00-0-0--01 0000010 +0-0001-0---0 0000010 +0-0000-0---1 0000010 +00---1--0000 0000010 +00---0--0001 0000010 +00--01--00-0 0000010 +00--00--00-1 0000010 +00-0-1--0-00 0000010 +00-0-0--0-01 0000010 +00-001--0--0 0000010 +00-000--0--1 0000010 +000--1---000 0000010 +000--0---001 0000010 +000-01---0-0 0000010 +000-00---0-1 0000010 +0000-1----00 0000010 +0000-0----01 0000010 +000001-----0 0000010 +000000-----1 0000010 +----10000010 0000010 +----11000011 0000010 +---010000-10 0000010 +---011000-11 0000010 +--0-1000-010 0000010 +--0-1100-011 0000010 +--001000--10 0000010 +--001100--11 0000010 +-0--100-0010 0000010 +-0--110-0011 0000010 +-0-0100-0-10 0000010 +-0-0110-0-11 0000010 +-00-100--010 0000010 +-00-110--011 0000010 +-000100---10 0000010 +-000110---11 0000010 +0---10-00010 0000010 +0---11-00011 0000010 +0--010-00-10 0000010 +0--011-00-11 0000010 +0-0-10-0-010 0000010 +0-0-11-0-011 0000010 +0-0010-0--10 0000010 +0-0011-0--11 0000010 +00--10--0010 0000010 +00--11--0011 0000010 +00-010--0-10 0000010 +00-011--0-11 0000010 +000-10---010 0000010 +000-11---011 0000010 +000010----10 0000010 +000011----11 0000010 +---101000100 0000010 +---100000101 0000010 +--010100-100 0000010 +--010000-101 0000010 +-0-1010-0100 0000010 +-0-1000-0101 0000010 +-001010--100 0000010 +-001000--101 0000010 +0--101-00100 0000010 +0--100-00101 0000010 +0-0101-0-100 0000010 +0-0100-0-101 0000010 +00-101--0100 0000010 +00-100--0101 0000010 +000101---100 0000010 +000100---101 0000010 +---1-0000110 0000010 +---1-1000111 0000010 +---1100001-0 0000010 +---1110001-1 0000010 +--01-000-110 0000010 +--01-100-111 0000010 +--011000-1-0 0000010 +--011100-1-1 0000010 +-0-1-00-0110 0000010 +-0-1-10-0111 0000010 +-0-1100-01-0 0000010 +-0-1110-01-1 0000010 +-001-00--110 0000010 +-001-10--111 0000010 +-001100--1-0 0000010 +-001110--1-1 0000010 +0--1-0-00110 0000010 +0--1-1-00111 0000010 +0--110-001-0 0000010 +0--111-001-1 0000010 +0-01-0-0-110 0000010 +0-01-1-0-111 0000010 +0-0110-0-1-0 0000010 +0-0111-0-1-1 0000010 +00-1-0--0110 0000010 +00-1-1--0111 0000010 +00-110--01-0 0000010 +00-111--01-1 0000010 +0001-0---110 0000010 +0001-1---111 0000010 +000110---1-0 0000010 +000111---1-1 0000010 +--10-1001000 0000010 +--10-0001001 0000010 +--10010010-0 0000010 +--10000010-1 0000010 +-010-10-1000 0000010 +-010-00-1001 0000010 +-010010-10-0 0000010 +-010000-10-1 0000010 +0-10-1-01000 0000010 +0-10-0-01001 0000010 +0-1001-010-0 0000010 +0-1000-010-1 0000010 +0010-1--1000 0000010 +0010-0--1001 0000010 +001001--10-0 0000010 +001000--10-1 0000010 +--1010001010 0000010 +--1011001011 0000010 +-010100-1010 0000010 +-010110-1011 0000010 +0-1010-01010 0000010 +0-1011-01011 0000010 +001010--1010 0000010 +001011--1011 0000010 +--1-01001100 0000010 +--1-00001101 0000010 +--1101001-00 0000010 +--1100001-01 0000010 +-01-010-1100 0000010 +-01-000-1101 0000010 +-011010-1-00 0000010 +-011000-1-01 0000010 +0-1-01-01100 0000010 +0-1-00-01101 0000010 +0-1101-01-00 0000010 +0-1100-01-01 0000010 +001-01--1100 0000010 +001-00--1101 0000010 +001101--1-00 0000010 +001100--1-01 0000010 +--1--0001110 0000010 +--1--1001111 0000010 +--1-100011-0 0000010 +--1-110011-1 0000010 +--11-0001-10 0000010 +--11-1001-11 0000010 +--1110001--0 0000010 +--1111001--1 0000010 +-01--00-1110 0000010 +-01--10-1111 0000010 +-01-100-11-0 0000010 +-01-110-11-1 0000010 +-011-00-1-10 0000010 +-011-10-1-11 0000010 +-011100-1--0 0000010 +-011110-1--1 0000010 +0-1--0-01110 0000010 +0-1--1-01111 0000010 +0-1-10-011-0 0000010 +0-1-11-011-1 0000010 +0-11-0-01-10 0000010 +0-11-1-01-11 0000010 +0-1110-01--0 0000010 +0-1111-01--1 0000010 +001--0--1110 0000010 +001--1--1111 0000010 +001-10--11-0 0000010 +001-11--11-1 0000010 +0011-0--1-10 0000010 +0011-1--1-11 0000010 +001110--1--0 0000010 +001111--1--1 0000010 +-10--1010000 0000010 +-10--0010001 0000010 +-10-010100-0 0000010 +-10-000100-1 0000010 +-100-1010-00 0000010 +-100-0010-01 0000010 +-10001010--0 0000010 +-10000010--1 0000010 +010--1-10000 0000010 +010--0-10001 0000010 +010-01-100-0 0000010 +010-00-100-1 0000010 +0100-1-10-00 0000010 +0100-0-10-01 0000010 +010001-10--0 0000010 +010000-10--1 0000010 +-10-10010010 0000010 +-10-11010011 0000010 +-10010010-10 0000010 +-10011010-11 0000010 +010-10-10010 0000010 +010-11-10011 0000010 +010010-10-10 0000010 +010011-10-11 0000010 +-10101010100 0000010 +-10100010101 0000010 +010101-10100 0000010 +010100-10101 0000010 +-101-0010110 0000010 +-101-1010111 0000010 +-101100101-0 0000010 +-101110101-1 0000010 +0101-0-10110 0000010 +0101-1-10111 0000010 +010110-101-0 0000010 +010111-101-1 0000010 +-1-0-1011000 0000010 +-1-0-0011001 0000010 +-1-0010110-0 0000010 +-1-0000110-1 0000010 +-110-101-000 0000010 +-110-001-001 0000010 +-1100101-0-0 0000010 +-1100001-0-1 0000010 +01-0-1-11000 0000010 +01-0-0-11001 0000010 +01-001-110-0 0000010 +01-000-110-1 0000010 +0110-1-1-000 0000010 +0110-0-1-001 0000010 +011001-1-0-0 0000010 +011000-1-0-1 0000010 +-1-010011010 0000010 +-1-011011011 0000010 +-1101001-010 0000010 +-1101101-011 0000010 +01-010-11010 0000010 +01-011-11011 0000010 +011010-1-010 0000010 +011011-1-011 0000010 +-1--01011100 0000010 +-1--00011101 0000010 +-1-101011-00 0000010 +-1-100011-01 0000010 +-11-0101-100 0000010 +-11-0001-101 0000010 +-1110101--00 0000010 +-1110001--01 0000010 +01--01-11100 0000010 +01--00-11101 0000010 +01-101-11-00 0000010 +01-100-11-01 0000010 +011-01-1-100 0000010 +011-00-1-101 0000010 +011101-1--00 0000010 +011100-1--01 0000010 +-1---0011110 0000010 +-1---1011111 0000010 +-1--100111-0 0000010 +-1--110111-1 0000010 +-1-1-0011-10 0000010 +-1-1-1011-11 0000010 +-1-110011--0 0000010 +-1-111011--1 0000010 +-11--001-110 0000010 +-11--101-111 0000010 +-11-1001-1-0 0000010 +-11-1101-1-1 0000010 +-111-001--10 0000010 +-111-101--11 0000010 +-1111001---0 0000010 +-1111101---1 0000010 +01---0-11110 0000010 +01---1-11111 0000010 +01--10-111-0 0000010 +01--11-111-1 0000010 +01-1-0-11-10 0000010 +01-1-1-11-11 0000010 +01-110-11--0 0000010 +01-111-11--1 0000010 +011--0-1-110 0000010 +011--1-1-111 0000010 +011-10-1-1-0 0000010 +011-11-1-1-1 0000010 +0111-0-1--10 0000010 +0111-1-1--11 0000010 +011110-1---0 0000010 +011111-1---1 0000010 +10---1100000 0000010 +10---0100001 0000010 +10--011000-0 0000010 +10--001000-1 0000010 +10-0-1100-00 0000010 +10-0-0100-01 0000010 +10-001100--0 0000010 +10-000100--1 0000010 +100--110-000 0000010 +100--010-001 0000010 +100-0110-0-0 0000010 +100-0010-0-1 0000010 +1000-110--00 0000010 +1000-010--01 0000010 +10000110---0 0000010 +10000010---1 0000010 +10--10100010 0000010 +10--11100011 0000010 +10-010100-10 0000010 +10-011100-11 0000010 +100-1010-010 0000010 +100-1110-011 0000010 +10001010--10 0000010 +10001110--11 0000010 +10-101100100 0000010 +10-100100101 0000010 +10010110-100 0000010 +10010010-101 0000010 +10-1-0100110 0000010 +10-1-1100111 0000010 +10-1101001-0 0000010 +10-1111001-1 0000010 +1001-010-110 0000010 +1001-110-111 0000010 +10011010-1-0 0000010 +10011110-1-1 0000010 +1010-1101000 0000010 +1010-0101001 0000010 +1010011010-0 0000010 +1010001010-1 0000010 +101010101010 0000010 +101011101011 0000010 +101-01101100 0000010 +101-00101101 0000010 +101101101-00 0000010 +101100101-01 0000010 +101--0101110 0000010 +101--1101111 0000010 +101-101011-0 0000010 +101-111011-1 0000010 +1011-0101-10 0000010 +1011-1101-11 0000010 +101110101--0 0000010 +101111101--1 0000010 +1-0--1110000 0000010 +1-0--0110001 0000010 +1-0-011100-0 0000010 +1-0-001100-1 0000010 +1-00-1110-00 0000010 +1-00-0110-01 0000010 +1-0001110--0 0000010 +1-0000110--1 0000010 +110--11-0000 0000010 +110--01-0001 0000010 +110-011-00-0 0000010 +110-001-00-1 0000010 +1100-11-0-00 0000010 +1100-01-0-01 0000010 +1100011-0--0 0000010 +1100001-0--1 0000010 +1-0-10110010 0000010 +1-0-11110011 0000010 +1-0010110-10 0000010 +1-0011110-11 0000010 +110-101-0010 0000010 +110-111-0011 0000010 +1100101-0-10 0000010 +1100111-0-11 0000010 +1-0101110100 0000010 +1-0100110101 0000010 +1101011-0100 0000010 +1101001-0101 0000010 +1-01-0110110 0000010 +1-01-1110111 0000010 +1-01101101-0 0000010 +1-01111101-1 0000010 +1101-01-0110 0000010 +1101-11-0111 0000010 +1101101-01-0 0000010 +1101111-01-1 0000010 +1--0-1111000 0000010 +1--0-0111001 0000010 +1--0011110-0 0000010 +1--0001110-1 0000010 +1-10-111-000 0000010 +1-10-011-001 0000010 +1-100111-0-0 0000010 +1-100011-0-1 0000010 +11-0-11-1000 0000010 +11-0-01-1001 0000010 +11-0011-10-0 0000010 +11-0001-10-1 0000010 +1110-11--000 0000010 +1110-01--001 0000010 +1110011--0-0 0000010 +1110001--0-1 0000010 +1--010111010 0000010 +1--011111011 0000010 +1-101011-010 0000010 +1-101111-011 0000010 +11-0101-1010 0000010 +11-0111-1011 0000010 +1110101--010 0000010 +1110111--011 0000010 +1---01111100 0000010 +1---00111101 0000010 +1--101111-00 0000010 +1--100111-01 0000010 +1-1-0111-100 0000010 +1-1-0011-101 0000010 +1-110111--00 0000010 +1-110011--01 0000010 +11--011-1100 0000010 +11--001-1101 0000010 +11-1011-1-00 0000010 +11-1001-1-01 0000010 +111-011--100 0000010 +111-001--101 0000010 +1111011---00 0000010 +1111001---01 0000010 +1----0111110 0000010 +1----1111111 0000010 +1---101111-0 0000010 +1---111111-1 0000010 +1--1-0111-10 0000010 +1--1-1111-11 0000010 +1--110111--0 0000010 +1--111111--1 0000010 +1-1--011-110 0000010 +1-1--111-111 0000010 +1-1-1011-1-0 0000010 +1-1-1111-1-1 0000010 +1-11-011--10 0000010 +1-11-111--11 0000010 +1-111011---0 0000010 +1-111111---1 0000010 +11---01-1110 0000010 +11---11-1111 0000010 +11--101-11-0 0000010 +11--111-11-1 0000010 +11-1-01-1-10 0000010 +11-1-11-1-11 0000010 +11-1101-1--0 0000010 +11-1111-1--1 0000010 +111--01--110 0000010 +111--11--111 0000010 +111-101--1-0 0000010 +111-111--1-1 0000010 +1111-01---10 0000010 +1111-11---11 0000010 +1111101----0 0000010 +1111111----1 0000010 +-----1000001 0000001 +----010000-1 0000001 +---0-1000-01 0000001 +---001000--1 0000001 +--0--100-001 0000001 +--0-0100-0-1 0000001 +--00-100--01 0000001 +--000100---1 0000001 +-0---10-0001 0000001 +-0--010-00-1 0000001 +-0-0-10-0-01 0000001 +-0-0010-0--1 0000001 +-00--10--001 0000001 +-00-010--0-1 0000001 +-000-10---01 0000001 +-000010----1 0000001 +0----1-00001 0000001 +0---01-000-1 0000001 +0--0-1-00-01 0000001 +0--001-00--1 0000001 +0-0--1-0-001 0000001 +0-0-01-0-0-1 0000001 +0-00-1-0--01 0000001 +0-0001-0---1 0000001 +00---1--0001 0000001 +00--01--00-1 0000001 +00-0-1--0-01 0000001 +00-001--0--1 0000001 +000--1---001 0000001 +000-01---0-1 0000001 +0000-1----01 0000001 +000001-----1 0000001 +----1-000011 0000001 +----1100001- 0000001 +---01-000-11 0000001 +---011000-1- 0000001 +--0-1-00-011 0000001 +--0-1100-01- 0000001 +--001-00--11 0000001 +--001100--1- 0000001 +-0--1-0-0011 0000001 +-0--110-001- 0000001 +-0-01-0-0-11 0000001 +-0-0110-0-1- 0000001 +-00-1-0--011 0000001 +-00-110--01- 0000001 +-0001-0---11 0000001 +-000110---1- 0000001 +0---1--00011 0000001 +0---11-0001- 0000001 +0--01--00-11 0000001 +0--011-00-1- 0000001 +0-0-1--0-011 0000001 +0-0-11-0-01- 0000001 +0-001--0--11 0000001 +0-0011-0--1- 0000001 +00--1---0011 0000001 +00--11--001- 0000001 +00-01---0-11 0000001 +00-011--0-1- 0000001 +000-1----011 0000001 +000-11---01- 0000001 +00001-----11 0000001 +000011----1- 0000001 +---101000101 0000001 +--010100-101 0000001 +-0-1010-0101 0000001 +-001010--101 0000001 +0--101-00101 0000001 +0-0101-0-101 0000001 +00-101--0101 0000001 +000101---101 0000001 +---1--000111 0000001 +---1-100011- 0000001 +---11-0001-1 0000001 +---1110001-- 0000001 +--01--00-111 0000001 +--01-100-11- 0000001 +--011-00-1-1 0000001 +--011100-1-- 0000001 +-0-1--0-0111 0000001 +-0-1-10-011- 0000001 +-0-11-0-01-1 0000001 +-0-1110-01-- 0000001 +-001--0--111 0000001 +-001-10--11- 0000001 +-0011-0--1-1 0000001 +-001110--1-- 0000001 +0--1---00111 0000001 +0--1-1-0011- 0000001 +0--11--001-1 0000001 +0--111-001-- 0000001 +0-01---0-111 0000001 +0-01-1-0-11- 0000001 +0-011--0-1-1 0000001 +0-0111-0-1-- 0000001 +00-1----0111 0000001 +00-1-1--011- 0000001 +00-11---01-1 0000001 +00-111--01-- 0000001 +0001-----111 0000001 +0001-1---11- 0000001 +00011----1-1 0000001 +000111---1-- 0000001 +--10-1001001 0000001 +--10010010-1 0000001 +-010-10-1001 0000001 +-010010-10-1 0000001 +0-10-1-01001 0000001 +0-1001-010-1 0000001 +0010-1--1001 0000001 +001001--10-1 0000001 +--101-001011 0000001 +--101100101- 0000001 +-0101-0-1011 0000001 +-010110-101- 0000001 +0-101--01011 0000001 +0-1011-0101- 0000001 +00101---1011 0000001 +001011--101- 0000001 +--1-01001101 0000001 +--1101001-01 0000001 +-01-010-1101 0000001 +-011010-1-01 0000001 +0-1-01-01101 0000001 +0-1101-01-01 0000001 +001-01--1101 0000001 +001101--1-01 0000001 +--1---001111 0000001 +--1--100111- 0000001 +--1-1-0011-1 0000001 +--1-110011-- 0000001 +--11--001-11 0000001 +--11-1001-1- 0000001 +--111-001--1 0000001 +--1111001--- 0000001 +-01---0-1111 0000001 +-01--10-111- 0000001 +-01-1-0-11-1 0000001 +-01-110-11-- 0000001 +-011--0-1-11 0000001 +-011-10-1-1- 0000001 +-0111-0-1--1 0000001 +-011110-1--- 0000001 +0-1----01111 0000001 +0-1--1-0111- 0000001 +0-1-1--011-1 0000001 +0-1-11-011-- 0000001 +0-11---01-11 0000001 +0-11-1-01-1- 0000001 +0-111--01--1 0000001 +0-1111-01--- 0000001 +001-----1111 0000001 +001--1--111- 0000001 +001-1---11-1 0000001 +001-11--11-- 0000001 +0011----1-11 0000001 +0011-1--1-1- 0000001 +00111---1--1 0000001 +001111--1--- 0000001 +-10--1010001 0000001 +-10-010100-1 0000001 +-100-1010-01 0000001 +-10001010--1 0000001 +010--1-10001 0000001 +010-01-100-1 0000001 +0100-1-10-01 0000001 +010001-10--1 0000001 +-10-1-010011 0000001 +-10-1101001- 0000001 +-1001-010-11 0000001 +-10011010-1- 0000001 +010-1--10011 0000001 +010-11-1001- 0000001 +01001--10-11 0000001 +010011-10-1- 0000001 +-10101010101 0000001 +010101-10101 0000001 +-101--010111 0000001 +-101-101011- 0000001 +-1011-0101-1 0000001 +-101110101-- 0000001 +0101---10111 0000001 +0101-1-1011- 0000001 +01011--101-1 0000001 +010111-101-- 0000001 +-1-0-1011001 0000001 +-1-0010110-1 0000001 +-110-101-001 0000001 +-1100101-0-1 0000001 +01-0-1-11001 0000001 +01-001-110-1 0000001 +0110-1-1-001 0000001 +011001-1-0-1 0000001 +-1-01-011011 0000001 +-1-01101101- 0000001 +-1101-01-011 0000001 +-1101101-01- 0000001 +01-01--11011 0000001 +01-011-1101- 0000001 +01101--1-011 0000001 +011011-1-01- 0000001 +-1--01011101 0000001 +-1-101011-01 0000001 +-11-0101-101 0000001 +-1110101--01 0000001 +01--01-11101 0000001 +01-101-11-01 0000001 +011-01-1-101 0000001 +011101-1--01 0000001 +-1----011111 0000001 +-1---101111- 0000001 +-1--1-0111-1 0000001 +-1--110111-- 0000001 +-1-1--011-11 0000001 +-1-1-1011-1- 0000001 +-1-11-011--1 0000001 +-1-111011--- 0000001 +-11---01-111 0000001 +-11--101-11- 0000001 +-11-1-01-1-1 0000001 +-11-1101-1-- 0000001 +-111--01--11 0000001 +-111-101--1- 0000001 +-1111-01---1 0000001 +-1111101---- 0000001 +01-----11111 0000001 +01---1-1111- 0000001 +01--1--111-1 0000001 +01--11-111-- 0000001 +01-1---11-11 0000001 +01-1-1-11-1- 0000001 +01-11--11--1 0000001 +01-111-11--- 0000001 +011----1-111 0000001 +011--1-1-11- 0000001 +011-1--1-1-1 0000001 +011-11-1-1-- 0000001 +0111---1--11 0000001 +0111-1-1--1- 0000001 +01111--1---1 0000001 +011111-1---- 0000001 +10---1100001 0000001 +10--011000-1 0000001 +10-0-1100-01 0000001 +10-001100--1 0000001 +100--110-001 0000001 +100-0110-0-1 0000001 +1000-110--01 0000001 +10000110---1 0000001 +10--1-100011 0000001 +10--1110001- 0000001 +10-01-100-11 0000001 +10-011100-1- 0000001 +100-1-10-011 0000001 +100-1110-01- 0000001 +10001-10--11 0000001 +10001110--1- 0000001 +10-101100101 0000001 +10010110-101 0000001 +10-1--100111 0000001 +10-1-110011- 0000001 +10-11-1001-1 0000001 +10-1111001-- 0000001 +1001--10-111 0000001 +1001-110-11- 0000001 +10011-10-1-1 0000001 +10011110-1-- 0000001 +1010-1101001 0000001 +1010011010-1 0000001 +10101-101011 0000001 +10101110101- 0000001 +101-01101101 0000001 +101101101-01 0000001 +101---101111 0000001 +101--110111- 0000001 +101-1-1011-1 0000001 +101-111011-- 0000001 +1011--101-11 0000001 +1011-1101-1- 0000001 +10111-101--1 0000001 +101111101--- 0000001 +1-0--1110001 0000001 +1-0-011100-1 0000001 +1-00-1110-01 0000001 +1-0001110--1 0000001 +110--11-0001 0000001 +110-011-00-1 0000001 +1100-11-0-01 0000001 +1100011-0--1 0000001 +1-0-1-110011 0000001 +1-0-1111001- 0000001 +1-001-110-11 0000001 +1-0011110-1- 0000001 +110-1-1-0011 0000001 +110-111-001- 0000001 +11001-1-0-11 0000001 +1100111-0-1- 0000001 +1-0101110101 0000001 +1101011-0101 0000001 +1-01--110111 0000001 +1-01-111011- 0000001 +1-011-1101-1 0000001 +1-01111101-- 0000001 +1101--1-0111 0000001 +1101-11-011- 0000001 +11011-1-01-1 0000001 +1101111-01-- 0000001 +1--0-1111001 0000001 +1--0011110-1 0000001 +1-10-111-001 0000001 +1-100111-0-1 0000001 +11-0-11-1001 0000001 +11-0011-10-1 0000001 +1110-11--001 0000001 +1110011--0-1 0000001 +1--01-111011 0000001 +1--01111101- 0000001 +1-101-11-011 0000001 +1-101111-01- 0000001 +11-01-1-1011 0000001 +11-0111-101- 0000001 +11101-1--011 0000001 +1110111--01- 0000001 +1---01111101 0000001 +1--101111-01 0000001 +1-1-0111-101 0000001 +1-110111--01 0000001 +11--011-1101 0000001 +11-1011-1-01 0000001 +111-011--101 0000001 +1111011---01 0000001 +1-----111111 0000001 +1----111111- 0000001 +1---1-1111-1 0000001 +1---111111-- 0000001 +1--1--111-11 0000001 +1--1-1111-1- 0000001 +1--11-111--1 0000001 +1--111111--- 0000001 +1-1---11-111 0000001 +1-1--111-11- 0000001 +1-1-1-11-1-1 0000001 +1-1-1111-1-- 0000001 +1-11--11--11 0000001 +1-11-111--1- 0000001 +1-111-11---1 0000001 +1-111111---- 0000001 +11----1-1111 0000001 +11---11-111- 0000001 +11--1-1-11-1 0000001 +11--111-11-- 0000001 +11-1--1-1-11 0000001 +11-1-11-1-1- 0000001 +11-11-1-1--1 0000001 +11-1111-1--- 0000001 +111---1--111 0000001 +111--11--11- 0000001 +111-1-1--1-1 0000001 +111-111--1-- 0000001 +1111--1---11 0000001 +1111-11---1- 0000001 +11111-1----1 0000001 +1111111----- 0000001 diff --git a/espresso/examples/math/addm4 b/espresso/examples/math/addm4 new file mode 100644 index 0000000..c52f6ea --- /dev/null +++ b/espresso/examples/math/addm4 @@ -0,0 +1,517 @@ +# 4 bit by 4 bit adder/multiplier +.i 9 +.o 8 +.p 512 +0 0000 0000 00000000 +0 0000 0001 00000001 +0 0000 0010 00000010 +0 0000 0011 00000011 +0 0000 0100 00000100 +0 0000 0101 00000101 +0 0000 0110 00000110 +0 0000 0111 00000111 +0 0000 1000 00001000 +0 0000 1001 00001001 +0 0000 1010 00001010 +0 0000 1011 00001011 +0 0000 1100 00001100 +0 0000 1101 00001101 +0 0000 1110 00001110 +0 0000 1111 00001111 +0 0001 0000 00000001 +0 0001 0001 00000010 +0 0001 0010 00000011 +0 0001 0011 00000100 +0 0001 0100 00000101 +0 0001 0101 00000110 +0 0001 0110 00000111 +0 0001 0111 00001000 +0 0001 1000 00001001 +0 0001 1001 00001010 +0 0001 1010 00001011 +0 0001 1011 00001100 +0 0001 1100 00001101 +0 0001 1101 00001110 +0 0001 1110 00001111 +0 0001 1111 00010000 +0 0010 0000 00000010 +0 0010 0001 00000011 +0 0010 0010 00000100 +0 0010 0011 00000101 +0 0010 0100 00000110 +0 0010 0101 00000111 +0 0010 0110 00001000 +0 0010 0111 00001001 +0 0010 1000 00001010 +0 0010 1001 00001011 +0 0010 1010 00001100 +0 0010 1011 00001101 +0 0010 1100 00001110 +0 0010 1101 00001111 +0 0010 1110 00010000 +0 0010 1111 00010001 +0 0011 0000 00000011 +0 0011 0001 00000100 +0 0011 0010 00000101 +0 0011 0011 00000110 +0 0011 0100 00000111 +0 0011 0101 00001000 +0 0011 0110 00001001 +0 0011 0111 00001010 +0 0011 1000 00001011 +0 0011 1001 00001100 +0 0011 1010 00001101 +0 0011 1011 00001110 +0 0011 1100 00001111 +0 0011 1101 00010000 +0 0011 1110 00010001 +0 0011 1111 00010010 +0 0100 0000 00000100 +0 0100 0001 00000101 +0 0100 0010 00000110 +0 0100 0011 00000111 +0 0100 0100 00001000 +0 0100 0101 00001001 +0 0100 0110 00001010 +0 0100 0111 00001011 +0 0100 1000 00001100 +0 0100 1001 00001101 +0 0100 1010 00001110 +0 0100 1011 00001111 +0 0100 1100 00010000 +0 0100 1101 00010001 +0 0100 1110 00010010 +0 0100 1111 00010011 +0 0101 0000 00000101 +0 0101 0001 00000110 +0 0101 0010 00000111 +0 0101 0011 00001000 +0 0101 0100 00001001 +0 0101 0101 00001010 +0 0101 0110 00001011 +0 0101 0111 00001100 +0 0101 1000 00001101 +0 0101 1001 00001110 +0 0101 1010 00001111 +0 0101 1011 00010000 +0 0101 1100 00010001 +0 0101 1101 00010010 +0 0101 1110 00010011 +0 0101 1111 00010100 +0 0110 0000 00000110 +0 0110 0001 00000111 +0 0110 0010 00001000 +0 0110 0011 00001001 +0 0110 0100 00001010 +0 0110 0101 00001011 +0 0110 0110 00001100 +0 0110 0111 00001101 +0 0110 1000 00001110 +0 0110 1001 00001111 +0 0110 1010 00010000 +0 0110 1011 00010001 +0 0110 1100 00010010 +0 0110 1101 00010011 +0 0110 1110 00010100 +0 0110 1111 00010101 +0 0111 0000 00000111 +0 0111 0001 00001000 +0 0111 0010 00001001 +0 0111 0011 00001010 +0 0111 0100 00001011 +0 0111 0101 00001100 +0 0111 0110 00001101 +0 0111 0111 00001110 +0 0111 1000 00001111 +0 0111 1001 00010000 +0 0111 1010 00010001 +0 0111 1011 00010010 +0 0111 1100 00010011 +0 0111 1101 00010100 +0 0111 1110 00010101 +0 0111 1111 00010110 +0 1000 0000 00001000 +0 1000 0001 00001001 +0 1000 0010 00001010 +0 1000 0011 00001011 +0 1000 0100 00001100 +0 1000 0101 00001101 +0 1000 0110 00001110 +0 1000 0111 00001111 +0 1000 1000 00010000 +0 1000 1001 00010001 +0 1000 1010 00010010 +0 1000 1011 00010011 +0 1000 1100 00010100 +0 1000 1101 00010101 +0 1000 1110 00010110 +0 1000 1111 00010111 +0 1001 0000 00001001 +0 1001 0001 00001010 +0 1001 0010 00001011 +0 1001 0011 00001100 +0 1001 0100 00001101 +0 1001 0101 00001110 +0 1001 0110 00001111 +0 1001 0111 00010000 +0 1001 1000 00010001 +0 1001 1001 00010010 +0 1001 1010 00010011 +0 1001 1011 00010100 +0 1001 1100 00010101 +0 1001 1101 00010110 +0 1001 1110 00010111 +0 1001 1111 00011000 +0 1010 0000 00001010 +0 1010 0001 00001011 +0 1010 0010 00001100 +0 1010 0011 00001101 +0 1010 0100 00001110 +0 1010 0101 00001111 +0 1010 0110 00010000 +0 1010 0111 00010001 +0 1010 1000 00010010 +0 1010 1001 00010011 +0 1010 1010 00010100 +0 1010 1011 00010101 +0 1010 1100 00010110 +0 1010 1101 00010111 +0 1010 1110 00011000 +0 1010 1111 00011001 +0 1011 0000 00001011 +0 1011 0001 00001100 +0 1011 0010 00001101 +0 1011 0011 00001110 +0 1011 0100 00001111 +0 1011 0101 00010000 +0 1011 0110 00010001 +0 1011 0111 00010010 +0 1011 1000 00010011 +0 1011 1001 00010100 +0 1011 1010 00010101 +0 1011 1011 00010110 +0 1011 1100 00010111 +0 1011 1101 00011000 +0 1011 1110 00011001 +0 1011 1111 00011010 +0 1100 0000 00001100 +0 1100 0001 00001101 +0 1100 0010 00001110 +0 1100 0011 00001111 +0 1100 0100 00010000 +0 1100 0101 00010001 +0 1100 0110 00010010 +0 1100 0111 00010011 +0 1100 1000 00010100 +0 1100 1001 00010101 +0 1100 1010 00010110 +0 1100 1011 00010111 +0 1100 1100 00011000 +0 1100 1101 00011001 +0 1100 1110 00011010 +0 1100 1111 00011011 +0 1101 0000 00001101 +0 1101 0001 00001110 +0 1101 0010 00001111 +0 1101 0011 00010000 +0 1101 0100 00010001 +0 1101 0101 00010010 +0 1101 0110 00010011 +0 1101 0111 00010100 +0 1101 1000 00010101 +0 1101 1001 00010110 +0 1101 1010 00010111 +0 1101 1011 00011000 +0 1101 1100 00011001 +0 1101 1101 00011010 +0 1101 1110 00011011 +0 1101 1111 00011100 +0 1110 0000 00001110 +0 1110 0001 00001111 +0 1110 0010 00010000 +0 1110 0011 00010001 +0 1110 0100 00010010 +0 1110 0101 00010011 +0 1110 0110 00010100 +0 1110 0111 00010101 +0 1110 1000 00010110 +0 1110 1001 00010111 +0 1110 1010 00011000 +0 1110 1011 00011001 +0 1110 1100 00011010 +0 1110 1101 00011011 +0 1110 1110 00011100 +0 1110 1111 00011101 +0 1111 0000 00001111 +0 1111 0001 00010000 +0 1111 0010 00010001 +0 1111 0011 00010010 +0 1111 0100 00010011 +0 1111 0101 00010100 +0 1111 0110 00010101 +0 1111 0111 00010110 +0 1111 1000 00010111 +0 1111 1001 00011000 +0 1111 1010 00011001 +0 1111 1011 00011010 +0 1111 1100 00011011 +0 1111 1101 00011100 +0 1111 1110 00011101 +0 1111 1111 00011110 +1 0000 0000 00000000 +1 0000 0001 00000000 +1 0000 0010 00000000 +1 0000 0011 00000000 +1 0000 0100 00000000 +1 0000 0101 00000000 +1 0000 0110 00000000 +1 0000 0111 00000000 +1 0000 1000 00000000 +1 0000 1001 00000000 +1 0000 1010 00000000 +1 0000 1011 00000000 +1 0000 1100 00000000 +1 0000 1101 00000000 +1 0000 1110 00000000 +1 0000 1111 00000000 +1 0001 0000 00000000 +1 0001 0001 00000001 +1 0001 0010 00000010 +1 0001 0011 00000011 +1 0001 0100 00000100 +1 0001 0101 00000101 +1 0001 0110 00000110 +1 0001 0111 00000111 +1 0001 1000 00001000 +1 0001 1001 00001001 +1 0001 1010 00001010 +1 0001 1011 00001011 +1 0001 1100 00001100 +1 0001 1101 00001101 +1 0001 1110 00001110 +1 0001 1111 00001111 +1 0010 0000 00000000 +1 0010 0001 00000010 +1 0010 0010 00000100 +1 0010 0011 00000110 +1 0010 0100 00001000 +1 0010 0101 00001010 +1 0010 0110 00001100 +1 0010 0111 00001110 +1 0010 1000 00010000 +1 0010 1001 00010010 +1 0010 1010 00010100 +1 0010 1011 00010110 +1 0010 1100 00011000 +1 0010 1101 00011010 +1 0010 1110 00011100 +1 0010 1111 00011110 +1 0011 0000 00000000 +1 0011 0001 00000011 +1 0011 0010 00000110 +1 0011 0011 00001001 +1 0011 0100 00001100 +1 0011 0101 00001111 +1 0011 0110 00010010 +1 0011 0111 00010101 +1 0011 1000 00011000 +1 0011 1001 00011011 +1 0011 1010 00011110 +1 0011 1011 00100001 +1 0011 1100 00100100 +1 0011 1101 00100111 +1 0011 1110 00101010 +1 0011 1111 00101101 +1 0100 0000 00000000 +1 0100 0001 00000100 +1 0100 0010 00001000 +1 0100 0011 00001100 +1 0100 0100 00010000 +1 0100 0101 00010100 +1 0100 0110 00011000 +1 0100 0111 00011100 +1 0100 1000 00100000 +1 0100 1001 00100100 +1 0100 1010 00101000 +1 0100 1011 00101100 +1 0100 1100 00110000 +1 0100 1101 00110100 +1 0100 1110 00111000 +1 0100 1111 00111100 +1 0101 0000 00000000 +1 0101 0001 00000101 +1 0101 0010 00001010 +1 0101 0011 00001111 +1 0101 0100 00010100 +1 0101 0101 00011001 +1 0101 0110 00011110 +1 0101 0111 00100011 +1 0101 1000 00101000 +1 0101 1001 00101101 +1 0101 1010 00110010 +1 0101 1011 00110111 +1 0101 1100 00111100 +1 0101 1101 01000001 +1 0101 1110 01000110 +1 0101 1111 01001011 +1 0110 0000 00000000 +1 0110 0001 00000110 +1 0110 0010 00001100 +1 0110 0011 00010010 +1 0110 0100 00011000 +1 0110 0101 00011110 +1 0110 0110 00100100 +1 0110 0111 00101010 +1 0110 1000 00110000 +1 0110 1001 00110110 +1 0110 1010 00111100 +1 0110 1011 01000010 +1 0110 1100 01001000 +1 0110 1101 01001110 +1 0110 1110 01010100 +1 0110 1111 01011010 +1 0111 0000 00000000 +1 0111 0001 00000111 +1 0111 0010 00001110 +1 0111 0011 00010101 +1 0111 0100 00011100 +1 0111 0101 00100011 +1 0111 0110 00101010 +1 0111 0111 00110001 +1 0111 1000 00111000 +1 0111 1001 00111111 +1 0111 1010 01000110 +1 0111 1011 01001101 +1 0111 1100 01010100 +1 0111 1101 01011011 +1 0111 1110 01100010 +1 0111 1111 01101001 +1 1000 0000 00000000 +1 1000 0001 00001000 +1 1000 0010 00010000 +1 1000 0011 00011000 +1 1000 0100 00100000 +1 1000 0101 00101000 +1 1000 0110 00110000 +1 1000 0111 00111000 +1 1000 1000 01000000 +1 1000 1001 01001000 +1 1000 1010 01010000 +1 1000 1011 01011000 +1 1000 1100 01100000 +1 1000 1101 01101000 +1 1000 1110 01110000 +1 1000 1111 01111000 +1 1001 0000 00000000 +1 1001 0001 00001001 +1 1001 0010 00010010 +1 1001 0011 00011011 +1 1001 0100 00100100 +1 1001 0101 00101101 +1 1001 0110 00110110 +1 1001 0111 00111111 +1 1001 1000 01001000 +1 1001 1001 01010001 +1 1001 1010 01011010 +1 1001 1011 01100011 +1 1001 1100 01101100 +1 1001 1101 01110101 +1 1001 1110 01111110 +1 1001 1111 10000111 +1 1010 0000 00000000 +1 1010 0001 00001010 +1 1010 0010 00010100 +1 1010 0011 00011110 +1 1010 0100 00101000 +1 1010 0101 00110010 +1 1010 0110 00111100 +1 1010 0111 01000110 +1 1010 1000 01010000 +1 1010 1001 01011010 +1 1010 1010 01100100 +1 1010 1011 01101110 +1 1010 1100 01111000 +1 1010 1101 10000010 +1 1010 1110 10001100 +1 1010 1111 10010110 +1 1011 0000 00000000 +1 1011 0001 00001011 +1 1011 0010 00010110 +1 1011 0011 00100001 +1 1011 0100 00101100 +1 1011 0101 00110111 +1 1011 0110 01000010 +1 1011 0111 01001101 +1 1011 1000 01011000 +1 1011 1001 01100011 +1 1011 1010 01101110 +1 1011 1011 01111001 +1 1011 1100 10000100 +1 1011 1101 10001111 +1 1011 1110 10011010 +1 1011 1111 10100101 +1 1100 0000 00000000 +1 1100 0001 00001100 +1 1100 0010 00011000 +1 1100 0011 00100100 +1 1100 0100 00110000 +1 1100 0101 00111100 +1 1100 0110 01001000 +1 1100 0111 01010100 +1 1100 1000 01100000 +1 1100 1001 01101100 +1 1100 1010 01111000 +1 1100 1011 10000100 +1 1100 1100 10010000 +1 1100 1101 10011100 +1 1100 1110 10101000 +1 1100 1111 10110100 +1 1101 0000 00000000 +1 1101 0001 00001101 +1 1101 0010 00011010 +1 1101 0011 00100111 +1 1101 0100 00110100 +1 1101 0101 01000001 +1 1101 0110 01001110 +1 1101 0111 01011011 +1 1101 1000 01101000 +1 1101 1001 01110101 +1 1101 1010 10000010 +1 1101 1011 10001111 +1 1101 1100 10011100 +1 1101 1101 10101001 +1 1101 1110 10110110 +1 1101 1111 11000011 +1 1110 0000 00000000 +1 1110 0001 00001110 +1 1110 0010 00011100 +1 1110 0011 00101010 +1 1110 0100 00111000 +1 1110 0101 01000110 +1 1110 0110 01010100 +1 1110 0111 01100010 +1 1110 1000 01110000 +1 1110 1001 01111110 +1 1110 1010 10001100 +1 1110 1011 10011010 +1 1110 1100 10101000 +1 1110 1101 10110110 +1 1110 1110 11000100 +1 1110 1111 11010010 +1 1111 0000 00000000 +1 1111 0001 00001111 +1 1111 0010 00011110 +1 1111 0011 00101101 +1 1111 0100 00111100 +1 1111 0101 01001011 +1 1111 0110 01011010 +1 1111 0111 01101001 +1 1111 1000 01111000 +1 1111 1001 10000111 +1 1111 1010 10010110 +1 1111 1011 10100101 +1 1111 1100 10110100 +1 1111 1101 11000011 +1 1111 1110 11010010 +1 1111 1111 11100001 +.e diff --git a/espresso/examples/math/adr4 b/espresso/examples/math/adr4 new file mode 100644 index 0000000..5e841c4 --- /dev/null +++ b/espresso/examples/math/adr4 @@ -0,0 +1,260 @@ +.i 8 +.o 5 +.p 256 +00000000|00000 +00000001|00001 +00000010|00010 +00000011|00011 +00000100|00100 +00000101|00101 +00000110|00110 +00000111|00111 +00001000|01000 +00001001|01001 +00001010|01010 +00001011|01011 +00001100|01100 +00001101|01101 +00001110|01110 +00001111|01111 +00010000|00001 +00010001|00010 +00010010|00011 +00010011|00100 +00010100|00101 +00010101|00110 +00010110|00111 +00010111|01000 +00011000|01001 +00011001|01010 +00011010|01011 +00011011|01100 +00011100|01101 +00011101|01110 +00011110|01111 +00011111|10000 +00100000|00010 +00100001|00011 +00100010|00100 +00100011|00101 +00100100|00110 +00100101|00111 +00100110|01000 +00100111|01001 +00101000|01010 +00101001|01011 +00101010|01100 +00101011|01101 +00101100|01110 +00101101|01111 +00101110|10000 +00101111|10001 +00110000|00011 +00110001|00100 +00110010|00101 +00110011|00110 +00110100|00111 +00110101|01000 +00110110|01001 +00110111|01010 +00111000|01011 +00111001|01100 +00111010|01101 +00111011|01110 +00111100|01111 +00111101|10000 +00111110|10001 +00111111|10010 +01000000|00100 +01000001|00101 +01000010|00110 +01000011|00111 +01000100|01000 +01000101|01001 +01000110|01010 +01000111|01011 +01001000|01100 +01001001|01101 +01001010|01110 +01001011|01111 +01001100|10000 +01001101|10001 +01001110|10010 +01001111|10011 +01010000|00101 +01010001|00110 +01010010|00111 +01010011|01000 +01010100|01001 +01010101|01010 +01010110|01011 +01010111|01100 +01011000|01101 +01011001|01110 +01011010|01111 +01011011|10000 +01011100|10001 +01011101|10010 +01011110|10011 +01011111|10100 +01100000|00110 +01100001|00111 +01100010|01000 +01100011|01001 +01100100|01010 +01100101|01011 +01100110|01100 +01100111|01101 +01101000|01110 +01101001|01111 +01101010|10000 +01101011|10001 +01101100|10010 +01101101|10011 +01101110|10100 +01101111|10101 +01110000|00111 +01110001|01000 +01110010|01001 +01110011|01010 +01110100|01011 +01110101|01100 +01110110|01101 +01110111|01110 +01111000|01111 +01111001|10000 +01111010|10001 +01111011|10010 +01111100|10011 +01111101|10100 +01111110|10101 +01111111|10110 +10000000|01000 +10000001|01001 +10000010|01010 +10000011|01011 +10000100|01100 +10000101|01101 +10000110|01110 +10000111|01111 +10001000|10000 +10001001|10001 +10001010|10010 +10001011|10011 +10001100|10100 +10001101|10101 +10001110|10110 +10001111|10111 +10010000|01001 +10010001|01010 +10010010|01011 +10010011|01100 +10010100|01101 +10010101|01110 +10010110|01111 +10010111|10000 +10011000|10001 +10011001|10010 +10011010|10011 +10011011|10100 +10011100|10101 +10011101|10110 +10011110|10111 +10011111|11000 +10100000|01010 +10100001|01011 +10100010|01100 +10100011|01101 +10100100|01110 +10100101|01111 +10100110|10000 +10100111|10001 +10101000|10010 +10101001|10011 +10101010|10100 +10101011|10101 +10101100|10110 +10101101|10111 +10101110|11000 +10101111|11001 +10110000|01011 +10110001|01100 +10110010|01101 +10110011|01110 +10110100|01111 +10110101|10000 +10110110|10001 +10110111|10010 +10111000|10011 +10111001|10100 +10111010|10101 +10111011|10110 +10111100|10111 +10111101|11000 +10111110|11001 +10111111|11010 +11000000|01100 +11000001|01101 +11000010|01110 +11000011|01111 +11000100|10000 +11000101|10001 +11000110|10010 +11000111|10011 +11001000|10100 +11001001|10101 +11001010|10110 +11001011|10111 +11001100|11000 +11001101|11001 +11001110|11010 +11001111|11011 +11010000|01101 +11010001|01110 +11010010|01111 +11010011|10000 +11010100|10001 +11010101|10010 +11010110|10011 +11010111|10100 +11011000|10101 +11011001|10110 +11011010|10111 +11011011|11000 +11011100|11001 +11011101|11010 +11011110|11011 +11011111|11100 +11100000|01110 +11100001|01111 +11100010|10000 +11100011|10001 +11100100|10010 +11100101|10011 +11100110|10100 +11100111|10101 +11101000|10110 +11101001|10111 +11101010|11000 +11101011|11001 +11101100|11010 +11101101|11011 +11101110|11100 +11101111|11101 +11110000|01111 +11110001|10000 +11110010|10001 +11110011|10010 +11110100|10011 +11110101|10100 +11110110|10101 +11110111|10110 +11111000|10111 +11111001|11000 +11111010|11001 +11111011|11010 +11111100|11011 +11111101|11100 +11111110|11101 +11111111|11110 +.e diff --git a/espresso/examples/math/bcd.div3 b/espresso/examples/math/bcd.div3 new file mode 100644 index 0000000..1429034 --- /dev/null +++ b/espresso/examples/math/bcd.div3 @@ -0,0 +1,20 @@ +.i 4 +.o 4 +.ilb b3 b2 b1 b0 +.ob q1 q0 r1 r0 +0000 00 00 +0001 00 01 +0010 00 10 +0011 01 00 +0100 01 01 +0101 01 10 +0110 10 00 +0111 10 01 +1000 10 10 +1001 11 00 +1010 22 22 +1011 22 22 +1100 22 22 +1101 22 22 +1110 22 22 +1111 22 22 diff --git a/espresso/examples/math/co14 b/espresso/examples/math/co14 new file mode 100644 index 0000000..099f3d8 --- /dev/null +++ b/espresso/examples/math/co14 @@ -0,0 +1,49 @@ +.i 14 +.o 1 +10000000000000 1 +01000000000000 1 +00100000000000 1 +00010000000000 1 +00001000000000 1 +00000100000000 1 +00000010000000 1 +00000001000000 1 +00000000100000 1 +00000000010000 1 +00000000001000 1 +00000000000100 1 +00000000000010 1 +00000000000001 1 +11------------ 0 +1-1----------- 0 +1--------1---- 0 +1---------1--- 0 +-11----------- 0 +-1-------1---- 0 +-1--------1--- 0 +--1-------1--- 0 +---1-1-------- 0 +---11--------- 0 +---1-----1---- 0 +----11-------- 0 +----1------1-- 0 +----1----1---- 0 +-----1---1---- 0 +-----1-----1-- 0 +------11------ 0 +------1-1----- 0 +------1---1--- 0 +------1----1-- 0 +-------11----- 0 +-------1--1--- 0 +-------1---1-- 0 +--------1--1-- 0 +---------11--- 0 +---------1-1-- 0 +---------1--1- 0 +----------11-- 0 +----------1-1- 0 +----------1--1 0 +-----------11- 0 +-----------1-1 0 +------------11 0 diff --git a/espresso/examples/math/dist b/espresso/examples/math/dist new file mode 100644 index 0000000..35e28d0 --- /dev/null +++ b/espresso/examples/math/dist @@ -0,0 +1,258 @@ +.i 8 +.o 5 +00000000 00000 +00000001 00001 +00000010 00010 +00000011 00011 +00000100 00100 +00000101 00101 +00000110 00110 +00000111 00111 +00001000 01000 +00001001 01001 +00001010 01010 +00001011 01011 +00001100 01100 +00001101 01101 +00001110 01110 +00001111 01111 +00010000 00001 +00010001 00001 +00010010 00010 +00010011 00011 +00010100 00100 +00010101 00101 +00010110 00110 +00010111 00111 +00011000 01000 +00011001 01001 +00011010 01010 +00011011 01011 +00011100 01100 +00011101 01101 +00011110 01110 +00011111 01111 +00100000 00010 +00100001 00010 +00100010 00011 +00100011 00100 +00100100 00100 +00100101 00101 +00100110 00110 +00100111 00111 +00101000 01000 +00101001 01001 +00101010 01010 +00101011 01011 +00101100 01100 +00101101 01101 +00101110 01110 +00101111 01111 +00110000 00011 +00110001 00011 +00110010 00100 +00110011 00100 +00110100 00101 +00110101 00110 +00110110 00111 +00110111 01000 +00111000 01001 +00111001 01001 +00111010 01010 +00111011 01011 +00111100 01100 +00111101 01101 +00111110 01110 +00111111 01111 +01000000 00100 +01000001 00100 +01000010 00100 +01000011 00101 +01000100 00110 +01000101 00110 +01000110 00111 +01000111 01000 +01001000 01001 +01001001 01010 +01001010 01011 +01001011 01100 +01001100 01101 +01001101 01110 +01001110 01111 +01001111 10000 +01010000 00101 +01010001 00101 +01010010 00101 +01010011 00110 +01010100 00110 +01010101 00111 +01010110 01000 +01010111 01001 +01011000 01001 +01011001 01010 +01011010 01011 +01011011 01100 +01011100 01101 +01011101 01110 +01011110 01111 +01011111 10000 +01100000 00110 +01100001 00110 +01100010 00110 +01100011 00111 +01100100 00111 +01100101 01000 +01100110 01000 +01100111 01001 +01101000 01010 +01101001 01011 +01101010 01100 +01101011 01101 +01101100 01101 +01101101 01110 +01101110 01111 +01101111 10000 +01110000 00111 +01110001 00111 +01110010 00111 +01110011 01000 +01110100 01000 +01110101 01001 +01110110 01001 +01110111 01010 +01111000 01011 +01111001 01011 +01111010 01100 +01111011 01101 +01111100 01110 +01111101 01111 +01111110 10000 +01111111 10001 +10000000 01000 +10000001 01000 +10000010 01000 +10000011 01001 +10000100 01001 +10000101 01001 +10000110 01010 +10000111 01011 +10001000 01011 +10001001 01100 +10001010 01101 +10001011 01110 +10001100 01110 +10001101 01111 +10001110 10000 +10001111 10001 +10010000 01001 +10010001 01001 +10010010 01001 +10010011 01001 +10010100 01010 +10010101 01010 +10010110 01011 +10010111 01011 +10011000 01100 +10011001 01101 +10011010 01101 +10011011 01110 +10011100 01111 +10011101 10000 +10011110 10001 +10011111 10001 +10100000 01010 +10100001 01010 +10100010 01010 +10100011 01010 +10100100 01011 +10100101 01011 +10100110 01100 +10100111 01100 +10101000 01101 +10101001 01101 +10101010 01110 +10101011 01111 +10101100 10000 +10101101 10000 +10101110 10001 +10101111 10010 +10110000 01011 +10110001 01011 +10110010 01011 +10110011 01011 +10110100 01100 +10110101 01100 +10110110 01101 +10110111 01101 +10111000 01110 +10111001 01110 +10111010 01111 +10111011 10000 +10111100 10000 +10111101 10001 +10111110 10010 +10111111 10011 +11000000 01100 +11000001 01100 +11000010 01100 +11000011 01100 +11000100 01101 +11000101 01101 +11000110 01101 +11000111 01110 +11001000 01110 +11001001 01111 +11001010 10000 +11001011 10000 +11001100 10001 +11001101 10010 +11001110 10010 +11001111 10011 +11010000 01101 +11010001 01101 +11010010 01101 +11010011 01101 +11010100 01110 +11010101 01110 +11010110 01110 +11010111 01111 +11011000 01111 +11011001 10000 +11011010 10000 +11011011 10001 +11011100 10010 +11011101 10010 +11011110 10011 +11011111 10100 +11100000 01110 +11100001 01110 +11100010 01110 +11100011 01110 +11100100 01111 +11100101 01111 +11100110 01111 +11100111 10000 +11101000 10000 +11101001 10001 +11101010 10001 +11101011 10010 +11101100 10010 +11101101 10011 +11101110 10100 +11101111 10101 +11110000 01111 +11110001 01111 +11110010 01111 +11110011 01111 +11110100 10000 +11110101 10000 +11110110 10000 +11110111 10001 +11111000 10001 +11111001 10001 +11111010 10010 +11111011 10011 +11111100 10011 +11111101 10100 +11111110 10101 +11111111 10101 diff --git a/espresso/examples/math/f51m b/espresso/examples/math/f51m new file mode 100644 index 0000000..b821bbb --- /dev/null +++ b/espresso/examples/math/f51m @@ -0,0 +1,258 @@ +.i 8 +.o 8 +00000000 00000001 +00000001 00000110 +00000010 00001011 +00000011 00010000 +00000100 00010101 +00000101 00011010 +00000110 00011111 +00000111 00100100 +00001000 00101001 +00001001 00101110 +00001010 00110011 +00001011 00111000 +00001100 00111101 +00001101 01000010 +00001110 01000111 +00001111 01001100 +00010000 01010001 +00010001 01010110 +00010010 01011011 +00010011 01100000 +00010100 01100101 +00010101 01101010 +00010110 01101111 +00010111 01110100 +00011000 01111001 +00011001 01111110 +00011010 10000011 +00011011 10001000 +00011100 10001101 +00011101 10010010 +00011110 10010111 +00011111 10011100 +00100000 10100001 +00100001 10100110 +00100010 10101011 +00100011 10110000 +00100100 10110101 +00100101 10111010 +00100110 10111111 +00100111 11000100 +00101000 11001001 +00101001 11001110 +00101010 11010011 +00101011 11011000 +00101100 11011101 +00101101 11100010 +00101110 11100111 +00101111 11101100 +00110000 11110001 +00110001 11110110 +00110010 11111011 +00110011 00000000 +00110100 00000101 +00110101 00001010 +00110110 00001111 +00110111 00010100 +00111000 00011001 +00111001 00011110 +00111010 00100011 +00111011 00101000 +00111100 00101101 +00111101 00110010 +00111110 00110111 +00111111 00111100 +01000000 01000001 +01000001 01000110 +01000010 01001011 +01000011 01010000 +01000100 01010101 +01000101 01011010 +01000110 01011111 +01000111 01100100 +01001000 01101001 +01001001 01101110 +01001010 01110011 +01001011 01111000 +01001100 01111101 +01001101 10000010 +01001110 10000111 +01001111 10001100 +01010000 10010001 +01010001 10010110 +01010010 10011011 +01010011 10100000 +01010100 10100101 +01010101 10101010 +01010110 10101111 +01010111 10110100 +01011000 10111001 +01011001 10111110 +01011010 11000011 +01011011 11001000 +01011100 11001101 +01011101 11010010 +01011110 11010111 +01011111 11011100 +01100000 11100001 +01100001 11100110 +01100010 11101011 +01100011 11110000 +01100100 11110101 +01100101 11111010 +01100110 11111111 +01100111 00000100 +01101000 00001001 +01101001 00001110 +01101010 00010011 +01101011 00011000 +01101100 00011101 +01101101 00100010 +01101110 00100111 +01101111 00101100 +01110000 00110001 +01110001 00110110 +01110010 00111011 +01110011 01000000 +01110100 01000101 +01110101 01001010 +01110110 01001111 +01110111 01010100 +01111000 01011001 +01111001 01011110 +01111010 01100011 +01111011 01101000 +01111100 01101101 +01111101 01110010 +01111110 01110111 +01111111 01111100 +10000000 10000001 +10000001 10000110 +10000010 10001011 +10000011 10010000 +10000100 10010101 +10000101 10011010 +10000110 10011111 +10000111 10100100 +10001000 10101001 +10001001 10101110 +10001010 10110011 +10001011 10111000 +10001100 10111101 +10001101 11000010 +10001110 11000111 +10001111 11001100 +10010000 11010001 +10010001 11010110 +10010010 11011011 +10010011 11100000 +10010100 11100101 +10010101 11101010 +10010110 11101111 +10010111 11110100 +10011000 11111001 +10011001 11111110 +10011010 00000011 +10011011 00001000 +10011100 00001101 +10011101 00010010 +10011110 00010111 +10011111 00011100 +10100000 00100001 +10100001 00100110 +10100010 00101011 +10100011 00110000 +10100100 00110101 +10100101 00111010 +10100110 00111111 +10100111 01000100 +10101000 01001001 +10101001 01001110 +10101010 01010011 +10101011 01011000 +10101100 01011101 +10101101 01100010 +10101110 01100111 +10101111 01101100 +10110000 01110001 +10110001 01110110 +10110010 01111011 +10110011 10000000 +10110100 10000101 +10110101 10001010 +10110110 10001111 +10110111 10010100 +10111000 10011001 +10111001 10011110 +10111010 10100011 +10111011 10101000 +10111100 10101101 +10111101 10110010 +10111110 10110111 +10111111 10111100 +11000000 11000001 +11000001 11000110 +11000010 11001011 +11000011 11010000 +11000100 11010101 +11000101 11011010 +11000110 11011111 +11000111 11100100 +11001000 11101001 +11001001 11101110 +11001010 11110011 +11001011 11111000 +11001100 11111101 +11001101 00000010 +11001110 00000111 +11001111 00001100 +11010000 00010001 +11010001 00010110 +11010010 00011011 +11010011 00100000 +11010100 00100101 +11010101 00101010 +11010110 00101111 +11010111 00110100 +11011000 00111001 +11011001 00111110 +11011010 01000011 +11011011 01001000 +11011100 01001101 +11011101 01010010 +11011110 01010111 +11011111 01011100 +11100000 01100001 +11100001 01100110 +11100010 01101011 +11100011 01110000 +11100100 01110101 +11100101 01111010 +11100110 01111111 +11100111 10000100 +11101000 10001001 +11101001 10001110 +11101010 10010011 +11101011 10011000 +11101100 10011101 +11101101 10100010 +11101110 10100111 +11101111 10101100 +11110000 10110001 +11110001 10110110 +11110010 10111011 +11110011 11000000 +11110100 11000101 +11110101 11001010 +11110110 11001111 +11110111 11010100 +11111000 11011001 +11111001 11011110 +11111010 11100011 +11111011 11101000 +11111100 11101101 +11111101 11110010 +11111110 11110111 +11111111 11111100 diff --git a/espresso/examples/math/l8err b/espresso/examples/math/l8err new file mode 100644 index 0000000..6c29dd6 --- /dev/null +++ b/espresso/examples/math/l8err @@ -0,0 +1,261 @@ +.i 8 +.o 8 +.p 256 +00000000 00000000 +00000001 00000000 +00000010 00000001 +00000011 00000001 +00000100 00000010 +00000101 00000010 +00000110 00000011 +00000111 00000011 +00001000 00000011 +00001001 00000100 +00001010 00000100 +00001011 00000101 +00001100 00000101 +00001101 00000101 +00001110 00000110 +00001111 00000110 +00010000 00000110 +00010001 00000111 +00010010 00000111 +00010011 00000111 +00010100 00001000 +00010101 00001000 +00010110 00001000 +00010111 00001001 +00011000 00001001 +00011001 00001001 +00011010 00001010 +00011011 00001010 +00011100 00001010 +00011101 00001011 +00011110 00001011 +00011111 00001011 +00100000 00001100 +00100001 00001100 +00100010 00001100 +00100011 00001100 +00100100 00001101 +00100101 00001101 +00100110 00001101 +00100111 00001101 +00101000 00001110 +00101001 00001110 +00101010 00001110 +00101011 00001110 +00101100 00001111 +00101101 00001111 +00101110 00001111 +00101111 00001111 +00110000 00001111 +00110001 00010000 +00110010 00010000 +00110011 00010000 +00110100 00010000 +00110101 00010000 +00110110 00010001 +00110111 00010001 +00111000 00010001 +00111001 00010001 +00111010 00010001 +00111011 00010010 +00111100 00010010 +00111101 00010010 +00111110 00010010 +00111111 00010010 +01000000 00010010 +01000001 00010011 +01000010 00010011 +01000011 00010011 +01000100 00010011 +01000101 00010011 +01000110 00010011 +01000111 00010011 +01001000 00010100 +01001001 00010100 +01001010 00010100 +01001011 00010100 +01001100 00010100 +01001101 00010100 +01001110 00010100 +01001111 00010100 +01010000 00010100 +01010001 00010101 +01010010 00010101 +01010011 00010101 +01010100 00010101 +01010101 00010101 +01010110 00010101 +01010111 00010101 +01011000 00010101 +01011001 00010101 +01011010 00010101 +01011011 00010101 +01011100 00010101 +01011101 00010101 +01011110 00010110 +01011111 00010110 +01100000 00010110 +01100001 00010110 +01100010 00010110 +01100011 00010110 +01100100 00010110 +01100101 00010110 +01100110 00010110 +01100111 00010110 +01101000 00010110 +01101001 00010110 +01101010 00010110 +01101011 00010110 +01101100 00010110 +01101101 00010110 +01101110 00010110 +01101111 00010110 +01110000 00010110 +01110001 00010110 +01110010 00010110 +01110011 00010110 +01110100 00010110 +01110101 00010110 +01110110 00010110 +01110111 00010110 +01111000 00010110 +01111001 00010110 +01111010 00010110 +01111011 00010110 +01111100 00010110 +01111101 00010110 +01111110 00010110 +01111111 00010110 +10000000 00010110 +10000001 00010110 +10000010 00010110 +10000011 00010110 +10000100 00010110 +10000101 00010110 +10000110 00010101 +10000111 00010101 +10001000 00010101 +10001001 00010101 +10001010 00010101 +10001011 00010101 +10001100 00010101 +10001101 00010101 +10001110 00010101 +10001111 00010101 +10010000 00010101 +10010001 00010101 +10010010 00010101 +10010011 00010101 +10010100 00010101 +10010101 00010100 +10010110 00010100 +10010111 00010100 +10011000 00010100 +10011001 00010100 +10011010 00010100 +10011011 00010100 +10011100 00010100 +10011101 00010100 +10011110 00010100 +10011111 00010011 +10100000 00010011 +10100001 00010011 +10100010 00010011 +10100011 00010011 +10100100 00010011 +10100101 00010011 +10100110 00010011 +10100111 00010010 +10101000 00010010 +10101001 00010010 +10101010 00010010 +10101011 00010010 +10101100 00010010 +10101101 00010010 +10101110 00010010 +10101111 00010001 +10110000 00010001 +10110001 00010001 +10110010 00010001 +10110011 00010001 +10110100 00010001 +10110101 00010001 +10110110 00010000 +10110111 00010000 +10111000 00010000 +10111001 00010000 +10111010 00010000 +10111011 00010000 +10111100 00001111 +10111101 00001111 +10111110 00001111 +10111111 00001111 +11000000 00001111 +11000001 00001111 +11000010 00001110 +11000011 00001110 +11000100 00001110 +11000101 00001110 +11000110 00001110 +11000111 00001101 +11001000 00001101 +11001001 00001101 +11001010 00001101 +11001011 00001101 +11001100 00001100 +11001101 00001100 +11001110 00001100 +11001111 00001100 +11010000 00001100 +11010001 00001011 +11010010 00001011 +11010011 00001011 +11010100 00001011 +11010101 00001011 +11010110 00001010 +11010111 00001010 +11011000 00001010 +11011001 00001010 +11011010 00001010 +11011011 00001001 +11011100 00001001 +11011101 00001001 +11011110 00001001 +11011111 00001000 +11100000 00001000 +11100001 00001000 +11100010 00001000 +11100011 00000111 +11100100 00000111 +11100101 00000111 +11100110 00000111 +11100111 00000111 +11101000 00000110 +11101001 00000110 +11101010 00000110 +11101011 00000110 +11101100 00000101 +11101101 00000101 +11101110 00000101 +11101111 00000101 +11110000 00000100 +11110001 00000100 +11110010 00000100 +11110011 00000100 +11110100 00000011 +11110101 00000011 +11110110 00000011 +11110111 00000010 +11111000 00000010 +11111001 00000010 +11111010 00000010 +11111011 00000001 +11111100 00000001 +11111101 00000001 +11111110 00000001 +11111111 00000000 +-------- 0000000- +.e diff --git a/espresso/examples/math/life b/espresso/examples/math/life new file mode 100644 index 0000000..4271653 --- /dev/null +++ b/espresso/examples/math/life @@ -0,0 +1,517 @@ +# Conways game of life +.i 9 +.o 1 +.ilb w b0 b1 b2 b3 b4 b5 b6 b7 +.ob neww +000000000 0 +000000001 0 +000000010 0 +000000011 0 +000000100 0 +000000101 0 +000000110 0 +000000111 1 +000001000 0 +000001001 0 +000001010 0 +000001011 1 +000001100 0 +000001101 1 +000001110 1 +000001111 0 +000010000 0 +000010001 0 +000010010 0 +000010011 1 +000010100 0 +000010101 1 +000010110 1 +000010111 0 +000011000 0 +000011001 1 +000011010 1 +000011011 0 +000011100 1 +000011101 0 +000011110 0 +000011111 0 +000100000 0 +000100001 0 +000100010 0 +000100011 1 +000100100 0 +000100101 1 +000100110 1 +000100111 0 +000101000 0 +000101001 1 +000101010 1 +000101011 0 +000101100 1 +000101101 0 +000101110 0 +000101111 0 +000110000 0 +000110001 1 +000110010 1 +000110011 0 +000110100 1 +000110101 0 +000110110 0 +000110111 0 +000111000 1 +000111001 0 +000111010 0 +000111011 0 +000111100 0 +000111101 0 +000111110 0 +000111111 0 +001000000 0 +001000001 0 +001000010 0 +001000011 1 +001000100 0 +001000101 1 +001000110 1 +001000111 0 +001001000 0 +001001001 1 +001001010 1 +001001011 0 +001001100 1 +001001101 0 +001001110 0 +001001111 0 +001010000 0 +001010001 1 +001010010 1 +001010011 0 +001010100 1 +001010101 0 +001010110 0 +001010111 0 +001011000 1 +001011001 0 +001011010 0 +001011011 0 +001011100 0 +001011101 0 +001011110 0 +001011111 0 +001100000 0 +001100001 1 +001100010 1 +001100011 0 +001100100 1 +001100101 0 +001100110 0 +001100111 0 +001101000 1 +001101001 0 +001101010 0 +001101011 0 +001101100 0 +001101101 0 +001101110 0 +001101111 0 +001110000 1 +001110001 0 +001110010 0 +001110011 0 +001110100 0 +001110101 0 +001110110 0 +001110111 0 +001111000 0 +001111001 0 +001111010 0 +001111011 0 +001111100 0 +001111101 0 +001111110 0 +001111111 0 +010000000 0 +010000001 0 +010000010 0 +010000011 1 +010000100 0 +010000101 1 +010000110 1 +010000111 0 +010001000 0 +010001001 1 +010001010 1 +010001011 0 +010001100 1 +010001101 0 +010001110 0 +010001111 0 +010010000 0 +010010001 1 +010010010 1 +010010011 0 +010010100 1 +010010101 0 +010010110 0 +010010111 0 +010011000 1 +010011001 0 +010011010 0 +010011011 0 +010011100 0 +010011101 0 +010011110 0 +010011111 0 +010100000 0 +010100001 1 +010100010 1 +010100011 0 +010100100 1 +010100101 0 +010100110 0 +010100111 0 +010101000 1 +010101001 0 +010101010 0 +010101011 0 +010101100 0 +010101101 0 +010101110 0 +010101111 0 +010110000 1 +010110001 0 +010110010 0 +010110011 0 +010110100 0 +010110101 0 +010110110 0 +010110111 0 +010111000 0 +010111001 0 +010111010 0 +010111011 0 +010111100 0 +010111101 0 +010111110 0 +010111111 0 +011000000 0 +011000001 1 +011000010 1 +011000011 0 +011000100 1 +011000101 0 +011000110 0 +011000111 0 +011001000 1 +011001001 0 +011001010 0 +011001011 0 +011001100 0 +011001101 0 +011001110 0 +011001111 0 +011010000 1 +011010001 0 +011010010 0 +011010011 0 +011010100 0 +011010101 0 +011010110 0 +011010111 0 +011011000 0 +011011001 0 +011011010 0 +011011011 0 +011011100 0 +011011101 0 +011011110 0 +011011111 0 +011100000 1 +011100001 0 +011100010 0 +011100011 0 +011100100 0 +011100101 0 +011100110 0 +011100111 0 +011101000 0 +011101001 0 +011101010 0 +011101011 0 +011101100 0 +011101101 0 +011101110 0 +011101111 0 +011110000 0 +011110001 0 +011110010 0 +011110011 0 +011110100 0 +011110101 0 +011110110 0 +011110111 0 +011111000 0 +011111001 0 +011111010 0 +011111011 0 +011111100 0 +011111101 0 +011111110 0 +011111111 0 +100000000 0 +100000001 0 +100000010 0 +100000011 1 +100000100 0 +100000101 1 +100000110 1 +100000111 1 +100001000 0 +100001001 1 +100001010 1 +100001011 1 +100001100 1 +100001101 1 +100001110 1 +100001111 0 +100010000 0 +100010001 1 +100010010 1 +100010011 1 +100010100 1 +100010101 1 +100010110 1 +100010111 0 +100011000 1 +100011001 1 +100011010 1 +100011011 0 +100011100 1 +100011101 0 +100011110 0 +100011111 0 +100100000 0 +100100001 1 +100100010 1 +100100011 1 +100100100 1 +100100101 1 +100100110 1 +100100111 0 +100101000 1 +100101001 1 +100101010 1 +100101011 0 +100101100 1 +100101101 0 +100101110 0 +100101111 0 +100110000 1 +100110001 1 +100110010 1 +100110011 0 +100110100 1 +100110101 0 +100110110 0 +100110111 0 +100111000 1 +100111001 0 +100111010 0 +100111011 0 +100111100 0 +100111101 0 +100111110 0 +100111111 0 +101000000 0 +101000001 1 +101000010 1 +101000011 1 +101000100 1 +101000101 1 +101000110 1 +101000111 0 +101001000 1 +101001001 1 +101001010 1 +101001011 0 +101001100 1 +101001101 0 +101001110 0 +101001111 0 +101010000 1 +101010001 1 +101010010 1 +101010011 0 +101010100 1 +101010101 0 +101010110 0 +101010111 0 +101011000 1 +101011001 0 +101011010 0 +101011011 0 +101011100 0 +101011101 0 +101011110 0 +101011111 0 +101100000 1 +101100001 1 +101100010 1 +101100011 0 +101100100 1 +101100101 0 +101100110 0 +101100111 0 +101101000 1 +101101001 0 +101101010 0 +101101011 0 +101101100 0 +101101101 0 +101101110 0 +101101111 0 +101110000 1 +101110001 0 +101110010 0 +101110011 0 +101110100 0 +101110101 0 +101110110 0 +101110111 0 +101111000 0 +101111001 0 +101111010 0 +101111011 0 +101111100 0 +101111101 0 +101111110 0 +101111111 0 +110000000 0 +110000001 1 +110000010 1 +110000011 1 +110000100 1 +110000101 1 +110000110 1 +110000111 0 +110001000 1 +110001001 1 +110001010 1 +110001011 0 +110001100 1 +110001101 0 +110001110 0 +110001111 0 +110010000 1 +110010001 1 +110010010 1 +110010011 0 +110010100 1 +110010101 0 +110010110 0 +110010111 0 +110011000 1 +110011001 0 +110011010 0 +110011011 0 +110011100 0 +110011101 0 +110011110 0 +110011111 0 +110100000 1 +110100001 1 +110100010 1 +110100011 0 +110100100 1 +110100101 0 +110100110 0 +110100111 0 +110101000 1 +110101001 0 +110101010 0 +110101011 0 +110101100 0 +110101101 0 +110101110 0 +110101111 0 +110110000 1 +110110001 0 +110110010 0 +110110011 0 +110110100 0 +110110101 0 +110110110 0 +110110111 0 +110111000 0 +110111001 0 +110111010 0 +110111011 0 +110111100 0 +110111101 0 +110111110 0 +110111111 0 +111000000 1 +111000001 1 +111000010 1 +111000011 0 +111000100 1 +111000101 0 +111000110 0 +111000111 0 +111001000 1 +111001001 0 +111001010 0 +111001011 0 +111001100 0 +111001101 0 +111001110 0 +111001111 0 +111010000 1 +111010001 0 +111010010 0 +111010011 0 +111010100 0 +111010101 0 +111010110 0 +111010111 0 +111011000 0 +111011001 0 +111011010 0 +111011011 0 +111011100 0 +111011101 0 +111011110 0 +111011111 0 +111100000 1 +111100001 0 +111100010 0 +111100011 0 +111100100 0 +111100101 0 +111100110 0 +111100111 0 +111101000 0 +111101001 0 +111101010 0 +111101011 0 +111101100 0 +111101101 0 +111101110 0 +111101111 0 +111110000 0 +111110001 0 +111110010 0 +111110011 0 +111110100 0 +111110101 0 +111110110 0 +111110111 0 +111111000 0 +111111001 0 +111111010 0 +111111011 0 +111111100 0 +111111101 0 +111111110 0 +111111111 0 diff --git a/espresso/examples/math/log8mod b/espresso/examples/math/log8mod new file mode 100644 index 0000000..22a05c7 --- /dev/null +++ b/espresso/examples/math/log8mod @@ -0,0 +1,49 @@ +.i 8 +.o 5 +0000000- 00000 +0000001- 00001 +111111-- 00001 +0000010- 00010 +111110-- 00010 +0000011- 00011 +111101-- 00011 +000010-- 00100 +111100-- 00100 +0000110- 00101 +111011-- 00101 +0000111- 00110 +0001000- 00110 +111010-- 00110 +000100-- 00111 +111001-- 00111 +000101-- 01000 +111000-- 01000 +0001100- 01001 +110111-- 01001 +0001101- 01010 +110110-- 01010 +000111-- 01011 +11010--- 01011 +001000-- 01100 +110011-- 01100 +001001-- 01101 +110010-- 01101 +001010-- 01110 +11000--- 01110 +001011-- 01111 +101111-- 01111 +00110--- 10000 +10111--- 10000 +001110-- 10001 +101100-- 10001 +001111-- 10010 +10101--- 10010 +01000--- 10011 +10100--- 10011 +01001--- 10100 +10011--- 10100 +0101---- 10101 +10010--- 10101 +10001--- 10101 +011----- 10110 +10000--- 10110 diff --git a/espresso/examples/math/m181 b/espresso/examples/math/m181 new file mode 100644 index 0000000..ac7eb60 --- /dev/null +++ b/espresso/examples/math/m181 @@ -0,0 +1,432 @@ +.i 15 +.o 9 +-0-0----0------ 000000010 +-------------0- 000001000 +0--0----------- 000000001 +---0----0------ 000000010 +-----------00-- 000100000 +--------0--0--- 000010000 +-------0-0----- 000010000 +-------0----0-- 000100000 +--00----0------ 000000010 +0------0------- 000010000 +0--------0----- 000000001 +0----------0--- 000010000 +-000----0------ 000000010 +---------0-0--- 000010000 +------------1-- 000001000 +0-----------1-- 000000001 +---------01---- 000000001 +----------1---- 000001011 +--------0-1---- 000000010 +-0--------1---- 000000010 +00-0---00-1---- 001000000 +-0------0-1---- 000000010 +-00-------1---- 000000010 +-00-----0-1---- 000000010 +--00----0-1---- 000000010 +--00------1---- 000000010 +--0-----0-1---- 000000010 +--0-------1---- 000000010 +-0-0------1---- 000000010 +---0----0-1---- 000000010 +-0-0----0-1---- 000000010 +-000------1---- 000000010 +---0------1---- 000000011 +-0-0---00-1---- 001000000 +00-0------1---- 001000000 +00-0----0-1---- 001000000 +0---------1---- 000000001 +00-0---0--1---- 001000000 +----------1-1-- 000000001 +00-0-----1----- 001000000 +-0------01----- 000000010 +-0-0---001----- 001000000 +-00-----01----- 000000010 +---0-----1----- 000000001 +00-0---001----- 001000000 +00-----0010---- 001000000 +00-0---0-10---- 001000100 +00-----0-10---- 001000000 +00-0---0-1----- 001000000 +--0-----01----- 000000010 +--------01----- 000000010 +-0-0---0010---- 001000100 +--00---0010---- 000000100 +-0-----0010---- 001000000 +0-00---0-10---- 000000100 +0--0---0-10---0 000000100 +00-0----010---- 001000000 +00-0----01----- 001000000 +---0---0010---0 000000100 +00-0-----10---- 001000000 +---------1--1-- 000000001 +--0-----011---- 000000010 +-00------11---- 000000010 +-0-------11---- 000000010 +---------11---- 000000011 +--0------11---- 000000010 +-0------011---- 000000010 +--------011---- 000000010 +0------1------- 000000001 +00-0---1------- 001000000 +00-0---1--0---- 001000000 +00-0---10------ 001000000 +00-0---10-0---- 001000000 +-0-0---1------- 000000010 +-0-0---10------ 000000010 +-00----1------- 000000010 +-00----10------ 000000010 +-------1-0----- 000000001 +-------1---0--- 000010000 +-------10------ 000000010 +---0---1------- 000000011 +---0---10------ 000000010 +-------1------- 000001011 +--0----1------- 000000010 +--0----10------ 000000010 +--00---1------- 000000010 +--00---10------ 000000010 +-0-----1------- 000000010 +-0-----10------ 000000010 +-000---1------- 000000010 +-------1----1-- 000000001 +-------1--1---- 000000011 +-------10-1---- 000000010 +-00----1--1---- 000000010 +-0-----10-1---- 000000010 +-0-----1--1---- 000000010 +--0----1--1---- 000000010 +-0-0---1--1---- 000000010 +---0---1--1---- 000000010 +--00---1--1---- 000000010 +---0---10-1---- 000000010 +--0----10-1---- 000000010 +-00----1-1----- 000000010 +-------101----- 000000010 +--0----1-1----- 000000010 +-0-----101----- 000000010 +--0----101----- 000000010 +-------1-1----- 000000011 +-0-----1-1----- 000000010 +-------1-11---- 000000010 +-------1011---- 000000010 +-0-----1-11---- 000000010 +--0----1-11---- 000000010 +00-1---0-00---- 000000100 +0--1---0-00---0 000000100 +---1---0000---0 000000100 +0-01---0-00---- 000000100 +--01---0000---- 000000100 +-0-1---0000---- 000000100 +-001------1---- 000000010 +-0-1------1---- 000000010 +-0-1----0-1---- 000000010 +---1------1---- 000000010 +--01----0-1---- 000000010 +---1----0-1---- 000000010 +--01------1---- 000000010 +--01----01----- 000000010 +---1----01----- 000000010 +-0-1----01----- 000000010 +-001-----1----- 000000010 +---1----011---- 000000010 +--01-----11---- 000000010 +---1-----11---- 000000010 +-0-1-----11---- 000000010 +-0-1---1------- 000000010 +--01---1------- 000000010 +-001---1------- 000000010 +---1---1------- 000000010 +-0-1---10------ 000000010 +---1---10------ 000000010 +--01---10------ 000000010 +--01---1--1---- 000000010 +---1---10-1---- 000000010 +---1---1--1---- 000000010 +-0-1---1--1---- 000000010 +--01---1-1----- 000000010 +-0-1---1-1----- 000000010 +---1---1-1----- 000000010 +---1---101----- 000000010 +---1---1-11---- 000000010 +--10---00------ 001000000 +001----0--0---- 001000100 +--1----0000---0 000000100 +--1----00-0---0 000000100 +--1----00-0---- 001000000 +--1----00------ 001000000 +0010----0-0---- 001000000 +--1-----0------ 000000010 +0010---0------- 001000000 +-01-----0------ 000000010 +0010----------- 001000000 +0-10---00------ 001000000 +0010---0--0---- 001000100 +001----0------- 001000000 +0-10---0--0---0 000000100 +0-10---0--0---- 001000000 +-01----00------ 001000000 +0-10---0------- 001000000 +001-----0-0---- 001000000 +-01----00-0---- 001000100 +-01----0000---- 000000100 +-010---00------ 001000000 +001-----0------ 001000000 +-010---00-0---- 001000100 +0-10----0-0---- 001000000 +001-------0---- 001000000 +0-10----0------ 001000000 +001----00-0---- 001000000 +001----00------ 001000000 +0-10------0---- 001000000 +0010---00------ 001000000 +0-10----------- 001000000 +001----0-00---- 000000100 +001------------ 001000000 +0-1----0--0---0 000000100 +0010------0---- 001000000 +0010----0------ 001000000 +--10---00-0---0 000000100 +--10---00-0---- 001000000 +0-1------------ 001000001 +0-1-------0---- 001000000 +0-1-----0------ 001000000 +0-1-----0-0---- 001000000 +0-1----00-0---- 001000000 +0-1----0------- 001000000 +0-1----00------ 001000000 +0-1----0-00---0 000000100 +0-1----0--0---- 001000000 +0010---0--1---- 001000000 +--1-------1---- 000000011 +0-1----0--1---- 001000000 +-01-------1---- 000000010 +--1-----0-1---- 000000010 +001-----0-1---- 001000000 +--1----00-1---- 001000000 +0-10------1---- 001000000 +--10---00-1---- 001000000 +001-------1---- 001000000 +0-1----00-1---- 001000000 +0-1-----0-1---- 001000000 +0010----0-1---- 001000000 +-01----00-1---- 001000000 +0010------1---- 001000000 +001----00-1---- 001000000 +0-1-------1---- 001000000 +0-10----0-1---- 001000000 +001----0--1---- 001000000 +-010---00-1---- 001000000 +0-10---0--1---- 001000000 +0-10---00-1---- 001000000 +-01-----0-1---- 000000010 +0-1----0-10---- 001000000 +0-1----0-10---0 000000100 +0010-----1----- 001000000 +-01----0010---- 001000100 +-01----001----- 001000000 +--10---0010---- 001000000 +0-1-----010---- 001000000 +0-1-----01----- 001000000 +0-1----001----- 001000000 +0-1------10---- 001000000 +0-1------1----- 001000000 +0-1----0010---- 001000000 +--10---001----- 001000000 +001----0-10---- 001000100 +001----001----- 001000000 +--1----0010---0 000000100 +0-10---0-1----- 001000000 +--1----0010---- 001000000 +0-10---0-10---- 001000000 +--1----001----- 001000000 +0-10---001----- 001000000 +001----0-1----- 001000000 +001-----010---- 001000000 +0010----01----- 001000000 +0-10-----1----- 001000000 +0-10-----10---- 001000000 +001------1----- 001000000 +001------10---- 001000000 +-010---001----- 001000000 +0-10----01----- 001000000 +0-10----010---- 001000000 +--1------1----- 000000001 +001-----01----- 001000000 +0010---0-1----- 001000000 +0-1----0-1----- 001000000 +0-1----10------ 001000000 +0-1----1--0---- 001000000 +0-1----1------- 001000000 +--1----1------- 000000011 +0010---10------ 001000000 +001----1--0---- 001000000 +0-10---1------- 001000000 +0-10---1--0---- 001000000 +0-1----10-0---- 001000000 +0-10---10------ 001000000 +001----10------ 001000000 +0-10---10-0---- 001000000 +-01----10------ 000000010 +0010---1------- 001000000 +001----10-0---- 001000000 +-01----1------- 000000010 +001----1------- 001000000 +--1----10------ 000000010 +--1----10-1---- 000000010 +--1----1--1---- 000000010 +-01----1--1---- 000000010 +001-1---------- 010000000 +0-1-10--------- 010000000 +0-1-1-0-------- 010000000 +0011----------- 010000000 +--11---00-0---0 000000100 +0-110---------- 100000000 +0-11--0-------- 010000000 +--11----0------ 000000010 +-011---00-0---- 000000100 +0-11-0--------- 010000000 +-011----0------ 000000010 +0011---0--0---- 000000100 +0-11---0--0---0 000000100 +-011------1---- 000000010 +--11----0-1---- 000000010 +--11------1---- 000000010 +--11---1------- 000000010 +--11---10------ 000000010 +-011---1------- 000000010 +--11---1--1---- 000000010 +0-1101--------- 100000000 +00111---------- 010000000 +0-1110--------- 010000000 +0-111-0-------- 010000000 +0100---0--0---- 000000100 +010----0-00---- 000000100 +-100---00-0---- 000000100 +-10----00-0---- 000000100 +-1-0---00-0---0 000000100 +010----0--0---- 000000100 +01-----0-00---0 000000100 +-10----0000---- 000000100 +01-----0--0---0 000000100 +-1-----0000---0 000000100 +01------------- 000000001 +-1-----00-0---0 000000100 +-10-----0------ 000000010 +-1------0------ 000000010 +01-0---0--0---0 000000100 +-1------0-1---- 000000010 +-1--------1---- 000000011 +-10-----0-1---- 000000010 +-10-------1---- 000000010 +-1-------1----- 000000001 +-10----0010---- 000000100 +-1-----0010---0 000000100 +010----0-10---- 000000100 +01-----0-10---0 000000100 +-1-----10------ 000000010 +-1-----1------- 000000011 +-10----10------ 000000010 +-10----1------- 000000010 +-10----1--1---- 000000010 +-1-----10-1---- 000000010 +-1-----1--1---- 000000010 +01-1--0-------- 010000000 +-101---00-0---- 000000100 +01-1-0--------- 010000000 +-101----0------ 000000010 +-1-1----0------ 000000010 +-1-1---00-0---0 000000100 +01-1---0--0---0 000000100 +0101---0--0---- 000000100 +01010---------- 100000000 +0101----------- 110000000 +01-10---------- 100000000 +-101------1---- 000000010 +-1-1------1---- 000000010 +-1-1----0-1---- 000000010 +-101---1------- 000000010 +-1-1---1------- 000000010 +-1-1---10------ 000000010 +-1-1---1--1---- 000000010 +01-101--------- 100000000 +01-1-1--------- 100000000 +01-11-0-------- 010000000 +01-110--------- 010000000 +01011---------- 010000000 +0110------0---- 001000000 +011----0--0---0 000000100 +-110---00-0---- 001000000 +011-----0-0---- 001000000 +0110----------- 001000000 +011----00------ 001000000 +-11----00-0---- 001000000 +011-----0------ 001000000 +011------------ 001000000 +011----00-0---- 001000000 +011-0---------- 100000000 +0110---00------ 001000000 +-11----00-0---0 000000100 +011-------0---- 001000000 +0110---0--0---- 001000000 +0110---0------- 001000000 +-110---00------ 001000000 +011----0--0---- 001000000 +0110----0-0---- 001000000 +0110----0------ 001000000 +011----0------- 001000000 +-11----00------ 001000000 +0110------1---- 001000000 +0110---0--1---- 001000000 +011-----0-1---- 001000000 +011----00-1---- 001000000 +011----0--1---- 001000000 +0110----0-1---- 001000000 +-110---00-1---- 001000000 +-11----00-1---- 001000000 +011-------1---- 001000000 +011----0-10---- 001000000 +011------10---- 001000000 +011----001----- 001000000 +011------1----- 001000000 +011-----010---- 001000000 +011----0-1----- 001000000 +011-----01----- 001000000 +-110---001----- 001000000 +-11----0010---- 001000000 +0110---0-1----- 001000000 +0110-----1----- 001000000 +0110----01----- 001000000 +-11----001----- 001000000 +011----1------- 001000000 +011----10------ 001000000 +011----1--0---- 001000000 +0110---10------ 001000000 +0110---1------- 001000000 +011----10-0---- 001000000 +011--1--------- 100000000 +011-01--------- 100000000 +011-1-0-------- 010000000 +011-10--------- 010000000 +0111-0--------- 010000000 +0111--0-------- 010000000 +01110---------- 100000000 +0111-1--------- 100000000 +011101--------- 100000000 +1-------------- 000001000 +1------0------- 000100000 +1----------0--- 000100000 +1--0---0010---- 000000100 +1--1---0000---- 000000100 +1-10---00-0---- 000000100 +1-1----0000---- 000000100 +1-1----00-0---- 000000100 +1-1----0010---- 000000100 +1-11---00-0---- 000000100 +11-0---00-0---- 000000100 +11-----00-0---- 000000100 +11-----0000---- 000000100 +11-----0010---- 000000100 +11-1---00-0---- 000000100 +111----00-0---- 000000100 diff --git a/espresso/examples/math/mlp4 b/espresso/examples/math/mlp4 new file mode 100644 index 0000000..da4de9f --- /dev/null +++ b/espresso/examples/math/mlp4 @@ -0,0 +1,261 @@ +# 4-bit by 4-bit binary multiplier +.i 8 +.o 8 +.p 256 +00000000 00000000 +00000001 00000000 +00000010 00000000 +00000011 00000000 +00000100 00000000 +00000101 00000000 +00000110 00000000 +00000111 00000000 +00001000 00000000 +00001001 00000000 +00001010 00000000 +00001011 00000000 +00001100 00000000 +00001101 00000000 +00001110 00000000 +00001111 00000000 +00010000 00000000 +00010001 00000001 +00010010 00000010 +00010011 00000011 +00010100 00000100 +00010101 00000101 +00010110 00000110 +00010111 00000111 +00011000 00001000 +00011001 00001001 +00011010 00001010 +00011011 00001011 +00011100 00001100 +00011101 00001101 +00011110 00001110 +00011111 00001111 +00100000 00000000 +00100001 00000010 +00100010 00000100 +00100011 00000110 +00100100 00001000 +00100101 00001010 +00100110 00001100 +00100111 00001110 +00101000 00010000 +00101001 00010010 +00101010 00010100 +00101011 00010110 +00101100 00011000 +00101101 00011010 +00101110 00011100 +00101111 00011110 +00110000 00000000 +00110001 00000011 +00110010 00000110 +00110011 00001001 +00110100 00001100 +00110101 00001111 +00110110 00010010 +00110111 00010101 +00111000 00011000 +00111001 00011011 +00111010 00011110 +00111011 00100001 +00111100 00100100 +00111101 00100111 +00111110 00101010 +00111111 00101101 +01000000 00000000 +01000001 00000100 +01000010 00001000 +01000011 00001100 +01000100 00010000 +01000101 00010100 +01000110 00011000 +01000111 00011100 +01001000 00100000 +01001001 00100100 +01001010 00101000 +01001011 00101100 +01001100 00110000 +01001101 00110100 +01001110 00111000 +01001111 00111100 +01010000 00000000 +01010001 00000101 +01010010 00001010 +01010011 00001111 +01010100 00010100 +01010101 00011001 +01010110 00011110 +01010111 00100011 +01011000 00101000 +01011001 00101101 +01011010 00110010 +01011011 00110111 +01011100 00111100 +01011101 01000001 +01011110 01000110 +01011111 01001011 +01100000 00000000 +01100001 00000110 +01100010 00001100 +01100011 00010010 +01100100 00011000 +01100101 00011110 +01100110 00100100 +01100111 00101010 +01101000 00110000 +01101001 00110110 +01101010 00111100 +01101011 01000010 +01101100 01001000 +01101101 01001110 +01101110 01010100 +01101111 01011010 +01110000 00000000 +01110001 00000111 +01110010 00001110 +01110011 00010101 +01110100 00011100 +01110101 00100011 +01110110 00101010 +01110111 00110001 +01111000 00111000 +01111001 00111111 +01111010 01000110 +01111011 01001101 +01111100 01010100 +01111101 01011011 +01111110 01100010 +01111111 01101001 +10000000 00000000 +10000001 00001000 +10000010 00010000 +10000011 00011000 +10000100 00100000 +10000101 00101000 +10000110 00110000 +10000111 00111000 +10001000 01000000 +10001001 01001000 +10001010 01010000 +10001011 01011000 +10001100 01100000 +10001101 01101000 +10001110 01110000 +10001111 01111000 +10010000 00000000 +10010001 00001001 +10010010 00010010 +10010011 00011011 +10010100 00100100 +10010101 00101101 +10010110 00110110 +10010111 00111111 +10011000 01001000 +10011001 01010001 +10011010 01011010 +10011011 01100011 +10011100 01101100 +10011101 01110101 +10011110 01111110 +10011111 10000111 +10100000 00000000 +10100001 00001010 +10100010 00010100 +10100011 00011110 +10100100 00101000 +10100101 00110010 +10100110 00111100 +10100111 01000110 +10101000 01010000 +10101001 01011010 +10101010 01100100 +10101011 01101110 +10101100 01111000 +10101101 10000010 +10101110 10001100 +10101111 10010110 +10110000 00000000 +10110001 00001011 +10110010 00010110 +10110011 00100001 +10110100 00101100 +10110101 00110111 +10110110 01000010 +10110111 01001101 +10111000 01011000 +10111001 01100011 +10111010 01101110 +10111011 01111001 +10111100 10000100 +10111101 10001111 +10111110 10011010 +10111111 10100101 +11000000 00000000 +11000001 00001100 +11000010 00011000 +11000011 00100100 +11000100 00110000 +11000101 00111100 +11000110 01001000 +11000111 01010100 +11001000 01100000 +11001001 01101100 +11001010 01111000 +11001011 10000100 +11001100 10010000 +11001101 10011100 +11001110 10101000 +11001111 10110100 +11010000 00000000 +11010001 00001101 +11010010 00011010 +11010011 00100111 +11010100 00110100 +11010101 01000001 +11010110 01001110 +11010111 01011011 +11011000 01101000 +11011001 01110101 +11011010 10000010 +11011011 10001111 +11011100 10011100 +11011101 10101001 +11011110 10110110 +11011111 11000011 +11100000 00000000 +11100001 00001110 +11100010 00011100 +11100011 00101010 +11100100 00111000 +11100101 01000110 +11100110 01010100 +11100111 01100010 +11101000 01110000 +11101001 01111110 +11101010 10001100 +11101011 10011010 +11101100 10101000 +11101101 10110110 +11101110 11000100 +11101111 11010010 +11110000 00000000 +11110001 00001111 +11110010 00011110 +11110011 00101101 +11110100 00111100 +11110101 01001011 +11110110 01011010 +11110111 01101001 +11111000 01111000 +11111001 10000111 +11111010 10010110 +11111011 10100101 +11111100 10110100 +11111101 11000011 +11111110 11010010 +11111111 11100001 +.e diff --git a/espresso/examples/math/radd b/espresso/examples/math/radd new file mode 100644 index 0000000..cf12234 --- /dev/null +++ b/espresso/examples/math/radd @@ -0,0 +1,122 @@ +.i 8 +.o 5 +1---0--- 10000 +0---1--- 10000 +-1--00-- 01000 +-0--01-- 01000 +01---0-- 01000 +00---1-- 01000 +10--10-- 01000 +11--11-- 01000 +--1-000- 00100 +--0-001- 00100 +-01-0-0- 00100 +-00-0-1- 00100 +0-1--00- 00100 +0-0--01- 00100 +001---0- 00100 +000---1- 00100 +-10-010- 00100 +-11-011- 00100 +010--10- 00100 +011--11- 00100 +101-100- 00100 +100-101- 00100 +1-0-110- 00100 +1-1-111- 00100 +110-1-0- 00100 +111-1-1- 00100 +---10000 00010 +---00001 00010 +--0100-0 00010 +--0000-1 00010 +-0-10-00 00010 +-0-00-01 00010 +-0010--0 00010 +-0000--1 00010 +0--1-000 00010 +0--0-001 00010 +0-01-0-0 00010 +0-00-0-1 00010 +00-1--00 00010 +00-0--01 00010 +0001---0 00010 +0000---1 00010 +--100010 00010 +--110011 00010 +-0100-10 00010 +-0110-11 00010 +0-10-010 00010 +0-11-011 00010 +0010--10 00010 +0011--11 00010 +-1010100 00010 +-1000101 00010 +0101-100 00010 +0100-101 00010 +-1-00110 00010 +-1-10111 00010 +01-0-110 00010 +01-1-111 00010 +-11001-0 00010 +-11101-1 00010 +0110-1-0 00010 +0111-1-1 00010 +10-11000 00010 +10-01001 00010 +100110-0 00010 +100010-1 00010 +10101010 00010 +10111011 00010 +1-011100 00010 +1-001101 00010 +11011-00 00010 +11001-01 00010 +1--01110 00010 +1--11111 00010 +1-1011-0 00010 +1-1111-1 00010 +11-01-10 00010 +11-11-11 00010 +11101--0 00010 +11111--1 00010 +---10001 00001 +--0100-1 00001 +-0-10-01 00001 +-0010--1 00001 +0--1-001 00001 +0-01-0-1 00001 +00-1--01 00001 +0001---1 00001 +--1-0011 00001 +-01-0-11 00001 +0-1--011 00001 +001---11 00001 +--11001- 00001 +-0110-1- 00001 +0-11-01- 00001 +0011--1- 00001 +-1010101 00001 +0101-101 00001 +-1--0111 00001 +01---111 00001 +-1-1011- 00001 +01-1-11- 00001 +-11-01-1 00001 +011--1-1 00001 +-11101-- 00001 +0111-1-- 00001 +10-11001 00001 +100110-1 00001 +101-1011 00001 +1011101- 00001 +1-011101 00001 +11011-01 00001 +1---1111 00001 +1--1111- 00001 +1-1-11-1 00001 +1-1111-- 00001 +11--1-11 00001 +11-11-1- 00001 +111-1--1 00001 +11111--- 00001 diff --git a/espresso/examples/math/rckl b/espresso/examples/math/rckl new file mode 100644 index 0000000..bca85e6 --- /dev/null +++ b/espresso/examples/math/rckl @@ -0,0 +1,98 @@ +.i 32 +.o 7 +00000000000000000000000000000000 1000000 +00000000000000001--------------- 0100000 +0000000000000000-1-------------- 0100000 +0000000000000000--1------------- 0100000 +0000000000000000---1------------ 0100000 +0000000000000000----1----------- 0100000 +0000000000000000-----1---------- 0100000 +0000000000000000------1--------- 0100000 +0000000000000000-------1-------- 0100000 +0000000000000000--------1------- 0100000 +0000000000000000---------1------ 0100000 +0000000000000000----------1----- 0100000 +0000000000000000-----------1---- 0100000 +0000000000000000------------1--- 0100000 +0000000000000000-------------1-- 0100000 +0000000000000000--------------1- 0100000 +0000000000000000---------------1 0100000 +000000001----------------------- 0010000 +00000000-1---------------------- 0010000 +00000000--1--------------------- 0010000 +00000000---1-------------------- 0010000 +00000000----1------------------- 0010000 +00000000-----1------------------ 0010000 +00000000------1----------------- 0010000 +00000000-------1---------------- 0010000 +00000000--------000000001------- 0010000 +00000000--------00000000-1------ 0010000 +00000000--------00000000--1----- 0010000 +00000000--------00000000---1---- 0010000 +00000000--------00000000----1--- 0010000 +00000000--------00000000-----1-- 0010000 +00000000--------00000000------1- 0010000 +00000000--------00000000-------1 0010000 +00001--------------------------- 0001000 +0000-1-------------------------- 0001000 +0000--1------------------------- 0001000 +0000---1------------------------ 0001000 +0000----00001------------------- 0001000 +0000----0000-1------------------ 0001000 +0000----0000--1----------------- 0001000 +0000----0000---1---------------- 0001000 +0000----0000----00001----------- 0001000 +0000----0000----0000-1---------- 0001000 +0000----0000----0000--1--------- 0001000 +0000----0000----0000---1-------- 0001000 +0000----0000----0000----00001--- 0001000 +0000----0000----0000----0000-1-- 0001000 +0000----0000----0000----0000--1- 0001000 +0000----0000----0000----0000---1 0001000 +001----------------------------- 0000100 +00-1---------------------------- 0000100 +00--001------------------------- 0000100 +00--00-1------------------------ 0000100 +00--00--001--------------------- 0000100 +00--00--00-1-------------------- 0000100 +00--00--00--001----------------- 0000100 +00--00--00--00-1---------------- 0000100 +00--00--00--00--001------------- 0000100 +00--00--00--00--00-1------------ 0000100 +00--00--00--00--00--001--------- 0000100 +00--00--00--00--00--00-1-------- 0000100 +00--00--00--00--00--00--001----- 0000100 +00--00--00--00--00--00--00-1---- 0000100 +00--00--00--00--00--00--00--001- 0000100 +00--00--00--00--00--00--00--00-1 0000100 +01------------------------------ 0000011 +0-01---------------------------- 0000010 +0-0-01-------------------------- 0000010 +0-0-0-01------------------------ 0000010 +0-0-0-0-01---------------------- 0000010 +0-0-0-0-0-01-------------------- 0000010 +0-0-0-0-0-0-01------------------ 0000010 +0-0-0-0-0-0-0-01---------------- 0000010 +0-0-0-0-0-0-0-0-01-------------- 0000010 +0-0-0-0-0-0-0-0-0-01------------ 0000010 +0-0-0-0-0-0-0-0-0-0-01---------- 0000010 +0-0-0-0-0-0-0-0-0-0-0-01-------- 0000010 +0-0-0-0-0-0-0-0-0-0-0-0-01------ 0000010 +0-0-0-0-0-0-0-0-0-0-0-0-0-01---- 0000010 +0-0-0-0-0-0-0-0-0-0-0-0-0-0-01-- 0000010 +0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-01 0000010 +0-1----------------------------- 0000001 +0--01--------------------------- 0000001 +0--0-001------------------------ 0000001 +0--0-00-1----------------------- 0000001 +0--0-00--001-------------------- 0000001 +0--0-00--00-01------------------ 0000001 +0--0-00--00-0-1----------------- 0000001 +0--0-00--00-0--01--------------- 0000001 +0--0-00--00-0--0-001------------ 0000001 +0--0-00--00-0--0-00-01---------- 0000001 +0--0-00--00-0--0-00-0-1--------- 0000001 +0--0-00--00-0--0-00-0--001------ 0000001 +0--0-00--00-0--0-00-0--00-1----- 0000001 +0--0-00--00-0--0-00-0--00--01--- 0000001 +0--0-00--00-0--0-00-0--00--0-00- 0000001 diff --git a/espresso/examples/math/rd53 b/espresso/examples/math/rd53 new file mode 100644 index 0000000..bf0af26 --- /dev/null +++ b/espresso/examples/math/rd53 @@ -0,0 +1,34 @@ +.i 5 +.o 3 +00000 000 +00001 001 +00010 001 +00011 010 +00100 001 +00101 010 +00110 010 +00111 011 +01000 001 +01001 010 +01010 010 +01011 011 +01100 010 +01101 011 +01110 011 +01111 100 +10000 001 +10001 010 +10010 010 +10011 011 +10100 010 +10101 011 +10110 011 +10111 100 +11000 010 +11001 011 +11010 011 +11011 100 +11100 011 +11101 100 +11110 100 +11111 101 diff --git a/espresso/examples/math/rd73 b/espresso/examples/math/rd73 new file mode 100644 index 0000000..98498e6 --- /dev/null +++ b/espresso/examples/math/rd73 @@ -0,0 +1,149 @@ +.i 7 +.o 3 +0000001 001 +0000010 001 +0000100 001 +0000111 001 +000011- 010 +00001-1 010 +0000-11 010 +0001000 001 +0001011 001 +000101- 010 +00010-1 010 +0001101 001 +000110- 010 +0001110 001 +00011-0 010 +0010000 001 +0010011 001 +001001- 010 +00100-1 010 +0010101 001 +001010- 010 +0010110 001 +00101-0 010 +0011001 001 +001100- 010 +0011010 001 +00110-0 010 +0011100 001 +0011111 001 +0011-00 010 +0100000 001 +0100011 001 +010001- 010 +01000-1 010 +0100101 001 +010010- 010 +0100110 001 +01001-0 010 +0101001 001 +010100- 010 +0101010 001 +01010-0 010 +0101100 001 +0101111 001 +0101-00 010 +0110001 001 +011000- 010 +0110010 001 +01100-0 010 +0110100 001 +0110111 001 +0110-00 010 +0111000 001 +0111011 001 +0111101 001 +0111110 001 +011-000 010 +1000000 001 +1000011 001 +100001- 010 +10000-1 010 +1000101 001 +100010- 010 +1000110 001 +10001-0 010 +1001001 001 +100100- 010 +1001010 001 +10010-0 010 +1001100 001 +1001111 001 +1001-00 010 +1010001 001 +101000- 010 +1010010 001 +10100-0 010 +1010100 001 +1010111 001 +1010-00 010 +1011000 001 +1011011 001 +1011101 001 +1011110 001 +101-000 010 +1100001 001 +110000- 010 +1100010 001 +11000-0 010 +1100100 001 +1100111 001 +1100-00 010 +1101000 001 +1101011 001 +1101101 001 +1101110 001 +110-000 010 +1110000 001 +1110011 001 +1110101 001 +1110110 001 +1111001 001 +1111010 001 +1111100 001 +1111111 001 +111111- 010 +11111-1 010 +1111-11 010 +1111--- 100 +111-111 010 +111-1-- 100 +111--1- 100 +111---1 100 +11-0000 010 +11-1111 010 +11-11-- 100 +11-1-1- 100 +11-1--1 100 +11--11- 100 +11--1-1 100 +11---11 100 +1-11111 010 +1-111-- 100 +1-11-1- 100 +1-11--1 100 +1-1-11- 100 +1-1-1-1 100 +1-1--11 100 +1--111- 100 +1--11-1 100 +1--1-11 100 +1---111 100 +-111111 010 +-1111-- 100 +-111-1- 100 +-111--1 100 +-11-11- 100 +-11-1-1 100 +-11--11 100 +-1-111- 100 +-1-11-1 100 +-1-1-11 100 +-1--111 100 +--1111- 100 +--111-1 100 +--11-11 100 +--1-111 100 +---1111 100 diff --git a/espresso/examples/math/root b/espresso/examples/math/root new file mode 100644 index 0000000..3edf0a3 --- /dev/null +++ b/espresso/examples/math/root @@ -0,0 +1,259 @@ +.i 8 +.o 5 +00000000 00000 +00000001 00001 +00000010 00001 +00000011 00010 +00000100 00010 +00000101 00010 +00000110 00010 +00000111 00011 +00001000 00011 +00001001 00011 +00001010 00011 +00001011 00011 +00001100 00011 +00001101 00100 +00001110 00100 +00001111 00100 +00010000 00100 +00010001 00100 +00010010 00100 +00010011 00100 +00010100 00100 +00010101 00101 +00010110 00101 +00010111 00101 +00011000 00101 +00011001 00101 +00011010 00101 +00011011 00101 +00011100 00101 +00011101 00101 +00011110 00101 +00011111 00110 +00100000 00110 +00100001 00110 +00100010 00110 +00100011 00110 +00100100 00110 +00100101 00110 +00100110 00110 +00100111 00110 +00101000 00110 +00101001 00110 +00101010 00110 +00101011 00111 +00101100 00111 +00101101 00111 +00101110 00111 +00101111 00111 +00110000 00111 +00110001 00111 +00110010 00111 +00110011 00111 +00110100 00111 +00110101 00111 +00110110 00111 +00110111 00111 +00111000 00111 +00111001 01000 +00111010 01000 +00111011 01000 +00111100 01000 +00111101 01000 +00111110 01000 +00111111 01000 +01000000 01000 +01000001 01000 +01000010 01000 +01000011 01000 +01000100 01000 +01000101 01000 +01000110 01000 +01000111 01000 +01001000 01000 +01001001 01001 +01001010 01001 +01001011 01001 +01001100 01001 +01001101 01001 +01001110 01001 +01001111 01001 +01010000 01001 +01010001 01001 +01010010 01001 +01010011 01001 +01010100 01001 +01010101 01001 +01010110 01001 +01010111 01001 +01011000 01001 +01011001 01001 +01011010 01001 +01011011 01010 +01011100 01010 +01011101 01010 +01011110 01010 +01011111 01010 +01100000 01010 +01100001 01010 +01100010 01010 +01100011 01010 +01100100 01010 +01100101 01010 +01100110 01010 +01100111 01010 +01101000 01010 +01101001 01010 +01101010 01010 +01101011 01010 +01101100 01010 +01101101 01010 +01101110 01010 +01101111 01011 +01110000 01011 +01110001 01011 +01110010 01011 +01110011 01011 +01110100 01011 +01110101 01011 +01110110 01011 +01110111 01011 +01111000 01011 +01111001 01011 +01111010 01011 +01111011 01011 +01111100 01011 +01111101 01011 +01111110 01011 +01111111 01011 +10000000 01011 +10000001 01011 +10000010 01011 +10000011 01011 +10000100 01011 +10000101 01100 +10000110 01100 +10000111 01100 +10001000 01100 +10001001 01100 +10001010 01100 +10001011 01100 +10001100 01100 +10001101 01100 +10001110 01100 +10001111 01100 +10010000 01100 +10010001 01100 +10010010 01100 +10010011 01100 +10010100 01100 +10010101 01100 +10010110 01100 +10010111 01100 +10011000 01100 +10011001 01100 +10011010 01100 +10011011 01100 +10011100 01100 +10011101 01101 +10011110 01101 +10011111 01101 +10100000 01101 +10100001 01101 +10100010 01101 +10100011 01101 +10100100 01101 +10100101 01101 +10100110 01101 +10100111 01101 +10101000 01101 +10101001 01101 +10101010 01101 +10101011 01101 +10101100 01101 +10101101 01101 +10101110 01101 +10101111 01101 +10110000 01101 +10110001 01101 +10110010 01101 +10110011 01101 +10110100 01101 +10110101 01101 +10110110 01101 +10110111 01110 +10111000 01110 +10111001 01110 +10111010 01110 +10111011 01110 +10111100 01110 +10111101 01110 +10111110 01110 +10111111 01110 +11000000 01110 +11000001 01110 +11000010 01110 +11000011 01110 +11000100 01110 +11000101 01110 +11000110 01110 +11000111 01110 +11001000 01110 +11001001 01110 +11001010 01110 +11001011 01110 +11001100 01110 +11001101 01110 +11001110 01110 +11001111 01110 +11010000 01110 +11010001 01110 +11010010 01110 +11010011 01111 +11010100 01111 +11010101 01111 +11010110 01111 +11010111 01111 +11011000 01111 +11011001 01111 +11011010 01111 +11011011 01111 +11011100 01111 +11011101 01111 +11011110 01111 +11011111 01111 +11100000 01111 +11100001 01111 +11100010 01111 +11100011 01111 +11100100 01111 +11100101 01111 +11100110 01111 +11100111 01111 +11101000 01111 +11101001 01111 +11101010 01111 +11101011 01111 +11101100 01111 +11101101 01111 +11101110 01111 +11101111 01111 +11110000 01111 +11110001 10000 +11110010 10000 +11110011 10000 +11110100 10000 +11110101 10000 +11110110 10000 +11110111 10000 +11111000 10000 +11111001 10000 +11111010 10000 +11111011 10000 +11111100 10000 +11111101 10000 +11111110 10000 +11111111 10000 + diff --git a/espresso/examples/math/sqr6 b/espresso/examples/math/sqr6 new file mode 100644 index 0000000..82a0020 --- /dev/null +++ b/espresso/examples/math/sqr6 @@ -0,0 +1,66 @@ +.i 6 +.o 12 +000000 000000000000 +000001 000000000001 +000010 000000000100 +000011 000000001001 +000100 000000010000 +000101 000000011001 +000110 000000100100 +000111 000000110001 +001000 000001000000 +001001 000001010001 +001010 000001100100 +001011 000001111001 +001100 000010010000 +001101 000010101001 +001110 000011000100 +001111 000011100001 +010000 000100000000 +010001 000100100001 +010010 000101000100 +010011 000101101001 +010100 000110010000 +010101 000110111001 +010110 000111100100 +010111 001000010001 +011000 001001000000 +011001 001001110001 +011010 001010100100 +011011 001011011001 +011100 001100010000 +011101 001101001001 +011110 001110000100 +011111 001111000001 +100000 010000000000 +100001 010001000001 +100010 010010000100 +100011 010011001001 +100100 010100010000 +100101 010101011001 +100110 010110100100 +100111 010111110001 +101000 011001000000 +101001 011010010001 +101010 011011100100 +101011 011100111001 +101100 011110010000 +101101 011111101001 +101110 100001000100 +101111 100010100001 +110000 100100000000 +110001 100101100001 +110010 100111000100 +110011 101000101001 +110100 101010010000 +110101 101011111001 +110110 101101100100 +110111 101111010001 +111000 110001000000 +111001 110010110001 +111010 110100100100 +111011 110110011001 +111100 111000010000 +111101 111010001001 +111110 111100000100 +111111 111110000001 diff --git a/espresso/examples/math/sym10 b/espresso/examples/math/sym10 new file mode 100644 index 0000000..af3a524 --- /dev/null +++ b/espresso/examples/math/sym10 @@ -0,0 +1,839 @@ +.i 10 +.o 1 +1111000000 1 +1110100000 1 +1101100000 1 +1011100000 1 +0111100000 1 +1111100000 1 +1110010000 1 +1101010000 1 +1011010000 1 +0111010000 1 +1111010000 1 +1100110000 1 +1010110000 1 +0110110000 1 +1110110000 1 +1001110000 1 +0101110000 1 +1101110000 1 +0011110000 1 +1011110000 1 +0111110000 1 +1111110000 1 +1110001000 1 +1101001000 1 +1011001000 1 +0111001000 1 +1111001000 1 +1100101000 1 +1010101000 1 +0110101000 1 +1110101000 1 +1001101000 1 +0101101000 1 +1101101000 1 +0011101000 1 +1011101000 1 +0111101000 1 +1111101000 1 +1100011000 1 +1010011000 1 +0110011000 1 +1110011000 1 +1001011000 1 +0101011000 1 +1101011000 1 +0011011000 1 +1011011000 1 +0111011000 1 +1111011000 1 +1000111000 1 +0100111000 1 +1100111000 1 +0010111000 1 +1010111000 1 +0110111000 1 +1110111000 1 +0001111000 1 +1001111000 1 +0101111000 1 +1101111000 1 +0011111000 1 +1011111000 1 +0111111000 1 +1111111000 1 +1110000100 1 +1101000100 1 +1011000100 1 +0111000100 1 +1111000100 1 +1100100100 1 +1010100100 1 +0110100100 1 +1110100100 1 +1001100100 1 +0101100100 1 +1101100100 1 +0011100100 1 +1011100100 1 +0111100100 1 +1111100100 1 +1100010100 1 +1010010100 1 +0110010100 1 +1110010100 1 +1001010100 1 +0101010100 1 +1101010100 1 +0011010100 1 +1011010100 1 +0111010100 1 +1111010100 1 +1000110100 1 +0100110100 1 +1100110100 1 +0010110100 1 +1010110100 1 +0110110100 1 +1110110100 1 +0001110100 1 +1001110100 1 +0101110100 1 +1101110100 1 +0011110100 1 +1011110100 1 +0111110100 1 +1111110100 1 +1100001100 1 +1010001100 1 +0110001100 1 +1110001100 1 +1001001100 1 +0101001100 1 +1101001100 1 +0011001100 1 +1011001100 1 +0111001100 1 +1111001100 1 +1000101100 1 +0100101100 1 +1100101100 1 +0010101100 1 +1010101100 1 +0110101100 1 +1110101100 1 +0001101100 1 +1001101100 1 +0101101100 1 +1101101100 1 +0011101100 1 +1011101100 1 +0111101100 1 +1111101100 1 +1000011100 1 +0100011100 1 +1100011100 1 +0010011100 1 +1010011100 1 +0110011100 1 +1110011100 1 +0001011100 1 +1001011100 1 +0101011100 1 +1101011100 1 +0011011100 1 +1011011100 1 +0111011100 1 +1111011100 1 +0000111100 1 +1000111100 1 +0100111100 1 +1100111100 1 +0010111100 1 +1010111100 1 +0110111100 1 +1110111100 1 +0001111100 1 +1001111100 1 +0101111100 1 +1101111100 1 +0011111100 1 +1011111100 1 +0111111100 1 +1111111100 1 +1110000010 1 +1101000010 1 +1011000010 1 +0111000010 1 +1111000010 1 +1100100010 1 +1010100010 1 +0110100010 1 +1110100010 1 +1001100010 1 +0101100010 1 +1101100010 1 +0011100010 1 +1011100010 1 +0111100010 1 +1111100010 1 +1100010010 1 +1010010010 1 +0110010010 1 +1110010010 1 +1001010010 1 +0101010010 1 +1101010010 1 +0011010010 1 +1011010010 1 +0111010010 1 +1111010010 1 +1000110010 1 +0100110010 1 +1100110010 1 +0010110010 1 +1010110010 1 +0110110010 1 +1110110010 1 +0001110010 1 +1001110010 1 +0101110010 1 +1101110010 1 +0011110010 1 +1011110010 1 +0111110010 1 +1111110010 1 +1100001010 1 +1010001010 1 +0110001010 1 +1110001010 1 +1001001010 1 +0101001010 1 +1101001010 1 +0011001010 1 +1011001010 1 +0111001010 1 +1111001010 1 +1000101010 1 +0100101010 1 +1100101010 1 +0010101010 1 +1010101010 1 +0110101010 1 +1110101010 1 +0001101010 1 +1001101010 1 +0101101010 1 +1101101010 1 +0011101010 1 +1011101010 1 +0111101010 1 +1111101010 1 +1000011010 1 +0100011010 1 +1100011010 1 +0010011010 1 +1010011010 1 +0110011010 1 +1110011010 1 +0001011010 1 +1001011010 1 +0101011010 1 +1101011010 1 +0011011010 1 +1011011010 1 +0111011010 1 +1111011010 1 +0000111010 1 +1000111010 1 +0100111010 1 +1100111010 1 +0010111010 1 +1010111010 1 +0110111010 1 +1110111010 1 +0001111010 1 +1001111010 1 +0101111010 1 +1101111010 1 +0011111010 1 +1011111010 1 +0111111010 1 +1111111010 1 +1100000110 1 +1010000110 1 +0110000110 1 +1110000110 1 +1001000110 1 +0101000110 1 +1101000110 1 +0011000110 1 +1011000110 1 +0111000110 1 +1111000110 1 +1000100110 1 +0100100110 1 +1100100110 1 +0010100110 1 +1010100110 1 +0110100110 1 +1110100110 1 +0001100110 1 +1001100110 1 +0101100110 1 +1101100110 1 +0011100110 1 +1011100110 1 +0111100110 1 +1111100110 1 +1000010110 1 +0100010110 1 +1100010110 1 +0010010110 1 +1010010110 1 +0110010110 1 +1110010110 1 +0001010110 1 +1001010110 1 +0101010110 1 +1101010110 1 +0011010110 1 +1011010110 1 +0111010110 1 +1111010110 1 +0000110110 1 +1000110110 1 +0100110110 1 +1100110110 1 +0010110110 1 +1010110110 1 +0110110110 1 +1110110110 1 +0001110110 1 +1001110110 1 +0101110110 1 +1101110110 1 +0011110110 1 +1011110110 1 +0111110110 1 +1111110110 1 +1000001110 1 +0100001110 1 +1100001110 1 +0010001110 1 +1010001110 1 +0110001110 1 +1110001110 1 +0001001110 1 +1001001110 1 +0101001110 1 +1101001110 1 +0011001110 1 +1011001110 1 +0111001110 1 +1111001110 1 +0000101110 1 +1000101110 1 +0100101110 1 +1100101110 1 +0010101110 1 +1010101110 1 +0110101110 1 +1110101110 1 +0001101110 1 +1001101110 1 +0101101110 1 +1101101110 1 +0011101110 1 +1011101110 1 +0111101110 1 +1111101110 1 +0000011110 1 +1000011110 1 +0100011110 1 +1100011110 1 +0010011110 1 +1010011110 1 +0110011110 1 +1110011110 1 +0001011110 1 +1001011110 1 +0101011110 1 +1101011110 1 +0011011110 1 +1011011110 1 +0111011110 1 +1111011110 1 +0000111110 1 +1000111110 1 +0100111110 1 +1100111110 1 +0010111110 1 +1010111110 1 +0110111110 1 +1110111110 1 +0001111110 1 +1001111110 1 +0101111110 1 +1101111110 1 +0011111110 1 +1011111110 1 +0111111110 1 +1110000001 1 +1101000001 1 +1011000001 1 +0111000001 1 +1111000001 1 +1100100001 1 +1010100001 1 +0110100001 1 +1110100001 1 +1001100001 1 +0101100001 1 +1101100001 1 +0011100001 1 +1011100001 1 +0111100001 1 +1111100001 1 +1100010001 1 +1010010001 1 +0110010001 1 +1110010001 1 +1001010001 1 +0101010001 1 +1101010001 1 +0011010001 1 +1011010001 1 +0111010001 1 +1111010001 1 +1000110001 1 +0100110001 1 +1100110001 1 +0010110001 1 +1010110001 1 +0110110001 1 +1110110001 1 +0001110001 1 +1001110001 1 +0101110001 1 +1101110001 1 +0011110001 1 +1011110001 1 +0111110001 1 +1111110001 1 +1100001001 1 +1010001001 1 +0110001001 1 +1110001001 1 +1001001001 1 +0101001001 1 +1101001001 1 +0011001001 1 +1011001001 1 +0111001001 1 +1111001001 1 +1000101001 1 +0100101001 1 +1100101001 1 +0010101001 1 +1010101001 1 +0110101001 1 +1110101001 1 +0001101001 1 +1001101001 1 +0101101001 1 +1101101001 1 +0011101001 1 +1011101001 1 +0111101001 1 +1111101001 1 +1000011001 1 +0100011001 1 +1100011001 1 +0010011001 1 +1010011001 1 +0110011001 1 +1110011001 1 +0001011001 1 +1001011001 1 +0101011001 1 +1101011001 1 +0011011001 1 +1011011001 1 +0111011001 1 +1111011001 1 +0000111001 1 +1000111001 1 +0100111001 1 +1100111001 1 +0010111001 1 +1010111001 1 +0110111001 1 +1110111001 1 +0001111001 1 +1001111001 1 +0101111001 1 +1101111001 1 +0011111001 1 +1011111001 1 +0111111001 1 +1111111001 1 +1100000101 1 +1010000101 1 +0110000101 1 +1110000101 1 +1001000101 1 +0101000101 1 +1101000101 1 +0011000101 1 +1011000101 1 +0111000101 1 +1111000101 1 +1000100101 1 +0100100101 1 +1100100101 1 +0010100101 1 +1010100101 1 +0110100101 1 +1110100101 1 +0001100101 1 +1001100101 1 +0101100101 1 +1101100101 1 +0011100101 1 +1011100101 1 +0111100101 1 +1111100101 1 +1000010101 1 +0100010101 1 +1100010101 1 +0010010101 1 +1010010101 1 +0110010101 1 +1110010101 1 +0001010101 1 +1001010101 1 +0101010101 1 +1101010101 1 +0011010101 1 +1011010101 1 +0111010101 1 +1111010101 1 +0000110101 1 +1000110101 1 +0100110101 1 +1100110101 1 +0010110101 1 +1010110101 1 +0110110101 1 +1110110101 1 +0001110101 1 +1001110101 1 +0101110101 1 +1101110101 1 +0011110101 1 +1011110101 1 +0111110101 1 +1111110101 1 +1000001101 1 +0100001101 1 +1100001101 1 +0010001101 1 +1010001101 1 +0110001101 1 +1110001101 1 +0001001101 1 +1001001101 1 +0101001101 1 +1101001101 1 +0011001101 1 +1011001101 1 +0111001101 1 +1111001101 1 +0000101101 1 +1000101101 1 +0100101101 1 +1100101101 1 +0010101101 1 +1010101101 1 +0110101101 1 +1110101101 1 +0001101101 1 +1001101101 1 +0101101101 1 +1101101101 1 +0011101101 1 +1011101101 1 +0111101101 1 +1111101101 1 +0000011101 1 +1000011101 1 +0100011101 1 +1100011101 1 +0010011101 1 +1010011101 1 +0110011101 1 +1110011101 1 +0001011101 1 +1001011101 1 +0101011101 1 +1101011101 1 +0011011101 1 +1011011101 1 +0111011101 1 +1111011101 1 +0000111101 1 +1000111101 1 +0100111101 1 +1100111101 1 +0010111101 1 +1010111101 1 +0110111101 1 +1110111101 1 +0001111101 1 +1001111101 1 +0101111101 1 +1101111101 1 +0011111101 1 +1011111101 1 +0111111101 1 +1100000011 1 +1010000011 1 +0110000011 1 +1110000011 1 +1001000011 1 +0101000011 1 +1101000011 1 +0011000011 1 +1011000011 1 +0111000011 1 +1111000011 1 +1000100011 1 +0100100011 1 +1100100011 1 +0010100011 1 +1010100011 1 +0110100011 1 +1110100011 1 +0001100011 1 +1001100011 1 +0101100011 1 +1101100011 1 +0011100011 1 +1011100011 1 +0111100011 1 +1111100011 1 +1000010011 1 +0100010011 1 +1100010011 1 +0010010011 1 +1010010011 1 +0110010011 1 +1110010011 1 +0001010011 1 +1001010011 1 +0101010011 1 +1101010011 1 +0011010011 1 +1011010011 1 +0111010011 1 +1111010011 1 +0000110011 1 +1000110011 1 +0100110011 1 +1100110011 1 +0010110011 1 +1010110011 1 +0110110011 1 +1110110011 1 +0001110011 1 +1001110011 1 +0101110011 1 +1101110011 1 +0011110011 1 +1011110011 1 +0111110011 1 +1111110011 1 +1000001011 1 +0100001011 1 +1100001011 1 +0010001011 1 +1010001011 1 +0110001011 1 +1110001011 1 +0001001011 1 +1001001011 1 +0101001011 1 +1101001011 1 +0011001011 1 +1011001011 1 +0111001011 1 +1111001011 1 +0000101011 1 +1000101011 1 +0100101011 1 +1100101011 1 +0010101011 1 +1010101011 1 +0110101011 1 +1110101011 1 +0001101011 1 +1001101011 1 +0101101011 1 +1101101011 1 +0011101011 1 +1011101011 1 +0111101011 1 +1111101011 1 +0000011011 1 +1000011011 1 +0100011011 1 +1100011011 1 +0010011011 1 +1010011011 1 +0110011011 1 +1110011011 1 +0001011011 1 +1001011011 1 +0101011011 1 +1101011011 1 +0011011011 1 +1011011011 1 +0111011011 1 +1111011011 1 +0000111011 1 +1000111011 1 +0100111011 1 +1100111011 1 +0010111011 1 +1010111011 1 +0110111011 1 +1110111011 1 +0001111011 1 +1001111011 1 +0101111011 1 +1101111011 1 +0011111011 1 +1011111011 1 +0111111011 1 +1000000111 1 +0100000111 1 +1100000111 1 +0010000111 1 +1010000111 1 +0110000111 1 +1110000111 1 +0001000111 1 +1001000111 1 +0101000111 1 +1101000111 1 +0011000111 1 +1011000111 1 +0111000111 1 +1111000111 1 +0000100111 1 +1000100111 1 +0100100111 1 +1100100111 1 +0010100111 1 +1010100111 1 +0110100111 1 +1110100111 1 +0001100111 1 +1001100111 1 +0101100111 1 +1101100111 1 +0011100111 1 +1011100111 1 +0111100111 1 +1111100111 1 +0000010111 1 +1000010111 1 +0100010111 1 +1100010111 1 +0010010111 1 +1010010111 1 +0110010111 1 +1110010111 1 +0001010111 1 +1001010111 1 +0101010111 1 +1101010111 1 +0011010111 1 +1011010111 1 +0111010111 1 +1111010111 1 +0000110111 1 +1000110111 1 +0100110111 1 +1100110111 1 +0010110111 1 +1010110111 1 +0110110111 1 +1110110111 1 +0001110111 1 +1001110111 1 +0101110111 1 +1101110111 1 +0011110111 1 +1011110111 1 +0111110111 1 +0000001111 1 +1000001111 1 +0100001111 1 +1100001111 1 +0010001111 1 +1010001111 1 +0110001111 1 +1110001111 1 +0001001111 1 +1001001111 1 +0101001111 1 +1101001111 1 +0011001111 1 +1011001111 1 +0111001111 1 +1111001111 1 +0000101111 1 +1000101111 1 +0100101111 1 +1100101111 1 +0010101111 1 +1010101111 1 +0110101111 1 +1110101111 1 +0001101111 1 +1001101111 1 +0101101111 1 +1101101111 1 +0011101111 1 +1011101111 1 +0111101111 1 +0000011111 1 +1000011111 1 +0100011111 1 +1100011111 1 +0010011111 1 +1010011111 1 +0110011111 1 +1110011111 1 +0001011111 1 +1001011111 1 +0101011111 1 +1101011111 1 +0011011111 1 +1011011111 1 +0111011111 1 +0000111111 1 +1000111111 1 +0100111111 1 +1100111111 1 +0010111111 1 +1010111111 1 +0110111111 1 +0001111111 1 +1001111111 1 +0101111111 1 +0011111111 1 diff --git a/espresso/examples/math/tial b/espresso/examples/math/tial new file mode 100644 index 0000000..a89eca5 --- /dev/null +++ b/espresso/examples/math/tial @@ -0,0 +1,642 @@ +.i 14 +.o 8 +0000000010-1-- 00010000 +00000000-1-0-- 00010000 +000001110010-- 00010000 +00000--1-010-- 00000100 +00000------0-- 00001000 +000010000001-- 00010000 +00001111101--- 00010000 +00001111-10--- 00010000 +00001--0-001-- 00000100 +00001-----0--- 00001000 +0000---010-1-- 00000100 +0000---1101--- 00000100 +0000----1011-- 00010000 +0000----1----- 00001000 +0000-----100-- 00010000 +0001000110-1-0 00010000 +00010001-1-0-1 00010000 +0001011000100- 00010000 +00010--0-0-00- 00000100 +000110010001-0 00010000 +00011110101-0- 00010000 +00011110-10-1- 00010000 +00011--1-00--0 00000100 +0001---010--0- 00000100 +0001---110---0 00000100 +000-0-1--010-- 00100000 +000-0--0---00- 00001000 +000-1-0--001-- 00100000 +000-1--1--0--0 00001000 +000---0-10-1-- 00100000 +000---1-101--- 00100000 +000----010110- 00010000 +000----01---0- 00001000 +000----11----0 00001000 +0010001010-1-0 00010000 +00100010-1-0-1 00010000 +0010010100100- 00010000 +001010100001-0 00010000 +00101101101-0- 00010000 +00101101-10-1- 00010000 +0011001110-1-0 00010000 +00110011-1-0-1 00010000 +0011010000100- 00010000 +001110110001-0 00010000 +00111100101-0- 00010000 +00111100-10-1- 00010000 +001-0-0--0-00- 00100000 +001-1-1--00--0 00100000 +001---0-10--0- 00100000 +001---1-10---0 00100000 +00-00-01-0100- 00000100 +00-00-0----00- 00001000 +00-01-10-001-0 00000100 +00-01-1---0--0 00001000 +00-0--01101-0- 00000100 +00-0--0-1---0- 00001000 +00-0--1010-1-0 00000100 +00-0--1-1----0 00001000 +00-10-00-0-00- 00000100 +00-11-11-00--0 00000100 +00-1--0010--0- 00000100 +00-1--1110---0 00000100 +00--01---010-- 01000000 +00--0-00---00- 00001000 +00--10---001-- 01000000 +00--1-11--0--0 00001000 +00---0--10-1-- 01000000 +00---1--101--- 01000000 +00----0010110- 00010000 +00----0010-10- 00000100 +00----001---0- 00001000 +00----00-1001- 00010000 +00----111011-0 00010000 +00----11101--0 00000100 +00----111----0 00001000 +00----11-100-1 00010000 +0100001100100- 00010000 +0100010010-1-0 00010000 +01000100-1-0-1 00010000 +01001011101-0- 00010000 +01001011-10-1- 00010000 +010011000001-0 00010000 +0101001000100- 00010000 +0101010110-1-0 00010000 +01010101-1-0-1 00010000 +01011010101-0- 00010000 +01011010-10-1- 00010000 +010111010001-0 00010000 +0110000100100- 00010000 +0110011010-1-0 00010000 +01100110-1-0-1 00010000 +01101001101-0- 00010000 +01101001-10-1- 00010000 +011011100001-0 00010000 +0111000000-00- 00010000 +0111011100-0-0 00010000 +0111011110-1-0 00010000 +01110111-1-0-1 00010000 +01110---00-000 00010000 +01111000000-0- 00010000 +01111000101-0- 00010000 +01111000-10-1- 00010000 +01111111000--0 00010000 +01111---000-00 00010000 +011-0--1001000 00010000 +011-1--0000100 00010000 +01-10-1-001000 00010000 +01-11-0-000100 00010000 +01--00---0-00- 01000000 +01--01---0-0-0 01000000 +01--10---00-0- 01000000 +01--11---00--0 01000000 +01---0--10--0- 01000000 +01---1--10---0 01000000 +0-0000-1-0100- 00000100 +0-0000-----00- 00001000 +0-0011-0-001-0 00000100 +0-0011----0--0 00001000 +0-00-0-1101-0- 00000100 +0-00-0--10110- 00010000 +0-00-0--1---0- 00001000 +0-00-1-010-1-0 00000100 +0-00-1--1----0 00001000 +0-0100-0-0-00- 00000100 +0-0111-1-00--0 00000100 +0-01-0-010--0- 00000100 +0-01-1-110---0 00000100 +0-0-001--0100- 00100000 +0-0-00-0---00- 00001000 +0-0-110--001-0 00100000 +0-0-11-1--0--0 00001000 +0-0--01-101-0- 00100000 +0-0--0-010-10- 00000100 +0-0--0-01---0- 00001000 +0-0--0-0-1001- 00010000 +0-0--10-10-1-0 00100000 +0-0--1-11011-0 00010000 +0-0--1-1101--0 00000100 +0-0--1-11----0 00001000 +0-0--1-1-100-1 00010000 +0-1101--001000 00010000 +0-1110--000100 00010000 +0-1-000--0-00- 00100000 +0-1-011--0-0-0 00100000 +0-1-0----0-000 00100000 +0-1-100--00-0- 00100000 +0-1-111--00--0 00100000 +0-1-1----00-00 00100000 +0-1--00-10--0- 00100000 +0-1--11-10---0 00100000 +0--00001-0100- 00000100 +0--0000----00- 00001000 +0--01110-001-0 00000100 +0--0111---0--0 00001000 +0--0-001101-0- 00000100 +0--0-00-10110- 00010000 +0--0-00-1---0- 00001000 +0--0-00--1001- 00010000 +0--0-11010-1-0 00000100 +0--0-11-1011-0 00010000 +0--0-11-1----0 00001000 +0--0-11--100-1 00010000 +0--10000-0-00- 00000100 +0--10111-0-0-0 00000100 +0--10----0-000 00000100 +0--11000-00-0- 00000100 +0--11111-00--0 00000100 +0--11----00-00 00000100 +0--1-00010--0- 00000100 +0--1-11110---0 00000100 +0---0000---00- 00001000 +0---01110010-0 00010000 +0---0111-010-0 00000100 +0---0111---0-0 00001000 +0---011--010-0 00100000 +0---0--1-01000 00000100 +0---0---0--0-- 10000000 +0---0---10-1-- 10000000 +0---0----1-0-- 10000000 +0---0------000 00001000 +0---100000010- 00010000 +0---1000-0010- 00000100 +0---1000--0-0- 00001000 +0---100--0010- 00100000 +0---1111--0--0 00001000 +0---1--0-00100 00000100 +0---1---0-0--- 10000000 +0---1---101--- 10000000 +0---1----10--- 10000000 +0---1-----0-00 00001000 +0----00010110- 00010000 +0----00010-10- 00000100 +0----0001---0- 00001000 +0----00-10-10- 00100000 +0----111101--0 00000100 +0----1111----0 00001000 +0----11-101--0 00100000 +1000001100101- 00010000 +1000010000011- 00010000 +10000111101-0- 00010000 +10000111-10-1- 00010000 +1000100010-1-0 00010000 +10001000-1-0-1 00010000 +100010110010-1 00010000 +100011000001-1 00010000 +10010101000110 00010000 +10010110101-0- 00010000 +10010110-10-1- 00010000 +1001100110-1-0 00010000 +10011001-1-0-1 00010000 +10011010001001 00010000 +10100101101-0- 00010000 +10100101-10-1- 00010000 +10100110000110 00010000 +10101001001001 00010000 +1010101010-1-0 00010000 +10101010-1-0-1 00010000 +1011001100-010 00010000 +10110100101-0- 00010000 +10110100-10-1- 00010000 +10110111000-10 00010000 +1011100000-001 00010000 +1011101110-1-0 00010000 +10111011-1-0-1 00010000 +10111100000-01 00010000 +10--0011001010 00010000 +10--01----0-1- 01000000 +10--10-----0-1 01000000 +10--1100000101 00010000 +10---0--0--0-- 01000000 +10---1--0-0--- 01000000 +1100001000011- 00010000 +11000011101-0- 00010000 +11000011-10-1- 00010000 +1100110010-1-0 00010000 +11001100-1-0-1 00010000 +110011010010-1 00010000 +1100--01001011 00010000 +1100--10000111 00010000 +1101000100-010 00010000 +11010010101-0- 00010000 +11010010-10-1- 00010000 +11010011000-10 00010000 +1101110000-001 00010000 +1101110110-1-0 00010000 +11011101-1-0-1 00010000 +11011110000-01 00010000 +110-0001001010 00010000 +110-0-1---0-1- 00100000 +110-1110000101 00010000 +110-1-0----0-1 00100000 +110---0-0--0-- 00100000 +110---1-0-0--- 00100000 +111000010-0-1- 00010000 +11100001101-0- 00010000 +11100001-10-1- 00010000 +11100--1--0-1- 00000100 +111011100--0-1 00010000 +1110111010-1-0 00010000 +11101110-1-0-1 00010000 +11101--0---0-1 00000100 +1110---00--0-- 00000100 +1110---10-0--- 00000100 +111100000---1- 00010000 +1111000010--0- 00010000 +11110000-1--1- 00010000 +11110--0----1- 00000100 +111111110----1 00010000 +1111111110---0 00010000 +11111111-1---1 00010000 +11111--1-----1 00000100 +1111---00---1- 00000100 +1111---10----1 00000100 +1111----0---11 00010000 +1111----10--00 00010000 +1111-----1--11 00010000 +1111---------- 00000010 +111-00000--01- 00010000 +111-0-0-----1- 00100000 +111-0--0---01- 00000100 +111-11110-0--1 00010000 +111-1-1------1 00100000 +111-1--1--0--1 00000100 +111---0-0---1- 00100000 +111---1-0----1 00100000 +111----00--011 00010000 +111----010-100 00010000 +111----0---1-- 00000010 +111----10-0-11 00010000 +111----1101-00 00010000 +111----1--1--- 00000010 +11-00-01--011- 00000100 +11-01-10--10-1 00000100 +11-0--010-01-- 00000100 +11-0--100-10-- 00000100 +11-10-00---11- 00000100 +11-11-11--1--1 00000100 +11-1--000--11- 00000100 +11-1--0-10-100 00010000 +11-1--0----1-- 00000010 +11-1--110-1--1 00000100 +11-1--1-101-00 00010000 +11-1--1---1--- 00000010 +11--00------1- 01000000 +11--0-0----01- 00100000 +11--11-------1 01000000 +11--1-1---0--1 00100000 +11---0--0---1- 01000000 +11---1--0----1 01000000 +11----00-1-011 00010000 +11----00---1-- 00000010 +11----11-10-11 00010000 +11----11--1--- 00000010 +11----------11 01000000 +1-0-001---011- 00100000 +1-0-110---10-1 00100000 +1-0--01-0-01-- 00100000 +1-0--10-0-10-- 00100000 +1-1000-1--011- 00000100 +1-1011-0--10-1 00000100 +1-10-0-10-01-- 00000100 +1-10-1-00-10-- 00000100 +1-1100-0---11- 00000100 +1-1111-1--1--1 00000100 +1-11-0-00--11- 00000100 +1-11-0--10-100 00010000 +1-11-0-----1-- 00000010 +1-11-1-10-1--1 00000100 +1-11-1--101-00 00010000 +1-11-1----1--- 00000010 +1-1-000----11- 00100000 +1-1-0-0---111- 00100000 +1-1-111---1--1 00100000 +1-1-1-1---11-1 00100000 +1-1--00-0--11- 00100000 +1-1--0-0-1-011 00010000 +1-1--0-0---1-- 00000010 +1-1--0-----111 00100000 +1-1--11-0-1--1 00100000 +1-1--1-1-10-11 00010000 +1-1--1-1--1--- 00000010 +1-1--1----1-11 00100000 +1--00001--011- 00000100 +1--01110--10-1 00000100 +1--0-0010-01-- 00000100 +1--0-1100-10-- 00000100 +1--10000---11- 00000100 +1--10--0--111- 00000100 +1--11111--1--1 00000100 +1--11--1--11-1 00000100 +1--1-0000--11- 00000100 +1--1-00--1-011 00010000 +1--1-00----111 00000100 +1--1-00----1-- 00000010 +1--1-1110-1--1 00000100 +1--1-11--10-11 00010000 +1--1-11---1-11 00000100 +1--1-11---1--- 00000010 +1--1------1111 00000100 +1---00-----01- 01000000 +1---010---101- 00100000 +1---0110--101- 00000100 +1---0---0---1- 10000000 +1---0---10--0- 10000000 +1---0----1--1- 10000000 +1---0-------1- 00000001 +1---1001--01-1 00000100 +1---101---01-1 00100000 +1---11----0--1 01000000 +1---1---0----1 10000000 +1---1---10---0 10000000 +1---1----1---1 10000000 +1---1--------1 00000001 +1----00010-100 00010000 +1----000---1-- 00000010 +1----111101-00 00010000 +1----111--1--- 00000010 +-0000--1101-0- 00000100 +-0000---10110- 00010000 +-0000---1---0- 00001000 +-0001--010-1-0 00000100 +-0001---1----0 00001000 +-000-0-1-010-- 00000100 +-000-0-----0-- 00001000 +-000-1-0-001-- 00000100 +-000-1----0--- 00001000 +-0010--010--0- 00000100 +-0011--110---0 00000100 +-001-0-0-0-00- 00000100 +-001-1-1-00--0 00000100 +-00-0-1-101-0- 00100000 +-00-0--010-10- 00000100 +-00-0--01---0- 00001000 +-00-0--0-1001- 00010000 +-00-1-0-10-1-0 00100000 +-00-1--11011-0 00010000 +-00-1--1101--0 00000100 +-00-1--11----0 00001000 +-00-1--1-100-1 00010000 +-00--01--010-- 00100000 +-00--0-0---00- 00001000 +-00--10--001-- 00100000 +-00--1-1--0--0 00001000 +-01-0-0-10--0- 00100000 +-01-1-1-10---0 00100000 +-01--00--0-00- 00100000 +-01--01--0-0-0 00100000 +-01--10--00-0- 00100000 +-01--11--00--0 00100000 +-0-00-01101-0- 00000100 +-0-00-0-10110- 00010000 +-0-00-0-1---0- 00001000 +-0-00-0--1001- 00010000 +-0-01-1010-1-0 00000100 +-0-01-1-1011-0 00010000 +-0-01-1-1----0 00001000 +-0-01-1--100-1 00010000 +-0-0-001-0100- 00000100 +-0-0-00----00- 00001000 +-0-0-110-001-0 00000100 +-0-0-11---0--0 00001000 +-0-10-0010--0- 00000100 +-0-11-1110---0 00000100 +-0-1-000-0-00- 00000100 +-0-1-011-0-0-0 00000100 +-0-1-0---0-000 00000100 +-0-1-100-00-0- 00000100 +-0-1-111-00--0 00000100 +-0-1-1---00-00 00000100 +-0--01--0-01-- 01000000 +-0--01--101-0- 01000000 +-0--0-0010110- 00010000 +-0--0-0010-10- 00000100 +-0--0-001---0- 00001000 +-0--0-0-10-10- 00100000 +-0--10--0-10-- 01000000 +-0--10--10-1-0 01000000 +-0--1-11101--0 00000100 +-0--1-111----0 00001000 +-0--1-1-101--0 00100000 +-0---000---00- 00001000 +-0---011-010-0 00000100 +-0---011---0-0 00001000 +-0---0---1-0-- 01000000 +-0---0-----000 00001000 +-0---100-0010- 00000100 +-0---100--0-0- 00001000 +-0---111--0--0 00001000 +-0---1---10--- 01000000 +-0---1----0-00 00001000 +-10-0-1-0-01-- 00100000 +-10-1-0-0-10-- 00100000 +-10--01---0-1- 00100000 +-10--10----0-1 00100000 +-1100--10-01-- 00000100 +-1101--00-10-- 00000100 +-110-0-1--0-1- 00000100 +-110-1-0---0-1 00000100 +-1110--00--11- 00000100 +-1110---10-100 00010000 +-1110------1-- 00000010 +-1111--10-1--1 00000100 +-1111---101-00 00010000 +-1111-----1--- 00000010 +-111-0-0----1- 00000100 +-111-0------1- 00000010 +-111-1-1-----1 00000100 +-111-1-------1 00000010 +-11-0-0-0--11- 00100000 +-11-0--0-1-011 00010000 +-11-0--0---1-- 00000010 +-11-1-1-0-1--1 00100000 +-11-1--1-10-11 00010000 +-11-1--1--1--- 00000010 +-11--00-----1- 00100000 +-11--0-0---01- 00000100 +-11--0-0---11- 00000010 +-11--11------1 00100000 +-11--1-1--0--1 00000100 +-11--1-1--1--1 00000010 +-11---------11 00100000 +-1-00-010-01-- 00000100 +-1-01-100-10-- 00000100 +-1-0-001--011- 00000100 +-1-0-110--10-1 00000100 +-1-10-000--11- 00000100 +-1-10-0--1-011 00010000 +-1-10-0----1-- 00000010 +-1-11-110-1--1 00000100 +-1-11-1--10-11 00010000 +-1-11-1---1--- 00000010 +-1-1-000---11- 00000100 +-1-1-00----11- 00000010 +-1-1-0-0--111- 00000100 +-1-1-111--1--1 00000100 +-1-1-11---1--1 00000010 +-1-1-1-1--11-1 00000100 +-1-1--0----111 00000100 +-1-1--1---1-11 00000100 +-1--00--0--11- 01000000 +-1--00--10--0- 01000000 +-1--01--0--1-1 01000000 +-1--0-0010-100 00010000 +-1--0-00---1-- 00000010 +-1--10--0-1-1- 01000000 +-1--11--0-1--1 01000000 +-1--11--10---0 01000000 +-1--1-11101-00 00010000 +-1--1-11--1--- 00000010 +-1---000---11- 00000010 +-1---00----01- 00100000 +-1---010--101- 00000100 +-1---011--1-1- 00000010 +-1---0---1--1- 01000000 +-1---0------1- 00000001 +-1---100---1-1 00000010 +-1---101--01-1 00000100 +-1---111--1--1 00000010 +-1---11---0--1 00100000 +-1---1---1---1 01000000 +-1---1-------1 00000001 +-1------10--00 01000000 +--0000-1101-0- 00000100 +--0000--1---0- 00001000 +--0000---1001- 00010000 +--0011-010-1-0 00000100 +--0011--1011-0 00010000 +--0011--1----0 00001000 +--0011---100-1 00010000 +--00--01-010-- 00000100 +--00--0----0-- 00001000 +--00--10-001-- 00000100 +--00--1---0--- 00001000 +--0100-010--0- 00000100 +--0111-110---0 00000100 +--01--00-0-00- 00000100 +--01--01-0-0-0 00000100 +--01--10-00-0- 00000100 +--01--11-00--0 00000100 +--0-001-0-01-- 00100000 +--0-001-101-0- 00100000 +--0-00-010110- 00010000 +--0-00-010-10- 00000100 +--0-00-01---0- 00001000 +--0-110-0-10-- 00100000 +--0-110-10-1-0 00100000 +--0-11-1101--0 00000100 +--0-11-11----0 00001000 +--0---00---00- 00001000 +--0---01---0-0 00001000 +--0---0--1-0-- 00100000 +--0---10--0-0- 00001000 +--0---11--0--0 00001000 +--0---1--10--- 00100000 +--1000-10-01-- 00000100 +--1011-00-10-- 00000100 +--10--01--0-1- 00000100 +--10--10---0-1 00000100 +--1100-00--11- 00000100 +--1100---1-011 00010000 +--1100-----1-- 00000010 +--1111-10-1--1 00000100 +--1111---10-11 00010000 +--1111----1--- 00000010 +--11--00----1- 00000100 +--11--0-----1- 00000010 +--11--11-----1 00000100 +--11--1------1 00000010 +--11--------11 00000100 +--1-000-0--11- 00100000 +--1-000-10--0- 00100000 +--1-001-0--1-1 00100000 +--1-00-010-100 00010000 +--1-00-0---1-- 00000010 +--1-110-0-1-1- 00100000 +--1-111-0-1--1 00100000 +--1-111-10---0 00100000 +--1-11-1101-00 00010000 +--1-11-1--1--- 00000010 +--1---00---01- 00000100 +--1---00---11- 00000010 +--1---01--1-1- 00000010 +--1---0-0-111- 00100000 +--1---0--1--1- 00100000 +--1---0-----1- 00000001 +--1---10---1-1 00000010 +--1---11--0--1 00000100 +--1---11--1--1 00000010 +--1---1-0-11-1 00100000 +--1---1--1---1 00100000 +--1---1------1 00000001 +--1-----10--00 00100000 +---000010-01-- 00000100 +---00001101-0- 00000100 +---0000-10110- 00010000 +---0000-1---0- 00001000 +---011100-10-- 00000100 +---0111010-1-0 00000100 +---0111-1----0 00001000 +---0---0-1-0-- 00000100 +---0---0---0-- 00001000 +---0---1-10--- 00000100 +---0---1--0--- 00001000 +---100000--11- 00000100 +---1000010--0- 00000100 +---100010--1-1 00000100 +---1000-10-100 00010000 +---1000----1-- 00000010 +---111100-1-1- 00000100 +---111110-1--1 00000100 +---1111110---0 00000100 +---1111-101-00 00010000 +---1111---1--- 00000010 +---1---00-111- 00000100 +---1---0-1--1- 00000100 +---1---0----1- 00000011 +---1---10-11-1 00000100 +---1---1-1---1 00000100 +---1---1-----1 00000011 +---1----10--00 00000100 +----000010-10- 00010100 +----00001---0- 00001000 +----0000-1-01- 00010000 +----0000---1-- 00000010 +----000-10-10- 00100000 +----00--10-10- 01000000 +----1111101--0 00010100 +----11111----0 00001000 +----1111-10--1 00010000 +----1111--1--- 00000010 +----111-101--0 00100000 +----11--101--0 01000000 +------0-10-100 00100000 +------1-101-00 00100000 +-------010-100 00000100 +-------1101-00 00000100 +--------101100 00010000 +--------1---00 00001000 +---------10011 00010000 +----------11-- 00000010 diff --git a/espresso/examples/math/z4 b/espresso/examples/math/z4 new file mode 100644 index 0000000..c2974e8 --- /dev/null +++ b/espresso/examples/math/z4 @@ -0,0 +1,130 @@ +.i 7 +.o 4 +0000000 0000 +0000001 0001 +0000010 0010 +0000011 0011 +0000100 0100 +0000101 0101 +0000110 0110 +0000111 0111 +0001000 0001 +0001001 0010 +0001010 0011 +0001011 0100 +0001100 0101 +0001101 0110 +0001110 0111 +0001111 1000 +0010000 0010 +0010001 0011 +0010010 0100 +0010011 0101 +0010100 0110 +0010101 0111 +0010110 1000 +0010111 1001 +0011000 0011 +0011001 0100 +0011010 0101 +0011011 0110 +0011100 0111 +0011101 1000 +0011110 1001 +0011111 1010 +0100000 0100 +0100001 0101 +0100010 0110 +0100011 0111 +0100100 1000 +0100101 1001 +0100110 1010 +0100111 1011 +0101000 0101 +0101001 0110 +0101010 0111 +0101011 1000 +0101100 1001 +0101101 1010 +0101110 1011 +0101111 1100 +0110000 0110 +0110001 0111 +0110010 1000 +0110011 1001 +0110100 1010 +0110101 1011 +0110110 1100 +0110111 1101 +0111000 0111 +0111001 1000 +0111010 1001 +0111011 1010 +0111100 1011 +0111101 1100 +0111110 1101 +0111111 1110 +1000000 0001 +1000001 0010 +1000010 0011 +1000011 0100 +1000100 0101 +1000101 0110 +1000110 0111 +1000111 1000 +1001000 0010 +1001001 0011 +1001010 0100 +1001011 0101 +1001100 0110 +1001101 0111 +1001110 1000 +1001111 1001 +1010000 0011 +1010001 0100 +1010010 0101 +1010011 0110 +1010100 0111 +1010101 1000 +1010110 1001 +1010111 1010 +1011000 0100 +1011001 0101 +1011010 0110 +1011011 0111 +1011100 1000 +1011101 1001 +1011110 1010 +1011111 1011 +1100000 0101 +1100001 0110 +1100010 0111 +1100011 1000 +1100100 1001 +1100101 1010 +1100110 1011 +1100111 1100 +1101000 0110 +1101001 0111 +1101010 1000 +1101011 1001 +1101100 1010 +1101101 1011 +1101110 1100 +1101111 1101 +1110000 0111 +1110001 1000 +1110010 1001 +1110011 1010 +1110100 1011 +1110101 1100 +1110110 1101 +1110111 1110 +1111000 1000 +1111001 1001 +1111010 1010 +1111011 1011 +1111100 1100 +1111101 1101 +1111110 1110 +1111111 1111 diff --git a/espresso/examples/random/bench b/espresso/examples/random/bench new file mode 100644 index 0000000..7860af5 --- /dev/null +++ b/espresso/examples/random/bench @@ -0,0 +1,66 @@ +.i 6 +.o 8 +000000 --0-0--- +000001 --10---- +000010 --0-01-1 +000011 ---1---- +000100 ---1---0 +000101 -0--0-10 +000110 0-0----- +000111 --0-0-0- +001000 0-1-1-0- +001001 0---00-- +001010 0-0-0110 +001011 -01----- +001100 ------0- +001101 -0-1-0-- +001110 0------- +001111 0-100--- +010000 --0----- +010001 11----1- +010010 -111---- +010011 ----0--0 +010100 ----00-- +010101 --0-0--- +010110 -0-0---0 +010111 -00-00-0 +011000 -------- +011001 ---0---- +011010 1-1----- +011011 --0-1--- +011100 ---0--0- +011101 ----0-0- +011110 11-----0 +011111 ----0-0- +100000 --00-1-- +100001 --0----- +100010 01-0---- +100011 -----0-- +100100 ------0- +100101 0-0---1- +100110 0----0-0 +100111 -0--1--1 +101000 ---0---- +101001 100-0--0 +101010 ------00 +101011 -0-----0 +101100 -0--0-0- +101101 ------11 +101110 1-0----- +101111 ---10101 +110000 ----0--0 +110001 ---0---0 +110010 ----1-10 +110011 -------0 +110100 -01---10 +110101 -0---1-- +110110 --0----- +110111 -------- +111000 ----0--1 +111001 ------0- +111010 --00--11 +111011 -0---0-- +111100 -0-10--- +111101 -0000-00 +111110 --1000-- +111111 --0001-1 diff --git a/espresso/examples/random/bench1 b/espresso/examples/random/bench1 new file mode 100644 index 0000000..7c977c7 --- /dev/null +++ b/espresso/examples/random/bench1 @@ -0,0 +1,483 @@ +.i 9 +.o 9 +000000000 ---0-0--- +000000001 -----0--- +000000010 --0---10- +000000011 -----0--- +000000100 -----10-- +000000101 01-0----0 +000000110 --1------ +000000111 --0--1--- +000001000 --0------ +000001001 ----0---- +000001011 -011-0--1 +000001101 0--01-00- +000001110 --------0 +000001111 00--0---- +000010000 -0-0---0- +000010001 ---00---0 +000010010 --0-0---0 +000010011 ----0--1- +000010100 --00----0 +000010101 --1--0--- +000010110 1-0------ +000010111 -0-0-0000 +000011000 01---1--1 +000011001 -000----- +000011010 -0--0-0-- +000011100 000---00- +000011101 -1000---- +000011110 0--0-0--- +000011111 0---11--- +000100000 00---0--1 +000100001 00-01---- +000100010 --1--01-- +000100011 1--00-0-- +000100100 -1--10--1 +000100101 0----1--- +000100110 -00--10-- +000100111 ---0----- +000101000 00------- +000101001 0---0---- +000101010 -0----0-0 +000101011 --0----1- +000101100 --0--0--1 +000101101 0--00---- +000101110 0---0---- +000101111 ---0----- +000110000 00----00- +000110001 0-1-111-- +000110010 ----0---0 +000110011 1----0--0 +000110110 -1------0 +000110111 --000-00- +000111000 --00--1-1 +000111001 -0--0-00- +000111010 -0-----1- +000111011 0---0--00 +000111100 --001-1-- +000111101 -----0--- +000111110 -0010---1 +000111111 ------1-0 +001000000 -----0--0 +001000001 -0-0-0--- +001000010 10-0----- +001000011 --0--00-0 +001000100 1---01-0- +001000101 --1-0---- +001000110 ----0-00- +001000111 ----1100- +001001000 --------1 +001001001 -----0--0 +001001010 1-------- +001001011 0-0----00 +001001100 --------1 +001001110 -----1--- +001001111 ---10---- +001010000 ---0----- +001010001 0------11 +001010010 ---0----- +001010011 --0--0--- +001010101 ----0---- +001010110 ---0----- +001010111 ---0--01- +001011001 ----0-0-0 +001011010 -1-----00 +001011011 1-0-0-0-- +001011100 0-1-----0 +001011101 --------0 +001011110 ---00--01 +001011111 1-1---00- +001100000 0-------- +001100001 --000---- +001100010 --------0 +001100011 0--0-000- +001100100 --1-1---- +001100101 10-0-0-1- +001100110 ------00- +001100111 0--0---00 +001101000 ---10-0-- +001101001 ---0---01 +001101010 --0-0---- +001101011 --1--00-- +001101100 0-0-1---0 +001101101 ---1--010 +001101110 ---1----1 +001101111 ----1-00- +001110000 0-1---000 +001110001 -------1- +001110010 00----1-- +001110011 ---10-0-- +001110100 0-------- +001110101 -1------- +001110110 ------0-- +001110111 0--0-00-- +001111000 0------10 +001111001 ------0-0 +001111010 ------0-- +001111011 -0-0----- +001111100 -0------- +001111101 0--0-1--- +001111110 -----1-0- +001111111 -----01-- +010000000 0----1-01 +010000001 ---00---- +010000010 -----00-1 +010000011 0--1----- +010000100 ---0-1-1- +010000101 ------1-- +010000110 -0--0--1- +010000111 ------1-- +010001000 -0---11-- +010001001 ----0-0-- +010001010 ----0110- +010001011 -----1--0 +010001100 --0------ +010001110 --0-----0 +010001111 -01----11 +010010000 0--011010 +010010001 -0------0 +010010010 -0-1--000 +010010011 ------0-- +010010100 0------0- +010010101 -00111--- +010010110 0--0----0 +010011000 1---00--- +010011001 --0--1--- +010011010 -100----- +010011011 0-0------ +010011100 --1-00--0 +010011101 ---1---01 +010011110 1--0--0-0 +010011111 --0------ +010100000 -000--01- +010100001 0-----0-- +010100010 --0------ +010100011 -----001- +010100100 --0---0-- +010100101 -----0010 +010100110 -1------1 +010100111 1100----- +010101000 0----0--- +010101001 0000--1-- +010101010 10--00--- +010101011 ----0--0- +010101100 11------0 +010101101 0--001--- +010101110 1--110--0 +010101111 -00-000-- +010110000 -01-10-0- +010110001 ----1---- +010110010 0------0- +010110011 0-1---001 +010110100 ---1---0- +010110101 -1------- +010110110 --00----- +010110111 --00----1 +010111000 00-0-0--- +010111001 -----10-- +010111011 1-0-----0 +010111100 -01-0---- +010111101 -------0- +010111110 01--1---- +010111111 -0----110 +011000000 ---10--0- +011000001 -00-0---- +011000010 ---0----- +011000011 ----0---0 +011000100 --00--10- +011000101 -0------- +011000110 --------0 +011001000 11-0----- +011001001 1--0--000 +011001010 -0--0-0-0 +011001011 10---01-- +011001100 0-0------ +011001101 --10--0-0 +011001110 -0------- +011001111 -----1--- +011010000 -0----00- +011010001 -1-00--00 +011010010 --------1 +011010100 -----010- +011010110 0-------- +011010111 -1--00-1- +011011000 11------- +011011001 -000---1- +011011010 ---00--0- +011011011 ------0-0 +011011100 0-1---00- +011011101 1--0-00-- +011011110 -00--0--- +011011111 -0-1----0 +011100000 -0-1--00- +011100001 -0------1 +011100010 1-0-00--0 +011100011 0-------- +011100100 --------0 +011100101 0-------- +011100110 1---0---- +011100111 0-0--0--- +011101000 -----1--0 +011101001 -------00 +011101010 0----00-- +011101011 0----0-0- +011101100 0------00 +011101101 ----1-0-- +011101110 1-1------ +011101111 -0------1 +011110000 0-----0-- +011110001 --1----0- +011110010 -----1--0 +011110011 -----0--- +011110100 ---0--0-- +011110101 000--0-1- +011110110 11-1-0--0 +011110111 --10-1--- +011111000 1---0-11- +011111001 --0-0---- +011111010 --0000-00 +011111100 0----0110 +011111101 0-0-0--0- +011111110 ----0000- +011111111 -0---0--- +100000000 ---1----- +100000001 1-10--1-- +100000010 --------1 +100000011 -00-1--1- +100000100 1-10---0- +100000111 ---1-1-1- +100001000 0-------- +100001001 --0-0-0-0 +100001010 11-10-0-- +100001011 -----011- +100001100 -----10-0 +100001101 010----00 +100001110 -1--10--- +100010000 --00----0 +100010001 1-0-10--- +100010010 00--00--- +100010011 1--1-00-0 +100010100 -00-1---- +100010101 0--0----- +100010111 0-1--01-1 +100011000 1-0--0--- +100011001 1-1---0-0 +100011010 -----0-10 +100011011 1------1- +100011100 1----010- +100011101 --------0 +100011110 11--1-0-- +100011111 --------0 +100100000 --0010-0- +100100001 -----0--1 +100100010 0--0----- +100100011 --0-----1 +100100100 --0-1---- +100100101 00---0--0 +100100110 1--0-0--1 +100100111 ----0-1-0 +100101000 0---0---- +100101001 -11--1--- +100101010 0-01--001 +100101011 --00--0-0 +100101100 --0-0---- +100101101 --1-----0 +100101110 00---1--0 +100101111 01---00-- +100110000 -----01-0 +100110001 ----0--0- +100110010 0-1----0- +100110011 00--00001 +100110100 1-1-0---0 +100110101 ----0---- +100110110 ---0----0 +100110111 ----11001 +100111000 ---10---- +100111001 --------1 +100111010 ----0---- +100111100 01------- +100111101 0-------0 +100111110 --------1 +100111111 --0--10-- +101000000 ---10-0-- +101000001 ----0---0 +101000010 0-0------ +101000011 ------0-0 +101000100 00---100- +101000101 01-0----0 +101000110 0-----0-- +101000111 --1---0-- +101001001 --010-1-- +101001010 ----1---- +101001011 0--00--1- +101001100 ----00--- +101001101 0--0-10-- +101001110 -00---1-- +101001111 1---0-00- +101010000 00------0 +101010001 11-0--00- +101010010 ---00---- +101010011 0----11-- +101010100 0-1------ +101010101 1000----- +101010110 -----0--- +101010111 -000---0- +101011000 -0---1--- +101011001 --0-0--0- +101011010 ----1--0- +101011011 ---0--0-- +101011100 ---11001- +101011101 0-1----0- +101011110 --1-0---- +101011111 -------1- +101100000 ----11--0 +101100001 0-0-1-011 +101100010 1---0---0 +101100011 ---001--- +101100101 -0-0--1-- +101100110 001-11-10 +101100111 ---0--0-- +101101000 1---0--1- +101101001 -0------- +101101010 ---1----1 +101101011 ------1-- +101101100 1--0--0-0 +101101101 -1---0-11 +101101110 01--0---- +101101111 -00-0---- +101110000 ---00--0- +101110001 0---00--- +101110010 --0-----0 +101110100 0---1---0 +101110101 ------00- +101110110 0-0---1-- +101110111 -00-0-010 +101111000 -1-0----- +101111001 ---1-0--- +101111010 ----000-- +101111011 -0------1 +101111100 1-----0-- +101111101 0----0--- +101111110 -0-1---0- +110000000 -0--0---- +110000001 --------1 +110000010 -0-0-0--- +110000011 -----0-0- +110000100 ----1-1-- +110000101 ----0--00 +110000110 -------0- +110000111 --0-----1 +110001000 0-----00- +110001001 0--00---1 +110001010 01----0-1 +110001011 --------0 +110001100 ----001-- +110001101 001--0--- +110001110 ---0----0 +110001111 0---1---- +110010000 0-------- +110010001 ----0---1 +110010010 0011--0-1 +110010100 11-----0- +110010101 -0---11-- +110010110 ---0----0 +110010111 --0-----1 +110011000 0--0--0-- +110011001 --000000- +110011010 1--0----- +110011011 --0011-00 +110011100 -0-----0- +110011101 -0---0-0- +110011110 1-----0-- +110011111 --1--1--- +110100000 -------1- +110100001 -100---0- +110100010 -----00-- +110100011 ---0---01 +110100100 -----0-1- +110100101 --0------ +110100110 -----0--- +110100111 -----10-- +110101000 -1-0---00 +110101001 -00---0-- +110101011 -0---0--- +110101100 0-0----00 +110101101 -----00-- +110101110 -1----1-- +110101111 ---01---- +110110000 0--111--- +110110001 -000-0--0 +110110010 -------0- +110110011 -----0--- +110110100 -10-1-0-- +110110101 -0---000- +110110110 -------00 +110110111 -000---1- +110111000 0-----1-0 +110111001 -1-0----0 +110111010 0000-0--- +110111011 00100--1- +110111100 -00---0-- +110111101 -----010- +110111110 -0------- +110111111 0------0- +111000000 01--0---- +111000001 11-0-000- +111000010 01-00--0- +111000011 --1------ +111000100 -00-0---- +111000101 ----00--- +111000110 ---0---0- +111000111 -1-000--- +111001000 -----00-- +111001001 -1-----0- +111001010 00-0000-- +111001100 1--0-0--- +111001101 -0--0-00- +111001110 1---0--0- +111001111 0----0--- +111010000 01-0-0--- +111010001 -0----0-0 +111010010 1---0-0-- +111010011 -0--10--0 +111010100 ------0-- +111010101 -----0-0- +111010111 0----01-0 +111011001 --0-1---0 +111011010 0---11--- +111011011 ----0--0- +111011100 0--00110- +111011110 10--00--0 +111011111 -1-0----- +111100000 0---0---- +111100001 -----001- +111100010 -01------ +111100011 ---0-0--0 +111100100 ----0--00 +111100101 1----000- +111100110 -10------ +111100111 -00--001- +111101000 -----0--- +111101001 -00--00-- +111101010 1---0---1 +111101011 --0----0- +111101100 --0-0---- +111101101 1-0-01-0- +111101110 -0-0-0--1 +111101111 -1-----00 +111110000 0-----0-- +111110010 0-------0 +111110011 -0--0--0- +111110100 --------1 +111110101 1----00-- +111110110 1---0---- +111110111 -0-01---0 +111111000 --0-01--0 +111111001 ----00--- +111111010 --10-1--- +111111011 111-10--- +111111100 0--0----- +111111101 0-000-1-- +111111110 1-1-----1 +111111111 00------- diff --git a/espresso/examples/random/ex1010 b/espresso/examples/random/ex1010 new file mode 100644 index 0000000..66fe566 --- /dev/null +++ b/espresso/examples/random/ex1010 @@ -0,0 +1,1026 @@ +.i 10 +.o 10 +0000000000 -110-1---- +0000000001 -0-0------ +0000000010 ---1-00--1 +0000000011 -0-------0 +0000000100 --01-----0 +0000000101 ------0--0 +0000000110 010--01--- +0000000111 -0001----- +0000001000 ---00-1--- +0000001001 0-1------- +0000001010 ---1--1-1- +0000001011 ---0-1---- +0000001100 -----0--01 +0000001101 ---------- +0000001110 --1------- +0000001111 -1---1--1- +0000010000 --0-0-1--- +0000010001 -1-------- +0000010010 0------0-- +0000010011 ------0-0- +0000010100 -00----0-- +0000010101 00-------- +0000010110 --0--0---- +0000010111 ------0--1 +0000011000 -----000-1 +0000011001 --0--0---- +0000011010 ----000-0- +0000011011 ----0---1- +0000011100 -1-----010 +0000011101 ---0------ +0000011110 1---0-01-- +0000011111 -1----0--- +0000100000 ---1---1-- +0000100001 -111--11-0 +0000100010 ------0-1- +0000100011 -------11- +0000100100 -----0---- +0000100101 ------1--1 +0000100110 10----0-01 +0000100111 1-0--11--1 +0000101000 -0-1----10 +0000101001 0-1------- +0000101010 1------1-1 +0000101011 -0---1-0-- +0000101100 ---1------ +0000101101 ----1-0-1- +0000101110 -1--10---1 +0000101111 ---00----- +0000110000 0-0--101-- +0000110001 ---0-----1 +0000110010 --0------- +0000110011 1-0-01---- +0000110100 ----0---1- +0000110101 00--0-1--- +0000110110 0-0----1-- +0000110111 --01------ +0000111000 ---------- +0000111001 ----111--1 +0000111010 ---0--0--- +0000111011 0--------- +0000111100 -----0---- +0000111101 --10---10- +0000111110 ------1--- +0000111111 -------0-- +0001000000 ----0--00- +0001000001 ---0------ +0001000010 ---------- +0001000011 -0--0--1-- +0001000100 -01-0----0 +0001000101 1-0-----1- +0001000110 -0-0---0-- +0001000111 -------0-- +0001001000 0-0000---0 +0001001001 10-01----- +0001001010 0-0--101-- +0001001011 -----00--1 +0001001100 1--------- +0001001101 1-1------- +0001001110 ---10---10 +0001001111 --00----1- +0001010000 --10----10 +0001010001 -1-11-11-- +0001010010 --01--0--- +0001010011 -------01- +0001010100 -0-------- +0001010101 0-------11 +0001010110 ----1---1- +0001010111 -1-001---0 +0001011000 ------0--- +0001011001 ---------- +0001011010 00-1-100-- +0001011011 --1------- +0001011100 ---00---0- +0001011101 -0----00-- +0001011110 -----0---- +0001011111 -----1-1-1 +0001100000 1------10- +0001100001 --01--01-- +0001100010 1-----1-1- +0001100011 1-0-1-1-01 +0001100100 10-0-11--- +0001100101 -0---1---0 +0001100110 ----1--0-- +0001100111 -11-----1- +0001101000 00000-0-0- +0001101001 0--00-110- +0001101010 --01------ +0001101011 --0------- +0001101100 010-01---1 +0001101101 -----1--1- +0001101110 ----0----- +0001101111 -0--0--0-- +0001110000 ---01----- +0001110001 -1110-0--1 +0001110010 --01------ +0001110011 ----0---0- +0001110100 -0-1-----1 +0001110101 -1-1--0-1- +0001110110 -0-01-1--0 +0001110111 01101----0 +0001111000 -------0-- +0001111001 0101---1-- +0001111010 01-----0-1 +0001111011 1-1--10-10 +0001111100 1-0-----1- +0001111101 ---------- +0001111110 -1-------- +0001111111 -----0--0- +0010000000 ---10---1- +0010000001 01101----0 +0010000010 --------1- +0010000011 1-1------- +0010000100 ---1--0--- +0010000101 --00-----0 +0010000110 ------0--- +0010000111 0-110----- +0010001000 -1--0----- +0010001001 ----0----- +0010001010 -1-0--0-10 +0010001011 ------0--- +0010001100 -----0-00- +0010001101 --0---0--1 +0010001110 ----1----0 +0010001111 -1-------- +0010010000 011----0-1 +0010010001 ---1--00-1 +0010010010 ----000--- +0010010011 --01-0---- +0010010100 -0------0- +0010010101 -1------00 +0010010110 0-----0--- +0010010111 -----10-0- +0010011000 100--0---- +0010011001 11--1--1-- +0010011010 ---------- +0010011011 0--00----- +0010011100 1--1-----0 +0010011101 1--1--0--- +0010011110 -0-------1 +0010011111 ---00---1- +0010100000 ---------1 +0010100001 -----1--0- +0010100010 1------1-- +0010100011 -1---1-01- +0010100100 ---0-01--1 +0010100101 --0--110-1 +0010100110 ------101- +0010100111 10--1-100- +0010101000 ----0---1- +0010101001 1-----011- +0010101010 1--0-011-- +0010101011 0-----1--- +0010101100 -------1-0 +0010101101 --0---0-0- +0010101110 -1---01-1- +0010101111 -------01- +0010110000 ----0--0-- +0010110001 10-------0 +0010110010 ----0----- +0010110011 --0-00-1-1 +0010110100 11-----0-- +0010110101 0----00--- +0010110110 -00-0---1- +0010110111 0-------1- +0010111000 1--000-0-- +0010111001 ----000--- +0010111010 ---1------ +0010111011 -0---1---- +0010111100 ------1-1- +0010111101 -01-1---0- +0010111110 0--0--0110 +0010111111 -0-0001--1 +0011000000 0---0-1--- +0011000001 -1--1--1-- +0011000010 ---01----0 +0011000011 ------1--- +0011000100 --0----0-1 +0011000101 --010----0 +0011000110 --1-1-0--1 +0011000111 --1--0---1 +0011001000 1-----101- +0011001001 1-0----00- +0011001010 --01--0--0 +0011001011 ----01---0 +0011001100 --1111---0 +0011001101 -1-----1-- +0011001110 -01-0--1-0 +0011001111 ------0-00 +0011010000 -1-1-0---- +0011010001 --0-0----- +0011010010 00-0------ +0011010011 --1-0---1- +0011010100 10--10-1-1 +0011010101 -0--1----- +0011010110 1---10---- +0011010111 ---00-1--0 +0011011000 -1-0-----1 +0011011001 -1---000-- +0011011010 1--01-0-11 +0011011011 --11------ +0011011100 -------0-- +0011011101 --1------- +0011011110 011--11--- +0011011111 -----0---1 +0011100000 --01--1--- +0011100001 -------11- +0011100010 0----0--0- +0011100011 -1-1---0-- +0011100100 -------1-- +0011100101 -10-1----- +0011100110 1--0-00--- +0011100111 100-11---1 +0011101000 1--00----0 +0011101001 --010---00 +0011101010 -0-----1-- +0011101011 1--0----1- +0011101100 --0-1--1-- +0011101101 1--1-1---- +0011101110 000-101-1- +0011101111 1-1---110- +0011110000 0--0-1---- +0011110001 -0-00-0-00 +0011110010 -1----0--- +0011110011 -00---1-1- +0011110100 0--------- +0011110101 1-0---1--- +0011110110 1-1--0---- +0011110111 -0---1-0-- +0011111000 -1-1-1--1- +0011111001 -00-00--0- +0011111010 -1-----1-- +0011111011 0-----1--- +0011111100 ---0-00--0 +0011111101 ------010- +0011111110 --11-1---- +0011111111 -001--100- +0100000000 -0---0-1-- +0100000001 1--1--10-- +0100000010 -0------1- +0100000011 -0-------- +0100000100 11-0---1-- +0100000101 ---0------ +0100000110 ---0---0-- +0100000111 1--0---1-- +0100001000 00------1- +0100001001 01--0-00-- +0100001010 0---001-0- +0100001011 -1---01--- +0100001100 1------01- +0100001101 --1------- +0100001110 -00-0--11- +0100001111 -----01-0- +0100010000 -111---1-- +0100010001 0--0-01-1- +0100010010 -0-0---01- +0100010011 0-----0--0 +0100010100 ---1-10-0- +0100010101 -0-------- +0100010110 --1-----1- +0100010111 0--00--1-1 +0100011000 ---0------ +0100011001 -1--00---- +0100011010 --1---11-- +0100011011 ---1---00- +0100011100 -10000-1-- +0100011101 --01------ +0100011110 -1-0---00- +0100011111 101--11--- +0100100000 -10--1-0-1 +0100100001 0--10---00 +0100100010 0-1-01-0-- +0100100011 -1-------- +0100100100 --10---0-- +0100100101 10--00---- +0100100110 ----01---- +0100100111 -1---1---- +0100101000 ---0-----0 +0100101001 0---00---- +0100101010 -0--0--0-1 +0100101011 --0-----01 +0100101100 ----01---0 +0100101101 ---111--1- +0100101110 ---1--11-0 +0100101111 ---------1 +0100110000 ---------- +0100110001 1-0-0-0-0- +0100110010 -------00- +0100110011 --1------0 +0100110100 1-----1--- +0100110101 ----0-0-1- +0100110110 -11-0----- +0100110111 -10------- +0100111000 ---------- +0100111001 1-11------ +0100111010 ---------1 +0100111011 1---00---1 +0100111100 1--010--0- +0100111101 0001-1---- +0100111110 ---0---0-1 +0100111111 -0---00-00 +0101000000 0----1--01 +0101000001 ----0----- +0101000010 -0-------- +0101000011 ---------- +0101000100 11--0----0 +0101000101 1----1---- +0101000110 --11---001 +0101000111 -0-00----- +0101001000 ---1------ +0101001001 ---1---1-- +0101001010 0-1-1-0--0 +0101001011 -------0-- +0101001100 ---------- +0101001101 -00---01-- +0101001110 --01-01--- +0101001111 ----1----- +0101010000 -10--0-0-- +0101010001 -1-0------ +0101010010 ---10----0 +0101010011 00--1--11- +0101010100 ---10-0--- +0101010101 ---1---111 +0101010110 ---10----0 +0101010111 1---10-0-- +0101011000 -0--10---- +0101011001 0-0--01--- +0101011010 -0--0-1--- +0101011011 --------1- +0101011100 1-1----1-1 +0101011101 -1---110-0 +0101011110 0----1---- +0101011111 -----00--- +0101100000 -----1---0 +0101100001 --------0- +0101100010 --0010---- +0101100011 --1-0-11-- +0101100100 -----0--0- +0101100101 ---1------ +0101100110 0------1-- +0101100111 10-------- +0101101000 --0-11---- +0101101001 --1-0-1-11 +0101101010 ----1--01- +0101101011 --1----1-- +0101101100 --1-00--0- +0101101101 1-1-0-0--- +0101101110 --1------- +0101101111 ---1-0---0 +0101110000 -1-1-1100- +0101110001 1-0--0---- +0101110010 -0-------- +0101110011 -0----1--- +0101110100 ---0-01-11 +0101110101 ----01---- +0101110110 10-10010-1 +0101110111 -0----100- +0101111000 -0----11-- +0101111001 0--0---011 +0101111010 -0--1-1-0- +0101111011 1------00- +0101111100 --0----0-- +0101111101 1-1---10-- +0101111110 -0-----1-- +0101111111 ------1--- +0110000000 00---1---- +0110000001 1-1---0--0 +0110000010 -0-------- +0110000011 1-0-0-1-1- +0110000100 -11-1----- +0110000101 -------00- +0110000110 --0---0-0- +0110000111 00--1----- +0110001000 ------0--- +0110001001 ---------0 +0110001010 -0-0-----0 +0110001011 --0-1---00 +0110001100 ----0--0-- +0110001101 ----101--- +0110001110 0--------- +0110001111 11--0-100- +0110010000 --0------- +0110010001 ----11---- +0110010010 --------10 +0110010011 --0-1--0-0 +0110010100 1--01-1--0 +0110010101 0-110---0- +0110010110 -0-1-10--- +0110010111 10---1---- +0110011000 -00---0--1 +0110011001 ---------- +0110011010 --0--1---- +0110011011 --0---0--0 +0110011100 -0----0--- +0110011101 ----01-1-- +0110011110 ---0--1-1- +0110011111 --1----1-1 +0110100000 ---------- +0110100001 1--------- +0110100010 10----1--- +0110100011 --1-0---1- +0110100100 -1-1--100- +0110100101 ---0---1-- +0110100110 ---0-1-101 +0110100111 ---11--1-- +0110101000 1-----0--- +0110101001 -0--1----0 +0110101010 00-------- +0110101011 ----0--1-0 +0110101100 -11-111-0- +0110101101 --0-1-101- +0110101110 0--01----1 +0110101111 ----010-11 +0110110000 1-0----0-1 +0110110001 0-1-1---0- +0110110010 -----10--1 +0110110011 0-1----1-- +0110110100 --01-110-0 +0110110101 ------1--- +0110110110 -----10--- +0110110111 -0-0---1-0 +0110111000 10----001- +0110111001 0-1-1-0--- +0110111010 -0-01---0- +0110111011 1---0----- +0110111100 -0--0--11- +0110111101 10-0---0-0 +0110111110 -0--0----- +0110111111 -0-------0 +0111000000 -1-1----0- +0111000001 10---1100- +0111000010 1--------- +0111000011 ---------0 +0111000100 ------0-1- +0111000101 ---------- +0111000110 -0---00--0 +0111000111 ---0--0--- +0111001000 -1--0---1- +0111001001 -0---0---- +0111001010 0--0-01--0 +0111001011 ----0-1--- +0111001100 -------0-- +0111001101 ---00-10-0 +0111001110 1--0---0-- +0111001111 10----1--- +0111010000 -0--010--- +0111010001 1-------1- +0111010010 --0--0--1- +0111010011 ---1-1-0-- +0111010100 0---0-0--1 +0111010101 --0---0--- +0111010110 0---111--- +0111010111 -----0-100 +0111011000 --0-0-1--- +0111011001 --0----0-- +0111011010 --0----0-0 +0111011011 ---10----0 +0111011100 0--------- +0111011101 0---0----- +0111011110 -10-00---- +0111011111 0--01----- +0111100000 0-0-00---- +0111100001 0---101--- +0111100010 ---0---1-- +0111100011 ---0--1-0- +0111100100 ----0--0-- +0111100101 -10--0---- +0111100110 ---10--10- +0111100111 ----0-0--- +0111101000 -1--11-1-- +0111101001 -----0---1 +0111101010 --1------- +0111101011 -10--1-1-- +0111101100 -----01--- +0111101101 0--1---1-1 +0111101110 0-----0-11 +0111101111 --0------- +0111110000 -------1-- +0111110001 ----10---- +0111110010 --00------ +0111110011 ----0---10 +0111110100 --1--0--0- +0111110101 -1----00-- +0111110110 -1--1----- +0111110111 -10------- +0111111000 01------0- +0111111001 11-------- +0111111010 10-------- +0111111011 -0---1-1-- +0111111100 ---01---0- +0111111101 ---0-11--0 +0111111110 1-----0-10 +0111111111 -0-----00- +1000000000 -11---10-- +1000000001 --10--0--- +1000000010 0--1------ +1000000011 0001-0-0-- +1000000100 1--0-0---- +1000000101 0-0---01-- +1000000110 -1--1-10-- +1000000111 0-0-1--1-- +1000001000 1-0-1-1--- +1000001001 ---01---0- +1000001010 -1-11----- +1000001011 ----1----- +1000001100 ----1--11- +1000001101 0--------- +1000001110 ----0---0- +1000001111 -0--0----1 +1000010000 ----0---00 +1000010001 1-1--0---- +1000010010 10--01---- +1000010011 -------1-- +1000010100 ----11-1-- +1000010101 ----0----1 +1000010110 -101-0---- +1000010111 1-0-11--0- +1000011000 -0--0--1-- +1000011001 --0------- +1000011010 -10---100- +1000011011 -01--0---- +1000011100 ---------- +1000011101 -----01--- +1000011110 --------1- +1000011111 1---0---0- +1000100000 -----0---0 +1000100001 --11-1---- +1000100010 ------0--- +1000100011 --1---1--1 +1000100100 1--1----1- +1000100101 0-00---1-0 +1000100110 1000------ +1000100111 ---10---1- +1000101000 ---01----0 +1000101001 ----0----- +1000101010 -1-11--1-1 +1000101011 ---01-0-10 +1000101100 ---0---1-- +1000101101 -1-01-1-10 +1000101110 ----1---00 +1000101111 ------0--- +1000110000 ----0----- +1000110001 --1------- +1000110010 -1----0--- +1000110011 ---111-0-- +1000110100 -----1---- +1000110101 0----1---- +1000110110 ---1--1--- +1000110111 00-1------ +1000111000 0-0---01-- +1000111001 1--1-1-0-- +1000111010 1--------1 +1000111011 1-1-1----- +1000111100 1-1----0-- +1000111101 -----0---- +1000111110 0--------- +1000111111 -----11--- +1001000000 0-1-----1- +1001000001 --00-1---- +1001000010 -----01--- +1001000011 1-1--0---- +1001000100 ------01-- +1001000101 0--1-00--- +1001000110 1-0----00- +1001000111 -0---0-11- +1001001000 --1------- +1001001001 1-0------- +1001001010 10-------- +1001001011 0--1-0--01 +1001001100 -----1--1- +1001001101 --000--00- +1001001110 ----0110-0 +1001001111 ----0---1- +1001010000 --1--0---- +1001010001 -10------1 +1001010010 --------1- +1001010011 10--10-0-- +1001010100 ---0-----0 +1001010101 ---1--1-0- +1001010110 --100-0--- +1001010111 1--1--1-10 +1001011000 1----1---- +1001011001 ---------- +1001011010 1-01-11-01 +1001011011 0-10-01--- +1001011100 --00--1-0- +1001011101 1--0-0---0 +1001011110 -0----1-00 +1001011111 --0------- +1001100000 10-1----0- +1001100001 ---0------ +1001100010 ---1-1--01 +1001100011 001--1-1-1 +1001100100 -10-0-01-- +1001100101 0--------- +1001100110 ---0----1- +1001100111 ---------- +1001101000 ----10---0 +1001101001 1-----1--- +1001101010 --------1- +1001101011 0--00----- +1001101100 -----0-0-- +1001101101 0-1--1---- +1001101110 -0-00--0-- +1001101111 --1------0 +1001110000 ---1--1--0 +1001110001 ----1----- +1001110010 --------0- +1001110011 -11-11--1- +1001110100 --0------1 +1001110101 -0101----- +1001110110 --0---0--- +1001110111 0--------- +1001111000 11------1- +1001111001 -------0-- +1001111010 00----0--1 +1001111011 0--1--1--- +1001111100 ----10-1-- +1001111101 1-----10-- +1001111110 ----01-11- +1001111111 -------1-0 +1010000000 -------01- +1010000001 -0-0------ +1010000010 00-------- +1010000011 1----100-1 +1010000100 --0---1--- +1010000101 ---1-1---- +1010000110 -----01--0 +1010000111 00-1------ +1010001000 00-11-101- +1010001001 1-0---1--1 +1010001010 ----1--1-- +1010001011 -1--0----- +1010001100 --0----1-- +1010001101 ---0--00-- +1010001110 -----1---0 +1010001111 ----0-0--- +1010010000 ---0--0--1 +1010010001 ---1----10 +1010010010 --0------- +1010010011 1-01--0--0 +1010010100 --0-1----- +1010010101 ----1----- +1010010110 ---0-10--- +1010010111 110-10---1 +1010011000 -1--1---0- +1010011001 10----0-1- +1010011010 ---------- +1010011011 1--00--01- +1010011100 -1-1-000-- +1010011101 -01-0--0-- +1010011110 ----01--11 +1010011111 ---1-0-0-- +1010100000 --01---1-1 +1010100001 -----001-- +1010100010 0---1----- +1010100011 0----1-010 +1010100100 ----1-1--- +1010100101 -110-0--1- +1010100110 ---1------ +1010100111 1--111---0 +1010101000 --11-----0 +1010101001 0--------0 +1010101010 01-0-0--1- +1010101011 ---------- +1010101100 1-01------ +1010101101 1---00---- +1010101110 --10----0- +1010101111 1--1------ +1010110000 11001--0-1 +1010110001 11---0-011 +1010110010 1-0------0 +1010110011 -1-0-0-0-0 +1010110100 1--------- +1010110101 --0------- +1010110110 11-1------ +1010110111 -0--1--1-- +1010111000 ---------1 +1010111001 -11---011- +1010111010 --------11 +1010111011 001-0-0-00 +1010111100 1-1---01-- +1010111101 --0---1--- +1010111110 11-----10- +1010111111 -1--01--10 +1011000000 1--1-11--- +1011000001 ------01-- +1011000010 ---0-1-1-- +1011000011 -----1--0- +1011000100 ---1---01- +1011000101 0----00-10 +1011000110 ---------- +1011000111 ---0001--0 +1011001000 00--1-100- +1011001001 ---10-10-- +1011001010 -----1---- +1011001011 00-1---0-- +1011001100 -----10-1- +1011001101 0-10-0---0 +1011001110 --1-1---11 +1011001111 -----1--0- +1011010000 ----0----- +1011010001 -------0-- +1011010010 --0-----11 +1011010011 ----1-1--- +1011010100 1--0--00-1 +1011010101 --00---01- +1011010110 -0---01--- +1011010111 0----10-11 +1011011000 -1-------0 +1011011001 -----11--- +1011011010 -1------0- +1011011011 0---1----- +1011011100 -0-----0-0 +1011011101 0--01-0-11 +1011011110 11-0----10 +1011011111 ------10-- +1011100000 ----0-00-- +1011100001 ------1--- +1011100010 10-1--0--0 +1011100011 ---1-00--- +1011100100 -0--0---1- +1011100101 ---1---1-- +1011100110 ---1-1---- +1011100111 1-1--1---- +1011101000 --1---0--- +1011101001 -0-1----1- +1011101010 ---0-1--0- +1011101011 0--------0 +1011101100 -1---1---- +1011101101 00----0--- +1011101110 10-----000 +1011101111 -1---0--0- +1011110000 --00---1-- +1011110001 ----0---10 +1011110010 10--1---1- +1011110011 -01----001 +1011110100 0----0--10 +1011110101 1------1-0 +1011110110 -1----0--- +1011110111 -11---0--1 +1011111000 -0----0--- +1011111001 -10-1----- +1011111010 --------0- +1011111011 10-11-1--- +1011111100 -1--1101-0 +1011111101 -0----1101 +1011111110 --1---0--- +1011111111 ---0----1- +1100000000 --0-0---0- +1100000001 --0---00-- +1100000010 0-----010- +1100000011 --0----1-- +1100000100 -0-0-0-0-- +1100000101 --10---0-- +1100000110 ---0----10 +1100000111 00--1----- +1100001000 1--0-0--10 +1100001001 -----0---1 +1100001010 1---11-0-1 +1100001011 ---001---0 +1100001100 1-1------0 +1100001101 ---------- +1100001110 ---01----1 +1100001111 ---1--1--1 +1100010000 ------0--1 +1100010001 -10-00---- +1100010010 1--------1 +1100010011 -0----0--- +1100010100 ----1----- +1100010101 -01--0---- +1100010110 ---000-1-- +1100010111 --001--111 +1100011000 0-----1--- +1100011001 -----01-1- +1100011010 ---------- +1100011011 -----0---1 +1100011100 1-0-1-01-- +1100011101 --------0- +1100011110 0---0--0-- +1100011111 -0-------- +1100100000 --1------1 +1100100001 ---00-10-- +1100100010 --0--1-1-- +1100100011 -00----1-- +1100100100 10----0--0 +1100100101 -0-0---0-- +1100100110 -------0-0 +1100100111 1--0--1000 +1100101000 -100-110-- +1100101001 -01------0 +1100101010 -----11-10 +1100101011 -----0---- +1100101100 1---1----- +1100101101 --------1- +1100101110 ----1-0--1 +1100101111 ---------1 +1100110000 -------0-- +1100110001 -1-11--0-- +1100110010 0-0--0---- +1100110011 ------0--- +1100110100 ---1------ +1100110101 ------1-1- +1100110110 --0110---0 +1100110111 1-1------- +1100111000 ---1--1-0- +1100111001 ---0------ +1100111010 ---1----01 +1100111011 --0-----0- +1100111100 ---0---1-1 +1100111101 1-1--0---- +1100111110 -1-------- +1100111111 -----1-0-1 +1101000000 -0---00--- +1101000001 --01----0- +1101000010 ---00----- +1101000011 010--0---- +1101000100 -------11- +1101000101 --0-----11 +1101000110 ---1----0- +1101000111 -11-10---- +1101001000 ---------- +1101001001 -0-0-1---- +1101001010 0---0-0-1- +1101001011 --1-1----- +1101001100 -010-0---- +1101001101 01-------0 +1101001110 ---------- +1101001111 10----1--0 +1101010000 ------11-- +1101010001 ---11--01- +1101010010 --11---00- +1101010011 0-0-1--1-0 +1101010100 --1------- +1101010101 --1------- +1101010110 ---01----- +1101010111 --1-----11 +1101011000 -1--10---- +1101011001 -001-01--- +1101011010 -1------0- +1101011011 -1---11--- +1101011100 0----1---- +1101011101 00111--0-0 +1101011110 1-01--0001 +1101011111 -------1-1 +1101100000 1--1--0--- +1101100001 -----10--1 +1101100010 ----0----- +1101100011 -1-1---0-- +1101100100 --------1- +1101100101 ---------0 +1101100110 0---1----0 +1101100111 0--1--001- +1101101000 ---0-1---- +1101101001 -------1-- +1101101010 0---1----- +1101101011 1----10-0- +1101101100 --------01 +1101101101 1-110-11-- +1101101110 -----11--1 +1101101111 ------11-- +1101110000 -1-1------ +1101110001 ---------0 +1101110010 1----11--- +1101110011 -----0---- +1101110100 ---1--1-1- +1101110101 1-0--0---0 +1101110110 --0-----1- +1101110111 -----1--0- +1101111000 -0---1-0-- +1101111001 ---00----- +1101111010 ---0------ +1101111011 -0---1---- +1101111100 ---01----- +1101111101 1--0-0---- +1101111110 1001--0-0- +1101111111 -----1-0-- +1110000000 -10---0-0- +1110000001 --1-10-00- +1110000010 1---0-01-- +1110000011 --1-0-1-0- +1110000100 ---10-0-10 +1110000101 --0------- +1110000110 -1-1---0-- +1110000111 0-011---1- +1110001000 00----1--- +1110001001 -11-----0- +1110001010 01-01--0-- +1110001011 ---0--01-- +1110001100 --101----- +1110001101 --111----- +1110001110 ----0---1- +1110001111 ----0-1-1- +1110010000 ---------- +1110010001 -0-------0 +1110010010 ----1-0--- +1110010011 -11111---1 +1110010100 ---1------ +1110010101 ----00---- +1110010110 1010--1--- +1110010111 -00-11-00- +1110011000 ---0-10--- +1110011001 -00------- +1110011010 --00100--1 +1110011011 ---1------ +1110011100 0--------- +1110011101 -11----0-1 +1110011110 011----11- +1110011111 ---0----11 +1110100000 --1111---1 +1110100001 ----1---1- +1110100010 -0--1-0--- +1110100011 1-101---0- +1110100100 0----1---- +1110100101 -----0-0-1 +1110100110 -------1-- +1110100111 --1-1-0--- +1110101000 1----1--11 +1110101001 -0----0--- +1110101010 --1-0-10-- +1110101011 -----1---- +1110101100 -0-0--0--0 +1110101101 -1-10-0--- +1110101110 -------0-- +1110101111 0--1----01 +1110110000 0-0--11--1 +1110110001 -1---0---- +1110110010 --0-1--10- +1110110011 ---------1 +1110110100 0--00-0--- +1110110101 ------0--- +1110110110 0------0-- +1110110111 11----1--- +1110111000 --1--0---- +1110111001 -0-0-1---- +1110111010 -----0-1-- +1110111011 ----1----- +1110111100 1-----01-0 +1110111101 ----0--101 +1110111110 --1------- +1110111111 --11------ +1111000000 0-1-010--- +1111000001 -1--1---1- +1111000010 -0-1-1---- +1111000011 0-1--00--- +1111000100 1--1-11--1 +1111000101 ---0-00-1- +1111000110 --1--0-1-- +1111000111 ---------1 +1111001000 ----1----- +1111001001 --0------- +1111001010 -----0---- +1111001011 ------0-1- +1111001100 1-----0--0 +1111001101 ---1-1--11 +1111001110 ----0-0--- +1111001111 --11-00--- +1111010000 --0---10-- +1111010001 ----1----1 +1111010010 ----1-1-0- +1111010011 ---------- +1111010100 -0----101- +1111010101 --0------1 +1111010110 0-00----0- +1111010111 --00-1-0-- +1111011000 --10-10--- +1111011001 111-----0- +1111011010 -10--0-0-- +1111011011 -1--0-1-1- +1111011100 1----0---- +1111011101 ---1------ +1111011110 --111-1--- +1111011111 ----01-0-- +1111100000 --11--0--- +1111100001 --100----- +1111100010 ----11---1 +1111100011 -11----1-1 +1111100100 -------1-- +1111100101 1---1---0- +1111100110 ---1------ +1111100111 -0-0---01- +1111101000 ----0-1-00 +1111101001 --0-0--0-- +1111101010 --0------- +1111101011 0--0-----0 +1111101100 1-1--0-0-0 +1111101101 -----10--- +1111101110 ----0---0- +1111101111 0----0---- +1111110000 1-----0--- +1111110001 101----00- +1111110010 -0--1----1 +1111110011 01----0-1- +1111110100 -1--00---- +1111110101 ----0----- +1111110110 --------1- +1111110111 1--1011--- +1111111000 -0----1-10 +1111111001 ----01--0- +1111111010 -----0--11 +1111111011 ----011--- +1111111100 1--0--1--- +1111111101 ---1---11- +1111111110 ----0100-- +1111111111 --10-000-1 diff --git a/espresso/examples/random/exam b/espresso/examples/random/exam new file mode 100644 index 0000000..94a4bb2 --- /dev/null +++ b/espresso/examples/random/exam @@ -0,0 +1,1026 @@ +.i 10 +.o 10 +0000000000 1----1-0-- +0000000001 --1-----00 +0000000010 ------1--0 +0000000011 ---1------ +0000000100 -----1---1 +0000000101 -1---0---- +0000000110 ---------- +0000000111 ---------- +0000001000 ---------- +0000001001 ---------- +0000001010 ---------- +0000001011 ---------- +0000001100 ---------- +0000001101 ---------- +0000001110 ---------- +0000001111 ---------- +0000010000 ---------- +0000010001 ---------- +0000010010 ---------- +0000010011 ---------- +0000010100 ---------- +0000010101 ---------- +0000010110 -11--100-- +0000010111 -----0-000 +0000011000 ------0-0- +0000011001 ---1-----0 +0000011010 --00------ +0000011011 --100----1 +0000011100 ----1----0 +0000011101 0--0------ +0000011110 ------1--1 +0000011111 01-----0-- +0000100000 1----1-0-- +0000100001 --1-----00 +0000100010 ------1--0 +0000100011 ---1------ +0000100100 -----1---1 +0000100101 -1---0---- +0000100110 ---------- +0000100111 ---------- +0000101000 ---------- +0000101001 ---------- +0000101010 ---------- +0000101011 ---------- +0000101100 ---------- +0000101101 ---------- +0000101110 ---------- +0000101111 ---------- +0000110000 ---------- +0000110001 ---------- +0000110010 ---------- +0000110011 ---------- +0000110100 ---------- +0000110101 ---------- +0000110110 -11--100-- +0000110111 -----0-000 +0000111000 ------0-0- +0000111001 ---1-----0 +0000111010 --00------ +0000111011 --100----1 +0000111100 ----1----0 +0000111101 0--0------ +0000111110 ------1--1 +0000111111 01-----0-- +0001000000 1----1-0-- +0001000001 --1-----00 +0001000010 ------1--0 +0001000011 ---1------ +0001000100 -----1---1 +0001000101 -1---0---- +0001000110 ---------- +0001000111 ---------- +0001001000 ---------- +0001001001 ---------- +0001001010 ---------- +0001001011 ---------- +0001001100 ---------- +0001001101 ---------- +0001001110 ---------- +0001001111 ---------- +0001010000 ---------- +0001010001 ---------- +0001010010 ---------- +0001010011 ---------- +0001010100 ---------- +0001010101 ---------- +0001010110 -11--100-- +0001010111 -----0-000 +0001011000 ------0-0- +0001011001 ---1-----0 +0001011010 --00------ +0001011011 --100----1 +0001011100 ----1----0 +0001011101 0--0------ +0001011110 ------1--1 +0001011111 01-----0-- +0001100000 1----1-0-- +0001100001 --1-----00 +0001100010 ------1--0 +0001100011 ---1------ +0001100100 -----1---1 +0001100101 -1---0---- +0001100110 ---------- +0001100111 ---------- +0001101000 ---------- +0001101001 ---------- +0001101010 ---------- +0001101011 ---------- +0001101100 ---------- +0001101101 ---------- +0001101110 ---------- +0001101111 ---------- +0001110000 ---------- +0001110001 ---------- +0001110010 ---------- +0001110011 ---------- +0001110100 ---------- +0001110101 ---------- +0001110110 -11--100-- +0001110111 -----0-000 +0001111000 ------0-0- +0001111001 ---1-----0 +0001111010 --00------ +0001111011 --100----1 +0001111100 ----1----0 +0001111101 0--0------ +0001111110 ------1--1 +0001111111 01-----0-- +0010000000 1----1-0-- +0010000001 --1-----00 +0010000010 ------1--0 +0010000011 ---1------ +0010000100 -----1---1 +0010000101 -1---0---- +0010000110 ---------- +0010000111 ---------- +0010001000 ---------- +0010001001 ---------- +0010001010 ---------- +0010001011 ---------- +0010001100 ---------- +0010001101 ---------- +0010001110 ---------- +0010001111 ---------- +0010010000 ---------- +0010010001 ---------- +0010010010 ---------- +0010010011 ---------- +0010010100 ---------- +0010010101 ---------- +0010010110 -1--1--0-- +0010010111 1------1-- +0010011000 ----0----1 +0010011001 -----1-0-1 +0010011010 -11--100-- +0010011011 -----0-000 +0010011100 ------0-0- +0010011101 ---1-----0 +0010011110 --00------ +0010011111 --100----1 +0010100000 ----1----0 +0010100001 0--0------ +0010100010 ------1--1 +0010100011 01-----0-- +0010100100 1----1-0-- +0010100101 --1-----00 +0010100110 ------1--0 +0010100111 ---1------ +0010101000 -----1---1 +0010101001 -1---0---- +0010101010 ---------- +0010101011 ---------- +0010101100 ---------- +0010101101 ---------- +0010101110 ---------- +0010101111 ---------- +0010110000 ---------- +0010110001 ---------- +0010110010 ---------- +0010110011 ---------- +0010110100 ---------- +0010110101 ---------- +0010110110 ---------- +0010110111 ---------- +0010111000 ---------- +0010111001 ---------- +0010111010 -1--1--0-- +0010111011 1------1-- +0010111100 ----0----1 +0010111101 -----1-0-1 +0010111110 -11--100-- +0010111111 -----0-000 +0011000000 ------0-0- +0011000001 ---1-----0 +0011000010 --00------ +0011000011 --100----1 +0011000100 ----1----0 +0011000101 0--0------ +0011000110 ------1--1 +0011000111 01-----0-- +0011001000 1----1-0-- +0011001001 --1-----00 +0011001010 ------1--0 +0011001011 ---1------ +0011001100 -----1---1 +0011001101 -1---0---- +0011001110 ---------- +0011001111 ---------- +0011010000 ---------- +0011010001 ---------- +0011010010 ---------- +0011010011 ---------- +0011010100 ---------- +0011010101 ---------- +0011010110 ---------- +0011010111 ---------- +0011011000 ---------- +0011011001 ---------- +0011011010 ---------- +0011011011 ---------- +0011011100 ---------- +0011011101 ---------- +0011011110 -1--1--0-- +0011011111 1------1-- +0011100000 ----0----1 +0011100001 -----1-0-1 +0011100010 -11--100-- +0011100011 -----0-000 +0011100100 ------0-0- +0011100101 ---1-----0 +0011100110 --00------ +0011100111 --100----1 +0011101000 ----1----0 +0011101001 0--0------ +0011101010 ------1--1 +0011101011 01-----0-- +0011101100 1----1-0-- +0011101101 --1-----00 +0011101110 ------1--0 +0011101111 ---1------ +0011110000 -----1---1 +0011110001 -1---0---- +0011110010 ---------- +0011110011 ---------- +0011110100 ---------- +0011110101 ---------- +0011110110 ---------- +0011110111 ---------- +0011111000 ---------- +0011111001 ---------- +0011111010 ---------- +0011111011 ---------- +0011111100 ---------- +0011111101 ---------- +0011111110 ---------- +0011111111 ---------- +0100000000 ---------- +0100000001 ---------- +0100000010 -1--1--0-- +0100000011 1------1-- +0100000100 ----0----1 +0100000101 -----1-0-1 +0100000110 -11--100-- +0100000111 -----0-000 +0100001000 ------0-0- +0100001001 ---1-----0 +0100001010 --00------ +0100001011 --100----1 +0100001100 ----1----0 +0100001101 0--0------ +0100001110 ------1--1 +0100001111 01-----0-- +0100010000 1----1-0-- +0100010001 --1-----00 +0100010010 ------1--0 +0100010011 ---1------ +0100010100 -----1---1 +0100010101 -1---0---- +0100010110 ---------- +0100010111 ---------- +0100011000 ---------- +0100011001 ---------- +0100011010 ---------- +0100011011 ---------- +0100011100 ---------- +0100011101 ---------- +0100011110 ---------- +0100011111 ---------- +0100100000 ---------- +0100100001 ---------- +0100100010 ---------- +0100100011 ---------- +0100100100 ---------- +0100100101 ---------- +0100100110 -1--1--0-- +0100100111 1------1-- +0100101000 ----0----1 +0100101001 -----1-0-1 +0100101010 -11--100-- +0100101011 -----0-000 +0100101100 ------0-0- +0100101101 ---1-----0 +0100101110 --00------ +0100101111 --100----1 +0100110000 ----1----0 +0100110001 0--0------ +0100110010 ------1--1 +0100110011 01-----0-- +0100110100 1----1-0-- +0100110101 --1-----00 +0100110110 ------1--0 +0100110111 ---1------ +0100111000 -----1---1 +0100111001 -1---0---- +0100111010 ---------- +0100111011 ---------- +0100111100 ---------- +0100111101 ---------- +0100111110 ---------- +0100111111 ---------- +0101000000 ---------- +0101000001 ---------- +0101000010 ---------- +0101000011 ---------- +0101000100 ---------- +0101000101 ---------- +0101000110 ---------- +0101000111 ---------- +0101001000 ---------- +0101001001 ---------- +0101001010 -1--1--0-- +0101001011 1------1-- +0101001100 ----0----1 +0101001101 -----1-0-1 +0101001110 -11--100-- +0101001111 -----0-000 +0101010000 ------0-0- +0101010001 ---1-----0 +0101010010 --00------ +0101010011 --100----1 +0101010100 ----1----0 +0101010101 0--0------ +0101010110 ------1--1 +0101010111 01-----0-- +0101011000 1----1-0-- +0101011001 --1-----00 +0101011010 ------1--0 +0101011011 ---1------ +0101011100 -----1---1 +0101011101 -1---0---- +0101011110 ---------- +0101011111 ---------- +0101100000 ---------- +0101100001 ---------- +0101100010 ---------- +0101100011 ---------- +0101100100 ---------- +0101100101 ---------- +0101100110 ---------- +0101100111 ---------- +0101101000 ---------- +0101101001 ---------- +0101101010 ---------- +0101101011 ---------- +0101101100 ---------- +0101101101 ---------- +0101101110 -1--1--0-- +0101101111 1------1-- +0101110000 ----0----1 +0101110001 -----1-0-1 +0101110010 -11--100-- +0101110011 -----0-000 +0101110100 ------0-0- +0101110101 ---1-----0 +0101110110 --00------ +0101110111 --100----1 +0101111000 ----1----0 +0101111001 0--0------ +0101111010 ------1--1 +0101111011 01-----0-- +0101111100 1----1-0-- +0101111101 --1-----00 +0101111110 ------1--0 +0101111111 ---1------ +0110000000 -----1---1 +0110000001 -1---0---- +0110000010 ---------- +0110000011 ---------- +0110000100 ---------- +0110000101 ---------- +0110000110 ---------- +0110000111 ---------- +0110001000 ---------- +0110001001 ---------- +0110001010 ---------- +0110001011 ---------- +0110001100 ---------- +0110001101 ---------- +0110001110 ---------- +0110001111 ---------- +0110010000 ---------- +0110010001 ---------- +0110010010 -1--1--0-- +0110010011 1------1-- +0110010100 ----0----1 +0110010101 -----1-0-1 +0110010110 -11--100-- +0110010111 -----0-000 +0110011000 ------0-0- +0110011001 ---1-----0 +0110011010 --00------ +0110011011 --100----1 +0110011100 ----1----0 +0110011101 0--0------ +0110011110 ------1--1 +0110011111 01-----0-- +0110100000 1----1-0-- +0110100001 --1-----00 +0110100010 ------1--0 +0110100011 ---1------ +0110100100 -----1---1 +0110100101 -1---0---- +0110100110 ---------- +0110100111 ---------- +0110101000 ---------- +0110101001 ---------- +0110101010 ---------- +0110101011 ---------- +0110101100 ---------- +0110101101 ---------- +0110101110 ---------- +0110101111 ---------- +0110110000 ---------- +0110110001 ---------- +0110110010 ---------- +0110110011 ---------- +0110110100 ---------- +0110110101 ---------- +0110110110 -1--1--0-- +0110110111 1------1-- +0110111000 ----0----1 +0110111001 -----1-0-1 +0110111010 -11--100-- +0110111011 -----0-000 +0110111100 ------0-0- +0110111101 ---1-----0 +0110111110 --00------ +0110111111 --100----1 +0111000000 ----1----0 +0111000001 0--0------ +0111000010 ------1--1 +0111000011 01-----0-- +0111000100 1----1-0-- +0111000101 --1-----00 +0111000110 ------1--0 +0111000111 ---1------ +0111001000 -----1---1 +0111001001 -1---0---- +0111001010 ---------- +0111001011 ---------- +0111001100 ---------- +0111001101 ---------- +0111001110 ---------- +0111001111 ---------- +0111010000 ---------- +0111010001 ---------- +0111010010 ---------- +0111010011 ---------- +0111010100 ---------- +0111010101 ---------- +0111010110 ---------- +0111010111 ---------- +0111011000 ---------- +0111011001 ---------- +0111011010 -1--1--0-- +0111011011 1------1-- +0111011100 ----0----1 +0111011101 -----1-0-1 +0111011110 -11--100-- +0111011111 -----0-000 +0111100000 ------0-0- +0111100001 ---1-----0 +0111100010 --00------ +0111100011 --100----1 +0111100100 ----1----0 +0111100101 0--0------ +0111100110 ------1--1 +0111100111 01-----0-- +0111101000 1----1-0-- +0111101001 --1-----00 +0111101010 ------1--0 +0111101011 ---1------ +0111101100 -----1---1 +0111101101 -1---0---- +0111101110 ---------- +0111101111 ---------- +0111110000 ---------- +0111110001 ---------- +0111110010 ---------- +0111110011 ---------- +0111110100 ---------- +0111110101 ---------- +0111110110 ---------- +0111110111 ---------- +0111111000 ---------- +0111111001 ---------- +0111111010 ---------- +0111111011 ---------- +0111111100 ---------- +0111111101 ---------- +0111111110 -11--100-- +0111111111 -----0-000 +1000000000 ------0-0- +1000000001 ---1-----0 +1000000010 --00------ +1000000011 --100----1 +1000000100 ----1----0 +1000000101 0--0------ +1000000110 ------1--1 +1000000111 01-----0-- +1000001000 1----1-0-- +1000001001 --1-----00 +1000001010 ------1--0 +1000001011 ---1------ +1000001100 -----1---1 +1000001101 -1---0---- +1000001110 ---------- +1000001111 ---------- +1000010000 ---------- +1000010001 ---------- +1000010010 ---------- +1000010011 ---------- +1000010100 ---------- +1000010101 ---------- +1000010110 ---------- +1000010111 ---------- +1000011000 ---------- +1000011001 ---------- +1000011010 ---------- +1000011011 ---------- +1000011100 ---------- +1000011101 ---------- +1000011110 -11--100-- +1000011111 -----0-000 +1000100000 ------0-0- +1000100001 ---1-----0 +1000100010 --00------ +1000100011 --100----1 +1000100100 ----1----0 +1000100101 0--0------ +1000100110 ------1--1 +1000100111 01-----0-- +1000101000 1----1-0-- +1000101001 --1-----00 +1000101010 ------1--0 +1000101011 ---1------ +1000101100 -----1---1 +1000101101 -1---0---- +1000101110 ---------- +1000101111 ---------- +1000110000 ---------- +1000110001 ---------- +1000110010 ---------- +1000110011 ---------- +1000110100 ---------- +1000110101 ---------- +1000110110 ---------- +1000110111 ---------- +1000111000 ---------- +1000111001 ---------- +1000111010 ---------- +1000111011 ---------- +1000111100 ---------- +1000111101 ---------- +1000111110 -11--100-- +1000111111 -----0-000 +1001000000 ------0-0- +1001000001 ---1-----0 +1001000010 --00------ +1001000011 --100----1 +1001000100 ----1----0 +1001000101 0--0------ +1001000110 ------1--1 +1001000111 01-----0-- +1001001000 1----1-0-- +1001001001 --1-----00 +1001001010 ------1--0 +1001001011 ---1------ +1001001100 -----1---1 +1001001101 -1---0---- +1001001110 ---------- +1001001111 ---------- +1001010000 ---------- +1001010001 ---------- +1001010010 ---------- +1001010011 ---------- +1001010100 ---------- +1001010101 ---------- +1001010110 ---------- +1001010111 ---------- +1001011000 ---------- +1001011001 ---------- +1001011010 ---------- +1001011011 ---------- +1001011100 ---------- +1001011101 ---------- +1001011110 -11--100-- +1001011111 -----0-000 +1001100000 ------0-0- +1001100001 ---1-----0 +1001100010 --00------ +1001100011 --100----1 +1001100100 ----1----0 +1001100101 0--0------ +1001100110 ------1--1 +1001100111 01-----0-- +1001101000 1----1-0-- +1001101001 --1-----00 +1001101010 ------1--0 +1001101011 ---1------ +1001101100 -----1---1 +1001101101 -1---0---- +1001101110 ---------- +1001101111 ---------- +1001110000 ---------- +1001110001 ---------- +1001110010 ---------- +1001110011 ---------- +1001110100 ---------- +1001110101 ---------- +1001110110 ---------- +1001110111 ---------- +1001111000 ---------- +1001111001 ---------- +1001111010 ---------- +1001111011 ---------- +1001111100 ---------- +1001111101 ---------- +1001111110 -11--100-- +1001111111 -----0-000 +1010000000 ------0-0- +1010000001 ---1-----0 +1010000010 --00------ +1010000011 --100----1 +1010000100 ----1----0 +1010000101 0--0------ +1010000110 ------1--1 +1010000111 01-----0-- +1010001000 1----1-0-- +1010001001 --1-----00 +1010001010 ------1--0 +1010001011 ---1------ +1010001100 -----1---1 +1010001101 -1---0---- +1010001110 ---------- +1010001111 ---------- +1010010000 ---------- +1010010001 ---------- +1010010010 ---------- +1010010011 ---------- +1010010100 ---------- +1010010101 ---------- +1010010110 ---------- +1010010111 ---------- +1010011000 ---------- +1010011001 ---------- +1010011010 ---------- +1010011011 ---------- +1010011100 ---------- +1010011101 ---------- +1010011110 -1--1--0-- +1010011111 1------1-- +1010100000 ----0----1 +1010100001 -----1-0-1 +1010100010 -11--100-- +1010100011 -----0-000 +1010100100 ------0-0- +1010100101 ---1-----0 +1010100110 --00------ +1010100111 --100----1 +1010101000 ----1----0 +1010101001 0--0------ +1010101010 ------1--1 +1010101011 01-----0-- +1010101100 1----1-0-- +1010101101 --1-----00 +1010101110 ------1--0 +1010101111 ---1------ +1010110000 -----1---1 +1010110001 -1---0---- +1010110010 ---------- +1010110011 ---------- +1010110100 ---------- +1010110101 ---------- +1010110110 ---------- +1010110111 ---------- +1010111000 ---------- +1010111001 ---------- +1010111010 ---------- +1010111011 ---------- +1010111100 ---------- +1010111101 ---------- +1010111110 ---------- +1010111111 ---------- +1011000000 ---------- +1011000001 ---------- +1011000010 -11--100-- +1011000011 -----0-000 +1011000100 ------0-0- +1011000101 ---1-----0 +1011000110 --00------ +1011000111 --100----1 +1011001000 ----1----0 +1011001001 0--0------ +1011001010 ------1--1 +1011001011 01-----0-- +1011001100 1----1-0-- +1011001101 --1-----00 +1011001110 ------1--0 +1011001111 ---1------ +1011010000 -----1---1 +1011010001 -1---0---- +1011010010 ---------- +1011010011 ---------- +1011010100 ---------- +1011010101 ---------- +1011010110 ---------- +1011010111 ---------- +1011011000 ---------- +1011011001 ---------- +1011011010 ---------- +1011011011 ---------- +1011011100 ---------- +1011011101 ---------- +1011011110 ---------- +1011011111 ---------- +1011100000 ---------- +1011100001 ---------- +1011100010 -11--100-- +1011100011 -----0-000 +1011100100 ------0-0- +1011100101 ---1-----0 +1011100110 --00------ +1011100111 --100----1 +1011101000 ----1----0 +1011101001 0--0------ +1011101010 ------1--1 +1011101011 01-----0-- +1011101100 1----1-0-- +1011101101 --1-----00 +1011101110 ------1--0 +1011101111 ---1------ +1011110000 -----1---1 +1011110001 -1---0---- +1011110010 ---------- +1011110011 ---------- +1011110100 ---------- +1011110101 ---------- +1011110110 ---------- +1011110111 ---------- +1011111000 ---------- +1011111001 ---------- +1011111010 ---------- +1011111011 ---------- +1011111100 ---------- +1011111101 ---------- +1011111110 ---------- +1011111111 ---------- +1100000000 ---------- +1100000001 ---------- +1100000010 -11--100-- +1100000011 -----0-000 +1100000100 ------0-0- +1100000101 ---1-----0 +1100000110 --00------ +1100000111 --100----1 +1100001000 ----1----0 +1100001001 0--0------ +1100001010 ------1--1 +1100001011 01-----0-- +1100001100 1----1-0-- +1100001101 --1-----00 +1100001110 ------1--0 +1100001111 ---1------ +1100010000 -----1---1 +1100010001 -1---0---- +1100010010 ---------- +1100010011 ---------- +1100010100 ---------- +1100010101 ---------- +1100010110 ---------- +1100010111 ---------- +1100011000 ---------- +1100011001 ---------- +1100011010 ---------- +1100011011 ---------- +1100011100 ---------- +1100011101 ---------- +1100011110 ---------- +1100011111 ---------- +1100100000 ---------- +1100100001 ---------- +1100100010 -11--100-- +1100100011 -----0-000 +1100100100 ------0-0- +1100100101 ---1-----0 +1100100110 --00------ +1100100111 --100----1 +1100101000 ----1----0 +1100101001 0--0------ +1100101010 ------1--1 +1100101011 01-----0-- +1100101100 1----1-0-- +1100101101 --1-----00 +1100101110 ------1--0 +1100101111 ---1------ +1100110000 -----1---1 +1100110001 -1---0---- +1100110010 ---------- +1100110011 ---------- +1100110100 ---------- +1100110101 ---------- +1100110110 ---------- +1100110111 ---------- +1100111000 ---------- +1100111001 ---------- +1100111010 ---------- +1100111011 ---------- +1100111100 ---------- +1100111101 ---------- +1100111110 ---------- +1100111111 ---------- +1101000000 ---------- +1101000001 ---------- +1101000010 -11--100-- +1101000011 -----0-000 +1101000100 ------0-0- +1101000101 ---1-----0 +1101000110 --00------ +1101000111 --100----1 +1101001000 ----1----0 +1101001001 0--0------ +1101001010 ------1--1 +1101001011 01-----0-- +1101001100 1----1-0-- +1101001101 --1-----00 +1101001110 ------1--0 +1101001111 ---1------ +1101010000 -----1---1 +1101010001 -1---0---- +1101010010 ---------- +1101010011 ---------- +1101010100 ---------- +1101010101 ---------- +1101010110 ---------- +1101010111 ---------- +1101011000 ---------- +1101011001 ---------- +1101011010 ---------- +1101011011 ---------- +1101011100 ---------- +1101011101 ---------- +1101011110 ---------- +1101011111 ---------- +1101100000 ---------- +1101100001 ---------- +1101100010 -11--100-- +1101100011 -----0-000 +1101100100 ------0-0- +1101100101 ---1-----0 +1101100110 --00------ +1101100111 --100----1 +1101101000 ----1----0 +1101101001 0--0------ +1101101010 ------1--1 +1101101011 01-----0-- +1101101100 1----1-0-- +1101101101 --1-----00 +1101101110 ------1--0 +1101101111 ---1------ +1101110000 -----1---1 +1101110001 -1---0---- +1101110010 ---------- +1101110011 ---------- +1101110100 ---------- +1101110101 ---------- +1101110110 ---------- +1101110111 ---------- +1101111000 ---------- +1101111001 ---------- +1101111010 ---------- +1101111011 ---------- +1101111100 ---------- +1101111101 ---------- +1101111110 ---------- +1101111111 ---------- +1110000000 ---------- +1110000001 ---------- +1110000010 -11--100-- +1110000011 -----0-000 +1110000100 ------0-0- +1110000101 ---1-----0 +1110000110 --00------ +1110000111 --100----1 +1110001000 ----1----0 +1110001001 0--0------ +1110001010 ------1--1 +1110001011 01-----0-- +1110001100 1----1-0-- +1110001101 --1-----00 +1110001110 ------1--0 +1110001111 ---1------ +1110010000 -----1---1 +1110010001 -1---0---- +1110010010 ---------- +1110010011 ---------- +1110010100 ---------- +1110010101 ---------- +1110010110 ---------- +1110010111 ---------- +1110011000 ---------- +1110011001 ---------- +1110011010 ---------- +1110011011 ---------- +1110011100 ---------- +1110011101 ---------- +1110011110 ---------- +1110011111 ---------- +1110100000 ---------- +1110100001 ---------- +1110100010 -11--100-- +1110100011 -----0-000 +1110100100 ------0-0- +1110100101 ---1-----0 +1110100110 --00------ +1110100111 --100----1 +1110101000 ----1----0 +1110101001 0--0------ +1110101010 ------1--1 +1110101011 01-----0-- +1110101100 1----1-0-- +1110101101 --1-----00 +1110101110 ------1--0 +1110101111 ---1------ +1110110000 -----1---1 +1110110001 -1---0---- +1110110010 ---------- +1110110011 ---------- +1110110100 ---------- +1110110101 ---------- +1110110110 ---------- +1110110111 ---------- +1110111000 ---------- +1110111001 ---------- +1110111010 ---------- +1110111011 ---------- +1110111100 ---------- +1110111101 ---------- +1110111110 ---------- +1110111111 ---------- +1111000000 ---------- +1111000001 ---------- +1111000010 -11--100-- +1111000011 -----0-000 +1111000100 ------0-0- +1111000101 ---1-----0 +1111000110 --00------ +1111000111 --100----1 +1111001000 ----1----0 +1111001001 0--0------ +1111001010 ------1--1 +1111001011 01-----0-- +1111001100 1----1-0-- +1111001101 --1-----00 +1111001110 ------1--0 +1111001111 ---1------ +1111010000 -----1---1 +1111010001 -1---0---- +1111010010 ---------- +1111010011 ---------- +1111010100 ---------- +1111010101 ---------- +1111010110 ---------- +1111010111 ---------- +1111011000 ---------- +1111011001 ---------- +1111011010 ---------- +1111011011 ---------- +1111011100 ---------- +1111011101 ---------- +1111011110 ---------- +1111011111 ---------- +1111100000 ---------- +1111100001 ---------- +1111100010 -11--100-- +1111100011 -----0-000 +1111100100 ------0-0- +1111100101 ---1-----0 +1111100110 --00------ +1111100111 --100----1 +1111101000 ----1----0 +1111101001 0--0------ +1111101010 ------1--1 +1111101011 01-----0-- +1111101100 1----1-0-- +1111101101 --1-----00 +1111101110 ------1--0 +1111101111 ---1------ +1111110000 -----1---1 +1111110001 -1---0---- +1111110010 ---------- +1111110011 ---------- +1111110100 ---------- +1111110101 ---------- +1111110110 ---------- +1111110111 ---------- +1111111000 ---------- +1111111001 ---------- +1111111010 ---------- +1111111011 ---------- +1111111100 ---------- +1111111101 ---------- +1111111110 ---------- +1111111111 ---------- diff --git a/espresso/examples/random/fout b/espresso/examples/random/fout new file mode 100644 index 0000000..dcdfcc4 --- /dev/null +++ b/espresso/examples/random/fout @@ -0,0 +1,66 @@ +.i 6 +.o 10 +000000 ----001-01 +100000 --1---01-- +010000 -00--010-1 +110000 ---00--01- +001000 -0---1-1-0 +101000 000-010-11 +011000 -01100111- +111000 -0--0-0--0 +000100 01-00---1- +100100 100001--1- +010100 00--01-101 +110100 --011--1-- +001100 11-1-1-0-1 +101100 -1-01--01- +011100 --01011110 +111100 01-0011--- +000010 0-01-001-- +100010 -000-0--0- +010010 11-0-00010 +110010 00111-1011 +001010 1-01-1--01 +101010 -1--1--0-0 +011010 --0--01-0- +111010 -1-1-10-00 +000110 001-0-000- +100110 11100-0--0 +010110 --0--1-100 +110110 1---0-0-00 +001110 --1-01101- +101110 00110--10- +011110 1100-0-101 +111110 1-10-10001 +000001 -1-1111--1 +100001 00-0--0-11 +010001 1----1---1 +110001 -1-0--1-1- +001001 0-1001001- +101001 0-01110110 +011001 -1-1110--- +111001 11001--10- +000101 01110-1001 +100101 110------0 +010101 -10---0-10 +110101 -0-101--00 +001101 ---11-0-01 +101101 -1-00--101 +011101 1-00-11-01 +111101 10110-01-- +000011 110------0 +100011 1-0---111- +010011 0--010-111 +110011 -0-0---000 +001011 0-1--1---1 +101011 -----011-0 +011011 1-1--11-10 +111011 11-0---110 +000111 -01-1--111 +100111 -10--011-0 +010111 11-01-1--- +110111 0--1-0---0 +001111 0--110-01- +101111 11-00--0-1 +011111 01-11--000 +111111 0-1-1-0-01 diff --git a/espresso/examples/random/p1 b/espresso/examples/random/p1 new file mode 100644 index 0000000..ca9073d --- /dev/null +++ b/espresso/examples/random/p1 @@ -0,0 +1,258 @@ +.i 8 +.o 18 +00000000 ------------------ +00000001 100001101--------0 +00000010 110000101-----1000 +00000011 110000111-----1000 +00000100 --------------1000 +00000101 --------------0100 +00000110 --------------0011 +00000111 ------------------ +00001000 ------------------ +00001001 ------------------ +00001010 ------------------ +00001011 ------------------ +00001100 ------------------ +00001101 ------------------ +00001110 ------------------ +00001111 ------------------ +00010000 ------------------ +00010001 ------------------ +00010010 ------------------ +00010011 ------------------ +00010100 ------------------ +00010101 ------------------ +00010110 ------------------ +00010111 ------------------ +00011000 ------------------ +00011001 ------------------ +00011010 ------------------ +00011011 ------------------ +00011100 ------------------ +00011101 ------------------ +00011110 ------------------ +00011111 ------------------ +00100000 ------------------ +00100001 100001101--------0 +00100010 110000101-----1000 +00100011 110000101-----1000 +00100100 110000111-----1000 +00100101 --------------1000 +00100110 --------------0100 +00100111 --------------0011 +00101000 ------------------ +00101001 ------------------ +00101010 ------------------ +00101011 ------------------ +00101100 ------------------ +00101101 ------------------ +00101110 ------------------ +00101111 ------------------ +00110000 ------------------ +00110001 ------------------ +00110010 ------------------ +00110011 ------------------ +00110100 ------------------ +00110101 ------------------ +00110110 ------------------ +00110111 ------------------ +00111000 ------------------ +00111001 ------------------ +00111010 ------------------ +00111011 ------------------ +00111100 ------------------ +00111101 ------------------ +00111110 ------------------ +00111111 ------------------ +01000000 ------------------ +01000001 100001101--------0 +01000010 110000101-----1000 +01000011 110000101-----1000 +01000100 110000101-----1000 +01000101 110000101-----1000 +01000110 110000111-----1000 +01000111 --------------1000 +01001000 --------------0100 +01001001 --------------0011 +01001010 ------------------ +01001011 ------------------ +01001100 ------------------ +01001101 ------------------ +01001110 ------------------ +01001111 ------------------ +01010000 ------------------ +01010001 ------------------ +01010010 ------------------ +01010011 ------------------ +01010100 ------------------ +01010101 ------------------ +01010110 ------------------ +01010111 ------------------ +01011000 ------------------ +01011001 ------------------ +01011010 ------------------ +01011011 ------------------ +01011100 ------------------ +01011101 ------------------ +01011110 ------------------ +01011111 ------------------ +01100000 ------------------ +01100001 100001101--------0 +01100010 110000101-----1000 +01100011 110000101-----1000 +01100100 110000101-----1000 +01100101 110000111-----1000 +01100110 --------------1000 +01100111 --------------0100 +01101000 --------------0011 +01101001 ------------------ +01101010 ------------------ +01101011 ------------------ +01101100 ------------------ +01101101 ------------------ +01101110 ------------------ +01101111 ------------------ +01110000 ------------------ +01110001 ------------------ +01110010 ------------------ +01110011 ------------------ +01110100 ------------------ +01110101 ------------------ +01110110 ------------------ +01110111 ------------------ +01111000 ------------------ +01111001 ------------------ +01111010 ------------------ +01111011 ------------------ +01111100 ------------------ +01111101 ------------------ +01111110 ------------------ +01111111 ------------------ +10000000 ------------------ +10000001 000001100--------0 +10000010 010000100-----1000 +10000011 010000100-----1000 +10000100 010000100100100000 +10000101 010000100100100000 +10000110 010000110100100000 +10000111 000001000100100000 +10001000 010000000010101000 +10001001 010000000001101000 +10001010 010000000100100000 +10001011 010000000100100000 +10001100 010000010100100000 +10001101 000001001100100000 +10001110 010000001010101000 +10001111 010000001001101000 +10010000 010000001-----1000 +10010001 010000001-----1000 +10010010 010000011-----1000 +10010011 --------------1000 +10010100 --------------0100 +10010101 --------------0011 +10010110 ------------------ +10010111 ------------------ +10011000 ------------------ +10011001 ------------------ +10011010 ------------------ +10011011 ------------------ +10011100 ------------------ +10011101 ------------------ +10011110 ------------------ +10011111 ------------------ +10100000 ------------------ +10100001 000001100--------0 +10100010 010000100-----1000 +10100011 010000100-----1000 +10100100 010000100100010000 +10100101 010000110100010000 +10100110 000001000100010000 +10100111 010000000010011000 +10101000 010000000001011000 +10101001 010000000100010000 +10101010 010000010100010000 +10101011 001001001100010000 +10101100 011000001010011000 +10101101 011000001001011000 +10101110 011000001-----1000 +10101111 011000011-----1000 +10110000 --------------1000 +10110001 --------------0100 +10110010 --------------0001 +10110011 ------------------ +10110100 ------------------ +10110101 ------------------ +10110110 ------------------ +10110111 ------------------ +10111000 ------------------ +10111001 ------------------ +10111010 ------------------ +10111011 ------------------ +10111100 ------------------ +10111101 ------------------ +10111110 ------------------ +10111111 ------------------ +11000000 ------------------ +11000001 000001100--------0 +11000010 010000100-----1000 +11000011 010000110-----1000 +11000100 ---------100000000 +11000101 001001001010001000 +11000110 011000001001001000 +11000111 011000011-----1000 +11001000 --------------0100 +11001001 --------------0001 +11001010 ------------------ +11001011 ------------------ +11001100 ------------------ +11001101 ------------------ +11001110 ------------------ +11001111 ------------------ +11010000 ------------------ +11010001 ------------------ +11010010 ------------------ +11010011 ------------------ +11010100 ------------------ +11010101 ------------------ +11010110 ------------------ +11010111 ------------------ +11011000 ------------------ +11011001 ------------------ +11011010 ------------------ +11011011 ------------------ +11011100 ------------------ +11011101 ------------------ +11011110 ------------------ +11011111 ------------------ +11100000 ------------------ +11100001 000001100--------0 +11100010 010000100-----1000 +11100011 010000100-----1000 +11100100 010000110100000000 +11100101 000001001100000000 +11100110 010000001010001000 +11100111 010000001001001000 +11101000 010000001-----1000 +11101001 --------------1000 +11101010 --------------0100 +11101011 --------------0011 +11101100 ------------------ +11101101 ------------------ +11101110 ------------------ +11101111 ------------------ +11110000 ------------------ +11110001 ------------------ +11110010 ------------------ +11110011 ------------------ +11110100 ------------------ +11110101 ------------------ +11110110 ------------------ +11110111 ------------------ +11111000 ------------------ +11111001 ------------------ +11111010 ------------------ +11111011 ------------------ +11111100 ------------------ +11111101 ------------------ +11111110 ------------------ +11111111 ------------------ diff --git a/espresso/examples/random/p3 b/espresso/examples/random/p3 new file mode 100644 index 0000000..7ff12b5 --- /dev/null +++ b/espresso/examples/random/p3 @@ -0,0 +1,258 @@ +.i 8 +.o 14 +00000000 -------------- +00000001 100001101----- +00000010 110000101----- +00000011 110000111----- +00000100 -------------- +00000101 -------------- +00000110 -------------- +00000111 -------------- +00001000 -------------- +00001001 -------------- +00001010 -------------- +00001011 -------------- +00001100 -------------- +00001101 -------------- +00001110 -------------- +00001111 -------------- +00010000 -------------- +00010001 -------------- +00010010 -------------- +00010011 -------------- +00010100 -------------- +00010101 -------------- +00010110 -------------- +00010111 -------------- +00011000 -------------- +00011001 -------------- +00011010 -------------- +00011011 -------------- +00011100 -------------- +00011101 -------------- +00011110 -------------- +00011111 -------------- +00100000 -------------- +00100001 100001101----- +00100010 110000101----- +00100011 110000101----- +00100100 110000111----- +00100101 -------------- +00100110 -------------- +00100111 -------------- +00101000 -------------- +00101001 -------------- +00101010 -------------- +00101011 -------------- +00101100 -------------- +00101101 -------------- +00101110 -------------- +00101111 -------------- +00110000 -------------- +00110001 -------------- +00110010 -------------- +00110011 -------------- +00110100 -------------- +00110101 -------------- +00110110 -------------- +00110111 -------------- +00111000 -------------- +00111001 -------------- +00111010 -------------- +00111011 -------------- +00111100 -------------- +00111101 -------------- +00111110 -------------- +00111111 -------------- +01000000 -------------- +01000001 100001101----- +01000010 110000101----- +01000011 110000101----- +01000100 110000101----- +01000101 110000101----- +01000110 110000111----- +01000111 -------------- +01001000 -------------- +01001001 -------------- +01001010 -------------- +01001011 -------------- +01001100 -------------- +01001101 -------------- +01001110 -------------- +01001111 -------------- +01010000 -------------- +01010001 -------------- +01010010 -------------- +01010011 -------------- +01010100 -------------- +01010101 -------------- +01010110 -------------- +01010111 -------------- +01011000 -------------- +01011001 -------------- +01011010 -------------- +01011011 -------------- +01011100 -------------- +01011101 -------------- +01011110 -------------- +01011111 -------------- +01100000 -------------- +01100001 100001101----- +01100010 110000101----- +01100011 110000101----- +01100100 110000101----- +01100101 110000111----- +01100110 -------------- +01100111 -------------- +01101000 -------------- +01101001 -------------- +01101010 -------------- +01101011 -------------- +01101100 -------------- +01101101 -------------- +01101110 -------------- +01101111 -------------- +01110000 -------------- +01110001 -------------- +01110010 -------------- +01110011 -------------- +01110100 -------------- +01110101 -------------- +01110110 -------------- +01110111 -------------- +01111000 -------------- +01111001 -------------- +01111010 -------------- +01111011 -------------- +01111100 -------------- +01111101 -------------- +01111110 -------------- +01111111 -------------- +10000000 -------------- +10000001 000001100----- +10000010 010000100----- +10000011 010000100----- +10000100 01000010010010 +10000101 01000010010010 +10000110 01000011010010 +10000111 00000100010010 +10001000 01000000001010 +10001001 01000000000110 +10001010 01000000010010 +10001011 01000000010010 +10001100 01000001010010 +10001101 00000100110010 +10001110 01000000101010 +10001111 01000000100110 +10010000 010000001----- +10010001 010000001----- +10010010 010000011----- +10010011 -------------- +10010100 -------------- +10010101 -------------- +10010110 -------------- +10010111 -------------- +10011000 -------------- +10011001 -------------- +10011010 -------------- +10011011 -------------- +10011100 -------------- +10011101 -------------- +10011110 -------------- +10011111 -------------- +10100000 -------------- +10100001 000001100----- +10100010 010000100----- +10100011 010000100----- +10100100 01000010010001 +10100101 01000011010001 +10100110 00000100010001 +10100111 01000000001001 +10101000 01000000000101 +10101001 01000000010001 +10101010 01000001010001 +10101011 00100100110001 +10101100 01100000101001 +10101101 01100000100101 +10101110 011000001----- +10101111 011000011----- +10110000 -------------- +10110001 -------------- +10110010 -------------- +10110011 -------------- +10110100 -------------- +10110101 -------------- +10110110 -------------- +10110111 -------------- +10111000 -------------- +10111001 -------------- +10111010 -------------- +10111011 -------------- +10111100 -------------- +10111101 -------------- +10111110 -------------- +10111111 -------------- +11000000 -------------- +11000001 000001100----- +11000010 010000100----- +11000011 010000110----- +11000100 ---------10000 +11000101 00100100101000 +11000110 01100000100100 +11000111 011000011----- +11001000 -------------- +11001001 -------------- +11001010 -------------- +11001011 -------------- +11001100 -------------- +11001101 -------------- +11001110 -------------- +11001111 -------------- +11010000 -------------- +11010001 -------------- +11010010 -------------- +11010011 -------------- +11010100 -------------- +11010101 -------------- +11010110 -------------- +11010111 -------------- +11011000 -------------- +11011001 -------------- +11011010 -------------- +11011011 -------------- +11011100 -------------- +11011101 -------------- +11011110 -------------- +11011111 -------------- +11100000 -------------- +11100001 000001100----- +11100010 010000100----- +11100011 010000100----- +11100100 01000011010000 +11100101 00000100110000 +11100110 01000000101000 +11100111 01000000100100 +11101000 010000001----- +11101001 -------------- +11101010 -------------- +11101011 -------------- +11101100 -------------- +11101101 -------------- +11101110 -------------- +11101111 -------------- +11110000 -------------- +11110001 -------------- +11110010 -------------- +11110011 -------------- +11110100 -------------- +11110101 -------------- +11110110 -------------- +11110111 -------------- +11111000 -------------- +11111001 -------------- +11111010 -------------- +11111011 -------------- +11111100 -------------- +11111101 -------------- +11111110 -------------- +11111111 -------------- diff --git a/espresso/examples/random/test1 b/espresso/examples/random/test1 new file mode 100644 index 0000000..bb68f77 --- /dev/null +++ b/espresso/examples/random/test1 @@ -0,0 +1,258 @@ +.i 8 +.o 10 +00000000 ----000-01 +10000000 --0----1-- +01000000 -00--000-1 +11000000 ----0--01- +00100000 -0---1-0-0 +10100000 000-01--00 +01100000 -000-0010- +11100000 -0--0-0--0 +00010000 -0-00---1- +10010000 00-0-0--1- +01010000 00--00-001 +11010000 ---01--1-- +00110000 00-0-0---1 +10110000 -1-01---1- +01110000 --01001110 +11110000 -1-0010--- +00001000 0-00-001-- +10001000 --00----0- +01001000 10----001- +11001000 00110-0011 +00101000 0--0-1--00 +10101000 -1--0--0-0 +01101000 --0--01-0- +11101000 -0-1-00-0- +00011000 -01---00-- +10011000 01000----0 +01011000 -----1-0-0 +11011000 1---0-0-00 +00111000 --0-01100- +10111000 00000--00- +01111000 00---0-000 +11111000 1-0--10001 +00000100 -0-1111--0 +10000100 0--0----10 +01000100 1----0---1 +11000100 -1-0--1-0- +00100100 0-0-01--0- +10100100 0-0010-000 +01100100 -0-1000--- +11100100 11001--0-- +00010100 01110-1000 +10010100 110------0 +01010100 -10-----00 +11010100 ---100--0- +00110100 ---00-0-00 +10110100 -0-0---000 +01110100 0----10--1 +11110100 10100-01-- +00001100 11-------0 +10001100 1-0---011- +01001100 ----10-011 +11001100 -0-----00- +00101100 --1--0---0 +10101100 -----011-0 +01101100 1-1--00-0- +11101100 10-0---00- +00011100 --0-1--100 +10011100 -10--001-- +01011100 00--1-0--- +11011100 0--0-0---- +00111100 0--000-00- +10111100 10--0----0 +01111100 -0-11--000 +11111100 0-1-1---00 +00000010 ---0-0-10- +10000010 01---0---1 +01000010 000--0--0- +11000010 0--0-0001- +00100010 0---0----- +10100010 0-000----0 +01100010 --00-0-0-0 +11100010 ---1----10 +00010010 -10-0----0 +10010010 -10-0-0--0 +01010010 0-0-1-0-00 +11010010 01-0----0- +00110010 00--01-0-- +10110010 00--1-00-- +01110010 00-1-000-0 +11110010 -10-00-010 +00001010 -1-1---00- +10001010 01010---0- +01001010 -----00--- +11001010 00-10----- +00101010 ---0000--- +10101010 10010--1-- +01101010 001-0--001 +11101010 -10-1--0-1 +00011010 0-11-000-0 +10011010 0--00-011- +01011010 1--1--01-0 +11011010 -1-110000- +00111010 -0--0-0--- +10111010 0-000--0-- +01111010 00------00 +11111010 -0-1-00-00 +00000110 10-001--0- +10000110 ---0-0-00- +01000110 01---01--1 +11000110 00---0--00 +00100110 10-0-110-- +10100110 0000-10-01 +01100110 0-0000--0- +11100110 00-1---100 +00010110 -0----0--1 +10010110 -010-0---- +01010110 -100-1-0-0 +11010110 0---1--0-- +00110110 --0--1---- +10110110 -000--0-1- +01110110 -1-00----1 +11110110 0----1---- +00001110 0-1011-0-0 +10001110 0--0---00- +01001110 -0----100- +11001110 000-0-0--0 +00101110 0-11--0-1- +10101110 0101000--- +01101110 01-1-00--- +11101110 1----0---- +00011110 --0-0-00-- +10011110 ---01--10- +01011110 --000-1--- +11011110 --10-10-01 +00111110 --00-0--00 +10111110 0-0-010--0 +01111110 11---0-001 +11111110 -100-0---0 +00000001 --------0- +10000001 11---0---0 +01000001 -0-0011--0 +11000001 ----0001-- +00100001 -001-11--0 +10100001 001100--01 +01100001 00-10--000 +11100001 01-00---00 +00010001 001----00- +10010001 -01-----1- +01010001 1-1-00-0-- +11010001 -0-0-0-00- +00110001 0-100-0--- +10110001 1--1--0--0 +01110001 0-10-1---1 +11110001 -0-0----0- +00001001 ---01000-- +10001001 -1--00-00- +01001001 011--0--00 +11001001 0-00-1--0- +00101001 -0100---00 +10101001 0-0100-0-- +01101001 -10-100--0 +11101001 1-0----1-- +00011001 1-0-----11 +10011001 ---0-00--1 +01011001 00-0-10--1 +11011001 ----000--0 +00111001 0-010--01- +10111001 0---0---01 +01111001 ----100000 +11111001 00-0---0-0 +00000101 ---0-0-10- +10000101 01-00-011- +01000101 -----1-0-0 +11000101 1-0--01000 +00100101 -00000-00- +10100101 --1---0010 +01100101 0--100---1 +11100101 -0-0-0-01- +00010101 00-010-0-0 +10010101 ----110--0 +01010101 1--001-0-- +11010101 -0-0-01-10 +00110101 1-100-0-0- +10110101 010--0-0-- +01110101 ---------0 +11110101 010----0-- +00001101 0-11---0-0 +10001101 00--1-0100 +01001101 0-0----101 +11001101 -0---1---0 +00101101 1---0---00 +10101101 -0-01-0--- +01101101 0101------ +11101101 ---0--0-00 +00011101 -00-0--01- +10011101 11-0-0-001 +01011101 ----1000-0 +11011101 10-0-1-000 +00111101 --1-000-0- +10111101 0100---0-0 +01111101 -0--0001-- +11111101 ----0----- +00000011 -0----0--0 +10000011 1110---000 +01000011 1010-00--0 +11000011 -0--0----- +00100011 0-1---1110 +10100011 1--110-0-- +01100011 00001--000 +11100011 00--0-0001 +00010011 -00100110- +10010011 --00----1- +01010011 1-000-0-01 +11010011 -001-0---1 +00110011 ---1-0-00- +10110011 --0--0--00 +01110011 10-0--00-- +11110011 -11-0---0- +00001011 --00--1-0- +10001011 --0011---0 +01001011 --00---000 +11001011 ---0000--- +00101011 -0-----0-- +10101011 --0-0----- +01101011 -101-0-11- +11101011 00-11000-0 +00011011 10--01-0-- +10011011 --00010--- +01011011 00---011-1 +11011011 -1-1-0-0-0 +00111011 -0----01-0 +10111011 --00-0-110 +01111011 -1-000---1 +11111011 ---000-0-- +00000111 -1-0---0-1 +10000111 -00----1-- +01000111 0--10---1- +11000111 0-------01 +00100111 1---1--0-0 +10100111 -----00--0 +01100111 0000-0---- +11100111 000-1100-- +00010111 00-----01- +10010111 100000-0-- +01010111 0--10010-- +11010111 --0-01---0 +00110111 -011--1-11 +10110111 -0-10010-0 +01110111 --1---1-0- +11110111 -000-0-100 +00001111 --1-100111 +10001111 0101-100-- +01001111 001-11-0-- +11001111 -0-000-0-- +00101111 1-0--00000 +10101111 -0--0--000 +01101111 -1--0-1--- +11101111 0--1---0-- +00011111 0-1-101--0 +10011111 -0000-0001 +01011111 0-0-0010-- +11011111 100-0---00 +00111111 -0000---0- +10111111 00-0--0-1- +01111111 0--10-000- +11111111 000-10-001 diff --git a/espresso/examples/random/test2 b/espresso/examples/random/test2 new file mode 100644 index 0000000..118698a --- /dev/null +++ b/espresso/examples/random/test2 @@ -0,0 +1,2050 @@ +.i 11 +.o 35 +00000000000 ------0--1--0----1--------0--1----- +10000000000 ---1------0---------1--00--00--000- +01000000000 -----------0------0-0-------1------ +11000000000 0-0-1---01--1--00-0-0---1-0--0---1- +00100000000 ---1-0110--1---10------0---1------- +10100000000 -----00------1---110-0-100--0-1---0 +01100000000 -1--0-----------1----0-0-0------0-- +11100000000 -----010------------0-0--1--------- +00010000000 --0--10-0---00---0--00-----0-00-0-- +10010000000 1---1-0-1111--0--------101----0---1 +01010000000 -1----1-----0--0--0----010-00--0-10 +11010000000 0----01--1--0---110--1--011-------- +00110000000 -1------0----1-0-------00----0-0--- +10110000000 --0-00----10--11-10---0--01-------- +01110000000 1-----010-----0--010------------1-- +11110000000 ----0------11--1-1--00-0-00-----00- +00001000000 --0-0--1-0-1----00--00--1-0------0- +10001000000 --------00---0-10-------0-0-01----- +01001000000 --0-1----0-----0-0---1-------00-0-- +11001000000 0-------0----0-0---0-----0-000----- +00101000000 --0----------1----10-10------0-00-- +10101000000 ----00-0-1-0--0-0-0-----------1---- +01101000000 0---0-0----0-0-------1---0--10-1-1- +11101000000 -----00010------------------1------ +00011000000 -----0----10000--0----0----0-1-1--1 +10011000000 ----0--11-----00--0--000-1--1---1-- +01011000000 -1-01------0--------0---0--0--00--- +11011000000 ----0-0-1-00-0-0---00---------0-00- +00111000000 01---00--00--------000---110--0---- +10111000000 0---10----------0-0---000------0--1 +01111000000 -01--------0---1--------1---------- +11111000000 0------0-----1--1-0-----1-----0---- +00000100000 0-0001-------0-------0----1-0--00-- +10000100000 ----00-11--0-1-01-1-------1-0--0--- +01000100000 1-----------0-----------1--0----0-- +11000100000 -1-----1--10-00--------0---0--10--0 +00100100000 11---0--01-1-------0--------0-11--- +10100100000 0---------01----------0---0-1-11--0 +01100100000 --01-0---1---10---0--1--0----0001-- +11100100000 ---0---0-----1-1-1--0-------0------ +00010100000 --00------1--1--0---0-0--1---1-0--- +10010100000 ---0-----00-----1---0----001------- +01010100000 0-0--1-----01------0--01---0---0--1 +11010100000 0---01------1--1-------10---0-----0 +00110100000 -0---10--1----------0--1----1-0---0 +10110100000 ---01----10--0000-0-----0---0-0-0-- +01110100000 -1-00--11------1----1-0---1-0------ +11110100000 -------1---001----1-0---0-0---0-00- +00001100000 -0--10---0----10---01---01-----0--- +10001100000 -1-101-1-----0--0-----0------------ +01001100000 -10----0--0-10-----00---1-000---0-- +11001100000 --1-1-----1----0---0---0-----1----- +00101100000 -000---------0-----0--0----01-11-0- +10101100000 ----1----0--0--1----1-00---0------- +01101100000 -0-0---0--------01-------------0--- +11101100000 -0---111----0--1-1--------0-------- +00011100000 0-1---00000--11-----00001------0--- +10011100000 -0--1-0010-00----------1-1---0---00 +01011100000 ---1-----1---0-0-00---------001---- +11011100000 --0---11-0-------00--0-----0-11---- +00111100000 --------------0------0------------- +10111100000 ------1-1---01--0-11-0---10--00---- +01111100000 ----00----0-----11-1-1-1---0-0----- +11111100000 --1---------11--1-000---1---000---- +00000010000 -1-----0-1-00----0--0--00---1------ +10000010000 ---001---1--0-------0---------0---- +01000010000 0---0100---------00-1-0--0-0-----00 +11000010000 -10----0-01---0--10--1-01---00-00-- +00100010000 --1---1----0-----0-0--1-1--1010001- +10100010000 1------0-11-0-----0---0--1-0--00--- +01100010000 -----------1----1------1------0-0-1 +11100010000 -0----0----0--00---0-1---000-0---00 +00010010000 -0--0---0--0-0--0-1----1--0-0-----1 +10010010000 ----1--01-0--0-1-1--------0-----000 +01010010000 00---0----0--0-0--1--000--00----0-- +11010010000 --------1---0-1-00---0------------- +00110010000 -0--------00--0-1---0-------11--0-0 +10110010000 -0-010-0-11--0----1------00--0----- +01110010000 0------01--0----0---11-0000-------- +11110010000 ------0----0-0---------1----------1 +00001010000 0-01-0-1--01--0-0--0--11-----0---00 +10001010000 0--01-0-----0--0--0-1-----0-----0-- +01001010000 ---1-------011-0------0-----1---0-- +11001010000 1--1--010-------0-000--0-------000- +00101010000 1--1---010--0-----0-------0--0-1--- +10101010000 --0-1--1---01------10-----0--0---0- +01101010000 -----0-----0--0----------0---01---1 +11101010000 ------0------0--00-----------0----0 +00011010000 --0----------0-0-1--------0--0----1 +10011010000 --0---00-1------000--0-10--------0- +01011010000 --010---0----------00-1----0-01---- +11011010000 ----100-------1-0--------1-00--0--1 +00111010000 ---------00-1---0-0--0----1-------0 +10111010000 --0-1--0---1-----0----10-1----01--- +01111010000 -------1----1000--001-----------0-0 +11111010000 0----00-0-----01---00-1--10-00-1--- +00000110000 ----0---0--0---00--0--0-00-0--1---- +10000110000 -----0-0---0--00-1--00110--1-0--000 +01000110000 -1----------0-----------1000-0----- +11000110000 0-------0---------1---000-0--01---- +00100110000 001-1-010------1-0------1-0-01----0 +10100110000 -0------------00--------10---00---- +01100110000 --------0--1-0-0-----11-------0--11 +11100110000 ----0--0--11-0-0---0-0----0-0--0-1- +00010110000 1000---0-------00-10---0---1---01-- +10010110000 -----00--00--0---1-1-00-00---10--0- +01010110000 1------0-0----1-11-------0---0-1--- +11010110000 1-----0---0--1----00-0-01010---0--- +00110110000 -10---0--1-----1----0-----0--0----- +10110110000 ----------1----------0-0-----00-0-1 +01110110000 -0---1------0--1--000---1-------0-- +11110110000 ------1-00-0----0----1-01-0--0---0- +00001110000 -----0---------0---0-------1-00---0 +10001110000 00-0--1------11---0-00---0100----0- +01001110000 -011-0--0---00-0--1---10---0---100- +11001110000 ---0---0--01------------01---1--1-- +00101110000 -0--------1--0-0---1--0--1-1----0-- +10101110000 -----0-------------1-----1----1--1- +01101110000 -01-------0-0--0-1-100---1----0---- +11101110000 -1-1-010---1--0--0---0-----0-010--- +00011110000 --1--------0----0------------0-11-0 +10011110000 1--1------1-----01-0--1-------11--- +01011110000 --1-----00--0----0------00-----0--0 +11011110000 ----0---0----0-------1------10-0-1- +00111110000 -1-----0---000-0--1-----0-0----0--- +10111110000 -1-0---1-------0--1-----1-0-----000 +01111110000 0-0----------01----1-10----01--0--- +11111110000 --0------0--1-------0----1------1-- +00000001000 0------00--0--001-----0--10-----1-- +10000001000 00-10-0---0----------0----0---101-1 +01000001000 0-0--00------0---00----000--------- +11000001000 --01101-10---1------------------00- +00100001000 0------01---0-----11--0-00-1---0-0- +10100001000 1----00---0-011--001---0------0---- +01100001000 ---1-----0----0--0-0-----0------0-- +11100001000 -01-0--010---10-0-----------0----0- +00010001000 --0------1----0----110000---------- +10010001000 -----------0---010--11------1-00--- +01010001000 -----0---0---0--------1----0-----00 +11010001000 --0--00-1-----1----0-11-0--1-01---- +00110001000 0---0---00-1--0-001-1-00-1-----0--0 +10110001000 1----1-------0-------0-----0000-0-- +01110001000 --00-----00----11---------001-0-0-1 +11110001000 --10-0--10-1-100--10--------000--0- +00001001000 --00-01-010-0----1-------0--1--0--- +10001001000 --0-10---1----10-1--0------1--0-1-- +01001001000 -0---0---1------01--10------0------ +11001001000 ----00-1---------0--------1-0--0--1 +00101001000 ---0--01-0--0-0--010---1----------- +10101001000 ----1--0-1-------0-------0--10----- +01101001000 -0010-0101-10--000--110------------ +11101001000 -------0--0-----0--------0--0-1---- +00011001000 --0001-1--------00----1---------0-1 +10011001000 ---0-----------------1---00-------0 +01011001000 ----------0---------1----1--1------ +11011001000 -0----0----------0001--------0----- +00111001000 -0-0----1----0-0----100----------1- +10111001000 0--------110-0-------0-0000----0--- +01111001000 -00-----1----1----1--1---10-------0 +11111001000 00---0--00----1------0------1--1--- +00000101000 0-0--0--0-000----1---0--0----0-0-0- +10000101000 ---0-1--0-1-----0-10-1--0----10-10- +01000101000 ---01---0-----10-0-1-00---010-0---- +11000101000 01--0-1--0-0-----------0----0----0- +00100101000 --0-------0-00------0-1-01----0-0-0 +10100101000 -00-0--11-----010-----0----000----- +01100101000 0-------01--00------1----------0--- +11100101000 --010-1-01-00----010--0-0---0-0---- +00010101000 ---0---0-00---0----0-01---------0-- +10010101000 --0----1---1--1------1--1-----1-01- +01010101000 --1----0---0---0-0--0--0----0--0--- +11010101000 0-----01-0--1------------0---01---0 +00110101000 1--011---0-0---0---1100---0----0-0- +10110101000 0--10----------0--0--1----------1-- +01110101000 -------10---------------0---0--1-0- +11110101000 -----0--1------0--0--0-0--1---01--0 +00001101000 --0-11-------1-0---------001----0-- +10001101000 -0------0--1-0--1-0-0---0--------1- +01001101000 -----1------1-----1------1---0----1 +11001101000 1--0-0--1--1--10-------010-1------- +00101101000 1---------0---------1----0--11-10-0 +10101101000 10-1----1-000--0101--1----0--0---00 +01101101000 ---1-11-1--00--1---1----1-0---0---1 +11101101000 1-0----01---0--------1--0-1-0--1-1- +00011101000 0----000-1-1----0-0-00---01-------- +10011101000 --10--1-------0--0-0-0------------- +01011101000 --0--10----0-0--0-----0----00--0--- +11011101000 0----------------0-1------------0-- +00111101000 -----0-000----01-0----0-101-00----- +10111101000 0-----0------------0--0--0-00-0---1 +01111101000 --0--0----10--0--------------0---0- +11111101000 -------11--0--0-1-0---0--0-------10 +00000011000 -----1000-0------0-0-0-01--000----- +10000011000 0--10-0---------1------0-0---0--1-- +01000011000 -0---1--------1-00--1----01------0- +11000011000 -0-----0-001---0---11-------0-0--00 +00100011000 -0-00--0---0----1--001------0----0- +10100011000 ------01---0-1----1100--00----0---- +01100011000 1----0------0---0-0--00-0-10--10-0- +11100011000 ----0-00---01----0---1-0----00----- +00010011000 -----0--0---001-0---------0---1---- +10010011000 --0------0--0-----1---------0----0- +01010011000 ----01-1-0----0--1-00--11-1------1- +11010011000 0-1------0--0----0---1----0-00--000 +00110011000 --00----0-0------0--1-0------------ +10110011000 ---1---0-----0---------0---0-0001-- +01110011000 --1--10-0---0---00----01----------0 +11110011000 1-------0-----0-----01--0------1--- +00001011000 --1----0----1--1-0-00----0-11-1---- +10001011000 -0----0-0-01-----11--1--0-------1-- +01001011000 00---0-------01--0---0--1-1-01----- +11001011000 0----10-0-00-0-0---1-011---------0- +00101011000 ---0--01-0------11--1--0-----0--11- +10101011000 -0-----0-0-------------0-0-0-1----1 +01101011000 -0--0-0-------0-----01-0--10-0----0 +11101011000 1-------1----0--0----01-0----1--00- +00011011000 0101---0---1--10-01-1-0--00----0--- +10011011000 -----------------10-0--0--1-01----- +01011011000 ----10-0----1--0---1---0--1------0- +11011011000 1-------0-01-------101---0-0---1-0- +00111011000 1---00--00101----00-00-0-0-------1- +10111011000 -0-1-----11-------100--0--00------- +01111011000 --010--0-----0---0--00--0----0--00- +11111011000 0110-----0-0--0---------0-101---1-- +00000111000 ---0-----1-0---0-1------0-0-00---0- +10000111000 11----00--0-01---1-1-----------11-0 +01000111000 0-----0---0--0--0-00---1----0------ +11000111000 1---0----------------1--0-0--0----1 +00100111000 -----0----0----0---0---010-0-----00 +10100111000 --101-0--00--00-0----1-0-0-----01-0 +01100111000 --01-1--1-0--11-----10----0-----0-1 +11100111000 ----------1-0---0-0-00000-00--0--0- +00010111000 -11-----1------0-0--0-0-----0-----0 +10010111000 ---1-01----0----0----000-1-1-00-1-- +01010111000 ------0-01---------------1-0-----0- +11010111000 00----0-------0----------1--0------ +00110111000 -----1-----00--1-0---011--0--1--1-- +10110111000 ---0-0-------0---01---1-0-1---1---- +01110111000 1------0-1----1-------10-----00-01- +11110111000 01000----00---1-1--10-100----00---1 +00001111000 -0-1--0-0--0-11----0-0---10--0----- +10001111000 0--0--0---0-----10-1-----000110---- +01001111000 0--10---010-1--0----0-1----0-0----- +11001111000 10--0-0-----1--------0----1-------1 +00101111000 ---01---10--------0-----0-------0-- +10101111000 ---101-0-0-0---0-------1--0--0----- +01101111000 0--0---00---01---10------0-0----0-- +11101111000 -----------------0-------0---0-0-1- +00011111000 -1-0-0-----0-0---1--0-0------------ +10011111000 -000-1----10--0---101---0-000---0-- +01011111000 ------0-------0--1-1----0-00----00- +11011111000 ---0----0---0--110---0-------0----- +00111111000 --------0--01------0------0-------- +10111111000 0-------1---0-0-0---0-----0---0--1- +01111111000 -----0--0--------000--1--00-1------ +11111111000 ---10-0--110--0------0--01----1-1-- +00000000100 01-111-0-01-0-0----0-------00----0- +10000000100 --0--0----00---------------------0- +01000000100 0----1--11-000-1--------1--010----1 +11000000100 0------0-0-1-0------------0--1----- +00100000100 1------0---0-----0----1----1---0-0- +10100000100 ---------0-----0----00--1---1---10- +01100000100 --0-0-1-----0----0-------10-00----0 +11100000100 -------0-------00-0---1------11-10- +00010000100 ---0---0-----11--0-01--------1---00 +10010000100 --00--0---0-1011--00---00---0------ +01010000100 -----1--0---00--01-1-----------0--0 +11010000100 --10--1-----00-----0---01----0-0--- +00110000100 ----01-0-0-------1-0-00--0---000--- +10110000100 --011-0--1-----1------0-0--10------ +01110000100 -1---1-1-1---01---1-------0--1----- +11110000100 -------0--------0----0----------1-- +00001000100 ------------1----0-01--1---0--00--- +10001000100 ----0--00--0---11----1-----00----1- +01001000100 1---------00-1--110-00--0-00------- +11001000100 00-0-000---------0--------00-0----- +00101000100 ---0-00------0---------0----001--01 +10101000100 -0-0-0---0---1---00--00----00--0-0- +01101000100 --0-01--1-------01--0-0---0-0------ +11101000100 --0----------0---0-0--00---0------1 +00011000100 -0-0---11-----------0-01--0----0--- +10011000100 1----1--0-0--0------------1---0--1- +01011000100 -----10-11--100-0110-1-----0------1 +11011000100 -----0-1--0--1---0--11-1-0---110--- +00111000100 1---11-10-0---01-1-0-----0-0-01--0- +10111000100 ---11--1-0-1-0----------0-00---1--- +01111000100 0---------------------0--0-0------1 +11111000100 --1-1---1----000-0-----00000-1-1--- +00000100100 ---0--0--0-1------1----10------0--- +10000100100 -01---0----0--0----01--1--01-0----- +01000100100 --------1---1---01-----0-----0---01 +11000100100 -0-001------1---00------0---0--1--- +00100100100 1--1--101-----0--01-----00--0-0---- +10100100100 --0-00----1-0-0-00--0-00--0------00 +01100100100 ----0--------1----1--0--1-1-----1-- +11100100100 0--0-----101----00---00------0----- +00010100100 --0---0-0-0--0---0----0--------1-0- +10010100100 00-1----000--------0--------------- +01010100100 -0-0----10---------1---1---0------- +11010100100 --0---0--0-00-----0------1----0-10- +00110100100 0-----0-------0--0-----------0---1- +10110100100 -01---------01---0-000-0-00--00110- +01110100100 -1-0--0-0--101--00-0-0--001-----0-- +11110100100 1---0--11--1------1--------1-0----- +00001100100 10-1-01-0---0------------00--0----- +10001100100 ---00--0-----00--0---0-1--00--0-1-- +01001100100 1--1-110-0-0-----011---00-------0-- +11001100100 -0-0-----0---00-1-----000-1--11---- +00101100100 ---1--0-0---0-----0--0-0-----0---1- +10101100100 0-0--0--0----0--0-------1-1-------- +01101100100 ----00-0-------00-0-----------0---1 +11101100100 ---------1---10-0--000---0--------- +00011100100 0-0-1-----------0----0----0-0000--1 +10011100100 -1----0-----------0---01---1-1--100 +01011100100 000--10---0-0-------11----------0-- +11011100100 -00--1------------0-----0-0-------0 +00111100100 -00---10--01--0--1----0-----1-----1 +10111100100 0--------1---10-----0-0-1--101-1--- +01111100100 ----0---1--10-----010---0-0-0-000-- +11111100100 --0-0-0--00-1--01------0----0--0--- +00000010100 -----00-------00---1-0--0---1---1-- +10000010100 ----0--0---10--1---11---------0---- +01000010100 ---0--0------1----01------0---0---- +11000010100 0-----0-0-0----------------00------ +00100010100 ---1-1---1--1-1----1--00-----000-00 +10100010100 -0-----1----10-1-00--0001-1-----1-- +01100010100 -------00--0---1--1-0--000------0-- +11100010100 -1--0-1------0--0-01---0-0---1-1--- +00010010100 --1----0-----111-------10-----10-00 +10010010100 -0010--------0-00-1---0-00--------0 +01010010100 -----0-0-----1----0-0-0-----00----- +11010010100 --0-1-0-----001--111-00----0---011- +00110010100 00-0-000--01----000-00-11-00----0-1 +10110010100 ----1--0-----0-1----0-----00--00--- +01110010100 ----------0---1--00-1001--1-00----- +11110010100 ---00---1--------1--0-0---10--0---1 +00001010100 ---00-------1---00---0-0--1--0---0- +10001010100 -00--1--0-----010-1-------------0-- +01001010100 -0-------1---0-0----0-0--001---00-1 +11001010100 ---------0------0-10--1-00--00--0-- +00101010100 1-0-------00-----0-------0-0--1---0 +10101010100 10---10--011----0-01--01---------01 +01101010100 0-------0-----0---01--01------0-1-- +11101010100 0----001----10---1--1--1--0010---1- +00011010100 1-------1-0-0---01011--0---0------1 +10011010100 -----1---1-----1--00-1--------0---- +01011010100 --------1-1----1-0-1--0010-0---1-0- +11011010100 --0-------000----00------11-1--0--0 +00111010100 ---0--0010-----0----1-----------0-- +10111010100 0-0-1--0----11--100----00------0-0- +01111010100 -0--00-00--010--1-1---------0------ +11111010100 101-10-1-1--0--00-------0000-0--0-- +00000110100 --00-0------0-0-0-------00----0--1- +10000110100 001--0---10-00---1000----0----1---0 +01000110100 ----0--0------------------1----10-- +11000110100 ---0---0--0-----0-0001---000-----00 +00100110100 1--00-0--0--0-000---0-----------0-0 +10100110100 -------0-00--1-0------0--00-011---- +01100110100 0-00--0--01-------0--00---------1-- +11100110100 -001--0---0-----1---0-10---0---0--- +00010110100 0-001-0------0-1-1-1--0-------0---0 +10010110100 1--0--0----1-11-0---1---0-0001-0--- +01010110100 --------0--0----10-0--10-1--0--1--- +11010110100 -----0-----0---1-1----------0--0--1 +00110110100 -0-1---01-1---------------1-0-0---0 +10110110100 1----11----------0---1-------01---- +01110110100 ---0110-------1--------1----0------ +11110110100 0--0----------1----0--1-0--0-0----- +00001110100 --------10-1-111-10-0---0----0---1- +10001110100 ----0--0------1---1--------0-0--00- +01001110100 1-------01--1---0---0--0-------10-- +11001110100 ---1--0-00----10------------1000--- +00101110100 0-----000--11---0-----01---0-0-1-0- +10101110100 10--1--0-0-1--------0----0-----110- +01101110100 -00--0---0----0-1-0---01--0------00 +11101110100 ----0--0--10-----10-10-1--1-----0-0 +00011110100 -00----0---------0----1---------1-0 +10011110100 -----0----------0--0----1---------- +01011110100 ----0--------1--1--0---------1----- +11011110100 000-1--0-------0-0----0-----0-0--0- +00111110100 --10--1---11-1--0------------1----0 +10111110100 -------00-00---------------1--0-0-- +01111110100 --0--------0----------0---0-0----0- +11111110100 0-0--010--------11-0-00--00--10-0-- +00000001100 ----1-0------0-1----0--0--1---0--0- +10000001100 0-1---1--0----0-0-0-011-1--0--00--- +01000001100 1--1--001-0------1-----00--1-1--1-- +11000001100 ----0----1-00------1--1---------0-- +00100001100 -0----00------0-----0---1-0-110--0- +10100001100 -----00-1-1---0-10--0---11--0-0---0 +01100001100 -1--0---010---00--10-0------1-00-00 +11100001100 -0---0--10-00----0-10-----01---0-00 +00010001100 00-1----1-0--101-------00---1------ +10010001100 ---------------00-----0-00--0----0- +01010001100 -----1---0---0-01----01-0001-0----- +11010001100 00--0-----0-0-0--1-1-----000-1---1- +00110001100 --0-1-------0-00--0-100----10-1---- +10110001100 ----0-0--11----0-----0-1-0------0-- +01110001100 -010----11------1-01--1-00--1--0--- +11110001100 --0--00-----1--0-------0--1---0---- +00001001100 0-1--1---0011-01-000---110-----1-0- +10001001100 ---0---0-0--0----0-----10-----01--0 +01001001100 ---0--0-------------1------1-1-11-- +11001001100 0---0-0--0----0-1---00-11--0----1-1 +00101001100 -0000------0-0-00-1-0---0-01----01- +10101001100 00---00-----------1-1----10-1---0-1 +01101001100 1----11--00----00-----00---1--1---- +11101001100 ---0---01-10-0-----0-----011----00- +00011001100 ---0-0----0---0---0---0-10--------1 +10011001100 --0-0---------0---0---0--10-0-----0 +01011001100 1---1---1-0--------0--------000-1-0 +11011001100 -0--11----00-------------101--1-10- +00111001100 --0---------1--------------------00 +10111001100 --0---0-0--1----0--0-------11------ +01111001100 -0-----10---0-0---1-0--0--000--0--- +11111001100 001------------0---0-----0--------- +00000101100 0-0--1----0---0000------------0---1 +10000101100 --0--------0---0---0-0--0---010-1-- +01000101100 0--1--0-----0-0-1---0--01--01-00--0 +11000101100 -1--0-0----0---0---0---------0-010- +00100101100 -01-01-----0-----0-1---0-0-0-1----- +10100101100 -------0-----1-00------0------0---- +01100101100 --0-------0--0---1--000--00------0- +11100101100 ---010--1-----00-00--0---0-001-1--- +00010101100 -0---00------------------0-00-0---- +10010101100 -0-10100-----------------------0-1- +01010101100 1--0-0----1--10-------00-0-----1--- +11010101100 -0-------0-----00-0----------00100- +00110101100 --00-------------0--010----01-1--0- +10110101100 --0--0---0--1-0-0----1--00-0-----0- +01110101100 -----------0---001100-0--111010--1- +11110101100 ----0---0--1-0-0-1--0-1--------0-0- +00001101100 11--00-----01-0-----0-------1----1- +10001101100 010--0-----------------1--------0-1 +01001101100 -0101-----------00---100-0---1-0--- +11001101100 -1-0--1-0-0--1--------10-----1--0-- +00101101100 10----0--1---01----1-------------0- +10101101100 ---01---0-0010-1--------11-------0- +01101101100 -0-00--00----0--00------0--0--1---- +11101101100 01--1-0--0-----1--0-0-1-0---1--1--0 +00011101100 00---1-----0--0--0-0--11----------1 +10011101100 0---------0----0-1--1----0--0------ +01011101100 -0-------00---11---1--1----0---0--1 +11011101100 ---0--1------0--0-0---0------------ +00111101100 --------------0-1-----000-0-0-0-0-- +10111101100 -------0---------0-1--1----0-000-01 +01111101100 01-0-110-11---------10--1-10----1-- +11111101100 1-1--0------0----------1010--110-0- +00000011100 -0-0----1-0----0--1----------1000-- +10000011100 -0-0-10-1-------0--0--0--111----0-- +01000011100 ---1----11----------1-01---0--01--- +11000011100 -----0----0--1-1-0--0-00-0--------0 +00100011100 -10--11--0-0--------0---1-1---10--- +10100011100 --00------1-0---------0--------00-0 +01100011100 1-000-1--0-0-00---01---0----0--0-10 +11100011100 --010--------0-0-----10-11---0-1--- +00010011100 1---00----0010-0-0---------00------ +10010011100 -0----1100010---00101---11-0----001 +01010011100 -0-0-0----0------100--------011---- +11010011100 ---1-0--10----01-0---0-010-000----0 +00110011100 -00------0--0---0---1---0-01-0--00- +10110011100 -1---100-0100---00--1--1--100-0--0- +01110011100 -0----0-----1----------0-0-00-0011- +11110011100 --00-0-0---01--0------1-----1-----0 +00001011100 1---------0-------1-------0-01--00- +10001011100 ------0--1----1-------1--00-0-1---- +01001011100 -0-----01-------10-------01-1----0- +11001011100 ---------0---------1-1------------- +00101011100 0--0--------01-----0-0---0--1-0---- +10101011100 -----0---10-0-0-----01---1--0-----0 +01101011100 0-----01--01-0----0----0-10000-1--- +11101011100 --0--1---01--0--0------0-00-------- +00011011100 -1--00----0-1--0--10-------1-10--00 +10011011100 ----1----0-01---1----01--0---0-0-0- +01011011100 ----001--0---0-----0-----1------0-- +11011011100 -0-00-----------0-1--0--0--1-1----0 +00111011100 ---11--011-10-0-00-----1----------1 +10111011100 01-0-0---------0---11-000---10-0--- +01111011100 ----0----000----0--------01-1-1---- +11111011100 -----0-----11-00001---------001001- +00000111100 0---01------0---01-1-1--010---1---- +10000111100 1--00--0-------000-------0-0------- +01000111100 1-0--1---1--11-----------------101- +11000111100 --0--110---1100-0----1--0-----0-0-0 +00100111100 -----0-0------1-1--0--1---0---0---- +10100111100 -------0----------1-100---0-0---0-- +01100111100 -----0-0-0--------0----000---1--0-- +11100111100 -111-----0-00--0-0----0--000----1-- +00010111100 ----11-0---0-0-1----10---0--0----11 +10010111100 -------0-------001--0-1-0--00------ +01010111100 -0-000-01---1-000---0-1---11------- +11010111100 ----0--00--11----1--0--0-----0-00-- +00110111100 1-00---0-10-------------00---01---- +10110111100 -----1--00--0-0-01----0----0--0-0-- +01110111100 ---011--0-01-1--------1--0-1--1---- +11110111100 0-0-----------000------0---0----0-0 +00001111100 -0----00--------0--0-110---1--10--- +10001111100 -0--0---0---010--0---------1---1--1 +01001111100 --0------0--010--1-0---0---------1- +11001111100 0--01--------1-----10----0-----10-- +00101111100 -0----00-00----11-0---1---------011 +10101111100 -00-----0--------1-----1-0--------- +01101111100 --------10---0--01----1-00---0-1--- +11101111100 1----------1----------------001---- +00011111100 --11----0-11------------1---------1 +10011111100 0--1-0-0----------1-0---0-0-----1-- +01011111100 --0-----1----1-----1---01--1------1 +11011111100 ------00-0--00-0---100-----0-1-1--- +00111111100 -00-0----01--00-0---010--------01-- +10111111100 -----------------01-0------0-1-10-1 +01111111100 1-101-----------------1--0---0-1-01 +11111111100 00-------00--1------------11-----1- +00000000010 --1-1100-----------1--0---11--1---- +10000000010 001-1---0---------------1-----0-0-- +01000000010 -00-0-00---0----000----01---1--01-0 +11000000010 ------0--01--0-----0-010--0--0-0--- +00100000010 000--010--01--11-010---0-1---0---0- +10100000010 -0--1--1-0-0----0---1--1--1-------- +01100000010 -------1----00--1-00-00-0---------- +11100000010 ---1---0-----1----1--0---00--0-0--- +00010000010 --1-00-0-----0-0-010-----00---11--0 +10010000010 ----11-01-0---0------0----0-0-----1 +01010000010 ----1-------01-----0-0--1-10-1----- +11010000010 -10-0----1---1--1---0-10-00--11---0 +00110000010 1------0-0-----1---11-10-0110----01 +10110000010 ----------100---1-00-----1--------1 +01110000010 1---1100----0-0---------0---------- +11110000010 -----1------0------1-0-0-----000--- +00001000010 ---0------1-0-----1--1-0----------- +10001000010 -0-------0-----00---00-1--0-0----0- +01001000010 00010--0--100-----0-011-0------1-1- +11001000010 -0------01-0---0-0---0----011--0--1 +00101000010 0---0-0---0-00-------------1------- +10101000010 ---0---0---00-----------001---0-0-- +01101000010 ---11-0-----00-----0----0---0--00-- +11101000010 10-----00--------10-01------0--10-1 +00011000010 --------011----0-100111----00100-1- +10011000010 0-----------11---1-----1-0---00--0- +01011000010 01---1--0--0-----0----111-01-0---10 +11011000010 ----1----------0--0000-----0------- +00111000010 0------1---1--11-----00--0----1--0- +10111000010 1-------0-----0---10-----0---0---0- +01111000010 --0--0-0---0-0--11------1---------- +11111000010 -00-------1--00--0----1-10-----0--- +00000100010 ---10001-----00-------0----001----- +10000100010 ------0---0-1011------00--1--01--1- +01000100010 -----------01-1--0--0-----00-00---1 +11000100010 101-------1---110-1--00--10-110---- +00100100010 -00--0---1-01-1----1--000-0----10-- +10100100010 ---------0------100---1--------0-0- +01100100010 --1--0---1-1----00--0--1-------0--0 +11100100010 -----00--0-0--1------1---01--0----0 +00010100010 -0--0--1------------0------0------- +10010100010 -0--0--0---1----------1----------00 +01010100010 --1-0-1---0--10-101-0-1---0------01 +11010100010 ----0-0-0--0-10-------0---011-0--1- +00110100010 -011-0--0-1-------0-----0-00------- +10110100010 0--1----0-0-------0--------00---0-0 +01110100010 00------00-----00-0-----------0---0 +11110100010 1-0-10----0--0--0-0------0---0-1--- +00001100010 -0---------00--1--1----0-1------100 +10001100010 00-----0--00-1--1--0110-------0-00- +01001100010 -00--0--1---0-11-00---1-0--0-----1- +11001100010 --10-1--1100----1--11-011----0-000- +00101100010 0--0--0-0-0--000-0--0-1----0----1-0 +10101100010 -----0----------0----0-1--1---1-101 +01101100010 ---1----0--10---------------1------ +11101100010 ---100---10---0--1-0---10-011--0--- +00011100010 --0---0--0-00-1-0---10--0-0-0--1--- +10011100010 ----1----0--00010--0------0--0----0 +01011100010 ----1-10----1----0----0-1-------1-- +11011100010 -0-------0--0-----0--0--1--0------1 +00111100010 -----01-----00-------1-11-----0-0-0 +10111100010 -0-00----1--1---00----1--0--------- +01111100010 -0--1--0-0--------0--1----0-------- +11111100010 011--------0-1------110-0----10-1-1 +00000010010 -------0-0--1------1-001----------0 +10000010010 ----011010-1--------0-00------0---0 +01000010010 --0-0-1---0--1010-----1--00-1----1- +11000010010 --00---00---0-------1----------0-0- +00100010010 --------------0--1---10----1------0 +10100010010 0101---1----0---0-001000---0------- +01100010010 0------10---------0---10---01------ +11100010010 ------1--10---00-0--------1-1-10--- +00010010010 -----11----------01------------0--1 +10010010010 ---0---0--0--0-------0--00-00--0-10 +01010010010 01000------0--0--0-0-1----1------0- +11010010010 0--10----00---1-1-1---1-----01--1-0 +00110010010 --1-----0--0---0---0-0-------0----- +10110010010 10-00-1---0-----1-0---0-1---10----- +01110010010 -0----0--0--01-----1-----1--00----- +11110010010 -0--011---101---1--00---------0---0 +00001010010 ----001---0---1---10-00--------00-- +10001010010 -----000---0-----1---000-0-----1--- +01001010010 --0--0--1----1----------0--01----00 +11001010010 -1--0-100---1--0--1-0--0---------0- +00101010010 ---0----0111---100------0-0------1- +10101010010 ------0-0-0---1000---------------1- +01101010010 -0---------0----11-0----1-0---1-00- +11101010010 ----0--0-0-0---0--1-11-0---0---10-- +00011010010 --0--00----0-0--1---------1--00---0 +10011010010 -11-0-----1-----0--------001---00-- +01011010010 --0---------110-1--1-------01------ +11011010010 0-1-----01----0-0----0--0-0-----10- +00111010010 1--11--01-0-0--------0-1-10-----10- +10111010010 -------0---10-0---------------0---- +01111010010 0------------0---1-0-0-----0--10--0 +11111010010 --0--0001---0---0-0-----0-01--1---- +00000110010 ----00---0--0--0----0----1--1---0-- +10000110010 ---0---0-001-------0-0----0--0-0-0- +01000110010 -------0--0-0------10------1-----0- +11000110010 1---0---1-0--1100---0---0-------00- +00100110010 -0---1----------0---1--1-0-1-----0- +10100110010 --1-----------1-----------0--1--1-0 +01100110010 1--01-0----00-----1----1-0-0-11-1-- +11100110010 ---00--0-------01--------0-0--1-1-0 +00010110010 1----10-0-0001---10--0-0----0------ +10010110010 0--0-0---0-0--01-------0---00-0--0- +01010110010 --01--------0---0------0--1----1--- +11010110010 --1---10---10----01-------10-----0- +00110110010 --0--00000---1--0-1------0-100-1110 +10110110010 0--0----01----01-0-------00---10--- +01110110010 1---------0-0----01------------0--- +11110110010 -0---0-10-00-00----1-0---1--0-1-01- +00001110010 -0-----0--1------0-100-1----0-0--0- +10001110010 ----------11--11--------------0---0 +01001110010 ----00---00-----0--11------0000---- +11001110010 ---1--00--0-01-0-0----1--10-------1 +00101110010 -----11--00---1----10-0--000000-0-- +10101110010 ----0-11-00---0-0--00-01-0---1-0--- +01101110010 ---------0----0--0-0---------00---- +11101110010 0--0---1111---0---11-0--00--------0 +00011110010 -0-0-------1-0--0--0---1---0----1-- +10011110010 ----0-00-0-0100-------10----1------ +01011110010 011------0-------0---1---0--01--0-- +11011110010 1--010--0-----0--10-1---10-1---0-0- +00111110010 ----1----0-1--010-0-000---0-0-0-0-1 +10111110010 00---0-0--1--------------10-------- +01111110010 -00-0---1-0-11------1--00---0--100- +11111110010 ----0-----1--1-----0------00-0----- +00000001010 1----1-010-01-------0--1-1---1--00- +10000001010 ----0-1---0------0---1-10--0-0-00-- +01000001010 -----0--0-----0----101--1---0---000 +11000001010 ----------1-0---00--0-0--1---0-00-- +00100001010 --1-0--0-0-0------000-10-0-------0- +10100001010 ---0-1----01--0--0---0-1--0---0---0 +01100001010 ---10-1--0--0-0-1--00-----00-0----- +11100001010 ------1---------------1---1----0--0 +00010001010 ---0-00--------0-----001-----10--0- +10010001010 0---------10-110-----1--0-0-0--1--- +01010001010 0-----1-0----------0-1---1-1------0 +11010001010 ----0--0-0----------1-1-0---------- +00110001010 0--00------0-01----1-0-00-1-01----- +10110001010 ------00100---0-----1-1--------10-- +01110001010 -11--10-01---0-0--0------0---10---- +11110001010 0-------0----10---0--------1----000 +00001001010 --1------01----0--0----1---1--0--0- +10001001010 -0-------------1---0------0-------- +01001001010 --100-----1-00-1-------1-00--11-0-- +11001001010 0-1---0--0---0--0001--000--0------- +00101001010 -------1--011----0--00---10-1--1--0 +10101001010 0--1--001---0-00---0-1--0--0---0--0 +01101001010 0--00-000--0-----0-1--0-1--00-1---0 +11101001010 --0--0-01-0---0--------0----0-0---- +00011001010 0--00---------------00-------0--0-0 +10011001010 --01-0--0--------0-0-00---00-0-0--- +01011001010 ---1-1--01--00----0---0-1---0-1---- +11011001010 ---010---1-------0--1-10--0-------- +00111001010 --00-10--00-0-1-----0-----1-100---- +10111001010 0-----0----00----1--1-1--00---0---- +01111001010 ----0-----1---0-------0---1-0----0- +11111001010 ---------0--0----0--11-1------100-0 +00000101010 -------0---0--0-0-----------1------ +10000101010 -----010--0-1----110------00--010-1 +01000101010 1---------1-1---------1-----00-1--- +11000101010 00----1-1-1-001--0---0--0--1--1-1-0 +00100101010 0-00------------01--------------0-- +10100101010 ---0-0-1-0----------1-0---0-----00- +01100101010 ----01---1--1-1---01-1-0---110----- +11100101010 ---0-----10--0-----00001---------0- +00010101010 -----0-------------000-0---1-----00 +10010101010 -0----0---------01-----1----------- +01010101010 0-----0--1---1-------0------0------ +11010101010 --------------0-----0--1-00--1-00-0 +00110101010 0-----1-1000---00---00---1-------0- +10110101010 --1-00---0--0-----10--1------------ +01110101010 -0----0--0-00---0-1-0---00--0-0-00- +11110101010 0-0--------0-0--1----0--0-------01- +00001101010 ------0----1--1----------0--0100-0- +10001101010 1----1----110------0-----0----0--0- +01001101010 -----000---001-------0--1--0-0----0 +11001101010 -1-0----0001--00----0-------00-0--- +00101101010 0-----0-0--0------0-----010----1--- +10101101010 -----0-01---00---1---1-----011--0-- +01101101010 --0------0-----0----------0---00-0- +11101101010 --------00----1--0---0-----0------- +00011101010 1---001-1----0---0-------------1--1 +10011101010 0------------0----1-1----00---011-- +01011101010 ----10-0-0-------0--------1-0--01-- +11011101010 -1--------0-00-0----01----111---100 +00111101010 ---0-0---00-------1-0----01--1----- +10111101010 ----0-0-11----0-1-------0---101-0-- +01111101010 00-01---0--0---0-0-------------0--- +11111101010 ---0---1--1----1----------0---0---- +00000011010 001--0------01---1-0-----0----11--- +10000011010 --1--------01--000-00-00-01--0----- +01000011010 00-1--1--1--1----0--0----0-----1-00 +11000011010 1-1--10--------1-0-1---0----1------ +00100011010 10--0-0------1--0-0--0------------- +10100011010 -0---0---0-------0-------0-1------- +01100011010 0--------------------0-----1---0--0 +11100011010 -------000-00----------------0---0- +00010011010 ------------00-10--0---1-------0--- +10010011010 1-----0-1-----1-----1--1-----0---1- +01010011010 10--0----1---1-010100-0--0--0-0-000 +11010011010 11-1-0------0------1------0----01-0 +00110011010 10---1-0--1--0-0--1---0------0----- +10110011010 --0-0-------0--------1--0--1-1-1--- +01110011010 --------0-----1-10-10-0-1--1-0-01-1 +11110011010 ------1----1-0--1-0--1--0--0--0---0 +00001011010 0------0-----01-0---1--00---0-0--0- +10001011010 ----00-0100-------01-10--0-0-11--0- +01001011010 ---10-------001--0---0-00-----00--0 +11001011010 11---------0000-----010-01---1---1- +00101011010 0-01-0---1-1-0--1-----1--00----0--- +10101011010 ----1-0--1--------00--0--1-0-00--0- +01101011010 -0---------1--0-00--------0---01--1 +11101011010 1---0----0-00100-0100---01----11-0- +00011011010 -----01--11--100----0--1-----1-0--- +10011011010 ---0---0-1----0-1--000------------- +01011011010 --------------0-1-------000-------- +11011011010 ----0-0-1---0-0----10---10--------- +00111011010 ------0-00----0-1-0--------00------ +10111011010 --0-01-101--0---0----------------0- +01111011010 --10---------00--000-----0----0100- +11111011010 -0-0--------0------------010-----0- +00000111010 -----0-----------0-1--------0------ +10000111010 --1-0-----0-101-----1--0--0---0-1-- +01000111010 ----1-1----10--00--1-10-0-0-0-1---0 +11000111010 --------0-------0-------0----00-1-- +00100111010 1--0---0-00------0--0-----------0-- +10100111010 1--0--0-----11------00-0---------0- +01100111010 1------100--00--0--0--0-----0-10--- +11100111010 --1-00----0-0-10-----00-0---1--0--- +00010111010 -0-----0-0----10-------------11-1-- +10010111010 -0--0-1-000---1-----0--01-----10--- +01010111010 ---01--0---0----1--00-------------- +11010111010 1-0--10-------10---00---1-0--0----1 +00110111010 0---------------0-000---0---0---1-- +10110111010 0---0-011-0-000----0-----------0011 +01110111010 ------1----1--01-01--------1---100- +11110111010 01--0---0--0----01----1-----001---1 +00001111010 ----1--0-----1--0----0---1-0------- +10001111010 -----0-0----00--0-----000----00--0- +01001111010 ----------------1---00---00-0---1-0 +11001111010 --00-------00--1--01-0--1----1----0 +00101111010 -11-----11-10----1-1--0-00-------1- +10101111010 -1-1-10-0-0--0--------00--00--0---- +01101111010 ---0-1----0---1---0-0-----1-------- +11101111010 --000----00-0--1-1-00-1----0-0---00 +00011111010 -0----1---0-0-0---00---0-1-1---1--1 +10011111010 -0---01010-------1----1-11--------- +01011111010 -1---1-0-----0------0--------11--0- +11011111010 --------0--0-00--0--0-1----0----0-- +00111111010 -0---1-10-0------0----0------1---0- +10111111010 ---0--00-----0---1---0------------- +01111111010 ------0-0-0--10----0--00------0-000 +11111111010 --0--11001-0----0------01-0--1-1-0- +00000000110 -1-1------000-------100--000----0-0 +10000000110 01-0----1--1-0------0----0-0------- +01000000110 ---0-0-0001--01-------0--1----01--- +11000000110 00-0--0-0------0----0-0-00--1-----1 +00100000110 1----1--1-------1----------10-0--0- +10100000110 1--01--1----------0---------0-----0 +01100000110 --00----0----------------011011-001 +11100000110 -----0--00-----0--------1--0-----00 +00010000110 -1---10-0--------00---0----0------- +10010000110 ---100----0101------0001----------1 +01010000110 -----1-------0--0-------01---1-0-1- +11010000110 ---------0-0----0----1-01-------000 +00110000110 -001--------1----00-----1----0-0-0- +10110000110 ---1--1------------0-1--01---0--011 +01110000110 ---------1-0---00-0-0------------0- +11110000110 -0-0-0--------100-------00--------0 +00001000110 0---0-----00---00-----0---0-----0-- +10001000110 0---1-00----100--00-0-011--1----10- +01001000110 --0-----0--0--0--01--10-----0-0--1- +11001000110 00-100-----0--------1---------0---- +00101000110 -------00--0--1-------0-01--111---- +10101000110 00--1------------------0----------- +01101000110 ----0-00---0-----1---1--0-0-0------ +11101000110 11-0----0----1----0---0-------0---0 +00011000110 --0-0-01--11--0--011---11001------0 +10011000110 ---11--00--00-0-0--0----1----0--1-- +01011000110 ---1---0--1--0------0-------0------ +11011000110 --0-0-1---0--10--11--001---0----0-- +00111000110 -01---0---0-1------------0-0------0 +10111000110 01-0-0---0-----1---00-----------0-- +01111000110 1------1---0-0-----------0----0-0-- +11111000110 -------0---0-000---0---0--0-----0-1 +00000100110 0--1-----0-----00---11------1--0-1- +10000100110 -1--------0--1000-0-0----0--0---0-- +01000100110 -0--001------00-1--1--1-0-11-10--0- +11000100110 --0-----01-----1000-00---1--0------ +00100100110 ---0-------00000---0--1-0-000-0---0 +10100100110 10-----------1---1---0-----------0- +01100100110 -0---------0--------0-1------0----- +11100100110 1-----------0-000-0-------0----0-00 +00010100110 1-0--1-010---000--1--0---1-0---0--- +10010100110 -----0---1-------1------1-1--1----- +01010100110 ----0---10--0--0--00---10----00---1 +11010100110 ---1------0-00---0--01--0-------1-- +00110100110 0-1---10-1-----111------1-0--1----- +10110100110 0---------0--0---1-10----0-0--0--0- +01110100110 -----0-10-0-0-000-------0--0-10-0-- +11110100110 1--0--1---1--1----1---0-------0---- +00001100110 -001-0-0-01-0----11-----0-----00--1 +10001100110 0-100-1----------0--------0-000---0 +01001100110 -00-1--0-----0-1------1----1----1-1 +11001100110 -0-1--0---0--0-0-----10-00------0-- +00101100110 -1---0-0-0-00-1--0-0-----0-------0- +10101100110 --0---------0-111-1---0------1010-- +01101100110 --------1-10---000----1-----1-----0 +11101100110 -----10------1---1--1-0-0-0--010--1 +00011100110 -00--1-------00--00--------0---1101 +10011100110 1--------0---0-1------0--10----0--- +01011100110 ------010----1---0--1-1-1------10-1 +11011100110 -10--1--01------000---0----11--0-00 +00111100110 ---00-0------10-------------------1 +10111100110 1----0-0-0--1--0----10-01-----0---- +01111100110 --1---1----1--00---0-0---0-0-00-0-- +11111100110 --0-0-0--00-0-0-00---1------0--0-1- +00000010110 --------00----1---0----00-0--0---1- +10000010110 0-1001--00-1------0001-0---00---1-0 +01000010110 -1-----0-0---00---0--0---0---10---- +11000010110 ------------0-----------0--11-0---- +00100010110 -1100---1--1--0-1--0-----1----1--1- +10100010110 --00-00------0---10----0--01--0---0 +01100010110 0----------------0--------0---00-1- +11100010110 000----0-0----0---0---0-0---0---00- +00010010110 ------0------0-------------01---0-- +10010010110 ---1---0------------01--00---1---00 +01010010110 -00---------0--1-----0------0---0-- +11010010110 0-1-0---0-----0---0------------0--- +00110010110 ----0------1-10-1-----------00---10 +10110010110 --111-----1-------1--0-------1----1 +01110010110 --10-0---00--0-----0---0---------0- +11110010110 ---0--100-----0---0--00---111-----0 +00001010110 -------01-------0-01-1-----1------- +10001010110 -----00---011---111-0---0-1----0--- +01001010110 0------00---1-1---01--0-00-1--0-000 +11001010110 ----0------1-00-0--1-0--1------1--- +00101010110 --10--00-01--1-0----1--0-----0----- +10101010110 -0-00---1--000-1-1-00--0----------- +01101010110 -----000000--0------0----0--1--0-0- +11101010110 01--0----0-0000001--1-10000---000-- +00011010110 -0----0-------0--00-0-100-------10- +10011010110 ----------00-----1-0--000-0-0--0000 +01011010110 ---10----1---01--0----00-0--1------ +11011010110 1--10---1-0---------10-1---1--1-1-- +00111010110 ----01--0-1--10-1--00-0--1----0-0-- +10111010110 ---0---01-------1-1-------1--1-1--0 +01111010110 -------1------11-110-0--------0001- +11111010110 0----0-------0-0----------1---0---- +00000110110 -1--00000-----1-0-1-0-----1011----- +10000110110 -----0------------01-----0--------- +01000110110 --0-------1-1-0-----0-1-0---0---0-- +11000110110 -1--------------0--1-0--00-0-0-00-- +00100110110 0-1---------0011----0-101-----0--0- +10100110110 ----0-0--0-1--0----0--------0------ +01100110110 ----------1----0-----0--0-1---0--10 +11100110110 ---------010-00--0-1---00--0-0---1- +00010110110 -----1----1-0-01----1------------11 +10010110110 --0---10-----1-----0-0--0-----0--0- +01010110110 -0--000---0-0---------00-1---01-00- +11010110110 ------0-1-000-0---0100----0-------- +00110110110 1--1--------0--1-10-0----------0--- +10110110110 --1---1----1----0-100-0-00----10--- +01110110110 ------10-1---10--0-0----0-------0-- +11110110110 -1-------1----0------1-0-0---1010-- +00001110110 -0--------10-----0-------0-0------1 +10001110110 --0---0--0-1-1-0------01-00-------0 +01001110110 -0-0-----01-1--0---0-------------0- +11001110110 --0---10----10--0-0----1--1---0---- +00101110110 -1----0-------000------1--------110 +10101110110 --0--0--1-00-1-010-------------0--- +01101110110 ---001---10--00----------0--------- +11101110110 ------0--10---------1---00-0110---- +00011110110 0-----01-----0-----11-1-1------0-10 +10011110110 -0-110--00---1-0-1----0-100-----1-1 +01011110110 --------110-------1-1--0-0-000----1 +11011110110 11-01---------00-110--00-1-1----0-- +00111110110 -0-0--000-0--11--0---------0---1--- +10111110110 -0---0-0-----0--01-00---1--1--00-0- +01111110110 ---0---0-00---0010--0---------00-1- +11111110110 0--10-----------0----0----000------ +00000001110 -0-1---0--1--1----0-----0---0--10-1 +10000001110 ----0-00-1----1--0-0--11------0-0-1 +01000001110 --1-01----010---0--01--0-------0000 +11000001110 10----0-------1-----11-0----------- +00100001110 00-------1--1------0-1---11-0--0000 +10100001110 -00--0-0-0-00010--0---------010--1- +01100001110 ------1-1--1-----0101----0--0----0- +11100001110 --1--1-----1-0---1------0--00-0---- +00010001110 -0----0-----------1-00-1--00-1--00- +10010001110 -0-0--0-1-0--0-1000---------0-00--- +01010001110 0--------1-1-0-0----00-----1-----1- +11010001110 -10-010-----01-1--01-0---00-1--0001 +00110001110 ------0------1-0---1--0-----------0 +10110001110 -0---------00------------1-----0--- +01110001110 11--0-0-----00-0-10---01-0---0----- +11110001110 0-------00011----1----0--1---1----- +00001001110 -----0--11---10--0--------0-0------ +10001001110 0----00-0------11-------0-----1000- +01001001110 -0----10---1------------0---01-0--- +11001001110 0-1--10----0-01-0---0-0-10--------1 +00101001110 --------0---------0---0--0-100---0- +10101001110 0-0-0---0011----1--0--1-0----00---- +01101001110 ---0-0----0-----10-0-1-1----------- +11101001110 1---------0-1----1-------0000---1-- +00011001110 --0-0---------0-0-00--0----00-1---- +10011001110 -0--1-01----0-000-----------1------ +01011001110 -1-0-0-----0-01--0-----0----10-0-1- +11011001110 11----10-00010--------0-0--1--0---- +00111001110 -----0---1-----0---1---00---------- +10111001110 -0---0-0--1--1-----0---0110-------- +01111001110 --1------0-0--01-0-10-0---0------0- +11111001110 0-------0--------100----011-------- +00000101110 -------0--0---10---0-00-1--10--01-- +10000101110 -1------0-------0-----1-1-0---0-1-- +01000101110 0---0---1-----0--1-01-----1-1---1-1 +11000101110 -------0------1-0---0---0----100000 +00100101110 ------01---0--1---0-0-----0-------- +10100101110 0-----0-1--010-0000--1----0--0-1-1- +01100101110 -00-0---1-01----0--1-0--1------1--0 +11100101110 ----------0--0---------1-01000----- +00010101110 --001----1------0--10-----1-------- +10010101110 ---00---0--1--11-0-1-0--11-----1--0 +01010101110 -1-0-1--------0----1--00------1--0- +11010101110 ---------------01----0-----10-0---- +00110101110 0--01-0-----1---0---0-1-00-----0--1 +10110101110 0----0---0--0--1---01-----0---00--- +01110101110 0-----1----0----11-----01-00-00-0-- +11110101110 -1-----0--0-1-0-----1-1--10--1---0- +00001101110 0-0--001-------1--1--0--01--------- +10001101110 --00-1--00-----01-----10--------0-0 +01001101110 ------0---00-----0-1--10---0-1----- +11001101110 0-----0--0---------101--10-1001-0-0 +00101101110 0--0--1--0---1-1-----0-0---0------- +10101101110 ----00----1-1-----10-1-0--0-0001--- +01101101110 ---0--------0----------000--0------ +11101101110 -0-----------00--001---00-0--10-1-- +00011101110 ---------11----0-------1--------0-- +10011101110 00---------0---0-00-1---0110--0---0 +01011101110 ----1001--1--10------01--0----0---0 +11011101110 0----0------0------0------1-----0-- +00111101110 --1--00----01---00--000--1--0------ +10111101110 1---0-1-0--1-1--0-----10--0---1-1-- +01111101110 --1-00---0--0----01---------11---1- +11111101110 ----0-----01---000-1-10---0--000-0- +00000011110 0------101-0--0-1-00---1-00-0-0---- +10000011110 --1--0-11-0--0----0-0----00-------- +01000011110 1------1-0-1--0-0-0-1---------0--0- +11000011110 00--00--10--1-010------0-------00-1 +00100011110 -----0-0--010-1-0--0---1--1-1--1--- +10100011110 --0------01---0----1--0--1----01--- +01100011110 -0---0------------1-------0----10-- +11100011110 -----10-0-1--1----0-00---0--------- +00010011110 -----11-------1---------01---1--01- +10010011110 0----00---11-10-0-1-10--------00--1 +01010011110 ----1---1---------1---------------- +11010011110 0-10---00----01----0---0001---0-00- +00110011110 1----0-00----0-1----------0--10--0- +10110011110 --00-1-----0-0---0--01--1---1------ +01110011110 -00-0-10-------0-00-----0-----11-1- +11110011110 00-0--11--101------------------00-- +00001011110 ----0-100-----------00--0-1--0----- +10001011110 1------01-1--0---1-----1-0--11-0100 +01001011110 ------110----00-00------1-100----0- +11001011110 0----0-1------1----1----0-0-10-0-0- +00101011110 -1-----1-0-00------00--1-----110--- +10101011110 --1--1-1------------01--1--0-00--10 +01101011110 --1---1---------00---000----001---- +11101011110 0011---0-------1-10--0-01001------- +00011011110 -0----------0---0----00-0---------- +10011011110 0000----1--0--------1--------100-1- +01011011110 ----0-------0--1--1-0-----10---00-- +11011011110 0-01----01-1----1---0-----0-001---- +00111011110 00-0------------10-1---------0----- +10111011110 0-----0-1--0-1-0----0--1----000--0- +01111011110 ------0-0---100--------------0-1--- +11111011110 ---0------00--1-----1-1-001-------0 +00000111110 1------------00-----101-------01--- +10000111110 ----0--1-----00----00-10----------- +01000111110 -0---0---01-0--0-0-00-----0----1--- +11000111110 ---1----0-1--------------0------0-- +00100111110 ----0-----0-0--1------0-----------1 +10100111110 -----0-----0-0---01-----001-----0-- +01100111110 010--00----0-0-0------1-----1-----1 +11100111110 0-0--------0--10----1-------------0 +00010111110 01-0-11101--0-0-0--000-------0----0 +10010111110 -10-------0------1-0--0------------ +01010111110 0---1---00001--------0--00------000 +11010111110 0--------0-0-1-1---0----1----0-1--- +00110111110 ----1-0-1-01--01-01----0-0--0-0---- +10110111110 --0---1--------1----1----0---0-1--- +01110111110 -0---1-0-10-0--0-------------10--0- +11110111110 -1-----0---1---1--------1-0-0---0-- +00001111110 ----00--01--------00-0-----0-----01 +10001111110 ---0---1-----0--00---0----1--001--- +01001111110 1--1----0-1--0-1------0--0---0000-- +11001111110 -1---------------0-1-10--0----0-0-- +00101111110 ----01-------001-0----------00-0--- +10101111110 -0--------1---0--------------1----0 +01101111110 011-0------------------1--0000-0--- +11101111110 0------0--10100-0--00--0----------- +00011111110 ------1----100---001--0---0-0--0--- +10011111110 -00-1-0--0-0--0-----0-0--10-0-1---0 +01011111110 1-0-1------01-1-0--------00-0--00-- +11011111110 --0-11----1--0---0---11--------01-- +00111111110 -0----10-01010----0-----0-----1--1- +10111111110 ----1---1-1----00-1-0-0--0---1-0-01 +01111111110 00-0--0-11--1-----00-11--0-0-11---1 +11111111110 1-------------1---1-00--0-0-1-----1 +00000000001 --0--1-10--------00---0-1---01-1--- +10000000001 ---0----0--1---1-----0----11------- +01000000001 ------1-0----0-1-001-1--0------0--- +11000000001 1-0---00-------0------------0---1-0 +00100000001 ---0---0-000--0-----1---1----0-0--- +10100000001 ---0---00---0------------01-----0-- +01100000001 ----0---0-------1----0--000-------- +11100000001 -0---1-----0-0-00000--0--1-00--0--- +00010000001 ---1-1--0------0000---0-------1---1 +10010000001 --0--1---10-----11--0-001-0-00--0-- +01010000001 --0----0----1----------00-------00- +11010000001 ------0----00-----0---0-1------111- +00110000001 --1---10-----0----------1-0-00----- +10110000001 -0---0-----1-10---0--------1------- +01110000001 -0------------0-1------1--00-0----1 +11110000001 -----001-0-0--0-0-0--0---1-0--00--0 +00001000001 ----0---0-0-1-1-1--0--1--1-0---01-0 +10001000001 --010--0-----0-----0-----1--0----0- +01001000001 -0--0---0---0----0-10----------1-10 +11001000001 ------0---0-------0001----0-----00- +00101000001 ------0--0--10-----0---0------110-- +10101000001 0--0-------0-------0-00-1--01----0- +01101000001 -0---1-----0------1---0-0-0--1----- +11101000001 ------------1-----------0-----0-1-- +00011000001 0-0-------00-1------00------01---00 +10011000001 -------01--1--011---0----0-----000- +01011000001 --------0010--------1------10---1-- +11011000001 010-1-110---1-1-0----01--0--00-01-- +00111000001 -----000-0----0--0---------00010--- +10111000001 -0-1---1----1-010----1-0--0-------0 +01111000001 ----1--000--10---0-----0-0--------- +11111000001 ----1-0-01-----10--0--0--0----0-0-1 +00000100001 -------0---01---------------0-101-- +10000100001 00---------0-0---0-----00010---1-00 +01000100001 --0-11--1-----1--0--1---0-0---10-00 +11000100001 -11-01-1---000-01-----000-0---00-11 +00100100001 ----0---0--0-00--0--01---0-1------- +10100100001 ----------------0--0--0--0-1-11---- +01100100001 ---0--0-1011-------0--1-----0---000 +11100100001 0-00------00---1----10------0-----1 +00010100001 0--------0-01--0-1-111-001-----00-- +10010100001 ----1--0-0-0-10--10-0---00--1-0--1- +01010100001 1---1--1----1--------0--1--0--0---- +11010100001 -1-------------10---------0-0--0--- +00110100001 ------0---0--00-1-000-------0-0---- +10110100001 -0--0-0--1---11--1----1-----0------ +01110100001 1-1-10-00--0-----0-0-------0------- +11110100001 0---00--0----------010--0--0----0-- +00001100001 -0-0--0------------1-0--1-00-1---0- +10001100001 ----1----1---1----1-000----01-0---- +01001100001 ------0--------------0-0-----0--1-- +11001100001 -0--0---0--1---0-0--00----1----11-- +00101100001 1--0----------10-1-----0-1--------0 +10101100001 -00-----0--0-----0-----1--1--10--11 +01101100001 ----0--1-1--0----0--1--0-0---00000- +11101100001 -------11--1----00---------00------ +00011100001 0----1-------------0--------0----1- +10011100001 --0-0-------1--1----0---11------0-- +01011100001 --0---1--0-----00-0---1--0----1---- +11011100001 001--0011--01--1--01-----000-1----- +00111100001 -0--1--1---0----100---------0--000- +10111100001 --0-10--0-00--1--00100--0-1-----1-0 +01111100001 0---1------0--0----0--00---------1- +11111100001 --0--0---1----001----------10----0- +00000010001 --1---11----0---1--0-------------1- +10000010001 ----1------0--0-----00-0--0-0---1-0 +01000010001 0--------00-1----00-----0----01-1-- +11000010001 1-000----0---0--00---0----1----1-0- +00100010001 --01--0-0----1-0--0----1-----10-0-0 +10100010001 10-1---01-------0-010-------------- +01100010001 -------0101--0--0--010---------0--- +11100010001 1------1-00------1----------00--01- +00010010001 -------0--0---1---1------0-----1-1- +10010010001 ---------------------------01---1-0 +01010010001 0------0-0-----01-0--1--0--00--1-0- +11010010001 0-0---10-00-1-00---0---1-0--0--00-- +00110010001 0-1-0------0-0--------0--1----10--0 +10110010001 0--0-1--0000--0-0-1------01----01-- +01110010001 ---0---0-0-------1--0-----0-00----- +11110010001 0---000-11--------00----------0-1-0 +00001010001 1-0-0-1--------0--0-0---0--0---101- +10001010001 -0--------0---1--00-----001--00-110 +01001010001 -------0-0----11--0--------00----0- +11001010001 -----------0-00-0001---0--0-------- +00101010001 0--0------00---0----0---0---00--0-- +10101010001 --111----0-1----0-0---------0---0-- +01101010001 0-0---0---00-1-------01---0--100--- +11101010001 0-101---0-0----0--------1--1--0-0-- +00011010001 -0--0--0-0-10--1-0-10---1--1-0-1-0- +10011010001 -0------10----0----00----0-1----1-1 +01011010001 -----01000--0--10---0---0---0010--- +11011010001 0----00------1--00--0------------0- +00111010001 ----0-1-0-0-000-------0---0--1---0- +10111010001 -----0----00------0--1-1-00-00---0- +01111010001 0-01-1-----101--00------------1-0-- +11111010001 --00-00--0----0-1----0------------- +00000110001 0-00-010-----1-----0--------0--1-0- +10000110001 0-------10---1---1-1--0---1-1----10 +01000110001 ----0---1--1-0--11------0-0100--0-- +11000110001 0--0--------10-0-------0-1-0---1--- +00100110001 ------1---1--------1----0--------1- +10100110001 0--110--00-00----1----1-1-0-----0-- +01100110001 100-------0--------0----0--01--1--- +11100110001 ----000----000--111-1-----0--1----- +00010110001 --01------0-0--1-00-0-0------0-0--- +10010110001 ---1-0--00--0-----10-00---1------1- +01010110001 -------0010------0--1--0-0-000--1-- +11010110001 ----0------1----1----0-0--0-10--0-- +00110110001 0---0---0-0-------0---------------- +10110110001 -0--------0-10---0--0----0----101-- +01110110001 ------1----0-0-000-----------111-0- +11110110001 -0------1-1-1-------01-----10---00- +00001110001 0----------------01----------0---0- +10001110001 ----0----0------0-----01-10----10-- +01001110001 00--01-----0-0--0-0-----1---0------ +11001110001 ------0--11--00------0---01-1-0--01 +00101110001 1---1------000--00-11---1---1----1- +10101110001 -0--0-1-11-----------0-----0------1 +01101110001 10--0----0----0-01-0--0----0-0-1--0 +11101110001 -----0-01-1------------0-0-0----0-- +00011110001 1-00----0-0----00-----0---1----11-- +10011110001 1-----00---------------0-0-1--100-- +01011110001 ------0--0--011------0-1-1--------- +11011110001 00-0-001--010--0------0----0--1-0-1 +00111110001 --1--00-0-1--0---------0--111-100-- +10111110001 --01--00-00-0----0----------0--0--- +01111110001 -11-0--0-01-----0-0-0--1--10---1-0- +11111110001 -00---1-----01--10--0100-1--00----- +00000001001 ---00---0-0--0-0101---0---0-------- +10000001001 -------0---000---1--------0-0-0--1- +01000001001 --000---0----------0---1---01--0-0- +11000001001 ---0-00--0-0-10---00----0-0-------- +00100001001 ------000-----0----1--0----1--1--01 +10100001001 00--0-1----0------101--1-0---110-1- +01100001001 0--10-0-----1-1-1-----------01----- +11100001001 -0-010-0--00---1-10--0-------0-0--- +00010001001 -0-100-0-0-0--1--1--01---1--0-0---- +10010001001 ---0-0--0------0---000-00------0--- +01010001001 ----------1000--1---0---0-11--0--01 +11010001001 -----1-0--1-0----0---1---1-------0- +00110001001 1-1------0----10----00--0---0-1---- +10110001001 0-0-0-------0--0-----01-1------00-- +01110001001 --0---0--1------------------------0 +11110001001 0----0-------00-0--0-------0--0001- +00001001001 --0-1--1--010-0-----11-01-010-0---- +10001001001 -1-1-1---10--10------------00-1---- +01001001001 ------------0--1-0-000----0---0---- +11001001001 --00-0------0-0-0----1-0-----0-0-01 +00101001001 11--------0----0------------------0 +10101001001 --0----0-0-10---1-------00-0---00-- +01101001001 ----0-0--0-------1-0-0----------1-- +11101001001 -----000---10-----------0-0---0-0-- +00011001001 0--------10-----1----1-----1-----0- +10011001001 -0----10-0------00-0--1-----0---0-- +01011001001 -0----0-0-11-0-0-1-0-00-0-0-11-1--- +11011001001 -0-00-0-00---0---01-------1--100--0 +00111001001 0--------1-------0---------100----- +10111001001 ----1-0-0--00--10-------1-1------1- +01111001001 0-0----0-0----1---000--0-0--0------ +11111001001 ---1-00--0--1--00--1---10-------0-- +00000101001 1---0-------------0-0----0-------1- +10000101001 --0-1------0-----------0-----10--1- +01000101001 1--01------0--000-----1--1---1--1-- +11000101001 --0---01--1-0------00---00---0--0-- +00100101001 ---10-----1-----0-----0-11---1--0-- +10100101001 001----1---0--1-0-0----------0-0--0 +01100101001 -000--0--10--0-----1-0--0---0----0- +11100101001 -0----1---0-00-----0-1------10-0--- +00010101001 -----0--0--0--00---00---00---0----1 +10010101001 -0-------0-1-01-0--------0--0-0--0- +01010101001 -10--------0-10-101----11--0------0 +11010101001 0----0-0-0---0--001-----0-0-11----0 +00110101001 1-------0-------------1-010--0-0--- +10110101001 ----00----0-------1--1-0011----1--- +01110101001 1-----0---1-1-----0-11---1-1------0 +11110101001 ---0--0-100--0--1---01-10---------- +00001101001 --0--------100--1-1-11-------0----- +10001101001 -------0---00--01---------1--0-0--- +01001101001 ------------------10-------1--11--1 +11001101001 -1-0-0----0--0--1--0-----0---0----- +00101101001 ---0-0---1----------0--000----1---- +10101101001 -------0-0-----0----------0------0- +01101101001 00--1----00-1-001----0---------0--1 +11101101001 ---000-0----1-----0-010-0---------1 +00011101001 --0--01-------0-0---101-1----0-1-0- +10011101001 -10-1-10-0------0----0--------1-0-- +01011101001 0----0-0-0--0---0-0--0--0-------001 +11011101001 -----1-----0---110---0----10------- +00111101001 -0-0-----0-----0-----0-----0-0----- +10111101001 -0-0----------0-------0------------ +01111101001 ---010-1-11--0----0------1--0--0--- +11111101001 101-----0-0---------01--0---10-1--- +00000011001 ----1------0------0-----0---------1 +10000011001 0---0----00--0------0--1-------1--1 +01000011001 1--0-----0--------0---1-----------0 +11000011001 11-1-1-0----1-0--1---0---1----0-1-- +00100011001 --10------0-------00---1------000-- +10100011001 ---1--00----1------01------1------- +01100011001 --0-----0------0------------0------ +11100011001 0-000----01----1-1-----1---------0- +00010011001 ---10--------1--00----1------1---00 +10010011001 0---1----1---------0-0------1-1--0- +01010011001 ---0-01-----1-0------0----1--0---0- +11010011001 1-------00001------------1-0----10- +00110011001 101--0--1--0------1-------1---0---- +10110011001 --01---0-11-0-----0---0-1---0------ +01110011001 00-------------1-01------0---0--0-0 +11110011001 10-------00--000---1-----1--1--0--- +00001011001 ------0-----0----0----------0-----0 +10001011001 ----00-11-0-0-0-------1-1--0-----00 +01001011001 ----0-0---0--0--110----1----0-0---- +11001011001 -------0--0-1--00-0--1----0---11--- +00101011001 -0------1-------100--0-1--11-----1- +10101011001 11-1--1----1----0-------0-0-------- +01101011001 0---0--0---0-0---0----01-0---0----- +11101011001 ----10-----0--0------------1010-01- +00011011001 -1----0--0-------1--0----1-0-0--0-- +10011011001 10-11-----11--------------10-1--0-- +01011011001 ------01-0-10-1---10--00--10---0--- +11011011001 ------0-----0---1-00------1----0--0 +00111011001 --------11---0---0--1-0----10-----0 +10111011001 ---10-----10--------------0---00--- +01111011001 0-----1----------0----0-11----1-0-1 +11111011001 00--0-0--0--00--0--00------00---0-0 +00000111001 1--0-----1-1-1-------00-------01--- +10000111001 1-0-----0------1------0-0-----0-1-1 +01000111001 0-0----1-101-01----0-1---1------00- +11000111001 -10-0----0--000--------------00--0- +00100111001 00--0-------00--------1---0-00-0--0 +10100111001 0-0----01----------00--011--0-0--1- +01100111001 -0------------0010010--10-----1---0 +11100111001 --------0010--------1-000-01----0-1 +00010111001 --10--0----0--1--0---0----1--11-0-1 +10010111001 0--0--0--0-------1-0-----0--0----00 +01010111001 0-0----0--0------01-0--1----01-01-- +11010111001 ----0--------------1--------1----00 +00110111001 ---10-------------0---0--0-0-0-1--- +10110111001 -10--010----1---0-----1------------ +01110111001 0--1-----0000-----00---01-0--0----0 +11110111001 -1--01------0---0---1010---001----- +00001111001 -----------00-1----011-------11---- +10001111001 --0---0------0-0----0--0-1-00--0-1- +01001111001 0-------1-1-----------0-00-----0--0 +11001111001 ----0-0-0--111-0110---0--------00-- +00101111001 ------0-----1-----------10-000-0-0- +10101111001 --1001--10--1------0-000----0---0-- +01101111001 1---0--1----1----0-1--0---0---00-1- +11101111001 0---------000---1----0------1----11 +00011111001 ---------0---0-11--10--0----010-0-- +10011111001 --10-1--0-1----0------0--010------- +01011111001 -1--0-1-----0---1--10------0-0-0--- +11011111001 ---10-11--------0-010--0-1--------- +00111111001 1---1---1-----0--00---1-------01-1- +10111111001 ---01--000---0------1---------01-10 +01111111001 ------00--0-00----0-1--10--0-11-100 +11111111001 -0-0-1-----0010-----1---00-1----001 +00000000101 -0----0-1----10----01----0--01-1--- +10000000101 -0---0-10-----------0-0-11--0--1--- +01000000101 -1--0---0----00--1----------00--00- +11000000101 ---0-0--0-011--------0---0--0----0- +00100000101 -0-----0-00-000----1---00----000--- +10100000101 -0--------0---11---0-------01-00-0- +01100000101 -------0---------1-1--0--000-1----- +11100000101 00----01---1000-1---00------010-0-- +00010000101 00---1----------0--0-0---1--1----0- +10010000101 --11-0--------00000-0--000------00- +01010000101 -0--0----10-0-1-00-0-000------0---- +11010000101 1---1---1----100-0---10------000--0 +00110000101 -0---------01--1----00---10----0--- +10110000101 --0-------1-01---0---------0-----1- +01110000101 ---0100--000-0---0----01--00------- +11110000101 -0---0-0-0----0--1----10------10-0- +00001000101 --0------0-00-1--1-----0---1--1---- +10001000101 ---0---1----00---0---10-1--0--0---- +01001000101 ----0--1--1-00--0----1------0-1---0 +11001000101 -0---11----11-0-1-----------0---0-- +00101000101 -0------0----00-----0-------0--0-0- +10101000101 ----1------0------0----0-0--0000--- +01101000101 011-0-0--0--0-0-0-10---0--0----1--0 +11101000101 -0--000-------1--0--------0-----0-0 +00011000101 ---0-1-0-----------0---------0---1- +10011000101 --0-----0-10---1----------01----0-0 +01011000101 ---------------1-----00-----000---0 +11011000101 1-----0---1----00--00--0----------- +00111000101 0----00-1---01---0--0--010-1------- +10111000101 -------0-0-0----1-----100---000--01 +01111000101 0--0--------1-----1-0-0-1--1-1-0--- +11111000101 1---1-0-0001---11----------0---0-11 +00000100101 1----1---------01--1--0-0-1----000- +10000100101 0-0000-0--0-----1101-----0------1-- +01000100101 ---1----------1---0---000-0-0--10-- +11000100101 10------0-0---00----1---0000--0---- +00100100101 ------0--1------0--1-10111--1-----0 +10100100101 0--------1-0---00-0--1--11-1------1 +01100100101 -------------1-0--1-0-0----0001-0-- +11100100101 --1------0----11--10--1------11---1 +00010100101 --------1-0--1001------1--0-------- +10010100101 0---0-1---1-101---010--0---01----1- +01010100101 -0-0-----0---1-1---0-1-1----1--10-- +11010100101 -0-0----1--0----0-10--------10----0 +00110100101 -------01-0---00--0-01-0---------10 +10110100101 ----1--0---0-----0--------0-0-----1 +01110100101 --1----0-1----0----00----1-0-0----- +11110100101 -0-001-1-0----1--0----0---------1-0 +00001100101 -1--00---100-0--0-------------0-0-- +10001100101 ------00---------1---0--00----01-0- +01001100101 -----00--00-0-00-----01--0---0--0-- +11001100101 -01-0-001---10--1-1--1-------1----0 +00101100101 --00--1-00-----0-0----0--0-0--1---- +10101100101 0-----1--0---------0---0----0------ +01101100101 ------0-0-------0----1-1--0---00-1- +11101100101 ---0------00-0-------0-0000--0----1 +00011100101 0----0-0-----1-1--0--0---100--00-10 +10011100101 -01--0-0-0---0-0----0-01---------01 +01011100101 0---0---1----10---1----001-0---0--0 +11011100101 --00-0000--1--000-1--0--1-01-----0- +00111100101 -----1--00------1110-0--0---0-0---0 +10111100101 -------0----1--000--0----00--0--0-- +01111100101 -0-0---------0--01-------0--0------ +11111100101 1-0-00--000------1-------1--------- +00000010101 --0--1--------0--0-0----10------0-0 +10000010101 1000------0----1--00--001---0-0---0 +01000010101 -00--00-----1--------0-----1------- +11000010101 --0--001-------0-------10--0--0-0-0 +00100010101 0--00-1-----0-------100------0----- +10100010101 -0---0----00-0--100-0--11--0-0--0-- +01100010101 -10-10--1-0-----00-1-0---1--01---10 +11100010101 ----------00-100--0-1---1--001-01-- +00010010101 ----0---00001--1-0--------01-0--0-- +10010010101 0-----0--------1-11------0--------- +01010010101 10-10--1------0-----0--11--1------- +11010010101 -----00-0-1---------11-0-0--------- +00110010101 -----00------1------0----0-----0--- +10110010101 ----00--1---1-----1--0-------101--1 +01110010101 ---000-------1-----------0----01-0- +11110010101 10--1--------00-------1--00--10---- +00001010101 --00-0----1-1--01------0-0-1--1---1 +10001010101 1----1-00-0------0-01-0-10-0-----0- +01001010101 0-0---1--0----0----1--------0---0-- +11001010101 --------01--------0----1--000-0-1-0 +00101010101 ------0---1--1-----10-------------- +10101010101 0-0--1--0----0-11-------0---0-1-0-- +01101010101 ---1--0-1---0---0----01-0-----1-0-- +11101010101 ---------------10---0--0----1-1-01- +00011010101 00---0----11-0-----0---0----------- +10011010101 --0-0--0--00---1-0-0--------0------ +01011010101 ----------0---0100---1-001-0----1-0 +11011010101 -1-0-------1--0---0--0-1-0-0-----0- +00111010101 1--1-------00---00----0--0100---0-- +10111010101 10--0--0--00-01---01--0-0-10---0-1- +01111010101 -1-001-1---0---0-0-10--0--0---0--00 +11111010101 1---0-----0--1---0--0------1----0-1 +00000110101 1----01------------0---10-0-0------ +10000110101 -01----0-1-----111--0-0--1-----1-1- +01000110101 1-01---0--0-1-1-0---0--0-01---1--00 +11000110101 0--0-----0---1-----0-0-0-0-0----0-1 +00100110101 ------1--1-0----0-0-0----0--0--1--- +10100110101 ---0---011--------1-------00----0-1 +01100110101 -0-0--0-----1--1011--10-1-00--0---- +11100110101 ---01------------1-0----1--0--0-0-1 +00010110101 --------1---1-0--1-00--10----0----- +10010110101 0--0--1011----0-0----1-------1----- +01010110101 -----0-0--00-0-------0-11---00-1--- +11010110101 -----0-0----01-----0---0-----0--0-- +00110110101 ---00-----0--------11-----0------0- +10110110101 00---00----000-----------0-0------- +01110110101 -0--01--0---1---0----0010-----0---- +11110110101 1--10-1-1-0------0--1---1-1----1--- +00001110101 -0000-0-0----1--0------01-01--11--- +10001110101 -----00----00----0-010---0--0---0-- +01001110101 ---0--0-------1-00--1---1---------- +11001110101 ----1-01--1--001-----1-----100-0--0 +00101110101 1----0-0-1-----1-0---1--0---0------ +10101110101 -1---0-000--00--00-1----1---00--0-- +01101110101 -0---0-0-0-----10---1------0------- +11101110101 1000--0-------0-------0--0101------ +00011110101 --00--------0-00--0---1--0----1--0- +10011110101 0------1011---0----1---0-----1----- +01011110101 ------1-0----00011--01------1-1--0- +11011110101 -01------0----1--------0-0-0------0 +00111110101 0-1----00--1-----00---1------------ +10111110101 -0---1----0--1----0-----1---0-000-- +01111110101 --0-----1--11--1----0---0----0---00 +11111110101 ------1-10--00----11---10-----0-0-- +00000001101 -1--------01--0---0----0--0-0-1---- +10000001101 --000----1-0-------1----0--1-1--1-1 +01000001101 1-110------1-------0-0--00--------- +11000001101 00-0---0-0----0-1--0-0-0--0-00--0-- +00100001101 ---00-1----0--0-------0-1-0------0- +10100001101 0-0-0-0-----1--1-1------0----1-0--- +01100001101 ---------------11----0-----0--00-1- +11100001101 ----0---------0-----0--1-0---1--00- +00010001101 --0-----------01--01------0-00---0- +10010001101 ---0-------1-----0-0-01--0----0-0-1 +01010001101 10-00----000--100------0-0-1------- +11010001101 00--1---1-------0-------10---11---- +00110001101 ------1101-100----1---000--0-1---00 +10110001101 -1------1----0-0-----0-----0-00-000 +01110001101 ---01--1-10-0----11---0-1-0-0----0- +11110001101 0-------------0---0-----0-----0---- +00001001101 1----0-------11--------0-1---1---0- +10001001101 ----1-0-00-----1--00---111-----0-01 +01001001101 -11----0--1------0-0-----0---11---0 +11001001101 -0-00--1------10-----1---0--------- +00101001101 0---0-0--0-0-11--0-01--0-10100----1 +10101001101 0---00-0-11---1----11----1--1----0- +01101001101 -0-----0-0-00-0-0--1--------------- +11101001101 --10-1---------0-1---1---011-0-1-1- +00011001101 --0-----0----1-0-0--00-0---0--0---- +10011001101 001----11-0101-000---1---01---0---0 +01011001101 ------11---0---01-0--01101-0--0--0- +11011001101 -0-1--1---0-----------1-00--0-0---- +00111001101 -0-------0---0----0------------00-- +10111001101 -1-----0----01--1---0---1------0--- +01111001101 0---110-0010--010--------1------0-0 +11111001101 -1-1-0---0-1------1----0----11-0-1- +00000101101 0--0----0------010-00-------0----1- +10000101101 ---0--0---110-0----00-----0-0-1--01 +01000101101 --100--0-11-0----1-1--1----00---1-- +11000101101 0---01-------00--1------1-----1--10 +00100101101 --0-0-----0----1--0-00-00--0-10-0-0 +10100101101 ----00----0-00----0----0----10----- +01100101101 ---1---01-00-------0---0101111011-- +11100101101 -----1000---00-1--0--001--0--01---- +00010101101 -0----00-0--0------1------0001---0- +10010101101 ---01----1---0-00-------1---------- +01010101101 ------0-000----1------00---0--0---- +11010101101 001----1---1---0-----0-010--1----0- +00110101101 -0-0---0----010-00-000-------1--0-- +10110101101 -00---------0-0-0--1--1-00---0----- +01110101101 ---1------1-00-01--0----------00--- +11110101101 010------------0-0--------1---0---0 +00001101101 ---00----0---10--00----00------10-1 +10001101101 -0-----10-000----0--1---1-----1000- +01001101101 --00--0----1---01000-00011---0-0--- +11001101101 1-----1-----1-0-0-------------0--1- +00101101101 -----0-----1-1---01--0---0-0------- +10101101101 -0-000--1-0---110---1-11--0-01--10- +01101101101 --0-0---110-0-01-0-1-1-0----001--01 +11101101101 1--00----0---0-00--1-0-1-0-1---1--0 +00011101101 00--0-----1--01--0----0-1--0-0---0- +10011101101 0-0---------100-1--0---------0----- +01011101101 --1----------0--0-10---0--1----00-- +11011101101 -0---0-1--1--0---0-----1-1---0-1--- +00111101101 0-----0-----0--0----00----00----0-- +10111101101 --1----001-00-----------00001------ +01111101101 ----1--000-------0----0--0---0---1- +11111101101 --00---0---0--------00-0-01-0------ +00000011101 -000-1-1--0--10-1---0-1--1----1--1- +10000011101 110--1-0-------1----------0-----0-- +01000011101 -101--1-----1010-1-----1--001---1-0 +11000011101 ------1-0-----0-----0-110--1------- +00100011101 -0-0--1----0--100-----------0-100-- +10100011101 -0-0---1--0--0-0--0---10-011----1-- +01100011101 ---0-------0001----0-1--101---0--0- +11100011101 1-----111--1-0--1--1----1-0-------- +00010011101 1-01-1-1----1-----1-0--1-------01-- +10010011101 --1110-1------00--0-01----0-0---0-- +01010011101 11--0-----1-------00--0---0----0-0- +11010011101 --1110-0-----1--------1-0---------- +00110011101 -1------1-0-----1-1-----1-1-10---0- +10110011101 -1001-1---1000----1---------------- +01110011101 ----0------0---0--01---00---0-0--1- +11110011101 --10--0-------0--0------0--0-0--0-1 +00001011101 1--0-----1--01-----0-1-0-000------- +10001011101 ------------0-----1------11-0----1- +01001011101 0-------01-00----1---0--00-1--0-0-0 +11001011101 1--1-0---00---11----1-0--0--0--0--- +00101011101 ---0-1-1-0--0----1-1----1------0-1- +10101011101 1-1------0-1---------0---1--00----- +01101011101 -0---1---1------1-0-0--0--0---0-0-- +11101011101 --0--1011-0-0--0-00-1--0-----0-10-- +00011011101 0-00------00-----00--0-------0----1 +10011011101 --1-0-1--010000-11-10-01--0---1-101 +01011011101 0-------0--0---1--1-00----------0-- +11011011101 -0--------0---0-----00----0-0------ +00111011101 ---0-00-0-1----00-------00-0001---- +10111011101 ------111----0-1---0--0---01---110- +01111011101 ---01--0--0-----0---1---------0-011 +11111011101 --0-00----0-1-1---1----1----------0 +00000111101 -------0--0---00---1-1-----0-0---1- +10000111101 -1---0----11--1--0-1-----0-100--001 +01000111101 0-1----1--1-0--1--1----1-1---0--01- +11000111101 -1---01------0--01-------0---0000-- +00100111101 ---00-0---01-1------11-----0------0 +10100111101 -------00----1-0---00----1-0----0-- +01100111101 --1-----1-0---11-----11----0----0-- +11100111101 --------0---0---0-0---1---0-------- +00010111101 -0---0-------010--0-1-1-00--------- +10010111101 -----------------010-01----01-1-10- +01010111101 -10----1----01--0----000--10----00- +11010111101 -----0--0---01--0---01---0-----00-- +00110111101 --0---------------------1--0-0---11 +10110111101 0----100---------00-0--0--10------0 +01110111101 -010------01-1------0-1--------0--0 +11110111101 10----------111--011---10---0--0--- +00001111101 001------00-0-----0-1------0-0-0--- +10001111101 -0--1--0---0-----1------0------0--- +01001111101 -----0-00-0--0-0------00----------- +11001111101 ---00-101----1---00---011----011-0- +00101111101 ----01-----0100-000----0------1-00- +10101111101 ---00-0--0----0-01----------10--0-1 +01101111101 -0-00----0-1-1------0-11-0---0---0- +11101111101 ------1-000----10-1---0---0-0010--- +00011111101 ---1-0--01-0--0------1--1--1-00--0- +10011111101 0-1-0110---000--1--0-0-------000--- +01011111101 --1------1------0-10-0-0----0------ +11011111101 ----00---00----00---1-1--010-1--1-- +00111111101 ----010---------0----10-00-0---0-0- +10111111101 -0-10-0----01---0---------1-----1-- +01111111101 0--0------------1----010----10----- +11111111101 ---1-0-0-0-0001--1-00-------10--1-0 +00000000011 ----0----0--1--10--------------0--- +10000000011 ------------------0-1---0--00--0-1- +01000000011 0---1--0-------0---10------10--0-00 +11000000011 ------0-00-----110------10--1---1-- +00100000011 ----------01---000---1------------- +10100000011 1---001--10-----------0-01--1-0---- +01100000011 -----0-----0-0--------0----00---00- +11100000011 -10-------1---0-0--00-0---000------ +00010000011 --01-1-0---00-1-0----00-1--10-----0 +10010000011 ---10--0------0---1--00----00------ +01010000011 100--0011---0--0-0---0--1-0-0-----0 +11010000011 -0-1---00---1---11--1-00--0--0-0--- +00110000011 0-0-10100-0-0--1-00--00----0---0--- +10110000011 -0-0-0----01-0-0-------1---0--00-0- +01110000011 0-------0----0-0-0--------00-1----- +11110000011 ---0--00--110----10--000-------0-0- +00001000011 -00-0-1--1---0-00---1----------1--1 +10001000011 --00--010------0-1-0-0-00--010-0--- +01001000011 ------01-0--1-0-10-0-10----10-0--0- +11001000011 ---00----1-0--1-----0--0------1---- +00101000011 -01--01--00---0--0-1------0-0-----1 +10101000011 --0---0-1-0-1--0-0---------01---00- +01101000011 -----0------1-1--100-000--1--01---- +11101000011 0--11-1-0------1---0----10-100---0- +00011000011 -------1---1------10-----01-1--0--1 +10011000011 -----1-------0---0-0---0-1--101---- +01011000011 --10-001-01-0-----------01--------- +11011000011 ----------0--0--0---0---------0---- +00111000011 ---00-----0-0-----00------00-1-1--0 +10111000011 0-0-0---1-0-0-1-------11-0-11------ +01111000011 0-----000-----0----0---0-0--------- +11111000011 ---10--------1---1-------0--000---- +00000100011 1------10----1---000----------1-0-- +10000100011 -1--------1--1---1---11-----0-0--0- +01000100011 ---1---00---------------0------0--- +11000100011 ------------00-------0----1-------0 +00100100011 0-0-1------------------0--0--1--0-- +10100100011 -------0-1--------00--1--00--0----0 +01100100011 ---0---0-00------10--0-01----00---- +11100100011 1---01--0---00--0-------00----0-1-- +00010100011 -01----000-------0----0----0----1-- +10010100011 --00-00--0-00---11-10--0--0-0--1--0 +01010100011 ---1-------1--111-------1-1----1-11 +11010100011 ----0-0--1-01--------0------110---- +00110100011 0--1--0-00-0---0-0-01-0-----0--0--- +10110100011 -0001--00-0--------10--01----00000- +01110100011 0--0-1-------1-00---0----0---0--0-0 +11110100011 --1--------0-00-----0--1----0----1- +00001100011 0-0---10-0--0-0----000---1------11- +10001100011 -0---11--0------0----0----0---11-0- +01001100011 0-11--0---------0-1--------0-10---- +11001100011 000-----1---11--------1-10--0-0--11 +00101100011 --0--1--0--0-0-0-----1----1-0------ +10101100011 ---00--10-----11-0-------000----0-0 +01101100011 -0-0-1--------1----1-0-0----10----0 +11101100011 00-0001-0---0--0-1-------11---0-1-- +00011100011 01-0--1-0-00-0---------0--1-----10- +10011100011 0--0--0-----0----1-------0---0----- +01011100011 0--0--0--00---1-----0-------------- +11011100011 -11-0-0--------0-0---1--0---------1 +00111100011 -110--0------------0----------0---- +10111100011 0------0---0---1--00-10-0-0-1---0-0 +01111100011 -1-------------------0-1----0----10 +11111100011 -0------010--0-000----0-0--1-----0- +00000010011 -----0-------11-----00-0---0--0---0 +10000010011 ---1------11----0-01-0----0---0--00 +01000010011 --1---1-0-10---1--0----------1--0-- +11000010011 ------11-0-1011-------1--0-----0--- +00100010011 --00-0-0-1---1-1-0-00-0---11-----0- +10100010011 ---0-10---1---0-000--0-0---1------1 +01100010011 10---0-01--1-0-----00---10------00- +11100010011 --0--------0----0---------1-1-1---0 +00010010011 ----0------------1-0----100-------0 +10010010011 -0-00--------011-00-0---1-------1-- +01010010011 ---0---------1---0--------0--0----1 +11010010011 -----0----01--0---10------0-1---1-- +00110010011 000--11-0---0--0---1--111-0--0100-- +10110010011 --0---0------1----0--1-1------0---0 +01110010011 0010----0--0--0-00--1---0100------- +11110010011 ----1-10---0---------0-00--1------- +00001010011 ------0-1-0----0---------10-1--0--- +10001010011 ----0--0---0-100--0-00----0---00--- +01001010011 0--1-1-100---00--01---0--10-1---1-- +11001010011 ------1-00--------0---------00--0-- +00101010011 0-----------00--0-1----1-0---010--- +10101010011 ---10--0--0--1---------0-0---0--00- +01101010011 0--0-100---0-------1----0---1--0--0 +11101010011 1--1-----0----0--1-1--1---0--11-1-- +00011010011 -0-------0--0-0-0---------------00- +10011010011 ---1--------0-10-0-0------00-----0- +01011010011 0---------10-1------1-------0--0--0 +11011010011 -----1--1--------0--0-01---001-1-0- +00111010011 0---01----0----0--1---11----0----1- +10111010011 0-0--10-----000----1-00-----1--01-- +01111010011 0-00-------1-----0---00101-10---0-- +11111010011 ---10------1---0-1-0-----11--0--0-1 +00000110011 --0--------1---1---0---0-------0-1- +10000110011 0-1--------0-1-----010-0-1----0--0- +01000110011 10--10-0-0---0---000000--01--1--0-- +11000110011 ---100-----00----0--0-0--0--110---- +00100110011 -----1--1-00001-0---1-------01----- +10100110011 1-----1-0-00----1-0100--00-00------ +01100110011 0-1------0----1---00-100---000-1--- +11100110011 -0-0---1--10---0----1--1-----1-1--- +00010110011 --10---0--0------0-1--0---0-0--01-- +10010110011 ----------1-----1-----1-----0-0-01- +01010110011 --0-0---0--0-0----0-0---1-1----011- +11010110011 -1-0--0010-00-0----00---1---1-----0 +00110110011 -----100--1----0-0---0---------0--0 +10110110011 -0-010-0--------1-01000-0----0-1--- +01110110011 01-0-0---0--1----------001--------0 +11110110011 00-1--00-0-010----0---1----0------- +00001110011 -1-0-0-0-0-------000---0----0--0--- +10001110011 -001--------0----0---0-----101---0- +01001110011 -00---------0------0-----1-0-01-0-- +11001110011 --0----01-00--1--0------00--100-0-0 +00101110011 1---0-------0--1--1----10-1-1---01- +10101110011 --000----0---0-1-------0-01-----1-0 +01101110011 -000---0--0------00----0--00-----1- +11101110011 -----1-1--0---001---1--0---------1- +00011110011 -1-1--10--------11----0010----0---- +10011110011 1-01---1--1-------00--0--0-10--1--- +01011110011 000----1---0-----0----01---0-100-11 +11011110011 --11-0-----0-0--0-0----0------001-0 +00111110011 10----0--0---1-10-----------------0 +10111110011 ---1-0--------01----1----0----0---- +01111110011 -----0---1---0--------1-11----0---- +11111110011 ---0--00---1-0--0---0-0-------00100 +00000001011 -1---00-0-0-----0--11--110-00-00--- +10000001011 --0-101-00--10--0-----10--0--1-0--0 +01000001011 --01------0------0---00-------1---- +11000001011 1--0------000---0---001------10---- +00100001011 1--1--0--1-------00---010-00-0---00 +10100001011 -----0-1-0--0-------1---1-----0---- +01100001011 0-0-----10---0-0------1------------ +11100001011 -0-0-0------01-0----0---0----00-0-1 +00010001011 1--100000-0--1--0---10-------00--0- +10010001011 ---10----1---1---1-1-00-1-------0-1 +01010001011 0-------1--110-0----0-----1-1111--0 +11010001011 -------------00-1----0---1-11001--- +00110001011 0--00----1---1-0---0-00----000---0- +10110001011 -11--1-0-0-----0-----00-000-00----- +01110001011 1-1--------00-0-0-01--00---11----11 +11110001011 1-00--000-0----0--1-101-1-----00-00 +00001001011 1-1-------00-1-101--10--0011---0--0 +10001001011 ---0------0--------1---------0--1-0 +01001001011 -0--0-0----1--0--10----0----0--00-- +11001001011 -------0---------01000--------0---- +00101001011 -1---0-1000--0-------1-0--------1-- +10101001011 --0--0-1----00-1---0--1----0-10--10 +01101001011 -1--0----0-----1------0--0---1----1 +11101001011 1--------0-0--0-00----0---0-------- +00011001011 -10110----------100-0-0------10---- +10011001011 ---------0----01----0000-00-10-1000 +01011001011 ---1---1-0--1---0--0--1110--1--0--1 +11011001011 -0011-0---------0--01-------------- +00111001011 -------0001--0--00-0-----1-----1-0- +10111001011 1-----01----0-0-0---0--0--0--0-0--- +01111001011 1------01-------11-1--1-------1-1-- +11111001011 -110-------00-11-0-1------------0-- +00000101011 --------1------1----000-0-0-------0 +10000101011 -00--00------------010-10-1--0-1-0- +01000101011 0---1--0----0---0--11--00--0----001 +11000101011 -0--1-00000---00--0-0-0-----1------ +00100101011 ------0--00-0---0---01-00--0-0--0-1 +10100101011 1-0-----0-00------10--1--0--------0 +01100101011 -01-1-1---0-------00-----0-0----1-0 +11100101011 ------------0---01----------000---0 +00010101011 -0---0--0-----0-----0-0--0----0---- +10010101011 ---1-0-0-0--1-0-01-0---0------1---- +01010101011 0--0-1-11-----0--00--01------10---0 +11010101011 00---0-00---0---0111--000-0-1------ +00110101011 1-------00----0-------------111---- +10110101011 ------0-0---1---0---10------------- +01110101011 00--10-----0--1-----1------------01 +11110101011 ---00----0-001-0--0-100-1-0-1------ +00001101011 ---0--11--11-0-101--1--0---0------- +10001101011 1-0-01--0-----------0-------0---0-- +01001101011 -----1--0----0-----------01----0--1 +11001101011 -0-------1-0-1-01-1-1-1-0----0----- +00101101011 1--0----0---0---1---0------00--00-- +10101101011 ----0-----1----0101--0----1-1----0- +01101101011 ----0-----0-1-0------0--11-0------1 +11101101011 -10-0--0----0-1--0-000---------1--- +00011101011 000----0---00--0--0---------------0 +10011101011 0---01--01-0-0-1-1---0-1----1------ +01011101011 --1-----------00--------0--1-----1- +11011101011 010-1-00-1-1----0----00---01----0-1 +00111101011 -1-0----0--0----0-----010---0-10--- +10111101011 1-1-----100--------1--10----------- +01111101011 ----00------------1-00------------- +11111101011 -0-----------0-----0--------1------ +00000011011 110---0----1-1--1-0--0-0----0-0-1-- +10000011011 0-0---010---0---0-------1---0--0-0- +01000011011 -----0--11-1-----------1--000---0-0 +11000011011 -01-01--------0---1-00--1-0-------- +00100011011 -----0-0----------1--0----0---0---- +10100011011 -01----0--0-00--0-1--1-0----1--0-0- +01100011011 0--0----0010-0--0-10---1101-1--0--- +11100011011 --0-110---01--00-----1-1-10-0------ +00010011011 0------1-000-----11---------0-0-01- +10010011011 0--0110------0---11-1----1-0---0--- +01010011011 0-10----1-0---0-------0----0-----0- +11010011011 -0--1---0-0-01-1-00--10----0000---- +00110011011 -0---0-0-1-0--0----00--0---0-01---- +10110011011 1-10-0---0--0----0--01----0-1------ +01110011011 ---------0--0-----0--0--00-1-0-0011 +11110011011 -0--1-01-1--010----0-0-0-1--------0 +00001011011 ----10--------------------0-----1-- +10001011011 0--0-101---11--------0-------0---0- +01001011011 -00-1---10010------------1-00-0---- +11001011011 --------0-----------1--1-0------0-- +00101011011 ---------1-0-0---0-----------0----0 +10101011011 -0-1-----0-----10------1--0-0----1- +01101011011 0-----------1-1----11-0-----00-0--- +11101011011 0---------0-00---------0---1--01--- +00011011011 -0-0-1--------1--0-00-0-----0---01- +10011011011 ------1------0-1------0-1--0----10- +01011011011 00--1001000-01---0---1--1------0--- +11011011011 1--11--00-0-----0100-0--001----1-0- +00111011011 -1--0---0---1-00---------0--00----- +10111011011 -1010-0-10--01---0----------0-----1 +01111011011 0------010-----0-----------0-0----- +11111011011 001--------1-1----------0----0--00- +00000111011 --1-----1------0-----00-------10--0 +10000111011 -1---0-----1---0-0--0-01---0-1----0 +01000111011 -0-----0--00-----------0--1----1--- +11000111011 ------10---1----010----0--0-----00- +00100111011 --1--10-0------1-----0------0----0- +10100111011 -0-------1------0-0--1----0---1---- +01100111011 ---01--1----0-0-0--01--0-1---0-0--- +11100111011 ------0-0-01---111-11-------------- +00010111011 -00--1--00-0--0----1---0-01------11 +10010111011 00---00-01-0-------00------------0- +01010111011 --0-00-11---0-----0--1100--0------- +11010111011 -----1-1100--0--0------0--101--0000 +00110111011 0-0-----100---10-------11----1-11-0 +10110111011 -0--11--1--1--0--------1-00-0--1--- +01110111011 ------0--1---1--0-01--------1-0-0-- +11110111011 0-0-0---0--0--1---0-1---1-0-1----1- +00001111011 -1---010---0------------0--0-10-00- +10001111011 0-0-00-------110--------1--1------0 +01001111011 -0---1---00----1---0-------0-----1- +11001111011 ---0---000-1--0---0----------1-1--- +00101111011 ----0--00----00---0------1--1--00-- +10101111011 -001--------00-00--1-----0-----00-0 +01101111011 ---0--------0---0-0-0---0---100-011 +11101111011 ------------------01----------0---- +00011111011 -------------1-1---0--0----0-0----- +10011111011 -0-0---1-----0-0-0---0--100-0------ +01011111011 0--1-----000------0-1-0------------ +11011111011 0---101-1---10---1-0--10-0-0-0--0-0 +00111111011 0---1---1--------1--1-------10----0 +10111111011 ----0-----------01----10-1-000----- +01111111011 1---0-1-----0--1-0-------------0-00 +11111111011 -----101--1-01--------0----1---00-1 +00000000111 1------1----------100-0100--------- +10000000111 1-11---1---------01--1-------00---- +01000000111 ------0-1-0---11-1---00----00---0-- +11000000111 --00--01-----00---0------0-------0- +00100000111 0---00--0-0----0-01-1-0---1--010-00 +10100000111 -----0-------1----------1-0---0-1-- +01100000111 ---0------0----0------0-0-01---0-0- +11100000111 ---0---1--1-------------1-0-------- +00010000111 --------------1-----0-------------- +10010000111 --0-0---0-----0---00---------10--0- +01010000111 -----1-0-----------1----010--0---0- +11010000111 ---0-------0---0----11----0------00 +00110000111 ----010---------1-------0-------0-- +10110000111 0---0-0--0-1--------00-01--01------ +01110000111 -00------0-----0---0----0-1--10-1-- +11110000111 -0-------1--10--------00---1---00-- +00001000111 1-----1--1------------0--1---0-00-- +10001000111 -0-10--0----0-0-----0-11------1-11- +01001000111 1----1---00-1--000-----0---------0- +11001000111 ---0----1-------0-----0----1-0----- +00101000111 1--0-0--0---1----0---1----0-0-00-0- +10101000111 -1--0----------01--0-------00-01-1- +01101000111 -----01---0--1-1-0--00-----00----0- +11101000111 0-00--0--------0----0-00------0---- +00011000111 10----00-0--000-0-1--------0----0-- +10011000111 -------0---0-----------010-1------- +01011000111 01------------0---0----1--1----0--0 +11011000111 0--1--000-------0-------1---1-0---- +00111000111 -1------0---0---00-10-0-10-1000---- +10111000111 -----1--0-----1-00-1-0-----0-1--00- +01111000111 1--011---100-00----1----0-0-----0-- +11111000111 -------1--0-0-0-10--0-0-1-11------- +00000100111 -00-0----100--10----0------0-1--0-1 +10000100111 ----00-0--0-01--0-0010-1-----1---1- +01000100111 ------------0-0---0--10---000-0---- +11000100111 0--1---1------1--1-0------0--0----0 +00100100111 0-----10----0-0-1---1--00----0---0- +10100100111 --0-----00-00--10--00-1-0---0000--0 +01100100111 -00-----10----01---0--0------------ +11100100111 -000----10-------0-0----------00-0- +00010100111 -1-0---0-11-----0--0-11-1----01---- +10010100111 ---0-0-----1-010---------------0--- +01010100111 -1----00---10-1------------0----0-- +11010100111 ----11-----1-01--0---11-0--10-0---- +00110100111 ---0--0------0--0------1-0----0---- +10110100111 0----0--0-----1----0-----0--0--0--- +01110100111 -----10--0--0--0----0-0-01--------- +11110100111 -0-00--------------1--1-----0-0-11- +00001100111 -0-0-------1-----0--0110--------1-- +10001100111 --1------0--------1---------00----- +01001100111 -0---1--0----000-------0---0---01-- +11001100111 ---1----1---0---0-1---1-----0------ +00101100111 1--11---10------------1-1--0010---- +10101100111 --010-----0--11-0-----------0----1- +01101100111 100-1-----0------0------------0---- +11101100111 --0-11------1----011----1-0---1---0 +00011100111 0-1----0-0-0-0-011------0----1----- +10011100111 -0--0000-----0-1--0----0----0-0---- +01011100111 -000---0------0--10----01010----1-- +11011100111 00--1---1000-0--1-0-00-00---0---0-- +00111100111 10--1----001---0---00-------0-10101 +10111100111 -1-0--00--0-0-0--0--0001--1-100-11- +01111100111 0-11-01--10-1--00----------1-0-0--- +11111100111 --01---------0--0--0-11-0--00-----1 +00000010111 ----1-11---00-0---0--11-1----1--0-- +10000010111 ------1-0-1--0--------0-----1-0--01 +01000010111 0-----0-10--0--0-----00-0-0---0-00- +11000010111 00--0----0-----0-1-------0-101--0-0 +00100010111 -0--000-0---1--1-------00-0----0--- +10100010111 ------0-1-----0-0--10--0-----0-1--- +01100010111 -----00-0---011--0----0---0-001---- +11100010111 -------00---01---0---0-0-0-1-0----- +00010010111 --0----00--1----0---01------0----1- +10010010111 ----000----0-1--00---01-0-----0---- +01010010111 1---0-1------0---0--0--------10--00 +11010010111 -00---0---10011--000-----0---0--00- +00110010111 00-0-1---0-0-0101-1--0-------0----0 +10110010111 ----0--0-0--1-01-00---1--------0--1 +01110010111 -----0011-0------0----0---00----0-- +11110010111 -10000--0-----110--0-01--011----0-- +00001010111 --1----000----0--0-0--------1-0---0 +10001010111 -----0---1-----0-0---1-0--0-------- +01001010111 1-------0-----------1--------01--0- +11001010111 -----00----------0-0---1--0-------- +00101010111 000---0------0--1-00-0----00-1--0-- +10101010111 --1-0----01--0----0--000------0---- +01101010111 0--10------00---------0-0--111111-- +11101010111 -------01----01--00-0-0----00------ +00011010111 -1-------11-0----1-00--------0----- +10011010111 --00---1--0---0-01------1-0-------- +01011010111 1----0------0------0----1---------- +11011010111 -0----00-0----0--00-1-----0-0----0- +00111010111 ------0-----110-------10-0-----0-1- +10111010111 -00-0-1-----0-0-----------0-0-00--0 +01111010111 ---0----1--0-000-------0----0-01-1- +11111010111 0--0--0-----1---1--0-------1---0--- +00000110111 1--------------------0--0-0---0---- +10000110111 ---000-------0---00----------1----- +01000110111 --0---00--0-100-------1000-------1- +11000110111 0-0-0-0--0--11-------0-----10---00- +00100110111 101-----0--0-------00----0-0-0---0- +10100110111 --0---0-0----1--------0---0---1---0 +01100110111 -00------0-----1-----0-00---0-1---- +11100110111 0-1----0-1--0---0-1-01---0-----00-- +00010110111 1-----------00---0-----00000----0-- +10010110111 -1-0-----11--001--11-11-----1-0---- +01010110111 0----01-0-1-----0-0-10-----0-0-1-0- +11010110111 1-11---0-0------0-1--11--------0--- +00110110111 -0-0--0-0---0-0------0-----01----0- +10110110111 -11--0---1----1-10-11-------0--00-- +01110110111 0-------------0----1---110----01--- +11110110111 ------0-01------00---0--0-01--1-0-- +00001110111 ---1-----0----00-0-----0------11--- +10001110111 ---0-00-1----0-00--------1--0-----0 +01001110111 -------1----------0-1---0-00------- +11001110111 -1--------0--1-0--0---0--1-00-0-00- +00101110111 ------10-------10----01---000-0---- +10101110111 0-0--1-011---0-----------1-----0--- +01101110111 0-1-10--1---0----1-----1--10---0--- +11101110111 -----0---1-1--0----0-----1--1---1-- +00011110111 ------0-0--------------000------0-- +10011110111 0--------0---1---0------------01--- +01011110111 0---10-0-00--0---------0--------0-- +11011110111 010--0--1-10--11--1------0--------- +00111110111 ---------10------1---0-------0--01- +10111110111 -0----100-1---------0--0----1-----0 +01111110111 ------0------1----0-1--------1--00- +11111110111 ----00--10-0-010000-----1--0----0-- +00000001111 --0---1-1---0---0-1---0---1-1--0--1 +10000001111 --1---0----------0--1---00--------- +01000001111 -100-1-1----------0010---1-----10-- +11000001111 -----0--1---1----0---0110---------- +00100001111 ---------1------0---1-00--0-------- +10100001111 --1--10-0-0--0--------1----011-1-0- +01100001111 0--------00----1--01----------0-00- +11100001111 -1----11-0--0--1-0--0-1----0----10- +00010001111 -0--0-01--10----------0-----1------ +10010001111 1--010-0---0001-------0----00------ +01010001111 --01-0-0--0--1--0-----1110--0---0-0 +11010001111 11--00-0-0-1--0-----------0-000--0- +00110001111 -10---01-0-0-0-0001--------1--1---- +10110001111 0-------11001110--1----1------1---- +01110001111 --1------00-1------1-0--0--0------- +11110001111 -------0001--11--1---1-0-10-1----0- +00001001111 -0--1-0----0--0--0--------0-1-00--- +10001001111 --------01-0---0-----01--0----0--1- +01001001111 ----10--1-----1-010-1----01-0----0- +11001001111 ---1-0--0-01---1-0--0---0---00----- +00101001111 --0--1-10---1---01-----01---------- +10101001111 --1------------------00---------0-- +01101001111 0--0011---------------00----------- +11101001111 --0--0-0-0----10-----1----0-----0-- +00011001111 --0-1------------------000-1-1----- +10011001111 ---0-1--0--10-10--000--00--1-----10 +01011001111 1---1---0--01--1000001--1-0---0---- +11011001111 --0-0------------101-------------1- +00111001111 --------1-----0---0-0-0--10-------- +10111001111 -0--------1---100-------0--00-----0 +01111001111 -------10--01-------1001---00-00-1- +11111001111 ---10---11------------0----0-0----- +00000101111 00---------0---0-00--0-01-111-0---- +10000101111 ----0-0---0-000-0--1-00----11-00--0 +01000101111 ---0--01---10---000-0------01------ +11000101111 -----------0----------0-----0-1--1- +00100101111 ----0000---0--1-011-0---0-------0-- +10100101111 -0-0----0---000----------1--0101--- +01100101111 --00-0-1------0----------0-11-----1 +11100101111 ------------0----0--0----------0-0- +00010101111 -0--------1-1------------------0--- +10010101111 0-0------00--00----00------101-1--- +01010101111 --00--0-0-00----1--0-1-------000--- +11010101111 ------0------1--1-0--1------01--0-- +00110101111 ---0-00---1--10-0-----00------0--00 +10110101111 --1---1------01-----0--------0--01- +01110101111 -------0-11---0------0-0----0--0--0 +11110101111 01---0-00-------1------------0--01- +00001101111 11-0-00-0---1---1-0-1---1-0010---1- +10001101111 -001-1-0--------0---10---01-0-00--- +01001101111 -10--10----1-010--1---10001----1--0 +11001101111 00------1--0------1-------10-----0- +00101101111 -10----0-0----------00--------1--1- +10101101111 -100--0--001----0-1-0--------0----- +01101101111 --------1----1---11-1--0------0-0-- +11101101111 --0-0-0-----0-01--0-----1------11-- +00011101111 00--0-0-0---1---0-0--0------------0 +10011101111 10--------1----1---001--1-----0-01- +01011101111 ----0-0---101-----1--00001--------- +11011101111 --00-0----1-1--------10-0-0--1----0 +00111101111 ---0--0-00---00----001---1------0-- +10111101111 --0-------01---1-----0------1---00- +01111101111 -0-1-1----------0-----0--1--------0 +11111101111 ---00----0----101--1----1-1----01-- +00000011111 -1---100--0-1-00----1---0---0---01- +10000011111 ----0------11------------10-0--01-- +01000011111 ---00-0-1-10---1-01-1-0----01---0-- +11000011111 --1---------10-10---010-100-0001--- +00100011111 0-------0-011----1-00-01--1-------- +10100011111 ------01------0----0--0--0-100--1-- +01100011111 -1-0----0-00--1-----0--00--1------0 +11100011111 01000---1----0-0-0--010---00--0--0- +00010011111 ----0-----0-0----0---0--------0---- +10010011111 0-1---00--------0-00-1-------1--0-0 +01010011111 100-010-0-------0--------0---1----- +11010011111 0-1---0-1-0-----0-1------0-101----0 +00110011111 -----0-------1-----------1000---0-0 +10110011111 0-------0---------0----1-1--------- +01110011111 -0-1----00----01----0---00--0-000-- +11110011111 0-00---------0-0--0-1----0-----0--- +00001011111 00----10--0----------0-0-00-----0-1 +10001011111 --------001-1----1001--00-0--1-0--1 +01001011111 00--------0---01-0--00-----1--0-0-0 +11001011111 ------------0-000---------000------ +00101011111 -0--10-0-1----0---0-0---0------10-0 +10101011111 --11-0----010-1--0---1--0---1-10--- +01101011111 ---------1-00-0----------10--00---- +11101011111 -01-00----00---------1----1----00-0 +00011011111 ---10----0--0----0-10-1-0--------0- +10011011111 -0---1------------0---0-00-------0- +01011011111 -10--000-----0--0-0----0-----01---- +11011011111 ----------0-----10--0-1-0-000---01- +00111011111 0-1-----1---11--1-----------1--1--- +10111011111 -------11----00-000-0-0------------ +01111011111 -01--0----1-0----0-1-----0-00-1-1-- +11111011111 --------0-0----1-0-----001-0-0-10-- +00000111111 ------1-10-10-----0--0------------- +10000111111 0-0---1----------1-01--1--01-1--01- +01000111111 0---0--01---0--0-------0---0----000 +11000111111 ---0--0--0----1-----1-1011--0-0001- +00100111111 -1----1--11--1-0----0----0--1--0--- +10100111111 -----0--1------0-0-----1------0-11- +01100111111 0------1-1-------0----1---1----0--- +11100111111 1-----0-0---10---1--10---00--0--011 +00010111111 0-1--00-----00---11--0------0--1--- +10010111111 1----0--1-----1--1---1-00-----0--1- +01010111111 1-1----010--0-0---00--0-100----1--- +11010111111 -1--------0--0------1--1-----0---1- +00110111111 -000-0----0----1-0--00---0-1------0 +10110111111 0--00--0-1--110-----0--0------0---- +01110111111 --0----0--0-0----0--0--100---0----- +11110111111 0--------000-0---0--0--0--1---00-00 +00001111111 0-10---1-1----0--0------------10-0- +10001111111 ---0----1----0-010----00----1----1- +01001111111 00--0-1-10--0-0------1---0--1----0- +11001111111 0-----0-----0-1-00------0-010---0-- +00101111111 1-0-0----00---0---1-----1---0--1--0 +10101111111 ----------010--1-00--0-----000----- +01101111111 0-----------00-----1-----1-1--011-- +11101111111 --0-1-----1-0-----00-0-1---1-0----- +00011111111 0-1-01----1--------0---00--1--01--- +10011111111 10--0-----0-0-00--0------------0--0 +01011111111 00---0--0-0-----1--0-0--00---10---0 +11011111111 10-----------00--0----01-1------00- +00111111111 ----0-------0------0-0-------0--0-- +10111111111 -00---01-0----1-1--0-----0-1000---- +01111111111 -1-----10----0----10---0-1-0------- +11111111111 1-00-0------111-10-010----0--0000-- diff --git a/espresso/examples/random/test3 b/espresso/examples/random/test3 new file mode 100644 index 0000000..9f34a6e --- /dev/null +++ b/espresso/examples/random/test3 @@ -0,0 +1,1026 @@ +.i 10 +.o 35 +0000000000 ------0--1--0----1--------0--1----- +1000000000 ---1------0---------1--00--00--000- +0100000000 -----------0------0-0-------1------ +1100000000 0-0-1---01--1--00-0-0---1-0--0---1- +0010000000 ---1-0110--1---10------0---1------- +1010000000 -----00------1---110-0-100--0-1---0 +0110000000 -1--0-----------1----0-0-0------0-- +1110000000 -----010------------0-0--1--------- +0001000000 --0--10-0---00---0--00-----0-00-0-- +1001000000 1---1-0-1111--0--------101----0---1 +0101000000 -1----1-----0--0--0----010-00--0-10 +1101000000 0----01--1--0---110--1--011-------- +0011000000 -1------0----1-0-------00----0-0--- +1011000000 --0-00----10--11-10---0--01-------- +0111000000 1-----010-----0--010------------1-- +1111000000 ----0------11--1-1--00-0-00-----00- +0000100000 --0-0--1-0-1----00--00--1-0------0- +1000100000 --------00---0-10-------0-0-01----- +0100100000 --0-1----0-----0-0---1-------00-0-- +1100100000 0-------0----0-0---0-----0-000----- +0010100000 --0----------1----10-10------0-00-- +1010100000 ----00-0-1-0--0-0-0-----------1---- +0110100000 0---0-0----0-0-------1---0--10-1-1- +1110100000 -----00010------------------1------ +0001100000 -----0----10000--0----0----0-1-1--1 +1001100000 ----0--11-----00--0--000-1--1---1-- +0101100000 -1-01------0--------0---0--0--00--- +1101100000 ----0-0-1-00-0-0---00---------0-00- +0011100000 01---00--00--------000---110--0---- +1011100000 0---10----------0-0---000------0--1 +0111100000 -01--------0---1--------1---------- +1111100000 0------0-----1--1-0-----1-----0---- +0000010000 0-0001-------0-------0----1-0--00-- +1000010000 ----00-11--0-1-01-1-------1-0--0--- +0100010000 1-----------0-----------1--0----0-- +1100010000 -1-----1--10-00--------0---0--10--0 +0010010000 11---0--01-1-------0--------0-11--- +1010010000 0---------01----------0---0-1-11--0 +0110010000 --01-0---1---10---0--1--0----0001-- +1110010000 ---0---0-----1-1-1--0-------0------ +0001010000 --00------1--1--0---0-0--1---1-0--- +1001010000 ---0-----00-----1---0----001------- +0101010000 0-0--1-----01------0--01---0---0--1 +1101010000 0---01------1--1-------10---0-----0 +0011010000 -0---10--1----------0--1----1-0---0 +1011010000 ---01----10--0000-0-----0---0-0-0-- +0111010000 -1-00--11------1----1-0---1-0------ +1111010000 -------1---001----1-0---0-0---0-00- +0000110000 -0--10---0----10---01---01-----0--- +1000110000 -1-101-1-----0--0-----0------------ +0100110000 -10----0--0-10-----00---1-000---0-- +1100110000 --1-1-----1----0---0---0-----1----- +0010110000 -000---------0-----0--0----01-11-0- +1010110000 ----1----0--0--1----1-00---0------- +0110110000 -0-0---0--------01-------------0--- +1110110000 -0---111----0--1-1--------0-------- +0001110000 0-1---00000--11-----00001------0--- +1001110000 -0--1-0010-00----------1-1---0---00 +0101110000 ---1-----1---0-0-00---------001---- +1101110000 --0---11-0-------00--0-----0-11---- +0011110000 --------------0------0------------- +1011110000 ------1-1---01--0-11-0---10--00---- +0111110000 ----00----0-----11-1-1-1---0-0----- +1111110000 --1---------11--1-000---1---000---- +0000001000 -1-----0-1-00----0--0--00---1------ +1000001000 ---001---1--0-------0---------0---- +0100001000 0---0100---------00-1-0--0-0-----00 +1100001000 -10----0-01---0--10--1-01---00-00-- +0010001000 --1---1----0-----0-0--1-1--1010001- +1010001000 1------0-11-0-----0---0--1-0--00--- +0110001000 -----------1----1------1------0-0-1 +1110001000 -0----0----0--00---0-1---000-0---00 +0001001000 -0--0---0--0-0--0-1----1--0-0-----1 +1001001000 ----1--01-0--0-1-1--------0-----000 +0101001000 00---0----0--0-0--1--000--00----0-- +1101001000 --------1---0-1-00---0------------- +0011001000 -0--------00--0-1---0-------11--0-0 +1011001000 -0-010-0-11--0----1------00--0----- +0111001000 0------01--0----0---11-0000-------- +1111001000 ------0----0-0---------1----------1 +0000101000 0-01-0-1--01--0-0--0--11-----0---00 +1000101000 0--01-0-----0--0--0-1-----0-----0-- +0100101000 ---1-------011-0------0-----1---0-- +1100101000 1--1--010-------0-000--0-------000- +0010101000 1--1---010--0-----0-------0--0-1--- +1010101000 --0-1--1---01------10-----0--0---0- +0110101000 -----0-----0--0----------0---01---1 +1110101000 ------0------0--00-----------0----0 +0001101000 --0----------0-0-1--------0--0----1 +1001101000 --0---00-1------000--0-10--------0- +0101101000 --010---0----------00-1----0-01---- +1101101000 ----100-------1-0--------1-00--0--1 +0011101000 ---------00-1---0-0--0----1-------0 +1011101000 --0-1--0---1-----0----10-1----01--- +0111101000 -------1----1000--001-----------0-0 +1111101000 0----00-0-----01---00-1--10-00-1--- +0000011000 ----0---0--0---00--0--0-00-0--1---- +1000011000 -----0-0---0--00-1--00110--1-0--000 +0100011000 -1----------0-----------1000-0----- +1100011000 0-------0---------1---000-0--01---- +0010011000 001-1-010------1-0------1-0-01----0 +1010011000 -0------------00--------10---00---- +0110011000 --------0--1-0-0-----11-------0--11 +1110011000 ----0--0--11-0-0---0-0----0-0--0-1- +0001011000 1000---0-------00-10---0---1---01-- +1001011000 -----00--00--0---1-1-00-00---10--0- +0101011000 1------0-0----1-11-------0---0-1--- +1101011000 1-----0---0--1----00-0-01010---0--- +0011011000 -10---0--1-----1----0-----0--0----- +1011011000 ----------1----------0-0-----00-0-1 +0111011000 -0---1------0--1--000---1-------0-- +1111011000 ------1-00-0----0----1-01-0--0---0- +0000111000 -----0---------0---0-------1-00---0 +1000111000 00-0--1------11---0-00---0100----0- +0100111000 -011-0--0---00-0--1---10---0---100- +1100111000 ---0---0--01------------01---1--1-- +0010111000 -0--------1--0-0---1--0--1-1----0-- +1010111000 -----0-------------1-----1----1--1- +0110111000 -01-------0-0--0-1-100---1----0---- +1110111000 -1-1-010---1--0--0---0-----0-010--- +0001111000 --1--------0----0------------0-11-0 +1001111000 1--1------1-----01-0--1-------11--- +0101111000 --1-----00--0----0------00-----0--0 +1101111000 ----0---0----0-------1------10-0-1- +0011111000 -1-----0---000-0--1-----0-0----0--- +1011111000 -1-0---1-------0--1-----1-0-----000 +0111111000 0-0----------01----1-10----01--0--- +1111111000 --0------0--1-------0----1------1-- +0000000100 0------00--0--001-----0--10-----1-- +1000000100 00-10-0---0----------0----0---101-1 +0100000100 0-0--00------0---00----000--------- +1100000100 --01101-10---1------------------00- +0010000100 0------01---0-----11--0-00-1---0-0- +1010000100 1----00---0-011--001---0------0---- +0110000100 ---1-----0----0--0-0-----0------0-- +1110000100 -01-0--010---10-0-----------0----0- +0001000100 --0------1----0----110000---------- +1001000100 -----------0---010--11------1-00--- +0101000100 -----0---0---0--------1----0-----00 +1101000100 --0--00-1-----1----0-11-0--1-01---- +0011000100 0---0---00-1--0-001-1-00-1-----0--0 +1011000100 1----1-------0-------0-----0000-0-- +0111000100 --00-----00----11---------001-0-0-1 +1111000100 --10-0--10-1-100--10--------000--0- +0000100100 --00-01-010-0----1-------0--1--0--- +1000100100 --0-10---1----10-1--0------1--0-1-- +0100100100 -0---0---1------01--10------0------ +1100100100 ----00-1---------0--------1-0--0--1 +0010100100 ---0--01-0--0-0--010---1----------- +1010100100 ----1--0-1-------0-------0--10----- +0110100100 -0010-0101-10--000--110------------ +1110100100 -------0--0-----0--------0--0-1---- +0001100100 --0001-1--------00----1---------0-1 +1001100100 ---0-----------------1---00-------0 +0101100100 ----------0---------1----1--1------ +1101100100 -0----0----------0001--------0----- +0011100100 -0-0----1----0-0----100----------1- +1011100100 0--------110-0-------0-0000----0--- +0111100100 -00-----1----1----1--1---10-------0 +1111100100 00---0--00----1------0------1--1--- +0000010100 0-0--0--0-000----1---0--0----0-0-0- +1000010100 ---0-1--0-1-----0-10-1--0----10-10- +0100010100 ---01---0-----10-0-1-00---010-0---- +1100010100 01--0-1--0-0-----------0----0----0- +0010010100 --0-------0-00------0-1-01----0-0-0 +1010010100 -00-0--11-----010-----0----000----- +0110010100 0-------01--00------1----------0--- +1110010100 --010-1-01-00----010--0-0---0-0---- +0001010100 ---0---0-00---0----0-01---------0-- +1001010100 --0----1---1--1------1--1-----1-01- +0101010100 --1----0---0---0-0--0--0----0--0--- +1101010100 0-----01-0--1------------0---01---0 +0011010100 1--011---0-0---0---1100---0----0-0- +1011010100 0--10----------0--0--1----------1-- +0111010100 -------10---------------0---0--1-0- +1111010100 -----0--1------0--0--0-0--1---01--0 +0000110100 --0-11-------1-0---------001----0-- +1000110100 -0------0--1-0--1-0-0---0--------1- +0100110100 -----1------1-----1------1---0----1 +1100110100 1--0-0--1--1--10-------010-1------- +0010110100 1---------0---------1----0--11-10-0 +1010110100 10-1----1-000--0101--1----0--0---00 +0110110100 ---1-11-1--00--1---1----1-0---0---1 +1110110100 1-0----01---0--------1--0-1-0--1-1- +0001110100 0----000-1-1----0-0-00---01-------- +1001110100 --10--1-------0--0-0-0------------- +0101110100 --0--10----0-0--0-----0----00--0--- +1101110100 0----------------0-1------------0-- +0011110100 -----0-000----01-0----0-101-00----- +1011110100 0-----0------------0--0--0-00-0---1 +0111110100 --0--0----10--0--------------0---0- +1111110100 -------11--0--0-1-0---0--0-------10 +0000001100 -----1000-0------0-0-0-01--000----- +1000001100 0--10-0---------1------0-0---0--1-- +0100001100 -0---1--------1-00--1----01------0- +1100001100 -0-----0-001---0---11-------0-0--00 +0010001100 -0-00--0---0----1--001------0----0- +1010001100 ------01---0-1----1100--00----0---- +0110001100 1----0------0---0-0--00-0-10--10-0- +1110001100 ----0-00---01----0---1-0----00----- +0001001100 -----0--0---001-0---------0---1---- +1001001100 --0------0--0-----1---------0----0- +0101001100 ----01-1-0----0--1-00--11-1------1- +1101001100 0-1------0--0----0---1----0-00--000 +0011001100 --00----0-0------0--1-0------------ +1011001100 ---1---0-----0---------0---0-0001-- +0111001100 --1--10-0---0---00----01----------0 +1111001100 1-------0-----0-----01--0------1--- +0000101100 --1----0----1--1-0-00----0-11-1---- +1000101100 -0----0-0-01-----11--1--0-------1-- +0100101100 00---0-------01--0---0--1-1-01----- +1100101100 0----10-0-00-0-0---1-011---------0- +0010101100 ---0--01-0------11--1--0-----0--11- +1010101100 -0-----0-0-------------0-0-0-1----1 +0110101100 -0--0-0-------0-----01-0--10-0----0 +1110101100 1-------1----0--0----01-0----1--00- +0001101100 0101---0---1--10-01-1-0--00----0--- +1001101100 -----------------10-0--0--1-01----- +0101101100 ----10-0----1--0---1---0--1------0- +1101101100 1-------0-01-------101---0-0---1-0- +0011101100 1---00--00101----00-00-0-0-------1- +1011101100 -0-1-----11-------100--0--00------- +0111101100 --010--0-----0---0--00--0----0--00- +1111101100 0110-----0-0--0---------0-101---1-- +0000011100 ---0-----1-0---0-1------0-0-00---0- +1000011100 11----00--0-01---1-1-----------11-0 +0100011100 0-----0---0--0--0-00---1----0------ +1100011100 1---0----------------1--0-0--0----1 +0010011100 -----0----0----0---0---010-0-----00 +1010011100 --101-0--00--00-0----1-0-0-----01-0 +0110011100 --01-1--1-0--11-----10----0-----0-1 +1110011100 ----------1-0---0-0-00000-00--0--0- +0001011100 -11-----1------0-0--0-0-----0-----0 +1001011100 ---1-01----0----0----000-1-1-00-1-- +0101011100 ------0-01---------------1-0-----0- +1101011100 00----0-------0----------1--0------ +0011011100 -----1-----00--1-0---011--0--1--1-- +1011011100 ---0-0-------0---01---1-0-1---1---- +0111011100 1------0-1----1-------10-----00-01- +1111011100 01000----00---1-1--10-100----00---1 +0000111100 -0-1--0-0--0-11----0-0---10--0----- +1000111100 0--0--0---0-----10-1-----000110---- +0100111100 0--10---010-1--0----0-1----0-0----- +1100111100 10--0-0-----1--------0----1-------1 +0010111100 ---01---10--------0-----0-------0-- +1010111100 ---101-0-0-0---0-------1--0--0----- +0110111100 0--0---00---01---10------0-0----0-- +1110111100 -----------------0-------0---0-0-1- +0001111100 -1-0-0-----0-0---1--0-0------------ +1001111100 -000-1----10--0---101---0-000---0-- +0101111100 ------0-------0--1-1----0-00----00- +1101111100 ---0----0---0--110---0-------0----- +0011111100 --------0--01------0------0-------- +1011111100 0-------1---0-0-0---0-----0---0--1- +0111111100 -----0--0--------000--1--00-1------ +1111111100 ---10-0--110--0------0--01----1-1-- +0000000010 01-111-0-01-0-0----0-------00----0- +1000000010 --0--0----00---------------------0- +0100000010 0----1--11-000-1--------1--010----1 +1100000010 0------0-0-1-0------------0--1----- +0010000010 1------0---0-----0----1----1---0-0- +1010000010 ---------0-----0----00--1---1---10- +0110000010 --0-0-1-----0----0-------10-00----0 +1110000010 -------0-------00-0---1------11-10- +0001000010 ---0---0-----11--0-01--------1---00 +1001000010 --00--0---0-1011--00---00---0------ +0101000010 -----1--0---00--01-1-----------0--0 +1101000010 --10--1-----00-----0---01----0-0--- +0011000010 ----01-0-0-------1-0-00--0---000--- +1011000010 --011-0--1-----1------0-0--10------ +0111000010 -1---1-1-1---01---1-------0--1----- +1111000010 -------0--------0----0----------1-- +0000100010 ------------1----0-01--1---0--00--- +1000100010 ----0--00--0---11----1-----00----1- +0100100010 1---------00-1--110-00--0-00------- +1100100010 00-0-000---------0--------00-0----- +0010100010 ---0-00------0---------0----001--01 +1010100010 -0-0-0---0---1---00--00----00--0-0- +0110100010 --0-01--1-------01--0-0---0-0------ +1110100010 --0----------0---0-0--00---0------1 +0001100010 -0-0---11-----------0-01--0----0--- +1001100010 1----1--0-0--0------------1---0--1- +0101100010 -----10-11--100-0110-1-----0------1 +1101100010 -----0-1--0--1---0--11-1-0---110--- +0011100010 1---11-10-0---01-1-0-----0-0-01--0- +1011100010 ---11--1-0-1-0----------0-00---1--- +0111100010 0---------------------0--0-0------1 +1111100010 --1-1---1----000-0-----00000-1-1--- +0000010010 ---0--0--0-1------1----10------0--- +1000010010 -01---0----0--0----01--1--01-0----- +0100010010 --------1---1---01-----0-----0---01 +1100010010 -0-001------1---00------0---0--1--- +0010010010 1--1--101-----0--01-----00--0-0---- +1010010010 --0-00----1-0-0-00--0-00--0------00 +0110010010 ----0--------1----1--0--1-1-----1-- +1110010010 0--0-----101----00---00------0----- +0001010010 --0---0-0-0--0---0----0--------1-0- +1001010010 00-1----000--------0--------------- +0101010010 -0-0----10---------1---1---0------- +1101010010 --0---0--0-00-----0------1----0-10- +0011010010 0-----0-------0--0-----------0---1- +1011010010 -01---------01---0-000-0-00--00110- +0111010010 -1-0--0-0--101--00-0-0--001-----0-- +1111010010 1---0--11--1------1--------1-0----- +0000110010 10-1-01-0---0------------00--0----- +1000110010 ---00--0-----00--0---0-1--00--0-1-- +0100110010 1--1-110-0-0-----011---00-------0-- +1100110010 -0-0-----0---00-1-----000-1--11---- +0010110010 ---1--0-0---0-----0--0-0-----0---1- +1010110010 0-0--0--0----0--0-------1-1-------- +0110110010 ----00-0-------00-0-----------0---1 +1110110010 ---------1---10-0--000---0--------- +0001110010 0-0-1-----------0----0----0-0000--1 +1001110010 -1----0-----------0---01---1-1--100 +0101110010 000--10---0-0-------11----------0-- +1101110010 -00--1------------0-----0-0-------0 +0011110010 -00---10--01--0--1----0-----1-----1 +1011110010 0--------1---10-----0-0-1--101-1--- +0111110010 ----0---1--10-----010---0-0-0-000-- +1111110010 --0-0-0--00-1--01------0----0--0--- +0000001010 -----00-------00---1-0--0---1---1-- +1000001010 ----0--0---10--1---11---------0---- +0100001010 ---0--0------1----01------0---0---- +1100001010 0-----0-0-0----------------00------ +0010001010 ---1-1---1--1-1----1--00-----000-00 +1010001010 -0-----1----10-1-00--0001-1-----1-- +0110001010 -------00--0---1--1-0--000------0-- +1110001010 -1--0-1------0--0-01---0-0---1-1--- +0001001010 --1----0-----111-------10-----10-00 +1001001010 -0010--------0-00-1---0-00--------0 +0101001010 -----0-0-----1----0-0-0-----00----- +1101001010 --0-1-0-----001--111-00----0---011- +0011001010 00-0-000--01----000-00-11-00----0-1 +1011001010 ----1--0-----0-1----0-----00--00--- +0111001010 ----------0---1--00-1001--1-00----- +1111001010 ---00---1--------1--0-0---10--0---1 +0000101010 ---00-------1---00---0-0--1--0---0- +1000101010 -00--1--0-----010-1-------------0-- +0100101010 -0-------1---0-0----0-0--001---00-1 +1100101010 ---------0------0-10--1-00--00--0-- +0010101010 1-0-------00-----0-------0-0--1---0 +1010101010 10---10--011----0-01--01---------01 +0110101010 0-------0-----0---01--01------0-1-- +1110101010 0----001----10---1--1--1--0010---1- +0001101010 1-------1-0-0---01011--0---0------1 +1001101010 -----1---1-----1--00-1--------0---- +0101101010 --------1-1----1-0-1--0010-0---1-0- +1101101010 --0-------000----00------11-1--0--0 +0011101010 ---0--0010-----0----1-----------0-- +1011101010 0-0-1--0----11--100----00------0-0- +0111101010 -0--00-00--010--1-1---------0------ +1111101010 101-10-1-1--0--00-------0000-0--0-- +0000011010 --00-0------0-0-0-------00----0--1- +1000011010 001--0---10-00---1000----0----1---0 +0100011010 ----0--0------------------1----10-- +1100011010 ---0---0--0-----0-0001---000-----00 +0010011010 1--00-0--0--0-000---0-----------0-0 +1010011010 -------0-00--1-0------0--00-011---- +0110011010 0-00--0--01-------0--00---------1-- +1110011010 -001--0---0-----1---0-10---0---0--- +0001011010 0-001-0------0-1-1-1--0-------0---0 +1001011010 1--0--0----1-11-0---1---0-0001-0--- +0101011010 --------0--0----10-0--10-1--0--1--- +1101011010 -----0-----0---1-1----------0--0--1 +0011011010 -0-1---01-1---------------1-0-0---0 +1011011010 1----11----------0---1-------01---- +0111011010 ---0110-------1--------1----0------ +1111011010 0--0----------1----0--1-0--0-0----- +0000111010 --------10-1-111-10-0---0----0---1- +1000111010 ----0--0------1---1--------0-0--00- +0100111010 1-------01--1---0---0--0-------10-- +1100111010 ---1--0-00----10------------1000--- +0010111010 0-----000--11---0-----01---0-0-1-0- +1010111010 10--1--0-0-1--------0----0-----110- +0110111010 -00--0---0----0-1-0---01--0------00 +1110111010 ----0--0--10-----10-10-1--1-----0-0 +0001111010 -00----0---------0----1---------1-0 +1001111010 -----0----------0--0----1---------- +0101111010 ----0--------1--1--0---------1----- +1101111010 000-1--0-------0-0----0-----0-0--0- +0011111010 --10--1---11-1--0------------1----0 +1011111010 -------00-00---------------1--0-0-- +0111111010 --0--------0----------0---0-0----0- +1111111010 0-0--010--------11-0-00--00--10-0-- +0000000110 ----1-0------0-1----0--0--1---0--0- +1000000110 0-1---1--0----0-0-0-011-1--0--00--- +0100000110 1--1--001-0------1-----00--1-1--1-- +1100000110 ----0----1-00------1--1---------0-- +0010000110 -0----00------0-----0---1-0-110--0- +1010000110 -----00-1-1---0-10--0---11--0-0---0 +0110000110 -1--0---010---00--10-0------1-00-00 +1110000110 -0---0--10-00----0-10-----01---0-00 +0001000110 00-1----1-0--101-------00---1------ +1001000110 ---------------00-----0-00--0----0- +0101000110 -----1---0---0-01----01-0001-0----- +1101000110 00--0-----0-0-0--1-1-----000-1---1- +0011000110 --0-1-------0-00--0-100----10-1---- +1011000110 ----0-0--11----0-----0-1-0------0-- +0111000110 -010----11------1-01--1-00--1--0--- +1111000110 --0--00-----1--0-------0--1---0---- +0000100110 0-1--1---0011-01-000---110-----1-0- +1000100110 ---0---0-0--0----0-----10-----01--0 +0100100110 ---0--0-------------1------1-1-11-- +1100100110 0---0-0--0----0-1---00-11--0----1-1 +0010100110 -0000------0-0-00-1-0---0-01----01- +1010100110 00---00-----------1-1----10-1---0-1 +0110100110 1----11--00----00-----00---1--1---- +1110100110 ---0---01-10-0-----0-----011----00- +0001100110 ---0-0----0---0---0---0-10--------1 +1001100110 --0-0---------0---0---0--10-0-----0 +0101100110 1---1---1-0--------0--------000-1-0 +1101100110 -0--11----00-------------101--1-10- +0011100110 --0---------1--------------------00 +1011100110 --0---0-0--1----0--0-------11------ +0111100110 -0-----10---0-0---1-0--0--000--0--- +1111100110 001------------0---0-----0--------- +0000010110 0-0--1----0---0000------------0---1 +1000010110 --0--------0---0---0-0--0---010-1-- +0100010110 0--1--0-----0-0-1---0--01--01-00--0 +1100010110 -1--0-0----0---0---0---------0-010- +0010010110 -01-01-----0-----0-1---0-0-0-1----- +1010010110 -------0-----1-00------0------0---- +0110010110 --0-------0--0---1--000--00------0- +1110010110 ---010--1-----00-00--0---0-001-1--- +0001010110 -0---00------------------0-00-0---- +1001010110 -0-10100-----------------------0-1- +0101010110 1--0-0----1--10-------00-0-----1--- +1101010110 -0-------0-----00-0----------00100- +0011010110 --00-------------0--010----01-1--0- +1011010110 --0--0---0--1-0-0----1--00-0-----0- +0111010110 -----------0---001100-0--111010--1- +1111010110 ----0---0--1-0-0-1--0-1--------0-0- +0000110110 11--00-----01-0-----0-------1----1- +1000110110 010--0-----------------1--------0-1 +0100110110 -0101-----------00---100-0---1-0--- +1100110110 -1-0--1-0-0--1--------10-----1--0-- +0010110110 10----0--1---01----1-------------0- +1010110110 ---01---0-0010-1--------11-------0- +0110110110 -0-00--00----0--00------0--0--1---- +1110110110 01--1-0--0-----1--0-0-1-0---1--1--0 +0001110110 00---1-----0--0--0-0--11----------1 +1001110110 0---------0----0-1--1----0--0------ +0101110110 -0-------00---11---1--1----0---0--1 +1101110110 ---0--1------0--0-0---0------------ +0011110110 --------------0-1-----000-0-0-0-0-- +1011110110 -------0---------0-1--1----0-000-01 +0111110110 01-0-110-11---------10--1-10----1-- +1111110110 1-1--0------0----------1010--110-0- +0000001110 -0-0----1-0----0--1----------1000-- +1000001110 -0-0-10-1-------0--0--0--111----0-- +0100001110 ---1----11----------1-01---0--01--- +1100001110 -----0----0--1-1-0--0-00-0--------0 +0010001110 -10--11--0-0--------0---1-1---10--- +1010001110 --00------1-0---------0--------00-0 +0110001110 1-000-1--0-0-00---01---0----0--0-10 +1110001110 --010--------0-0-----10-11---0-1--- +0001001110 1---00----0010-0-0---------00------ +1001001110 -0----1100010---00101---11-0----001 +0101001110 -0-0-0----0------100--------011---- +1101001110 ---1-0--10----01-0---0-010-000----0 +0011001110 -00------0--0---0---1---0-01-0--00- +1011001110 -1---100-0100---00--1--1--100-0--0- +0111001110 -0----0-----1----------0-0-00-0011- +1111001110 --00-0-0---01--0------1-----1-----0 +0000101110 1---------0-------1-------0-01--00- +1000101110 ------0--1----1-------1--00-0-1---- +0100101110 -0-----01-------10-------01-1----0- +1100101110 ---------0---------1-1------------- +0010101110 0--0--------01-----0-0---0--1-0---- +1010101110 -----0---10-0-0-----01---1--0-----0 +0110101110 0-----01--01-0----0----0-10000-1--- +1110101110 --0--1---01--0--0------0-00-------- +0001101110 -1--00----0-1--0--10-------1-10--00 +1001101110 ----1----0-01---1----01--0---0-0-0- +0101101110 ----001--0---0-----0-----1------0-- +1101101110 -0-00-----------0-1--0--0--1-1----0 +0011101110 ---11--011-10-0-00-----1----------1 +1011101110 01-0-0---------0---11-000---10-0--- +0111101110 ----0----000----0--------01-1-1---- +1111101110 -----0-----11-00001---------001001- +0000011110 0---01------0---01-1-1--010---1---- +1000011110 1--00--0-------000-------0-0------- +0100011110 1-0--1---1--11-----------------101- +1100011110 --0--110---1100-0----1--0-----0-0-0 +0010011110 -----0-0------1-1--0--1---0---0---- +1010011110 -------0----------1-100---0-0---0-- +0110011110 -----0-0-0--------0----000---1--0-- +1110011110 -111-----0-00--0-0----0--000----1-- +0001011110 ----11-0---0-0-1----10---0--0----11 +1001011110 -------0-------001--0-1-0--00------ +0101011110 -0-000-01---1-000---0-1---11------- +1101011110 ----0--00--11----1--0--0-----0-00-- +0011011110 1-00---0-10-------------00---01---- +1011011110 -----1--00--0-0-01----0----0--0-0-- +0111011110 ---011--0-01-1--------1--0-1--1---- +1111011110 0-0-----------000------0---0----0-0 +0000111110 -0----00--------0--0-110---1--10--- +1000111110 -0--0---0---010--0---------1---1--1 +0100111110 --0------0--010--1-0---0---------1- +1100111110 0--01--------1-----10----0-----10-- +0010111110 -0----00-00----11-0---1---------011 +1010111110 -00-----0--------1-----1-0--------- +0110111110 --------10---0--01----1-00---0-1--- +1110111110 1----------1----------------001---- +0001111110 --11----0-11------------1---------1 +1001111110 0--1-0-0----------1-0---0-0-----1-- +0101111110 --0-----1----1-----1---01--1------1 +1101111110 ------00-0--00-0---100-----0-1-1--- +0011111110 -00-0----01--00-0---010--------01-- +1011111110 -----------------01-0------0-1-10-1 +0111111110 1-101-----------------1--0---0-1-01 +1111111110 00-------00--1------------11-----1- +0000000001 --1-1100-----------1--0---11--1---- +1000000001 001-1---0---------------1-----0-0-- +0100000001 -00-0-00---0----000----01---1--01-0 +1100000001 ------0--01--0-----0-010--0--0-0--- +0010000001 000--010--01--11-010---0-1---0---0- +1010000001 -0--1--1-0-0----0---1--1--1-------- +0110000001 -------1----00--1-00-00-0---------- +1110000001 ---1---0-----1----1--0---00--0-0--- +0001000001 --1-00-0-----0-0-010-----00---11--0 +1001000001 ----11-01-0---0------0----0-0-----1 +0101000001 ----1-------01-----0-0--1-10-1----- +1101000001 -10-0----1---1--1---0-10-00--11---0 +0011000001 1------0-0-----1---11-10-0110----01 +1011000001 ----------100---1-00-----1--------1 +0111000001 1---1100----0-0---------0---------- +1111000001 -----1------0------1-0-0-----000--- +0000100001 ---0------1-0-----1--1-0----------- +1000100001 -0-------0-----00---00-1--0-0----0- +0100100001 00010--0--100-----0-011-0------1-1- +1100100001 -0------01-0---0-0---0----011--0--1 +0010100001 0---0-0---0-00-------------1------- +1010100001 ---0---0---00-----------001---0-0-- +0110100001 ---11-0-----00-----0----0---0--00-- +1110100001 10-----00--------10-01------0--10-1 +0001100001 --------011----0-100111----00100-1- +1001100001 0-----------11---1-----1-0---00--0- +0101100001 01---1--0--0-----0----111-01-0---10 +1101100001 ----1----------0--0000-----0------- +0011100001 0------1---1--11-----00--0----1--0- +1011100001 1-------0-----0---10-----0---0---0- +0111100001 --0--0-0---0-0--11------1---------- +1111100001 -00-------1--00--0----1-10-----0--- +0000010001 ---10001-----00-------0----001----- +1000010001 ------0---0-1011------00--1--01--1- +0100010001 -----------01-1--0--0-----00-00---1 +1100010001 101-------1---110-1--00--10-110---- +0010010001 -00--0---1-01-1----1--000-0----10-- +1010010001 ---------0------100---1--------0-0- +0110010001 --1--0---1-1----00--0--1-------0--0 +1110010001 -----00--0-0--1------1---01--0----0 +0001010001 -0--0--1------------0------0------- +1001010001 -0--0--0---1----------1----------00 +0101010001 --1-0-1---0--10-101-0-1---0------01 +1101010001 ----0-0-0--0-10-------0---011-0--1- +0011010001 -011-0--0-1-------0-----0-00------- +1011010001 0--1----0-0-------0--------00---0-0 +0111010001 00------00-----00-0-----------0---0 +1111010001 1-0-10----0--0--0-0------0---0-1--- +0000110001 -0---------00--1--1----0-1------100 +1000110001 00-----0--00-1--1--0110-------0-00- +0100110001 -00--0--1---0-11-00---1-0--0-----1- +1100110001 --10-1--1100----1--11-011----0-000- +0010110001 0--0--0-0-0--000-0--0-1----0----1-0 +1010110001 -----0----------0----0-1--1---1-101 +0110110001 ---1----0--10---------------1------ +1110110001 ---100---10---0--1-0---10-011--0--- +0001110001 --0---0--0-00-1-0---10--0-0-0--1--- +1001110001 ----1----0--00010--0------0--0----0 +0101110001 ----1-10----1----0----0-1-------1-- +1101110001 -0-------0--0-----0--0--1--0------1 +0011110001 -----01-----00-------1-11-----0-0-0 +1011110001 -0-00----1--1---00----1--0--------- +0111110001 -0--1--0-0--------0--1----0-------- +1111110001 011--------0-1------110-0----10-1-1 +0000001001 -------0-0--1------1-001----------0 +1000001001 ----011010-1--------0-00------0---0 +0100001001 --0-0-1---0--1010-----1--00-1----1- +1100001001 --00---00---0-------1----------0-0- +0010001001 --------------0--1---10----1------0 +1010001001 0101---1----0---0-001000---0------- +0110001001 0------10---------0---10---01------ +1110001001 ------1--10---00-0--------1-1-10--- +0001001001 -----11----------01------------0--1 +1001001001 ---0---0--0--0-------0--00-00--0-10 +0101001001 01000------0--0--0-0-1----1------0- +1101001001 0--10----00---1-1-1---1-----01--1-0 +0011001001 --1-----0--0---0---0-0-------0----- +1011001001 10-00-1---0-----1-0---0-1---10----- +0111001001 -0----0--0--01-----1-----1--00----- +1111001001 -0--011---101---1--00---------0---0 +0000101001 ----001---0---1---10-00--------00-- +1000101001 -----000---0-----1---000-0-----1--- +0100101001 --0--0--1----1----------0--01----00 +1100101001 -1--0-100---1--0--1-0--0---------0- +0010101001 ---0----0111---100------0-0------1- +1010101001 ------0-0-0---1000---------------1- +0110101001 -0---------0----11-0----1-0---1-00- +1110101001 ----0--0-0-0---0--1-11-0---0---10-- +0001101001 --0--00----0-0--1---------1--00---0 +1001101001 -11-0-----1-----0--------001---00-- +0101101001 --0---------110-1--1-------01------ +1101101001 0-1-----01----0-0----0--0-0-----10- +0011101001 1--11--01-0-0--------0-1-10-----10- +1011101001 -------0---10-0---------------0---- +0111101001 0------------0---1-0-0-----0--10--0 +1111101001 --0--0001---0---0-0-----0-01--1---- +0000011001 ----00---0--0--0----0----1--1---0-- +1000011001 ---0---0-001-------0-0----0--0-0-0- +0100011001 -------0--0-0------10------1-----0- +1100011001 1---0---1-0--1100---0---0-------00- +0010011001 -0---1----------0---1--1-0-1-----0- +1010011001 --1-----------1-----------0--1--1-0 +0110011001 1--01-0----00-----1----1-0-0-11-1-- +1110011001 ---00--0-------01--------0-0--1-1-0 +0001011001 1----10-0-0001---10--0-0----0------ +1001011001 0--0-0---0-0--01-------0---00-0--0- +0101011001 --01--------0---0------0--1----1--- +1101011001 --1---10---10----01-------10-----0- +0011011001 --0--00000---1--0-1------0-100-1110 +1011011001 0--0----01----01-0-------00---10--- +0111011001 1---------0-0----01------------0--- +1111011001 -0---0-10-00-00----1-0---1--0-1-01- +0000111001 -0-----0--1------0-100-1----0-0--0- +1000111001 ----------11--11--------------0---0 +0100111001 ----00---00-----0--11------0000---- +1100111001 ---1--00--0-01-0-0----1--10-------1 +0010111001 -----11--00---1----10-0--000000-0-- +1010111001 ----0-11-00---0-0--00-01-0---1-0--- +0110111001 ---------0----0--0-0---------00---- +1110111001 0--0---1111---0---11-0--00--------0 +0001111001 -0-0-------1-0--0--0---1---0----1-- +1001111001 ----0-00-0-0100-------10----1------ +0101111001 011------0-------0---1---0--01--0-- +1101111001 1--010--0-----0--10-1---10-1---0-0- +0011111001 ----1----0-1--010-0-000---0-0-0-0-1 +1011111001 00---0-0--1--------------10-------- +0111111001 -00-0---1-0-11------1--00---0--100- +1111111001 ----0-----1--1-----0------00-0----- +0000000101 1----1-010-01-------0--1-1---1--00- +1000000101 ----0-1---0------0---1-10--0-0-00-- +0100000101 -----0--0-----0----101--1---0---000 +1100000101 ----------1-0---00--0-0--1---0-00-- +0010000101 --1-0--0-0-0------000-10-0-------0- +1010000101 ---0-1----01--0--0---0-1--0---0---0 +0110000101 ---10-1--0--0-0-1--00-----00-0----- +1110000101 ------1---------------1---1----0--0 +0001000101 ---0-00--------0-----001-----10--0- +1001000101 0---------10-110-----1--0-0-0--1--- +0101000101 0-----1-0----------0-1---1-1------0 +1101000101 ----0--0-0----------1-1-0---------- +0011000101 0--00------0-01----1-0-00-1-01----- +1011000101 ------00100---0-----1-1--------10-- +0111000101 -11--10-01---0-0--0------0---10---- +1111000101 0-------0----10---0--------1----000 +0000100101 --1------01----0--0----1---1--0--0- +1000100101 -0-------------1---0------0-------- +0100100101 --100-----1-00-1-------1-00--11-0-- +1100100101 0-1---0--0---0--0001--000--0------- +0010100101 -------1--011----0--00---10-1--1--0 +1010100101 0--1--001---0-00---0-1--0--0---0--0 +0110100101 0--00-000--0-----0-1--0-1--00-1---0 +1110100101 --0--0-01-0---0--------0----0-0---- +0001100101 0--00---------------00-------0--0-0 +1001100101 --01-0--0--------0-0-00---00-0-0--- +0101100101 ---1-1--01--00----0---0-1---0-1---- +1101100101 ---010---1-------0--1-10--0-------- +0011100101 --00-10--00-0-1-----0-----1-100---- +1011100101 0-----0----00----1--1-1--00---0---- +0111100101 ----0-----1---0-------0---1-0----0- +1111100101 ---------0--0----0--11-1------100-0 +0000010101 -------0---0--0-0-----------1------ +1000010101 -----010--0-1----110------00--010-1 +0100010101 1---------1-1---------1-----00-1--- +1100010101 00----1-1-1-001--0---0--0--1--1-1-0 +0010010101 0-00------------01--------------0-- +1010010101 ---0-0-1-0----------1-0---0-----00- +0110010101 ----01---1--1-1---01-1-0---110----- +1110010101 ---0-----10--0-----00001---------0- +0001010101 -----0-------------000-0---1-----00 +1001010101 -0----0---------01-----1----------- +0101010101 0-----0--1---1-------0------0------ +1101010101 --------------0-----0--1-00--1-00-0 +0011010101 0-----1-1000---00---00---1-------0- +1011010101 --1-00---0--0-----10--1------------ +0111010101 -0----0--0-00---0-1-0---00--0-0-00- +1111010101 0-0--------0-0--1----0--0-------01- +0000110101 ------0----1--1----------0--0100-0- +1000110101 1----1----110------0-----0----0--0- +0100110101 -----000---001-------0--1--0-0----0 +1100110101 -1-0----0001--00----0-------00-0--- +0010110101 0-----0-0--0------0-----010----1--- +1010110101 -----0-01---00---1---1-----011--0-- +0110110101 --0------0-----0----------0---00-0- +1110110101 --------00----1--0---0-----0------- +0001110101 1---001-1----0---0-------------1--1 +1001110101 0------------0----1-1----00---011-- +0101110101 ----10-0-0-------0--------1-0--01-- +1101110101 -1--------0-00-0----01----111---100 +0011110101 ---0-0---00-------1-0----01--1----- +1011110101 ----0-0-11----0-1-------0---101-0-- +0111110101 00-01---0--0---0-0-------------0--- +1111110101 ---0---1--1----1----------0---0---- +0000001101 001--0------01---1-0-----0----11--- +1000001101 --1--------01--000-00-00-01--0----- +0100001101 00-1--1--1--1----0--0----0-----1-00 +1100001101 1-1--10--------1-0-1---0----1------ +0010001101 10--0-0------1--0-0--0------------- +1010001101 -0---0---0-------0-------0-1------- +0110001101 0--------------------0-----1---0--0 +1110001101 -------000-00----------------0---0- +0001001101 ------------00-10--0---1-------0--- +1001001101 1-----0-1-----1-----1--1-----0---1- +0101001101 10--0----1---1-010100-0--0--0-0-000 +1101001101 11-1-0------0------1------0----01-0 +0011001101 10---1-0--1--0-0--1---0------0----- +1011001101 --0-0-------0--------1--0--1-1-1--- +0111001101 --------0-----1-10-10-0-1--1-0-01-1 +1111001101 ------1----1-0--1-0--1--0--0--0---0 +0000101101 0------0-----01-0---1--00---0-0--0- +1000101101 ----00-0100-------01-10--0-0-11--0- +0100101101 ---10-------001--0---0-00-----00--0 +1100101101 11---------0000-----010-01---1---1- +0010101101 0-01-0---1-1-0--1-----1--00----0--- +1010101101 ----1-0--1--------00--0--1-0-00--0- +0110101101 -0---------1--0-00--------0---01--1 +1110101101 1---0----0-00100-0100---01----11-0- +0001101101 -----01--11--100----0--1-----1-0--- +1001101101 ---0---0-1----0-1--000------------- +0101101101 --------------0-1-------000-------- +1101101101 ----0-0-1---0-0----10---10--------- +0011101101 ------0-00----0-1-0--------00------ +1011101101 --0-01-101--0---0----------------0- +0111101101 --10---------00--000-----0----0100- +1111101101 -0-0--------0------------010-----0- +0000011101 -----0-----------0-1--------0------ +1000011101 --1-0-----0-101-----1--0--0---0-1-- +0100011101 ----1-1----10--00--1-10-0-0-0-1---0 +1100011101 --------0-------0-------0----00-1-- +0010011101 1--0---0-00------0--0-----------0-- +1010011101 1--0--0-----11------00-0---------0- +0110011101 1------100--00--0--0--0-----0-10--- +1110011101 --1-00----0-0-10-----00-0---1--0--- +0001011101 -0-----0-0----10-------------11-1-- +1001011101 -0--0-1-000---1-----0--01-----10--- +0101011101 ---01--0---0----1--00-------------- +1101011101 1-0--10-------10---00---1-0--0----1 +0011011101 0---------------0-000---0---0---1-- +1011011101 0---0-011-0-000----0-----------0011 +0111011101 ------1----1--01-01--------1---100- +1111011101 01--0---0--0----01----1-----001---1 +0000111101 ----1--0-----1--0----0---1-0------- +1000111101 -----0-0----00--0-----000----00--0- +0100111101 ----------------1---00---00-0---1-0 +1100111101 --00-------00--1--01-0--1----1----0 +0010111101 -11-----11-10----1-1--0-00-------1- +1010111101 -1-1-10-0-0--0--------00--00--0---- +0110111101 ---0-1----0---1---0-0-----1-------- +1110111101 --000----00-0--1-1-00-1----0-0---00 +0001111101 -0----1---0-0-0---00---0-1-1---1--1 +1001111101 -0---01010-------1----1-11--------- +0101111101 -1---1-0-----0------0--------11--0- +1101111101 --------0--0-00--0--0-1----0----0-- +0011111101 -0---1-10-0------0----0------1---0- +1011111101 ---0--00-----0---1---0------------- +0111111101 ------0-0-0--10----0--00------0-000 +1111111101 --0--11001-0----0------01-0--1-1-0- +0000000011 -1-1------000-------100--000----0-0 +1000000011 01-0----1--1-0------0----0-0------- +0100000011 ---0-0-0001--01-------0--1----01--- +1100000011 00-0--0-0------0----0-0-00--1-----1 +0010000011 1----1--1-------1----------10-0--0- +1010000011 1--01--1----------0---------0-----0 +0110000011 --00----0----------------011011-001 +1110000011 -----0--00-----0--------1--0-----00 +0001000011 -1---10-0--------00---0----0------- +1001000011 ---100----0101------0001----------1 +0101000011 -----1-------0--0-------01---1-0-1- +1101000011 ---------0-0----0----1-01-------000 +0011000011 -001--------1----00-----1----0-0-0- +1011000011 ---1--1------------0-1--01---0--011 +0111000011 ---------1-0---00-0-0------------0- +1111000011 -0-0-0--------100-------00--------0 +0000100011 0---0-----00---00-----0---0-----0-- +1000100011 0---1-00----100--00-0-011--1----10- +0100100011 --0-----0--0--0--01--10-----0-0--1- +1100100011 00-100-----0--------1---------0---- +0010100011 -------00--0--1-------0-01--111---- +1010100011 00--1------------------0----------- +0110100011 ----0-00---0-----1---1--0-0-0------ +1110100011 11-0----0----1----0---0-------0---0 +0001100011 --0-0-01--11--0--011---11001------0 +1001100011 ---11--00--00-0-0--0----1----0--1-- +0101100011 ---1---0--1--0------0-------0------ +1101100011 --0-0-1---0--10--11--001---0----0-- +0011100011 -01---0---0-1------------0-0------0 +1011100011 01-0-0---0-----1---00-----------0-- +0111100011 1------1---0-0-----------0----0-0-- +1111100011 -------0---0-000---0---0--0-----0-1 +0000010011 0--1-----0-----00---11------1--0-1- +1000010011 -1--------0--1000-0-0----0--0---0-- +0100010011 -0--001------00-1--1--1-0-11-10--0- +1100010011 --0-----01-----1000-00---1--0------ +0010010011 ---0-------00000---0--1-0-000-0---0 +1010010011 10-----------1---1---0-----------0- +0110010011 -0---------0--------0-1------0----- +1110010011 1-----------0-000-0-------0----0-00 +0001010011 1-0--1-010---000--1--0---1-0---0--- +1001010011 -----0---1-------1------1-1--1----- +0101010011 ----0---10--0--0--00---10----00---1 +1101010011 ---1------0-00---0--01--0-------1-- +0011010011 0-1---10-1-----111------1-0--1----- +1011010011 0---------0--0---1-10----0-0--0--0- +0111010011 -----0-10-0-0-000-------0--0-10-0-- +1111010011 1--0--1---1--1----1---0-------0---- +0000110011 -001-0-0-01-0----11-----0-----00--1 +1000110011 0-100-1----------0--------0-000---0 +0100110011 -00-1--0-----0-1------1----1----1-1 +1100110011 -0-1--0---0--0-0-----10-00------0-- +0010110011 -1---0-0-0-00-1--0-0-----0-------0- +1010110011 --0---------0-111-1---0------1010-- +0110110011 --------1-10---000----1-----1-----0 +1110110011 -----10------1---1--1-0-0-0--010--1 +0001110011 -00--1-------00--00--------0---1101 +1001110011 1--------0---0-1------0--10----0--- +0101110011 ------010----1---0--1-1-1------10-1 +1101110011 -10--1--01------000---0----11--0-00 +0011110011 ---00-0------10-------------------1 +1011110011 1----0-0-0--1--0----10-01-----0---- +0111110011 --1---1----1--00---0-0---0-0-00-0-- +1111110011 --0-0-0--00-0-0-00---1------0--0-1- +0000001011 --------00----1---0----00-0--0---1- +1000001011 0-1001--00-1------0001-0---00---1-0 +0100001011 -1-----0-0---00---0--0---0---10---- +1100001011 ------------0-----------0--11-0---- +0010001011 -1100---1--1--0-1--0-----1----1--1- +1010001011 --00-00------0---10----0--01--0---0 +0110001011 0----------------0--------0---00-1- +1110001011 000----0-0----0---0---0-0---0---00- +0001001011 ------0------0-------------01---0-- +1001001011 ---1---0------------01--00---1---00 +0101001011 -00---------0--1-----0------0---0-- +1101001011 0-1-0---0-----0---0------------0--- +0011001011 ----0------1-10-1-----------00---10 +1011001011 --111-----1-------1--0-------1----1 +0111001011 --10-0---00--0-----0---0---------0- +1111001011 ---0--100-----0---0--00---111-----0 +0000101011 -------01-------0-01-1-----1------- +1000101011 -----00---011---111-0---0-1----0--- +0100101011 0------00---1-1---01--0-00-1--0-000 +1100101011 ----0------1-00-0--1-0--1------1--- +0010101011 --10--00-01--1-0----1--0-----0----- +1010101011 -0-00---1--000-1-1-00--0----------- +0110101011 -----000000--0------0----0--1--0-0- +1110101011 01--0----0-0000001--1-10000---000-- +0001101011 -0----0-------0--00-0-100-------10- +1001101011 ----------00-----1-0--000-0-0--0000 +0101101011 ---10----1---01--0----00-0--1------ +1101101011 1--10---1-0---------10-1---1--1-1-- +0011101011 ----01--0-1--10-1--00-0--1----0-0-- +1011101011 ---0---01-------1-1-------1--1-1--0 +0111101011 -------1------11-110-0--------0001- +1111101011 0----0-------0-0----------1---0---- +0000011011 -1--00000-----1-0-1-0-----1011----- +1000011011 -----0------------01-----0--------- +0100011011 --0-------1-1-0-----0-1-0---0---0-- +1100011011 -1--------------0--1-0--00-0-0-00-- +0010011011 0-1---------0011----0-101-----0--0- +1010011011 ----0-0--0-1--0----0--------0------ +0110011011 ----------1----0-----0--0-1---0--10 +1110011011 ---------010-00--0-1---00--0-0---1- +0001011011 -----1----1-0-01----1------------11 +1001011011 --0---10-----1-----0-0--0-----0--0- +0101011011 -0--000---0-0---------00-1---01-00- +1101011011 ------0-1-000-0---0100----0-------- +0011011011 1--1--------0--1-10-0----------0--- +1011011011 --1---1----1----0-100-0-00----10--- +0111011011 ------10-1---10--0-0----0-------0-- +1111011011 -1-------1----0------1-0-0---1010-- +0000111011 -0--------10-----0-------0-0------1 +1000111011 --0---0--0-1-1-0------01-00-------0 +0100111011 -0-0-----01-1--0---0-------------0- +1100111011 --0---10----10--0-0----1--1---0---- +0010111011 -1----0-------000------1--------110 +1010111011 --0--0--1-00-1-010-------------0--- +0110111011 ---001---10--00----------0--------- +1110111011 ------0--10---------1---00-0110---- +0001111011 0-----01-----0-----11-1-1------0-10 +1001111011 -0-110--00---1-0-1----0-100-----1-1 +0101111011 --------110-------1-1--0-0-000----1 +1101111011 11-01---------00-110--00-1-1----0-- +0011111011 -0-0--000-0--11--0---------0---1--- +1011111011 -0---0-0-----0--01-00---1--1--00-0- +0111111011 ---0---0-00---0010--0---------00-1- +1111111011 0--10-----------0----0----000------ +0000000111 -0-1---0--1--1----0-----0---0--10-1 +1000000111 ----0-00-1----1--0-0--11------0-0-1 +0100000111 --1-01----010---0--01--0-------0000 +1100000111 10----0-------1-----11-0----------- +0010000111 00-------1--1------0-1---11-0--0000 +1010000111 -00--0-0-0-00010--0---------010--1- +0110000111 ------1-1--1-----0101----0--0----0- +1110000111 --1--1-----1-0---1------0--00-0---- +0001000111 -0----0-----------1-00-1--00-1--00- +1001000111 -0-0--0-1-0--0-1000---------0-00--- +0101000111 0--------1-1-0-0----00-----1-----1- +1101000111 -10-010-----01-1--01-0---00-1--0001 +0011000111 ------0------1-0---1--0-----------0 +1011000111 -0---------00------------1-----0--- +0111000111 11--0-0-----00-0-10---01-0---0----- +1111000111 0-------00011----1----0--1---1----- +0000100111 -----0--11---10--0--------0-0------ +1000100111 0----00-0------11-------0-----1000- +0100100111 -0----10---1------------0---01-0--- +1100100111 0-1--10----0-01-0---0-0-10--------1 +0010100111 --------0---------0---0--0-100---0- +1010100111 0-0-0---0011----1--0--1-0----00---- +0110100111 ---0-0----0-----10-0-1-1----------- +1110100111 1---------0-1----1-------0000---1-- +0001100111 --0-0---------0-0-00--0----00-1---- +1001100111 -0--1-01----0-000-----------1------ +0101100111 -1-0-0-----0-01--0-----0----10-0-1- +1101100111 11----10-00010--------0-0--1--0---- +0011100111 -----0---1-----0---1---00---------- +1011100111 -0---0-0--1--1-----0---0110-------- +0111100111 --1------0-0--01-0-10-0---0------0- +1111100111 0-------0--------100----011-------- +0000010111 -------0--0---10---0-00-1--10--01-- +1000010111 -1------0-------0-----1-1-0---0-1-- +0100010111 0---0---1-----0--1-01-----1-1---1-1 +1100010111 -------0------1-0---0---0----100000 +0010010111 ------01---0--1---0-0-----0-------- +1010010111 0-----0-1--010-0000--1----0--0-1-1- +0110010111 -00-0---1-01----0--1-0--1------1--0 +1110010111 ----------0--0---------1-01000----- +0001010111 --001----1------0--10-----1-------- +1001010111 ---00---0--1--11-0-1-0--11-----1--0 +0101010111 -1-0-1--------0----1--00------1--0- +1101010111 ---------------01----0-----10-0---- +0011010111 0--01-0-----1---0---0-1-00-----0--1 +1011010111 0----0---0--0--1---01-----0---00--- +0111010111 0-----1----0----11-----01-00-00-0-- +1111010111 -1-----0--0-1-0-----1-1--10--1---0- +0000110111 0-0--001-------1--1--0--01--------- +1000110111 --00-1--00-----01-----10--------0-0 +0100110111 ------0---00-----0-1--10---0-1----- +1100110111 0-----0--0---------101--10-1001-0-0 +0010110111 0--0--1--0---1-1-----0-0---0------- +1010110111 ----00----1-1-----10-1-0--0-0001--- +0110110111 ---0--------0----------000--0------ +1110110111 -0-----------00--001---00-0--10-1-- +0001110111 ---------11----0-------1--------0-- +1001110111 00---------0---0-00-1---0110--0---0 +0101110111 ----1001--1--10------01--0----0---0 +1101110111 0----0------0------0------1-----0-- +0011110111 --1--00----01---00--000--1--0------ +1011110111 1---0-1-0--1-1--0-----10--0---1-1-- +0111110111 --1-00---0--0----01---------11---1- +1111110111 ----0-----01---000-1-10---0--000-0- +0000001111 0------101-0--0-1-00---1-00-0-0---- +1000001111 --1--0-11-0--0----0-0----00-------- +0100001111 1------1-0-1--0-0-0-1---------0--0- +1100001111 00--00--10--1-010------0-------00-1 +0010001111 -----0-0--010-1-0--0---1--1-1--1--- +1010001111 --0------01---0----1--0--1----01--- +0110001111 -0---0------------1-------0----10-- +1110001111 -----10-0-1--1----0-00---0--------- +0001001111 -----11-------1---------01---1--01- +1001001111 0----00---11-10-0-1-10--------00--1 +0101001111 ----1---1---------1---------------- +1101001111 0-10---00----01----0---0001---0-00- +0011001111 1----0-00----0-1----------0--10--0- +1011001111 --00-1-----0-0---0--01--1---1------ +0111001111 -00-0-10-------0-00-----0-----11-1- +1111001111 00-0--11--101------------------00-- +0000101111 ----0-100-----------00--0-1--0----- +1000101111 1------01-1--0---1-----1-0--11-0100 +0100101111 ------110----00-00------1-100----0- +1100101111 0----0-1------1----1----0-0-10-0-0- +0010101111 -1-----1-0-00------00--1-----110--- +1010101111 --1--1-1------------01--1--0-00--10 +0110101111 --1---1---------00---000----001---- +1110101111 0011---0-------1-10--0-01001------- +0001101111 -0----------0---0----00-0---------- +1001101111 0000----1--0--------1--------100-1- +0101101111 ----0-------0--1--1-0-----10---00-- +1101101111 0-01----01-1----1---0-----0-001---- +0011101111 00-0------------10-1---------0----- +1011101111 0-----0-1--0-1-0----0--1----000--0- +0111101111 ------0-0---100--------------0-1--- +1111101111 ---0------00--1-----1-1-001-------0 +0000011111 1------------00-----101-------01--- +1000011111 ----0--1-----00----00-10----------- +0100011111 -0---0---01-0--0-0-00-----0----1--- +1100011111 ---1----0-1--------------0------0-- +0010011111 ----0-----0-0--1------0-----------1 +1010011111 -----0-----0-0---01-----001-----0-- +0110011111 010--00----0-0-0------1-----1-----1 +1110011111 0-0--------0--10----1-------------0 +0001011111 01-0-11101--0-0-0--000-------0----0 +1001011111 -10-------0------1-0--0------------ +0101011111 0---1---00001--------0--00------000 +1101011111 0--------0-0-1-1---0----1----0-1--- +0011011111 ----1-0-1-01--01-01----0-0--0-0---- +1011011111 --0---1--------1----1----0---0-1--- +0111011111 -0---1-0-10-0--0-------------10--0- +1111011111 -1-----0---1---1--------1-0-0---0-- +0000111111 ----00--01--------00-0-----0-----01 +1000111111 ---0---1-----0--00---0----1--001--- +0100111111 1--1----0-1--0-1------0--0---0000-- +1100111111 -1---------------0-1-10--0----0-0-- +0010111111 ----01-------001-0----------00-0--- +1010111111 -0--------1---0--------------1----0 +0110111111 011-0------------------1--0000-0--- +1110111111 0------0--10100-0--00--0----------- +0001111111 ------1----100---001--0---0-0--0--- +1001111111 -00-1-0--0-0--0-----0-0--10-0-1---0 +0101111111 1-0-1------01-1-0--------00-0--00-- +1101111111 --0-11----1--0---0---11--------01-- +0011111111 -0----10-01010----0-----0-----1--1- +1011111111 ----1---1-1----00-1-0-0--0---1-0-01 +0111111111 00-0--0-11--1-----00-11--0-0-11---1 +1111111111 1-------------1---1-00--0-0-1-----1 diff --git a/espresso/examples/random/test4 b/espresso/examples/random/test4 new file mode 100644 index 0000000..547acad --- /dev/null +++ b/espresso/examples/random/test4 @@ -0,0 +1,258 @@ +.i 8 +.o 30 +00000000 ------1--1--1----1--------0--1 +10000000 --------1------1---------1--01 +01000000 --11--111------------1------1- +11000000 0-------1------1-1-1---01--1-- +00100000 00-0-0---1-1--1---1----1-0111- +10100000 -1---10------0---1------------ +01100000 10------1---110-0-111--0-1---0 +11100000 -1--0-----------1----1-1-1---- +00010000 --1-------010------------1-1-- +10010000 1-----------0--11-1---10---0-- +01010000 00-----1-11-0--1---1-1-1111--0 +11010000 --------101----1---1-1----1--- +00110000 --0--1--1----111-01--1-110---- +10110000 11--1--0---111--1--011-------- +01110000 -1------0----1-0-------00----1 +11110000 -0-----1-11----10--11-10---1-- +00001000 11--------1-----111-----1--011 +10001000 ------------1------1------11-- +01001000 1-1--00-1-10-----01---1-1--1-1 +11001000 -1----01--11--1-0------1------ +00101000 ---01---0-11-------0-0-11----- +10101000 --1-1----0-----1-1---1-------1 +01101000 1-1--0-------0----1-0---1----- +11101000 0-101-------1----------1----11 +00011000 -10------0-11------01-0-1-0--1 +10011000 -1-1-----------1----0---1-0--- +01011000 -0-1-------1---0--10-1-1------ +11011000 01110------------------1------ +00111000 -----0----10010--1----1----0-1 +10111000 -1--1----1--11-----00--0--011- +01111000 1--1---1---1-11------1-------- +11111000 0---1--0--00-------0-0-1-01-1- +00000100 1---01---------0-00-11---01--1 +10000100 0--------010---110--0----1---1 +01000100 0----------0-1---110------0--1 +11000100 -01--------1---1--------1----- +00100100 -----1------0-----1--1-0-----1 +10100100 -----1----0-1011-------0------ +01100100 -1----1-0--00------10-11--0-1- +11100100 01-1-------1-1--0---1--------- +00010100 --0-----------1--1----0---1--- +10010100 --1--11-01--------0---1--10--0 +01010100 11---0--11-1-------1--------0- +11010100 11---0---------11----------1-- +00110100 -1-1-11--0--11-0---1---10---0- +10110100 -1--1----0111-----0---1-----1- +01110100 1-1--1-------1--------11------ +11110100 1--1--0---0-1--1---1-1------0- +00001100 ----11-----1---0----111------- +10001100 0-1--1-----11------1--01---0-- +01001100 -1--11---01------1--1-------11 +11001100 ---1-----1-0---10--1---------- +00101100 1--1----1-1---1---01----10--00 +10101100 01-0-----1---1-1-1---1-00--11- +01101100 -----1----1-1---1-1----------- +11101100 --1---001----1-0---1-0---0-01- +00011100 -1--10---0----11---01---01---- +10011100 -0----1-101-1-----0--1-----1-- +01011100 -----------10----0--0-11-----1 +11011100 0---1-010---1----1-1-----1---- +00111100 1---0---1-----1------111------ +10111100 ---0-----0--0----11-11-1-----1 +01111100 ----1--0--1----1-11---1------- +11111100 -1-0---1--------01------------ +00000010 -1----1---111----0--1-1------- +10000010 -1--------0-1---11101--11----- +01000010 01111------0----1--1-0010-11-- +11000010 --------1-1---0---11---1-----1 +00100010 ---1-1-11---------001------1-- +10100010 -11-0-------01--1-----1-11---- +01100010 --------------1------0-------- +11100010 -----------1-1---11--0-11-1--- +00010010 11--01--------11----1-----11-1 +10010010 -1-1---0-0-------1---------11- +01010010 -1-001---1---000-----1-----0-1 +11010010 -01----1--0--11---1---------11 +00110010 1---1--0-------1---------0---- +10110010 0---1100---------01-1-1--1-0-- +01110010 ---10-11----1-11---0--11--1-11 +11110010 ---11-10----1---1----0-----1-0 +00001010 --1-1--1110101-1------1-11-0-- +10001010 ---0---1--1-0--10------------- +01001010 -1----1------1------0-1-1-1--- +11001010 -1----1--10---0-1---110-0---00 +00101010 -0--1---0--0-1--1-1----1--0-1- +10101010 ----1----1--11-0--1-1-1------- +01101010 -1-----11001---0----0--0-0--1- +11101010 -000--00----0----------1---0-1 +00011010 -11---0--------------0-------- +10011010 10--1-1---0-------11--0-0-1-01 +01011010 1-0-11--0----1------01--1----- +11011010 1------11--1----0---11-0110--- +00111010 -----------1----1-1---------1- +10111010 ---------11-01-1-1--11--0-1--0 +01111010 --11-----1---000--11-0-----0-- +11111010 1--0-1-----1-----0-----1------ +00000110 -011-1------1-----1---0--1--1- +10000110 -110-------0-110--0-------101- +01000110 1--1---011--1-----1-------1--0 +11000110 -1-----1-1--1---01------11---- +00100110 -1--0---1------0-----0--1----- +10100110 -----1---01---1------1------1- +01100110 -10-----------0----0--0------- +11100110 ---1-1-1--------0--1----1--1-- +00010110 -10-1------101--1-11--------1- +10010110 --111---0----------11-1----1-0 +01010110 1--------100-------1-0-------- +11010110 1-11--1--1---------11-1---1-0- +00110110 -0----1-------1--0-1--1---1--- +10110110 --1----11-1----01----------1-- +01110110 --1010--101-----------1-00---- +11110110 11-1-----11---00-1--10-11-1--- +00001110 ----1---0--1---00--1--1-10-0-- +10001110 1---------0-0---1--11-1--01110 +01001110 --1-1--101-1----------0------- +11001110 ----1110-1-----1-------0------ +00101110 ---1---100-0--01----011-1-010- +10101110 -----1-0------1-0-11----1-1--- +01101110 ---------10--------10---10---- +11101110 --------0--1-0-1-----11------- +00011110 0--11----1--0--11-1-1---1-0--- +10011110 -1-0--0-1-1010---1-------10-11 +01011110 ---0---1---11-------11--11--1- +11011110 --1-1-00-11---10--1-1------1-0 +00111110 ----1-11-------1---0-1---1---- +10111110 -0---0--1----01-0-11111---1--- +01111110 -10---1--1-----1----0-----0--1 +11111110 ---------------1----------0-0- +00000001 ----11-0-1-1---1------1--1--10 +10000001 0---1-------1--------1-10-1--- +01000001 -0----1-11-0--0---1------1---- +11000001 -----1---1-------1-01---110-0- +00100001 -1------11---0-11---0110----1- +10100001 -111-1--1---11-0--1---10---0-- +01100001 -101----1---0--11------------0 +11100001 1---1--1---1--------1--0-0---1 +00010001 --1--1-1----1-------0--------- +10010001 ----1-----1----1--1--11------- +01010001 1-1--1-1-110---1----0-----1-1- +11010001 111---1--1--0---1-----0-110--- +00110001 --1--------1----1------------1 +10110001 -11-11--1------1-----01-1--1-- +01110001 -----11-----1-----01--1----0-- +11110001 ----10-----1--0----1---1----1- +00001001 ------1------11-0-1--1-----1-- +10001001 -000-1--1-----1-1----1----1-0- +01001001 --1-------1--1-----1-0-----001 +11001001 1-1----------11----1-11----11- +00101001 -1-----1------0--1-------0---- +10101001 1------1--1------01--0--001--- +01101001 --0--10-----1--11-11-0---1---- +11101001 ------0----1---101-10-1--00--- +00011001 ---0---00----101-----------111 +10011001 11-10---1------------------00- +01011001 0------11---1-----11--0-00-1-- +11011001 -1-0-1----10---1-111--111---0- +00111001 -----1-------1-----0----0--0-1 +10111001 -----1------1---01-1--110---11 +01111001 -0-----------1----1---0------1 +11111001 ----1----110101--------------- +00000101 ------1---011--11------1-01--- +10000101 -----1---0---1--------1----1-- +01000101 ---11--1--10-1-----1----1-11-0 +11000101 --1-01----1---0---10-1--0-101- +00100101 1-10-1-----0--01----1-------1- +10100101 ------1-----1111-1----01-----0 +01100101 0----11---------111-1-1-1--11- +11100101 0--10-1-100--11--------100--1- +00010101 --11-01-011-1----1-------1--1- +10010101 -0-----0-11---1----11-1--0---- +01010101 --1--0-1---1---0---1------01-- +11010101 10------0----------11-1------- +00110101 --1--------1-1--0--1---1--11-0 +10110101 --1-1--010---1---------------1 +01110101 --1-1-------0-------1--10----- +11110101 -0011-1101-11--100--111------- +00001101 ------------1--0-----0-------- +10001101 0--1-1------1101-1--------01-- +01001101 --1---------1-1---1----------- +11001101 ------1---10-------0---------- +00101101 0---------1----1--1-------0--- +10101101 -1----------1011--------0----- +01101101 -1-1----1----1-0----111------- +11101101 ---1-0--------110-0-------0-11 +00011101 01----1----01-----1----1----1- +10011101 -1---11-------010---0--10----1 +01011101 ------1------1--1---0-1--0--1- +11011101 011----1---0--1----1-0-1----1- +00111101 1--1-1-----1-11-1--0----10-10- +10111101 ---11---0-----10-0-1-11---111- +01111101 1----11--0-1--1-0-----------1- +11111101 ---0----0---1-------0-10------ +00000011 1-1-11----1-0-1-10-1--11-----1 +10000011 11-----1----110-----0-------01 +01000011 --00------1----------1-----010 +11000011 -1-11-10----110--1-1---1-1---- +00100011 ---0---0-10---1----1-01------- +10100011 --0----1----1---1--1------1--1 +01100011 -----1-11---1----0---1---1-0-- +11100011 0--1----1--0---0-----11-0--1-- +00010011 ----------1---11---11--011---1 +10010011 -1---1---1110---0----1-1-1--10 +01010011 ----------0--0--1----------1-- +11010011 -------11---------------1---0- +00110011 -1-1------0--1------1--1--1-1- +10110011 -1---11--0--1-11-------1-1---- +01110011 -----011----1---1------1--1-0- +11110011 -1-0-0---0--------1------1---- +00001011 --1-----1------1---1----11--0- +10001011 1--1--1--11-------111-1------- +01001011 1---------0---------1----0--11 +11001011 -11-011-1----1-110--1101--1--- +00101011 -1--1---10---1-11-1--11--1---1 +10101011 ----1-1---0---11-0----11---0-- +01101011 ------1--0-1-0--1-1-1----100-1 +11101011 -1----0-0-00---11----------10- +00011011 -1-------1--0-1-0------------- +10011011 --1--11----1-0--1-----0----00- +01011011 -1---0----------------1-1----- +11011011 -------1-------0-111----11-1-- +00111011 --1-101-11-----0-----1-------- +10111011 ----0--1--1-11-1---1--1--1---- +01111011 11--1--------------1---1------ +11111011 --11--1--1-1-0---0--0-------11 +00000111 -----1101-1------0-0-1-01--110 +10000111 -----1--11-0---------1------0- +01000111 1---0--1---1---1--------1-00-- +11000111 1----11------1--1-----1-011--- +00100111 0---11-------0-0--00-1-00--0-- +10100111 -0----1--101------0----1------ +01100111 -01---0-1----1110--01----1---- +11100111 1----1------1---0-1--00-0-10-- +00010111 11-1-----0-11---01----1---1-1- +10010111 ---11----------1--1---001-0--- +01010111 ------1---1------1------0--1-- +11010111 ---1---------0----0-----11-1-0 +00110111 ----1--1-11--11-1------1-1-1-- +10110111 ----0--0----1---1----1-01--001 +01110111 --10----1-0------1--1-0------- +11110111 --------1---0-----1---------1- +00001111 --0-0111----1--11-0---0---10-- +10001111 --11----------01-------1-----1 +01001111 -----01--1------1-----1----0-- +11001111 --1--1-0-11----0-11-1-----1--- +00101111 -0-0-01-----11--1--0-------1-- +10101111 01---0-------11--1---0--1-1-01 +01101111 -----0----11-0-10-0-0---1-111- +11101111 --------0----1--01-1------11-- +00011111 1--1-----0--11--0-----1-1----- +10011111 --------1-1-1-1----1-0--0-0--- +01011111 ----1-----01-1--10-0----01---- +11011111 ---1----0--1----01-0----1--01- +00111111 1111---0---1--10-11-1-1--01--- +10111111 -0--------------------11-1--1- +01111111 -1-01---------11-1----1--0---1 +11111111 ---0--1------0-1-------0-01--- diff --git a/espresso/expand.c b/espresso/expand.c new file mode 100644 index 0000000..4475dfd --- /dev/null +++ b/espresso/expand.c @@ -0,0 +1,689 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/expand.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + module: expand.c + purpose: Perform the Espresso-II Expansion Step + + The idea is to take each nonprime cube of the on-set and expand it + into a prime implicant such that we can cover as many other cubes + of the on-set. If no cube of the on-set can be covered, then we + expand each cube into a large prime implicant by transforming the + problem into a minimum covering problem which is solved by the + heuristics of minimum_cover. + + These routines revolve around having a representation of the + OFF-set. (In contrast to the Espresso-II manuscript, we do NOT + require an "unwrapped" version of the OFF-set). + + Some conventions on variable names: + + SUPER_CUBE is the supercube of all cubes which can be covered + by an expansion of the cube being expanded + + OVEREXPANDED_CUBE is the cube which would result from expanding + all parts which can expand individually of the cube being expanded + + RAISE is the current expansion of the current cube + + FREESET is the set of parts which haven't been raised or lowered yet. + + INIT_LOWER is a set of parts to be removed from the free parts before + starting the expansion +*/ + +#include "espresso.h" + +/* + expand -- expand each nonprime cube of F into a prime implicant + + If nonsparse is true, only the non-sparse variables will be expanded; + this is done by forcing all of the sparse variables out of the free set. +*/ + +pcover expand(F, R, nonsparse) +INOUT pcover F; +IN pcover R; +IN bool nonsparse; /* expand non-sparse variables only */ +{ + register pcube last, p; + pcube RAISE, FREESET, INIT_LOWER, SUPER_CUBE, OVEREXPANDED_CUBE; + int var, num_covered; + bool change; + + /* Order the cubes according to "chewing-away from the edges" of mini */ + if (use_random_order) + F = random_order(F); + else + F = mini_sort(F, ascend); + + /* Allocate memory for variables needed by expand1() */ + RAISE = new_cube(); + FREESET = new_cube(); + INIT_LOWER = new_cube(); + SUPER_CUBE = new_cube(); + OVEREXPANDED_CUBE = new_cube(); + + /* Setup the initial lowering set (differs only for nonsparse) */ + if (nonsparse) + for(var = 0; var < cube.num_vars; var++) + if (cube.sparse[var]) + (void) set_or(INIT_LOWER, INIT_LOWER, cube.var_mask[var]); + + /* Mark all cubes as not covered, and maybe essential */ + foreach_set(F, last, p) { + RESET(p, COVERED); + RESET(p, NONESSEN); + } + + /* Try to expand each nonprime and noncovered cube */ + foreach_set(F, last, p) { + /* do not expand if PRIME or if covered by previous expansion */ + if (! TESTP(p, PRIME) && ! TESTP(p, COVERED)) { + + /* expand the cube p, result is RAISE */ + expand1(R, F, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + INIT_LOWER, &num_covered, p); + if (debug & EXPAND) + printf("EXPAND: %s (covered %d)\n", pc1(p), num_covered); + (void) set_copy(p, RAISE); + SET(p, PRIME); + RESET(p, COVERED); /* not really necessary */ + + /* See if we generated an inessential prime */ + if (num_covered == 0 && ! setp_equal(p, OVEREXPANDED_CUBE)) { + SET(p, NONESSEN); + } + } + } + + /* Delete any cubes of F which became covered during the expansion */ + F->active_count = 0; + change = FALSE; + foreach_set(F, last, p) { + if (TESTP(p, COVERED)) { + RESET(p, ACTIVE); + change = TRUE; + } else { + SET(p, ACTIVE); + F->active_count++; + } + } + if (change) + F = sf_inactive(F); + + free_cube(RAISE); + free_cube(FREESET); + free_cube(INIT_LOWER); + free_cube(SUPER_CUBE); + free_cube(OVEREXPANDED_CUBE); + return F; +} + +/* + expand1 -- Expand a single cube against the OFF-set +*/ +void expand1(BB, CC, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + INIT_LOWER, num_covered, c) +pcover BB; /* Blocking matrix (OFF-set) */ +pcover CC; /* Covering matrix (ON-set) */ +pcube RAISE; /* The current parts which have been raised */ +pcube FREESET; /* The current parts which are free */ +pcube OVEREXPANDED_CUBE; /* Overexpanded cube of c */ +pcube SUPER_CUBE; /* Supercube of all cubes of CC we cover */ +pcube INIT_LOWER; /* Parts to initially remove from FREESET */ +int *num_covered; /* Number of cubes of CC which are covered */ +pcube c; /* The cube to be expanded */ +{ + int bestindex; + + if (debug & EXPAND1) + printf("\nEXPAND1: \t%s\n", pc1(c)); + + /* initialize BB and CC */ + SET(c, PRIME); /* don't try to cover ourself */ + setup_BB_CC(BB, CC); + + /* initialize count of # cubes covered, and the supercube of them */ + *num_covered = 0; + (void) set_copy(SUPER_CUBE, c); + + /* Initialize the lowering, raising and unassigned sets */ + (void) set_copy(RAISE, c); + (void) set_diff(FREESET, cube.fullset, RAISE); + + /* If some parts are forced into lowering set, remove them */ + if (! setp_empty(INIT_LOWER)) { + (void) set_diff(FREESET, FREESET, INIT_LOWER); + elim_lowering(BB, CC, RAISE, FREESET); + } + + /* Determine what can be raised, and return the over-expanded cube */ + essen_parts(BB, CC, RAISE, FREESET); + (void) set_or(OVEREXPANDED_CUBE, RAISE, FREESET); + + /* While there are still cubes which can be covered, cover them ! */ + if (CC->active_count > 0) { + select_feasible(BB, CC, RAISE, FREESET, SUPER_CUBE, num_covered); + } + + /* While there are still cubes covered by the overexpanded cube ... */ + while (CC->active_count > 0) { + bestindex = most_frequent(CC, FREESET); + set_insert(RAISE, bestindex); + set_remove(FREESET, bestindex); + essen_parts(BB, CC, RAISE, FREESET); + } + + /* Finally, when all else fails, choose the largest possible prime */ + /* We will loop only if we decide unravelling OFF-set is too expensive */ + while (BB->active_count > 0) { + mincov(BB, RAISE, FREESET); + } + + /* Raise any remaining free coordinates */ + (void) set_or(RAISE, RAISE, FREESET); +} + +/* + essen_parts -- determine which parts are forced into the lowering + set to insure that the cube be orthognal to the OFF-set. + + If any cube of the OFF-set is distance 1 from the raising cube, + then we must lower all parts of the conflicting variable. (If the + cube is distance 0, we detect this error here.) + + If there are essentially lowered parts, we can remove from consideration + any cubes of the OFF-set which are more than distance 1 from the + overexpanded cube of RAISE. +*/ + +void essen_parts(BB, CC, RAISE, FREESET) +pcover BB, CC; +pcube RAISE, FREESET; +{ + register pcube p, r = RAISE; + pcube lastp, xlower = cube.temp[0]; + int dist; + + (void) set_copy(xlower, cube.emptyset); + + foreach_active_set(BB, lastp, p) { +#ifdef NO_INLINE + if ((dist = cdist01(p, r)) > 1) goto exit_if; +#else + {register int w,last;register unsigned int x;dist=0;if((last=cube.inword)!=-1) +{x=p[last]&r[last];if(x=~(x|x>>1)&cube.inmask)if((dist=count_ones(x))>1)goto +exit_if;for(w=1;w>1)&DISJOINT)if(dist==1||( +dist+=count_ones(x))>1)goto exit_if;}}}{register int w,var,last;register pcube +mask;for(var=cube.num_binary_vars;var1)goto exit_if;nextvar:;}} +#endif + if (dist == 0) { + fatal("ON-set and OFF-set are not orthogonal"); + } else { + (void) force_lower(xlower, p, r); + BB->active_count--; + RESET(p, ACTIVE); + } +exit_if: ; + } + + if (! setp_empty(xlower)) { + (void) set_diff(FREESET, FREESET, xlower);/* remove from free set */ + elim_lowering(BB, CC, RAISE, FREESET); + } + + if (debug & EXPAND1) + printf("ESSEN_PARTS:\tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); +} + +/* + essen_raising -- determine which parts may always be added to + the raising set without restricting further expansions + + General rule: if some part is not blocked by any cube of BB, then + this part can always be raised. +*/ + +void essen_raising(BB, RAISE, FREESET) +register pcover BB; +pcube RAISE, FREESET; +{ + register pcube last, p, xraise = cube.temp[0]; + + /* Form union of all cubes of BB, and then take complement wrt FREESET */ + (void) set_copy(xraise, cube.emptyset); + foreach_active_set(BB, last, p) + INLINEset_or(xraise, xraise, p); + (void) set_diff(xraise, FREESET, xraise); + + (void) set_or(RAISE, RAISE, xraise); /* add to raising set */ + (void) set_diff(FREESET, FREESET, xraise); /* remove from free set */ + + if (debug & EXPAND1) + printf("ESSEN_RAISING:\tRAISE=%s FREESET=%s\n", + pc1(RAISE), pc2(FREESET)); +} + +/* + elim_lowering -- after removing parts from FREESET, we can reduce the + size of both BB and CC. + + We mark as inactive any cube of BB which does not intersect the + overexpanded cube (i.e., RAISE + FREESET). Likewise, we remove + from CC any cube which is not covered by the overexpanded cube. +*/ + +void elim_lowering(BB, CC, RAISE, FREESET) +pcover BB, CC; +pcube RAISE, FREESET; +{ + register pcube p, r = set_or(cube.temp[0], RAISE, FREESET); + pcube last; + + /* + * Remove sets of BB which are orthogonal to future expansions + */ + foreach_active_set(BB, last, p) { +#ifdef NO_INLINE + if (! cdist0(p, r)) +#else + {register int w,lastw;register unsigned int x;if((lastw=cube.inword)!=-1){x=p[ +lastw]&r[lastw];if(~(x|x>>1)&cube.inmask)goto false;for(w=1;w>1)&DISJOINT)goto false;}}}{register int w,var,lastw;register +pcube mask;for(var=cube.num_binary_vars;varactive_count--, RESET(p, ACTIVE); + } + + + /* + * Remove sets of CC which cannot be covered by future expansions + */ + if (CC != (pcover) NULL) { + foreach_active_set(CC, last, p) { +#ifdef NO_INLINE + if (! setp_implies(p, r)) +#else + INLINEsetp_implies(p, r, /* when false => */ goto false1); + /* when true => go to end of loop */ continue; + false1: +#endif + CC->active_count--, RESET(p, ACTIVE); + } + } +} + +/* + most_frequent -- When all else fails, select a reasonable part to raise + The active cubes of CC are the cubes which are covered by the + overexpanded cube of the original cube (however, we know that none + of them can actually be covered by a feasible expansion of the + original cube). We resort to the MINI strategy of selecting to + raise the part which will cover the same part in the most cubes of CC. +*/ +int most_frequent(CC, FREESET) +pcover CC; +pcube FREESET; +{ + register int i, best_part, best_count, *count; + register pset p, last; + + /* Count occurences of each variable */ + count = ALLOC(int, cube.size); + for(i = 0; i < cube.size; i++) + count[i] = 0; + if (CC != (pcover) NULL) + foreach_active_set(CC, last, p) + set_adjcnt(p, count, 1); + + /* Now find which free part occurs most often */ + best_count = best_part = -1; + for(i = 0; i < cube.size; i++) + if (is_in_set(FREESET,i) && count[i] > best_count) { + best_part = i; + best_count = count[i]; + } + FREE(count); + + if (debug & EXPAND1) + printf("MOST_FREQUENT:\tbest=%d FREESET=%s\n", best_part, pc2(FREESET)); + return best_part; +} + +/* + setup_BB_CC -- set up the blocking and covering set families; + + Note that the blocking family is merely the set of cubes of R, and + that CC is the set of cubes of F which might possibly be covered + (i.e., nonprime cubes, and cubes not already covered) +*/ + +void setup_BB_CC(BB, CC) +register pcover BB, CC; +{ + register pcube p, last; + + /* Create the block and cover set families */ + BB->active_count = BB->count; + foreach_set(BB, last, p) + SET(p, ACTIVE); + + if (CC != (pcover) NULL) { + CC->active_count = CC->count; + foreach_set(CC, last, p) + if (TESTP(p, COVERED) || TESTP(p, PRIME)) + CC->active_count--, RESET(p, ACTIVE); + else + SET(p, ACTIVE); + } +} + +/* + select_feasible -- Determine if there are cubes which can be covered, + and if so, raise those parts necessary to cover as many as possible. + + We really don't check to maximize the number that can be covered; + instead, we check, for each fcc, how many other fcc remain fcc + after expanding to cover the fcc. (Essentially one-level lookahead). +*/ + +void select_feasible(BB, CC, RAISE, FREESET, SUPER_CUBE, num_covered) +pcover BB, CC; +pcube RAISE, FREESET, SUPER_CUBE; +int *num_covered; +{ + register pcube p, last, bestfeas, *feas; + register int i, j; + pcube *feas_new_lower; + int bestcount, bestsize, count, size, numfeas, lastfeas; + pcover new_lower; + + /* Start out with all cubes covered by the over-expanded cube as + * the "possibly" feasibly-covered cubes (pfcc) + */ + feas = ALLOC(pcube, CC->active_count); + numfeas = 0; + foreach_active_set(CC, last, p) + feas[numfeas++] = p; + + /* Setup extra cubes to record parts forced low after a covering */ + feas_new_lower = ALLOC(pcube, CC->active_count); + new_lower = new_cover(numfeas); + for(i = 0; i < numfeas; i++) + feas_new_lower[i] = GETSET(new_lower, i); + + +loop: + /* Find the essentially raised parts -- this might cover some cubes + for us, without having to find out if they are fcc or not + */ + essen_raising(BB, RAISE, FREESET); + + /* Now check all "possibly" feasibly covered cubes to check feasibility */ + lastfeas = numfeas; + numfeas = 0; + for(i = 0; i < lastfeas; i++) { + p = feas[i]; + + /* Check active because essen_parts might have removed it */ + if (TESTP(p, ACTIVE)) { + + /* See if the cube is already covered by RAISE -- + * this can happen because of essen_raising() or because of + * the previous "loop" + */ + if (setp_implies(p, RAISE)) { + (*num_covered) += 1; + (void) set_or(SUPER_CUBE, SUPER_CUBE, p); + CC->active_count--; + RESET(p, ACTIVE); + SET(p, COVERED); + /* otherwise, test if it is feasibly covered */ + } else if (feasibly_covered(BB,p,RAISE,feas_new_lower[numfeas])) { + feas[numfeas] = p; /* save the fcc */ + numfeas++; + } + } + } + if (debug & EXPAND1) + printf("SELECT_FEASIBLE: started with %d pfcc, ended with %d fcc\n", + lastfeas, numfeas); + + /* Exit here if there are no feasibly covered cubes */ + if (numfeas == 0) { + FREE(feas); + FREE(feas_new_lower); + free_cover(new_lower); + return; + } + + /* Now find which is the best feasibly covered cube */ + bestcount = 0; + bestsize = 9999; + for(i = 0; i < numfeas; i++) { + size = set_dist(feas[i], FREESET); /* # of newly raised parts */ + count = 0; /* # of other cubes which remain fcc after raising */ + +#define NEW +#ifdef NEW + for(j = 0; j < numfeas; j++) + if (setp_disjoint(feas_new_lower[i], feas[j])) + count++; +#else + for(j = 0; j < numfeas; j++) + if (setp_implies(feas[j], feas[i])) + count++; +#endif + if (count > bestcount) { + bestcount = count; + bestfeas = feas[i]; + bestsize = size; + } else if (count == bestcount && size < bestsize) { + bestfeas = feas[i]; + bestsize = size; + } + } + + /* Add the necessary parts to the raising set */ + (void) set_or(RAISE, RAISE, bestfeas); + (void) set_diff(FREESET, FREESET, RAISE); + if (debug & EXPAND1) + printf("FEASIBLE: \tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); + essen_parts(BB, CC, RAISE, FREESET); + goto loop; +/* NOTREACHED */ +} + +/* + feasibly_covered -- determine if the cube c is feasibly covered + (i.e., if it is possible to raise all of the necessary variables + while still insuring orthogonality with R). Also, if c is feasibly + covered, then compute the new set of parts which are forced into + the lowering set. +*/ + +bool feasibly_covered(BB, c, RAISE, new_lower) +pcover BB; +pcube c, RAISE, new_lower; +{ + register pcube p, r = set_or(cube.temp[0], RAISE, c); + int dist; + pcube lastp; + + set_copy(new_lower, cube.emptyset); + foreach_active_set(BB, lastp, p) { +#ifdef NO_INLINE + if ((dist = cdist01(p, r)) > 1) goto exit_if; +#else + {register int w,last;register unsigned int x;dist=0;if((last=cube.inword)!=-1) +{x=p[last]&r[last];if(x=~(x|x>>1)&cube.inmask)if((dist=count_ones(x))>1)goto +exit_if;for(w=1;w>1)&DISJOINT)if(dist==1||( +dist+=count_ones(x))>1)goto exit_if;}}}{register int w,var,last;register pcube +mask;for(var=cube.num_binary_vars;var1)goto exit_if;nextvar:;}} +#endif + if (dist == 0) + return FALSE; + else + (void) force_lower(new_lower, p, r); + exit_if: ; + } + return TRUE; +} + +/* + mincov -- transform the problem of expanding a cube to a maximally- + large prime implicant into the problem of selecting a minimum + cardinality cover over a family of sets. + + When we get to this point, we must unravel the remaining off-set. + This may be painful. +*/ + +void mincov(BB, RAISE, FREESET) +pcover BB; +pcube RAISE, FREESET; +{ + int expansion, nset, var, dist; + pset_family B; + register pcube xraise=cube.temp[0], xlower, p, last, plower; + +#ifdef RANDOM_MINCOV + dist = random() % set_ord(FREESET); + for(var = 0; var < cube.size && dist >= 0; var++) { + if (is_in_set(FREESET, var)) { + dist--; + } + } + + set_insert(RAISE, var); + set_remove(FREESET, var); + (void) essen_parts(BB, /*CC*/ (pcover) NULL, RAISE, FREESET); +#else + + /* Create B which are those cubes which we must avoid intersecting */ + B = new_cover(BB->active_count); + foreach_active_set(BB, last, p) { + plower = set_copy(GETSET(B, B->count++), cube.emptyset); + (void) force_lower(plower, p, RAISE); + } + + /* Determine how many sets it will blow up into after the unravel */ + nset = 0; + foreach_set(B, last, p) { + expansion = 1; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + if ((dist=set_dist(p, cube.var_mask[var])) > 1) { + expansion *= dist; + if (expansion > 500) goto heuristic_mincov; + } + } + nset += expansion; + if (nset > 500) goto heuristic_mincov; + } + + B = unravel(B, cube.num_binary_vars); + xlower = do_sm_minimum_cover(B); + + /* Add any remaining free parts to the raising set */ + (void) set_or(RAISE, RAISE, set_diff(xraise, FREESET, xlower)); + (void) set_copy(FREESET, cube.emptyset); /* free set is empty */ + BB->active_count = 0; /* BB satisfied */ + if (debug & EXPAND1) { + printf("MINCOV: \tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); + } + sf_free(B); + set_free(xlower); + return; + +heuristic_mincov: + sf_free(B); + /* most_frequent will pick first free part */ + set_insert(RAISE, most_frequent(/*CC*/ (pcover) NULL, FREESET)); + (void) set_diff(FREESET, FREESET, RAISE); + essen_parts(BB, /*CC*/ (pcover) NULL, RAISE, FREESET); + return; +#endif +} + +/* + find_all_primes -- find all of the primes which cover the + currently reduced BB +*/ +pcover find_all_primes(BB, RAISE, FREESET) +pcover BB; +register pcube RAISE, FREESET; +{ + register pset last, p, plower; + pset_family B, B1; + + if (BB->active_count == 0) { + B1 = new_cover(1); + p = GETSET(B1, B1->count++); + (void) set_copy(p, RAISE); + SET(p, PRIME); + } else { + B = new_cover(BB->active_count); + foreach_active_set(BB, last, p) { + plower = set_copy(GETSET(B, B->count++), cube.emptyset); + (void) force_lower(plower, p, RAISE); + } + B = sf_rev_contain(unravel(B, cube.num_binary_vars)); + B1 = exact_minimum_cover(B); + foreach_set(B1, last, p) { + INLINEset_diff(p, FREESET, p); + INLINEset_or(p, p, RAISE); + SET(p, PRIME); + } + free_cover(B); + } + return B1; +} + +/* + all_primes -- foreach cube in F, generate all of the primes + which cover the cube. +*/ + +pcover all_primes(F, R) +pcover F, R; +{ + register pcube last, p, RAISE, FREESET; + pcover Fall_primes, B1; + + FREESET = new_cube(); + RAISE = new_cube(); + Fall_primes = new_cover(F->count); + + foreach_set(F, last, p) { + if (TESTP(p, PRIME)) { + Fall_primes = sf_addset(Fall_primes, p); + } else { + /* Setup for call to essential parts */ + (void) set_copy(RAISE, p); + (void) set_diff(FREESET, cube.fullset, RAISE); + setup_BB_CC(R, /* CC */ (pcover) NULL); + essen_parts(R, /* CC */ (pcover) NULL, RAISE, FREESET); + + /* Find all of the primes, and add them to the prime set */ + B1 = find_all_primes(R, RAISE, FREESET); + Fall_primes = sf_append(Fall_primes, B1); + } + } + + set_free(RAISE); + set_free(FREESET); + return Fall_primes; +} diff --git a/espresso/gasp.c b/espresso/gasp.c new file mode 100644 index 0000000..f5f9a42 --- /dev/null +++ b/espresso/gasp.c @@ -0,0 +1,228 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/gasp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + module: gasp.c + + The "last_gasp" heuristic computes the reduction of each cube in + the cover (without replacement) and then performs an expansion of + these cubes. The cubes which expand to cover some other cube are + added to the original cover and irredundant finds a minimal subset. + + If one of the reduced cubes expands to cover some other reduced + cube, then the new prime thus generated is a candidate for reducing + the size of the cover. + + super_gasp is a variation on this strategy which extracts a minimal + subset from the set of all prime implicants which cover all + maximally reduced cubes. +*/ + +#include "espresso.h" + + +/* + * reduce_gasp -- compute the maximal reduction of each cube of F + * + * If a cube does not reduce, it remains prime; otherwise, it is marked + * as nonprime. If the cube is redundant (should NEVER happen here) we + * just crap out ... + * + * A cover with all of the cubes of F is returned. Those that did + * reduce are marked "NONPRIME"; those that reduced are marked "PRIME". + * The cubes are in the same order as in F. + */ +static pcover reduce_gasp(F, D) +pcover F, D; +{ + pcube p, last, cunder, *FD; + pcover G; + + G = new_cover(F->count); + FD = cube2list(F, D); + + /* Reduce cubes of F without replacement */ + foreach_set(F, last, p) { + cunder = reduce_cube(FD, p); + if (setp_empty(cunder)) { + fatal("empty reduction in reduce_gasp, shouldn't happen"); + } else if (setp_equal(cunder, p)) { + SET(cunder, PRIME); /* just to make sure */ + G = sf_addset(G, p); /* it did not reduce ... */ + } else { + RESET(cunder, PRIME); /* it reduced ... */ + G = sf_addset(G, cunder); + } + if (debug & GASP) { + printf("REDUCE_GASP: %s reduced to %s\n", pc1(p), pc2(cunder)); + } + free_cube(cunder); + } + + free_cubelist(FD); + return G; +} + +/* + * expand_gasp -- expand each nonprime cube of F into a prime implicant + * + * The gasp strategy differs in that only those cubes which expand to + * cover some other cube are saved; also, all cubes are expanded + * regardless of whether they become covered or not. + */ + +pcover expand_gasp(F, D, R, Foriginal) +INOUT pcover F; +IN pcover D; +IN pcover R; +IN pcover Foriginal; +{ + int c1index; + pcover G; + + /* Try to expand each nonprime and noncovered cube */ + G = new_cover(10); + for(c1index = 0; c1index < F->count; c1index++) { + expand1_gasp(F, D, R, Foriginal, c1index, &G); + } + G = sf_dupl(G); + G = expand(G, R, /*nonsparse*/ FALSE); /* Make them prime ! */ + return G; +} + + + +/* + * expand1 -- Expand a single cube against the OFF-set, using the gasp strategy + */ +void expand1_gasp(F, D, R, Foriginal, c1index, G) +pcover F; /* reduced cubes of ON-set */ +pcover D; /* DC-set */ +pcover R; /* OFF-set */ +pcover Foriginal; /* ON-set before reduction (same order as F) */ +int c1index; /* which index of F (or Freduced) to be checked */ +pcover *G; +{ + register int c2index; + register pcube p, last, c2under; + pcube RAISE, FREESET, temp, *FD, c2essential; + pcover F1; + + if (debug & EXPAND1) { + printf("\nEXPAND1_GASP: \t%s\n", pc1(GETSET(F, c1index))); + } + + RAISE = new_cube(); + FREESET = new_cube(); + temp = new_cube(); + + /* Initialize the OFF-set */ + R->active_count = R->count; + foreach_set(R, last, p) { + SET(p, ACTIVE); + } + /* Initialize the reduced ON-set, all nonprime cubes become active */ + F->active_count = F->count; + foreachi_set(F, c2index, c2under) { + if (c1index == c2index || TESTP(c2under, PRIME)) { + F->active_count--; + RESET(c2under, ACTIVE); + } else { + SET(c2under, ACTIVE); + } + } + + /* Initialize the raising and unassigned sets */ + (void) set_copy(RAISE, GETSET(F, c1index)); + (void) set_diff(FREESET, cube.fullset, RAISE); + + /* Determine parts which must be lowered */ + essen_parts(R, F, RAISE, FREESET); + + /* Determine parts which can always be raised */ + essen_raising(R, RAISE, FREESET); + + /* See which, if any, of the reduced cubes we can cover */ + foreachi_set(F, c2index, c2under) { + if (TESTP(c2under, ACTIVE)) { + /* See if this cube can be covered by an expansion */ + if (setp_implies(c2under, RAISE) || + feasibly_covered(R, c2under, RAISE, temp)) { + + /* See if c1under can expanded to cover c2 reduced against + * (F - c1) u c1under; if so, c2 can definitely be removed ! + */ + + /* Copy F and replace c1 with c1under */ + F1 = sf_save(Foriginal); + (void) set_copy(GETSET(F1, c1index), GETSET(F, c1index)); + + /* Reduce c2 against ((F - c1) u c1under) */ + FD = cube2list(F1, D); + c2essential = reduce_cube(FD, GETSET(F1, c2index)); + free_cubelist(FD); + sf_free(F1); + + /* See if c2essential is covered by an expansion of c1under */ + if (feasibly_covered(R, c2essential, RAISE, temp)) { + (void) set_or(temp, RAISE, c2essential); + RESET(temp, PRIME); /* cube not prime */ + *G = sf_addset(*G, temp); + } + set_free(c2essential); + } + } + } + + free_cube(RAISE); + free_cube(FREESET); + free_cube(temp); +} + +/* irred_gasp -- Add new primes to F and find an irredundant subset */ +pcover irred_gasp(F, D, G) +pcover F, D, G; /* G is disposed of */ +{ + if (G->count != 0) + F = irredundant(sf_append(F, G), D); + else + free_cover(G); + return F; +} + + +/* last_gasp */ +pcover last_gasp(F, D, R, cost) +pcover F, D, R; +cost_t *cost; +{ + pcover G, G1; + + EXECUTE(G = reduce_gasp(F, D), GREDUCE_TIME, G, *cost); + EXECUTE(G1 = expand_gasp(G, D, R, F), GEXPAND_TIME, G1, *cost); + free_cover(G); + EXECUTE(F = irred_gasp(F, D, G1), GIRRED_TIME, F, *cost); + return F; +} + + +/* super_gasp */ +pcover super_gasp(F, D, R, cost) +pcover F, D, R; +cost_t *cost; +{ + pcover G, G1; + + EXECUTE(G = reduce_gasp(F, D), GREDUCE_TIME, G, *cost); + EXECUTE(G1 = all_primes(G, R), GEXPAND_TIME, G1, *cost); + free_cover(G); + EXEC(G = sf_dupl(sf_append(F, G1)), "NEWPRIMES", G); + EXECUTE(F = irredundant(G, D), IRRED_TIME, F, *cost); + return F; +} diff --git a/espresso/getopt.c b/espresso/getopt.c new file mode 100644 index 0000000..ac67142 --- /dev/null +++ b/espresso/getopt.c @@ -0,0 +1,56 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/getopt.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:59 $ + * + */ +#include "port.h" +/* File : getopt.c + Author : Henry Spencer, University of Toronto + Updated: 28 April 1984 + Purpose: get option letter from argv. +*/ +#define NullS ((char *) 0) + +char *optarg; /* Global argument pointer. */ +int optind = 0; /* Global argv index. */ + +int getopt(argc, argv, optstring) + int argc; + char *argv[]; + char *optstring; + { + register int c; + register char *place; + static char *scan = NullS; /* Private scan pointer. */ + + optarg = NullS; + + if (scan == NullS || *scan == '\0') { + if (optind == 0) optind++; + if (optind >= argc) return EOF; + place = argv[optind]; + if (place[0] != '-' || place[1] == '\0') return EOF; + optind++; + if (place[1] == '-' && place[2] == '\0') return EOF; + scan = place+1; + } + + c = *scan++; + place = strchr(optstring, c); + if (place == NullS || c == ':') { + (void) fprintf(stderr, "%s: unknown option %c\n", argv[0], c); + return '?'; + } + if (*++place == ':') { + if (*scan != '\0') { + optarg = scan, scan = NullS; + } else { + optarg = argv[optind], optind++; + } + } + return c; + } diff --git a/espresso/gimpel.c b/espresso/gimpel.c new file mode 100644 index 0000000..960712f --- /dev/null +++ b/espresso/gimpel.c @@ -0,0 +1,106 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/gimpel.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "mincov_int.h" + + +/* + * check for: + * + * c1 c2 rest + * -- -- --- + * 1 1 0 0 0 0 <-- primary row + * 1 0 S1 <-- secondary row + * 0 1 T1 + * 0 1 T2 + * 0 1 Tn + * 0 0 R + */ + +int +gimpel_reduce(A, select, weight, lb, bound, depth, stats, best) +sm_matrix *A; +solution_t *select; +int *weight; +int lb; +int bound; +int depth; +stats_t *stats; +solution_t **best; +{ + register sm_row *prow, *save_sec; + register sm_col *c1, *c2; + register sm_element *p, *p1; + int c1_col_num, c2_col_num, primary_row_num, secondary_row_num; + int reduce_it; + + reduce_it = 0; + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->length == 2) { + c1 = sm_get_col(A, prow->first_col->col_num); + c2 = sm_get_col(A, prow->last_col->col_num); + if (c1->length == 2) { + reduce_it = 1; + } else if (c2->length == 2) { + c1 = sm_get_col(A, prow->last_col->col_num); + c2 = sm_get_col(A, prow->first_col->col_num); + reduce_it = 1; + } + if (reduce_it) { + primary_row_num = prow->row_num; + secondary_row_num = c1->first_row->row_num; + if (secondary_row_num == primary_row_num) { + secondary_row_num = c1->last_row->row_num; + } + break; + } + } + } + + if (reduce_it) { + c1_col_num = c1->col_num; + c2_col_num = c2->col_num; + save_sec = sm_row_dup(sm_get_row(A, secondary_row_num)); + sm_row_remove(save_sec, c1_col_num); + + for(p = c2->first_row; p != 0; p = p->next_row) { + if (p->row_num != primary_row_num) { + /* merge rows S1 and T */ + for(p1 = save_sec->first_col; p1 != 0; p1 = p1->next_col) { + (void) sm_insert(A, p->row_num, p1->col_num); + } + } + } + + sm_delcol(A, c1_col_num); + sm_delcol(A, c2_col_num); + sm_delrow(A, primary_row_num); + sm_delrow(A, secondary_row_num); + + stats->gimpel_count++; + stats->gimpel++; + *best = sm_mincov(A, select, weight, lb-1, bound-1, depth, stats); + stats->gimpel--; + + if (*best != NIL(solution_t)) { + /* is secondary row covered ? */ + if (sm_row_intersects(save_sec, (*best)->row)) { + /* yes, actually select c2 */ + solution_add(*best, weight, c2_col_num); + } else { + solution_add(*best, weight, c1_col_num); + } + } + + sm_row_free(save_sec); + return 1; + } else { + return 0; + } +} diff --git a/espresso/globals.c b/espresso/globals.c new file mode 100644 index 0000000..6cf5d71 --- /dev/null +++ b/espresso/globals.c @@ -0,0 +1,76 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/globals.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +#include "espresso.h" + +/* + * Global Variable Declarations + */ + +unsigned int debug; /* debug parameter */ +bool verbose_debug; /* -v: whether to print a lot */ +char *total_name[TIME_COUNT]; /* basic function names */ +long total_time[TIME_COUNT]; /* time spent in basic fcts */ +int total_calls[TIME_COUNT]; /* # calls to each fct */ + +bool echo_comments; /* turned off by -eat option */ +bool echo_unknown_commands; /* always true ?? */ +bool force_irredundant; /* -nirr command line option */ +bool skip_make_sparse; +bool kiss; /* -kiss command line option */ +bool pos; /* -pos command line option */ +bool print_solution; /* -x command line option */ +bool recompute_onset; /* -onset command line option */ +bool remove_essential; /* -ness command line option */ +bool single_expand; /* -fast command line option */ +bool summary; /* -s command line option */ +bool trace; /* -t command line option */ +bool unwrap_onset; /* -nunwrap command line option */ +bool use_random_order; /* -random command line option */ +bool use_super_gasp; /* -strong command line option */ +char *filename; /* filename PLA was read from */ + +struct pla_types_struct pla_types[] = { + "-f", F_type, + "-r", R_type, + "-d", D_type, + "-fd", FD_type, + "-fr", FR_type, + "-dr", DR_type, + "-fdr", FDR_type, + "-fc", F_type | CONSTRAINTS_type, + "-rc", R_type | CONSTRAINTS_type, + "-dc", D_type | CONSTRAINTS_type, + "-fdc", FD_type | CONSTRAINTS_type, + "-frc", FR_type | CONSTRAINTS_type, + "-drc", DR_type | CONSTRAINTS_type, + "-fdrc", FDR_type | CONSTRAINTS_type, + "-pleasure", PLEASURE_type, + "-eqn", EQNTOTT_type, + "-eqntott", EQNTOTT_type, + "-kiss", KISS_type, + "-cons", CONSTRAINTS_type, + "-scons", SYMBOLIC_CONSTRAINTS_type, + 0, 0 +}; + + +struct cube_struct cube, temp_cube_save; +struct cdata_struct cdata, temp_cdata_save; + +int bit_count[256] = { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 +}; diff --git a/espresso/hack.c b/espresso/hack.c new file mode 100644 index 0000000..ae10ad6 --- /dev/null +++ b/espresso/hack.c @@ -0,0 +1,641 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/hack.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +#include "espresso.h" + +map_dcset(PLA) +pPLA PLA; +{ + int var, i; + pcover Tplus, Tminus, Tplusbar, Tminusbar; + pcover newf, term1, term2, dcset, dcsetbar; + pcube cplus, cminus, last, p; + + if (PLA->label == NIL(char *) || PLA->label[0] == NIL(char)) + return; + + /* try to find a binary variable named "DONT_CARE" */ + var = -1; + for(i = 0; i < cube.num_binary_vars * 2; i++) { + if (strncmp(PLA->label[i], "DONT_CARE", 9) == 0 || + strncmp(PLA->label[i], "DONTCARE", 8) == 0 || + strncmp(PLA->label[i], "dont_care", 9) == 0 || + strncmp(PLA->label[i], "dontcare", 8) == 0) { + var = i/2; + break; + } + } + if (var == -1) { + return; + } + + /* form the cofactor cubes for the don't-care variable */ + cplus = set_save(cube.fullset); + cminus = set_save(cube.fullset); + set_remove(cplus, var*2); + set_remove(cminus, var*2 + 1); + + /* form the don't-care set */ + EXEC(simp_comp(cofactor(cube1list(PLA->F), cplus), &Tplus, &Tplusbar), + "simpcomp+", Tplus); + EXEC(simp_comp(cofactor(cube1list(PLA->F), cminus), &Tminus, &Tminusbar), + "simpcomp-", Tminus); + EXEC(term1 = cv_intersect(Tplus, Tminusbar), "term1 ", term1); + EXEC(term2 = cv_intersect(Tminus, Tplusbar), "term2 ", term2); + EXEC(dcset = sf_union(term1, term2), "union ", dcset); + EXEC(simp_comp(cube1list(dcset), &PLA->D, &dcsetbar), "simplify", PLA->D); + EXEC(newf = cv_intersect(PLA->F, dcsetbar), "separate ", PLA->F); + free_cover(PLA->F); + PLA->F = newf; + free_cover(Tplus); + free_cover(Tminus); + free_cover(Tplusbar); + free_cover(Tminusbar); + free_cover(dcsetbar); + + /* remove any cubes dependent on the DONT_CARE variable */ + (void) sf_active(PLA->F); + foreach_set(PLA->F, last, p) { + if (! is_in_set(p, var*2) || ! is_in_set(p, var*2+1)) { + RESET(p, ACTIVE); + } + } + PLA->F = sf_inactive(PLA->F); + + /* resize the cube and delete the don't-care variable */ + setdown_cube(); + for(i = 2*var+2; i < cube.size; i++) { + PLA->label[i-2] = PLA->label[i]; + } + for(i = var+1; i < cube.num_vars; i++) { + cube.part_size[i-1] = cube.part_size[i]; + } + cube.num_binary_vars--; + cube.num_vars--; + cube_setup(); + PLA->F = sf_delc(PLA->F, 2*var, 2*var+1); + PLA->D = sf_delc(PLA->D, 2*var, 2*var+1); +} + +map_output_symbolic(PLA) +pPLA PLA; +{ + pset_family newF, newD; + pset compress; + symbolic_t *p1; + symbolic_list_t *p2; + int i, bit, tot_size, base, old_size; + + /* Remove the DC-set from the ON-set (is this necessary ??) */ + if (PLA->D->count > 0) { + sf_free(PLA->F); + PLA->F = complement(cube2list(PLA->D, PLA->R)); + } + + /* tot_size = width added for all symbolic variables */ + tot_size = 0; + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + if (p2->pos<0 || p2->pos>=cube.part_size[cube.output]) { + fatal("symbolic-output index out of range"); +/* } else if (p2->variable != cube.output) { + fatal("symbolic-output label must be an output");*/ + } + } + tot_size += 1 << p1->symbolic_list_length; + } + + /* adjust the indices to skip over new outputs */ + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + p2->pos += tot_size; + } + } + + /* resize the cube structure -- add enough for the one-hot outputs */ + old_size = cube.size; + cube.part_size[cube.output] += tot_size; + setdown_cube(); + cube_setup(); + + /* insert space in the output part for the one-hot output */ + base = cube.first_part[cube.output]; + PLA->F = sf_addcol(PLA->F, base, tot_size); + PLA->D = sf_addcol(PLA->D, base, tot_size); + PLA->R = sf_addcol(PLA->R, base, tot_size); + + /* do the real work */ + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + newF = new_cover(100); + newD = new_cover(100); + find_inputs(NIL(set_family_t), PLA, p1->symbolic_list, base, 0, + &newF, &newD); +/* + * Not sure what this means + find_dc_inputs(PLA, p1->symbolic_list, + base, 1 << p1->symbolic_list_length, &newF, &newD); + */ + free_cover(PLA->F); + PLA->F = newF; +/* + * retain OLD DC-set -- but we've lost the don't-care arc information + * (it defaults to branch to the zero state) + free_cover(PLA->D); + PLA->D = newD; + */ + free_cover(newD); + base += 1 << p1->symbolic_list_length; + } + + /* delete the old outputs, and resize the cube */ + compress = set_full(newF->sf_size); + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + bit = cube.first_part[cube.output] + p2->pos; + set_remove(compress, bit); + } + } + cube.part_size[cube.output] -= newF->sf_size - set_ord(compress); + setdown_cube(); + cube_setup(); + PLA->F = sf_compress(PLA->F, compress); + PLA->D = sf_compress(PLA->D, compress); + if (cube.size != PLA->F->sf_size) fatal("error"); + + /* Quick minimization */ + PLA->F = sf_contain(PLA->F); + PLA->D = sf_contain(PLA->D); + for(i = 0; i < cube.num_vars; i++) { + PLA->F = d1merge(PLA->F, i); + PLA->D = d1merge(PLA->D, i); + } + PLA->F = sf_contain(PLA->F); + PLA->D = sf_contain(PLA->D); + + free_cover(PLA->R); + PLA->R = new_cover(0); + + symbolic_hack_labels(PLA, PLA->symbolic_output, + compress, cube.size, old_size, tot_size); + set_free(compress); +} + + +find_inputs(A, PLA, list, base, value, newF, newD) +pcover A; +pPLA PLA; +symbolic_list_t *list; +int base, value; +pcover *newF, *newD; +{ + pcover S, S1; + register pset last, p; + + /* + * A represents th 'input' values for which the outputs assume + * the integer value 'value + */ + if (list == NIL(symbolic_list_t)) { + /* + * Simulate these inputs against the on-set; then, insert into the + * new on-set a 1 in the proper position + */ + S = cv_intersect(A, PLA->F); + foreach_set(S, last, p) { + set_insert(p, base + value); + } + *newF = sf_append(*newF, S); + + /* + * 'simulate' these inputs against the don't-care set + S = cv_intersect(A, PLA->D); + *newD = sf_append(*newD, S); + */ + + } else { + /* intersect and recur with the OFF-set */ + S = cof_output(PLA->R, cube.first_part[cube.output] + list->pos); + if (A != NIL(set_family_t)) { + S1 = cv_intersect(A, S); + free_cover(S); + S = S1; + } + find_inputs(S, PLA, list->next, base, value*2, newF, newD); + free_cover(S); + + /* intersect and recur with the ON-set */ + S = cof_output(PLA->F, cube.first_part[cube.output] + list->pos); + if (A != NIL(set_family_t)) { + S1 = cv_intersect(A, S); + free_cover(S); + S = S1; + } + find_inputs(S, PLA, list->next, base, value*2 + 1, newF, newD); + free_cover(S); + } +} + + +#if 0 +find_dc_inputs(PLA, list, base, maxval, newF, newD) +pPLA PLA; +symbolic_list_t *list; +int base, maxval; +pcover *newF, *newD; +{ + pcover A, S, S1; + symbolic_list_t *p2; + register pset p, last; + register int i; + + /* painfully find the points for which the symbolic output is dc */ + A = NIL(set_family_t); + for(p2=list; p2!=NIL(symbolic_list_t); p2=p2->next) { + S = cof_output(PLA->D, cube.first_part[cube.output] + p2->pos); + if (A == NIL(set_family_t)) { + A = S; + } else { + S1 = cv_intersect(A, S); + free_cover(S); + free_cover(A); + A = S1; + } + } + + S = cv_intersect(A, PLA->F); + *newF = sf_append(*newF, S); + + S = cv_intersect(A, PLA->D); + foreach_set(S, last, p) { + for(i = base; i < base + maxval; i++) { + set_insert(p, i); + } + } + *newD = sf_append(*newD, S); + free_cover(A); +} +#endif + +map_symbolic(PLA) +pPLA PLA; +{ + symbolic_t *p1; + symbolic_list_t *p2; + int var, base, num_vars, num_binary_vars, *new_part_size; + int new_size, size_added, num_deleted_vars, num_added_vars, newvar; + pset compress; + + /* Verify legal values are in the symbolic lists */ + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + if (p2->variable < 0 || p2->variable >= cube.num_binary_vars) { + fatal(".symbolic requires binary variables"); + } + } + } + + /* + * size_added = width added for all symbolic variables + * num_deleted_vars = # binary variables to be deleted + * num_added_vars = # new mv variables + * compress = a cube which will be used to compress the set families + */ + size_added = 0; + num_added_vars = 0; + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + size_added += 1 << p1->symbolic_list_length; + num_added_vars++; + } + compress = set_full(PLA->F->sf_size + size_added); + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + set_remove(compress, p2->variable*2); + set_remove(compress, p2->variable*2+1); + } + } + num_deleted_vars = ((PLA->F->sf_size + size_added) - set_ord(compress))/2; + + /* compute the new cube constants */ + num_vars = cube.num_vars - num_deleted_vars + num_added_vars; + num_binary_vars = cube.num_binary_vars - num_deleted_vars; + new_size = cube.size - num_deleted_vars*2 + size_added; + new_part_size = ALLOC(int, num_vars); + new_part_size[num_vars-1] = cube.part_size[cube.num_vars-1]; + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) { + new_part_size[var-num_deleted_vars] = cube.part_size[var]; + } + + /* re-size the covers, opening room for the new mv variables */ + base = cube.first_part[cube.output]; + PLA->F = sf_addcol(PLA->F, base, size_added); + PLA->D = sf_addcol(PLA->D, base, size_added); + PLA->R = sf_addcol(PLA->R, base, size_added); + + /* compute the values for the new mv variables */ + newvar = (cube.num_vars - 1) - num_deleted_vars; + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + PLA->F = map_symbolic_cover(PLA->F, p1->symbolic_list, base); + PLA->D = map_symbolic_cover(PLA->D, p1->symbolic_list, base); + PLA->R = map_symbolic_cover(PLA->R, p1->symbolic_list, base); + base += 1 << p1->symbolic_list_length; + new_part_size[newvar++] = 1 << p1->symbolic_list_length; + } + + /* delete the binary variables which disappear */ + PLA->F = sf_compress(PLA->F, compress); + PLA->D = sf_compress(PLA->D, compress); + PLA->R = sf_compress(PLA->R, compress); + + symbolic_hack_labels(PLA, PLA->symbolic, compress, + new_size, cube.size, size_added); + setdown_cube(); + FREE(cube.part_size); + cube.num_vars = num_vars; + cube.num_binary_vars = num_binary_vars; + cube.part_size = new_part_size; + cube_setup(); + set_free(compress); +} + + +pcover map_symbolic_cover(T, list, base) +pcover T; +symbolic_list_t *list; +int base; +{ + pset last, p; + foreach_set(T, last, p) { + form_bitvector(p, base, 0, list); + } + return T; +} + + +form_bitvector(p, base, value, list) +pset p; /* old cube, looking at binary variables */ +int base; /* where in mv cube the new variable starts */ +int value; /* current value for this recursion */ +symbolic_list_t *list; /* current place in the symbolic list */ +{ + if (list == NIL(symbolic_list_t)) { + set_insert(p, base + value); + } else { + switch(GETINPUT(p, list->variable)) { + case ZERO: + form_bitvector(p, base, value*2, list->next); + break; + case ONE: + form_bitvector(p, base, value*2+1, list->next); + break; + case TWO: + form_bitvector(p, base, value*2, list->next); + form_bitvector(p, base, value*2+1, list->next); + break; + default: + fatal("bad cube in form_bitvector"); + } + } +} + + +symbolic_hack_labels(PLA, list, compress, new_size, old_size, size_added) +pPLA PLA; +symbolic_t *list; +pset compress; +int new_size, old_size, size_added; +{ + int i, base; + char **oldlabel; + symbolic_t *p1; + symbolic_label_t *p3; + + /* hack with the labels */ + if ((oldlabel = PLA->label) == NIL(char *)) + return; + PLA->label = ALLOC(char *, new_size); + for(i = 0; i < new_size; i++) { + PLA->label[i] = NIL(char); + } + + /* copy the binary variable labels and unchanged mv variable labels */ + base = 0; + for(i = 0; i < cube.first_part[cube.output]; i++) { + if (is_in_set(compress, i)) { + PLA->label[base++] = oldlabel[i]; + } else { + if (oldlabel[i] != NIL(char)) { + FREE(oldlabel[i]); + } + } + } + + /* add the user-defined labels for the symbolic outputs */ + for(p1 = list; p1 != NIL(symbolic_t); p1 = p1->next) { + p3 = p1->symbolic_label; + for(i = 0; i < (1 << p1->symbolic_list_length); i++) { + if (p3 == NIL(symbolic_label_t)) { + PLA->label[base+i] = ALLOC(char, 10); + (void) sprintf(PLA->label[base+i], "X%d", i); + } else { + PLA->label[base+i] = p3->label; + p3 = p3->next; + } + } + base += 1 << p1->symbolic_list_length; + } + + /* copy the labels for the binary outputs which remain */ + for(i = cube.first_part[cube.output]; i < old_size; i++) { + if (is_in_set(compress, i + size_added)) { + PLA->label[base++] = oldlabel[i]; + } else { + if (oldlabel[i] != NIL(char)) { + FREE(oldlabel[i]); + } + } + } + FREE(oldlabel); +} + +static pcover fsm_simplify(F) +pcover F; +{ + pcover D, R; + D = new_cover(0); + R = complement(cube1list(F)); + F = espresso(F, D, R); + free_cover(D); + free_cover(R); + return F; +} + + +disassemble_fsm(PLA, verbose_mode) +pPLA PLA; +int verbose_mode; +{ + int nin, nstates, nout; + int before, after, present_state, next_state, i, j; + pcube next_state_mask, present_state_mask, state_mask, p, p1, last; + pcover go_nowhere, F, tF; + + /* We make the DISGUSTING assumption that the first 'n' outputs have + * been created by .symbolic-output, and represent a one-hot encoding + * of the next state. 'n' is the size of the second-to-last multiple- + * valued variable (i.e., before the outputs + */ + + if (cube.num_vars - cube.num_binary_vars != 2) { + (void) fprintf(stderr, + "use .symbolic and .symbolic-output to specify\n"); + (void) fprintf(stderr, + "the present state and next state field information\n"); + fatal("disassemble_pla: need two multiple-valued variables\n"); + } + + nin = cube.num_binary_vars; + nstates = cube.part_size[cube.num_binary_vars]; + nout = cube.part_size[cube.num_vars - 1]; + if (nout < nstates) { + (void) fprintf(stderr, + "use .symbolic and .symbolic-output to specify\n"); + (void) fprintf(stderr, + "the present state and next state field information\n"); + fatal("disassemble_pla: # outputs < # states\n"); + } + + + present_state = cube.first_part[cube.num_binary_vars]; + present_state_mask = new_cube(); + for(i = 0; i < nstates; i++) { + set_insert(present_state_mask, i + present_state); + } + + next_state = cube.first_part[cube.num_binary_vars+1]; + next_state_mask = new_cube(); + for(i = 0; i < nstates; i++) { + set_insert(next_state_mask, i + next_state); + } + + state_mask = set_or(new_cube(), next_state_mask, present_state_mask); + + F = new_cover(10); + + + /* + * check for arcs which go from ANY state to state #i + */ + for(i = 0; i < nstates; i++) { + tF = new_cover(10); + foreach_set(PLA->F, last, p) { + if (setp_implies(present_state_mask, p)) { /* from any state ! */ + if (is_in_set(p, next_state + i)) { + tF = sf_addset(tF, p); + } + } + } + before = tF->count; + if (before > 0) { + tF = fsm_simplify(tF); + /* don't allow the next state to disappear ... */ + foreach_set(tF, last, p) { + set_insert(p, next_state + i); + } + after = tF->count; + F = sf_append(F, tF); + if (verbose_mode) { + printf("# state EVERY to %d, before=%d after=%d\n", + i, before, after); + } + } + } + + + /* + * some 'arcs' may NOT have a next state -- handle these + * we must unravel the present state part + */ + go_nowhere = new_cover(10); + foreach_set(PLA->F, last, p) { + if (setp_disjoint(p, next_state_mask)) { /* no next state !! */ + go_nowhere = sf_addset(go_nowhere, p); + } + } + before = go_nowhere->count; + go_nowhere = unravel_range(go_nowhere, + cube.num_binary_vars, cube.num_binary_vars); + after = go_nowhere->count; + F = sf_append(F, go_nowhere); + if (verbose_mode) { + printf("# state ANY to NOWHERE, before=%d after=%d\n", before, after); + } + + + /* + * minimize cover for all arcs from state #i to state #j + */ + for(i = 0; i < nstates; i++) { + for(j = 0; j < nstates; j++) { + tF = new_cover(10); + foreach_set(PLA->F, last, p) { + /* not EVERY state */ + if (! setp_implies(present_state_mask, p)) { + if (is_in_set(p, present_state + i)) { + if (is_in_set(p, next_state + j)) { + p1 = set_save(p); + set_diff(p1, p1, state_mask); + set_insert(p1, present_state + i); + set_insert(p1, next_state + j); + tF = sf_addset(tF, p1); + set_free(p1); + } + } + } + } + before = tF->count; + if (before > 0) { + tF = fsm_simplify(tF); + /* don't allow the next state to disappear ... */ + foreach_set(tF, last, p) { + set_insert(p, next_state + j); + } + after = tF->count; + F = sf_append(F, tF); + if (verbose_mode) { + printf("# state %d to %d, before=%d after=%d\n", + i, j, before, after); + } + } + } + } + + + free_cube(state_mask); + free_cube(present_state_mask); + free_cube(next_state_mask); + + free_cover(PLA->F); + PLA->F = F; + free_cover(PLA->D); + PLA->D = new_cover(0); + + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = nin; + cube.num_vars = nin + 3; + cube.part_size = ALLOC(int, cube.num_vars); + cube.part_size[cube.num_binary_vars] = nstates; + cube.part_size[cube.num_binary_vars+1] = nstates; + cube.part_size[cube.num_binary_vars+2] = nout - nstates; + cube_setup(); + + foreach_set(PLA->F, last, p) { + kiss_print_cube(stdout, PLA, p, "~1"); + } +} diff --git a/espresso/indep.c b/espresso/indep.c new file mode 100644 index 0000000..e4005d2 --- /dev/null +++ b/espresso/indep.c @@ -0,0 +1,134 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/indep.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "mincov_int.h" + +static sm_matrix *build_intersection_matrix(); + + +#if 0 +/* + * verify that all rows in 'indep' are actually independent ! + */ +static int +verify_indep_set(A, indep) +sm_matrix *A; +sm_row *indep; +{ + register sm_row *prow, *prow1; + register sm_element *p, *p1; + + for(p = indep->first_col; p != 0; p = p->next_col) { + prow = sm_get_row(A, p->col_num); + for(p1 = p->next_col; p1 != 0; p1 = p1->next_col) { + prow1 = sm_get_row(A, p1->col_num); + if (sm_row_intersects(prow, prow1)) { + return 0; + } + } + } + return 1; +} +#endif + +solution_t * +sm_maximal_independent_set(A, weight) +sm_matrix *A; +int *weight; +{ + register sm_row *best_row, *prow; + register sm_element *p; + int least_weight; + sm_row *save; + sm_matrix *B; + solution_t *indep; + + indep = solution_alloc(); + B = build_intersection_matrix(A); + + while (B->nrows > 0) { + /* Find the row which is disjoint from a maximum number of rows */ + best_row = B->first_row; + for(prow = B->first_row->next_row; prow != 0; prow = prow->next_row) { + if (prow->length < best_row->length) { + best_row = prow; + } + } + + /* Find which element in this row has least weight */ + if (weight == NIL(int)) { + least_weight = 1; + } else { + prow = sm_get_row(A, best_row->row_num); + least_weight = weight[prow->first_col->col_num]; + for(p = prow->first_col->next_col; p != 0; p = p->next_col) { + if (weight[p->col_num] < least_weight) { + least_weight = weight[p->col_num]; + } + } + } + indep->cost += least_weight; + (void) sm_row_insert(indep->row, best_row->row_num); + + /* Discard the rows which intersect this row */ + save = sm_row_dup(best_row); + for(p = save->first_col; p != 0; p = p->next_col) { + sm_delrow(B, p->col_num); + sm_delcol(B, p->col_num); + } + sm_row_free(save); + } + + sm_free(B); + +/* + if (! verify_indep_set(A, indep->row)) { + fail("sm_maximal_independent_set: row set is not independent"); + } +*/ + return indep; +} + +static sm_matrix * +build_intersection_matrix(A) +sm_matrix *A; +{ + register sm_row *prow, *prow1; + register sm_element *p, *p1; + register sm_col *pcol; + sm_matrix *B; + + /* Build row-intersection matrix */ + B = sm_alloc(); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + + /* Clear flags on all rows we can reach from row 'prow' */ + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + for(p1 = pcol->first_row; p1 != 0; p1 = p1->next_row) { + prow1 = sm_get_row(A, p1->row_num); + prow1->flag = 0; + } + } + + /* Now record which rows can be reached */ + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + for(p1 = pcol->first_row; p1 != 0; p1 = p1->next_row) { + prow1 = sm_get_row(A, p1->row_num); + if (! prow1->flag) { + prow1->flag = 1; + (void) sm_insert(B, prow->row_num, prow1->row_num); + } + } + } + } + + return B; +} diff --git a/espresso/irred.c b/espresso/irred.c new file mode 100644 index 0000000..ad1016b --- /dev/null +++ b/espresso/irred.c @@ -0,0 +1,440 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/irred.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +#include "espresso.h" + +static void fcube_is_covered(); +static void ftautology(); +static bool ftaut_special_cases(); + + +static int Rp_current; + +/* + * irredundant -- Return a minimal subset of F + */ + +pcover +irredundant(F, D) +pcover F, D; +{ + mark_irredundant(F, D); + return sf_inactive(F); +} + + +/* + * mark_irredundant -- find redundant cubes, and mark them "INACTIVE" + */ + +void +mark_irredundant(F, D) +pcover F, D; +{ + pcover E, Rt, Rp; + pset p, p1, last; + sm_matrix *table; + sm_row *cover; + sm_element *pe; + + /* extract a minimum cover */ + irred_split_cover(F, D, &E, &Rt, &Rp); + table = irred_derive_table(D, E, Rp); + cover = sm_minimum_cover(table, NIL(int), /* heuristic */ 1, /* debug */ 0); + + /* mark the cubes for the result */ + foreach_set(F, last, p) { + RESET(p, ACTIVE); + RESET(p, RELESSEN); + } + foreach_set(E, last, p) { + p1 = GETSET(F, SIZE(p)); + assert(setp_equal(p1, p)); + SET(p1, ACTIVE); + SET(p1, RELESSEN); /* for essen(), mark as rel. ess. */ + } + sm_foreach_row_element(cover, pe) { + p1 = GETSET(F, pe->col_num); + SET(p1, ACTIVE); + } + + if (debug & IRRED) { + printf("# IRRED: F=%d E=%d R=%d Rt=%d Rp=%d Rc=%d Final=%d Bound=%d\n", + F->count, E->count, Rt->count+Rp->count, Rt->count, Rp->count, + cover->length, E->count + cover->length, 0); + } + + free_cover(E); + free_cover(Rt); + free_cover(Rp); + sm_free(table); + sm_row_free(cover); +} + +/* + * irred_split_cover -- find E, Rt, and Rp from the cover F, D + * + * E -- relatively essential cubes + * Rt -- totally redundant cubes + * Rp -- partially redundant cubes + */ + +void +irred_split_cover(F, D, E, Rt, Rp) +pcover F, D; +pcover *E, *Rt, *Rp; +{ + register pcube p, last; + register int index; + pcover R; + pcube *FD, *ED; + + /* number the cubes of F -- these numbers track into E, Rp, Rt, etc. */ + index = 0; + foreach_set(F, last, p) { + PUTSIZE(p, index); + index++; + } + + *E = new_cover(10); + *Rt = new_cover(10); + *Rp = new_cover(10); + R = new_cover(10); + + /* Split F into E and R */ + FD = cube2list(F, D); + foreach_set(F, last, p) { + if (cube_is_covered(FD, p)) { + R = sf_addset(R, p); + } else { + *E = sf_addset(*E, p); + } + if (debug & IRRED1) { + (void) printf("IRRED1: zr=%d ze=%d to-go=%d time=%s\n", + R->count, (*E)->count, F->count - (R->count + (*E)->count), + print_time(ptime())); + } + } + free_cubelist(FD); + + /* Split R into Rt and Rp */ + ED = cube2list(*E, D); + foreach_set(R, last, p) { + if (cube_is_covered(ED, p)) { + *Rt = sf_addset(*Rt, p); + } else { + *Rp = sf_addset(*Rp, p); + } + if (debug & IRRED1) { + (void) printf("IRRED1: zr=%d zrt=%d to-go=%d time=%s\n", + (*Rp)->count, (*Rt)->count, + R->count - ((*Rp)->count +(*Rt)->count), print_time(ptime())); + } + } + free_cubelist(ED); + + free_cover(R); +} + +/* + * irred_derive_table -- given the covers D, E and the set of + * partially redundant primes Rp, build a covering table showing + * possible selections of primes to cover Rp. + */ + +sm_matrix * +irred_derive_table(D, E, Rp) +pcover D, E, Rp; +{ + register pcube last, p, *list; + sm_matrix *table; + int size_last_dominance, i; + + /* Mark each cube in DE as not part of the redundant set */ + foreach_set(D, last, p) { + RESET(p, REDUND); + } + foreach_set(E, last, p) { + RESET(p, REDUND); + } + + /* Mark each cube in Rp as partially redundant */ + foreach_set(Rp, last, p) { + SET(p, REDUND); /* belongs to redundant set */ + } + + /* For each cube in Rp, find ways to cover its minterms */ + list = cube3list(D, E, Rp); + table = sm_alloc(); + size_last_dominance = 0; + i = 0; + foreach_set(Rp, last, p) { + Rp_current = SIZE(p); + fcube_is_covered(list, p, table); + RESET(p, REDUND); /* can now consider this cube redundant */ + if (debug & IRRED1) { + (void) printf("IRRED1: %d of %d to-go=%d, table=%dx%d time=%s\n", + i, Rp->count, Rp->count - i, + table->nrows, table->ncols, print_time(ptime())); + } + /* try to keep memory limits down by reducing table as we go along */ + if (table->nrows - size_last_dominance > 1000) { + (void) sm_row_dominance(table); + size_last_dominance = table->nrows; + if (debug & IRRED1) { + (void) printf("IRRED1: delete redundant rows, now %dx%d\n", + table->nrows, table->ncols); + } + } + i++; + } + free_cubelist(list); + + return table; +} + +/* cube_is_covered -- determine if a cubelist "covers" a single cube */ +bool +cube_is_covered(T, c) +pcube *T, c; +{ + return tautology(cofactor(T,c)); +} + + + +/* tautology -- answer the tautology question for T */ +bool +tautology(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best, result; + static int taut_level = 0; + + if (debug & TAUT) { + debug_print(T, "TAUTOLOGY", taut_level++); + } + + if ((result = taut_special_cases(T)) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, TAUT); + result = tautology(scofactor(T, cl, best)) && + tautology(scofactor(T, cr, best)); + free_cubelist(T); + free_cube(cl); + free_cube(cr); + } + + if (debug & TAUT) { + printf("exit TAUTOLOGY[%d]: %s\n", --taut_level, print_bool(result)); + } + return result; +} + +/* + * taut_special_cases -- check special cases for tautology + */ + +bool +taut_special_cases(T) +pcube *T; /* will be disposed if answer is determined */ +{ + register pcube *T1, *Tsave, p, ceil=cube.temp[0], temp=cube.temp[1]; + pcube *A, *B; + int var; + + /* Check for a row of all 1's which implies tautology */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, T[0])) { + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which implies no tautology */ +start: + INLINEset_copy(ceil, T[0]); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + free_cubelist(T); + return FALSE; + } + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If function is unate (and no row of all 1's), then no tautology */ + if (cdata.vars_unate == cdata.vars_active) { + free_cubelist(T); + return FALSE; + + /* If active in a single variable (and no column of 0's) then tautology */ + } else if (cdata.vars_active == 1) { + free_cubelist(T); + return TRUE; + + /* Check for unate variables, and reduce cover if there are any */ + } else if (cdata.vars_unate != 0) { + /* Form a cube "ceil" with full variables in the unate variables */ + (void) set_copy(ceil, cube.emptyset); + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + INLINEset_or(ceil, ceil, cube.var_mask[var]); + } + } + + /* Save only those cubes that are "full" in all unate variables */ + for(Tsave = T1 = T+2; (p = *T1++) != 0; ) { + if (setp_implies(ceil, set_or(temp, p, T[0]))) { + *Tsave++ = p; + } + } + *Tsave++ = NULL; + T[1] = (pcube) Tsave; + + if (debug & TAUT) { + printf("UNATE_REDUCTION: %d unate variables, reduced to %d\n", + cdata.vars_unate, CUBELISTSIZE(T)); + } + goto start; + + /* Check for component reduction */ + } else if (cdata.var_zeros[cdata.best] < CUBELISTSIZE(T) / 2) { + if (cubelist_partition(T, &A, &B, debug & TAUT) == 0) { + return MAYBE; + } else { + free_cubelist(T); + if (tautology(A)) { + free_cubelist(B); + return TRUE; + } else { + return tautology(B); + } + } + } + + /* We tried as hard as we could, but must recurse from here on */ + return MAYBE; +} + +/* fcube_is_covered -- determine exactly how a cubelist "covers" a cube */ +static void +fcube_is_covered(T, c, table) +pcube *T, c; +sm_matrix *table; +{ + ftautology(cofactor(T,c), table); +} + + +/* ftautology -- find ways to make a tautology */ +static void +ftautology(T, table) +pcube *T; /* T will be disposed of */ +sm_matrix *table; +{ + register pcube cl, cr; + register int best; + static int ftaut_level = 0; + + if (debug & TAUT) { + debug_print(T, "FIND_TAUTOLOGY", ftaut_level++); + } + + if (ftaut_special_cases(T, table) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, TAUT); + + ftautology(scofactor(T, cl, best), table); + ftautology(scofactor(T, cr, best), table); + + free_cubelist(T); + free_cube(cl); + free_cube(cr); + } + + if (debug & TAUT) { + (void) printf("exit FIND_TAUTOLOGY[%d]: table is %d by %d\n", + --ftaut_level, table->nrows, table->ncols); + } +} + +static bool +ftaut_special_cases(T, table) +pcube *T; /* will be disposed if answer is determined */ +sm_matrix *table; +{ + register pcube *T1, *Tsave, p, temp = cube.temp[0], ceil = cube.temp[1]; + int var, rownum; + + /* Check for a row of all 1's in the essential cubes */ + for(T1 = T+2; (p = *T1++) != 0; ) { + if (! TESTP(p, REDUND)) { + if (full_row(p, T[0])) { + /* subspace is covered by essentials -- no new rows for table */ + free_cubelist(T); + return TRUE; + } + } + } + + /* Collect column counts, determine unate variables, etc. */ +start: + massive_count(T); + + /* If function is unate, find the rows of all 1's */ + if (cdata.vars_unate == cdata.vars_active) { + /* find which nonessentials cover this subspace */ + rownum = table->last_row ? table->last_row->row_num+1 : 0; + (void) sm_insert(table, rownum, Rp_current); + for(T1 = T+2; (p = *T1++) != 0; ) { + if (TESTP(p, REDUND)) { + /* See if a redundant cube covers this leaf */ + if (full_row(p, T[0])) { + (void) sm_insert(table, rownum, (int) SIZE(p)); + } + } + } + free_cubelist(T); + return TRUE; + + /* Perform unate reduction if there are any unate variables */ + } else if (cdata.vars_unate != 0) { + /* Form a cube "ceil" with full variables in the unate variables */ + (void) set_copy(ceil, cube.emptyset); + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + INLINEset_or(ceil, ceil, cube.var_mask[var]); + } + } + + /* Save only those cubes that are "full" in all unate variables */ + for(Tsave = T1 = T+2; (p = *T1++) != 0; ) { + if (setp_implies(ceil, set_or(temp, p, T[0]))) { + *Tsave++ = p; + } + } + *Tsave++ = 0; + T[1] = (pcube) Tsave; + + if (debug & TAUT) { + printf("UNATE_REDUCTION: %d unate variables, reduced to %d\n", + cdata.vars_unate, CUBELISTSIZE(T)); + } + goto start; + } + + /* Not much we can do about it */ + return MAYBE; +} diff --git a/espresso/main.c b/espresso/main.c new file mode 100644 index 0000000..b950ecb --- /dev/null +++ b/espresso/main.c @@ -0,0 +1,746 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/main.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +/* + * Main driver for espresso + * + * Old style -do xxx, -out xxx, etc. are still supported. + */ + +#include "espresso.h" +#include "main.h" /* table definitions for options */ + +static FILE *last_fp; +static int input_type = FD_type; + + +main(argc, argv) +int argc; +char *argv[]; +{ + int i, j, first, last, strategy, out_type, option; + pPLA PLA, PLA1; + pcover F, Fold, Dold; + pset last1, p; + cost_t cost; + bool error, exact_cover; + long start; + extern char *optarg; + extern int optind; + + start = ptime(); + + error = FALSE; + init_runtime(); +#ifdef RANDOM + srandom(314973); +#endif + + option = 0; /* default -D: ESPRESSO */ + out_type = F_type; /* default -o: default is ON-set only */ + debug = 0; /* default -d: no debugging info */ + verbose_debug = FALSE; /* default -v: not verbose */ + print_solution = TRUE; /* default -x: print the solution (!) */ + summary = FALSE; /* default -s: no summary */ + trace = FALSE; /* default -t: no trace information */ + strategy = 0; /* default -S: strategy number */ + first = -1; /* default -R: select range */ + last = -1; + remove_essential = TRUE; /* default -e: */ + force_irredundant = TRUE; + unwrap_onset = TRUE; + single_expand = FALSE; + pos = FALSE; + recompute_onset = FALSE; + use_super_gasp = FALSE; + use_random_order = FALSE; + kiss = FALSE; + echo_comments = TRUE; + echo_unknown_commands = TRUE; + exact_cover = FALSE; /* for -qm option, the default */ + + backward_compatibility_hack(&argc, argv, &option, &out_type); + + + /* parse command line options*/ + while ((i = getopt(argc, argv, "D:S:de:o:r:stv:x")) != EOF) { + switch(i) { + case 'D': /* -Dcommand invokes a subcommand */ + for(j = 0; option_table[j].name != 0; j++) { + if (strcmp(optarg, option_table[j].name) == 0) { + option = j; + break; + } + } + if (option_table[j].name == 0) { + (void) fprintf(stderr, "%s: bad subcommand \"%s\"\n", + argv[0], optarg); + exit(1); + } + break; + + case 'o': /* -ooutput selects and output option */ + for(j = 0; pla_types[j].key != 0; j++) { + if (strcmp(optarg, pla_types[j].key+1) == 0) { + out_type = pla_types[j].value; + break; + } + } + if (pla_types[j].key == 0) { + (void) fprintf(stderr, "%s: bad output type \"%s\"\n", + argv[0], optarg); + exit(1); + } + break; + + case 'e': /* -eespresso selects an option for espresso */ + for(j = 0; esp_opt_table[j].name != 0; j++) { + if (strcmp(optarg, esp_opt_table[j].name) == 0) { + *(esp_opt_table[j].variable) = esp_opt_table[j].value; + break; + } + } + if (esp_opt_table[j].name == 0) { + (void) fprintf(stderr, "%s: bad espresso option \"%s\"\n", + argv[0], optarg); + exit(1); + } + break; + + case 'd': /* -d turns on (softly) all debug switches */ + debug = debug_table[0].value; + trace = TRUE; + summary = TRUE; + break; + + case 'v': /* -vdebug invokes a debug option */ + verbose_debug = TRUE; + for(j = 0; debug_table[j].name != 0; j++) { + if (strcmp(optarg, debug_table[j].name) == 0) { + debug |= debug_table[j].value; + break; + } + } + if (debug_table[j].name == 0) { + (void) fprintf(stderr, "%s: bad debug type \"%s\"\n", + argv[0], optarg); + exit(1); + } + break; + + case 't': + trace = TRUE; + break; + + case 's': + summary = TRUE; + break; + + case 'x': /* -x suppress printing of results */ + print_solution = FALSE; + break; + + case 'S': /* -S sets a strategy for several cmds */ + strategy = atoi(optarg); + break; + + case 'r': /* -r selects range (outputs or vars) */ + if (sscanf(optarg, "%d-%d", &first, &last) < 2) { + (void) fprintf(stderr, "%s: bad output range \"%s\"\n", + argv[0], optarg); + exit(1); + } + break; + + default: + usage(); + exit(1); + } + } + + /* provide version information and summaries */ + if (summary || trace) { + /* echo command line and arguments */ + printf("#"); + for(i = 0; i < argc; i++) { + printf(" %s", argv[i]); + } + printf("\n"); + printf("# %s\n", VERSION); + } + + /* the remaining arguments are argv[optind ... argc-1] */ + PLA = PLA1 = NIL(PLA_t); + switch(option_table[option].num_plas) { + case 2: + if (optind+2 < argc) fatal("trailing arguments on command line"); + getPLA(optind++, argc, argv, option, &PLA, out_type); + getPLA(optind++, argc, argv, option, &PLA1, out_type); + break; + case 1: + if (optind+1 < argc) fatal("trailing arguments on command line"); + getPLA(optind++, argc, argv, option, &PLA, out_type); + break; + } + if (optind < argc) fatal("trailing arguments on command line"); + + if (summary || trace) { + if (PLA != NIL(PLA_t)) PLA_summary(PLA); + if (PLA1 != NIL(PLA_t)) PLA_summary(PLA1); + } + +/* + * Now a case-statement to decide what to do + */ + + switch(option_table[option].key) { + + +/******************** Espresso operations ********************/ + + case KEY_ESPRESSO: + Fold = sf_save(PLA->F); + PLA->F = espresso(PLA->F, PLA->D, PLA->R); + EXECUTE(error=verify(PLA->F,Fold,PLA->D), VERIFY_TIME, PLA->F, cost); + if (error) { + print_solution = FALSE; + PLA->F = Fold; + (void) check_consistency(PLA); + } else { + free_cover(Fold); + } + break; + + case KEY_MANY_ESPRESSO: { + int pla_type; + do { + EXEC(PLA->F=espresso(PLA->F,PLA->D,PLA->R),"ESPRESSO ",PLA->F); + if (print_solution) { + fprint_pla(stdout, PLA, out_type); + (void) fflush(stdout); + } + pla_type = PLA->pla_type; + free_PLA(PLA); + setdown_cube(); + FREE(cube.part_size); + } while (read_pla(last_fp, TRUE, TRUE, pla_type, &PLA) != EOF); + exit(0); + } + + case KEY_simplify: + EXEC(PLA->F = simplify(cube1list(PLA->F)), "SIMPLIFY ", PLA->F); + break; + + case KEY_so: /* minimize all functions as single-output */ + if (strategy < 0 || strategy > 1) { + strategy = 0; + } + so_espresso(PLA, strategy); + break; + + case KEY_so_both: /* minimize all functions as single-output */ + if (strategy < 0 || strategy > 1) { + strategy = 0; + } + so_both_espresso(PLA, strategy); + break; + + case KEY_expand: /* execute expand */ + EXECUTE(PLA->F=expand(PLA->F,PLA->R,FALSE),EXPAND_TIME, PLA->F, cost); + break; + + case KEY_irred: /* extract minimal irredundant subset */ + EXECUTE(PLA->F = irredundant(PLA->F, PLA->D), IRRED_TIME, PLA->F, cost); + break; + + case KEY_reduce: /* perform reduction */ + EXECUTE(PLA->F = reduce(PLA->F, PLA->D), REDUCE_TIME, PLA->F, cost); + break; + + case KEY_essen: /* check for essential primes */ + foreach_set(PLA->F, last1, p) { + SET(p, RELESSEN); + RESET(p, NONESSEN); + } + EXECUTE(F = essential(&(PLA->F), &(PLA->D)), ESSEN_TIME, PLA->F, cost); + free_cover(F); + break; + + case KEY_super_gasp: + PLA->F = super_gasp(PLA->F, PLA->D, PLA->R, &cost); + break; + + case KEY_gasp: + PLA->F = last_gasp(PLA->F, PLA->D, PLA->R, &cost); + break; + + case KEY_make_sparse: /* make_sparse step of Espresso */ + PLA->F = make_sparse(PLA->F, PLA->D, PLA->R); + break; + + case KEY_exact: + exact_cover = TRUE; + + case KEY_qm: + Fold = sf_save(PLA->F); + PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, exact_cover); + EXECUTE(error=verify(PLA->F,Fold,PLA->D), VERIFY_TIME, PLA->F, cost); + if (error) { + print_solution = FALSE; + PLA->F = Fold; + (void) check_consistency(PLA); + } + free_cover(Fold); + break; + + case KEY_primes: /* generate all prime implicants */ + EXEC(PLA->F = primes_consensus(cube2list(PLA->F, PLA->D)), + "PRIMES ", PLA->F); + break; + + case KEY_map: /* print out a Karnaugh map of function */ + map(PLA->F); + print_solution = FALSE; + break; + + + +/******************** Output phase and bit pairing ********************/ + + case KEY_opo: /* sasao output phase assignment */ + phase_assignment(PLA, strategy); + break; + + case KEY_opoall: /* try all phase assignments (!) */ + if (first < 0 || first >= cube.part_size[cube.output]) { + first = 0; + } + if (last < 0 || last >= cube.part_size[cube.output]) { + last = cube.part_size[cube.output] - 1; + } + opoall(PLA, first, last, strategy); + break; + + case KEY_pair: /* find an optimal pairing */ + find_optimal_pairing(PLA, strategy); + break; + + case KEY_pairall: /* try all pairings !! */ + pair_all(PLA, strategy); + break; + + + +/******************** Simple cover operations ********************/ + + case KEY_echo: /* echo the PLA */ + break; + + case KEY_taut: /* tautology check */ + printf("ON-set is%sa tautology\n", + tautology(cube1list(PLA->F)) ? " " : " not "); + print_solution = FALSE; + break; + + case KEY_contain: /* single cube containment */ + PLA->F = sf_contain(PLA->F); + break; + + case KEY_intersect: /* cover intersection */ + PLA->F = cv_intersect(PLA->F, PLA1->F); + break; + + case KEY_union: /* cover union */ + PLA->F = sf_union(PLA->F, PLA1->F); + break; + + case KEY_disjoint: /* make cover disjoint */ + PLA->F = make_disjoint(PLA->F); + break; + + case KEY_dsharp: /* cover disjoint-sharp */ + PLA->F = cv_dsharp(PLA->F, PLA1->F); + break; + + case KEY_sharp: /* cover sharp */ + PLA->F = cv_sharp(PLA->F, PLA1->F); + break; + + case KEY_lexsort: /* lexical sort order */ + PLA->F = lex_sort(PLA->F); + break; + + case KEY_stats: /* print info on size */ + if (! summary) PLA_summary(PLA); + print_solution = FALSE; + break; + + case KEY_minterms: /* explode into minterms */ + if (first < 0 || first >= cube.num_vars) { + first = 0; + } + if (last < 0 || last >= cube.num_vars) { + last = cube.num_vars - 1; + } + PLA->F = sf_dupl(unravel_range(PLA->F, first, last)); + break; + + case KEY_d1merge: /* distance-1 merge */ + if (first < 0 || first >= cube.num_vars) { + first = 0; + } + if (last < 0 || last >= cube.num_vars) { + last = cube.num_vars - 1; + } + for(i = first; i <= last; i++) { + PLA->F = d1merge(PLA->F, i); + } + break; + + case KEY_d1merge_in: /* distance-1 merge inputs only */ + for(i = 0; i < cube.num_binary_vars; i++) { + PLA->F = d1merge(PLA->F, i); + } + break; + + case KEY_PLA_verify: /* check two PLAs for equivalence */ + EXECUTE(error = PLA_verify(PLA, PLA1), VERIFY_TIME, PLA->F, cost); + if (error) { + printf("PLA comparison failed; the PLA's are not equivalent\n"); + exit(1); + } else { + printf("PLA's compared equal\n"); + exit(0); + } + break; /* silly */ + + case KEY_verify: /* check two covers for equivalence */ + Fold = PLA->F; Dold = PLA->D; F = PLA1->F; + EXECUTE(error=verify(F, Fold, Dold), VERIFY_TIME, PLA->F, cost); + if (error) { + printf("PLA comparison failed; the PLA's are not equivalent\n"); + exit(1); + } else { + printf("PLA's compared equal\n"); + exit(0); + } + break; /* silly */ + + case KEY_check: /* check consistency */ + (void) check_consistency(PLA); + print_solution = FALSE; + break; + + case KEY_mapdc: /* compute don't care set */ + map_dcset(PLA); + out_type = FD_type; + break; + + case KEY_equiv: + find_equiv_outputs(PLA); + print_solution = FALSE; + break; + + case KEY_separate: /* remove PLA->D from PLA->F */ + PLA->F = complement(cube2list(PLA->D, PLA->R)); + break; + + case KEY_xor: { + pcover T1 = cv_intersect(PLA->F, PLA1->R); + pcover T2 = cv_intersect(PLA1->F, PLA->R); + free_cover(PLA->F); + PLA->F = sf_contain(sf_join(T1, T2)); + free_cover(T1); + free_cover(T2); + break; + } + + case KEY_fsm: { + disassemble_fsm(PLA, summary); + print_solution = FALSE; + break; + } + + case KEY_test: { + pcover T, E; + T = sf_join(PLA->D, PLA->R); + E = new_cover(10); + sf_free(PLA->F); + EXECUTE(PLA->F = complement(cube1list(T)), COMPL_TIME, PLA->F, cost); + EXECUTE(PLA->F = expand(PLA->F, T, FALSE), EXPAND_TIME, PLA->F, cost); + EXECUTE(PLA->F = irredundant(PLA->F, E), IRRED_TIME, PLA->F, cost); + sf_free(T); + T = sf_join(PLA->F, PLA->R); + EXECUTE(PLA->D = expand(PLA->D, T, FALSE), EXPAND_TIME, PLA->D, cost); + EXECUTE(PLA->D = irredundant(PLA->D, E), IRRED_TIME, PLA->D, cost); + sf_free(T); + sf_free(E); + break; + } + + + } + + /* Print a runtime summary if trace mode enabled */ + if (trace) { + runtime(); + } + + /* Print total runtime */ + if (summary || trace) { + print_trace(PLA->F, option_table[option].name, ptime()-start); + } + + /* Output the solution */ + if (print_solution) { + EXECUTE(fprint_pla(stdout, PLA, out_type), WRITE_TIME, PLA->F, cost); + } + + /* Crash and burn if there was a verify error */ + if (error) { + fatal("cover verification failed"); + } + + /* cleanup all used memory */ + free_PLA(PLA); + FREE(cube.part_size); + setdown_cube(); /* free the cube/cdata structure data */ + sf_cleanup(); /* free unused set structures */ + sm_cleanup(); /* sparse matrix cleanup */ + + exit(0); +} + + +getPLA(opt, argc, argv, option, PLA, out_type) +int opt; +int argc; +char *argv[]; +int option; +pPLA *PLA; +int out_type; +{ + FILE *fp; + int needs_dcset, needs_offset; + char *fname; + + if (opt >= argc) { + fp = stdin; + fname = "(stdin)"; + } else { + fname = argv[opt]; + if (strcmp(fname, "-") == 0) { + fp = stdin; + } else if ((fp = fopen(argv[opt], "r")) == NULL) { + (void) fprintf(stderr, "%s: Unable to open %s\n", argv[0], fname); + exit(1); + } + } + if (option_table[option].key == KEY_echo) { + needs_dcset = (out_type & D_type) != 0; + needs_offset = (out_type & R_type) != 0; + } else { + needs_dcset = option_table[option].needs_dcset; + needs_offset = option_table[option].needs_offset; + } + + if (read_pla(fp, needs_dcset, needs_offset, input_type, PLA) == EOF) { + (void) fprintf(stderr, "%s: Unable to find PLA on file %s\n", argv[0], fname); + exit(1); + } + (*PLA)->filename = util_strsav(fname); + filename = (*PLA)->filename; +/* (void) fclose(fp);*/ +/* hackto support -Dmany */ + last_fp = fp; +} + + +runtime() +{ + int i; + long total = 1, temp; + + for(i = 0; i < TIME_COUNT; i++) { + total += total_time[i]; + } + for(i = 0; i < TIME_COUNT; i++) { + if (total_calls[i] != 0) { + temp = 100 * total_time[i]; + printf("# %s\t%2d call(s) for %s (%2ld.%01ld%%)\n", + total_name[i], total_calls[i], print_time(total_time[i]), + temp/total, (10 * (temp%total)) / total); + } + } +} + + +init_runtime() +{ + total_name[READ_TIME] = "READ "; + total_name[WRITE_TIME] = "WRITE "; + total_name[COMPL_TIME] = "COMPL "; + total_name[REDUCE_TIME] = "REDUCE "; + total_name[EXPAND_TIME] = "EXPAND "; + total_name[ESSEN_TIME] = "ESSEN "; + total_name[IRRED_TIME] = "IRRED "; + total_name[GREDUCE_TIME] = "REDUCE_GASP"; + total_name[GEXPAND_TIME] = "EXPAND_GASP"; + total_name[GIRRED_TIME] = "IRRED_GASP "; + total_name[MV_REDUCE_TIME] ="MV_REDUCE "; + total_name[RAISE_IN_TIME] = "RAISE_IN "; + total_name[VERIFY_TIME] = "VERIFY "; + total_name[PRIMES_TIME] = "PRIMES "; + total_name[MINCOV_TIME] = "MINCOV "; +} + + +subcommands() +{ + int i, col; + printf(" "); + col = 16; + for(i = 0; option_table[i].name != 0; i++) { + if ((col + strlen(option_table[i].name) + 1) > 76) { + printf(",\n "); + col = 16; + } else if (i != 0) { + printf(", "); + } + printf("%s", option_table[i].name); + col += strlen(option_table[i].name) + 2; + } + printf("\n"); +} + + +usage() +{ + printf("%s\n\n", VERSION); + printf("SYNOPSIS: espresso [options] [file]\n\n"); + printf(" -d Enable debugging\n"); + printf(" -e[opt] Select espresso option:\n"); + printf(" fast, ness, nirr, nunwrap, onset, pos, strong,\n"); + printf(" eat, eatdots, kiss, random\n"); + printf(" -o[type] Select output format:\n"); + printf(" f, fd, fr, fdr, pleasure, eqntott, kiss, cons\n"); + printf(" -rn-m Select range for subcommands:\n"); + printf(" d1merge: first and last variables (0 ... m-1)\n"); + printf(" minterms: first and last variables (0 ... m-1)\n"); + printf(" opoall: first and last outputs (0 ... m-1)\n"); + printf(" -s Provide short execution summary\n"); + printf(" -t Provide longer execution trace\n"); + printf(" -x Suppress printing of solution\n"); + printf(" -v[type] Verbose debugging detail (-v '' for all)\n"); + printf(" -D[cmd] Execute subcommand 'cmd':\n"); + subcommands(); + printf(" -Sn Select strategy for subcommands:\n"); + printf(" opo: bit2=exact bit1=repeated bit0=skip sparse\n"); + printf(" opoall: 0=minimize, 1=exact\n"); + printf(" pair: 0=algebraic, 1=strongd, 2=espresso, 3=exact\n"); + printf(" pairall: 0=minimize, 1=exact, 2=opo\n"); + printf(" so_espresso: 0=minimize, 1=exact\n"); + printf(" so_both: 0=minimize, 1=exact\n"); +} + +/* + * Hack for backward compatibility (ACK! ) + */ + +backward_compatibility_hack(argc, argv, option, out_type) +int *argc; +char **argv; +int *option; +int *out_type; +{ + int i, j; + + /* Scan the argument list for something to do (default is ESPRESSO) */ + *option = 0; + for(i = 1; i < (*argc)-1; i++) { + if (strcmp(argv[i], "-do") == 0) { + for(j = 0; option_table[j].name != 0; j++) + if (strcmp(argv[i+1], option_table[j].name) == 0) { + *option = j; + delete_arg(argc, argv, i+1); + delete_arg(argc, argv, i); + break; + } + if (option_table[j].name == 0) { + (void) fprintf(stderr, + "espresso: bad keyword \"%s\" following -do\n",argv[i+1]); + exit(1); + } + break; + } + } + + for(i = 1; i < (*argc)-1; i++) { + if (strcmp(argv[i], "-out") == 0) { + for(j = 0; pla_types[j].key != 0; j++) + if (strcmp(pla_types[j].key+1, argv[i+1]) == 0) { + *out_type = pla_types[j].value; + delete_arg(argc, argv, i+1); + delete_arg(argc, argv, i); + break; + } + if (pla_types[j].key == 0) { + (void) fprintf(stderr, + "espresso: bad keyword \"%s\" following -out\n",argv[i+1]); + exit(1); + } + break; + } + } + + for(i = 1; i < (*argc); i++) { + if (argv[i][0] == '-') { + for(j = 0; esp_opt_table[j].name != 0; j++) { + if (strcmp(argv[i]+1, esp_opt_table[j].name) == 0) { + delete_arg(argc, argv, i); + *(esp_opt_table[j].variable) = esp_opt_table[j].value; + break; + } + } + } + } + + if (check_arg(argc, argv, "-fdr")) input_type = FDR_type; + if (check_arg(argc, argv, "-fr")) input_type = FR_type; + if (check_arg(argc, argv, "-f")) input_type = F_type; +} + + +/* delete_arg -- delete an argument from the argument list */ +delete_arg(argc, argv, num) +int *argc, num; +register char *argv[]; +{ + register int i; + (*argc)--; + for(i = num; i < *argc; i++) { + argv[i] = argv[i+1]; + } +} + + +/* check_arg -- scan argv for an argument, and return TRUE if found */ +bool check_arg(argc, argv, s) +int *argc; +register char *argv[], *s; +{ + register int i; + for(i = 1; i < *argc; i++) { + if (strcmp(argv[i], s) == 0) { + delete_arg(argc, argv, i); + return TRUE; + } + } + return FALSE; +} diff --git a/espresso/main.h b/espresso/main.h new file mode 100644 index 0000000..03880bf --- /dev/null +++ b/espresso/main.h @@ -0,0 +1,122 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/main.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:56 $ + * + */ +enum keys { + KEY_ESPRESSO, KEY_PLA_verify, KEY_check, KEY_contain, KEY_d1merge, + KEY_disjoint, KEY_dsharp, KEY_echo, KEY_essen, KEY_exact, KEY_expand, + KEY_gasp, KEY_intersect, KEY_irred, KEY_lexsort, KEY_make_sparse, + KEY_map, KEY_mapdc, KEY_minterms, KEY_opo, KEY_opoall, + KEY_pair, KEY_pairall, KEY_primes, KEY_qm, KEY_reduce, KEY_sharp, + KEY_simplify, KEY_so, KEY_so_both, KEY_stats, KEY_super_gasp, KEY_taut, + KEY_test, KEY_equiv, KEY_union, KEY_verify, KEY_MANY_ESPRESSO, + KEY_separate, KEY_xor, KEY_d1merge_in, KEY_fsm, + KEY_unknown +}; + +/* Lookup table for program options */ +struct { + char *name; + enum keys key; + int num_plas; + bool needs_offset; + bool needs_dcset; +} option_table [] = { + /* ways to minimize functions */ + "ESPRESSO", KEY_ESPRESSO, 1, TRUE, TRUE, /* must be first */ + "many", KEY_MANY_ESPRESSO, 1, TRUE, TRUE, + "exact", KEY_exact, 1, TRUE, TRUE, + "qm", KEY_qm, 1, TRUE, TRUE, + "single_output", KEY_so, 1, TRUE, TRUE, + "so", KEY_so, 1, TRUE, TRUE, + "so_both", KEY_so_both, 1, TRUE, TRUE, + "simplify", KEY_simplify, 1, FALSE, FALSE, + "echo", KEY_echo, 1, FALSE, FALSE, + + /* output phase assignment and assignment of inputs to two-bit decoders */ + "opo", KEY_opo, 1, TRUE, TRUE, + "opoall", KEY_opoall, 1, TRUE, TRUE, + "pair", KEY_pair, 1, TRUE, TRUE, + "pairall", KEY_pairall, 1, TRUE, TRUE, + + /* Ways to check covers */ + "check", KEY_check, 1, TRUE, TRUE, + "stats", KEY_stats, 1, FALSE, FALSE, + "verify", KEY_verify, 2, FALSE, TRUE, + "PLAverify", KEY_PLA_verify, 2, FALSE, TRUE, + + /* hacks */ + "equiv", KEY_equiv, 1, TRUE, TRUE, + "map", KEY_map, 1, FALSE, FALSE, + "mapdc", KEY_mapdc, 1, FALSE, FALSE, + "fsm", KEY_fsm, 1, FALSE, TRUE, + + /* the basic boolean operations on covers */ + "contain", KEY_contain, 1, FALSE, FALSE, + "d1merge", KEY_d1merge, 1, FALSE, FALSE, + "d1merge_in", KEY_d1merge_in, 1, FALSE, FALSE, + "disjoint", KEY_disjoint, 1, TRUE, FALSE, + "dsharp", KEY_dsharp, 2, FALSE, FALSE, + "intersect", KEY_intersect, 2, FALSE, FALSE, + "minterms", KEY_minterms, 1, FALSE, FALSE, + "primes", KEY_primes, 1, FALSE, TRUE, + "separate", KEY_separate, 1, TRUE, TRUE, + "sharp", KEY_sharp, 2, FALSE, FALSE, + "union", KEY_union, 2, FALSE, FALSE, + "xor", KEY_xor, 2, TRUE, TRUE, + + /* debugging only -- call each step of the espresso algorithm */ + "essen", KEY_essen, 1, FALSE, TRUE, + "expand", KEY_expand, 1, TRUE, FALSE, + "gasp", KEY_gasp, 1, TRUE, TRUE, + "irred", KEY_irred, 1, FALSE, TRUE, + "make_sparse", KEY_make_sparse, 1, TRUE, TRUE, + "reduce", KEY_reduce, 1, FALSE, TRUE, + "taut", KEY_taut, 1, FALSE, FALSE, + "super_gasp", KEY_super_gasp, 1, TRUE, TRUE, + "lexsort", KEY_lexsort, 1, FALSE, FALSE, + "test", KEY_test, 1, TRUE, TRUE, + 0, KEY_unknown, 0, FALSE, FALSE /* must be last */ +}; + + +struct { + char *name; + int value; +} debug_table[] = { + "", EXPAND + ESSEN + IRRED + REDUCE + SPARSE + GASP + SHARP + MINCOV, + "compl", COMPL, "essen", ESSEN, + "expand", EXPAND, "expand1", EXPAND1|EXPAND, + "irred", IRRED, "irred1", IRRED1|IRRED, + "reduce", REDUCE, "reduce1", REDUCE1|REDUCE, + "mincov", MINCOV, "mincov1", MINCOV1|MINCOV, + "sparse", SPARSE, "sharp", SHARP, + "taut", TAUT, "gasp", GASP, + "exact", EXACT, + 0, +}; + + +struct { + char *name; + int *variable; + int value; +} esp_opt_table[] = { + "eat", &echo_comments, FALSE, + "eatdots", &echo_unknown_commands, FALSE, + "fast", &single_expand, TRUE, + "kiss", &kiss, TRUE, + "ness", &remove_essential, FALSE, + "nirr", &force_irredundant, FALSE, + "nunwrap", &unwrap_onset, FALSE, + "onset", &recompute_onset, TRUE, + "pos", &pos, TRUE, + "random", &use_random_order, TRUE, + "strong", &use_super_gasp, TRUE, + 0, +}; diff --git a/espresso/map.c b/espresso/map.c new file mode 100644 index 0000000..cdda741 --- /dev/null +++ b/espresso/map.c @@ -0,0 +1,115 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/map.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +#include "espresso.h" + +static pcube Gcube; +static pset Gminterm; + +pset minterms(T) +pcover T; +{ + int size, var; + register pcube last; + + size = 1; + for(var = 0; var < cube.num_vars; var++) + size *= cube.part_size[var]; + Gminterm = set_new(size); + + foreach_set(T, last, Gcube) + explode(cube.num_vars-1, 0); + + return Gminterm; +} + + +void explode(var, z) +int var, z; +{ + int i, last = cube.last_part[var]; + for(i=cube.first_part[var], z *= cube.part_size[var]; i<=last; i++, z++) + if (is_in_set(Gcube, i)) + if (var == 0) + set_insert(Gminterm, z); + else + explode(var-1, z); +} + + +static int mapindex[16][16] = { + 0, 1, 3, 2, 16, 17, 19, 18, 80, 81, 83, 82, 64, 65, 67, 66, + 4, 5, 7, 6, 20, 21, 23, 22, 84, 85, 87, 86, 68, 69, 71, 70, + 12, 13, 15, 14, 28, 29, 31, 30, 92, 93, 95, 94, 76, 77, 79, 78, + 8, 9, 11, 10, 24, 25, 27, 26, 88, 89, 91, 90, 72, 73, 75, 74, + + 32, 33, 35, 34, 48, 49, 51, 50, 112,113,115,114, 96, 97, 99, 98, + 36, 37, 39, 38, 52, 53, 55, 54, 116,117,119,118, 100,101,103,102, + 44, 45, 47, 46, 60, 61, 63, 62, 124,125,127,126, 108,109,111,110, + 40, 41, 43, 42, 56, 57, 59, 58, 120,121,123,122, 104,105,107,106, + + + 160,161,163,162, 176,177,179,178, 240,241,243,242, 224,225,227,226, + 164,165,167,166, 180,181,183,182, 244,245,247,246, 228,229,231,230, + 172,173,175,174, 188,189,191,190, 252,253,255,254, 236,237,239,238, + 168,169,171,170, 184,185,187,186, 248,249,251,250, 232,233,235,234, + + 128,129,131,130, 144,145,147,146, 208,209,211,210, 192,193,195,194, + 132,133,135,134, 148,149,151,150, 212,213,215,214, 196,197,199,198, + 140,141,143,142, 156,157,159,158, 220,221,223,222, 204,205,207,206, + 136,137,139,138, 152,153,155,154, 216,217,219,218, 200,201,203,202 +}; + +#define POWER2(n) (1 << n) +void map(T) +pcover T; +{ + int j, k, l, other_input_offset, output_offset, outnum, ind; + int largest_input_ind, numout; + char c; + pset m; + bool some_output; + + m = minterms(T); + largest_input_ind = POWER2(cube.num_binary_vars); + numout = cube.part_size[cube.num_vars-1]; + + for(outnum = 0; outnum < numout; outnum++) { + output_offset = outnum * largest_input_ind; + printf("\n\nOutput space # %d\n", outnum); + for(l = 0; l <= MAX(cube.num_binary_vars - 8, 0); l++) { + other_input_offset = l * 256; + for(k = 0; k < 16; k++) { + some_output = FALSE; + for(j = 0; j < 16; j++) { + ind = mapindex[k][j] + other_input_offset; + if (ind < largest_input_ind) { + c = is_in_set(m, ind+output_offset) ? '1' : '.'; + putchar(c); + some_output = TRUE; + } + if ((j+1)%4 == 0) + putchar(' '); + if ((j+1)%8 == 0) + printf(" "); + } + if (some_output) + putchar('\n'); + if ((k+1)%4 == 0) { + if (k != 15 && mapindex[k+1][0] >= largest_input_ind) + break; + putchar('\n'); + } + if ((k+1)%8 == 0) + putchar('\n'); + } + } + } + set_free(m); +} diff --git a/espresso/matrix.c b/espresso/matrix.c new file mode 100644 index 0000000..381f0a6 --- /dev/null +++ b/espresso/matrix.c @@ -0,0 +1,574 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/matrix.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:59 $ + * + */ +#include "port.h" +#include "sparse_int.h" + +/* + * free-lists are only used if 'FAST_AND_LOOSE' is set; this is because + * we lose the debugging capability of libmm_t which trashes objects when + * they are free'd. However, FAST_AND_LOOSE is much faster if matrices + * are created and freed frequently. + */ + +#ifdef FAST_AND_LOOSE +sm_element *sm_element_freelist; +sm_row *sm_row_freelist; +sm_col *sm_col_freelist; +#endif + + +sm_matrix * +sm_alloc() +{ + register sm_matrix *A; + + A = ALLOC(sm_matrix, 1); + A->rows = NIL(sm_row *); + A->cols = NIL(sm_col *); + A->nrows = A->ncols = 0; + A->rows_size = A->cols_size = 0; + A->first_row = A->last_row = NIL(sm_row); + A->first_col = A->last_col = NIL(sm_col); + A->user_word = NIL(char); /* for our user ... */ + return A; +} + + +sm_matrix * +sm_alloc_size(row, col) +int row, col; +{ + register sm_matrix *A; + + A = sm_alloc(); + sm_resize(A, row, col); + return A; +} + + +void +sm_free(A) +sm_matrix *A; +{ +#ifdef FAST_AND_LOOSE + register sm_row *prow; + + if (A->first_row != 0) { + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + /* add the elements to the free list of elements */ + prow->last_col->next_col = sm_element_freelist; + sm_element_freelist = prow->first_col; + } + + /* Add the linked list of rows to the row-free-list */ + A->last_row->next_row = sm_row_freelist; + sm_row_freelist = A->first_row; + + /* Add the linked list of cols to the col-free-list */ + A->last_col->next_col = sm_col_freelist; + sm_col_freelist = A->first_col; + } +#else + register sm_row *prow, *pnext_row; + register sm_col *pcol, *pnext_col; + + for(prow = A->first_row; prow != 0; prow = pnext_row) { + pnext_row = prow->next_row; + sm_row_free(prow); + } + for(pcol = A->first_col; pcol != 0; pcol = pnext_col) { + pnext_col = pcol->next_col; + pcol->first_row = pcol->last_row = NIL(sm_element); + sm_col_free(pcol); + } +#endif + + /* Free the arrays to map row/col numbers into pointers */ + FREE(A->rows); + FREE(A->cols); + FREE(A); +} + + +sm_matrix * +sm_dup(A) +sm_matrix *A; +{ + register sm_row *prow; + register sm_element *p; + register sm_matrix *B; + + B = sm_alloc(); + if (A->last_row != 0) { + sm_resize(B, A->last_row->row_num, A->last_col->col_num); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(B, p->row_num, p->col_num); + } + } + } + return B; +} + + +void +sm_resize(A, row, col) +register sm_matrix *A; +int row, col; +{ + register int i, new_size; + + if (row >= A->rows_size) { + new_size = MAX(A->rows_size*2, row+1); + A->rows = REALLOC(sm_row *, A->rows, new_size); + for(i = A->rows_size; i < new_size; i++) { + A->rows[i] = NIL(sm_row); + } + A->rows_size = new_size; + } + + if (col >= A->cols_size) { + new_size = MAX(A->cols_size*2, col+1); + A->cols = REALLOC(sm_col *, A->cols, new_size); + for(i = A->cols_size; i < new_size; i++) { + A->cols[i] = NIL(sm_col); + } + A->cols_size = new_size; + } +} + + +/* + * insert -- insert a value into the matrix + */ +sm_element * +sm_insert(A, row, col) +register sm_matrix *A; +register int row, col; +{ + register sm_row *prow; + register sm_col *pcol; + register sm_element *element; + sm_element *save_element; + + if (row >= A->rows_size || col >= A->cols_size) { + sm_resize(A, row, col); + } + + prow = A->rows[row]; + if (prow == NIL(sm_row)) { + prow = A->rows[row] = sm_row_alloc(); + prow->row_num = row; + sorted_insert(sm_row, A->first_row, A->last_row, A->nrows, + next_row, prev_row, row_num, row, prow); + } + + pcol = A->cols[col]; + if (pcol == NIL(sm_col)) { + pcol = A->cols[col] = sm_col_alloc(); + pcol->col_num = col; + sorted_insert(sm_col, A->first_col, A->last_col, A->ncols, + next_col, prev_col, col_num, col, pcol); + } + + /* get a new item, save its address */ + sm_element_alloc(element); + save_element = element; + + /* insert it into the row list */ + sorted_insert(sm_element, prow->first_col, prow->last_col, + prow->length, next_col, prev_col, col_num, col, element); + + /* if it was used, also insert it into the column list */ + if (element == save_element) { + sorted_insert(sm_element, pcol->first_row, pcol->last_row, + pcol->length, next_row, prev_row, row_num, row, element); + } else { + /* otherwise, it was already in matrix -- free element we allocated */ + sm_element_free(save_element); + } + return element; +} + + +sm_element * +sm_find(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; +{ + sm_row *prow; + sm_col *pcol; + + prow = sm_get_row(A, rownum); + if (prow == NIL(sm_row)) { + return NIL(sm_element); + } else { + pcol = sm_get_col(A, colnum); + if (pcol == NIL(sm_col)) { + return NIL(sm_element); + } + if (prow->length < pcol->length) { + return sm_row_find(prow, colnum); + } else { + return sm_col_find(pcol, rownum); + } + } +} + + +void +sm_remove(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; +{ + sm_remove_element(A, sm_find(A, rownum, colnum)); +} + + + +void +sm_remove_element(A, p) +register sm_matrix *A; +register sm_element *p; +{ + register sm_row *prow; + register sm_col *pcol; + + if (p == 0) return; + + /* Unlink the element from its row */ + prow = sm_get_row(A, p->row_num); + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + + /* if no more elements in the row, discard the row header */ + if (prow->first_col == NIL(sm_element)) { + sm_delrow(A, p->row_num); + } + + /* Unlink the element from its column */ + pcol = sm_get_col(A, p->col_num); + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + + /* if no more elements in the column, discard the column header */ + if (pcol->first_row == NIL(sm_element)) { + sm_delcol(A, p->col_num); + } + + sm_element_free(p); +} + +void +sm_delrow(A, i) +sm_matrix *A; +int i; +{ + register sm_element *p, *pnext; + sm_col *pcol; + sm_row *prow; + + prow = sm_get_row(A, i); + if (prow != NIL(sm_row)) { + /* walk across the row */ + for(p = prow->first_col; p != 0; p = pnext) { + pnext = p->next_col; + + /* unlink the item from the column (and delete it) */ + pcol = sm_get_col(A, p->col_num); + sm_col_remove_element(pcol, p); + + /* discard the column if it is now empty */ + if (pcol->first_row == NIL(sm_element)) { + sm_delcol(A, pcol->col_num); + } + } + + /* discard the row -- we already threw away the elements */ + A->rows[i] = NIL(sm_row); + dll_unlink(prow, A->first_row, A->last_row, + next_row, prev_row, A->nrows); + prow->first_col = prow->last_col = NIL(sm_element); + sm_row_free(prow); + } +} + +void +sm_delcol(A, i) +sm_matrix *A; +int i; +{ + register sm_element *p, *pnext; + sm_row *prow; + sm_col *pcol; + + pcol = sm_get_col(A, i); + if (pcol != NIL(sm_col)) { + /* walk down the column */ + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; + + /* unlink the element from the row (and delete it) */ + prow = sm_get_row(A, p->row_num); + sm_row_remove_element(prow, p); + + /* discard the row if it is now empty */ + if (prow->first_col == NIL(sm_element)) { + sm_delrow(A, prow->row_num); + } + } + + /* discard the column -- we already threw away the elements */ + A->cols[i] = NIL(sm_col); + dll_unlink(pcol, A->first_col, A->last_col, + next_col, prev_col, A->ncols); + pcol->first_row = pcol->last_row = NIL(sm_element); + sm_col_free(pcol); + } +} + +void +sm_copy_row(dest, dest_row, prow) +register sm_matrix *dest; +int dest_row; +sm_row *prow; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(dest, dest_row, p->col_num); + } +} + + +void +sm_copy_col(dest, dest_col, pcol) +register sm_matrix *dest; +int dest_col; +sm_col *pcol; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) sm_insert(dest, dest_col, p->row_num); + } +} + + +sm_row * +sm_longest_row(A) +sm_matrix *A; +{ + register sm_row *large_row, *prow; + register int max_length; + + max_length = 0; + large_row = NIL(sm_row); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->length > max_length) { + max_length = prow->length; + large_row = prow; + } + } + return large_row; +} + + +sm_col * +sm_longest_col(A) +sm_matrix *A; +{ + register sm_col *large_col, *pcol; + register int max_length; + + max_length = 0; + large_col = NIL(sm_col); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + if (pcol->length > max_length) { + max_length = pcol->length; + large_col = pcol; + } + } + return large_col; +} + +int +sm_num_elements(A) +sm_matrix *A; +{ + register sm_row *prow; + register int num; + + num = 0; + sm_foreach_row(A, prow) { + num += prow->length; + } + return num; +} + +int +sm_read(fp, A) +FILE *fp; +sm_matrix **A; +{ + int i, j, err; + + *A = sm_alloc(); + while (! feof(fp)) { + err = fscanf(fp, "%d %d", &i, &j); + if (err == EOF) { + return 1; + } else if (err != 2) { + return 0; + } + (void) sm_insert(*A, i, j); + } + return 1; +} + + +int +sm_read_compressed(fp, A) +FILE *fp; +sm_matrix **A; +{ + int i, j, k, nrows, ncols; + unsigned long x; + + *A = sm_alloc(); + if (fscanf(fp, "%d %d", &nrows, &ncols) != 2) { + return 0; + } + sm_resize(*A, nrows, ncols); + + for(i = 0; i < nrows; i++) { + if (fscanf(fp, "%lx", &x) != 1) { + return 0; + } + for(j = 0; j < ncols; j += 32) { + if (fscanf(fp, "%lx", &x) != 1) { + return 0; + } + for(k = j; x != 0; x >>= 1, k++) { + if (x & 1) { + (void) sm_insert(*A, i, k); + } + } + } + } + return 1; +} + + +void +sm_write(fp, A) +FILE *fp; +sm_matrix *A; +{ + register sm_row *prow; + register sm_element *p; + + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) fprintf(fp, "%d %d\n", p->row_num, p->col_num); + } + } +} + +void +sm_print(fp, A) +FILE *fp; +sm_matrix *A; +{ + register sm_row *prow; + register sm_col *pcol; + int c; + + if (A->last_col->col_num >= 100) { + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", (pcol->col_num / 100)%10); + } + putc('\n', fp); + } + + if (A->last_col->col_num >= 10) { + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", (pcol->col_num / 10)%10); + } + putc('\n', fp); + } + + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", pcol->col_num % 10); + } + putc('\n', fp); + + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "-"); + } + putc('\n', fp); + + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + (void) fprintf(fp, "%3d:", prow->row_num); + + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + c = sm_row_find(prow, pcol->col_num) ? '1' : '.'; + putc(c, fp); + } + putc('\n', fp); + } +} + + +void +sm_dump(A, s, max) +sm_matrix *A; +char *s; +int max; +{ + FILE *fp = stdout; + + (void) fprintf(fp, "%s %d rows by %d cols\n", s, A->nrows, A->ncols); + if (A->nrows < max) { + sm_print(fp, A); + } +} + +void +sm_cleanup() +{ +#ifdef FAST_AND_LOOSE + register sm_element *p, *pnext; + register sm_row *prow, *pnextrow; + register sm_col *pcol, *pnextcol; + + for(p = sm_element_freelist; p != 0; p = pnext) { + pnext = p->next_col; + FREE(p); + } + sm_element_freelist = 0; + + for(prow = sm_row_freelist; prow != 0; prow = pnextrow) { + pnextrow = prow->next_row; + FREE(prow); + } + sm_row_freelist = 0; + + for(pcol = sm_col_freelist; pcol != 0; pcol = pnextcol) { + pnextcol = pcol->next_col; + FREE(pcol); + } + sm_col_freelist = 0; +#endif +} diff --git a/espresso/mincov.c b/espresso/mincov.c new file mode 100644 index 0000000..51a547f --- /dev/null +++ b/espresso/mincov.c @@ -0,0 +1,378 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/mincov.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "mincov_int.h" + +/* + * mincov.c + */ + +#define USE_GIMPEL +#define USE_INDEP_SET + +static int select_column(); +static void select_essential(); +static int verify_cover(); + +#define fail(why) {\ + (void) fprintf(stderr, "Fatal error: file %s, line %d\n%s\n",\ + __FILE__, __LINE__, why);\ + (void) fflush(stdout);\ + abort();\ +} + +sm_row * +sm_minimum_cover(A, weight, heuristic, debug_level) +sm_matrix *A; +int *weight; +int heuristic; /* set to 1 for a heuristic covering */ +int debug_level; /* how deep in the recursion to provide info */ +{ + stats_t stats; + solution_t *best, *select; + sm_row *prow, *sol; + sm_col *pcol; + sm_matrix *dup_A; + int nelem, bound; + double sparsity; + + /* Avoid sillyness */ + if (A->nrows <= 0) { + return sm_row_alloc(); /* easy to cover */ + } + + /* Initialize debugging structure */ + stats.start_time = util_cpu_time(); + stats.debug = debug_level > 0; + stats.max_print_depth = debug_level; + stats.max_depth = -1; + stats.nodes = 0; + stats.component = stats.comp_count = 0; + stats.gimpel = stats.gimpel_count = 0; + stats.no_branching = heuristic != 0; + stats.lower_bound = -1; + + /* Check the matrix sparsity */ + nelem = 0; + sm_foreach_row(A, prow) { + nelem += prow->length; + } + sparsity = (double) nelem / (double) (A->nrows * A->ncols); + + /* Determine an upper bound on the solution */ + bound = 1; + sm_foreach_col(A, pcol) { + bound += WEIGHT(weight, pcol->col_num); + } + + /* Perform the covering */ + select = solution_alloc(); + dup_A = sm_dup(A); + best = sm_mincov(dup_A, select, weight, 0, bound, 0, &stats); + sm_free(dup_A); + solution_free(select); + + if (stats.debug) { + if (stats.no_branching) { + (void) printf("**** heuristic covering ...\n"); + (void) printf("lower bound = %d\n", stats.lower_bound); + } + (void) printf("matrix = %d by %d with %d elements (%4.3f%%)\n", + A->nrows, A->ncols, nelem, sparsity * 100.0); + (void) printf("cover size = %d elements\n", best->row->length); + (void) printf("cover cost = %d\n", best->cost); + (void) printf("time = %s\n", + util_print_time(util_cpu_time() - stats.start_time)); + (void) printf("components = %d\n", stats.comp_count); + (void) printf("gimpel = %d\n", stats.gimpel_count); + (void) printf("nodes = %d\n", stats.nodes); + (void) printf("max_depth = %d\n", stats.max_depth); + } + + sol = sm_row_dup(best->row); + if (! verify_cover(A, sol)) { + fail("mincov: internal error -- cover verification failed\n"); + } + solution_free(best); + return sol; +} + +/* + * Find the best cover for 'A' (given that 'select' already selected); + * + * - abort search if a solution cannot be found which beats 'bound' + * + * - if any solution meets 'lower_bound', then it is the optimum solution + * and can be returned without further work. + */ + +solution_t * +sm_mincov(A, select, weight, lb, bound, depth, stats) +sm_matrix *A; +solution_t *select; +int *weight; +int lb; +int bound; +int depth; +stats_t *stats; +{ + sm_matrix *A1, *A2, *L, *R; + sm_element *p; + solution_t *select1, *select2, *best, *best1, *best2, *indep; + int pick, lb_new, debug; + + /* Start out with some debugging information */ + stats->nodes++; + if (depth > stats->max_depth) stats->max_depth = depth; + debug = stats->debug && (depth <= stats->max_print_depth); + + /* Apply row dominance, column dominance, and select essentials */ + select_essential(A, select, weight, bound); + if (select->cost >= bound) { + return NIL(solution_t); + } + + /* See if gimpel's reduction technique applies ... */ +#ifdef USE_GIMPEL + if ( weight == NIL(int)) { /* hack until we fix it */ + if (gimpel_reduce(A, select, weight, lb, bound, depth, stats, &best)) { + return best; + } + } +#endif + +#ifdef USE_INDEP_SET + /* Determine bound from here to final solution using independent-set */ + indep = sm_maximal_independent_set(A, weight); + + /* make sure the lower bound is monotonically increasing */ + lb_new = MAX(select->cost + indep->cost, lb); + pick = select_column(A, weight, indep); + solution_free(indep); +#else + lb_new = select->cost + (A->nrows > 0); + pick = select_column(A, weight, NIL(solution_t)); +#endif + + if (depth == 0) { + stats->lower_bound = lb_new + stats->gimpel; + } + + if (debug) { + (void) printf("ABSMIN[%2d]%s", depth, stats->component ? "*" : " "); + (void) printf(" %3dx%3d sel=%3d bnd=%3d lb=%3d %12s ", + A->nrows, A->ncols, select->cost + stats->gimpel, + bound + stats->gimpel, lb_new + stats->gimpel, + util_print_time(util_cpu_time()-stats->start_time)); + } + + /* Check for bounding based on no better solution possible */ + if (lb_new >= bound) { + if (debug) (void) printf("bounded\n"); + best = NIL(solution_t); + + + /* Check for new best solution */ + } else if (A->nrows == 0) { + best = solution_dup(select); + if (debug) (void) printf("BEST\n"); + if (stats->debug && stats->component == 0) { + (void) printf("new 'best' solution %d at level %d (time is %s)\n", + best->cost + stats->gimpel, depth, + util_print_time(util_cpu_time() - stats->start_time)); + } + + + /* Check for a partition of the problem */ + } else if (sm_block_partition(A, &L, &R)) { + /* Make L the smaller problem */ + if (L->ncols > R->ncols) { + A1 = L; + L = R; + R = A1; + } + if (debug) (void) printf("comp %d %d\n", L->nrows, R->nrows); + stats->comp_count++; + + /* Solve problem for L */ + select1 = solution_alloc(); + stats->component++; + best1 = sm_mincov(L, select1, weight, 0, + bound-select->cost, depth+1, stats); + stats->component--; + solution_free(select1); + sm_free(L); + + /* Add best solution to the selected set */ + if (best1 == NIL(solution_t)) { + best = NIL(solution_t); + } else { + for(p = best1->row->first_col; p != 0; p = p->next_col) { + solution_add(select, weight, p->col_num); + } + solution_free(best1); + + /* recur for the remaining block */ + best = sm_mincov(R, select, weight, lb_new, bound, depth+1, stats); + } + sm_free(R); + + /* We've tried as hard as possible, but now we must split and recur */ + } else { + if (debug) (void) printf("pick=%d\n", pick); + + /* Assume we choose this column to be in the covering set */ + A1 = sm_dup(A); + select1 = solution_dup(select); + solution_accept(select1, A1, weight, pick); + best1 = sm_mincov(A1, select1, weight, lb_new, bound, depth+1, stats); + solution_free(select1); + sm_free(A1); + + /* Update the upper bound if we found a better solution */ + if (best1 != NIL(solution_t) && bound > best1->cost) { + bound = best1->cost; + } + + /* See if this is a heuristic covering (no branching) */ + if (stats->no_branching) { + return best1; + } + + /* Check for reaching lower bound -- if so, don't actually branch */ + if (best1 != NIL(solution_t) && best1->cost == lb_new) { + return best1; + } + + /* Now assume we cannot have that column */ + A2 = sm_dup(A); + select2 = solution_dup(select); + solution_reject(select2, A2, weight, pick); + best2 = sm_mincov(A2, select2, weight, lb_new, bound, depth+1, stats); + solution_free(select2); + sm_free(A2); + + best = solution_choose_best(best1, best2); + } + + return best; +} + +static int +select_column(A, weight, indep) +sm_matrix *A; +int *weight; +solution_t *indep; +{ + register sm_col *pcol; + register sm_row *prow, *indep_cols; + register sm_element *p, *p1; + double w, best; + int best_col; + + indep_cols = sm_row_alloc(); + if (indep != NIL(solution_t)) { + /* Find which columns are in the independent sets */ + for(p = indep->row->first_col; p != 0; p = p->next_col) { + prow = sm_get_row(A, p->col_num); + for(p1 = prow->first_col; p1 != 0; p1 = p1->next_col) { + (void) sm_row_insert(indep_cols, p1->col_num); + } + } + } else { + /* select out of all columns */ + sm_foreach_col(A, pcol) { + (void) sm_row_insert(indep_cols, pcol->col_num); + } + } + + /* Find the best column */ + best_col = -1; + best = -1; + + /* Consider only columns which are in some independent row */ + sm_foreach_row_element(indep_cols, p1) { + pcol = sm_get_col(A, p1->col_num); + + /* Compute the total 'value' of all things covered by the column */ + w = 0.0; + for(p = pcol->first_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + w += 1.0 / ((double) prow->length - 1.0); + } + + /* divide this by the relative cost of choosing this column */ + w = w / (double) WEIGHT(weight, pcol->col_num); + + /* maximize this ratio */ + if (w > best) { + best_col = pcol->col_num; + best = w; + } + } + + sm_row_free(indep_cols); + return best_col; +} + +static void +select_essential(A, select, weight, bound) +sm_matrix *A; +solution_t *select; +int *weight; +int bound; /* must beat this solution */ +{ + register sm_element *p; + register sm_row *prow, *essen; + int delcols, delrows, essen_count; + + do { + /* Check for dominated columns */ + delcols = sm_col_dominance(A, weight); + + /* Find the rows with only 1 element (the essentials) */ + essen = sm_row_alloc(); + sm_foreach_row(A, prow) { + if (prow->length == 1) { + (void) sm_row_insert(essen, prow->first_col->col_num); + } + } + + /* Select all of the elements */ + sm_foreach_row_element(essen, p) { + solution_accept(select, A, weight, p->col_num); + /* Make sure solution still looks good */ + if (select->cost >= bound) { + sm_row_free(essen); + return; + } + } + essen_count = essen->length; + sm_row_free(essen); + + /* Check for dominated rows */ + delrows = sm_row_dominance(A); + + } while (delcols > 0 || delrows > 0 || essen_count > 0); +} + +static int +verify_cover(A, cover) +sm_matrix *A; +sm_row *cover; +{ + sm_row *prow; + + sm_foreach_row(A, prow) { + if (! sm_row_intersects(prow, cover)) { + return 0; + } + } + return 1; +} diff --git a/espresso/mincov.h b/espresso/mincov.h new file mode 100644 index 0000000..3539e06 --- /dev/null +++ b/espresso/mincov.h @@ -0,0 +1,11 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/mincov.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +/* exported */ +extern sm_row *sm_minimum_cover(); diff --git a/espresso/mincov_int.h b/espresso/mincov_int.h new file mode 100644 index 0000000..84b747f --- /dev/null +++ b/espresso/mincov_int.h @@ -0,0 +1,53 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/mincov_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "port.h" +#include "utility.h" +#include "sparse.h" +#include "mincov.h" + + +typedef struct stats_struct stats_t; +struct stats_struct { + int debug; /* 1 if debugging is enabled */ + int max_print_depth; /* dump stats for levels up to this level */ + int max_depth; /* deepest the recursion has gone */ + int nodes; /* total nodes visited */ + int component; /* currently solving a component */ + int comp_count; /* number of components detected */ + int gimpel_count; /* number of times Gimpel reduction applied */ + int gimpel; /* currently inside Gimpel reduction */ + long start_time; /* cpu time when the covering started */ + int no_branching; + int lower_bound; +}; + + + +typedef struct solution_struct solution_t; +struct solution_struct { + sm_row *row; + int cost; +}; + + +extern solution_t *solution_alloc(); +extern void solution_free(); +extern solution_t *solution_dup(); +extern void solution_accept(); +extern void solution_reject(); +extern void solution_add(); +extern solution_t *solution_choose_best(); + +extern solution_t *sm_maximal_independent_set(); +extern solution_t *sm_mincov(); +extern int gimpel_reduce(); + + +#define WEIGHT(weight, col) (weight == NIL(int) ? 1 : weight[col]) diff --git a/espresso/opo.c b/espresso/opo.c new file mode 100644 index 0000000..9b86974 --- /dev/null +++ b/espresso/opo.c @@ -0,0 +1,624 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/opo.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:57 $ + * + */ +#include "espresso.h" + +/* + * Phase assignment technique (T. Sasao): + * + * 1. create a function with 2*m outputs which implements the + * original function and its complement for each output + * + * 2. minimize this function + * + * 3. choose the minimum number of prime implicants from the + * result of step 2 which are needed to realize either a function + * or its complement for each output + * + * Step 3 is performed in a rather crude way -- by simply multiplying + * out a large expression of the form: + * + * I = (ab + cdef)(acd + bgh) ... + * + * which is a product of m expressions where each expression has two + * product terms -- one representing which primes are needed for the + * function, and one representing which primes are needed for the + * complement. The largest product term resulting shows which primes + * to keep to implement one function or the other for each output. + * For problems with many outputs, this may grind to a + * halt. + * + * Untried: form complement of I and use unate_complement ... + * + * I have unsuccessfully tried several modifications to the basic + * algorithm. The first is quite simple: use Sasao's technique, but + * only commit to a single output at a time (rather than all + * outputs). The goal would be that the later minimizations can "take + * into account" the partial assignment at each step. This is + * expensive (m+1 minimizations rather than 2), and the results are + * discouraging. + * + * The second modification is rather complicated. The result from the + * minimization in step 2 is guaranteed to be minimal. Hence, for + * each output, the set of primes with a 1 in that output are both + * necessary and sufficient to implement the function. Espresso + * achieves the minimality using the routine MAKE_SPARSE. The + * modification is to prevent MAKE_SPARSE from running. Hence, there + * are potentially many subsets of the set of primes with a 1 in a + * column which can be used to implement that output. We use + * IRREDUNDANT to enumerate all possible subsets and then proceed as + * before. + */ + +static int opo_no_make_sparse; +static int opo_repeated; +static int opo_exact; +static void minimize(); + +void phase_assignment(PLA, opo_strategy) +pPLA PLA; +int opo_strategy; +{ + opo_no_make_sparse = opo_strategy % 2; + skip_make_sparse = opo_no_make_sparse; + opo_repeated = (opo_strategy / 2) % 2; + opo_exact = (opo_strategy / 4) % 2; + + /* Determine a phase assignment */ + if (PLA->phase != NULL) { + FREE(PLA->phase); + } + + if (opo_repeated) { + PLA->phase = set_save(cube.fullset); + repeated_phase_assignment(PLA); + } else { + PLA->phase = find_phase(PLA, 0, (pcube) NULL); + } + + /* Now minimize with this assignment */ + skip_make_sparse = FALSE; + (void) set_phase(PLA); + minimize(PLA); +} + +/* + * repeated_phase_assignment -- an alternate strategy which commits + * to a single phase assignment a step at a time. Performs m + 1 + * minimizations ! + */ +void repeated_phase_assignment(PLA) +pPLA PLA; +{ + int i; + pcube phase; + + for(i = 0; i < cube.part_size[cube.output]; i++) { + + /* Find best assignment for all undecided outputs */ + phase = find_phase(PLA, i, PLA->phase); + + /* Commit for only a single output ... */ + if (! is_in_set(phase, cube.first_part[cube.output] + i)) { + set_remove(PLA->phase, cube.first_part[cube.output] + i); + } + + if (trace || summary) { + printf("\nOPO loop for output #%d\n", i); + printf("PLA->phase is %s\n", pc1(PLA->phase)); + printf("phase is %s\n", pc1(phase)); + } + set_free(phase); + } +} + + +/* + * find_phase -- find a phase assignment for the PLA for all outputs starting + * with output number first_output. + */ +pcube find_phase(PLA, first_output, phase1) +pPLA PLA; +int first_output; +pcube phase1; +{ + pcube phase; + pPLA PLA1; + + phase = set_save(cube.fullset); + + /* setup the double-phase characteristic function, resize the cube */ + PLA1 = new_PLA(); + PLA1->F = sf_save(PLA->F); + PLA1->R = sf_save(PLA->R); + PLA1->D = sf_save(PLA->D); + if (phase1 != NULL) { + PLA1->phase = set_save(phase1); + (void) set_phase(PLA1); + } + EXEC_S(output_phase_setup(PLA1, first_output), "OPO-SETUP ", PLA1->F); + + /* minimize the double-phase function */ + minimize(PLA1); + + /* set the proper phases according to what gives a minimum solution */ + EXEC_S(PLA1->F = opo(phase, PLA1->F, PLA1->D, PLA1->R, first_output), + "OPO ", PLA1->F); + free_PLA(PLA1); + + /* set the cube structure to reflect the old size */ + setdown_cube(); + cube.part_size[cube.output] -= + (cube.part_size[cube.output] - first_output) / 2; + cube_setup(); + + return phase; +} + +/* + * opo -- multiply the expression out to determine a minimum subset of + * primes. + */ + +/*ARGSUSED*/ +pcover opo(phase, T, D, R, first_output) +pcube phase; +pcover T, D, R; +int first_output; +{ + int offset, output, i, last_output, ind; + pset pdest, select, p, p1, last, last1, not_covered, tmp; + pset_family temp, T1, T2; + + /* must select all primes for outputs [0 .. first_output-1] */ + select = set_full(T->count); + for(output = 0; output < first_output; output++) { + ind = cube.first_part[cube.output] + output; + foreachi_set(T, i, p) { + if (is_in_set(p, ind)) { + set_remove(select, i); + } + } + } + + /* Recursively perform the intersections */ + offset = (cube.part_size[cube.output] - first_output) / 2; + last_output = first_output + offset - 1; + temp = opo_recur(T, D, select, offset, first_output, last_output); + + /* largest set is on top -- select primes which are inferred from it */ + pdest = temp->data; + T1 = new_cover(T->count); + foreachi_set(T, i, p) { + if (! is_in_set(pdest, i)) { + T1 = sf_addset(T1, p); + } + } + + set_free(select); + sf_free(temp); + + /* finding phases is difficult -- see which functions are not covered */ + T2 = complement(cube1list(T1)); + not_covered = new_cube(); + tmp = new_cube(); + foreach_set(T, last, p) { + foreach_set(T2, last1, p1) { + if (cdist0(p, p1)) { + (void) set_or(not_covered, not_covered, set_and(tmp, p, p1)); + } + } + } + free_cover(T); + free_cover(T2); + set_free(tmp); + + /* Now reflect the phase choice in a single cube */ + for(output = first_output; output <= last_output; output++) { + ind = cube.first_part[cube.output] + output; + if (is_in_set(not_covered, ind)) { + if (is_in_set(not_covered, ind + offset)) { + fatal("error in output phase assignment"); + } else { + set_remove(phase, ind); + } + } + } + set_free(not_covered); + return T1; +} + +pset_family opo_recur(T, D, select, offset, first, last) +pcover T, D; +pcube select; +int offset, first, last; +{ + static int level = 0; + int middle; + pset_family sl, sr, temp; + + level++; + if (first == last) { +#if 0 + if (opo_no_make_sparse) { + temp = form_cover_table(T, D, select, first, first + offset); + } else { + temp = opo_leaf(T, select, first, first + offset); + } +#else + temp = opo_leaf(T, select, first, first + offset); +#endif + } else { + middle = (first + last) / 2; + sl = opo_recur(T, D, select, offset, first, middle); + sr = opo_recur(T, D, select, offset, middle+1, last); + temp = unate_intersect(sl, sr, level == 1); + if (trace) { + printf("# OPO[%d]: %4d = %4d x %4d, time = %s\n", level - 1, + temp->count, sl->count, sr->count, print_time(ptime())); + (void) fflush(stdout); + } + free_cover(sl); + free_cover(sr); + } + level--; + return temp; +} + + +pset_family opo_leaf(T, select, out1, out2) +register pcover T; +pset select; +int out1, out2; +{ + register pset_family temp; + register pset p, pdest; + register int i; + + out1 += cube.first_part[cube.output]; + out2 += cube.first_part[cube.output]; + + /* Allocate space for the result */ + temp = sf_new(2, T->count); + + /* Find which primes are needed for the ON-set of this fct */ + pdest = GETSET(temp, temp->count++); + (void) set_copy(pdest, select); + foreachi_set(T, i, p) { + if (is_in_set(p, out1)) { + set_remove(pdest, i); + } + } + + /* Find which primes are needed for the OFF-set of this fct */ + pdest = GETSET(temp, temp->count++); + (void) set_copy(pdest, select); + foreachi_set(T, i, p) { + if (is_in_set(p, out2)) { + set_remove(pdest, i); + } + } + + return temp; +} + +#if 0 +pset_family form_cover_table(F, D, select, f, fbar) +pcover F, D; +pset select; +int f, fbar; /* indices of f and fbar in the output part */ +{ + register int i; + register pcube p; + pset_family f_table, fbar_table; + + /* setup required for fcube_is_covered */ + Rp_size = F->count; + Rp_start = set_new(Rp_size); + foreachi_set(F, i, p) { + PUTSIZE(p, i); + } + foreachi_set(D, i, p) { + RESET(p, REDUND); + } + + f_table = find_covers(F, D, select, f); + fbar_table = find_covers(F, D, select, fbar); + f_table = sf_append(f_table, fbar_table); + + set_free(Rp_start); + return f_table; +} + + +pset_family find_covers(F, D, select, n) +pcover F, D; +register pset select; +int n; +{ + register pset p, last, new; + pcover F1; + pcube *Flist; + pset_family f_table, table; + int i; + + n += cube.first_part[cube.output]; + + /* save cubes in this output, and remove the output variable */ + F1 = new_cover(F->count); + foreach_set(F, last, p) + if (is_in_set(p, n)) { + new = GETSET(F1, F1->count++); + set_or(new, p, cube.var_mask[cube.output]); + PUTSIZE(new, SIZE(p)); + SET(new, REDUND); + } + + /* Find ways (sop form) to fail to cover output indexed by n */ + Flist = cube2list(F1, D); + table = sf_new(10, Rp_size); + foreach_set(F1, last, p) { + set_fill(Rp_start, Rp_size); + set_remove(Rp_start, SIZE(p)); + table = sf_append(table, fcube_is_covered(Flist, p)); + RESET(p, REDUND); + } + set_fill(Rp_start, Rp_size); + foreach_set(table, last, p) { + set_diff(p, Rp_start, p); + } + + /* complement this to get possible ways to cover the function */ + for(i = 0; i < Rp_size; i++) { + if (! is_in_set(select, i)) { + p = set_new(Rp_size); + set_insert(p, i); + table = sf_addset(table, p); + set_free(p); + } + } + f_table = unate_compl(table); + + /* what a pain, but we need bitwise complement of this */ + set_fill(Rp_start, Rp_size); + foreach_set(f_table, last, p) { + set_diff(p, Rp_start, p); + } + + free_cubelist(Flist); + sf_free(F1); + return f_table; +} +#endif + +/* + * Take a PLA (ON-set, OFF-set and DC-set) and create the + * "double-phase characteristic function" which is merely a new + * function which has twice as many outputs and realizes both the + * function and the complement. + * + * The cube structure is assumed to represent the PLA upon entering. + * It will be modified to represent the double-phase function upon + * exit. + * + * Only the outputs numbered starting with "first_output" are + * duplicated in the output part + */ + +output_phase_setup(PLA, first_output) +INOUT pPLA PLA; +int first_output; +{ + pcover F, R, D; + pcube mask, mask1, last; + int first_part, offset; + bool save; + register pcube p, pr, pf; + register int i, last_part; + + if (cube.output == -1) + fatal("output_phase_setup: must have an output"); + + F = PLA->F; + D = PLA->D; + R = PLA->R; + first_part = cube.first_part[cube.output] + first_output; + last_part = cube.last_part[cube.output]; + offset = cube.part_size[cube.output] - first_output; + + /* Change the output size, setup the cube structure */ + setdown_cube(); + cube.part_size[cube.output] += offset; + cube_setup(); + + /* Create a mask to select that part of the cube which isn't changing */ + mask = set_save(cube.fullset); + for(i = first_part; i < cube.size; i++) + set_remove(mask, i); + mask1 = set_save(mask); + for(i = cube.first_part[cube.output]; i < first_part; i++) { + set_remove(mask1, i); + } + + PLA->F = new_cover(F->count + R->count); + PLA->R = new_cover(F->count + R->count); + PLA->D = new_cover(D->count); + + foreach_set(F, last, p) { + pf = GETSET(PLA->F, (PLA->F)->count++); + pr = GETSET(PLA->R, (PLA->R)->count++); + INLINEset_and(pf, mask, p); + INLINEset_and(pr, mask1, p); + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + set_insert(pf, i); + save = FALSE; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + save = TRUE, set_insert(pr, i+offset); + if (! save) PLA->R->count--; + } + + foreach_set(R, last, p) { + pf = GETSET(PLA->F, (PLA->F)->count++); + pr = GETSET(PLA->R, (PLA->R)->count++); + INLINEset_and(pf, mask1, p); + INLINEset_and(pr, mask, p); + save = FALSE; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + save = TRUE, set_insert(pf, i+offset); + if (! save) PLA->F->count--; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + set_insert(pr, i); + } + + foreach_set(D, last, p) { + pf = GETSET(PLA->D, (PLA->D)->count++); + INLINEset_and(pf, mask, p); + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) { + set_insert(pf, i); + set_insert(pf, i+offset); + } + } + + free_cover(F); + free_cover(D); + free_cover(R); + set_free(mask); + set_free(mask1); +} + +/* + * set_phase -- given a "cube" which describes which phases of the output + * are to be implemented, compute the appropriate on-set and off-set + */ +pPLA set_phase(PLA) +INOUT pPLA PLA; +{ + pcover F1, R1; + register pcube last, p, outmask; + register pcube temp=cube.temp[0], phase=PLA->phase, phase1=cube.temp[1]; + + outmask = cube.var_mask[cube.num_vars - 1]; + set_diff(phase1, outmask, phase); + set_or(phase1, set_diff(temp, cube.fullset, outmask), phase1); + F1 = new_cover((PLA->F)->count + (PLA->R)->count); + R1 = new_cover((PLA->F)->count + (PLA->R)->count); + + foreach_set(PLA->F, last, p) { + if (! setp_disjoint(set_and(temp, p, phase), outmask)) + set_copy(GETSET(F1, F1->count++), temp); + if (! setp_disjoint(set_and(temp, p, phase1), outmask)) + set_copy(GETSET(R1, R1->count++), temp); + } + foreach_set(PLA->R, last, p) { + if (! setp_disjoint(set_and(temp, p, phase), outmask)) + set_copy(GETSET(R1, R1->count++), temp); + if (! setp_disjoint(set_and(temp, p, phase1), outmask)) + set_copy(GETSET(F1, F1->count++), temp); + } + free_cover(PLA->F); + free_cover(PLA->R); + PLA->F = F1; + PLA->R = R1; + return PLA; +} + +#define POW2(x) (1 << (x)) + +void opoall(PLA, first_output, last_output, opo_strategy) +pPLA PLA; +int first_output, last_output; +int opo_strategy; +{ + pcover F, D, R, best_F, best_D, best_R; + int i, j, ind, num; + pcube bestphase; + + opo_exact = opo_strategy; + + if (PLA->phase != NULL) { + set_free(PLA->phase); + } + + bestphase = set_save(cube.fullset); + best_F = sf_save(PLA->F); + best_D = sf_save(PLA->D); + best_R = sf_save(PLA->R); + + for(i = 0; i < POW2(last_output - first_output + 1); i++) { + + /* save the initial PLA covers */ + F = sf_save(PLA->F); + D = sf_save(PLA->D); + R = sf_save(PLA->R); + + /* compute the phase cube for this iteration */ + PLA->phase = set_save(cube.fullset); + num = i; + for(j = last_output; j >= first_output; j--) { + if (num % 2 == 0) { + ind = cube.first_part[cube.output] + j; + set_remove(PLA->phase, ind); + } + num /= 2; + } + + /* set the phase and minimize */ + (void) set_phase(PLA); + printf("# phase is %s\n", pc1(PLA->phase)); + summary = TRUE; + minimize(PLA); + + /* see if this is the best so far */ + if (PLA->F->count < best_F->count) { + /* save new best solution */ + set_copy(bestphase, PLA->phase); + sf_free(best_F); + sf_free(best_D); + sf_free(best_R); + best_F = PLA->F; + best_D = PLA->D; + best_R = PLA->R; + } else { + /* throw away the solution */ + free_cover(PLA->F); + free_cover(PLA->D); + free_cover(PLA->R); + } + set_free(PLA->phase); + + /* restore the initial PLA covers */ + PLA->F = F; + PLA->D = D; + PLA->R = R; + } + + /* one more minimization to restore the best answer */ + PLA->phase = bestphase; + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = best_F; + PLA->D = best_D; + PLA->R = best_R; +} + +static void minimize(PLA) +pPLA PLA; +{ + if (opo_exact) { + EXEC_S(PLA->F = minimize_exact(PLA->F,PLA->D,PLA->R,1), "EXACT", PLA->F); + } else { + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), "ESPRESSO ",PLA->F); + } +} diff --git a/espresso/pair.c b/espresso/pair.c new file mode 100644 index 0000000..70480a1 --- /dev/null +++ b/espresso/pair.c @@ -0,0 +1,675 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/pair.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "espresso.h" + +void set_pair(PLA) +pPLA PLA; +{ + set_pair1(PLA, TRUE); +} + +void set_pair1(PLA, adjust_labels) +pPLA PLA; +bool adjust_labels; +{ + int i, var, *paired, newvar; + int old_num_vars, old_num_binary_vars, old_size, old_mv_start; + int *new_part_size, new_num_vars, new_num_binary_vars, new_mv_start; + ppair pair = PLA->pair; + char scratch[1000], **oldlabel, *var1, *var1bar, *var2, *var2bar; + + if (adjust_labels) + makeup_labels(PLA); + + /* Check the pair structure for valid entries and see which binary + variables are left unpaired + */ + paired = ALLOC(bool, cube.num_binary_vars); + for(var = 0; var < cube.num_binary_vars; var++) + paired[var] = FALSE; + for(i = 0; i < pair->cnt; i++) + if ((pair->var1[i] > 0 && pair->var1[i] <= cube.num_binary_vars) && + (pair->var2[i] > 0 && pair->var2[i] <= cube.num_binary_vars)) { + paired[pair->var1[i]-1] = TRUE; + paired[pair->var2[i]-1] = TRUE; + } else + fatal("can only pair binary-valued variables"); + + PLA->F = delvar(pairvar(PLA->F, pair), paired); + PLA->R = delvar(pairvar(PLA->R, pair), paired); + PLA->D = delvar(pairvar(PLA->D, pair), paired); + + /* Now painfully adjust the cube size */ + old_size = cube.size; + old_num_vars = cube.num_vars; + old_num_binary_vars = cube.num_binary_vars; + old_mv_start = cube.first_part[cube.num_binary_vars]; + /* Create the new cube.part_size vector and setup the cube structure */ + new_num_binary_vars = 0; + for(var = 0; var < old_num_binary_vars; var++) + new_num_binary_vars += (paired[var] == FALSE); + new_num_vars = new_num_binary_vars + pair->cnt; + new_num_vars += old_num_vars - old_num_binary_vars; + new_part_size = ALLOC(int, new_num_vars); + for(var = 0; var < pair->cnt; var++) + new_part_size[new_num_binary_vars + var] = 4; + for(var = 0; var < old_num_vars - old_num_binary_vars; var++) + new_part_size[new_num_binary_vars + pair->cnt + var] = + cube.part_size[old_num_binary_vars + var]; + setdown_cube(); + FREE(cube.part_size); + cube.num_vars = new_num_vars; + cube.num_binary_vars = new_num_binary_vars; + cube.part_size = new_part_size; + cube_setup(); + + /* hack with the labels to get them correct */ + if (adjust_labels) { + oldlabel = PLA->label; + PLA->label = ALLOC(char *, cube.size); + for(var = 0; var < pair->cnt; var++) { + newvar = cube.num_binary_vars*2 + var*4; + var1 = oldlabel[ (pair->var1[var]-1) * 2 + 1]; + var2 = oldlabel[ (pair->var2[var]-1) * 2 + 1]; + var1bar = oldlabel[ (pair->var1[var]-1) * 2]; + var2bar = oldlabel[ (pair->var2[var]-1) * 2]; + (void) sprintf(scratch, "%s+%s", var1bar, var2bar); + PLA->label[newvar] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1bar, var2); + PLA->label[newvar+1] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1, var2bar); + PLA->label[newvar+2] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1, var2); + PLA->label[newvar+3] = util_strsav(scratch); + } + /* Copy the old labels for the unpaired binary vars */ + i = 0; + for(var = 0; var < old_num_binary_vars; var++) { + if (paired[var] == FALSE) { + PLA->label[2*i] = oldlabel[2*var]; + PLA->label[2*i+1] = oldlabel[2*var+1]; + oldlabel[2*var] = oldlabel[2*var+1] = (char *) NULL; + i++; + } + } + /* Copy the old labels for the remaining unpaired vars */ + new_mv_start = cube.num_binary_vars*2 + pair->cnt*4; + for(i = old_mv_start; i < old_size; i++) { + PLA->label[new_mv_start + i - old_mv_start] = oldlabel[i]; + oldlabel[i] = (char *) NULL; + } + /* free remaining entries in oldlabel */ + for(i = 0; i < old_size; i++) + if (oldlabel[i] != (char *) NULL) + FREE(oldlabel[i]); + FREE(oldlabel); + } + + /* the paired variables should not be sparse (cf. mv_reduce/raise_in)*/ + for(var = 0; var < pair->cnt; var++) + cube.sparse[cube.num_binary_vars + var] = 0; + FREE(paired); +} + +pcover pairvar(A, pair) +pcover A; +ppair pair; +{ + register pcube last, p; + register int val, p1, p2, b1, b0; + int insert_col, pairnum; + + insert_col = cube.first_part[cube.num_vars - 1]; + + /* stretch the cover matrix to make room for the paired variables */ + A = sf_delcol(A, insert_col, -4*pair->cnt); + + /* compute the paired values */ + foreach_set(A, last, p) { + for(pairnum = 0; pairnum < pair->cnt; pairnum++) { + p1 = cube.first_part[pair->var1[pairnum] - 1]; + p2 = cube.first_part[pair->var2[pairnum] - 1]; + b1 = is_in_set(p, p2+1); + b0 = is_in_set(p, p2); + val = insert_col + pairnum * 4; + if (/* a0 */ is_in_set(p, p1)) { + if (b0) + set_insert(p, val + 3); + if (b1) + set_insert(p, val + 2); + } + if (/* a1 */ is_in_set(p, p1+1)) { + if (b0) + set_insert(p, val + 1); + if (b1) + set_insert(p, val); + } + } + } + return A; +} + + +/* delvar -- delete variables from A, minimize the number of column shifts */ +pcover delvar(A, paired) +pcover A; +bool paired[]; +{ + bool run; + int first_run, run_length, var, offset = 0; + + run = FALSE; run_length = 0; + for(var = 0; var < cube.num_binary_vars; var++) + if (paired[var]) + if (run) + run_length += cube.part_size[var]; + else { + run = TRUE; + first_run = cube.first_part[var]; + run_length = cube.part_size[var]; + } + else + if (run) { + A = sf_delcol(A, first_run-offset, run_length); + run = FALSE; + offset += run_length; + } + if (run) + A = sf_delcol(A, first_run-offset, run_length); + return A; +} + +/* + find_optimal_pairing -- find which binary variables should be paired + to maximally reduce the number of terms + + This is essentially the technique outlined by T. Sasao in the + Trans. on Comp., Oct 1984. We estimate the cost of pairing each + pair individually using 1 of 4 strategies: (1) algebraic division + of F by the pair (exactly T. Sasao technique); (2) strong division + of F by the paired variables (using REDUCE/EXPAND/ IRREDUNDANT from + espresso); (3) full minimization using espresso; (4) exact + minimization. These are in order of both increasing accuracy and + increasing difficulty (!) + + Once the n squared pairs have been evaluated, T. Sasao proposes a + graph covering of nodes by disjoint edges. For now, I solve this + problem exhaustively (complexity = (n-1)*(n-3)*...*3*1 for n + variables when n is even). Note that solving this problem exactly + is the same as evaluating the cost function for all possible + pairings. + + n pairs + + 1, 2 1 + 3, 4 3 + 5, 6 15 + 7, 8 105 + 9,10 945 + 11,12 10,395 + 13,14 135,135 + 15,16 2,027,025 + 17,18 34,459,425 + 19,20 654,729,075 +*/ +void find_optimal_pairing(PLA, strategy) +pPLA PLA; +int strategy; +{ + int i, j, **cost_array; + + cost_array = find_pairing_cost(PLA, strategy); + + if (summary) { + printf(" "); + for(i = 0; i < cube.num_binary_vars; i++) + printf("%3d ", i+1); + printf("\n"); + for(i = 0; i < cube.num_binary_vars; i++) { + printf("%3d ", i+1); + for(j = 0; j < cube.num_binary_vars; j++) + printf("%3d ", cost_array[i][j]); + printf("\n"); + } + } + + if (cube.num_binary_vars <= 14) { + PLA->pair = pair_best_cost(cost_array); + } else { + (void) greedy_best_cost(cost_array, &(PLA->pair)); + } + printf("# "); + print_pair(PLA->pair); + + for(i = 0; i < cube.num_binary_vars; i++) + FREE(cost_array[i]); + FREE(cost_array); + + set_pair(PLA); + EXEC_S(PLA->F=espresso(PLA->F,PLA->D,PLA->R),"ESPRESSO ",PLA->F); +} + +int **find_pairing_cost(PLA, strategy) +pPLA PLA; +int strategy; +{ + int var1, var2, **cost_array; + int i, j, xnum_binary_vars, xnum_vars, *xpart_size, cost; + pcover T, Fsave, Dsave, Rsave; + pset mask; +/* char *s;*/ + + /* data is returned in the cost array */ + cost_array = ALLOC(int *, cube.num_binary_vars); + for(i = 0; i < cube.num_binary_vars; i++) + cost_array[i] = ALLOC(int, cube.num_binary_vars); + for(i = 0; i < cube.num_binary_vars; i++) + for(j = 0; j < cube.num_binary_vars; j++) + cost_array[i][j] = 0; + + /* Setup the pair structure for pairing variables together */ + PLA->pair = pair_new(1); + PLA->pair->cnt = 1; + + for(var1 = 0; var1 < cube.num_binary_vars-1; var1++) { + for(var2 = var1+1; var2 < cube.num_binary_vars; var2++) { + /* if anything but simple strategy, perform setup */ + if (strategy > 0) { + /* save the original covers */ + Fsave = sf_save(PLA->F); + Dsave = sf_save(PLA->D); + Rsave = sf_save(PLA->R); + + /* save the original cube structure */ + xnum_binary_vars = cube.num_binary_vars; + xnum_vars = cube.num_vars; + xpart_size = ALLOC(int, cube.num_vars); + for(i = 0; i < cube.num_vars; i++) + xpart_size[i] = cube.part_size[i]; + + /* pair two variables together */ + PLA->pair->var1[0] = var1 + 1; + PLA->pair->var2[0] = var2 + 1; + set_pair1(PLA, /* adjust_labels */ FALSE); + } + + + /* decide how to best estimate worth of this pairing */ + switch(strategy) { + case 3: + /*s = "exact minimization";*/ + PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1); + cost = Fsave->count - PLA->F->count; + break; + case 2: + /*s = "full minimization";*/ + PLA->F = espresso(PLA->F, PLA->D, PLA->R); + cost = Fsave->count - PLA->F->count; + break; + case 1: + /*s = "strong division";*/ + PLA->F = reduce(PLA->F, PLA->D); + PLA->F = expand(PLA->F, PLA->R, FALSE); + PLA->F = irredundant(PLA->F, PLA->D); + cost = Fsave->count - PLA->F->count; + break; + case 0: + /*s = "weak division";*/ + mask = new_cube(); + set_or(mask, cube.var_mask[var1], cube.var_mask[var2]); + T = dist_merge(sf_save(PLA->F), mask); + cost = PLA->F->count - T->count; + sf_free(T); + set_free(mask); + } + + cost_array[var1][var2] = cost; + + if (strategy > 0) { + /* restore the original cube structure -- free the new ones */ + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = xnum_binary_vars; + cube.num_vars = xnum_vars; + cube.part_size = xpart_size; + cube_setup(); + + /* restore the original cover(s) -- free the new ones */ + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = Fsave; + PLA->D = Dsave; + PLA->R = Rsave; + } + } + } + + pair_free(PLA->pair); + PLA->pair = NULL; + return cost_array; +} + +static int best_cost; +static int **cost_array; +static ppair best_pair; +static pset best_phase; +static pPLA global_PLA; +static pcover best_F, best_D, best_R; +static int pair_minim_strategy; + + +print_pair(pair) +ppair pair; +{ + int i; + + printf("pair is"); + for(i = 0; i < pair->cnt; i++) + printf (" (%d %d)", pair->var1[i], pair->var2[i]); + printf("\n"); +} + + +int greedy_best_cost(cost_array_local, pair_p) +int **cost_array_local; +ppair *pair_p; +{ + int i, j, besti, bestj, maxcost, total_cost; + pset cand; + ppair pair; + + pair = pair_new(cube.num_binary_vars); + cand = set_full(cube.num_binary_vars); + total_cost = 0; + + while (set_ord(cand) >= 2) { + maxcost = -1; + for(i = 0; i < cube.num_binary_vars; i++) { + if (is_in_set(cand, i)) { + for(j = i+1; j < cube.num_binary_vars; j++) { + if (is_in_set(cand, j)) { + if (cost_array_local[i][j] > maxcost) { + maxcost = cost_array_local[i][j]; + besti = i; + bestj = j; + } + } + } + } + } + pair->var1[pair->cnt] = besti+1; + pair->var2[pair->cnt] = bestj+1; + pair->cnt++; + set_remove(cand, besti); + set_remove(cand, bestj); + total_cost += maxcost; + } + set_free(cand); + *pair_p = pair; + return total_cost; +} + + +ppair pair_best_cost(cost_array_local) +int **cost_array_local; +{ + ppair pair; + pset candidate; + + best_cost = -1; + best_pair = NULL; + cost_array = cost_array_local; + + pair = pair_new(cube.num_binary_vars); + candidate = set_full(cube.num_binary_vars); + generate_all_pairs(pair, cube.num_binary_vars, candidate, find_best_cost); + pair_free(pair); + set_free(candidate); + return best_pair; +} + + +int find_best_cost(pair) +register ppair pair; +{ + register int i, cost; + + cost = 0; + for(i = 0; i < pair->cnt; i++) + cost += cost_array[pair->var1[i]-1][pair->var2[i]-1]; + if (cost > best_cost) { + best_cost = cost; + best_pair = pair_save(pair, pair->cnt); + } + if ((debug & MINCOV) && trace) { + printf("cost is %d ", cost); + print_pair(pair); + } +} + +/* + pair_all: brute-force approach to try all possible pairings + + pair_strategy is: + 2) for espresso + 3) for minimize_exact + 4) for phase assignment +*/ + +pair_all(PLA, pair_strategy) +pPLA PLA; +int pair_strategy; +{ + ppair pair; + pset candidate; + + global_PLA = PLA; + pair_minim_strategy = pair_strategy; + best_cost = PLA->F->count + 1; + best_pair = NULL; + best_phase = NULL; + best_F = best_D = best_R = NULL; + pair = pair_new(cube.num_binary_vars); + candidate = set_fill(set_new(cube.num_binary_vars), cube.num_binary_vars); + + generate_all_pairs(pair, cube.num_binary_vars, candidate, minimize_pair); + + pair_free(pair); + set_free(candidate); + + PLA->pair = best_pair; + PLA->phase = best_phase; +/* not really necessary + if (phase != NULL) + (void) set_phase(PLA->phase); +*/ + set_pair(PLA); + printf("# "); + print_pair(PLA->pair); + + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = best_F; + PLA->D = best_D; + PLA->R = best_R; +} + + +/* + * minimize_pair -- called as each pair is generated + */ +int minimize_pair(pair) +ppair pair; +{ + pcover Fsave, Dsave, Rsave; + int i, xnum_binary_vars, xnum_vars, *xpart_size; + + /* save the original covers */ + Fsave = sf_save(global_PLA->F); + Dsave = sf_save(global_PLA->D); + Rsave = sf_save(global_PLA->R); + + /* save the original cube structure */ + xnum_binary_vars = cube.num_binary_vars; + xnum_vars = cube.num_vars; + xpart_size = ALLOC(int, cube.num_vars); + for(i = 0; i < cube.num_vars; i++) + xpart_size[i] = cube.part_size[i]; + + /* setup the paired variables */ + global_PLA->pair = pair; + set_pair1(global_PLA, /* adjust_labels */ FALSE); + + /* call the minimizer */ + if (summary) + print_pair(pair); + switch(pair_minim_strategy) { + case 2: + EXEC_S(phase_assignment(global_PLA,0), "OPO ", global_PLA->F); + if (summary) + printf("# phase is %s\n", pc1(global_PLA->phase)); + break; + case 1: + EXEC_S(global_PLA->F = minimize_exact(global_PLA->F, global_PLA->D, + global_PLA->R, 1), "EXACT ", global_PLA->F); + break; + case 0: + EXEC_S(global_PLA->F = espresso(global_PLA->F, global_PLA->D, + global_PLA->R), "ESPRESSO ", global_PLA->F); + break; + default: + break; + } + + /* see if we have a new best solution */ + if (global_PLA->F->count < best_cost) { + best_cost = global_PLA->F->count; + best_pair = pair_save(pair, pair->cnt); + best_phase = global_PLA->phase!=NULL?set_save(global_PLA->phase):NULL; + if (best_F != NULL) sf_free(best_F); + if (best_D != NULL) sf_free(best_D); + if (best_R != NULL) sf_free(best_R); + best_F = sf_save(global_PLA->F); + best_D = sf_save(global_PLA->D); + best_R = sf_save(global_PLA->R); + } + + /* restore the original cube structure -- free the new ones */ + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = xnum_binary_vars; + cube.num_vars = xnum_vars; + cube.part_size = xpart_size; + cube_setup(); + + /* restore the original cover(s) -- free the new ones */ + sf_free(global_PLA->F); + sf_free(global_PLA->D); + sf_free(global_PLA->R); + global_PLA->F = Fsave; + global_PLA->D = Dsave; + global_PLA->R = Rsave; + global_PLA->pair = NULL; + global_PLA->phase = NULL; +} + +generate_all_pairs(pair, n, candidate, action) +ppair pair; +int n; +pset candidate; +int (*action)(); +{ + int i, j; + pset recur_candidate; + ppair recur_pair; + + if (set_ord(candidate) < 2) { + (*action)(pair); + return; + } + + recur_pair = pair_save(pair, n); + recur_candidate = set_save(candidate); + + /* Find first variable still in the candidate set */ + for(i = 0; i < n; i++) + if (is_in_set(candidate, i)) + break; + + /* Try all pairs of i with other variables */ + for(j = i+1; j < n; j++) + if (is_in_set(candidate, j)) { + /* pair (i j) -- remove from candidate set for future pairings */ + set_remove(recur_candidate, i); + set_remove(recur_candidate, j); + + /* add to the pair array */ + recur_pair->var1[recur_pair->cnt] = i+1; + recur_pair->var2[recur_pair->cnt] = j+1; + recur_pair->cnt++; + + /* recur looking for the end ... */ + generate_all_pairs(recur_pair, n, recur_candidate, action); + + /* now break this pair, and restore candidate set */ + recur_pair->cnt--; + set_insert(recur_candidate, i); + set_insert(recur_candidate, j); + } + + /* if odd, generate all pairs which do NOT include i */ + if ((set_ord(candidate) % 2) == 1) { + set_remove(recur_candidate, i); + generate_all_pairs(recur_pair, n, recur_candidate, action); + } + + pair_free(recur_pair); + set_free(recur_candidate); +} + +ppair pair_new(n) +register int n; +{ + register ppair pair1; + + pair1 = ALLOC(pair_t, 1); + pair1->cnt = 0; + pair1->var1 = ALLOC(int, n); + pair1->var2 = ALLOC(int, n); + return pair1; +} + + +ppair pair_save(pair, n) +register ppair pair; +register int n; +{ + register int k; + register ppair pair1; + + pair1 = pair_new(n); + pair1->cnt = pair->cnt; + for(k = 0; k < pair->cnt; k++) { + pair1->var1[k] = pair->var1[k]; + pair1->var2[k] = pair->var2[k]; + } + return pair1; +} + + +int pair_free(pair) +register ppair pair; +{ + FREE(pair->var1); + FREE(pair->var2); + FREE(pair); +} diff --git a/espresso/part.c b/espresso/part.c new file mode 100644 index 0000000..7409e9b --- /dev/null +++ b/espresso/part.c @@ -0,0 +1,122 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/part.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "mincov_int.h" + +static int visit_col(); + +static void +copy_row(A, prow) +register sm_matrix *A; +register sm_row *prow; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(A, p->row_num, p->col_num); + } +} + + +static int +visit_row(A, prow, rows_visited, cols_visited) +sm_matrix *A; +sm_row *prow; +int *rows_visited; +int *cols_visited; +{ + sm_element *p; + sm_col *pcol; + + if (! prow->flag) { + prow->flag = 1; + (*rows_visited)++; + if (*rows_visited == A->nrows) { + return 1; + } + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + if (! pcol->flag) { + if (visit_col(A, pcol, rows_visited, cols_visited)) { + return 1; + } + } + } + } + return 0; +} + + +static int +visit_col(A, pcol, rows_visited, cols_visited) +sm_matrix *A; +sm_col *pcol; +int *rows_visited; +int *cols_visited; +{ + sm_element *p; + sm_row *prow; + + if (! pcol->flag) { + pcol->flag = 1; + (*cols_visited)++; + if (*cols_visited == A->ncols) { + return 1; + } + for(p = pcol->first_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + if (! prow->flag) { + if (visit_row(A, prow, rows_visited, cols_visited)) { + return 1; + } + } + } + } + return 0; +} + +int +sm_block_partition(A, L, R) +sm_matrix *A; +sm_matrix **L, **R; +{ + int cols_visited, rows_visited; + register sm_row *prow; + register sm_col *pcol; + + /* Avoid the trivial case */ + if (A->nrows == 0) { + return 0; + } + + /* Reset the visited flags for each row and column */ + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + prow->flag = 0; + } + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + pcol->flag = 0; + } + + cols_visited = rows_visited = 0; + if (visit_row(A, A->first_row, &rows_visited, &cols_visited)) { + /* we found all of the rows */ + return 0; + } else { + *L = sm_alloc(); + *R = sm_alloc(); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->flag) { + copy_row(*L, prow); + } else { + copy_row(*R, prow); + } + } + return 1; + } +} diff --git a/espresso/pla.5 b/espresso/pla.5 new file mode 100644 index 0000000..942ce4e --- /dev/null +++ b/espresso/pla.5 @@ -0,0 +1,167 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/espresso/pla.5,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:13:58 $ +.\" * +.\" +.TH PLA 5OCTTOOLS 8/23/81 +.SH NAME +pla \- Format for physical description of Programmable Logic Arrays. +.SH SYNOPSIS +.B pla +.SH DESCRIPTION +This format is used by programs which manipulate +plas to describe the physical implementation. +Lines beginning with a `\fB#\fR' are comments and are ignored. +Lines beginning with a `\fB.\fR' contain control +information about the pla. +Currently, the control information is given in the following order: +.nf + \fB.i\fP + \fB.o\fP + \fB.p\fP + and optionally, + \fB.na\fP (the name to be used for the pla) +.fi +.PP +What follows then is a description of the AND and OR planes +of the pla with one line per product term. +Connections in the AND plane are represented with a `\fB1\fR' for +connection to the non-inverted input line and a \fB`0\fR' for +connection to the inverted input line. +No connection to an input line is indicated +with '\fBx\fR', '\fBX\fR', or '\fB-\fR' with '\fB-\fR' being preferred. +Connections in the OR plane are indicated by a '\fB1\fR' with no +connection being indicated +with '\fBx\fR', '\fBX\fR', '\fB0\fR', or '\fB-\fR' with '\fB-\fR' being +preferred. Spaces or tabs may be used freely and are ignored. +.PP +The end of the pla description is indicated with: +.br + \fB.e\fP +.PP +Programs capable of handling split and folded arrays +employ the following format: +.RS +.nf +.nj + + +.B "AND PLANE" +.RS + +Column (1) Contact to input (2) No contact to input + +(1) (2) + 1 \- Normal contacts, no splits or folds + ! _ Split below + ; , Fold to right + : . Split below and fold to right + +.RE +.B "OR PLANE" +.RS + +Column (1) Contact to output (2) No contact to output + +(1) (2) + I ~ Normal contacts, no splits or folds + i = Split below + | ' Fold to right + j " Split below and fold to right + +.RE +.B "ADDITIONAL ELEMENTS" +.RS + + * Input buffer + + Output buffer + D Depletion load associated with product term + N No depletion load associated with product term + +.RE +.ju +.fi +.RE +.PP +Note that +the decoding function of the AND plane is separated +from the specification of its connectivity. +This makes the AND and OR plane specifications identical. +.PP +These programs handle the following more general set of\ \.\c +parameters: +.nf + + \fB.il\fP + \fB.ir\fP + \fB.ol\fP + \fB.or\fP + \fB.p\fP + + \fB.ilt\fP + \fB.ilb\fP + \fB.irt\fP + \fB.irb\fP + \fB.olb\fP + \fB.olt\fP + \fB.orb\fP + \fB.ort\fP + \fB.pl\fP + \fB.pr\fP + +.fi +The first group of parameters must precede the second group. +If there is only one AND or OR plane it is assumed +to be the left one and the companion\ \.\c +parameters may be shortened by dropping their (left,right) +designation character. +.PP +In order to better deal with folded and split PLAs, the +following\ \.\c +parameters are proposed: +.nf + + \fB.ig\fP + \fB.og\fP + \fB.ins\fP + \fB.inf\fP + \fB.ons\fP + \fB.onf\fP + +.fi +.PP +In order to build finite state machines, the following\ \.\c +parameters are proposed: +.nf + + \fB.iltf\fP + \fB.ilbf\fP + \fB.irtf\fP + \fB.irbf\fP + \fB.oltf\fP + \fB.olbf\fP + \fB.ortf\fP + \fB.orbf\fP + + \fB.ilr\fP + \fB.irr\fP + \fB.olrf\fP + \fB.orrf\fP + +.fi +The\ \.\c +XXXf parameters must occur in pairs, with +the\ \.\c +oXXf line first. +Input and output terms must occur on the same side (top, bottom) +of the PLA. +Feedback terms must be given in ascending order. +The re-order\ \.\c +parameters simplify feedback routing. + +.SH "SEE ALSO" +espresso(1OCTTOOLS), espresso(5OCTTOOLS), misII(1OCTTOOLS) diff --git a/espresso/primes.c b/espresso/primes.c new file mode 100644 index 0000000..0b3eaeb --- /dev/null +++ b/espresso/primes.c @@ -0,0 +1,170 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/primes.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "espresso.h" + +static bool primes_consensus_special_cases(); +static pcover primes_consensus_merge(); +static pcover and_with_cofactor(); + + +/* primes_consensus -- generate primes using consensus */ +pcover primes_consensus(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tnew, Tl, Tr; + + if (primes_consensus_special_cases(T, &Tnew) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + Tl = primes_consensus(scofactor(T, cl, best)); + Tr = primes_consensus(scofactor(T, cr, best)); + Tnew = primes_consensus_merge(Tl, Tr, cl, cr); + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + return Tnew; +} + +static bool +primes_consensus_special_cases(T, Tnew) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tnew = new_cover(0); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tnew = sf_addset(new_cover(1), set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + free_cube(p); + + A = primes_consensus(T); + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + *Tnew = A; + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = cubeunlist(T); + *Tnew = sf_contain(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +static pcover +primes_consensus_merge(Tl, Tr, cl, cr) +pcover Tl, Tr; +pcube cl, cr; +{ + register pcube pl, pr, lastl, lastr, pt; + pcover T, Tsave; + + Tl = and_with_cofactor(Tl, cl); + Tr = and_with_cofactor(Tr, cr); + + T = sf_new(500, Tl->sf_size); + pt = T->data; + Tsave = sf_contain(sf_join(Tl, Tr)); + + foreach_set(Tl, lastl, pl) { + foreach_set(Tr, lastr, pr) { + if (cdist01(pl, pr) == 1) { + consensus(pt, pl, pr); + if (++T->count >= T->capacity) { + Tsave = sf_union(Tsave, sf_contain(T)); + T = sf_new(500, Tl->sf_size); + pt = T->data; + } else { + pt += T->wsize; + } + } + } + } + free_cover(Tl); + free_cover(Tr); + + Tsave = sf_union(Tsave, sf_contain(T)); + return Tsave; +} + + +static pcover +and_with_cofactor(A, cof) +pset_family A; +register pset cof; +{ + register pset last, p; + + foreach_set(A, last, p) { + INLINEset_and(p, p, cof); + if (cdist(p, cube.fullset) > 0) { + RESET(p, ACTIVE); + } else { + SET(p, ACTIVE); + } + } + return sf_inactive(A); +} diff --git a/espresso/reduce.c b/espresso/reduce.c new file mode 100644 index 0000000..0d664fa --- /dev/null +++ b/espresso/reduce.c @@ -0,0 +1,258 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/reduce.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +/* + module: reduce.c + purpose: Perform the Espresso-II reduction step + + Reduction is a technique used to explore larger regions of the + optimization space. We replace each cube of F with a smaller + cube while still maintaining a cover of the same logic function. +*/ + +#include "espresso.h" + +static bool toggle = TRUE; + + +/* + reduce -- replace each cube in F with its reduction + + The reduction of a cube is the smallest cube contained in the cube + which can replace the cube in the original cover without changing + the cover. This is equivalent to the super cube of all of the + essential points in the cube. This can be computed directly. + + The problem is that the order in which the cubes are reduced can + greatly affect the final result. We alternate between two ordering + strategies: + + (1) Order the cubes in ascending order of distance from the + largest cube breaking ties by ordering cubes of equal distance + in descending order of size (sort_reduce) + + (2) Order the cubes in descending order of the inner-product of + the cube and the column sums (mini_sort) + + The real workhorse of this section is the routine SCCC which is + used to find the Smallest Cube Containing the Complement of a cover. + Reduction as proposed by Espresso-II takes a cube and computes its + maximal reduction as the intersection between the cube and the + smallest cube containing the complement of (F u D - {c}) cofactored + against c. + + As usual, the unate-recursive paradigm is used to compute SCCC. + The SCCC of a unate cover is trivial to compute, and thus we perform + Shannon Cofactor expansion attempting to drive the cover to be unate + as fast as possible. +*/ + +pcover reduce(F, D) +INOUT pcover F; +IN pcover D; +{ + register pcube last, p, cunder, *FD; + + /* Order the cubes */ + if (use_random_order) + F = random_order(F); + else { + F = toggle ? sort_reduce(F) : mini_sort(F, descend); + toggle = ! toggle; + } + + /* Try to reduce each cube */ + FD = cube2list(F, D); + foreach_set(F, last, p) { + cunder = reduce_cube(FD, p); /* reduce the cube */ + if (setp_equal(cunder, p)) { /* see if it actually did */ + SET(p, ACTIVE); /* cube remains active */ + SET(p, PRIME); /* cube remains prime ? */ + } else { + if (debug & REDUCE) { + printf("REDUCE: %s to %s %s\n", + pc1(p), pc2(cunder), print_time(ptime())); + } + set_copy(p, cunder); /* save reduced version */ + RESET(p, PRIME); /* cube is no longer prime */ + if (setp_empty(cunder)) + RESET(p, ACTIVE); /* if null, kill the cube */ + else + SET(p, ACTIVE); /* cube is active */ + } + free_cube(cunder); + } + free_cubelist(FD); + + /* Delete any cubes of F which reduced to the empty cube */ + return sf_inactive(F); +} + +/* reduce_cube -- find the maximal reduction of a cube */ +pcube reduce_cube(FD, p) +IN pcube *FD, p; +{ + pcube cunder; + + cunder = sccc(cofactor(FD, p)); + return set_and(cunder, cunder, p); +} + + +/* sccc -- find Smallest Cube Containing the Complement of a cover */ +pcube sccc(T) +INOUT pcube *T; /* T will be disposed of */ +{ + pcube r; + register pcube cl, cr; + register int best; + static int sccc_level = 0; + + if (debug & REDUCE1) { + debug_print(T, "SCCC", sccc_level++); + } + + if (sccc_special_cases(T, &r) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, REDUCE1); + r = sccc_merge(sccc(scofactor(T, cl, best)), + sccc(scofactor(T, cr, best)), cl, cr); + free_cubelist(T); + } + + if (debug & REDUCE1) + printf("SCCC[%d]: result is %s\n", --sccc_level, pc1(r)); + return r; +} + + +pcube sccc_merge(left, right, cl, cr) +INOUT register pcube left, right; /* will be disposed of ... */ +INOUT register pcube cl, cr; /* will be disposed of ... */ +{ + INLINEset_and(left, left, cl); + INLINEset_and(right, right, cr); + INLINEset_or(left, left, right); + free_cube(right); + free_cube(cl); + free_cube(cr); + return left; +} + + +/* + sccc_cube -- find the smallest cube containing the complement of a cube + + By DeMorgan's law and the fact that the smallest cube containing a + cover is the "or" of the positional cubes, it is simple to see that + the SCCC is the universe if the cube has more than two active + variables. If there is only a single active variable, then the + SCCC is merely the bitwise complement of the cube in that + variable. A last special case is no active variables, in which + case the SCCC is empty. + + This is "anded" with the incoming cube result. +*/ +pcube sccc_cube(result, p) +register pcube result, p; +{ + register pcube temp=cube.temp[0], mask; + int var; + + if ((var = cactive(p)) >= 0) { + mask = cube.var_mask[var]; + INLINEset_xor(temp, p, mask); + INLINEset_and(result, result, temp); + } + return result; +} + +/* + * sccc_special_cases -- check the special cases for sccc + */ + +bool sccc_special_cases(T, result) +INOUT pcube *T; /* will be disposed if answer is determined */ +OUT pcube *result; /* returned only if answer determined */ +{ + register pcube *T1, p, temp = cube.temp[1], ceil, cof = T[0]; + pcube *A, *B; + + /* empty cover => complement is universe => SCCC is universe */ + if (T[2] == NULL) { + *result = set_save(cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* row of 1's => complement is empty => SCCC is empty */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *result = new_cube(); + free_cubelist(T); + return TRUE; + } + } + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If cover is unate (or single cube), apply simple rules to find SCCCU */ + if (cdata.vars_unate == cdata.vars_active || T[3] == NULL) { + *result = set_save(cube.fullset); + for(T1 = T+2; (p = *T1++) != NULL; ) { + (void) sccc_cube(*result, set_or(temp, p, cof)); + } + free_cubelist(T); + return TRUE; + } + + /* Check for column of 0's (which can be easily factored( */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + *result = sccc_cube(set_save(cube.fullset), ceil); + if (setp_equal(*result, cube.fullset)) { + free_cube(ceil); + } else { + *result = sccc_merge(sccc(cofactor(T,ceil)), + set_save(cube.fullset), ceil, *result); + } + free_cubelist(T); + return TRUE; + } + free_cube(ceil); + + /* Single active column at this point => tautology => SCCC is empty */ + if (cdata.vars_active == 1) { + *result = new_cube(); + free_cubelist(T); + return TRUE; + } + + /* Check for components */ + if (cdata.var_zeros[cdata.best] < CUBELISTSIZE(T)/2) { + if (cubelist_partition(T, &A, &B, debug & REDUCE1) == 0) { + return MAYBE; + } else { + free_cubelist(T); + *result = sccc(A); + ceil = sccc(B); + (void) set_and(*result, *result, ceil); + set_free(ceil); + return TRUE; + } + } + + /* Not much we can do about it */ + return MAYBE; +} diff --git a/espresso/rows.c b/espresso/rows.c new file mode 100644 index 0000000..9d67bf4 --- /dev/null +++ b/espresso/rows.c @@ -0,0 +1,314 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/rows.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:59 $ + * + */ +#include "port.h" +#include "sparse_int.h" + + +/* + * allocate a new row vector + */ +sm_row * +sm_row_alloc() +{ + register sm_row *prow; + +#ifdef FAST_AND_LOOSE + if (sm_row_freelist == NIL(sm_row)) { + prow = ALLOC(sm_row, 1); + } else { + prow = sm_row_freelist; + sm_row_freelist = prow->next_row; + } +#else + prow = ALLOC(sm_row, 1); +#endif + + prow->row_num = 0; + prow->length = 0; + prow->first_col = prow->last_col = NIL(sm_element); + prow->next_row = prow->prev_row = NIL(sm_row); + prow->flag = 0; + prow->user_word = NIL(char); /* for our user ... */ + return prow; +} + + +/* + * free a row vector -- for FAST_AND_LOOSE, this is real cheap for rows; + * however, freeing a column must still walk down the column discarding + * the elements one-by-one; that is the only use for the extra '-DCOLS' + * compile flag ... + */ +void +sm_row_free(prow) +register sm_row *prow; +{ +#if defined(FAST_AND_LOOSE) && ! defined(COLS) + if (prow->first_col != NIL(sm_element)) { + /* Add the linked list of row items to the free list */ + prow->last_col->next_col = sm_element_freelist; + sm_element_freelist = prow->first_col; + } + + /* Add the row to the free list of rows */ + prow->next_row = sm_row_freelist; + sm_row_freelist = prow; +#else + register sm_element *p, *pnext; + + for(p = prow->first_col; p != 0; p = pnext) { + pnext = p->next_col; + sm_element_free(p); + } + FREE(prow); +#endif +} + + +/* + * duplicate an existing row + */ +sm_row * +sm_row_dup(prow) +register sm_row *prow; +{ + register sm_row *pnew; + register sm_element *p; + + pnew = sm_row_alloc(); + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_row_insert(pnew, p->col_num); + } + return pnew; +} + + +/* + * insert an element into a row vector + */ +sm_element * +sm_row_insert(prow, col) +register sm_row *prow; +register int col; +{ + register sm_element *test, *element; + + /* get a new item, save its address */ + sm_element_alloc(element); + test = element; + sorted_insert(sm_element, prow->first_col, prow->last_col, prow->length, + next_col, prev_col, col_num, col, test); + + /* if item was not used, free it */ + if (element != test) { + sm_element_free(element); + } + + /* either way, return the current new value */ + return test; +} + + +/* + * remove an element from a row vector + */ +void +sm_row_remove(prow, col) +register sm_row *prow; +register int col; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0 && p->col_num < col; p = p->next_col) + ; + if (p != 0 && p->col_num == col) { + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + sm_element_free(p); + } +} + + +/* + * find an element (if it is in the row vector) + */ +sm_element * +sm_row_find(prow, col) +sm_row *prow; +int col; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0 && p->col_num < col; p = p->next_col) + ; + if (p != 0 && p->col_num == col) { + return p; + } else { + return NIL(sm_element); + } +} + +/* + * return 1 if row p2 contains row p1; 0 otherwise + */ +int +sm_row_contains(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + while (q1 != 0) { + if (q2 == 0 || q1->col_num < q2->col_num) { + return 0; + } else if (q1->col_num == q2->col_num) { + q1 = q1->next_col; + q2 = q2->next_col; + } else { + q2 = q2->next_col; + } + } + return 1; +} + + +/* + * return 1 if row p1 and row p2 share an element in common + */ +int +sm_row_intersects(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + if (q1 == 0 || q2 == 0) return 0; + for(;;) { + if (q1->col_num < q2->col_num) { + if ((q1 = q1->next_col) == 0) { + return 0; + } + } else if (q1->col_num > q2->col_num) { + if ((q2 = q2->next_col) == 0) { + return 0; + } + } else { + return 1; + } + } +} + + +/* + * compare two rows, lexical ordering + */ +int +sm_row_compare(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + while(q1 != 0 && q2 != 0) { + if (q1->col_num != q2->col_num) { + return q1->col_num - q2->col_num; + } + q1 = q1->next_col; + q2 = q2->next_col; + } + + if (q1 != 0) { + return 1; + } else if (q2 != 0) { + return -1; + } else { + return 0; + } +} + + +/* + * return the intersection + */ +sm_row * +sm_row_and(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + register sm_row *result; + + result = sm_row_alloc(); + q1 = p1->first_col; + q2 = p2->first_col; + if (q1 == 0 || q2 == 0) return result; + for(;;) { + if (q1->col_num < q2->col_num) { + if ((q1 = q1->next_col) == 0) { + return result; + } + } else if (q1->col_num > q2->col_num) { + if ((q2 = q2->next_col) == 0) { + return result; + } + } else { + (void) sm_row_insert(result, q1->col_num); + if ((q1 = q1->next_col) == 0) { + return result; + } + if ((q2 = q2->next_col) == 0) { + return result; + } + } + } +} + +int +sm_row_hash(prow, modulus) +sm_row *prow; +int modulus; +{ + register int sum; + register sm_element *p; + + sum = 0; + for(p = prow->first_col; p != 0; p = p->next_col) { + sum = (sum*17 + p->col_num) % modulus; + } + return sum; +} + +/* + * remove an element from a row vector (given a pointer to the element) + */ +void +sm_row_remove_element(prow, p) +register sm_row *prow; +register sm_element *p; +{ + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + sm_element_free(p); +} + + +void +sm_row_print(fp, prow) +FILE *fp; +sm_row *prow; +{ + sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) fprintf(fp, " %d", p->col_num); + } +} diff --git a/espresso/set.c b/espresso/set.c new file mode 100644 index 0000000..aec3d35 --- /dev/null +++ b/espresso/set.c @@ -0,0 +1,820 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/set.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +/* + * set.c -- routines for maniuplating sets and set families + */ + +/* LINTLIBRARY */ + +#include "espresso.h" +static pset_family set_family_garbage = NULL; + +static int intcpy(d, s, n) +register unsigned int *d, *s; +register long n; +{ + register int i; + for(i = 0; i < n; i++) { + *d++ = *s++; + } +} + + +/* bit_index -- find first bit (from LSB) in a word (MSB=bit n, LSB=bit 0) */ +int bit_index(a) +register unsigned int a; +{ + register int i; + if (a == 0) + return -1; + for(i = 0; (a & 1) == 0; a >>= 1, i++) + ; + return i; +} + + +/* set_ord -- count number of elements in a set */ +int set_ord(a) +register pset a; +{ + register int i, sum = 0; + register unsigned int val; + for(i = LOOP(a); i > 0; i--) + if ((val = a[i]) != 0) + sum += count_ones(val); + return sum; +} + +/* set_dist -- distance between two sets (# elements in common) */ +int set_dist(a, b) +register pset a, b; +{ + register int i, sum = 0; + register unsigned int val; + for(i = LOOP(a); i > 0; i--) + if ((val = a[i] & b[i]) != 0) + sum += count_ones(val); + return sum; +} + +/* set_clear -- make "r" the empty set of "size" elements */ +pset set_clear(r, size) +register pset r; +int size; +{ + register int i = LOOPINIT(size); + *r = i; do r[i] = 0; while (--i > 0); + return r; +} + +/* set_fill -- make "r" the universal set of "size" elements */ +pset set_fill(r, size) +register pset r; +register int size; +{ + register int i = LOOPINIT(size); + *r = i; + r[i] = ~ (unsigned) 0; + r[i] >>= i * BPI - size; + while (--i > 0) + r[i] = ~ (unsigned) 0; + return r; +} + +/* set_copy -- copy set a into set r */ +pset set_copy(r, a) +register pset r, a; +{ + register int i = LOOPCOPY(a); + do r[i] = a[i]; while (--i >= 0); + return r; +} + +/* set_and -- compute intersection of sets "a" and "b" */ +pset set_and(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] & b[i]; while (--i > 0); + return r; +} + +/* set_or -- compute union of sets "a" and "b" */ +pset set_or(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] | b[i]; while (--i > 0); + return r; +} + +/* set_diff -- compute difference of sets "a" and "b" */ +pset set_diff(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] & ~b[i]; while (--i > 0); + return r; +} + +/* set_xor -- compute exclusive-or of sets "a" and "b" */ +pset set_xor(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); +#ifdef IBM_WATC + PUTLOOP(r,i); do r[i] = (a[i]&~b[i]) | (~a[i]&b[i]); while (--i > 0); +#else + PUTLOOP(r,i); do r[i] = a[i] ^ b[i]; while (--i > 0); +#endif + return r; +} + +/* set_merge -- compute "a" & "mask" | "b" & ~ "mask" */ +pset set_merge(r, a, b, mask) +register pset r, a, b, mask; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = (a[i]&mask[i]) | (b[i]&~mask[i]); while (--i > 0); + return r; +} + +/* set_andp -- compute intersection of sets "a" and "b" , TRUE if nonempty */ +bool set_andp(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + register unsigned int x = 0; + PUTLOOP(r,i); do {r[i] = a[i] & b[i]; x |= r[i];} while (--i > 0); + return x != 0; +} + +/* set_orp -- compute union of sets "a" and "b" , TRUE if nonempty */ +bool set_orp(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + register unsigned int x = 0; + PUTLOOP(r,i); do {r[i] = a[i] | b[i]; x |= r[i];} while (--i > 0); + return x != 0; +} + +/* setp_empty -- check if the set "a" is empty */ +bool setp_empty(a) +register pset a; +{ + register int i = LOOP(a); + do if (a[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_full -- check if the set "a" is the full set of "size" elements */ +bool setp_full(a, size) +register pset a; +register int size; +{ + register int i = LOOP(a); + register unsigned int test; + test = ~ (unsigned) 0; + test >>= i * BPI - size; + if (a[i] != test) + return FALSE; + while (--i > 0) + if (a[i] != (~(unsigned) 0)) + return FALSE; + return TRUE; +} + +/* setp_equal -- check if the set "a" equals set "b" */ +bool setp_equal(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] != b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_disjoint -- check if intersection of "a" and "b" is empty */ +bool setp_disjoint(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] & b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_implies -- check if "a" implies "b" ("b" contains "a") */ +bool setp_implies(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] & ~b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* sf_or -- form the "or" of all sets in a set family */ +pset sf_or(A) +pset_family A; +{ + register pset or, last, p; + + or = set_new(A->sf_size); + foreach_set(A, last, p) + INLINEset_or(or, or, p); + return or; +} + +/* sf_and -- form the "and" of all sets in a set family */ +pset sf_and(A) +pset_family A; +{ + register pset and, last, p; + + and = set_fill(set_new(A->sf_size), A->sf_size); + foreach_set(A, last, p) + INLINEset_and(and, and, p); + return and; +} + +/* sf_active -- make all members of the set family active */ +pset_family sf_active(A) +pset_family A; +{ + register pset p, last; + foreach_set(A, last, p) { + SET(p, ACTIVE); + } + A->active_count = A->count; + return A; +} + + +/* sf_inactive -- remove all inactive cubes in a set family */ +pset_family sf_inactive(A) +pset_family A; +{ + register pset p, last, pdest; + + pdest = A->data; + foreach_set(A, last, p) { + if (TESTP(p, ACTIVE)) { + if (pdest != p) { + INLINEset_copy(pdest, p); + } + pdest += A->wsize; + } else { + A->count--; + } + } + return A; +} + + +/* sf_copy -- copy a set family */ +pset_family sf_copy(R, A) +pset_family R, A; +{ + R->sf_size = A->sf_size; + R->wsize = A->wsize; +/*R->capacity = A->count;*/ +/*R->data = REALLOC(unsigned int, R->data, (long) R->capacity * R->wsize);*/ + R->count = A->count; + R->active_count = A->active_count; + intcpy(R->data, A->data, (long) A->wsize * A->count); + return R; +} + + +/* sf_join -- join A and B into a single set_family */ +pset_family sf_join(A, B) +pset_family A, B; +{ + pset_family R; + long asize = A->count * A->wsize; + long bsize = B->count * B->wsize; + + if (A->sf_size != B->sf_size) fatal("sf_join: sf_size mismatch"); + R = sf_new(A->count + B->count, A->sf_size); + R->count = A->count + B->count; + R->active_count = A->active_count + B->active_count; + intcpy(R->data, A->data, asize); + intcpy(R->data + asize, B->data, bsize); + return R; +} + + +/* sf_append -- append the sets of B to the end of A, and dispose of B */ +pset_family sf_append(A, B) +pset_family A, B; +{ + long asize = A->count * A->wsize; + long bsize = B->count * B->wsize; + + if (A->sf_size != B->sf_size) fatal("sf_append: sf_size mismatch"); + A->capacity = A->count + B->count; + A->data = REALLOC(unsigned int, A->data, (long) A->capacity * A->wsize); + intcpy(A->data + asize, B->data, bsize); + A->count += B->count; + A->active_count += B->active_count; + sf_free(B); + return A; +} + + +/* sf_new -- allocate "num" sets of "size" elements each */ +pset_family sf_new(num, size) +int num, size; +{ + pset_family A; + if (set_family_garbage == NULL) { + A = ALLOC(set_family_t, 1); + } else { + A = set_family_garbage; + set_family_garbage = A->next; + } + A->sf_size = size; + A->wsize = SET_SIZE(size); + A->capacity = num; + A->data = ALLOC(unsigned int, (long) A->capacity * A->wsize); + A->count = 0; + A->active_count = 0; + return A; +} + + +/* sf_save -- create a duplicate copy of a set family */ +pset_family sf_save(A) +register pset_family A; +{ + return sf_copy(sf_new(A->count, A->sf_size), A); +} + + +/* sf_free -- free the storage allocated for a set family */ +void sf_free(A) +pset_family A; +{ + FREE(A->data); + A->next = set_family_garbage; + set_family_garbage = A; +} + + +/* sf_cleanup -- free all of the set families from the garbage list */ +void sf_cleanup() +{ + register pset_family p, pnext; + for(p = set_family_garbage; p != (pset_family) NULL; p = pnext) { + pnext = p->next; + FREE(p); + } + set_family_garbage = (pset_family) NULL; +} + + +/* sf_addset -- add a set to the end of a set family */ +pset_family sf_addset(A, s) +pset_family A; +pset s; +{ + register pset p; + + if (A->count >= A->capacity) { + A->capacity = A->capacity + A->capacity/2 + 1; + A->data = REALLOC(unsigned int, A->data, (long) A->capacity * A->wsize); + } + p = GETSET(A, A->count++); + INLINEset_copy(p, s); + return A; +} + +/* sf_delset -- delete a set from a set family */ +void sf_delset(A, i) +pset_family A; +int i; +{ (void) set_copy(GETSET(A,i), GETSET(A, --A->count));} + +/* sf_print -- print a set_family as a set (list the element numbers) */ +void sf_print(A) +pset_family A; +{ + char *ps1(); + register pset p; + register int i; + foreachi_set(A, i, p) + printf("A[%d] = %s\n", i, ps1(p)); +} + +/* sf_bm_print -- print a set_family as a bit-matrix */ +void sf_bm_print(A) +pset_family A; +{ + char *pbv1(); + register pset p; + register int i; + foreachi_set(A, i, p) + printf("[%4d] %s\n", i, pbv1(p, A->sf_size)); +} + + +/* sf_write -- output a set family in an unintelligable manner */ +void sf_write(fp, A) +FILE *fp; +pset_family A; +{ + register pset p, last; + (void) fprintf(fp, "%d %d\n", A->count, A->sf_size); + foreach_set(A, last, p) + set_write(fp, p); + (void) fflush(fp); +} + + +/* sf_read -- read a set family written by sf_write */ +pset_family sf_read(fp) +FILE *fp; +{ + int i, j; + register pset p, last; + pset_family A; + + (void) fscanf(fp, "%d %d\n", &i, &j); + A = sf_new(i, j); + A->count = i; + foreach_set(A, last, p) { + (void) fscanf(fp, "%x", p); + for(j = 1; j <= LOOP(p); j++) + (void) fscanf(fp, "%x", p+j); + } + return A; +} + + +/* set_write -- output a set in an unintelligable manner */ +void set_write(fp, a) +register FILE *fp; +register pset a; +{ + register int n = LOOP(a), j; + + for(j = 0; j <= n; j++) { + (void) fprintf(fp, "%x ", a[j]); + if ((j+1) % 8 == 0 && j != n) + (void) fprintf(fp, "\n\t"); + } + (void) fprintf(fp, "\n"); +} + + +/* sf_bm_read -- read a set family written by sf_bm_print (almost) */ +pset_family sf_bm_read(fp) +FILE *fp; +{ + int i, j, rows, cols; + register pset pdest; + pset_family A; + + (void) fscanf(fp, "%d %d\n", &rows, &cols); + A = sf_new(rows, cols); + for(i = 0; i < rows; i++) { + pdest = GETSET(A, A->count++); + (void) set_clear(pdest, A->sf_size); + for(j = 0; j < cols; j++) { + switch(getc(fp)) { + case '0': + break; + case '1': + set_insert(pdest, j); + break; + default: + fatal("Error reading set family"); + } + } + if (getc(fp) != '\n') { + fatal("Error reading set family (at end of line)"); + } + } + return A; +} + + + +/* ps1 -- convert a set into a printable string */ +#define largest_string 120 +static char s1[largest_string]; +char *ps1(a) +register pset a; +{ + register int i, num, l, len = 0, n = NELEM(a); + char temp[20]; + bool first = TRUE; + + s1[len++] = '['; + for(i = 0; i < n; i++) + if (is_in_set(a,i)) { + if (! first) + s1[len++] = ','; + first = FALSE; num = i; + /* Generate digits (reverse order) */ + l = 0; do temp[l++] = num % 10 + '0'; while ((num /= 10) > 0); + /* Copy them back in correct order */ + do s1[len++] = temp[--l]; while (l > 0); + if (len > largest_string-15) { + s1[len++] = '.'; s1[len++] = '.'; s1[len++] = '.'; + break; + } + } + + s1[len++] = ']'; + s1[len++] = '\0'; + return s1; +} + +/* pbv1 -- print bit-vector */ +char *pbv1(s, n) +pset s; +int n; +{ + register int i; + for(i = 0; i < n; i++) + s1[i] = is_in_set(s,i) ? '1' : '0'; + s1[n] = '\0'; + return s1; +} + + +/* set_adjcnt -- adjust the counts for a set by "weight" */ +void +set_adjcnt(a, count, weight) +register pset a; +register int *count, weight; +{ + register int i, base; + register unsigned int val; + + for(i = LOOP(a); i > 0; ) { + for(val = a[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) { + if (val & 1) { + count[base] += weight; + } + } + } +} + + + +/* sf_count -- perform a column sum over a set family */ +int *sf_count(A) +pset_family A; +{ + register pset p, last; + register int i, base, *count; + register unsigned int val; + + count = ALLOC(int, A->sf_size); + for(i = A->sf_size - 1; i >= 0; i--) { + count[i] = 0; + } + + foreach_set(A, last, p) { + for(i = LOOP(p); i > 0; ) { + for(val = p[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) { + if (val & 1) { + count[base]++; + } + } + } + } + return count; +} + + +/* sf_count_restricted -- perform a column sum over a set family, restricting + * to only the columns which are in r; also, the columns are weighted by the + * number of elements which are in each row + */ +int *sf_count_restricted(A, r) +pset_family A; +register pset r; +{ + register pset p; + register int i, base, *count; + register unsigned int val; + int weight; + pset last; + + count = ALLOC(int, A->sf_size); + for(i = A->sf_size - 1; i >= 0; i--) { + count[i] = 0; + } + + /* Loop for each set */ + foreach_set(A, last, p) { + weight = 1024 / (set_ord(p) - 1); + for(i = LOOP(p); i > 0; ) { + for(val=p[i]&r[i], base= --i<>= 1) { + if (val & 1) { + count[base] += weight; + } + } + } + } + return count; +} + + +/* + * sf_delc -- delete columns first ... last of A + */ +pset_family sf_delc(A, first, last) +pset_family A; +int first, last; +{ + return sf_delcol(A, first, last-first + 1); +} + + +/* + * sf_addcol -- add columns to a set family; includes a quick check to see + * if there is already enough room (and hence, can avoid copying) + */ +pset_family sf_addcol(A, firstcol, n) +pset_family A; +int firstcol, n; +{ + int maxsize; + + /* Check if adding columns at the end ... */ + if (firstcol == A->sf_size) { + /* If so, check if there is already enough room */ + maxsize = BPI * LOOPINIT(A->sf_size); + if ((A->sf_size + n) <= maxsize) { + A->sf_size += n; + return A; + } + } + return sf_delcol(A, firstcol, -n); +} + +/* + * sf_delcol -- add/delete columns to/from a set family + * + * if n > 0 then n columns starting from firstcol are deleted if n < 0 + * then n blank columns are inserted starting at firstcol + * (i.e., the first new column number is firstcol) + * + * This is done by copying columns in the array which is a relatively + * slow operation. + */ +pset_family sf_delcol(A, firstcol, n) +pset_family A; +register int firstcol, n; +{ + register pset p, last, pdest; + register int i; + pset_family B; + + B = sf_new(A->count, A->sf_size - n); + foreach_set(A, last, p) { + pdest = GETSET(B, B->count++); + INLINEset_clear(pdest, B->sf_size); + for(i = 0; i < firstcol; i++) + if (is_in_set(p, i)) + set_insert(pdest, i); + for(i = n > 0 ? firstcol + n : firstcol; i < A->sf_size; i++) + if (is_in_set(p, i)) + set_insert(pdest, i - n); + } + sf_free(A); + return B; +} + + +/* + * sf_copy_col -- copy column "srccol" from "src" to column "dstcol" of "dst" + */ +pset_family sf_copy_col(dst, dstcol, src, srccol) +pset_family dst, src; +int dstcol, srccol; +{ + register pset last, p, pdest; + register int word_test, word_set; + unsigned int bit_set, bit_test; + + /* CHEAT! form these constants outside the loop */ + word_test = WHICH_WORD(srccol); + bit_test = 1 << WHICH_BIT(srccol); + word_set = WHICH_WORD(dstcol); + bit_set = 1 << WHICH_BIT(dstcol); + + pdest = dst->data; + foreach_set(src, last, p) { + if ((p[word_test] & bit_test) != 0) + pdest[word_set] |= bit_set; +/* + * equivalent code for this is ... + * if (is_in_set(p, srccol)) set_insert(pdest, destcol); + */ + pdest += dst->wsize; + } + return dst; +} + + + +/* + * sf_compress -- delete columns from a matrix + */ +pset_family sf_compress(A, c) +pset_family A; /* will be freed */ +register pset c; +{ + register pset p; + register int i, bcol; + pset_family B; + + /* create a clean set family for the result */ + B = sf_new(A->count, set_ord(c)); + for(i = 0; i < A->count; i++) { + p = GETSET(B, B->count++); + INLINEset_clear(p, B->sf_size); + } + + /* copy each column of A which has a 1 in c */ + bcol = 0; + for(i = 0; i < A->sf_size; i++) { + if (is_in_set(c, i)) { + (void) sf_copy_col(B, bcol++, A, i); + } + } + sf_free(A); + return B; +} + + + +/* + * sf_transpose -- transpose a bit matrix + * + * There are trickier ways of doing this, but this works. + */ +pset_family sf_transpose(A) +pset_family A; +{ + pset_family B; + register pset p; + register int i, j; + + B = sf_new(A->sf_size, A->count); + B->count = A->sf_size; + foreachi_set(B, i, p) { + INLINEset_clear(p, B->sf_size); + } + foreachi_set(A, i, p) { + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(p, j)) { + set_insert(GETSET(B, j), i); + } + } + } + sf_free(A); + return B; +} + + +/* + * sf_permute -- permute the columns of a set_family + * + * permute is an array of integers containing column numbers of A which + * are to be retained. + */ +pset_family sf_permute(A, permute, npermute) +pset_family A; +register int *permute, npermute; +{ + pset_family B; + register pset p, last, pdest; + register int j; + + B = sf_new(A->count, npermute); + B->count = A->count; + foreach_set(B, last, p) + INLINEset_clear(p, npermute); + + pdest = B->data; + foreach_set(A, last, p) { + for(j = 0; j < npermute; j++) + if (is_in_set(p, permute[j])) + set_insert(pdest, j); + pdest += B->wsize; + } + sf_free(A); + return B; +} diff --git a/espresso/setc.c b/espresso/setc.c new file mode 100644 index 0000000..9bfcab7 --- /dev/null +++ b/espresso/setc.c @@ -0,0 +1,483 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/setc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +/* + setc.c -- massive bit-hacking for performing special "cube"-type + operations on a set + + The basic trick used for binary valued variables is the following: + + If a[w] and b[w] contain a full word of binary variables, then: + + 1) to get the full word of their intersection, we use + + x = a[w] & b[w]; + + + 2) to see if the intersection is null in any variables, we examine + + x = ~(x | x >> 1) & DISJOINT; + + this will have a single 1 in each binary variable for which + the intersection is null. In particular, if this is zero, + then there are no disjoint variables; or, if this is nonzero, + then there is at least one disjoint variable. A "count_ones" + over x will tell in how many variables they have an null + intersection. + + + 3) to get a mask which selects the disjoint variables, we use + + (x | x << 1) + + this provides a selector which can be used to see where + they have an null intersection + + + cdist return distance between two cubes + cdist0 return true if two cubes are distance 0 apart + cdist01 return distance, or 2 if distance exceeds 1 + consensus compute consensus of two cubes distance 1 apart + force_lower expand hack (for now), related to consensus +*/ + +#include "espresso.h" + +/* see if the cube has a full row of 1's (with respect to cof) */ +bool full_row(p, cof) +IN register pcube p, cof; +{ + register int i = LOOP(p); + do if ((p[i] | cof[i]) != cube.fullset[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* + cdist0 -- return TRUE if a and b are distance 0 apart +*/ + +bool cdist0(a, b) +register pcube a, b; +{ + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (~(x | x >> 1) & cube.inmask) + return FALSE; /* disjoint in some variable */ + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (~(x | x >> 1) & DISJOINT) + return FALSE; /* disjoint in some variable */ + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + return FALSE; /* disjoint in this variable */ + nextvar: ; + } + } + return TRUE; +} + +/* + cdist01 -- return the "distance" between two cubes (defined as the + number of null variables in their intersection). If the distance + exceeds 1, the value 2 is returned. +*/ + +int cdist01(a, b) +register pset a, b; +{ + int dist = 0; + + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~ (x | x >> 1) & cube.inmask) + if ((dist = count_ones(x)) > 1) + return 2; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~ (x | x >> 1) & DISJOINT) + if (dist == 1 || (dist += count_ones(x)) > 1) + return 2; + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + if (++dist > 1) + return 2; + nextvar: ; + } + } + return dist; +} + +/* + cdist -- return the "distance" between two cubes (defined as the + number of null variables in their intersection). +*/ + +int cdist(a, b) +register pset a, b; +{ + int dist = 0; + + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~ (x | x >> 1) & cube.inmask) + dist = count_ones(x); + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~ (x | x >> 1) & DISJOINT) + dist += count_ones(x); + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + dist++; + nextvar: ; + } + } + return dist; +} + +/* + force_lower -- Determine which variables of a do not intersect b. +*/ + +pset force_lower(xlower, a, b) +INOUT pset xlower; +IN register pset a, b; +{ + + { /* Check binary variables (if any) */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~(x | x >> 1) & cube.inmask) + xlower[last] |= (x | (x << 1)) & a[last]; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~(x | x >> 1) & DISJOINT) + xlower[w] |= (x | (x << 1)) & a[w]; + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + for(w = cube.first_word[var]; w <= last; w++) + xlower[w] |= a[w] & mask[w]; + nextvar: ; + } + } + return xlower; +} + +/* + consensus -- multiple-valued consensus + + Although this looks very messy, the idea is to compute for r the + "and" of the cubes a and b for each variable, unless the "and" is + null in a variable, in which case the "or" of a and b is computed + for this variable. + + Because we don't check how many variables are null in the + intersection of a and b, the returned value for r really only + represents the consensus when a and b are distance 1 apart. +*/ + +void consensus(r, a, b) +INOUT pcube r; +IN register pcube a, b; +{ + INLINEset_clear(r, cube.size); + + { /* Check binary variables (if any) */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + r[last] = x = a[last] & b[last]; + if (x = ~(x | x >> 1) & cube.inmask) + r[last] |= (x | (x << 1)) & (a[last] | b[last]); + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + r[w] = x = a[w] & b[w]; + if (x = ~(x | x >> 1) & DISJOINT) + r[w] |= (x | (x << 1)) & (a[w] | b[w]); + } + } + } + + + { /* Check the multiple-valued variables */ + bool empty; int var; unsigned int x; + register int w, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + last = cube.last_word[var]; + empty = TRUE; + for(w = cube.first_word[var]; w <= last; w++) + if (x = a[w] & b[w] & mask[w]) + empty = FALSE, r[w] |= x; + if (empty) + for(w = cube.first_word[var]; w <= last; w++) + r[w] |= mask[w] & (a[w] | b[w]); + } + } +} + +/* + cactive -- return the index of the single active variable in + the cube, or return -1 if there are none or more than 2. +*/ + +int cactive(a) +register pcube a; +{ + int active = -1, dist = 0, bit_index(); + + { /* Check binary variables */ + register int w, last; + register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last]; + if (x = ~ (x & x >> 1) & cube.inmask) { + if ((dist = count_ones(x)) > 1) + return -1; /* more than 2 active variables */ + active = (last-1)*(BPI/2) + bit_index(x) / 2; + } + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w]; + if (x = ~ (x & x >> 1) & DISJOINT) { + if ((dist += count_ones(x)) > 1) + return -1; /* more than 2 active variables */ + active = (w-1)*(BPI/2) + bit_index(x) / 2; + } + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; + register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~ a[w]) { + if (++dist > 1) + return -1; + active = var; + break; + } + } + } + return active; +} + +/* + ccommon -- return TRUE if a and b are share "active" variables + active variables include variables that are empty; +*/ + +bool ccommon(a, b, cof) +register pcube a, b, cof; +{ + { /* Check binary variables */ + int last; + register int w; + register unsigned int x, y; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] | cof[last]; + y = b[last] | cof[last]; + if (~(x & x>>1) & ~(y & y>>1) & cube.inmask) + return TRUE; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] | cof[w]; + y = b[w] | cof[w]; + if (~(x & x>>1) & ~(y & y>>1) & DISJOINT) + return TRUE; + } + } + } + + { /* Check the multiple-valued variables */ + int var; + register int w, last; + register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + /* Check for some part missing from a */ + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~a[w] & ~cof[w]) { + + /* If so, check for some part missing from b */ + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~b[w] & ~cof[w]) + return TRUE; /* both active */ + break; + } + } + } + return FALSE; +} + +/* + These routines compare two sets (cubes) for the qsort() routine and + return: + + -1 if set a is to precede set b + 0 if set a and set b are equal + 1 if set a is to follow set b + + Usually the SIZE field of the set is assumed to contain the size + of the set (which will save recomputing the set size during the + sort). For distance-1 merging, the global variable cube.temp[0] is + a mask which mask's-out the merging variable. +*/ + +/* descend -- comparison for descending sort on set size */ +int descend(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + if (SIZE(a1) > SIZE(b1)) return -1; + else if (SIZE(a1) < SIZE(b1)) return 1; + else { + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return -1; else if (a1[i] < b1[i]) return 1; + while (--i > 0); + } + return 0; +} + +/* ascend -- comparison for ascending sort on set size */ +int ascend(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + if (SIZE(a1) > SIZE(b1)) return 1; + else if (SIZE(a1) < SIZE(b1)) return -1; + else { + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return 1; else if (a1[i] < b1[i]) return -1; + while (--i > 0); + } + return 0; +} + + +/* lex_order -- comparison for "lexical" ordering of cubes */ +int lex_order(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return -1; else if (a1[i] < b1[i]) return 1; + while (--i > 0); + return 0; +} + + +/* d1_order -- comparison for distance-1 merge routine */ +int d1_order(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b, c1 = cube.temp[0]; + register int i = LOOP(a1); + register unsigned int x1, x2; + do + if ((x1 = a1[i] | c1[i]) > (x2 = b1[i] | c1[i])) return -1; + else if (x1 < x2) return 1; + while (--i > 0); + return 0; +} + + +/* desc1 -- comparison (without indirection) for descending sort */ +/* also has effect of handling NULL pointers,and a NULL pointer has smallest +order */ +int desc1(a, b) +register pset a, b; +{ + if (a == (pset) NULL) + return (b == (pset) NULL) ? 0 : 1; + else if (b == (pset) NULL) + return -1; + if (SIZE(a) > SIZE(b)) return -1; + else if (SIZE(a) < SIZE(b)) return 1; + else { + register int i = LOOP(a); + do + if (a[i] > b[i]) return -1; else if (a[i] < b[i]) return 1; + while (--i > 0); + } + return 0; +} diff --git a/espresso/sharp.c b/espresso/sharp.c new file mode 100644 index 0000000..e1eed94 --- /dev/null +++ b/espresso/sharp.c @@ -0,0 +1,247 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/sharp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +/* + sharp.c -- perform sharp, disjoint sharp, and intersection +*/ + +#include "espresso.h" + +long start_time; + + +/* cv_sharp -- form the sharp product between two covers */ +pcover cv_sharp(A, B) +pcover A, B; +{ + pcube last, p; + pcover T; + + T = new_cover(0); + foreach_set(A, last, p) + T = sf_union(T, cb_sharp(p, B)); + return T; +} + + +/* cb_sharp -- form the sharp product between a cube and a cover */ +pcover cb_sharp(c, T) +pcube c; +pcover T; +{ + if (T->count == 0) { + T = sf_addset(new_cover(1), c); + } else { + start_time = ptime(); + T = cb_recur_sharp(c, T, 0, T->count-1, 0); + } + return T; +} + + +/* recursive formulation to provide balanced merging */ +pcover cb_recur_sharp(c, T, first, last, level) +pcube c; +pcover T; +int first, last, level; +{ + pcover temp, left, right; + int middle; + + if (first == last) { + temp = sharp(c, GETSET(T, first)); + } else { + middle = (first + last) / 2; + left = cb_recur_sharp(c, T, first, middle, level+1); + right = cb_recur_sharp(c, T, middle+1, last, level+1); + temp = cv_intersect(left, right); + if ((debug & SHARP) && level < 4) { + printf("# SHARP[%d]: %4d = %4d x %4d, time = %s\n", + level, temp->count, left->count, right->count, + print_time(ptime() - start_time)); + (void) fflush(stdout); + } + free_cover(left); + free_cover(right); + } + return temp; +} + + +/* sharp -- form the sharp product between two cubes */ +pcover sharp(a, b) +pcube a, b; +{ + register int var; + register pcube d=cube.temp[0], temp=cube.temp[1], temp1=cube.temp[2]; + pcover r = new_cover(cube.num_vars); + + if (cdist0(a, b)) { + set_diff(d, a, b); + for(var = 0; var < cube.num_vars; var++) { + if (! setp_empty(set_and(temp, d, cube.var_mask[var]))) { + set_diff(temp1, a, cube.var_mask[var]); + set_or(GETSET(r, r->count++), temp, temp1); + } + } + } else { + r = sf_addset(r, a); + } + return r; +} + +pcover make_disjoint(A) +pcover A; +{ + pcover R, new; + register pset last, p; + + R = new_cover(0); + foreach_set(A, last, p) { + new = cb_dsharp(p, R); + R = sf_append(R, new); + } + return R; +} + + +/* cv_dsharp -- disjoint-sharp product between two covers */ +pcover cv_dsharp(A, B) +pcover A, B; +{ + register pcube last, p; + pcover T; + + T = new_cover(0); + foreach_set(A, last, p) { + T = sf_union(T, cb_dsharp(p, B)); + } + return T; +} + + +/* cb1_dsharp -- disjoint-sharp product between a cover and a cube */ +pcover cb1_dsharp(T, c) +pcover T; +pcube c; +{ + pcube last, p; + pcover R; + + R = new_cover(T->count); + foreach_set(T, last, p) { + R = sf_union(R, dsharp(p, c)); + } + return R; +} + + +/* cb_dsharp -- disjoint-sharp product between a cube and a cover */ +pcover cb_dsharp(c, T) +pcube c; +pcover T; +{ + pcube last, p; + pcover Y, Y1; + + if (T->count == 0) { + Y = sf_addset(new_cover(1), c); + } else { + Y = new_cover(T->count); + set_copy(GETSET(Y,Y->count++), c); + foreach_set(T, last, p) { + Y1 = cb1_dsharp(Y, p); + free_cover(Y); + Y = Y1; + } + } + return Y; +} + + +/* dsharp -- form the disjoint-sharp product between two cubes */ +pcover dsharp(a, b) +pcube a, b; +{ + register pcube mask, diff, and, temp, temp1 = cube.temp[0]; + int var; + pcover r; + + r = new_cover(cube.num_vars); + + if (cdist0(a, b)) { + diff = set_diff(new_cube(), a, b); + and = set_and(new_cube(), a, b); + mask = new_cube(); + for(var = 0; var < cube.num_vars; var++) { + /* check if position var of "a and not b" is not empty */ + if (! setp_disjoint(diff, cube.var_mask[var])) { + + /* coordinate var equals the difference between a and b */ + temp = GETSET(r, r->count++); + (void) set_and(temp, diff, cube.var_mask[var]); + + /* coordinates 0 ... var-1 equal the intersection */ + INLINEset_and(temp1, and, mask); + INLINEset_or(temp, temp, temp1); + + /* coordinates var+1 .. cube.num_vars equal a */ + set_or(mask, mask, cube.var_mask[var]); + INLINEset_diff(temp1, a, mask); + INLINEset_or(temp, temp, temp1); + } + } + free_cube(diff); + free_cube(and); + free_cube(mask); + } else { + r = sf_addset(r, a); + } + return r; +} + +/* cv_intersect -- form the intersection of two covers */ + +#define MAGIC 500 /* save 500 cubes before containment */ + +pcover cv_intersect(A, B) +pcover A, B; +{ + register pcube pi, pj, lasti, lastj, pt; + pcover T, Tsave = NULL; + + /* How large should each temporary result cover be ? */ + T = new_cover(MAGIC); + pt = T->data; + + /* Form pairwise intersection of each cube of A with each cube of B */ + foreach_set(A, lasti, pi) { + foreach_set(B, lastj, pj) { + if (cdist0(pi, pj)) { + (void) set_and(pt, pi, pj); + if (++T->count >= T->capacity) { + if (Tsave == NULL) + Tsave = sf_contain(T); + else + Tsave = sf_union(Tsave, sf_contain(T)); + T = new_cover(MAGIC); + pt = T->data; + } else + pt += T->wsize; + } + } + } + + + if (Tsave == NULL) + Tsave = sf_contain(T); + else + Tsave = sf_union(Tsave, sf_contain(T)); + return Tsave; +} diff --git a/espresso/sminterf.c b/espresso/sminterf.c new file mode 100644 index 0000000..a44206d --- /dev/null +++ b/espresso/sminterf.c @@ -0,0 +1,44 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/sminterf.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "espresso.h" + + +pset +do_sm_minimum_cover(A) +pset_family A; +{ + sm_matrix *M; + sm_row *sparse_cover; + sm_element *pe; + pset cover; + register int i, base, rownum; + register unsigned val; + register pset last, p; + + M = sm_alloc(); + rownum = 0; + foreach_set(A, last, p) { + foreach_set_element(p, i, val, base) { + (void) sm_insert(M, rownum, base); + } + rownum++; + } + + sparse_cover = sm_minimum_cover(M, NIL(int), 1, 0); + sm_free(M); + + cover = set_new(A->sf_size); + sm_foreach_row_element(sparse_cover, pe) { + set_insert(cover, pe->col_num); + } + sm_row_free(sparse_cover); + + return cover; +} diff --git a/espresso/solution.c b/espresso/solution.c new file mode 100644 index 0000000..96a2c51 --- /dev/null +++ b/espresso/solution.c @@ -0,0 +1,114 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/solution.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "mincov_int.h" + + +solution_t * +solution_alloc() +{ + solution_t *sol; + + sol = ALLOC(solution_t, 1); + sol->cost = 0; + sol->row = sm_row_alloc(); + return sol; +} + + +void +solution_free(sol) +solution_t *sol; +{ + sm_row_free(sol->row); + FREE(sol); +} + + +solution_t * +solution_dup(sol) +solution_t *sol; +{ + solution_t *new_sol; + + new_sol = ALLOC(solution_t, 1); + new_sol->cost = sol->cost; + new_sol->row = sm_row_dup(sol->row); + return new_sol; +} + + +void +solution_add(sol, weight, col) +solution_t *sol; +int *weight; +int col; +{ + (void) sm_row_insert(sol->row, col); + sol->cost += WEIGHT(weight, col); +} + + +void +solution_accept(sol, A, weight, col) +solution_t *sol; +sm_matrix *A; +int *weight; +int col; +{ + register sm_element *p, *pnext; + sm_col *pcol; + + solution_add(sol, weight, col); + + /* delete rows covered by this column */ + pcol = sm_get_col(A, col); + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; /* grab it before it disappears */ + sm_delrow(A, p->row_num); + } +} + + +/* ARGSUSED */ +void +solution_reject(sol, A, weight, col) +solution_t *sol; +sm_matrix *A; +int *weight; +int col; +{ + sm_delcol(A, col); +} + + +solution_t * +solution_choose_best(best1, best2) +solution_t *best1, *best2; +{ + if (best1 != NIL(solution_t)) { + if (best2 != NIL(solution_t)) { + if (best1->cost <= best2->cost) { + solution_free(best2); + return best1; + } else { + solution_free(best1); + return best2; + } + } else { + return best1; + } + } else { + if (best2 != NIL(solution_t)) { + return best2; + } else { + return NIL(solution_t); + } + } +} diff --git a/espresso/sparse.c b/espresso/sparse.c new file mode 100644 index 0000000..4d8cdda --- /dev/null +++ b/espresso/sparse.c @@ -0,0 +1,146 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/sparse.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +/* + module: sparse.c + + make_sparse is a last-step cleanup to reduce the total number + of literals in the cover. + + This is done by reducing the "sparse" variables (using a modified + version of irredundant rather than reduce), followed by expanding + the "dense" variables (using modified version of expand). +*/ + +#include "espresso.h" + +pcover make_sparse(F, D, R) +pcover F, D, R; +{ + cost_t cost, best_cost; + + cover_cost(F, &best_cost); + + do { + EXECUTE(F = mv_reduce(F, D), MV_REDUCE_TIME, F, cost); + if (cost.total == best_cost.total) + break; + copy_cost(&cost, &best_cost); + + EXECUTE(F = expand(F, R, TRUE), RAISE_IN_TIME, F, cost); + if (cost.total == best_cost.total) + break; + copy_cost(&cost, &best_cost); + } while (force_irredundant); + + return F; +} + +/* + mv_reduce -- perform an "optimal" reduction of the variables which + we desire to be sparse + + This could be done using "reduce" and then saving just the desired + part of the reduction. Instead, this version uses IRRED to find + which cubes of an output are redundant. Note that this gets around + the cube-ordering problem. + + In normal use, it is expected that the cover is irredundant and + hence no cubes will be reduced to the empty cube (however, this is + checked for and such cubes will be deleted) +*/ + +pcover +mv_reduce(F, D) +pcover F, D; +{ + register int i, var; + register pcube p, p1, last; + int index; + pcover F1, D1; + pcube *F_cube_table; + + /* loop for each multiple-valued variable */ + for(var = 0; var < cube.num_vars; var++) { + + if (cube.sparse[var]) { + + /* loop for each part of the variable */ + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + + /* remember mapping of F1 cubes back to F cubes */ + F_cube_table = ALLOC(pcube, F->count); + + /* 'cofactor' against part #i of variable #var */ + F1 = new_cover(F->count); + foreach_set(F, last, p) { + if (is_in_set(p, i)) { + F_cube_table[F1->count] = p; + p1 = GETSET(F1, F1->count++); + (void) set_diff(p1, p, cube.var_mask[var]); + set_insert(p1, i); + } + } + + /* 'cofactor' against part #i of variable #var */ + /* not really necessary -- just more efficient ? */ + D1 = new_cover(D->count); + foreach_set(D, last, p) { + if (is_in_set(p, i)) { + p1 = GETSET(D1, D1->count++); + (void) set_diff(p1, p, cube.var_mask[var]); + set_insert(p1, i); + } + } + + mark_irredundant(F1, D1); + + /* now remove part i from cubes which are redundant */ + index = 0; + foreach_set(F1, last, p1) { + if (! TESTP(p1, ACTIVE)) { + p = F_cube_table[index]; + + /* don't reduce a variable which is full + * (unless it is the output variable) + */ + if (var == cube.num_vars-1 || + ! setp_implies(cube.var_mask[var], p)) { + set_remove(p, i); + } + RESET(p, PRIME); + } + index++; + } + + free_cover(F1); + free_cover(D1); + FREE(F_cube_table); + } + } + } + + /* Check if any cubes disappeared */ + (void) sf_active(F); + for(var = 0; var < cube.num_vars; var++) { + if (cube.sparse[var]) { + foreach_active_set(F, last, p) { + if (setp_disjoint(p, cube.var_mask[var])) { + RESET(p, ACTIVE); + F->active_count--; + } + } + } + } + + if (F->count != F->active_count) { + F = sf_inactive(F); + } + return F; +} diff --git a/espresso/sparse.h b/espresso/sparse.h new file mode 100644 index 0000000..f65f4d8 --- /dev/null +++ b/espresso/sparse.h @@ -0,0 +1,135 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/sparse.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#ifndef SPARSE_H +#define SPARSE_H + +/* + * sparse.h -- sparse matrix package header file + */ + +typedef struct sm_element_struct sm_element; +typedef struct sm_row_struct sm_row; +typedef struct sm_col_struct sm_col; +typedef struct sm_matrix_struct sm_matrix; + + +/* + * sparse matrix element + */ +struct sm_element_struct { + int row_num; /* row number of this element */ + int col_num; /* column number of this element */ + sm_element *next_row; /* next row in this column */ + sm_element *prev_row; /* previous row in this column */ + sm_element *next_col; /* next column in this row */ + sm_element *prev_col; /* previous column in this row */ + char *user_word; /* user-defined word */ +}; + + +/* + * row header + */ +struct sm_row_struct { + int row_num; /* the row number */ + int length; /* number of elements in this row */ + int flag; /* user-defined word */ + sm_element *first_col; /* first element in this row */ + sm_element *last_col; /* last element in this row */ + sm_row *next_row; /* next row (in sm_matrix linked list) */ + sm_row *prev_row; /* previous row (in sm_matrix linked list) */ + char *user_word; /* user-defined word */ +}; + + +/* + * column header + */ +struct sm_col_struct { + int col_num; /* the column number */ + int length; /* number of elements in this column */ + int flag; /* user-defined word */ + sm_element *first_row; /* first element in this column */ + sm_element *last_row; /* last element in this column */ + sm_col *next_col; /* next column (in sm_matrix linked list) */ + sm_col *prev_col; /* prev column (in sm_matrix linked list) */ + char *user_word; /* user-defined word */ +}; + + +/* + * A sparse matrix + */ +struct sm_matrix_struct { + sm_row **rows; /* pointer to row headers (by row #) */ + int rows_size; /* alloc'ed size of above array */ + sm_col **cols; /* pointer to column headers (by col #) */ + int cols_size; /* alloc'ed size of above array */ + sm_row *first_row; /* first row (linked list of all rows) */ + sm_row *last_row; /* last row (linked list of all rows) */ + int nrows; /* number of rows */ + sm_col *first_col; /* first column (linked list of columns) */ + sm_col *last_col; /* last column (linked list of columns) */ + int ncols; /* number of columns */ + char *user_word; /* user-defined word */ +}; + + +#define sm_get_col(A, colnum) \ + (((colnum) >= 0 && (colnum) < (A)->cols_size) ? \ + (A)->cols[colnum] : (sm_col *) 0) + +#define sm_get_row(A, rownum) \ + (((rownum) >= 0 && (rownum) < (A)->rows_size) ? \ + (A)->rows[rownum] : (sm_row *) 0) + +#define sm_foreach_row(A, prow) \ + for(prow = A->first_row; prow != 0; prow = prow->next_row) + +#define sm_foreach_col(A, pcol) \ + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) + +#define sm_foreach_row_element(prow, p) \ + for(p = prow->first_col; p != 0; p = p->next_col) + +#define sm_foreach_col_element(pcol, p) \ + for(p = pcol->first_row; p != 0; p = p->next_row) + +#define sm_put(x, val) \ + (x->user_word = (char *) val) + +#define sm_get(type, x) \ + ((type) (x->user_word)) + +extern sm_matrix *sm_alloc(), *sm_alloc_size(), *sm_dup(); +extern void sm_free(), sm_delrow(), sm_delcol(), sm_resize(); +extern void sm_write(), sm_print(), sm_dump(), sm_cleanup(); +extern void sm_copy_row(), sm_copy_col(); +extern void sm_remove(), sm_remove_element(); +extern sm_element *sm_insert(), *sm_find(); +extern sm_row *sm_longest_row(); +extern sm_col *sm_longest_col(); +extern int sm_read(), sm_read_compressed(); + +extern sm_row *sm_row_alloc(), *sm_row_dup(), *sm_row_and(); +extern void sm_row_free(), sm_row_remove(), sm_row_print(); +extern sm_element *sm_row_insert(), *sm_row_find(); +extern int sm_row_contains(), sm_row_intersects(); +extern int sm_row_compare(), sm_row_hash(); + +extern sm_col *sm_col_alloc(), *sm_col_dup(), *sm_col_and(); +extern void sm_col_free(), sm_col_remove(), sm_col_print(); +extern sm_element *sm_col_insert(), *sm_col_find(); +extern int sm_col_contains(), sm_col_intersects(); +extern int sm_col_compare(), sm_col_hash(); + +extern int sm_row_dominance(), sm_col_dominance(), sm_block_partition(); + +#endif diff --git a/espresso/sparse_int.h b/espresso/sparse_int.h new file mode 100644 index 0000000..c350bbb --- /dev/null +++ b/espresso/sparse_int.h @@ -0,0 +1,119 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/sparse_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +#include "port.h" +#include "utility.h" +#include "sparse.h" + + + +/* + * sorted, double-linked list insertion + * + * type: object type + * + * first, last: fields (in header) to head and tail of the list + * count: field (in header) of length of the list + * + * next, prev: fields (in object) to link next and previous objects + * value: field (in object) which controls the order + * + * newval: value field for new object + * e: an object to use if insertion needed (set to actual value used) + */ + +#define sorted_insert(type, first, last, count, next, prev, value, newval, e) \ + if (last == 0) { \ + e->value = newval; \ + first = e; \ + last = e; \ + e->next = 0; \ + e->prev = 0; \ + count++; \ + } else if (last->value < newval) { \ + e->value = newval; \ + last->next = e; \ + e->prev = last; \ + last = e; \ + e->next = 0; \ + count++; \ + } else if (first->value > newval) { \ + e->value = newval; \ + first->prev = e; \ + e->next = first; \ + first = e; \ + e->prev = 0; \ + count++; \ + } else { \ + type *p; \ + for(p = first; p->value < newval; p = p->next) \ + ; \ + if (p->value > newval) { \ + e->value = newval; \ + p = p->prev; \ + p->next->prev = e; \ + e->next = p->next; \ + p->next = e; \ + e->prev = p; \ + count++; \ + } else { \ + e = p; \ + } \ + } + + +/* + * double linked-list deletion + */ +#define dll_unlink(p, first, last, next, prev, count) { \ + if (p->prev == 0) { \ + first = p->next; \ + } else { \ + p->prev->next = p->next; \ + } \ + if (p->next == 0) { \ + last = p->prev; \ + } else { \ + p->next->prev = p->prev; \ + } \ + count--; \ +} + + +#ifdef FAST_AND_LOOSE +extern sm_element *sm_element_freelist; +extern sm_row *sm_row_freelist; +extern sm_col *sm_col_freelist; + +#define sm_element_alloc(newobj) \ + if (sm_element_freelist == NIL(sm_element)) { \ + newobj = ALLOC(sm_element, 1); \ + } else { \ + newobj = sm_element_freelist; \ + sm_element_freelist = sm_element_freelist->next_col; \ + } \ + newobj->user_word = NIL(char); \ + +#define sm_element_free(e) \ + (e->next_col = sm_element_freelist, sm_element_freelist = e) + +#else + +#define sm_element_alloc(newobj) \ + newobj = ALLOC(sm_element, 1); \ + newobj->user_word = NIL(char); +#define sm_element_free(e) \ + FREE(e) +#endif + + +extern void sm_row_remove_element(); +extern void sm_col_remove_element(); + +/* LINTLIBRARY */ diff --git a/espresso/unate.c b/espresso/unate.c new file mode 100644 index 0000000..e79f788 --- /dev/null +++ b/espresso/unate.c @@ -0,0 +1,441 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/unate.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +/* + * unate.c -- routines for dealing with unate functions + */ + +#include "espresso.h" + +static pset_family abs_covered(); +static pset_family abs_covered_many(); +static int abs_select_restricted(); + +pcover map_cover_to_unate(T) +pcube *T; +{ + register unsigned int word_test, word_set, bit_test, bit_set; + register pcube p, pA; + pset_family A; + pcube *T1; + int ncol, i; + + A = sf_new(CUBELISTSIZE(T), cdata.vars_unate); + A->count = CUBELISTSIZE(T); + foreachi_set(A, i, p) { + (void) set_clear(p, A->sf_size); + } + ncol = 0; + + for(i = 0; i < cube.size; i++) { + if (cdata.part_zeros[i] > 0) { + assert(ncol <= cdata.vars_unate); + + /* Copy a column from T to A */ + word_test = WHICH_WORD(i); + bit_test = 1 << WHICH_BIT(i); + word_set = WHICH_WORD(ncol); + bit_set = 1 << WHICH_BIT(ncol); + + pA = A->data; + for(T1 = T+2; (p = *T1++) != 0; ) { + if ((p[word_test] & bit_test) == 0) { + pA[word_set] |= bit_set; + } + pA += A->wsize; + } + + ncol++; + } + } + + return A; +} + +pcover map_unate_to_cover(A) +pset_family A; +{ + register int i, ncol, lp; + register pcube p, pB; + int var, nunate, *unate; + pcube last; + pset_family B; + + B = sf_new(A->count, cube.size); + B->count = A->count; + + /* Find the unate variables */ + unate = ALLOC(int, cube.num_vars); + nunate = 0; + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + unate[nunate++] = var; + } + } + + /* Loop for each set of A */ + pB = B->data; + foreach_set(A, last, p) { + + /* Initialize this set of B */ + INLINEset_fill(pB, cube.size); + + /* Now loop for the unate variables; if the part is in A, + * then this variable of B should be a single 1 in the unate + * part. + */ + for(ncol = 0; ncol < nunate; ncol++) { + if (is_in_set(p, ncol)) { + lp = cube.last_part[unate[ncol]]; + for(i = cube.first_part[unate[ncol]]; i <= lp; i++) { + if (cdata.part_zeros[i] == 0) { + set_remove(pB, i); + } + } + } + } + pB += B->wsize; + } + + FREE(unate); + return B; +} + +/* + * unate_compl + */ + +pset_family unate_compl(A) +pset_family A; +{ + register pset p, last; + + /* Make sure A is single-cube containment minimal */ +/* A = sf_rev_contain(A);*/ + + foreach_set(A, last, p) { + PUTSIZE(p, set_ord(p)); + } + + /* Recursively find the complement */ + A = unate_complement(A); + + /* Now, we can guarantee a minimal result by containing the result */ + A = sf_rev_contain(A); + return A; +} + + +/* + * Assume SIZE(p) records the size of each set + */ +pset_family unate_complement(A) +pset_family A; /* disposes of A */ +{ + pset_family Abar; + register pset p, p1, restrict; + register int i; + int max_i, min_set_ord, j; + + /* Check for no sets in the matrix -- complement is the universe */ + if (A->count == 0) { + sf_free(A); + Abar = sf_new(1, A->sf_size); + (void) set_clear(GETSET(Abar, Abar->count++), A->sf_size); + + /* Check for a single set in the maxtrix -- compute de Morgan complement */ + } else if (A->count == 1) { + p = A->data; + Abar = sf_new(A->sf_size, A->sf_size); + for(i = 0; i < A->sf_size; i++) { + if (is_in_set(p, i)) { + p1 = set_clear(GETSET(Abar, Abar->count++), A->sf_size); + set_insert(p1, i); + } + } + sf_free(A); + + } else { + + /* Select splitting variable as the variable which belongs to a set + * of the smallest size, and which has greatest column count + */ + restrict = set_new(A->sf_size); + min_set_ord = A->sf_size + 1; + foreachi_set(A, i, p) { + if (SIZE(p) < min_set_ord) { + set_copy(restrict, p); + min_set_ord = SIZE(p); + } else if (SIZE(p) == min_set_ord) { + set_or(restrict, restrict, p); + } + } + + /* Check for no data (shouldn't happen ?) */ + if (min_set_ord == 0) { + A->count = 0; + Abar = A; + + /* Check for "essential" columns */ + } else if (min_set_ord == 1) { + Abar = unate_complement(abs_covered_many(A, restrict)); + sf_free(A); + foreachi_set(Abar, i, p) { + set_or(p, p, restrict); + } + + /* else, recur as usual */ + } else { + max_i = abs_select_restricted(A, restrict); + + /* Select those rows of A which are not covered by max_i, + * recursively find all minimal covers of these rows, and + * then add back in max_i + */ + Abar = unate_complement(abs_covered(A, max_i)); + foreachi_set(Abar, i, p) { + set_insert(p, max_i); + } + + /* Now recur on A with all zero's on column max_i */ + foreachi_set(A, i, p) { + if (is_in_set(p, max_i)) { + set_remove(p, max_i); + j = SIZE(p) - 1; + PUTSIZE(p, j); + } + } + + Abar = sf_append(Abar, unate_complement(A)); + } + set_free(restrict); + } + + return Abar; +} + +pset_family exact_minimum_cover(T) +IN pset_family T; +{ + register pset p, last, p1; + register int i, n; + int lev, lvl; + pset nlast; + pset_family temp; + long start = ptime(); + struct { + pset_family sf; + int level; + } stack[32]; /* 32 suffices for 2 ** 32 cubes ! */ + + if (T->count <= 0) + return sf_new(1, T->sf_size); + for(n = T->count, lev = 0; n != 0; n >>= 1, lev++) ; + + /* A simple heuristic ordering */ + T = lex_sort(sf_save(T)); + + /* Push a full set on the stack to get things started */ + n = 1; + stack[0].sf = sf_new(1, T->sf_size); + stack[0].level = lev; + set_fill(GETSET(stack[0].sf, stack[0].sf->count++), T->sf_size); + + nlast = GETSET(T, T->count - 1); + foreach_set(T, last, p) { + + /* "unstack" the set into a family */ + temp = sf_new(set_ord(p), T->sf_size); + for(i = 0; i < T->sf_size; i++) + if (is_in_set(p, i)) { + p1 = set_fill(GETSET(temp, temp->count++), T->sf_size); + set_remove(p1, i); + } + stack[n].sf = temp; + stack[n++].level = lev; + + /* Pop the stack and perform (leveled) intersections */ + while (n > 1 && (stack[n-1].level==stack[n-2].level || p == nlast)) { + temp = unate_intersect(stack[n-1].sf, stack[n-2].sf, FALSE); + lvl = MIN(stack[n-1].level, stack[n-2].level) - 1; + if (debug & MINCOV && lvl < 10) { + printf("# EXACT_MINCOV[%d]: %4d = %4d x %4d, time = %s\n", + lvl, temp->count, stack[n-1].sf->count, + stack[n-2].sf->count, print_time(ptime() - start)); + (void) fflush(stdout); + } + sf_free(stack[n-2].sf); + sf_free(stack[n-1].sf); + stack[n-2].sf = temp; + stack[n-2].level = lvl; + n--; + } + } + + temp = stack[0].sf; + p1 = set_fill(set_new(T->sf_size), T->sf_size); + foreach_set(temp, last, p) + INLINEset_diff(p, p1, p); + set_free(p1); + if (debug & MINCOV1) { + printf("MINCOV: family of all minimal coverings is\n"); + sf_print(temp); + } + sf_free(T); /* this is the copy of T we made ... */ + return temp; +} + +/* + * unate_intersect -- intersect two unate covers + * + * If largest_only is TRUE, then only the largest cube(s) are returned + */ + +#define MAGIC 500 /* save 500 cubes before containment */ + +pset_family unate_intersect(A, B, largest_only) +pset_family A, B; +bool largest_only; +{ + register pset pi, pj, lasti, lastj, pt; + pset_family T, Tsave; + bool save; + int maxord, ord; + + /* How large should each temporary result cover be ? */ + T = sf_new(MAGIC, A->sf_size); + Tsave = NULL; + maxord = 0; + pt = T->data; + + /* Form pairwise intersection of each set of A with each cube of B */ + foreach_set(A, lasti, pi) { + + foreach_set(B, lastj, pj) { + + save = set_andp(pt, pi, pj); + + /* Check if we want the largest only */ + if (save && largest_only) { + if ((ord = set_ord(pt)) > maxord) { + /* discard Tsave and T */ + if (Tsave != NULL) { + sf_free(Tsave); + Tsave = NULL; + } + pt = T->data; + T->count = 0; + /* Re-create pt (which was just thrown away) */ + (void) set_and(pt, pi, pj); + maxord = ord; + } else if (ord < maxord) { + save = FALSE; + } + } + + if (save) { + if (++T->count >= T->capacity) { + T = sf_contain(T); + Tsave = (Tsave == NULL) ? T : sf_union(Tsave, T); + T = sf_new(MAGIC, A->sf_size); + pt = T->data; + } else { + pt += T->wsize; + } + } + } + } + + + /* Contain the final result and merge it into Tsave */ + T = sf_contain(T); + Tsave = (Tsave == NULL) ? T : sf_union(Tsave, T); + + return Tsave; +} + +/* + * abs_covered -- after selecting a new column for the selected set, + * create a new matrix which is only those rows which are still uncovered + */ +static pset_family +abs_covered(A, pick) +pset_family A; +register int pick; +{ + register pset last, p, pdest; + register pset_family Aprime; + + Aprime = sf_new(A->count, A->sf_size); + pdest = Aprime->data; + foreach_set(A, last, p) + if (! is_in_set(p, pick)) { + INLINEset_copy(pdest, p); + Aprime->count++; + pdest += Aprime->wsize; + } + return Aprime; +} + + +/* + * abs_covered_many -- after selecting many columns for ther selected set, + * create a new matrix which is only those rows which are still uncovered + */ +static pset_family +abs_covered_many(A, pick_set) +pset_family A; +register pset pick_set; +{ + register pset last, p, pdest; + register pset_family Aprime; + + Aprime = sf_new(A->count, A->sf_size); + pdest = Aprime->data; + foreach_set(A, last, p) + if (setp_disjoint(p, pick_set)) { + INLINEset_copy(pdest, p); + Aprime->count++; + pdest += Aprime->wsize; + } + return Aprime; +} + + +/* + * abs_select_restricted -- select the column of maximum column count which + * also belongs to the set "restrict"; weight each column of a set as + * 1 / (set_ord(p) - 1). + */ +static int +abs_select_restricted(A, restrict) +pset_family A; +pset restrict; +{ + register int i, best_var, best_count, *count; + + /* Sum the elements in these columns */ + count = sf_count_restricted(A, restrict); + + /* Find which variable has maximum weight */ + best_var = -1; + best_count = 0; + for(i = 0; i < A->sf_size; i++) { + if (count[i] > best_count) { + best_var = i; + best_count = count[i]; + } + } + FREE(count); + + if (best_var == -1) + fatal("abs_select_restricted: should not have best_var == -1"); + + return best_var; +} diff --git a/espresso/verify.c b/espresso/verify.c new file mode 100644 index 0000000..dd6665a --- /dev/null +++ b/espresso/verify.c @@ -0,0 +1,193 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/espresso/verify.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:13:58 $ + * + */ +/* + */ + +#include "espresso.h" + +/* + * verify -- check that all minterms of F are contained in (Fold u Dold) + * and that all minterms of Fold are contained in (F u Dold). + */ +bool verify(F, Fold, Dold) +pcover F, Fold, Dold; +{ + pcube p, last, *FD; + bool verify_error = FALSE; + + /* Make sure the function didn't grow too large */ + FD = cube2list(Fold, Dold); + foreach_set(F, last, p) + if (! cube_is_covered(FD, p)) { + printf("some minterm in F is not covered by Fold u Dold\n"); + verify_error = TRUE; + if (verbose_debug) printf("%s\n", pc1(p)); else break; + } + free_cubelist(FD); + + /* Make sure minimized function covers the original function */ + FD = cube2list(F, Dold); + foreach_set(Fold, last, p) + if (! cube_is_covered(FD, p)) { + printf("some minterm in Fold is not covered by F u Dold\n"); + verify_error = TRUE; + if (verbose_debug) printf("%s\n", pc1(p)); else break; + } + free_cubelist(FD); + + return verify_error; +} + + + +/* + * PLA_verify -- verify that two PLA's are identical + * + * If names are given, row and column permutations are done to make + * the comparison meaningful. + * + */ +bool PLA_verify(PLA1, PLA2) +pPLA PLA1, PLA2; +{ + /* Check if both have names given; if so, attempt to permute to + * match the names + */ + if (PLA1->label != NULL && PLA1->label[0] != NULL && + PLA2->label != NULL && PLA2->label[0] != NULL) { + PLA_permute(PLA1, PLA2); + } else { + (void) fprintf(stderr, "Warning: cannot permute columns without names\n"); + return TRUE; + } + + if (PLA1->F->sf_size != PLA2->F->sf_size) { + (void) fprintf(stderr, "PLA_verify: PLA's are not the same size\n"); + return TRUE; + } + + return verify(PLA2->F, PLA1->F, PLA1->D); +} + + + +/* + * Permute the columns of PLA1 so that they match the order of PLA2 + * Discard any columns of PLA1 which are not in PLA2 + * Association is strictly by the names of the columns of the cover. + */ +PLA_permute(PLA1, PLA2) +pPLA PLA1, PLA2; +{ + register int i, j, *permute, npermute; + register char *labi; + char **label; + + /* determine which columns of PLA1 to save, and place these in the list + * "permute"; the order in this list is the final output order + */ + npermute = 0; + permute = ALLOC(int, PLA2->F->sf_size); + for(i = 0; i < PLA2->F->sf_size; i++) { + labi = PLA2->label[i]; + for(j = 0; j < PLA1->F->sf_size; j++) { + if (strcmp(labi, PLA1->label[j]) == 0) { + permute[npermute++] = j; + break; + } + } + } + + /* permute columns */ + if (PLA1->F != NULL) { + PLA1->F = sf_permute(PLA1->F, permute, npermute); + } + if (PLA1->R != NULL) { + PLA1->R = sf_permute(PLA1->R, permute, npermute); + } + if (PLA1->D != NULL) { + PLA1->D = sf_permute(PLA1->D, permute, npermute); + } + + /* permute the labels */ + label = ALLOC(char *, cube.size); + for(i = 0; i < npermute; i++) { + label[i] = PLA1->label[permute[i]]; + } + for(i = npermute; i < cube.size; i++) { + label[i] = NULL; + } + FREE(PLA1->label); + PLA1->label = label; + + FREE(permute); +} + + + +/* + * check_consistency -- test that the ON-set, OFF-set and DC-set form + * a partition of the boolean space. + */ +bool check_consistency(PLA) +pPLA PLA; +{ + bool verify_error = FALSE; + pcover T; + + T = cv_intersect(PLA->F, PLA->D); + if (T->count == 0) + printf("ON-SET and DC-SET are disjoint\n"); + else { + printf("Some minterm(s) belong to both the ON-SET and DC-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + T = cv_intersect(PLA->F, PLA->R); + if (T->count == 0) + printf("ON-SET and OFF-SET are disjoint\n"); + else { + printf("Some minterm(s) belong to both the ON-SET and OFF-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + T = cv_intersect(PLA->D, PLA->R); + if (T->count == 0) + printf("DC-SET and OFF-SET are disjoint\n"); + else { + printf("Some minterm(s) belong to both the OFF-SET and DC-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + if (tautology(cube3list(PLA->F, PLA->D, PLA->R))) + printf("Union of ON-SET, OFF-SET and DC-SET is the universe\n"); + else { + T = complement(cube3list(PLA->F, PLA->D, PLA->R)); + printf("There are minterms left unspecified !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + free_cover(T); + } + (void) fflush(stdout); + return verify_error; +} diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..77bc381 --- /dev/null +++ b/install-sh @@ -0,0 +1,316 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2004-02-15.20 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# 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= + +usage="Usage: $0 [OPTION]... SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 -d DIRECTORIES... + +In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default. +In the second, create the directory path DIR. + +Options: +-b=TRANSFORMBASENAME +-c copy source (using $cpprog) instead of moving (using $mvprog). +-d create directories instead of installing files. +-g GROUP $chgrp installed files to GROUP. +-m MODE $chmod installed files to MODE. +-o USER $chown installed files to USER. +-s strip installed files (using $stripprog). +-t=TRANSFORM +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + -c) instcmd=$cpprog + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit 0;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + --version) echo "$0 $scriptversion"; exit 0;; + + *) # When -d is used, all remaining arguments are directories to create. + test -n "$dir_arg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + instcmd=: + chmodcmd= + else + instcmd=$mkdirprog + 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 test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -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 test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" || lasterr=$? + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test ! -d "$pathcomp" && { (exit ${lasterr-1}); exit; } + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $instcmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + # If we're going to rename the final executable, determine the name now. + if test -z "$transformarg"; then + dstfile=`basename "$dst"` + else + dstfile=`basename "$dst" $transformbasename \ + | sed $transformarg`$transformbasename + fi + + # don't allow the sed command to completely eliminate the filename. + test -z "$dstfile" && dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Move or copy the file name to the temp name + $doit $instcmd "$src" "$dsttmp" && + + # 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. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now remove or move aside any old file at destination location. We + # try this two ways since rm can't unlink itself on some systems and + # the destination file might be busy for other reasons. In this case, + # the final cleanup might fail but the new file should still install + # successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + fi || { (exit 1); exit; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/jedi/Makefile.am b/jedi/Makefile.am new file mode 100644 index 0000000..619f0ec --- /dev/null +++ b/jedi/Makefile.am @@ -0,0 +1,8 @@ +AM_CPPFLAGS = -I$(top_srcdir)/port -I$(top_srcdir)/utility +LDADD = ../utility/libutility.a -lm + +bin_PROGRAMS = jedi +jedi_SOURCES = cluster.c expand.c getopt.c hill.c hot.c jedi.c jedi.h \ + jedi_int.h options.c random.c read.c rp.c rp.h rp_int.h util.c util.h \ + weights.c write.c +dist_man1_MANS = jedi.1 diff --git a/jedi/Makefile.in b/jedi/Makefile.in new file mode 100644 index 0000000..1e44a3d --- /dev/null +++ b/jedi/Makefile.in @@ -0,0 +1,449 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(jedi_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = jedi$(EXEEXT) +subdir = jedi +DIST_COMMON = $(dist_man1_MANS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_jedi_OBJECTS = cluster.$(OBJEXT) expand.$(OBJEXT) getopt.$(OBJEXT) \ + hill.$(OBJEXT) hot.$(OBJEXT) jedi.$(OBJEXT) options.$(OBJEXT) \ + random.$(OBJEXT) read.$(OBJEXT) rp.$(OBJEXT) util.$(OBJEXT) \ + weights.$(OBJEXT) write.$(OBJEXT) +jedi_OBJECTS = $(am_jedi_OBJECTS) +jedi_LDADD = $(LDADD) +jedi_DEPENDENCIES = ../utility/libutility.a +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(jedi_SOURCES) +DIST_SOURCES = $(jedi_SOURCES) +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(dist_man1_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I$(top_srcdir)/port -I$(top_srcdir)/utility +LDADD = ../utility/libutility.a -lm +jedi_SOURCES = cluster.c expand.c getopt.c hill.c hot.c jedi.c jedi.h \ + jedi_int.h options.c random.c read.c rp.c rp.h rp_int.h util.c util.h \ + weights.c write.c + +dist_man1_MANS = jedi.1 +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps jedi/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps jedi/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +jedi$(EXEEXT): $(jedi_OBJECTS) $(jedi_DEPENDENCIES) + @rm -f jedi$(EXEEXT) + $(LINK) $(jedi_LDFLAGS) $(jedi_OBJECTS) $(jedi_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-man + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: install-man1 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am uninstall-man + +uninstall-man: uninstall-man1 + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-man1 \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-info-am uninstall-man uninstall-man1 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/jedi/cluster.c b/jedi/cluster.c new file mode 100644 index 0000000..48f0f24 --- /dev/null +++ b/jedi/cluster.c @@ -0,0 +1,149 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/cluster.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:07 $ + * + */ +/* + * Symbolic encoding program for compiling a symbolic + * description into a binary representation. Target + * is multi-level logic synthesis + * + * History: + * + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ +#include "jedi.h" + +extern int currentEnumtype; + +cluster_embedding() +{ + int i; + double cost; + + for (i=0; i 0) { + s = select_state(type, sa); + sa[s] = TRUE; + c = select_code(type, sa, s); + type.symbols[s].code_ptr = c; + type.codes[c].symbol_ptr = s; + type.codes[c].assigned = TRUE; + t--; + + if (verboseFlag) { + (void) fprintf(stderr, "\tassigning %s with %s ...\n", + type.symbols[s].token, type.codes[c].bit_vector); + } + } + + FREE(sa); + + if (verboseFlag) { + time = util_cpu_time() - time; + (void) fprintf(stderr,"total cpu time is %s.\n", util_print_time(time)); + } +} + +int +select_state(type, sa) +struct Enumtype type; +int *sa; +{ + int s, i, j; + int ns, we; + int best, force; + + best = -1; + ns = type.ns; + for (i=0;i best) { + best = force; + s = i; + } + } + } + return s; +} + +int select_code(type, sa, s) +struct Enumtype type; +int *sa, s; +{ + int c; + int best, force; + int ns, nc; + int we, dist; + int i, f, p; + + best = -1; + ns = type.ns; + nc = type.nc; + for (i=0;i temp2"); + fp = my_fopen("temp2", "r"); + (void) fgets(line, BUFSIZE, fp); + (void) fgets(line, BUFSIZE, fp); + (void) fgets(line, BUFSIZE, fp); + (void) fgets(line, BUFSIZE, fp); + for (j=0;j= argc) return EOF; + place = argv[optind]; + if (place[0] != '-' || place[1] == '\0') return EOF; + optind++; + if (place[1] == '-' && place[2] == '\0') return EOF; + scan = place+1; + } + + c = *scan++; + place = strchr(optstring, c); + if (place == NullS || c == ':') { + (void) fprintf(stderr, "%s: unknown option %c\n", argv[0], c); + return '?'; + } + if (*++place == ':') { + if (*scan != '\0') { + optarg = scan, scan = NullS; + } else { + optarg = argv[optind], optind++; + } + } + return c; + } diff --git a/jedi/hill.c b/jedi/hill.c new file mode 100644 index 0000000..498d911 --- /dev/null +++ b/jedi/hill.c @@ -0,0 +1,242 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/hill.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:07 $ + * + */ +/* + * Symbolic encoding program for compiling a symbolic + * description into a binary representation. Target + * is multi-level logic synthesis + * + * History: + * + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ + +#include "jedi.h" +#include "rp.h" + +#define DISPLACE1 0 /* flag for displacement */ +#define DISPLACE2 1 /* flag for displacement */ +#define INTERCHANGE 2 /* flag for interchange */ + +/* + * global variables + */ +int move_type; /* move type for SA */ +int random1; /* random variable for SA */ +int random2; /* random variable for SA */ +int currentEnumtype; /* states the current type being encoded */ + +/* + * external declarations + */ +double rint(); /* math.h */ +extern char *int_to_binary(); /* util.c */ +extern int binary_to_int(); /* util.c */ + +/* + * forward declarations + */ +int opt_embedding(); +int cost_function(); +int generate_function(); +int accept_function(); +int reject_function(); + +opt_embedding() +{ + int i; + + for (i=0; i output] +.SH DESCRIPTION +.PP +.I JEDI +is a general symbolic encoding program intended for multi-level +logic optimization by a logic synthesis system such as +.I MISII(1OCTTOOLS). A symbolic description is different than +a traditional Boolean logic description in that data types are +defined in terms of symbolic values rather than simply 0 and 1. +A special symbolic type is the Boolean set (0, 1). More general +symbolic types can be defined. For example, one may wish to define +a data type with the following values: (ADD, CMP, MUL, SUB). To convert +a symbolic description to a form that can be implemented in hardware, +the symbolic values must be given binary codes (eg. ADD -> 00, CMP -> 01, +MUL -> 10, SUB -> 11). Depending on the choice of codes, the cost of +the final implementation may vary dramatically (may be a factor of 2). +Multiple symbolic data types and symbolic variables can be defined. JEDI +can handle both input and output variables. The former is treated as an +input encoding problem while the latter is treated as an output encoding +problem. Variables of the same symbolic type are given the same encodings. +The input format will be explained below. +.PP +JEDI can also be used for state assignment, which is a special case +of symbolic encoding where the internal states of a finite state +machine are expressed symbolically (eg. st0, st1, st2, st3). Here, +only the state variables are encoded; the other binary variables are +maintained. The input format for the state assignment problem is +basically the same as those used by the state assignment programs +.I KISS(1OCTTOOLS), +.I MUSTANG(1OCTTOOLS), +and +.I NOVA(1OCTTOOLS). +This is so that these programs can be used interchangeably. +Currently, this is the most commonly used application of JEDI. +Since this is the case, JEDI assumes a state assignment problem +unless otherwise specified. +.PP +If JEDI is used with the general symbolic format, the output is a fully +encoded logic description in the Berkeley PLA format suitable for further +optimization by the programs +.I ESPRESSO(1OCTTOOLS), +and +.I MISII(1OCTTOOLS). +The unused binary codes are automatically inserted as external don't +cares. Therefore, the output of JEDI should be processed through the +ESPRESSO program so that these don't care conditions can be properly +exploited. Other logic optimization programs can be used if they accept the +same logic interchange formats as the Berkeley logic tools. +.PP +If JEDI is used for state assignment, then it will by default produce +an extended BLIF format suitable for further processing by the +sequential logic synthesis system called SIS. An option can be +specified to produce the PLA output format. +.SH "OPTIONS" +.IP -\fBh\fP +prints out usage information. +.IP -\fBe option\fP +r) performs random encoding. +h) performs one-hot encoding. +d) performs dynamic random encoding. +s) performs straightforward mapping. +i) encodes using the input dominant algorithm. +o) encodes using the output dominant algorithm (default). +c) encodes using a combination of input and output dominant algorithms. +y) encodes using a modified output dominant algorithm. +.IP -\fBx\fP +expands the state codes using the invalid state codes as don't cares. +.IP -\fBc\fP +uses a group based embedding algorithm. +.IP -\fBp\fP +outputs in the PLA format. +.IP -\fBg\fP +reads a general symbolic encoding format and performs general encoding. +.SH "INPUT FILE FORMAT" +Below is a general input description. +.nf + + .i 4 + .o 4 + .ilb c1 c2 c3 presentState + .ob nextState o1 light1 light2 + .enum States 4 2 HG HY FG FY + .enum Colors 3 2 GREEN RED BLUE + .itype Boolean Boolean Boolean States + .otype States Boolean Colors Colors + 0 - - HG HG 0 GREEN RED + - 0 - HG HG 0 GREEN RED + 1 1 - HG HY 1 GREEN RED + - - 0 HY HY 0 YELLOW RED + - - 1 HY FG 1 YELLOW RED + 1 0 - FG FG 0 RED GREEN + 0 - - FG FY 1 RED GREEN + - 1 - FG FY 1 RED GREEN + - - 0 FY FY 0 RED YELLOW + - - 1 FY HG 1 RED YELLOW + +.fi +The user can specify different symbolic types using the ".enum" command. +Then, the type of the input and output variables can be declared using +the ".itype" and ".otype" commands, respectively. The syntax of the ".enum" +command is: .enum \fItypename\fP \fInumber_of_symbols\fP \fIcode_length\fP +symbol1 ... symboln. A built-in type called "Boolean" can be used for binary +variables. Binary variables of type "Boolean" are kept as they are. The ".i" +command specifies the number of input variables, and the ".o" command +specifies the number of output variables. The ."ilb" command is used to +give the names of the input variables. The ".ob" command is used to give +the names of the output variables. These two commands are optional. +.pp +Below is a finite state machine description for the state assignment +problem. +.nf + + .i 3 + .o 5 + .s 4 + 0-- HG HG 00010 + -0- HG HG 00010 + 11- HG HY 10010 + --0 HY HY 00110 + --1 HY FG 10110 + 10- FG FG 01000 + 0-- FG FY 11000 + -1- FG FY 11000 + --0 FY FY 01001 + --1 FY HG 11001 + +.fi +Typical state assignment use is the following: +.nf + + % jedi -p fsm.kiss2 | espresso > fsm.pla + % misII + misII> read_pla -s fsm.pla + misII> source script + misII> print_stats -f + misII> write_blif fsm.blif + misII> quit + % + +.fi +.SH "ADDITIONAL COMMENT" +When reading in the encoded PLA after encoding, "read_pla -s" often +works better than "read_pla". The -s option reads in the PLA in a +collapsed single output single-level PLA form. +.SH "SEE ALSO" +misII(1OCTTOOLS), espresso(1OCTTOOLS) +.LP +Bill Lin and A. Richard Newton, "Synthesis of Multiple Level Logic from +Symbolic High-Level Description Languages", \fIProc. VLSI 89 Conference\fR, +Munich, West Germany, August 1989. +.SH "AUTHOR" +Please direct any questions or comments to: +.nf +Bill Lin +Cory Hall +Dept. of EECS +University of California +Berkeley, CA 94720 +email: billlin@ic.Berkeley.EDU +.fi diff --git a/jedi/jedi.c b/jedi/jedi.c new file mode 100644 index 0000000..9bf3ec7 --- /dev/null +++ b/jedi/jedi.c @@ -0,0 +1,84 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/jedi.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:07 $ + * + */ +/* + * Symbolic encoding program for compiling a symbolic + * description into a binary representation. Target + * is multi-level logic synthesis + * + * History: + * + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ + +#include "jedi.h" + +FILE *infp; /* input file pointer */ +FILE *outfp; /* output file pointer */ + +main(argc, argv) +int argc; +char **argv; +{ + /* + * parse options + */ + parse_options(argc, argv); + + /* + * read input from stdin + */ + if (kissFlag) { + read_kiss(infp, outfp); + } else { + read_input(infp, outfp); + } + + /* + * check if one hot + */ + if (hotFlag) { + write_one_hot(outfp); + (void) exit(0); + } + + /* + * compute weights + */ + if (!sequentialFlag && !srandomFlag && !drandomFlag) { + compute_weights(); + } + + /* + * solve the embedding problem + */ + if (srandomFlag || drandomFlag) { + random_embedding(); + } else if (clusterFlag) { + cluster_embedding(); + } else if (!sequentialFlag) { + opt_embedding(); + } + + if (kissFlag && !plaFlag) { + write_blif(outfp); + } else if (kissFlag && plaFlag) { + write_output(outfp); + } else { + write_output(outfp); + } + + (void) exit(0); +} /* end of main */ diff --git a/jedi/jedi.h b/jedi/jedi.h new file mode 100644 index 0000000..557133c --- /dev/null +++ b/jedi/jedi.h @@ -0,0 +1,89 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/jedi.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +/* + * Symbolic encoding program for compiling a symbolic + * description into a binary representation. Target + * is multi-level logic synthesis + * + * History: + * + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ + +#include "copyright.h" +#include "port.h" +#include "utility.h" + +#include "util.h" +#include "jedi_int.h" + +/* + * type declarations + */ +typedef struct Enumtype { + char *name; /* name of the enumerated type */ + int ns; /* number of symbols */ + int nb; /* number of bits for encoding */ + int nc; /* number of possible codes */ + Boolean input_flag; /* indicate input weights computed */ + Boolean output_flag; /* indicate output weights computed */ + char *dont_care; /* don't care bit-vector */ + struct Symbol *symbols; /* array of admissible values */ + struct Code *codes; /* array of possible codes */ + struct Link **links; /* connectivity matrix */ + int **distances; /* code distance matrix */ +} Enumtype; + +typedef struct Symbol { + char *token; /* mnemonic string */ + int code_ptr; /* pointer to current assigned code */ +} Symbol; + +typedef struct Code { + Boolean assigned; /* assigned flag */ + char *bit_vector; /* binary bit vector equivalent of decimal */ + int symbol_ptr; /* pointer to current assigned symbol */ +} Code; + +typedef struct Link { + int weight; /* weight of this link */ +} Link; + +typedef struct Variable { + char *name; /* name of the variable */ + Boolean boolean_flag; /* indicates a boolean type */ + int enumtype_ptr; /* pointer to enumtype type */ + struct Entry *entries; /* array of table entries */ +} Variable; + +typedef struct Entry { + char *token; /* mnemonic string */ + int enumtype_ptr; /* pointer to enumtype type */ + int symbol_ptr; /* pointer to symbol in enumtype */ +} Entry; + +/* + * global variables + */ +int ni; /* number of inputs */ +int no; /* number of outputs */ +int np; /* number of symbolic product terms */ +int ne; /* number of enumtype types */ +int tni; /* total number of binary inputs */ +int tno; /* total number of binary outputs */ +struct Enumtype *enumtypes; /* array of enumtypes */ +struct Variable *inputs; /* array of inputs */ +struct Variable *outputs; /* array of outputs */ diff --git a/jedi/jedi_int.h b/jedi/jedi_int.h new file mode 100644 index 0000000..b3408f5 --- /dev/null +++ b/jedi/jedi_int.h @@ -0,0 +1,67 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/jedi_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +/* + * Symbolic encoding program for compiling a symbolic + * description into a binary representation. Target + * is multi-level logic synthesis + * + * History: + * + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ + +/* + * constants + */ +#define INFINITY 100000 /* constant for infinity */ +#define BUFSIZE 512 /* buffer size */ +#define INPUT 0 /* input weighting */ +#define OUTPUT 1 /* output weighting */ +#define COUPLED 2 /* coupled weighting */ +#define MAXSPACE 8 /* maximum Boolean dimensions */ + +#define RELEASE "official release 1.2" +#define DATE "June 5, 1991" +#define HEADER "JEDI, official release 1.2 (compiled: June 5, 1991)" + +/* + * flags + */ +Boolean addDontCareFlag; /* fully specify the machine */ +Boolean bitsFlag; /* specify a kiss-style input */ +Boolean kissFlag; /* specify a kiss-style input */ +Boolean verboseFlag; /* display verbose information */ +Boolean sequentialFlag; /* run sequential encoding */ +Boolean clusterFlag; /* run cluster encoding */ +Boolean srandomFlag; /* run static random */ +Boolean drandomFlag; /* run dynamic random */ +Boolean variationFlag; /* variation of weight calculation */ +Boolean oneplaneFlag; /* compute weights only on one plane */ +Boolean hotFlag; /* one hot encoding */ +Boolean expandFlag; /* code expansion flag */ +Boolean plaFlag; /* output PLA format */ + +/* + * parameters + */ +double beginningStates; /* number of beginning states for SA */ +double endingStates; /* number of ending states for SA */ +double startingTemperature; /* starting temperature for SA */ +double maximumTemperature; /* maximum temperature for SA */ +int weightType; /* options for weighting type */ + +char *reset_state; /* reset state for state assignment */ +int code_length; /* code length for state assignemnt */ diff --git a/jedi/options.c b/jedi/options.c new file mode 100644 index 0000000..cc01008 --- /dev/null +++ b/jedi/options.c @@ -0,0 +1,169 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/options.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:07 $ + * + */ +/* + * Symbolic encoding program for compiling a symbolic + * description into a binary representation. Target + * is multi-level logic synthesis + * + * History: + * + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ + +#include +#include "jedi.h" + +int parse_options(); /* forward declaration */ + +extern FILE *infp; /* jedi.c */ +extern FILE *outfp; /* jedi.c */ + +usage() +{ + (void) fprintf(stderr, "usage: jedi [options] [input] \n"); + (void) fprintf(stderr, " -%s\t\t%s\n", "h", "print help message" ); + (void) fprintf(stderr, " -%s %s\t%s\n", "e", "option", "specify encoding option" ); + (void) fprintf(stderr, "\t\t%s\n", " r: random encoding" ); + + (void) fprintf(stderr, "\t\t%s\n", " h: one hot encoding" ); + + (void) fprintf(stderr, "\t\t%s\n", " d: dynamic random encoding" ); + (void) fprintf(stderr, "\t\t%s\n", " s: straightforward mapping" ); + (void) fprintf(stderr, "\t\t%s\n", " i: input dominant algorithm" ); + (void) fprintf(stderr, "\t\t%s\n", " o: output dominant algorithm (default)" ); + (void) fprintf(stderr, "\t\t%s\n", " c: coupled dominant algorithm" ); + (void) fprintf(stderr, "\t\t%s\n", " y: modified output dominant algorithm" ); + (void) fprintf(stderr, " -%s %s\t%s\n", "s", "length", "code length for state assignment" ); + (void) fprintf(stderr, " -%s\t\t%s\n", "x", "expand state code" ); + (void) fprintf(stderr, " -%s\t\t%s\n", "c", "use group based embedding algorithm" ); + (void) fprintf(stderr, " -%s\t\t%s\n", "p", "output in PLA format" ); + (void) fprintf(stderr, " -%s\t\t%s\n", "g", "general symbolic encoding format" ); + (void) fprintf(stderr, "\n"); + (void) fprintf(stderr, " [%s]\t%s\n", "input", "file to be processed (default stdin)" ); + (void) fprintf(stderr, "\n"); + (void) fprintf(stderr, "%s\n", HEADER ); + (void) fprintf(stderr, "\n"); + (void) exit(-1); +} + +parse_options(argc, argv) +int argc; +char **argv; +{ + extern int optind; + extern char *optarg; + int c; + + /* + * set defaults + */ + beginningStates = 1; + endingStates = 10; + startingTemperature = 1000; + maximumTemperature = INFINITY; + + bitsFlag = FALSE; + addDontCareFlag = TRUE; + kissFlag = TRUE; + verboseFlag = FALSE; + sequentialFlag = FALSE; + clusterFlag = FALSE; + srandomFlag = FALSE; + drandomFlag = FALSE; + variationFlag = TRUE; + oneplaneFlag = FALSE; + hotFlag = FALSE; + expandFlag = FALSE; + plaFlag = FALSE; + + weightType = OUTPUT; + + /* + * parse options + */ + while ((c=getopt(argc,argv,"hxcpge:s:"))!=EOF) { + switch(c) { + case 'h': + usage(); + break; + case 'e': + if (!strcmp(optarg, "s")) { + sequentialFlag = TRUE; + break; + } else if (!strcmp(optarg, "r")) { + srandomFlag = TRUE; + break; + } else if (!strcmp(optarg, "d")) { + drandomFlag = TRUE; + break; + } else if (!strcmp(optarg, "h")) { + hotFlag = TRUE; + break; + } else if (!strcmp(optarg, "i")) { + weightType = INPUT; + variationFlag = FALSE; + break; + } else if (!strcmp(optarg, "o")) { + weightType = OUTPUT; + variationFlag = TRUE; + break; + } else if (!strcmp(optarg, "c")) { + weightType = COUPLED; + variationFlag = TRUE; + break; + } else if (!strcmp(optarg, "y")) { + weightType = OUTPUT; + variationFlag = FALSE; + break; + } else { + usage(); + break; + } + case 's': + bitsFlag = TRUE; + code_length = atoi(optarg); + break; + case 'x': + expandFlag = TRUE; + break; + case 'c': + clusterFlag = TRUE; + break; + case 'p': + plaFlag = TRUE; + break; + case 'g': + kissFlag = FALSE; + break; + default: + usage(); + } + } + + /* + * check for sufficient arguments + */ + if (optind != argc && optind != argc-1) { + usage(); + } + + if (optind == argc) { + infp = stdin; + } else { + infp = my_fopen(argv[argc-1], "r"); + } + outfp = stdout; +} /* end of parse_options */ diff --git a/jedi/random.c b/jedi/random.c new file mode 100644 index 0000000..ba2e2a7 --- /dev/null +++ b/jedi/random.c @@ -0,0 +1,66 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/random.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:07 $ + * + */ +/* + * Symbolic encoding program for compiling a symbolic + * description into a binary representation. Target + * is multi-level logic synthesis + * + * History: + * + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ + +#include "jedi.h" + +random_embedding() +{ + int i, j; + int random_code; + long time(); + + /* + * generate random seed + */ + if (drandomFlag) { + srandom((int) time(NIL(long))); + } + + /* + * for each enumerated type + */ + for (i=0; i MAXSPACE) { + (void) fprintf(stderr, + "panic: type (%s) code length %d exceeds limit of %d.\n", + targv[1], nb, MAXSPACE); + } + nc = enumtypes[k].nc = pow_of_2(nb); + + enumtypes[k].input_flag = FALSE; + enumtypes[k].output_flag = FALSE; + + enumtypes[k].dont_care = ALLOC(char, nb + 1); + for (i=0; i %s", line); + } + } + + /* + * check to make sure a truth table was read in + */ + if (!iflag || !oflag || !itypeflag || !otypeflag) { + (void) fprintf(stderr, "jedi: unable to find input truth table\n"); + exit(1); + } + + /* + * determine total inputs and total outputs + */ + tni = 0; + for (i=0; i MAXSPACE) { + (void) fprintf(stderr, + "panic: type (%s) code length %d exceeds limit of %d.\n", + "States", nb, MAXSPACE); + } + + nc = enumtypes[0].nc = pow_of_2(nb); + enumtypes[0].input_flag = FALSE; + enumtypes[0].output_flag = FALSE; + + enumtypes[0].dont_care = ALLOC(char, nb + 1); + for (i=0; i %s", line); + } + } + + /* + * check to make sure a truth table was read in + */ + if (!iflag || !oflag || !sflag) { + (void) fprintf(stderr, "jedi: unable to find input truth table\n"); + exit(1); + } + + /* + * initialize connectivity matrix to be + * computed when the weights are computed + */ + enumtypes[0].links = ALLOC(struct Link *, enumtypes[0].ns); + for (i=0; i= 1.0) { + factor = log(new_temp)/log(start_temp); + } else { + factor = 0; + RangeSmall = SA_SMALL_RANGE; + } + + NewStatesPerUnit = StatesEnd - (StatesEnd - StatesBegin)*factor; + + return (new_temp); +} /* end of update_temp */ + + +accept_new_state(accept_state) +int (*accept_state)(); +{ + int ret_val; + + OldCost = NewCost; + ret_val = (*accept_state)(); + if (ret_val != SA_OK) { + (void) fprintf(Ferr, "Panic: error in accept new state function\n"); + (void) exit(1); + } +} /* end of accept_new_state */ + + +reject_new_state(reject_state) +int (*reject_state)(); +{ + int ret_val; + + ret_val = (*reject_state)(); + if (ret_val != SA_OK) { + (void) fprintf(Ferr, "Panic: error in reject new state function\n"); + (void) exit(1); + } +} /* end of reject_new_state */ + + +inner_loop_criterion(num_states_per_stage, num_states_generated) +int num_states_per_stage, num_states_generated; +{ + if (num_states_per_stage < num_states_generated) + return (TRUE); + else + return (FALSE); +} /* end of inner_loop_criterion */ + + +stopping_criterion(c1, c2, c3, c4, stop_temp, temp) +double c1, c2, c3, c4; +double stop_temp, temp; +{ + if (stop_temp < temp) + return (FALSE); + if ((c1 == c2) && (c1 == c3) && (c1 == c4)) + return (TRUE); + else + return (FALSE); +} /* end of stopping_criterion */ + + +double +find_starting_temp(starting_temperature, maximum_temperature) +double starting_temperature, maximum_temperature; +{ + double delta_c; + double start_temp; + + delta_c = 0.04 * OldCost; + start_temp = delta_c/log(1.25); + + if (starting_temperature != SA_DEFAULT_PARAMETER) { + start_temp = starting_temperature; + } + + if (maximum_temperature != SA_DEFAULT_PARAMETER) { + if (start_temp > maximum_temperature) { + start_temp = maximum_temperature; + } + } + + return (start_temp); +} /* end of find_starting_temp */ + + +double determine_cost(cost_function) +int (*cost_function)(); +{ + int ret_val; + double cost = 0.0; + + ret_val = (*cost_function)(&cost); + if (ret_val != SA_OK) { + (void) fprintf(Ferr, "Panic: error in determine cost function\n"); + (void) exit(1); + } + + return (cost); +} /* end of determine_cost */ + + +generate_new_state(range, generate_function) +int range; +int (*generate_function)(); +{ + int ret_val; + + ret_val = (*generate_function)(range); + if (ret_val != SA_OK) { + (void) fprintf(Ferr, "Panic: error in generate new state function\n"); + (void) exit(1); + } +} /* end of generate_new_state */ + + +double +random_generator(left,right) +int left,right; +{ + double range, divide, rnum, number; + + rnum = (double) random(); + divide = 2147483647; + number = rnum/divide; + range = (double) right - left; + number = number*range + left; + + return(number); + +} /* end of random_generator */ + + +int int_random_generator(x,y) +int x, y; +{ + int i; + + i = (int) floor(random_generator(x,y+1)); + if (i > y) { + return y; + } else { + return i; + } +} /* end of int_random_generator */ diff --git a/jedi/rp.h b/jedi/rp.h new file mode 100644 index 0000000..fe2fab8 --- /dev/null +++ b/jedi/rp.h @@ -0,0 +1,35 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/rp.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +/* + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ + +#define SA_ERROR 0 +#define SA_OK 1 +#define SA_FULL_RANGE 2 +#define SA_SMALL_RANGE 3 +#define SA_DEFAULT_PARAMETER -1.0 + +#define SA_ASSERT(fct)\ + if ((fct) != SA_OK) {\ + fprintf(stderr, "SA Assertion failed: file %s, line %d\n",\ + __FILE__, __LINE__);\ + exit(-1);\ + } + +void combinatorial_optimize(); +double random_generator(); +int int_random_generator(); diff --git a/jedi/rp_int.h b/jedi/rp_int.h new file mode 100644 index 0000000..9c73d62 --- /dev/null +++ b/jedi/rp_int.h @@ -0,0 +1,40 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/rp_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +/* + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ + +/* + * constants + */ +#define TRUE 1 +#define FALSE 0 +#define BUF_SIZE 100 + +/* + * global variables + */ +FILE *Fin; +FILE *Fout; +FILE *Ferr; +int RangeSmall; +int Verbose; +double OldCost; +double NewCost; +double StatesBegin; +double StatesEnd; +double Alpha; +double NewStatesPerUnit; diff --git a/jedi/util.c b/jedi/util.c new file mode 100644 index 0000000..a96dfe4 --- /dev/null +++ b/jedi/util.c @@ -0,0 +1,126 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +/* + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ + +#include "jedi.h" + +int distance(); /* forward declaration */ +char *int_to_binary(); /* forward declaration */ +int binary_to_int(); /* forward declaration */ +int parse_line(); /* forward declaration */ +FILE *my_fopen(); /* forward declaration */ + +int distance(code1, code2, width) +char *code1, *code2; +int width; +{ + int dist; + int pdist; + int i; + + dist = 0; pdist = 0; + for (i=0; i=0; i--) { + if (j & 1) { + buffer[i] = '1'; + } else { + buffer[i] = '0'; + } + j = j >> 1; + } + + return buffer; +} /* end of int_to_binary */ + + +int binary_to_int(binary, width) +char *binary; +int width; +{ + int i, total; + int mask; + + total = 0; + mask = 1; + for (i=width-1; i>=0; i--) { + if (binary[i] == '1') { + total = total | mask; + } + mask = mask << 1; + } + + return total; +} /* end of binary_to_int */ + + +parse_line(line) +register char *line; +{ + register char **carg = targv; + register char ch; + + targc = 0; + while (ch = *line++) { + if (ch <= ' ') continue; + targc++; + *carg++ = line-1; + while ((ch = *line) && ch > ' ' ) line++; + if (ch) *line++ = '\0'; + } + *carg = 0; +} /* end of parse_line */ + + +FILE *my_fopen(fname, mode) +char *fname; +char *mode; +{ + FILE *fp; + + if ((fp = fopen(fname, mode)) == NULL) { + (void) fprintf(stderr, + "error: couldn't open file %s under mode (%s)\n", + fname, mode); + exit(1); + } + + return fp; +} /* end of my_fopen */ diff --git a/jedi/util.h b/jedi/util.h new file mode 100644 index 0000000..be3bba6 --- /dev/null +++ b/jedi/util.h @@ -0,0 +1,44 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/util.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +/* + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ + +/* + * useful types + */ +typedef int Boolean; + +/* + * useful macros + */ + +#define TRUE 1 +#define FALSE 0 + +#define pow_of_2(x) (int) pow((double) 2, (double) x) + +/* + * token holders for parse_line + */ +char *targv[5000]; /* pointer to tokens */ +int targc; /* number of tokens */ + +/* + * forward declarations + */ +char *int_to_binary(); /* converts decimal to binary */ +FILE *my_fopen(); /* opens a file */ diff --git a/jedi/weights.c b/jedi/weights.c new file mode 100644 index 0000000..c30d2ab --- /dev/null +++ b/jedi/weights.c @@ -0,0 +1,451 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/jedi/weights.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +/* + * Bill Lin + * University of California, Berkeley + * Comments to billlin@ic.Berkeley.EDU + * + * Copyright (c) 1989 Bill Lin, UC Berkeley CAD Group + * Permission is granted to do anything with this + * code except sell it or remove this message. + */ +#include "jedi.h" + +int compute_weights(); /* forward declaration */ +int add_input_weights(); /* forward declaration */ +int add_output_weights(); /* forward declaration */ +int add_normal_inputs(); /* forward declaration */ +int add_normal_outputs(); /* forward declaration */ +int add_variation_inputs(); /* forward declaration */ +int add_variation_outputs(); /* forward declaration */ +int normal_input_proximity(); /* forward declaration */ +int normal_output_proximity(); /* forward declaration */ + +compute_weights() +{ + int i, e; + + if (verboseFlag) { + (void) fprintf(stderr, "computing weights ...\n"); + } + + /* + * only compute weights if the variable + * is not a boolean + */ + if (weightType == OUTPUT) { + for (i=0; i, 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 + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; +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] + +Send bug reports to ." + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is $msg. 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) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is $msg. 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) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is $msg. 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*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is $msg. 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 + ;; + + autom4te) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. 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 $msg. 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) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is $msg. 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 $msg. 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 "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && 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 is $msg. + 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 prerequisites 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 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/nova/Makefile.am b/nova/Makefile.am new file mode 100644 index 0000000..5fd8e4e --- /dev/null +++ b/nova/Makefile.am @@ -0,0 +1,12 @@ +AM_CPPFLAGS = -I$(top_srcdir)/port -I../sis/include +LDADD = ../sis/libsis.a -lm + +bin_PROGRAMS = nova +nova_SOURCES = alloc.c anneal_code.c auxil.c coloring.c comb_objects.c \ + exact_backtrack.c exact_code.c exact_graph.c exact_lbound.c \ + exact_mini.c exact_output.c get_constr.c ihybrid_code.c input_fsm.c \ + iohybrid_code.c iovariant_code.c log_approx.c log_code.c log_mini.c \ + log_output.c log_precode.c log_sel.c lower_bound.c nova.c nova_summ.c \ + options.c out_encoder.c out_eval.c show.c symbolic_loop.c user_codes.c \ + analisi.h decls.h nova.h oldport.h out_encoder.h +dist_man1_MANS = nova.1 diff --git a/nova/Makefile.in b/nova/Makefile.in new file mode 100644 index 0000000..5bee73f --- /dev/null +++ b/nova/Makefile.in @@ -0,0 +1,462 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(nova_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = nova$(EXEEXT) +subdir = nova +DIST_COMMON = $(dist_man1_MANS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_nova_OBJECTS = alloc.$(OBJEXT) anneal_code.$(OBJEXT) \ + auxil.$(OBJEXT) coloring.$(OBJEXT) comb_objects.$(OBJEXT) \ + exact_backtrack.$(OBJEXT) exact_code.$(OBJEXT) \ + exact_graph.$(OBJEXT) exact_lbound.$(OBJEXT) \ + exact_mini.$(OBJEXT) exact_output.$(OBJEXT) \ + get_constr.$(OBJEXT) ihybrid_code.$(OBJEXT) \ + input_fsm.$(OBJEXT) iohybrid_code.$(OBJEXT) \ + iovariant_code.$(OBJEXT) log_approx.$(OBJEXT) \ + log_code.$(OBJEXT) log_mini.$(OBJEXT) log_output.$(OBJEXT) \ + log_precode.$(OBJEXT) log_sel.$(OBJEXT) lower_bound.$(OBJEXT) \ + nova.$(OBJEXT) nova_summ.$(OBJEXT) options.$(OBJEXT) \ + out_encoder.$(OBJEXT) out_eval.$(OBJEXT) show.$(OBJEXT) \ + symbolic_loop.$(OBJEXT) user_codes.$(OBJEXT) +nova_OBJECTS = $(am_nova_OBJECTS) +nova_LDADD = $(LDADD) +nova_DEPENDENCIES = ../sis/libsis.a +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(nova_SOURCES) +DIST_SOURCES = $(nova_SOURCES) +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(dist_man1_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I$(top_srcdir)/port -I../sis/include +LDADD = ../sis/libsis.a -lm +nova_SOURCES = alloc.c anneal_code.c auxil.c coloring.c comb_objects.c \ + exact_backtrack.c exact_code.c exact_graph.c exact_lbound.c \ + exact_mini.c exact_output.c get_constr.c ihybrid_code.c input_fsm.c \ + iohybrid_code.c iovariant_code.c log_approx.c log_code.c log_mini.c \ + log_output.c log_precode.c log_sel.c lower_bound.c nova.c nova_summ.c \ + options.c out_encoder.c out_eval.c show.c symbolic_loop.c user_codes.c \ + analisi.h decls.h nova.h oldport.h out_encoder.h + +dist_man1_MANS = nova.1 +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps nova/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps nova/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +nova$(EXEEXT): $(nova_OBJECTS) $(nova_DEPENDENCIES) + @rm -f nova$(EXEEXT) + $(LINK) $(nova_LDFLAGS) $(nova_OBJECTS) $(nova_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-man + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: install-man1 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am uninstall-man + +uninstall-man: uninstall-man1 + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-man1 \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-info-am uninstall-man uninstall-man1 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/nova/alloc.c b/nova/alloc.c new file mode 100644 index 0000000..d3a129e --- /dev/null +++ b/nova/alloc.c @@ -0,0 +1,494 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/alloc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +/*************************************************************************** +* ALLOCATES MEMORY * +***************************************************************************/ + + +#include "nova.h" + +newinputrow (input,pstate,nstate,output) +char *input; +char *pstate; +char *nstate; +char *output; + +{ + INPUTTABLE *new; + + if ( (new = (INPUTTABLE *) calloc((unsigned)1,sizeof(INPUTTABLE))) == (INPUTTABLE *) 0) { + fprintf(stderr,"Insufficient memory for inputtable"); + exit(-1); + } + + + if ( (new->input = (char *) calloc((unsigned)strlen(input)+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for inputtable->input"); + exit(-1); + } + + if ( (new->pstate = (char *) calloc((unsigned)strlen(pstate)+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for inputtable->pstate"); + exit(-1); + } + + if ( (new->nstate = (char *) calloc((unsigned)strlen(nstate)+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for inputtable->nstate"); + exit(-1); + } + + if ( (new->output = (char *) calloc((unsigned)strlen(output)+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for inputtable->output"); + exit(-1); + } + + strcpy(new->input,input); + strcpy(new->pstate,pstate); + strcpy(new->nstate,nstate); + strcpy(new->output,output); + + new->acc = 0; + + if (firstable == (INPUTTABLE *) 0) { + firstable = new; + } else { + lastable->next = new; + } + lastable = new; + + +} + + + + +CONSTRAINT *newconstraint(relation,card,level) +char *relation; +int card; +int level; + +{ + CONSTRAINT *new; + + if ( (new = (CONSTRAINT *) calloc((unsigned)1,sizeof(CONSTRAINT))) == (CONSTRAINT *) 0) { + fprintf(stderr,"Insufficient memory for constraint"); + exit(-1); + } + + if ( (new->relation = (char *) calloc((unsigned)strlen(relation)+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for constraint->relation"); + exit(-1); + } + strcpy(new->relation,relation); + + if ( (new->next_states = (char *) calloc((unsigned)strlen(relation)+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for constraint->next_states"); + exit(-1); + } + + new->face = ""; + + new->weight = 1; + new->level = level; + new->newlevel = level; + new->card = card; + + new->attribute = NOTUSED; + new->odd_type = NOTADMITTED; + new->source_type = INPUT; + + new->levelnext = (CONSTRAINT *) 0; + new->cardnext = (CONSTRAINT *) 0; + new->next = (CONSTRAINT *) 0; + + return (new); + +} + + + +newcode(code,which_element,symbleme_type) +char *code; +int which_element; +SYMBLEME *symbleme_type; + +{ + CODE *new; + + if ( (new = (CODE *) calloc((unsigned)1,sizeof(CODE))) == (CODE *) 0) { + fprintf(stderr,"Insufficient memory for code"); + exit(-1); + } + + if ( (new->value = (char *) calloc((unsigned)strlen(code)+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for code->value"); + exit(-1); + } + + new->value[strlen(code)] = '\0'; + + strcpy(new->value,code); + + new->next = symbleme_type[which_element].vertices; + + symbleme_type[which_element].vertices = new; + + +} + + + +CONSTRAINT_E *newconstraint_e(relation,card) +char *relation; +int card; + +{ + CONSTRAINT_E *new; + + if ( (new = (CONSTRAINT_E *) calloc((unsigned)1,sizeof(CONSTRAINT_E))) == (CONSTRAINT_E *) 0) { + fprintf(stderr,"Insufficient memory for constraint"); + exit(-1); + } + + if ( (new->relation = (char *) calloc((unsigned)strlen(relation)+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for constraint->relation"); + exit(-1); + } + strcpy(new->relation,relation); + + new->weight = 1; + new->card = card; + + new->up_ptr = (FATHERS_LINK *) 0; + new->down_ptr = (SONS_LINK *) 0; + new->next = (CONSTRAINT_E *) 0; + new->face_ptr = (FACE *) 0; + + return (new); + +} + + + +array_alloc() + +{ + int i,max_codelength,num_codes; + + if (ISYMB) { + symblemenum = max(statenum,inputnum); + } else { + symblemenum = statenum; + } + + if ( (states = (SYMBLEME *) calloc((unsigned)statenum,sizeof(SYMBLEME))) == (SYMBLEME *) 0) { + fprintf(stderr,"Insufficient memory for states"); + exit(-1); + } + + for (i=0; ielement = (char *) calloc((unsigned)strlen(element)+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for outsymbol->element"); + exit(-1); + } + + new->element[strlen(element)] = '\0'; + + strcpy(new->element,element); + + new->nlab = lab; + + new->card = 1; + + new->selected = 0; + + new->next = outsymbol_list; + + outsymbol_list = new; + + +} + + + +new_order_relation(row,column) +int row; +int column; + +{ + ORDER_RELATION *new; + + if ( (new = (ORDER_RELATION *) calloc((unsigned)1,sizeof(ORDER_RELATION))) == (ORDER_RELATION *) 0) { + fprintf(stderr,"Insufficient memory for order_relation"); + exit(-1); + } + + new->index = column; + + new->next = order_graph[row]; + + order_graph[row] = new; + +} + + + +new_order_path(row,column) +int row; +int column; + +{ + ORDER_PATH *new; + + if ( (new = (ORDER_PATH *) calloc((unsigned)1,sizeof(ORDER_PATH))) == (ORDER_PATH *) 0) { + fprintf(stderr,"Insufficient memory for order_path"); + exit(-1); + } + + new->dest = column; + + new->next = path_graph[row]; + + path_graph[row] = new; + +} + + + +IMPLICANT *newimplicant(row,state) +char *row; +int state; + +{ + IMPLICANT *new; + + if ( (new = (IMPLICANT *) calloc((unsigned)1,sizeof(IMPLICANT))) == (IMPLICANT *) 0) { + fprintf(stderr,"Insufficient memory for implicant"); + exit(-1); + } + + if ( (new->row = (char *) calloc((unsigned)strlen(row)+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for implicant->row"); + exit(-1); + } + strcpy(new->row,row); + + new->state = state; + new->attribute = NOTUSED; + + new->next = (IMPLICANT *) 0; + + return (new); + +} + + + +/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ + + +array_alloc2() + +{ + + int i; + + if ( (order_graph = (ORDER_RELATION **) calloc((unsigned)statenum,sizeof(ORDER_RELATION *))) == (ORDER_RELATION **) 0) { + fprintf(stderr,"Insufficient memory for order_graph"); + exit(-1); + } + + for ( i = 0; i < statenum; i++ ) { + order_graph[i] = ( ORDER_RELATION *) 0; + } + + if ( (path_graph = (ORDER_PATH **) calloc((unsigned)statenum,sizeof(ORDER_PATH *))) == (ORDER_PATH **) 0) { + fprintf(stderr,"Insufficient memory for order_graph"); + exit(-1); + } + + for ( i = 0; i < statenum; i++ ) { + path_graph[i] = ( ORDER_PATH *) 0; + } + + if ( (reached = (int *) calloc((unsigned)statenum,sizeof(int ))) == (int *) 0) { + fprintf(stderr,"Insufficient memory for array 'reached'"); + exit(-1); + } + for ( i = 0; i < statenum; i++ ) { + reached[i] = 0; + } + + if ( (order_array = (char **) calloc((unsigned)statenum,sizeof(char *))) == (char **) 0) { fprintf(stderr,"Insufficient memory for 'order_array'"); exit(-1); } + for ( i = 0; i < statenum; i++ ) { + if ( (order_array[i] = (char *) calloc((unsigned)statenum+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for order_array[i]"); + exit(-1); + } + order_array[i][statenum] = '\0'; + } + + if ( (gain_array = (int *) calloc((unsigned)statenum,sizeof(int ))) == (int *) 0) { + fprintf(stderr,"Insufficient memory for gain_array"); + exit(-1); + } + for ( i = 0; i < statenum; i++ ) { + gain_array[i] = 0; + } + + if ( (select_array = (int *) calloc((unsigned)statenum,sizeof(int ))) == (int *) 0) { + fprintf(stderr,"Insufficient memory for select_array"); + exit(-1); + } + for ( i = 0; i < statenum; i++ ) { + select_array[i] = PRUNED; + } + +} diff --git a/nova/analisi.h b/nova/analisi.h new file mode 100644 index 0000000..3764d51 --- /dev/null +++ b/nova/analisi.h @@ -0,0 +1,85 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/analisi.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +typedef struct espterm { /* product terms in minimized file */ + + char *input; + char *output; + char *nstate; + char *poutput; + struct espterm *next; + +} ESPTERM; + +typedef struct termlink { /* list of product terms */ + + char *input; /* input and output parts of the product term */ + char *output; + char *nstate; + char *poutput; + struct termlink *next; + +} TERMLINK; + +typedef struct translink { + + char *input; /* fields of the transition */ + char *pstate; + char *nstate; + char *output; + int ilab; + int plab; + int nlab; + struct translink *next; + +} TRANSLINK; + +typedef struct coverlink { /* list of product terms/covered transitions */ + + char *input; /* input and output parts of the product term */ + char *output; + TRANSLINK *ccovered; /* list of transitions completely covered */ + TRANSLINK *pcovered; /* list of transitions partially covered */ + struct coverlink *next; + +} COVERLINK; + +typedef struct orlink { /* list of transitions/ored next states */ + + char *input; /* fields of the transitions */ + char *pstate; + char *nstate; + char *output; + TERMLINK *orstate; /* list of ored product terms */ + struct orlink *next; + +} ORLINK; + +typedef struct codex { + + char *code; /* code to analyze */ + char *state; /* name of the state */ + TRANSLINK *transnull; /* list transitions not implemented */ + COVERLINK *cover; /* list of product terms/covered transitions */ + ORLINK *oring; /* list ored transitions */ + +} CODEX; + + +/* GLOBAL VARIABLES */ + +extern ESPTERM *esptable; /* pointer to esp file product terms */ +extern CODEX *codici; /* array of states/codes descriptors */ +extern int codexnum; /* number of next state binary patterns */ +extern int espterm_card; /* number of product terms of minimized implem. */ +extern int espinp_card; /* number of binary inputs of minimized implem. */ +extern int espout_card; /* number of binary outputs of minimized implem. */ +extern int nulltrans_card;/* number of product terms saved for zero effect */ +extern int mvtrans_card; /* number of product terms saved for join effect */ +extern int ortrans_card; /* number of product terms saved for oring effect */ diff --git a/nova/anneal_code.c b/nova/anneal_code.c new file mode 100644 index 0000000..96e07ec --- /dev/null +++ b/nova/anneal_code.c @@ -0,0 +1,680 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/anneal_code.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +#include "nova.h" +#undef ZERO +#undef ONE +#undef DASH +#include "espresso.h" +#define NIL(type) ((type *) 0) + + +/**********************************************************************/ +/* outline of the procedure simulated annealing */ +/* */ +/* INITIALIZE(state(0),temp(0),moves(0)); */ +/* */ +/* k = 0; */ +/* state = state(0); */ +/* */ +/* while (stopcriterion is unsatisfied) { */ +/* move_count = MOVES(k); */ +/* temp = TEMPERATURE(k); */ +/* for (l = 1; l <= move_count; l++) { */ +/* GENERATE(newstate from neighbours of oldstate); */ +/* if (cost(newstate) <= cost(oldstate) oldstate = newstate; */ +/* else if (exp( (cost(oldstate)-cost(newstate))/temp ) > */ +/* random(0,1) oldstate = newstate; */ +/* } */ +/* k++; */ +/* } */ +/**********************************************************************/ + +#define DISPLACEMENT 1 +#define INTERCHANGE 2 + +double STATES_BEGIN, STATES_END; +double ALPHA, START_TEMP; +int init_cost; +int codes_num; +int num1,num2; +static int do_single_expand = 1; +static int new_cost = 0; +static int best_cost = 0; +static int accepted = 0; +static int attempted = 0; +extern int num_moves; +static pcover constr_sf; +HYPERVERTEX *vertices; + +int +anneal_code(net,simboli,node_num,codelength) +CONSTRAINT *net; +SYMBLEME *simboli; +int node_num; +int codelength; + +{ +/* +* Solve face hypercube embedding for a given dimension of the cube +*/ + + CONSTRAINT *constrptr; + int c1, c2, c3, start_cost, add, i, card,size; + double temp, update_temp(), find_starting_temp(); + int cur_gen, max_gen; + int try, type; + pset constr, p, last; + + + single_expand = do_single_expand; + codes_num = power(2,codelength); + vert_alloc(codelength); + + if (cost_function == 1) { + if (net == NIL(CONSTRAINT)) { + constr_sf = sf_new (0, 1); + } + else { + card = strlen (net->relation); + define_cube_size (card); + constr_sf = sf_new (0, 2 * card); + constr = set_new (2 * card); + for (constrptr = net; constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + for (i = 0; i < card; i++) { + switch (constrptr->relation[i]) { + case '0': + PUTINPUT (constr, i, ZERO); + break; + case '1': + PUTINPUT (constr, i, ONE); + break; + default: + PUTINPUT (constr, i, TWO); + break; + } + } + add = 1; + foreach_set (constr_sf, last, p) { + /*if (cdist0 (constr, p)) {PATCH*/ + if (setp_implies(constr, p)) { + set_and (p, p, constr); + size = SIZE (p); + PUTSIZE (p, (size + 1)); + add = 0; + break; + } + } + if (add) { + PUTSIZE (constr, 1); + sf_addset (constr_sf, constr); + } + } + set_free (constr); + if (DEBUG) { + fprintf (stdout, "Constraints:\n"); + cprint (constr_sf); + } + } + define_cube_size (codelength); + } + assign_initial_encoding(simboli,node_num,codelength); + if (net == (CONSTRAINT *) 0) { + if (DEBUG) { + printf("Best codes (cost = %d):\n", best_cost); + show_bestcode(simboli,node_num); + } + return best_cost; + } + START_TEMP = find_starting_temp(net,simboli,codelength); + ALPHA = 0.90; + + STATES_BEGIN = STATES_END = num_moves; + c1 = init_cost - 30; + c2 = init_cost - 20; + c3 = init_cost - 10; + max_gen = STATES_BEGIN * node_num; + temp = START_TEMP; + if (DEBUG) { + printf("\n# Initial temperature %f, cost is %d, moves are %d\n", + temp,init_cost,max_gen); + } + while (temp > 0.0 && + ( c1 != init_cost || c2 != init_cost || c3 != init_cost)) { + cur_gen = 0; start_cost = init_cost; + accepted = attempted = 0; + while (cur_gen < max_gen) { + cur_gen++; + try = generate_state(simboli,&type); + if (try) + + accept_or_reject_state(net,simboli,codelength,node_num,temp,type); + + } + temp = update_temp(temp, &max_gen, node_num); + if (DEBUG) { + printf("\n# Changing temperature to %f, cost is %d, moves are %d\n", + temp,init_cost,max_gen); + } + c1 = c2; c2 = c3; c3 = start_cost; + } + if (DEBUG) { + printf("# Final cost is %d\n",init_cost); + printf("# Minimum cost is %d\n",best_cost); + printf("Final codes :\n"); + show_code(simboli,node_num); + if (best_cost < init_cost) { + printf("Best codes :\n"); + show_bestcode(simboli,node_num); + } + } + + single_expand = 0; + if (constr_sf != NIL(set_family_t)) { + sf_free (constr_sf); + } + return best_cost; + +} /* end of simulated_anneal */ + + + +assign_initial_encoding(simboli,node_num,codelength) +SYMBLEME *simboli; +int node_num; +int codelength; +{ +/* +* Assign nodes initial encodings prior to annealing +*/ + + long time(); + int i,new_code,increment,range,seed,trandom(); + + /* seed = (int) time(0); */ + seed = 0; + srand(seed); + srandom(seed); + + /* random codes the states */ + range = minpow2(node_num); + new_code = trandom(range); + increment = trandom(range)*2 + 1; + for (i = 0; i < node_num; i++) { + itob(simboli[i].code,new_code,codelength); + strcpy(simboli[i].best_code,simboli[i].code); + vertices[code_index(simboli[i].code)].label = i; + new_code = (new_code + increment) % range; + } + /*if (DEBUG) printf("Initial codes :\n"); + show_code(simboli,node_num);*/ + +} /* end of assign_initial_encoding */ + +int trandom(range) /* returns a random integer in the interval (0,range) */ +int range; +{ + int result,rand(); + + result = rand() % range; + return(result); +} + + + +generate_state(simboli,type) +SYMBLEME *simboli; +int *type; +{ +/* +* randomly generate an interchange or a displacement +*/ + + double PRANDOM(); + int stato1,stato2; + + + /* codes_num is the number of possible encodings = 2**code_bits */ + /* num1 e num2 sono due codici scelti a caso tra tutti i possibili */ + num1 = PRANDOM(0,codes_num); + num2 = PRANDOM(0,codes_num); + if (num1 is num2 || num1 is codes_num || num2 is codes_num) return(FALSE); + if (vertices[num1].label == -1 && vertices[num2].label == -1) + return FALSE; + if (vertices[num1].label == -1) { + *type = DISPLACEMENT; + /* swap the code of stato2 with that of num1 to find the new cost */ + stato2 = vertices[num2].label; + strcpy(simboli[stato2].code,vertices[num1].code); + vertices[num1].label = stato2; + vertices[num2].label = -1; + return(TRUE); + } + else if (vertices[num2].label == -1) { + *type = DISPLACEMENT; + /* swap the code of stato1 with that of num2 to find the new cost */ + stato1 = vertices[num1].label; + strcpy(simboli[stato1].code,vertices[num2].code); + vertices[num1].label = -1; + vertices[num2].label = stato1; + return(TRUE); + } + else { + *type = INTERCHANGE; + /* interchange the codes between stato1 and stato2 to find the new cost */ + stato1 = vertices[num1].label; + stato2 = vertices[num2].label; + strcpy(simboli[stato1].code,vertices[num2].code); + strcpy(simboli[stato2].code,vertices[num1].code); + vertices[num1].label = stato2; + vertices[num2].label = stato1; + return(TRUE); + } + +} /* end of generate_state */ + + +double +PRANDOM(left,right) +int left,right; +{ + + long divide, random_num; +#if !defined(__osf__) +#endif + double number; + + random_num = random(); + divide = 2147483647; + number = ((double)random_num)/divide; + number = number*abs(right - left) + left ; + + return(number); + +} /* end of PRANDOM */ + + +double +find_starting_temp(net,simboli,codelength) +CONSTRAINT *net; +SYMBLEME *simboli; +int codelength; +{ + + double delta_c, temp; + int find_cost(); +/* +* Let's not accept a move which increases the initial cost by more than +* X percent. +*/ + + init_cost = find_cost(net,simboli,codelength); + best_cost = init_cost; + delta_c = 0.04 * (double)init_cost; + temp = delta_c/log(1.25) ; + return(temp); + +} /* end of find_starting_temp */ + + +int +find_cost(net,simboli,codelength) +CONSTRAINT *net; +SYMBLEME *simboli; +int codelength; +{ +/* +* find the cost of the given encoding as sum of the weights of the +* unsatisfied constraints +*/ + + CONSTRAINT *constrptr; + char *face; + char bit1; + int i,j,card,satisfied; + int sat_measure,unsat_measure; + int cost, count; + static int call_count = 0; + pcover F, D, R, codes; + pset p, last, pnew, p1, last1; + + call_count ++; + cost = 0; + + cost = init_cost; + + + /* empty net : do nothing */ + if (net == (CONSTRAINT *) 0) { + return 0; + } + + sat_measure = unsat_measure = 0; + + card = strlen(net->relation); + if (cost_function == 1) { + pnew = set_new (codelength * 2); + /* create the codes as set family */ + codes = sf_new (card, codelength * 2); + for ( j = 0; j < card; j++) { + for (i = 0; i < codelength; i++) { + switch (simboli[j].code[i]) { + case '1': + PUTINPUT (pnew, i, ONE); + break; + case '0': + PUTINPUT (pnew, i, ZERO); + break; + default: + fprintf (stderr,"invalid code value\n"); + exit(-1); + } + } + sf_addset (codes, pnew); + } + foreach_set (constr_sf, last1, p1) { + /* insert the codes in the appropriate set family */ + F = sf_new (card, codelength * 2); + R = sf_new (card, codelength * 2); + + for ( j = 0; j < card; j++) { + set_copy (pnew, GETSET (codes, j)); + switch (GETINPUT (p1, j)) { + case ONE: + sf_addset (F, pnew); + break; + case ZERO: + sf_addset (R, pnew); + break; + } + } + + D = complement (cube2list (F, R)); + F = espresso (F, D, R); + + /* now count the literals */ + count = 0; + foreach_set (F, last, p) { + count += 2 * codelength - set_ord (p); + } + unsat_measure += SIZE (p1) * count; + sf_free (F); + if (cost_function == 1) { + sf_free (D); + } + sf_free (R); + } + sf_free (codes); + set_free (pnew); + } + else { + /*shownet(net); + exit(-1);*/ + + if ((face = (char *) calloc((unsigned)codelength+1,sizeof(char))) == (char *) 0) { + } + + /* scans all constraints */ + for (constrptr = net; constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + + /*printf("The constraint is %s\n", constrptr->relation);*/ + + /* scans all boolean coordinates */ + for (i = 0; i < codelength; i++) { + + /* stores in bit1 the "i-th" bit of the best_code of the "j-th" + symbleme ( which belongs to the current constraint ) */ + for ( j = 0; j < card; j++) { + if ( constrptr->relation[j] == '1' ) { + bit1 = simboli[j].code[i]; + } + } + + /* if there are two symblemes in the current constraint different + on the i-th boolean coordinate face[i] gets a * (don't care) + otherwise face[i] gets the common coordinate value */ + for ( j = 0; j < card; j++) { + if ( constrptr->relation[j] == '1' ) { + if ( bit1 != simboli[j].code[i]) { + face[i] = '*'; + break; + } else { + face[i] = bit1; + } + } + } + + } + + /*printf("the spanned face is %s\n", face);*/ + + /* if the code of any other symbleme ( i.e. a symbleme not + contained in constraint ) is covered by face , the current + constraint has not been satisfied */ + for (j = 0; j < card; j++) { + if ( constrptr->relation[j] == '0' ) { + if (inclusion(simboli[j].code,face,codelength) == 1) { + /*printf("the symbleme %s (%d) is covered by face %s\n",simboli[j].name, j, face);*/ + satisfied = 0; + /*printf("UNSATISFIED\n");*/ + break; + } + } + } + /* no other constraint covered by face */ + if (j == card) { + satisfied = 1; + /*printf("SATISFIED\n");*/ + } + if (satisfied == 0) { + unsat_measure = unsat_measure + constrptr->weight; + } + if (satisfied == 1) { + sat_measure = sat_measure + constrptr->weight; + } + + } + } + + if (DEBUG) printf("\nGain = %d ; Cost = %d\n", sat_measure, unsat_measure); + cost = unsat_measure; + + return(cost); + +} /* end of find_cost */ + + +should_accept(change_in_cost, temp) +int change_in_cost; +double temp; +{ + + double R,Y,PRANDOM(); + + + if (change_in_cost < 0) + return(TRUE); + else { + Y = exp(- (double)change_in_cost/temp); + R = PRANDOM(0,1); + if (R < Y) + return(TRUE); + else + return(FALSE); + } + +} /* end of should_accept */ + + +accept_or_reject_state(net,simboli,codelength,node_num,temp,type) +CONSTRAINT *net; +SYMBLEME *simboli; +int codelength; +int node_num; +double temp; +int type; +{ + + int find_cost(); + int i,stato1,stato2; + + new_cost = find_cost(net,simboli,codelength); + if (best_cost > new_cost) { /* save the best codes found so far */ + best_cost = new_cost; + for (i = 0; i < node_num; i++) { + strcpy(simboli[i].best_code,simboli[i].code); + } + } + attempted++; + if (should_accept(new_cost-init_cost, temp) is TRUE) { + accepted++; + if (DEBUG) printf("Move accepted\n"); + init_cost = new_cost; + } else { + if (type is DISPLACEMENT) { + if (vertices[num1].label == -1) { + /* swap the code of stato2 with that of num1 to undo last move */ + stato2 = vertices[num2].label; + strcpy(simboli[stato2].code,vertices[num1].code); + vertices[num1].label = stato2; + vertices[num2].label = -1; + return(TRUE); + } + else if (vertices[num2].label == -1) { + /* swap the code of stato1 with that of num2 to undo last move */ + stato1 = vertices[num1].label; + strcpy(simboli[stato1].code,vertices[num2].code); + vertices[num1].label = -1; + vertices[num2].label = stato1; + return(TRUE); + } + } else if (type is INTERCHANGE) { + /* interchange the codes between stato1 and stato2 to undo last move */ + stato1 = vertices[num1].label; + stato2 = vertices[num2].label; + strcpy(simboli[stato1].code,vertices[num2].code); + strcpy(simboli[stato2].code,vertices[num1].code); + vertices[num1].label = stato2; + vertices[num2].label = stato1; + } + } + + return FALSE; + +} /* end of accept_or_reject_state */ + + + +double +update_temp(temp, new_states, node_num) +double temp; +int *new_states; +int node_num; +{ + + double new_temp,factor; + + if (sqrt(START_TEMP) < temp ) + new_temp = temp*ALPHA*ALPHA ; + else + new_temp = ALPHA * temp; + if (new_temp >= 1.0 ) + factor = log(new_temp)/log(START_TEMP); + else + factor = 0; + *new_states = (int) ((STATES_END - + (STATES_END - STATES_BEGIN)*factor) * 10 * node_num); + + return(new_temp); + +} /* end of update_temp */ + + + +/************************************************************************** +* Fills the field "code" of "vertices" with the boolean coordinates of * +* that vertex on the hypercube of dimension "codelength" * +**************************************************************************/ + +vert_alloc(codelength) +int codelength; + +{ + char module; + int i,j,k; + + if ( (vertices = (HYPERVERTEX *) calloc((unsigned)codes_num,sizeof(HYPERVERTEX))) == (HYPERVERTEX *) 0) { + fprintf(stderr,"Insufficient memory for vertices"); + exit(-1); + } + + for (i=0; i 0 ) { + + if ( j % 2 == 0 ) { + module = '0'; + } else { + module = '1'; + } + + vertices[i].code[k] = module; + + j = j / 2; + k--; + } + + vertices[i].label = -1; + } + + /*printf("Codes provided by codes_box\n"); + for (i=0; i 1) { + for (i=1, value=0; i < arg ; i = i << 1 , value++) ; + } + + return(value); + +} + + +minpow2(arg) /* computes the minimum power of 2 >= than its argument */ +int arg; + +{ + int value; + + for (value=1; value < arg ; value = value << 1) ; + + return(value); + +} + + +/* computes the hamming-distance between the cubes "arg1" and "arg2" + of "length" size */ +hamm_dist(arg1,arg2,length) +char *arg1; +char *arg2; +int length; + +{ + int i,distance; + + distance = 0; + + for ( i=0; i < length; i++) { + if ( ((arg1[i] == ONE) && (arg2[i] == ZERO)) || + ((arg1[i] == ZERO) && (arg2[i] == ONE)) ) { + distance++; + } + } + + return(distance); + +} + + +perimeter(dim) /* computes the perimeter of an hyperface of dimension "dim" */ +int dim; + +{ + int i,power; + + power = 1; + + for (i = 0; i < dim-1; i++) { + power = power * 2; + } + + return( dim * power ); +} + + +myatoi(s) /* converts s to integer */ +char s[]; + +{ + int i,n; + + for (i=0; s[i]==' ' || s[i]=='\n' || s[i]=='\t' || s[i]=='.' || + s[i]=='i' || s[i]=='o' || s[i]=='p'; i++) { + ; /* skips white space and the keys '.i' , '.o' , '.p' */ + } + + for (n = 0; s[i] >= '0' && s[i] <= '9'; i++) { + n = 10 * n + s[i] - '0'; + } + + return(n); +} + + + +size() + +{ + FILE *fp, *fopen(); + char line[MAXLINE], *fgets(); + int min_size; + /* note : min_inputs,min_ouputs,min_products have been defined as global + variables */ + + if ( (fp = fopen(temp4,"r")) == NULL ) { + fprintf(stderr,"size: can't open temp4\n"); + exit(-1); + } else { + /* skips the first line ( comment ) + fgets(line,MAXLINE,fp );*/ + + if ( fgets(line,MAXLINE,fp ) != (char *) 0 && + myindex(line,".i") != -1 ) { + min_inputs = myatoi(line); + } + if (VERBOSE) printf("\nmin_inputs = %d\n",min_inputs); + + if ( fgets(line,MAXLINE,fp ) != (char *) 0 && + myindex(line,".o") != -1 ) { + min_outputs = myatoi(line); + } + if (VERBOSE) printf("min_outputs = %d\n",min_outputs); + + if ( fgets(line,MAXLINE,fp ) != (char *) 0 && + myindex(line,".p") != -1 ) { + min_products = myatoi(line); + } + if (VERBOSE) printf("min_products = %d\n",min_products); + } + + fclose(fp); + + min_size = ( 2*min_inputs + min_outputs ) * min_products; + + if (VERBOSE) printf("min_size = %d\n", min_size); + + return (min_size); + +} + + +/* converts the integer "value" into the binary coded string "binary" + of length "length" */ +itob(binary,value,length) +char *binary; +int value; +int length; + +{ + + int i; + + for (i = length - 1; i >= 0; i-- ) { + + if ( (value % 2) == 1 ) { + binary[i] = ONE; + } else { + binary[i] = ZERO; + } + + value = value / 2; + + } + + binary[length] = '\0'; + +} + + +/* converts the binary coded string "binary" of length "length" + in the integer "value" */ +btoi(binary,length) +char *binary; +int length; + +{ + + int i,value; + + value = 0; + for (i = length - 1; i >= 0; i-- ) { + + if (binary[i] == ONE) { + value = value + power(2,length - 1 - i); + } + + } + + return(value); + +} + + +/* replaces all characters from a pound sign to end of line with blanks */ +comment(string,length) +char *string; +int length; + +{ + int i,j; + + for (i = 0; i < length; i++) { + if (string[i] == '#') { + for (j = i; j < length; j++) { + string[j] = ' '; + } + break; + } + } +} + + + +/* replaces tabs with blanks */ +tabs(string,length) +char *string; +int length; + +{ + int i; + + for (i = 0; i < length; i++) { + if (string[i] == '\t') { + string[i] = ' '; + } + } +} + + + +/* removes trailing blanks and tabs */ +trailblanks(string,length) +char *string; +int length; + +{ + int i; + + i = length; + + while (--i >= 0) { + if (string[i] != ' ' && string[i] != '\t' && string[i] != '\n') { + break; + } + string[i+1] = '\0'; + } + +} + + + +p_incl_s(p,s) /* returns 1 (otherwise 0) iff set p includes set s - + it does not check whether the inclusion is proper */ +char *p; +char *s; + +{ + + int j; + + for (j=0; p[j] != '\0'; j++) { + if (p[j] == ZERO && s[j] == ONE) { + return(0); + } + } + + return(1); + +} + + + +face1_incl_face2(face1,face2,dim) /* returns 1 (otherwise 0) iff face1 includes + properly face2 */ +char *face1; +char *face2; +int dim; + +{ + + int j; + BOOLEAN inclusion,proper; + + inclusion = TRUE; + proper = FALSE; + + for (j=0; j 0 */ +int x,n; + +{ + int i,p; + + p = 1; + for (i=1; i<=n; ++i) + p = p * x; + return(p); +} + + + +char *a_inter_b(a,b,constr_card,dim) /* returns the intersection of faces a and + b ; checks also if it has dimension + large enough to contain constr->card */ +char *a; +char *b; +int constr_card; +int dim; + +{ + + int j,inter_dim; + char *new_code; + + if ( (new_code = (char *) calloc((unsigned)dim+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for new_code in a_inter_b"); + exit(-1); + } + + new_code[dim] = '\0'; + + inter_dim = 1; + + for (j=0; j= 1 ) { + return(new_code); + } else { + free_mem(new_code); + return( (char *) 0 ); + } + +} + + + +int card_c1c2(a,b,dim) /* returns #(intersection of constraints a and b) */ +char *a; +char *b; +int dim; + +{ + + int j,num_ones; + + num_ones = 0; + + for (j=0; jnext ) { + if ( reached[curptr->index] == 0 ) { + if (path_is_new(old_source,curptr->index) == 0) { + new_order_path(old_source,curptr->index); + } + dfs(old_source,curptr->index); + } + } + +} + + + +relation_is_new(row,column) +int row; +int column; + +{ + ORDER_RELATION *curptr; + + for ( curptr = order_graph[row]; curptr != (ORDER_RELATION *) 0 ; + curptr = curptr->next ) { + if ( curptr->index == column ) { + return(1); + } + } + return(0); + +} + + + +path_is_new(row,column) +int row; +int column; + +{ + ORDER_PATH *curptr; + + for ( curptr = path_graph[row]; curptr != (ORDER_PATH *) 0 ; + curptr = curptr->next ) { + if ( curptr->dest == column ) { + return(1); + } + } + return(0); + +} + + + +/****************************************************************************** +* Copies string t[0,statenum-1] to string s * +******************************************************************************/ + +strcar(s,t) +char s[],t[]; + +{ + int i; + + for (i = 0; i < statenum; i++) { + s[i] = t[i]; + } + s[statenum] = '\0'; + +} + + + + +/****************************************************************************** +* s[index] = '0' , otherwise s[i] = '~' * +******************************************************************************/ + +stroff(s,index) +char s[]; +int index; + +{ + int i; + + for (i = 0; i < statenum; i++) { + s[i] = '0'; + } + s[index] = '0'; + s[statenum] = '\0'; + +} + +/****************************************************************************** +* s[index] = '-' , otherwise s[i] = '~' * +******************************************************************************/ + +strdc(s,index) +char s[]; +int index; + +{ + int i; + + for (i = 0; i < statenum; i++) { + s[i] = '0'; + } + s[index] = '-'; + s[statenum] = '\0'; + +} + +stron(s,index) +char s[]; +int index; + +{ + int i; + + for (i = 0; i < statenum; i++) { + s[i] = '0'; + } + s[index] = '1'; + s[statenum] = '\0'; + +} + + + +save_in_code(simboli,simbnum) +SYMBLEME *simboli; +int simbnum; + +{ + + int i; + + for ( i = 0; i < simbnum; i++ ) { + strcpy(simboli[i].code,simboli[i].best_code); + } + +} diff --git a/nova/coloring.c b/nova/coloring.c new file mode 100644 index 0000000..7723197 --- /dev/null +++ b/nova/coloring.c @@ -0,0 +1,200 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/coloring.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +#include "nova.h" + +coloring(ns,inco_array) +int ns; +int **inco_array; + +/* Colors the connected components of the incompatibles graph */ + +{ + + int i,j,maxk,mink,vi,vj,i1,k; + int flagadja,colornum; + int *color; + int **LForder; + + /* Largest-first vertex ordering - vertices are ordered as follows : + deg(v1) >= deg(v2) >= ... >= deg(vn) . + Before the lfs-ordering : + LForder[2,i] = j iff vertex #(i+1) is connected to j other vertices - + After the lfs-ordering : + LForder[2,i1] <= LForder[2,i2] iff + deg(vertex#(LForder[1,i1])) <= deg(vertex#(LForder[1,i2])) + from right to left is the largest-first ordering */ + + if ( (LForder = (int **) calloc((unsigned)2,sizeof(int *))) == (int **) 0) { + fprintf(stderr,"Insufficient memory for 'LForder'"); + exit(-1); + } + for ( i = 0; i < 2; i++ ) { + if ( (LForder[i] = (int *) calloc((unsigned)ns,sizeof(int))) == (int *) 0) { + fprintf(stderr,"Insufficient memory for LForder[i]"); + exit(-1); + } + } + + if ( (color = (int *) calloc((unsigned)ns,sizeof(int))) == (int *) 0) { + fprintf(stderr,"Insufficient memory for 'color'"); + exit(-1); + } + + /* lfs-ordering */ + for (i=0; i0; vi--) /* loop on the nodes to be colored */ + { + mink = ns + 1; /* mink is the smallest colour assignable to vi */ + for (vj=0; vj < ns; vj++) /* scan the colour array */ + { + if ( color[vj] != 0 ) + { + k = color[vj]; /* k is the color of node vj */ + /* vj is a colored node */ + i1 = 0; + flagadja = 1; + /* check whether color k has not been assigned to any node + adjacent to vi (iff flagadja = 1) */ + while ( i1 < ns & flagadja == 1 ) /* i1 scans the nodes */ + { /* adjacent to vi */ + if (inco_array[LForder[0][vi-1]-1][i1] == 1 & color[i1] == k) + flagadja = 0; + i1++; + } + if ( flagadja == 1 ) /* colour k can be given to vi */ + { + if (mink > k ) mink = k; + } + } + } + /* when no old colour can be assigned to vi, a new one is given */ + if (mink != ns + 1) color[LForder[0][vi-1]-1] = mink; + else {maxk++; color[LForder[0][vi-1]-1] = maxk;} + } + colornum = maxk; + + printf("\nThe number of colors used is %d\n", colornum); + /*printf("Color array : "); + for (i=0; i= pivot */ + + pivotindex = qspivot(array,init,length); + if (pivotindex != 0) /* do nothing if array[init-1]=array[length-1] */ + { + pivot = array[1][pivotindex-1]; + k = qspart(array,init,length,pivot); + quicksort(array,init,k-1); + quicksort(array,k,length); + } + +} + + + +qspivot(array,init,length) +int **array; +int init; +int length; + +/* returns 0 if array[init],...array[length] have identical keys, + otherwise the index of the larger of the leftmost two different keys */ + +{ + int k; /* runs left to right looking for a different key */ + int firstkey; /* value of first key found */ + + firstkey = array[1][init-1]; + for (k=init+1; k firstkey) return(k); /* select larger key */ + else if (array[1][k-1] < firstkey) return(init); + } + return(0); + +} + + + +qspart(array,init,length,pivot) +int **array; +int init; +int length; +int pivot; + +/* partitions array[init],...,array[length] so keys < pivot are at the left + and keys >= pivot are on the right . Returns the beginning of the group on + the right */ + +{ + int l,r; /* cursors used during the permutation process */ + int temp; + + l = init; + r = length; + while (l<=r) + { + /* swap array[1][r-1] & array[1][l-1] */ + temp = array[1][r-1]; + array[1][r-1] = array[1][l-1]; + array[1][l-1] = temp; + /* swap array[0][r-1] & array[0][l-1] */ + temp = array[0][r-1]; + array[0][r-1] = array[0][l-1]; + array[0][l-1] = temp; + + /* Now the scan phase begins */ + while (array[1][l-1] < pivot) l++; + while (array[1][r-1] >= pivot) r--; + } + return(l); + +} + + + diff --git a/nova/comb_objects.c b/nova/comb_objects.c new file mode 100644 index 0000000..74e85ad --- /dev/null +++ b/nova/comb_objects.c @@ -0,0 +1,851 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/comb_objects.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:08 $ + * + */ +#include "nova.h" + +/***************************************************************** +* * +* Generation of a new face available for a constraint * +* There are three different variations of gen_newcode * +* according to the category of the constraint encoded * +* * +*****************************************************************/ + +/***************************************************************** +* gen_newcode for constraints of category 1 : * +* constraints of category 1 have the universe as only father * +*****************************************************************/ + +char *gen_newcode_cat1(curptr,seed_code,dim_cube) +CODORDER_LINK *curptr; +char *seed_code; +int dim_cube; + +{ + + int i; + int num_x; + int count_max,comb_max,lex_max; + char *new_code,*combinations(),*counting(); + + /*printf("\nGen_newcode_cat1 :");*/ + + num_x = 0; + for (i=0; iconstraint_e->face_ptr->lexmap_index == 0 ) { + new_code = combinations(seed_code,dim_cube); + /*printf("gen_newcode_cat1 returned = %s\n", new_code);*/ + strcpy(curptr->constraint_e->face_ptr->first_value,new_code); + curptr->constraint_e->face_ptr->first_valid = TRUE; + strcpy(curptr->constraint_e->face_ptr->cur_value,new_code); + curptr->constraint_e->face_ptr->code_valid = TRUE; + curptr->constraint_e->face_ptr->count_index = 1; + curptr->constraint_e->face_ptr->comb_index = 1; + curptr->constraint_e->face_ptr->lexmap_index = 1; + (curptr->constraint_e->face_ptr->tried_codes)++; + } else { + /* if all possible faces have already been assigned in vain to the + current constraint return the null code */ + if (curptr->constraint_e->face_ptr->lexmap_index == lex_max) { + return( (char *) 0 ); + } else { + /* otherwise apply to the current face the transformation + 1) 'counting' if the current counting cycle is unfinished + 2) 'combinations' if the current counting cycle is finished + and there are still combinations to try */ + if (curptr->constraint_e->face_ptr->count_index < count_max) { + new_code = counting(curptr->constraint_e->face_ptr->cur_value, + dim_cube); + /*printf("gen_newcode_cat1 returned = %s\n", new_code);*/ + (curptr->constraint_e->face_ptr->count_index)++; + (curptr->constraint_e->face_ptr->lexmap_index)++; + (curptr->constraint_e->face_ptr->tried_codes)++; + strcpy(curptr->constraint_e->face_ptr->cur_value,new_code); + curptr->constraint_e->face_ptr->code_valid = TRUE; + } else { + if (curptr->constraint_e->face_ptr->comb_index < comb_max) { + new_code = + combinations(curptr->constraint_e->face_ptr->cur_value, + dim_cube); + /*printf("gen_newcode_cat1 returned = %s\n", new_code);*/ + curptr->constraint_e->face_ptr->count_index = 1; + (curptr->constraint_e->face_ptr->comb_index)++; + (curptr->constraint_e->face_ptr->lexmap_index)++; + (curptr->constraint_e->face_ptr->tried_codes)++; + strcpy(curptr->constraint_e->face_ptr->cur_value,new_code); + curptr->constraint_e->face_ptr->code_valid = TRUE; + } + } + } + } + + if (DEBUG) printf("lexmap_index = %d\n", curptr->constraint_e->face_ptr->lexmap_index); + + free_mem(new_code); + return(curptr->constraint_e->face_ptr->cur_value); + +} + + + +/***************************************************************************** +* gen_newcode for constraints of category 2 : * +* constraints of category 2 should be assigned faces contained in the * +* intersection of those already assigned to their fathers - * +* the dimension of each face varies from a minimum (face_ptr->curdim_face) * +* to a maximum (dimension of the intersection of the faces assigned to the * +* fathers) and this is taken care by the upper level routine * +* (gen_newcode_cat2), while at the lower level (newcode_cat2) all possible * +* faces of a certain (current) dimension are generated * +*****************************************************************************/ + +char *gen_newcode_cat2(curptr,dim_cube) +CODORDER_LINK *curptr; +int dim_cube; + +{ + + char *newcode_cat2(),*new_code,*fathers_intercode,*fathers_codes_inter(); + int i,num_x,dim_subcube; + + /* num_x is the face dimension of curptr */ + num_x = curptr->constraint_e->face_ptr->curdim_face; + + /* the variables fathers_intercode and dim_subcube should be + computed once for all at a (more) global level - for reasons of + easy coding they are recomputed at every call of gen_newcode_cat2 */ + /* intersection of the faces already assigned to the fathers */ + fathers_intercode = fathers_codes_inter(curptr->constraint_e,dim_cube); + /* dim_subcube is the face dimension of the intersection of the codes of + the fathers of curptr */ + dim_subcube = 0; + for (i=0; iconstraint_e->face_ptr->dim_index == 0 ) { + curptr->constraint_e->face_ptr->dim_index = num_x; + i = curptr->constraint_e->face_ptr->dim_index; + new_code = + newcode_cat2(curptr,dim_cube,i,dim_subcube,fathers_intercode); + } else { + /* a new code is generated with the current dim_index */ + i = curptr->constraint_e->face_ptr->dim_index; + new_code = + newcode_cat2(curptr,dim_cube,i,dim_subcube,fathers_intercode); + if ( new_code == (char *) 0 && + curptr->constraint_e->face_ptr->dim_index < dim_subcube ) { + /* all codes of the current dim_index have been generated - + dim_index is set to the next value (if it is still within + dim_subcube) and a new code is generated - + notice that the counting and combinations indexes are + reset because a new generation cycle starts */ + (curptr->constraint_e->face_ptr->dim_index)++; + curptr->constraint_e->face_ptr->count_index = 0; + curptr->constraint_e->face_ptr->comb_index = 0; + curptr->constraint_e->face_ptr->lexmap_index = 0; + i = curptr->constraint_e->face_ptr->dim_index; + if (DEBUG) printf("\ni = %d\n", i); + new_code = + newcode_cat2(curptr,dim_cube,i,dim_subcube,fathers_intercode); + } + } + + free_mem(fathers_intercode); + + return(new_code); + +} + + +char *newcode_cat2(curptr,dim_cube,num_x,dim_subcube,fathers_intercode) +CODORDER_LINK *curptr; +int dim_cube; +int num_x; /* num_x is the current face dimension of curptr */ +int dim_subcube; /* dim_subcube is the face dimension of the + intersection of the codes of the fathers of curptr */ +char *fathers_intercode; /*=fathers_codes_inter(curptr->constraint_e,dim_cube)*/ + +{ + + int count_max,comb_max,lex_max; + char *new_code,*new_subcode,*seed,*start_seed(), + *insert_code(),*copy_code(),*combinations(),*counting(); + + /*printf("\nGen_newcode_cat2 :");*/ + + /* if the intersection of the faces already assigned to the fathers is + empty return the empty face because a mistake has been made in the + past and is worthless attempting to assign meaningful faces to the son */ + if (fathers_intercode == (char *) 0) { + return( (char *) 0); + } + + /* maximum of counting */ + count_max = power(2,dim_subcube - num_x); + /* maximum of combinations */ + comb_max = comb_num(dim_subcube,num_x); + /* maximum of transformations (new faces) */ + lex_max = count_max * comb_max; + + if (DEBUG) printf("\nlex_max = %d\n", lex_max); + + /* if it is the first attempt to assign a face to the current constraint + start from start_seed (with a subface dimension) and generate a new + subcode calling 'combinations'. + The subcode is + 1) merged into the code of the father, and + 2) assigned to seed_value to be the starting point of the next + combinatorial transformation */ + if ( curptr->constraint_e->face_ptr->lexmap_index == 0 ) { + if (dim_subcube > 0) { + seed = start_seed(dim_subcube,num_x); + new_subcode = combinations(seed,dim_subcube); + free_mem(seed); + new_code = insert_code(new_subcode,fathers_intercode,dim_cube); + } else { /* fathers_intercode is already the only possible new_code */ + new_code = copy_code(fathers_intercode,dim_cube); + new_subcode = copy_code(fathers_intercode,dim_cube); + } + /*printf("gen_newcode_cat2 returned = %s\n", new_code);*/ + strcpy(curptr->constraint_e->face_ptr->seed_value,new_subcode); + curptr->constraint_e->face_ptr->seed_valid = TRUE; + strcpy(curptr->constraint_e->face_ptr->first_value,new_code); + curptr->constraint_e->face_ptr->first_valid = TRUE; + strcpy(curptr->constraint_e->face_ptr->cur_value,new_code); + curptr->constraint_e->face_ptr->code_valid = TRUE; + curptr->constraint_e->face_ptr->count_index = 1; + curptr->constraint_e->face_ptr->comb_index = 1; + curptr->constraint_e->face_ptr->lexmap_index = 1; + (curptr->constraint_e->face_ptr->tried_codes)++; + } else { + /* if all possible faces have already been assigned in vain to the + current constraint return the null code */ + if (curptr->constraint_e->face_ptr->lexmap_index == lex_max) { + return( (char *) 0); + } else { + /* otherwise apply to the current face the transformation + 1) 'counting' if the current counting cycle is unfinished + 2) 'combinations' if the current counting cycle is finished + and there are still combinations to try */ + if (curptr->constraint_e->face_ptr->count_index < count_max) { + new_subcode = counting( + curptr->constraint_e->face_ptr->seed_value,dim_subcube); + new_code = insert_code(new_subcode,fathers_intercode,dim_cube); + /*printf("gen_newcode_cat2 returned = %s\n", new_code);*/ + (curptr->constraint_e->face_ptr->count_index)++; + (curptr->constraint_e->face_ptr->lexmap_index)++; + (curptr->constraint_e->face_ptr->tried_codes)++; + strcpy(curptr->constraint_e->face_ptr->seed_value,new_subcode); + curptr->constraint_e->face_ptr->seed_valid = TRUE; + strcpy(curptr->constraint_e->face_ptr->cur_value,new_code); + curptr->constraint_e->face_ptr->code_valid = TRUE; + } else { + if (curptr->constraint_e->face_ptr->comb_index < comb_max) { + new_subcode = combinations( + curptr->constraint_e->face_ptr->seed_value,dim_subcube); + new_code = insert_code(new_subcode,fathers_intercode, + dim_cube); + /*printf("gen_newcode_cat2 returned = %s\n", new_code);*/ + curptr->constraint_e->face_ptr->count_index = 1; + (curptr->constraint_e->face_ptr->comb_index)++; + (curptr->constraint_e->face_ptr->lexmap_index)++; + (curptr->constraint_e->face_ptr->tried_codes)++; + strcpy(curptr->constraint_e->face_ptr->seed_value,new_subcode); + curptr->constraint_e->face_ptr->seed_valid = TRUE; + strcpy(curptr->constraint_e->face_ptr->cur_value,new_code); + curptr->constraint_e->face_ptr->code_valid = TRUE; + } + } + } + } + + if (DEBUG) printf("lexmap_index = %d\n", curptr->constraint_e->face_ptr->lexmap_index); + + free_mem(new_subcode); + free_mem(new_code); + return(curptr->constraint_e->face_ptr->cur_value); + +} + + + +/***************************************************************************** +* gen_newcode for constraints of category 3 : * +* constraints of category 3 should be assigned faces contained in that * +* already assigned to their unique father - * +* the dimension of each face varies from a minimum (face_ptr->curdim_face) * +* to a maximum (dimension of the face assigned to its father - 1) * +* and this is taken care by the upper level routine (gen_newcode_cat3), * +* while at the lower level (newcode_cat3) all possible faces of a certain * +* (current) dimension are generated * +*****************************************************************************/ + +char *gen_newcode_cat3(curptr,dim_cube) +CODORDER_LINK *curptr; +int dim_cube; + +{ + + char *newcode_cat3(),*new_code,*father_code; + int i,num_x,dim_subcube; + + /* num_x is the face dimension of curptr */ + num_x = curptr->constraint_e->face_ptr->curdim_face; + + father_code = + curptr->constraint_e->up_ptr->constraint_e->face_ptr->cur_value; + if (DEBUG) printf("\nfather_code = %s", father_code); + + /* the variable dim_subcube should be computed once for all + at a (more) global level - for reasons of easy coding it + is recomputed at every call of gen_newcode_cat3 */ + /* dim_subcube is the face dimension of the father of curptr */ + dim_subcube = 0; + for (i=0; iconstraint_e->face_ptr->dim_index == 0 ) { + curptr->constraint_e->face_ptr->dim_index = num_x; + i = curptr->constraint_e->face_ptr->dim_index; + new_code = + newcode_cat3(curptr,dim_cube,i,dim_subcube,father_code); + } else { + /* a new code is generated with the current dim_index */ + i = curptr->constraint_e->face_ptr->dim_index; + new_code = + newcode_cat3(curptr,dim_cube,i,dim_subcube,father_code); + if ( new_code == (char *) 0 && + curptr->constraint_e->face_ptr->dim_index < (dim_subcube - 1) ) { + /* all codes of the current dim_index have been generated - + dim_index is set to the next value (if it is still within + dim_subcube) and a new code is generated - + notice that the counting and combinations indexes are + reset because a new generation cycle starts */ + (curptr->constraint_e->face_ptr->dim_index)++; + curptr->constraint_e->face_ptr->count_index = 0; + curptr->constraint_e->face_ptr->comb_index = 0; + curptr->constraint_e->face_ptr->lexmap_index = 0; + i = curptr->constraint_e->face_ptr->dim_index; + if (DEBUG) printf("\ni = %d\n", i); + new_code = + newcode_cat3(curptr,dim_cube,i,dim_subcube,father_code); + } + } + + return(new_code); + +} + + + +char *newcode_cat3(curptr,dim_cube,num_x,dim_subcube,father_code) +CODORDER_LINK *curptr; +int dim_cube; +int num_x; /* num_x is the current face dimension of curptr */ +int dim_subcube; /* dim_subcube is the face dimension of the + father of curptr */ +char *father_code; /* face assigned to the father of curptr */ + +{ + + int count_max,comb_max,lex_max; + char *new_code,*new_subcode,*seed,*start_seed(), + *insert_code(),*combinations(),*counting(); + + /*printf("\nGen_newcode_cat3 :");*/ + + /* maximum of counting */ + count_max = power(2,dim_subcube - num_x); + /* maximum of combinations */ + comb_max = comb_num(dim_subcube,num_x); + /* maximum of transformations (new faces) */ + lex_max = count_max * comb_max; + + if (DEBUG) printf("\nlex_max = %d\n", lex_max); + + /* if it is the first attempt to assign a face to the current constraint + start from start_seed (with a subface dimension) and generate a new + subcode calling 'combinations'. + The subcode is + 1) merged into the code of the father, and + 2) assigned to seed_value to be the starting point of the next + combinatorial transformation */ + if ( curptr->constraint_e->face_ptr->lexmap_index == 0 ) { + seed = start_seed(dim_subcube,num_x); + new_subcode = combinations(seed,dim_subcube); + free_mem(seed); + new_code = insert_code(new_subcode,father_code,dim_cube); + /*printf("gen_newcode_cat3 returned = %s\n", new_code);*/ + strcpy(curptr->constraint_e->face_ptr->seed_value,new_subcode); + curptr->constraint_e->face_ptr->seed_valid = TRUE; + strcpy(curptr->constraint_e->face_ptr->first_value,new_code); + curptr->constraint_e->face_ptr->first_valid = TRUE; + strcpy(curptr->constraint_e->face_ptr->cur_value,new_code); + curptr->constraint_e->face_ptr->code_valid = TRUE; + curptr->constraint_e->face_ptr->count_index = 1; + curptr->constraint_e->face_ptr->comb_index = 1; + curptr->constraint_e->face_ptr->lexmap_index = 1; + (curptr->constraint_e->face_ptr->tried_codes)++; + } else { + /* if all possible faces have already been assigned in vain to the + current constraint return the null code */ + if (curptr->constraint_e->face_ptr->lexmap_index == lex_max) { + if (DEBUG) printf("\n"); + return( (char *) 0 ); + } else { + /* otherwise apply to the current face the transformation + 1) 'counting' if the current counting cycle is unfinished + 2) 'combinations' if the current counting cycle is finished + and there are still combinations to try */ + if (curptr->constraint_e->face_ptr->count_index < count_max) { + new_subcode = counting( + curptr->constraint_e->face_ptr->seed_value,dim_subcube); + new_code = insert_code(new_subcode,father_code,dim_cube); + /*printf("gen_newcode_cat3 returned = %s\n", new_code);*/ + (curptr->constraint_e->face_ptr->count_index)++; + (curptr->constraint_e->face_ptr->lexmap_index)++; + (curptr->constraint_e->face_ptr->tried_codes)++; + strcpy(curptr->constraint_e->face_ptr->seed_value,new_subcode); + curptr->constraint_e->face_ptr->seed_valid = TRUE; + strcpy(curptr->constraint_e->face_ptr->cur_value,new_code); + curptr->constraint_e->face_ptr->code_valid = TRUE; + } else { + if (curptr->constraint_e->face_ptr->comb_index < comb_max) { + new_subcode = combinations( + curptr->constraint_e->face_ptr->seed_value,dim_subcube); + new_code = insert_code(new_subcode,father_code,dim_cube); + /*printf("gen_newcode_cat3 returned = %s\n", new_code);*/ + curptr->constraint_e->face_ptr->count_index = 1; + (curptr->constraint_e->face_ptr->comb_index)++; + (curptr->constraint_e->face_ptr->lexmap_index)++; + (curptr->constraint_e->face_ptr->tried_codes)++; + strcpy(curptr->constraint_e->face_ptr->seed_value,new_subcode); + curptr->constraint_e->face_ptr->seed_valid = TRUE; + strcpy(curptr->constraint_e->face_ptr->cur_value,new_code); + curptr->constraint_e->face_ptr->code_valid = TRUE; + } + } + } + } + + if (DEBUG) printf("lexmap_index = %d\n", curptr->constraint_e->face_ptr->lexmap_index); + + free_mem(new_subcode); + free_mem(new_code); + return(curptr->constraint_e->face_ptr->cur_value); + +} + + + +char *insert_code(new_subcode,father_code,dim_cube) +char *new_subcode; +char *father_code; +int dim_cube; + +{ + + int i,j; + char *new_code; + + if ( (new_code = (char *) calloc((unsigned)dim_cube+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for new_code in insert_code"); + exit(-1); + } + + j=0; + for (i=0; i=0; i--) { + binary[i] = -1; + } + binary[dim_cube-num_x] = 0; + + j = dim_cube-num_x-1; + for (i=0; i=0; i--) { + printf("binary[i] = %d ", binary[i]); + } + printf("\n");*/ + + i = 0; + while (binary[i] == 1) { + binary[i] = 0; + i++; + } + binary[i] = 1; + + /*}*/ + + /*printf("tranformed binary : "); + for (i=dim_cube-num_x; i>=0; i--) { + printf("binary[i] = %d ", binary[i]); + } + printf("\n");*/ + + output[dim_cube] = '\0'; + for (i=0; i=0; i--) { + for (j=0; j=k>0 */ + +char *min_combinations(seed_code,dim_cube) +char *seed_code; +int dim_cube; + +{ + int i,j,l,t,num_x; + int *buffer,*stack; + char *output; + + if (DEBUG) printf("\nEntered into min_combinations\n"); + + /* compute the size k (= num_x) of the subsets */ + num_x = 0; + for (i=0; i= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + /* constraints of category 1 get as current face dimension the + minimum feasible face dimension */ + if (constrptr->face_ptr->category == 1 ) { + constrptr->face_ptr->curdim_face = + constrptr->face_ptr->mindim_face; + if (VERBOSE) { + printf("constraint %s : ",constrptr->relation); + printf("new curdim_face = %d\n", + constrptr->face_ptr->curdim_face); + } + cart_prod *= constrptr->face_ptr->maxdim_face - + constrptr->face_ptr->mindim_face + 1; + if (cart_prod < 0) { + fprintf(stderr,"\nSolution space too large: exact search discontinued\n"); + exit(-1); + } + } + } + } + + if (VERBOSE) printf("\ncart_prod in init_backtrack_up = %d\n", cart_prod); + + return(TRUE); + +} + + + +/******************************************************************************* +* backtrack_up finds a new configuration of the dimensions of the faces * +* according to the lexicographic order introduced in the cartesian * +* product of the linearly ordered sets of the integer dimensions that * +* each constraint of cardinality 1 can assume (cardinality of each such * +* set = maxdim_face - mindim_face for that constraint) * +*******************************************************************************/ + +BOOLEAN backtrack_up() + +{ + + int i,search_st; + CONSTRAINT_E *constrptr,*lex_constrptr; + + if (VERBOSE) + printf("\nBacktrack_up updates curdim of constraints of cat. 1\n"); + + /* A new configuration of the dimensions of the faces is generated + according to the lexicographic order introduced in the cartesian + product of the linearly ordered sets of the integer dimensions + that each constraint of cardinality 1 can assume (cardinality of + each such set = maxdim_face - mindim_face for that constraint) - + To find the next configuration in lex order we increase by one + the right-most value that can be increased and set all values + further to the right to one */ + + if (VERBOSE) printf("bktup_count = %d\n",bktup_count); + + if (bktup_count == cart_prod) { /* no more configurations available */ + return(FALSE); + } else { + /* we find the right_most value that can be increased - + lex_constrptr points to it */ + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + if (constrptr->face_ptr->category == 1) { + if (constrptr->face_ptr->curdim_face < + constrptr->face_ptr->maxdim_face) { + lex_constrptr = constrptr; + } + } + } + } + /* we increase by one the right-most value that can be increased + and set all values further to the right to one */ + search_st = 0; + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + if (constrptr->face_ptr->category == 1) { + if (search_st == 0) { + if (constrptr == lex_constrptr) { + constrptr->face_ptr->curdim_face++; + search_st = 1; + } + } + if (constrptr != lex_constrptr && search_st == 1 ) { + constrptr->face_ptr->curdim_face = + constrptr->face_ptr->mindim_face; + } + } + } + } + bktup_count++; + /* bktup_calls (global variable) is set to 0 in faces_alloc */ + bktup_calls++; + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + if (constrptr->face_ptr->category == 1) { + if (VERBOSE) { + printf("constraint %s : ",constrptr->relation); + printf("new curdim_face = %d\n", + constrptr->face_ptr->curdim_face); + } + } + } + } + } + + return(TRUE); + +} + + + +/***************************************************************************** +* LOWER LEVEL BACKTRACKING * +*******************************************************************************/ + +BOOLEAN backtrack_down(net_num,dim_cube) +int net_num; +int dim_cube; + +{ + + CODORDER_LINK *firstptr,*curptr,*backtrackptr,*first_to_code(), + *insert_in_list(); + CONSTRAINT_E *next_constr,*next_to_code(); + BOOLEAN face_found,backtrack,assign_face(),toomuch_work(); + + if (VERBOSE) + printf("\n ********* B A C K T R A C K _ D O W N *********\n"); + /* clears the faces (to start a new encoding attempt) */ + clear_faces(); + + /* the complete cube is assigned to the complete constraint */ + code_complete_constr(dim_cube, + graph_levels[graph_depth-1]->face_ptr->curdim_face); + + /* Selects the first constraint to code and inserts it in the selection + list - firstptr points to the first linker in the order list */ + firstptr = first_to_code(dim_cube); + curptr = firstptr; + backtrackptr = firstptr; + + /* assigns a face to the first selected constraint */ + assign_face_tofirst(curptr,dim_cube); + + /* selects a new constraint to code */ + next_constr = next_to_code(curptr->constraint_e,dim_cube); + + while (next_constr != (CONSTRAINT_E *) 0) { + + /* inserts the constraint pointed to by curptr in the selection list and + returns a pointer to the last element added to the selection list */ + curptr = insert_in_list(curptr,next_constr); + backtrackptr = curptr; + + backtrack = FALSE; + + /* assigns a face to the current constraint */ + face_found = assign_face(curptr,dim_cube,net_num); + + while ( ! (face_found == TRUE && backtrack == FALSE) ) { + + if (face_found == FALSE && backtrack == FALSE) { + if ( (I_HYBRID || IO_HYBRID || IO_VARIANT) && (toomuch_work() == TRUE) ) { + btkdown_summary(); + return(FALSE); + } + /* a backtracking phase starts */ + if (DEBUG) printf("\nA BACKTRACKING PHASE STARTS\n"); + backtrack = TRUE; + /* the current face information is cancelled */ + undo_face(backtrackptr); + backtrackptr = backtrackptr->right; + if (DEBUG) printf("Backwards to %s\n", + backtrackptr->constraint_e->relation); + if (backtrackptr == firstptr) { + if (VERBOSE) printf("\nBacktrack failed : WRONG CONFIGURATION OR CUBE TOO SMALL\n"); + btkdown_summary(); + if (DEBUG) show_faces(); + return(FALSE); + } else { + face_found = assign_face(backtrackptr,dim_cube,net_num); + } + } + + if (face_found == FALSE && backtrack == TRUE) { + if ( (I_HYBRID || IO_HYBRID || IO_VARIANT) && (toomuch_work() == TRUE) ) { + btkdown_summary(); + return(FALSE); + } + /* the current backtracking phase continues */ + if (DEBUG) printf("\nTHE CURRENT BACKTRACKING PHASE CONTINUES\n"); + undo_face(backtrackptr); + backtrackptr = backtrackptr->right; + if (DEBUG) printf("Backwards to %s\n", + backtrackptr->constraint_e->relation); + if (backtrackptr == firstptr) { + if (VERBOSE) printf("\nBacktrack failed : WRONG CONFIGURATION OR CUBE TOO SMALL\n"); + btkdown_summary(); + if (DEBUG) show_faces(); + return(FALSE); + } else { + face_found = assign_face(backtrackptr,dim_cube,net_num); + } + } + + if (face_found == TRUE && backtrack == TRUE) { + if ( (I_HYBRID || IO_HYBRID || IO_VARIANT) && (toomuch_work() == TRUE) ) { + btkdown_summary(); + return(FALSE); + } + /* a backtracking phase ends */ + /* we are recovering from the current backtracking phase */ + /* climbing ahead the current backtracking phase */ + if (DEBUG) printf("\nCLIMBING AHEAD THE CURRENT BACKTRACKING PHASE\n"); + backtrackptr = backtrackptr->left; + if (DEBUG) printf("Forwards to %s\n", + backtrackptr->constraint_e->relation); + face_found = assign_face(backtrackptr,dim_cube,net_num); + if (backtrackptr == curptr) { + backtrack = FALSE; + } + } + + } + + /* selects a new constraint to code */ + next_constr = next_to_code(curptr->constraint_e,dim_cube); + + } + + /* summarizes the work performed by backtrack_down */ + if (VERBOSE) printf("\nBACKTRACK_DOWN SUCCESSFULLY COMPLETED\n"); + btkdown_summary(); + if (DEBUG) show_faces(); + return(TRUE); + +} + + + +/* clears the information of the faces (to start a new encoding attempt) */ + +clear_faces() + +{ + + CONSTRAINT_E *constrptr; + int i; + + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + constrptr->face_ptr->seed_valid = FALSE; + constrptr->face_ptr->first_valid = FALSE; + constrptr->face_ptr->code_valid = FALSE; + constrptr->face_ptr->count_index = 0; + constrptr->face_ptr->comb_index = 0; + constrptr->face_ptr->lexmap_index = 0; + constrptr->face_ptr->dim_index = 0; + constrptr->face_ptr->tried_codes = 1; + } + } + +} + + + +/******************************************************************************* +* clears the face information of backtrackptr and the other constraints * +* that point to it as their codfather * +*******************************************************************************/ + +undo_face(backtrackptr) +CODORDER_LINK *backtrackptr; + +{ + + SONS_LINK *son_scanner; + CONSTRAINT_E *constrptr; + + constrptr = backtrackptr->constraint_e; + + if (constrptr->face_ptr->category != 1) { + /* constraints of category 1 are assigned a seed_value only once by + next_to_code, while other constraints are reassigned a seed_value + by every call of gen_newcode_catx */ + constrptr->face_ptr->seed_valid = FALSE; + } + constrptr->face_ptr->first_valid = FALSE; + constrptr->face_ptr->code_valid = FALSE; + constrptr->face_ptr->count_index = 0; + constrptr->face_ptr->comb_index = 0; + constrptr->face_ptr->lexmap_index = 0; + constrptr->face_ptr->dim_index = 0; + + for (son_scanner = constrptr->down_ptr; son_scanner != (SONS_LINK *) 0; + son_scanner = son_scanner->next ) { + if (son_scanner->codfather_ptr == constrptr) { + if (DEBUG) printf("cleared son : %s\n",son_scanner->constraint_e->relation); + son_scanner->constraint_e->face_ptr->seed_valid = FALSE; + son_scanner->constraint_e->face_ptr->first_valid = FALSE; + son_scanner->constraint_e->face_ptr->code_valid = FALSE; + son_scanner->constraint_e->face_ptr->count_index = 0; + son_scanner->constraint_e->face_ptr->comb_index = 0; + son_scanner->constraint_e->face_ptr->lexmap_index = 0; + son_scanner->constraint_e->face_ptr->dim_index = 0; + son_scanner->codfather_ptr = (CONSTRAINT_E *) 0; + } + } + +} + + + +/******************************************************************************* +* Selects the first constraint to code and inserts it in the selection list * +* The selected constraint has to be of category 1 with maximum curdim_face * +*******************************************************************************/ + +CODORDER_LINK *first_to_code(dim_cube) +int dim_cube; + +{ + int i,max_curdim_face; + char *seed,*start_seed(); + CONSTRAINT_E *constrptr,*prov_constrptr; + CODORDER_LINK *ord_link; + + if ((ord_link = (CODORDER_LINK *) calloc((unsigned)1,sizeof(CODORDER_LINK))) == + ( CODORDER_LINK *) 0) { + fprintf(stderr,"Insufficient memory for ord_link in first_to_code"); + exit(-1); + } + + max_curdim_face = -1; + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + if (constrptr->face_ptr->category == 1 && + constrptr->face_ptr->curdim_face > max_curdim_face) { + max_curdim_face = constrptr->face_ptr->curdim_face; + prov_constrptr = constrptr; + } + } + } + ord_link->constraint_e = prov_constrptr; + ord_link->right = (CODORDER_LINK *) 0; + ord_link->left = (CODORDER_LINK *) 0; + + if (DEBUG) printf("\nThe first chosen constraint is : %s \n", + ord_link->constraint_e->relation); + + seed = start_seed(dim_cube,ord_link->constraint_e->face_ptr->curdim_face); + strcpy(ord_link->constraint_e->face_ptr->seed_value,seed); + free_mem(seed); + ord_link->constraint_e->face_ptr->seed_valid = TRUE; + if (DEBUG) printf("The first seed is : %s\n", + ord_link->constraint_e->face_ptr->seed_value); + + return(ord_link); + +} + + + +/******************************************************************************* +* Selects a new constraint to code * +* Try the selection in the following priority order : * +* 1) are there constraints of category 1 not already coded with the same * +* curdim_face as constrptr and having intersections in common with it ? * +* i.e. among the sons of constrptr having fathers of category 1 with the same * +* curdim_face choose one and among its fathers choose one not already coded * +* 2) are there constraints of category 1 not already coded with the same * +* curdim_face as constrptr ? * +* 3) are there constraints not already coded with the same curdim_face as * +* constrptr and having intersections in common with it ? * +* i.e. among the sons of constrptr having fathers with the same curdim_face * +* choose one and among its fathers choose one not already coded * +* 4) are there constraints not already coded with the same curdim_face as * +* constrptr ? * +* 5) are there constraints not already coded with a smaller curdim_face ? * +*******************************************************************************/ + +CONSTRAINT_E *next_to_code(constrptr,dim_cube) +CONSTRAINT_E *constrptr; +int dim_cube; + +{ + + int i,level; + char *seed,*start_seed(),*copy_seed(); + SONS_LINK *son_scanner; + FATHERS_LINK *ft_scanner; + CONSTRAINT_E *scanner,*temp_ptr; + + temp_ptr = (CONSTRAINT_E *) 0; + + /* first branch of the selection criterion : + are there constraints of category 1 not already coded with the same + curdim_face as constrptr and having intersections in common with it ? + i.e. among the sons of constrptr having fathers of category 1 with the + same curdim_face choose one and among its fathers choose one not already + coded */ + for (son_scanner = constrptr->down_ptr; son_scanner != (SONS_LINK *) 0; + son_scanner = son_scanner->next ) { + for (ft_scanner = son_scanner->constraint_e->up_ptr; + ft_scanner != (FATHERS_LINK *) 0; ft_scanner = ft_scanner->next) { + if (ft_scanner->constraint_e->face_ptr->first_valid == FALSE && + (constrptr->face_ptr->curdim_face == + ft_scanner->constraint_e->face_ptr->curdim_face) && + ft_scanner->constraint_e->face_ptr->category == 1 ) { + if (DEBUG) printf("\nThe next chosen constraint is : %s \n", + ft_scanner->constraint_e->relation); + /* computes seed_value */ + if (constrptr->face_ptr->curdim_face == + ft_scanner->constraint_e->face_ptr->curdim_face) { + seed = copy_seed(dim_cube,constrptr->face_ptr->cur_value); + strcpy(ft_scanner->constraint_e->face_ptr->seed_value,seed); + free_mem(seed); + ft_scanner->constraint_e->face_ptr->seed_valid = TRUE; + } else { + seed = start_seed(dim_cube, + ft_scanner->constraint_e->face_ptr->curdim_face); + strcpy(ft_scanner->constraint_e->face_ptr->seed_value,seed); + free_mem(seed); + ft_scanner->constraint_e->face_ptr->seed_valid = TRUE; + } + if (DEBUG) { printf("The seed is : %s\n", + ft_scanner->constraint_e->face_ptr->seed_value); + printf("next_to_code : branch n. 1\n"); } + return(ft_scanner->constraint_e); + } + } + } + + /* second branch of the selection criterion : + are there constraints of category 1 not already coded with the same + curdim_face as constrptr ? */ + for (i = graph_depth-1; i >= 0; i--) { + for (scanner = graph_levels[i]; scanner != (CONSTRAINT_E *) 0; + scanner = scanner->next ) { + if ( scanner->face_ptr->first_valid == FALSE && + constrptr->face_ptr->curdim_face == + scanner->face_ptr->curdim_face && + scanner->face_ptr->category == 1 ) { + if (DEBUG) printf("The next chosen constraint is : %s \n", + scanner->relation); + /* computes seed_value */ + seed = start_seed(dim_cube,scanner->face_ptr->curdim_face); + strcpy(scanner->face_ptr->seed_value,seed); + free_mem(seed); + scanner->face_ptr->seed_valid = TRUE; + if (DEBUG) { printf("The seed is : %s\n", scanner->face_ptr->seed_value); + printf("next_to_code : branch n. 2\n"); } + return(scanner); + } + } + } + + /* third branch of the selection criterion : + are there constraints not already coded with the same curdim_face + as constrptr and having intersections in common with it ? + i.e. among the sons of constrptr having fathers with the same curdim_face + choose one and among its fathers choose one not already coded */ + for (son_scanner = constrptr->down_ptr; son_scanner != (SONS_LINK *) 0; + son_scanner = son_scanner->next ) { + for (ft_scanner = son_scanner->constraint_e->up_ptr; + ft_scanner != (FATHERS_LINK *) 0; ft_scanner = ft_scanner->next) { + if (ft_scanner->constraint_e->face_ptr->first_valid == FALSE && + (constrptr->face_ptr->curdim_face == + ft_scanner->constraint_e->face_ptr->curdim_face) ) { + if (DEBUG) printf("\nThe next chosen constraint is : %s \n", + ft_scanner->constraint_e->relation); + /* computes seed_value */ + if (constrptr->face_ptr->curdim_face == + ft_scanner->constraint_e->face_ptr->curdim_face) { + seed = copy_seed(dim_cube,constrptr->face_ptr->cur_value); + strcpy(ft_scanner->constraint_e->face_ptr->seed_value,seed); + free_mem(seed); + ft_scanner->constraint_e->face_ptr->seed_valid = TRUE; + } else { + seed = start_seed(dim_cube, + ft_scanner->constraint_e->face_ptr->curdim_face); + strcpy(ft_scanner->constraint_e->face_ptr->seed_value,seed); + free_mem(seed); + ft_scanner->constraint_e->face_ptr->seed_valid = TRUE; + } + if (DEBUG) { printf("The seed is : %s\n", + ft_scanner->constraint_e->face_ptr->seed_value); + printf("next_to_code : branch n. 3\n"); } + return(ft_scanner->constraint_e); + } + } + } + + /* fourth branch of the selection criterion : + are there constraints not already coded with the same curdim_face as + constrptr ? */ + for (i = graph_depth-1; i >= 0; i--) { + for (scanner = graph_levels[i]; scanner != (CONSTRAINT_E *) 0; + scanner = scanner->next ) { + if ( scanner->face_ptr->first_valid == FALSE && + constrptr->face_ptr->curdim_face == + scanner->face_ptr->curdim_face ) { + if (DEBUG) printf("The next chosen constraint is : %s \n", + scanner->relation); + /* computes seed_value */ + seed = start_seed(dim_cube,scanner->face_ptr->curdim_face); + strcpy(scanner->face_ptr->seed_value,seed); + free_mem(seed); + scanner->face_ptr->seed_valid = TRUE; + if (DEBUG) { printf("The seed is : %s\n", scanner->face_ptr->seed_value); + printf("next_to_code : branch n. 4\n"); } + return(scanner); + } + } + } + + /* fifth branch of the selection criterion : + are there constraints not already coded with a smaller + curdim_face ? */ + + /* are there constraints not already coded with a smaller + curdim_face ? choose the maximum curdim_face */ + level = -1; + for (i = graph_depth-1; i >= 0; i--) { + for (scanner = graph_levels[i]; scanner != (CONSTRAINT_E *) 0; + scanner = scanner->next ) { + if (scanner->face_ptr->first_valid == FALSE && + scanner->face_ptr->curdim_face > level) { + level = scanner->face_ptr->curdim_face; + temp_ptr = scanner; + } + } + } + /* is any of them of category 1 ? choose it */ + level = -1; + for (i = graph_depth-1; i >= 0; i--) { + for (scanner = graph_levels[i]; scanner != (CONSTRAINT_E *) 0; + scanner = scanner->next ) { + if (scanner->face_ptr->first_valid == FALSE && + scanner->face_ptr->category == 1 && + scanner->face_ptr->curdim_face == + temp_ptr->face_ptr->curdim_face ) { + level = scanner->face_ptr->curdim_face; + if (DEBUG) printf("The next chosen constraint is : %s \n", + scanner->relation); + /* computes seed_value */ + seed = start_seed(dim_cube,scanner->face_ptr->curdim_face); + strcpy(scanner->face_ptr->seed_value,seed); + free_mem(seed); + scanner->face_ptr->seed_valid = TRUE; + if (DEBUG) { printf("The seed is : %s\n", scanner->face_ptr->seed_value); + printf("next_to_code : branch n. 5.1\n"); } + return(scanner); + } + } + } + /* otherwise choose what pointed to by temptr */ + if (level == -1 && temp_ptr != (CONSTRAINT_E *) 0) { + if (DEBUG) printf("The next chosen constraint is : %s \n",temp_ptr->relation); + /* computes seed_value */ + seed = start_seed(dim_cube,temp_ptr->face_ptr->curdim_face); + strcpy(temp_ptr->face_ptr->seed_value,seed); + free_mem(seed); + temp_ptr->face_ptr->seed_valid = TRUE; + if (DEBUG) { printf("The seed is : %s\n", temp_ptr->face_ptr->seed_value); + printf("next_to_code : branch n. 5.2\n"); } + return(temp_ptr); + } + + /* PREVIOUS IMPLEMENTATION OF THE 5TH BRANCH - STARTS + for (level = constrptr->face_ptr->curdim_face; level >= 0; level--) { + if (DEBUG) printf("\nencoding level = %d \n", level); + for (i = graph_depth-1; i >= 0; i--) { + for (scanner = graph_levels[i]; scanner != (CONSTRAINT_E *) 0; + scanner = scanner->next ) { + if (scanner->face_ptr->first_valid == FALSE && + scanner->face_ptr->curdim_face == level ) { + if (DEBUG) printf("The next chosen constraint is : %s \n", + scanner->relation); + seed = start_seed(dim_cube,level); + strcpy(scanner->face_ptr->seed_value,seed); + free_mem(seed); + scanner->face_ptr->seed_valid = TRUE; + if (DEBUG) { printf("The seed is : %s\n", scanner->face_ptr->seed_value); + printf("next_to_code : branch n. 5\n"); } + return(scanner); + } + } + } + } + PREVIOUS IMPLEMENTATION OF THE 5TH BRANCH - ENDS */ + + return((CONSTRAINT_E *) 0); + +} + + + +/******************************************************************************* +* Inserts the constraint pointed to by curptr in the selection list and * +* returns a pointer to the last element added to the selection list ********************************************************************************/ + +CODORDER_LINK *insert_in_list(curptr,next_constr) +CODORDER_LINK *curptr; +CONSTRAINT_E *next_constr; + +{ + + CODORDER_LINK *ord_link; + + if ((ord_link = (CODORDER_LINK *) calloc((unsigned)1,sizeof(CODORDER_LINK))) == + ( CODORDER_LINK *) 0) { + fprintf(stderr,"Insufficient memory for ord_link in backtrack"); + exit(-1); + } + ord_link->constraint_e = next_constr; + ord_link->right = curptr; + curptr->left = ord_link; + ord_link->left = (CODORDER_LINK *) 0; + curptr = ord_link; + + return(curptr); + +} + + + +/* codes the universe constraint */ + +code_complete_constr(dim_cube,dim_face) +int dim_cube; +int dim_face; + +{ + + int j; + char *cube_code; + + if ( (cube_code = (char *) calloc((unsigned)dim_cube+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for cube_code in start_code"); + exit(-1); + } + + cube_code[dim_cube] = '\0'; + + for (j=0; jface_ptr->seed_value,cube_code); + graph_levels[graph_depth-1]->face_ptr->seed_valid = TRUE; + strcpy(graph_levels[graph_depth-1]->face_ptr->first_value,cube_code); + graph_levels[graph_depth-1]->face_ptr->first_valid = TRUE; + strcpy(graph_levels[graph_depth-1]->face_ptr->cur_value,cube_code); + graph_levels[graph_depth-1]->face_ptr->code_valid = TRUE; + graph_levels[graph_depth-1]->face_ptr->count_index = 1; + graph_levels[graph_depth-1]->face_ptr->comb_index = 1; + graph_levels[graph_depth-1]->face_ptr->lexmap_index = 1; + + free_mem(cube_code); + +} + + + + +/******************************************************************************* +* creates a face of dim_cube bits with dim_face x's and the pattern x..x0..0 * +*******************************************************************************/ + +char *copy_seed(dim_cube,cur_face) +int dim_cube; +char *cur_face; + +{ + + int j; + char *seed_code; + + if ( (seed_code = (char *) calloc((unsigned)dim_cube+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for seed_code"); + exit(-1); + } + + seed_code[dim_cube] = '\0'; + + for (j = 0; j < dim_cube; j++) { + seed_code[j] = cur_face[j]; + } + + return(seed_code); + +} + + +/******************************************************************************* +* creates a face of dim_cube bits with dim_face x's and the pattern x..x0..0 * +*******************************************************************************/ + +char *start_seed(dim_cube,dim_face) +int dim_cube; +int dim_face; + +{ + + int i,j; + char *seed_code; + + /* dim_face = number of x's in the face of "dim_cube" bits */ + + if ( (seed_code = (char *) calloc((unsigned)dim_cube+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for seed_code"); + exit(-1); + } + + seed_code[dim_cube] = '\0'; + + for (j=0; jconstraint_e->face_ptr->seed_value,dim_cube); + if (DEBUG) printf("\ngen_newcode_cat1 returned = %s\n", new_code); + + + /* debug print to show the selection list */ + level = mylog2(minpow2(curptr->constraint_e->card)); + + /* for all constraints already coded at the same level */ + if (DEBUG) { printf("\nConstraints at the same level already in ord_link :\n"); + for (ord_temptr = curptr; ord_temptr != (CODORDER_LINK *) 0; + ord_temptr = ord_temptr->right ) { + if ( mylog2(minpow2(ord_temptr->constraint_e->card)) == level ) { + printf("%s ", ord_temptr->constraint_e->relation); + } + } + printf("\n"); } + + if (DEBUG) printf("** Exit from assign_face_tofirst **\n"); + +} + + + +/******************************************************************************* +* Assigns a face to the current constraint * +* Given a constraint, it assigns to it a face compatible with the partial * +* assignment built up to now; at the same time, it assigns faces to those * +* constraints of category 2, that are children of the constraint being * +* currently encoded and have another father already encoded. * +* When unable to map a constraint to a face, it informs backtrack_down which * +* takes actions. * +* Faces are generated calling the routines gen_newface_catx, and they are * +* verified with help of the routines fathers_codes_ok and code_verify * +*******************************************************************************/ + +BOOLEAN assign_face(curptr,dim_cube,net_num) +CODORDER_LINK *curptr; +int dim_cube; +int net_num; + +{ + + CODORDER_LINK *ord_temptr; + SONS_LINK *son_scanner; + CONSTRAINT_E *scanner,*constrptr,*inter_ptr,*exist_son(); + char *new_code,*inter_code,*gen_newcode_cat1(),*gen_newcode_cat2(), + *gen_newcode_cat3(),*a_inter_b(); + int level; + BOOLEAN ok_to_code; + + if (DEBUG) printf("\n** Monitoring of assign_face **\n"); + + /* the faces of sons of curptr having it as codfather and already assigned + are cleared */ + constrptr = curptr->constraint_e; + for (son_scanner = constrptr->down_ptr; son_scanner != (SONS_LINK *) 0; + son_scanner = son_scanner->next ) { + if (son_scanner->codfather_ptr == constrptr) { + if (DEBUG) printf("\ncleared son : %s\n",son_scanner->constraint_e->relation); + son_scanner->constraint_e->face_ptr->seed_valid = FALSE; + son_scanner->constraint_e->face_ptr->first_valid = FALSE; + son_scanner->constraint_e->face_ptr->code_valid = FALSE; + son_scanner->constraint_e->face_ptr->count_index = 0; + son_scanner->constraint_e->face_ptr->comb_index = 0; + son_scanner->constraint_e->face_ptr->lexmap_index = 0; + son_scanner->constraint_e->face_ptr->dim_index = 0; + son_scanner->codfather_ptr = (CONSTRAINT_E *) 0; + } + } + + + ok_to_code = FALSE; + + /* generates a new code starting from the seed - according to the + category of constrptr a different gen_newcode is invoked */ + if (curptr->constraint_e->face_ptr->category == 1) { + new_code = gen_newcode_cat1(curptr, + curptr->constraint_e->face_ptr->seed_value,dim_cube); + if (DEBUG) printf("\ngen_newcode_cat1 returned = %s\n", new_code); + } + if (curptr->constraint_e->face_ptr->category == 2 ) { + new_code = gen_newcode_cat2(curptr,dim_cube); + if (DEBUG) printf("\ngen_newcode_cat2 returned = %s\n", new_code); + } + if (curptr->constraint_e->face_ptr->category == 3 ) { + new_code = gen_newcode_cat3(curptr,dim_cube); + if (DEBUG) printf("\ngen_newcode_cat3 returned = %s\n", new_code); + } + + while (new_code != (char *) 0) { + + /* checks if new_code satisfies the inclusion relations with + respect to the codes already assigned */ + if ( fathers_codes_ok(curptr->constraint_e,new_code,dim_cube) == 1 && + code_verify(curptr->constraint_e,new_code,net_num,dim_cube) == 1 ) { + + ok_to_code = TRUE; + if (DEBUG) printf("code_verify verified the code\n"); + + /* assigns faces to those constraints of category 2, that are + children of the constraint being currently encoded and have + another father already encoded */ + for (level = graph_depth-1; level >= 0; level--) { + for (scanner = graph_levels[level]; scanner != (CONSTRAINT_E *) 0; + scanner = scanner->next ) { + if (scanner->face_ptr->code_valid != FALSE && + scanner != curptr->constraint_e) { + + /* that have a non-void intersection with the current one */ + inter_ptr = + exist_son(scanner,curptr->constraint_e,dim_cube); + + if ( inter_ptr != (CONSTRAINT_E *) 0 ) { + + if (DEBUG) { printf("\nThere are non-empty intersections\n"); + printf("%s intersects with ", + curptr->constraint_e->relation); + printf("%s ", scanner->relation); + printf("in %s\n", inter_ptr->relation); } + inter_code = a_inter_b(scanner->face_ptr->cur_value, + curptr->constraint_e->face_ptr->cur_value, + inter_ptr->card,dim_cube); + + if ( inter_ptr->face_ptr->code_valid == FALSE ) { + /* intersection not already coded */ + + /*printf("It has not been already coded \n");*/ + + /* if possible, a face is assigned to the + intersection, otherwise ok_to_code = FALSE and + break */ + if (DEBUG) { printf("codes = %s ", + curptr->constraint_e->face_ptr->cur_value); + printf("and = %s ", scanner->face_ptr->cur_value); } + if ( inter_code != (char *) 0 ) { + if (DEBUG) printf("intersect in %s (feasible code)\n", + inter_code); + } else { + if (DEBUG) printf("intersect in a non-feasible code\n"); + } + + if ( inter_code != (char *) 0 ) { + + if ( fathers_codes_ok(inter_ptr,inter_code, + dim_cube) == 1 && + code_verify(inter_ptr,inter_code,net_num, + dim_cube) == 1 ) { + if (DEBUG) printf("code_verify verified the code\n"); + ok_to_code = TRUE; + /* a face is assigned to the intersection */ + strcpy(inter_ptr->face_ptr->first_value,inter_code); + inter_ptr->face_ptr->first_valid = + TRUE; + strcpy(inter_ptr->face_ptr->cur_value,inter_code); + free_mem(inter_code); + inter_ptr->face_ptr->code_valid = TRUE; + inter_ptr->face_ptr->count_index = 1; + inter_ptr->face_ptr->comb_index = 1; + inter_ptr->face_ptr->lexmap_index = 1; + /* sets properly codfather_ptr */ + set_codfather(curptr->constraint_e, + inter_ptr); + + } else { + + ok_to_code = FALSE; + free_mem(inter_code); + break; + + } + } else { + + ok_to_code = FALSE; + break; + + } + + } else { + + /* intersection already coded */ + if (DEBUG) printf("Its already assigned code is : %s\n", + inter_ptr->face_ptr->cur_value); + if ( strcmp(inter_code, + inter_ptr->face_ptr->cur_value) == 0 ) { + if (DEBUG) printf("Codes are compatible\n"); + ok_to_code = TRUE; + free_mem(inter_code); + + } else { + if (DEBUG) printf("Codes are incompatible\n"); + ok_to_code = FALSE ; + free_mem(inter_code); + break; + + } + + } + + } + + } + + } + if (ok_to_code == FALSE) break; + } + + } + + if ( ok_to_code == FALSE ) { + + /* generates a new code starting from the seed - according to the + category of constrptr a different gen_newcode is invoked */ + if (curptr->constraint_e->face_ptr->category == 1) { + new_code = gen_newcode_cat1(curptr, + curptr->constraint_e->face_ptr->seed_value,dim_cube); + if (DEBUG) printf("\ngen_newcode_cat1 returned = %s\n", new_code); + } + if (curptr->constraint_e->face_ptr->category == 2 ) { + new_code = gen_newcode_cat2(curptr,dim_cube); + if (DEBUG) printf("\ngen_newcode_cat2 returned = %s\n", new_code); + } + if (curptr->constraint_e->face_ptr->category == 3 ) { + new_code = gen_newcode_cat3(curptr,dim_cube); + if (DEBUG) printf("\ngen_newcode_cat3 returned = %s\n", new_code); + } + + } else { /* ok_to_code == TRUE */ + break; + } + + } + + + /* for all constraints already coded in ord_link */ + if (DEBUG) { printf("\nConstraints already in ord_link :\n"); + for (ord_temptr = curptr; ord_temptr != (CODORDER_LINK *) 0; + ord_temptr = ord_temptr->right ) { + printf("%s ", ord_temptr->constraint_e->relation); + } + printf("\n"); } + + + if (DEBUG) printf("** Exit from assign_face **\n"); + + if ( new_code != (char *) 0) { + return(TRUE); + } else { + return(FALSE); + } + +} + + + +/******************************************************************************* +* are the constraints constrptr1 and constrptr2 connected to an intersection * +* constraint ? * +* i.e., among the children of constrptr1 is there any who is also a child of * +* constrptr2 ? * +* if yes and the dimension of the intersection of the fathers' faces is <= * +* than the current face dimension of the son * +* a pointer to the son is returned ; * +* otherwise (i.e., if a) yes and the dimen. of the inter. of the fathers' * +* faces is > than the current face dimension of the son * +* b) or there is no intersection constraint) * +* a pointer to nil is returned . * +* In case b) the reason is that there is more than 1 possible code and we can * +* generate these codes only via invoking gen_newcode_cat2 at the upper level, * +* while we can code intersections as a byproduct of other coding operations * +* only when they can have at most one code ; notice that this was a practical * +* design decision due to a later understanding of this circumstance * +*******************************************************************************/ + +CONSTRAINT_E *exist_son(constrptr1,constrptr2,dim_cube) +CONSTRAINT_E *constrptr1; +CONSTRAINT_E *constrptr2; +int dim_cube; + +{ + + SONS_LINK *son_scanner; + FATHERS_LINK *ft_scanner; + int dim_fathers_inter(); + + /* are the constraints constrptr1 and constrptr2 connected to an + intersection constraint ? + i.e., among the children of constrptr1 is there any who is also + child of constrptr2 ? */ + for (son_scanner = constrptr1->down_ptr; son_scanner != (SONS_LINK *) 0; + son_scanner = son_scanner->next ) { + for (ft_scanner = son_scanner->constraint_e->up_ptr; + ft_scanner != (FATHERS_LINK *) 0; + ft_scanner = ft_scanner->next) { + if ( ( ft_scanner->constraint_e == constrptr2 ) && + ( dim_fathers_inter(constrptr1->face_ptr->cur_value, + constrptr2->face_ptr->cur_value,dim_cube) <= + son_scanner->constraint_e->face_ptr->curdim_face ) ) { + /*printf("op. # 1 = %d\n",dim_fathers_inter(constrptr1->face_ptr->cur_value,constrptr2->face_ptr->cur_value,dim_cube)); + printf("op. # 2 = %d\n",son_scanner->constraint_e->face_ptr->curdim_face);*/ + /* if the dimension of the intersection of the fathers' + faces is <= than the current face dimension of the son + a pointer to the son is returned - + if the dimen. of the inter. of the fathers' faces is > + than the current face dimension of the son a pointer to + nil is returned, because there is more than 1 possible + code and we can generate these codes only via invoking + gen_newcode_cat2 at the upper level, while we can code + intersections as a byproduct of other coding operations + only when they can have at most one code - + notice that this is an implementation choice due to a + later understanding of this situation */ + return(son_scanner->constraint_e); + } + } + } + + return((CONSTRAINT_E *) 0); + +} + + + +/******************************************************************************* +* called by assign_face : let codfather_ptr of constrptr2 point to constrptr1 * +*******************************************************************************/ + +set_codfather(constrptr1,constrptr2) +CONSTRAINT_E *constrptr1; +CONSTRAINT_E *constrptr2; + +{ + + SONS_LINK *son_scanner; + + for (son_scanner = constrptr1->down_ptr; son_scanner != (SONS_LINK *) 0; + son_scanner = son_scanner->next ) { + if (son_scanner->constraint_e == constrptr2) { + son_scanner->codfather_ptr = constrptr1; + if (DEBUG) printf("The codfather of %s is %s\n", constrptr2->relation , + son_scanner->codfather_ptr->relation); + break; + } + } + +} + + + +/******************************************************************************* +* The verifications of a new proposed code carried on by this routine are : * +* 1) if the new constraint has only one father, the latter's face must include * +* properly the face proposed for the former * +* 2) if the new constraint has more than one father : * +* 2.1) if the dimension of the intersection of the faces assigned * +* to the fathers is > than curdim_face of the son : * +* ditto intersection must contain (also not properly) the face * +* proposed for the son * +* 2.2) if the dimension of the intersection of the fathers is == * +* to curdim_face of the son : * +* the faces assigned to the fathers must intersect in the face * +* proposed for the son * +*******************************************************************************/ + +fathers_codes_ok(refptr,code,dim_cube) +CONSTRAINT_E *refptr; +char *code; +int dim_cube; + +{ + + FATHERS_LINK *father_scanner; + char *ft_inter,*a_inter_b(),*prov_ptr; + BOOLEAN flag; + int i; + + flag = FALSE; + + if ( (ft_inter = (char *) calloc((unsigned)dim_cube+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for ft_inter in fathers_codes_ok"); + exit(-1); + } + + ft_inter[dim_cube] = '\0'; + for (i=0; irelation);*/ + if ( refptr->up_ptr->next == (FATHERS_LINK *) 0 ) { + if ( refptr->up_ptr->constraint_e->face_ptr->code_valid != FALSE ) { + /*printf("%s \n", refptr->up_ptr->constraint_e->relation);*/ + if ( face1_incl_face2(refptr->up_ptr->constraint_e->face_ptr->cur_value, + code,dim_cube) == 1 ) { + /*printf("Father satisfied : %s includes %s\n", + refptr->up_ptr->constraint_e->face_ptr->cur_value,code);*/ + flag = TRUE; + free_mem(ft_inter); + return(flag); + } + } + + } else { + + /* 2) if the new constraint has more than one father : + (notice that every constraint (except the universe) has either 1 or + more fathers, and that only constraints with more than 1 father + reach this point) */ + for (father_scanner = refptr->up_ptr; father_scanner != (FATHERS_LINK *) 0; + father_scanner = father_scanner->next ) { + if ( father_scanner->constraint_e->face_ptr->code_valid != FALSE ) { + /*printf("%s \n", father_scanner->constraint_e->relation);*/ + prov_ptr = ft_inter; + ft_inter = a_inter_b(ft_inter, + father_scanner->constraint_e->face_ptr->cur_value,0,dim_cube); + free_mem(prov_ptr); + + } + } + + /* 2.1) if the dimension of the intersection of the faces assigned + to the fathers is > than curdim_face of the son : + ditto intersection must contain (also not properly) the face + proposed for the son */ + if (dim_face(ft_inter,dim_cube) > refptr->face_ptr->curdim_face) { + if ( face1_incl2_face2(ft_inter,code,dim_cube) == 1 ) { + /*printf( + "Fathers satisfied : ft_inter = %s includes code = %s \n", + ft_inter, code); + printf("fathers_codes_ok verified the code\n");*/ + flag = TRUE; + free_mem(ft_inter); + return(flag); + } + } + /* 2.2) if the dimension of the intersection of the fathers is == + to curdim_face of the son : + the faces assigned to the fathers must intersect in the face + proposed for the son */ + if (dim_face(ft_inter,dim_cube) == refptr->face_ptr->curdim_face) { + if ( strcmp(ft_inter,code) == 0 ) { + /*printf( + "Fathers satisfied : ft_inter = %s and code = %s coincide\n", + ft_inter, code); + printf("fathers_codes_ok verified the code\n");*/ + flag = TRUE; + free_mem(ft_inter); + return(flag); + } + } + + } + + free_mem(ft_inter); + + return(flag); + +} + + + +/******************************************************************************* +* computes the intersection of the codes assigned to the fathers of refptr * +*******************************************************************************/ + +char *fathers_codes_inter(refptr,dim_cube) +CONSTRAINT_E *refptr; +int dim_cube; + +{ + + FATHERS_LINK *father_scanner; + char *ft_inter,*prov_ptr,*a_inter_b(); + int i; + + if ( (ft_inter = (char *) calloc((unsigned)dim_cube+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for ft_inter in fathers_code_inter"); + exit(-1); + } + + ft_inter[dim_cube] = '\0'; + for (i=0; irelation); + if ( refptr->up_ptr->next == (FATHERS_LINK *) 0 ) { + if ( refptr->up_ptr->constraint_e->face_ptr->code_valid != FALSE ) { + if (DEBUG) { printf("%s ", refptr->up_ptr->constraint_e->relation); + printf("with intersection = %s \n", + refptr->up_ptr->constraint_e->face_ptr->cur_value);} + strcpy(ft_inter,refptr->up_ptr->constraint_e->face_ptr->cur_value); + return(ft_inter); + } + + } else { + + for (father_scanner = refptr->up_ptr; father_scanner != (FATHERS_LINK *) 0; + father_scanner = father_scanner->next ) { + if ( father_scanner->constraint_e->face_ptr->code_valid != FALSE ) { + if (DEBUG){ printf("%s ",father_scanner->constraint_e->relation); + printf("with code %s \n", + father_scanner->constraint_e->face_ptr->cur_value);} + prov_ptr = ft_inter; + ft_inter = a_inter_b(ft_inter, + father_scanner->constraint_e->face_ptr->cur_value,0,dim_cube); + free_mem(prov_ptr); + + } + } + + if (DEBUG) printf("and intersection = %s \n",ft_inter); + + return(ft_inter); + + } + + return(0); + +} + + + +/******************************************************************************* +* The verifications of a new proposed code carried on by this routine are : * +* 1) an assigned face shouldn't coincide with the new one * +* 2) if an assigned face includes properly the new one, the old constraint * +* should be a father of the new one * +* 3) if the new face includes properly a face already assigned, the new * +* constraint should be a father of the old one * +* 4) if an assigned face has a non-empty intersection with the new one (and * +* both of them contain properly the intersection), the related constraints * +* should have a non_empty intersection * +* A last check helpful for efficiency, not necessary for correcteness : * +* 5) if an already coded constraint (not of cardinality 1) has a nonempty * +* intersection with the current constraint (not cardinality 1) the related * +* faces must intersect in a subface large enough to contain the * +* intersection of the constraints * +*******************************************************************************/ + +code_verify(refptr,code,net_num,dim_cube) +CONSTRAINT_E *refptr; +char *code; +int net_num; +int dim_cube; + +{ + + CONSTRAINT_E *constrptr; + char *inter_code,*inter_constr,*a_inter_b(),*c1_inter_c2(); + int i,state_pos1,state_pos2; + + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + if ( constrptr != refptr && constrptr->face_ptr->code_valid != + FALSE ) { + + /* 1) an assigned face must not coincide with the new one */ + if ( strcmp(constrptr->face_ptr->cur_value,code) == 0 ) { + if (DEBUG) printf("The code already exists\n"); + return(0); + } + + /* 2) if an assigned face includes properly the new one the old + constraint must be a father of the new one */ + if ( face1_incl_face2(constrptr->face_ptr->cur_value,code, + dim_cube) == 1 ) { + if ( p_incl_s(constrptr->relation,refptr->relation) == 0 ) { + if (DEBUG) printf("%s includes properly %s but %s is not father of %s\n", + constrptr->face_ptr->cur_value, code, + constrptr->relation, refptr->relation); + return(0); + } + } + + /* 3) if the new face includes properly a face already assigned + the new constraint must be a father of the old one */ + if ( face1_incl_face2(code,constrptr->face_ptr->cur_value, + dim_cube) == 1 ) { + if ( p_incl_s(refptr->relation,constrptr->relation) == 0 ) { + if (DEBUG) printf("%s includes properly %s but %s is not father of %s\n", + code, constrptr->face_ptr->cur_value, + refptr->relation, constrptr->relation ); + return(0); + } + } + + /* 4) if an assigned face has a non-empty intersection with + the new one ( and both of them contain the intersection + properly ) the related constraints must have a non_empty + intersection */ + inter_code = a_inter_b(constrptr->face_ptr->cur_value,code,0, + dim_cube); + if ( inter_code != (char *) 0 && + face1_incl_face2(constrptr->face_ptr->cur_value,inter_code, + dim_cube) == 1 && + face1_incl_face2(code,inter_code,dim_cube) == 1 ) { + inter_constr = c1_inter_c2(constrptr->relation, + refptr->relation,net_num); + if ( inter_constr == (char *) 0 ) { + if (DEBUG) printf("%s and %s intersect but %s and %s don't\n", + constrptr->face_ptr->cur_value, code, + constrptr->relation, refptr->relation); + free_mem(inter_code); + return(0); + } + free_mem(inter_constr); + } + free_mem(inter_code); + + /* A last check helpful for efficiency, not necessary for + correcteness : + 5) if an already coded constraint (not of cardinality 1) has + a nonempty intersection with the current constraint (not of + of cardinality 1) the related faces must intersect in a + subface large enough to contain the intersection of the + constraints */ + if (refptr->card != 1 && constrptr->card != 1) { + inter_constr = c1_inter_c2(constrptr->relation, + refptr->relation,net_num); + if ( inter_constr != (char *) 0 ) { + inter_code = a_inter_b(constrptr->face_ptr->cur_value, + code,card_c1(inter_constr,net_num),dim_cube); + if ( inter_code == (char *) 0 ) { + if (DEBUG) printf("%s & %s intersect but %s and %s don't\n", + constrptr->relation, refptr->relation, + constrptr->face_ptr->cur_value, code); + free_mem(inter_constr); + return(0); + } + free_mem(inter_code); + free_mem(inter_constr); + } + } + + } + } + } + + if ( (IO_HYBRID || IO_VARIANT) && OUT_VERIFY && refptr->card == 1) { + state_pos1 = locate_state(refptr->relation,net_num); + if (DEBUG) printf("\n\noutput verification of state %d (%s)", state_pos1, code); + for (constrptr = graph_levels[0]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + if ( constrptr != refptr && constrptr->face_ptr->code_valid != FALSE ) { + state_pos2 = locate_state(constrptr->relation,net_num); + if (DEBUG) printf("\nversus state %d (%s) : ", state_pos2, + constrptr->face_ptr->cur_value); + /* if order_array(state_pos1,state_pos2) is = 1 then the + code of state_pos2 ought to cover the code of state_pos1 */ + if (select_array[state_pos1] == USED && + order_array[state_pos1][state_pos2] == ONE) { + if ( codei_covers_codej(constrptr->face_ptr->cur_value,code) + == 0 ) { + if (DEBUG) printf("%d doesn't cover %d",state_pos2,state_pos1); + return(0); + } + if (DEBUG) printf("%d covers %d",state_pos2,state_pos1); + } + /* if order_array(state_pos2,state_pos1) is = 1 then the + code of state_pos1 ought to cover the code of state_pos2 */ + if (select_array[state_pos2] == USED && + order_array[state_pos2][state_pos1] == ONE) { + if ( codei_covers_codej(code,constrptr->face_ptr->cur_value) + == 0 ) { + if (DEBUG) printf("%d doesn't cover %d",state_pos1,state_pos2); + return(0); + } + if (DEBUG) printf("%d covers %d",state_pos1,state_pos2); + } + } + } + } + + return(1); + +} + + + +/******************************************************************************* +* updates the counters of the # of codes tried up to now * +* and prints the # of codes tried in the last backtrack_down * +* * +* "local_work" counts the codes tried in the last backtrack_down * +* "cube_work" counts the codes tried in the current cube * +* "total_work" counts the codes tried in overall by exact_code * +*******************************************************************************/ + +btkdown_summary() + +{ + + CONSTRAINT_E *constrptr_e; + int local_work; + int i; + + local_work = 0; + + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr_e = graph_levels[i]; constrptr_e != (CONSTRAINT_E *) 0; + constrptr_e = constrptr_e->next ) { + local_work = local_work + constrptr_e->face_ptr->tried_codes; + } + } + + /* cube_work (global variable) is set to 0 in faces_dim_set */ + cube_work += local_work; + /* total_work (global variable) is set to 0 in faces_alloc */ + total_work += local_work; + + if (VERBOSE) { + printf("\nBTKDOWN_SUMMARY : \n", local_work); + printf("local_work = %d\n", local_work); + } + +} + + + +BOOLEAN toomuch_work() + +{ + + CONSTRAINT_E *constrptr_e; + int local_work; + int i; + + local_work = 0; + + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr_e = graph_levels[i]; constrptr_e != (CONSTRAINT_E *) 0; + constrptr_e = constrptr_e->next ) { + local_work = local_work + constrptr_e->face_ptr->tried_codes; + } + } + + if ( local_work > MAXWORK) { + if (VERBOSE) + printf("\nBacktrack interrupted : SEARCH TOO LONG OR CUBE TOO SMALL\n"); + return(TRUE); + } + else return(FALSE); + +} + + + +int locate_state(relation,net_num) +char *relation; +int net_num; + +{ + + int i; + + for (i = 0; i < net_num; i++) { + if (relation[i] == ONE) break; + } + + return(i); + +} diff --git a/nova/exact_code.c b/nova/exact_code.c new file mode 100644 index 0000000..9f88d1d --- /dev/null +++ b/nova/exact_code.c @@ -0,0 +1,482 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/exact_code.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +/****************************************************************************** +* Exact encoding algorithm * +* * +******************************************************************************/ + + +#include "nova.h" + +exact_code(net_num) +int net_num; + +{ + + int dim_cube,least_cube; + BOOLEAN code_found,outer_loop,init_backtrack_up(),backtrack_up(), + backtrack_down(); + + if (VERBOSE) { printf("\n\nExact_code\n"); printf("==========\n"); } + + faces_alloc(net_num); + + code_found = FALSE; + least_cube = least_dimcube(net_num); + if (VERBOSE) printf("least_cube = %d\n", least_cube); + + /* decides the categories and bounds of the faces (func. of dim_cube) - + the dimension of the hypercube (it might be increased) is returned */ + least_cube = faces_dim_set(least_cube); + + for (dim_cube = least_cube; dim_cube <= net_num; dim_cube++) { + if (VERBOSE) printf("\nCURRENT dim_cube = %d\n", dim_cube); + + /* finds a starting feasible configuration of the dimensions of faces */ + outer_loop = init_backtrack_up(); + + while (code_found == FALSE && outer_loop == TRUE) { + + /* finds an encoding (if any) for the current configuration */ + code_found = backtrack_down(net_num,dim_cube); + + /*if no code was found sets a new feasible configuration (if any) */ + if (code_found == FALSE) { + outer_loop = backtrack_up(); + } + + } + + cube_summary(); + + if (code_found == TRUE) { + if (VERBOSE) + printf("\nA code was found for dim_cube = %d\n", dim_cube); + break; + } + + /* maxdim of constraints of category 0 & 1 are updated because + dim_cube is increased by 1 in the coming iteration */ + faces_maxdim_set(dim_cube + 1); + + } + + if (code_found == FALSE) { + /*something went wrong*/ + if (VERBOSE) + printf("SOMETHING WENT WRONG : no code found in the maximum cube\n"); + exit(-1); + } + + exact_summary(); + +} + + + +/******************************************************************************* +* allocates memory for the faces and connects them to the graph_levels array * +*******************************************************************************/ + +faces_alloc(net_num) +int net_num; + +{ + + FACE *new_face; + CONSTRAINT_E *constrptr_e; + int i; + + /* total_work (global variable) counts the # of codes tried in overall + by exact_code */ + total_work = 0; + /* bktup_calls (global variable) counts the # of face configurations + tried in all */ + bktup_calls = 1; + + /* set to true to start next_to_code on constraints of category 1 */ + SEL_CAT1 = TRUE; + + /* it allocates the FACE data structure */ + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr_e = graph_levels[i]; constrptr_e != (CONSTRAINT_E *) 0; + constrptr_e = constrptr_e->next ) { + if ((new_face = (FACE *) calloc((unsigned)1,sizeof(FACE))) == ( FACE *) 0) { + fprintf(stderr,"Insufficient memory for face in faces_alloc"); + exit(-1); + } + constrptr_e->face_ptr = new_face; + + if ((constrptr_e->face_ptr->seed_value = (char *) calloc((unsigned)net_num+1,sizeof(char))) == ( char *) 0) { + fprintf(stderr,"Insufficient memory for seed_value in faces_alloc"); + exit(-1); + } + if ((constrptr_e->face_ptr->first_value = (char *) calloc((unsigned)net_num+1,sizeof(char))) == ( char *) 0) { + fprintf(stderr,"Insufficient memory for first_value in faces_alloc"); + exit(-1); + } + if ((constrptr_e->face_ptr->cur_value = (char *) calloc((unsigned)net_num+1,sizeof(char))) == ( char *) 0) { + fprintf(stderr,"Insufficient memory for cur_value in faces_alloc"); + exit(-1); + } + + constrptr_e->face_ptr->code_valid = FALSE; + constrptr_e->face_ptr->tried_codes = 1; + } + } + +} + + + +/******************************************************************************* +* Sets the categories & mindim,curdim and maxdim of the faces that can * +* be assigned to the constraints (function of dim_cube) - * +* it returns the dimension of the hypercube : it may be increased * +* with respect to its input value as a consequence of the fact that * +* the dimensions of the faces of some constraints may need to be * +* increased to be able to contain other constraints at the same level * +* (i.e. sons at the same level) * +*******************************************************************************/ + +int faces_dim_set(dim_cube) +int dim_cube; + +{ + + FATHERS_LINK *ft_scanner; + CONSTRAINT_E *constrptr,*supremum_ptr; + int i,fathers_num,new_dimcube; + + /* cube_work (global variable) counts the # of codes tried in the current + cube */ + cube_work = 0; + + /* PART A + The constraints are classified in categories : + 1) the complete constraint is of category 0; + 2) constraints whose unique father is the complete constraint are + of category 1; + 3) constraints whose unique father is not the complete constraint + are of category 3; + 4) constraints with at least two fathers are of category 2 - + + The dimensions of the faces of the constraints are set on the basis + of the minimum feasible dimension and of current hypercube dimension */ + + if (VERBOSE) printf("\nFaces_dim_set - Part A :\n"); + + /* takes care of the complete constraint */ + supremum_ptr = graph_levels[graph_depth-1]; + supremum_ptr->face_ptr->category = 0; + if (VERBOSE) + printf("constraint %s is of cat. %d ",supremum_ptr->relation, + supremum_ptr->face_ptr->category); + supremum_ptr->face_ptr->mindim_face = dim_cube; + supremum_ptr->face_ptr->maxdim_face = dim_cube; + supremum_ptr->face_ptr->curdim_face = dim_cube; + if (VERBOSE) + printf("curdim_face = %d\n", supremum_ptr->face_ptr->curdim_face); + + for (i = graph_depth-2; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + + fathers_num = 0; + for (ft_scanner = constrptr->up_ptr; + ft_scanner != (FATHERS_LINK *) 0; ft_scanner = ft_scanner->next) { + fathers_num++; + } + + /* if the constraint has only one father */ + if (fathers_num == 1) { + /* if the father is the complete constraint */ + if (constrptr->up_ptr->constraint_e == supremum_ptr) { + constrptr->face_ptr->category = 1; + if (VERBOSE) + printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category); + if (constrptr->card == 1) { + /* the dimension of faces of constraints of category 1 + and cardinality 1 is nailed down to 0 */ + constrptr->face_ptr->mindim_face = + mylog2(minpow2(constrptr->card)); + if (VERBOSE) printf("mindim_face = %d ", + constrptr->face_ptr->mindim_face); + constrptr->face_ptr->maxdim_face = + constrptr->face_ptr->mindim_face; + if (VERBOSE) printf("maxdim_face = %d \n", + constrptr->face_ptr->maxdim_face); + } else { + constrptr->face_ptr->mindim_face = + mylog2(minpow2(constrptr->card)); + if (VERBOSE) printf("mindim_face = %d ", + constrptr->face_ptr->mindim_face); + constrptr->face_ptr->maxdim_face = dim_cube - 1; + if (VERBOSE) printf("maxdim_face = %d \n", + constrptr->face_ptr->maxdim_face); + } + } else { + constrptr->face_ptr->category = 3; + if (VERBOSE) + printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category); + constrptr->face_ptr->mindim_face = + mylog2(minpow2(constrptr->card)); + constrptr->face_ptr->curdim_face = + constrptr->face_ptr->mindim_face; + if (VERBOSE) printf("mindim_face = %d\n", + constrptr->face_ptr->mindim_face); + } + } + + /* if the constraint has at least two fathers */ + if (fathers_num > 1) { + constrptr->face_ptr->category = 2; + if (VERBOSE) + printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category); + constrptr->face_ptr->mindim_face = + mylog2(minpow2(constrptr->card)); + constrptr->face_ptr->curdim_face = + constrptr->face_ptr->mindim_face; + if (VERBOSE) printf("mindim_face = %d\n", + constrptr->face_ptr->mindim_face); + } + + } + } + + + /* PART B + mindim_face & curdim_face of all constraints are recomputed by + max_tree (called on the complete constraint) - + it must be done because the dimensions of the faces of some + constraints may need to be increased to be able to contain other + constraints at the same level (i.e. sons at the same level) - + this process may end up increasing the dimension of the complete + constraint, i.e. increasing the dimension of the hypercube - + this plays the role of another necessary condition (besides those + implemented in least_dimcube) that needs to be satisfied by the + hypercube dimension to allow a feasible embedding */ + new_dimcube = max_tree(graph_levels[graph_depth-1]); + + /* FORZATURA DELLA DIMENSIONE PER PROVA */ + /*new_dimcube = 6;*/ + /* FORZATURA DELLA DIMENSIONE PER PROVA - FINE */ + + /* if the hypercube dimension has been increased, also maxdim_face of + constraints of category 0 & 1 need to be updated */ + if (new_dimcube > dim_cube) { + if (VERBOSE)printf("\nThe cube dimension went up to %d\n", new_dimcube); + faces_maxdim_set(new_dimcube); + } + + if (VERBOSE) { + printf("\nFaces_dim_set - Part B :\n"); + show_dimfaces(); + } + + /* FORZATURA DELLE FACCE PER PROVA */ + /*new_dimcube = 6; + if (VERBOSE) printf("\nThe cube dimension went up to %d\n", new_dimcube); + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + if (strcmp(constrptr->relation,"11111111") == 0) { + constrptr->face_ptr->mindim_face = 6; + constrptr->face_ptr->curdim_face = 6; + constrptr->face_ptr->maxdim_face = 6; + } + if (strcmp(constrptr->relation,"01001010") == 0) { + constrptr->face_ptr->mindim_face = 4; + constrptr->face_ptr->maxdim_face = 4; + } + if (strcmp(constrptr->relation,"00110010") == 0) { + constrptr->face_ptr->mindim_face = 3; + constrptr->face_ptr->maxdim_face = 3; + } + if (strcmp(constrptr->relation,"01001100") == 0) { + constrptr->face_ptr->mindim_face = 4; + constrptr->face_ptr->maxdim_face = 4; + } + if (strcmp(constrptr->relation,"00110100") == 0) { + constrptr->face_ptr->mindim_face = 4; + constrptr->face_ptr->maxdim_face = 4; + } + if (strcmp(constrptr->relation,"11010100") == 0) { + constrptr->face_ptr->mindim_face = 4; + constrptr->face_ptr->maxdim_face = 4; + } + if (strcmp(constrptr->relation,"10101010") == 0) { + constrptr->face_ptr->mindim_face = 5; + constrptr->face_ptr->maxdim_face = 5; + } + if (strcmp(constrptr->relation,"00000110") == 0) { + constrptr->face_ptr->mindim_face = 3; + constrptr->face_ptr->maxdim_face = 3; + } + } + } + if (VERBOSE) printf("\nFaces_dim_set - Part C :\n"); + show_dimfaces();*/ + /* FORZATURA DELLE FACCE PER PROVA - FINE */ + + return(new_dimcube); + +} + + + +/******************************************************************************* +* recursive procedure to compute the mindim_face of root_ptr to accomodate the * +* the subdag rooted here - * +* if mindim_face of root_ptr is bigger than the minimum dimension of the * +* subgraph rooted here return mindim_face of root_ptr (i.e., it can accomodate * +* the subgraph rooted here), * +* otherwise update mindim_face & curdim_face of face_ptr to the minimum * +* dimension of the subgraph + 1 and return it (i.e., it needs a dimension * +* larger by one to accomodate the subgraph rooted here) * +*******************************************************************************/ + +int max_tree(root_ptr) +CONSTRAINT_E *root_ptr; + +{ + + SONS_LINK *son_scanner; + int local_max; + int parz_max; + + /*printf("max_tree called by %s\n", root_ptr->relation);*/ + + if (root_ptr->down_ptr == (SONS_LINK *) 0) { + /*printf("max_tree evaluates to %d\n", root_ptr->face_ptr->mindim_face);*/ + return(root_ptr->face_ptr->mindim_face); + } else { + local_max = -1; + for (son_scanner = root_ptr->down_ptr; son_scanner != (SONS_LINK *) 0; + son_scanner = son_scanner->next ) { + /* computes the max of max_tree of the sons of root_ptr */ + parz_max = max_tree(son_scanner->constraint_e); + if (local_max < parz_max) { + local_max = parz_max; + } + } + /*printf("local_max = %d\n", local_max);*/ + /* if mindim_face of root_ptr is bigger than the minimum dimension of + the subgraph rooted here return mindim_face of root_ptr (i.e., it + can accomodate the subgraph rooted here), + otherwise update mindim_face & curdim_face of face_ptr to the + minimum dimension of the subgraph + 1 and return it (i.e., it + needs a dimension larger by one to accomodate the subgraph rooted + here) */ + if ( root_ptr->face_ptr->mindim_face > + (local_max) ) { + /*printf("max_tree evaluates to %d\n", + root_ptr->face_ptr->mindim_face);*/ + return(root_ptr->face_ptr->mindim_face); + } else { + root_ptr->face_ptr->mindim_face = + local_max + 1; + root_ptr->face_ptr->curdim_face = + local_max + 1; + /*printf("max_tree evaluates to %d\n", local_max +1);*/ + return(local_max + 1); + } + } +} + + + +/******************************************************************************* +* updates the maxdim of the faces of constraints of category 0 & 1 * +* (function of dim_cube) * +*******************************************************************************/ + +faces_maxdim_set(dim_cube) +int dim_cube; + +{ + + CONSTRAINT_E *constrptr; + int i; + + /* cube_work (global variable) counts the # of codes tried in the current + cube */ + cube_work = 0; + + /*printf("\nFace_maxdim_set results :\n");*/ + + /* maxdim of constraints of category 0 & 1 are updated (only for constraints + of category 0 & 1 maxdim matters at the upper level) */ + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + if (constrptr->face_ptr->category == 0) { + /*printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category);*/ + constrptr->face_ptr->mindim_face = dim_cube; + constrptr->face_ptr->maxdim_face = dim_cube; + constrptr->face_ptr->curdim_face = dim_cube; + /*printf("curdim_face = %d\n", + constrptr->face_ptr->curdim_face);*/ + } + if (constrptr->face_ptr->category == 1 && constrptr->card != 1) { + /*printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category);*/ + constrptr->face_ptr->maxdim_face = dim_cube - 1; + /*printf("maxdim_face = %d \n", + constrptr->face_ptr->maxdim_face);*/ + } + } + } + +} + + + +/******************************************************************************* +* prints a summary of the work done in the current cube * +* * +* cube_work counts the # of codes tried in the current cube * +*******************************************************************************/ + +cube_summary() + +{ + + if (VERBOSE) { + printf("\nCUBE_SUMMARY : \n"); + printf("cube_work = %d\n", cube_work); + } + +} + + + +/******************************************************************************* +* prints a summary of exact_code * +* * +* bktup_calls counts the # of face configurations tried in all * +* total_work counts the # of codes tried in overall by exact_code * +*******************************************************************************/ + +exact_summary() + +{ + + if (VERBOSE) { + printf("\nEXACT_SUMMARY : \n"); + printf("bktup_calls = %d\n", bktup_calls); + printf("total_work = %d\n", total_work); + } + +} diff --git a/nova/exact_graph.c b/nova/exact_graph.c new file mode 100644 index 0000000..6e7453d --- /dev/null +++ b/nova/exact_graph.c @@ -0,0 +1,408 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/exact_graph.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +/****************************************************************************** +* Builds the graph of the inclusions among the constraints * +* * +******************************************************************************/ + +#include "nova.h" + +exact_graph(net,net_num) +CONSTRAINT **net; +int net_num; + +{ + + /* graph_depth is set to max(inputnum,statenum) in array_alloc + and here is reset to the exact depth of the graph of net */ + graph_depth = mylog2(minpow2(net_num)) + 2; + + /* builds the graph of the constraints as given by the problem */ + base_graph(net); + + if (DEBUG) { + printf("\nGraph of the constraints for the exact algorithm "); + printf("( %d levels )\n" , mylog2(minpow2(net_num)) +1 ); + printf("\nAfter base_graph :\n"); + printf("---------------- \n"); + show_graph(); + } + + inter_graph(net_num); + if (DEBUG) { + printf("\nAfter inter_graph :\n"); + printf("----------------- \n"); + show_graph(); + } + + complete_graph(net_num); + if (DEBUG) { + printf("\nAfter complete_graph :\n"); + printf("-------------------- \n"); + show_graph(); + } else { + if (VERBOSE) { + printf("\nGraph of the constraints:\n"); + show_graph(); + } + } + + sons_graph(); + if (DEBUG) { + printf("\nAfter sons_graph :\n"); + printf("---------------- \n"); + show_sons(); + } + + fathers_graph(); + if (DEBUG) { + printf("\nAfter fathers_graph :\n"); + printf("------------------- \n"); + show_fathers(); + } + + + +} + + + +/****************************************************************************** +* * +* Builds the graph of the constraints as given by the problem * +* * +******************************************************************************/ + +base_graph(net) +CONSTRAINT **net; + +{ + + int i,level; + CONSTRAINT *constrptr; + CONSTRAINT_E *newconstr,*newconstraint_e(); + + /* clears pointers of graph_levels array */ + for (i = 0; i <= graph_depth-1; i++) { + graph_levels[i] = ( CONSTRAINT_E *) 0; + } + + /* empty net : do nothing */ + if ((*net) == (CONSTRAINT *) 0) return; + + /* "constrptr" scans the list of the constraints found by "analysis" */ + if (I_EXACT) { + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + /* insert the constraints at the various levels of graph_levels */ + level = mylog2(minpow2(constrptr->card)); + newconstr = newconstraint_e(constrptr->relation,constrptr->card); + + newconstr->next = graph_levels[level]; + graph_levels[level] = newconstr; + } + } + if (I_HYBRID || IO_HYBRID || IO_VARIANT) { + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if (constrptr->attribute == USED) { + /* insert the constraints at the various levels of graph_levels */ + level = mylog2(minpow2(constrptr->card)); + newconstr = newconstraint_e(constrptr->relation,constrptr->card); + + newconstr->next = graph_levels[level]; + graph_levels[level] = newconstr; + } + } + } + + + +} + + + + +/******************************************************************************* +* Finds the intersections between the constraints already present in * +* base_graph * +*******************************************************************************/ + + +inter_graph(net_num) +int net_num; + +{ + CONSTRAINT_E *constrptr1,*constrptr2,*temptr,*new,*newconstraint_e(); + char *newrelation; + int i,k,j,card,inter_level; + int countnewconstr; + + countnewconstr = 0; + + if ((newrelation = (char *) calloc((unsigned)net_num+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for newrelation in inter_graph\n"); + exit(-1); + } + newrelation[net_num] = '\0'; + + for (i = graph_depth-2; i >= 0; i--) { + /* "constrptr1" points to the first operand of the intersection + operation */ + for (constrptr1 = graph_levels[i]; constrptr1 != (CONSTRAINT_E *) 0; + constrptr1 = constrptr1->next ) { + + for (k = i; k >= 0; k--) { + /* "constrptr2" points to the second operand of the intersection + operation */ + for (constrptr2 = graph_levels[k]; constrptr2 != (CONSTRAINT_E *) 0; + constrptr2 = constrptr2->next) { + + /* compute a new constraint as the intersection of two other + ones */ + card = 0; + for (j=0; constrptr1->relation[j] != '\0'; j++) { + if (constrptr1->relation[j] == ONE && + constrptr2->relation[j] == ONE ) { + card++; + newrelation[j] = ONE; + } else { + newrelation[j] = ZERO; + } + } + + /* discard empty or single intersections */ + if ( card <= 1 ) { + continue; + } + + /* take care of intersections coinciding with already present + elements */ + inter_level = mylog2(minpow2(card)); + for (temptr = graph_levels[inter_level]; + temptr != (CONSTRAINT_E *) 0; temptr = temptr->next ) { + if (strcmp(newrelation,temptr->relation) == 0) { + break; + } + } + + /* constraint not already found */ + if (temptr == (CONSTRAINT_E *) 0) { + new = newconstraint_e(newrelation,card); + new->next = graph_levels[inter_level]; + graph_levels[inter_level] = new; + countnewconstr++; + } + + if ( countnewconstr > 1000 ) { + fprintf(stderr,"\n WARNING\n"); + fprintf(stderr,"** After that lattice added the 1001-th new constraint ,\n"); + fprintf(stderr,"Nova stopped executing lattice and went ahead with the\n"); + fprintf(stderr,"constraints that lattice already got ****************\n\n"); + return; + } + } + } + } + } +} + + + +/******************************************************************************* +* Adds to the graph of the constraints the following trivial ones : * +* 1) the constraint including all symbols * +* 2) the constraints including only one symbol at a time * +*******************************************************************************/ + + +complete_graph(net_num) +int net_num; + +{ + CONSTRAINT_E *new,*newconstraint_e(); + char *newrelation; + int i,j,level; + + if ((newrelation = (char *) calloc((unsigned)net_num+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for newrelation in inter_graph\n"); + exit(-1); + } + newrelation[net_num] = '\0'; + + + + /* Adds to the graph of the constraints the following trivial one : + the constraint including all symbols */ + + for (j=0; j < net_num; j++) { + newrelation[j] = ONE; + } + + new = newconstraint_e(newrelation,net_num); + new->next = graph_levels[graph_depth-1]; + graph_levels[graph_depth-1] = new; + + /* Adds to the graph of the constraints the following trivial ones : + the constraints including only one symbol at a time */ + level = 0; + + for (i=0; i < net_num; i++) { + for (j=0; j < net_num; j++) { + newrelation[j] = ZERO; + } + newrelation[i] = ONE; + + new = newconstraint_e(newrelation,1); + new->next = graph_levels[level]; + graph_levels[level] = new; + } + +} + + + +/***************************************************************************** +* Links the constraints to all their sons * +*****************************************************************************/ + +sons_graph() + +{ + + CONSTRAINT_E *ftconstr,*sonconstr,*temptr2; + SONS_LINK *sons_link,*temptr1; + int i,j; + + for (i = graph_depth-1; i > 0; i--) { + for (ftconstr = graph_levels[i]; ftconstr != (CONSTRAINT_E *) 0; + ftconstr = ftconstr->next ) { + for (j = i; j >= 0; j--) { + for (sonconstr = graph_levels[j]; sonconstr != (CONSTRAINT_E *) 0; + sonconstr = sonconstr->next ) { + + /* if the constraint pointed to by sonconstr is contained + properly in the father it is a potential son */ + if (p_incl_s(ftconstr->relation,sonconstr->relation) == 1 && + strcmp(ftconstr->relation,sonconstr->relation) != 0 ) { + + /* if the current potential son is included properly in + another son already in the list , don't add it */ + for (temptr1 = ftconstr->down_ptr; temptr1 != ( SONS_LINK *) 0; + temptr1 = temptr1->next ) { + + if ( p_incl_s(temptr1->constraint_e->relation,sonconstr->relation) == 1 && + strcmp(temptr1->constraint_e->relation,sonconstr->relation) != 0 ) { + break; + } + } + + /* if the current potential son is included properly in + another constraint at the same level, which in its + turn is included properly in the father, don't add + it */ + for (temptr2 = graph_levels[j]; temptr2 != (CONSTRAINT_E *) 0; + temptr2 = temptr2->next ) { + if ( p_incl_s(temptr2->relation,sonconstr->relation) == 1 && + strcmp(temptr2->relation,sonconstr->relation) != 0 && + p_incl_s(ftconstr->relation,temptr2->relation) == 1 && + strcmp(ftconstr->relation,temptr2->relation) != 0 ) { + break; + } + } + + if (temptr1 == (SONS_LINK *) 0 && + temptr2 == (CONSTRAINT_E *) 0) { + if ((sons_link = (SONS_LINK *) calloc((unsigned)1,sizeof(SONS_LINK))) == ( SONS_LINK *) 0) { + fprintf(stderr,"Insufficient memory for sons_link in sons_graph"); + exit(-1); + } + sons_link->constraint_e = sonconstr; + sons_link->next = ftconstr->down_ptr; + ftconstr->down_ptr = sons_link; + sons_link->codfather_ptr = (CONSTRAINT_E *) 0; + } + + } + } + } + } + } + +} + + + +/***************************************************************************** +* Links the constraints to all their fathers * +*****************************************************************************/ + +fathers_graph() + +{ + + CONSTRAINT_E *ftconstr,*sonconstr,*temptr2; + FATHERS_LINK *fathers_link,*temptr1; + int i,j; + + for (i = 0; i < graph_depth-1; i++) { + for (sonconstr = graph_levels[i]; sonconstr != (CONSTRAINT_E *) 0; + sonconstr = sonconstr->next ) { + for (j = i; j <= graph_depth-1; j++) { + for (ftconstr = graph_levels[j]; ftconstr != (CONSTRAINT_E *) 0; + ftconstr = ftconstr->next ) { + + /* if the constraint pointed to by ftconstr contains + properly the son it is a potential father */ + if (p_incl_s(ftconstr->relation,sonconstr->relation) == 1 && + strcmp(ftconstr->relation,sonconstr->relation) != 0 ) { + + /* if the current potential father includes properly + another father already in the list , don't add it */ + for (temptr1 = sonconstr->up_ptr; temptr1 != ( FATHERS_LINK *) 0; + temptr1 = temptr1->next ) { + + if (p_incl_s(ftconstr->relation,temptr1->constraint_e->relation) == 1 && + strcmp(ftconstr->relation,temptr1->constraint_e->relation) != 0 ) { + break; + } + } + + /* if the current potential father includes properly + another constraint at the same level, which in its + turn includes properly the son, don't add it */ + for (temptr2 = graph_levels[j]; temptr2 != (CONSTRAINT_E *) 0; + temptr2 = temptr2->next ) { + if ( p_incl_s(ftconstr->relation,temptr2->relation) == 1 && + strcmp(ftconstr->relation,temptr2->relation) != 0 && + p_incl_s(temptr2->relation,sonconstr->relation) == 1 && + strcmp(temptr2->relation,sonconstr->relation) != 0 ) { + break; + } + } + + if (temptr1 == (FATHERS_LINK *) 0 && + temptr2 == (CONSTRAINT_E *) 0 ) { + if ((fathers_link = (FATHERS_LINK *) calloc((unsigned)1,sizeof(FATHERS_LINK))) == ( FATHERS_LINK *) 0) { + fprintf(stderr,"Insufficient memory for fathers_link in fathers_graph"); + exit(-1); + } + fathers_link->constraint_e = ftconstr; + fathers_link->next = sonconstr->up_ptr; + sonconstr->up_ptr = fathers_link; + } + + } + } + } + } + } + +} diff --git a/nova/exact_lbound.c b/nova/exact_lbound.c new file mode 100644 index 0000000..dd50e33 --- /dev/null +++ b/nova/exact_lbound.c @@ -0,0 +1,352 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/exact_lbound.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +/******************************************************************************* +* NECESSARY CONDITIONS ON THE HYPERCUBE DIMENSION * +* (to allow a quick rejection of dimensions unfeasible for a given problem * +* instance). * +* The following necessary conditions that need to be satisfied by a solution * +* have been found so far : * +* 1) first counting criterion - the k-face-poset should have at least as many * +* faces of a given cardinality as the instance poset has constraints of a * +* a given cardinality * +* 2) second counting criterion - a constraint cannot have more fathers than * +* the face of minimum dimension (that can be assigned to it in the current * +* hypercube) has minimal including neighbours in the current hypercube * +* 3) third counting criterion - the current hypercube must have at least as * +* many free positions (#vertices - net_num) as the minimum number of imaginary * +* states to introduce ( plus a corollary on the feasibility of a densest * +* packing ) * +*******************************************************************************/ + +#include "nova.h" + +least_dimcube(net_num) +int net_num; + +{ + + int i,cube_dim,constr_num,fathers_num,violations_num,neighbours_num, + immag_num,prov,work,iter_num,horiz_steps,free_pos,*level_count; + BOOLEAN dim_notfound,packing_cond(); + CONSTRAINT_E *constrptr_e; + FATHERS_LINK *father_scanner; + + typedef struct int_list { + int value; + int workarea; + struct int_list *next; + } INT_LIST; + + INT_LIST *immag_list,*new_int,*int_scanner,*int_ptr,*bound_ptr; + + /* FIST COUNTING CRITERION + the number of faces of dimension i of a cube of dimension cube_dim + must be >= than the number of constraints of level i */ + + if (VERBOSE) printf("\nFirst counting criterion\n"); + + if ( (level_count = (int *) calloc((unsigned)graph_depth,sizeof(int))) == (int *) 0) { + if (VERBOSE) + printf("Insufficient memory for level_count in least_dimcube"); + exit(-1); + } + + /* level_count[i] tells how many constraints of level i there are */ + for (i = 0; i < graph_depth; i++) { + constr_num = 0; + for (constrptr_e = graph_levels[i]; constrptr_e != (CONSTRAINT_E *) 0; + constrptr_e = constrptr_e->next ) { + constr_num++; + } + level_count[i] = constr_num; + /*printf("level_count[i] = %d\n", level_count[i]);*/ + } + + + dim_notfound = TRUE; + cube_dim = 1; + + while (dim_notfound == TRUE) { + i = 0; + while ( (i < graph_depth-1) && + (comb_num(cube_dim,cube_dim-i)*power(2,cube_dim-i) + >= level_count[i]) ) { + /*printf("i = %d\n",i); + printf("faces = %d\n",comb_num(cube_dim,cube_dim-i) * power(2,cube_dim-i)); + printf("constraints = %d\n",level_count[i]);*/ + i++; + } + if (i == graph_depth-1) { + dim_notfound = FALSE; + } else { + cube_dim++; + /*printf("cube_dim = %d\n",cube_dim);*/ + } + } + + /* special check if there is space for the complete constraint : + either the dimension of the cube = height of the constraint poset + or there are no constraints of one level < than the complete one */ + if ( !( (cube_dim == graph_depth-1) || + (level_count[graph_depth-2] == 0) ) ) { + /* increase cube_dim to accomodate the complete constraint */ + cube_dim++; + } + + if (VERBOSE) printf("cube_dim after first nec. cond. = %d\n",cube_dim); + + + + /* SECOND COUNTING CRITERION + a constraint cannot have more fathers than the face of minimum + dimension (that can be assigned to it in the current hypercube) + has minimal including neighbours in the current hypercube */ + + if (VERBOSE) printf("Second counting criterion\n"); + + violations_num = 1; + while (violations_num > 0 ) { + violations_num = 0; + for ( i = 0; i < graph_depth-1; i++) { + for (constrptr_e = graph_levels[i]; + constrptr_e != (CONSTRAINT_E *) 0; + constrptr_e = constrptr_e->next ) { + neighbours_num = cube_dim-mylog2(minpow2(constrptr_e->card)); + /*printf("neighbours_num = %d ", neighbours_num);*/ + fathers_num = 0; + for (father_scanner = constrptr_e->up_ptr; + father_scanner != (FATHERS_LINK *) 0; + father_scanner = father_scanner->next ) { + fathers_num++; + } + /*printf("fathers_num = %d \n", fathers_num);*/ + if ( neighbours_num < fathers_num) { + violations_num++; + break; + } + } + if (violations_num > 0) { + cube_dim++; + break; + } + } + } + if (VERBOSE) printf("cube_dim after second nec. cond. = %d\n",cube_dim); + + + + /* THIRD COUNTING CRITERION + If there are constraints whose cardinality is not a power of 2 , + the faces assigned to them will have some frozen vertices , as if + the initial problem have more than net_num states , ie. some + "imaginary" states , too . How many imaginary states should + we introduce to satisfy the constraints ? + There are two facts to take into account : + 1) for a constraint of cardinality "c" we need to introduce + minpow2(c) - c + imaginary states; + 2) at most "cube_dim" constraints can share the same imaginary state. + Using the two given facts we can compute the minimum # of imaginary + states, i.e. the densiest packing of imaginary states . + Since a closed formula for it is ackward, we give a dynamic scheme + to compute it. + The bottomline is : the current hypercube must have enough free + positions (#vertices - net_num) to fit at least the densiest packing. + A corollary ot this criterion is the packing condition that checks + whether introducing imaginary vertices, in a hypercube with no more + free positions, creates completed constraints sharing intersections + whose cardinality is not a power of 2 (an unfeasible situation) */ + + if (VERBOSE) printf("Third counting criterion\n"); + + /* build immag_list, the list of the # of imaginary states introduced + by each constraint whose cardinality is not a power of 2 */ + + immag_list = (INT_LIST *) 0; + + for (i = graph_depth-2; i >= 0; i--) { + for (constrptr_e = graph_levels[i]; constrptr_e != (CONSTRAINT_E *) 0; + constrptr_e = constrptr_e->next ) { + immag_num = minpow2(constrptr_e->card) - constrptr_e->card; + if ( immag_num > 0) { + if ((new_int = (INT_LIST *) calloc((unsigned)1,sizeof(INT_LIST))) == ( INT_LIST *) 0) { + if (VERBOSE) + printf("Insufficient memory for new_int in least_dimcube"); + exit(-1); + } + new_int->value = immag_num; + new_int->next = immag_list; + immag_list = new_int; + } + } + } + + /*printf("immag_list : "); + for (int_scanner = immag_list; int_scanner != (INT_LIST *) 0; + int_scanner = int_scanner->next) { + printf("%d ", int_scanner->value); + } + printf("\n");*/ + + /* immag_list is sorted (in non-decreasing order) - + a simple bubble sort is used */ + + bound_ptr = (INT_LIST *) 0; + work = 1; + while ( work > 0 ) { + work = 0; + for (int_scanner = immag_list; int_scanner != bound_ptr && + int_scanner->next != (INT_LIST *) 0; + int_scanner = int_scanner->next) { + if (int_scanner->value < (int_scanner->next)->value) { + prov = int_scanner->value; + int_scanner->value = (int_scanner->next)->value; + (int_scanner->next)->value = prov; + int_ptr = int_scanner; + work = 1; + } + } + bound_ptr = int_ptr; + } + + /*printf("immag_list : "); + for (int_scanner = immag_list; int_scanner != (INT_LIST *) 0; + int_scanner = int_scanner->next) { + printf("%d ", int_scanner->value); + } + printf("\n");*/ + + /* simulate on immag_list (in the work area) the identification of + imaginary states belonging to different constraints - + at each step, one subtracts 1 to the first "cube_dim" non-zero + elements of immag_list - + the number of steps needed to reduce to zero all elements of + immag_list is the minimum number of imaginary states + to introduce, i.e. the densiest packing - + if the current hypercube doesn't have at least as many free + positions (#vertices - net_num) as the minimum number of imaginary + states to introduce, "cube_dim" is incremented and the necessary + condition is verified again, until for a suitable "cube_dim" it holds */ + + while (1) { + + for (int_scanner = immag_list; int_scanner != (INT_LIST *) 0; + int_scanner = int_scanner->next) { + int_scanner->workarea = int_scanner->value; + } + + iter_num = 0; + work = 1; + while (work > 0) { + work = 0; + horiz_steps = cube_dim; + int_scanner = immag_list; + while (horiz_steps > 0 && int_scanner != (INT_LIST *) 0) { + if (int_scanner->workarea > 0) { + (int_scanner->workarea)--; + work = 1; + horiz_steps--; + } + int_scanner = int_scanner->next; + } + if (work > 0) iter_num++; + + /*printf("immag_list : "); + for (int_scanner = immag_list; int_scanner != (INT_LIST *) 0; + int_scanner = int_scanner->next) { + printf("%d ", int_scanner->workarea); + } + printf("\n");*/ + + } + /*printf("iter_num = %d\n", iter_num);*/ + free_pos = power(2,cube_dim) - net_num; + if (free_pos >= iter_num) { /* 3rd count. criterion satisfied */ + + /* the packing condition checks whether introducing imaginary + vertices, in a hypercube with no more free positions, creates + completed constraints sharing intersections whose cardinality + is not a power of 2 (an unfeasible situation) */ + if (free_pos == iter_num) { /* check packing condition */ + + if (packing_cond(iter_num,net_num)) { /* packing cond. sat. */ + break; + + } else { /* packing condition violated */ + cube_dim++; + } + + } else { /* free_pos > iter_num - no other check is made */ + break; + } + + } else { /* free_pos < iter_num - 3rd count. crit. violated */ + cube_dim++; + } + } + + if (VERBOSE) printf("cube_dim after third nec. cond. = %d\n",cube_dim); + + + return(cube_dim); + +} + + + +BOOLEAN packing_cond(iter_num,net_num) +int iter_num; +int net_num; + +{ + + int i,card_inter,diff,new_card,card_c1c2(); + CONSTRAINT_E *constrptr_e,*constrptr1_e,*constrptr2_e; + + /* check all couples of constraints whose cardinality is a not a power + of 2 - + if the constraints of one of them have the same cardinality and + (cardinality of their intersection + the difference to the + next power of 2) is not a power of 2 and + all imaginary vertices are used for these constraints (i.e. + "iter_num" is equal to "diff") + return FALSE + otherwise return TRUE */ + for (i = graph_depth-2; i >= 0; i--) { + for (constrptr_e = graph_levels[i]; constrptr_e != (CONSTRAINT_E *) 0; + constrptr_e = constrptr_e->next ) { + if (minpow2(constrptr_e->card) - constrptr_e->card != 0) { + constrptr1_e = constrptr_e; + /*printf("constrptr1_e = %s\n", constrptr1_e->relation);*/ + for (constrptr2_e = constrptr1_e->next; + constrptr2_e != (CONSTRAINT_E *) 0; + constrptr2_e = constrptr2_e->next ) { + diff = minpow2(constrptr2_e->card) - constrptr2_e->card; + if ( diff != 0 && + constrptr1_e->card == constrptr2_e->card && + iter_num == diff ) { + /*printf("constrptr2_e = %s\n", constrptr2_e->relation);*/ + card_inter = + card_c1c2(constrptr1_e->relation,constrptr2_e->relation,net_num); + /*printf("card_inter = %d\n", card_inter);*/ + new_card = card_inter + diff; + /*printf("card_inter + diff = %d\n", new_card);*/ + if ( minpow2(new_card) - new_card != 0 ) { + return(FALSE); + } + } + } + } + } + } + + return(TRUE); + +} diff --git a/nova/exact_mini.c b/nova/exact_mini.c new file mode 100644 index 0000000..f34b0f4 --- /dev/null +++ b/nova/exact_mini.c @@ -0,0 +1,180 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/exact_mini.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +/******************************************************************************* +* Invokes the minimizer to get the final boolean representation * +* This version uses the espresso-II version#2.0 binary-valued minimizer * +*******************************************************************************/ + +#include "nova.h" + +exact_mini() + +{ + + FILE *fopen(),*fp3,*fp1; + char line[MAXLINE],*fgets(); + char string1[MAXSTRING]; + char string2[MAXSTRING]; + char string3[MAXSTRING]; + char string4[MAXSTRING]; + char string5[MAXSTRING]; + char command[MAXSTRING]; + int i,j,cursor,linelength; + int code_index,notany_index; + + if ( (fp3 = fopen(temp3,"w")) == NULL ) { + fprintf(stderr,"fopen in exact_mini: can't create temp3\n"); + exit(-1); + } + + if ( (fp1 = fopen(temp1,"r")) == NULL ) { + fprintf(stderr,"fopen in exact_mini: can't read temp1\n"); + exit(-1); + } + + st_codelength = strlen(states[0].exact_code); + + if (TYPEFR && !ONEHOT) fputs(".type fr\n", fp3); + if (TYPEFR && ONEHOT) fputs(".type f\n", fp3); /* no exdc with 1-h enc. */ + if (ISYMB) { + inp_codelength = strlen(inputs[0].exact_code); + sprintf(string1,".i %d\n", inp_codelength + st_codelength); + } else { + sprintf(string1,".i %d\n", inputfield + st_codelength); + } + fputs(string1,fp3); + /*printf("string1 = %s\n", string1);*/ + + sprintf(string1,".o %d\n", st_codelength + outputfield -1); + fputs(string1,fp3); + /*printf("string1 = %s\n", string1);*/ + + while ( fgets(line,MAXLINE,fp1) != (char *) 0) { + + linelength = strlen(line); + + /* skip blank lines , comment lines and command lines */ + if ( (linelength == 1) || (myindex(line,"#") >= 0) || + (myindex(line,".") >= 0) ) { + ; + } else { + + /* takes care of proper inputs */ + if (ISYMB) { + + for (i = 0; i < inputnum; i++) { + string2[i] = line[i]; + } + + string2[inputnum] = '\0'; + /*printf("string2 = %s\n", string2);*/ + code_index = myindex(string2,"1"); + /*printf("index = %d\n", code_index);*/ + + if ( code_index != -1 ) { + strcpy(string2,inputs[code_index].exact_code); + } else { + for (j = 0; j < inp_codelength; j++) { + string2[j] = '-'; + } + string2[inp_codelength] = '\0'; + } + + /*printf("string2 = %s\n", string2);*/ + cursor = inputnum + 3; + + } else { + + for (i = 0; i < inputfield; i++) { + string2[i] = line[i]; + } + string2[inputfield] = '\0'; + /*printf("string2 = %s\n", string2);*/ + cursor = inputfield + 3; + + } + + /* takes care of present states */ + for (i = cursor; i < cursor + statenum; i++) { + string3[i-cursor] = line[i]; + } + string3[statenum] = '\0'; + /*printf("string3 = %s\n", string3);*/ + notany_index = myindex(string3,"0"); + /*printf("notany_index = %d\n", notany_index);*/ + if ( notany_index != -1 ) { + code_index = myindex(string3,"1"); + /*printf("code_index = %d\n", code_index);*/ + strcpy(string3,states[code_index].exact_code); + } else { + for (j = 0; j < st_codelength; j++) { + string3[j] = '-'; + } + string3[st_codelength] = '\0'; + } + /*printf("string3 = %s\n", string3);*/ + cursor = i + 3; + + /* takes care of next states */ + for (i = cursor; i < cursor + statenum; i++) { + string4[i-cursor] = line[i]; + } + string4[statenum] = '\0'; + /*printf("string4 = %s\n", string4);*/ + notany_index = myindex(string4,"0"); + /*printf("notany_index = %d\n", notany_index);*/ + if ( notany_index != -1 ) { + code_index = myindex(string4,"1"); + /*printf("code_index = %d\n", code_index);*/ + strcpy(string4,states[code_index].exact_code); + } else { + for (j = 0; j < st_codelength; j++) { + string4[j] = '-'; + } + string4[st_codelength] = '\0'; + } + /*printf("string4 = %s\n", string4);*/ + cursor = i + 1; + + /* takes care of proper outputs */ + for (i = cursor; i < cursor + outputfield; i++) { + string5[i-cursor] = line[i]; + } + string5[outputfield] = '\0'; + /*printf("string5 = %s\n", string5);*/ + + sprintf(string1,"%s %s %s %s\n", string2, string3, string4, + string5); + fputs(string1,fp3); + + } + + } + + fclose(fp1); + + fclose(fp3); + + + if (!ONEHOT) { /* hack to skip minimization with 1-hot encoding */ + if (VERBOSE) printf("\nRunning Espresso from exact_mini\n"); + /*sprintf(command,"espresso -fr %s > %s", temp3, temp4);changed*/ + sprintf(command,"espresso %s > %s", temp3, temp4); + system(command); + if (VERBOSE) printf("Espresso terminated\n"); + } else { + sprintf(command,"cp %s %s", temp3, temp4); + system(command); + sprintf(command,"cp %s %s", temp3, temp5); + system(command); + } + + +} diff --git a/nova/exact_output.c b/nova/exact_output.c new file mode 100644 index 0000000..ee218f3 --- /dev/null +++ b/nova/exact_output.c @@ -0,0 +1,333 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/exact_output.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +#include "nova.h" + +/****************************************************************************** +* Last small business before leaving NOVA * +******************************************************************************/ + + +exact_output() + +{ + ex_summary(); + + if (VERBOSE) printf("\nTHE END of NOVA\n"); +} + + + + +/************************************************************************** +* Prints the most interesting results * +**************************************************************************/ + +ex_summary() + +{ + if (VERBOSE) printf("\n\n\n SUMMARY\n\n"); + fprintf(stdout,"# Prod.-terms of minimized MV cover = %d\n", onehot_products); + if (IO_HYBRID || IO_VARIANT) fprintf(stdout,"# Prod.-terms of symbolic cover = %d\n", symbmin_card()); + /*printf("worst_products = %d\n", worst_products);*/ + fprintf(stdout,"# Prod.-terms of encoded cover = %d\n", best_products); + fprintf(stdout,"# Pla area = %d\n", best_size); + printf("#\n# .start_codes\n"); + if (ISYMB) show_exbestcode(inputs,inputnum); + show_exbestcode(states,statenum); + printf("# .end_codes\n"); + if (VERBOSE) { + if (I_HYBRID || IO_HYBRID || IO_VARIANT || USER || ONEHOT) { + if (ISYMB) { + printf("\nINPUTS :"); + constr_satisfaction(&inputnet,inputs,inp_codelength,"exact"); + } + printf("\nSTATES :"); + constr_satisfaction(&statenet,states,st_codelength,"exact"); + } + if (IO_HYBRID || IO_VARIANT) { + out_performance("exbest"); + weighted_outperf(statenum,"exbest"); + } + } + +} + + + +/******************************************************************************* +* Verifies if the exact encoding algorithm satisfied all constraints * +* (as it should!) - if it didn't , it stops the execution signalling * +* the event (it means that there is a bug in the program) * +*******************************************************************************/ + +int exact_check(net,symblemes,net_num) +CONSTRAINT **net; +SYMBLEME *symblemes; +int net_num; + +{ + + CONSTRAINT_E *constrptr_e; + CONSTRAINT *constrptr; + char *face; + char bit1; + BOOLEAN check; + int i,j,code_lgt; + + check = TRUE; + + /* copy the codes of the exact algorithm in symblemes[].exact_code */ + i = net_num-1; + for (constrptr_e = graph_levels[0]; constrptr_e != (CONSTRAINT_E *) 0; + constrptr_e = constrptr_e->next ) { + if ( constrptr_e->face_ptr != (FACE *) 0 ) { + strcpy(symblemes[i].exact_code,constrptr_e->face_ptr->cur_value); + i--; + } + } + + /* empty net : do nothing */ + if ((*net) == (CONSTRAINT *) 0) { + return; + } + + code_lgt = strlen(symblemes[0].exact_code); + + if ((face = (char *) calloc((unsigned)code_lgt+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"\nInsufficient memory for 'face' in exact_check\n"); + exit(-1); + } + face[code_lgt] = '\0'; + + /* scans all constraints */ + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + + /*printf("The constraint is %s ", constrptr->relation);*/ + + /* scans all boolean coordinates */ + for (i = 0; i < code_lgt; i++) { + + /* stores in bit1 the "i-th" bit of the best_code of the "j-th" + symbleme ( which belongs to the current constraint ) */ + for ( j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ONE ) { + bit1 = symblemes[j].exact_code[i]; + } + } + + /* if there are two symblemes in the current constraint different + on the i-th boolean coordinate face[i] gets a * (don't care) + otherwise face[i] gets the common coordinate value */ + for ( j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ONE ) { + if ( bit1 != symblemes[j].exact_code[i]) { + face[i] = '*'; + break; + } else { + face[i] = bit1; + } + } + } + + } + + /*printf("the spanned face is %s\n", face);*/ + + /* if the exact_code of any other symbleme ( i.e. a symbleme not + contained in constraint ) is covered by face , the current + constraint has not been satisfied */ + for (j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ZERO ) { + if (inclusion(symblemes[j].exact_code,face,code_lgt) == 1) { + fprintf(stderr,"the symbleme %s (%d) is covered by face\n", symblemes[j].name, j); + fprintf(stderr,"UNSATISFIED\n"); + fprintf(stderr,"\nFATAL ERROR in the verification of the exact encoding\n"); + check = FALSE; + exit(-1); + break; + } + } + } + + /* no other constraint covered by face */ + if (j == net_num) { + /*printf("SATISFIED\n");*/ + } + + } + + if (VERBOSE && check == TRUE) { + printf("\nThe exact encoding algorithm satisfied all constraints\n"); + } + +} + + + +/************************************************************************ +* Tries the best complementation and then minimizes * +* * +************************************************************************/ + + +exact_rotation() + +{ + + int i,current_size; + + if (VERBOSE) printf("\n\nSTARTS THE COMPLEMENTATION PART\n"); + + worst_products = 0; + first_size = best_size = 0; + + if (COMPLEMENT) { + + /* complements the codes of the states and then minimizes */ + for (i = 0; i < statenum; i++) { + + if (VERBOSE)printf("\nThe null code is assigned to the state %s\n", + states[i].name); + excompl_states(i); + + exact_mini(); + + current_size = size(); + + if (min_products > worst_products) { + worst_products = min_products; + } + + /* local optimality */ + if ( first_size == 0 || first_size > current_size ) { + first_size = current_size; + } + + /* global optimality */ + if ( best_size == 0 || best_size > first_size ) { + best_products = min_products; + best_size = first_size; + save_excover(); + } + + if (VERBOSE) { + printf("\nbest_products = %d", best_products); + printf("\nbest_size = %d\n", best_size); + /*printf("\nbest codes for the states found so far"); + show_exbestcode(states,statenum);*/ + + /* analyzes the correlation between the output + covering relations and rotations */ + if (IO_HYBRID || IO_VARIANT) out_performance("exact"); + } + + } + + } else { + + excompl_states(zerostate()); + + exact_mini(); + + current_size = size(); + + /* global optimality */ + if ( best_size == 0 || best_size > current_size ) { + best_products = min_products; + best_size = current_size; + save_excover(); + } + + if (VERBOSE) printf("best_size = %d\n", best_size); + /*printf("\nbest codes for the states found so far"); + show_exbestcode(states,statenum);*/ + + } + + if (VERBOSE) printf("\nENDS THE COMPLEMENTATION PART\n"); + +} + + + + +/****************************************************************************** +* Saves the best code found so far in the bestcode field of the symblemes * +******************************************************************************/ + +save_excover() + +{ + + char command[MAXSTRING]; + int i; + + /* saves the input codes */ + if (ISYMB) { + for ( i = 0; i < inputnum; i++ ) { + strcpy(inputs[i].exbest_code,inputs[i].exact_code); +} + } + + /* saves the state codes */ + for ( i = 0; i < statenum; i++ ) { + strcpy(states[i].exbest_code,states[i].exact_code); + } + + /* saves the unminimized cover in temp33 - to fix a bug, july 1994 */ + sprintf(command,"cp %s %s", temp3, temp33); + system(command); + + /* saves the minimized cover in temp5 */ + sprintf(command,"cp %s %s", temp4, temp5); + system(command); + +} + + + +/****************************************************************************** +* Complements the codes of the states * +******************************************************************************/ + +excompl_states(null_code) +int null_code; + +{ + + int state,bit; + + if ( null_code == -1 ) { + if (VERBOSE) printf("\nUnspecified argument to excompl_states\n"); + return; + } + + + /*printf("Codes of the states before the complementation"); + show_exactcode(states,statenum);*/ + + for ( bit = 0; bit < strlen(states[0].exact_code); bit++ ) { + if ( states[null_code].exact_code[bit] == ONE) { + /* complements this bit */ + for ( state = 0; state < statenum; state++ ) { + if ( states[state].exact_code[bit] == ONE ) { + states[state].exact_code[bit] = ZERO; + } else { + states[state].exact_code[bit] = ONE; + } + } + } + } + + /*printf("\nCodes of the states after the complementation"); + show_exactcode(states,statenum);*/ + +} diff --git a/nova/get_constr.c b/nova/get_constr.c new file mode 100644 index 0000000..865a089 --- /dev/null +++ b/nova/get_constr.c @@ -0,0 +1,315 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/get_constr.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +/******************************************************************************* +* Invokes the minimizer to get the input constraints * +* This version uses the espresso-II version#2.0 multiple-valued minimizer * +*******************************************************************************/ + +#include "nova.h" + +mini() + +{ + + FILE *fopen(),*fp; + INPUTTABLE *new; + char string1[MAXSTRING]; + char string2[MAXSTRING]; + char string3[MAXSTRING]; + char string4[MAXSTRING]; + char command[MAXSTRING]; + int i,pos; + + for (i = 0; i < statenum; i++) zeroutput[i] = 0; + + if ((fp = fopen(temp1,"w")) == NULL) { + fprintf(stderr,"fopen: can't create %s (temp1)\n", temp1); + exit(-1); + } + + /* determine number and sizes of multiple-valued variables and write the command ".mv ...parameters..." */ + if (TYPEFR) fputs(".type fr\n",fp); + if (ISYMB) { + sprintf(string1,".mv %d %d %d %d %d\n", 3, 0 , inputnum , statenum, outputfield+statenum-1); + fputs(string1,fp); + } else { + sprintf(string1,".mv %d %d %d %d\n", inputfield+2, inputfield , statenum, outputfield+statenum-1); + fputs(string1,fp); + } + + /* write the product terms in "temp1" */ + for (new=firstable; new!=(INPUTTABLE *) 0; new=new->next) { + if (ISYMB){ + mvlab(string2,new->ilab,inputnum); + } else { + strcpy(string2, new->input); + } + mvlab(string3,new->plab,statenum); + mvlab(string4,new->nlab,statenum); + sprintf(string1,"%s | %s | %s %s\n", string2, string3 , string4, new->output); + fputs(string1,fp); + + /* if the proper output part is all zeroes updates the array zeroutput + at the "next-state"-th position */ + if (myindex(new->output,"1") < 0) { + pos = myindex(string4,"1"); + if (pos >= 0) { + (zeroutput[pos])++; + } + } + + } + + if (VERBOSE) { + printf("\nzeroutput = "); + for (i = 0; i < statenum; i++) printf("%d", zeroutput[i]); + printf("\n"); + } + + fclose(fp); + + + if (!ONEHOT) { /* hack to skip minimization with 1-hot encoding */ + if (VERBOSE) printf("\nRunning Espresso\n"); + sprintf(command,"espresso %s > %s", temp1, temp2); + system(command); + if (VERBOSE) printf("Espresso terminated\n"); + + + /* analyses the minimized file */ + analysis(temp2); + onehot_card(); + } else { + sprintf(command,"cp %s %s", temp1, temp2); + system(command); + } + +} + + + + +/* converts a symbleme into a multiple-valued part of 0's and 1's */ +mvlab(string,label,size) +char string[MAXSTRING]; +int label; +int size; + +{ + + int k; + + for (k=0; k= 0) || + (myindex(line,".") >= 0) ) { + } + + else { + if (ISYMB) { + for (i=1; i<=inputnum; i++) { + binput[i-1] = line[i]; + } + binput[inputnum] = '\0'; + cursor = inputnum+2; + + for (i=cursor; i 1 && cont < inputnum) { + for (scanner = inputnet; scanner != (CONSTRAINT *) 0; + scanner = scanner->next) { + if (strcmp(binput,scanner->relation) == 0 ) break; + } + if (scanner == (CONSTRAINT *) 0) { + new = newconstraint(binput,cont,0); + new->next = inputnet; + inputnet = new; + } else { + scanner->weight++; + } + } + } + + /* deduce the constraints on the states */ + cont = 0; + for (i=0; i 1 && cont < statenum) { + for (scanner = statenet; scanner != (CONSTRAINT *) 0; + scanner = scanner->next) { + if (strcmp(bprstate,scanner->relation) == 0 ) { + for (i=0; inext_states[i] = ONE; + } + break; + } + } + if (scanner == (CONSTRAINT *) 0) { + new = newconstraint(bprstate,cont,0); + new->next = statenet; + statenet = new; + strcpy(new->next_states,bnxstate); + } else { + scanner->weight++; + } + } + + + } + + } + + /*if (ISYMB){ + shownet(&inputnet,"Inputnet","after analysis"); + } + + shownet(&statenet,"Statenet","after analysis");*/ + + fclose(fp); + } + + +} + + + +onehot_card() + +{ + + FILE *fopen(), *fpin; + char line[MAXLINE], string[MAXLINE]; + + if ((fpin = fopen(temp2, "r")) == NULL) { + fprintf(stderr,"fopen: can't read file temp2\n"); + exit(-1); + } + while (fgets(line, MAXLINE, fpin) != NULL) { + if (myindex(line,".p") >= 0) { + sscanf(line, "%s %d", string, &onehot_products); + break; + } + } + fclose(fpin); + +} diff --git a/nova/ihybrid_code.c b/nova/ihybrid_code.c new file mode 100644 index 0000000..2fda892 --- /dev/null +++ b/nova/ihybrid_code.c @@ -0,0 +1,953 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/ihybrid_code.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +/****************************************************************************** +* Approximate encoding algorithm * +* * +******************************************************************************/ + +#include "nova.h" + +ihybrid_code(net,symblemes,net_name,net_num,code_length) +CONSTRAINT **net; +SYMBLEME *symblemes; +char *net_name; +int net_num; +int code_length; + +{ + + int dim_cube,iter_num,i,approx_work; + BOOLEAN code_found,found_coding,backtrack_down(); + CONSTRAINT *update_net(),*last_constr; + + code_found = FALSE; + found_coding = FALSE; + + dim_cube = mylog2(minpow2(net_num)); + approx_work = 0; + + iter_num = num_constr(net); + + for (i = 0; i < iter_num; i++) { + last_constr = update_net(net); + /*printf("last_constr->relation = %s\n", last_constr->relation);*/ + exact_graph(net,net_num); + faces_alloc(net_num); + + /* decides the categories and bounds of the faces (func. of dim_cube) */ + faces_set(dim_cube); + + /* finds an encoding (if any) for the current configuration */ + code_found = backtrack_down(net_num,dim_cube); + + approx_work += cube_work; + + if (code_found == FALSE) { + last_constr->attribute = PRUNED; + if (VERBOSE) printf("\nNo code was found\n"); + } else { + found_coding = TRUE; + faces_to_codes(symblemes,net_num); + if (VERBOSE) printf("\nA code was found\n"); + } + } + if (VERBOSE) { + printf("\nApprox_work = %d\n", approx_work); + constr_satisfaction(net,symblemes,dim_cube,"exact"); + } + if (found_coding == FALSE) random_patch(symblemes,net_num); + + /* add a new dimension to the current cube to satisfy more constraints */ + if (code_length > dim_cube) { + project_code(net,symblemes,net_name,net_num,code_length); + } + + if (strcmp(net_name,"Inputnet") != 0) { + exact_rotation(); + exact_output(); + } + +} + + + +project_code(net,symblemes,net_name,net_num,code_length) +CONSTRAINT **net; +SYMBLEME *symblemes; +char *net_name; +int net_num; +int code_length; + +{ + + CONSTRAINT *constrptr,*inspect_net(),*last_constr; + int *mask_constr,*mask_move; + int state_sel(),face_action(),state_pos,action,mindim_cube,i,k; + BOOLEAN feasible_move(); + + if (VERBOSE) printf("\nSTARTS CUBE EXPANSION\n"); + + if ( (mask_constr = (int *) calloc((unsigned)net_num,sizeof(int))) == (int *) 0 ) { + fprintf(stderr,"Insufficient memory for mask_constr in project_code"); + } + if ( (mask_move = (int *) calloc((unsigned)net_num,sizeof(int))) == (int *) 0 ) { + fprintf(stderr,"Insufficient memory for mask_move in project_code"); + } + + mindim_cube = mylog2(minpow2(net_num)); + + for (i = mindim_cube+1; i <= code_length; i++) { + if (VERBOSE) printf("\nCURRENT CUBE DIMENSION = %d\n", i); + + elong_code(symblemes,net_num); + + /* all PRUNED constraints become NOTUSED */ + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if (constrptr->attribute == PRUNED) { + constrptr->attribute = NOTUSED; + } + } + + /* select the NOTUSED constraint of maximum weight with at least + one raisable state - NOTUSED constraints with no raisable state + are PRUNED */ + last_constr = inspect_net(net,symblemes,net_num); + while (last_constr != (CONSTRAINT *) 0) { + + /*printf("last_constr->relation = %s\n", last_constr->relation);*/ + for (k = 0; k < net_num; k++) { + if (last_constr->relation[k] == ONE) mask_constr[k] = 1; + if (last_constr->relation[k] == ZERO) mask_constr[k] = 0; + mask_move[k] = 0; + } + + /* select the raisable state more frequent in NOTUSED constraints */ + state_pos = state_sel(net,symblemes,net_num,mask_constr); + while (state_pos != -1) { + /*printf("state_pos = %d\n", state_pos);*/ + /* assign "state_pos" to the new dimension and record the move */ + mask_constr[state_pos] = 0; + raise_code(symblemes,state_pos); + mask_move[state_pos] = 1; + /* check if the move makes NOTUSED an USED constraint + (by invoking feasible_move() inside face_action() - + compute the face spanned by the states of last_constr + and decide which action to take according to the new codes */ + action = + face_action(net,symblemes,net_num,last_constr,mask_constr,state_pos); + if (action == 1) { /* last_constr USED */ + last_constr->attribute = USED; + /*printf("%s was USED\n", last_constr->relation);*/ + break; + } + if (action == 2) { /* last_constr PRUNED - cancell all moves */ + lower_codes(symblemes,net_num,mask_move); + last_constr->attribute = PRUNED; + break; + } + if (action == 3) { /* cancell the last move */ + lower_code(symblemes,state_pos); + mask_move[state_pos] = 0; + } + if (action == 4) { /* accept the last move */ + } + state_pos = state_sel(net,symblemes,net_num,mask_constr); + } + + /* verify if some UNSATISFIED constraints were USED as a side-effect */ + moreconstr_used(net,symblemes,net_num); + /*shownet(net,net_name,"AFTER CONSTRAINT CYCLE");*/ + last_constr = inspect_net(net,symblemes,net_num); + /*show_exactcode(symblemes,net_num);*/ + + } + if (VERBOSE) { + shownet(net,net_name,"AFTER CUBE EXPANSION"); + show_exactcode(symblemes,net_num); + constr_satisfaction(net,symblemes,i,"exact"); + } + } + +} + + + +elong_code(symblemes,net_num) +SYMBLEME *symblemes; +int net_num; + +{ + + int i,old_length; + + old_length = strlen(symblemes[0].exact_code); + + for (i = 0; i < net_num; i++) { + symblemes[i].exact_code[old_length] = ZERO; + symblemes[i].exact_code[old_length+1] = '\0'; + } + +} + + + +CONSTRAINT *inspect_net(net,symblemes,net_num) +CONSTRAINT **net; +SYMBLEME *symblemes; +int net_num; + +{ + + CONSTRAINT *constrptr,*inspect_constr; + int max_weight,length,eligible,i; + + max_weight = 0; + length = strlen(symblemes[0].exact_code); + inspect_constr = (CONSTRAINT *) 0; + + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if (constrptr->attribute == NOTUSED) { + eligible = 0; + for (i = 0; i < net_num; i++) { + if (constrptr->relation[i] == ONE && + symblemes[i].exact_code[length - 1] == ZERO) { + eligible = 1; + break; + } + } + if (eligible == 0) { + /* NOTE: bug corrected here - test it */ + constrptr->attribute = PRUNED; + } + if (eligible == 1 && constrptr->weight > max_weight) { + max_weight = constrptr->weight; + inspect_constr = constrptr; + } + } + } + + return(inspect_constr); + +} + + + +int state_sel(net,symblemes,net_num,mask) +CONSTRAINT **net; +SYMBLEME *symblemes; +int net_num; +int *mask; + +{ + + CONSTRAINT *constrptr; + int state_pos,i_freq,max_freq,length,i; + + length = strlen(symblemes[0].exact_code); + + max_freq = 0; + state_pos = -1; + + for (i = 0; i < net_num; i++) { + /* state in the first half of the hypercube */ + if (mask[i] == 1 && symblemes[i].exact_code[length-1] == ZERO) { + i_freq = 0; + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if (constrptr->attribute == NOTUSED && + constrptr->relation[i] == ONE) { + i_freq++; + } + } + if (i_freq > max_freq) { + max_freq = i_freq; + state_pos = i; + } + } + } + /*mask[state_pos] = 0;*/ + + return(state_pos); + +} + + + +raise_code(symblemes,state_pos) +SYMBLEME *symblemes; +int state_pos; + +{ + + int length; + + length = strlen(symblemes[0].exact_code); + + symblemes[state_pos].exact_code[length-1] = ONE; + +} + + + +lower_code(symblemes,state_pos) +SYMBLEME *symblemes; +int state_pos; + +{ + + int length; + + length = strlen(symblemes[0].exact_code); + + symblemes[state_pos].exact_code[length-1] = ZERO; + +} + + + +lower_codes(symblemes,net_num,mask_move) +SYMBLEME *symblemes; +int net_num; +int *mask_move; + +{ + + int i,length; + + length = strlen(symblemes[0].exact_code); + + for (i = 0; i < net_num; i++) { + if (mask_move[i] == 1) { + symblemes[i].exact_code[length-1] = ZERO; + } + } + +} + + + +int face_action(net,symblemes,net_num,constrptr,mask,state_pos) +CONSTRAINT **net; +SYMBLEME *symblemes; +int net_num; +CONSTRAINT *constrptr; +int *mask; +int state_pos; + +{ + + char *face; + char bit1; + BOOLEAN last_state; + int i,j,satisfied,face_length,new_cube,length; + + satisfied = 0; + length = strlen(symblemes[0].exact_code); + last_state = TRUE; + if (satisfied == 0) { + for (i = 0; i < net_num; i++) { + if (mask[i] == 1 && symblemes[i].exact_code[length-1] == ZERO) { + last_state = FALSE; + break; + } + } + } + + if (feasible_move(net,symblemes,net_num,state_pos) == FALSE) { + if (last_state == TRUE) { + /*printf("CANCELL ALL MOVES\n");*/ + return(2); + } + if (last_state == FALSE) { + /*printf("CANCELL THE LAST MOVE\n");*/ + return(3); + } + } + + face_length = strlen(symblemes[0].exact_code); + if ((face = (char *) calloc((unsigned)face_length+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for face in face_action"); + } + + /* scans all boolean coordinates */ + for (i = 0; i < face_length; i++) { + + /* stores in bit1 the "i-th" bit of the exact_code of the "j-th" + symbleme ( which belongs to constrptr ) */ + for ( j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ONE ) { + bit1 = symblemes[j].exact_code[i]; + } + } + + /* if there are two symblemes in constrptr different + on the i-th boolean coordinate face[i] gets a * (don't care) + otherwise face[i] gets the common coordinate value */ + for ( j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ONE ) { + if ( bit1 != symblemes[j].exact_code[i]) { + face[i] = '*'; + break; + } else { + face[i] = bit1; + } + } + } + + } + /*printf("the spanned face is %s\n", face);*/ + + /* if the exact_code of any other symbleme ( i.e. a symbleme not + contained in constrptr ) is covered by face , constrptr + has not been satisfied */ + satisfied = 1; + /* new_cube set to 1 if the face assigned to constrptr covers wrongly + a state coded in the new half of the hypercube */ + new_cube = 0; + for (j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ZERO ) { + if (inclusion(symblemes[j].exact_code,face,face_length) == 1) { + /*printf("the symbleme %s (%d) is covered by face %s\n",symblemes[j].name, j, face);*/ + satisfied = 0; + if (symblemes[j].exact_code[face_length-1] == ONE) new_cube = 1; + /*printf("UNSATISFIED\n");*/ + } + } + } + if (satisfied == 1) { + /*printf("SATISFIED\n");*/ + return(1); + } + if (satisfied == 0 && last_state == TRUE) { + /*printf("CANCELL ALL MOVES\n");*/ + return(2); + } + if (satisfied == 0 && last_state == FALSE && new_cube == 1) { + /*printf("CANCELL THE LAST MOVE\n");*/ + return(3); + } + if (satisfied == 0 && last_state == FALSE && new_cube == 0) { + /*printf("ACCEPT THE LAST MOVE\n");*/ + return(4); + } + + return(0); + +} + + + +BOOLEAN feasible_move(net,symblemes,net_num,state) +CONSTRAINT **net; +SYMBLEME *symblemes; +int net_num; +int state; + +{ + + CONSTRAINT *constrptr; + char *face; + char bit1; + int i,j,satisfied,face_length; + + /* empty net : do nothing */ + if ((*net) == (CONSTRAINT *) 0) { + return(FALSE); + } + + face_length = strlen(symblemes[0].exact_code); + if ((face = (char *) calloc((unsigned)face_length+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for face in feasible_move"); + } + + /* scans all constraints */ + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + + if (constrptr->attribute == USED) { + /*printf("The constraint is %s\n", constrptr->relation);*/ + + /* scans all boolean coordinates */ + for (i = 0; i < face_length; i++) { + + /* stores in bit1 the "i-th" bit of the best_code of the "j-th" + symbleme ( which belongs to the current constraint ) */ + for ( j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ONE ) { + bit1 = symblemes[j].exact_code[i]; + } + } + + /* if there are two symblemes in the current constraint different + on the i-th boolean coordinate face[i] gets a * (don't care) + otherwise face[i] gets the common coordinate value */ + for ( j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ONE ) { + if ( bit1 != symblemes[j].exact_code[i]) { + face[i] = '*'; + break; + } else { + face[i] = bit1; + } + } + } + + } + + /*printf("the spanned face is %s\n", face);*/ + + /* if the best_code of any other symbleme ( i.e. a symbleme not + contained in constraint ) is covered by face , the current + constraint has not been satisfied */ + for (j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ZERO ) { + if (inclusion(symblemes[j].exact_code,face,face_length) == 1) { + /*printf("the symbleme %s (%d) is covered by face %s\n",symblemes[j].name, j, face);*/ + satisfied = 0; + /*printf("UNSATISFIED\n");*/ + break; + } + } + } + /* no other constraint covered by face */ + if (j == net_num) { + satisfied = 1; + /*printf("SATISFIED\n");*/ + } + if (satisfied == 0) { + /*printf("%s would be NOTUSED\n", constrptr->relation);*/ + lower_code(symblemes,state); + return(FALSE); + } + } + + } + + return(TRUE); + +} + + + +moreconstr_used(net,symblemes,net_num) +CONSTRAINT **net; +SYMBLEME *symblemes; +int net_num; + +{ + + CONSTRAINT *constrptr; + char *face; + char bit1; + int i,j,satisfied,face_length; + + /* empty net : do nothing */ + if ((*net) == (CONSTRAINT *) 0) { + return; + } + + face_length = strlen(symblemes[0].exact_code); + if ((face = (char *) calloc((unsigned)face_length+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for face in moreconstr_used"); + } + + /* scans all constraints */ + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + + if (constrptr->attribute == NOTUSED || constrptr->attribute == PRUNED) { + /*printf("The constraint is %s\n", constrptr->relation);*/ + + /* scans all boolean coordinates */ + for (i = 0; i < face_length; i++) { + + /* stores in bit1 the "i-th" bit of the best_code of the "j-th" + symbleme ( which belongs to the current constraint ) */ + for ( j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ONE ) { + bit1 = symblemes[j].exact_code[i]; + } + } + + /* if there are two symblemes in the current constraint different + on the i-th boolean coordinate face[i] gets a * (don't care) + otherwise face[i] gets the common coordinate value */ + for ( j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ONE ) { + if ( bit1 != symblemes[j].exact_code[i]) { + face[i] = '*'; + break; + } else { + face[i] = bit1; + } + } + } + + } + + /*printf("the spanned face is %s\n", face);*/ + + /* if the best_code of any other symbleme ( i.e. a symbleme not + contained in constraint ) is covered by face , the current + constraint has not been satisfied */ + for (j = 0; j < net_num; j++) { + if ( constrptr->relation[j] == ZERO ) { + if (inclusion(symblemes[j].exact_code,face,face_length) == 1) { + /*printf("the symbleme %s (%d) is covered by face %s\n",symblemes[j].name, j, face);*/ + satisfied = 0; + /*printf("UNSATISFIED\n");*/ + break; + } + } + } + /* no other constraint covered by face */ + if (j == net_num) { + satisfied = 1; + /*printf("SATISFIED\n");*/ + } + if (satisfied == 1) { + constrptr->attribute = USED; + /*printf("%s was USED as a side-effect\n", constrptr->relation);*/ + } + } + + } + +} + + + +/******************************************************************************* +* Sets the categories & mindim,curdim and maxdim of the faces that can * +* be assigned to the constraints (function of dim_cube) * +*******************************************************************************/ + +faces_set(dim_cube) +int dim_cube; + +{ + + FATHERS_LINK *ft_scanner; + CONSTRAINT_E *constrptr,*supremum_ptr; + int i,fathers_num; + + /* cube_work (global variable) counts the # of codes tried in the current + cube */ + cube_work = 0; + + /* The constraints are classified in categories : + 1) the complete constraint is of category 0; + 2) constraints whose unique father is the complete constraint are + of category 1; + 3) constraints whose unique father is not the complete constraint + are of category 3; + 4) constraints with at least two fathers are of category 2 - + + The dimensions of the faces of the constraints are set on the basis + of the minimum feasible dimension and of current hypercube dimension */ + + /* takes care of the complete constraint */ + supremum_ptr = graph_levels[graph_depth-1]; + supremum_ptr->face_ptr->category = 0; + /*printf("constraint %s is of cat. %d ",supremum_ptr->relation, + supremum_ptr->face_ptr->category);*/ + supremum_ptr->face_ptr->mindim_face = dim_cube; + supremum_ptr->face_ptr->maxdim_face = dim_cube; + supremum_ptr->face_ptr->curdim_face = dim_cube; + /*printf("curdim_face = %d\n", supremum_ptr->face_ptr->curdim_face);*/ + + for (i = graph_depth-2; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + + fathers_num = 0; + for (ft_scanner = constrptr->up_ptr; + ft_scanner != (FATHERS_LINK *) 0; ft_scanner = ft_scanner->next) { + fathers_num++; + } + + /* if the constraint has only one father */ + if (fathers_num == 1) { + /* if the father is the complete constraint */ + if (constrptr->up_ptr->constraint_e == supremum_ptr) { + constrptr->face_ptr->category = 1; + /*printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category);*/ + constrptr->face_ptr->mindim_face = + mylog2(minpow2(constrptr->card)); + /*printf("mindim_face = %d ", + constrptr->face_ptr->mindim_face);*/ + constrptr->face_ptr->curdim_face = + constrptr->face_ptr->mindim_face; + /*printf("curdim_face = %d \n", + constrptr->face_ptr->curdim_face);*/ + constrptr->face_ptr->maxdim_face = + constrptr->face_ptr->mindim_face; + /*printf("maxdim_face = %d \n", + constrptr->face_ptr->maxdim_face);*/ + } else { + constrptr->face_ptr->category = 3; + /*printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category);*/ + constrptr->face_ptr->mindim_face = + mylog2(minpow2(constrptr->card)); + constrptr->face_ptr->curdim_face = + constrptr->face_ptr->mindim_face; + /*printf("mindim_face = %d\n", + constrptr->face_ptr->mindim_face);*/ + } + } + + /* if the constraint has at least two fathers */ + if (fathers_num > 1) { + constrptr->face_ptr->category = 2; + /*printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category);*/ + constrptr->face_ptr->mindim_face = + mylog2(minpow2(constrptr->card)); + constrptr->face_ptr->curdim_face = + constrptr->face_ptr->mindim_face; + /*printf("mindim_face = %d\n", + constrptr->face_ptr->mindim_face);*/ + } + + } + } + +} + + + +int num_constr(net) +CONSTRAINT **net; + +{ + + CONSTRAINT *constrptr; + int i; + + i = 0; + + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + i++; + } + + return(i); + +} + + + +CONSTRAINT *update_net(net) +CONSTRAINT **net; + +{ + + CONSTRAINT *constrptr,*update_constr; + int max_weight; + + max_weight = 0; + + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if (constrptr->attribute == NOTUSED && constrptr->weight > max_weight) { + max_weight = constrptr->weight; + update_constr = constrptr; + } + } + update_constr->attribute = USED; + + return(update_constr); + +} + + + +faces_to_codes(symblemes,net_num) +SYMBLEME *symblemes; +int net_num; + +{ + + CONSTRAINT_E *constrptr_e; + int i; + + /* copy the codes of the exact algorithm in symblemes[].exact_code */ + i = net_num-1; + for (constrptr_e = graph_levels[0]; constrptr_e != (CONSTRAINT_E *) 0; + constrptr_e = constrptr_e->next ) { + if ( constrptr_e->face_ptr != (FACE *) 0 ) { + strcpy(symblemes[i].exact_code,constrptr_e->face_ptr->cur_value); + i--; + } + } + +} + + + +/******************************************************************************* +* Verifies which constraints have been satisfied by the encoding algorithm * +* and which haven't - prints out the related information * +*******************************************************************************/ + +constr_satisfaction(net,symblemes,code_length,label) +CONSTRAINT **net; +SYMBLEME *symblemes; +int code_length; +char *label; + +{ + + CONSTRAINT *constrptr; + char *face; + char bit1; + int i,j,card,satisfied; + int sat_measure,unsat_measure; + + /* empty net : do nothing */ + if ((*net) == (CONSTRAINT *) 0) { + return; + } + + sat_measure = unsat_measure = 0; + + card = strlen((*net)->relation); + + if ((face = (char *) calloc((unsigned)code_length+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for face in constr_satisfaction"); + exit(-1); + } + + /* scans all constraints */ + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + + /* discards meaningless constraints */ + if (constrptr->card == 1) continue; + + /*printf("The constraint is %s\n", constrptr->relation);*/ + + /* scans all boolean coordinates */ + for (i = 0; i < code_length; i++) { + + /* stores in bit1 the "i-th" bit of the best_code of the "j-th" + symbleme ( which belongs to the current constraint ) */ + for ( j = 0; j < card; j++) { + if ( constrptr->relation[j] == ONE ) { + if (strcmp(label,"exact") == 0) + bit1 = symblemes[j].exact_code[i]; + if (strcmp(label,"best") == 0) + bit1 = symblemes[j].best_code[i]; + } + } + + /* if there are two symblemes in the current constraint different + on the i-th boolean coordinate face[i] gets a * (don't care) + otherwise face[i] gets the common coordinate value */ + for ( j = 0; j < card; j++) { + if ( constrptr->relation[j] == ONE ) { + if (strcmp(label,"exact") == 0 ) { + if ( bit1 != symblemes[j].exact_code[i]) { + face[i] = '*'; + break; + } else { + face[i] = bit1; + } + } + if (strcmp(label,"best") == 0 ) { + if ( bit1 != symblemes[j].best_code[i]) { + face[i] = '*'; + break; + } else { + face[i] = bit1; + } + } + } + } + + } + + /*printf("the spanned face is %s\n", face);*/ + + /* if the code of any other symbleme ( i.e. a symbleme not + contained in constraint ) is covered by face , the current + constraint has not been satisfied */ + for (j = 0; j < card; j++) { + if ( constrptr->relation[j] == ZERO ) { + if (strcmp(label,"exact") == 0) { + if (inclusion(symblemes[j].exact_code,face,code_length) == 1) { + /*printf("the symbleme %s (%d) is covered by face %s\n",symblemes[j].name, j, face);*/ + satisfied = 0; + /*printf("UNSATISFIED\n");*/ + break; + } + } + if (strcmp(label,"best") == 0) { + if (inclusion(symblemes[j].best_code,face,code_length) == 1) { + /*printf("the symbleme %s (%d) is covered by face %s\n",symblemes[j].name, j, face);*/ + satisfied = 0; + /*printf("UNSATISFIED\n");*/ + break; + } + } + } + } + /* no other constraint covered by face */ + if (j == card) { + satisfied = 1; + /*printf("SATISFIED\n");*/ + } + if (satisfied == 0) { + unsat_measure = unsat_measure + constrptr->weight; + } + if (satisfied == 1) { + sat_measure = sat_measure + constrptr->weight; + } + + } + + if (VERBOSE) { + printf("\nInput constraints satisfaction = %d ", sat_measure); + printf("\nInput constraints unsatisfaction = %d\n", unsat_measure); + } + +} + + + +random_patch(symblemes,net_num) +SYMBLEME *symblemes; +int net_num; + +{ + + long time(); + int code_bits,i,new_code,increment,range,seed,trandom(); + + if (VERBOSE) printf("\nI generated a random code\n"); + + code_bits = mylog2(net_num); + + seed = (int) time(0); + srand(seed); + + range = minpow2(net_num); + new_code = trandom(range); + increment = trandom(range)*2 + 1; + for (i = 0; i < net_num; i++) { + itob(symblemes[i].exact_code,new_code,code_bits); + new_code = (new_code + increment) % range; + } + +} diff --git a/nova/input_fsm.c b/nova/input_fsm.c new file mode 100644 index 0000000..7c0089d --- /dev/null +++ b/nova/input_fsm.c @@ -0,0 +1,467 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/input_fsm.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2005/03/08 01:07:22 $ + * + */ +#include "nova.h" + +/********************************************************************* +* * +* This routine reads the input data file * +* and creates the data structure of the symbolic table * +* * +*********************************************************************/ + +input_fsm(infile) +int infile; + +{ + + FILE *fp , *fopen(); + char line[MAXLINE], *fgets(); + int linelength; + int sfd; + + productnum = 0; + + if ((infile == 1) && (fp = fopen(file_name, "r")) == NULL) { + fprintf(stderr,"input: can't open %s\n",file_name); + exit(-1); + } else { + if (infile == 0) { + fp = stdin; + strcpy(file_name,"/tmp/SISXXXXXX"); + sfd = mkstemp(file_name); + if(sfd == -1) { + fprintf(stderr, "can't create temp file\n"); + exit(-1); + } + getname(file_name); + } + temp_files(); + printf(".model %s\n", esp); + printf(".start_kiss\n"); + while ( fgets(line,MAXLINE,fp) != (char *) 0 ) { + linelength = strlen(line); + /*printf("Linelength = %d\n", linelength); + printf("Line = %s\n", line);*/ + + /* echoes the input line */ + if (LIST) printf("%s" , line); + + /* replaces all characters after a pound sign with blanks */ + comment(line,linelength); + + /* removes trailing blanks and tabs - + practical reason : shrinks blank lines to length 1 so that + later they are skipped */ + trailblanks(line,linelength); + + /* updates linelength for consistency with "trailblanks" */ + linelength = strlen(line); + + /* skip blank lines and comment lines - + comment lines are introduced by "/*" or "#" */ + if ( (linelength == 1) || (myindex(line, "/*") >= 0) + || (myindex(line, "#" ) >= 0) ) + ; + + /* check for end of file flag */ + else if (myindex(line,".end") >= 0) break ; + + /* check for command line option */ + else if (line[0] == '.') commandline(line); + + /* otherwise assume symbolic implicant */ + else { + productnum++; + productline(line,linelength); + /*printf("product term line memorized internally\n"); + printf("%s", lastable->input); + printf("%s", lastable->pstate); + printf("%s", lastable->nstate); + printf("%s\n", lastable->output);*/ + } + + } + printf(".end_kiss\n#\n"); + + fclose(fp) ; + + } + + + label(); + + if (ISYMB && IBITS_DEF) { + inp_codelength = special_log2(minpow2(inputnum)); + } + if (ISYMB && !IBITS_DEF) { + icheck_usercode(inputnum,inp_codelength); + } + + if (SBITS_DEF) { + st_codelength = special_log2(minpow2(statenum)); + } + if (!SBITS_DEF) { + scheck_usercode(statenum,st_codelength); + } + + array_alloc(); + + name(); + + + +} + + + +/************************************************************************** +* Reads a command line in the input file * +* * +**************************************************************************/ + +commandline(line) +char *line; + +{ + + /*if (LIST) printf("%s" , line);*/ + + if (myindex(line,"list") >= 0) LIST = TRUE; + + if (myindex(line,"type") >=0) { + if (myindex(line,"fr") >=0) TYPEFR = TRUE; + if (myindex(line,"fd") >=0) TYPEFR = FALSE; + } + + if (myindex(line,"option") >=0) { + if (myindex(line,"short") >=0) SHORT = TRUE; + if (myindex(line,"prtall") >=0) PRTALL = TRUE; + if (myindex(line,"fr") >=0) TYPEFR = TRUE; + if (myindex(line,"fd") >=0) TYPEFR = FALSE; + } + + if (myindex(line,"symbolic") >=0) { + if (myindex(line,"input") >=0) ISYMB = TRUE; + if (myindex(line,"output") >=0) OSYMB = TRUE; + } + + if (myindex(line,".r ") >=0) { + sscanf(line, ".r %s", init_state); + INIT_FLAG = TRUE; + } + + if (myindex(line,"ilb") >=0) { + strcpy(input_names,line); + ILB = TRUE; + } + if (myindex(line,"ob") >=0) { + strcpy(output_names,line); + OB = TRUE; + } + +} + + + + + +/**************************************************************************** +* Reads a product term line * +* * +****************************************************************************/ + + +productline(line,linelength) +char *line; +int linelength; + +{ + + int i,j,first; + + char inputstr[MAXSTRING]; + char prstatestr[MAXSTRING]; + char nxstatestr[MAXSTRING]; + char outputstr[MAXSTRING]; + + /*if (LIST) printf("%s" , line);*/ + + /* replaces tabs with blanks */ + tabs(line,linelength); + + /* captures the proper input */ + for (i = 0; i < linelength; i++) { + if (line[i] != ' ') { + break; + } + } + for (first = i; i < linelength; i++) { + if (line[i] == ' ') { + break; + } + } + for (j = 0; j < (i-first); j++) { + inputstr[j] = line[j+first]; + } + inputstr[i-first] = '\0'; + inputfield = i-first; + + /* captures the present state */ + for (; i < linelength; i++) { + if (line[i] != ' ') { + break; + } + } + for (first = i; i < linelength; i++) { + if (line[i] == ' ') { + break; + } + } + for (j = 0; j < (i-first); j++) { + prstatestr[j] = line[j+first]; + } + prstatestr[i-first] = '\0'; + + /* captures the next state */ + for (; i < linelength; i++) { + if (line[i] != ' ') { + break; + } + } + for (first = i; i < linelength; i++) { + if (line[i] == ' ') { + break; + } + } + for (j = 0; j < (i-first); j++) { + nxstatestr[j] = line[j+first]; + } + nxstatestr[i-first] = '\0'; + + /* captures the proper output */ + for (; inext) { + /* if the current present state is a don't care state it gets the + label "-1" - a don't care state may be denoted by a "-" in the + first position of the string or by the string "ANY" */ + if (new->pstate[0] == DASH || myindex(new->pstate,ANYSTATE) >=0 ) { + new->plab = DCLABEL; + } else { + for (old=firstable; old!=new; old=old->next) { + if (strcmp(new->pstate,old->pstate) == 0) { + new->plab = old->plab; + break; + } + } + if (new!=old) continue; + new->plab = statenum++; + } + } + + + /* labels next states */ + for (new=firstable; new!=(INPUTTABLE *) 0; new=new->next) { + /* if the current next state is a don't care state it gets the + label "-1" - a don't care state may be denoted by a "-" in the + first position of the string or by the string "ANY" */ + if (new->nstate[0] == DASH || myindex(new->nstate,ANYSTATE) >=0) { + new->nlab = DCLABEL; + } else { + for (old=firstable; old!=(INPUTTABLE *) 0; old=old->next) { + if (strcmp(new->nstate,old->pstate) == 0) { + new->nlab=old->plab; + break; + } + } + if (old!=(INPUTTABLE *) 0) continue; + for (old=firstable; old!=new; old=old->next) { + if (strcmp(new->nstate,old->nstate) == 0) { + new->nlab=old->nlab; + break; + } + } + if (new!=old) continue; + new->nlab = statenum++; + } + } + + + + /* labels symbolic inputs */ + if (ISYMB) { + for (new=firstable; new!=(INPUTTABLE *) 0; new=new->next) { + /* if the current symbolic input is a don't care it gets the label + "-1" - a don't care symbolic input may be denoted by a "-" in + the first position of the string or by the string "ANY" */ + if (new->input[0] == DASH || myindex(new->input,ANYSTATE) >=0) { + new->ilab = DCLABEL; + } else { + for (old=firstable; old!=new; old=old->next) { + if (strcmp(new->input,old->input) == 0) { + new->ilab=old->ilab; + break; + } + } + if (new!=old) continue; + new->ilab = inputnum++; + } + } + } + + /* note : outputfield is larger than 1 than actual outputfield */ + outputnum = outputfield - 1; + /*printf("\noutputnum = %d\n", outputnum);*/ + + /*for (new=firstable; new!=(INPUTTABLE *) 0; new=new->next) { + printf("new->input= %s , new->ilab= %d\n", new->input , new->ilab); + printf("new->pstate= %s , new->plab= %d\n", new->pstate , new->plab); + printf("new->nstate= %s , new->nlab= %d\n", new->nstate , new->nlab); + printf("new->output= %s , new->olab= %d\n", new->output , new->olab); + } + + + if (ISYMB) printf("inputnum= %d\n", inputnum); + else printf("inputfield= %d\n", inputfield); + printf("inputfield= %d\n", inputfield); + printf("statenum= %d\n", statenum); + printf("outputfield= %d\n", outputfield);*/ + + +} + + + +/******************************************************************************* +* fills in the field "name" of the symblemes * +*******************************************************************************/ + +name() + +{ + + INPUTTABLE *new; + + int i; + + for (new=firstable; new!=(INPUTTABLE *) 0; new=new->next) { + + if (ISYMB && (new->ilab!=DCLABEL)) { + inputs[new->ilab].name = new->input; + } + if (new->plab != DCLABEL) { + states[new->plab].name = new->pstate; + } + if (new->nlab != DCLABEL) { + states[new->nlab].name = new->nstate; + } + } + + + if (VERBOSE) { + printf("\n"); + for (i=0; i codes_num ) { + fprintf(stderr,"Argument of option -s too small\n"); + exit(-1); + } + if ( code_length > symblemes_num ) { + fprintf(stderr,"Argument of option -s too large\n"); + exit(-1); + } + +} + + + +icheck_usercode(symblemes_num,code_length) +int symblemes_num; +int code_length; + +{ + + int codes_num; + + codes_num = power(2,code_length); + + if ( symblemes_num > codes_num ) { + fprintf(stderr,"Argument of option -i too small\n"); + exit(-1); + } + if ( code_length > symblemes_num ) { + fprintf(stderr,"Argument of option -i too large\n"); + exit(-1); + } + +} diff --git a/nova/iohybrid_code.c b/nova/iohybrid_code.c new file mode 100644 index 0000000..2e17296 --- /dev/null +++ b/nova/iohybrid_code.c @@ -0,0 +1,152 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/iohybrid_code.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +/****************************************************************************** +* Approximate encoding algorithm * +* * +******************************************************************************/ + + +#include "nova.h" + +iohybrid_code(net,symblemes,net_name,net_num,code_length) +CONSTRAINT **net; +SYMBLEME *symblemes; +char *net_name; +int net_num; +int code_length; + +{ + + int dim_cube,iter_num,i,approx_work,state; + BOOLEAN code_found,found_coding,backtrack_down(); + CONSTRAINT *update_net(),*last_constr; + + if ( (*net) == (CONSTRAINT *) 0 || OUT_ONLY ) { + if (VERBOSE) + printf("SATISFACTION OF OUTPUT RELATIONS WITH SPECIALIZED ALGORITHM\n"); + out_encoder(code_length); + if (strcmp(net_name,"Inputnet") != 0) { + exact_rotation(); + exact_output(); + } + return; + } + + code_found = FALSE; + found_coding = FALSE; + OUT_VERIFY = FALSE; + + dim_cube = mylog2(minpow2(net_num)); + approx_work = 0; + + iter_num = num_constr(net); + + for (i = 0; i < iter_num; i++) { + last_constr = update_net(net); + /*printf("last_constr->relation = %s\n", last_constr->relation);*/ + exact_graph(net,net_num); + faces_alloc(net_num); + + /* decides the categories and bounds of the faces (func. of dim_cube) */ + faces_set(dim_cube); + + /* finds an encoding (if any) for the current configuration */ + code_found = backtrack_down(net_num,dim_cube); + + approx_work += cube_work; + + if (code_found == FALSE) { + last_constr->attribute = PRUNED; + if (VERBOSE) printf("\nNo code was found\n"); + } else { + found_coding = TRUE; + faces_to_codes(symblemes,net_num); + if (VERBOSE) printf("\nA code was found\n"); + } + } + if (VERBOSE) { + printf("\nApprox_work = %d\n", approx_work); + constr_satisfaction(net,symblemes,dim_cube,"exact"); + } + + /* tries to satisfy the output covering relations */ + if (VERBOSE) printf("\n\nSATISFACTION OF OUTPUT COVERING RELATIONS\n\n"); + OUT_VERIFY = TRUE; + state = maxgain_state(); + while (state != -1) { + select_array[state] = USED; + /*printf("state = %d\n", state); + show_orderarray(net_num);*/ + + exact_graph(net,net_num); + faces_alloc(net_num); + faces_set(dim_cube); + code_found = backtrack_down(net_num,dim_cube); + approx_work += cube_work; + + if (code_found == FALSE) { + select_array[state] = PRUNED; + if (VERBOSE) printf("\nNo code was found\n"); + } else { + found_coding = TRUE; + faces_to_codes(symblemes,net_num); + if (VERBOSE) printf("\nA code was found\n"); + } + + state = maxgain_state(); + } + if (VERBOSE) { + printf("\nApprox_work = %d\n", approx_work); + out_performance("exact"); + weighted_outperf(net_num,"exact"); + } + + if (found_coding == FALSE) random_patch(symblemes,net_num); + + /* add a new dimension to the current cube to satisfy more constraints */ + if (code_length > dim_cube) { + project_code(net,symblemes,net_name,net_num,code_length); + } + + if (strcmp(net_name,"Inputnet") != 0) { + exact_rotation(); + exact_output(); + } + +} + + + +int maxgain_state() + +{ + + int i,min_gain,max_gain,state; + + state = -1; + + min_gain = 0; + for (i = 0; i < statenum; i++) { + if (gain_array[i] < min_gain) { + min_gain = gain_array[i]; + } + } + max_gain = min_gain - 1; + + for (i = 0; i < statenum; i++) { + if (select_array[i] == NOTUSED && gain_array[i] > max_gain) { + max_gain = gain_array[i]; + state = i; + } + } + + return(state); + +} diff --git a/nova/iovariant_code.c b/nova/iovariant_code.c new file mode 100644 index 0000000..21a5b96 --- /dev/null +++ b/nova/iovariant_code.c @@ -0,0 +1,263 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/iovariant_code.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +/****************************************************************************** +* Approximate encoding algorithm * +* * +******************************************************************************/ + + +#include "nova.h" + +iovariant_code(net,symblemes,net_name,net_num,code_length) +CONSTRAINT **net; +SYMBLEME *symblemes; +char *net_name; +int net_num; +int code_length; + +{ + + int dim_cube,iter_num,i,approx_work,state; + BOOLEAN code_found,found_coding,backtrack_down(); + CONSTRAINT *update_net(),*last_constr; + + if ( (*net) == (CONSTRAINT *) 0 ) { + if (VERBOSE) + printf("SATISFACTION OF OUTPUT RELATIONS WITH SPECIALIZED ALGORITHM\n"); + out_encoder(code_length); + if (strcmp(net_name,"Inputnet") != 0) { + exact_rotation(); + exact_output(); + } + return; + } + + code_found = FALSE; + found_coding = FALSE; + OUT_VERIFY = FALSE; + + dim_cube = mylog2(minpow2(net_num)); + approx_work = 0; + + /* set to PRUNED all face constraints associated to next states */ + cut_nxstconstr(net,net_num); + /* count the face constraints associated only to outputs */ + iter_num = num_outconstr(net); + + for (i = 0; i < iter_num; i++) { + last_constr = update_net(net); + /*printf("last_constr->relation = %s\n", last_constr->relation);*/ + exact_graph(net,net_num); + faces_alloc(net_num); + + /* decides the categories and bounds of the faces (func. of dim_cube) */ + faces_set(dim_cube); + + /* finds an encoding (if any) for the current configuration */ + code_found = backtrack_down(net_num,dim_cube); + + approx_work += cube_work; + + if (code_found == FALSE) { + last_constr->attribute = PRUNED; + if (VERBOSE) printf("\nNo code was found\n"); + } else { + found_coding = TRUE; + faces_to_codes(symblemes,net_num); + if (VERBOSE) printf("\nA code was found\n"); + } + } + if (VERBOSE) printf("\nApprox_work = %d\n", approx_work); + + /* set to NOTUSED all face constraints associated to next states */ + restore_nxstconstr(net,net_num); + + /* tries to satisfy the output covering relations */ + if (VERBOSE) printf("\n\nSATISFACTION OF OUTPUT COVERING RELATIONS\n\n"); + OUT_VERIFY = TRUE; + state = maxgain_state(); + while (state != -1) { + select_array[state] = USED; + /*printf("state = %d\n", state); + show_orderarray(net_num);*/ + + /* set to TRIED all UNUSED face constraints associated to state */ + tried_nxstconstr(net,state); + + exact_graph(net,net_num); + faces_alloc(net_num); + faces_set(dim_cube); + code_found = backtrack_down(net_num,dim_cube); + approx_work += cube_work; + + if (code_found == FALSE) { + select_array[state] = PRUNED; + + /* set to NOTUSED all TRIED face constraints associated to state */ + notused_nxstconstr(net,state); + + if (VERBOSE) printf("\nNo code was found\n"); + } else { + found_coding = TRUE; + + /* set to USED all TRIED face constraints associated to state */ + used_nxstconstr(net,state); + + faces_to_codes(symblemes,net_num); + if (VERBOSE) printf("\nA code was found\n"); + } + + state = maxgain_state(); + } + if (VERBOSE) { + printf("\nApprox_work = %d\n", approx_work); + constr_satisfaction(net,symblemes,dim_cube,"exact"); + out_performance("exact"); + weighted_outperf(net_num,"exact"); + } + + if (found_coding == FALSE) random_patch(symblemes,net_num); + + /* add a new dimension to the current cube to satisfy more constraints */ + if (code_length > dim_cube) { + project_code(net,symblemes,net_name,net_num,code_length); + } + + if (strcmp(net_name,"Inputnet") != 0) { + exact_rotation(); + exact_output(); + } + +} + + + +int num_outconstr(net) +CONSTRAINT **net; + +{ + + CONSTRAINT *constrptr; + int i; + + i = 0; + + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if (constrptr->attribute == NOTUSED) i++; + } + + return(i); + +} + + + +cut_nxstconstr(net,net_num) +CONSTRAINT **net; +int net_num; + +{ + + CONSTRAINT *constrptr; + int i; + + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + for (i=0; inext_states[i] == ONE) { + constrptr->attribute = PRUNED; + break; + } + } + } + +} + + +restore_nxstconstr(net,net_num) +CONSTRAINT **net; +int net_num; + +{ + + CONSTRAINT *constrptr; + int i; + + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + for (i=0; inext_states[i] == ONE) { + constrptr->attribute = NOTUSED; + break; + } + } + } + +} + + +tried_nxstconstr(net,next_state) +CONSTRAINT **net; +int next_state; + +{ + + CONSTRAINT *constrptr; + + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if (constrptr->next_states[next_state] == ONE && + constrptr->attribute == NOTUSED ) { + constrptr->attribute = TRIED; + } + } + +} + + + +notused_nxstconstr(net,next_state) +CONSTRAINT **net; +int next_state; + +{ + + CONSTRAINT *constrptr; + + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if (constrptr->next_states[next_state] == ONE && + constrptr->attribute == TRIED ) { + constrptr->attribute = NOTUSED; + } + } + +} + + + +used_nxstconstr(net,next_state) +CONSTRAINT **net; +int next_state; + +{ + + CONSTRAINT *constrptr; + + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if (constrptr->next_states[next_state] == ONE && + constrptr->attribute == TRIED ) { + constrptr->attribute = USED; + } + } + +} diff --git a/nova/log_approx.c b/nova/log_approx.c new file mode 100644 index 0000000..b7dcf8b --- /dev/null +++ b/nova/log_approx.c @@ -0,0 +1,97 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/log_approx.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +/**************************************************************************** +* Ve]rtices-wise [b]ottom-[u]p [c]onstraint-[c]lustered [heu]ristic [code] * +*****************************************************************************/ + +#include "nova.h" + +log_approx(net,symblemes,num,code_length) +CONSTRAINT *net; +SYMBLEME *symblemes; +int num; +int code_length; + +{ + int i,sel_symbleme; + BOOLEAN cycle_in_progress; + + codes_box(code_length); + + /* selects the first symbleme to encode */ + sel_symbleme = sel_first(net,symblemes,num); + + /*printf("\nThe first selected symbleme is %s (%d)\n", + symblemes[sel_symbleme].name , sel_symbleme);*/ + + /* codes the symbleme returned by sel_first */ + code_first(sel_symbleme,symblemes,num,code_length); + + + /* loops while there are symblemes not yet encoded */ + + cycle_in_progress = FALSE; + + /* checks if there are symblemes not already encoded */ + for (i=0; i= 0; i--) { + + for (constrptr = levelarray[i]; constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->levelnext) { + + if (constrptr->attribute == PRUNED || constrptr->attribute == USED) { + continue; + } + + /* if the current constraint involves "source" */ + if (constrptr->relation[source] == ONE) { + + /*printf("\nConstraint currently considered:%s", constrptr->relation);*/ + + for (j=0; jrelation[j] == ONE && + j != source && symblemes[j].code_status == NOTCODED) { + + /* assigns to the j-th symbleme the free code (k-th + vertex) at the minimum distance from the part of + constrptr already coded */ + mindist = -1; /* mindist is the minimum distance from a + free vertex to the part of constrptr + already coded */ + + for (k=0; krelation[l] == ONE && + symblemes[l].code_status != NOTCODED) { + + /* l is an already coded symbleme + belonging to constrptr */ + totdist = totdist + + hamm_dist(hypervertices[k].code, + symblemes[l].code,code_length); + + } + + } + + if ( (totdistodd_type == ADMITTED) + freeze(constrptr,symblemes,num,code_length); + constrptr->attribute = USED; + + /* prints the codes */ + /*show_code(symblemes,num); + printf("\n\n");*/ + + } + + } + + } + + /* prints the net */ + /*shownet(&net,net_name,"after code_first");*/ + +} + + + + +/************************************************************************** +* Propagates from the source a cluster of new codes * +* * +**************************************************************************/ + +int code_propagate(source,symblemes,num,code_length) +int source; +SYMBLEME *symblemes; +int num; +int code_length; + +{ + CONSTRAINT *constrptr; + int i,j,k,l; + int mindist,totdist,savevert; + + /*printf("\nCode_propagate\n"); + printf("==============\n");*/ + + /* scans the constraints involving "source" starting from the deepest */ + for (i = num - 1; i >= 0; i--) { + + for (constrptr = levelarray[i]; constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->levelnext) { + + if ( constrptr->attribute == PRUNED || + constrptr->attribute == USED) { + continue; + } + + /* if the current constraint involves "source" */ + if (constrptr->relation[source] == ONE) { + + /*printf("\nConstraint currently considered:%s", constrptr->relation);*/ + + for (j=0; jrelation[j] == ONE && j != source && + symblemes[j].code_status != FIXED) { + + /* assigns to the j-th symbleme the free code + (k vertex) at the minimum distance from the subset + of constrptr already coded */ + mindist = -1; /* mindist is the minimum distance from a + free vertex to the subset of constrptr + already coded */ + + for (k=0; krelation[l] == ONE && + symblemes[l].code_status == FIXED) { + + /* l is an already coded symbleme + included in constrptr */ + totdist = totdist + hamm_dist( + hypervertices[k].code, + symblemes[l].code,code_length); + + } + + } + + if ( (totdist < mindist) || (mindist<0) ) { + mindist = totdist; + savevert = k; + } + + } + + } + + newcode(hypervertices[savevert].code,j,symblemes); + strcpy(symblemes[j].code,hypervertices[savevert].code); + symblemes[j].code_status = FIXED; + hypervertices[savevert].ass_status = TRUE; + + } + + } + + /* deals with the holes if the constraint is not a power of 2 */ + if (constrptr->odd_type == ADMITTED) { + freeze(constrptr,symblemes,num,code_length); + } + + constrptr->attribute = USED; + + /* prints the codes */ + /*show_code(symblemes,num); + printf("\n\n");*/ + + } + + } + + } + + /*shownet(&net,net_name,"after code_propagate");*/ + +} + + + + + +/************************************************************************** +* codes the source element and the other ones related to the constraints * +* involving it * +**************************************************************************/ + +code_next(source,symblemes,num,code_length) +int source; +SYMBLEME *symblemes; +int num; +int code_length; + +{ + CONSTRAINT *constrptr; + int i,j,k,l; + int mindist,maxdist,totdist,savevert; + + /*printf("\nCode_next\n"); + printf("=========\n");*/ + + /* assigns to source the free code ( k vertex ) at the maximum distance from + the vertices already assigned */ + maxdist = 0; /* maxdist is the maximum distance from a free vertex to the + vertices already assigned */ + for (k=0; k maxdist) { + maxdist = totdist; + savevert = k; + } + + } + + } + + newcode(hypervertices[savevert].code,source,symblemes); + strcpy(symblemes[source].code,hypervertices[savevert].code); + symblemes[source].code_status = FIXED; + hypervertices[savevert].ass_status = TRUE; + + /* prints the codes */ + /*show_code(symblemes,num); + printf("\n\n");*/ + + /* scans the constraints involving "source" starting from the deepest */ + for (i = num-1; i >= 0; i--) { + + for (constrptr = levelarray[i]; constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->levelnext) { + + if (constrptr->attribute == PRUNED || + constrptr->attribute == USED) { + continue; + } + + /* if the current constraint involves "source" */ + if (constrptr->relation[source] == ONE) { + + /*printf("\nConstraint currently considered:%s", constrptr->relation);*/ + + for (j=0; jrelation[j] == ONE && + j != source && symblemes[j].code_status != FIXED) { + + /* assigns to the j-th symbleme the free code + (k vertex) at the minimum distance from the subset + of constrptr already encoded */ + mindist = -1; /* mindist is the minimum distance from a + free vertex to the part of constrptr + already encoded */ + for (k=0; krelation[l] == ONE && + symblemes[l].code_status == FIXED) { + + /* l is an already encoded symbleme + included in constrptr */ + totdist = totdist + + hamm_dist(hypervertices[k].code, + symblemes[l].code,code_length); + + } + + } + + if ( (totdist < mindist) || (mindist < 0) ) { + mindist = totdist; + savevert = k; + } + + } + + } + + newcode(hypervertices[savevert].code,j,symblemes); + strcpy(symblemes[j].code,hypervertices[savevert].code); + symblemes[j].code_status = FIXED; + hypervertices[savevert].ass_status = TRUE; + + } + + } + + /* deals with the holes if the constraint is not a power of 2 */ + if (constrptr->odd_type == ADMITTED) { + freeze(constrptr,symblemes,num,code_length); + } + constrptr->attribute = USED; + + /* prints the codes */ + /*show_code(symblemes,num); + printf("\n\n");*/ + + } + + } + + } + + /* prints the net */ + /*shownet(&net,net_name,"after code_next");*/ + +} + + + +/************************************************************************** +* Fills the field "code" of "vertices" with the boolean coordinates of * +* that hypervertex on the hypercube of dimension "code_length" * +**************************************************************************/ + +codes_box(code_length) +int code_length; + +{ + char module; + int i,j,k,codes_num; + + codes_num = power(2,code_length); + + /* clears hypervertices[].code[] before filling them with the right codes */ + for (i=0; i 0 ) { + + if ( j % 2 == 0 ) { + module = ZERO; + } else { + module = ONE; + } + + hypervertices[i].code[k] = module; + + j = j / 2; + k--; + } + + hypervertices[i].ass_status = FALSE; + } + + /*printf("\nCodes provided by codes_box\n"); + for (i=0; icard) - constrptr->card); i++) { + + /* assigns to the i-th hole of "constrptr" the free code ( k vertex ) + at the minimum distance from the subset of constrptr alrady coded */ + mindist = -1; /* mindist is the minimum distance from a free vertex to + the subset of "constrptr" already coded */ + for (k = 0; k < power(2,code_length); k++) { + + if (hypervertices[k].ass_status == FALSE) { + + /* k is a free vertex on the hypercube */ + totdist = 0; + for (l = 0; l < num; l++) { + + if (constrptr->relation[l] == ONE && + symblemes[l].code_status == FIXED ) { + + /* l is an already coded symbleme included in + constrptr */ + totdist = totdist + + hamm_dist(hypervertices[k].code,symblemes[l].code, + code_length); + + } + + } + + if ( (totdist < mindist) || (mindist < 0) ) { + mindist = totdist; + savevert = k; + } + + } + + } + + /* freezes a vertex iff it is included in the hyperface spanned by + "constrptr" */ + /*printf("mindist = %d ", mindist); + printf("perimeter = %d\n", perimeter(mylog2(minpow2(constrptr->card))));*/ + + if ( mindist <= perimeter(mylog2(minpow2(constrptr->card)))) { + hypervertices[savevert].ass_status = TRUE; + /*printf("mindist <= perimeter : frozen vertex = %s\n", hypervertices[savevert].code);*/ + } else { + /*printf("mindist > perimeter : no vertex frozen\n");*/ + } + + } + +} diff --git a/nova/log_mini.c b/nova/log_mini.c new file mode 100644 index 0000000..bc037a5 --- /dev/null +++ b/nova/log_mini.c @@ -0,0 +1,170 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/log_mini.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ + +/******************************************************************************* +* Invokes the minimizer to get the final boolean representation * +* This version uses the espresso-II version#2.0 binary-valued minimizer * +*******************************************************************************/ + +#include "nova.h" + +coded_mini() + +{ + + FILE *fopen(),*fp3,*fp1; + char line[MAXLINE],*fgets(); + char string1[MAXSTRING]; + char string2[MAXSTRING]; + char string3[MAXSTRING]; + char string4[MAXSTRING]; + char string5[MAXSTRING]; + char command[MAXSTRING]; + int i,j,cursor,linelength; + int code_index,notany_index; + + if ( (fp3 = fopen(temp3,"w")) == NULL ) { + fprintf(stderr,"fopen in coded_mini: can't create temp3\n"); + exit(-1); + } + + if ( (fp1 = fopen(temp1,"r")) == NULL ) { + fprintf(stderr,"fopen in coded_mini: can't read temp1\n"); + exit(-1); + } + + if (TYPEFR) fputs(".type fr\n", fp3); + if (ISYMB) { + sprintf(string1,".i %d\n", inp_codelength + st_codelength); + } else { + sprintf(string1,".i %d\n", inputfield + st_codelength); + } + fputs(string1,fp3); + /*printf("string1 = %s\n", string1);*/ + + sprintf(string1,".o %d\n", st_codelength + outputfield -1); + fputs(string1,fp3); + /*printf("string1 = %s\n", string1);*/ + + while ( fgets(line,MAXLINE,fp1) != (char *) 0) { + + linelength = strlen(line); + + /* skip blank lines , comment lines and command lines */ + if ( (linelength == 1) || (myindex(line,"#") >= 0) || + (myindex(line,".") >= 0) ) { + ; + } else { + + /* takes care of proper inputs */ + if (ISYMB) { + + for (i = 0; i < inputnum; i++) { + string2[i] = line[i]; + } + + string2[inputnum] = '\0'; + /*printf("string2 = %s\n", string2);*/ + code_index = myindex(string2,"1"); + /*printf("index = %d\n", code_index);*/ + + if ( code_index != -1 ) { + strcpy(string2,inputs[code_index].code); + } else { + for (j = 0; j < inp_codelength; j++) { + string2[j] = '-'; + } + string2[inp_codelength] = '\0'; + } + + /*printf("string2 = %s\n", string2);*/ + cursor = inputnum + 3; + + } else { + + for (i = 0; i < inputfield; i++) { + string2[i] = line[i]; + } + string2[inputfield] = '\0'; + /*printf("string2 = %s\n", string2);*/ + cursor = inputfield + 3; + + } + + /* takes care of present states */ + for (i = cursor; i < cursor + statenum; i++) { + string3[i-cursor] = line[i]; + } + string3[statenum] = '\0'; + /*printf("string3 = %s\n", string3);*/ + notany_index = myindex(string3,"0"); + /*printf("notany_index = %d\n", notany_index);*/ + if ( notany_index != -1 ) { + code_index = myindex(string3,"1"); + /*printf("code_index = %d\n", code_index);*/ + strcpy(string3,states[code_index].code); + } else { + for (j = 0; j < st_codelength; j++) { + string3[j] = '-'; + } + string3[st_codelength] = '\0'; + } + /*printf("string3 = %s\n", string3);*/ + cursor = i + 3; + + /* takes care of next states */ + for (i = cursor; i < cursor + statenum; i++) { + string4[i-cursor] = line[i]; + } + string4[statenum] = '\0'; + /*printf("string4 = %s\n", string4);*/ + notany_index = myindex(string4,"0"); + /*printf("notany_index = %d\n", notany_index);*/ + if ( notany_index != -1 ) { + code_index = myindex(string4,"1"); + /*printf("code_index = %d\n", code_index);*/ + strcpy(string4,states[code_index].code); + } else { + for (j = 0; j < st_codelength; j++) { + string4[j] = '-'; + } + string4[st_codelength] = '\0'; + } + /*printf("string4 = %s\n", string4);*/ + cursor = i + 1; + + /* takes care of proper outputs */ + for (i = cursor; i < cursor + outputfield; i++) { + string5[i-cursor] = line[i]; + } + string5[outputfield] = '\0'; + /*printf("string5 = %s\n", string5);*/ + + sprintf(string1,"%s %s %s %s\n", string2, string3, string4, + string5); + fputs(string1,fp3); + + } + + } + + fclose(fp1); + + fclose(fp3); + + + if (VERBOSE) printf("\nRunning Espresso from coded_mini\n"); + /*sprintf(command,"espresso -fr %s > %s", temp3, temp4);changed*/ + sprintf(command,"espresso %s > %s", temp3, temp4); + system(command); + if (VERBOSE) printf("Espresso terminated\n"); + + +} diff --git a/nova/log_output.c b/nova/log_output.c new file mode 100644 index 0000000..72386f5 --- /dev/null +++ b/nova/log_output.c @@ -0,0 +1,405 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/log_output.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +#include "nova.h" + +/****************************************************************************** +* Last small business before leaving NOVA * +******************************************************************************/ + + +log_output() + +{ + lsummary(); + + if (VERBOSE) printf("\nTHE END of NOVA\n"); +} + + + + +/************************************************************************** +* Prints the most interesting results * +**************************************************************************/ + +lsummary() + +{ + + if (VERBOSE) printf("\n\n\n SUMMARY\n\n"); + fprintf(stdout,"# Prod.-terms of minimized MV cover = %d\n", onehot_products); + fprintf(stdout,"# Prod.-terms of encoded cover = %d\n", best_products); + /*printf("worst_products = %d\n", worst_products);*/ + fprintf(stdout,"# Pla area = %d\n", best_size); + printf("#\n# .start_codes\n"); + if (ISYMB) show_bestcode(inputs,inputnum); + show_bestcode(states,statenum); + printf("# .end_codes\n"); + + if (VERBOSE) { + if (I_GREEDY) { + printf("\nSatisfaction of the input constraints intersection lattice\n"); + if (ISYMB) { + printf("INPUTS :"); + constr_satisfaction(&inputnet,inputs,inp_codelength,"best"); + printf("\n"); + } + printf("STATES :"); + constr_satisfaction(&statenet,states,st_codelength,"best"); + printf("\n"); + inputnet = (CONSTRAINT *) 0; + statenet = (CONSTRAINT *) 0; + analysis(temp2); + } + printf("\nSatisfaction of the input constraints\n"); + if (ISYMB) { + printf("INPUTS :"); + constr_satisfaction(&inputnet,inputs,inp_codelength,"best"); + printf("\n"); + } + printf("STATES :"); + constr_satisfaction(&statenet,states,st_codelength,"best"); + } + +} + + + +int inclusion(string1,string2,length) +char *string1; +char *string2; +int length; + +{ + int i,value; + + value = 0; + + for (i = 0; i < length; i++) { + + if ( (string2[i] == '*') || (string1[i] == string2[i]) ) { + + value = 1; + + } else { + value = 0; + break; + } + + } + + return(value); + +} + + + +/************************************************************************** +* Assigns random codes to symblemes and minimizes * +**************************************************************************/ + +randomization() + +{ + + int i; + int size_summ = 0; + int random_size; + + if (VERBOSE) printf("\n\nRANDOM ENCODINGS\n"); + + /* if the value of "rand_trials" is still -1 at this point it means that the + user didn't specify his own value of "rand_trials" and relies on the + values assigned by default : "statenum" if proper inputs are not + symbolic , "statenum" + "inputnum" if the proper inputs are symbolic */ + if ( rand_trials == -1) { + + rand_trials = statenum; + + if (ISYMB) { + rand_trials = rand_trials + inputnum; + } + + } + + for (i=1; i<= rand_trials; i++) { + + if (VERBOSE) printf("\nRand_trials # %d\n", i); + random_code(&random_size); + size_summ = size_summ + random_size; + + } + + fprintf(stdout,"# Prod.-terms of minimized MV cover = %d\n", onehot_products); + fprintf(stdout,"# Prod.-terms of best encoded cover = %d\n", best_products); + fprintf(stdout,"# Best pla area = %d\n", best_size); + fprintf(stdout,"# Average pla area= %d\n", size_summ / rand_trials); + if (VERBOSE) printf("\nBest random codes:\n"); + printf("#\n# .start_codes\n"); + if (ISYMB) show_bestcode(inputs,inputnum); + show_bestcode(states,statenum); + printf("# .end_codes\n"); + +} + + + + +random_code(rand_size) +int *rand_size; + +{ + + long time(); + int i,new_code,increment,range,current_size,seed,trandom(); + + seed = (int) time(0); + srand(seed); + + /* random codes the inputs */ + if (ISYMB) { + range = power(2,inp_codelength); + new_code = trandom(range); + increment = trandom(range)*2 + 1; + for (i = 0; i < inputnum; i++) { + itob(inputs[i].code,new_code,inp_codelength); + new_code = (new_code + increment) % range; + } + } + + /* random codes the states */ + range = power(2,st_codelength); + new_code = trandom(range); + increment = trandom(range)*2 + 1; + for (i = 0; i < statenum; i++) { + itob(states[i].code,new_code,st_codelength); + new_code = (new_code + increment) % range; + } + + coded_mini(); + + current_size = size(); + *rand_size = current_size; + + if ( best_size == 0 || current_size < best_size ) { + best_products = min_products; + best_size = current_size; + savecover(); + } + +} + + + +/************************************************************************ +* Tries the best complementation and then minimizes * +* * +************************************************************************/ + + +rotation() + +{ + + int i,current_size; + + if (VERBOSE) printf("\n\nSTARTS THE COMPLEMENTATION PART\n"); + + worst_products = 0; + first_size = best_size = 0; + + if (COMPLEMENT) { + + /* complements the codes of the states and then minimizes */ + for (i = 0; i < statenum; i++) { + + if (VERBOSE)printf("\nThe null code is assigned to the state %s\n", + states[i].name); + compl_states(i); + + coded_mini(); + + current_size = size(); + + if (min_products > worst_products) { + worst_products = min_products; + } + + /* local optimality */ + if ( first_size == 0 || first_size > current_size ) { + first_size = current_size; + } + + /* global optimality */ + if ( best_size == 0 || best_size > first_size ) { + best_products = min_products; + best_size = first_size; + savecover(); + } + + if (VERBOSE) { + printf("\nbest_products = %d", best_products); + printf("\nbest_size = %d\n", best_size); + } + /*printf("\nbest codes for the states found so far"); + show_bestcode(states,statenum);*/ + + } + + } else { + + compl_states(zerostate()); + + coded_mini(); + + current_size = size(); + + /* global optimality */ + if ( best_size == 0 || best_size > current_size ) { + best_products = min_products; + best_size = current_size; + savecover(); + } + + if (VERBOSE) printf("best_size = %d\n", best_size); + /*printf("\nbest codes for the states found so far"); + show_bestcode(states,statenum);*/ + + } + + if (VERBOSE) printf("\nENDS THE COMPLEMENTATION PART\n"); + +} + + + + +/****************************************************************************** +* Saves the best code found so far in the bestcode field of the symblemes * +******************************************************************************/ + +savecover() + +{ + + char command[MAXSTRING]; + int i; + + /* saves the input codes */ + if (ISYMB) { + for ( i = 0; i < inputnum; i++ ) { + strcpy(inputs[i].best_code,inputs[i].code); + strcpy(inputs[i].exbest_code,inputs[i].code); + } + } + + /* saves the state codes */ + for ( i = 0; i < statenum; i++ ) { + strcpy(states[i].best_code,states[i].code); + strcpy(states[i].exbest_code,states[i].code); + } + + /* saves the unminimized cover in temp33 - to fix a bug, july 1994 */ + sprintf(command,"cp %s %s", temp3, temp33); + system(command); + + /* saves the minimized cover in temp5 */ + sprintf(command,"cp %s %s", temp4, temp5); + system(command); + +} + +/****************************************************************************** +* Finds zerostate , i.e. the state that appears more * +* often as a next state with a zero proper output * +******************************************************************************/ + + +zerostate() + +{ + + int i,zero,maxi; + + if (IO_HYBRID || IO_VARIANT || USER || ONEHOT) return(-1); + + zero = -1; + maxi = -1; + + if (ZERO_FL) { + for (i=0; i maxi) { + maxi = zeroutput[i]; + zero = i; + } + } + } + + if (VERBOSE) { + if (zero == -1) { + printf("\nThe zerostate is unspecified\n"); + } else { + printf("\nThe zerostate is %s (%d)\n" , states[zero].name , zero); + } + } + + return(zero); + +} + + + +/****************************************************************************** +* Complements the codes of the states * +******************************************************************************/ + +compl_states(null_code) +int null_code; + +{ + + int state,bit; + + if ( null_code == -1 ) { + if (VERBOSE) printf("\nUnspecified argument to compl_state\n"); + return; + } + + + /*printf("Codes of the states before the complementation"); + show_code(states,statenum);*/ + + for ( bit = 0; bit < strlen(states[0].code); bit++ ) { + if ( states[null_code].code[bit] == ONE) { + /* complements this bit */ + for ( state = 0; state < statenum; state++ ) { + if ( states[state].code[bit] == ONE ) { + states[state].code[bit] = ZERO; + } else { + states[state].code[bit] = ONE; + } + } + } + } + + /*printf("\nCodes of the states after the complementation"); + show_code(states,statenum);*/ + +} diff --git a/nova/log_precode.c b/nova/log_precode.c new file mode 100644 index 0000000..795facd --- /dev/null +++ b/nova/log_precode.c @@ -0,0 +1,551 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/log_precode.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +/****************************************************************************** +* Massages the constraintlist "net" to create its lattice * +* * +******************************************************************************/ + +#include "nova.h" + +precode(net) +CONSTRAINT **net; + +{ + if (POW2CONSTR) { + + /* generates the constraints lattice using only power-of-two constraints */ + pow2pruning(net); + + /*shownet(net,net_name,"after pow2pruning (1st pass)");*/ + + red_lattice(net); + + /*shownet(net,net_name,"after red_lattice");*/ + + pow2pruning(net); + + /*shownet(net,net_name,"after pow2pruning (2nd pass)");*/ + + + } else { + + /* generates the constraints lattice using all available constraints */ + + lattice(net); + + /*shownet(net,net_name,"after lattice");*/ + + + } + +} + + + + +/******************************************************************************* +* Manipulates the constraints whose cardinality is not a power of two : * +* either keeps them in the lattice freezing degrees of freedom on the * +* hypercube ( up to the closest power of two ) or deletes them * +* ( according to whether free positions on the hypercube are still available * +* or not ) * +*******************************************************************************/ + + +pow2pruning(net) +CONSTRAINT **net; + +{ + CONSTRAINT *constrptr,*temptr; + + int virtuals; /* virtual symblemes introduced by forcing the satisfaction + of constraints whose cardinality is not a power of 2 */ + int free_places; /* # of vertices of the hypercube not already assigned to + symblemes */ + + /* empty net : do nothing */ + if ((*net) == (CONSTRAINT *) 0) return; + + /* prune the constraints whose cardinality is either 1 or larger than 1/2 + of the # of symblemes - + pruning is done by setting to PRUNED the field "attribute" of + "constraint " */ + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if ( (constrptr->card == 1) || + (constrptr->card > (minpow2(strlen((*net)->relation))/2)) ) { + constrptr->attribute = PRUNED; + } + } + + + /* prune the constraints whose cardinality is not a power of 2 + if the number of symblemes is a power of two */ + + /* virtuals is set to the proper value */ + virtuals = 0; + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) { + if (constrptr->odd_type == ADMITTED ) { + virtuals = virtuals + minpow2(constrptr->card) - constrptr->card; + } + } + + /* free_places is set to the proper value */ + free_places = minpow2(strlen((*net)->relation)) - + strlen((*net)->relation) - virtuals; + + + if (free_places == 0) { + + /* prune the constraints whose cardinality is not a power of 2 + if the number of symblemes is a power of two */ + + for ( constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next ) { + if ( constrptr->attribute != PRUNED && + constrptr->odd_type != ADMITTED && + minpow2(constrptr->card) != constrptr->card ) { + constrptr->attribute = PRUNED; + } + } + + } else { + + /* consider as constraints to be satisfied + ( i.e. set to ADMITTED the field "odd_type" of "constraint" ) + the unpruned constraints whose cardinality is not a + power-of-two as long as there are free places on the + hypercube - + heuristics : keep with higher priority the constraints of + larger cardinality */ + + /* "temptr" points to the next constraint ( whose cardinality + is not a power of two ) not yet taken into consideration */ + for (constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next) + { + if (constrptr->attribute != PRUNED && + constrptr->odd_type != ADMITTED && + (minpow2(constrptr->card) - constrptr->card != 0) ) { + temptr = constrptr ; + break; + } + } + + /* loops as long as there are free places and constraints + whose cardinality is not a power of two - + according to the chosen heuristics , + "temptr" points to the next constraint of larger cardinality + ( whose cardinality is not a power of two ) not yet taken + into consideration */ + while ( free_places > 0 && constrptr != ( CONSTRAINT *) 0 ) { + for ( constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next ) { + if ( constrptr->attribute != PRUNED && + (constrptr->odd_type != ADMITTED && + constrptr->odd_type != EXAMINED ) && + minpow2(constrptr->card)-constrptr->card != 0 ) { + if (constrptr->card > temptr->card) { + temptr = constrptr ; + } + } + } + + /* sets temptr->oddtype to ADMITTED if temptr needs less or + equal free_places than available ( and freepos gets the + updated value ) - otherwise sets temptr->odd_type to + EXAMINED to avoid reconsidering it as the while goes on */ + if ((minpow2(temptr->card) - temptr->card) <= free_places) { + free_places = + free_places - (minpow2(temptr->card) - temptr->card); + temptr->odd_type = ADMITTED; + } else { + temptr->odd_type = EXAMINED; + } + + /* finds the next constraint (whose cardinality is not + a power of two) not yet taken into consideration */ + for ( constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next ) { + if (constrptr->attribute != PRUNED && + (constrptr->odd_type != ADMITTED && + constrptr->odd_type != EXAMINED) && + minpow2(constrptr->card) - constrptr->card != 0) { + temptr = constrptr; + break; + } + } + + + } + + } + + /* prune the remaining constraints (of cardinality not a + power of two) not taken into consideration because all + the free places on the hypercube were already gone */ + for ( constrptr = (*net); constrptr != (CONSTRAINT *) 0; + constrptr = constrptr->next ) { + if ( constrptr->attribute != PRUNED && + (minpow2(constrptr->card)-constrptr->card != 0) && + constrptr->odd_type != ADMITTED ) { + constrptr->attribute = PRUNED; + } + } + + + + +} + + + + +/******************************************************************************* +* Creates the lattice of the constraintlist "list" , appending to the bare * +* constraintlist outputted by the routine "analysis" all the intersections * +* of constraints without repetitions ( if an intersection coincides with a * +* constraint already present , the action taken is to increase the depth of * +* the constraint ) * +* "lattice" is called when the option POW2CONSTR is not active , i.e. when * +* the lattice is not pruned by "pow2pruning" * +*******************************************************************************/ + + +lattice(net) +CONSTRAINT **net; + +{ + CONSTRAINT *constrptr1,*constrptr2,*temptr,*new,*newconstraint(); + char *newrelation; + int i,card,level; + BOOLEAN cycle_in_progress; + int countnewconstr; + + countnewconstr = 0; + + /* empty net : do nothing */ + if ((*net) == (CONSTRAINT *) 0) return; + + if ((newrelation = (char *) calloc((unsigned)(strlen((*net)->relation)+1),sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for newrelation in lattice\n"); + exit(-1); + } + newrelation[strlen((*net)->relation)] = '\0'; + + level = 0; + + do { + + cycle_in_progress = FALSE; + + /* "constrptr1" points to the first operand of the intersection + operation */ + for (constrptr1 = (*net); constrptr1 != (CONSTRAINT *) 0; + constrptr1 = constrptr1->next) { + if ( constrptr1->attribute == PRUNED || + constrptr1->level != level ) { + continue; + } + + /* "constrptr2" points to the second operand of the intersection + operation */ + for (constrptr2 = constrptr1->next; constrptr2 != (CONSTRAINT *) 0; + constrptr2 = constrptr2->next) { + if ( constrptr2->attribute == PRUNED || + constrptr2->level != level ) { + continue; + } + + /* compute a new constraint as the intersection of two other ones */ + card = 0; + for (i=0; constrptr1->relation[i] != '\0'; i++) { + if (constrptr1->relation[i] == ONE && + constrptr2->relation[i] == ONE ) { + card++; + newrelation[i] = ONE; + } else { + newrelation[i] = ZERO; + } + } + + /* discard intersections empty or with cardinality either 1 + or larger than 1/2 of the # of symblemes */ + if ( card == 0 || + card == 1 || + card > (minpow2(strlen((*net)->relation))/2) ) { + continue; + } + + cycle_in_progress = TRUE; + + /* take care of intersections coinciding with already present elements */ + for ( temptr = (*net); temptr != (CONSTRAINT *) 0; + temptr = temptr->next) { + if (strcmp(newrelation,temptr->relation) == 0) { + break; + } + } + + /* constraint not already found */ + if (temptr == (CONSTRAINT *) 0) { + new = newconstraint(newrelation,card,level+1); + new->next = (*net); + (*net) = new; + countnewconstr++; + } else { + temptr->weight++; + temptr->newlevel = level+1; + } + + if ( countnewconstr > 1000 ) { + fprintf(stderr,"\n WARNING\n"); + fprintf(stderr,"** After that lattice added the 1001-th new constraint ,\n"); + fprintf(stderr,"Nova stopped executing lattice and went ahead with the\n"); + fprintf(stderr,"constraints that lattice already got ****************\n\n"); + return; + } + + } + } + + for ( constrptr1 = (*net); constrptr1 != (CONSTRAINT *) 0; + constrptr1 = constrptr1->next) { + if (constrptr1->newlevel > constrptr1->level) { + constrptr1->level = constrptr1->newlevel; + } + } + + level++; + + + } while (cycle_in_progress); + + +} + + + + + + + +/******************************************************************************* +* Creates the lattice of the constraintlist "list" , appending to the bare * +* constraintlist outputted by the routine "analysis" all the intersections * +* of constraints without repetitions ( if an intersection coincides with a * +* constraint already present , the action taken is to increase the depth of * +* the constraint ) - * +* "red_lattice" is called when the option POW2CONSTR is active , i.e. when * +* the lattice is pruned by "pow2pruning" * +*******************************************************************************/ + + +red_lattice(net) +CONSTRAINT **net; + +{ + CONSTRAINT *constrptr1,*constrptr2,*temptr,*new,*newconstraint(); + char *newrelation; + int i,card,samecard,level; + BOOLEAN cycle_in_progress; + int countnewconstr; + + countnewconstr = 0; + + /* empty net : do nothing */ + if ((*net) == (CONSTRAINT *) 0) return; + + if ((newrelation = (char *) calloc((unsigned)(strlen((*net)->relation)+1),sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for newrelation in lattice\n"); + exit(-1); + } + newrelation[strlen((*net)->relation)] = '\0'; + + level = 0; + + do { + + cycle_in_progress = FALSE; + + /* "constrptr1" points to the first operand of the intersection + operation */ + for (constrptr1 = (*net); constrptr1 != (CONSTRAINT *) 0; + constrptr1 = constrptr1->next) { + if ( constrptr1->attribute == PRUNED || + constrptr1->level != level ) { + continue; + } + + /* "constrptr2" points to the second operand of the intersection + operation */ + for (constrptr2 = constrptr1->next; constrptr2 != (CONSTRAINT *) 0; + constrptr2 = constrptr2->next) { + if ( constrptr2->attribute == PRUNED || + constrptr2->level != level ) { + continue; + } + + /* compute a new constraint as the intersection of two other ones */ + card = 0; + if (constrptr1->card == constrptr2->card ) { + samecard = 1; + } else { + samecard = 0; + } + for (i=0; constrptr1->relation[i] != '\0'; i++) { + if (constrptr1->relation[i] == ONE && + constrptr2->relation[i] == ONE ) { + card++; + newrelation[i] = ONE; + } else { + newrelation[i] = ZERO; + } + } + + /* discard empty intersections */ + if (card == 0) { + continue; + } + + + /* Disregard intersections if + a) they come from rows of same cardinality + && + b) their cardinality is not 1\2 of the cardinality of the + parents . + Heuristics : we have to prune one of the two new constraints + (because they are incompatible) , in case one of them is found + via the "output_forcing" routine and the other is found via the + "mini" routine we choose to get rid of the one not originated + via the "output_forcing" routine */ + + if ( constrptr1->card == constrptr2->card && + card != (constrptr1->card/2) ) { + if (constrptr1->source_type != INPUT && + constrptr2->source_type == INPUT ) { + constrptr2->attribute = PRUNED; + continue; + } + + if (constrptr1->source_type == INPUT && + constrptr2->source_type != INPUT ) { + constrptr1->attribute = PRUNED; + break; + } + } + + + cycle_in_progress = TRUE; + + /* take care of intersections coinciding with already present elements */ + for ( temptr = (*net); temptr != (CONSTRAINT *) 0; + temptr = temptr->next) { + if (strcmp(newrelation,temptr->relation) == 0) { + break; + } + } + + /* constraint not already found */ + if (temptr == (CONSTRAINT *) 0) { + new = newconstraint(newrelation,card,level+samecard+1); + new->next = (*net); + (*net) = new; + countnewconstr++; + } else { + temptr->weight++; + temptr->newlevel = level+samecard+1; + } + + if ( countnewconstr > 1000 ) { + fprintf(stderr,"\n WARNING\n"); + fprintf(stderr,"** After that red_lattice added the 1001-th new constraint ,\n"); + fprintf(stderr,"Nova stopped executing red_lattice and went ahead with the\n"); + fprintf(stderr,"constraints that red_lattice already got ****************\n\n"); + return; + } + + } + } + + for ( constrptr1 = (*net); constrptr1 != (CONSTRAINT *) 0; + constrptr1 = constrptr1->next) { + if (constrptr1->newlevel > constrptr1->level) { + constrptr1->level = constrptr1->newlevel; + } + } + + level++; + + + } while (cycle_in_progress); + + +} + + + +/***************************************************************************** +* Links the constraints to all the data structures involved in the coding * +* algorithm (e.g. "symblemes", "levelarray", "cardarray") * +*****************************************************************************/ + +link_constr(net,symblemes,num) +CONSTRAINT *net; +SYMBLEME *symblemes; +int num; + +{ + + CONSTRAINT *temptr; + CONSTRLINK *newlink; + int i; + + for (i=0; inext ) { + + if ( temptr->attribute == PRUNED ) { + continue; + } + + temptr->attribute = NOTUSED; + + for (i=0; irelation[i] == ONE) { + + if ((newlink = (CONSTRLINK *) calloc((unsigned)1,sizeof(CONSTRLINK))) == ( CONSTRLINK *) 0) { + fprintf(stderr,"Insufficient memory for newlink in link_constr"); + exit(-1); + } + + newlink->constraint = temptr; + newlink->next = symblemes[i].constraints; + symblemes[i].constraints = newlink; + + } + } + + temptr->levelnext = levelarray[temptr->level]; + levelarray[temptr->level] = temptr; + temptr->cardnext = cardarray[temptr->card]; + cardarray[temptr->card] = temptr; + + } + +} diff --git a/nova/log_sel.c b/nova/log_sel.c new file mode 100644 index 0000000..7a20048 --- /dev/null +++ b/nova/log_sel.c @@ -0,0 +1,318 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/log_sel.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +#include "nova.h" + +/************************************************************************** +* Chooses the first symbleme to encode * +* * +**************************************************************************/ + +sel_first(net,symblemes,num) +CONSTRAINT *net; +SYMBLEME *symblemes; +int num; + +{ + CONSTRAINT *constrptr1,*constrptr2; + int *candidates; + int i,selected,maxcount; + + /* allocates memory for candidates */ + if ((candidates = (int *) calloc((unsigned)(num+1),sizeof(int))) == (int *) 0) { + fprintf(stderr,"Insufficient memory for candidates in sel_first\n"); + exit(-1); + } + + /* searches the deepest constraint */ + for (i = num-1; i>=0; i--) { + for (constrptr1 = levelarray[i]; constrptr1 != (CONSTRAINT *) 0; + constrptr1 = constrptr1->levelnext) { + if (constrptr1->attribute == NOTUSED) { + break; + } + } + if (constrptr1 != (CONSTRAINT *) 0) { + break; + } + } + + /* if the search for a constraint doesn't return a pointer to nil */ + if ( (constrptr1 != (CONSTRAINT *) 0) && ( i>= 0 ) ) { + + for (i=0; ilevelnext) { + if (constrptr2->attribute == NOTUSED) { + for (i=0; irelation[i] == ONE) { + candidates[i] = candidates[i] + 10 + constrptr2->weight; + } + } + } + + /* gives each symbleme belonging to a constraint originated from an + output an additional score of 10 */ + for (constrptr1 = net; constrptr1 != (CONSTRAINT *) 0; + constrptr1 = constrptr1->next) { + if (constrptr1->source_type != 0) { + for (i=0; irelation[i] == ONE) { + candidates[i] = candidates[i] + 10; + } + } + } + } + + /* chooses the element with the largest score */ + maxcount = -1; + for (i=0; i= maxcount) { + maxcount = candidates[i]; + selected = i; + } + } + + /* prints the candidates + printf("\nCandidates = "); + for (i=0; inext) { + + if ( (constrptr->attribute == NOTUSED) && + (constrptr->relation[i]== ONE) ) { + + /* k is a symbleme not already coded */ + for (k=0; krelation[k] == ONE) && + (symblemes[k].code_status == NOTCODED) ) { + + /* scans the notused constraints involving i + to compute its score - chooses the "i-th" + symbleme with the largest score */ + score = 0; + + for (link = symblemes[i].constraints; + link != (CONSTRLINK *) 0; + link = link->next) { + + if (link->constraint->attribute == NOTUSED) { + + score = score + + (link->constraint->level+1) * + link->constraint->weight; + + } + + } + + if (score > maxscore) { + maxscore = score; + propagate = i; + } + + } + + } + + } + } + } + + } + + } + + } + + return(propagate); + +} + + + +/************************************************************************** +* Chooses a new symbleme to code (not constraint-related to the symblemes * +* already coded) * +* * +**************************************************************************/ + + +sel_next(net,symblemes,num) +CONSTRAINT *net; +SYMBLEME *symblemes; +int num; + +{ + CONSTRAINT *constrptr1,*constrptr2; + int *candidates; + int i,j,jump,selected,maxcount; + + /* allocate memory for candidates */ + if ((candidates = (int *) calloc((unsigned)(num+1),sizeof(int))) == (int *) 0) { + fprintf(stderr,"Insufficient memory for candidates in sel_next\n"); + exit(-1); + } + + /* search the deepest constraint */ + jump = 0; + for (i = num-1; i >= 0; i--) { + for (constrptr1 = levelarray[i]; constrptr1 != (CONSTRAINT *) 0; + constrptr1 = constrptr1->levelnext) { + if ( constrptr1->attribute == NOTUSED ) { + for (j=0; jrelation[j] == ONE) && + (symblemes[j].code_status == NOTCODED ) ) { + jump = 1; + break; + } + } + } + if ( constrptr1 != (CONSTRAINT *) 0 && jump == 1) break; + } + if ( constrptr1 != (CONSTRAINT *) 0 && jump == 1) break; + } + + /* if the search for a constraint doesn't return a pointer to nil */ + if ( (constrptr1 != (CONSTRAINT *) 0) && (i >= 0) ) { + + for (i=0; ilevelnext) { + + if (constrptr2->attribute == NOTUSED) { + + for (i = 0; i < num; i++) { + + if ( constrptr2->relation[i] == ONE && + symblemes[i].code_status == NOTCODED ) { + + candidates[i] = candidates[i] + 10 + constrptr2->weight; + + } + + } + + } + + } + + /* each element belonging to a constraint originated from an + output is given an additional score of 10 */ + for (constrptr1 = net; constrptr1 != (CONSTRAINT *) 0; + constrptr1 = constrptr1->next ) { + if (constrptr1->source_type != 0) { + for (i=0; irelation[i] == ONE && + symblemes[i].code_status == NOTCODED ) { + candidates[i] = candidates[i] + 10; + } + } + } + } + + /* the element with the maximum score is chosen */ + maxcount = -1; + for (i=0; i= maxcount) { + maxcount = candidates[i]; + selected = i; + } + } + + /* prints the candidates */ + /*printf ("\nCandidates = "); + for (i=0; iinput); + st_length = strlen(firstable->pstate); + for ( i = 0; i < 2; i++ ) { + if ( (arg_array[i] = (char *) calloc((unsigned)inp_length+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for arg_array[i]"); + exit(-1); + } + arg_array[i][inp_length] = '\0'; + } + for ( i = 2; i < 4; i++ ) { + if ( (arg_array[i] = (char *) calloc((unsigned)st_length+1,sizeof(char))) == (char *) 0) { + fprintf(stderr,"Insufficient memory for arg_array[i]"); + exit(-1); + } + arg_array[i][st_length] = '\0'; + } + + ones = 0; + for (new = firstable; new != (INPUTTABLE *) 0; new = new->next) { + for (i = 0; i < strlen(new->output) -1; i++) { + if (new->output[i] == ONE) { + ones++; + } + } + } + printf("Incompatibility graph (size = %d):\n", ones); + + if (ones >0) { + if ( (inco1_array = (int **) calloc((unsigned)ones,sizeof(int *))) == (int **) 0) { + fprintf(stderr,"Insufficient memory for 'inco1_array'"); + exit(-1); + } + for ( i = 0; i < ones; i++ ) { + if ( (inco1_array[i] = (int *) calloc((unsigned)ones,sizeof(int))) == (int *) 0) { + fprintf(stderr,"Insufficient memory for inco1_array[i]"); + exit(-1); + } + } + + for (i = 0; i < ones; i++) { + for (j = 0; j < ones; j++) { + inco1_array[i][j] = 0; + } + } + + for (i = 0; i < ones -1; i++) { + i_col = argument1(i,arg_array[0],arg_array[2]); + for (j = i+1; j < ones; j++) { + j_col = argument1(j,arg_array[1],arg_array[3]); + INCOMPATIBLE = FALSE; + for (new = firstable; new != (INPUTTABLE *) 0; new = new->next) { + if (new->output[i_col] == ZERO || new->output[j_col] == ZERO) { + if ( (strcmp(new->pstate,arg_array[2]) == 0) || + (strcmp(new->pstate,arg_array[3]) == 0) || + (strcmp(new->pstate,"ANY") == 0) ) { + if (ISYMB) { + if ( (strcmp(new->input,arg_array[0]) == 0) || + (strcmp(new->input,arg_array[1]) == 0) ) { + INCOMPATIBLE = TRUE; + break; + } + } else { + if (inp_test(arg_array[0],arg_array[1],new->input) == 1) { + INCOMPATIBLE = TRUE; + break; + } + } + } + } + } + if (INCOMPATIBLE == TRUE) { + inco1_array[i][j] = 1; + inco1_array[j][i] = 1; + } + /*printf("%d %d %d\n", i, j, inco1_array[i][j]);*/ + } + } + for (i = 0; i < ones; i++) { + for (j = 0; j < ones; j++) { + printf("%d", inco1_array[i][j]); + } + printf("\n"); + } + + ones_color = coloring(ones,inco1_array); + + } + + zeroes = 0; + for (new = firstable; new != (INPUTTABLE *) 0; new = new->next) { + for (i = 0; i < strlen(new->output) -1; i++) { + if (new->output[i] == ZERO) { + zeroes++; + } + } + } + printf("\nIncompatibility graph (size = %d):\n", zeroes); + + if (zeroes >0) { + if ( (inco0_array = (int **) calloc((unsigned)zeroes,sizeof(int *))) == (int **) 0) { + fprintf(stderr,"Insufficient memory for 'inco0_array'"); + exit(-1); + } + for ( i = 0; i < zeroes; i++ ) { + if ( (inco0_array[i] = (int *) calloc((unsigned)zeroes,sizeof(int))) == (int *) 0) { + fprintf(stderr,"Insufficient memory for inco0_array[i]"); + exit(-1); + } + } + + for (i = 0; i < zeroes; i++) { + for (j = 0; j < zeroes; j++) { + inco0_array[i][j] = 0; + } + } + + for (i = 0; i < zeroes -1; i++) { + i_col = argument0(i,arg_array[0],arg_array[2]); + for (j = i+1; j < zeroes; j++) { + j_col = argument0(j,arg_array[1],arg_array[3]); + INCOMPATIBLE = FALSE; + for (new = firstable; new != (INPUTTABLE *) 0; new = new->next) { + if (new->output[i_col] == ONE || new->output[j_col] == ONE) { + if ( (strcmp(new->pstate,arg_array[2]) == 0) || + (strcmp(new->pstate,arg_array[3]) == 0) || + (strcmp(new->pstate,"ANY") == 0) ) { + if (ISYMB) { + if ( (strcmp(new->input,arg_array[0]) == 0) || + (strcmp(new->input,arg_array[1]) == 0) ) { + INCOMPATIBLE = TRUE; + break; + } + } else { + if (inp_test(arg_array[0],arg_array[1],new->input) == 1) { + INCOMPATIBLE = TRUE; + break; + } + } + } + } + } + if (INCOMPATIBLE == TRUE) { + inco0_array[i][j] = 1; + inco0_array[j][i] = 1; + } + /*printf("%d %d %d\n", i, j, inco0_array[i][j]);*/ + } + } + for (i = 0; i < zeroes; i++) { + for (j = 0; j < zeroes; j++) { + printf("%d", inco0_array[i][j]); + } + printf("\n"); + } + + zero_color = coloring(zeroes,inco0_array); + + } + + bound = max(ones_color,zero_color); + printf("\nLower bound on the # of product-terms = %d\n", bound); + +} + + + +int argument1(index,arg_array0,arg_array2) +int index; +char *arg_array0; +char *arg_array2; + +{ + + int i,i_count; + INPUTTABLE *new; + + i_count = -1; + for (new = firstable; new != (INPUTTABLE *) 0; new = new->next) { + for (i = 0; i < strlen(new->output) -1; i++) { + if (new->output[i] == ONE) { + i_count++; + } + if (index == i_count) { + strcpy(arg_array0,new->input); + strcpy(arg_array2,new->pstate); + /*printf("%s", arg_array0); + printf("%s\n", arg_array2);*/ + return(i); + } + } + } + + return(0); + +} + + + +int argument0(index,arg_array0,arg_array2) +int index; +char *arg_array0; +char *arg_array2; + +{ + + int i,i_count; + INPUTTABLE *new; + + i_count = -1; + for (new = firstable; new != (INPUTTABLE *) 0; new = new->next) { + for (i = 0; i < strlen(new->output) -1; i++) { + if (new->output[i] == ZERO) { + i_count++; + } + if (index == i_count) { + strcpy(arg_array0,new->input); + strcpy(arg_array2,new->pstate); + /*printf("%s", arg_array0); + printf("%s\n", arg_array2);*/ + return(i); + } + } + } + + return(0); + +} + + + +inp_test(cube1,cube2,cube3) +char *cube1; +char *cube2; +char *cube3; + +{ + + int i,cube_length; + + cube_length = strlen(cube1); + for (i = 0; i < cube_length; i++) { + if (cube1[i] != '-' || cube2[i] != '-') { + if (cube1[i] == cube2[i] && cube1[i] != cube3[i]) return(0); + } + } + return(1); + +} diff --git a/nova/nova.1 b/nova/nova.1 new file mode 100644 index 0000000..a40bbd3 --- /dev/null +++ b/nova/nova.1 @@ -0,0 +1,341 @@ +.TH NOVA 1CAD "12 August 1991" +.SH NAME +nova \- State Assignment Program for PLA-based Finite-State Machines +.SH SYNOPSIS +.B nova +[\fIoptions\fR] [\fIfile\fR] +.SH DESCRIPTION +\fInova\fR is a program that performs an optimal assignment of binary codes to +the states of a Finite State Machine (FSM). +The primary goal is to optimize the silicon area occupied by the finite +state machine after two-level optimization using ESPRESSO(1). +The program minimizes the number of product terms needed to implement +the encoded finite state machine, for a given code length. +Different encoding algorithms are available in \fInova\fR. +They are based on a FSM symbolic minimization step that produces encoding +constraints and an encoding step that produces codes +satisfying some or all of the encoding constraints, +for a fixed or free code-length. +The user specifies which algorithm should be invoked with the +option \fB-e\fR and related arguments, according to the +format explained below. +By default the algorithm \fB-e ig\fR is invoked. +The user may specify a code length with the options \fB-i\fR for +symbolic inputs and \fB-s\fR for states, otherwise by default +the minimum code-length is assumed. +\fInova\fR reads the file provided (or standard input if no files +are specified), performs the state assignment, and returns by default +a big blif format to standard output (see SIS(1)). +When invoked as a stand-alone program, \fInova\fR outputs also +the best coded minimized two-level implementation of the FSM, if the option +\fB-t\fR is specified. +.SH KEYWORDS +The following keywords embedded in the input are understood by \fInova\fR. +The keyword lines start with ".". +Keywords not understood by the program are ignored. +.TP +.B .symbolic input +Inputs are considered as symbolic strings +and an optimal assignment of binary vectors to each symbolic input +is also performed. +.SH OPTIONS +A complete list of the command line options is given below. +Be warned that some of the command line options are not intended for +general use. +[d] denotes a decimal number and [s] denotes a text string. +.TP +.B -e ig [-pr] +The encoding is driven only by input constraints. +Input constraints are computed by heuristic multiple-valued minimization +and satisfied by an heuristic greedy algorithm. Very fast, suboptimal. +If \fB-p\fR is specified, some input constraints unlikely to be +satisfied by a short code are pruned. +If \fB-r\fR is specified, all the rotations of the codes are tried. +.TP +.B -e ih [-r] +The encoding is driven only by input constraints. +Input constraints are computed by heuristic multiple-valued minimization +and satisfied by an heuristic algorithm based on limited backtracking. +It produces on average very good results. +It has the best trade-off between quality of results versus computing +time. +If \fB-r\fR is specified, all the rotations of the codes are tried. +.TP +.B -e ioh [-jry] +The encoding is driven by input and output (dominance) constraints. +Input and output constraints are computed by a version of symbolic minimization +and satisfied by an heuristic algorithm based on limited backtracking. +More computationally expensive than the previous one. It gives +often better results. +If \fB-j\fR is specified, all output constraints are kept, while by +default the algorithm prunes those which don't guarantee a gain. +If \fB-y\fR is specified, only output constraints are satisfied. +If \fB-r\fR is specified, all the rotations of the codes are tried. +.TP +.B -e iov [-jry] +Variation of the previous encoding strategy. +In practice it works less effectively. +.TP +.B -e ie [-br] +The encoding is driven only by input constraints. +Input constraints are computed by heuristic multiple-valued minimization +and satisfied by an exact algorithm based on backtracking. +The minimum code length that allows the satisfaction of all input constraints +is found (the user cannot specify a code length). +It may be computationally unfeasible. +\fB-b\fR is a debug option. +If \fB-r\fR is specified, all the rotations of the codes are tried. +.TP +.B -e ia [-c=[d]] [-m=[d]] [-br] +The encoding is driven only by input constraints. +Input constraints are computed by heuristic multiple-valued minimization +and satisfied by an algorithm based on simulated annealing. +\fB-c\fR specifies the cost function. It may assume values 0 or 1. +If the cost function is 0, the number of product terms is minimized. +If the cost function is 1, the number of literals after +\fIespresso\fR is minimized. +By default the cost function has value 0. +\fB-m\fR specifies the number of moves of simulated annealing at a given +temperature. It must be a positive integer. By default it has value 10. +\fB-b\fR is a debug option. +If \fB-r\fR is specified, all the rotations of the codes are tried. +.TP +.B -e h +Specifies 1-hot state assignment. In this case, the default two-level +minimization on the encoded finite state machine is not performed, +and the external don't care set is not computed. +As an example, the 1-hot codes when there are four states are +1---, -1--, --1- and ---1. +.TP +.B -e r [-n=[d]] +Random encodings are tried. +The user can specify how many trials by the option \fB-n\fR, +otherwise the following default values hold: #states if the proper inputs are +not symbolic, #states + #inputs if the proper inputs are symbolic. +The best result is kept. +.TP +.B -e u +The user supplies in the input file \fIfile.codes\fR the codes for the states +(and inputs, if symbolic), as suggested in the example #2 of the input file +format section. +\fInova\fR +substitutes the codes in the fsm and minimizes it. +.TP +.B -e lb +Computes a lower bound on the number of product terms needed to implement +the finite state machine. The lower bound is tight, i.e. there are examples +where it can be matched by the encoding found by \fInova\fR, but on the +average there is a large gap between the lower and upper bounds. +It can be computationally very expensive. +Use only when \fInova\fR is invoked as a stand-alone program. +.TP +.B -h[elp] +Outputs a summary of the command-line options. +.TP +.B -i =[d] +Specifies the code length of the symbolic inputs. +The default value of \fInova\fR is the shortest code that allows an injective +coding. +.TP +.B -s =[d] +Specifies the code length of the states. +The default value of \fInova\fR is the shortest code that allows an injective +coding. +.TP +.B -z =[s] +Specifies the state whose code has to be set to zero. +By default the program chooses which state to assign the zero code. +.TP +.B -b +Will produce a debug trace. Active only with \fB-e ie\fR and \fB-e ia\fR. +Use only when \fInova\fR is invoked as a stand-alone program. +.TP +.B -t +Outputs the coded minimized two-level implementation of the FSM. +Use only when \fInova\fR is invoked as a stand-alone program. +.TP +.B -v +Will produce a trace showing the execution of the program. +Use only when \fInova\fR is invoked as a stand-alone program. +.TP +.B -a +Analyzes the two-level realization after encoding. +Not yet available. +.TP +.B -d +Obtains generalized input constraints, i.e. input constraints +with don't-care entries. +Not yet available. +.sp 2 +.SH "INPUT FILE FORMAT" +The FSM is described by a symbolic cover. +A symbolic cover is a set of symbolic implicants +consisting of four fields +corresponding to the FSM inputs, present-states, next-states +and outputs respectively. The fields are separated by either blanks +or tabs, and all four fields must fit on a single line. +To allow comments within the input file, +any characters after a pound sign ('#') are ignored. +.PP +The FSM states are represented by strings of characters +(at most 30 characters). Either the present-state or the next-state may +be given as \fB\ANY\fR to indicate that the state is +a \fIdon't care\fR. +(This is useful, for example, in describing the reset logic for the FSM.) +.PP +The inputs to the FSM are represented by a string of characters of +\fB0\fR, \fB1\fR, and \fB\-\fR +(where \fB\-\fR indicates the symbolic implicant does not +depend on the corresponding input). The inputs may also be treated as +symbolic inputs (analogous to the way that the present-state is a symbolic +input), and \fInova\fR will determine an optimal assignment for the inputs as +well (see below). +.PP +The outputs from the FSM are also given as a string of characters from the +set \fB0\fR, \fB1\fR, and \fB\-\fR. +A \fB0\fR or a \fB1\fR indicates that the output must be +either low or high (respectively) for this transition. A \fB\-\fR indicates +that, for this transition, the output may be either low or high. +.PP +The meaning of the first symbolic implicant in the first example below above +is "when input input_1 is +asserted , proceed from state +state_1 to state state_3 with the first, second, third and fifth outputs low, +and the fourth output high". Note that the symbolic implicants +are in one-to-one correspondence +with the edges in a state-diagram representation of the FSM. +.SH "EXAMPLE #1" +This example shows the description of a finite state machine. +.nf + .symbolic input + input_1 state_1 state_3 00010 + input_1 state_2 state_1 01001 + input_1 state_3 state_3 10010 + input_1 state_4 state_3 00010 + input_1 state_5 state_1 01001 + input_1 state_6 state_1 01001 + + input_2 state_2 state_2 01001 + input_2 state_5 state_2 01001 + input_2 state_6 state_2 01001 + input_2 state_1 state_4 00010 + input_2 state_3 state_4 10010 + input_2 state_4 state_4 00010 + ... + input_6 state_2 state_1 00101 + input_6 state_5 state_1 00101 + input_6 state_1 state_5 00010 + input_6 state_3 state_5 10010 + input_6 state_4 state_5 00010 + input_6 state_6 state_5 10100 + .end +.fi +.SH "EXAMPLE #2" +This example shows how the user specifies its own codes in the additional +file \fIfile.codes\fR, when the option +\fB-e u\fR is active. +When the code-lenghts are not the default ones (shortest ones), the options +\fB-i\fR and +\fB-s\fR should be specified in the command line, +as it happens when \fInova\fR finds an encoding. +The token words \fIicode\fR and \fIscode\fR introduce, +respectively, a code and the symbolic input to which it is assigned +or a code and the state to which it is assigned. +.nf +icode 0000 input_5 +icode 0001 input_6 +icode 0100 input_1 +icode 0101 input_2 +icode 0110 input_3 +icode 0111 input_4 +scode 1000 state_6 +scode 1001 state_7 +scode 1111 state_1 +scode 0010 state_2 +scode 1101 state_3 +scode 1011 state_4 +scode 0000 state_5 +.fi +.sp 2 +.SH "STANDARD OUTPUT FORMAT" +By default a big blif format is written to standard output. +When the option +.B -t +is specified, also the coded minimized two-level implementation of the FSM +is written to standard output +(to use only when \fInova\fR is invoked as a stand-alone program). +The option +.B -v +will produce a trace showing the execution of the program. +.sp 2 +.SH DIAGNOSTICS +A message like follows (rarely issued and only when the option \fB-e ig\fR +is active) warns only that the detection +of the lattice intersections has been stopped after a quite large number +of them has been computed . +No action needs to be taken . + Message fac-simile : + WARNING + "After that lattice added the 1001-th new constraint , +Nova stopped executing lattice and went ahead with the +constraints that lattice already got" . +.PP +When running in the \fB-e ie\fR mode, \fInova\fR might issue a message warning +that in the worst-case too many configurations should be examined before finding +an exact solution and then it exits. Although it would have been +possible to let the program run for as long as needed, it exits +because an exact solution appears computationally unfeasible. +.sp 2 +.SH "SEE ALSO" +espresso(1CAD), kiss(1CAD), mis(1CAD), sis(1CAD) +.LP +T.Villa, A.Sangiovanni-Vincentelli, +"NOVA: state assignment of finite-state machines for optimal +two-level logic implementations", \fI IEEE Trans. on Computer-Aided Design \fR, +September 1990 +.sp 2 +.SH "AUTHOR" +Tiziano Villa (villa@ic.berkeley.edu) +.sp +.SH COMMENTS +In a given state, if symbolic implicants are not specified for all possible +input conditions, then the state machine response for the unspecified +conditions is undefined. In particular, \fInova\fR will use this +to its advantage when assigning the state codes. +It is possible to see all of the don't cares created in this way +by using the \fB-out fd\fR option when the +PLA is minimized with \fIespresso\fR. +.PP +Temporary files with unique names are created in the current working directory +during the run +of the program. They are removed at the end. +At the end of a run, \fInova\fR creates two files: \fIfile.esp\fR stores +the best coded minimized pla implementation, \fIfile.summ\fR +stores the face and output constraints (if any) and the final codes. +\fIfile.esp\fR is in PLA(1) format, suitable for input to ESPRESSO(1) +or MIS(1). +Terminal names, when provided by the user, are retained. +.PP +Only a single symbolic input (besides the present state) is allowed. +The ability to specify any number of symbolic inputs along with +binary inputs would be much more practical. +.PP +\fInova\fR invokes the multiple-valued minimization program +\fIespresso\fR (1CAD). +.PP +\fInova\fR is written in C. +There are no limitations on the number +of binary or symbolic inputs, binary outputs, states, or +symbolic implicants. +.PP +\fI(implementatio) nova\fR comes from latin and means \fIa new +(implementation)\fR. +No connection to astronomical objects is implied. +.sp +.SH BUGS +It is possible to specify logically inconsistent finite state machines +(i.e., to specify two transitions +for the same set of inputs in a single state) +and this should be, but is not, detected as an error. +.PP +Keywords not understood by the program are ignored. diff --git a/nova/nova.c b/nova/nova.c new file mode 100644 index 0000000..ec737da --- /dev/null +++ b/nova/nova.c @@ -0,0 +1,673 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/nova.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +#include "nova.h" +#include "decls.h" + +/************************************************************************ +* * +* MAIN OF NOVA * +* * +* ENCODING OF FINITE STATE MACHINES REPRESENTED IN STRUCTURAL FORM * +* * +* TIZIANO VILLA * +* UC BERKELEY - DEPT. OF ELECTRICAL ENGINEERING AND COMPUTER SCIENCES * +* * +* VERSION 3.2 - January 1990 * +************************************************************************/ + + +main(argc,argv) +int argc; /* number of command-lines arguments the program was invoked with */ +char *argv[]; /* pointer to an array of character strings that contain the arguments , one per string */ + +{ + + + int infile; + char command[MAXSTRING]; + long elapse_time; + + set_flags(); + + infile = options(argc,argv); + + input_fsm(infile); + + if (!L_BOUND && !USER && !I_EXACT && !I_HYBRID && !IO_HYBRID && + !IO_VARIANT && !I_GREEDY && !RANDOM && !ONEHOT && !I_ANNEAL) { + I_GREEDY = TRUE; + } + + if (L_BOUND) { /* computes a lower bound on the # of product-terms + needed to realize the fsm */ + lower_bound(); + elapse_time = util_cpu_time(); + if (VERBOSE) printf("#\n# \nCPU time = %2.1f seconds\n", elapse_time / 1000.0); + exit(-1); + } + + mini(); + + if (USER) { /* substitute user-given codes and analize performance */ + user_codes(); + } + + if (ONEHOT) { /* substitute one-hot codes and analize performance */ + onehot_codes(); + } + + if (I_EXACT) { /* use exact encoding algorithm */ + + if (ISYMB) { + if (VERBOSE) + printf("\n\nSYMBOLIC INPUTS CODING WITH EXACT ALGORITHM\n\n"); + + exact_graph(&inputnet,inputnum); + + exact_code(inputnum); + + exact_check(&inputnet,inputs,inputnum); + + } + + if (VERBOSE) + printf("\n\nSTATES CODING WITH EXACT ALGORITHM\n\n"); + + exact_graph(&statenet,statenum); + + exact_code(statenum); + + exact_check(&statenet,states,statenum); + + + exact_rotation(); + + exact_output(); + + } + + if (I_HYBRID) { + + if (ISYMB) { + if (VERBOSE) + printf("\n\nSYMBOLIC INPUTS CODING WITH I_HYBRID ALGORITHM\n\n"); + + ihybrid_code(&inputnet,inputs,"Inputnet",inputnum,inp_codelength); + } + + if (VERBOSE) printf("\n\nSTATES CODING WITH I_HYBRID ALGORITHM\n\n"); + + ihybrid_code(&statenet,states,"Statenet",statenum,st_codelength); + } + + if (IO_HYBRID) { + + symbolic_loop(); + + if (ISYMB) { + if (VERBOSE) + printf("\n\nSYMBOLIC INPUTS CODING WITH IO_HYBRID ALGORITHM\n\n"); + + ihybrid_code(&inputnet,inputs,"Inputnet",inputnum,inp_codelength); + } + + if (VERBOSE) printf("\n\nSTATES CODING WITH IO_HYBRID ALGORITHM\n\n"); + + iohybrid_code(&statenet,states,"Statenet",statenum,st_codelength); + + sprintf(command, "rm %s %s %s %s %s %s %s %s", temp6, temp7, temp81, temp82, temp83, temp9, temp10, constraints); + system(command); + } + + if (IO_VARIANT) { + + symbolic_loop(); + + if (ISYMB) { + if (VERBOSE) + printf("\n\nSYMBOLIC INPUTS CODING WITH IO_VARIANT ALGORITHM\n\n"); + + ihybrid_code(&inputnet,inputs,"Inputnet",inputnum,inp_codelength); + } + + if (VERBOSE) printf("\n\nSTATES CODING WITH IO_VARIANT ALGORITHM\n\n"); + + iovariant_code(&statenet,states,"Statenet",statenum,st_codelength); + + sprintf(command, "rm %s %s %s %s %s %s %s %s", temp6, temp7, temp81, temp82, temp83, temp9, temp10, constraints); + system(command); + } + + if (I_GREEDY) { /* use greedy encoding algorithm */ + + if (ISYMB) { + if (VERBOSE) + printf("\n\nSYMBOLIC INPUTS CODING WITH I_GREEDY ALGORITHM\n\n"); + + precode(&inputnet); + + link_constr(inputnet,inputs,inputnum); + + log_approx(inputnet,inputs,inputnum,inp_codelength); + + } + + + if (VERBOSE) printf("\n\nSTATES CODING WITH I_GREEDY ALGORITHM\n\n"); + + precode(&statenet); + + link_constr(statenet,states,statenum); + + log_approx(statenet,states,statenum,st_codelength); + + + rotation(); + + log_output(); + + } + + if (I_ANNEAL) { + if (VERBOSE) { + printf("\nSIM ANNEAL: cost = %d, ", cost_function); + printf("moves = %d\n", num_moves); + } + + if (ISYMB) { + if (VERBOSE) + printf("\n\nSYMBOLIC INPUTS CODING WITH SIM ANNEAL ALGORITHM\n\n"); + anneal_code(inputnet,inputs,inputnum,inp_codelength); + if (VERBOSE) show_bestcode(inputs,inputnum); + save_in_code(inputs,inputnum); + } + + if (VERBOSE) printf("\n\nSTATES CODING WITH SIM ANNEAL ALGORITHM\n\n"); + anneal_code(statenet,states,statenum,st_codelength); + if (VERBOSE) { + printf("\n\nCodes returned by sim.-anneal.:\n"); + show_bestcode(states,statenum); + } + save_in_code(states,statenum); + + rotation(); + log_output(); + + } + + if (RANDOM) randomization(); + + add_terminals(); /* temp5 copied to esp here */ + if (!ONEHOT) { + /* temp33 contains the best unminimized cover - + input of previous version was temp3 my mistake - july 1994 */ + sprintf(command, "sis -o %s -t pla -T blif %s", dc, temp33); + system(command); + } else { + read_script(esp); + sprintf(command, "sis -f %s -o %s -t pla -T blif %s", readscript, dc, esp); + system(command); + sprintf(command, "rm %s", readscript); system(command); + /* or replace esp by temp3 in the else clause */ + } + sprintf(command, "rm %s %s %s %s %s %s", temp1, temp2, temp3, temp33, temp4, temp5); + system(command); + + if (!SIS) nova_summ(); + + if (ANALYSIS) ; + + if (SIS) { + printf("#\n# .start_network\n"); + if (!ONEHOT) { + sprintf(command, "sis -o %s -t pla -T blif %s", blif, esp); + system(command); + } else { + sprintf(command, "cp %s %s", dc, blif); system(command); + /* or call sis to get blif from esp as in the above else clause */ + } + nova_blif(); + sprintf(command, "rm %s %s", dc, blif); system(command); + printf("# .end_network\n"); + } + if (PLA_OUTPUT) { + sprintf(command, "cat %s", esp); system(command); + } + sprintf(command, "rm %s", esp); system(command); + + elapse_time = util_cpu_time(); + printf("#\n# CPU time = %2.1f seconds\n", elapse_time / 1000.0); + + exit(0); + +} + + + +/****************************************************************************** +* Initialization of global variables * +******************************************************************************/ + +set_flags() + +{ + + LIST = TRUE; + DEBUG = FALSE; + NAMES = FALSE; + ISYMB = FALSE; + OSYMB = FALSE; + SHORT = TRUE; + PRTALL = FALSE; + TYPEFR = TRUE; + IBITS_DEF = TRUE; + SBITS_DEF = TRUE; + DCARE = FALSE; + L_BOUND = FALSE; + RANDOM = FALSE; + USER = FALSE; + ONEHOT = FALSE; + I_ANNEAL = FALSE; + ANALYSIS = FALSE; + I_GREEDY = FALSE; + I_HYBRID = FALSE; + IO_HYBRID = FALSE; + IO_VARIANT = FALSE; + I_EXACT = FALSE; + COMPLEMENT = FALSE; + POW2CONSTR = FALSE; + OUT_ALL = FALSE; + OUT_ONLY = FALSE; + ZERO_FL = FALSE; + INIT_FLAG = FALSE; + ILB = FALSE; + OB = FALSE; + SIS = TRUE; + VERBOSE = FALSE; + PLA_OUTPUT = FALSE; + + cost_function = 0; + num_moves = 10; + rand_trials = -1; + +} + + + +/******************************************************************************* +* Routine for dealing with processor time reporting * +*******************************************************************************/ + +#include + +/* + p_time -- return a floating point number which represents the + elapsed processor time in seconds since the program started +*/ + +double p_time() + +{ + struct tms buffer; + double time; + + times(&buffer); + time = (buffer.tms_utime + buffer.tms_stime) / 60.0 ; + return( time ); +} + + + +temp_files() + +{ + + sprintf(temp1, "%s.temp1", file_name); + sprintf(temp2, "%s.temp2", file_name); + sprintf(temp3, "%s.temp3", file_name); + sprintf(temp33, "%s.temp33", file_name); + sprintf(temp4, "%s.temp4", file_name); + sprintf(temp5, "%s.temp5", file_name); + sprintf(temp6, "%s.temp6", file_name); + sprintf(temp7, "%s.temp7", file_name); + sprintf(temp81, "%s.temp81", file_name); + sprintf(temp82, "%s.temp82", file_name); + sprintf(temp83, "%s.temp83", file_name); + sprintf(temp9, "%s.temp9", file_name); + sprintf(temp10, "%s.temp10", file_name); + sprintf(constraints, "%s.constraints", file_name); + sprintf(summ, "%s.summ", file_name); + sprintf(esp, "%s.esp", file_name); + sprintf(readscript, "%s.readscript", file_name); + sprintf(dc, "%s.dc", file_name); + sprintf(blif, "%s.blif", file_name); + +} + + + +add_terminals() + +{ + + FILE *sfile,*dfile,*fopen(); + char line[MAXSTRING],linex[MAXSTRING],linexx[MAXSTRING]; + int i,len; + + line[0] = '\0'; linex[0] = '\0'; linexx[0] = '\0'; + + if ((sfile = fopen(temp5,"r")) == NULL) { + fprintf(stderr,"Error in opening temp5 in add_terminals\n"); + exit(-1); + } else { + if ((dfile = fopen(esp,"w")) == NULL) { + fprintf(stderr,"Error in opening esp in add_terminals\n"); + exit(-1); + } else { + while (fgets(line,sizeof(line),sfile)) { + fputs(line,dfile); + if (myindex(line,".p ") >= 0) { + if (ILB) { + len = strlen(input_names); + /* notice: I copy len-1 chars because of char newline */ + strncpy(line,input_names,len-1); + line[len-1] = '\0'; + for (i = 0; i < st_codelength; i++) { + sprintf(linex," st%d*",i); + strcat(line,linex); + } + fputs(line,dfile); + fputs("\n",dfile); + } + if (OB) { + sprintf(line,".ob st%d*",0); + for (i = 1; i < st_codelength; i++) { + sprintf(linex," st%d*",i); + strcat(line,linex); + } + len = strlen(output_names); + /* notice: I copy len-1 chars because of char newline */ + for (i = 3; i < len-1; i++) + linexx[i-3] = output_names[i]; + linexx[len-4] = '\0'; + strcat(line,linexx); + fputs(line,dfile); + fputs("\n",dfile); + } + } + } + fclose(dfile); + } + fclose(sfile); + } + +} + + + +read_script(sfile) +char *sfile; + +{ + FILE *readscriptfile,*fopen(); + char string1[MAXSTRING]; + + if ((readscriptfile = fopen(readscript,"w")) == NULL) { + fprintf(stderr,"Error in opening readscript in read_script\n"); + exit(-1); + } else { + sprintf(string1,"read_pla -s %s\n", sfile); + fputs(string1, readscriptfile); + fclose(readscriptfile); + } + +} + + + +nova_blif() + +{ + + FILE *blifile,*sfile,*fopen(); + char line[MAXSTRING],i_line[MAXSTRING],idc_line[MAXSTRING],o_line[MAXSTRING], + s_line[2*MAXSTRING],l_line[MAXSTRING],w_line[2*MAXSTRING], + lorder_line[2*MAXSTRING],string[2]; + char *tokptr, *strptr; + int i,j,input_length,input_max,output_max; + BOOLEAN found=FALSE; + + if (!INIT_FLAG) strcpy(init_state,states[0].name); + /*printf("init_state = %s\n", init_state);*/ + + if (I_GREEDY || I_ANNEAL || RANDOM) { + for (i = 0; i < statenum; i++) { + if (strcmp(states[i].name,init_state) == 0) { + strcpy(init_code,states[i].best_code); + break; + } + } + } + if (I_EXACT || I_HYBRID || IO_HYBRID || IO_VARIANT || ONEHOT || USER) { + for (i = 0; i < statenum; i++) { + if (strcmp(states[i].name,init_state) == 0) { + strcpy(init_code,states[i].exbest_code); + break; + } + } + } + if (ONEHOT) { + for (i = 0; i < statenum; i++) { + if (init_code[i] == DASH) init_code[i] = ZERO; + } + } + /*printf("init_code = %s\n", init_code);*/ + line[0] = '\0'; i_line[0] = '\0'; idc_line[0] = '\0'; o_line[0] = '\0'; s_line[0] = '\0'; + l_line[0] = '\0'; lorder_line[0] = '\0'; + + if (ISYMB) { + input_length = inp_codelength; + } else { + input_length = inputfield; + } + input_max = 1+ input_length + st_codelength; + output_max = 1+ st_codelength + outputfield -1; + + if ((blifile = fopen(blif,"r")) == NULL) { + fprintf(stderr,"Error in opening blif in nova_blif\n"); + exit(-1); + } else { + while (fgets(line,sizeof(line),blifile)) { + + if (myindex(line,".inputs") >= 0) { + strptr = line; + i = 1; + while ( (tokptr = strtok(strptr," ")) != (char *) 0 ) { + if ( strchr (tokptr,'\\') != (char *) 0 ) { + if (i <= input_length +1) { + strncat(i_line,tokptr,strlen(tokptr)-1); + printf("%s\n", i_line); + i_line[0] = '\0'; + } + fgets(line,sizeof(line),blifile); + strptr = line; + continue; + } + if (i == 1) { + strcat(i_line,tokptr); + strcat(i_line," "); + } + if (i > 1 && i < input_length+1) { + strcat(i_line,tokptr); + strcat(i_line," "); + } + if (i == input_length +1) { + strcat(i_line,tokptr); + printf("%s\n", i_line); + } + if (i > input_length+1 && i < input_max) { + strcat(s_line,tokptr); + strcat(s_line," "); + } + if (i == input_max) { + strncat(s_line,tokptr,strlen(tokptr)-1); + strcat(s_line," "); + } + strptr = (char *) 0; + i++; + } + /* format input line for exdc network */ + /* notice: in a previous edition pi's were intentionally + left out of the .inputs line - and the comment was: + format input line for exdc network with no pi's - + it seems an obvious error of unclear motivation + (fixed in sept. 1993) */ + strcpy(idc_line, i_line); strcat(idc_line," "); strcat(idc_line, s_line); + strcat(idc_line, "\n"); + /*printf("%s\n", s_line);*/ + } + + else if (myindex(line,".outputs") >= 0) { + strptr = line; + i = 1; + while ( (tokptr = strtok(strptr," ")) != (char *) 0 ) { + if ( strchr (tokptr,'\\') != (char *) 0 ) { + if (i > st_codelength +1) { + strncat(o_line,tokptr,strlen(tokptr)-1); + printf("%s\n", o_line); + o_line[0] = '\0'; + } + fgets(line,sizeof(line),blifile); + strptr = line; + continue; + } + if (i == 1) { + strcat(o_line,tokptr); + strcat(o_line," "); + } + if (i > 1 && i < st_codelength+1) { + strcat(s_line,tokptr); + strcat(s_line," "); + } + if (i == st_codelength +1) { + strcat(s_line,tokptr); + } + if (i > st_codelength+1 && i < output_max) { + strcat(o_line,tokptr); + strcat(o_line," "); + } + if (i == output_max) { + strncat(o_line,tokptr,strlen(tokptr)-1); + printf("%s\n", o_line); + } + strptr = (char *) 0; + i++; + } + /*printf("%s\n", s_line);*/ + + strcpy(lorder_line,".latch_order"); + for (j = 1; j <= st_codelength; j++) { + strcpy(l_line,".latch"); + strcpy(w_line,s_line); + strptr = w_line; + i = 1; + while ( (tokptr = strtok(strptr," ")) != (char *) 0 ) { + if (i == st_codelength+j) { + strcat(l_line," "); + strcat(l_line,tokptr); + } + strptr = (char *) 0; + i++; + } + strcpy(w_line,s_line); + strptr = w_line; + i = 1; + while ( (tokptr = strtok(strptr," ")) != (char *) 0 ) { + if (i == j) { + strcat(l_line," "); + strcat(l_line,tokptr); + strcat(lorder_line," "); + strcat(lorder_line,tokptr); + } + strptr = (char *) 0; + i++; + } + strcat(l_line," "); + string[0] = init_code[j-1]; string[1] = '\0'; + strcat(l_line, string); + printf("%s\n", l_line); + } + printf("%s\n", lorder_line); + + } + + else if (myindex(line,".model") >= 0) { + /* skip the .model line because outputted at the start */ + } + + /* clause that outputs the dc set of the encoded fsm */ + else if ((!ONEHOT && myindex(line,".end") >= 0) || + (ONEHOT && myindex(line,".exdc") >= 0)) { + if ((sfile = fopen(dc,"r")) == NULL) { + fprintf(stderr,"Error in opening dc in nova_blif\n"); + exit(-1); + } else { + while (fgets(line,sizeof(line),sfile)) { + /* the external dc net starts here */ + if (myindex(line,".exdc") >= 0) { + found = TRUE; + } + if (found == TRUE) { + /* hack to avoid printing 1 empty line after .end */ + if (myindex(line,".end") >= 0) { + printf("%s", line); + break; + } + /* don't output .model twice and output idc_line as input + line (has no pi's) instead than current input line */ + if ( (myindex(line,".model") < 0) + && (myindex(line,".inputs") < 0) ) printf("%s", line); + if (myindex(line,".inputs") >= 0) printf("%s", idc_line); + } + } + fclose(sfile); + } + fclose(blifile); + return; + } + + else printf("%s", line); + + } + fclose(blifile); + } + +} + + + +getname(name) +char *name; + +{ + + int i; + + i = 0; + while(name[i] != '\0') { + if (name[i] != '.') { + sh_filename[i] = name[i]; + } else break; + i++; + } + sh_filename[i] = '\0'; + /*printf("sh_filename = %s\n", sh_filename);*/ + +} diff --git a/nova/nova.h b/nova/nova.h new file mode 100644 index 0000000..92ac461 --- /dev/null +++ b/nova/nova.h @@ -0,0 +1,437 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/nova.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:09 $ + * + */ +#include "port.h" + +#define BOOLEAN int +#define TRUE 1 +#define FALSE 0 +#define ONE '1' +#define ZERO '0' +#define DASH '-' +#define ANYSTATE "ANY" +#define DCLABEL -1 + +#define MAXLINE 1026 +#define MAXSTRING 1026 +#define MAXWORK 20000 + +#define is == +#define isnt != +#define max(a,b) (a >b) ? a : b +#define free_mem(ptr) if (ptr != NULL) free(ptr) + + +extern int cost_function,num_moves; + +/* data structure representing the input machine symbolic table */ + +typedef struct inputtable { + + char *input; + int ilab; + char *pstate; + int plab; + char *nstate; + int nlab; + char *output; + int olab; + int acc; + struct inputtable *next; + +} INPUTTABLE; + + +/* data structure representing a constraint among a group of symblemes ( symbolic elements ) */ + +/* range of "attribute" in data structure "constraint" */ +#define NOTUSED 0 /* constraint not already used */ +#define PRUNED 1 /* constraint pruned away */ +#define USED 2 /* constraint already used in the encoding */ +#define TRIED 3 /* constraint being tried in the encoding */ + +/* range of "odd_type" in data structure "constraint" */ +#define ADMITTED 0 /* not-a-power-of-two constraint kept in the lattice */ +#define NOTADMITTED 1 /* otherwise */ +#define EXAMINED 2 /* not-a-power-of-two-constraint that failed the test + to be kept in the lattice since it needed too many + free positions */ + +/* range of "source_type" in data structure "constraint" */ +#define INPUT 0 /* constraint obtained from the input structure */ +#define OUTPUT 1 /* constraint obtained from the output structure */ +#define MIXED 2 /* constraint obtained from both the input and output + structure */ + + +typedef struct constraint { + + char *relation; /* relation[i] == '1' iff the i-th symbleme belongs to this constraint */ + char *face; /* face corresponding to this constraint */ + char *next_states; /* next-states associated to this constraint */ + int weight; /* number of times this constraint appears in the constraint list */ + int level; /* depth in the intersection chain */ + int newlevel; /* temporary depth (implementation convenience) */ + int card; /* # of symblemes in the constraint */ + int attribute; /* NOTUSED USED PRUNED TRIED */ + int odd_type; /* ADMITTED NOTADMITTED EXAMINED */ + int source_type; /* INPUT OUTPUT MIXED */ + struct constraint *levelnext; /* pointer to the next constraint at the + same level */ + struct constraint *cardnext; /* pointer to the next constraint with the same card */ + struct constraint *next; /* pointer to the next constraint in the + global list */ + +} CONSTRAINT; + + +/* data structure linking all constraints involving a certain symbleme */ + +typedef struct constrlink { + + CONSTRAINT *constraint; + struct constrlink *next; + +} CONSTRLINK; + + +/* data structure representing binary codes */ + +typedef struct code { + + char *value; /* the code in binary form */ + struct code *next; + +} CODE; + + +/* data structure representing the symbolic elements ( i.e. symbolic inputs, outputs , states , called here collectively "symblemes" ) to be encoded */ + +/* range of "code_status" in data structure "symbleme" */ +#define NOTCODED 0 /* symbleme with no code already assigned */ +#define TEMPORARY 1 /* symbleme with a temporary code assigned */ +#define FIXED 2 /* symbleme with a definitive code assigned */ + +typedef struct symbleme { + + CONSTRLINK *constraints; /* list of the constraints involving this + symbleme */ + CODE *vertices;/* list of codes temporarily assigned to this symbleme */ + char *code; /* definitive code */ + char *name; /* name of the symbleme */ + int code_status; /* status of the code currently assigned to + this symbleme */ + char *best_code; /* best definitive code obtained up to now */ + char *exact_code; /* exact code */ + char *exbest_code; /* best exact code */ + +} SYMBLEME; + +/* data structure representing the vertices of an hypercube */ + +typedef struct hypervertex { + + char *code; /* boolean code of this hypervertex */ + BOOLEAN ass_status; /* true iff this code has been assigned in a + definitive way */ + int label; + +} HYPERVERTEX; + + +/* GLOBAL VARIABLES */ + +extern CONSTRAINT *inputnet; /* net of the constraints on the input symblemes */ +extern CONSTRAINT *statenet; /* net of the constraints on the state symblemes */ +extern CONSTRAINT *outputnet; /* net of the constraints on the output symblemes */ + +extern SYMBLEME *inputs; /* array of inputs symblemes descriptors */ +extern SYMBLEME *states; /* array of states symblemes descriptors */ +extern SYMBLEME *outputs; /* array of outputs symblemes descriptors */ + +extern CONSTRAINT **levelarray; /* array of pointers to the constraints with the same level */ +extern CONSTRAINT **cardarray; /* array of pointers to the constraints with the same cardinality */ + +extern HYPERVERTEX *hypervertices; /* array of vertices on the hypercube and related information */ + +extern INPUTTABLE *firstable; /* pointer to the beginning of the input table */ +extern INPUTTABLE *lastable; /* pointer to the last item of the input table */ + + +extern int *zeroutput; /* zeroutput[i] = n iff the i-th next-state symbleme appears + n times with an all zeroes proper output */ +extern int inputnum; /* number of inputs (if ISYMB) */ +extern int statenum; /* number of states */ +extern int outputnum; /* number of outputs (if OSYMB) */ +extern int inputfield; /* length of the input (when not symbolic) */ +extern int outputfield; /* length of the output (when not symbolic) */ + +extern int productnum; /* number of rows of the input table */ +extern int symblemenum; /* number of symblemes */ + +extern int st_codelength; /* number of bits used to encode the states */ +extern int inp_codelength; /* number of bits used to encode the inputs */ +extern int out_codelength; /* number of bits used to encode the outputs */ + +extern int onehot_products; /* number of product terms of the minimized + onehot cover */ +extern int min_inputs; /* number of inputs of the currently minimized + pla */ +extern int min_outputs; /* number of outputs of the currently minimized + pla */ +extern int min_products; /* number of product terms of the currently + minimized pla */ +extern int best_products; /* number of product terms of the minimum size + pla obtained so far */ +extern int worst_products; /* number of product terms of the maximum size + pla obtained so far */ + + +extern int first_size; /* size of the minimized pla after the default + encoding */ +extern int best_size; /* minimum size of the minimized pla obtained so + far */ +extern int rand_trials; /* number of required random codings */ +extern char zero_state[MAXSTRING]; /* user given state to code to zero */ +extern char init_state[MAXSTRING]; /* user given initial state */ +extern char init_code[MAXSTRING]; /* code assigned to the init. state */ +extern char file_name[MAXSTRING]; /* name of the input file */ +extern char sh_filename[MAXSTRING]; /* name of the input file */ +extern char temp1[MAXSTRING]; /* name of the temp1 file */ +extern char temp2[MAXSTRING]; /* name of the temp2 file */ +extern char temp3[MAXSTRING]; /* name of the temp3 file */ +extern char temp33[MAXSTRING]; /* name of the temp33 file */ +extern char temp4[MAXSTRING]; /* name of the temp4 file */ +extern char temp5[MAXSTRING]; /* name of the temp5 file */ +extern char temp6[MAXSTRING]; /* name of the temp6 file */ +extern char temp7[MAXSTRING]; /* name of the temp7 file */ +extern char temp81[MAXSTRING]; /* name of the temp81 file */ +extern char temp82[MAXSTRING]; /* name of the temp82 file */ +extern char temp83[MAXSTRING]; /* name of the temp83 file */ +extern char temp9[MAXSTRING]; /* name of the temp9 file */ +extern char temp10[MAXSTRING]; /* name of the temp10 file */ +extern char constraints[MAXSTRING]; /* name of the constraints file */ +extern char summ[MAXSTRING]; /* name of summary file */ +extern char esp[MAXSTRING]; /* name of the esp file */ +extern char readscript[MAXSTRING]; /* name of the readscript file */ +extern char dc[MAXSTRING]; /* name of the dc file */ +extern char blif[MAXSTRING]; /* name of the blif file */ +extern char input_names[MAXSTRING]; /* name of the input terminals */ +extern char output_names[MAXSTRING]; /* name of the output terminals */ + +/* boolean global flags True : False : */ +extern BOOLEAN LIST; /* echoes input file Nothing */ +extern BOOLEAN DEBUG; /* prints out debug info. Nothing */ +extern BOOLEAN ISYMB; /* inputs are symbolic boolean inputs */ +extern BOOLEAN OSYMB; /* outputs are symbolic boolean outputs */ +extern BOOLEAN SHORT; /* considers inputs only */ +extern BOOLEAN PRTALL; /* prints extended information */ +extern BOOLEAN TYPEFR; /* pla format - see Espresso manual */ +extern BOOLEAN DCARE; /* input constraints extracted with dcares */ +extern BOOLEAN POW2CONSTR; /* considers only constraints of cardinality + power of two */ +extern BOOLEAN I_GREEDY; /* vertices-wise bottom-up constraint-clustered + (loglength) heuristic encoding algorithm */ +extern BOOLEAN I_ANNEAL; /* sim.anneal-based encoding algorithm */ +extern BOOLEAN USER; /* the fsm is encoded by the user */ +extern BOOLEAN ONEHOT; /* the fsm is 1-hot encoded */ +extern BOOLEAN COMPLEMENT; /* complements in turn each column of the + otherwise maximizes implicants with empty + output */ +extern BOOLEAN ZERO_FL; /* TRUE iff user gives state to code zero */ +extern BOOLEAN INIT_FLAG; /* TRUE iff user gives initial state */ +extern BOOLEAN RANDOM; /* compares the result with random codings */ +extern BOOLEAN IBITS_DEF; /* TRUE iff code_length of inputs = + log2(minpow2(inputnum)) */ + +extern BOOLEAN SBITS_DEF; /* TRUE iff code_length of states = + log2(minpow2(statenum)) */ +extern BOOLEAN ILB; /* TRUE iff input terminals are given */ +extern BOOLEAN OB; /* TRUE iff output terminals are given */ +extern BOOLEAN ANALYSIS; /* analysis of the current encoding required */ +extern BOOLEAN PLA_OUTPUT; /* if TRUE output two-level minimized fsm */ + + + +/* **************************************************************************** +***************** ADDITION RELATED TO THE EXACT ALGORITHM ******************** +***************************************************************************** */ + +extern BOOLEAN I_EXACT; /* exact encoding algorithm */ +extern BOOLEAN NAMES; /* symbols are assigned names by the user */ +extern BOOLEAN SEL_CAT1; /* true if last call to next_to_code selected + a constraint of category 1 */ +extern int graph_depth; /* depth of graph_levels */ +extern int cart_prod; /* cardinality of the upper level search tree */ +extern int bktup_count; /* index in the upper level search tree */ +extern int bktup_calls; /* number of face configurations tried in all */ +extern int cube_work; /* number of codes tried in the current cube */ +extern int total_work; /* number of codes tried by exact_code in all */ + +typedef struct constraint_e { + + int weight; + int card; + int have_father; /* = 1 (otherwise = 0) iff a father of this constraint + at exactly one level above was already found (set + in "link_graph") */ + char *relation; /* relation[i] == '1' iff the i-th symbleme belongs to + this constraint */ + struct constraint_e *next; /* pointer to the next constraint at the same + level */ + struct fathers_link *up_ptr; /* pointer to the list of the constraints + that include this one */ + struct sons_link *down_ptr; /* pointer to the list of the constraints + that are included by this one */ + struct face *face_ptr; /* pointer to the list of faces assigned to this + constraint by "x_code" - the first of the list + is the face currently assigned */ + +} CONSTRAINT_E; + +/* links all constraints including a certain one */ +typedef struct fathers_link { + + CONSTRAINT_E *constraint_e; /* pointer to an including constraint */ + struct fathers_link *next; /* pointer to the next linker */ + +} FATHERS_LINK; + +/* links all constraints included in a certain one */ +typedef struct sons_link { + + CONSTRAINT_E *constraint_e; /* pointer to an included constraint */ + CONSTRAINT_E *codfather_ptr; /* pointer to the father triggering the + coding of this son */ + struct sons_link *next; /* pointer to the next linker */ + +} SONS_LINK; + +/* links the (primary) constraints in encoding order */ +typedef struct codorder_link { + + CONSTRAINT_E *constraint_e; /* pointer to an included constraint */ + struct codorder_link *right; /* pointer to the right linker */ + struct codorder_link *left; /* pointer to the left linker */ + +} CODORDER_LINK; + +/* data structure representing binary codes */ +typedef struct face { + + char *seed_value; /* the seed code used for the constraint pointing + to this face */ + BOOLEAN seed_valid;/* TRUE iff current seed_value is valid */ + char *first_value; /* the first code tried for the constraint pointing + to this face */ + BOOLEAN first_valid;/* TRUE iff current first_value is valid */ + char *cur_value; /* the current code assigned to the constraint + pointing to this face */ + BOOLEAN code_valid;/* TRUE iff current cur_value is valid */ + int count_index; /* counting index of cur_value */ + int comb_index; /* combinations index of cur_value */ + int lexmap_index; /* lexicographical mapping index of cur_value */ + int dim_index; /* dimensional index of cur_value */ + int tried_codes; /* numbers of attempts to assign a code to the + constraint pointing to this face */ + int category; /* type of constraint in backtrack_up */ + int mindim_face; /* minimum face dimension given the cube dimension */ + int curdim_face; /* currently assigned dimension of the face */ + int maxdim_face; /* maximum face dimension given the cube dimension */ + +} FACE; + +extern CONSTRAINT_E **graph_levels; /* array of pointers to the constraints with + the same cardinality */ + + +/* **************************************************************************** +********* ADDITION RELATED TO THE I_HYBRID AND IO_HYBRID ALGORITHMS ********* +**************************************************************************** */ + +typedef struct implicant { + + char *row; /* product-term specification */ + int state; /* state which originated this product-term */ + int attribute; /* NOTUSED USED PRUNED */ + struct implicant *next; /* pointer to the next implicant in the list */ + +} IMPLICANT; + +extern IMPLICANT *implicant_list; /* list of the implicants found in + symbolic minimization */ +extern int *select_array; /* status of state selection in iohybrid */ + +extern int symbmin_products; /* upper bound of symbolic minimization */ + +extern BOOLEAN I_HYBRID; /* i_hybrid encoding algorithm */ +extern BOOLEAN IO_HYBRID; /* io_hybrid encoding algorithm */ +extern BOOLEAN IO_VARIANT; /* io_variant encoding algorithm */ +extern BOOLEAN OUT_ONLY; /* output only encoding algorithm */ +extern BOOLEAN OUT_VERIFY; /* verifies the output covering relations */ + +/* ************************************************************************* */ +/* DATA STRUCTURES USED FOR THE OUTPUT COVERING EXTENSION */ +/* ************************************************************************* */ + +extern BOOLEAN OUT_ALL; /* accepts all output covering relations - FALSE by + default, when we accept only if the gain of the + slice minimization is positive */ + +/* set of the admissable values of the output symbolic function ( next states +column ) */ +typedef struct outsymbol { + char *element; /* symbolic name of the next-state */ + int nlab; /* next-state label (same as given by label.c) */ + int card; /* cardinality of the set of prod.terms whose next- + state is the current one */ + int selected; /* = 1 iff already selected by select_oni() */ + struct outsymbol *next; +} OUTSYMBOL; + + +/* directed acyclic graph (given by row-lists indexed by an array of pointers) + representing the partial order on the set of values of the output symbolic + function */ +typedef struct order_relation { + int index; /* column index in the order_relation */ + struct order_relation *next; +} ORDER_RELATION; + +/* lists of the path-connected pairs of nodes of the partial order graph + (the starting vertex is given by the index of the array of pointers) */ +typedef struct order_path { + int dest; /* destination node in order_path (integer label) */ + struct order_path *next; +} ORDER_PATH; + + +extern int *reached; /* auxiliary array used in dfs */ +extern OUTSYMBOL *outsymbol_list; /* list of the next-state symbols */ +extern ORDER_RELATION **order_graph; /* array of pointers to the row-lists of + the partial order graph */ +extern ORDER_PATH **path_graph; /* array of pointers to the row-lists of + the graph of the paths */ +extern char **order_array; /* array of pointers to strings + representing output covering relations */ +extern int *gain_array; /* gain_array[i] = j iff covering state i + with the states of order_array[i] achieves a gain of j implicants */ + +/* ************************************************************************* */ +/* DATA STRUCTURES USED FOR THE LOWER BOUND */ +/* ************************************************************************* */ + +extern BOOLEAN L_BOUND; /* the fsm is encoded by the user */ + +/* ************************************************************************* */ +/* DATA STRUCTURES USED FOR SIS */ +/* ************************************************************************* */ + +extern BOOLEAN SIS; /* feature for the SIS version */ +extern BOOLEAN VERBOSE; /* verbose output statistics */ diff --git a/nova/nova_summ.c b/nova/nova_summ.c new file mode 100644 index 0000000..97fd3b7 --- /dev/null +++ b/nova/nova_summ.c @@ -0,0 +1,105 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/nova_summ.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +#include "nova.h" + +/******************************************************************************* +* WRITES THE CONSTRAINTS INTO EXTERNAL FILES * +*******************************************************************************/ + +nova_summ() + +{ + + FILE *fopen(),*fpcons; + CONSTRAINT *scanner; + int i,j; + + if ( (fpcons = fopen(summ,"w") ) == NULL ) { + fprintf(stderr,"fopen: can't create summ\n"); + exit(-1); + } + + if (I_GREEDY || I_EXACT || I_ANNEAL || I_HYBRID || IO_HYBRID || IO_VARIANT) { + /*fprintf(fpcons, "onehot_products = %d\n", onehot_products);*/ + } + + if (IO_HYBRID || IO_VARIANT) { + + /*fprintf(fpcons, "symbmin_products = %d\n", symbmin_products);*/ + + fprintf(fpcons, "# Cover (bit-wise covering relations among the codes of the states)\n"); + fprintf(fpcons, "# Cover(i,j) = 1 iff the i-th state must be covered by the j-th state\n"); + for ( i = 0; i < statenum; i++) { + for ( j = 0; j < statenum; j++) { + fprintf(fpcons, "%c", order_array[i][j]); + } + fprintf(fpcons, " wgt:%d", gain_array[i]); + fprintf(fpcons, "\n"); + } + fprintf(fpcons, "\n"); + + } + + if (I_GREEDY || I_EXACT || I_ANNEAL || I_HYBRID || IO_HYBRID || IO_VARIANT) { + + if (ISYMB) { + fprintf(fpcons, "# Face constraints of the symbolic inputs\n"); + for (scanner = inputnet; scanner != (CONSTRAINT *) 0; scanner = scanner->next) { + fprintf(fpcons, "%s wgt:%d\n", scanner->relation, scanner->weight); + } + } + fprintf(fpcons, "\n# Face constraints of the states\n"); + for (scanner = statenet; scanner != (CONSTRAINT *) 0; scanner = scanner->next) { + fprintf(fpcons, "%s wgt:%d nxst:%s\n", scanner->relation, scanner->weight, scanner->next_states); + } + + } + + if (I_GREEDY || RANDOM) { + + if (RANDOM) fprintf(fpcons, " RANDOM CODES\n"); + + if (ISYMB) { + fprintf(fpcons, "\nCODES OF THE SYMBOLIC INPUTS"); + for (i = 0; i < inputnum; i++) { + fprintf(fpcons, "\ninputs[%d]:%s ", i , inputs[i].name); + fprintf(fpcons, "Best code: %s", inputs[i].best_code); + } + } + fprintf(fpcons, "\n\nCODES OF THE STATES"); + for (i = 0; i < statenum; i++) { + fprintf(fpcons, "\nstates[%d]:%s ", i , states[i].name); + fprintf(fpcons, "Best code: %s", states[i].best_code); + } + fprintf(fpcons, "\n"); + + } + + if (I_EXACT || I_ANNEAL || I_HYBRID || IO_HYBRID || IO_VARIANT) { + + if (ISYMB) { + fprintf(fpcons, "\nCODES OF THE SYMBOLIC INPUTS"); + for (i = 0; i < inputnum; i++) { + fprintf(fpcons, "\ninputs[%d]:%s ", i , inputs[i].name); + fprintf(fpcons, "Best code: %s", inputs[i].exbest_code); + } + } + fprintf(fpcons, "\n\nCODES OF THE STATES"); + for (i = 0; i < statenum; i++) { + fprintf(fpcons, "\nstates[%d]:%s ", i , states[i].name); + fprintf(fpcons, "Best code: %s", states[i].exbest_code); + } + fprintf(fpcons, "\n"); + + } + + fclose(fpcons); + +} diff --git a/nova/oldport.h b/nova/oldport.h new file mode 100644 index 0000000..1a88623 --- /dev/null +++ b/nova/oldport.h @@ -0,0 +1,242 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/oldport.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/oldport.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +#ifndef PORT_H +#define PORT_H + +#ifdef SABER +#define volatile +#endif + +/* + * int32 should be defined as the most economical sized integer capable of + * holding a 32 bit quantity + * int16 should be similarly defined + */ + +/* XXX hack */ +#ifndef MACHDEP_INCLUDED +#define MACHDEP_INCLUDED +#ifdef vax +typedef int int32; +typedef short int16; +#else + /* Ansi-C promises that these definitions should always work */ +typedef long int32; +typedef int int16; +#endif /* vax */ +#endif /* MACHDEP_INCLUDED */ + + +#ifndef __STDC__ +#ifndef __DATE__ +#ifdef CUR_DATE +#define __DATE__ CUR_DATE +#else +#define __DATE__ "unknown-date" +#endif /* CUR_DATE */ +#endif /* __DATE__ */ + +#ifndef __TIME__ +#ifdef CUR_TIME +#define __TIME__ CUR_TIME +#else +#define __TIME__ "unknown-time" +#endif /* CUR_TIME */ +#endif /* __TIME__ */ +#endif /* __STDC__ */ + +#ifdef sun386 +#define PORTAR +#endif + +#include +#include +#include +#undef HUGE +#include +#include + +#if defined(ultrix) /* { */ +#if defined(_SIZE_T_) /* { */ +#define ultrix4 +#else /* } else { */ +#if defined(SIGLOST) /* { */ +#define ultrix3 +#else /* } else { */ +#define ultrix2 +#endif /* } */ +#endif /* } */ +#endif /* } */ + +#if defined(ultrix3) && defined(mips) +extern double rint(); +extern double trunc(); +#endif + +#if defined(sun) && defined(FD_SETSIZE) +#define sunos4 +#else +#define sunos3 +#endif + +#if defined(sequent) || defined(news800) +#define LACK_SYS5 +#endif + +#if defined(ultrix3) || defined(sunos4) +#define SIGNAL_FN void +#else +/* sequent, ultrix2, 4.3BSD (vax, hp), sunos3 */ +#define SIGNAL_FN int +#endif + +/* Some systems have 'fixed' certain functions which used to be int */ +#if defined(ultrix) || defined(SABER) || defined(__hpux) || defined(aiws) || defined(apollo) || defined(__STDC__) +#define VOID_HACK void +#else +#define VOID_HACK int +#endif + +#ifndef NULL +#define NULL 0 +#endif /* NULL */ + +/* + * CHARBITS should be defined only if the compiler lacks "unsigned char". + * It should be a mask, e.g. 0377 for an 8-bit machine. + */ + +#ifndef CHARBITS +# define UNSCHAR(c) ((unsigned char)(c)) +#else +# define UNSCHAR(c) ((c)&CHARBITS) +#endif + +#define SIZET int + +#ifdef __STDC__ +#define CONST const +#define VOIDSTAR void * +#else +#define CONST +#define VOIDSTAR char * +#endif /* __STDC__ */ + + +/* Some machines fail to define some functions in stdio.h */ +#ifndef __STDC__ +extern FILE *popen(), *tmpfile(); +extern int pclose(); +#ifndef clearerr /* is a macro on many machines, but not all */ +extern VOID_HACK clearerr(); +#endif /* clearerr */ +#ifndef rewind +extern VOID_HACK rewind(); +#endif /* rewind */ +#endif /* __STDC__ */ + + +/* most machines don't give us a header file for these */ +#ifdef __STDC__ +#include +#else +#ifdef __hpux +extern int abort(); +extern void free(), exit(), perror(); +#else +extern VOID_HACK abort(), free(), exit(), perror(); +#endif /* __hpux */ +extern char *getenv(), *malloc(), *realloc(), *calloc(); +#ifdef aiws +extern int sprintf(); +#else +extern char *sprintf(); +#endif +extern int system(); +extern double atof(); +extern long atol(); +extern int sscanf(); +#endif /* __STDC__ */ + + +/* some call it strings.h, some call it string.h; others, also have memory.h */ +#ifdef __STDC__ +#include +#else +/* ANSI C string.h -- 1/11/88 Draft Standard */ +#if defined(ultrix4) +#include +#else +extern char *strcpy(), *strncpy(), *strcat(), *strncat(), *strerror(); +extern char *strpbrk(), *strtok(), *strchr(), *strrchr(), *strstr(); +extern int strcoll(), strxfrm(), strncmp(), strlen(), strspn(), strcspn(); +extern char *memmove(), *memccpy(), *memchr(), *memcpy(), *memset(); +extern int memcmp(), strcmp(); +#endif /* ultrix4 */ +#endif /* __STDC__ */ + +#ifdef lint +#undef putc /* correct lint '_flsbuf' bug */ +#endif /* lint */ + +/* a few extras */ +extern VOID_HACK srandom(); +extern long random(); + +#if defined(ultrix3) +extern unsigned sleep(); +#else +extern VOID_HACK sleep(); +#endif + +/* assertion macro */ + +#ifndef assert +#ifdef __STDC__ +#include +#else +#ifndef NDEBUG +#define assert(ex) {\ + if (! (ex)) {\ + (void) fprintf(stderr, "Assertion failed: file %s, line %d\n",\ + __FILE__, __LINE__);\ + (void) fflush(stdout);\ + abort();\ + }\ +} +#else +#define assert(ex) {;} +#endif +#endif +#endif + +/* handle the various limits */ +#if defined(__STDC__) || defined(POSIX) +#include +#else +#define USHRT_MAX (~ (unsigned short int) 0) +#define UINT_MAX (~ (unsigned int) 0) +#define ULONG_MAX (~ (unsigned long int) 0) +#define SHRT_MAX ((short int) (USHRT_MAX >> 1)) +#define INT_MAX ((int) (UINT_MAX >> 1)) +#define LONG_MAX ((long int) (ULONG_MAX >> 1)) +#endif + +#endif /* PORT_H */ + diff --git a/nova/options.c b/nova/options.c new file mode 100644 index 0000000..c253825 --- /dev/null +++ b/nova/options.c @@ -0,0 +1,226 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/options.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +#include "nova.h" + +/**********************************************************************/ +/* Here is the command_line routine */ +/* */ +/**********************************************************************/ + +options(argc, argv) +int argc; +char *argv[]; +{ + BOOLEAN encoding_algo = FALSE; + register int i,k; + register int infile = 0; + void usage(); + + for (i = 1; i < argc; i++) { + + if (!(strcmp(argv[i],"-i"))) { + i++; + if (i >= argc) { + fprintf(stderr,"no argument for input code length!\n"); + exit(-1); + } + inp_codelength = atoi(argv[i]); + IBITS_DEF = FALSE; + } + + else if (!(strcmp(argv[i],"-s"))) { + i++; + if (i >= argc) { + fprintf(stderr,"no argument for state code length!\n"); + exit(-1); + } + st_codelength = atoi(argv[i]); + SBITS_DEF = FALSE; + } + + else if (!(strcmp(argv[i],"-o"))) { + i++; + if (i >= argc) { + /*fprintf(stderr,"no argument for output code length!\n"); + exit(-1);*/ + } + /*out_codelength = atoi(argv[i]); + OBITS_DEF = FALSE;*/ + } + + + else if (!(strcmp(argv[i],"-c"))) { + i++; + if (i >= argc) { + fprintf(stderr,"no argument for cost function in sa!\n"); + exit(-1); + } + cost_function = atoi(argv[i]); + if (cost_function < 0 || cost_function > 1) { + fprintf(stderr,"Cost function of sa may be only 0 or 1!\n"); + exit(-1); + } + } + + else if (!(strcmp(argv[i],"-m"))) { + i++; + if (i >= argc) { + fprintf(stderr,"no argument for # of moves in sa!\n"); + exit(-1); + } + num_moves = atoi(argv[i]); + if (num_moves < 1) { + fprintf(stderr,"Invalid # of moves in sa (non-pos. int.)!\n"); + exit(-1); + } + } + + else if (!(strcmp(argv[i],"-n"))) { + i++; + if (i >= argc) { + fprintf(stderr,"no argument for # of random trials!\n"); + exit(-1); + } + rand_trials = atoi(argv[i]); + if (rand_trials < 1) { + fprintf(stderr,"Invalid # of random trials!\n"); + exit(-1); + } + } + + else if (!(strcmp(argv[i],"-e"))) { + if (encoding_algo == FALSE) { + i++; + if (!(strcmp(argv[i],"ig"))) { + I_GREEDY = TRUE; + encoding_algo = TRUE; + } + else if (!(strcmp(argv[i],"ih"))) { + I_HYBRID = TRUE; + encoding_algo = TRUE; + } + else if (!(strcmp(argv[i],"ie"))) { + I_EXACT = TRUE; + encoding_algo = TRUE; + } + else if (!(strcmp(argv[i],"ioh"))) { + IO_HYBRID = TRUE; + encoding_algo = TRUE; + } + else if (!(strcmp(argv[i],"iov"))) { + IO_VARIANT = TRUE; + encoding_algo = TRUE; + } + else if (!(strcmp(argv[i],"h"))) { + ONEHOT = TRUE; + encoding_algo = TRUE; + } + else if (!(strcmp(argv[i],"r"))) { + RANDOM = TRUE; + encoding_algo = TRUE; + } + else if (!(strcmp(argv[i],"u"))) { + USER = TRUE; + encoding_algo = TRUE; + } + else if (!(strcmp(argv[i],"ia"))) { + I_ANNEAL = TRUE; + encoding_algo = TRUE; + } + } + else { + fprintf(stderr,"More than one encoding_algo!\n"); + exit(-1); + } + if (encoding_algo == FALSE) usage(1); + } + + else if (!(strcmp(argv[i],"-z"))) { + i++; + if (i >= argc) { + fprintf(stderr,"no argument for -z!\n"); + exit(-1); + } + strcpy(zero_state,argv[i]); + ZERO_FL = TRUE; + } + + else if (!(strcmp(argv[i],"-help")) || !(strcmp(argv[i],"h"))) + usage(0); + + else if (argv[i][0] == '-') { + k = 1; + while (argv[i][k] != '\0') { + switch(argv[i][k]) { + case 'p': POW2CONSTR = TRUE; break; + case 'r': COMPLEMENT = TRUE; break; + case 't': PLA_OUTPUT = TRUE; break; + case 'j': OUT_ALL = TRUE; break; + case 'y': OUT_ONLY = TRUE; break; + default : usage(1); break; + } + k++; + } + } + else if (infile == 0) { + strcpy(file_name,argv[i]); + getname(argv[i]); + infile++; + } + else usage(1); + } + /*if (infile == 0) usage();*/ + fprintf(stdout,"#"); + for (i = 0; i < argc; i++) { + fprintf(stdout," %s",argv[i]); + } + fprintf(stdout,"\n"); + return(infile); +}/* end of command_line_proc */ + + + +void +usage(exit_flag) +int exit_flag; +{ + fprintf(stderr, + "\nNOVA, Version 3.2, Date: january 1990\n"); + fprintf(stderr, "nova [options] [infile] [> outfile]\n\n"); + fprintf(stderr, "infile\tspecify the input file.\n"); + fprintf(stderr, "outfile\tspecify the output file.\n\n"); + fprintf(stderr,"Please read the manual page to understand the options\n\n"); + fprintf(stderr, "Options allowed are:\n"); + fprintf(stderr, "-h\tDisplay the available command options.\n"); + fprintf(stderr, "-e ig\tencoding-algo. inp.constr.+ greedy (default)\n"); + fprintf(stderr, "-e ih\tencoding-algo. inp.constr.+ hybrid\n"); + fprintf(stderr, "-e ioh\tencoding-algo. inp./out.constr.+ hybrid\n"); + fprintf(stderr, "-e iov\tencoding-algo. inp./out.constr.+ hybrid\n"); + fprintf(stderr, "-e ie\tencoding-algo. inp.constr.+ exact\n"); + fprintf(stderr, "-e ia\tencoding-algo. inp.constr.+ sim.annealing\n"); + fprintf(stderr, "-e h\tencoding-algo. onehot\n"); + fprintf(stderr, "-e r\tencoding-algo. random\n"); + fprintf(stderr, "-e u\tencoding-algo. user\n"); + fprintf(stderr, "-i\tspecify code-length of inputs\n"); + fprintf(stderr, "-s\tspecify code-length of states\n"); + fprintf(stderr, "-o\tspecify code-length of outputs\n"); + fprintf(stderr, "-n\tspecify number of random encodings\n"); + fprintf(stderr, "-c\tcost function of sim-anneal: 0=faces, 1=literals\n"); + fprintf(stderr, "-m\tspecify number of moves of sim-anneal\n"); + fprintf(stderr, "-p\t-e ig on power-of-2 input constraints\n"); + fprintf(stderr, "-r\ttry all rotations\n"); + fprintf(stderr, "-t\toutput two-level minimized fsm\n"); + fprintf(stderr, "-j\t-e ioh on all output constraints\n"); + fprintf(stderr, "-y\t-e ioh on only output constraints\n"); + fprintf(stderr, "-z\tspecify state to be assigned all zeroes code\n"); + fprintf(stderr, "\n"); + if (exit_flag == 0) exit(0); + else exit(-1); +} /* end of usage() */ diff --git a/nova/out_encoder.c b/nova/out_encoder.c new file mode 100644 index 0000000..708f565 --- /dev/null +++ b/nova/out_encoder.c @@ -0,0 +1,350 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/out_encoder.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +#include "out_encoder.h" +#include "nova.h" + +int iter, flag[MAXNODE]; +int enc_iter; + +/* main routine of the bounded row encoding strategy */ +out_encoder(bits) +int bits; +{ + pgraph get_node_constraints(); + t_solution add_soln(); + + char encoding[MAXDIM]; + int node, n_nodes, pow2_num, i; + pgraph graph[MAXNODE]; + t_dag dag[MAXNODE]; + t_solution soln; + + if (bits > MAXDIM) { + fprintf(stderr,"\nNot enough memory allocated in out_encoder.h\n"); + fprintf(stderr,"Please increase the memory allocated by: \n"); + fprintf(stderr,"#define MAXDIM 8+1 \n"); + fprintf(stderr,"#define MAXPOW2DIM 256 \n"); + exit(-1); + } + + iter = 0; + enc_iter = 0; + n_nodes = read_constraints(graph, dag); + soln.dim = bits; + powers(soln.dim, &pow2_num); + for (i = 0; i < n_nodes; i++) { + flag[i] = NOT_DONE; + } + for (i = 0; i < n_nodes; i++) { + node = get_next_node(dag, n_nodes); + while (try_encoding(graph[node], soln, pow2_num, encoding) + == FAIL) { + change_graph(graph, n_nodes); + update_dag(graph, dag, n_nodes); + } + flag[node] = DONE; + update_dag(graph, dag, n_nodes); + soln = add_soln(soln, node, encoding); + } + print_soln(soln, n_nodes); +} + +powers(num, num_pow2) + int num, *num_pow2; +{ + int i, j; + + for (i = 0, j = 1; i < num; i ++, j *= 2); + *num_pow2 = j; +} + +/* + * format of constraint file : ... + */ +read_constraints(graph, dag) + pgraph graph[MAXNODE]; + t_dag dag[MAXNODE]; +{ + FILE *fpin; + char line[MAXLINE]; + int i, num, index; + int count; + pgraph new_node; + + if ((fpin = fopen(constraints, "r")) == NULL) { + fprintf(stderr,"Error in opening file constraints\n"); + exit(1); + } + count = 0; + while (fgets(line, MAXLINE, fpin) != NULL) { + i = 0; + index = getnum(line, &i); + count++; + graph[index] = NULL; + while ((num = getnum(line, &i)) != EOF) { + + /* insert into constraint graph */ + new_node = (pgraph) malloc(sizeof(struct g_type)); + new_node->num = num; + new_node->next = graph[index]; + graph[index] = new_node; + } + } + update_dag(graph, dag, count); + fclose(fpin); + + return (count); +} + +update_dag(graph, dag, count) +pgraph graph[MAXNODE]; +t_dag dag[MAXNODE]; +int count; +{ + int i; + pgraph p; + + /* update the dag info fields */ + for (i = 0; i < count; i ++) { + dag[i].depth = 0; + dag[i].incard = 0; + dag[i].outcard = 0; + dag[i].out_done = 0; + } + + for (i = 0; i < count; i ++) { + for (p = graph[i]; p != NULL; p = p->next) { + if (flag[p->num] == DONE) { + dag[i].out_done ++; + } + dag[i].outcard ++; + dag[p->num].incard ++; + if (dag[i].depth >= dag[p->num].depth) + dag[p->num].depth = 1 + dag[i].depth; + } + } +} + +getnum(line, ind) + char *line; + int *ind; +{ + + int i; + char ch, str[MAXLINE]; + + while (((ch = *(line + *ind)) == ' ') || (ch == ':')) + (*ind)++; + if ((ch == '\n') || (ch == EOS)) + return (EOF); + for (i = 0; isdigit(line[*ind]); (*ind)++) + str[i++] = line[*ind]; + str[i] = EOS; + return (atoi(str)); +} + +/* remove edges to already encoded nodes */ +change_graph(graph, n_nodes) + pgraph graph[MAXNODE]; + int n_nodes; +{ + + pgraph p, prev; + int i, found = FALSE; + + for (i = 0; i < n_nodes; i++) { + if (flag[i] == DONE) + continue; + for (p = graph[i], prev = NULL; p != NULL; p = p->next) { + if (flag[p->num] == DONE) { + found = TRUE; + if (prev == NULL) + graph[i] = NULL; + else + prev->next = p->next; + } + prev = p; + } + } + + /* if no edges deleted remove any one edge from node with max cardinality */ + if (!found) { + fprintf(stderr,"Achtung : Reached the unreachable\n"); + exit(-1); + } +} + +/* + * find the next node to be encoded - it should have no outgoing edges it is + * then deleted from the graph + */ +get_next_node(dag, n_nodes) +t_dag dag[MAXNODE]; +int n_nodes; + +{ + + int consider[MAXNODE], card[MAXNODE]; + int i = 0, max_so_far; + + for (i = 0; i < n_nodes; i++) { + consider[i] = FALSE; + card[i] = 0; + if (flag[i] == NOT_DONE) { + if (dag[i].outcard == dag[i].out_done) { + consider[i] = TRUE; + } + } + } + + iter++; + + /* return the node with max out nodes done then max depth and then max + incard */ + max_so_far = -1; + for (i = 0; i < n_nodes; i++) { + if (consider[i]) { + if (max_so_far == -1) + max_so_far = i; + else if (dag[i].out_done > dag[max_so_far].out_done) + max_so_far = i; + else if ((dag[i].out_done == dag[max_so_far].out_done) && + (dag[i].depth > dag[max_so_far].depth)) + max_so_far = i; + else if ((dag[i].out_done == dag[max_so_far].out_done) && + (dag[i].depth == dag[max_so_far].depth) && + (dag[i].incard > dag[max_so_far].incard)) + max_so_far = i; + } + } + if (max_so_far == -1) { + fprintf(stderr,"No node found : Graph not acyclic"); + exit(-1); + } else { + return (max_so_far); + } + return(0); +} + +/* + * given the bit positions which should be set try using an encoding that has + * not yet been used to cover this bit pattern. return FAIL on failure + */ +try_encoding(constraint, soln, num, encoding) + pgraph constraint; + int num; + t_solution soln; + char encoding[MAXDIM]; + +{ + + static int encodings_used[MAXPOW2DIM]; + static char enc[MAXPOW2DIM][MAXDIM]; + char set_bits[MAXDIM]; + int useful[MAXPOW2DIM], min_set, min_index, i, j; + int one_kount, found; + pgraph p; + + if (enc_iter == 0) + for (i = 0; i < MAXPOW2DIM; i++) + encodings_used[i] = NOT_DONE; + if (enc_iter == 0) + for (i = 0; i < num; i++) + for (j = 0; j < soln.dim; j++) + enc[i][j] = ((i >> j) & 1) ? ONE : ZERO; + enc_iter++; + + for (i = 0; i < soln.dim; i++) + set_bits[i] = ZERO; + + /* find all the bits that must be set using the constraint graph */ + for (p = constraint; p != NULL; p = p->next) + for (i = 0; i < soln.dim; i++) + if (soln.node[p->num][i] == ONE) + set_bits[i] = ONE; + + /* find the encoding still available with the fewest bits set */ + found = FALSE; + for (i = 0; i < num; i++) { + useful[i] = FALSE; + if (encodings_used[i] == DONE) + continue; + if (covers(enc[i], set_bits, soln.dim)) { + found = TRUE; + useful[i] = TRUE; + } + } + if (found != TRUE) + return (FAIL); + min_set = -1; + one_kount = 0; + for (i = 0; i < num; i++) + if (useful[i]) { + for (j = 0; j < soln.dim; j++) + if (enc[i][j] == ONE) + one_kount++; + if ((min_set == -1) || (one_kount < min_set)) { + min_set = one_kount; + min_index = i; + } + } + for (j = 0; j < soln.dim; j++) { + encoding[j] = enc[min_index][j]; + } + encodings_used[min_index] = DONE; + return (TRUE); +} + +/* does the first string cover the second string bit-wise */ +covers(a, b, dim) + char *a, *b; + int dim; +{ + + int i; + + for (i = 0; i < dim; i++) + if (b[i] == ONE) + if (a[i] != ONE) + return (FALSE); + return (TRUE); +} + +t_solution +add_soln(soln, node, encoding) + t_solution soln; + int node; + char encoding[MAXDIM]; + +{ + + int i; + + for (i = 0; i < soln.dim; i++) + soln.node[node][i] = encoding[i]; + return (soln); +} + +print_soln(soln, num) + t_solution soln; + int num; +{ + + int i; + + if (VERBOSE) printf("\nFINAL CODES\n"); + for (i = 0; i < num; i++) + soln.node[i][soln.dim] = EOS; + for (i=0; i= '0') && (ch <= '9')) +#define isalpha(ch) (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')))*/ + +#define MAXNODE 220 +#define MAXDIM 8+1 +#define MAXPOW2DIM 256 + +#define Z_X '?' +#define NOT_DONE 0 +#define DONE 1 +#define EOS '\0' +#define FAIL '\0' + +typedef struct g_type { + int num; + int name; + struct g_type *next; +} t_graph,*pgraph; + +typedef struct dag_t { + int depth; + int incard; + int outcard; + int out_done; +} t_dag; + +typedef struct sol_type { + int dim; + char node[MAXNODE] [MAXDIM]; +} t_solution; diff --git a/nova/out_eval.c b/nova/out_eval.c new file mode 100644 index 0000000..82cd10f --- /dev/null +++ b/nova/out_eval.c @@ -0,0 +1,138 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/out_eval.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +#include "nova.h" + +out_performance(label) +char *label; + +{ + + ORDER_RELATION *curptr; + int i,cover_count,ycover_count; + int codei_covers_codej(); + + cover_count = ycover_count = 0; + + for ( i = 0; i < statenum; i++) { + for ( curptr = order_graph[i] ; curptr != (ORDER_RELATION *) 0; + curptr = curptr->next ) { + cover_count++; + if (strcmp(label,"exact") == 0) { + if (codei_covers_codej(states[i].exact_code,states[curptr->index].exact_code) == 1) { + ycover_count++; + } + } + if (strcmp(label,"exbest") == 0) { + if (codei_covers_codej(states[i].exbest_code,states[curptr->index].exbest_code) == 1) { + ycover_count++; + } + } + } + } + printf("\n\nOutput constraints satisfaction = %d\n", ycover_count); + printf("Output constraints unsatisfaction = %d\n", cover_count - ycover_count); + +} + + + +weighted_outperf(net_num,label) +int net_num; +char *label; + +{ + + BOOLEAN ROW; + int i,j,row_count,weighted_gain,weighted_loss; + + weighted_gain = 0; + weighted_loss = 0; + for (i = 0; i < net_num; i++) { + ROW = TRUE; + row_count = 0; + for (j = 0; j < net_num; j++) { + if (order_array[i][j] == ONE) { + row_count++; + if (strcmp(label,"exact") == 0) { + if (codei_covers_codej(states[j].exact_code,states[i].exact_code) != 1) { + ROW = FALSE; + } + } + if (strcmp(label,"exbest") == 0) { + if (codei_covers_codej(states[j].exbest_code,states[i].exbest_code) != 1) { + ROW = FALSE; + } + } + } + } + if (ROW == TRUE && row_count > 0) { + weighted_gain += gain_array[i]; + } + if (ROW == FALSE && row_count > 0) { + weighted_loss += gain_array[i]; + } + } + printf("Weighted_gain = %d\n", weighted_gain); + printf("Weighted_loss = %d\n", weighted_loss); + +} + + + +int codei_covers_codej(p,s) /* returns 1 iff set p includes properly set s */ +char *p; +char *s; + +{ + + int j; + BOOLEAN cover; + + cover = FALSE; + + for (j=0; p[j] != '\0'; j++) { + if (p[j] == ONE && s[j] == ZERO) cover = TRUE; + if (p[j] == ZERO && s[j] == ONE) { + cover = FALSE; + return(cover); + } + } + + return(cover); + +} + + + +int symbmin_card() + +{ + + FILE *fopen(), *fpin; + char line[MAXLINE], string[MAXLINE]; + int symb_card; + + if ((fpin = fopen(temp10, "r")) == NULL) { + fprintf(stderr,"fopen: can't read file temp10\n"); + exit(-1); + } + while (fgets(line, MAXLINE, fpin) != NULL) { + if (myindex(line,".p") >= 0) { + sscanf(line, "%s %d", string, &symb_card); + break; + } + } + fclose(fpin); + + symbmin_products = symb_card; + + return(symb_card); + +} diff --git a/nova/show.c b/nova/show.c new file mode 100644 index 0000000..f2089a7 --- /dev/null +++ b/nova/show.c @@ -0,0 +1,341 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/show.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +/***************************************************************************** +* Shows the net of the constraints * +* * +*****************************************************************************/ + +#include "nova.h" + +shownet(net,net_name,header) +CONSTRAINT **net; +char *net_name; +char *header; + +{ + CONSTRAINT *scanner; + + if ( header != (char *) 0) printf("\n%s %s\n", net_name, header); + + for (scanner = (*net); scanner != (CONSTRAINT *) 0; scanner = scanner->next) { + printf("%s wgt:%d lev:%d nxst:%s ", scanner->relation, scanner->weight, scanner->level, scanner->next_states); + + switch(scanner->attribute) { + case NOTUSED : printf("NOTUSED\n"); + break; + case PRUNED : printf("PRUNED-\n"); + break; + case USED : printf("USED---\n"); + break; + case TRIED : printf("TRIED--\n"); + break; + default : printf("illegal: %d\n", scanner->attribute); + } + + /*switch(scanner->odd_type) { + case ADMITTED : printf("ADMITTED "); + break; + case NOTADMITTED : printf("-------- "); + break; + case EXAMINED : printf("EXAMINED "); + break; + default : printf("illegal: %d", scanner->odd_type); + } + + switch(scanner->source_type) { + case INPUT : printf("INPUT-\n"); + break; + case OUTPUT : printf("OUTPUT\n"); + break; + case MIXED : printf("MIXED-\n"); + break; + default : printf("illegal: %d\n", scanner->source_type); + }*/ + + } + +} + + + + + +/***************************************************************************** +* Shows the codes * +* * +*****************************************************************************/ + + +show_code(symblemes,num) +SYMBLEME *symblemes; +int num; + +{ + int i; + + for (i = 0; i < num; i++) { + printf(".code %s", symblemes[i].name); + if (symblemes[i].code_status == FIXED || I_ANNEAL == TRUE) { + printf(" %s\n", symblemes[i].code); + } + } + +} + + + +show_exactcode(symblemes,num) +SYMBLEME *symblemes; +int num; + +{ + + int i; + + for (i = 0; i < num; i++) { + printf(".code %s", symblemes[i].name); + printf(" %s\n", symblemes[i].exact_code); + } + +} + + + +show_bestcode(symblemes,num) +SYMBLEME *symblemes; +int num; + +{ + + int i; + + for (i = 0; i < num; i++) { + printf(".code %s", symblemes[i].name); + printf(" %s\n", symblemes[i].best_code); + } + +} + + + +show_exbestcode(symblemes,num) +SYMBLEME *symblemes; +int num; + +{ + + int i; + + for (i = 0; i < num; i++) { + printf(".code %s", symblemes[i].name); + printf(" %s\n", symblemes[i].exbest_code); + } + +} + + + +/******************************************************************************* +* Shows the graph of the constraints (built for the exact algorithm) * +*******************************************************************************/ + +show_graph() + +{ + + int i; + CONSTRAINT_E *showptr; + + for (i = graph_depth-1; i >= 0; i--) { + printf("\nlevel of the graph = %d\n", i); + for (showptr = graph_levels[i]; showptr != (CONSTRAINT_E *) 0; + showptr = showptr->next ) { + printf("%s ", showptr->relation); + } + } + printf("\n"); + +} + + + +/***************************************************************************** +* Shows the sons of all constraints * +*****************************************************************************/ + +show_sons() + +{ + + CONSTRAINT_E *upconstr; + SONS_LINK *son_scanner; + int i; + + for (i = graph_depth-1; i >= 0; i--) { + for (upconstr = graph_levels[i]; upconstr != (CONSTRAINT_E *) 0; + upconstr = upconstr->next ) { + printf("The sons of constraint %s are :\n", upconstr->relation); + for (son_scanner = upconstr->down_ptr; son_scanner != (SONS_LINK *) 0; + son_scanner = son_scanner->next ) { + printf("%s \n", son_scanner->constraint_e->relation); + /*printf("%s \n", son_scanner->codfather_ptr->relation);*/ + } + } + } + +} + + + +/***************************************************************************** +* Shows the fathers of all constraints * +*****************************************************************************/ + +show_fathers() + +{ + + CONSTRAINT_E *downconstr; + FATHERS_LINK *father_scanner; + int i; + + for (i = graph_depth-1; i >= 0; i--) { + for (downconstr = graph_levels[i]; downconstr != (CONSTRAINT_E *) 0; + downconstr = downconstr->next ) { + printf("The fathers of constraint %s are :\n", downconstr->relation); + for (father_scanner = downconstr->up_ptr; father_scanner != (FATHERS_LINK *) 0; + father_scanner = father_scanner->next ) { + printf("%s \n", father_scanner->constraint_e->relation); + } + } + } + +} + + +/***************************************************************************** +* Shows the faces assigned to the constraints * +*****************************************************************************/ + +show_faces() + +{ + + CONSTRAINT_E *constrptr; + int i; + + printf("\nFINAL CODES\n"); + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + if ( constrptr->face_ptr != (FACE *) 0 ) { + printf("constraint = %s ", constrptr->relation); + printf("face = "); + /*if (constrptr->face_ptr->code_valid == TRUE) {*/ + printf(" %s ", constrptr->face_ptr->cur_value); + /*}*/ + printf("tried_codes = %d \n", constrptr->face_ptr->tried_codes); + } + } + } + +} + + + +/***************************************************************************** +* Shows the dimensions of the faces assigned to the constraints * +*****************************************************************************/ + +show_dimfaces() + +{ + + CONSTRAINT_E *constrptr; + int i; + + for (i = graph_depth-1; i >= 0; i--) { + for (constrptr = graph_levels[i]; constrptr != (CONSTRAINT_E *) 0; + constrptr = constrptr->next ) { + if (constrptr->face_ptr->category == 0) { + printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category); + printf("curdim_face = %d\n", constrptr->face_ptr->curdim_face); + } + if (constrptr->face_ptr->category == 1) { + printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category); + printf("mindim_face = %d ", constrptr->face_ptr->mindim_face); + printf("maxdim_face = %d\n", constrptr->face_ptr->maxdim_face); + } + if (constrptr->face_ptr->category == 2) { + printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category); + printf("mindim_face = %d\n", constrptr->face_ptr->mindim_face); + } + if (constrptr->face_ptr->category == 3) { + printf("constraint %s is of cat. %d ",constrptr->relation, + constrptr->face_ptr->category); + printf("mindim_face = %d\n", constrptr->face_ptr->mindim_face); + } + } + } + +} + + + +show_implicant() + +{ + + IMPLICANT *scanner; + + printf("\nImplicants produced by symbolic minimization\n"); + for (scanner = implicant_list; scanner != (IMPLICANT *) 0; scanner = scanner->next) { + printf("State = %d ", scanner->state); + switch(scanner->attribute) { + case NOTUSED : printf("NOTUSED "); + break; + case PRUNED : printf("PRUNED- "); + break; + case USED : printf("USED--- "); + break; + default : printf("illegal: %d", scanner->attribute); + } + printf("%s", scanner->row); + } + +} + + + +show_orderarray(net_num) +int net_num; + +{ + + int i,j; + + printf("\nOrder_array\n"); + for (i = 0; i < net_num; i++) { + for (j = 0; j < net_num; j++) printf("%c", order_array[i][j]); + switch(select_array[i]) { + case NOTUSED : printf(" NOTUSED\n"); + break; + case PRUNED : printf(" PRUNED-\n"); + break; + case USED : printf(" USED---\n"); + break; + default : printf(" illegal: %d\n", select_array[i]); + } + } + +} diff --git a/nova/symbolic_loop.c b/nova/symbolic_loop.c new file mode 100644 index 0000000..21a91dd --- /dev/null +++ b/nova/symbolic_loop.c @@ -0,0 +1,777 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/symbolic_loop.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +#include "nova.h" + +/******************************************************************************* +* SYMBOLIC MINIMIZATION LOOP * +* * +* * +* External files used : <> temp6 is the input to espresso (ON1i , OFFi) * +* <> temp7 is the output from espresso (Mi) * +* <> temp81 contains Mi with simplified output part * +* <> temp82 contains ON0j with simplified output part * +* (covers of temp81 and temp82 are intersected) * +* <> temp83 contains the intersection of the covers * +* contained in temp81 and temp82 * +* <> temp9 contains the final minimized cover : * +* (P = union Mi for i=1,...,q) * +* <> temp10 contains the final irredundant cover * +*******************************************************************************/ + + +symbolic_loop() + +{ + + + FILE *fopen(),*fpcons,*fp9; + INPUTTABLE *new; + OUTSYMBOL *temptr,*onjptr,*oniptr,*select_oni(); + ORDER_RELATION *curptr; + /*ORDER_PATH *cursor;*/ + char mvline[MAXSTRING]; + char command[MAXSTRING]; + int i,j,found; + int oni_card,onk,card_gain; + int relation_is_new(); + int count_prods(); + unsigned status; + + + /* allocates and initializes array_cover */ + array_alloc2(); + + /* fills order_array with zeroes */ + for ( i = 0; i < statenum; i++) { + for ( j = 0; j < statenum; j++) { + order_array[i][j] = ZERO; + } + } + + /* determines the correct .mv command line */ + if ( (fp9 = fopen(temp9,"w") ) == NULL ) { + fprintf(stderr,"fopen: can't create temp9\n"); + exit(-1); + } else { + if (ISYMB) { + sprintf(mvline,".mv %d %d %d %d %d\n", 3, 0 , inputnum , statenum, statenum+outputfield-1); + fputs(mvline,fp9); + } else { + sprintf(mvline,".mv %d %d %d %d\n", inputfield+2, inputfield , statenum, statenum+outputfield-1); + fputs(mvline,fp9); + } + } + fclose(fp9); + + + /* scans the next-state column of the input-table to build + "outsymbol_list" */ + oni_card = 0; + for ( new = firstable; new != (INPUTTABLE *) 0; new = new->next ) { + + /* if the current next state is a don't care state , do nothing + ( a don't care state may be denoted by a "-" in the + first position of the string or by the string "ANY" ) */ + if ( new->nstate[0] == DASH || myindex(new->nstate,ANYSTATE) >=0 ) { + ; + + } else { + + /* adds the current next-state symbol to outsymbol_list , + unless it is already there */ + found = 0; + for ( temptr = outsymbol_list ; temptr != (OUTSYMBOL *) 0; + temptr = temptr->next ) { + if ( strcmp(temptr->element , new->nstate) == 0 ) { + found = 1; + temptr->card++; + break; + } + } + if ( found == 0 ) { + new_outsymbol(new->nstate,new->nlab); + oni_card++ ; + } + + } + } + + if (VERBOSE) { + printf("\nOUTSYMBOL_LIST\n"); + /*printf("Card = %d\n", oni_card);*/ + for ( temptr = outsymbol_list ; temptr != (OUTSYMBOL *) 0; + temptr = temptr->next ) { + printf("%s ", temptr->element); + printf("%d ", temptr->nlab); + printf("card = %d\n", temptr->card); + } + } + + + + /* ^^^^^^^^^ SYMBOLIC MINIMIZATION LOOP ^^^^^^^^^ */ + + for ( onk = 0; onk < oni_card; onk++ ) { + + /* procedure "select" selects the sets ONi according to a heuristic + criterion */ + oniptr = select_oni(); + if (VERBOSE) printf(" Select_oni returned %s\n", oniptr->element); + select_array[oniptr->nlab] = NOTUSED; + + + /* dfs (depth-first search) builds the set of indices + J = { j : such that there is a path from vi to vj in G(V,A) } */ + for ( i= 0; i < statenum; i++ ) { + reached[i] = 0; + } + /*printf("dfs called by node = %d", oniptr->nlab);*/ + dfs(oniptr->nlab ,oniptr->nlab ); + + /*printf("\nPath graph\n"); + for ( i = 0; i < statenum; i++) { + printf("row = %d: ", i); + for ( cursor = path_graph[i] ; cursor != (ORDER_PATH *) 0; + cursor = cursor->next ) { + printf("%d ", cursor->dest); + } + printf("\n"); + }*/ + + + /* Mi = minimize(ON0i,DCi,OFFi) + out_mini invokes Espresso to minimize (ON0i,DCi,OFFi) where + OFFi = Union ( Union(ON0j) ) and j varies in J defined above . + At each iteration of the symbolic minimization loop Mi is obtained + by minimizing ON0i, using a routine that performs multiple-valued- + input binary-valued output minimization. We invoke the minimization + routine with the triple (ON0i,DCi,OFFi), where the corresponding + don't care set DCi includes by construction all the sets ON0j + for which no path exists in G(V,A) from vi to vj . + As a result, minimization may be very efficient in reducing the + cardinality of ON0i because of the advantageous don't care set */ + card_gain = out_mini(oniptr); + gain_array[oniptr->nlab] = card_gain; + /*printf("out_mini = %d\n", card_gain);*/ + + /* Comment if card_gain > 0 */ + /* if Mi intersects ONj , (vj,vi) is added to the edge set of the + graph: A = A U { (vj,vi) such that (Mi intersection ON0j) != 0 } + (Mi is the minimized cover of ON0i written by espresso in temp6) - + the intersection is detected by a system call to a modified version + of espresso called test : + system("ESPRESSO/test -Dinter Mi On0j") + note : status = 1 covers are not disjoint + status = 2 covers are disjoint */ + if ( OUT_ALL || (!OUT_ALL && card_gain > 0) ) { + for ( onjptr = outsymbol_list ; onjptr != (OUTSYMBOL *) 0; + onjptr = onjptr->next ) { + /*printf("\nonjptr->nlab = %d ", onjptr->nlab); + printf("oniptr->nlab = %d\n", oniptr->nlab);*/ + if ( onjptr->nlab != oniptr->nlab ) { + + /* oncover_inter1 writes in temp81 the cover Mi after + substituting string "1" instead of the next-state string */ + oncover_inter1(); + /*printf("\nFile temp81\n"); + system("cat temp81");*/ + + /* oncover_inter2 writes in temp82 the cover ON0j (j = + onjptr->nlab) after substituting string "1" instead of + the next-state string */ + oncover_inter2(onjptr); + /*printf("File temp82\n"); + system("cat temp82");*/ + + sprintf(command, + "espresso -Dintersect %s %s > %s", temp81, temp82, temp83); + system(command); + status = count_prods(temp83); + /*printf("exit code was = %d\n", status);*/ + if ( status == 1 ) { + if (relation_is_new(onjptr->nlab,oniptr->nlab) == 0) { + new_order_relation(onjptr->nlab,oniptr->nlab); + order_array[oniptr->nlab][onjptr->nlab] = ONE; + } + } + + } + } + } + + if (VERBOSE) { + printf("\nPartial order graph\n"); + for ( i = 0; i < statenum; i++) { + printf("%d: ", i); + for ( curptr = order_graph[i] ; curptr != (ORDER_RELATION *) 0; + curptr = curptr->next ) { + printf("%d ", curptr->index); + } + printf("\n"); + } + } + + } + if (VERBOSE) { + printf("\nOrder_array\n"); + for ( i = 0; i < statenum; i++) { + for ( j = 0; j < statenum; j++) { + printf("%c", order_array[i][j]); + } + printf(" wgt:%d", gain_array[i]); + printf("\n"); + } + printf("\n"); + } + /*show_implicant();*/ + + if ( (fpcons = fopen(constraints,"w") ) == NULL ) { + fprintf(stderr,"fopen: can't create constraints\n"); + exit(-1); + } + for ( i = 0; i < statenum; i++) { + fprintf(fpcons,"%d: ", i); + for ( curptr = order_graph[i] ; curptr != (ORDER_RELATION *) 0; + curptr = curptr->next ) { + fprintf(fpcons,"%d ", curptr->index); + } + fprintf(fpcons,"\n"); + } + fclose(fpcons); + + /* runs the final cover through Espresso to eliminate redundant terms */ + sprintf(command,"espresso %s > %s", temp9, temp10); + system(command); + inputnet = (CONSTRAINT *) 0; + statenet = (CONSTRAINT *) 0; + analysis(temp10); + +} + + + +/******************************************************************************* +* Sorts the sets ONi according to a heuristic criterion - * +* Heuristic implemented : to sort the sets ONi in descending order of * +* cardinality , so that the largest sets will benefit from larger don't * +* care sets * +* +*******************************************************************************/ + +OUTSYMBOL *select_oni() + +{ + OUTSYMBOL *temptr,*maxptr; + int max_card; + + max_card = 0; + + for ( temptr = outsymbol_list ; temptr != (OUTSYMBOL *) 0; + temptr = temptr->next ) { + if ( temptr->selected == 0 && temptr->card >= max_card ) { + max_card = temptr->card; + maxptr = temptr; + } + } + + if (VERBOSE) printf("\nMax_card = %d", max_card); + + maxptr->selected = 1; + + return(maxptr); +} + + + +/******************************************************************************* +* Writes Mi (result of the i-th partial minimization) into the file "temp81" * +* after substituting string "1" instead of the next-state string * +* * +*******************************************************************************/ + +oncover_inter1() + +{ + + FILE *fopen(),*fp7,*fp81; + char string1[MAXSTRING]; + char string2[MAXSTRING]; + char string3[MAXSTRING]; + char line[MAXLINE]; + char newline[MAXLINE]; + + if ((fp81 = fopen(temp81,"w")) == NULL) { + fprintf(stderr,"fopen: can't open temp81\n"); + exit(-1); + } + + /* determines number and size of multiple-valued variables and writes in + "temp81" the command ".mv ...parameters..." */ + if (ISYMB) { + sprintf(string1,".mv %d %d %d %d %d\n", 3, 0 , inputnum , statenum, 1+outputfield-1); + fputs(string1,fp81); + } else { + sprintf(string1,".mv %d %d %d %d\n", inputfield+2, inputfield , statenum, 1+outputfield-1); + fputs(string1,fp81); + } + + /* WRITES THE PRODUCT-TERMS OF Mi IN "temp81" */ + if ((fp7 = fopen(temp7,"r")) == NULL) { + fprintf(stderr,"fopen: can't read temp7\n"); + exit(-1); + } else { + while ( fgets(line,MAXLINE,fp7) != (char *) 0 ) { + trailblanks(line,strlen(line)); + if ( myindex(line,"# espresso") < 0 && myindex(line,".mv") < 0 && + myindex(line,".p") < 0 && myindex(line,".e") < 0 && + myindex(line,".type") < 0 && strlen(line) > 1 ) { + sscanf(line, "%s %s %s", string1 , string2 , string3); + if ( string3[0] == '1') { + sprintf(newline, "%s %s %s%s \n", string1, string2, "1", string3+1); + fputs(newline,fp81); + } else { + /*sprintf(newline, "%s %s %s%s \n", string1, string2, "0", cdrstring3); + fputs(newline,fp81);*/ + } + } + } + fclose(fp7); + } + + fclose(fp81); + +} + + + +/******************************************************************************* +* Writes into the file "temp82" the cover ON0j (where j = onjptr->nlab) * +* after substituting the string "1" instead of the next-state string * +* * +*******************************************************************************/ + +oncover_inter2(onjptr) +OUTSYMBOL *onjptr; + +{ + + FILE *fopen(),*fp82,*fp1; + char string1[MAXSTRING]; + char string2[MAXSTRING]; + char string3[MAXSTRING]; + char string4[MAXSTRING]; + char carstring3[MAXSTRING]; + char labelstring[MAXSTRING]; + char line[MAXLINE]; + char newline[MAXLINE]; + + if ((fp82 = fopen(temp82,"w")) == NULL) { + fprintf(stderr,"fopen: can't create temp82\n"); + exit(-1); + } + + /* determines number and size of multiple-valued variables and writes in + "temp82" the command ".mv ...parameters..." */ + /* + if (ISYMB) { + sprintf(string1,".mv %d %d %d %d %d\n", 3, 0 , inputnum , statenum, 1+outputfield-1); + fputs(string1,fp82); + } else { + sprintf(string1,".mv %d %d %d %d\n", inputfield+2, inputfield , statenum, 1+outputfield-1); + fputs(string1,fp82); + } + */ + + /* WRITES THE PRODUCT-TERMS OF ON0j IN "temp82" */ + if ((fp1 = fopen(temp1,"r")) == NULL) { + fprintf(stderr,"fopen: can't read temp1\n"); + exit(-1); + } else { + mvlab(labelstring,onjptr->nlab,statenum); + while ( fgets(line,MAXLINE,fp1) != (char *) 0 ) { + trailblanks(line,strlen(line)); + if ( myindex(line,"# espresso") < 0 && myindex(line,".mv") < 0 && + myindex(line,".p") < 0 && myindex(line,".e") < 0 && + myindex(line,".type") < 0 && strlen(line) > 1 ) { + sscanf(line, "%s | %s | %s %s", string1 , string2 , string3, string4); + strcar(carstring3,string3); + if ( myindex(carstring3,labelstring) >= 0 ) { + sprintf(newline, "%s %s %s%s \n", string1, string2, "1", string4); + fputs(newline,fp82); + } + } + } + fclose(fp1); + } + + fclose(fp82); + +} + + + +/******************************************************************************* +* Invokes the minimizer to get the output constraints * +* This version uses the espresso-II version#2.0 multiple-valued minimizer * +* * +* External files used : <> temp6 is the input to espresso (ON1i , OFFi) * +* <> temp7 is the output from espresso (Mi) * +* <> temp81 contains Mi with simplified output part * +* <> temp82 contains ON0j with simplified output part * +* (covers of temp81 and temp82 are intersected) * +* <> temp9 contains the final minimized cover : * +* (P = union Mi for i=1,...,q) * +* <> temp10 contains the irredundant cover * +*******************************************************************************/ + +int out_mini(oniptr) +OUTSYMBOL *oniptr; + +{ + + FILE *fopen(),*fp6,*fp1; + OUTSYMBOL *outptr; + ORDER_PATH *curptr; + char string1[MAXSTRING]; + char string2[MAXSTRING]; + char string3[MAXSTRING]; + char string4[MAXSTRING]; + char carstring3[MAXSTRING]; + char labelstring[MAXSTRING]; + char dcstring[MAXSTRING]; + char offstring[MAXSTRING]; + char newstring[MAXSTRING]; + char line[MAXLINE]; + char newline[MAXLINE]; + char command[MAXSTRING]; + int on_temp6,on_temp7,card_gain; + + /* temp6 is the input to espresso (ON1i , OFFi) */ + if ((fp6 = fopen(temp6,"w")) == NULL) { + fprintf(stderr,"fopen: can't create temp6\n"); + exit(-1); + } + on_temp6 = 0; + + /* determines number and size of multiple-valued variables and writes in + "temp6" the command ".mv ...parameters..." */ + if (ISYMB) { + sprintf(string1,".type fr\n.mv %d %d %d %d %d\n", 3, 0 , inputnum , statenum, 1+outputfield-1); + fputs(string1,fp6); + } else { + sprintf(string1,".type fr\n.mv %d %d %d %d\n", inputfield+2, inputfield , statenum, 1+outputfield-1); + fputs(string1,fp6); + } + + + /* PROVARE A LEGGERE I PRODOTTI DI ON1j INVECE CHE DI ON0j + <> ON1i is the i-th slice of the result of the disjoint minimization + of the initial cover */ + + /* WRITES THE PRODUCT-TERMS OF ON0i IN "temp6" + <> ON0i is the i-th slice of the multiple-value interpretation of the + initial cover */ + if ((fp1 = fopen(temp1,"r")) == NULL) { + fprintf(stderr,"fopen: can't read temp1\n"); + exit(-1); + } else { + mvlab(labelstring,oniptr->nlab,statenum); + while ( fgets(line,MAXLINE,fp1) != (char *) 0 ) { + trailblanks(line,strlen(line)); + if ( myindex(line,"# espresso") < 0 && myindex(line,".mv") < 0 && + myindex(line,".p") < 0 && myindex(line,".e") < 0 && + myindex(line,".type") < 0 && strlen(line) > 1 ) { + sscanf(line, "%s | %s | %s %s", string1 , string2 , string3, string4); + strcar(carstring3,string3); + if ( myindex(carstring3,labelstring) >= 0 ) { + sprintf(newline, " %s %s 1%s \n", string1 , string2 , string4); + fputs(newline,fp6); + on_temp6++; + } + } + } + fclose(fp1); + } + + + /* APPENDS THE PRODUCT-TERMS OF DCi TO "temp6" + DCi = Union(ON0k) + where k varies in K and + K = { k s.t. there is no path from vi to vk in G(V,A) } ) */ + + for ( outptr = outsymbol_list; outptr != ( OUTSYMBOL *) 0; + outptr = outptr->next ) { + if ( outptr->nlab != oniptr->nlab && + not_offi(oniptr,outptr) == 1 ) { + if ((fp1 = fopen(temp1,"r")) == NULL) { + fprintf(stderr,"fopen: can't read temp1\n"); + exit(-1); + } else { + mvlab(labelstring,outptr->nlab,statenum); + while ( fgets(line,MAXLINE,fp1) != (char *) 0 ) { + trailblanks(line,strlen(line)); + if (myindex(line,"# espresso") < 0 && myindex(line,".mv") < 0 && + myindex(line,".p") < 0 && myindex(line,".e") < 0 && + myindex(line,".type") < 0 && strlen(line) > 1 ) { + sscanf(line, "%s | %s | %s %s", string1 , string2 , string3 , string4); + strcar(carstring3,string3); + if ( myindex(carstring3,labelstring) >= 0 ) { + /* we found a product-term in ON0k that has to be added + to DCi */ + strdc(dcstring,oniptr->nlab); + sprintf(newstring," %s %s -%s\n", string1 , string2 , string4); + fputs(newstring,fp6); + } + } + } + fclose(fp1); + } + } + } + + + /* APPENDS THE PRODUCT-TERMS OF OFFi TO "temp6" + OFFi = Union ( Union(ON0j) + where j varies in J and + J = { j s.t. there is a path from vi to vj in G(V,A) } ) */ + for ( curptr = path_graph[oniptr->nlab]; curptr != ( ORDER_PATH *) 0; + curptr = curptr->next ) { + if ((fp1 = fopen(temp1,"r")) == NULL) { + fprintf(stderr,"fopen: can't read temp1\n"); + exit(-1); + } else { + mvlab(labelstring,curptr->dest,statenum); + while ( fgets(line,MAXLINE,fp1) != (char *) 0 ) { + trailblanks(line,strlen(line)); + if ( myindex(line,"# espresso") < 0 && myindex(line,".mv") < 0 && + myindex(line,".p") < 0 && myindex(line,".e") < 0 && + myindex(line,".type") < 0 && strlen(line) > 1 ) { + sscanf(line, "%s | %s | %s %s", string1 , string2 , string3 , string4); + strcar(carstring3,string3); + sprintf(newstring," %s %s %s\n", string1 , string2 , dcstring); + if ( myindex(carstring3,labelstring) >= 0 ) { + /* we found a product-term in ON0j that has to be added + to OFFi */ + stroff(offstring,oniptr->nlab); + sprintf(newstring," %s %s 0%s\n", string1 , string2 , string4); + fputs(newstring,fp6); + } + } + } + fclose(fp1); + } + } + + fclose(fp6); + + /*printf("\nInput to espresso\n"); + system("cat temp6"); + printf("on_temp6 = %d\n", on_temp6);*/ + + if (VERBOSE) printf("\nRunning Espresso\n"); + sprintf(command,"espresso %s > %s", temp6, temp7); + system(command); + if (VERBOSE) printf("Espresso terminated\n\n"); + + /*printf("Output from espresso\n"); + system("cat temp7");*/ + on_temp7 = oncounter_temp7(); + /*printf("on_temp7 = %d\n", on_temp7);*/ + + + /* P = P U Mi + the minimized final cover is written into the file "temp9" */ + card_gain = on_temp6 - on_temp7; + if ( OUT_ALL || (!OUT_ALL && card_gain > 0) ) final_cover7(oniptr); + else final_cover6(oniptr); + + return(card_gain); +} + + + + +/******************************************************************************* +* = 1 iff the next-state symbol pointed to by outptr does not belong to the * +* covering path of path_graph[oniptr->nlab] * +*******************************************************************************/ + +not_offi(oniptr,outptr) +OUTSYMBOL *oniptr; +OUTSYMBOL *outptr; + +{ + ORDER_PATH *pathptr; + + for ( pathptr = path_graph[oniptr->nlab]; + pathptr != (ORDER_PATH *) 0; pathptr = pathptr->next ) { + if (pathptr->dest == outptr->nlab) return(0); + } + + return(1); + +} + + + +/******************************************************************************* +* write into the file "temp9" the minimized final cover computed +* +* incrementally by "out_mini" * +*******************************************************************************/ + +final_cover6(oniptr) +OUTSYMBOL *oniptr; + +{ + + FILE *fopen(),*fp6,*fp9; + IMPLICANT *new,*newimplicant(); + char line[MAXLINE],*fgets(); + char string1[MAXLINE]; + char string2[MAXLINE]; + char string3[MAXLINE]; + char onstring[MAXLINE]; + + if ( (fp9 = fopen(temp9,"a") ) == NULL ) { + fprintf(stderr,"fopen: can't open temp9\n"); + exit(-1); + } + + if ( (fp6 = fopen(temp6,"r") ) == NULL ) { + fprintf(stderr,"fopen: can't read temp6\n"); + exit(-1); + } else { + while ( fgets(line,MAXLINE,fp6) != (char *) 0 ) { + if ( myindex(line,"# espresso") < 0 && myindex(line,".mv") < 0 && + myindex(line,".p") < 0 && myindex(line,".e") < 0 && + myindex(line,".type") < 0 ) { + sscanf(line, "%s %s %s", string1, string2, string3); + if (string3[0] == ONE) { + stron(onstring, oniptr->nlab); + onstring[oniptr->nlab] = string3[0]; + sprintf(line, "%s %s %s%s\n", string1, string2, onstring, string3+1); + fputs(line,fp9); + new = newimplicant(line,oniptr->nlab); + new->next = implicant_list; + implicant_list = new; + } + } + } + } + + fclose(fp6); + fclose(fp9); + +} + + +final_cover7(oniptr) +OUTSYMBOL *oniptr; + +{ + + FILE *fopen(),*fp7,*fp9; + IMPLICANT *new,*newimplicant(); + char line[MAXLINE],*fgets(); + char string1[MAXLINE]; + char string2[MAXLINE]; + char string3[MAXLINE]; + char onstring[MAXLINE]; + + if ( (fp9 = fopen(temp9,"a") ) == NULL ) { + fprintf(stderr,"fopen: can't open temp9\n"); + exit(-1); + } + + if ( (fp7 = fopen(temp7,"r") ) == NULL ) { + fprintf(stderr,"fopen: can't read temp7\n"); + exit(-1); + } else { + while ( fgets(line,MAXLINE,fp7) != (char *) 0 ) { + if ( myindex(line,"# espresso") < 0 && myindex(line,".mv") < 0 && + myindex(line,".p") < 0 && myindex(line,".e") < 0 ) { + sscanf(line, "%s %s %s", string1, string2, string3); + stron(onstring, oniptr->nlab); + onstring[oniptr->nlab] = string3[0]; + sprintf(line, "%s %s %s%s\n", string1, string2, onstring, string3+1); + fputs(line,fp9); + new = newimplicant(line,oniptr->nlab); + new->next = implicant_list; + implicant_list = new; + } + } + } + + fclose(fp7); + fclose(fp9); + +} + + + +int oncounter_temp7() + +{ + + FILE *fopen(),*fp7; + char line[MAXLINE],*fgets(); + char string1[MAXLINE]; + char string2[MAXLINE]; + char string3[MAXLINE]; + int counter; + + counter = 0; + + if ( (fp7 = fopen(temp7,"r") ) == NULL ) { + fprintf(stderr,"fopen: can't read temp7\n"); + exit(-1); + } else { + while ( fgets(line,MAXLINE,fp7) != (char *) 0 ) { + if ( myindex(line,"# espresso") < 0 && myindex(line,".mv") < 0 && + myindex(line,".p") < 0 && myindex(line,".e") < 0 ) { + sscanf(line, "%s %s %s", string1, string2, string3); + if ( string3[0] == ONE ) counter++; + } + } + } + + fclose(fp7); + + return(counter); + +} + + + +int count_prods(name) +char *name; +{ + + FILE *fopen(), *fpin; + char line[MAXLINE], string[MAXLINE]; + int count; + + if ((fpin = fopen(name, "r")) == NULL) { + fprintf(stderr,"fopen: can't read file temp83\n"); + exit(-1); + } + while (fgets(line, MAXLINE, fpin) != NULL) { + if (myindex(line,".p") >= 0) { + sscanf(line, "%s %d", string, &count); + break; + } + } + fclose(fpin); + + if (count == 0) return(2); + else return(1); + +} diff --git a/nova/user_codes.c b/nova/user_codes.c new file mode 100644 index 0000000..21b7d36 --- /dev/null +++ b/nova/user_codes.c @@ -0,0 +1,89 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/nova/user_codes.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +#include "nova.h" + +user_codes() + +{ + + FILE *fp , *fopen(); + char line[MAXLINE],*fgets(),name[MAXSTRING],code[MAXSTRING]; + char codefile[MAXSTRING]; + int i; + + sprintf(codefile, "%s.codes", sh_filename); + if ((fp = fopen(codefile, "r")) == NULL) { + fprintf(stderr,"Error in opening codefile\n"); + exit(-1); + } + + while (fgets(line, MAXLINE, fp) != NULL) { + if (myindex(line,"scode") >= 0) { + sscanf(line, "scode %s %s", code , name); + + for (i=0; i= 0) { + sscanf(line, "icode %s %s", code , name); + + for (i=0; i= argc) { + (void) fprintf(stderr, "%s: you must specify at least one file\n", + optProgName); + optUsage(); + } + + while (optind < argc) { + processFile(argv[optind], xFlag, yFlag, framSize, debugType, display); + optind++; + } + + exit(0); +} + +/*ARGSUSED*/ +processFile(fName, xFlag, yFlag, framSize, debugType, display) +char *fName; +int xFlag, yFlag, framSize, debugType; +char *display; +{ +} diff --git a/options/options-test.usage b/options/options-test.usage new file mode 100644 index 0000000..7679e18 --- /dev/null +++ b/options/options-test.usage @@ -0,0 +1,30 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/options/options-test.usage,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +options-test: unknown option -- j +usage: options-test [-=E on_error] [-=M mem_flags] [-xy] [-b|-k frammitz_size] + [-d debug_type] file_name ... [host:display] + -=E: cause fatal errors to core dump (on_error = "core") or exit + (on_error = "exit") + -=M: adjust memory manager behavior: mem_flags is comma-separated + list of + [no]trace turn tracing on/off + [no]trash do/don't trash freed memory + pad=n pad each block with `n' extra words + -x: flag option + -y: another flag option + -b|-k: frammitz size in 512-byte blocks (-b) or kilobytes (-k) + -d: set debug mode: (debug_type: action) + 1: flood the user with junk + 2: flood the world with junk + 3: flood the galaxy with junk + file_name: file to be processed + [host:display]: the display to use for the gratuitous menus (defaults to + the value of the environment variable $DISPLAY) +Accomplishes nothing useful at all with each file it processes diff --git a/options/options.3 b/options/options.3 new file mode 100644 index 0000000..bc33b04 --- /dev/null +++ b/options/options.3 @@ -0,0 +1,239 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/options/options.3,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:10 $ +.\" * +.\" +.TH OPTIONS 3OCTTOOLS "6 February 1989" +.de Sm +\s-2\\$1\s0\\$2 +.. +.SH NAME +options \- option parsing and usage message package +.SH SYNOPSIS +.nf +.PP +.ft B +#include +#include "options.h" +.sp +.PP +.ft B +/* defined in "options.h" */ +typedef struct { + char *optionLetters; + char *argName; + char *description; +} optionStruct; +.sp +.PP +.ft B +int optGetOption(argc, argv) +int argc; +char *argv[]; +.PP +.ft B +void optUsage() +.sp +.PP +.ft B +optionStruct optionList[]; +int optind; +char *optarg; +char *optProgName; +.SH DESCRIPTION +.PP +.I optGetOption +parses option arguments in the same style as +.IR getopt (3) +(all options are single characters; +option flags without arguments can be packed; +if an option takes an value, the +option letter and value may or may not be separated by a space; +a dummy argument, ``--'' can be used to separate options and other arguments +to resolve ambiguity). +The difference is that +.I optGetOption +looks at the global variable +.I optionList +for a list of available options and whether they take values. +Also, after the first call to +.IR optGetOption , +the global variable +.I optProgName +is set to the name of the program (this can be used in error messages +so the program user knows which program in a sequence or pipeline detected +an error). +As with +.IR getopt , +.I optind +is the index of the command-line argument following the current option +or option/value pair (after all options have been parsed, it is the +index of the first non-option argument), and +.I optarg +points to the value of an option that requires one. +Normally, one uses +.I optarg +to access an option's argument, and +.I optind +only after all options have been processed. +.PP +.I optUsage +formats and prints a usage message based on the information in +.IR optionList , +then calls +.IR exit . +.PP +.I optionList +is an array of structures, each of which describes one or more related options. +The last element of this array has a null pointer for the value of +.BR optionLetters . +For each group of options, +.B optionLetters +contains the option letter(s); +.B argName +is a descriptive name for the value taken by the option(s), +or a null or empty string for flag options; +and +.B description +is free-form text describing the option(s). +If this description is long, it will be word-wrapped as appropriate. +A newline character can be used to force a line break at some desired point. +If a description is broken across lines by either of these methods, the +continuation will be aligned under the beginning part of the description. +Several special values are defined for the +.B optionLetters +field: +.TS +l lw(40n) . +\s-1OPT_RARG\s0 T{ +\fBargName\fP is a required argument +T} +\s-1OPT_OARG\s0 T{ +\fBargName\fP is an optional argument +T} +\s-1OPT_DESC\s0 T{ +general description (\fBargName\fP is ignored) +T} +\s-1OPT_ELLIP\s0 T{ +put an ellipsis in summary line +(\fBargName\fP and \fBdescription\fP are ignored) +T} +\s-1OPT_CONT\s0 T{ +continues the description from the previous entry (the only thing this does +is let you avoid very long strings in your source code) +T} +.TE +.SH EXAMPLES +.PP +The following program, +.IR opttest, +when incorrectly called with a +.B -j +option, prints +.sp +.nf +opttest: unknown option -- j +usage: opttest [-xy] [-b|-k frammitz_size] [-d debug_type] file_name ... + [host:display] + -x: flag option + -y: another flag option + -b|-k: frammitz size in 512-byte blocks (-b) or kilobytes (-k) + -d: set debug mode: (debug_type: action) + 1: flood the user with junk + 2: flood the world with junk + 3: flood the galaxy with junk + file_name: file to be processed + [host:display]: the display to use for the gratuitous menus (defaults to + the value of the environment variable $DISPLAY) +Accomplishes nothing useful at all with each file it processes +.sp 2 +#include +#include "options.h" + +optionStruct optionList[] = { + { "x", "", "flag option" }, + { "y", "", "another flag option" }, + { "bk", "frammitz_size", + "frammitz size in 512-byte blocks (-b) or kilobytes (-k)" }, + { "d", "debug_type", "set debug mode: (debug_type: action)" }, + { OPT_CONT, 0, "\\n 1: flood the user with junk" }, + { OPT_CONT, 0, "\\n 2: flood the world with junk" }, + { OPT_CONT, 0, "\\n 3: flood the galaxy with junk" }, + { OPT_RARG, "file_name", "file to be processed" }, + { OPT_ELLIP, 0, 0 }, + { OPT_OARG, "host:display", + "the display to use for the gratuitous menus " }, + { OPT_CONT, 0, + "(defaults to the value of the environment variable $DISPLAY)" }, + { OPT_DESC, 0, + "Accomplishes nothing useful at all with each file it processes" }, + { 0, 0, 0 } +}; + +main(argc, argv) +int argc; +char *argv[]; +{ + int option; /* option letter from optGetOption */ + int xFlag = 0; /* the x flag */ + int yFlag = 0; /* the y flag */ + int framSize = 0; /* the frammitz size */ + int debugType = 0; /* quantity of debuggin info */ + char *display = ""; /* the X display */ + char *strchr(); + + while ((option = optGetOption(argc, argv)) != EOF) { + switch (option) { + case 'x': /* set x mode */ + xFlag = 1; + break; + case 'y': /* set y mode */ + yFlag = 1; + break; + case 'b': /* frammitz size in blocks */ + framSize = atoi(optarg) * 512; + break; + case 'k': /* frammitz size in K */ + framSize = atoi(optarg) * 1024; + break; + case 'd': /* set debugging type */ + debugType = atoi(optarg); + break; + default: + optUsage(); + } + } + + if (strchr(argv[argc-1], ':')) { + display = argv[--argc]; + } + + if (optind >= argc) { + (void) fprintf(stderr, "%s: you must specify at least one file\n", + optProgName); + optUsage(); + } + + while (optind < argc) { + /* processFile(argv[optind]) */ + optind++; + } + + exit(0); +} +.SH "SEE ALSO" +getopt(3) +.SH AUTHOR +Tom Laidig +.SH DIAGNOSTICS +.I optGetOption +calls +.I optUsage +for an unrecognized option, and returns +.SM EOF +to indicate the end of options. +.SH BUGS diff --git a/options/options.c b/options/options.c new file mode 100644 index 0000000..9be62fe --- /dev/null +++ b/options/options.c @@ -0,0 +1,490 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/options/options.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +#include "copyright.h" +#include "port.h" +#include "utility.h" +#include "options.h" + +static int doUnivOption(); +static void usageSummary(); +static void usageDetailed(); +static void formatInit(); +static void formatFlush(); +static void formatString(); +static void formatChar(); +static void formatTab(); +static void formatOptChoice(); + +#ifndef MM_TRACE +#define MM_PAD 0 +#define MM_TRACE 1 +#define MM_TRASH 2 +#endif + +/* dummy `optionLetters' values for arguments following options */ +/* make sure the strings are different so smart compilers don't alias them */ +char OPT_RARG[] = "r"; /* required argument */ +char OPT_OARG[] = "o"; /* optional argument */ +char OPT_ELLIP[] = "e"; /* flag to put ellipsis at end of summary */ +char OPT_DESC[] = "d"; /* overall description */ +char OPT_CONT[] = "c"; /* continues description */ + +char *optProgName = "unknown program"; +char *optarg; +int optind = 0; +static char *scanPtr; + +#define HARD_SP '\0' /* A space we don't allow to split lines */ + +#define LINEWIDTH 79 /* Maximum number of characters in a line */ +#define DETAIL_INDENT 15 /* indent of detailed option descriptions */ +#define SUMMARY_INDENT 20 /* indent of continuation of summary line */ + +static char usageProlog[LINEWIDTH] = ""; +static char *usageString = NIL(char); +static int usageStrlen = 0; + +/* The linked list of optionStruct arrays */ +struct optGroup { + optionStruct *array; + struct optGroup *next; +}; + +static struct optGroup *allOptions = NIL(struct optGroup); +static int exitBad = 1; + +#define OPT_UNIV_CHAR '=' +#define OPT_UNIV_FLAG (0200) + +static char *expandOptChar(); +/*LINTLIBRARY*/ + +optGetOption(argc, argv) +int argc; +char *argv[]; +{ + int optChar; + struct optGroup *optGrpPtr; + optionStruct *optPtr; + int doUnivOption(); + + /* initialize, if necessary */ + if (allOptions == NIL(struct optGroup)) { + optInit(argv[0], optionList, 0); + optAddUnivOptions(); + } + + optarg = NIL(char); + usageProlog[0] = '\0'; + + if (scanPtr == NIL(char) || *scanPtr == '\0') { + if ( optind >= argc || + argv[optind][0] != '-' || + strlen(argv[optind]) < 2 || + strcmp(argv[optind], "--") == 0) { + return(EOF); + } + scanPtr = &argv[optind++][1]; + } + + optChar = *scanPtr++; + if (optChar == OPT_UNIV_CHAR && *scanPtr) { + optChar = *scanPtr++ | OPT_UNIV_FLAG; + } + + for (optGrpPtr = allOptions; optGrpPtr; optGrpPtr = optGrpPtr->next) { + for (optPtr = optGrpPtr->array; optPtr->optionLetters; optPtr++) { + if (strchr(optPtr->optionLetters, optChar)) { + /* we found the option */ + /* Make sure that it is not one of those dummy options. */ + if (optPtr->optionLetters == OPT_RARG || + optPtr->optionLetters == OPT_OARG || + optPtr->optionLetters == OPT_ELLIP || + optPtr->optionLetters == OPT_DESC || + optPtr->optionLetters == OPT_CONT ) continue; /* Skip dummy opt. */ + /* OK, it is a regular option. */ + if (optPtr->argName && optPtr->argName[0] != '\0') { + /* it takes an argumment */ + optarg = (*scanPtr == '\0') ? argv[optind++] : scanPtr; + if (optarg == NIL(char)) { + (void) sprintf(usageProlog, + "%s: option %s requires an argument", + optProgName, expandOptChar(optChar)); + if (exitBad) optUsage(); + return('?'); + } + scanPtr = NIL(char); + } + if (optChar & OPT_UNIV_FLAG) { + if (doUnivOption(optChar)) { + return(optGetOption(argc, argv)); + } else { + if (exitBad) optUsage(); + return('?'); + } + } else { + return(optChar); + } + } + } + } + + (void) sprintf(usageProlog, "%s: unknown option -- %s", + optProgName, expandOptChar(optChar)); + if (exitBad) optUsage(); + return('?'); +} + +void optInit(progName, options, rtnBadFlag) +char *progName; +optionStruct options[]; +int rtnBadFlag; +{ + struct optGroup *optGrpPtr; + + while (allOptions) { + optGrpPtr = allOptions->next; + FREE(allOptions); + allOptions = optGrpPtr; + } + + /* errProgramName(optProgName = progName); */ + optAddOptions(options); + exitBad = ! rtnBadFlag; + + optind = 1; + scanPtr = NIL(char); +} + +void optAddOptions(options) +optionStruct options[]; +{ + struct optGroup *optGrpPtr; + + optGrpPtr = ALLOC(struct optGroup, 1); + optGrpPtr->next = allOptions; + optGrpPtr->array = options; + allOptions = optGrpPtr; +} + +void optAddUnivOptions() +{ +#ifndef _IBMR2 + static optionStruct univOptions[] = { + { "T", "tech_root_dir","set the technology root directory" }, + { "E", "on_error", "cause fatal errors to core dump (on_error = \"core\") or exit (on_error = \"exit\")" }, +#ifdef notdef + { "M", "mem_flags", "adjust memory manager behavior: mem_flags is comma-separated list of" }, + { OPT_CONT, 0, "\n [no]trace turn tracing on/off" }, + { OPT_CONT, 0, "\n [no]trash do/don't trash freed memory" }, + { OPT_CONT, 0, "\n pad=n pad each block with `n' extra words" }, +#endif + { 0, 0, 0 } + }; + optionStruct *optPtr; + char *cPtr; + char *tapRootDirectory(); + + for (optPtr = univOptions; optPtr->optionLetters; optPtr++) { + for (cPtr = optPtr->optionLetters; *cPtr; cPtr++) { + *cPtr |= OPT_UNIV_FLAG; + } + } + + if (tapRootDirectory(NIL(char)) == NIL(char)) { + /* tap isn't really loaded */ + optAddOptions(&univOptions[1]); + } else { + optAddOptions(univOptions); + } +#endif +} + +static int doUnivOption(optChar) +int optChar; +{ + char *tapRootDirectory(); +#ifdef notdef + int parseMMoptions(); +#endif + + switch (optChar) { + case 'T'|OPT_UNIV_FLAG: + (void) tapRootDirectory(optarg); + return(1); + case 'E'|OPT_UNIV_FLAG: + if (strcmp(optarg, "core") == 0) { + /* errCore(1); */ + return(1); + } else if (strcmp(optarg, "exit") == 0) { + /* errCore(0); */ + return(1); + } else { + (void) sprintf(usageProlog, + "%s: bad argument for option %s -- %s", + optProgName, expandOptChar(optChar), optarg); + return(0); + } +#ifdef notdef + case 'M'|OPT_UNIV_FLAG: + return(parseMMoptions()); +#endif + default: + fprintf(stderr, "unknown universal option `%c'", optChar); + exit(-1); + /*NOTREACHED*/ + } +} + +#ifdef notdef +static int parseMMoptions() +{ + char *oneOpt; + int val; + + for (oneOpt = strtok(optarg, ","); oneOpt; oneOpt = strtok(NIL(char), ",")){ + if (strcmp(oneOpt, "trace") == 0) { + mm_set(MM_TRACE, 1); + } else if (strcmp(oneOpt, "notrace") == 0) { + mm_set(MM_TRACE, 0); + } else if (strcmp(oneOpt, "trash") == 0) { + mm_set(MM_TRASH, 1); + } else if (strcmp(oneOpt, "notrash") == 0) { + mm_set(MM_TRASH, 0); + } else if (sscanf(oneOpt, " pad = %d", &val) == 1) { + mm_set(MM_PAD, val); + } else { + (void) sprintf(usageProlog, + "%s: bad memory manager flag -- %s", + optProgName, oneOpt); + } + } + return(1); +} +#endif + +void optUsage() +{ + (void) fprintf(stderr, "%s", optUsageString()); + exit(2); +} + +char *optUsageString() +{ + usageStrlen = 0; + + if (usageProlog[0] != '\0') { + formatString(usageProlog); + formatFlush(); + } + + usageSummary(); + usageDetailed(); + formatFlush(); + + return(usageString); +} + +#define START_OPTION_GROUP() if (inGroup++ == 0) { \ + formatString(" [-"); \ + } +#define FINISH_OPTION_GROUP() if (inGroup != 0) { \ + formatChar(']'); \ + inGroup = 0; \ + } + +static void +usageSummary() +{ + struct optGroup *optGrpPtr; + optionStruct *optPtr; + int inGroup = 0; + + formatInit(SUMMARY_INDENT); + formatString("usage: "); + formatString(optProgName); + for (optGrpPtr = allOptions; optGrpPtr; optGrpPtr = optGrpPtr->next) { + for (optPtr = optGrpPtr->array; optPtr->optionLetters; optPtr++) { + if (optPtr->optionLetters == OPT_DESC || + optPtr->optionLetters == OPT_CONT) { + /* descriptions don't appear in summary line */ + ; + } else if (optPtr->optionLetters == OPT_ELLIP) { + FINISH_OPTION_GROUP(); + formatString(" ..."); + } else if (optPtr->optionLetters == OPT_RARG) { + FINISH_OPTION_GROUP(); + formatChar(' '); + formatString(optPtr->argName); + } else if (optPtr->optionLetters == OPT_OARG) { + FINISH_OPTION_GROUP(); + formatString(" ["); + formatString(optPtr->argName); + formatChar(']'); + } else if (optPtr->argName && optPtr->argName[0] != '\0') { + FINISH_OPTION_GROUP(); + formatString(" ["); + formatOptChoice(optPtr->optionLetters); + formatChar(HARD_SP); + formatString(optPtr->argName); + formatChar(']'); + } else { + START_OPTION_GROUP(); + formatString(optPtr->optionLetters); + } + } + } + FINISH_OPTION_GROUP(); +} + +static void +usageDetailed() +{ + struct optGroup *optGrpPtr; + optionStruct *optPtr; + + for (optGrpPtr = allOptions; optGrpPtr; optGrpPtr = optGrpPtr->next) { + for (optPtr = optGrpPtr->array; optPtr->optionLetters; optPtr++) { + if (optPtr->optionLetters == OPT_CONT) { + formatString(optPtr->description); + } else if (optPtr->optionLetters == OPT_DESC) { + formatInit(0); + formatString(optPtr->description); + } else if (optPtr->optionLetters == OPT_ELLIP) { + /* ellipses don't appear in the detailed info */ + ; + } else { + formatInit(DETAIL_INDENT); + formatString(" "); + if (optPtr->optionLetters == OPT_RARG) { + formatString(optPtr->argName); + } else if (optPtr->optionLetters == OPT_OARG) { + formatChar('['); + formatString(optPtr->argName); + formatChar(']'); + } else { + formatOptChoice(optPtr->optionLetters); + } + formatString(": "); + formatTab(DETAIL_INDENT); + formatString(optPtr->description); + } + } + } +} + +static int curColumn = 0; +static int indent; +static char lineBuffer[LINEWIDTH]; + +static void +formatInit(contIndent) +int contIndent; +{ + if (curColumn > 0) formatFlush(); + indent = contIndent; +} + +static void +formatFlush() +{ + int i; + + usageString = REALLOC(char, usageString, usageStrlen + curColumn + 2); + for (i = 0; i < curColumn; i++) { + usageString[usageStrlen++] = (lineBuffer[i] == HARD_SP) ? + ' ' : lineBuffer[i]; + } + usageString[usageStrlen++] = '\n'; + usageString[usageStrlen] = '\0'; + curColumn = 0; +} + +static void +formatString(string) +char *string; +{ + while (*string != '\0') formatChar(*string++); +} + +static void +formatChar(ch) +int ch; +{ + if (ch == '\n') { + formatFlush(); + formatTab(indent); + } else { + if (curColumn >= LINEWIDTH) { + int i; + + /* find and mark a space for splitting the line */ + for (i = LINEWIDTH - 1; i > 0; i--) { + if (lineBuffer[i] == ' ') { + curColumn = i; + break; + } + } + formatFlush(); + + /* space out for the indent */ + formatTab(indent); + + /* copy anything that was after the line break */ + while (++i < LINEWIDTH) { + lineBuffer[curColumn++] = lineBuffer[i]; + } + } + + lineBuffer[curColumn++] = ch; + } +} + +static void +formatTab(position) +int position; +{ + if (position >= LINEWIDTH) position = LINEWIDTH - 1; + + while (curColumn < position) formatChar(' '); +} + +static void +formatOptChoice(optChars) +char *optChars; +{ + int firstFlag = 1; + + while (*optChars != '\0') { + if (firstFlag) { + firstFlag = 0; + } else { + formatChar('|'); + } + formatChar('-'); + formatString(expandOptChar(*optChars++)); + } +} + +static char *expandOptChar(optChar) +int optChar; +{ + static char string[3]; + char *cPtr; + + cPtr = string; + if (optChar & OPT_UNIV_FLAG) { + optChar &= ~OPT_UNIV_FLAG; + *cPtr++ = OPT_UNIV_CHAR; + } + *cPtr++ = optChar; + *cPtr = '\0'; + return(string); +} diff --git a/options/options.doc.src b/options/options.doc.src new file mode 100644 index 0000000..76b625e --- /dev/null +++ b/options/options.doc.src @@ -0,0 +1,163 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/options/options.doc.src,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +options - option parsing and usage message package +Tom Laidig +University of California, Berkeley + +Include in source files: + "options.h" + +Link with: + liboptions.a liberrtrap.a uprintf.a libmm.a libport.a + + +/* `optionsStruct' type defined in "options.h" */ +typedef struct { + char *optionLetters; + char *argName; + char *description; +} optionStruct; +optionStruct optionList[]; + + `optionList' is a global array of structures, each of which + describes one or more related options to the options package. + The last element of this array has a null pointer for the value + of `optionLetters'. For each group of options, `optionLetters' + contains the option letter(s); `argName' is a descriptive name + for the value taken by the option(s), or a null or empty string + for flag options; and `description' is free-form text + describing the option(s). If this description is long, it will + be word-wrapped as appropriate. A newline character can be + used to force a line break at some desired point. If a + description is broken across lines by either of these methods, + the continuation will be aligned under the beginning part of + the description. Several special values are defined for the + `optionLetters' field: + + OPT_RARG `argName' is a required argument + OPT_OARG `argName' is an optional argument + OPT_DESC general description (`argName' is ignored) + OPT_ELLIP put an ellipsis in summary line (`argName' and + `description' are ignored) + OPT_CONT continues the description from the previous + entry (the only thing this does is let you + avoid very long strings in your source code) + + If `optionList' is not defined, a dummy value describing no + options will be included from the library. + +int optGetOption(argc, argv) +int argc; +char *argv[]; + + `optGetOption' parses option arguments in the same style as + getopt(3) (all options are single characters; option flags + without arguments can be packed; if an option takes a value, + the option letter and value may or may not be separated by a + space; a dummy argument, ``--'' can be used to separate options + and other arguments to resolve ambiguity). The difference is + that `optGetOption' looks at an array of `optionStruct' + structures for a list of available options and whether they + take values. + + Unless `optInit' is called first, the first call to + `optGetOption' initializes the allowed options to those + described in the global variable `optionList' plus some + universal options (described under `optAddUnivOptions'), and + sets the program name from `argv[0]'. This includes setting + the global variable `optProgName' (which can be used in error + messages so the program user knows which program in a sequence + or pipeline detected an error) and passing the program name to + `errProgramName' (see the `errtrap' package) for use by its + error handlers. Unlike `getopt', `optGetOption' normally does + not return with an invalid option; instead, it calls + `optUsage', which prints a usage message and exits. This + behavior can be changed by calling `optInit'. + + Like `getopt', `optGetOption' returns the current option letter + (or EOF, if all options have been processed), sets `optind' to + the index of the command-line argument following the current + option or option/value pair (after all options have been + parsed, it is the index of the first non-option argument), and + sets `optarg' to point to the value of an option that requires + one. Normally, one uses `optarg' to access an option's + argument, and `optind' only after all options have been + processed. + +void optUsage() + + `optUsage' formats and prints a usage message based on the + information in `optionList' (or the result of calls to + `optInit', `optAddOptions', and `optAddUnivOptions'), then + calls `exit' with a return code of 2. Note that the usage + message includes the name of the program, so `optGetOption' + or `optInit' should be called at least once before calling + `optUsage'. + +int optind; +char *optarg; +char *optProgName; + + These global variables are declared and set by the options + package. See the description for `optGetOption'. + + +/* + * The following functions give tool writers more control of + * the options package. They are expected not to be used often. + */ + +void optInit(progName, options, rtnBadFlag) +char *progName; +optStruct options[]; +int rtnBadFlag; + + This function sets the program name to `progName' (setting + `optProgName' and calling `errProgramName') and sets the list + of available options to those described by `options' (an array + of option descriptions in the form of `optionList'). If + `rtnBadFlag' is non-zero, `optGetOption' will return '?' if an + unrecognized option is encountered; otherwise, it will call + `optUsage'. This function can be called at any time, to change + the list of available options. + +void optAddOptions(options) +optionStruct options[]; + + This function adds the options described in `options' (an array + of option descriptions in the form of `optionList') to the list + of available options. + +void optAddUnivOptions() + + This function adds `universal' options to the list of available + options. These options are ones that are common to all (?) oct + tools, and are distinguished from other command-line options by + being preceeded by `-=' instead of `-'. These options are: + + -=T tech_root: set the technology root directory (see + the `tap' package) if tap is used + + -=E on_error: arrange for fatal errors detected by the + `errtrap' package to exit (on_error = + "exit") or dump core (on_error = "core") + + -=M mem_flags: `mem_flags' is a comma-separated list of + flags that adjust the behavior of the + memory allocator (see the `mm' package): + [no]trace turn tracing on/off + [no]trash do/don't trash freed memory + pad=n allocate `n' extra words + + -=R: (reserved for rpc) + +char *optUsageString() + + Returns the string that `optUsage' would print. diff --git a/options/options.h b/options/options.h new file mode 100644 index 0000000..6e803ba --- /dev/null +++ b/options/options.h @@ -0,0 +1,48 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/options/options.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:10 $ + * + */ +#ifndef OPT_H +#define OPT_H + +#include "ansi.h" + +#define OPT_PKG_NAME "options" + +typedef struct { + char *optionLetters; + char *argName; + char *description; +} optionStruct; + +/* dummy `optionLetters' values for arguments following options */ +extern char OPT_RARG[]; /* required argument */ +extern char OPT_OARG[]; /* optional argument */ +extern char OPT_ELLIP[]; /* flag to put ellipsis in summary */ +extern char OPT_DESC[]; /* general description */ +extern char OPT_CONT[]; /* continues description */ + +extern optionStruct optionList[]; +extern int optind; +extern char *optarg; +extern char *optProgName; + +EXTERN int optGetOption + ARGS((int argc, char **argv)); +EXTERN void optUsage + NULLARGS; +EXTERN void optInit + ARGS((char *progName, optionStruct options[], int rtnBadFlag)); +EXTERN void optAddOptions + ARGS((optionStruct options[])); +EXTERN void optAddUnivOptions + NULLARGS; +EXTERN char *optUsageString + NULLARGS; + +#endif /* OPT_H */ diff --git a/port/Makefile.am b/port/Makefile.am new file mode 100644 index 0000000..8f573b8 --- /dev/null +++ b/port/Makefile.am @@ -0,0 +1 @@ +noinst_HEADERS = ansi.h autoconf.h copyright.h port.h regex.h diff --git a/port/Makefile.in b/port/Makefile.in new file mode 100644 index 0000000..44fe3a9 --- /dev/null +++ b/port/Makefile.in @@ -0,0 +1,330 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = port +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +noinst_HEADERS = ansi.h autoconf.h copyright.h port.h regex.h +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps port/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps port/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + ctags distclean distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags uninstall uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/port/ansi.h b/port/ansi.h new file mode 100644 index 0000000..53f16c0 --- /dev/null +++ b/port/ansi.h @@ -0,0 +1,53 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/port/ansi.h,v $ + * $Author: pchong $ + * $Revision: 1.3 $ + * $Date: 2004/03/14 04:06:00 $ + * + */ +#ifndef ANSI_H +#define ANSI_H + +/* + * ANSI Compiler Support + * + * David Harrison + * University of California, Berkeley + * 1988 + * + * ANSI compatible compilers are supposed to define the preprocessor + * directive __STDC__. Based on this directive, this file defines + * certain ANSI specific macros. + * + * ARGS: + * Used in function prototypes. Example: + * extern int foo + * ARGS((char *, double)); + */ + +/* Function prototypes */ +#if defined(__STDC__) || defined(__cplusplus) +#define ARGS(args) args +#else +#define ARGS(args) () +#endif + +#if defined(__cplusplus) +#define NULLARGS (void) +#else +#define NULLARGS () +#endif + +#ifdef __cplusplus +#define EXTERN extern "C" +#else +#define EXTERN extern +#endif + +#if defined(__cplusplus) || defined(__STDC__) +#define HAS_STDARG +#endif + +#endif diff --git a/port/autoconf.h b/port/autoconf.h new file mode 100644 index 0000000..e45b6e9 --- /dev/null +++ b/port/autoconf.h @@ -0,0 +1,56 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/port/autoconf.h,v $ + * $Author: pchong $ + * $Revision: 1.3 $ + * $Date: 2004/03/27 11:01:36 $ + * + */ +#ifndef AUTOCONF_H +#define AUTOCONF_H + +#include "config.h" + +#include + +#if HAVE_SYS_WAIT_H +#include +#endif + +#if HAVE_UNISTD_H +#include +#endif + +#if defined(_POSIX_VERSION) +#define RETWAITTYPE int +#undef wait3 +#define wait3(x,y,z) waitpid(0,(x),(y)); +#else +#define RETWAITTYPE union wait +#endif + +#if HAVE_DIRENT_H +#include +#define NAMLEN(dirent) strlen((dirent)->d_name) +#else +#define dirent direct +#define NAMLEN(dirent) (dirent)->d_namlen +#if HAVE_SYS_NDIR_H +#include +#endif +#if HAVE_SYS_DIR_H +#include +#endif +#if HAVE_NDIR_H +#include +#endif +#endif + +#if defined(_POSIX_VERSION) || defined(__CYGWIN__) +#define USE_TERMIO +#else +#undef USE_TERMIO +#endif + +#endif /* AUTOCONF_H */ diff --git a/port/copyright.h b/port/copyright.h new file mode 100644 index 0000000..8a43913 --- /dev/null +++ b/port/copyright.h @@ -0,0 +1,38 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/port/copyright.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#ifndef OCTTOOLS_COPYRIGHT_H +#define OCTTOOLS_COPYRIGHT_H +/* + * Oct Tools Distribution 4.0 + * + * Copyright (c) 1988, 1989, 1990, Regents of the University of California. + * All rights reserved. + * + * Use and copying of this software and preparation of derivative works + * based upon this software are permitted. However, any distribution of + * this software or derivative works must include the above copyright + * notice. + * + * This software is made available AS IS, and neither the Electronics + * Research Laboratory or the University of California make any + * warranty about the software, its performance or its conformity to + * any specification. + * + * Suggestions, comments, or improvements are welcome and should be + * addressed to: + * + * octtools@eros.berkeley.edu + * ..!ucbvax!eros!octtools + */ + +#if !defined(lint) && !defined(SABER) +static char octtools_copyright[] = "Copyright (c) 1988, 1989, Regents of the University of California. All rights reserved."; +#endif +#endif diff --git a/port/port.h b/port/port.h new file mode 100644 index 0000000..981df8b --- /dev/null +++ b/port/port.h @@ -0,0 +1,289 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/port/port.h,v $ + * $Author: pchong $ + * $Revision: 1.3 $ + * $Date: 2004/03/27 10:33:57 $ + * + */ +#ifndef PORT_H +#define PORT_H + +#ifdef SABER +#define volatile +#endif + +#ifdef _IBMR2 +#define _BSD +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE /* Argh! IBM strikes again */ +#endif +#ifndef _ALL_SOURCE +#define _ALL_SOURCE /* Argh! IBM strikes again */ +#endif +#ifndef _ANSI_C_SOURCE +#define _ANSI_C_SOURCE /* Argh! IBM strikes again */ +#endif +#endif + +/* + * int32 should be defined as the most economical sized integer capable of + * holding a 32 bit quantity + * int16 should be similarly defined + */ + +/* XXX hack */ +#ifndef MACHDEP_INCLUDED +#define MACHDEP_INCLUDED +#ifdef vax +typedef int int32; +typedef short int16; +#else + /* Ansi-C promises that these definitions should always work */ +typedef long int32; +typedef int int16; +#endif /* vax */ +#endif /* MACHDEP_INCLUDED */ + + +/* + * Do not do anything if already somebody else is doing it. + * _std_h is defined by the g++ std.h file + * __STDC__ + */ +#if !defined(__STDC__) && !defined(_std_h) + + +#ifndef __DATE__ +#ifdef CUR_DATE +#define __DATE__ CUR_DATE +#else +#define __DATE__ "unknown-date" +#endif /* CUR_DATE */ +#endif /* __DATE__ */ + +#ifndef __TIME__ +#ifdef CUR_TIME +#define __TIME__ CUR_TIME +#else +#define __TIME__ "unknown-time" +#endif /* CUR_TIME */ +#endif /* __TIME__ */ +#endif /* __STDC__ */ + +#ifdef sun386 +#define PORTAR +#endif + +#include +#include +#include +#undef HUGE +#include +#include + +#if defined(ultrix) /* { */ +#if defined(_SIZE_T_) /* { */ +#define ultrix4 +#else /* } else { */ +#if defined(SIGLOST) /* { */ +#define ultrix3 +#else /* } else { */ +#define ultrix2 +#endif /* } */ +#endif /* } */ +#endif /* } */ + +#if defined(ultrix3) && defined(mips) +extern double rint(); +extern double trunc(); +#endif + +#if defined(sun) && defined(FD_SETSIZE) +#define sunos4 +#else +#define sunos3 +#endif + +#if defined(sequent) || defined(news800) +#define LACK_SYS5 +#endif + +#if defined(ultrix3) || defined(sunos4) || defined(_IBMR2) || defined(ultrix4) || defined(__osf__) +#define SIGNAL_FN void +#else +/* sequent, ultrix2, 4.3BSD (vax, hp), sunos3 */ +#define SIGNAL_FN int +#endif + + +/* Some systems have 'fixed' certain functions which used to be int */ +#if defined(ultrix) || defined(SABER) || defined(__hpux) || defined(aiws) || defined(apollo) || defined(AIX) || defined(__STDC__) +#define VOID_HACK void +#else +#define VOID_HACK int +#endif + +#ifndef NULL +#define NULL 0 +#endif /* NULL */ + +/* + * CHARBITS should be defined only if the compiler lacks "unsigned char". + * It should be a mask, e.g. 0377 for an 8-bit machine. + */ + +#ifndef CHARBITS +# define UNSCHAR(c) ((unsigned char)(c)) +#else +# define UNSCHAR(c) ((c)&CHARBITS) +#endif + +#define SIZET int + +#ifdef __STDC__ +#define CONST const +#define VOIDSTAR void * +#else +#define CONST +#define VOIDSTAR char * +#endif /* __STDC__ */ + + +/* Some machines fail to define some functions in stdio.h */ +#if !defined(__STDC__) && !defined(sprite) +extern FILE *popen(), *tmpfile(); +extern int pclose(); +#ifndef clearerr /* is a macro on many machines, but not all */ +extern VOID_HACK clearerr(); +#endif /* clearerr */ +#ifndef _IBMR2 +#ifndef __osf__ +#ifndef rewind +extern VOID_HACK rewind(); +#endif /* rewind */ +#endif /* __osf__ */ +#endif /* _IBMR2 */ +#endif /* __STDC__ */ + + +/* most machines don't give us a header file for these */ +#if defined(__STDC__) || defined(sprite) || defined(__osf__) || defined(__hpux) +#include +#if defined(__hpux) +#include /* For perror() defininition */ +#endif /* __hpux */ +#else +#ifdef _IBMR2 +extern int abort(), exit(); +extern void free(), perror(); +#else +extern VOID_HACK abort(), free(), exit(), perror(); +#endif +extern char *getenv(); +#ifdef ultrix4 +extern void *malloc(), *realloc(), *calloc(); +#else +extern char *malloc(), *realloc(), *calloc(); +#endif +#if defined(aiws) +extern int sprintf(); +#else +#ifndef _IBMR2 +extern char *sprintf(); +#endif +#endif +extern int system(); +extern double atof(); +extern long atol(); +#ifndef _IBMR2 +extern int sscanf(); +#endif +#endif /* __STDC__ */ + + +/* some call it strings.h, some call it string.h; others, also have memory.h */ +#if defined(__STDC__) || defined(sprite) +#include +#else +/* ANSI C string.h -- 1/11/88 Draft Standard */ +#if defined(ultrix4) || defined(__hpux) +#include +#else +extern char *strcpy(), *strncpy(), *strcat(), *strncat(), *strerror(); +extern char *strpbrk(), *strtok(), *strchr(), *strrchr(), *strstr(); +extern int strcoll(), strxfrm(), strncmp(), strlen(), strspn(), strcspn(); +extern char *memmove(), *memccpy(), *memchr(), *memcpy(), *memset(); +extern int memcmp(), strcmp(); +#endif /* ultrix4 */ +#endif /* __STDC__ */ + +#ifdef lint +#undef putc /* correct lint '_flsbuf' bug */ +#endif /* lint */ + +/* a few extras */ +#if ! defined(_std_h) +#if defined(__hpux) +#define random() lrand48() +#define srandom(a) srand48(a) +#define bzero(a,b) memset(a, 0, b) +#else +#if !defined(__osf__) && !defined(__CYGWIN__) +extern VOID_HACK srandom(); +extern long random(); +#endif +#endif +#endif /* _std_h */ + +/* assertion macro */ +#ifndef assert +#if defined(__STDC__) || defined(sprite) +#include +#else +#ifndef NDEBUG +#define assert(ex) {\ + if (! (ex)) {\ + (void) fprintf(stderr, "Assertion failed: file %s, line %d\n",\ + __FILE__, __LINE__);\ + (void) fflush(stdout);\ + abort();\ + }\ +} +#else +#define assert(ex) {;} +#endif +#endif +#endif + +/* handle the various limits */ +#if defined(__STDC__) || defined(POSIX) +#include +#else +#ifndef _IBMR2 +#ifndef __osf__ +#define USHRT_MAX (~ (unsigned short int) 0) +#define UINT_MAX (~ (unsigned int) 0) +#define ULONG_MAX (~ (unsigned long int) 0) +#define SHRT_MAX ((short int) (USHRT_MAX >> 1)) +#define INT_MAX ((int) (UINT_MAX >> 1)) +#define LONG_MAX ((long int) (ULONG_MAX >> 1)) +#endif +#endif +#endif + +/* +* +*/ + + + +#ifdef sequent +#define SIG_FLAGS(s) (s).sv_onstack +#else +#define SIG_FLAGS(s) (s).sv_flags +#endif + +#endif /* PORT_H */ + diff --git a/port/regex.h b/port/regex.h new file mode 100644 index 0000000..2acb6ea --- /dev/null +++ b/port/regex.h @@ -0,0 +1,278 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/port/regex.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#if defined(__hpux) +/* Definitions for data structures callers pass the regex library. + Copyright (C) 1985 Free Software Foundation, Inc. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS 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. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1985 Free Software Foundation, Inc."; and include following the +copyright notice a verbatim copy of the above disclaimer of warranty +and of this License. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of this source file 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 or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution 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 unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute this 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 + shipping charge) 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.) + +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. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of this program into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We 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. + + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + + +/* Define number of parens for which we record the beginnings and ends. + This affects how much space the `struct re_registers' type takes up. */ +#ifndef RE_NREGS +#define RE_NREGS 10 +#endif + +/* These bits are used in the obscure_syntax variable to choose among + alternative regexp syntaxes. */ + +/* 1 means plain parentheses serve as grouping, and backslash + parentheses are needed for literal searching. + 0 means backslash-parentheses are grouping, and plain parentheses + are for literal searching. */ +#define RE_NO_BK_PARENS 1 + +/* 1 means plain | serves as the "or"-operator, and \| is a literal. + 0 means \| serves as the "or"-operator, and | is a literal. */ +#define RE_NO_BK_VBAR 2 + +/* 0 means plain + or ? serves as an operator, and \+, \? are literals. + 1 means \+, \? are operators and plain +, ? are literals. */ +#define RE_BK_PLUS_QM 4 + +/* 1 means | binds tighter than ^ or $. + 0 means the contrary. */ +#define RE_TIGHT_VBAR 8 + +/* 1 means treat \n as an _OR operator + 0 means treat it as a normal character */ +#define RE_NEWLINE_OR 16 + +/* 0 means that a special characters (such as *, ^, and $) always have + their special meaning regardless of the surrounding context. + 1 means that special characters may act as normal characters in some + contexts. Specifically, this applies to: + ^ - only special at the beginning, or after ( or | + $ - only special at the end, or before ) or | + *, +, ? - only special when not after the beginning, (, or | */ +#define RE_CONTEXT_INDEP_OPS 32 + +/* Now define combinations of bits for the standard possibilities. */ +#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS) +#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR) +#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR) +#define RE_SYNTAX_EMACS 0 + +/* This data structure is used to represent a compiled pattern. */ + +struct re_pattern_buffer + { + char *buffer; /* Space holding the compiled pattern commands. */ + int allocated; /* Size of space that buffer points to */ + int used; /* Length of portion of buffer actually occupied */ + char *fastmap; /* Pointer to fastmap, if any, or zero if none. */ + /* re_search uses the fastmap, if there is one, + to skip quickly over totally implausible characters */ + char *translate; /* Translate table to apply to all characters before comparing. + Or zero for no translation. + The translation is applied to a pattern when it is compiled + and to data when it is matched. */ + char fastmap_accurate; + /* Set to zero when a new pattern is stored, + set to one when the fastmap is updated from it. */ + char can_be_null; /* Set to one by compiling fastmap + if this pattern might match the null string. + It does not necessarily match the null string + in that case, but if this is zero, it cannot. + 2 as value means can match null string + but at end of range or before a character + listed in the fastmap. */ + }; + +/* Structure to store "register" contents data in. + + Pass the address of such a structure as an argument to re_match, etc., + if you want this information back. + + start[i] and end[i] record the string matched by \( ... \) grouping i, + for i from 1 to RE_NREGS - 1. + start[0] and end[0] record the entire string matched. */ + +struct re_registers + { + int start[RE_NREGS]; + int end[RE_NREGS]; + }; + +/* These are the command codes that appear in compiled regular expressions, one per byte. + Some command codes are followed by argument bytes. + A command code can specify any interpretation whatever for its arguments. + Zero-bytes may appear in the compiled regular expression. */ + +enum regexpcode + { + unused, + exactn, /* followed by one byte giving n, and then by n literal bytes */ + begline, /* fails unless at beginning of line */ + endline, /* fails unless at end of line */ + jump, /* followed by two bytes giving relative address to jump to */ + on_failure_jump, /* followed by two bytes giving relative address of place + to resume at in case of failure. */ + finalize_jump, /* Throw away latest failure point and then jump to address. */ + maybe_finalize_jump, /* Like jump but finalize if safe to do so. + This is used to jump back to the beginning + of a repeat. If the command that follows + this jump is clearly incompatible with the + one at the beginning of the repeat, such that + we can be sure that there is no use backtracking + out of repetitions already completed, + then we finalize. */ + dummy_failure_jump, /* jump, and push a dummy failure point. + This failure point will be thrown away + if an attempt is made to use it for a failure. + A + construct makes this before the first repeat. */ + anychar, /* matches any one character */ + charset, /* matches any one char belonging to specified set. + First following byte is # bitmap bytes. + Then come bytes for a bit-map saying which chars are in. + Bits in each byte are ordered low-bit-first. + A character is in the set if its bit is 1. + A character too large to have a bit in the map + is automatically not in the set */ + charset_not, /* similar but match any character that is NOT one of those specified */ + start_memory, /* starts remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + stop_memory, /* stops remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + duplicate, /* match a duplicate of something remembered. + Followed by one byte containing the index of the memory register. */ + before_dot, /* Succeeds if before dot */ + at_dot, /* Succeeds if at dot */ + after_dot, /* Succeeds if after dot */ + begbuf, /* Succeeds if at beginning of buffer */ + endbuf, /* Succeeds if at end of buffer */ + wordchar, /* Matches any word-constituent character */ + notwordchar, /* Matches any char that is not a word-constituent */ + wordbeg, /* Succeeds if at word beginning */ + wordend, /* Succeeds if at word end */ + wordbound, /* Succeeds if at a word boundary */ + notwordbound, /* Succeeds if not at a word boundary */ + syntaxspec, /* Matches any character whose syntax is specified. + followed by a byte which contains a syntax code, Sword or such like */ + notsyntaxspec /* Matches any character whose syntax differs from the specified. */ + }; + +extern char *re_compile_pattern (); +/* Is this really advertised? */ +extern void re_compile_fastmap (); +extern int re_search (), re_search_2 (); +extern int re_match (), re_match_2 (); + +/* 4.2 bsd compatibility (yuck) */ +extern char *re_comp (); +extern int re_exec (); + +#ifdef SYNTAX_TABLE +extern char *re_syntax_table; +#endif +#endif diff --git a/sis/Makefile.am b/sis/Makefile.am new file mode 100644 index 0000000..4531ea6 --- /dev/null +++ b/sis/Makefile.am @@ -0,0 +1,84 @@ +SUBDIRS = include \ + array astg atpg avl bdd_cmu bdd_cudd bdd_ucb clock command decomp \ + delay doc enc error espresso extract factor gcd genlib graph graphics \ + io latch linsolv list lsort main map maxflow mincov minimize network \ + node ntbdd octio order phase pld power resub retime seqbdd sim \ + simplify sis_lib sparse speed st stg test timing util var_set + +if SIS_COND_CMUBDD +SIS_BDD_LIBS= bdd_cmu/bdd_cmu/libbdd_cmu.a \ + bdd_cmu/bdd_port/libbdd_port.a \ + bdd_cmu/mem/libmem.a \ + st/libst.a +endif +if SIS_COND_UCBBDD +SIS_BDD_LIBS = bdd_ucb/libbdd_ucb.a \ + st/libst.a +endif +if SIS_COND_CUDD +SIS_BDD_LIBS = bdd_cudd/libbdd_cudd.a \ + bdd_cudd/libcudd_mtr.a \ + bdd_cudd/libcudd_st.a +endif + +lib_LIBRARIES = libsis.a +libsis_a_SOURCES = +libsis_a_DEPENDENCIES = array/libarray.a \ + astg/libastg.a \ + atpg/libatpg.a \ + avl/libavl.a \ + clock/libclock.a \ + command/libcommand.a \ + decomp/libdecomp.a \ + delay/libdelay.a \ + enc/libenc.a \ + error/liberror.a \ + espresso/libespresso.a \ + extract/libextract.a \ + factor/libfactor.a \ + gcd/libgcd.a \ + genlib/libgenlib.a \ + graph/libgraph.a \ + graphics/libgraphics.a \ + io/libio.a \ + latch/liblatch.a \ + linsolv/liblinsolv.a \ + list/liblist.a \ + main/libmain.a \ + map/libmap.a \ + maxflow/libmaxflow.a \ + mincov/libmincov.a \ + minimize/libminimize.a \ + network/libnetwork.a \ + node/libnode.a \ + ntbdd/libntbdd.a \ + order/liborder.a \ + phase/libphase.a \ + pld/libpld.a \ + power/libpower.a \ + resub/libresub.a \ + retime/libretime.a \ + seqbdd/libseqbdd.a \ + sim/libsim.a \ + simplify/libsimplify.a \ + sparse/libsparse.a \ + speed/libspeed.a \ + stg/libstg.a \ + test/libtest.a \ + timing/libtiming.a \ + util/libutil.a \ + var_set/libvar_set.a \ + $(SIS_BDD_LIBS) + +libsis.a: $(libsis_a_DEPENDENCIES) + $(RM) $@ + for I in $^ ; do \ + $(RM) -r workdir && mkdir workdir && cd workdir \ + && $(AR) x ../$$I && $(AR) r ../$@ * \ + && cd .. && $(RM) -r workdir ; \ + done + $(RANLIB) $@ + +bin_PROGRAMS = sis +sis_SOURCES = +sis_LDADD = libsis.a -lm diff --git a/sis/Makefile.in b/sis/Makefile.in new file mode 100644 index 0000000..e9f7675 --- /dev/null +++ b/sis/Makefile.in @@ -0,0 +1,595 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +SOURCES = $(libsis_a_SOURCES) $(sis_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = sis$(EXEEXT) +subdir = sis +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" +libLIBRARIES_INSTALL = $(INSTALL_DATA) +LIBRARIES = $(lib_LIBRARIES) +libsis_a_AR = $(AR) $(ARFLAGS) +libsis_a_LIBADD = +am_libsis_a_OBJECTS = +libsis_a_OBJECTS = $(am_libsis_a_OBJECTS) +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_sis_OBJECTS = +sis_OBJECTS = $(am_sis_OBJECTS) +sis_DEPENDENCIES = libsis.a +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libsis_a_SOURCES) $(sis_SOURCES) +DIST_SOURCES = $(libsis_a_SOURCES) $(sis_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +SUBDIRS = include \ + array astg atpg avl bdd_cmu bdd_cudd bdd_ucb clock command decomp \ + delay doc enc error espresso extract factor gcd genlib graph graphics \ + io latch linsolv list lsort main map maxflow mincov minimize network \ + node ntbdd octio order phase pld power resub retime seqbdd sim \ + simplify sis_lib sparse speed st stg test timing util var_set + +@SIS_COND_CMUBDD_TRUE@SIS_BDD_LIBS = bdd_cmu/bdd_cmu/libbdd_cmu.a \ +@SIS_COND_CMUBDD_TRUE@ bdd_cmu/bdd_port/libbdd_port.a \ +@SIS_COND_CMUBDD_TRUE@ bdd_cmu/mem/libmem.a \ +@SIS_COND_CMUBDD_TRUE@ st/libst.a + +@SIS_COND_CUDD_TRUE@SIS_BDD_LIBS = bdd_cudd/libbdd_cudd.a \ +@SIS_COND_CUDD_TRUE@ bdd_cudd/libcudd_mtr.a \ +@SIS_COND_CUDD_TRUE@ bdd_cudd/libcudd_st.a + +@SIS_COND_UCBBDD_TRUE@SIS_BDD_LIBS = bdd_ucb/libbdd_ucb.a \ +@SIS_COND_UCBBDD_TRUE@ st/libst.a + +lib_LIBRARIES = libsis.a +libsis_a_SOURCES = +libsis_a_DEPENDENCIES = array/libarray.a \ + astg/libastg.a \ + atpg/libatpg.a \ + avl/libavl.a \ + clock/libclock.a \ + command/libcommand.a \ + decomp/libdecomp.a \ + delay/libdelay.a \ + enc/libenc.a \ + error/liberror.a \ + espresso/libespresso.a \ + extract/libextract.a \ + factor/libfactor.a \ + gcd/libgcd.a \ + genlib/libgenlib.a \ + graph/libgraph.a \ + graphics/libgraphics.a \ + io/libio.a \ + latch/liblatch.a \ + linsolv/liblinsolv.a \ + list/liblist.a \ + main/libmain.a \ + map/libmap.a \ + maxflow/libmaxflow.a \ + mincov/libmincov.a \ + minimize/libminimize.a \ + network/libnetwork.a \ + node/libnode.a \ + ntbdd/libntbdd.a \ + order/liborder.a \ + phase/libphase.a \ + pld/libpld.a \ + power/libpower.a \ + resub/libresub.a \ + retime/libretime.a \ + seqbdd/libseqbdd.a \ + sim/libsim.a \ + simplify/libsimplify.a \ + sparse/libsparse.a \ + speed/libspeed.a \ + stg/libstg.a \ + test/libtest.a \ + timing/libtiming.a \ + util/libutil.a \ + var_set/libvar_set.a \ + $(SIS_BDD_LIBS) + +sis_SOURCES = +sis_LDADD = libsis.a -lm +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLIBRARIES: $(lib_LIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(libLIBRARIES_INSTALL) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(libLIBRARIES_INSTALL) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + @$(POST_INSTALL) + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + p="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(RANLIB) '$(DESTDIR)$(libdir)/$$p'"; \ + $(RANLIB) "$(DESTDIR)$(libdir)/$$p"; \ + else :; fi; \ + done + +uninstall-libLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LIBRARIES)'; for p in $$list; do \ + p="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLIBRARIES: + -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +sis$(EXEEXT): $(sis_OBJECTS) $(sis_DEPENDENCIES) + @rm -f sis$(EXEEXT) + $(LINK) $(sis_LDFLAGS) $(sis_OBJECTS) $(sis_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || mkdir "$(distdir)/$$subdir" \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="../$(top_distdir)" \ + distdir="../$(distdir)/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LIBRARIES) $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-libLIBRARIES \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS install-libLIBRARIES + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am \ + uninstall-libLIBRARIES + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-binPROGRAMS clean-generic clean-libLIBRARIES \ + clean-recursive ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-recursive \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-libLIBRARIES install-man install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-recursive pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-info-am uninstall-libLIBRARIES + + +libsis.a: $(libsis_a_DEPENDENCIES) + $(RM) $@ + for I in $^ ; do \ + $(RM) -r workdir && mkdir workdir && cd workdir \ + && $(AR) x ../$$I && $(AR) r ../$@ * \ + && cd .. && $(RM) -r workdir ; \ + done + $(RANLIB) $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/array/Makefile.am b/sis/array/Makefile.am new file mode 100644 index 0000000..4d56918 --- /dev/null +++ b/sis/array/Makefile.am @@ -0,0 +1,9 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libarray.a +libarray_a_SOURCES = array.c +pkginclude_HEADERS = array.h +dist_doc_DATA = array.doc + +EXTRA_DIST = arr_main.c diff --git a/sis/array/Makefile.in b/sis/array/Makefile.in new file mode 100644 index 0000000..abf3008 --- /dev/null +++ b/sis/array/Makefile.in @@ -0,0 +1,419 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libarray_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/array +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libarray_a_AR = $(AR) $(ARFLAGS) +libarray_a_LIBADD = +am_libarray_a_OBJECTS = array.$(OBJEXT) +libarray_a_OBJECTS = $(am_libarray_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libarray_a_SOURCES) +DIST_SOURCES = $(libarray_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libarray.a +libarray_a_SOURCES = array.c +pkginclude_HEADERS = array.h +dist_doc_DATA = array.doc +EXTRA_DIST = arr_main.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/array/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/array/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libarray.a: $(libarray_a_OBJECTS) $(libarray_a_DEPENDENCIES) + -rm -f libarray.a + $(libarray_a_AR) libarray.a $(libarray_a_OBJECTS) $(libarray_a_LIBADD) + $(RANLIB) libarray.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/array/arr_main.c b/sis/array/arr_main.c new file mode 100644 index 0000000..4e867ce --- /dev/null +++ b/sis/array/arr_main.c @@ -0,0 +1,182 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/array/arr_main.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +#include +#include "util.h" +#include "array.h" + +extern long random(); +extern void srandom(); + +static int count; /* global: count # compares */ + + +static int +compare(a, b) +char **a, **b; +{ + count++; + return *(int *) a - * (int *) b; +} + + +static void +print(s, a) +char *s; +array_t *a; +{ + int i; + + (void) printf("%s\n", s); + for(i = 0; i < array_n(a); i++) { + (void) printf(" %d", array_fetch(int, a, i)); + } + (void) printf("\n"); +} + + +#define IN_ORDER 1 +#define REVERSE_ORDER 2 +#define RANDOM 3 +#define RANDOM_RANGE 4 + + +void +usage(prog) +char *prog; +{ + (void) fprintf(stderr, "%s: check out the array package\n", prog); + (void) fprintf(stderr, "\t-o\tinitial data in order\n"); + (void) fprintf(stderr, "\t-r\tinitial data in reverse order\n"); + (void) fprintf(stderr, "\t-n #\tnumber of values to sort\n"); + (void) fprintf(stderr, "\t-b #\tmaximum value for the random values\n"); + exit(2); +} + +int +main(argc, argv) +int argc; +char *argv[]; +{ + long time; + array_t *a, *a1; + int *b, i, n, type, c, range, value; + + type = RANDOM_RANGE; + range = 10; + n = 15; + while ((c = util_getopt(argc, argv, "b:orn:")) != EOF) { + switch (c) { + case 'o': + type = IN_ORDER; + break; + case 'r': + type = REVERSE_ORDER; + break; + case 'n': + n = atoi(util_optarg); + break; + case 'b': + type = RANDOM_RANGE; + range = atoi(util_optarg); + break; + default: + usage(argv[0]); + break; + } + } + + if (util_optind != argc) { + usage(argv[0]); + } + + /* + * create the input-data + */ + srandom(1); + time = util_cpu_time(); + a = array_alloc(int, 0); + for(i = 0; i < n; i++) { + if (type == IN_ORDER) { + value = i; + } else if (type == REVERSE_ORDER) { + value = n - i; + } else if (type == RANDOM_RANGE) { + value = random() % range; + } else { + value = random(); + } + array_insert(int, a, i, value); + if (n < 20) (void) printf(" %d", value); + } + (void) printf("\nfill: %d objects, time was %s\n", + array_n(a), util_print_time(util_cpu_time()-time)); + if (n < 20) print("unsorted list", a); + + + /* + * time a fill using normal subscripted arrays + */ + srandom(1); + time = util_cpu_time(); + b = ALLOC(int, n); + for(i = 0; i < n; i++) { + if (type == IN_ORDER) { + value = i; + } else if (type == REVERSE_ORDER) { + value = n - i; + } else if (type == RANDOM_RANGE) { + value = random() % range; + } else { + value = random(); + } + b[i] = value; + } + (void) printf("fill (fast): %d objects, time was %s\n", + array_n(a), util_print_time(util_cpu_time()-time)); + + /* + * now a quick check of append() and insert_last() + */ + a1 = array_alloc(int, 5); + array_insert_last(int, a1, 2); + array_insert_last(int, a1, 1); + array_insert_last(int, a1, 0); + if (n < 20) print("unsorted list1", a1); + array_append(a, a1); + (void) printf("after join: %d objects, time was %s\n", + array_n(a), util_print_time(util_cpu_time()-time)); + if (n < 20) print("unsorted list (after join)", a); + array_free(a1); + + + + /* + * Test the sorter + */ + count = 0; + time = util_cpu_time(); + array_sort(a, compare); + (void) printf("sort: %d objects, %d compares, time was %s\n", + array_n(a), count, util_print_time(util_cpu_time()-time)); + if (n < 20) print("sorted list", a); + + + /* + * Try the uniq + */ + count = 0; + time = util_cpu_time(); + array_uniq(a, compare, (void (*)()) 0); + (void) printf("uniq: %d objects, %d compares, time was %s\n", + array_n(a), count, util_print_time(util_cpu_time()-time)); + if (n < 20) print("uniq list", a); + + return 0; +} diff --git a/sis/array/array.c b/sis/array/array.c new file mode 100644 index 0000000..f080300 --- /dev/null +++ b/sis/array/array.c @@ -0,0 +1,230 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/array/array.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +/* LINTLIBRARY */ + +#include +#include "util.h" +#include "array.h" + +#define INIT_SIZE 3 + +unsigned int array_global_index; + +array_t * +array_do_alloc(size, number) +int size; +int number; +{ + array_t *array; + + array = ALLOC(array_t, 1); + array->num = 0; + array->n_size = MAX(number, INIT_SIZE); + array->obj_size = size; + array->index = -size; + array->space = ALLOC(char, array->n_size * array->obj_size); + (void) memset(array->space, 0, array->n_size * array->obj_size); + return array; +} + + +void +array_free(array) +array_t *array; +{ + if (array == NIL(array_t)) return; + if (array->index >= 0) array_abort(array,4); + FREE(array->space); + FREE(array); +} + + +array_t * +array_dup(old) +array_t *old; +{ + array_t *new; + + new = ALLOC(array_t, 1); + new->num = old->num; + new->n_size = old->num; + new->obj_size = old->obj_size; + new->index = -new->obj_size; + new->space = ALLOC(char, new->n_size * new->obj_size); + (void) memcpy(new->space, old->space, old->num * old->obj_size); + return new; +} + +/* append the elements of array2 to the end of array1 */ +void +array_append(array1, array2) +array_t *array1; +array_t *array2; +{ + char *pos; + + if (array1->index >= 0) array_abort(array1,4); + if (array1->obj_size != array2->obj_size) { + array_abort(array1,2); + /* NOTREACHED */ + } + + /* make sure array1 has enough room */ + if (array1->n_size < array1->num + array2->num) { + (void) array_resize(array1, array1->num + array2->num); + } + + pos = array1->space + array1->num * array1->obj_size; + (void) memcpy(pos, array2->space, array2->num * array2->obj_size); + array1->num += array2->num; +} + + +/* join array1 and array2, returning a new array */ +array_t * +array_join(array1, array2) +array_t *array1; +array_t *array2; +{ + array_t *array; + char *pos; + + if (array1->obj_size != array2->obj_size) { + array_abort(array1,3); + fail("array: join not defined for arrays of different sizes\n"); + /* NOTREACHED */ + } + + array = ALLOC(array_t, 1); + array->num = array1->num + array2->num; + array->n_size = array->num; + array->obj_size = array1->obj_size; + array->index = -array->obj_size; + array->space = ALLOC(char, array->n_size * array->obj_size); + (void) memcpy(array->space, array1->space, array1->num * array1->obj_size); + pos = array->space + array1->num * array1->obj_size; + (void) memcpy(pos, array2->space, array2->num * array2->obj_size); + return array; +} + +char * +array_do_data(array) +array_t *array; +{ + char *data; + + data = ALLOC(char, array->num * array->obj_size); + (void) memcpy(data, array->space, array->num * array->obj_size); + return data; +} + + +int /* would like to be void, except for macro's */ +array_resize(array, new_size) +array_t *array; +int new_size; +{ + int old_size; + char *pos; + + /* Note that this is not an exported function, and does not check if + the array is locked since that is already done by the caller. */ + old_size = array->n_size; + array->n_size = MAX(array->n_size * 2, new_size); + array->space = REALLOC(char, array->space, array->n_size * array->obj_size); + pos = array->space + old_size * array->obj_size; + (void) memset(pos, 0, (array->n_size - old_size)*array->obj_size); +} + +void +array_sort(array, compare) +array_t *array; +int (*compare)(); +{ + qsort(array->space, array->num, array->obj_size, compare); +} + + +void +array_uniq(array, compare, free_func) +array_t *array; +int (*compare)(); +void (*free_func)(); +{ + int i, last; + char *dest, *obj1, *obj2; + + dest = array->space; + obj1 = array->space; + obj2 = array->space + array->obj_size; + last = array->num; + + for(i = 1; i < last; i++) { + if ((*compare)((char **) obj1, (char **) obj2) != 0) { + if (dest != obj1) { + (void) memcpy(dest, obj1, array->obj_size); + } + dest += array->obj_size; + } else { + if (free_func != 0) (*free_func)(obj1); + array->num--; + } + obj1 += array->obj_size; + obj2 += array->obj_size; + } + if (dest != obj1) { + (void) memcpy(dest, obj1, array->obj_size); + } +} + +int /* would like to be void, except for macro's */ +array_abort(a,i) +array_t *a; +int i; +{ + fputs("array: ",stderr); + + switch (i) { + + case 0: /* index error on insert */ + fprintf(stderr,"insert of %d\n",a->index); + break; + + case 1: /* index error on fetch */ + fprintf(stderr,"fetch index %d not in [0,%d]\n", + array_global_index,a->num-1); + break; + + case 2: /* append with different element sizes */ + fprintf(stderr,"append undefined for arrays of different sizes\n"); + break; + + case 3: /* join with different element sizes */ + fprintf(stderr,"join not defined for arrays of different sizes\n"); + break; + + case 4: /* size error or locked error */ + if (a->index >= 0) { + /* Since array_insert is a macro, it is not allowed to nest a + call to any routine which might move the array space through + a realloc or free inside an array_insert call. */ + fprintf(stderr,"nested insert, append, or free operations\n"); + } else { + fprintf(stderr,"object size mismatch\n"); + } + break; + + default: + fputs("unknown error\n", stderr); + break; + } + + fail("array package error"); +} diff --git a/sis/array/array.doc b/sis/array/array.doc new file mode 100644 index 0000000..0632260 --- /dev/null +++ b/sis/array/array.doc @@ -0,0 +1,171 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/array/array.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +An array_t is a dynamically allocated array. As elements are inserted +the array is automatically grown to accomodate the new elements. + +The first element of the array is always element 0, and the last +element is element n-1 (if the array contains n elements). + +This array package is intended for generic objects (i.e., an array of +int, array of char, array of double, array of struct foo *, or even +array of struct foo). + +Be careful when creating an array with holes (i.e., when there is no +object stored at a particular position). An attempt to read such a +position will return a 'zero' object. It is poor practice to assume +that this value will be properly interpreted as, for example, (double) +0.0 or (char *) 0. + +In the definitions below, 'typeof' indicates that the argument to the +'function' is a C data type; these 'functions' are actually implemented +as macros. + + + +array_t * +array_alloc(type, number) +typeof type; +int number; + Allocate and initialize an array of objects of type `type'. + Polymorphic arrays are okay as long as the type of largest + object is used for initialization. The array can initially + hold `number' objects. Typical use sets `number' to 0, and + allows the array to grow dynamically. + + +void +array_free(array) +array_t *array; + Deallocate an array. Freeing the individual elements of the + array is the responsibility of the user. + + +int +array_n(array) +array_t *array; + Returns the number of elements stored in the array. If this is + `n', then the last element of the array is at position `n' - 1. + + +type * +array_data(type, array) +array_t *array; +typeof type; + Returns a normal `C' array from an array_t structure. This is + sometimes necessary when dealing with functions which do not + understand the array_t data type. A copy of the array is + returned, and it is the users responsibility to free it. array_n() + can be used to get the number of elements in the array. + + +array_t * +array_dup(array) +array_t *array; + Create a duplicate copy of an array. + + +void +array_insert(type, array, position, object) +typeof type; +array_t *array; +int position; +type object; + Insert a new element into an array at the given position. The + array is dynamically extended if necessary to accomodate the + new item. It is a serious error if sizeof(type) is not the + same as the type used when the array was allocated. It is also + a serious error for 'position' to be less than zero. + + +void +array_insert_last(type, array, object) +typeof type; +array_t *array; +type object; + Insert a new element at the end of the array. Equivalent to: + array_insert(type, array, array_n(array), object). + + +type +array_fetch(type, array, position) +typeof type; +array_t *array; +int position; + Fetch an element from an array. A runtime error occurs on an + attempt to reference outside the bounds of the array. There is + no type-checking that the value at the given position is + actually of the type used when dereferencing the array. + + +type +array_fetch_last(type, array) +typeof type; +array_t *array; + Fetch the last element from an array. A runtime error occurs + if there are no elements in the array. There is no type-checking + that the value at the given position is actually of the type used + when dereferencing the array. Equivalent to: + array_fetch(type, array, array_n(array)) + + +array_t * +array_join(array1, array2) +array_t *array1; +array_t *array2; + Returns a new array which consists of the elements from array1 + followed by the elements of array2. + + +void +array_append(array1, array2) +array_t *array1; +array_t *array2; + Appends the elements of array2 to the end of array1. + + +void +array_sort(array, compare) +array_t *array; +int (*compare)(); + Sort the elements of an array. `compare' is defined as: + + int + compare(obj1, obj2) + char *obj1; + char *obj2; + + and should return -1 if obj1 < obj2, 0 if obj1 == obj2, or 1 + if obj1 > obj2. + + + +void +array_uniq(array, compare, free_func) +array_t *array; +int (*compare)(); +void (*free_func)(); + Compare adjacent elements of the array, and delete any duplicates. + Usually the array should be sorted (using array_sort) before calling + array_uniq. `compare' is defined as: + + int + compare(obj1, obj2) + char *obj1; + char *obj2; + + and returns -1 if obj1 < obj2, 0 if obj1 == obj2, or 1 if obj1 > obj2. + + `free_func' (if non-null) is defined as: + + void + free_func(obj1) + char *obj1; + + and frees the given array element. diff --git a/sis/array/array.h b/sis/array/array.h new file mode 100644 index 0000000..1e485f7 --- /dev/null +++ b/sis/array/array.h @@ -0,0 +1,69 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/array/array.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +#ifndef ARRAY_H +#define ARRAY_H + +typedef struct array_t { + char *space; + int num; /* number of array elements. */ + int n_size; /* size of 'data' array (in objects) */ + int obj_size; /* size of each array object. */ + int index; /* combined index and locking flag. */ +} array_t; + + +EXTERN array_t *array_do_alloc ARGS((int, int)); +EXTERN array_t *array_dup ARGS((array_t *)); +EXTERN array_t *array_join ARGS((array_t *, array_t *)); +EXTERN void array_free ARGS((array_t *)); +EXTERN void array_append ARGS((array_t *, array_t *)); +EXTERN void array_sort ARGS((array_t *, int (*)())); +EXTERN void array_uniq ARGS((array_t *, int (*)(), void (*)())); +EXTERN int array_abort ARGS((array_t *, int)); +EXTERN int array_resize ARGS((array_t *, int)); +EXTERN char *array_do_data ARGS((array_t *)); + +extern unsigned int array_global_index; + +#define array_alloc(type, number) \ + array_do_alloc(sizeof(type), number) + +#define array_insert(type, a, i, datum) \ + ( -(a)->index != sizeof(type) ? array_abort((a),4) : 0,\ + (a)->index = (i),\ + (a)->index < 0 ? array_abort((a),0) : 0,\ + (a)->index >= (a)->n_size ? array_resize(a, (a)->index + 1) : 0,\ + *((type *) ((a)->space + (a)->index * (a)->obj_size)) = datum,\ + (a)->index >= (a)->num ? (a)->num = (a)->index + 1 : 0,\ + (a)->index = -(int)sizeof(type) ) + +#define array_insert_last(type, array, datum) \ + array_insert(type, array, (array)->num, datum) + +#define array_fetch(type, a, i) \ + (array_global_index = (i), \ + (array_global_index >= (a)->num) ? array_abort((a),1) : 0,\ + *((type *) ((a)->space + array_global_index * (a)->obj_size))) + +#define array_fetch_p(type, a, i) \ + (array_global_index = (i), \ + (array_global_index >= (a)->num) ? array_abort((a),1) : 0,\ + ((type *) ((a)->space + array_global_index * (a)->obj_size))) + +#define array_fetch_last(type, array) \ + array_fetch(type, array, ((array)->num)-1) + +#define array_n(array) \ + (array)->num + +#define array_data(type, array) \ + (type *) array_do_data(array) + +#endif diff --git a/sis/astg/Makefile.am b/sis/astg/Makefile.am new file mode 100644 index 0000000..4375252 --- /dev/null +++ b/sis/astg/Makefile.am @@ -0,0 +1,12 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libastg.a +libastg_a_SOURCES = astg_blif.c astg_cmds.c astg_contract.c astg_core1.c \ + astg_core2.c astg_flow.c astg_irred.c astg_lkgraph.c astg_marking.c \ + astg_persist.c astg_read.c astg_reduce.c bwd_code.c bwd_com.c \ + bwd_hazard.c bwd_io.c bwd_lp.c bwd_min_delay.c bwd_slow.c bwd_stg_to_f.c \ + bwd_util.c com_astg.c si_com.c si_encode.c si_min.c astg_core.h \ + astg_int.h bwd_int.h min_delay_int.h si_int.h +pkginclude_HEADERS = astg.h +dist_doc_DATA = astg.doc diff --git a/sis/astg/Makefile.in b/sis/astg/Makefile.in new file mode 100644 index 0000000..56cfcb1 --- /dev/null +++ b/sis/astg/Makefile.in @@ -0,0 +1,433 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libastg_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/astg +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libastg_a_AR = $(AR) $(ARFLAGS) +libastg_a_LIBADD = +am_libastg_a_OBJECTS = astg_blif.$(OBJEXT) astg_cmds.$(OBJEXT) \ + astg_contract.$(OBJEXT) astg_core1.$(OBJEXT) \ + astg_core2.$(OBJEXT) astg_flow.$(OBJEXT) astg_irred.$(OBJEXT) \ + astg_lkgraph.$(OBJEXT) astg_marking.$(OBJEXT) \ + astg_persist.$(OBJEXT) astg_read.$(OBJEXT) \ + astg_reduce.$(OBJEXT) bwd_code.$(OBJEXT) bwd_com.$(OBJEXT) \ + bwd_hazard.$(OBJEXT) bwd_io.$(OBJEXT) bwd_lp.$(OBJEXT) \ + bwd_min_delay.$(OBJEXT) bwd_slow.$(OBJEXT) \ + bwd_stg_to_f.$(OBJEXT) bwd_util.$(OBJEXT) com_astg.$(OBJEXT) \ + si_com.$(OBJEXT) si_encode.$(OBJEXT) si_min.$(OBJEXT) +libastg_a_OBJECTS = $(am_libastg_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libastg_a_SOURCES) +DIST_SOURCES = $(libastg_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libastg.a +libastg_a_SOURCES = astg_blif.c astg_cmds.c astg_contract.c astg_core1.c \ + astg_core2.c astg_flow.c astg_irred.c astg_lkgraph.c astg_marking.c \ + astg_persist.c astg_read.c astg_reduce.c bwd_code.c bwd_com.c \ + bwd_hazard.c bwd_io.c bwd_lp.c bwd_min_delay.c bwd_slow.c bwd_stg_to_f.c \ + bwd_util.c com_astg.c si_com.c si_encode.c si_min.c astg_core.h \ + astg_int.h bwd_int.h min_delay_int.h si_int.h + +pkginclude_HEADERS = astg.h +dist_doc_DATA = astg.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/astg/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/astg/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libastg.a: $(libastg_a_OBJECTS) $(libastg_a_DEPENDENCIES) + -rm -f libastg.a + $(libastg_a_AR) libastg.a $(libastg_a_OBJECTS) $(libastg_a_LIBADD) + $(RANLIB) libastg.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/astg/astg.doc b/sis/astg/astg.doc new file mode 100644 index 0000000..c623a8b --- /dev/null +++ b/sis/astg/astg.doc @@ -0,0 +1,14 @@ +#/* +# * Revision Control Information +# * +# * $Source: /users/pchong/CVS/sis/sis/astg/astg.doc,v $ +# * $Author: pchong $ +# * $Revision: 1.1.1.1 $ +# * $Date: 2004/02/07 10:14:58 $ +# * +# */ +astg -- Asynchronous Signal Transition Graph package + +There is no exported programmer interface to the ASTG package. See +the user commands read_astg, write_astg, astg_* and _astg_* for the +user interface to the SIS asynchronous synthesis commands. diff --git a/sis/astg/astg.h b/sis/astg/astg.h new file mode 100644 index 0000000..dcfb30f --- /dev/null +++ b/sis/astg/astg.h @@ -0,0 +1,22 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* astg.h -- exported programming interface to ASTG package. */ + +#ifndef ASTG_H +#define ASTG_H + +typedef char astg_t; + +void init_astg ARGS(()); +void end_astg ARGS(()); +astg_t *astg_dup ARGS((astg_t *)); +void astg_free ARGS((astg_t *)); + +#endif /* ASTG_H */ diff --git a/sis/astg/astg_blif.c b/sis/astg/astg_blif.c new file mode 100644 index 0000000..86541ab --- /dev/null +++ b/sis/astg/astg_blif.c @@ -0,0 +1,291 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_blif.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* -------------------------------------------------------------------------- *\ + astg_blif.c -- Write BLIF description of astg flow graph. + + After an exhaustive token flow has been completed successfully, function + astg_to_blif will write a BLIF description of the corresponding sis + network. Real pi/po names are preserved, and latches are generated for + the feedback signals. The naming convention is illustrated for an astg + which has input a and output b: + + +-------+ + a ---->| | + | logic +------> b_next (fake PO) + (fake PI) b_ --+->| | + | +-------+ + | + +-----------------> b + + A latch is connected from b_next to b_ and a don't care network is + created for b_next. If the internal names with the _ and _next suffixes + would conflict with existing names, a number is appended to make them + unique. The latch type is specified as an argument to the function. + + Since additional synthesis steps will usually need to identify the two + POs and single PI associated with an output signal, function + astg_find_pi_or_po is provided to do this. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + +static astg_bool astg_uses_name (stg,name) +astg_graph *stg; +char *name; +{ + /* Return true if astg has a signal with this name. */ + astg_generator gen; + astg_signal *sig_p; + astg_foreach_signal (stg,gen,sig_p) { + if (!strcmp(name,sig_p->name)) return ASTG_TRUE; + } + return ASTG_FALSE; +} + +static char *astg_make_fake_name (stg,name,suffix) +astg_graph *stg; +char *name; +char *suffix; +{ + /* Generate name+suffix[+digits] which is not a signal name. */ + int real_len = strlen(name) + strlen(suffix); + char *buffer = ALLOC (char,real_len + 10); + int name_index = 0; + strcat(strcpy(buffer,name), suffix); + while (astg_uses_name(stg,buffer)) { + sprintf(buffer+real_len,"%d",++name_index); + } + return buffer; +} + +static void astg_print_inputs (fp,header,stg,fake_pis) +FILE *fp; +char *header; +astg_graph *stg; +char **fake_pis; +{ + /* Print a .names line with all inputs. */ + astg_generator gen; + astg_signal *sig_p; + int sig_n = 0; + fprintf(fp,"%s",header); + astg_foreach_signal (stg,gen,sig_p) { + if (astg_is_input(sig_p)) { + fprintf(fp," %s",sig_p->name); + } else if (astg_is_noninput (sig_p) && fake_pis != NULL) { + fprintf(fp," %s",fake_pis[sig_n++]); + } + } +} + +static void astg_print_real_outputs (fp,stg) +FILE *fp; +astg_graph *stg; +{ + /* Print a .outputs command for all the real outputs. */ + astg_generator gen; + astg_signal *sig_p; + fprintf(fp,".outputs"); + astg_foreach_signal (stg,gen,sig_p) { + if (astg_is_noninput(sig_p)) fprintf(fp," %s",sig_p->name); + } + fprintf(fp,"\n"); +} + +static void astg_print_cube (fp,stg,scode,fr) +FILE *fp; +astg_graph *stg; +astg_scode scode; +int fr; +{ + /* Print cube in signal order, followed by 1 or 0 based on fr flag. */ + astg_generator gen; + astg_signal *sig_p; + astg_foreach_signal (stg,gen,sig_p) { + if (astg_is_input(sig_p) || astg_is_noninput(sig_p)) { + fprintf(fp,"%d",(sig_p->state_bit&scode)!=0); + } + } + fprintf(fp," %d\n",fr); +} + +extern void astg_to_blif (fp,stg,latch_type) +FILE *fp; +astg_graph *stg; +char *latch_type; +{ + /* Write a sequential BLIF description of the token flow state graph. + The network can be read in using read_blif of the SIS io package. + Primary input and output names are preserved. In addition, for each + output variable x, a latch of the specified type is added with input + x_next, and output x_. Digits are appended if these generated names + would conflict with existing io names. */ + + char **fake_pi_names, **fake_po_names; + astg_generator gen, tgen; + astg_signal *sig_p; + int sig_n = 0; + char *dc_name; + astg_state *state_p; + astg_scode scode = 0; + astg_scode enabled = 0; + + if (stg->flow_info.out_width == 0) { + printf("warning: no noninput signals; no network generated.\n"); + return; + } + + fake_pi_names = ALLOC(char *, stg->flow_info.out_width); + fake_po_names = ALLOC(char *, stg->flow_info.out_width); + + astg_foreach_signal (stg,gen,sig_p) { + if (astg_is_input(sig_p) || astg_is_dummy(sig_p)) continue; + fake_pi_names[sig_n] = astg_make_fake_name (stg,sig_p->name,"_"); + fake_po_names[sig_n] = astg_make_fake_name (stg,sig_p->name,"_next"); + sig_n++; + } + assert (sig_n == stg->flow_info.out_width); + + /* Write model and list of real primary inputs and outputs. */ + fprintf(fp,".model %s\n", stg->name); + astg_print_inputs (fp,".inputs",stg,NULL); fputs("\n",fp); + astg_print_real_outputs(fp,stg); + + /* Write sis descriptions of latches. */ + sig_n = 0; + astg_initial_state (stg,&scode); + astg_foreach_signal (stg,gen,sig_p) { + if (astg_is_input(sig_p)) continue; + if (astg_is_noninput(sig_p)) { + fprintf(fp,".latch %s %s %s NIL %d\n", + fake_po_names[sig_n], fake_pi_names[sig_n], + latch_type, (sig_p->state_bit&scode) != 0); + sig_n++; + } + } + + sig_n = 0; + astg_foreach_signal (stg,gen,sig_p) { + if (astg_is_input(sig_p)) continue; + if (astg_is_noninput(sig_p)) { + astg_print_inputs (fp,".names",stg,fake_pi_names); + fprintf(fp," %s\n",fake_po_names[sig_n]); + astg_foreach_state (stg,tgen,state_p) { + scode = astg_state_code (state_p); + enabled = astg_state_enabled (state_p); + if ((scode^enabled)&sig_p->state_bit) { + astg_print_cube(fp,stg,scode,1); + } + } + fprintf(fp,".names %s %s\n1 1\n",fake_pi_names[sig_n++],sig_p->name); + } + } + + fprintf(fp,".exdc\n"); + astg_print_inputs (fp,".inputs",stg,fake_pi_names); + sig_n = 0; + fputs("\n.outputs",fp); + astg_foreach_signal (stg,gen,sig_p) { + if (astg_is_noninput(sig_p)) fprintf(fp," %s",fake_po_names[sig_n++]); + } + fputs("\n",fp); + dc_name = astg_make_fake_name (stg,"DC",""); + astg_print_inputs (fp,".names",stg,fake_pi_names); + fprintf(fp," %s\n",dc_name); + astg_foreach_state (stg,gen,state_p) { + scode = astg_state_code(state_p); + astg_print_cube (fp,stg,scode,0); + } + + sig_n = 0; + astg_foreach_signal (stg,gen,sig_p) { + if (astg_is_input(sig_p)) continue; + if (astg_is_noninput(sig_p)) { + fprintf(fp,".names %s %s\n1 1\n",dc_name,fake_po_names[sig_n++]); + } + } + + fprintf(fp,".end\n"); + FREE (dc_name); + for (sig_n=stg->flow_info.out_width; sig_n--; ) { + FREE (fake_pi_names[sig_n]); + FREE (fake_po_names[sig_n]); + } +} + +static node_t *astg_trace_fake_pi (node) +node_t *node; +{ + node_t *fake_pi = node; + + if (fake_pi != NULL) { + do { + fake_pi = node_get_fanin (fake_pi,0); + if (fake_pi == NULL) return NULL; + } while (node_function(fake_pi) == NODE_BUF); + + if (node_function(fake_pi) != NODE_PI + || network_is_real_pi(node_network(node),fake_pi)) { + fake_pi = NULL; + } + } + return fake_pi; +} + +extern node_t *astg_find_pi_or_po (network,sig_name,type) +network_t *network; +char *sig_name; +astg_io_enum type; +{ + /* Find the primary input or output of the given type for a signal. This + assumes the network has a specific structure: any output which is used + for feedback is connected to the fake PI for the SIS latch. If no + node matches the name/type, NULL is returned. Possible io types are: + ASTG_REAL_PI, ASTG_REAL_PO, ASTG_FAKE_PI, ASTG_FAKE_PO. */ + + node_t *pi_or_po, *node; + name_mode_t old_mode; + + old_mode = name_mode; + name_mode = LONG_NAME_MODE; + pi_or_po = network_find_node (network,sig_name); + name_mode = old_mode; + + if (pi_or_po == NULL) { + node = NULL; + } + else if (type == ASTG_REAL_PI) { + node = (network_is_real_pi(network,pi_or_po)) ? pi_or_po : NULL; + } + else if (!network_is_real_po(network,pi_or_po)) { + /* All the other types are derived from a real PO. */ + node = NULL; + } + else if (type == ASTG_REAL_PO) { + node = pi_or_po; + } + else if (type == ASTG_FAKE_PI) { + node = astg_trace_fake_pi (pi_or_po); + } + else if (type == ASTG_FAKE_PO) { + node = astg_trace_fake_pi (pi_or_po); + if (node != NULL) { + node = network_latch_end (node); + if (node_function(node) != NODE_PO || network_is_real_po(network,node)) { + node = NULL; + } + } + } + + return node; +} +#endif /* SIS */ diff --git a/sis/astg/astg_cmds.c b/sis/astg/astg_cmds.c new file mode 100644 index 0000000..f25ea74 --- /dev/null +++ b/sis/astg/astg_cmds.c @@ -0,0 +1,975 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_cmds.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/14 08:35:21 $ + * + */ +/* -------------------------------------------------------------------------- *\ + astg_cmds.c -- SIS command interface to basic ASTG commands. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + +int astg_debug_flag = 0; /* global debugging flag */ + + +extern char *astg_dup (old_astg) +char *old_astg; +{ + /* Duplicate the network astg slot value. */ + return (char*) astg_duplicate ((astg_graph*) old_astg, NULL); +} + +extern void astg_free (old_astg) +char *old_astg; +{ + /* Free all structures for the given network astg slot. */ + astg_delete ((astg_graph*) old_astg); +} + +extern astg_graph *astg_current (network) +network_t *network; /*i network to find astg info for */ +{ + /* Return the ASTG corresponding to this network, or NULL if either + the network pointer is NULL or it has no ASTG. */ + + return (network==NULL) ? NULL : (astg_graph*)(network->astg); +} + +extern void astg_set_current (network_p,stg,reset) +network_t **network_p; +astg_graph *stg; +astg_bool reset; +{ + /* Whenever the astg is changed, call astg_set_current with the indirect + network pointer, and set reset to ASTG_TRUE if the previous network + contents should be destroyed, or ASTG_FALSE if the network does + correspond with the astg you are setting. This handles all special + cases such as a nonexistent network, or if the current astg equals + the new one, etc. The one special case is if stg is NULL and reset + is ASTG_FALSE, then any previous stg is not freed first. This is + useful if you need to do some command which will destroy the network + and you want to preserve the astg across the call: set it to NULL, + then set it back. */ + + if (*network_p != NULL) { /* Destroy old stuff. */ + if (reset) { + /* Destroy the previous network. */ + if ((*network_p)->astg == (astg_t*)stg) { + /* Don't destroy the astg we are trying to install. */ + (*network_p)->astg = NULL; + } + network_free (*network_p); + *network_p = NULL; + } + else if ((*network_p)->astg != NULL) { + /* Destroy previous astg if necessary. */ + if ((*network_p)->astg != (astg_t*)stg) { + if (stg != NULL) astg_free ((*network_p)->astg); + (*network_p)->astg = NULL; + } + } + } + + if (stg != NULL) { /* Install the new astg. */ + if (reset) { + astg_do_daemons (stg,NIL(astg_graph),ASTG_DAEMON_INVALID); + } + if (*network_p == NULL) { + *network_p = network_alloc(); + } + (*network_p)->astg = (astg_t*) stg; + } +} + +extern void astg_usage (usage,cmd) +char **usage; +char *cmd; +{ + /* Print a set of usage strings, replacing the first %s with cmd. A + newline is automatically added to each line in usage; you can put + more for special formatting. The last element in the usage array + must be a NULL pointer. */ + + char **p; + + for (p=usage; *p != NULL; p++) { + printf(*p,cmd); + fputs ("\n",stdout); + } +} + +static char *flow_usage[] = { + + "usage: %s [-x] [-l ] [-o ] [-q]", + " -x bypass one-token SM check before flow", + " -l use specified latch type, default=as", + " -o save BLIF description in , use '-' for stdout", + " -q turn off verbose option of flow", + +NULL }; + +static int com_astg_flow (network_p,argc, argv) +network_t **network_p; +int argc; +char **argv; +{ + int c; + char *outfile; + astg_bool del_out = ASTG_TRUE; + FILE *fout; + astg_graph *stg, *curr_stg; + char *latch_type = "as"; + astg_retval result = ASTG_OK; + astg_bool full_checks = ASTG_TRUE; + astg_bool verbose = ASTG_TRUE; + char stempname[20]; + int sfd; + + outfile = NULL; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"xo:l:q")) != EOF) { + switch (c) { + case 'x': full_checks = ASTG_FALSE; break; + case 'l': latch_type = util_optarg; break; + case 'o': outfile = util_strsav(util_optarg); + del_out = ASTG_FALSE; break; + case 'q': verbose = ASTG_FALSE; break; + default : result = ASTG_BAD_OPTION; break; + } + } + + stg = curr_stg = astg_current (*network_p); + + if (stg == NULL || util_optind != argc) { + result = ASTG_BAD_OPTION; + } + else if (result == ASTG_OK) { + if (outfile == NULL) { + strcpy(stempname, "/tmp/fileXXXXXX"); + sfd = mkstemp(stempname); + fout = fdopen(sfd, "w+"); + } else if (!strcmp(outfile,"-")) { + fout = stdout; + } else { + fout = com_open_file (outfile,"w+",NULL,ASTG_FALSE); + } + if (fout != NULL) { + if (!astg_is_free_choice_net(stg)) { + printf("Note: %s is not a free-choice net.\n",astg_name(stg)); + if (!stg->has_marking) { + printf(" You must specify an initial marking first.\n"); + result = ASTG_ERROR; + } + } else if (full_checks) { + if (!astg_one_sm_token (stg)) result = ASTG_ERROR; + } + if (result == ASTG_OK && astg_token_flow (stg,verbose) == ASTG_OK) { + astg_to_blif (fout,stg,latch_type); + if (del_out) { + rewind (fout); + /* Clear astg, read new network, restore astg. */ + astg_set_current(network_p,NIL(astg_graph),ASTG_FALSE); + network_free (*network_p); *network_p = NULL; + error_init(); + read_register_filename ("astg_flow"); + if (read_blif (fout,network_p) == 0) { + fprintf(siserr,"%s",error_string()); + result = ASTG_ERROR; + } + astg_set_current(network_p,curr_stg,ASTG_FALSE); + } + } + if (fout != stdout) fclose (fout); + if (del_out) unlink (outfile); + if (outfile) FREE (outfile); + } + } + + if (result == ASTG_BAD_OPTION) { + astg_usage (flow_usage,argv[0]); + } + + return (result != ASTG_OK); +} + +static char *read_usage[] = { + + "usage: %s []", + " Reads from stdin if no file name is specified.", + +NULL }; + +static int com_astg_read (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + int c; + char *infile; + char alt_infile[80]; + astg_bool from_file = ASTG_FALSE; + FILE *fin; + astg_graph *stg; + astg_retval result = ASTG_OK; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"")) != EOF) { + switch (c) { + default : result = ASTG_BAD_OPTION; break; + } + } + + if (util_optind < argc) { + infile = argv[util_optind++]; + strcpy (alt_infile,infile); + fin = com_open_file (alt_infile,"r",NULL,ASTG_FALSE); + if (fin == NULL) { + printf("Failed to open input file '%s'\n",infile); + result = ASTG_ERROR; + } else { + from_file = ASTG_TRUE; + } + } + else { + strcpy (alt_infile,""); + fin = stdin; + from_file = ASTG_FALSE; + } + + if (util_optind != argc) { + result = ASTG_BAD_OPTION; + } + else if (result == ASTG_OK) { + stg = astg_read (fin,alt_infile); + if (from_file) fclose (fin); + if (stg == NULL) result = ASTG_ERROR; + } + + if (result == ASTG_BAD_OPTION) { + astg_usage (read_usage,argv[0]); + } + else if (result == ASTG_OK) { + astg_set_current (network_p,stg,ASTG_TRUE); + } + return (result != ASTG_OK); +} + +static char *print_usage[] = { + + "usage: %s [-p] []", + " -p print all places even with 1 in edge and out edge", + +NULL }; + +static int com_astg_write (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + astg_retval result = ASTG_OK; + astg_bool hide_places = ASTG_TRUE; + char *outfile = NULL; + FILE *fout; + int c; + astg_graph *curr_stg; + + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"p")) != EOF) { + switch (c) { + case 'p': hide_places = ASTG_FALSE; break; + default : result = ASTG_BAD_OPTION; break; + } + } + if (util_optind < argc) { + outfile = argv[util_optind++]; + } + curr_stg = astg_current (*network_p); + + if (result == ASTG_BAD_OPTION || util_optind != argc || curr_stg == NULL) { + astg_usage (print_usage,argv[0]); + return 1; + } + + if (outfile != NULL) { + fout = com_open_file (outfile,"w",NULL,ASTG_TRUE); + if (fout == NULL) return 1; + astg_write (curr_stg,hide_places,fout); + fclose (fout); + } + else { + astg_write (curr_stg,hide_places,stdout); + } + return (result != ASTG_OK); +} + + +static char *cycle_usage[] = { + + "usage: %s [-la] [-t ] []", + " select simple cycles in the STG (default = all)", + " -l select longest delay", + " -a append to existing set", + " -t optionally only through specified trans", + " -c count total number of simple cycles", + +NULL }; + +static int astg_count_cycles (stg,data) +astg_graph *stg; +void *data; +{ + /* Return 1 to count number of simple cycles in the net. */ + /* ARGSUSED */ + return 1; +} + +static int com_astg_cycle (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + int c; + astg_retval result = ASTG_OK; + astg_graph *stg; + io_t source; + char *tname = NULL; + astg_trans *thru = NULL; + astg_bool longest = ASTG_FALSE; + astg_bool append = ASTG_FALSE; + astg_bool count_em = ASTG_FALSE; + int n_cycle, cycle_n = 0; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"t:lac")) != EOF) { + switch (c) { + case 'a': append = ASTG_TRUE; break; + case 'l': longest = ASTG_TRUE; break; + case 't': tname = util_optarg; break; + case 'c': count_em = ASTG_TRUE; break; + default : result = ASTG_BAD_OPTION; break; + } + } + + if ((stg=astg_current (*network_p)) == NULL) result = ASTG_BAD_OPTION; + + if (result == ASTG_OK && tname != NULL) { + io_open (&source,NIL(FILE),tname); + io_token (&source); + thru = find_trans_by_name (&source,stg,ASTG_FALSE); + io_close (&source); + if (thru == NULL) result = ASTG_BAD_OPTION; + } + + if (util_optind != argc) { + cycle_n = atoi (argv[util_optind++]); + } + + if (result == ASTG_BAD_OPTION) { + astg_usage (cycle_usage,argv[0]); + } else if (count_em) { + n_cycle = astg_simple_cycles (stg,NULL,astg_count_cycles,NULL,ASTG_ALL); + printf("Total number of simple cycles: %d\n",n_cycle); + } else { + astg_select_cycle (stg,thru,cycle_n,longest,append); + } + return (result != ASTG_OK); +} + + +static char *lockgraph_usage[] = { + + "usage: %s [-l]", + " print lock graph for an STG", + " -l try to form one lock class first", + +NULL }; + +static int print_stg_comp (varray,n,extra) +array_t *varray; +int n; +void *extra; /* ARGSUSED */ +{ + int i; + astg_vertex *v; + + printf(" %d)",n); + for (i=0; i < array_n(varray); i++) { + v = array_fetch (astg_vertex *,varray,i); + printf(" %s",astg_v_name(v)); + } + fputs("\n",stdout); +} + +static int com_astg_lockgraph (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + int c; + astg_retval result = ASTG_OK; + int n_comp; + astg_graph *stg; + astg_graph *curr_stg; + astg_bool do_lock = ASTG_FALSE; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"l")) != EOF) { + switch (c) { + case 'l': do_lock = ASTG_TRUE; break; + default : result = ASTG_BAD_OPTION; break; + } + } + + curr_stg = astg_current (*network_p); + + if (result == ASTG_BAD_OPTION || curr_stg == NULL) { + result = ASTG_BAD_OPTION; + astg_usage (lockgraph_usage,argv[0]); + } + else { + stg = curr_stg; + if (! astg_state_coding (stg,do_lock)) { + return 1; + } + n_comp = astg_lock_graph_components (stg,ASTG_NO_CALLBACK,ASTG_NO_DATA); + dbg(1,msg("lock graph has %d componen%s\n",n_comp,n_comp==1?"t":"ts")); + if (n_comp != 1) { + printf("\nwarning: STG may have complementary sets:\n"); + astg_lock_graph_components (stg,print_stg_comp,ASTG_NO_DATA); + printf("This could cause duplicate state codings.\n"); + } + dbg(1,msg("\n")); + if (do_lock) astg_set_current (network_p,stg,ASTG_TRUE); + } + return (result != ASTG_OK); +} + +static char *persist_usage[] = { + + "usage: %s [-p]", + " -p just print nonpersistent transitions (don't modify STG)", + " Otherwise, add persistency constraints to the STG.", + +NULL }; + +static int com_astg_persist (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + int c; + astg_retval result = ASTG_OK; + astg_graph *stg; + astg_bool modify = ASTG_TRUE; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"p")) != EOF) { + switch (c) { + case 'p': modify = ASTG_FALSE; break; + default : result = ASTG_BAD_OPTION; break; + } + } + + stg = astg_current (*network_p); + + if (result == ASTG_BAD_OPTION || stg == NULL) { + result = ASTG_BAD_OPTION; + astg_usage (persist_usage,argv[0]); + } + else { + make_persistent (stg,modify); + if (!modify) { + astg_sel_show (stg); + } else { + astg_set_current (network_p,stg,ASTG_TRUE); + } + } + + return (result != ASTG_OK); +} + +static char *red_usage[] = { + + "usage: %s [-p]", + " -p print redundant edges instead of deleting them.", + +NULL }; + +static int com_astg_irred (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + int c; + astg_retval result = ASTG_OK; + astg_bool modify = ASTG_TRUE; + astg_graph *curr_stg; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"p")) != EOF) { + switch (c) { + case 'p': modify = ASTG_FALSE; break; + default : result = ASTG_BAD_OPTION; break; + } + } + + curr_stg = astg_current (*network_p); + + if (result == ASTG_BAD_OPTION || curr_stg == NULL) { + result = ASTG_BAD_OPTION; + astg_usage (red_usage,argv[0]); + } + else { + astg_irred (curr_stg,modify); + if (modify) astg_set_current (network_p,curr_stg,ASTG_TRUE); + } + return (result != ASTG_OK); +} + + +static char *current_usage[] = { + + "usage: %s [-d #]", + " -d set debug output (0=no debug output)", + " display information about the current stg", + +NULL }; + +static int com_astg_current (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + int c; + astg_retval result = ASTG_OK; + int n_comp1, n_comp2; + astg_graph *curr_stg; + lsGen cgen; + lsGeneric data; + long change_count; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"d:")) != EOF) { + switch (c) { + case 'd': astg_debug_flag = atoi(util_optarg); break; + default : result = ASTG_BAD_OPTION; break; + } + } + + curr_stg = astg_current (*network_p); + + if (argc > util_optind || result == ASTG_BAD_OPTION) { + result = ASTG_BAD_OPTION; + astg_usage (current_usage,argv[0]); + } + else if (curr_stg == NULL) { + fprintf(sisout,"No current ASTG.\n"); + } + else { + change_count = astg_change_count (curr_stg); + printf("%s\n", astg_name(curr_stg)); + /* Print all comments for this graph. */ + cgen = lsStart (curr_stg->comments); + while (lsNext(cgen,&data,LS_NH) == LS_OK) { + printf(" %s\n",(char *) data); + } + lsFinish (cgen); + printf("\tFile: %s", curr_stg->filename); + if (curr_stg->file_count != change_count) { + fputs(" (modified)",stdout); + } + fputs("\n",stdout); + printf("\tPure: %c Place-simple: %c\n", + astg_is_pure(curr_stg)?'Y':'N', astg_is_place_simple(curr_stg)?'Y':'N'); + n_comp1 = astg_connected_comp (curr_stg,ASTG_NO_CALLBACK,ASTG_NO_DATA,ASTG_ALL); + n_comp2 = astg_strong_comp (curr_stg,ASTG_NO_CALLBACK,ASTG_NO_DATA,ASTG_ALL); + printf("\tConnected: %c Strongly Connected: %c\n", + (n_comp1==1?'Y':'N'), (n_comp2==1?'Y':'N')); + printf("\tFree Choice: %c Marked Graph: %c State Machine: %c\n", + astg_is_free_choice_net(curr_stg)?'Y':'N', + astg_is_marked_graph(curr_stg)?'Y':'N', + astg_is_state_machine(curr_stg)?'Y':'N'); + if (curr_stg->sm_comp != NULL) { + printf("\tSM components: %d\n",array_n(curr_stg->sm_comp)); + } + if (curr_stg->mg_comp != NULL) { + printf("\tMG components: %d\n",array_n(curr_stg->mg_comp)); + } + } + + return (result != ASTG_OK); +} + +static char *marking_usage[] = { + + "usage: %s [-s] [new_marking]", + " print or set initial marking for the current STG", + " -s specify new marking using signal values", + " e.g. a 1 b 0", + " otherwise new marking in format: {place1 place2 ...}", + " where place is either place name or transition pair.", + +NULL }; + +static int com_astg_marking (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + astg_retval result = ASTG_OK; + astg_graph *stg; + astg_place *p; + io_t source; + int c; + astg_graph *curr_stg; + astg_generator pgen; + astg_retval status; + int value; + astg_scode state_code; + st_table *sig_values; + char *sig_name; + astg_bool by_state_code = ASTG_FALSE; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"s")) != EOF) { + switch (c) { + case 's': by_state_code = ASTG_TRUE; break; + default : result = ASTG_BAD_OPTION; break; + } + } + + stg = curr_stg = astg_current (*network_p); + + if (stg == NULL || result != ASTG_OK) { + result = ASTG_BAD_OPTION; + } + else if (util_optind == argc) { + if (stg->has_marking) { + if (by_state_code) { + status = astg_initial_state (stg,&state_code); + if (status == ASTG_OK || status == ASTG_NOT_USC) { + printf("%X\n",state_code); + } + } + else { + astg_write_marking (stg,stdout); + } + } + else { + printf("%s does not have an initial marking set.\n", + astg_name(curr_stg)); + } + } + else if (util_optind == argc-1 || by_state_code) { + if (by_state_code) { + sig_values = st_init_table (strcmp,st_strhash); + while (util_optind < argc) { + sig_name = argv[util_optind++]; + if (util_optind < argc && sscanf(argv[util_optind++],"%d",&value) == 1) { + st_insert (sig_values,sig_name,(char *)value); + } + else { + printf("Bad value for signal '%s' ignored.\n", + sig_name); + } + } + astg_set_marking_by_name (stg,sig_values); + st_free_table (sig_values); + } + else { + astg_foreach_place (stg,pgen,p) { + p->type.place.initial_token = ASTG_FALSE; + } + io_open (&source,NIL(FILE),argv[util_optind++]); + astg_read_marking (&source,stg); + if (io_status (&source) != 0) result = ASTG_ERROR; + } + astg_set_current (network_p,stg,ASTG_TRUE); + } + else { + result = ASTG_BAD_OPTION; + } + + if (result == ASTG_BAD_OPTION) astg_usage (marking_usage,argv[0]); + return (result != ASTG_OK); +} + +static int astg_print_component_pieces (vertices,n,fdata) +array_t *vertices; +int n; +void *fdata; /* ARGSUSED */ +{ + /* Callback for astg_strong_comp, to print parts of a component + to the user. */ + + astg_vertex *v; + int i; + + printf("\n %d)",n); + for (i=array_n(vertices); i--; ) { + v = array_fetch (astg_vertex *, vertices, i); + if (astg_v_type(v) == ASTG_TRANS) { + printf(" %s",astg_trans_name(v)); + } else { + printf(" %s",astg_place_name(v)); + } + } + printf("\n"); + return 1; +} + +static void select_comp (stg,comp,comp_name,comp_n) +astg_graph *stg; +array_t *comp; +char *comp_name; +int comp_n; +{ + astg_vertex *v; + int n, n_scc; + astg_generator gen; + static char set_name[90]; + + sprintf(set_name,"%s component %d",comp_name,comp_n); + astg_sel_new (stg,set_name,ASTG_FALSE); + astg_foreach_vertex (stg,gen,v) v->subset = ASTG_FALSE; + + for (n=array_n(comp); n--; ) { + v = array_fetch (astg_vertex *,comp,n); + v->subset = ASTG_TRUE; + astg_sel_vertex (v,ASTG_TRUE); + } + + astg_sel_show (stg); + n_scc = astg_strong_comp (stg,ASTG_NO_CALLBACK,ASTG_NO_DATA,ASTG_SUBSET); + if (n_scc != 1) { + printf( + "warning: this %s component has %d strongly connected components.\n", + comp_name,n_scc); + astg_strong_comp (stg,astg_print_component_pieces, + ASTG_NO_DATA,ASTG_SUBSET); + } +} + + +static char *mgc_usage[] = { + + "usage: %s [ ...]", + " find marked graph (MG) components. If no arguments are given", + " then any vertices which are not covered by the MG compoents", + " are printed, otherwise the components with the given numbers are", + " printed.", + +NULL }; + +static int com_astg_mgc (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + astg_retval result = ASTG_OK; + astg_graph *stg; + int c, n, status; + array_t *comp; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"")) != EOF) { + switch (c) { + default : result = ASTG_BAD_OPTION; break; + } + } + + stg = astg_current (*network_p); + + if (result == ASTG_BAD_OPTION || stg == NULL) { + astg_usage (mgc_usage,argv[0]); + return 1; + } + + status = get_mg_comp (stg,ASTG_TRUE); + dbg(1,msg("%d marked graph (MG) components.\n", array_n(stg->mg_comp))); + + if (util_optind == argc) { + if (status == ASTG_NOT_COVER) astg_sel_show (stg); + } + else { + for (; util_optind < argc; util_optind++) { + n = atoi (argv[util_optind]); + if (n > 0 && n <= array_n(stg->mg_comp)) { + comp = array_fetch (array_t *,stg->mg_comp,n-1); + select_comp (stg,comp,"MG",n); + } + else { + printf("There are only %d MG components.\n", + array_n(stg->mg_comp)); + } + } + } + + return (result != ASTG_OK); +} + +static char *smc_usage[] = { + + "usage: %s [ ...]", + " find state machine (SM) components. If no arguments are given", + " then any vertices which are not covered by the SM compoents", + " are printed, otherwise the components with the given numbers are", + " printed.", + +NULL }; + +static int com_astg_smc (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + astg_retval result = ASTG_OK; + astg_graph *stg; + int c, n, status; + array_t *comp; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"")) != EOF) { + switch (c) { + default : result = ASTG_BAD_OPTION; break; + } + } + + stg = astg_current (*network_p); + + if (result == ASTG_BAD_OPTION || stg == NULL) { + astg_usage (smc_usage,argv[0]); + return 1; + } + + status = get_sm_comp (stg,ASTG_TRUE); + dbg(1,msg("%d state machine (SM) components.\n", array_n(stg->sm_comp))); + + if (util_optind == argc) { + if (status == ASTG_NOT_COVER) astg_sel_show (stg); + } + else { + for (; util_optind < argc; util_optind++) { + n = atoi (argv[util_optind]); + if (n > 0 && n <= array_n(stg->sm_comp)) { + comp = array_fetch (array_t *,stg->sm_comp,n-1); + select_comp (stg,comp,"SM",n); + } + else { + printf("There are only %d SM components.\n", + array_n(stg->sm_comp)); + } + } + } + + return (result != ASTG_OK); +} + + +static char *contract_usage[] = { + + "usage: %s [-f] ", + " -f keep contracted nets Free Choice", + " generate the contracted net for the specified noninput signal", + +NULL }; + +static int com_astg_contract (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + astg_retval result = ASTG_OK; + astg_signal *sig_p; + astg_graph *cstg = NIL(astg_graph); + astg_bool keep_fc = ASTG_FALSE; + astg_graph *curr_stg; + int c; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"f")) != EOF) { + switch (c) { + case 'f': + keep_fc = ASTG_TRUE; + break; + default: + result = ASTG_BAD_OPTION; + break; + } + } + + curr_stg = astg_current (*network_p); + + if (result == ASTG_BAD_OPTION || util_optind != argc - 1 || curr_stg == NULL) { + result = ASTG_BAD_OPTION; + astg_usage (contract_usage,argv[0]); + } + else { + if (! astg_state_coding (curr_stg,ASTG_TRUE)) { + return 1; + } + sig_p = astg_find_named_signal (curr_stg,argv[util_optind]); + if (sig_p == NULL) { + printf("STG %s does not have signal '%s'.\n", + astg_name(curr_stg), argv[util_optind]); + } else if (sig_p->sig_type == ASTG_INPUT_SIG) { + printf("'%s' is an input signal.\n",argv[util_optind]); + } else { + cstg = astg_contract (curr_stg,sig_p,keep_fc); + astg_irred (cstg,ASTG_TRUE); + /* Set current stg to the contracted net. */ + astg_set_current (network_p,cstg,ASTG_TRUE); + } + } + + return (result != ASTG_OK); +} + +typedef struct astg_cmd_rec { + char *cmd_name; + int (*cmd)(); + astg_bool modifies; +} +astg_cmd_rec; + + +static astg_cmd_rec basic_commands[] = { + { "read_astg", com_astg_read, ASTG_TRUE }, + { "_astg_flow", com_astg_flow, ASTG_TRUE }, + { "astg_current", com_astg_current, ASTG_FALSE }, + { "astg_persist", com_astg_persist, ASTG_TRUE }, + { "astg_lockgraph", com_astg_lockgraph, ASTG_TRUE }, + { "_astg_cycle", com_astg_cycle, ASTG_FALSE }, + { "write_astg", com_astg_write, ASTG_FALSE }, + { "astg_marking", com_astg_marking, ASTG_TRUE }, + { "_astg_irred", com_astg_irred, ASTG_TRUE }, + { "astg_contract", com_astg_contract, ASTG_TRUE }, + { "_astg_smc", com_astg_smc, ASTG_FALSE }, + { "_astg_mgc", com_astg_mgc, ASTG_FALSE } +}; + +void astg_basic_cmds (do_init) +astg_bool do_init; /*i ASTG_TRUE=do initialize, ASTG_FALSE=do end. */ +{ + astg_cmd_rec *p; + int i; + + if (do_init) { + i = sizeof(basic_commands) / sizeof(basic_commands[0]); + for (p=basic_commands; i--; p++) { + com_add_command (p->cmd_name, p->cmd, p->modifies); + } + } + else { + astg_discard_daemons (); + } +} +#endif /* SIS */ diff --git a/sis/astg/astg_contract.c b/sis/astg/astg_contract.c new file mode 100644 index 0000000..507fbd5 --- /dev/null +++ b/sis/astg/astg_contract.c @@ -0,0 +1,437 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_contract.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* -------------------------------------------------------------------------- *\ + contract.c -- net contraction for LSFCN STGs. + + Contraction on LSFC nets is described by Chu [87] in his thesis. In + section 6, a detailed analysis is given which defines several restrictions + for how and when contraction can be done. This is implemented here. + + Questions: + Is the order of processing transitions important? + Chu mentions on p. 99 that "we trust that the results developed here + also apply to these nets which are non-FC (but behaviorally FC". Where + might this lead? + Does contraction really lead to a better implementation? + The check 6.8b can be simplified by finding a covering set of cycles instead + of all simple cycles. But not to worry for now. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + + +static void print_place_info (p) +astg_place *p; +{ + astg_generator gen; + astg_edge *e; + + astg_foreach_in_edge (p,gen,e) printf(" %s",astg_v_name(astg_tail(e))); + printf(" > %s:%d >",astg_v_name(p),p->type.place.initial_token); + astg_foreach_out_edge (p,gen,e) printf(" %s",astg_v_name(astg_head(e))); + printf("\n"); +} + +/* ----------------------------- Check Contract ----------------------------- *\ + + This implements the checks from Chu's dissertation to see if it is legal + to remove a transition as part of contraction. +\* -------------------------------------------------------------------------- */ + +static astg_bool check_62 (stg,te) +astg_graph *stg; +astg_vertex *te; +{ + astg_edge *e1, *e2, *e3; + astg_vertex *v, *p1, *p2; + astg_vertex *ti, *to; + astg_generator gen1, gen2, gen3; + + astg_foreach_vertex (stg,gen1,v) v->flag0 = ASTG_FALSE; + + /* Mark input places and transitions of te */ + astg_foreach_in_edge (te,gen1,e1) { + p1 = astg_tail (e1); + p1->flag0 = ASTG_TRUE; + astg_foreach_in_edge (p1,gen2,e2) { + ti = astg_tail (e2); + ti->flag0 = ASTG_TRUE; + } + } + + /* Now check Restriction 6.2, p. 100 Chu '87 */ + astg_foreach_out_edge (te,gen1,e1) { + p1 = astg_head (e1); + astg_foreach_out_edge (p1,gen2,e2) { + to = astg_head (e2); + if (to->flag0) { + if (astg_debug_flag >= 2) { + msg("%s fails 6.2a:",astg_v_name(p1)); + msg(" it's an input place for %s.\n",astg_v_name(to)); + msg("cycle includes: %s -> %s -> %s -> ...\n", + astg_v_name(te),astg_v_name(p1),astg_v_name(to)); + } + return ASTG_FALSE; + } + astg_foreach_out_edge (to,gen3,e3) { + p2 = astg_head (e3); + if (p2->flag0) { + if (astg_debug_flag >= 2) { + msg("%s fails 6.2b:",astg_v_name(p2)); + msg(" it's an output place for %s.\n",astg_v_name(to)); + msg("cycle is: %s -> %s -> %s -> %s ->...\n", + astg_v_name(te),astg_v_name(p1),astg_v_name(to),astg_v_name(p2)); + } + return ASTG_FALSE; + } + } + } + } + + return ASTG_TRUE; +} + +static astg_bool check_68a1 (te) +astg_vertex *te; +{ + astg_edge *e; + astg_vertex *place; + astg_generator gen; + + astg_foreach_in_edge (te,gen,e) { + place = astg_tail (e); + if (astg_out_degree (place) > 1) { + dbg(2,msg("6.8a1 violated by %s\n",astg_v_name(place))); + return ASTG_FALSE; + } + } + return ASTG_TRUE; +} + +static astg_bool check_68a2 (te) +astg_vertex *te; +{ + astg_edge *e; + astg_vertex *place; + astg_generator gen; + + astg_foreach_out_edge (te,gen,e) { + place = astg_head (e); + if (astg_in_degree (place) > 1) { + dbg(2,msg("6.8a2 violated by %s\n",astg_v_name(place))); + return ASTG_FALSE; + } + } + return ASTG_TRUE; +} + +static astg_bool check_68a (te) +astg_vertex *te; +{ + astg_bool pass_68a; + /* This check can be satisfied in two ways. */ + pass_68a = check_68a1(te) || check_68a2(te); + dbg(2,if (!pass_68a) msg("%s fails 6.8a\n")); + return pass_68a; +} + +static int mark_flag1 (stg,data) +astg_graph *stg; /*u set flag1 to ASTG_TRUE for all path vertices. */ +void *data; /* ARGSUSED */ +{ + astg_vertex *v; + astg_generator gen; + + astg_foreach_path_vertex (stg,gen,v) { + v->flag1 = ASTG_TRUE; + } + return 0; +} + +static int check_flag1 (stg,data) +astg_graph *stg; /*i return 1 if any flag1 is set on path. */ +void *data; /* ARGSUSED */ +{ + astg_generator gen; + astg_vertex *v; + int rc = 0; + + astg_foreach_path_vertex (stg,gen,v) { + if (v->flag1) rc = 1; + } + return rc; +} + +static astg_bool check_68b (stg,te) +astg_graph *stg; +astg_vertex *te; +{ + astg_generator gen1, gen2, gen3, gen4; + astg_vertex *v; + astg_vertex *ti, *to; + astg_edge *e1, *e2, *e3, *e4; + int overlap; + + if (astg_in_degree (te) <= 1) return ASTG_TRUE; + if (astg_out_degree (te) <= 1) return ASTG_TRUE; + + astg_foreach_in_edge (te,gen1,e1) { + astg_foreach_in_edge (astg_tail (e1), gen2, e2) { + ti = astg_tail (e2); + /* Mark all cycles that ti is in. */ + astg_foreach_vertex (stg,gen3,v) v->flag1 = ASTG_FALSE; + astg_simple_cycles (stg,ti,mark_flag1,ASTG_NO_DATA,ASTG_ALL); + astg_foreach_out_edge (te,gen3,e3) { + astg_foreach_out_edge (astg_head(e3),gen4,e4) { + to = astg_head (e4); + /* Check for overlap with cycles of ti */ + overlap = astg_simple_cycles (stg,to,check_flag1,ASTG_NO_DATA,ASTG_ALL); + if (overlap == 0) { + dbg(2,msg("6.8b violated for %s:",astg_v_name(te))); + dbg(2,msg(" %s and",astg_v_name(ti))); + dbg(2,msg(" %s would become sequential.\n",astg_v_name(to))); + return ASTG_FALSE; + } + } + } + } + } + + /* Whew. Passed the check */ + return ASTG_TRUE; +} + +static astg_bool check_68 (stg,te) +astg_graph *stg; +astg_vertex *te; +{ + return check_68a (te) && check_68b (stg,te); +} + +static astg_bool can_contract_trans (stg,te,keep_fc) +astg_graph *stg; +astg_vertex *te; +astg_bool keep_fc; /*i maintain free choice property? */ +{ + /* The STG can be contracted by eliminating transition te iff + te is not in the input set of the significant output signal, + and it meets the two restrictions given in Chu's thesis. */ + + astg_bool can_do_it; + + if (keep_fc) + can_do_it = check_62 (stg,te) && check_68 (stg,te); + else + can_do_it = check_68 (stg,te); + + return can_do_it; +} + +static astg_bool can_contract (stg,sig_p,keep_fc) +astg_graph *stg; +astg_signal *sig_p; +astg_bool keep_fc; +{ + astg_bool can_do_it = sig_p->can_elim; + astg_generator gen; + astg_trans *sv; + + if (can_do_it) { + astg_foreach_sig_trans (sig_p,gen,sv) { + can_do_it &= can_contract_trans (stg,sv,keep_fc); + } + } + + dbg(2,if (!can_do_it) msg("...cannot contract signal %s.\n",sig_p->name)); + return can_do_it; +} + +/* ------------------------------ Eliminate Signal -------------------------- */ + +static astg_bool pure_place_simple (p) +astg_vertex *p; +{ + astg_vertex *in_trans, *out_trans; + astg_generator gen; + astg_vertex *alt_p; + astg_edge *e; + + /* Only can test this for single fanin/fanout places. */ + if (astg_in_degree(p) == 1 && astg_out_degree(p) == 1) { + in_trans = p->in_edges->tail; + out_trans = p->out_edges->head; + + /* First check the pure part. */ + if (in_trans == out_trans) { + dbg(3,printf("not pure: ")); dbg(3,print_place_info(p)); + return ASTG_FALSE; + } + + /* Now check place simple. */ + astg_foreach_out_edge (in_trans,gen,e) { + alt_p = astg_head (e); + if (alt_p == p) continue; + if (astg_in_degree(alt_p) != 1 || astg_out_degree(alt_p) != 1) continue; + if (alt_p->out_edges->head == out_trans) { + dbg(3,printf("not place simple by %s: ",astg_v_name(alt_p))); + dbg(3,print_place_info(p)); + return ASTG_FALSE; + } + } + } + + /* Seems to be pure and place simple. */ + dbg(2,print_place_info(p)); + return ASTG_TRUE; +} + +static void elim_trans (stg,te) +astg_graph *stg; +astg_vertex *te; +{ + astg_edge *e1, *e2, *ex; + astg_vertex *pin, *pout; + astg_vertex *p_prime; + astg_generator gen1, gen2, gen3; + char pp_name[30]; + static int n = 0; + + dbg(2,msg("elim_trans %s\n",astg_v_name(te))); + + astg_foreach_in_edge (te,gen1,e1) { + pin = astg_tail (e1); + astg_foreach_out_edge (te,gen2,e2) { + pout = astg_head (e2); + (void) sprintf(pp_name,"pc_%d",n++); + /* Core leak on the name of this vertex... */ + /* Need a create_unique_vertex call. */ + p_prime = astg_new_place (stg,pp_name,NULL); + /* It is possible that both have a token. */ + if (pin->type.place.initial_token || pout->type.place.initial_token) { + p_prime->type.place.initial_token = ASTG_TRUE; + } + astg_foreach_in_edge (pin,gen3,ex) { + astg_new_edge (astg_tail(ex),p_prime); + } + astg_foreach_out_edge (pout,gen3,ex) { + astg_new_edge (p_prime,astg_head(ex)); + } + /* check for pure and place simple. */ + if (!pure_place_simple (p_prime)) astg_delete_place (p_prime); + } + } + + /* Now remove the old transition. */ + astg_foreach_in_edge (te,gen1,e1) { + pin = astg_tail (e1); + if (astg_out_degree(pin) == 1) astg_delete_place (pin); + } + astg_foreach_out_edge (te,gen2,e2) { + pout = astg_head (e2); + if (astg_in_degree(pout) == 1) astg_delete_place (pout); + } + astg_delete_trans (te); +} + +static void keep_in_sig (stg,sv,outsig) +astg_graph *stg; /* ARGSUSED */ +astg_trans *sv; +astg_signal *outsig; +{ + astg_vertex *en_trans, *place; + astg_signal *trigger, *context; + astg_generator gen1, gen2; + astg_vertex *v = sv; + + astg_foreach_input_place (v,gen1,place) { + + astg_foreach_input_trans (place,gen2,en_trans) { + + trigger = en_trans->type.trans.sig_p; + dbg(2,msg("%s is a trigger signal\n",trigger->name)); + trigger->can_elim = ASTG_FALSE; + + for (context=trigger; context != NULL; context=context->lg_from) { + dbg(2,msg("%s is a context signal\n",context->name)); + context->can_elim = ASTG_FALSE; + } + } + } +} + +static void elim_sig (g,sig_p) +astg_graph *g; +astg_signal *sig_p; +{ + astg_graph *stg = g; + astg_generator gen; + astg_trans *sv; + + /* eliminate signal completely. */ + astg_foreach_pos_trans (sig_p,gen,sv) { + elim_trans (g,sv); + } + + astg_foreach_neg_trans (sig_p,gen,sv) { + elim_trans (g,sv); + } + + stg->n_sig--; + assert (sig_p->sig_type == ASTG_INPUT_SIG); + DLL_REMOVE (sig_p,stg->sig_list,next,prev); + /* can't free it now, since iterator is in use */ +} + +/* ---------------------- Net Contraction Interface ------------------------- */ + +astg_graph *astg_contract (stg,outsig,keep_fc) +astg_graph *stg; +astg_signal *outsig; +astg_bool keep_fc; +{ + astg_graph *cstg; + astg_signal *sig_p, *one_out; + astg_trans *sv; + astg_generator gen; + char name[80]; + + dbg(2,msg("\ncontract net for %s...\n",outsig->name)); + + astg_foreach_signal (stg,gen,sig_p) { + sig_p->can_elim = ASTG_TRUE; + } + outsig->can_elim = ASTG_FALSE; + astg_lock_graph_shortest_path (stg,outsig); + astg_foreach_sig_trans (outsig,gen,sv) { + keep_in_sig (stg,sv,outsig); + } + + /* Make duplicate graph with single output signal. */ + sprintf(name,"net_%s",astg_signal_name(outsig)); + cstg = astg_duplicate (stg,name); + + astg_foreach_signal (cstg,gen,sig_p) { + sig_p->sig_type = ASTG_INPUT_SIG; + } + + one_out = astg_find_named_signal (cstg,astg_signal_name(outsig)); + one_out->sig_type = ASTG_OUTPUT_SIG; + cstg->n_out = 1; + + /* Is this order-sensitive? */ + astg_foreach_signal (cstg,gen,sig_p) { + if (can_contract (cstg,sig_p,keep_fc)) elim_sig (cstg,sig_p); + } + + return cstg; +} +#endif /* SIS */ diff --git a/sis/astg/astg_core.h b/sis/astg/astg_core.h new file mode 100644 index 0000000..1bc1806 --- /dev/null +++ b/sis/astg/astg_core.h @@ -0,0 +1,356 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_core.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* -------------------------------------------------------------------------- *\ + astg_core.h -- asynchronous signal transition graph core declarations. + + This is the "core" of the ASTG package, the lowest level data structures + and functions which the rest of the ASTG package is based on. Although + SIS supports multilevel combinational networks, it unfortunately does + not support a multilevel package implementation. So the "core" is sort + of a package within a package. See "astg_int.h" for the interface to + the core package. + + A signal transition graph (STG) is an interpreted Petri Net, which is a + bipartite graph with a marking. Transitions are modelled with type 0 + vertices and places are type 1 vertices. +\* -------------------------------------------------------------------------- */ + +#ifndef ASTG_CORE_H +#define ASTG_CORE_H + +#include "sis.h" +#include "astg.h" + + +#define ASTG_NAME_LEN 128 + +#define dbg(level,action) if (astg_debug_flag >= (level)) action +#define msg printf + +#define io_status(source) ((source)->errflag) + +#define astg_plx(p) (&(p)->type.place) +#define astg_trx(t) (&(t)->type.trans) + +/* ------------------------- astg_ba: array of bits ------------------------- */ + +typedef struct astg_ba_rec { + int n_elem; + int n_word; + unsigned *bit_array; +} astg_ba_rec; + +void astg_ba_set ARGS((astg_ba_rec *, int)); +void astg_ba_clr ARGS((astg_ba_rec *, int)); +astg_bool astg_ba_get ARGS((astg_ba_rec *, int)); +int astg_ba_cmp ARGS((astg_ba_rec *, astg_ba_rec *)); +astg_ba_rec *astg_ba_init ARGS((astg_ba_rec *, int)); +astg_ba_rec *astg_ba_new ARGS((int)); +astg_ba_rec *astg_ba_dup ARGS((astg_ba_rec *)); +void astg_ba_dispose ARGS((astg_ba_rec *)); + +/* -------------------- DLL : doubly-linked list macros --------------------- */ + +#define DLL_PREPEND(item,head,next,prev) \ + (item)->next = (head); \ + (item)->prev = NULL; \ + if ((head) != NULL) (head)->prev = (item); \ + (head) = (item); + +#define DLL_INSERT(item,head,next,prev,after) \ + if (after != NULL) { \ + (item)->next = (after)->next; \ + (item)->prev = (after); \ + if ((after)->next != NULL) (after)->next->prev = (item); \ + (after)->next = (item); \ + } else { \ + DLL_PREPEND(item,head,next,prev); \ + } + +#define DLL_REMOVE(item,head,next,prev) \ + if ((item)->next != NULL) (item)->next->prev = (item)->prev; \ + if ((item)->prev != NULL) (item)->prev->next = (item)->next; \ + else (head) = (item)->next; + + +#define get_bit(i,mask) (((i)&(mask))?1:0) +#define set_bit(i,mask) ((i)|=(mask)) +#define clr_bit(i,mask) ((i)&=~(mask)) +#define val_bit(i,mask,f) ((i)=(f)?((i)|(mask)):((i)&~(mask))) + + +struct astg_signal { + char *name; /* name of signal: a, b, etc. */ + astg_signal *next; /* linked list of signals */ + astg_signal *prev; /* doubly linked, for deletion */ + astg_signal *dup; /* used while duplicating */ + int id; /* for building lock matrix */ + astg_signal_enum sig_type; /* input, output, internal */ + astg_scode state_bit; /* for state coding */ + astg_bool all_in_one_smc;/* all trans found in some smc */ + astg_trans *t_list; /* List of transitions of this signal. */ + astg_bool sm_checked; /* astg_check_sm: signal was checked */ + int n_trans; /* set_opp: trans for this sig */ + int n_found; /* set_opp: trans found so far */ + astg_bool mark; /* set_opp: all trans found */ + astg_trans *last_trans; /* set_opp: prev. trans found */ + astg_bool can_elim; /* contract: signal can be eliminated? */ + + array_t *lg_edges; /* Lock graph edges adjacency list. */ + int lg_weight; /* Weight for finding shortest path. */ + astg_bool unprocessed; /* Flag for shortest path alg. */ + astg_signal *lg_from; /* To find shortest path, trace these. */ + lsHandle lg_queue; /* Handle in priority queue. */ +}; + + +typedef union astg_v_alg { /* algorithm-specific vertex fields */ + + struct { /* astg_simple_cycles */ + astg_edge *trail; /* edge from this vertex in cycle */ + } sc; + + struct { /* astg_strong_comp */ + int comp_num; /* numbering for the components */ + } scc; + + struct { /* astg_top_sort */ + int index; /* topological index for this vertex */ + } ts; + + struct { /* astg_connected_comp */ + int comp_num; /* numbering for the components */ + } cc; + + struct { /* astg_dup */ + astg_vertex *eq; /* equivalent vertex in new graph */ + } dup; + + struct { /* astg_maxflow */ + astg_edge *pathedge; /* edge to use for augmenting path */ + } mf; + + struct { /* astg_shortest_path */ + astg_vertex *from; /* how shortest path got to here */ + lsHandle util_p; /* direct access to priority queue */ + } sp; + +} astg_v_alg; + + +struct astg_place_info { + int flow_id; /* index of place during token flow */ + astg_bool user_named :1; /* user explicitly named this place? */ + astg_bool initial_token :1; /* initial token marking */ + astg_scode cset_label; /* For identifying concurreny. */ + astg_trans *token_from; /* Where current token came from. */ +}; + +struct astg_trans_info { + char *alpha_name; /* Name using only alpha and _ chars. */ + astg_signal *sig_p; /* signal this is for */ + astg_trans_enum trans_type; /* pos_x, neg_x, toggle, dummy */ + int copy_n; /* for duplicate transitions */ + astg_trans *parent; /* vertex in parent stg (for subgraphs) */ + astg_trans *next_t; /* link in pos_t/neg_t list */ + astg_trans *opp_trans; /* opposite transition in this stg */ + float delay; /* time to fire once enabled */ + astg_bool can_be_low :1; /* sig can be low after this trans? */ + astg_bool can_be_high :1;/* sig can be high after this? */ +}; + +typedef union astg_weight { + long i; + float f; +} astg_weight; + + +struct astg_vertex { + char *name; /* name of the vertex */ + astg_vertex *parent; /* vertex in parent stg (for subgraphs) */ + astg_vertex *next; /* link through all vertices in graph */ + astg_vertex *prev; /* doubly linked for easy deletion */ + astg_graph *stg; /* graph this vertex is in */ + astg_edge *out_edges; /* list of outgoing edges */ + astg_edge *in_edges; /* list of incoming edges */ + astg_bool active :1; /* marks active path during DFS */ + astg_bool unprocessed :1;/* marks processed vertices */ + astg_bool subset :1; /* for marking a subset for processing */ + astg_bool on_path :1; /* for reporting paths and cycles */ + astg_bool adjusting :1; /* cpm: vertex is being adjusted */ + astg_bool forward :1; /* maxflow: is flow increasing here? */ + astg_bool pkg_mem :1; /* memory allocated by graph package */ + astg_bool flag0 :1; /* Replace these generic flags. */ + astg_bool flag1 :1; + astg_bool flag2 :1; + astg_bool flag3 :1; + astg_bool useful :1; /* vertex used during token flow? */ + astg_bool selected :1; /* transition is in selection set? */ + astg_bool hilited :1; /* transition has been hilighted */ + float x,y; /* location of this transition */ + astg_v_alg alg; /* algorithm-specific vertex fields */ + astg_weight weight1; /* weight for maxflow, cpm, etc. */ + astg_weight weight2; /* weight for maxflow, cpm, etc. */ + void *userdata; /* whatever you want to do with this */ + + astg_vertex_enum vtype; /* Which union below is applicable. */ + union { /* Type-specific vertex information. */ + struct astg_place_info place; + struct astg_trans_info trans; + } type; +}; + + +struct astg_edge { + astg_vertex *tail; /* tail (source) end of this edge */ + astg_edge *prev_out; /* prev out edge for tail vertex */ + astg_edge *next_out; /* next out edge for tail vertex */ + astg_vertex *head; /* head (target) end of this edge */ + astg_edge *prev_in; /* prev in edge for head vertex */ + astg_edge *next_in; /* next in edge for head vertex */ + astg_bool cutset :1; /* maxflow: edge is in cutset */ + astg_bool pkg_mem :1; /* memory allocated by graph package */ + astg_bool flag0 :1; + astg_bool flag1 :1; + astg_weight weight1; /* weights for basic graph algorithms */ + astg_weight weight2; /* maxflow, cpm, shortest path, etc. */ + void *userdata; /* whatever you want to do with this */ + + char *guard_eqn; /* text description of guard */ + int guard_n; /* guard node name suffix */ + node_t *guard; /* only for output edges of places */ + array_t *spline_points; /* for displaying the edge */ + unsigned selected :1; /* edge has been selected */ + unsigned hilighted :1; /* edge has been highlighted */ +}; + + +struct astg_marking { /* Defines a single marking of the net. */ + astg_scode state_code; /* Vector of state bit values. */ + astg_scode enabled; /* Vector of enabled signals. */ + astg_ba_rec *marked_places; /* Places identified using flow_id. */ + astg_bool is_dummy; /* Marking has enabled dummy trans? */ +}; + + +struct astg_state { + array_t *states; /* state is just an array of markings */ + astg_graph *stg; /* parent STG for this state info. */ +}; + +typedef struct astg_flow { /* Information from net token flow. */ + long change_count; /* Change count for current flow states.*/ + astg_retval status; /* Status from last token flow. */ + st_table *state_list; /* Reached in token flow, astg_state*. */ + astg_scode initial_state; /* For saving initial state code. */ + astg_scode flip_phase; /* Used by flow to find new phase adj. */ + astg_scode phase_adj; /* Correction for state code phase. */ + int in_width; /* Input width for token flow. */ + int out_width; /* Output width for token flow. */ +} astg_flow; + + + +struct astg_graph { + astg_vertex *vertices; /* linked list of vertices */ + astg_vertex *vtail; /* tail end of vertex list */ + long change_count; /* incremented on every change to graph */ + int (*f)(); /* user callback for graph algorithms */ + void *f_data; /* user data for callbacks */ + char *name; /* graph name */ + astg_graph *parent; /* for subgraphs */ + int n_vertex; /* number of vertices */ + int n_edge; /* number of edges */ + astg_vertex *path_start; /* For reporting paths in graph. */ + int next_place; /* generating unique place names */ + int next_sig; /* generating unique signal names */ + int guard_n; /* for generating guard names */ + network_t *guards; /* astg_bool conditions on place edges */ + lsList comments; /* save entire-line comments */ + char *filename; /* file this came from (if any) */ + long file_count; /* initial change count for the STG */ + int n_sig; /* total number of signals */ + int n_out; /* number of output signals */ + astg_signal *sig_list; /* head of signal DLL list */ + char *sel_name; /* name of current selection set */ + astg_bool has_marking; /* set if marking already */ + array_t *sm_comp; /* state machine components */ + long smc_count; /* change count for current smc */ + array_t *mg_comp; /* marked graph components */ + long mgc_count; /* change count for current mgc */ + astg_flow flow_info; /* exhaustive token flow for net */ + void* slots[ASTG_N_SLOTS]; /* Array of slots for data. */ +}; + +typedef struct astg_daemon_t { + struct astg_daemon_t *next; /* Singly-linked list of daemons. */ + astg_daemon_enum type; /* Which type of daemon this is. */ + astg_daemon daemon; /* The daemon to call. */ +} astg_daemon_t; + +typedef struct astg_flow_t { /* Info for generating markings. */ + astg_retval status; /* status code, 0=ok, see astg.h */ + astg_bool force_safe; /* ASTG_TRUE=avoid unsafe markings */ + astg_graph *stg; /* graph to generate reachability graph */ + astg_scode state_code; /* used during guard evaluation */ + astg_marking*marking; /* current marking of the flow */ +} astg_flow_t; + +typedef struct io_t { + astg_bool from_file; /* reading from file or string? */ + astg_bool errflag; /* used by io_error */ + char *inbuf; /* input buffer for stream */ + int in_len; /* length of input buffer */ + int line_n; /* which line */ + char *next_c; /* current character pointer */ + char *buffer; /* for reading from a file */ + int buflen; /* length of input buffer */ + FILE *stream; /* stream if from file */ + char *s; /* current input buffer */ + char *p; /* current position in input */ + int save_one; /* single-character undo */ +} io_t; + + +typedef astg_bool (*astg_pi_fcn) ARGS((char *, astg_graph *, void *)); + + +char *astg_make_name ARGS((char *, astg_trans_enum, int)); +astg_signal *astg_new_sig ARGS((astg_graph *, astg_signal_enum)); +astg_signal *astg_dup_signals ARGS((astg_signal *)); +astg_bool astg_sim_node ARGS((node_t *, astg_pi_fcn, astg_graph *, void *)); +int astg_register ARGS((astg_graph *)); +void astg_write_marking ARGS((astg_graph *, FILE *)); +astg_retval get_sm_comp ARGS((astg_graph *, astg_bool)); +astg_retval get_mg_comp ARGS((astg_graph *, astg_bool)); +astg_retval astg_usc ARGS((astg_graph *)); +astg_retval astg_check_sm ARGS((astg_graph *)); +void astg_lock_graph_shortest_path ARGS((astg_graph *, astg_signal *)); +int astg_lock_graph_components ARGS((astg_graph *, int (*)(array_t *,int,void*), void*)); +astg_bool astg_is_rel ARGS((astg_trans *, astg_trans *)); +void astg_set_marking ARGS((astg_graph *, astg_marking *)); +astg_bool astg_set_guard ARGS((astg_edge *, char *, io_t *)); +astg_scode astg_marking_enabled ARGS((astg_marking *)); +void astg_make_place_name ARGS((astg_graph *, astg_place *)); + +void io_open ARGS((io_t *, FILE *, char *)); +static void io_unget ARGS((int, io_t *)); +int io_get ARGS((io_t *)); +static int io_getc ARGS((io_t *)); +int io_error ARGS((io_t *, char *)); + +astg_trans *find_trans_by_name ARGS((io_t *, astg_graph *, astg_bool)); +void astg_read_marking ARGS((io_t *, astg_graph *)); +void astg_do_daemons ARGS((astg_graph *, astg_graph *, astg_daemon_enum)); +void astg_discard_daemons ARGS(()); +array_t *astg_check_new_state ARGS((astg_flow_t*, astg_scode)); +void astg_flow_setup ARGS((astg_flow_t*, astg_graph*)); + +#endif /* ASTG_CORE_H */ diff --git a/sis/astg/astg_core1.c b/sis/astg/astg_core1.c new file mode 100644 index 0000000..9918d3a --- /dev/null +++ b/sis/astg/astg_core1.c @@ -0,0 +1,2137 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_core1.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* -------------------------------------------------------------------------- *\ + astg.c -- Lowest level graph functions and algorithms for ASTG. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + +int astg_debug_flag; + + +/* ------------------------------ Bit arrays -------------------------------- */ + +static unsigned BA_WORD_SIZE = 0; /* Number of bits in an unsigned. */ +static unsigned BA_WORD_BITS; /* Bits for 0..WORDSIZE-1. */ +static unsigned BA_WORD_MASK; /* Mask of BA_WORD_BITS 1's. */ + +void astg_ba_init_param () +{ + unsigned int one_bit = 1; + int n_bit; + + if (BA_WORD_SIZE != 0) return; + + for (n_bit=0,one_bit=1; one_bit != 0; one_bit<<=1) { + n_bit++; + } + BA_WORD_SIZE = n_bit; + + BA_WORD_MASK = BA_WORD_BITS = 0; + while (n_bit != 1) { + BA_WORD_BITS++; + BA_WORD_MASK = (BA_WORD_MASK << 1) | 1; + n_bit /= 2; + } +} + +void astg_ba_set (ba,n) +astg_ba_rec *ba; +int n; +{ + if (n < 0 || n > ba->n_elem) fail("bad index"); + ba->bit_array[n>>BA_WORD_BITS] |= (1<<(n&BA_WORD_MASK)); +} + +void astg_ba_clr (ba,n) +astg_ba_rec *ba; +int n; +{ + if (n < 0 || n > ba->n_elem) fail("bad index"); + ba->bit_array[n>>BA_WORD_BITS] &= ~(1<<(n&BA_WORD_MASK)); +} + +astg_bool astg_ba_get (ba,n) +astg_ba_rec *ba; +int n; +{ + unsigned which_int, bit_mask; + + if (n < 0 || n > ba->n_elem) fail("bad index"); + which_int = ba->bit_array[n>>BA_WORD_BITS]; + bit_mask = 1 << (n&BA_WORD_MASK); + return ((which_int & bit_mask) != 0); +} + +int astg_ba_cmp (ba1,ba2) +astg_ba_rec *ba1, *ba2; +{ + int result; + int n_byte; + + if (ba1->n_elem != ba2->n_elem) { + result = (ba1->n_elem - ba2->n_elem); + } + else { + n_byte = ba1->n_word * sizeof(unsigned); + result = memcmp ((char *)ba1->bit_array,(char *)ba2->bit_array,n_byte); + } + + return result; +} + +astg_ba_rec *astg_ba_init (b,n) +astg_ba_rec *b; +int n; +{ + /* Initialize a bitarray record. */ + int n_byte; + + b->n_elem = n; + b->n_word = (n+BA_WORD_SIZE) / BA_WORD_SIZE; + b->bit_array = ALLOC (unsigned,b->n_word); + n_byte = b->n_word * sizeof(unsigned); + memset ((char *)b->bit_array,0,n_byte); + return b; +} + +astg_ba_rec *astg_ba_new (n) +int n; +{ + return astg_ba_init(ALLOC(astg_ba_rec,1),n); +} + +astg_ba_rec *astg_ba_dup (b) +astg_ba_rec *b; +{ + astg_ba_rec *bcopy; + int n_byte; + + bcopy = astg_ba_new (b->n_elem); + n_byte = b->n_word * sizeof(unsigned); + (void) memcpy ((char *)bcopy->bit_array, (char *)b->bit_array, n_byte); + return bcopy; +} + +void astg_ba_dispose (ba) +astg_ba_rec *ba; +{ + FREE (ba->bit_array); + FREE (ba); +} + +/* --------------------------- Generic Vertex ------------------------------- */ + +static astg_vertex *astg_new_vertex (stg,vtype,name,userdata) +astg_graph *stg; +astg_vertex_enum vtype; +char *name; +void *userdata; +{ + astg_vertex *v = ALLOC (astg_vertex,1); + + v->vtype = vtype; + v->x = v->y = 0.0; + stg->change_count++; + v->stg = stg; + v->subset = ASTG_TRUE; + v->selected = ASTG_FALSE; + v->userdata = userdata; + v->out_edges = v->in_edges = NULL; + stg->n_vertex++; + v->name = (name == NULL) ? NULL : util_strsav(name); + + DLL_INSERT (v,stg->vertices,next,prev,stg->vtail); + stg->vtail = v; + return v; +} + +extern astg_vertex_enum astg_v_type (v) +astg_vertex *v; +{ + /* Return whether a vertex is a place or transition. */ + return v->vtype; +} + +char *astg_v_name (v) +astg_vertex *v; +{ + return (v->name != NULL) ? v->name : "*unnamed*"; +} + +void astg_set_useful (v,value) +astg_vertex *v; +astg_bool value; +{ + v->useful = value; +} + +astg_bool astg_get_useful (v) +astg_vertex *v; +{ + return v->useful; +} + +void astg_delete_vertex (v) +astg_vertex *v; +{ + astg_graph *stg = v->stg; + astg_generator gen; + astg_edge *e; + + astg_foreach_out_edge (v,gen,e) astg_delete_edge (e); + astg_foreach_in_edge (v,gen,e) astg_delete_edge (e); + + FREE (v->name); + DLL_REMOVE (v,stg->vertices,next,prev); + if (stg->vtail == v) stg->vtail = v->prev; + stg->n_vertex--; + stg->change_count++; + FREE (v); +} + +extern int astg_out_degree (v) +astg_vertex *v; +{ + /* Return the out-degree of a vertex. */ + int n_out_edge = 0; + astg_generator gen; + astg_edge *e; + + astg_foreach_out_edge (v,gen,e) n_out_edge++; + return n_out_edge; +} + +extern int astg_in_degree (v) +astg_vertex *v; +{ + /* Return the in-degree of a vertex. */ + int n_in_edge = 0; + astg_generator gen; + astg_edge *e; + + astg_foreach_in_edge (v,gen,e) n_in_edge++; + return n_in_edge; +} + +extern int astg_degree (v) +astg_vertex *v; +{ + /* Return the degree (in-degree+out-degree) of a vertex. */ + return astg_in_degree(v) + astg_out_degree(v); +} + +void astg_set_v_locn (v,x,y) +astg_vertex *v; +float *x, *y; +{ + v->x = *x; + v->y = *y; +} + +void astg_get_v_locn (v,xp,yp) +astg_vertex *v; +float *xp, *yp; +{ + *xp = v->x; *yp = v->y; +} + +void astg_set_hilite (v,value) +astg_vertex *v; +astg_bool value; +{ + v->hilited = value; +} + +astg_bool astg_get_hilite (v) +astg_vertex *v; +{ + return v->hilited; +} + +astg_bool astg_get_selected (v) +astg_vertex *v; +{ + return v->selected; +} + +/* ------------------------------- Places ----------------------------------- */ + +astg_place *astg_new_place (g,name,userdata) +astg_graph *g; +char *name; +void *userdata; +{ + astg_place *p = astg_new_vertex (g,ASTG_PLACE,name,userdata); + p->type.place.initial_token = ASTG_FALSE; + p->type.place.user_named = ASTG_FALSE; + p->type.place.flow_id = -1; + return p; +} + +static astg_place *astg_dup_place (g,old_p) +astg_graph *g; +astg_place *old_p; +{ + astg_place *p = astg_new_place (g,old_p->name,NULL); + p->x = old_p->x; p->y = old_p->y; + p->parent = old_p; + old_p->alg.dup.eq = p; + p->type.place.initial_token = old_p->type.place.initial_token; + return p; +} + +void astg_delete_place (p) +astg_place *p; +{ + astg_delete_vertex (p); +} + +astg_bool astg_boring_place (p) +astg_place *p; +{ + return ( p->vtype == ASTG_PLACE && + !p->type.place.user_named && + astg_in_degree(p) == 1 && + astg_out_degree(p) == 1 ); +} + +extern char *astg_place_name (p) +astg_place *p; +{ + /* Return name of a place. Do not modify the string. */ + + static char pname[80], *rc; + char *in, *out; + + if (astg_boring_place (p)) { + in = astg_trans_name (astg_tail (p->in_edges)); + out = astg_trans_name (astg_head (p->out_edges)); + sprintf(pname,"<%s,%s>", in, out); + rc = pname; + } + else { + rc = astg_v_name(p); + } + return rc; +} + +extern astg_place *astg_find_place (stg,name,create) +astg_graph *stg; +char *name; +astg_bool create; +{ + /* Return the specified place, or NULL if it does not exist. If create + is true, the place is created if it does not already exist. If name + is NULL, it does not match any existing place, and a new, unnamed + place is created if necessary. */ + + astg_generator pgen; + astg_place *p, *new_p = NULL; + astg_bool found = ASTG_FALSE; + + if (name != NULL) { + astg_foreach_place (stg,pgen,p) { + if (!found && p->name != NULL && !strcmp(p->name,name)) { + found = ASTG_TRUE; + new_p = p; + } + } + } + + if (!found && create) { + new_p = astg_new_place (stg,name,NULL); + } + + return new_p; +} + +void astg_make_place_name (stg,p) +astg_graph *stg; +astg_place *p; +{ + /* If the place does not have a name (because it was created implicitly) + then generate and assign one now. */ + + char place_name[20]; + + if (p->name == NULL) { + do { + sprintf(place_name,"pin%d",stg->next_place++); + } while (astg_find_place (stg,place_name,ASTG_FALSE)); + p->name = util_strsav(place_name); + } +} + +/* -------------------------------------------------------------------------- *\ + The flow search history is maintained in a hash table, key=state code, + data=array of markings and enabled transitions for that + state. This allows state coding problems to be detected: for a new + state, look up all previous markings, if any are incompatible then there + is a state coding problem. If the marking was used directly as the key, + this could not be done. + + The state code that is hashed is the uncorrected state code, which must + be interpreted using the phase_adj mask after the flow is completed. +\* ---------------------------------------------------------------------------*/ + +static enum st_retval free_marking_info (key,value,arg) +char *key; /* ARGSUSED */ +char *value; /* astg_state * */ +char *arg; /* ARGSUSED */ +{ + /* Callback for st_foreach for flow states. */ + astg_delete_state ((astg_state *)value); + return ST_DELETE; +} + +astg_bool astg_reset_state_graph (stg) +astg_graph *stg; +{ + /* If the existing state graph is out of date, clear it and return + ASTG_TRUE, else return ASTG_FALSE. */ + + astg_scode state_bit; + astg_generator gen; + astg_trans *t; + astg_place *p; + astg_signal *sig_p; + int n_place = 0; + + if (stg->change_count == stg->flow_info.change_count) return ASTG_FALSE; + + stg->flow_info.status = ASTG_OK; + stg->flow_info.change_count = stg->change_count; + stg->flow_info.phase_adj = 0; + stg->flow_info.initial_state = 0; + + if (stg->flow_info.state_list != NULL) { + st_foreach (stg->flow_info.state_list,free_marking_info,NIL(char)); + st_free_table (stg->flow_info.state_list); + stg->flow_info.state_list = NULL; + } + + state_bit = 1; + stg->flow_info.in_width = 0; + stg->flow_info.out_width = 0; + + astg_foreach_signal (stg,gen,sig_p) { + if (astg_is_noninput(sig_p)) { + stg->flow_info.in_width++; + stg->flow_info.out_width++; + sig_p->state_bit = state_bit; + state_bit <<= 1; + } + } + + astg_foreach_signal (stg,gen,sig_p) { + if (astg_is_input(sig_p)) { + stg->flow_info.in_width++; + sig_p->state_bit = state_bit; + state_bit <<= 1; + } + dbg(2,msg("%s: 0x%X\n",sig_p->name,sig_p->state_bit)); + } + + astg_foreach_trans (stg,gen,t) { + astg_set_useful (t,ASTG_FALSE); + } + + astg_foreach_place (stg,gen,p) { + astg_set_useful (p,ASTG_FALSE); + astg_plx(p)->flow_id = n_place++; + } + + stg->flow_info.state_list = st_init_table (st_numcmp,st_numhash); + return ASTG_TRUE; +} + +extern astg_state *astg_find_state (stg,real_code,create) +astg_graph *stg; +astg_scode real_code; +astg_bool create; +{ + /* Return the state information for a state code, or NULL if it could + not be returned (flow not performed, invalid state code, etc.). If + not found and create is ASTG_TRUE, then a new state with no markings + is created. */ + + astg_state *state = NULL; + astg_scode scode = real_code ^ stg->flow_info.phase_adj; + + if (!st_lookup (stg->flow_info.state_list,(char *)scode, (char **)&state)) { + if (create) { + /* Create a new state record with zero markings. */ + state = astg_new_state (stg); + st_insert (stg->flow_info.state_list, (char *)scode, (char *)state); + } + } + return state; +} + +/* ------------------------ More Token Firing Stuff ------------------------- */ + +astg_bool astg_sim_node (node,f,stg,data) +node_t *node; +astg_pi_fcn f; +astg_graph *stg; +void *data; +{ + int cube_n, in_n; + node_t *fanin; + node_cube_t cube; + astg_bool result; + + switch (node_function(node)) { + + case NODE_PI: + result = (*f) (node_name(node),stg,data); + break; + + case NODE_PO: + assert (node_num_fanin(node) == 1); + result = astg_sim_node (node_get_fanin(node,0), f,stg,data); + break; + + case NODE_0: + result = ASTG_FALSE; + break; + + case NODE_1: + result = ASTG_TRUE; + break; + + default: + result = ASTG_FALSE; + for (cube_n=node_num_cube(node); cube_n-- && !result; ) { + result = ASTG_TRUE; + cube = node_get_cube (node, cube_n); + foreach_fanin (node, in_n, fanin) { + if (!result) continue; + switch (node_get_literal (cube, in_n)) { + case ONE : result = astg_sim_node (fanin,f,stg,data); break; + case ZERO: result = !astg_sim_node (fanin,f,stg,data); break; + } + } + } + break; + + } /* end switch */ + + dbg(2,msg("sim %s = %d\n",node_name(node),result)); + return result; +} + +astg_bool astg_signal_level (sig_name,stg,data) +char *sig_name; +astg_graph *stg; +void *data; +{ + astg_marking *marking = (astg_marking *) data; + astg_signal *sig_p; + astg_bool value; + + sig_p = astg_find_named_signal (stg,sig_name); + assert (sig_p != NULL); + value = astg_get_level (sig_p, marking->state_code); + dbg(2,msg(" sig %s level %d\n",sig_name,value)); + return value; +} + +astg_retval astg_mark (place,marking) +astg_vertex *place; +astg_marking *marking; +{ + astg_retval status = ASTG_OK; + + if (astg_get_marked(marking,place)) { + status = ASTG_NOT_SAFE; + astg_sel_new (place->stg,"unsafe place",ASTG_FALSE); + astg_sel_vertex (place,ASTG_TRUE); + dbg(1,msg("Unsafe marking at place %s\n",astg_v_name(place))); + } + else { + astg_set_marked (marking,place,ASTG_TRUE); + } + return status; +} + +void astg_unmark (place,marking) +astg_vertex *place; +astg_marking *marking; +{ + assert (place); + astg_ba_clr (marking->marked_places,place->type.place.flow_id); +} + +int astg_disabled_count (trans,marking) +astg_trans *trans; +astg_marking *marking; +{ + /* Returns number of input places which do not have a token. */ + + int in_degree = astg_in_degree (trans); + int n_marked = 0; + astg_edge *e; + astg_generator gen; + astg_place *p; + + astg_foreach_in_edge (trans,gen,e) { + p = astg_tail (e); + if (astg_get_marked (marking,p) && + (e->guard_eqn == NULL || + astg_sim_node (e->guard,astg_signal_level,trans->stg,(void *)marking))) { + n_marked++; + } + } + + return (in_degree-n_marked); +} + +void astg_print_state (stg,state) +astg_graph *stg; +astg_scode state; +{ + astg_signal *sig_p; + astg_generator gen; + + astg_foreach_signal (stg,gen,sig_p) { + printf(" %s=%d",astg_signal_name(sig_p),astg_get_level(sig_p,state)); + } + fputs("\n",stdout); +} + +void astg_print_marking (marking_n,stg,marking) +int marking_n; /*i title to print for this marking */ +astg_graph *stg; /*i the STG doing the flow for */ +astg_marking *marking; /*i the marking to print */ +{ + astg_generator gen; + astg_place *p; + + printf("marking %d\n state 0x%lX, enabled 0x%lX\n marked:", + marking_n, marking->state_code, marking->enabled); + + astg_foreach_place (stg,gen,p) { + if (astg_get_marked (marking,p)) { + printf(" %s",astg_place_name(p)); + } + } + printf("\n"); +} + +extern void astg_set_marking (stg,marking_p) +astg_graph *stg; +astg_marking *marking_p; +{ + /* Set the STG marking to the specified one. This new marking will be + returned by astg_initial_marking until it is changed again. It is + also used for astg_token_flow. The stg change count is incremented + if the new marking is different than the old one. */ + + astg_generator pgen; + astg_place *p; + astg_bool changed = !stg->has_marking; + + dbg(1,msg("changing marking to %x\n",marking_p->state_code)); + astg_foreach_place (stg,pgen,p) { + if (astg_plx(p)->initial_token != astg_get_marked (marking_p,p)) { + changed = ASTG_TRUE; + astg_plx(p)->initial_token = astg_get_marked (marking_p,p); + } + } + stg->flow_info.initial_state = marking_p->state_code; + stg->has_marking = ASTG_TRUE; + if (changed) stg->change_count++; +} + +astg_scode astg_adjusted_code (stg,scode) +astg_graph *stg; +astg_scode scode; +{ + return (scode ^ stg->flow_info.phase_adj); +} + +astg_scode astg_fire (marking,t) +astg_marking *marking; +astg_trans *t; +{ + astg_generator gen; + astg_edge *e; + astg_scode tmask; + astg_scode new_state, real_state; + int should_be, is; + astg_graph *stg = t->stg; + + tmask = astg_trx(t)->sig_p->state_bit; + new_state = marking->state_code ^ tmask; + + if (astg_trx(t)->trans_type == ASTG_POS_X || astg_trx(t)->trans_type == ASTG_NEG_X) { + real_state = new_state ^ stg->flow_info.phase_adj; + should_be = (astg_trx(t)->trans_type == ASTG_POS_X); + is = get_bit (real_state,tmask); + if (should_be && !is || is && !should_be) { + /* Seem to have the phase wrong. */ + if (get_bit (stg->flow_info.phase_adj,tmask)) { + /* But we've tried correction already. */ + stg->flow_info.status = ASTG_NOT_CSA; + astg_sel_new (stg,"Inconsistent state assignment",ASTG_FALSE); + dbg(1,msg("Phase error for %s.\n",astg_trans_name(t))); + astg_sel_vertex (t,ASTG_TRUE); + } + set_bit (stg->flow_info.phase_adj,tmask); + } + } + + astg_foreach_in_edge (t,gen,e) { + astg_unmark (astg_tail(e),marking); + } + + marking->state_code ^= t->type.trans.sig_p->state_bit; + dbg(2,msg("fire %s = 0x%lX\n",astg_trans_name(t),marking->state_code)); + + astg_foreach_out_edge (t,gen,e) { + astg_mark (astg_head(e),marking); + } + return new_state; +} + +astg_scode astg_unfire (marking,t) +astg_marking *marking; +astg_trans *t; +{ + astg_edge *e; + astg_scode prev_state; + astg_generator gen; + + prev_state = marking->state_code ^ astg_trx(t)->sig_p->state_bit; + + astg_foreach_out_edge (t,gen,e) { + astg_unmark (astg_head(e),marking); + } + + marking->state_code ^= t->type.trans.sig_p->state_bit; + dbg(2,msg("unfire %s = 0x%lX\n",astg_v_name(t),marking->state_code)); + + astg_foreach_in_edge (t,gen,e) { + astg_mark (astg_tail(e),marking); + } + return prev_state; +} + +void astg_set_flow_status (stg,status) +astg_graph *stg; +astg_retval status; +{ + stg->flow_info.status = status; +} + +astg_scode astg_get_enabled (marking) +astg_marking *marking; +{ + return marking->enabled; +} + +astg_retval astg_get_flow_status (stg) +astg_graph *stg; +{ + return stg->flow_info.status; +} + +void astg_delete_marking (marking) +astg_marking *marking; +{ + FREE (marking->marked_places); + FREE (marking); +} + +astg_marking *astg_dup_marking (marking) +astg_marking *marking; +{ + astg_marking *dup = ALLOC (astg_marking,1); + dup->marked_places = astg_ba_dup (marking->marked_places); + dup->enabled = marking->enabled; + dup->state_code = marking->state_code; + dup->is_dummy = marking->is_dummy; + return dup; +} + +extern astg_marking *astg_initial_marking (stg) +astg_graph *stg; +{ + /* Return initial marking of the STG if there is one, or NULL. */ + + astg_marking *marking = ALLOC (astg_marking,1); + astg_generator pgen; + astg_place *p; + int n_place = 0; + + astg_foreach_place (stg,pgen,p) { + n_place++; + } + + marking->marked_places = astg_ba_new (n_place); + marking->enabled = 0; + marking->state_code = 0; + marking->is_dummy = ASTG_FALSE; + + astg_foreach_place (stg,pgen,p) { + if (astg_plx(p)->initial_token) { + astg_mark (p,marking); + } + } + return marking; +} + +void astg_set_marked (marking,p,value) +astg_marking *marking; +astg_place *p; +astg_bool value; +{ + if (value) { + astg_ba_set (marking->marked_places,p->type.place.flow_id); + } else { + astg_ba_clr (marking->marked_places,p->type.place.flow_id); + } +} + +extern astg_bool astg_get_marked (marking,p) +astg_marking *marking; +astg_place *p; +{ + /* Return true if this place has a token in this marking or + * if the place has no flow-id, i.e. it has just been added (e.g. by the + * state encoding routines) + */ + + if (p->type.place.flow_id < 0) { + return 1; + } + return astg_ba_get (marking->marked_places,p->type.place.flow_id); +} + +/* ---------------------------- Transitions --------------------------------- */ + +static char *astg_sanitize_name (name) +char *name; +{ + char c, *p, *s, buffer[100], tmp[2]; + + buffer[0] = '\0'; + for (p=name; *p != 0; p++) { + c = *p; + if (isalpha(c)) { + tmp[0] = c; tmp[1] = '\0'; + s = tmp; + } else if (c == '+') { + s = "_plus"; + } else if (c == '-') { + s = "_minus"; + } else if (c == '~') { + s = "_toggle"; + } else { + s = "x"; + } + strcat(buffer,s); + } + + return util_strsav(buffer); +} + +astg_trans *astg_new_trans (g,name,userdata) +astg_graph *g; +char *name; +void *userdata; +{ + astg_trans *t = astg_new_vertex (g,ASTG_TRANS,name,userdata); + + t->type.trans.sig_p = NULL; + t->type.trans.delay = 0.0; + t->type.trans.alpha_name = astg_sanitize_name (t->name); + return t; +} + +static astg_trans *astg_dup_trans (g,old_t) +astg_graph *g; +astg_trans *old_t; +{ + astg_trans *t = astg_find_trans (g,old_t->type.trans.sig_p->name, + old_t->type.trans.trans_type, + old_t->type.trans.copy_n, TRUE); + t->x = old_t->x; t->y = old_t->y; + t->parent = old_t; + old_t->alg.dup.eq = t; + /* Could use signal dup to copy signal info here. */ + return t; +} + +void astg_delete_trans (t) +astg_place *t; +{ + astg_generator gen; + astg_trans *tx; + + astg_foreach_sig_trans (t->type.trans.sig_p,gen,tx) { + if (tx->type.trans.next_t == t) { + tx->type.trans.next_t = t->type.trans.next_t; + } + } + + FREE (t->type.trans.alpha_name); + astg_delete_vertex (t); +} + +static void astg_link_trans (new_t) +astg_trans *new_t; +{ + new_t->type.trans.next_t = new_t->type.trans.sig_p->t_list; + new_t->type.trans.sig_p->t_list = new_t; +} + +char *astg_trans_alpha_name (t) +astg_trans *t; +{ + return t->type.trans.alpha_name; +} + +astg_trans_enum astg_trans_type (t) +astg_trans *t; +{ + return t->type.trans.trans_type; +} + +extern char *astg_trans_name (t) +astg_place *t; +{ + /* Return name of a transition. Do not modify the string. */ + + return astg_v_name(t); +} + +extern astg_trans *astg_find_trans (stg,sig_name,type,copy_n,create) +astg_graph *stg; +char *sig_name; +astg_trans_enum type; +int copy_n; +astg_bool create; +{ + /* Return the corresponding transition, or NULL if it does not exist. + If create is true, the transition is created if it does not already + exist (and thus will never return NULL). */ + + astg_generator tgen; + astg_trans *t, *new_t = NULL; + astg_bool found = ASTG_FALSE; + astg_signal *sig_p; + char *saved_name; + + astg_foreach_trans (stg,tgen,t) { + if (!found && t->type.trans.copy_n == copy_n && t->type.trans.trans_type == type && + !strcmp(t->type.trans.sig_p->name,sig_name)) { + found = ASTG_TRUE; + new_t = t; + } + } + + if (!found && create) { + sig_p = astg_find_named_signal (stg,sig_name); + if (sig_p == NULL || + (type == ASTG_DUMMY_X && sig_p->sig_type != ASTG_DUMMY_SIG) + || (type != ASTG_DUMMY_X && sig_p->sig_type == ASTG_DUMMY_SIG)) { + new_t = NULL; + } + else { + saved_name = astg_make_name (sig_name,type,copy_n); + new_t = astg_new_trans (stg,saved_name,NULL); + new_t->type.trans.trans_type = type; + new_t->type.trans.copy_n = copy_n; + new_t->type.trans.sig_p = sig_p; + astg_link_trans (new_t); + } + } + + return new_t; +} + +extern astg_trans *astg_noninput_trigger (one_trans) +astg_trans *one_trans; +{ + /* Return a noninput signal which enables t. If there is more than + one such signal, an arbitrary one is selected. */ + + astg_trans *t = one_trans; + astg_place *p; + + while (astg_is_input(t->type.trans.sig_p)) { + p = astg_tail (t->in_edges); + t = astg_tail (p->in_edges); + if (t == one_trans) return NULL; + } + return t; +} + +astg_bool astg_has_constraint (t1,t2) +astg_trans *t1, *t2; +{ + astg_bool found = ASTG_FALSE; + astg_generator pgen, tgen; + astg_place *p; + astg_trans *tx; + + astg_foreach_output_place (t1,pgen,p) { + if (found) continue; + astg_foreach_output_trans (p,tgen,tx) { + if (tx == t2) found = ASTG_TRUE; + } + } + return found; +} + +astg_signal *astg_trans_sig (t) +astg_trans *t; +{ + return t->type.trans.sig_p; +} + +/* -------------------------------- Edges ----------------------------------- */ + +astg_edge *astg_new_edge (tail,head) +astg_vertex *tail; +astg_vertex *head; +{ + astg_edge *e = ALLOC (astg_edge,1); + astg_graph *stg = head->stg; + + if (head->vtype == tail->vtype) fail(""); + if (head->stg != tail->stg) fail(""); + + e->userdata = NULL; + e->tail = tail; + e->guard_eqn = NULL; + e->guard = NULL; + e->spline_points = NULL; + + stg->n_edge++; + stg->change_count++; + DLL_PREPEND (e,tail->out_edges,next_out,prev_out); + e->head = head; + DLL_PREPEND (e,head->in_edges,next_in,prev_in); + return e; +} + +void astg_delete_edge (e) +astg_edge *e; +{ + astg_graph *stg = e->tail->stg; + + DLL_REMOVE (e,e->tail->out_edges,next_out,prev_out); + DLL_REMOVE (e,e->head->in_edges, next_in, prev_in ); + stg->n_edge--; + stg->change_count++; + FREE (e->guard_eqn); + if (e->spline_points != NULL) array_free (e->spline_points); + FREE (e); +} + +static astg_edge *astg_dup_edge (old_e) +astg_edge *old_e; +{ + astg_edge *e = astg_new_edge (astg_tail(old_e)->alg.dup.eq, + astg_head(old_e)->alg.dup.eq); + if (old_e->guard_eqn != NULL) { + e->guard_n = old_e->guard_n; + e->guard_eqn = util_strsav(old_e->guard_eqn); + } + if (old_e->spline_points != NULL) { + e->spline_points = array_dup (old_e->spline_points); + } + return e; +} + +char *astg_edge_name (e) +astg_edge *e; +{ + static char buffer[180]; + + strcat (strcpy (buffer,"("), astg_v_name(astg_tail(e))); + strcat (strcat (buffer,","), astg_v_name(astg_head(e))); + strcat (buffer,")"); + return buffer; +} + + +astg_vertex *astg_head (e) +astg_edge *e; +{ + return e->head; +} + +astg_vertex *astg_tail (e) +astg_edge *e; +{ + return e->tail; +} + +static char *astg_make_guard_name (e,buffer,n) +astg_edge *e; +char *buffer; +int n; +{ + sprintf(buffer,"guard_%s_%s", astg_place_name(astg_tail(e)), + astg_trans_alpha_name(astg_head(e))); + if (strlen(buffer) >= n) fail("buffer overflow"); + return buffer; +} + +astg_bool astg_set_guard (se,guard_str,source) +astg_edge *se; +char *guard_str; +io_t *source; +{ + astg_bool ok = ASTG_TRUE; /* assume no problems. */ + int n_missing = 0; + char *p; + char guard_name[80], buf1[80]; + network_t *eqn_network; + lsGen pi_gen; + node_t *pi_node; + astg_graph *stg = astg_head(se)->stg; + + if (guard_str == NULL) { /* degenerate case */ + se->guard_eqn = NULL; + se->guard = NULL; + return ok; + } + + se->guard_eqn = util_strsav (source->buffer); + se->guard_n = ++stg->guard_n; + astg_make_guard_name (se,guard_name,sizeof(guard_name)); + strcat(strcat(strcpy(buf1, guard_name), " = "), se->guard_eqn); + while ((p=strchr(buf1,'"')) != NULL) *p = ' '; + strcat (buf1,";"); + dbg(2,msg("guard = \"%s\"\n",buf1)); + eqn_network = read_eqn_string (buf1); + + if (eqn_network == NULL) { + ok = ASTG_FALSE; + } + else { + foreach_primary_input (eqn_network,pi_gen,pi_node) { + if (astg_find_named_signal(stg,node_name(pi_node)) == NULL) { + if (source != NULL) { + io_error (source,"invalid signals used in guard"); + printf(" Signal \"%s\"\n",node_name(pi_node)); + } + n_missing++; + ok = ASTG_FALSE; + } + } + + if (n_missing == 0) { + network_append (stg->guards,eqn_network); + se->guard = astg_guard_node (stg,se); + assert (se->guard != NULL); + } + network_free (eqn_network); + } + + return ok; +} + +node_t *astg_guard_node (stg,e) +astg_graph *stg; +astg_edge *e; +{ + char guard_name[100]; + + astg_make_guard_name (e,guard_name,sizeof(guard_name)); + return network_find_node (stg->guards,guard_name); +} + +extern astg_edge *astg_find_edge (v1,v2,create) +astg_vertex *v1, *v2; +astg_bool create; +{ + /* Return the specified edge if it already exists. If create is + ASTG_TRUE, then create the edge and return it, otherwise return + NULL. */ + + astg_edge *e; + astg_generator gen; + + astg_foreach_out_edge (v1,gen,e) { + if (astg_head(e) == v2) { + return e; + } + } + + if (create) return astg_new_edge (v1,v2); + return NULL; +} + +/* -------------------------------- Graph ----------------------------------- */ + +astg_graph *astg_new (grName) +char *grName; +{ + astg_graph *stg = ALLOC (astg_graph,1); + + astg_ba_init_param (); + stg->name = util_strsav (grName); + stg->change_count = 1; + stg->file_count = 0; + stg->parent = NULL; + stg->n_vertex = 0; + stg->n_edge = 0; + stg->vertices = NULL; + stg->vtail = NULL; + + stg->has_marking = ASTG_FALSE; + stg->comments = lsCreate (); + stg->guards = network_alloc (); + stg->guard_n = 0; + stg->sig_list = NULL; stg->n_sig = stg->n_out = 0; + network_set_name (stg->guards,"guards"); + stg->flow_info.status = ASTG_OK; + stg->flow_info.state_list = NULL; + stg->flow_info.change_count = 0; + stg->sm_comp = NULL; stg->smc_count = 0; + stg->mg_comp = NULL; stg->mgc_count = 0; + + stg->next_place = 0; + stg->next_sig = 0; + + astg_do_daemons (stg,NIL(astg_graph),ASTG_DAEMON_ALLOC); + return stg; +} + +int astg_num_vertex (stg) +astg_graph *stg; +{ + return stg->n_vertex; +} + +char *astg_name (stg) +astg_graph *stg; +{ + return stg->name; +} + +void astg_free_components (component_array) +array_t *component_array; +{ + int i; + + if (component_array != NULL) { + for (i=0; i < array_n(component_array); i++) { + array_free (array_fetch (array_t *,component_array,i)); + } + array_free (component_array); + } +} + +void astg_delete_sig (stg,sig_p) +astg_graph *stg; +astg_signal *sig_p; +{ + if (sig_p == NULL) return; + DLL_REMOVE (sig_p,stg->sig_list,next,prev); + array_free (sig_p->lg_edges); + FREE (sig_p->name); + FREE (sig_p); +} + +void astg_delete (stg) +astg_graph *stg; +{ + astg_generator gen; + astg_vertex *v; + + if (stg == NULL) return; + + astg_do_daemons (stg,NIL(astg_graph),ASTG_DAEMON_FREE); + + astg_foreach_place (stg,gen,v) { + /* This dumps edges too. */ + astg_delete_place (v); + } + astg_foreach_trans (stg,gen,v) { + astg_delete_trans (v); + } + + while (stg->sig_list != NULL) { + astg_delete_sig (stg,stg->sig_list); + } + + if (stg->flow_info.state_list != NULL) { + st_free_table (stg->flow_info.state_list); + } + lsDestroy (stg->comments,free); + network_free (stg->guards); + astg_free_components (stg->sm_comp); + astg_free_components (stg->mg_comp); + FREE (stg->name); + FREE (stg); +} + +long astg_change_count (stg) +astg_graph *stg; +{ + return stg->change_count; +} + +static lsGeneric astg_copy_comments (data) +lsGeneric data; +{ + /* Callback for lsCopy(), used in astg_copy(). */ + char *s = (char *) data; + return (lsGeneric) util_strsav (s); +} + +astg_graph *astg_duplicate (old_g,name) +astg_graph *old_g; +char *name; +{ + /* Create a suitable copy of an STG. It is not an exact duplicate + since computed values may be reset instead of copied. How does + dup_signals fit into this? */ + + astg_graph *g; + astg_generator gen; + astg_vertex *old_v; + astg_edge *old_e; + astg_signal *old_s, *sig_p; + + if (old_g == NULL) return NULL; + g = astg_new (name?name:old_g->name); + + g->parent = old_g; + + /* Must dup guard network before duplicating signals. */ + network_free (g->guards); + g->guards = network_dup (old_g->guards); + g->next_place = old_g->next_place; + g->next_sig = old_g->next_sig; + g->comments = lsCopy (old_g->comments,astg_copy_comments); + g->filename = util_strsav(""); + g->has_marking = old_g->has_marking; + + astg_foreach_signal (old_g,gen,old_s) { + sig_p = astg_find_signal (g,old_s->name,old_s->sig_type,ASTG_TRUE); + old_s->dup = sig_p; + sig_p->can_elim = old_s->can_elim; + } + + astg_foreach_place (old_g,gen,old_v) { + astg_dup_place (g,old_v); + } + + astg_foreach_trans (old_g,gen,old_v) { + astg_dup_trans (g,old_v); + } + + astg_foreach_edge (old_g,gen,old_e) { + astg_dup_edge (old_e); + } + + astg_do_daemons (g,old_g,ASTG_DAEMON_DUP); + return g; +} + +/* -------------------------------- Marking stuff --------------------------- */ + +extern astg_scode astg_marking_enabled (marking_p) +astg_marking *marking_p; +{ + /* Return set of enabled transitions for this marking. */ + + return marking_p->enabled; +} + +extern int astg_state_count (stg) +astg_graph *stg; +{ + /* Return the number of states in the state graph. This is only valid + after some call which does token flow such as astg_token_flow or + astg_initial_state. */ + + return st_count (stg->flow_info.state_list); +} + +extern astg_scode astg_state_code (state_p) +astg_state *state_p; +{ + /* Return the state code for a flow state. */ + + astg_scode real_code = 0; + astg_marking *one_marking; + + one_marking = array_fetch (astg_marking *,state_p->states,0); + real_code = one_marking->state_code ^ state_p->stg->flow_info.phase_adj; + return real_code; +} + +extern astg_scode astg_state_enabled (state_p) +astg_state *state_p; +{ + /* Return the complete set of enabled transitions in this state. */ + + astg_scode enabled = 0; + astg_generator gen; + astg_marking *one_marking; + + astg_foreach_marking (state_p,gen,one_marking) { + enabled |= astg_marking_enabled (one_marking); + } + return enabled; +} + +int astg_state_n_marking (state_p) +astg_state *state_p; +{ + return array_n (state_p->states); +} + +int astg_cmp_marking (m1,m2) +astg_marking *m1, *m2; +{ + int result = 0; + if (m1->state_code != m2->state_code) { + result = 1; + } else if (astg_ba_cmp(m1->marked_places,m2->marked_places)) { + result = 1; + } + return result; +} + +/* --------------------------------- States stuff --------------------------- */ +astg_state *astg_new_state (stg) +astg_graph *stg; +{ + astg_state *state_p = ALLOC (astg_state,1); + state_p->states = array_alloc (astg_marking *,0); + state_p->stg = stg; + return state_p; +} + +astg_bool astg_is_dummy_marking (marking) +astg_marking *marking; +{ + return marking->is_dummy; +} + +void astg_add_marking (state_p,marking) +astg_state *state_p; +astg_marking *marking; +{ + astg_generator gen; + astg_scode enabled = 0; + astg_trans *trans; + astg_signal *sig_p; + int n_disabled; + + marking->is_dummy = ASTG_FALSE; + + astg_foreach_trans (state_p->stg,gen,trans) { + /* All input places are marked => transition enabled. */ + n_disabled = astg_disabled_count (trans,marking); + if (n_disabled == 0) { + sig_p = astg_trans_sig(trans); + enabled |= astg_state_bit (sig_p); + if (astg_signal_type(sig_p) == ASTG_DUMMY_SIG) { + marking->is_dummy = ASTG_TRUE; + } + } + } + + marking->enabled = enabled; + array_insert_last (astg_marking *,state_p->states,marking); +} + +void astg_delete_state (state_p) +astg_state *state_p; +{ + astg_generator mgen; + astg_marking *marking; + + astg_foreach_marking (state_p,mgen,marking) { + astg_ba_dispose (marking->marked_places); + FREE (marking); + } + array_free (state_p->states); + FREE (state_p); +} + +/* ----------------------------- Iterator Functions ------------------------- */ + +astg_bool astg_spline_iter (e,gen,xp,yp) +astg_edge *e; +astg_generator *gen; +float *xp, *yp; +{ + astg_vertex *v; + astg_bool ok = ASTG_FALSE; + int i = (gen->first_time) ? 0 : gen->gen_index; + gen->first_time = ASTG_FALSE; + + if (e->spline_points == NULL) { + v = astg_head(e); + if (v->vtype == ASTG_PLACE && astg_in_degree(v) == 1 && + astg_out_degree(v) == 1) { + if (i == 0) { + v = astg_tail(e); + *xp = v->x; *yp = v->y; + i += 2; + ok = ASTG_TRUE; + } else if (i == 2) { + v = astg_head(v->out_edges); + *xp = v->x; *yp = v->y; + i += 2; + ok = ASTG_TRUE; + } + } + } else if ((i+1) < array_n(e->spline_points)) { + *xp = array_fetch (float,e->spline_points,i++); + *yp = array_fetch (float,e->spline_points,i++); + ok = ASTG_TRUE; + } + + gen->gen_index = i; + return ok; +} + +astg_bool astg_sig_x_iter (sig,gen,type,trans_p) +astg_signal *sig; +astg_generator *gen; +astg_trans_enum type; +astg_trans **trans_p; +{ + astg_trans *t = (gen->first_time) ? sig->t_list : gen->gv; + gen->first_time = ASTG_FALSE; + + if (type != ASTG_ALL_X) { + /* Advance to transition type of interest. */ + while (t != NULL && t->type.trans.trans_type != type) { + t = t->type.trans.next_t; + } + } + + if (t != NULL) gen->gv = t->type.trans.next_t; + *trans_p = t; + return (t != NULL); +} + +astg_bool astg_vertex_iter (stg,gen,vtype,vertex_p) +astg_graph *stg; +astg_generator *gen; +astg_vertex_enum vtype; +astg_vertex **vertex_p; +{ + astg_bool ok = ASTG_FALSE; + astg_vertex *v; + + v = (gen->first_time) ? stg->vertices : gen->gv; + gen->first_time = ASTG_FALSE; + + while (v != NULL && v->vtype == vtype) { + v = v->next; + } + + if (v == NULL) { + gen->gv = NULL; + } else { + *vertex_p = v; + gen->gv = v->next; + ok = ASTG_TRUE; + } + + return ok; +} + +astg_bool astg_path_iter (stg,gen,vertex_p) +astg_graph *stg; +astg_generator *gen; +astg_vertex **vertex_p; +{ + astg_vertex *v; + + if (gen->first_time) { + v = stg->path_start; + gen->first_time = ASTG_FALSE; + } else { + v = gen->gv; + if (v == stg->path_start) v = NULL; + } + + gen->gv = (v == NULL) ? NULL : v->alg.sc.trail->head; + *vertex_p = v; + return (v != NULL); +} + +astg_bool astg_edge_iter (stg,gen,edge_p) +astg_graph *stg; +astg_generator *gen; +astg_edge **edge_p; +{ + astg_vertex *v; + astg_edge *e; + + if (gen->first_time) { + v = stg->vertices; + e = (v == NULL) ? NULL : v->out_edges; + gen->first_time = ASTG_FALSE; + } else { + v = gen->gv; + e = gen->ge; + } + + if (v != NULL) { + while (e == NULL) { + v = v->next; + if (v == NULL) { + gen->ge = NULL; + break; + } + e = v->out_edges; + } + } + + gen->gv = v; + if (e != NULL) gen->ge = e->next_out; + *edge_p = e; + return (e != NULL); +} + +astg_bool astg_out_edge_iter (v,gen,edge_p) +astg_vertex *v; +astg_generator *gen; +astg_edge **edge_p; +{ + astg_edge *e = (gen->first_time) ? v->out_edges : gen->ge; + gen->first_time = ASTG_FALSE; + + if (e != NULL) { + gen->ge = e->next_out; + *edge_p = e; + } + return (e != NULL); +} + +astg_bool astg_in_edge_iter (v,gen,edge_p) +astg_vertex *v; +astg_generator *gen; +astg_edge **edge_p; +{ + astg_edge *e = (gen->first_time) ? v->in_edges : gen->ge; + gen->first_time = ASTG_FALSE; + + if (e != NULL) { + gen->ge = e->next_in; + *edge_p = e; + } + return (e != NULL); +} + +astg_bool astg_in_vertex_iter (v,gen,vertex_p) +astg_vertex *v; +astg_generator *gen; +astg_vertex **vertex_p; +{ + astg_edge *e = (gen->first_time) ? v->in_edges : gen->ge; + gen->first_time = ASTG_FALSE; + + if (e != NULL) { + gen->ge = e->next_in; + *vertex_p = e->tail; + } + return (e != NULL); +} + +astg_bool astg_out_vertex_iter (v,gen,vertex_p) +astg_vertex *v; +astg_generator *gen; +astg_vertex **vertex_p; +{ + astg_edge *e = (gen->first_time) ? v->out_edges : gen->ge; + gen->first_time = ASTG_FALSE; + + if (e != NULL) { + gen->ge = e->next_out; + *vertex_p = e->head; + } + return (e != NULL); +} + +astg_bool astg_sig_iter (stg,gen,sig_p) +astg_graph *stg; +astg_generator *gen; +astg_signal **sig_p; +{ + astg_signal *sig = (gen->first_time) ? stg->sig_list : gen->sig_p; + gen->first_time = ASTG_FALSE; + + if (sig != NULL) gen->sig_p = sig->next; + *sig_p = sig; + return (sig != NULL); +} + +astg_bool astg_state_iter (stg,gen,state_p) +astg_graph *stg; +astg_generator *gen; +astg_state **state_p; +{ + astg_bool ok; + astg_scode key; + st_generator *sgen; + + if (gen->first_time) { + gen->state_gen = st_init_gen (stg->flow_info.state_list); + gen->first_time = ASTG_FALSE; + } + + sgen = (st_generator *) gen->state_gen; + ok = sgen != NULL && st_gen (sgen,(char**)&key,(char**)state_p); + + if (!ok && gen->state_gen != NULL) { + st_free_gen (sgen); + gen->state_gen = NULL; + } + return ok; +} + +astg_bool astg_marking_iter (state,gen,marking_p) +astg_state *state; +astg_generator *gen; +astg_marking **marking_p; +{ + int marking_n = (gen->first_time) ? 0 : gen->marking_n; + gen->first_time = ASTG_FALSE; + + if (marking_n >= array_n(state->states)) return ASTG_FALSE; + gen->marking_n = marking_n + 1; + *marking_p = array_fetch (astg_marking *, state->states, marking_n); + return ASTG_TRUE; +} + + +/* ----------------------------- Misc --------------------------------------- */ + +astg_bool astg_is_rel (t1,t2) +astg_trans *t1, *t2; +{ + astg_bool found = ASTG_FALSE; + astg_generator pgen, tgen; + astg_place *p; + astg_trans *tx; + + if (t1 == NULL || t2 == NULL) return ASTG_FALSE; + + astg_foreach_output_place (t1,pgen,p) { + if (found) continue; + astg_foreach_output_trans (p,tgen,tx) { + if (tx == t2) found = ASTG_TRUE; + } + } + return found; +} + +void astg_add_constraint (t1,t2,check) +astg_trans *t1, *t2; /*u Adding constraint from t1 to t2. */ +astg_bool check; /*i Check first before adding? */ +{ + /* Add an ordering constraint between these two transitions. */ + + char place_name[ASTG_NAME_LEN]; + astg_place *p; + astg_graph *stg = t1->stg; + + if (!check || !astg_is_rel(t1,t2)) { + dbg(2,msg(" adding constraint %s -> %s\n",t1->name,t2->name)); + sprintf(place_name,"p_%d",stg->next_place++); + p = astg_find_place (stg,place_name,ASTG_TRUE); + astg_new_edge (t1,p); + astg_new_edge (p,t2); + /* This invalidates any current marking. */ + stg->has_marking = ASTG_FALSE; + } +} + +/* ------------------- Net Selection Functions ------------------ */ + +void astg_sel_vertex (v,val) +astg_vertex *v; +astg_bool val; +{ + v->selected = val; +} + +void astg_sel_edge (e,val) +astg_edge *e; +astg_bool val; +{ + e->selected = val; +} + +void astg_sel_clear (stg) +astg_graph *stg; +{ + stg->sel_name = NULL; +} + +void astg_sel_new (stg,selname,value) +astg_graph *stg; +char *selname; +astg_bool value; +{ + astg_generator gen; + astg_place *p; + astg_trans *t; + astg_edge *e; + + stg->sel_name = selname; + astg_foreach_place (stg,gen,p) astg_sel_vertex (p,value); + astg_foreach_trans (stg,gen,t) astg_sel_vertex (t,value); + astg_foreach_edge (stg,gen,e) e->selected = value; +} + +void astg_sel_show (stg) +astg_graph *stg; +{ + /* Print list of selected transitions and places. Also, if graphics + is enabled, highlight these vertices. */ + + astg_generator tgen, pgen; + astg_place *p; + astg_trans *t; + int n_trans = 0, n_place= 0; + FILE *gfp; + + astg_foreach_trans (stg,tgen,t) { + if (t->selected) n_trans++; + } + astg_foreach_place (stg,pgen,p) { + if (p->selected) n_place++; + } + if (stg->sel_name == NULL || (n_trans+n_place) == 0) return; + + if (com_graphics_enabled()) { + gfp = com_graphics_open ("astg",stg->name,"highlight"); + fprintf(gfp,".clear\t%s\n.nodes",stg->sel_name); + } else { + gfp = NULL; + } + fprintf(stdout,"%s:\n",stg->sel_name); + + if (n_trans != 0) { + astg_foreach_trans (stg,tgen,t) { + if (t->selected) { + fprintf(stdout,"%s ",astg_trans_name(t)); + if (gfp) fprintf(gfp,"\t%s",astg_v_name(t)); + } + } + fputs ("\n",stdout); + } + + if (n_place != 0) { + astg_foreach_place (stg,pgen,p) { + if (p->selected) { + fprintf(stdout,"%s ",astg_place_name(p)); + if (gfp) fprintf(gfp,"\t%s",astg_v_name(p)); + } + } + fputs ("\n",stdout); + } + + if (gfp) { + fprintf(gfp,"\n"); + com_graphics_close (gfp); + } +} + +/* ---------------------------- Signal Stuff ----------------------- */ + +astg_signal_enum astg_signal_type (sig) +astg_signal *sig; +{ + return sig->sig_type; +} + +extern char *astg_signal_name (sig) +astg_signal *sig; +{ + /* Return name of a signal. Do not modify the string. */ + + return sig->name; +} + +extern astg_scode astg_state_bit (sig) +astg_signal *sig; +{ + /* Returns a bit mask for the bit being used to represent this signal. + This mask is used to interpret the state code and enabled transitions + from the state list and astg_get_enabled. */ + + return sig->state_bit; +} + +void astg_set_level (sig,scode,value) +astg_signal *sig; +astg_scode *scode; +astg_bool value; +{ + if (value) { + set_bit (*scode, sig->state_bit); + } else { + clr_bit (*scode, sig->state_bit); + } +} + +astg_bool astg_get_level (sig,scode) +astg_signal *sig; +astg_scode scode; +{ + return get_bit (scode, sig->state_bit); +} + +astg_bool astg_is_noninput (sig) +astg_signal *sig; +{ + return ( sig->sig_type == ASTG_OUTPUT_SIG || + sig->sig_type == ASTG_INTERNAL_SIG ); +} + +astg_bool astg_is_dummy (sig) +astg_signal *sig; +{ + return (sig->sig_type == ASTG_DUMMY_SIG); +} + +astg_bool astg_is_input (sig) +astg_signal *sig; +{ + return (sig->sig_type == ASTG_INPUT_SIG); +} + +int astg_signal_bit (sig) +astg_signal *sig; +{ + return sig->state_bit; +} + +static astg_signal *sig_new (stg,name) +astg_graph *stg; +char *name; +{ + astg_signal *sig_p = ALLOC (astg_signal, 1); + astg_signal *after = stg->sig_list; + + while (after != NULL && after->next != NULL) after = after->next; + DLL_INSERT (sig_p,stg->sig_list,next,prev,after); + sig_p->name = util_strsav(name); + return sig_p; +} + +extern astg_signal *astg_find_named_signal (stg,sig_name) +astg_graph *stg; +char *sig_name; +{ + /* Return the signal, or NULL if it does not exist. */ + + astg_signal *sig_p, *found_sig = NULL; + astg_generator sgen; + + astg_foreach_signal (stg,sgen,sig_p) { + if (!strcmp(astg_signal_name(sig_p),sig_name)) { + found_sig = sig_p; break; + } + } + return found_sig; +} + +extern astg_signal *astg_find_signal (stg,name,type,create) +astg_graph *stg; +char *name; +astg_signal_enum type; +astg_bool create; +{ + /* Return the signal, or NULL if it does not exist. */ + + astg_signal *sig_p = astg_find_named_signal (stg,name); + node_t *new_pi; + + if (sig_p != NULL) { + if (type != ASTG_ANY_SIG && type != sig_p->sig_type) { + sig_p = NULL; + } + } else if (sig_p == NULL && create) { + sig_p = sig_new (stg,name); + stg->n_sig++; + sig_p->sig_type = type; + sig_p->t_list = NULL; + if (network_find_node (stg->guards,name) == NULL) { + new_pi = node_alloc (); /* Make a PI in the guards network. */ + network_add_primary_input (stg->guards,new_pi); + network_change_node_name (stg->guards,new_pi,util_strsav(name)); + } + sig_p->lg_edges = array_alloc (astg_signal *, 0); + if (astg_is_noninput(sig_p)) { + stg->n_out++; + } + sig_p->state_bit = 0; + sig_p->can_elim = ASTG_FALSE; + } + return sig_p; +} + +astg_signal *astg_new_sig (stg,type) +astg_graph *stg; +astg_signal_enum type; +{ + char sig_name[40]; + + do { + sprintf (sig_name,"is%d",stg->next_sig++); + } while (astg_find_named_signal (stg,sig_name) != NULL); + + /* Create a new internal signal. */ + return astg_find_signal (stg,sig_name,type,ASTG_TRUE); +} + +extern astg_bool astg_is_trigger (sig1,sig2) +astg_signal *sig1, *sig2; +{ + /* Returns true if sig1 is a trigger signal for sig2. */ + + astg_trans *trigger, *t; + astg_place *p; + astg_generator pgen, tgen, sgen; + astg_bool is_trigger = ASTG_FALSE; + + astg_foreach_pos_trans (sig1,sgen,trigger) { + astg_foreach_output_place (trigger,pgen,p) { + astg_foreach_output_trans (p,tgen,t) { + if (t->type.trans.sig_p == sig2) { + is_trigger = ASTG_TRUE; + } + } + } + } + + astg_foreach_neg_trans (sig1,sgen,trigger) { + astg_foreach_output_place (trigger,pgen,p) { + astg_foreach_output_trans (p,tgen,t) { + if (t->type.trans.sig_p == sig2) { + is_trigger = ASTG_TRUE; + } + } + } + } + + return is_trigger; +} + +/* ---------------------- Write PLA (espresso) format ----------------------- */ + +static int add_espresso (stg, fout, in_mask, out_mask, new_state, delta_ns) +astg_graph *stg; +FILE *fout; +astg_scode in_mask, out_mask; +astg_scode new_state, delta_ns; +{ + astg_scode s, v; + int i; + + s = new_state; + v = in_mask; + for (i=stg->flow_info.in_width; i--; s >>= 1, v >>= 1) { + fputc ((v&1)?((s&1)?'1':'0'):'-',fout); + } + fputc (' ',fout); + + s = new_state ^ delta_ns; + v = out_mask; + for (i=stg->flow_info.out_width; i--; s >>= 1, v >>= 1) { + fputc ((v&1)?((s&1)?'1':'0'):'-',fout); + } + fputc ('\n',fout); +} + +static int cmp_encoding (data1,data2) +char *data1, *data2; +{ + /* callback for array_sort */ + astg_signal *en1 = *((astg_signal **) data1); + astg_signal *en2 = *((astg_signal **) data2); + int order; + + if (en1->state_bit < en2->state_bit) + order = -1; + else if (en1->state_bit == en2->state_bit) + order = 0; + else + order = 1; + return order; +} + +int astg_write_pla (stg,fout) +astg_graph *stg; +FILE *fout; +{ + astg_signal *sig_p; + array_t *signals; /* array of (astg_signal *) */ + astg_generator sgen; + astg_state *state_p; + astg_scode in_mask = 0, out_mask = 0; + int n; + + if (astg_token_flow (stg,ASTG_FALSE) != ASTG_OK) return 1; + + signals = array_alloc (astg_signal *,stg->flow_info.in_width); + astg_foreach_signal (stg,sgen,sig_p) { + if (sig_p->sig_type != ASTG_DUMMY_SIG) { + array_insert_last (astg_signal *,signals,sig_p); + } + } + array_sort (signals,cmp_encoding); + + fprintf(fout, "# %s\n", astg_name(stg)); + fprintf(fout, ".i %d\n.o %d", array_n(signals), stg->n_out); + + fputs("\n.ilb",fout); + for (n=0; n < array_n(signals); n++) { + sig_p = array_fetch (astg_signal *,signals,n); + fprintf(fout," %s",sig_p->name); + in_mask |= sig_p->state_bit; + dbg(2,msg("%s: 0x%X\n",sig_p->name,sig_p->state_bit)); + } + + fputs("\n.ob",fout); + for (n=0; n < array_n(signals); n++) { + sig_p = array_fetch (astg_signal *,signals,n); + if (astg_is_noninput(sig_p)) { + fprintf(fout," %s_out",sig_p->name); + out_mask |= sig_p->state_bit; + } + } + + fputs("\n.type fr\n",fout); + + astg_foreach_state (stg,sgen,state_p) { + add_espresso (stg, fout, in_mask,out_mask, + astg_state_code (state_p), + astg_state_enabled (state_p)); + } + + fputs(".e\n",fout); + return 0; +} +#endif /* SIS */ diff --git a/sis/astg/astg_core2.c b/sis/astg/astg_core2.c new file mode 100644 index 0000000..5a44559 --- /dev/null +++ b/sis/astg/astg_core2.c @@ -0,0 +1,541 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_core2.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* -------------------------------------------------------------------------- *\ + astg2.c -- Graph and net algorithms for STG's. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + +/* ---------------------------- ASTG Daemons -------------------------------- */ + +static astg_daemon_t *daemon_list = NULL; + +void astg_do_daemons (stg1,stg2,type) +astg_graph *stg1, *stg2; +astg_daemon_enum type; +{ + /* Execute all daemons of the given type. */ + astg_daemon_t *d; + + dbg(1,printf("do daemons %lX %lX %d\n",stg1,stg2,type)); + + for (d=daemon_list; d != NULL; d=d->next) { + if (type == d->type) (*d->daemon)(stg1,stg2); + } +} + +extern void astg_register_daemon (type, daemon) +astg_daemon_enum type; +astg_daemon daemon; +{ + /* Register an ASTG daemon. A daemon is a function which takes two + arguments: + static void daemon (astg_graph *g1, astg_graph *g2); + The usage of the arguments depends on the daemon type: + ASTG_DAEMON_ALLOC: g1 is the new astg, and g2 is NULL. + ASTG_DAEMON_DUP: g1 is the new astg, and g2 is the old astg. + ASTG_DAEMON_INVALID: g1 is invalidated astg, g2 is NULL. + ASTG_DAEMON_FREE: g1 is the old astg, and and g2 is NULL. + The astg g2 must never be modified. */ + + astg_daemon_t *info = ALLOC(astg_daemon_t,1); + info->daemon = daemon; + info->type = type; + info->next = daemon_list; + daemon_list = info; +} + +void astg_discard_daemons () +{ + /* Called at the very end to free structures for daemons. */ + + astg_daemon_t *info = daemon_list, *next; + + for (info=daemon_list; info != NULL; info=next) { + next = info->next; + FREE (info); + } + daemon_list = NULL; +} + +extern void *astg_get_slot (stg,slot_id) +astg_graph *stg; +astg_slot_enum slot_id; +{ + /* Return the value of the given slot. */ + return stg->slots[(int)slot_id]; +} + +extern void astg_set_slot (stg,slot_id,value) +astg_graph *stg; +astg_slot_enum slot_id; +void *value; +{ + /* Set a slot to a new value. */ + stg->slots[(int)slot_id] = value; +} + +/* --------------------------- Net Predicates ------------------------------- */ + +extern astg_bool astg_is_marked_graph (stg) +astg_graph *stg; +{ + /* Returns true if stg is a marked graph. */ + + astg_generator pgen; + astg_place *p; + astg_bool is_mg = ASTG_TRUE; + + astg_foreach_place (stg,pgen,p) { + if (astg_in_degree(p) > 1 || astg_out_degree(p) > 1) { + is_mg = ASTG_FALSE; + } + } + return is_mg; +} + +extern astg_bool astg_is_state_machine (stg) +astg_graph *stg; +{ + /* Returns true if stg is a state machine. */ + + astg_bool is_sm = ASTG_TRUE; + astg_generator tgen; + astg_trans *t; + + astg_foreach_trans (stg,tgen,t) { + if (astg_in_degree(t) > 1 || astg_out_degree(t) > 1) { + is_sm = ASTG_FALSE; + } + } + return is_sm; +} + +extern astg_bool astg_is_free_choice_net (stg) +astg_graph *stg; +{ + /* Returns true if the stg is a Free Choice net. */ + + astg_bool is_fcn = ASTG_TRUE; + astg_generator pgen, tgen; + astg_place *p; + astg_trans *t; + + astg_sel_new (stg,"not free choice",ASTG_FALSE); + astg_foreach_place (stg,pgen,p) { + if (astg_out_degree(p) <= 1) continue; + astg_foreach_output_trans (p,tgen,t) { + if (astg_in_degree(t) != 1) { + astg_sel_vertex (p,ASTG_TRUE); + astg_sel_vertex (t,ASTG_TRUE); + is_fcn = ASTG_FALSE; + } + } + } + return is_fcn; +} + +astg_bool astg_is_place_simple (g) +astg_graph *g; +{ + astg_generator gen1, gen2, gen3; + astg_vertex *src_t, *dest_t; + astg_edge *e, *e2; + astg_bool place_simple = ASTG_TRUE; + + astg_foreach_trans (g,gen1,src_t) src_t->flag0 = ASTG_FALSE; + + astg_foreach_trans (g,gen1,src_t) { + astg_foreach_out_edge (src_t,gen2,e) { + astg_foreach_out_edge (astg_head(e),gen3,e2) { + dest_t = astg_head (e2); + if (dest_t->flag0) place_simple = ASTG_FALSE; + dest_t->flag0 = ASTG_TRUE; + } + } + astg_foreach_out_edge (src_t,gen2,e) { + astg_foreach_out_edge (astg_head(e),gen3,e2) { + astg_head(e2)->flag0 = ASTG_FALSE; + } + } + } + return place_simple; +} + +astg_bool astg_is_pure (g) +astg_graph *g; +{ + astg_generator gen1, gen2, gen3; + astg_vertex *p, *p2; + astg_edge *e1, *e2; + astg_vertex *t; + astg_bool rc = ASTG_TRUE; + + astg_foreach_place (g,gen1,p) { + astg_foreach_out_edge (p,gen2,e1) { + t = astg_head (e1); + astg_foreach_out_edge (t,gen3,e2) { + p2 = astg_head (e2); + if (p == p2) { + rc = ASTG_FALSE; + printf("warning: place %s, trans %s not pure.\n", + astg_v_name(p), astg_v_name(t)); + } + } + } + } + return rc; +} + +/* --------------------------- Simple Cycles ------------------------- */ + +static int astg_report_cycle (g) +astg_graph *g; +{ + astg_generator gen; + astg_vertex *v; + int rc; + + astg_foreach_path_vertex (g,gen,v) { + v->on_path = ASTG_TRUE; + } + rc = (*g->f) (g,g->f_data); + astg_foreach_path_vertex (g,gen,v) { + v->on_path = ASTG_FALSE; + } + return rc; +} + +static int astg_cycles (g,v) +astg_graph *g; +astg_vertex *v; +{ + astg_generator gen; + int rc = 0; + astg_edge *e; + + if (v->active) { + if (v->unprocessed) { + g->path_start = v; + rc = astg_report_cycle (g); + } + } + else if (v->subset) { + v->active = ASTG_TRUE; + astg_foreach_out_edge (v,gen,e) { + v->alg.sc.trail = e; + rc += astg_cycles (g,astg_head(e)); + } + v->active = v->unprocessed = ASTG_FALSE; + } + return rc; +} + +int astg_simple_cycles (g,target_v,f,f_data,subset) +astg_graph *g; +astg_vertex *target_v; +int (*f)(); +void *f_data; +astg_bool subset; +{ + int rc = 0; + astg_bool x; + astg_vertex *v; + astg_generator gen; + + /* Initialize the unprocessed flag to ASTG_TRUE if all cycles are + being reported, or ASTG_FALSE if a specific target is given. */ + x = (target_v == NULL); + + astg_foreach_vertex (g,gen,v) { + v->active = ASTG_FALSE; + if (!subset) v->subset = ASTG_TRUE; + v->unprocessed = x && v->subset; + v->on_path = ASTG_FALSE; + v->alg.sc.trail = NULL; + } + + /* Save callback and callback data */ + g->f = f; g->f_data = f_data; + + if (target_v != NULL) { + target_v->unprocessed = ASTG_TRUE; + rc = astg_cycles (g,target_v); + } + else { + astg_foreach_vertex (g,gen,v) { + if (v->unprocessed) rc += astg_cycles (g,v); + } + } + return rc; +} + +/* --------------------- Topological Ordering --------------------------- */ + +static void astg_ts_dfs (g,v,num_p) +astg_graph *g; +astg_vertex *v; +int *num_p; +{ + astg_generator gen; + astg_edge *e; + + if (v->unprocessed) { + v->unprocessed = ASTG_FALSE; + astg_foreach_out_edge (v,gen,e) { + astg_ts_dfs (g,astg_head(e),num_p); + } + v->alg.ts.index = (*num_p)++; + } +} + +array_t *astg_top_sort (g,subset) +astg_graph *g; /*u graph to sort vertices in a topological order */ +astg_bool subset; /*i only process vertices marked with subset flag */ +{ + astg_generator gen; + astg_vertex *v; + int vertex_n; + array_t *varray; + + astg_foreach_vertex (g,gen,v) { + v->alg.ts.index = 0; + if (subset) { + v->unprocessed = v->subset; + } + else { + v->subset = v->unprocessed = ASTG_TRUE; + } + } + + vertex_n = 0; + astg_foreach_vertex (g,gen,v) { + if (v->unprocessed) astg_ts_dfs (g,v,&vertex_n); + } + + assert (vertex_n <= g->n_vertex); + varray = array_alloc (astg_vertex *, g->n_vertex); + astg_foreach_vertex (g,gen,v) { + v->unprocessed = v->subset; + if (!v->subset) continue; + array_insert (astg_vertex *, varray, v->alg.ts.index, v); + } + + return varray; +} + +/* -------------------------- Connected Components --------------------- */ + +static void astg_cc_dfs (v,vcomp,component_n) +astg_vertex *v; +array_t *vcomp; +int component_n; +{ + astg_generator gen; + astg_edge *e; + + if (v->unprocessed) { + v->unprocessed = ASTG_FALSE; + v->alg.cc.comp_num = component_n; + array_insert_last (astg_vertex *, vcomp, v); + astg_foreach_in_edge (v,gen,e) { + astg_cc_dfs (astg_tail(e),vcomp,component_n); + } + astg_foreach_out_edge (v,gen,e) { + astg_cc_dfs (astg_head(e),vcomp,component_n); + } + } +} + +astg_connected_comp (g,f,f_data,subset) +astg_graph *g; /*u graph to find components for */ +int (*f)(); /*i callback: int f(array_t *, int n, void *); */ +void *f_data; /*i arbitrary data to pass to callback */ +astg_bool subset; /*i only process vertices marked with subset flag */ +{ + astg_generator gen; + astg_vertex *v; + int component_n; + array_t *vcomp; + + if (!subset) { + astg_foreach_vertex (g,gen,v) v->unprocessed = ASTG_TRUE; + } + component_n = 0; + + astg_foreach_vertex (g,gen,v) { + if (v->unprocessed) { + vcomp = array_alloc (astg_vertex *,0); + astg_cc_dfs (v,vcomp,component_n); + if (f != NULL) (*f) (vcomp,component_n,f_data); + component_n++; + array_free (vcomp); + } + } + return component_n; +} + +static void astg_scc_dfs (v,vcomp,component_n) +astg_vertex *v; +array_t *vcomp; +int component_n; +{ + astg_generator gen; + astg_edge *e; + + if (v->unprocessed) { + v->unprocessed = ASTG_FALSE; + /* Add to component array, and number it. */ + v->alg.scc.comp_num = component_n; + array_insert_last (astg_vertex *, vcomp, v); + astg_foreach_in_edge (v,gen,e) { + astg_scc_dfs (astg_tail(e),vcomp,component_n); + } + } +} + +int astg_strong_comp (g,f,f_data,subset) +astg_graph *g; /*u find strong components of g */ +int (*f)(); /*i callback: int f(array_t *, int n, void *); */ +void *f_data; /*i arbitrary data to pass to callback */ +astg_bool subset; /*i only process vertices marked with subset flag */ +{ + array_t *varray; + array_t *vcomp; + astg_vertex *v; + int n, component_n; + + varray = astg_top_sort (g,subset); + /* unprocessed is set appropriately. */ + component_n = 0; + + for (n=array_n(varray); n--; /*empty*/) { + v = array_fetch (astg_vertex *,varray,n); + if (v->unprocessed) { + vcomp = array_alloc (astg_vertex *,0); + astg_scc_dfs (v,vcomp,component_n); + if (f != NULL) (*f) (vcomp,component_n,f_data); + component_n++; + array_free (vcomp); + } + } + + array_free (varray); + return component_n; +} + +/* --------------------------- Cycles -------------------------- */ + +static int astg_find_cycles (v) +astg_vertex *v; +{ + astg_generator gen; + astg_edge *e; + int rc = 0; + + if (v->active) { + rc = 1; + } + else if (v->unprocessed) { + v->active = ASTG_TRUE; + astg_foreach_out_edge (v,gen,e) { + rc = astg_find_cycles (astg_head(e)); + if (rc != 0) break; + } + v->active = v->unprocessed = ASTG_FALSE; + } + return rc; +} + +int astg_has_cycles (g) +astg_graph *g; +{ + astg_generator gen; + astg_vertex *v; + int n_cycles; + + astg_foreach_vertex (g,gen,v) { + v->active = ASTG_FALSE; + v->unprocessed = ASTG_TRUE; + } + + astg_foreach_vertex (g,gen,v) { + n_cycles = astg_find_cycles (v); + if (n_cycles != 0) break; + } + + return (n_cycles != 0); +} + +/* --------------------------- Misc. Stuff ------------------------------------ */ + +static astg_bool astg_cp_dfs (v,dest) +astg_vertex *v; /*u vertex to continue DFS trace from */ +astg_vertex *dest; /*i target vertex for the path */ +{ + astg_edge *e; + astg_bool path_found = ASTG_FALSE; + astg_generator gen; + + if (v->unprocessed) { + v->unprocessed = ASTG_FALSE; + astg_foreach_out_edge (v,gen,e) { + if (!path_found) path_found = astg_cp_dfs (astg_head(e),dest); + } + } + return path_found; +} + +astg_bool astg_choose_path (g,start,dest) +astg_graph *g; /*u find any path from start to dest */ +astg_vertex *start; /*u vertex to start path at */ +astg_vertex *dest; /*i vertex to try to reach */ +{ + astg_generator gen; + astg_vertex *v; + + astg_foreach_vertex (g,gen,v) v->unprocessed = ASTG_TRUE; + return astg_cp_dfs (start,dest); +} + +void astg_print_path (stg,stream) +astg_graph *stg; +FILE *stream; +{ + astg_generator gen; + astg_vertex *v; + + fprintf (stream,"Path:"); + astg_foreach_path_vertex (stg,gen,v) { + fprintf(stream," %s",astg_v_name(v)); + } + fputs("\n",stream); +} + +void astg_print (g,stream) +astg_graph *g; +FILE *stream; +{ + astg_generator gen; + astg_vertex *v; + astg_edge *e; + + fprintf(stream,"Graph '%s':\n",g->name); + astg_foreach_vertex (g,gen,v) { + fprintf(stream," %s",astg_v_name(v)); + astg_foreach_out_edge (v,gen,e) { + fprintf(stream," %s",astg_v_name(astg_head(e))); + } + fputs("\n",stream); + } +} +#endif /* SIS */ diff --git a/sis/astg/astg_flow.c b/sis/astg/astg_flow.c new file mode 100644 index 0000000..ad3ad5c --- /dev/null +++ b/sis/astg/astg_flow.c @@ -0,0 +1,224 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_flow.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* -------------------------------------------------------------------------- *\ + astg_flow.c -- do exhaustive token flow on an STG. + + int astg_token_flow (astg_graph *stg, astg_bool verbose); + + input: The initial marking is given by the initial_token bit of each + place in the STG. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + + +array_t *astg_check_new_state (finfo,new_state) +astg_flow_t *finfo; +astg_scode new_state; +{ + astg_place *p; + astg_trans *sv; + astg_state *state_p; + astg_marking *one_marking; + unsigned n_disabled; + array_t *enabled; + astg_generator tgen, pgen, mgen; + + if (finfo->status != 0) return NULL; + + state_p = astg_find_state (finfo->stg, + astg_adjusted_code(finfo->stg,new_state),ASTG_TRUE); + + /* Check if this marking was reached already. */ + astg_foreach_marking (state_p,mgen,one_marking) { + if (astg_cmp_marking(finfo->marking,one_marking) == 0) { + return NULL; /* Marking was reached already. */ + } + } + + enabled = array_alloc (astg_vertex *,0); + + astg_foreach_trans (finfo->stg,tgen,sv) { + /* All input places are marked => transition enabled. */ + n_disabled = astg_disabled_count (sv,finfo->marking); + if (n_disabled == 0) { + if (finfo->force_safe) { + /* Special handling of unsafe condition. */ + astg_foreach_output_place (sv,pgen,p) { + if (astg_get_marked(finfo->marking,p)) n_disabled++; + } + } + if (n_disabled == 0) { + array_insert_last (astg_vertex *, enabled, sv); + astg_set_useful(sv,ASTG_TRUE); + } + } + else if (n_disabled == 1) { + /* Exactly one place is unmarked. */ + astg_foreach_input_place (sv,pgen,p) { + if (!astg_get_marked(finfo->marking,p)) astg_set_useful(p,ASTG_TRUE); + } + } + } + + /* Add the new marking to this state. */ + one_marking = astg_dup_marking (finfo->marking); + astg_add_marking (state_p, one_marking); + if (astg_debug_flag >= 2) astg_print_marking (0,finfo->stg,one_marking); + return enabled; +} + +static int flow_state (flow_info,new_state) +astg_flow_t *flow_info; +astg_scode new_state; +{ + array_t *enabled = astg_check_new_state (flow_info,new_state); + astg_trans *t; + int i; + + if (enabled != NULL) { + /* Recursively generate each succeeding marking. */ + for (i=array_n(enabled); flow_info->status == 0 && i--; ) { + t = array_fetch (astg_trans *, enabled, i); + new_state = astg_fire (flow_info->marking,t); + flow_state (flow_info,new_state); + astg_unfire (flow_info->marking,t); + } + array_free (enabled); + } +} + +static astg_scode astg_flow_outmask (stg) +astg_graph *stg; /*i return output state bit mask for this stg. */ +{ + /* Compute a mask of the state bits of all output signals. */ + + astg_trans *t; + astg_generator gen; + astg_signal *sig_p; + astg_scode out_mask = 0; + + astg_foreach_trans (stg,gen,t) { + sig_p = astg_trans_sig(t); + if (astg_is_noninput(sig_p)) { + out_mask |= astg_state_bit (sig_p); + } + } + + return out_mask; +} + + +static astg_bool astg_flow_check_csc (stg,verbose) +astg_graph *stg; +astg_bool verbose; +{ + /* Check for state coding problems in the STG. */ + + astg_bool has_usc = ASTG_TRUE; + astg_generator sgen, mgen; + int n; + astg_state *state_p; + astg_marking *marking_p; + astg_scode min_enabled, max_enabled, out_mask; + + if (astg_get_flow_status(stg) != ASTG_OK) return ASTG_FALSE; + + out_mask = astg_flow_outmask (stg); + + astg_foreach_state (stg,sgen,state_p) { + min_enabled = out_mask; + max_enabled = 0; + astg_foreach_marking (state_p,mgen,marking_p) { + if (astg_is_dummy_marking (marking_p)) continue; + min_enabled &= astg_get_enabled(marking_p); + max_enabled |= astg_get_enabled(marking_p); + } + max_enabled &= out_mask; + + if (min_enabled != max_enabled) { + has_usc = ASTG_FALSE; + astg_set_flow_status (stg, ASTG_NOT_USC); + if (verbose) { + printf("\nerror: state assignment problem for state"); + astg_print_state (stg,astg_state_code(state_p)); + n = 0; + astg_foreach_marking (state_p,mgen,marking_p) { + astg_print_marking (++n,stg,marking_p); + } + } + } + } /* end for each state code */ + + return has_usc; +} + +static void astg_flow_check_redundant (stg) +astg_graph *stg; +{ + astg_generator gen; + astg_place *p; + astg_trans *t; + + if (astg_get_flow_status(stg) != ASTG_OK) return; + astg_sel_new (stg,"unfired transitions",ASTG_FALSE); + astg_foreach_trans (stg,gen,t) { + if (!astg_get_useful(t)) { + astg_sel_vertex (t,ASTG_TRUE); + astg_set_flow_status (stg,ASTG_NOT_LIVE); + } + } + + if (astg_get_flow_status(stg) != ASTG_OK) return; + astg_sel_new (stg,"redundant places",ASTG_FALSE); + astg_foreach_place (stg,gen,p) { + if (!astg_get_useful(p)) { + astg_sel_vertex (p,ASTG_TRUE); + } + } +} + +astg_retval astg_token_flow (stg,verbose) +astg_graph *stg; /*u stg to do marking flow */ +astg_bool verbose; /*i ASTG_TRUE=print messages for flow problems */ +{ + /* If the previous flow status was ASTG_OK, and the graph has not + changed structurally since the last flow, then just print messages. + Otherwise, do exhaustive token flow on the astg. */ + + astg_flow_t flow_rec; + astg_retval status; + astg_scode initial_state = 0; + astg_bool redo_flow = astg_reset_state_graph (stg); + + astg_sel_clear (stg); + + if (redo_flow) { + flow_rec.force_safe = ASTG_FALSE; + flow_rec.status = 0; + flow_rec.stg = stg; + flow_rec.marking = astg_initial_marking (stg); + flow_state (&flow_rec,initial_state); + astg_delete_marking (flow_rec.marking); + } + + astg_flow_check_csc (stg,verbose); + astg_flow_check_redundant (stg); + if (verbose) astg_sel_show (stg); + + status = astg_get_flow_status (stg); + if (astg_debug_flag >= 2) { + printf("flow: redo=%d, status=%d\n",redo_flow,status); + } + return status; +} +#endif /* SIS */ diff --git a/sis/astg/astg_int.h b/sis/astg/astg_int.h new file mode 100644 index 0000000..bda8ead --- /dev/null +++ b/sis/astg/astg_int.h @@ -0,0 +1,308 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* -------------------------------------------------------------------------- *\ + astg_int.h -- asynchronous signal transition graph (ASTG) interface. + + This is the "interface" which the rest of the astg package uses to access + the astg "core". This interface is not exported to the rest of SIS since + it is not of general interest. +\* ---------------------------------------------------------------------------*/ + +#ifndef ASTG_INT_H +#define ASTG_INT_H + +#include "sis.h" +#include "astg.h" + +extern int astg_debug_flag; + +typedef unsigned astg_bool; +#define ASTG_FALSE 0 +#define ASTG_TRUE 1 + +#define ASTG_NO_CALLBACK NULL +#define ASTG_NO_DATA NULL +#define ASTG_ALL ASTG_FALSE +#define ASTG_SUBSET ASTG_TRUE +#define ASTG_ALL_CYCLES NIL(astg_vertex) + + +typedef enum astg_retval { + ASTG_OK, /* No error, success. */ + ASTG_NOT_SAFE, /* STG is not safe. */ + ASTG_NOT_LIVE, /* STG is not live. */ + ASTG_NOT_IRRED, /* Has redundant constraints. */ + ASTG_NOT_USC, /* Not unique state coding. */ + ASTG_NOT_CSC, /* Not complete state coding. */ + ASTG_NOT_CSA, /* Not consistent state assignment. */ + ASTG_NO_MARKING, /* No initial marking found. */ + ASTG_BAD_SIGNAME, /* Invalid signal name. */ + ASTG_GOT_MARKING, /* For finding partial traces. */ + ASTG_NOT_COVER, /* Components don't cover STG. */ + ASTG_BAD_OPTION, /* No such option for command. */ + ASTG_ERROR /* Generic error. */ +} astg_retval; + +typedef enum astg_signal_enum { + ASTG_ANY_SIG, /* Only for calls to astg_find_signal. */ + ASTG_INPUT_SIG, /* Rest of these are real signal types. */ + ASTG_OUTPUT_SIG, + ASTG_INTERNAL_SIG, + ASTG_DUMMY_SIG +} astg_signal_enum; + +typedef enum astg_vertex_enum { + ASTG_VERTEX, + ASTG_PLACE, + ASTG_TRANS +} astg_vertex_enum; + +typedef enum astg_trans_enum { + ASTG_ALL_X, + ASTG_POS_X, + ASTG_NEG_X, + ASTG_TOGGLE_X, + ASTG_HATCH_X, + ASTG_DUMMY_X +} astg_trans_enum; + +typedef enum astg_daemon_enum { + ASTG_DAEMON_ALLOC, + ASTG_DAEMON_DUP, + ASTG_DAEMON_INVALID, + ASTG_DAEMON_FREE +} astg_daemon_enum; + +typedef enum astg_slot_enum { + ASTG_BWD_SLOT, + ASTG_UNDEF1_SLOT, + ASTG_N_SLOTS +} astg_slot_enum; + +typedef enum astg_io_enum { + ASTG_REAL_PI, + ASTG_REAL_PO, + ASTG_FAKE_PI, + ASTG_FAKE_PO +} astg_io_enum; + + /* Basic types: only declare pointers to these. */ + +typedef struct astg_graph astg_graph; +typedef struct astg_signal astg_signal; +typedef struct astg_vertex astg_vertex; +typedef struct astg_vertex astg_place; +typedef struct astg_vertex astg_trans; +typedef struct astg_edge astg_edge; +typedef struct astg_state astg_state; +typedef struct astg_marking astg_marking; +typedef unsigned long astg_scode; + +typedef struct astg_generator { + astg_bool first_time; + astg_edge *ge; + astg_vertex *gv; + astg_trans *gt; + void *state_gen; + int marking_n; + int gen_index; + astg_signal *sig_p; +} astg_generator; + +typedef void (*astg_daemon) ARGS((astg_graph*, astg_graph*)); + +#ifndef ARGS +#define ARGS(args) args +#endif + +astg_vertex_enum astg_v_type ARGS((astg_vertex *)); +char *astg_v_name ARGS((astg_vertex *)); +void astg_set_useful ARGS((astg_vertex *, astg_bool)); +astg_bool astg_get_useful ARGS((astg_vertex *)); +void astg_set_hilite ARGS((astg_vertex *, astg_bool)); +astg_bool astg_get_hilite ARGS((astg_vertex *)); +astg_bool astg_get_selected ARGS((astg_vertex *)); +void astg_set_v_locn ARGS((astg_vertex *, float*, float*)); +void astg_get_v_locn ARGS((astg_vertex *, float*, float*)); + +astg_place *astg_new_place ARGS((astg_graph *, char *, void *)); +void astg_delete_place ARGS((astg_place *)); +char *astg_place_name ARGS((astg_place *)); +astg_place *astg_find_place ARGS((astg_graph *, char *, astg_bool)); +astg_bool astg_boring_place ARGS((astg_place *)); +astg_bool astg_get_marked ARGS((astg_marking *, astg_place *)); +void astg_set_marked ARGS((astg_marking *, astg_place *, astg_bool)); + +astg_trans *astg_new_trans ARGS((astg_graph *,char *, void *)); +void astg_delete_trans ARGS((astg_trans *)); +char *astg_trans_name ARGS((astg_trans *)); +char *astg_trans_alpha_name ARGS((astg_trans *)); +astg_trans *astg_find_trans ARGS((astg_graph *, char *, astg_trans_enum, int, astg_bool)); +astg_trans *astg_noninput_trigger ARGS((astg_trans *)); +astg_bool astg_has_constraint ARGS((astg_trans *, astg_trans *)); +astg_trans_enum astg_trans_type ARGS((astg_trans *)); +astg_signal *astg_trans_sig ARGS((astg_trans *)); + +astg_edge *astg_new_edge ARGS((astg_vertex *, astg_vertex *)); +void astg_delete_edge ARGS((astg_edge *)); +char *astg_edge_name ARGS((astg_edge *)); +astg_vertex *astg_tail ARGS((astg_edge *)); +astg_vertex *astg_head ARGS((astg_edge *)); +astg_edge *astg_find_edge ARGS((astg_vertex *, astg_vertex *, astg_bool)); + +astg_graph *astg_new ARGS((char *)); +astg_graph *astg_read ARGS((FILE *, char *)); +astg_graph *astg_contract ARGS((astg_graph *, astg_signal *, astg_bool)); +void astg_delete ARGS((astg_graph *)); +long astg_change_count ARGS((astg_graph *)); +char *astg_name ARGS((astg_graph *)); +astg_graph *astg_duplicate ARGS((astg_graph *, char *)); +void astg_check ARGS((astg_graph *)); +void astg_add_constraint ARGS((astg_trans *, astg_trans *, astg_bool)); +void astg_register_daemon ARGS((astg_daemon_enum, astg_daemon)); +void *astg_get_slot ARGS((astg_graph *, astg_slot_enum)); +void astg_set_slot ARGS((astg_graph *, astg_slot_enum, void *)); + +void astg_sel_new ARGS((astg_graph *, char *, astg_bool)); +void astg_sel_show ARGS((astg_graph *)); +void astg_sel_clear ARGS((astg_graph *)); +void astg_sel_vertex ARGS((astg_vertex *, astg_bool)); +void astg_sel_edge ARGS((astg_edge *, astg_bool)); + +astg_bool astg_is_trigger ARGS ((astg_signal *, astg_signal *)); +astg_bool astg_is_input ARGS((astg_signal *)); +astg_bool astg_is_dummy ARGS((astg_signal *)); +astg_bool astg_is_noninput ARGS((astg_signal *)); +astg_signal *astg_find_named_signal ARGS ((astg_graph *, char *)); +astg_signal *astg_find_signal ARGS((astg_graph *, char *, astg_signal_enum, astg_bool)); +char *astg_signal_name ARGS((astg_signal *)); +astg_signal_enum astg_signal_type ARGS((astg_signal *)); +astg_bool astg_get_level ARGS((astg_signal *, astg_scode)); +void astg_set_level ARGS((astg_signal *, astg_scode *, astg_bool)); +astg_retval astg_unique_state ARGS((astg_graph *, astg_scode *)); + +astg_scode astg_state_bit ARGS((astg_signal *)); +astg_scode astg_state_code ARGS((astg_state *)); +astg_retval astg_token_flow ARGS((astg_graph *, astg_bool)); +astg_bool astg_one_sm_token ARGS((astg_graph *)); +astg_retval astg_initial_state ARGS((astg_graph *, astg_scode *)); +astg_scode astg_state_enabled ARGS((astg_state *)); +astg_bool astg_state_coding ARGS((astg_graph *, astg_bool)); +astg_state *astg_new_state ARGS((astg_graph *)); +void astg_add_marking ARGS((astg_state *, astg_marking *)); +astg_bool astg_is_dummy_marking ARGS((astg_marking *)); +void astg_print_state ARGS((astg_graph *, astg_scode)); + +void astg_to_blif ARGS((FILE *, astg_graph *, char *)); +astg_bool astg_reset_state_graph ARGS((astg_graph *)); +astg_retval astg_get_flow_status ARGS((astg_graph *)); +void astg_set_flow_status ARGS((astg_graph *, astg_retval)); +astg_state *astg_find_state ARGS((astg_graph *, astg_scode, astg_bool)); +void astg_delete_state ARGS((astg_state *)); +void astg_set_marking ARGS((astg_graph *, astg_marking *)); +astg_retval astg_set_marking_by_code ARGS((astg_graph *, astg_scode, astg_scode)); +astg_scode astg_fire ARGS((astg_marking *, astg_trans *)); +astg_scode astg_unfire ARGS((astg_marking *, astg_trans *)); +astg_marking *astg_initial_marking ARGS((astg_graph *)); +astg_marking *astg_dup_marking ARGS((astg_marking *)); +void astg_delete_marking ARGS((astg_marking *)); +astg_scode astg_get_enabled ARGS((astg_marking *)); +void astg_print_marking ARGS ((int, astg_graph *, astg_marking *)); + +astg_bool astg_is_marked_graph ARGS((astg_graph *)); +astg_bool astg_is_state_machine ARGS((astg_graph *)); +astg_bool astg_is_free_choice_net ARGS((astg_graph *)); +astg_bool astg_is_place_simple ARGS((astg_graph *)); +astg_bool astg_is_pure ARGS((astg_graph *)); +int astg_num_vertex ARGS((astg_graph *)); +astg_scode astg_adjusted_code ARGS((astg_graph *, astg_scode)); + +void astg_hilite ARGS((astg_graph *)); +void astg_basic_cmds ARGS((astg_bool)); +char *astg_pi_name ARGS((char *)); +void astg_usage ARGS((char**, char*)); + +#ifdef SIS_H /* Declarations depending on . */ + +astg_graph *astg_current ARGS((network_t *)); +void astg_set_current ARGS((network_t **, astg_graph *, astg_bool)); + +node_t *astg_guard_node ARGS((astg_graph *, astg_edge *)); +astg_retval astg_set_marking_by_name ARGS((astg_graph *, st_table *)); + +int astg_simple_cycles ARGS((astg_graph *, astg_vertex *, int (*)(astg_graph *, void *), void *, astg_bool)); +array_t *astg_top_sort ARGS((astg_graph *, astg_bool)); +int astg_connected_comp ARGS((astg_graph *, int (*)(array_t *, int, void *), void *, astg_bool)); +int astg_strong_comp ARGS((astg_graph *, int (*)(array_t *, int, void *), void *, astg_bool)); +int astg_has_cycles ARGS((astg_graph *)); +void astg_shortest_path ARGS((astg_graph *, astg_vertex *)); +network_t *astg_to_network ARGS((astg_graph*, latch_synch_t)); +node_t *astg_find_pi_or_po ARGS((network_t *, char *, astg_io_enum)); + +#endif /* SIS_H */ + + /* Not for direct use: see iterators below. */ + +astg_bool astg_vertex_iter ARGS((astg_graph *, astg_generator *, astg_vertex_enum, astg_vertex **)); +astg_bool astg_edge_iter ARGS((astg_graph *, astg_generator *, astg_edge **)); +astg_bool astg_path_iter ARGS((astg_graph *, astg_generator *, astg_vertex **)); +astg_bool astg_out_edge_iter ARGS((astg_vertex *, astg_generator *, astg_edge **)); +astg_bool astg_in_edge_iter ARGS((astg_vertex *, astg_generator *, astg_edge **)); +astg_bool astg_in_vertex_iter ARGS((astg_vertex *, astg_generator *, astg_vertex **)); +astg_bool astg_out_vertex_iter ARGS((astg_vertex *, astg_generator *, astg_vertex **)); +astg_bool astg_sig_iter ARGS((astg_graph *, astg_generator *, astg_signal **)); +astg_bool astg_sig_x_iter ARGS((astg_signal *, astg_generator *, astg_trans_enum, astg_trans **)); +astg_bool astg_state_iter ARGS((astg_graph *, astg_generator *, astg_state **)); +astg_bool astg_marking_iter ARGS((astg_state *, astg_generator *, astg_marking **)); +astg_bool astg_spline_iter ARGS((astg_edge *, astg_generator *, float *, float *)); + + +/* DOCUMENT Public use iterators. + Iterators: + + astg_graph *stg; + astg_generator gen; + astg_trans *t; + astg_place *p; + astg_signal *sig_p; + + astg_foreach_trans (stg,gen,t) + astg_foreach_place (stg,gen,t) + astg_foreach_input_place (t,gen,p) + astg_foreach_output_place (t,gen,p) + astg_foreach_input_trans (p,gen,t) + astg_foreach_output_trans (p,gen,t) + astg_foreach_signal (stg,gen,sig_p) + astg_foreach_pos_trans (sig_p,gen,t) + astg_foreach_neg_trans (sig_p,gen,t) + */ + +#define astg_iter(g,f) for (g.first_time=ASTG_TRUE;f;g.first_time=ASTG_FALSE) + +#define astg_foreach_vertex(stg,gen,v) astg_iter (gen, astg_vertex_iter(stg,&gen,ASTG_VERTEX,&v)) +#define astg_foreach_place(stg,gen,p) astg_iter (gen, astg_vertex_iter(stg,&gen,ASTG_TRANS,&p)) +#define astg_foreach_trans(stg,gen,t) astg_iter (gen, astg_vertex_iter(stg,&gen,ASTG_PLACE,&t)) +#define astg_foreach_edge(stg,gen,e) astg_iter (gen, astg_edge_iter(stg,&gen,&e)) +#define astg_foreach_path_vertex(stg,gen,v) astg_iter (gen, astg_path_iter(stg,&gen,&v)) +#define astg_foreach_out_edge(v,gen,e) astg_iter (gen, astg_out_edge_iter(v,&gen,&e)) +#define astg_foreach_in_edge(v,gen,e) astg_iter (gen, astg_in_edge_iter(v,&gen,&e)) +#define astg_foreach_output_place(t,gen,p) astg_iter (gen, astg_out_vertex_iter(t,&gen,&p)) +#define astg_foreach_input_place(t,gen,p) astg_iter (gen, astg_in_vertex_iter(t,&gen,&p)) +#define astg_foreach_output_trans(p,gen,t) astg_iter (gen, astg_out_vertex_iter(p,&gen,&t)) +#define astg_foreach_input_trans(p,gen,t) astg_iter (gen, astg_in_vertex_iter(p,&gen,&t)) +#define astg_foreach_signal(stg,gen,sig) astg_iter (gen, astg_sig_iter(stg,&gen,&sig)) +#define astg_foreach_sig_trans(sig,gen,t) astg_iter (gen, astg_sig_x_iter(sig,&gen,ASTG_ALL_X,&t)) +#define astg_foreach_pos_trans(sig,gen,t) astg_iter (gen, astg_sig_x_iter(sig,&gen,ASTG_POS_X,&t)) +#define astg_foreach_neg_trans(sig,gen,t) astg_iter (gen, astg_sig_x_iter(sig,&gen,ASTG_NEG_X,&t)) +#define astg_foreach_state(sig,gen,state) astg_iter (gen, astg_state_iter(stg,&gen,&state)) +#define astg_foreach_marking(state,gen,m) astg_iter (gen, astg_marking_iter(state,&gen,&m)) +#define astg_foreach_spline_point(e,gen,x,y) astg_iter (gen, astg_spline_iter(e,&gen,&x,&y)) + +#endif /* ASTG_INT_H */ diff --git a/sis/astg/astg_irred.c b/sis/astg/astg_irred.c new file mode 100644 index 0000000..75a17fc --- /dev/null +++ b/sis/astg/astg_irred.c @@ -0,0 +1,205 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_irred.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* -------------------------------------------------------------------- *\ + irred.c -- check for and optionally remove redundant constraints. +\* ---------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + +static void pr_path (stg,s) +astg_graph *stg; +char *s; +{ + astg_generator gen; + astg_vertex *v; + + msg("%s:",s); + astg_foreach_path_vertex (stg,gen,v) { + msg(" %s",astg_v_name(v)); + } + msg("\n"); +} + +typedef struct irred_rec { + astg_vertex *red_tail; + astg_vertex *red_head; + astg_vertex *red_place; +} irred_rec; + + +static int check_redundant (stg,data) +astg_graph *stg; +void *data; +{ + /* Callback for simple cycles to see if this is an alternate cycle. */ + irred_rec *info = (irred_rec *) data; + + if (info->red_tail->on_path && info->red_head->on_path && + !info->red_place->on_path) { + /* Found another loop through these two. */ + dbg(3,pr_path(stg,"alt")); + return 1; + } + return 0; +} + +extern int astg_irred (stg,modify) +astg_graph *stg; +astg_bool modify; +{ + /* Count the number of redundant arcs in the STG, and if modify is + true, delete them as well. */ + + astg_generator gen; + int n_redundant = 0; + astg_place *p; + irred_rec info; + + astg_foreach_place (stg,gen,p) { + p->subset = ASTG_TRUE; + } + + astg_foreach_place (stg,gen,p) { + if (astg_in_degree(p) != 1 || astg_out_degree(p) != 1) continue; + info.red_tail = p->in_edges->tail; + info.red_head = p->out_edges->head; + info.red_place = p; + if (astg_simple_cycles (stg,info.red_tail, + check_redundant,(void *)&info,ASTG_SUBSET)) { + n_redundant++; + dbg(1,msg(" %s -> ", astg_v_name(info.red_tail))); + dbg(1,msg("%s is redundant\n", astg_v_name(info.red_head))); + p->subset = ASTG_FALSE; + if (modify) astg_delete_place (p); + } + } + + dbg (1,msg("%s %d redundant constraints\n",modify?"Deleted":"Found",n_redundant)); + return n_redundant; +} + +/* -------------------------- Calculate Worst Delay --------------------- */ + +typedef struct cycle_info { + astg_bool find_longest; + int which_cycle; + int cycle_n; + array_t *longest_cycle; + float its_delay; +} cycle_info; + +static float astg_calc_delay (stg) +astg_graph *stg; +{ + float rc = 0.0; + astg_vertex *v; + astg_generator gen; + + astg_foreach_path_vertex (stg,gen,v) { + if (v->vtype == ASTG_TRANS) { + rc += astg_trx(v)->delay; + } + } + return rc; +} + +static int check_cycles (stg,data) +astg_graph *stg; +void *data; +{ + cycle_info *cinfo = (cycle_info *) data; + astg_generator gen; + int n_found = 0; + float cycle_delay; + astg_vertex *v; + + cinfo->cycle_n++; + + if (cinfo->find_longest) { + cycle_delay = astg_calc_delay (stg); + n_found = 1; + if (cinfo->longest_cycle == NULL || cycle_delay > cinfo->its_delay) { + if (cinfo->longest_cycle != NULL) array_free (cinfo->longest_cycle); + cinfo->longest_cycle = array_alloc (astg_vertex *,0); + astg_foreach_path_vertex (stg,gen,v) { + array_insert_last (astg_vertex *,cinfo->longest_cycle,v); + } + cinfo->its_delay = cycle_delay; + } + } + else if (cinfo->cycle_n == cinfo->which_cycle || cinfo->which_cycle <= 0) { + n_found = 1; + astg_foreach_path_vertex (stg,gen,v) { + astg_sel_vertex (v,ASTG_TRUE); + } + } + + return n_found; +} + +float astg_longest_cycle (stg) +astg_graph *stg; +{ + cycle_info cinfo_rec; + + cinfo_rec.find_longest = ASTG_TRUE; + cinfo_rec.longest_cycle = NULL; + astg_simple_cycles (stg,NIL(astg_vertex),check_cycles,(void *)&cinfo_rec,ASTG_ALL); + if (cinfo_rec.longest_cycle != NULL) array_free (cinfo_rec.longest_cycle); + return cinfo_rec.its_delay; +} + +int astg_select_cycle (stg,thru_trans,cycle_n,find_longest,add_to_set) +astg_graph *stg; +astg_trans *thru_trans; +int cycle_n; /*i index, 0=all, of which cycle */ +astg_bool find_longest; /*i 1=longest delay cycle, 0=any cycles */ +astg_bool add_to_set; /*i 1=add to existing set, 0=new set */ +{ + cycle_info cinfo_rec; + char set_name[180]; + astg_vertex *v; + int n, n_cycle; + + cinfo_rec.find_longest = find_longest; + cinfo_rec.cycle_n = 0; + cinfo_rec.which_cycle = cycle_n; + + if (find_longest) { + cinfo_rec.longest_cycle = NULL; + } + else if (cycle_n == 0 && !add_to_set) { + astg_sel_new (stg,"simple cycles",ASTG_FALSE); + } + else if (!add_to_set) { + (void) sprintf(set_name,"simple cycle %d",cycle_n); + astg_sel_new (stg,set_name,ASTG_FALSE); + } + + v = (thru_trans == NULL) ? NULL : thru_trans; + + n_cycle = astg_simple_cycles (stg,v,check_cycles,(void *)&cinfo_rec,ASTG_ALL); + + if (find_longest && cinfo_rec.longest_cycle != NULL) { + (void) sprintf(set_name,"longest cycle %.1f",cinfo_rec.its_delay); + astg_sel_new (stg,set_name,ASTG_FALSE); + for (n=0; n < array_n(cinfo_rec.longest_cycle); n++) { + v = array_fetch (astg_vertex *,cinfo_rec.longest_cycle,n); + astg_sel_vertex (v,ASTG_TRUE); + } + array_free (cinfo_rec.longest_cycle); + } + + dbg(1,msg("Selected %d %s.\n",n_cycle,n_cycle==1?"cycle":"cycles")); + astg_sel_show (stg); +} +#endif /* SIS */ diff --git a/sis/astg/astg_lkgraph.c b/sis/astg/astg_lkgraph.c new file mode 100644 index 0000000..64c6990 --- /dev/null +++ b/sis/astg/astg_lkgraph.c @@ -0,0 +1,589 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_lkgraph.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* -------------------------------------------------------------------------- *\ + lockgraph.c -- build lock graph for a marked graph STG. + + Lock graph: vertices are astg_signal, edges are stored as adjacency list + lg_edges of each signal. A lock graph component is an array of signals. + + Needs more testing for case when do_lock is true. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + +#define ARRAY_DELETE_LAST(a) (--((a)->num)) +#define ARRAY_RESET(a) (((a)->num) = 0) + + +typedef struct lock_class { + array_t *lg_vertices; /* Array of astg_signal *. */ + int connectivity; /* Used to select class for locking. */ +} lock_class; + + +typedef struct lc_rec { + array_t *classes; /* Array of lock_class struct */ + sm_matrix *lock_matrix; /* Used to form the lock graph. */ + astg_graph *stg; /* To be available to callbacks. */ +} lc_rec; + + +static void print_lock_graph (stg) +astg_graph *stg; +{ + /* Print adjacency list format of lock graph. */ + + int n; + astg_generator gen; + astg_signal *sig_p, *edge; + + astg_foreach_signal (stg,gen,sig_p) { + printf("%s:",sig_p->name); + for (n=0; n < array_n(sig_p->lg_edges); n++) { + edge = array_fetch (astg_signal *, sig_p->lg_edges, n); + printf(" %s", edge->name); + } + printf("\n"); + } +} + +static void print_path (stg) +astg_graph *stg; +{ + astg_vertex *v; + astg_generator gen; + + astg_foreach_path_vertex (stg,gen,v) { + if (v->vtype == ASTG_PLACE) continue; + printf(" %s",astg_v_name(v)); + } + printf("\n"); +} + +/* ------------------- Connected Components of Lock Graph ------------------- *\ + + Uses a DFS to find the connected components of the lock graph. Since the + lock graph is undirected, this is also the strongly connected components. +\* -------------------------------------------------------------------------- */ + +static void astg_lg_comp (sig_p,component) +astg_signal *sig_p; +array_t *component; +{ + astg_signal *s; + int n; + + if (sig_p->unprocessed) { + sig_p->unprocessed = ASTG_FALSE; + array_insert_last (astg_signal *,component,sig_p); + for (n=array_n(sig_p->lg_edges); n--; ) { + s = array_fetch (astg_signal *,sig_p->lg_edges,n); + astg_lg_comp (s,component); + } + } +} + +int astg_lock_graph_components (stg,f,fdata) +astg_graph *stg; /*u STG to process. */ +int (*f)(); /*i What to do with each component. */ +void *fdata; +{ + astg_generator gen; + astg_signal *sig_p; + array_t *component; + int n_comp = 0; + + astg_foreach_signal (stg,gen,sig_p) { + sig_p->unprocessed = ASTG_TRUE; + } + + astg_foreach_signal (stg,gen,sig_p) { + if (sig_p->unprocessed) { + component = array_alloc (astg_signal *,0); + astg_lg_comp (sig_p,component); + if (f != NULL) (*f) (component,n_comp,fdata); + n_comp++; + array_free (component); + } + } + + return n_comp; +} + +/* ----------------------- Shortest Path Algorithm -------------------------- *\ + + astg_lock_graph_shortest_path: finding shortest path from single source. + On exit, all weights for all signals will be set to the minimum + path to that signal from the source. From will be NULL if there + is no path. +\* -------------------------------------------------------------------------- */ + +static void astg_sp_insert (q,sig_p,new_weight,src) +lsList q; +astg_signal *sig_p; +int new_weight; +astg_signal *src; +{ + astg_signal *old_sig; + lsGen gen; + + if (sig_p->lg_queue != NULL) lsRemoveItem (sig_p->lg_queue,NULL); + sig_p->lg_weight = new_weight; + sig_p->lg_from = src; + + gen = lsStart (q); + while (lsNext(gen,(lsGeneric*)&old_sig,LS_NH) == LS_OK) { + if (new_weight <= old_sig->lg_weight) break; + } + + lsInBefore (gen,(lsGeneric)sig_p,&sig_p->lg_queue); +} + +static void astg_sp_adjust (src,dest,src_pqueue) +astg_signal *src, *dest; +lsList src_pqueue; +{ + int new_weight = src->lg_weight + 1; /* edge weight == 1 */ + + if (dest->unprocessed) { + dest->unprocessed = ASTG_FALSE; + astg_sp_insert (src_pqueue,dest,new_weight,src); + } + else if (new_weight < dest->lg_weight) { + astg_sp_insert (src_pqueue,dest,new_weight,src); + } +} + +void astg_lock_graph_shortest_path (stg,source) +astg_graph *stg; /*u Lock graph path information is updated. */ +astg_signal *source; /*u Signal to start with in lock graph. */ +{ + astg_generator gen; + lsList src_pqueue; + astg_signal *sig_p, *head; + int n; + + astg_foreach_signal (stg,gen,sig_p) { + sig_p->unprocessed = ASTG_TRUE; + sig_p->lg_queue = NULL; + sig_p->lg_from = NULL; + } + + src_pqueue = lsCreate (); + source->unprocessed = ASTG_FALSE; + astg_sp_insert (src_pqueue,source,0,NIL(astg_signal)); + + while (lsDelBegin(src_pqueue,(lsGeneric*)&sig_p) == LS_OK) { + sig_p->lg_queue = NULL; + for (n=array_n(sig_p->lg_edges); n--; ) { + head = array_fetch (astg_signal *,sig_p->lg_edges,n); + astg_sp_adjust (sig_p,head,src_pqueue); + } + } + + lsDestroy (src_pqueue,NULL); +} + +/* ----------------------------- Misc. Stuff -------------------------------- */ + +static astg_bool sandwich (t1,t,t2) +int t1, t, t2; +{ + int t1n, t2n; + + t1n = MIN (t1, t2); + t2n = MAX (t1, t2); + + return (t1n < t && t < t2n); +} + +static astg_bool interleaved (s1pos,s1neg,s2pos,s2neg) +int s1pos, s1neg; +int s2pos, s2neg; +{ + return sandwich (s1pos,s2pos,s1neg) ^ sandwich (s1pos,s2neg,s1neg); +} + +static astg_bool lg_all_on_path (sig_p,weightp,weightn) +astg_signal *sig_p; +int *weightp, *weightn; +{ + astg_generator gen; + astg_trans *t; + + astg_foreach_sig_trans (sig_p,gen,t) { + if (!t->on_path) return ASTG_FALSE; + if (t->type.trans.trans_type == ASTG_POS_X) { + *weightp = t->weight1.i; + } else if (t->type.trans.trans_type == ASTG_NEG_X) { + *weightn = t->weight1.i; + } else { + fail("bad trans"); + } + } + return ASTG_TRUE; +} + +static int find_interlocks (stg,data) +astg_graph *stg; +void *data; +{ + /* callback for simple cycles to find lock matrix */ + astg_signal *sig1, *sig2; + astg_generator sgen1, sgen2; + astg_vertex *v; + int n = 0; + lc_rec *lminfo = (lc_rec *) data; + int weight1p, weight1n, weight2p, weight2n; + + astg_foreach_path_vertex (stg,sgen1,v) { + v->weight1.i = n++; + } + + astg_foreach_signal (lminfo->stg,sgen1,sig1) { + + if (!lg_all_on_path(sig1,&weight1p,&weight1n)) continue; + + astg_foreach_signal (lminfo->stg,sgen2,sig2) { + + if (!lg_all_on_path(sig2,&weight2p,&weight2n)) continue; + + /* Both signals are on cycle -- check for interleaving. */ + if (interleaved (weight1p,weight1n,weight2p,weight2n)) { + if (sm_find (lminfo->lock_matrix,sig1->id,sig2->id) == 0) { + if (sig1->id < sig2->id) { + dbg(3,msg("%s SL %s because:",sig1->name,sig2->name)); + dbg(3,print_path (stg)); + } + sm_insert (lminfo->lock_matrix,sig1->id,sig2->id); + } + } + + } /* end for each sig2 */ + } /* end for each sig1 */ + + return 1; +} + +static int save_lock_classes (component,comp_n,data) +array_t *component; +int comp_n; /* ARGSUSED */ +void *data; +{ + /* Callback for strong components on lock graph */ + lc_rec *lc_info = (lc_rec *) data; + lock_class *new_class = ALLOC (lock_class,1); + + new_class->lg_vertices = array_dup (component); + array_insert_last (lock_class *,lc_info->classes,new_class); + return 0; +} + +static void free_lock_classes (lc_info) +lc_rec *lc_info; +{ + int n; + + if (lc_info->classes != NULL) { + for (n=array_n(lc_info->classes); n--; ) { + array_free (array_fetch(array_t *,lc_info->classes,n)); + } + array_free (lc_info->classes); + lc_info->classes = NULL; + } +} + +static int make_lock_graph (stg,lc_info) +astg_graph *stg; +lc_rec *lc_info; +{ + astg_signal *sig_p; + astg_generator sgen; + astg_signal *sig1, *sig2; + array_t *mapping; + int i,j,n = 0; + int n_comp; + + lc_info->lock_matrix = sm_alloc (); + mapping = array_alloc (astg_vertex *,0); + astg_foreach_signal (stg,sgen,sig_p) { + sig_p->id = n++; + array_insert_last (astg_signal *, mapping, sig_p); + } + + lc_info->stg = stg; + astg_simple_cycles (stg,ASTG_ALL_CYCLES,find_interlocks,(void *)lc_info,ASTG_ALL); + + for (i=0; i < stg->n_sig; i++) { + for (j=0; j < i; j++) { + assert ((sm_find(lc_info->lock_matrix,i,j) == 0) == (sm_find(lc_info->lock_matrix,j,i) == 0)); + if (sm_find(lc_info->lock_matrix,i,j)) { + sig1 = array_fetch (astg_signal *,mapping,i); + sig2 = array_fetch (astg_signal *,mapping,j); + /* Add to both lists since lock graph is undirected. */ + array_insert_last (astg_signal *,sig1->lg_edges,sig2); + array_insert_last (astg_signal *,sig2->lg_edges,sig1); + } + } + } + + array_free (mapping); + sm_free (lc_info->lock_matrix); + + free_lock_classes (lc_info); + lc_info->classes = array_alloc (array_t *,0); + n_comp = astg_lock_graph_components (stg, save_lock_classes,(void *)lc_info); + if (n_comp <= 1) { + free_lock_classes (lc_info); + } + dbg(1,msg("lock graph has %d componen%s\n",n_comp,n_comp==1?"t":"ts")); + return n_comp; +} + + /* ----------------------- Rectify Unique State Coding ------------------- */ + +static astg_bool can_lock_trans (t1,t2) +astg_trans *t1, *t2; +{ + /* Try t1 -> t2 -> t1->opp_trans -> t2->opp_trans + This has to bypass places -- not a gr function */ + astg_bool can_lock = ASTG_TRUE; + + if (astg_is_rel (astg_noninput_trigger(t2),t1) || + astg_is_rel (astg_noninput_trigger(astg_trx(t1)->opp_trans),t2) || + astg_is_rel (astg_noninput_trigger(astg_trx(t2)->opp_trans),astg_trx(t1)->opp_trans) || + astg_is_rel (astg_noninput_trigger(t1),astg_trx(t2)->opp_trans)) { + can_lock = ASTG_FALSE; + } + dbg(3,msg("can_lock %s %s = %d\n",astg_trans_name(t1),astg_trans_name(t2),can_lock)); + return can_lock; +} + +static astg_do_lock (t1,t2) +astg_trans *t1, *t2; +{ + /* Form lock t1 -> t2 -> t1->opp -> t2->opp */ + + dbg(1,msg("locking %s to %s\n",t1->name,t2->name)); + astg_add_constraint (t1,astg_noninput_trigger(t2),ASTG_TRUE); + astg_add_constraint (t2,astg_noninput_trigger(astg_trx(t1)->opp_trans),ASTG_TRUE); + astg_add_constraint (astg_trx(t1)->opp_trans,astg_noninput_trigger(astg_trx(t2)->opp_trans),ASTG_TRUE); + astg_add_constraint (astg_trx(t2)->opp_trans,astg_noninput_trigger(t1),ASTG_TRUE); +} + +static astg_bool astg_lock_sig (s1,s2,modify) +astg_signal *s1, *s2; +astg_bool modify; +{ + /* Try either s1+ -> s2+ -> s1- -> s2- or + s1+ -> s2- -> s1- -> s2+ */ + + astg_trans *t_s1_plus; + astg_trans *t_s2_plus; + astg_generator tgen1, tgen2; + + astg_foreach_pos_trans (s1,tgen1,t_s1_plus) { + astg_foreach_pos_trans (s2,tgen2,t_s2_plus) { + if (can_lock_trans (t_s1_plus,t_s2_plus)) { + if (modify) astg_do_lock (t_s1_plus,t_s2_plus); + return ASTG_TRUE; + } + else if (can_lock_trans (t_s1_plus,astg_trx(t_s2_plus)->opp_trans)) { + if (modify) astg_do_lock (t_s1_plus,astg_trx(t_s2_plus)->opp_trans); + return ASTG_TRUE; + } + } + } + + return ASTG_FALSE; +} + +static int astg_lock_sig_cost (stg,sig1,sig2) +astg_graph *stg; +astg_signal *sig1; +astg_signal *sig2; +{ + int cost = 0; + astg_signal *s1, *s2; + astg_generator gen1, gen2; + + /* Temporarily add this arc to the lock graph. */ + array_insert_last (astg_signal *, sig1->lg_edges, sig2); + array_insert_last (astg_signal *, sig2->lg_edges, sig1); + + astg_foreach_signal (stg,gen1,s1) { + astg_lock_graph_shortest_path (stg,s1); + astg_foreach_signal (stg,gen2,s2) { + if (astg_is_trigger(s1,s2) || astg_is_trigger(s2,s1)) { + cost += s2->lg_weight; + } + } + } + + ARRAY_DELETE_LAST (sig1->lg_edges); + ARRAY_DELETE_LAST (sig2->lg_edges); + return cost; +} + +static astg_bool select_from_lc (stg,lc1,sig1_p,lc2,sig2_p) +astg_graph *stg; +lock_class *lc1, *lc2; +astg_signal **sig1_p, **sig2_p; +{ + astg_bool found_sigs = ASTG_FALSE; + astg_signal *sig1, *sig2; + int new_cost, min_cost = 0; + int n1, n2; + + *sig1_p = *sig2_p = NULL; + + for (n1=array_n(lc1->lg_vertices); n1--; ) { + sig1 = array_fetch (astg_signal *,lc1->lg_vertices,n1); + for (n2=array_n(lc2->lg_vertices); n2--; ) { + sig2 = array_fetch (astg_signal *,lc2->lg_vertices,n2); + + if (astg_lock_sig(sig1,sig2,ASTG_FALSE)) { + new_cost = astg_lock_sig_cost (stg,sig1,sig2); + dbg(2,msg(" cost = %d (min=%d)\n",new_cost,min_cost)); + if (!found_sigs || new_cost < min_cost) { + found_sigs = ASTG_TRUE; + min_cost = new_cost; + *sig1_p = sig1; *sig2_p = sig2; + } + } + + } /* end for each sig2 */ + } /* end for each sig2 */ + + return found_sigs; +} + +static int measure_lc (lc1,lc2) +lock_class *lc1, *lc2; +{ + /* measure the "connectivity" between these two lock classes. */ + return (array_n(lc1->lg_vertices) - array_n(lc2->lg_vertices)); +} + +static int cmp_lc (obj1,obj2) +char *obj1, *obj2; +{ + /* Callback for array_sort */ + lock_class *lc1 = *(lock_class **) obj1; + lock_class *lc2 = *(lock_class **) obj2; + + /* Sort in order of decreasing connectivity measures. */ + return (lc2->connectivity - lc1->connectivity); +} + +static astg_bool select_two_signals (lc_info,sig1_p,sig2_p) +lc_rec *lc_info; +astg_signal **sig1_p; +astg_signal **sig2_p; +{ + astg_bool found_sig = ASTG_FALSE; + lock_class *lc1, *lc2; + int n; + + /* Just take the first lock class arbitrarily. */ + dbg(1,msg("select two signals\n")); + lc1 = array_fetch (lock_class *,lc_info->classes,0); + lc1->connectivity = 0; + + for (n=0; n < array_n(lc_info->classes); n++) { + lc2 = array_fetch (lock_class *,lc_info->classes,n); + if (lc2 == lc1) continue; + lc2->connectivity = measure_lc (lc1,lc2); + } + array_sort (lc_info->classes,cmp_lc); + + for (n=0; n < array_n(lc_info->classes); n++) { + lc2 = array_fetch (lock_class *,lc_info->classes,n); + if (lc2 == lc1) continue; + dbg(2,msg("checking LC %d\n",n)); + found_sig = select_from_lc (lc_info->stg,lc1,sig1_p,lc2,sig2_p); + if (found_sig) break; + } + + dbg(1,msg("exit select two sig %d\n",found_sig)); + return found_sig; +} + +static void lock_new_sig (stg) +astg_graph *stg; +{ + astg_signal *new_sig; + astg_trans *pos_t, *neg_t; + + new_sig = astg_new_sig (stg,ASTG_INTERNAL_SIG); + + /* Find two existing signals to lock this to. */ + pos_t = astg_find_trans (stg,new_sig->name,ASTG_POS_X, 0,ASTG_TRUE); + neg_t = astg_find_trans (stg,new_sig->name,ASTG_NEG_X,0,ASTG_TRUE); + + /* Go ahead and lock this up. */ + if (pos_t != NULL && neg_t != NULL) { + dbg(1,msg("How to lock these?\n")); + } +} + +astg_bool astg_state_coding (stg,do_lock) +astg_graph *stg; +astg_bool do_lock; +{ + /* Optionally try to form one lock class, and print lock graph. */ + + astg_bool rc = ASTG_TRUE; + astg_signal *sig_p, *sig1, *sig2; + astg_generator sgen; + lc_rec lc_info; + + if (!astg_is_marked_graph(stg)) { + printf("Sorry, lock graphs only work for marked graph STGs.\n"); + return 1; + } + + if (astg_set_opp (stg,ASTG_ALL) != 0) return 1; + + astg_foreach_signal (stg,sgen,sig_p) { + ARRAY_RESET (sig_p->lg_edges); + if (sig_p->n_trans != 2) { + printf("%s has %d transitions of signal %s.\n", + astg_name(stg), sig_p->n_trans, astg_signal_name(sig_p)); + printf("Lock graph only applies for unique transitions.\n"); + return 1; + } + } + + lc_info.stg = stg; + lc_info.lock_matrix = NULL; + lc_info.classes = NULL; + + while (make_lock_graph (stg,&lc_info) > 1 && do_lock) { + + if (select_two_signals (&lc_info,&sig1,&sig2)) { + astg_lock_sig (sig1,sig2,ASTG_TRUE); + } + else { + /* Add a signal and lock to that. */ + dbg(1,msg("Could not find two signals to lock.\n")); + lock_new_sig (stg); + rc = ASTG_FALSE; + break; + } + + } /* end while */ + + print_lock_graph (stg); + return rc; +} +#endif /* SIS */ diff --git a/sis/astg/astg_marking.c b/sis/astg/astg_marking.c new file mode 100644 index 0000000..e435b0e --- /dev/null +++ b/sis/astg/astg_marking.c @@ -0,0 +1,315 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_marking.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +/* -------------------------------------------------------------------------- *\ + marking.c -- conversion between markings and state codings. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + +#define NOT_IN_SM_FLAG flag1 + +astg_bool valid_marking (stg) +astg_graph *stg; +{ + int i,j; + int n_token, token_count; + array_t *smc; + astg_vertex *v; + int x = 0; + astg_bool good_marking = ASTG_TRUE; + astg_generator pgen; + + n_token = 0; + astg_foreach_place (stg,pgen,v) { + if (astg_plx(v)->initial_token) n_token++; + } + dbg(1,msg("checking marking of %d tokens\n",n_token)); + + for (i=0; i < array_n(stg->sm_comp); i++) { + smc = array_fetch (array_t *, stg->sm_comp, i); + token_count = 0; + for (j=0; j < array_n(smc); j++) { + v = array_fetch (astg_vertex *, smc, j); + if (v->vtype != ASTG_PLACE) continue; + if (astg_plx(v)->initial_token) token_count++; + } + if (token_count != 1) { + good_marking = ASTG_FALSE; + printf("warning: SM component %d has %d tokens:\n", + i+1,token_count); + astg_print_component (x++,smc,stdout); + } + } + + return good_marking; +} + +static lsStatus remove_marked_smc (data,arg) +lsGeneric data; +lsGeneric arg; /* ARGSUSED */ +{ + array_t *smc = (array_t *) data; + astg_vertex *place; + astg_vertex *v; + lsStatus rc = LS_OK; + int i; + + for (i=0; i < array_n(smc); i++) { + place = array_fetch (astg_vertex *, smc, i); + if (place->vtype != ASTG_PLACE) continue; + if (astg_plx(place)->initial_token) { + rc = LS_DELETE; + break; + } + } + + if (rc == LS_DELETE) { + /* This component has a token, so mark all its + vertices as invalid for further marking. */ + dbg(2,msg("deleting smc\n")); + for (i=0; i < array_n(smc); i++) { + v = array_fetch (astg_vertex *, smc, i); + v->NOT_IN_SM_FLAG = ASTG_FALSE; + } + } + + return rc; +} + +static astg_bool find_marking (stg) +astg_graph *stg; +{ + lsList unmarked_smc; + array_t *smc; + astg_vertex *place, *new_marked; + astg_generator gen; + astg_vertex *v; + astg_bool unmarked; + astg_generator pgen; + astg_place *p; + int i; + + astg_foreach_vertex (stg,gen,v) { + v->NOT_IN_SM_FLAG = ASTG_TRUE; /* is not in marked SM */ + } + + stg->has_marking = ASTG_FALSE; + stg->change_count++; + astg_foreach_place (stg,pgen,p) { + astg_plx(p)->initial_token = ASTG_FALSE; + } + + unmarked_smc = lsCreate (); + for (i=0; i < array_n(stg->sm_comp); i++) { + smc = array_fetch (array_t *, stg->sm_comp, i); + lsNewBegin (unmarked_smc,(char *)smc,(lsHandle *)NULL); + } + + while (lsDelBegin (unmarked_smc,(lsGeneric *)&smc) != LS_NOMORE) { + + /* Attempt to place token in this SM. */ + unmarked = ASTG_TRUE; + for (i=0; i < array_n(smc); i++) { + place = array_fetch (astg_vertex *, smc, i); + if (place->vtype != ASTG_PLACE) continue; + if (unmarked && place->NOT_IN_SM_FLAG) { + astg_plx(place)->initial_token = ASTG_TRUE; + new_marked = place; + unmarked = ASTG_FALSE; + } + place->NOT_IN_SM_FLAG = ASTG_FALSE; + } + + if (unmarked) break; + dbg(1,msg("marking %s\n",astg_place_name(new_marked))); + + lsForeach (unmarked_smc, remove_marked_smc, (lsGeneric)new_marked); + + } /* end while */ + + lsDestroy (unmarked_smc,(void (*)())NULL); + + if (unmarked) { + printf("error: no 1-token state machine marking.\n"); + } + else { + stg->has_marking = ASTG_TRUE; + if (astg_debug_flag >= 2) { + printf("Valid initial marking:\n"); + astg_foreach_place (stg,pgen,p) { + if (astg_plx(p)->initial_token) printf(" %s",p->name); + } + printf("\n"); + } + } + + return stg->has_marking; +} + +astg_bool astg_one_sm_token (stg) +astg_graph *stg; +{ + astg_bool found_marking = ASTG_FALSE; + + if (get_sm_comp (stg,ASTG_TRUE) != ASTG_OK || + get_mg_comp (stg,ASTG_TRUE) != ASTG_OK) { + printf("No initial marking; STG is not even live/safe.\n"); + } + else if (stg->has_marking) { + found_marking = valid_marking (stg); + } + else { + found_marking = find_marking (stg); + } + + return found_marking; +} + +extern astg_retval astg_initial_state (stg,state_p) +astg_graph *stg; /*u do token flow for this STG */ +astg_scode *state_p; /*o state code if result OK or NOT_USC */ +{ + /* Returns the state code and corresponding marking for some initial state + of the STG. If a marking has been set with the initial_token flags of + each place, then that is used, otherwise an arbitrary live-safe marking + is selected. Returns: + ASTG_OK: state code of initial marking is returned. + ASTG_NO_MARKING: no live-safe initial marking. + ASTG_NOT_SAFE: the initial marking was not safe. */ + + astg_retval status = ASTG_NO_MARKING; + + if (stg->has_marking || astg_one_sm_token(stg)) { + status = astg_token_flow (stg,ASTG_FALSE); + if (status == ASTG_OK || status == ASTG_NOT_USC) { + *state_p = astg_adjusted_code(stg,stg->flow_info.initial_state); + status = ASTG_OK; + } + } + + return status; +} + +extern astg_retval astg_unique_state (stg,state_code) +astg_graph *stg; +astg_scode *state_code; +{ + /* Returns an arbitrary unique state code for this STG. Even if the STG + has a state assignment problem, a state code will be returned which + corresponds to a unique marking. Possible return values: + ASTG_OK: a unique state code is returned + ASTG_NO_MARKING: no state codes were unique + otherwise some other token flow error occured. */ + + astg_retval status; + astg_generator sgen; + astg_state *state_p; + + status = astg_token_flow (stg,ASTG_FALSE); + if (status == ASTG_OK) { + /* Any state including initial state is okay. */ + *state_code = astg_adjusted_code(stg,stg->flow_info.initial_state); + } + else if (status == ASTG_NOT_USC) { + /* Try to find some unique state. */ + status = ASTG_NO_MARKING; + astg_foreach_state (stg,sgen,state_p) { + if (status == ASTG_OK) continue; + if (astg_state_n_marking(state_p) == 1) { + status = ASTG_OK; + *state_code = astg_state_code (state_p); + } + } + + if (status != ASTG_OK) { + printf("No unique state code was found.\n"); + } + } + + return status; +} + +astg_retval astg_set_marking_by_code (stg,state_code,sig_mask) +astg_graph *stg; /*u Net to set an initial marking for. */ +astg_scode state_code; /*i State code for desired initial marking. */ +astg_scode sig_mask; /*i Mask of signals to ignore in state code. */ +{ + astg_retval status; + astg_generator sgen; + astg_state *state_p; + astg_marking *marking_p; + astg_scode mismatches; + + status = astg_token_flow (stg,ASTG_FALSE); + if (status != ASTG_OK && status != ASTG_NOT_USC) return status; + status = ASTG_NO_MARKING; + + astg_foreach_state (stg,sgen,state_p) { + if (status == ASTG_OK) continue; + mismatches = (~sig_mask) & (state_code ^ astg_state_code(state_p)); + if (mismatches == 0) { + status = ASTG_OK; + marking_p = array_fetch (astg_marking *,state_p->states,0); + astg_set_marking (stg,marking_p); + } + } + + dbg(1,msg("set_marking %d\n",status)); + return status; +} + +extern astg_retval astg_set_marking_by_name (stg,sig_values) +astg_graph *stg; +st_table *sig_values; +{ + /* Set the marking using pairs of signal name/value. The key for the hash + table is signal name strings, the data is an int which nonzero means + the signal should have level 1, otherwise 0. These values are combined + into a astg_scode value and then astg_set_marking is called. + Return values: + ASTG_OK: marking found and set + ASTG_BAD_SIGNAME: unrecognized signal name, message is printed + ASTG_NO_MARKING: no compatible marking could be found + Other various flow errors can occur (not safe, etc.). Also see + astg_set_marking. */ + + astg_retval status; + st_generator *sig_gen; + astg_signal *sig_p; + char *sig_name; + astg_scode state_code = 0, sig_mask = 0; + int value; + + status = astg_token_flow (stg,ASTG_FALSE); + /* State assignment problem does not phaze us here. */ + if (status == ASTG_NOT_USC) status = ASTG_OK; + if (status != ASTG_OK) return status; + + st_foreach_item_int (sig_values,sig_gen,(char **)&sig_name, &value) { + sig_p = astg_find_named_signal (stg,sig_name); + if (sig_p == NULL) { + printf("No signal '%s'\n",sig_name); + status = ASTG_BAD_SIGNAME; + } + else { + sig_mask |= astg_signal_bit (sig_p); + if (value) state_code |= astg_signal_bit (sig_p); + } + } + + if (status == ASTG_OK) { + status = astg_set_marking_by_code (stg,state_code,sig_mask); + } + + return status; +} +#endif /* SIS */ diff --git a/sis/astg/astg_persist.c b/sis/astg/astg_persist.c new file mode 100644 index 0000000..90f4d5e --- /dev/null +++ b/sis/astg/astg_persist.c @@ -0,0 +1,194 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_persist.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +/* -------------------------------------------------------------------------- *\ + persist.c -- algorithm for making persistent MG STGs. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + +typedef struct { + astg_vertex *per1; + astg_vertex *per2; +} per_two_trans; + + +static int find_per (stg,data) +astg_graph *stg; /* ARGSUSED */ +void *data; /*i persistency information structure. */ +{ + per_two_trans *per = (per_two_trans *) data; + + /* Simple cycles callback: check if two transitions are on the cycle. */ + return (per->per1->on_path && per->per2->on_path); +} + +static int find_opp (stg,data) +astg_graph *stg; /*u Try to match +/- transition pairs. */ +void *data; /* ARGSUSED */ +{ + /* Simple cycles callback to locate transition matchings. */ + + astg_generator gen; + astg_trans *t; + astg_signal *sig_p; + + astg_foreach_path_vertex (stg,gen,t) { + if (t->vtype != ASTG_TRANS) continue; + sig_p = astg_trx(t)->sig_p; + sig_p->mark = ASTG_FALSE; + sig_p->n_found++; + if (sig_p->n_found == sig_p->n_trans) { + sig_p->last_trans = t; + sig_p->mark = ASTG_TRUE; + } + } + + astg_foreach_path_vertex (stg,gen,t) { + if (t->vtype != ASTG_TRANS) continue; + sig_p = astg_trx(t)->sig_p; + sig_p->n_found = 0; + if (sig_p->mark) { + assert (astg_trx(t)->trans_type != astg_trx(sig_p->last_trans)->trans_type); + astg_trx(sig_p->last_trans)->opp_trans = t; + sig_p->last_trans = t; + } + } + + return 0; +} + +int astg_set_opp (stg,subset) +astg_graph *stg; +astg_bool subset; +{ + int result = 0; + astg_signal *sig_p; + astg_trans *t; + astg_generator tgen, sgen; + + astg_foreach_signal (stg,sgen,sig_p) { + sig_p->n_trans = 0; + sig_p->n_found = 0; + } + + astg_foreach_trans (stg,tgen,t) { + if (subset && !t->subset) continue; + astg_trx(t)->sig_p->n_trans++; + astg_trx(t)->opp_trans = NULL; + } + + astg_simple_cycles (stg,ASTG_ALL_CYCLES,find_opp,ASTG_NO_DATA,subset); + + astg_foreach_trans (stg,tgen,t) { + if (subset && !t->subset) continue; + if (astg_trx(t)->opp_trans == NULL) { + printf("No opposite found for %s.\n",t->name); + result = -1; + } + } + + return result; +} + +static int make_mgc_persistent (stg,modify) +astg_graph *stg; +astg_bool modify; /*i ASTG_FALSE=only identify nonpersistent transitions */ +{ + astg_vertex *dest; + astg_graph *g = stg; + lsList vertex_stack; + int n_added = 0; + per_two_trans per_rec; + astg_generator tgen, pgen; + astg_trans *t; + astg_place *p; + + if (astg_set_opp (stg,ASTG_SUBSET) != 0) return -1; + vertex_stack = lsCreate(); + + astg_foreach_trans (stg,tgen,t) { + if (t->subset && astg_out_degree(t) > 1) { + lsNewBegin (vertex_stack, (lsGeneric)t, LS_NH); + } + } + + while (lsDelBegin(vertex_stack, (lsGeneric*) &t) == LS_OK) { + assert (t->vtype == ASTG_TRANS); + astg_foreach_output_place (t,pgen,p) { + per_rec.per1 = p->out_edges->head; + per_rec.per2 = astg_trx(t)->opp_trans; + assert (per_rec.per1->vtype == ASTG_TRANS); + if (astg_simple_cycles (g,ASTG_ALL_CYCLES,find_per,(void *)&per_rec,ASTG_SUBSET) == 0) { + dbg(1,msg(" %s -> %s non-persistent transition\n", + astg_v_name(t),astg_v_name(per_rec.per1))); + astg_sel_vertex (t,ASTG_TRUE); + if (modify) { /* Add a persistency constraint. */ + dest = astg_noninput_trigger (per_rec.per2); + if (dest == NULL) { + printf("Error: cannot make %s -> %s persistent\n", + astg_trans_name(t),astg_trans_name(per_rec.per1)); + printf("because no noninput transition enables %s.\n", + astg_trans_name(per_rec.per2)); + } else { + n_added++; + astg_add_constraint (per_rec.per1,dest,ASTG_FALSE); + /* Now per1 needs to be checked. */ + lsNewBegin (vertex_stack, (lsGeneric)per_rec.per1, LS_NH); + } + } + } + } + } + + lsDestroy (vertex_stack,NULL); + return n_added; +} + +int make_persistent (stg,modify) +astg_graph *stg; +astg_bool modify; +{ + int status = 0, n_added = 0; + array_t *mgc; + astg_vertex *v; + astg_generator gen; + int mgc_n, n, n_scc; + + n_scc = astg_connected_comp (stg,ASTG_NO_CALLBACK,ASTG_NO_DATA,ASTG_ALL); + if (n_scc != 1) { + printf("error: %s is not connected (it has %d components).\n", + astg_name(stg), n_scc); + status = -1; + } + else { + dbg(1,msg("checking each MGC for nonpersistent transitions\n")); + get_mg_comp (stg,ASTG_FALSE); + + astg_sel_new (stg,"nonpersistent transitions",ASTG_FALSE); + for (mgc_n=0; mgc_n < array_n(stg->mg_comp); mgc_n++) { + mgc = array_fetch (array_t *,stg->mg_comp,mgc_n); + astg_foreach_vertex (stg,gen,v) v->subset = ASTG_FALSE; + for (n=0; n < array_n(mgc); n++) { + v = array_fetch (astg_vertex *,mgc,n); + v->subset = ASTG_TRUE; + } + dbg(1,msg("MG component %d...\n",mgc_n+1)); + status = make_mgc_persistent (stg,modify); + if (status < 0) break; + n_added += status; + } + } + + dbg(1,msg("added %d persistency constraints\n",n_added)); + return status; +} +#endif /* SIS */ diff --git a/sis/astg/astg_read.c b/sis/astg/astg_read.c new file mode 100644 index 0000000..4da3dc8 --- /dev/null +++ b/sis/astg/astg_read.c @@ -0,0 +1,969 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_read.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +/* -------------------------------------------------------------------------- *\ + astg_read.c -- read STG from text description. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + + +char *astg_make_name (sig_name,trans_type,copy_n) +char *sig_name; +astg_trans_enum trans_type; +int copy_n; +{ + char tname[ASTG_NAME_LEN], copy_name[ASTG_NAME_LEN]; + + strcpy (tname,sig_name); + if (trans_type == ASTG_POS_X) + strcat (tname,"+"); + else if (trans_type == ASTG_NEG_X) + strcat (tname,"-"); + else if (trans_type == ASTG_TOGGLE_X) + strcat (tname,"~"); + else if (trans_type == ASTG_HATCH_X) + strcat (tname,"*"); + else if (trans_type != ASTG_DUMMY_X) + fail("bad trans type"); + + if (copy_n > 0) { + sprintf(copy_name,"/%d",copy_n); + strcat (tname, copy_name); + } + return util_strsav (tname); +} + +static int parse_name (source,signame,type,copy_n) +io_t *source; /*u buffer contains vertex name */ +char *signame; /*o signal name */ +astg_trans_enum *type; /*o transition type for ASTG_TRANS */ +int *copy_n; /*o copy number for ASTG_TRANS */ +{ + char *t, *s; + + s = source->buffer; + signame[0] = '\0'; + if ((t = strrchr(s,'+')) != NULL) { + *type = ASTG_POS_X; + strncat (signame,s, (t-s)); + } + else if ((t = strrchr(s,'-')) != NULL) { + *type = ASTG_NEG_X; + strncat (signame,s, (t-s)); + } + else if ((t = strrchr(s,'~')) != NULL) { + *type = ASTG_TOGGLE_X; + strncat (signame,s, (t-s)); + } + else if ((t = strrchr(s,'*')) != NULL) { + *type = ASTG_HATCH_X; + strncat (signame,s, (t-s)); + } + else { + *type = ASTG_DUMMY_X; + if ((t = strchr(s,'/')) != NULL) { + strncat (signame,s, (t-s)); + } else { + strcpy (signame,s); + } + } + + *copy_n = 0; + if ((t=strrchr(s,'/')) != NULL && sscanf(t+1,"%d",copy_n) != 1) { + return io_error (source,"unrecognizable copy number"); + } + return 0; +} + +astg_trans *find_trans_by_name (source,stg,create) +io_t *source; +astg_graph *stg; +astg_bool create; +{ + astg_trans_enum trans_type; + int copy_n; + char name[ASTG_NAME_LEN]; + astg_trans *t = NULL; + + if (parse_name(source,name,&trans_type,©_n) == 0) { + t = astg_find_trans (stg,name,trans_type,copy_n,create); + if (t == NULL) { + if (create) + io_error (source,"no such signal"); + else + io_error(source,"no such transition"); + } + } + return t; +} + +/* --------------------- Simple input parsing utilities --------------------- */ + +void io_open (source,stream,s) +io_t *source; +FILE *stream; +char *s; +{ + if (s != NULL) { + source->from_file = ASTG_FALSE; + source->s = source->p = s; + source->inbuf = NULL; + } else { + source->from_file = ASTG_TRUE; + source->stream = (stream == NULL) ? stdin : stream; + source->in_len = 180; + source->inbuf = ALLOC (char,source->in_len); + source->p = source->s = source->inbuf; + *source->s = '\0'; + } + source->line_n = 0; + source->buflen = 180; + source->buffer = ALLOC (char,source->buflen); + source->save_one = '\0'; + source->errflag = 0; +} + +int io_close (source) +io_t *source; +{ + int status = source->errflag; + FREE (source->inbuf); + FREE (source->buffer); + return status; +} + +static int io_dump_string (buffer, offset) +char *buffer; +int offset; +{ + char *p = buffer; + char buff[5], *s; + int c; + int rel_posn = 0, new_offset = 0; + + while ((c=(*(p++))) != '\0') { + if (isprint(c)) { + buff[0] = c; buff[1] = '\0'; + s = buff; + } else if (c == '\n') { + s = ""; + } else if (c == '\t') { + s = "\\t"; + } else if (c == EOF) { + s = ""; + } else { + sprintf(buff,"\\%3.3o",c); + s = buff; + } + + rel_posn += strlen(s); + if (--offset == 0) new_offset = rel_posn; + fputs(s,stdout); + } + + fputs("\n",stdout); + return new_offset; +} + +void io_msg (source,warning,message) +io_t *source; +astg_bool warning; +char *message; +{ + int offset; + int n_spaces, n_dashes; + + fputs(warning?"\nWarning: ":"\nError: ",stdout); + puts (message); + + printf("\n%4d: ",source->line_n); + offset = (source->p - source->s); + if (source->save_one != '\0') offset--; + n_spaces = 6 + io_dump_string (source->s,offset); + + n_dashes = strlen(source->buffer); + n_spaces -= n_dashes; + + while (n_spaces--) fputc(' ',stdout); + while (n_dashes--) fputc('^',stdout); + fputs("\n",stdout); +} + +void io_warn (source,message) +io_t *source; +char *message; +{ + if (source->errflag == 0) { + io_msg (source,ASTG_TRUE,message); + } +} + +int io_error (source,message) +io_t *source; +char *message; +{ + if (source->errflag == 0) { + source->errflag = -1; + io_msg (source,ASTG_FALSE,message); + source->save_one = EOF; + } + return -1; +} + + +int io_get2 (source) +io_t *source; +{ + int c = source->save_one; + + if (c != '\0') { + if (c != EOF) source->save_one = '\0'; + } + else if ((c=(*source->p)) == '\0') { + if (source->from_file) { + if (fgets (source->inbuf,source->in_len,source->stream) == NULL) { + c = source->save_one = EOF; + } + else { + source->line_n++; + source->p = source->inbuf; + c = *(source->p++); + } + } + else { + c = EOF; + } + } + else { + source->p++; + } + dbg(3,msg("io_get %c (%d)\n",c,c)); + return c; +} + + +int io_get (source) +io_t *source; +{ + int c = io_get2 (source); + + if (c == '#') { + do { + c = io_get2 (source); + } while (c != EOF && c != '\n'); + io_unget (c,source); + c = ' '; + } + return c; +} + + +static int io_getc (source) +io_t *source; +{ + int c; + do { + c = io_get (source); + if (c == EOF) io_error(source,"unexpected end-of-file"); + } while (c != EOF && c != '\n' && isspace(c)); + return c; +} + +static void io_unget (c,source) +int c; +io_t *source; +{ + if (source->save_one != EOF) { + source->save_one = c; + } +} + +static int io_peek (source) +io_t *source; +{ + int c = io_getc (source); + io_unget (c,source); + return c; +} + +int io_token (source) +io_t *source; +{ + int c, start_char, end_char, depth; + char *p; + static char separators[] = {",>)}?"}; + int len = source->buflen; + + do { + c = io_get(source); + if (c == '\n') break; + } while (isspace(c)); + + p = source->buffer; + + if (strchr("{}<,>",c)) { + *(p++) = c; + } + else if (isprint(c)) { + depth = 1; start_char = c; + if (c == '(') + end_char = ')'; + else if (c == '"') + end_char = '"'; + else + end_char = EOF; + + while (c != EOF) { + if (len == 1) { + printf("Warning: token truncated.\n"); + } else if (len > 0) { + *(p++) = c; + } + len--; + if (depth == 0) break; + c = io_get(source); + if (end_char == EOF) { + if (isspace(c) || strchr(separators,c) != NULL) { + io_unget (c,source); + break; + } + } else if (c == end_char) { + depth--; + } else if (c == start_char) { + depth++; + } + } /* end while */ + } + else { + *(p++) = c; + } + + *p = '\0'; + c = *source->buffer; + return c; +} + +static astg_bool io_maybe (source,target_char) +io_t *source; +int target_char; +{ + int next_c = io_getc(source); + if (next_c != target_char) io_unget (next_c,source); + return (next_c == target_char); +} + +static int io_mustbe (source,token) +io_t *source; +char *token; +{ + char msgbuf[80]; + + io_token (source); + if (strcmp(source->buffer,token)) { + strcpy(msgbuf,"expecting '"); + if (!strcmp("\n",token)) { + strcat(msgbuf,"end of line"); + } + else { + strcat(msgbuf,token); + } + strcat(msgbuf,"' here"); + io_error (source,msgbuf); + } + return io_status(source); +} + +/* ------------------------- Parser for STG --------------------------------- */ + +static int is_place_name (stg,vname) +astg_graph *stg; +char *vname; +{ + int is_place, c; + int n; + char *p; + + if ((p=strchr(vname,'/')) != NULL) { + is_place = ASTG_FALSE; + } + else if (astg_find_named_signal (stg,vname) != NULL) { + is_place = ASTG_FALSE; + } + else { + p = strrchr (vname,'/'); + n = ((p == NULL) ? strlen(vname) : (p-vname)) - 1; + c = vname[n]; + is_place = (strchr("+-*~",c) == NULL); + } + return is_place; +} + +static int read_point_list (source,e) +io_t *source; +astg_edge *e; +{ + float xp; + + if (io_maybe(source,'(')) { + if (e->spline_points == NULL) { + e->spline_points = array_alloc (float,0); + } + do { + io_token (source); + if (sscanf(source->buffer,"%f",&xp) == 1) { + array_insert_last (float,e->spline_points,xp); + } else { + io_error (source,"bad coordinate"); + } + } while (io_maybe(source,',')); + + io_mustbe (source,")"); + } + return io_status(source); +} + +static void read_edge_guard (source,se) +io_t *source; +astg_edge *se; +{ + if (io_maybe(source,'?')) { + io_token (source); + if (!astg_set_guard (se,source->buffer,source)) { + io_error (source,"unrecognizable guard"); + } + } +} + +static int read_place_fanout (source,stg,startp) +io_t *source; +astg_graph *stg; +astg_place *startp; +{ + astg_trans *t; + + dbg(2,msg("read place fanout\n")); + io_token (source); + + if ((t=find_trans_by_name(source,stg,ASTG_TRUE)) != NULL) { + astg_edge *e = astg_find_edge (startp,t,ASTG_FALSE); + if (e != NULL) { + io_warn (source,"Repeated edge to this transition is ignored."); + } else { + e = astg_new_edge (startp,t); + read_edge_guard (source,e); + read_point_list (source,e); + } + } + else { + io_error (source,"unrecognized signal transition name"); + } + return io_status(source); +} + +static int read_trans_fanout (source,stg,startt) +io_t *source; +astg_graph *stg; +astg_trans *startt; +{ + int c = io_token(source); + int status = 0; + astg_place *p; + astg_trans *t; + astg_edge *e; + + dbg(2,msg("read trans fanout\n")); + + if (isalpha(c)) { + if (is_place_name(stg,source->buffer)) { + /* This is an explicit place. */ + p = astg_find_place (stg,source->buffer,ASTG_TRUE); + e = astg_find_edge (startt,p,ASTG_FALSE); + if (e != NULL) { + io_warn (source,"Repeated edge to this place is ignored."); + } + else { + e = astg_new_edge (startt,p); + read_point_list (source,e); + } + } + else { + /* This has an implied place; insert a place automatically. */ + t = find_trans_by_name (source,stg,ASTG_TRUE); + if (t != NULL) { + p = astg_find_place (stg,NULL,ASTG_TRUE); + astg_new_edge (startt,p); + astg_new_edge (p,t); + } + /* How to do edges for this? */ + } + } + else { + status = io_error (source,"bad fanout place"); + } + return status; +} + +void astg_read_marking (source,stg) +io_t *source; +astg_graph *stg; +{ + astg_trans *t1, *t2, *t; + astg_generator tgen, pgen; + astg_place *place, *meant_p; + + stg->has_marking = ASTG_TRUE; + io_mustbe (source,"{"); + + while (io_status(source) == 0 && !io_maybe(source,'}')) { + if (io_maybe(source,'<')) { + io_token (source); + t1 = find_trans_by_name (source,stg,ASTG_FALSE); + io_mustbe (source,","); + io_token (source); + t2 = find_trans_by_name (source,stg,ASTG_FALSE); + io_mustbe (source,">"); + if (t1 != NULL && t2 != NULL) { + meant_p = NULL; + astg_foreach_output_place (t1,pgen,place) { + astg_foreach_output_trans (place,tgen,t) { + if (t == t2) meant_p = place; + } + } + if (meant_p == NULL) { + io_error (source,"couldn't find this edge"); + } else { + meant_p->type.place.initial_token = ASTG_TRUE; + } + } + } + else { + io_token (source); + meant_p = astg_find_place (stg,source->buffer,ASTG_FALSE); + if (meant_p == NULL) { + io_error (source,"no place with this name"); + } else { + meant_p->type.place.initial_token = ASTG_TRUE; + } + } + } + + if (io_status(source) == 0) stg->has_marking = ASTG_TRUE; + stg->change_count++; +} + +static void read_delay (source,delay) +io_t *source; +float *delay; +{ + if (isdigit(io_peek(source))) { + io_token (source); + if (sscanf(source->buffer,"%f",delay) != 1) { + io_error (source,"invalid transition delay value"); + } + } +} + +static int read_posn (source,xp,yp) +io_t *source; +float *xp, *yp; +{ + if (io_maybe(source,'(')) { + io_token (source); + if (sscanf(source->buffer," %f",xp) != 1) { + io_error (source,"bad x coordinate"); + } + io_mustbe(source,","); + io_token (source); + if (sscanf(source->buffer," %f",yp) != 1) { + io_error (source,"bad y coordinate"); + } + io_mustbe(source,")"); + } + return io_status(source); +} + +static void read_vertex (source,stg) +io_t *source; +astg_graph *stg; +{ + astg_place *p; + astg_trans *t; + + dbg(2,msg("enter read_vertex\n")); + io_token (source); + + if (is_place_name (stg,source->buffer)) { + if ((p=astg_find_place (stg,source->buffer,ASTG_TRUE)) != NULL) { + p->type.place.user_named = ASTG_TRUE; + read_posn (source,&p->x,&p->y); + while (io_status(source) == 0 && !io_maybe(source,'\n')) { + if (read_place_fanout (source,stg,p)) break; + } + } + } + else { + if ((t=find_trans_by_name (source,stg,ASTG_TRUE)) != NULL) { + read_delay (source,&t->type.trans.delay); + read_posn (source,&t->x,&t->y); + while (io_status(source) == 0 && !io_maybe(source,'\n')) { + if (read_trans_fanout (source,stg,t)) break; + } + } + } + + dbg(2,msg("end read_vertex\n")); +} + +static void read_graph_check (source,stg) +io_t *source; +astg_graph *stg; +{ + astg_generator gen, gen2; + astg_signal *s; + astg_place *p, *fan_place; + astg_trans *t, *new_t; + + if (io_status(source) != 0) return; + + /* --- check that all signals were used? */ + + /* Expand hatch transitions into toggles equivalent. */ + + astg_foreach_trans (stg,gen,t) { + if (astg_trans_type(t) == ASTG_HATCH_X) { + s = astg_new_sig (stg,ASTG_DUMMY_SIG); + p = astg_new_place (stg,NULL,NULL); + + new_t = astg_find_trans (stg,astg_signal_name(s),ASTG_DUMMY_X,1,ASTG_TRUE); + astg_new_edge (new_t,p); + astg_foreach_input_place (t,gen2,fan_place) { + astg_new_edge (fan_place,new_t); + } + + new_t = astg_find_trans (stg,astg_signal_name(s),ASTG_DUMMY_X,2,ASTG_TRUE); + astg_new_edge (p,new_t); + astg_foreach_output_place (t,gen2,fan_place) { + astg_new_edge (new_t,fan_place); + } + + /* Use same copy number to generate a toggle transition. */ + new_t = astg_find_trans (stg,astg_signal_name(astg_trans_sig(t)), + ASTG_TOGGLE_X,t->type.trans.copy_n,ASTG_TRUE); + astg_new_edge (p,new_t); + astg_new_edge (new_t,p); + + astg_delete_trans (t); + } + } + + astg_foreach_trans (stg,gen,t) { + if (astg_in_degree(t) == 0) { + printf("warning: '%s' has no in edges\n",astg_trans_name(t)); + } + if (astg_out_degree(t) == 0) { + printf("warning: '%s' has no out edges\n",astg_trans_name(t)); + } + } + + astg_foreach_place (stg,gen,p) { + astg_make_place_name (stg,p); + if (astg_in_degree(p) == 0) { + printf("warning: '%s' has no in edges\n",astg_place_name(p)); + } + if (astg_out_degree(p) == 0) { + printf("warning: '%s' has no out edges\n",astg_place_name(p)); + } + } +} + +static void read_graph (source,stg) +io_t *source; +astg_graph *stg; +{ + int c; + + while (io_status(source) == 0) { + c = io_peek (source); + if (isalpha(c)) { + read_vertex (source,stg); + } else if (c == '.') { + break; + } else if (c == '\n') { + io_getc (source); + } else { + io_error (source,"bad vertex description"); + } + } + + read_graph_check (source,stg); +} + +static void read_signals (source,stg,sig_type) +io_t *source; +astg_graph *stg; +astg_signal_enum sig_type; +{ + while (io_status(source) == 0 && io_token(source) != '\n') { + if (isalpha(source->buffer[0]) && + strchr(source->buffer,'/') == NULL && + strchr(source->buffer,'-') == NULL && + strchr(source->buffer,'+') == NULL) { + astg_find_signal (stg,source->buffer,sig_type,ASTG_TRUE); + } + else { + io_error (source,"invalid signal name"); + } + } +} + +static void read_note (source,stg) +io_t *source; +astg_graph *stg; +{ + int c; + char *p; + + p = source->buffer; + while ((c=io_get(source)) != '\n' && c != EOF) { + *(p++) = c; + } + *p = '\0'; + lsNewEnd (stg->comments,util_strsav(source->buffer),LS_NH); +} + +static void read_stg (source,stg) +io_t *source; +astg_graph *stg; +{ + int c; + + while ((c=io_token(source)) != EOF) { + + if (!strcmp(source->buffer,".end")) { + /* No newline required for this. */ + break; + } + else if (!strcmp(source->buffer,".model") || + !strcmp(source->buffer,".name")) { + if (io_token (source) == '\n') { + io_error(source,"no model name specified"); + } else { + FREE (stg->name); + stg->name = util_strsav(source->buffer); + io_mustbe (source,"\n"); + } + } + else if (!strcmp(source->buffer,".note")) { + read_note (source,stg); + } + else if (!strcmp(source->buffer,".graph")) { + io_mustbe (source,"\n"); + read_graph (source,stg); + } + else if (!strcmp(source->buffer,".inputs")) { + read_signals (source,stg,ASTG_INPUT_SIG); + } + else if (!strcmp(source->buffer,".internal")) { + read_signals (source,stg,ASTG_INTERNAL_SIG); + } + else if (!strcmp(source->buffer,".outputs")) { + read_signals (source,stg,ASTG_OUTPUT_SIG); + } + else if (!strcmp(source->buffer,".dummy")) { + read_signals (source,stg,ASTG_DUMMY_SIG); + } + else if (!strcmp(source->buffer,".marking")) { + astg_read_marking (source,stg); + } + else if (c == '.') { + io_error (source,"unrecognized keyword"); + } + else if (c != '\n') { + io_error (source,"what is this supposed to be?"); + } + + } /* end while */ +} + +extern astg_graph *astg_read (fin,fname) +FILE *fin; /*i stream to read STG from */ +char *fname; /*i name of stream to use in messages */ +{ + /* Read an STG description from the opened stream. The filename + argument is used for error messages and to remember where the STG + description came from. */ + + io_t source; + astg_graph *stg; + + io_open (&source,fin,(char *)NULL); + + stg = astg_new (fname); + stg->filename = util_strsav (fname); + + read_stg (&source,stg); + io_close (&source); /* Caller must close fin */ + + if (io_status(&source) == 0) { + stg->file_count = astg_change_count (stg); + dbg(2,write_blif(stdout,stg->guards,ASTG_FALSE,ASTG_FALSE)); + } + else { + astg_delete (stg); + stg = NULL; + } + + return stg; +} + +/* ---------------------------- Write STG ----------------------------------- */ + +void astg_write_marking (stg,fout) +astg_graph *stg; +FILE *fout; +{ + int sep_char, n_token = 0; + astg_generator pgen; + astg_place *p; + + if (stg->has_marking) { + sep_char = '{'; + astg_foreach_place (stg,pgen,p) { + if (p->type.place.initial_token) { + n_token++; + fputc(sep_char,fout); sep_char = ' '; + fputs(astg_place_name(p),fout); + } + } + fputs ((n_token==0)?"{ }\n":"}\n",fout); + } +} + +static char *trim_float (value,buffer) +double value; +char *buffer; +{ + char *p; + sprintf(buffer,"%f",value); + p = buffer + strlen(buffer) - 1; + while (p > buffer && *p == '0') p--; + if (p > buffer && *p == '.') p--; + *(p+1) = '\0'; + return buffer; +} + +int astg_write (stg,hide_places,stream) +astg_graph *stg; +astg_bool hide_places; +FILE *stream; +{ + astg_signal *sig_p; + astg_edge *se; + astg_trans *t; + astg_place *p; + astg_generator tgen, egen, pgen, sgen; + lsGen cgen; + lsGeneric data; + int n_internal, n_dummy; + char fbuf1[20], fbuf2[20]; + + fprintf(stream,".model %s\n",stg->name); + cgen = lsStart (stg->comments); + while (lsNext(cgen,&data,LS_NH) == LS_OK) { + fprintf(stream,".note%s\n",(char *) data); + } + lsFinish (cgen); + + n_dummy = n_internal = 0; + fputs(".inputs",stream); + astg_foreach_signal (stg,sgen,sig_p) { + if (sig_p->sig_type == ASTG_INPUT_SIG) { + fprintf(stream," %s",sig_p->name); + } + if (sig_p->sig_type == ASTG_INTERNAL_SIG) n_internal++; + if (sig_p->sig_type == ASTG_DUMMY_SIG) n_dummy++; + } + fputs("\n",stream); + + fputs(".outputs",stream); + astg_foreach_signal (stg,sgen,sig_p) { + if (sig_p->sig_type == ASTG_OUTPUT_SIG) { + fprintf(stream," %s",sig_p->name); + } + } + fputs("\n",stream); + + if (n_internal != 0) { + fputs(".internal",stream); + astg_foreach_signal (stg,sgen,sig_p) { + if (sig_p->sig_type == ASTG_INTERNAL_SIG) { + fprintf(stream," %s",sig_p->name); + } + } + fputs("\n",stream); + } + + if (n_dummy != 0) { + fputs(".dummy",stream); + astg_foreach_signal (stg,sgen,sig_p) { + if (sig_p->sig_type == ASTG_DUMMY_SIG) { + fprintf(stream," %s",sig_p->name); + } + } + fputs("\n",stream); + } + + fputs(".graph\n",stream); + astg_foreach_place (stg,pgen,p) { + if (hide_places && astg_boring_place(p)) continue; + fputs (astg_v_name(p),stream); + if (p->y != 0 || p->x != 0) { + fprintf(stream," (%s,%s)",trim_float(p->x,fbuf1),trim_float(p->y,fbuf2)); + } + astg_foreach_out_edge (p,egen,se) { + t = astg_head (se); + fputs(" ",stream); + fputs(astg_trans_name(t),stream); + if (se->guard_eqn != NULL) { + fprintf(stream," ?%s",se->guard_eqn); + } + } + fputs("\n",stream); + } + + astg_foreach_trans (stg,tgen,t) { + fputs (astg_trans_name(t),stream); + if (t->type.trans.delay != 0) { + fprintf(stream," %s",trim_float(t->type.trans.delay,fbuf1)); + } + if (t->y != 0 || t->x != 0) { + fprintf(stream," (%s,%s)",trim_float(t->x,fbuf1),trim_float(t->y,fbuf2)); + } + astg_foreach_output_place (t,pgen,p) { + if (hide_places && astg_boring_place(p)) { + fprintf(stream," %s",astg_v_name(p->out_edges->head)); + } + else { + fprintf(stream," %s",astg_v_name(p)); + } + } + fputs("\n",stream); + } + + if (stg->has_marking) { + fputs(".marking ",stream); + astg_write_marking (stg,stream); + } + + fputs(".end\n",stream); +} +#endif /* SIS */ diff --git a/sis/astg/astg_reduce.c b/sis/astg/astg_reduce.c new file mode 100644 index 0000000..d7c1ee0 --- /dev/null +++ b/sis/astg/astg_reduce.c @@ -0,0 +1,469 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/astg_reduce.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +/* -------------------------------------------------------------------- *\ + reduce.c -- generate net reductions + + Uses a brute force approach to enumerate all MG allocations. + Set of transitions with indegree > 1 are the key. + Product of all indegrees is upper bound on # SM components + But there can be duplicates if this is used as an exact number. + + Need to establish link from stg to smc and vice versa. And + also to find a better way to answer the 1-token SM restriction. + + References: + [CHU87] p. 50-51 Hack's reduction algorithms + p. 95 persistency/u.s.c. for each MG component + + Usage of vertex fields: + flag0: 0=in MG allocation, 1=not + flag1: 1=deleted during MG reduction, 0=not + flag2: 1=covered in some allocation, 0=not +\* ---------------------------------------------------------------------*/ + +#ifdef SIS +#include "astg_int.h" +#include "astg_core.h" + + +#define covered flag2 +#define dead flag1 +#define not_in_allocation flag0 + + +int astg_print_component (i,varray,stream) +int i; +array_t *varray; +FILE *stream; +{ + astg_vertex *v; + int n; + + fprintf (stream," %d)",i); + for (n=0; n < array_n(varray); n++) { + v = array_fetch (astg_vertex *, varray, n); + fprintf(stream," %s",astg_v_name(v)); + } + fputs("\n",stream); +} + +static array_t *get_key_vertices (stg,type,ubound) +astg_graph *stg; +int type; +int *ubound; +{ + astg_generator gen; + array_t *key_vertices; + astg_vertex *v; + astg_edge *e; + int degree; + + key_vertices = array_alloc (astg_vertex *, 0); + *ubound = 1; + + astg_foreach_vertex (stg,gen,v) { + if (v->vtype != type) continue; + degree = (type == ASTG_TRANS) ? astg_in_degree (v) : astg_out_degree (v); + if (degree < 2) continue; + *ubound *= degree; + array_insert_last (astg_vertex *, key_vertices, v); + if (type == ASTG_TRANS) { + astg_foreach_in_edge (v,gen,e) { + astg_tail(e)->not_in_allocation = ASTG_TRUE; + } + } + else { + astg_foreach_out_edge (v,gen,e) { + astg_head(e)->not_in_allocation = ASTG_TRUE; + } + } + } + + dbg(1,printf("bound of %d components\n",*ubound)); + return key_vertices; +} + +static int n_undead_fanin (v) +astg_vertex *v; +{ + astg_generator gen; + int rc = 0; + astg_edge *e; + + astg_foreach_in_edge (v,gen,e) + if (astg_tail(e)->dead == ASTG_FALSE) rc++; + return rc; +} + +static int n_undead_fanout (v) +astg_vertex *v; +{ + astg_generator gen; + int rc = 0; + astg_edge *e; + + astg_foreach_out_edge (v,gen,e) + if (astg_head(e)->dead == ASTG_FALSE) rc++; + return rc; +} + +static void del_mg_trans (stg,trans,depth) +astg_graph *stg; +astg_vertex *trans; +int depth; +{ + astg_edge *e1, *e2; + astg_vertex *place; + astg_generator gen1, gen2; + + if (trans == NULL || trans->dead) return; + if (++depth > 40) fail ("infinite loop"); + trans->dead = ASTG_TRUE; + + astg_foreach_out_edge (trans,gen1,e1) { + place = astg_head (e1); + if (place->dead) continue; + if (n_undead_fanin(place) == 0) { + astg_foreach_out_edge (place,gen2,e2) { + del_mg_trans (stg,astg_head(e2),depth); + } + place->dead = ASTG_TRUE; + } + } +} + +static void del_sm_place (stg,place,depth) +astg_graph *stg; +astg_vertex *place; +int depth; +{ + astg_generator gen1, gen2; + astg_edge *e1, *e2; + astg_vertex *trans; + + if (place == NULL || place->dead) return; + if (++depth > 40) fail ("infinite loop"); + place->dead = ASTG_TRUE; + + astg_foreach_in_edge (place,gen1,e1) { + trans = astg_tail (e1); + if (trans->dead) continue; + if (n_undead_fanout(trans) == 0) { + astg_foreach_in_edge (trans,gen2,e2) { + del_sm_place (stg,astg_tail(e2),depth); + } + trans->dead = ASTG_TRUE; + } + } +} + +static int cmp_vertex (obj1,obj2) +char *obj1, *obj2; +{ + astg_vertex *v1 = *((astg_vertex **) obj1); + astg_vertex *v2 = *((astg_vertex **) obj2); + + return (v2->weight1.i - v1->weight1.i); +} + +static int cmp_component (comp1,comp2) +array_t *comp1, *comp2; +{ + /* These are already in canonical form. */ + /* Only need equal/not equal test, no ordering. */ + int n = array_n(comp1); + + if (n != array_n(comp2)) return -1; + + while (n--) { + if ( array_fetch(astg_vertex *,comp1,n) != + array_fetch(astg_vertex *,comp2,n) ) return 1; + } + + /* These are equal. */ + return 0; +} + +static int g_type; +static int n_tried; + +static int add_component (cc,n,fdata) +array_t *cc; +int n; /* ARGSUSED */ +void *fdata; +{ + /* callback for astg_connected_comp. */ + array_t *component_array = (array_t *) fdata; + array_t *component; + astg_bool unique = ASTG_TRUE; + int i; + + /* Copy the component and make canonical. */ + component = array_dup (cc); + array_sort (component,cmp_vertex); + + if ((++n_tried%25000) == 0) + dbg(1,printf("checking component %d/%d\n",n_tried,array_n(component_array))); + + for (i=array_n(component_array); i--; ) { + if (!cmp_component(component,array_fetch(array_t *,component_array,i))) { + array_free (component); + unique = ASTG_FALSE; break; + } + } + + if (unique) { + dbg(3,astg_print_component(array_n(component_array),component,stdout)); + array_insert_last (array_t *, component_array, component); + } +} + +static void do_sm_reduce (stg,component_array) +astg_graph *stg; +array_t *component_array; +{ + astg_vertex *v; + astg_generator gen1, gen2; + astg_vertex *trans, *place; + astg_edge *e; + + astg_foreach_vertex (stg,gen1,v) v->dead = ASTG_FALSE; + + astg_foreach_vertex (stg,gen1,trans) { + if (trans->dead) continue; + astg_foreach_in_edge (trans,gen2,e) { + place = astg_tail (e); + if (place->dead) continue; + if (place->not_in_allocation) { + del_sm_place (stg,place,0); + } + } + } + + astg_foreach_vertex (stg,gen1,v) v->unprocessed = !v->dead; + g_type = ASTG_PLACE; + astg_connected_comp (stg,add_component,(void *)component_array,ASTG_SUBSET); +} + +static void do_mg_reduce (stg,component_array) +astg_graph *stg; +array_t *component_array; +{ + astg_vertex *v; + astg_generator gen1, gen2; + astg_vertex *place, *trans; + astg_edge *e; + + astg_foreach_vertex (stg,gen1,v) v->dead = ASTG_FALSE; + + astg_foreach_vertex (stg,gen1,place) { + if (place->dead) continue; + astg_foreach_out_edge (place,gen2,e) { + trans = astg_head (e); + if (trans->dead) continue; + if (trans->not_in_allocation) { + del_mg_trans (stg,trans,0); + } + } + } + + astg_foreach_vertex (stg,gen1,v) v->unprocessed = !v->dead; + g_type = ASTG_TRANS; + astg_connected_comp (stg,add_component,(void *)component_array,ASTG_SUBSET); +} + +static void gen_sm_allocation (stg,component_array,t,n) +astg_graph *stg; +array_t *component_array; +array_t *t; +int n; +{ + astg_vertex *trans, *place; + astg_generator gen; + astg_edge *e; + + if (n-- == 0) { + do_sm_reduce (stg,component_array); + } + else { + trans = array_fetch (astg_vertex *, t, n); + assert (trans->vtype == ASTG_TRANS); + astg_foreach_in_edge (trans,gen,e) { + place = astg_tail (e); + place->not_in_allocation = ASTG_FALSE; + gen_sm_allocation (stg,component_array,t,n); + place->not_in_allocation = ASTG_TRUE; + } + } +} + + +static void gen_mg_allocation (stg,component_array,t,n) +astg_graph *stg; +array_t *component_array; +array_t *t; +int n; +{ + astg_vertex *place, *trans; + astg_generator gen; + astg_edge *e; + + if (n-- == 0) { + do_mg_reduce (stg,component_array); + } + else { + place = array_fetch (astg_vertex *, t, n); + assert (place->vtype == ASTG_PLACE); + astg_foreach_out_edge (place,gen,e) { + trans = astg_head (e); + trans->not_in_allocation = ASTG_FALSE; + gen_mg_allocation (stg,component_array,t,n); + trans->not_in_allocation = ASTG_TRUE; + } + } +} + +static void find_reductions (stg,type) +astg_graph *stg; /*u graph to generate reductions for */ +int type; /*i ASTG_PLACE=MG red., ASTG_TRANS=SM red. */ +{ + array_t *b; + astg_vertex *v; + int ubound; + int n = 0; + astg_graph *g = stg; + astg_generator gen; + array_t *component_array; + + n_tried = 0; + /* Unique int ID used for sorting in add_component. */ + astg_foreach_vertex (g,gen,v) { + v->weight1.i = n++; + v->dead = ASTG_FALSE; + v->not_in_allocation = ASTG_FALSE; + } + + dbg(3,printf("generating %s components\n",type==ASTG_PLACE?"MG":"SM")); + component_array = array_alloc (array_t *,0); + b = get_key_vertices (g,type,&ubound); + if (type == ASTG_TRANS) { + gen_sm_allocation (g,component_array,b,array_n(b)); + stg->sm_comp = component_array; + } + else { + gen_mg_allocation (g,component_array,b,array_n(b)); + stg->mg_comp = component_array; + } + array_free (b); + + dbg(2,printf("%d %s components (%d maximum) in %s\n", + array_n(component_array),type==ASTG_TRANS?"SM":"MG",ubound,astg_name(stg))); +} + +static astg_retval check_reductions (stg,type,verbose) +astg_graph *stg; +int type; /* ASTG_TRANS=smc, ASTG_PLACE=mgc */ +astg_bool verbose; +{ + astg_retval status = ASTG_OK; + int i, j, n_bad = 0; + astg_vertex *v; + astg_graph *g = stg; + astg_generator gen; + array_t *component_array; + array_t *component; + + component_array = (type==ASTG_TRANS) ? stg->sm_comp : stg->mg_comp; + + astg_foreach_vertex (g,gen,v) { + v->covered = ASTG_FALSE; + } + + for (i=0; i < array_n(component_array); i++) { + component = array_fetch (array_t *,component_array,i); + /* Make sure the component is strongly connected. */ + astg_foreach_vertex (g,gen,v) v->subset = ASTG_FALSE; + /* Mark all vertices covered by some component. */ + for (j=0; j < array_n(component); j++) { + v = array_fetch (astg_vertex *,component,j); + v->covered = ASTG_TRUE; + v->subset = ASTG_TRUE; + } + if (astg_debug_flag >= 4) { + /* Print all components for debugging. */ + astg_print_component (i,array_fetch (array_t *,component_array,i),stdout); + } + if (astg_strong_comp (g,ASTG_NO_CALLBACK,ASTG_NO_DATA,ASTG_SUBSET) != 1) { + if (verbose && status == ASTG_OK) { + printf("warning: %s component(s)", + type==ASTG_TRANS?"state machine":"marked graph"); + } + if (verbose) printf(" %d",i+1); + status = ASTG_NOT_COVER; + n_bad++; + } + } + + if (verbose && n_bad != 0) { + printf(" %s not strongly connected.\n",(n_bad==1)?"is":"are"); + } + + /* Check if the components cover the net. */ + astg_sel_new (stg,"uncovered vertices",ASTG_FALSE); + astg_foreach_vertex (g,gen,v) { + if (!v->covered) { + status = ASTG_NOT_COVER; + astg_sel_vertex (v,ASTG_TRUE); + dbg(1,msg("warning: %s not covered by reductions\n",astg_v_name(v))); + } + } + + return status; +} + +astg_retval get_sm_comp (stg,verbose) +astg_graph *stg; +astg_bool verbose; +{ + long stg_count = astg_change_count (stg); + + if (stg_count != stg->smc_count) { + find_reductions (stg,ASTG_TRANS); + stg->smc_count = stg_count; + } + return check_reductions (stg,ASTG_TRANS,verbose); +} + +astg_retval get_mg_comp (stg,verbose) +astg_graph *stg; +astg_bool verbose; +{ + long stg_count = astg_change_count (stg); + + if (stg_count != stg->mgc_count) { + find_reductions (stg,ASTG_PLACE); + stg->mgc_count = stg_count; + } + return check_reductions (stg,ASTG_PLACE,verbose); +} + +void free_components (component_array) +array_t *component_array; +{ + int i; + + if (component_array != NULL) { + for (i=0; i < array_n(component_array); i++) { + array_free (array_fetch (array_t *,component_array,i)); + } + array_free (component_array); + } +} +#endif /* SIS */ diff --git a/sis/astg/bwd_code.c b/sis/astg/bwd_code.c new file mode 100644 index 0000000..b59870c --- /dev/null +++ b/sis/astg/bwd_code.c @@ -0,0 +1,3142 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/bwd_code.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +#ifdef SIS +/* Routines to enforce CSC in an ASTG + */ + +#include "sis.h" +#ifdef MDD +#include "mdd.h" +#endif +#include "astg_int.h" +#include "astg_core.h" +#include "bwd_int.h" + +#define TRANS_TYPE(c) (((c) == '0') ? ASTG_POS_X : ASTG_NEG_X) + +struct ptr_pair_struct { + char *p1, *p2; +}; +typedef struct ptr_pair_struct ptr_pair; + +/* Structure to store pairs of markings that must be distinguished inserting + * an appropriate state sig_p transition + */ +struct marking_pair_struct { + char * from_state; + /* array of astg_marking * */ + array_t *from_markings; + char * to_state; + /* array of astg_marking * */ + array_t *to_markings; +}; +typedef struct marking_pair_struct marking_pair_t; + +/* array of (marking_pair_t) */ +static array_t *marking_pairs; +/* array of (astg_signal *) */ +static array_t *partitioning_signals; + +/* from bin_mincov.c */ +extern int call_count; + +/* dummy signal for dummy transitions... */ +static astg_signal *dum_sig; +static int dum_i; + +/* symbol table with costs */ +static st_table *g_sig_cost; + +/* column selection in the binate covering formulation; first we put + * "nsig" signals, then we put the states + */ +#define POS_STATE(nsig,ncl,cl,st) (2 * ((nsig) + (ncl) * (st) + (cl))) +#define NEG_STATE(nsig,ncl,cl,st) (2 * ((nsig) + (ncl) * (st) + (cl)) + 1) +#define POS_SIG(sig) (2 * (sig)) +#define NEG_SIG(sig) (2 * (sig) + 1) + +static int +ptr_pair_cmp (key1, key2) +char *key1, *key2; +{ + int result; + ptr_pair *pair1, *pair2; + + pair1 = (ptr_pair *) key1; + pair2 = (ptr_pair *) key2; + result = st_ptrcmp (pair1->p1, pair2->p1); + if (result) { + return result; + } + result = st_ptrcmp (pair1->p2, pair2->p2); + return result; +} + +static int +ptr_pair_hash (key, modulus) +char *key; +int modulus; +{ + int result; + ptr_pair *pair; + + pair = (ptr_pair *) key; + result = st_ptrhash(pair->p1, modulus) ^ st_ptrhash(pair->p2, modulus); + return result % modulus; +} + +static void +constrain (str, astg, trans1, trans2) +char *str; +astg_graph *astg; +astg_trans *trans1, *trans2; +{ + static st_table *printed; + static astg_graph *curr_astg; + ptr_pair pair, *pairptr; + st_generator *stgen; + + if (astg_is_rel (trans1, trans2)) { + return; + } + + if (astg != curr_astg) { + if (printed != NIL(st_table)) { + st_foreach_item (printed, stgen, (char **) &pairptr, NIL(char *)) { + FREE (pairptr); + } + st_free_table (printed); + } + printed = st_init_table (ptr_pair_cmp, ptr_pair_hash); + curr_astg = astg; + } + + pair.p1 = (char *) trans1; + pair.p2 = (char *) trans2; + if (st_is_member (printed, (char *) &pair)) { + return; + } + + pairptr = ALLOC (ptr_pair, 1); + *pairptr = pair; + st_insert (printed, (char *) pairptr, NIL(char)); + + fprintf (siserr, "warning: %s: may need constraint %s -> %s\n", + str, astg_trans_name (trans1), astg_trans_name (trans2)); +} + +static int +signal_cost (sig_p, astg) +astg_signal *sig_p; +astg_graph *astg; +{ + int cost; + + if (g_sig_cost != NIL(st_table) && + st_lookup (g_sig_cost, astg_signal_name (sig_p), (char **) &cost)) { + return cost; + } + if (astg_signal_type (sig_p) == ASTG_INPUT_SIG) { + return MAX (100, 2 * astg->n_sig); + } + else { + return 1; + } +} + +static int +subset_cost (subset, astg) +astg_scode subset; +astg_graph *astg; +{ + int cost; + astg_generator gen; + astg_signal *sig_p; + + cost = 0; + astg_foreach_signal (astg, gen, sig_p) { + if (subset & bwd_astg_state_bit (sig_p)) { + cost += signal_cost (sig_p, astg); + } + } + return cost; +} + +static void +print_subset (subset, astg) +astg_scode subset; +astg_graph *astg; +{ + astg_generator gen; + astg_signal *sig_p; + + if (astg_debug_flag > 1) { + fprintf (sisout, " "); + astg_foreach_signal (astg, gen, sig_p) { + if (subset & bwd_astg_state_bit (sig_p)) { + fprintf (sisout, "1"); + } + else { + fprintf (sisout, "0"); + } + } + } + astg_foreach_signal (astg, gen, sig_p) { + if (subset & bwd_astg_state_bit (sig_p)) { + if (astg_signal_type (sig_p) == ASTG_INPUT_SIG) { + fprintf (sisout, " %s (i)", sig_p->name); + } + else if (astg_signal_type (sig_p) == ASTG_OUTPUT_SIG) { + fprintf (sisout, " %s (o)", sig_p->name); + } + else if (astg_signal_type (sig_p) == ASTG_INTERNAL_SIG) { + fprintf (sisout, " %s (x)", sig_p->name); + } + } + } + if (astg_debug_flag > 0) { + fprintf (sisout, " (cost %d)", subset_cost (subset, astg)); + } + fprintf (sisout, "\n"); +} + +static void +equiv_free (equiv_states) +equiv_t *equiv_states; +{ + array_free (equiv_states->index_state); + equiv_states->index_state = NIL(array_t); + st_free_table (equiv_states->state_index); + equiv_states->state_index = NIL(st_table); + sf_free (equiv_states->classes); + equiv_states->classes = NIL(set_family_t); +} + +static equiv_t * +equiv_alloc (nstates, nclasses) +int nstates, nclasses; +{ + equiv_t *equiv_states; + pset p, last; + + equiv_states = ALLOC (equiv_t, 1); + equiv_states->index_state = array_alloc (vertex_t *, nstates); + equiv_states->state_index = st_init_table_with_params (st_ptrcmp, + st_ptrhash, ST_DEFAULT_INIT_TABLE_SIZE, /* density */ 1, + ST_DEFAULT_GROW_FACTOR, ST_DEFAULT_REORDER_FLAG); + equiv_states->classes = sf_new (nclasses, nstates); + equiv_states->classes->count = nclasses; + foreach_set (equiv_states->classes, last, p) { + set_clear (p, nstates); + } + return equiv_states; +} + +equiv_t * +bwd_read_equiv_states (file, stg) +FILE *file; +graph_t *stg; +{ + char buf[256], name[256], *str; + int class, n, nclasses, idx, i, j, len; + equiv_t *equiv_states; + pset p; + int nstates; + vertex_t *state; + array_t *names; + + if (global_orig_stg_names == NIL(st_table) || + global_orig_stg == NIL(graph_t)) { + fprintf (siserr, "no state transition graph (use astg_to_stg)\n"); + return NIL(equiv_t); + } + + nstates = stg_get_num_states(global_orig_stg); + + nclasses = -1; + while (fgets (buf, (sizeof(buf)/sizeof(char)), file) != NULL) { + if (sscanf (buf, "#begin_classes %d", &nclasses) == 1) { + break; + } + } + if (nclasses < 0) { + fprintf (siserr, "no class information in minimizer output\n"); + return NIL(equiv_t); + } + + equiv_states = equiv_alloc (nstates, nclasses); + idx = 0; + while (fgets (buf, (sizeof(buf)/sizeof(char)), file) != NULL) { + if (! strcmp (buf, "#end_classes\n")) { + break; + } + n = sscanf (buf, "# %s %d", name, &class); + if (n != 2) { + fprintf (siserr, + "invalid class information in minimizer output:\n%s\n", buf); + equiv_free (equiv_states); + return NIL(equiv_t); + } + if (! st_lookup (global_orig_stg_names, (char *) name, + (char **) &names)) { + fprintf (siserr, + "invalid class information in minimizer output:\n%s\n", buf); + equiv_free (equiv_states); + return NIL(equiv_t); + } + for (j = 0; j < array_n (names); j++) { + state = bwd_get_state_by_name (global_orig_stg, + array_fetch (char *, names, j)); + if (! st_lookup (equiv_states->state_index, (char *) state, + (char **) &i)) { + st_insert (equiv_states->state_index, (char *) state, + (char *) idx); + array_insert (vertex_t *, equiv_states->index_state, idx, + state); + i = idx++; + } + set_insert (GETSET (equiv_states->classes, class), i); + } + } + if (idx != nstates) { + fprintf (siserr, + "not enough states in class information in minimizer output (%d vs. %d)\n", + idx, nstates); + equiv_free (equiv_states); + return NIL(equiv_t); + } + + if (astg_debug_flag > 1) { + fprintf (sisout, "Equivalence classes:\n"); + foreachi_set (equiv_states->classes, i, p) { + fprintf (sisout, "%2d ", i); + len = 3; + for (j = 0; j < array_n (equiv_states->index_state); j++) { + if (is_in_set (p, j)) { + state = array_fetch (vertex_t *, + equiv_states->index_state, j); + str = stg_get_state_name (state); + len += strlen (str) + 1; + if (len >= 80) { + fprintf (sisout, "\n "); + len = 3 + strlen (str) + 1; + } + fprintf (sisout, "%s ", str); + } + } + fprintf (sisout, "\n"); + } + } + + return equiv_states; +} + +static int +same_class (classes, st1, st2) +pset_family classes; +int st1, st2; +{ + pset last, class; + + foreach_set (classes, last, class) { + if (is_in_set (class, st1) && is_in_set (class, st2)) { + return 1; + } + } + + return 0; +} + +/* Test if all the signals that are enabled in state2 and not in state1 + * are in subset (so that subset "distinguishes" among them). + */ +static int +distinguishable (edge, subset, edge_trans, state_marking) +edge_t *edge; +astg_scode subset; +st_table *edge_trans, *state_marking; +{ + astg_scode new_enabled; + + new_enabled = bwd_new_enabled_signals (edge, edge_trans, state_marking); + if (new_enabled == 0 || (subset & new_enabled) != new_enabled) { + return 0; + } + + return 1; +} + +#ifdef MDD +/* FROM YOSINORI WATANABE + * br_dfs_bdd() recursively performs a depth first search over nodes + * in BDD 'f' and assigns post_visit numbers for all the nodes except + * 0 terminal nodes. The post_visit number is a number assigned to a + * node after all of its children have been visited. The number + * starts with 'start_num'. Once a node that is not a 0 terminal is + * assigned a post_visit number, then the number is set in a hash_table + * 'id_table' with key as the pointer to the node. Also, the pointer + * to the node is stored in a hash_table 'order' with key as its post_ + * visit number. *total_num_ptr is returned as the number of the + * nodes in f except the 0 terminal nodes plus start_num. + */ +static void +br_dfs_bdd(mg, f, id_table, order, start_num, total_num_ptr) +bdd_manager *mg; +bdd_node *f; +st_table *id_table, *order; +int start_num, *total_num_ptr; +{ + int total; + bdd_node *v0, *v1; + bdd_node *b0, *b1; + + b0 = BDD_ZERO(mg); b1 = BDD_ONE(mg); + if(st_is_member(id_table, (char *)f)){ + *total_num_ptr = start_num; + return; + } + if(f == b0){ + *total_num_ptr = start_num; + return; + } + if(f == b1){ + (void)st_insert(id_table, (char *)f, (char *)start_num); + (void)st_insert(order, (char *)start_num, (char *)f); + *total_num_ptr = start_num + 1; + return; + } + + bdd_get_branches(f, &v1, &v0); + + br_dfs_bdd(mg, v1, id_table, order, start_num, &total); + + start_num = total; + br_dfs_bdd(mg, v0, id_table, order, start_num, &total); + + /* The post_cisit number of f is total */ + (void)st_insert(id_table, (char *)f, (char *)total); + (void)st_insert(order, (char *)total, (char *)f); + *total_num_ptr = total + 1; + + return; +} + +/* FROM YOSINORI WATANABE + * br_shortestpath() finds the shortest path in a BDD f that + * ends with a 1 terminal, where an edge has a weight 'wtt' if it + * is a then edge and has a weight 'wte' if it is an else edge. + * This routine does not check if f is NIL or is a constant + * terminal BDD. This routine should not be used for these + * cases. + */ +static st_table * +br_shortestpath(f, wtt_table, wte_table) +bdd_t *f; +st_table *wtt_table, *wte_table; +{ + st_table *id_table, *order, *visited; + int num_nodes, t_num, i, k; + int *length, *phase, *terminal; + int wtt, wte; + bdd_node **parent, *v, *w0, *w1; + bdd_node *b0, *b1; + char *value, *id; + int best_length, path_len, best_i; + bdd_manager *mg; + st_table *result; + + mg = f->bdd; + b0 = BDD_ZERO(mg); b1 = BDD_ONE(mg); + + if(f->node == b0){ + return NIL(st_table); + } + else if(f->node == b1){ + return NIL(st_table); + } + /* id_table contains a post_visit number of the top node of + * BDD 'g' with g as a key. + */ + id_table = st_init_table(st_ptrcmp, st_ptrhash); + /* order contains a BDD 'g' with the post_visit number of the + * top node of g in the depth first search of BDD 'f'. + */ + order = st_init_table(st_numcmp, st_numhash); + + br_dfs_bdd(mg, f->node, id_table, order, 0, &num_nodes); + + /* num_nodes is the number of nodes visited in the dfs. */ + length = ALLOC(int, num_nodes); + parent = ALLOC(bdd_node *, num_nodes); + phase = ALLOC(int, num_nodes); + terminal = ALLOC(int, num_nodes); + visited = st_init_table(st_ptrcmp, st_ptrhash); + + /* length[i] gives the length of the shortest path of the + * BDD node with the post_visit number i from the top node of f. + * parent[i] gives the parent BDD of the BDD node with + * the post_visit number i in the path. phase[i] is 1 if the + * BDD node with id = i is a then child of parent[i] and + * 0 if an else child. terminal is an array of post_visit number + * of BDDs of 1 terminal nodes in f. + */ + for(i=0; i=0; i--){ + (void)st_lookup(order, (char *)i, &value); + v = (bdd_node *)value; + + /* Skip if v is a leaf. */ + if((v == b0) || (v == b1)) continue; + + bdd_get_branches(v, &w1, &w0); + + /* Labeling the then child */ + if(w1 != b0){ /* Skip if w is 0 terminal. */ + (void)st_lookup(id_table, (char *)w1, &id); + if (! st_lookup(wtt_table, (char *)w1->id, (char **)&wtt)) { + wtt = 0; + } + k = (int)id; + if(length[k] > (wtt+length[i])){ + length[k] = wtt+length[i]; + parent[k] = v; + phase[k] = 1; + } + if((w1 == b1) && (!st_is_member(visited, (char *)w1))){ + (void)st_insert(visited, (char *)w1, (char *)k); + terminal[t_num++] = k; + } + } + + /* Labeling the else child */ + if(w0 != b0){ + (void)st_lookup(id_table, (char *)w0, &id); + if (wte_table == NIL(st_table) || + ! st_lookup(wte_table, (char *)w0->id, (char **)&wte)) { + wte = 0; + } + k = (int)id; + if(length[k] > (wte+length[i])){ + length[k] = wte + length[i]; + parent[k] = v; + phase[k] = 0; + } + if((w0 == b1) && (!st_is_member(visited, (char *)w0))){ + (void)st_insert(visited, (char *)w0, (char *)k); + terminal[t_num++] = k; + } + } + } + + /* Look for the terminal with the shortest path */ + best_length = 99999; + for(i=0; i path_len){ + best_length = path_len; + best_i = terminal[i]; + } + } + (void)st_lookup(order, (char *)best_i, &value); + v = (bdd_node *)value; + k = best_i; + + /* setup brpt_t * data structure. */ + result = st_init_table (st_ptrcmp, st_ptrhash); + while(parent[k] != NIL(bdd_node)){ + if(v != b1) { + st_insert (result, (char *) v->id, (char *) phase[k]); + } + v = parent[k]; + (void)st_lookup(id_table, (char *)v, &id); + k = (int)id; + } + + /* cleanup */ + FREE(length); FREE(phase); FREE(terminal); FREE(parent); + st_free_table(id_table); st_free_table(order); + st_free_table(visited); + + return result; +} + +/* Find a shortest path from the root to the "1" leaf on the MDD, using sig_p + * cost as weight. Use Yosinori's function for the shortest path computation. + */ + +static astg_scode +mdd_subset (mgr, mdd, sig_mdd_var, wtt_table) +mdd_manager *mgr; +mdd_t *mdd; +st_table *sig_mdd_var, *wtt_table; +{ + st_table *var_phase; + int phase; + astg_scode subset; + bdd_t *lit; + st_generator *stgen; + astg_signal *sig_p; + + var_phase = br_shortestpath(mdd, wtt_table, NIL(st_table)); + + subset = 0; + st_foreach_item (sig_mdd_var, stgen, (char **) &sig_p, (char **) &lit) { + if (! st_lookup (var_phase, (char *) lit->node->id, + (char **) &phase)) { + continue; + } + if (phase) { + subset |= bwd_astg_state_bit (sig_p); + } + } + + st_free_table (var_phase); + + return subset; +} +#endif + +/* Return a set of signals in the ASTG sufficient to partition the state graph + * so that each partition includes only states belonging only to one STG + * equivalence class. + */ +static astg_scode +find_partitioning_signals (astg, stg, equiv_states, index_sig, visited, mincov_option, use_mdd, edge_trans, state_marking) +astg_graph *astg; +graph_t *stg; +equiv_t *equiv_states; +array_t *index_sig; +pset visited; +int mincov_option, use_mdd; +st_table *edge_trans, *state_marking; +{ + int cl1, cl2, s1, s2, i, row, found, count; + int nclasses, nsig, nstates; + int mincov_debug = 0; + astg_scode subset, new_enabled; + lsGen gen; + astg_generator sgen; + vertex_t *state1, *state2; + edge_t *edge; + pset class1, class2, single_class; + sm_matrix *M; + sm_row *cover; + sm_element *el; + astg_signal *sig_p; + int *weight; +#ifdef MDD + int v; + array_t *mvar_sizes, *values; + st_table *state_mdd_var, *wtt_table, *sig_mdd_var; + st_generator *stgen; + mdd_manager *mgr; + mdd_t *mdd, *mdd1, *lit1, *lit2, *lit3; +#endif + + call_count = 0; + nclasses = equiv_states->classes->count; + nstates = array_n (equiv_states->index_state); + nsig = array_n (index_sig); + single_class = set_new (nstates); + if (use_mdd) { +#ifdef MDD + state_mdd_var = st_init_table (st_ptrcmp, st_ptrhash); + wtt_table = st_init_table (st_ptrcmp, st_ptrhash); + mvar_sizes = array_alloc (int, 0); + sig_mdd_var = st_init_table (st_ptrcmp, st_ptrhash); +#else + fail ("MDD's not supported\n"); +#endif + } + else { + M = sm_alloc (); + } + + for (s1 = 0; s1 < nstates; s1++) { + count = 0; + foreachi_set (equiv_states->classes, cl1, class1) { + if (is_in_set (class1, s1)) { + count++; + } + } + if (count == 1) { + set_insert (single_class, s1); + } + } + + /* for each state create a set of rows stating that it must be in one + * and only one class: + * for each state + * create a row with all its classes in the positive phase + * for each class to which it does not belong + * create a row with the class in the negative phase + * for each pair of classes to which it belongs + * create a row with the classes in the negative phase + */ + for (s1 = 0; s1 < nstates; s1++) { + state1 = array_fetch (vertex_t *, equiv_states->index_state, s1); + if (is_in_set (single_class, s1)) { + found = 0; + foreach_state_outedge (state1, gen, edge) { + state2 = stg_edge_to_state (edge); + if (state1 == state2) { + continue; + } + assert (st_lookup (equiv_states->state_index, (char *) state2, (char **) &s2)); + if (! is_in_set (single_class, s2) || + ! same_class (equiv_states->classes, s1, s2)) { + found = 1; + lsFinish (gen); + break; + } + } + if (! found) { + foreach_state_inedge (state1, gen, edge) { + state2 = stg_edge_from_state (edge); + if (state1 == state2) { + continue; + } + assert (st_lookup (equiv_states->state_index, (char *) state2, (char **) &s2)); + if (! is_in_set (single_class, s2) || + ! same_class (equiv_states->classes, s1, s2)) { + found = 1; + lsFinish (gen); + break; + } + } + } + + if (! found) { + if (astg_debug_flag > 4) { + fprintf (sisout, "skipping %s\n", + stg_get_state_name (state1)); + } + continue; + } + } + if (use_mdd) { +#ifdef MDD + assert (! st_insert (state_mdd_var, (char *) state1, (char *) array_n (mvar_sizes))); + array_insert_last (int, mvar_sizes, nclasses); +#endif + } + else { + row = M->nrows; + if (astg_debug_flag > 3) { + fprintf (sisout, " %d:", row); + } + foreachi_set (equiv_states->classes, cl1, class1) { + if (is_in_set (class1, s1)) { + sm_insert (M, row, POS_STATE (nsig, nclasses, cl1, s1)); + if (astg_debug_flag > 3) { + fprintf (sisout, " ( %s %d )", + stg_get_state_name (state1), cl1); + } + } + } + if (astg_debug_flag > 3) { + fprintf (sisout, "\n"); + } + foreachi_set (equiv_states->classes, cl1, class1) { + if (is_in_set (class1, s1)) { + for (cl2 = cl1 + 1; cl2 < nclasses; cl2++) { + class2 = GETSET (equiv_states->classes, cl2); + if (! is_in_set (class2, s1)) { + continue; + } + row = M->nrows; + sm_insert (M, row, NEG_STATE (nsig, nclasses, cl1, s1)); + sm_insert (M, row, NEG_STATE (nsig, nclasses, cl2, s1)); + if (astg_debug_flag > 3) { + fprintf (sisout, " %d: ! ( %s %d ) ! ( %s %d )\n", + row, stg_get_state_name (state1), cl1, + stg_get_state_name (state1), cl2); + } + } + } + else { + row = M->nrows; + sm_insert (M, row, NEG_STATE (nsig, nclasses, cl1, s1)); + if (astg_debug_flag > 3) { + fprintf (sisout, " %d: ! ( %s %d )\n", row, + stg_get_state_name (state1), cl1); + } + } + } + } + } + + /* assert the range of values for each variable */ + if (use_mdd) { +#ifdef MDD + /* we should really do something smarter for variable ordering... */ + mgr = mdd_init (mvar_sizes); + array_free (mvar_sizes); + + mdd = bdd_one (mgr); + + st_foreach_item (state_mdd_var, stgen, (char **) &state1, + (char **) &v) { + values = array_alloc (int, 0); + assert (st_lookup (equiv_states->state_index, (char *) state1, (char **) &s1)); + foreachi_set (equiv_states->classes, cl1, class1) { + if (is_in_set (class1, s1)) { + array_insert_last (int, values, cl1); + } + } + lit1 = mdd_literal (mgr, v, values); + array_free (values); + + mdd = mdd_and (mdd, lit1, 1, 1); + } + + astg_foreach_signal (astg, sgen, sig_p) { + lit1 = bdd_create_variable (mgr); + st_insert (sig_mdd_var, (char *) sig_p, (char *) lit1); + st_insert (wtt_table, (char *) lit1->node->id, (char *) + signal_cost (sig_p, astg)); + } +#endif + } + + /* for each pair of states that are adjacent and may not be in the same + * class (i.e. with the exception of a pair of states that belong to only + * one class, and this happens to be the same class), create a set of rows + * stating that they must be distinguishable: + * for each edge such that the states may be in a different class + * for each class to which from may belong + * if there exists a distinguishing set + * for each sig_p distinguishing the edge + * create a row with the negative phase of from and class, + * the positive phase of to and class, the sig_p + * else + * create a row with the negative phase of from and class, + * the positive phase of to + */ + + stg_foreach_transition (stg, gen, edge) { + state1 = stg_edge_from_state (edge); + state2 = stg_edge_to_state (edge); + if (state1 == state2) { + continue; + } + assert (st_lookup (equiv_states->state_index, (char *) state1, (char **) &s1)); + assert (st_lookup (equiv_states->state_index, (char *) state2, (char **) &s2)); + if (is_in_set (single_class, s1) && is_in_set (single_class, s2) && + same_class (equiv_states->classes, s1, s2)) { + continue; + } + + new_enabled = bwd_new_enabled_signals (edge, edge_trans, state_marking); + foreachi_set (equiv_states->classes, cl1, class1) { + if (! is_in_set (class1, s1)) { + continue; + } + + if (new_enabled) { + astg_foreach_signal (astg, sgen, sig_p) { + if (! (new_enabled & bwd_astg_state_bit (sig_p))) { + continue; + } + i = bwd_log2 (bwd_astg_state_bit (sig_p)); + /* we should use mdd_eq here !!!!!!! */ + if (use_mdd) { +#ifdef MDD + assert (st_lookup (state_mdd_var, (char *) state1, (char **) &v)); + values = array_alloc (int, 0); + array_insert_last (int, values, cl1); + lit1 = mdd_literal (mgr, v, values); + array_free (values); + + assert (st_lookup (state_mdd_var, (char *) state2, (char **) &v)); + values = array_alloc (int, 0); + array_insert_last (int, values, cl1); + lit2 = mdd_literal (mgr, v, values); + array_free (values); + + mdd1 = bdd_or (lit1, lit2, 0, 1); + assert (st_lookup (sig_mdd_var, (char *) sig_p, (char **) &lit3)); + mdd1 = bdd_or (mdd1, lit3, 1, 1); + mdd = mdd_and (mdd, mdd1, 1, 1); +#endif + } + else { + row = M->nrows; + sm_insert (M, row, NEG_STATE (nsig, nclasses, cl1, s1)); + sm_insert (M, row, POS_STATE (nsig, nclasses, cl1, s2)); + sm_insert (M, row, POS_SIG (i)); + if (astg_debug_flag > 3) { + sig_p = array_fetch (astg_signal *, index_sig, i); + fprintf (sisout, " %d: ! ( %s %d ) ( %s %d ) %s\n", + row, stg_get_state_name (state1), cl1, + stg_get_state_name (state2), cl1, + sig_p->name); + } + } + } + } + else { + if (use_mdd) { +#ifdef MDD + assert (st_lookup (state_mdd_var, (char *) state1, (char **) &v)); + values = array_alloc (int, 0); + array_insert_last (int, values, cl1); + lit1 = mdd_literal (mgr, v, values); + array_free (values); + + assert (st_lookup (state_mdd_var, (char *) state2, (char **) &v)); + values = array_alloc (int, 0); + array_insert_last (int, values, cl1); + lit2 = mdd_literal (mgr, v, values); + array_free (values); + + mdd1 = bdd_or (lit1, lit2, 0, 1); + mdd = mdd_and (mdd, mdd1, 1, 1); +#endif + } + else { + row = M->nrows; + sm_insert (M, row, NEG_STATE (nsig, nclasses, cl1, s1)); + sm_insert (M, row, POS_STATE (nsig, nclasses, cl1, s2)); + if (astg_debug_flag > 3) { + fprintf (sisout, " %d: ! ( %s %d ) ( %s %d )\n", row, + stg_get_state_name (state1), cl1, + stg_get_state_name (state2), cl1); + } + } + } + } + } + + if (use_mdd) { +#ifdef MDD + if (astg_debug_flag > 1) { + fprintf (sisout, "bdd size: %d\n", mdd_size (mdd)); + } + subset = mdd_subset (mgr, mdd, sig_mdd_var, wtt_table); + mdd_quit (mgr); + st_free_table (sig_mdd_var); + st_free_table (state_mdd_var); + st_free_table (wtt_table); +#endif + } + else { + if (M->last_col == NIL(sm_col)) { + fprintf (siserr, "empty matrix ???\n"); + subset = 0; + return subset; + } + + weight = ALLOC (int, M->last_col->col_num + 1); + for (i = 0; i < M->last_col->col_num + 1; i++) { + weight[i] = 0; + } + astg_foreach_signal (astg, sgen, sig_p) { + weight[POS_SIG (bwd_log2 (bwd_astg_state_bit (sig_p)))] = + signal_cost (sig_p, astg); + } + + sm_row_dominance (M); + if (astg_debug_flag > 2) { + mincov_debug = 1; + } + + cover = sm_mat_bin_minimum_cover (M, weight, /* heuristic */ 0, + mincov_debug, /* ubound */ 0, /* option */ mincov_option, + /* record_fun */ (int(*)()) 0); + + subset = 0; + sm_foreach_row_element (cover, el) { + if (el->col_num >= 2 * array_n (index_sig) || el->col_num % 2) { + continue; + } + subset |= 1 << (el->col_num / 2); + } + + sm_row_free (cover); + sm_free (M); + } + set_free (single_class); + + return subset; +} + + +static int +is_forbidden (cur_trans_sets, edge_trans, edge) +st_table *cur_trans_sets, *edge_trans; +edge_t *edge; +{ + array_t *trans_arr; + int i; + astg_trans *trans; + + assert (st_lookup (edge_trans, (char *) edge, (char **) &trans_arr)); + for (i = 0; i < array_n (trans_arr); i++) { + trans = array_fetch (astg_trans *, trans_arr, i); + if (st_is_member (cur_trans_sets, (char *) trans)) { + return 1; + } + } + return 0; +} + +/* return 1 if something changed */ +static int +closure (stg, allowed_partitions, equiv_states, trans_comb, edge_trans) +graph_t *stg; +array_t *allowed_partitions; +equiv_t *equiv_states; +array_t *trans_comb; +st_table *edge_trans; +{ + lsGen gen; + edge_t *edge; + vertex_t *from, *to; + pset intersection, class, part; + int s, e, cl, changed, result, j; + char *input; + array_t *edges; + st_generator *stgen; + st_table *in_to_edges, *cur_trans_sets; + astg_trans *trans; + + intersection = set_new (equiv_states->classes->count); + + /* create a symbol table with all edges with the same label */ + in_to_edges = st_init_table (strcmp, st_strhash); + stg_foreach_transition (stg, gen, edge) { + if (stg_edge_from_state (edge) == stg_edge_to_state (edge)) { + continue; + } + input = stg_edge_input_string (edge); + if (! st_lookup (in_to_edges, (char *) input, (char **) &edges)) { + edges = array_alloc (edge_t *, 0); + st_insert (in_to_edges, (char *) input, (char *) edges); + } + array_insert_last (edge_t *, edges, edge); + } + result = 0; + + do { + changed = 0; + + /* for each set of excluded transitions */ + for (j = 0; j < array_n (trans_comb); j++) { + cur_trans_sets = array_fetch (st_table *, trans_comb, j); + if (astg_debug_flag > 2 && st_count (cur_trans_sets)) { + fprintf (sisout, "excluding transitions"); + st_foreach_item (cur_trans_sets, stgen, (char **) &trans, + NIL(char *)) { + fprintf (sisout, " %s", astg_trans_name (trans)); + } + fprintf (sisout, "\n"); + } + + /* for each input label, for each class, for each from_state in + * this class with this label, intersect the allowed next states + */ + st_foreach_item (in_to_edges, stgen, (char **) &input, + (char **) &edges) { + if (astg_debug_flag > 3) { + fprintf (sisout, "examining input %s\n", input); + } + foreachi_set (equiv_states->classes, cl, class) { + if (astg_debug_flag > 3) { + fprintf (sisout, "examining class %d\n", cl); + } + set_fill (intersection, equiv_states->classes->count); + for (e = 0; e < array_n (edges); e++) { + edge = array_fetch (edge_t *, edges, e); + /* check if associated with the forbidden transitions */ + if (is_forbidden (cur_trans_sets, edge_trans, edge)) { + continue; + } + + /* check if the "from" state is in this class */ + from = stg_edge_from_state (edge); + assert (st_lookup (equiv_states->state_index, (char *) from, (char **) &s)); + if (! is_in_set (class, s)) { + continue; + } + + /* intersect the classes of the "to" states */ + to = stg_edge_to_state (edge); + assert (st_lookup (equiv_states->state_index, (char *) to, (char **) &s)); + part = array_fetch (pset, allowed_partitions, s); + set_and (intersection, intersection, part); + if (astg_debug_flag > 3) { + fprintf (sisout, "%s -> %s part %s ", + stg_get_state_name (from), + stg_get_state_name (to), ps1(part)); + fprintf (sisout, "intersection %s\n", + ps1(intersection)); + } + } + + /* now put the information back */ + for (e = 0; e < array_n (edges); e++) { + edge = array_fetch (edge_t *, edges, e); + /* check if associated with the forbidden transitions */ + if (is_forbidden (cur_trans_sets, edge_trans, edge)) { + continue; + } + + /* check if the "from" state is in this class */ + from = stg_edge_from_state (edge); + assert (st_lookup (equiv_states->state_index, (char *) from, (char **) &s)); + if (! is_in_set (class, s)) { + continue; + } + + /* copy the classes of the "to" states */ + to = stg_edge_to_state (edge); + assert (st_lookup (equiv_states->state_index, (char *) to, (char **) &s)); + part = array_fetch (pset, allowed_partitions, s); + if (! setp_equal (part, intersection)) { + set_copy (part, intersection); + changed = 1; + result = 1; + if (astg_debug_flag > 3) { + fprintf (sisout, "%s updated part %s\n", + stg_get_state_name (to), ps1(part)); + } + } + } + } + } + } + } while (changed); + + st_foreach_item (in_to_edges, stgen, (char **) &input, + (char **) &edges) { + array_free (edges); + } + st_free_table (in_to_edges); + + return result; +} + +static int * +choose_class (stg, allowed_partitions, equiv_states, orig_stg_names) +graph_t *stg; +array_t *allowed_partitions; +equiv_t *equiv_states; +st_table *orig_stg_names; +{ + int *index_part; + vertex_t *state; + pset intersection, part; + int s, s1, idx, cl, nstates; + char *str; + array_t *names; + st_generator *stgen; + + intersection = set_new (equiv_states->classes->count); + nstates = array_n (equiv_states->index_state); + + /* put all "forced" merges together */ + index_part = ALLOC (int, nstates); + for (s = 0; s < nstates; s++) { + index_part[s] = -1; + } + st_foreach_item (orig_stg_names, stgen, (char **) &str, + (char **) &names) { + if (astg_debug_flag > 3) { + fprintf (sisout, "considering the group %s\n", str); + } + set_fill (intersection, equiv_states->classes->count); + for (s = 0; s < array_n (names); s++) { + state = bwd_get_state_by_name (stg, array_fetch (char *, names, s)); + assert (st_lookup (equiv_states->state_index, (char *) state, (char **) &s1)); + part = array_fetch (pset, allowed_partitions, s1); + set_and (intersection, intersection, part); + + if (astg_debug_flag > 3) { + fprintf (sisout, "%s part %s ", + stg_get_state_name (state), ps1(part)); + fprintf (sisout, "intersection %s\n", ps1(intersection)); + } + + if (set_ord (intersection) == 0) { + if (astg_debug_flag > 2) { + fprintf (sisout, "aborting due to state %s\n", + stg_get_state_name (state)); + } + set_free (intersection); + FREE (index_part); + return NIL(int); + } + } + + for (s = 0; s < array_n (names); s++) { + state = bwd_get_state_by_name (stg, array_fetch (char *, names, s)); + if (astg_debug_flag > 2) { + if (set_ord (intersection) > 1) { + fprintf (sisout, "multiple choice for %s:", + stg_get_state_name (state)); + for (cl = 0; cl < equiv_states->classes->count; cl++) { + if (is_in_set (intersection, cl)) { + fprintf (sisout, " %d", cl); + } + } + fprintf (sisout, "\n"); + } + } + + for (cl = 0; cl < equiv_states->classes->count; cl++) { + if (is_in_set (intersection, cl)) { + if (astg_debug_flag > 2) { + fprintf (sisout, "inserting %s in partition %d\n", + stg_get_state_name (state), cl); + } + assert (st_lookup (equiv_states->state_index, (char *) state, (char **) &idx)); + index_part[idx] = cl; + break; + } + } + } + } + + set_free (intersection); + return index_part; +} + +/* Check if state1 is in this class. Otherwise move from state1 forward + * in the STG stopping as soon as one selected sig_p is traversed. + * If doing so no other class is met, then state1 belongs to this class. + * Returns 1 if state 1 is assigned to this class, 0 otherwise. + */ +static int +check_this_partition_recur (state1, cl, equiv_states, subset, visited, allowed_partitions, forward, rm, edge_trans, state_marking) +vertex_t *state1; +int cl; +equiv_t *equiv_states; +astg_scode subset; +pset visited; +array_t *allowed_partitions; +int forward, rm; +st_table *edge_trans, *state_marking; +{ + int st1, st2, result; + lsGen gen; + edge_t *edge; + vertex_t *state2; + pset part1; + + assert (st_lookup (equiv_states->state_index, (char *) state1, (char **) &st1)); + /* check if we can belong to this partition at all */ + part1 = array_fetch (pset, allowed_partitions, st1); + if (! rm && ! is_in_set (part1, cl)) { + return 0; + } + + /* now proceed to check recursively the fanout of state1 */ + set_insert (visited, st1); + result = 1; + for (gen=lsStart(forward?g_get_out_edges(state1):g_get_in_edges(state1)); + lsNext(gen,(lsGeneric*)&edge,LS_NH)==LS_OK||((void)lsFinish(gen),0);) { + state2 = stg_edge_to_state (edge); + if (state2 == state1) { + continue; + } + + assert (st_lookup (equiv_states->state_index, (char *) state2, (char **) &st2)); + if (is_in_set (visited, st2)) { + continue; + } + + if (! distinguishable (edge, subset, edge_trans, state_marking)) { + /* if the two cannot be distinguished, then st1 is in this class + * only if st2 is, so first check if st2 is in this class... + */ + if (! check_this_partition_recur (state2, cl, equiv_states, + subset, visited, allowed_partitions, forward, + rm, edge_trans, state_marking) && + is_in_set (part1, cl)) { + if (astg_debug_flag > 3) { + fprintf (sisout, "Removing %d from %s due to %s\n", + cl, stg_get_state_name (state1), + stg_get_state_name (state2)); + } + set_remove (part1, cl); + result = 0; + } + } + } + + if (rm && is_in_set (part1, cl)) { + if (astg_debug_flag > 3) { + fprintf (sisout, "Removing %d from %s\n", + cl, stg_get_state_name (state1)); + } + set_remove (part1, cl); + } + return result; +} + +static int +check_this_partition (state1, cl, equiv_states, subset, visited, allowed_partitions, rm, edge_trans, state_marking) +vertex_t *state1; +int cl; +equiv_t *equiv_states; +astg_scode subset; +pset visited; +array_t *allowed_partitions; +int rm; +st_table *edge_trans, *state_marking; +{ + int result; + + set_clear (visited, array_n (equiv_states->index_state)); + result = check_this_partition_recur (state1, cl, equiv_states, subset, + visited, allowed_partitions, /* forward */ 1, rm, edge_trans, + state_marking); + if (rm || ! result) { + set_clear (visited, array_n (equiv_states->index_state)); + result |= check_this_partition_recur (state1, cl, equiv_states, subset, + visited, allowed_partitions, /* forward */ 1, rm, edge_trans, + state_marking); + } + + return result; +} + +/* Check if subset performs a valid partition of the states, and return it + */ +static int * +check_partitions (stg, equiv_states, subset, visited, allowed_partitions, trans_comb, edge_trans, state_marking, orig_stg_names) +graph_t *stg; +equiv_t *equiv_states; +astg_scode subset; +pset visited; +array_t *allowed_partitions, *trans_comb; +st_table *edge_trans, *state_marking, *orig_stg_names; +{ + vertex_t *state; + pset part, class; + int s, cl; + + /* transpose the "class" information into "allowed_partitions" */ + for (s = 0; s < array_n(equiv_states->index_state); s++) { + part = array_fetch (pset, allowed_partitions, s); + set_clear (part, equiv_states->classes->count); + foreachi_set (equiv_states->classes, cl, class) { + if (is_in_set (class, s)) { + set_insert (part, cl); + } + } + } + + do { + /* now examine all states */ + for (s = 0; s < array_n(equiv_states->index_state); s++) { + state = array_fetch (vertex_t *, equiv_states->index_state, s); + foreachi_set (equiv_states->classes, cl, class) { + set_clear (visited, array_n (equiv_states->index_state)); + if (! check_this_partition (state, cl, equiv_states, subset, + visited, allowed_partitions, /* rm */ 0, + edge_trans, state_marking)) { + (void) check_this_partition (state, cl, equiv_states, + subset, visited, allowed_partitions, /* rm */ 1, + edge_trans, state_marking); + } + } + } + } + while (closure (stg, allowed_partitions, equiv_states, trans_comb, + edge_trans)); + + /* and choose one class for each state */ + return choose_class (stg, allowed_partitions, equiv_states, orig_stg_names); +} + +/* generate all subsets in decreasing cost order */ +static astg_scode +partition_states_recur (astg, stg, equiv_states, base_subset, visited, masks, allowed_partitions, index_sig, first_signal, first_mask, trans_comb, edge_trans, state_marking, orig_stg_names) +astg_graph *astg; +graph_t *stg; +equiv_t *equiv_states; +astg_scode base_subset; +pset visited; +array_t *masks, *allowed_partitions, *index_sig; +int first_signal, first_mask; +array_t *trans_comb; +st_table *edge_trans, *state_marking, *orig_stg_names; +{ + astg_scode best_subset, subset, mask; + int i, m; + int *index_part; + astg_signal *sig_p; + + best_subset = base_subset; + for (m = first_mask; m < array_n (masks); m++) { + mask = array_fetch (astg_scode, masks, m); + for (i = first_signal; i < array_n (index_sig); i++) { + sig_p = array_fetch (astg_signal *, index_sig, i); + if (! (mask & bwd_astg_state_bit (sig_p))) { + continue; + } + + /* first try without this sig_p */ + subset = base_subset & ~bwd_astg_state_bit (sig_p); + if (astg_debug_flag > 1) { + fprintf (sisout, "trying signals:"); + print_subset (subset, astg); + } + + index_part = check_partitions (stg, equiv_states, subset, visited, + allowed_partitions, trans_comb, edge_trans, + state_marking, orig_stg_names); + + if (index_part != NIL(int)) { + FREE (index_part); + + /* at most this will return the current subset */ + subset = partition_states_recur (astg, stg, equiv_states, + subset, visited, masks, allowed_partitions, + index_sig, i + 1, m, trans_comb, edge_trans, state_marking, + orig_stg_names); + if (subset_cost (subset, astg) < + subset_cost (best_subset, astg)) { + best_subset = subset; + } + } + + /* then try with this sig_p */ + subset = partition_states_recur (astg, stg, equiv_states, + base_subset, visited, masks, allowed_partitions, + index_sig, i + 1, m, trans_comb, edge_trans, state_marking, + orig_stg_names); + + if (subset_cost (subset, astg) < + subset_cost (best_subset, astg)) { + best_subset = subset; + } + + return best_subset; + } + first_signal = 0; + } + return best_subset; +} + +static void +forced_sets_recur (equiv_states, allowed_partitions, state1, visited, tmp, copy, edge_trans, state_marking) +equiv_t *equiv_states; +array_t *allowed_partitions; +vertex_t *state1; +pset visited, tmp; +int copy; +st_table *edge_trans, *state_marking; +{ + lsGen gen; + edge_t *edge; + vertex_t *state2; + int s1, s2; + pset part1; + astg_scode new_enabled; + + assert (st_lookup (equiv_states->state_index, (char *) state1, (char **) &s1)); + set_insert (visited, s1); + part1 = array_fetch (pset, allowed_partitions, s1); + if (copy) { + if (! setp_equal (part1, tmp)) { + set_copy (part1, tmp); + if (astg_debug_flag > 3) { + fprintf (sisout, "%s updated part %s\n", + stg_get_state_name (state1), ps1(part1)); + } + } + } + else { + set_and (tmp, tmp, part1); + } + + foreach_state_outedge (state1, gen, edge) { + state2 = stg_edge_to_state (edge); + if (state1 == state2) { + continue; + } + new_enabled = bwd_new_enabled_signals (edge, edge_trans, state_marking); + if (new_enabled) { + continue; + } + assert (st_lookup (equiv_states->state_index, (char *) state2, (char **) &s2)); + if (is_in_set (visited, s2)) { + continue; + } + + forced_sets_recur (equiv_states, allowed_partitions, state2, + visited, tmp, copy, edge_trans, state_marking); + } + + foreach_state_inedge (state1, gen, edge) { + state2 = stg_edge_from_state (edge); + if (state1 == state2) { + continue; + } + new_enabled = bwd_new_enabled_signals (edge, edge_trans, state_marking); + if (new_enabled) { + continue; + } + assert (st_lookup (equiv_states->state_index, (char *) state2, (char **) &s2)); + if (is_in_set (visited, s2)) { + continue; + } + + forced_sets_recur (equiv_states, allowed_partitions, state2, + visited, tmp, copy, edge_trans, state_marking); + } +} + +/* force in the same set of classes all states that are separated by some + * input sig_p (may be very far from optimal) + */ +static void +reduce_input_dependency (stg, equiv_states, allowed_partitions, index_sig, visited, edge_trans, state_marking) +graph_t *stg; +equiv_t *equiv_states; +array_t *allowed_partitions, *index_sig; +pset visited; +st_table *edge_trans, *state_marking; +{ + lsGen gen; + edge_t *edge; + vertex_t *state1, *state2; + int i, s1, s2, nclasses, changed, nstates; + astg_scode new_enabled, in_mask; + pset class, part1, part2, tmp, tmp1, tmp2; + astg_signal *sig_p; + + in_mask = 0; + for (i = 0; i < array_n (index_sig); i++) { + sig_p = array_fetch (astg_signal *, index_sig, i); + if (astg_signal_type (sig_p) == ASTG_INPUT_SIG) { + in_mask |= bwd_astg_state_bit (sig_p); + } + } + + nclasses = equiv_states->classes->count; + nstates = array_n (equiv_states->index_state); + tmp = set_new (nclasses); + tmp1 = set_new (nclasses); + tmp2 = set_new (nclasses); + + for (s1 = 0; s1 < array_n(equiv_states->index_state); s1++) { + part1 = array_fetch (pset, allowed_partitions, s1); + set_clear (part1, nclasses); + foreachi_set (equiv_states->classes, i, class) { + if (is_in_set (class, s1)) { + set_insert (part1, i); + } + } + } + + do { + changed = 0; + stg_foreach_transition (stg, gen, edge) { + state1 = stg_edge_from_state (edge); + state2 = stg_edge_to_state (edge); + if (state1 == state2) { + continue; + } + new_enabled = bwd_new_enabled_signals (edge, edge_trans, + state_marking); + /* check if only input signals are enough to distinguish them */ + if (! (new_enabled & in_mask)) { + continue; + } + + set_fill (tmp1, nclasses); + set_clear (visited, nstates); + forced_sets_recur (equiv_states, allowed_partitions, + state1, visited, tmp1, /* copy */ 0, edge_trans, state_marking); + + set_fill (tmp2, nclasses); + set_clear (visited, nstates); + forced_sets_recur (equiv_states, allowed_partitions, + state2, visited, tmp2, /* copy */ 0, edge_trans, state_marking); + + /* make the two sets equal, if this does not rm the last class + * from each + */ + assert (st_lookup (equiv_states->state_index, (char *) state1, (char **) &s1)); + part1 = array_fetch (pset, allowed_partitions, s1); + assert (st_lookup (equiv_states->state_index, (char *) state2, (char **) &s2)); + part2 = array_fetch (pset, allowed_partitions, s2); + if ((setp_equal (part1, tmp1) && + setp_equal (part2, tmp2) && + setp_equal (tmp1, tmp2)) + || ! set_andp (tmp, tmp1, tmp2)) { + continue; + } + + changed = 1; + set_clear (visited, nstates); + forced_sets_recur (equiv_states, allowed_partitions, + state1, visited, tmp, /* copy */ 1, edge_trans, state_marking); + set_clear (visited, nstates); + forced_sets_recur (equiv_states, allowed_partitions, + state2, visited, tmp, /* copy */ 1, edge_trans, state_marking); + } + } while (changed); + + /* put back the information */ + for (s1 = 0; s1 < array_n(equiv_states->index_state); s1++) { + part1 = array_fetch (pset, allowed_partitions, s1); + foreachi_set (equiv_states->classes, i, class) { + if (! is_in_set (part1, i)) { + set_remove (class, s1); + } + } + } + + set_free (tmp); + set_free (tmp1); + set_free (tmp2); +} + +/* return 1 if trans1 and trans2 are in direct conflict, 0 otherwise */ +static int +is_conflict (trans1, trans2) +astg_trans *trans1, *trans2; +{ + int confl; + astg_generator tgen, pgen; + astg_trans *trans; + astg_place *place; + + if (trans1 == trans2) { + return 0; + } + /* check if there is a free choice place in the common fanin of the two */ + confl = 0; + astg_foreach_input_place (trans1, pgen, place) { + if (confl) { + continue; + } + astg_foreach_output_trans (place, tgen, trans) { + if (confl) { + continue; + } + if (trans == trans2) { + confl = 1; + } + } + } + + return confl; +} + +/* If the from and to states of edge belong to p_from and p_to respectively, + * then: + * (1) insert the corresponding markings in from_markings and to_markings + * (2) recur on all states reachable from from and to (using the merged super- + * states) that do not require to traverse any edge in conflict with edge + */ +static void +find_marking_pairs_recur (stg, astg, orig_stg_names, state_index, edge_trans, partitions, from, p_from, p_to, to_visit, from_set, to_set, cur_trans_sets) +graph_t *stg; +astg_graph *astg; +st_table *orig_stg_names, *state_index; +st_table *edge_trans, *partitions; +vertex_t *from; +int p_from, p_to; +pset to_visit, from_set, to_set; +st_table *cur_trans_sets; +{ + lsGen gen; + edge_t *edge; + vertex_t *to, *from1; + int p, s_from, s_to; + + assert (st_lookup (state_index, (char *) from, (char **) &s_from)); + if (! is_in_set (to_visit, s_from)) { + return; + } + set_remove (to_visit, s_from); + + foreach_state_outedge (from, gen, edge) { + to = stg_edge_to_state (edge); + if (to == from) { + continue; + } + + if (is_forbidden (cur_trans_sets, edge_trans, edge)) { + continue; + } + + assert (st_lookup (state_index, (char *) to, (char **) &s_to)); + /* insert the pair only if they belong to the proper partitions */ + assert (st_lookup (partitions, (char *) to, (char **) &p)); + if (p_to == p) { + set_insert (from_set, s_from); + set_insert (to_set, s_to); + } + + if (! is_in_set (to_visit, s_to)) { + continue; + } + + find_marking_pairs_recur (stg, astg, + orig_stg_names, state_index, edge_trans, + partitions, to, p_from, p_to, + to_visit, from_set, to_set, cur_trans_sets); + } + + foreach_state_inedge (from, gen, edge) { + from1 = stg_edge_from_state (edge); + if (from1 == from) { + continue; + } + + if (is_forbidden (cur_trans_sets, edge_trans, edge)) { + continue; + } + + assert (st_lookup (state_index, (char *) from1, (char **) &s_from)); + if (! is_in_set (to_visit, s_from)) { + continue; + } + + find_marking_pairs_recur (stg, astg, + orig_stg_names, state_index, edge_trans, + partitions, from1, p_from, p_to, + to_visit, from_set, to_set, cur_trans_sets); + } +} + +static void +free_marking_pair (marking_pair) +marking_pair_t marking_pair; +{ + FREE (marking_pair.from_state); + FREE (marking_pair.to_state); + array_free (marking_pair.from_markings); + array_free (marking_pair.to_markings); +} + +/* check for multiple exit points */ +static void +check_multiple_exit (astg, stg, from, partitions, merged_head, orig_stg_names, edge_trans, index_sig) +astg_graph *astg; +graph_t *stg; +vertex_t *from; +st_table *partitions, *merged_head, *orig_stg_names, *edge_trans; +array_t *index_sig; +{ + lsGen gen1, gen2; + vertex_t *from_head, *to1, *to2, *from2, *new_from; + edge_t *edge1, *edge2; + int i, p_to1, p_to2, p_from, p_from2, k1, k2; + char *str; + astg_trans *trans1, *trans2; + array_t *names, *trans_arr1, *trans_arr2; + + /* check all pre-merged states together */ + assert (st_lookup (merged_head, (char *) from, (char **) &from_head)); + str = stg_get_state_name (from_head); + /* avoid useless duplication of work... */ + if (strcmp (str, stg_get_state_name (from))) { + return; + } + + assert (st_lookup (orig_stg_names, (char *) str, (char **) &names)); + assert (st_lookup (partitions, (char *) from, (char **) &p_from)); + for (i = 0; i < array_n (names); i++) { + str = array_fetch (char *, names, i); + new_from = bwd_get_state_by_name (stg, str); + foreach_state_outedge (new_from, gen1, edge1) { + to1 = stg_edge_to_state (edge1); + if (to1 == new_from) { + continue; + } + assert (st_lookup (partitions, (char *) to1, (char **) &p_to1)); + if (p_from == p_to1) { + continue; + } + + foreach_state_outedge (new_from, gen2, edge2) { + to2 = stg_edge_to_state (edge2); + if (to2 == to1) { + /* avoid duplicates by considering them "ordered" */ + lsFinish(gen2); + break; + } + + if (to2 == new_from) { + continue; + } + assert (st_lookup (partitions, (char *) to2, (char **) &p_to2)); + if (p_from == p_to2) { + continue; + } + + assert (st_lookup (edge_trans, (char *) edge1, (char **) &trans_arr1)); + assert (st_lookup (edge_trans, (char *) edge2, (char **) &trans_arr2)); + + for (k1 = 0; k1 < array_n (trans_arr1); k1++) { + trans1 = array_fetch (astg_trans *, trans_arr1, k1); + for (k2 = 0; k2 < array_n (trans_arr2); k2++) { + trans2 = array_fetch (astg_trans *, trans_arr2, k2); + if (! is_conflict (trans1, trans2)) { + constrain ( + "the STG may not be live (multiple exit point)", + astg, trans1, trans2); + } + } + } + } + + /* highly inefficient way to check p_from2 -> p_from -> p_to1 */ + foreach_state_inedge (new_from, gen2, edge2) { + from2 = stg_edge_from_state (edge2); + if (from2 == new_from) { + continue; + } + assert (st_lookup (partitions, (char *) from2, (char **) &p_from2)); + if (p_from == p_from2) { + continue; + } + + assert (st_lookup (edge_trans, (char *) edge1, (char **) &trans_arr1)); + assert (st_lookup (edge_trans, (char *) edge2, (char **) &trans_arr2)); + + for (k1 = 0; k1 < array_n (trans_arr1); k1++) { + trans1 = array_fetch (astg_trans *, trans_arr1, k1); + for (k2 = 0; k2 < array_n (trans_arr2); k2++) { + trans2 = array_fetch (astg_trans *, trans_arr2, k2); + if (! is_conflict (trans1, trans2)) { + constrain ( + "the STG may not be live (multiple exit point)", + astg, trans2, trans1); + } + } + } + } + } + } +} + +/* Find all maximal sets of transitions that are concurrently enabled in + * "state". For each such set generate a symbol table containing edges + * enabled in "state" but not in the set. + */ +static void +find_maximal_concurrent (astg, stg, state, marking, cur_fc, edge_trans, state_marking, trans_set, trans_sets) +astg_graph *astg; +graph_t *stg; +vertex_t *state; +astg_marking *marking; +int cur_fc; +st_table *edge_trans, *state_marking, *trans_set; +array_t *trans_sets; +{ + int fc, all_in; + astg_trans *trans, *trans1; + astg_generator tgen, pgen, tgen1; + astg_place *place; + st_generator *stgen; + + fc = 0; + astg_foreach_place (astg, pgen, place) { + if (! astg_get_marked (marking, place)) { + continue; + } + if (astg_out_degree (place) > 1) { + fc++; + } + if (fc > cur_fc) { + break; + } + } + + if (fc > cur_fc) { + /* split on "place" */ + astg_foreach_output_trans (place, tgen, trans) { + all_in = 1; + astg_foreach_output_trans (place, tgen1, trans1) { + if (trans1 == trans) { + continue; + } + if (! st_is_member (trans_set, (char *) trans1)) { + all_in = 0; + } + } + if (all_in) { + continue; + } + st_insert (trans_set, (char *) trans, NIL(char)); + find_maximal_concurrent (astg, stg, state, marking, fc, + edge_trans, state_marking, trans_set, + trans_sets); + st_delete (trans_set, (char **) &trans, NIL(char *)); + } + } + else { + /* everything is concurrent: add a new element to the array */ + if (st_count (trans_set)) { + if (astg_debug_flag > 1) { + fprintf (sisout, "forbidden transitions for %s:", + stg_get_state_name (state)); + st_foreach_item (trans_set, stgen, (char **) &trans, + NIL(char *)) { + fprintf (sisout, " %s", astg_trans_name (trans)); + } + fprintf (sisout, "\n"); + } + array_insert_last (st_table *, trans_sets, + st_copy (trans_set)); + } + } +} + +static void +create_combinations_recur (trans_comb, all_trans_sets, cur_trans_sets, i) +array_t *trans_comb, *all_trans_sets; +st_table *cur_trans_sets; +int i; +{ + int j; + array_t *trans_sets; + st_table *trans_set; + st_generator *stgen; + astg_trans *trans; + + if (i >= array_n (all_trans_sets)) { + array_insert_last (st_table *, trans_comb, st_copy (cur_trans_sets)); + } + else { + trans_sets = array_fetch (array_t *, all_trans_sets, i); + for (j = 0; j < array_n (trans_sets); j++) { + trans_set = array_fetch (st_table *, + trans_sets, j); + st_foreach_item (trans_set, stgen, (char **) &trans, + NIL(char *)) { + st_insert (cur_trans_sets, (char *) trans, NIL(char)); + } + + create_combinations_recur (trans_comb, all_trans_sets, + cur_trans_sets, i + 1); + + st_foreach_item (trans_set, stgen, (char **) &trans, + NIL(char *)) { + st_delete (cur_trans_sets, (char **) &trans, NIL(char *)); + } + } + } +} + +static void +find_to_visit (stg, to_visit, partitions, orig_stg_names, state_index, p_from, p_to) +graph_t *stg; +pset to_visit; +st_table *partitions, *orig_stg_names, *state_index; +int p_from, p_to; +{ + lsGen gen; + edge_t *edge; + vertex_t *from, *to, *head; + int s, p, i, found; + st_generator *stgen; + char *str; + array_t *names; + + st_foreach_item (orig_stg_names, stgen, (char **) &str, + (char **) &names) { + head = bwd_get_state_by_name (stg, str); + assert (st_lookup (partitions, (char *) head, (char **) &p)); + if (p != p_from) { + continue; + } + found = 0; + for (i = 0; ! found && i < array_n (names); i++) { + str = array_fetch (char *, names, i); + from = bwd_get_state_by_name (stg, str); + foreach_state_outedge (from, gen, edge) { + to = stg_edge_to_state (edge); + if (to == from) { + continue; + } + assert (st_lookup (partitions, (char *) to, (char **) &p)); + if (p == p_to) { + found = 1; + lsFinish(gen); + break; + } + } + } + if (found) { + for (i = 0; i < array_n (names); i++) { + str = array_fetch (char *, names, i); + from = bwd_get_state_by_name (stg, str); + assert (st_lookup (state_index, (char *) from, (char **) &s)); + set_insert (to_visit, s); + } + } + } +} + +static int +st_eq (st1, st2) +st_table *st1, *st2; +{ + st_generator *stgen; + char *key; + + if (st_count (st1) != st_count (st2)) { + return 0; + } + st_foreach_item (st1, stgen, &key, NIL(char*)) { + if (! st_is_member (st2, key)) { + return 0; + } + } + + return 1; +} + +/* return 1 if maring can be reached from any from_marking firing a single + * transition + */ +static int +has_neighbor (astg, marking, markings, forward) +astg_graph *astg; +astg_marking *marking; +array_t *markings; +int forward; +{ + int i; + astg_marking *dup, *cand; + astg_generator tgen; + astg_trans *trans; + + for (i = 0; i < array_n (markings); i++) { + cand = array_fetch (astg_marking *, markings, i); + astg_foreach_trans (astg, tgen, trans) { + if (forward) { + /* try marking [trans> cand */ + dup = astg_dup_marking (marking); + if (! astg_disabled_count (trans, dup)) { + (void) astg_fire (dup, trans); + if (! astg_cmp_marking (dup, cand)) { + astg_delete_marking (dup); + return 1; + } + } + astg_delete_marking (dup); + } + else { + /* try cand [trans> marking */ + dup = astg_dup_marking (cand); + if (! astg_disabled_count (trans, dup)) { + (void) astg_fire (dup, trans); + if (! astg_cmp_marking (dup, marking)) { + astg_delete_marking (dup); + return 1; + } + } + astg_delete_marking (dup); + } + } + } + + return 0; +} + +/* Partition the set of states in stg according to the classes in equiv_states, + * using signals as class separators. + */ +static st_table * +partition_states (astg, stg, equiv_states, use_mincov, greedy, go_down, mincov_option, use_mdd, edge_trans, state_marking, orig_stg_names) +astg_graph *astg; +graph_t *stg; +equiv_t *equiv_states; +int use_mincov, greedy, go_down, mincov_option, use_mdd; +st_table *edge_trans, *state_marking, *orig_stg_names; +{ + st_table *partitions, *trans_set, *cur_trans_sets, *old_trans_set; + array_t *index_sig, *allowed_partitions, *masks, *names, *froms, *tos; + array_t *trans_sets, *all_trans_sets, *trans_comb, *old_trans_sets; + array_t *marking_arr, *from_markings, *to_markings; + lsGen gen; + vertex_t *state_head, *state, *from, *to; + pset part, from_set, to_set, visited, to_visit, old_from, old_to; + int s, i, j, m, in, out, cl, len, p_from, p_to, npart, found, k; + int *index_part; + char *str, buf[80]; + astg_scode base_subset, best_subset, subset, in_mask, out_mask, mask; + astg_signal *sig_p; + astg_generator sgen; + st_generator *stgen; + marking_pair_t marking_pair; + st_table *merged_head; + astg_marking *marking; + astg_trans *trans; + + if (equiv_states->classes->count < 2) { + /* too easy... */ + fprintf (siserr, + "info: the STG has complete state coding (no state coding is necessary)\n"); + + partitions = st_init_table (st_ptrcmp, st_ptrhash); + stg_foreach_state (stg, gen, state) { + st_insert (partitions, (char *) state, (char *) 0); + } + return partitions; + } + + /* initialize variables */ + index_sig = array_alloc (astg_signal *, 0); + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + array_insert_last (astg_signal *, index_sig, sig_p); + } + visited = set_new (array_n(equiv_states->index_state)); + to_visit = set_new (array_n(equiv_states->index_state)); + allowed_partitions = array_alloc (pset, 0); + for (i = 0; i < array_n(equiv_states->index_state); i++) { + part = set_new (equiv_states->classes->count); + array_insert_last (pset, allowed_partitions, part); + } + + /* find the sets of mutually exclusive transitions, to avoid traversing + * them together while computing closure etc. + */ + all_trans_sets = array_alloc (array_t *, 0); + st_foreach_item (orig_stg_names, stgen, (char **) &str, (char **) &names) { + state = bwd_get_state_by_name (stg, str); + trans_sets = array_alloc (st_table *, 0); + trans_set = st_init_table (st_ptrcmp, st_ptrhash); + + assert (st_lookup (state_marking, (char *) state, (char **) &marking_arr)); + for (k = 0; k < array_n (marking_arr); k++) { + marking = array_fetch (astg_marking *, marking_arr, k); + find_maximal_concurrent (astg, stg, state, marking, 0, + edge_trans, state_marking, trans_set, trans_sets); + } + + st_free_table (trans_set); + if (array_n (trans_sets)) { + found = 0; + for (i = 0; ! found && i < array_n (all_trans_sets); i++) { + old_trans_sets = array_fetch (array_t *, all_trans_sets, i); + if (array_n (old_trans_sets) != array_n (trans_sets)) { + continue; + } + for (j = 0; ! found && j < array_n (trans_sets); j++) { + trans_set = array_fetch (st_table *, trans_sets, j); + old_trans_set = array_fetch (st_table *, old_trans_sets, j); + if (st_eq (trans_set, old_trans_set)) { + found = 1; + } + } + } + + if (found) { + for (j = 0; ! found && j < array_n (trans_sets); j++) { + trans_set = array_fetch (st_table *, trans_sets, j); + st_free_table (trans_set); + } + array_free (trans_sets); + } + else { + array_insert_last (array_t *, all_trans_sets, trans_sets); + } + } + } + trans_comb = array_alloc (st_table *, 0); + cur_trans_sets = st_init_table (st_ptrcmp, st_ptrhash); + create_combinations_recur (trans_comb, all_trans_sets, cur_trans_sets, 0); + st_free_table (cur_trans_sets); + + if (greedy > 1) { + reduce_input_dependency (stg, equiv_states, + allowed_partitions, index_sig, visited, edge_trans, state_marking); + } + /* find the initial subset */ + if (use_mincov || use_mdd) { + assert (go_down); + base_subset = find_partitioning_signals (astg, stg, equiv_states, + index_sig, visited, mincov_option, use_mdd, + edge_trans, state_marking); + } + else { + base_subset = 0; + if (go_down) { + for (i = 0; i < array_n (index_sig); i++) { + sig_p = array_fetch (astg_signal *, index_sig, i); + base_subset |= bwd_astg_state_bit (sig_p); + } + } + } + + if (astg_debug_flag > 1) { + fprintf (sisout, "initial signals:"); + print_subset (base_subset, astg); + } + + if (use_mincov >= 2 || use_mdd >= 2) { + index_part = check_partitions (stg, equiv_states, base_subset, + visited, allowed_partitions, trans_comb, edge_trans, + state_marking, orig_stg_names); + best_subset = base_subset; + } + else { + /* try to improve (or make valid altogether) the initial solution */ + out_mask = in_mask = 0; + for (i = 0; i < array_n (index_sig); i++) { + sig_p = array_fetch (astg_signal *, index_sig, i); + if (go_down && ! (bwd_astg_state_bit (sig_p) & base_subset)) { + continue; + } + if (signal_cost (sig_p, astg) == 1) { + in_mask |= bwd_astg_state_bit (sig_p); + } + else { + out_mask |= bwd_astg_state_bit (sig_p); + } + } + + if (go_down) { + masks = array_alloc (astg_scode, 0); + array_insert_last (astg_scode, masks, out_mask); + array_insert_last (astg_scode, masks, in_mask); + if (greedy) { + best_subset = base_subset; + for (m = 0; m < array_n (masks); m++) { + mask = array_fetch (astg_scode, masks, m); + for (i = 0; i < array_n (index_sig); i++) { + sig_p = array_fetch (astg_signal *, index_sig, i); + if (! (mask & bwd_astg_state_bit (sig_p))) { + continue; + } + + subset = best_subset & ~bwd_astg_state_bit (sig_p); + if (astg_debug_flag > 1) { + fprintf (sisout, "trying signals:"); + print_subset (subset, astg); + } + + index_part = check_partitions (stg, equiv_states, + subset, visited, allowed_partitions, trans_comb, + edge_trans, state_marking, orig_stg_names); + + if (index_part == NIL(int)) { + continue; + } + + best_subset = subset; + FREE (index_part); + } + } + } + else { + best_subset = partition_states_recur (astg, stg, equiv_states, + base_subset, visited, masks, allowed_partitions, index_sig, + 0, 0, trans_comb, edge_trans, state_marking, + orig_stg_names); + } + if (astg_debug_flag > 1) { + fprintf (sisout, "checking final signals:"); + print_subset (best_subset, astg); + } + array_free (masks); + index_part = check_partitions (stg, equiv_states, best_subset, + visited, allowed_partitions, trans_comb, edge_trans, + state_marking, orig_stg_names); + } + else { + /* generate all subsets in increasing cost order */ + index_part = NIL(int); + for (in = 0; in <= count_ones (in_mask); in++) { + for (out = 0; out <= count_ones (out_mask); out++) { + for (subset = 1; subset <= (in_mask | out_mask); subset++) { + if (count_ones((subset & in_mask)) != in || + count_ones ((subset & out_mask)) != out) { + continue; + } + + if (astg_debug_flag > 1) { + fprintf (sisout, "trying signals:"); + print_subset (subset, astg); + } + index_part = check_partitions (stg, equiv_states, + subset, visited, allowed_partitions, trans_comb, + edge_trans, state_marking, orig_stg_names); + if (index_part != NIL(int)) { + break; + } + } + if (index_part != NIL(int)) { + break; + } + } + if (index_part != NIL(int)) { + break; + } + } + best_subset = subset; + } + } + + if (astg_debug_flag > 0 && index_part != NIL(int)) { + fprintf (sisout, "selected signals:"); + print_subset (best_subset, astg); + } + + if (index_part == NIL(int)) { + fprintf (siserr, "internal error: cannot find a valid partition\n"); + return NIL(st_table); + } + partitions = st_init_table (st_ptrcmp, st_ptrhash); + npart = 0; + for (i = 0; i < array_n (equiv_states->index_state); i++) { + state = array_fetch (vertex_t *, equiv_states->index_state, i); + assert (index_part[i] >= 0); + npart = MAX (npart, index_part[i] + 1); + st_insert (partitions, (char *) state, (char *) index_part[i]); + } + + /* create a table with key each state in the un-minimized graph + * and data the corresponding pre-minimized state (invert the information + * of the orig_stg_names table) + */ + merged_head = st_init_table (st_ptrcmp, st_ptrhash); + st_foreach_item (orig_stg_names, stgen, (char **) &str, + (char **) &names) { + state_head = bwd_get_state_by_name (stg, str); + for (s = 0; s < array_n (names); s++) { + state = bwd_get_state_by_name (stg, array_fetch (char*, names, s)); + st_insert (merged_head, (char *) state, (char *) state_head); + } + } + + stg_foreach_state (stg, gen, from) { + check_multiple_exit (astg, stg, from, partitions, + merged_head, orig_stg_names, edge_trans, index_sig); + } + st_free_table (merged_head); + + /* store the marking pairs */ + if (marking_pairs != NIL(array_t)) { + for (i = 0; i < array_n (marking_pairs); i++) { + marking_pair = array_fetch (marking_pair_t, marking_pairs, i); + free_marking_pair (marking_pair); + } + array_free (marking_pairs); + } + marking_pairs = array_alloc (marking_pair_t, 0); + + for (p_from = 0; p_from < npart; p_from++) { + for (p_to = 0; p_to < npart; p_to++) { + if (p_to == p_from) { + continue; + } + + froms = array_alloc (pset, 0); + tos = array_alloc (pset, 0); + + for (j = 0; j < array_n (trans_comb); j++) { + cur_trans_sets = array_fetch (st_table *, trans_comb, j); + if (astg_debug_flag > 2 && st_count (cur_trans_sets)) { + fprintf (sisout, "excluding transitions"); + st_foreach_item (cur_trans_sets, stgen, (char **) &trans, + NIL(char *)) { + fprintf (sisout, " %s", astg_trans_name (trans)); + } + fprintf (sisout, "\n"); + } + + /* insert in to_visit all the states in p_from that are + * adjacent (as super-states) to a state in p_to + */ + set_clear (to_visit, array_n(equiv_states->index_state)); + find_to_visit (stg, to_visit, partitions, orig_stg_names, + equiv_states->state_index, p_from, p_to); + + stg_foreach_state (stg, gen, from) { + from_set = set_new (array_n(equiv_states->index_state)); + to_set = set_new (array_n(equiv_states->index_state)); + + find_marking_pairs_recur (stg, astg, + orig_stg_names, equiv_states->state_index, edge_trans, + partitions, from, p_from, p_to, + to_visit, from_set, to_set, cur_trans_sets); + + for (i = 0; i < array_n (froms); i++) { + old_from = array_fetch (pset, froms, i); + old_to = array_fetch (pset, tos, i); + if (setp_implies (old_from, from_set) && + setp_implies (old_to, to_set)) { + /* new pair contains old pair */ + set_copy (old_from, from_set); + set_copy (old_to, to_set); + break; + } + + if (setp_implies (from_set, old_from) && + setp_implies (to_set, old_to)) { + /* old pair contains new pair */ + break; + } + } + if (i >= array_n (froms)) { + /* not found: add it */ + array_insert_last (pset, froms, from_set); + array_insert_last (pset, tos, to_set); + } + else { + set_free (from_set); + set_free (to_set); + } + } + } + + for (i = 0; i < array_n (froms); i++) { + from_set = array_fetch (pset, froms, i); + to_set = array_fetch (pset, tos, i); + + sprintf (buf, "s%d", p_from); + marking_pair.from_state = util_strsav (buf); + sprintf (buf, "s%d", p_to); + marking_pair.to_state = util_strsav (buf); + if (astg_debug_flag > 1) { + fprintf (sisout, + "creating marking pair from %s to %s\n from", + marking_pair.from_state, marking_pair.to_state); + } + + /* Now, thanks to those dummy transitions, we must do all our + * checks again... This may be LONG... + */ + from_markings = array_alloc (astg_marking *, 0); + for (s = 0; s < array_n (equiv_states->index_state); s++) { + if (! is_in_set (from_set, s)) { + continue; + } + from = array_fetch (vertex_t *, + equiv_states->index_state, s); + assert (st_lookup (state_marking, (char *) from, (char **) &marking_arr)); + for (k = 0; k < array_n (marking_arr); k++) { + marking = array_fetch (astg_marking *, marking_arr, k); + array_insert_last (astg_marking *, + from_markings, marking); + } + if (astg_debug_flag > 1) { + fprintf (sisout, " %s", stg_get_state_name (from)); + } + } + + if (astg_debug_flag > 1) { + fprintf (sisout, "\n to"); + } + + to_markings = array_alloc (astg_marking *, 0); + for (s = 0; s < array_n (equiv_states->index_state); s++) { + if (! is_in_set (to_set, s)) { + continue; + } + to = array_fetch (vertex_t *, + equiv_states->index_state, s); + assert (st_lookup (state_marking, (char *) to, (char **) &marking_arr)); + for (k = 0; k < array_n (marking_arr); k++) { + marking = array_fetch (astg_marking *, marking_arr, k); + array_insert_last (astg_marking *, + to_markings, marking); + } + if (astg_debug_flag > 1) { + fprintf (sisout, " %s", stg_get_state_name (to)); + } + } + + if (astg_debug_flag > 1) { + fprintf (sisout, "\n"); + } + + marking_pair.from_markings = array_alloc (astg_marking *, 0); + for (k = 0; k < array_n (from_markings); k++) { + marking = array_fetch (astg_marking *, from_markings, k); + if (! has_neighbor (astg, marking, to_markings, + /*forward*/ 1)) { + continue; + } + array_insert_last (astg_marking *, + marking_pair.from_markings, marking); + } + marking_pair.to_markings = array_alloc (astg_marking *, 0); + for (k = 0; k < array_n (to_markings); k++) { + marking = array_fetch (astg_marking *, to_markings, k); + if (! has_neighbor (astg, marking, from_markings, + /*forward*/ 0)) { + continue; + } + array_insert_last (astg_marking *, + marking_pair.to_markings, marking); + } + + if (array_n (marking_pair.to_markings) > 0 && + array_n (marking_pair.from_markings) > 0) { + array_insert_last (marking_pair_t, marking_pairs, + marking_pair); + } + else { + array_free (marking_pair.to_markings); + array_free (marking_pair.from_markings); + } + array_free (to_markings); + array_free (from_markings); + set_free (from_set); + set_free (to_set); + } + + array_free (froms); + array_free (tos); + } + } + + /* store the partitioning signals */ + if (partitioning_signals != NIL(array_t)) { + array_free (partitioning_signals); + } + partitioning_signals = array_alloc (astg_signal *, 0); + for (i = 0; i < array_n (index_sig); i++) { + sig_p = array_fetch (astg_signal *, index_sig, i); + if (! (best_subset & bwd_astg_state_bit (sig_p))) { + continue; + } + array_insert_last (astg_signal *, partitioning_signals, sig_p); + } + + for (j = 0; j < array_n (trans_comb); j++) { + cur_trans_sets = array_fetch (st_table *, trans_comb, j); + st_free_table (cur_trans_sets); + } + array_free (index_sig); + FREE (index_part); + for (i = 0; i < array_n (all_trans_sets); i++) { + trans_sets = array_fetch (array_t *, all_trans_sets, i); + for (j = 0; j < array_n (trans_sets); j++) { + trans_set = + array_fetch (st_table *, trans_sets, j); + st_free_table (trans_set); + } + array_free (trans_sets); + } + array_free (all_trans_sets); + array_free (trans_comb); + + if (astg_debug_flag > 1) { + fprintf (sisout, "Reduced machine state partitions:\n"); + for (i = 0; i < equiv_states->classes->count; i++) { + fprintf (sisout, "%2d ", i); + len = 3; + st_foreach_item (partitions, stgen, (char **) &state, + (char **) &cl) { + if (cl == i) { + str = stg_get_state_name (state); + len += strlen (str) + 1; + if (len >= 80) { + fprintf (sisout, "\n "); + len = 3 + strlen (str) + 1; + } + fprintf (sisout, "%s ", str); + } + } + fprintf (sisout, "\n"); + } + } + + set_free (visited); + set_free (to_visit); + for (i = 0; i < array_n (allowed_partitions); i++) { + part = array_fetch (pset, allowed_partitions, i); + set_free (part); + } + array_free (allowed_partitions); + + return partitions; +} + +/* Minimize the flow table (represented as an STG) using the equivalence class + * information. + * First find a set of signals that partitions the equivalence classes. Then + * for each class class1, decide what states belong to it, according to whether + * or not the relevant transition was in the cover. Then build the minimized + * flow table (for Tracey encoding). + */ +graph_t * +bwd_state_minimize (astg, equiv_states, use_mincov, greedy, go_down, mincov_option, use_mdd, sig_cost) +astg_graph *astg; +equiv_t *equiv_states; +int use_mincov, greedy, go_down, mincov_option, use_mdd; +st_table *sig_cost; +{ + graph_t *red_stg; + st_table *partitions; + st_generator *stgen; + array_t *names; + char *str; + + if (global_orig_stg == NIL(graph_t)) { + fprintf (siserr, "No state transition graph (use astg_to_stg)\n"); + return NIL(graph_t); + } + g_sig_cost = sig_cost; + partitions = partition_states (astg, global_orig_stg, equiv_states, + use_mincov, greedy, go_down, mincov_option, use_mdd, global_edge_trans, + global_state_marking, global_orig_stg_names); + if (partitions == NIL(st_table)) { + /* something wrong occurred */ + g_sig_cost = NIL(st_table); + return NIL(graph_t); + } + + red_stg = bwd_reduced_stg (global_orig_stg, partitions, NIL(st_table), + NIL(array_t), equiv_states->classes->count); + + equiv_free (equiv_states); + st_free_table (partitions); + stg_free (global_orig_stg); + global_orig_stg = NIL(graph_t); + st_foreach_item (global_orig_stg_names, stgen, (char **) &str, + (char **) &names) { + array_free (names); + } + st_free_table (global_orig_stg_names); + + g_sig_cost = NIL(st_table); + return red_stg; +} + +/* return (if any) a transition of sig_p between from_trans and place */ +static astg_trans * +find_transition (from_trans, from_to_place, sig_p) +astg_trans *from_trans; +astg_place *from_to_place; +astg_signal *sig_p; +{ + astg_generator pgen, tgen, pgen1, tgen1, pgen2; + astg_place *place, *place1, *place2; + astg_trans *result, *trans1, *sig_trans; + + result = NIL(astg_trans); + astg_foreach_output_place (from_trans, pgen, place) { + if (result != NIL(astg_trans)) { + continue; + } + astg_foreach_output_trans (place, tgen, sig_trans) { + if (result != NIL(astg_trans)) { + continue; + } + if (astg_trans_sig (sig_trans) != sig_p) { + continue; + } + astg_foreach_output_place (sig_trans, pgen1, place1) { + if (result != NIL(astg_trans)) { + continue; + } + if (place1 == from_to_place) { + result = sig_trans; + } + astg_foreach_output_trans (place1, tgen1, trans1) { + if (result != NIL(astg_trans) || + astg_signal_type (astg_trans_sig (trans1)) + != ASTG_DUMMY_SIG) { + continue; + } + astg_foreach_output_place (trans1, pgen2, place2) { + if (result != NIL(astg_trans)) { + continue; + } + if (place2 == from_to_place) { + result = sig_trans; + } + } + } + } + } + } + return result; +} + +static astg_place * +add_and_return_constraint (from_trans, to_trans) +astg_trans *from_trans, *to_trans; +{ + astg_generator tgen, pgen; + astg_place *new_p, *place; + astg_trans *trans; + + astg_add_constraint (from_trans, to_trans, ASTG_TRUE); + new_p = NIL(astg_place); + astg_foreach_output_place (from_trans, pgen, place) { + if (new_p != NIL(astg_place)) { + continue; + } + astg_foreach_output_trans (place, tgen, trans) { + if (new_p != NIL(astg_place)) { + continue; + } + if (trans == to_trans) { + new_p = place; + } + } + } + assert (new_p != NIL(astg_trans)); + return new_p; +} + +/* return 1 if from_trans is predecessor of all to_transitions + */ +static int +is_predecessor (from_trans, to_transitions) +astg_trans *from_trans; +st_table *to_transitions; +{ + int result, found; + st_generator *stgen; + astg_generator pgen, tgen; + astg_trans *to_trans, *trans; + astg_place *place; + + result = 1; + st_foreach_item (to_transitions, stgen, (char **) &to_trans, NIL(char *)) { + if (! result) { + continue; + } + found = 0; + astg_foreach_input_place (to_trans, pgen, place) { + if (found) { + continue; + } + astg_foreach_input_trans (place, tgen, trans) { + if (found) { + continue; + } + if (trans == from_trans) { + found = 1; + } + } + } + if (! found) { + result = 0; + } + } + + return result; +} + +/* Split each place in new_places and insert a dummy transition dum1, a set + * of state transitions and a dummy transition dum2 between them + */ +static void +add_state_vars (astg, initial_marking, added, initial, from_transitions, new_places, from_code, to_code, nbits, idx, state_signals) +astg_graph *astg; +astg_marking *initial_marking; +st_table *added, *initial, *from_transitions, *new_places; +char *from_code, *to_code; +int nbits, idx; +astg_signal **state_signals; +{ + int i; + astg_place *new_p1, *new_p2, *from_to_place; + astg_trans *new_t, *from_trans, *dum_t1, *dum_t2; + st_generator *stgen, *stgen1; + static char buf[50]; + + /* create a pair of dummy transition, dum_t1 with fanout the new_places + * dum_t2 with fanin copied from the set of transitions in + * from_transitions + */ + if (dum_sig == NIL(astg_signal)) { + strcpy (buf, "dummy"); + while ((dum_sig = astg_find_signal (astg, buf, + ASTG_DUMMY_SIG, ASTG_FALSE)) != + NIL(astg_signal)) { + strcat (buf, "_"); + } + dum_sig = astg_find_signal (astg, buf, + ASTG_DUMMY_SIG, ASTG_TRUE); + } + dum_t1 = astg_find_trans (astg, + astg_signal_name (dum_sig), + ASTG_DUMMY_X, dum_i++, ASTG_TRUE); + dum_t2 = astg_find_trans (astg, + astg_signal_name (dum_sig), + ASTG_DUMMY_X, dum_i++, ASTG_TRUE); + st_foreach_item (new_places, stgen, (char **) &from_to_place, + NIL(char *)) { + new_p1 = NIL(astg_place); + st_foreach_item (from_transitions, stgen1, (char **) &from_trans, + NIL(char *)) { + if (astg_find_edge (from_trans, from_to_place, ASTG_FALSE) + == NIL(astg_edge)) { + continue; + } + + /* move the fanout from from_trans to dum_t2 */ + if (astg_debug_flag > 0) { + fprintf (sisout, + "replacing %s %s with\n", + astg_trans_name (from_trans), + astg_place_name (from_to_place)); + } + astg_delete_edge (astg_find_edge (from_trans, + from_to_place, ASTG_FALSE)); + if (astg_find_edge (dum_t2, from_to_place, ASTG_FALSE) + == NIL(astg_edge)) { + astg_find_edge (dum_t2, from_to_place, ASTG_TRUE); + } + if (astg_debug_flag > 0) { + fprintf (sisout, + " %s %s and\n", + astg_trans_name (dum_t2), + astg_place_name (from_to_place)); + } + + /* create a fanin from dum_t1 */ + if (new_p1 == NIL(astg_place)) { + new_p1 = add_and_return_constraint (from_trans, dum_t1); + st_insert (added, (char *) new_p1, NIL(char)); + } + else { + if (astg_find_edge (new_p1, dum_t2, ASTG_FALSE) + == NIL(astg_edge)) { + astg_find_edge (new_p1, dum_t2, ASTG_TRUE); + } + } + if (astg_debug_flag > 0) { + fprintf (sisout, + " %s %s %s\n", + astg_trans_name (from_trans), + astg_place_name (new_p1), + astg_trans_name (dum_t1)); + } + } + + /* if from_to_place was initially marked, then + * new_p1 must be marked instead + */ + if (! st_is_member (added, (char *) from_to_place)) { + if (astg_get_marked (initial_marking, from_to_place)) { + st_insert (initial, (char *) new_p1, NIL(char)); + st_delete (initial, (char **) &from_to_place, NIL(char*)); + } + } + } + + /* now add the state transitions between dum_t1 and dum_t2 */ + for (i = 0; i < nbits; i++) { + if (from_code[i] == to_code[i]) { + continue; + } + + /* create the transition */ + new_t = astg_find_trans (astg, state_signals[i]->name, + TRANS_TYPE (from_code[i]), idx, ASTG_TRUE); + + new_p1 = add_and_return_constraint (dum_t1, new_t); + st_insert (added, (char *) new_p1, NIL(char)); + new_p2 = add_and_return_constraint (new_t, dum_t2); + st_insert (added, (char *) new_p2, NIL(char)); + } +} + +void +bwd_add_state (stg, astg, restore_marking) +graph_t *stg; +astg_graph *astg; +int restore_marking; +{ + vertex_t *from_state, *to_state; + int nbits, i, m, j, found, idx; + astg_signal **state_signals, *sig_p; + char *from_code, *to_code; + astg_place *place; + astg_trans *to_trans, *from_trans, *trans; + st_table *new_places, *sig_index, *initial, *added, *from_transitions; + astg_generator sgen, pgen, tgen; + marking_pair_t marking_pair; + st_generator *stgen; + astg_marking *initial_marking, *from_marking, *to_marking, *marking; + + idx = 1; + dum_sig = NIL(astg_signal); + dum_i = 1; + + /* get the number of bits */ + from_state = stg_get_start (stg); + from_code = stg_get_state_encoding (from_state); + if (from_code == NIL(char)) { + fprintf (siserr, "No state encoding: define it with astg_encode\n"); + return; + } + nbits = strlen (from_code); + + /* store the initially marked places */ + astg_reset_state_graph (astg); + initial_marking = astg_initial_marking (astg); + initial = st_init_table (st_ptrcmp, st_ptrhash); + astg_foreach_place (astg, pgen, place) { + place->type.place.initial_token = ASTG_FALSE; + if (! astg_get_marked (initial_marking, place)) { + continue; + } + st_insert (initial, (char *) place, NIL(char)); + } + + /* store the initial ASTG signals */ + sig_index = st_init_table (st_ptrcmp, st_ptrhash); + i = 0; + astg_foreach_signal (astg, sgen, sig_p) { + st_insert (sig_index, (char *) sig_p, (char *) i); + i++; + } + + /* create the state variable signals */ + state_signals = ALLOC (astg_signal *, nbits); + for (i = 0; i < nbits; i++) { + state_signals[i] = astg_new_sig (astg, ASTG_OUTPUT_SIG); + } + + added = st_init_table (st_ptrcmp, st_ptrhash); + /* insert the transitions */ + for (m = 0; m < array_n (marking_pairs); m++) { + marking_pair = array_fetch (marking_pair_t, marking_pairs, m); + if (astg_debug_flag > 1) { + fprintf (sisout, "marking pair from %s to %s\n", + marking_pair.from_state, marking_pair.to_state); + fprintf (sisout, "from"); + for (i = 0; i < array_n (marking_pair.from_markings); + i++) { + marking = array_fetch (astg_marking *, + marking_pair.from_markings, i); + fprintf (sisout, " s%s", + bwd_marking_string (marking->marked_places)); + } + fprintf (sisout, "\nto"); + for (i = 0; i < array_n (marking_pair.to_markings); + i++) { + marking = array_fetch (astg_marking *, + marking_pair.to_markings, i); + fprintf (sisout, " s%s", + bwd_marking_string (marking->marked_places)); + } + fprintf (sisout, "\n"); + } + + /* get the state codes */ + from_state = bwd_get_state_by_name (stg, marking_pair.from_state); + assert (from_state != NIL(vertex_t)); + from_code = stg_get_state_encoding (from_state); + + to_state = bwd_get_state_by_name (stg, marking_pair.to_state); + assert (to_state != NIL(vertex_t)); + to_code = stg_get_state_encoding (to_state); + + /* get the places marked in ALL to_marking and NOT in SOME + * from_marking + */ + new_places = st_init_table (st_ptrcmp, st_ptrhash); + if (astg_debug_flag > 1) { + fprintf (sisout, "new marked places:"); + } + astg_foreach_place (astg, pgen, place) { + if (st_is_member (added, (char *) place)) { + continue; + } + /* check if place is marked in ALL to_marking */ + for (j = 0; j < array_n (marking_pair.to_markings); j++) { + to_marking = array_fetch (astg_marking *, + marking_pair.to_markings, j); + if (! astg_get_marked (to_marking, place)) { + break; + } + } + if (j < array_n (marking_pair.to_markings)) { + continue; + } + + /* check if place is marked in ALL from_marking */ + for (j = 0; j < array_n (marking_pair.from_markings); j++) { + from_marking = array_fetch (astg_marking *, + marking_pair.from_markings, j); + if (! astg_get_marked (from_marking, place)) { + break; + } + } + if (j >= array_n (marking_pair.from_markings)) { + continue; + } + + /* skip those places that are not predecessors of a transition + * that is enabled in some to_marking + */ + found = 0; + astg_foreach_output_trans (place, tgen, to_trans) { + /* skip added dummy signal... */ + if (astg_trans_sig (to_trans) == dum_sig) { + continue; + } + + /* check if trans is enabled in SOME to_marking */ + for (j = 0; j < array_n (marking_pair.to_markings); j++) { + to_marking = array_fetch (astg_marking *, + marking_pair.to_markings, j); + if (! astg_disabled_count (to_trans, to_marking)) { + break; + } + } + if (j < array_n (marking_pair.to_markings)) { + found = 1; + } + } + if (! found) { + continue; + } + + st_insert (new_places, (char *) place, NIL(char)); + if (astg_debug_flag > 1) { + fprintf (sisout, " %s", astg_place_name (place)); + } + } + if (astg_debug_flag > 1) { + fprintf (sisout, "\n"); + } + + if (st_count (new_places) == 0) { + fprintf (siserr, "internal error: the STG will not be live:\n"); + fprintf (siserr, "there is no place marked in all\n"); + for (j = 0; j < array_n (marking_pair.to_markings); j++) { + to_marking = array_fetch (astg_marking *, + marking_pair.to_markings, j); + astg_foreach_place (astg, pgen, place) { + if (astg_get_marked (to_marking, place)) { + fprintf (siserr, " %s", astg_place_name (place)); + } + } + fprintf (siserr, "\n"); + } + fprintf (siserr, "that is not marked in some\n"); + for (j = 0; j < array_n (marking_pair.from_markings); j++) { + from_marking = array_fetch (astg_marking *, + marking_pair.from_markings, j); + astg_foreach_place (astg, pgen, place) { + if (astg_get_marked (from_marking, place)) { + fprintf (siserr, " %s", astg_place_name (place)); + } + } + fprintf (siserr, "\n"); + } + + continue; + } + + /* now check what transitions enbled those places */ + from_transitions = st_init_table (st_ptrcmp, st_ptrhash); + if (astg_debug_flag > 1) { + fprintf (sisout, "from transitions:"); + } + astg_foreach_trans (astg, tgen, from_trans) { + /* skip added dummy signal... */ + if (astg_trans_sig (from_trans) == dum_sig) { + continue; + } + + /* check if trans is enabled in SOME from_marking */ + for (j = 0; j < array_n (marking_pair.from_markings); j++) { + from_marking = array_fetch (astg_marking *, + marking_pair.from_markings, j); + if (! astg_disabled_count (from_trans, from_marking)) { + break; + } + } + if (j >= array_n (marking_pair.from_markings)) { + continue; + } + /* check if its fanout is in new_places */ + found = 0; + astg_foreach_output_place (from_trans, pgen, place) { + if (found) { + continue; + } + if (st_is_member (new_places, (char *) place)) { + found = 1; + } + } + if (! found) { + continue; + } + + st_insert (from_transitions, (char *) from_trans, NIL(char)); + if (astg_debug_flag > 1) { + fprintf (sisout, " %s", astg_trans_name (from_trans)); + } + } + if (astg_debug_flag > 1) { + fprintf (sisout, "\n"); + } + if (st_count (from_transitions) == 0) { + fprintf (siserr, "internal error: no from transitions\n"); + } + + add_state_vars (astg, initial_marking, added, initial, from_transitions, + new_places, from_code, to_code, nbits, idx, state_signals); + + idx++; + st_free_table (new_places); + } + + if (restore_marking) { + st_foreach_item (initial, stgen, (char **) &place, NIL(char *)) { + place->type.place.initial_token = ASTG_TRUE; + if (astg_debug_flag > 0) { + fprintf (sisout, "marking place"); + astg_foreach_input_trans (place, tgen, trans) { + fprintf (sisout, " %s", astg_trans_name (trans)); + } + fprintf (sisout, " ->"); + astg_foreach_output_trans (place, tgen, trans) { + fprintf (sisout, " %s", astg_trans_name (trans)); + } + fprintf (sisout, "\n"); + } + } + + astg->has_marking = ASTG_TRUE; + } + else { + astg->has_marking = ASTG_FALSE; + } + + st_free_table (initial); + st_free_table (sig_index); + st_free_table (added); + FREE (state_signals); + idx = 0; + dum_sig = NIL(astg_signal); + dum_i = 0; +} +#endif /* SIS */ diff --git a/sis/astg/bwd_com.c b/sis/astg/bwd_com.c new file mode 100644 index 0000000..bc6c31a --- /dev/null +++ b/sis/astg/bwd_com.c @@ -0,0 +1,1448 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/bwd_com.c,v $ + * $Author: pchong $ + * $Revision: 1.3 $ + * $Date: 2005/03/08 01:07:22 $ + * + */ +#ifdef SIS +/* bwd_com_astg.c -- SIS command interface to bounded wire delay STG + * synthesis sub-package + */ + +#include "sis.h" +#include "astg_int.h" +#include "astg_core.h" +#include "bwd_int.h" +#include "si_int.h" + +static void +bwd_alloc_daemon (astg, dummy) +astg_graph *astg, *dummy; +{ + bwd_t *bwd; + + bwd = ALLOC (bwd_t, 1); + bwd->hazard_list = st_init_table (strcmp, st_strhash); + bwd->slowed_amounts = st_init_table (strcmp, st_strhash); + bwd->pi_names = array_alloc (char *, 0); + + BWD_SET (astg, bwd); +} + +static void +bwd_dup_daemon (new_astg, old_astg) +astg_graph *new_astg, *old_astg; +{ + st_table *old_hazard_list, *old_slowed_amounts; + st_table *new_hazard_list, *new_slowed_amounts; + st_generator *gen; + char *n; + int i; + array_t *old_hazards, *new_hazards, *old_pi_names, *new_pi_names; + hazard_t old_hazard, new_hazard; + double *old_slowed, *new_slowed; + bwd_t *new_bwd, *old_bwd; + + old_bwd = BWD_GET(old_astg); + new_bwd = BWD_GET(new_astg); + + /* get it from the new ASTG, since it is different !! */ + new_bwd->change_count = astg_change_count (new_astg); + + new_hazard_list = new_bwd->hazard_list; + old_hazard_list = old_bwd->hazard_list; + + if (old_hazard_list != NIL(st_table)) { + st_foreach_item (old_hazard_list, gen, &n, (char **) &old_hazards) { + if (n != NIL(char) && old_hazards != NIL(array_t)) { + new_hazards = array_alloc (hazard_t, 0); + for (i = 0; i < array_n (old_hazards); i++) { + old_hazard = array_fetch (hazard_t, old_hazards, i); + bwd_dup_hazard (&new_hazard, &old_hazard); + array_insert_last (hazard_t, new_hazards, new_hazard); + } + st_insert (new_hazard_list, util_strsav (n), + (char *) new_hazards); + } + } + } + + new_slowed_amounts = new_bwd->slowed_amounts; + old_slowed_amounts = old_bwd->slowed_amounts; + + if (old_slowed_amounts != NIL(st_table)) { + st_foreach_item (old_slowed_amounts, gen, &n, (char **) &old_slowed) { + if (n != NIL(char) && old_slowed != NIL(double)) { + new_slowed = ALLOC (double, 1); + *new_slowed = *old_slowed; + st_insert (new_slowed_amounts, util_strsav (n), + (char *) new_slowed); + } + } + } + + old_pi_names = old_bwd->pi_names; + new_pi_names = new_bwd->pi_names; + if (old_pi_names != NIL(array_t)) { + for (i = 0; i < array_n (old_pi_names); i++) { + array_insert_last (char *, new_pi_names, + util_strsav (array_fetch (char *, old_pi_names, i))); + } + } +} + +static void +bwd_free_daemon (astg, dummy) +astg_graph *astg, *dummy; +{ + bwd_t *bwd; + st_table *hazard_list, *slowed_amounts; + st_generator *gen; + char *n; + int i; + array_t *hazards, *pi_names; + hazard_t hazard; + double *slowed; + + bwd = BWD_GET (astg); + hazard_list = bwd->hazard_list; + slowed_amounts = bwd->slowed_amounts; + pi_names = bwd->pi_names; + + if (hazard_list != NIL(st_table)) { + st_foreach_item (hazard_list, gen, &n, (char **) &hazards) { + if (n != NIL(char)) { + FREE(n); + } + if (hazards != NIL(array_t)) { + for (i = 0; i < array_n (hazards); i++) { + hazard = array_fetch (hazard_t, hazards, i); + bwd_free_hazard (&hazard); + } + array_free (hazards); + } + } + st_free_table (hazard_list); + } + + if (slowed_amounts != NIL(st_table)) { + st_foreach_item (slowed_amounts, gen, &n, (char **) &slowed) { + if (n != NIL(char)) { + FREE (n); + } + if (slowed != NIL(double)) { + FREE (slowed); + } + } + st_free_table (slowed_amounts); + } + if (pi_names != NIL (array_t)) { + for (i = 0; i < array_n (pi_names); i++) { + n = array_fetch (char *, pi_names, i); + FREE (n); + } + array_free (pi_names); + } + + FREE(bwd); + + BWD_SET (astg, NIL(bwd_t)); +} + +static void +bwd_invalid_daemon (astg, dummy) +astg_graph *astg, *dummy; +{ + bwd_free_daemon (astg, dummy); + bwd_alloc_daemon (astg, dummy); +} + +/* global initialization routine */ +void +bwd_cmds () +{ + com_add_command ("astg_to_f", com_bwd_astg_to_f, 1); + com_add_command ("astg_to_stg", com_bwd_astg_to_stg, 1); + com_add_command ("astg_slow", com_bwd_astg_slow_down, 1); + com_add_command ("astg_stg_scr", com_bwd_astg_stg_scr, 1); + com_add_command ("stg_to_astg", com_bwd_stg_to_astg, 1); + com_add_command ("astg_state_min", com_bwd_astg_state_minimize, 1); + com_add_command ("astg_add_state", com_bwd_astg_add_state, 1); + com_add_command ("astg_encode", com_bwd_astg_encode, 1); + com_add_command ("_stg_scc", com_stg_scc, 0); + com_add_command ("_write_sg", com_bwd_astg_write_sg, 0); + + astg_register_daemon (ASTG_DAEMON_ALLOC, bwd_alloc_daemon); + astg_register_daemon (ASTG_DAEMON_DUP, bwd_dup_daemon); + astg_register_daemon (ASTG_DAEMON_INVALID, bwd_invalid_daemon); + astg_register_daemon (ASTG_DAEMON_FREE, bwd_free_daemon); +} + +/* Produce on-set and offset covers for the next state function of each + * output signal in the STG, and generate the list of potential hazards. + * Also each next-state function is decomposed into two primary oututs, one for + * the set input and one for the reset input of SR flip-flops. Primary outputs + * are added so that optimization does not throw these away... + * If we want to make S and R disjoint, then this is done also for purely + * combinational output signals (by creating a flip-flop with equation + * q = s q + s), and we make the set and reset functions disjoint, by + * using the equation q = m q + s q + s (redundant, but we use scan FF's + * anyway). + */ + +static char *astg_to_f_usage[] = { + "usage: %s [-v debug_level] [-f] [-o] [-l] [-d] [-h] [PO_name ...]", + " Generates a function for each output signal directly from the STG", + " -f: force even if CSC problem (vertices assigned to on-set)", + " -o: use the old DAC algorithm (default: the more recent one)", + " -r: keep PI's without fanout (default: remove them)", + " -l: does not create the asynchronous latches (for debugging)", + " -d: the functions of S and R are made disjoint", + " -h: do not check potential hazards", + " PO_name: ensure mapping of the specified signals into SR flip-flops", + NULL +}; + +int +com_bwd_astg_to_f (network_p,argc, argv) +network_t **network_p; +int argc; +char **argv; +{ + int c, result, flag, index, use_old, i, find_hazards; + int keep_red, use_s_r, disjoint, do_latch, force; + astg_retval status; + astg_graph *astg; + astg_signal *sig_p; + astg_generator sgen; + astg_scode state; + array_t *fanin, *to_del, *pi_names, *node_vec; + node_t *node; + st_table *hazard_list, *s_r_names; + char *name; + latch_t *l; + + result = 0; + flag = 0; + use_old = 0; + keep_red = 0; + use_s_r = 0; + disjoint = 0; + force = 0; + do_latch = 1; + find_hazards = 1; + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"forv:dlh")) != EOF) { + switch (c) { + case 'f': force = 1; break; + case 'o': use_old = 1; break; + case 'r': keep_red = 1; break; + case 'l': do_latch = 0; break; + case 'd': disjoint = 1; break; + case 'h': find_hazards = 0; break; + case 'v': flag = atoi (util_optarg); break; + default : result = 1; break; + } + } + s_r_names = st_init_table (strcmp, st_strhash); + for (; util_optind < argc; util_optind++) { + st_insert (s_r_names, argv[util_optind], NIL(char)); + } + if (result) { + astg_usage (astg_to_f_usage,argv[0]); + astg_debug_flag = 0; + return result; + } + + if (flag > 100) { + astg_debug_flag = flag; + } + + if ((astg=astg_current (*network_p)) == NULL) { + astg_debug_flag = 0; + return 1; + } + + /* look for the initial marking, and if not defined find one (it might not + * always work..) + */ + if (! astg->has_marking) { + if (! astg_one_sm_token(astg)) { + fprintf (siserr, "cannot find the initial state\n"); + fprintf (siserr, "please define one in the STG with .marking\n"); + astg_debug_flag = 0; + return 1; + } + } + + /* derive the state graph by token flow */ + status = astg_initial_state (astg, &state); + if (status != ASTG_OK && status != ASTG_NOT_USC) { + fprintf (siserr, "inconsistency during token flow\n"); + astg_sel_show (astg); + astg_debug_flag = 0; + return 1; + } + + astg_debug_flag = flag; + name_mode = LONG_NAME_MODE; + BWD_GET(astg)->change_count = astg_change_count(astg); + if (find_hazards) { + hazard_list = BWD_GET(astg)->hazard_list; + } + else { + hazard_list = NIL(st_table); + } + network_set_name (*network_p, util_strsav (astg_name (astg))); + + /* remove all nodes from the old network */ + to_del = network_dfs_from_input (*network_p); + for (i = 0; i < array_n (to_del); i++) { + node = array_fetch (node_t *, to_del, i); + l = latch_from_node (node); + if (l != NIL(latch_t)) { + network_delete_latch(*network_p, l); + } + network_delete_node (*network_p, node); + } + array_free (to_del); + + /* create the PI's and PO's of the network */ + fanin = array_alloc (node_t *, 0); + pi_names = BWD_GET(astg)->pi_names; + if (astg_debug_flag > 1) { + fprintf (sisout, "inputs "); + } + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + + if (astg_signal_type (sig_p) == ASTG_INPUT_SIG) { + name = bwd_po_name (sig_p->name); + } + else { + name = bwd_fake_pi_name (sig_p->name); + } + + node = node_alloc (); + network_add_primary_input(*network_p, node); + network_change_node_name (*network_p, node, util_strsav (name)); + + if (astg_debug_flag > 1) { + fprintf (sisout, "%s (%x) ", node_long_name (node), + astg_state_bit (sig_p)); + } + array_insert_last (node_t *, fanin, node); + array_insert_last (char *, pi_names, util_strsav (bwd_po_name (name))); + } + if (astg_debug_flag > 1) { + fprintf (sisout, "\n"); + } + + /* now generate the next-state for each non-input signal */ + index = 0; + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + if (astg_signal_type (sig_p) == ASTG_OUTPUT_SIG || + astg_signal_type (sig_p) == ASTG_INTERNAL_SIG) { + if (astg_debug_flag > 1) { + fprintf (sisout, + "generating function for signal %s\n", sig_p->name); + } + use_s_r = st_is_member (s_r_names, sig_p->name) || + st_is_member (s_r_names, "*"); + bwd_astg_to_f (*network_p, astg, sig_p, fanin, state, + hazard_list, index, use_old, use_s_r, disjoint, force); + } + index++; + } + + if (do_latch) { + /* create the latches */ + bwd_astg_latch (*network_p, ASYNCH, keep_red); + } + + astg_debug_flag = 0; + + if (result) { + astg_usage (astg_to_f_usage,argv[0]); + } + + astg_debug_flag = 0; + st_free_table (s_r_names); + return result; +} + +/* Transform an AFSM into an AFSM with the single cube restriction + */ +static char *astg_stg_scr_usage[] = { + "usage: %s [-v debug_level]", + " Transforms an STG into an STG with the Single Cube Restriction", + NULL +}; + +int +com_bwd_astg_stg_scr (network_p,argc, argv) +network_t **network_p; +int argc; +char **argv; +{ + int c, result; + graph_t *stg; + lsGen gen; + vertex_t *state; + astg_graph *astg; + network_t *new_net; + + astg_debug_flag = 0; + result = 0; + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"v:")) != EOF) { + switch (c) { + case 'v': astg_debug_flag = atoi (util_optarg); break; + default : result = 1; break; + } + } + + if (result || network_stg(*network_p) == NIL(graph_t)) { + astg_usage (astg_stg_scr_usage,argv[0]); + astg_debug_flag = 0; + return 1; + } + + stg = bwd_stg_scr (network_stg(*network_p)); + if (stg == NIL(graph_t)) { + return 1; + } + network_set_stg (*network_p, stg); + + astg_debug_flag = 0; + return result; +} + +/* Transform an AFSM into an STG. Experimental. + */ +static char *stg_to_astg_usage[] = { + "usage: %s [-v debug_level]", + " Generates an STG from a synchronous state transition graph.", + NULL +}; + +int +com_bwd_stg_to_astg (network_p,argc, argv) +network_t **network_p; +int argc; +char **argv; +{ + int c, result; + astg_graph *astg; + + astg_debug_flag = 0; + result = 0; + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"v:")) != EOF) { + switch (c) { + case 'v': astg_debug_flag = atoi (util_optarg); break; + default : result = 1; break; + } + } + + if (result || network_stg(*network_p) == NIL(graph_t)) { + astg_usage (stg_to_astg_usage,argv[0]); + astg_debug_flag = 0; + return 1; + } + + astg = bwd_stg_to_astg(network_stg(*network_p), *network_p); + if (astg == NIL(astg_graph)) { + return 1; + } + + astg_set_current (network_p, astg, ASTG_TRUE); + + astg_debug_flag = 0; + return result; +} + +/* Transform an STG into a state graph through token flow. Experimental. + */ +static char *astg_to_stg_usage[] = { + "usage: %s [-v debug_level] [-o] [-i] [-m]", + " Generates a synchronous state transition graph from the STG.", + " -o: the OUTPUT signals are NOT used as INPUTS of the graph", + " -m: perform a pre-minimization of the STG (for state encoding)", + NULL +}; + +int +com_bwd_astg_to_stg (network_p,argc, argv) +network_t **network_p; +int argc; +char **argv; +{ + int c, result, use_output, pre_minimize, d, i, len, j; + astg_retval status; + graph_t *stg; + astg_graph *astg; + astg_generator sgen; + astg_scode code; + astg_signal *sig_p; + array_t *inputs, *outputs, *to_del, *components, *component; + node_t *node; + latch_t *l; + char *name, *str; + vertex_t *state; + + d = astg_debug_flag = 0; + result = 0; + use_output = 1; + pre_minimize = 0; + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"v:om")) != EOF) { + switch (c) { + case 'v': d = atoi (util_optarg); break; + case 'o': use_output = 0; break; + case 'm': pre_minimize = 1; break; + default : result = 1; break; + } + } + + if (result) { + astg_usage (astg_to_stg_usage,argv[0]); + astg_debug_flag = 0; + return result; + } + if ((astg=astg_current (*network_p)) == NULL) { + astg_debug_flag = 0; + return 1; + } + + if (! astg->has_marking) { + if (! astg_one_sm_token(astg)) { + fprintf (siserr, "cannot find the initial state\n"); + fprintf (siserr, "please define one in the STG with .marking\n"); + return 1; + } + } + + /* derive the state graph by token flow */ + status = astg_initial_state (astg, &code); + if (status != ASTG_OK && status != ASTG_NOT_USC) { + fprintf (siserr, "inconsistency during token flow\n"); + astg_sel_show (astg); + return 1; + } + + astg_debug_flag = d; + /* store the input and output names */ + inputs = array_alloc (char *, 0); + if (astg_debug_flag > 0) { + fprintf (sisout, "inputs "); + } + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + if (use_output || astg_signal_type (sig_p) == ASTG_INPUT_SIG) { + if (astg_signal_type (sig_p) == ASTG_INPUT_SIG) { + name = util_strsav (bwd_po_name (sig_p->name)); + } + else { + name = util_strsav (bwd_fake_pi_name (sig_p->name)); + } + if (astg_debug_flag > 0) { + fprintf (sisout, "%s ", name); + } + array_insert_last (char *, inputs, name); + } + } + if (astg_debug_flag > 0) { + fprintf (sisout, "\n"); + } + outputs = array_alloc (char *, 0); + if (astg_debug_flag > 0) { + fprintf (sisout, "outputs "); + } + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + if (astg_signal_type (sig_p) == ASTG_OUTPUT_SIG || + astg_signal_type (sig_p) == ASTG_INTERNAL_SIG) { + name = util_strsav (bwd_fake_po_name (sig_p->name)); + if (astg_debug_flag > 0) { + fprintf (sisout, "%s ", name); + } + array_insert_last (char *, outputs, name); + } + } + if (astg_debug_flag > 0) { + fprintf (sisout, "\n"); + } + /* produce the state transition graph */ + stg = network_stg(*network_p); + if (stg != NIL(graph_t)) { + stg_free (stg); + } + stg = bwd_astg_to_stg (astg, code, use_output, pre_minimize); + if (stg == NIL(graph_t)) { + return 1; + } + if (!stg_check(stg)) { + fprintf (siserr, "stg check failed\n"); + astg_debug_flag = 0; + return 1; + } + components = graph_scc (stg); + if (array_n (components) > 1) { + fprintf (siserr, + "internal error: the state transition graph is not strongly connected\n"); + if (astg_debug_flag > 0) { + for (i = 0; i < array_n (components); i++) { + component = array_fetch (array_t *, components, i); + fprintf (sisout, "%d:", i); + len = 4; + for (j = 0; j < array_n (component); j++) { + state = array_fetch (vertex_t *, component, j); + str = stg_get_state_name (state); + len += strlen (str) + 1; + if (len > 80) { + fprintf (sisout, "\n "); + len = strlen (str) + 4; + } + fprintf (sisout, " %s", str); + } + fprintf (sisout, "\n"); + } + } + array_free (components); + return 1; + } + array_free (components); + /* remove all nodes from the old network */ + to_del = network_dfs_from_input (*network_p); + for (i = 0; i < array_n (to_del); i++) { + node = array_fetch (node_t *, to_del, i); + l = latch_from_node (node); + if (l != NIL(latch_t)) { + network_delete_latch(*network_p, l); + } + network_delete_node (*network_p, node); + } + array_free (to_del); + + network_set_stg (*network_p, stg); + + stg_set_names (stg, inputs, /* input names */ 1); + stg_set_names (stg, outputs, /* output names */ 0); + + astg_debug_flag = 0; + return result; +} + +/* Check if potential hazards actually are possible given the mapped network + * delays, and if so remove them by selectively slowing down STG signals. + * Currently we insert inverter pairs at the network INPUTS, while it would be + * better in principle to insert them at the outputs. But the delay tracing + * would then become much clumsier, and the final result is the same anyway... + * Parameter of the procedure: + * - External delay file: if the other subcircuits have been synthesized + * separately, this file gives the relevant minimum input->output delays. + * The file is also updated with our own delays. + * - Tolerance: if the difference between paths is greater than this amount, + * then we have a hazard (> 0 means stricter, more conservative checking, + * < 0 means overly optimistic...). + * - Default minimum delay for external signals (if they are not found in the + * external delay file). Usually the delay of an inverter or of an inverter + * pair, but 0 by default (overly pessimistic). + * - By default an all-pair shortest path is used to infer unspecified delays + * from those measured or given. If this flag is set, then this algorithm + * is disabled (resulting in a pessimistic result, on average). + */ + +static char *slow_down_usage[] = { + "usage: %s [[-f|-F] filename] [-d default_delay] [-s] [-i] [-u] [-l]", + " [-m min_delay_factor] [-t tolerance]", + " Removes hazards, by adding inverter pairs", + " -f: specifies the filename containing the minimum delays", + " between external signals", + " -F: same as above but update the file with the new estimates", + " -d: specifies the default mimimum delay between external signals,", + " when not available from the file (default 0)", + " -s: do not use the shorthest path algorithm to compute d3", + " -i: iterate the slowing down process (slower)", + " -u: do not remove hazards, only update the external delay file", + " -m: multiply all minimum delays by the specified factor", + " (0 < min_delay_factor <= 1)", + " -t: specifies the time tolerance for hazard checking (default 0)", + " -l: use the linear programming solver for hazard removal", + " -L: use the LINDO linear programming solver for hazard removal", + " -b: use bounding to reduce the linear program calls", + NULL +}; + +int +com_bwd_astg_slow_down (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + int c, update, do_slow, do_bound, lindo, lp, i; + double tol, default_del, min_delay_factor; + int result = 0; + int shortest_path, iterate; + FILE *file; + char *filename, *name; + st_table *external_del, *to_table, *hazard_list, *slowed_amounts, *pi_index; + array_t *pi_names; + char pi_buf[80], po_buf[80], buf[256]; + char *pi_name, *po_name; + min_del_t delay, *delay_p; + st_generator *pigen, *pogen; + astg_graph *astg; + lsGen gen; + node_t *node; + + tol = 0; + default_del = 0; + min_delay_factor = 1; + shortest_path = 1; + iterate = 0; + update = 0; + do_slow = 1; + lp = 0; + lindo = 0; + do_bound = 0; + filename = NIL(char); + external_del = NIL(st_table); + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"bv:d:f:F:im:st:ulL")) != EOF) { + switch (c) { + case 'b': do_bound = 1; break; + case 'l': lp = 1; break; + case 'L': lp = 1; lindo = 1; break; + case 'v': astg_debug_flag = atoi (util_optarg); break; + case 'd': default_del = atof (util_optarg); break; + case 'i': iterate = 1; break; + case 'm': min_delay_factor = atof (util_optarg); break; + case 's': shortest_path = 0; break; + case 't': tol = atof (util_optarg); break; + case 'f': filename = util_optarg; break; + case 'u': do_slow = 0; break; + case 'F': filename = util_optarg; update = 1; break; + default: result = 1; + } + } + if (min_delay_factor <= 0 || min_delay_factor > 1) { + result = 1; + } + if (result) { + astg_usage (slow_down_usage,argv[0]); + astg_debug_flag = 0; + return result; + } + + if ((astg=astg_current (*network_p)) == NULL) { + astg_debug_flag = 0; + return 1; + } + + if (astg_change_count(astg) != BWD_GET(astg)->change_count) { + fprintf (siserr, "the ASTG was changed since the last astg_to_f call\n"); + astg_debug_flag = 0; + return 1; + } + + hazard_list = BWD_GET(astg)->hazard_list; + + /* open the external delay file and read it in the symbol table (see + * bwd_slow.c for details on the table organization) + */ + if (filename != NIL(char)) { + external_del = st_init_table (strcmp, st_strhash); + + file = com_open_file (filename,"r",NULL,0); + if (file == NULL) { + fprintf (siserr,"Warning: cannot read external delay file '%s'\n", + filename); + } + else { + while (fgets (buf, sizeof(buf), file) != NULL) { + if (buf[0] == '#') { + continue; + } + if (sscanf (buf, "%s %s %lf %lf %lf %lf\n", + pi_buf, po_buf, &delay.rise.rise, &delay.rise.fall, + &delay.fall.rise, &delay.fall.fall) != 6) { + fprintf (siserr, "Error: incorrect delay file line:\n"); + fprintf (siserr, "%s", buf); + continue; + } + if (delay.rise.rise < 0) { + delay.rise.rise = INFINITY; + } + if (delay.rise.fall < 0) { + delay.rise.fall = INFINITY; + } + if (delay.fall.rise < 0) { + delay.fall.rise = INFINITY; + } + if (delay.fall.fall < 0) { + delay.fall.fall = INFINITY; + } + if (! st_lookup (external_del, pi_buf, (char **) &to_table)) { + to_table = st_init_table (strcmp, st_strhash); + st_insert (external_del, util_strsav (pi_buf), + (char *) to_table); + } + if (st_lookup (to_table, po_buf, (char **) &delay_p)) { + fprintf (siserr, + "Warning: duplicate delay table entry: %s -> %s\n", + pi_buf, po_buf); + continue; + } + if (astg_debug_flag > 1) { + fprintf (sisout, "Reading delay %s -> %s ++ %f +- %f -+ %f -- %f\n", + pi_buf, po_buf, delay.rise.rise, delay.rise.fall, + delay.fall.rise, delay.fall.fall); + } + delay_p = ALLOC (min_del_t, 1); + *delay_p = delay; + st_insert (to_table, util_strsav (po_buf), (char *) delay_p); + } + fclose (file); + } + } + + /* do an initial delay trace (for delay computations) */ + if (! delay_trace (*network_p, DELAY_MODEL_LIBRARY)) { + fprintf (siserr, "%s\n", error_string ()); + astg_debug_flag = 0; + return 1; + } + if (lp) { + if (external_del == NIL(st_table)) { + external_del = st_init_table (strcmp, st_strhash); + } + pi_index = st_init_table (strcmp, st_strhash); + pi_names = BWD_GET(astg)->pi_names; + if (astg_debug_flag > 1) { + fprintf (sisout, "signal order:"); + } + for (i = 0; i < array_n (pi_names); i++) { + name = array_fetch (char *, pi_names, i); + st_insert (pi_index, name, (char *) i); + if (astg_debug_flag > 1) { + fprintf (sisout, " %s", name); + } + } + if (astg_debug_flag > 1) { + fprintf (sisout, "\n"); + } + bwd_lp_slow (astg, *network_p, hazard_list, external_del, + pi_index, tol, default_del, min_delay_factor, do_bound, lindo); + } + else { + slowed_amounts = BWD_GET(astg)->slowed_amounts; + /* remove hazards */ + bwd_slow_down (*network_p, hazard_list, slowed_amounts, external_del, tol, + default_del, min_delay_factor, shortest_path, iterate, do_slow); + } + + /* reset arrival times on PIs */ + foreach_primary_input (*network_p, gen, node) { + delay_set_parameter (node, DELAY_ARRIVAL_RISE, (double) -1); + delay_set_parameter (node, DELAY_ARRIVAL_FALL, (double) -1); + } + + /* write back the (possibly updated) external delay table */ + if (update && filename != NIL(char)) { + file = com_open_file (filename,"w",NULL,0); + if (file == NULL) { + fprintf (siserr,"Warning: cannot write external delay file '%s'\n", + filename); + } + else { + fprintf (file, "# signal1 signal2 ++del +-del -+del --del\n"); + st_foreach_item (external_del, pigen, (char **) &pi_name, + (char **) &to_table) { + st_foreach_item (to_table, pogen, (char **) &po_name, + (char **) &delay_p) { + fprintf (file, "%s %s %lf %lf %lf %lf\n", + pi_name, po_name, delay_p->rise.rise, delay_p->rise.fall, + delay_p->fall.rise, delay_p->fall.fall); + if (astg_debug_flag > 1) { + fprintf (sisout, "Writing delay %s -> %s ++ %f +- %f -+ %f -- %f\n", + pi_name, po_name, delay_p->rise.rise, delay_p->rise.fall, + delay_p->fall.rise, delay_p->fall.fall); + } + } + } + fclose (file); + } + } + if (external_del != NIL(st_table)) { + st_foreach_item (external_del, pigen, (char **) &pi_name, + (char **) &to_table) { + st_foreach_item (to_table, pogen, (char **) &po_name, + (char **) &delay_p) { + FREE (delay_p); + FREE (po_name); + } + FREE (pi_name); + st_free_table (to_table); + } + st_free_table (external_del); + } + astg_debug_flag = 0; + return result; +} + + +/* Minimize the flow table corresponding to an ASTG, then find a minimum + * set of signals to distinguish among non-equivalent state classes. + * The STG associated with the network can the be encoded using Tracey's + * algorithm. + * The equivalent state information (as found by the state minimizer) is stored + * in the "equiv_states" structure. + */ +static char *astg_state_minimize_usage[] = { + "usage: %s [-v debug_level] [-p minimized_file] [-c \"command\"]", + " [-b|-B] [-g|-G] [-u] [-m|-M] [-o #] [-f signal_cost_file]", + " Minimizes the flow table associated with the STG", + " -c: use the specified command for flow table minimization", + " (default: \"sred -c\")", + " -B: use BDDs to find the set of partitioning signals", + " (default: iteratively improve the set)", + " -b: use BDDs to find the initial set of partitioning signals", + " (default: all the signals if removing, no signals if adding)", + " -M: use minimum cover to find the set of partitioning signals", + " (default: iteratively improve the set)", + " -o: if -M is specified, defines the binate covering option", + " -m: use minimum cover to find the initial set of partitioning signals", + " (default: all the signals if removing, no signals if adding)", + " -g: use a greedy algorithm to improve the initial set", + " (default: use exhaustive branch and bound)", + " -G: use a VERY greedy algorithm to improve the initial set", + " (default: use exhaustive branch and bound)", + " -u: add signals to an initially empty set", + " (default: remove signals from the initial set)", + " -p: do not call the minimizer, just read the specified minimized file", + NULL +}; + +int +com_bwd_astg_state_minimize (network_p,argc, argv) +network_t **network_p; +int argc; +char **argv; +{ + int c, result, cost; + int use_mincov, greedy, go_down, mincov_option, use_mdd, premin; + graph_t *stg, *red_stg; + astg_graph *astg; + equiv_t *equiv_states; + FILE *to, *from; + char command[1024]; + char infile[1024]; + char outfile[1024]; + st_table *sig_cost; + FILE *sig_file; + st_generator *stgen; + char buf[80], *str; + int tempfd; + + strcpy(infile, "/usr/tmp/astg_in.XXXXXX"); + tempfd = mkstemp(infile); + if(tempfd == -1) { + fprintf(siserr, "error: cannot open temporary file\n"); + return 1; + } + close(tempfd); + strcpy(outfile, "/usr/tmp/astg_out.XXXXXX"); + tempfd = mkstemp(outfile); + if(tempfd == -1) { + fprintf(siserr, "error: cannot open temporary file\n"); + unlink(infile); + return 1; + } + close(tempfd); + (void) strcpy (command, "sred -c "); + + astg_debug_flag = 0; + result = 0; + use_mincov = 0; + greedy = 0; + go_down = 1; + mincov_option = 4096; + use_mdd = 0; + premin = 0; + sig_file = NIL(FILE); + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"bBgGmMuf:o:v:c:p:")) != EOF) { + switch (c) { + case 'f': + sig_file = fopen (util_optarg, "r"); + if (sig_file == NULL) { + perror (util_optarg); + result = 1; + } + break; + case 'c': + strcpy(command, util_optarg); + break; + case 'p': premin = 1; strcpy (outfile, util_optarg); break; + case 'b': use_mdd = 1; break; + case 'B': use_mdd = 2; break; + case 'u': go_down = 0; break; + case 'g': greedy = 1; break; + case 'G': greedy = 2; break; + case 'm': use_mincov = 1; break; + case 'M': use_mincov = 2; break; + case 'o': mincov_option = atoi (util_optarg); break; + case 'v': astg_debug_flag = atoi (util_optarg); break; + default : result = 1; break; + } + } + if ((greedy || use_mincov) && ! go_down) { + result = 1; + } + + if (result) { + astg_usage (astg_state_minimize_usage,argv[0]); + astg_debug_flag = 0; + return result; + } + + strcat(command, " < "); + strcat(command, infile); + strcat(command, " > "); + strcat(command, outfile); + + if ((astg=astg_current (*network_p)) == NULL) { + astg_debug_flag = 0; + return 1; + } + + stg = network_stg(*network_p); + if (stg == NIL(graph_t)) { + fprintf (siserr, "No State Transition Graph (use astg_to_stg)\n"); + astg_debug_flag = 0; + return 1; + } + + if ((to = fopen(infile, "w")) == NULL) { + (void) fprintf(siserr, "error: can not open temporary file - %s\n", infile); + (void) unlink(infile); + (void) unlink(outfile); + return 1; + } + + if (!write_kiss(to, network_stg(*network_p))) { + (void) fprintf(siserr, "error in write_kiss\n"); + (void) fclose(to); + (void) unlink(infile); + (void) unlink(outfile); + return 1; + } + (void) fclose(to); + + if (premin) { + (void) fprintf(siserr, + "please issue\n%s\nand then\nkill -CONT %d\n", command, getpid ()); + kill (getpid (), SIGSTOP); + (void) fprintf(siserr, "continuing\n"); + } + else { + if (system(command)) { + (void) fprintf(siserr, + "state minimization program returned non-zero exit status\n%s\n", + command); + (void) unlink(infile); + (void) unlink(outfile); + return 1; + } + } + + if ((from = fopen(outfile, "r")) == NULL) { + (void) fprintf(siserr, "error: can not open output file - %s\n", outfile); + (void) unlink(infile); + (void) unlink(outfile); + return 1; + } + + equiv_states = bwd_read_equiv_states (from, stg); + if (equiv_states == NIL(equiv_t)) { + (void) fprintf(siserr, "Error in state minimization program output\n"); + (void) fclose(from); + (void) unlink(infile); + (void) unlink(outfile); + return 1; + } + + (void) fclose(from); + (void) unlink(infile); + if (! premin) { + (void) unlink(outfile); + } + + sig_cost = NIL(st_table); + if (sig_file) { + sig_cost = st_init_table (strcmp, st_strhash); + while (fscanf (sig_file, "%s %d", buf, &cost) > 0) { + st_insert (sig_cost, util_strsav (buf), (char *) cost); + } + fclose (sig_file); + } + + red_stg = bwd_state_minimize (astg, equiv_states, use_mincov, greedy, + go_down, mincov_option, use_mdd, sig_cost); + + if (sig_cost != NIL(st_table)) { + st_foreach_item (sig_cost, stgen, (char **) &str, NIL(char*)) { + FREE (str); + } + st_free_table (sig_cost); + } + + if (red_stg == NIL(graph_t)) { + astg_debug_flag = 0; + return 1; + } + + stg_free (stg); + + if (!stg_check(red_stg)) { + fprintf (siserr, "stg check failed\n"); + astg_debug_flag = 0; + return 1; + } + network_set_stg (*network_p, red_stg); + + astg_debug_flag = 0; + return result; +} + +/* Add state variables to distinguish between non-equivalent markings + */ +static char *astg_add_state_usage[] = { + "usage: %s [-v debug_level] [-m]", + " Insert state variables to guarantee Complete State Coding", + " -m: do not preserve the original marking", + NULL +}; + +int +com_bwd_astg_add_state (network_p,argc, argv) +network_t **network_p; +int argc; +char **argv; +{ + int c, result, cost; + int restore_marking; + graph_t *stg; + astg_graph *astg; + + astg_debug_flag = 0; + result = 0; + restore_marking = 1; + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"v:mf")) != EOF) { + switch (c) { + case 'm': restore_marking = 0; break; + case 'v': astg_debug_flag = atoi (util_optarg); break; + default : result = 1; break; + } + } + + if (result) { + astg_usage (astg_add_state_usage,argv[0]); + astg_debug_flag = 0; + return result; + } + if ((astg=astg_current (*network_p)) == NULL) { + astg_debug_flag = 0; + return 1; + } + + stg = network_stg(*network_p); + if (stg == NIL(graph_t)) { + fprintf (siserr, "No State Transition Graph (use astg_encode)\n"); + astg_debug_flag = 0; + return 1; + } + + bwd_add_state (stg, astg, restore_marking); + + return 0; +} + +/* Perform state assignment using Tracey's technique + */ +int +com_bwd_astg_encode(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, user, i, ns, heuristic; + network_t *new_net; + vertex_t *state; + char buf1[80], buf2[80], buf3[80]; + astg_graph *astg; + graph_t *stg; + + g_debug = 0; + enc_summary = 0; + heuristic = 0; + user = 0; + util_getopt_reset(); + + while ((c = util_getopt(argc, argv, "ushv:")) != EOF) { + switch (c) { + case 'h': + heuristic = 1; + break; + case 'u': + user = 1; + break; + case 's': + enc_summary = 1; + break; + case 'v': + g_debug = atoi(util_optarg); + break; + default: + goto usage; + } + } + + astg = astg_current(*network); + + if (user) { + stg = network_stg (*network); + ns = stg_get_num_states (stg); + fprintf (siserr, "give the codes in the form state_name binary_code\n"); + for (i = 0; i < ns; i++) { + fgets (buf1, 80, stdin); + do { + sscanf (buf1, "%s %s", buf2, buf3); + state = stg_get_state_by_name (stg, buf2); + if (state == NIL(vertex_t)) { + fprintf (siserr, "state %s not found\n", buf2); + } + } while (state == NIL(vertex_t)); + stg_set_state_encoding (state, buf3); + } + } + else { + new_net = astg_encode(network_stg(*network), astg, heuristic); + + if (new_net == NIL(network_t)) return 0; + network_set_name(new_net, network_name(*network)); + new_net->stg = stg_dup((*network)->stg); + new_net->astg = astg_dup((*network)->astg); + network_free(*network); + *network = new_net; + } + return 0; + + usage: + (void)fprintf(siserr, "perform hazard-free state assignment\n"); + (void)fprintf(siserr, "encode_tracey [-v #]\n"); + (void)fprintf(siserr, " -u : user-defined codes\n"); + (void)fprintf(siserr, " -s : print summary\n"); + (void)fprintf(siserr, " -v #: debug option\n"); + return 1; +} + +/* Write out a state graph (in the format for Peter Beerel's synthesis system) + */ + +static char *write_sg_usage[] = { + "usage: %s [filename]", + " Writes out a state graph file", + NULL +}; + +int +com_bwd_astg_write_sg (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + int c, result, d, i, len, j; + FILE *file; + astg_retval status; + graph_t *stg; + astg_graph *astg; + astg_generator sgen; + astg_scode code; + astg_signal *sig_p; + array_t *inputs, *outputs; + node_t *node; + latch_t *l; + char *filename, *name, *str; + vertex_t *state; + + d = astg_debug_flag = 0; + result = 0; + filename = NIL(char); + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"v:")) != EOF) { + switch (c) { + case 'v': d = atoi (util_optarg); break; + default : result = 1; break; + } + } + if (util_optind < argc) { + filename = argv[util_optind]; + } + else { + filename = "-"; + } + file = com_open_file (filename,"w",NIL(char *), /* silent */0); + if (file == NIL(FILE)) { + return 1; + } + + + if (result) { + astg_usage (write_sg_usage,argv[0]); + astg_debug_flag = 0; + return result; + } + if ((astg=astg_current (*network_p)) == NULL) { + astg_debug_flag = 0; + return 1; + } + + if (! astg->has_marking) { + if (! astg_one_sm_token(astg)) { + fprintf (siserr, "cannot find the initial state\n"); + fprintf (siserr, "please define one in the STG with .marking\n"); + return 1; + } + } + + /* derive the state graph by token flow */ + status = astg_initial_state (astg, &code); + if (status != ASTG_OK && status != ASTG_NOT_USC) { + fprintf (siserr, "inconsistency during token flow\n"); + astg_sel_show (astg); + return 1; + } + + astg_debug_flag = d; + /* store the input and output names */ + inputs = array_alloc (char *, 0); + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + if (astg_signal_type (sig_p) == ASTG_INPUT_SIG) { + name = util_strsav (bwd_po_name (sig_p->name)); + } + else { + name = util_strsav (bwd_fake_pi_name (sig_p->name)); + } + array_insert_last (char *, inputs, name); + } + outputs = array_alloc (char *, 0); + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + if (astg_signal_type (sig_p) == ASTG_OUTPUT_SIG || + astg_signal_type (sig_p) == ASTG_INTERNAL_SIG) { + name = util_strsav (bwd_fake_po_name (sig_p->name)); + array_insert_last (char *, outputs, name); + } + } + /* produce the state transition graph */ + stg = network_stg(*network_p); + if (stg != NIL(graph_t)) { + stg_free (stg); + } + stg = bwd_astg_to_stg (astg, code, /* use_output */ 1, /* pre_minimize */ 0); + if (stg == NIL(graph_t)) { + return 1; + } + if (!stg_check(stg)) { + fprintf (siserr, "stg check failed\n"); + astg_debug_flag = 0; + return 1; + } + stg_set_names (stg, inputs, /* input names */ 1); + stg_set_names (stg, outputs, /* output names */ 0); + + bwd_write_sg (file, stg, astg); + stg_free (stg); + + if (file != stdout) { + (void) fclose (file); + } + + return 0; +} + +int +com_stg_scc (network_p,argc, argv) +network_t **network_p; +int argc; +char **argv; +{ + graph_t *stg; + array_t *components, *component; + vertex_t *state; + int i, j, len, result, c; + char *str; + + result = 0; + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"v:")) != EOF) { + switch (c) { + case 'v': astg_debug_flag = atoi (util_optarg); break; + default : result = 1; break; + } + } + stg = network_stg(*network_p); + + if (result || stg == NIL(graph_t)) { + astg_debug_flag = 0; + return 0; + } + + components = graph_scc (stg); + fprintf (sisout, "there are %d components\n", array_n (components)); + if (astg_debug_flag > 0) { + for (i = 0; i < array_n (components); i++) { + component = array_fetch (array_t *, components, i); + fprintf (sisout, "%d:", i); + len = 4; + for (j = 0; j < array_n (component); j++) { + state = array_fetch (vertex_t *, component, j); + str = stg_get_state_name (state); + len += strlen (str) + 1; + if (len > 80) { + fprintf (sisout, "\n "); + len = strlen (str) + 4; + } + fprintf (sisout, " %s", str); + } + fprintf (sisout, "\n"); + } + } + + astg_debug_flag = 0; + return 0; +} + + +#endif /* SIS */ diff --git a/sis/astg/bwd_hazard.c b/sis/astg/bwd_hazard.c new file mode 100644 index 0000000..d305f31 --- /dev/null +++ b/sis/astg/bwd_hazard.c @@ -0,0 +1,774 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/bwd_hazard.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +/* Routines to find out potential hazards in the initial two-level + * implementation of the next state function of each STG signal + */ + +#ifdef SIS +#include "sis.h" +#include "astg_int.h" +#include "astg_core.h" +#include "bwd_int.h" + +#define XOR(a,b) (((a)&&!(b))||(!(a)&&(b))) + +#define ONEFROMTOP 0x8000 +#define ONEFROMBOT 0x4000 + +#if 0 +/* compare two strings: used to sort hazards (obsolete) */ +static int +array_strcmp (s1, s2) +char **s1, **s2; +{ + return strcmp (*s1, *s2); +} + +/* compare two set families: used to sort hazards (obsolete) */ +static int +sf_compare (sf1, sf2) +set_family_t *sf1, *sf2; +{ + register pset p1, p2; + register int i, j; + + if (sf1->count != sf2->count) { + return sf1->count - sf2->count; + } + foreachi_set (sf1, j, p1) { + p2 = GETSET (sf2, j); + i = LOOP(p1); + do { + if (p1[i] > p2[i]) { + return 1; + } + else if (p1[i] < p2[i]) { + return -1; + } + } + while (--i > 0); + } + return 0; +} + +#endif + +/* cb_intersect -- form the intersection of a cover with a cube */ +/* hacked from espresso */ + +#define MAGIC 100 /* save 100 cubes before containment */ + +static set_family_t * +cb_intersect(pi, B) +pset pi; +set_family_t *B; +{ + register pset pj, lastj, pt; + set_family_t *T, *Tsave = NULL; + + /* How large should each temporary result cover be ? */ + T = sf_new (MAGIC, B->sf_size); + pt = T->data; + + /* Form pairwise intersection of each cube of A with each cube of B */ + foreach_set(B, lastj, pj) { + if (cdist0(pi, pj)) { + (void) set_and(pt, pi, pj); + if (++T->count >= T->capacity) { + if (Tsave == NULL) + Tsave = sf_contain(T); + else + Tsave = sf_union(Tsave, sf_contain(T)); + T = new_cover(MAGIC); + pt = T->data; + } else + pt += T->wsize; + } + } + + + if (Tsave == NULL) + Tsave = sf_contain(T); + else + Tsave = sf_union(Tsave, sf_contain(T)); + return Tsave; +} + +/* convert an integer representation into a cube representation */ +static void +bit_to_cube (stg, bits, cb) +astg_graph *stg; +astg_scode bits; +pset cb; +{ + register int i = 0; + astg_signal *sig_p; + register astg_scode bit; + astg_generator sgen; + + astg_foreach_signal (stg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + bit = astg_state_bit (sig_p); + PUTINPUT (cb, i, ((bit & bits) ? ONE : ZERO)); + i++; + } +} + +/* compute the value of cover "F" for input minterm "vector" */ +static int +func_value (F, vector) +set_family_t *F; +pset vector; +{ + register pset last, p; + + foreach_set (F, last, p) { + if (cdist0 (vector, p)) { + return 1; + } + } + return 0; +} + +void +bwd_dup_hazard (new, old) +hazard_t *new, *old; +{ + new->dir1 = old->dir1; + new->dir2 = old->dir2; + new->s1 = util_strsav (old->s1); + new->s2 = util_strsav (old->s2); + new->on_cb1 = set_save (old->on_cb1); + new->off_cb1 = set_save (old->off_cb1); + new->on_cb2 = set_save (old->on_cb2); + new->off_cb2 = set_save (old->off_cb2); +} + +void +bwd_free_hazard (haz) +hazard_t *haz; +{ + FREE (haz->s1); + FREE (haz->s2); + set_free (haz->on_cb1); + set_free (haz->off_cb1); + set_free (haz->on_cb2); + set_free (haz->off_cb2); +} + + +/* return 1 if t1 == t2, 0 otherwise */ +static int +same_hazard (t1, t2) +hazard_t *t1, *t2; +{ + if (t1->dir1 != t2->dir1 || + t1->dir2 != t2->dir2) { + return 0; + } + if (strcmp (t1->s1, t2->s1)) { + return 0; + } + if (strcmp (t1->s2, t2->s2)) { + return 0; + } + if (setp_equal (t1->on_cb1, t2->on_cb1)) { + return 0; + } + if (setp_equal (t1->off_cb1, t2->off_cb1)) { + return 0; + } + if (setp_equal (t1->on_cb2, t2->on_cb2)) { + return 0; + } + if (setp_equal (t1->off_cb2, t2->on_cb2)) { + return 0; + } + return 1; +} + +/* Use the algorithm and terminology of the DAC paper. + * if R intersected with cb is empty then return + * for each off-cube in R + * for each on-cube1, on-cube2 in F + * if d(on-cube1, top) == d(off-cube, top) - 1 and + * d(on-cube2, bot) == d(off-cube, bot) - 1 then + * store a potential hazard with the variables changing + * from on-cube1 to off-cube and from on-cube2 to off-cube + */ +static void +store_hazards_old (fanin, hazards, F, R, cb, top, bot, onset, name) +array_t *fanin, *hazards; +set_family_t *F, *R; +pset cb, top, bot; +int onset; +char *name; +{ + pset tmp, off_cube, on_cube1, on_cube2, last, last1, last2; + set_family_t *F_1, *R_1; + int d_top, d_bot, var1, var2, nvar, i, cnt; + char dir1, dir2; + hazard_t hazard, hazard1; + + if (astg_debug_flag > 2) { + fprintf (sisout, "transition cube %s\n", pc1(cb)); + fprintf (sisout, "top %s ", pc1(top)); + fprintf (sisout, "bot %s\n", pc1(bot)); + } + + /* let us restrict F and R to the transition cube "cb" */ + R_1 = cb_intersect (cb, R); + + F_1 = cb_intersect (cb, F); + nvar = F->sf_size / 2; + if (astg_debug_flag > 3) { + fprintf (sisout, "R_1:\n"); + foreach_set (R_1, last, off_cube) { + fprintf (sisout, "%s\n", pc1(off_cube)); + } + fprintf (sisout, "F_1:\n"); + foreach_set (F_1, last, on_cube1) { + fprintf (sisout, "%s\n", pc1(on_cube1)); + } + } + tmp = set_new (F->sf_size); + + /* now for each off-set cube find: + * 1) all on-set cubes at 1 less distance from top; + * 2) all on-set cubes at 1 less distance from bot. + * These cubes must be distance-1 from the offset cube. Add to the hazards + * the variable pair. + */ + foreach_set (R_1, last, off_cube) { + d_top = cdist (off_cube, top); + d_bot = cdist (off_cube, bot); + if (d_top < 0 || d_bot < 0) { + /* something went wrong with the enabling conditions... */ + continue; + } + if (astg_debug_flag > 3) { + fprintf (sisout, "off_cube %s (%d from top %d from bot)\n", + pc1(off_cube), d_top, d_bot); + } + foreach_set (F_1, last1, on_cube1) { + if (cdist (on_cube1, top) == d_top - 1) { + SET (on_cube1, ONEFROMTOP); + } + else { + RESET (on_cube1, ONEFROMTOP); + } + if (cdist (on_cube1, bot) == d_bot - 1) { + SET (on_cube1, ONEFROMBOT); + } + else { + RESET (on_cube1, ONEFROMBOT); + } + } + foreach_set (F_1, last1, on_cube1) { + if (! TESTP (on_cube1, ONEFROMTOP) || + cdist01 (on_cube1, off_cube) != 1) { + continue; + } + INLINEset_and (tmp, on_cube1, off_cube); + for (i = cnt = 0; i < nvar; i++) { + if (GETINPUT (tmp, i) == 0) { + dir1 = (GETINPUT (on_cube1, i) == ZERO) ? '+' : '-'; + var1 = i; + cnt++; + } + } + assert (cnt == 1); + if (astg_debug_flag > 3) { + fprintf (sisout, "on_cube1 %s\n", pc1(on_cube1)); + } + foreach_set (F_1, last2, on_cube2) { + if (on_cube1 == on_cube2 || + ! TESTP (on_cube2, ONEFROMBOT) || + cdist01 (on_cube2, off_cube) != 1) { + continue; + } + INLINEset_and (tmp, on_cube2, off_cube); + for (i = cnt = 0; i < nvar; i++) { + if (GETINPUT (tmp, i) == 0) { + dir2 = (GETINPUT (on_cube2, i) == ONE) ? '+' : '-'; + var2 = i; + cnt++; + } + } + assert (cnt == 1); + if (astg_debug_flag > 3) { + fprintf (sisout, "on_cube2 %s\n", pc1(on_cube2)); + } + + /* check for duplicates */ + hazard.s1 = node_long_name (array_fetch (node_t *, fanin, var1)); + hazard.s2 = node_long_name (array_fetch (node_t *, fanin, var2)); + hazard.dir1 = dir1; + hazard.dir2 = dir2; + hazard.on = onset; + for (i = 0; i < array_n (hazards); i++) { + hazard1 = array_fetch (hazard_t, hazards, i); + if (same_hazard (&hazard, &hazard1)) { + break; + } + } + + if (i >= array_n (hazards)) { + hazard.s1 = util_strsav (hazard.s1); + hazard.s2 = util_strsav (hazard.s2); + array_insert_last (hazard_t, hazards, hazard); + if (astg_debug_flag > 0) { + fprintf (sisout, + "potential hazard %s%c -> %s%c -> %s (%d)\n", hazard.s2, + hazard.dir2, hazard.s1, hazard.dir1, name, hazard.on); + } + } + } + } + } + + /* wrap up */ + sf_free (F_1); + sf_free (R_1); + set_free (tmp); +} + +/* Use the algorithm and terminology of the TCAD paper. + * if F or R intersected with cb is empty then return + * for each off_cube1, off_cube2 in R intersected with cb + * for each on_cube1, on_cube2 in F intersected with cb + * if d(off_cube1, on_cube1) == 1 and + * d(off_cube2, on_cube2) == 1 then + * store a potential hazard with the variables changing + * from on_cube1 to off_cube1 and from off_cube2 to on_cube2 + */ +static void +store_hazards (fanin, hazards, F, R, cb, top, bot, onset, name) +array_t *fanin, *hazards; +set_family_t *F, *R; +pset cb, top, bot; +int onset; +char *name; +{ + pset tmp, off_cube1, off_cube2, on_cube1, on_cube2; + set_family_t *F_1, *R_1; + int var1, var2, nvar, i, off_i1, off_i2, on_i1, on_i2; + int top_to_off1, top_to_off2, bot_to_off1, bot_to_off2; + int top_to_on1, top_to_on2, bot_to_on1, bot_to_on2; + char dir1, dir2; + hazard_t hazard, hazard1; + + if (astg_debug_flag > 2) { + fprintf (sisout, "transition cube %s\n", pc1(cb)); + fprintf (sisout, "top %s ", pc1(top)); + fprintf (sisout, "bot %s\n", pc1(bot)); + } + + /* let us restrict F and R to the transition cube "cb" */ + R_1 = cb_intersect (cb, R); + if (! R_1->count) { + if (astg_debug_flag > 2) { + fprintf (sisout, "R_1 empty: no need to check for hazards\n"); + } + sf_free (R_1); + return; + } + + F_1 = cb_intersect (cb, F); + if (! F_1->count) { + if (astg_debug_flag > 2) { + fprintf (sisout, "F_1 empty: no need to check for hazards\n"); + } + sf_free (F_1); + sf_free (R_1); + return; + } + + nvar = F->sf_size / 2; + if (astg_debug_flag > 3) { + fprintf (sisout, "F_1:\n"); + foreachi_set (F_1, on_i1, on_cube1) { + fprintf (sisout, "%s\n", pc1(on_cube1)); + } + fprintf (sisout, "R_1:\n"); + foreachi_set (R_1, off_i1, off_cube1) { + fprintf (sisout, "%s\n", pc1(off_cube1)); + } + } + tmp = set_new (F->sf_size); + + foreachi_set (R_1, off_i1, off_cube1) { + top_to_off1 = cdist (top, off_cube1); + bot_to_off1 = cdist (bot, off_cube1); + if (astg_debug_flag > 3) { + fprintf (sisout, "off_cube1 %s (%d from top %d from bot)\n", + pc1(off_cube1), top_to_off1, bot_to_off1); + } + + foreachi_set (R_1, off_i2, off_cube2) { + top_to_off2 = cdist (top, off_cube2); + bot_to_off2 = cdist (bot, off_cube2); + /* make sure that off_cube1 is closer to top and off_cube2 is + * closer to bot + */ + if (top_to_off2 < top_to_off1 || bot_to_off1 < bot_to_off2) { + continue; + } + + if (astg_debug_flag > 3) { + fprintf (sisout, "off_cube2 %s (%d from top %d from bot)\n", + pc1(off_cube2), top_to_off2, bot_to_off2); + } + + foreachi_set (F_1, on_i1, on_cube1) { + /* make sure that on_cube1 is at distance 1 from off_cube1 */ + if (cdist01 (on_cube1, off_cube1) != 1) { + continue; + } + top_to_on1 = cdist (top, on_cube1); + bot_to_on1 = cdist (bot, on_cube1); + + INLINEset_and (tmp, on_cube1, off_cube1); + for (i = 0; i < nvar; i++) { + if (GETINPUT (tmp, i) == 0) { + dir1 = (GETINPUT (on_cube1, i) == ZERO) ? '+' : '-'; + var1 = i; + break; + } + } + if (astg_debug_flag > 3) { + fprintf (sisout, "on_cube1 %s (%d from top %d from bot %s%c)\n", + pc1(on_cube1), top_to_on1, bot_to_on1, + node_long_name (array_fetch (node_t *, fanin, var1)), dir1); + } + + foreachi_set (F_1, on_i2, on_cube2) { + if (on_i1 == on_i2 || cdist01 (on_cube2, off_cube2) != 1) { + continue; + } + top_to_on2 = cdist (top, on_cube2); + bot_to_on2 = cdist (bot, on_cube2); + /* make sure that on_cube1 is closer to top and on_cube2 is + * closer to bot + */ + if (top_to_on2 < top_to_on1 || bot_to_on1 < bot_to_on2) { + continue; + } + + INLINEset_and (tmp, on_cube2, off_cube2); + for (i = 0; i < nvar; i++) { + if (GETINPUT (tmp, i) == 0) { + dir2 = (GETINPUT (on_cube2, i) == ONE) ? '+' : '-'; + var2 = i; + break; + } + } + if (astg_debug_flag > 3) { + fprintf (sisout, "on_cube2 %s (%d from top %d from bot %s%c)\n", + pc1(on_cube2), top_to_on2, bot_to_on2, + node_long_name (array_fetch (node_t *, fanin, var2)), dir2); + } + + /* check for duplicates */ + hazard.s1 = node_long_name (array_fetch (node_t *, fanin, var1)); + hazard.s2 = node_long_name (array_fetch (node_t *, fanin, var2)); + hazard.dir1 = dir1; + hazard.dir2 = dir2; + hazard.on_cb1 = on_cube1; + hazard.off_cb1 = off_cube1; + hazard.on_cb2 = on_cube2; + hazard.off_cb2 = off_cube2; + for (i = 0; i < array_n (hazards); i++) { + hazard1 = array_fetch (hazard_t, hazards, i); + if (same_hazard (&hazard, &hazard1)) { + break; + } + } + + if (i >= array_n (hazards)) { + hazard.s1 = util_strsav (hazard.s1); + hazard.s2 = util_strsav (hazard.s2); + hazard.on_cb1 = set_save (hazard.on_cb1); + hazard.off_cb1 = set_save (hazard.off_cb1); + hazard.on_cb2 = set_save (hazard.on_cb2); + hazard.off_cb2 = set_save (hazard.off_cb2); + array_insert_last (hazard_t, hazards, hazard); + if (astg_debug_flag > 0) { + fprintf (sisout, + "potential hazard %s%c -> %s%c -> %s (%d)\n", hazard.s2, + hazard.dir2, hazard.s1, hazard.dir1, name, onset); + } + } + } + } + } + } + + sf_free (F_1); + sf_free (R_1); + set_free (tmp); +} + +/* Recur from current state "state" until you find a state where the next state + * function (always F: checking for hazards due to R we just swap the + * pointers...) is different from the current value. At this point we can + * check for all potential hazards. "Top" is the top state of the chain, + * "bot" is the bottom and "cb" is the transition cube between the two. + */ +static void +find_bot (fanin, hazards, F, R, stg, sig_bit, state_code, reached, cb, top, bot, onset, use_old, name) +array_t *fanin, *hazards; +set_family_t *F, *R; +astg_graph *stg; +astg_scode sig_bit, state_code; +st_table *reached; +pset cb, top, bot; +int onset, use_old; +char *name; +{ + astg_scode enabled, to_fire, new_state; + astg_signal * sig_p; + int i, savebit, recursions; + astg_generator sgen; + + enabled = astg_state_enabled (astg_find_state (stg, state_code, 0)); + + i = -1; + recursions = 0; + astg_foreach_signal (stg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + i++; + to_fire = astg_state_bit (sig_p); + if (! (to_fire & enabled)) { + continue; + } + new_state = state_code ^ to_fire; + savebit = GETINPUT (cb, i); + PUTINPUT (cb, i, TWO); + bit_to_cube (stg, new_state, bot); + /* if the function value is different, stop the recursion (remember that + * here F can be on-set or off-set...) + */ + if (func_value (F, bot) == 0) { + PUTINPUT (cb, i, savebit); + continue; + } + + recursions++; + /* count it, but only recur if not yet reached... */ + if (st_lookup (reached, (char *) new_state, NIL(char *))) { + PUTINPUT (cb, i, savebit); + continue; + } + st_insert (reached, (char *) new_state, NIL(char)); + + find_bot (fanin, hazards, F, R, stg, sig_bit, new_state, + reached, cb, top, bot, onset, use_old, name); + + PUTINPUT (cb, i, savebit); + } + + /* if we did not recur, then we reached the bottom of a state chain */ + if (! recursions) { + bit_to_cube (stg, state_code, bot); + if (use_old) { + store_hazards_old (fanin, hazards, F, R, cb, top, bot, onset, name); + } + else { + store_hazards (fanin, hazards, F, R, cb, top, bot, onset, name); + } + } +} + +/* Find all state graph states which "are not top", that is they are next + * states for some state with the same next state function value. + * This is done by marking each NEXT state of the current state. + */ +static void +find_not_top (F, stg, sig_bit, state_code, reached, not_top, bot, onset) +set_family_t *F; +astg_graph *stg; +astg_scode sig_bit, state_code; +st_table *reached, *not_top; +pset bot; +int onset; +{ + astg_scode enabled, to_fire, new_state; + astg_signal * sig_p; + astg_generator sgen; + + enabled = astg_state_enabled (astg_find_state (stg, state_code, 0)); + + astg_foreach_signal (stg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + to_fire = astg_state_bit (sig_p); + if (! (to_fire & enabled)) { + continue; + } + new_state = state_code ^ to_fire; + if (st_lookup (reached, (char *) new_state, NIL(char *))) { + continue; + } + st_insert (reached, (char *) new_state, NIL(char)); + + bit_to_cube (stg, new_state, bot); + /* Remember that here we always call F what can be on-set or off-set... */ + if (func_value (F, bot) == 0) { + continue; + } + + st_insert (not_top, (char *) new_state, NIL(char)); + find_not_top (F, stg, sig_bit, new_state, reached, + not_top, bot, onset); + } +} + +/* Must be called with a PO immediately after function generation. + * It explores all states in the SG where a transition for that signal is + * enabled. It marks all those that can be reached from other similar states, + * and drops them (since they are not maximally distant, or "top"). + * From "top"s we can now traverse depth-first the SG until we meet a + * transition for the same signal again ("bot"). + * Now if + * 1) the signal must be at 0 and its transition cube intersects the on-set OR + * 2) the signal must be at 1 and its transition cube is not covered by a + * single cube + * then we must record a pair of signals, so that we can later measure the + * delays in the bwd_slow_down procedure. + * We use either F or R as the "current on-set and off-set", according to + * whether the next state function value for the current "top" is 1 or 0. + * We must generate ALL PRIMES in the "current off-set", because otherwise + * we miss some potential hazards... + */ + +void +bwd_find_hazards (stg, sig_p, fanin, node_F, node_R, hazard_list, name, use_old) +astg_graph *stg; +astg_signal *sig_p; +array_t *fanin; +set_family_t *node_F, *node_R; +st_table *hazard_list; +char *name; +int use_old; +{ + astg_generator gen; + astg_scode sig_bit, state_code, new_state, enabled; + set_family_t *F, *R, *R_D; + array_t * hazards; + int onset; + pset cb, top, bot; + st_table *reached, *not_top; + astg_state *state; + char *buf; + + /* set up the variables for the recursion */ + sig_bit = astg_state_bit (sig_p); + + cb = set_new (2 * array_n (fanin)); + top = set_new (2 * array_n (fanin)); + bot = set_new (2 * array_n (fanin)); + hazards = array_alloc (hazard_t, 0); + + /* find "not top" states and mark them */ + not_top = st_init_table (st_numcmp, st_numhash); + astg_foreach_state (stg, gen, state) { + state_code = astg_state_code (state); + enabled = astg_state_enabled (state); + if (! (enabled & sig_bit)) { + continue; + } + + bit_to_cube (stg, state_code, cb); + bit_to_cube (stg, state_code, bot); + reached = st_init_table (st_numcmp, st_numhash); + st_insert (reached, (char *) state_code, NIL(char)); + + new_state = state_code ^ sig_bit; + if (new_state & sig_bit) { + onset = 1; + F = node_F; + } + else { + onset = 0; + F = node_R; + } + + find_not_top (F, stg, sig_bit, state_code, reached, not_top, + bot, onset); + + st_free_table (reached); + } + + /* now explore all "top" states and detect potential hazards */ + astg_foreach_state (stg, gen, state) { + state_code = astg_state_code (state); + enabled = astg_state_enabled (state); + if (st_lookup (not_top, (char *) state_code, NIL(char *))) { + continue; + } + + /* initialize local recursion variables */ + bit_to_cube (stg, state_code, cb); + bit_to_cube (stg, state_code, top); + bit_to_cube (stg, state_code, bot); + reached = st_init_table (st_numcmp, st_numhash); + st_insert (reached, (char *) state_code, NIL(char)); + + new_state = state_code; + if (enabled & sig_bit) { + new_state ^= sig_bit; + } + + /* check if F or R is the "current on-set" */ + if (new_state & sig_bit) { + onset = 1; + F = node_F; + } + else { + onset = 0; + F = node_R; + } + R_D = complement (cube1list (F)); + if (use_old) { + R = primes_consensus (cube1list (R_D)); + sf_free (R_D); + } + else { + R = R_D; + } + + /* do the actual computation, finding all maximally distant + * "bot" states from currrent "top" state_code + */ + find_bot (fanin, hazards, F, R, stg, sig_bit, state_code, + reached, cb, top, bot, onset, use_old, sig_p->name); + + /* wrap up */ + sf_free (R); + st_free_table (reached); + } + + /* save the hazard list under the current output signal name */ + buf = util_strsav (bwd_po_name (name)); + st_insert (hazard_list, buf, (char *) hazards); + + /* wrap up */ + set_free (cb); + set_free (top); + set_free (bot); + st_free_table (not_top); +} +#endif /* SIS */ diff --git a/sis/astg/bwd_int.h b/sis/astg/bwd_int.h new file mode 100644 index 0000000..c96051d --- /dev/null +++ b/sis/astg/bwd_int.h @@ -0,0 +1,134 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/bwd_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +#ifndef BWD_INT_H +#define BWD_INT_H + +#define BWD_SLOT undef1 +#define BWD(node) ((bwd_node_t *) (node)->BWD_SLOT) +struct bwd_node_struct { + double arrival; + int flags; +}; +typedef struct bwd_node_struct bwd_node_t; + +/* structure to store minimum delays between transitions. + * One structure for each pair * of signals (s1,s2). + * delay.rise.rise is the delay between s1+ and s2+, and so on. + */ +struct min_del_struct { + delay_time_t rise, fall; +}; +typedef struct min_del_struct min_del_t; + +/* Structure to store potential hazards: the symbol table is indexed by the + * name of the signal currently checked for hazard. Each record in the dynamic + * array contains a pair of signal names, ordered s1 -> s2 in the STG, that if + * reversed can cause a hazard. Later we can add some information on the + * vectors that cause a hazard. + */ + +struct hazard_struct { + char *s1, *s2; /* names of involved signals */ + char dir1, dir2, on, off_eq; /* transition type and off_cb1 == off_cb2 */ + pset on_cb1, off_cb1, on_cb2, off_cb2; /* involved cubes */ +}; +typedef struct hazard_struct hazard_t; + +/* structure to store equivalent states for state encoding (EXPERIMENTAL) + */ +struct equiv_struct { + array_t *index_state; /* maps index -> name */ + st_table *state_index; /* maps name -> index */ + pset_family classes; /* each set is a class, with the above indices */ +}; +typedef struct equiv_struct equiv_t; + +struct bwd_struct { + st_table *hazard_list; + st_table *slowed_amounts; + long change_count; + array_t *pi_names; /* order of PI's for cubes in hazard_list */ +}; +typedef struct bwd_struct bwd_t; + +#define BWD_GET(stg) ((bwd_t*)astg_get_slot((stg),ASTG_BWD_SLOT)) +#define BWD_SET(stg,value) (astg_set_slot((stg),ASTG_BWD_SLOT,(value))) + +astg_scode dummy_mask; + +int enc_summary; + +/* defined in bwd_util.c */ +extern graph_t *global_orig_stg; +extern st_table *global_orig_stg_names; +extern st_table *global_edge_trans; +extern st_table *global_state_marking; + +/* bwd_com_astg.c */ +extern void bwd_cmds (); +extern int com_bwd_astg_stg_scr (); +extern int com_bwd_astg_to_f (); +extern int com_bwd_astg_to_stg (); +extern int com_bwd_astg_slow_down (); +extern int com_stg_scc (); +extern int com_bwd_astg_latch (); +extern int com_bwd_astg_state_minimize (); +extern int com_bwd_astg_add_state (); +extern int com_bwd_stg_to_astg (); +extern int com_bwd_astg_encode (); +extern int com_bwd_astg_write_sg (); + +/* bwd_stg_to_f.c */ +extern void bwd_astg_to_f (); + +/* bwd_util.c */ +extern graph_t *bwd_stg_scr (); +extern void bwd_dc_to_self_loop (); +extern int bwd_is_enabled (); +extern astg_trans *bwd_edge_trans (); +extern graph_t * bwd_astg_to_stg (); +extern vertex_t *bwd_get_state_by_name (); +extern array_t *graph_scc (); +extern astg_scode bwd_new_enabled_signals (); +extern char * bwd_marking_string (); +extern graph_t * bwd_reduced_stg (); +extern void bwd_pedge (); +extern void bwd_pstate (); +extern void bwd_astg_latch (); +extern char *bwd_fake_pi_name (); +extern char *bwd_po_name (); +extern char *bwd_fake_po_name (); +extern int bwd_marking_cmp (); +extern int bwd_marking_ptr_cmp (); +extern int bwd_marking_hash (); +extern astg_scode bwd_astg_state_bit (); +extern astg_graph *bwd_stg_to_astg (); +extern void bwd_write_sg (); + + +/* bwd_lp.c */ +extern void bwd_lp_slow (); + +/* bwd_slow.c */ +extern void bwd_slow_down (); +extern char *bwd_make_in_name (); +extern void bwd_external_delay_update (); + +/* bwd_hazard.c */ +extern void bwd_find_hazards (); + +/* bwd_min_delay.c */ +extern int bwd_min_delay_trace(); + +/* bwd_code.c */ +extern equiv_t * bwd_read_equiv_states (); +extern graph_t * bwd_state_minimize (); +extern void bwd_add_state (); +#endif /* BWD_INT_H */ diff --git a/sis/astg/bwd_io.c b/sis/astg/bwd_io.c new file mode 100644 index 0000000..847e651 --- /dev/null +++ b/sis/astg/bwd_io.c @@ -0,0 +1,453 @@ +/* + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:59 $ +*/ +#ifdef SIS +/* Write a network in Jeff Burch's verifier format. + */ +#include +#include "sis.h" +#include "astg_int.h" +#include "astg_core.h" +#include "bwd_int.h" + +static int +is_garbage_node (node) +node_t *node; +{ + node_t *fanout, *pi; + lsGen gen; + + /* check if it is a "garbage" node, i.e. it does not feed any latch */ + pi = NIL(node_t); + foreach_fanout (node, gen, fanout) { + if (node_type (fanout) == PRIMARY_OUTPUT) { + pi = network_latch_end (fanout); + if (pi != NIL(node_t) && node_type(pi) == PRIMARY_INPUT) { + break; + } + } + } + return (pi == NIL(node_t)); +} + +static char * +make_legal_name (name) +char *name; +{ + static char buf[512]; + int i, len; + + len = strlen (name); + if (len >= (sizeof(buf)/sizeof(char))) { + fprintf (siserr, "name too long ?\n"); + return ""; + } + + strcpy (buf, name); + for (i = 0; i < len; i++) { + if (! isalnum (buf[i])) { + buf[i] = '_'; + } + } + + return buf; +} + +static node_t * +get_named_node (node) +node_t *node; +{ + node_t *fanout, *pi, *result; + lsGen gen; + + /* look if any first level fanout is a latch input, and if so + * return its latch output (which is a PI) + */ + pi = NIL(node_t); + foreach_fanout (node, gen, fanout) { + if (node_type (fanout) == PRIMARY_OUTPUT) { + pi = network_latch_end (fanout); + if (pi != NIL(node_t) && node_type(pi) == PRIMARY_INPUT) { + break; + } + } + } + + if (pi != NIL(node_t)) { + result = pi; + if (astg_debug_flag > 1) { + (void) fprintf (siserr, "using %s for node %s\n", + node_long_name (result), node_long_name (node)); + } + } + else { + result = node; + } + return result; +} + +static char * +get_gate_name (node) +node_t *node; +{ + char *name; + + name = lib_gate_name(lib_gate_of(node)); + + if (! strncmp (name, "NAND", 3)) { + return ("orgate"); + } + if (! strncmp (name, "NOR", 2)) { + return ("andgate"); + } + if (! strncmp (name, "INV", 3)) { + return ("inverter"); + } + if (! strncmp (name, "DELAY", 5)) { + return ("buffer"); + } + + return NIL(char); +} + +void +bwd_write_burch (file, network, min_delay_factor, write_spec) +FILE *file; +network_t *network; +double min_delay_factor; +int write_spec; +{ + node_t *node, *pi, *po, *fanin, *fanin1, *n, *n1; + lsGen gen; + delay_time_t delay; + int max_delay, min_delay, max_hazard; + int i, j, nin; + pset p, last; + char *gate_name, *n_name; + network_t * collapsed_network; + array_t *node_vec, *in_value; + astg_retval status; + astg_graph *astg; + astg_scode state, bit; + astg_signal *sig_p; + char buf[80]; + st_table *inputs, *outputs; + astg_generator sgen; + + if (! lib_network_is_mapped(network)) { + fprintf(siserr,"network not mapped, cannot write netlist\n"); + return; + } + + /* initialize the node values */ + astg=astg_current (network); + state = (astg_scode) 0; + if (astg == NIL(astg_graph)) { + fprintf(siserr,"cannot find the STG\n"); + return; + } + status = astg_initial_state (astg, &state); + if (status != ASTG_OK && status != ASTG_NOT_USC) { + fprintf(siserr,"cannot find the initial state\n"); + return; + } + node_vec = network_dfs (network); + in_value = array_alloc (int, 0); + + foreach_primary_input (network, gen, pi) { + sig_p = astg_find_named_signal (astg, bwd_po_name (node_long_name (pi))); + if (sig_p == NIL(astg_signal)) { + fprintf (siserr, "cannot find signal for %s\n", node_long_name (pi)); + return; + } + bit = astg_state_bit (sig_p); + if (bit & state) { + array_insert_last (int, in_value, 1); + } + else { + array_insert_last (int, in_value, 0); + } + } + + (void) simulate_network (network, node_vec, in_value); + array_free (node_vec); + array_free (in_value); + + /* initialize the input and output symbol tables */ + inputs = st_init_table (strcmp, st_strhash); + outputs = st_init_table (strcmp, st_strhash); + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + if (astg_signal_type (sig_p) == ASTG_OUTPUT_SIG) { + st_insert (outputs, sig_p->name, NIL(char)); + } + else { + st_insert (inputs, sig_p->name, NIL(char)); + } + } + + if (write_spec) { + /* print out the specification */ + collapsed_network = network_dup (network); + (void) network_collapse (collapsed_network); + node_vec = network_dfs (collapsed_network); + in_value = array_alloc (int, 0); + + foreach_primary_input (collapsed_network, gen, pi) { + sig_p = astg_find_named_signal (astg, + bwd_po_name (node_long_name (pi))); + if (sig_p == NIL(astg_signal)) { + fprintf (siserr, "cannot find signal for %s\n", node_long_name (pi)); + return; + } + bit = astg_state_bit (sig_p); + if (bit & state) { + array_insert_last (int, in_value, 1); + } + else { + array_insert_last (int, in_value, 0); + } + } + + (void) simulate_network (collapsed_network, node_vec, in_value); + array_free (node_vec); + array_free (in_value); + + (void) fprintf(file, "\n(setq %s-spec\n", + make_legal_name(network_name(network))); + (void) fprintf(file, " (teval\n"); + (void) fprintf(file, " (compose\n"); + foreach_node (collapsed_network, gen, node) { + if (is_garbage_node (node)) { + continue; + } + + nin = node_num_fanin (node); + if (nin == 0) { + (void) fprintf(siserr, "warning: constant node function %s\n", + node_long_name (node)); + continue; + } + + n = get_named_node (node); + n_name = node_long_name (n); + if (node->type == INTERNAL) { + /* PI... no hazard */ + (void) fprintf(file, " (no-hazard gate ( "); + } + else { + (void) fprintf(file, " (gate ( "); + } + foreach_fanin (node, i, fanin) { + n = get_named_node (fanin); + if (! strcmp (node_long_name (n), n_name)) { + continue; + } + if ((int) n->simulation) { + (void) fprintf(file, "(%s %d) ", + make_legal_name (node_long_name (n)), + n->simulation); + } + else { + (void) fprintf(file, "%s ", + make_legal_name (node_long_name (n))); + } + } + (void) fprintf(file, ")"); + n = get_named_node (node); + if ((int) n->simulation) { + (void) fprintf(file, "(%s %d)\n", + make_legal_name (node_long_name (n)), + n->simulation); + } + else { + (void) fprintf(file, "%s\n", make_legal_name (node_long_name (n))); + } + (void) fprintf(file, "; insert here min del for %s\n", + node_long_name (n)); + (void) fprintf(file, " (0 infty)\n"); + if (node->F->count > 1) { + (void) fprintf(file, " (logior\n"); + } + foreach_set (node->F, last, p) { + if (set_ord (p) < 2 * nin - 1) { + (void) fprintf(file, " (logand "); + } + else { + (void) fprintf(file, " "); + } + for (i = 0; i < nin; i++) { + switch (GETINPUT (p, i)) { + case ZERO: + fanin = node_get_fanin (node, i); + (void) fprintf(file, " (lognot %s)", + node_long_name (fanin)); + break; + case ONE: + fanin = node_get_fanin (node, i); + (void) fprintf(file, " %s", node_long_name (fanin)); + break; + default: + break; + } + } + if (set_ord (p) < 2 * nin - 1) { + (void) fprintf(file, ")\n"); + } + else { + (void) fprintf(file, "\n"); + } + } + if (node->F->count > 1) { + (void) fprintf(file, " )\n"); + } + (void) fprintf(file, " )\n"); + } + (void) fprintf(file, ")))\n"); + network_free (collapsed_network); + } + else { + /* initialize the delays */ + foreach_primary_input (network, gen, pi) { + delay_set_parameter (pi, DELAY_ARRIVAL_RISE, (double) 0); + delay_set_parameter (pi, DELAY_ARRIVAL_FALL, (double) 0); + } + foreach_primary_output (network, gen, po) { + delay_set_parameter (po, DELAY_OUTPUT_LOAD, (double) 1.0); + } + + assert (delay_trace (network, DELAY_MODEL_LIBRARY)); + + /* print out the implementation */ + (void) fprintf(file, "(setq %s-impl\n", + make_legal_name(network_name(network))); + (void) fprintf(file, " (project '("); + foreach_primary_input (network, gen, node) { + (void) fprintf(file, " %s", make_legal_name (node_long_name (node))); + } + (void) fprintf(file, " Phi)\n"); + + (void) fprintf(file, " (compose\n"); + + foreach_node (network, gen, node) { + if (node->type != INTERNAL || + (gate_name = get_gate_name (node)) == NIL(char)) { + continue; + } + + nin = node_num_fanin (node); + if (nin == 0) { + (void) fprintf(siserr, "warning: constant node function %s\n", + node_long_name (node)); + continue; + } + + /* get the min and max delays through the gate */ + max_delay = 0; + min_delay = INFINITY; + foreach_fanin (node, i, fanin) { + delay = delay_node_pin (node, i, DELAY_MODEL_LIBRARY); + max_delay = MAX (max_delay, delay.rise); + max_delay = MAX (max_delay, delay.fall); + min_delay = MIN (min_delay, delay.rise); + min_delay = MIN (min_delay, delay.fall); + } + min_delay *= min_delay_factor; + + (void) fprintf(file, " (chaos %s ", gate_name); + + if (nin == 1) { + /* one fanin, no input node list */ + fanin = node_get_fanin (node, 0); + assert (fanin != NIL(node_t)); + + n = get_named_node (fanin); + if ((int) n->simulation) { + (void) fprintf(file, "(%s %d)", make_legal_name (node_long_name (n)), + (int) n->simulation); + } + else { + (void) fprintf(file, "%s", make_legal_name (node_long_name (n))); + } + if (astg_debug_flag == 1) { + (void) fprintf (siserr, "%s ", make_legal_name (node_long_name (n))); + } + } + else { + /* else, run through its fanin list*/ + (void) fprintf(file, "( "); + foreach_fanin (node, i, fanin) { + n = get_named_node (fanin); + n_name = node_long_name (n); + /* avoid duplicate names (it happens...) */ + for (j = i + 1; j < nin; j++) { + fanin1 = node_get_fanin (node, j); + n1 = get_named_node (fanin1); + if (! strcmp (node_long_name (n1), n_name)) { + break; + } + } + if (j < nin) { + continue; + } + + if ((int) n->simulation) { + (void) fprintf(file, "(-%s %d) ", + make_legal_name (node_long_name (n)), + (int) n->simulation); + } + else { + (void) fprintf(file, "-%s ", + make_legal_name (node_long_name (n))); + } + if (astg_debug_flag == 1) { + (void) fprintf (siserr, "%s ", + make_legal_name (node_long_name (n))); + } + } + (void) fprintf(file, ")"); + } + + /* check if the node is not internal, and if so don't allow hazards */ + n = get_named_node (node); + n_name = make_legal_name (node_long_name (n)); + if (st_is_member (inputs, n_name)) { + /* no hazards allowed here ! */ + max_hazard = -1; + strcpy (buf, "infty"); + } + else if (st_is_member (outputs, n_name)) { + /* no hazards allowed here ! */ + max_hazard = -1; + sprintf (buf, "%d", max_delay); + } + else { + /* internal node: do not care about hazards */ + max_hazard = max_delay; + sprintf (buf, "%d", max_delay); + } + + if ((int) n->simulation) { + (void) fprintf(file, " (%s %d) (%d %d))\n", + make_legal_name (node_long_name (n)), + n->simulation, min_delay, max_delay); + } + else { + (void) fprintf(file, " %s (%d %d))\n", + make_legal_name (node_long_name (n)), + min_delay, max_delay); + } + if (astg_debug_flag == 1) { + (void) fprintf (siserr, "%s\n", n_name); + } + } + (void) fprintf(file, ")))\n"); + } + + st_free_table (inputs); + st_free_table (outputs); +} +#endif /* SIS */ diff --git a/sis/astg/bwd_lp.c b/sis/astg/bwd_lp.c new file mode 100644 index 0000000..54ad8eb --- /dev/null +++ b/sis/astg/bwd_lp.c @@ -0,0 +1,1390 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/bwd_lp.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2005/03/08 05:31:11 $ + * + */ +#ifdef SIS +/* Routines that insert inverter pairs where a potential hazard can actually + * occur, using the linear programming formulation of the ICCD92 paper. + */ +#include "sis.h" +#include "astg_int.h" +#include "astg_core.h" +#include "bwd_int.h" +#include + +/* hacked from sim/interpret.c */ +#define SIM_SLOT simulation +#define GET_VALUE(node) ((int) node->SIM_SLOT) +#define SET_VALUE(node, value) (node->SIM_SLOT = (char *) (value)) +#define UP (2 | 1) +#define DOWN (2 | 0) +#define UNDEF 4 +#define VAL_MASK 1 + +#define EQ 0 +#define GE 1 +#define LE 2 +struct _constraint_struct { + int *vars; + int *coeffs; + double val; + int n; /* number of vars and coeffs */ + int type; + int level; /* same level for same MAX */ +}; +typedef struct _constraint_struct constraint_t; + +/* if UNDEF, set to new, otherwise set to UP and DOWN appropriately + */ +static void +new_value (node, new) +node_t *node; +int new; +{ + if ((GET_VALUE (node) & UNDEF) || (new & UNDEF)) { + SET_VALUE (node, new); + } + else { + if (new) { + switch (GET_VALUE (node)) { + case 1: + SET_VALUE (node, 1); + break; + case 0: + SET_VALUE (node, UP); + break; + case DOWN: + fprintf (siserr, "error: up and down transition for %s\n", + node_name (node)); + break; + case UP: + SET_VALUE (node, UP); + break; + default: + break; + } + } + else { + switch (GET_VALUE (node)) { + case 0: + SET_VALUE (node, 0); + break; + case 1: + SET_VALUE (node, DOWN); + break; + case UP: + fprintf (siserr, "error: up and down transition for %s\n", + node_name (node)); + break; + case DOWN: + SET_VALUE (node, DOWN); + break; + default: + break; + } + } + } +} + +/* simulate a node; hacked from simulate.c + */ +static void +sim_node(node) +node_t *node; +{ + int i, value; + node_t *fanin, *func, *func1, *lit; + + func = node_dup(node); + foreach_fanin(node, i, fanin) { + if (GET_VALUE(fanin) & UNDEF) { + continue; + } + value = GET_VALUE(fanin) & VAL_MASK; + + lit = node_literal(fanin, value); + func1 = node_cofactor(func, lit); + node_free(func); + node_free(lit); + func = func1; + + if (node_function(func) == NODE_0 || node_function(func) == NODE_1) { + break; + } + } + + switch (node_function(func)) { + case NODE_0: + new_value (node, 0); + break; + case NODE_1: + new_value (node, 1); + break; + default: + break; + } + if (astg_debug_flag > 3) { + switch (GET_VALUE (node)) { + case 0: + fprintf (sisout, " %s 0\n", node_long_name (node)); + break; + case 1: + fprintf (sisout, " %s 1\n", node_long_name (node)); + break; + case UP: + fprintf (sisout, " %s +\n", node_long_name (node)); + break; + case DOWN: + fprintf (sisout, " %s -\n", node_long_name (node)); + break; + default: + break; + } + } + + node_free(func); +} + +/* simulate a network; hacked from simulate.c + * cb gives the pattern, and change_index signals which PI (if any) is changing + * to change_val + */ + +static void +sim_network(network, node_vec, pi_index, cb, change_index, change_val) +network_t *network; +array_t *node_vec; +st_table *pi_index; +pset cb; +int change_index, change_val; +{ + int i; + node_t *node, *pi; + lsGen gen; + + /* set the values on the primary inputs */ + foreach_primary_input(network, gen, pi) { + if (! st_lookup (pi_index, bwd_po_name (node_long_name (pi)), + (char **) &i)) { + /* test input... set it to 1 */ + new_value (pi, 1); + if (astg_debug_flag > 3) { + fprintf (sisout, " %s 1 (test)\n", node_long_name (pi)); + } + continue; + } + if (change_index == i) { + new_value (pi, change_val); + } + else { + switch (GETINPUT (cb, i)) { + case ONE: + new_value (pi, 1); + break; + case ZERO: + new_value (pi, 0); + break; + default: + new_value (pi, UNDEF); + break; + } + } + + if (astg_debug_flag > 3) { + switch (GET_VALUE (pi)) { + case 0: + fprintf (sisout, " %s 0\n", node_long_name (pi)); + break; + case 1: + fprintf (sisout, " %s 1\n", node_long_name (pi)); + break; + case UP: + fprintf (sisout, " %s +\n", node_long_name (pi)); + break; + case DOWN: + fprintf (sisout, " %s -\n", node_long_name (pi)); + break; + default: + break; + } + } + } + + /* simulate the values through the network */ + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (node->type == INTERNAL) { + sim_node(node); + } + } +} + +/* find the subnet that is changing value. + * we can have more than one fanin changing because they are killed + * inside a complex gate... so the path is actually a subnetwork + */ +static void +find_subnet (node, subnet) +node_t *node; +st_table *subnet; +{ + node_t *fanin; + int i; + + foreach_fanin (node, i, fanin) { + switch (GET_VALUE (fanin)) { + case UP: + if (astg_debug_flag > 2) { + fprintf (sisout, " %s+", node_long_name (node)); + } + st_insert (subnet, (char *) fanin, (char *) GET_VALUE (fanin)); + find_subnet (fanin, subnet); + break; + case DOWN: + if (astg_debug_flag > 2) { + fprintf (sisout, " %s-", node_long_name (node)); + } + st_insert (subnet, (char *) fanin, (char *) GET_VALUE (fanin)); + find_subnet (fanin, subnet); + break; + default: + break; + } + } +} + +/* Compute the delay inside subnet1 (which should end in po). + * Gates also in subnet2 have their upper bound used anyway, otherwise + * if we are computing a lower bound, min_delay_factor is used + * We should become smarter here... + */ +static double +subnet_delay (node_vec, po, subnet1, subnet2, upper_bound, min_delay_factor) +array_t *node_vec; +node_t *po; +st_table *subnet1, *subnet2; +int upper_bound; +double min_delay_factor; +{ + node_t *node, *fanin; + int i, j, node_dir, fanin_dir, cnt; + double delta; + delay_time_t delay; + + for (j = 0; j < array_n (node_vec); j++) { + node = array_fetch (node_t *, node_vec, j); + BWD(node)->arrival = -1; + } + for (j = 0; j < array_n (node_vec); j++) { + node = array_fetch (node_t *, node_vec, j); + if (! st_lookup (subnet1, (char *) node, (char **) &node_dir)) { + continue; + } + + /* compute the arrival time at node */ + if (node_num_fanin (node) == 0) { + /* PI */ + delay = delay_node_pin (node, 0, DELAY_MODEL_LIBRARY); + if (node_dir == UP) { + delta = delay.rise; + } + else { + delta = delay.fall; + } + if (! upper_bound) { + delta *= min_delay_factor; + } + BWD(node)->arrival = delta; + } + else { + cnt = 0; + foreach_fanin (node, i, fanin) { + if (! st_lookup (subnet1, (char *) fanin, + (char **) &fanin_dir)) { + continue; + } + cnt++; + delay = delay_node_pin (node, i, DELAY_MODEL_LIBRARY); + if (node_dir == UP) { + delta = delay.rise; + } + else { + delta = delay.fall; + } + /* use upper bound it if it is also on subnet2 */ + if (! upper_bound && ! st_is_member (subnet2, (char *) node)) { + delta *= min_delay_factor; + } + + /* here we should take into account the + * controlling/noncontrolling values + */ + if (upper_bound) { + if (BWD(node)->arrival < 0 || + BWD(node)->arrival < BWD(fanin)->arrival + delta) { + BWD(node)->arrival = BWD(fanin)->arrival + delta; + } + } + else { + if (BWD(node)->arrival < 0 || + BWD(node)->arrival > BWD(fanin)->arrival + delta) { + BWD(node)->arrival = BWD(fanin)->arrival + delta; + } + } + if (astg_debug_flag > 4) { + if (node_dir == UP) { + fprintf (sisout, "%s+ from %s %f\n", + node_long_name (node), node_long_name (fanin), + BWD(fanin)->arrival + delta); + } + else { + fprintf (sisout, "%s- from %s %f\n", + node_long_name (node), node_long_name (fanin), + BWD(fanin)->arrival + delta); + } + } + } + if (cnt > 1 && astg_debug_flag > 1) { + fprintf (sisout, "warning: more than one fanin of %s changed\n", + node_long_name (node)); + } + } + assert (BWD(node)->arrival >= 0); + if (node_dir == UP) { + if (astg_debug_flag > 3) { + fprintf (sisout, "%s+ %f\n", node_long_name (node), + BWD(node)->arrival); + } + } + else { + if (astg_debug_flag > 3) { + fprintf (sisout, "%s- %f\n", node_long_name (node), + BWD(node)->arrival); + } + } + } + + node = node_get_fanin (po, 0); + return BWD(node)->arrival; +} + +/* return the upper bound on d (hazard.s2, po) - d (hazard.s1, po) + */ +static double +hazard_delay (network, pi_index, po, hazard, min_delay_factor) +network_t *network; +st_table *pi_index; +node_t *po; +hazard_t *hazard; +double min_delay_factor; +{ + node_t *node; + array_t *node_vec; + st_table *subnet1, *subnet2; + int i, old_val, new_val; + double d2, d1; + pset cb = cube.temp[0]; + + node_vec = network_dfs (network); + /* simulate under on_cb1 -> off_cb1 */ + for (i = 0; i < array_n (node_vec); i++) { + node = array_fetch (node_t *, node_vec, i); + SET_VALUE (node, UNDEF); + } + consensus (cb, hazard->on_cb1, hazard->off_cb1); + if (astg_debug_flag > 2) { + fprintf (sisout, "simulating %s under %s\n", + node_long_name (po), pc1(cb)); + } + assert (st_lookup (pi_index, bwd_po_name (hazard->s1), (char **) &i)); + if (hazard->dir1 == '+') { + old_val = 0; + new_val = 1; + } + else { + old_val = 1; + new_val = 0; + } + sim_network(network, node_vec, pi_index, cb, i, old_val); + if (astg_debug_flag > 2) { + fprintf (sisout, "simulating %s under %s with %s%c\n", + node_long_name (po), pc1(cb), hazard->s1, hazard->dir1); + } + sim_network(network, node_vec, pi_index, cb, i, new_val); + + /* now get the subnet */ + subnet1 = st_init_table (st_ptrcmp, st_ptrhash); + if (astg_debug_flag > 2) { + fprintf (sisout, "subnet 1:"); + } + find_subnet (po, subnet1); + if (astg_debug_flag > 2) { + fprintf (sisout, "\n"); + } + + /* simulate under off_cb2 -> on_cb2 */ + for (i = 0; i < array_n (node_vec); i++) { + node = array_fetch (node_t *, node_vec, i); + SET_VALUE (node, UNDEF); + } + consensus (cb, hazard->on_cb2, hazard->off_cb2); + if (astg_debug_flag > 2) { + fprintf (sisout, "simulating %s under %s\n", + node_long_name (po), pc1(cb)); + } + assert (st_lookup (pi_index, bwd_po_name (hazard->s2), (char **) &i)); + if (hazard->dir2 == '+') { + old_val = 0; + new_val = 1; + } + else { + old_val = 1; + new_val = 0; + } + sim_network(network, node_vec, pi_index, cb, i, old_val); + if (astg_debug_flag > 2) { + fprintf (sisout, "simulating %s under %s with %s%c\n", + node_long_name (po), pc1(cb), hazard->s2, hazard->dir2); + } + assert (st_lookup (pi_index, bwd_po_name (hazard->s2), (char **) &i)); + sim_network(network, node_vec, pi_index, cb, i, new_val); + + /* get the subnet */ + subnet2 = st_init_table (st_ptrcmp, st_ptrhash); + if (astg_debug_flag > 2) { + fprintf (sisout, "subnet 2:"); + } + find_subnet (po, subnet2); + if (astg_debug_flag > 2) { + fprintf (sisout, "\n"); + } + + /* compute d1 and d2 */ + if (astg_debug_flag > 3) { + fprintf (sisout, "computing d1\n"); + } + d1 = subnet_delay (node_vec, po, subnet1, subnet2, /*upper_bound*/ 0, + min_delay_factor); + + if (astg_debug_flag > 3) { + fprintf (sisout, "computing d2\n"); + } + d2 = subnet_delay (node_vec, po, subnet2, subnet1, /*upper_bound*/ 1, + min_delay_factor); + + st_free_table (subnet1); + st_free_table (subnet2); + if (astg_debug_flag > 2) { + fprintf (sisout, "d1 %f d2 %f\n", d1, d2); + } + if (d1 < 0 || d2 < 0) { + return -1; + } + return d2 - d1; +} + +/* find a subset of vertices that are on a path to a vertex that is on the + * subset + */ +static int +find_astg_subset (v) +astg_vertex *v; +{ + astg_edge *e; + astg_generator gen; + + if (v->on_path || ! v->active) { + return 0; + } + v->on_path = ASTG_TRUE; + + if (v->subset) { + v->on_path = ASTG_FALSE; + return 1; + } + if (v->unprocessed) { + v->unprocessed = ASTG_FALSE; + astg_foreach_out_edge (v, gen, e) { + if (find_astg_subset (astg_head (e))) { + v->subset = ASTG_TRUE; + } + } + } + v->on_path = ASTG_FALSE; + return v->subset; +} + +/* assign a topological sort index to each vertex in the subset + */ +static void +ts_dfs (g, v, num_p) +astg_graph *g; +astg_vertex *v; +int *num_p; +{ + astg_generator gen; + astg_edge *e; + + if (v->unprocessed) { + v->unprocessed = ASTG_FALSE; + astg_foreach_out_edge (v,gen,e) { + ts_dfs (g,astg_head(e),num_p); + } + if (v->vtype == ASTG_TRANS) { + v->alg.ts.index = (*num_p)++; + } + } +} + +/* return the minimum estimated delay between from and to + */ +static double +min_del (from, to, external_del, default_del) +astg_trans *from, *to; +st_table *external_del; +double default_del; +{ + st_table *to_table; + char *n; + min_del_t *delay; + + n = astg_signal_name (astg_trans_sig (from)); + if (! st_lookup (external_del, n, (char **) &to_table)) { + return default_del; + } + n = astg_signal_name (astg_trans_sig (to)); + if (! st_lookup (to_table, n, (char **) &delay)) { + return default_del; + } + switch (astg_trans_type (from)) { + case ASTG_POS_X: + switch (astg_trans_type (to)) { + case ASTG_POS_X: + return delay->rise.rise; + case ASTG_NEG_X: + return delay->rise.fall; + } + case ASTG_NEG_X: + switch (astg_trans_type (to)) { + case ASTG_POS_X: + return delay->fall.rise; + case ASTG_NEG_X: + return delay->fall.fall; + } + default: + break; + } + fail ("invalid transition type\n"); + return 0; +} + +static void +print_constr (file, constr) +FILE *file; +constraint_t *constr; +{ + int i; + + for (i = 0; i < constr->n; i++) { + if (i != 0 && constr->coeffs[i] >= 0) { + fprintf (file, "+ "); + } + fprintf (file, "%d x%d ", constr->coeffs[i], constr->vars[i]); + } + switch (constr->type) { + case EQ: + fprintf (file, "="); + break; + case GE: + fprintf (file, ">="); + break; + case LE: + fprintf (file, "<="); + break; + default: + fail ("illegal LP constraint type"); + } + fprintf (file, "%f\n", constr->val); +} + +/* define an order, and stick to it... "level" does not matter */ +static int +constr_cmp (c1, c2) +constraint_t *c1, *c2; +{ + int result, i; + + result = c1->n - c2->n; + if (result) { + return result; + } + result = c1->type - c2->type; + if (result) { + return result; + } + + for (i = 0; i < c1->n; i++) { + result = c1->vars[i] - c2->vars[i]; + if (result) { + return result; + } + result = c1->coeffs[i] - c2->coeffs[i]; + if (result) { + return result; + } + } + if (c1->val < c2->val) { + return -1; + } + if (c1->val > c2->val) { + return 1; + } + return 0; +} + +/* this should be optimized ... */ +static void +add_constr (constrs, constr) +array_t *constrs; +constraint_t *constr; +{ + constraint_t *old_constr; + int i; + + for (i = 0; i < array_n (constrs); i++) { + old_constr = array_fetch (constraint_t *, constrs, i); + if (! constr_cmp (constr, old_constr)) { + return; + } + } + array_insert_last (constraint_t *, constrs, constr); + if (astg_debug_flag > 2) { + print_constr (sisout, constr); + } +} + +static void +add_constr_1 (constrs, coeff, var, type, level, val) +array_t *constrs; +int coeff, var, type, level; +double val; +{ + constraint_t *constr; + + constr = ALLOC (constraint_t, 1); + constr->n = 1; + constr->vars = ALLOC (int, 1); + constr->vars[0] = var; + constr->coeffs = ALLOC (int, 1); + constr->coeffs[0] = coeff; + constr->val = val; + constr->type = type; + constr->level = level; + add_constr (constrs, constr); +} + +static void +add_constr_3 (constrs, coeff1, var1, coeff2, var2, coeff3, var3, type, level, val) +array_t *constrs; +int coeff1, var1, coeff2, var2, coeff3, var3, type, level; +double val; +{ + constraint_t *constr; + + constr = ALLOC (constraint_t, 1); + constr->n = 3; + constr->vars = ALLOC (int, 3); + constr->vars[0] = var1; + constr->vars[1] = var2; + constr->vars[2] = var3; + constr->coeffs = ALLOC (int, 3); + constr->coeffs[0] = coeff1; + constr->coeffs[1] = coeff2; + constr->coeffs[2] = coeff3; + constr->val = val; + constr->type = type; + constr->level = level; + add_constr (constrs, constr); +} + +/* write a set of LP constraints for the sub-STG between t2 and t1 + * Returns the number of equations written. + */ +static int +write_constr (t1, t2, constrs, order, names, min_var, external_del, sig_table, pair, level, delta, default_del) +astg_trans *t1, *t2; +array_t *constrs, *order, *names, *min_var; +st_table *external_del, *sig_table; +int pair, *level; +double delta, default_del; +{ + int k, to_n, from_n, sig_n; + double w; + astg_trans *to, *from; + astg_generator pgen, tgen; + astg_place *p; + static char buf[512], *n; + st_table *trans_table; + + trans_table = st_init_table (st_ptrcmp, st_ptrhash); + for (k = 0; k < array_n (order); k++) { + /* get all transition in topological order */ + to = array_fetch (astg_vertex *, order, k); + /* create a variable with the delay of to and name D_to_pair */ + to_n = array_n (names); + sprintf (buf, "D_%s_%d", astg_trans_name (to), pair); + n = util_strsav (buf); + array_insert_last (char *, names, n); + st_insert (trans_table, (char *) to, (char *) to_n); + + if (k == 0) { + /* source: the variable is 0 */ + assert (to == t2); + add_constr_1 (constrs, 1, to_n, EQ, -1, (double) 0); + continue; + } + if (k == array_n (order) - 1) { + assert (to == t1); + add_constr_1 (constrs, 1, to_n, GE, -1, delta); + } + + astg_foreach_input_place (to, pgen, p) { + astg_foreach_input_trans (p, tgen, from) { + /* it may not be in trans_table yet if it also belongs to + * another MG component, i.e. if there is a loop pivoting on + * a predecessor place of "to" + */ + if (! from->subset || + ! st_lookup (trans_table, (char *) from, + (char **) &from_n)) { + continue; + } + /* create a constraint + * D_to_pair {>=,=} D_from_pair + W(from,to) + X_to + * where D are arrival times + */ + w = min_del (from, to, external_del, default_del); + + assert (st_lookup (sig_table, astg_signal_name (astg_trans_sig (to)), (char **) &sig_n)); + + add_constr_3 (constrs, 1, to_n, -1, from_n, -1, + sig_n, GE, *level, w); + } + } + (*level)++; + } + st_free_table (trans_table); +} + +static double +solve_lp (constrs, min_var, names, slow, eval, lindo) +array_t *constrs, *min_var, *names; +double *slow; +int *eval, lindo; +{ + static char buf[512], tmp[L_tmpnam], out[L_tmpnam], in[L_tmpnam]; + FILE *lp_out, *lp_in, *lp_tmp; + int i, j, cnt, m, n, m1, m2, m3, *izrov, *iposv, r1, r2, r3, row, icase; + constraint_t *constr, *constr1; + char *gt, *str, *name; + double cost, **a; + st_table *to_min; + int tmpfd, infd, outfd; + + (*eval)++; + if (lindo) { + /* run the LP and get the cost */ + strcpy(tmp, "/tmp/astg_tmp_XXXXXX"); + tmpfd = mkstemp(tmp); + if(tmpfd == -1) { + perror ("error creating tmp file"); + return; + } + strcpy(tmp, "/tmp/astg_out_XXXXXX"); + outfd = mkstemp(out); + if(outfd == -1) { + perror ("error creating out file"); + return; + } + strcpy(tmp, "/tmp/astg_in_XXXXXX"); + infd = mkstemp(in); + if(infd == -1) { + perror ("error creating in file"); + return; + } + /* now create the LP input file lp_in */ + lp_in = fdopen (infd, "w"); + if (lp_in == NULL) { + perror (in); + return; + } + + fprintf (lp_in, "MIN"); + if (astg_debug_flag > 1) { + fprintf (sisout, "MIN"); + } + for (i = 0; i < array_n (min_var); i++) { + if (i > 0) { + fprintf (lp_in, " +"); + if (astg_debug_flag > 1) { + fprintf (sisout, " +"); + } + } + /* signal: cost 1 */ + fprintf (lp_in, " x%d\n", array_fetch (int, min_var, i)); + if (astg_debug_flag > 1) { + fprintf (sisout, " x%d\n", array_fetch (int, min_var, i)); + } + } + fprintf (lp_in, "ST\n"); + if (astg_debug_flag > 1) { + fprintf (sisout, "ST\n"); + } + for (i = 0; i < array_n (constrs); i++) { + constr = array_fetch (constraint_t *, constrs, i); + print_constr (lp_in, constr); + if (astg_debug_flag > 1) { + print_constr (sisout, constr); + } + } + fprintf (lp_in, "END\nGO\nn\nQUIT\n"); + if (astg_debug_flag > 1) { + fprintf (sisout, "END\nGO\nn\nQUIT\n"); + } + fclose (lp_in); + + /* write the symbol table to the beginning of the LP output file */ + lp_out = fdopen (outfd, "w"); + if (lp_out == NULL) { + perror (out); + return; + } + if (astg_debug_flag > 1) { + fprintf (sisout, "variable names\n"); + } + fprintf (lp_out, "variable names\n"); + for (i = 0; i < array_n (names); i++) { + str = array_fetch (char *, names, i); + if (astg_debug_flag > 1) { + fprintf (sisout, "%s x%d\n", str, i); + } + fprintf (lp_out, "%s x%d\n", str, i); + } + fclose (lp_out); + + sprintf (buf, "rsh dent run_lindo < %s >> %s", in, out); + if (astg_debug_flag > 1) { + fprintf (sisout, "%s\n", buf); + } + fprintf (sisout, "running lindo..."); + fflush(sisout); + system (buf); + fprintf (sisout, " done\n"); + + /* analyze the output */ + if (astg_debug_flag > 1) { + sprintf (buf, + "cat %s; tr a-z A-Z < %s | awk -f lindo.awk > %s", + out, out, tmp); + } + else { + sprintf (buf, "tr a-z A-Z < %s | awk -f lindo.awk > %s", + out, tmp); + } + if (astg_debug_flag > 1) { + fprintf (sisout, "%s\n", buf); + } + system (buf); + + lp_tmp = fdopen (tmpfd, "r"); + if (lp_tmp == NULL) { + perror (tmp); + return; + } + cost = -2; + while (fgets (buf, sizeof(buf), lp_tmp) != NULL) { + fputs (buf, sisout); + if (! strncmp (buf, "total", 5)) { + sscanf (buf, "total %lf", &cost); + } + } + fclose (lp_tmp); + unlink (tmp); + unlink (in); + unlink (out); + } + else { + m1 = m2 = m3 = 0; + for (i = 0; i < array_n (constrs); i++) { + constr = array_fetch (constraint_t *, constrs, i); + switch (constr->type) { + case LE: + m1++; + break; + case GE: + m2++; + break; + case EQ: + m3++; + break; + default: + fail ("illegal linear constraint type"); + } + } + m = m1 + m2 + m3; + n = array_n (names); + a = ALLOC (double *, m + 3); + for (i = 1; i <= m + 2; i++) { + a[i] = ALLOC (double, n + 2); + for (j = 1; j <= n + 1; j++) { + a[i][j] = 0; + } + } + iposv = ALLOC (int, m + 1); + izrov = ALLOC (int, n + 1); + + if (astg_debug_flag > 1) { + fprintf (sisout, "variable names\n"); + for (i = 0; i < array_n (names); i++) { + str = array_fetch (char *, names, i); + fprintf (sisout, "%s x%d\n", str, i); + } + fprintf (sisout, "linear program:\nMIN\n"); + } + /* the cost function: MIN, hence cost -1 */ + to_min = st_init_table (st_numcmp, st_numhash); + for (i = 0; i < array_n (min_var); i++) { + j = array_fetch (int, min_var, i); + slow[j] = 0; + st_insert (to_min, (char *) j, (char *) i); + a[1][j+2] = -1; + if (astg_debug_flag > 1) { + fprintf (sisout, " x%d\n", j); + } + } + if (astg_debug_flag > 1) { + fprintf (sisout, "ST\n"); + } + r1 = r2 = r3 = 0; + for (i = 0; i < array_n (constrs); i++) { + constr = array_fetch (constraint_t *, constrs, i); + if (astg_debug_flag > 1) { + print_constr (sisout, constr); + } + switch (constr->type) { + case LE: + row = r1 + 2; + r1++; + break; + case GE: + row = m1 + r2 + 2; + r2++; + break; + case EQ: + row = m2 + r3 + 2; + r3++; + break; + default: + break; + } + for (j = 0; j < constr->n; j++) { + a[row][constr->vars[j]+2] = -constr->coeffs[j]; + } + a[row][1] = constr->val; + } + + if (astg_debug_flag > 1) { + fprintf (sisout, "solving...\n"); + } + /* run the simplex and analyze the result */ + if (re_simplx (a, m, n, m1, m2, m3, &icase, izrov, iposv)) { + fprintf (siserr, "%s\n", error_string ()); + error_init(); + return -2; + } + switch (icase) { + case 1: + fprintf (siserr, "unbounded solution ???\n"); + return -2; + case -1: + if (astg_debug_flag > 1) { + fprintf (sisout, "infeasible\n"); + } + return -2; + default: + break; + } + + cost = 0; + for (i = 1; i <= m; i++) { + if (iposv[i] <= n) { + if (! st_lookup_int (to_min, (char *) (iposv[i] - 1), &j)) { + continue; + } + cost += a[i+1][1]; + slow[j] = a[i+1][1]; + if (astg_debug_flag > 1) { + fprintf (sisout, "x%d by %f\n", i, a[i+1][1]); + } + } + } + + for (i = 1; i <= m + 2; i++) { + FREE (a[i]); + } + FREE (a); + st_free_table (to_min); + } + return cost; +} + +static void +write_lp_recur (constrs, min_var, names, slow, best_slow, n, do_bound, lindo, bound, eval, best_cost) +array_t *constrs, *min_var, *names; +double *slow, *best_slow; +int n, do_bound, lindo, *bound, *eval; +double *best_cost; +{ + int i, cnt; + constraint_t *constr, *constr1; + char *str; + double cost; + + /* look for the first MAX type constraint */ + for (; n < array_n (constrs); n++) { + constr = array_fetch (constraint_t *, constrs, n); + if (constr->level >= 0) { + /* we must resolve it... */ + break; + } + } + + if (n >= array_n (constrs)) { + /* bottom: solve the LP and return */ + cost = solve_lp (constrs, min_var, names, slow, eval, lindo); + if (*best_cost < 0 || (cost > -1 && cost < *best_cost)) { + for (i = 0; i < array_n (min_var); i++) { + best_slow[i] = slow[i]; + } + *best_cost = cost; + if (astg_debug_flag > 0) { + fprintf (sisout, "new BEST cost %f\n", *best_cost); + } + } + return; + } + + + /* choose one constraint at the current level */ + constr = array_fetch (constraint_t *, constrs, n); + cnt = 1; + for (i = n + 1; i < array_n (constrs); i++) { + constr1 = array_fetch (constraint_t *, constrs, i); + if (constr1->level != constr->level) { + break; + } + cnt++; + } + if (cnt > 1 && astg_debug_flag > 1) { + fprintf (sisout, "we must resolve %d constraints at level %d\n", + cnt, constr->level); + } + if (do_bound && cnt > 1) { + /* try to bound... */ + if (astg_debug_flag > 1) { + fprintf (sisout, "trying to bound...\n"); + } + cost = solve_lp (constrs, min_var, names, slow, eval, lindo); + if (cost < 0) { + (*bound)++; + if (astg_debug_flag > 1) { + fprintf (sisout, "bounding %f due to infeasibility\n", + cost, *best_cost); + } + return; + } + if (*best_cost > 0 && cost > *best_cost) { + (*bound)++; + if (astg_debug_flag > 1) { + fprintf (sisout, "bounding %f due to old best cost %f\n", + cost, *best_cost); + } + return; + } + } + /* sorry, we must recur... */ + for (i = 0; i < cnt; i++) { + /* set constraint "i" at the current level to be an equality */ + constr = array_fetch (constraint_t *, constrs, n + i); + assert (constr->type == GE); + constr->type = EQ; + if (astg_debug_flag > 1) { + fprintf (sisout, " setting equality for %d\n ", i); + print_constr (sisout, constr); + } + write_lp_recur (constrs, min_var, names, slow, best_slow, + n + cnt, do_bound, lindo, bound, eval, best_cost); + constr->type = GE; + } +} + +/* remove hazards by linear programming (JVSP paper) + */ +void +bwd_lp_slow (astg, network, hazard_list, external_del, pi_index, tol, default_del, min_delay_factor, do_bound, lindo) +astg_graph *astg; +network_t *network; +st_table *hazard_list, *external_del, *pi_index; +double tol, default_del, min_delay_factor; +int do_bound, lindo; +{ + array_t *hazards, *order, *comp, *names, *min_var, *constrs; + constraint_t *constr; + st_table *sig_table; + hazard_t hazard; + lsGen gen; + node_t *po, *node; + char *n; + int i, j, k, num, pair, sig_n, max_delta, level, bound, eval; + double w, best_cost, *slow, *best_slow; + double delta; + astg_trans *t1, *t2, *t3, *from, *to; + astg_place *p; + astg_signal *sig1, *sig2; + astg_generator tgen1, tgen2, tgen3, vgen, tgen, pgen, sgen; + astg_trans_enum type1, type2; + astg_vertex *v; + static char buf[512]; + bwd_node_t *bwd; + + pair = 0; + max_delta = 1; + names = array_alloc (char *, 0); + min_var = array_alloc (int, 0); + define_cube_size (st_count (pi_index)); + (void) get_mg_comp (astg, /*verbose*/ 0); + /* do a first update, to take into account the logic delays */ + bwd_external_delay_update (network, external_del, min_delay_factor, + /*silent*/ 1); + + sig_table = st_init_table (st_ptrcmp, st_ptrhash); + astg_foreach_signal (astg, sgen, sig1) { + /* create a new variable for the padded delay at the signal */ + sig_n = array_n (names); + sprintf (buf, "X_%s", astg_signal_name (sig1)); + n = util_strsav (buf); + array_insert_last (char *, names, n); + /* we want to minimize the padded delays */ + array_insert_last (int, min_var, sig_n); + + st_insert (sig_table, astg_signal_name (sig1), (char *) sig_n); + } + + foreach_node (network, gen, node) { + bwd = ALLOC (bwd_node_t, 1); + node->BWD_SLOT = (char *) bwd; + } + constrs = array_alloc (constraint_t *, 0); + level = 0; + foreach_primary_output (network, gen, po) { + if (network_is_real_po(network, po)) { + /* skip real PO's connected directly to the PI */ + node = node_get_fanin (po, 0); + if (node_type (node) == PRIMARY_INPUT) { + continue; + } + } + + n = bwd_po_name (node_long_name (po)); + assert (st_lookup (hazard_list, n, (char **) &hazards)); + for (i = 0; i < array_n (hazards); i++) { + hazard = array_fetch (hazard_t, hazards, i); + sig1 = astg_find_named_signal (astg, bwd_po_name (hazard.s1)); + assert (sig1 != NIL(astg_signal)); + sig2 = astg_find_named_signal (astg, bwd_po_name (hazard.s2)); + assert (sig2 != NIL(astg_signal)); + /* derive the upper bound on d2 - d1 */ + delta = hazard_delay (network, pi_index, po, &hazard, + min_delay_factor); + + if (astg_debug_flag > 2) { + fprintf (sisout, + "%s%c -> %s%c for %s d2 - d1 %f\n", + astg_signal_name (sig2), hazard.dir2, + astg_signal_name (sig1), hazard.dir1, + bwd_po_name (node_long_name (po)), delta); + } + if (delta < 0) { + if (astg_debug_flag > 2) { + fprintf (sisout, "trivially satisfied (%f < 0)\n", delta); + } + continue; + } + + /* now search each firing sequence between t2 and t1 ... */ + astg_foreach_vertex (astg, vgen, v) { + v->active = ASTG_FALSE; + v->on_path = ASTG_FALSE; + } + for (j = 0; j < array_n (astg->mg_comp); j++) { + /* explore MG component j */ + comp = array_fetch (array_t *, astg->mg_comp, j); + for (k = 0; k < array_n (comp); k++) { + v = array_fetch (astg_vertex *, comp, k); + v->active = ASTG_TRUE; + } + + type1 = (hazard.dir1 == '+') ? ASTG_POS_X : ASTG_NEG_X; + type2 = (hazard.dir2 == '+') ? ASTG_POS_X : ASTG_NEG_X; + astg_foreach_trans (astg, tgen1, t1) { + if (! t1->active || + astg_trans_sig (t1) != sig1 || + astg_trans_type (t1) != type1) { + continue; + } + astg_foreach_trans (astg, tgen2, t2) { + if (! t2->active || + astg_trans_sig (t2) != sig2 || + astg_trans_type (t2) != type2) { + continue; + } + if (astg_debug_flag > 2) { + fprintf (sisout, "exploring %s -> %s\n", + astg_trans_name (t2), astg_trans_name (t1)); + } + astg_foreach_vertex (astg, vgen, v) { + v->unprocessed = ASTG_TRUE; + v->subset = ASTG_FALSE; + } + /* do not process transitions of the same signal as t1 */ + astg_foreach_trans (astg, tgen3, t3) { + if (astg_trans_sig (t3) == astg_trans_sig (t1)) { + t3->unprocessed = ASTG_FALSE; + } + } + t1->subset = ASTG_TRUE; + find_astg_subset (t2); + astg_foreach_vertex (astg, vgen, v) { + v->alg.ts.index = 0; + v->unprocessed = v->subset; + } + num = 0; + ts_dfs (astg, t2, &num); + order = array_alloc (astg_vertex *, num); + if (num) { + astg_foreach_vertex (astg, vgen, v) { + if (! v->subset || v->vtype != ASTG_TRANS) { + continue; + } + array_insert (astg_vertex *, order, + (num - v->alg.ts.index - 1), v); + v->weight1.f = 0; + } + } + if (astg_debug_flag > 3) { + fprintf (sisout, "subset:"); + } + /* now check if the constraint is trivial */ + for (k = 0; k < array_n (order); k++) { + to = array_fetch (astg_vertex *, order, k); + astg_foreach_input_place (to, pgen, p) { + astg_foreach_input_trans (p, tgen, from) { + if (! from->subset) { + continue; + } + w = min_del (from, to, external_del, + default_del); + to->weight1.f = MAX (to->weight1.f, + from->weight1.f + w); + } + } + if (astg_debug_flag > 3) { + fprintf (sisout, " %s %f", astg_v_name (to), + to->weight1.f); + } + } + if (astg_debug_flag > 3) { + fprintf (sisout, "\n"); + } + if (t1->weight1.f > delta) { + if (astg_debug_flag > 2) { + fprintf (sisout, + "%s -> %s trivially satisfied (%f > %f)\n", + astg_trans_name (t2), astg_trans_name (t1), + t1->weight1.f, delta); + } + array_free (order); + continue; + } + + /* produce the constraints */ + pair++; + if (astg_debug_flag > 2) { + fprintf (sisout, + "%s -> %s produces constraint\n", + astg_trans_name (t2), astg_trans_name (t1)); + } + write_constr (t1, t2, constrs, order, + names, min_var, external_del, sig_table, pair, + &level, delta, default_del); + max_delta = MAX (delta, max_delta); + array_free (order); + } + } + } + } + } + foreach_node (network, gen, node) { + FREE (node->BWD_SLOT); + } + + if (astg_debug_flag > 0) { + fprintf (sisout, "%d constraints %d variables\n", + array_n (constrs), array_n (names)); + } + bound = 0; + eval = 0; + if (array_n (constrs)) { + best_cost = -1; + slow = ALLOC (double, array_n (min_var)); + best_slow = ALLOC (double, array_n (min_var)); + write_lp_recur (constrs, min_var, names, slow, best_slow, + 0, do_bound, lindo, &bound, &eval, &best_cost); + + for (i = 0; i < array_n (min_var); i++) { + if (best_slow[i] > 0.0) { + n = array_fetch (char *, names, i); + fprintf (sisout, "slowing %s by %f\n", &n[2], best_slow[i]); + } + } + FREE (slow); + FREE (best_slow); + } + else { + best_cost = 0; + } + fprintf (sisout, "final BEST slow down %f %d boundings %d evaluations\n", + best_cost, bound, eval); + + /* free and wrap up */ + for (i = 0; i < array_n (names); i++) { + n = array_fetch (char *, names, i); + FREE (n); + } + for (i = 0; i < array_n (constrs); i++) { + constr = array_fetch (constraint_t *, constrs, i); + FREE (constr->vars); + FREE (constr->coeffs); + FREE (constr); + } + array_free (constrs); + array_free (names); + array_free (min_var); + st_free_table (sig_table); +} +#endif /* SIS */ diff --git a/sis/astg/bwd_min_delay.c b/sis/astg/bwd_min_delay.c new file mode 100644 index 0000000..57e2d19 --- /dev/null +++ b/sis/astg/bwd_min_delay.c @@ -0,0 +1,650 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/bwd_min_delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +#ifdef SIS +/* + * The purpose of this package is the computation of node and network delays + * in MIS. Delays are returned as delay_time_t structures, which contain two + * doubles, rise and fall. + * + * This package is designed to manipulate the basic timing package. In + * particular, routines are provided to compute the delay of a node for both + * rising and falling times, to reset the delay model to a specialized + * function, if desired, or to provide parameters to the default delay model. + * + * The delay package that comes with mis/sis computes MAXIMUM delays: this is a + * copy that computes MINIMUM delays. Eventually we should use simulation to + * compute both. + */ +#include +#include +#include "sis.h" +#include "min_delay_int.h" + +node_t * min_delay_latest_output(); +static jmp_buf delay_botch; + +static void set_arrival_time(); +static void set_required_time(); +static void set_fanout_load(); +static void delay_error(); +static void allocate_pin_params(); +static delay_time_t compute_delay(); +static network_t *map_node_to_network(); +static void delay_force_pininfo(); +#ifndef lint +static void print_pin_delays(); +#endif +static delay_time_t pi_arrival_time(); +static delay_time_t po_required_time(); + +#define node_type(n) ((n)->type) + +static delay_time_t time_not_given = { + DELAY_VALUE_NOT_GIVEN, DELAY_VALUE_NOT_GIVEN +}; + +static double delay_value_not_given = DELAY_VALUE_NOT_GIVEN; + +#undef DELAY_VALUE_NOT_GIVEN +#define DELAY_VALUE_NOT_GIVEN delay_value_not_given + +int +bwd_min_delay_trace(network, model) +network_t *network; +delay_model_t model; +{ + int i; + node_t *node; + array_t *nodevec; + double latest; + lsGen gen; + delay_node_t *delay; + + error_init(); + if (setjmp(delay_botch)) { + return 0; + } + + if (DEF_DELAY(network) == NIL(delay_network_t)) { + delay_network_alloc(network); + } + + /* compute the load on each driver */ + foreach_node (network, gen, node) { + set_fanout_load(node, model); + } + + /* Compute arrival times */ + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + set_arrival_time(node, model); + } + array_free(nodevec); + + /* Find latest output */ + (void) min_delay_latest_output(network, &latest); + + /* compute required times */ + nodevec = network_dfs_from_input(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + set_required_time(node, latest, model); + } + array_free(nodevec); + + /* finally, compute the slacks */ + foreach_node (network, gen, node) { + delay = DELAY(node); + delay->slack.rise = delay->required.rise - delay->arrival.rise; + delay->slack.fall = delay->required.fall - delay->arrival.fall; + } + + return 1; +} + +#define ARRIVAL(time, new_time) _arrival(&(time), (new_time)) + +static void +_arrival(time, new_time) +double *time, new_time; +{ + if (new_time < *time) { + *time = new_time; + } +} + +static void +set_arrival_time(node, model) +register node_t *node; +delay_model_t model; +{ + register int i; + register node_t *fanin; + delay_pin_t *pin_delay; + delay_time_t delay, *node_arrival, fanin_arrival; + delay_node_t *node_delay; + pin_phase_t phase; + + node_delay = DELAY(node); + + if (node_type(node) == PRIMARY_INPUT) { + node_delay->arrival = pi_arrival_time(node); + + pin_delay = get_pin_delay(node, /* pin */ 0, model); + delay = compute_delay(node, pin_delay, model); + + node_delay->arrival.rise += delay.rise; + node_delay->arrival.fall += delay.fall; + return; + } + else if (node_type(node) == PRIMARY_OUTPUT) { + fanin = node_get_fanin(node, 0); + node_delay->arrival.rise = DELAY(fanin)->arrival.rise; + node_delay->arrival.fall = DELAY(fanin)->arrival.fall; + return; + } + + node_arrival = &node_delay->arrival; + node_arrival->rise = INFINITY; + node_arrival->fall = INFINITY; + + foreach_fanin (node, i, fanin) { + pin_delay = get_pin_delay(node, i, model); + delay = compute_delay(node, pin_delay, model); + + fanin_arrival = DELAY(fanin)->arrival; + phase = pin_delay->phase; + if (phase == PHASE_NOT_GIVEN) { + delay_error("set_arrival_time: bad pin phase\n"); + } + if (phase == PHASE_INVERTING || phase == PHASE_NEITHER) { + ARRIVAL(node_arrival->rise, fanin_arrival.fall + delay.rise); + ARRIVAL(node_arrival->fall, fanin_arrival.rise + delay.fall); + } + if (phase == PHASE_NONINVERTING || phase == PHASE_NEITHER) { + ARRIVAL(node_arrival->rise, fanin_arrival.rise + delay.rise); + ARRIVAL(node_arrival->fall, fanin_arrival.fall + delay.fall); + } + } +} + +/* Compute the arrival time for a primary input. */ + +static delay_time_t +pi_arrival_time(node) +node_t *node; +{ + delay_time_t delay; + delay_pin_t *pin_delay; + + pin_delay = DELAY(node)->pin_delay; + delay = DEF_DELAY(node_network(node))->default_arrival; + + if (pin_delay != 0 && + pin_delay->user_time.rise != DELAY_VALUE_NOT_GIVEN && + pin_delay->user_time.fall != DELAY_VALUE_NOT_GIVEN) { + return(pin_delay->user_time); + } + else if (delay.rise != DELAY_VALUE_NOT_GIVEN && + delay.fall != DELAY_VALUE_NOT_GIVEN) { + return(delay); + } + else { + delay.rise = 0; + delay.fall = 0; + return(delay); + } +} + + +#define REQUIRED(time, new_time) _required(&(time), (new_time)) + +static void +_required(time, new_time) +double *time, new_time; +{ + if (new_time < *time) { + *time = new_time; + } +} + +static void +set_required_time(node, latest, model) +node_t *node; +double latest; +delay_model_t model; +{ + int pin; + node_t *fanout; + delay_pin_t *pin_delay; + delay_time_t delay, *node_required, fanout_required; + delay_node_t *node_delay; + pin_phase_t phase; + lsGen gen; + + node_delay = DELAY(node); + if (node_type(node) == PRIMARY_OUTPUT) { + node_delay->required = po_required_time(node, latest); + return; + } + + node_required = &node_delay->required; + node_required->rise = -INFINITY; + node_required->fall = -INFINITY; + + foreach_fanout_pin(node, gen, fanout, pin) { + fanout_required = DELAY(fanout)->required; + if (node_type(fanout) == PRIMARY_OUTPUT) { + REQUIRED(node_required->rise, fanout_required.rise); + REQUIRED(node_required->fall, fanout_required.fall); + continue; + } + + pin_delay = get_pin_delay(fanout, pin, model); + delay = compute_delay(fanout, pin_delay, model); + phase = pin_delay->phase; + if (phase == PHASE_NOT_GIVEN) { + delay_error("set_required_time: bad pin phase\n"); + } + if (phase == PHASE_INVERTING || phase == PHASE_NEITHER) { + REQUIRED(node_required->rise, fanout_required.fall - delay.fall); + REQUIRED(node_required->fall, fanout_required.rise - delay.rise); + } + if (phase == PHASE_NONINVERTING || phase == PHASE_NEITHER) { + REQUIRED(node_required->rise, fanout_required.rise - delay.rise); + REQUIRED(node_required->fall, fanout_required.fall - delay.fall); + } + } +} + +/* Compute the required time at a primary output */ + +static delay_time_t +po_required_time(node, latest) +node_t *node; +double latest; +{ + delay_time_t delay; + delay_pin_t *pin_delay; + + pin_delay = DELAY(node)->pin_delay; + delay = DEF_DELAY(node_network(node))->default_required; + + if (pin_delay != NIL(delay_pin_t) && + pin_delay->user_time.rise != DELAY_VALUE_NOT_GIVEN && + pin_delay->user_time.fall != DELAY_VALUE_NOT_GIVEN) { + return(pin_delay->user_time); + } + else if (delay.rise != DELAY_VALUE_NOT_GIVEN && + delay.fall != DELAY_VALUE_NOT_GIVEN) { + return(delay); + } + else { + delay.rise = latest; + delay.fall = latest; + return(delay); + } +} + + +static void +set_fanout_load(node, model) +node_t *node; +delay_model_t model; +{ + int pin; + node_t *fanout; + delay_pin_t *pin_delay; + lsGen gen; + + /* Sum the output capacitance (load of each pin we fanout to) */ + + DELAY(node)->load = compute_wire_load(node_network(node), node_num_fanout(node)); + foreach_fanout_pin (node, gen, fanout, pin) { + pin_delay = get_pin_delay(fanout, pin, model); + DELAY(node)->load += pin_delay->load; + } +} + +/* + * Allocate storage for new pin params, attempting to reuse storage where + * possible. The number of fanins is the number of delays we need, number of + * allocated parameters is the number we have. If we have allocated none, + * then just do a standard storage allocation. If we have too few, copy the + * storage we do have and allocate the rest. If we have too many, copy what + * we need and free the rest. If we have just the right number (I suspect, + * the usual case), then do nothing. + */ +static void +allocate_pin_params(node) +node_t *node; +{ + int nparams, n_old_params, i; + delay_pin_t **old_pins, **new_pins; + delay_node_t *delay; + + nparams = node_num_fanin(node); + delay = DELAY(node); + n_old_params = delay->num_pin_params; + + if (delay->pin_params == NIL(delay_pin_t *)) { + delay->num_pin_params = nparams; + new_pins = ALLOC(delay_pin_t *, nparams); + for (i = 0; i < nparams; i++) { + new_pins[i] = ALLOC(delay_pin_t, 1); + } + delay->pin_params = new_pins; + } + else if (nparams != n_old_params) { + old_pins = delay->pin_params; + new_pins = ALLOC(delay_pin_t *, nparams); + + if (n_old_params < nparams) { + for (i = 0; i < n_old_params; i++) { + new_pins[i] = old_pins[i]; + } + for (i = n_old_params; i < nparams; i++) { + new_pins[i] = ALLOC(delay_pin_t, 1); + } + } + else { + for (i = 0; i < n_old_params; i++) { + new_pins[i] = old_pins[i]; + } + for (i = nparams; i < n_old_params; ++i) { + FREE(old_pins[i]); + } + } + FREE(old_pins); + delay->pin_params = new_pins; + /* BUG FIX: by KJ --- Set the field for the no. of parameters */ + delay->num_pin_params = nparams; + } +} + +/* + * Essentially similar to compute mapped params -- but also returns the + * mapped network. Put on request of the speedup package where a node may + * be replaced by its decomposition + */ +network_t * +min_delay_generate_decomposition(node, mode) +node_t *node; +double mode; +{ + network_t *network; + int i, found = 0; + delay_pin_t *pin, *pin1; + lsGen gen, gen1; + node_t *this_node, *out_node, *fanin, *p, *q, *r; + char *name; + delay_time_t *user_time; + + /* Just in case one did not allocate the storage for the mapped model */ + allocate_pin_params(node); + if ((network = map_node_to_network(node, mode)) == NIL(network_t)) + delay_error(NIL(char)); + + /* + * Strategy here is to assume that all the delay at reaching the output is + * due to the ith input pin. Hence, we begin by setting the arrival times + * of all inputs to INFINITY and the output loads driven to be 0. This + * means (again, for linear models) that the delay across the node is + * ENTIRELY due to the set delay for the ith pin. + */ + + foreach_primary_output(network, gen, out_node) { /* only one */ + DELAY(out_node)->load = 0; + } + + foreach_primary_input(network, gen, this_node) { + delay_force_pininfo(this_node); + /* + delay_set_parameter(this_node, DELAY_ARRIVAL_RISE, INFINITY); + delay_set_parameter(this_node, DELAY_ARRIVAL_FALL, INFINITY); + */ + user_time = &DELAY(this_node)->pin_delay->user_time; + user_time->rise = INFINITY; + user_time->fall = INFINITY; + } + + foreach_primary_input(network, gen, this_node){ + name = node_name(this_node); + found = 0; + + /* + * Find the pin which corresponds to input this_node of the mapped + * network + */ + foreach_fanin(node, i, fanin) { + if (strcmp(name, node_name(fanin)) == 0) { + found = 1; + break; + } + } + if (found == 0) { + delay_error("Severe internal error in mapped delay model"); + } + + pin = DELAY(node)->pin_params[i]; + + /* + * Compute the phase. Computes node = pf + qf' + r (f == fanin). + * Node is inverting iff q != 0; both if p != 0, q != 0; noninverting + * otherwise + */ + node_algebraic_cofactor(node, fanin, &p, &q, &r); + + if (node_function(q) == NODE_0) { + pin->phase = PHASE_NONINVERTING; + } + else if (node_function(p) == NODE_0) { + pin->phase = PHASE_INVERTING; + } + else { + pin->phase = PHASE_NEITHER; + } + + node_free(p); + node_free(q); + node_free(r); + + user_time = &DELAY(this_node)->pin_delay->user_time; + user_time->rise = 0; + user_time->fall = 0; + + /* + * Compute block parameter. This is the delay result when the network + * output is driving a load of 0. The drive parameter, similarly, is + * equal to the drive parameter of the node driving the output. + */ + (void) bwd_min_delay_trace(network, DELAY_MODEL_LIBRARY); + + foreach_primary_output(network, gen1, out_node) { /* only one */ + pin->block = delay_arrival_time(out_node); + /* + * It turns out that the drive parameter for each pin of node is + * equal to the drive parameter of the (single) fanin of the + * output node of the mapped network. Get this fanin. We do it + * through a foreach loop because that's the easiest way to do it, + * but we ought to go through this loop only once. Ditto for the + * outer loop + */ + pin1 = get_pin_delay(out_node, 0, DELAY_MODEL_LIBRARY); + pin->drive = pin1->drive; + + } + + /* Compute the load. This is a little tricky, so watch the comment */ + + pin -> load = DELAY(this_node) -> load; + + /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Naive and WRONG. The load on this_node (a PI) is merely the + load on the buffer it drives. What we want is the load driven by + that buffer. The following code gets it: */ + + + /* + foreach_fanout_pin(this_node, gen1, p, i) { + pin -> load = DELAY(p) -> load; + } + */ + + +#ifdef DEBUG + printf("Pin parameters for node %s, pin %s\n", node_name(node), + node_name(fanin)); + printf("pin %d br %f bf %f dr %f df %f phase %s load %f alt_load %f\n", + i, pin -> block.rise, pin -> block.fall, + pin -> drive.rise, pin -> drive.fall, + (pin -> phase == PHASE_INVERTING?"neg": + (pin -> phase == PHASE_NONINVERTING?"pos":"both")), + pin -> load, DELAY(this_node) -> load); +#endif + + + /* reset this node's user time given to be INFINITY for next + iteration */ + + user_time = &DELAY(this_node)->pin_delay->user_time; + user_time->rise = INFINITY; + user_time->fall = INFINITY; + } + return(network); +} + +/* Model dependent code */ +static delay_time_t +compute_delay(node, pin_delay, model) +node_t *node; +delay_pin_t *pin_delay; +delay_model_t model; +{ + delay_time_t delay; + + switch(model) { + case DELAY_MODEL_UNIT: + case DELAY_MODEL_UNIT_FANOUT: + case DELAY_MODEL_LIBRARY: + case DELAY_MODEL_MAPPED: + delay.rise = pin_delay->drive.rise * DELAY(node)->load; + delay.fall = pin_delay->drive.fall * DELAY(node)->load; + if (node_type(node) != PRIMARY_INPUT) { + delay.rise += pin_delay->block.rise; + delay.fall += pin_delay->block.fall; + } + break; + default: + delay_error("compute_delay: bad model type"); + /* NOTREACHED */ + } + return delay; +} + +static void +delay_error(string) +char *string; +{ + if (string != NIL(char)) { + error_append(string); + } + longjmp(delay_botch, 1); +} + +#define DELAY_NODE_CHECK(network, node, fname) \ + network = network_of_node(node);\ + if(!network_has_been_traced(network)) {\ + fail("fname called before trace done\n");\ + } else if (network_has_been_modified(network)) {\ + (void)fprintf(siserr,\ + "Warning: network modified between delay_trace and fname\n");\ + } + + +node_t * +min_delay_latest_output(network, latest_p) +network_t *network; +double *latest_p; +{ + node_t *po, *last_output; + lsGen gen; + double latest; + delay_time_t arrival; + + /* Goes in when I get the name of the fns from RR + DELAY_NODE_CHECK(network, node, min_delay_latest_output); + */ + + /* Find latest output */ + latest = INFINITY; + last_output = 0; + + foreach_primary_output (network, gen, po) { + arrival = DELAY(po)->arrival; + if (arrival.rise > latest) { + latest = arrival.rise; + last_output = po; + } + if (arrival.fall > latest) { + latest = arrival.fall; + last_output = po; + } + } + + *latest_p = latest; + return(last_output); +} + + +static void +delay_force_pininfo(node) +node_t *node; +{ + delay_pin_t *pin_delay; + + assert(node != NIL(node_t)); + if (DELAY(node) == NIL(delay_node_t)) { + delay_alloc(node); + } + if (DELAY(node)->pin_delay == NIL(delay_pin_t)) { + DELAY(node)->pin_delay = pin_delay = ALLOC(delay_pin_t, 1); + pin_delay->block = time_not_given; + pin_delay->drive = time_not_given; + /* BUG FIX: by KJ --- Earlier the phase was not initialized */ + pin_delay->phase = PHASE_NOT_GIVEN; + pin_delay->load = DELAY_VALUE_NOT_GIVEN; + pin_delay->max_load = DELAY_VALUE_NOT_GIVEN; + pin_delay->user_time = time_not_given; + } +} + +static network_t * +map_node_to_network(node, mode) +node_t *node; +double mode; +{ + network_t *net1, *net2; + library_t *library; + + if ((library = lib_get_library()) == NIL(library_t)) { + delay_error("Mapped Delay model: no current library\n"); + return(NIL(network_t)); /* Not reached -- in to keep lint happy */ + } else { + net1 = network_create_from_node(node); + net2 = map_network(net1, library, mode, 1, 0); /* user spec mode & inverters */ + network_free(net1); + return net2; + } +} + +#undef node_type +#endif /* SIS */ diff --git a/sis/astg/bwd_slow.c b/sis/astg/bwd_slow.c new file mode 100644 index 0000000..387312a --- /dev/null +++ b/sis/astg/bwd_slow.c @@ -0,0 +1,635 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/bwd_slow.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +#ifdef SIS +/* Routines that insert inverter pairs where a potential hazard can actually + * occur. + * The static symbol table slowed_amounts keeps an information on how much + * each signal is slowed. + */ +#include "sis.h" +#include "astg_int.h" +#include "astg_core.h" +#include "bwd_int.h" +#include + +#define XOR(a,b) (((a)&&!(b))||(!(a)&&(b))) +/* tests on floating point equality */ +#define EPS 1.e-24 +#define EQ(a,b) (fabs((a)-(b)) < EPS) + +static delay_time_t delay_simulate (); + +/* Write back into the external delay table the MINIMUM delays PI->PO as updated + * after the synthesis/hazard removal procedure. + * Inform the user if the table was actually changed, so that iteration is + * required. + * The table is organized as a double-level symbol table, indexed by signal + * names in the STG form (i.e. the true PO form) + * The first level is indexed by the name of the signal from which the delay + * is requested. Each entry at the first level is a symbol table indexed by + * the name of the signal to which the delay is requested. Each entry at the + * second level is a delay record. + */ +void +bwd_external_delay_update (network, external_del, min_delay_factor, silent) +network_t * network; +st_table *external_del; +double min_delay_factor; +int silent; +{ + st_table *to_table; + node_t *pi, *po, *node; + delay_time_t delay; + min_del_t new_delay, *old_delay; + lsGen pigen, pogen; + int updated, found; + + if (external_del == NIL(st_table)) { + return; + } + updated = 0; + foreach_primary_input (network, pigen, pi) { + foreach_primary_output (network, pogen, po) { + if (network_is_real_po(network, po)) { + /* skip real PO's connected directly to the PI */ + node = node_get_fanin (po, 0); + if (node_type (node) == PRIMARY_INPUT) { + continue; + } + } + delay = delay_simulate (network, pi, po, /* is_max */ 0, + min_delay_factor); + /* INFINITY needs not to be stored */ + if ((delay.rise > (INFINITY / 100.0)) && + (delay.fall > (INFINITY / 100.0))) { + continue; + } + new_delay.rise = delay; + new_delay.fall = delay; + + /* DO NOT update only if already present AND smaller */ + if ((found = st_lookup (external_del, bwd_po_name (node_long_name (pi)), + (char **) &to_table)) && + (found = st_lookup (to_table, bwd_po_name (node_long_name (po)), + (char **) &old_delay)) && + (old_delay->rise.rise < new_delay.rise.rise || + EQ(old_delay->rise.rise, new_delay.rise.rise)) && + (old_delay->rise.fall < new_delay.rise.fall || + EQ(old_delay->rise.fall, new_delay.rise.fall)) && + (old_delay->fall.rise < new_delay.fall.rise || + EQ(old_delay->fall.rise, new_delay.fall.rise)) && + (old_delay->fall.fall < new_delay.fall.fall || + EQ(old_delay->fall.fall, new_delay.fall.fall))) { + continue; + } + + updated = 1; + if (astg_debug_flag > 1) { + if (found) { + fprintf (sisout, + "Updating the delay %s -> %s ++ %f->%f +- %f->%f -+ %f->%f -- %f->%f\n", + node_long_name (pi), node_long_name (po), + old_delay->rise.rise, new_delay.rise.rise, + old_delay->rise.fall, new_delay.rise.fall, + old_delay->fall.rise, new_delay.fall.rise, + old_delay->fall.fall, new_delay.fall.fall); + } + else { + fprintf (sisout, + "Inserting the delay %s -> %s %f %f %f %f\n", + node_long_name (pi), node_long_name (po), + new_delay.rise.rise, + new_delay.rise.fall, + new_delay.fall.rise, + new_delay.fall.fall); + } + } + + if (! st_lookup (external_del, bwd_po_name (node_long_name (pi)), + (char **) &to_table)) { + to_table = st_init_table (strcmp, st_strhash); + st_insert (external_del, + util_strsav (bwd_po_name (node_long_name (pi))), + (char *) to_table); + } + if (! st_lookup (to_table, bwd_po_name (node_long_name (po)), (char **) + &old_delay)) { + old_delay = ALLOC (min_del_t, 1); + st_insert (to_table, + util_strsav (bwd_po_name (node_long_name (po))), + (char *) old_delay); + } + *old_delay = new_delay; + } + } + if (! silent && updated) { + fprintf (siserr, "Warning: the delay table has been updated\n"); + } +} + +/* Perform a delay trace to the network (eventually this must become a delay + * simulation, as the name suggests) by setting: + * 1) the arrival time of "from" to 0. + * 2) all other arrival times to INFINITY or -INFINITY (depending on whether we + * check for max or min delay). + * We return the maximum or minimum arrival time at "to" (depending on + * "is_max"). + */ +static delay_time_t +delay_simulate (network, from, to, is_max, min_delay_factor) +network_t *network; +node_t *from, *to; +int is_max; +double min_delay_factor; +{ + lsGen gen; + node_t *pi, *node; + delay_time_t delay1; + + foreach_primary_input (network, gen, pi) { + if (is_max) { + delay_set_parameter (pi, DELAY_ARRIVAL_RISE, (double) -INFINITY); + delay_set_parameter (pi, DELAY_ARRIVAL_FALL, (double) -INFINITY); + } + else { + delay_set_parameter (pi, DELAY_ARRIVAL_RISE, (double) INFINITY); + delay_set_parameter (pi, DELAY_ARRIVAL_FALL, (double) INFINITY); + } + } + delay1.rise = (double) -INFINITY; + delay1.fall = (double) -INFINITY; + + delay_set_parameter (from, DELAY_ARRIVAL_RISE, (double) 0); + delay_set_parameter (from, DELAY_ARRIVAL_FALL, (double) 0); + delay_set_parameter (to, DELAY_OUTPUT_LOAD, (double) 1.0); + + if (is_max) { + assert (delay_trace (network, DELAY_MODEL_LIBRARY)); + } + else { + assert (bwd_min_delay_trace (network, DELAY_MODEL_LIBRARY)); + } + + if (astg_debug_flag > 3) { + foreach_node (network, gen, node) { + delay1 = delay_arrival_time (node); + fprintf (sisout, "%s arrival %s: %2.2f %2.2f\n", + is_max ? "max" : "min", + node_long_name (node), delay1.rise, delay1.fall); + } + } + + delay1 = delay_arrival_time (to); + if (! is_max) { + /* we should really support min-max delays ... */ + delay1.rise *= min_delay_factor; + delay1.fall *= min_delay_factor; + } + if (astg_debug_flag > 2) { + fprintf (sisout, "%s delay %s->%s: %2.2f %2.2f\n", + is_max ? "max" : "min", + node_long_name (from), node_long_name(to), delay1.rise, delay1.fall); + } + return delay1; +} + +/* Retrieve or compute the values of "d3" for all PI-PO pairs. + * Each delay is stored as a double into a square matrix, where the first index + * runs across signals "from" which the delay is computed, and the second index + * runs across signals "to" which the delay is computed (we have "nd3s" signals + * of each kind, so the matrix is nd3s x nd3s). + * The "pio" symbol table is indexed by primary INPUT names, and contains for + * each name the index (valid both as "from" and "to" index) in the "d3s" + * matrix. + * We use, in order: + * 1) the delay_simulate routine, for "to" signals we are synthesizing now. + * 2) the external_del symbol table, for signal pairs that were synthesized + * previously. + * 3) the default delay. + * 4) the Floyd-Warshall all pair shortest path algorithm (if "shortest_path" + * is true). + */ +static void +fill_d3s (network, d3s, nd3s, pio, external_del, shortest_path, default_del, min_delay_factor) +network_t *network; +double **d3s; +int nd3s; +st_table *pio, *external_del; +int shortest_path; +double default_del, min_delay_factor; +{ + int from, to, iter; + lsGen gen, gen1; + node_t *po, *pi, *pi1, *node; + delay_time_t delay; + min_del_t *delay_p; + char *from_name, *to_name; + st_generator *pigen, *pogen; + st_table *to_table; + double new_del; + + /* initialize the array */ + for (from = 0; from < nd3s; from++) { + for (to = 0; to < nd3s; to++) { + d3s[from][to] = INFINITY; + } + } + + /* first try to get delays for signals we are synthesizing */ + foreach_primary_input (network, gen, pi) { + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi)), &from)); + foreach_primary_output (network, gen1, po) { + if (network_is_real_po(network, po)) { + /* skip real PO's connected directly to the PI */ + node = node_get_fanin (po, 0); + if (node_type (node) == PRIMARY_INPUT) { + continue; + } + } + assert (st_lookup_int (pio, bwd_po_name (node_long_name (po)), &to)); + delay = delay_simulate (network, pi, po, /* is_max */ 0, + min_delay_factor); + d3s[from][to] = MIN (delay.rise, delay.fall); + if (d3s[from][to] < 0) { + /* this means no path inside our network between "from" and "to" */ + d3s[from][to] = INFINITY; + } + } + } + + if (external_del != NIL(st_table)) { + /* print out debugging information */ + if (astg_debug_flag > 2) { + fprintf (sisout, "before external delay:\n"); + foreach_primary_input (network, gen, pi) { + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi)), &from)); + foreach_primary_input (network, gen1, pi1) { + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi1)), &to)); + fprintf (sisout, "d3: %s->%s : %2.2f\n", + node_long_name (pi), node_long_name (pi1), + d3s[from][to]); + } + } + } + + /* now get as much information as possible from the external delay table */ + st_foreach_item (external_del, pigen, (char **) &from_name, + (char **) &to_table) { + assert (st_lookup_int (pio, from_name, &from)); + st_foreach_item (to_table, pogen, (char **) &to_name, + (char **) &delay_p) { + assert (st_lookup_int (pio, to_name, &to)); + new_del = MIN (MIN (delay_p->rise.rise, delay_p->rise.fall), + MIN (delay_p->fall.rise, delay_p->fall.fall)); + if (d3s[from][to] > new_del) { + d3s[from][to] = new_del; + } + } + } + } + + if (shortest_path) { + /* print out debugging information */ + if (astg_debug_flag > 2) { + fprintf (sisout, "before shortest path:\n"); + foreach_primary_input (network, gen, pi) { + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi)), &from)); + foreach_primary_input (network, gen1, pi1) { + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi1)), &to)); + fprintf (sisout, "d3: %s->%s : %2.2f\n", + node_long_name (pi), node_long_name (pi1), + d3s[from][to]); + } + } + } + /* use Floyd-Warshall for all pairs shortest path */ + for (iter = 0; iter < nd3s; iter++) { + for (from = 0; from < nd3s; from++) { + for (to = 0; to < nd3s; to++) { + if (d3s[from][to] > + (d3s[from][iter] + d3s[iter][to])) { + d3s[from][to] = + d3s[from][iter] + d3s[iter][to]; + } + } + } + } + } + + /* print out debugging information */ + if (astg_debug_flag > 2) { + fprintf (sisout, "before default delay:\n"); + foreach_primary_input (network, gen, pi) { + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi)), &from)); + foreach_primary_input (network, gen1, pi1) { + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi1)), &to)); + fprintf (sisout, "d3: %s->%s : %2.2f\n", + node_long_name (pi), node_long_name (pi1), + d3s[from][to]); + } + } + } + + /* now set all still unspecified delays to the default value */ + for (from = 0; from < nd3s; from++) { + for (to = 0; to < nd3s; to++) { + /* I don't like this test, but... */ + if (d3s[from][to] > (INFINITY / 100.0)) { + d3s[from][to] = default_del; + } + } + } + + /* print out debugging information */ + if (astg_debug_flag > 2) { + fprintf (sisout, "final d3 table:\n"); + foreach_primary_input (network, gen, pi) { + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi)), &from)); + foreach_primary_input (network, gen1, pi1) { + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi1)), &to)); + fprintf (sisout, "d3: %s->%s : %2.2f\n", + node_long_name (pi), node_long_name (pi1), + d3s[from][to]); + } + } + } +} + +/* For each "i" signal in the network (hazard.s1, pi1) we check that the effect + * of its "j" input (hazard.s2, pi2) has finished propagating in the circuit + * for "t" (po). + * This amount to check that, if + * d1 = min delay (pi1 -> po) + * d2 = max delay (pi2 -> po) + * d3 = min delay (pi2 -> pi1) + * then we have a hazard if d2 is less than d3 plus d1, using the tolerance + * "tol". In case of problems, we slow down the worst such pi1 for each po, and + * loop. + * The external delays (i.e. from output signals to output signals) are + * looked up in the "external_del" table. Otherwise "default_del" is used. + * Moreover an all-pair shortest path algorithm is used (if "shortest_path" is + * 1) to infer missing delay pairs (i.e. if a -> b is 5 and b -> c is 3, then + * a -> c is assumed to be 8...). + * When computing MINIMUM delays, they are MULTIPLIED by min_delay_factor + * (until we will be able to provide somtheing better for min/max delays). + * If do_slow is 0, then only the external delays are updated as appropriate. + */ + +void +bwd_slow_down (network, hazard_list, slowed_amounts, external_del, tol, default_del, min_delay_factor, shortest_path, iterate, do_slow) +network_t *network; +st_table *hazard_list, *slowed_amounts, *external_del; +double tol, default_del, min_delay_factor; +int shortest_path, iterate, do_slow; +{ + char *buf; + node_t *po, *pi, *pi1, *pi2, *inv1, *inv2, *fanout, *pi1_sav, *pi2_sav; + node_t *node; + char dir1, dir2; + lib_gate_t *inv, *lib_get_default_inverter(); + array_t *hazards, *old_hazards; + hazard_t hazard, hazard1; + delay_time_t delay1, delay2, slowed_delay; + double d1, d2, d3, max_diff, *slowed, zero, curr_slow; + double **d3s; + int i, j, failed, from, to, nd3s; + lsGen gen, gen1; + st_table *pio, *to_table; + st_generator *pigen, *pogen; + char *from_name, *to_name; + double *delay_p; + + inv = lib_get_default_inverter(); + zero = 0; + + /* initialize the PI/PO name -> index table and the d3 matrix */ + pio = st_init_table (strcmp, st_strhash); + nd3s = 0; + foreach_primary_input (network, gen, pi) { + st_insert (pio, util_strsav (bwd_po_name (node_long_name (pi))), + (char *) nd3s++); + } + foreach_primary_output (network, gen, po) { + if (! st_is_member (pio, bwd_po_name (node_long_name (po)))) { + st_insert (pio, util_strsav (bwd_po_name (node_long_name (po))), + (char *) nd3s++); + } + } + if (external_del != NIL(st_table)) { + st_foreach_item (external_del, pigen, (char **) &from_name, + (char **) &to_table) { + if (! st_lookup (pio, from_name, NIL (char *))) { + st_insert (pio, util_strsav (from_name), (char *) nd3s++); + } + st_foreach_item (to_table, pogen, (char **) &to_name, + (char **) &delay_p) { + if (! st_lookup (pio, to_name, NIL (char *))) { + st_insert (pio, util_strsav (to_name), (char *) nd3s++); + } + } + } + } + + d3s = ALLOC (double *, nd3s); + for (i = 0; i < nd3s; i++) { + d3s[i] = ALLOC (double, nd3s); + } + + fill_d3s (network, d3s, nd3s, pio, external_del, shortest_path, + default_del, min_delay_factor); + + if (do_slow) { + /* now slow down each PO in the network */ + foreach_primary_output (network, gen, po) { + if (network_is_real_po(network, po)) { + /* skip real PO's connected directly to the PI */ + node = node_get_fanin (po, 0); + if (node_type (node) == PRIMARY_INPUT) { + continue; + } + } + buf = bwd_po_name (node_long_name (po)); + assert (st_lookup (hazard_list, buf, (char **) &old_hazards)); + /* avoid uninteresting ones (here we are less strict than when we + * store them, since we do not care about rising or falling delays...) + */ + hazards = array_alloc (hazard_t, 0); + if (astg_debug_flag > 0) { + fprintf (sisout, "Hazards checked for %s:\n", buf); + } + for (i = 0; i < array_n (old_hazards); i++) { + hazard = array_fetch (hazard_t, old_hazards, i); +#if 0 + /* use them all, for error reporting */ + for (j = 0; j < array_n (hazards); j++) { + hazard1 = array_fetch (hazard_t, hazards, j); + if (! strcmp (hazard.s1, hazard1.s1) && + ! strcmp (hazard.s2, hazard1.s2)) { + break; + } + } + if (j >= array_n (hazards)) { +#endif + array_insert_last (hazard_t, hazards, hazard); + if (astg_debug_flag > 0) { + fprintf (sisout, " %s %s\n", hazard.s2, hazard.s1); + } +#if 0 + } +#endif + } + + /* loop until we do not have hazards at this PO */ + do { + /* max_diff contains the amount to slow down pi1_sav, that is the + * pi1 which has the currently highest d2 - (d3 + d1) + */ + max_diff = -INFINITY; + pi1_sav = NIL(node_t); + pi2_sav = NIL(node_t); + failed = 0; + + for (i = 0; i < array_n (hazards); i++) { + /* now check each potential hazard in turn */ + hazard = array_fetch (hazard_t, hazards, i); + + /* we must subtract the slowing time of pi1 because we + * should be measuring d1 AFTER the added delay + */ + pi1 = network_find_node (network, hazard.s1); + if (! st_lookup (slowed_amounts, bwd_po_name (node_long_name (pi1)), + (char **) &slowed)) { + slowed = & zero; + } + delay1 = delay_simulate (network, pi1, po, /* is_max */ 0, + min_delay_factor); + d1 = MIN (delay1.rise, delay1.fall) - (*slowed); + if (d1 < 0) { + d1 = 0; + } + if (astg_debug_flag > 1) { + fprintf (sisout, "d1: %s->%s : %2.2f\n", + node_long_name (pi1), node_long_name (po), d1); + } + + /* we must subtract the slowing time of pi2 because we + * should be measuring d2 AFTER the added delay + */ + pi2 = network_find_node (network, hazard.s2); + if (! st_lookup (slowed_amounts, bwd_po_name (node_long_name (pi2)), + (char **) &slowed)) { + slowed = & zero; + } + delay2 = delay_simulate (network, pi2, po, /* is_max */ 1, + min_delay_factor); + d2 = MAX (delay2.rise, delay2.fall) - (*slowed); + if (d2 < 0) { + d2 = 0; + } + if (astg_debug_flag > 1) { + fprintf (sisout, "d2: %s->%s : %2.2f\n", + node_long_name (pi2), node_long_name (po), d2); + } + + /* we must add the slowing time of pi1 because we + * should be measuring d3 AFTER the added delay + */ + if (! st_lookup (slowed_amounts, bwd_po_name (node_long_name (pi1)), + (char **) &slowed)) { + slowed = & zero; + } + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi2)), &from)); + assert (st_lookup_int (pio, bwd_po_name (node_long_name (pi1)), &to)); + d3 = d3s[from][to] + (*slowed); + if (d3 < 0) { + d3 = 0; + } + if (astg_debug_flag > 1) { + fprintf (sisout, "d3: %s->%s : %2.2f\n", + node_long_name (pi2), node_long_name (pi1), d3); + } + + if (pi1_sav == NIL(node_t) || (d2 - (d1 + d3)) > max_diff) { + pi1_sav = pi1; + pi2_sav = pi2; + dir1 = hazard.dir1; + dir2 = hazard.dir2; + max_diff = d2 - (d1 + d3); + if (astg_debug_flag > 0) { + fprintf (sisout, "d2 > d1 + d3 by %2.2f\n", max_diff); + } + } + } + + /* now check if we have a hazard to remove */ + if (max_diff + tol > 0) { + failed = 1; + fprintf (sisout, + "Hazard %s%c -> %s%c -> %s by %2.2f (slowing %s)\n", + node_long_name (pi2_sav), dir2, node_long_name (pi1_sav), + dir1, node_long_name (po), (max_diff + tol), + node_long_name (pi1_sav)); + curr_slow = 0; + + do { + inv1 = node_literal (pi1_sav, 0); + network_add_node (network, inv1); + inv2 = node_literal (inv1, 0); + network_add_node (network, inv2); + + buf = lib_gate_pin_name (inv, 0, 1); + assert (buf != NIL(char)); + assert (lib_set_gate (inv1, inv, &buf, &pi1_sav, 1)); + assert (lib_set_gate (inv2, inv, &buf, &inv1, 1)); + + foreach_fanout (pi1_sav, gen1, fanout) { + if (fanout != inv1) { + assert (node_patch_fanin (fanout, pi1_sav, inv2)); + } + } + slowed_delay = delay_simulate (network, pi1_sav, inv2, + /* is_max */ 0, min_delay_factor); + if (! st_lookup (slowed_amounts, + bwd_po_name (node_long_name(pi1_sav)), (char **) &slowed)) { + slowed = ALLOC (double, 1); + *slowed = 0; + st_insert (slowed_amounts, + util_strsav (bwd_po_name (node_long_name(pi1_sav))), + (char *) slowed); + } + *slowed += MIN (slowed_delay.rise, slowed_delay.fall); + curr_slow += MIN (slowed_delay.rise, slowed_delay.fall); + } while (! iterate && curr_slow < max_diff + tol); + } + } while (failed); + + array_free (hazards); + } + } + + /* now save the new delay information (if required) and wrap up */ + bwd_external_delay_update (network, external_del, min_delay_factor, + /*silent*/ 0); + + for (i = 0; i < nd3s; i++) { + FREE (d3s[i]); + } + FREE (d3s); + st_foreach_item (pio, pigen, &buf, NIL(char *)) { + FREE (buf); + } + st_free_table (pio); + + foreach_primary_input (network, gen, pi) { + delay_set_parameter (pi, DELAY_ARRIVAL_RISE, (double) 0); + delay_set_parameter (pi, DELAY_ARRIVAL_FALL, (double) 0); + } +} +#endif /* SIS */ diff --git a/sis/astg/bwd_stg_to_f.c b/sis/astg/bwd_stg_to_f.c new file mode 100644 index 0000000..a178c3d --- /dev/null +++ b/sis/astg/bwd_stg_to_f.c @@ -0,0 +1,880 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/bwd_stg_to_f.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +#ifdef SIS +/* Routines to transform a Signal Transition Graph ("astg", for asynchronous + * STG) into a network implementing it. + */ + +#include "sis.h" +#include "astg_int.h" +#include "astg_core.h" +#include "bwd_int.h" + +/* print the set of enabled transitions in the present state */ +static void +print_enabled(stg, state, enabled) +astg_graph *stg; +astg_scode state; +astg_scode enabled; +{ + astg_signal *s; + astg_generator agen; + + (void)fprintf(sisout, "\tenabled transitions : ["); + astg_foreach_signal(stg, agen, s) { + if (s->state_bit & enabled) { + (void)fprintf(sisout,"%s%s ", s->name, (s->state_bit & state)?"-":"+"); + } + } + (void)fprintf(sisout, "]\n"); +} + +/* return the transition enabled in marking_p itself AND the markings reached + * by firing dummy transitions + */ +static astg_scode +astg_marking_enabled_dummy (astg, marking) +astg_graph *astg; +astg_marking *marking; +{ + astg_generator tgen; + astg_trans *trans; + astg_marking *dup; + astg_scode result; + astg_signal *sig_p; + + result = 0; + astg_foreach_trans (astg, tgen, trans) { + if (astg_disabled_count (trans, marking)) { + continue; + } + sig_p = astg_trans_sig (trans); + result |= astg_state_bit (sig_p); + if (! trans->active && astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + dup = astg_dup_marking (marking); + (void) astg_fire (dup, trans); + trans->active = 1; + result |= astg_marking_enabled_dummy (astg, dup); + trans->active = 0; + astg_delete_marking (dup); + } + } + return result; +} + +/* Find maximal subsets of transitions enabled in the current state ("state") + * that do not enable a transition on the signal we are synthesizing logic for + * ("sig_bit"): for each such subset generate a cube of the on-set or the + * off-set covers of the next state function ("F" and "R"), according to + * whether the next-state value is 1 or 0 (position "sig_bit" in "value"). + * + * The algorithm is as follows: + * for each marking enabled in the current state + * for each place marked + * if the place is free-choice and we did not recur on it yet then + * for each output transition of the place + * enable that transition and recur + * else (now all free choices are solved) + * if the current signal is enabled firing enabled transitions then + * for each enabled signal + * fire it and recur + * unfire it and recur + * else (now the current signal is not enabled) + * generate a cube and add it to the on-set or off-set cover + * + * Meaning of (too many) parameters: + * cur_fc: index among the free-choice places enabled in all markings enabled + * in the current state ("state") of the place we are currently recurring on: + * we choose one marked free-choice place in sequence, and we recur as long + * as there is choice. + * cur_sig: integer index of the signal we are recurring on, splitting on the + * astg: our signal transition graph. + * sig_bit: bit mask of the signal we are synthesizing (NOT "cur_sig"). + * state: current STG state (may not be unique... so we must transform it into + * a list of enabled markings). + * value: same as state, except that "sig_bit" may be complemented, if it is + * enabled: then "value" must be used to decide if we generate on-set or + * off-set cubes. + * enabled: signals enabled in the current marking for "state". + * F, R: current on-set and off-set covers for "cur_sig". + * dup: cubes in the intersection of "F" and "R": used for error messages. + * dup_arr: array, indexed by dup cube number, containing states where the + * intersection of "F" and "R" is not empty: used for error messages. + * Even entries are on-set entries, odd entries are off-set entries. + * dup_marking: current marking where we began looking for maximal subsets: + * used for error messages. + * cb: the cube (statically allocated for speed...). + */ +static void +find_maximal_subset (cur_fc, cur_sig, astg, sig_bit, state, value, enabled, F, R, dup, dup_arr, dup_marking, cb) +int cur_fc, cur_sig; +astg_graph *astg; +astg_scode sig_bit, state, value, enabled; +set_family_t *F, *R, *dup; +array_t *dup_arr; +astg_marking *dup_marking; +pset cb; +{ + astg_scode new_state, new_enabled, bit, fc_enabled, mask_fc, tmp_enabled; + astg_signal * sig_p; + astg_generator mgen, sgen, pgen, tgen; + astg_place *place; + astg_marking *marking; + astg_trans *trans; + int j, i, found, fc; + pset p; + st_table *dup_st; + + /* get the new state, if we fire all enabled transitions */ + new_state = state ^ enabled; + + /* check if a free-choice place, with index greater than "cur_fc" is + * marked in some marking corresponding to "state" + */ + fc = 0; + if (astg_find_state (astg, state, /* create */ 0) == NIL(astg_state)) { + fprintf (siserr, "Fatal error in state %x\n", state); + fail ("cannot retrieve the current state??\n"); + } + astg_foreach_marking (astg_find_state (astg, state, 0), mgen, marking) { + astg_foreach_place (astg, pgen, place) { + if (! astg_get_marked (marking, place)) { + continue; + } + + /* many output transitions == free-choice... */ + if (astg_out_degree (place) > 1) { + fc++; + } + if (fc > cur_fc) { + break; + } + } + if (fc > cur_fc) { + break; + } + } + /* now if fc > cur_fc, an unvisited free-choice place is marked, and + * "place" points to it + */ + if (astg_debug_flag > 2) { + if (fc > cur_fc) { + fprintf (sisout, "free-choice place marked in state %x\n", state); + } + } + + if (fc > cur_fc) { + /* free-choice place is marked: recur on it, and increment "cur_fc" */ + + /* mask_fc is all 1 except for fanout of place */ + mask_fc = (astg_scode) ~0; + astg_foreach_output_trans(place, tgen, trans) { + sig_p = astg_trans_sig(trans); + bit = astg_state_bit (sig_p); + mask_fc &= ~ (bit); + } + + /* fc_enabled is all 0 except for enabled fanout of place */ + fc_enabled = (astg_scode) 0; + astg_foreach_output_trans(place, tgen, trans) { + sig_p = astg_trans_sig(trans); + bit = astg_state_bit (sig_p); + fc_enabled |= bit; + } + + /* save fc enabled bits, and remove them from enabled */ + fc_enabled &= enabled; + tmp_enabled = enabled & mask_fc; + + if (fc_enabled == (astg_scode) 0) { + /* check if we are really free-choice */ + /* WHY ??? + * if (astg_is_free_choice_net (astg)) { + */ + /* no fanout transition of place is enabled in the current marking */ + find_maximal_subset (cur_fc + 1, cur_sig, astg, sig_bit, + state, value, enabled, F, R, dup, dup_arr, dup_marking, cb); + /* + * } + */ + } + else { + /* recur by enabling in turn each fanout transition of "place" */ + astg_foreach_output_trans(place, tgen, trans) { + sig_p = astg_trans_sig(trans); + bit = astg_state_bit (sig_p); + if (fc_enabled & bit) { + new_enabled = tmp_enabled | bit; + find_maximal_subset (cur_fc + 1, cur_sig, astg, sig_bit, + state, value, new_enabled, F, R, dup, dup_arr, + dup_marking, cb); + } + } + } + } + else { + /* we have resolved all choices */ + + /* sanity check: we want the next state to be reachable */ + if (astg_find_state (astg, new_state, /* create */ 0) == NIL(astg_state)) { + fprintf (siserr, "Fatal error in state %x\n", state); + fail ("no next state from current marking ??\n"); + } + + /* loop over all markings enabled in the current state (it should + * become the other way around: the marking is a parameter of the + * procedure, and we get the state from it, but this does not hurt...) + */ + astg_foreach_marking (astg_find_state (astg, new_state, 0), mgen, + marking) { + /* now check if a transition on "sig_bit" is enabled in this marking */ + new_enabled = astg_marking_enabled_dummy (astg, marking); + if (! new_enabled) { + fprintf (siserr, "the STG is not live: no transition enabled in\n"); + astg_print_marking (0, astg, marking); + continue; + } + if (sig_bit & new_enabled) { + /* look for the first enabled signal at or after cur_sig, and split */ + i = 0; + found = 0; + astg_foreach_signal (astg, sgen, sig_p) { + bit = astg_state_bit (sig_p); + if (i >= cur_sig && (enabled & bit)) { + found = 1; + break; + } + i++; + } + if (! found) { + /* bottom of recursion: no subset of enabled can be found */ + continue; + } + + /* first leave the current signal enabled, and try + * disabling some signal AFTER it, recurring + */ + find_maximal_subset (cur_fc, i + 1, astg, sig_bit, state, + value, enabled, F, R, dup, dup_arr, dup_marking, cb); + + /* now disable the current signal and recur again */ + new_enabled = enabled & ~ (bit); + if (new_enabled) { + find_maximal_subset (cur_fc, i + 1, astg, sig_bit, + state, value, new_enabled, F, R, dup, dup_arr, + dup_marking, cb); + } + } + else { + /* no transition for "sig_bit" enabled: generate a cube */ + i = 0; + /* values as in "value" except for enabled signals, which + * are don't care + */ + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + bit = astg_state_bit (sig_p); + if (bit & enabled) { + PUTINPUT (cb, i, TWO); + } + else if (bit & value) { + PUTINPUT (cb, i, ONE); + } + else { + PUTINPUT (cb, i, ZERO); + } + i++; + } + /* choose whether on-set or off-set, according to "value" */ + if (sig_bit & value) { + sf_addset (F, cb); + if (astg_debug_flag > 3) { + fprintf(sisout, "if we fire "); + print_enabled (astg, state, enabled); + fprintf(sisout, "the reached marking would have "); + print_enabled (astg, new_state, new_enabled); + fprintf(sisout, "so we add %s to F\n", pc1(cb)); + } + } + else { + sf_addset (R, cb); + if (astg_debug_flag > 3) { + fprintf(sisout, "if we fire "); + print_enabled (astg, state, enabled); + fprintf(sisout, "the reached marking would have "); + print_enabled (astg, new_state, new_enabled); + fprintf(sisout, "so we add %s to R\n", pc1(cb)); + } + } + + /* save non-empty intersection information, to give error + * messages later, if required + */ + if (dup != NIL(set_family_t)) { + foreachi_set (dup, j, p) { + if (cdist0 (p, cb)) { + if (sig_bit & value) { + dup_st = array_fetch (st_table *, dup_arr, 2 * j); + } + else { + dup_st = array_fetch (st_table *, dup_arr, 2 * j + 1); + } + if (dup_st == NIL(st_table)) { + dup_st = st_init_table (st_numcmp, st_numhash); + if (sig_bit & value) { + array_insert (st_table *, dup_arr, 2 * j, dup_st); + } + else { + array_insert (st_table *, dup_arr, 2 * j + 1, dup_st); + } + } + st_insert (dup_st, (char*) enabled, (char*) dup_marking); + break; + } + } + } + } + } + } +} + +/* Recursive step, computing the new state and exploring it if not yet + * reached. See find_maximal_subset for the meaning of the parameters, + * except for "reached", the symbol table of reached states. + * For each state, we call find_maximal_subset on it, and then we fire each + * enabled transition in turn, calling astg_to_f_recur recursively. + * Since the STG may not be strictly USC, we need to loop for all markings + * corresponding to "state", and we do the same in find_maximal_subset: it + * would be MUCH better to recur on markings, rather than on states. + */ + +static void +astg_to_f_recur (astg, sig_bit, state, reached, F, R, dup, dup_arr, cb) +astg_graph *astg; +astg_scode sig_bit, state; +st_table * reached; +set_family_t *F, *R, *dup; +array_t *dup_arr; +pset cb; +{ + astg_scode enabled, to_fire; + astg_signal *sig_p; + astg_generator sgen, mgen; + astg_marking *marking; + astg_scode new_state, value, bit; + int i, found; + static int mcount; + + /* may not be USC: check all markings */ + if (astg_find_state (astg, state, /* create */ 0) == NIL(astg_state)) { + fprintf (siserr, "Fatal error in state %x\n", state); + fail ("cannot retrieve the current state??\n"); + } + astg_foreach_marking (astg_find_state (astg, state, 0), mgen, marking) { + enabled = astg_marking_enabled (marking); + if (! enabled) { + /* dummy transitions... */ + continue; + } + value = state; + if (enabled & sig_bit) { + value ^= sig_bit; + } + + if (astg_debug_flag > 3) { + fprintf(sisout, "reached state "); + astg_print_state (astg, state); + fprintf(sisout, "with value "); + astg_print_state (astg, value); + astg_print_marking (mcount++, astg, marking); + } + + i = 0; + found = 0; + astg_foreach_signal (astg, sgen, sig_p) { + bit = astg_state_bit (sig_p); + if (enabled & bit) { + found = 1; + break; + } + i++; + } + if (! found) { + if (astg_debug_flag > 1) { + fprintf (sisout, "no enabled transitions in current marking\n"); + astg_print_state (astg, state); + } + continue; + } + + /* first produce cubes, if any */ + find_maximal_subset (0, i, astg, sig_bit, state, value, enabled, + F, R, dup, dup_arr, marking, cb); + + /* then fire each transition in turn */ + astg_foreach_signal (astg, sgen, sig_p) { + to_fire = astg_state_bit (sig_p); + if (to_fire & enabled) { + if (astg_debug_flag > 3) { + fprintf(sisout, "firing "); + print_enabled (astg, state, to_fire); + fprintf(sisout, "\n"); + } + + new_state = state ^ to_fire; + + if (st_lookup (reached, (char *) new_state, NIL(char *))) { + if (astg_debug_flag > 3) { + fprintf(sisout, "reaching again "); + astg_print_state (astg, new_state); + fprintf(sisout, "\n"); + } + continue; + } + + st_insert (reached, (char *) new_state, NIL(char)); + + astg_to_f_recur (astg, sig_bit, new_state, + reached, F, R, dup, dup_arr, cb); + } + } + } +} + +/* Add to M a minimum number of cubes to cover S + M. + * Hacked from espresso irred.c + */ +static set_family_t * +add_cubes(S, M, R) +set_family_t *S, *M, *R; +{ + set_family_t *SM, *D; + pset p, p1, last; + sm_matrix *table; + sm_row *cover; + sm_element *pe; + int index, added_cubes; + + /* extract a minimum cover */ + index = 0; + foreach_set(S, last, p) { + PUTSIZE(p, index); + index++; + } + foreach_set(M, last, p) { + PUTSIZE(p, index); + index++; + } + SM = sf_append (sf_save (S), sf_save (M)); + D = complement (cube2list (SM, R)); + table = irred_derive_table(D, M, SM); + cover = sm_minimum_cover(table, NIL(int), /* heuristic */ 0, /* debug */ 0); + + /* mark the cubes for the result */ + foreach_set(SM, last, p) { + RESET(p, ACTIVE); + } + foreach_set(M, last, p) { + p1 = GETSET(SM, SIZE(p)); + assert(setp_equal(p1, p)); + SET(p1, ACTIVE); + } + sm_foreach_row_element(cover, pe) { + p1 = GETSET(SM, pe->col_num); + SET(p1, ACTIVE); + } + + added_cubes = (-M->count); + sf_free(D); + sf_free(M); + sm_free(table); + sm_row_free(cover); + + M = sf_inactive (SM); + added_cubes += M->count; + if (added_cubes > 0) { + fprintf (sisout, + "warning: added %d cubes to make S and R disjoint\n", + added_cubes); + } + return M; +} + +/* Create and return the node function for the specified signal (position + * "index" in the "fanin" array). + * We set up variables for astg_to_f_recur and call it. Then we check if the + * intersection of F and R is empty. If not, we call astg_to_f_recur again + * in order to get detailed error information. In this way we are (maybe ??) + * faster if the STG can be synthesized... + * We set up a minimum covering problem between the set of unexpanded and + * the set of expanded on-set and off-set cubes. + * Then if omit_fake is 0, we decompose each next-state function into an S + * and an M cover, and implement a node of the form + * x = M x + S (x = (M + S) x + S if "disjoint" + * is 1, to make the Set and Reset inputs of the FF disjoint) by adding primary + * outputs for S and M, so that subsequent optimizations will preserve them. + */ + +void +bwd_astg_to_f (network, astg, sig_p, fanin, state, hazard_list, index, use_old, sep_s_r, disjoint, force) +network_t * network; +astg_graph *astg; +astg_signal *sig_p; +array_t *fanin; +astg_scode state; +st_table *hazard_list; +int index, use_old, sep_s_r, disjoint, force; +{ + astg_scode sig_bit, dup_enabled; + astg_signal *tsig; + set_family_t *F, *R, *dup, *old_F, *old_R, *new_R; + st_table *dup_on, *dup_off; + st_table * reached; + st_generator *rgen; + astg_place *place; + astg_trans *trans; + astg_generator pgen, tgen, sgen; + astg_marking *dup_marking; + pset c, last, p, old_p; + node_t *node, *po; + int i, old_i, j; + sm_matrix *matrix; + sm_row *cover; + sm_element *el; + int mincov_debug; + char *name; + array_t *dup_arr; + set_family_t *S, *M, *tmp; + char *buf; + int len; + node_t *M_node, *S_node, *R_node, **new_fanin; + pset mask; + char *dummy; + + name = util_strsav (bwd_fake_po_name (sig_p->name)); + mincov_debug = 0; + F = sf_new (0, 2 * array_n (fanin)); + R = sf_new (0, 2 * array_n (fanin)); + c = set_new (2 * array_n (fanin)); + reached = st_init_table (st_numcmp, st_numhash); + st_insert (reached, (char *) state, NIL(char)); + sig_bit = astg_state_bit (sig_p); + define_cube_size (array_n (fanin)); + astg_foreach_trans (astg, tgen, trans) { + trans->active = 0; + } + + /* first pass, hopefully without problems */ + astg_to_f_recur (astg, sig_bit, state, reached, F, R, NIL(set_family_t), + NIL(array_t), c); + + F = sf_contain (F); + R = sf_contain (R); + + if (astg_debug_flag > 1) { + mincov_debug = 1; + + fprintf (sisout, "on-set cover\n"); + foreach_set (F, last, p) { + fprintf(sisout, "%s\n", pc1(p)); + } + fprintf (sisout, "off-set cover\n"); + foreach_set (R, last, p) { + fprintf(sisout, "%s\n", pc1(p)); + } + } + + dup = cv_intersect(F, R); + if (dup->count) { + /* oops... we have a problem... find it out, signal and wrap up */ + fprintf (siserr, "State assignment problem for %s:\n", + name); + F->count = R->count = 0; + st_free_table (reached); + reached = st_init_table (st_numcmp, st_numhash); + dup_arr = array_alloc (st_table *, 2 * dup->count); + for (i = 0; i < 2 * dup->count; i++) { + array_insert (st_table *, dup_arr, i, NIL(st_table)); + } + st_insert (reached, (char *) state, NIL(char)); + astg_to_f_recur (astg, sig_bit, state, reached, F, R, dup, dup_arr, c); + + foreachi_set (dup, i, p) { + dup_on = array_fetch (st_table *, dup_arr, 2 * i); + dup_off = array_fetch (st_table *, dup_arr, 2 * i + 1); + if (dup_on != NIL(st_table) && dup_off != NIL(st_table)) { + fprintf(siserr, "signal values"); + j = 0; + astg_foreach_signal (astg, sgen, tsig) { + switch (GETINPUT (p, j)) { + case ONE: + fprintf (siserr, " %s=1", tsig->name); + break; + case ZERO: + fprintf (siserr, " %s=0", tsig->name); + break; + case TWO: + fprintf (siserr, " %s=+/-", tsig->name); + break; + default: + break; + } + j++; + } + fprintf(siserr, "\n"); + fprintf(siserr, " on-set markings\n", pc1(p)); + st_foreach_item (dup_on, rgen, &dummy, + (char **) &dup_marking) { + dup_enabled = (astg_scode) dummy; + fprintf (siserr, " "); + astg_foreach_place (astg, pgen, place) { + if (astg_get_marked (dup_marking, place)) { +#ifdef UNSAFE + fprintf(siserr, " %s (%d)", astg_place_name(place), + astg_get_nmarked(dup_marking,place)); +#else /* UNSAFE */ + fprintf(siserr, " %s", astg_place_name(place)); +#endif /* UNSAFE */ + } + } + fprintf (siserr, "\n"); + } + fprintf(siserr, " off-set markings\n", pc1(p)); + st_foreach_item (dup_off, rgen, &dummy, + (char **) &dup_marking) { + dup_enabled = (astg_scode) dummy; + fprintf (siserr, " "); + astg_foreach_place (astg, pgen, place) { + if (astg_get_marked (dup_marking, place)) { +#ifdef UNSAFE + fprintf(siserr, " %s (%d)", astg_place_name(place), + astg_get_nmarked(dup_marking,place)); +#else /* UNSAFE */ + fprintf(siserr, " %s", astg_place_name(place)); +#endif /* UNSAFE */ + } + } + fprintf (siserr, "\n"); + } + } + if (dup_on != NIL(st_table)) { + st_free_table (dup_on); + } + if (dup_off != NIL(st_table)) { + st_free_table (dup_off); + } + } + array_free (dup_arr); + if (force) { + new_R = cv_dsharp (R, F); + sf_free (R); + R = new_R; + } + else { + st_free_table (reached); + sf_free (dup); + sf_free (F); + sf_free (R); + set_free (c); + + /* create a dummy node, otherwise we will die later... */ + node = node_constant (0); + network_add_node (network, node); + network_change_node_name (network, node, name); + (void) network_add_primary_output(network, node); + return; + } + } + + sf_free (dup); + + /* no USC problems: generate the covers by expanding and covering */ + old_F = sf_save (F); + old_R = sf_save (R); + F = expand (F, R, /* nonsparse */ 0); + R = expand (R, F, /* nonsparse */ 0); + + /* each cube in old_F must be covered by at least one cube in F */ + matrix = sm_alloc (); + foreachi_set (old_F, old_i, old_p) { + foreachi_set (F, i, p) { + if (setp_implies (old_p, p)) { + sm_insert (matrix, old_i, i); + } + } + } + cover = sm_minimum_cover (matrix, NIL(int), /*heuristic*/ 0, mincov_debug); + + /* now copy back in F only cubes in the minimum cover */ + sf_free (old_F); + old_F = F; + F = sf_new (cover->length, 2 * array_n (fanin)); + sm_foreach_row_element (cover, el) { + p = GETSET (old_F, el->col_num); + sf_addset (F, p); + } + + sf_free (old_F); + sm_row_free (cover); + sm_free (matrix); + + /* each cube in old_R must be covered by at least one cube in R */ + matrix = sm_alloc (); + foreachi_set (old_R, old_i, old_p) { + foreachi_set (R, i, p) { + if (setp_implies (old_p, p)) { + sm_insert (matrix, old_i, i); + } + } + } + cover = sm_minimum_cover (matrix, NIL(int), /*heuristic*/ 0, mincov_debug); + + /* now copy back in R only cubes in the minimum cover */ + sf_free (old_R); + old_R = R; + R = sf_new (cover->length, 2 * array_n (fanin)); + sm_foreach_row_element (cover, el) { + p = GETSET (old_R, el->col_num); + sf_addset (R, p); + } + + sf_free (old_R); + sm_row_free (cover); + sm_free (matrix); + + if (astg_debug_flag > 1) { + fprintf (sisout, "final on-set cover\n"); + foreach_set (F, last, p) { + fprintf(sisout, "%s\n", pc1(p)); + } + fprintf (sisout, "final off-set cover\n"); + foreach_set (R, last, p) { + fprintf(sisout, "%s\n", pc1(p)); + } + } + + if (sep_s_r) { + /* now partition F into S (cubes not depending on input "index") and M + * (cubes depending on input "index") + */ + mask = set_clear (set_new (2 * array_n (fanin)), 2 * array_n (fanin)); + PUTINPUT (mask, index, TWO); + S = sf_new (0, 2 * array_n (fanin)); + M = sf_new (0, 2 * array_n (fanin)); + foreach_set (F, last, p) { + switch (GETINPUT (p, index)) { + case ONE: + set_or (c, p, mask); + sf_addset (M, c); + break; + case TWO: + sf_addset (S, p); + break; + default: + fail ("illegal cube value in bwd_astg_to_f\n"); + break; + } + } + set_free (c); + + if (disjoint) { + /* add to M all cubes of S which are not covered by it: this will make + * S and M' disjoint + */ + define_cube_size (array_n (fanin)); + M = add_cubes (S, M, R); + } + + if (M->count) { + /* create a new PO holding the function for S */ + S_node = node_create (S, array_data (node_t *, fanin), array_n (fanin)); + node_minimum_base (S_node); + network_add_node (network, S_node); + buf = util_strsav (name); + len = strlen(buf); + buf[len - 3] = 'S'; + buf[len - 2] = '_'; + buf[len - 1] = '\0'; + network_change_node_name (network, S_node, buf); + (void) network_add_primary_output(network, S_node); + + /* create a new PO holding the function for M */ + M_node = node_create (M, array_data (node_t *, fanin), array_n (fanin)); + node_minimum_base (M_node); + network_add_node (network, M_node); + buf = util_strsav (name); + len = strlen(buf); + buf[len - 3] = 'M'; + buf[len - 2] = '_'; + buf[len - 1] = '\0'; + network_change_node_name (network, M_node, buf); + (void) network_add_primary_output(network, M_node); + + /* now complement M to obtain M' */ + R_node = node_literal (M_node, 0); + network_add_node (network, R_node); + buf = util_strsav (name); + len = strlen(buf); + buf[len - 3] = 'R'; + buf[len - 2] = '_'; + buf[len - 1] = '\0'; + network_change_node_name (network, R_node, buf); + (void) network_add_primary_output(network, R_node); + + /* finally build the new flip flop node with function X * (! M') + S */ + tmp = sf_new (2, 6); + c = set_new (6); + new_fanin = ALLOC (node_t *, 3); + new_fanin[0] = array_fetch (node_t *, fanin, index); + new_fanin[1] = R_node; + new_fanin[2] = S_node; + /* X * (! M') */ + PUTINPUT (c, 0, ONE); + PUTINPUT (c, 1, ZERO); + PUTINPUT (c, 2, TWO); + sf_addset (tmp, c); + /* S */ + PUTINPUT (c, 0, TWO); + PUTINPUT (c, 1, TWO); + PUTINPUT (c, 2, ONE); + sf_addset (tmp, c); + node = node_create (tmp, new_fanin, 3); + } + else { + sf_free (S); + sf_free (M); + node = node_create (sf_save (F), array_data (node_t *, fanin), + array_n(fanin)); + } + } + else { + node = node_create (sf_save (F), array_data (node_t *, fanin), + array_n(fanin)); + } + node_minimum_base (node); + network_add_node (network, node); + network_change_node_name (network, node, name); + (void) network_add_primary_output(network, node); + + if (hazard_list != NIL(st_table)) { + /* now find potential hazards in the next-state function */ + define_cube_size (array_n (fanin)); + + bwd_find_hazards (astg, sig_p, fanin, F, R, hazard_list, name, use_old); + } + + /* wrap up and return */ + sf_free (F); + sf_free (R); + st_free_table (reached); +} +#endif /* SIS */ diff --git a/sis/astg/bwd_util.c b/sis/astg/bwd_util.c new file mode 100644 index 0000000..aff57be --- /dev/null +++ b/sis/astg/bwd_util.c @@ -0,0 +1,2188 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/bwd_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +#ifdef SIS +/* Routines to transform a Signal Transition Graph ("astg", for asynchronous + * STG) into a State Transition Graph ("stg"), and various auxiliary things. + */ + +#include "sis.h" +#include "astg_int.h" +#include "astg_core.h" +#include "bwd_int.h" + +#define TNAME(t) ((t)==NIL(astg_trans)?"":astg_trans_name(t)) +#define TRANS_TYPE(c) (((c) == '0') ? ASTG_POS_X : ASTG_NEG_X) + +struct _scr_state { + char *name, *in, *out; + vertex_t *state; +}; + +typedef struct _scr_state scr_state_t; + +/* needed here because we must delete states in stg_patch */ +static st_table *state_cache; +static graph_t *state_cached_stg; + +astg_scode +bwd_astg_state_bit (sig_p) +astg_signal *sig_p; +{ + return astg_state_bit (sig_p); +} + +/* un-minimized STG */ +graph_t *global_orig_stg; +st_table *global_orig_stg_names; + +/* associates a state with a marking and vice-versa */ +st_table *global_state_marking; +st_table *global_marking_state; +st_table *global_edge_trans; + +/* same as stg_create_transition, but does not check for duplicate edges + */ +edge_t * +stg_create_nfa_transition(from, to, in, out) +vertex_t *from, *to; +char *in, *out; +{ + edge_t *edge; + graph_t *stg; + + stg = g_vertex_graph(from); + if (stg != g_vertex_graph(to)) { + fail("Vertices to and from belong to different stgs"); + } + if (strlen(in) != (int) g_get_g_slot_static(stg, NUM_INPUTS)) { + fail("In stg_create_nfa_transition: Invalid number of inputs specified"); + } + if (strlen(out) != (int) g_get_g_slot_static(stg, NUM_OUTPUTS)) { + fail("In stg_create_nfa_transition: Invalid number of outputs specified"); + } + edge = g_add_edge_static(from, to); + g_set_e_slot_static(edge, INPUT_STRING, (gGeneric) util_strsav(in)); + g_set_e_slot_static(edge, OUTPUT_STRING, (gGeneric) util_strsav(out)); + g_set_g_slot_static(stg,NUM_PRODUCTS, + (gGeneric) ((int) g_get_g_slot_static(stg, NUM_PRODUCTS) + 1)); + return(edge); +} +int +bwd_log2(arg) +astg_scode arg; +{ + astg_scode i; + int value; + + for (i=1, value=0; i < arg ; i = i << 1 , value++) ; + return value; +} + +/* auxiliary debugging function */ +void +bwd_pedge (edge) +edge_t *edge; +{ + fprintf (sisout, "%s %s %s %s\n", stg_edge_input_string (edge), + stg_get_state_name (stg_edge_from_state (edge)), + stg_get_state_name (stg_edge_to_state (edge)), + stg_edge_output_string (edge)); +} + +/* auxiliary debugging function */ +void +bwd_pstate (state) +vertex_t *state; +{ + lsGen gen; + edge_t *edge; + + foreach_state_inedge (state, gen, edge) { + bwd_pedge (edge); + } + foreach_state_outedge (state, gen, edge) { + bwd_pedge (edge); + } +} + +vertex_t * +bwd_get_state_by_name (stg, name) +graph_t *stg; +char *name; +{ + vertex_t *state; + lsGen gen; + + if (state_cached_stg != stg) { + if (state_cache != NIL(st_table)) { + st_free_table (state_cache); + state_cache = NIL(st_table); + } + } + if (state_cache == NIL(st_table)) { + state_cache = st_init_table (strcmp, st_strhash); + state_cached_stg = stg; + + stg_foreach_state (stg, gen, state) { + st_insert (state_cache, stg_get_state_name (state), (char *) state); + } + } + + if (! st_lookup (state_cache, name, (char **) &state)) { + /* better slow than dead... */ + state = stg_get_state_by_name (stg, name); + if (state != NIL(vertex_t)) { + st_insert (state_cache, stg_get_state_name (state), (char *) state); + } + } + + return state; +} + +static void +print_sg (astg, stg, edge_trans) +astg_graph *astg; +graph_t *stg; +st_table *edge_trans; +{ + vertex_t *state, *to; + edge_t *edge; + astg_trans *trans; + array_t *trans_arr; + int i; + lsGen gen, gen1; + + stg_foreach_state (stg, gen, state) { + foreach_state_outedge (state, gen1, edge) { + to = stg_edge_to_state (edge); + if (to == state) { + continue; + } + assert (st_lookup (edge_trans, (char *) edge, (char **) &trans_arr)); + fprintf (sisout, "%s", stg_get_state_name (state)); + for (i = 0; i < array_n (trans_arr); i++) { + trans = array_fetch (astg_trans *, trans_arr, i); + fprintf (sisout, " %s", astg_trans_name (trans)); + } + fprintf (sisout, " %s\n", stg_get_state_name (to)); + } + } +} + +/* return the set of signals enabled in "to_state" not enabled in "from_state" + */ +astg_scode +bwd_new_enabled_signals (edge, edge_trans, state_marking) +edge_t *edge; +st_table *edge_trans, *state_marking; +{ + astg_scode from_enabled, new_enabled, firing; + astg_marking *marking; + static st_table *new_enabled_cache; + static graph_t *new_enabled_cached_stg; + astg_trans *trans; + int i; + array_t *marking_arr, *trans_arr; + + if (new_enabled_cached_stg != g_edge_graph (edge)) { + if (new_enabled_cache != NIL(st_table)) { + st_free_table (new_enabled_cache); + new_enabled_cache = NIL(st_table); + } + } + if (new_enabled_cache == NIL(st_table)) { + new_enabled_cache = st_init_table_with_params (st_ptrcmp, st_ptrhash, + ST_DEFAULT_INIT_TABLE_SIZE, /* density */ 1, ST_DEFAULT_GROW_FACTOR, + ST_DEFAULT_REORDER_FLAG); + new_enabled_cached_stg = g_edge_graph (edge); + } + + if (st_lookup (new_enabled_cache, (char *) edge, (char **) &new_enabled)) { + return new_enabled; + } + + assert (st_lookup (state_marking, (char *) stg_edge_from_state (edge), (char **) &marking_arr)); + from_enabled = 0; + for (i = 0; i < array_n (marking_arr); i++) { + marking = array_fetch (astg_marking *, marking_arr, i); + from_enabled |= astg_marking_enabled (marking); + } + assert (st_lookup (state_marking, (char *) stg_edge_to_state (edge), (char **) &marking_arr)); + new_enabled = 0; + for (i = 0; i < array_n (marking_arr); i++) { + marking = array_fetch (astg_marking *, marking_arr, i); + new_enabled |= astg_marking_enabled (marking); + } + assert (st_lookup (edge_trans, (char *) edge, (char **) &trans_arr)); + firing = 0; + for (i = 0; i < array_n (trans_arr); i++) { + trans = array_fetch (astg_trans *, trans_arr, i); + firing |= bwd_astg_state_bit (astg_trans_sig (trans)); + } + + /* check if the firing signal is enabled again, if so do not rm it */ + if (firing & new_enabled) { + from_enabled &= ~firing; + } + new_enabled &= ~from_enabled; + + st_insert (new_enabled_cache, (char *) edge, (char *) new_enabled); + return new_enabled; +} + +/* transform a marking into a (unique) STG state name */ +char * +bwd_marking_string (marked_places) +astg_ba_rec *marked_places; +{ + int i; + static char buf1[9], buf2[513]; + + buf2[0] = '\0'; + assert(marked_places->n_word); + for (i = 0; i < marked_places->n_word && i < (sizeof(buf2)/sizeof(buf1)); + i++) { + sprintf (buf1, "_%x", marked_places->bit_array[i]); + strcat (buf2, buf1); + } + return buf2; +} + +/* check if an edge in,from -> to,out exists already in the STG */ +int +duplicate (stg, from, to, in, out) +graph_t *stg; +vertex_t *from, *to; +char *in, *out; +{ + lsGen gen; + edge_t *edge, *dup_edge; + int result, base, len, i; + char *old_out; + + result = 0; + dup_edge = NIL(edge_t); + foreach_state_outedge (from, gen, edge) { + if (! strcmp (in, stg_edge_input_string(edge))) { + result = 1; + if (to != stg_edge_to_state (edge) || + strcmp (out, stg_edge_output_string (edge))) { + dup_edge = edge; + } + } + } + + if (dup_edge == NIL(edge_t)) { + /* no duplication or same next state and output */ + return result; + } + + /* check if we are just moving along a dummy edge to a new self loop */ + if (to == from && + stg_edge_to_state (dup_edge) == stg_edge_from_state (dup_edge)) { + /* change the output to a "maximal" set of enabled transitions */ + len = strlen (out); + base = strlen (in) - len; + old_out = stg_edge_output_string (dup_edge); + for (i = 0; i < len; i++) { + if (old_out[i] != out[i] && in[base + i] != out[i]) { + old_out[i] = out[i]; + } + } + if (astg_debug_flag > 2) { + fprintf (sisout, "updating %s %s %s %s\n", + in, stg_get_state_name (from), + stg_get_state_name (to), old_out); + } + return 1; + } + return 1; +} + +/* patch the stg replacing the state called "old" with "new" + */ +static void +stg_patch (stg, state_out, edge_trans, marking_state, state_marking, old, new, from_stack, from_sp) +graph_t *stg; +st_table *edge_trans, *state_out, *marking_state, *state_marking; +vertex_t *old, *new; +array_t *from_stack; +int from_sp; +{ + astg_marking *marking; + array_t *marking_arr_old, *marking_arr_new; + char *out, *in, *name; + lsGen gen; + edge_t *edge, *new_edge; + vertex_t *state, **from_p; + int i; + array_t *trans_arr; + + /* patch the "from" of the callers, if appropriate */ + for (i = 0; i < from_sp; i++) { + from_p = array_fetch (vertex_t **, from_stack, i); + if (*from_p == old) { + *from_p = new; + if (astg_debug_flag > 2) { + fprintf (sisout, "stack patch %s -> %s at level %d\n", + stg_get_state_name (*from_p), stg_get_state_name (new), i); + } + } + } + + /* delete from state_marking */ + assert (st_delete (state_marking, (char **) &old, (char **) &marking_arr_old)); + assert (st_lookup (state_marking, (char *) new, (char **) &marking_arr_new)); + for (i = 0; i < array_n (marking_arr_old); i++) { + marking = array_fetch (astg_marking *, marking_arr_old, i); + array_insert_last (astg_marking *, marking_arr_new, marking); + st_insert (marking_state, (char *) marking, (char *) new); + } + array_free (marking_arr_old); + /* delete from state_out */ + assert (st_delete (state_out, (char **) &old, &out)); + + /* now patch the stg (ugh...) */ + foreach_state_inedge (old, gen, edge) { + state = stg_edge_from_state (edge); + in = stg_edge_input_string (edge); + out = stg_edge_output_string (edge); + if (state == old) { + if (duplicate (stg, new, new, in, out)) { + if (astg_debug_flag > 0) { + fprintf (sisout, + "skipping replacement %s (%s -> %s) -> (%s -> %s) %s\n", in, + stg_get_state_name (old), stg_get_state_name (new), + stg_get_state_name (state), stg_get_state_name (new), + out); + } + st_delete (edge_trans, (char **) &edge, (char **) &trans_arr); + continue; + } + if (astg_debug_flag > 2) { + fprintf (sisout, "replacing %s (%s -> %s) -> (%s -> %s) %s\n", + in, stg_get_state_name (state), stg_get_state_name (new), + stg_get_state_name (old), stg_get_state_name (new), out); + } + + new_edge = stg_create_transition (new, new, in, out); + } + else { + /* no duplication checking, because we are CERTAINLY duplicated */ + if (astg_debug_flag > 2) { + fprintf (sisout, "replacing %s %s -> (%s -> %s) %s\n", in, + stg_get_state_name (state), stg_get_state_name (old), + stg_get_state_name (new), out); + } + + new_edge = stg_create_nfa_transition (state, new, in, out); + } + if (st_delete (edge_trans, (char **) &edge, (char **) &trans_arr)) { + st_insert (edge_trans, (char *) new_edge, (char *) trans_arr); + } + } + foreach_state_outedge (old, gen, edge) { + state = stg_edge_to_state (edge); + if (state == old) { + continue; + } + in = stg_edge_input_string (edge); + out = stg_edge_output_string (edge); + if (duplicate (stg, new, state, in, out)) { + if (astg_debug_flag > 0) { + fprintf (sisout, + "skipping replacement %s (%s -> %s) -> %s %s\n", in, + stg_get_state_name (old), stg_get_state_name (new), + stg_get_state_name (state), out); + } + st_delete (edge_trans, (char **) &edge, (char **) &trans_arr); + continue; + } + if (astg_debug_flag > 2) { + fprintf (sisout, "replacing %s (%s -> %s) -> %s %s\n", in, + stg_get_state_name (old), stg_get_state_name (new), + stg_get_state_name (state), out); + } + + new_edge = stg_create_transition (new, state, in, out); + if (st_delete (edge_trans, (char **) &edge, (char **) &trans_arr)) { + st_insert (edge_trans, (char *) new_edge, (char *) trans_arr); + } + } + /* remove from cache (sigh...) */ + if (state_cache != NIL(st_table) && state_cached_stg == stg) { + name = stg_get_state_name (old); + st_delete (state_cache, &name, (char **) &state); + } + /* better not free than corrupt... */ + g_delete_vertex (old, (void(*)()) 0, (void(*)()) 0); +} + +/* Explore the reachability graph of the STG by firing each enabled transition + * in turn. Maybe stg_to_f_recur should inherit this structure in the future. + * The code structure is borrowed from flow_state in astg_flow.c. + * It returns the newly created state transition graph state. + */ +static vertex_t * +astg_to_stg_recur (flow_info, astg, stg, state, curr_marking, in, out, buf, use_output, edge_trans, state_marking, marking_state, state_out, curr_trans, curr_i, from_stack, from_sp) +astg_flow_t *flow_info; +astg_graph *astg; +graph_t *stg; +astg_scode state; +astg_marking *curr_marking; +char *in, *out, *buf; +int use_output; +st_table *edge_trans, *state_marking, *marking_state, *state_out; +array_t *curr_trans; +int curr_i; +array_t *from_stack; +int from_sp; +{ + astg_scode enabled; + astg_signal *sig_p; + astg_generator sgen; + astg_scode new_state, new_out, bit; + int in_cnt, out_cnt, i, dummy_cnt, k, new_curr_i; + vertex_t *from, *to; + edge_t *edge; + array_t *enabled_array; + astg_trans *trans, *trans1; + astg_marking *marking, *new_curr_marking; + char *str; + array_t *marking_arr, *trans_arr, *new_curr_trans; + + /* get the array of enabled transitions in the current state */ + if ((enabled_array = astg_check_new_state (flow_info, state)) + == NIL(array_t)) { + assert (st_lookup (marking_state, (char *) flow_info->marking, (char **) &from)); + } + else { + /* create the state, if not reached yet */ + sprintf (buf, "s%s", bwd_marking_string(curr_marking->marked_places)); + from = bwd_get_state_by_name (stg, buf); + if (from == NIL (vertex_t)) { + from = stg_create_state (stg, buf, NIL (char)); + } + + /* all enabled transitions must fire in the proper output */ + enabled = 0; + for (i = array_n(enabled_array); flow_info->status == 0 && i--;) { + trans = array_fetch (astg_trans *, enabled_array, i); + enabled |= bwd_astg_state_bit(astg_trans_sig(trans)); + } + marking = astg_dup_marking (flow_info->marking); + marking->enabled = enabled; + + if (! st_lookup (state_marking, (char *) from, (char **) &marking_arr)) { + marking_arr = array_alloc (astg_marking *, 0); + st_insert (state_marking, (char *) from, (char *) marking_arr); + } + array_insert_last (astg_marking *, marking_arr, marking); + st_insert (marking_state, (char *) marking, (char *) from); + + /* if nothing changes, we have a self loop on the current state */ + in_cnt = out_cnt = 0; + new_out = state ^ enabled; + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + bit = bwd_astg_state_bit (sig_p); + if (use_output || astg_signal_type (sig_p) == ASTG_INPUT_SIG) { + in[in_cnt++] = (state & bit) ?'1':'0'; + } + if (astg_signal_type (sig_p) == ASTG_OUTPUT_SIG || + astg_signal_type (sig_p) == ASTG_INTERNAL_SIG) { + out[out_cnt++] = (new_out & bit) ?'1':'0'; + } + } + + /* add the new (self-loop) edge */ + edge = stg_create_nfa_transition (from, from, in, out); + st_insert (state_out, (char *) from, stg_edge_output_string (edge)); + + if (astg_debug_flag > 2) { + fprintf (sisout, "%s %s -(self)> %s %s\n", + in, stg_get_state_name (from), + stg_get_state_name (from), out); + } + new_state = state; + + dummy_cnt = 0; + for (i = array_n(enabled_array); flow_info->status == 0 && i--;) { + trans = array_fetch (astg_trans *, enabled_array, i); + if (astg_signal_type (astg_trans_sig (trans)) == ASTG_DUMMY_SIG) { + dummy_cnt++; + } + } + for (i = array_n(enabled_array); flow_info->status == 0 && i--;) { + /* now fire each enabled transition in turn */ + trans = array_fetch (astg_trans *, enabled_array, i); + new_state = astg_fire (flow_info->marking, trans); + + /* check if we fired a dummy transition which is NOT unique (choice) */ + new_curr_trans = curr_trans; + if (dummy_cnt > 1 && + astg_signal_type (astg_trans_sig (trans)) == ASTG_DUMMY_SIG) { + new_curr_marking = curr_marking; + array_insert (astg_trans *, curr_trans, curr_i, trans); + curr_i++; + new_curr_i = curr_i; + } + else { + new_curr_marking = astg_dup_marking (flow_info->marking); + if (curr_i) { + new_curr_trans = array_alloc (astg_trans *, 0); + } + new_curr_i = 0; + } + + array_insert (vertex_t **, from_stack, from_sp, &from); + + /* recur */ + to = astg_to_stg_recur (flow_info, astg, stg, new_state, + new_curr_marking, in, out, buf, use_output, + edge_trans, state_marking, marking_state, state_out, + new_curr_trans, new_curr_i, from_stack, from_sp + 1); + + if (astg_signal_type (astg_trans_sig (trans)) == ASTG_DUMMY_SIG) { + if (from != to) { + stg_patch (stg, state_out, edge_trans, marking_state, + state_marking, from, to, from_stack, from_sp); + from = to; + } + if (dummy_cnt > 1) { + curr_i--; + } + } + else { + astg_delete_marking (new_curr_marking); + if (curr_i) { + array_free (new_curr_trans); + } + } + + /* "In" is the input label of the new edge: it has the same + * signal values as the current state except for the FIRED + * transition. + * "Out" is the output label: it has the same signal values as + * the next state, except for the ENABLED transitions. It is + * produced by the PREVIOUS call. + * ALL signals go into the "in" label, only OUTPUT signals go + * into the "out" label. + */ + + in_cnt = 0; + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + bit = bwd_astg_state_bit (sig_p); + if (use_output || astg_signal_type (sig_p) == ASTG_INPUT_SIG) { + in[in_cnt++] = (new_state & bit) ?'1':'0'; + } + } + /* retrieve the self-loop from "to" */ + assert (st_lookup (state_out, (char *) to, (char **) &str)); + strcpy (out, str); + + /* add the new edge */ + edge = stg_create_nfa_transition (from, to, in, out); + if (! st_lookup (edge_trans, (char *) edge, (char **) &trans_arr)) { + trans_arr = array_alloc (astg_trans *, 0); + st_insert (edge_trans, (char *) edge, (char *) trans_arr); + } + if (astg_debug_flag > 2) { + fprintf (sisout, "%s %s - %s", + in, stg_get_state_name (from), TNAME (trans)); + } + array_insert_last (astg_trans *, trans_arr, trans); + for (k = 0; k < curr_i; k++) { + trans1 = array_fetch (astg_trans *, curr_trans, k); + array_insert_last (astg_trans *, trans_arr, trans1); + if (astg_debug_flag > 2) { + fprintf (sisout, " %s", TNAME (trans1)); + } + } + if (astg_debug_flag > 2) { + fprintf (sisout, " > %s %s\n", stg_get_state_name (to), out); + } + /* backtrack and go to the next transition */ + new_state = astg_unfire (flow_info->marking, trans); + } + array_free (enabled_array); + } + + return from; +} + +static void +stg_set_prod_states (stg) +graph_t *stg; +{ + lsGen gen; + int n; + vertex_t *state; + edge_t *trans; + + n = 0; + stg_foreach_state (stg, gen, state) { + n++; + } + stg_set_num_states (stg, n); + + n = 0; + stg_foreach_transition (stg, gen, trans) { + n++; + } + stg_set_num_products (stg, n); +} + +graph_t * +bwd_reduced_stg (stg, partitions, orig_stg_names, names, nstates) +graph_t *stg; +st_table *partitions, *orig_stg_names; +array_t *names; +int nstates; +{ + graph_t *red_stg; + char buf[80], *name1, *name2, *name, *str; + vertex_t **states, *state1, *state2, *state3, *state; + edge_t *edge; + lsGen gen, gen1, gen2; + int cl1, cl2, cl3, merged, i, j, collapse, len; + char *in, *out; + pset deleted; + array_t *names1, *names2, *components, *component; + + deleted = set_new (nstates); + for (collapse = 0; collapse < 2; collapse++) { + do { + merged = 0; + red_stg = stg_alloc (); + stg_set_num_inputs (red_stg, stg_get_num_inputs (stg)); + stg_set_num_outputs (red_stg, stg_get_num_outputs (stg)); + + states = ALLOC (vertex_t *, nstates); + for (cl1 = 0; cl1 < nstates; cl1++) { + if (is_in_set (deleted, cl1)) { + states[cl1] = NIL(vertex_t); + } + else { + if (names == NIL(array_t)) { + sprintf (buf, "s%d", cl1); + states[cl1] = stg_create_state (red_stg, buf, + NIL (char)); + } + else { + states[cl1] = stg_create_state (red_stg, + array_fetch (char *, names, cl1), NIL (char)); + } + } + } + + stg_foreach_state (stg, gen, state1) { + assert (st_lookup_int (partitions, (char *) state1, &cl1)); + + /* take care of transitions to other partitions first */ + foreach_state_outedge (state1, gen1, edge) { + state2 = stg_edge_to_state (edge); + assert (st_lookup_int (partitions, (char *) state2, &cl2)); + if (cl1 == cl2) { + continue; + } + + in = stg_edge_input_string (edge); + out = stg_edge_output_string (edge); + + if (duplicate (red_stg, states[cl1], states[cl2], in, + out)) { + if (collapse) { + /* merge together cl1 and cl2 */ + if (astg_debug_flag > 1) { + fprintf (sisout, "merging class %d into %d\n", + cl2, cl1); + } + set_insert (deleted, cl2); + + stg_foreach_state (stg, gen2, state3) { + assert (st_lookup_int (partitions, (char *) state3, &cl3)); + if (cl3 == cl2) { + st_insert (partitions, (char *) state3, + (char *) cl1); + } + } + + /* update orig_stg_names */ + if (names != NIL(array_t)) { + name1 = array_fetch (char *, names, cl1); + name2 = array_fetch (char *, names, cl2); + assert (st_lookup (orig_stg_names, name1, (char **) &names1)); + assert (st_lookup (orig_stg_names, name2, (char **) &names2)); + for (i = 0; i < array_n (names2); i++) { + name = array_fetch (char *, names2, i); + array_insert_last (char *, names1, name); + } + array_free (names2); + st_delete (orig_stg_names, &name2, NIL(char*)); + } + merged = 1; + lsFinish (gen1); + break; + } + else { + /* just skip it... */ + continue; + } + } + + (void) stg_create_transition (states[cl1], states[cl2], + in, out); + } + if (merged) { + lsFinish (gen); + break; + } + + /* now deal with self-loops (which should be taken care of by + * duplicate) + */ + foreach_state_outedge (state1, gen1, edge) { + state2 = stg_edge_to_state (edge); + assert (st_lookup_int (partitions, (char *) state2, &cl2)); + in = stg_edge_input_string (edge); + out = stg_edge_output_string (edge); + + if (duplicate (red_stg, states[cl1], states[cl2], in, + out)) { + continue; + } + + (void) stg_create_transition (states[cl1], states[cl2], + in, out); + } + } + if (merged) { + FREE (states); + stg_free (red_stg); + } + } while(merged); + + components = graph_scc (red_stg); + if (array_n (components) <= 1) { + break; + } + else { + if (astg_debug_flag > 1) { + for (i = 0; i < array_n (components); i++) { + component = array_fetch (array_t *, components, i); + fprintf (sisout, "%d:", i); + len = 4; + for (j = 0; j < array_n (component); j++) { + state = array_fetch (vertex_t *, component, j); + str = stg_get_state_name (state); + len += strlen (str) + 1; + if (len > 80) { + fprintf (sisout, "\n "); + len = strlen (str) + 4; + } + fprintf (sisout, " %s", str); + } + fprintf (sisout, "\n"); + } + } + + if (collapse > 1) { + fail ("internal error: cannot force a connected STG ?\n"); + } + fprintf (siserr, + "warning: forcing a connected state transition graph\n"); + fprintf (siserr, + " (may not work if the signal transition graph had critical races)\n"); + FREE (states); + stg_free (red_stg); + } + array_free (components); + } + + state1 = stg_get_start (stg); + assert (st_lookup_int (partitions, (char *) state1, &cl1)); + stg_set_start (red_stg, states[cl1]); + stg_set_current (red_stg, states[cl1]); + stg_set_prod_states (red_stg); + + FREE (states); + set_free (deleted); + + return red_stg; +} + +/* Collapse any successor of "state1" whose newly enabled signal set is empty + * or who is reached through the same transition + */ +static void +remove_subset_states (state1, partitions, class, saved_names, edge_trans, state_marking, pre_minimize) +vertex_t *state1; +st_table *partitions; +int class; +array_t *saved_names; +st_table *edge_trans, *state_marking; +int pre_minimize; +{ + edge_t *edge, *edge2; + lsGen gen, gen1, gen2; + vertex_t *state2, *from; + + if (! pre_minimize) { + return; + } + foreach_state_outedge (state1, gen, edge) { + state2 = stg_edge_to_state (edge); + if (state1 == state2 || st_is_member (partitions, (char *) state2)) { + continue; + } + + /* remove if there are no newly enabled signals + */ + if (bwd_new_enabled_signals (edge, edge_trans, state_marking)) { + continue; + } + + if (astg_debug_flag > 1) { + fprintf (sisout, "removing subset state %s (%d)\n", + stg_get_state_name (state2), class); + } + st_insert (partitions, (char *) state2, (char *) class); + array_insert_last (char *, saved_names, stg_get_state_name (state2)); + + remove_subset_states (state2, partitions, class, saved_names, + edge_trans, state_marking, pre_minimize); + } +} + +/* If pre_minimize, merge states where no new signal is enabled. + */ +static graph_t * +merge_equivalent (stg, pre_minimize, edge_trans, state_marking, orig_stg_names) +graph_t *stg; +int pre_minimize; +st_table *edge_trans, *state_marking, *orig_stg_names; +{ + st_table *partitions; + graph_t *red_stg; + int rm, class, after; + vertex_t *state, *from; + edge_t *edge, *edge2; + astg_scode new_enabled; + lsGen gen, gen1, gen2; + array_t *names, *saved_names; + + partitions = st_init_table (st_ptrcmp, st_ptrhash); + names = array_alloc (char *, 0); + + stg_foreach_state (stg, gen, state) { + rm = 0; + foreach_state_inedge (state, gen1, edge) { + from = stg_edge_from_state (edge); + if (state == from) { + continue; + } + + /* check for no new enabled signals */ + if (pre_minimize) { + new_enabled = bwd_new_enabled_signals (edge, edge_trans, + state_marking); + + if (! new_enabled) { + rm = 1; + lsFinish(gen1); + break; + } + } + +#if 0 + /* check for parallel identical transitions, ORDERING according to + * the position in the fanout list of "from" + */ + after = 0; + foreach_state_outedge (from, gen2, edge2) { + if (edge2 == edge) { + after = 1; + } + if (! after || + stg_edge_to_state (edge2) == state || + stg_edge_to_state (edge2) == from) { + continue; + } + + if (! strcmp (stg_edge_input_string (edge), + stg_edge_input_string (edge2))) { + rm = 1; + lsFinish(gen2); + break; + } + } +#endif + } + + if (rm) { + continue; + } + + class = array_n (names); + array_insert_last (char *, names, stg_get_state_name (state)); + if (astg_debug_flag > 1) { + fprintf (sisout, "keeping state %s (%d)\n", + stg_get_state_name (state), class); + } + saved_names = array_alloc (char *, 0); + array_insert_last (char *, saved_names, stg_get_state_name (state)); + st_insert (orig_stg_names, (char *) stg_get_state_name (state), + (char *) saved_names); + st_insert (partitions, (char *) state, (char *) class); + remove_subset_states (state, partitions, class, saved_names, + edge_trans, state_marking, pre_minimize); + } + + red_stg = bwd_reduced_stg (stg, partitions, orig_stg_names, + names, array_n (names)); + + st_free_table (partitions); + array_free (names); + + return red_stg; +} + +/* hash the marked places */ +int +bwd_marking_hash (key, modulus) +char *key; +int modulus; +{ + astg_ba_rec *ba; +#ifdef UNSAFE + ba_element_t result; +#else + unsigned result; +#endif + int i; + + ba = ((astg_marking *) key)->marked_places; + for (result = i = 0; i < ba->n_word; i++) { + result ^= ba->bit_array[i]; + } + + return result % modulus; +} + +int +bwd_marking_ptr_cmp (c1, c2) +char *c1, *c2; +{ + char *p1, *p2; + + p1 = *(char **) c1; + p2 = *(char **) c2; + return bwd_marking_cmp (p1, p2); +} + +/* compare two markings (astg_cmp_marking returns +1 or 0) */ +int +bwd_marking_cmp (c1, c2) +char *c1, *c2; +{ + int n; + astg_marking *m1, *m2; + astg_ba_rec *ba1, *ba2; + + m1 = (astg_marking *) c1; + m2 = (astg_marking *) c2; + ba1 = m1->marked_places; + ba2 = m2->marked_places; + /* copied from ba_cmp in astg.c */ + if (ba1->n_elem != ba2->n_elem) { + return ba1->n_elem - ba2->n_elem; + } +#ifdef UNSAFE + n = ba1->n_word * sizeof(ba_element_t); +#else + n = ba1->n_word * sizeof(unsigned); +#endif + return memcmp ((char *) ba1->bit_array, (char *) ba2->bit_array, n); +} + +/* Transform the ASTG into an STG from the initial state "state" + * (ASTG = Signal Transition Graph, STG = State Transition Graph). + * If "use_output" is TRUE, then output signals are also considered to be + * input signals to the STG. The resulting STG is returned. + */ +graph_t * +bwd_astg_to_stg (astg, code, use_output, pre_minimize) +astg_graph *astg; +astg_scode code; +int use_output, pre_minimize; +{ + graph_t *stg; + char *in, *out; + static char buf[512]; + int nin, nout, change_count; + astg_generator sgen, tgen; + astg_signal* sig_p; + astg_trans *t; + vertex_t *init_state, *state; + astg_flow_t flow_rec; + edge_t *edge; + lsGen gen; + astg_marking *curr_marking; + st_table *state_out; + array_t *curr_trans, *from_stack; + + /* set up variables for the recursion */ + stg = stg_alloc (); + nin = nout = 0; + astg_foreach_signal (astg, sgen, sig_p) { + if (astg_signal_type (sig_p) == ASTG_DUMMY_SIG) { + continue; + } + /* all signals are inputs, only output signals are outputs */ + if (use_output || astg_signal_type (sig_p) == ASTG_INPUT_SIG) { + nin++; + } + if (astg_signal_type (sig_p) == ASTG_OUTPUT_SIG || + astg_signal_type (sig_p) == ASTG_INTERNAL_SIG) { + nout++; + } + } + stg_set_num_inputs (stg, nin); + stg_set_num_outputs (stg, nout); + in = ALLOC (char, nin+1); + in[nin] = '\0'; + out = ALLOC (char, nout+1); + out[nout] = '\0'; + + if (global_edge_trans != NIL(st_table)) { + /* we should free the elements here */ + st_free_table (global_edge_trans); + } + global_edge_trans = st_init_table (st_ptrcmp, st_ptrhash); + + if (global_marking_state != NIL(st_table)) { + st_free_table (global_marking_state); + } + global_marking_state = st_init_table (bwd_marking_cmp, bwd_marking_hash); + + if (global_state_marking != NIL(st_table)) { + /* we should free the elements here */ + st_free_table (global_state_marking); + } + global_state_marking = st_init_table (st_ptrcmp, st_ptrhash); + + flow_rec.force_safe = ASTG_FALSE; + flow_rec.status = 0; + flow_rec.stg = astg; + astg_foreach_trans (astg,tgen,t) { + astg_set_useful(t,ASTG_FALSE); + } + flow_rec.marking = astg_initial_marking (astg); + + change_count = astg->change_count; + astg->change_count = -1; + + astg_sel_clear (astg); + astg_reset_state_graph (astg); + astg->change_count = change_count; + flow_rec.marking->state_code = code; + + state_out = st_init_table (st_ptrcmp, st_ptrhash); + + /* recursively traverse the state transition graph */ + curr_marking = astg_dup_marking (flow_rec.marking); + curr_trans = array_alloc (astg_trans *, 0); + from_stack = array_alloc (vertex_t **, 0); + init_state = astg_to_stg_recur (&flow_rec, astg, stg, code, + curr_marking, in, out, buf, use_output, + global_edge_trans, global_state_marking, global_marking_state, state_out, + curr_trans, 0, from_stack, 0); + astg_delete_marking (curr_marking); + array_free (curr_trans); + array_free (from_stack); + + st_free_table (state_out); + + /* set up the global parameters of the transition graph */ + stg_set_start (stg, init_state); + stg_set_current (stg, init_state); + stg_set_prod_states (stg); + + if (astg_debug_flag > 1) { + print_sg (astg, stg, global_edge_trans); + } + + /* now look for states, where the next state differs only in the firing + * of one transition (no new one is enabled), and merge them together. + */ + if (global_orig_stg != NIL(graph_t)) { + stg_free (global_orig_stg); + } + global_orig_stg = stg; + global_orig_stg_names = st_init_table (strcmp, st_strhash); + stg = merge_equivalent (stg, pre_minimize, global_edge_trans, + global_state_marking, global_orig_stg_names); + + return stg; +} + +/* Given a string, return its PO form (the STG name): truncate any trailing + * "_" or "_next", if any. + * The result is a statically allocated area !!. + */ +char * +bwd_po_name (name) +char *name; +{ + int len; + static char buf[256]; + + strcpy (buf, name); + len = strlen (buf); + switch (buf[len-1]) { + case '_': + assert (len > 1); + buf[len-1] = '\0'; + break; + case 't': + if (len > 5) { + if (buf[len-5] == '_' && + buf[len-4] == 'n' && + buf[len-3] == 'e' && + buf[len-2] == 'x' && + buf[len-1] == 't') { + buf[len-5] = '\0'; + } + } + break; + default: + break; + } + return buf; +} + +/* Given a string, return its fake PO form (the PO form with "_next" appended). + * The result is a statically allocated area !!. + */ +char * +bwd_fake_po_name (name) +char *name; +{ + static char buf[256]; + + strcpy (buf, bwd_po_name (name)); + strcat (buf, "_next"); + return buf; +} + +/* Given a string, return its fake PI form (the PO form with "_" appended). + * The result is a statically allocated area !!. + */ +char * +bwd_fake_pi_name (name) +char *name; +{ + static char buf[256]; + + strcpy (buf, bwd_po_name (name)); + strcat (buf, "_"); + return buf; +} + + +void +bwd_astg_latch (network, latch_type, keep_red) +network_t *network; +latch_synch_t latch_type; +int keep_red; +{ + node_t *po, *fake_po, *pi, *node, *old_po; + char *new_name; + lsGen gen; + latch_t *latch; + int i; + astg_retval status; + astg_graph *astg; + astg_signal *sig_p; + astg_scode state, bit; + array_t *po_arr; + + /* find the initial marking, if missing, for the initial latch value */ + astg=astg_current (network); + state = (astg_scode) 0; + if (astg != NIL(astg_graph)) { + status = astg_initial_state (astg, &state); + if (status != ASTG_OK && status != ASTG_NOT_USC) { + fprintf (siserr, "inconsistency during token flow (use astg_flow)\n"); + return; + } + } + + /* we must use this array because we are messing up with the PO list */ + po_arr = array_alloc (node_t *, 0); + foreach_primary_output (network, gen, po) { + array_insert_last (node_t *, po_arr, po); + } + for (i = 0; i < array_n (po_arr); i++) { + po = array_fetch (node_t *, po_arr, i); + if (! network_is_real_po(network, po)){ + /* in the synchronous case... */ + continue; + } + /* find the corresponding PI (every PO must have one...) */ + pi = network_find_node (network, bwd_fake_pi_name (node_long_name (po))); + if (pi == NIL(node_t) || pi == po) { + /* a strange PO */ + continue; + } + + /* remove PI's without fanout */ + if (! keep_red && node_type (pi) == PRIMARY_INPUT && + node_num_fanout (pi) == 0) { + network_delete_node (network, pi); + continue; + } + + /* create the latch and find its initial value */ + node = node_get_fanin (po, 0); + fake_po = network_add_fake_primary_output (network, node); + network_create_latch (network, &latch, fake_po, pi); + node_patch_fanin (po, node, pi); + + latch_set_type (latch, latch_type); + latch_set_initial_value (latch, 0); + if (astg != NIL(astg_graph)) { + sig_p = astg_find_named_signal (astg, bwd_po_name (node_long_name (pi))); + if (sig_p == NIL(astg_signal)) { + fprintf (siserr, "cannot find signal for %s\n", + node_long_name (pi)); + } + else { + bit = astg_state_bit (sig_p); + if (bit & state) { + latch_set_initial_value (latch, 1); + } + } + } + + new_name = util_strsav (bwd_po_name (node_long_name (po))); + network_change_node_name (network, po, new_name); + + new_name = util_strsav (bwd_fake_po_name (node_long_name (po))); + network_change_node_name (network, fake_po, new_name); +#if 0 + /* hope the printing routines are fixed eventually... */ + node = node_get_fanin (fake_po, 0); + if (node_num_fanout (node) == 1 && node_type (node) == INTERNAL) { + network_change_node_name (network, node, new_name); + } + else { + network_change_node_name (network, fake_po, new_name); + } +#endif + } + array_free (po_arr); +} +static int sp, count; +/* Terminology and algorithm from Aho Hopcroft Ullman page 192 + * It returns LOWLINK[v]; the array of strongly connected components + * is sc. + */ +static int +scc_search (v, df, stack_st, components, stack_arr, lev) +vertex_t *v; +st_table *df, *stack_st; +array_t *components, *stack_arr; +int lev; +{ + edge_t *e; + vertex_t *w; + array_t *component; + lsGen gen; + int i, df_v, df_w, low_v, low_w; + + if (astg_debug_flag > 2) { + for (i = 0; i < lev; i++) { + fprintf (sisout, " "); + } + fprintf (sisout, "v %s\n", stg_get_state_name (v)); + } + + df_v = count++; + (void) st_insert (df, (char *) v, (char *) df_v); + (void) st_insert (stack_st, (char *) v, NIL(char)); + array_insert (vertex_t *, stack_arr, sp++, v); + low_v = df_v; + + foreach_out_edge (v, gen, e) { + w = g_e_dest (e); + if (astg_debug_flag > 2) { + for (i = 0; i < lev; i++) { + fprintf (sisout, " "); + } + fprintf (sisout, "w %s\n", stg_get_state_name (w)); + } + + if (st_lookup_int (df, (char *) w, &df_w)) { + if (df_w < df_v && st_is_member (stack_st, (char *) w)) { + low_v = MIN (low_v, df_w); + } + } + else { + low_w = scc_search (w, df, stack_st, components, stack_arr, + lev + 1); + low_v = MIN (low_v, low_w); + } + if (astg_debug_flag > 2) { + for (i = 0; i < lev; i++) { + fprintf (sisout, " "); + } + fprintf (sisout, "low_v %d\n", low_v); + } + } + + if (low_v == df_v) { + component = array_alloc (vertex_t *, 0); + array_insert_last (array_t *, components, component); + do { + w = array_fetch (vertex_t *, stack_arr, --sp); + if (astg_debug_flag > 2) { + for (i = 0; i < lev; i++) { + fprintf (sisout, " "); + } + fprintf (sisout, "c %s\n", stg_get_state_name (w)); + } + array_insert_last (vertex_t *, component, w); + (void) st_delete (stack_st, (char **) &w, NIL(char *)); + } while (w != v); + } + + return low_v; +} + +array_t * +graph_scc (g) +graph_t *g; +{ + vertex_t *v; + lsGen gen; + st_table *df, *stack_st; + array_t *components, *stack_arr; + + df = st_init_table (st_ptrcmp, st_ptrhash); + stack_st = st_init_table (st_ptrcmp, st_ptrhash); + components = array_alloc (array_t *, 0); + stack_arr = array_alloc (array_t *, 0); + sp = 0; + count = 0; + + foreach_vertex (g, gen, v) { + if (! st_is_member (df, (char *) v)) { + (void) scc_search (v, df, stack_st, components, stack_arr, 0); + } + } + + st_free_table (df); + st_free_table (stack_st); + array_free (stack_arr); + + return components; +} + +static int +covers (in1, in2) +char *in1, *in2; +{ + int i; + + for (i = 0; in1[i]; i++) { + if (in1[i] == '-') { + continue; + } + if (in1[i] != in2[i]) { + return 0; + } + } + return 1; +} + +static int +compatible (in1, in2) +char *in1, *in2; +{ + int i; + + for (i = 0; in1[i]; i++) { + if (in1[i] == '-' || in2[i] == '-') { + continue; + } + if (in1[i] != in2[i]) { + return 0; + } + } + return 1; +} + +static vertex_t * +search_scr_state (new_stg, states, name, in, out, buf, code, new) +graph_t *new_stg; +array_t *states; +char *name, *in, *out, *buf, *code; +int *new; +{ + int i; + scr_state_t *state; + vertex_t *new_state; + + *new = 0; + for (i = 0; i < array_n (states); i++) { + state = array_fetch (scr_state_t *, states, i); + if (strcmp (state->name, name) || + strcmp (state->in, in) || strcmp (state->out, out)) { + continue; + } +#if 0 + if (strcmp (state->name, name) || + ! compatible (state->in, in) || strcmp (state->out, out)) { + continue; + } + /* found, now check who covers whom */ + if (covers (state->in, in)) { + return state->state; + } + /* we must replace the old state with the new one... */ + sprintf (buf, "%s_%s_%s", name, in, out); + stg_set_state_name (state->state, buf); + FREE (state->name); + state->name = util_strsav (name); + FREE (state->in); + state->in = util_strsav (in); + FREE (state->out); + state->out = util_strsav (out); + +#endif + return state->state; + } + + /* not found: create a new record and a new STG state */ + *new = 1; + sprintf (buf, "%s_%s_%s", name, in, out); + new_state = stg_create_state (new_stg, buf, code); + state = ALLOC (scr_state_t, 1); + state->state = new_state; + state->name = util_strsav (name); + state->in = util_strsav (in); + state->out = util_strsav (out); + array_insert_last (scr_state_t *, states, state); + + return state->state; +} + +/* transform an FSM into an FSM satisfying the single cube restriction */ +static void +stg_scr_recur (buf, states, old_from, old_stg, new_stg) +char *buf; +array_t *states; +vertex_t *old_from; +graph_t *old_stg, *new_stg; +{ + lsGen gen1, gen2; + edge_t *inedge, *outedge; + vertex_t *old_to, *new_from, *new_to; + char *in, *out, *name; + int new; + + foreach_state_inedge (old_from, gen1, inedge) { + /* self-loops don't matter */ + if (stg_edge_from_state (inedge) == old_from) { + continue; + } + in = stg_edge_input_string (inedge); + out = stg_edge_output_string (inedge); + name = stg_get_state_name (old_from); + new_from = search_scr_state (new_stg, states, name, in, out, buf, + stg_get_state_encoding (old_from), &new); + foreach_state_outedge (old_from, gen2, outedge) { + old_to = stg_edge_to_state (outedge); + /* self-loops are a special case */ + if (old_to == old_from) { + (void) stg_create_transition (new_from, new_from, + stg_edge_input_string (outedge), + stg_edge_output_string (outedge)); + } + else { + in = stg_edge_input_string (outedge); + out = stg_edge_output_string (outedge); + name = stg_get_state_name (old_to); + new_to = search_scr_state (new_stg, states, name, + in, out, buf, stg_get_state_encoding (old_to), &new); + if (new) { + stg_scr_recur (buf, states, old_to, old_stg, new_stg); + } + + if (! duplicate (new_stg, new_from, new_to, in, out)) { + (void) stg_create_transition (new_from, new_to, in, out); + } + } + } + } +} + +/* check if some signal changes from loop to in1 but not from loop to in2 */ +static int +is_burst_subset (loop, in1, in2) +char *loop, *in1, *in2; +{ + int i; + + for (i = 0; loop[i]; i++) { + if (loop[i] == '-' || in1[i] == '-' || in2[i] == '-') { + continue; + } + if (loop[i] != in1[i] && loop[i] == in2[i]) { + return 0; + } + } + return 1; +} + +graph_t * +bwd_stg_scr (old_stg) +graph_t *old_stg; +{ + graph_t *new_stg; + lsGen gen, gen1, gen2; + vertex_t *state, *old_start, *new_start; + edge_t *edge, *edge1; + int len, i; + char *buf, *in, *out, *name; + array_t *states; + scr_state_t *scr_state; + + /* check if the STG has output don't cares */ + stg_foreach_transition (old_stg, gen, edge) { + if (strchr (stg_edge_output_string (edge), '-') != NULL) { + fprintf (siserr, "invalid output don't care:\n"); + fprintf (siserr, "%s %s %s %s\n", stg_edge_input_string (edge), + stg_get_state_name (stg_edge_from_state (edge)), + stg_get_state_name (stg_edge_to_state (edge)), + stg_edge_output_string (edge)); + return NIL(graph_t); + } + } + + /* initialize the new STG */ + new_stg = stg_alloc (); + stg_set_num_inputs (new_stg, stg_get_num_inputs (old_stg)); + stg_set_num_outputs (new_stg, stg_get_num_outputs (old_stg)); + + /* get the max name length */ + len = 0; + stg_foreach_state (old_stg, gen, state) { + len = MAX (len, strlen (stg_get_state_name (state))); + } + len += 3 + stg_get_num_inputs (old_stg) + stg_get_num_outputs (old_stg); + buf = ALLOC (char, len); + + /* do the actual state splitting */ + states = array_alloc (scr_state_t *, 0); + old_start = stg_get_start (old_stg); + stg_scr_recur (buf, states, old_start, old_stg, new_stg); + + for (i = 0; i < array_n (states); i++) { + scr_state = array_fetch (scr_state_t *, states, i); + FREE (scr_state); + } + array_free (states); + + /* check if some burst is a subset of another burst */ + stg_foreach_state (new_stg, gen, state) { + in = NIL(char); + foreach_state_inedge (state, gen1, edge) { + if (stg_edge_from_state (edge) == state) { + continue; + } + in = stg_edge_input_string (edge); + lsFinish (gen1); + break; + } + if (in == NIL(char)) { + fprintf (siserr, "state %s has only self loops ?\n", + stg_get_state_name (state)); + continue; + } + + foreach_state_outedge (state, gen1, edge) { + if (stg_edge_to_state (edge) == state) { + continue; + } + foreach_state_outedge (state, gen2, edge1) { + if (edge1 == edge || stg_edge_to_state (edge1) == state) { + continue; + } + if (is_burst_subset (in, stg_edge_input_string (edge), + stg_edge_input_string (edge1))) { + fprintf (siserr, + "warning: changing input signals of transition\n"); + fprintf (siserr, "%s %s %s %s\n", + stg_edge_input_string (edge), + stg_get_state_name (stg_edge_from_state (edge)), + stg_get_state_name (stg_edge_to_state (edge)), + stg_edge_output_string (edge)); + fprintf (siserr, "are a subset of transition\n"); + fprintf (siserr, "%s %s %s %s\n", + stg_edge_input_string (edge1), + stg_get_state_name (stg_edge_from_state (edge1)), + stg_get_state_name (stg_edge_to_state (edge1)), + stg_edge_output_string (edge1)); + fprintf (siserr, "(old input signal values %s)\n", in); + } + } + } + } + + /* find a reset state, the first generated by the old one */ + name = stg_get_state_name (old_start); + len = strlen (name); + stg_foreach_state (new_stg, gen, new_start) { + if (! strncmp (stg_get_state_name (new_start), name, len)) { + stg_set_start (new_stg, new_start); + stg_set_current (new_stg, new_start); + lsFinish (gen); + break; + } + } + + FREE (buf); + + stg_set_prod_states (new_stg); + return new_stg; +} + +/* create the ASTG fragment corresponding to "from" */ +astg_place * +stg_to_astg_recur (from, stg, astg, finedge, foutedge, finbuf, foutbuf, statebuf, innames, outnames, stnames, dummyname) +vertex_t *from; +graph_t *stg; +astg_graph *astg; +edge_t *finedge, *foutedge; +char *finbuf, *foutbuf, *statebuf, **innames, **outnames, **stnames, *dummyname; +{ + astg_place *from_p, *to_p; + astg_trans *from_t, *to_t, *mid_t1, *mid_t2, *trans; + vertex_t *to; + lsGen gen; + char *fin, *fout, *from_code, *to_code, *str, *new_name; + int i, len; + static int idx = 0; + + from_p = NIL(astg_place); + if (foutedge != NIL(edge_t)) { + /* we are recurring on the fanout cube */ + str = strchr (foutbuf, '-'); + if (str == NULL) { + /* we are at the bottom of the double recursion: finedge and foutedge + * are set, and finbuf and foutbuf contain the resolved values + */ + fout = stg_edge_input_string (foutedge); + len = strlen (fout); + fin = stg_edge_input_string (finedge); + to = stg_edge_to_state (foutedge); + + /* find or create the new places */ + strcpy (statebuf, stg_get_state_name (from)); + str = strchr (statebuf, '_') + 1; + strncpy (str, finbuf, len); + from_p = astg_find_place (astg, statebuf, /*create*/ ASTG_TRUE); + + strcpy (statebuf, stg_get_state_name (to)); + str = strchr (statebuf, '_') + 1; + strncpy (str, foutbuf, len); + if ((to_p = astg_find_place (astg, statebuf, + /*create*/ ASTG_FALSE)) == NIL(astg_place)) { + new_name = util_strsav (statebuf); + /* recur to create the new place */ + to_p = stg_to_astg_recur (to, stg, astg, + NIL(edge_t), NIL(edge_t), NIL(char), NIL(char), statebuf, + innames, outnames, stnames, dummyname); + to_p = astg_find_place (astg, new_name, /*create*/ ASTG_FALSE); + FREE (new_name); + } + assert (from_p != NIL(astg_place)); + assert (to_p != NIL(astg_place)); + + if (astg_debug_flag > 1) { + fprintf (sisout, "(%s %s) %s -> (%s %s) %s\n", + fin, finbuf, stg_get_state_name (from), + fout, foutbuf, stg_get_state_name (to)); + } + + /* create the dummy transitions */ + from_t = astg_find_trans (astg, dummyname, + ASTG_DUMMY_X, idx++, ASTG_TRUE); + astg_find_edge (from_p, from_t, ASTG_TRUE); + to_t = astg_find_trans (astg, dummyname, + ASTG_DUMMY_X, idx++, ASTG_TRUE); + astg_find_edge (to_t, to_p, ASTG_TRUE); + if (stnames != NIL(char*)) { + mid_t1 = astg_find_trans (astg, dummyname, + ASTG_DUMMY_X, idx++, ASTG_TRUE); + mid_t2 = astg_find_trans (astg, dummyname, + ASTG_DUMMY_X, idx++, ASTG_TRUE); + } + else { + mid_t1 = mid_t2 = astg_find_trans (astg, dummyname, + ASTG_DUMMY_X, idx++, ASTG_TRUE); + } + astg_add_constraint (from_t, mid_t1, ASTG_TRUE); + astg_add_constraint (mid_t2, to_t, ASTG_TRUE); + if (astg_debug_flag > 0) { + fprintf (sisout, "%s -> %s -> %s -> %s -> %s -> %s\n", + astg_place_name (from_p), + astg_trans_name (from_t), + astg_trans_name (mid_t1), + astg_trans_name (mid_t2), + astg_trans_name (to_t), + astg_place_name (to_p)); + } + + /* create the input burst */ + fout = stg_edge_input_string (foutedge); + len = strlen (fout); + fin = stg_edge_input_string (finedge); + for (i = 0; i < len; i++) { + if (fout[i] == '-') { + /* create the long arc */ + if (finbuf[i] != foutbuf[i]) { + trans = astg_find_trans (astg, innames[i], + TRANS_TYPE(finbuf[i]), idx++, ASTG_TRUE); + astg_add_constraint (from_t, trans, ASTG_TRUE); + astg_add_constraint (trans, to_t, ASTG_TRUE); + if (astg_debug_flag > 0) { + fprintf (sisout, "%s -> %s -> %s\n", + astg_trans_name (from_t), + astg_trans_name (trans), + astg_trans_name (to_t)); + } + } + } + else { + /* create the input transition */ + if (finbuf[i] != foutbuf[i]) { + trans = astg_find_trans (astg, innames[i], + TRANS_TYPE(finbuf[i]), idx++, ASTG_TRUE); + astg_add_constraint (from_t, trans, ASTG_TRUE); + astg_add_constraint (trans, mid_t1, ASTG_TRUE); + if (astg_debug_flag > 0) { + fprintf (sisout, "%s -> %s -> %s\n", + astg_trans_name (from_t), + astg_trans_name (trans), + astg_trans_name (mid_t1)); + } + } + } + } + + if (stnames != NIL(char*)) { + /* create the state burst */ + from_code = stg_get_state_encoding (from); + to_code = stg_get_state_encoding (to); + if (! strcmp (from_code, to_code)) { + /* same state code, split due to SCR */ + astg_add_constraint (mid_t1, mid_t2, ASTG_TRUE); + } + else { + for (i = 0; from_code[i]; i++) { + if (from_code[i] != to_code[i]) { + trans = astg_find_trans (astg, stnames[i], + TRANS_TYPE(from_code[i]), idx++, ASTG_TRUE); + astg_add_constraint (mid_t1, trans, ASTG_TRUE); + astg_add_constraint (trans, mid_t2, ASTG_TRUE); + if (astg_debug_flag > 0) { + fprintf (sisout, "%s -> %s -> %s\n", + astg_trans_name (mid_t1), + astg_trans_name (trans), + astg_trans_name (mid_t2)); + } + } + } + } + } + + /* create the output burst */ + fout = stg_edge_output_string (foutedge); + len = strlen (fout); + fin = stg_edge_output_string (finedge); + + for (i = 0; i < len; i++) { + /* sanity check... */ + if (fout[i] == '-') { + fprintf (siserr, "illegal output don't care value\n"); + fprintf (siserr, "%s %s %s %s\n", + stg_edge_input_string (foutedge), + stg_get_state_name (from), + stg_get_state_name (to), + stg_edge_output_string (foutedge)); + } + /* create the output transition */ + if (fin[i] != fout[i]) { + trans = astg_find_trans (astg, outnames[i], + TRANS_TYPE(fin[i]), idx++, ASTG_TRUE); + astg_add_constraint (mid_t2, trans, ASTG_TRUE); + astg_add_constraint (trans, to_t, ASTG_TRUE); + if (astg_debug_flag > 0) { + fprintf (sisout, "%s -> %s -> %s\n", + astg_trans_name (mid_t2), + astg_trans_name (trans), + astg_trans_name (to_t)); + } + } + } + } + else { + /* split on the two cases of the fanout cube */ + *str = '0'; + from_p = stg_to_astg_recur (from, stg, astg, finedge, foutedge, + finbuf, foutbuf, statebuf, + innames, outnames, stnames, dummyname); + assert (from_p != NIL(astg_place)); + *str = '1'; + from_p = stg_to_astg_recur (from, stg, astg, finedge, foutedge, + finbuf, foutbuf, statebuf, + innames, outnames, stnames, dummyname); + assert (from_p != NIL(astg_place)); + *str = '-'; + } + } + else if (finedge != NIL(edge_t)) { + /* we are recurring on the fanin cube */ + str = strchr (finbuf, '-'); + if (str == NULL) { + /* recur on the fanout cube */ + foreach_state_outedge (from, gen, foutedge) { + if (stg_edge_to_state (foutedge) == from) { + continue; + } + foutbuf = util_strsav (stg_edge_input_string (foutedge)); + from_p = stg_to_astg_recur (from, stg, astg, finedge, foutedge, + finbuf, foutbuf, statebuf, + innames, outnames, stnames, dummyname); + FREE (foutbuf); + assert (from_p != NIL(astg_place)); + } + } + else { + /* split on the two cases of the fanin cube */ + *str = '0'; + from_p = stg_to_astg_recur (from, stg, astg, finedge, NIL(edge_t), + finbuf, NIL(char), statebuf, + innames, outnames, stnames, dummyname); + assert (from_p != NIL(astg_place)); + *str = '1'; + from_p = stg_to_astg_recur (from, stg, astg, finedge, NIL(edge_t), + finbuf, NIL(char), statebuf, + innames, outnames, stnames, dummyname); + assert (from_p != NIL(astg_place)); + *str = '-'; + } + } + else { + /* at the top: recur on the fanin cube (the first one is enough) */ + foreach_state_inedge (from, gen, finedge) { + if (stg_edge_from_state (finedge) == from) { + continue; + } + finbuf = util_strsav (stg_edge_input_string (finedge)); + from_p = stg_to_astg_recur (from, stg, astg, finedge, NIL(edge_t), + finbuf, NIL(char), statebuf, + innames, outnames, stnames, dummyname); + FREE (finbuf); + assert (from_p != NIL(astg_place)); + break; + } + } + assert (from_p != NIL(astg_place)); + + return from_p; +} + +/* transform an AFSM satisfying the single cube restriction into an STG */ +astg_graph * +bwd_stg_to_astg (stg, network) +graph_t *stg; +network_t *network; +{ + astg_graph *astg; + lsGen gen; + node_t *pi, *po; + vertex_t *start, *state; + astg_place *place; + char *statebuf, **innames, **outnames, **stnames, *dummyname, buf[80]; + int i, len, ni, no, ns; + + start = stg_get_start (stg); + if (start == NIL(vertex_t)) { + fprintf (siserr, "the state transition graph needs an initial state\n"); + return NIL(astg_graph); + } + + astg = astg_new (network_name (network)); + astg->filename = util_strsav (network_name (network)); + astg->name = util_strsav (network_name (network)); + + ni = stg_get_num_inputs (stg); + innames = ALLOC (char *, ni); + if (ni == network_num_pi (network)) { + i = 0; + foreach_primary_input (network, gen, pi) { + innames[i] = util_strsav (node_long_name (pi)); + astg_find_signal (astg, innames[i], ASTG_INPUT_SIG, ASTG_TRUE); + i++; + } + } + else { + for (i = 0; i < ni; i++) { + sprintf (buf, "I%d", i); + innames[i] = util_strsav (buf); + astg_find_signal (astg, innames[i], ASTG_INPUT_SIG, ASTG_TRUE); + } + } + + no = stg_get_num_outputs (stg); + outnames = ALLOC (char *, no); + if (no == network_num_po (network)) { + i = 0; + foreach_primary_output (network, gen, po) { + outnames[i] = util_strsav (node_long_name (po)); + astg_find_signal (astg, outnames[i], ASTG_OUTPUT_SIG, ASTG_TRUE); + i++; + } + } + else { + for (i = 0; i < no; i++) { + sprintf (buf, "O%d", i); + outnames[i] = util_strsav (buf); + astg_find_signal (astg, outnames[i], ASTG_OUTPUT_SIG, ASTG_TRUE); + } + } + + if (stg_get_state_encoding (start) != NIL(char)) { + ns = strlen (stg_get_state_encoding (start)); + stnames = ALLOC (char *, ns); + for (i = 0; i < ns; i++) { + sprintf (buf, "S%d", i); + stnames[i] = util_strsav (buf); + astg_find_signal (astg, stnames[i], ASTG_INTERNAL_SIG, ASTG_TRUE); + } + } + else { + stnames = NIL(char*); + } + + dummyname = "dummy"; + astg_find_signal (astg, dummyname, ASTG_DUMMY_SIG, ASTG_TRUE); + + len = 0; + stg_foreach_state (stg, gen, state) { + len = MAX (len, strlen (stg_get_state_name (state))); + } + statebuf = ALLOC (char, (len + 1)); + + place = stg_to_astg_recur (start, stg, astg, + NIL(edge_t), NIL(edge_t), NIL(char), NIL(char), statebuf, + innames, outnames, stnames, dummyname); + + astg->has_marking = ASTG_TRUE; + place->type.place.initial_token = ASTG_TRUE; + astg->file_count = astg_change_count (astg); + + for (i = 0; i < ni; i++) { + FREE (innames[i]); + } + FREE (innames); + for (i = 0; i < no; i++) { + FREE (outnames[i]); + } + FREE (outnames); + if (stnames != NIL(char*)) { + for (i = 0; i < ns; i++) { + FREE (stnames[i]); + } + FREE (stnames); + } + FREE (statebuf); + + return astg; +} + +static void +string_to_set (set, str) +pset set; +char *str; +{ + int i; + + for (i = 0; str[i]; i++) { + switch (str[i]) { + case '0': + PUTINPUT (set, i, ZERO); + break; + case '1': + PUTINPUT (set, i, ONE); + break; + default: + PUTINPUT (set, i, TWO); + break; + } + } +} + +static void +set_to_string (str, set, n) +char *str; +pset set; +int n; +{ + int i; + + for (i = 0; i < n; i++) { + switch (GETINPUT (set, i)) { + case ZERO: + str[i] = '0'; + break; + case ONE: + str[i] = '1'; + break; + default: + str[i] = '-'; + break; + } + } + str[n] = '\0'; +} + +/* replace each unspecified edge with a self-loop, with the same output + * value as the entering output label. + * The STG must satisfy the single-cube restriction + */ +void +bwd_dc_to_self_loop (stg) +graph_t *stg; +{ + set_family_t *F, *R; + pset p, p1, last; + int nin, nout; + lsGen gen, gen1; + vertex_t *state; + edge_t *edge; + char *in, *out; + + nin = stg_get_num_inputs (stg); + nout = stg_get_num_outputs (stg); + define_cube_size (nin); + in = ALLOC (char, nin + 1); + out = ALLOC (char, nout + 1); + p = set_new (2 * nin); + stg_foreach_state (stg, gen, state) { + /* collect input strings */ + F = sf_new (0, 2 * nin); + foreach_state_outedge (state, gen1, edge) { + string_to_set (p, stg_edge_input_string (edge)); + sf_addset (F, p); + } + R = complement (cube1list (F)); + + /* collect the output string (SCR !) */ + foreach_state_inedge (state, gen1, edge) { + if (stg_edge_from_state (edge) == state) { + continue; + } + strcpy (out, stg_edge_output_string (edge)); + lsFinish (gen1); + break; + } + + /* create the self-loops */ + foreach_set (R, last, p1) { + set_to_string (in, p1, nin); + stg_create_transition(state, state, in, out); + } + sf_free (R); + sf_free (F); + } + set_free (p); + FREE (in); + FREE (out); +} + +void +bwd_write_sg(fp,stg, astg) +FILE *fp; +graph_t *stg; +astg_graph *astg; +{ + lsGen gen, gen2; + vertex_t *v; + edge_t *e; + char *state_encoding, *next_state_encoding; + array_t *ionames; + int i, first, not_open; + FILE *output_file; + char name[180]; + + + (void) fprintf(fp,"SG:\nSTATEVECTOR:"); + + ionames = stg_get_names(stg, 1); + if (ionames == NIL(array_t)) { + (void) fprintf(fp, "input names cannot be found.\n"); + } else { + for (i = 0; i < stg_get_num_inputs(stg); i++) { + (void) sprintf(name, "%s", array_fetch(char *, ionames, i)); + if (name[strlen(name)-1] == '_') + name[strlen(name)-1] = '\0'; + else + (void) fprintf(fp, "INP "); + (void) fprintf(fp, "%s ",name); + } + } + (void) fprintf(fp,"\n"); + (void) fprintf(fp,"STATES:\n"); + + stg_foreach_state(stg,gen,v) { + first = 1; + foreach_state_outedge(v,gen2,e) { + if (first == 1) { + /* catch state encoding via self-loop transition */ + state_encoding = stg_edge_input_string(e); + /* (void) fprintf(fp,"state encoding: %s\n", state_encoding);*/ + first = 0; + } else { + next_state_encoding = stg_edge_input_string(e); + for (i = 0; i < stg_get_num_inputs(stg); i++) { + if (next_state_encoding[i] != state_encoding[i]) { + if (state_encoding[i] == '1') + state_encoding[i] = 'F'; + else if (state_encoding[i] == '0') + state_encoding[i] = 'R'; + } + } + } + } + (void) fprintf(fp,"%s\n", state_encoding); + } +} +#endif /* SIS */ diff --git a/sis/astg/com_astg.c b/sis/astg/com_astg.c new file mode 100644 index 0000000..0043992 --- /dev/null +++ b/sis/astg/com_astg.c @@ -0,0 +1,36 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/com_astg.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +/* -------------------------------------------------------------------------- *\ + com_astg.c -- Add commands for ASTG package. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:59 $ + + Package initialization and cleanup. +\* ---------------------------------------------------------------------------*/ + +#ifdef SIS +#include "sis.h" +#include "astg_int.h" +#include "si_int.h" +#include "bwd_int.h" + +void init_astg() +{ + astg_basic_cmds (ASTG_TRUE); + si_cmds(); + bwd_cmds (); +} + +void end_astg() +{ + astg_basic_cmds (ASTG_FALSE); +} +#endif /* SIS */ diff --git a/sis/astg/min_delay_int.h b/sis/astg/min_delay_int.h new file mode 100644 index 0000000..f304e24 --- /dev/null +++ b/sis/astg/min_delay_int.h @@ -0,0 +1,62 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/min_delay_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +#include "delay.h" + +#define DELAY_SLOT delay +#define DELAY(node) ((delay_node_t *) node->DELAY_SLOT) + +#define DEF_DELAY_SLOT default_delay +#define DEF_DELAY(network) ((delay_network_t *) network->DEF_DELAY_SLOT) + +/* + * Each node is annotated with a 'delay_node_t'; this stores the arrival, + * required, and slack times for each node. Also, for PRIMARY_INPUT and + * PRIMARY_OUTPUT nodes, the pair (time, time_given) allows the specification + * of input arrival and output required times, respectively. Finally, a delay + * model slot is reserved for PRIMARY_INPUT and PRIMARY_OUTPUT nodes; if + * present, it stores the input-rise factor and output-load factors. + */ + +typedef struct delay_node_struct { + delay_time_t arrival; + delay_time_t required; + delay_time_t slack; + unsigned pin_params_valid; + int num_pin_params; + delay_pin_t **pin_params; + delay_pin_t *pin_delay; + double load; +#ifdef SIS + char *synch_clock_name; /* clock_name w.r.t. arr & req times spec. */ + int synch_clock_edge; /* RISE_TRANSITION or FALL_TRANSITION */ + int synch_relative_flag; /* BEFORE_CLOCK_EDGE or AFTER_CLOCK_EDGE */ +#endif /* SIS */ +} delay_node_t; + +typedef struct delay_wire_load_struct { + double slope; + int num_pins_set; + array_t *pins; +} delay_wire_load_table_t; + +typedef struct delay_network_struct { + delay_time_t default_arrival; + delay_time_t default_required; + delay_wire_load_table_t wire_load_table; + delay_pin_t pipo_model; +} delay_network_t; + +/* used in com_delay.c */ +extern void delay_dup(); +extern void delay_free(); +extern void delay_alloc(); +extern void delay_invalid(); + +extern void delay_print_wire_loads(); diff --git a/sis/astg/si_com.c b/sis/astg/si_com.c new file mode 100644 index 0000000..34b94ee --- /dev/null +++ b/sis/astg/si_com.c @@ -0,0 +1,137 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/si_com.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "astg_int.h" +#include "astg_core.h" +#include "si_int.h" +#include "bwd_int.h" + +static char file[] = "/tmp/SISXXXXXX"; + +/* Given a state graph derived from the STG, synthesize a logic + * which is hazard-free under the unbounded gate delay model. + */ +int +com_astg_syn(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *new_net; + int c, skip_flow; + + g_debug = 0; + add_red = 1; + do_reduce = 1; + skip_flow = 0; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "mrv:x")) != EOF) { + switch (c) { + case 'm': + do_reduce = 0; + break; + case 'r': + add_red = 0; + break; + case 'v': + g_debug = atoi(util_optarg); + break; + case 'x': + skip_flow = 1; + break; + default: + goto usage; + } + } + + if (!skip_flow) { + /* perform token flow */ + if (com_execute(network, "_astg_flow")) { + return 1; + } + } + new_net = astg_min(*network); + + if (new_net == 0) { /* well, happens for some weird cases */ + return 0; + } + network_free(*network); + *network = new_net; + return 0; + + usage: + (void)fprintf(siserr, "usage: astg_syn [-m] [-r] [-v debug_level] [-x] \n"); + (void)fprintf(siserr, " -m : don't remove MIC/MOC-related hazards\n"); + (void)fprintf(siserr, " -r : don't add redundancy (run espresso)\n"); + (void)fprintf(siserr, " -v debug_level : print debug info\n"); + (void)fprintf(siserr, " -x : skip token flow and synthesize direclty\n"); + return 1; +} + +/* Print simple statistics of the given STG */ +int +com_astg_print_stat(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + astg_graph *stg; + astg_scode initial, enabled; + astg_state *state_p; + + stg = astg_current(*network); + if (stg == NIL(astg_graph)) return 1; + + (void)fprintf(sisout, "File Name = %s\n", stg->filename); + (void)fprintf(sisout, "Total Number of Signals = %d (I = %d/O = %d)\n", + stg->n_sig, stg->n_sig - stg->n_out, stg->n_out); + if (astg_initial_state(stg, &initial) != ASTG_OK) { + (void)fprintf(sisout, "Initial State = ?? (can't find live, safe initial marking\n"); + (void)fprintf(sisout, "Total Number of States = ??\n"); + return 1; + } + state_p = astg_find_state(stg, initial, /* don't create */ 0); + assert(state_p != NIL(astg_state)); + enabled = astg_state_enabled(state_p); + (void)fprintf(sisout, "Initial State = "); + print_state(stg, initial); + print_enabled(stg, initial, enabled); + if (astg_token_flow(stg, /* silent */ ASTG_FALSE) == ASTG_OK) { + (void)fprintf(sisout, "Total Number of States = %d\n", astg_state_count(stg)); + } else { + (void)fprintf(sisout, "Total Number of States = ?? (csc violation)\n"); + return 1; + } + return 0; +} + +/* Print the state graph */ +int +com_astg_print_sg(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + print_state_graph(astg_current(*network)); + return 0; +} + +/* global initialization routine */ +void +si_cmds() +{ + /* speed-independent commands */ + com_add_command ("astg_syn", com_astg_syn, 1); + com_add_command ("astg_print_sg", com_astg_print_sg, 0); + com_add_command ("astg_print_stat", com_astg_print_stat, 0); +} +#endif /* SIS */ diff --git a/sis/astg/si_encode.c b/sis/astg/si_encode.c new file mode 100644 index 0000000..88ef424 --- /dev/null +++ b/sis/astg/si_encode.c @@ -0,0 +1,398 @@ +#ifdef SIS +#include "sis.h" +#include "astg_int.h" +#include "si_int.h" +#include + +#define ZERO_CODE "0" +#define ONE_CODE "1" + +static network_t *stg_to_net(); +static int extract_and_solve_cons(); +static void encode_stg(); + +static char file[] = "/tmp/SISXXXXXX"; + +/* Tracey's single transition time (STT) state assignment algorithm */ +network_t * +astg_encode(stg, astg, heuristic) +graph_t *stg; +astg_graph *astg; +int heuristic; +{ + network_t *network; + int initial; + lsGen gen; + vertex_t *state; + FILE *fp; + + if (stg == NIL(graph_t)) { + return NIL(network_t); + } + + switch(stg_get_num_states(stg)) { + case 0: + fail("STG with no states?"); + /* NOTREACHED */ + break; + case 1: + break; + case 2: + initial = 1; + stg_foreach_state(stg, gen, state) { + if (initial) { + stg_set_state_encoding(state, ZERO_CODE); + initial = 0; + } else { + stg_set_state_encoding(state, ONE_CODE); + } + } + break; + default: + if (!extract_and_solve_cons(stg, heuristic)) return NIL(network_t); + break; + } + + return NIL(network_t); + /* return stg_to_net(stg, astg); */ +} + + +static void +dic_add (l1, l2, r1, r2, n, dic, list) +int l1, l2, r1, r2, n; +pset dic; +dic_family_t *list; +{ + set_clear (lhs_dic(dic), n); + if (l1 >= 0) { + set_insert (lhs_dic(dic), l1); + } + if (l2 >= 0) { + set_insert (lhs_dic(dic), l2); + } + + set_clear (rhs_dic(dic), n); + if (r1 >= 0) { + set_insert (rhs_dic(dic), r1); + } + if (r2 >= 0) { + set_insert (rhs_dic(dic), r2); + } + dic_family_add_irred(list, dic); +} + +/* extract dichotomoy constraints from an STG */ +static int +extract_and_solve_cons(stg, heuristic) +graph_t *stg; +int heuristic; +{ + edge_t *edge; + vertex_t *s_i, *s_j, *to_state, *from_state, *s_m, *s_k; + lsGen gen; + st_generator *sgen1, *sgen2, sgen3; + char *input_label; + int x, y, n, j, m, i, k; + st_table *input_label_table; /* hashed by edge labels */ + st_table *next_state_table; /* hashed by next state pointers */ + array_t *dic_array, *dic_array1; /* states with the same next states */ + st_table *index; + dic_family_t *seed_list, *dic_list, *prime_list; + pset dic; + sm_matrix *table; + sm_row *cover; + + index = st_init_table(st_ptrcmp, st_ptrhash); + x = 0; + stg_foreach_state(stg, gen, s_j) { + st_insert (index, (char *) s_j, (char *) x); + x++; + } + input_label_table = st_init_table(strcmp, st_strhash); + stg_foreach_transition(stg, gen, edge) { + input_label = stg_edge_input_string(edge); + to_state = stg_edge_to_state(edge); + from_state = stg_edge_from_state(edge); + if (!st_lookup(input_label_table, input_label, + (char**) &next_state_table)) { + + dic_array = array_alloc(vertex_t *, 0); + array_insert_last(vertex_t *, dic_array, from_state); + + next_state_table = st_init_table(st_ptrcmp, st_ptrhash); + assert (! st_insert(next_state_table, (char *) to_state, (char *) dic_array)); + + st_insert(input_label_table, input_label, (char*) next_state_table); + + } else { + if (! st_lookup(next_state_table, (char *) to_state, + (char**) &dic_array)) { + + dic_array = array_alloc(vertex_t *, 0); + array_insert_last(vertex_t *, dic_array, from_state); + assert(! st_insert(next_state_table, (char *) to_state, (char *) dic_array)); + + } else { + array_insert_last(vertex_t *, dic_array, from_state); + } + } + } + + /* fill out the seed data structure; terminology from Unger's book */ + n = stg_get_num_states(stg); + dic = dic_new(n); + seed_list = dic_family_alloc(ALLOCSIZE, n); + st_foreach_item(input_label_table, sgen1, &input_label, + (char**) &next_state_table) { + if (g_debug > 1) { + (void)fprintf(sisout, "input %s: ", input_label); + } + if (st_count (next_state_table) < 2) { + if (g_debug > 1) { + (void)fprintf(sisout, "skipped (only one entry)\n"); + } + continue; + } + st_foreach_item(next_state_table, sgen2, (char**) &s_j, + (char **) &dic_array) { + if (g_debug > 1) { + (void)fprintf(sisout, "[%s] ", stg_get_state_name(s_j)); + } + for (x = array_n(dic_array) - 1; x >= 0; x--) { + s_i = array_fetch(vertex_t *, dic_array, x); + if (g_debug > 1) { + (void)fprintf(sisout, "%s ", stg_get_state_name(s_i)); + } + } + st_lookup (index, (char *) s_j, (char **) &j); + sgen3 = *sgen2; + /* this ensures j != m */ + while (st_gen (sgen2, (char **) &s_m, (char **) &dic_array1)) { + st_lookup (index, (char *) s_m, (char **) &m); + for (x = array_n(dic_array) - 1; x >= 0; x--) { + s_i = array_fetch(vertex_t *, dic_array, x); + st_lookup (index, (char *) s_i, (char **) &i); + for (y = array_n(dic_array1) - 1; y >= 0; y--) { + s_k = array_fetch(vertex_t *, dic_array1, y); + st_lookup (index, (char *) s_k, (char **) &k); + /* now test i != j or k != m */ + if (i != j || k != m) { + /* [j, i; m] */ + dic_add (j, i, m, -1, n, dic, seed_list); + + /* [j, i; k] */ + dic_add (j, i, -1, k, n, dic, seed_list); + + /* [j; m, k] */ + dic_add (j, -1, m, k, n, dic, seed_list); + + /* [i; m, k] */ + dic_add (-1, i, m, k, n, dic, seed_list); + + /* [m, k; j] */ + dic_add (m, k, j, -1, n, dic, seed_list); + + /* [m, k; i] */ + dic_add (m, k, -1, i, n, dic, seed_list); + + /* [m; j, i] */ + dic_add (m, -1, j, i, n, dic, seed_list); + + /* [k; j, i] */ + dic_add (-1, k, j, i, n, dic, seed_list); + } + } + } + } + *sgen2 = sgen3; + array_free(dic_array); + if (g_debug > 1) { + (void)fprintf(sisout, ";"); + } + } + if (g_debug > 1) { + (void)fprintf(sisout, "\n"); + } + st_free_table(next_state_table); + } + dic_free(dic); + st_free_table(input_label_table); + if (g_debug > 2) { + (void)fprintf(sisout, "There are %d initial seeds\n", seed_list->dcount); + dic_family_print (seed_list); + } + + /* now solve them */ + dic_list = reduce_seeds(gen_uniq(seed_list)); + if (g_debug > 2) { + (void)fprintf(sisout, "There are %d reduced seeds\n", dic_list->dcount); + dic_family_print (dic_list); + } + + prime_list = gen_eqn(dic_list, LIMIT); + table = dic_to_sm(prime_list, dic_list); + cover = sm_minimum_cover(table, NIL(int), heuristic, 0); + if (g_debug > 2) { + print_min_cover(table, cover, prime_list); + } + + encode_stg(stg, cover, table, prime_list); + + (void) dic_family_free(seed_list); + (void) dic_family_free(dic_list); + (void) dic_family_free(prime_list); + sm_row_free(cover); + sm_free(table); + return 1; +} + +static void +encode_stg(stg, cover, table, prime_list) +graph_t *stg; +sm_row *cover; +sm_matrix *table; +dic_family_t *prime_list; +{ + int i, j, state_bits; + char **codes; + sm_element *elem; + sm_col *col; + pset p; + vertex_t *state; + lsGen gen; + int num_states = stg_get_num_states(stg); + + assert(prime_list->dset_elem == num_states); + + state_bits = 0; + sm_foreach_row_element(cover, elem) { + state_bits ++; + } + + codes = ALLOC(char *, num_states); + for (i = 0; i < num_states; i++) { + codes[i] = ALLOC(char, state_bits+1); + codes[i][state_bits] = '\0'; + } + + j = 0; + sm_foreach_row_element(cover, elem) { + col = sm_get_col(table, elem->col_num); + p = sm_get(pset, col); + for (i = 0; i < num_states; i++) { + codes[i][j] = is_in_set(p, i) ? '1' : '0'; + } + j++; + } + + i = 0; + stg_foreach_state(stg, gen, state) { + if (g_debug) (void)fprintf(sisout, "state %s = %s\n", + stg_get_state_name(state), codes[i]); + stg_set_state_encoding(state, codes[i]); + FREE(codes[i]); + i++; + } + FREE(codes); +} + + +/* map an encoded stg into an unminimized network */ +static network_t * +stg_to_net(stg, astg) +graph_t *stg; +astg_graph *astg; +{ + network_t *network; + FILE *fp; + + lsGen gen; + vertex_t *start; + edge_t *e; + astg_generator agen; + astg_signal *signal; + int i, state_bits; + char **state_vars = NIL(char*); + char buf[80]; + int sfd; + + sfd = mkstemp(file); + if (sfd == -1) { + (void)fprintf(siserr, "stg_to_net: can't create temporary file"); + return NIL(network_t); + } + fp = fdopen(sfd, "w+"); + unlink(file); + + if (fp == 0) { + (void)fprintf(siserr, "stg_to_net: can't open a temporary file"); + return NIL(network_t); + } + + start = stg_get_start(stg); + if (stg_get_state_encoding(start) == NIL(char)) { + if (stg_get_num_states(stg) != 1) return NIL(network_t); + state_bits = 0; + } else { + state_bits = strlen(stg_get_state_encoding(start)); + state_vars = ALLOC(char *, state_bits); + for (i = 0; i < state_bits; i++) { + (void)sprintf(buf, "_x%d", i); + state_vars[i] = util_strsav (buf); + } + } + (void) fprintf(fp, ".type fr\n"); + (void) fprintf(fp, ".i %d\n", stg_get_num_inputs(stg) + state_bits); + (void) fprintf(fp, ".o %d\n", stg_get_num_outputs(stg) + state_bits); + (void) fprintf(fp, ".ilb"); + if (astg != NIL(astg_graph)) { + astg_foreach_signal(astg, agen, signal) { + (void) fprintf(fp, " %s", astg_signal_name(signal)); + } + for (i = 0; i < state_bits; i++) { + (void) fprintf(fp, " %s", state_vars[i]); + } + (void) fprintf(fp, "\n.ob"); + for (i = 0; i < state_bits; i++) { + (void) fprintf(fp, " %s_out", state_vars[i]); + } + astg_foreach_signal(astg, agen, signal) { + if (astg_is_noninput(signal)) { + (void) fprintf(fp, " %s_out", astg_signal_name(signal)); + } + } + (void) fprintf(fp, "\n"); + } + + stg_foreach_transition(stg, gen, e) { + if (state_bits == 0) { + (void) fprintf(fp, "%s %s\n", stg_edge_input_string(e), + stg_edge_output_string(e)); + } else { + (void) fprintf(fp, "%s %s %s %s\n", stg_edge_input_string(e), + stg_get_state_encoding(stg_edge_from_state(e)), + stg_get_state_encoding(stg_edge_to_state(e)), + stg_edge_output_string(e)); + } + } + (void) fprintf(fp, ".e\n"); + fflush(fp); + rewind(fp); + + /* sis_read_pla needs this */ + read_register_filename(file); + network = sis_read_pla(fp, /* single output */ 1); + read_register_filename(NIL(char)); + + fclose(fp); + if (state_vars != NIL(char *)) { + for (i = 0 ; i < state_bits; i++) { + FREE(state_vars[i]); + } + FREE(state_vars); + } + return network; +} +#endif /* SIS */ + diff --git a/sis/astg/si_int.h b/sis/astg/si_int.h new file mode 100644 index 0000000..d440057 --- /dev/null +++ b/sis/astg/si_int.h @@ -0,0 +1,51 @@ +/* + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:58 $ +*/ +/* global variables */ +int g_debug; +int add_red; +int do_reduce; + +/* si_com_astg.c */ +extern int com_astg_minimize(); +extern int com_astg_decomp(); +extern int com_astg_analyze(); +extern int com_astg_verify(); +extern int com_astg_print_sg(); +extern int com_astg_print_stat(); +extern int com_astg_read_eqn(); + +/* si_min.c */ +extern network_t *astg_min(); + +/* si_3sim.c */ +#define SIM3_SLOT undef1 +#define GETVAL(n) ((int)((n)->SIM3_SLOT)) +#define SETVAL(n,v) ((n)->SIM3_SLOT = (char*) (v)) +#define EMPTY -1 +extern void ter_simulate(); +extern void ter_simulate_node(); +extern void ter_sim_print(); + +/* si_decomp.c */ +#define MAXSTR 512 +extern network_t *two_level_decomp(); +extern void hack_buf(); +extern void set_names(); +extern int feeds_po(); +extern node_t *get_latch_end(); +extern char *get_real_name(); +extern int is_latch(); + +/* si_verify.c */ +extern void stg_to_sr(); +extern void network_to_sr(); + +/* si_encode.c */ +extern network_t *astg_encode(); + +/* debug routines (si_min.c) */ +extern void print_state(); +extern void print_enabled(); +extern void print_state_graph(); diff --git a/sis/astg/si_min.c b/sis/astg/si_min.c new file mode 100644 index 0000000..02d2076 --- /dev/null +++ b/sis/astg/si_min.c @@ -0,0 +1,1015 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/astg/si_min.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:58 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "astg_int.h" +#include "astg_core.h" +#include "si_int.h" + +static void astg_do_min(); +static st_table *link_state_minterm(); +static pcube find_minterm(); +static void do_consensus(); +static void astg_do_reduce(); +static array_t *sort_states(); +static int possible_glitch(); +static int remove_glitch(); +static int compare_fanouts(); +static int perform_reduction(); +static int logic_hazard(); +static int cube_empty(); +static void fprint_cube(); +static int constant_one(); +static int fc_marking(); +static node_t *find_real_po(); +static void alloc_pipo_names(); +static void free_pipo_names(); +static void add_latch(); + +static array_t *real_pi_names, *real_po_names; + +#define STG_INLABEL(i) (array_fetch(char *, real_pi_names, (i))) +#define STG_OUTLABEL(i) (array_fetch(char *, real_po_names, (i))) + +typedef struct state_rec { + astg_scode state; + astg_scode enabled; /* set of enabled transitions */ + int num_fanouts; /* number of next states */ + int index; /* index in state_array */ +} state_rec; + +network_t * +astg_min(network) +network_t *network; +{ + network_t *new_net; + pPLA PLA; + + PLA = network_to_pla(network); + if (PLA == 0) return 0; + network_sweep(network); + alloc_pipo_names(network, PLA); + + if (PLA->R != 0) sf_free(PLA->R); + if (PLA->D != 0) { + PLA->R = complement(cube2list(PLA->F,PLA->D)); + } else { + PLA->D = new_cover(0); + PLA->R = complement(cube1list(PLA->F)); + } + + if (!add_red) { + so_espresso(PLA, 0); + } else { + astg_do_min(PLA, astg_current(network)); + } + + /* avoid hazards due to simultaneously changing signals */ + if (do_reduce) { + astg_do_reduce(PLA, astg_current(network)); + } + + new_net = pla_to_network_single(PLA); + new_net->stg = stg_dup(network->stg); + new_net->astg = network->astg; + network->astg = NIL(astg_t); + network_set_name(new_net, network_name(network)); + add_latch(network, new_net); + discard_pla(PLA); + free_pipo_names(); + return new_net; +} + +static void +alloc_pipo_names(network, PLA) +network_t *network; +pPLA PLA; +{ + node_t *node, *fake_pi, *real_po; + int i; + + if (g_debug) { + (void)fprintf(sisout, "PLA Input Names = "); + for (i = 0; i < NUMINPUTS; i++) (void)fprintf(sisout, "%s ", INLABEL(i)); + (void)fprintf(sisout, "\nPLA Output Names = "); + for (i = 0; i < NUMOUTPUTS; i++) (void)fprintf(sisout, "%s ", OUTLABEL(i)); + (void)fprintf(sisout, "\n"); + } + + real_pi_names = array_alloc(char *, NUMINPUTS); + for (i = NUMINPUTS - 1; i >= 0; i--) { + node = network_find_node(network, INLABEL(i)); + assert (node != NIL(node_t)); + if (network_is_real_pi(network, node)) { + array_insert(char *, real_pi_names, i, node->name); + } else { + real_po = find_real_po(node); + assert(real_po != NIL(node_t)); + array_insert(char *, real_pi_names, i, real_po->name); + } + } + + real_po_names = array_alloc(char *, NUMOUTPUTS); + for (i = NUMOUTPUTS - 1; i >= 0; i--) { + node = network_find_node(network, OUTLABEL(i)); + assert(node != NIL(node_t)); + if (network_is_real_po(network, node)) { + array_insert(char *, real_po_names, i, node->name); + } else { + fake_pi = network_latch_end(node); + assert (fake_pi != NIL(node_t)); + real_po = find_real_po(fake_pi); + assert(real_po != NIL(node_t)); + array_insert(char *, real_po_names, i, real_po->name); + /* also change the fake name to real PO name */ + FREE(OUTLABEL(i)); + OUTLABEL(i) = util_strsav(node_name(node_get_fanin(node, 0))); + } + } + + if (g_debug) { + (void)fprintf(sisout, "PLA Input Names = "); + for (i = 0; i < NUMINPUTS; i++) (void)fprintf(sisout, "%s ", INLABEL(i)); + (void)fprintf(sisout, "\nPLA Output Names = "); + for (i = 0; i < NUMOUTPUTS; i++) (void)fprintf(sisout, "%s ", OUTLABEL(i)); + (void)fprintf(sisout, "\n"); + } +} + +static void +free_pipo_names() +{ + array_free(real_pi_names); + array_free(real_po_names); +} + + +static void +add_latch(old, new) +network_t *old, *new; +{ + lsGen gen; + latch_t *latch_old, *latch_new; + node_t *in_old, *in_new, *out_old, *out_new; + node_t *node, *node2; + + foreach_latch(old, gen, latch_old) { + in_old = latch_get_input(latch_old); + in_new = network_find_node(new, in_old->name); + if (in_new == NIL(node_t)) { + in_new = network_find_node(new, node_name(node_get_fanin(in_old, 0))); + assert(in_new != NIL(node_t)); + } + out_old = latch_get_output(latch_old); + out_new = network_find_node(new, out_old->name); + assert(out_new != NIL(node_t)); + + if (node_num_fanout(out_new) == 1) { + node = node_get_fanout(out_new, 0); + if (node_type(node) == INTERNAL) { + node2 = node_get_fanout(node, 0); + assert(node_num_fanout(node) == 1 && node_type(node2) == PRIMARY_OUTPUT); + network_delete_node(new, node2); + } else { + assert(node_type(node) == PRIMARY_OUTPUT); + } + network_delete_node(new, node); + network_delete_node(new, out_new); + } else { + network_create_latch(new, &latch_new, in_new, out_new); + if (!network_is_real_po(new, in_new)) { + /* hack to preserve the fake PO name - is this needed? */ + network_swap_names(new, in_new, node_get_fanin(in_new, 0)); + } + latch_set_initial_value(latch_new, latch_get_initial_value(latch_old)); + latch_set_current_value(latch_new, latch_get_current_value(latch_old)); + latch_set_type(latch_new, latch_get_type(latch_old)); + } + } +} + + +static void +astg_do_min(PLA, stg) +pPLA PLA; +astg_graph *stg; +{ + pcover C, Fnew; + st_table *state_minterms; + pPLA PLA1; + int i; + + /* sanity check */ + C = cv_intersect(PLA->F, PLA->R); + if (C->count) fail("on-set and off-set are not disjoint\n"); + sf_free(C); + + /* associate each state with a minterm in the PLA */ + state_minterms = link_state_minterm(PLA, stg); + + /* insert necessary consensus cubes */ + do_consensus(PLA, stg, state_minterms); + + if (g_debug) { + (void)fprintf(sisout, "Before Expansion\n"); + cprint(PLA->F); + } + + /* code borrowed from cvrm.c in epsresso */ + /* loop for each output function */ + Fnew = new_cover(0); + for(i = 0; i < cube.part_size[cube.output]; i++) { + + /* cofactor on the output part */ + PLA1 = new_PLA(); + PLA1->F = cof_output(PLA->F, i + cube.first_part[cube.output]); + PLA1->R = cof_output(PLA->R, i + cube.first_part[cube.output]); + PLA1->D = cof_output(PLA->D, i + cube.first_part[cube.output]); + + /* eliminate cubes contained in other cubes */ + PLA1->F = sf_contain(PLA1->F); + + /* expand against offset */ + PLA1->F = expand(PLA1->F, PLA1->R, 0 /* expand every variable */); + + /* intersect with the particular output part again */ + PLA1->F = uncof_output(PLA1->F, i + cube.first_part[cube.output]); + + Fnew = sf_append(Fnew, PLA1->F); + PLA1->F = NULL; + free_PLA(PLA1); + } + + sf_free(PLA->F); + PLA->F = Fnew; + + if (g_debug) { + (void)fprintf(sisout, "After Expansion\n"); + cprint(PLA->F); + } + st_free_table(state_minterms); +} + +static st_table * +link_state_minterm(PLA, stg) +pPLA PLA; +astg_graph *stg; +{ + st_table *table; + astg_generator gen; + astg_state *state_p; + astg_scode state; + pcube c; + +/* assert(astg_state_count(stg) == (PLA->F->count + PLA->R->count)); */ + + table = st_init_table(st_numcmp, st_numhash); + astg_foreach_state(stg, gen, state_p) { + state = astg_state_code(state_p); + c = find_minterm(PLA, stg, state); + if (c != (pcube) 0) { + assert(!st_insert(table, (char*) state, (char*) c)); + } + } + if (g_debug > 1) { + astg_foreach_state(stg, gen, state_p) { + state = astg_state_code(state_p); + print_state(stg, state); + if (st_lookup(table, (char*) state, (char**) &c)) { + fprint_cube(c, PLA); + (void)fprintf(sisout, "\n"); + } else { + (void)fprintf(sisout, " offset minterm\n"); + } + } + } + return table; +} + +/* find a minterm in the PLA->F corresponding to the state 'state' */ +static pcube +find_minterm(PLA, stg, state) +pPLA PLA; +astg_graph *stg; +astg_scode state; +{ + pcube last, p, c; + register int i; + register astg_signal *s; + int val, match; + + c = NULL; + foreach_set(PLA->F, last, p) { + match = 1; + for (i = NUMINPUTS - 1; i >= 0; i--) { + s = astg_find_named_signal(stg, STG_INLABEL(i)); + assert(s != NIL(astg_signal)); + val = (s->state_bit & state)?1:0; + switch(GETINPUT(p, i)) { + case ZERO: + if (val) match = 0; + break; + case ONE: + if (!val) match = 0; + break; + default: + match = 0; +/* + fail("PLA should contain only minterms"); +*/ + break; + } + if (!match) break; + } + if (match) { + if (c == NULL) { + c = set_save(p); + } else { + for (i = cube.first_part[cube.output]; + i < cube.first_part[cube.output] + NUMOUTPUTS; i++) { + if (is_in_set(p, i)) set_insert(c, i); + } + } + } + } + return c; +} + +static void +do_consensus(PLA, stg, state_minterms) +pPLA PLA; +astg_graph *stg; +st_table *state_minterms; +{ + astg_generator gen, sgen; + astg_state *state_p; + astg_scode state, next_state, enabled; + pcube c, c1, c2; + astg_signal *s; + + astg_foreach_state(stg, gen, state_p) { + + state = astg_state_code(state_p); + enabled = astg_state_enabled(state_p); + + /* if this state belongs to any output onset, do the following */ + if (st_lookup(state_minterms, (char*) state, (char**) &c1)) { + + /* for each next state */ + astg_foreach_signal(stg, sgen, s) { + if (s->state_bit & enabled) { + next_state = state ^ s->state_bit; + if (st_lookup(state_minterms, (char*)next_state, (char**) &c2)) { + + /* distance of 1 between 2 state minterms means that there is at least one + * output which should stay at 1 during the state change + */ + if (cdist(c1, c2) == 1) { + c = new_cube(); + consensus(c, c1, c2); + PLA->F= sf_addset(PLA->F, c); + if (g_debug > 1) { + (void)fprintf(sisout, "#### Adding a cube "); + print_state(stg, state); + print_state(stg, next_state); + fprint_cube(c, PLA); + (void)fprintf(sisout, "\n"); + } + } + } + } + } /* end of for each next state */ + } + } +} + +static void +astg_do_reduce(PLA, stg) +pPLA PLA; +astg_graph *stg; +{ + array_t *state_array; + int i, index, reducing; + state_rec *state_info; + pcube c; + pcover F; + + if (stg == 0) return; + + /* sort states in decreasing order of number of fanout edges */ + state_array = sort_states(stg); + + F = sf_save(PLA->F); + do { + reducing = 0; + for (i = 0; i < array_n(state_array); i++) { + state_info = array_fetch(state_rec *, state_array, i); + foreachi_set (F, index, c) { + if (remove_glitch(index, c, state_info, state_array, stg, F, PLA)) { + reducing = 1; + } + } + } + } while (reducing); + free_cover(PLA->F); + PLA->F = F; + + for (i = 0; i < array_n(state_array); i++) { + state_info = array_fetch(state_rec *, state_array, i); + FREE(state_info); + } + array_free(state_array); +} + +/* try to remove a glitch by introducing a constant 0 literal */ +static int +remove_glitch(index, c, state_info, state_array, stg, F, PLA) +int index; /* cube index */ +pcube c; +state_rec *state_info; +array_t *state_array; +astg_graph *stg; +pcover F; +pPLA PLA; +{ + if (possible_glitch(c, state_info, stg, F, PLA)) { + if (perform_reduction(index, c, state_info, state_array, stg, F, PLA)) return 1; + } + return 0; +} + +static int +possible_glitch(c, state_info, stg, F, PLA) +pcube c; +state_rec *state_info; +astg_graph *stg; +pcover F; +pPLA PLA; +{ + astg_signal *signal; + int i, init_val, changing; + int rising, falling; + + rising = falling = 0; + + /* check if this cube can glitch */ + for (i = NUMINPUTS - 1; i >= 0; i--) { + signal = astg_find_named_signal(stg, STG_INLABEL(i)); + assert(signal != NIL(astg_signal)); + if (GETINPUT(c, i) == TWO) continue; + init_val = (signal->state_bit & state_info->state)?1:0; + changing = (signal->state_bit & state_info->enabled)?1:0; + if (GETINPUT(c, i) == ZERO) { + if (!changing && init_val == 1) return 0; + if (changing) { + if (init_val) rising++; + else falling++; + } + } else { + if (!changing && init_val == 0) return 0; + if (changing) { + if (init_val) falling++; + else rising++; + } + } + } + + if (rising && falling) { + if (g_debug) { + (void)fprintf(sisout, "glitching cube = "); + fprint_cube(c, PLA); + (void)fprintf(sisout, "\n"); + print_enabled(stg, state_info->state, state_info->enabled); + } + return (!constant_one(c, state_info, stg, F, PLA)); + } + return 0; +} + +/* check for the presence of constant 1 cube during the concurrent firing + * of all the enabled transitions */ +static int +constant_one(c, state_info, stg, F, PLA) +pcube c; +state_rec *state_info; +astg_graph *stg; +pcover F; +pPLA PLA; +{ + pcube c1, c2, p1, p2; + astg_signal *s; + int i; + pcube last, p; + int *const1; + int constant_1 = 1; + + const1 = ALLOC(int, NUMOUTPUTS); + for (i = NUMOUTPUTS - 1; i >= 0; i--) { + const1[i] = 0; + } + + c1 = new_cube(); + c2 = new_cube(); + p1 = new_cube(); + p2 = new_cube(); + + for (i = NUMINPUTS - 1; i >= 0; i--) { + s = astg_find_named_signal(stg, STG_INLABEL(i)); + assert(s != NIL(astg_signal)); + if (s->state_bit & state_info->state) { + PUTINPUT(c1, i, ONE); + if (s->state_bit & state_info->enabled) PUTINPUT(c2, i, ZERO); + else PUTINPUT(c2, i, ONE); + } else { + PUTINPUT(c1, i, ZERO); + if (s->state_bit & state_info->enabled) PUTINPUT(c2, i, ONE); + else PUTINPUT(c2, i, ZERO); + } + } + for (i = 0 ; i < NUMOUTPUTS; i++) { + set_insert(c1, cube.first_part[cube.output] + i); + set_insert(c2, cube.first_part[cube.output] + i); + } + if (g_debug) {(void)fprintf(sisout,"\t..> checking for constant 1 : c1 = (%s), c2 = (%s)\n", + pc1(c1), pc2(c2));} + foreach_set(F, last, p) { + (void) set_and(p1, p, c1); + (void) set_and(p2, p, c2); + for (i = NUMOUTPUTS - 1; i >= 0; i--) { + if (GETOUTPUT(c, i) && GETOUTPUT(p1, i) && GETOUTPUT(p2, i)) { + if (!cube_empty(p1) && !cube_empty(p2)) const1[i]++; + } + } + } + for (i = NUMOUTPUTS - 1; i >= 0; i--) { + if (GETOUTPUT(c, i)) { + constant_1 *= const1[i]; + } + } + FREE(const1); + free_cube(c1); + free_cube(c2); + free_cube(p1); + free_cube(p2); + if (constant_1) { + if (g_debug) (void)fprintf(sisout,"\t..> detected a constant 1 cube\n"); + return 1; + } + if (g_debug) (void)fprintf(sisout,"\t..< no constant 1 cube\n"); + return 0; +} + +static int +perform_reduction(index, c, state_info, state_array, stg, F, PLA) +int index; /* cube index */ +pcube c; +state_rec *state_info; +array_t *state_array; +astg_graph *stg; +pcover F; +pPLA PLA; +{ + pcube *FD, c1; + pcover F_old; + int i, j; + astg_signal *signal; + int *cost; /* cost of reducing each literal */ + state_rec *s; + int best_literal, best_cost; + + F_old = sf_save(PLA->F); + sf_delset(F_old, index); + FD = cube2list(F_old, PLA->D); + + cost = ALLOC(int, NUMINPUTS); + for (i = NUMINPUTS - 1; i >= 0; i--) { + signal = astg_find_named_signal(stg, STG_INLABEL(i)); + assert(signal != NIL(astg_signal)); + cost[i] = 0; + if (signal->state_bit & state_info->enabled || GETINPUT(c,i) != TWO) { + cost[i] = INFINITY; + continue; + } + /* try to reduce this literal */ + if (signal->state_bit & state_info->state) { + /* need to preserve the positive unateness of output */ + if (signal->sig_type != ASTG_INPUT_SIG) { + PUTINPUT(c, i, ZERO); + } else { + if (g_debug) (void)fprintf(sisout,"\t..>< invalid reduction because of neg output %s\n", signal->name); + cost[i] = INFINITY; + continue; + } + } else { + PUTINPUT(c, i, ONE); + } + if (g_debug){ + (void)fprintf(sisout, "\t..> trying reduced cube = "); + fprint_cube(c, PLA); + (void)fprintf(sisout, "\n"); + } + + /* check if the reduction is valid */ + c1 = set_save(c); + if (GETINPUT(c, i) == ONE) { + PUTINPUT(c1, i, ZERO); + } else { + PUTINPUT(c1, i, ONE); + } + if (cube_is_covered(FD, c1)) { + + /* check if this reduction doesn't undo the previous add_redundant step */ + if (logic_hazard(F, PLA, signal, stg)) { + cost[i] = INFINITY; + } else { + /* check how many additional conflicts this reduction can cause */ + for (j = array_n(state_array) - 1 ; j >= 0; j--) { + s = array_fetch(state_rec *, state_array, j); + if (j == state_info->index) continue; + if (possible_glitch(c, s, stg, F, PLA)) { + if (j < state_info->index) { + /* we processed this state already--can't go back */ + cost[i] = INFINITY; + break; + } else { + cost[i]++; + } + } + } + if (g_debug)(void)fprintf(sisout, "\t..< reduction is valid (%d additional glitches)\n", cost[i]); + } + } else { + if (g_debug){ + (void)fprintf(sisout,"\t..< invalid reduction because this cube is no longer covered : "); + fprint_cube(c1, PLA); + (void)fprintf(sisout, "\n"); + } + cost[i] = INFINITY; + } + free_cube(c1); + PUTINPUT(c, i, TWO); + } + + best_literal = -1; + best_cost = INFINITY; + for (i = NUMINPUTS - 1; i >= 0; i--) { + if (cost[i] < best_cost) { + best_literal = i; + best_cost = cost[i]; + } + } + + FREE(cost); + free_cover(F_old); + free_cubelist(FD); + + if (best_literal == -1) { + (void)fprintf(sisout,"warning: no valid reduction found for cube :"); + fprint_cube(c, PLA); + (void)fprintf(sisout,"\n\t"); + print_state(stg, state_info->state); + print_enabled(stg, state_info->state, state_info->enabled); + return 0; + } else { + signal = astg_find_named_signal(stg, STG_INLABEL(best_literal)); + if (signal->state_bit & state_info->state) { + PUTINPUT(c, best_literal, ZERO); + } else { + PUTINPUT(c, best_literal, ONE); + } + } + return 1; +} + +static array_t * +sort_states(stg) +astg_graph *stg; +{ + array_t *state_array; + astg_generator gen, _gen; + astg_signal *signal; + astg_state *state_p; + astg_scode state, enabled; + state_rec *s; + int num_fanouts; + array_t *fc_places; + astg_place *p; + astg_trans *t; + int i; + + /* mark all the free choice places */ + if (astg_is_marked_graph(stg)) { + fc_places = NIL(array_t); + } else { + fc_places = array_alloc(astg_place *, 0); + astg_foreach_place(stg, gen, p) { + i = 0; + astg_foreach_output_trans(p, _gen, t) { + i++; + } + if (i > 1) array_insert_last(astg_place *, fc_places, p); + } + } + if (g_debug) (void)fprintf(sisout, "## %d free-choice places found\n", (fc_places!=0)?array_n(fc_places):0); + + state_array = array_alloc(state_rec *, 0); + + astg_foreach_state(stg, gen, state_p) { + state = astg_state_code(state_p); + enabled = astg_state_enabled(state_p); + num_fanouts = 0; + astg_foreach_signal(stg, _gen, signal) { + if (enabled & signal->state_bit) num_fanouts++; + } + if (num_fanouts > 1) { + /* check if this marking involves a free-choice place */ + if ( !fc_marking(state_p, fc_places)) { + s = ALLOC(state_rec, 1); + s->state = state; + s->enabled = enabled; + s->num_fanouts = num_fanouts; + array_insert_last(state_rec *, state_array, s); + } + } + } + + array_sort(state_array, compare_fanouts); + for (i = array_n(state_array) - 1; i >= 0; i--) { + s = array_fetch(state_rec *, state_array, i); + s->index = i; + } + if (g_debug > 1) { + int i; + for (i = 0; i < array_n(state_array); i++) { + s = array_fetch(state_rec *, state_array, i); + print_state(stg, s->state); + print_enabled(stg, s->state, s->enabled); + (void)fprintf(sisout, "\t(%d)\n", s->num_fanouts); + } + } + + if (fc_places != NIL(array_t)) array_free(fc_places); + return state_array; +} + +/* place states with high fanouts near the beginning */ +static int +compare_fanouts(s1, s2) +char *s1, *s2; +{ + int diff; + state_rec *r1 = *(state_rec **) s1; + state_rec *r2 = *(state_rec **) s2; + + assert(r1 != 0 && r2 != 0); + diff = r1->num_fanouts - r2->num_fanouts; + if (diff > 0) return -1; + if (diff < 0) return 1; + return 0; +} + +/* check if this state marking involves any of the free-choice places */ +static int +fc_marking(state_p, fc_places) +astg_state *state_p; +array_t *fc_places; +{ + astg_generator gen; + astg_marking *marking; + int i; + astg_place *p; + + if (fc_places == NIL(array_t)) return 0; + astg_foreach_marking(state_p, gen, marking) { + for (i = array_n(fc_places) - 1; i >= 0; i--) { + p = array_fetch(astg_place *, fc_places, i); + if (astg_get_marked(marking, p)) return 1; + } + } + return 0; +} + +/* check if there is a logic hazard in cover F due to the firing of + * this signal 'signal' + */ +static int +logic_hazard(F, PLA, signal, stg) +pcover F; +pPLA PLA; +astg_signal *signal; +astg_graph *stg; +{ + register int i; + astg_scode state, enabled; + astg_generator gen; + astg_state *state_p; + astg_signal *s; + pcube c1, c2, p1, p2, p, last; + int *rising, *falling, *const1; + int p1_zero, p2_zero, hazard; + + rising = ALLOC(int, NUMOUTPUTS); + falling = ALLOC(int, NUMOUTPUTS); + const1 = ALLOC(int, NUMOUTPUTS); + c1 = new_cube(); + c2 = new_cube(); + p1 = new_cube(); + p2 = new_cube(); + hazard = 0; + + astg_foreach_state(stg, gen, state_p) { + state = astg_state_code(state_p); + enabled = astg_state_enabled(state_p); + + if (signal->state_bit & enabled) { + if (g_debug) { + (void)fprintf(sisout,"\t....>> checking for logic hazard : "); + print_state(stg, state); + (void)fprintf(sisout,"\t"); + print_enabled(stg, state, enabled); + } + for (i = NUMINPUTS - 1; i >= 0; i--) { + s = astg_find_named_signal(stg, STG_INLABEL(i)); + assert(s != NIL(astg_signal)); + if (s->state_bit & state) { + PUTINPUT(c1, i, ONE); + if (s != signal) PUTINPUT(c2, i, ONE); + else PUTINPUT(c2, i, ZERO); + } else { + PUTINPUT(c1, i, ZERO); + if (s != signal) PUTINPUT(c2, i, ZERO); + else PUTINPUT(c2, i, ONE); + } + } + for (i = 0 ; i < NUMOUTPUTS; i++) { + set_insert(c1, cube.first_part[cube.output] + i); + set_insert(c2, cube.first_part[cube.output] + i); + } + if (g_debug) {(void)fprintf(sisout,"\t....>> c1 = (%s), c2 = (%s) [changing signal = %s]\n", + pc1(c1), pc2(c2), signal->name);} + for (i = NUMOUTPUTS - 1; i >= 0; i--) { + rising[i] = falling[i] = const1[i] = 0; + } + foreach_set(F, last, p) { + (void) set_and(p1, p, c1); + (void) set_and(p2, p, c2); + for (i = NUMOUTPUTS - 1; i >= 0; i--) { + if (GETOUTPUT(p1, i) && GETOUTPUT(p2, i)) { + p1_zero = cube_empty(p1); + p2_zero = cube_empty(p2); + if (p1_zero && !p2_zero) rising[i]++; + if (!p1_zero && p2_zero) falling[i]++; + if (!p1_zero && !p2_zero) const1[i]++; + } + } + } + for (i = NUMOUTPUTS - 1; i >= 0; i--) { + if (rising[i] && falling[i] && !const1[i]) { + if (g_debug) (void)fprintf(sisout,"\t....<< found logic hazard in %s (r=%d,f=%d,1=%d)\n", + STG_OUTLABEL(i), rising[i], falling[i], const1[i]); + hazard = 1; + break; + } + } + if (hazard) { + goto hazard_end; + } + if (g_debug) (void)fprintf(sisout,"\t....<< no logic hazard in %s\n", STG_OUTLABEL(i)); + } + } + + hazard_end: + FREE(rising); + FREE(falling); + FREE(const1); + free_cube(c1); + free_cube(c2); + free_cube(p1); + free_cube(p2); + if (hazard) return 1; + return 0; +} + +/* should be in espresso.h ? */ +static int +cube_empty(c) +pcube c; +{ + register int i; + + for (i = NUMINPUTS - 1; i >= 0; i--) { + if (GETINPUT(c, i) == 0) return 1; + } + return 0; +} + +/* find a PO fanned out by this node */ +static node_t * +find_real_po(node) +node_t *node; +{ + lsGen gen; + node_t *fanout, *real_po; + + real_po = NIL(node_t); + foreach_fanout(node, gen, fanout) { + if (node_type(fanout) == PRIMARY_OUTPUT) { + assert(real_po == NIL(node_t)); /* assumes that there's a single PO */ + real_po = fanout; + } + } + return real_po; +} + +/* --- debug routines --- */ +/* print present state */ +void +print_state(stg, state) +astg_graph *stg; +astg_scode state; +{ + astg_signal *s; + astg_generator agen; + + (void)fprintf(sisout, "state %d : (", state); + astg_foreach_signal(stg, agen, s) { + (void)fprintf(sisout,"%s=%d ", s->name, (s->state_bit & state)?1:0); + } + (void)fprintf(sisout, ")\n"); +} + +/* print the set of enabled transitions in the present state */ +void +print_enabled(stg, state, enabled) +astg_graph *stg; +astg_scode state; +astg_scode enabled; +{ + astg_signal *s; + astg_generator agen; + + (void)fprintf(sisout, "\tenabled transitions : ["); + astg_foreach_signal(stg, agen, s) { + if (s->state_bit & enabled) { + (void)fprintf(sisout,"%s%s ", s->name, (s->state_bit & state)?"-":"+"); + } + } + (void)fprintf(sisout, "]\n"); +} + +void +print_state_graph(stg) +astg_graph *stg; +{ + astg_scode state, enabled; + astg_generator gen; + astg_state *state_p; + + if (stg == NIL(astg_graph)) return; + if (astg_token_flow (stg, /* print error messages */ ASTG_TRUE) == ASTG_OK) { + (void)fprintf(sisout, "STATE GRAPH\n"); + astg_foreach_state(stg, gen, state_p) { + state = astg_state_code(state_p); + enabled = astg_state_enabled(state_p); + print_state(stg, state); + print_enabled(stg, state, enabled); + } + (void)fprintf(sisout, "\n"); + } +} + +static void +fprint_cube(c, PLA) +pcube c; +pPLA PLA; +{ + int i; + + for (i = NUMINPUTS - 1; i >= 0; i--) { + switch(GETINPUT(c,i)) { + case TWO: break; + case ONE: (void)fprintf(sisout,"%s ",STG_INLABEL(i)); + break; + case ZERO: (void)fprintf(sisout,"!%s ", STG_INLABEL(i)); + break; + case 0: (void)fprintf(sisout, "?%s ", STG_INLABEL(i)); + break; + default: + break; + } + } + (void)fprintf(sisout,"|| "); + for (i = NUMOUTPUTS - 1; i >= 0; i--) { + if (GETOUTPUT(c,i)) { + (void)fprintf(sisout, "%s ", STG_OUTLABEL(i)); + } + } +} +#endif /* SIS */ diff --git a/sis/atpg/Makefile.am b/sis/atpg/Makefile.am new file mode 100644 index 0000000..fcdffaf --- /dev/null +++ b/sis/atpg/Makefile.am @@ -0,0 +1,10 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libatpg.a +libatpg_a_SOURCES = atpg_clauses.c atpg_comb.c atpg_faults.c \ + atpg_faultsim.c atpg_gen_test.c atpg_init.c atpg_seq.c atpg_seq_util.c \ + atpg_util.c com_atpg.c com_redund.c com_short_t.c fast_avl.c sat.c \ + atpg_int.h fast_avl.h sat_int.h +pkginclude_HEADERS = atpg.h sat.h +dist_doc_DATA = atpg.doc diff --git a/sis/atpg/Makefile.in b/sis/atpg/Makefile.in new file mode 100644 index 0000000..04f19ea --- /dev/null +++ b/sis/atpg/Makefile.in @@ -0,0 +1,427 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libatpg_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/atpg +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libatpg_a_AR = $(AR) $(ARFLAGS) +libatpg_a_LIBADD = +am_libatpg_a_OBJECTS = atpg_clauses.$(OBJEXT) atpg_comb.$(OBJEXT) \ + atpg_faults.$(OBJEXT) atpg_faultsim.$(OBJEXT) \ + atpg_gen_test.$(OBJEXT) atpg_init.$(OBJEXT) atpg_seq.$(OBJEXT) \ + atpg_seq_util.$(OBJEXT) atpg_util.$(OBJEXT) com_atpg.$(OBJEXT) \ + com_redund.$(OBJEXT) com_short_t.$(OBJEXT) fast_avl.$(OBJEXT) \ + sat.$(OBJEXT) +libatpg_a_OBJECTS = $(am_libatpg_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libatpg_a_SOURCES) +DIST_SOURCES = $(libatpg_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libatpg.a +libatpg_a_SOURCES = atpg_clauses.c atpg_comb.c atpg_faults.c \ + atpg_faultsim.c atpg_gen_test.c atpg_init.c atpg_seq.c atpg_seq_util.c \ + atpg_util.c com_atpg.c com_redund.c com_short_t.c fast_avl.c sat.c \ + atpg_int.h fast_avl.h sat_int.h + +pkginclude_HEADERS = atpg.h sat.h +dist_doc_DATA = atpg.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/atpg/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/atpg/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libatpg.a: $(libatpg_a_OBJECTS) $(libatpg_a_DEPENDENCIES) + -rm -f libatpg.a + $(libatpg_a_AR) libatpg.a $(libatpg_a_OBJECTS) $(libatpg_a_LIBADD) + $(RANLIB) libatpg.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/atpg/atpg.doc b/sis/atpg/atpg.doc new file mode 100644 index 0000000..e6f2eb0 --- /dev/null +++ b/sis/atpg/atpg.doc @@ -0,0 +1,39 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +int +com_atpg(network, argc, argv) +network_t **network; +int argc; +char **argv; + + Perform deterministic test pattern generation on a sequential or + combinational network. Network is modified if the -t option is used. + +int +com_redundancy_removal(network, argc, argv) +network_t **network; +int argc; +char **argv; + + Perform sequential redundancy removal on a sequential or combinational + network using deterministic test pattern generation on network. + Network is modified. The network is 100% single stuck-fault testable + unless the test generator aborts on any faults. + +int +com_short_tests(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ +} + Perform deterministic test pattern generation on a sequential network. + Several heuristics are used during the test pattern generation process + to reduce the size of the test set that is generated. diff --git a/sis/atpg/atpg.h b/sis/atpg/atpg.h new file mode 100644 index 0000000..5df2929 --- /dev/null +++ b/sis/atpg/atpg.h @@ -0,0 +1,384 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +#include "sat.h" + +typedef enum stuck_value_enum stuck_value_t; +enum stuck_value_enum { + S_A_0, S_A_1 +}; + +typedef enum fault_status_enum fault_status_t; +enum fault_status_enum { + REDUNDANT, ABORTED, TESTED, UNTESTED +}; + +typedef enum redund_type_enum redund_type_t; +enum redund_type_enum { + CONTROL, OBSERVE +}; + +typedef struct { + node_t *node; + int index; +} node_index_t; + +typedef struct { + array_t *vectors; + int n_covers; + int index; +} sequence_t; + +typedef struct fault_struct fault_t; +struct fault_struct { + node_t *node; /* node on which fault occurs */ + node_t *fanin; /* input connection, NIL if output */ + int index; /* index of fanin for input fault */ + bool is_covered; /* initially 0; set to 1 if covered */ + stuck_value_t value; + fault_status_t status; + redund_type_t redund_type; /* Used in redundancy removal. + CONTROL: fault cannot be excited + (SNE fault) + OBSERVE: fault can be excited, but + effect cannot be observed + at a primary output (ND fault) + Removing a CONTROL redundancy does not change + reachable states or output functions. + Removing an OBSERVE redundancy may change + reachable states and output functions */ + sequence_t *sequence; /* which sequence covers fault */ + int sequence_index; /* which sequence detects fault, + * when using parallel sequence simulation */ + unsigned *current_state; /* saves 32 states in parallel for use in + * parallel pattern simulation */ +}; + +typedef struct fault_pattern_struct fault_pattern_t; +struct fault_pattern_struct { + node_t *node; + node_t *fanin; + unsigned value; +}; + +typedef void (*VoidFN)(); + +/* simulation data structures */ +typedef struct atpg_sim_node_struct atpg_sim_node_t; +struct atpg_sim_node_struct { + node_t *node; + int nfanout; + int *fanout; + int uid; + node_function_t type; + unsigned value; + unsigned *or_input_masks; + unsigned *and_input_masks; + unsigned or_output_mask; + unsigned and_output_mask; + VoidFN eval; + int n_inputs; + unsigned **fanin_values; + int n_cubes; + int **function; /* function[cube][input] is 0, 1, 2 */ + unsigned **inputs; /* inputs[0] is negative, + inputs[1] is inputs, + input[2] is 0xffffffff */ + int visited; +}; + +typedef struct { + bool quick_redund; + bool reverse_fault_sim; + bool use_internal_states; + bool PMT_only; + int n_sim_sequences; + bool deterministic_prop; + bool random_prop; + int rtg_depth; + int prop_rtg_depth; + int n_random_prop_iter; + bool fault_simulate; + bool fast_sat; + bool rtg; + bool build_product_machines; + bool tech_decomp; + int timeout; + int verbosity; + bool print_sequences; + char *real_filename; + FILE *fp; + bool force_comb; +} atpg_options_t; + +typedef struct { + long setup; + long traverse_stg; + long RTG; + long SAT_clauses; + long SAT_solve; + long justify; + long ff_propagate; + long random_propagate; + long fault_simulate; + long product_machine_verify; + long reverse_fault_sim; + long total_time; +} time_info_t; + +typedef struct { + int initial_faults; + int stg_depth; + int n_RTG_tested; + int sat_red; + int verified_red; + int n_random_propagated; + int n_not_ff_propagated; + int n_ff_propagated; + int n_just_reused; + int n_prop_reused; + int n_random_propagations; + int n_det_propagations; + int n_untested_by_main_loop; + int n_verifications; + int n_vectors; + int n_sequences; +} statistics_t; + +typedef struct { + bool seq; /* false if the circuit has no latches */ + atpg_options_t *atpg_opt; /* all user options */ + time_info_t *time_info; /* stores stats about execution time */ + statistics_t *statistics; /* stores execution statistics */ + lsList faults; /* fault list */ + lsList tested_faults; + lsList redundant_faults; + lsList untested_faults; + lsList final_untested_faults; + st_table *sequence_table; /* test sequences */ + st_table *redund_table; + st_table *control_node_table; + int n_pi; + int n_po; + int n_real_pi; + int n_real_po; + int n_latch; + network_t *network; +} atpg_info_t; + +typedef struct { + int n_nodes; + int n_pi; + int n_po; + int n_real_pi; + int n_real_po; + int n_latch; + network_t *network; + sat_t *atpg_sat; /* sat structure */ + array_t *sat_input_vars; /* pi's used in sat call */ + atpg_sim_node_t *sim_nodes; /* simulation nodes */ + st_table *pi_po_table; /* pi-po reference index */ + int *pi_uid; /* uid for pi's */ + int *po_uid; /* uid for po's */ + unsigned *reset_state; /* reset state used in faultsim */ + array_t *word_vectors; /* tmp space - faultsim */ + array_t *prop_word_vectors; /* tmp space for random propagation - + faultsim */ + unsigned *real_po_values; /* tmp space - faultsim */ + unsigned *true_value; /* tmp space - faultsim */ + unsigned *true_state; /* tmp space - faultsim */ + unsigned *faulty_state; /* tmp space - faultsim */ + unsigned *all_true_value; /* tmp space - faultsim */ + unsigned *all_po_values; /* tmp space - faultsim */ + int *used; /* tmp space - faultsim */ + sequence_t **alloc_sequences; /* tmp space - faultsim */ + fault_t **faults_ptr; /* tmp space - faultsim */ + int *changed_node_indices; /* tmp space - faultsim */ + int *tfo; +} atpg_ss_info_t; + +typedef struct { + bool product_machine_built; + verif_options_t *seq_opt; + verif_options_t *seq_product_opt; + range_data_t *range_data; + range_data_t *product_range_data; + network_t *network_copy; + network_t *product_network; + bdd_t *start_states; /* for short_tests */ + bdd_t *product_start_states; /* for short_tests */ + bdd_t *start_state_used; /* for short_tests */ + array_t *latch_to_pi_ordering; /* used in short_tests */ + array_t *latch_to_product_pi_ordering; /* used in short_tests */ + array_t *orig_external_outputs; + array_t *orig_transition_outputs; + array_t *reached_sets; + array_t *product_reached_sets; + st_table *state_sequence_table; /* for short_tests */ + st_table *just_sequence_table; + st_table *prop_sequence_table; + array_t *just_sequence; /* tmp space - justification */ + array_t *input_trace; /* tmp space - justification */ + array_t *prop_sequence; /* tmp space - propagation */ + array_t *real_pi_bdds; /* used in justification */ + st_table *var_table; /* used in justification */ + array_t *input_vars; /* used in justification */ + array_t *product_real_pi_bdds; /* used in PMT */ + st_table *product_var_table; /* used in PMT */ + array_t *product_input_vars; /* used in PMT */ + bdd_t *justified_states; + array_t *good_state; + array_t *faulty_state; + network_t *valid_states_network; +} seq_info_t; + +/* com_atpg.c */ +extern int com_atpg(); + +/* com_short_tests.c */ +extern int com_short_tests(); + +/* com_redund.c */ +extern int com_redundancy_removal(); +extern int st_fpcmp(); +extern int st_fphash(); + +/* atpg_clauses.c */ +extern int atpg_network_fault_clauses(); +extern void atpg_node_clause(); +extern void atpg_setup_clause_info(); +extern void atpg_clause_info_free(); +extern void atpg_sat_clause_begin(); +extern void atpg_sat_clause_end(); + +/* atpg_util.c */ +extern bool bdd_is_cube(); +extern double tmg_compute_optimal_clock(); +extern void concat_lists(); +extern void create_just_sequence(); +extern void atpg_print_fault(); +extern void atpg_print_vectors(); +extern void atpg_print_some_vectors(); +extern void atpg_print_bdd(); +extern void atpg_print_results(); +extern void atpg_derive_excitation_vector(); +extern int *fanin_dfs_sort(); +extern node_t **sat_fanout_dfs_sort(); +extern sequence_t *derive_test_sequence(); +extern void reset_word_vectors(); +extern void lengthen_word_vectors(); +extern void fillin_word_vectors(); + +/* atpg_faults.c */ +extern void atpg_gen_faults(); +extern void atpg_gen_node_faults(); +extern fault_t *new_fault(); +extern void free_fault(); + +/* atpg_faultsim.c */ +extern lsList atpg_seq_single_fault_simulate(); +extern lsList atpg_random_cover(); +extern int random_propagate(); +extern void fault_simulate(); +extern void atpg_simulate_pattern_fault(); +extern int get_min_just_sequence(); +extern void simulate_entire_sequence(); +extern bool atpg_verify_test(); +extern lsList seq_single_sequence_simulate(); +extern void fault_simulate_to_get_final_state(); +extern void atpg_simulate_old_sequences(); +extern void extract_test_sequences(); +extern void reverse_fault_simulate(); +extern void atpg_sf_set_sim_masks(); +extern void atpg_sf_reset_sim_masks(); +extern void atpg_set_sim_masks(); +extern void atpg_reset_sim_masks(); +extern void extract_sequences(); + +/* atpg_init.c */ +extern int set_atpg_options(); +extern atpg_info_t *atpg_info_init(); +extern atpg_ss_info_t *atpg_sim_sat_info_init(); +extern seq_info_t *atpg_seq_info_init(); +extern void atpg_setup_seq_info(); +extern void atpg_product_setup_seq_info(); +extern void atpg_sim_setup(); +extern void atpg_comb_sim_setup(); +extern void atpg_exdc_sim_link(); +extern void atpg_sat_init(); +extern void atpg_sat_node_info_setup(); +extern void print_and_destroy_sequences(); +extern void atpg_sim_unsetup(); +extern void atpg_comb_sim_unsetup(); +extern void atpg_sim_free(); +extern void atpg_sat_free(); +extern void seq_info_free(); +extern void seq_info_product_free(); +extern void atpg_free_info(); + +/* atpg_generate_test.c */ +extern sequence_t *generate_test(); +extern sequence_t *generate_test_using_verification(); + +/* atpg_seq.c */ +extern void seq_setup(); +extern void seq_product_setup(); +extern void copy_orig_bdds(); +extern void record_reset_state(); +extern void construct_product_start_states(); +extern bool calculate_reachable_states(); +extern bdd_t *seq_derive_excitation_states(); +extern int seq_reuse_just_sequence(); +extern int seq_state_justify(); +extern int internal_states_seq_state_justify(); +extern int seq_reuse_prop_sequence(); +extern int seq_fault_free_propagate(); +extern int traverse_product_machine(); +extern int good_faulty_PMT(); + +/* atpg_seq_util.c */ +extern void free_bdds_in_array(); +extern network_t *convert_bdd_to_network(); +extern int convert_bdd_to_int(); +extern int convert_product_bdd_to_key(); +extern bdd_t *convert_state_to_bdd(); +extern st_table *get_pi_to_var_table(); +extern bdd_t *seq_get_one_minterm(); +extern bdd_t *find_good_constraint(); +extern void use_cofactored_set(); +extern void bdd_add_varids_to_table(); +extern bdd_t *convert_states_to_product_bdd(); +extern int derive_prop_key(); +extern int derive_inverted_prop_key(); + +/* atpg_comb.c */ +extern sequence_t *derive_comb_test(); +extern lsList atpg_comb_single_fault_simulate(); +extern void atpg_comb_simulate_old_sequences(); + +typedef struct { + int true_id; + int fault_id; + int active_id; + int current_id; /* either true_id, fault_id */ + int *fanin; + node_t **fanout; + int nfanin; + int nfanout; + int order; + int visited; + int tmp; +} atpg_clause_t; + +#define ATPG_CLAUSE_GET(node) ((atpg_clause_t *) node->atpg) +#define ATPG_CLAUSE_SET(node, id) node->atpg = (char *) id +#define ATPG_GET_VARIABLE(n) (ATPG_CLAUSE_GET(n)->current_id) + +#define GET_ATPG_ID(node) ((int) node->simulation) +#define SET_ATPG_ID(node, id) node->simulation = (char *) id diff --git a/sis/atpg/atpg_clauses.c b/sis/atpg/atpg_clauses.c new file mode 100644 index 0000000..46e9da3 --- /dev/null +++ b/sis/atpg/atpg_clauses.c @@ -0,0 +1,456 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg_clauses.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +#include "sis.h" +#include "atpg_int.h" + +static int *c_sum_literals = NIL(int); +static int *c_cube_literals = NIL(int); +static int c_max_cubes = 0; +static int c_max_fanin = 0; + +static void add_sum (); +static void atpg_sop_clauses(); +static void fault_path_outputs(); +static void tfanin_cone(); +static void exdc_tfanin_cone(); +static void atpg_gen_fault_clauses(); +static void atpg_gen_fault_site(); +static void atpg_gen_active_clauses(); + +static void +add_sum(sat_prob, literals, nlits, out_var) +sat_t *sat_prob; +int *literals; +int nlits; +int out_var; +{ + int i; + + for (i = nlits; i --; ) { + sat_add_2clause(sat_prob, sat_neg(literals[i]), out_var); + } + switch (nlits) { + case 0: sat_add_1clause(sat_prob, sat_neg(out_var)); + break; + case 1: sat_add_2clause(sat_prob, literals[0], sat_neg(out_var)); + break; + default: + sat_begin_clause(sat_prob); + for (i = 0; i < nlits; i ++) { + sat_add_literal(sat_prob, literals[i]); + } + sat_add_literal(sat_prob, sat_neg(out_var)); + } + +} + +/* gates of fanin > 1 */ +static void +atpg_sop_clauses(sat_prob, node, output_var) +sat_t *sat_prob; +node_t *node; +int output_var; +{ + int lit; + atpg_clause_t *node_info; + int n_cubes, n_lit, value, i, j, index; + node_cube_t cube; + node_t *fanin; + + n_cubes = node_num_cube(node); + if (n_cubes > c_max_cubes) { + c_max_cubes = n_cubes; + c_sum_literals = REALLOC(int, c_sum_literals, c_max_cubes); + } + i = node_num_fanin(node); + if (i > c_max_fanin) { + c_max_fanin = i; + c_cube_literals = REALLOC(int, c_cube_literals, c_max_fanin); + } + node_info = ATPG_CLAUSE_GET(node); + for (i = n_cubes; i --; ) { + cube = node_get_cube(node, i); + n_lit = 0; + for (j = 0; j < node_info->nfanin; j ++) { + index = node_info->fanin[j]; + fanin = node_get_fanin(node, index); + value = node_get_literal(cube, index); + if (value == ZERO) { + c_cube_literals[n_lit ++] = ATPG_GET_VARIABLE(fanin); + } + else if (value == ONE) { + c_cube_literals[n_lit ++] = sat_neg(ATPG_GET_VARIABLE(fanin)); + } + } + + if (n_lit == 1) { + c_sum_literals[i] = sat_neg(c_cube_literals[0]); + } + else { + lit = (n_cubes == 1) ? + output_var : sat_new_variable(sat_prob); + c_sum_literals[i] = lit; + add_sum(sat_prob, c_cube_literals, n_lit, sat_neg(lit)); + } + } + + if (n_cubes > 1) { + add_sum(sat_prob, c_sum_literals, n_cubes, output_var); + } +} + +void +atpg_node_clause(node, sat_prob) +node_t *node; +sat_t *sat_prob; +{ + int in_var, out_var; + + switch (node_function(node)) { + case NODE_0: + sat_add_1clause(sat_prob, sat_neg(ATPG_GET_VARIABLE(node))); + break; + case NODE_1: + sat_add_1clause(sat_prob, ATPG_GET_VARIABLE(node)); + break; + case NODE_PI: + break; + case NODE_PO: + case NODE_BUF: + in_var = ATPG_GET_VARIABLE(node_get_fanin(node, 0)); + out_var = ATPG_GET_VARIABLE(node); + sat_add_2clause(sat_prob, in_var, sat_neg(out_var)); + sat_add_2clause(sat_prob, sat_neg(in_var), out_var); + break; + case NODE_INV: + in_var = ATPG_GET_VARIABLE(node_get_fanin(node, 0)); + out_var = ATPG_GET_VARIABLE(node); + sat_add_2clause(sat_prob, in_var, out_var); + sat_add_2clause(sat_prob, sat_neg(in_var), sat_neg(out_var)); + break; + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + atpg_sop_clauses(sat_prob, node, ATPG_GET_VARIABLE(node)); + break; + default: + fail ("illegal node function"); + } +} + +static void +fault_path_outputs(node, fault_tfo, cone_heads) +node_t *node; +array_t *fault_tfo; +array_t *cone_heads; +{ + atpg_clause_t *node_info; + int i; + + node_info = ATPG_CLAUSE_GET(node); + if (! node_info->visited) { + node_info->visited = TRUE; + for (i = 0; i < node_info->nfanout; i ++) { + fault_path_outputs(node_info->fanout[i], fault_tfo, cone_heads); + } + array_insert_last(node_t *, fault_tfo, node); + /* boths PO's and fanout free nodes into cone_heads */ + if (node_info->nfanout == 0) { + array_insert_last(node_t *, cone_heads, node); + } + } +} + +/* generate good circuit clauses + * return list of PI's in transitive fanin of cone_heads */ +static void +tfanin_cone(node, sat_prob, pi_list) +node_t *node; +sat_t *sat_prob; +array_t *pi_list; +{ + atpg_clause_t *node_info; + node_t *fanin; + int i; + + node_info = ATPG_CLAUSE_GET(node); + if (! node_info->visited) { + node_info->visited = TRUE; + if (node_function(node) == NODE_PI) { + array_insert_last(node_t *, pi_list, node); + } + node_info->true_id = sat_new_variable(sat_prob); + node_info->current_id = node_info->true_id; + for (i = 0; i < node_info->nfanin; i ++) { + fanin = node_get_fanin(node, node_info->fanin[i]); + tfanin_cone(fanin, sat_prob, pi_list); + } + atpg_node_clause(node, sat_prob); + } +} + +/* generate clauses for ex_dc network */ +static void +exdc_tfanin_cone(node, sat_prob, network, pi_list) +node_t *node; +sat_t *sat_prob; +network_t *network; +array_t *pi_list; +{ + atpg_clause_t *node_info, *pi_info; + node_t *pi, *fanin; + int i; + + node_info = ATPG_CLAUSE_GET(node); + if (! node_info->visited) { + node_info->visited = TRUE; + if (node_function(node) == NODE_PI) { + pi = network_find_node(network, node->name); + assert(pi != NIL(node_t)); + pi_info = ATPG_CLAUSE_GET(pi); + if (pi_info->visited) { + node_info->true_id = pi_info->true_id; + } + else { + node_info->true_id = sat_new_variable(sat_prob); + pi_info->true_id = node_info->true_id; + pi_info->visited = TRUE; + array_insert_last(node_t *, pi_list, pi); + } + node_info->current_id = node_info->true_id; + } + else { + node_info->true_id = sat_new_variable(sat_prob); + node_info->current_id = node_info->true_id; + for (i = 0; i < node_info->nfanin; i ++) { + fanin = node_get_fanin(node, node_info->fanin[i]); + exdc_tfanin_cone(fanin, sat_prob, network, pi_list); + } + atpg_node_clause(node, sat_prob); + } + } +} + +/* setup fault_id field and generate faulty clauses - skips last entry */ +static void +atpg_gen_fault_clauses(sat_prob, fault_shadow) +sat_t *sat_prob; +array_t *fault_shadow; +{ + atpg_clause_t *node_info; + int i; + node_t *node; + + /* set up fault id's - process fanin before fanout so id's are set up + * right */ + for (i = array_n(fault_shadow); i --; ) { + node = array_fetch(node_t *, fault_shadow, i); + node_info = ATPG_CLAUSE_GET(node); + node_info->fault_id = sat_new_variable(sat_prob); + node_info->current_id = ATPG_CLAUSE_GET(node)->fault_id; + + /* skip the fault node itself */ + if (i != (array_n(fault_shadow) - 1)) { + atpg_node_clause(node, sat_prob); + } + } +} + +static void +atpg_gen_fault_site(sat_prob, fault) +sat_t *sat_prob; +fault_t *fault; +{ + int faulty_site_id, good_site_id; + node_t *fanin; + + if (fault->fanin == NIL(node_t)) { + faulty_site_id = ATPG_CLAUSE_GET(fault->node)->fault_id; + good_site_id = ATPG_CLAUSE_GET(fault->node)->true_id; + } + else { + fanin = node_get_fanin(fault->node, fault->index); + faulty_site_id = sat_new_variable(sat_prob); + good_site_id = ATPG_CLAUSE_GET(fanin)->true_id; + ATPG_CLAUSE_GET(fanin)->fault_id = faulty_site_id; + ATPG_CLAUSE_GET(fanin)->current_id = faulty_site_id; + atpg_node_clause(fault->node, sat_prob); + } + + if (fault->value == S_A_0) { + sat_add_1clause(sat_prob, good_site_id); + sat_add_1clause(sat_prob, sat_neg(faulty_site_id)); + } + else { + sat_add_1clause(sat_prob, sat_neg(good_site_id)); + sat_add_1clause(sat_prob, faulty_site_id); + } +} + +static void +atpg_gen_active_clauses(sat_prob, fault_shadow) +sat_t *sat_prob; +array_t *fault_shadow; +{ + int i, n; + atpg_clause_t *node_info; + node_t *node, *fanout; + lsGen gen; + + /* set up active id's and generate clauses + * do fanout before fanin */ + for (i = 0, n = array_n(fault_shadow); i < n; i ++) { + node = array_fetch(node_t *, fault_shadow, i); + node_info = ATPG_CLAUSE_GET(node); + node_info->active_id = sat_new_variable(sat_prob); + sat_add_3clause(sat_prob, sat_neg(node_info->active_id), + node_info->true_id, node_info->fault_id); + sat_add_3clause(sat_prob, sat_neg(node_info->active_id), + sat_neg(node_info->true_id), sat_neg(node_info->fault_id)); + if (node_function(node) != NODE_PO) { + /* atleast one fanout must be active */ + if (node_num_fanout(node) == 1) { + sat_add_2clause(sat_prob, sat_neg(node_info->active_id), + ATPG_CLAUSE_GET(node_get_fanout(node, 0))->active_id); + } + else { + sat_begin_clause(sat_prob); + sat_add_literal(sat_prob, sat_neg(node_info->active_id)); + foreach_fanout(node, gen, fanout) { + sat_add_literal(sat_prob, + ATPG_CLAUSE_GET(fanout)->active_id); + } + } + } + if (i == (n - 1)) { + /* fault site is always active */ + sat_add_1clause(sat_prob, ATPG_CLAUSE_GET(node)->active_id); + } + } +} + +/* returns array of primary inputs in transitive fanin of fault */ +int +atpg_network_fault_clauses(info, exdc_info, seq_info, fault) +atpg_ss_info_t *info; +atpg_ss_info_t *exdc_info; +seq_info_t *seq_info; +fault_t *fault; +{ + int i, pi_cnt; + node_t *node, *dc_po, *output; + array_t *cone_heads, *fault_shadow, *pi_list; + atpg_clause_t *node_info; + lsGen gen; + sat_input_t sv; + + /* find coneheads */ + cone_heads = array_alloc(node_t *, 0); + fault_shadow = array_alloc(node_t *, 0); + foreach_node(info->network, gen, node) { + node_info = ATPG_CLAUSE_GET(node); + node_info->visited = FALSE; + node_info->true_id = -1; + node_info->fault_id = -1; + node_info->active_id = -1; + node_info->current_id = -1; + } + fault_path_outputs(fault->node, fault_shadow, cone_heads); + + /* generate good circuit clauses */ + foreach_node(info->network, gen, node) { + node_info = ATPG_CLAUSE_GET(node); + node_info->visited = FALSE; + } + pi_list = array_alloc(node_t *, 0); + for (i = 0; i < array_n(cone_heads); i ++) { + tfanin_cone(array_fetch(node_t *, cone_heads, i), + info->atpg_sat, pi_list); + } + + /* generate fault clauses */ + atpg_gen_fault_clauses(info->atpg_sat, fault_shadow); + atpg_gen_fault_site(info->atpg_sat, fault); + atpg_gen_active_clauses(info->atpg_sat, fault_shadow); + + /* add test condition */ + sat_begin_clause(info->atpg_sat); + for (i = array_n(cone_heads); i --; ) { + node = array_fetch(node_t *, cone_heads, i); + if (node_function(node) == NODE_PO) { + sat_add_literal(info->atpg_sat, ATPG_CLAUSE_GET(node)->active_id); + } + } + + /* add external don't cares */ + if (exdc_info != NIL(atpg_ss_info_t)) { + foreach_node(exdc_info->network, gen, node) { + node_info = ATPG_CLAUSE_GET(node); + node_info->visited = FALSE; + } + for (i = 0; i < array_n(cone_heads); i ++) { + node = array_fetch(node_t *, cone_heads, i); + if (node_function(node) == NODE_PO) { + dc_po = network_find_node(exdc_info->network, node->name); + assert(dc_po != NIL(node_t)); + exdc_tfanin_cone(dc_po, info->atpg_sat, info->network, pi_list); + sat_add_2clause(info->atpg_sat, + sat_neg(ATPG_CLAUSE_GET(node)->active_id), + sat_neg(ATPG_CLAUSE_GET(dc_po)->true_id)); + } + } + } + /* restrict solutions to reachable states */ + if (seq_info != NIL(seq_info_t)) { + foreach_node(seq_info->valid_states_network, gen, node) { + node_info = ATPG_CLAUSE_GET(node); + node_info->visited = FALSE; + } + output = network_get_po(seq_info->valid_states_network, 0); + exdc_tfanin_cone(output, info->atpg_sat, info->network, pi_list); + /* add a clause requiring the output to be 1 */ + sat_add_1clause(info->atpg_sat, ATPG_CLAUSE_GET(output)->true_id); + } + + pi_cnt = array_n(pi_list); + for (i = pi_cnt; i --; ) { + node = array_fetch(node_t *, pi_list, i); + sv.info = (char *) node; + sv.sat_id = ATPG_CLAUSE_GET(node)->true_id; + array_insert(sat_input_t, info->sat_input_vars, i, sv); + } + array_free(cone_heads); + array_free(fault_shadow); + array_free(pi_list); + + return pi_cnt; +} + +void +atpg_sat_clause_begin() +{ + c_sum_literals = NIL(int); + c_cube_literals = NIL(int); + c_max_cubes = 0; + c_max_fanin = 0; +} + +void +atpg_sat_clause_end() +{ + if (c_sum_literals) { + FREE(c_sum_literals); + c_max_cubes = 0; + } + if (c_cube_literals) { + FREE(c_cube_literals); + c_max_fanin = 0; + } +} diff --git a/sis/atpg/atpg_comb.c b/sis/atpg/atpg_comb.c new file mode 100644 index 0000000..1036a44 --- /dev/null +++ b/sis/atpg/atpg_comb.c @@ -0,0 +1,349 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg_comb.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +#include "sis.h" +#include "atpg_int.h" + +static void atpg_comb_network_simulate(); +static void atpg_sim_set_pi(); +static void get_tfo(); +static void atpg_sim_tfo(); +static void atpg_sim_get_po(); +static bool sf_comb_record_covered_faults(); +static void atpg_fault_pattern_sim(); +static void fp_comb_record_covered_faults(); + + +sequence_t * +derive_comb_test(info, n_var, pos) +atpg_ss_info_t *info; +int n_var; +int pos; +{ + array_t *word_vectors = info->word_vectors; + sequence_t *sequence; + unsigned *vector, *word_vector; + int i, v, ind; + sat_input_t sv; + + if (array_n(word_vectors) == 0) { + lengthen_word_vectors(info, 1, info->n_pi); + } + + sequence = ALLOC(sequence_t, 1); + sequence->vectors = array_alloc(unsigned *, 1); + vector = ALLOC(unsigned, info->n_pi); + array_insert(unsigned *, sequence->vectors, 0, vector); + word_vector = array_fetch(unsigned *, word_vectors, 0); + for (i = 0; i < info->n_pi; i ++) { + vector[i] = ALL_ONE; + } + for (i = 0; i < n_var; i ++) { + sv = array_fetch(sat_input_t, info->sat_input_vars, i); + v = sat_get_value(info->atpg_sat, sv.sat_id); + assert(st_lookup_int(info->pi_po_table, sv.info, &ind)); + if (v == 0) { + vector[ind] = ALL_ZERO; + word_vector[ind] &= ~ (1 << pos); + } + else { + vector[ind] = ALL_ONE; + word_vector[ind] |= (1 << pos); + } + } + return sequence; +} + +static void +atpg_comb_network_simulate(info, pi_values, po_values) +atpg_ss_info_t *info; +unsigned *pi_values; +unsigned *po_values; +{ + int i; + atpg_sim_node_t *sim_nodes; + + sim_nodes = info->sim_nodes; + for (i = info->n_pi; i --; ) { + sim_nodes[info->pi_uid[i]].value = pi_values[i]; + } + for (i = 0; i < info->n_nodes; i ++) { + (*(sim_nodes[i].eval))(sim_nodes, i); + } + for (i = info->n_po; i --; ) { + po_values[i] = sim_nodes[info->po_uid[i]].value; + } +} + +lsList +atpg_comb_single_fault_simulate(info, exdc_info, word_vectors, fault_list) +atpg_ss_info_t *info; +atpg_ss_info_t *exdc_info; +array_t *word_vectors; +lsList fault_list; +{ + unsigned *true_value, *po_values, *exdc_value, *pattern; + fault_t *fault, *prev_fault; + lsList covered_faults; + lsGen gen1; + lsGeneric data; + lsHandle handle1; + + true_value = info->all_true_value; + po_values = info->all_po_values; + exdc_value = NIL(unsigned); + pattern = array_fetch(unsigned *, word_vectors, 0); + + /* first simulate to get true values */ + atpg_comb_network_simulate(info, pattern, true_value); + + /* simulate don't cares */ + if (exdc_info != NIL(atpg_ss_info_t)) { + exdc_value = exdc_info->all_true_value; + atpg_comb_network_simulate(exdc_info, pattern, exdc_value); + } + + gen1 = lsStart(fault_list); + covered_faults = lsCreate(); + prev_fault = NIL(fault_t); + while (lsNext(gen1, (lsGeneric *) &fault, &handle1) == LS_OK) { + atpg_sf_set_sim_masks(info, fault); + if (prev_fault != NIL(fault_t)) { + if (node_function(prev_fault->node) == NODE_PI) { + atpg_sim_set_pi(info, pattern); + } + atpg_sim_tfo(info, GET_ATPG_ID(prev_fault->node)); + } + atpg_sim_tfo(info, GET_ATPG_ID(fault->node)); + atpg_sim_get_po(info, po_values); + atpg_sf_reset_sim_masks(info, fault); + prev_fault = fault; + if (sf_comb_record_covered_faults(fault, true_value, po_values, + exdc_value, info->n_po)) { + lsRemoveItem(handle1, &data); + lsNewEnd(covered_faults, (lsGeneric) data, 0); + } + } + lsFinish(gen1); + return covered_faults; +} + +static void +atpg_sim_set_pi(info, pi_values) +atpg_ss_info_t *info; +unsigned *pi_values; +{ + int i; + + for (i = info->n_pi; i --; ) { + info->sim_nodes[info->pi_uid[i]].value = pi_values[i]; + } +} + +static void +get_tfo(info, id, index) +atpg_ss_info_t *info; +int id; +int *index; +{ + int i; + + if (! info->sim_nodes[id].visited) { + info->sim_nodes[id].visited = TRUE; + for (i = 0; i < info->sim_nodes[id].nfanout; i ++) { + get_tfo(info, (info->sim_nodes[id].fanout)[i], index); + } + info->tfo[*index] = id; + (*index) ++; + } + +} + +/* assumes pi values are set */ +static void +atpg_sim_tfo(info, id) +atpg_ss_info_t *info; +int id; +{ + int f, index; + + index = 0; + get_tfo(info, id, &index); + for ( ; index --; ) { + f = info->tfo[index]; + (*(info->sim_nodes[f].eval))(info->sim_nodes, f); + info->sim_nodes[f].visited = FALSE; + } +} + +static void +atpg_sim_get_po(info, po_values) +atpg_ss_info_t *info; +unsigned *po_values; +{ + int i; + + for (i = info->n_po; i --; ) { + po_values[i] = info->sim_nodes[info->po_uid[i]].value; + } +} + +static bool +sf_comb_record_covered_faults(fault, true_value, po_values, exdc_value, npo) +fault_t *fault; +unsigned *true_value; +unsigned *po_values; +unsigned *exdc_value; +int npo; +{ + int i, j; + unsigned tval, fval, dcval; + + for (i = npo; i --; ) { + tval = true_value[i]; + fval = po_values[i]; + dcval = (exdc_value == NIL(unsigned) ? 0 : exdc_value[i]); + if ((tval ^ fval) & ~dcval) { + for (j = 0; j < WORD_LENGTH; j ++) { + if ((EXTRACT_BIT(dcval, j) == 0) && + (EXTRACT_BIT(tval, j) != EXTRACT_BIT(fval, j))) { + break; + } + } + fault->sequence_index = j; + return TRUE; + } + } + return FALSE; +} + +void +atpg_comb_simulate_old_sequences(info, ss_info, exdc_info, fault_pattern_table, + untested_faults) +atpg_info_t *info; +atpg_ss_info_t *ss_info; +atpg_ss_info_t *exdc_info; +st_table *fault_pattern_table; +lsList untested_faults; +{ + int i, n_seq; + fault_t *f; + fault_pattern_t fp; + sequence_t **sequences_ptr, *sequence; + lsList local_covered; + lsGen gen; + st_generator *sgen; + + foreach_fault(info->faults, gen, f) { + fp.node = f->node; + fp.fanin = f->fanin; + fp.value = (f->value == S_A_0) ? 0 : 1; + if (st_lookup(fault_pattern_table, (char *) &fp, (char **) &sequence)) { + f->sequence = sequence; + } + } + atpg_fault_pattern_sim(info, ss_info); + + n_seq = st_count(info->sequence_table); + sequences_ptr = ALLOC(sequence_t *, n_seq); + i = 0; + st_foreach_item(info->sequence_table, sgen, (char **) &sequence, NIL(char *)) { + sequences_ptr[i ++] = sequence; + } + + /* parallel pattern, single fault */ + for (i = 0; i < n_seq; i += WORD_LENGTH) { + extract_sequences(ss_info, sequences_ptr, i, MIN(i + WORD_LENGTH, n_seq), + 1, ss_info->n_pi); + local_covered = atpg_comb_single_fault_simulate(ss_info, exdc_info, + ss_info->word_vectors, info->faults, + NIL(sequence_t *), 0); + concat_lists(local_covered, atpg_seq_single_fault_simulate(ss_info, + exdc_info, ss_info->word_vectors, + untested_faults, NIL(sequence_t *), 0)); + lsDestroy(local_covered, free_fault); + reset_word_vectors(ss_info); + } + FREE(sequences_ptr); +} + +static void +atpg_fault_pattern_sim(info, ss_info) +atpg_info_t *info; +atpg_ss_info_t *ss_info; +{ + unsigned *true_outputs, *faulty_outputs, *pattern; + int j, done; + fault_t *fault; + lsGeneric data; + lsHandle handle; + lsGen gen; + + true_outputs = ss_info->all_true_value; + faulty_outputs = ss_info->all_po_values; + gen = lsStart(info->faults); + j = 0; + done = FALSE; + do { + if (lsNext(gen, (lsGeneric *) &fault, &handle) == LS_OK) { + if (fault->sequence != NIL(sequence_t)) { + ss_info->faults_ptr[j ++] = fault; + } + } + else { + done = TRUE; + for ( ; j < WORD_LENGTH; j ++) { + ss_info->faults_ptr[j] = NIL(fault_t); + } + } + if (j == WORD_LENGTH) { + fillin_word_vectors(ss_info, 1, info->n_pi); + pattern = array_fetch(unsigned *, ss_info->word_vectors, 0); + atpg_comb_network_simulate(ss_info, pattern, true_outputs); + atpg_set_sim_masks(ss_info); + atpg_comb_network_simulate(ss_info, pattern, faulty_outputs); + atpg_reset_sim_masks(ss_info); + fp_comb_record_covered_faults(ss_info, true_outputs, faulty_outputs); + j = 0; + } + } while (! done); + lsFinish(gen); + + gen = lsStart(info->faults); + while (lsNext(gen, (lsGeneric *) &fault, &handle) == LS_OK) { + if (fault->is_covered) { + lsRemoveItem(handle, &data); + FREE(data); + } + } + lsFinish(gen); +} + +static void +fp_comb_record_covered_faults(info, true_outputs, faulty_outputs) +atpg_ss_info_t *info; +unsigned *true_outputs; +unsigned *faulty_outputs; +{ + int i, j; + fault_t *f; + + for (i = 0; i < WORD_LENGTH; i++) { + f = info->faults_ptr[i]; + if (f != NIL(fault_t)) { + for (j = 0; j < info->n_po; j++) { + if (EXTRACT_BIT(true_outputs[j], i) != + EXTRACT_BIT(faulty_outputs[j], i)) { + f->is_covered = TRUE; + break; + } + } + } + } +} diff --git a/sis/atpg/atpg_faults.c b/sis/atpg/atpg_faults.c new file mode 100644 index 0000000..2005212 --- /dev/null +++ b/sis/atpg/atpg_faults.c @@ -0,0 +1,265 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg_faults.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +#include "sis.h" +#include "atpg_int.h" + +static void atpg_node_faults(); +static void atpg_collapse_node_faults(); +static void pi_fault_collapse(); +static void collapse_fanin_fault(); + +void +atpg_gen_faults(info) +atpg_info_t *info; +{ + array_t *nodevec; + int i; + node_t *node; + + info->faults = lsCreate(); + nodevec = network_dfs(info->network); + /* faults closer to primary outputs first */ + for (i = array_n(nodevec); i --; ) { + node = array_fetch(node_t *, nodevec, i); + if (!st_lookup(info->control_node_table, (char *) node, NIL(char *))) { + atpg_collapse_node_faults(info->faults, node, info); + } + } + array_free(nodevec); +} + +void +atpg_gen_node_faults(info, node_vec) +atpg_info_t *info; +array_t *node_vec; +{ + node_t *node; + int i; + + info->faults = lsCreate(); + for (i = array_n(node_vec); i --; ) { + node = array_fetch(node_t *, node_vec, i); + atpg_node_faults(info->faults, node, info); + } +} + +/* all transitive fanin of node must have been processed already + * for equivalent faults, */ +static void +atpg_collapse_node_faults(faults, node, info) +lsList faults; +node_t *node; +atpg_info_t *info; +{ + node_function_t node_func; + fault_t *fault; + node_t *fanin; + int i; + + node_func = node_function(node); + + /* don't collapse faults on complex gates */ + if (node_func == NODE_COMPLEX) { + atpg_node_faults(faults, node, info); + return; + } + + if (node_func == NODE_PO || node_func == NODE_0 || node_func == NODE_1) { + return; + } + + /* if PI choose equivalent fault */ + if (node_func == NODE_PI) { + switch (node_num_fanout(node)) { + case 0: + return; + case 1: + pi_fault_collapse(faults, node, info); + return; + default: + /* no collapsing possible */ + fault = new_fault(node, NIL(node_t), S_A_0, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + fault = new_fault(node, NIL(node_t), S_A_1, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + return; + } + } + + /* process each fanin */ + foreach_fanin(node, i, fanin) { + /* only handle branches of fanout-points */ + if (node_num_fanout(fanin) > 1) { + collapse_fanin_fault(faults, node, fanin, info); + } + } +} + +/* node is a PI with single fanout. For AND gate, if it is the first fanin + * then don't collapse s-a-0. If OR gate, then don't collapse s-a-1 on first + * fanin. For both AND gate and OR gate choose all s-a-1 and s-a-0 + * respectively */ +static void +pi_fault_collapse(faults, node, info) +lsList faults; +node_t *node; +atpg_info_t *info; +{ + node_t *fanout; + stuck_value_t value, opp_value; + input_phase_t phase; + node_function_t fanout_func; + fault_t *fault; + + assert(node_num_fanout(node) == 1); + fanout = node_get_fanout(node, 0); + fanout_func = node_function(fanout); + + /* equivalence exists only for AND and OR gates (this includes NOR + * and NAND and either phases of inputs */ + if (fanout_func == NODE_AND || fanout_func == NODE_OR) { + phase = node_input_phase(fanout, node); + if (node_get_fanin_index(fanout, node) == 0) { + /* AND gate S_A_0 are equivalent */ + if (fanout_func == NODE_AND) { + value = (phase == POS_UNATE ? S_A_0 : S_A_1); + } + /* OR gate S_A_1 are equivalent */ + else { + value = (phase == POS_UNATE ? S_A_1 : S_A_0); + } + fault = new_fault(node, NIL(node_t), value, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + } + if (fanout_func == NODE_AND) { + opp_value = (phase == POS_UNATE ? S_A_1 : S_A_0); + } + else { + opp_value = (phase == POS_UNATE ? S_A_0 : S_A_1); + } + fault = new_fault(node, NIL(node_t), opp_value, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + } + /* no equivalence possible */ + else { + fault = new_fault(node, NIL(node_t), S_A_0, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + fault = new_fault(node, NIL(node_t), S_A_1, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + } +} + +/* fanin must be non-null */ +static void +collapse_fanin_fault(faults, node, fanin, info) +lsList faults; +node_t *node; +node_t *fanin; +atpg_info_t *info; +{ + stuck_value_t value, opp_value; + input_phase_t phase; + node_function_t node_func; + fault_t *fault; + + assert(fanin != NIL(node_t)); + assert(node_num_fanout(fanin) > 1); + + node_func = node_function(node); + + if (node_func == NODE_AND || node_func == NODE_OR) { + phase = node_input_phase(node, fanin); + if (node_get_fanin_index(node, fanin) == 0) { + /* AND gate S_A_0 are equivalent */ + if (node_func == NODE_AND) { + value = (phase == POS_UNATE ? S_A_0 : S_A_1); + } + /* OR gate S_A_1 are equivalent */ + else { + value = (phase == POS_UNATE ? S_A_1 : S_A_0); + } + fault = new_fault(node, fanin, value, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + } + if (node_func == NODE_AND) { + opp_value = (phase == POS_UNATE ? S_A_1 : S_A_0); + } + else { + opp_value = (phase == POS_UNATE ? S_A_0 : S_A_1); + } + fault = new_fault(node, fanin, opp_value, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + } + /* no equivalence possible */ + else { + fault = new_fault(node, fanin, S_A_0, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + fault = new_fault(node, fanin, S_A_1, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + } +} + +static void +atpg_node_faults(faults, node, info) +lsList faults; +node_t *node; +atpg_info_t *info; +{ + int i; + node_t *fanin; + fault_t *fault; + + /* faults on inputs */ + foreach_fanin(node, i, fanin) { + fault = new_fault(node, fanin, S_A_0, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + fault = new_fault(node, fanin, S_A_1, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + } + /* faults on outputs */ + fault = new_fault(node, NIL(node_t), S_A_0, info); + lsNewEnd(faults, (lsGeneric) fault, 0); + fault = new_fault(node, NIL(node_t), S_A_1, info); + lsNewEnd(faults, (lsGeneric) fault, 0); +} + +fault_t * +new_fault(node, fanin, value, info) +node_t *node; +node_t *fanin; +stuck_value_t value; +atpg_info_t *info; +{ + fault_t *f; + + f = ALLOC(fault_t, 1); + f->node = node; + f->fanin = fanin; + if (fanin == NIL(node_t)) { + f->index = -1; + } + else { + f->index = node_get_fanin_index(node, fanin); + } + f->value = value; + f->status = UNTESTED; + f->is_covered = FALSE; + f->sequence = NIL(sequence_t); + f->current_state = ALLOC(unsigned, info->n_latch); + return f; +} + +void +free_fault(fault) +fault_t *fault; +{ + FREE(fault->current_state); + FREE(fault); +} diff --git a/sis/atpg/atpg_faultsim.c b/sis/atpg/atpg_faultsim.c new file mode 100644 index 0000000..27fa2cb --- /dev/null +++ b/sis/atpg/atpg_faultsim.c @@ -0,0 +1,1208 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg_faultsim.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +#include "sis.h" +#include "atpg_int.h" + +static void atpg_network_simulate(); +static void get_tfo(); +static void get_tfo_of_array(); +static void atpg_sim_tfo_array(); +static void atpg_sim_get_po(); +static bool sf_record_covered_faults(); +static void ss_record_covered_faults(); +static void atpg_fault_sequence_sim(); +static void fp_record_covered_faults(); +static int seq_length_cmp(); +static void record_different_states(); +static int seq_index_cmp(); + +/* Takes input vector and present state, and gives back real po values + * and next state. The next state is written over the present state! + */ +static void +atpg_network_simulate(info, real_pi_values, state, real_po_values) +atpg_ss_info_t *info; +unsigned *real_pi_values; +unsigned *state; +unsigned *real_po_values; +{ + int i, n_latch; + atpg_sim_node_t *sim_nodes; + + n_latch = info->n_latch; + sim_nodes = info->sim_nodes; + for (i = info->n_latch; i --; ) { + sim_nodes[info->pi_uid[i]].value = state[i]; + } + for (i = info->n_real_pi; i --; ) { + sim_nodes[info->pi_uid[i + n_latch]].value = real_pi_values[i]; + } + for (i = 0; i < info->n_nodes; i ++) { + (*(sim_nodes[i].eval))(sim_nodes, i); + } + for (i = n_latch; i --; ) { + state[i] = sim_nodes[info->po_uid[i]].value; + } + for (i = info->n_real_po; i --; ) { + real_po_values[i] = sim_nodes[info->po_uid[i + n_latch]].value; + } +} + +lsList +atpg_seq_single_fault_simulate(ss_info, exdc_info, sequences, fault_list, + original_sequences, cnt) +atpg_ss_info_t *ss_info; +atpg_ss_info_t *exdc_info; +array_t *sequences; +lsList fault_list; +sequence_t **original_sequences; +int cnt; +{ + int i, j, prev_atpg_id, pi_index, n_changed_nodes, seq_length; + unsigned *vector; + unsigned *true_value, *real_po_values, *exdc_value, *true_state; + fault_t *fault, *prev_fault; + lsList covered_faults; + lsGen gen1; + lsGeneric data; + lsHandle handle1; + + true_value = ss_info->true_value; + true_state = ss_info->true_state; + real_po_values = ss_info->real_po_values; + exdc_value = NIL(unsigned); + seq_length = array_n(sequences); + + for (i = ss_info->n_latch; i --; ) { + true_state[i] = ss_info->reset_state[i]; + } + covered_faults = lsCreate(); + /* for each vector of the sequence... */ + for (i = 0; i < seq_length; i ++) { + vector = array_fetch(unsigned *, sequences, i); + + /* first simulate to get true value and true state */ + atpg_network_simulate(ss_info, vector, true_state, true_value); + + /* simulate don't cares */ + /* Note: the value of the state here doesn't matter, since this only + * executes when the circuit is combinational */ + if (exdc_info != NIL(atpg_ss_info_t)) { + exdc_value = exdc_info->true_value; + atpg_network_simulate(exdc_info, vector, NIL(unsigned), exdc_value); + } + + gen1 = lsStart(fault_list); + prev_fault = NIL(fault_t); + while (lsNext(gen1, (lsGeneric *) &fault, &handle1) == LS_OK) { + n_changed_nodes = 0; + atpg_sf_set_sim_masks(ss_info, fault); + if (prev_fault != NIL(fault_t)) { + prev_atpg_id = GET_ATPG_ID(prev_fault->node); + + /* if the previous fault was on a pi, we need to reset the value */ + if (node_function(prev_fault->node) == NODE_PI) { + st_lookup_int(ss_info->pi_po_table, (char *) prev_fault->node, &pi_index); + if (network_is_real_pi(ss_info->network, prev_fault->node)) { + ss_info->sim_nodes[prev_atpg_id].value + = vector[pi_index - ss_info->n_latch]; + } else { + if (i) { + ss_info->sim_nodes[prev_atpg_id].value + = fault->current_state[pi_index]; + } else { + ss_info->sim_nodes[prev_atpg_id].value + = ss_info->reset_state[pi_index]; + } + } + } + ss_info->changed_node_indices[n_changed_nodes] = prev_atpg_id; + n_changed_nodes += 1; + } + /* if latch values are different for this fault than for the previous... */ + if (i) { + for (j = ss_info->n_latch; j --; ) { + if (ss_info->sim_nodes[ss_info->pi_uid[j]].value != + fault->current_state[j]) { + ss_info->sim_nodes[ss_info->pi_uid[j]].value = + fault->current_state[j]; + ss_info->changed_node_indices[n_changed_nodes] = + ss_info->pi_uid[j]; + n_changed_nodes += 1; + } + } + } + ss_info->changed_node_indices[n_changed_nodes] = GET_ATPG_ID(fault->node); + n_changed_nodes += 1; + atpg_sim_tfo_array(ss_info, n_changed_nodes); + atpg_sim_get_po(ss_info, real_po_values, fault->current_state); + atpg_sf_reset_sim_masks(ss_info, fault); + prev_fault = fault; + if (sf_record_covered_faults(fault, true_value, real_po_values, + exdc_value, ss_info->n_real_po, i, + original_sequences, cnt)) { + lsRemoveItem(handle1, &data); + lsNewEnd(covered_faults, (lsGeneric) data, 0); + } + } + lsFinish(gen1); + } + return covered_faults; +} + +/* use parallel sequence, single fault simulation */ +lsList +atpg_random_cover(info, ss_info, exdc_ss_info, save_sequences, n_tests_ptr) +atpg_info_t *info; +atpg_ss_info_t *ss_info; +atpg_ss_info_t *exdc_ss_info; +bool save_sequences; +int *n_tests_ptr; +{ + atpg_options_t *atpg_opt = info->atpg_opt; + int i, j, niter, npi; + lsList local_covered, covered_faults; + array_t *sequences; + unsigned *vector; + + npi = info->n_real_pi; + sequences = array_alloc(unsigned *, atpg_opt->rtg_depth); + for (i = atpg_opt->rtg_depth; i --; ) { + vector = ALLOC(unsigned, npi); + array_insert(unsigned *, sequences, i, vector); + } + + covered_faults = lsCreate(); + niter = 0; + do { + for (i = atpg_opt->rtg_depth; i --; ) { + vector = array_fetch(unsigned *, sequences, i); + for (j = npi; j --; ) { + vector[j] = (random() << 16) | (random() & 0xffff); + } + } + local_covered = atpg_seq_single_fault_simulate(ss_info, exdc_ss_info, + sequences, info->faults, NIL(sequence_t *), 0); + concat_lists(local_covered, atpg_seq_single_fault_simulate(ss_info, + exdc_ss_info, sequences, info->untested_faults, + NIL(sequence_t *), 0)); + if (save_sequences && (lsLength(local_covered) > 0)) { + extract_test_sequences(info, ss_info, local_covered, sequences, + n_tests_ptr, info->n_real_pi); + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "RTG: covered %d remaining %d\n", + lsLength(local_covered), lsLength(info->faults)); + } + } + if (lsLength(local_covered) < 10) { + niter ++; + if (niter > 1) { + concat_lists(covered_faults, local_covered); + for (i = atpg_opt->rtg_depth; i --; ) { + vector = array_fetch(unsigned *, sequences, i); + FREE(vector); + } + array_free(sequences); + return covered_faults; + } + } else { + niter = 0; + } + concat_lists(covered_faults, local_covered); + } while (lsLength(info->faults) != 0); + for (i = atpg_opt->rtg_depth; i --; ) { + vector = array_fetch(unsigned *, sequences, i); + FREE(vector); + } + array_free(sequences); + return covered_faults; +} + +int +random_propagate(fault, info, ss_info, seq_info) +fault_t *fault; +atpg_info_t *info; +atpg_ss_info_t *ss_info; +seq_info_t *seq_info; +{ + array_t *word_vectors = ss_info->prop_word_vectors; + array_t *good_start_state = seq_info->good_state; + array_t *faulty_start_state = seq_info->faulty_state; + array_t *prop_sequence = seq_info->prop_sequence; + int h, i, j, k, c, npi, npo, seq_length, good_value, faulty_value, + n_changed_nodes; + unsigned *vector, *prop_vector, *word_vector; + unsigned word; + unsigned *true_value = ss_info->true_value; + unsigned *true_state = ss_info->true_state; + unsigned *real_po_values = ss_info->real_po_values; + unsigned *faulty_state = fault->current_state; + unsigned *exdc_value = NIL(unsigned); + + seq_length = array_n(word_vectors); + npi = info->n_real_pi; + npo = info->n_real_po; + + for (h = info->atpg_opt->n_random_prop_iter; h --; ) { + /* set values of random prop vectors */ + for (i = seq_length; i --; ) { + vector = array_fetch(unsigned *, word_vectors, i); + for (j = npi; j --; ) { + vector[j] = (random() << 16) | (random() & 0xffff); + } + } + + /* set states to good and faulty latch values */ + for (i = ss_info->n_latch; i --; ) { + good_value = array_fetch(int, good_start_state, i); + if (good_value == 0) { + true_state[i] = ALL_ZERO; + } else { + true_state[i] = ALL_ONE; + } + faulty_value = array_fetch(int, faulty_start_state, i); + if (faulty_value == 0) { + faulty_state[i] = ALL_ZERO; + } else { + faulty_state[i] = ALL_ONE; + } + } + /* for each vector of the sequence... */ + for (i = 0; i < seq_length; i ++) { + vector = array_fetch(unsigned *, word_vectors, i); + + /* first simulate to get true value and true state */ + atpg_network_simulate(ss_info, vector, true_state, true_value); + + n_changed_nodes = 0; + atpg_sf_set_sim_masks(ss_info, fault); + /* if latch values are different for this simulation... */ + for (j = ss_info->n_latch; j --; ) { + if (ss_info->sim_nodes[ss_info->pi_uid[j]].value != + faulty_state[j]) { + ss_info->sim_nodes[ss_info->pi_uid[j]].value = + faulty_state[j]; + ss_info->changed_node_indices[n_changed_nodes] = + ss_info->pi_uid[j]; + n_changed_nodes += 1; + } + } + ss_info->changed_node_indices[n_changed_nodes] = GET_ATPG_ID(fault->node); + n_changed_nodes += 1; + atpg_sim_tfo_array(ss_info, n_changed_nodes); + atpg_sim_get_po(ss_info, real_po_values, fault->current_state); + atpg_sf_reset_sim_masks(ss_info, fault); + if (sf_record_covered_faults(fault, true_value, real_po_values, + exdc_value, npo, NIL(sequence_t *), 0)) { + c = fault->sequence_index; + if (seq_length > array_n(prop_sequence)) { + for (j = seq_length - array_n(prop_sequence); j --; ) { + prop_vector = ALLOC(unsigned, npi); + array_insert_last(unsigned *, prop_sequence, prop_vector); + } + } + for (j = seq_length; j --; ) { + prop_vector = array_fetch(unsigned *, prop_sequence, j); + word_vector = array_fetch(unsigned *, word_vectors, j); + for (k = npi; k --; ) { + word = word_vector[k]; + prop_vector[k] = (EXTRACT_BIT(word, c) == 0) ? ALL_ZERO : ALL_ONE; + } + array_insert(unsigned *, prop_sequence, j, prop_vector); + } + return (i + 1); + } + } + } + return 0; +} + +void +fault_simulate(info, ss_info, exdc_info, cnt) +atpg_info_t *info; +atpg_ss_info_t *ss_info, *exdc_info; +int cnt; +{ + lsList covered_faults; + array_t *sequences = ss_info->word_vectors; + fault_t *f; + lsHandle handle; + lsGeneric data; + + covered_faults = atpg_seq_single_fault_simulate(ss_info, exdc_info, + sequences, info->faults, ss_info->alloc_sequences, cnt); + concat_lists(covered_faults, atpg_seq_single_fault_simulate(ss_info, + exdc_info, sequences, info->untested_faults, + ss_info->alloc_sequences, cnt)); + if (info->atpg_opt->verbosity > 0) { + fprintf(sisout, "fault simulation covered %d\n", lsLength(covered_faults)); + } + while (lsFirstItem(covered_faults, (lsGeneric *) &f, &handle) == LS_OK) { + f->sequence = ss_info->alloc_sequences[f->sequence_index]; + if (ATPG_DEBUG) { + assert(atpg_verify_test(ss_info, f, f->sequence)); + } + f->sequence->n_covers ++; + f->is_covered = TRUE; + lsNewEnd(info->tested_faults, (lsGeneric) f, 0); + lsRemoveItem(handle, &data); + } + lsDestroy(covered_faults, 0); +} + +void +atpg_sf_set_sim_masks(info, fault) +atpg_ss_info_t *info; +fault_t *fault; +{ + atpg_sim_node_t *node; + + node = &(info->sim_nodes[GET_ATPG_ID(fault->node)]); + if (fault->fanin == NIL(node_t)) { + if (fault->value == S_A_1) { + node->or_output_mask = ALL_ONE; + } + else { + node->and_output_mask = ALL_ZERO; + } + } + else { + if (fault->value == S_A_1) { + node->or_input_masks[fault->index] = ALL_ONE; + } + else { + node->and_input_masks[fault->index] = ALL_ZERO; + } + } +} + +void +atpg_sf_reset_sim_masks(info, fault) +atpg_ss_info_t *info; +fault_t *fault; +{ + atpg_sim_node_t *node; + + node = &(info->sim_nodes[GET_ATPG_ID(fault->node)]); + if (fault->fanin == NIL(node_t)) { + node->or_output_mask = ALL_ZERO; + node->and_output_mask = ALL_ONE; + } + else { + node->or_input_masks[fault->index] = ALL_ZERO; + node->and_input_masks[fault->index] = ALL_ONE; + } +} + +static void +get_tfo(info, id, index) +atpg_ss_info_t *info; +int id; +int *index; +{ + int i; + + if (! info->sim_nodes[id].visited) { + info->sim_nodes[id].visited = TRUE; + for (i = 0; i < info->sim_nodes[id].nfanout; i ++) { + get_tfo(info, (info->sim_nodes[id].fanout)[i], index); + } + info->tfo[*index] = id; + (*index) ++; + } +} + +static void +get_tfo_of_array(info, index, array_size) +atpg_ss_info_t *info; +int *index; +int array_size; +{ + int id; + + for ( ; array_size -- ; ) { + id = info->changed_node_indices[array_size]; + get_tfo(info, id, index); + } +} + +/* assumes pi values are set */ +static void +atpg_sim_tfo_array(info, array_size) +atpg_ss_info_t *info; +int array_size; +{ + int f, index; + + index = 0; + get_tfo_of_array(info, &index, array_size); + for ( ; index --; ) { + f = info->tfo[index]; + (*(info->sim_nodes[f].eval))(info->sim_nodes, f); + info->sim_nodes[f].visited = FALSE; + } +} + +static void +atpg_sim_get_po(info, real_po_values, next_state) +atpg_ss_info_t *info; +unsigned *real_po_values; +unsigned *next_state; +{ + int i, n_latch; + + n_latch = info->n_latch; + for (i = n_latch; i --; ) { + next_state[i] = info->sim_nodes[info->po_uid[i]].value; + } + for (i = info->n_real_po; i --; ) { + real_po_values[i] = info->sim_nodes[info->po_uid[i + n_latch]].value; + } +} + +static bool +sf_record_covered_faults(fault, true_value, po_values, exdc_value, npo, + vector_number, original_sequences, cnt) +fault_t *fault; +unsigned *true_value; +unsigned *po_values; +unsigned *exdc_value; +int npo; +int vector_number; +sequence_t **original_sequences; +int cnt; +{ + int i, j; + unsigned tval, fval, dcval; + + if (original_sequences == NIL(sequence_t *)) { + for (i = npo; i --; ) { + tval = true_value[i]; + fval = po_values[i]; + dcval = (exdc_value == NIL(unsigned) ? 0 : exdc_value[i]); + if ((tval ^ fval) & ~dcval) { + for (j = 0; j < WORD_LENGTH; j ++) { + if ((EXTRACT_BIT(dcval, j) == 0) && + (EXTRACT_BIT(tval, j) != EXTRACT_BIT(fval, j))) { + fault->sequence_index = j; + return TRUE; + } + } + } + } + } else { + for (i = npo; i --; ) { + tval = true_value[i]; + fval = po_values[i]; + dcval = (exdc_value == NIL(unsigned) ? 0 : exdc_value[i]); + if ((tval ^ fval) & ~dcval) { + for (j = 0; j < cnt; j ++) { + if ((EXTRACT_BIT(dcval, j) == 0) && + (EXTRACT_BIT(tval, j) != EXTRACT_BIT(fval, j))) { + if (vector_number < array_n(original_sequences[j]->vectors)) { + fault->sequence_index = j; + return TRUE; + } + } + } + } + } + } + return FALSE; +} + +static void +ss_record_covered_faults(po_values, faults_ptr, npo) +unsigned *po_values; +fault_t **faults_ptr; +int npo; +{ + fault_t *f; + int i, j, *true_value; + unsigned val; + + true_value = ALLOC(int, npo); + for (i = npo; i --; ) { + val = po_values[i]; + true_value[i] = EXTRACT_BIT(val, WORD_LENGTH - 1); + } + + for (i = 0; i < WORD_LENGTH - 1; i ++) { + f = faults_ptr[i]; + if (f != NIL(fault_t)) { + for (j = 0; j < npo; j ++) { + val = po_values[j]; + /* fault detected at some PO? */ + if (EXTRACT_BIT(val, i) != true_value[j]) { + f->is_covered = TRUE; + break; + } + } + } + } + FREE(true_value); +} + +static void +record_different_states(seq_info, state, n_latch) +seq_info_t *seq_info; +unsigned *state; +int n_latch; +{ + array_t *good_state = seq_info->good_state; + array_t *faulty_state = seq_info->faulty_state; + unsigned latch_value_i; + int i, tval, fval; + + for (i = n_latch; i -- ; ) { + latch_value_i = state[i]; + tval = (EXTRACT_BIT(latch_value_i, 1) ? 1 : 0); + array_insert(int, good_state, i, tval); + fval = (EXTRACT_BIT(latch_value_i, 0) ? 1 : 0); + array_insert(int, faulty_state, i, fval); + } + +} + +/* create sequences that are tests for faults */ +void +extract_test_sequences(info, ss_info, faults, sequences, n_tests_ptr, npi) +atpg_info_t *info; +atpg_ss_info_t *ss_info; +lsList faults; +array_t *sequences; +int *n_tests_ptr; +int npi; +{ + int i, j, k, word, seq_length; + sequence_t *sequence; + fault_t *f; + lsGen gen; + unsigned *word_vector, *vector; + + seq_length = array_n(sequences); + for (i = WORD_LENGTH; i --; ) { + ss_info->used[i] = FALSE; + } + foreach_fault(faults, gen, f) { + ss_info->used[f->sequence_index] = TRUE; + } + for (i = WORD_LENGTH; i --; ) { + if (ss_info->used[i]) { + sequence = ALLOC(sequence_t, 1); + sequence->vectors = array_alloc(unsigned *, seq_length); + sequence->n_covers = 0; + if (n_tests_ptr != NIL(int)) { + *n_tests_ptr += 1; + sequence->index = *n_tests_ptr; + } + for (j = seq_length; j --; ) { + vector = ALLOC(unsigned, npi); + word_vector = array_fetch(unsigned *, sequences, j); + for (k = npi; k --; ) { + word = word_vector[k]; + vector[k] = (EXTRACT_BIT(word, i) == 0) ? ALL_ZERO : ALL_ONE; + } + array_insert(unsigned *, sequence->vectors, j, vector); + } + ss_info->alloc_sequences[i] = sequence; + st_insert(info->sequence_table, (char *) sequence, (char *) 0); + } + } + foreach_fault(faults, gen, f) { + f->sequence = ss_info->alloc_sequences[f->sequence_index]; + if (ATPG_DEBUG) { + assert(atpg_verify_test(ss_info, f, f->sequence)); + } + f->sequence->n_covers ++; + f->is_covered = TRUE; + } +} + +void +atpg_set_sim_masks(info) +atpg_ss_info_t *info; +{ + int i; + fault_t *fault; + atpg_sim_node_t *node; + + for (i = 0; i < WORD_LENGTH; i ++) { + if ((fault = info->faults_ptr[i]) != NIL(fault_t)) { + node = &(info->sim_nodes[GET_ATPG_ID(fault->node)]); + if (fault->fanin == NIL(node_t)) { + if (fault->value == S_A_1) { + node->or_output_mask |= (1 << i); + } + else { + node->and_output_mask &= ~ (1 << i); + } + } + else { + if (fault->value == S_A_1) { + node->or_input_masks[fault->index] |= (1 << i); + } + else { + node->and_input_masks[fault->index] &= ~ (1 << i); + } + } + } + } +} + +void +atpg_reset_sim_masks(info) +atpg_ss_info_t *info; +{ + int i, id; + fault_t *fault; + atpg_sim_node_t *node; + + for (i = 0; i < WORD_LENGTH; i++) { + if ((fault = info->faults_ptr[i]) != NIL(fault_t)) { + id = GET_ATPG_ID(fault->node); + node = &(info->sim_nodes[id]); + if (fault->fanin == NIL(node_t)) { + node->or_output_mask = ALL_ZERO; + node->and_output_mask = ALL_ONE; + } + else { + node->or_input_masks[fault->index] = ALL_ZERO; + node->and_input_masks[fault->index] = ALL_ONE; + } + } + } +} + +int +get_min_just_sequence(ss_info, fault, seq_info) +atpg_ss_info_t *ss_info; +fault_t *fault; +seq_info_t *seq_info; +{ + array_t *just_sequence = seq_info->just_sequence; + unsigned *po_values, *state, *vector, po_j; + int seq_length, i, j; + fault_t **faults_ptr = ss_info->faults_ptr; + + po_values = ss_info->true_value; + state = ss_info->true_state; + seq_length = array_n(just_sequence); + + for (i = WORD_LENGTH; i -- ; ) { + faults_ptr[i] = NIL(fault_t); + } + faults_ptr[0] = fault; + + for (i = ss_info->n_latch; i --; ) { + state[i] = ss_info->reset_state[i]; + } + atpg_set_sim_masks(ss_info); + + /* for each vector of the sequence... */ + for (i = 0; i < seq_length; i ++) { + vector = array_fetch(unsigned *, just_sequence, i); + + atpg_network_simulate(ss_info, vector, state, po_values); + + /* is fault effect propagated to a real primary output? */ + for (j = ss_info->n_real_po; j -- ; ) { + po_j = po_values[j]; + if (EXTRACT_BIT(po_j, 1) != EXTRACT_BIT(po_j, 0)) { + fault->is_covered = TRUE; + atpg_reset_sim_masks(ss_info); + return (i + 1); + } + } + /* is fault effect propagated to a next state line? */ + for (j = ss_info->n_latch; j -- ; ) { + po_j = state[j]; + if (EXTRACT_BIT(po_j, 1) != EXTRACT_BIT(po_j, 0)) { + atpg_reset_sim_masks(ss_info); + record_different_states(seq_info, state, ss_info->n_latch); + return (i + 1); + } + } + } + atpg_reset_sim_masks(ss_info); + return -1; +} + +void +simulate_entire_sequence(ss_info, fault, seq_info, vectors) +atpg_ss_info_t *ss_info; +fault_t *fault; +seq_info_t *seq_info; +array_t *vectors; +{ + unsigned *po_values, *state, *vector; + int seq_length, i; + fault_t **faults_ptr = ss_info->faults_ptr; + + po_values = ss_info->true_value; + state = ss_info->true_state; + seq_length = array_n(vectors); + + for (i = WORD_LENGTH; i -- ; ) { + faults_ptr[i] = NIL(fault_t); + } + faults_ptr[0] = fault; + + for (i = ss_info->n_latch; i --; ) { + state[i] = ss_info->reset_state[i]; + } + atpg_set_sim_masks(ss_info); + + /* for each vector of the sequence... */ + for (i = 0; i < seq_length; i ++) { + vector = array_fetch(unsigned *, vectors, i); + atpg_network_simulate(ss_info, vector, state, po_values); + } + record_different_states(seq_info, state, ss_info->n_latch); + atpg_reset_sim_masks(ss_info); +} + +bool +atpg_verify_test(ss_info, fault, test_sequence) +atpg_ss_info_t *ss_info; +fault_t *fault; +sequence_t *test_sequence; +{ + array_t *test_vectors = test_sequence->vectors; + unsigned *po_values, *state, *vector, po_j; + int seq_length, i, j; + fault_t **faults_ptr = ss_info->faults_ptr; + + po_values = ss_info->true_value; + state = ss_info->true_state; + seq_length = array_n(test_vectors); + + for (i = WORD_LENGTH; i -- ; ) { + faults_ptr[i] = NIL(fault_t); + } + faults_ptr[0] = fault; + + for (i = ss_info->n_latch; i --; ) { + state[i] = ss_info->reset_state[i]; + } + + atpg_set_sim_masks(ss_info); + + /* for each vector of the sequence... */ + for (i = 0; i < seq_length; i ++) { + vector = array_fetch(unsigned *, test_vectors, i); + + atpg_network_simulate(ss_info, vector, state, po_values); + + /* is fault effect propagated to a real primary output? */ + for (j = ss_info->n_real_po; j -- ; ) { + po_j = po_values[j]; + if (EXTRACT_BIT(po_j, 1) != EXTRACT_BIT(po_j, 0)) { + atpg_reset_sim_masks(ss_info); + return TRUE; + } + } + } + atpg_reset_sim_masks(ss_info); + return FALSE; +} + +/* single sequence/parallel fault simulation */ +lsList +seq_single_sequence_simulate(ss_info, test_sequence, fault_list) +atpg_ss_info_t *ss_info; +sequence_t *test_sequence; +lsList fault_list; +{ + unsigned *real_outputs = ss_info->true_value; + unsigned *states = ss_info->true_state; + array_t *vectors = test_sequence->vectors; + unsigned *vector; + int j, k, done, seq_length; + fault_t *fault; + lsGeneric data; + lsHandle handle; + lsGen gen; + lsList covered_faults; + + seq_length = array_n(vectors); + gen = lsStart(fault_list); + j = 0; + done = FALSE; + ss_info->faults_ptr[WORD_LENGTH - 1] = NIL(fault_t); + do { + /* Fill faults_ptr with next WORD_LENGTH - 1 faults. (Last + * position must contain NIL(fault_t)--the good machine.) + */ + if (lsNext(gen, (lsGeneric *) &fault, &handle) == LS_OK) { + ss_info->faults_ptr[j ++] = fault; + } else { + done = TRUE; + for ( ; j < WORD_LENGTH - 1; j ++) { + ss_info->faults_ptr[j] = NIL(fault_t); + } + } + if (j == (WORD_LENGTH - 1)) { + atpg_set_sim_masks(ss_info); + for (k = ss_info->n_latch; k --; ) { + states[k] = ss_info->reset_state[k]; + } + for (k = 0; k < seq_length; k ++) { + vector = array_fetch(unsigned *, vectors, k); + atpg_network_simulate(ss_info, vector, states, real_outputs); + ss_record_covered_faults(real_outputs, ss_info->faults_ptr, + ss_info->n_real_po); + } + atpg_reset_sim_masks(ss_info); + j = 0; + } + } while (! done); + lsFinish(gen); + + covered_faults = lsCreate(); + gen = lsStart(fault_list); + while (lsNext(gen, (lsGeneric *) &fault, &handle) == LS_OK) { + if (fault->is_covered) { + fault->status = TESTED; + fault->sequence = test_sequence; + if (ATPG_DEBUG) { + atpg_verify_test(ss_info, fault, test_sequence); + } + test_sequence->n_covers += 1; + lsRemoveItem(handle, &data); + lsNewEnd(covered_faults, data, 0); + } + } + lsFinish(gen); + return covered_faults; +} + +void +fault_simulate_to_get_final_state(ss_info, test_sequence, seq_info) +atpg_ss_info_t *ss_info; +sequence_t *test_sequence; +seq_info_t *seq_info; +{ + array_t *test_vectors = test_sequence->vectors; + unsigned *po_values, *state, *vector; + int seq_length, i; + unsigned latch_value; + array_t *good_state = seq_info->good_state; + + po_values = ss_info->true_value; + state = ss_info->true_state; + seq_length = array_n(test_vectors); + + for (i = ss_info->n_latch; i --; ) { + state[i] = ss_info->reset_state[i]; + } + + /* for each vector of the sequence... */ + for (i = 0; i < seq_length; i ++) { + vector = array_fetch(unsigned *, test_vectors, i); + atpg_network_simulate(ss_info, vector, state, po_values); + } + + for (i = ss_info->n_latch; i -- ; ) { + latch_value = state[i]; + if (latch_value == ALL_ZERO) { + array_insert(int, good_state, i, 0); + } else { + assert(latch_value == ALL_ONE); + array_insert(int, good_state, i, 1); + } + } +} + +static int +seq_length_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + sequence_t **s1, **s2; + + s1 = (sequence_t **) obj1; + s2 = (sequence_t **) obj2; + return (array_n((*s2)->vectors) - array_n((*s1)->vectors)); +} + +void +atpg_simulate_old_sequences(info, ss_info, exdc_info, fp_table, untested_faults) +atpg_info_t *info; +atpg_ss_info_t *ss_info, *exdc_info; +st_table *fp_table; +lsList untested_faults; +{ + int i, n_seq, max_seq_length; + fault_t *f; + fault_pattern_t fp; + sequence_t **sequences_ptr, *sequence; + array_t *sequences = ss_info->word_vectors; + lsList local_covered; + lsGen gen; + st_generator *sgen; + + foreach_fault(info->faults, gen, f) { + fp.node = f->node; + fp.fanin = f->fanin; + fp.value = (f->value == S_A_0) ? 0 : 1; + if (st_lookup(fp_table, (char *) &fp, (char **) &sequence)) { + f->sequence = sequence; + } + } + atpg_fault_sequence_sim(info, ss_info); + + /* try all patterns on remaining faults */ + n_seq = st_count(info->sequence_table); + sequences_ptr = ALLOC(sequence_t *, n_seq); + i = 0; + max_seq_length = 0; + st_foreach_item(info->sequence_table, sgen, (char **) &sequence, NIL(char *)) { + sequences_ptr[i ++] = sequence; + if (array_n(sequence->vectors) > max_seq_length) + max_seq_length = array_n(sequence->vectors); + } + + /* parallel pattern, single fault */ + for (i = 0; i < n_seq; i += WORD_LENGTH) { + extract_sequences(ss_info, sequences_ptr, i, MIN(i + WORD_LENGTH, n_seq), + max_seq_length, ss_info->n_real_pi); + local_covered = atpg_seq_single_fault_simulate(ss_info, exdc_info, + sequences, info->faults, NIL(sequence_t *), 0); + concat_lists(local_covered, atpg_seq_single_fault_simulate(ss_info, + exdc_info, sequences, untested_faults, + NIL(sequence_t *), 0)); + lsDestroy(local_covered, free_fault); + reset_word_vectors(ss_info); + } + FREE(sequences_ptr); +} + +static void +atpg_fault_sequence_sim(atpg_info, ss_info) +atpg_info_t *atpg_info; +atpg_ss_info_t *ss_info; +{ + unsigned *true_outputs = ss_info->true_value; + unsigned *faulty_outputs = ss_info->real_po_values; + unsigned *true_states = ss_info->true_state; + unsigned *faulty_states = ss_info->faulty_state; + unsigned *vectors; + array_t *word_vectors = ss_info->word_vectors; + int j, k, done, max_seq_length; + fault_t *fault; + lsGeneric data; + lsHandle handle; + lsGen gen; + sequence_t *sequence; + + gen = lsStart(atpg_info->faults); + j = 0; + max_seq_length = 0; + done = FALSE; + do { + if (lsNext(gen, (lsGeneric *) &fault, &handle) == LS_OK) { + sequence = fault->sequence; + if (sequence != NIL(sequence_t)) { + if (array_n(sequence->vectors) > max_seq_length) + max_seq_length = array_n(sequence->vectors); + ss_info->faults_ptr[j ++] = fault; + } + } else { + done = TRUE; + for ( ; j < WORD_LENGTH; j ++) { + ss_info->faults_ptr[j] = NIL(fault_t); + } + } + if (j == WORD_LENGTH) { + fillin_word_vectors(ss_info, max_seq_length, ss_info->n_real_pi); + for (k = ss_info->n_latch; k --; ) { + faulty_states[k] = true_states[k] = ss_info->reset_state[k]; + } + for (k = 0; k < max_seq_length; k ++) { + vectors = array_fetch(unsigned *, word_vectors, k); + atpg_network_simulate(ss_info, vectors, true_states, true_outputs); + atpg_set_sim_masks(ss_info); + atpg_network_simulate(ss_info, vectors, faulty_states, faulty_outputs); + atpg_reset_sim_masks(ss_info); + fp_record_covered_faults(ss_info, true_outputs, faulty_outputs); + } + j = 0; + max_seq_length = 0; + reset_word_vectors(ss_info); + } + } while (! done); + lsFinish(gen); + + gen = lsStart(atpg_info->faults); + while (lsNext(gen, (lsGeneric *) &fault, &handle) == LS_OK) { + if (fault->is_covered) { + lsRemoveItem(handle, &data); + free_fault((fault_t *) data); + } + } + lsFinish(gen); +} + +void +extract_sequences(info, sequences_ptr, from, to, seq_length, npi) +atpg_ss_info_t *info; +sequence_t **sequences_ptr; +int from; +int to; +int seq_length; +int npi; +{ + int h, i, j; + array_t *vectors; + array_t *word_vectors = info->word_vectors; + unsigned *vector, *word_vector; + + if (array_n(word_vectors) < seq_length) { + lengthen_word_vectors(info, seq_length - array_n(word_vectors), npi); + } + + for (h = from; h < to; h ++) { + vectors = sequences_ptr[h]->vectors; + for (i = array_n(vectors); i -- ; ) { + vector = array_fetch(unsigned *, vectors, i); + word_vector = array_fetch(unsigned *, word_vectors, i); + for (j = npi; j -- ; ) { + if (vector[j] == ALL_ZERO) { + word_vector[j] &= ~ (1 << h); + } else { + assert(vector[j] == ALL_ONE); + word_vector[j] |= (1 << h); + } + } + } + } +} + +static void +fp_record_covered_faults(info, true_outputs, faulty_outputs) +atpg_ss_info_t *info; +unsigned *true_outputs; +unsigned *faulty_outputs; +{ + int i, j; + fault_t *f; + + for (i = 0; i < WORD_LENGTH; i++) { + f = info->faults_ptr[i]; + if (f != NIL(fault_t)) { + for (j = 0; j < info->n_real_po; j++) { + if (EXTRACT_BIT(true_outputs[j], i) != + EXTRACT_BIT(faulty_outputs[j], i)) { + f->is_covered = TRUE; + break; + } + } + } + } +} + +static int +seq_index_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + sequence_t **s1, **s2; + + s1 = (sequence_t **) obj1; + s2 = (sequence_t **) obj2; + return ((*s2)->index - (*s1)->index); +} + +void +reverse_fault_simulate(info, ss_info) +atpg_info_t *info; +atpg_ss_info_t *ss_info; +{ + long start_time; + st_table *table = info->sequence_table; + st_generator *sgen; + sequence_t *sequence; + sequence_t **sequences_ptr; + int i, j, n_seq, count; + lsList covered; + fault_t *fault; + lsHandle handle; + fault_pattern_t fault_info; + lsGeneric data; + array_t *vectors; + unsigned *vector; + + start_time = util_cpu_time(); + assert(lsLength(info->faults) == 0); + lsDestroy(info->faults, free_fault); + atpg_gen_faults(info); + /* retain only testable faults */ + count = lsLength(info->faults); + while (count-- && lsFirstItem(info->faults, (lsGeneric *) &fault, &handle) == LS_OK) { + fault_info.node = fault->node; + fault_info.fanin = fault->fanin; + fault_info.value = (fault->value == S_A_0) ? 0 : 1 ; + lsRemoveItem(handle, &data); + if (st_lookup(info->redund_table, (char *) &fault_info, NIL(char *))) { + free_fault((fault_t *) data); + } else { + lsNewEnd(info->faults, (lsGeneric) data, 0); + } + } + + n_seq = st_count(table); + sequences_ptr = ALLOC(sequence_t *, n_seq); + i = 0; + st_foreach_item(table, sgen, (char **) &sequence, NIL(char *)) { + sequences_ptr[i ++] = sequence; + st_delete(table, (char **) &sequence, NIL(char *)); + } + qsort((void *) sequences_ptr, n_seq, sizeof(sequence_t *), seq_index_cmp); + + for (i = 0; i < n_seq; i ++) { + covered = seq_single_sequence_simulate(ss_info, sequences_ptr[i], + info->faults); + if (lsLength(covered) > 0) { + st_insert(table, (char *) sequences_ptr[i], (char *) 0); + } else { + vectors = sequences_ptr[i]->vectors; + for (j = array_n(vectors); j -- ; ) { + vector = array_fetch(unsigned *, vectors, j); + FREE(vector); + } + array_free(vectors); + FREE(sequences_ptr[i]); + } + lsDestroy(covered, free_fault); + if (lsLength(info->faults) == 0) { + i ++; + break; + } + } + if (info->atpg_opt->build_product_machines) { + assert(lsLength(info->faults) == 0); + } else { + lsDestroy(info->faults, free_fault); + info->faults = lsCreate(); + } + for ( ; i < n_seq; i ++) { + vectors = sequences_ptr[i]->vectors; + for (j = array_n(vectors); j -- ; ) { + vector = array_fetch(unsigned *, vectors, j); + FREE(vector); + } + array_free(vectors); + FREE(sequences_ptr[i]); + } + FREE(sequences_ptr); + info->time_info->reverse_fault_sim += (util_cpu_time() - start_time); +} + diff --git a/sis/atpg/atpg_gen_test.c b/sis/atpg/atpg_gen_test.c new file mode 100644 index 0000000..68be073 --- /dev/null +++ b/sis/atpg/atpg_gen_test.c @@ -0,0 +1,471 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg_gen_test.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include "sis.h" +#include "atpg_int.h" + +static sequence_t *justify_and_ff_propagate(); +static sequence_t *internal_states_justify_and_ff_propagate(); + +/* This function generates a test sequence using a 3-step process of combinational + * testing, fault-free justification, and fault-free propagation. + * The returned test sequence is ALLOCed only if a test is found. + */ +sequence_t * +generate_test(fault, info, ss_info, seq_info, exdc_info, cnt) +fault_t *fault; +atpg_info_t *info; +atpg_ss_info_t *ss_info; +seq_info_t *seq_info; +atpg_ss_info_t *exdc_info; +int cnt; +{ + long time, last_time; + sat_t *atpg_sat = ss_info->atpg_sat; + time_info_t *time_info = info->time_info; + atpg_options_t *atpg_opt = info->atpg_opt; + int n_pi_vars; + sat_result_t sat_value; + sequence_t *test_sequence; + unsigned *vector; + + last_time = util_cpu_time(); + sat_reset(atpg_sat); + n_pi_vars = atpg_network_fault_clauses(ss_info, exdc_info, seq_info, fault); + time = util_cpu_time(); + time_info->SAT_clauses += (time - last_time); + last_time = time; + + sat_value = sat_solve(atpg_sat, atpg_opt->fast_sat, atpg_opt->verbosity); + time = util_cpu_time(); + time_info->SAT_solve += (time - last_time); + switch (sat_value) { + case SAT_ABSURD: + fault->status = REDUNDANT; + fault->redund_type = CONTROL; + info->statistics->sat_red += 1; + break; + case SAT_GAVEUP: + fault->status = ABORTED; + break; + case SAT_SOLVED: + if (info->seq) { + if (atpg_opt->use_internal_states) { + test_sequence = internal_states_justify_and_ff_propagate(fault, + info, ss_info, seq_info, n_pi_vars, cnt); + } else { + test_sequence = justify_and_ff_propagate(fault, info, + ss_info, seq_info, n_pi_vars, cnt); + } + } else { + fault->is_covered = TRUE; + test_sequence = ALLOC(sequence_t, 1); + test_sequence->vectors = array_alloc(unsigned *, 1); + vector = ALLOC(unsigned, info->n_real_pi); + atpg_derive_excitation_vector(ss_info, n_pi_vars, vector); + array_insert(unsigned *, test_sequence->vectors, 0, vector); + } + if (fault->is_covered) { + fault->status = TESTED; + } + break; + default: + fail("bad result returned by SAT"); + break; + } + + return test_sequence; +} + +/* The returned test sequence is ALLOCed only if a test is found. + */ +static sequence_t * +justify_and_ff_propagate(fault, info, ss_info, seq_info, n_pi_vars, cnt) +fault_t *fault; +atpg_info_t *info; +atpg_ss_info_t *ss_info; +seq_info_t *seq_info; +int n_pi_vars; +int cnt; +{ + statistics_t *stats = info->statistics; + time_info_t *time_info = info->time_info; + atpg_options_t *atpg_opt = info->atpg_opt; + sequence_t *test_sequence; + long time, last_time; + bdd_t *excite_states, *already_justified; + int i, n_just_vectors, actual_n_just_vectors, n_prop_vectors, + key, inverted_key; + unsigned *vector, *excitation_vector; + bool guaranteed_test; + + last_time = util_cpu_time(); + /* generate excitation states bdd from SAT solution */ + excite_states = seq_derive_excitation_states(ss_info, seq_info, n_pi_vars); + if (ATPG_DEBUG) { + if (!bdd_leq(excite_states, seq_info->range_data->total_set, 1, 1)) { + fail("SAT returned some unreachable tests"); + } + } + already_justified = bdd_and(excite_states, + seq_info->justified_states, 1, 1); + if (!(bdd_is_tautology(already_justified, 0))) { + stats->n_just_reused += 1; + n_just_vectors = seq_reuse_just_sequence(info->n_real_pi, info->n_latch, + seq_info, already_justified); + excitation_vector = array_fetch(unsigned *, seq_info->just_sequence, + n_just_vectors); + atpg_derive_excitation_vector(ss_info, n_pi_vars, excitation_vector); + actual_n_just_vectors = get_min_just_sequence(ss_info, fault, seq_info); + if (actual_n_just_vectors < 1) { + n_just_vectors = seq_state_justify(info, seq_info, excite_states); + excitation_vector = array_fetch(unsigned *, seq_info->just_sequence, + n_just_vectors); + atpg_derive_excitation_vector(ss_info, n_pi_vars, excitation_vector); + actual_n_just_vectors = get_min_just_sequence(ss_info, fault, seq_info); + } + } else { + n_just_vectors = seq_state_justify(info, seq_info, excite_states); + excitation_vector = array_fetch(unsigned *, seq_info->just_sequence, + n_just_vectors); + atpg_derive_excitation_vector(ss_info, n_pi_vars, excitation_vector); + actual_n_just_vectors = get_min_just_sequence(ss_info, fault, seq_info); + } + bdd_free(excite_states); + bdd_free(already_justified); + assert(actual_n_just_vectors > 0); + time = util_cpu_time(); + time_info->justify += (time - last_time); + if (fault->is_covered) { + test_sequence = derive_test_sequence(ss_info, seq_info, + actual_n_just_vectors, 0, info->n_real_pi, cnt); + return test_sequence; + } else { /* find propagation sequence */ + guaranteed_test = FALSE; + n_prop_vectors = 0; + if (atpg_opt->random_prop) { + stats->n_random_propagations += 1; + last_time = util_cpu_time(); + n_prop_vectors = random_propagate(fault, info, ss_info, seq_info); + time = util_cpu_time(); + time_info->random_propagate += (time - last_time); + if (n_prop_vectors) { + guaranteed_test = TRUE; + fault->is_covered = TRUE; + stats->n_random_propagated += 1; + } + } + if (!n_prop_vectors && atpg_opt->deterministic_prop + && atpg_opt->build_product_machines && seq_info->product_machine_built) { + last_time = util_cpu_time(); + stats->n_det_propagations += 1; + key = derive_prop_key(seq_info); + if (st_lookup(seq_info->prop_sequence_table, (char *) key, NIL(char *))) { + stats->n_prop_reused += 1; + n_prop_vectors = seq_reuse_prop_sequence(info->n_real_pi, + seq_info, key); + } else { + inverted_key = derive_inverted_prop_key(seq_info); + if (st_lookup(seq_info->prop_sequence_table, + (char *) inverted_key, NIL(char *))) { + stats->n_prop_reused += 1; + n_prop_vectors = seq_reuse_prop_sequence(info->n_real_pi, + seq_info, inverted_key); + } else { + n_prop_vectors = seq_fault_free_propagate(info, seq_info); + } + } + time = util_cpu_time(); + time_info->ff_propagate += (time - last_time); + } + if (n_prop_vectors) { + test_sequence = derive_test_sequence(ss_info, seq_info, + actual_n_just_vectors, n_prop_vectors, + info->n_real_pi, cnt); + if (!guaranteed_test) { + last_time = util_cpu_time(); + if (atpg_verify_test(ss_info, fault, test_sequence)) { + fault->is_covered = TRUE; + stats->n_ff_propagated += 1; + } else { + stats->n_not_ff_propagated += 1; + for (i = array_n(test_sequence->vectors); i -- ; ) { + vector = array_fetch(unsigned *, test_sequence->vectors, i); + FREE(vector); + } + array_free(test_sequence->vectors); + FREE(test_sequence); + } + time = util_cpu_time(); + time_info->ff_propagate += (time - last_time); + } + } + } + return test_sequence; +} + +/* The returned test sequence is ALLOCed only if a test is found. + */ +static sequence_t * +internal_states_justify_and_ff_propagate(fault, info, ss_info, seq_info, n_pi_vars, cnt) +fault_t *fault; +atpg_info_t *info; +atpg_ss_info_t *ss_info; +seq_info_t *seq_info; +int n_pi_vars; +int cnt; +{ + statistics_t *stats = info->statistics; + time_info_t *time_info = info->time_info; + atpg_options_t *atpg_opt = info->atpg_opt; + sequence_t *test_sequence; + long time, last_time; + bdd_t *excite_states; + int i, n_just_vectors, actual_n_just_vectors, n_prop_vectors, key, + inverted_key, bdd_key, n_old_vectors; + unsigned *vector, *excitation_vector; + bool guaranteed_test; + bdd_t *new_start_states; + lsList sequence_list; + sequence_t *sequence_start; + array_t *old_vectors; + unsigned *old_vector; + + last_time = util_cpu_time(); + /* generate excitation states bdd from SAT solution */ + excite_states = seq_derive_excitation_states(ss_info, seq_info, n_pi_vars); + if (ATPG_DEBUG) { + if (!bdd_leq(excite_states, seq_info->range_data->total_set, 1, 1)) { + fail("SAT returned some unreachable tests"); + } + } + n_just_vectors = internal_states_seq_state_justify(info, seq_info, excite_states); + bdd_free(excite_states); + excitation_vector = array_fetch(unsigned *, seq_info->just_sequence, + n_just_vectors); + atpg_derive_excitation_vector(ss_info, n_pi_vars, excitation_vector); + if (bdd_equal(seq_info->start_state_used, seq_info->range_data->init_state_fn)) { + n_old_vectors = 0; + } else { + bdd_key = convert_bdd_to_int(seq_info->start_state_used); + assert(st_lookup(seq_info->state_sequence_table, (char *) bdd_key, (char **) &sequence_list)); + assert(lsLength(sequence_list) > 0); + (void) lsFirstItem(sequence_list, (lsGeneric *) &sequence_start, 0); + old_vectors = sequence_start->vectors; + n_old_vectors = array_n(old_vectors); + create_just_sequence(seq_info, n_just_vectors + 1, old_vectors, info->n_real_pi); + } + actual_n_just_vectors = get_min_just_sequence(ss_info, fault, seq_info); + if (actual_n_just_vectors < n_old_vectors) { + fault->is_covered = FALSE; + simulate_entire_sequence(ss_info, fault, seq_info, old_vectors); + actual_n_just_vectors = n_old_vectors; + } + assert(actual_n_just_vectors > 0); + time = util_cpu_time(); + time_info->justify += (time - last_time); + if (fault->is_covered) { + test_sequence = derive_test_sequence(ss_info, seq_info, + actual_n_just_vectors, 0, info->n_real_pi, cnt); + + } else { /* find propagation sequence */ + guaranteed_test = FALSE; + n_prop_vectors = 0; + if (atpg_opt->random_prop) { + stats->n_random_propagations += 1; + last_time = util_cpu_time(); + n_prop_vectors = random_propagate(fault, info, ss_info, seq_info); + time = util_cpu_time(); + time_info->random_propagate += (time - last_time); + if (n_prop_vectors) { + guaranteed_test = TRUE; + fault->is_covered = TRUE; + stats->n_random_propagated += 1; + } + } + if (!n_prop_vectors && atpg_opt->deterministic_prop + && atpg_opt->build_product_machines && seq_info->product_machine_built) { + last_time = util_cpu_time(); + stats->n_det_propagations += 1; + key = derive_prop_key(seq_info); + if (st_lookup(seq_info->prop_sequence_table, (char *) key, NIL(char *))) { + stats->n_prop_reused += 1; + n_prop_vectors = seq_reuse_prop_sequence(info->n_real_pi, + seq_info, key); + } else { + inverted_key = derive_inverted_prop_key(seq_info); + if (st_lookup(seq_info->prop_sequence_table, + (char *) inverted_key, NIL(char *))) { + stats->n_prop_reused += 1; + n_prop_vectors = seq_reuse_prop_sequence(info->n_real_pi, + seq_info, inverted_key); + } else { + n_prop_vectors = seq_fault_free_propagate(info, seq_info); + } + } + time = util_cpu_time(); + time_info->ff_propagate += (time - last_time); + } + if (n_prop_vectors) { + test_sequence = derive_test_sequence(ss_info, seq_info, + actual_n_just_vectors, n_prop_vectors, + info->n_real_pi, cnt); + if (!guaranteed_test) { + last_time = util_cpu_time(); + if (atpg_verify_test(ss_info, fault, test_sequence)) { + fault->is_covered = TRUE; + stats->n_ff_propagated += 1; + } else { + stats->n_not_ff_propagated += 1; + for (i = array_n(test_sequence->vectors); i -- ; ) { + vector = array_fetch(unsigned *, test_sequence->vectors, i); + FREE(vector); + } + array_free(test_sequence->vectors); + FREE(test_sequence); + } + time = util_cpu_time(); + time_info->ff_propagate += (time - last_time); + } + } + } + if (n_old_vectors && fault->is_covered) { + assert(st_delete_int(seq_info->state_sequence_table, &bdd_key, (char **) &sequence_list)); + (void) lsDelBegin(sequence_list, (lsGeneric *) &sequence_start); + assert(st_delete(info->sequence_table, (char **) &sequence_start, NIL(char *))); + if (lsLength(sequence_list) == 0) { + new_start_states = bdd_and(seq_info->start_states, + seq_info->start_state_used, 1, 0); + bdd_free(seq_info->start_states); + seq_info->start_states = new_start_states; + lsDestroy(sequence_list, 0); + } else { + st_insert(seq_info->state_sequence_table, + (char *) bdd_key, (char *) sequence_list); + } + for (i = n_old_vectors; i -- ; ) { + old_vector = array_fetch(unsigned *, old_vectors, i); + FREE(old_vector); + } + array_free(old_vectors); + FREE(sequence_start); + } + bdd_free(seq_info->start_state_used); + return test_sequence; +} + +/* The returned test sequence is ALLOCed only if a test is found. + */ +sequence_t * +generate_test_using_verification(fault, info, ss_info, seq_info, cnt) +fault_t *fault; +atpg_info_t *info; +atpg_ss_info_t *ss_info; +seq_info_t *seq_info; +int cnt; +{ + sequence_t *test_sequence; + int n_test_vectors, n_old_vectors, actual_n_just_vectors, i, j, key; + bdd_t *new_start_states; + lsList sequence_list; + sequence_t *sequence_start; + array_t *old_vectors; + unsigned *vector, *old_vector; + array_t *just_sequence = seq_info->just_sequence; + int npi = info->n_real_pi; + bdd_t *start_state_used; + bool internal_state_used, tested; + + assert(seq_info->product_machine_built); + info->statistics->n_verifications += 1; + n_test_vectors = good_faulty_PMT(fault, info, seq_info); + start_state_used = seq_info->start_state_used; + if (n_test_vectors) { + tested = TRUE; + internal_state_used = FALSE; + n_old_vectors = 0; + if (info->atpg_opt->use_internal_states) { + if (!bdd_equal(start_state_used, + seq_info->product_range_data->init_state_fn)) { + internal_state_used = TRUE; + key = convert_product_bdd_to_key(info, seq_info, start_state_used); + assert(st_lookup(seq_info->state_sequence_table, (char *) key, (char **) &sequence_list)); + assert(lsLength(sequence_list) > 0); + (void) lsFirstItem(sequence_list, (lsGeneric *) &sequence_start, 0); + old_vectors = sequence_start->vectors; + n_old_vectors = array_n(old_vectors); + if (n_old_vectors > array_n(just_sequence)) { + for (i = n_old_vectors - array_n(just_sequence); i --; ) { + vector = ALLOC(unsigned, npi); + array_insert_last(unsigned *, just_sequence, vector); + } + } + for (i = n_old_vectors; i -- ; ) { + vector = array_fetch(unsigned *, just_sequence, i); + old_vector = array_fetch(unsigned *, old_vectors, i); + for (j = npi; j -- ; ) { + vector[j] = old_vector[j]; + } + } + } + } + test_sequence = derive_test_sequence(ss_info, seq_info, n_old_vectors, + n_test_vectors, info->n_real_pi, cnt); + if (internal_state_used) { + tested = atpg_verify_test(ss_info, fault, test_sequence); + if (!tested && ATPG_DEBUG) { + create_just_sequence(seq_info, 0, test_sequence->vectors, + info->n_real_pi); + actual_n_just_vectors = get_min_just_sequence(ss_info, fault, seq_info); + assert(actual_n_just_vectors <= n_old_vectors); + } + } + if (tested) { + fault->is_covered = TRUE; + fault->status = TESTED; + if (internal_state_used) { + assert(st_delete_int(seq_info->state_sequence_table, &key, (char **) &sequence_list)); + (void) lsDelBegin(sequence_list, (lsGeneric *) &sequence_start); + assert(st_delete(info->sequence_table, (char **) &sequence_start, NIL(char *))); + if (lsLength(sequence_list) == 0) { + new_start_states = bdd_and(seq_info->product_start_states, + start_state_used, 1, 0); + bdd_free(seq_info->product_start_states); + seq_info->product_start_states = new_start_states; + lsDestroy(sequence_list, 0); + } else { + st_insert(seq_info->state_sequence_table, + (char *) key, (char *) sequence_list); + } + for (i = n_old_vectors; i -- ; ) { + old_vector = array_fetch(unsigned *, old_vectors, i); + FREE(old_vector); + } + array_free(old_vectors); + FREE(sequence_start); + } + } else { + for (i = array_n(test_sequence->vectors); i -- ; ) { + vector = array_fetch(unsigned *, test_sequence->vectors, i); + FREE(vector); + } + array_free(test_sequence->vectors); + FREE(test_sequence); + } + if (info->atpg_opt->use_internal_states) { + bdd_free(start_state_used); + } + } else { + fault->status = REDUNDANT; + fault->redund_type = OBSERVE; + info->statistics->verified_red += 1; + test_sequence = NIL(sequence_t); + } + return test_sequence; +} diff --git a/sis/atpg/atpg_init.c b/sis/atpg/atpg_init.c new file mode 100644 index 0000000..1ee0bd4 --- /dev/null +++ b/sis/atpg/atpg_init.c @@ -0,0 +1,1064 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg_init.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include "sis.h" +#include "atpg_int.h" + +static void atpg_extract_sim_node(); +static void atpg_extract_sim_function(); +static int *sim_fanout_dfs_sort(); +static int id_cmp(); +static void atpg_eval_sim_po(); +static void atpg_eval_sim_pi(); +static void atpg_eval_sim_node(); +static void free_sim_node(); + +static time_info_t INIT_TIME_INFO = {0,0,0,0,0,0,0,0,0,0,0,0}; +static statistics_t INIT_STATS = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +int +set_atpg_options(info, argc, argv) +atpg_info_t *info; +int argc; +char **argv; +{ + atpg_options_t *atpg_opt; + int c; + char *fname, *real_filename; + + atpg_opt = info->atpg_opt; + + /* default values */ + atpg_opt->quick_redund = FALSE; + atpg_opt->reverse_fault_sim = TRUE; + atpg_opt->PMT_only = FALSE; + atpg_opt->use_internal_states = FALSE; + atpg_opt->n_sim_sequences = WORD_LENGTH; + atpg_opt->deterministic_prop = TRUE; + atpg_opt->random_prop = TRUE; + atpg_opt->rtg_depth = -1; + atpg_opt->fault_simulate = TRUE; + atpg_opt->fast_sat = FALSE; + atpg_opt->rtg = TRUE; + atpg_opt->build_product_machines = TRUE; + atpg_opt->tech_decomp = FALSE; + atpg_opt->timeout = 0; + atpg_opt->verbosity = 0; + atpg_opt->prop_rtg_depth = 20; + atpg_opt->n_random_prop_iter = 1; + atpg_opt->print_sequences = FALSE; + atpg_opt->force_comb = FALSE; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "cd:DfFhn:qrRptT:v:y:z:")) != EOF) { + switch (c) { + case 'c': + atpg_opt->force_comb = TRUE; + break; + case 'd': + atpg_opt->rtg_depth = atoi(util_optarg); + break; + case 'D': + atpg_opt->deterministic_prop = FALSE; + break; + case 'f': + atpg_opt->fault_simulate = FALSE; + break; + case 'F': + atpg_opt->reverse_fault_sim = FALSE; + break; + case 'h': + atpg_opt->fast_sat = TRUE; + break; + case 'n': + atpg_opt->n_sim_sequences = atoi(util_optarg); + if (atpg_opt->n_sim_sequences > WORD_LENGTH) { + return 0; + } + break; + case 'q': + atpg_opt->quick_redund = TRUE; + atpg_opt->build_product_machines = FALSE; + break; + case 'r': + atpg_opt->rtg = FALSE; + break; + case 'R': + atpg_opt->random_prop = FALSE; + break; + case 'p': + atpg_opt->build_product_machines = FALSE; + break; + case 't': + atpg_opt->tech_decomp = TRUE; + break; + case 'T': + atpg_opt->timeout = atoi(util_optarg); + if (atpg_opt->timeout < 0 || atpg_opt->timeout > 3600 * 24 * 365) { + return 0; + } + break; + case 'v': + atpg_opt->verbosity = atoi(util_optarg); + break; + case 'y': + atpg_opt->prop_rtg_depth = atoi(util_optarg); + break; + case 'z': + atpg_opt->n_random_prop_iter = atoi(util_optarg); + break; + default: + return 0; + } + } + if (argc - util_optind == 1) { + atpg_opt->print_sequences = TRUE; + fname = argv[util_optind]; + atpg_opt->fp = com_open_file(fname, "w", &real_filename, /* silent */ 0); + atpg_opt->real_filename = real_filename; + if (atpg_opt->fp == NULL) { + FREE(real_filename); + return 0; + } + } + else if (argc - util_optind != 0) { + return 0; + } + return 1; /* everything's OK */ +} + +atpg_info_t * +atpg_info_init(network) +network_t *network; +{ + atpg_info_t *info; + statistics_t *stats; + time_info_t *time_info; + lsGen gen; + node_t *pi, *po, *node; + array_t *nodevec; + int i; + + info = ALLOC(atpg_info_t, 1); + + info->network = network; + info->n_pi = network_num_pi(network); + info->n_po = network_num_po(network); + info->n_latch = network_num_latch(network); + info->n_real_pi = 0; + info->n_real_po = 0; + foreach_primary_input(network, gen, pi) { + if (network_is_real_pi(network, pi)) { + info->n_real_pi ++; + } + } + info->control_node_table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_output(network, gen, po) { + if (network_is_real_po(network, po)) { + info->n_real_po ++; + } else { + if (network_is_control(info->network, po)) { + nodevec = network_tfi(po, INFINITY); + for (i = array_n(nodevec); i --; ) { + node = array_fetch(node_t *, nodevec, i); + st_insert(info->control_node_table, (char *) node, (char *) 0); + } + array_free(nodevec); + } + } + } + if (st_count(info->control_node_table) != 0) { + fprintf(sisout, "NOTE: faults on clock lines and other latch control lines will not be tested.\n"); + } + + info->atpg_opt = ALLOC(atpg_options_t, 1); + + stats = ALLOC(statistics_t, 1); + *stats = INIT_STATS; + info->statistics = stats; + + time_info = ALLOC(time_info_t, 1); + *time_info = INIT_TIME_INFO; + info->time_info = time_info; + + info->sequence_table = st_init_table(st_ptrcmp, st_ptrhash); + info->redund_table = st_init_table(st_fpcmp, st_fphash); + + info->redundant_faults = lsCreate(); + info->untested_faults = lsCreate(); + info->final_untested_faults = lsCreate(); + /* info->tested_faults is created during RTG */ + + return info; +} + +atpg_ss_info_t * +atpg_sim_sat_info_init(network, atpg_info) +network_t *network; +atpg_info_t *atpg_info; +{ + atpg_ss_info_t *ss_info; + int i; + unsigned *vector; + lsGen gen; + node_t *pi, *po; + + ss_info = ALLOC(atpg_ss_info_t, 1); + + ss_info->network = network; + + ss_info->n_real_pi = 0; + ss_info->n_real_po = 0; + foreach_primary_input(network, gen, pi) { + if (network_is_real_pi(network, pi)) { + ss_info->n_real_pi ++; + } + } + foreach_primary_output(network, gen, po) { + if (network_is_real_po(network, po)) { + ss_info->n_real_po ++; + } + } + + ss_info->used = ALLOC(int, WORD_LENGTH); + ss_info->alloc_sequences = ALLOC(sequence_t *, WORD_LENGTH); + ss_info->word_vectors = array_alloc(unsigned *, 0); + ss_info->prop_word_vectors = array_alloc(unsigned *, 0); + for (i = atpg_info->atpg_opt->prop_rtg_depth; i --; ) { + vector = ALLOC(unsigned, ss_info->n_real_pi); + array_insert_last(unsigned *, ss_info->prop_word_vectors, vector); + } + ss_info->real_po_values = ALLOC(unsigned, ss_info->n_real_po); + ss_info->true_value = ALLOC(unsigned, ss_info->n_real_po); + ss_info->faults_ptr = ALLOC(fault_t *, WORD_LENGTH); + + return ss_info; +} + +seq_info_t * +atpg_seq_info_init(info) +atpg_info_t *info; +{ + seq_info_t *seq_info; + + seq_info = ALLOC(seq_info_t, 1); + seq_info->seq_opt = ALLOC(verif_options_t, 1); + seq_info->seq_opt->output_info = ALLOC(output_info_t, 1); + seq_info->seq_product_opt = ALLOC(verif_options_t, 1); + seq_info->seq_product_opt->output_info = ALLOC(output_info_t, 1); + seq_info->start_states = NIL(bdd_t); + seq_info->product_start_states = NIL(bdd_t); + seq_info->reached_sets = array_alloc(bdd_t *, 0); + if (info->atpg_opt->build_product_machines) { + seq_info->product_reached_sets = array_alloc(bdd_t *, 0); + } + seq_info->input_trace = array_alloc(bdd_t *, 0); + seq_info->product_machine_built = FALSE; + + return seq_info; +} + +void +atpg_setup_seq_info(info, seq_info, stg_depth) +atpg_info_t *info; +seq_info_t *seq_info; +int stg_depth; +{ + range_data_t *data = seq_info->range_data; + output_info_t *output_info = seq_info->seq_opt->output_info; + st_table *pi_to_var_table; + node_t *pi; + bdd_t *var; + int i; + unsigned *vector; + + seq_info->just_sequence = array_alloc(unsigned *, stg_depth + 1); + seq_info->prop_sequence = array_alloc(unsigned *, stg_depth + 1); + for (i = stg_depth + 1; i -- ; ) { + vector = ALLOC(unsigned, info->n_real_pi); + array_insert(unsigned *, seq_info->just_sequence, i, vector); + vector = ALLOC(unsigned, info->n_real_pi); + array_insert(unsigned *, seq_info->prop_sequence, i, vector); + } + + seq_info->real_pi_bdds = bdd_extract_var_array(data->manager, + output_info->extern_pi, output_info->pi_ordering); + seq_info->var_table = st_init_table(st_numcmp, st_numhash); + bdd_add_varids_to_table(data->input_vars, seq_info->var_table); + bdd_add_varids_to_table(seq_info->real_pi_bdds, seq_info->var_table); + pi_to_var_table = get_pi_to_var_table(data->manager, output_info); + seq_info->input_vars = array_alloc(bdd_t *, 0); + for(i = 0; i < array_n(output_info->extern_pi); i++) { + pi = array_fetch(node_t *, output_info->extern_pi, i); + assert(st_lookup(pi_to_var_table, (char *) pi, (char **) &var)); + array_insert_last(bdd_t *, seq_info->input_vars, var); + } + st_free_table(pi_to_var_table); +} + +void +atpg_product_setup_seq_info(seq_info) +seq_info_t *seq_info; +{ + range_data_t *product_data = seq_info->product_range_data; + output_info_t *product_output_info = seq_info->seq_product_opt->output_info; + st_table *pi_to_var_table; + node_t *pi; + bdd_t *var; + int i; + + seq_info->product_real_pi_bdds = + bdd_extract_var_array(product_data->manager, + product_output_info->extern_pi, + product_output_info->pi_ordering); + seq_info->product_var_table = st_init_table(st_numcmp, st_numhash); + bdd_add_varids_to_table(product_data->input_vars, + seq_info->product_var_table); + bdd_add_varids_to_table(seq_info->product_real_pi_bdds, + seq_info->product_var_table); + pi_to_var_table = get_pi_to_var_table(product_data->manager, + product_output_info); + seq_info->product_input_vars = array_alloc(bdd_t *, 0); + for(i = 0; i < array_n(product_output_info->extern_pi); i++) { + pi = array_fetch(node_t *, product_output_info->extern_pi, i); + assert(st_lookup(pi_to_var_table, (char *) pi, (char **) &var)); + array_insert_last(bdd_t *, seq_info->product_input_vars, var); + } + st_free_table(pi_to_var_table); + seq_info->product_machine_built = TRUE; +} + +void +atpg_sat_init(info) +atpg_ss_info_t *info; +{ + if (info->network == NIL(network_t)) { + return; + } + atpg_sat_node_info_setup(info->network); + atpg_sat_clause_begin(); + info->atpg_sat = sat_new(); + info->sat_input_vars = array_alloc(sat_input_t, info->n_pi); +} + +void +atpg_sat_node_info_setup(network) +network_t *network; +{ + array_t *nodevec; + int i, max_fanin; + node_t *node; + node_index_t *fanin_ptr; + atpg_clause_t *node_info; + + nodevec = network_dfs(network); + max_fanin = 0; + for (i = 0; i < array_n(nodevec); i ++) { + node = array_fetch(node_t *, nodevec, i); + node_info = ALLOC(atpg_clause_t, 1); + ATPG_CLAUSE_SET(node, node_info); + node_info->true_id = -1; + node_info->fault_id = -1; + node_info->active_id = -1; + node_info->current_id = -1; + node_info->visited = FALSE; + node_info->order = i; + max_fanin = MAX(max_fanin, node_num_fanin(node)); + } + fanin_ptr = ALLOC(node_index_t, max_fanin); + for (i = 0; i < array_n(nodevec); i ++) { + node = array_fetch(node_t *, nodevec, i); + node_info = ATPG_CLAUSE_GET(node); + node_info->nfanin = node_num_fanin(node); + node_info->nfanout = node_num_fanout(node); + node_info->fanin = fanin_dfs_sort(node, fanin_ptr); + node_info->fanout = sat_fanout_dfs_sort(node); + } + FREE(fanin_ptr); + array_free(nodevec); +} + +void +atpg_sim_setup(ss_info) +atpg_ss_info_t *ss_info; +{ + node_t *pi, *po; + int id; + lsGen gen, latch_gen; + latch_t *l; + unsigned value; + + ss_info->n_latch = network_num_latch(ss_info->network); + ss_info->n_pi = network_num_pi(ss_info->network); + ss_info->n_po = network_num_po(ss_info->network); + ss_info->pi_po_table = st_init_table(st_ptrcmp, st_ptrhash); + id = 0; + /* give latches the first n_latch id's, and match latch pi's and po's by id */ + foreach_latch(ss_info->network, gen, l) { + pi = latch_get_output(l); + st_insert(ss_info->pi_po_table, (char *) pi, (char *) id); + po = latch_get_input(l); + st_insert(ss_info->pi_po_table, (char *) po, (char *) id++); + } + assert(id == ss_info->n_latch); + foreach_primary_input(ss_info->network, gen, pi) { + if (network_is_real_pi(ss_info->network, pi)) { + st_insert(ss_info->pi_po_table, (char *) pi, (char *) id++); + } else { + if (!network_is_control(ss_info->network, pi)) { + assert(st_is_member(ss_info->pi_po_table, (char *) pi)); + } + } + } + assert(id == (ss_info->n_latch + ss_info->n_real_pi)); + id = ss_info->n_latch; + foreach_primary_output(ss_info->network, gen, po) { + if (network_is_real_po(ss_info->network, po)) { + st_insert(ss_info->pi_po_table, (char *) po, (char *) id++); + } else { + if (!network_is_control(ss_info->network, po)) { + assert(st_is_member(ss_info->pi_po_table, (char *) po)); + } + } + } + assert(id == (ss_info->n_latch + ss_info->n_real_po)); + ss_info->pi_uid = ALLOC(int, ss_info->n_real_pi + ss_info->n_latch); + ss_info->po_uid = ALLOC(int, ss_info->n_real_po + ss_info->n_latch); + + /* create the reset state array used in fault simulation */ + ss_info->reset_state = ALLOC(unsigned, ss_info->n_latch); + foreach_latch(ss_info->network, latch_gen, l) { + value = ((latch_get_initial_value(l) == 0) ? ALL_ZERO : ALL_ONE); + pi = latch_get_output(l); + st_lookup_int(ss_info->pi_po_table, (char *) pi, &id); + ss_info->reset_state[id] = value; + } + ss_info->true_state = ALLOC(unsigned, ss_info->n_latch); + ss_info->faulty_state = ALLOC(unsigned, ss_info->n_latch); + ss_info->changed_node_indices = ALLOC(int, ss_info->n_latch + 2); + ss_info->all_true_value = ALLOC(unsigned, ss_info->n_po); + ss_info->all_po_values = ALLOC(unsigned, ss_info->n_po); +} + +void +atpg_comb_sim_setup(ss_info) +atpg_ss_info_t *ss_info; +{ + array_t *nodevec; + node_t *node, **fanout_ptr; + int id, max_fanout; + lsGen gen; + node_t *pi, *po; + + ss_info->n_nodes = ss_info->n_pi + ss_info->n_po + + network_num_internal(ss_info->network); + ss_info->tfo = ALLOC(int, ss_info->n_nodes); + + /* create simulation nodes */ + max_fanout = 0; + nodevec = network_dfs(ss_info->network); + ss_info->sim_nodes = ALLOC(atpg_sim_node_t, ss_info->n_nodes); + + /* allocate all id's before extraction */ + for (id = 0; id < array_n(nodevec); id ++) { + node = array_fetch(node_t *, nodevec, id); + SET_ATPG_ID(node, id); + max_fanout = MAX(max_fanout, node_num_fanout(node)); + } + fanout_ptr = ALLOC(node_t *, max_fanout); + for (id = 0; id < array_n(nodevec); id ++) { + node = array_fetch(node_t *, nodevec, id); + atpg_extract_sim_node(node, ss_info->sim_nodes, fanout_ptr); + } + FREE(fanout_ptr); + array_free(nodevec); + + /* match pi's with an index for consistent reference */ + /* Because the latches were given the first n_latch id's they will appear + first in the uid arrays, and a latch's pi and po will have the same index + */ + foreach_primary_input(ss_info->network, gen, pi) { + if (!network_is_control(ss_info->network, pi)) { + assert(st_lookup_int(ss_info->pi_po_table, (char *) pi, &id)); + ss_info->pi_uid[id] = GET_ATPG_ID(pi); + } + } + foreach_primary_output(ss_info->network, gen, po) { + if (!network_is_control(ss_info->network, po)) { + assert(st_lookup_int(ss_info->pi_po_table, (char *) po, &id)); + ss_info->po_uid[id] = GET_ATPG_ID(po); + } + } +} + +void +atpg_add_pi_and_po(dc_network, info) +network_t *dc_network; +atpg_info_t *info; +{ + node_t *orig_pi, *orig_po, *exdc_pi, *exdc_po, *new_pi, *new_po; + int id; + lsGen gen; + bool network_changed; + + network_changed = FALSE; + foreach_primary_input(info->network, gen, orig_pi) { + exdc_pi = network_find_node(dc_network, orig_pi->name); + if (exdc_pi == NIL(node_t)) { + new_pi = node_alloc(); + new_pi->name = ALLOC(char, strlen (node_long_name(orig_pi)) + 1); + strcpy(new_pi->name, node_long_name(orig_pi)); + network_add_primary_input(dc_network, new_pi); + network_changed = TRUE; + } + } + foreach_primary_output(info->network, gen, orig_po) { + exdc_po = network_find_node(dc_network, orig_po->name); + if (exdc_po == NIL(node_t)) { + new_po = node_constant(0); + new_po->name = ALLOC(char, strlen (node_long_name(orig_po)) + 1); + strcpy(new_po->name, node_long_name(orig_po)); + network_add_node(dc_network, new_po); + network_add_primary_output(dc_network, new_po); + network_changed = TRUE; + } + } + if (network_changed) { + fprintf(sisout, +"\nNOTE: When using an external don't care network, the primary inputs and\noutputs of the external don't care network must match exactly with the\nprimary inputs and outputs of the network. Your external don't care network\nwas missing some inputs or outputs, so dummy primary inputs or outputs\nhave been added to the exdc network. This will not change the behavior\nof the circuit.\n\n"); + } +} + + +void +atpg_exdc_sim_link(exdc_info, info) +atpg_ss_info_t *exdc_info; +atpg_ss_info_t *info; +{ + node_t *pi, *po, *orig_pi, *orig_po; + int id; + lsGen gen; + + /* must have same pi's and po's as original network */ + /* Dummy pi's and po's should have been added (if they were needed) + in the procedure atpg_add_pi_and_po */ + assert(exdc_info->n_real_pi == info->n_pi); + assert(exdc_info->n_real_po == info->n_po); + + /* Match pi's with index in info->network for consistent reference + * same order of pi's and po's as original network. */ + foreach_primary_input(exdc_info->network, gen, pi) { + orig_pi = network_find_node(info->network, pi->name); + assert(orig_pi != NIL(node_t)); + assert(st_lookup_int(info->pi_po_table, (char *) orig_pi, &id)); + exdc_info->pi_uid[id] = GET_ATPG_ID(pi); + } + foreach_primary_output(exdc_info->network, gen, po) { + orig_po = network_find_node(info->network, po->name); + assert(orig_po != NIL(node_t)); + assert(st_lookup_int(info->pi_po_table, (char *) orig_po, &id)); + exdc_info->po_uid[id] = GET_ATPG_ID(po); + } +} + +void +print_and_destroy_sequences(info) +atpg_info_t *info; +{ + st_table *sequence_table = info->sequence_table; + atpg_options_t *atpg_opt = info->atpg_opt; + statistics_t *stats = info->statistics; + st_generator *sgen; + sequence_t *sequence; + array_t *vectors; + unsigned *vector; + int i; + lsGen gen; + node_t *pi; + + if (atpg_opt->print_sequences) { + fprintf(atpg_opt->fp, + "atpg test sequences for %s\n", network_name(info->network)); + if (st_count(info->control_node_table) != 0) { + fprintf(atpg_opt->fp, "\nNOTE: Ignore setting of clock and other latch control inputs.\n\n"); + } + fprintf(atpg_opt->fp, "inputs:\n"); + foreach_primary_input(info->network, gen, pi) { + if (network_is_real_pi(info->network, pi)) { + fprintf(atpg_opt->fp, "%s ", node_name(pi)); + } + } + fprintf(atpg_opt->fp, "\n\n"); + } + st_foreach_item(sequence_table, sgen, (char **) &sequence, NIL(char *)) { + vectors = sequence->vectors; + if (atpg_opt->print_sequences) { + atpg_print_vectors(atpg_opt->fp, vectors, info->n_real_pi); + } + stats->n_vectors += array_n(vectors); + stats->n_sequences += 1; + for (i = array_n(vectors); i -- ; ) { + vector = array_fetch(unsigned *, vectors, i); + FREE(vector); + } + array_free(vectors); + FREE(sequence); + } + if (atpg_opt->print_sequences) { + FREE(atpg_opt->real_filename); + if (atpg_opt->fp != sisout) (void) fclose(atpg_opt->fp); + } +} + +void +atpg_sat_free(info) +atpg_ss_info_t *info; +{ + node_t *node; + lsGen gen; + atpg_clause_t *node_info; + + sat_delete(info->atpg_sat); + foreach_node(info->network, gen, node) { + node_info = ATPG_CLAUSE_GET(node); + if (node_info) { + FREE(node_info->fanin); + FREE(node_info->fanout); + FREE(node_info); + ATPG_CLAUSE_SET(node, 0); + } + } + atpg_sat_clause_end(); + array_free(info->sat_input_vars); +} + +void atpg_sim_unsetup(info) +atpg_ss_info_t *info; +{ + st_free_table(info->pi_po_table); + FREE(info->pi_uid); + FREE(info->po_uid); + FREE(info->reset_state); + FREE(info->true_state); + FREE(info->faulty_state); + FREE(info->all_true_value); + FREE(info->all_po_values); + FREE(info->changed_node_indices); +} + +void atpg_comb_sim_unsetup(info) +atpg_ss_info_t *info; +{ + int i; + + for (i = info->n_nodes; i --; ) { + free_sim_node(&((info->sim_nodes)[i])); + } + FREE(info->sim_nodes); + FREE(info->tfo); +} + +void +atpg_sim_free(info) +atpg_ss_info_t *info; +{ + int i; + unsigned *vector; + array_t *word_vectors = info->word_vectors; + array_t *prop_word_vectors = info->prop_word_vectors; + + FREE(info->real_po_values); + FREE(info->true_value); + FREE(info->used); + FREE(info->alloc_sequences); + for (i = array_n(word_vectors); i -- ; ) { + vector = array_fetch(unsigned *, word_vectors, i); + FREE(vector); + } + array_free(word_vectors); + for (i = array_n(prop_word_vectors); i -- ; ) { + vector = array_fetch(unsigned *, prop_word_vectors, i); + FREE(vector); + } + array_free(prop_word_vectors); + FREE(info->faults_ptr); + FREE(info->tfo); +} + +void +seq_info_product_free(seq_info) +seq_info_t *seq_info; +{ + seq_info->product_machine_built = FALSE; + product_free_range_data(seq_info->product_range_data, + seq_info->seq_product_opt); + network_free(seq_info->product_network); + output_info_free(seq_info->seq_product_opt->output_info); + free_bdds_in_array(seq_info->orig_external_outputs); + array_free(seq_info->orig_external_outputs); + free_bdds_in_array(seq_info->orig_transition_outputs); + array_free(seq_info->orig_transition_outputs); + array_free(seq_info->product_real_pi_bdds); + array_free(seq_info->product_input_vars); + st_free_table(seq_info->product_var_table); +} + +void +seq_info_free(info, seq_info) +atpg_info_t *info; +seq_info_t *seq_info; +{ + int i; + unsigned *vector; + st_table *just_table; + st_table *prop_table; + atpg_options_t *atpg_opt = info->atpg_opt; + st_generator *sgen; + array_t *vectors; + char *key; + lsGen gen; + node_t *node; + atpg_clause_t *node_info; + lsList seq_list; + + product_free_range_data(seq_info->range_data, seq_info->seq_opt); + network_free(seq_info->network_copy); + output_info_free(seq_info->seq_opt->output_info); + free_bdds_in_array(seq_info->reached_sets); + bdd_free(seq_info->justified_states); + array_free(seq_info->good_state); + array_free(seq_info->faulty_state); + + just_table = seq_info->just_sequence_table; + st_foreach_item(just_table, sgen, &key, (char **) &vectors) { + for (i = array_n(vectors); i -- ; ) { + vector = array_fetch(unsigned *, vectors, i); + FREE(vector); + } + array_free(vectors); + } + st_free_table(just_table); + prop_table = seq_info->prop_sequence_table; + st_foreach_item(prop_table, sgen, &key, (char **) &vectors) { + if (vectors != NIL(array_t)) { + for (i = array_n(vectors); i -- ; ) { + vector = array_fetch(unsigned *, vectors, i); + FREE(vector); + } + array_free(vectors); + } + } + st_free_table(prop_table); + array_free(seq_info->latch_to_pi_ordering); + if (atpg_opt->use_internal_states) { + bdd_free(seq_info->start_states); + if (atpg_opt->build_product_machines) { + if (seq_info->product_start_states != NIL(bdd_t)) + bdd_free(seq_info->product_start_states); + array_free(seq_info->latch_to_product_pi_ordering); + } + st_foreach_item(seq_info->state_sequence_table, sgen, + &key, (char **) &seq_list) { + lsDestroy(seq_list, 0); + } + st_free_table(seq_info->state_sequence_table); + } + + foreach_node(seq_info->valid_states_network, gen, node) { + node_info = ATPG_CLAUSE_GET(node); + if (node_info) { + FREE(node_info->fanin); + FREE(node_info->fanout); + FREE(node_info); + ATPG_CLAUSE_SET(node, 0); + } + } + network_free(seq_info->valid_states_network); + array_free(seq_info->real_pi_bdds); + array_free(seq_info->input_vars); + st_free_table(seq_info->var_table); + + if (info->atpg_opt->build_product_machines) { + array_free(seq_info->product_reached_sets); + } + FREE(seq_info->seq_opt->output_info); + FREE(seq_info->seq_product_opt->output_info); + FREE(seq_info->seq_opt); + FREE(seq_info->seq_product_opt); + array_free(seq_info->reached_sets); + + for (i = array_n(seq_info->just_sequence); i -- ; ) { + vector = array_fetch(unsigned *, seq_info->just_sequence, i); + FREE(vector); + } + array_free(seq_info->just_sequence); + for (i = array_n(seq_info->prop_sequence); i -- ; ) { + vector = array_fetch(unsigned *, seq_info->prop_sequence, i); + FREE(vector); + } + array_free(seq_info->prop_sequence); + array_free(seq_info->input_trace); + FREE(seq_info); +} + +void +atpg_free_info(info) +atpg_info_t *info; +{ + st_generator *sgen; + fault_pattern_t *info_p; + + FREE(info->atpg_opt); + FREE(info->time_info); + FREE(info->statistics); + lsDestroy(info->redundant_faults, free_fault); + lsDestroy(info->untested_faults, free_fault); + lsDestroy(info->final_untested_faults, free_fault); + st_free_table(info->sequence_table); + st_foreach_item(info->redund_table, sgen, (char **) &info_p, NIL(char *)) { + FREE(info_p); + } + st_free_table(info->redund_table); + st_free_table(info->control_node_table); + FREE(info); +} + +static void +atpg_extract_sim_node(node, sim_nodes, fanout_ptr) +node_t *node; +atpg_sim_node_t *sim_nodes; +node_t **fanout_ptr; +{ + int i; + node_t *fanin; + atpg_sim_node_t *sm; + + sm = &(sim_nodes[GET_ATPG_ID(node)]); + sm->node = node; + sm->nfanout = node_num_fanout(node); + sm->fanout = sim_fanout_dfs_sort(node, fanout_ptr); + sm->uid = GET_ATPG_ID(node); + sm->type = node_function(node); + sm->visited = FALSE; + sm->n_inputs = node_num_fanin(node); + sm->or_output_mask = ALL_ZERO; + sm->and_output_mask = ALL_ONE; + sm->or_input_masks = ALLOC(unsigned, sm->n_inputs); + sm->and_input_masks = ALLOC(unsigned, sm->n_inputs); + for (i = sm->n_inputs; i --; ) { + sm->or_input_masks[i] = ALL_ZERO; + sm->and_input_masks[i] = ALL_ONE; + } + switch (sm->type) { + case NODE_0: + sm->value = ALL_ZERO; + sm->eval = atpg_eval_sim_pi; + return; + case NODE_1: + sm->value = ALL_ONE; + sm->eval = atpg_eval_sim_pi; + return; + case NODE_PI: + sm->eval = atpg_eval_sim_pi; + return; + case NODE_PO: + sm->fanin_values = ALLOC(unsigned *, sm->n_inputs); + for (i = sm->n_inputs; i --; ) { + fanin = node_get_fanin(node, i); + sm->fanin_values[i] = + &(sim_nodes[GET_ATPG_ID(fanin)].value); + } + sm->eval = atpg_eval_sim_po; + return; + case NODE_BUF: + case NODE_INV: + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + sm->fanin_values = ALLOC(unsigned *, sm->n_inputs); + for (i = sm->n_inputs; i --; ) { + fanin = node_get_fanin(node, i); + sm->fanin_values[i] = + &(sim_nodes[GET_ATPG_ID(fanin)].value); + } + sm->n_cubes = node_num_cube(node); + sm->function = ALLOC(int *, sm->n_cubes); + for (i = sm->n_cubes; i --; ) { + sm->function[i] = ALLOC(int, sm->n_inputs); + } + sm->inputs = ALLOC(unsigned *, 3); + for (i = 3; i --; ) { + sm->inputs[i] = ALLOC(unsigned, sm->n_inputs); + } + for (i = sm->n_inputs; i --; ) { + sm->inputs[2][i] = ALL_ONE; + } + atpg_extract_sim_function(sm); + sm->eval = atpg_eval_sim_node; + return; + case NODE_UNDEFINED: + default: + fail("unexpected node type"); + } +} + +static void +atpg_extract_sim_function(sim_node) +atpg_sim_node_t *sim_node; +{ + int c, l, literal; + node_t *node; + node_cube_t cube; + + node = sim_node->node; + for (c = sim_node->n_cubes; c --; ) { + cube = node_get_cube(node, c); + for (l = node_num_fanin(node); l --; ) { + literal = node_get_literal(cube, l); + switch (literal) { + case ZERO: + sim_node->function[c][l] = 0; + break; + case ONE: + sim_node->function[c][l] = 1; + break; + case TWO: + sim_node->function[c][l] = 2; + break; + default: + fail("bad literal"); + } + } + } +} + +static int * +sim_fanout_dfs_sort(node, fanout_ptr) +node_t *node; +node_t **fanout_ptr; +{ + node_t *fanout; + lsGen gen; + int j, n, *fanout_list; + + n = node_num_fanout(node); + j = 0; + foreach_fanout(node, gen, fanout) { + fanout_ptr[j ++] = fanout; + } + qsort((void *) fanout_ptr, n, sizeof(node_t *), id_cmp); + fanout_list = ALLOC(int, n); + for (j = 0; j < n ; j ++) { + fanout_list[j] = GET_ATPG_ID(fanout_ptr[j]); + } + return fanout_list; +} + +static int +id_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + node_t **n1, **n2; + + n1 = (node_t **) obj1; + n2 = (node_t **) obj2; + return GET_ATPG_ID((*n1)) - GET_ATPG_ID((*n2)); +} + +static void +atpg_eval_sim_po(sim_nodes, uid) +atpg_sim_node_t *sim_nodes; +int uid; +{ + int result; + atpg_sim_node_t *sim_node = &sim_nodes[uid]; + + result = *(sim_node->fanin_values[0]); + result &= (sim_node->and_input_masks[0] & sim_node->and_output_mask); + result |= (sim_node->or_input_masks[0] | sim_node->or_output_mask); + sim_node->value = result; +} + +static void +atpg_eval_sim_pi(sim_nodes, uid) +atpg_sim_node_t *sim_nodes; +int uid; +{ + int result; + atpg_sim_node_t *sim_node = &sim_nodes[uid]; + + result = sim_node->value; + result &= sim_node->and_output_mask; + result |= sim_node->or_output_mask; + sim_node->value = result; +} + +static void +atpg_eval_sim_node(sim_nodes, uid) +atpg_sim_node_t *sim_nodes; +int uid; +{ + int i, j; + int result, and_result; + atpg_sim_node_t *sim_node = &sim_nodes[uid]; + + for (j = sim_node->n_inputs; j --; ) { + result = *(sim_node->fanin_values[j]); + result &= sim_node->and_input_masks[j]; + result |= sim_node->or_input_masks[j]; + sim_node->inputs[1][j] = result; + sim_node->inputs[0][j] = ~result; + } + result = sim_node->or_output_mask; + for (i = sim_node->n_cubes; i --; ) { + and_result = sim_node->and_output_mask; + for (j = sim_node->n_inputs; j --; ) { + and_result &= sim_node->inputs[sim_node->function[i][j]][j]; + } + result |= and_result; + } + sim_node->value = result; +} + +static void +free_sim_node(sim_node) +atpg_sim_node_t *sim_node; +{ + int i; + + FREE(sim_node->and_input_masks); + FREE(sim_node->or_input_masks); + FREE(sim_node->fanout); + + switch (sim_node->type) { + case NODE_PI: + case NODE_0: + case NODE_1: + break; + case NODE_PO: + FREE(sim_node->fanin_values); + break; + case NODE_BUF: + case NODE_INV: + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + FREE(sim_node->fanin_values); + for (i = 3; i --; ) { + FREE(sim_node->inputs[i]); + } + FREE(sim_node->inputs); + for (i = sim_node->n_cubes; i --; ) { + FREE(sim_node->function[i]); + } + FREE(sim_node->function); + break; + } +} diff --git a/sis/atpg/atpg_int.h b/sis/atpg/atpg_int.h new file mode 100644 index 0000000..03043a4 --- /dev/null +++ b/sis/atpg/atpg_int.h @@ -0,0 +1,25 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include "atpg.h" + +#define ALL_ZERO 0 +#define ALL_ONE ~0 +#define WORD_LENGTH 32 +#define ATPG_DEBUG 0 + +#define EXTRACT_BIT(word,pos) (((word) & (1 << (pos))) != 0) + +/* fault list data structures */ +#define foreach_fault(faults, gen, f) \ + for(gen = lsStart(faults); \ + (lsNext(gen, (lsGeneric *) &f, LS_NH) == LS_OK) \ + || ((void) lsFinish(gen), 0); ) + + diff --git a/sis/atpg/atpg_seq.c b/sis/atpg/atpg_seq.c new file mode 100644 index 0000000..d391e02 --- /dev/null +++ b/sis/atpg/atpg_seq.c @@ -0,0 +1,903 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg_seq.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include "sis.h" +#include "atpg_int.h" + +typedef struct { + int which_case; + node_t *faulty_node; + node_t *faulty_fanin; + node_t *orig_faulty_node; + node_t *orig_faulty_fanin; + node_t *const_node; + int n_fanout; + node_t **fanouts; +} saved_nodes_t; + +static void set_options(); +static void reverse_generate_Sj(); +static void convert_trace_to_sequence(); +static int seq_check_output(); +static void insert_fault(); +static void remove_fault(); +static void add_minterms_to_product_start_states(); + +void +seq_setup(seq_info, info) +seq_info_t *seq_info; +atpg_info_t *info; +{ + range_data_t *data; + verif_options_t *options = seq_info->seq_opt; + network_t *network = info->network; + lsGen gen; + latch_t *l; + node_t *pi; + st_table *pi_ordering; + int i, position; + + seq_info->network_copy = network_dup(network); + seq_info->good_state = array_alloc(int, info->n_latch); + seq_info->faulty_state = array_alloc(int, info->n_latch); + seq_info->just_sequence_table = st_init_table(st_numcmp, st_numhash); + seq_info->prop_sequence_table = st_init_table(st_numcmp, st_numhash); + set_options(options); + options->does_verification = 0; + output_info_init(options->output_info); + extract_network_info(seq_info->network_copy, options); + assert(options->output_info->init_node != NIL(node_t)); + data = product_alloc_range_data(seq_info->network_copy, options); + data->total_set = bdd_zero(data->manager); + assert(data->init_state_fn != NIL(bdd_t)); + seq_info->range_data = data; + + seq_info->latch_to_pi_ordering = array_alloc(int, info->n_latch); + pi_ordering = options->output_info->pi_ordering; + i = 0; + foreach_latch(seq_info->network_copy, gen, l) { + pi = latch_get_output(l); + assert(st_lookup_int(pi_ordering, (char *) pi, &position)); + array_insert(int, seq_info->latch_to_pi_ordering, i ++, position); + } + + if (info->atpg_opt->use_internal_states) { + seq_info->state_sequence_table = st_init_table(st_numcmp, st_numhash); + } +} + +void +seq_product_setup(info, seq_info, network) +atpg_info_t *info; +seq_info_t *seq_info; +network_t *network; +{ + network_t *network_copy; + range_data_t *data; + verif_options_t *options; + st_table *product_pi_ordering; + int i, position; + lsGen gen; + latch_t *l; + node_t *pi; + + seq_info->product_network = network_dup(network); + options = seq_info->seq_product_opt; + network_copy = network_dup(seq_info->product_network); + set_options(options); + options->does_verification = 1; + output_info_init(options->output_info); + options->output_info->is_product_network = 1; + extract_product_network_info(network_copy, seq_info->product_network, options); + network_free(network_copy); + assert(options->output_info->init_node != NIL(node_t)); + data = product_alloc_range_data(seq_info->product_network, options); + assert(data->init_state_fn != NIL(bdd_t)); + seq_info->product_range_data = data; + if (info->atpg_opt->use_internal_states) { + seq_info->latch_to_product_pi_ordering = array_alloc(int, info->n_latch); + product_pi_ordering = options->output_info->pi_ordering; + i = 0; + foreach_latch(seq_info->product_network, gen, l) { + pi = latch_get_output(l); + assert(st_lookup_int(product_pi_ordering, (char *) pi, &position)); + if (i < info->n_latch) { + array_insert(int, seq_info->latch_to_product_pi_ordering, i ++, position); + } + } + } +} + +static void +set_options(options) +verif_options_t *options; +{ + options->verbose = 0; + options->ordering_depth = 0; + options->n_iter = INFINITY; + options->timeout = 0; + options->keep_old_network = 1; + options->type = PRODUCT_METHOD; + options->alloc_range_data = product_alloc_range_data; + options->compute_next_states = product_compute_next_states; + options->compute_reverse_image = product_compute_reverse_image; + options->free_range_data = product_free_range_data; + options->check_output = product_check_output; + options->bdd_sizes = product_bdd_sizes; + options->use_manual_order = 0; + options->order_network = NIL(network_t); + options->last_time = util_cpu_time(); + options->total_time = 0; + options->sim_file = NIL(char); + return; +} + +void +copy_orig_bdds(seq_info) +seq_info_t *seq_info; +{ + int i; + range_data_t *range_data; + array_t *ext_outputs; + array_t *trans_outputs; + bdd_t *copy; + + range_data = seq_info->product_range_data; + ext_outputs = array_alloc(bdd_t *, array_n(range_data->external_outputs)); + trans_outputs = array_alloc(bdd_t *, array_n(range_data->transition_outputs)); + for (i = 0; i < array_n(range_data->external_outputs); i++) { + copy = bdd_dup(array_fetch(bdd_t *, range_data->external_outputs, i)); + array_insert(bdd_t *, ext_outputs, i, copy); + } + for (i = 0; i < array_n(range_data->transition_outputs); i++) { + copy = bdd_dup(array_fetch(bdd_t *, range_data->transition_outputs, i)); + array_insert(bdd_t *, trans_outputs, i, copy); + } + seq_info->orig_external_outputs = ext_outputs; + seq_info->orig_transition_outputs = trans_outputs; +} + +void +record_reset_state(seq_info, info) +seq_info_t *seq_info; +atpg_info_t *info; +{ + range_data_t *data = seq_info->range_data; + array_t *just_sequence = array_alloc(unsigned *, 0); + int key; + lsList sequence_list; + + key = convert_bdd_to_int(data->init_state_fn); + st_insert(seq_info->just_sequence_table, (char *) key, (char *) just_sequence); + seq_info->justified_states = bdd_dup(data->init_state_fn); + + if (info->atpg_opt->use_internal_states) { + seq_info->start_states = bdd_dup(data->init_state_fn); + sequence_list = lsCreate(); + st_insert(seq_info->state_sequence_table, (char *) key, + (char *) sequence_list); + } +} + +/* convert the set of start_states into equivalent product_start_states */ +void +construct_product_start_states(seq_info, n_latch) +seq_info_t *seq_info; +int n_latch; +{ + bdd_t *start_states = seq_info->start_states; + array_t *latch_to_pi_ordering = seq_info->latch_to_pi_ordering; + bdd_gen *gen; + array_t *cube; + int i, position_in_pi_ordering; + bdd_literal current_lit; + array_t *state_cube = seq_info->good_state; + + seq_info->product_start_states = bdd_zero(seq_info->product_range_data->manager); + foreach_bdd_cube(start_states, gen, cube) { + for (i = 0; i < n_latch; i++) { + position_in_pi_ordering = array_fetch(int, latch_to_pi_ordering, i); + current_lit = array_fetch(bdd_literal, cube, position_in_pi_ordering); + array_insert(bdd_literal, state_cube, i, current_lit); + } + add_minterms_to_product_start_states(seq_info, state_cube, n_latch); + } +} + +static void +add_minterms_to_product_start_states(seq_info, state_cube, n_to_check) +seq_info_t *seq_info; +array_t *state_cube; +int n_to_check; +{ + int i, val; + bdd_t *minterm_bdd, *new_product_start_states; + + for (i = n_to_check; i --; ) { + val = array_fetch(int, state_cube, i); + if (val == 2) { + array_insert(int, state_cube, i, 0); + add_minterms_to_product_start_states(seq_info, state_cube, i); + array_insert(int, state_cube, i, 1); + add_minterms_to_product_start_states(seq_info, state_cube, i); + } + } + minterm_bdd = convert_states_to_product_bdd(seq_info, state_cube, state_cube); + new_product_start_states = bdd_or(seq_info->product_start_states, minterm_bdd, 1, 1); + bdd_free(minterm_bdd); + bdd_free(seq_info->product_start_states); + seq_info->product_start_states = new_product_start_states; +} + + +bool +calculate_reachable_states(seq_info) +seq_info_t *seq_info; +{ + int i; + bdd_t *total_set, *reset_states; + bdd_t *set_i; + bdd_t *previous_set; + range_data_t *range_data = seq_info->range_data; + verif_options_t *options = seq_info->seq_opt; + array_t *reached_sets = seq_info->reached_sets; + + total_set = bdd_zero(range_data->manager); + reset_states = range_data->init_state_fn; + + for (i = 0; i < options->n_iter; i++) { + if (i == 0) { + set_i = bdd_dup(reset_states); + } else { + previous_set = bdd_dup(array_fetch(bdd_t *, reached_sets, i-1)); + set_i = product_compute_next_states(previous_set, range_data, options); + bdd_free(previous_set); + } + if (bdd_leq(set_i, total_set, 1, 1)) { + range_data->total_set = total_set; + return TRUE; + } + use_cofactored_set(&set_i, &total_set, bdd_cofactor); + array_insert(bdd_t *, reached_sets, i, set_i); + } + range_data->total_set = total_set; + return FALSE; +} + +bdd_t * +seq_derive_excitation_states(info, seq_info, n_pi_vars) +atpg_ss_info_t *info; +seq_info_t *seq_info; +int n_pi_vars; +{ + network_t *network_copy = seq_info->network_copy; + array_t *input_vars = info->sat_input_vars; + range_data_t *data = seq_info->range_data; + verif_options_t *options = seq_info->seq_opt; + bdd_t *excite_states; + st_table *table; + int i, value; + node_t *pi; + node_t *pi_in_copy; + sat_input_t sat_var; + lsGen gen; + node_t *excite_node; + node_t *n1, *n2, *n3; + + table = st_init_table(st_ptrcmp, st_ptrhash); + /* unassigned PI's are set to 2 */ + foreach_primary_input(info->network, gen, pi) { + (void) st_insert(table, (char *) pi, (char *) 2); + } + + for (i = n_pi_vars; i-- ; ) { + sat_var = array_fetch(sat_input_t, input_vars, i); + (void) st_insert(table, sat_var.info, + (char *) sat_get_value(info->atpg_sat, sat_var.sat_id)); + } + excite_node = node_constant(1); + foreach_primary_input(info->network, gen, pi) { + if ( (latch_from_node(pi)) != NIL(latch_t) ) { + assert(st_lookup_int(table, (char *) pi, &value)); + pi_in_copy = network_find_node(network_copy, pi->name); + switch (value) { + case 0: + case 1: + n1 = pi_in_copy; + n2 = node_literal(n1, value); + n3 = node_and(excite_node, n2); + node_free(n2); + node_free(excite_node); + excite_node = n3; + break; + case 2: + break; + } + } + } + network_add_node(network_copy, excite_node); + excite_states = ntbdd_node_to_local_bdd(excite_node, data->manager, options->output_info->pi_ordering); + network_delete_node(network_copy, excite_node); + st_free_table(table); + return excite_states; +} + +int +seq_reuse_just_sequence(n_inputs, n_latch, seq_info, already_justified) +int n_inputs; +int n_latch; +seq_info_t *seq_info; +bdd_t *already_justified; +{ + range_data_t *range_data = seq_info->range_data; + array_t *just_sequence = seq_info->just_sequence; + bdd_t *minterm, *justified_excite_state; + array_t *old_just_sequence; + int i, j, seq_length; + unsigned *vector, *old_vector; + + minterm = seq_get_one_minterm(range_data->manager, + already_justified, seq_info->var_table); + justified_excite_state = bdd_smooth(minterm, seq_info->real_pi_bdds); + assert(st_lookup(seq_info->just_sequence_table, + (char *) convert_bdd_to_int(justified_excite_state), + (char **) &old_just_sequence)); + seq_length = array_n(old_just_sequence); + if (ATPG_DEBUG) { + if (array_n(old_just_sequence) == 0) + assert(bdd_leq(justified_excite_state, range_data->init_state_fn, 1, 1)); + } + for (i = seq_length; i -- ; ) { + vector = array_fetch(unsigned *, just_sequence, i); + old_vector = array_fetch(unsigned *, old_just_sequence, i); + for (j = n_inputs; j -- ; ) { + vector[j] = old_vector[j]; + } + } + bdd_free(minterm); + bdd_free(justified_excite_state); + return seq_length; +} + +int +seq_state_justify(info, seq_info, excite_states) +atpg_info_t *info; +seq_info_t *seq_info; +bdd_t *excite_states; +{ + int i, stg_depth; + bdd_t *reached_excite_states; + array_t *reached_sets = seq_info->reached_sets; + + stg_depth = array_n(reached_sets); + /* i starts at 1; if the excite states contain the reset state, then + * the just_sequence was already generated by seq_reuse_just_sequence. + */ + for (i = 1; i < stg_depth; i++ ) { + reached_excite_states = bdd_and(excite_states, + array_fetch(bdd_t *, reached_sets, i), 1, 1); + if (!(bdd_is_tautology(reached_excite_states, 0))) { + reverse_generate_Sj(info, seq_info, i, reached_excite_states); + bdd_free(reached_excite_states); + return i; + } + bdd_free(reached_excite_states); + } + /* shouldn't ever get to this line, since we checked previously that + excite_states were contained in total_set */ + return -1; +} + +int +internal_states_seq_state_justify(info, seq_info, excite_states) +atpg_info_t *info; +seq_info_t *seq_info; +bdd_t *excite_states; +{ + int i; + bdd_t *total_set, *reset_states; + bdd_t *set_i; + bdd_t *previous_set; + bdd_t *reached_excite_states; + range_data_t *range_data = seq_info->range_data; + verif_options_t *options = seq_info->seq_opt; + array_t *reached_sets = seq_info->reached_sets; + + total_set = bdd_zero(range_data->manager); + reset_states = seq_info->start_states; + + for (i = 0; i < options->n_iter; i++) { + if (i == 0) { + set_i = bdd_dup(reset_states); + } else { + previous_set = bdd_dup(array_fetch(bdd_t *, reached_sets, i-1)); + set_i = product_compute_next_states(previous_set, range_data, options); + bdd_free(previous_set); + } + if (bdd_leq(set_i, total_set, 1, 1)) { + /* shouldn't ever get to this line, since we checked + * previously that excite_states were contained in total_set + */ + return -1; + } + use_cofactored_set(&set_i, &total_set, bdd_cofactor); + array_insert(bdd_t *, reached_sets, i, set_i); + reached_excite_states = bdd_and(excite_states, + array_fetch(bdd_t *, reached_sets, i), 1, 1); + if (!(bdd_is_tautology(reached_excite_states, 0))) { + reverse_generate_Sj(info, seq_info, i, reached_excite_states); + bdd_free(reached_excite_states); + return i; + } + bdd_free(reached_excite_states); + } + /* shouldn't ever get to this line, since we checked previously that + excite_states were contained in total_set */ + return -1; +} + +static void +reverse_generate_Sj(info, seq_info, depth, reached_excite_states) +atpg_info_t *info; +seq_info_t *seq_info; +int depth; +bdd_t *reached_excite_states; +{ + range_data_t *range_data = seq_info->range_data; + verif_options_t *options = seq_info->seq_opt; + array_t *reached_sets = seq_info->reached_sets; + array_t *input_trace = seq_info->input_trace; + bdd_t *minterm; + bdd_t *reset_states; + bdd_t *preimage; + bdd_t *support_reached; + bdd_t *state_justified; + bdd_t *input; + bdd_t *new_justified_states; + int i, justified_excite_state_key; + + if (info->atpg_opt->use_internal_states) { + reset_states = seq_info->start_states; + } else { + reset_states = range_data->init_state_fn; + } + minterm = seq_get_one_minterm(range_data->manager, + reached_excite_states, seq_info->var_table); + state_justified = bdd_smooth(minterm, seq_info->real_pi_bdds); + new_justified_states = bdd_or(seq_info->justified_states, state_justified, 1, 1); + bdd_free(seq_info->justified_states); + seq_info->justified_states = new_justified_states; + bdd_free(minterm); + justified_excite_state_key = convert_bdd_to_int(state_justified); + + for (i = depth; i -- ; ) { + preimage = product_compute_reverse_image(state_justified, + range_data, options); + bdd_free(state_justified); + support_reached = bdd_and(preimage, + array_fetch(bdd_t *, reached_sets, i), 1, 1); + bdd_free(preimage); + minterm = seq_get_one_minterm(range_data->manager, + support_reached, seq_info->var_table); + bdd_free(support_reached); + state_justified = bdd_smooth(minterm, seq_info->real_pi_bdds); + input = bdd_smooth(minterm, range_data->input_vars); + array_insert(bdd_t *, input_trace, i, input); + } + /* state_justified should be a start state at this point */ + assert(bdd_leq(state_justified, reset_states, 1, 1)); + if (info->atpg_opt->use_internal_states) { + seq_info->start_state_used = state_justified; + } else { + bdd_free(state_justified); + } + + convert_trace_to_sequence(info, seq_info, seq_info->just_sequence_table, + seq_info->just_sequence, seq_info->input_vars, + depth, justified_excite_state_key); + for (i = depth; i -- ; ) { + input = array_fetch(bdd_t *, input_trace, i); + bdd_free(input); + } +} + +static void +convert_trace_to_sequence(info, seq_info, table, sequence, input_vars, + seq_length, key) +atpg_info_t *info; +seq_info_t *seq_info; +st_table *table; +array_t *sequence; +array_t *input_vars; +int seq_length; +int key; +{ + array_t *input_trace = seq_info->input_trace; + int i, j, value, npi; + bdd_t *input, *var; + unsigned *vector, *vector_for_reuse; + array_t *sequence_for_reuse; + bool save_sequence_for_reuse; + array_t *old_just_sequence; + + npi = info->n_real_pi; + if (seq_length > array_n(sequence)) { + for (i = seq_length - array_n(sequence); i --; ) { + vector = ALLOC(unsigned, npi); + array_insert_last(unsigned *, sequence, vector); + } + } + save_sequence_for_reuse = FALSE; + if (table != NIL(st_table)) { + if (! st_lookup(table, (char *) key, NIL(char *))) { + save_sequence_for_reuse = TRUE; + } + } + if (save_sequence_for_reuse) { + sequence_for_reuse = array_alloc(unsigned *, seq_length); + } + /* for each vector of sequence... */ + for (i = 0; i < seq_length; i ++ ) { + input = array_fetch(bdd_t *, input_trace, i); + vector = array_fetch(unsigned *, sequence, i); + if (save_sequence_for_reuse) { + vector_for_reuse = ALLOC(unsigned, npi); + } + + /* fill in the vectors minterm by minterm: 2->0 */ + for (j = 0; j < array_n(input_vars); j++) { + var = array_fetch(bdd_t *, input_vars, j); + value = (bdd_leq(input, var, 1, 1)) ? ALL_ONE : ALL_ZERO; + vector[j] = value; + if (save_sequence_for_reuse) { + vector_for_reuse[j] = value; + } + } + if (save_sequence_for_reuse) { + array_insert(unsigned *, sequence_for_reuse, i, vector_for_reuse); + } + } + if (save_sequence_for_reuse) { + st_insert(table, (char *) key, (char *) sequence_for_reuse); + } +} + +int +seq_reuse_prop_sequence(npi, seq_info, key) +int npi; +seq_info_t *seq_info; +int key; +{ + array_t *prop_sequence = seq_info->prop_sequence; + array_t *old_prop_sequence; + int i, j, seq_length; + unsigned *vector, *old_vector; + + assert(st_lookup(seq_info->prop_sequence_table, (char *) key, + (char **) &old_prop_sequence)); + if (old_prop_sequence == NIL(array_t)) return 0; + seq_length = array_n(old_prop_sequence); + for (i = seq_length; i -- ; ) { + vector = array_fetch(unsigned *, prop_sequence, i); + old_vector = array_fetch(unsigned *, old_prop_sequence, i); + for (j = npi; j -- ; ) { + vector[j] = old_vector[j]; + } + } + return seq_length; +} + +int +seq_fault_free_propagate(info, seq_info) +atpg_info_t *info; +seq_info_t *seq_info; +{ + bdd_t *init_state; + int n_prop_vectors, key; + + init_state = convert_states_to_product_bdd(seq_info, seq_info->good_state, + seq_info->faulty_state); + n_prop_vectors = traverse_product_machine(info, seq_info, init_state, TRUE); + if (n_prop_vectors == 0) { + key = derive_prop_key(seq_info); + st_insert(seq_info->prop_sequence_table, (char *) key, NIL(char)); + } + bdd_free(init_state); + return n_prop_vectors; +} + +int +traverse_product_machine(info, seq_info, init_state, prop) +atpg_info_t *info; +seq_info_t *seq_info; +bdd_t *init_state; +bool prop; +{ + range_data_t *range_data = seq_info->product_range_data; + verif_options_t *options = seq_info->seq_product_opt; + array_t *reached_sets = seq_info->product_reached_sets; + array_t *input_trace = seq_info->input_trace; + bdd_t *current_set, *total_set, *new_current_set, *output_fn, + *incorrect_support, *incorrect_input, *incorrect_state, *tmp, + *minterm; + int output_index, iter_count, seq_length, i, init_state_key; + + current_set = bdd_dup(init_state); + total_set = bdd_zero(range_data->manager); + + iter_count = 0; + for (;;) { + if (! (seq_check_output(current_set, range_data, &output_index))) { + break; + } + if (bdd_leq(current_set, total_set, 1, 1)) return 0; + use_cofactored_set(¤t_set, &total_set, bdd_cofactor); + array_insert(bdd_t *, reached_sets, iter_count, bdd_dup(total_set)); + if (bdd_is_tautology(total_set, 1)) return 0; + new_current_set = product_compute_next_states(current_set, range_data, + options); + bdd_free(current_set); + current_set = new_current_set; + iter_count++; + } + seq_length = iter_count + 1; + output_fn = array_fetch(bdd_t *, range_data->external_outputs, output_index); + incorrect_support = bdd_and(current_set, output_fn, 1, 0); + bdd_free(current_set); + for (;;) { + minterm = seq_get_one_minterm(range_data->manager, incorrect_support, + seq_info->product_var_table); + bdd_free(incorrect_support); + incorrect_state = bdd_smooth(minterm, seq_info->product_real_pi_bdds); + incorrect_input = bdd_smooth(minterm, range_data->input_vars); + array_insert(bdd_t *, input_trace, iter_count, incorrect_input); + if (iter_count == 0) { + assert(bdd_leq(incorrect_state, init_state,1 , 1)); + if (!prop && info->atpg_opt->use_internal_states) { + seq_info->start_state_used = incorrect_state; + } else { + bdd_free(incorrect_state); + } + break; + } + iter_count--; + tmp = product_compute_reverse_image(incorrect_state, range_data, options); + bdd_free(incorrect_state); + total_set = array_fetch(bdd_t *, reached_sets, iter_count); + incorrect_support = bdd_and(tmp, total_set, 1, 1); + bdd_free(tmp); + } + if (prop) { + init_state_key = derive_prop_key(seq_info); + convert_trace_to_sequence(info, seq_info, seq_info->prop_sequence_table, + seq_info->prop_sequence, + seq_info->product_input_vars, seq_length, + init_state_key); + } else { + convert_trace_to_sequence(info, seq_info, NIL(st_table), + seq_info->prop_sequence, + seq_info->product_input_vars, seq_length, 0); + } + for (i = seq_length; i -- ; ) { + tmp = array_fetch(bdd_t *, input_trace, i); + bdd_free(tmp); + } + for (i = seq_length - 1; i -- ; ) { + tmp = array_fetch(bdd_t *, reached_sets, i); + bdd_free(tmp); + } + return seq_length; +} + +static int +seq_check_output(current_set, data, output_index) +bdd_t *current_set; +range_data_t *data; +int *output_index; +{ + int i; + bdd_t *output; + + for (i = 0; i < array_n(data->external_outputs); i++) { + output = array_fetch(bdd_t *, data->external_outputs, i); + if (! bdd_leq(current_set, output, 1, 1)) { + if (output_index != NIL(int)) { + *output_index = i; + } + return 0; + } + } + return 1; +} + +/* --insert the fault into the faulty network, and make necessary changes to + the bdd formulas for the external outputs and transition outputs + --verify the equivalence of the good and faulty machine (thus proving the + fault redundant), or else produce a distinguishing sequence (which is a + test sequence) + --put the network and range data back into its original condition +*/ +int +good_faulty_PMT(fault, info, seq_info) +fault_t *fault; +atpg_info_t *info; +seq_info_t *seq_info; +{ + range_data_t *range_data = seq_info->product_range_data; + output_info_t *output_info = seq_info->seq_product_opt->output_info; + network_t *network = seq_info->product_network; + array_t *orig_external_outputs = seq_info->orig_external_outputs; + array_t *orig_transition_outputs = seq_info->orig_transition_outputs; + saved_nodes_t saved_nodes; + array_t *node_vec; + int i, n_prop_vectors; + node_t *node; + bdd_t *output, *orig_output; + + insert_fault(network, fault, &saved_nodes); + + ntbdd_free_at_node(saved_nodes.const_node); + node_vec = network_tfo(saved_nodes.const_node, INFINITY); + for (i = array_n(node_vec); i --; ) { + node = array_fetch(node_t *, node_vec, i); + ntbdd_free_at_node(node); + } + array_free(node_vec); + + for (i = 0; i < array_n(output_info->xnor_nodes); i++) { + node = array_fetch(node_t *, output_info->xnor_nodes, i); + output = ntbdd_node_to_bdd(node, range_data->manager, + output_info->pi_ordering); + array_insert(bdd_t *, range_data->external_outputs, i, output); + } + for (i = 0; i < array_n(output_info->transition_nodes); i++) { + node = array_fetch(node_t *, output_info->transition_nodes, i); + output = ntbdd_node_to_bdd(node, range_data->manager, + output_info->pi_ordering); + array_insert(bdd_t *, range_data->transition_outputs, i, output); + } + + if (info->atpg_opt->use_internal_states) { + n_prop_vectors = traverse_product_machine(info, seq_info, + seq_info->product_start_states, FALSE); + } else { + n_prop_vectors = traverse_product_machine(info, seq_info, + range_data->init_state_fn, FALSE); + } + + ntbdd_free_at_node(saved_nodes.const_node); + node_vec = network_tfo(saved_nodes.const_node, INFINITY); + for (i = array_n(node_vec); i --; ) { + node = array_fetch(node_t *, node_vec, i); + ntbdd_free_at_node(node); + } + array_free(node_vec); + + remove_fault(network, &saved_nodes); + + for (i = 0; i < array_n(output_info->xnor_nodes); i++) { + node = array_fetch(node_t *, output_info->xnor_nodes, i); + ntbdd_free_at_node(node); + orig_output = bdd_dup(array_fetch(bdd_t *, orig_external_outputs, i)); + ntbdd_set_at_node(node, orig_output); + array_insert(bdd_t *, range_data->external_outputs, i, orig_output); + } + for (i = 0; i < array_n(output_info->transition_nodes); i++) { + node = array_fetch(node_t *, output_info->transition_nodes, i); + ntbdd_free_at_node(node); + orig_output = bdd_dup(array_fetch(bdd_t *, orig_transition_outputs, i)); + ntbdd_set_at_node(node, orig_output); + array_insert(bdd_t *, range_data->transition_outputs, i, + bdd_dup(orig_output)); + } + + return n_prop_vectors; +} + +static void +insert_fault(network, fault, saved_nodes) +network_t *network; +fault_t *fault; +saved_nodes_t *saved_nodes; +{ + int n_fanout, i; + node_t *faulty_node, *faulty_fanin, *const_node, *fanout, **fanouts; + lsGen gen; + + faulty_node = fault->node->copy; + if ((fault->fanin) == NIL(node_t)) { + faulty_fanin = NIL(node_t); + } else { + faulty_fanin = fault->fanin->copy; + } + saved_nodes->faulty_node = faulty_node; + saved_nodes->faulty_fanin = faulty_fanin; + + if (node_function(fault->node) != NODE_PI) { + const_node = (fault->value == S_A_0 ? node_constant(0) : node_constant(1)); + + if ((faulty_fanin) == NIL(node_t)) { + saved_nodes->which_case = 1; + saved_nodes->orig_faulty_node = node_dup(faulty_node); + node_replace(faulty_node, const_node); + saved_nodes->const_node = faulty_node; + } + else if (node_num_fanout(faulty_fanin) == 1) { + saved_nodes->which_case = 2; + saved_nodes->orig_faulty_fanin = node_dup(faulty_fanin); + node_replace(faulty_fanin, const_node); + saved_nodes->const_node = faulty_fanin; + } + else { + saved_nodes->which_case = 3; + network_add_node(network, const_node); + saved_nodes->const_node = const_node; + node_patch_fanin(faulty_node, faulty_fanin, const_node); + } + } + else { + saved_nodes->which_case = 4; + n_fanout = 0; + foreach_fanout(faulty_node, gen, fanout) { + if (strstr(fanout->name, ":0") != NULL) { + n_fanout ++; + } + } + const_node = (fault->value == S_A_0 ? node_constant(0) : node_constant(1)); + network_add_node(network, const_node); + fanouts = ALLOC(node_t *, n_fanout); + i = 0; + foreach_fanout(faulty_node, gen, fanout) { + if (strstr(fanout->name, ":0") != NULL) { + fanouts[i ++] = fanout; + } + } + saved_nodes->const_node = const_node; + saved_nodes->n_fanout = n_fanout; + saved_nodes->fanouts = fanouts; + for (i = 0; i < n_fanout; i ++) { + node_patch_fanin(fanouts[i], faulty_node, const_node); + } + } +} + +static void +remove_fault(network, saved_nodes) +network_t *network; +saved_nodes_t *saved_nodes; +{ + int i; + + switch (saved_nodes->which_case) { + case 1: + node_replace(saved_nodes->faulty_node, saved_nodes->orig_faulty_node); + break; + case 2: + node_replace(saved_nodes->faulty_fanin, saved_nodes->orig_faulty_fanin); + break; + case 3: + node_patch_fanin(saved_nodes->faulty_node, saved_nodes->const_node, + saved_nodes->faulty_fanin); + network_delete_node(network, saved_nodes->const_node); + break; + case 4: + for (i = 0; i < saved_nodes->n_fanout; i ++) { + node_patch_fanin(saved_nodes->fanouts[i], saved_nodes->const_node, + saved_nodes->faulty_node); + } + network_delete_node(network, saved_nodes->const_node); + FREE(saved_nodes->fanouts); + break; + default: + fprintf(sisout, "ERROR--saved_nodes->which case was not in [1,4]\n"); + break; + } +} + + diff --git a/sis/atpg/atpg_seq_util.c b/sis/atpg/atpg_seq_util.c new file mode 100644 index 0000000..df864bf --- /dev/null +++ b/sis/atpg/atpg_seq_util.c @@ -0,0 +1,384 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg_seq_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include "sis.h" +#include "atpg_int.h" + +void +free_bdds_in_array(bdd_array) +array_t *bdd_array; +{ + int i; + bdd_t *fn; + + for (i = 0; i < array_n(bdd_array); i++) { + fn = array_fetch(bdd_t *, bdd_array, i); + bdd_free(fn); + } +} + +network_t * +convert_bdd_to_network(seq_info, fn) +seq_info_t *seq_info; +bdd_t *fn; +{ + verif_options_t *options = seq_info->seq_opt; + network_t *result; + st_table *leaves = options->output_info->pi_ordering; + array_t *var_names; + st_generator *gen; + node_t *node; + int index; + + var_names = array_alloc(char *, st_count(leaves)); + st_foreach_item_int(leaves, gen, (char **) &node, &index) { + array_insert(char *, var_names, index, node->name); + } + result = ntbdd_bdd_single_to_network(fn, "bdd_out", var_names); + eliminate(result, 0, 10000); + assert(network_num_po(result) == 1); + array_free(var_names); + return result; +} + +/* This procedure converts the first cube of the input bdd into an integer. + * Don't cares (i.e. 2's) are set to 0. + */ +int +convert_bdd_to_int(state_fn) +bdd_t *state_fn; +{ + int state_int; + int i, cube_length, current_lit; + array_t *cube; + bdd_gen *gen; + + state_int = 0; + gen = bdd_first_cube(state_fn, &cube); + cube_length = array_n(cube); + for (i = 0; i < cube_length; i++) { + current_lit = array_fetch(bdd_literal, cube, i); + if (current_lit != 2) { + state_int += current_lit << i; + } + } + (void) bdd_gen_free(gen); + return state_int; +} + +int +convert_product_bdd_to_key(info, seq_info, state_fn) +atpg_info_t *info; +seq_info_t *seq_info; +bdd_t *state_fn; +{ + bdd_gen *gen; + array_t *cube; + int state_int, i, position_in_cube, position_in_key; + array_t *latch_to_product_pi_ordering = seq_info->latch_to_product_pi_ordering; + array_t *latch_to_pi_ordering = seq_info->latch_to_pi_ordering; + lsGen latch_gen; + latch_t *l; + bdd_literal current_lit; + + state_int = 0; + gen = bdd_first_cube(state_fn, &cube); + i = 0; + foreach_latch(info->network, latch_gen, l) { + position_in_cube = array_fetch(int, latch_to_product_pi_ordering, i); + current_lit = array_fetch(bdd_literal, cube, position_in_cube); + position_in_key = array_fetch(int, latch_to_pi_ordering, i ++); + if (current_lit != 2) { + state_int += current_lit << position_in_key; + } + } + (void) bdd_gen_free(gen); + return state_int; +} + +st_table * +get_pi_to_var_table(manager, info) +bdd_manager *manager; +output_info_t *info; +{ + int index; + node_t *pi; + bdd_t *var; + st_table *pi_to_var_table; + st_generator *gen; + + pi_to_var_table = st_init_table(st_ptrcmp, st_ptrhash); + st_foreach_item_int(info->pi_ordering, gen, (char **) &pi, &index) { + var = ntbdd_node_to_local_bdd(pi, manager, info->pi_ordering); + st_insert(pi_to_var_table, (char *) pi, (char *) var); + } + return pi_to_var_table; +} + +bdd_t * +seq_get_one_minterm(manager, fn, vars) +bdd_manager *manager; +bdd_t *fn; +st_table *vars; +{ +/* bdd_gen *gen; + array_t *cube; + array_t *latch_settings = seq_info->good_state; + int i, position_in_pi_ordering; + array_t *latch_to_pi_ordering = seq_info->latch_to_pi_ordering; + bdd_literal current_lit; + bdd_t *minterm; + + assert(! bdd_is_tautology(fn, 0)); + gen = bdd_first_cube(fn, &cube); + for (i = 0; i < n_latch; i++) { + position_in_pi_ordering = array_fetch(int, latch_to_pi_ordering, i); + current_lit = array_fetch(bdd_literal, cube, position_in_pi_ordering); + if (current_lit == 2) current_lit = 0; + array_insert(bdd_literal, latch_settings, i, current_lit); + } + minterm = convert_state_to_bdd(seq_info, latch_settings); + return minterm; +*/ + + int i; + bdd_t *tmp; + bdd_t *bdd_lit; + bdd_t *minterm; + bdd_gen *gen; + int n_lits; + bdd_literal *lits; + array_t *cube; + + assert(! bdd_is_tautology(fn, 0)); + + minterm = bdd_one(manager); + gen = bdd_first_cube(fn, &cube); + n_lits = array_n(cube); + + lits = ALLOC(bdd_literal, n_lits); + for (i = 0; i < n_lits; i++) { + lits[i] = array_fetch(bdd_literal, cube, i); + } + (void) bdd_gen_free(gen); + + for (i = 0; i < n_lits; i++) { + if (! st_lookup(vars, (char *) i, NIL(char *))) { + assert(lits[i] == 2); + continue; + } + switch (lits[i]) { + case 0: + case 2: + tmp = bdd_get_variable(manager, i); + bdd_lit = bdd_not(tmp); + bdd_free(tmp); + break; + case 1: + bdd_lit = bdd_get_variable(manager, i); + break; + default: + fail("unexpected literal in get_one_minterm"); + break; + } + tmp = bdd_and(minterm, bdd_lit, 1, 1); + bdd_free(minterm); + bdd_free(bdd_lit); + minterm = tmp; + } + FREE(lits); + return minterm; +} + +bdd_t * +find_good_constraint(current_set, total_set, cofactor_fn) +bdd_t *current_set; +bdd_t *total_set; +BddFn cofactor_fn; +{ + bdd_t *care_set = bdd_not(total_set); + bdd_t *result = (*cofactor_fn)(current_set, care_set); + bdd_free(care_set); + return result; +} + + +void +use_cofactored_set(current_set, total_set, cofactor_fn) +bdd_t **current_set; +bdd_t **total_set; +BddFn cofactor_fn; +{ + bdd_t *new_total_set, *new_current_set; + + new_current_set = find_good_constraint(*current_set, *total_set, cofactor_fn); + new_total_set = bdd_or(*current_set, *total_set, 1, 1); + bdd_free(*current_set); + bdd_free(*total_set); + *total_set = new_total_set; + *current_set = new_current_set; +} + +void +bdd_add_varids_to_table(vars, table) +array_t *vars; +st_table *table; +{ + int i; + int varid; + array_t *ids; + + ids = bdd_get_varids(vars); + for (i = 0; i < array_n(vars); i++) { + varid = array_fetch(int, ids, i); + st_insert(table, (char *) varid, NIL(char)); + } + array_free(ids); +} + +bdd_t * +convert_states_to_product_bdd(seq_info, good_state, faulty_state) +seq_info_t *seq_info; +array_t *good_state; +array_t *faulty_state; +{ + network_t *product_network = seq_info->product_network; + range_data_t *data = seq_info->product_range_data; + verif_options_t *options = seq_info->seq_product_opt; + bdd_t *init_state; + int i, value, state_length; + latch_t *latch; + lsGen gen; + node_t *init_node; + node_t *n1, *n2, *n3; + + state_length = array_n(good_state); + init_node = node_constant(1); + i = 0; + foreach_latch(product_network, gen, latch) { + if (i < state_length) { + value = array_fetch(int, good_state, i); + } else { + value = array_fetch(int, faulty_state, i - state_length); + } + i ++; + switch (value) { + case 0: + case 1: + n1 = latch_get_output(latch); + n2 = node_literal(n1, value); + n3 = node_and(init_node, n2); + node_free(n2); + node_free(init_node); + init_node = n3; + break; + case 2: + break; + default: + fail("latch values were not in set {0,1,2}"); + break; + } + } + network_add_node(product_network, init_node); + init_state = ntbdd_node_to_local_bdd(init_node, data->manager, options->output_info->pi_ordering); + network_delete_node(product_network, init_node); + return init_state; +} + +bdd_t * +convert_state_to_bdd(seq_info, state) +seq_info_t *seq_info; +array_t *state; +{ + network_t *network = seq_info->network_copy; + range_data_t *data = seq_info->range_data; + verif_options_t *options = seq_info->seq_opt; + bdd_t *init_state; + int i, value; + latch_t *latch; + lsGen gen; + node_t *init_node; + node_t *n1, *n2, *n3; + + init_node = node_constant(1); + i = 0; + foreach_latch(network, gen, latch) { + value = array_fetch(int, state, i++); + switch (value) { + case 0: + case 1: + n1 = latch_get_output(latch); + n2 = node_literal(n1, value); + n3 = node_and(init_node, n2); + node_free(n2); + node_free(init_node); + init_node = n3; + break; + case 2: + break; + default: + fail("latch values were not in set {0,1,2}"); + break; + } + } + network_add_node(network, init_node); + init_state = ntbdd_node_to_local_bdd(init_node, data->manager, options->output_info->pi_ordering); + network_delete_node(network, init_node); + return init_state; +} + +int +derive_prop_key(seq_info) +seq_info_t *seq_info; +{ + array_t *good_state = seq_info->good_state; + array_t *faulty_state = seq_info->faulty_state; + int state_length, i, gval, fval, good_state_int, faulty_state_int, key; + + state_length = array_n(good_state); + good_state_int = faulty_state_int = 0; + + for (i = 0; i < state_length; i++) { + gval = array_fetch(int, good_state, i); + fval = array_fetch(int, faulty_state, i); + if (ATPG_DEBUG) { + assert ((gval == 0) || (gval == 1)); + assert ((fval == 0) || (fval == 1)); + } + good_state_int += gval << i; + faulty_state_int += fval << i; + } + key = (good_state_int << state_length) + faulty_state_int; + return key; +} + +int +derive_inverted_prop_key(seq_info) +seq_info_t *seq_info; +{ + array_t *good_state = seq_info->good_state; + array_t *faulty_state = seq_info->faulty_state; + int state_length, i, gval, fval, good_state_int, faulty_state_int, key; + + state_length = array_n(good_state); + good_state_int = faulty_state_int = 0; + + for (i = 0; i < state_length; i++) { + gval = array_fetch(int, good_state, i); + fval = array_fetch(int, faulty_state, i); + if (ATPG_DEBUG) { + assert ((gval == 0) || (gval == 1)); + assert ((fval == 0) || (fval == 1)); + } + good_state_int += gval << i; + faulty_state_int += fval << i; + } + key = (faulty_state_int << state_length) + good_state_int; + return key; +} diff --git a/sis/atpg/atpg_util.c b/sis/atpg/atpg_util.c new file mode 100644 index 0000000..0f75960 --- /dev/null +++ b/sis/atpg/atpg_util.c @@ -0,0 +1,436 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/atpg_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include "sis.h" +#include "atpg_int.h" + +static int order_cmp(); +static void print_time_info(); + +/* the following are only here to let me link to +the cmu bdd package! */ +/*bool bdd_is_cube(){} +double tmg_compute_optimal_clock(){} +*/ + +static int +order_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + node_index_t *n1, *n2; + + n1 = (node_index_t *) obj1; + n2 = (node_index_t *) obj2; + return (ATPG_CLAUSE_GET(n1->node))->order - + (ATPG_CLAUSE_GET(n2->node))->order; +} + +int * +fanin_dfs_sort(node, fanin_ptr) +node_t *node; +node_index_t *fanin_ptr; +{ + node_t *fanin; + int *fanin_list, j, n; + + n = node_num_fanin(node); + foreach_fanin(node, j, fanin) { + fanin_ptr[j].node = fanin; + fanin_ptr[j].index = j; + } + qsort((void *) fanin_ptr, n, sizeof(node_index_t), order_cmp); + fanin_list = ALLOC(int, n); + for (j = 0; j < n; j ++) { + fanin_list[j] = fanin_ptr[j].index; + } + return fanin_list; +} + +node_t ** +sat_fanout_dfs_sort(node) +node_t *node; +{ + node_t *fanout, **fanout_ptr; + lsGen gen; + int j; + + fanout_ptr = ALLOC(node_t *, node_num_fanout(node)); + j = 0; + foreach_fanout(node, gen, fanout) { + fanout_ptr[j ++] = fanout; + } + qsort((void *) fanout_ptr, node_num_fanout(node), sizeof(node_t *), + order_cmp); + return fanout_ptr; +} + +void +concat_lists(l1, l2) +lsList l1; +lsList l2; +{ + lsGeneric data; + + while (lsDelBegin(l2, &data) != LS_NOMORE) { + lsNewEnd(l1, (lsGeneric) data, 0); + } + lsDestroy(l2, 0); +} + +void +create_just_sequence(seq_info, n_new_vectors, old_vectors, npi) +seq_info_t *seq_info; +int n_new_vectors; +array_t *old_vectors; +int npi; +{ + array_t *just_sequence = seq_info->just_sequence; + array_t *tmp_sequence = seq_info->prop_sequence; + int i, j, n_old_vectors; + unsigned *just_vector, *tmp_vector, *old_vector; + + n_old_vectors = array_n(old_vectors); + if ((n_old_vectors + n_new_vectors) > array_n(just_sequence)) { + for (i = n_old_vectors + n_new_vectors - array_n(just_sequence); i --; ) { + just_vector = ALLOC(unsigned, npi); + array_insert_last(unsigned *, just_sequence, just_vector); + } + } + for (i = n_new_vectors; i --; ) { + just_vector = array_fetch(unsigned *, just_sequence, i); + tmp_vector = array_fetch(unsigned *, tmp_sequence, i); + for (j = npi; j -- ; ) { + tmp_vector[j] = just_vector[j]; + } + } + for (i = n_old_vectors; i --; ) { + just_vector = array_fetch(unsigned *, just_sequence, i); + old_vector = array_fetch(unsigned *, old_vectors, i); + for (j = npi; j -- ; ) { + just_vector[j] = old_vector[j]; + } + } + for (i = n_new_vectors; i --; ) { + just_vector = array_fetch(unsigned *, just_sequence, i + n_old_vectors); + tmp_vector = array_fetch(unsigned *, tmp_sequence, i); + for (j = npi; j -- ; ) { + just_vector[j] = tmp_vector[j]; + } + } +} + +/* assign test values to each real PI of network */ +void +atpg_derive_excitation_vector(info, n_pi_vars, vector) +atpg_ss_info_t *info; +int n_pi_vars; +unsigned *vector; +{ + int i, v, ind; + sat_input_t sv; + + /* give unassigned values the value 1 */ + for (i = 0; i < info->n_real_pi; i ++) { + vector[i] = ALL_ONE; + } + for (i = 0; i < n_pi_vars; i ++) { + sv = array_fetch(sat_input_t, info->sat_input_vars, i); + v = sat_get_value(info->atpg_sat, sv.sat_id); + assert(st_lookup_int(info->pi_po_table, sv.info, &ind)); + if ((v == 0) && (ind >= info->n_latch)) { + vector[ind - info->n_latch] = ALL_ZERO; + } + } +} + +void +atpg_print_fault(fp, fault) +FILE *fp; +fault_t *fault; +{ + if (fault->value == S_A_0) { + fprintf(fp, "S_A_0: NODE: %s ", node_name(fault->node)); + } + else { + fprintf(fp, "S_A_1: NODE: %s ", node_name(fault->node)); + } + if (fault->fanin == NIL(node_t)) { + fprintf(fp, "\tOUTPUT\n"); + } + else { + fprintf(fp, "\tINPUT: %s\n", node_name(fault->fanin)); + } +} + +void +atpg_print_vectors(fp, vectors, n_inputs) +FILE *fp; +array_t *vectors; +int n_inputs; +{ + int i, j, seq_length; + unsigned *vector; + + seq_length = array_n(vectors); + for (i = 0; i < seq_length; i ++) { + vector = array_fetch(unsigned *, vectors, i); + for (j = 0; j < n_inputs; j ++) { + fprintf(fp, "%c ", (vector[j] == ALL_ZERO) ? '0':'1'); + } + fprintf(fp, "\n"); + } + fprintf(fp, "\n"); +} + +void +atpg_print_some_vectors(fp, vectors, n_inputs, seq_length) +FILE *fp; +array_t *vectors; +int n_inputs; +int seq_length; +{ + int i, j; + unsigned *vector; + + for (i = 0; i < seq_length; i ++) { + vector = array_fetch(unsigned *, vectors, i); + for (j = 0; j < n_inputs; j ++) { + fprintf(fp, "%c ", (vector[j] == ALL_ZERO) ? '0':'1'); + } + fprintf(fp, "\n"); + } + fprintf(fp, "\n"); +} + +void +atpg_print_bdd(bdd_fn, message) +bdd_t *bdd_fn; +char *message; +{ + fprintf(sisout, "%s: \n", message); + bdd_print(bdd_fn); +} + + + +void +atpg_print_results(info, seq_info) +atpg_info_t *info; +seq_info_t *seq_info; +{ + statistics_t *stats = info->statistics; + time_info_t *time_info = info->time_info; + + fprintf(sisout, "faults: %d\ttested: %d\tredundant: %d\tuntested: %d\n", + stats->initial_faults, lsLength(info->tested_faults), + lsLength(info->redundant_faults), + lsLength(info->untested_faults) + lsLength(info->final_untested_faults)); + if (info->atpg_opt->verbosity > 1) { + fprintf(sisout, "tested by RTG: %d\n", stats->n_RTG_tested); + fprintf(sisout, + "comb. red. or all excite states unreachable: %d\tverified red.: %d\n", + stats->sat_red, stats->verified_red); + fprintf(sisout, "reused justification sequences: %d\n", stats->n_just_reused); + fprintf(sisout, "random propagations: %d\tsuccessful: %d\n", + stats->n_random_propagations, stats->n_random_propagated); + fprintf(sisout, "deterministic propagations: %d\n", stats->n_det_propagations); + fprintf(sisout, "reused propagation sequences: %d\n", stats->n_prop_reused); + fprintf(sisout, + "ff prop. sequence was test in faulty machine: %d\twasn't test: %d\n", + stats->n_ff_propagated, stats->n_not_ff_propagated); + fprintf(sisout, "untested by main loop: %d\tverifications performed: %d\n", + stats->n_untested_by_main_loop, stats->n_verifications); + if (info->seq) { + fprintf(sisout, "DFS depth: %d\tstates reached in DFS: %1.0f\n", + array_n(seq_info->reached_sets), + bdd_count_onset(seq_info->range_data->total_set, + seq_info->range_data->pi_inputs)); + fprintf(sisout, "justified states: %1.0f\n", + bdd_count_onset(seq_info->justified_states, + seq_info->range_data->pi_inputs)); + } + print_time_info(time_info); + fprintf(sisout, "number of tests in test set: %d\n", stats->n_sequences); + if (info->seq) { + fprintf(sisout, "number of vectors in test set: %d\n", stats->n_vectors); + } + } +} + +static void +print_time_info(time_info) +time_info_t *time_info; +{ + long total_time = time_info->total_time; + + fprintf(sisout, "setup time:\t\t\t%.2f\t%.2f%%\n", + (time_info->setup)/1000.0, + 100.0 * time_info->setup/total_time); + fprintf(sisout, "STG traversal time:\t\t%.2f\t%.2f%%\n", + (time_info->traverse_stg)/1000.0, + 100.0 * time_info->traverse_stg/total_time); + fprintf(sisout, "RTG time:\t\t\t%.2f\t%.2f%%\n", + (time_info->RTG)/1000.0, + 100.0 * time_info->RTG/total_time); + fprintf(sisout, "SAT clause setup time:\t\t%.2f\t%.2f%%\n", + (time_info->SAT_clauses)/1000.0, + 100.0 * time_info->SAT_clauses/total_time); + fprintf(sisout, "SAT solve time:\t\t\t%.2f\t%.2f%%\n", + (time_info->SAT_solve)/1000.0, + 100.0 * time_info->SAT_solve/total_time); + fprintf(sisout, "justification time:\t\t%.2f\t%.2f%%\n", + (time_info->justify)/1000.0, + 100.0 * time_info->justify/total_time); + fprintf(sisout, "random propagation time:\t%.2f\t%.2f%%\n", + (time_info->random_propagate)/1000.0, + 100.0 * time_info->random_propagate/total_time); + fprintf(sisout, "fault-free propagation time:\t%.2f\t%.2f%%\n", + (time_info->ff_propagate)/1000.0, + 100.0 * time_info->ff_propagate/total_time); + fprintf(sisout, "fault simulation time:\t\t%.2f\t%.2f%%\n", + (time_info->fault_simulate)/1000.0, + 100.0 * time_info->fault_simulate/total_time); + fprintf(sisout, "product machine verification:\t%.2f\t%.2f%%\n", + (time_info->product_machine_verify)/1000.0, + 100.0 * time_info->product_machine_verify/total_time); + fprintf(sisout, "reverse fault simulation:\t%.2f\t%.2f%%\n", + (time_info->reverse_fault_sim)/1000.0, + 100.0 * time_info->reverse_fault_sim/total_time); + fprintf(sisout, "total time:\t\t\t%.2f\n", total_time/1000.0); +} + +sequence_t * +derive_test_sequence(ss_info, seq_info, n_just_vectors, n_prop_vectors, npi, cnt) +atpg_ss_info_t *ss_info; +seq_info_t *seq_info; +int n_just_vectors, n_prop_vectors; +int npi; +int cnt; +{ + sequence_t *sequence; + array_t *just_sequence = seq_info->just_sequence; + array_t *prop_sequence = seq_info->prop_sequence; + array_t *word_vectors = ss_info->word_vectors; + array_t *vectors; + unsigned *vector, *just_vector, *prop_vector, *word_vector; + int i, j; + + if (array_n(word_vectors) < (n_just_vectors + n_prop_vectors)) { + lengthen_word_vectors(ss_info, + n_just_vectors + n_prop_vectors - array_n(word_vectors), + ss_info->n_real_pi); + } + + sequence = ALLOC(sequence_t, 1); + sequence->vectors = array_alloc(unsigned *, n_just_vectors + n_prop_vectors); + vectors = sequence->vectors; + for (i = n_just_vectors; i -- ; ) { + just_vector = array_fetch(unsigned *, just_sequence, i); + word_vector = array_fetch(unsigned *, word_vectors, i); + vector = ALLOC(unsigned, npi); + for (j = npi; j -- ; ) { + vector[j] = just_vector[j]; + if (just_vector[j] == ALL_ZERO) { + word_vector[j] &= ~ (1 << cnt); + } else { + assert(just_vector[j] == ALL_ONE); + word_vector[j] |= (1 << cnt); + } + } + array_insert(unsigned *, vectors, i, vector); + } + for (i = n_prop_vectors; i --; ) { + prop_vector = array_fetch(unsigned *, prop_sequence, i); + word_vector = array_fetch(unsigned *, word_vectors, i + n_just_vectors); + vector = ALLOC(unsigned, npi); + for (j = npi; j -- ; ) { + vector[j] = prop_vector[j]; + if (prop_vector[j] == ALL_ZERO) { + word_vector[j] &= ~ (1 << cnt); + } else { + assert(prop_vector[j] == ALL_ONE); + word_vector[j] |= (1 << cnt); + } + } + array_insert(unsigned *, vectors, i + n_just_vectors, vector); + } + + return sequence; +} + +void +reset_word_vectors(info) +atpg_ss_info_t *info; +{ + array_t *word_vectors = info->word_vectors; + unsigned *vector; + int i, j, npi; + + npi = info->n_real_pi; + for (i = array_n(word_vectors); i --; ) { + vector = array_fetch(unsigned *, word_vectors, i); + for (j = npi; j --; ) { + vector[j] = ALL_ONE; + } + } +} + +void +lengthen_word_vectors(info, n_vectors, npi) +atpg_ss_info_t *info; +int n_vectors; +int npi; +{ + array_t *word_vectors = info->word_vectors; + int i, j; + unsigned *new_vector; + + for (i = n_vectors; i --; ) { + new_vector = ALLOC(unsigned, npi); + for (j = npi; j --; ) { + new_vector[j] = ALL_ONE; + } + array_insert_last(unsigned *, word_vectors, new_vector); + } +} + +void +fillin_word_vectors(info, seq_length, npi) +atpg_ss_info_t *info; +int seq_length; +int npi; +{ + int h, i, j; + array_t *word_vectors = info->word_vectors; + array_t *vectors; + unsigned *vector, *word_vector; + + if (array_n(word_vectors) < seq_length) { + lengthen_word_vectors(info, seq_length - array_n(word_vectors), npi); + } + + for (h = WORD_LENGTH; h --; ) { + if (info->faults_ptr[h] != NIL(fault_t)) { + vectors = info->faults_ptr[h]->sequence->vectors; + for (i = array_n(vectors); i -- ; ) { + vector = array_fetch(unsigned *, vectors, i); + word_vector = array_fetch(unsigned *, word_vectors, i); + for (j = npi; j -- ; ) { + if (vector[j] == ALL_ZERO) { + word_vector[j] &= ~ (1 << h); + } else { + assert(vector[j] == ALL_ONE); + word_vector[j] |= (1 << h); + } + } + } + } + } +} diff --git a/sis/atpg/com_atpg.c b/sis/atpg/com_atpg.c new file mode 100644 index 0000000..c088630 --- /dev/null +++ b/sis/atpg/com_atpg.c @@ -0,0 +1,359 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/com_atpg.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include +#include +#include "sis.h" +#include "atpg_int.h" + +static void print_usage(); + +static jmp_buf timeout_env; +static void timeout_handle() +{ + longjmp(timeout_env, 1); +} + +init_atpg() +{ + com_add_command("atpg", com_atpg, 1); + com_add_command("red_removal", com_redundancy_removal, 1); + com_add_command("short_tests", com_short_tests, 1); +} + +end_atpg() +{ +} + +static void +print_usage() +{ + fprintf(sisout, "usage: atpg [-dfFhnrRptvy] [file]\n"); + fprintf(sisout, "-d\tdepth of RTG sequences (default is STG depth)\n"); + fprintf(sisout, "-f\tno fault simulation\n"); + fprintf(sisout, "-F\tno reverse fault simulation\n"); + fprintf(sisout, "-h\tuse fast SAT; no non-local implications\n"); + fprintf(sisout, "-n\tnumber of sequences to fault simulate at one time\n"); + fprintf(sisout, "\t(default is system word length; n must be less than this length)\n"); + fprintf(sisout, "-r\tno RTG\n"); + fprintf(sisout, "-R\tno random propagation\n"); + fprintf(sisout, "-p\tno product machines, i.e. no fault-free propagation or \n\tgood/faulty PMT\n"); + fprintf(sisout, "-t\tperform tech decomp of network\n"); + fprintf(sisout, "-v\tverbosity\n"); + fprintf(sisout, "-y\tlength of random prop sequences (default is 20)\n"); + fprintf(sisout, "file\toutput file for test patterns\n"); +} + +int +com_atpg(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + long begin_time, time, last_time; + network_t *dc_network; + int cnt, stg_depth, n_tests, n_det_tests; + atpg_info_t *info; + atpg_ss_info_t *ss_info, *exdc_ss_info; + seq_info_t *seq_info; + fault_t *fault; + lsHandle handle; + lsGeneric data; + atpg_options_t *atpg_opt; + sequence_t *test_sequence; + fault_pattern_t *fault_info; + + if ((*network) == NIL(network_t)) return 0; + if (network_num_internal(*network) == 0) return 0; + + last_time = begin_time = util_cpu_time(); + info = atpg_info_init(*network); + info->seq = (network_num_latch(*network) ? TRUE : FALSE); + atpg_opt = info->atpg_opt; + if (!set_atpg_options(info, argc, argv)) { + print_usage(); + atpg_free_info(info); + return 1; + } + if (atpg_opt->timeout > 0) { + (void) signal(SIGALRM, timeout_handle); + (void) alarm((unsigned int) atpg_opt->timeout); + if (setjmp(timeout_env) > 0) { + fprintf(sisout, "timeout occurred after %d seconds\n", + atpg_opt->timeout); + atpg_free_info(info); + return 1; + } + } + if (atpg_opt->tech_decomp) { + decomp_tech_network(*network, INFINITY, INFINITY); + } + + ss_info = atpg_sim_sat_info_init(*network, info); + if (info->seq) { + seq_info = atpg_seq_info_init(info); + } else { + seq_info = NIL(seq_info_t); + } + atpg_gen_faults(info); + atpg_sim_setup(ss_info); + atpg_comb_sim_setup(ss_info); + atpg_sat_init(ss_info); + + /* external don't cares (only used for combinational circuits) */ + if (info->seq || ((dc_network = network_dc_network(*network)) == NULL)) { + exdc_ss_info = NIL(atpg_ss_info_t); + } else { + exdc_ss_info = atpg_sim_sat_info_init(dc_network, info); + atpg_sim_setup(exdc_ss_info); + atpg_comb_sim_setup(exdc_ss_info); + atpg_exdc_sim_link(exdc_ss_info, ss_info); + atpg_sat_init(exdc_ss_info); + } + + info->statistics->initial_faults = lsLength(info->faults); + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d total faults\n", lsLength(info->faults)); + } + + if (info->seq) { + seq_setup(seq_info, info); + if (atpg_opt->build_product_machines) { + seq_product_setup(info, seq_info, info->network); + copy_orig_bdds(seq_info); + atpg_product_setup_seq_info(seq_info); + } + record_reset_state(seq_info, info); + } + + time = util_cpu_time(); + info->time_info->setup = (time - last_time); + last_time = time; + + if (info->seq) { + assert(calculate_reachable_states(seq_info)); + seq_info->valid_states_network = convert_bdd_to_network(seq_info, + seq_info->range_data->total_set); + time = util_cpu_time(); + info->time_info->traverse_stg = (time - last_time); + last_time = time; + stg_depth = array_n(seq_info->reached_sets); + info->statistics->stg_depth = stg_depth; + atpg_sat_node_info_setup(seq_info->valid_states_network); + atpg_setup_seq_info(info, seq_info, stg_depth); + } else { + info->time_info->traverse_stg = 0; + info->statistics->stg_depth = 0; + } + + /* I think that the rtg_depth should depend on the STG depth, but I'm + * not sure that this exact length is the best choice... + */ + n_tests = 0; + if (atpg_opt->rtg) { + if (info->seq) { + if (atpg_opt->rtg_depth == -1) atpg_opt->rtg_depth = stg_depth; + } else { + atpg_opt->rtg_depth = 1; + } + info->tested_faults = atpg_random_cover(info, ss_info, exdc_ss_info, + TRUE, &n_tests); + info->statistics->n_RTG_tested = lsLength(info->tested_faults); + } else { + info->tested_faults = lsCreate(); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults covered by RTG\n", + lsLength(info->tested_faults)); + } + time = util_cpu_time(); + info->time_info->RTG = (time - last_time); + last_time = time; + + cnt = 0; + n_det_tests = 0; + while (lsFirstItem(info->faults, (lsGeneric *) &fault, &handle) == LS_OK) { + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + /* find test using three-step algorithm and fault-free assumption */ + test_sequence = generate_test(fault, info, ss_info, seq_info, + exdc_ss_info, cnt); + + switch (fault->status) { + case REDUNDANT: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + lsNewEnd(info->redundant_faults, (lsGeneric) fault, 0); + if (atpg_opt->reverse_fault_sim) { + fault_info = ALLOC(fault_pattern_t, 1); + fault_info->node = fault->node; + fault_info->fanin = fault->fanin; + fault_info->value = (fault->value == S_A_0) ? 0 : 1; + st_insert(info->redund_table, (char *) fault_info, (char *) 0); + } + lsRemoveItem(handle, (lsGeneric *) &data); + break; + case ABORTED: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Aborted by SAT\n"); + } + lsNewEnd(info->untested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + break; + case UNTESTED: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Untested\n"); + } + lsNewEnd(info->untested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + break; + case TESTED: + n_tests ++; + n_det_tests ++; + if (ATPG_DEBUG) { + assert(atpg_verify_test(ss_info, fault, test_sequence)); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Tested\n"); + } + if (atpg_opt->fault_simulate) { + ss_info->alloc_sequences[cnt] = test_sequence; + cnt ++; + } + lsNewEnd(info->tested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + test_sequence->n_covers = 1; + test_sequence->index = n_tests; + fault->sequence = test_sequence; + st_insert(info->sequence_table, (char *) test_sequence, (char *) 0); + if (atpg_opt->fault_simulate && + (cnt == atpg_opt->n_sim_sequences || n_det_tests < 3)) { + last_time = util_cpu_time(); + fault_simulate(info, ss_info, exdc_ss_info, cnt); + cnt = 0; + reset_word_vectors(ss_info); + time = util_cpu_time(); + info->time_info->fault_simulate += (time - last_time); + } + break; + default: + fail("bad fault->status returned by generate_test"); + break; + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults remaining\n", + lsLength(info->faults) + lsLength(info->untested_faults)); + } + } + info->statistics->n_untested_by_main_loop = lsLength(info->untested_faults); + + if (info->seq && atpg_opt->build_product_machines && + (info->statistics->n_untested_by_main_loop > 0)) { + last_time = util_cpu_time(); + while (lsFirstItem(info->untested_faults, + (lsGeneric *) &fault, &handle) == LS_OK) { + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + /* find test using good/faulty product machine traversal */ + last_time = util_cpu_time(); + test_sequence = generate_test_using_verification(fault, info, + ss_info, seq_info, cnt); + time = util_cpu_time(); + info->time_info->product_machine_verify += (time - last_time); + switch (fault->status) { + case REDUNDANT: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + lsNewEnd(info->redundant_faults, (lsGeneric) fault, 0); + if (atpg_opt->reverse_fault_sim) { + fault_info = ALLOC(fault_pattern_t, 1); + fault_info->node = fault->node; + fault_info->fanin = fault->fanin; + fault_info->value = (fault->value == S_A_0) ? 0 : 1; + st_insert(info->redund_table, (char *) fault_info, (char *) 0); + } + lsRemoveItem(handle, &data); + break; + case TESTED: + n_tests ++; + if (ATPG_DEBUG) { + assert(atpg_verify_test(ss_info, fault, test_sequence)); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Tested\n"); + } + if (atpg_opt->fault_simulate) { + ss_info->alloc_sequences[cnt] = test_sequence; + cnt ++; + } + lsNewEnd(info->tested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + test_sequence->n_covers = 1; + test_sequence->index = n_tests; + fault->sequence = test_sequence; + st_insert(info->sequence_table, (char *) test_sequence, + (char *) 0); + if (atpg_opt->fault_simulate && + cnt == atpg_opt->n_sim_sequences) { + last_time = util_cpu_time(); + fault_simulate(info, ss_info, exdc_ss_info, cnt); + cnt = 0; + reset_word_vectors(ss_info); + time = util_cpu_time(); + info->time_info->fault_simulate += (time - last_time); + } + break; + default: + fail("bad fault->status returned by PMT"); + break; + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults remaining\n", + lsLength(info->untested_faults)); + } + } + } + + if (atpg_opt->reverse_fault_sim) { + reverse_fault_simulate(info, ss_info); + } + print_and_destroy_sequences(info); + info->time_info->total_time = (util_cpu_time() - begin_time); + atpg_print_results(info, seq_info); + if (exdc_ss_info != NIL(atpg_ss_info_t)) { + atpg_sim_unsetup(exdc_ss_info); + atpg_comb_sim_unsetup(exdc_ss_info); + atpg_sim_free(exdc_ss_info); + atpg_sat_free(exdc_ss_info); + FREE(exdc_ss_info); + } + + atpg_sim_unsetup(ss_info); + atpg_comb_sim_unsetup(ss_info); + atpg_sim_free(ss_info); + atpg_sat_free(ss_info); + FREE(ss_info); + if (info->seq) { + if (atpg_opt->build_product_machines) { + seq_info_product_free(seq_info); + } + seq_info_free(info, seq_info); + } + lsDestroy(info->tested_faults, free_fault); + lsDestroy(info->faults, 0); + atpg_free_info(info); + sm_cleanup(); + fast_avl_cleanup(); + return 0; +} + diff --git a/sis/atpg/com_redund.c b/sis/atpg/com_redund.c new file mode 100644 index 0000000..f345ac0 --- /dev/null +++ b/sis/atpg/com_redund.c @@ -0,0 +1,951 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/com_redund.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include +#include +#include "sis.h" +#include "atpg_int.h" + +static bool remove_redundancy(); +static bool atpg_application(); +static bool quick_atpg_application(); +static void save_fault_pattern(); + +static jmp_buf timeout_env; +static void timeout_handle() +{ + longjmp(timeout_env, 1); +} + + +static void +print_usage() +{ + fprintf(sisout, "usage: red_removal [-dhnqrRptvy]\n"); + fprintf(sisout, "-d\tdepth of RTG sequences (default is STG depth)\n"); + fprintf(sisout, "-h\tuse fast SAT; no non-local implications\n"); + fprintf(sisout, "-n\tnumber of sequences to fault simulate at one time\n"); + fprintf(sisout, "\t(default is system word length; n must be less than this length)\n"); + fprintf(sisout, "-r\tno RTG\n"); + fprintf(sisout, "-R\tno random propagation\n"); + fprintf(sisout, "-q\tquick redundancy removal--remove only SNE redundancies\n"); + fprintf(sisout, "-p\tno product machines, i.e. no fault-free propagation or \n\tgood/faulty PMT\n"); + fprintf(sisout, "-t\tperform tech decomp of network\n"); + fprintf(sisout, "-v\tverbosity\n"); + fprintf(sisout, "-y\tlength of random prop sequences (default is 20)\n"); +} + +int +st_fpcmp(obj1, obj2) +char *obj1; +char *obj2; +{ + fault_pattern_t *fp1, *fp2; + int diff; + + fp1 = (fault_pattern_t *) obj1; + fp2 = (fault_pattern_t *) obj2; + diff = (int) (fp1->node - fp2->node); + if (diff) { + return diff; + } + diff = (int) (fp1->fanin - fp2->fanin); + if (diff) { + return diff; + } + diff = fp1->value - fp2->value; + return diff; +} + +int +st_fphash(obj, modulus) +char *obj; +int modulus; +{ + unsigned hash; + fault_pattern_t *fp; + + fp = (fault_pattern_t *) obj; + hash = (unsigned) (fp->node) + (unsigned) (fp->fanin) + (unsigned) (fp->value + 1); + return hash % modulus; +} + +int +com_redundancy_removal(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + long begin_time; + network_t *dc_network; + int stg_depth, n_redundant, n_setups, i; + bool output_fns_changed, redundancy_found; + atpg_info_t *info; + atpg_ss_info_t *ss_info, *exdc_ss_info; + seq_info_t *seq_info; + fault_t *tf; + atpg_options_t *atpg_opt; + fault_pattern_t *info_p; + sequence_t *sequence; + array_t *vectors; + unsigned *vector; + st_table *fp_table, *aborted_table, *prev_fault_table; + st_generator *sgen; + lsGen gen; + lsList tested_faults; + + if ((*network) == NIL(network_t)) return 0; + if (network_num_internal(*network) == 0) return 0; + + n_setups = 0; + begin_time = util_cpu_time(); + info = atpg_info_init(*network); + info->seq = (network_num_latch(info->network) ? TRUE : FALSE); + atpg_opt = info->atpg_opt; + if (!set_atpg_options(info, argc, argv)) { + print_usage(); + atpg_free_info(info); + return 1; + } + + /* This is a hack. Currently, atpg and hence redundancy removal only + works if a single initial state is given. This forces a sequential + circuit to look combinational, so the assumption is that all states + are possible initial states. This means a conservative approximation + for sequential redundancy removal. */ + + if (atpg_opt->force_comb) info->seq = FALSE; + if (atpg_opt->timeout > 0) { + (void) signal(SIGALRM, timeout_handle); + (void) alarm((unsigned int) atpg_opt->timeout); + if (setjmp(timeout_env) > 0) { + fprintf(sisout, "timeout occurred after %d seconds\n", + atpg_opt->timeout); + atpg_free_info(info); + return 1; + } + } + if (atpg_opt->tech_decomp) { + decomp_tech_network(*network, INFINITY, INFINITY); + } + network_sweep(*network); + + ss_info = atpg_sim_sat_info_init(*network, info); + if (!info->seq) { + seq_info = NIL(seq_info_t); + } + + fp_table = st_init_table(st_fpcmp, st_fphash); + aborted_table = st_init_table(st_fpcmp, st_fphash); + prev_fault_table = st_init_table(st_fpcmp, st_fphash); + output_fns_changed = TRUE; + n_redundant = -1; + /* external don't cares */ + if (info->seq || ((dc_network = network_dc_network(*network)) == NULL)) { + exdc_ss_info = NIL(atpg_ss_info_t); + } else { + exdc_ss_info = atpg_sim_sat_info_init(dc_network, info); + atpg_sim_setup(exdc_ss_info); + atpg_comb_sim_setup(exdc_ss_info); + atpg_sat_init(exdc_ss_info); + } + + do { + n_redundant ++; + /* setup data structures for one redundancy removal */ + /* Only need to update the output functions if the previous redundancy + * was an "observability" redundancy. + */ + if (output_fns_changed) { + if (n_redundant != 0) { + atpg_sim_unsetup(ss_info); + } + atpg_sim_setup(ss_info); + if (info->seq) { + if (n_redundant != 0) { + seq_info_free(info, seq_info); + } + n_setups += 1; + seq_info = atpg_seq_info_init(info); + seq_setup(seq_info, info); + record_reset_state(seq_info, info); + assert(calculate_reachable_states(seq_info)); + seq_info->valid_states_network = convert_bdd_to_network(seq_info, + seq_info->range_data->total_set); + stg_depth = array_n(seq_info->reached_sets); + info->statistics->stg_depth = stg_depth; + atpg_sat_node_info_setup(seq_info->valid_states_network); + atpg_setup_seq_info(info, seq_info, stg_depth); + } + } + + atpg_gen_faults(info); + atpg_comb_sim_setup(ss_info); + if (exdc_ss_info != NIL(atpg_ss_info_t)) { + atpg_exdc_sim_link(ss_info, ss_info); + } + + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d total faults\n", lsLength(info->faults)); + } + + /* start off with RTG */ + if (n_redundant == 0) { + if (atpg_opt->rtg_depth == -1) { + if (info->seq) atpg_opt->rtg_depth = stg_depth; + else atpg_opt->rtg_depth = 1; + } + if (atpg_opt->quick_redund) { + tested_faults = lsCreate(); + } else { + tested_faults = atpg_random_cover(info, ss_info, exdc_ss_info, + TRUE, NIL(int)); + } + info->statistics->n_RTG_tested = lsLength(tested_faults); + foreach_fault(tested_faults, gen, tf) { + save_fault_pattern(fp_table, prev_fault_table, tf); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults covered by RTG\n", + lsLength(tested_faults)); + } + /* patterns still retained */ + lsDestroy(tested_faults, free_fault); + } + if (atpg_opt->quick_redund) { + redundancy_found = quick_atpg_application(info, ss_info, seq_info, + exdc_ss_info, fp_table, aborted_table, + prev_fault_table, &output_fns_changed); + } else { + redundancy_found = atpg_application(info, ss_info, seq_info, + exdc_ss_info, fp_table, aborted_table, + prev_fault_table, &output_fns_changed); + } + + if (network_num_latch(*network) != info->n_latch) { + info->n_po = network_num_po(*network); + info->n_pi = network_num_pi(*network); + info->n_latch = network_num_latch(*network); + if (info->n_latch == 0) { + seq_info_free(info, seq_info); + info->seq = FALSE; + } + output_fns_changed = TRUE; + if (atpg_opt->quick_redund) { + st_foreach_item(fp_table, sgen, (char **) &info_p, NIL(char *)) { + st_delete(fp_table, (char **) &info_p, NIL(char *)); + FREE(info_p); + } + st_foreach_item(info->sequence_table, sgen, (char **) &sequence, + NIL(char *)) { + st_delete(info->sequence_table, (char **) &sequence, + NIL(char *)); + vectors = sequence->vectors; + for (i = array_n(vectors); i -- ; ) { + vector = array_fetch(unsigned *, vectors, i); + FREE(vector); + } + array_free(vectors); + FREE(sequence); + } + } + } + lsDestroy(info->faults, free_fault); + atpg_comb_sim_unsetup(ss_info); + + } while (redundancy_found == TRUE); + + info->time_info->total_time = (util_cpu_time() - begin_time); + + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "number of setups: %d\n", n_setups); + fprintf(sisout, "total time:\t\t\t%.2f\n", + info->time_info->total_time/1000.0); + } + + /* free all aborted faults and fault-pattern pairs */ + st_foreach_item(fp_table, sgen, (char **) &info_p, (char **) &sequence) { + FREE(info_p); + } + st_free_table(fp_table); + st_foreach_item(prev_fault_table, sgen, (char **) &info_p, NIL(char *)) { + FREE(info_p); + } + st_free_table(prev_fault_table); + st_foreach_item(aborted_table, sgen, (char **) &info_p, NIL(char *)) { + FREE(info_p); + } + st_free_table(aborted_table); + + print_and_destroy_sequences(info); + if (exdc_ss_info != NIL(atpg_ss_info_t)) { + atpg_sim_unsetup(exdc_ss_info); + atpg_comb_sim_unsetup(exdc_ss_info); + atpg_sim_free(exdc_ss_info); + atpg_sat_free(exdc_ss_info); + FREE(exdc_ss_info); + } + atpg_sim_unsetup(ss_info); + atpg_sim_free(ss_info); + FREE(ss_info); + if (info->seq) { + seq_info_free(info, seq_info); + } + atpg_free_info(info); + sm_cleanup(); + fast_avl_cleanup(); + return 0; +} + +static bool +atpg_application(info, ss_info, seq_info, exdc_info, fp_table, aborted_table, + prev_fault_table, output_fns_changed) +atpg_info_t *info; +atpg_ss_info_t *ss_info; +seq_info_t *seq_info; +atpg_ss_info_t *exdc_info; +st_table *fp_table; +st_table *aborted_table; +st_table *prev_fault_table; +bool *output_fns_changed; +{ + atpg_options_t *atpg_opt = info->atpg_opt; + bool pi_seen_before; + int hit, *slot, count, cnt; + fault_t *fault, *tf; + fault_pattern_t fault_info, *new_info; + st_generator *sgen; + lsList seen_faults, covered, untested_faults; + lsHandle handle; + lsGeneric data; + lsGen gen; + sequence_t *test_sequence; + + untested_faults = lsCreate(); + /* reset aborted fault flags */ + st_foreach_item(aborted_table, sgen, (char **) &new_info, NIL(char *)) { + st_insert(aborted_table, (char *) new_info, 0); + } + + /* retain only previously unseen faults */ + count = lsLength(info->faults); + seen_faults = lsCreate(); + atpg_sat_init(ss_info); + while (count-- && lsFirstItem(info->faults, (lsGeneric *) &fault, &handle) == LS_OK) { + fault_info.node = fault->node; + fault_info.fanin = fault->fanin; + fault_info.value = (fault->value == S_A_0) ? 0 : 1 ; + lsRemoveItem(handle, &data); + if (st_lookup(prev_fault_table, (char *) &fault_info, NIL(char *))) { + lsNewEnd(seen_faults, (lsGeneric) data, 0); + } + else { + lsNewEnd(info->faults, (lsGeneric) data, 0); + } + } + cnt = 0; + /* deterministic ATPG on previously unseen faults only */ + while (lsFirstItem(info->faults, (lsGeneric *) &fault, &handle) == LS_OK) { + fault_info.node = fault->node; + fault_info.fanin = fault->fanin; + fault_info.value = (fault->value == S_A_0) ? 0 : 1 ; + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + + /* find test using three-step algorithm and fault-free assumption */ + test_sequence = generate_test(fault, info, ss_info, seq_info, + exdc_info, cnt); + + switch (fault->status) { + case REDUNDANT: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + pi_seen_before = remove_redundancy(info, ss_info, fault, + output_fns_changed); + lsRemoveItem(handle, &data); + free_fault((fault_t *)data); + break; + case ABORTED: + case UNTESTED: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Untested\n"); + } + assert(! st_lookup(aborted_table, (char *) &fault_info, NIL(char *))); + new_info = ALLOC(fault_pattern_t, 1); + *new_info = fault_info; + st_insert(aborted_table, (char *) new_info, (char *) 0); + assert(! st_lookup(prev_fault_table, (char *) &fault_info, NIL(char *))); + new_info = ALLOC(fault_pattern_t, 1); + *new_info = fault_info; + st_insert(prev_fault_table, (char *) new_info, 0); + lsRemoveItem(handle, &data); + lsNewEnd(untested_faults, (lsGeneric) data, 0); + break; + case TESTED: /* tested fault */ + if (ATPG_DEBUG) { + assert(atpg_verify_test(ss_info, fault, test_sequence)); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Tested\n"); + } + cnt ++; + lsRemoveItem(handle, &data); + test_sequence->n_covers = 1; + fault->sequence = test_sequence; + st_insert(info->sequence_table, (char *) test_sequence, (char *) 0); + save_fault_pattern(fp_table, prev_fault_table, fault); + free_fault((fault_t *)data); + if (cnt == atpg_opt->n_sim_sequences) { + covered = atpg_seq_single_fault_simulate(ss_info, exdc_info, + ss_info->word_vectors, info->faults, + NIL(sequence_t *), 0); + concat_lists(covered, + atpg_seq_single_fault_simulate(ss_info, + exdc_info, ss_info->word_vectors, + untested_faults, NIL(sequence_t *), 0)); + extract_test_sequences(info, ss_info, covered, + ss_info->word_vectors, + NIL(int), info->n_real_pi); + foreach_fault(covered, gen, tf) { + save_fault_pattern(fp_table, prev_fault_table, tf); + } + lsDestroy(covered, free_fault); + cnt = 0; + reset_word_vectors(ss_info); + } + break; + default: + fail("bad fault->status returned by generate_test"); + break; + } + /* pi's cannot be removed */ + if (fault->status == REDUNDANT && !pi_seen_before) { + lsDestroy(seen_faults, free_fault); + lsDestroy(untested_faults, free_fault); + return TRUE; + } + } + + /* look at previously-seen faults now */ + concat_lists(info->faults, seen_faults); + + /* get faults using previous patterns */ + atpg_simulate_old_sequences(info, ss_info, exdc_info, fp_table, untested_faults); + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults remaining after using previous tests\n", + lsLength(info->faults) + lsLength(untested_faults)); + } + + cnt = 0; + /* now deterministic TPG on remaining faults */ + while (lsFirstItem(info->faults, (lsGeneric *) &fault, &handle) == LS_OK) { + fault_info.node = fault->node; + fault_info.fanin = fault->fanin; + fault_info.value = (fault->value == S_A_0) ? 0 : 1 ; + hit = st_find(aborted_table, (char *) &fault_info, (char ***) &slot); + if (hit && !(*slot)) { + *slot = 1; + lsRemoveItem(handle, &data); + lsNewEnd(info->faults, (lsGeneric) data, 0); + continue; + } + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + if (info->seq) { + if (!seq_info->product_machine_built && atpg_opt->deterministic_prop + && atpg_opt->build_product_machines) { + seq_product_setup(info, seq_info, info->network); + copy_orig_bdds(seq_info); + atpg_product_setup_seq_info(seq_info); + } + } + + /* find test using three-step algorithm and fault-free assumption */ + test_sequence = generate_test(fault, info, ss_info, seq_info, + exdc_info, cnt); + + switch (fault->status) { + case REDUNDANT: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + pi_seen_before = remove_redundancy(info, ss_info, fault, + output_fns_changed); + lsRemoveItem(handle, &data); + free_fault((fault_t *)data); + break; + case ABORTED: + case UNTESTED: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Untested\n"); + } + if (! st_lookup(aborted_table, (char *) &fault_info, NIL(char *))) { + new_info = ALLOC(fault_pattern_t, 1); + *new_info = fault_info; + st_insert(aborted_table, (char *) new_info, (char *) 1); + } + assert(st_lookup(prev_fault_table, (char *) &fault_info, NIL(char *))); + lsRemoveItem(handle, &data); + lsNewEnd(untested_faults, (lsGeneric) data, 0); + break; + case TESTED: /* tested fault */ + if (ATPG_DEBUG) { + assert(atpg_verify_test(ss_info, fault, test_sequence)); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Tested\n"); + } + cnt ++; + lsRemoveItem(handle, &data); + test_sequence->n_covers = 1; + fault->sequence = test_sequence; + st_insert(info->sequence_table, (char *) test_sequence, (char *) 0); + save_fault_pattern(fp_table, prev_fault_table, fault); + free_fault((fault_t *)data); + if (cnt == atpg_opt->n_sim_sequences) { + covered = atpg_seq_single_fault_simulate(ss_info, + exdc_info, ss_info->word_vectors, info->faults, + NIL(sequence_t *), 0); + concat_lists(covered, + atpg_seq_single_fault_simulate(ss_info, + exdc_info, ss_info->word_vectors, + untested_faults, NIL(sequence_t *), 0)); + extract_test_sequences(info, ss_info, covered, + ss_info->word_vectors, + NIL(int), info->n_real_pi); + foreach_fault(covered, gen, tf) { + save_fault_pattern(fp_table, prev_fault_table, tf); + } + lsDestroy(covered, free_fault); + cnt = 0; + reset_word_vectors(ss_info); + } + break; + default: + fail("bad fault->status returned by generate_test"); + break; + } + + /* pi's cannot be removed */ + if (fault->status == REDUNDANT && !pi_seen_before) { + if (info->seq) { + if (seq_info->product_machine_built) { + seq_info_product_free(seq_info); + } + } + lsDestroy(untested_faults, free_fault); + return TRUE; + } + } + + /* now product machine traversal on remaining untested faults */ + if (info->seq && atpg_opt->build_product_machines) { + while (lsFirstItem(untested_faults, (lsGeneric *) &fault, &handle) == LS_OK) { + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + if (!seq_info->product_machine_built) { + seq_product_setup(info, seq_info, info->network); + copy_orig_bdds(seq_info); + atpg_product_setup_seq_info(seq_info); + } + + /* find test using PMT */ + test_sequence = generate_test_using_verification(fault, info, ss_info, + seq_info, cnt); + + switch (fault->status) { + case REDUNDANT: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + pi_seen_before = remove_redundancy(info, ss_info, fault, + output_fns_changed); + lsRemoveItem(handle, &data); + free_fault((fault_t *)data); + break; + case ABORTED: + case UNTESTED: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Untested by PMT\n"); + } + assert(st_lookup(aborted_table, (char *) &fault_info, NIL(char *))); + assert(st_lookup(prev_fault_table, (char *) &fault_info, NIL(char *))); + lsRemoveItem(handle, &data); + free_fault((fault_t *)data); + break; + case TESTED: /* tested fault */ + if (ATPG_DEBUG) { + assert(atpg_verify_test(ss_info, fault, test_sequence)); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Tested\n"); + } + cnt ++; + lsRemoveItem(handle, &data); + test_sequence->n_covers = 1; + fault->sequence = test_sequence; + st_insert(info->sequence_table, (char *) test_sequence, (char *) 0); + save_fault_pattern(fp_table, prev_fault_table, fault); + free_fault((fault_t *)data); + if (cnt == atpg_opt->n_sim_sequences) { + covered = atpg_seq_single_fault_simulate(ss_info, + exdc_info, ss_info->word_vectors, + untested_faults, NIL(sequence_t *), 0); + extract_test_sequences(info, ss_info, covered, + ss_info->word_vectors, + NIL(int), info->n_real_pi); + foreach_fault(covered, gen, tf) { + save_fault_pattern(fp_table, prev_fault_table, tf); + } + lsDestroy(covered, free_fault); + cnt = 0; + reset_word_vectors(ss_info); + } + break; + default: + fail("bad fault->status returned by generate_test"); + break; + } + + /* pi's cannot be removed */ + if (fault->status == REDUNDANT && !pi_seen_before) { + lsDestroy(untested_faults, free_fault); + if (seq_info->product_machine_built) { + seq_info_product_free(seq_info); + } + return TRUE; + } + } + } + /* if a redundancy was removed, then sat has already been freed in + * the remove_redundancy procedure. + */ + atpg_sat_free(ss_info); + lsDestroy(untested_faults, free_fault); + if (info->seq) { + if (seq_info->product_machine_built) { + seq_info_product_free(seq_info); + } + } + return FALSE; +} + +static bool +quick_atpg_application(info, ss_info, seq_info, exdc_info, fp_table, + aborted_table, prev_fault_table, output_fns_changed) +atpg_info_t *info; +atpg_ss_info_t *ss_info; +seq_info_t *seq_info; +atpg_ss_info_t *exdc_info; +st_table *fp_table; +st_table *aborted_table; +st_table *prev_fault_table; +bool *output_fns_changed; +{ + atpg_options_t *atpg_opt = info->atpg_opt; + bool pi_seen_before; + int hit, *slot, count, cnt, n_pi_vars; + fault_t *fault, *tf; + fault_pattern_t fault_info, *new_info; + st_generator *sgen; + lsList seen_faults, covered, untested_faults; + lsHandle handle; + lsGeneric data; + lsGen gen; + sat_result_t sat_value; + + untested_faults = lsCreate(); + /* reset aborted fault flags */ + st_foreach_item(aborted_table, sgen, (char **) &new_info, NIL(char *)) { + st_insert(aborted_table, (char *) new_info, 0); + } + + /* retain only previously unseen faults */ + count = lsLength(info->faults); + seen_faults = lsCreate(); + atpg_sat_init(ss_info); + while (count-- && lsFirstItem(info->faults, (lsGeneric *) &fault, &handle) == LS_OK) { + fault_info.node = fault->node; + fault_info.fanin = fault->fanin; + fault_info.value = (fault->value == S_A_0) ? 0 : 1 ; + lsRemoveItem(handle, &data); + if (st_lookup(prev_fault_table, (char *) &fault_info, NIL(char *))) { + lsNewEnd(seen_faults, (lsGeneric) data, 0); + } + else { + lsNewEnd(info->faults, (lsGeneric) data, 0); + } + } + cnt = 0; + /* deterministic SNE redundancy identification on previously unseen + faults only + */ + while (lsFirstItem(info->faults, (lsGeneric *) &fault, &handle) == LS_OK) { + fault_info.node = fault->node; + fault_info.fanin = fault->fanin; + fault_info.value = (fault->value == S_A_0) ? 0 : 1 ; + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + sat_reset(ss_info->atpg_sat); + n_pi_vars = atpg_network_fault_clauses(ss_info, exdc_info, seq_info, fault); + sat_value = sat_solve(ss_info->atpg_sat, atpg_opt->fast_sat, + atpg_opt->verbosity); + switch (sat_value) { + case SAT_ABSURD: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + fault->redund_type = CONTROL; + pi_seen_before = remove_redundancy(info, ss_info, fault, + output_fns_changed); + lsRemoveItem(handle, &data); + free_fault((fault_t *)data); + break; + case SAT_GAVEUP: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Aborted by SAT\n"); + } + assert(! st_lookup(aborted_table, (char *) &fault_info, NIL(char *))); + new_info = ALLOC(fault_pattern_t, 1); + *new_info = fault_info; + st_insert(aborted_table, (char *) new_info, (char *) 0); + assert(! st_lookup(prev_fault_table, (char *) &fault_info, NIL(char *))); + new_info = ALLOC(fault_pattern_t, 1); + *new_info = fault_info; + st_insert(prev_fault_table, (char *) new_info, 0); + lsRemoveItem(handle, &data); + lsNewEnd(untested_faults, (lsGeneric) data, 0); + break; + case SAT_SOLVED: /* tested fault */ + fault->sequence = derive_comb_test(ss_info, n_pi_vars, cnt); + lsRemoveItem(handle, &data); + save_fault_pattern(fp_table, prev_fault_table, fault); + free_fault((fault_t *)data); + cnt ++; + st_insert(info->sequence_table, (char *) fault->sequence, (char *) 0); + if (cnt == atpg_opt->n_sim_sequences) { + covered = atpg_comb_single_fault_simulate(ss_info, exdc_info, + ss_info->word_vectors, info->faults); + concat_lists(covered, + atpg_comb_single_fault_simulate(ss_info, + exdc_info, ss_info->word_vectors, + untested_faults)); + extract_test_sequences(info, ss_info, covered, + ss_info->word_vectors, + NIL(int), info->n_pi); + foreach_fault(covered, gen, tf) { + save_fault_pattern(fp_table, prev_fault_table, tf); + } + lsDestroy(covered, free_fault); + cnt = 0; + reset_word_vectors(ss_info); + } + break; + default: + fail("bad fault->status returned by generate_test"); + break; + } + /* pi's cannot be removed */ + if (sat_value == SAT_ABSURD && !pi_seen_before) { + lsDestroy(seen_faults, free_fault); + lsDestroy(untested_faults, free_fault); + return TRUE; + } + } + + /* look at previously-seen faults now */ + concat_lists(info->faults, seen_faults); + + /* get faults using previous patterns */ + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults remaining\n", + lsLength(info->faults) + lsLength(untested_faults)); + } + atpg_comb_simulate_old_sequences(info, ss_info, exdc_info, fp_table, + untested_faults); + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults remaining after using previous tests\n", + lsLength(info->faults) + lsLength(untested_faults)); + } + + cnt = 0; + /* now deterministic SNE identification on remaining faults */ + while (lsFirstItem(info->faults, (lsGeneric *) &fault, &handle) == LS_OK) { + fault_info.node = fault->node; + fault_info.fanin = fault->fanin; + fault_info.value = (fault->value == S_A_0) ? 0 : 1 ; + hit = st_find(aborted_table, (char *) &fault_info, (char ***) &slot); + if (hit && !(*slot)) { + *slot = 1; + lsRemoveItem(handle, &data); + lsNewEnd(info->faults, (lsGeneric) data, 0); + continue; + } + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + + sat_reset(ss_info->atpg_sat); + n_pi_vars = atpg_network_fault_clauses(ss_info, exdc_info, seq_info, fault); + sat_value = sat_solve(ss_info->atpg_sat, atpg_opt->fast_sat, + atpg_opt->verbosity); + switch (sat_value) { + case SAT_ABSURD: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + fault->redund_type = CONTROL; + pi_seen_before = remove_redundancy(info, ss_info, fault, + output_fns_changed); + lsRemoveItem(handle, &data); + free_fault((fault_t *)data); + break; + case SAT_GAVEUP: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Aborted by SAT\n"); + } + if (! st_lookup(aborted_table, (char *) &fault_info, NIL(char *))) { + new_info = ALLOC(fault_pattern_t, 1); + *new_info = fault_info; + st_insert(aborted_table, (char *) new_info, (char *) 1); + } + assert(st_lookup(prev_fault_table, (char *) &fault_info, NIL(char *))); + lsRemoveItem(handle, &data); + lsNewEnd(untested_faults, (lsGeneric) data, 0); + break; + case SAT_SOLVED: /* tested fault */ + fault->sequence = derive_comb_test(ss_info, n_pi_vars, cnt); + lsRemoveItem(handle, &data); + save_fault_pattern(fp_table, prev_fault_table, fault); + free_fault((fault_t *)data); + cnt ++; + st_insert(info->sequence_table, (char *) fault->sequence, (char *) 0); + if (cnt == atpg_opt->n_sim_sequences) { + covered = atpg_comb_single_fault_simulate(ss_info, exdc_info, + ss_info->word_vectors, info->faults); + concat_lists(covered, + atpg_comb_single_fault_simulate(ss_info, + exdc_info, ss_info->word_vectors, + untested_faults)); + extract_test_sequences(info, ss_info, covered, + ss_info->word_vectors, + NIL(int), info->n_pi); + foreach_fault(covered, gen, tf) { + save_fault_pattern(fp_table, prev_fault_table, tf); + } + lsDestroy(covered, free_fault); + cnt = 0; + reset_word_vectors(ss_info); + } + break; + default: + fail("bad fault->status returned by generate_test"); + break; + } + + /* pi's cannot be removed */ + if (sat_value == SAT_ABSURD && !pi_seen_before) { + lsDestroy(untested_faults, free_fault); + return TRUE; + } + } + + /* If a redundancy was removed, then sat has already been freed in + * the remove_redundancy procedure. + */ + atpg_sat_free(ss_info); + lsDestroy(untested_faults, free_fault); + return FALSE; +} + + +/* TRUE if pi redundancy had been handled before + * FALSE otherwise + */ +static bool +remove_redundancy(info, ss_info, fault, output_fns_changed) +atpg_info_t *info; +atpg_ss_info_t *ss_info; +fault_t *fault; +bool *output_fns_changed; +{ + int n_fanout, i; + node_t *const_node, *fanout, **fanouts; + lsGen gen; + + n_fanout = node_num_fanout(fault->node); + if (node_function(fault->node) == NODE_PI && n_fanout == 0) { + return TRUE; + } + /* free sat here, since it's impossible to free completely after + * a redundancy has been removed + */ + atpg_sat_free(ss_info); + + const_node = (fault->value == S_A_0 ? node_constant(0) : node_constant(1)); + network_add_node(info->network, const_node); + if (fault->fanin == NIL(node_t)) { + fanouts = ALLOC(node_t *, n_fanout); + i = 0; + foreach_fanout(fault->node, gen, fanout) { + fanouts[i ++] = fanout; + } + for (i = 0; i < n_fanout; i ++) { + node_patch_fanin(fanouts[i], fault->node, const_node); + } + FREE(fanouts); + } + else { + node_patch_fanin(fault->node, fault->fanin, const_node); + } + + network_sweep(info->network); + if (fault->redund_type == CONTROL) { + *output_fns_changed = FALSE; + } else { + assert(fault->redund_type == OBSERVE); + *output_fns_changed = TRUE; + } + return FALSE; +} + +/* matches fault with a sequence that detects it */ +static void +save_fault_pattern(fault_pattern_table, prev_fault_table, f) +st_table *fault_pattern_table; +st_table *prev_fault_table; +fault_t *f; +{ + sequence_t **slot; + fault_pattern_t fp, *fp_ptr; + + fp.node = f->node; + fp.fanin = f->fanin; + fp.value = (f->value == S_A_0) ? 0 : 1; + if (! st_find(fault_pattern_table, (char *) &fp, (char ***) &slot)) { + fp_ptr = ALLOC(fault_pattern_t, 1); + *fp_ptr = fp; + st_insert(fault_pattern_table, (char *) fp_ptr, (char *) f->sequence); + } + /* update sequence stored with fault */ + else { + *slot = f->sequence; + } + if (! st_lookup(prev_fault_table, (char *) &fp, NIL(char *))) { + fp_ptr = ALLOC(fault_pattern_t, 1); + *fp_ptr = fp; + st_insert(prev_fault_table, (char *) fp_ptr, 0); + } +} + diff --git a/sis/atpg/com_short_t.c b/sis/atpg/com_short_t.c new file mode 100644 index 0000000..50ab63e --- /dev/null +++ b/sis/atpg/com_short_t.c @@ -0,0 +1,651 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/com_short_t.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include +#include +#include "sis.h" +#include "atpg_int.h" + +static void print_usage(); +static int set_short_tests_options(); +static void update_start_states(); +static void update_product_start_states(); + +static jmp_buf timeout_env; +static void timeout_handle() +{ + longjmp(timeout_env, 1); +} + +static void +print_usage() +{ + fprintf(sisout, "usage: short_tests [-fFhirtvV] [fil\n"); + fprintf(sisout, "-f\tno fault simulation\n"); + fprintf(sisout, "-F\tno reverse fault simulation\n"); + fprintf(sisout, "-h\tuse fast SAT; no non-local implications\n"); + fprintf(sisout, "-i\tdo not use internal states as start states for tests\n"); + fprintf(sisout, "-r\tuse random test generation and propagation\n"); + fprintf(sisout, "-t\tperform tech decomp of network\n"); + fprintf(sisout, "-v\tverbosity\n"); + fprintf(sisout, "-V\tall tests generated by product machine traversal\n"); + fprintf(sisout, "file\toutput file for test patterns\n"); +} + +static int +set_short_tests_options(info, argc, argv) +atpg_info_t *info; +int argc; +char **argv; +{ + atpg_options_t *atpg_opt; + int c; + char *fname, *real_filename; + + atpg_opt = info->atpg_opt; + + /* default values */ + atpg_opt->quick_redund = FALSE; + atpg_opt->reverse_fault_sim = TRUE; + atpg_opt->PMT_only = FALSE; + atpg_opt->use_internal_states = TRUE; + atpg_opt->n_sim_sequences = WORD_LENGTH; + atpg_opt->deterministic_prop = TRUE; + atpg_opt->random_prop = FALSE; + atpg_opt->rtg_depth = -1; + atpg_opt->fault_simulate = TRUE; + atpg_opt->fast_sat = FALSE; + atpg_opt->rtg = FALSE; + atpg_opt->build_product_machines = TRUE; + atpg_opt->tech_decomp = FALSE; + atpg_opt->timeout = 0; + atpg_opt->verbosity = 0; + atpg_opt->prop_rtg_depth = 10; + atpg_opt->n_random_prop_iter = 1; + atpg_opt->print_sequences = FALSE; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "DfFhirtT:v:V")) != EOF) { + switch (c) { + case 'D': + atpg_opt->deterministic_prop = FALSE; + break; + case 'f': + atpg_opt->fault_simulate = FALSE; + break; + case 'F': + atpg_opt->reverse_fault_sim = FALSE; + break; + case 'h': + atpg_opt->fast_sat = TRUE; + break; + case 'i': + atpg_opt->use_internal_states = FALSE; + break; + case 'r': + atpg_opt->rtg = TRUE; + atpg_opt->random_prop = TRUE; + break; + case 't': + atpg_opt->tech_decomp = TRUE; + break; + case 'T': + atpg_opt->timeout = atoi(util_optarg); + if (atpg_opt->timeout < 0 || atpg_opt->timeout > 3600 * 24 * 365) { + return 0; + } + break; + case 'v': + atpg_opt->verbosity = atoi(util_optarg); + break; + case 'V': + atpg_opt->PMT_only = TRUE; + break; + default: + return 0; + } + } + if (argc - util_optind == 1) { + atpg_opt->print_sequences = TRUE; + fname = argv[util_optind]; + atpg_opt->fp = com_open_file(fname, "w", &real_filename, /* silent */ 0); + atpg_opt->real_filename = real_filename; + if (atpg_opt->fp == NULL) { + FREE(real_filename); + return 0; + } + } + else if (argc - util_optind != 0) { + return 0; + } + return 1; /* everything's OK */ +} + +int +com_short_tests(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + long begin_time, time, last_time; + int stg_depth, n_tests; + atpg_info_t *info; + atpg_ss_info_t *ss_info; + seq_info_t *seq_info; + fault_t *fault; + lsHandle handle; + lsGeneric data; + atpg_options_t *atpg_opt; + sequence_t *test_sequence; + lsList covered, testable_faults; + sat_result_t sat_value; + fault_pattern_t *fault_info; + bool use_internal_states = FALSE; + + if ((*network) == NIL(network_t)) return 0; + if (network_num_internal(*network) == 0) return 0; + if (network_num_latch(*network) == 0) { + fprintf(sisout, "Use the atpg command for combinational circuits.\nThe short_tests techniques are useful only for sequential circuits.\n"); + return 0; + } + + last_time = begin_time = util_cpu_time(); + info = atpg_info_init(*network); + info->seq = TRUE; + atpg_opt = info->atpg_opt; + if (!set_short_tests_options(info, argc, argv)) { + print_usage(); + atpg_free_info(info); + return 1; + } + if (atpg_opt->timeout > 0) { + (void) signal(SIGALRM, timeout_handle); + (void) alarm((unsigned int) atpg_opt->timeout); + if (setjmp(timeout_env) > 0) { + fprintf(sisout, "timeout occurred after %d seconds\n", + atpg_opt->timeout); + atpg_free_info(info); + return 1; + } + } + if (atpg_opt->tech_decomp) { + decomp_tech_network(*network, INFINITY, INFINITY); + } + + ss_info = atpg_sim_sat_info_init(*network, info); + seq_info = atpg_seq_info_init(info); + atpg_gen_faults(info); + atpg_sim_setup(ss_info); + atpg_comb_sim_setup(ss_info); + atpg_sat_init(ss_info); + + info->statistics->initial_faults = lsLength(info->faults); + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d total faults\n", lsLength(info->faults)); + } + + seq_setup(seq_info, info); + if (atpg_opt->build_product_machines) { + seq_product_setup(info, seq_info, info->network); + copy_orig_bdds(seq_info); + atpg_product_setup_seq_info(seq_info); + } + record_reset_state(seq_info, info); + + time = util_cpu_time(); + info->time_info->setup = (time - last_time); + last_time = time; + + assert(calculate_reachable_states(seq_info)); + seq_info->valid_states_network = convert_bdd_to_network(seq_info, + seq_info->range_data->total_set); + time = util_cpu_time(); + info->time_info->traverse_stg = (time - last_time); + last_time = time; + stg_depth = array_n(seq_info->reached_sets); + info->statistics->stg_depth = stg_depth; + atpg_sat_node_info_setup(seq_info->valid_states_network); + atpg_setup_seq_info(info, seq_info, stg_depth); + + n_tests = 0; + if (atpg_opt->rtg) { + atpg_opt->rtg_depth = stg_depth; + info->tested_faults = atpg_random_cover(info, ss_info, NIL(atpg_ss_info_t), + TRUE, &n_tests); + info->statistics->n_RTG_tested = lsLength(info->tested_faults); + } else { + info->tested_faults = lsCreate(); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults covered by RTG\n", + lsLength(info->tested_faults)); + } + time = util_cpu_time(); + info->time_info->RTG += (time - last_time); + last_time = time; + + if (atpg_opt->PMT_only) { + /* Before going to PMT, first find redundancies that can be identified + * by SAT. To cut down on SAT time, if RTG has not already been + * performed, first run RTG to eliminate + * testable faults from the search. (These random tests are NOT used as + * tests--tests will be generated later during PMT.) + */ + if (!atpg_opt->rtg) { + last_time = util_cpu_time(); + atpg_opt->rtg_depth = stg_depth; + testable_faults = atpg_random_cover(info, ss_info, NIL(atpg_ss_info_t), + FALSE, NIL(int)); + time = util_cpu_time(); + info->time_info->RTG += (time - last_time); + concat_lists(info->untested_faults, testable_faults); + } + + while (lsFirstItem(info->faults, (lsGeneric *) &fault, &handle) == LS_OK) { + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + last_time = util_cpu_time(); + sat_reset(ss_info->atpg_sat); + (void) atpg_network_fault_clauses(ss_info, NIL(atpg_ss_info_t), + seq_info, fault); + time = util_cpu_time(); + info->time_info->SAT_clauses += (time - last_time); + last_time = time; + + sat_value = sat_solve(ss_info->atpg_sat, atpg_opt->fast_sat, + atpg_opt->verbosity); + time = util_cpu_time(); + info->time_info->SAT_solve += (time - last_time); + if (sat_value == SAT_ABSURD) { + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + fault->status = REDUNDANT; + fault->redund_type = CONTROL; + info->statistics->sat_red += 1; + lsNewEnd(info->redundant_faults, (lsGeneric) fault, 0); + if (atpg_opt->reverse_fault_sim) { + fault_info = ALLOC(fault_pattern_t, 1); + fault_info->node = fault->node; + fault_info->fanin = fault->fanin; + fault_info->value = (fault->value == S_A_0) ? 0 : 1; + st_insert(info->redund_table, (char *) fault_info, (char *) 0); + } + lsRemoveItem(handle, (lsGeneric *) &data); + } else { + lsNewEnd(info->untested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + } + } + + } else { + while (lsFirstItem(info->faults, (lsGeneric *) &fault, &handle) == LS_OK) { + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + /* find test using three-step algorithm and fault-free assumption */ + test_sequence = generate_test(fault, info, ss_info, seq_info, + NIL(atpg_ss_info_t), 0); + + switch (fault->status) { + case REDUNDANT: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + lsNewEnd(info->redundant_faults, (lsGeneric) fault, 0); + if (atpg_opt->reverse_fault_sim) { + fault_info = ALLOC(fault_pattern_t, 1); + fault_info->node = fault->node; + fault_info->fanin = fault->fanin; + fault_info->value = (fault->value == S_A_0) ? 0 : 1; + st_insert(info->redund_table, (char *) fault_info, (char *) 0); + } + lsRemoveItem(handle, (lsGeneric *) &data); + break; + case ABORTED: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Aborted by SAT\n"); + } + lsNewEnd(info->untested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + break; + case UNTESTED: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Untested\n"); + } + lsNewEnd(info->untested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + break; + case TESTED: + n_tests ++; + if (atpg_opt->verbosity > 2) { + atpg_print_vectors(sisout, test_sequence->vectors, + info->n_real_pi); + } + if (ATPG_DEBUG) { + assert(atpg_verify_test(ss_info, fault, test_sequence)); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Tested\n"); + } + lsNewEnd(info->tested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + test_sequence->index = n_tests; + fault->sequence = test_sequence; + st_insert(info->sequence_table, (char *) test_sequence, (char *) 0); + if (atpg_opt->use_internal_states) { + update_start_states(info, seq_info, test_sequence, + ss_info); + } + if (atpg_opt->fault_simulate) { + last_time = util_cpu_time(); + covered = seq_single_sequence_simulate(ss_info, + test_sequence, info->faults); + concat_lists(covered, + seq_single_sequence_simulate(ss_info, + test_sequence, info->untested_faults)); + if (info->atpg_opt->verbosity > 0) { + fprintf(sisout, "fault simulation covered %d\n", + lsLength(covered)); + } + concat_lists(info->tested_faults, covered); + time = util_cpu_time(); + info->time_info->fault_simulate += (time - last_time); + } + break; + default: + fail("bad fault->status returned by generate_test"); + break; + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults remaining\n", + lsLength(info->faults) + lsLength(info->untested_faults)); + } + } + } + + info->statistics->n_untested_by_main_loop = lsLength(info->untested_faults); + + if (atpg_opt->build_product_machines && + (info->statistics->n_untested_by_main_loop > 0)) { + if (atpg_opt->use_internal_states) { + construct_product_start_states(seq_info, info->n_latch); + } + while (lsFirstItem(info->untested_faults, + (lsGeneric *) &fault, &handle) == LS_OK) { + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + /* find test using good/faulty product machine traversal */ + last_time = util_cpu_time(); + test_sequence = generate_test_using_verification(fault, info, + ss_info, seq_info, 0); + time = util_cpu_time(); + info->time_info->product_machine_verify += (time - last_time); + switch (fault->status) { + case REDUNDANT: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + lsNewEnd(info->redundant_faults, (lsGeneric) fault, 0); + if (atpg_opt->reverse_fault_sim) { + fault_info = ALLOC(fault_pattern_t, 1); + fault_info->node = fault->node; + fault_info->fanin = fault->fanin; + fault_info->value = (fault->value == S_A_0) ? 0 : 1; + st_insert(info->redund_table, (char *) fault_info, (char *) 0); + } + lsRemoveItem(handle, &data); + break; + case TESTED: + n_tests ++; + if (atpg_opt->verbosity > 2) { + atpg_print_vectors(sisout, test_sequence->vectors, + info->n_real_pi); + } + if (ATPG_DEBUG) { + assert(atpg_verify_test(ss_info, fault, test_sequence)); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Tested\n"); + } + lsNewEnd(info->tested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + test_sequence->index = n_tests; + fault->sequence = test_sequence; + st_insert(info->sequence_table, (char *) test_sequence, + (char *) 0); + if (atpg_opt->use_internal_states) { + update_product_start_states(info, seq_info, test_sequence, + ss_info); + } + if (atpg_opt->fault_simulate) { + last_time = util_cpu_time(); + covered = seq_single_sequence_simulate(ss_info, + test_sequence, info->untested_faults); + if (info->atpg_opt->verbosity > 0) { + fprintf(sisout, "fault simulation covered %d\n", + lsLength(covered)); + } + concat_lists(info->tested_faults, covered); + time = util_cpu_time(); + info->time_info->fault_simulate += (time - last_time); + } + break; + case UNTESTED: + assert(atpg_opt->use_internal_states == TRUE); + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Untested\n"); + } + lsNewEnd(info->final_untested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + break; + default: + fail("bad fault->status returned by PMT"); + break; + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults remaining\n", + lsLength(info->untested_faults) + lsLength(info->final_untested_faults)); + } + } + /* if internal states were used, PMT might not have generated a test + for some faults */ + if (lsLength(info->final_untested_faults) > 0) { + assert(atpg_opt->use_internal_states == TRUE); + use_internal_states = TRUE; + atpg_opt->use_internal_states = FALSE; + } + while (lsFirstItem(info->final_untested_faults, + (lsGeneric *) &fault, &handle) == LS_OK) { + if (atpg_opt->verbosity > 0) { + atpg_print_fault(sisout, fault); + } + /* find test using good/faulty product machine traversal */ + last_time = util_cpu_time(); + test_sequence = generate_test_using_verification(fault, info, + ss_info, seq_info, 0); + time = util_cpu_time(); + info->time_info->product_machine_verify += (time - last_time); + switch (fault->status) { + case REDUNDANT: + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Redundant\n"); + } + lsNewEnd(info->redundant_faults, (lsGeneric) fault, 0); + if (atpg_opt->reverse_fault_sim) { + fault_info = ALLOC(fault_pattern_t, 1); + fault_info->node = fault->node; + fault_info->fanin = fault->fanin; + fault_info->value = (fault->value == S_A_0) ? 0 : 1; + st_insert(info->redund_table, (char *) fault_info, (char *) 0); + } + lsRemoveItem(handle, &data); + break; + case TESTED: + n_tests ++; + if (atpg_opt->verbosity > 2) { + atpg_print_vectors(sisout, test_sequence->vectors, + info->n_real_pi); + } + if (ATPG_DEBUG) { + assert(atpg_verify_test(ss_info, fault, test_sequence)); + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "Tested\n"); + } + lsNewEnd(info->tested_faults, (lsGeneric) fault, 0); + lsRemoveItem(handle, &data); + test_sequence->index = n_tests; + fault->sequence = test_sequence; + st_insert(info->sequence_table, (char *) test_sequence, + (char *) 0); + if (atpg_opt->use_internal_states) { + update_product_start_states(info, seq_info, test_sequence, + ss_info); + } + if (atpg_opt->fault_simulate) { + last_time = util_cpu_time(); + covered = seq_single_sequence_simulate(ss_info, + test_sequence, info->untested_faults); + if (info->atpg_opt->verbosity > 0) { + fprintf(sisout, "fault simulation covered %d\n", + lsLength(covered)); + } + concat_lists(info->tested_faults, covered); + time = util_cpu_time(); + info->time_info->fault_simulate += (time - last_time); + } + break; + default: + fail("bad fault->status returned by PMT"); + break; + } + if (atpg_opt->verbosity > 0) { + fprintf(sisout, "%d faults remaining\n", + lsLength(info->final_untested_faults)); + } + } + if (use_internal_states == TRUE) atpg_opt->use_internal_states = TRUE; + } + + if (atpg_opt->reverse_fault_sim) { + reverse_fault_simulate(info, ss_info); + } + print_and_destroy_sequences(info); + info->time_info->total_time = (util_cpu_time() - begin_time); + atpg_print_results(info, seq_info); + + atpg_sim_unsetup(ss_info); + atpg_comb_sim_unsetup(ss_info); + atpg_sim_free(ss_info); + atpg_sat_free(ss_info); + FREE(ss_info); + if (atpg_opt->build_product_machines) { + seq_info_product_free(seq_info); + } + seq_info_free(info, seq_info); + lsDestroy(info->tested_faults, free_fault); + lsDestroy(info->faults, 0); + atpg_free_info(info); + sm_cleanup(); + fast_avl_cleanup(); + return 0; +} + +static void +update_start_states(info, seq_info, test_sequence, ss_info) +atpg_info_t *info; +seq_info_t *seq_info; +sequence_t *test_sequence; +atpg_ss_info_t *ss_info; +{ + int i, key, value, position_in_key; + int n_latch = info->n_latch; + array_t *latch_to_pi_ordering = seq_info->latch_to_pi_ordering; + array_t *good_state = seq_info->good_state; + bool found; + st_table *state_sequence_table = seq_info->state_sequence_table; + lsList sequence_list; + bdd_t *new_state, *new_start_states; + + fault_simulate_to_get_final_state(ss_info, test_sequence, seq_info); + key = 0; + for (i = n_latch; i --; ) { + value = array_fetch(int, good_state, i); + position_in_key = array_fetch(int, latch_to_pi_ordering, i); + key += value << position_in_key; + } + + found = st_lookup(state_sequence_table, (char *) key, (char **) &sequence_list); + if (found) { + if (lsLength(sequence_list) == 0) { + /* final_state == reset_state */ + return; + } else { + lsNewBegin(sequence_list, (lsGeneric) test_sequence, 0); + } + } else { + sequence_list = lsCreate(); + lsNewBegin(sequence_list, (lsGeneric) test_sequence, 0); + st_insert(state_sequence_table, (char *) key, (char *) sequence_list); + new_state = convert_state_to_bdd(seq_info, good_state); + new_start_states = bdd_or(seq_info->start_states, new_state, 1, 1); + bdd_free(new_state); + bdd_free(seq_info->start_states); + seq_info->start_states = new_start_states; + } + return; +} + +static void +update_product_start_states(info, seq_info, test_sequence, ss_info) +atpg_info_t *info; +seq_info_t *seq_info; +sequence_t *test_sequence; +atpg_ss_info_t *ss_info; +{ + int i, key, value, position_in_key; + int n_latch = info->n_latch; + array_t *latch_to_pi_ordering = seq_info->latch_to_pi_ordering; + array_t *good_state = seq_info->good_state; + bool found; + st_table *state_sequence_table = seq_info->state_sequence_table; + lsList sequence_list; + bdd_t *new_state, *new_start_states; + + fault_simulate_to_get_final_state(ss_info, test_sequence, seq_info); + key = 0; + for (i = n_latch; i --; ) { + value = array_fetch(int, good_state, i); + position_in_key = array_fetch(int, latch_to_pi_ordering, i); + key += value << position_in_key; + } + + found = st_lookup(state_sequence_table, (char *) key, (char **) &sequence_list); + if (found) { + if (lsLength(sequence_list) == 0) { + /* final_state == reset_state */ + return; + } else { + lsNewBegin(sequence_list, (lsGeneric) test_sequence, 0); + } + } else { + sequence_list = lsCreate(); + lsNewBegin(sequence_list, (lsGeneric) test_sequence, 0); + st_insert(state_sequence_table, (char *) key, (char *) sequence_list); + new_state = convert_states_to_product_bdd(seq_info, good_state, good_state); + new_start_states = bdd_or(seq_info->product_start_states, new_state, 1, 1); + bdd_free(new_state); + bdd_free(seq_info->product_start_states); + seq_info->product_start_states = new_start_states; + } + return; +} diff --git a/sis/atpg/fast_avl.c b/sis/atpg/fast_avl.c new file mode 100644 index 0000000..fa4d735 --- /dev/null +++ b/sis/atpg/fast_avl.c @@ -0,0 +1,455 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/fast_avl.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include + +#include "util.h" +#include "fast_avl.h" + +fast_avl_node *fast_avl_node_freelist = NIL(fast_avl_node); +fast_avl_tree *fast_avl_tree_freelist = NIL(fast_avl_tree); +fast_avl_generator *fast_avl_generator_freelist = NIL(fast_avl_generator); +fast_avl_nodelist *fast_avl_nodelist_freelist = NIL(fast_avl_nodelist); + +#define HEIGHT(node) (node == NIL(fast_avl_node) ? -1 : (node)->height) +#define BALANCE(node) (HEIGHT((node)->right) - HEIGHT((node)->left)) + +#define compute_height(node) { \ + int x=HEIGHT(node->left), y=HEIGHT(node->right); \ + (node)->height = MAX(x,y) + 1; \ +} + +#define COMPARE(key, nodekey, compare) \ + ((compare == fast_avl_numcmp) ? \ + (int) key - (int) nodekey : \ + (*compare)(key, nodekey)) + +#define STACK_SIZE 50 + +static fast_avl_node *new_node(); +static void do_rebalance(); +static rotate_left(); +static rotate_right(); +static int do_check_tree(); + +fast_avl_tree * +fast_avl_init_tree(compar) +int (*compar)(); +{ + fast_avl_tree *tree; + + fast_avl_tree_alloc(tree); + tree->root = NIL(fast_avl_node); + tree->compar = compar; + tree->num_entries = 0; + return tree; +} + +fast_avl_lookup(tree, key, value_p) +fast_avl_tree *tree; +char *key; +char **value_p; +{ + fast_avl_node *node; + int (*compare)() = tree->compar, diff; + + node = tree->root; + while (node != NIL(fast_avl_node)) { + diff = COMPARE(key, node->key, compare); + if (diff == 0) { + /* got a match */ + if (value_p != NIL(char *)) *value_p = node->value; + return 1; + } + node = (diff < 0) ? node->left : node->right; + } + return 0; +} + +fast_avl_insert(tree, key, value) +fast_avl_tree *tree; +char *key; +char *value; +{ + fast_avl_node **node_p, *node; + int stack_n = 0; + int (*compare)() = tree->compar; + fast_avl_node **stack_nodep[STACK_SIZE]; + int diff, status; + + node_p = &tree->root; + + /* walk down the tree (saving the path); stop at insertion point */ + status = 0; + while ((node = *node_p) != NIL(fast_avl_node)) { + stack_nodep[stack_n++] = node_p; + diff = COMPARE(key, node->key, compare); + if (diff == 0) status = 1; + node_p = (diff < 0) ? &node->left : &node->right; + } + + /* insert the item and re-balance the tree */ + *node_p = new_node(key, value); + do_rebalance(stack_nodep, stack_n); + tree->num_entries++; + tree->modified = 1; + return status; +} + +static void +fast_avl_record_gen_forward(node, gen) +fast_avl_node *node; +fast_avl_generator *gen; +{ + if (node != NIL(fast_avl_node)) { + fast_avl_record_gen_forward(node->left, gen); + gen->nodelist->arr[gen->count++] = node; + fast_avl_record_gen_forward(node->right, gen); + } +} + + +static void +fast_avl_record_gen_backward(node, gen) +fast_avl_node *node; +fast_avl_generator *gen; +{ + if (node != NIL(fast_avl_node)) { + fast_avl_record_gen_backward(node->right, gen); + gen->nodelist->arr[gen->count++] = node; + fast_avl_record_gen_backward(node->left, gen); + } +} + +static fast_avl_nodelist * +fast_avl_nodelist_alloc(count) +int count; +{ + fast_avl_nodelist *obj, *new; + + if (fast_avl_nodelist_freelist == NIL(fast_avl_nodelist)) { + new = ALLOC(fast_avl_nodelist, 1); + new->arr = ALLOC(fast_avl_node *, count); + new->size = count; + } + else { + if (count <= fast_avl_nodelist_freelist->size) { + new = fast_avl_nodelist_freelist; + fast_avl_nodelist_freelist = fast_avl_nodelist_freelist->next; + } + else { + obj = fast_avl_nodelist_freelist; + fast_avl_nodelist_freelist = fast_avl_nodelist_freelist->next; + FREE(obj->arr); + FREE(obj); + new = ALLOC(fast_avl_nodelist, 1); + new->arr = ALLOC(fast_avl_node *, count); + new->size = count; + } + } + new->next = NIL(fast_avl_nodelist); + return new; +} + +fast_avl_generator * +fast_avl_init_gen(tree, dir) +fast_avl_tree *tree; +int dir; +{ + int count; + fast_avl_generator *gen; + + /* what a hack */ + fast_avl_generator_alloc(gen); + gen->tree = tree; + count = avl_count(tree); + gen->nodelist = fast_avl_nodelist_alloc(count); + gen->count = 0; + if (dir == AVL_FORWARD) { + fast_avl_record_gen_forward(tree->root, gen); + } else { + fast_avl_record_gen_backward(tree->root, gen); + } + gen->count = 0; + + /* catch any attempt to modify the tree while we generate */ + tree->modified = 0; + return gen; +} + +fast_avl_gen(gen, key_p, value_p) +fast_avl_generator *gen; +char **key_p; +char **value_p; +{ + fast_avl_node *node; + + if (gen->count == gen->tree->num_entries) { + return 0; + } else { + node = gen->nodelist->arr[gen->count++]; + if (key_p != NIL(char *)) *key_p = node->key; + if (value_p != NIL(char *)) *value_p = node->value; + return 1; + } +} + +void +fast_avl_free_gen(gen) +fast_avl_generator *gen; +{ + fast_avl_nodelist_free(gen->nodelist); + fast_avl_generator_free(gen); +} + +static void +do_rebalance(stack_nodep, stack_n) +fast_avl_node ***stack_nodep; +int stack_n; +{ + fast_avl_node **node_p, *node; + int hl, hr; + int height; + + /* work our way back up, re-balancing the tree */ + while (--stack_n >= 0) { + node_p = stack_nodep[stack_n]; + node = *node_p; + hl = HEIGHT(node->left); /* watch for NIL */ + hr = HEIGHT(node->right); /* watch for NIL */ + if ((hr - hl) < -1) { + rotate_right(node_p); + } else if ((hr - hl) > 1) { + rotate_left(node_p); + } else { + height = MAX(hl, hr) + 1; + if (height == node->height) break; + node->height = height; + } + } +} + +static +rotate_left(node_p) +fast_avl_node **node_p; +{ + fast_avl_node *old_root = *node_p, *new_root, *new_right; + + if (BALANCE(old_root->right) >= 0) { + *node_p = new_root = old_root->right; + old_root->right = new_root->left; + new_root->left = old_root; + } else { + new_right = old_root->right; + *node_p = new_root = new_right->left; + old_root->right = new_root->left; + new_right->left = new_root->right; + new_root->right = new_right; + new_root->left = old_root; + compute_height(new_right); + } + compute_height(old_root); + compute_height(new_root); +} + +static +rotate_right(node_p) +fast_avl_node **node_p; +{ + fast_avl_node *old_root = *node_p, *new_root, *new_left; + + if (BALANCE(old_root->left) <= 0) { + *node_p = new_root = old_root->left; + old_root->left = new_root->right; + new_root->right = old_root; + } else { + new_left = old_root->left; + *node_p = new_root = new_left->right; + old_root->left = new_root->right; + new_left->right = new_root->left; + new_root->left = new_left; + new_root->right = old_root; + compute_height(new_left); + } + compute_height(old_root); + compute_height(new_root); +} + +static void +fast_avl_walk_forward(node, func) +fast_avl_node *node; +void (*func)(); +{ + if (node != NIL(fast_avl_node)) { + fast_avl_walk_forward(node->left, func); + (*func)(node->key, node->value); + fast_avl_walk_forward(node->right, func); + } +} + +static void +fast_avl_walk_backward(node, func) +fast_avl_node *node; +void (*func)(); +{ + if (node != NIL(fast_avl_node)) { + fast_avl_walk_backward(node->right, func); + (*func)(node->key, node->value); + fast_avl_walk_backward(node->left, func); + } +} + +void +fast_avl_foreach(tree, func, direction) +fast_avl_tree *tree; +void (*func)(); +int direction; +{ + if (direction == AVL_FORWARD) { + fast_avl_walk_forward(tree->root, func); + } else { + fast_avl_walk_backward(tree->root, func); + } +} + +static void +free_entry(node, key_free, value_free) +fast_avl_node *node; +void (*key_free)(); +void (*value_free)(); +{ + if (node != NIL(fast_avl_node)) { + free_entry(node->left, key_free, value_free); + free_entry(node->right, key_free, value_free); + if (key_free != 0) (*key_free)(node->key); + if (value_free != 0) (*value_free)(node->value); + fast_avl_node_free(node); + } +} + +void +fast_avl_free_tree(tree, key_free, value_free) +fast_avl_tree *tree; +void (*key_free)(); +void (*value_free)(); +{ + free_entry(tree->root, key_free, value_free); + fast_avl_tree_free(tree); +} + +static fast_avl_node * +new_node(key, value) +char *key; +char *value; +{ + fast_avl_node *new; + + fast_avl_node_alloc(new); + new->key = key; + new->value = value; + new->height = 0; + new->left = new->right = NIL(fast_avl_node); + return new; +} + +int +fast_avl_numcmp(x, y) +char *x, *y; +{ + return (int) x - (int) y; +} + +int +fast_avl_check_tree(tree) +fast_avl_tree *tree; +{ + int error = 0; + (void) do_check_tree(tree->root, tree->compar, &error); + return error; +} + +static int +do_check_tree(node, compar, error) +fast_avl_node *node; +int (*compar)(); +int *error; +{ + int l_height, r_height, comp_height, bal; + + if (node == NIL(fast_avl_node)) { + return -1; + } + + r_height = do_check_tree(node->right, compar, error); + l_height = do_check_tree(node->left, compar, error); + + comp_height = MAX(l_height, r_height) + 1; + bal = r_height - l_height; + + if (comp_height != node->height) { + (void) printf("Bad height for 0x%08x: computed=%d stored=%d\n", + node, comp_height, node->height); + ++*error; + } + + if (bal > 1 || bal < -1) { + (void) printf("Out of balance at node 0x%08x, balance = %d\n", + node, bal); + ++*error; + } + + if (node->left != NIL(fast_avl_node) && + (*compar)(node->left->key, node->key) > 0) { + (void) printf("Bad ordering between 0x%08x and 0x%08x", + node, node->left); + ++*error; + } + + if (node->right != NIL(fast_avl_node) && + (*compar)(node->key, node->right->key) > 0) { + (void) printf("Bad ordering between 0x%08x and 0x%08x", + node, node->right); + ++*error; + } + + return comp_height; +} + +void +fast_avl_cleanup() +{ + fast_avl_tree *t, *tnext; + fast_avl_node *n, *nnext; + fast_avl_nodelist *e, *enext; + fast_avl_generator *g, *gnext; + + for (t = fast_avl_tree_freelist; t != NIL(fast_avl_tree); t = tnext) { + tnext = t->next; + FREE(t); + } + fast_avl_tree_freelist = NIL(fast_avl_tree); + for (n = fast_avl_node_freelist; n != NIL(fast_avl_node); n = nnext) { + nnext = n->next; + FREE(n); + } + fast_avl_node_freelist = NIL(fast_avl_node); + for (e = fast_avl_nodelist_freelist; e != NIL(fast_avl_nodelist); + e = enext) { + enext = e->next; + FREE(e->arr); + FREE(e); + } + fast_avl_nodelist_freelist = NIL(fast_avl_nodelist); + for (g = fast_avl_generator_freelist; g != NIL(fast_avl_generator); + g = gnext) { + gnext = g->next; + FREE(g); + } + fast_avl_generator_freelist = NIL(fast_avl_generator); +} diff --git a/sis/atpg/fast_avl.h b/sis/atpg/fast_avl.h new file mode 100644 index 0000000..daadeef --- /dev/null +++ b/sis/atpg/fast_avl.h @@ -0,0 +1,122 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/fast_avl.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ + +typedef struct fast_avl_node_struct fast_avl_node; +struct fast_avl_node_struct { + fast_avl_node *left, *right; + char *key; + char *value; + int height; + fast_avl_node *next; +}; + +typedef struct fast_avl_tree_struct fast_avl_tree; +struct fast_avl_tree_struct { + fast_avl_node *root; + int (*compar)(); + int num_entries; + int modified; + fast_avl_tree *next; +}; + +typedef struct fast_avl_nodelist_struct fast_avl_nodelist; +struct fast_avl_nodelist_struct { + int size; + fast_avl_node **arr; + fast_avl_nodelist *next; +}; + +typedef struct fast_avl_generator_struct fast_avl_generator; +struct fast_avl_generator_struct { + fast_avl_tree *tree; + fast_avl_nodelist *nodelist; + int count; + fast_avl_generator *next; +}; + +#define AVL_FORWARD 0 +#define AVL_BACKWARD 1 + + +EXTERN fast_avl_tree *fast_avl_init_tree ARGS((int (*)())); +EXTERN int fast_avl_insert ARGS((fast_avl_tree *, char *, char *)); +EXTERN int fast_avl_lookup ARGS((fast_avl_tree *, char *, char **)); +EXTERN int fast_avl_numcmp ARGS((char *, char *)); +EXTERN int fast_avl_gen ARGS((fast_avl_generator *, char **, char **)); +EXTERN void fast_avl_foreach ARGS((fast_avl_tree *, void (*)(), int)); +EXTERN void fast_avl_free_tree ARGS((fast_avl_tree *, void (*)(), void (*)())); +EXTERN void fast_avl_free_gen ARGS((fast_avl_generator *)); +EXTERN fast_avl_generator *fast_avl_init_gen ARGS((fast_avl_tree *, int)); +EXTERN void fast_avl_cleanup ARGS(()); + +#define fast_avl_count(tree) (tree)->num_entries + +#define fast_avl_is_member(tree, key) fast_avl_lookup(tree, key, (char **) 0) + +#define fast_avl_foreach_item(tree, gen, dir, key_p, value_p) \ + for(gen = fast_avl_init_gen(tree, dir); \ + fast_avl_gen(gen, key_p, value_p) || (fast_avl_free_gen(gen),0);) + +extern fast_avl_node *fast_avl_node_freelist; +extern fast_avl_tree *fast_avl_tree_freelist; +extern fast_avl_generator *fast_avl_generator_freelist; +extern fast_avl_nodelist *fast_avl_nodelist_freelist; + +#define fast_avl_node_alloc(newobj) \ + if (fast_avl_node_freelist == NIL(fast_avl_node)) { \ + newobj = ALLOC(fast_avl_node, 1); \ + } else { \ + newobj = fast_avl_node_freelist; \ + fast_avl_node_freelist = fast_avl_node_freelist->next; \ + } \ + newobj->next = 0; + +#define fast_avl_node_free(e) \ + if (e) {\ + e->next = fast_avl_node_freelist; \ + fast_avl_node_freelist = e; \ + } + +#define fast_avl_tree_alloc(newobj) \ + if (fast_avl_tree_freelist == NIL(fast_avl_tree)) { \ + newobj = ALLOC(fast_avl_tree, 1); \ + } else { \ + newobj = fast_avl_tree_freelist; \ + fast_avl_tree_freelist = fast_avl_tree_freelist->next; \ + } \ + newobj->next = 0; + +#define fast_avl_tree_free(e) \ + if (e) {\ + e->next = fast_avl_tree_freelist; \ + fast_avl_tree_freelist = e; \ + } + +#define fast_avl_generator_alloc(newobj) \ + if (fast_avl_generator_freelist == NIL(fast_avl_generator)) { \ + newobj = ALLOC(fast_avl_generator, 1); \ + } else { \ + newobj = fast_avl_generator_freelist; \ + fast_avl_generator_freelist = fast_avl_generator_freelist->next; \ + } \ + newobj->next = 0; + +#define fast_avl_generator_free(e) \ + if (e) {\ + e->next = fast_avl_generator_freelist; \ + fast_avl_generator_freelist = e; \ + } + +#define fast_avl_nodelist_free(e) \ + if (e) {\ + e->next = fast_avl_nodelist_freelist; \ + fast_avl_nodelist_freelist = e; \ + } + diff --git a/sis/atpg/sat.c b/sis/atpg/sat.c new file mode 100644 index 0000000..674ab4c --- /dev/null +++ b/sis/atpg/sat.c @@ -0,0 +1,537 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/sat.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include "sis.h" +#include "sat_int.h" +#include "fast_avl.h" + +/* Based on original SAT package written by Paul Stephan */ + +#define array_reset(a) ((a)->num = 0) +#define ASIZE 8 +#define N_UNBOUND(r) ((int) (r)->flag) +#define DEC_UNBOUND(r) ((r)->flag = ((r)->flag - 1)) +#define INC_UNBOUND(r) ((r)->flag = ((r)->flag + 1)) +#define INV_UNBOUND(r) ((r)->flag = (- (r)->flag)) +#define sat_satisfies(r) ((r)->flag < 0) +#define sat_save_tos(sat, p) p.tos_var = array_n(sat->stk_var); \ + p.tos_inc = array_n(sat->stk_inc); \ + p.tos_cla = array_n(sat->stk_cla) + +static sm_col *sat_find_next_lit(); +static void create_sat_lit(); +static bool sat_bound(); +static void sat_undo_assignment(); +static bool sat_branch(); +static bool sat_find_impl(); +static sat_result_t sat_branch_n_bound(); +static bool sat_fix_literal(); + +/* SAT search strategies */ +static sat_strategy_t sat_strategy[] = { + {0, 1, 15, 0, 0, 0}, + {0, 2, 15, 0, 0, 0}, + {0, 4, 15, 0, 0, 0}, + {0, 5, 15, 0, 0, 0}, + {0, 1, 100, 10, 1, 1}, + {0, 2, 100, 0, 0, 0}, + {0, 4, 100, 0, 0, 0}, + {0, 5, 100, 0, 0, 0}, + {0, 1, 500, 10, 1, 1}, + {0, 2, 500, 0, 0, 0}, + {0, 4, 500, 0, 0, 0}, + {0, 5, 500, 0, 0, 0} +}; + +static sm_col * +sat_find_next_lit(sat, next_clause) +sat_t *sat; +sm_row **next_clause; +{ + int order, best; + sm_row *cl; + sm_element *p; + + order = sat->strategy->var_order; + best = -1; + cl = *next_clause; + if (order == 1 || order == 2) { + + /* find literal in first unsatisfied clause */ + for ( ; cl != NIL(sm_row); cl = cl->next_row) { + if (sat_satisfies(cl)) { + continue; + } + sm_foreach_row_element(cl, p) { + if (! sm_get_col(sat->matrix, sat_neg(p->col_num))->flag) { + best = p->col_num; + if (order == 1) { + break; + } + } + } + break; + } + } + else if (order == 4 || order == 5) { + + /* find literal in last unsatisfied clause */ + for ( ; cl != NIL(sm_row); cl = cl->prev_row) { + if (sat_satisfies(cl)) { + continue; + } + sm_foreach_row_element(cl, p) { + if (! sm_get_col(sat->matrix, sat_neg(p->col_num))->flag) { + best = p->col_num; + if (order == 4) { + break; + } + } + } + break; + } + } + else { + fail("Unknown clause / variable ordering"); + } + *next_clause = cl; + + return sm_get_col(sat->matrix, best); +} + +/* SAT interface */ +sat_t * +sat_new() +{ + sat_t *sat; + + sat = ALLOC(sat_t, 1); + sat->matrix = sm_alloc_size(0, 0); + sat->one_clauses = array_alloc(int, ASIZE); + sat->nclause = 0; + sat->lit_index = 0; + + /* stacks */ + sat->stk_var = array_alloc(int, ASIZE); + sat->stk_inc = array_alloc(int, ASIZE); + sat->stk_cla = array_alloc(int, ASIZE); + + return sat; +} + +void +sat_reset(sat) +sat_t *sat; +{ + sm_col *c; + + sm_foreach_col(sat->matrix, c) { + fast_avl_free_tree((fast_avl_tree *) c->user_word, 0, 0); + } + sm_free(sat->matrix); + sat->matrix = sm_alloc_size(100, 100); + array_reset(sat->one_clauses); + sat->nclause = 0; + sat->lit_index = 0; + sat->n_impl = -1; + + /* stacks */ + array_reset(sat->stk_var); + array_reset(sat->stk_inc); + array_reset(sat->stk_cla); +} + +void +sat_delete(sat) +sat_t *sat; +{ + sm_col *c; + + sm_foreach_col(sat->matrix, c) { + fast_avl_free_tree((fast_avl_tree *) c->user_word, 0, 0); + } + sm_free(sat->matrix); + array_free(sat->one_clauses); + + /* stacks */ + array_free(sat->stk_var); + array_free(sat->stk_inc); + array_free(sat->stk_cla); + + FREE(sat); +} + +static void +create_sat_lit(A, col) +sm_matrix *A; +int col; +{ + sm_col *pcol; + + if (col >= A->cols_size) { + sm_resize(A, A->rows_size, col); + } + + pcol = A->cols[col] = sm_col_alloc(); + pcol->col_num = col; + sorted_insert(sm_col, A->first_col, A->last_col, A->ncols, + next_col, prev_col, col_num, col, pcol); + pcol->flag = FALSE; + pcol->user_word = (char *) fast_avl_init_tree(fast_avl_numcmp); +} + +/* return an index of sat variable */ +int +sat_new_variable(sat) +sat_t *sat; +{ + create_sat_lit(sat->matrix, sat->lit_index); + create_sat_lit(sat->matrix, sat->lit_index + 1); + sat->lit_index += 2; + return sat->lit_index - 2; +} + +bool +sat_add_implication(sat, var1, var2) +sat_t *sat; +int var1; +int var2; +{ + fast_avl_tree *imply; + + if (var1 == var2) { + return FALSE; + } + imply = (fast_avl_tree *) sm_get_col(sat->matrix, var1)->user_word; + if (fast_avl_is_member(imply, (char *) var2)) { + return FALSE; + } + fast_avl_insert(imply, (char *) var2, (char *) 0); + return TRUE; +} + +/* SAT solver */ +static bool +sat_bound(sat, c, add_impl) +sat_t *sat; +sm_col *c; +bool add_impl; +{ + int bot, lit, imp_lit; + sm_row *r; + fast_avl_tree *table; + fast_avl_generator *sgen; + sm_col *lit_col, *imp_col; + sm_element *e1, *e2; + bool implied_one; + + bot = array_n(sat->stk_var); + array_insert_last(int, sat->stk_var, c->col_num); + c->flag = TRUE; + + while (bot < array_n(sat->stk_var)) { + lit = array_fetch(int, sat->stk_var, bot ++); + lit_col = sm_get_col(sat->matrix, lit); + + /* do 2-sat implications */ + table = (fast_avl_tree *) lit_col->user_word; + fast_avl_foreach_item(table, sgen, AVL_FORWARD, (char **) &imp_lit, NIL(char *)) { + imp_col = sm_get_col(sat->matrix, imp_lit); + if (sm_get_col(sat->matrix, sat_neg(imp_lit))->flag) { + fast_avl_free_gen(sgen); + return FALSE; + } + + /* if variable not set, push on implied variable stack */ + if (! (imp_col->flag)) { + array_insert_last(int, sat->stk_var, imp_lit); + imp_col->flag = TRUE; + } + } + + /* imply its complement literal */ + sm_foreach_col_element(sm_get_col(sat->matrix, sat_neg(lit)), e1) { + r = sm_get_row(sat->matrix, e1->row_num); + if (sat_satisfies(r)) { + continue; + } + if (N_UNBOUND(r) > 2) { + /* push on implied clause stack */ + array_insert_last(int, sat->stk_inc, r->row_num); + DEC_UNBOUND(r); + continue; + } + implied_one = FALSE; + sm_foreach_row_element(r, e2) { + imp_col = sm_get_col(sat->matrix, e2->col_num); + if (imp_col->flag) { + implied_one = TRUE; + break; + } + if (! sm_get_col(sat->matrix, sat_neg(e2->col_num))->flag) { + implied_one = TRUE; + + /* push on implied variable stack */ + array_insert_last(int, sat->stk_var, e2->col_num); + imp_col->flag = TRUE; + + /* if lit_col => imp_col, deduce contrapositive */ + if (add_impl && sat_add_implication(sat, + sat_neg(e2->col_num), + sat_neg(c->col_num))) { + sat->n_impl ++; + } + break; + } + } + if (! implied_one) { + return FALSE; + } + } + + /* satisfy clauses where it occurs */ + sm_foreach_col_element(lit_col, e1) { + r = sm_get_row(sat->matrix, e1->row_num); + + /* check if not satisfied */ + if (N_UNBOUND(r) > 0) { + + /* push on satisfied clause stack */ + array_insert_last(int, sat->stk_cla, r->row_num); + INV_UNBOUND(r); + } + } + } + return TRUE; +} + +static void +sat_undo_assignment(sat, prev_status) +sat_t *sat; +stk_status_t prev_status; +{ + int i, lit, clause; + + for (i = array_n(sat->stk_var); i -- > prev_status.tos_var; ) { + lit = array_fetch(int, sat->stk_var, i); + sm_get_col(sat->matrix, lit)->flag = FALSE; + } + for (i = array_n(sat->stk_cla); i -- > prev_status.tos_cla; ) { + clause = array_fetch(int, sat->stk_cla, i); + INV_UNBOUND(sm_get_row(sat->matrix, clause)); + } + for (i = array_n(sat->stk_inc); i -- > prev_status.tos_inc; ) { + clause = array_fetch(int, sat->stk_inc, i); + INC_UNBOUND(sm_get_row(sat->matrix, clause)); + } + sat->stk_var->num = prev_status.tos_var; + sat->stk_inc->num = prev_status.tos_inc; + sat->stk_cla->num = prev_status.tos_cla; +} + +static bool +sat_branch(sat, next_clause) +sat_t *sat; +sm_row *next_clause; +{ + sm_col *c; + stk_status_t prev_tos; + + c = sat_find_next_lit(sat, &next_clause); + if (c == NIL(sm_col)) { + return TRUE; + } + + sat_save_tos(sat, prev_tos); + + if (sat_bound(sat, c, FALSE) && sat_branch(sat, next_clause)) { + return TRUE; + } + if (++ sat->bktrack > sat->strategy->bktrack_lim) { + sat->gaveup = TRUE; + return TRUE; + } + + /* restore stack here */ + sat_undo_assignment(sat, prev_tos); + + return (sat_bound(sat, sm_get_col(sat->matrix, sat_neg(c->col_num)), + FALSE) && sat_branch(sat, next_clause)); +} + +static bool +sat_find_impl(sat) +sat_t *sat; +{ + bool result; + int lit; + sm_col *col, *comp_col; + stk_status_t prev_tos; + + sat->n_impl = 0; + sm_foreach_col(sat->matrix, col) { + lit = col->col_num; + comp_col = sm_get_col(sat->matrix, sat_neg(lit)); + if (! col->flag && ! comp_col->flag && + (fast_avl_count((fast_avl_tree *) col->user_word))) { + sat_save_tos(sat, prev_tos); + result = sat_bound(sat, col, sat->strategy->add_nli); + sat_undo_assignment(sat, prev_tos); + if (! result && sat->strategy->add_unique) { + sat->n_impl ++; + if (! sat_fix_literal(sat, comp_col)) { + return FALSE; + } + } + } + } + return TRUE; +} + +static sat_result_t +sat_branch_n_bound(sat, verbosity) +sat_t *sat; +int verbosity; +{ + int i; + sm_col *c; + sm_row *start_clause; + bool bnb_status; + stk_status_t prev_tos; + sat_result_t result; + + sat->bktrack = 0; + sat->gaveup = FALSE; + bnb_status = TRUE; + + /* do static implications if required */ + if (sat->n_impl && sat->strategy->n_static_pass) { + i = 0; + while (i ++ < sat->strategy->n_static_pass && + bnb_status && sat->n_impl) { + bnb_status = sat_find_impl(sat); + if (sat->n_impl && bnb_status && (verbosity > 1)) { + fprintf(sisout, "%d Implications\n", sat->n_impl); + } + } + } + + sat_save_tos(sat, prev_tos); + if (sat->strategy->var_order < 4) { + start_clause = sat->matrix->first_row; + } + else { + start_clause = sat->matrix->last_row; + } + + while (bnb_status) { + c = sat_find_next_lit(sat, &start_clause); + if (c == NIL(sm_col)) { + break; + } + if (sat_bound(sat, c, FALSE) && sat_branch(sat, start_clause)) { + break; + } + + /* undo partial assignment */ + sat_undo_assignment(sat, prev_tos); + + bnb_status = sat_fix_literal(sat, sm_get_col(sat->matrix, + sat_neg(c->col_num))); + } + + if (sat->gaveup) { + result = SAT_GAVEUP; + /* undo partial assignment */ + sat_undo_assignment(sat, prev_tos); + } + else { + result = (bnb_status) ? SAT_SOLVED : SAT_ABSURD; + } + return result; +} + +/* fix variables from one-literal clauses */ +static bool +sat_fix_literal(sat, c) +sat_t *sat; +sm_col *c; +{ + if (c->flag) { + return TRUE; + } + if (sm_get_col(sat->matrix, sat_neg(c->col_num))->flag || + ! sat_bound(sat, c, FALSE)) { + return FALSE; + } + array_reset(sat->stk_var); + array_reset(sat->stk_inc); + array_reset(sat->stk_cla); + return TRUE; +} + +sat_result_t +sat_solve(sat, fast_sat, verbosity) +sat_t *sat; +bool fast_sat; +int verbosity; +{ + int i; + sm_col *c; + sm_row *r; + sat_result_t result; + + sm_foreach_row(sat->matrix, r) { + r->flag = r->length; + if (r->length == 1) { + INV_UNBOUND(r); + array_insert_last(int, sat->one_clauses, r->first_col->col_num); + } + else if (r->length == 0) { + return SAT_ABSURD; + } + } + for (i = 0; i < array_n(sat->one_clauses); i ++) { + c = sm_get_col(sat->matrix, array_fetch(int, sat->one_clauses, i)); + if (! sat_fix_literal(sat, c)) { + return SAT_ABSURD; + } + } + result = SAT_GAVEUP; + if (fast_sat) { + for (i = 0; result == SAT_GAVEUP && i < 4; i ++) { + sat->strategy = &sat_strategy[i]; + result = sat_branch_n_bound(sat, verbosity); + } + } + else { + for (i = 0; result == SAT_GAVEUP && i < 12; i ++) { + sat->strategy = &sat_strategy[i]; + result = sat_branch_n_bound(sat, verbosity); + } + } + return result; +} + +int +sat_get_value(sat, id) +sat_t *sat; +int id; +{ + if (sm_get_col(sat->matrix, id)->flag) { + return 1; + } + else if (sm_get_col(sat->matrix, sat_neg(id))->flag) { + return 0; + } + else { + return 2; + } +} + diff --git a/sis/atpg/sat.h b/sis/atpg/sat.h new file mode 100644 index 0000000..8cdbc32 --- /dev/null +++ b/sis/atpg/sat.h @@ -0,0 +1,71 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/sat.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#ifndef SATISFY_H +#define SATISFY_H + +#define sat_neg(i) ((i%2)?i-1:i+1) +#define sat_begin_clause(s) s->nclause ++ +#define sat_add_literal(s, v) sm_insert(s->matrix, s->nclause - 1, (v)) +#define sat_add_1clause(s, v) array_insert_last(int, s->one_clauses, (v)) +#define sat_add_2clause(s, v1, v2) \ + (void) sat_add_implication(s, sat_neg((v1)), (v2)); \ + (void) sat_add_implication(s, sat_neg((v2)), (v1)) +#define sat_add_3clause(s, v1, v2, v3) \ + sm_insert(s->matrix, s->nclause, (v1)); \ + sm_insert(s->matrix, s->nclause, (v2)); \ + sm_insert(s->matrix, s->nclause, (v3)); \ + s->nclause ++; + +typedef struct { + int cl_order; /* Subformula clause ordering */ + int var_order; /* Variable ordering for branching */ + int bktrack_lim; /* Limit on backtracks for this phase */ + int n_static_pass; /* Number of static GI passes to make */ + bool add_nli; /* Add nonlocal implications? */ + bool add_unique; /* Assign values found by contradition? */ +} sat_strategy_t; + +typedef struct { + sm_matrix *matrix; + array_t *one_clauses; + array_t *imply; + array_t *stk_var; + array_t *stk_inc; + array_t *stk_cla; + sat_strategy_t *strategy; + int nclause; + int lit_index; + int bktrack; + int n_impl; + bool gaveup; +} sat_t; + +typedef enum sat_result { + SAT_SOLVED, /* Satisfying solution is found. */ + SAT_ABSURD, /* Formula has no satisfying solution. */ + SAT_GAVEUP /* SAT package gave up search. */ +} sat_result_t; + +/* interface data structure */ +typedef struct { + int sat_id; + char *info; +} sat_input_t; + +extern sat_t *sat_new(); +extern void sat_reset(); +extern void sat_delete(); +extern int sat_new_variable(); +extern bool sat_add_implication(); +extern sat_result_t sat_solve(); +extern int sat_get_value(); +#endif /* SATISFY_H */ + + diff --git a/sis/atpg/sat_int.h b/sis/atpg/sat_int.h new file mode 100644 index 0000000..e18a372 --- /dev/null +++ b/sis/atpg/sat_int.h @@ -0,0 +1,71 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/atpg/sat_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +typedef struct { + int tos_var; + int tos_cla; + int tos_inc; +} stk_status_t; + +extern bool sat_add_implication(); + +/* + * sorted, double-linked list insertion + * + * type: object type + * + * first, last: fields (in header) to head and tail of the list + * count: field (in header) of length of the list + * + * next, prev: fields (in object) to link next and previous objects + * value: field (in object) which controls the order + * + * newval: value field for new object + * e: an object to use if insertion needed (set to actual value used) + */ + +#define sorted_insert(type, first, last, count, next, prev, value, newval, e) \ + if (last == 0) { \ + e->value = newval; \ + first = e; \ + last = e; \ + e->next = 0; \ + e->prev = 0; \ + count++; \ + } else if (last->value < newval) { \ + e->value = newval; \ + last->next = e; \ + e->prev = last; \ + last = e; \ + e->next = 0; \ + count++; \ + } else if (first->value > newval) { \ + e->value = newval; \ + first->prev = e; \ + e->next = first; \ + first = e; \ + e->prev = 0; \ + count++; \ + } else { \ + type *p; \ + for(p = first; p->value < newval; p = p->next) \ + ; \ + if (p->value > newval) { \ + e->value = newval; \ + p = p->prev; \ + p->next->prev = e; \ + e->next = p->next; \ + p->next = e; \ + e->prev = p; \ + count++; \ + } else { \ + e = p; \ + } \ + } + diff --git a/sis/avl/Makefile.am b/sis/avl/Makefile.am new file mode 100644 index 0000000..b988fe5 --- /dev/null +++ b/sis/avl/Makefile.am @@ -0,0 +1,9 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libavl.a +libavl_a_SOURCES = avl.c +pkginclude_HEADERS = avl.h +dist_doc_DATA = avl.doc + +EXTRA_DIST = avl_bench1.c diff --git a/sis/avl/Makefile.in b/sis/avl/Makefile.in new file mode 100644 index 0000000..9ab7384 --- /dev/null +++ b/sis/avl/Makefile.in @@ -0,0 +1,419 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libavl_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/avl +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libavl_a_AR = $(AR) $(ARFLAGS) +libavl_a_LIBADD = +am_libavl_a_OBJECTS = avl.$(OBJEXT) +libavl_a_OBJECTS = $(am_libavl_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libavl_a_SOURCES) +DIST_SOURCES = $(libavl_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libavl.a +libavl_a_SOURCES = avl.c +pkginclude_HEADERS = avl.h +dist_doc_DATA = avl.doc +EXTRA_DIST = avl_bench1.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/avl/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/avl/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libavl.a: $(libavl_a_OBJECTS) $(libavl_a_DEPENDENCIES) + -rm -f libavl.a + $(libavl_a_AR) libavl.a $(libavl_a_OBJECTS) $(libavl_a_LIBADD) + $(RANLIB) libavl.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/avl/avl.c b/sis/avl/avl.c new file mode 100644 index 0000000..3077b54 --- /dev/null +++ b/sis/avl/avl.c @@ -0,0 +1,572 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/avl/avl.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +/* LINTLIBRARY */ + + +#include + +#ifndef PACKAGE +#include "util.h" +#endif + +#include "avl.h" + +#ifdef PACKAGE +extern char *malloc(); +#ifdef ultrix +extern void free(); +#endif + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#define NIL(type) \ + ((type *) 0) +#define ALLOC(type, num) \ + ((type *) malloc(sizeof(type) * (num))) +#define REALLOC(type, obj, num) \ + ((type *) realloc((char *) obj, sizeof(type) * (num))) +#define FREE(obj) \ + free((char *) (obj)) +#endif + + +#define HEIGHT(node) (node == NIL(avl_node) ? -1 : (node)->height) +#define BALANCE(node) (HEIGHT((node)->right) - HEIGHT((node)->left)) + +#define compute_height(node) { \ + int x=HEIGHT(node->left), y=HEIGHT(node->right); \ + (node)->height = MAX(x,y) + 1; \ +} + +#define COMPARE(key, nodekey, compare) \ + ((compare == avl_numcmp) ? \ + (int) key - (int) nodekey : \ + (*compare)(key, nodekey)) + + +#define STACK_SIZE 50 + +static avl_node *new_node(); +static avl_node *find_rightmost(); +static void do_rebalance(); +static rotate_left(); +static rotate_right(); +static int do_check_tree(); + +avl_tree * +avl_init_table(compar) +int (*compar)(); +{ + avl_tree *tree; + + tree = ALLOC(avl_tree, 1); + tree->root = NIL(avl_node); + tree->compar = compar; + tree->num_entries = 0; + return tree; +} + + + +avl_lookup(tree, key, value_p) +avl_tree *tree; +register char *key; +char **value_p; +{ + register avl_node *node; + register int (*compare)() = tree->compar, diff; + + node = tree->root; + while (node != NIL(avl_node)) { + diff = COMPARE(key, node->key, compare); + if (diff == 0) { + /* got a match */ + if (value_p != NIL(char *)) *value_p = node->value; + return 1; + } + node = (diff < 0) ? node->left : node->right; + } + return 0; +} + +avl_first(tree, key_p, value_p) +avl_tree *tree; +char **key_p; +char **value_p; +{ + register avl_node *node; + + if (tree->root == 0) { + return 0; /* no entries */ + } else { + /* walk down the tree; stop at leftmost leaf */ + for(node = tree->root; node->left != 0; node = node->left) { + } + if (key_p != NIL(char *)) *key_p = node->key; + if (value_p != NIL(char *)) *value_p = node->value; + return 1; + } +} + + +avl_last(tree, key_p, value_p) +avl_tree *tree; +char **key_p; +char **value_p; +{ + register avl_node *node; + + if (tree->root == 0) { + return 0; /* no entries */ + } else { + /* walk down the tree; stop at rightmost leaf */ + for(node = tree->root; node->right != 0; node = node->right) { + } + if (key_p != NIL(char *)) *key_p = node->key; + if (value_p != NIL(char *)) *value_p = node->value; + return 1; + } +} + +avl_insert(tree, key, value) +avl_tree *tree; +char *key; +char *value; +{ + register avl_node **node_p, *node; + register int stack_n = 0; + register int (*compare)() = tree->compar; + avl_node **stack_nodep[STACK_SIZE]; + int diff, status; + + node_p = &tree->root; + + /* walk down the tree (saving the path); stop at insertion point */ + status = 0; + while ((node = *node_p) != NIL(avl_node)) { + stack_nodep[stack_n++] = node_p; + diff = COMPARE(key, node->key, compare); + if (diff == 0) status = 1; + node_p = (diff < 0) ? &node->left : &node->right; + } + + /* insert the item and re-balance the tree */ + *node_p = new_node(key, value); + do_rebalance(stack_nodep, stack_n); + tree->num_entries++; + tree->modified = 1; + return status; +} + + + +avl_find_or_add(tree, key, slot_p) +avl_tree *tree; +char *key; +char ***slot_p; +{ + register avl_node **node_p, *node; + register int stack_n = 0; + register int (*compare)() = tree->compar; + avl_node **stack_nodep[STACK_SIZE]; + int diff; + + node_p = &tree->root; + + /* walk down the tree (saving the path); stop at insertion point */ + while ((node = *node_p) != NIL(avl_node)) { + stack_nodep[stack_n++] = node_p; + diff = COMPARE(key, node->key, compare); + if (diff == 0) { + if (slot_p != 0) *slot_p = &node->value; + return 1; /* found */ + } + node_p = (diff < 0) ? &node->left : &node->right; + } + + /* insert the item and re-balance the tree */ + *node_p = new_node(key, NIL(char)); + do_rebalance(stack_nodep, stack_n); + tree->num_entries++; + tree->modified = 1; + if (slot_p != 0) *slot_p = &node->value; + return 0; /* not already in tree */ +} + +avl_delete(tree, key_p, value_p) +avl_tree *tree; +char **key_p; +char **value_p; +{ + register avl_node **node_p, *node, *rightmost; + register int stack_n = 0; + char *key = *key_p; + int (*compare)() = tree->compar, diff; + avl_node **stack_nodep[STACK_SIZE]; + + node_p = &tree->root; + + /* Walk down the tree saving the path; return if not found */ + while ((node = *node_p) != NIL(avl_node)) { + diff = COMPARE(key, node->key, compare); + if (diff == 0) goto delete_item; + stack_nodep[stack_n++] = node_p; + node_p = (diff < 0) ? &node->left : &node->right; + } + return 0; /* not found */ + + /* prepare to delete node and replace it with rightmost of left tree */ +delete_item: + *key_p = node->key; + if (value_p != 0) *value_p = node->value; + if (node->left == NIL(avl_node)) { + *node_p = node->right; + } else { + rightmost = find_rightmost(&node->left); + rightmost->left = node->left; + rightmost->right = node->right; + rightmost->height = -2; /* mark bogus height for do_rebal */ + *node_p = rightmost; + stack_nodep[stack_n++] = node_p; + } + FREE(node); + + /* work our way back up, re-balancing the tree */ + do_rebalance(stack_nodep, stack_n); + tree->num_entries--; + tree->modified = 1; + return 1; +} + +static void +avl_record_gen_forward(node, gen) +avl_node *node; +avl_generator *gen; +{ + if (node != NIL(avl_node)) { + avl_record_gen_forward(node->left, gen); + gen->nodelist[gen->count++] = node; + avl_record_gen_forward(node->right, gen); + } +} + + +static void +avl_record_gen_backward(node, gen) +avl_node *node; +avl_generator *gen; +{ + if (node != NIL(avl_node)) { + avl_record_gen_backward(node->right, gen); + gen->nodelist[gen->count++] = node; + avl_record_gen_backward(node->left, gen); + } +} + + +avl_generator * +avl_init_gen(tree, dir) +avl_tree *tree; +int dir; +{ + avl_generator *gen; + + /* what a hack */ + gen = ALLOC(avl_generator, 1); + gen->tree = tree; + gen->nodelist = ALLOC(avl_node *, avl_count(tree)); + gen->count = 0; + if (dir == AVL_FORWARD) { + avl_record_gen_forward(tree->root, gen); + } else { + avl_record_gen_backward(tree->root, gen); + } + gen->count = 0; + + /* catch any attempt to modify the tree while we generate */ + tree->modified = 0; + return gen; +} + + +avl_gen(gen, key_p, value_p) +avl_generator *gen; +char **key_p; +char **value_p; +{ + avl_node *node; + + if (gen->count == gen->tree->num_entries) { + return 0; + } else { + node = gen->nodelist[gen->count++]; + if (key_p != NIL(char *)) *key_p = node->key; + if (value_p != NIL(char *)) *value_p = node->value; + return 1; + } +} + + +void +avl_free_gen(gen) +avl_generator *gen; +{ + FREE(gen->nodelist); + FREE(gen); +} + +static avl_node * +find_rightmost(node_p) +register avl_node **node_p; +{ + register avl_node *node; + register int stack_n = 0; + avl_node **stack_nodep[STACK_SIZE]; + + node = *node_p; + while (node->right != NIL(avl_node)) { + stack_nodep[stack_n++] = node_p; + node_p = &node->right; + node = *node_p; + } + *node_p = node->left; + + do_rebalance(stack_nodep, stack_n); + return node; +} + + +static void +do_rebalance(stack_nodep, stack_n) +register avl_node ***stack_nodep; +register int stack_n; +{ + register avl_node **node_p, *node; + register int hl, hr; + int height; + + /* work our way back up, re-balancing the tree */ + while (--stack_n >= 0) { + node_p = stack_nodep[stack_n]; + node = *node_p; + hl = HEIGHT(node->left); /* watch for NIL */ + hr = HEIGHT(node->right); /* watch for NIL */ + if ((hr - hl) < -1) { + rotate_right(node_p); + } else if ((hr - hl) > 1) { + rotate_left(node_p); + } else { + height = MAX(hl, hr) + 1; + if (height == node->height) break; + node->height = height; + } + } +} + +static +rotate_left(node_p) +register avl_node **node_p; +{ + register avl_node *old_root = *node_p, *new_root, *new_right; + + if (BALANCE(old_root->right) >= 0) { + *node_p = new_root = old_root->right; + old_root->right = new_root->left; + new_root->left = old_root; + } else { + new_right = old_root->right; + *node_p = new_root = new_right->left; + old_root->right = new_root->left; + new_right->left = new_root->right; + new_root->right = new_right; + new_root->left = old_root; + compute_height(new_right); + } + compute_height(old_root); + compute_height(new_root); +} + + +static +rotate_right(node_p) +avl_node **node_p; +{ + register avl_node *old_root = *node_p, *new_root, *new_left; + + if (BALANCE(old_root->left) <= 0) { + *node_p = new_root = old_root->left; + old_root->left = new_root->right; + new_root->right = old_root; + } else { + new_left = old_root->left; + *node_p = new_root = new_left->right; + old_root->left = new_root->right; + new_left->right = new_root->left; + new_root->left = new_left; + new_root->right = old_root; + compute_height(new_left); + } + compute_height(old_root); + compute_height(new_root); +} + +static void +avl_walk_forward(node, func) +avl_node *node; +void (*func)(); +{ + if (node != NIL(avl_node)) { + avl_walk_forward(node->left, func); + (*func)(node->key, node->value); + avl_walk_forward(node->right, func); + } +} + + +static void +avl_walk_backward(node, func) +avl_node *node; +void (*func)(); +{ + if (node != NIL(avl_node)) { + avl_walk_backward(node->right, func); + (*func)(node->key, node->value); + avl_walk_backward(node->left, func); + } +} + + +void +avl_foreach(tree, func, direction) +avl_tree *tree; +void (*func)(); +int direction; +{ + if (direction == AVL_FORWARD) { + avl_walk_forward(tree->root, func); + } else { + avl_walk_backward(tree->root, func); + } +} + + +static void +free_entry(node, key_free, value_free) +avl_node *node; +void (*key_free)(); +void (*value_free)(); +{ + if (node != NIL(avl_node)) { + free_entry(node->left, key_free, value_free); + free_entry(node->right, key_free, value_free); + if (key_free != 0) (*key_free)(node->key); + if (value_free != 0) (*value_free)(node->value); + FREE(node); + } +} + + +void +avl_free_table(tree, key_free, value_free) +avl_tree *tree; +void (*key_free)(); +void (*value_free)(); +{ + free_entry(tree->root, key_free, value_free); + FREE(tree); +} + + +int +avl_count(tree) +avl_tree *tree; +{ + return tree->num_entries; +} + +static avl_node * +new_node(key, value) +char *key; +char *value; +{ + register avl_node *new; + + new = ALLOC(avl_node, 1); + new->key = key; + new->value = value; + new->height = 0; + new->left = new->right = NIL(avl_node); + return new; +} + + +int +avl_numcmp(x, y) +char *x, *y; +{ + return (int) x - (int) y; +} + +int +avl_check_tree(tree) +avl_tree *tree; +{ + int error = 0; + (void) do_check_tree(tree->root, tree->compar, &error); + return error; +} + + +static int +do_check_tree(node, compar, error) +avl_node *node; +int (*compar)(); +int *error; +{ + int l_height, r_height, comp_height, bal; + + if (node == NIL(avl_node)) { + return -1; + } + + r_height = do_check_tree(node->right, compar, error); + l_height = do_check_tree(node->left, compar, error); + + comp_height = MAX(l_height, r_height) + 1; + bal = r_height - l_height; + + if (comp_height != node->height) { + (void) printf("Bad height for 0x%08x: computed=%d stored=%d\n", + node, comp_height, node->height); + ++*error; + } + + if (bal > 1 || bal < -1) { + (void) printf("Out of balance at node 0x%08x, balance = %d\n", + node, bal); + ++*error; + } + + if (node->left != NIL(avl_node) && + (*compar)(node->left->key, node->key) > 0) { + (void) printf("Bad ordering between 0x%08x and 0x%08x", + node, node->left); + ++*error; + } + + if (node->right != NIL(avl_node) && + (*compar)(node->key, node->right->key) > 0) { + (void) printf("Bad ordering between 0x%08x and 0x%08x", + node, node->right); + ++*error; + } + + return comp_height; +} diff --git a/sis/avl/avl.doc b/sis/avl/avl.doc new file mode 100644 index 0000000..8144a83 --- /dev/null +++ b/sis/avl/avl.doc @@ -0,0 +1,166 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/avl/avl.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +avl_tree * +avl_init_table(compare) +int (*compare)(); + Initialize and return a new avl_tree. Use the function `compare' to + compare items in the tree. `compare' should be of the form: + + int + compare(a,b) + char *a, *b; + + and return a number < 0, == 0, > 0 depending on whether a < b, + a == b, or a > b, respectively. + + +void +avl_free_table(tree, key_delete_func, value_delete_func) +avl_tree *tree; +void (*key_delete_func)(); +void (*value_delete_func)(); + + Delete all storage associated with `tree'. The functions + key_delete_func and value_delete_func, if non-null, are called + to free each (key, value) pair. They are declared as: + + void + key_delete_func(key) + char *key; + {} + + void + value_delete_func(value) + char *value; + {} + + The C-library function free is often suitable as a free function. + + +avl_first(tree, key_p, value_p) +avl_tree *tree; +char **key_p; +char **value_p; + Retrieves the smallest element in the tree. Returns 0 if there + are no elements in the tree. + + +avl_last(tree, key_p, value_p) +avl_tree *tree; +char **key_p; +char **value_p; + Retrieves the largest element in the tree. Returns 0 if there + are no elements in the tree. + + +avl_lookup(tree, key, value_p) +avl_tree *tree; +char *key; +char **value_p; + Search for an entry matching `key'. If found, set `value_p' to + the associated value field and return 1. If not found, return + 0 and leave `value_p' unchanged. + + +avl_insert(tree, key, value); +avl_tree *tree; +char *key; +char *value; + Insert the value `value' under the key `key'. Multiple items + are allowed with the same value; all are inserted. + + +avl_delete(tree, key_p, value_p) +avl_tree *tree; +char **key_p; +char **value_p; + Search for the item with key `*key_p' in `tree'. If found, set + `key_p' and `value_p' to point to the key and value of item, + delete the item and return 1. Otherwise return 0 and leave + `key_p' and `value_p' unchanged. WARNING: This interface is + buggy; in particular, if identical keys are in the table, it is + not possible to delete a particular (key, value) pair. This + will be fixed either with 'handles' or a separate delete + function. + + +avl_find_or_add(tree, key, slot_p) +avl_tree *tree; +char *key; +char ***slot_p; + Search for an entry matching key; if not found, insert key and + return the address of the value slot for this entry. If found, + do not insert key, and return the address of the value slot for + the existing entry. slot_p can be used to associate a value with + the key. + + +void +avl_foreach(tree, func, direction) +avl_tree *tree; +int (*func)(); +int direction; + + Apply `func' to each item in the tree `tree' in turn. If + direction is AVL_FORWARD, the tree is traversed from smallest + to largest. Otherwise it is traversed from largest to smallest. + + func should be of the form: + + void + func(key, value) + char *key; + char *value; + + where `key' is the key the item was stored under, and `value' + the value of the item. + + +avl_count(tree) +avl_tree *tree; + Returns the number of entries in the avl tree. + + +avl_generator * +avl_init_gen(tree, direction) +avl_tree *tree; +int direction; + Start up a generator on an avl-tree. direction is either + AVL_FORWARD or AVL_BACKWARD indicating the direction of + generation. + + +avl_gen(gen, key_p, value_p) +avl_generator *gen; +char **key_p; +char **value_p; + Generate the next item from the avl-tree. Returns 0 if there + are no more items in the tree. Deletion of last generated item + (via avl_delete) is supported. Insertion of items during + generation will result in these items never being generated + (until the next avl_init_gen()). Excercise for the interested + student: how does one write an avl generator ? + + +void +avl_free_gen(gen) +avl_generator *gen; + Free a generator. + + +avl_foreach_item(tree, gen, direction, key_p, value_p) +avl_tree *tree; +avl_generator *gen; +int direction; +char **key_p; +char **value_p; + Generate over all items in an avl-tree. This macro iterator + combines avl_init_gen(), avl_gen(), and avl_free_gen() into + a single statement iterator. diff --git a/sis/avl/avl.h b/sis/avl/avl.h new file mode 100644 index 0000000..9ca6517 --- /dev/null +++ b/sis/avl/avl.h @@ -0,0 +1,65 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/avl/avl.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#ifndef AVL_INCLUDED +#define AVL_INCLUDED + + +typedef struct avl_node_struct avl_node; +struct avl_node_struct { + avl_node *left, *right; + char *key; + char *value; + int height; +}; + + +typedef struct avl_tree_struct avl_tree; +struct avl_tree_struct { + avl_node *root; + int (*compar)(); + int num_entries; + int modified; +}; + + +typedef struct avl_generator_struct avl_generator; +struct avl_generator_struct { + avl_tree *tree; + avl_node **nodelist; + int count; +}; + + +#define AVL_FORWARD 0 +#define AVL_BACKWARD 1 + + +EXTERN avl_tree *avl_init_table ARGS((int (*)())); +EXTERN int avl_delete ARGS((avl_tree *, char **, char **)); +EXTERN int avl_insert ARGS((avl_tree *, char *, char *)); +EXTERN int avl_lookup ARGS((avl_tree *, char *, char **)); +EXTERN int avl_first ARGS((avl_tree *, char **, char **)); +EXTERN int avl_last ARGS((avl_tree *, char **, char **)); +EXTERN int avl_find_or_add ARGS((avl_tree *, char *, char ***)); +EXTERN int avl_count ARGS((avl_tree *)); +EXTERN int avl_numcmp ARGS((char *, char *)); +EXTERN int avl_gen ARGS((avl_generator *, char **, char **)); +EXTERN void avl_foreach ARGS((avl_tree *, void (*)(), int)); +EXTERN void avl_free_table ARGS((avl_tree *, void (*)(), void (*)())); +EXTERN void avl_free_gen ARGS((avl_generator *)); +EXTERN avl_generator *avl_init_gen ARGS((avl_tree *, int)); + +#define avl_is_member(tree, key) avl_lookup(tree, key, (char **) 0) + +#define avl_foreach_item(table, gen, dir, key_p, value_p) \ + for(gen = avl_init_gen(table, dir); \ + avl_gen(gen, key_p, value_p) || (avl_free_gen(gen),0);) + +#endif diff --git a/sis/avl/avl_bench1.c b/sis/avl/avl_bench1.c new file mode 100644 index 0000000..4b139ce --- /dev/null +++ b/sis/avl/avl_bench1.c @@ -0,0 +1,72 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/avl/avl_bench1.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:17 $ + * + */ +#include +#include "array.h" +#include "avl.h" +#include "util.h" + +#define MAX_WORD 1024 + +extern long random(); + +/* ARGSUSED */ +main(argc, argv) +char *argv; +{ + array_t *words; + avl_tree *table; + char word[MAX_WORD], *tempi, *tempj; + register int i, j; + long time; +#ifdef TEST + avl_generator *gen; + char *key; +#endif + + /* read the words */ + words = array_alloc(char *, 1000); + while (gets(word) != NIL(char)) { + array_insert_last(char *, words, util_strsav(word)); + if (array_n(words) == 100000) break; + } + + /* scramble them */ + for(i = array_n(words)-1; i >= 1; i--) { + j = random() % i; + tempi = array_fetch(char *, words, i); + tempj = array_fetch(char *, words, j); + array_insert(char *, words, i, tempj); + array_insert(char *, words, j, tempi); + } + +#ifdef TEST + (void) printf("Initial data is\n"); + for(i = array_n(words)-1; i >= 0; i--) { + (void) printf("%s\n", array_fetch(char *, words, i)); + } +#endif + + /* time putting them into an avl tree */ + time = util_cpu_time(); + table = avl_init_table(strcmp); + for(i = array_n(words)-1; i >= 0; i--) { + (void) avl_insert(table, array_fetch(char *, words, i), NIL(char)); + } + (void) printf("Elapsed time for insert of %d objects was %s\n", + array_n(words), util_print_time(util_cpu_time() - time)); + +#ifdef TEST + (void) printf("Sorted data is\n"); + avl_foreach_item(table, gen, AVL_FORWARD, &key, NIL(char *)) { + (void) printf("%s\n", key); + } +#endif + return 0; +} diff --git a/sis/bdd_cmu/Makefile.am b/sis/bdd_cmu/Makefile.am new file mode 100644 index 0000000..662ff31 --- /dev/null +++ b/sis/bdd_cmu/Makefile.am @@ -0,0 +1,7 @@ +SUBDIRS = bdd_cmu bdd_port mem + +if SIS_COND_CMUBDD +pkginclude_HEADERS = bdd.h +endif + +EXTRA_DIST = bdd.h diff --git a/sis/bdd_cmu/Makefile.in b/sis/bdd_cmu/Makefile.in new file mode 100644 index 0000000..9ed47d5 --- /dev/null +++ b/sis/bdd_cmu/Makefile.in @@ -0,0 +1,452 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/bdd_cmu +DIST_COMMON = $(am__pkginclude_HEADERS_DIST) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +am__pkginclude_HEADERS_DIST = bdd.h +am__installdirs = "$(DESTDIR)$(pkgincludedir)" +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +SUBDIRS = bdd_cmu bdd_port mem +@SIS_COND_CMUBDD_TRUE@pkginclude_HEADERS = bdd.h +EXTRA_DIST = bdd.h +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/bdd_cmu/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/bdd_cmu/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || mkdir "$(distdir)/$$subdir" \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="../$(top_distdir)" \ + distdir="../$(distdir)/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am uninstall-pkgincludeHEADERS + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-generic clean-recursive ctags ctags-recursive \ + distclean distclean-generic distclean-recursive distclean-tags \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive \ + mostlyclean mostlyclean-generic mostlyclean-recursive pdf \ + pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \ + uninstall-info-am uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/bdd_cmu/bdd.h b/sis/bdd_cmu/bdd.h new file mode 100644 index 0000000..b49906f --- /dev/null +++ b/sis/bdd_cmu/bdd.h @@ -0,0 +1,344 @@ +/* + * Revision Control Information + * + * /projects/hsis/CVS/utilities/bdd_cmu/bdd_port/bdd.h,v + * shiple + * 1.2 + * 1993/08/10 19:04:56 + * + */ + +/* + * This is the header file for the port from the UCB BDD package to the CMU BDD package. + */ + +#ifndef bdd_h /* { */ +#define bdd_h + +#include "var_set.h" + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef refany +/* this otta be a typedef somewhere */ +#define refany char * /* a void * or any sort of untyped pointer */ +#endif + +#ifndef any /* Ansi C defines this right? */ +/* this otta be a typedef somewhere */ +#define any char /* so that NIL(any) == refany */ +#endif + +/* + * Data structures and typedefs. + */ +#define boolean int +typedef struct bdd_manager_ bdd_manager; /* referenced via a pointer only */ +typedef unsigned int bdd_variableId; /* the id of the variable in a bdd node */ +typedef struct bdd_ bdd_node; /* referenced via a pointer only */ +typedef int bdd_literal; /* integers in the set { 0, 1, 2 } */ + +typedef struct bdd_t { + boolean free; /* TRUE if this is free, FALSE otherwise ... */ + struct bdd_ *node; /* ptr to the top node of the function */ + struct bdd_manager_ *mgr; /* the manager */ +} bdd_t; + +/* + * Initialization data structure. Not supported in CMU package. + */ +typedef struct bdd_mgr_init { + struct { + boolean on; /* TRUE/FALSE: is the cache on */ + unsigned int resize_at; /* percentage at which to resize (e.g. 85% is 85); doesn't apply to adhoc */ + unsigned int max_size; /* max allowable number of buckets; for adhoc, max allowable number of entries */ + } ITE_cache, + ITE_const_cache, + adhoc_cache; + struct { + boolean on; /* TRUE/FALSE: is the garbage collector on */ + } garbage_collector; + struct { + void (*daemon)(); /* used for callback when memory limit exceeded */ + unsigned int limit; /* upper bound on memory allocated by the manager; in megabytes */ + } memory; + struct { + float ratio; /* allocate new bdd_nodes to achieve ratio of used to unused nodes */ + unsigned int init_blocks; /* number of bdd_nodeBlocks initially allocated */ + } nodes; +} bdd_mgr_init; + +/* + * Match types for BDD minimization. + */ +typedef enum { + BDD_MIN_TSM, /* two-side match */ + BDD_MIN_OSM, /* one-side match */ + BDD_MIN_OSDM /* one-side DC match */ +} bdd_min_match_type_t; + +/* + * BDD Manager Allocation And Destruction + */ +EXTERN void bdd_end ARGS((bdd_manager *)); +EXTERN void bdd_register_daemon ARGS((bdd_manager *, void (*daemon)())); +EXTERN void bdd_set_mgr_init_dflts ARGS((bdd_mgr_init *)); +EXTERN bdd_manager *bdd_start ARGS((int)); +EXTERN bdd_manager *bdd_start_with_params ARGS((int, bdd_mgr_init *)); + +/* + * BDD Variable Allocation + */ +EXTERN bdd_t *bdd_create_variable ARGS((bdd_manager *)); +EXTERN bdd_t *bdd_get_variable ARGS((bdd_manager *, bdd_variableId)); + +/* + * BDD Formula Management + */ +EXTERN bdd_t *bdd_dup ARGS((bdd_t *)); +EXTERN void bdd_free ARGS((bdd_t *)); + +/* + * Operations on BDD Formulas + */ +EXTERN bdd_t *bdd_and ARGS((bdd_t *, bdd_t *, boolean, boolean)); +EXTERN bdd_t *bdd_and_smooth ARGS((bdd_t *, bdd_t *, array_t *)); +EXTERN bdd_t *bdd_between ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_cofactor ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_compose ARGS((bdd_t *, bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_consensus ARGS((bdd_t *, array_t *)); +EXTERN bdd_t *bdd_cproject ARGS((bdd_t *, array_t *)); +EXTERN bdd_t *bdd_else ARGS((bdd_t *)); +EXTERN bdd_t *bdd_ite ARGS((bdd_t *, bdd_t *, bdd_t *, boolean, boolean, boolean)); +EXTERN bdd_t *bdd_minimize ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_minimize_with_params ARGS((bdd_t *, bdd_t *, bdd_min_match_type_t, boolean, boolean, boolean)); +EXTERN bdd_t *bdd_not ARGS((bdd_t *)); +EXTERN bdd_t *bdd_one ARGS((bdd_manager *)); +EXTERN bdd_t *bdd_or ARGS((bdd_t *, bdd_t *, boolean, boolean)); +EXTERN bdd_t *bdd_smooth ARGS((bdd_t *, array_t *)); +EXTERN bdd_t *bdd_substitute ARGS((bdd_t *, array_t *, array_t *)); +EXTERN bdd_t *bdd_then ARGS((bdd_t *)); +EXTERN bdd_t *bdd_top_var ARGS((bdd_t *)); +EXTERN bdd_t *bdd_xnor ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_xor ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_zero ARGS((bdd_manager *)); + +/* + * Queries about BDD Formulas + */ +EXTERN boolean bdd_equal ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_intersects ARGS((bdd_t *, bdd_t *)); +EXTERN boolean bdd_is_tautology ARGS((bdd_t *, boolean)); +EXTERN boolean bdd_leq ARGS((bdd_t *, bdd_t *, boolean, boolean)); + +/* + * Statistics and Other Queries + */ +typedef struct bdd_cache_stats { + unsigned int hits; + unsigned int misses; + unsigned int collisions; + unsigned int inserts; +} bdd_cache_stats; + +typedef struct bdd_stats { + struct { + bdd_cache_stats hashtable; /* the unique table; collisions and inserts fields not used */ + bdd_cache_stats itetable; + bdd_cache_stats consttable; + bdd_cache_stats adhoc; + } cache; /* various cache statistics */ + struct { + unsigned int calls; + struct { + unsigned int trivial; + unsigned int cached; + unsigned int full; + } returns; + } ITE_ops, + ITE_constant_ops, + adhoc_ops; + struct { + unsigned int total; + } blocks; /* bdd_nodeBlock count */ + struct { + unsigned int used; + unsigned int unused; + unsigned int total; + unsigned int peak; + } nodes; /* bdd_node count */ + struct { + unsigned int used; + unsigned int unused; + unsigned int total; + unsigned int blocks; + } extptrs; /* bdd_t count */ + struct { + unsigned int times; /* the number of times the garbage-collector has run */ + unsigned int nodes_collected; /* cumulative number of nodes collected over life of manager */ + long runtime; /* cumulative CPU time spent garbage collecting */ + } gc; + struct { + int first_sbrk; /* value of sbrk at start of manager; used to analyze memory usage */ + int last_sbrk; /* value of last sbrk (see "man sbrk") fetched; used to analyze memory usage */ + unsigned int manager; + unsigned int nodes; + unsigned int hashtable; + unsigned int ext_ptrs; + unsigned int ITE_cache; + unsigned int ITE_const_cache; + unsigned int adhoc_cache; + unsigned int total; + } memory; /* memory usage */ +} bdd_stats; + +EXTERN double bdd_count_onset ARGS((bdd_t *, array_t *)); +EXTERN bdd_manager *bdd_get_manager ARGS((bdd_t *)); +EXTERN bdd_node *bdd_get_node ARGS((bdd_t *, boolean *)); +EXTERN void bdd_get_stats ARGS((bdd_manager *, bdd_stats *)); +EXTERN var_set_t *bdd_get_support ARGS((bdd_t *)); +EXTERN array_t *bdd_get_varids ARGS((array_t *)); +EXTERN unsigned int bdd_num_vars ARGS((bdd_manager *)); +EXTERN void bdd_print ARGS((bdd_t *)); +EXTERN void bdd_print_stats ARGS((bdd_stats, FILE *)); +EXTERN int bdd_size ARGS((bdd_t *)); +EXTERN bdd_variableId bdd_top_var_id ARGS((bdd_t *)); + +/* + * Traversal of BDD Formulas + */ +typedef enum { + bdd_EMPTY, + bdd_NONEMPTY +} bdd_gen_status; + +typedef enum { + bdd_gen_cubes, + bdd_gen_nodes +} bdd_gen_type; + +typedef struct { + bdd_manager *manager; + bdd_gen_status status; + bdd_gen_type type; + union { + struct { + array_t *cube; /* of bdd_literal */ + /* ... expansion ... */ + } cubes; + struct { + st_table *visited; /* of bdd_node* */ + /* ... expansion ... */ + } nodes; + } gen; + struct { + int sp; + bdd_node **stack; + } stack; + bdd_node *node; +} bdd_gen; + +/* + * foreach macro in the most misesque tradition + * bdd_gen_free always returns 0 + * + * CAUTION: in the context of the port to the CMU package, it is assumed that + * dynamic reordering will not occur while there are open generators. It is + * the user's responsibility to make sure dynamic reordering doesn't occur. + * As long as new nodes are not created during generation, and you don't + * explicitly call dynamic reordering, you should be okay. + */ + +/* + * foreach_bdd_cube(fn, gen, cube) + * bdd_t *fn; + * bdd_gen *gen; + * array_t *cube; - return + * + * foreach_bdd_cube(fn, gen, cube) { + * ... + * } + */ +#define foreach_bdd_cube(fn, gen, cube)\ + for((gen) = bdd_first_cube(fn, &cube);\ + ((gen)->status != bdd_EMPTY) ? TRUE: bdd_gen_free(gen);\ + (void) bdd_next_cube(gen, &cube)) + +/* + * foreach_bdd_node(fn, gen, node) + * bdd_t *fn; + * bdd_gen *gen; + * bdd_node *node; - return + */ +#define foreach_bdd_node(fn, gen, node)\ + for((gen) = bdd_first_node(fn, &node);\ + ((gen)->status != bdd_EMPTY) ? TRUE: bdd_gen_free(gen);\ + (void) bdd_next_node(gen, &node)) + +EXTERN int bdd_gen_free ARGS((bdd_gen *)); + +/* + * These are NOT to be used directly; only indirectly in the macros. + */ +EXTERN bdd_gen *bdd_first_cube ARGS((bdd_t *, array_t **)); +EXTERN boolean bdd_next_cube ARGS((bdd_gen *, array_t **)); +EXTERN bdd_gen *bdd_first_node ARGS((bdd_t *, bdd_node **)); +EXTERN boolean bdd_next_node ARGS((bdd_gen *, bdd_node **)); + +/* + * Miscellaneous + */ +EXTERN void bdd_set_gc_mode ARGS((bdd_manager *, boolean)); + +/* + * These are the hooks for stuff that uses bdd's + * + * There are three hooks, and users may use them in whatever + * way they wish; these hooks are guaranteed to never be used + * by the bdd package. + */ +typedef struct bdd_external_hooks { + char *network; + char *mdd; + char *undef1; +} bdd_external_hooks; + +EXTERN bdd_external_hooks *bdd_get_external_hooks ARGS((bdd_manager *)); + +/* + * Dynamic reordering. + */ +typedef enum { + BDD_REORDER_SIFT, + BDD_REORDER_WINDOW, + BDD_REORDER_NONE +} bdd_reorder_type_t; + +EXTERN void bdd_dynamic_reordering ARGS((bdd_manager *, bdd_reorder_type_t)); +EXTERN void bdd_reorder ARGS((bdd_manager *)); + +/* + * Default settings. + */ +#define BDD_NO_LIMIT ((1<<30)-2) +#define BDD_DFLT_ITE_ON TRUE +#define BDD_DFLT_ITE_RESIZE_AT 75 +#define BDD_DFLT_ITE_MAX_SIZE 1000000 +#define BDD_DFLT_ITE_CONST_ON TRUE +#define BDD_DFLT_ITE_CONST_RESIZE_AT 75 +#define BDD_DFLT_ITE_CONST_MAX_SIZE 1000000 +#define BDD_DFLT_ADHOC_ON TRUE +#define BDD_DFLT_ADHOC_RESIZE_AT 0 +#define BDD_DFLT_ADHOC_MAX_SIZE 10000000 +#define BDD_DFLT_GARB_COLLECT_ON TRUE +#define BDD_DFLT_DAEMON NIL(void) +#define BDD_DFLT_MEMORY_LIMIT BDD_NO_LIMIT +#define BDD_DFLT_NODE_RATIO 2.0 +#define BDD_DFLT_INIT_BLOCKS 10 + +#endif /* } */ diff --git a/sis/bdd_cmu/bdd_cmu/Makefile.am b/sis/bdd_cmu/bdd_cmu/Makefile.am new file mode 100644 index 0000000..7b28e4b --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/Makefile.am @@ -0,0 +1,15 @@ +AM_CPPFLAGS = -I$(srcdir)/../mem + +libbdd_cmu_a_SOURCES_local = bdd.c bddapply.c bddassoc.c bddblk.c bddcache.c \ + bddcmp.c bddcomp.c bddcproject.c bdddump.c bddhash.c bddint.h bddmisc.c \ + bddprimes.c bddprint.c bddprprofile.c bddqnt.c bddreduce.c bddrelprod.c \ + bddreorder.c bddsat.c bddsize.c bddsupport.c bddswap.c bddunique.c \ + bdduser.h bddwarn.c mtbdd.c + +if SIS_COND_CMUBDD +noinst_LIBRARIES = libbdd_cmu.a +libbdd_cmu_a_SOURCES = $(libbdd_cmu_a_SOURCES_local) +dist_man3_MANS = bdd.3 +endif + +EXTRA_DIST = $(libbdd_cmu_a_SOURCES_local) bdd.3 testbdd.c diff --git a/sis/bdd_cmu/bdd_cmu/Makefile.in b/sis/bdd_cmu/bdd_cmu/Makefile.in new file mode 100644 index 0000000..ddcbc33 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/Makefile.in @@ -0,0 +1,445 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(libbdd_cmu_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/bdd_cmu/bdd_cmu +DIST_COMMON = $(dist_man3_MANS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libbdd_cmu_a_AR = $(AR) $(ARFLAGS) +libbdd_cmu_a_LIBADD = +am__libbdd_cmu_a_SOURCES_DIST = bdd.c bddapply.c bddassoc.c bddblk.c \ + bddcache.c bddcmp.c bddcomp.c bddcproject.c bdddump.c \ + bddhash.c bddint.h bddmisc.c bddprimes.c bddprint.c \ + bddprprofile.c bddqnt.c bddreduce.c bddrelprod.c bddreorder.c \ + bddsat.c bddsize.c bddsupport.c bddswap.c bddunique.c \ + bdduser.h bddwarn.c mtbdd.c +am__objects_1 = bdd.$(OBJEXT) bddapply.$(OBJEXT) bddassoc.$(OBJEXT) \ + bddblk.$(OBJEXT) bddcache.$(OBJEXT) bddcmp.$(OBJEXT) \ + bddcomp.$(OBJEXT) bddcproject.$(OBJEXT) bdddump.$(OBJEXT) \ + bddhash.$(OBJEXT) bddmisc.$(OBJEXT) bddprimes.$(OBJEXT) \ + bddprint.$(OBJEXT) bddprprofile.$(OBJEXT) bddqnt.$(OBJEXT) \ + bddreduce.$(OBJEXT) bddrelprod.$(OBJEXT) bddreorder.$(OBJEXT) \ + bddsat.$(OBJEXT) bddsize.$(OBJEXT) bddsupport.$(OBJEXT) \ + bddswap.$(OBJEXT) bddunique.$(OBJEXT) bddwarn.$(OBJEXT) \ + mtbdd.$(OBJEXT) +@SIS_COND_CMUBDD_TRUE@am_libbdd_cmu_a_OBJECTS = $(am__objects_1) +libbdd_cmu_a_OBJECTS = $(am_libbdd_cmu_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libbdd_cmu_a_SOURCES) +DIST_SOURCES = $(am__libbdd_cmu_a_SOURCES_DIST) +man3dir = $(mandir)/man3 +am__installdirs = "$(DESTDIR)$(man3dir)" +NROFF = nroff +MANS = $(dist_man3_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I$(srcdir)/../mem +libbdd_cmu_a_SOURCES_local = bdd.c bddapply.c bddassoc.c bddblk.c bddcache.c \ + bddcmp.c bddcomp.c bddcproject.c bdddump.c bddhash.c bddint.h bddmisc.c \ + bddprimes.c bddprint.c bddprprofile.c bddqnt.c bddreduce.c bddrelprod.c \ + bddreorder.c bddsat.c bddsize.c bddsupport.c bddswap.c bddunique.c \ + bdduser.h bddwarn.c mtbdd.c + +@SIS_COND_CMUBDD_TRUE@noinst_LIBRARIES = libbdd_cmu.a +@SIS_COND_CMUBDD_TRUE@libbdd_cmu_a_SOURCES = $(libbdd_cmu_a_SOURCES_local) +@SIS_COND_CMUBDD_TRUE@dist_man3_MANS = bdd.3 +EXTRA_DIST = $(libbdd_cmu_a_SOURCES_local) bdd.3 testbdd.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/bdd_cmu/bdd_cmu/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/bdd_cmu/bdd_cmu/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libbdd_cmu.a: $(libbdd_cmu_a_OBJECTS) $(libbdd_cmu_a_DEPENDENCIES) + -rm -f libbdd_cmu.a + $(libbdd_cmu_a_AR) libbdd_cmu.a $(libbdd_cmu_a_OBJECTS) $(libbdd_cmu_a_LIBADD) + $(RANLIB) libbdd_cmu.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-man3: $(man3_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man3dir)" || $(mkdir_p) "$(DESTDIR)$(man3dir)" + @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.3*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 3*) ;; \ + *) ext='3' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \ + done +uninstall-man3: + @$(NORMAL_UNINSTALL) + @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.3*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 3*) ;; \ + *) ext='3' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man3dir)/$$inst"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(man3dir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-man + +install-exec-am: + +install-info: install-info-am + +install-man: install-man3 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-man + +uninstall-man: uninstall-man3 + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-man3 install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am uninstall-man uninstall-man3 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/bdd_cmu/bdd_cmu/bdd.3 b/sis/bdd_cmu/bdd_cmu/bdd.3 new file mode 100644 index 0000000..1aa24c9 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bdd.3 @@ -0,0 +1,2001 @@ +.\" BDD library man page +.TH BDD 3 "11 June 1993" +.SH NAME +bdd \- a binary decision diagram (BDD) package +.SH SYNOPSIS +.B #include +.SH DESCRIPTION +The +.B libbdd +library provides a set of routines for manipulating binary decision +diagrams (BDDs). Some support is also provided for multi-terminal +BDDs (MTBDDs). Programs designed to be used with the library should +use the +.B -lbdd -lmem +options to +.B cc +when linking. +.SH "LIST OF FUNCTIONS" +.nf +.ta 3in +\fIName\fP \fIFunction\fP +bdd_init Initialize the library +bdd_quit Finish using the library +bdd_new_var_first Create a variable first in the order +bdd_new_var_last Create a variable last in the order +bdd_new_var_before Create a variable before an existing one +bdd_new_var_after Create a variable after an existing one +bdd_var_with_index Obtain an existing variable +bdd_var_with_id Obtain an existing variable +bdd_one Constant TRUE +bdd_zero Constant FALSE +bdd_and Logical AND +bdd_nand Logical NAND +bdd_or Logical OR +bdd_nor Logical NOR +bdd_xor Logical XOR +bdd_xnor Logical XNOR +bdd_identity Logical identity +bdd_not Logical NOT +bdd_ite Logical IF-THEN-ELSE +bdd_if Get the variable of the top node in a BDD +bdd_then Get the THEN branch of the top node in a BDD +bdd_else Get the ELSE branch of the top node in a BDD +bdd_if_index Get the index of the top variable in a BDD +bdd_if_id Get a unique ID number for the top variable +bdd_intersects Check intersection +bdd_implies Check boolean implication +bdd_new_assoc Make a new variable association +bdd_free_assoc Free a variable association +bdd_temp_assoc Set the temporary variable association +bdd_augment_temp_assoc Set the temporary variable association +bdd_assoc Set the current variable association +bdd_exists Existential quantification +bdd_forall Universal quantification +bdd_rel_prod Relational product +bdd_compose Substitute for a variable +bdd_substitute Substitute for a set of variables +bdd_reduce Simplify given a constraint +bdd_cofactor Generalized cofactor +bdd_depends_on Determine if a BDD depends on a variable +bdd_support Find the support of a BDD +bdd_satisfy Find a satisfying assignment +bdd_satisfy_support Find a satisfying assignment +bdd_satisfying_fraction Fraction of valuations satisfying a BDD +bdd_swap_vars Swap two variables in a BDD +bdd_apply2 Generic apply routine +bdd_apply1 Generic apply routine +bdd_size Number of nodes in a BDD +bdd_size_multiple Number of nodes in multiple BDDs +bdd_profile Node profile of a BDD +bdd_profile_multiple Node profile of multiple BDDs +bdd_function_profile Function profile of a BDD +bdd_function_profile_multiple Function profile of multiple BDDs +bdd_print_bdd Print a BDD in human-readable form +bdd_print_profile Print a node profile of a BDD +bdd_print_profile_multiple Print a profile of multiple BDDs +bdd_print_function_profile Print a function profile of a BDD +bdd_dump_bdd Write a BDD to a file +bdd_undump_bdd Load a BDD from a file +bdd_type Classify a BDD +bdd_free Decrease the reference count of a BDD +bdd_unfree Increase the reference count of a BDD +bdd_clear_refs Set all BDD reference counts to zero +bdd_gc Garbage collect unused BDD nodes +bdd_total_size Total number of BDD nodes in use +bdd_vars Total number of variables in existence +bdd_cache_ratio Get/set operation result cache size +bdd_node_limit Get/set the number of BDD nodes allowed +bdd_overflow Get/clear overflow flag +bdd_overflow_closure Set a closure to invoke on overflow +bdd_abort_closure Used to abort operations in progress +bdd_stats Print statistics +bdd_dynamic_reordering Specify dynamic reordering technique +bdd_reorder Invoke dynamic reordering +bdd_new_var_block Create variable block +bdd_var_block_reorderable Set block reorderability +mtbdd_free_terminal_closure Called when freeing an MTBDD terminal +mtbdd_get_terminal Get an MTBDD terminal node +mtbdd_terminal_value Get the value of an MTBDD terminal node +mtbdd_ite IF-THEN-ELSE operation for MTBDDs +mtbdd_equal Equality operation for MTBDDs +mtbdd_transform Applies the current transform to an MTBDD +mtbdd_transform_closure Called to set the MTBDD transform +mtbdd_one_data Sets the MTBDD data value for TRUE +.fi +.SH "BASIC CONCEPTS" +For a general overview of BDDs, see the original article by Bryant +[1]. + +Almost all of the BDD library routines require a BDD manager as one of +their arguments. A BDD manager is a structure which holds various +variables used by the BDD routines. The type +.B bdd_manager +is a pointer to this structure. BDDs themselves are also represented +internally as structures. The type +.B bdd +is a pointer to one of these structures. + +There is a global ordering on the boolean variables which may appear +in a BDD. The variable at the root of a BDD is earlier in the +ordering than all other variables in the BDD. Each variable has an +index which represents its position in the ordering; +.I v1 +appears before +.I v2 +in the ordering if and only if the index for +.I v1 +is less than the ordering for \fIv2\fR. Each variable is also +assigned a unique ID number that is invariant. Since variables can be +created at any position within the order, this is not true for the +index. Also, the library supports dynamic variable reordering. With +dynamic variable reordering, variables may be shuffled around in the +middle of an operation in order to reduce the number of BDD nodes in +use. + +Some routines such as +.B bdd_substitute +require a mapping from variables to BDDs to operate. This mapping is +supplied in the form of a variable association which is a set of +pairs. The first element of each pair is the variable, and the second +element is the BDD that the variable is associated with. Multiple +associations may exist at any one time. Other routines such as +.B bdd_exists +require sets of variables. Sets of variables are represented by +variable associations where only the fact that a variable is +associated with some BDD is significant. There is one association, +called the temporary variable association, which is special in two +ways. First, this association always exists. Second, results are not +cached across calls when this association is used. The temporary +association is intended for when an association will not be reused. +The advantage of using it is that setting the temporary association +does not require scanning the result cache to flush out-of-date +results. + +The results returned by the library represent canonical forms and may +be checked for equivalence using the standard C comparison operators. +For example: + +.nf +{ + bdd_manager bddm; + bdd f; + ... + if (f == bdd_one(bddm)) /* Tautology check */ + ... +} +.fi + +For checking for relations such as boolean implication, use +.B bdd_intersects +and \fBbdd_implies\fR. + +Multi-terminal BDDs are like BDDs, except an MTBDD may have more than +just the constants TRUE and FALSE at the leaves. Passing an MTBDD to +a routine expecting a BDD will give undefined results, except where +noted below. MTBDDs are built up using +.B mtbdd_get_terminal +and \fBmtbdd_ite\fR. +.SH "STORAGE MANAGEMENT" +Each BDD node has an associated reference count which records the +number of references to the BDD (internal and external). Whenever a +BDD is returned from a function, the reference count for its top node +is incremented. (If the BDD did not exist before, the reference count +will be 1.) Each time a garbage collection occurs, either internally +or because of a call to \fBbdd_gc\fR, all nodes which are not +referenced are reclaimed. The reference count of a BDD may be +decremented by calling \fBbdd_free\fR. This should be done whenever +possible for maximum space efficiency. You may also specify a limit +for the total number of BDD nodes using \fBbdd_node_limit\fR. If it +is not possible to complete an operation without exceeding this limit, +the operation is aborted and (by default) a null pointer is returned. +Whenever this happens, the reference counts of all nodes are restored +to what they were before the operation. If a null pointer is passed +to a routine, the routine simply returns null. Thus, it is not +necessary to check for overflows after each operation. There is also +an internal flag that indicates whether any operation has caused an +overflow. It may be read and reset by \fBbdd_overflow\fR. +Optionally, a user-defined closure may be invoked when an overflow +occurs; see \fBbdd_overflow_closure\fR. Also see \fBbdd_free\fR, +\fBbdd_unfree\fR, \fBbdd_clear_refs\fR, \fBbdd_node_limit\fR and +\fBbdd_gc\fR. The library also includes high-performance replacements +for +.B malloc +and \fBfree\fR. See the discussion at the end of the section on +adding new routines. +.SH "DETAILED DESCRIPTION" +.B bdd_manager +.br +.B bdd_init() +.in +4 +Creates and initializes a new BDD manager. Multiple BDD managers may +exist at any time. +.LP +.B void +.br +.B bdd_quit(bddm) +.br +.B bdd_manager bddm; +.in +4 +Deallocates the BDD manager given by +.B bddm +and all the storage associated with it. +.LP +.B bdd +.br +.B bdd_new_var_first(bddm) +.br +.B bdd_manager bddm; +.in +4 +Creates a new variable at the start of the BDD variable ordering and +returns the BDD for it. +.LP +.B bdd +.br +.B bdd_new_var_last(bddm) +.br +.B bdd_manager bddm; +.in +4 +Creates a new variable at the end of the BDD variable ordering and +returns the BDD for it. +.LP +.B bdd +.br +.B bdd_new_var_before(bddm, var) +.br +.B bdd_manager bddm; +.br +.B bdd var; +.in +4 +Creates a new variable which is before +.B var +in the BDD variable ordering and returns the BDD for the new variable. +.LP +.B bdd +.br +.B bdd_new_var_after(bddm, var) +.br +.B bdd_manager bddm; +.br +.B bdd var; +.in +4 +Creates a new variable which is after +.B var +in the BDD variable ordering and returns the BDD for the new variable. +.LP +.B bdd +.br +.B bdd_var_with_index(bddm, i) +.br +.B bdd_manager bddm; +.br +.B long i; +.in +4 +If a variable with index +.B i +has been created, returns the BDD for the variable. If no such +variable exists, returns null. See also \fBbdd_if_index\fR. +.LP +.B bdd +.br +.B bdd_var_with_id(bddm, i) +.br +.B bdd_manager bddm; +.br +.B long i; +.in +4 +If a variable with ID +.B i +has been created, returns the BDD for the variable. If no such +variable has been created, returns null. See also \fBbdd_if_id\fR. +.LP +.B bdd +.br +.B bdd_one(bddm) +.br +.B bdd_manager bddm; +.in +4 +Returns the BDD for the constant TRUE. +.LP +.B bdd +.br +.B bdd_zero(bddm) +.br +.B bdd_manager bddm; +.in +4 +Returns the BDD for the constant FALSE. +.LP +.B bdd +.br +.B bdd_and(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +Returns the BDD for the logical AND of +.B f +and \fBg\fR. +.LP +.B bdd +.br +.B bdd_nand(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +Returns the BDD for the logical NAND of +.B f +and \fBg\fR. +.LP +.B bdd +.br +.B bdd_or(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +Returns the BDD for the logical OR of +.B f +and \fBg\fR. +.LP +.B bdd +.br +.B bdd_nor(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +Returns the BDD for the logical NOR of +.B f +and \fBg\fR. +.LP +.B bdd +.br +.B bdd_xor(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +Returns the BDD for the logical XOR of +.B f +and \fBg\fR. +.LP +.B bdd +.br +.B bdd_xnor(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +Returns the BDD for the logical XNOR of +.B f +and \fBg\fR. +.LP +.B bdd +.br +.B bdd_identity(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns the BDD for \fBf\fR. The only real effect of this function is +to increase the reference count of \fBf\fR. Also works with MTBDDs. +.LP +.B bdd +.br +.B bdd_not(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns the BDD for the logical NOT of \fBf\fR. +.LP +.B bdd +.br +.B bdd_ite(bddm, f, g, h) +.br +.B bdd_manager bddm; +.br +.B bdd f, g, h; +.in +4 +Returns the BDD for the logical operation IF +.B f +THEN +.B g +ELSE \fBh\fR. +.LP +.B bdd +.br +.B bdd_if(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns the BDD for the variable which labels the root of the BDD +given by \fBf\fR. Also works with MTBDDs. The result is undefined if +.B f +is one of the constants TRUE or FALSE or an MTBDD terminal node. +.LP +.B bdd +.br +.B bdd_then(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns the BDD for the THEN branch of the root of the BDD given by +\fBf\fR. Also works with MTBDDs. The result is undefined if +.B f +is one of the constants TRUE or FALSE or an MTBDD terminal node. +.LP +.B bdd +.br +.B bdd_else(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns the BDD for the ELSE branch of the root of the BDD given by +\fBf\fR. Also works with MTBDDs. The result is undefined if +.B f +is one of the constants TRUE or FALSE or an MTBDD terminal node. +.LP +.B long +.br +.B bdd_if_index(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns the index of the variable which labels the root of the BDD +given by \fBf\fR. Also works with MTBDDs. The result is undefined if +.B f +is one of the constants TRUE or FALSE or an MTBDD terminal node. The +variable at the start of variable ordering has index 0, the next has +index 1, etc. Note that creating new variables may change the index +of existing variables. Dynamic reordering may also change the index +of variables. +.LP +.B long +.br +.B bdd_if_id(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns a unique ID number for the variable which labels the root of +the BDD given by \fBf\fR. Also works with MTBDDs. The result is +undefined if +.B f +is one of the constants TRUE or FALSE or an MTBDD terminal node. The +ID for a variable is fixed at the time the variable is created and +never changes after that. +.LP +.B bdd +.br +.B bdd_intersects(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +Computes a BDD that implies the conjunction of +.B f +and \fBg\fR. If the conjunction is not FALSE, then the BDD returned +will not be FALSE. Also, the function tries to construct as few new +nodes as possible. This routine is intended for cases where you need +to test for a FALSE conjunction, and, when it the conjunction is not +FALSE, to obtain just one valuation satisfying both +.B f +and \fBg\fR. A non-FALSE result from +.B bdd_intersects +can be passed directly to a routine like \fBbdd_satisfy_support\fR. +.LP +.B bdd +.br +.B bdd_implies(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +This is equivalent to calling +.B bdd_intersects +with +.B f +and NOT \fBg\fR. +.LP +.B int +.br +.B bdd_new_assoc(bddm, assoc, pairs) +.br +.B bdd_manager bddm; +.br +.B bdd *assoc; +.br +.B int pairs; +.in +4 +Creates or finds a variable association. The association is specified +by +.B assoc +and should be a null-terminated array of BDDs. If +.B pairs +is 0, the array is assumed to be an array of variables. In this case, +each variable is paired with the BDD for TRUE. Such an association +may essentially be viewed as specifying a set of variables for use +with routines such as \fBbdd_exists\fR. If +.B pairs +is nonzero, then the even numbered array elements should be variables +and the odd numbered elements should be the BDDs which they are mapped +to. In both cases, the return value is an integer identifier for this +association. Note: if the given association is equivalent to one +which already exists, the same identifier is used for both, and the +reference count of the association is increased by one. +.LP +.B void +.br +.B bdd_free_assoc(bddm, id) +.br +.B bdd_manager bddm; +.br +.B int id; +.in +4 +Decrements the reference count of the variable association with +identifier \fBid\fR, and frees it if the reference count becomes zero. +.LP +.B void +.br +.B bdd_temp_assoc(bddm, assoc, pairs) +.br +.B bdd_manager bddm; +.br +.B bdd *assoc; +.br +.B int pairs; +.in +4 +Sets the temporary variable association. The arguments +.B assoc +and +.B pairs +are as in \fBbdd_new_assoc\fR. +.LP +.B void +.br +.B bdd_augment_temp_assoc(bddm, assoc, pairs) +.br +.B bdd_manager bddm; +.br +.B bdd *assoc; +.br +.B int pairs; +.in +4 +Add to the temporary variable association. The arguments +.B assoc +and +.B pairs +are as in \fBbdd_new_assoc\fR. Any existing associations are +overwritten. This is mainly used when doing things like substituting +for all variables in a BDD. It isn't necessary to clear out the +temporary association in such cases, so you can save a little time by +using this routine. +.LP +.B int +.br +.B bdd_assoc(bddm, id) +.br +.B bdd_manager bddm; +.br +.B int id; +.in +4 +Sets the current variable association to the one identified by +\fBid\fR. The identifier for the old current association is returned. +The temporary variable association has identifier -1. +.LP +.B bdd +.br +.B bdd_exists(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns the BDD for +.B f +with all the variables that are paired with something in the current +variable association existentially quantified out. +.LP +.B bdd +.br +.B bdd_forall(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns the BDD for +.B f +with all the variables that are paired with something in the current +variable association universally quantified out. +.LP +.B bdd +.br +.B bdd_rel_prod(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +Returns the BDD for the logical AND of +.B f +and +.B g +with all the variables that are paired with something in the current +variable association existentially quantified out. If +.B f +and +.B g +are viewed as boolean relations, this operation corresponds to +relational product. This routine is generally much more efficient +than doing the operations separately. +.LP +.B bdd +.br +.B bdd_compose(bddm, f, g, h) +.br +.B bdd_manager bddm; +.br +.B bdd f, g, h; +.in +4 +Returns the BDD for the substitution of +.B h +for the variable +.B g +in \fBf\fR. When +.B h +does not depend on \fBg\fR, the operation may be viewed as composition +of boolean functions. If +.B h +does depend on \fBg\fR, it corresponds to instantaneous substitution +in a boolean formula. +.LP +.B bdd +.br +.B bdd_substitute(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns the BDD for +.B f +under a substitution defined by the current variable association. +Each variable is replaced by its associated BDD. The substitution is +effectively simultaneous. +.LP +.B bdd +.br +.B bdd_reduce(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +Returns a BDD which agrees with +.B f +for all valuations which satisfy \fBg\fR. The result is usually +smaller in terms of number of BDD nodes than \fBf\fR. This operation +is typically used in state space searches to simplify the +representation for the set of states which will be expanded at each +step. +.LP +.B bdd +.br +.B bdd_cofactor(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f, g; +.in +4 +Returns a BDD for the generalized cofactor of +.B f +by \fBg\fR. The BDD indicated by +.B g +should not be the constant FALSE. For some properties of this +operation, see Touati +.I et al. +[2]. +.LP +.B int +.br +.B bdd_depends_on(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B bdd g; +.in +4 +Returns 1 if the BDD or MTBDD +.B f +depends on the variable given by the BDD \fBg\fR, and returns 0 +otherwise. +.LP +.B void +.br +.B bdd_support(bddm, f, support) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B bdd *support; +.in +4 +Stores the support of +.B f +as a null-terminated sequence of variables in \fBsupport\fR. Works +for MTBDDs also. +.LP +.B bdd +.br +.B bdd_satisfy(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns a BDD which is not false, implies \fBf\fR, and has at most one +BDD node at each level. The BDD indicated by +.B f +should not be the constant FALSE. +.LP +.B bdd +.br +.B bdd_satisfy_support(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns a BDD which is not false, implies \fBf\fR, has at most one +BDD node at each level, and has a node labeled with each variable +which is paired with something in the current variable association. +If +.B f +is the constant FALSE, the result is undefined. +.LP +.B double +.br +.B bdd_satisfying_fraction(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns the fraction of valuations which satisfy \fBf\fR. If +.B f +is a function of +.I n +variables, then 2 to the power +.I n +times this fraction is the number of valuations which satisfy \fBf\fR. +.LP +.B bdd +.br +.B bdd_swap_vars(bddm, f, g, h) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B bdd g; +.br +.B bdd h; +.in +4 +Returns the BDD for +.B f +with +.B g +substituted for +.B h +and +.B h +substituted for \fBg\fR. The substitution is effectively +simultaneous. +.LP +.B bdd +.br +.B bdd_apply2(bddm, terminal_fn, f, g, env) +.br +.B bdd_manager bddm; +.br +.B bdd (*terminal_fn)(); +.br +.B bdd f; +.br +.B bdd g; +.br +.B pointer env; +.in +4 +This is a generic two-argument operation. The behavior of the +operation on terminal values is given by \fBterminal_fn\fR. It should +take as arguments: the BDD manager, pointers to two BDDs (the +arguments for the call), and the pointer given by \fBenv\fR. If the +value of the call can be determined immediately from the arguments, it +should return that value. Otherwise, it should return a null pointer. +In this case, it may also use the BDD pointers that it received to +alter the arguments to the call. A typical use for this ability is to +put the arguments in a canonical order for commutative operations. +The function should not alter the reference counts of either the +arguments or the returned value. Also, the returned value (if +non-null) has its temporary reference count incremented once +automatically. If your function always returns one of the arguments +or TRUE or FALSE, this is the right thing and you don't have to worry +about it. If you want to call other routines to determine the return +value, you should read the section on adding new routines below. +Works with MTBDDs. +.LP +.B bdd +.br +.B bdd_apply1(bddm, terminal_fn, f, env) +.br +.B bdd_manager bddm; +.br +.B bdd (*terminal_fn)(); +.br +.B bdd f; +.br +.B pointer env; +.in +4 +This is a generic one-argument operation. It is basically like +\fBbdd_apply2\fR, except that +.B terminal_fn +takes a single BDD pointer argument instead of the pair of pointers in +the two-argument case. Works with MTBDDs. +.LP +.B long +.br +.B bdd_size(bddm, f, negout) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B int negout; +.in +4 +Returns the number of nodes in \fBf\fR. The parameter +.B negout +is a flag indicating whether negative output pointers should be +considered. The library uses this type of pointer flag internally, +so if the flag is nonzero, the actual number of nodes used is +returned. If the flag is zero, the return value is the number of +nodes which would be needed to represent +.B f +using a basic BDD. Works for MTBDDs too. +.LP +.B long +.br +.B bdd_size_multiple(bddm, fs, negout) +.br +.B bdd_manager bddm; +.br +.B bdd *fs; +.br +.B int negout; +.in +4 +Returns the number of nodes in the set of BDDs or MTBDDs given by +\fBfs\fR, which should be a null-terminated array. Nodes which are +shared among the BDDs are only counted once. The parameter +.B negout +is as in \fBbdd_size\fR. +.LP +.B void +.br +.B bdd_profile(bddm, f, level_counts, negout) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B long *level_counts; +.br +.B int negout; +.in +4 +Returns the ``node profile'' of \fBf\fR, i.e., the number of nodes at +each level in \fBf\fR. The parameter +.B level_counts +should be an array of longs of size one plus the number of variables +in existence (see \fBbdd_vars\fR). On return, this array holds the +profile; the \fIi\fRth entry is the number of nodes labeled with the +variable of index \fIi\fR. The last entry corresponds to the nodes +for TRUE and FALSE. The parameter +.B negout +is as in \fBbdd_size\fR. Works for MTBDDs too; in this case, the +last entry corresponds to the MTBDD terminal nodes. +.LP +.B void +.br +.B bdd_profile_multiple(bddm, fs, level_counts, negout) +.br +.B bdd_manager bddm; +.br +.B bdd* fs; +.br +.B long *level_counts; +.br +.B int negout; +.in +4 +Returns the ``node profile'' of the set of BDDs or MTBDDs given by +\fBfs\fR, which should be a null-terminated array. The parameters +\fBlevel_counts\fR and +.B negout +are as in \fBbdd_profile\fR. +.LP +.B void +.br +.B bdd_function_profile(bddm, f, func_counts) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B long *func_counts; +.in +4 +Returns the ``function profile'' of \fBf\fR, i.e., the number of +functions at or below each level in \fBf\fR. The parameter +.B func_counts +should be an array of longs of size one plus the number of variables +in existence (see \fBbdd_vars\fR). On return, this array holds the +profile. The \fIi\fRth entry corresponds to the number of functions +which can be obtained by restricting those variables of index less +than \fIi\fR, provided that +.B f +has at least one node labeled with the variable of index \fIi\fR. If +.B f +has no nodes labeled with the variable of index \fIi\fR, then the +\fIi\fRth entry of the profile is 0. Works for MTBDDs also. +.LP +.B void +.br +.B bdd_function_profile_multiple(bddm, fs, func_counts) +.br +.B bdd_manager bddm; +.br +.B bdd *fs; +.br +.B long *func_counts; +.in +4 +Returns the ``function profile'' of the set of BDDs or MTBDDs given by +\fBfs\fR, which should be a null-terminated array. The parameter +.B func_counts +is as in \fBbdd_function_profile\fR. +.LP +.B void +.br +.B bdd_print_bdd(bddm, f, naming_fn, terminal_id_fn, env, fp) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B char *(*naming_fn)(); +.br +.B char *(*terminal_id_fn)(); +.br +.B pointer env; +.br +.B FILE *fp; +.in +4 +Prints a human-readable representation of the BDD or MTBDD +.B f +to the file given by \fBfp\fR. The +.B naming_fn +should be a pointer to a function taking a \fBbdd_manager\fR, a +.B bdd +and the pointer given by \fBenv\fR. This function should return +either a null pointer or a string that is the name of the supplied +variable. If it returns a null pointer, a default name is generated +based on the index of the variable. It is also legal for +.B naming_fn +to be null; in this case, default names are generated for all variables. +The macro +.B bdd_naming_fn_none +is a null pointer of suitable type. +.B terminal_id_fn +should be a pointer to a function taking a +.B bdd_manager +and two longs, plus the pointer given by \fBenv\fR. It should +return either a null pointer or a string representing the MTBDD +terminal represented by the given value. If it returns a null +pointer, or if +.B terminal_id_fn +is null, then default names are generated for the terminals. +The macro +.B bdd_terminal_id_fn_none +is a null pointer of suitable type. +.LP +.B void +.br +.B bdd_print_profile(bddm, f, naming_fn, env, width, fp) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B char *(*naming_fn)(); +.br +.B pointer env; +.br +.B int width; +.br +.B FILE *fp; +.in +4 +Prints a node profile of a BDD in histogram form. The argument +.B naming_fn +should be as described in \fBbdd_print_bdd\fR. The width of the +output stream is specified by \fBwidth\fR. This is used to determine +how to scale the histogram. +.LP +.B void +.br +.B bdd_print_profile_multiple(bddm, fs, naming_fn, env, width, fp) +.br +.B bdd_manager bddm; +.br +.B bdd *fs; +.br +.B char *(*naming_fn)(); +.br +.B pointer env; +.br +.B int width; +.br +.B FILE *fp; +.in +4 +Prints a node profile of a set of BDDs, which should be given as a +null-terminated array. The other arguments are as in +\fBbdd_print_profile\fR. +.LP +.B void +.br +.B bdd_print_function_profile(bddm, f, naming_fn, env, width, fp) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B char *(*naming_fn)(); +.br +.B pointer env; +.br +.B int width; +.br +.B FILE *fp; +.in +4 +Prints a function profile of a BDD in histogram form. The arguments +are the same as those to \fBbdd_print_profile\fR. +.LP +.B int +.br +.B bdd_dump_bdd(bddm, f, vars, fp) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B bdd *vars; +.br +.B FILE *fp; +.in +4 +Writes an encoded description of the BDD or MTBDD +.B f +to the file given by \fBfp\fR. The argument +.B vars +should be a null-terminated array of variables that include the +support of \fBf\fR. These variables need not be in order of +increasing index. The function returns a nonzero value if +.B f +was written to the file successfully. +.LP +.B bdd +.br +.B bdd_undump_bdd(bddm, vars, fp, error) +.br +.B bdd_manager bddm; +.br +.B bdd *vars; +.br +.B FILE *fp; +.br +.B int *error; +.in +4 +Loads an encoded description of a BDD or MTBDD from the file given by +\fBfp\fR. The argument +.B vars +should be a null-terminated array of variables that will become the +support of the BDD. As in \fBbdd_dump_bdd\fR, these need not be in +order of increasing index. If the same array of variables is used in +dumping and undumping, the BDD returned will be equal to the one that +was dumped. More generally, if the array +.B v1 +is used when dumping, and the array +.B v2 +is used when undumping, the BDD returned will be equal to the original +BDD with the \fIi\fRth variable in +.B v2 +substituted for the \fIi\fRth variable in +.B v1 +for all \fIi\fR. Null is returned if the operation fails for some +reason (node limit reached, I/O error, invalid file format, etc.). +In this case, an error code is stored in \fBerror\fR. The code will +be one of the following. +.nf +.ta 3in +\fIValue\fR \fIMeaning\fR +BDD_UNDUMP_FORMAT Invalid file format +BDD_UNDUMP_OVERFLOW Node limit exceeded +BDD_UNDUMP_IOERROR File I/O error +BDD_UNDUMP_EOF Unexpected EOF +.fi +.LP +.B int +.br +.B bdd_type(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Returns an integer classifying the BDD or MTBDD \fBf\fR. The possible +return values and their meanings are as follows. +.nf +.ta 3in +\fIValue\fR \fIMeaning\fR +BDD_TYPE_OVERFLOW \fBf\fR is a null pointer +BDD_TYPE_ZERO \fBf\fR is the constant FALSE +BDD_TYPE_ONE \fBf\fR is the constant TRUE +BDD_TYPE_CONSTANT \fBf\fR is an MTBDD constant +BDD_TYPE_POSVAR \fBf\fR is a variable +BDD_TYPE_NEGVAR \fBf\fR is the negation of a variable +BDD_TYPE_NONTERMINAL \fBf\fR is not one of the above +.fi +.LP +.B void +.br +.B bdd_free(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Decreases the reference count of +.B f +by one. When the reference count of a BDD or MTBDD node reaches 0, +the node and any of its children that are not otherwise referenced may +eventually be garbage collected and reused. Intermediate results and +unused BDDs and MTBDDs should be freed whenever possible. For +example: + +.nf +bdd +f_or_g_and_h(bddm, f, g, h) + bdd_manager bddm; + bdd f, g, h; +{ + bdd temp, result; + temp=bdd_and(bddm, g, h); + result=bdd_or(bddm, f, temp); + bdd_free(bddm, temp); /* Free intermediate */ + return (result); +} +.fi +.LP +.B void +.br +.B bdd_unfree(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Increases the reference count of +.B f +by one. This is usually used in conjunction with +\fBbdd_clear_refs\fR. Works with MTBDDs. +.LP +.B void +.br +.B bdd_clear_refs(bddm) +.br +.B bdd_manager bddm; +.in +4 +Sets the reference counts of all BDD and MTBDD nodes (except for the +node for TRUE/FALSE) to 0. Calling this routine and then immediately +calling +.B bdd_unfree +on a set of BDDs has the effect of disposing of all BDDs except those +in the set. +.LP +.B void +.br +.B bdd_gc(bddm) +.br +.B bdd_manager bddm; +.in +4 +Forces a BDD garbage collection; all nodes not reachable from a node +with a nonzero reference count are disposed of. (Garbage collections +also occur internally at various times.) +.LP +.B long +.br +.B bdd_total_size(bddm) +.br +.B bdd_manager bddm; +.in +4 +Returns the number of BDD and MTBDD nodes in existence (including +those which are eligible for garbage collection). +.LP +.B long +.br +.B bdd_vars(bddm) +.br +.B bdd_manager bddm; +.in +4 +Returns the number of variables in existence. +.LP +.B int +.br +.B bdd_cache_ratio(bddm, ratio) +.br +.B bdd_manager bddm; +.br +.B int ratio; +.in +4 +Sets the BDD operation cache size ratio to +.B ratio +and returns the old cache size ratio. The number of cache entries is +constrained to be (roughly) less than the cache size ratio divided by +16 times the number of BDD nodes in existence. The default size ratio +is 4, which gives about 1 cache entry per 4 BDD nodes. The amount of +memory required per node will be about 17+(\fBratio\fR/16)*20 bytes on +a machine with 32-bit words. +.LP +.B void +.br +.B bdd_node_limit(bddm, limit) +.br +.B bdd_manager bddm; +.br +.B long limit; +.in +4 +Sets the number of allowed BDD nodes to +.B limit +and returns the old limit. A value of 0 specifies no limit. If in +the course of an operation, the number of nodes reaches the limit, an +internal garbage collection takes place. If this does not free enough +nodes to continue, the operation is aborted and a null value is +returned. When dynamic reordering is used to shift around large +variable block, this limit may be exceeded during reordering. +.LP +.B int +.br +.B bdd_overflow(bddm) +.br +.B bdd_manager bddm; +.in +4 +Returns 1 if any operation has caused an overflow in the number of +nodes, and 0 otherwise. Calling this routine clears the internal +overflow flag, so subsequent calls will return 0 until the next +overflow occurs. +.LP +.B void +.br +.B bdd_overflow_closure(bddm, overflow_fn, overflow_env) +.br +.B bdd_manager bddm; +.br +.B void (*overflow_fn)(); +.br +.B pointer overflow_env; +.in +4 +Sets the closure to invoke when an overflow occurs. The function +given by +.B overflow_fn +will be invoked as the last stage in the cleanup after the overflow. +The function is passed the BDD manager and the pointer given by +\fBoverflow_env\fR. Typically, the function will jump to a +user-provided error recovery routine. +.LP +.B void +.br +.B bdd_abort_closure(bddm, abort_fn, abort_env) +.br +.B bdd_manager bddm; +.br +.B void (*abort_fn)(); +.br +.B pointer abort_env; +.in +4 +Sets a closure to invoke when the next node creation is attempted. +All temporary results will be cleaned up just before the function +given by +.B abort_fn +is called. The function is passed the BDD manager and the pointer +given by \fBabort_env\fR. Typically, the function will jump to a +user-provided error recovery routine. This functionality is intended +to be used to cleanly interrupt BDD operations. Typically, +.B bdd_abort_closure +will be called within a signal handler. +.LP +.B void +.br +.B bdd_stats(bddm, fp) +.br +.B bdd_manager bddm; +.br +.B FILE *fp; +.in +4 +Prints some statistics to the file given by \fBfp\fR. +.LP +.B void +.br +.B bdd_dynamic_reordering(bddm, reorder_fn) +.br +.B bdd_manager bddm; +.br +.B void (*reorder_fn)(); +.in +4 +Selects the method for dynamic reordering. When dynamic reordering is +being used, the library may attempt to rearrange the BDD variable +ordering in the midst of an operation so as to reduce the number of +nodes in use. There are currently two available reordering methods. +The first, \fBbdd_reorder_stable_window3\fR, permutes the variables +within windows of three adjacent variables so as to minimize the +overall BDD size. This process is repeated until no more reduction in +size occurs. The second method, \fBbdd_reorder_sift\fR, moves each +variable throughout the order to find an optimal position for that +variable (assuming all other variables are fixed). This generally +achieves greater size reductions than the window-based method, but is +slower. The +.B reorder_fn +may also be +.B bdd_reorder_none +(an appropriately cast null pointer), in which case dynamic reordering +is turned off. Also see the discussion on variable blocks in +\fBbdd_new_var_block\fR. +.LP +.B void +.br +.B bdd_reorder(bddm) +.br +.B bdd_manager bddm; +.in +4 +Invoke the current dynamic reordering method. +.LP +.B block +.br +.B bdd_new_var_block(bddm, v, n) +.br +.B bdd_manager bddm; +.br +.B bdd v; +.br +.B long n; +.in +4 +Groups the variable +.B v +and the \fBn\fR-1 variables after it in the ordering into a single +block for purposes of dynamic reordering. The purpose of blocks is to +provide control over the possible orders that dynamic reordering will +consider. In general, the variable blocks form a hierarchy. For +example, a block consisting of the variables with indexes 0 through 3 +might be made up of two sub-blocks, one for the variables with index 0 +and 1, and one for the variables with index 2 and 3. When dynamic +reordering is invoked, it is actually applied to each block within the +hierarchy. Reordering a block involves shuffling around the +sub-blocks within it. Thus, dynamic reordering actually moves groups +of variables rather than single variables. If you know that a group +of variables should be together in the ordering, you should collect +them together into a block. As an example, in BDD-based sequential +verification algorithms, the variables representing the current state +and next state of a state-holding element should generally be adjacent +in a good ordering. By grouping these variables into a block, we can +ensure that only orderings with this property are considered. After a +block has been reordered, each sub-block within it is recursively +reordered as well. You can also specify that certain blocks should +not be reordered (see +.B bdd_var_block_reorderable +below). +.LP +.B void +.br +.B bdd_var_block_reorderable(bddm, b, reorderable) +.br +.B bdd_manager bddm; +.br +.B block b; +.br +.B int reorderable; +.in +4 +If +.B reorderable +is non-zero, turns on reordering for the given block, otherwise turns +it off. By default, blocks are not reorderable. As an example, +suppose we are building the BDDs representing a circuit with distinct +control and data path. In such a case, we typically want to have the +control variables at the top of the ordering. For the data path, we +probably want to have the variables for each bit slice grouped +together, and we want the bit slices to be ordered from +most-significant to least-significant. However, we want to allow +reordering within the control part and within each slice. To do this, +we create the variables in the following order: control variables +first, down to LSB slice variables. Then we create separate variable +blocks for the control part and for each slice. We then turn on +reordering for these blocks. Next, we create a block containing all +of the variables, and we leave reordering off for this block. When +dynamic reordering is invoked, it will rearrange the control variables +and the variables within each slice, but will not move the control +variables or the slices in relation to each other. +.LP +.B void +.br +.B bdd_free_terminal_closure(bddm, free_terminal_fn, free_terminal_env) +.br +.B bdd_manager bddm; +.br +.B void (*free_terminal_fn)(); +.br +.B pointer free_terminal_env; +.in +4 +Sets a closure to invoke when freeing an MTBDD terminal node. The +function receives the BDD manager, two longs representing the value of +the terminal, and the pointer given by \fBfree_terminal_env\fR. If +you using the terminal value to hold pointers to other data +structures, you can set up this routine to free those structures. +.LP +.B bdd +.br +.B mtbdd_get_terminal(bddm, value1, value2) +.br +.B bdd_manager bddm; +.br +.B long value1; +.br +.B long value2; +.in +4 +Creates an MTBDD terminal node corresponding to the value given by +.B value1 +and \fBvalue2\fR. If a terminal node with the value already exists, +its reference count is increased. See also +\fBbdd_free_terminal_closure\fR. +.LP +.B void +.br +.B mtbdd_terminal_value(bddm, f, value1, value2) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B long *value1; +.br +.B long *value2; +.in +4 +.B f +should be an MTBDD terminal node. The value of the node is stored in +.B value1 +and \fBvalue2\fR. +.LP +.B bdd +.br +.B mtbdd_ite(bddm, f, g, h) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B bdd g; +.br +.B bdd h; +.in +4 +.B f +should be a BDD and +.B g +and +.B h +should be MTBDDs. Returns the MTBDD for the operation IF +.B f +THEN +.B g +ELSE \fBh\fR. +.LP +.B bdd +.br +.B mtbdd_substitute(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Does the analog of +.B bdd_substitute +for the MTBDD \fBf\fR. The elements in the variable association must +be BDDs. +.LP +.B bdd +.br +.B mtbdd_equal(bddm, f, g) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.br +.B bdd g; +.in +4 +Returns the BDD which is true for those valuations on which the MTBDDs +.B f +and +.B g +are equal. That is, this is the analog of a logical XNOR for MTBDDs. +.LP +.B bdd +.br +.B mtbdd_transform(bddm, f) +.br +.B bdd_manager bddm; +.br +.B bdd f; +.in +4 +Conceptually applies the user-defined transform to all terminals of +the specified MTBDD. (This is actually done by just flipping the +pointer flag, so this routine is really a macro for \fBbdd_not\fR.) +See \fBmtbdd_transform_closure\fR. +.LP +.B void +.br +.B mtbdd_transform_closure(bddm, canonical_fn, transform_fn, env) +.br +.B bdd_manager bddm; +.br +.B int (*canonical_fn)(); +.br +.B void (*transform_fn)(); +.br +.B pointer env; +.in +4 +Sets the MTBDD terminal transformation closure. Currently in the +library, the pointer representing a boolean function and the pointer +representing the negation of that function are identical except for +the low-order bit. Complementing a function is done by simply +toggling that bit. The MTBDD terminal transformation allows this +mechanism to be extended to MTBDDs. Whenever a terminal is created, +.B canonical_fn +will be called. It is passed the BDD manager, two longs representing +the terminal being created, and the pointer given by \fBenv\fR. The +function should return zero if the value is already canonical, and a +non-zero result if it needs to be transformed. If the value needs to +be transformed, then +.B transform_fn +will be called, with the BDD manager, two longs representing the value +to be transformed, pointers to two longs to hold the result, and the +pointer given by \fBenv\fR. The actual terminal node that is created +will contain the transformed value. The original terminal requested +will be represented by a pointer to this node, with the low-order bit +of the pointer set. Also see \fBmtbdd_one_data\fR. If you are going +to call this function, you should do it before creating any MTBDD +terminals. +.LP +.B void +.br +.B mtbdd_one_data(bddm, value1, value2) +.br +.B bdd_manager bddm; +.br +.B long value1; +.br +.B long value2; +.in +4 +If you are planning to use MTBDDs that contain TRUE and FALSE as well +as other values, you may need to use this function to set the MTBDD +value for the node representing TRUE. In this case, also keep in mind +that the when the transformation function is applied to this value, it +should yield the value that you want for FALSE. Also, the value for +TRUE should be regarding as canonical, i.e., TRUE must be represented +by a pointer with the low-order bit cleared. As an example, suppose +that we are planning to use MTBDDs to represent spectral transforms of +boolean functions [4]. In this case, the MTBDD terminal values will +conceptually be integers. Further, it is convenient for TRUE to be +represented by the value -1, and FALSE to be represented by +1. We +will represent terminal values using two longs, with the first long +representing the most-significant part of the integer. We will also +assume a 2's complement representation, so TRUE should be represented +by the data values -1 and -1. Since the value for FALSE is the +negation of that for TRUE, we will have our transform function +represent integer negation. Also, since we want the value for TRUE to +be canonical, we will regard nonnegative values as canonical. Thus, +we define + +.nf +int +canonical_fn(bddm, value1, value2, env) + bdd_manager bddm; + long value1; + long value2; + pointer env; +{ + return (value1 > 0 || (!value1 && value2 > 0)); +} + +void +transform_fn(bddm, value1, value2, result1, result2, env) + bdd_manager bddm; + long value1; + long value2; + long *result1; + long *result2; + pointer env; +{ + if (!value2) + /* Will be a carry when taking 2's complement of value2. Thus, */ + /* take 2's complement of high part. */ + value1= -value1; + else + { + value2= -value2; + value1= ~value1; + } + *result1=value1; + *result2=value2; +} +.fi + +We then call +.B mtbdd_transform_closure +to register these functions, and use + +.nf +bdd_one_data(bddm, -1l, -1l); +.fi + +to set the value for TRUE to -1. (The default canonical checking and +transformation functions and the default MTBDD values for TRUE and +FALSE are actually as given in this example.) If you are going to +call \fBbdd_one_data\fR, you should do it before creating any MTBDD +terminals. +.SH "ADDING NEW ROUTINES" +If you want to add new routines to the library, you would be +well-advised to look at some of the existing ones to get a feel for +how they operate. Good ones include \fBbdd_ite\fR (the basic logical +operation) and \fBbdd_exists\fR (a routine using variable +associations). Some basic points are explained below. To get the +declarations of the internal library data structures and routines, you +should +.B #include +instead of using \fBbdduser.h\fR. You will probably want to study +this file to become familiar with the data structures. + +Pointers to BDD nodes and cache entries are tagged using the low three +bits of the pointer. Because of this, all structures must be aligned +on eight byte boundaries. The storage allocation routines guarantee +this alignment. The tag field of a tagged pointer is extracted with +the +.B TAG +macro. The +.B POINTER +macro masks off the tag to get the actual pointer. If the pointer is +a pointer to a BDD node, you can use +.B BDD_POINTER +instead; this just casts the result to a +.B bdd +after masking off the tag. The tag can be set using \fBSET_TAG\fR, and +individual tag bits can be manipulated with \fBTAG0\fR, +.B FLIP_TAG0 +and \fBSET_TAG0\fR for tag bit 0, and the analogous macros for tag +bits 1 and 2. More commonly, slightly higher level macros are used +for manipulating tags. For BDD nodes, there is only one tag bit that +is actually used. When it is set, it indicates the pointer should be +interpreted as representing the complement of the node that it points +to. (Or for MTBDDs, that it should be interpreted as transformed +using the user-definable transformation function). There are macros +for testing, clearing, and flipping the negation flag. + +Before using the macros below on a pointer \fBf\fR, you need to use +\fBBDD_SETUP(f)\fR. This actually declares a new variable to hold the +masked pointer \fBBDD_POINTER(f)\fR. Hence, it needs to be placed at +some point where a variable declaration could legally go. If you +change \fBf\fR, you can reset this internal variable using +\fBBDD_RESET\fR. + +BDD pointers are generally manipulated using the following macros. +Below, ``node'' refers to the node referenced by the pointer. +.LP +.B BDD_IS_CONST +.in +4 +Tests if the node represents the constant TRUE or FALSE or an MTBDD +terminal node. +.LP +.B BDD_INDEX +.in +4 +Returns the index of the node, or +.B BDD_MAX_INDEX +if given a constant node. +.LP +.B BDD_INDEXINDEX +.in +4 +Returns the index index of a node. This field is the value returned +by \fBbdd_if_id\fR and is invariant; when you create a new variable, +the index of old nodes may change, but the index index stays the same. +When you call \fBbdd_find\fR, you pass the desired index index of the +new node, not the index. +.LP +.B BDD_NOT +.in +4 +Flips the negation flag on a pointer. +.LP +.B BDD_THEN, BDD_ELSE +.in +4 +Return the THEN and ELSE pointers of a node, taking proper account of +pointer flags. These are used for doing Shannon expansions on a node. +.LP +.B BDD_TOP_VAR2 +Takes a \fBbdd_manager\fR, a variable that can hold an index index, +and two \fBbdd\fRs. Sets the index index variable to the index index +of the variable with the lowest index among the variables at the roots +of the BDDs. This index index can then be used with... +.LP +.B BDD_COFACTOR +Takes an index index, a BDD, and two variables of type \fBbdd\fR, and +sets the two variables either to the original BDD or to the cofactors +of the original BDD with respect to its top variable, depending on +whether the index index of the first BDD matches that specified. You +can do a Shannon expansion on the top variable of two BDDs by using +.B BDD_TOP_VAR2 +to get the index index of the highest variable and then using +.B BDD_COFACTOR +to take the appropriate cofactors. +.LP +.B BDD_MARK +.in +4 +Accesses the mark field of a node. This expands to a l-value, so you +can set the mark with this as well. (But see BDD_TEMP_REFS below.) +.LP +.B BDD_ONE, BDD_ZERO +.in +4 +Take a BDD manager and give back the BDDs for TRUE and FALSE. +.LP +.B BDD_REFS +.in +4 +Accesses the reference count field of a node. +.LP +.B BDD_INCREFS, BDD_DECREFS +.in +4 +Increment and decrement the reference count. +.LP +.B BDD_TEMP_REFS +.in +4 +Accesses the temporary reference count field of a node. The temporary +reference count and the mark actually share storage, so you can't use +both at once! That is, unless you are very clever, you can't write a +routine that builds temporary nodes and uses the marks. +.LP +.B BDD_TEMP_INCREFS, BDD_TEMP_DECREFS +.in +4 +Increment and decrement the temporary reference count. +.LP + +New BDD nodes are created using \fBbdd_find\fR. This routine takes a +BDD manager, an index index, and two subBDDs as arguments. New MTBDD +terminals can be created with \fBbdd_find_terminal\fR. The result +cache is manipulated using the +.B bdd_lookup_in_cache +and +.B bdd_insert_in_cache +routines. There are different versions of these routines depending on +exactly what is being cached. The basic ones are +\fBbdd_lookup_in_cache31\fR and \fBbdd_insert_in_cache31\fR. +The first of these takes a cache entry type (CACHE_TYPE_ITE, +CACHE_TYPE_TWO, etc.), three arguments of unspecified type (passed as +longs), and a pointer to an unspecified type of result (a pointer to a +long). It returns a nonzero result if the lookup succeeds. The +corresponding insert routine is similar except that the result is +passed in as a long, and nothing is returned. There are similar +functions that are for routines that take two arguments and return two +results (or a single double-word result), or for routines that take +one argument and return three results. There are also macros such as +\fBbdd_lookup_in_cache2\fR that are wrappers for things like +two-argument functions, etc. In general, some action must be taken +when results are returned from the cache, when entries are purged from +the cache, when entries are garbage collected, and when a variable +association ID is reclaimed. For the built-in cache entry types, +these actions are done automatically. For example, when a BDD is +returned from an entry with CACHE_TYPE_TWO, the temporary reference +count of the BDD is incremented. Some of the entry types are +available for customization. The actions to take for these entry +types are specified by calling \fBbdd_cache_functions\fR. This +function takes a BDD manager, an integer between 1 and 3 specifying +the number of arguments you want to cache on, and four function +pointers. When returning a result, purging an entry, garbage +collecting, or reclaiming an association ID, these functions are +called. The first three functions are passed the BDD manager and the +entry. (The tag bits will have already been masked off the entry +pointer.) The last receives these plus the association ID being freed +(cast to a pointer). The garbage collection function should return a +nonzero result if the entry should be garbage collected. If the entry +contains some BDD nodes, they should be tested with \fBBDD_IS_USED\fR. +The function called when an association ID is reclaimed should return +a nonzero result if the entry should be flushed from the cache. This +function and the purge function and return functions may be null, +specifying that no action need be taken. \fBbdd_cache_functions\fR +returns an integer that represents a tag to use with the cache +insertion and lookup routines, or -1 if there are no more free tags +available. The routine \fBbdd_free_cache_tag\fR makes a tag available +again. + +Routines that build new BDD nodes must take into account the +possibility of running into the node limit. The package is set up to +make this easy if you use the following strategy. Organize your +routine as a top-level (user-callable) procedure and an internal +procedure for performing the actual computation. The top-level +procedure should check its arguments before calling the internal +routine. The +.B bdd_check_arguments +function can be used to test for null arguments (indicating a prior +overflow) or arguments with a zero reference count (indicating a bug). +It should also use the +.B FIREWALL +macro to set up an overflow trap. The internal routine should use +temporary reference counts to keep track of the nodes it is using. +When a node is returned from the internal routine, increment its +temporary reference count once. (You don't have to do this for the +constants or for variables, since they can't be garbage collected.) +When you pass a node to \fBbdd_find\fR, its temporary reference count +is decremented once automatically, and its reference count is +incremented. Also, the result of \fBbdd_find\fR has its temporary +reference count incremented once automatically. Hence, if you your +routine has the standard organization (Shannon's expansion followed by +\fBbdd_find\fR on the subresults), you usually don't have to worry +about incrementing or decrementing the reference counts yourself. If +you don't use a subresult, or if you want a subresult to stick around +after calling \fBbdd_find\fR, you'll have to do the appropriate +twiddling. When the internal routine finally returns, you should have +a BDD with a single temporary reference count. Use +.B RETURN_BDD +to convert this temporary reference count to an external one and +return the result to the user. If you follow this strategy, you won't +have to deal with overflow; when the node limit is reached, +\fBbdd_find\fR will try garbage collecting, and if that doesn't work, +will call the overflow trap set up by \fBFIREWALL\fR. The overflow +trap handler will automatically zero all temporary reference counts +and return a null pointer to the user. Note: if you want to call +other routines, such as the IF-THEN-ELSE routine, within your internal +procedure, you should call the internal procedure for the routine. +That way, the overflow handler will give control back to the user +if the routine you are calling causes an overflow. + +A typical routine looks like: + +.nf +bdd +foo_step(bddm, f, g) + bdd_manager bddm; + bdd f, g; +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + BDD_SETUP(g); + if () + { + BDD_TEMP_INCREFS(f); + return (f); + } + if (bdd_lookup_in_cache2(bddm, , f, g, &result)) + return (result); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + temp1=foo_step(bddm, f1, g1); + temp2=foo_step(bddm, f2, g2); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache2(bddm, , f, g, result); + return (result); +} + +bdd +foo(bddm, f, g) + bdd_manager bddm; + bdd f, g; +{ + if (bdd_check_arguments(2, f, g)) + { + FIREWALL(bddm); + RETURN_BDD(foo_step(bddm, f, g)); + } + return ((bdd)0); +} +.fi + +In the case of dynamic variable reordering, the same abort mechanism +is used. After reordering, all reference counts are reset to their +original values and the operation is retried. This is handled +automatically by the FIREWALL macro. (The operation is aborted since +after reordering, the implicit ordering represented in the C +subroutine call stack may be different from the new variable order. +Reordering occurs before freeing the temporaries, since we want to +minimize the aggregate size of the operands plus the result that is +being constructed.) + +Storage can be allocated through a number of mechanisms. The routines +\fBmem_get_block\fR, \fBmem_free_block\fR, and \fBmem_resize_block\fR +are generally used for large single items. For smaller uniformly +sized items, you probably should use a record manager. +.B mem_new_rec_mgr +will return a record manager that handles blocks of a given size. +Use +.B mem_new_rec +and +.B mem_free_rec +to obtain and free individual records. Finally, +.B mem_free_rec_mgr +will dispose of the record manager and all of its associated records. +These routines are documented in more detail in the storage management +library man page. If your structures are at most 64 bytes in size, +you can use the macros +.B BDD_NEW_REC +and \fBBDD_FREE_REC\fR. These obtain records from the internal BDD +record managers. +.SH "PORTABILITY NOTES" +Since pointer tagging is heavily used, you'll have major problems if +you can't cast back and forth between pointers and longs without +losing something. The low-level storage management routines are +fairly UNIX specific; they call +.B sbrk +directly. If you don't have something similar, you may have to +rewrite them. The storage management routines also need to be able to +move and clear blocks of memory whose size is given by a long. You +may have to fiddle with these, especially if you have a machine where +int and long are different. If you encounter portability problems, +let me know; maybe the next release will be able to accommodate your +machine. +.SH "SEE ALSO" +mem(3) +.SH BUGS +Surely you're joking. +.SH REFERENCES +[1] R. E. Bryant. Graph Based Algorithms for Boolean Function +Manipulation. \fIIEEE Transactions on Computers\fR, C-35(8):677-691, +August 1986. +.LP +[2] H. J. Touati, H. Savoj, B. Lin, R. K. Brayton, and A. +Sangiovanni-Vincentelli. Implicit State Enumeration of Finite State +Machines using BDD's. In \fIProceedings of the 1990 IEEE +International Conference on Computer-Aided Design\fR, November, 1990. +.LP +[3] K. S. Brace, R. L. Rudell, and R. E. Bryant. Efficient +Implementation of a BDD Package. In \fIProceedings of the 27th +ACM/IEEE Design Automation Conference\fR, June, 1990. +.LP +[4] E. M. Clarke, K. L. McMillan, X. Zhao, M. Fujita, and J. C.-Y. +Yang. Spectral Transforms for Large Boolean Functions with +Applications to Technology Mapping. In \fIProceedings of the 30th +ACM/IEEE Design Automation Conference\fR, June, 1993. +.SH AUTHOR +David E. Long +.br +long@research.att.com diff --git a/sis/bdd_cmu/bdd_cmu/bdd.c b/sis/bdd_cmu/bdd_cmu/bdd.c new file mode 100644 index 0000000..3f78e2e --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bdd.c @@ -0,0 +1,1402 @@ +/* Basic BDD routines */ + + +#include "bddint.h" + + +/* cmu_bdd_one(bddm) gives the BDD for true. */ + +bdd +#if defined(__STDC__) +cmu_bdd_one(cmu_bdd_manager bddm) +#else +cmu_bdd_one(bddm) + cmu_bdd_manager bddm; +#endif +{ + return (BDD_ONE(bddm)); +} + + +/* cmu_bdd_zero(bddm) gives the BDD for false. */ + +bdd +#if defined(__STDC__) +cmu_bdd_zero(cmu_bdd_manager bddm) +#else +cmu_bdd_zero(bddm) + cmu_bdd_manager bddm; +#endif +{ + return (BDD_ZERO(bddm)); +} + + +bdd +#if defined(__STDC__) +bdd_make_external(bdd f) +#else +bdd_make_external(f) + bdd f; +#endif +{ + BDD_SETUP(f); + BDD_INCREFS(f); + BDD_TEMP_DECREFS(f); + return (f); +} + + +long +#if defined(__STDC__) +bdd_find_block(block b, long index) +#else +bdd_find_block(b, index) + block b; + long index; +#endif +{ + long i, j, k; + + i=0; + j=b->num_children-1; + while (i <= j) + { + k=(i+j)/2; + if (b->children[k]->first_index <= index && b->children[k]->last_index >= index) + return (k); + if (b->children[k]->first_index > index) + j=k-1; + else + i=k+1; + } + return (i); +} + + +void +#if defined(__STDC__) +bdd_block_delta(block b, long delta) +#else +bdd_block_delta(b, delta) + block b; + long delta; +#endif +{ + long i; + + b->first_index+=delta; + b->last_index+=delta; + for (i=0; i < b->num_children; ++i) + bdd_block_delta(b->children[i], delta); +} + + +static +block +#if defined(__STDC__) +shift_block(cmu_bdd_manager bddm, block b, long index) +#else +shift_block(bddm, b, index) + cmu_bdd_manager bddm; + block b; + long index; +#endif +{ + long i, j; + block p; + + if (b->first_index >= index) + { + bdd_block_delta(b, 1l); + return (b); + } + if (b->last_index < index) + return (b); + b->last_index++; + i=bdd_find_block(b, index); + if (i == b->num_children || b->children[i]->first_index == index) + { + b->children=(block *)mem_resize_block((pointer)b->children, (SIZE_T)(sizeof(block)*(b->num_children+1))); + for (j=b->num_children-1; j >= i; --j) + b->children[j+1]=shift_block(bddm, b->children[j], index); + b->num_children++; + p=(block)BDD_NEW_REC(bddm, sizeof(struct block_)); + p->reorderable=0; + p->first_index=index; + p->last_index=index; + p->num_children=0; + p->children=0; + b->children[i]=p; + } + else + while (i < b->num_children) + { + shift_block(bddm, b->children[i], index); + ++i; + } + return (b); +} + + +/* bdd_new_var(bddm, index) creates a new variable with the */ +/* specified index. Existing variables with greater or equal index */ +/* have their index incremented. */ + +static +bdd +#if defined(__STDC__) +bdd_new_var(cmu_bdd_manager bddm, bdd_index_type index) +#else +bdd_new_var(bddm, index) + cmu_bdd_manager bddm; + bdd_index_type index; +#endif +{ + long i; + long temp; + long oldmax; + assoc_list p; + bdd var; + + if (bddm->vars == BDD_MAX_INDEXINDEX) + cmu_bdd_fatal("bdd_new_var: no more indexes"); + if (index > bddm->vars) + cmu_bdd_fatal("bdd_new_var: index out of range"); + if (bddm->vars == bddm->maxvars) + { + /* Expand indexing tables and variable associations. */ + oldmax=bddm->maxvars; + temp=bddm->maxvars*2; + if (temp > BDD_MAX_INDEXINDEX-1) + temp=BDD_MAX_INDEXINDEX-1; + bddm->maxvars=temp; + bddm->variables=(bdd *)mem_resize_block((pointer)bddm->variables, + (SIZE_T)((bddm->maxvars+1)*sizeof(bdd))); + bddm->indexes=(bdd_index_type *)mem_resize_block((pointer)bddm->indexes, + (SIZE_T)((bddm->maxvars+1)*sizeof(bdd_index_type))); + bddm->indexindexes= + (bdd_indexindex_type *)mem_resize_block((pointer)bddm->indexindexes, + (SIZE_T)(bddm->maxvars*sizeof(bdd_indexindex_type))); + bddm->unique_table.tables= + (var_table *)mem_resize_block((pointer)bddm->unique_table.tables, + (SIZE_T)((bddm->maxvars+1)*sizeof(var_table))); + /* Variable associations are padded with nulls in case new variables */ + /* are created. */ + for (p=bddm->assocs; p; p=p->next) + { + p->va.assoc=(bdd *)mem_resize_block((pointer)p->va.assoc, (SIZE_T)((bddm->maxvars+1)*sizeof(bdd))); + for (i=oldmax; i < bddm->maxvars; ++i) + p->va.assoc[i+1]=0; + } + bddm->temp_assoc.assoc=(bdd *)mem_resize_block((pointer)bddm->temp_assoc.assoc, (SIZE_T)((bddm->maxvars+1)*sizeof(bdd))); + for (i=oldmax; i < bddm->maxvars; ++i) + bddm->temp_assoc.assoc[i+1]=0; + } + /* Shift index of following variables. */ + if (index != bddm->vars) + for (i=0; i < bddm->vars; ++i) + if (bddm->indexes[i+1] >= index) + bddm->indexes[i+1]++; + for (p=bddm->assocs; p; p=p->next) + if (p->va.last >= index) + p->va.last++; + if (bddm->temp_assoc.last >= index) + bddm->temp_assoc.last++; + /* Shift indexindex values. */ + for (i=bddm->vars; i > index; --i) + bddm->indexindexes[i]=bddm->indexindexes[i-1]; + /* Make a new variable table. */ + bddm->vars++; + bddm->unique_table.tables[bddm->vars]=bdd_new_var_table(bddm); + /* Create the variable. */ + var=bdd_find_aux(bddm, (bdd_indexindex_type)bddm->vars, (INT_PTR)BDD_ONE(bddm), (INT_PTR)BDD_ZERO(bddm)); + var->refs=BDD_MAX_REFS; + /* Record everything. */ + bddm->variables[bddm->vars]=var; + bddm->indexes[bddm->vars]=index; + bddm->indexindexes[index]=bddm->vars; + /* Make a new variable block containing the variable. */ + shift_block(bddm, bddm->super_block, (long)index); + return (var); +} + + +/* cmu_bdd_new_var_first(bddm) returns the BDD for a new variable at the */ +/* start of the variable order. */ + +bdd +#if defined(__STDC__) +cmu_bdd_new_var_first(cmu_bdd_manager bddm) +#else +cmu_bdd_new_var_first(bddm) + cmu_bdd_manager bddm; +#endif +{ + return (bdd_new_var(bddm, (bdd_index_type)0)); +} + + +/* cmu_bdd_new_var_last(bddm) returns the BDD for a new variable at the */ +/* end of the variable order. */ + +bdd +#if defined(__STDC__) +cmu_bdd_new_var_last(cmu_bdd_manager bddm) +#else +cmu_bdd_new_var_last(bddm) + cmu_bdd_manager bddm; +#endif +{ + return (bdd_new_var(bddm, (bdd_index_type)bddm->vars)); +} + + +/* cmu_bdd_new_var_before(bddm, var) returns the BDD for a new variable */ +/* before the specified one in the variable order. */ + +bdd +#if defined(__STDC__) +cmu_bdd_new_var_before(cmu_bdd_manager bddm, bdd var) +#else +cmu_bdd_new_var_before(bddm, var) + cmu_bdd_manager bddm; + bdd var; +#endif +{ + if (bdd_check_arguments(1, var)) + { + BDD_SETUP(var); + if (cmu_bdd_type_aux(bddm, var) != BDD_TYPE_POSVAR) + { + cmu_bdd_warning("cmu_bdd_new_var_before: argument is not a positive variable"); + if (BDD_IS_CONST(var)) + return (cmu_bdd_new_var_last(bddm)); + } + return (bdd_new_var(bddm, BDD_INDEX(bddm, var))); + } + return ((bdd)0); +} + + +/* cmu_bdd_new_var_after(bddm, var) returns the BDD for a new variable */ +/* after the specified one in the variable order. */ + +bdd +#if defined(__STDC__) +cmu_bdd_new_var_after(cmu_bdd_manager bddm, bdd var) +#else +cmu_bdd_new_var_after(bddm, var) + cmu_bdd_manager bddm; + bdd var; +#endif +{ + if (bdd_check_arguments(1, var)) + { + BDD_SETUP(var); + if (cmu_bdd_type_aux(bddm, var) != BDD_TYPE_POSVAR) + { + cmu_bdd_warning("cmu_bdd_new_var_after: argument is not a positive variable"); + if (BDD_IS_CONST(var)) + return (cmu_bdd_new_var_last(bddm)); + } + return (bdd_new_var(bddm, BDD_INDEX(bddm, var)+1)); + } + return ((bdd)0); +} + + +/* cmu_bdd_var_with_index(bddm, index) returns the variable with the */ +/* specified index, or null if there is no such variable. */ + +bdd +#if defined(__STDC__) +cmu_bdd_var_with_index(cmu_bdd_manager bddm, long index) +#else +cmu_bdd_var_with_index(bddm, index) + cmu_bdd_manager bddm; + long index; +#endif +{ + if (index < 0 || index >= bddm->vars) + return ((bdd)0); + return (bddm->variables[bddm->indexindexes[index]]); +} + + +/* cmu_bdd_var_with_id(bddm, id) returns the variable with the specified */ +/* id, or null if there is no such variable. */ + +bdd +#if defined(__STDC__) +cmu_bdd_var_with_id(cmu_bdd_manager bddm, long indexindex) +#else +cmu_bdd_var_with_id(bddm, indexindex) + cmu_bdd_manager bddm; + long indexindex; +#endif +{ + if (indexindex <= 0 || indexindex > bddm->vars) + return ((bdd)0); + return (bddm->variables[indexindex]); +} + + +static +bdd +#if defined(__STDC__) +cmu_bdd_and_step(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_and_step(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + BDD_SETUP(g); + if (BDD_IS_CONST(f)) + { + if (f == BDD_ZERO(bddm)) + return (f); + BDD_TEMP_INCREFS(g); + return (g); + } + /* f is not constant. */ + if (BDD_IS_CONST(g)) + { + if (g == BDD_ZERO(bddm)) + return (g); + BDD_TEMP_INCREFS(f); + return (f); + } + /* f and g are not constant. */ + if (BDD_SAME_OR_NEGATIONS(f, g)) + { + if (f == g) + { + BDD_TEMP_INCREFS(f); + return (f); + } + return (BDD_ZERO(bddm)); + } + /* f and g are not constant and are not equal or negations. */ + if (BDD_OUT_OF_ORDER(f, g)) + BDD_SWAP(f, g); + if (bdd_lookup_in_cache31(bddm, CACHE_TYPE_ITE, (INT_PTR)f, (INT_PTR)g, (INT_PTR)BDD_ZERO(bddm), (INT_PTR *)&result)) + return (result); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + temp1=cmu_bdd_and_step(bddm, f1, g1); + temp2=cmu_bdd_and_step(bddm, f2, g2); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache31(bddm, CACHE_TYPE_ITE, (INT_PTR)f, (INT_PTR)g, (INT_PTR)BDD_ZERO(bddm), (INT_PTR)result); + return (result); +} + + +static +bdd +#if defined(__STDC__) +cmu_bdd_xnor_step(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_xnor_step(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + int outneg; + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + BDD_SETUP(g); + if (BDD_IS_CONST(f)) + { + BDD_TEMP_INCREFS(g); + if (f == BDD_ONE(bddm)) + return (g); + return (BDD_NOT(g)); + } + if (BDD_IS_CONST(g)) + { + BDD_TEMP_INCREFS(f); + if (g == BDD_ONE(bddm)) + return (f); + return (BDD_NOT(f)); + } + /* f and g are not constant. */ + if (BDD_SAME_OR_NEGATIONS(f, g)) + { + if (f == g) + return (BDD_ONE(bddm)); + return (BDD_ZERO(bddm)); + } + /* f and g are not constant, not same, not negations. */ + if (BDD_OUT_OF_ORDER(f, g)) + BDD_SWAP(f, g); + if (BDD_IS_OUTPOS(g)) + outneg=0; + else + { + outneg=1; + g=BDD_NOT(g); + } + /* g is an uncomplemented output pointer. */ + if (bdd_lookup_in_cache31(bddm, CACHE_TYPE_ITE, (INT_PTR)f, (INT_PTR)g, (INT_PTR)BDD_NOT(g), (INT_PTR *)&result)) + return (outneg ? BDD_NOT(result) : result); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + temp1=cmu_bdd_xnor_step(bddm, f1, g1); + temp2=cmu_bdd_xnor_step(bddm, f2, g2); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache31(bddm, CACHE_TYPE_ITE, (INT_PTR)f, (INT_PTR)g, (INT_PTR)BDD_NOT(g), (INT_PTR)result); + return (outneg ? BDD_NOT(result) : result); +} + + +bdd +#if defined(__STDC__) +cmu_bdd_ite_step(cmu_bdd_manager bddm, bdd f, bdd g, bdd h) +#else +cmu_bdd_ite_step(bddm, f, g, h) + cmu_bdd_manager bddm; + bdd f; + bdd g; + bdd h; +#endif +{ + int outneg; + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd h1, h2; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + BDD_SETUP(g); + BDD_SETUP(h); + if (BDD_IS_CONST(f)) + { + if (f == BDD_ONE(bddm)) + { + BDD_TEMP_INCREFS(g); + return (g); + } + BDD_TEMP_INCREFS(h); + return (h); + } + /* f is not constant. */ + if (BDD_SAME_OR_NEGATIONS(f, g)) + { + if (f == g) + g=BDD_ONE(bddm); + else + g=BDD_ZERO(bddm); + BDD_RESET(g); + } + if (BDD_SAME_OR_NEGATIONS(f, h)) + { + if (f == h) + h=BDD_ZERO(bddm); + else + h=BDD_ONE(bddm); + BDD_RESET(h); + } + if (BDD_IS_CONST(g)) + { + if (BDD_IS_CONST(h)) + { + if (g == h) + return (g); + BDD_TEMP_INCREFS(f); + if (g == BDD_ONE(bddm)) + return (f); + return (BDD_NOT(f)); + } + if (g == BDD_ZERO(bddm)) + return (cmu_bdd_and_step(bddm, BDD_NOT(f), h)); + return (BDD_NOT(cmu_bdd_and_step(bddm, BDD_NOT(f), BDD_NOT(h)))); + } + else if (BDD_SAME_OR_NEGATIONS(g, h)) + { + if (g == h) + { + BDD_TEMP_INCREFS(g); + return (g); + } + return (cmu_bdd_xnor_step(bddm, f, g)); + } + else if (BDD_IS_CONST(h)) + if (h == BDD_ZERO(bddm)) + return (cmu_bdd_and_step(bddm, f, g)); + else + return (BDD_NOT(cmu_bdd_and_step(bddm, f, BDD_NOT(g)))); + /* No special cases; it's a real if-then-else. */ + if (!BDD_IS_OUTPOS(f)) + { + f=BDD_NOT(f); + BDD_SWAP(g, h); + } + /* f is now an uncomplemented output pointer. */ + if (BDD_IS_OUTPOS(g)) + outneg=0; + else + { + outneg=1; + g=BDD_NOT(g); + h=BDD_NOT(h); + } + /* g is now an uncomplemented output pointer. */ + if (bdd_lookup_in_cache31(bddm, CACHE_TYPE_ITE, (INT_PTR)f, (INT_PTR)g, (INT_PTR)h, (INT_PTR *)&result)) + return (outneg ? BDD_NOT(result) : result); + BDD_TOP_VAR3(top_indexindex, bddm, f, g, h); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + BDD_COFACTOR(top_indexindex, h, h1, h2); + temp1=cmu_bdd_ite_step(bddm, f1, g1, h1); + temp2=cmu_bdd_ite_step(bddm, f2, g2, h2); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache31(bddm, CACHE_TYPE_ITE, (INT_PTR)f, (INT_PTR)g, (INT_PTR)h, (INT_PTR)result); + return (outneg ? BDD_NOT(result) : result); +} + + +/* cmu_bdd_ite(bddm, f, g, h) returns the BDD for "if f then g else h". */ + +bdd +#if defined(__STDC__) +cmu_bdd_ite(cmu_bdd_manager bddm, bdd f, bdd g, bdd h) +#else +cmu_bdd_ite(bddm, f, g, h) + cmu_bdd_manager bddm; + bdd f; + bdd g; + bdd h; +#endif +{ + if (bdd_check_arguments(3, f, g, h)) + { + FIREWALL(bddm); + RETURN_BDD(cmu_bdd_ite_step(bddm, f, g, h)); + } + return ((bdd)0); +} + + +/* cmu_bdd_and(bddm, f, g) returns the BDD for "f and g". */ + +bdd +#if defined(__STDC__) +cmu_bdd_and(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_and(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + return (cmu_bdd_ite(bddm, f, g, BDD_ZERO(bddm))); +} + + +/* cmu_bdd_nand(bddm, f, g) returns the BDD for "f nand g". */ + +bdd +#if defined(__STDC__) +cmu_bdd_nand(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_nand(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + bdd temp; + + if ((temp=cmu_bdd_and(bddm, f, g))) + return (BDD_NOT(temp)); + return ((bdd)0); +} + + +/* cmu_bdd_or(bddm, f, g) returns the BDD for "f or g". */ + +bdd +#if defined(__STDC__) +cmu_bdd_or(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_or(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + return (cmu_bdd_ite(bddm, f, BDD_ONE(bddm), g)); +} + + +/* cmu_bdd_nor(bddm, f, g) returns the BDD for "f nor g". */ + +bdd +#if defined(__STDC__) +cmu_bdd_nor(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_nor(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + bdd temp; + + if ((temp=cmu_bdd_or(bddm, f, g))) + return (BDD_NOT(temp)); + return ((bdd)0); +} + + +/* cmu_bdd_xor(bddm, f, g) returns the BDD for "f xor g". */ + +bdd +#if defined(__STDC__) +cmu_bdd_xor(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_xor(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + return (cmu_bdd_ite(bddm, f, BDD_NOT(g), g)); +} + + +/* cmu_bdd_xnor(bddm, f, g) returns the BDD for "f xnor g". */ + +bdd +#if defined(__STDC__) +cmu_bdd_xnor(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_xnor(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + bdd temp; + + if ((temp=cmu_bdd_xor(bddm, f, g))) + return (BDD_NOT(temp)); + return ((bdd)0); +} + + +/* cmu_bdd_identity(bddm, f) returns the BDD for f. (The only effect is */ +/* to increase the reference count for f.) */ + +bdd +#if defined(__STDC__) +cmu_bdd_identity(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_identity(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (bdd_check_arguments(1, f)) + { + BDD_SETUP(f); + BDD_INCREFS(f); + } + return (f); +} + + +/* cmu_bdd_not(bddm, f) returns the BDD for "not f". */ + +bdd +#if defined(__STDC__) +cmu_bdd_not(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_not(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (bdd_check_arguments(1, f)) + { + BDD_SETUP(f); + BDD_INCREFS(f); + return (BDD_NOT(f)); + } + return ((bdd)0); +} + + +/* cmu_bdd_if(bddm, f) returns the BDD for the variable at the top of f. */ + +bdd +#if defined(__STDC__) +cmu_bdd_if(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_if(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (bdd_check_arguments(1, f)) + { + BDD_SETUP(f); + if (BDD_IS_CONST(f)) + { + cmu_bdd_warning("cmu_bdd_if: argument is a constant"); + return (f); + } + FIREWALL(bddm); + RETURN_BDD(BDD_IF(bddm, f)); + } + return (f); +} + + +/* cmu_bdd_if_index(bddm, f) returns the index for the variable at the top */ +/* of f. */ + +long +#if defined(__STDC__) +cmu_bdd_if_index(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_if_index(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (bdd_check_arguments(1, f)) + { + BDD_SETUP(f); + if (BDD_IS_CONST(f)) + return (-1l); + return ((long)BDD_INDEX(bddm, f)); + } + return (-1l); +} + + +/* cmu_bdd_if_id(bddm, f) returns a unique identifier for the variable at */ +/* the top of f. */ + +long +#if defined(__STDC__) +cmu_bdd_if_id(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_if_id(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (bdd_check_arguments(1, f)) + { + BDD_SETUP(f); + if (BDD_IS_CONST(f)) + return (-1l); + return ((long)BDD_INDEXINDEX(f)); + } + return (-1l); +} + + +/* cmu_bdd_then(bddm, f) returns the BDD for the "then" pointer of f. */ + +bdd +#if defined(__STDC__) +cmu_bdd_then(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_then(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (bdd_check_arguments(1, f)) + { + BDD_SETUP(f); + if (BDD_IS_CONST(f)) + { + cmu_bdd_warning("cmu_bdd_then: argument is a constant"); + return (f); + } + f=BDD_THEN(f); + BDD_RESET(f); + BDD_INCREFS(f); + } + return (f); +} + + +/* cmu_bdd_else(bddm, f) returns the BDD for the "else" pointer of f. */ + +bdd +#if defined(__STDC__) +cmu_bdd_else(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_else(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (bdd_check_arguments(1, f)) + { + BDD_SETUP(f); + if (BDD_IS_CONST(f)) + { + cmu_bdd_warning("cmu_bdd_else: argument is a constant"); + return (f); + } + f=BDD_ELSE(f); + BDD_RESET(f); + BDD_INCREFS(f); + } + return (f); +} + + +static +bdd +#if defined(__STDC__) +cmu_bdd_intersects_step(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_intersects_step(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd temp; + + BDD_SETUP(f); + BDD_SETUP(g); + if (BDD_IS_CONST(f)) + { + if (f == BDD_ZERO(bddm)) + return (f); + BDD_TEMP_INCREFS(g); + return (g); + } + /* f is not constant. */ + if (BDD_IS_CONST(g)) + { + if (g == BDD_ZERO(bddm)) + return (g); + BDD_TEMP_INCREFS(f); + return (f); + } + /* f and g are not constant. */ + if (BDD_SAME_OR_NEGATIONS(f, g)) + { + if (f == g) + { + BDD_TEMP_INCREFS(f); + return (f); + } + return (BDD_ZERO(bddm)); + } + /* f and g are not constant and are not equal or negations. */ + if (BDD_OUT_OF_ORDER(f, g)) + BDD_SWAP(f, g); + if (bdd_lookup_in_cache31(bddm, CACHE_TYPE_ITE, (INT_PTR)f, (INT_PTR)g, (INT_PTR)BDD_ZERO(bddm), (INT_PTR *)&temp)) + return (temp); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + temp=cmu_bdd_intersects_step(bddm, f1, g1); + if (temp != BDD_ZERO(bddm)) + return (bdd_find(bddm, top_indexindex, temp, BDD_ZERO(bddm))); + temp=bdd_find(bddm, top_indexindex, BDD_ZERO(bddm), cmu_bdd_intersects_step(bddm, f2, g2)); + if (temp == BDD_ZERO(bddm)) + bdd_insert_in_cache31(bddm, CACHE_TYPE_ITE, (INT_PTR)f, (INT_PTR)g, (INT_PTR)BDD_ZERO(bddm), (INT_PTR)temp); + return (temp); +} + + +/* cmu_bdd_intersects(bddm, f, g) returns a BDD contained in "f and g", */ +/* while building as few nodes as possible. The idea is that it */ +/* gives us a fast test for intersection, and, when f and g do */ +/* intersect, we can call cmu_bdd_satisfy or cmu_bdd_satisfy_support on the */ +/* result to get a valuation in the intersection. */ + +bdd +#if defined(__STDC__) +cmu_bdd_intersects(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_intersects(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + if (bdd_check_arguments(2, f, g)) + { + FIREWALL(bddm); + RETURN_BDD(cmu_bdd_intersects_step(bddm, f, g)); + } + return ((bdd)0); +} + + +/* cmu_bdd_implies(bddm, f, g) is analogous to cmu_bdd_intersects, but it */ +/* looks for things in "f and not g". */ + +bdd +#if defined(__STDC__) +cmu_bdd_implies(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_implies(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + if (bdd_check_arguments(2, f, g)) + { + FIREWALL(bddm); + RETURN_BDD(cmu_bdd_intersects_step(bddm, f, BDD_NOT(g))); + } + return ((bdd)0); +} + + +int +#if defined(__STDC__) +cmu_bdd_type_aux(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_type_aux(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + BDD_SETUP(f); + if (BDD_IS_CONST(f)) + { + if (f == BDD_ZERO(bddm)) + return (BDD_TYPE_ZERO); + if (f == BDD_ONE(bddm)) + return (BDD_TYPE_ONE); + return (BDD_TYPE_CONSTANT); + } + if (BDD_THEN(f) == BDD_ONE(bddm) && BDD_ELSE(f) == BDD_ZERO(bddm)) + return (BDD_TYPE_POSVAR); + if (BDD_THEN(f) == BDD_ZERO(bddm) && BDD_ELSE(f) == BDD_ONE(bddm)) + return (BDD_TYPE_NEGVAR); + return (BDD_TYPE_NONTERMINAL); +} + + +/* cmu_bdd_type(bddm, f) returns BDD_TYPE_ZERO if f is false, BDD_TYPE_ONE */ +/* if f is true, BDD_TYPE_CONSTANT if f is an MTBDD constant, */ +/* BDD_TYPE_POSVAR is f is an unnegated variable, BDD_TYPE_NEGVAR if */ +/* f is a negated variable, BDD_TYPE_OVERFLOW if f is null, and */ +/* BDD_TYPE_NONTERMINAL otherwise. */ + +int +#if defined(__STDC__) +cmu_bdd_type(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_type(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (bdd_check_arguments(1, f)) + return (cmu_bdd_type_aux(bddm, f)); + return (BDD_TYPE_OVERFLOW); +} + + +/* cmu_bdd_unfree(bddm, f) increments the reference count for f. */ + +void +#if defined(__STDC__) +cmu_bdd_unfree(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_unfree(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (f) + { + BDD_SETUP(f); + BDD_INCREFS(f); + } +} + + +/* cmu_bdd_free(bddm, f) decrements the reference count for f. */ + +void +#if defined(__STDC__) +cmu_bdd_free(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_free(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (f) + { + BDD_SETUP(f); + if (BDD_REFS(f) == 0) + cmu_bdd_fatal("cmu_bdd_free: attempt to free node with zero references"); + else + BDD_DECREFS(f); + } +} + + +/* cmu_bdd_vars(bddm) returns the number of variables in existence. */ + +long +#if defined(__STDC__) +cmu_bdd_vars(cmu_bdd_manager bddm) +#else +cmu_bdd_vars(bddm) + cmu_bdd_manager bddm; +#endif +{ + return (bddm->vars); +} + + +/* cmu_bdd_total_size(bddm) returns the number of BDD nodes in existence. */ + +long +#if defined(__STDC__) +cmu_bdd_total_size(cmu_bdd_manager bddm) +#else +cmu_bdd_total_size(bddm) + cmu_bdd_manager bddm; +#endif +{ + return (bddm->unique_table.entries); +} + + +/* cmu_bdd_cache_ratio(bddm, new_ratio) sets the cache size ratio to */ +/* new_ratio and returns the old ratio. */ + +int +#if defined(__STDC__) +cmu_bdd_cache_ratio(cmu_bdd_manager bddm, int new_ratio) +#else +cmu_bdd_cache_ratio(bddm, new_ratio) + cmu_bdd_manager bddm; + int new_ratio; +#endif +{ + int old_ratio; + + old_ratio=bddm->op_cache.cache_ratio; + if (new_ratio < 1) + new_ratio=1; + else if (new_ratio > 32) + new_ratio=32; + bddm->op_cache.cache_ratio=new_ratio; + return (old_ratio); +} + + +/* cmu_bdd_node_limit(bddm, new_limit) sets the node limit to */ +/* new_limit and returns the old limit. */ + +long +#if defined(__STDC__) +cmu_bdd_node_limit(cmu_bdd_manager bddm, long new_limit) +#else +cmu_bdd_node_limit(bddm, new_limit) + cmu_bdd_manager bddm; + long new_limit; +#endif +{ + long old_limit; + + old_limit=bddm->unique_table.node_limit; + if (new_limit < 0) + new_limit=0; + bddm->unique_table.node_limit=new_limit; + if (new_limit && bddm->unique_table.gc_limit > new_limit) + bddm->unique_table.gc_limit=new_limit; + return (old_limit); +} + + +/* cmu_bdd_overflow(bddm) returns 1 if the node limit has been exceeded */ +/* and 0 otherwise. The overflow flag is cleared. */ + +int +#if defined(__STDC__) +cmu_bdd_overflow(cmu_bdd_manager bddm) +#else +cmu_bdd_overflow(bddm) + cmu_bdd_manager bddm; +#endif +{ + int result; + + result=bddm->overflow; + bddm->overflow=0; + return (result); +} + + +/* cmu_bdd_overflow_closure(bddm, overflow_fn, overflow_env) sets the */ +/* closure to be invoked on overflow. If overflow_fn is null, it */ +/* indicates that no function should be called. */ + +void +#if defined(__STDC__) +cmu_bdd_overflow_closure(cmu_bdd_manager bddm, void (*overflow_fn)(cmu_bdd_manager, pointer), pointer overflow_env) +#else +cmu_bdd_overflow_closure(bddm, overflow_fn, overflow_env) + cmu_bdd_manager bddm; + void (*overflow_fn)(); + pointer overflow_env; +#endif +{ + bddm->overflow_fn=overflow_fn; + bddm->overflow_env=overflow_env; +} + + +/* cmu_bdd_abort_closure(bddm, abort_fn, abort_env) sets a closure to be */ +/* invoked when the next find operation is attempted. This is */ +/* intended for aborting BDD operations from signal handlers. The */ +/* handler should set this closure so that invoking it will cause */ +/* a longjmp to a recovery routine. */ + +void +#if defined(__STDC__) +cmu_bdd_abort_closure(cmu_bdd_manager bddm, void (*abort_fn)(cmu_bdd_manager, pointer), pointer abort_env) +#else +cmu_bdd_abort_closure(bddm, abort_fn, abort_env) + cmu_bdd_manager bddm; + void (*abort_fn)(); + pointer abort_env; +#endif +{ + bddm->bag_it_fn=abort_fn; + bddm->bag_it_env=abort_env; +} + + +/* cmu_bdd_stats(bddm, fp) prints random statistics to the file indicated */ +/* by fp. */ + +void +#if defined(__STDC__) +cmu_bdd_stats(cmu_bdd_manager bddm, FILE *fp) +#else +cmu_bdd_stats(bddm, fp) + cmu_bdd_manager bddm; + FILE *fp; +#endif +{ + long i; + long ue, ce, cs, mem; + SIZE_T alloc; + assoc_list q; + + ue=bddm->unique_table.entries; + ce=bddm->op_cache.entries; + cs=bddm->op_cache.size; + mem=0; + for (i=0; i < bddm->vars; ++i) + { + mem+=sizeof(struct var_table_); + mem+=bddm->unique_table.tables[i]->size*sizeof(bdd); + } + mem=ue*sizeof(struct bdd_); + mem+=cs*sizeof(struct cache_bin_)+ce*sizeof(struct cache_entry_); + mem+=bddm->maxvars*(sizeof(bdd_index_type)+sizeof(bdd_indexindex_type)+sizeof(bdd)+sizeof(var_table)); + for (q=bddm->assocs, i=1; q; q=q->next, ++i); + mem+=i*bddm->maxvars*sizeof(bdd); + if ((alloc=mem_allocation())) + /* mem_allocation may be meaningless depending on mem library. */ + fprintf(fp, "Memory manager bytes allocated: %ld\n", (long)alloc); + fprintf(fp, "Approximate bytes used: %ld\n", mem); + fprintf(fp, "Number of nodes: %ld\n", ue); + if (bddm->unique_table.node_limit) + fprintf(fp, "Node limit: %ld\n", bddm->unique_table.node_limit); + else + fprintf(fp, "Node limit: ---\n"); + fprintf(fp, "Overflow: %s\n", bddm->overflow ? "yes" : "no"); + fprintf(fp, "Approximate bytes per node: %-.2f\n", ((double)mem)/ue); + fprintf(fp, "Cache entries: %ld\n", ce); + fprintf(fp, "Cache size: %ld\n", 2*cs); + fprintf(fp, "Cache load factor: %-.2f\n", ((double)ce)/(2*cs)); + fprintf(fp, "Cache look ups: %ld\n", bddm->op_cache.lookups); + fprintf(fp, "Cache hits: %ld\n", bddm->op_cache.hits); + if (bddm->op_cache.lookups) + fprintf(fp, "Cache hit rate: %-.2f\n", ((double)(bddm->op_cache.hits))/bddm->op_cache.lookups); + else + fprintf(fp, "Cache hit rate: ---\n"); + fprintf(fp, "Cache insertions: %ld\n", bddm->op_cache.inserts); + fprintf(fp, "Cache collisions: %ld\n", bddm->op_cache.collisions); + fprintf(fp, "Number of variables: %ld\n", bddm->vars); + fprintf(fp, "Number of variable associations: %d\n", i); + fprintf(fp, "Number of garbage collections: %ld\n", bddm->unique_table.gcs); + fprintf(fp, "Number of nodes garbage collected: %ld\n", bddm->unique_table.freed); + fprintf(fp, "Number of find operations: %ld\n", bddm->unique_table.finds); +} + + +static +int +#if defined(__STDC__) +bdd_default_canonical_fn(cmu_bdd_manager bddm, INT_PTR value1, INT_PTR value2, pointer junk) +#else +bdd_default_canonical_fn(bddm, value1, value2, junk) + cmu_bdd_manager bddm; + INT_PTR value1; + INT_PTR value2; + pointer junk; +#endif +{ + /* Default transformation is treat the value as a 64-bit integer and to */ + /* negate it if it is positive. */ + return ((long)value1 > 0 || (!value1 && (long)value2 > 0)); +} + + +static +void +#if defined(__STDC__) +bdd_default_transform_fn(cmu_bdd_manager bddm, INT_PTR value1, INT_PTR value2, INT_PTR *result1, INT_PTR *result2, pointer junk) +#else +bdd_default_transform_fn(bddm, value1, value2, result1, result2, junk) + cmu_bdd_manager bddm; + INT_PTR value1; + INT_PTR value2; + INT_PTR *result1; + INT_PTR *result2; + pointer junk; +#endif +{ + if (!value2) + /* Will be a carry when taking 2's complement of value2. Thus, */ + /* take 2's complement of high part. */ + value1= -(long)value1; + else + { + value2= -(long)value2; + value1= ~value1; + } + *result1=value1; + *result2=value2; +} + + +/* cmu_bdd_init() creates and returns a new BDD manager. */ + +cmu_bdd_manager +#if defined(__STDC__) +cmu_bdd_init(void) +#else +cmu_bdd_init() +#endif +{ + cmu_bdd_manager bddm; + long i; + + bddm=(cmu_bdd_manager)mem_get_block((SIZE_T)sizeof(struct bdd_manager_)); + bddm->overflow=0; + bddm->overflow_fn=0; + bddm->overflow_env=0; + bddm->bag_it_fn=0; + bddm->bag_it_env=0; + bddm->canonical_fn=bdd_default_canonical_fn; + bddm->transform_fn=bdd_default_transform_fn; + bddm->transform_env=0; + bddm->reorder_fn=0; + bddm->reorder_data=0; + bddm->vars=0; + bddm->maxvars=30; + bddm->check=1; + bddm->variables=(bdd *)mem_get_block((SIZE_T)((bddm->maxvars+1)*sizeof(bdd))); + bddm->indexes=(bdd_index_type *)mem_get_block((SIZE_T)((bddm->maxvars+1)*sizeof(bdd_index_type))); + bddm->indexindexes=(bdd_indexindex_type *)mem_get_block((SIZE_T)(bddm->maxvars*sizeof(bdd_indexindex_type))); + bddm->indexes[BDD_CONST_INDEXINDEX]=BDD_MAX_INDEX; + for (i=0; i < REC_MGRS; ++i) + bddm->rms[i]=mem_new_rec_mgr(MIN_REC_SIZE+ALLOC_ALIGNMENT*i); + bddm->temp_assoc.assoc=(bdd *)mem_get_block((SIZE_T)((bddm->maxvars+1)*sizeof(bdd))); + bddm->temp_assoc.last= -1; + for (i=0; i < bddm->maxvars; ++i) + bddm->temp_assoc.assoc[i+1]=0; + bddm->curr_assoc_id= -1; + bddm->curr_assoc= &bddm->temp_assoc; + bddm->assocs=0; + bddm->temp_op= -1; + bddm->super_block=(block)BDD_NEW_REC(bddm, sizeof(struct block_)); + bddm->super_block->num_children=0; + bddm->super_block->children=0; + bddm->super_block->reorderable=1; + bddm->super_block->first_index= -1; + bddm->super_block->last_index=0; + cmu_bdd_init_unique(bddm); + cmu_bdd_init_cache(bddm); + bddm->one=bdd_find_terminal(bddm, ~(INT_PTR)0, ~(INT_PTR)0); + bddm->one->refs=BDD_MAX_REFS; + bddm->one->mark=0; + bddm->zero=BDD_NOT(bddm->one); + if (sizeof(double) > 2*sizeof(long)) + cmu_bdd_warning("cmu_bdd_init: portability problem for cmu_bdd_satisfying_fraction"); + return (bddm); +} + + +/* cmu_bdd_quit(bddm) frees all storage associated with the BDD manager */ +/* bddm. */ + +void +#if defined(__STDC__) +cmu_bdd_quit(cmu_bdd_manager bddm) +#else +cmu_bdd_quit(bddm) + cmu_bdd_manager bddm; +#endif +{ + int i; + assoc_list p, q; + + cmu_bdd_free_unique(bddm); + cmu_bdd_free_cache(bddm); + mem_free_block((pointer)bddm->variables); + mem_free_block((pointer)bddm->indexes); + mem_free_block((pointer)bddm->indexindexes); + mem_free_block((pointer)bddm->temp_assoc.assoc); + for (p=bddm->assocs; p; p=q) + { + q=p->next; + mem_free_block((pointer)p->va.assoc); + BDD_FREE_REC(bddm, (pointer)p, sizeof(struct assoc_list_)); + } + BDD_FREE_REC(bddm, (pointer)bddm->super_block, sizeof(struct block_)); + for (i=0; i < REC_MGRS; ++i) + mem_free_rec_mgr(bddm->rms[i]); + mem_free_block((pointer)bddm); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddapply.c b/sis/bdd_cmu/bdd_cmu/bddapply.c new file mode 100644 index 0000000..3be4d9e --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddapply.c @@ -0,0 +1,134 @@ +/* BDD generic apply routines */ + + +#include "bddint.h" + + +static +bdd +#if defined(__STDC__) +bdd_apply2_step(cmu_bdd_manager bddm, + bdd (*terminal_fn)(cmu_bdd_manager, bdd *, bdd *, pointer), + long op, + bdd f, + bdd g, + pointer env) +#else +bdd_apply2_step(bddm, terminal_fn, op, f, g, env) + cmu_bdd_manager bddm; + bdd (*terminal_fn)(); + long op; + bdd f; + bdd g; + pointer env; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd temp1, temp2; + bdd result; + + if ((result=(*terminal_fn)(bddm, &f, &g, env))) + { + BDD_SETUP(result); + BDD_TEMP_INCREFS(result); + return (result); + } + if (bdd_lookup_in_cache2(bddm, op, f, g, &result)) + return (result); + { + BDD_SETUP(f); + BDD_SETUP(g); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + temp1=bdd_apply2_step(bddm, terminal_fn, op, f1, g1, env); + temp2=bdd_apply2_step(bddm, terminal_fn, op, f2, g2, env); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache2(bddm, op, f, g, result); + return (result); + } +} + + +bdd +#if defined(__STDC__) +bdd_apply2(cmu_bdd_manager bddm, bdd (*terminal_fn)(cmu_bdd_manager, bdd *, bdd *, pointer), bdd f, bdd g, pointer env) +#else +bdd_apply2(bddm, terminal_fn, f, g, env) + cmu_bdd_manager bddm; + bdd (*terminal_fn)(); + bdd f; + bdd g; + pointer env; +#endif +{ + long op; + + if (bdd_check_arguments(2, f, g)) + { + FIREWALL(bddm); + op=bddm->temp_op--; + RETURN_BDD(bdd_apply2_step(bddm, terminal_fn, op, f, g, env)); + } + return ((bdd)0); +} + + +static +bdd +#if defined(__STDC__) +bdd_apply1_step(cmu_bdd_manager bddm, bdd (*terminal_fn)(cmu_bdd_manager, bdd *, pointer), long op, bdd f, pointer env) +#else +bdd_apply1_step(bddm, terminal_fn, op, f, env) + cmu_bdd_manager bddm; + bdd (*terminal_fn)(); + long op; + bdd f; + pointer env; +#endif +{ + bdd temp1, temp2; + bdd result; + + if ((result=(*terminal_fn)(bddm, &f, env))) + { + BDD_SETUP(result); + BDD_TEMP_INCREFS(result); + return (result); + } + if (bdd_lookup_in_cache1(bddm, op, f, &result)) + return (result); + { + BDD_SETUP(f); + temp1=bdd_apply1_step(bddm, terminal_fn, op, BDD_THEN(f), env); + temp2=bdd_apply1_step(bddm, terminal_fn, op, BDD_ELSE(f), env); + result=bdd_find(bddm, BDD_INDEXINDEX(f), temp1, temp2); + bdd_insert_in_cache1(bddm, op, f, result); + return (result); + } +} + + +bdd +#if defined(__STDC__) +bdd_apply1(cmu_bdd_manager bddm, bdd (*terminal_fn)(cmu_bdd_manager, bdd *, pointer), bdd f, pointer env) +#else +bdd_apply1(bddm, terminal_fn, f, g, env) + cmu_bdd_manager bddm; + bdd (*terminal_fn)(); + bdd f; + pointer env; +#endif +{ + long op; + + if (bdd_check_arguments(1, f)) + { + FIREWALL(bddm); + op=bddm->temp_op--; + RETURN_BDD(bdd_apply1_step(bddm, terminal_fn, op, f, env)); + } + return ((bdd)0); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddassoc.c b/sis/bdd_cmu/bdd_cmu/bddassoc.c new file mode 100644 index 0000000..43bce2d --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddassoc.c @@ -0,0 +1,331 @@ +/* BDD variable association routines */ + + +#include "bddint.h" + + +static +int +#if defined(__STDC__) +cmu_bdd_assoc_eq(cmu_bdd_manager bddm, bdd *p, bdd *q) +#else +cmu_bdd_assoc_eq(bddm, p, q) + cmu_bdd_manager bddm; + bdd *p; + bdd *q; +#endif +{ + bdd_indexindex_type i; + + for (i=0; i < bddm->maxvars; ++i) + if (p[i+1] != q[i+1]) + return (0); + return (1); +} + + +static +int +#if defined(__STDC__) +check_assoc(cmu_bdd_manager bddm, bdd *assoc_info, int pairs) +#else +check_assoc(bddm, assoc_info, pairs) + cmu_bdd_manager bddm; + bdd *assoc_info; + int pairs; +#endif +{ + bdd_check_array(assoc_info); + if (pairs) + while (assoc_info[0] && assoc_info[1]) + { + if (cmu_bdd_type_aux(bddm, assoc_info[0]) != BDD_TYPE_POSVAR) + { + cmu_bdd_warning("check_assoc: first element in pair is not a positive variable"); + return (0); + } + assoc_info+=2; + } + return (1); +} + + +/* cmu_bdd_new_assoc(bddm, assoc_info, pairs) creates or finds a variable */ +/* association given by assoc_info. pairs is 0 if the information */ +/* represents only a list of variables rather than a full association. */ + +int +#if defined(__STDC__) +cmu_bdd_new_assoc(cmu_bdd_manager bddm, bdd *assoc_info, int pairs) +#else +cmu_bdd_new_assoc(bddm, assoc_info, pairs) + cmu_bdd_manager bddm; + bdd *assoc_info; + int pairs; +#endif +{ + long i; + assoc_list p, *q; + bdd f; + bdd *assoc; + bdd_indexindex_type j; + long last; + + if (!check_assoc(bddm, assoc_info, pairs)) + return (-1); + assoc=(bdd *)mem_get_block((SIZE_T)((bddm->maxvars+1)*sizeof(bdd))); + /* Unpack the association. */ + for (i=0; i < bddm->maxvars; ++i) + assoc[i+1]=0; + if (pairs) + for (i=0; (f=assoc_info[i]) && assoc_info[i+1]; i+=2) + { + BDD_SETUP(f); + assoc[BDD_INDEXINDEX(f)]=assoc_info[i+1]; + } + else + for (i=0; (f=assoc_info[i]); ++i) + { + BDD_SETUP(f); + assoc[BDD_INDEXINDEX(f)]=BDD_ONE(bddm); + } + /* Check for existence. */ + for (p=bddm->assocs; p; p=p->next) + if (cmu_bdd_assoc_eq(bddm, p->va.assoc, assoc)) + { + mem_free_block((pointer)assoc); + p->refs++; + return (p->id); + } + /* Find the first unused id. */ + for (q= &bddm->assocs, p= *q, i=0; p && p->id == i; q= &p->next, p= *q, ++i); + p=(assoc_list)BDD_NEW_REC(bddm, sizeof(struct assoc_list_)); + p->id=i; + p->next= *q; + *q=p; + p->va.assoc=assoc; + last= -1; + if (pairs) + for (i=0; (f=assoc_info[i]) && assoc_info[i+1]; i+=2) + { + BDD_SETUP(f); + j=BDD_INDEXINDEX(f); + if ((long)bddm->indexes[j] > last) + last=bddm->indexes[j]; + } + else + for (i=0; (f=assoc_info[i]); ++i) + { + BDD_SETUP(f); + j=BDD_INDEXINDEX(f); + if ((long)bddm->indexes[j] > last) + last=bddm->indexes[j]; + } + p->va.last=last; + p->refs=1; + /* Protect BDDs in the association. */ + if (pairs) + for (i=0; assoc_info[i] && (f=assoc_info[i+1]); i+=2) + { + BDD_SETUP(f); + BDD_INCREFS(f); + } + return (p->id); +} + + +static +int +#if defined(__STDC__) +bdd_flush_id_entries(cmu_bdd_manager bddm, cache_entry p, pointer closure) +#else +bdd_flush_id_entries(bddm, p, closure) + cmu_bdd_manager bddm; + cache_entry p; + pointer closure; +#endif +{ +#if defined(__STDC__) + int (*flush_fn)(cmu_bdd_manager, cache_entry, pointer); +#else + int (*flush_fn)(); +#endif + + flush_fn=bddm->op_cache.flush_fn[TAG(p)]; + if (flush_fn) + return ((*flush_fn)(bddm, CACHE_POINTER(p), closure)); + return (0); +} + + +/* cmu_bdd_free_assoc(bddm, id) deletes the variable association given by */ +/* id. */ + +void +#if defined(__STDC__) +cmu_bdd_free_assoc(cmu_bdd_manager bddm, int assoc_id) +#else +cmu_bdd_free_assoc(bddm, assoc_id) + cmu_bdd_manager bddm; + int assoc_id; +#endif +{ + bdd_indexindex_type i; + bdd f; + assoc_list p, *q; + + if (bddm->curr_assoc_id == assoc_id) + { + bddm->curr_assoc_id= -1; + bddm->curr_assoc= &bddm->temp_assoc; + } + for (q= &bddm->assocs, p= *q; p; q= &p->next, p= *q) + if (p->id == assoc_id) + { + p->refs--; + if (!p->refs) + { + /* Unprotect the BDDs in the association. */ + for (i=0; i < bddm->vars; ++i) + if ((f=p->va.assoc[i+1])) + { + BDD_SETUP(f); + BDD_DECREFS(f); + } + /* Flush old cache entries. */ + bdd_flush_cache(bddm, bdd_flush_id_entries, (pointer)assoc_id); + *q=p->next; + mem_free_block((pointer)(p->va.assoc)); + BDD_FREE_REC(bddm, (pointer)p, sizeof(struct assoc_list_)); + } + return; + } + cmu_bdd_warning("cmu_bdd_free_assoc: no variable association with specified ID"); +} + + +/* cmu_bdd_augment_temp_assoc(bddm, assoc_info, pairs) adds to the temporary */ +/* variable association as specified by assoc_info. pairs is 0 if the */ +/* information represents only a list of variables rather than a full */ +/* association. */ + +void +#if defined(__STDC__) +cmu_bdd_augment_temp_assoc(cmu_bdd_manager bddm, bdd *assoc_info, int pairs) +#else +cmu_bdd_augment_temp_assoc(bddm, assoc_info, pairs) + cmu_bdd_manager bddm; + bdd *assoc_info; + int pairs; +#endif +{ + long i; + bdd_indexindex_type j; + bdd f; + long last; + + if (check_assoc(bddm, assoc_info, pairs)) + { + last=bddm->temp_assoc.last; + if (pairs) + for (i=0; (f=assoc_info[i]) && assoc_info[i+1]; i+=2) + { + BDD_SETUP(f); + j=BDD_INDEXINDEX(f); + if ((long)bddm->indexes[j] > last) + last=bddm->indexes[j]; + if ((f=bddm->temp_assoc.assoc[j])) + { + BDD_SETUP(f); + BDD_DECREFS(f); + } + f=assoc_info[i+1]; + BDD_RESET(f); + bddm->temp_assoc.assoc[j]=f; + /* Protect BDDs in the association. */ + BDD_INCREFS(f); + } + else + for (i=0; (f=assoc_info[i]); ++i) + { + BDD_SETUP(f); + j=BDD_INDEXINDEX(f); + if ((long)bddm->indexes[j] > last) + last=bddm->indexes[j]; + if ((f=bddm->temp_assoc.assoc[j])) + { + BDD_SETUP(f); + BDD_DECREFS(f); + } + bddm->temp_assoc.assoc[j]=BDD_ONE(bddm); + } + bddm->temp_assoc.last=last; + } +} + + +/* cmu_bdd_temp_assoc(bddm, assoc_info, pairs) sets the temporary variable */ +/* association as specified by assoc_info. pairs is 0 if the */ +/* information represents only a list of variables rather than a full */ +/* association. */ + +void +#if defined(__STDC__) +cmu_bdd_temp_assoc(cmu_bdd_manager bddm, bdd *assoc_info, int pairs) +#else +cmu_bdd_temp_assoc(bddm, assoc_info, pairs) + cmu_bdd_manager bddm; + bdd *assoc_info; + int pairs; +#endif +{ + long i; + bdd f; + + /* Clean up old temporary association. */ + for (i=0; i < bddm->vars; ++i) + { + if ((f=bddm->temp_assoc.assoc[i+1])) + { + BDD_SETUP(f); + BDD_DECREFS(f); + } + bddm->temp_assoc.assoc[i+1]=0; + } + bddm->temp_assoc.last= -1; + cmu_bdd_augment_temp_assoc(bddm, assoc_info, pairs); +} + + +/* cmu_bdd_assoc(bddm, id) sets the current variable association to the */ +/* one given by id and returns the ID of the old association. An */ +/* id of -1 indicates the temporary association. */ + +int +#if defined(__STDC__) +cmu_bdd_assoc(cmu_bdd_manager bddm, int assoc_id) +#else +cmu_bdd_assoc(bddm, assoc_id) + cmu_bdd_manager bddm; + int assoc_id; +#endif +{ + int old_assoc; + assoc_list p; + + old_assoc=bddm->curr_assoc_id; + if (assoc_id != -1) + { + for (p=bddm->assocs; p; p=p->next) + if (p->id == assoc_id) + { + bddm->curr_assoc_id=p->id; + bddm->curr_assoc= &p->va; + return (old_assoc); + } + cmu_bdd_warning("cmu_bdd_assoc: no variable association with specified ID"); + } + bddm->curr_assoc_id= -1; + bddm->curr_assoc= &bddm->temp_assoc; + return (old_assoc); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddblk.c b/sis/bdd_cmu/bdd_cmu/bddblk.c new file mode 100644 index 0000000..bfedc24 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddblk.c @@ -0,0 +1,95 @@ +/* BDD variable block routines */ + + +#include "bddint.h" + + +static +void +#if defined(__STDC__) +add_block(block b1, block b2) +#else +add_block(b1, b2) + block b1; + block b2; +#endif +{ + long i, j, k; + block start, end; + + if (b1->num_children) + { + i=bdd_find_block(b1, b2->first_index); + start=b1->children[i]; + j=bdd_find_block(b1, b2->last_index); + end=b1->children[j]; + if (i == j) + add_block(start, b2); + else + { + if (start->first_index != b2->first_index || end->last_index != b2->last_index) + cmu_bdd_fatal("add_block: illegal block overlap"); + b2->num_children=j-i+1; + b2->children=(block *)mem_get_block((SIZE_T)(sizeof(block)*b2->num_children)); + for (k=0; k < b2->num_children; ++k) + b2->children[k]=b1->children[i+k]; + b1->children[i]=b2; + ++i; + for (k=j+1; k < b1->num_children; ++k, ++i) + b1->children[i]=b1->children[k]; + b1->num_children-=(b2->num_children-1); + b1->children=(block *)mem_resize_block((pointer)b1->children, (SIZE_T)(sizeof(block)*b1->num_children)); + } + } + else + { + /* b1 and b2 are blocks representing just single variables. */ + b1->num_children=1; + b1->children=(block *)mem_get_block((SIZE_T)(sizeof(block)*b1->num_children)); + b1->children[0]=b2; + b2->num_children=0; + b2->children=0; + } +} + + +block +#if defined(__STDC__) +cmu_bdd_new_var_block(cmu_bdd_manager bddm, bdd v, long n) +#else +cmu_bdd_new_var_block(bddm, v, n) + cmu_bdd_manager bddm; + bdd v; + long n; +#endif +{ + block b; + + if (bdd_check_arguments(1, v)) + { + BDD_SETUP(v); + if (cmu_bdd_type_aux(bddm, v) != BDD_TYPE_POSVAR) + { + cmu_bdd_warning("cmu_bdd_new_var_block: second argument is not a positive variable"); + if (BDD_IS_CONST(v)) + return ((block)0); + } + b=(block)BDD_NEW_REC(bddm, sizeof(struct block_)); + b->reorderable=0; + b->first_index=BDD_INDEX(bddm, v); + if (n <= 0) + { + cmu_bdd_warning("cmu_bdd_new_var_block: invalid final argument"); + n=1; + } + b->last_index=b->first_index+n-1; + if (b->last_index >= bddm->vars) + { + cmu_bdd_warning("cmu_bdd_new_var_block: range covers non-existent variables"); + b->last_index=bddm->vars-1; + } + add_block(bddm->super_block, b); + return (b); + } + return ((block)0); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddcache.c b/sis/bdd_cmu/bdd_cmu/bddcache.c new file mode 100644 index 0000000..3acb7bf --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddcache.c @@ -0,0 +1,840 @@ +/* BDD system cache routines */ + + +#include "bddint.h" + + +#define HASH1(d1) ((INT_PTR)d1) +#define HASH2(d1, d2) ((INT_PTR)(d1)+(((INT_PTR)(d2)) << 1)) +#define HASH3(d1, d2, d3) ((INT_PTR)(d1)+(((INT_PTR)(d2)) << 1)+(((INT_PTR)(d3)) << 2)) + + +static +void +#if defined(__STDC__) +bdd_purge_entry(cmu_bdd_manager bddm, cache_entry *bin) +#else +bdd_purge_entry(bddm, bin) + cmu_bdd_manager bddm; + cache_entry *bin; +#endif +{ +#if defined(__STDC__) + void (*purge_fn)(cmu_bdd_manager, cache_entry); +#else + void (*purge_fn)(); +#endif + cache_entry p; + + p= *bin; + purge_fn=bddm->op_cache.purge_fn[TAG(p)]; + p=CACHE_POINTER(p); + if (purge_fn) + (*purge_fn)(bddm, p); + bddm->op_cache.entries--; + BDD_FREE_REC(bddm, (pointer)p, sizeof(struct cache_entry_)); + *bin=0; +} + + +static +void +#if defined(__STDC__) +bdd_purge_lru(cmu_bdd_manager bddm, cache_entry *bin) +#else +bdd_purge_lru(bddm, bin) + cmu_bdd_manager bddm; + cache_entry *bin; +#endif +{ + if (bin[1]) + bdd_purge_entry(bddm, bin+1); + bin[1]=bin[0]; +} + + +static +cache_entry +#if defined(__STDC__) +bdd_get_entry(cmu_bdd_manager bddm, int tag, cache_entry *bin) +#else +bdd_get_entry(bddm, tag, bin) + cmu_bdd_manager bddm; + int tag; + cache_entry *bin; +#endif +{ +#if defined(__STDC__) + void (*purge_fn)(cmu_bdd_manager, cache_entry); +#else + void (*purge_fn)(); +#endif + cache_entry p; + + if (bin[0] && bin[1]) + { + p=bin[1]; + purge_fn=bddm->op_cache.purge_fn[TAG(p)]; + p=CACHE_POINTER(p); + if (purge_fn) + (*purge_fn)(bddm, p); + bddm->op_cache.collisions++; + if (bddm->op_cache.cache_level == 0) + bin[1]=bin[0]; + else + ++bin; + } + else + { + p=(cache_entry)BDD_NEW_REC(bddm, sizeof(struct cache_entry_)); + bddm->op_cache.entries++; + if (bin[0]) + ++bin; + } + *bin=(cache_entry)SET_TAG(p, tag); + return (p); +} + + +static +long +#if defined(__STDC__) +bdd_rehash1(cmu_bdd_manager bddm, cache_entry p) +#else +bdd_rehash1(bddm, p) + cmu_bdd_manager bddm; + cache_entry p; +#endif +{ + return (HASH1(p->slot[0])); +} + + +static +long +#if defined(__STDC__) +bdd_rehash2(cmu_bdd_manager bddm, cache_entry p) +#else +bdd_rehash2(bddm, p) + cmu_bdd_manager bddm; + cache_entry p; +#endif +{ + return (HASH2(p->slot[0], p->slot[1])); +} + + +static +long +#if defined(__STDC__) +bdd_rehash3(cmu_bdd_manager bddm, cache_entry p) +#else +bdd_rehash3(bddm, p) + cmu_bdd_manager bddm; + cache_entry p; +#endif +{ + return (HASH3(p->slot[0], p->slot[1], p->slot[2])); +} + + +void +#if defined(__STDC__) +bdd_rehash_cache(cmu_bdd_manager bddm, int grow) +#else +bdd_rehash_cache(bddm, grow) + cmu_bdd_manager bddm; + int grow; +#endif +{ + long i; + long hash; + int j; + long oldsize; + cache_bin *newtable; + cache_entry *bin; + cache_entry *newbin; + cache_entry p; + cache_entry q; + + oldsize=bddm->op_cache.size; + if (grow) + bddm->op_cache.size_index++; + else + bddm->op_cache.size_index--; + bddm->op_cache.size=TABLE_SIZE(bddm->op_cache.size_index); + newtable=(cache_bin *)mem_get_block((SIZE_T)(bddm->op_cache.size*sizeof(struct cache_bin_))); + for (i=0; i < bddm->op_cache.size; ++i) + for (j=0; j < 2; ++j) + newtable[i].entry[j]=0; + /* Rehash LRU first. */ + for (j=1; j >= 0; --j) + for (i=0; i < oldsize; ++i) + { + bin=bddm->op_cache.table[i].entry; + if ((p=bin[j])) + { + q=CACHE_POINTER(p); + hash=(*bddm->op_cache.rehash_fn[TAG(p)])(bddm, q); + BDD_REDUCE(hash, bddm->op_cache.size); + newbin=newtable[hash].entry; + bdd_purge_lru(bddm, newbin); + newbin[0]=p; + } + } + mem_free_block((pointer)(bddm->op_cache.table)); + bddm->op_cache.table=newtable; +} + + +/* The routines bdd_insert_in_cachex insert things in the cache. */ +/* The routines bdd_lookup_in_cachex look up things in the cache. */ + +void +#if defined(__STDC__) +bdd_insert_in_cache31(cmu_bdd_manager bddm, int tag, INT_PTR d1, INT_PTR d2, INT_PTR d3, INT_PTR result) +#else +bdd_insert_in_cache31(bddm, tag, d1, d2, d3, result) + cmu_bdd_manager bddm; + int tag; + INT_PTR d1; + INT_PTR d2; + INT_PTR d3; + INT_PTR result; +#endif +{ + long hash; + cache_entry p; + + hash=HASH3(d1, d2, d3); + BDD_REDUCE(hash, bddm->op_cache.size); + if (hash < 0) + hash= -hash; + p=bdd_get_entry(bddm, tag, bddm->op_cache.table[hash].entry); + p->slot[0]=d1; + p->slot[1]=d2; + p->slot[2]=d3; + p->slot[3]=result; + bddm->op_cache.inserts++; +} + + +#if defined(__STDC__) +#define RETURN_BDD_FN ((void (*)(cmu_bdd_manager, cache_entry))-1) +#else +#define RETURN_BDD_FN ((void (*)())-1) +#endif + + +int +#if defined(__STDC__) +bdd_lookup_in_cache31(cmu_bdd_manager bddm, int tag, INT_PTR d1, INT_PTR d2, INT_PTR d3, INT_PTR *result) +#else +bdd_lookup_in_cache31(bddm, tag, d1, d2, d3, result) + cmu_bdd_manager bddm; + int tag; + INT_PTR d1; + INT_PTR d2; + INT_PTR d3; + INT_PTR *result; +#endif +{ + long hash; + cache_entry *bin; + cache_entry p; + cache_entry q; + bdd f; +#if defined(__STDC__) + void (*return_fn)(cmu_bdd_manager, cache_entry); +#else + void (*return_fn)(); +#endif + + bddm->op_cache.lookups++; + hash=HASH3(d1, d2, d3); + BDD_REDUCE(hash, bddm->op_cache.size); + bin=bddm->op_cache.table[hash].entry; + if ((p=bin[0])) + { + q=CACHE_POINTER(p); + if (q->slot[0] != d1 || q->slot[1] != d2 || q->slot[2] != d3 || TAG(p) != tag) + if ((p=bin[1])) + { + q=CACHE_POINTER(p); + if (q->slot[0] != d1 || q->slot[1] != d2 || q->slot[2] != d3 || TAG(p) != tag) + return (0); + bin[1]=bin[0]; + bin[0]=p; + } + else + return (0); + } + else + return (0); + bddm->op_cache.hits++; + if ((return_fn=bddm->op_cache.return_fn[TAG(p)])) + if (return_fn == RETURN_BDD_FN) + { + f=(bdd)q->slot[3]; + { + BDD_SETUP(f); + BDD_TEMP_INCREFS(f); + } + } + else + (*return_fn)(bddm, q); + *result=q->slot[3]; + return (1); +} + + +void +#if defined(__STDC__) +bdd_insert_in_cache22(cmu_bdd_manager bddm, int tag, INT_PTR d1, INT_PTR d2, INT_PTR result1, INT_PTR result2) +#else +bdd_insert_in_cache22(bddm, tag, d1, d2, result1, result2) + cmu_bdd_manager bddm; + int tag; + INT_PTR d1; + INT_PTR d2; + INT_PTR result1; + INT_PTR result2; +#endif +{ + long hash; + cache_entry p; + + hash=HASH2(d1, d2); + BDD_REDUCE(hash, bddm->op_cache.size); + p=bdd_get_entry(bddm, tag, bddm->op_cache.table[hash].entry); + p->slot[0]=d1; + p->slot[1]=d2; + p->slot[2]=result1; + p->slot[3]=result2; + bddm->op_cache.inserts++; +} + + +int +#if defined(__STDC__) +bdd_lookup_in_cache22(cmu_bdd_manager bddm, int tag, INT_PTR d1, INT_PTR d2, INT_PTR *result1, INT_PTR *result2) +#else +bdd_lookup_in_cache22(bddm, tag, d1, d2, result1, result2) + cmu_bdd_manager bddm; + int tag; + INT_PTR d1; + INT_PTR d2; + INT_PTR *result1; + INT_PTR *result2; +#endif +{ + long hash; + cache_entry *bin; + cache_entry p; + cache_entry q; +#if defined(__STDC__) + void (*return_fn)(cmu_bdd_manager, cache_entry); +#else + void (*return_fn)(); +#endif + + bddm->op_cache.lookups++; + hash=HASH2(d1, d2); + BDD_REDUCE(hash, bddm->op_cache.size); + bin=bddm->op_cache.table[hash].entry; + if ((p=bin[0])) + { + q=CACHE_POINTER(p); + if (q->slot[0] != d1 || q->slot[1] != d2 || TAG(p) != tag) + if ((p=bin[1])) + { + q=CACHE_POINTER(p); + if (q->slot[0] != d1 || q->slot[1] != d2 || TAG(p) != tag) + return (0); + bin[1]=bin[0]; + bin[0]=p; + } + else + return (0); + } + else + return (0); + bddm->op_cache.hits++; + if ((return_fn=bddm->op_cache.return_fn[TAG(p)])) + (*return_fn)(bddm, q); + *result1=q->slot[2]; + *result2=q->slot[3]; + return (1); +} + + +void +#if defined(__STDC__) +bdd_insert_in_cache13(cmu_bdd_manager bddm, int tag, INT_PTR d1, INT_PTR result1, INT_PTR result2, INT_PTR result3) +#else +bdd_insert_in_cache13(bddm, tag, d1, result1, result2, result3) + cmu_bdd_manager bddm; + int tag; + INT_PTR d1; + INT_PTR result1; + INT_PTR result2; + INT_PTR result3; +#endif +{ + long hash; + cache_entry p; + + hash=HASH1(d1); + BDD_REDUCE(hash, bddm->op_cache.size); + p=bdd_get_entry(bddm, tag, bddm->op_cache.table[hash].entry); + p->slot[0]=d1; + p->slot[1]=result1; + p->slot[2]=result2; + p->slot[3]=result3; + bddm->op_cache.inserts++; +} + + +int +#if defined(__STDC__) +bdd_lookup_in_cache13(cmu_bdd_manager bddm, int tag, INT_PTR d1, INT_PTR *result1, INT_PTR *result2, INT_PTR *result3) +#else +bdd_lookup_in_cache13(bddm, tag, d1, result1, result2, result3) + cmu_bdd_manager bddm; + int tag; + INT_PTR d1; + INT_PTR *result1; + INT_PTR *result2; + INT_PTR *result3; +#endif +{ + long hash; + cache_entry *bin; + cache_entry p; + cache_entry q; +#if defined(__STDC__) + void (*return_fn)(cmu_bdd_manager, cache_entry); +#else + void (*return_fn)(); +#endif + + bddm->op_cache.lookups++; + hash=HASH1(d1); + BDD_REDUCE(hash, bddm->op_cache.size); + bin=bddm->op_cache.table[hash].entry; + if ((p=bin[0])) + { + q=CACHE_POINTER(p); + if (q->slot[0] != d1 || TAG(p) != tag) + if ((p=bin[1])) + { + q=CACHE_POINTER(p); + if (q->slot[0] != d1 || TAG(p) != tag) + return (0); + bin[1]=bin[0]; + bin[0]=p; + } + else + return (0); + } + else + return (0); + bddm->op_cache.hits++; + if ((return_fn=bddm->op_cache.return_fn[TAG(p)])) + (*return_fn)(bddm, q); + *result1=q->slot[1]; + *result2=q->slot[2]; + *result3=q->slot[3]; + return (1); +} + + +static +int +#if defined(__STDC__) +cmu_bdd_ite_gc_fn(cmu_bdd_manager bddm, cache_entry p) +#else +cmu_bdd_ite_gc_fn(bddm, p) + cmu_bdd_manager bddm; + cache_entry p; +#endif +{ + int i; + bdd f; + + for (i=0; i < 4; ++i) + { + f=(bdd)p->slot[i]; + { + BDD_SETUP(f); + if (!BDD_IS_USED(f)) + return (1); + } + } + return (0); +} + + +static +int +#if defined(__STDC__) +bdd_two_gc_fn(cmu_bdd_manager bddm, cache_entry p) +#else +bdd_two_gc_fn(bddm, p) + cmu_bdd_manager bddm; + cache_entry p; +#endif +{ + int i; + bdd f; + + for (i=1; i < 4; ++i) + { + f=(bdd)p->slot[i]; + { + BDD_SETUP(f); + if (!BDD_IS_USED(f)) + return (1); + } + } + return (0); +} + + +static +int +#if defined(__STDC__) +bdd_two_data_gc_fn(cmu_bdd_manager bddm, cache_entry p) +#else +bdd_two_data_gc_fn(bddm, p) + cmu_bdd_manager bddm; + cache_entry p; +#endif +{ + int i; + bdd f; + + for (i=1; i < 3; ++i) + { + f=(bdd)p->slot[i]; + { + BDD_SETUP(f); + if (!BDD_IS_USED(f)) + return (1); + } + } + return (0); +} + + +static +int +#if defined(__STDC__) +cmu_bdd_one_data_gc_fn(cmu_bdd_manager bddm, cache_entry p) +#else +cmu_bdd_one_data_gc_fn(bddm, p) + cmu_bdd_manager bddm; + cache_entry p; +#endif +{ + bdd f; + + f=(bdd)p->slot[1]; + { + BDD_SETUP(f); + return (!BDD_IS_USED(f)); + } +} + + +/* bdd_purge_cache(bddm) purges the cache of any entries which mention */ +/* a BDD node that is about to be garbage collected. */ + +void +#if defined(__STDC__) +bdd_purge_cache(cmu_bdd_manager bddm) +#else +bdd_purge_cache(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i; + int j; + cache_entry *bin; + cache_entry p; + cache_entry q; + + for (i=0; i < bddm->op_cache.size; ++i) + { + bin= &bddm->op_cache.table[i].entry[0]; + for (j=0; j < 2; ++j) + if ((p=bin[j])) + { + q=CACHE_POINTER(p); + if ((*bddm->op_cache.gc_fn[TAG(p)])(bddm, q)) + bdd_purge_entry(bddm, bin+j); + else if (j == 1 && !bin[0]) + { + bin[0]=bin[1]; /* LRU is only one left */ + bin[1]=0; + } + } + else + break; + } +} + + +/* bdd_flush_cache(bddm, flush_fn, closure) purges all entries for which */ +/* the given function returns true. */ + +void +#if defined(__STDC__) +bdd_flush_cache(cmu_bdd_manager bddm, int (*flush_fn)(cmu_bdd_manager, cache_entry, pointer), pointer closure) +#else +bdd_flush_cache(bddm, flush_fn, closure) + cmu_bdd_manager bddm; + int (*flush_fn)(); + pointer closure; +#endif +{ + long i; + int j; + cache_entry *bin; + + for (i=0; i < bddm->op_cache.size; ++i) + { + bin=bddm->op_cache.table[i].entry; + for (j=0; j < 2; ++j) + if (bin[j]) + { + if ((*flush_fn)(bddm, bin[j], closure)) + bdd_purge_entry(bddm, bin+j); + else if (j == 1 && !bin[0]) + { + bin[0]=bin[1]; /* LRU is only one left */ + bin[1]=0; + } + } + else + break; + } +} + + +/* bdd_flush_all(bddm) flushes the entire cache. */ + +void +#if defined(__STDC__) +bdd_flush_all(cmu_bdd_manager bddm) +#else +bdd_flush_all(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i; + int j; + cache_entry *bin; + + for (i=0; i < bddm->op_cache.size; ++i) + { + bin=bddm->op_cache.table[i].entry; + for (j=0; j < 2; ++j) + if (bin[j]) + bdd_purge_entry(bddm, bin+j); + else + break; + } +} + + +/* bdd_cache_functions(bddm, args, gc_fn, purge_fn, return_fn, flush_fn) */ +/* controls the user cache types. Allocates an unused cache entry type */ +/* tag and returns the tag, or -1 if no more tags are available. */ + +int +#if defined(__STDC__) +bdd_cache_functions(cmu_bdd_manager bddm, + int args, + int (*gc_fn)(cmu_bdd_manager, cache_entry), + void (*purge_fn)(cmu_bdd_manager, cache_entry), + void (*return_fn)(cmu_bdd_manager, cache_entry), + int (*flush_fn)(cmu_bdd_manager, cache_entry, pointer)) +#else +bdd_cache_functions(bddm, args, gc_fn, purge_fn, return_fn, flush_fn) + cmu_bdd_manager bddm; + int args; + int (*gc_fn)(); + void (*purge_fn)(); + void (*return_fn)(); + int (*flush_fn)(); +#endif +{ +#if defined(__STDC__) + long (*rehash_fn)(cmu_bdd_manager, cache_entry); +#else + long (*rehash_fn)(); +#endif + int i; + + if (args == 1) + rehash_fn=bdd_rehash1; + else if (args == 2) + rehash_fn=bdd_rehash2; + else if (args == 3) + rehash_fn=bdd_rehash3; + else + { + rehash_fn=0; + cmu_bdd_fatal("bdd_cache_functions: illegal number of cache arguments"); + } + for (i=CACHE_TYPE_USER1; i < CACHE_TYPE_USER1+USER_ENTRY_TYPES; ++i) + if (!bddm->op_cache.rehash_fn[i]) + break; + if (i == CACHE_TYPE_USER1+USER_ENTRY_TYPES) + return (-1); + bddm->op_cache.rehash_fn[i]=rehash_fn; + bddm->op_cache.gc_fn[i]=gc_fn; + bddm->op_cache.purge_fn[i]=purge_fn; + bddm->op_cache.return_fn[i]=return_fn; + bddm->op_cache.flush_fn[i]=flush_fn; + return (i); +} + + +static +int +#if defined(__STDC__) +bdd_flush_tag(cmu_bdd_manager bddm, cache_entry p, pointer tag) +#else +bdd_flush_tag(bddm, p, tag) + cmu_bdd_manager bddm; + cache_entry p; + pointer tag; +#endif +{ + return (TAG(p) == (int)tag); +} + + +/* cmu_bdd_free_cache_tag(bddm, tag) frees a previously allocated user */ +/* cache tag. */ + +void +#if defined(__STDC__) +cmu_bdd_free_cache_tag(cmu_bdd_manager bddm, int tag) +#else +cmu_bdd_free_cache_tag(bddm, tag) + cmu_bdd_manager bddm; + int tag; +#endif +{ + if (tag < CACHE_TYPE_USER1 || + tag >= CACHE_TYPE_USER1+USER_ENTRY_TYPES || + !bddm->op_cache.rehash_fn[tag]) + cmu_bdd_fatal("cmu_bdd_free_cache_tag: attempt to free unallocated tag"); + bdd_flush_cache(bddm, bdd_flush_tag, (pointer)tag); + bddm->op_cache.rehash_fn[tag]=0; + bddm->op_cache.gc_fn[tag]=0; + bddm->op_cache.purge_fn[tag]=0; + bddm->op_cache.return_fn[tag]=0; + bddm->op_cache.flush_fn[tag]=0; +} + + +static +int +#if defined(__STDC__) +bdd_two_flush_fn(cmu_bdd_manager bddm, cache_entry p, pointer closure) +#else +bdd_two_flush_fn(bddm, p, closure) + cmu_bdd_manager bddm; + cache_entry p; + pointer closure; +#endif +{ + int id_to_nuke; + + id_to_nuke=(int)closure; + return (p->slot[0] == OP_RELPROD+id_to_nuke || + p->slot[0] == OP_QNT+id_to_nuke || + p->slot[0] == OP_SUBST+id_to_nuke); +} + + +/* cmu_bdd_init_cache(bddm) initializes the cache for a BDD manager. */ + +void +#if defined(__STDC__) +cmu_bdd_init_cache(cmu_bdd_manager bddm) +#else +cmu_bdd_init_cache(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i; + int j; + + bddm->op_cache.size_index=13; + bddm->op_cache.size=TABLE_SIZE(bddm->op_cache.size_index); + bddm->op_cache.table=(cache_bin *)mem_get_block((SIZE_T)(bddm->op_cache.size*sizeof(cache_bin))); + for (i=0; i < bddm->op_cache.size; ++i) + for (j=0; j < 2; ++j) + bddm->op_cache.table[i].entry[j]=0; + /* ITE cache control functions. */ + bddm->op_cache.rehash_fn[CACHE_TYPE_ITE]=bdd_rehash3; + bddm->op_cache.gc_fn[CACHE_TYPE_ITE]=cmu_bdd_ite_gc_fn; + bddm->op_cache.purge_fn[CACHE_TYPE_ITE]=0; + bddm->op_cache.return_fn[CACHE_TYPE_ITE]=RETURN_BDD_FN; + bddm->op_cache.flush_fn[CACHE_TYPE_ITE]=0; + /* Two argument op cache control functions. */ + bddm->op_cache.rehash_fn[CACHE_TYPE_TWO]=bdd_rehash3; + bddm->op_cache.gc_fn[CACHE_TYPE_TWO]=bdd_two_gc_fn; + bddm->op_cache.purge_fn[CACHE_TYPE_TWO]=0; + bddm->op_cache.return_fn[CACHE_TYPE_TWO]=RETURN_BDD_FN; + bddm->op_cache.flush_fn[CACHE_TYPE_TWO]=bdd_two_flush_fn; + /* One argument op w/ data result cache control functions. */ + bddm->op_cache.rehash_fn[CACHE_TYPE_ONEDATA]=bdd_rehash2; + bddm->op_cache.gc_fn[CACHE_TYPE_ONEDATA]=cmu_bdd_one_data_gc_fn; + bddm->op_cache.purge_fn[CACHE_TYPE_ONEDATA]=0; + bddm->op_cache.return_fn[CACHE_TYPE_ONEDATA]=0; + bddm->op_cache.flush_fn[CACHE_TYPE_ONEDATA]=0; + /* Two argument op w/ data result cache control functions. */ + bddm->op_cache.rehash_fn[CACHE_TYPE_TWODATA]=bdd_rehash3; + bddm->op_cache.gc_fn[CACHE_TYPE_TWODATA]=bdd_two_data_gc_fn; + bddm->op_cache.purge_fn[CACHE_TYPE_TWODATA]=0; + bddm->op_cache.return_fn[CACHE_TYPE_TWODATA]=0; + bddm->op_cache.flush_fn[CACHE_TYPE_TWODATA]=0; + /* User-defined cache control functions. */ + for (j=CACHE_TYPE_USER1; j < CACHE_TYPE_USER1+USER_ENTRY_TYPES; ++j) + { + bddm->op_cache.rehash_fn[j]=0; + bddm->op_cache.gc_fn[j]=0; + bddm->op_cache.purge_fn[j]=0; + bddm->op_cache.return_fn[j]=0; + bddm->op_cache.flush_fn[j]=0; + } + bddm->op_cache.cache_ratio=4; + bddm->op_cache.cache_level=0; + bddm->op_cache.entries=0; + bddm->op_cache.lookups=0; + bddm->op_cache.hits=0; + bddm->op_cache.inserts=0; + bddm->op_cache.collisions=0; +} + + +/* cmu_bdd_free_cache(bddm) frees the storage associated with the cache of */ +/* the indicated BDD manager. */ + +void +#if defined(__STDC__) +cmu_bdd_free_cache(cmu_bdd_manager bddm) +#else +cmu_bdd_free_cache(bddm) + cmu_bdd_manager bddm; +#endif +{ + bdd_flush_all(bddm); + mem_free_block((pointer)bddm->op_cache.table); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddcmp.c b/sis/bdd_cmu/bdd_cmu/bddcmp.c new file mode 100644 index 0000000..12324ba --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddcmp.c @@ -0,0 +1,115 @@ +/* BDD comparison routine */ + + +#include "bddint.h" + + +static +int +#if defined(__STDC__) +bdd_fraction_compare(cmu_bdd_manager bddm, bdd f, bdd g) +#else +bdd_fraction_compare(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + double f_frac, g_frac; + + bddm->op_cache.cache_level++; + f_frac=cmu_bdd_satisfying_fraction_step(bddm, f); + g_frac=cmu_bdd_satisfying_fraction_step(bddm, g); + bddm->op_cache.cache_level--; + if (f_frac < g_frac) + return (-1); + if (f_frac > g_frac) + return (1); + return (0); +} + + +static +int +#if defined(__STDC__) +cmu_bdd_compare_step(cmu_bdd_manager bddm, bdd f, bdd g, bdd_indexindex_type v_indexindex, long op) +#else +cmu_bdd_compare_step(bddm, f, g, v_indexindex, op) + cmu_bdd_manager bddm; + bdd f; + bdd g; + bdd_index_type v_indexindex; + long op; +#endif +{ + bdd f1, f2; + bdd g1, g2; + bdd_indexindex_type top_indexindex; + INT_PTR result; + + BDD_SETUP(f); + BDD_SETUP(g); + if (f == g) + return (0); + if (BDD_IS_CONST(f) || BDD_IS_CONST(g)) + { + if (f == BDD_ZERO(bddm) || g == BDD_ONE(bddm)) + return (-1); + return (1); + } + if (bdd_lookup_in_cache2d(bddm, op, f, g, &result)) + return ((int)result); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + if (bddm->indexes[top_indexindex] > bddm->indexes[v_indexindex]) + result=bdd_fraction_compare(bddm, f, g); + else + { + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + if (!(result=cmu_bdd_compare_step(bddm, f2, g2, v_indexindex, op))) + result=cmu_bdd_compare_step(bddm, f1, g1, v_indexindex, op); + } + bdd_insert_in_cache2d(bddm, op, f, g, result); + return ((int)result); +} + + +int +#if defined(__STDC__) +cmu_bdd_compare_temp(cmu_bdd_manager bddm, bdd f, bdd g, bdd v) +#else +cmu_bdd_compare_temp(bddm, f, g, v) + cmu_bdd_manager bddm; + bdd f; + bdd g; + bdd v; +#endif +{ + BDD_SETUP(v); + return (cmu_bdd_compare_step(bddm, f, g, BDD_INDEXINDEX(v), OP_CMPTO+BDD_INDEXINDEX(v))); +} + + +int +#if defined(__STDC__) +cmu_bdd_compare(cmu_bdd_manager bddm, bdd f, bdd g, bdd v) +#else +cmu_bdd_compare(bddm, f, g, v) + cmu_bdd_manager bddm; + bdd f; + bdd g; + bdd v; +#endif +{ + if (bdd_check_arguments(3, f, g, v)) + { + BDD_SETUP(v); + if (cmu_bdd_type_aux(bddm, v) != BDD_TYPE_POSVAR) + { + cmu_bdd_warning("cmu_bdd_compare: third argument is not a positive variable"); + return (0); + } + return (cmu_bdd_compare_step(bddm, f, g, BDD_INDEXINDEX(v), OP_CMPTO+BDD_INDEXINDEX(v))); + } + return (0); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddcomp.c b/sis/bdd_cmu/bdd_cmu/bddcomp.c new file mode 100644 index 0000000..a898ed0 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddcomp.c @@ -0,0 +1,240 @@ +/* BDD composition routines */ + + +#include "bddint.h" + + +static +bdd +#if defined(__STDC__) +bdd_restrict_step(cmu_bdd_manager bddm, bdd f, bdd_indexindex_type g_indexindex, bdd h, long op) +#else +bdd_restrict_step(bddm, f, g_indexindex, h, op) + cmu_bdd_manager bddm; + bdd f; + bdd_indexindex_type g_indexindex; + bdd h; + long op; +#endif +{ + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + if (BDD_INDEX(bddm, f) > bddm->indexes[g_indexindex]) + { + /* f doesn't depend on the variable g. */ + BDD_TEMP_INCREFS(f); + return (f); + } + if (BDD_INDEXINDEX(f) == g_indexindex) + { + /* Do the restriction. */ + result=(h == BDD_ONE(bddm) ? BDD_THEN(f) : BDD_ELSE(f)); + { + BDD_SETUP(result); + BDD_TEMP_INCREFS(result); + return (result); + } + } + if (bdd_lookup_in_cache2(bddm, op, BDD_OUTPOS(f), h, &result)) + return (BDD_IS_OUTPOS(f) ? result : BDD_NOT(result)); + temp1=bdd_restrict_step(bddm, BDD_THEN(f), g_indexindex, h, op); + temp2=bdd_restrict_step(bddm, BDD_ELSE(f), g_indexindex, h, op); + result=bdd_find(bddm, BDD_INDEXINDEX(f), temp1, temp2); + if (BDD_IS_OUTPOS(f)) + bdd_insert_in_cache2(bddm, op, f, h, result); + else + bdd_insert_in_cache2(bddm, op, BDD_NOT(f), h, BDD_NOT(result)); + return (result); +} + + +static +bdd +#if defined(__STDC__) +cmu_bdd_compose_step(cmu_bdd_manager bddm, bdd f, bdd_indexindex_type g_indexindex, bdd h, long op) +#else +cmu_bdd_compose_step(bddm, f, g_indexindex, h, op) + cmu_bdd_manager bddm; + bdd f; + bdd_indexindex_type g_indexindex; + bdd h; + long op; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd h1, h2; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + BDD_SETUP(h); + /* Use restriction if possible. */ + if (BDD_IS_CONST(h)) + return (bdd_restrict_step(bddm, f, g_indexindex, h, op)); + if (BDD_INDEX(bddm, f) > bddm->indexes[g_indexindex]) + { + /* f doesn't depend on the variable g. */ + BDD_TEMP_INCREFS(f); + return (f); + } + if (bdd_lookup_in_cache2(bddm, op, BDD_OUTPOS(f), h, &result)) + return (BDD_IS_OUTPOS(f) ? result : BDD_NOT(result)); + if (BDD_INDEXINDEX(f) == g_indexindex) + { + /* Do the replacement. */ + bddm->op_cache.cache_level++; + result=cmu_bdd_ite_step(bddm, h, BDD_THEN(f), BDD_ELSE(f)); + bddm->op_cache.cache_level--; + } + else + { + BDD_TOP_VAR2(top_indexindex, bddm, f, h); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, h, h1, h2); + temp1=cmu_bdd_compose_step(bddm, f1, g_indexindex, h1, op); + temp2=cmu_bdd_compose_step(bddm, f2, g_indexindex, h2, op); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + } + if (BDD_IS_OUTPOS(f)) + bdd_insert_in_cache2(bddm, op, f, h, result); + else + bdd_insert_in_cache2(bddm, op, BDD_NOT(f), h, BDD_NOT(result)); + return (result); +} + + +/* cmu_bdd_compose_temp is used internally by cmu_bdd_swap_vars. */ + +bdd +#if defined(__STDC__) +cmu_bdd_compose_temp(cmu_bdd_manager bddm, bdd f, bdd g, bdd h) +#else +cmu_bdd_compose_temp(bddm, f, g, h) + cmu_bdd_manager bddm; + bdd f, g, h; +#endif +{ + BDD_SETUP(g); + return (cmu_bdd_compose_step(bddm, f, BDD_INDEXINDEX(g), h, OP_COMP+BDD_INDEXINDEX(g))); +} + + +/* cmu_bdd_compose(bddm, f, g, h) returns the BDD for substituting h for */ +/* the variable g in f. h may depend on g. */ + +bdd +#if defined(__STDC__) +cmu_bdd_compose(cmu_bdd_manager bddm, bdd f, bdd g, bdd h) +#else +cmu_bdd_compose(bddm, f, g, h) + cmu_bdd_manager bddm; + bdd f, g, h; +#endif +{ + if (bdd_check_arguments(3, f, g, h)) + { + BDD_SETUP(f); + BDD_SETUP(g); + if (cmu_bdd_type_aux(bddm, g) != BDD_TYPE_POSVAR) + { + cmu_bdd_warning("cmu_bdd_compose: second argument is not a positive variable"); + BDD_INCREFS(f); + return (f); + } + FIREWALL(bddm); + RETURN_BDD(cmu_bdd_compose_step(bddm, f, BDD_INDEXINDEX(g), h, OP_COMP+BDD_INDEXINDEX(g))); + } + return ((bdd)0); +} + + +bdd +#if defined(__STDC__) +cmu_bdd_substitute_step(cmu_bdd_manager bddm, bdd f, long op, bdd (*ite_fn)(cmu_bdd_manager, bdd, bdd, bdd), var_assoc subst) +#else +cmu_bdd_substitute_step(bddm, f, op, ite_fn, subst) + cmu_bdd_manager bddm; + bdd f; + long op; + bdd (*ite_fn)(); + var_assoc subst; +#endif +{ + bdd g; + bdd temp1, temp2; + bdd result; + bdd_index_type g_index; + + BDD_SETUP(f); + if ((long)BDD_INDEX(bddm, f) > subst->last) + { + BDD_TEMP_INCREFS(f); + return (f); + } + if (bdd_lookup_in_cache1(bddm, op, BDD_OUTPOS(f), &result)) + return (BDD_IS_OUTPOS(f) ? result : BDD_NOT(result)); + g=subst->assoc[BDD_INDEXINDEX(f)]; + /* See if we are substituting a constant at this level. */ + if (g == BDD_ONE(bddm)) + return (cmu_bdd_substitute_step(bddm, BDD_THEN(f), op, ite_fn, subst)); + if (g == BDD_ZERO(bddm)) + return (cmu_bdd_substitute_step(bddm, BDD_ELSE(f), op, ite_fn, subst)); + temp1=cmu_bdd_substitute_step(bddm, BDD_THEN(f), op, ite_fn, subst); + temp2=cmu_bdd_substitute_step(bddm, BDD_ELSE(f), op, ite_fn, subst); + if (!g) + g=BDD_IF(bddm, f); + { + BDD_SETUP(g); + BDD_SETUP(temp1); + BDD_SETUP(temp2); + if (g == BDD_IF(bddm, g) && + (g_index=BDD_INDEX(bddm, g)) < BDD_INDEX(bddm, temp1) && + g_index < BDD_INDEX(bddm, temp2)) + /* Substituting with variable above the tops of the subresults. */ + result=bdd_find(bddm, BDD_INDEXINDEX(g), temp1, temp2); + else + { + /* Do an ITE. */ + bddm->op_cache.cache_level++; + result=(*ite_fn)(bddm, g, temp1, temp2); + BDD_TEMP_DECREFS(temp1); + BDD_TEMP_DECREFS(temp2); + bddm->op_cache.cache_level--; + } + } + if (BDD_IS_OUTPOS(f)) + bdd_insert_in_cache1(bddm, op, f, result); + else + bdd_insert_in_cache1(bddm, op, BDD_NOT(f), BDD_NOT(result)); + return (result); +} + + +/* cmu_bdd_substitute(bddm, f) returns the BDD for substituting in f */ +/* according to the current variable association. */ + +bdd +#if defined(__STDC__) +cmu_bdd_substitute(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_substitute(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + long op; + + if (bdd_check_arguments(1, f)) + { + FIREWALL(bddm); + if (bddm->curr_assoc_id == -1) + op=bddm->temp_op--; + else + op=OP_SUBST+bddm->curr_assoc_id; + RETURN_BDD(cmu_bdd_substitute_step(bddm, f, op, cmu_bdd_ite_step, bddm->curr_assoc)); + } + return ((bdd)0); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddcproject.c b/sis/bdd_cmu/bdd_cmu/bddcproject.c new file mode 100644 index 0000000..be97b22 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddcproject.c @@ -0,0 +1,229 @@ +/* Written by Gitanjali M. Swamy */ +/* bddcproject.c,v 1.2 1994/06/02 02:36:30 shiple Exp */ +/* bddcproject.c,v + * Revision 1.2 1994/06/02 02:36:30 shiple + * Fixed bug in RETURN_BDD use. + * + * Revision 1.1 1994/06/02 00:48:50 shiple + * Initial revision + * + * Revision 1.5 1994/05/31 15:19:32 gms + * May31 Tues + * */ + +#ifndef lint +static char vcid[] = "bddcproject.c,v 1.2 1994/06/02 02:36:30 shiple Exp"; +#endif /* lint */ + +#include "bddint.h" /* CMU internal routines; for use in bdd_get_node() */ + +#define OP_CPROJ 5000001 + +extern bdd cmu_bdd_project(); + +/* INTERNAL ONLY */ + +/* + * smooth - recursively perform the smoothing + * + * return the result of the reorganization + */ + +static +bdd +#if defined(__STDC__) +cmu_bdd_smooth_g_step(cmu_bdd_manager bddm, bdd f, long op, var_assoc vars ,long id) +#else +cmu_bdd_smooth_g_step(bddm, f, op, vars, id) + cmu_bdd_manager bddm; + bdd f; + long op; + var_assoc vars; + long id; +#endif +{ + bdd temp1, temp2; + bdd result; + int quantifying; + + BDD_SETUP(f); + if ((long)BDD_INDEX(bddm, f) > vars->last) + { + BDD_TEMP_INCREFS(f); + return (f); + } + if (bdd_lookup_in_cache1(bddm, op, f, &result)) + return (result); + quantifying=(vars->assoc[BDD_INDEXINDEX(f)] != 0); + + temp1=cmu_bdd_smooth_g_step(bddm, BDD_THEN(f), op, vars,id); + + if ((quantifying && temp1 == BDD_ONE(bddm))&&((long)BDD_INDEX(bddm, f) > id )) + + result=temp1; + else + { + temp2=cmu_bdd_smooth_g_step(bddm, BDD_ELSE(f), op, vars,id); + if (quantifying) + { + BDD_SETUP(temp1); + BDD_SETUP(temp2); + bddm->op_cache.cache_level++; + result=cmu_bdd_ite_step(bddm, temp1, BDD_ONE(bddm), temp2); + BDD_TEMP_DECREFS(temp1); + BDD_TEMP_DECREFS(temp2); + bddm->op_cache.cache_level--; + } + else + result=bdd_find(bddm, BDD_INDEXINDEX(f), temp1, temp2); + } + bdd_insert_in_cache1(bddm, op, f, result); + + + return (result); +} + + +bdd +#if defined(__STDC__) +cmu_bdd_smooth_g(cmu_bdd_manager bddm, bdd f, long id) +#else +cmu_bdd_smooth_g(bddm, f, id) + cmu_bdd_manager bddm; + bdd f; + long id; +#endif +{ + long op; + + if (bddm->curr_assoc_id == -1) + op=bddm->temp_op--; + else + op=OP_QNT+bddm->curr_assoc_id; + RETURN_BDD(cmu_bdd_smooth_g_step(bddm, f, op, bddm->curr_assoc,id)); + } + + +/* + * project - recursively perform compatible projection + * + * return the result of the reorganization + */ + + + +static +bdd +#if defined(__STDC__) +cmu_bdd_project_step(cmu_bdd_manager bddm, bdd f, long op, var_assoc vars) +#else +cmu_bdd_project_step(bddm, f, op, vars) + cmu_bdd_manager bddm; + bdd f; + long op; + var_assoc vars; +#endif + +{ + bdd temp1, temp2; + bdd sm, pr; + bdd result; + int quantifying; + + BDD_SETUP(f); + if ((long)BDD_INDEX(bddm, f) > vars->last) + { + BDD_TEMP_INCREFS(f); + return (f); + } + if (bdd_lookup_in_cache1(bddm, op, f, &result)) + return (result); + quantifying=(vars->assoc[BDD_INDEXINDEX(f)] != 0); + + if (quantifying) + { + + sm = cmu_bdd_smooth_g(bddm,BDD_THEN(f),(long)BDD_INDEXINDEX(f)); + if (sm == BDD_ONE(bddm)) + { + pr = cmu_bdd_project_step(bddm, BDD_THEN(f), op, vars); + { + BDD_SETUP(pr); + result = bdd_find(bddm, BDD_INDEXINDEX(f), pr,BDD_ZERO(bddm)); + BDD_TEMP_DECREFS(pr); + } + + } + else if (sm == BDD_ZERO(bddm)) + { + pr = cmu_bdd_project_step(bddm, BDD_ELSE(f), op, vars); + { + BDD_SETUP(pr); + result = bdd_find(bddm, BDD_INDEXINDEX(f), BDD_ZERO(bddm), pr); + BDD_TEMP_DECREFS(pr); + } + + } + else + { + temp1 = cmu_bdd_project_step(bddm, BDD_THEN(f), op, vars); + temp2 = cmu_bdd_project_step(bddm, BDD_ELSE(f),op, vars); + { + BDD_SETUP(temp1); + BDD_SETUP(temp2); + pr = cmu_bdd_ite_step(bddm, sm, BDD_ZERO(bddm), temp2); + bddm->op_cache.cache_level++; + result = bdd_find(bddm, BDD_INDEXINDEX(f), temp1, pr); + BDD_TEMP_DECREFS(temp1); + BDD_TEMP_DECREFS(temp2); + bddm->op_cache.cache_level--; + } + + } + } + + else + { + temp1=cmu_bdd_project_step(bddm, BDD_THEN(f), op, vars); + temp2=cmu_bdd_project_step(bddm, BDD_ELSE(f), op, vars); + result=bdd_find(bddm, BDD_INDEXINDEX(f), temp1, temp2); + + } + + bdd_insert_in_cache1(bddm, op, f, result); + return (result); +} + +bdd +#if defined(__STDC__) +cmu_bdd_project(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_project(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + long op; + + if (bdd_check_arguments(1, f)) + { + FIREWALL(bddm); + if (bddm->curr_assoc_id == -1) + op=bddm->temp_op--; + else + op=OP_CPROJ+bddm->curr_assoc_id; + RETURN_BDD(cmu_bdd_project_step(bddm, f, op, bddm->curr_assoc)); + } + return ((bdd)0); +} + + + + + + + + + + + diff --git a/sis/bdd_cmu/bdd_cmu/bdddump.c b/sis/bdd_cmu/bdd_cmu/bdddump.c new file mode 100644 index 0000000..3806e97 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bdddump.c @@ -0,0 +1,466 @@ +/* BDD library dump/undump routines */ + + +#include "bddint.h" + + +#define MAGIC_COOKIE 0x5e02f795l +#define BDD_IOERROR 100 + + +#define TRUE_ENCODING 0xffffff00l +#define FALSE_ENCODING 0xffffff01l +#define POSVAR_ENCODING 0xffffff02l +#define NEGVAR_ENCODING 0xffffff03l +#define POSNODE_ENCODING 0xffffff04l +#define NEGNODE_ENCODING 0xffffff05l +#define NODELABEL_ENCODING 0xffffff06l +#define CONSTANT_ENCODING 0xffffff07l + + +static +int +#if defined(__STDC__) +bytes_needed(long n) +#else +bytes_needed(n) + long n; +#endif +{ + if (n <= 0x100l) + return (1); + if (n <= 0x10000l) + return (2); + if (n <= 0x1000000l) + return (3); + return (4); +} + + +static +void +#if defined(__STDC__) +write(cmu_bdd_manager bddm, unsigned long n, int bytes, FILE *fp) +#else +write(bddm, n, bytes, fp) + cmu_bdd_manager bddm; + unsigned long n; + int bytes; + FILE *fp; +#endif +{ + while (bytes) + { + if (fputc((char)(n >> (8*(bytes-1)) & 0xff), fp) == EOF) + longjmp(bddm->abort.context, BDD_IOERROR); + --bytes; + } +} + + +static +void +#if defined(__STDC__) +cmu_bdd_dump_bdd_step(cmu_bdd_manager bddm, + bdd f, + FILE *fp, + hash_table h, + bdd_index_type *normalized_indexes, + int index_size, + int node_number_size) +#else +cmu_bdd_dump_bdd_step(bddm, f, fp, h, normalized_indexes, index_size, node_number_size) + cmu_bdd_manager bddm; + bdd f; + FILE *fp; + hash_table h; + bdd_index_type *normalized_indexes; + int index_size; + int node_number_size; +#endif +{ + int negated; + long *number; + + BDD_SETUP(f); + switch (cmu_bdd_type_aux(bddm, f)) + { + case BDD_TYPE_ZERO: + write(bddm, FALSE_ENCODING, index_size+1, fp); + break; + case BDD_TYPE_ONE: + write(bddm, TRUE_ENCODING, index_size+1, fp); + break; + case BDD_TYPE_CONSTANT: + write(bddm, CONSTANT_ENCODING, index_size+1, fp); + write(bddm, (unsigned long)BDD_DATA(f)[0], sizeof(long), fp); + write(bddm, (unsigned long)BDD_DATA(f)[1], sizeof(long), fp); + break; + case BDD_TYPE_POSVAR: + write(bddm, POSVAR_ENCODING, index_size+1, fp); + write(bddm, (unsigned long)normalized_indexes[BDD_INDEX(bddm, f)], index_size, fp); + break; + case BDD_TYPE_NEGVAR: + write(bddm, NEGVAR_ENCODING, index_size+1, fp); + write(bddm, (unsigned long)normalized_indexes[BDD_INDEX(bddm, f)], index_size, fp); + break; + case BDD_TYPE_NONTERMINAL: + if (bdd_lookup_in_hash_table(h, BDD_NOT(f))) + { + f=BDD_NOT(f); + negated=1; + } + else + negated=0; + number=(long *)bdd_lookup_in_hash_table(h, f); + if (number && *number < 0) + { + if (negated) + write(bddm, NEGNODE_ENCODING, index_size+1, fp); + else + write(bddm, POSNODE_ENCODING, index_size+1, fp); + write(bddm, (unsigned long)(-*number-1), node_number_size, fp); + } + else + { + if (number) + { + write(bddm, NODELABEL_ENCODING, index_size+1, fp); + *number= -*number-1; + } + write(bddm, (unsigned long)normalized_indexes[BDD_INDEX(bddm, f)], index_size, fp); + cmu_bdd_dump_bdd_step(bddm, BDD_THEN(f), fp, h, normalized_indexes, index_size, node_number_size); + cmu_bdd_dump_bdd_step(bddm, BDD_ELSE(f), fp, h, normalized_indexes, index_size, node_number_size); + } + break; + default: + cmu_bdd_fatal("cmu_bdd_dump_bdd_step: unknown type returned by cmu_bdd_type"); + } +} + + +int +#if defined(__STDC__) +cmu_bdd_dump_bdd(cmu_bdd_manager bddm, bdd f, bdd *vars, FILE *fp) +#else +cmu_bdd_dump_bdd(bddm, f, vars, fp) + cmu_bdd_manager bddm; + bdd f; + bdd *vars; + FILE *fp; +#endif +{ + long i; + bdd_index_type *normalized_indexes; + bdd_index_type v_index; + bdd var; + bdd_index_type number_vars; + bdd *support; + int ok; + hash_table h; + int index_size; + long next; + int node_number_size; + + if (bdd_check_arguments(1, f)) + { + for (i=0; vars[i]; ++i) + if (cmu_bdd_type(bddm, vars[i]) != BDD_TYPE_POSVAR) + { + cmu_bdd_warning("cmu_bdd_dump_bdd: support is not all positive variables"); + return (0); + } + normalized_indexes=(bdd_index_type *)mem_get_block((SIZE_T)(bddm->vars*sizeof(bdd_index_type))); + for (i=0; i < bddm->vars; ++i) + normalized_indexes[i]=BDD_MAX_INDEX; + for (i=0; (var=vars[i]); ++i) + { + BDD_SETUP(var); + v_index=BDD_INDEX(bddm, var); + if (normalized_indexes[v_index] != BDD_MAX_INDEX) + { + cmu_bdd_warning("cmu_bdd_dump_bdd: variables duplicated in support"); + mem_free_block((pointer)normalized_indexes); + return (0); + } + normalized_indexes[v_index]=i; + } + number_vars=i; + support=(bdd *)mem_get_block((SIZE_T)((bddm->vars+1)*sizeof(bdd))); + cmu_bdd_support(bddm, f, support); + ok=1; + for (i=0; ok && (var=support[i]); ++i) + { + BDD_SETUP(var); + if (normalized_indexes[BDD_INDEX(bddm, var)] == BDD_MAX_INDEX) + { + cmu_bdd_warning("cmu_bdd_dump_bdd: incomplete support specified"); + ok=0; + } + } + if (!ok) + { + mem_free_block((pointer)normalized_indexes); + mem_free_block((pointer)support); + return (0); + } + mem_free_block((pointer)support); + /* Everything checked now; barring I/O errors, we should be able to */ + /* write a valid output file. */ + h=bdd_new_hash_table(bddm, sizeof(long)); + FIREWALL1(bddm, + if (retcode == BDD_IOERROR) + { + cmu_bdd_free_hash_table(h); + mem_free_block((pointer)normalized_indexes); + return (0); + } + else + cmu_bdd_fatal("cmu_bdd_dump_bdd: got unexpected retcode"); + ); + index_size=bytes_needed(number_vars+1); + bdd_mark_shared_nodes(bddm, f); + next=0; + bdd_number_shared_nodes(bddm, f, h, &next); + node_number_size=bytes_needed(next); + write(bddm, MAGIC_COOKIE, sizeof(long), fp); + write(bddm, (unsigned long)number_vars, sizeof(bdd_index_type), fp); + write(bddm, (unsigned long)next, sizeof(long), fp); + cmu_bdd_dump_bdd_step(bddm, f, fp, h, normalized_indexes, index_size, node_number_size); + cmu_bdd_free_hash_table(h); + mem_free_block((pointer)normalized_indexes); + return (1); + } + return (0); +} + + +static +unsigned long +#if defined(__STDC__) +read(int *error, int bytes, FILE *fp) +#else +read(error, bytes, fp) + int *error; + int bytes; + FILE *fp; +#endif +{ + int c; + long result; + + result=0; + if (*error) + return (result); + while (bytes) + { + c=fgetc(fp); + if (c == EOF) + { + if (ferror(fp)) + *error=BDD_UNDUMP_IOERROR; + else + *error=BDD_UNDUMP_EOF; + return (0l); + } + result=(result << 8)+c; + --bytes; + } + return (result); +} + + +static long index_mask[]={0xffl, 0xffffl, 0xffffffl}; + + +static +bdd +#if defined(__STDC__) +cmu_bdd_undump_bdd_step(cmu_bdd_manager bddm, + bdd *vars, + FILE *fp, + bdd_index_type number_vars, + bdd *shared, + long number_shared, + long *shared_so_far, + int index_size, + int node_number_size, + int *error) +#else +cmu_bdd_undump_bdd_step(bddm, vars, fp, number_vars, shared, number_shared, shared_so_far, index_size, node_number_size, error) + cmu_bdd_manager bddm; + bdd *vars; + FILE *fp; + bdd_index_type number_vars; + bdd *shared; + long number_shared; + long *shared_so_far; + int index_size; + int node_number_size; + int *error; +#endif +{ + long node_number; + long encoding; + bdd_index_type i; + INT_PTR value1, value2; + bdd v; + bdd temp1, temp2; + bdd result; + + i=read(error, index_size, fp); + if (*error) + return ((bdd)0); + if (i == index_mask[index_size-1]) + { + encoding=0xffffff00l+read(error, 1, fp); + if (*error) + return ((bdd)0); + switch (encoding) + { + case TRUE_ENCODING: + return (BDD_ONE(bddm)); + case FALSE_ENCODING: + return (BDD_ZERO(bddm)); + case CONSTANT_ENCODING: + value1=read(error, sizeof(long), fp); + value2=read(error, sizeof(long), fp); + if (*error) + return ((bdd)0); + if ((result=cmu_mtbdd_get_terminal(bddm, value1, value2))) + return (result); + *error=BDD_UNDUMP_OVERFLOW; + return ((bdd)0); + case POSVAR_ENCODING: + case NEGVAR_ENCODING: + i=read(error, index_size, fp); + if (!*error && i >= number_vars) + *error=BDD_UNDUMP_FORMAT; + if (*error) + return ((bdd)0); + v=vars[i]; + if (encoding == POSVAR_ENCODING) + return (v); + else + return (BDD_NOT(v)); + case POSNODE_ENCODING: + case NEGNODE_ENCODING: + node_number=read(error, node_number_size, fp); + if (!*error && (node_number >= number_shared || !shared[node_number])) + *error=BDD_UNDUMP_FORMAT; + if (*error) + return ((bdd)0); + v=shared[node_number]; + v=cmu_bdd_identity(bddm, v); + if (encoding == POSNODE_ENCODING) + return (v); + else + return (BDD_NOT(v)); + case NODELABEL_ENCODING: + node_number= *shared_so_far; + ++*shared_so_far; + v=cmu_bdd_undump_bdd_step(bddm, vars, fp, number_vars, shared, number_shared, + shared_so_far, index_size, node_number_size, error); + shared[node_number]=v; + v=cmu_bdd_identity(bddm, v); + return (v); + default: + *error=BDD_UNDUMP_FORMAT; + return ((bdd)0); + } + } + if (i >= number_vars) + { + *error=BDD_UNDUMP_FORMAT; + return ((bdd)0); + } + temp1=cmu_bdd_undump_bdd_step(bddm, vars, fp, number_vars, shared, number_shared, + shared_so_far, index_size, node_number_size, error); + temp2=cmu_bdd_undump_bdd_step(bddm, vars, fp, number_vars, shared, number_shared, + shared_so_far, index_size, node_number_size, error); + if (*error) + { + cmu_bdd_free(bddm, temp1); + return ((bdd)0); + } + result=cmu_bdd_ite(bddm, vars[i], temp1, temp2); + cmu_bdd_free(bddm, temp1); + cmu_bdd_free(bddm, temp2); + if (!result) + *error=BDD_UNDUMP_OVERFLOW; + return (result); +} + + +bdd +#if defined(__STDC__) +cmu_bdd_undump_bdd(cmu_bdd_manager bddm, bdd *vars, FILE *fp, int *error) +#else +cmu_bdd_undump_bdd(bddm, vars, fp, error) + cmu_bdd_manager bddm; + bdd *vars; + FILE *fp; + int *error; +#endif +{ + long i; + bdd_index_type number_vars; + long number_shared; + int index_size; + int node_number_size; + bdd *shared; + long shared_so_far; + bdd v; + bdd result; + + *error=0; + for (i=0; vars[i]; ++i) + if (cmu_bdd_type(bddm, vars[i]) != BDD_TYPE_POSVAR) + { + cmu_bdd_warning("cmu_bdd_undump_bdd: support is not all positive variables"); + return ((bdd)0); + } + if (read(error, sizeof(long), fp) != MAGIC_COOKIE) + { + if (!*error) + *error=BDD_UNDUMP_FORMAT; + return ((bdd)0); + } + number_vars=read(error, sizeof(bdd_index_type), fp); + if (*error) + return ((bdd)0); + if (number_vars != i) + { + *error=BDD_UNDUMP_FORMAT; + return ((bdd)0); + } + number_shared=read(error, sizeof(long), fp); + if (*error) + return ((bdd)0); + index_size=bytes_needed(number_vars+1); + node_number_size=bytes_needed(number_shared); + if (number_shared < 0) + { + *error=BDD_UNDUMP_FORMAT; + return ((bdd)0); + } + shared=(bdd *)mem_get_block((SIZE_T)(number_shared*sizeof(bdd))); + for (i=0; i < number_shared; ++i) + shared[i]=0; + shared_so_far=0; + result=cmu_bdd_undump_bdd_step(bddm, vars, fp, number_vars, shared, number_shared, + &shared_so_far, index_size, node_number_size, error); + for (i=0; i < number_shared; ++i) + if ((v=shared[i])) + cmu_bdd_free(bddm, v); + if (!*error && shared_so_far != number_shared) + *error=BDD_UNDUMP_FORMAT; + mem_free_block((pointer)shared); + if (*error) + { + if (result) + cmu_bdd_free(bddm, result); + return ((bdd)0); + } + return (result); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddhash.c b/sis/bdd_cmu/bdd_cmu/bddhash.c new file mode 100644 index 0000000..8701887 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddhash.c @@ -0,0 +1,150 @@ +/* BDD hash table routines */ + + +#include "bddint.h" + + +#define HASH(d) ((INT_PTR)(d)) + + +/* bdd_rehash_hash_table(h) increases the size of h by roughly a */ +/* factor of 2 and rehashes all of its entries. */ + +static +void +#if defined(__STDC__) +bdd_rehash_hash_table(hash_table h) +#else +bdd_rehash_hash_table(h) + hash_table h; +#endif +{ + long i; + long hash; + long oldsize; + hash_rec *newtable; + hash_rec p, q; + + oldsize=h->size; + h->size_index++; + h->size=TABLE_SIZE(h->size_index); + newtable=(hash_rec *)mem_get_block((SIZE_T)(h->size*sizeof(hash_rec))); + for (i=0; i < h->size; ++i) + newtable[i]=0; + for (i=0; i < oldsize; ++i) + for (p=h->table[i]; p; p=q) + { + q=p->next; + hash=HASH(p->key); + BDD_REDUCE(hash, h->size); + p->next=newtable[hash]; + newtable[hash]=p; + } + mem_free_block((pointer)h->table); + h->table=newtable; +} + + +/* bdd_insert_in_hash_table(h, f, data) associates the specified data */ +/* with f in h. */ + +void +#if defined(__STDC__) +bdd_insert_in_hash_table(hash_table h, bdd f, pointer data) +#else +bdd_insert_in_hash_table(h, f, data) + hash_table h; + bdd f; + pointer data; +#endif +{ + long hash; + hash_rec p; + + p=(hash_rec)BDD_NEW_REC(h->bddm, ALIGN(sizeof(struct hash_rec_))+h->item_size); + p->key=f; + mem_copy((pointer)(ALIGN(sizeof(struct hash_rec_))+(INT_PTR)p), data, (SIZE_T)h->item_size); + hash=HASH(f); + BDD_REDUCE(hash, h->size); + p->next=h->table[hash]; + h->table[hash]=p; + h->entries++; + if ((h->size << 2) < h->entries) + bdd_rehash_hash_table(h); +} + + +/* bdd_lookup_in_hash_table(h, f) looks up f in h and returns either a */ +/* pointer to the associated data or null. */ + +pointer +#if defined(__STDC__) +bdd_lookup_in_hash_table(hash_table h, bdd f) +#else +bdd_lookup_in_hash_table(h, f) + hash_table h; + bdd f; +#endif +{ + long hash; + hash_rec p; + + hash=HASH(f); + BDD_REDUCE(hash, h->size); + for (p=h->table[hash]; p; p=p->next) + if (p->key == f) + return ((pointer)(ALIGN(sizeof(struct hash_rec_))+(char *)p)); + return ((pointer)0); +} + + +/* bdd_new_hash_table(bddm, item_size) creates a new hash table with */ +/* the specified data item size. */ + +hash_table +#if defined(__STDC__) +bdd_new_hash_table(cmu_bdd_manager bddm, int item_size) +#else +bdd_new_hash_table(bddm, item_size) + cmu_bdd_manager bddm; + int item_size; +#endif +{ + long i; + hash_table h; + + h=(hash_table)BDD_NEW_REC(bddm, sizeof(struct hash_table_)); + h->size_index=10; + h->size=TABLE_SIZE(h->size_index); + h->table=(hash_rec *)mem_get_block((SIZE_T)(h->size*sizeof(hash_rec))); + for (i=0; i < h->size; ++i) + h->table[i]=0; + h->entries=0; + h->item_size=item_size; + h->bddm=bddm; + return (h); +} + + +/* cmu_bdd_free_hash_table(h) frees up the storage associated with h. */ + +void +#if defined(__STDC__) +cmu_bdd_free_hash_table(hash_table h) +#else +cmu_bdd_free_hash_table(h) + hash_table h; +#endif +{ + long i; + hash_rec p, q; + + for (i=0; i < h->size; ++i) + for (p=h->table[i]; p; p=q) + { + q=p->next; + BDD_FREE_REC(h->bddm, (pointer)p, ALIGN(sizeof(struct hash_rec_))+h->item_size); + } + mem_free_block((pointer)h->table); + BDD_FREE_REC(h->bddm, (pointer)h, sizeof(struct hash_table_)); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddint.h b/sis/bdd_cmu/bdd_cmu/bddint.h new file mode 100644 index 0000000..783f7af --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddint.h @@ -0,0 +1,733 @@ +/* BDD package internal definitions */ + + +#if !defined(_BDDINTH) +#define _BDDINTH + + +#include + + +/* >>> Configuration things */ + +/* Define this for cache and unique sizes to be a power of 2. */ +/* Probably not a good idea given the current simplistic hash function. */ + +/* #define POWER_OF_2_SIZES */ + +/* Define this if your C preprocessor is broken in such a way that */ +/* token concatenation can be done with something like: */ +/* #define CONCAT(f, g) f/''/g */ +/* where /''/ above would be an empty comment (' => *) if this */ +/* wasn't itself a comment. Most of the (non-ANSI) UNIX C preprocessors */ +/* do seem to be broken, which is why this is defined. If your C */ +/* preprocessor is ANSI, this shouldn't have any effect. */ + +#define BROKEN_CPP + + + +/* >>> All user-visible stuff */ + +#include "bdduser.h" + + +#if defined(__STDC__) +#define ARGS(args) args +#else +#define ARGS(args) () +#endif + + +/* Miscellaneous type definitions */ + +typedef struct hash_table_ *hash_table; + + +/* >>> BDD data structures */ + +#if !defined(POWER_OF_2_SIZES) +extern long bdd_primes[]; +#endif + + +/* Pointer tagging stuff */ + +#define POINTER(p) ((pointer)(((INT_PTR)(p)) & ~(INT_PTR)0x7)) +#define BDD_POINTER(p) ((bdd)POINTER(p)) +#define CACHE_POINTER(p) ((cache_entry)POINTER(p)) + +#define TAG(p) ((int)(((INT_PTR)(p)) & 0x7)) +#define SET_TAG(p, t) ((pointer)((INT_PTR)POINTER(p) | (t))) + +#define TAG0(p) ((int)((INT_PTR)(p) & 0x1)) +#define FLIP_TAG0(p) ((pointer)((INT_PTR)(p) ^ 0x1)) +#define TAG0_HI(p) ((pointer)((INT_PTR)(p) | 0x1)) +#define TAG0_LO(p) ((pointer)((INT_PTR)(p) & ~(INT_PTR)0x1)) + +#define TAG1(p) ((int)((INT_PTR)(p) & 0x2)) +#define FLIP_TAG1(p) ((pointer)((INT_PTR)(p) ^ 0x2)) +#define TAG1_HI(p) ((pointer)((INT_PTR)(p) | 0x2)) +#define TAG1_LO(p) ((pointer)((INT_PTR)(p) & ~(INT_PTR)0x2)) + +#define TAG2(p) ((int)((INT_PTR)(p) & 0x4)) +#define FLIP_TAG2(p) ((pointer)((INT_PTR)(p) ^ 0x4)) +#define TAG2_HI(p) ((pointer)((INT_PTR)(p) | 0x4)) +#define TAG2_LO(p) ((pointer)((INT_PTR)(p) & ~(INT_PTR)0x4)) + + +/* Indexes */ + +typedef unsigned short bdd_index_type; + + +/* Types of various BDD node fields */ + +typedef unsigned short bdd_indexindex_type; +typedef unsigned char bdd_refcount_type; +typedef unsigned char bdd_mark_type; + + +/* A BDD node */ + +struct bdd_ +{ + bdd_indexindex_type indexindex; + /* Index into indexes table */ + bdd_refcount_type refs; /* External reference count */ + bdd_mark_type mark; /* Mark and temporary ref count */ + INT_PTR data[2]; /* Then and else pointers, or data */ + /* values for terminals */ + struct bdd_ *next; +}; + + +/* Maximum reference counts */ + +#define BDD_MAX_REFS ((bdd_refcount_type)((1l << (8*sizeof(bdd_refcount_type))) - 1)) +#define BDD_MAX_TEMP_REFS ((bdd_mark_type)((1l << (8*sizeof(bdd_mark_type)-1)) - 1)) + +#define BDD_GC_MARK ((bdd_mark_type)(1l << (8*sizeof(bdd_mark_type)-1))) + + +/* Special indexindexes and indexes */ + +#define BDD_CONST_INDEXINDEX 0 +#define BDD_MAX_INDEXINDEX ((bdd_indexindex_type)((1l << (8*sizeof(bdd_indexindex_type))) - 1)) +#define BDD_MAX_INDEX ((bdd_index_type)((1l << (8*sizeof(bdd_index_type))) - 1)) + + +/* Can this be done legally with a non-ANSI cpp? */ + +#if defined(__STDC__) +#define CONCAT_PTR(f) f##_ptr +#elif defined(BROKEN_CPP) +#define CONCAT_PTR(f) f/**/_ptr +#endif + +#if defined(CONCAT_PTR) +/* Field accessing stuff */ + +#define BDD_SETUP(f) bdd CONCAT_PTR(f)=BDD_POINTER(f) +#define BDD_RESET(f) CONCAT_PTR(f)=BDD_POINTER(f) +#define BDD_INDEXINDEX(f) (CONCAT_PTR(f)->indexindex) +#define BDD_DATA(f) (CONCAT_PTR(f)->data) +#define BDD_DATA0(f) (CONCAT_PTR(f)->data[0]) +#define BDD_DATA1(f) (CONCAT_PTR(f)->data[1]) +#define BDD_REFS(f) (CONCAT_PTR(f)->refs) +#define BDD_MARK(f) (CONCAT_PTR(f)->mark) +#define BDD_TEMP_REFS(f) (CONCAT_PTR(f)->mark) + + +/* Basic stuff stuff for indexes, testing, etc. */ + +#define BDD_INDEX(bddm, f) ((bddm)->indexes[BDD_INDEXINDEX(f)]) +#define BDD_THEN(f) ((bdd)(BDD_DATA0(f) ^ TAG0(f))) +#define BDD_ELSE(f) ((bdd)(BDD_DATA1(f) ^ TAG0(f))) +#define BDD_SAME_OR_NEGATIONS(f, g) (CONCAT_PTR(f) == CONCAT_PTR(g)) +#define BDD_IS_CONST(f) (BDD_INDEXINDEX(f) == BDD_CONST_INDEXINDEX) +#else +/* Field accessing stuff */ + +#define BDD_SETUP(f) +#define BDD_RESET(f) +#define BDD_INDEXINDEX(f) (BDD_POINTER(f)->indexindex) +#define BDD_DATA(f) (BDD_POINTER(f)->data) +#define BDD_DATA0(f) (BDD_POINTER(f)->data[0]) +#define BDD_DATA1(f) (BDD_POINTER(f)->data[1]) +#define BDD_REFS(f) (BDD_POINTER(f)->refs) +#define BDD_MARK(f) (BDD_POINTER(f)->mark) +#define BDD_TEMP_REFS(f) (BDD_POINTER(f)->mark) + + +/* Basic stuff stuff for indexes, testing, etc. */ + +#define BDD_INDEX(bddm, f) ((bddm)->indexes[BDD_INDEXINDEX(f)]) +#define BDD_THEN(f) ((bdd)(BDD_DATA0(f) ^ TAG0(f))) +#define BDD_ELSE(f) ((bdd)(BDD_DATA1(f) ^ TAG0(f))) +#define BDD_SAME_OR_NEGATIONS(f, g) (BDD_POINTER(f) == BDD_POINTER(g)) +#define BDD_IS_CONST(f) (BDD_INDEXINDEX(f) == BDD_CONST_INDEXINDEX) +#endif + + +/* BDD complement flag stuff */ + +#define BDD_IS_OUTPOS(f) (!TAG0(f)) +#define BDD_OUTPOS(f) ((bdd)TAG0_LO(f)) +#define BDD_NOT(f) ((bdd)FLIP_TAG0(f)) + + +/* Cofactoring stuff */ + +#define BDD_TOP_VAR2(top_indexindex, bddm, f, g)\ +do\ + if (BDD_INDEX(bddm, f) < BDD_INDEX(bddm, g))\ + top_indexindex=BDD_INDEXINDEX(f);\ + else\ + top_indexindex=BDD_INDEXINDEX(g);\ +while (0) + +#define BDD_TOP_VAR3(top_indexindex, bddm, f, g, h)\ +do\ + if (BDD_INDEX(bddm, f) < BDD_INDEX(bddm, g))\ + {\ + top_indexindex=BDD_INDEXINDEX(f);\ + if ((bddm)->indexes[top_indexindex] > BDD_INDEX(bddm, h))\ + top_indexindex=BDD_INDEXINDEX(h);\ + }\ + else\ + {\ + top_indexindex=BDD_INDEXINDEX(g);\ + if ((bddm)->indexes[top_indexindex] > BDD_INDEX(bddm, h))\ + top_indexindex=BDD_INDEXINDEX(h);\ + }\ +while (0) + +#define BDD_COFACTOR(top_indexindex, f, f_then, f_else)\ +do\ + if (BDD_INDEXINDEX(f) == top_indexindex)\ + {\ + f_then=BDD_THEN(f);\ + f_else=BDD_ELSE(f);\ + }\ + else\ + {\ + f_then=f;\ + f_else=f;\ + }\ +while (0) + + +/* Ordering stuff */ + +#define BDD_OUT_OF_ORDER(f, g) ((INT_PTR)f > (INT_PTR)g) + +#if defined(CONCAT_PTR) +#define BDD_SWAP(f, g)\ +do\ + {\ + bdd _temp;\ + _temp=f;\ + f=g;\ + g=_temp;\ + _temp=CONCAT_PTR(f);\ + CONCAT_PTR(f)=CONCAT_PTR(g);\ + CONCAT_PTR(g)=_temp;\ + }\ +while (0) +#else +#define BDD_SWAP(f, g)\ +do\ + {\ + bdd _temp;\ + _temp=f;\ + f=g;\ + g=_temp;\ + }\ +while (0) +#endif + + +/* This gets the variable at the top of a node. */ + +#define BDD_IF(bddm, f) ((bddm)->variables[BDD_INDEXINDEX(f)]) + + +/* Reference count stuff */ + +#define BDD_INCREFS(f)\ +do\ + {\ + if (BDD_REFS(f) >= BDD_MAX_REFS-1)\ + {\ + BDD_REFS(f)=BDD_MAX_REFS;\ + BDD_TEMP_REFS(f)=0;\ + }\ + else\ + BDD_REFS(f)++;\ + }\ +while (0) + +#define BDD_DECREFS(f)\ +do\ + {\ + if (BDD_REFS(f) < BDD_MAX_REFS)\ + BDD_REFS(f)--;\ + }\ +while (0) + +#define BDD_TEMP_INCREFS(f)\ +do\ + {\ + if (BDD_REFS(f) < BDD_MAX_REFS)\ + {\ + BDD_TEMP_REFS(f)++;\ + if (BDD_TEMP_REFS(f) == BDD_MAX_TEMP_REFS)\ + {\ + BDD_REFS(f)=BDD_MAX_REFS;\ + BDD_TEMP_REFS(f)=0;\ + }\ + }\ + }\ +while (0) + +#define BDD_TEMP_DECREFS(f)\ +do\ + {\ + if (BDD_REFS(f) < BDD_MAX_REFS)\ + BDD_TEMP_REFS(f)--;\ + }\ +while (0) + +#define BDD_IS_USED(f) ((BDD_MARK(f) & BDD_GC_MARK) != 0) + + +/* Convert an internal reference to an external one and return. */ + +#define RETURN_BDD(thing)\ +return (bdd_make_external(thing)) + + +/* These return the constants. */ + +#define BDD_ONE(bddm) ((bddm)->one) +#define BDD_ZERO(bddm) ((bddm)->zero) + + +/* Cache entries */ + +struct cache_entry_ +{ + INT_PTR slot[4]; +}; + +typedef struct cache_entry_ *cache_entry; + + +/* Cache entry tags; ITE is for IF-THEN-ELSE operations. TWO is for */ +/* the two argument operations that return a BDD result. ONEDATA */ +/* and TWODATA are for one and two argument operations that return */ +/* double and single word data results. Everything else is under */ +/* user control. */ + +#define CACHE_TYPE_ITE 0x0 +#define CACHE_TYPE_TWO 0x1 +#define CACHE_TYPE_ONEDATA 0x2 +#define CACHE_TYPE_TWODATA 0x3 +#define CACHE_TYPE_USER1 0x4 + +#define USER_ENTRY_TYPES 4 + + +/* Operation numbers (for CACHE_TYPE_TWO) */ +/* OP_RELPROD, OP_QNT and OP_SUBST need a reasonable number of holes */ +/* after them since the variable association number is added to them */ +/* to get the actual op. OP_COMP, OP_SWAP and OP_CMPTO need */ +/* BDD_MAX_INDEX. OP_SWAPAUX needs 2*BDD_MAX_INDEX. Negative */ +/* operation numbers denote temporaries and are generated as needed. */ + +#define OP_COFACTOR 100l +#define OP_SATFRAC 200l +#define OP_FWD 300l +#define OP_REV 400l +#define OP_RED 500l +#define OP_EQUAL 600l +#define OP_QNT 10000l +#define OP_RELPROD 20000l +#define OP_SUBST 30000l +#define OP_COMP 100000l +#define OP_CMPTO 200000l +#define OP_SWAP 300000l +#define OP_SWAPAUX 400000l + + +/* Variable associations */ + +struct var_assoc_ +{ + bdd *assoc; /* Array with associated BDDs */ + long last; /* Indexindex for lowest variable */ +}; + +typedef struct var_assoc_ *var_assoc; + + +struct assoc_list_ +{ + struct var_assoc_ va; /* The association */ + int id; /* Identifier for this association */ + int refs; /* Number of outstanding references */ + struct assoc_list_ *next; /* The next association */ +}; + +typedef struct assoc_list_ *assoc_list; + + +/* Variable blocks */ + +struct block_ +{ + long num_children; + struct block_ **children; + int reorderable; + long first_index; + long last_index; +}; + + +/* A cache bin; the cache is two-way associative. */ + +struct cache_bin_ +{ + cache_entry entry[2]; /* LRU has index 1 */ +}; + +typedef struct cache_bin_ cache_bin; + + +/* The cache */ + +struct cache_ +{ + cache_bin *table; /* The cache itself */ + int size_index; /* Index giving number of cache lines */ + long size; /* Number of cache lines */ + int cache_level; /* Bin to start search in cache */ + /* Cache control functions: */ + long (*rehash_fn[8]) ARGS((cmu_bdd_manager, cache_entry)); + /* Rehashes a cache entry */ + int (*gc_fn[8]) ARGS((cmu_bdd_manager, cache_entry)); + /* Checks to see if an entry needs flushing */ + void (*purge_fn[8]) ARGS((cmu_bdd_manager, cache_entry)); + /* Called when purging an entry */ + void (*return_fn[8]) ARGS((cmu_bdd_manager, cache_entry)); + /* Called before returning from cache hit */ + int (*flush_fn[8]) ARGS((cmu_bdd_manager, cache_entry, pointer)); + /* Called when freeing variable association */ + int cache_ratio; /* Cache to unique table size ratio */ + long entries; /* Number of cache entries */ + long lookups; /* Number of cache lookups */ + long hits; /* Number of cache hits */ + long inserts; /* Number of cache inserts */ + long collisions; /* Number of cache collisions */ +}; + +typedef struct cache_ cache; + + +/* One part of the node table */ + +struct var_table_ +{ + bdd *table; /* Pointers to the start of each bucket */ + int size_index; /* Index giving number of buckets */ + long size; /* Number of buckets */ + long entries; /* Number of BDD nodes in table */ +}; + +typedef struct var_table_ *var_table; + + +/* The BDD node table */ + +struct unique_ +{ + var_table *tables; /* Individual variable tables */ + void (*free_terminal_fn) ARGS((cmu_bdd_manager, INT_PTR, INT_PTR, pointer)); + /* Called when freeing MTBDD terminals */ + pointer free_terminal_env; /* Environment for free terminal function */ + long entries; /* Total number of BDD nodes */ + long gc_limit; /* Try garbage collection at this point */ + long node_limit; /* Maximum number of BDD nodes allowed */ + long gcs; /* Number of garbage collections */ + long freed; /* Number of nodes freed */ + long finds; /* Number of find operations */ +}; + +typedef struct unique_ unique; + + +/* Record manager size range stuff */ + +#define MIN_REC_SIZE ALLOC_ALIGNMENT +#define MAX_REC_SIZE 64 + +#define REC_MGRS (((MAX_REC_SIZE-MIN_REC_SIZE)/ALLOC_ALIGNMENT)+1) + + +/* Wrapper for jmp_buf since we may need to copy it sometimes and */ +/* we can't easily do it if it happens to be an array. */ + +struct jump_buf_ +{ + jmp_buf context; +}; + +typedef struct jump_buf_ jump_buf; + + +/* A BDD manager */ + +struct bdd_manager_ +{ + unique unique_table; /* BDD node table */ + cache op_cache; /* System result cache */ + int check; /* Number of find calls 'til size checks */ + bdd one; /* BDD for one */ + bdd zero; /* BDD for zero */ + int overflow; /* Nonzero if node limit exceeded */ + void (*overflow_fn) ARGS((cmu_bdd_manager, pointer)); + /* Function to call on overflow */ + pointer overflow_env; /* Environment for overflow function */ + void (*transform_fn) ARGS((cmu_bdd_manager, INT_PTR, INT_PTR, INT_PTR *, INT_PTR *, pointer)); + /* Function to transform terminal values */ + pointer transform_env; /* Environment for transform_fn */ + int (*canonical_fn) ARGS((cmu_bdd_manager, INT_PTR, INT_PTR, pointer)); + /* Function to check if a terminal value is */ + /* canonical */ + block super_block; /* Top-level variable block */ + void (*reorder_fn) ARGS((cmu_bdd_manager)); + /* Function to call to reorder variables */ + pointer reorder_data; /* For saving information btwn reorderings */ + int allow_reordering; /* Nonzero if reordering allowed */ + long nodes_at_start; /* Nodes at start of operation */ + long vars; /* Number of variables */ + long maxvars; /* Maximum number of variables w/o resize */ + bdd *variables; /* Array of variables, by indexindex */ + bdd_index_type *indexes; /* indexindex -> index table */ + bdd_indexindex_type *indexindexes; + /* index -> indexindex table */ + int curr_assoc_id; /* Current variable association number */ + var_assoc curr_assoc; /* Current variable association */ + assoc_list assocs; /* Variable associations */ + struct var_assoc_ temp_assoc; /* Temporary variable association */ + rec_mgr rms[REC_MGRS]; /* Record managers */ + long temp_op; /* Current temporary operation number */ + jump_buf abort; /* Jump for out-of-memory cleanup */ + void (*bag_it_fn) ARGS((cmu_bdd_manager, pointer)); + /* Non-null if going to abort at next find */ + pointer bag_it_env; char *hooks; /* Environment for bag it function */ +}; + + +/* Abort stuff */ + +#define BDD_ABORTED 1 +#define BDD_OVERFLOWED 2 +#define BDD_REORDERED 3 + + +#define FIREWALL(bddm)\ +do\ + {\ + int retcode;\ + (bddm)->allow_reordering=1;\ + (bddm)->nodes_at_start=(bddm)->unique_table.entries;\ + while ((retcode=(setjmp((bddm)->abort.context))))\ + {\ + bdd_cleanup(bddm, retcode);\ + if (retcode == BDD_ABORTED || retcode == BDD_OVERFLOWED)\ + return ((bdd)0);\ + (bddm)->nodes_at_start=(bddm)->unique_table.entries;\ + }\ + }\ +while (0) + + +#define FIREWALL1(bddm, cleanupcode)\ +do\ + {\ + int retcode;\ + (bddm)->allow_reordering=1;\ + (bddm)->nodes_at_start=(bddm)->unique_table.entries;\ + while ((retcode=(setjmp((bddm)->abort.context))))\ + {\ + bdd_cleanup(bddm, retcode);\ + cleanupcode\ + (bddm)->nodes_at_start=(bddm)->unique_table.entries;\ + }\ + }\ +while (0) + + +/* Node hash function */ + +#define HASH_NODE(f, g) (((f) << 1)+(g)) + + +/* Table size stuff */ + +#if defined(POWER_OF_2_SIZES) +#define TABLE_SIZE(size_index) (1l << (size_index)) +#define BDD_REDUCE(i, size) (i)&=(size)-1 +#else +#define TABLE_SIZE(size_index) (bdd_primes[size_index]) +#define BDD_REDUCE(i, size)\ +do\ + {\ + (i)%=(size);\ + if ((i) < 0)\ + (i)= -(i);\ + }\ +while (0) +#endif + + +/* Record management */ + +#define BDD_NEW_REC(bddm, size) mem_new_rec((bddm)->rms[(ROUNDUP(size)-MIN_REC_SIZE)/ALLOC_ALIGNMENT]) +#define BDD_FREE_REC(bddm, rec, size) mem_free_rec((bddm)->rms[(ROUNDUP(size)-MIN_REC_SIZE)/ALLOC_ALIGNMENT], (rec)) + + +/* >>> Declarations for random routines */ + +/* Internal BDD routines */ + +extern int bdd_check_arguments ARGS((int, ...)); +extern void bdd_check_array ARGS((bdd *)); +extern bdd bdd_make_external ARGS((bdd)); +extern int cmu_bdd_type_aux ARGS((cmu_bdd_manager, bdd)); +extern void bdd_rehash_var_table ARGS((var_table, int)); +extern bdd bdd_find_aux ARGS((cmu_bdd_manager, bdd_indexindex_type, INT_PTR, INT_PTR)); +extern bdd cmu_bdd_ite_step ARGS((cmu_bdd_manager, bdd, bdd, bdd)); +extern bdd cmu_bdd_exists_temp ARGS((cmu_bdd_manager, bdd, long)); +extern bdd cmu_bdd_compose_temp ARGS((cmu_bdd_manager, bdd, bdd, bdd)); +extern bdd cmu_bdd_substitute_step ARGS((cmu_bdd_manager, bdd, long, bdd (*) ARGS((cmu_bdd_manager, bdd, bdd, bdd)), var_assoc)); +extern bdd cmu_bdd_swap_vars_temp ARGS((cmu_bdd_manager, bdd, bdd, bdd)); +extern int cmu_bdd_compare_temp ARGS((cmu_bdd_manager, bdd, bdd, bdd)); +extern double cmu_bdd_satisfying_fraction_step ARGS((cmu_bdd_manager, bdd)); +extern void bdd_mark_shared_nodes ARGS((cmu_bdd_manager, bdd)); +extern void bdd_number_shared_nodes ARGS((cmu_bdd_manager, bdd, hash_table, long *)); +extern char *bdd_terminal_id ARGS((cmu_bdd_manager, bdd, char *(*) ARGS((cmu_bdd_manager, INT_PTR, INT_PTR, pointer)), pointer)); +extern char *bdd_var_name ARGS((cmu_bdd_manager, bdd, char *(*) ARGS((cmu_bdd_manager, bdd, pointer)), pointer)); +extern long bdd_find_block ARGS((block, long)); +extern void bdd_block_delta ARGS((block, long)); +extern void cmu_bdd_reorder_aux ARGS((cmu_bdd_manager)); +extern void cmu_mtbdd_terminal_value_aux ARGS((cmu_bdd_manager, bdd, INT_PTR *, INT_PTR *)); + + +/* System cache routines */ + +extern void bdd_insert_in_cache31 ARGS((cmu_bdd_manager, int, INT_PTR, INT_PTR, INT_PTR, INT_PTR)); +extern int bdd_lookup_in_cache31 ARGS((cmu_bdd_manager, int, INT_PTR, INT_PTR, INT_PTR, INT_PTR *)); +extern void bdd_insert_in_cache22 ARGS((cmu_bdd_manager, int, INT_PTR, INT_PTR, INT_PTR, INT_PTR)); +extern int bdd_lookup_in_cache22 ARGS((cmu_bdd_manager, int, INT_PTR, INT_PTR, INT_PTR *, INT_PTR *)); +extern void bdd_insert_in_cache13 ARGS((cmu_bdd_manager, int, INT_PTR, INT_PTR, INT_PTR, INT_PTR)); +extern int bdd_lookup_in_cache13 ARGS((cmu_bdd_manager, int, INT_PTR, INT_PTR *, INT_PTR *, INT_PTR *)); +extern void bdd_flush_cache ARGS((cmu_bdd_manager, int (*) ARGS((cmu_bdd_manager, cache_entry, pointer)), pointer)); +extern void bdd_purge_cache ARGS((cmu_bdd_manager)); +extern void bdd_flush_all ARGS((cmu_bdd_manager)); +extern int bdd_cache_functions ARGS((cmu_bdd_manager, + int, + int (*) ARGS((cmu_bdd_manager, cache_entry)), + void (*) ARGS((cmu_bdd_manager, cache_entry)), + void (*) ARGS((cmu_bdd_manager,cache_entry)), + int (*) ARGS((cmu_bdd_manager, cache_entry, pointer)))); +extern void cmu_bdd_free_cache_tag ARGS((cmu_bdd_manager, int)); +extern void bdd_rehash_cache ARGS((cmu_bdd_manager, int)); +extern void cmu_bdd_init_cache ARGS((cmu_bdd_manager)); +extern void cmu_bdd_free_cache ARGS((cmu_bdd_manager)); + +#define bdd_insert_in_cache2(bddm, op, f, g, result)\ +bdd_insert_in_cache31((bddm), CACHE_TYPE_TWO, (INT_PTR)(op), (INT_PTR)(f), (INT_PTR)(g), (INT_PTR)(result)) +#define bdd_lookup_in_cache2(bddm, op, f, g, result)\ +bdd_lookup_in_cache31((bddm), CACHE_TYPE_TWO, (INT_PTR)(op), (INT_PTR)(f), (INT_PTR)(g), (INT_PTR *)(result)) + +#define bdd_insert_in_cache1(bddm, op, f, result)\ +bdd_insert_in_cache2((bddm), (op), (f), BDD_ONE(bddm), (result)) +#define bdd_lookup_in_cache1(bddm, op, f, result)\ +bdd_lookup_in_cache2((bddm), (op), (f), BDD_ONE(bddm), (result)) + +#define bdd_insert_in_cache2d(bddm, op, f, g, result)\ +bdd_insert_in_cache31((bddm), CACHE_TYPE_TWODATA, (INT_PTR)(op), (INT_PTR)(f), (INT_PTR)(g), (INT_PTR)(result)) +#define bdd_lookup_in_cache2d(bddm, op, f, g, result)\ +bdd_lookup_in_cache31((bddm), CACHE_TYPE_TWODATA, (INT_PTR)(op), (INT_PTR)(f), (INT_PTR)(g), (INT_PTR *)(result)) + +#define bdd_insert_in_cache1d(bddm, op, f, result1, result2)\ +bdd_insert_in_cache22((bddm), CACHE_TYPE_ONEDATA, (INT_PTR)(op), (INT_PTR)(f), (INT_PTR)(result1), (INT_PTR)(result2)) +#define bdd_lookup_in_cache1d(bddm, op, f, result1, result2)\ +bdd_lookup_in_cache22((bddm), CACHE_TYPE_ONEDATA, (INT_PTR)(op), (INT_PTR)(f), (INT_PTR *)(result1), (INT_PTR *)(result2)) + +#if defined(__STDC__) +#define cache_return_fn_none ((void (*)(cmu_bdd_manager, cache_entry))0) +#define cache_purge_fn_none ((void (*)(cmu_bdd_manager, cache_entry))0) +#define cache_reclaim_fn_none ((int (*)(cmu_bdd_manager, cache_entry, pointer))0) +#else +#define cache_return_fn_none ((void (*)())0) +#define cache_purge_fn_none ((void (*)())0) +#define cache_reclaim_fn_none ((int (*)())0) +#endif + + +/* Unique table routines */ + +extern void bdd_clear_temps ARGS((cmu_bdd_manager)); +extern void bdd_sweep_var_table ARGS((cmu_bdd_manager, long, int)); +extern void bdd_sweep ARGS((cmu_bdd_manager)); +extern void bdd_cleanup ARGS((cmu_bdd_manager, int)); +extern bdd bdd_find ARGS((cmu_bdd_manager, bdd_indexindex_type, bdd, bdd)); +extern bdd bdd_find_terminal ARGS((cmu_bdd_manager, INT_PTR, INT_PTR)); +extern var_table bdd_new_var_table ARGS((cmu_bdd_manager)); +extern void cmu_bdd_init_unique ARGS((cmu_bdd_manager)); +extern void cmu_bdd_free_unique ARGS((cmu_bdd_manager)); + + +/* Error routines */ + +extern void cmu_bdd_fatal ARGS((char *)); +extern void cmu_bdd_warning ARGS((char *)); + + +/* >>> Hash table declarations */ + +struct hash_rec_ +{ + bdd key; + struct hash_rec_ *next; +}; + +typedef struct hash_rec_ *hash_rec; + + +struct hash_table_ +{ + hash_rec *table; + int size_index; + long size; + long entries; + int item_size; + cmu_bdd_manager bddm; +}; + + +/* Hash table routines */ + +extern void bdd_insert_in_hash_table ARGS((hash_table, bdd, pointer)); +extern pointer bdd_lookup_in_hash_table ARGS((hash_table, bdd)); +extern hash_table bdd_new_hash_table ARGS((cmu_bdd_manager, int)); +extern void cmu_bdd_free_hash_table ARGS((hash_table)); + + +#undef ARGS + +#endif diff --git a/sis/bdd_cmu/bdd_cmu/bddmisc.c b/sis/bdd_cmu/bdd_cmu/bddmisc.c new file mode 100644 index 0000000..29366f8 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddmisc.c @@ -0,0 +1,141 @@ +/* Support functions need by miscellaneous BDD routines */ + + +#include "bddint.h" + + +void +#if defined(__STDC__) +bdd_mark_shared_nodes(cmu_bdd_manager bddm, bdd f) +#else +bdd_mark_shared_nodes(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + BDD_SETUP(f); + f=BDD_OUTPOS(f); + if (BDD_IS_CONST(f) || cmu_bdd_type_aux(bddm, f) == BDD_TYPE_POSVAR) + return; + if (BDD_MARK(f)) + { + if (BDD_MARK(f) == 1) + BDD_MARK(f)=2; + return; + } + BDD_MARK(f)=1; + bdd_mark_shared_nodes(bddm, BDD_THEN(f)); + bdd_mark_shared_nodes(bddm, BDD_ELSE(f)); +} + + +void +#if defined(__STDC__) +bdd_number_shared_nodes(cmu_bdd_manager bddm, bdd f, hash_table h, long *next) +#else +bdd_number_shared_nodes(bddm, f, h, next) + cmu_bdd_manager bddm; + bdd f; + hash_table h; + long *next; +#endif +{ + BDD_SETUP(f); + if (BDD_IS_CONST(f) || ((1 << cmu_bdd_type_aux(bddm, f)) & ((1 << BDD_TYPE_POSVAR) | (1 << BDD_TYPE_NEGVAR)))) + return; + if (BDD_MARK(f) == 0) + return; + if (BDD_MARK(f) == 2) + { + bdd_insert_in_hash_table(h, f, (pointer)next); + ++*next; + } + BDD_MARK(f)=0; + bdd_number_shared_nodes(bddm, BDD_THEN(f), h, next); + bdd_number_shared_nodes(bddm, BDD_ELSE(f), h, next); +} + + +static char default_terminal_id[]="terminal XXXXXXXXXX XXXXXXXXXX"; +static char default_var_name[]="var.XXXXXXXXXX"; + + +char * +#if defined(__STDC__) +bdd_terminal_id(cmu_bdd_manager bddm, bdd f, char *(*terminal_id_fn)(cmu_bdd_manager, INT_PTR, INT_PTR, pointer), pointer env) +#else +bdd_terminal_id(bddm, f, terminal_id_fn, env) + cmu_bdd_manager bddm; + bdd f; + char *(*terminal_id_fn)(); + pointer env; +#endif +{ + char *id; + INT_PTR v1, v2; + + cmu_mtbdd_terminal_value_aux(bddm, f, &v1, &v2); + if (terminal_id_fn) + id=(*terminal_id_fn)(bddm, v1, v2, env); + else + id=0; + if (!id) + { + if (f == BDD_ONE(bddm)) + return ("1"); + if (f == BDD_ZERO(bddm)) + return ("0"); + sprintf(default_terminal_id, "terminal %ld %ld", (long)v1, (long)v2); + id=default_terminal_id; + } + return (id); +} + + +char * +#if defined(__STDC__) +bdd_var_name(cmu_bdd_manager bddm, bdd v, char *(*var_naming_fn)(cmu_bdd_manager, bdd, pointer), pointer env) +#else +bdd_var_name(bddm, v, var_naming_fn, env) + cmu_bdd_manager bddm; + bdd v; + char *(*var_naming_fn)(); + pointer env; +#endif +{ + char *name; + + if (var_naming_fn) + name=(*var_naming_fn)(bddm, v, env); + else + name=0; + if (!name) + { + BDD_SETUP(v); + sprintf(default_var_name, "var.%d", BDD_INDEX(bddm, v)); + name=default_var_name; + } + return (name); +} + + +void +#if defined(__STDC__) +cmu_mtbdd_terminal_value_aux(cmu_bdd_manager bddm, bdd f, INT_PTR *value1, INT_PTR *value2) +#else +cmu_mtbdd_terminal_value_aux(bddm, f, value1, value2) + cmu_bdd_manager bddm; + bdd f; + INT_PTR *value1; + INT_PTR *value2; +#endif +{ + BDD_SETUP(f); + if (BDD_IS_OUTPOS(f)) + { + *value1=BDD_DATA0(f); + *value2=BDD_DATA1(f); + } + else + (*bddm->transform_fn)(bddm, BDD_DATA0(f), BDD_DATA1(f), value1, value2, bddm->transform_env); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddprimes.c b/sis/bdd_cmu/bdd_cmu/bddprimes.c new file mode 100644 index 0000000..6152491 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddprimes.c @@ -0,0 +1,55 @@ +/* BDD routine prime numbers for table sizes */ + + +long bdd_primes[]= +{ + 1, + 2, + 3, + 7, + 13, + 23, + 59, + 113, + 241, + 503, + 1019, + 2039, + 4091, + 8179, + 11587, + 16369, + 23143, + 32749, + 46349, + 65521, + 92683, + 131063, + 185363, + 262139, + 330287, + 416147, + 524269, + 660557, + 832253, + 1048571, + 1321109, + 1664501, + 2097143, + 2642201, + 3328979, + 4194287, + 5284393, + 6657919, + 8388593, + 10568797, + 13315831, + 16777199, + 33554393, + 67108859, + 134217689, + 268435399, + 536870879, + 1073741789, + 2147483629 +}; diff --git a/sis/bdd_cmu/bdd_cmu/bddprint.c b/sis/bdd_cmu/bdd_cmu/bddprint.c new file mode 100644 index 0000000..15e5274 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddprint.c @@ -0,0 +1,173 @@ +/* BDD library print routines */ + + +#include "bddint.h" + + +static +void +#if defined(__STDC__) +chars(char c, int n, FILE *fp) +#else +chars(c, n, fp) + char c; + int n; + FILE *fp; +#endif +{ + int i; + + for (i=0; i < n; ++i) + fputc(c, fp); +} + + +static +void +#if defined(__STDC__) +bdd_print_top_var(cmu_bdd_manager bddm, + bdd f, + char *(*var_naming_fn)(cmu_bdd_manager, bdd, pointer), + pointer env, + FILE *fp) +#else +bdd_print_top_var(bddm, f, var_naming_fn, env, fp) + cmu_bdd_manager bddm; + bdd f; + char *(*var_naming_fn)(); + pointer env; + FILE *fp; +#endif +{ + BDD_SETUP(f); + fputs(bdd_var_name(bddm, BDD_IF(bddm, f), var_naming_fn, env), fp); + fputc('\n', fp); +} + + +static +void +#if defined(__STDC__) +cmu_bdd_print_bdd_step(cmu_bdd_manager bddm, + bdd f, + char *(*var_naming_fn)(cmu_bdd_manager, bdd, pointer), + char *(*terminal_id_fn)(cmu_bdd_manager, INT_PTR, INT_PTR, pointer), + pointer env, + FILE *fp, + hash_table h, + int indentation) +#else +cmu_bdd_print_bdd_step(bddm, f, var_naming_fn, terminal_id_fn, env, fp, h, indentation) + cmu_bdd_manager bddm; + bdd f; + char *(*var_naming_fn)(); + char *(*terminal_id_fn)(); + pointer env; + FILE *fp; + hash_table h; + int indentation; +#endif +{ + int negated; + long *number; + + BDD_SETUP(f); + chars(' ', indentation, fp); + switch (cmu_bdd_type_aux(bddm, f)) + { + case BDD_TYPE_ZERO: + case BDD_TYPE_ONE: + case BDD_TYPE_CONSTANT: + fputs(bdd_terminal_id(bddm, f, terminal_id_fn, env), fp); + fputc('\n', fp); + break; + case BDD_TYPE_NEGVAR: + fputc('!', fp); + /* fall through */ + case BDD_TYPE_POSVAR: + bdd_print_top_var(bddm, f, var_naming_fn, env, fp); + break; + case BDD_TYPE_NONTERMINAL: + if (bdd_lookup_in_hash_table(h, BDD_NOT(f))) + { + f=BDD_NOT(f); + negated=1; + } + else + negated=0; + number=(long *)bdd_lookup_in_hash_table(h, f); + if (number && *number < 0) + { + if (negated) + fputc('!', fp); + fprintf(fp, "subformula %d\n", -*number-1); + } + else + { + if (number) + { + fprintf(fp, "%d: ", *number); + *number= -*number-1; + } + fputs("if ", fp); + bdd_print_top_var(bddm, f, var_naming_fn, env, fp); + cmu_bdd_print_bdd_step(bddm, BDD_THEN(f), var_naming_fn, terminal_id_fn, env, fp, h, indentation+2); + chars(' ', indentation, fp); + fputs("else if !", fp); + bdd_print_top_var(bddm, f, var_naming_fn, env, fp); + cmu_bdd_print_bdd_step(bddm, BDD_ELSE(f), var_naming_fn, terminal_id_fn, env, fp, h, indentation+2); + chars(' ', indentation, fp); + fputs("endif ", fp); + bdd_print_top_var(bddm, f, var_naming_fn, env, fp); + } + break; + default: + cmu_bdd_fatal("cmu_bdd_print_bdd_step: unknown type returned by cmu_bdd_type"); + } +} + + +/* cmu_bdd_print_bdd(bddm, f, var_naming_fn, terminal_id_fn, env, fp) prints a */ +/* human-readable representation of f to the file given by fp. If */ +/* var_naming_fn is non-null, it should be a pointer to a function that */ +/* assigns names to BDD variables. It is passed bddm, a BDD representing */ +/* a variable, and the pointer given by env, and should return a string */ +/* giving the name of the variable or null. If terminal_id_fn is */ +/* non-null, it should be a pointer to a function that formats terminal */ +/* nodes. It is passed bddm, two longs representing the data value of */ +/* the terminal node, and env. It should return a string for the */ +/* terminal node, or null. */ + +void +#if defined(__STDC__) +cmu_bdd_print_bdd(cmu_bdd_manager bddm, + bdd f, + char *(*var_naming_fn)(cmu_bdd_manager, bdd, pointer), + char *(*terminal_id_fn)(cmu_bdd_manager, INT_PTR, INT_PTR, pointer), + pointer env, + FILE *fp) +#else +cmu_bdd_print_bdd(bddm, f, var_naming_fn, terminal_id_fn, env, fp) + cmu_bdd_manager bddm; + bdd f; + char *(*var_naming_fn)(); + char *(*terminal_id_fn)(); + pointer env; + FILE *fp; +#endif +{ + long next; + hash_table h; + + if (!bdd_check_arguments(1, f)) + { + fprintf(fp, "overflow\n"); + return; + } + bdd_mark_shared_nodes(bddm, f); + h=bdd_new_hash_table(bddm, sizeof(long)); + next=0; + bdd_number_shared_nodes(bddm, f, h, &next); + cmu_bdd_print_bdd_step(bddm, f, var_naming_fn, terminal_id_fn, env, fp, h, 0); + cmu_bdd_free_hash_table(h); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddprprofile.c b/sis/bdd_cmu/bdd_cmu/bddprprofile.c new file mode 100644 index 0000000..bbb30d5 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddprprofile.c @@ -0,0 +1,239 @@ +/* BDD library profile printing routines */ + + +#include "bddint.h" + + +static char profile_width[]="XXXXXXXXX"; + + +static +void +#if defined(__STDC__) +chars(char c, int n, FILE *fp) +#else +chars(c, n, fp) + char c; + int n; + FILE *fp; +#endif +{ + int i; + + for (i=0; i < n; ++i) + fputc(c, fp); +} + + +/* cmu_bdd_print_profile_aux(bddm, level_counts, var_naming_fn, line_length, */ +/* env, fp) prints a profile to the file given by fp. The var_naming_fn */ +/* is as in cmu_bdd_print_bdd. line_length gives the line width to scale the */ +/* profile to. */ + +void +#if defined(__STDC__) +cmu_bdd_print_profile_aux(cmu_bdd_manager bddm, + long *level_counts, + char *(*var_naming_fn)(cmu_bdd_manager, bdd, pointer), + pointer env, + int line_length, + FILE *fp) +#else +cmu_bdd_print_profile_aux(bddm, level_counts, var_naming_fn, env, line_length, fp) + cmu_bdd_manager bddm; + long *level_counts; + char *(*var_naming_fn)(); + pointer env; + int line_length; + FILE *fp; +#endif +{ + long i, n; + int l; + char *name; + int max_prefix_len; + int max_profile_width; + int histogram_column; + int histogram_width; + int profile_scale; + long total; + + n=bddm->vars; + /* max_... initialized with values for leaf nodes */ + max_prefix_len=5; + max_profile_width=level_counts[n]; + total=level_counts[n]; + for (i=0; i < n; ++i) + if (level_counts[i]) + { + sprintf(profile_width, "%d", level_counts[i]); + l=strlen(bdd_var_name(bddm, bddm->variables[bddm->indexindexes[i]], var_naming_fn, env))+strlen(profile_width); + if (l > max_prefix_len) + max_prefix_len=l; + if (level_counts[i] > max_profile_width) + max_profile_width=level_counts[i]; + total+=level_counts[i]; + } + histogram_column=max_prefix_len+3; + histogram_width=line_length-histogram_column-1; + if (histogram_width < 20) + histogram_width=20; /* Random minimum width */ + if (histogram_width >= max_profile_width) + profile_scale=1; + else + profile_scale=(max_profile_width+histogram_width-1)/histogram_width; + for (i=0; i < n; ++i) + if (level_counts[i]) + { + name=bdd_var_name(bddm, bddm->variables[bddm->indexindexes[i]], var_naming_fn, env); + fputs(name, fp); + fputc(':', fp); + sprintf(profile_width, "%d", level_counts[i]); + chars(' ', (int)(max_prefix_len-strlen(name)-strlen(profile_width)+1), fp); + fputs(profile_width, fp); + fputc(' ', fp); + chars('#', level_counts[i]/profile_scale, fp); + fputc('\n', fp); + } + fputs("leaf:", fp); + sprintf(profile_width, "%d", level_counts[n]); + chars(' ', (int)(max_prefix_len-4-strlen(profile_width)+1), fp); + fputs(profile_width, fp); + fputc(' ', fp); + chars('#', level_counts[n]/profile_scale, fp); + fputc('\n', fp); + fprintf(fp, "Total: %d\n", total); +} + + +/* cmu_bdd_print_profile(bddm, f, var_naming_fn, env, line_length, fp) displays */ +/* the node profile for f on fp. line_length specifies the maximum line */ +/* length. var_naming_fn is as in cmu_bdd_print_bdd. */ + +void +#if defined(__STDC__) +cmu_bdd_print_profile(cmu_bdd_manager bddm, + bdd f, + char *(*var_naming_fn)(cmu_bdd_manager, bdd, pointer), + pointer env, + int line_length, + FILE *fp) +#else +cmu_bdd_print_profile(bddm, f, var_naming_fn, env, line_length, fp) + cmu_bdd_manager bddm; + bdd f; + char *(*var_naming_fn)(); + pointer env; + int line_length; + FILE *fp; +#endif +{ + long *level_counts; + + if (bdd_check_arguments(1, f)) + { + level_counts=(long *)mem_get_block((SIZE_T)((bddm->vars+1)*sizeof(long))); + cmu_bdd_profile(bddm, f, level_counts, 1); + cmu_bdd_print_profile_aux(bddm, level_counts, var_naming_fn, env, line_length, fp); + mem_free_block((pointer)level_counts); + } + else + fputs("overflow\n", fp); +} + + +/* cmu_bdd_print_profile_multiple is like cmu_bdd_print_profile except it displays */ +/* the profile for a set of BDDs. */ + +void +#if defined(__STDC__) +cmu_bdd_print_profile_multiple(cmu_bdd_manager bddm, + bdd* fs, + char *(*var_naming_fn)(cmu_bdd_manager, bdd, pointer), + pointer env, + int line_length, + FILE *fp) +#else +cmu_bdd_print_profile_multiple(bddm, fs, var_naming_fn, env, line_length, fp) + cmu_bdd_manager bddm; + bdd *fs; + char *(*var_naming_fn)(); + pointer env; + int line_length; + FILE *fp; +#endif +{ + long *level_counts; + + bdd_check_array(fs); + level_counts=(long *)mem_get_block((SIZE_T)((bddm->vars+1)*sizeof(long))); + cmu_bdd_profile_multiple(bddm, fs, level_counts, 1); + cmu_bdd_print_profile_aux(bddm, level_counts, var_naming_fn, env, line_length, fp); + mem_free_block((pointer)level_counts); +} + + +/* cmu_bdd_print_function_profile is like cmu_bdd_print_profile except it displays */ +/* a function profile for f. */ + +void +#if defined(__STDC__) +cmu_bdd_print_function_profile(cmu_bdd_manager bddm, + bdd f, + char *(*var_naming_fn)(cmu_bdd_manager, bdd, pointer), + pointer env, + int line_length, + FILE *fp) +#else +cmu_bdd_print_function_profile(bddm, f, var_naming_fn, env, line_length, fp) + cmu_bdd_manager bddm; + bdd f; + char *(*var_naming_fn)(); + pointer env; + int line_length; + FILE *fp; +#endif +{ + long *level_counts; + + if (bdd_check_arguments(1, f)) + { + level_counts=(long *)mem_get_block((SIZE_T)((bddm->vars+1)*sizeof(long))); + cmu_bdd_function_profile(bddm, f, level_counts); + cmu_bdd_print_profile_aux(bddm, level_counts, var_naming_fn, env, line_length, fp); + mem_free_block((pointer)level_counts); + } + else + fputs("overflow\n", fp); +} + + +/* cmu_bdd_print_function_profile_multiple is like cmu_bdd_print_function_profile */ +/* except for multiple BDDs. */ + +void +#if defined(__STDC__) +cmu_bdd_print_function_profile_multiple(cmu_bdd_manager bddm, + bdd* fs, + char *(*var_naming_fn)(cmu_bdd_manager, bdd, pointer), + pointer env, + int line_length, + FILE *fp) +#else +cmu_bdd_print_function_profile_multiple(bddm, fs, var_naming_fn, env, line_length, fp) + cmu_bdd_manager bddm; + bdd* fs; + char *(*var_naming_fn)(); + pointer env; + int line_length; + FILE *fp; +#endif +{ + long *level_counts; + + bdd_check_array(fs); + level_counts=(long *)mem_get_block((SIZE_T)((bddm->vars+1)*sizeof(long))); + cmu_bdd_function_profile_multiple(bddm, fs, level_counts); + cmu_bdd_print_profile_aux(bddm, level_counts, var_naming_fn, env, line_length, fp); + mem_free_block((pointer)level_counts); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddqnt.c b/sis/bdd_cmu/bdd_cmu/bddqnt.c new file mode 100644 index 0000000..982fab3 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddqnt.c @@ -0,0 +1,120 @@ +/* BDD quantification routines */ + + +#include "bddint.h" + + +static +bdd +#if defined(__STDC__) +cmu_bdd_exists_step(cmu_bdd_manager bddm, bdd f, long op, var_assoc vars) +#else +cmu_bdd_exists_step(bddm, f, op, vars) + cmu_bdd_manager bddm; + bdd f; + long op; + var_assoc vars; +#endif +{ + bdd temp1, temp2; + bdd result; + int quantifying; + + BDD_SETUP(f); + if ((long)BDD_INDEX(bddm, f) > vars->last) + { + BDD_TEMP_INCREFS(f); + return (f); + } + if (bdd_lookup_in_cache1(bddm, op, f, &result)) + return (result); + quantifying=(vars->assoc[BDD_INDEXINDEX(f)] != 0); + temp1=cmu_bdd_exists_step(bddm, BDD_THEN(f), op, vars); + if (quantifying && temp1 == BDD_ONE(bddm)) + result=temp1; + else + { + temp2=cmu_bdd_exists_step(bddm, BDD_ELSE(f), op, vars); + if (quantifying) + { + BDD_SETUP(temp1); + BDD_SETUP(temp2); + bddm->op_cache.cache_level++; + result=cmu_bdd_ite_step(bddm, temp1, BDD_ONE(bddm), temp2); + BDD_TEMP_DECREFS(temp1); + BDD_TEMP_DECREFS(temp2); + bddm->op_cache.cache_level--; + } + else + result=bdd_find(bddm, BDD_INDEXINDEX(f), temp1, temp2); + } + bdd_insert_in_cache1(bddm, op, f, result); + return (result); +} + + +/* cmu_bdd_exists_temp is used internally by cmu_bdd_rel_prod. */ + +bdd +#if defined(__STDC__) +cmu_bdd_exists_temp(cmu_bdd_manager bddm, bdd f, long op) +#else +cmu_bdd_exists_temp(bddm, f, op) + cmu_bdd_manager bddm; + bdd f; + long op; +#endif +{ + if (bddm->curr_assoc_id != -1) + op=OP_QNT+bddm->curr_assoc_id; + return (cmu_bdd_exists_step(bddm, f, op, bddm->curr_assoc)); +} + + +/* cmu_bdd_exists(bddm, f) returns the BDD for existentially quantifying */ +/* out in f all variables which are associated with something in the */ +/* current variable association. */ + +bdd +#if defined(__STDC__) +cmu_bdd_exists(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_exists(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + long op; + + if (bdd_check_arguments(1, f)) + { + FIREWALL(bddm); + if (bddm->curr_assoc_id == -1) + op=bddm->temp_op--; + else + op=OP_QNT+bddm->curr_assoc_id; + RETURN_BDD(cmu_bdd_exists_step(bddm, f, op, bddm->curr_assoc)); + } + return ((bdd)0); +} + + +/* cmu_bdd_forall(bddm, f) returns the BDD for universally quantifying */ +/* out in f all variables which are associated with something in the */ +/* current variable association. */ + +bdd +#if defined(__STDC__) +cmu_bdd_forall(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_forall(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + bdd temp; + + if ((temp=cmu_bdd_exists(bddm, BDD_NOT(f)))) + return (BDD_NOT(temp)); + return ((bdd)0); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddreduce.c b/sis/bdd_cmu/bdd_cmu/bddreduce.c new file mode 100644 index 0000000..2eabcad --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddreduce.c @@ -0,0 +1,169 @@ +/* BDD reduce routines */ + + +#include "bddint.h" + + +static +bdd +#if defined(__STDC__) +cmu_bdd_reduce_step(cmu_bdd_manager bddm, bdd f, bdd c) +#else +cmu_bdd_reduce_step(bddm, f, c) + cmu_bdd_manager bddm; + bdd f; + bdd c; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd c1, c2; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + BDD_SETUP(c); + if (BDD_IS_CONST(c)) + { + if (c == BDD_ZERO(bddm)) + return ((bdd)0); + BDD_TEMP_INCREFS(f); + return (f); + } + if (BDD_IS_CONST(f)) + return (f); + if (bdd_lookup_in_cache2(bddm, OP_RED, f, c, &result)) + return (result); + BDD_TOP_VAR2(top_indexindex, bddm, f, c); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, c, c1, c2); + if (f == f1) + { + bddm->op_cache.cache_level++; + temp1=cmu_bdd_ite_step(bddm, c1, BDD_ONE(bddm), c2); + bddm->op_cache.cache_level--; + result=cmu_bdd_reduce_step(bddm, f, temp1); + { + BDD_SETUP(temp1); + BDD_TEMP_DECREFS(temp1); + } + } + else + { + temp1=cmu_bdd_reduce_step(bddm, f1, c1); + temp2=cmu_bdd_reduce_step(bddm, f2, c2); + if (!temp1) + result=temp2; + else if (!temp2) + result=temp1; + else + result=bdd_find(bddm, top_indexindex, temp1, temp2); + } + bdd_insert_in_cache2(bddm, OP_RED, f, c, result); + return (result); +} + + +/* cmu_bdd_reduce(bddm, f, c) returns a BDD which agrees with f for all */ +/* valuations for which c is true, and which is hopefully smaller than */ +/* f. */ + +bdd +#if defined(__STDC__) +cmu_bdd_reduce(cmu_bdd_manager bddm, bdd f, bdd c) +#else +cmu_bdd_reduce(bddm, f, c) + cmu_bdd_manager bddm; + bdd f; + bdd c; +#endif +{ + bdd result; + + if (bdd_check_arguments(2, f, c)) + { + FIREWALL(bddm); + result=cmu_bdd_reduce_step(bddm, f, c); + if (!result) + return (BDD_ZERO(bddm)); + RETURN_BDD(result); + } + return ((bdd)0); +} + + +static +bdd +#if defined(__STDC__) +cmu_bdd_cofactor_step(cmu_bdd_manager bddm, bdd f, bdd c) +#else +cmu_bdd_cofactor_step(bddm, f, c) + cmu_bdd_manager bddm; + bdd f; + bdd c; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd c1, c2; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + BDD_SETUP(c); + if (BDD_IS_CONST(c)) + { + if (c == BDD_ZERO(bddm)) + return ((bdd)0); + BDD_TEMP_INCREFS(f); + return (f); + } + if (BDD_IS_CONST(f)) + return (f); + if (bdd_lookup_in_cache2(bddm, OP_COFACTOR, f, c, &result)) + return (result); + BDD_TOP_VAR2(top_indexindex, bddm, f, c); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, c, c1, c2); + temp1=cmu_bdd_cofactor_step(bddm, f1, c1); + temp2=cmu_bdd_cofactor_step(bddm, f2, c2); + if (!temp1) + result=temp2; + else if (!temp2) + result=temp1; + else + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache2(bddm, OP_COFACTOR, f, c, result); + return (result); +} + + +/* cmu_bdd_cofactor(bddm, f, c) returns a BDD for the generalized cofactor */ +/* of f by c. This operation has the useful property that if */ +/* [f1, ..., fn] is a function vector and fi|c denotes the g.c. of fi */ +/* by c, then the image of [f1|c, ..., fn|c] over all valuations is */ +/* the same as the image of [f1, ..., fn] over the valuations for */ +/* which c is true. */ + +bdd +#if defined(__STDC__) +cmu_bdd_cofactor(cmu_bdd_manager bddm, bdd f, bdd c) +#else +cmu_bdd_cofactor(bddm, f, c) + cmu_bdd_manager bddm; + bdd f; + bdd c; +#endif +{ + if (bdd_check_arguments(2, f, c)) + { + if (c == BDD_ZERO(bddm)) + { + cmu_bdd_warning("cmu_bdd_cofactor: second argument is false"); + return (BDD_ONE(bddm)); + } + FIREWALL(bddm); + RETURN_BDD(cmu_bdd_cofactor_step(bddm, f, c)); + } + return ((bdd)0); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddrelprod.c b/sis/bdd_cmu/bdd_cmu/bddrelprod.c new file mode 100644 index 0000000..dc40dee --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddrelprod.c @@ -0,0 +1,106 @@ +/* BDD relational product routine */ + + +#include "bddint.h" + + +static +bdd +#if defined(__STDC__) +cmu_bdd_rel_prod_step(cmu_bdd_manager bddm, bdd f, bdd g, long op, var_assoc vars) +#else +cmu_bdd_rel_prod_step(bddm, f, g, op, vars) + cmu_bdd_manager bddm; + bdd f; + bdd g; + long op; + var_assoc vars; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd temp1, temp2; + bdd result; + int quantifying; + + BDD_SETUP(f); + BDD_SETUP(g); + if (BDD_IS_CONST(f) || BDD_IS_CONST(g)) + { + if (f == BDD_ZERO(bddm) || g == BDD_ZERO(bddm)) + return (BDD_ZERO(bddm)); + if (f == BDD_ONE(bddm)) + return (cmu_bdd_exists_temp(bddm, g, op-1)); + return (cmu_bdd_exists_temp(bddm, f, op-1)); + } + if ((long)BDD_INDEX(bddm, f) > vars->last && (long)BDD_INDEX(bddm, g) > vars->last) + return (cmu_bdd_ite_step(bddm, f, g, BDD_ZERO(bddm))); + /* Put in canonical order. */ + if (BDD_OUT_OF_ORDER(f, g)) + BDD_SWAP(f, g); + if (bdd_lookup_in_cache2(bddm, op, f, g, &result)) + return (result); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + quantifying=(vars->assoc[top_indexindex] != 0); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + temp1=cmu_bdd_rel_prod_step(bddm, f1, g1, op, vars); + if (quantifying && temp1 == BDD_ONE(bddm)) + result=temp1; + else + { + temp2=cmu_bdd_rel_prod_step(bddm, f2, g2, op, vars); + if (quantifying) + { + BDD_SETUP(temp1); + BDD_SETUP(temp2); + bddm->op_cache.cache_level++; + result=cmu_bdd_ite_step(bddm, temp1, BDD_ONE(bddm), temp2); + BDD_TEMP_DECREFS(temp1); + BDD_TEMP_DECREFS(temp2); + bddm->op_cache.cache_level--; + } + else + result=bdd_find(bddm, top_indexindex, temp1, temp2); + } + bdd_insert_in_cache2(bddm, op, f, g, result); + return (result); +} + + +/* cmu_bdd_rel_prod(bddm, f, g) returns the BDD for "f and g" with those */ +/* variables which are associated with something in the current */ +/* variable association quantified out. */ + +bdd +#if defined(__STDC__) +cmu_bdd_rel_prod(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_bdd_rel_prod(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + long op; + + if (bdd_check_arguments(2, f, g)) + { + FIREWALL(bddm); + if (bddm->curr_assoc_id == -1) + { + op=bddm->temp_op--; + /* We decrement the temporary opcode once more because */ + /* cmu_bdd_rel_prod may call cmu_bdd_exists_temp, and we don't */ + /* want to generate new temporary opcodes for each such */ + /* call. Instead, we pass op-1 to cmu_bdd_exists_temp, and */ + /* have it use this opcode for caching. */ + bddm->temp_op--; + } + else + op=OP_RELPROD+bddm->curr_assoc_id; + RETURN_BDD(cmu_bdd_rel_prod_step(bddm, f, g, op, bddm->curr_assoc)); + } + return ((bdd)0); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddreorder.c b/sis/bdd_cmu/bdd_cmu/bddreorder.c new file mode 100644 index 0000000..9ecba6e --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddreorder.c @@ -0,0 +1,835 @@ +/* BDD dynamic reordering stuff */ + + +#include "bddint.h" + + +static +void +#if defined(__STDC__) +increfs(bdd f) +#else +increfs(f) + bdd f; +#endif +{ + bdd g; + + BDD_SETUP(f); + BDD_INCREFS(f); + if (BDD_REFS(f) == 1 && !BDD_TEMP_REFS(f)) + { + g=(bdd)BDD_DATA0(f); + { + BDD_SETUP(g); + BDD_INCREFS(g); + } + g=(bdd)BDD_DATA1(f); + { + BDD_SETUP(g); + BDD_INCREFS(g); + } + } +} + + +static +void +#if defined(__STDC__) +decrefs(bdd f) +#else +decrefs(f) + bdd f; +#endif +{ + bdd g; + + BDD_SETUP(f); + BDD_DECREFS(f); + if (!BDD_REFS(f) && !BDD_TEMP_REFS(f)) + { + g=(bdd)BDD_DATA0(f); + { + BDD_SETUP(g); + BDD_DECREFS(g); + } + g=(bdd)BDD_DATA1(f); + { + BDD_SETUP(g); + BDD_DECREFS(g); + } + } +} + + +static +void +#if defined(__STDC__) +bdd_exchange_aux(cmu_bdd_manager bddm, bdd f, bdd_indexindex_type next_indexindex) +#else +bdd_exchange_aux(bddm, f, next_indexindex) + cmu_bdd_manager bddm; + bdd f; + bdd_indexindex_type next_indexindex; +#endif +{ + bdd f1, f2; + bdd f11, f12, f21, f22; + bdd temp1, temp2; + + BDD_SETUP(f); + f1=BDD_THEN(f); + f2=BDD_ELSE(f); + { + BDD_SETUP(f1); + BDD_SETUP(f2); + if (BDD_INDEXINDEX(f1) == next_indexindex) + { + f11=BDD_THEN(f1); + f12=BDD_ELSE(f1); + } + else + { + f11=f1; + f12=f1; + } + if (BDD_INDEXINDEX(f2) == next_indexindex) + { + f21=BDD_THEN(f2); + f22=BDD_ELSE(f2); + } + else + { + f21=f2; + f22=f2; + } + if (f11 == f21) + temp1=f11; + else + temp1=bdd_find_aux(bddm, BDD_INDEXINDEX(f), (INT_PTR)f11, (INT_PTR)f21); + if (f12 == f22) + temp2=f12; + else if (BDD_IS_OUTPOS(f12)) + temp2=bdd_find_aux(bddm, BDD_INDEXINDEX(f), (INT_PTR)f12, (INT_PTR)f22); + else + temp2=BDD_NOT(bdd_find_aux(bddm, BDD_INDEXINDEX(f), (INT_PTR)BDD_NOT(f12), (INT_PTR)BDD_NOT(f22))); + BDD_INDEXINDEX(f)=next_indexindex; + BDD_DATA0(f)=(INT_PTR)temp1; + BDD_DATA1(f)=(INT_PTR)temp2; + if (BDD_REFS(f) || BDD_TEMP_REFS(f)) + { + increfs(temp1); + increfs(temp2); + decrefs(f1); + decrefs(f2); + } + else + cmu_bdd_fatal("bdd_exchange_aux: how did this happen?"); + } +} + + +static +void +#if defined(__STDC__) +fixup_assoc(cmu_bdd_manager bddm, long indexindex1, long indexindex2, var_assoc va) +#else +fixup_assoc(bddm, indexindex1, indexindex2, va) + cmu_bdd_manager bddm; + long indexindex1; + long indexindex2; + var_assoc va; +#endif +{ + /* Variable with indexindex1 is moving down a spot. */ + if (va->assoc[indexindex1] && va->last == bddm->indexes[indexindex1]) + va->last++; + else if (!va->assoc[indexindex1] && va->assoc[indexindex2] && va->last == bddm->indexes[indexindex2]) + va->last--; +} + + +static +void +#if defined(__STDC__) +sweep_var_table(cmu_bdd_manager bddm, long i) +#else +sweep_var_table(bddm, i) + cmu_bdd_manager bddm; + long i; +#endif +{ + long j; + var_table table; + bdd f, *p; + + table=bddm->unique_table.tables[i]; + for (j=0; j < table->size; ++j) + for (p= &table->table[j], f= *p; f; f= *p) + { + BDD_SETUP(f); + if (BDD_REFS(f) || BDD_TEMP_REFS(f)) + p= &f->next; + else + { + *p=f->next; + BDD_FREE_REC(bddm, (pointer)f, sizeof(struct bdd_)); + table->entries--; + bddm->unique_table.entries--; + bddm->unique_table.freed++; + } + } +} + + +static +void +#if defined(__STDC__) +bdd_exchange(cmu_bdd_manager bddm, long i) +#else +bdd_exchange(bddm, i) + cmu_bdd_manager bddm; + long i; +#endif +{ + bdd_indexindex_type next_indexindex; + var_table table, next_table; + long j; + bdd f, *p; + bdd f1, f2; + bdd g; + long hash; + bdd_index_type temp; + assoc_list q; + + next_indexindex=bddm->indexindexes[bddm->indexes[i]+1]; + table=bddm->unique_table.tables[i]; + next_table=bddm->unique_table.tables[next_indexindex]; + g=0; + for (j=0; j < table->size; ++j) + for (p= &table->table[j], f= *p; f; f= *p) + { + BDD_SETUP(f); + if (BDD_REFS(f) || BDD_TEMP_REFS(f)) + { + f1=(bdd)BDD_DATA0(f); + f2=(bdd)BDD_DATA1(f); + { + BDD_SETUP(f1); + BDD_SETUP(f2); + if (BDD_INDEXINDEX(f1) != next_indexindex && BDD_INDEXINDEX(f2) != next_indexindex) + p= &f->next; + else + { + *p=f->next; + f->next=g; + g=f; + } + } + } + else + { + *p=f->next; + BDD_FREE_REC(bddm, (pointer)f, sizeof(struct bdd_)); + table->entries--; + bddm->unique_table.entries--; + bddm->unique_table.freed++; + } + } + for (f=g; f; f=g) + { + bdd_exchange_aux(bddm, f, next_indexindex); + g=f->next; + hash=HASH_NODE(f->data[0], f->data[1]); + BDD_REDUCE(hash, next_table->size); + f->next=next_table->table[hash]; + next_table->table[hash]=f; + table->entries--; + next_table->entries++; + if (4*next_table->size < next_table->entries) + bdd_rehash_var_table(next_table, 1); + } + fixup_assoc(bddm, i, next_indexindex, &bddm->temp_assoc); + for (q=bddm->assocs; q; q=q->next) + fixup_assoc(bddm, i, next_indexindex, &q->va); + sweep_var_table(bddm, next_indexindex); + temp=bddm->indexes[i]; + bddm->indexes[i]=bddm->indexes[next_indexindex]; + bddm->indexes[next_indexindex]=temp; + bddm->indexindexes[temp]=next_indexindex; + bddm->indexindexes[bddm->indexes[i]]=i; +} + + +void +#if defined(__STDC__) +cmu_bdd_var_block_reorderable(cmu_bdd_manager bddm, block b, int reorderable) +#else +cmu_bdd_var_block_reorderable(bddm, b, reorderable) + cmu_bdd_manager bddm; + block b; + int reorderable; +#endif +{ + b->reorderable=reorderable; +} + + +static +void +#if defined(__STDC__) +bdd_exchange_var_blocks(cmu_bdd_manager bddm, block parent, long bi) +#else +bdd_exchange_var_blocks(bddm, parent, bi) + cmu_bdd_manager bddm; + block parent; + long bi; +#endif +{ + block b1, b2; + long i, j, k, l; + long delta; + block temp; + + b1=parent->children[bi]; + b2=parent->children[bi+1]; + /* This slides the blocks past each other in a kind of interleaving */ + /* fashion. */ + for (i=0; i <= b1->last_index-b1->first_index+b2->last_index-b2->first_index; ++i) + { + j=i-b1->last_index+b1->first_index; + if (j < 0) + j=0; + k=i; + if (k > b2->last_index-b2->first_index) + k=b2->last_index-b2->first_index; + while (j <= k) + { + l=b2->first_index+j-i+j; + bdd_exchange(bddm, bddm->indexindexes[l-1]); + ++j; + } + } + delta=b2->last_index-b2->first_index+1; + bdd_block_delta(b1, delta); + delta=b1->last_index-b1->first_index+1; + bdd_block_delta(b2, -delta); + temp=parent->children[bi]; + parent->children[bi]=parent->children[bi+1]; + parent->children[bi+1]=temp; +} + + +static +int +#if defined(__STDC__) +cmu_bdd_reorder_window2(cmu_bdd_manager bddm, block b, long i) +#else +cmu_bdd_reorder_window2(bddm, b, i) + cmu_bdd_manager bddm; + block b; + long i; +#endif +{ + long size, best_size; + + /* 1 2 */ + best_size=bddm->unique_table.entries; + bdd_exchange_var_blocks(bddm, b, i); + /* 2 1 */ + size=bddm->unique_table.entries; + if (size < best_size) + return (1); + bdd_exchange_var_blocks(bddm, b, i); + return (0); +} + + +static +int +#if defined(__STDC__) +cmu_bdd_reorder_window3(cmu_bdd_manager bddm, block b, long i) +#else +cmu_bdd_reorder_window3(bddm, b, i) + cmu_bdd_manager bddm; + block b; + long i; +#endif +{ + int best; + long size, best_size; + + best=0; + /* 1 2 3 */ + best_size=bddm->unique_table.entries; + bdd_exchange_var_blocks(bddm, b, i); + /* 2 1 3 */ + size=bddm->unique_table.entries; + if (size < best_size) + { + best=1; + best_size=size; + } + bdd_exchange_var_blocks(bddm, b, i+1); + /* 2 3 1 */ + size=bddm->unique_table.entries; + if (size < best_size) + { + best=2; + best_size=size; + } + bdd_exchange_var_blocks(bddm, b, i); + /* 3 2 1 */ + size=bddm->unique_table.entries; + if (size < best_size) + { + best=3; + best_size=size; + } + bdd_exchange_var_blocks(bddm, b, i+1); + /* 3 1 2 */ + size=bddm->unique_table.entries; + if (size < best_size) + { + best=4; + best_size=size; + } + bdd_exchange_var_blocks(bddm, b, i); + /* 1 3 2 */ + size=bddm->unique_table.entries; + if (size < best_size) + { + best=5; + best_size=size; + } + switch (best) + { + case 0: + bdd_exchange_var_blocks(bddm, b, i+1); + break; + case 1: + bdd_exchange_var_blocks(bddm, b, i+1); + bdd_exchange_var_blocks(bddm, b, i); + break; + case 2: + bdd_exchange_var_blocks(bddm, b, i+1); + bdd_exchange_var_blocks(bddm, b, i); + bdd_exchange_var_blocks(bddm, b, i+1); + break; + case 3: + bdd_exchange_var_blocks(bddm, b, i); + bdd_exchange_var_blocks(bddm, b, i+1); + break; + case 4: + bdd_exchange_var_blocks(bddm, b, i); + break; + case 5: + break; + } + return (best > 0); +} + + +static +void +#if defined(__STDC__) +cmu_bdd_reorder_stable_window3_aux(cmu_bdd_manager bddm, block b, char *levels) +#else +cmu_bdd_reorder_stable_window3_aux(bddm, b, levels) + cmu_bdd_manager bddm; + block b; + char *levels; +#endif +{ + long i; + int moved; + int any_swapped; + + if (b->reorderable) + { + for (i=0; i < b->num_children-1; ++i) + levels[i]=1; + do + { + any_swapped=0; + for (i=0; i < b->num_children-1; ++i) + if (levels[i]) + { + if (i < b->num_children-2) + moved=cmu_bdd_reorder_window3(bddm, b, i); + else + moved=cmu_bdd_reorder_window2(bddm, b, i); + if (moved) + { + if (i > 0) + { + levels[i-1]=1; + if (i > 1) + levels[i-2]=1; + } + levels[i]=1; + levels[i+1]=1; + if (i < b->num_children-2) + { + levels[i+2]=1; + if (i < b->num_children-3) + { + levels[i+3]=1; + if (i < b->num_children-4) + levels[i+4]=1; + } + } + any_swapped=1; + } + else + levels[i]=0; + } + } + while (any_swapped); + } + for (i=0; i < b->num_children; ++i) + cmu_bdd_reorder_stable_window3_aux(bddm, b->children[i], levels); +} + + +void +#if defined(__STDC__) +cmu_bdd_reorder_stable_window3(cmu_bdd_manager bddm) +#else +cmu_bdd_reorder_stable_window3(bddm) + cmu_bdd_manager bddm; +#endif +{ + char *levels; + + levels=(char *)mem_get_block(bddm->vars*sizeof(char)); + cmu_bdd_reorder_stable_window3_aux(bddm, bddm->super_block, levels); + mem_free_block((pointer)levels); +} + + +static +void +#if defined(__STDC__) +bdd_sift_block(cmu_bdd_manager bddm, block b, long start_pos, double max_size_factor) +#else +bdd_sift_block(bddm, b, start_pos, max_size_factor) + cmu_bdd_manager bddm; + block b; + long start_pos; + double max_size_factor; +#endif +{ + long start_size; + long best_size; + long best_pos; + long curr_size; + long curr_pos; + long max_size; + + start_size=bddm->unique_table.entries; + best_size=start_size; + best_pos=start_pos; + curr_size=start_size; + curr_pos=start_pos; + max_size=max_size_factor*start_size; + if (bddm->unique_table.node_limit && max_size > bddm->unique_table.node_limit) + max_size=bddm->unique_table.node_limit; + while (curr_pos < b->num_children-1 && curr_size <= max_size) + { + bdd_exchange_var_blocks(bddm, b, curr_pos); + ++curr_pos; + curr_size=bddm->unique_table.entries; + if (curr_size < best_size) + { + best_size=curr_size; + best_pos=curr_pos; + } + } + while (curr_pos != start_pos) + { + --curr_pos; + bdd_exchange_var_blocks(bddm, b, curr_pos); + } + curr_size=start_size; + while (curr_pos && curr_size <= max_size) + { + --curr_pos; + bdd_exchange_var_blocks(bddm, b, curr_pos); + curr_size=bddm->unique_table.entries; + if (curr_size < best_size) + { + best_size=curr_size; + best_pos=curr_pos; + } + } + while (curr_pos != best_pos) + { + bdd_exchange_var_blocks(bddm, b, curr_pos); + ++curr_pos; + } +} + + +static +void +#if defined(__STDC__) +cmu_bdd_reorder_sift_aux(cmu_bdd_manager bddm, block b, block *to_sift, double max_size_factor) +#else +cmu_bdd_reorder_sift_aux(bddm, b, to_sift, max_size_factor) + cmu_bdd_manager bddm; + block b; + block *to_sift; + double max_size_factor; +#endif +{ + long i, j, k; + long w; + long max_w; + long widest; + + if (b->reorderable) + { + for (i=0; i < b->num_children; ++i) + to_sift[i]=b->children[i]; + while (i) + { + --i; + max_w=0; + widest=0; + for (j=0; j <= i; ++j) + { + for (w=0, k=to_sift[j]->first_index; k <= to_sift[j]->last_index; ++k) + w+=bddm->unique_table.tables[bddm->indexindexes[k]]->entries; + w/=to_sift[j]->last_index-to_sift[j]->first_index+1; + if (w > max_w) + { + max_w=w; + widest=j; + } + } + if (max_w > 1) + { + for (j=0; b->children[j] != to_sift[widest]; ++j); + bdd_sift_block(bddm, b, j, max_size_factor); + to_sift[widest]=to_sift[i]; + } + else + break; + } + } + for (i=0; i < b->num_children; ++i) + cmu_bdd_reorder_sift_aux(bddm, b->children[i], to_sift, max_size_factor); +} + + +static +void +#if defined(__STDC__) +cmu_bdd_reorder_sift_aux1(cmu_bdd_manager bddm, double max_size_factor) +#else +cmu_bdd_reorder_sift_aux1(bddm, max_size_factor) + cmu_bdd_manager bddm; + double max_size_factor; +#endif +{ + block *to_sift; + + to_sift=(block *)mem_get_block(bddm->vars*sizeof(block)); + cmu_bdd_reorder_sift_aux(bddm, bddm->super_block, to_sift, max_size_factor); + mem_free_block((pointer)to_sift); +} + + +void +#if defined(__STDC__) +cmu_bdd_reorder_sift(cmu_bdd_manager bddm) +#else +cmu_bdd_reorder_sift(bddm) + cmu_bdd_manager bddm; +#endif +{ + cmu_bdd_reorder_sift_aux1(bddm, 2.0); +} + + +void +#if defined(__STDC__) +cmu_bdd_reorder_hybrid(cmu_bdd_manager bddm) +#else +cmu_bdd_reorder_hybrid(bddm) + cmu_bdd_manager bddm; +#endif +{ + long nodes; + double max_size_factor; + + nodes=bddm->unique_table.entries; + max_size_factor= *(double *)bddm->reorder_data; + if (max_size_factor > 2.0 || nodes < 10000) + max_size_factor=2.0; + cmu_bdd_reorder_sift_aux1(bddm, max_size_factor); + *(double *)bddm->reorder_data=1.0+(2.0*(nodes-bddm->unique_table.entries))/nodes; +} + + +/* cmu_bdd_dynamic_reordering(bddm, reorder_fn) sets the dynamic reordering */ +/* method to that specified by reorder_fn. */ + +void +#if defined(__STDC__) +cmu_bdd_dynamic_reordering(cmu_bdd_manager bddm, void (*reorder_fn)(cmu_bdd_manager)) +#else +cmu_bdd_dynamic_reordering(bddm, reorder_fn) + cmu_bdd_manager bddm; + void (*reorder_fn)(); +#endif +{ + bddm->reorder_fn=reorder_fn; + if (bddm->reorder_data) + mem_free_block(bddm->reorder_data); + bddm->reorder_data=0; + if (reorder_fn == cmu_bdd_reorder_hybrid) + { + bddm->reorder_data=mem_get_block((SIZE_T)sizeof(double)); + *(double *)bddm->reorder_data=2.0; + } +} + + +static +void +#if defined(__STDC__) +bdd_add_internal_references(cmu_bdd_manager bddm) +#else +bdd_add_internal_references(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i, j; + var_table table; + bdd *f, g, h; + + for (i=0; i <= bddm->vars; ++i) + { + if (i == bddm->vars) + table=bddm->unique_table.tables[BDD_CONST_INDEXINDEX]; + else + table=bddm->unique_table.tables[bddm->indexindexes[i]]; + for (j=0; j < table->size; ++j) + { + f= &table->table[j]; + while ((g= *f)) + { + BDD_SETUP(g); + if (BDD_REFS(g) || BDD_TEMP_REFS(g)) + { + if (!BDD_IS_CONST(g)) + { + h=(bdd)BDD_DATA0(g); + { + BDD_SETUP(h); + BDD_INCREFS(h); + } + h=(bdd)BDD_DATA1(g); + { + BDD_SETUP(h); + BDD_INCREFS(h); + } + } + f= &g->next; + } + else + { + *f=g->next; + if (i == bddm->vars && bddm->unique_table.free_terminal_fn) + (*bddm->unique_table.free_terminal_fn)(bddm, + BDD_DATA0(g), + BDD_DATA1(g), + bddm->unique_table.free_terminal_env); + BDD_FREE_REC(bddm, (pointer)g, sizeof(struct bdd_)); + table->entries--; + bddm->unique_table.entries--; + bddm->unique_table.freed++; + } + } + } + } +} + + +static +void +#if defined(__STDC__) +bdd_nuke_internal_references(cmu_bdd_manager bddm) +#else +bdd_nuke_internal_references(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i, j; + var_table table; + bdd *f, g, h; + + for (i=bddm->vars-1; i >= 0; --i) + { + table=bddm->unique_table.tables[bddm->indexindexes[i]]; + for (j=0; j < table->size; ++j) + { + f= &table->table[j]; + while ((g= *f)) + { + BDD_SETUP(g); + if (BDD_REFS(g) || BDD_TEMP_REFS(g)) + { + h=(bdd)BDD_DATA0(g); + { + BDD_SETUP(h); + BDD_DECREFS(h); + } + h=(bdd)BDD_DATA1(g); + { + BDD_SETUP(h); + BDD_DECREFS(h); + } + f= &g->next; + } + else + cmu_bdd_fatal("bdd_nuke_internal_references: what happened?"); + } + } + } +} + + +void +#if defined(__STDC__) +cmu_bdd_reorder_aux(cmu_bdd_manager bddm) +#else +cmu_bdd_reorder_aux(bddm) + cmu_bdd_manager bddm; +#endif +{ + if (bddm->reorder_fn) + { + bdd_flush_all(bddm); + bdd_add_internal_references(bddm); + (*bddm->reorder_fn)(bddm); + bdd_nuke_internal_references(bddm); + } +} + + +/* cmu_bdd_reorder(bddm) invokes the current dynamic reordering method. */ + +void +#if defined(__STDC__) +cmu_bdd_reorder(cmu_bdd_manager bddm) +#else +cmu_bdd_reorder(bddm) + cmu_bdd_manager bddm; +#endif +{ + cmu_bdd_gc(bddm); + cmu_bdd_reorder_aux(bddm); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddsat.c b/sis/bdd_cmu/bdd_cmu/bddsat.c new file mode 100644 index 0000000..dc7ce72 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddsat.c @@ -0,0 +1,237 @@ +/* BDD satisfying valuation routines */ + + +#include "bddint.h" + + +#if defined(__STDC__) +extern void qsort(pointer, unsigned, int, int (*)(pointer, pointer)); +#else +extern void qsort(); +#endif + + +static +bdd +#if defined(__STDC__) +cmu_bdd_satisfy_step(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_satisfy_step(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + bdd temp; + bdd result; + + BDD_SETUP(f); + if (BDD_IS_CONST(f)) + return (f); + if (BDD_THEN(f) == BDD_ZERO(bddm)) + { + temp=cmu_bdd_satisfy_step(bddm, BDD_ELSE(f)); + result=bdd_find(bddm, BDD_INDEXINDEX(f), BDD_ZERO(bddm), temp); + } + else + { + temp=cmu_bdd_satisfy_step(bddm, BDD_THEN(f)); + result=bdd_find(bddm, BDD_INDEXINDEX(f), temp, BDD_ZERO(bddm)); + } + return (result); +} + + +/* cmu_bdd_satisfy(bddm, f) returns a BDD which implies f, is true for */ +/* some valuation on which f is true, and which has at most one node */ +/* at each level. */ + +bdd +#if defined(__STDC__) +cmu_bdd_satisfy(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_satisfy(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (bdd_check_arguments(1, f)) + { + if (f == BDD_ZERO(bddm)) + { + cmu_bdd_warning("cmu_bdd_satisfy: argument is false"); + return (f); + } + FIREWALL(bddm); + RETURN_BDD(cmu_bdd_satisfy_step(bddm, f)); + } + return ((bdd)0); +} + + +static +bdd +#if defined(__STDC__) +cmu_bdd_satisfy_support_step(cmu_bdd_manager bddm, bdd f, bdd_indexindex_type *support) +#else +cmu_bdd_satisfy_support_step(bddm, f, support) + cmu_bdd_manager bddm; + bdd f; + bdd_indexindex_type *support; +#endif +{ + bdd temp; + bdd result; + + BDD_SETUP(f); + if (!*support) + return (cmu_bdd_satisfy_step(bddm, f)); + if (BDD_INDEX(bddm, f) <= bddm->indexes[*support]) + { + if (BDD_INDEXINDEX(f) == *support) + ++support; + if (BDD_THEN(f) == BDD_ZERO(bddm)) + { + temp=cmu_bdd_satisfy_support_step(bddm, BDD_ELSE(f), support); + result=bdd_find(bddm, BDD_INDEXINDEX(f), BDD_ZERO(bddm), temp); + } + else + { + temp=cmu_bdd_satisfy_support_step(bddm, BDD_THEN(f), support); + result=bdd_find(bddm, BDD_INDEXINDEX(f), temp, BDD_ZERO(bddm)); + } + } + else + { + temp=cmu_bdd_satisfy_support_step(bddm, f, support+1); + result=bdd_find(bddm, *support, BDD_ZERO(bddm), temp); + } + return (result); +} + + +static +int +#if defined(__STDC__) +index_cmp(pointer p1, pointer p2) +#else +index_cmp(p1, p2) + pointer p1; + pointer p2; +#endif +{ + bdd_index_type i1, i2; + + i1= *(bdd_indexindex_type *)p1; + i2= *(bdd_indexindex_type *)p2; + if (i1 < i2) + return (-1); + if (i1 > i2) + return (1); + return (0); +} + + +/* cmu_bdd_satisfy_support(bddm, f) returns a BDD which implies f, is true */ +/* for some valuation on which f is true, which has at most one node */ +/* at each level, and which has exactly one node corresponding to each */ +/* variable which is associated with something in the current variable */ +/* association. */ + +bdd +#if defined(__STDC__) +cmu_bdd_satisfy_support(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_satisfy_support(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + bdd_indexindex_type *support, *p; + long i; + bdd result; + + if (bdd_check_arguments(1, f)) + { + if (f == BDD_ZERO(bddm)) + { + cmu_bdd_warning("cmu_bdd_satisfy_support: argument is false"); + return (f); + } + support=(bdd_indexindex_type *)mem_get_block((bddm->vars+1)*sizeof(bdd)); + FIREWALL1(bddm, + if (retcode == BDD_ABORTED || retcode == BDD_OVERFLOWED) + { + mem_free_block((pointer)support); + return ((bdd)0); + } + ); + for (i=0, p=support; i < bddm->vars; ++i) + if (bddm->curr_assoc->assoc[i+1]) + { + *p=bddm->indexes[i+1]; + ++p; + } + *p=0; + qsort((pointer)support, (unsigned)(p-support), sizeof(bdd_indexindex_type), index_cmp); + while (p != support) + { + --p; + *p=bddm->indexindexes[*p]; + } + result=cmu_bdd_satisfy_support_step(bddm, f, support); + mem_free_block((pointer)support); + RETURN_BDD(result); + } + return ((bdd)0); +} + + +double +#if defined(__STDC__) +cmu_bdd_satisfying_fraction_step(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_satisfying_fraction_step(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + long cache_result[2]; + double result; + + BDD_SETUP(f); + if (BDD_IS_CONST(f)) + { + if (f == BDD_ZERO(bddm)) + return (0.0); + return (1.0); + } + if (bdd_lookup_in_cache1d(bddm, OP_SATFRAC, f, &cache_result[0], &cache_result[1])) + { + result= *((double *)cache_result); + return (result); + } + result=0.5*cmu_bdd_satisfying_fraction_step(bddm, BDD_THEN(f))+ + 0.5*cmu_bdd_satisfying_fraction_step(bddm, BDD_ELSE(f)); + *((double *)cache_result)=result; + bdd_insert_in_cache1d(bddm, OP_SATFRAC, f, cache_result[0], cache_result[1]); + return (result); +} + + +/* cmu_bdd_satisfying_fraction(bddm, f) returns the fraction of valuations */ +/* which make f true. (Note that this fraction is independent of */ +/* whatever set of variables f is supposed to be a function of.) */ + +double +#if defined(__STDC__) +cmu_bdd_satisfying_fraction(cmu_bdd_manager bddm, bdd f) +#else +cmu_bdd_satisfying_fraction(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + if (bdd_check_arguments(1, f)) + return (cmu_bdd_satisfying_fraction_step(bddm, f)); + return (0.0); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddsize.c b/sis/bdd_cmu/bdd_cmu/bddsize.c new file mode 100644 index 0000000..86e2e13 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddsize.c @@ -0,0 +1,437 @@ +/* BDD size and profile routines */ + + +#include "bddint.h" + + +static +void +#if defined(__STDC__) +bdd_mark_bdd(bdd f) +#else +bdd_mark_bdd(f) + bdd f; +#endif +{ + int curr_marking, this_marking; + + BDD_SETUP(f); + curr_marking=BDD_MARK(f); + this_marking=(1 << TAG(f)); + if (curr_marking & this_marking) + return; + BDD_MARK(f)=curr_marking | this_marking; + if (BDD_IS_CONST(f)) + return; + bdd_mark_bdd(BDD_THEN(f)); + bdd_mark_bdd(BDD_ELSE(f)); +} + + +static +int +#if defined(__STDC__) +bdd_count_no_nodes(bdd f) +#else +bdd_count_no_nodes(f) + bdd f; +#endif +{ + BDD_SETUP(f); + return (BDD_MARK(f) > 0); +} + + +static +int +#if defined(__STDC__) +bdd_count_nodes(bdd f) +#else +bdd_count_nodes(f) + bdd f; +#endif +{ + int mark; + + BDD_SETUP(f); + mark=BDD_MARK(f); + return (((mark & 0x1) != 0)+((mark & 0x2) != 0)); +} + + +static +#if defined(__STDC__) +int (*(counting_fns[]))(bdd)= +#else +int (*(counting_fns[]))()= +#endif +{ + bdd_count_no_nodes, + bdd_count_nodes, +}; + + +static +long +#if defined(__STDC__) +cmu_bdd_size_step(bdd f, int (*count_fn)(bdd)) +#else +cmu_bdd_size_step(f, count_fn) + bdd f; + int (*count_fn)(); +#endif +{ + long result; + + BDD_SETUP(f); + if (!BDD_MARK(f)) + return (0l); + result=(*count_fn)(f); + if (!BDD_IS_CONST(f)) + result+=cmu_bdd_size_step(BDD_THEN(f), count_fn)+cmu_bdd_size_step(BDD_ELSE(f), count_fn); + BDD_MARK(f)=0; + return (result); +} + + +/* cmu_bdd_size(bddm, f, negout) returns the number of nodes in f when */ +/* negout is nonzero. If negout is zero, we pretend that the BDDs */ +/* don't have negative-output pointers. */ + +long +#if defined(__STDC__) +cmu_bdd_size(cmu_bdd_manager bddm, bdd f, int negout) +#else +cmu_bdd_size(bddm, f, negout) + cmu_bdd_manager bddm; + bdd f; + int negout; +#endif +{ + bdd g; + + if (bdd_check_arguments(1, f)) + { + g=BDD_ONE(bddm); + { + BDD_SETUP(g); + BDD_MARK(g)=0; + } + bdd_mark_bdd(f); + return (cmu_bdd_size_step(f, counting_fns[!negout])); + } + return (0l); +} + + +/* cmu_bdd_size_multiple is like cmu_bdd_size, but takes a null-terminated */ +/* array of BDDs and accounts for sharing of nodes. */ + +long +#if defined(__STDC__) +cmu_bdd_size_multiple(cmu_bdd_manager bddm, bdd* fs, int negout) +#else +cmu_bdd_size_multiple(bddm, fs, negout) + cmu_bdd_manager bddm; + bdd *fs; + int negout; +#endif +{ + long size; + bdd *f; + bdd g; + + bdd_check_array(fs); + g=BDD_ONE(bddm); + { + BDD_SETUP(g); + BDD_MARK(g)=0; + } + for (f=fs; *f; ++f) + bdd_mark_bdd(*f); + size=0l; + for (f=fs; *f; ++f) + size+=cmu_bdd_size_step(*f, counting_fns[!negout]); + return (size); +} + + +static +void +#if defined(__STDC__) +cmu_bdd_profile_step(cmu_bdd_manager bddm, bdd f, long *level_counts, int (*count_fn)(bdd)) +#else +cmu_bdd_profile_step(bddm, f, level_counts, count_fn) + cmu_bdd_manager bddm; + bdd f; + long *level_counts; + int (*count_fn)(); +#endif +{ + BDD_SETUP(f); + if (!BDD_MARK(f)) + return; + if (BDD_IS_CONST(f)) + level_counts[bddm->vars]+=(*count_fn)(f); + else + { + level_counts[BDD_INDEX(bddm, f)]+=(*count_fn)(f); + cmu_bdd_profile_step(bddm, BDD_THEN(f), level_counts, count_fn); + cmu_bdd_profile_step(bddm, BDD_ELSE(f), level_counts, count_fn); + } + BDD_MARK(f)=0; +} + + +/* cmu_bdd_profile(bddm, f, level_counts, negout) returns a "node profile" */ +/* of f, i.e., the number of nodes at each level in f. negout is as in */ +/* cmu_bdd_size. level_counts should be an array of size cmu_bdd_vars(bddm)+1 */ +/* to hold the profile. */ + +void +#if defined(__STDC__) +cmu_bdd_profile(cmu_bdd_manager bddm, bdd f, long *level_counts, int negout) +#else +cmu_bdd_profile(bddm, f, level_counts, negout) + cmu_bdd_manager bddm; + bdd f; + long *level_counts; + int negout; +#endif +{ + bdd_index_type i; + bdd g; + + for (i=0; i <= bddm->vars; ++i) + level_counts[i]=0l; + if (bdd_check_arguments(1, f)) + { + g=BDD_ONE(bddm); + { + BDD_SETUP(g); + BDD_MARK(g)=0; + } + bdd_mark_bdd(f); + cmu_bdd_profile_step(bddm, f, level_counts, counting_fns[!negout]); + } +} + + +/* cmu_bdd_profile_multiple is to cmu_bdd_profile as cmu_bdd_size_multiple is to */ +/* cmu_bdd_size. */ + +void +#if defined(__STDC__) +cmu_bdd_profile_multiple(cmu_bdd_manager bddm, bdd *fs, long *level_counts, int negout) +#else +cmu_bdd_profile_multiple(bddm, fs, level_counts, negout) + cmu_bdd_manager bddm; + bdd *fs; + long *level_counts; + int negout; +#endif +{ + bdd_index_type i; + bdd *f; + bdd g; + + bdd_check_array(fs); + for (i=0; i <= bddm->vars; ++i) + level_counts[i]=0l; + g=BDD_ONE(bddm); + { + BDD_SETUP(g); + BDD_MARK(g)=0; + } + for (f=fs; *f; ++f) + bdd_mark_bdd(*f); + for (f=fs; *f; ++f) + cmu_bdd_profile_step(bddm, *f, level_counts, counting_fns[!negout]); +} + + +static +void +#if defined(__STDC__) +bdd_highest_ref_step(cmu_bdd_manager bddm, bdd f, hash_table h) +#else +bdd_highest_ref_step(bddm, f, h) + cmu_bdd_manager bddm; + bdd f; + hash_table h; +#endif +{ + long *hash_result; + long f_index; + + BDD_SETUP(f); + if (BDD_IS_CONST(f)) + return; + f_index=BDD_INDEX(bddm, f); + if ((hash_result=(long *)bdd_lookup_in_hash_table(h, BDD_THEN(f)))) + { + if (*hash_result > f_index) + *hash_result=f_index; + } + else + { + bdd_insert_in_hash_table(h, BDD_THEN(f), (pointer)&f_index); + bdd_highest_ref_step(bddm, BDD_THEN(f), h); + } + if ((hash_result=(long *)bdd_lookup_in_hash_table(h, BDD_ELSE(f)))) + { + if (*hash_result > f_index) + *hash_result=f_index; + } + else + { + bdd_insert_in_hash_table(h, BDD_ELSE(f), (pointer)&f_index); + bdd_highest_ref_step(bddm, BDD_ELSE(f), h); + } +} + + +static +void +#if defined(__STDC__) +bdd_dominated_step(cmu_bdd_manager bddm, bdd f, long *func_counts, hash_table h) +#else +bdd_dominated_step(bddm, f, func_counts, h) + cmu_bdd_manager bddm; + bdd f; + long *func_counts; + hash_table h; +#endif +{ + long *hash_result; + + hash_result=(long *)bdd_lookup_in_hash_table(h, f); + if (*hash_result >= 0) + func_counts[*hash_result]-=2; + if (*hash_result > -2) + { + BDD_SETUP(f); + *hash_result= -2; + if (!BDD_IS_CONST(f)) + { + bdd_dominated_step(bddm, BDD_THEN(f), func_counts, h); + bdd_dominated_step(bddm, BDD_ELSE(f), func_counts, h); + } + } +} + + +/* cmu_bdd_function_profile(bddm, f, func_counts) returns a "function */ +/* profile" for f. The nth entry of the function profile array is the */ +/* number of subfunctions of f which may be obtained by restricting */ +/* the variables whose index is less than n. An entry of zero */ +/* indicates that f is independent of the variable with the */ +/* corresponding index. */ + +void +#if defined(__STDC__) +cmu_bdd_function_profile(cmu_bdd_manager bddm, bdd f, long *func_counts) +#else +cmu_bdd_function_profile(bddm, f, func_counts) + cmu_bdd_manager bddm; + bdd f; + long *func_counts; +#endif +{ + long i; + bdd_index_type j; + hash_table h; + + /* The number of subfunctions obtainable by restricting the */ + /* variables of index < n is the number of subfunctions whose top */ + /* variable has index n plus the number of subfunctions obtainable */ + /* by restricting the variables of index < n+1 minus the number of */ + /* these latter subfunctions whose highest reference is by a node at */ + /* level n. */ + /* The strategy will be to start with the number of subfunctions */ + /* whose top variable has index n. We compute the highest level at */ + /* which each subfunction is referenced. Then we work bottom up; at */ + /* level n we add in the result from level n+1 and subtract the */ + /* number of subfunctions whose highest reference is at level n. */ + cmu_bdd_profile(bddm, f, func_counts, 0); + if (bdd_check_arguments(1, f)) + { + /* Encode the profile. The low bit of a count will be zero for */ + /* those levels where f actually has a node. */ + for (j=0; j < bddm->vars; ++j) + if (!func_counts[j]) + func_counts[j]=1; + else + func_counts[j]<<=1; + h=bdd_new_hash_table(bddm, sizeof(long)); + /* For each subfunction in f, compute the highest level where it is */ + /* referenced. f itself is conceptually referenced at the highest */ + /* possible level, which we represent by -1. */ + i= -1; + bdd_insert_in_hash_table(h, f, (pointer)&i); + bdd_highest_ref_step(bddm, f, h); + /* Walk through these results. For each subfunction, decrement the */ + /* count at the highest level where it is referenced. */ + bdd_dominated_step(bddm, f, func_counts, h); + cmu_bdd_free_hash_table(h); + /* Now add each level n+1 result to that of level n. */ + for (i=bddm->vars-1, j=i+1; i>= 0; --i) + if (func_counts[i] != 1) + { + func_counts[i]=(func_counts[i] >> 1)+func_counts[j]; + j=i; + } + else + func_counts[i]=0; + } +} + + +/* cmu_bdd_function_profile_multiple is to cmu_bdd_function_profile as */ +/* cmu_bdd_size_multiple is to cmu_bdd_size. */ + +void +#if defined(__STDC__) +cmu_bdd_function_profile_multiple(cmu_bdd_manager bddm, bdd *fs, long *func_counts) +#else +cmu_bdd_function_profile_multiple(bddm, fs, func_counts) + cmu_bdd_manager bddm; + bdd *fs; + long *func_counts; +#endif +{ + long i; + bdd_index_type j; + bdd *f; + long *hash_result; + hash_table h; + + bdd_check_array(fs); + /* See cmu_bdd_function_profile for the strategy involved here. */ + cmu_bdd_profile_multiple(bddm, fs, func_counts, 0); + for (j=0; j < bddm->vars; ++j) + if (!func_counts[j]) + func_counts[j]=1; + else + func_counts[j]<<=1; + h=bdd_new_hash_table(bddm, sizeof(long)); + for (f=fs; *f; ++f) + bdd_highest_ref_step(bddm, *f, h); + i= -1; + for (f=fs; *f; ++f) + if ((hash_result=(long *)bdd_lookup_in_hash_table(h, *f))) + *hash_result= -1; + else + bdd_insert_in_hash_table(h, *f, (pointer)&i); + for (f=fs; *f; ++f) + bdd_dominated_step(bddm, *f, func_counts, h); + cmu_bdd_free_hash_table(h); + for (i=bddm->vars-1, j=i+1; i>= 0; --i) + if (func_counts[i] != 1) + { + func_counts[i]=(func_counts[i] >> 1)+func_counts[j]; + j=i; + } + else + func_counts[i]=0; +} diff --git a/sis/bdd_cmu/bdd_cmu/bddsupport.c b/sis/bdd_cmu/bdd_cmu/bddsupport.c new file mode 100644 index 0000000..361ff8b --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddsupport.c @@ -0,0 +1,146 @@ +/* BDD support routines */ + + +#include "bddint.h" + + +static +int +#if defined(__STDC__) +cmu_bdd_depends_on_step(cmu_bdd_manager bddm, bdd f, bdd_index_type var_index, int mark) +#else +cmu_bdd_depends_on_step(bddm, f, var_index, mark) + cmu_bdd_manager bddm; + bdd f; + bdd_index_type var_index; + int mark; +#endif +{ + bdd_index_type f_index; + + BDD_SETUP(f); + f_index=BDD_INDEX(bddm, f); + if (f_index > var_index) + return (0); + if (f_index == var_index) + return (1); + if (BDD_MARK(f) == mark) + return (0); + BDD_MARK(f)=mark; + if (cmu_bdd_depends_on_step(bddm, BDD_THEN(f), var_index, mark)) + return (1); + return (cmu_bdd_depends_on_step(bddm, BDD_ELSE(f), var_index, mark)); +} + + +/* cmu_bdd_depends_on(bddm, f, var) returns 1 if f depends on var and */ +/* returns 0 otherwise. */ + +int +#if defined(__STDC__) +cmu_bdd_depends_on(cmu_bdd_manager bddm, bdd f, bdd var) +#else +cmu_bdd_depends_on(bddm, f, var) + cmu_bdd_manager bddm; + bdd f; + bdd var; +#endif +{ + if (bdd_check_arguments(2, f, var)) + { + BDD_SETUP(var); + if (cmu_bdd_type_aux(bddm, var) != BDD_TYPE_POSVAR) + { + cmu_bdd_warning("cmu_bdd_depends_on: second argument is not a positive variable"); + if (BDD_IS_CONST(var)) + return (1); + } + (void)cmu_bdd_depends_on_step(bddm, f, BDD_INDEX(bddm, var), 1); + return (cmu_bdd_depends_on_step(bddm, f, BDD_INDEX(bddm, var), 0)); + } + return (0); +} + + +static +void +#if defined(__STDC__) +bdd_unmark_nodes(cmu_bdd_manager bddm, bdd f) +#else +bdd_unmark_nodes(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + bdd temp; + + BDD_SETUP(f); + if (!BDD_MARK(f) || BDD_IS_CONST(f)) + return; + BDD_MARK(f)=0; + temp=BDD_IF(bddm, f); + { + BDD_SETUP(temp); + BDD_MARK(temp)=0; + } + bdd_unmark_nodes(bddm, BDD_THEN(f)); + bdd_unmark_nodes(bddm, BDD_ELSE(f)); +} + + +static +bdd * +#if defined(__STDC__) +cmu_bdd_support_step(cmu_bdd_manager bddm, bdd f, bdd *support) +#else +cmu_bdd_support_step(bddm, f, support) + cmu_bdd_manager bddm; + bdd f; + bdd *support; +#endif +{ + bdd temp; + + BDD_SETUP(f); + if (BDD_MARK(f) || BDD_IS_CONST(f)) + return (support); + temp=BDD_IF(bddm, f); + { + BDD_SETUP(temp); + if (!BDD_MARK(temp)) + { + BDD_MARK(temp)=1; + *support=temp; + ++support; + } + } + BDD_MARK(f)=1; + support=cmu_bdd_support_step(bddm, BDD_THEN(f), support); + return (cmu_bdd_support_step(bddm, BDD_ELSE(f), support)); +} + + +/* cmu_bdd_support(bddm, f, support) returns the support of f as a */ +/* null-terminated array of variables. */ + +void +#if defined(__STDC__) +cmu_bdd_support(cmu_bdd_manager bddm, bdd f, bdd *support) +#else +cmu_bdd_support(bddm, f, support) + cmu_bdd_manager bddm; + bdd f; + bdd *support; +#endif +{ + bdd *end; + + if (bdd_check_arguments(1, f)) + { + end=cmu_bdd_support_step(bddm, f, support); + *end=0; + bdd_unmark_nodes(bddm, f); + } + else + *support=0; +} diff --git a/sis/bdd_cmu/bdd_cmu/bddswap.c b/sis/bdd_cmu/bdd_cmu/bddswap.c new file mode 100644 index 0000000..7623bb3 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddswap.c @@ -0,0 +1,189 @@ +/* BDD variable exchange routine */ + + +#include "bddint.h" + + +static +bdd +#if defined(__STDC__) +cmu_bdd_swap_vars_aux_step(cmu_bdd_manager bddm, bdd f, bdd g, bdd h, bdd_indexindex_type h_indexindex, long op) +#else +cmu_bdd_swap_vars_aux_step(bddm, f, g, h, h_indexindex, op) + cmu_bdd_manager bddm; + bdd f; + bdd g; + bdd h; + bdd_indexindex_type h_indexindex; + long op; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd_index_type f_index, g_index; + bdd f1, f2; + bdd g1, g2; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + BDD_SETUP(g); + f_index=BDD_INDEX(bddm, f); + g_index=BDD_INDEX(bddm, g); + if (f_index == bddm->indexes[h_indexindex]) + { + if (op & 1) + f=BDD_THEN(f); + else + f=BDD_ELSE(f); + BDD_RESET(f); + } + if (g_index == bddm->indexes[h_indexindex]) + { + if (op & 1) + g=BDD_THEN(g); + else + g=BDD_ELSE(g); + BDD_RESET(g); + } + if (f == g) + if (op & 1) + return (cmu_bdd_compose_temp(bddm, f, h, BDD_ONE(bddm))); + else + return (cmu_bdd_compose_temp(bddm, f, h, BDD_ZERO(bddm))); + if (f_index >= bddm->indexes[h_indexindex] && g_index >= bddm->indexes[h_indexindex]) + { + BDD_TEMP_INCREFS(f); + BDD_TEMP_INCREFS(g); + return (bdd_find(bddm, h_indexindex, f, g)); + } + if (bdd_lookup_in_cache2(bddm, op, f, g, &result)) + return (result); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + temp1=cmu_bdd_swap_vars_aux_step(bddm, f1, g1, h, h_indexindex, op); + temp2=cmu_bdd_swap_vars_aux_step(bddm, f2, g2, h, h_indexindex, op); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache2(bddm, op, f, g, result); + return (result); +} + + +static +bdd +#if defined(__STDC__) +cmu_bdd_swap_vars_step(cmu_bdd_manager bddm, bdd f, bdd_indexindex_type g_indexindex, bdd h, long op) +#else +cmu_bdd_swap_vars_step(bddm, f, g_indexindex, h, op) + cmu_bdd_manager bddm; + bdd f; + bdd_indexindex_type g_indexindex; + bdd h; + long op; +#endif +{ + bdd_index_type f_index; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + if (BDD_IS_CONST(f)) + return (f); + if (bdd_lookup_in_cache2(bddm, op, f, h, &result)) + return (result); + f_index=BDD_INDEX(bddm, f); + if (f_index > bddm->indexes[g_indexindex]) + { + temp1=cmu_bdd_compose_temp(bddm, f, h, BDD_ONE(bddm)); + temp2=cmu_bdd_compose_temp(bddm, f, h, BDD_ZERO(bddm)); + result=bdd_find(bddm, g_indexindex, temp1, temp2); + } + else if (f_index < bddm->indexes[g_indexindex]) + { + temp1=cmu_bdd_swap_vars_step(bddm, BDD_THEN(f), g_indexindex, h, op); + temp2=cmu_bdd_swap_vars_step(bddm, BDD_ELSE(f), g_indexindex, h, op); + result=bdd_find(bddm, BDD_INDEXINDEX(f), temp1, temp2); + } + else + { + BDD_SETUP(h); + temp1=cmu_bdd_swap_vars_aux_step(bddm, BDD_THEN(f), BDD_ELSE(f), h, BDD_INDEXINDEX(h), OP_SWAPAUX+2*BDD_INDEXINDEX(h)+1); + temp2=cmu_bdd_swap_vars_aux_step(bddm, BDD_THEN(f), BDD_ELSE(f), h, BDD_INDEXINDEX(h), OP_SWAPAUX+2*BDD_INDEXINDEX(h)); + result=bdd_find(bddm, g_indexindex, temp1, temp2); + } + bdd_insert_in_cache2(bddm, op, f, h, result); + return (result); +} + + +bdd +#if defined(__STDC__) +cmu_bdd_swap_vars_temp(cmu_bdd_manager bddm, bdd f, bdd g, bdd h) +#else +cmu_bdd_swap_vars_temp(bddm, f, g, h) + cmu_bdd_manager bddm; + bdd f; + bdd g; + bdd h; +#endif +{ + bdd_index_type g_index, h_index; + + BDD_SETUP(f); + BDD_SETUP(g); + BDD_SETUP(h); + g_index=BDD_INDEX(bddm, g); + h_index=BDD_INDEX(bddm, h); + if (g_index == h_index) + { + BDD_TEMP_INCREFS(f); + return (f); + } + if (g_index > h_index) + return (cmu_bdd_swap_vars_step(bddm, f, BDD_INDEXINDEX(h), g, OP_SWAP+BDD_INDEXINDEX(h))); + else + return (cmu_bdd_swap_vars_step(bddm, f, BDD_INDEXINDEX(g), h, OP_SWAP+BDD_INDEXINDEX(g))); +} + + +/* cmu_bdd_swap_vars(bddm, f, g, h) substitutes g for h and h for g in f. */ + +bdd +#if defined(__STDC__) +cmu_bdd_swap_vars(cmu_bdd_manager bddm, bdd f, bdd g, bdd h) +#else +cmu_bdd_swap_vars(bddm, f, g, h) + cmu_bdd_manager bddm; + bdd f; + bdd g; + bdd h; +#endif +{ + bdd_index_type g_index, h_index; + + if (bdd_check_arguments(3, f, g, h)) + { + BDD_SETUP(f); + BDD_SETUP(g); + BDD_SETUP(h); + if (cmu_bdd_type_aux(bddm, g) != BDD_TYPE_POSVAR || cmu_bdd_type_aux(bddm, h) != BDD_TYPE_POSVAR) + { + cmu_bdd_warning("cmu_bdd_swap_vars: second and third arguments are not both positive variables"); + BDD_INCREFS(f); + return (f); + } + FIREWALL(bddm); + g_index=BDD_INDEX(bddm, g); + h_index=BDD_INDEX(bddm, h); + if (g_index == h_index) + { + BDD_INCREFS(f); + return (f); + } + if (g_index > h_index) + RETURN_BDD(cmu_bdd_swap_vars_step(bddm, f, BDD_INDEXINDEX(h), g, OP_SWAP+BDD_INDEXINDEX(h))); + else + RETURN_BDD(cmu_bdd_swap_vars_step(bddm, f, BDD_INDEXINDEX(g), h, OP_SWAP+BDD_INDEXINDEX(g))); + } + return ((bdd)0); +} diff --git a/sis/bdd_cmu/bdd_cmu/bddunique.c b/sis/bdd_cmu/bdd_cmu/bddunique.c new file mode 100644 index 0000000..d3d712b --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddunique.c @@ -0,0 +1,506 @@ +/* BDD unique table routines */ + + +#include "bddint.h" + + +#define MIN_GC_LIMIT 10000 + + +void +#if defined(__STDC__) +bdd_rehash_var_table(var_table table, int grow) +#else +bdd_rehash_var_table(table, grow) + var_table table; + int grow; +#endif +{ + long i; + long hash; + long oldsize; + bdd *newtable; + bdd p, q; + + oldsize=table->size; + if (grow) + table->size_index++; + else + table->size_index--; + table->size=TABLE_SIZE(table->size_index); + newtable=(bdd *)mem_get_block((SIZE_T)(table->size*sizeof(bdd))); + for (i=0; i < table->size; ++i) + newtable[i]=0; + for (i=0; i < oldsize; ++i) + for (p=table->table[i]; p; p=q) + { + q=p->next; + hash=HASH_NODE(p->data[0], p->data[1]); + BDD_REDUCE(hash, table->size); + p->next=newtable[hash]; + newtable[hash]=p; + } + mem_free_block((pointer)table->table); + table->table=newtable; +} + + +static +void +#if defined(__STDC__) +bdd_mark(cmu_bdd_manager bddm) +#else +bdd_mark(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i, j; + var_table table; + bdd f, g; + + for (i=0; i <= bddm->vars; ++i) + { + if (i == bddm->vars) + table=bddm->unique_table.tables[BDD_CONST_INDEXINDEX]; + else + table=bddm->unique_table.tables[bddm->indexindexes[i]]; + for (j=0; j < table->size; ++j) + for (f=table->table[j]; f; f=f->next) + { + BDD_SETUP(f); + if (BDD_REFS(f) || BDD_TEMP_REFS(f)) + BDD_MARK(f)|=BDD_GC_MARK; + if (BDD_IS_USED(f) && !BDD_IS_CONST(f)) + { + g=(bdd)BDD_DATA0(f); + { + BDD_SETUP(g); + BDD_MARK(g)|=BDD_GC_MARK; + } + g=(bdd)BDD_DATA1(f); + { + BDD_SETUP(g); + BDD_MARK(g)|=BDD_GC_MARK; + } + } + } + } +} + + +void +#if defined(__STDC__) +bdd_sweep_var_table(cmu_bdd_manager bddm, long i, int maybe_rehash) +#else +bdd_sweep_var_table(bddm, i, maybe_rehash) + cmu_bdd_manager bddm; + long i; + int maybe_rehash; +#endif +{ + long j; + var_table table; + bdd f, *p; + + table=bddm->unique_table.tables[i]; + for (j=0; j < table->size; ++j) + for (p= &table->table[j], f= *p; f; f= *p) + { + BDD_SETUP(f); + if (BDD_IS_USED(f)) + { + BDD_SETUP(f); + BDD_MARK(f)&=~BDD_GC_MARK; + p= &f->next; + } + else + { + *p=f->next; + if (i == BDD_CONST_INDEXINDEX && bddm->unique_table.free_terminal_fn) + (*bddm->unique_table.free_terminal_fn)(bddm, + BDD_DATA0(f), + BDD_DATA1(f), + bddm->unique_table.free_terminal_env); + BDD_FREE_REC(bddm, (pointer)f, sizeof(struct bdd_)); + table->entries--; + bddm->unique_table.entries--; + bddm->unique_table.freed++; + } + } + if (maybe_rehash && table->size > table->entries && table->size_index > 3) + bdd_rehash_var_table(table, 0); +} + + +void +#if defined(__STDC__) +bdd_sweep(cmu_bdd_manager bddm) +#else +bdd_sweep(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i; + + for (i=0; i <= bddm->vars; ++i) + bdd_sweep_var_table(bddm, i, 1); +} + + +/* cmu_bdd_gc(bddm) performs a garbage collection. */ + +void +#if defined(__STDC__) +cmu_bdd_gc(cmu_bdd_manager bddm) +#else +cmu_bdd_gc(bddm) + cmu_bdd_manager bddm; +#endif +{ + bdd_mark(bddm); + bdd_purge_cache(bddm); + bdd_sweep(bddm); + bddm->unique_table.gcs++; +} + + +static +void +#if defined(__STDC__) +bdd_set_gc_limit(cmu_bdd_manager bddm) +#else +bdd_set_gc_limit(bddm) + cmu_bdd_manager bddm; +#endif +{ + bddm->unique_table.gc_limit=2*bddm->unique_table.entries; + if (bddm->unique_table.gc_limit < MIN_GC_LIMIT) + bddm->unique_table.gc_limit=MIN_GC_LIMIT; + if (bddm->unique_table.node_limit && + bddm->unique_table.gc_limit > bddm->unique_table.node_limit) + bddm->unique_table.gc_limit=bddm->unique_table.node_limit; +} + + +void +#if defined(__STDC__) +bdd_clear_temps(cmu_bdd_manager bddm) +#else +bdd_clear_temps(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i, j; + var_table table; + bdd f; + + for (i=0; i <= bddm->vars; ++i) + { + table=bddm->unique_table.tables[i]; + for (j=0; j < table->size; ++j) + for (f=table->table[j]; f; f=f->next) + { + BDD_SETUP(f); + BDD_TEMP_REFS(f)=0; + } + } + cmu_bdd_gc(bddm); + bdd_set_gc_limit(bddm); +} + + +void +#if defined(__STDC__) +bdd_cleanup(cmu_bdd_manager bddm, int code) +#else +bdd_cleanup(bddm, code) + cmu_bdd_manager bddm; + int code; +#endif +{ + bdd_clear_temps(bddm); + switch (code) + { + case BDD_ABORTED: + (*bddm->bag_it_fn)(bddm, bddm->bag_it_env); + break; + case BDD_OVERFLOWED: + if (bddm->overflow_fn) + (*bddm->overflow_fn)(bddm, bddm->overflow_env); + break; + } +} + + +bdd +#if defined(__STDC__) +bdd_find_aux(cmu_bdd_manager bddm, bdd_indexindex_type indexindex, INT_PTR d1, INT_PTR d2) +#else +bdd_find_aux(bddm, indexindex, d1, d2) + cmu_bdd_manager bddm; + bdd_indexindex_type indexindex; + INT_PTR d1; + INT_PTR d2; +#endif +{ + var_table table; + long hash; + bdd temp; + + table=bddm->unique_table.tables[indexindex]; + hash=HASH_NODE(d1, d2); + BDD_REDUCE(hash, table->size); + for (temp=table->table[hash]; temp; temp=temp->next) + if (temp->data[0] == d1 && temp->data[1] == d2) + break; + if (!temp) + { + /* Not found; make a new node. */ + temp=(bdd)BDD_NEW_REC(bddm, sizeof(struct bdd_)); + temp->indexindex=indexindex; + temp->refs=0; + temp->mark=0; + temp->data[0]=d1; + temp->data[1]=d2; + temp->next=table->table[hash]; + table->table[hash]=temp; + table->entries++; + bddm->unique_table.entries++; + if (4*table->size < table->entries) + bdd_rehash_var_table(table, 1); + } + bddm->unique_table.finds++; + return (temp); +} + + +static +void +#if defined(__STDC__) +bdd_check(cmu_bdd_manager bddm) +#else +bdd_check(bddm) + cmu_bdd_manager bddm; +#endif +{ + long nodes; + + bddm->check=100; + /* When bag_it_fn set, clean up and abort immediately. */ + if (bddm->bag_it_fn) + longjmp(bddm->abort.context, BDD_ABORTED); + if (bddm->unique_table.entries > bddm->unique_table.gc_limit) + { + cmu_bdd_gc(bddm); + /* Table full. */ + nodes=bddm->unique_table.entries; + if (3*nodes > 2*bddm->unique_table.gc_limit && bddm->allow_reordering && bddm->reorder_fn) + { + cmu_bdd_reorder_aux(bddm); + if (4*bddm->unique_table.entries > 3*nodes && 3*nodes > 4*bddm->nodes_at_start) + /* If we didn't save much, but we have created a reasonable number */ + /* of nodes, then don't bother reordering next time. */ + bddm->allow_reordering=0; + /* Go try again. */ + bdd_set_gc_limit(bddm); + longjmp(bddm->abort.context, BDD_REORDERED); + } + bdd_set_gc_limit(bddm); + if (bddm->unique_table.node_limit && + bddm->unique_table.entries >= bddm->unique_table.node_limit-1000) + { + /* Out of memory; go clean up. */ + bddm->overflow=1; + longjmp(bddm->abort.context, BDD_OVERFLOWED); + } + } + /* Maybe increase cache size if it's getting full. */ + if (3*bddm->op_cache.size < 2*bddm->op_cache.entries && + 32*bddm->op_cache.size < bddm->op_cache.cache_ratio*bddm->unique_table.entries) + bdd_rehash_cache(bddm, 1); +} + + +/* bdd_find(bddm, indexindex, f, g) creates or finds a node with the */ +/* given indexindex, "then" pointer, and "else" pointer. */ + +bdd +#if defined(__STDC__) +bdd_find(cmu_bdd_manager bddm, bdd_indexindex_type indexindex, bdd f, bdd g) +#else +bdd_find(bddm, indexindex, f, g) + cmu_bdd_manager bddm; + bdd_indexindex_type indexindex; + bdd f; + bdd g; +#endif +{ + bdd temp; + + BDD_SETUP(f); + BDD_SETUP(g); + if (f == g) + { + BDD_TEMP_DECREFS(f); + temp=f; + } + else + { + if (BDD_IS_OUTPOS(f)) + temp=bdd_find_aux(bddm, indexindex, (INT_PTR)f, (INT_PTR)g); + else + temp=BDD_NOT(bdd_find_aux(bddm, indexindex, (INT_PTR)BDD_NOT(f), (INT_PTR)BDD_NOT(g))); + { + BDD_SETUP(temp); + BDD_TEMP_INCREFS(temp); + } + BDD_TEMP_DECREFS(f); + BDD_TEMP_DECREFS(g); + } + bddm->check--; + if (!bddm->check) + bdd_check(bddm); + return (temp); +} + + +/* bdd_find_terminal(bddm, value1, value2) creates or finds a terminal */ +/* node with the given data value. */ + +bdd +#if defined(__STDC__) +bdd_find_terminal(cmu_bdd_manager bddm, INT_PTR value1, INT_PTR value2) +#else +bdd_find_terminal(bddm, value1, value2) + cmu_bdd_manager bddm; + INT_PTR value1; + INT_PTR value2; +#endif +{ + bdd temp; + + if ((*bddm->canonical_fn)(bddm, value1, value2, bddm->transform_env)) + { + (*bddm->transform_fn)(bddm, value1, value2, &value1, &value2, bddm->transform_env); + temp=BDD_NOT(bdd_find_aux(bddm, BDD_CONST_INDEXINDEX, value1, value2)); + } + else + temp=bdd_find_aux(bddm, BDD_CONST_INDEXINDEX, value1, value2); + { + BDD_SETUP(temp); + BDD_TEMP_INCREFS(temp); + } + bddm->check--; + if (!bddm->check) + bdd_check(bddm); + return (temp); +} + + +/* cmu_bdd_clear_refs(bddm) sets the reference count of all nodes to 0. */ + +void +#if defined(__STDC__) +cmu_bdd_clear_refs(cmu_bdd_manager bddm) +#else +cmu_bdd_clear_refs(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i, j; + var_table table; + bdd f; + assoc_list q; + + for (i=0; i <= bddm->vars; ++i) + { + table=bddm->unique_table.tables[i]; + for (j=0; j < table->size; ++j) + for (f=table->table[j]; f; f=f->next) + { + BDD_SETUP(f); + BDD_REFS(f)=0; + } + } + for (i=0; i < bddm->vars; ++i) + bddm->variables[i+1]->refs=BDD_MAX_REFS; + bddm->one->refs=BDD_MAX_REFS; + for (q=bddm->assocs; q; q=q->next) + for (i=0; i < bddm->vars; ++i) + if ((f=q->va.assoc[i+1])) + { + BDD_SETUP(f); + BDD_INCREFS(f); + } +} + + +var_table +#if defined(__STDC__) +bdd_new_var_table(cmu_bdd_manager bddm) +#else +bdd_new_var_table(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i; + var_table table; + + table=(var_table)BDD_NEW_REC(bddm, sizeof(struct var_table_)); + table->size_index=3; + table->size=TABLE_SIZE(table->size_index); + table->entries=0; + table->table=(bdd *)mem_get_block((SIZE_T)(table->size*sizeof(bdd))); + for (i=0; i < table->size; ++i) + table->table[i]=0; + return (table); +} + + +void +#if defined(__STDC__) +cmu_bdd_init_unique(cmu_bdd_manager bddm) +#else +cmu_bdd_init_unique(bddm) + cmu_bdd_manager bddm; +#endif +{ + bddm->unique_table.tables=(var_table *)mem_get_block((SIZE_T)((bddm->maxvars+1)*sizeof(var_table))); + bddm->unique_table.tables[BDD_CONST_INDEXINDEX]=bdd_new_var_table(bddm); + bddm->unique_table.gc_limit=MIN_GC_LIMIT; + bddm->unique_table.node_limit=0; + bddm->unique_table.entries=0; + bddm->unique_table.freed=0; + bddm->unique_table.gcs=0; + bddm->unique_table.finds=0; + bddm->unique_table.free_terminal_fn=0; + bddm->unique_table.free_terminal_env=0; +} + + +void +#if defined(__STDC__) +cmu_bdd_free_unique(cmu_bdd_manager bddm) +#else +cmu_bdd_free_unique(bddm) + cmu_bdd_manager bddm; +#endif +{ + long i, j; + var_table table; + bdd p, q; + + for (i=0; i <= bddm->vars; ++i) + { + table=bddm->unique_table.tables[i]; + for (j=0; j < table->size; ++j) + for (p=table->table[j]; p; p=q) + { + q=p->next; + BDD_FREE_REC(bddm, (pointer)p, sizeof(struct bdd_)); + } + mem_free_block((pointer)table->table); + BDD_FREE_REC(bddm, (pointer)table, sizeof(struct var_table_)); + } + mem_free_block((pointer)bddm->unique_table.tables); +} diff --git a/sis/bdd_cmu/bdd_cmu/bdduser.h b/sis/bdd_cmu/bdd_cmu/bdduser.h new file mode 100644 index 0000000..709fb46 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bdduser.h @@ -0,0 +1,258 @@ +/* BDD user-visible definitions */ + + +#if !defined(_BDDUSERH) +#define _BDDUSERH + + +#include +#include + + +#if defined(__STDC__) +#define ARGS(args) args +#else +#define ARGS(args) () +#endif + + +/* Types */ + +typedef struct bdd_ *bdd; +typedef struct bdd_manager_ *cmu_bdd_manager; +typedef struct block_ *block; + + +/* Return values for cmu_bdd_type */ + +#define BDD_TYPE_NONTERMINAL 0 +#define BDD_TYPE_ZERO 1 +#define BDD_TYPE_ONE 2 +#define BDD_TYPE_POSVAR 3 +#define BDD_TYPE_NEGVAR 4 +#define BDD_TYPE_OVERFLOW 5 +#define BDD_TYPE_CONSTANT 6 + + +/* Error codes for cmu_bdd_undump_bdd */ + +#define BDD_UNDUMP_FORMAT 1 +#define BDD_UNDUMP_OVERFLOW 2 +#define BDD_UNDUMP_IOERROR 3 +#define BDD_UNDUMP_EOF 4 + + +/* Basic BDD routine declarations */ + +extern bdd cmu_bdd_one ARGS((cmu_bdd_manager)); +extern bdd cmu_bdd_zero ARGS((cmu_bdd_manager)); +extern bdd cmu_bdd_new_var_first ARGS((cmu_bdd_manager)); +extern bdd cmu_bdd_new_var_last ARGS((cmu_bdd_manager)); +extern bdd cmu_bdd_new_var_before ARGS((cmu_bdd_manager, bdd)); +extern bdd cmu_bdd_new_var_after ARGS((cmu_bdd_manager, bdd)); +extern bdd cmu_bdd_var_with_index ARGS((cmu_bdd_manager, long)); +extern bdd cmu_bdd_var_with_id ARGS((cmu_bdd_manager, long)); +extern bdd cmu_bdd_ite ARGS((cmu_bdd_manager, bdd, bdd, bdd)); +extern bdd cmu_bdd_and ARGS((cmu_bdd_manager, bdd, bdd)); +extern bdd cmu_bdd_nand ARGS((cmu_bdd_manager, bdd, bdd)); +extern bdd cmu_bdd_or ARGS((cmu_bdd_manager, bdd, bdd)); +extern bdd cmu_bdd_nor ARGS((cmu_bdd_manager, bdd, bdd)); +extern bdd cmu_bdd_xor ARGS((cmu_bdd_manager, bdd, bdd)); +extern bdd cmu_bdd_xnor ARGS((cmu_bdd_manager, bdd, bdd)); +extern bdd cmu_bdd_identity ARGS((cmu_bdd_manager, bdd)); +extern bdd cmu_bdd_not ARGS((cmu_bdd_manager, bdd)); +extern bdd cmu_bdd_if ARGS((cmu_bdd_manager, bdd)); +extern long cmu_bdd_if_index ARGS((cmu_bdd_manager, bdd)); +extern long cmu_bdd_if_id ARGS((cmu_bdd_manager, bdd)); +extern bdd cmu_bdd_then ARGS((cmu_bdd_manager, bdd)); +extern bdd cmu_bdd_else ARGS((cmu_bdd_manager, bdd)); +extern bdd cmu_bdd_intersects ARGS((cmu_bdd_manager, bdd, bdd)); +extern bdd cmu_bdd_implies ARGS((cmu_bdd_manager, bdd, bdd)); +extern int cmu_bdd_type ARGS((cmu_bdd_manager, bdd)); +extern void cmu_bdd_unfree ARGS((cmu_bdd_manager, bdd)); +extern void cmu_bdd_free ARGS((cmu_bdd_manager, bdd)); +extern long cmu_bdd_vars ARGS((cmu_bdd_manager)); +extern long cmu_bdd_total_size ARGS((cmu_bdd_manager)); +extern int cmu_bdd_cache_ratio ARGS((cmu_bdd_manager, int)); +extern long cmu_bdd_node_limit ARGS((cmu_bdd_manager, long)); +extern int cmu_bdd_overflow ARGS((cmu_bdd_manager)); +extern void cmu_bdd_overflow_closure ARGS((cmu_bdd_manager, void (*) ARGS((cmu_bdd_manager, pointer)), pointer)); +extern void cmu_bdd_abort_closure ARGS((cmu_bdd_manager, void (*) ARGS((cmu_bdd_manager, pointer)), pointer)); +extern void cmu_bdd_stats ARGS((cmu_bdd_manager, FILE *)); +extern cmu_bdd_manager cmu_bdd_init ARGS((void)); +extern void cmu_bdd_quit ARGS((cmu_bdd_manager)); + + +/* Variable association routine declarations */ + +extern int cmu_bdd_new_assoc ARGS((cmu_bdd_manager, bdd *, int)); +extern void cmu_bdd_free_assoc ARGS((cmu_bdd_manager, int)); +extern void cmu_bdd_temp_assoc ARGS((cmu_bdd_manager, bdd *, int)); +extern void cmu_bdd_augment_temp_assoc ARGS((cmu_bdd_manager, bdd *, int)); +extern int cmu_bdd_assoc ARGS((cmu_bdd_manager, int)); + + +/* Comparison routine declarations */ + +extern int cmu_bdd_compare ARGS((cmu_bdd_manager, bdd, bdd, bdd)); + + +/* Composition routine declarations */ + +extern bdd cmu_bdd_compose ARGS((cmu_bdd_manager, bdd, bdd, bdd)); +extern bdd cmu_bdd_substitute ARGS((cmu_bdd_manager, bdd)); + + +/* Variable exchange routine declarations */ + +extern bdd cmu_bdd_swap_vars ARGS((cmu_bdd_manager, bdd, bdd, bdd)); + + +/* Quantification routine declarations */ + +extern bdd cmu_bdd_exists ARGS((cmu_bdd_manager, bdd)); +extern bdd cmu_bdd_forall ARGS((cmu_bdd_manager, bdd)); + + +/* Reduce routine declarations */ + +extern bdd cmu_bdd_reduce ARGS((cmu_bdd_manager, bdd, bdd)); +extern bdd cmu_bdd_cofactor ARGS((cmu_bdd_manager, bdd, bdd)); + + +/* Relational product routine declarations */ + +extern bdd cmu_bdd_rel_prod ARGS((cmu_bdd_manager, bdd, bdd)); + + +/* Satisfying valuation routine declarations */ + +extern bdd cmu_bdd_satisfy ARGS((cmu_bdd_manager, bdd)); +extern bdd cmu_bdd_satisfy_support ARGS((cmu_bdd_manager, bdd)); +extern double cmu_bdd_satisfying_fraction ARGS((cmu_bdd_manager, bdd)); + + +/* Generic apply routine declarations */ + +extern bdd bdd_apply2 ARGS((cmu_bdd_manager, bdd (*) ARGS((cmu_bdd_manager, bdd *, bdd *, pointer)), bdd, bdd, pointer)); +extern bdd bdd_apply1 ARGS((cmu_bdd_manager, bdd (*) ARGS((cmu_bdd_manager, bdd *, pointer)), bdd, pointer)); + + +/* Size and profile routine declarations */ + +extern long cmu_bdd_size ARGS((cmu_bdd_manager, bdd, int)); +extern long cmu_bdd_size_multiple ARGS((cmu_bdd_manager, bdd *, int)); +extern void cmu_bdd_profile ARGS((cmu_bdd_manager, bdd, long *, int)); +extern void cmu_bdd_profile_multiple ARGS((cmu_bdd_manager, bdd *, long *, int)); +extern void cmu_bdd_function_profile ARGS((cmu_bdd_manager, bdd, long *)); +extern void cmu_bdd_function_profile_multiple ARGS((cmu_bdd_manager, bdd *, long *)); + + +/* Print routine declarations */ + +#if defined(__STDC__) +#define bdd_naming_fn_none ((char *(*)(cmu_bdd_manager, bdd, pointer))0) +#define bdd_terminal_id_fn_none ((char *(*)(cmu_bdd_manager, INT_PTR, INT_PTR, pointer))0) +#else +#define bdd_naming_fn_none ((char *(*)())0) +#define bdd_terminal_id_fn_none ((char *(*)())0) +#endif + +extern void cmu_bdd_print_bdd ARGS((cmu_bdd_manager, + bdd, + char *(*) ARGS((cmu_bdd_manager, bdd, pointer)), + char *(*) ARGS((cmu_bdd_manager, INT_PTR, INT_PTR, pointer)), + pointer, + FILE *)); +extern void cmu_bdd_print_profile_aux ARGS((cmu_bdd_manager, + long *, + char *(*) ARGS((cmu_bdd_manager, bdd, pointer)), + pointer, + int, + FILE *)); +extern void cmu_bdd_print_profile ARGS((cmu_bdd_manager, + bdd, + char *(*) ARGS((cmu_bdd_manager, bdd, pointer)), + pointer, + int, + FILE *)); +extern void cmu_bdd_print_profile_multiple ARGS((cmu_bdd_manager, + bdd *, + char *(*) ARGS((cmu_bdd_manager, bdd, pointer)), + pointer, + int, + FILE *)); +extern void cmu_bdd_print_function_profile ARGS((cmu_bdd_manager, + bdd, + char *(*) ARGS((cmu_bdd_manager, bdd, pointer)), + pointer, + int, + FILE *)); +extern void cmu_bdd_print_function_profile_multiple ARGS((cmu_bdd_manager, + bdd *, + char *(*) ARGS((cmu_bdd_manager, bdd, pointer)), + pointer, + int, + FILE *)); + + +/* Dump/undump routine declarations */ + +extern int cmu_bdd_dump_bdd ARGS((cmu_bdd_manager, bdd, bdd *, FILE *)); +extern bdd cmu_bdd_undump_bdd ARGS((cmu_bdd_manager, bdd *, FILE *, int *)); + + +/* Support routine declarations */ + +extern int cmu_bdd_depends_on ARGS((cmu_bdd_manager, bdd, bdd)); +extern void cmu_bdd_support ARGS((cmu_bdd_manager, bdd, bdd *)); + + +/* Unique table routine declarations */ + +extern void cmu_bdd_gc ARGS((cmu_bdd_manager)); +extern void cmu_bdd_clear_refs ARGS((cmu_bdd_manager)); + + +/* Dynamic reordering routines */ + +#if defined(__STDC__) +#define cmu_bdd_reorder_none ((void (*)(cmu_bdd_manager))0) +#else +#define cmu_bdd_reorder_none ((void (*)())0) +#endif + +extern void cmu_bdd_reorder_stable_window3 ARGS((cmu_bdd_manager)); +extern void cmu_bdd_reorder_sift ARGS((cmu_bdd_manager)); +extern void cmu_bdd_reorder_hybrid ARGS((cmu_bdd_manager)); +extern void cmu_bdd_var_block_reorderable ARGS((cmu_bdd_manager, block, int)); +extern void cmu_bdd_dynamic_reordering ARGS((cmu_bdd_manager, void (*) ARGS((cmu_bdd_manager)))); +extern void cmu_bdd_reorder ARGS((cmu_bdd_manager)); + + +/* Variable block routines */ + +extern block cmu_bdd_new_var_block ARGS((cmu_bdd_manager, bdd, long)); + + +/* Multi-terminal BDD routine declarations */ + +extern void mtbdd_transform_closure ARGS((cmu_bdd_manager, + int (*) ARGS((cmu_bdd_manager, INT_PTR, INT_PTR, pointer)), + void (*) ARGS((cmu_bdd_manager, INT_PTR, INT_PTR, INT_PTR *, INT_PTR *, pointer)), + pointer)); +extern void mtcmu_bdd_one_data ARGS((cmu_bdd_manager, INT_PTR, INT_PTR)); +extern void cmu_mtbdd_free_terminal_closure ARGS((cmu_bdd_manager, + void (*) ARGS((cmu_bdd_manager, INT_PTR, INT_PTR, pointer)), + pointer)); +extern bdd cmu_mtbdd_get_terminal ARGS((cmu_bdd_manager, INT_PTR, INT_PTR)); +extern void cmu_mtbdd_terminal_value ARGS((cmu_bdd_manager, bdd, INT_PTR *, INT_PTR *)); +extern bdd mtcmu_bdd_ite ARGS((cmu_bdd_manager, bdd, bdd, bdd)); +extern bdd cmu_mtbdd_equal ARGS((cmu_bdd_manager, bdd, bdd)); +extern bdd mtcmu_bdd_substitute ARGS((cmu_bdd_manager, bdd)); +#define mtbdd_transform(bddm, f) (cmu_bdd_not(bddm, f)) + + +#undef ARGS + +#endif diff --git a/sis/bdd_cmu/bdd_cmu/bddwarn.c b/sis/bdd_cmu/bdd_cmu/bddwarn.c new file mode 100644 index 0000000..91e1407 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/bddwarn.c @@ -0,0 +1,101 @@ +/* BDD error and argument checking routines */ + + +#include +#if defined(__STDC__) +#include +#else +#include +#endif +#include "bddint.h" + + +#if defined(__STDC__) +extern void exit(int); +#else +extern void exit(); +#endif + + +/* cmu_bdd_warning(message) prints a warning and returns. */ + +void +#if defined(__STDC__) +cmu_bdd_warning(char *message) +#else +cmu_bdd_warning(message) + char *message; +#endif +{ + fprintf(stderr, "BDD library: warning: %s\n", message); +} + + +/* cmu_bdd_fatal(message) prints an error message and exits. */ + +void +#if defined(__STDC__) +cmu_bdd_fatal(char *message) +#else +cmu_bdd_fatal(message) + char *message; +#endif +{ + fprintf(stderr, "BDD library: error: %s\n", message); + exit(1); + /* NOTREACHED */ +} + + +int +#if defined(__STDC__) +bdd_check_arguments(int count, ...) +{ + int all_valid; + va_list ap; + bdd f; + + va_start(ap, count); +#else +bdd_check_arguments(va_alist) + va_dcl +{ + int count; + int all_valid; + va_list ap; + bdd f; + + va_start(ap); + count=va_arg(ap, int); +#endif + all_valid=1; + while (count) + { + f=va_arg(ap, bdd); + { + BDD_SETUP(f); + if (!f) + all_valid=0; + else if (BDD_REFS(f) == 0) + cmu_bdd_fatal("bdd_check_arguments: argument has zero references"); + } + --count; + } + return (all_valid); +} + + +void +#if defined(__STDC__) +bdd_check_array(bdd *fs) +#else +bdd_check_array(fs) + bdd *fs; +#endif +{ + while (*fs) + { + bdd_check_arguments(1, *fs); + ++fs; + } +} diff --git a/sis/bdd_cmu/bdd_cmu/mtbdd.c b/sis/bdd_cmu/bdd_cmu/mtbdd.c new file mode 100644 index 0000000..808fef1 --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/mtbdd.c @@ -0,0 +1,301 @@ +/* Basic multi-terminal BDD routines */ + + +#include "bddint.h" + + +/* mtbdd_transform_closure(bddm, canonical_fn, transform_fn, env) sets */ +/* the transformation for MTBDD terminal values for the "negative-output" */ +/* pointer flag. The canonical_fn receives the BDD manager, two longs */ +/* representing the input value, and the value of env. It should return */ +/* a non-zero value if the result needs to be transformed. The */ +/* transform_fn receives the BDD manager, two longs (the input value), */ +/* pointers to two longs (for the output) and the value of env. This */ +/* should not be called after any MTBDD terminals are created. */ + +void +#if defined(__STDC__) +mtbdd_transform_closure(cmu_bdd_manager bddm, + int (*canonical_fn)(cmu_bdd_manager, INT_PTR, INT_PTR, pointer), + void (*transform_fn)(cmu_bdd_manager, INT_PTR, INT_PTR, INT_PTR *, INT_PTR *, pointer), + pointer transform_env) +#else +mtbdd_transform_closure(bddm, canonical_fn, transform_fn, transform_env) + cmu_bdd_manager bddm; + int (*canonical_fn)(); + void (*transform_fn)(); + pointer transform_env; +#endif +{ + bddm->transform_fn=transform_fn; + bddm->transform_env=transform_env; + bddm->canonical_fn=canonical_fn; +} + + +/* mtcmu_bdd_one_data(bddm, value1, value2) sets the MTBDD value for TRUE. */ +/* This should not be called after MTBDD terminals have been created. */ + +void +#if defined(__STDC__) +mtcmu_bdd_one_data(cmu_bdd_manager bddm, INT_PTR value1, INT_PTR value2) +#else +mtcmu_bdd_one_data(bddm, value1, value2) + cmu_bdd_manager bddm; + INT_PTR value1; + INT_PTR value2; +#endif +{ + var_table table; + long hash; + + table=bddm->unique_table.tables[BDD_CONST_INDEXINDEX]; + if (table->entries != 1) + cmu_bdd_fatal("mtcmu_bdd_one_data: other terminal nodes already exist"); + hash=HASH_NODE(bddm->one->data[0], bddm->one->data[1]); + BDD_REDUCE(hash, table->size); + table->table[hash]=0; + bddm->one->data[0]=value1; + bddm->one->data[1]=value2; + hash=HASH_NODE(bddm->one->data[0], bddm->one->data[1]); + BDD_REDUCE(hash, table->size); + table->table[hash]=bddm->one; +} + + +/* cmu_mtbdd_free_terminal_closure(bddm, free_terminal_fn, free_terminal_env) */ +/* sets the closure to be invoked on when freeing MTBDD terminals. If */ +/* free_terminal_fn is null, it indicates that no function should be */ +/* called. The free_terminal_fn gets the BDD manager, two longs */ +/* holding the data for the terminal, and the value of free_terminal_env. */ + +void +#if defined(__STDC__) +cmu_mtbdd_free_terminal_closure(cmu_bdd_manager bddm, + void (*free_terminal_fn)(cmu_bdd_manager, INT_PTR, INT_PTR, pointer), + pointer free_terminal_env) +#else +cmu_mtbdd_free_terminal_closure(bddm, free_terminal_fn, free_terminal_env) + cmu_bdd_manager bddm; + void (*free_terminal_fn)(); + pointer free_terminal_env; +#endif +{ + bddm->unique_table.free_terminal_fn=free_terminal_fn; + bddm->unique_table.free_terminal_env=free_terminal_env; +} + + +/* cmu_mtbdd_get_terminal(bddm, value1, value2) returns the multi-terminal */ +/* BDD for a constant. */ + +bdd +#if defined(__STDC__) +cmu_mtbdd_get_terminal(cmu_bdd_manager bddm, INT_PTR value1, INT_PTR value2) +#else +cmu_mtbdd_get_terminal(bddm, value1, value2) + cmu_bdd_manager bddm; + INT_PTR value1; + INT_PTR value2; +#endif +{ + FIREWALL(bddm); + RETURN_BDD(bdd_find_terminal(bddm, value1, value2)); +} + + +/* cmu_mtbdd_terminal_value(bddm, f, value1, value2) returns the data value */ +/* for the terminal node f. */ + +void +#if defined(__STDC__) +cmu_mtbdd_terminal_value(cmu_bdd_manager bddm, bdd f, INT_PTR *value1, INT_PTR *value2) +#else +cmu_mtbdd_terminal_value(bddm, f, value1, value2) + cmu_bdd_manager bddm; + bdd f; + INT_PTR *value1; + INT_PTR *value2; +#endif +{ + if (bdd_check_arguments(1, f)) + { + BDD_SETUP(f); + if (!BDD_IS_CONST(f)) + { + cmu_bdd_warning("mtbdd_terminal_data: argument is terminal node"); + *value1=0; + *value2=0; + return; + } + cmu_mtbdd_terminal_value_aux(bddm, f, value1, value2); + } +} + + +static +bdd +#if defined(__STDC__) +mtcmu_bdd_ite_step(cmu_bdd_manager bddm, bdd f, bdd g, bdd h) +#else +mtcmu_bdd_ite_step(bddm, f, g, h) + cmu_bdd_manager bddm; + bdd f; + bdd g; + bdd h; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd h1, h2; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + BDD_SETUP(g); + BDD_SETUP(h); + if (BDD_IS_CONST(f)) + { + if (f == BDD_ONE(bddm)) + { + BDD_TEMP_INCREFS(g); + return (g); + } + BDD_TEMP_INCREFS(h); + return (h); + } + /* f is not constant. */ + if (g == h) + { + BDD_TEMP_INCREFS(g); + return (g); + } + /* f is not constant, g and h are distinct. */ + if (!BDD_IS_OUTPOS(f)) + { + f=BDD_NOT(f); + BDD_SWAP(g, h); + } + /* f is now an uncomplemented output pointer. */ + if (bdd_lookup_in_cache31(bddm, CACHE_TYPE_ITE, (INT_PTR)f, (INT_PTR)g, (INT_PTR)h, (INT_PTR *)&result)) + return (result); + BDD_TOP_VAR3(top_indexindex, bddm, f, g, h); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + BDD_COFACTOR(top_indexindex, h, h1, h2); + temp1=mtcmu_bdd_ite_step(bddm, f1, g1, h1); + temp2=mtcmu_bdd_ite_step(bddm, f2, g2, h2); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache31(bddm, CACHE_TYPE_ITE, (INT_PTR)f, (INT_PTR)g, (INT_PTR)h, (INT_PTR)result); + return (result); +} + + +/* mtcmu_bdd_ite(bddm, f, g, h) returns the BDD for "if f then g else h", */ +/* where g and h are multi-terminal BDDs. */ + +bdd +#if defined(__STDC__) +mtcmu_bdd_ite(cmu_bdd_manager bddm, bdd f, bdd g, bdd h) +#else +mtcmu_bdd_ite(bddm, f, g, h) + cmu_bdd_manager bddm; + bdd f; + bdd g; + bdd h; +#endif +{ + if (bdd_check_arguments(3, f, g, h)) + { + FIREWALL(bddm); + RETURN_BDD(mtcmu_bdd_ite_step(bddm, f, g, h)); + } + return ((bdd)0); +} + + +/* mtcmu_bdd_substitute(bddm, f) does the analog of cmu_bdd_substitute for MTBDDs. */ + +bdd +#if defined(__STDC__) +mtcmu_bdd_substitute(cmu_bdd_manager bddm, bdd f) +#else +mtcmu_bdd_substitute(bddm, f) + cmu_bdd_manager bddm; + bdd f; +#endif +{ + long op; + + if (bdd_check_arguments(1, f)) + { + FIREWALL(bddm); + if (bddm->curr_assoc_id == -1) + op=bddm->temp_op--; + else + op=OP_SUBST+bddm->curr_assoc_id; + RETURN_BDD(cmu_bdd_substitute_step(bddm, f, op, mtcmu_bdd_ite_step, bddm->curr_assoc)); + } + return ((bdd)0); +} + + +static +bdd +#if defined(__STDC__) +cmu_mtbdd_equal_step(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_mtbdd_equal_step(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd temp1, temp2; + bdd result; + + BDD_SETUP(f); + BDD_SETUP(g); + if (f == g) + return (BDD_ONE(bddm)); + if (BDD_IS_CONST(f) && BDD_IS_CONST(g)) + return (BDD_ZERO(bddm)); + if (BDD_OUT_OF_ORDER(f, g)) + BDD_SWAP(f, g); + if (bdd_lookup_in_cache2(bddm, OP_EQUAL, f, g, &result)) + return (result); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + temp1=cmu_mtbdd_equal_step(bddm, f1, g1); + temp2=cmu_mtbdd_equal_step(bddm, f2, g2); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache2(bddm, OP_EQUAL, f, g, result); + return (result); +} + + +/* cmu_mtbdd_equal(bddm, f, g) returns a BDD indicating when the */ +/* multi-terminal BDDs f and g are equal. */ + +bdd +#if defined(__STDC__) +cmu_mtbdd_equal(cmu_bdd_manager bddm, bdd f, bdd g) +#else +cmu_mtbdd_equal(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + if (bdd_check_arguments(2, f, g)) + { + FIREWALL(bddm); + RETURN_BDD(cmu_mtbdd_equal_step(bddm, f, g)); + } + return ((bdd)0); +} diff --git a/sis/bdd_cmu/bdd_cmu/testbdd.c b/sis/bdd_cmu/bdd_cmu/testbdd.c new file mode 100644 index 0000000..ba7664c --- /dev/null +++ b/sis/bdd_cmu/bdd_cmu/testbdd.c @@ -0,0 +1,1308 @@ +/* Basic operation tests */ + + +#include +#if defined(__STDC__) +#include +#else +#include +#endif +#include "bddint.h" + + +#define VARS 500 + + +#define TT_BITS 32 /* Size of tt in bits */ +#define TT_VARS 5 /* log2 of BITS */ +/* Also see cofactor_masks below. */ + + +#define ITERATIONS 20000 /* Number of trials to run */ + + +#if defined(__STDC__) +extern void srandom(int); +extern long random(void); +extern char *mktemp(char *); +extern int unlink(char *); +#else +extern void srandom(); +extern long random(); +extern char *mktemp(); +extern int unlink(); +#endif + + +typedef unsigned long tt; /* "Truth table" */ + + +static cmu_bdd_manager bddm; + + +static bdd vars[VARS]; +static bdd aux_vars[VARS]; + + +static tt cofactor_masks[]= +{ + 0xffff0000, + 0xff00ff00, + 0xf0f0f0f0, + 0xcccccccc, + 0xaaaaaaaa, +}; + + +static +bdd +#if defined(__STDC__) +decode(int var, tt table) +#else +decode(var, table) + int var; + tt table; +#endif +{ + bdd temp1, temp2; + bdd result; + + if (var == TT_VARS) + return ((table & 1) ? cmu_bdd_one(bddm) : cmu_bdd_zero(bddm)); + temp1=decode(var+1, table >> (1 << (TT_VARS-var-1))); + temp2=decode(var+1, table); + result=cmu_bdd_ite(bddm, vars[var], temp1, temp2); + cmu_bdd_free(bddm, temp1); + cmu_bdd_free(bddm, temp2); + return (result); +} + + +#define encoding_to_bdd(table) (decode(0, (table))) + + +static INT_PTR as_double_space[2]; + + +static +double +#if defined(__STDC__) +as_double(INT_PTR v1, INT_PTR v2) +#else +as_double(v1, v2) + INT_PTR v1; + INT_PTR v2; +#endif +{ + as_double_space[0]=v1; + as_double_space[1]=v2; + return (*(double *)as_double_space); +} + + +static +void +#if defined(__STDC__) +as_INT_PTRs(double n, INT_PTR *r1, INT_PTR *r2) +#else +as_INT_PTRs(n, r1, r2) + double n; + INT_PTR *r1; + INT_PTR *r2; +#endif +{ + (*(double *)as_double_space)=n; + *r1=as_double_space[0]; + *r2=as_double_space[1]; +} + + +static +char * +#if defined(__STDC__) +terminal_id_fn(cmu_bdd_manager bddm, INT_PTR v1, INT_PTR v2, pointer junk) +#else +terminal_id_fn(bddm, v1, v2, junk) + cmu_bdd_manager bddm; + INT_PTR v1; + INT_PTR v2; + pointer junk; +#endif +{ + static char result[100]; + + sprintf(result, "%g", as_double(v1, v2)); + return (result); +} + + +static +void +#if defined(__STDC__) +print_bdd(bdd f) +#else +print_bdd(f) + bdd f; +#endif +{ + cmu_bdd_print_bdd(bddm, f, bdd_naming_fn_none, terminal_id_fn, (pointer)0, stderr); +} + + +#if defined(__STDC__) +static +void +error(char *op, bdd result, bdd expected, ...) +{ + int i; + va_list ap; + bdd f; + + va_start(ap, expected); + fprintf(stderr, "\nError: operation %s:\n", op); + i=0; + while (1) + { + f=va_arg(ap, bdd); + if (f) + { + ++i; + fprintf(stderr, "Argument %d:\n", i); + print_bdd(f); + } + else + break; + } + fprintf(stderr, "Result:\n"); + print_bdd(result); + fprintf(stderr, "Expected result:\n"); + print_bdd(expected); + va_end(ap); +} +#else +static +void +error(va_alist) + va_dcl +{ + int i; + va_list ap; + char *op; + bdd result; + bdd expected; + bdd f; + + va_start(ap); + op=va_arg(ap, char *); + result=va_arg(ap, bdd); + expected=va_arg(ap, bdd); + fprintf(stderr, "\nError: operation %s:\n", op); + i=0; + while (1) + { + f=va_arg(ap, bdd); + if (f) + { + ++i; + fprintf(stderr, "Argument %d:\n", i); + print_bdd(f); + } + else + break; + } + fprintf(stderr, "Result:\n"); + print_bdd(result); + fprintf(stderr, "Expected result:\n"); + print_bdd(expected); + va_end(ap); +} +#endif + + +static +tt +#if defined(__STDC__) +cofactor(tt table, int var, int value) +#else +cofactor(table, var, value) + tt table; + int var; + int value; +#endif +{ + int shift; + + shift=1 << (TT_VARS-var-1); + if (value) + { + table&=cofactor_masks[var]; + table|=table >> shift; + } + else + { + table&=~cofactor_masks[var]; + table|=table << shift; + } + return (table); +} + + +static +void +#if defined(__STDC__) +test_ite(bdd f1, tt table1, bdd f2, tt table2, bdd f3, tt table3) +#else +test_ite(f1, table1, f2, table2, f3, table3) + bdd f1; + tt table1; + bdd f2; + tt table2; + bdd f3; + tt table3; +#endif +{ + bdd result; + tt resulttable; + bdd expected; + + result=cmu_bdd_ite(bddm, f1, f2, f3); + resulttable=(table1 & table2) | (~table1 & table3); + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("ITE", result, expected, f1, f2, f3, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_and(bdd f1, tt table1, bdd f2, tt table2) +#else +test_and(f1, table1, f2, table2) + bdd f1; + tt table1; + bdd f2; + tt table2; +#endif +{ + bdd result; + tt resulttable; + bdd expected; + + result=cmu_bdd_and(bddm, f1, f2); + resulttable=table1 & table2; + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("and", result, expected, f1, f2, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_or(bdd f1, tt table1, bdd f2, tt table2) +#else +test_or(f1, table1, f2, table2) + bdd f1; + tt table1; + bdd f2; + tt table2; +#endif +{ + bdd result; + tt resulttable; + bdd expected; + + result=cmu_bdd_or(bddm, f1, f2); + resulttable=table1 | table2; + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("or", result, expected, f1, f2, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_xor(bdd f1, tt table1, bdd f2, tt table2) +#else +test_xor(f1, table1, f2, table2) + bdd f1; + tt table1; + bdd f2; + tt table2; +#endif +{ + bdd result; + tt resulttable; + bdd expected; + + result=cmu_bdd_xor(bddm, f1, f2); + resulttable=table1 ^ table2; + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("xor", result, expected, f1, f2, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_id_not(bdd f, tt table) +#else +test_id_not(f, table) + bdd f; + tt table; +#endif +{ + bdd result; + tt resulttable; + bdd expected; + + result=cmu_bdd_not(bddm, f); + resulttable= ~table; + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("not", result, expected, f, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); + result=cmu_bdd_identity(bddm, f); + resulttable=table; + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("identity", result, expected, f, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_compose(bdd f1, tt table1, bdd f2, tt table2) +#else +test_compose(f1, table1, f2, table2) + bdd f1; + tt table1; + bdd f2; + tt table2; +#endif +{ + int var; + bdd result; + tt resulttable; + bdd expected; + + var=((unsigned long)random())%TT_VARS; + result=cmu_bdd_compose(bddm, f1, vars[var], cmu_bdd_one(bddm)); + resulttable=cofactor(table1, var, 1); + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("restrict1", result, expected, f1, vars[var], (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); + result=cmu_bdd_compose(bddm, f1, vars[var], cmu_bdd_zero(bddm)); + resulttable=cofactor(table1, var, 0); + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("restrict0", result, expected, f1, vars[var], (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); + result=cmu_bdd_compose(bddm, f1, vars[var], f2); + resulttable=(table2 & cofactor(table1, var, 1)) | (~table2 & cofactor(table1, var, 0)); + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("compose", result, expected, f1, vars[var], f2, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_qnt(bdd f, tt table) +#else +test_qnt(f, table) + bdd f; + tt table; +#endif +{ + int var1, var2; + bdd assoc[3]; + bdd temp; + bdd result; + tt resulttable; + bdd expected; + + var1=((unsigned long)random())%TT_VARS; + do + var2=((unsigned long)random())%TT_VARS; + while (var1 == var2); + assoc[0]=vars[var1]; + assoc[1]=vars[var2]; + assoc[2]=0; + cmu_bdd_temp_assoc(bddm, assoc, 0); + cmu_bdd_assoc(bddm, -1); + if (random()%2) + result=cmu_bdd_exists(bddm, f); + else + { + temp=cmu_bdd_not(bddm, f); + result=cmu_bdd_forall(bddm, temp); + cmu_bdd_free(bddm, temp); + temp=result; + result=cmu_bdd_not(bddm, temp); + cmu_bdd_free(bddm, temp); + } + resulttable=cofactor(table, var1, 1) | cofactor(table, var1, 0); + resulttable=cofactor(resulttable, var2, 1) | cofactor(resulttable, var2, 0); + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("quantification", result, expected, f, vars[var1], vars[var2], (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_rel_prod(bdd f1, tt table1, bdd f2, tt table2) +#else +test_rel_prod(f1, table1, f2, table2) + bdd f1; + tt table1; + bdd f2; + tt table2; +#endif +{ + int var1, var2; + bdd assoc[3]; + bdd result; + tt resulttable; + bdd expected; + + var1=((unsigned long)random())%TT_VARS; + do + var2=((unsigned long)random())%TT_VARS; + while (var1 == var2); + assoc[0]=vars[var1]; + assoc[1]=vars[var2]; + assoc[2]=0; + cmu_bdd_temp_assoc(bddm, assoc, 0); + cmu_bdd_assoc(bddm, -1); + result=cmu_bdd_rel_prod(bddm, f1, f2); + table1&=table2; + resulttable=cofactor(table1, var1, 1) | cofactor(table1, var1, 0); + resulttable=cofactor(resulttable, var2, 1) | cofactor(resulttable, var2, 0); + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("relational product", result, expected, f1, f2, vars[var1], vars[var2], (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_subst(bdd f1, tt table1, bdd f2, tt table2, bdd f3, tt table3) +#else +test_subst(f1, table1, f2, table2, f3, table3) + bdd f1; + tt table1; + bdd f2; + tt table2; + bdd f3; + tt table3; +#endif +{ + int var1, var2; + bdd assoc[6]; + bdd result; + tt resulttable; + tt temp1, temp2, temp3, temp4; + bdd expected; + + var1=((unsigned long)random())%TT_VARS; + do + var2=((unsigned long)random())%TT_VARS; + while (var1 == var2); + assoc[0]=vars[var1]; + assoc[1]=f2; + assoc[2]=vars[var2]; + assoc[3]=f3; + assoc[4]=0; + assoc[5]=0; + cmu_bdd_temp_assoc(bddm, assoc, 1); + cmu_bdd_assoc(bddm, -1); + result=cmu_bdd_substitute(bddm, f1); + temp1=cofactor(cofactor(table1, var1, 1), var2, 1); + temp2=cofactor(cofactor(table1, var1, 1), var2, 0); + temp3=cofactor(cofactor(table1, var1, 0), var2, 1); + temp4=cofactor(cofactor(table1, var1, 0), var2, 0); + resulttable=table2 & table3 & temp1; + resulttable|=table2 & ~table3 & temp2; + resulttable|=~table2 & table3 & temp3; + resulttable|=~table2 & ~table3 & temp4; + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("substitute", result, expected, f1, vars[var1], f2, vars[var2], f3, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_inter_impl(bdd f1, tt table1, bdd f2, tt table2) +#else +test_inter_impl(f1, table1, f2, table2) + bdd f1; + tt table1; + bdd f2; + tt table2; +#endif +{ + bdd result; + tt resulttable; + bdd expected; + bdd implies_result; + + result=cmu_bdd_intersects(bddm, f1, f2); + resulttable=table1 & table2; + expected=encoding_to_bdd(resulttable); + implies_result=cmu_bdd_implies(bddm, result, expected); + if (implies_result != cmu_bdd_zero(bddm)) + { + error("intersection test", result, expected, f1, f2, (bdd)0); + cmu_bdd_free(bddm, implies_result); + } + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_sat(bdd f, tt table) +#else +test_sat(f, table) + bdd f; + tt table; +#endif +{ + int var1, var2; + bdd assoc[TT_VARS+1]; + bdd result; + bdd temp1, temp2, temp3; + + if (f == cmu_bdd_zero(bddm)) + return; + result=cmu_bdd_satisfy(bddm, f); + temp1=cmu_bdd_not(bddm, f); + temp2=cmu_bdd_intersects(bddm, temp1, result); + if (temp2 != cmu_bdd_zero(bddm)) + error("intersection of satisfy result with negated argument", temp2, cmu_bdd_zero(bddm), f, (bdd)0); + cmu_bdd_free(bddm, temp1); + cmu_bdd_free(bddm, temp2); + var1=((unsigned long)random())%TT_VARS; + do + var2=((unsigned long)random())%TT_VARS; + while (var1 == var2); + assoc[0]=vars[var1]; + assoc[1]=vars[var2]; + assoc[2]=0; + cmu_bdd_temp_assoc(bddm, assoc, 0); + cmu_bdd_assoc(bddm, -1); + temp1=cmu_bdd_satisfy_support(bddm, result); + temp2=cmu_bdd_not(bddm, result); + temp3=cmu_bdd_intersects(bddm, temp2, temp1); + if (temp3 != cmu_bdd_zero(bddm)) + error("intersection of satisfy support result with negated argument", temp3, cmu_bdd_zero(bddm), result, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, temp1); + cmu_bdd_free(bddm, temp2); + cmu_bdd_free(bddm, temp3); + temp1=cmu_bdd_compose(bddm, f, vars[var1], cmu_bdd_zero(bddm)); + temp2=cmu_bdd_compose(bddm, f, vars[var1], cmu_bdd_one(bddm)); + if (cmu_bdd_satisfying_fraction(bddm, temp1)+cmu_bdd_satisfying_fraction(bddm, temp2) != + 2.0*cmu_bdd_satisfying_fraction(bddm, f)) + { + fprintf(stderr, "\nError: operation satisfying fraction:\n"); + fprintf(stderr, "Argument:\n"); + print_bdd(f); + fprintf(stderr, "Cofactor on:\n"); + print_bdd(vars[var1]); + } + cmu_bdd_free(bddm, temp1); + cmu_bdd_free(bddm, temp2); +} + + +static +void +#if defined(__STDC__) +test_gen_cof(bdd f1, tt table1, bdd f2, tt table2) +#else +test_gen_cof(f1, table1, f2, table2) + bdd f1; + tt table1; + bdd f2; + tt table2; +#endif +{ + int var1, var2; + bdd result; + bdd temp1, temp2, temp3; + tt resulttable; + bdd expected; + + result=cmu_bdd_cofactor(bddm, f1, f2); + temp1=cmu_bdd_xnor(bddm, result, f1); + temp2=cmu_bdd_not(bddm, f2); + temp3=cmu_bdd_or(bddm, temp1, temp2); + if (temp3 != cmu_bdd_one(bddm)) + error("d.c. comparison of generalized cofactor", temp3, cmu_bdd_one(bddm), f1, f2, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, temp1); + cmu_bdd_free(bddm, temp2); + cmu_bdd_free(bddm, temp3); + var1=((unsigned long)random())%TT_VARS; + do + var2=((unsigned long)random())%TT_VARS; + while (var1 == var2); + temp1=cmu_bdd_not(bddm, vars[var2]); + temp2=cmu_bdd_and(bddm, vars[var1], temp1); + cmu_bdd_free(bddm, temp1); + result=cmu_bdd_cofactor(bddm, f1, temp2); + resulttable=cofactor(cofactor(table1, var1, 1), var2, 0); + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("generalized cofactor", result, expected, f1, temp2, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); + cmu_bdd_free(bddm, temp2); +} + + +static +void +#if defined(__STDC__) +test_reduce(bdd f1, tt table1, bdd f2, tt table2) +#else +test_reduce(f1, table1, f2, table2) + bdd f1; + tt table1; + bdd f2; + tt table2; +#endif +{ + bdd result; + bdd temp1, temp2, temp3; + + result=cmu_bdd_reduce(bddm, f1, f2); + temp1=cmu_bdd_xnor(bddm, result, f1); + temp2=cmu_bdd_not(bddm, f2); + temp3=cmu_bdd_or(bddm, temp1, temp2); + if (temp3 != cmu_bdd_one(bddm)) + error("d.c. comparison of reduce", temp3, cmu_bdd_one(bddm), f1, f2, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, temp1); + cmu_bdd_free(bddm, temp2); + cmu_bdd_free(bddm, temp3); +} + + +static +bdd +#if defined(__STDC__) +apply_and(cmu_bdd_manager bddm, bdd *f, bdd *g, pointer env) +#else +apply_and(bddm, f, g, env) + cmu_bdd_manager bddm; + bdd *f; + bdd *g; + pointer env; +#endif +{ + bdd f1, g1; + + f1= *f; + g1= *g; + { + if (f1 == BDD_ZERO(bddm)) + return (f1); + if (g1 == BDD_ZERO(bddm)) + return (g1); + if (f1 == BDD_ONE(bddm)) + return (g1); + if (g1 == BDD_ONE(bddm)) + return (f1); + if ((INT_PTR)f1 < (INT_PTR)g1) + { + *f=g1; + *g=f1; + } + return ((bdd)0); + } +} + + +static +void +#if defined(__STDC__) +test_apply(bdd f1, tt table1, bdd f2, tt table2) +#else +test_apply(f1, table1, f2, table2) + bdd f1; + tt table1; + bdd f2; + tt table2; +#endif +{ + bdd result; + tt resulttable; + bdd expected; + + result=bdd_apply2(bddm, apply_and, f1, f2, (pointer)0); + resulttable=table1 & table2; + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("apply2", result, expected, f1, f2, (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +void +#if defined(__STDC__) +test_size(bdd f1, tt table1, bdd f2, tt table2) +#else +test_size(f1, table1, f2, table2) + bdd f1; + tt table1; + bdd f2; + tt table2; +#endif +{ + int i; + long size; + long profile[2*TT_VARS+1]; + bdd fs[3]; + + size=cmu_bdd_size(bddm, f1, 1); + cmu_bdd_profile(bddm, f1, profile, 1); + for (i=0; i < 2*TT_VARS+1; ++i) + size-=profile[i]; + if (size) + { + fprintf(stderr, "\nError: size count vs. profile sum:\n"); + fprintf(stderr, "Argument:\n"); + print_bdd(f1); + } + size=cmu_bdd_size(bddm, f1, 0); + cmu_bdd_profile(bddm, f1, profile, 0); + for (i=0; i < 2*TT_VARS+1; ++i) + size-=profile[i]; + if (size) + { + fprintf(stderr, "\nError: no negout size count vs. profile sum:\n"); + fprintf(stderr, "Argument:\n"); + print_bdd(f1); + } + fs[0]=f1; + fs[1]=f2; + fs[2]=0; + size=cmu_bdd_size_multiple(bddm, fs, 1); + cmu_bdd_profile_multiple(bddm, fs, profile, 1); + for (i=0; i < 2*TT_VARS+1; ++i) + size-=profile[i]; + if (size) + { + fprintf(stderr, "\nError: multiple size count vs. multiple profile sum:\n"); + fprintf(stderr, "Argument 1:\n"); + print_bdd(f1); + fprintf(stderr, "Argument 2:\n"); + print_bdd(f2); + } +} + + +static +int +#if defined(__STDC__) +canonical_fn(cmu_bdd_manager bddm, INT_PTR v1, INT_PTR v2, pointer env) +#else +canonical_fn(bddm, v1, v2, env) + cmu_bdd_manager bddm; + INT_PTR v1; + INT_PTR v2; + pointer env; +#endif +{ + return (as_double(v1, v2) > 0); +} + + +static +void +#if defined(__STDC__) +transform_fn(cmu_bdd_manager bddm, INT_PTR v1, INT_PTR v2, INT_PTR *r1, INT_PTR *r2, pointer env) +#else +transform_fn(bddm, v1, v2, r1, r2, env) + cmu_bdd_manager bddm; + INT_PTR v1; + INT_PTR v2; + INT_PTR *r1; + INT_PTR *r2; + pointer env; +#endif +{ + as_INT_PTRs(-as_double(v1, v2), r1, r2); +} + + +static +bdd +#if defined(__STDC__) +terminal(double n) +#else +terminal(n) + double n; +#endif +{ + INT_PTR v1, v2; + + as_INT_PTRs(n, &v1, &v2); + return (cmu_mtbdd_get_terminal(bddm, v1, v2)); +} + + +static +bdd +#if defined(__STDC__) +walsh_matrix(int n) +#else +walsh_matrix(n) + int n; +#endif +{ + bdd temp1, temp2, temp3; + bdd result; + + if (n == TT_VARS) + return (terminal(1.0)); + temp1=walsh_matrix(n+1); + temp2=mtbdd_transform(bddm, temp1); + temp3=temp2; + temp2=mtcmu_bdd_ite(bddm, aux_vars[n], temp3, temp1); + cmu_bdd_free(bddm, temp3); + result=mtcmu_bdd_ite(bddm, vars[n], temp2, temp1); + cmu_bdd_free(bddm, temp1); + cmu_bdd_free(bddm, temp2); + return (result); +} + + +#define OP_MULT 1000l +#define OP_ADD 1100l + + +static +bdd +#if defined(__STDC__) +mtbdd_mult_step(cmu_bdd_manager bddm, bdd f, bdd g) +#else +mtbdd_mult_step(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd temp1, temp2; + bdd result; + INT_PTR u1, u2; + INT_PTR v1, v2; + + BDD_SETUP(f); + BDD_SETUP(g); + if (BDD_IS_CONST(f) && BDD_IS_CONST(g)) + { + cmu_mtbdd_terminal_value_aux(bddm, f, &u1, &u2); + cmu_mtbdd_terminal_value_aux(bddm, g, &v1, &v2); + as_INT_PTRs(as_double(u1, u2)*as_double(v1, v2), &u1, &u2); + return (bdd_find_terminal(bddm, u1, u2)); + } + if (BDD_OUT_OF_ORDER(f, g)) + BDD_SWAP(f, g); + if (bdd_lookup_in_cache2(bddm, OP_MULT, f, g, &result)) + return (result); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + temp1=mtbdd_mult_step(bddm, f1, g1); + temp2=mtbdd_mult_step(bddm, f2, g2); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache2(bddm, OP_MULT, f, g, result); + return (result); +} + + +static +bdd +#if defined(__STDC__) +mtbdd_mult(cmu_bdd_manager bddm, bdd f, bdd g) +#else +mtbdd_mult(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + if (bdd_check_arguments(2, f, g)) + { + FIREWALL(bddm); + RETURN_BDD(mtbdd_mult_step(bddm, f, g)); + } + return ((bdd)0); +} + + +static +bdd +#if defined(__STDC__) +mtbdd_add_step(cmu_bdd_manager bddm, bdd f, bdd g) +#else +mtbdd_add_step(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + bdd_indexindex_type top_indexindex; + bdd f1, f2; + bdd g1, g2; + bdd temp1, temp2; + bdd result; + INT_PTR u1, u2; + INT_PTR v1, v2; + + BDD_SETUP(f); + BDD_SETUP(g); + if (BDD_IS_CONST(f) && BDD_IS_CONST(g)) + { + cmu_mtbdd_terminal_value_aux(bddm, f, &u1, &u2); + cmu_mtbdd_terminal_value_aux(bddm, g, &v1, &v2); + as_INT_PTRs(as_double(u1, u2)+as_double(v1, v2), &u1, &u2); + return (bdd_find_terminal(bddm, u1, u2)); + } + if (BDD_OUT_OF_ORDER(f, g)) + BDD_SWAP(f, g); + if (bdd_lookup_in_cache2(bddm, OP_ADD, f, g, &result)) + return (result); + BDD_TOP_VAR2(top_indexindex, bddm, f, g); + BDD_COFACTOR(top_indexindex, f, f1, f2); + BDD_COFACTOR(top_indexindex, g, g1, g2); + temp1=mtbdd_add_step(bddm, f1, g1); + temp2=mtbdd_add_step(bddm, f2, g2); + result=bdd_find(bddm, top_indexindex, temp1, temp2); + bdd_insert_in_cache2(bddm, OP_ADD, f, g, result); + return (result); +} + + +static +bdd +#if defined(__STDC__) +mtbdd_add(cmu_bdd_manager bddm, bdd f, bdd g) +#else +mtbdd_add(bddm, f, g) + cmu_bdd_manager bddm; + bdd f; + bdd g; +#endif +{ + if (bdd_check_arguments(2, f, g)) + { + FIREWALL(bddm); + RETURN_BDD(mtbdd_add_step(bddm, f, g)); + } + return ((bdd)0); +} + + +static +bdd +#if defined(__STDC__) +transform(bdd f, bdd g, bdd *elim_vars) +#else +transform(f, g, elim_vars) + bdd f; + bdd g; + bdd *elim_vars; +#endif +{ + int i; + bdd temp1, temp2; + bdd result; + + result=mtbdd_mult(bddm, f, g); + for (i=0; i < TT_VARS; ++i) + { + temp1=cmu_bdd_compose(bddm, result, elim_vars[i], cmu_bdd_one(bddm)); + temp2=cmu_bdd_compose(bddm, result, elim_vars[i], cmu_bdd_zero(bddm)); + cmu_bdd_free(bddm, result); + result=mtbdd_add(bddm, temp1, temp2); + cmu_bdd_free(bddm, temp1); + cmu_bdd_free(bddm, temp2); + } + return (result); +} + + +static +void +#if defined(__STDC__) +test_mtbdd(bdd f1, tt table1) +#else +test_mtbdd(f1, table1) + bdd f1; + tt table1; +#endif +{ + bdd wm; + bdd temp1, temp2; + bdd result; + + wm=walsh_matrix(0); + temp1=transform(wm, f1, vars); + temp2=temp1; + temp1=transform(wm, temp2, aux_vars); + cmu_bdd_free(bddm, wm); + cmu_bdd_free(bddm, temp2); + temp2=terminal(1.0/TT_BITS); + result=mtbdd_mult(bddm, temp1, temp2); + cmu_bdd_free(bddm, temp1); + cmu_bdd_free(bddm, temp2); + if (f1 != result) + error("Walsh transformation and inverse", result, f1, (bdd)0); + cmu_bdd_free(bddm, result); +} + + +static +void +#if defined(__STDC__) +test_swap(bdd f, tt table) +#else +test_swap(f, table) + bdd f; + tt table; +#endif +{ + int var1, var2; + bdd result; + tt resulttable; + tt temp1, temp2, temp3, temp4; + bdd expected; + + var1=((unsigned long)random())%TT_VARS; + var2=((unsigned long)random())%TT_VARS; + result=cmu_bdd_swap_vars(bddm, f, vars[var1], vars[var2]); + temp1=cofactor(cofactor(table, var1, 1), var2, 1); + temp2=cofactor(cofactor(table, var1, 1), var2, 0); + temp3=cofactor(cofactor(table, var1, 0), var2, 1); + temp4=cofactor(cofactor(table, var1, 0), var2, 0); + resulttable=cofactor_masks[var2] & cofactor_masks[var1] & temp1; + resulttable|=cofactor_masks[var2] & ~cofactor_masks[var1] & temp2; + resulttable|=~cofactor_masks[var2] & cofactor_masks[var1] & temp3; + resulttable|=~cofactor_masks[var2] & ~cofactor_masks[var1] & temp4; + expected=encoding_to_bdd(resulttable); + if (result != expected) + error("swap variables", result, expected, f, vars[var1], vars[var2], (bdd)0); + cmu_bdd_free(bddm, result); + cmu_bdd_free(bddm, expected); +} + + +static +char filename[]="/tmp/tmpXXXXXX"; + + +static +void +#if defined(__STDC__) +test_dump(bdd f, tt table) +#else +test_dump(f, table) + bdd f; + tt table; +#endif +{ + FILE *fp; + int i, j; + bdd dump_vars[TT_VARS+1]; + bdd temp; + bdd result; + int err; + + mktemp(filename); + if (!(fp=fopen(filename, "w+"))) + { + fprintf(stderr, "could not open temporary file %s\n", filename); + exit(1); + } + unlink(filename); + for (i=0; i < TT_VARS; ++i) + dump_vars[i]=vars[i]; + dump_vars[i]=0; + for (i=0; i < TT_VARS-1; ++i) + { + j=i+((unsigned long)random())%(TT_VARS-i); + temp=dump_vars[i]; + dump_vars[i]=dump_vars[j]; + dump_vars[j]=temp; + } + if (!cmu_bdd_dump_bdd(bddm, f, dump_vars, fp)) + { + fprintf(stderr, "Error: dump failure:\n"); + fprintf(stderr, "Argument:\n"); + print_bdd(f); + fclose(fp); + return; + } + rewind(fp); + if (!(result=cmu_bdd_undump_bdd(bddm, dump_vars, fp, &err)) || err) + { + fprintf(stderr, "Error: undump failure: code %d:\n", err); + fprintf(stderr, "Argument:\n"); + print_bdd(f); + fclose(fp); + return; + } + fclose(fp); + if (result != f) + error("dump/undump", result, f, f, (bdd)0); + cmu_bdd_free(bddm, result); +} + + +static +void +#if defined(__STDC__) +check_leak(void) +#else +check_leak() +#endif +{ + bdd assoc[1]; + + assoc[0]=0; + cmu_bdd_temp_assoc(bddm, assoc, 0); + cmu_bdd_gc(bddm); + if (cmu_bdd_total_size(bddm) != 2*TT_VARS+1l) + fprintf(stderr, "Memory leak somewhere...\n"); +} + + +static +void +#if defined(__STDC__) +random_tests(int iterations) +#else +random_tests(iterations) + int iterations; +#endif +{ + int i; + tt table1, table2, table3; + bdd f1, f2, f3; + INT_PTR v1, v2; + + printf("Random operation tests...\n"); + bddm=cmu_bdd_init(); + cmu_bdd_node_limit(bddm, 5000); + mtbdd_transform_closure(bddm, canonical_fn, transform_fn, (pointer)0); + as_INT_PTRs(-1.0, &v1, &v2); + mtcmu_bdd_one_data(bddm, v1, v2); + vars[1]=cmu_bdd_new_var_last(bddm); + vars[0]=cmu_bdd_new_var_first(bddm); + vars[4]=cmu_bdd_new_var_after(bddm, vars[1]); + vars[3]=cmu_bdd_new_var_before(bddm, vars[4]); + vars[2]=cmu_bdd_new_var_after(bddm, vars[1]); + for (i=0; i < 5; ++i) + aux_vars[i]=cmu_bdd_new_var_after(bddm, vars[i]); + for (i=0; i < iterations; ++i) + { + if ((i & 0xf) == 0) + { + putchar('.'); + fflush(stdout); + } + if ((i & 0x3ff) == 0x3ff) + { + putchar('\n'); + fflush(stdout); + check_leak(); + } + table1=random(); + table2=random(); + table3=random(); + f1=encoding_to_bdd(table1); + f2=encoding_to_bdd(table2); + f3=encoding_to_bdd(table3); + test_ite(f1, table1, f2, table2, f3, table3); + test_and(f1, table1, f2, table2); + test_or(f1, table1, f2, table2); + test_xor(f1, table1, f2, table2); + test_id_not(f1, table1); + test_compose(f1, table1, f2, table2); + test_qnt(f1, table1); + test_rel_prod(f1, table1, f2, table2); + test_subst(f1, table1, f2, table2, f3, table3); + test_inter_impl(f1, table1, f2, table2); + test_sat(f1, table1); + test_gen_cof(f1, table1, f2, table2); + test_reduce(f1, table1, f2, table2); + test_apply(f1, table1, f2, table2); + test_size(f1, table1, f2, table2); + test_mtbdd(f1, table1); + test_swap(f1, table1); + if (i < 100) + test_dump(f1, table1); + cmu_bdd_free(bddm, f1); + cmu_bdd_free(bddm, f2); + cmu_bdd_free(bddm, f3); + } + putchar('\n'); + cmu_bdd_stats(bddm, stdout); + cmu_bdd_quit(bddm); +} + + +void +#if defined(__STDC__) +main(void) +#else +main() +#endif +{ + srandom(1); + random_tests(ITERATIONS); +} diff --git a/sis/bdd_cmu/bdd_port/Makefile.am b/sis/bdd_cmu/bdd_port/Makefile.am new file mode 100644 index 0000000..e191e54 --- /dev/null +++ b/sis/bdd_cmu/bdd_port/Makefile.am @@ -0,0 +1,10 @@ +AM_CPPFLAGS = -I../../include -I$(srcdir)/../bdd_cmu -I$(srcdir)/../mem + +libbdd_port_a_SOURCES_local = bdditer.c bddport.c bdd.h + +if SIS_COND_CMUBDD +noinst_LIBRARIES = libbdd_port.a +libbdd_port_a_SOURCES = $(libbdd_port_a_SOURCES_local) +endif + +EXTRA_DIST = $(libbdd_port_a_SOURCES_local) diff --git a/sis/bdd_cmu/bdd_port/Makefile.in b/sis/bdd_cmu/bdd_port/Makefile.in new file mode 100644 index 0000000..d083ea0 --- /dev/null +++ b/sis/bdd_cmu/bdd_port/Makefile.in @@ -0,0 +1,371 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(libbdd_port_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/bdd_cmu/bdd_port +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libbdd_port_a_AR = $(AR) $(ARFLAGS) +libbdd_port_a_LIBADD = +am__libbdd_port_a_SOURCES_DIST = bdditer.c bddport.c bdd.h +am__objects_1 = bdditer.$(OBJEXT) bddport.$(OBJEXT) +@SIS_COND_CMUBDD_TRUE@am_libbdd_port_a_OBJECTS = $(am__objects_1) +libbdd_port_a_OBJECTS = $(am_libbdd_port_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libbdd_port_a_SOURCES) +DIST_SOURCES = $(am__libbdd_port_a_SOURCES_DIST) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I../../include -I$(srcdir)/../bdd_cmu -I$(srcdir)/../mem +libbdd_port_a_SOURCES_local = bdditer.c bddport.c bdd.h +@SIS_COND_CMUBDD_TRUE@noinst_LIBRARIES = libbdd_port.a +@SIS_COND_CMUBDD_TRUE@libbdd_port_a_SOURCES = $(libbdd_port_a_SOURCES_local) +EXTRA_DIST = $(libbdd_port_a_SOURCES_local) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/bdd_cmu/bdd_port/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/bdd_cmu/bdd_port/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libbdd_port.a: $(libbdd_port_a_OBJECTS) $(libbdd_port_a_DEPENDENCIES) + -rm -f libbdd_port.a + $(libbdd_port_a_AR) libbdd_port.a $(libbdd_port_a_OBJECTS) $(libbdd_port_a_LIBADD) + $(RANLIB) libbdd_port.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/bdd_cmu/bdd_port/bdd.h b/sis/bdd_cmu/bdd_port/bdd.h new file mode 100644 index 0000000..b49906f --- /dev/null +++ b/sis/bdd_cmu/bdd_port/bdd.h @@ -0,0 +1,344 @@ +/* + * Revision Control Information + * + * /projects/hsis/CVS/utilities/bdd_cmu/bdd_port/bdd.h,v + * shiple + * 1.2 + * 1993/08/10 19:04:56 + * + */ + +/* + * This is the header file for the port from the UCB BDD package to the CMU BDD package. + */ + +#ifndef bdd_h /* { */ +#define bdd_h + +#include "var_set.h" + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef refany +/* this otta be a typedef somewhere */ +#define refany char * /* a void * or any sort of untyped pointer */ +#endif + +#ifndef any /* Ansi C defines this right? */ +/* this otta be a typedef somewhere */ +#define any char /* so that NIL(any) == refany */ +#endif + +/* + * Data structures and typedefs. + */ +#define boolean int +typedef struct bdd_manager_ bdd_manager; /* referenced via a pointer only */ +typedef unsigned int bdd_variableId; /* the id of the variable in a bdd node */ +typedef struct bdd_ bdd_node; /* referenced via a pointer only */ +typedef int bdd_literal; /* integers in the set { 0, 1, 2 } */ + +typedef struct bdd_t { + boolean free; /* TRUE if this is free, FALSE otherwise ... */ + struct bdd_ *node; /* ptr to the top node of the function */ + struct bdd_manager_ *mgr; /* the manager */ +} bdd_t; + +/* + * Initialization data structure. Not supported in CMU package. + */ +typedef struct bdd_mgr_init { + struct { + boolean on; /* TRUE/FALSE: is the cache on */ + unsigned int resize_at; /* percentage at which to resize (e.g. 85% is 85); doesn't apply to adhoc */ + unsigned int max_size; /* max allowable number of buckets; for adhoc, max allowable number of entries */ + } ITE_cache, + ITE_const_cache, + adhoc_cache; + struct { + boolean on; /* TRUE/FALSE: is the garbage collector on */ + } garbage_collector; + struct { + void (*daemon)(); /* used for callback when memory limit exceeded */ + unsigned int limit; /* upper bound on memory allocated by the manager; in megabytes */ + } memory; + struct { + float ratio; /* allocate new bdd_nodes to achieve ratio of used to unused nodes */ + unsigned int init_blocks; /* number of bdd_nodeBlocks initially allocated */ + } nodes; +} bdd_mgr_init; + +/* + * Match types for BDD minimization. + */ +typedef enum { + BDD_MIN_TSM, /* two-side match */ + BDD_MIN_OSM, /* one-side match */ + BDD_MIN_OSDM /* one-side DC match */ +} bdd_min_match_type_t; + +/* + * BDD Manager Allocation And Destruction + */ +EXTERN void bdd_end ARGS((bdd_manager *)); +EXTERN void bdd_register_daemon ARGS((bdd_manager *, void (*daemon)())); +EXTERN void bdd_set_mgr_init_dflts ARGS((bdd_mgr_init *)); +EXTERN bdd_manager *bdd_start ARGS((int)); +EXTERN bdd_manager *bdd_start_with_params ARGS((int, bdd_mgr_init *)); + +/* + * BDD Variable Allocation + */ +EXTERN bdd_t *bdd_create_variable ARGS((bdd_manager *)); +EXTERN bdd_t *bdd_get_variable ARGS((bdd_manager *, bdd_variableId)); + +/* + * BDD Formula Management + */ +EXTERN bdd_t *bdd_dup ARGS((bdd_t *)); +EXTERN void bdd_free ARGS((bdd_t *)); + +/* + * Operations on BDD Formulas + */ +EXTERN bdd_t *bdd_and ARGS((bdd_t *, bdd_t *, boolean, boolean)); +EXTERN bdd_t *bdd_and_smooth ARGS((bdd_t *, bdd_t *, array_t *)); +EXTERN bdd_t *bdd_between ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_cofactor ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_compose ARGS((bdd_t *, bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_consensus ARGS((bdd_t *, array_t *)); +EXTERN bdd_t *bdd_cproject ARGS((bdd_t *, array_t *)); +EXTERN bdd_t *bdd_else ARGS((bdd_t *)); +EXTERN bdd_t *bdd_ite ARGS((bdd_t *, bdd_t *, bdd_t *, boolean, boolean, boolean)); +EXTERN bdd_t *bdd_minimize ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_minimize_with_params ARGS((bdd_t *, bdd_t *, bdd_min_match_type_t, boolean, boolean, boolean)); +EXTERN bdd_t *bdd_not ARGS((bdd_t *)); +EXTERN bdd_t *bdd_one ARGS((bdd_manager *)); +EXTERN bdd_t *bdd_or ARGS((bdd_t *, bdd_t *, boolean, boolean)); +EXTERN bdd_t *bdd_smooth ARGS((bdd_t *, array_t *)); +EXTERN bdd_t *bdd_substitute ARGS((bdd_t *, array_t *, array_t *)); +EXTERN bdd_t *bdd_then ARGS((bdd_t *)); +EXTERN bdd_t *bdd_top_var ARGS((bdd_t *)); +EXTERN bdd_t *bdd_xnor ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_xor ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_zero ARGS((bdd_manager *)); + +/* + * Queries about BDD Formulas + */ +EXTERN boolean bdd_equal ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_intersects ARGS((bdd_t *, bdd_t *)); +EXTERN boolean bdd_is_tautology ARGS((bdd_t *, boolean)); +EXTERN boolean bdd_leq ARGS((bdd_t *, bdd_t *, boolean, boolean)); + +/* + * Statistics and Other Queries + */ +typedef struct bdd_cache_stats { + unsigned int hits; + unsigned int misses; + unsigned int collisions; + unsigned int inserts; +} bdd_cache_stats; + +typedef struct bdd_stats { + struct { + bdd_cache_stats hashtable; /* the unique table; collisions and inserts fields not used */ + bdd_cache_stats itetable; + bdd_cache_stats consttable; + bdd_cache_stats adhoc; + } cache; /* various cache statistics */ + struct { + unsigned int calls; + struct { + unsigned int trivial; + unsigned int cached; + unsigned int full; + } returns; + } ITE_ops, + ITE_constant_ops, + adhoc_ops; + struct { + unsigned int total; + } blocks; /* bdd_nodeBlock count */ + struct { + unsigned int used; + unsigned int unused; + unsigned int total; + unsigned int peak; + } nodes; /* bdd_node count */ + struct { + unsigned int used; + unsigned int unused; + unsigned int total; + unsigned int blocks; + } extptrs; /* bdd_t count */ + struct { + unsigned int times; /* the number of times the garbage-collector has run */ + unsigned int nodes_collected; /* cumulative number of nodes collected over life of manager */ + long runtime; /* cumulative CPU time spent garbage collecting */ + } gc; + struct { + int first_sbrk; /* value of sbrk at start of manager; used to analyze memory usage */ + int last_sbrk; /* value of last sbrk (see "man sbrk") fetched; used to analyze memory usage */ + unsigned int manager; + unsigned int nodes; + unsigned int hashtable; + unsigned int ext_ptrs; + unsigned int ITE_cache; + unsigned int ITE_const_cache; + unsigned int adhoc_cache; + unsigned int total; + } memory; /* memory usage */ +} bdd_stats; + +EXTERN double bdd_count_onset ARGS((bdd_t *, array_t *)); +EXTERN bdd_manager *bdd_get_manager ARGS((bdd_t *)); +EXTERN bdd_node *bdd_get_node ARGS((bdd_t *, boolean *)); +EXTERN void bdd_get_stats ARGS((bdd_manager *, bdd_stats *)); +EXTERN var_set_t *bdd_get_support ARGS((bdd_t *)); +EXTERN array_t *bdd_get_varids ARGS((array_t *)); +EXTERN unsigned int bdd_num_vars ARGS((bdd_manager *)); +EXTERN void bdd_print ARGS((bdd_t *)); +EXTERN void bdd_print_stats ARGS((bdd_stats, FILE *)); +EXTERN int bdd_size ARGS((bdd_t *)); +EXTERN bdd_variableId bdd_top_var_id ARGS((bdd_t *)); + +/* + * Traversal of BDD Formulas + */ +typedef enum { + bdd_EMPTY, + bdd_NONEMPTY +} bdd_gen_status; + +typedef enum { + bdd_gen_cubes, + bdd_gen_nodes +} bdd_gen_type; + +typedef struct { + bdd_manager *manager; + bdd_gen_status status; + bdd_gen_type type; + union { + struct { + array_t *cube; /* of bdd_literal */ + /* ... expansion ... */ + } cubes; + struct { + st_table *visited; /* of bdd_node* */ + /* ... expansion ... */ + } nodes; + } gen; + struct { + int sp; + bdd_node **stack; + } stack; + bdd_node *node; +} bdd_gen; + +/* + * foreach macro in the most misesque tradition + * bdd_gen_free always returns 0 + * + * CAUTION: in the context of the port to the CMU package, it is assumed that + * dynamic reordering will not occur while there are open generators. It is + * the user's responsibility to make sure dynamic reordering doesn't occur. + * As long as new nodes are not created during generation, and you don't + * explicitly call dynamic reordering, you should be okay. + */ + +/* + * foreach_bdd_cube(fn, gen, cube) + * bdd_t *fn; + * bdd_gen *gen; + * array_t *cube; - return + * + * foreach_bdd_cube(fn, gen, cube) { + * ... + * } + */ +#define foreach_bdd_cube(fn, gen, cube)\ + for((gen) = bdd_first_cube(fn, &cube);\ + ((gen)->status != bdd_EMPTY) ? TRUE: bdd_gen_free(gen);\ + (void) bdd_next_cube(gen, &cube)) + +/* + * foreach_bdd_node(fn, gen, node) + * bdd_t *fn; + * bdd_gen *gen; + * bdd_node *node; - return + */ +#define foreach_bdd_node(fn, gen, node)\ + for((gen) = bdd_first_node(fn, &node);\ + ((gen)->status != bdd_EMPTY) ? TRUE: bdd_gen_free(gen);\ + (void) bdd_next_node(gen, &node)) + +EXTERN int bdd_gen_free ARGS((bdd_gen *)); + +/* + * These are NOT to be used directly; only indirectly in the macros. + */ +EXTERN bdd_gen *bdd_first_cube ARGS((bdd_t *, array_t **)); +EXTERN boolean bdd_next_cube ARGS((bdd_gen *, array_t **)); +EXTERN bdd_gen *bdd_first_node ARGS((bdd_t *, bdd_node **)); +EXTERN boolean bdd_next_node ARGS((bdd_gen *, bdd_node **)); + +/* + * Miscellaneous + */ +EXTERN void bdd_set_gc_mode ARGS((bdd_manager *, boolean)); + +/* + * These are the hooks for stuff that uses bdd's + * + * There are three hooks, and users may use them in whatever + * way they wish; these hooks are guaranteed to never be used + * by the bdd package. + */ +typedef struct bdd_external_hooks { + char *network; + char *mdd; + char *undef1; +} bdd_external_hooks; + +EXTERN bdd_external_hooks *bdd_get_external_hooks ARGS((bdd_manager *)); + +/* + * Dynamic reordering. + */ +typedef enum { + BDD_REORDER_SIFT, + BDD_REORDER_WINDOW, + BDD_REORDER_NONE +} bdd_reorder_type_t; + +EXTERN void bdd_dynamic_reordering ARGS((bdd_manager *, bdd_reorder_type_t)); +EXTERN void bdd_reorder ARGS((bdd_manager *)); + +/* + * Default settings. + */ +#define BDD_NO_LIMIT ((1<<30)-2) +#define BDD_DFLT_ITE_ON TRUE +#define BDD_DFLT_ITE_RESIZE_AT 75 +#define BDD_DFLT_ITE_MAX_SIZE 1000000 +#define BDD_DFLT_ITE_CONST_ON TRUE +#define BDD_DFLT_ITE_CONST_RESIZE_AT 75 +#define BDD_DFLT_ITE_CONST_MAX_SIZE 1000000 +#define BDD_DFLT_ADHOC_ON TRUE +#define BDD_DFLT_ADHOC_RESIZE_AT 0 +#define BDD_DFLT_ADHOC_MAX_SIZE 10000000 +#define BDD_DFLT_GARB_COLLECT_ON TRUE +#define BDD_DFLT_DAEMON NIL(void) +#define BDD_DFLT_MEMORY_LIMIT BDD_NO_LIMIT +#define BDD_DFLT_NODE_RATIO 2.0 +#define BDD_DFLT_INIT_BLOCKS 10 + +#endif /* } */ diff --git a/sis/bdd_cmu/bdd_port/bdditer.c b/sis/bdd_cmu/bdd_port/bdditer.c new file mode 100644 index 0000000..76f19b3 --- /dev/null +++ b/sis/bdd_cmu/bdd_port/bdditer.c @@ -0,0 +1,576 @@ +/* + * Revision Control Information + * + * /projects/hsis/CVS/utilities/bdd_cmu/bdd_port/bdditer.c,v + * shiple + * 1.6 + * 1993/12/04 06:19:30 + * + */ +#include "util.h" /* includes math.h */ +#include "array.h" +#include "st.h" + +#include "bdd.h" /* UCB interface to CMU */ +#include "bdduser.h" /* CMU exported routines */ +#include "bddint.h" /* CMU internal routines; for use in bdd_get_branches() and for BDD_POINTER */ + +static void pop_cube_stack(); +static void pop_node_stack(); +static void push_cube_stack(); +static void push_node_stack(); + +/* + * Defines an iterator on the onset of a BDD. Two routines are + * provided: bdd_first_cube, which extracts one cube from a BDD and + * returns a bdd_gen structure containing the information necessary to + * continue the enumeration; and bdd_next_cube, which returns 1 if another cube was + * found, and 0 otherwise. A cube is represented + * as an array of bdd_literal (which are integers in {0, 1, 2}), where 0 represents + * negated literal, 1 for literal, and 2 for don't care. Returns a disjoint + * cover. A third routine is there to clean up. + */ + +/* + * bdd_first_cube - return the first cube of the function. + * A generator is returned that will iterate over the rest. + * Return the generator. + */ +bdd_gen * +bdd_first_cube(fn, cube) +bdd_t *fn; +array_t **cube; /* of bdd_literal */ +{ + struct bdd_manager_ *manager; + bdd_gen *gen; + int i; + long num_vars; + bdd_node *f; + + if (fn == NIL(bdd_t)) { + cmu_bdd_fatal("bdd_first_cube: invalid BDD"); + } + + manager = fn->mgr; + + /* + * Allocate a new generator structure and fill it in; the stack and the + * cube will be used, but the visited table and the node will not be used. + */ + gen = ALLOC(bdd_gen, 1); + if (gen == NIL(bdd_gen)) { + cmu_bdd_fatal("bdd_first_cube: failed on memory allocation, location 1"); + } + + /* + * first - init all the members to a rational value for cube iteration + */ + gen->manager = manager; + gen->status = bdd_EMPTY; + gen->type = bdd_gen_cubes; + gen->gen.cubes.cube = NIL(array_t); + gen->stack.sp = 0; + gen->stack.stack = NIL(bdd_node *); + gen->node = NIL(bdd_node); + + num_vars = cmu_bdd_vars(manager); + gen->gen.cubes.cube = array_alloc(bdd_literal, num_vars); + if (gen->gen.cubes.cube == NIL(array_t)) { + cmu_bdd_fatal("bdd_first_cube: failed on memory allocation, location 2"); + } + + /* + * Initialize each literal to 2 (don't care). + */ + for (i = 0; i < num_vars; i++) { + array_insert(bdd_literal, gen->gen.cubes.cube, i, 2); + } + + /* + * The stack size will never exceed the number of variables in the BDD, since + * the longest possible path from root to constant 1 is the number of variables + * in the BDD. + */ + gen->stack.sp = 0; + gen->stack.stack = ALLOC(bdd_node *, num_vars); + if (gen->stack.stack == NIL(bdd_node *)) { + cmu_bdd_fatal("bdd_first_cube: failed on memory allocation, location 3"); + } + /* + * Clear out the stack so that in bdd_gen_free, we can decrement the ref count + * of those nodes still on the stack. + */ + for (i = 0; i < num_vars; i++) { + gen->stack.stack[i] = NIL(bdd_node); + } + + if (bdd_is_tautology(fn, 0)) { + /* + * All done, for this was but the zero constant ... + * We are enumerating the onset, (which is vacuous). + * gen->status initialized to bdd_EMPTY above, so this + * appears to be redundant. + */ + gen->status = bdd_EMPTY; + } else { + /* + * Get to work enumerating the onset. Get the first cube. Note that + * if fn is just the constant 1, push_cube_stack will properly handle this. + * Get a new pointer to fn->node beforehand: this increments + * the reference count of fn->node; this is necessary, because when fn->node + * is popped from the stack at the very end, it's ref count is decremented. + */ + gen->status = bdd_NONEMPTY; + f = cmu_bdd_identity(manager, fn->node); + push_cube_stack(f, gen); + } + + *cube = gen->gen.cubes.cube; + return (gen); +} + +/* + * bdd_next_cube - get the next cube on the generator. + * Returns {TRUE, FALSE} when {more, no more}. + */ +boolean +bdd_next_cube(gen, cube) +bdd_gen *gen; +array_t **cube; /* of bdd_literal */ +{ + + pop_cube_stack(gen); + if (gen->status == bdd_EMPTY) { + return (FALSE); + } + *cube = gen->gen.cubes.cube; + return (TRUE); +} + +/* + * bdd_first_node - enumerates all bdd_node * in fn. + * Return the generator. + */ +bdd_gen * +bdd_first_node(fn, node) +bdd_t *fn; +bdd_node **node; /* return */ +{ + struct bdd_manager_ *manager; + bdd_gen *gen; + long num_vars; + bdd_node *f; + int i; + + if (fn == NIL(bdd_t)) { + cmu_bdd_fatal("bdd_first_node: invalid BDD"); + } + + manager = fn->mgr; + + /* + * Allocate a new generator structure and fill it in; the + * visited table will be used, as will the stack, but the + * cube array will not be used. + */ + gen = ALLOC(bdd_gen, 1); + if (gen == NIL(bdd_gen)) { + cmu_bdd_fatal("bdd_first_node: failed on memory allocation, location 1"); + } + + /* + * first - init all the members to a rational value for node iteration. + */ + gen->manager = manager; + gen->status = bdd_NONEMPTY; + gen->type = bdd_gen_nodes; + gen->gen.nodes.visited = NIL(st_table); + gen->stack.sp = 0; + gen->stack.stack = NIL(bdd_node *); + gen->node = NIL(bdd_node); + + /* + * Set up the hash table for visited nodes. Every time we visit a node, + * we insert it into the table. + */ + gen->gen.nodes.visited = st_init_table(st_ptrcmp, st_ptrhash); + if (gen->gen.nodes.visited == NIL(st_table)) { + cmu_bdd_fatal("bdd_first_node: failed on memory allocation, location 2"); + } + + /* + * The stack size will never exceed the number of variables in the BDD, since + * the longest possible path from root to constant 1 is the number of variables + * in the BDD. + */ + gen->stack.sp = 0; + num_vars = cmu_bdd_vars(manager); + gen->stack.stack = ALLOC(bdd_node *, num_vars); + if (gen->stack.stack == NIL(bdd_node *)) { + cmu_bdd_fatal("bdd_first_node: failed on memory allocation, location 3"); + } + /* + * Clear out the stack so that in bdd_gen_free, we can decrement the ref count + * of those nodes still on the stack. + */ + for (i = 0; i < num_vars; i++) { + gen->stack.stack[i] = NIL(bdd_node); + } + + /* + * Get the first node. Get a new pointer to fn->node beforehand: this increments + * the reference count of fn->node; this is necessary, because when fn->node + * is popped from the stack at the very end, it's ref count is decremented. + */ + f = cmu_bdd_identity(manager, fn->node); + push_node_stack(f, gen); + gen->status = bdd_NONEMPTY; + + *node = gen->node; /* return the node */ + return (gen); /* and the new generator */ +} + +/* + * bdd_next_node - get the next node in the BDD. + * Return {TRUE, FALSE} when {more, no more}. + */ +boolean +bdd_next_node(gen, node) +bdd_gen *gen; +bdd_node **node; /* return */ +{ + pop_node_stack(gen); + if (gen->status == bdd_EMPTY) { + return (FALSE); + } + *node = gen->node; + return (TRUE); +} + +/* + * bdd_gen_free - frees up the space used by the generator. + * Return an int so that it is easier to fit in a foreach macro. + * Return 0 (to make it easy to put in expressions). + */ +int +bdd_gen_free(gen) +bdd_gen *gen; +{ + long num_vars; + int i; + struct bdd_manager_ *mgr; + bdd_node *f; + st_table *visited_table; + st_generator *visited_gen; + + mgr = gen->manager; + + switch (gen->type) { + case bdd_gen_cubes: + array_free(gen->gen.cubes.cube); + gen->gen.cubes.cube = NIL(array_t); + break; + case bdd_gen_nodes: + visited_table = gen->gen.nodes.visited; + st_foreach_item(visited_table, visited_gen, (refany*) &f, NIL(refany)) { + cmu_bdd_free(mgr, f); + } + st_free_table(visited_table); + visited_table = NIL(st_table); + break; + } + + /* + * Free the data associated with this generator. If there are any nodes remaining + * on the stack, we must free them, to get their ref counts back to what they were before. + */ + num_vars = cmu_bdd_vars(mgr); + for (i = 0; i < num_vars; i++) { + f = gen->stack.stack[i]; + if (f != NIL(bdd_node)) { + cmu_bdd_free(mgr, f); + } + } + FREE(gen->stack.stack); + + FREE(gen); + + return (0); /* make it return some sort of an int */ +} + +/* + * INTERNAL INTERFACE + * + * Invariants: + * + * gen->stack.stack contains nodes that remain to be explored. + * + * For a cube generator, + * gen->gen.cubes.cube reflects the choices made to reach node at top of the stack. + * For a node generator, + * gen->gen.nodes.visited reflects the nodes already visited in the BDD dag. + */ + +/* + * push_cube_stack - push a cube onto the stack to visit. + * Return nothing, just do it. + * + * The BDD is traversed using depth-first search, with the ELSE branch + * searched before the THEN branch. + * + * Caution: If you are creating new BDD's while iterating through the + * cubes, and a garbage collection happens to be performed during this + * process, then the BDD generator will get lost and an error will result. + * + */ +static void +push_cube_stack(f, gen) +bdd_node *f; +bdd_gen *gen; +{ + bdd_variableId topf_id; + bdd_node *f0, *f1; + struct bdd_manager_ *mgr; + + mgr = gen->manager; + + if (f == cmu_bdd_one(mgr)) { + return; + } + + topf_id = (bdd_variableId) (cmu_bdd_if_id(mgr, f) - 1); + + /* + * Get the then and else branches of f. Note that cmu_bdd_then and cmu_bdd_else + * automatically take care of inverted pointers. + */ + f0 = cmu_bdd_else(mgr, f); + f1 = cmu_bdd_then(mgr, f); + + if (f1 == cmu_bdd_zero(mgr)) { + /* + * No choice: take the 0 branch. Since there is only one branch to + * explore from f, there is no need to push f onto the stack, because + * after exploring this branch we are done with f. A consequence of + * this is that there will be no f to pop either. Same goes for the + * next case. Decrement the ref count of f and of the branch leading + * to zero, since we will no longer need to access these nodes. + */ + array_insert(bdd_literal, gen->gen.cubes.cube, topf_id, 0); + push_cube_stack(f0, gen); + cmu_bdd_free(mgr, f1); + cmu_bdd_free(mgr, f); + } else if (f0 == cmu_bdd_zero(mgr)) { + /* + * No choice: take the 1 branch + */ + array_insert(bdd_literal, gen->gen.cubes.cube, topf_id, 1); + push_cube_stack(f1, gen); + cmu_bdd_free(mgr, f0); + cmu_bdd_free(mgr, f); + } else { + /* + * In this case, we must explore both branches of f. We always choose + * to explore the 0 branch first. We must push f on the stack, so that + * we can later pop it and explore its 1 branch. Decrement the ref count + * of f1 since we will no longer need to access this node. Note that + * the parent of f1 was bdd_freed above or in pop_cube_stack. + */ + gen->stack.stack[gen->stack.sp++] = f; + array_insert(bdd_literal, gen->gen.cubes.cube, topf_id, 0); + push_cube_stack(f0, gen); + cmu_bdd_free(mgr, f1); + } +} + +static void +pop_cube_stack(gen) +bdd_gen *gen; +{ + bdd_variableId topf_id, level_i_id; + bdd_node *branch_f; + bdd_node *f1; + int i; + long topf_level; + struct bdd_manager_ *mgr; + struct bdd_ *var_bdd; + + mgr = gen->manager; + + if (gen->stack.sp == 0) { + /* + * Stack is empty. Have already explored both the 0 and 1 branches of + * the root of the BDD. + */ + gen->status = bdd_EMPTY; + } else { + /* + * Explore the 1 branch of the node at the top of the stack (since it is + * on the stack, this means we have already explored the 0 branch). We + * permanently pop the top node, and bdd_free it, since there are no more edges left to + * explore. + */ + branch_f = gen->stack.stack[--gen->stack.sp]; + gen->stack.stack[gen->stack.sp] = NIL(bdd_node); /* overwrite with NIL */ + topf_id = (bdd_variableId) (cmu_bdd_if_id(mgr, branch_f) - 1); + array_insert(bdd_literal, gen->gen.cubes.cube, topf_id, 1); + + /* + * We must set the variables with levels greater than the level of branch_f, + * back to 2 (don't care). This is because these variables are not + * on the current path, and thus there values are don't care. + * + * Note the following correspondence: + * CMU UCB + * index level (both start at zero) + * indexindex id (CMU has id 0 for constant, thus really start numbering at 1; + * UCB starts numbering at 0) + */ + topf_level = cmu_bdd_if_index(mgr, branch_f); + for (i = topf_level + 1; i < array_n(gen->gen.cubes.cube); i++) { + var_bdd = cmu_bdd_var_with_index(mgr, i); + level_i_id = (bdd_variableId) (cmu_bdd_if_id(mgr, var_bdd) - 1); + /* + * No need to free var_bdd, since single variable BDDs are never garbage collected. + * Note that level_i_id is just (mgr->indexindexes[i] - 1); however, wanted + * to avoid using CMU internals. + */ + array_insert(bdd_literal, gen->gen.cubes.cube, level_i_id, 2); + } + f1 = cmu_bdd_then(mgr, branch_f); + push_cube_stack(f1, gen); + cmu_bdd_free(mgr, branch_f); + } +} + +/* + * push_node_stack - push a node onto the stack. + * + * The same as push_cube_stack but for enumerating nodes instead of cubes. + * The BDD is traversed using depth-first search, with the ELSE branch searched + * before the THEN branch, and a node returned only after its children have been + * returned. Note that the returned bdd_node pointer has the complement + * bit zeroed out. + * + * Caution: If you are creating new BDD's while iterating through the + * nodes, and a garbage collection happens to be performed during this + * process, then the BDD generator will get lost and an error will result. + * + * Return nothing, just do it. + */ +static void +push_node_stack(f, gen) +bdd_node *f; +bdd_gen *gen; +{ + bdd_node *f0, *f1; + bdd_node *reg_f, *reg_f0, *reg_f1; + struct bdd_manager_ *mgr; + + mgr = gen->manager; + + reg_f = (bdd_node *) BDD_POINTER(f); /* use of bddint.h */ + if (st_lookup(gen->gen.nodes.visited, (refany) reg_f, NIL(refany))) { + /* + * Already been visited. + */ + return; + } + + if (f == cmu_bdd_one(mgr) || f == cmu_bdd_zero(mgr)) { + /* + * If f is the constant node and it has not been visited yet, then put it in the visited table + * and set the gen->node pointer. There is no need to put it in the stack because + * the constant node does not have any branches, and there is no need to free f because + * constant nodes have a saturated reference count. + */ + st_insert(gen->gen.nodes.visited, (refany) reg_f, NIL(any)); + gen->node = reg_f; + } else { + /* + * f has not been marked as visited. We don't know yet if any of its branches + * remain to be explored. First get its branches. Note that cmu_bdd_then and + * cmu_bdd_else automatically take care of inverted pointers. + */ + f0 = cmu_bdd_else(mgr, f); + f1 = cmu_bdd_then(mgr, f); + + reg_f0 = (bdd_node *) BDD_POINTER(f0); /* use of bddint.h */ + reg_f1 = (bdd_node *) BDD_POINTER(f1); + if (! st_lookup(gen->gen.nodes.visited, (refany) reg_f0, NIL(refany))) { + /* + * The 0 child has not been visited, so explore the 0 branch. First push f on + * the stack. Bdd_free f1 since we will not need to access this exact pointer + * any more. + */ + gen->stack.stack[gen->stack.sp++] = f; + push_node_stack(f0, gen); + cmu_bdd_free(mgr, f1); + } else if (! st_lookup(gen->gen.nodes.visited, (refany) reg_f1, NIL(refany))) { + /* + * The 0 child has been visited, but the 1 child has not been visited, so + * explore the 1 branch. First push f on the stack. We are done with f0, + * so bdd_free it. + */ + gen->stack.stack[gen->stack.sp++] = f; + push_node_stack(f1, gen); + cmu_bdd_free(mgr, f0); + } else { + /* + * Both the 0 and 1 children have been visited. Thus we are done exploring from f. + * Mark f as visited (put it in the visited table), and set the gen->node pointer. + * We will no longer need to refer to f0 and f1, so bdd_free them. f will be + * bdd_freed when the visited table is freed. + */ + st_insert(gen->gen.nodes.visited, (refany) reg_f, NIL(any)); + gen->node = reg_f; + cmu_bdd_free(mgr, f0); + cmu_bdd_free(mgr, f1); + } + } +} + +static void +pop_node_stack(gen) +bdd_gen *gen; +{ + bdd_node *branch_f; + + if (gen->stack.sp == 0) { + gen->status = bdd_EMPTY; + } else { + branch_f = gen->stack.stack[--gen->stack.sp]; /* overwrite with NIL */ + gen->stack.stack[gen->stack.sp] = NIL(bdd_node); + push_node_stack(branch_f, gen); + } +} + +/* + * bdd_get_branches - get the branches of a node + * + * return nothing, just do it. + * + * This function is not currently being used (TRS 9/29/93) + */ +static void +bdd_get_branches(f, f_T, f_E) +bdd_node *f; +bdd_node **f_T; /* return */ +bdd_node **f_E; /* return */ +{ + BDD_SETUP(f); + + /* + * In the CMU package, the T and E pointers of the constant ONE node have + * strange values: + * bddm->one->data[0]=0x5552436c; + * bddm->one->data[1]=0x65766572; + * bddm->zero=BDD_NOT(bddm->one); + * Thus, if f points to a constant node, don't expect to get NILs back for + * T and E, as is done in the Berkeley package. + */ + + *f_T = BDD_THEN(f); /* using bddint.h */ + *f_E = BDD_ELSE(f); /* using bddint.h */ +} + diff --git a/sis/bdd_cmu/bdd_port/bddport.c b/sis/bdd_cmu/bdd_port/bddport.c new file mode 100644 index 0000000..496aea1 --- /dev/null +++ b/sis/bdd_cmu/bdd_port/bddport.c @@ -0,0 +1,813 @@ +/* + * Revision Control Information + * + * /projects/hsis/CVS/utilities/bdd_cmu/bdd_port/bddport.c,v + * serdar + * 1.7 + * 1994/04/28 19:28:08 + * + */ +/* + * UCB BDD package to CMU BDD package interface. + * + * Translate each exported UCB BDD function described in bdd.doc into an + * equivalent CMU BDD package call. + * + * Author: Thomas R. Shiple + * Date: 7 June 93 + * + */ + +#include "util.h" /* includes math.h */ +#include "array.h" +#include "st.h" + +#include "bdd.h" /* UCB interface to CMU */ +#include "memuser.h" +#include "bdduser.h" /* CMU exported routines */ +#include "bddint.h" /* CMU internal routines; for use in bdd_get_node() */ + +/* + * Function to construct a bdd_t. + */ +static bdd_t * +bdd_construct_bdd_t(mgr, fn) +struct bdd_manager_ *mgr; +struct bdd_ *fn; +{ + bdd_t *result; + + if (fn == (struct bdd_ *) 0) { + cmu_bdd_fatal("bdd_construct_bdd_t: possible memory overflow"); + } + + result = ALLOC(bdd_t, 1); + result->mgr = mgr; + result->node = fn; + result->free = FALSE; + return result; +} + +/* +BDD Manager Allocation And Destruction ---------------------------------------- +*/ +void +bdd_end(mgr) +struct bdd_manager_ *mgr; +{ + bdd_external_hooks *hooks; + + hooks = (bdd_external_hooks *) mgr->hooks; + FREE(hooks); + cmu_bdd_quit(mgr); +} + +void +bdd_set_mgr_init_dflts(mgr_init) +bdd_mgr_init *mgr_init; +{ + cmu_bdd_warning("bdd_set_mgr_init_dflts: translated to no-op in CMU package"); + return; +} + +struct bdd_manager_ * +bdd_start(nvariables) +int nvariables; +{ + struct bdd_manager_ *mgr; + int i; + bdd_external_hooks *hooks; + + mgr = cmu_bdd_init(); /*no args*/ + + /* + * Calls to UCB bdd_get_variable are translated into cmu_bdd_var_with_id calls. However, + * cmu_bdd_var_with_id assumes that single variable BDDs have already been created for + * all the variables that we wish to access. Thus, following, we explicitly create n + * variables. We do not care about the return value of cmu_bdd_new_var_last; in the + * CMU package, the single variable BDDs are NEVER garbage collected. + */ + for (i = 0; i < nvariables; i++) { + (void) cmu_bdd_new_var_last(mgr); + } + + hooks = ALLOC(bdd_external_hooks, 1); + hooks->mdd = hooks->network = hooks->undef1 = (char *) 0; + mgr->hooks = (char *) hooks; /* new field added to CMU manager */ + + return mgr; +} + +struct bdd_manager_ * +bdd_start_with_params(nvariables, mgr_init) +int nvariables; +bdd_mgr_init *mgr_init; +{ + cmu_bdd_warning("bdd_start_with_params: translated to bdd_start(nvariables) in CMU package"); + return bdd_start(nvariables); +} + +/* +BDD Variable Allocation ------------------------------------------------------- +*/ + +bdd_t * +bdd_create_variable(mgr) +struct bdd_manager_ *mgr; +{ + return bdd_construct_bdd_t(mgr, cmu_bdd_new_var_last(mgr)); +} + +bdd_t * +bdd_create_variable_after(mgr, after_id) +struct bdd_manager_ *mgr; +bdd_variableId after_id; +{ + struct bdd_ *after_var; + bdd_t *result; + + after_var = cmu_bdd_var_with_id(mgr, (long)after_id + 1); + + result = bdd_construct_bdd_t(mgr, cmu_bdd_new_var_after(mgr, after_var)); + + /* No need to free after_var, since single variable BDDs are never garbage collected */ + + return result; +} + + + +bdd_t * +bdd_get_variable(mgr, variable_ID) +struct bdd_manager_ *mgr; +bdd_variableId variable_ID; /* unsigned int */ +{ + struct bdd_ *fn; + + fn = cmu_bdd_var_with_id(mgr, (long) (variable_ID + 1)); + + if (fn == (struct bdd_ *) 0) { + /* variable should always be found, since they are created at bdd_start */ + cmu_bdd_fatal("bdd_get_variable: assumption violated"); + } + + return bdd_construct_bdd_t(mgr, fn); +} + +/* +BDD Formula Management -------------------------------------------------------- +*/ + +bdd_t * +bdd_dup(f) +bdd_t *f; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_identity(f->mgr, f->node)); +} + +void +bdd_free(f) +bdd_t *f; +{ + if (f == NIL(bdd_t)) { + fail("bdd_free: trying to free a NIL bdd_t"); + } + + if (f->free == TRUE) { + fail("bdd_free: trying to free a freed bdd_t"); + } + + cmu_bdd_free(f->mgr, f->node); + + /* + * In case the user tries to free this bdd_t again, set the free field to TRUE, + * and NIL out the other fields. Then free the bdd_t structure itself. + */ + f->free = TRUE; + f->node = NIL(struct bdd_); + f->mgr = NIL(struct bdd_manager_); + FREE(f); +} + +/* +Operations on BDD Formulas ---------------------------------------------------- +*/ + +bdd_t * +bdd_and(f, g, f_phase, g_phase) +bdd_t *f; +bdd_t *g; +boolean f_phase; +boolean g_phase; +{ + struct bdd_ *temp1, *temp2; + bdd_t *result; + struct bdd_manager_ *mgr; + + mgr = f->mgr; + temp1 = ( (f_phase == TRUE) ? cmu_bdd_identity(mgr, f->node) : cmu_bdd_not(mgr, f->node)); + temp2 = ( (g_phase == TRUE) ? cmu_bdd_identity(mgr, g->node) : cmu_bdd_not(mgr, g->node)); + result = bdd_construct_bdd_t(mgr, cmu_bdd_and(mgr, temp1, temp2)); + cmu_bdd_free(mgr, temp1); + cmu_bdd_free(mgr, temp2); + return result; +} + +bdd_t * +bdd_and_smooth(f, g, smoothing_vars) +bdd_t *f; +bdd_t *g; +array_t *smoothing_vars; /* of bdd_t *'s */ +{ + int num_vars, i; + bdd_t *fn, *result; + struct bdd_ **assoc; + struct bdd_manager_ *mgr; + + num_vars = array_n(smoothing_vars); + if (num_vars <= 0) { + cmu_bdd_fatal("bdd_and_smooth: no smoothing variables"); + } + + assoc = ALLOC(struct bdd_ *, num_vars+1); + + for (i = 0; i < num_vars; i++) { + fn = array_fetch(bdd_t *, smoothing_vars, i); + assoc[i] = fn->node; + } + assoc[num_vars] = (struct bdd_ *) 0; + + mgr = f->mgr; + cmu_bdd_temp_assoc(mgr, assoc, 0); + (void) cmu_bdd_assoc(mgr, -1); /* set the temp association as the current association */ + + result = bdd_construct_bdd_t(mgr, cmu_bdd_rel_prod(mgr, f->node, g->node)); + FREE(assoc); + return result; +} + +bdd_t * +bdd_between(f_min, f_max) +bdd_t *f_min; +bdd_t *f_max; +{ + bdd_t *temp, *ret; + + temp = bdd_or(f_min, f_max, 1, 0); + ret = bdd_minimize(f_min, temp); + bdd_free(temp); + return ret; +} + +bdd_t * +bdd_cofactor(f, g) +bdd_t *f; +bdd_t *g; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_cofactor(f->mgr, f->node, g->node)); +} + +bdd_t * +bdd_compose(f, v, g) +bdd_t *f; +bdd_t *v; +bdd_t *g; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_compose(f->mgr, f->node, v->node, g->node)); +} + +bdd_t * +bdd_consensus(f, quantifying_vars) +bdd_t *f; +array_t *quantifying_vars; /* of bdd_t *'s */ +{ + int num_vars, i; + bdd_t *fn, *result; + struct bdd_ **assoc; + struct bdd_manager_ *mgr; + + num_vars = array_n(quantifying_vars); + if (num_vars <= 0) { + cmu_bdd_fatal("bdd_consensus: no quantifying variables"); + } + + assoc = ALLOC(struct bdd_ *, num_vars+1); + + for (i = 0; i < num_vars; i++) { + fn = array_fetch(bdd_t *, quantifying_vars, i); + assoc[i] = fn->node; + } + assoc[num_vars] = (struct bdd_ *) 0; + + mgr = f->mgr; + cmu_bdd_temp_assoc(mgr, assoc, 0); + (void) cmu_bdd_assoc(mgr, -1); /* set the temp association as the current association */ + + result = bdd_construct_bdd_t(mgr, cmu_bdd_forall(mgr, f->node)); + FREE(assoc); + return result; +} + +extern bdd cmu_bdd_project(); + +/* + * bdd_cproject - the compatible projection function + * + * return the new bdd (external pointer) + */ + + +bdd_t * +bdd_cproject(f, quantifying_vars) +bdd_t *f; +array_t *quantifying_vars; /* of bdd_t* */ +{ + int num_vars, i; + bdd_t *fn, *result; + struct bdd_ **assoc; + struct bdd_manager_ *mgr; + + + + if (f == NIL(bdd_t)) + fail ("bdd_cproject: invalid BDD"); + + num_vars = array_n(quantifying_vars); + if (num_vars <= 0) { + cmu_bdd_fatal("bdd_cproject: no projection variables"); + } + + assoc = ALLOC(struct bdd_ *, num_vars+1); + + for (i = 0; i < num_vars; i++) { + fn = array_fetch(bdd_t *, quantifying_vars, i); + assoc[i] = fn->node; + } + assoc[num_vars] = (struct bdd_ *) 0; + + mgr = f->mgr; + cmu_bdd_temp_assoc(mgr, assoc, 0); + (void) cmu_bdd_assoc(mgr, -1); /* set the temp association as the current a + ssociation */ + + result = bdd_construct_bdd_t(mgr, cmu_bdd_project(mgr, f->node)); + FREE(assoc); + return result; + +} + + +bdd_t * +bdd_else(f) +bdd_t *f; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_else(f->mgr, f->node)); +} + + +bdd_t * +bdd_ite(i, t, e, i_phase, t_phase, e_phase) +bdd_t *i; +bdd_t *t; +bdd_t *e; +boolean i_phase; +boolean t_phase; +boolean e_phase; +{ + struct bdd_ *temp1, *temp2, *temp3; + bdd_t *result; + struct bdd_manager_ *mgr; + + mgr = i->mgr; + temp1 = ( (i_phase == TRUE) ? cmu_bdd_identity(mgr, i->node) : cmu_bdd_not(mgr, i->node)); + temp2 = ( (t_phase == TRUE) ? cmu_bdd_identity(mgr, t->node) : cmu_bdd_not(mgr, t->node)); + temp3 = ( (e_phase == TRUE) ? cmu_bdd_identity(mgr, e->node) : cmu_bdd_not(mgr, e->node)); + result = bdd_construct_bdd_t(mgr, cmu_bdd_ite(mgr, temp1, temp2, temp3)); + cmu_bdd_free(mgr, temp1); + cmu_bdd_free(mgr, temp2); + cmu_bdd_free(mgr, temp3); + return result; +} + +bdd_t * +bdd_minimize(f, c) +bdd_t *f; +bdd_t *c; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_reduce(f->mgr, f->node, c->node)); +} + +bdd_t * +bdd_minimize_with_params(f, c, match_type, compl, no_new_vars, return_min) +bdd_t *f; +bdd_t *c; +bdd_min_match_type_t match_type; +boolean compl; +boolean no_new_vars; +boolean return_min; +{ + return bdd_minimize(f, c); +} + +bdd_t * +bdd_not(f) +bdd_t *f; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_not(f->mgr, f->node)); +} + +bdd_t * +bdd_one(mgr) +struct bdd_manager_ *mgr; +{ + return bdd_construct_bdd_t(mgr, cmu_bdd_one(mgr)); +} + +bdd_t * +bdd_or(f, g, f_phase, g_phase) +bdd_t *f; +bdd_t *g; +boolean f_phase; +boolean g_phase; +{ + struct bdd_ *temp1, *temp2; + bdd_t *result; + struct bdd_manager_ *mgr; + + mgr = f->mgr; + temp1 = ( (f_phase == TRUE) ? cmu_bdd_identity(mgr, f->node) : cmu_bdd_not(mgr, f->node)); + temp2 = ( (g_phase == TRUE) ? cmu_bdd_identity(mgr, g->node) : cmu_bdd_not(mgr, g->node)); + result = bdd_construct_bdd_t(mgr, cmu_bdd_or(mgr, temp1, temp2)); + cmu_bdd_free(mgr, temp1); + cmu_bdd_free(mgr, temp2); + return result; +} + +bdd_t * +bdd_smooth(f, smoothing_vars) +bdd_t *f; +array_t *smoothing_vars; /* of bdd_t *'s */ +{ + int num_vars, i; + bdd_t *fn, *result; + struct bdd_ **assoc; + struct bdd_manager_ *mgr; + + num_vars = array_n(smoothing_vars); + if (num_vars <= 0) { + cmu_bdd_fatal("bdd_smooth: no smoothing variables"); + } + + assoc = ALLOC(struct bdd_ *, num_vars+1); + + for (i = 0; i < num_vars; i++) { + fn = array_fetch(bdd_t *, smoothing_vars, i); + assoc[i] = fn->node; + } + assoc[num_vars] = (struct bdd_ *) 0; + + mgr = f->mgr; + cmu_bdd_temp_assoc(mgr, assoc, 0); + (void) cmu_bdd_assoc(mgr, -1); /* set the temp association as the current association */ + + result = bdd_construct_bdd_t(mgr, cmu_bdd_exists(mgr, f->node)); + FREE(assoc); + return result; +} + +bdd_t * +bdd_substitute(f, old_array, new_array) +bdd_t *f; +array_t *old_array; /* of bdd_t *'s */ +array_t *new_array; /* of bdd_t *'s */ +{ + int num_old_vars, num_new_vars, i; + bdd_t *fn_old, *fn_new, *result; + struct bdd_ **assoc; + struct bdd_manager_ *mgr; + + num_old_vars = array_n(old_array); + num_new_vars = array_n(new_array); + if (num_old_vars != num_new_vars) { + cmu_bdd_fatal("bdd_substitute: mismatch of number of new and old variables"); + } + + assoc = ALLOC(struct bdd_ *, 2*(num_old_vars+1)); + + for (i = 0; i < num_old_vars; i++) { + fn_old = array_fetch(bdd_t *, old_array, i); + fn_new = array_fetch(bdd_t *, new_array, i); + assoc[2*i] = fn_old->node; + assoc[2*i+1] = fn_new->node; + } + assoc[2*num_old_vars] = (struct bdd_ *) 0; + assoc[2*num_old_vars+1] = (struct bdd_ *) 0; /* not sure if we need this second 0 */ + + mgr = f->mgr; + cmu_bdd_temp_assoc(mgr, assoc, 1); + (void) cmu_bdd_assoc(mgr, -1); /* set the temp association as the current association */ + + result = bdd_construct_bdd_t(mgr, cmu_bdd_substitute(mgr, f->node)); + FREE(assoc); + return result; +} + +bdd_t * +bdd_then(f) +bdd_t *f; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_then(f->mgr, f->node)); +} + +bdd_t * +bdd_top_var(f) +bdd_t *f; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_if(f->mgr, f->node)); +} + +bdd_t * +bdd_xnor(f, g) +bdd_t *f; +bdd_t *g; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_xnor(f->mgr, f->node, g->node)); +} + +bdd_t * +bdd_xor(f, g) +bdd_t *f; +bdd_t *g; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_xor(f->mgr, f->node, g->node)); +} + +bdd_t * +bdd_zero(mgr) +struct bdd_manager_ *mgr; +{ + return bdd_construct_bdd_t(mgr, cmu_bdd_zero(mgr)); +} + +/* +Queries about BDD Formulas ---------------------------------------------------- +*/ + +boolean +bdd_equal(f, g) +bdd_t *f; +bdd_t *g; +{ + return (f->node == g->node); +} + +bdd_t * +bdd_intersects(f, g) +bdd_t *f; +bdd_t *g; +{ + return bdd_construct_bdd_t(f->mgr, cmu_bdd_intersects(f->mgr, f->node, g->node)); +} + +boolean +bdd_is_tautology(f, phase) +bdd_t *f; +boolean phase; +{ + return ((phase == TRUE) ? (f->node == cmu_bdd_one(f->mgr)) : (f->node == cmu_bdd_zero(f->mgr))); +} + +boolean +bdd_leq(f, g, f_phase, g_phase) +bdd_t *f; +bdd_t *g; +boolean f_phase; +boolean g_phase; +{ + struct bdd_ *temp1, *temp2, *implies_fn; + struct bdd_manager_ *mgr; + boolean result_value; + + mgr = f->mgr; + temp1 = ( (f_phase == TRUE) ? cmu_bdd_identity(mgr, f->node) : cmu_bdd_not(mgr, f->node)); + temp2 = ( (g_phase == TRUE) ? cmu_bdd_identity(mgr, g->node) : cmu_bdd_not(mgr, g->node)); + implies_fn = cmu_bdd_implies(mgr, temp1, temp2); /* returns a minterm of temp1*!temp2 */ + result_value = (implies_fn == cmu_bdd_zero(mgr)); + cmu_bdd_free(mgr, temp1); + cmu_bdd_free(mgr, temp2); + cmu_bdd_free(mgr, implies_fn); + return result_value; +} + +/* +Statistics and Other Queries -------------------------------------------------- +*/ + +double +bdd_count_onset(f, var_array) +bdd_t *f; +array_t *var_array; /* of bdd_t *'s */ +{ + int num_vars; + double fraction; + + num_vars = array_n(var_array); + fraction = cmu_bdd_satisfying_fraction(f->mgr, f->node); /* cannot give support vars */ + return (fraction * pow((double) 2, (double) num_vars)); +} + +struct bdd_manager_ * +bdd_get_manager(f) +bdd_t *f; +{ + return (f->mgr); +} + +bdd_node * +bdd_get_node(f, is_complemented) +bdd_t *f; +boolean *is_complemented; /* return */ +{ + *is_complemented = (boolean) TAG0(f->node); /* using bddint.h */ + return ((bdd_node *) BDD_POINTER(f->node)); /* using bddint.h */ +} + +void +bdd_get_stats(mgr, stats) +struct bdd_manager_ *mgr; +bdd_stats *stats; /* return */ +{ + stats->gc.runtime = (long) mgr; /* for use in bdd_print_stats; this is a hack */ + /* SIS simplify package looks at these fields */ + stats->nodes.total = stats->nodes.used = (unsigned int) cmu_bdd_total_size(mgr); + return; +} + +var_set_t * +bdd_get_support(f) +bdd_t *f; +{ + struct bdd_ **support, *var; + struct bdd_manager_ *mgr; + long num_vars; + var_set_t *result; + int id, i; + + mgr = f->mgr; + num_vars = cmu_bdd_vars(mgr); + + result = var_set_new((int) num_vars); + support = (struct bdd_ **) mem_get_block((num_vars+1) * sizeof(struct bdd_ *)); + (void) cmu_bdd_support(mgr, f->node, support); + + for (i = 0; i < num_vars; ++i) { /* can never have more than num_var non-zero entries in array */ + var = support[i]; + if (var == (struct bdd_ *) 0) { + break; /* have reach end of null-terminated array */ + } + id = (int) (cmu_bdd_if_id(mgr, var) - 1); /* a variable is never garbage collected, so no need to free */ + var_set_set_elt(result, id); + } + + mem_free_block((pointer)support); + + return result; +} + +array_t * +bdd_get_varids(var_array) +array_t *var_array; +{ + int i; + bdd_t *var; + array_t *result; + + result = array_alloc(bdd_variableId, 0); + for (i = 0; i < array_n(var_array); i++) { + var = array_fetch(bdd_t *, var_array, i); + array_insert_last(bdd_variableId, result, bdd_top_var_id(var)); + } + return result; +} + +unsigned int +bdd_num_vars(mgr) +struct bdd_manager_ *mgr; +{ + return (cmu_bdd_vars(mgr)); +} + +void +bdd_print(f) +bdd_t *f; +{ + cmu_bdd_print_bdd(f->mgr, f->node, bdd_naming_fn_none, bdd_terminal_id_fn_none, (pointer) 0, stdout); +} + +void +bdd_print_stats(stats, file) +bdd_stats stats; +FILE *file; +{ + struct bdd_manager_ *mgr; + + mgr = (struct bdd_manager_ *) stats.gc.runtime; + cmu_bdd_stats(mgr, file); +} + +int +bdd_size(f) +bdd_t *f; +{ + return ((int) cmu_bdd_size(f->mgr, f->node, 1)); +} + +bdd_variableId +bdd_top_var_id(f) +bdd_t *f; +{ + return ((bdd_variableId) (cmu_bdd_if_id(f->mgr, f->node) - 1)); +} + +/* +Miscellaneous ----------------------------------------------------------------- +*/ + +bdd_external_hooks * +bdd_get_external_hooks(mgr) +struct bdd_manager_ *mgr; +{ + return ((bdd_external_hooks *) mgr->hooks); +} + +void +bdd_register_daemon(mgr, daemon) +struct bdd_manager_ *mgr; +void (*daemon)(); +{ + cmu_bdd_warning("bdd_register_daemon: translated to no-op in CMU package"); +} + +void +bdd_set_gc_mode(mgr, no_gc) +struct bdd_manager_ *mgr; +boolean no_gc; +{ + cmu_bdd_warning("bdd_set_gc_mode: translated to no-op in CMU package"); +} + +void +bdd_dynamic_reordering(mgr, algorithm_type) +struct bdd_manager_ *mgr; +bdd_reorder_type_t algorithm_type; +{ + switch(algorithm_type) { + case BDD_REORDER_SIFT: + cmu_bdd_dynamic_reordering(mgr, cmu_bdd_reorder_sift); + break; + case BDD_REORDER_WINDOW: + cmu_bdd_dynamic_reordering(mgr, cmu_bdd_reorder_stable_window3); + break; + case BDD_REORDER_NONE: + cmu_bdd_dynamic_reordering(mgr, cmu_bdd_reorder_none); + break; + default: + cmu_bdd_fatal("bdd_dynamic_reordering: unknown algorithm type"); + } +} + +void +bdd_reorder(mgr) +struct bdd_manager_ *mgr; +{ + cmu_bdd_reorder(mgr); +} + +bdd_variableId +bdd_get_id_from_level(mgr, level) +struct bdd_manager_ *mgr; +long level; +{ + struct bdd_ *fn; + + fn = cmu_bdd_var_with_index(mgr, level); + + if (fn == (struct bdd_ *) 0) { + /* variable should always be found, since they are created at bdd_start */ + cmu_bdd_fatal("bdd_get_id_from_level: assumption violated"); + } + + return ((bdd_variableId)(cmu_bdd_if_id(mgr, fn) - 1 )); + +} + +long +bdd_top_var_level(mgr, fn) +struct bdd_manager_ *mgr; +bdd_t *fn; +{ + + return cmu_bdd_if_index(mgr, fn->node); +} + + diff --git a/sis/bdd_cmu/mem/Makefile.am b/sis/bdd_cmu/mem/Makefile.am new file mode 100644 index 0000000..6bb73b1 --- /dev/null +++ b/sis/bdd_cmu/mem/Makefile.am @@ -0,0 +1,9 @@ +libmem_a_SOURCES_local = memblock.c memrec.c memint.h memuser.h + +if SIS_COND_CMUBDD +noinst_LIBRARIES = libmem.a +libmem_a_SOURCES = $(libmem_a_SOURCES_local) +dist_man3_MANS = mem.3 +endif + +EXTRA_DIST = $(libmem_a_SOURCES_local) mem.3 diff --git a/sis/bdd_cmu/mem/Makefile.in b/sis/bdd_cmu/mem/Makefile.in new file mode 100644 index 0000000..337509a --- /dev/null +++ b/sis/bdd_cmu/mem/Makefile.in @@ -0,0 +1,426 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(libmem_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/bdd_cmu/mem +DIST_COMMON = $(dist_man3_MANS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libmem_a_AR = $(AR) $(ARFLAGS) +libmem_a_LIBADD = +am__libmem_a_SOURCES_DIST = memblock.c memrec.c memint.h memuser.h +am__objects_1 = memblock.$(OBJEXT) memrec.$(OBJEXT) +@SIS_COND_CMUBDD_TRUE@am_libmem_a_OBJECTS = $(am__objects_1) +libmem_a_OBJECTS = $(am_libmem_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libmem_a_SOURCES) +DIST_SOURCES = $(am__libmem_a_SOURCES_DIST) +man3dir = $(mandir)/man3 +am__installdirs = "$(DESTDIR)$(man3dir)" +NROFF = nroff +MANS = $(dist_man3_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +libmem_a_SOURCES_local = memblock.c memrec.c memint.h memuser.h +@SIS_COND_CMUBDD_TRUE@noinst_LIBRARIES = libmem.a +@SIS_COND_CMUBDD_TRUE@libmem_a_SOURCES = $(libmem_a_SOURCES_local) +@SIS_COND_CMUBDD_TRUE@dist_man3_MANS = mem.3 +EXTRA_DIST = $(libmem_a_SOURCES_local) mem.3 +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/bdd_cmu/mem/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/bdd_cmu/mem/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libmem.a: $(libmem_a_OBJECTS) $(libmem_a_DEPENDENCIES) + -rm -f libmem.a + $(libmem_a_AR) libmem.a $(libmem_a_OBJECTS) $(libmem_a_LIBADD) + $(RANLIB) libmem.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-man3: $(man3_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man3dir)" || $(mkdir_p) "$(DESTDIR)$(man3dir)" + @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.3*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 3*) ;; \ + *) ext='3' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \ + done +uninstall-man3: + @$(NORMAL_UNINSTALL) + @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.3*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 3*) ;; \ + *) ext='3' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man3dir)/$$inst"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(man3dir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-man + +install-exec-am: + +install-info: install-info-am + +install-man: install-man3 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-man + +uninstall-man: uninstall-man3 + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-man3 install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am uninstall-man uninstall-man3 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/bdd_cmu/mem/mem.3 b/sis/bdd_cmu/mem/mem.3 new file mode 100644 index 0000000..24e9994 --- /dev/null +++ b/sis/bdd_cmu/mem/mem.3 @@ -0,0 +1,173 @@ +.\" Storage management library man page +.TH MEM 3 "16 November 1993" +.SH NAME +mem \- a memory management package +.SH SYNOPSIS +.B #include +.SH DESCRIPTION +The +.B libmem +library provides a set of routines for allocating storage. Programs +designed to be used with the library should use the +.B -lmem +options to +.B cc +when linking. +.SH "LIST OF FUNCTIONS" +.nf +.ta 3in +\fIName\fP \fIFunction\fP +mem_get_block Allocate a block of memory +mem_free_block Free a block of memory +mem_resize_block Resize a block of memory +mem_copy Copy a block of memory +mem_zero Initialize a block of memory to all zeros +mem_allocation Get total memory allocation +mem_new_rec_mgr Create a record manager +mem_free_rec_mgr Destroy a record manager +mem_new_rec Get a record from a record manager +mem_free_rec Return a record to a record manager +.fi +.SH "OVERVIEW" +The library includes routines for handling blocks of memory and for +dealing with fixed size records. The block manipulation routines use +a binary buddy scheme, so fragmentation generally is not a problem. +The record manager routines are designed for handling many small, +fixed size records. There is essentially no storage overhead when +using these routines, and allocation and deallocation are particularly +fast. +.SH "DETAILED DESCRIPTION" +.B pointer +.br +.B mem_get_block(size) +.br +.B long size; +.in +4 +Allocate a block of storage +.B size +bytes long. The type +.B pointer +is defined to be either a character pointer or a void pointer, +depending on whether the C compiler is ANSI-standard. +.LP +.B void +.br +.B mem_free_block(p) +.br +.B pointer p; +.in +4 +Free the block of storage pointed to by \fBp\fR. +.LP +.B pointer +.br +.B mem_resize_block(p, size) +.br +.B pointer p; +.br +.B long size; +.in +4 +Try to resize the block of memory pointed to by +.B p +to be +.B size +bytes long. If this is not possible, a new block is allocated and the +contents of the old block are copied. A pointer to the expanded block +is returned. +.LP +.B void +.br +.B mem_copy(p, q, size) +.br +.B pointer p; +.br +.B pointer q; +.br +.B long size; +.in +4 +Copy +.B size +bytes from the location given by +.B q +to the location give by \fBp\fR. +.LP +.LP +.B void +.br +.B mem_zero(p, size) +.br +.B pointer p; +.br +.B long size; +.in +4 +Fill +.B size +bytes at the location given by +.B p +with zero. +.LP +.B long +.br +.B mem_allocation() +.in +4 +Returns the total memory allocation in bytes. +.LP +.B rec_mgr +.br +.B mem_new_rec_mgr(size) +.br +.B int size; +.in +4 +Returns a new record manager for handling record of +.B size +bytes. The size is limited to approximately 4K, but is really +intended to be smaller. +.LP +.B void +.br +.B mem_free_rec_mgr(m) +.br +.B rec_mgr m; +.in +4 +Free the record manager given by +.B m +and all of its associated storage. +.LP +.B pointer +.br +.B mem_new_rec(m) +.br +.B rec_mgr m; +.in +4 +Return a pointer to a new record. +.LP +.B void +.br +.B mem_free_rec(m, p) +.br +.B rec_mgr m; +.br +.B pointer p; +.in +4 +Return the record pointed to by +.B p +to the record manager \fBm\fR. +.SH "PORTABILITY NOTES" +The library is fairly UNIX specific; it calls +.B sbrk +directly. If you don't have something similar, you may have to +rewrite parts of it. The storage management routines need to be able +to move and clear blocks of memory whose size is given by a long. You +may have to fiddle with these, especially if you have a machine where +int and long are different. If you encounter portability problems, +let me know; maybe the next release will be able to accommodate your +machine. For non-UNIX people, or if you are using malloc elsewhere +and it is unhappy about other routines calling sbrk, you can try +defining the symbol USE_MALLOC_FREE in memint.h. It turns calls to +the memory management library routines into calls to malloc, free, and +cousins. This has not been tested extensively. +.SH BUGS +It's a feature. +.SH AUTHOR +David E. Long +.br +long@research.att.com diff --git a/sis/bdd_cmu/mem/memblock.c b/sis/bdd_cmu/mem/memblock.c new file mode 100644 index 0000000..a0cad32 --- /dev/null +++ b/sis/bdd_cmu/mem/memblock.c @@ -0,0 +1,483 @@ +/* Memory block management routines */ + + +#include "memint.h" + + +#if defined(__STDC__) +extern void exit(int); +#else +extern void exit(); +#endif + + +/* Amount of memory allocated */ + +static SIZE_T block_allocation; + + +/* mem_copy(dest, src, size) copies a block of memory. */ + +void +#if defined(__STDC__) +mem_copy(pointer dest, pointer src, SIZE_T size) +#else +mem_copy(dest, src, size) + pointer dest; + pointer src; + SIZE_T size; +#endif +{ + MEM_COPY(dest, src, size); +} + + +/* mem_zero(ptr, size) zeros a block of memory. */ + +void +#if defined(__STDC__) +mem_zero(pointer ptr, SIZE_T size) +#else +mem_zero(ptr, size) + pointer ptr; + SIZE_T size; +#endif +{ + MEM_ZERO(ptr, size); +} + + +/* mem_fatal(message) prints an error message and exits. */ + +void +#if defined(__STDC__) +mem_fatal(char *message) +#else +mem_fatal(message) + char *message; +#endif +{ + fprintf(stderr, "Memory management library: error: %s\n", message); + exit(1); +} + + +SIZE_T +#if defined(__STDC__) +mem_allocation(void) +#else +mem_allocation() +#endif +{ + /* This will always returns zero when we're using malloc and free, */ + /* but you can maybe change it depending on your system. */ + return (block_allocation); +} + + +/* This code used if we're going to do our own memory management. */ + +#if !defined(USE_MALLOC_FREE) +/* Free lists of various sizes */ + +static block avail[MAX_SIZE_INDEX+1]; + + +/* Bogus segment for initialization */ + +static struct segment_ dummy_seg={(pointer)0, (SIZE_T)0}; + + +/* Current segment */ + +static segment curr_seg= &dummy_seg; + + +static +int +#if defined(__STDC__) +ceiling_log_2(SIZE_T i) +#else +ceiling_log_2(i) + SIZE_T i; +#endif +{ + SIZE_T j; + int result; + + for (result=0, j=1; j < i; ++result, j*=2); + return (result); +} + + +/* block_size_index(size) return the coded size for a block. */ + +static +int +#if defined(__STDC__) +block_size_index(SIZE_T size) +#else +block_size_index(size) + SIZE_T size; +#endif +{ + if (size < 1) + return (-1); + if (size > MAX_SIZE) + mem_fatal("block_size_index: block size too large"); + else + size+=HEADER_SIZE; + return (ceiling_log_2(size)); +} + + +/* add_to_free_list(b) adds b to the appropriate free list. */ + +static +void +#if defined(__STDC__) +add_to_free_list(block b) +#else +add_to_free_list(b) + block b; +#endif +{ + int i; + + i=b->size_index; + if (!avail[i]) + { + b->next=b; + b->prev=b; + avail[i]=b; + } + else + { + b->next=avail[i]->next; + avail[i]->next->prev=b; + avail[i]->next=b; + b->prev=avail[i]; + } + b->used=0; +} + + +/* remove_from_free_list(b) removes b from the free list which it */ +/* is on. */ + +static +block +#if defined(__STDC__) +remove_from_free_list(block b) +#else +remove_from_free_list(b) + block b; +#endif +{ + int i; + + i=b->size_index; + if (b->next == b) + avail[i]=0; + else + { + b->next->prev=b->prev; + b->prev->next=b->next; + if (avail[i] == b) + avail[i]=b->next; + } + b->used=1; + return (b); +} + + +/* buddy(b) returns the buddy block of b, or null if there is no */ +/* buddy. */ + +static +block +#if defined(__STDC__) +buddy(block b) +#else +buddy(b) + block b; +#endif +{ + SIZE_T buddy_offset; + + buddy_offset=(SIZE_T)(((INT_PTR)b-(INT_PTR)b->seg->base_address) ^ ((SIZE_T)1 << b->size_index)); + if (buddy_offset < b->seg->limit) + return ((block)((INT_PTR)b->seg->base_address+buddy_offset)); + else + return ((block)0); +} + + +/* trim_to_size(b, size_index) repeatedly splits b until it has */ +/* the indicated size. Blocks which are split off are added to the */ +/* appropriate free list. */ + +static +void +#if defined(__STDC__) +trim_to_size(block b, int size_index) +#else +trim_to_size(b, size_index) + block b; + int size_index; +#endif +{ + block bb; + + while (b->size_index > size_index) + { + b->size_index--; + bb=buddy(b); + bb->size_index=b->size_index; + bb->seg=b->seg; + add_to_free_list(bb); + } +} + + +/* merge_and_free(b) repeatedly merges b its buddy until b has no */ +/* buddy or the buddy isn't free, then adds the result to the */ +/* appropriate free list. */ + +static +void +#if defined(__STDC__) +merge_and_free(block b) +#else +merge_and_free(b) + block b; +#endif +{ + block bb; + + for (bb=buddy(b); bb && !bb->used && bb->size_index == b->size_index; bb=buddy(b)) + { + remove_from_free_list(bb); + if ((INT_PTR)bb < (INT_PTR)b) + b=bb; + b->size_index++; + } + add_to_free_list(b); +} + + +/* mem_get_block(size) allocates a new block of the specified size. */ + +pointer +#if defined(__STDC__) +mem_get_block(SIZE_T size) +#else +mem_get_block(size) + SIZE_T size; +#endif +{ + int i; + int size_index; + int alloc_size_index; + int new_seg; + SIZE_T alloc_size; + pointer sbrk_ret; + block b; + + if ((size_index=block_size_index(size)) < 0) + return ((pointer)0); + /* Find smallest free block which is large enough. */ + for (i=size_index; i <= MAX_SIZE_INDEX && !avail[i]; ++i); + if (i > MAX_SIZE_INDEX) + { + /* We must get more storage; don't allocate less than */ + /* 2^MIN_ALLOC_SIZE_INDEX. */ + if (size_index < MIN_ALLOC_SIZE_INDEX) + alloc_size_index=MIN_ALLOC_SIZE_INDEX; + else + alloc_size_index=size_index; + alloc_size=((SIZE_T)1 << alloc_size_index); + /* Pad current segment to be a multiple of 2^alloc_size_index in */ + /* length. */ + alloc_size+=((curr_seg->limit+alloc_size-1) & ~(alloc_size-1))-curr_seg->limit; + if ((sbrk_ret=(pointer)SBRK(0)) != (pointer)((INT_PTR)curr_seg->base_address+curr_seg->limit) || + alloc_size+curr_seg->limit > MAX_SEG_SIZE) + { + /* Segment is too large or someone else has moved the break. */ + /* Pad to get to appropriate boundary. */ + alloc_size=ROUNDUP((INT_PTR)sbrk_ret)-(INT_PTR)sbrk_ret; + /* Pad allocation request with storage for new segment */ + /* information and indicate that a new segment must be */ + /* created. */ + alloc_size+=((SIZE_T)1 << alloc_size_index)+ROUNDUP(sizeof(struct segment_)); + new_seg=1; + } + else + new_seg=0; + sbrk_ret=(pointer)SBRK(alloc_size); + if (sbrk_ret == (pointer)-1) + mem_fatal("mem_get_block: allocation failed"); + block_allocation+=alloc_size; + if (new_seg) + { + curr_seg=(segment)ROUNDUP((INT_PTR)sbrk_ret); + curr_seg->base_address=(pointer)((INT_PTR)curr_seg+ROUNDUP(sizeof(struct segment_))); + curr_seg->limit=0; + /* Readjust allocation size. */ + alloc_size=(1l << alloc_size_index); + } + /* Carve allocated space up into blocks and add to free lists. */ + while (alloc_size) + { + size=alloc_size-(alloc_size & (alloc_size-1)); + b=(block)((INT_PTR)curr_seg->base_address+curr_seg->limit); + b->size_index=ceiling_log_2(size); + b->seg=curr_seg; + add_to_free_list(b); + curr_seg->limit+=size; + alloc_size-=size; + } + /* Find free block of appropriate size. */ + for (i=size_index; i <= MAX_SIZE_INDEX && !avail[i]; ++i); + } + b=remove_from_free_list(avail[i]); + trim_to_size(b, size_index); + return ((pointer)((INT_PTR)b+HEADER_SIZE)); +} + + +/* mem_free_block(p) frees the block indicated by p. */ + +void +#if defined(__STDC__) +mem_free_block(pointer p) +#else +mem_free_block(p) + pointer p; +#endif +{ + block b; + + if (!p) + return; + b=(block)((INT_PTR)p-HEADER_SIZE); + if (!b->used) + mem_fatal("mem_free_block: block not in use"); + if (b->size_index < 0 || b->size_index > MAX_SIZE_INDEX) + mem_fatal("mem_free_block: invalid block header"); + merge_and_free(b); +} + + +/* mem_resize_block(p, new_size) expands or contracts the block */ +/* indicated by p to a new size. We try to avoid moving the block if */ +/* possible. */ + +pointer +#if defined(__STDC__) +mem_resize_block(pointer p, SIZE_T new_size) +#else +mem_resize_block(p, new_size) + pointer p; + SIZE_T new_size; +#endif +{ + int new_size_index; + block b; + block bb; + pointer q; + SIZE_T old_size; + + if (!p) + return (mem_get_block(new_size)); + b=(block)((INT_PTR)p-HEADER_SIZE); + if (!b->used) + mem_fatal("mem_resize_block: block not in use"); + if (b->size_index < 0 || b->size_index > MAX_SIZE_INDEX) + mem_fatal("mem_resize_block: invalid block header"); + if ((new_size_index=block_size_index(new_size)) < 0) + { + mem_free_block(p); + return ((pointer)0); + } + if (b->size_index >= new_size_index) + { + /* Shrink block. */ + trim_to_size(b, new_size_index); + return (p); + } + old_size=(1l << b->size_index)-HEADER_SIZE; + /* Try to expand by adding buddies at higher addresses. */ + for (bb=buddy(b); + bb && (INT_PTR)b < (INT_PTR)bb && !bb->used && bb->size_index == b->size_index; + bb=buddy(b)) + { + remove_from_free_list(bb); + if (++(b->size_index) == new_size_index) + return (p); + } + /* Couldn't expand all the way to needed size; allocate a new block */ + /* and move the contents of the old one. */ + q=mem_get_block(new_size); + mem_copy(q, p, old_size); + merge_and_free(b); + return (q); +} +#endif + + +/* This code used if we're using malloc and free. */ + +#if defined(USE_MALLOC_FREE) +pointer +#if defined(__STDC__) +mem_get_block(SIZE_T size) +#else +mem_get_block(size) + SIZE_T size; +#endif +{ + pointer result; + + if (size <= 0) + return ((pointer)0); + result=MALLOC(size); + if (!result) + mem_fatal("mem_get_block: allocation failed"); + return (result); +} + + +void +#if defined(__STDC__) +mem_free_block(pointer p) +#else +mem_free_block(p) + pointer p; +#endif +{ + if (!p) + return; + FREE(p); +} + + +pointer +#if defined(__STDC__) +mem_resize_block(pointer p, SIZE_T new_size) +#else +mem_resize_block(p, new_size) + pointer p; + SIZE_T new_size; +#endif +{ + if (!p) + return (mem_get_block(new_size)); + if (new_size <= 0) + { + mem_free_block(p); + return ((pointer)0); + } + return (REALLOC(p, new_size)); +} +#endif diff --git a/sis/bdd_cmu/mem/memint.h b/sis/bdd_cmu/mem/memint.h new file mode 100644 index 0000000..9e3c905 --- /dev/null +++ b/sis/bdd_cmu/mem/memint.h @@ -0,0 +1,116 @@ +/* Memory management internal definitions */ + + +#if !defined(_MEMINTH) +#define _MEMINTH + + +/* All user-visible stuff */ + +#include "memuser.h" + + +/* >>> Potentially system dependent configuration stuff */ +/* See memuser.h as well. */ + +/* The storage management library can either use system-provided */ +/* versions of malloc, free and friends, or it can implement a buddy */ +/* scheme based on something like sbrk. If you want to do the former, */ +/* define USE_MALLOC_FREE. */ + +/* #define USE_MALLOC_FREE */ + +/* Now we need macros for routines to copy and zero-fill blocks of */ +/* memory, and to either do malloc/free/whatever or to do an sbrk. Since */ +/* different systems have different types that these routines expect, we */ +/* wrap everything in macros. */ + +#if defined(USE_MALLOC_FREE) +#if defined(__STDC__) +extern void *malloc(unsigned long); +extern void free(void *); +extern void *realloc(void *, unsigned long); +#define MALLOC(size) ((pointer)malloc((unsigned long)(size))) +#define FREE(p) (free((void *)(p))) +#define REALLOC(p, size) ((pointer)realloc((void *)(p), (unsigned long)(size))) +#else +extern char *malloc(); +extern void free(); +extern char *realloc(); +#define MALLOC(size) ((pointer)malloc((int)(size))) +#define FREE(p) (free((char *)(p))) +#define REALLOC(p, size) ((pointer)realloc((char *)(p), (int)(size))) +#endif +#else +#if defined(__STDC__) +extern char *sbrk(int); +#define SBRK(size) ((pointer)sbrk((int)(size))) +#else +extern char *sbrk(); +#define SBRK(size) ((pointer)sbrk((int)(size))) +#endif +#endif + +/* You may need to muck with these depending on whether you have */ +/* bcopy or memcpy. */ + +#if defined(__STDC__) +extern void *memcpy(); /* TRS, 6/17/94: removed arg types to suppress warning on mips/gcc */ +/* extern void *memcpy(void *, const void *, unsigned long); */ +extern void *memset(); +/* extern void *memset(void *, int, unsigned long); */ +#define MEM_COPY(dest, src, size) (void)memcpy((void *)(dest), (const void *)(src), (unsigned long)(size)) +#define MEM_ZERO(ptr, size) (void)memset((void *)(ptr), 0, (unsigned long)(size)) +#else +extern void bcopy(); +extern void bzero(); +#define MEM_COPY(dest, src, size) bcopy((char *)(src), (char *)(dest), (int)(size)) +#define MEM_ZERO(ptr, size) bzero((char *)(ptr), (int)(size)) +#endif + + +#if defined(__STDC__) +#define ARGS(args) args +#else +#define ARGS(args) () +#endif + + +/* >>> System independent stuff here. */ + +struct segment_ +{ + pointer base_address; + SIZE_T limit; +}; + +typedef struct segment_ *segment; + + +struct block_ +{ + int used; + int size_index; + struct block_ *next; + struct block_ *prev; + segment seg; +}; + +typedef struct block_ *block; + + +#define HEADER_SIZE ((SIZE_T)ROUNDUP(sizeof(struct block_))) +#define MAX_SIZE_INDEX (8*sizeof(SIZE_T)-2) +#define MAX_SEG_SIZE ((SIZE_T)1 << MAX_SIZE_INDEX) +#define MAX_SIZE ((SIZE_T)(MAX_SEG_SIZE-HEADER_SIZE)) +#define MIN_ALLOC_SIZE_INDEX 15 + +#define NICE_BLOCK_SIZE ((SIZE_T)4096-ROUNDUP(sizeof(struct block_))) + + +extern void mem_fatal ARGS((char *)); + + +#undef ARGS + +#endif diff --git a/sis/bdd_cmu/mem/memrec.c b/sis/bdd_cmu/mem/memrec.c new file mode 100644 index 0000000..d49515d --- /dev/null +++ b/sis/bdd_cmu/mem/memrec.c @@ -0,0 +1,156 @@ +/* Record manager routines */ + + +#include "memint.h" + + +#define ALLOC_SIZE NICE_BLOCK_SIZE + + +/* #define DEBUG_MEM */ +#define MAGIC_COOKIE 0x34f21ab3l +#define MAGIC_COOKIE1 0x432fa13bl + + +struct list_ +{ + struct list_ *next; +}; + +typedef struct list_ *list; + + +struct rec_mgr_ +{ + int size; + int recs_per_block; + list free; + list blocks; +}; + + +/* mem_new_rec(mgr) allocates a record from the specified record */ +/* manager. */ + +pointer +#if defined(__STDC__) +mem_new_rec(rec_mgr mgr) +#else +mem_new_rec(mgr) + rec_mgr mgr; +#endif +{ + int i; + pointer p; + list new; + + if (!mgr->free) + { + /* Allocate a new block. */ + new=(list)mem_get_block(ALLOC_SIZE); + new->next=mgr->blocks; + mgr->blocks=new; + mgr->free=(list)((INT_PTR)new+ROUNDUP(sizeof(struct list_))); + p=(pointer)(mgr->free); + /* Carve the block into pieces. */ + for (i=1; i < mgr->recs_per_block; ++i) + { + ((list)p)->next=(list)((INT_PTR)p+mgr->size); +#if defined(DEBUG_MEM) + if (mgr->size >= sizeof(long)+sizeof(struct list_)) + *(long *)(sizeof(struct list_)+(INT_PTR)p)=MAGIC_COOKIE; +#endif + p=(pointer)((INT_PTR)p+mgr->size); + } + ((list)p)->next=0; +#if defined(DEBUG_MEM) + if (mgr->size >= sizeof(long)+sizeof(struct list_)) + *(long *)(sizeof(struct list_)+(INT_PTR)p)=MAGIC_COOKIE; +#endif + } + new=mgr->free; +#if defined(DEBUG_MEM) + if (mgr->size >= sizeof(long)+sizeof(struct list_)) + if (*(long *)(sizeof(struct list_)+(INT_PTR)new) != MAGIC_COOKIE) + fprintf(stderr, "record at 0x%lx may be in use\n", (INT_PTR)new); + else + *(long *)(sizeof(struct list_)+(INT_PTR)new)=MAGIC_COOKIE1; +#endif + mgr->free=mgr->free->next; + return ((pointer)new); +} + + +/* mem_free_rec(mgr, rec) frees a record managed by the indicated */ +/* record manager. */ + +void +#if defined(__STDC__) +mem_free_rec(rec_mgr mgr, pointer rec) +#else +mem_free_rec(mgr, rec) + rec_mgr mgr; + pointer rec; +#endif +{ +#if defined(DEBUG_MEM) + if (mgr->size >= sizeof(long)+sizeof(struct list_)) + if (*(long *)(sizeof(struct list_)+(INT_PTR)rec) == MAGIC_COOKIE) + fprintf(stderr, "record at 0x%lx may already be freed\n", (INT_PTR)rec); +#endif + ((list)rec)->next=mgr->free; +#if defined(DEBUG_MEM) + if (mgr->size >= sizeof(long)+sizeof(struct list_)) + *(long *)(sizeof(struct list_)+(INT_PTR)rec)=MAGIC_COOKIE; +#endif + mgr->free=(list)rec; +} + + +/* mem_new_rec_mgr(size) creates a new record manager with the given */ +/* record size. */ + +rec_mgr +#if defined(__STDC__) +mem_new_rec_mgr(int size) +#else +mem_new_rec_mgr(size) + int size; +#endif +{ + rec_mgr mgr; + + if (size < sizeof(struct list_)) + size=sizeof(struct list_); + size=ROUNDUP(size); + if (size > ALLOC_SIZE-ROUNDUP(sizeof(struct list_))) + mem_fatal("mem_new_rec_mgr: record size too large"); + mgr=(rec_mgr)mem_get_block((SIZE_T)sizeof(struct rec_mgr_)); + mgr->size=size; + mgr->recs_per_block=(ALLOC_SIZE-ROUNDUP(sizeof(struct list_)))/size; + mgr->free=0; + mgr->blocks=0; + return (mgr); +} + + +/* mem_free_rec_mgr(mgr) frees all the storage associated with the */ +/* specified record manager. */ + +void +#if defined(__STDC__) +mem_free_rec_mgr(rec_mgr mgr) +#else +mem_free_rec_mgr(mgr) + rec_mgr mgr; +#endif +{ + list p, q; + + for (p=mgr->blocks; p; p=q) + { + q=p->next; + mem_free_block((pointer)p); + } + mem_free_block((pointer)mgr); +} diff --git a/sis/bdd_cmu/mem/memuser.h b/sis/bdd_cmu/mem/memuser.h new file mode 100644 index 0000000..6c40a7f --- /dev/null +++ b/sis/bdd_cmu/mem/memuser.h @@ -0,0 +1,75 @@ +/* Memory management user-visible definitions */ + + +#if !defined(_MEMUSERH) +#define _MEMUSERH + + +#include + + +#if defined(__STDC__) +#define ARGS(args) args +#else +#define ARGS(args) () +#endif + + +/* >>> Potentially machine dependent stuff */ +/* See memint.h as well. */ + +typedef unsigned long INT_PTR; /* Integral type that can hold a pointer */ +typedef unsigned long SIZE_T; /* Integral type that can hold the maximum */ + /* size of an object */ + +/* REQUIRED_ALIGNMENT is the alignment required by the machine hardware; */ +/* it is provided for user use. */ + +#define REQUIRED_ALIGNMENT 4 + + +/* Types */ + +#if defined(__STDC__) +typedef void *pointer; +#else +typedef char *pointer; +#endif + + +typedef struct rec_mgr_ *rec_mgr; + + +/* ALLOC_ALIGNMENT is the alignment for all storage returned by the */ +/* storage allocation routines. */ + +#define ALLOC_ALIGNMENT 8 + + +/* Round a size up for alignment */ + +#define ROUNDUP(size) ((((size)+ALLOC_ALIGNMENT-1)/ALLOC_ALIGNMENT)*ALLOC_ALIGNMENT) +#define ALIGN(size) ((((size)+REQUIRED_ALIGNMENT-1)/REQUIRED_ALIGNMENT)*REQUIRED_ALIGNMENT) + + +/* Block storage management routines */ + +extern pointer mem_get_block ARGS((SIZE_T)); +extern void mem_free_block ARGS((pointer)); +extern pointer mem_resize_block ARGS((pointer, SIZE_T)); +extern void mem_copy ARGS((pointer, pointer, SIZE_T)); +extern void mem_zero ARGS((pointer, SIZE_T)); +extern SIZE_T mem_allocation ARGS((void)); + + +/* Record manager routines */ + +extern pointer mem_new_rec ARGS((rec_mgr)); +extern void mem_free_rec ARGS((rec_mgr, pointer)); +extern rec_mgr mem_new_rec_mgr ARGS((int)); +extern void mem_free_rec_mgr ARGS((rec_mgr)); + + +#undef ARGS + +#endif diff --git a/sis/bdd_cudd/Makefile.am b/sis/bdd_cudd/Makefile.am new file mode 100644 index 0000000..91bf81b --- /dev/null +++ b/sis/bdd_cudd/Makefile.am @@ -0,0 +1,143 @@ +AM_CPPFLAGS = -I../include + +libbdd_cudd_a_SOURCES_local = \ + cuddAPI.c \ + cuddAddAbs.c \ + cuddAddApply.c \ + cuddAddFind.c \ + cuddAddInv.c \ + cuddAddIte.c \ + cuddAddNeg.c \ + cuddAddWalsh.c \ + cuddAndAbs.c \ + cuddAnneal.c \ + cuddApa.c \ + cuddApprox.c \ + cuddBddAbs.c \ + cuddBddCorr.c \ + cuddBddIte.c \ + cuddBridge.c \ + cuddCache.c \ + cuddCheck.c \ + cuddClip.c \ + cuddCof.c \ + cuddCompose.c \ + cuddDecomp.c \ + cuddEssent.c \ + cuddExact.c \ + cuddExport.c \ + cuddGenCof.c \ + cuddGenetic.c \ + cuddGroup.c \ + cuddHarwell.c \ + cuddInit.c \ + cuddInteract.c \ + cuddLCache.c \ + cuddLevelQ.c \ + cuddLinear.c \ + cuddLiteral.c \ + cuddMatMult.c \ + cuddPriority.c \ + cuddRead.c \ + cuddRef.c \ + cuddReorder.c \ + cuddSat.c \ + cuddSign.c \ + cuddSolve.c \ + cuddSplit.c \ + cuddSubsetHB.c \ + cuddSubsetSP.c \ + cuddSymmetry.c \ + cuddTable.c \ + cuddUtil.c \ + cuddWindow.c \ + cuddZddCount.c \ + cuddZddFuncs.c \ + cuddZddGroup.c \ + cuddZddIsop.c \ + cuddZddLin.c \ + cuddZddMisc.c \ + cuddZddPort.c \ + cuddZddReord.c \ + cuddZddSetop.c \ + cuddZddSymm.c \ + cuddZddUtil.c \ + cudd.h \ + cuddInt.h \ + cuddBddPort.c \ + cuddPwPt.c \ + cuddBdd.h \ + epd.c \ + epd.h \ + datalimit.c + +libcudd_mtr_a_SOURCES_local = \ + mtrBasic.c \ + mtrGroup.c \ + mtr.h \ + mtrInt.h + +libcudd_st_a_SOURCES_local = \ + st.c \ + st.h + +if SIS_COND_CUDD + +BUILT_SOURCES = $(libbdd_cudd_a_SOURCES_local) bdd.h \ + $(libcudd_mtr_a_SOURCES_local) \ + $(libcudd_st_a_SOURCES_local) + +install: $(BUILT_SOURCES) +CLEANFILES = $(BUILT_SOURCES) + +noinst_LIBRARIES = libbdd_cudd.a libcudd_mtr.a libcudd_st.a +nodist_libbdd_cudd_a_SOURCES = $(libbdd_cudd_a_SOURCES_local) +nodist_libcudd_mtr_a_SOURCES = $(libcudd_mtr_a_SOURCES_local) +nodist_libcudd_st_a_SOURCES = $(libcudd_st_a_SOURCES_local) +nodist_pkginclude_HEADERS = bdd.h mtr.h st.h + +%.c: @SIS_CUDDDIR@/cudd/%.c + $(RM) $@ + $(LN_S) $< $@ + +%.h: @SIS_CUDDDIR@/cudd/%.h + $(RM) $@ + $(LN_S) $< $@ + +%.c: @SIS_CUDDDIR@/epd/%.c + $(RM) $@ + $(LN_S) $< $@ + +%.h: @SIS_CUDDDIR@/epd/%.h + $(RM) $@ + $(LN_S) $< $@ + +%.c: @SIS_CUDDDIR@/mtr/%.c + $(RM) $@ + $(LN_S) $< $@ + +%.h: @SIS_CUDDDIR@/mtr/%.h + $(RM) $@ + $(LN_S) $< $@ + +%.c: @SIS_CUDDDIR@/sis/%.c + $(RM) $@ + $(LN_S) $< $@ + +%.h: @SIS_CUDDDIR@/sis/%.h + $(RM) $@ + $(LN_S) $< $@ + +%.c: @SIS_CUDDDIR@/util/%.c + $(RM) $@ + $(LN_S) $< $@ + +%.h: @SIS_CUDDDIR@/util/%.h + $(RM) $@ + $(LN_S) $< $@ + +bdd.h: cuddBdd.h + $(RM) $@ + $(LN_S) $< $@ + +endif diff --git a/sis/bdd_cudd/Makefile.in b/sis/bdd_cudd/Makefile.in new file mode 100644 index 0000000..51babd5 --- /dev/null +++ b/sis/bdd_cudd/Makefile.in @@ -0,0 +1,578 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +SOURCES = $(nodist_libbdd_cudd_a_SOURCES) $(nodist_libcudd_mtr_a_SOURCES) $(nodist_libcudd_st_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/bdd_cudd +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libbdd_cudd_a_AR = $(AR) $(ARFLAGS) +libbdd_cudd_a_LIBADD = +am__objects_1 = cuddAPI.$(OBJEXT) cuddAddAbs.$(OBJEXT) \ + cuddAddApply.$(OBJEXT) cuddAddFind.$(OBJEXT) \ + cuddAddInv.$(OBJEXT) cuddAddIte.$(OBJEXT) cuddAddNeg.$(OBJEXT) \ + cuddAddWalsh.$(OBJEXT) cuddAndAbs.$(OBJEXT) \ + cuddAnneal.$(OBJEXT) cuddApa.$(OBJEXT) cuddApprox.$(OBJEXT) \ + cuddBddAbs.$(OBJEXT) cuddBddCorr.$(OBJEXT) \ + cuddBddIte.$(OBJEXT) cuddBridge.$(OBJEXT) cuddCache.$(OBJEXT) \ + cuddCheck.$(OBJEXT) cuddClip.$(OBJEXT) cuddCof.$(OBJEXT) \ + cuddCompose.$(OBJEXT) cuddDecomp.$(OBJEXT) \ + cuddEssent.$(OBJEXT) cuddExact.$(OBJEXT) cuddExport.$(OBJEXT) \ + cuddGenCof.$(OBJEXT) cuddGenetic.$(OBJEXT) cuddGroup.$(OBJEXT) \ + cuddHarwell.$(OBJEXT) cuddInit.$(OBJEXT) \ + cuddInteract.$(OBJEXT) cuddLCache.$(OBJEXT) \ + cuddLevelQ.$(OBJEXT) cuddLinear.$(OBJEXT) \ + cuddLiteral.$(OBJEXT) cuddMatMult.$(OBJEXT) \ + cuddPriority.$(OBJEXT) cuddRead.$(OBJEXT) cuddRef.$(OBJEXT) \ + cuddReorder.$(OBJEXT) cuddSat.$(OBJEXT) cuddSign.$(OBJEXT) \ + cuddSolve.$(OBJEXT) cuddSplit.$(OBJEXT) cuddSubsetHB.$(OBJEXT) \ + cuddSubsetSP.$(OBJEXT) cuddSymmetry.$(OBJEXT) \ + cuddTable.$(OBJEXT) cuddUtil.$(OBJEXT) cuddWindow.$(OBJEXT) \ + cuddZddCount.$(OBJEXT) cuddZddFuncs.$(OBJEXT) \ + cuddZddGroup.$(OBJEXT) cuddZddIsop.$(OBJEXT) \ + cuddZddLin.$(OBJEXT) cuddZddMisc.$(OBJEXT) \ + cuddZddPort.$(OBJEXT) cuddZddReord.$(OBJEXT) \ + cuddZddSetop.$(OBJEXT) cuddZddSymm.$(OBJEXT) \ + cuddZddUtil.$(OBJEXT) cuddBddPort.$(OBJEXT) cuddPwPt.$(OBJEXT) \ + epd.$(OBJEXT) datalimit.$(OBJEXT) +@SIS_COND_CUDD_TRUE@nodist_libbdd_cudd_a_OBJECTS = $(am__objects_1) +libbdd_cudd_a_OBJECTS = $(nodist_libbdd_cudd_a_OBJECTS) +libcudd_mtr_a_AR = $(AR) $(ARFLAGS) +libcudd_mtr_a_LIBADD = +am__objects_2 = mtrBasic.$(OBJEXT) mtrGroup.$(OBJEXT) +@SIS_COND_CUDD_TRUE@nodist_libcudd_mtr_a_OBJECTS = $(am__objects_2) +libcudd_mtr_a_OBJECTS = $(nodist_libcudd_mtr_a_OBJECTS) +libcudd_st_a_AR = $(AR) $(ARFLAGS) +libcudd_st_a_LIBADD = +am__objects_3 = st.$(OBJEXT) +@SIS_COND_CUDD_TRUE@nodist_libcudd_st_a_OBJECTS = $(am__objects_3) +libcudd_st_a_OBJECTS = $(nodist_libcudd_st_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(nodist_libbdd_cudd_a_SOURCES) \ + $(nodist_libcudd_mtr_a_SOURCES) $(nodist_libcudd_st_a_SOURCES) +DIST_SOURCES = +am__installdirs = "$(DESTDIR)$(pkgincludedir)" +nodist_pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(nodist_pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I../include +libbdd_cudd_a_SOURCES_local = \ + cuddAPI.c \ + cuddAddAbs.c \ + cuddAddApply.c \ + cuddAddFind.c \ + cuddAddInv.c \ + cuddAddIte.c \ + cuddAddNeg.c \ + cuddAddWalsh.c \ + cuddAndAbs.c \ + cuddAnneal.c \ + cuddApa.c \ + cuddApprox.c \ + cuddBddAbs.c \ + cuddBddCorr.c \ + cuddBddIte.c \ + cuddBridge.c \ + cuddCache.c \ + cuddCheck.c \ + cuddClip.c \ + cuddCof.c \ + cuddCompose.c \ + cuddDecomp.c \ + cuddEssent.c \ + cuddExact.c \ + cuddExport.c \ + cuddGenCof.c \ + cuddGenetic.c \ + cuddGroup.c \ + cuddHarwell.c \ + cuddInit.c \ + cuddInteract.c \ + cuddLCache.c \ + cuddLevelQ.c \ + cuddLinear.c \ + cuddLiteral.c \ + cuddMatMult.c \ + cuddPriority.c \ + cuddRead.c \ + cuddRef.c \ + cuddReorder.c \ + cuddSat.c \ + cuddSign.c \ + cuddSolve.c \ + cuddSplit.c \ + cuddSubsetHB.c \ + cuddSubsetSP.c \ + cuddSymmetry.c \ + cuddTable.c \ + cuddUtil.c \ + cuddWindow.c \ + cuddZddCount.c \ + cuddZddFuncs.c \ + cuddZddGroup.c \ + cuddZddIsop.c \ + cuddZddLin.c \ + cuddZddMisc.c \ + cuddZddPort.c \ + cuddZddReord.c \ + cuddZddSetop.c \ + cuddZddSymm.c \ + cuddZddUtil.c \ + cudd.h \ + cuddInt.h \ + cuddBddPort.c \ + cuddPwPt.c \ + cuddBdd.h \ + epd.c \ + epd.h \ + datalimit.c + +libcudd_mtr_a_SOURCES_local = \ + mtrBasic.c \ + mtrGroup.c \ + mtr.h \ + mtrInt.h + +libcudd_st_a_SOURCES_local = \ + st.c \ + st.h + +@SIS_COND_CUDD_TRUE@BUILT_SOURCES = $(libbdd_cudd_a_SOURCES_local) bdd.h \ +@SIS_COND_CUDD_TRUE@ $(libcudd_mtr_a_SOURCES_local) \ +@SIS_COND_CUDD_TRUE@ $(libcudd_st_a_SOURCES_local) + +@SIS_COND_CUDD_TRUE@CLEANFILES = $(BUILT_SOURCES) +@SIS_COND_CUDD_TRUE@noinst_LIBRARIES = libbdd_cudd.a libcudd_mtr.a libcudd_st.a +@SIS_COND_CUDD_TRUE@nodist_libbdd_cudd_a_SOURCES = $(libbdd_cudd_a_SOURCES_local) +@SIS_COND_CUDD_TRUE@nodist_libcudd_mtr_a_SOURCES = $(libcudd_mtr_a_SOURCES_local) +@SIS_COND_CUDD_TRUE@nodist_libcudd_st_a_SOURCES = $(libcudd_st_a_SOURCES_local) +@SIS_COND_CUDD_TRUE@nodist_pkginclude_HEADERS = bdd.h mtr.h st.h +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/bdd_cudd/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/bdd_cudd/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libbdd_cudd.a: $(libbdd_cudd_a_OBJECTS) $(libbdd_cudd_a_DEPENDENCIES) + -rm -f libbdd_cudd.a + $(libbdd_cudd_a_AR) libbdd_cudd.a $(libbdd_cudd_a_OBJECTS) $(libbdd_cudd_a_LIBADD) + $(RANLIB) libbdd_cudd.a +libcudd_mtr.a: $(libcudd_mtr_a_OBJECTS) $(libcudd_mtr_a_DEPENDENCIES) + -rm -f libcudd_mtr.a + $(libcudd_mtr_a_AR) libcudd_mtr.a $(libcudd_mtr_a_OBJECTS) $(libcudd_mtr_a_LIBADD) + $(RANLIB) libcudd_mtr.a +libcudd_st.a: $(libcudd_st_a_OBJECTS) $(libcudd_st_a_DEPENDENCIES) + -rm -f libcudd_st.a + $(libcudd_st_a_AR) libcudd_st.a $(libcudd_st_a_OBJECTS) $(libcudd_st_a_LIBADD) + $(RANLIB) libcudd_st.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-nodist_pkgincludeHEADERS: $(nodist_pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(nodist_pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(nodist_pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(nodist_pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-nodist_pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nodist_pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +@SIS_COND_CUDD_FALSE@install: $(BUILT_SOURCES) +@SIS_COND_CUDD_FALSE@ $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-nodist_pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-nodist_pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-nodist_pkgincludeHEADERS \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-nodist_pkgincludeHEADERS + + +@SIS_COND_CUDD_TRUE@install: $(BUILT_SOURCES) + +@SIS_COND_CUDD_TRUE@%.c: @SIS_CUDDDIR@/cudd/%.c +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@%.h: @SIS_CUDDDIR@/cudd/%.h +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@%.c: @SIS_CUDDDIR@/epd/%.c +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@%.h: @SIS_CUDDDIR@/epd/%.h +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@%.c: @SIS_CUDDDIR@/mtr/%.c +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@%.h: @SIS_CUDDDIR@/mtr/%.h +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@%.c: @SIS_CUDDDIR@/sis/%.c +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@%.h: @SIS_CUDDDIR@/sis/%.h +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@%.c: @SIS_CUDDDIR@/util/%.c +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@%.h: @SIS_CUDDDIR@/util/%.h +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@bdd.h: cuddBdd.h +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/bdd_ucb/Makefile.am b/sis/bdd_ucb/Makefile.am new file mode 100644 index 0000000..9c02725 --- /dev/null +++ b/sis/bdd_ucb/Makefile.am @@ -0,0 +1,20 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +libbdd_ucb_a_SOURCES_local = adhoc_cache.c and_smooth.c assert_frame.c \ + assert_heap.c bdd_cofactor.c bdd_compose.c bdd_cproject.c bdd_end.c \ + bdd_ite.c bdd_iter.c bdd_min_sibl.c bdd_min_util.c bdd_print.c \ + bdd_quantify.c bdd_start.c bdd_substit.c bdd_support.c bdd_tovar.c \ + bdd_util.c boolean_ops.c config.c const_cache.c dmp_ext_ptrs.c \ + dmp_mgr_stat.c dmp_node_age.c external_ptr.c find_or_add.c \ + garb_collect.c hash_cache.c ite.c ite_common.c ite_constant.c \ + new_node.c print_stats.c resize_table.c bdd_int.h + +if SIS_COND_UCBBDD +noinst_LIBRARIES = libbdd_ucb.a +libbdd_ucb_a_SOURCES = $(libbdd_ucb_a_SOURCES_local) +pkginclude_HEADERS = bdd.h +dist_doc_DATA = bdd.doc +endif + +EXTRA_DIST = $(libbdd_ucb_a_SOURCES_local) bdd.doc bdd.h diff --git a/sis/bdd_ucb/Makefile.in b/sis/bdd_ucb/Makefile.in new file mode 100644 index 0000000..a70d0a4 --- /dev/null +++ b/sis/bdd_ucb/Makefile.in @@ -0,0 +1,454 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libbdd_ucb_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/bdd_ucb +DIST_COMMON = $(am__dist_doc_DATA_DIST) $(am__pkginclude_HEADERS_DIST) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libbdd_ucb_a_AR = $(AR) $(ARFLAGS) +libbdd_ucb_a_LIBADD = +am__libbdd_ucb_a_SOURCES_DIST = adhoc_cache.c and_smooth.c \ + assert_frame.c assert_heap.c bdd_cofactor.c bdd_compose.c \ + bdd_cproject.c bdd_end.c bdd_ite.c bdd_iter.c bdd_min_sibl.c \ + bdd_min_util.c bdd_print.c bdd_quantify.c bdd_start.c \ + bdd_substit.c bdd_support.c bdd_tovar.c bdd_util.c \ + boolean_ops.c config.c const_cache.c dmp_ext_ptrs.c \ + dmp_mgr_stat.c dmp_node_age.c external_ptr.c find_or_add.c \ + garb_collect.c hash_cache.c ite.c ite_common.c ite_constant.c \ + new_node.c print_stats.c resize_table.c bdd_int.h +am__objects_1 = adhoc_cache.$(OBJEXT) and_smooth.$(OBJEXT) \ + assert_frame.$(OBJEXT) assert_heap.$(OBJEXT) \ + bdd_cofactor.$(OBJEXT) bdd_compose.$(OBJEXT) \ + bdd_cproject.$(OBJEXT) bdd_end.$(OBJEXT) bdd_ite.$(OBJEXT) \ + bdd_iter.$(OBJEXT) bdd_min_sibl.$(OBJEXT) \ + bdd_min_util.$(OBJEXT) bdd_print.$(OBJEXT) \ + bdd_quantify.$(OBJEXT) bdd_start.$(OBJEXT) \ + bdd_substit.$(OBJEXT) bdd_support.$(OBJEXT) \ + bdd_tovar.$(OBJEXT) bdd_util.$(OBJEXT) boolean_ops.$(OBJEXT) \ + config.$(OBJEXT) const_cache.$(OBJEXT) dmp_ext_ptrs.$(OBJEXT) \ + dmp_mgr_stat.$(OBJEXT) dmp_node_age.$(OBJEXT) \ + external_ptr.$(OBJEXT) find_or_add.$(OBJEXT) \ + garb_collect.$(OBJEXT) hash_cache.$(OBJEXT) ite.$(OBJEXT) \ + ite_common.$(OBJEXT) ite_constant.$(OBJEXT) new_node.$(OBJEXT) \ + print_stats.$(OBJEXT) resize_table.$(OBJEXT) +@SIS_COND_UCBBDD_TRUE@am_libbdd_ucb_a_OBJECTS = $(am__objects_1) +libbdd_ucb_a_OBJECTS = $(am_libbdd_ucb_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libbdd_ucb_a_SOURCES) +DIST_SOURCES = $(am__libbdd_ucb_a_SOURCES_DIST) +am__dist_doc_DATA_DIST = bdd.doc +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +am__pkginclude_HEADERS_DIST = bdd.h +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +libbdd_ucb_a_SOURCES_local = adhoc_cache.c and_smooth.c assert_frame.c \ + assert_heap.c bdd_cofactor.c bdd_compose.c bdd_cproject.c bdd_end.c \ + bdd_ite.c bdd_iter.c bdd_min_sibl.c bdd_min_util.c bdd_print.c \ + bdd_quantify.c bdd_start.c bdd_substit.c bdd_support.c bdd_tovar.c \ + bdd_util.c boolean_ops.c config.c const_cache.c dmp_ext_ptrs.c \ + dmp_mgr_stat.c dmp_node_age.c external_ptr.c find_or_add.c \ + garb_collect.c hash_cache.c ite.c ite_common.c ite_constant.c \ + new_node.c print_stats.c resize_table.c bdd_int.h + +@SIS_COND_UCBBDD_TRUE@noinst_LIBRARIES = libbdd_ucb.a +@SIS_COND_UCBBDD_TRUE@libbdd_ucb_a_SOURCES = $(libbdd_ucb_a_SOURCES_local) +@SIS_COND_UCBBDD_TRUE@pkginclude_HEADERS = bdd.h +@SIS_COND_UCBBDD_TRUE@dist_doc_DATA = bdd.doc +EXTRA_DIST = $(libbdd_ucb_a_SOURCES_local) bdd.doc bdd.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/bdd_ucb/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/bdd_ucb/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libbdd_ucb.a: $(libbdd_ucb_a_OBJECTS) $(libbdd_ucb_a_DEPENDENCIES) + -rm -f libbdd_ucb.a + $(libbdd_ucb_a_AR) libbdd_ucb.a $(libbdd_ucb_a_OBJECTS) $(libbdd_ucb_a_LIBADD) + $(RANLIB) libbdd_ucb.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/bdd_ucb/adhoc_cache.c b/sis/bdd_ucb/adhoc_cache.c new file mode 100644 index 0000000..ae266d0 --- /dev/null +++ b/sis/bdd_ucb/adhoc_cache.c @@ -0,0 +1,213 @@ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/adhoc_cache.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: adhoc_cache.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.5 1993/05/04 15:30:57 sis + * BDD package updates. Tom Shiple 5/4/93. + * + * Revision 1.3 1993/05/03 20:30:18 shiple + * In insert routine, changed policy on what to do if a new key cannot be + * allocated because it would cause the memory limit to be exceeded. + * Before, just returned, without inserting. Now, insert, even if memory + * limit will be exceeded. Also, now when max_size is reached, we kill + * the current cache and start a new one. + * + * Revision 1.2 1992/09/19 02:01:27 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added code to limit size of adhoc cache. + * In bdd_adhoccache_lookup, just return if caching is off. Added usage of + * bdd_will_exceed_mem_limit in bdd_adhoccache_insert. + * + * Revision 1.1 1992/07/29 00:26:36 shiple + * Initial revision + * + * Revision 1.3 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/24 22:51:34 sis + * Core leak fixed. + * + * Revision 1.1 91/03/27 14:31:23 shiple + * Initial revision + * + * Revision 1.1 91/03/27 14:29:37 shiple + * Initial revision + * + * + */ + +static int cmp(); +static int hash(); + +/* + * bdd_adhoccache_init - initialize the adhoc cache for the manager + * + * return nothing, just do it. + */ +void +bdd_adhoccache_init(manager) +bdd_manager *manager; +{ + manager->heap.cache.adhoc.table = st_init_table(cmp, hash); +} + +/* + * bdd_adhoccache_insert - insert an entry into the adhoc cache + * + * return nothing, just do it. + */ +void +bdd_adhoccache_insert(manager, f, g, v, value) +bdd_manager *manager; +bdd_node *f; /* may be NIL(bdd_node) */ +bdd_node *g; /* may be NIL(bdd_node) */ +bdd_int v; /* may be any integer */ +bdd_node *value; +{ + bdd_adhoccache_key *key; + int status; + + if ( ! manager->heap.cache.adhoc.on ) { + return; /* has no effect if caching is off */ + } + + /* + * If we have already reached the max number of entries, then kill the current + * adhoc_cache and start a new one. We must do this, because the st package + * doesn't provide a convenient way to just overwrite an old entry. + */ + if (st_count(manager->heap.cache.adhoc.table) > manager->heap.cache.adhoc.max_size) { + (void) bdd_adhoccache_uninit(manager); + (void) bdd_adhoccache_init(manager); + } + + /* + * Allocate a new key (even if it would cause the memory limit to be exceeded). + */ + key = ALLOC(bdd_adhoccache_key, 1); + if (key == NIL(bdd_adhoccache_key)) { + (void) bdd_memfail(manager, "bdd_adhoccache_insert"); + } + + /* + * Set the values of the key. + */ + key->f = f; + key->g = g; + key->v = v; + + /* + * Insert the new key. Since we previous lookup on this entry was not successful, there should + * not be another entry already under the key. st_insert returns 1 if there was an entry already under + * the key, and 0 otherwise. Since the table has collision chains, there should not be any collisions. + */ + status = st_insert(manager->heap.cache.adhoc.table, (refany) key, (refany) value); + BDD_ASSERT(!status); + manager->heap.stats.cache.adhoc.inserts++; +} + +/* + * bdd_adhoccache_lookup - lookup an entry in the adhoc cache + * + * return {TRUE, FALSE} on {found, not found}. + */ +boolean +bdd_adhoccache_lookup(manager, f, g, v, value) +bdd_manager *manager; +bdd_node *f; /* may be NIL(bdd_node) */ +bdd_node *g; /* may be NIL(bdd_node) */ +bdd_int v; /* may be any integer */ +bdd_node **value; /* return */ +{ + bdd_adhoccache_key key; + + + if ( ! manager->heap.cache.adhoc.on ) { + /* + * Always fails if caching is off. + */ + return (FALSE); + } + + key.f = f; + key.g = g; + key.v = v; + + if (st_lookup(manager->heap.cache.adhoc.table, (refany) &key, (refany*) value)) { + manager->heap.stats.cache.adhoc.hits++; + return (TRUE); + } + + manager->heap.stats.cache.adhoc.misses++; + return (FALSE); +} + +/* + * bdd_adhoccache_uninit - destroy a adhoc cache + * + * delete all the keys + * + * return nothing, just do it. + */ +void +bdd_adhoccache_uninit(manager) +bdd_manager *manager; +{ + st_generator *gen; + bdd_adhoccache_key *key; + bdd_node *value; + + st_foreach_item(manager->heap.cache.adhoc.table, gen, (refany*) &key, (refany*) &value) { + FREE(key); + } + st_free_table(manager->heap.cache.adhoc.table); + manager->heap.cache.adhoc.table = NIL(st_table); +} + +/* + * cmp - a st_table comparison function + * + * return {0, 1} on {same, different}. + */ +static int +cmp(n1, n2) +bdd_adhoccache_key *n1; +bdd_adhoccache_key *n2; +{ + boolean samep; + + samep = n1->f == n2->f && n1->g == n2->g && n1->v == n2->v; + return (samep ? /* equal */ 0: /* different */ 1); +} + +/* + * hash - a st_table hash function + * + * return an integer in the range 0 .. modulus-1 + */ +static int +hash(key, modulus) +bdd_adhoccache_key *key; +int modulus; +{ + unsigned int hval; + + hval = bdd_generic_hash(key->f, key->g, key->v, modulus); + return (hval); +} diff --git a/sis/bdd_ucb/and_smooth.c b/sis/bdd_ucb/and_smooth.c new file mode 100644 index 0000000..20ef8a4 --- /dev/null +++ b/sis/bdd_ucb/and_smooth.c @@ -0,0 +1,300 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/and_smooth.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/and_smooth.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: and_smooth.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 02:03:04 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. In and_smooth, in first nonterminal case, changed g to h. + * Added typecast to void to some function calls. Added adhoc_ops stats. + * + * Revision 1.1 1992/07/29 00:26:37 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:22 sis + * Initial revision + * + * Revision 1.1 91/04/11 20:58:46 shiple + * Initial revision + * + * + */ + +static bdd_variableId get_next_variable(); +static bdd_node *and_smooth(); + +/* + * bdd_and_smooth - smooth and and at the same time + * + * smoothing_vars: array of bdd_t *'s, input variables to be smoothed out + * + * return the smoothed and anded result + */ +bdd_t * +bdd_and_smooth(f, g, smoothing_vars) +bdd_t *f; +bdd_t *g; +array_t *smoothing_vars; /* of bdd_t* */ +{ + bdd_safeframe frame; + bdd_safenode real_f, real_g, ret; + bdd_manager *manager; + array_t *vars; + bdd_t *h; + + if (f == NIL(bdd_t) || g == NIL(bdd_t)) + fail("bdd_and_smooth: invalid BDD"); + + BDD_ASSERT( ! f->free ); + BDD_ASSERT( ! g->free ); + + if (f->bdd != g->bdd) + fail("bdd_and_smooth: different bdd managers"); + + manager = f->bdd; /* either this or g->bdd will do */ + + /* + * After the input is checked for correctness, start the safe frame + * f and g are already external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, real_f); + bdd_safenode_declare(manager, real_g); + bdd_safenode_declare(manager, ret); + + real_f.node = f->node; + real_g.node = g->node; + + vars = bdd_get_sorted_varids(smoothing_vars); + (void) bdd_adhoccache_init(manager); + + ret.node = and_smooth(manager, real_f.node, real_g.node, /* index */ 0, vars); + + /* + * Free the cache, end the safe frame and return the (safe) result + */ + (void) bdd_adhoccache_uninit(manager); + (void) array_free(vars); + bdd_safeframe_end(manager); + h = bdd_make_external_pointer(manager, ret.node, "bdd_and_smooth"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_and_smooth(%d, %d, { ", + bdd_index_of_external_pointer(h), + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(g)); + { + int i; + + for (i=0; idebug.flight_recorder.log, "%d%s", + bdd_index_of_external_pointer(v), + i+1 == array_n(smoothing_vars) ? " } )\n": ", "); + } + } +#endif /* } */ + + return (h); +} + +/* + * and_smooth - and and smooth at the same time + * + * Can't share with the other smooth because of caching!!! + * Should we put the index in the cache? + * + * return the anding and the smoothing ... + */ +static bdd_node * +and_smooth(manager, f, g, index, vars) +bdd_manager *manager; +bdd_node *f; +bdd_node *g; +int index; +array_t *vars; +{ + bdd_safeframe frame; + bdd_safenode safe_f, safe_g; + bdd_safenode f_T, f_E, g_T, g_E; + bdd_safenode T, E; + bdd_safenode h; + bdd_safenode ret, var; + bdd_variableId fId, gId, varId; + int next_index; + + bdd_safeframe_start(manager, frame); + bdd_safenode_link(manager, safe_f, f); + bdd_safenode_link(manager, safe_g, g); + bdd_safenode_declare(manager, ret); + bdd_safenode_declare(manager, var); + bdd_safenode_declare(manager, f_T); + bdd_safenode_declare(manager, f_E); + bdd_safenode_declare(manager, g_T); + bdd_safenode_declare(manager, g_E); + bdd_safenode_declare(manager, T); + bdd_safenode_declare(manager, E); + bdd_safenode_declare(manager, h); + + manager->heap.stats.adhoc_ops.calls++; + + if (f == BDD_ZERO(manager) || g == BDD_ZERO(manager)) { + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager); + return BDD_ZERO(manager); + } + if (f == BDD_ONE(manager) && g == BDD_ONE(manager)) { + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager); + return BDD_ONE(manager); + } + if (bdd_adhoccache_lookup(manager, f, g, /* unused */ 0, &ret.node)) { + manager->heap.stats.adhoc_ops.returns.cached++; + bdd_safeframe_end(manager); + return (ret.node); + } + + fId = BDD_REGULAR(f)->id; + gId = BDD_REGULAR(g)->id; + + /* + * if f or g constant, only one is a constant, and that constant is ONE + * in that case, the var ID should put the constant infinitely far and + * everything should work fine. + */ + (void) bdd_get_branches(f, &f_T.node, &f_E.node); + (void) bdd_get_branches(g, &g_T.node, &g_E.node); + + /* + * skip over uninteresting variables + */ + varId = get_next_variable(MIN(fId,gId), index, vars, &next_index); + if (fId > gId) { + if (varId == gId) { + /* + * should smooth + * not clear to me whether faster to smooth g first, + * and then recur or the other way around + */ + h.node = bdd__ITE_(manager, g_T.node, BDD_ONE(manager), g_E.node); + ret.node = and_smooth(manager, f, h.node, next_index, vars); + } else { + /* + * should not smooth + */ + T.node = and_smooth(manager, f, g_T.node, next_index, vars); + E.node = and_smooth(manager, f, g_E.node, next_index, vars); + var.node = bdd_find_or_add(manager, gId, BDD_ONE(manager), BDD_ZERO(manager)); + ret.node = bdd__ITE_(manager, var.node, T.node, E.node); + } + } else if (fId == gId) { + T.node = and_smooth(manager, f_T.node, g_T.node, next_index, vars); + E.node = and_smooth(manager, f_E.node, g_E.node, next_index, vars); + if (varId == fId) { + /* + * should smooth + */ + ret.node = bdd__ITE_(manager, T.node, BDD_ONE(manager), E.node); + } else { + /* + * should not smooth + */ + var.node = bdd_find_or_add(manager, fId, BDD_ONE(manager), BDD_ZERO(manager)); + ret.node = bdd__ITE_(manager, var.node, T.node, E.node); + } + } else { /* fId < gId */ + if (varId == fId) { + /* + * should smooth + * should we or f first, or recur first? + */ + T.node = and_smooth(manager, f_T.node, g, next_index, vars); + E.node = and_smooth(manager, f_E.node, g, next_index, vars); + ret.node = bdd__ITE_(manager, T.node, BDD_ONE(manager), E.node); + } else { + /* + * should not smooth + */ + T.node = and_smooth(manager, f_T.node, g, next_index, vars); + E.node = and_smooth(manager, f_E.node, g, next_index, vars); + var.node = bdd_find_or_add(manager, fId, BDD_ONE(manager), BDD_ZERO(manager)); + ret.node = bdd__ITE_(manager, var.node, T.node, E.node); + } + } + (void) bdd_adhoccache_insert(manager, f, g, /* unused */ 0, ret.node); + manager->heap.stats.adhoc_ops.returns.full++; + + bdd_safeframe_end(manager); + return ret.node; +} + +/* + * get_next_variable - get the next variable + * + * The ID of BDD_ONE if the bound is exceeded + * otherwise the first variable in the array that is + * no smaller than top_var as side effect, increment + * index to next position. + * + * return the variableId + */ +static bdd_variableId +get_next_variable(top_var, index, smoothing_vars, next_index) +bdd_variableId top_var; +int index; +array_t *smoothing_vars; +int *next_index; +{ + int i; + bdd_variableId value; + + for (i = index; i < array_n(smoothing_vars); i++) { + value = array_fetch(bdd_variableId, smoothing_vars, i); + if (value >= top_var) break; + } + if (i >= array_n(smoothing_vars)) { + *next_index = array_n(smoothing_vars); + return BDD_ONE_ID; + } else if (value == top_var) { + *next_index = i + 1; + return value; + } else { + *next_index = i; + return value; + } +} diff --git a/sis/bdd_ucb/assert_frame.c b/sis/bdd_ucb/assert_frame.c new file mode 100644 index 0000000..731c36a --- /dev/null +++ b/sis/bdd_ucb/assert_frame.c @@ -0,0 +1,104 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/assert_frame.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/assert_frame.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: assert_frame.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 01:44:15 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. + * + * Revision 1.1 1992/07/29 00:26:38 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:23 sis + * Initial revision + * + * Revision 1.1 91/04/11 20:58:22 shiple + * Initial revision + * + * + */ + +static void assert_okay(); + +/* + * bdd_assert_frames_correct - assert that all of the safe frames are okay + * + * Traverse all of the internal references and touch them + * + * return if correct or don't + */ +void +bdd_assert_frames_correct(manager) +bdd_manager *manager; +{ + bdd_safeframe *sf; + bdd_safenode *sn; + + for (sf=manager->heap.internal_refs.frames; sf != NIL(bdd_safeframe); sf=sf->prev) { + for (sn=sf->nodes; sn != NIL(bdd_safenode); sn=sn->next) { + if (sn->arg != NIL(bdd_node *)) + assert_okay(manager, *sn->arg); + assert_okay(manager, sn->node); + } + } +} + +/* + * assert_okay - assert that the pointer is okay + * + * return nothing, just do it. + */ +static void +assert_okay(manager, node) +bdd_manager *manager; +bdd_node *node; +{ + bdd_node *reg_node; + + if (node == NIL(bdd_node)) + return; /* okay */ + + reg_node = BDD_REGULAR(node); + +#if defined(BDD_DEBUG_GC) /* { */ + BDD_ASSERT(reg_node->halfspace == manager->heap.gc.halfspace); +#endif /* } */ + + BDD_ASSERT_NOT_BROKEN_HEART(reg_node); + + /* okay */ +} diff --git a/sis/bdd_ucb/assert_heap.c b/sis/bdd_ucb/assert_heap.c new file mode 100644 index 0000000..5cb9ad9 --- /dev/null +++ b/sis/bdd_ucb/assert_heap.c @@ -0,0 +1,158 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/assert_heap.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/assert_heap.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: assert_heap.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 02:06:29 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Changed ITE and ITE_const caches to be array of pointers. + * + * Revision 1.1 1992/07/29 00:26:39 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:23 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:25 shiple + * Initial revision + * + * + */ + +static void assert_okay(); + +/* + * bdd_assert_heap_correct - look over the heap and say its okay. + * + * return if okay, fail if bad + */ +void +bdd_assert_heap_correct(manager) +bdd_manager *manager; +{ + bdd_nodeBlock *block; + bdd_node *node; + bdd_hashcache_entry *hentry; + bdd_constcache_entry *centry; + bdd_adhoccache_key *key; + bdd_safeframe *sf; + bdd_safenode *sn; + bdd_bddBlock *bblock; + bdd_t *bnode; + int node_i, i; + st_generator *gen; + + (void) assert_okay(manager, manager->bdd.one); + + for (block=manager->heap.half[manager->heap.gc.halfspace].inuse.top; + block != NIL(bdd_nodeBlock); block=block->next) { + for (node_i=0; node_iused; node_i++) { + node = &block->subheap[node_i]; + (void) assert_okay(manager, node->T); + (void) assert_okay(manager, node->E); + } + } + + for (sf=manager->heap.internal_refs.frames; sf != NIL(bdd_safeframe); sf=sf->prev) { + for (sn=sf->nodes; sn != NIL(bdd_safenode); sn=sn->next) { + if (sn->arg != NIL(bdd_node *)) + (void) assert_okay(manager, *sn->arg); + (void) assert_okay(manager, sn->node); + } + } + + for (bblock=manager->heap.external_refs.map; + bblock != NIL(bdd_bddBlock); bblock=bblock->next) { + for (i=0; isubheap); i++) { + bnode = &bblock->subheap[i]; + if ( ! bnode->free ) + (void) assert_okay(manager, bnode->node); + } + } + + for (i = 0; i < manager->heap.cache.itetable.nbuckets; i++) { + hentry = manager->heap.cache.itetable.buckets[i]; + if (hentry != NIL(bdd_hashcache_entry)) { + (void) assert_okay(manager, hentry->ITE.f); + (void) assert_okay(manager, hentry->ITE.g); + (void) assert_okay(manager, hentry->ITE.h); + (void) assert_okay(manager, hentry->data); + } + } + + for (i = 0; i < manager->heap.cache.consttable.nbuckets; i++) { + centry = manager->heap.cache.consttable.buckets[i]; + if (centry != NIL(bdd_constcache_entry)) { + (void) assert_okay(manager, centry->ITE.f); + (void) assert_okay(manager, centry->ITE.g); + (void) assert_okay(manager, centry->ITE.h); + /* ignore centry->data */ + } + } + + if (manager->heap.cache.adhoc.table != NIL(st_table)) { + gen = st_init_gen(manager->heap.cache.adhoc.table); + while (st_gen(gen, (refany*) &key, (refany*) &node)) { + (void) assert_okay(manager, key->f); + (void) assert_okay(manager, key->g); + /* ignore key->v */ + (void) assert_okay(manager, node); + } + (void) st_free_gen(gen); + } +} + +static void +assert_okay(manager, node) +bdd_manager *manager; +bdd_node *node; /* may be complemented */ +{ + bdd_node *reg_node; + + if (node == NIL(bdd_node)) + return; /* okay */ + + reg_node = BDD_REGULAR(node); + +#if defined(BDD_DEBUG_GC) /* { */ + BDD_ASSERT(reg_node->halfspace == manager->heap.gc.halfspace); +#endif /* } */ + + BDD_ASSERT_NOT_BROKEN_HEART(reg_node); + + return; /* okay */ +} diff --git a/sis/bdd_ucb/bdd.doc b/sis/bdd_ucb/bdd.doc new file mode 100644 index 0000000..209db86 --- /dev/null +++ b/sis/bdd_ucb/bdd.doc @@ -0,0 +1,964 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ + +Binary Decision Diagram (BDD) Package, Version 2.4 + +Tom Shiple (original contributors: Herve' Touati, Wendell Baker) +University of California, Berkeley, 1991, 1992 + + +Introduction ------------------------------------------------------------------ + +The interface for this package is modeled on that described in Brace, Rudell, +Bryant, "Efficient Implementation of a BDD Package", DAC 1990. The user +manipulates only BDD formulas, corresponding to the data type bdd_t. A bdd_t is +a pointer to a bdd_node, and more than one bdd_t can point to the same bdd_node. + +A BDD manager is a collection of bdd_nodes, which together constitute a number +of BDDs. A variable ordering is associated with each manager. Variables are +numbered starting from zero. This ordering is not stored explicitly in the +manager, but is implicit in the variable ID stored in each node created. It is +the user's responsibility to define an ordering, and to maintain the +correspondence between application variables and BDD variable IDs. The BDD +manager maintains the invariant that variables occur in ascending order in every +root-to-leaf path. + +A "single variable BDD formula" is a BDD for a single variable: it has one node, +with the THEN branch pointing to 1, and the ELSE branch pointing to 0. + +All of the functions which operate on BDD formulas return new BDD formulas. The +BDDs associated with BDD formulas which are arguments to a function are not +disturbed. For example, bdd_substitute creates a new BDD and leaves the old one +intact. To purge the old BDD, free the bdd_t pointing to it, and the next +garbage collection will free those bdd_nodes which can no longer be reached from +a bdd_t. + +A user should never allocate bdd_t data structures; this should only be done by +the BDD manager. A BDD which is only pointed to by a bdd_t allocated by a user +will be treated as garbage during garbage collection since the bdd_t is not +registered with the manager. + +For any operation involving multiple BDDs, all the BDDs must belong to the same +manager. For example, in bdd_and(f, g, 0, 1), the BDDs for 'f' and 'g' must +exist in the same manager. Also, it is bad form to nest BDD operations because +the returned bdd_t's will be "lost", potentially causing a buildup of garbage +which cannot be collected. For example, bdd_and(bdd_or(f,g,1,1), bdd_xor(h,e), +1, 0) should be avoided. + +IMPORTANT: To reiterate the above points: 1) you should only be using bdd_t's +which are returned by BDD package functions, and 2) you should free bdd_t's +(using bdd_free) as soon as you no longer need them, so that their corresponding +BDDs may be garbaged collected at the next opportunity. + +Summary ----------------------------------------------------------------------- + +BDD Manager Allocation And Destruction: + bdd_end() + bdd_set_mgr_init_dflts() + bdd_start() + bdd_start_with_params() + +BDD Variable Allocation: + bdd_create_variable() + bdd_get_variable() + +BDD Formula Management: + bdd_dup() + bdd_free() + +Operations on BDD Formulas: + bdd_and() + bdd_and_smooth() + bdd_between() + bdd_cofactor() + bdd_compose() + bdd_consensus() + bdd_cproject() + bdd_else() + bdd_ite() + bdd_minimize() + bdd_minimize_with_params() + bdd_not() + bdd_one() + bdd_or() + bdd_smooth() + bdd_substitute() + bdd_then() + bdd_top_var() + bdd_xnor() + bdd_xor() + bdd_zero() + +Queries about BDD Formulas: + bdd_equal() + bdd_is_cube() + bdd_is_tautology() + bdd_leq() + +Statistics and Other Queries: + bdd_count_onset() + bdd_get_manager() + bdd_get_node() + bdd_get_stats() + bdd_get_support() + bdd_get_varids() + bdd_num_vars() + bdd_print() + bdd_print_stats() + bdd_size() + bdd_top_var_id() + +Traversal of BDD Formulas: + bdd_gen_free() + foreach_bdd_cube() + foreach_bdd_node() + +Miscellaneous: + bdd_get_external_hooks() + bdd_register_daemon() + bdd_set_gc_mode() + bdd_dynamic_reordering() + + + +BDD Manager Allocation And Destruction ---------------------------------------- + +void +bdd_end(manager) +bdd_manager *manager; + +Frees all the resources associated with a BDD manager. + +void +bdd_set_mgr_init_dflts(mgr_init) +bdd_mgr_init *mgr_init; + + Initializes `mgr_init' with the default values. (See BDD_DFLT_* in bdd.h + for the default values.) See bdd_start_with_params and bdd_register_daemon + for sample usages. + +bdd_manager * +bdd_start(nvariables) +int nvariables; + + Initializes a new BDD manager that can contain at most nvariables. The BDD + manager ensures that no variable in the manager is greater than or equal to + nvariables over the lifetime of the manager. The range of variable IDs is + zero to nvariables-1. The manager's nvariables value can be incremented by + calling bdd_create_variable. This function also creates the constant 1 BDD, + and registers it with the manager. + +bdd_manager * +bdd_start_with_params(nvariables, mgr_init) +int nvariables; +bdd_mgr_init *mgr_init; + + Same as bdd_start, but allows user to set the parameters specified in the + bdd_mgr_init data structure. + + The ITE cache, ITE_const cache, and the adhoc cache store the result of + previous computations, in an attempt to improve performance. See + bdd_print_stats for more information on the caches. For each of the three + caches, the following fields can be set ("*" is one of ITE, ITE_const, + adhoc): + + 1) *_cache_on: turn it on or off. In general, the performance of the BDD + package is horrible if the caches are turned off. + + 2) *_cache_resize_at: set the percentage at which you want resizing to + occur. For example, a value of 85 means to resize when greater than 85% of + the buckets are being used. This setting does not apply to the adhoc + cache. + + 3) *_cache_max_size: for the ITE and ITE_const caches, set the maximum + number of buckets allowed in the cache. When this value is reached, the + caches will not be grown. For the adhoc cache, set the maximum number of + entries allowed in the cache. When this value is reached, new entries + will not be inserted into the cache. + + garbage_collector.on determines whether or not the garbage collector is + used. memory.limit, specified as a positive integer denoting megabytes (1MB + = 1048576 bytes), places a limit on how much memory the BDD package is + allowed to use. memory.deamon specifies the callback routine to be used + when the memory limit is exceeded. If a non-default memory limit is + specified, then a daemon must be given (see bdd_register_daemon for sample + usage). + + nodes.ratio determines how many new bdd_node blocks should be allocated + after garbage collection to achieve the desired ratio between "used" and + "unused" bdd_nodes. A larger value of nodes.ratio gives the BDDs more room + to grow before the next garbage collection, but uses more space. + nodes.init_blocks determines the number of bdd_node blocks allocated at + initialization. A larger value of nodes.init_blocks delays the occurrence of + the first garbage collection. + + bdd_start(n) is equivalent to bdd_start_with_parameters(n, mgr_init), where + `mgr_init' has been initialized by bdd_set_mgr_init_dflts. + + Below is a sample usage of bdd_set_mgr_init_dflts and bdd_start_with_params: + + bdd_mgr_init mgr_init; + bdd_manager *manager; + + bdd_set_mgr_init_dflts(&mgr_init); /* get the defaults */ + mgr_init.adhoc_cache.max_size = 50000; /* change those you want to */ + mgr_init.node.init_blocks = 20; + manager = bdd_start_with_params(SOME_NUMBER, &mgr_init); /* create mgr */ + + + + +BDD Variable Allocation ------------------------------------------------------- + +bdd_t * +bdd_create_variable(manager) +bdd_manager *manager; + + Returns a single variable BDD formula for a new variable after registering + the variable with the manager. This function calls bdd_get_variable with + the arguments `manager' and the manager's nvariables value, and then + increments the manager's nvariables value. Thus, the variable created by + bdd_create_variable is effectively placed at the end of the current variable + ordering. + +bdd_t * +bdd_get_variable(manager, variable_ID) +bdd_manager *manager; +bdd_variableId variable_ID; /* unsigned int */ + + If the single variable BDD formula corresponding to variable_ID already + exists, then return it. Otherwise, create a new single variable BDD formula + with ID `variable_ID', register it with the manager, and return it. This + function checks that variable_ID is less than the manager's current value of + nvariables. + + Sample usages of these functions: + + bdd_manager_t *manager; + bdd_t *bdd; + + manager = bdd_start(SOME_NUMBER); + for (i = 0; i < SOME_NUMBER; i++) { + bdd = bdd_get_variable(manager, i); + /* do something with bdd */ + } + . + . + bdd = bdd_create_variable(manager); /* create another var, add to end */ + . + . + bdd_end(manager); + + + The following is equivalent: + + manager = bdd_start(0); + for (i = 0; i < SOME_NUMBER; i++) { + bdd = bdd_create_variable(manager); + /* do something with bdd */ + } + . + . + bdd = bdd_create_variable(manager); /* create another var, add to end */ + . + . + bdd_end(manager); + + +BDD Formula Management -------------------------------------------------------- + +bdd_t * +bdd_dup(bdd) +bdd_t *bdd; + + Returns a copy of the BDD formula. No new bdd_nodes are created, since the + existing bdd_nodes will be shared. + +void +bdd_free(bdd) +bdd_t *bdd; + + Frees the bdd_t `bdd'. During garbage collection, a bdd_node is freed if it + cannot be reached starting from a bdd_t. Intermediate results and unused + bdd_t's should be freed as soon as you no longer need them. For example: + + /* to compute f + gh */ + temp = bdd_and(g, h, 1, 1); + result = bdd_or(f, temp, 1, 1); + bdd_free(temp); + + + +Operations on BDD Formulas ---------------------------------------------------- + +IMPORTANT: All of the operations in this section return a pointer to a bdd_t. +Such a bdd_t is registered with the BDD manager. The garbage collector locates +all bdd_nodes which can be reached by recursive descent from the bdd_t's +registered with the manager, and these nodes are saved. All nodes not reachable +are considered garbage and are destroyed. The function bdd_free "unregisters" a +bdd_t. Thus, it is crucial that you use bdd_free to unregister bdd_t's after +you no longer need them so that the garbage collector can reclaim as much space +as possible. + +bdd_t * +bdd_and(f, g, f_phase, g_phase) +bdd_t *f; +bdd_t *g; +boolean f_phase; +boolean g_phase; + + Returns the BDD formula for the and of `f' and `g' in the phases specified + by `f_phase' and `g_phase'. For example, bdd_and(f,g,0,1) will return the + BDD formula for (f' and g). Don't forget the phase arguments. + +bdd_t * +bdd_and_smooth(f, g, smoothing_vars) +bdd_t *f; +bdd_t *g; +array_t *smoothing_vars; /* of bdd_t *'s */ + + Ands and smooths `f' and 'g' with respect to the `smoothing_vars'. + `smoothing_vars' is an array of bdd_t *'s, which are the single variable BDD + formulas to be smoothed out. + +bdd_t * +bdd_between(f_min, f_max) +bdd_t *f_min; +bdd_t *f_max; + + Returns a heuristically minimized BDD containing `f_min', and contained in + `f_max'. Calls bdd_minimize(f_min, f_min+!f_max); + +bdd_t * +bdd_cofactor(f, g) +bdd_t *f; +bdd_t *g; + + Returns the BDD formula of cofactor of `f' with respect to `g'. `g' must be + different from 0. If `g' is a cube, this computes the usual cofactor. If + `g' is not a cube, then this computes the generalized cofactor. + +bdd_t * +bdd_compose(f, v, g) +bdd_t *f; +bdd_t *v; +bdd_t *g; + + Returns the BDD formula with `v' replaced by `g' in `f'. `v' must be a + single variable BDD formula. + +bdd_t * +bdd_consensus(f, quantifying_vars) +bdd_t *f; +array_t *quantifying_vars; /* of bdd_t *'s */ + + Returns the BDD formula of `f' universally quantified with respect to the + variables in the array `quantifying_vars'. `quantifying_vars' is an array + of bdd_t *'s, which are the single variable BDD formulas to be quantified. + +bdd_t * +bdd_cproject(f, var_array) +bdd_t *f; +array_t *var_array; /* of bdd_t *'s */ + + Returns the BDD corresponding to the compatible projection of `f' onto the + variables in `var_array'. `f' is interpreted as the characteristic + function of a one-to-many relation. `var_array' is an array of bdd_t *'s, + which are single variable BDD formulas. The reference vertex is hardcoded + to be all 1's. + + The compatible projection operator is used to symbolically manipulate + equivalence classes. See the following for more details: Bill Lin, + "Implicit Manipulation of Equivalence Classes using Binary Decision + Diagrams", International Conference on Computer Design, Cambridge, + Massachusetts, November, 1991. + +bdd_t * +bdd_else(bdd) +bdd_t *bdd; + + Returns the BDD formula of the function when the top_var of `bdd' evaluates + to 0. The return value takes into account that `bdd' may be a "complemented + pointer". + +bdd_t * +bdd_ite(i, t, e, i_phase, t_phase, e_phase) +bdd_t *i; +bdd_t *t; +bdd_t *e; +boolean i_phase; +boolean t_phase; +boolean e_phase; + + Returns the BDD formula resulting in the ITE of `i', `t' and `e'. For + example, bdd_ite(i, t, e, 1, 0, 1) will return the BDD formula for ((i and + t') or (i' and e)). + +bdd_t * +bdd_not(f) +bdd_t *f; + + Returns the BDD formula for the complement of `f'. + +bdd_t * +bdd_minimize(f, c) +bdd_t *f; +bdd_t *c; + + Returns bdd_minimize_with_params(f, c, BDD_MIN_OSM, TRUE, TRUE, TRUE). + +bdd_t * +bdd_minimize_with_params(f, c, match_type, compl, no_new_vars, return_min) +bdd_t *f; +bdd_t *c; +bdd_min_match_type_t match_type; +boolean compl; +boolean no_new_vars; +boolean return_min; + + Minimizes `f' with respect to the care function `c'; that is, `f' is a don't + care wherever `c' is 0. The result contains f*c, and is contained in f+!c. + `match_type' is one of BDD_MIN_OSM, BDD_MIN_OSDM, or BDD_MIN_TSM. When + `compl' is TRUE, matches between sub-functions and the complements of others + are attempted. When `no_new_vars' is TRUE, the variables in the result will + be a subset of those in `f'. When `return_min' is TRUE, if the result is + larger than `f', then a copy of `f' is returned. The restrict operator of + Coudert and Madre, ICCAD '90, p. 126, is (BDD_MIN_OSDM, FALSE, TRUE, FALSE), + and the constrain operator (which is the same as bdd_cofactor) is + (BDD_MIN_OSDM, FALSE, FALSE, FALSE). See Shiple et al., "Heuristic + Minimization of BDDs Using Don't Cares," UCB ERL Memo, UCB/ERL M93/58, for + more details. + +bdd_t * +bdd_one(manager) +bdd_manager *manager; + + Returns a BDD formula pointing to the constant function 1 of the manager. + +bdd_t * +bdd_or(f, g, f_phase, g_phase) +bdd_t *f; +bdd_t *g; +boolean f_phase; +boolean g_phase; + + Returns the BDD formula for the or of `f' and `g' in the phases specified by + `f_phase' and `g_phase'. For example, bdd_or(f, g, 0, 1) will return the BDD + formula for (f' or g). + +bdd_t * +bdd_smooth(f, smoothing_vars) +bdd_t *f; +array_t *smoothing_vars; /* of bdd_t *'s */ + + Returns the BDD formula of `f' existentially quantified with respect to + the variables in the array `smoothing_vars'. `smoothing_vars' is an array of + bdd_t *'s, which are the single variable BDD formulas to be quantified. + +bdd_t * +bdd_substitute(f, old_array, new_array) +bdd_t *f; +array_t *old_array; /* of bdd_t *'s */ +array_t *new_array; /* of bdd_t *'s */ + + Substitute all old_array vars with new_array vars. `old_array' and + `new_array' are arrays of bdd_t *'s. Given two arrays of variables a and b + consisting of member values (a1 .. an) and (b1 .. bn), replace all + occurrences of ai by bi. This could be done iteratively with bdd_compose but + would require n passes instead of one. Thus, this algorithm is only a + performance optimization. + +bdd_t * +bdd_then(bdd) +bdd_t *bdd; + + Returns the BDD formula of the function when the top_var of `bdd' evaluates + to 1. The return value takes into account that `bdd' may be a "complemented + pointer". + +bdd_t * +bdd_top_var(bdd) +bdd_t *bdd; + + Returns the BDD formula corresponding to the top variable of `bdd'. For + example, if the top variable of 'bdd' is x, then returns the single variable + BDD formula for x. + +bdd_t * +bdd_xnor(f, g) +bdd_t *f; +bdd_t *g; + + Returns the BDD formula for the xnor of `f' and `g'. + +bdd_t * +bdd_xor(f, g) +bdd_t *f; +bdd_t *g; + + Returns the BDD formula for the xor of `f' and `g'. + +bdd_t * +bdd_zero(manager) +bdd_manager *manager; + + Returns the BDD formula pointing to the constant function 0 of the manager + (a complemented pointer to the constant function 1). + + +Queries about BDD Formulas ---------------------------------------------------- + +boolean +bdd_equal(f, g) +bdd_t *f; +bdd_t *g; + + Checks if the two BDD are identical; returns `1' if they are, `0' otherwise. + +boolean +bdd_is_cube(f) +bdd_t *f; + + Returns TRUE if `f' is a cube, else returns FALSE. `f' is a cube if it has + a single path to the constant ONE node. + +boolean +bdd_is_tautology(f, phase) +bdd_t *f; +boolean phase; + + Checks if the given function is tautologously true. `phase' indicates the + phase to be used for `f', i.e. phase==1 checks if f==1 and phase==0 checks + if f'==1. + +boolean +bdd_leq(f, g, f_phase, g_phase) +bdd_t *f; +bdd_t *g; +boolean f_phase; +boolean g_phase; + + Checks for implications. `f_phase' and `g_phase' indicate the phases to be + used for `f' and `g'. For example, bdd_leq(f, g, 1, 0) returns returns the + value of (f => g'). (While this can be done using bdd_or and then checking + if this result is a constant value, using bdd_leq is generally faster and + uses less memory. Note that bdd_leq uses the ITE_const cache.) + + +Statistics and Other Queries -------------------------------------------------- + +double +bdd_count_onset(fn, var_array) +bdd_t *fn; +array_t *var_array; /* of bdd_t *'s */ + + Counts the number of minterms in the onset of the function `fn', over the + variables in `var_array' (single variable BDD formulas). `var_array' must + contain the variables in the support of `fn'. For example, if fn=b*d, and + var_array=[a,b,c,d], then this function returns 4.0. + +bdd_manager * +bdd_get_manager(f) +bdd_t *f; + + Returns the bdd_manager to which `f' is associated. + +bdd_node * +bdd_get_node(f, is_complemented) +bdd_t *f; +boolean *is_complemented; /* return */ + + Return the regularized (i.e. uncomplemented) pointer to the bdd_node + to which `f' refers. Also, returns whether or not the bdd_node pointer + is complemented. Note well: the address of a bdd_node changes upon + garbage collection. If your code is sensitive to the addresses of + bdd_nodes, and you invoke BDD routines which cause new bdd_nodes to be + created, then a garbage collection may automatically be triggered. To + prevent a garbage collection from automatically occurring, use + bdd_set_gc_mode to turn off garbage collection before a sensitive piece + of code is executed. + +void +bdd_get_stats(manager, stats) +bdd_manager *manager; +bdd_stats *stats; /* return */ + + Statistics for the BDD manager are returned in stats; these stats can then + be used directly in a call to bdd_print_stats. Statistics include + information about usage of caches, number of ITE operations, number of + bdd_node's and bdd_t's, and operation of the garbage collector. + + Following is a sample usage: + + bdd_stats stats; /* allocate a struct, not a pointer to a struct */ + + bdd_get_stats(manager, &stats); + bdd_print_stats(stats, stdout); + +var_set_t +*bdd_get_support(fn) +bdd_t *fn; + + Returns the support of `fn' in terms of the variables in the BDD manager. + The result is returned as a bit array (see the var_set package). + +array_t * +bdd_get_varids(var_array) +array_t *var_array; /* of bdd_t * */ + + Given an array of single variable BDD formulas, returns an array of the + same length whose entries are the corresponding bdd_variableIds of the BDDs. + +unsigned int +bdd_num_vars(manager) +bdd_manager *manager; + + Returns the number of variables in the BDD manager. + +void +bdd_print(f) +bdd_t *f; + + A representation of the BDD is printed out on the standard output. For + example, the following is printed out for the function z = !a*b + a*!b where + the indices (variable IDs) for a and b are 0 and 1 respectively. A "!" + before an address indicates a complemented pointer. Note that the variables + from the root to the leaves of the BDD are in ascending order. + + node: a + index 0 is v#0 + index 1 is v#1 + ID = 0x1007651 index = 0 T = 1 E = 0 + + node: b + index 0 is v#0 + index 1 is v#1 + ID = 0x1007652 index = 1 T = 1 E = 0 + + node: {z} + index 0 is v#0 + index 1 is v#1 + ID = !0x1007655 index = 0 T = 0x1007652 E = !0x1007652 + ID = 0x1007652 index = 1 T = 1 E = 0 + + +void +bdd_print_stats(stats, file) +bdd_stats stats; +FILE *file; + + Print the statistics as returned by bdd_get_stats. The following is a + sample output. + + BDD Package Statistics + + Blocks (bdd_nodeBlock): 10 + + Nodes (bdd_node): + used unused total peak + 7672 2558 10230 10230 + + Extptr (bdd_t): + used unused total + 2 350 352 + + Hashtable: + hits: 168530 (75.0%) + misses: 56325 (25.0%) + total: 224855 (find_or_add calls) + + Caches: ITE ITE_const adhoc + Total calls: 240415 3790 318680 + trivial: 64.8% 41.2% 22.7% + cached: 6.3% 4.7% 9.0% + full: 28.9% 54.1% 68.3% + Total lookups: 86590 2229 246289 + misses: 82.6% 92.0% 88.4% + Total inserts: 69487 2051 -- + collisions: 82.7% 68.6% -- + + Garbage Collections: + collections: 6 + total nodes collected: 48653 + total time: 0.48 sec + + Memory Usage (bytes): + manager: 492 + bdd_nodes: 327520 + hashtable: 16364 + extptrs (bdd_t): 4312 + ITE cache: 35852 + ITE_const cache: 2068 + adhoc cache: 0 + total: 386608 + + "Blocks" gives the number of pairs of bdd_nodeBlocks allocated. A + bdd_nodeBlock is an array of bdd_nodes. Blocks are allocated in pairs since + an equal space must be maintained for the stop-and-copy garbage collector. + Thus, at any time, only one block of the pair is being used. For a given + manager, the number of blocks is a non-decreasing number over time. The + number of blocks initially allocated can be controlled by using + bdd_start_with_params. + + "Nodes" gives the number of bdd_nodes currently in use ("used"), and the + number currently available for use ("unused"). Their sum is "total". + "total" divided by the number of blocks gives the number of nodes per block. + "peak" gives the maximum value of "used" seen so far. Nodes which are not + reachable from bdd_t's, but which have not been garbage collected yet, are + counted under "used". If garbage nodes are found during a garbage + collection, then "used" will decrease and "unused" will increase. + Immediately following a garbage collection, more bdd_nodeBlocks are + allocated (if sufficient memory exists) so that the ratio of "used" to + "unused" is 2 to 1. This ratio can be controlled by using + bdd_start_with_params. + + "Extptr" gives the number of bdd_t's currently in use ("used") and the + number currently available for use ("unused"). Their sum is "total". + + "Hashtable" gives statistics on the table which maintains the uniqueness of + bdd_nodes. Before a new node is inserted into the table, a find_or_add call + is made. If the node already exists in the table, a "hit" is recorded, and + if not, a "miss" is recorded and the node is added to the table. + + "Caches" gives statistics on the caches used to improve the performance of + the BDD package. A cache is used to remember the result of certain + computations. The ITE cache remembers the results of ITE(f,g,h) operations; + the ITE_const cache remembers the result of ITE_const operations (used only + for bdd_leq; see the Brace paper); the adhoc cache remembers the results of + "adhoc operations" (bdd_and_smooth, bdd_cofactor, bdd_compose, bdd_cproject, + bdd_smooth, and bdd_substitute). Only one ITE cache and one ITE_const cache + are used throughout the lifetime of a manager. On the other hand, a new + adhoc cache is created each time an application calls an adhoc operation; the + cache is destroyed at the end of the operation. + + These caches are appropriately modified so that they are consistent after a + garbage collection. An entry ((f,g,h), result) in the ITE or ITE_const + cache is saved only if f, g, h and `result' survived the garbage collection. + All the entries in the adhoc cache are saved. + + "Total calls" gives the number of calls to the "core" function involved. + For example, for the ITE cache, this gives the number of calls to bdd__ITE_. + Note that these core functions are recursive. Of the total number of calls, + "trivial" gives the percentage for which the result is determined trivially + (e.g. bdd__ITE_(1,g,h) = g), "cached" gives the percentage for which the + result was found in the cache, and "full" gives the percentage for which a + full computation had do be performed. The sum of these three percentages is + 100%. + + "Total lookups" gives the number of non-trivial calls. "misses" gives the + percentage of lookups which resulted in a cache miss. "Total inserts" gives + the number of cache misses, which is the number of insertions into the + cache. + + The ITE and ITE_const caches do not maintain collision chains: they are + "closed" caches. Consequently, if a key hashes to a bucket which is already + occupied, causing a collision, then the old key is destroyed and the new key + takes its place. "collisions" gives the percentage of insertions which + result in a collision. The adhoc cache is an open cache, and thus there are + no collisions. + + "Garbage Collections" gives the total number of garbage collections, the + cumulative number of nodes collected, and the total time spent garbage + collecting. + + "Memory Usage" gives a breakdown of the memory used by various components of + the BDD manager. "manager" refers to the bdd_manager data structure. + Remember that the adhoc cache is destroyed after each call to an operation + that uses the adhoc cache, and thus will probably read 0. The memory usage + statistics are not updated incrementally; they are only updated by calling + bdd_get_stats. + + Upon certain memory allocation failures in the BDD package, statistics are + printed under the title "BDD Manager Death Statistics" before the program + exits. + +int +bdd_size(bdd) +bdd_t *bdd; + + Returns the size of the BDD: 1 for the constant functions 0 and 1, 2 for a + single variable BDD formula, and so on. + +bdd_variableId +bdd_top_var_id(f) +bdd_t *f; + + Returns the variable ID of the bdd_node to which `f' refers. The variable + ID of a node never changes. The result is undefined if `f' refers to one + of the constant functions. + + + +Traversal of BDD Formulas ----------------------------------------------------- + +int +bdd_gen_free(gen) +bdd_gen *gen; + + Frees the bdd_gen `gen'. This should be called after breaking out of + foreach_bdd_cube or foreach_bdd_node. Always returns 0. + +foreach_bdd_cube(fn, gen, cube) +bdd_t *fn; +bdd_gen *gen; +array_t *cube; /* return of bdd_literal */ + + The BDD corresponding to `fn' is traversed via `gen', with `cube' being + filled with successive members of the BDD formula onset. The cube is an + array of bdd_literals. A bdd_literal can have values 0 (variable appears + complemented), 1 (variable appears not complemented), or 2 (variable does + not appear). The cover generated is disjoint. The BDD is traversed using + depth-first search, with the ELSE branch searched before the THEN branch. + The same array `cube' is used for each iteration; do not attempt to free + it, and use array_dup if you need to remember it. A single array is + allocated for `cube' by the generator, and it is freed when the generator + completes, or when bdd_gen_free is called. + +foreach_bdd_node(fn, gen, node) +bdd_t *fn; +bdd_gen *gen; +bdd_node *node; /* return */ + + The BDD corresponding to `fn' is traversed via `gen', with `node' being + filled with each node in the BDD. The BDD is traversed using depth-first + search, with the ELSE branch searched before the THEN branch, and a node + returned only after its children have been returned. Note that the returned + bdd_node pointer has the complement bit zeroed out. + + + These generators are macros. Typical usage is: + + foreach_bdd_node(fn, gen, node) { + /* do something with node */ + } + + Caution: If you are creating new BDDs while iterating through the nodes or + cubes, and a garbage collection happens to be performed during this process, + the program will abort. To avoid this, use bdd_set_gc_mode to toggle the + garbage collector off before you start the iteration, and back on after you + have completed the iteration. + + + +Miscellaneous ----------------------------------------------------------------- + +bdd_external_hooks * +bdd_get_external_hooks(manager) +bdd_manager *manager; + + Returns a pointer to the external_hooks data structure of `manager'. The + external_hooks structure is used to store application-specific data with + the manager. + +void +bdd_register_daemon(manager, daemon) +bdd_manager *manager; +void (*daemon)(); + + Register `daemon' as the function to be called from the BDD manager when the + application-specified memory limit is exceeded. If no memory limit is set, + then no daemon needs to be registered. The `daemon' must take a pointer to + bdd_manager as its only argument and must return void: + + void daemon(manager) + bdd_manager *manager; + + Memory allocations in the BDD package fall into three categories: + + 1) bdd_nodeBlock allocations - the memory limit is checked. If the limit + will be exceeded, then the current, partial computation is cleared, the + garbage collector is called, and then the daemon is called. + + 2) cache allocations - the memory limit is checked. If the limit will be + exceeded, then the allocation is not made, and the BDD package continues. + Such allocations only serve to cache previous results, and thus not making + such allocations trades off time in favor of space. + + 3) small, one-time allocations or temporary allocations - the memory limit + is not checked. (Also included in this category are allocations of + bdd_t's.) + + Following is a sample usage: + + static void + my_callback(manager) + bdd_manager *manager; + { + bdd_stats stats; + + bdd_get_stats(manager, &stats); + bdd_print_stats(stats, stdout); + (void) fprintf(stdout, "Exceeded memory limit\n"); + exit(1); + } + + int check_networks_equal(ntwk1, ntwk2, num_vars) + network_t *ntwk1; + network_t *ntwk2; + int num_vars; + { + bdd_manager *manager; + bdd_mgr_init mgr_init; + + bdd_set_mgr_init_dflts(&mgr_init); /* get defaults */ + mgr_init.memory.limit = 10; /* set at 10 megabytes */ + mgr_init.memory.deamon = my_callback; /* set daemon */ + manager = bdd_start_with_params(num_vars, &mgr_init); + return(networks_equal(manager, ntwk1, ntwk2)); + } + + + Another sample usage (see "man setjmp" for details on setjmp and longjmp): + + #include /* defines jmp_buf, setjmp, longjmp */ + static jmp_buf my_jmpbuf /* global variable */ + static void mem_limit_callback() /* callback routine */ + { + longjmp(my_jmpbuf, 1); + } + + void simplify_network(network, manager) + network_t *network; + bdd_manager *manager; /* already initialized and in use */ + { + node_t *node; + lsGen gen; + + bdd_register_daemon(manager, mem_limit_callback); + foreach_node(network, gen, node){ + if (setjmp(my_jmpbuf) > 0) { + /* memory limit exceeded; go to next node */ + continue; + } + simplify_node_using_bdds(node); + } + } + +void +bdd_set_gc_mode(manager, no_gc) +bdd_manager *manager; +boolean no_gc; + + If no_gc==0, turn on garbage collection, else if no_gc==1, turn off garbage + collection. + +void +bdd_dynamic_reordering(manager, algorithm_type) +bdd_manager *manager; +bdd_reorder_type_t algorithm_type; + + Prints the following message: "WARNING: Dynamic variable reordering not + implemented in the Berkeley BDD package." + + + + + + diff --git a/sis/bdd_ucb/bdd.h b/sis/bdd_ucb/bdd.h new file mode 100644 index 0000000..8a77e31 --- /dev/null +++ b/sis/bdd_ucb/bdd.h @@ -0,0 +1,408 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#ifndef bdd_h /* { */ +#define bdd_h + +#include "var_set.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd.h,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.9 1993/07/27 20:15:45 sis + * Added declarations of 5 new functions, and bdd_min_match enumerated type. + * + * Revision 1.9 1993/07/27 20:15:45 sis + * Added declarations of 5 new functions, and bdd_min_match enumerated type. + * + * Revision 1.9 1993/07/27 19:29:53 shiple + * Added declarations of 5 new functions, and bdd_min_match enumerated type. + * + * Revision 1.8 1993/07/19 21:27:59 shiple + * Added declaration of bdd_get_varids. + * + * Revision 1.7 1993/06/30 00:14:37 shiple + * Added declaration of bdd_dynamic_reordering. + * + * Revision 1.6 1993/06/28 22:34:05 shiple + * Added declaration of bdd_num_vars. + * + * Revision 1.5 1993/06/04 15:42:51 shiple + * Added declarations for the new functions bdd_get_manager, bdd_top_var_id, + * and bdd_get_node. Removed declaration for bdd_set_external_hooks. + * + * Revision 1.4 1993/05/03 20:27:49 shiple + * Made changes for ANSI C compatibility: 1) moved the definition of + * bdd_mgr_init forward; 2) removed illegal comma in enum definition; 3) + * fixed declaration of bdd_register_daemon. Changed default sizes of + * caches. Added declarations for bdd_cproject and bdd_consensus. + * + * Revision 1.3 1993/02/24 20:30:46 shiple + * Added declarations for bdd_get_support and bdd_count_onset. + * Added include of var_set.h + * + * Revision 1.2 1992/09/19 02:17:44 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added BDD_MEMORY_USAGE debug switch. + * Added sbrk, cache.itetable, gc.runtime, memory, ext ptr blocks, peak nodes, + * and nodes collected to stats data structure. Added BDD_DFLT_* definitions. + * Always define boolean. Added bdd_register_daemon declaration. + * + * Revision 1.1 1992/07/29 00:26:43 shiple + * Initial revision + * + * Revision 1.3 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 21:29:14 sis + * Corrected some arguments to EXTERN declarations. + * + * Revision 1.1 92/01/08 17:34:24 sis + * Initial revision + * + * Revision 1.2 91/05/01 17:46:40 shiple + * convert to new declaration format using EXTERN and ARGS + * + * Revision 1.1 91/03/27 14:35:27 shiple + * Initial revision + * + * + */ + +/* + * The BDD Package using Garbage Collection + * + * Within a bdd manager there can be multiple + * bdd's which all share the same storage. + */ + + /* basic definitions for debugging */ + +#undef BDD_AUTOMATED_STATISTICS_GATHERING +#undef BDD_DEBUG +#undef BDD_DEBUG_AGE +#undef BDD_DEBUG_EXT +#undef BDD_DEBUG_EXT_ALL +#undef BDD_DEBUG_GC +#undef BDD_DEBUG_GC_STATS +#undef BDD_DEBUG_LIFESPAN +#undef BDD_DEBUG_SF +#undef BDD_DEBUG_UID +#undef BDD_FLIGHT_RECORDER +#define BDD_INLINE_ITE +#define BDD_INLINE_ITE_CONSTANT +#undef BDD_NO_GC +#undef BDD_STATS +#undef BDD_DEBUG_LIFESPAN_TRACEFILE "/usr/tmp/lifespan.trace" +#undef BDD_FLIGHT_RECORDER_LOGFILE "/usr/tmp/flight_recorder%06d.log" +#undef BDD_MEMORY_USAGE + +typedef struct bdd_manager bdd_manager; /* referenced via a pointer only */ +typedef struct bdd_t bdd_t; /* referenced via a pointer only */ +typedef unsigned int bdd_variableId; /* the id of the variable in a bdd node */ +typedef struct bdd_node bdd_node; /* referenced via a pointer only */ +typedef int bdd_literal; /* integers in the set { 0, 1, 2 } */ + +#define boolean int + +/* + * Initialization data structure. + */ +typedef struct bdd_mgr_init { + struct { + boolean on; /* TRUE/FALSE: is the cache on */ + unsigned int resize_at; /* percentage at which to resize (e.g. 85% is 85); doesn't apply to adhoc */ + unsigned int max_size; /* max allowable number of buckets; for adhoc, max allowable number of entries */ + } ITE_cache, + ITE_const_cache, + adhoc_cache; + struct { + boolean on; /* TRUE/FALSE: is the garbage collector on */ + } garbage_collector; + struct { + void (*daemon)(); /* used for callback when memory limit exceeded */ + unsigned int limit; /* upper bound on memory allocated by the manager; in megabytes */ + } memory; + struct { + float ratio; /* allocate new bdd_nodes to achieve ratio of used to unused nodes */ + unsigned int init_blocks; /* number of bdd_nodeBlocks initially allocated */ + } nodes; +} bdd_mgr_init; + +/* + * Match types for BDD minimization. + */ +typedef enum { + BDD_MIN_TSM, /* two-side match */ + BDD_MIN_OSM, /* one-side match */ + BDD_MIN_OSDM /* one-side DC match */ +} bdd_min_match_type_t; + +/* + * BDD Manager Allocation And Destruction + */ +EXTERN void bdd_end ARGS((bdd_manager *)); +EXTERN void bdd_register_daemon ARGS((bdd_manager *, void (*daemon)())); +EXTERN void bdd_set_mgr_init_dflts ARGS((bdd_mgr_init *)); +EXTERN bdd_manager *bdd_start ARGS((int)); +EXTERN bdd_manager *bdd_start_with_params ARGS((int, bdd_mgr_init *)); + +/* + * BDD Variable Allocation + */ +EXTERN bdd_t *bdd_create_variable ARGS((bdd_manager *)); +EXTERN bdd_t *bdd_get_variable ARGS((bdd_manager *, bdd_variableId)); + +/* + * BDD Formula Management + */ +EXTERN bdd_t *bdd_dup ARGS((bdd_t *)); +EXTERN void bdd_free ARGS((bdd_t *)); + +/* + * Operations on BDD Formulas + */ +EXTERN bdd_t *bdd_and ARGS((bdd_t *, bdd_t *, boolean, boolean)); +EXTERN bdd_t *bdd_and_smooth ARGS((bdd_t *, bdd_t *, array_t *)); +EXTERN bdd_t *bdd_between ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_cofactor ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_compose ARGS((bdd_t *, bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_consensus ARGS((bdd_t *, array_t *)); +EXTERN bdd_t *bdd_cproject ARGS((bdd_t *, array_t *)); +EXTERN bdd_t *bdd_else ARGS((bdd_t *)); +EXTERN bdd_t *bdd_ite ARGS((bdd_t *, bdd_t *, bdd_t *, boolean, boolean, boolean)); +EXTERN bdd_t *bdd_minimize ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_minimize_with_params ARGS((bdd_t *, bdd_t *, bdd_min_match_type_t, boolean, boolean, boolean)); +EXTERN bdd_t *bdd_not ARGS((bdd_t *)); +EXTERN bdd_t *bdd_one ARGS((bdd_manager *)); +EXTERN bdd_t *bdd_or ARGS((bdd_t *, bdd_t *, boolean, boolean)); +EXTERN bdd_t *bdd_smooth ARGS((bdd_t *, array_t *)); +EXTERN bdd_t *bdd_substitute ARGS((bdd_t *, array_t *, array_t *)); +EXTERN bdd_t *bdd_then ARGS((bdd_t *)); +EXTERN bdd_t *bdd_top_var ARGS((bdd_t *)); +EXTERN bdd_t *bdd_xnor ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_xor ARGS((bdd_t *, bdd_t *)); +EXTERN bdd_t *bdd_zero ARGS((bdd_manager *)); + +/* + * Queries about BDD Formulas + */ +EXTERN boolean bdd_equal ARGS((bdd_t *, bdd_t *)); +EXTERN boolean bdd_is_cube ARGS((bdd_t *)); +EXTERN boolean bdd_is_tautology ARGS((bdd_t *, boolean)); +EXTERN boolean bdd_leq ARGS((bdd_t *, bdd_t *, boolean, boolean)); + +/* + * Statistics and Other Queries + */ +typedef struct bdd_cache_stats { + unsigned int hits; + unsigned int misses; + unsigned int collisions; + unsigned int inserts; +} bdd_cache_stats; + +typedef struct bdd_stats { + struct { + bdd_cache_stats hashtable; /* the unique table; collisions and inserts fields not used */ + bdd_cache_stats itetable; + bdd_cache_stats consttable; + bdd_cache_stats adhoc; + } cache; /* various cache statistics */ + struct { + unsigned int calls; + struct { + unsigned int trivial; + unsigned int cached; + unsigned int full; + } returns; + } ITE_ops, + ITE_constant_ops, + adhoc_ops; + struct { + unsigned int total; + } blocks; /* bdd_nodeBlock count */ + struct { + unsigned int used; + unsigned int unused; + unsigned int total; + unsigned int peak; + } nodes; /* bdd_node count */ + struct { + unsigned int used; + unsigned int unused; + unsigned int total; + unsigned int blocks; + } extptrs; /* bdd_t count */ + struct { + unsigned int times; /* the number of times the garbage-collector has run */ + unsigned int nodes_collected; /* cumulative number of nodes collected over life of manager */ + long runtime; /* cumulative CPU time spent garbage collecting */ + } gc; + struct { + int first_sbrk; /* value of sbrk at start of manager; used to analyze memory usage */ + int last_sbrk; /* value of last sbrk (see "man sbrk") fetched; used to analyze memory usage */ + unsigned int manager; + unsigned int nodes; + unsigned int hashtable; + unsigned int ext_ptrs; + unsigned int ITE_cache; + unsigned int ITE_const_cache; + unsigned int adhoc_cache; + unsigned int total; + } memory; /* memory usage */ +} bdd_stats; + +EXTERN double bdd_count_onset ARGS((bdd_t *, array_t *)); +EXTERN bdd_manager *bdd_get_manager ARGS((bdd_t *)); +EXTERN bdd_node *bdd_get_node ARGS((bdd_t *, boolean *)); +EXTERN void bdd_get_stats ARGS((bdd_manager *, bdd_stats *)); +EXTERN var_set_t *bdd_get_support ARGS((bdd_t *)); +EXTERN array_t *bdd_get_varids ARGS((array_t *)); +EXTERN unsigned int bdd_num_vars ARGS((bdd_manager *)); +EXTERN void bdd_print ARGS((bdd_t *)); +EXTERN void bdd_print_stats ARGS((bdd_stats, FILE *)); +EXTERN int bdd_size ARGS((bdd_t *)); +EXTERN bdd_variableId bdd_top_var_id ARGS((bdd_t *)); + +/* + * Traversal of BDD Formulas + */ +typedef enum { + bdd_EMPTY, + bdd_NONEMPTY +} bdd_gen_status; + +typedef enum { + bdd_gen_cubes, + bdd_gen_nodes +} bdd_gen_type; + +typedef struct { + bdd_manager *manager; + bdd_gen_status status; + bdd_gen_type type; + union { + struct { + array_t *cube; /* bdd_cube_literal */ + /* ... expansion ... */ + } cubes; + struct { + st_table *visited; /* of bdd_node* */ + /* ... expansion ... */ + } nodes; + } gen; + struct { + int sp; + bdd_node **stack; + } stack; + bdd_node *node; +} bdd_gen; + +/* + * foreach macro in the most misesque tradition + * bdd_gen_free always returns 0 + */ + +/* + * foreach_bdd_cube(fn, gen, cube) + * bdd_t *fn; + * bdd_gen *gen; + * array_t *cube; - return + * + * foreach_bdd_cube(fn, gen, cube) { + * ... + * } + */ +#define foreach_bdd_cube(fn, gen, cube)\ + for((gen) = bdd_first_cube(fn, &cube);\ + ((gen)->status != bdd_EMPTY) ? TRUE: bdd_gen_free(gen);\ + (void) bdd_next_cube(gen, &cube)) + +/* + * foreach_bdd_node(fn, gen, node) + * bdd_t *fn; + * bdd_gen *gen; + * bdd_node *node; - return + */ +#define foreach_bdd_node(fn, gen, node)\ + for((gen) = bdd_first_node(fn, &node);\ + ((gen)->status != bdd_EMPTY) ? TRUE: bdd_gen_free(gen);\ + (void) bdd_next_node(gen, &node)) + +EXTERN int bdd_gen_free ARGS((bdd_gen *)); + +/* + * These are NOT to be used directly; only indirectly in the macros. + */ +EXTERN bdd_gen *bdd_first_cube ARGS((bdd_t *, array_t **)); +EXTERN boolean bdd_next_cube ARGS((bdd_gen *, array_t **)); +EXTERN bdd_gen *bdd_first_node ARGS((bdd_t *, bdd_node **)); +EXTERN boolean bdd_next_node ARGS((bdd_gen *, bdd_node **)); + +/* + * Miscellaneous + */ +EXTERN void bdd_set_gc_mode ARGS((bdd_manager *, boolean)); + +/* + * These are the hooks for stuff that uses bdd's + * + * There are three hooks, and users may use them in whatever + * way they wish; these hooks are guaranteed to never be used + * by the bdd package. + */ +typedef struct bdd_external_hooks { + char *network; + char *mdd; + char *undef1; +} bdd_external_hooks; + +EXTERN bdd_external_hooks *bdd_get_external_hooks ARGS((bdd_manager *)); + +/* + * Dynamic reordering. + */ +typedef enum { + BDD_REORDER_SIFT, + BDD_REORDER_WINDOW, + BDD_REORDER_NONE +} bdd_reorder_type_t; + +EXTERN void bdd_dynamic_reordering ARGS((bdd_manager *, bdd_reorder_type_t)); + +/* + * Default settings. + */ +#define BDD_NO_LIMIT ((1<<30)-2) +#define BDD_DFLT_ITE_ON TRUE +#define BDD_DFLT_ITE_RESIZE_AT 75 +#define BDD_DFLT_ITE_MAX_SIZE 1000000 +#define BDD_DFLT_ITE_CONST_ON TRUE +#define BDD_DFLT_ITE_CONST_RESIZE_AT 75 +#define BDD_DFLT_ITE_CONST_MAX_SIZE 1000000 +#define BDD_DFLT_ADHOC_ON TRUE +#define BDD_DFLT_ADHOC_RESIZE_AT 0 +#define BDD_DFLT_ADHOC_MAX_SIZE 10000000 +#define BDD_DFLT_GARB_COLLECT_ON TRUE +#define BDD_DFLT_DAEMON NIL(void) +#define BDD_DFLT_MEMORY_LIMIT BDD_NO_LIMIT +#define BDD_DFLT_NODE_RATIO 2.0 +#define BDD_DFLT_INIT_BLOCKS 10 + +#endif /* } */ + diff --git a/sis/bdd_ucb/bdd_cofactor.c b/sis/bdd_ucb/bdd_cofactor.c new file mode 100644 index 0000000..af43543 --- /dev/null +++ b/sis/bdd_ucb/bdd_cofactor.c @@ -0,0 +1,266 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_cofactor.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_cofactor.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd_cofactor.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.4 1993/02/25 01:09:39 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.4 1993/02/25 01:09:39 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.3 1993/01/20 23:45:49 shiple + * Moved block of code. Fixed three errors in comments. + * + * Revision 1.2 1992/09/19 02:23:19 shiple + * Version 2.4 + * > Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Added adhoc_ops stats. Restructured _cofactor so that the cases where one branch of g + * is ZERO are properly hashed and accounted for in the statistics. + * + * Revision 1.1 1992/07/29 00:26:44 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:25 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:28 shiple + * Initial revision + * + * + */ + +/* + * ARGH! The word ``cofactor'' is an exported function in mis, + * so we are not allowed to use it here! ARGH! These guys don't + * believe in package prefixes! ARGH! + */ +static bdd_node *_cofactor(); + +/* + * bdd_cofactor - cofactor f by g + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_cofactor(f, g) +bdd_t *f; +bdd_t *g; +{ + bdd_safeframe frame; + bdd_safenode ret; + bdd_manager *manager; + bdd_t *h; + + if (f == NIL(bdd_t) || g == NIL(bdd_t)) + fail("bdd_cofactor: invalid BDD"); + + BDD_ASSERT( ! f->free ); + BDD_ASSERT( ! g->free ); + + if (g->node == BDD_ZERO(g->bdd)) + fail("bdd_cofactor: cofactor wrt zero not defined"); + + if (f->bdd != g->bdd) + fail("bdd_cofactor: different bdd managers"); + + manager = f->bdd; /* either this or g->bdd will do */ + + /* + * Start the safe frame now that we know the input is correct. + * f and g are external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, ret); + + (void) bdd_adhoccache_init(manager); + + ret.node = _cofactor(manager, f->node, g->node); + + /* + * Free the cache, end the safe frame and return the (safe) result + */ + (void) bdd_adhoccache_uninit(manager); + h = bdd_make_external_pointer(manager, ret.node, "bdd_cofactor"); + bdd_safeframe_end(manager); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_cofactor(%d, %d)\n", + bdd_index_of_external_pointer(h), + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(g)); +#endif /* } */ + + return (h); +} + +/* + * _cofactor - recursively perform the cofactoring + * + * ARGH! The word ``cofactor'' is an exported function in mis, + * so we are not allowed to use it here! ARGH! These guys don't + * believe in package prefixes! ARGH! + * + * return the result of the reorganization + */ +static bdd_node * +_cofactor(manager, f, g) +bdd_manager *manager; +bdd_node *f; +bdd_node *g; +{ + bdd_safeframe frame; + bdd_safenode safe_f, safe_g, + ret, + f_T, f_E, + g_T, g_E, + var, co_T, co_E; + bdd_variableId fId, gId; + + bdd_safeframe_start(manager, frame); + bdd_safenode_link(manager, safe_f, f); + bdd_safenode_link(manager, safe_g, g); + bdd_safenode_declare(manager, ret); + bdd_safenode_declare(manager, f_T); + bdd_safenode_declare(manager, f_E); + bdd_safenode_declare(manager, g_T); + bdd_safenode_declare(manager, g_E); + bdd_safenode_declare(manager, var); + bdd_safenode_declare(manager, co_T); + bdd_safenode_declare(manager, co_E); + + BDD_ASSERT(g != BDD_ZERO(manager)); + + manager->heap.stats.adhoc_ops.calls++; + + if (BDD_IS_CONSTANT(manager, f)) { + /* + * f is either zero or one + */ + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager); + return (f); + } + + if (g == BDD_ONE(manager)) { + /* + * If the thing to cofactor by is the constant one + * then the result is just the function itself + */ + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager); + return (f); + } + + /* + * If there is some possibility that the function may have + * been computed before then look up the function in the cache ... + */ + if (bdd_adhoccache_lookup(manager, f, g, /* v */ 0, &ret.node)) { + /* + * The answer was already in the cache, so just return it. + */ + manager->heap.stats.adhoc_ops.returns.cached++; + bdd_safeframe_end(manager); + return (ret.node); + } + + /* + * Dereference the id of the top node, and the then and else branches, + * for each of f and g. + */ + fId = BDD_REGULAR(f)->id; + gId = BDD_REGULAR(g)->id; + (void) bdd_get_branches(f, &f_T.node, &f_E.node); + (void) bdd_get_branches(g, &g_T.node, &g_E.node); + + /* + * In the following code, we must worry about taking a _cofactor + * by the zero function. So, in each case this is special-cased. + * For those cases where we call _cofactor recursively on both branches, + * we subsequently call bdd_find_or_add to get the node (var, 1, 0), + * where the id of var = (fId > gId) ? gId: fId. + */ + if (fId > gId) { + if (g_E.node == BDD_ZERO(manager)) { + /* + * cofactor(f, g_T) + */ + ret.node = _cofactor(manager, f, g_T.node); + } else if (g_T.node == BDD_ZERO(manager)) { + /* + * cofactor(f, g_E) + */ + ret.node = _cofactor(manager, f, g_E.node); + } else { + /* + * ITE(gid, cofactor(f, g_T), cofactor(f, g_E)) + */ + co_T.node = _cofactor(manager, f, g_T.node); + co_E.node = _cofactor(manager, f, g_E.node); + var.node = bdd_find_or_add(manager, gId, BDD_ONE(manager), BDD_ZERO(manager)); + ret.node = bdd__ITE_(manager, var.node, co_T.node, co_E.node); + } + } else if (fId == gId) { + if (g_E.node == BDD_ZERO(manager)) { + /* + * cofactor(f_T, g_T) + */ + ret.node = _cofactor(manager, f_T.node, g_T.node); + } else if (g_T.node == BDD_ZERO(manager)) { + /* + * cofactor(f_E, g_E) + */ + ret.node = _cofactor(manager, f_E.node, g_E.node); + } else { + /* + * ITE(fId, cofactor(f_T, g_T), cofactor(f_E, g_E)) + */ + co_T.node = _cofactor(manager, f_T.node, g_T.node); + co_E.node = _cofactor(manager, f_E.node, g_E.node); + var.node = bdd_find_or_add(manager, fId, BDD_ONE(manager), BDD_ZERO(manager)); + ret.node = bdd__ITE_(manager, var.node, co_T.node, co_E.node); + } + } else { /* fId < gId */ + /* + * ITE(fId, cofactor(f_T, g), cofactor(f_E, g)) + */ + co_T.node = _cofactor(manager, f_T.node, g); + co_E.node = _cofactor(manager, f_E.node, g); + var.node = bdd_find_or_add(manager, fId, BDD_ONE(manager), BDD_ZERO(manager)); + ret.node = bdd__ITE_(manager, var.node, co_T.node, co_E.node); + } + + (void) bdd_adhoccache_insert(manager, f, g, /* v */ 0, ret.node); + manager->heap.stats.adhoc_ops.returns.full++; + + bdd_safeframe_end(manager); + return (ret.node); +} diff --git a/sis/bdd_ucb/bdd_compose.c b/sis/bdd_ucb/bdd_compose.c new file mode 100644 index 0000000..2cbe751 --- /dev/null +++ b/sis/bdd_ucb/bdd_compose.c @@ -0,0 +1,207 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_compose.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_compose.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd_compose.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.4 1993/02/25 01:09:39 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.4 1993/02/25 01:09:39 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.3 1993/01/22 21:13:30 shiple + * Eliminated a redundant line of code. Fixed a comment. + * + * Revision 1.2 1992/09/19 02:26:30 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Added adhoc_ops stats. + * + * Revision 1.1 1992/07/29 00:26:45 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:26 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:29 shiple + * Initial revision + * + * + */ + +static bdd_node *compose(); + +/* + * bdd_compose - compose g into the v slot of f + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_compose(f, v, g) +bdd_t *f; +bdd_t *v; /* must be a var */ +bdd_t *g; +{ + bdd_safeframe frame; + bdd_safenode ret; + bdd_manager *manager; + bdd_t *h; + + if (f == NIL(bdd_t) || v == NIL(bdd_t) || g == NIL(bdd_t)) { + fail ("bdd_compose: invalid BDD"); + } + + BDD_ASSERT( ! f->free ); + BDD_ASSERT( ! v->free ); + BDD_ASSERT( ! g->free ); + + if (f->bdd != v->bdd || f->bdd != g->bdd) { + fail("bdd_compose: different bdd managers"); + } + + /* + * If v does not represent a variable of the form (varId, 1, 0) + */ + if (BDD_IS_COMPLEMENT(v->node)) { + fail("bdd_compose: second argument not a variable"); + } + + manager = f->bdd; /* either this or v->bdd or g->bdd will do */ + + BDD_ASSERT_REGNODE(v->node); + if (v->node->T != BDD_ONE(manager) || + v->node->E != BDD_ZERO(manager)) { + fail("bdd_compose: second argument not a variable"); + } + + /* + * Start the safe frame now that we know the input is correct. + * f, v and g are external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, ret); + + (void) bdd_adhoccache_init(manager); + + BDD_ASSERT_REGNODE(v->node); + ret.node = compose(manager, f->node, v->node->id, g->node); + + /* + * Free the cache, end the safe frame and return the (safe) result + */ + (void) bdd_adhoccache_uninit(manager); + h = bdd_make_external_pointer(manager, ret.node, "bdd_compose"); + bdd_safeframe_end(manager); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_compose(%d, %d, %d)\n", + bdd_index_of_external_pointer(h), + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(v), + bdd_index_of_external_pointer(g)); +#endif /* } */ + + return (h); +} + +static bdd_node * +compose(manager, f, varId, g) +bdd_manager *manager; +bdd_node *f; +bdd_variableId varId; +bdd_node *g; +{ + bdd_safeframe frame; + bdd_safenode safe_f, safe_g, + ret, + f_T, f_E, + var, co_T, co_E; + bdd_variableId fId; + + bdd_safeframe_start(manager, frame); + bdd_safenode_link(manager, safe_f, f); + bdd_safenode_link(manager, safe_g, g); + bdd_safenode_declare(manager, ret); + bdd_safenode_declare(manager, f_T); + bdd_safenode_declare(manager, f_E); + bdd_safenode_declare(manager, var); + bdd_safenode_declare(manager, co_T); + bdd_safenode_declare(manager, co_E); + + manager->heap.stats.adhoc_ops.calls++; + + fId = BDD_REGULAR(f)->id; + + if (fId > varId) { + /* + * The variable in question, varId, is not related to + * the function f, so just return f directly as the compose + */ + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager) + return (f); + } + + if (bdd_adhoccache_lookup(manager, f, g, (bdd_int) varId, &ret.node)) { + /* + * The answer was already in the cache, so just return it. + */ + manager->heap.stats.adhoc_ops.returns.cached++; + bdd_safeframe_end(manager); + return (ret.node); + } + + (void) bdd_get_branches(f, &f_T.node, &f_E.node); + + if (fId == varId) { + /* + * ITE(g, f_T, f_E) + * + * This is where the real work gets done + */ + ret.node = bdd__ITE_(manager, g, f_T.node, f_E.node); + } else { + /* + * ITE(f, compose(f_T, var, g), compose(f_E, var, g)) + */ + co_T.node = compose(manager, f_T.node, varId, g); + co_E.node = compose(manager, f_E.node, varId, g); + + var.node = bdd_find_or_add(manager, fId, BDD_ONE(manager), BDD_ZERO(manager)); + + ret.node = bdd__ITE_(manager, var.node, co_T.node, co_E.node); + } + + (void) bdd_adhoccache_insert(manager, f, g, (bdd_int) varId, ret.node); + manager->heap.stats.adhoc_ops.returns.full++; + + bdd_safeframe_end(manager); + return (ret.node); +} diff --git a/sis/bdd_ucb/bdd_cproject.c b/sis/bdd_ucb/bdd_cproject.c new file mode 100644 index 0000000..e9f0aae --- /dev/null +++ b/sis/bdd_ucb/bdd_cproject.c @@ -0,0 +1,183 @@ +#include "util.h" +#include "array.h" +#include "st.h" +#include "bdd.h" +#include "bdd_int.h" + +static bdd_node *cproject(); + +/* + * This CPROJ_OFFSET is used to effectively partition the adhoc cache into two pieces: one used for + * cproject, the other for smooth. It is assumed that the size of the var_array will never + * exceed this value. + */ +#define CPROJ_OFFSET 1000000 + + +/* + * bdd_cproject - the compatible projection function + * + * + * Return the new bdd (external pointer) corresponding to the compatible + * projection of f onto the variables in var_array. The "reference vertex" + * mentioned in Bill Lin's work is here hardcoded to all 1's. + */ +bdd_t * +bdd_cproject(f, var_array) +bdd_t *f; +array_t *var_array; /* of bdd_t* */ +{ + bdd_manager *manager; + bdd_safeframe frame; + bdd_safenode real_f, ret; + array_t *vars; /* of int */ + bdd_t *h; + + if (f == NIL(bdd_t)) { + fail ("bdd_cproject: invalid BDD"); + } + + BDD_ASSERT( ! f->free ); + + manager = f->bdd; + + /* + * After the input is checked for correctness, start the safe frame + * f and g are already external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, real_f); + bdd_safenode_declare(manager, ret); + + real_f.node = f->node; + + vars = bdd_get_sorted_varids(var_array); + (void) bdd_adhoccache_init(manager); + + ret.node = cproject(manager, f->node, 0, vars); + + /* + * End the safe frame and return the result + */ + (void) bdd_adhoccache_uninit(manager); + h = bdd_make_external_pointer(manager, ret.node, "bdd_cproject"); + bdd_safeframe_end(manager); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + fprintf(manager->debug.flight_recorder.log, "%d <- bdd_cproject(%d, { ", + bdd_index_of_external_pointer(h), + bdd_index_of_external_pointer(f)); + { + int i; + + for (i=0; idebug.flight_recorder.log, "%d%s", + bdd_index_of_external_pointer(v), + i+1 == array_n(var_array) ? " } )\n": ", "); + } + } +#endif /* } */ + + return h; +} + +/* + * cproject - recursively perform compatible projection + * + * return the result of the reorganization + */ +static bdd_node * +cproject(manager, f, index, vars) +bdd_manager *manager; +bdd_node *f; +int index; +array_t *vars; +{ + bdd_safeframe frame; + bdd_safenode safe_f; + bdd_safenode f_T, f_E; + bdd_safenode pr_T, pr_E; + bdd_safenode sm, pr; + bdd_safenode ret, var, local; + bdd_variableId fId, top_varId; + + bdd_safeframe_start(manager, frame); + bdd_safenode_link(manager, safe_f, f); + bdd_safenode_declare(manager, ret); + bdd_safenode_declare(manager, f_T); + bdd_safenode_declare(manager, f_E); + bdd_safenode_declare(manager, pr_T); + bdd_safenode_declare(manager, pr_E); + bdd_safenode_declare(manager, sm); + bdd_safenode_declare(manager, pr); + bdd_safenode_declare(manager, var); + bdd_safenode_declare(manager, local); + + manager->heap.stats.adhoc_ops.calls++; + + if (index >= array_n(vars)) { + /* no more variables to project */ + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager); + return f; + } + if (f == BDD_ZERO(manager)) { + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager); + return f; + } + + if (bdd_adhoccache_lookup(manager, f, NIL(bdd_node), index+CPROJ_OFFSET, &ret.node)) { + /* + * The answer was already in the cache, so just return it. + */ + manager->heap.stats.adhoc_ops.returns.cached++; + bdd_safeframe_end(manager); + return (ret.node); + } + + /* + * Get the single variable BDD corresponding to the next variable to be processed. + */ + top_varId = array_fetch(int, vars, index); + var.node = bdd_find_or_add(manager, top_varId, BDD_ONE(manager), BDD_ZERO(manager)); + + (void) bdd_get_branches(f, &f_T.node, &f_E.node); + fId = BDD_REGULAR(f)->id; + + if (fId > top_varId || f == BDD_ONE(manager)) { + /* f does not depend on y_i, then set it to constant */ + pr.node = cproject(manager, f, index + 1, vars); + ret.node = bdd__ITE_(manager, var.node, pr.node, BDD_ZERO(manager)); + } else if (fId == top_varId) { + /* smooth out from f_T all remaining variables in vars, after top_varId */ + sm.node = bdd_internal_quantify(manager, f_T.node, index + 1, vars, BDD_EXISTS); + if (sm.node == BDD_ONE(manager)) { + pr.node = cproject(manager, f_T.node, index + 1, vars); + ret.node = bdd__ITE_(manager, var.node, pr.node, BDD_ZERO(manager)); + } else if (sm.node == BDD_ZERO(manager)) { + pr.node = cproject(manager, f_E.node, index + 1, vars); + ret.node = bdd__ITE_(manager, var.node, BDD_ZERO(manager), pr.node); + } else { + pr_T.node = cproject(manager, f_T.node, index + 1, vars); + pr_E.node = cproject(manager, f_E.node, index + 1, vars); + pr.node = bdd__ITE_(manager, sm.node, BDD_ZERO(manager), pr_E.node); + ret.node = bdd__ITE_(manager, var.node, pr_T.node, pr.node); + } + } else { /* fId < top_varId */ + pr_T.node = cproject(manager, f_T.node, index, vars); + pr_E.node = cproject(manager, f_E.node, index, vars); + local.node = bdd_find_or_add(manager, fId, BDD_ONE(manager), BDD_ZERO(manager)); + ret.node = bdd__ITE_(manager, local.node, pr_T.node, pr_E.node); + } + + (void) bdd_adhoccache_insert(manager, f, NIL(bdd_node), index+CPROJ_OFFSET, ret.node); + manager->heap.stats.adhoc_ops.returns.full++; + + bdd_safeframe_end(manager); + return (ret.node); +} + diff --git a/sis/bdd_ucb/bdd_end.c b/sis/bdd_ucb/bdd_end.c new file mode 100644 index 0000000..714dc77 --- /dev/null +++ b/sis/bdd_ucb/bdd_end.c @@ -0,0 +1,157 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_end.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_end.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd_end.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 02:29:20 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Changed ITE and ITE_const caches to be arrays of pointers. Added call to + * bdd_dump_manager_stats if BDD_DEBUG switch is on. + * + * Revision 1.1 1992/07/29 00:26:46 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:26 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:30 shiple + * Initial revision + * + * + */ + +/* + * bdd_end - terminate a bdd manager + * + * return nothing, just do it. + */ +void +bdd_end(manager) +bdd_manager *manager; +{ + int h; + bdd_nodeBlock *b, *next_b; + bdd_bddBlock *bb, *next_bb; + int i; + bdd_hashcache_entry *hentry; + bdd_constcache_entry *centry; + + if (manager == NIL(bdd_manager)) + return; /* for compatibility with v2.2 */ + +#if defined(BDD_DEBUG) /* { */ + (void) fprintf(stderr, "\n\nFINAL BDD MANAGER STATS:\n"); + (void) bdd_dump_manager_stats(manager); +#if defined(BDD_FLIGHT_RECORDER) /* { */ + fclose(manager->debug.flight_recorder.log); +#endif /* } */ +#if defined(BDD_DEBUG_LIFESPAN) /* { */ + fclose(manager->debug.lifespan.trace); +#endif /* } */ +#if defined(BDD_DEBUG_AGE) /* { */ + (void) bdd_dump_node_ages(manager, stderr); +#endif /* } */ +#if defined(BDD_DEBUG_EXT) /* { */ + (void) bdd_dump_external_pointers(manager, stderr); +#endif /* } */ +#endif /* } */ + + /* Destruct in order in the structure declaration */ + + /* + * Free the hashtable + */ + FREE(manager->heap.hashtable.buckets); + + /* + * Free the ITE cache, and any entries it contains. + */ + for (i = 0; i < manager->heap.cache.itetable.nbuckets; i++) { + hentry = manager->heap.cache.itetable.buckets[i]; + if (hentry != NIL(bdd_hashcache_entry)) { + FREE(hentry); + } + } + FREE(manager->heap.cache.itetable.buckets); + + /* + * Free the ITE constant cache, and any entries it contains. + */ + for (i = 0; i < manager->heap.cache.consttable.nbuckets; i++) { + centry = manager->heap.cache.consttable.buckets[i]; + if (centry != NIL(bdd_constcache_entry)) { + FREE(centry); + } + } + FREE(manager->heap.cache.consttable.buckets); + + /* + * Free the adhoc cache. + */ + if (manager->heap.cache.adhoc.table != NIL(st_table)) { + bdd_adhoccache_uninit(manager); + } + + /* + * Free the external references + */ + for (bb=manager->heap.external_refs.map; bb != NIL(bdd_bddBlock); bb=next_bb) { + next_bb = bb->next; + FREE(bb); + } + + /* + * Free the nodeBlocks in the heap halves + */ + for (h=0; hheap.half); h++) { + for (b=manager->heap.half[h].inuse.top; b != NIL(bdd_nodeBlock); b=next_b) { + next_b = b->next; + FREE(b); + } + for (b=manager->heap.half[h].free; b != NIL(bdd_nodeBlock); b=next_b) { + next_b = b->next; + FREE(b); + } + } + + /* + * DO NOT touch the mis-specific info that is freed in bdd_quit. + * This routine is designed to be called from network_free + */ + + FREE(manager); +} diff --git a/sis/bdd_ucb/bdd_int.h b/sis/bdd_ucb/bdd_int.h new file mode 100644 index 0000000..2536de3 --- /dev/null +++ b/sis/bdd_ucb/bdd_int.h @@ -0,0 +1,881 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * + */ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: bdd_int.h,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.7 1993/07/27 20:16:10 sis + * Added declarations for BDD minimization related routines. + * + * Revision 1.7 1993/07/27 19:29:53 shiple + * Added declarations for BDD minimization related routines. + * + * Revision 1.6 1993/07/19 21:28:18 shiple + * Removed external declaration of bdd_get_varids. + * + * Revision 1.5 1993/05/03 20:32:24 shiple + * Made changes for ANSI C compatibility: removed illegal comma in enum + * definition. Added bdd_internal_quantify declaration. Added enum for + * quantification type. + * + * Revision 1.4 1993/01/11 23:43:19 shiple + * Made changes for DEC Alpha compatibility. + * + * Revision 1.3 1992/09/19 03:45:08 shiple + * Fix typo on change just made. + * + * Revision 1.2 1992/09/19 02:35:33 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added declaration of bdd_get_percentage. + * Defined bdd_const_hash macro. Before, the constcache was using the bdd_ITE_hash function, and + * thus there was an implicit assumption that the constcache and ITE cache had the same number of + * entries. Renamed hashtable struct in manager to itetable. Changed ITE and ITE_const caches to + * be arrays of pointers. In manager, added rehash_at and max_size fields to caches. In manager, + * added node_ratio, init_node_blocks, and memory structure. + * + * Revision 1.1 1992/07/29 00:26:47 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:27 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:30 shiple + * Initial revision + * + * + */ + +/* + * Internal stuff for the BDD package + * + * None of this stuff is exported back to the package user. + */ + +/* stuff.h - generic useful stuff */ +/* + * Stuff to make the code more pleasant + * + * These kinds of things ought to be in + * the global .h files for any project. + */ + +#if ! defined(__STDC__) && ! defined(boolean) +/* + * Ansi C defines this right? + * this otta be a typedef somewhere + */ +#define boolean int /* either 0 or 1 */ +#endif + +#ifndef NIL +/* this otta be a defined somewhere for us already */ +#define NIL(type) ((type *) 0) +#endif + +#ifndef string /* Ansi C defines this right? */ +/* this otta be a typedef somewhere */ +#define string char * /* a real live '\0' terminated string, not a refany */ +#endif + +#ifndef refany +/* this otta be a typedef somewhere */ +#define refany char * /* a void * or any sort of untyped pointer */ +#endif + +#ifndef any /* Ansi C defines this right? */ +/* this otta be a typedef somewhere */ +#define any char /* so that NIL(any) == refany */ +#endif + +#ifndef TRUE /* Ansi C defines this right? */ +#define TRUE 1 +#endif +#ifndef FALSE /* Ansi C defines this right? */ +#define FALSE 0 +#endif + +#define sizeof_el(thing) (sizeof (thing)/sizeof (thing[0])) + +#ifndef MIN /* Ansi C defines this right? */ +#define MIN(a, b) ((a) < (b) ? (a): (b)) +#endif + +#ifndef MAX /* Ansi C defines this right? */ +#define MAX(a, b) ((a) > (b) ? (a): (b)) +#endif + +#ifndef MIN3 +#define MIN3(a, b, c) MIN(a, MIN(b, c)) +#endif + +#ifndef MAX3 +#define MAX3(a, b, c) MAX(a, MAX(b, c)) +#endif + +/* end stuff.h - end generic useful stuff */ + +/* + * This is the formal beginning of the internal bdd stuff +*/ + +extern int bdd__fail(); /* must return an int so it can be in an expression */ +extern void bdd_memfail(); + +/* + * void + * BDD_FAIL(message) + * string message; + */ +#define BDD_FAIL(message) bdd__fail(__FILE__, __LINE__, message, /* assertion */ NIL(char)) + +#if defined(BDD_DEBUG) /* { */ +#define BDD_ASSERT(condition) ((condition) ? TRUE: \ + bdd__fail(__FILE__, __LINE__, "BDD_ASSERT assertion failed", "condition")) +#else /* } else { */ +#define BDD_ASSERT(condition) (/* be happy */ TRUE) +#endif /* } */ + +/* + * The hash following function is the one that is suggested by Rudell's paper + * + * unsigned int + * bdd_generic_hash(a, b, c, nbuckets) + * unsigned int a; + * unsigned int b; + * unsigned int c; + * unsigned int nbuckets; - presumably a prime + */ +#define bdd_generic_hash(a, b, c, nbuckets) \ + (((((unsigned int) (a)) << 5) + (((unsigned int) (b)) << 7) + (((unsigned int) (c)) << 11)) % ((unsigned int) (nbuckets))) + +/* + * The id's and how some are reserved for system use +*/ +#define BDD_ONE_ID ((bdd_variableId) (1<<30)) +#define BDD_BROKEN_HEART_ID ((bdd_variableId) (1<<30)-1) /* see the broken_heart implementation below */ +#define BDD_USER_0_ID ((bdd_variableId) 0) /* the 0th variableId */ + +/* + * Note the caveat above about referencing bdd nodes only + * via BDD_REGULAR and BDD_COMPLEMENT because any pointer. + * is going to have a sign bit encoded in it. + * + * In addition to being a node in a bdd structure, this node + * is a chain element in a open-hashing chain. The next field + * points to the next member of the chain. + */ +/* typedef struct bdd_node bdd_node is in bdd.h */ +struct bdd_node { + bdd_variableId id; /* variableId is the index of the variable in the bdd */ + struct bdd_node *T; /* then */ + struct bdd_node *E; /* else */ + struct bdd_node *next; /* chain pointer of the containing hashtable */ +#if defined(BDD_DEBUG) /* { */ +#if defined(BDD_DEBUG_AGE) || defined(BDD_DEBUG_LIFESPAN) /* { */ + unsigned int age; /* the garbage-collect epoch of its creation */ +#endif /* } */ +#if defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + unsigned int uniqueId; +#endif /* } */ +#if defined(BDD_DEBUG_GC) /* { */ + int halfspace; /* the halfspace that we're operating in now */ +#endif /* } */ +#endif /* } */ +}; + +/* + * Here's the trick: bdd_node*'s can be either complemented or uncomplemented. + * This means that they are either suitable or unsuitable for use as a C pointer. + * To be used as a pointer, they must be ``regularized'' via BDD_REGULAR. + * + * The convention is that bdd_node*'s can be either regular or unregular + * however some bdd_node*'s MUST be regular. That way we can assert that things + * are correct by asserting that the regular nodes are in fact really regular. + */ +#if defined(BDD_DEBUG) /* { */ +#define BDD_ASSERT_REGNODE(p) \ + ( ! BDD_IS_COMPLEMENT(p) ? TRUE: \ + bdd__fail(__FILE__, __LINE__, "BDD_ASSERT_REGNODE - a bdd_node* is complemented", "p")) +#else /* } else { */ +#define BDD_ASSERT_REGNODE(p) \ + (/* be happy */ TRUE) +#endif /* } */ + +#if defined(BDD_DEBUG) /* { */ +#define BDD_ASSERT_NOTNIL(p) \ + ( (p) != NIL(bdd_node) ? TRUE: \ + bdd__fail(__FILE__, __LINE__, "BDD_ASSERT_NOTNIL - a bdd_node* is NIL", "p")) +#else /* } else { */ +#define BDD_ASSERT_NOTNIL(p) \ + (/* be happy */ TRUE) +#endif /* } */ + +/* + * Now some help for the garbage-collector: + * + * Each bdd_node will need to represent forwarding pointers so that + * the garbage-collector can see what pointers have been forwarded + * from the old space to the new space. These forwarding pointers + * are called ``broken hearts'' (Abelson & Sussman pg 500). + * + * boolean + * BDD_BROKEN_HEART(node) + * bdd_node *node; + * + * boolean + * BDD_FORWARD_POINTER(node) + * bdd_node *node; + * + * boolean + * BDD_SET_FORWARD_POINTER(node, forward) + * bdd_node *node; + * bdd_node *forward; + */ +#define BDD__BROKEN_HEART(node) ( (node) != NIL(bdd_node) && \ + ! BDD_IS_COMPLEMENT(node) && \ + (node)->id == BDD_BROKEN_HEART_ID ) +#define BDD__FORWARD_POINTER(node) ((node)->T) +#define BDD__SET_FORWARD_POINTER(node, forward) { (node)->id = BDD_BROKEN_HEART_ID; \ + (node)->T = (forward); } + +#if defined(BDD_DEBUG_GC) /* { */ +#define BDD_ASSERT_BROKEN_HEART(n) \ + ( BDD_BROKEN_HEART(n) ? TRUE: \ + bdd__fail(__FILE__, __LINE__, "BDD_ASSERT_BROKEN_HEART - not a broken heart", "n")) +#else /* } else { */ +#define BDD_ASSERT_BROKEN_HEART(n) \ + (/* be happy */ TRUE) +#endif /* } */ + +#if defined(BDD_DEBUG_GC) /* { */ +#define BDD_ASSERT_NOT_BROKEN_HEART(n) \ + ( ! BDD_BROKEN_HEART(n) ? TRUE: \ + bdd__fail(__FILE__, __LINE__, "BDD_ASSERT_NOT_BROKEN_HEART - is a broken heart", "n")) +#else /* } else { */ +#define BDD_ASSERT_NOT_BROKEN_HEART(n) \ + (/* be happy */ TRUE) +#endif /* } */ + +#define BDD_BROKEN_HEART(node) \ + BDD__BROKEN_HEART(node) +#define BDD_FORWARD_POINTER(node) \ + ( BDD_ASSERT_BROKEN_HEART(node), \ + BDD__FORWARD_POINTER(node)) +#define BDD_SET_FORWARD_POINTER(node, forward) \ + { BDD_ASSERT_REGNODE(node); \ + BDD_ASSERT_REGNODE(forward); \ + BDD__SET_FORWARD_POINTER(node, forward); } + +/* + * int + * bdd_raw_node_hash(manager, variableId, T, E) + * bdd_manager *manager; + * bdd_variableId variableId; + * bdd_node *T; - may be nil + * bdd_node *E; - may be nil + */ +#if defined(BDD_DEBUG) && (defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN)) /* { */ +#define bdd_raw_node_hash(manager, variableId, T, E) \ + bdd_generic_hash(variableId, \ + (T) == NIL(bdd_node) ? 0: BDD_REGULAR(T)->uniqueId, \ + (E) == NIL(bdd_node) ? 0: BDD_REGULAR(E)->uniqueId, \ + (manager)->heap.hashtable.nbuckets) +#else /* } else { */ +#define bdd_raw_node_hash(manager, variableId, T, E) \ + bdd_generic_hash(variableId, T, E, (manager)->heap.hashtable.nbuckets) +#endif /* } */ + +/* + * int + * bdd_node_hash(manager, node) + * bdd_manager *manager; + * bdd_node *node; - may not be nil + */ +#define bdd_node_hash(manager, node) \ + bdd_raw_node_hash(manager, (node)->id, BDD_REGULAR(node)->T, BDD_REGULAR(node)->E) + +/* + * WATCHOUT A sign bit is encoded in the low-order bit of a + * node pointer. This allows a bdd node to represent both the + * positive phase and negative phase of the function at the same + * time. The phase all depends on how you reference the bdd. + * + * bdd_node * + * BDD_NOT(node) + * bdd_node *node; + * + * Create the negated function of the bdd + * + * bdd_node * + * BDD_REGULAR(node) + * bdd_node *node; + * + * Create the regular function of the bdd + * + * boolean + * BDD_IS_COMPLEMENT(node) + * bdd_node *node; + * + * Does this reprsent the complemented function? + * + * boolean + * BDD_IS_CONSTANT(manager, node) + * bdd_manager *manager; + * bdd_node *node; + * + * Does this reprsent a (the) constant? + */ +#define BDD_NOT(node) ((bdd_node *) ((long) (node) ^ 01L)) +#define BDD_REGULAR(node) ((bdd_node *) ((long) (node) & ~01L)) +#define BDD_IS_COMPLEMENT(node) ((long) (node) & 01L) +#define BDD_IS_CONSTANT(manager, node) (BDD_REGULAR(node) == (manager)->bdd.one) + +/* + * The constants available in the system + * + * bdd_node * + * BDD_ONE(manager) + * bdd_manager *manager; + * + * the constant one + * + * bdd_node * + * BDD_ZERO(manager) + * bdd_manager *manager; + * + * the constant zero (derived from one by complementation) + */ +#define BDD_ONE(manager) (manager)->bdd.one +#define BDD_ZERO(manager) BDD_NOT(BDD_ONE(manager)) + +/* + * The bdd_node heap is made up of a chain of nodeBlocks, each + * of which contain some number of bdd_nodes. + * + * Note now magical the incantiation is for BDD_NODES_PER_NODEBLOCK. + * This is done to ensure that the memory allocator which underlys + * this package is not too smart for our own good. Typical behaviors + * are that memory allocators add their internal overhead, round + * up to the nextclosest power of 2 and allocate that amount of space + * to satisfy the user's (large) space request. We want that internal + * number to be exactly a power of two (or real close to one but less-than) + * + * Want: BDD_NODES_PER_NODEBLOCK == 2^k - BDD_MALLOC_OVERHEAD_ESTIMATE + * ... for appropriate value of k (k is called BDD_NODEBLOCK_PO2 here) + */ +#define BDD_MALLOC_OVERHEAD_ESTIMATE 8 /* assume malloc adds 4 bytes of header info */ + +#if defined(BDD_DEBUG_GC) /* { */ +#define BDD_NODEBLOCK_PO2 7 /* 2^7 = 128 - small for debugging */ +#else /* } else { */ +#if defined(BDD_DEBUG_LIFESPAN) /* { */ +#define BDD_NODEBLOCK_PO2 12 /* 2^12 = 4K - small(er) for debuggin lifespans */ +#else /* } else { */ +#define BDD_NODEBLOCK_PO2 15 /* 2^15 = 32K - the magic Power 'O 2 (PO2) */ +#endif /* } */ +#endif /* } */ + +#define BDD_NODES_PER_NODEBLOCK \ + (((1<<(BDD_NODEBLOCK_PO2-1)) - \ + BDD_MALLOC_OVERHEAD_ESTIMATE - \ + /* used */ sizeof (int) - \ + /* next */ sizeof (long)) / sizeof (bdd_node)) + +typedef struct bdd_nodeBlock { + int used; + struct bdd_nodeBlock *next; + bdd_node subheap[BDD_NODES_PER_NODEBLOCK]; +} bdd_nodeBlock; /* total size plus malloc overhead should be an exact power of 2 */ + +/* + * The hashtable cache + * + * Statement: For the purposes of validation of the BDD package it should + * be (e.g. it is and always must be) possible to turn off the cache. + */ +typedef struct bdd_hashcache_entry { + struct { + bdd_node *f; + bdd_node *g; + bdd_node *h; + } ITE; /* ITE(f, g, h) */ + bdd_node *data; /* NIL(bdd_node) indicates in invalid entry */ +} bdd_hashcache_entry; + +extern void bdd_hashcache_insert(); +extern boolean bdd_hashcache_lookup(); + +/* + * int + * bdd_ITE_hash(manager, f, g, h) + * bdd_manager *manager; + * bdd_node *f; - may not be nil + * bdd_node *g; - may not be nil + * bdd_node *h; - may not be nil + */ +#define bdd_ITE_hash(manager, f, g, h) \ + bdd_generic_hash(f, g, h, (manager)->heap.cache.itetable.nbuckets) + +/* + * int + * bdd_hashcache_entry_hash(manager, entry, nbuckets) + * bdd_manager *manager; + * bdd_hashcache_entry *entry; - may not be nil + */ +#define bdd_hashcache_entry_hash(manager, entry) \ + bdd_ITE_hash(manager, (entry)->ITE.f, (entry)->ITE.g, (entry)->ITE.h) + +/* + * The constant cache + * + * Statement: For the purposes of validation of the BDD package it should + * be (e.g. it is and always must be) possible to turn off the cache. + */ +typedef enum bdd_constant_status { + bdd_status_unknown, /* the cache entry is invalid */ + bdd_constant_zero, /* has the constant value of zero */ + bdd_constant_one, /* has the constant value of one */ + bdd_nonconstant /* has a nonconstant value */ +} bdd_constant_status; + +typedef struct bdd_constcache_entry { + struct { + bdd_node *f; + bdd_node *g; + bdd_node *h; + } ITE; /* ITE(f, g, h) */ + bdd_constant_status data; /* bdd_status_unknown indicates an invalid entry */ +} bdd_constcache_entry; + +extern void bdd_constcache_insert(); +extern boolean bdd_constcache_lookup(); + +/* + * int + * bdd_const_hash(manager, f, g, h) + * bdd_manager *manager; + * bdd_node *f; - may not be nil + * bdd_node *g; - may not be nil + * bdd_node *h; - may not be nil + */ +#define bdd_const_hash(manager, f, g, h) \ + bdd_generic_hash(f, g, h, (manager)->heap.cache.consttable.nbuckets) + +/* + * int + * bdd_constcache_entry_hash(manager, entry) + * bdd_manager *manager; + * bdd_constcache_entry *entry; - may not be nil + */ +#define bdd_constcache_entry_hash(manager, entry) \ + bdd_const_hash(manager, (entry)->ITE.f, (entry)->ITE.g, (entry)->ITE.h) + + +/* + * The ad hoc cache + */ +typedef int bdd_int; /* any integer value */ + +typedef struct bdd_adhoccache_key { + bdd_node *f; /* may be NIL(bdd_node) */ + bdd_node *g; /* may be NIL(bdd_node) */ + bdd_int v; /* may be any integer value */ +} bdd_adhoccache_key; + +extern void bdd_adhoccache_init(); +extern void bdd_adhoccache_uninit(); + +extern void bdd_adhoccache_insert(); +extern boolean bdd_adhoccache_lookup(); + +/* + * The external user's view of a bdd is a bdd_t* (an external pointer) + * + * A ``bdd'' proper is this thing which is a pointer to a (possibly + * complemented) node and a pointer to the bdd manager that manages + * that node. The package user always references into the bdd package + * with a ``bdd_t*'' which provides a safe, indirect way of referencing + * into the garbage-collecting heap. + */ +/* typedef struct bdd_t bdd_t; already typedef'd in bdd.h */ +struct bdd_t { + boolean free; /* TRUE if this is free, FALSE otherwise ... */ + bdd_node *node; /* the node referenced */ + bdd_manager *bdd; /* the manager from whence this came */ +#if defined(BDD_DEBUG_EXT) /* { */ + string origin; /* track the origin of all bdd_t*'s */ +#endif /* } */ +}; + +/* + * And then how these bdd_t's are managed internally (in blocks) + */ +#define BDD_BDDBLOCK_PO2 6 /* 2^6 = 64 */ + +#define BDD_NODES_PER_BDDBLOCK (1<<(BDD_BDDBLOCK_PO2-1)) + +typedef struct bdd_bddBlock { + struct bdd_bddBlock *next; + bdd_t subheap[BDD_NODES_PER_BDDBLOCK]; +} bdd_bddBlock; /* total size plus malloc overhead should be an exact power of 2 */ + +extern bdd_t *bdd_make_external_pointer(); +extern void bdd_destroy_external_pointer(); + +/* + * Safe pointers so that garbage-collection can be called with impunity + * in specially-written routines (e.g. inside a recursive bdd__ITE_()) + * + * A bdd_safenode is a safe pointer + * A bdd_safeframe is a list of safe pointers which are all + * used in the same routine + */ +typedef struct bdd_safenode { + bdd_node *node; /* the node referenced */ + bdd_node **arg; /* the address of a value to clean up */ + struct bdd_safenode *next; /* next (safe) node in the list */ +} bdd_safenode; + +typedef struct bdd_safeframe { + struct bdd_safeframe *prev; + bdd_safenode *nodes; +} bdd_safeframe; + +#if defined(BDD_DEBUG_SF) /* { */ +#define BDD_ASSERT_FRAMES_CORRECT(manager) bdd_assert_frames_correct(manager) +#else /* } else { */ +#define BDD_ASSERT_FRAMES_CORRECT(manager) (/* be happy */ TRUE) +#endif /* } */ + +/* + * void + * bdd_safeframe__start(manager, sf) + * bdd_manager *manager; - by value + * bdd_safeframe sf; - by value (sortof - by reference b/c its a macro) + * + * void + * bdd_safeframe__end(manager) + * bdd_manager *manager; - by value + * + * Usage: DO NOT USE THESE (they are only useful in bdd_new_node) + * use the versions below which do the assertion checks. + */ +#define bdd_safeframe__start(manager, sf) \ + { (sf).nodes = NIL(bdd_safenode); \ + (sf).prev = (manager)->heap.internal_refs.frames; \ + (manager)->heap.internal_refs.frames = &(sf); } +#define bdd_safeframe__end(manager) \ + { (manager)->heap.internal_refs.frames = \ + (manager)->heap.internal_refs.frames->prev; } + +/* + * void + * bdd_safeframe_start(manager, sf) + * bdd_manager *manager; - by value + * bdd_safeframe sf; - by value (sortof - by reference b/c its a macro) + * + * void + * bdd_safeframe_end(manager) + * bdd_manager *manager; - by value + * + * Usage: (see below) + */ +#define bdd_safeframe_start(manager, sf) \ + { BDD_ASSERT_FRAMES_CORRECT(manager); \ + bdd_safeframe__start(manager, sf); } +#define bdd_safeframe_end(manager) \ + { BDD_ASSERT((manager)->heap.internal_refs.frames != NIL(bdd_safeframe)); \ + BDD_ASSERT_FRAMES_CORRECT(manager); \ + bdd_safeframe__end(manager); } + +/* + * void + * bdd_safenode__link(manager, sn, n) + * bdd_manager *manager; - by value + * bdd_safenode sn; - by value (sortof - by reference b/c its a macro) + * bdd_node *n; - by value (sortof - by reference b/c its a macro) + * + * void + * bdd_safenode__declare(manager, sn, n) + * bdd_manager *manager; - by value + * bdd_safenode sn; - by value (sortof - by reference b/c its a macro) + * + * Usage: DO NOT USE THESE (they are only useful in bdd_new_node) + * use the versions below which do the assertion checks. + */ +#define bdd_safenode__link(manager, sn, n) \ + { (sn).node = NIL(bdd_node); \ + (sn).arg = &(n); \ + (sn).next = (manager)->heap.internal_refs.frames->nodes; \ + (manager)->heap.internal_refs.frames->nodes = &(sn); } + +#define bdd_safenode__declare(manager, sn) \ + { (sn).node = NIL(bdd_node); \ + (sn).arg = NIL(bdd_node *); \ + (sn).next = (manager)->heap.internal_refs.frames->nodes; \ + (manager)->heap.internal_refs.frames->nodes = &(sn); } + +/* + * void + * bdd_safenode_link(manager, sn, n) + * bdd_manager *manager; - by value + * bdd_safenode sn; - by value (sortof - by reference b/c its a macro) + * bdd_node *n; - by value (sortof - by reference b/c its a macro) + * + * void + * bdd_safenode_declare(manager, sn, n) + * bdd_manager *manager; - by value + * bdd_safenode sn; - by value (sortof - by reference b/c its a macro) + * + * Usage: (see below) + */ +#define bdd_safenode_link(manager, sn, n) \ + { bdd_safenode__link(manager, sn, n); \ + BDD_ASSERT_FRAMES_CORRECT(manager); } + +#define bdd_safenode_declare(manager, sn) \ + { bdd_safenode__declare(manager, sn); \ + BDD_ASSERT_FRAMES_CORRECT(manager); } + +/* + * Usage: + * void + * some_function_or_another(manager, a) + * bdd_manager *manager; + * bdd_node *a; + * { + * bdd_safeframe frame; + * bdd_safenode safe_a, b, c; + * + * bdd_safeframe_start(manager, frame); + * bdd_safenode_link(manager, safe_a, a); + * bdd_safenode_declare(manager, b); + * bdd_safenode_declare(manager, c); + * + * ... + * + * a = c.node; -- a is referenced directly + * b.node = a; -- b.node references a safenode's value + * + * ... + * + * bdd_safeframe_end(manager); + * } + */ + +/* + * The bdd_manager contains all of the information necessary to manage + * a garbage-collecting heap of bdd_nodes. Garbage-collection is to + * happen transparently to the user, so no pointers can be exported. + * + * Note that this is a BIG structure. That is because it must hold EVERY + * single pointer and variable which is to be used by the bdd package. + * Each bdd_manager contains the _complete_ set of state variables required + * for the bdd package to operate on a heap of bdd's. + */ +/* typedef struct bdd_manager bdd_manager; already typedef'd in bdd.h */ +struct bdd_manager { + char *undef1; /* used for debugging */ + struct { + struct { + unsigned int nkeys; /* the number of keys in the hash table */ + unsigned int nbuckets; /* the size of the buckets array */ + bdd_node **buckets; /* the buckets array */ + int rehash_at_nkeys; /* the number of keys at which we rehash */ + } hashtable; /* all live bdd_nodes are in this hash table */ + struct { + struct { + unsigned int index; /* the roving index in the block */ + bdd_bddBlock *block; /* the block in which we look */ + } pointer; /* the roving pointer in the map */ + unsigned int free; /* the number which are known to be free */ + unsigned int nmap; /* the total number of bdd_t's in map */ + bdd_bddBlock *map; /* mapping bdd_t*'s to bdd_node*'s */ + } external_refs; /* external references from the package user */ + struct { + bdd_safeframe *frames; /* a list of safe frames on the stack */ + } internal_refs; /* internal references from the bdd package */ + struct { + struct { + boolean on; /* is caching even turned on? */ + boolean invalidate_on_gc; /* always invalidate the cache on a gc */ + unsigned int resize_at; /* percentage at which to resize (e.g. 85% is 85) */ + unsigned int max_size; /* don't resize if nbuckets exceeds this */ + unsigned int nbuckets; /* buckets in the cache */ + unsigned int nentries; /* entries in the cache */ + bdd_hashcache_entry **buckets; /* the cache */ + } itetable; /* cache of the hashtable entries */ + struct { + boolean on; /* is caching even turned on? */ + boolean invalidate_on_gc; /* always invalidate the cache on a gc */ + unsigned int resize_at; /* percentage at which to resize (e.g. 85% is 85) */ + unsigned int max_size; /* don't resize if nbuckets exceeds this */ + unsigned int nbuckets; /* buckets in the cache */ + unsigned int nentries; /* entries in the cache */ + bdd_constcache_entry **buckets; /* the cache */ + } consttable; /* for the exclusive use of ITE_constant */ + struct { + boolean on; /* is caching even turned on? */ + unsigned int max_size; /* don't resize if nbuckets exceeds this */ + st_table *table; /* may be NIL - of {bdd_adhoccache_key, bdd_node *} */ + } adhoc; /* cache used for various nefarious purposes (transient) */ + } cache; /* a cache for past computations (partially voided on gc) */ + struct { + struct { + bdd_nodeBlock *top; /* the top of the in-use list (append only) */ + bdd_nodeBlock **tail; /* either &top or &p->next of some member of the list */ + } inuse; /* an in-use list of nodeBlock */ + bdd_nodeBlock *free; /* a free list of unused blocks in this space */ + } half[2]; + unsigned int init_node_blocks; /* number of bdd_nodeBlocks initially allocated */ + struct { + bdd_nodeBlock *block; + unsigned int index; + } pointer; /* a pointer to the next block/object at which to allocate */ + struct { + boolean on; /* is garbage-collection even turned on? */ + int halfspace; /* either 0 or 1, indicating which halfspace is in use */ + float node_ratio; /* ratio of used to unused nodes */ + struct { + int open_generators; /* must be zero to perform a garbage-collect */ + } status; + struct { + struct { + bdd_nodeBlock *block; + unsigned int index; + } start; /* to communicate where to start gc passes */ + } during; /* used _during_ gc only */ + } gc; /* garbage-collection relevancies */ + bdd_stats stats; + } heap; + struct { + bdd_node *one; /* the constant 1 (there is no constant 0) */ + unsigned int nvariables; /* variables in the bdd (same as array_n(order) */ + } bdd; /* stuff relevant to bdd's and algorithms on bdd's */ + bdd_external_hooks hooks; + struct { + void (*daemon)(); /* used for callback when memory limit exceeded */ + unsigned int limit; /* upper bound on memory allocated by the manager; in megabytes */ + } memory; +#if defined(BDD_DEBUG) /* { */ + struct { + struct { +#if defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + unsigned int uniqueId; /* to assign each bdd_node a unique id */ +#endif /* } */ +#if defined(BDD_DEBUG_AGE) || defined(BDD_DEBUG_LIFESPAN) /* { */ + unsigned int age; /* the age is determined by number of garbage collections */ +#endif /* } */ + int dummy; /* just in case nothing else is defined ... */ + } gc; /* debugging of the garbage collector */ +#if defined(BDD_DEBUG_LIFESPAN) /* { */ + struct { + FILE *trace; /* where to write out the lifespan trace */ + } lifespan; +#endif /* } */ +#if defined(BDD_FLIGHT_RECORDER) /* { */ + struct { + FILE *log; /* where to write out the log */ + } flight_recorder; +#endif /* } */ + } debug; /* all this stuff goes away when not debugging */ +#endif /* } */ +}; + +/* + * Various bdd_manager initialization values + */ +#define BDD_HASHTABLE_INITIAL_SIZE 113 /* the cache must be the same size, must match an entry in bdd_get_next_hash_prime */ +#define BDD_CACHE_INITIAL_SIZE 113 + +#define BDD_CACHE_GROW_FACTOR 2.0 /* grow the caches by this factor */ + +#define BDD_HASHTABLE_MAXCHAINLEN 4 /* max number bdd_nodes per chain (before a rehash) */ +#define BDD_HASHTABLE_GROW_FACTOR 2.0 /* grow the hashtable by this factor */ + +/* + * Node allocation and management + * + * This includes cache management and external pointer management. + * The internal pointer management declarations were given above + * with the structure declarations for bdd_safeframe and bdd_safenode. + */ +extern bdd_node *bdd_find_or_add(); +extern bdd_node *bdd_new_node(); +extern void bdd_garbage_collect(); +extern void bdd_resize_hashtable(); + +/* + * return or die - debugging various things + */ +extern void bdd_assert_frames_correct(); +extern void bdd_assert_heap_correct(); + +extern void bdd_dump_external_pointers(); +extern void bdd_dump_node_ages(); +extern void bdd_dump_manager_stats(); + +/* + * The ITE functions knowing about ITE identities + * + * THESE ARE INTERNAL FUNCTIONS. Call them from outside + * of the bdd package, and I will personally hunt you down. + * + * They have so many underscores in them because if they didn't + * they would be spelled much like exported functions of the same + * name: bdd_ite(). We don't want people inadvertently calling + * internal routines just because they are named the same as an + * exported routine. This is a matter of robustness rather than style. + */ +extern bdd_node *bdd__ITE_(); +extern bdd_constant_status bdd__ITE_constant(); + +/* + * Generally useful + */ +extern void bdd_get_branches(); +extern array_t *bdd_get_sorted_varids(); +extern float bdd_get_percentage(); +extern unsigned int bdd_get_next_hash_prime(); +extern boolean bdd_will_exceed_mem_limit(); + +/* + * Quantification function. + */ +typedef enum {BDD_EXISTS, BDD_FORALL} bdd_quantify_type_t; +extern bdd_node *bdd_internal_quantify(); /* used by bdd_cproject also */ + +/* + * BDD minimization related functions. + */ +EXTERN void bdd_match_result ARGS((bdd_manager *, bdd_min_match_type_t, boolean, + bdd_node *, bdd_node *, bdd_node *, bdd_node *, bdd_node **, bdd_node **)); +EXTERN boolean bdd_is_match ARGS((bdd_manager *, bdd_min_match_type_t, boolean, + bdd_node *, bdd_node *, bdd_node *, bdd_node *)); + +/* + * helper funtions common to bdd__ITE_() and bdd__ITE_constant() + */ +extern void bdd_ite_quick_cofactor(); +extern void bdd_ite_var_to_const(); +extern void bdd_ite_canonicalize_ite_inputs(); + + + diff --git a/sis/bdd_ucb/bdd_ite.c b/sis/bdd_ucb/bdd_ite.c new file mode 100644 index 0000000..3f9254f --- /dev/null +++ b/sis/bdd_ucb/bdd_ite.c @@ -0,0 +1,120 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_ite.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_ite.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd_ite.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 01:46:00 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. + * + * Revision 1.1 1992/07/29 00:26:48 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:27 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:31 shiple + * Initial revision + * + * + */ + +/* + * bdd_ite - returns the ite of three bdd's + * + * ITE Identity: ITE(F, G, H) = ITE(F, G, H) <---- no kidding + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_ite(f, g, h, f_phase, g_phase, h_phase) +bdd_t *f; +bdd_t *g; +bdd_t *h; +boolean f_phase; /* if ! f_phase then negate f */ +boolean g_phase; /* if ! g_phase then negate g */ +boolean h_phase; /* if ! h_phase then negate g */ +{ + bdd_safeframe frame; + bdd_safenode real_f, real_g, real_h, ret; + bdd_t *i; + bdd_manager *manager; + + if (f == NIL(bdd_t) || g == NIL(bdd_t) || h == NIL(bdd_t)) + fail("bdd_ite: invalid BDD"); + + BDD_ASSERT( ! f->free ); + BDD_ASSERT( ! g->free ); + BDD_ASSERT( ! h->free ); + + if (f->bdd != g->bdd || g->bdd != h->bdd) + fail("bdd_ite: different bdd managers"); + + manager = f->bdd; /* either this or g->bdd or h->bdd will do */ + + /* + * After the input is checked for correctness, start the safe frame + * f and g are already external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, real_f); + bdd_safenode_declare(manager, real_g); + bdd_safenode_declare(manager, real_h); + bdd_safenode_declare(manager, ret); + + real_f.node = f_phase ? f->node: BDD_NOT(f->node); + real_g.node = g_phase ? g->node: BDD_NOT(g->node); + real_h.node = h_phase ? h->node: BDD_NOT(h->node); + + ret.node = bdd__ITE_(manager, real_f.node, real_g.node, real_h.node); + + /* + * End the safe frame and return the result + */ + bdd_safeframe_end(manager); + i = bdd_make_external_pointer(manager, ret.node, "bdd_ite"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_ite(%d, %d, %d, %d, %d, %d)\n", + bdd_index_of_external_pointer(i), + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(g), + bdd_index_of_external_pointer(h), + f_phase, g_phase, h_phase); +#endif /* } */ + + return (i); +} diff --git a/sis/bdd_ucb/bdd_iter.c b/sis/bdd_ucb/bdd_iter.c new file mode 100644 index 0000000..1d8a343 --- /dev/null +++ b/sis/bdd_ucb/bdd_iter.c @@ -0,0 +1,499 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_iter.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_iter.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd_iter.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.4 1993/05/04 15:30:57 sis + * BDD package updates. Tom Shiple 5/4/93. + * + * Revision 1.3 1993/05/03 20:32:57 shiple + * Changed occurences of "refany *" to "refany". Removed unused variable + * "literal" in bdd_first_cube. + * + * Revision 1.2 1992/09/19 01:46:31 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. + * + * Revision 1.1 1992/07/29 00:26:49 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:28 sis + * Initial revision + * + * Revision 1.2 91/04/29 16:32:43 shiple + * bug fix in pop_cube_stack to reset literals to 2; added comments in code + * + * Revision 1.1 91/03/27 14:35:32 shiple + * Initial revision + * + * + */ + +static void pop_cube_stack(); +static void pop_node_stack(); +static void push_cube_stack(); +static void push_node_stack(); + +/* + * Defines an iterator on the onset of a BDD. Two routines are + * provided: bdd_first_cube, which extracts one cube from a BDD and + * returns a bdd_gen structure containing the information necessary to + * continue the enumeration; and bdd_next_cube, which returns 1 if another cube was + * found, and 0 otherwise. A cube is represented + * as an array of bdd_literal (which are integers in {0, 1, 2}), where 0 represents + * negated literal, 1 for literal, and 2 for don't care. Returns a disjoint + * cover. A third routine is there to clean up. + */ + +/* + * bdd_first_cube - return the first cube of the function. + * A generator is returned that will iterate over the rest. + * Return the generator. + */ +bdd_gen * +bdd_first_cube(fn, cube) +bdd_t *fn; +array_t **cube; /* of bdd_literal */ +{ + bdd_manager *manager; + bdd_gen *gen; + int i; + + if (fn == NIL(bdd_t)) + fail("bdd_first_cube: invalid BDD"); + + BDD_ASSERT( ! fn->free ); + + manager = fn->bdd; + + /* + * Allocate a new generator structure and fill it in; the stack and the + * cube will be used, but the visited table and the node will not be used. + */ + gen = ALLOC(bdd_gen, 1); + if (gen == NIL(bdd_gen)) + (void) bdd_memfail(manager, "bdd_first_cube"); + + /* + * first - init all the members to a rational value for cube iteration + */ + gen->manager = manager; + gen->status = bdd_EMPTY; + gen->type = bdd_gen_cubes; + gen->gen.cubes.cube = NIL(array_t); + gen->stack.sp = 0; + gen->stack.stack = NIL(bdd_node *); + gen->node = NIL(bdd_node); + + gen->gen.cubes.cube = array_alloc(bdd_literal, manager->bdd.nvariables); + if (gen->gen.cubes.cube == NIL(array_t)) + (void) bdd_memfail(manager, "bdd_first_cube"); + + /* + * Initialize each literal to 2 (don't care). + */ + for (i = manager->bdd.nvariables; --i >= 0; ) { + (void) array_insert(bdd_literal, gen->gen.cubes.cube, i, 2); + } + + /* + * The stack size will never exceed the number of variables in the BDD, since + * the longest possible path from root to constant 1 is the number of variables + * in the BDD. + */ + gen->stack.sp = 0; + gen->stack.stack = ALLOC(bdd_node *, manager->bdd.nvariables); + if (gen->stack.stack == NIL(bdd_node *)) + (void) bdd_memfail(fn->bdd, "bdd_first_cube"); + + if (fn->node == BDD_ZERO(gen->manager)) { + /* + * All done, for this was but the zero constant ... + * We are enumerating the onset, (which is vacuous). + * gen->status initialized to bdd_EMPTY above, so this + * appears to be redundant. + */ + gen->status = bdd_EMPTY; + } else { + /* + * Get to work enumerating the onset. Get the first cube. Note that + * if fn is just the constant 1, push_cube_stack will properly handle this. + */ + gen->status = bdd_NONEMPTY; + (void) push_cube_stack(fn->node, gen); + } + + /* + * There is one more generator open on the manager now. + */ + gen->manager->heap.gc.status.open_generators++; + + *cube = gen->gen.cubes.cube; + return (gen); +} + +/* + * bdd_next_cube - get the next cube on the generator. + * Returns {TRUE, FALSE} when {more, no more}. + */ +boolean +bdd_next_cube(gen, cube) +bdd_gen *gen; +array_t **cube; /* of bdd_literal */ +{ + + (void) pop_cube_stack(gen); + if (gen->status == bdd_EMPTY) { + return (FALSE); + } + *cube = gen->gen.cubes.cube; + return (TRUE); +} + +/* + * bdd_first_node - enumerates all bdd_node * in fn. + * Return the generator. + */ +bdd_gen * +bdd_first_node(fn, node) +bdd_t *fn; +bdd_node **node; /* return */ +{ + bdd_manager *manager; + bdd_gen *gen; + + if (fn == NIL(bdd_t)) + fail("bdd_first_node: invalid BDD"); + + BDD_ASSERT(! fn->free ); + + manager = fn->bdd; + + /* + * Allocate a new generator structure and fill it in; the + * visited table will be used, as will the stack, but the + * cube array will not be used. + */ + gen = ALLOC(bdd_gen, 1); + if (gen == NIL(bdd_gen)) + (void) bdd_memfail(manager, "bdd_first_node"); + + /* + * first - init all the members to a rational value for node iteration. + */ + gen->manager = manager; + gen->status = bdd_NONEMPTY; + gen->type = bdd_gen_nodes; + gen->gen.nodes.visited = NIL(st_table); + gen->stack.sp = 0; + gen->stack.stack = NIL(bdd_node *); + gen->node = NIL(bdd_node); + + /* + * Set up the hash table for visited nodes. Every time we visit a node, + * we insert it into the table. + */ + gen->gen.nodes.visited = st_init_table(st_ptrcmp, st_ptrhash); + if (gen->gen.nodes.visited == NIL(st_table)) + (void) bdd_memfail(manager, "bdd_first_node"); + + /* + * The stack size will never exceed the number of variables in the BDD, since + * the longest possible path from root to constant 1 is the number of variables + * in the BDD. + */ + gen->stack.sp = 0; + gen->stack.stack = ALLOC(bdd_node *, manager->bdd.nvariables); + if (gen->stack.stack == NIL(bdd_node *)) + (void) bdd_memfail(manager, "bdd_first_node"); + + /* + * Get the first node. + */ + (void) push_node_stack(fn->node, gen); + gen->status = bdd_NONEMPTY; + + /* + * There is one more generator open on the manager now. + */ + gen->manager->heap.gc.status.open_generators++; + + *node = gen->node; /* return the node */ + return (gen); /* and the new generator */ +} + +/* + * bdd_next_node - get the next node in the BDD. + * Return {TRUE, FALSE} when {more, no more}. + */ +boolean +bdd_next_node(gen, node) +bdd_gen *gen; +bdd_node **node; /* return */ +{ + (void) pop_node_stack(gen); + if (gen->status == bdd_EMPTY) + return (FALSE); + + *node = gen->node; + return (TRUE); +} + +/* + * bdd_gen_free - frees up the space used by the generator. + * Return an int so that it is easier to fit in a foreach macro. + * Return 0 (to make it easy to put in expressions). + */ +int +bdd_gen_free(gen) +bdd_gen *gen; +{ + gen->manager->heap.gc.status.open_generators--; + + switch (gen->type) { + case bdd_gen_cubes: + (void) array_free(gen->gen.cubes.cube); + gen->gen.cubes.cube = NIL(array_t); + break; + case bdd_gen_nodes: + (void) st_free_table(gen->gen.nodes.visited); + gen->gen.nodes.visited = NIL(st_table); + break; + } + + /* + * These are always allocated. + */ + FREE(gen->stack.stack); + FREE(gen); + + return (0); /* make it return some sort of an int */ +} + +/* + * INTERNAL INTERFACE + * + * Invariants: + * + * gen->stack.stack contains nodes that remain to be explored. + * + * For a cube generator, + * gen->gen.cubes.cube reflects the choices made to reach node at top of the stack. + * For a node generator, + * gen->gen.nodes.visited reflects the nodes already visited in the BDD dag. + */ + +/* + * push_cube_stack - push a cube onto the stack to visit. + * Return nothing, just do it. + * + * The BDD is traversed using depth-first search, with the ELSE branch + * searched before the THEN branch. + * + * Caution: If you are creating new BDD's while iterating through the + * cubes, and a garbage collection happens to be performed during this + * process, then the BDD generator will get lost and an error will result. + * + */ +static void +push_cube_stack(f, gen) +bdd_node *f; +bdd_gen *gen; +{ + bdd_variableId topf; + bdd_node *f0, *f1; + + if (f == BDD_ONE(gen->manager)) + return; + + topf = BDD_REGULAR(f)->id; + + /* + * Note that bdd_get_branches automatically takes care of inverted pointers. + * For example, if f is a complemented pointer, then bdd_get_branches(f, &f1, &f0) + * will automatically set f1 to be NOT(BDD_REGULAR(f)->T) and f0 to be + * NOT(BDD_REGULAR(f)->E). + */ + (void) bdd_get_branches(f, &f1, &f0); + if (f1 == BDD_ZERO(gen->manager)) { + /* + * No choice: take the 0 branch. Since there is only one branch to + * explore from f, there is no need to push f onto the stack, because + * after exploring this branch we are done with f. A consequence of + * this is that there will be no f to pop either. Same goes for the + * next case. + */ + (void) array_insert(bdd_literal, gen->gen.cubes.cube, topf, 0); + (void) push_cube_stack(f0, gen); + } else if (f0 == BDD_ZERO(gen->manager)) { + /* + * No choice: take the 1 branch + */ + (void) array_insert(bdd_literal, gen->gen.cubes.cube, topf, 1); + (void) push_cube_stack(f1, gen); + } else { + /* + * In this case, we must explore both branches of f. We always choose + * to explore the 0 branch first. We must push f on the stack, so that + * we can later pop it and explore its 1 branch. + */ + gen->stack.stack[gen->stack.sp++] = f; + (void) array_insert(bdd_literal, gen->gen.cubes.cube, topf, 0); + (void) push_cube_stack(f0, gen); + } +} + +static void +pop_cube_stack(gen) +bdd_gen *gen; +{ + bdd_variableId topf; + bdd_node *branch_f; + bdd_node *f0, *f1; + int i; + + if (gen->stack.sp == 0) { + /* + * Stack is empty. Have already explored both the 0 and 1 branches of + * the root of the BDD. + */ + gen->status = bdd_EMPTY; + } else { + /* + * Explore the 1 branch of the node at the top of the stack (since it is + * on the stack, this means we have already explored the 0 branch). We + * permanently pop the top node, since there are no more edges left to + * explore. + */ + branch_f = gen->stack.stack[--gen->stack.sp]; + topf = BDD_REGULAR(branch_f)->id; + (void) bdd_get_branches(branch_f, &f1, &f0); + (void) array_insert(bdd_literal, gen->gen.cubes.cube, topf, 1); + + /* + * We must set the variables with variables ids greater than topf, + * back to 2 (don't care). This is because these variables are not + * on the current path, and thus there values are don't care. + */ + for (i=topf+1; igen.cubes.cube); i++) { + array_insert(bdd_literal, gen->gen.cubes.cube, i, 2); + } + (void) push_cube_stack(f1, gen); + } +} + +/* + * push_node_stack - push a node onto the stack. + * + * The same as push_cube_stack but for enumerating nodes instead of cubes. + * The BDD is traversed using depth-first search, with the ELSE branch searched + * before the THEN branch, and a node returned only after its children have been + * returned. Note that the returned bdd_node pointer has the complement + * bit zeroed out. + * + * Caution: If you are creating new BDD's while iterating through the + * nodes, and a garbage collection happens to be performed during this + * process, then the BDD generator will get lost and an error will result. + * + * Return nothing, just do it. + */ +static void +push_node_stack(f, gen) +bdd_node *f; +bdd_gen *gen; +{ + bdd_node *f0, *f1; + + if (st_lookup(gen->gen.nodes.visited, (refany) BDD_REGULAR(f), NIL(refany))) { + /* + * Already been visited. + */ + return; + } + + if (f == BDD_ONE(gen->manager) || f == BDD_ZERO(gen->manager)) { + /* + * If f is the constant node and it has not been visited yet, then put it in the visited table + * and set the gen->node pointer. There is no need to put it in the stack because + * the constant node does not have any branches. + */ + (void) st_insert(gen->gen.nodes.visited, (refany) BDD_REGULAR(f), NIL(any)); + gen->node = BDD_REGULAR(f); + } else { + /* + * f has not been marked as visited. We don't know yet if any of its branches remain to be explored. + * First get its branches. Note that bdd_get_branches properly handles inverted pointers. + */ + (void) bdd_get_branches(f, &f1, &f0); + if (! st_lookup(gen->gen.nodes.visited, (refany) BDD_REGULAR(f0), NIL(refany))) { + /* + * The 0 child has not been visited, so explore the 0 branch. First push f on + * the stack. + */ + gen->stack.stack[gen->stack.sp++] = f; + (void) push_node_stack(f0, gen); + } else if (! st_lookup(gen->gen.nodes.visited, (refany) BDD_REGULAR(f1), NIL(refany))) { + /* + * The 0 child has been visited, but the 1 child has not been visited, so + * explore the 1 branch. First push f on the stack. + */ + gen->stack.stack[gen->stack.sp++] = f; + (void) push_node_stack(f1, gen); + } else { + /* + * Both the 0 and 1 children have been visited. Thus we are done exploring from f. + * Mark f as visited (put it in the visited table), and set the gen->node pointer. + */ + (void) st_insert(gen->gen.nodes.visited, (refany) BDD_REGULAR(f), NIL(any)); + gen->node = BDD_REGULAR(f); + } + } +} + +static void +pop_node_stack(gen) +bdd_gen *gen; +{ + bdd_node *branch_f; + + if (gen->stack.sp == 0) { + gen->status = bdd_EMPTY; + } else { + branch_f = gen->stack.stack[--gen->stack.sp]; + (void) push_node_stack(branch_f, gen); + } +} + + + + + + + diff --git a/sis/bdd_ucb/bdd_min_sibl.c b/sis/bdd_ucb/bdd_min_sibl.c new file mode 100644 index 0000000..838ad94 --- /dev/null +++ b/sis/bdd_ucb/bdd_min_sibl.c @@ -0,0 +1,315 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_min_sibl.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: bdd_min_sibl.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.1 1993/07/27 20:14:50 sis + * Initial revision + * + * Revision 1.1 1993/07/27 19:30:53 shiple + * Initial revision + * + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" +#include "bdd.h" +#include "bdd_int.h" + + +static bdd_node *min_sibling(); + +/* + * bdd_minimize_with_params - perform minimization on the incompletely specified + * function [f,c] using match_type in {BDD_MIN_TSM, BDD_MIN_OSM, BDD_MIN_OSDM}. + * The compl flag indicates whether the complement of one child should be matched + * to the other child. When the no_new_vars flag is TRUE, new variables will not + * be introduced into f. + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_minimize_with_params(f, c, match_type, compl, no_new_vars, return_min) +bdd_t *f; +bdd_t *c; +bdd_min_match_type_t match_type; +boolean compl; +boolean no_new_vars; +boolean return_min; +{ + bdd_safeframe frame; + bdd_safenode ret; + bdd_manager *manager; + bdd_t *h; + int size_h, size_f; + + if (f == NIL(bdd_t) || c == NIL(bdd_t)) { + fail("bdd_minimize_with_params: invalid BDD"); + } + + BDD_ASSERT( ! f->free ); + BDD_ASSERT( ! c->free ); + + if (f->bdd != c->bdd) { + fail("bdd_minimize_with_params: different bdd managers"); + } + + manager = f->bdd; /* either this or c->bdd will do */ + + /* + * Start the safe frame now that we know the input is correct. + * f and c are external pointers so they need not be protected. + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, ret); + + bdd_adhoccache_init(manager); + + ret.node = min_sibling(manager, f->node, c->node, match_type, compl, no_new_vars); + + /* + * Free the cache, end the safe frame and return the (safe) result + */ + bdd_adhoccache_uninit(manager); + h = bdd_make_external_pointer(manager, ret.node, "bdd_minimize_with_params"); + bdd_safeframe_end(manager); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_minimize_with_params(%d, %d)\n", + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(c)); +#endif /* } */ + + /* + * If return_min is TRUE and if h is larger than f, then free h, and return a copy of f. + */ + if (return_min == TRUE) { + size_h = bdd_size(h); + size_f = bdd_size(f); + if (size_h > size_f) { + bdd_free(h); + h = bdd_dup(f); + } + } + + return (h); +} + +/* + * bdd_minimize - call bdd_minimize_with_params with default parameters. + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_minimize(f, c) +bdd_t *f; +bdd_t *c; +{ + return (bdd_minimize_with_params(f, c, BDD_MIN_OSM, TRUE, TRUE, TRUE)); +} + +/* + * bdd_between - return a small BDD between f_min and f_max. + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_between(f_min, f_max) +bdd_t *f_min; +bdd_t *f_max; +{ + bdd_t *temp, *ret; + + temp = bdd_or(f_min, f_max, 1, 0); + ret = bdd_minimize(f_min, temp); + bdd_free(temp); + return ret; +} + +/* + * min_sibling - recursively perform the min_siblinging + * + * return the result of the reorganization + */ +static bdd_node * +min_sibling(mgr, f, c, mtype, compl, no_new_vars) +bdd_manager *mgr; +bdd_node *f; +bdd_node *c; +bdd_min_match_type_t mtype; +boolean compl; +boolean no_new_vars; +{ + bdd_safeframe frame; + bdd_safenode safe_f, safe_c, + ret, + f_T, f_E, + c_T, c_E, + var, co_T, co_E, + new_f, new_c, sum; + bdd_variableId fId, cId, topId; + boolean match_made; + + mgr->heap.stats.adhoc_ops.calls++; + + if (BDD_IS_CONSTANT(mgr, f)) { + /* + * f is either zero or one, so just return f. + */ + mgr->heap.stats.adhoc_ops.returns.trivial++; + return (f); + } + + if (c == BDD_ONE(mgr)) { + /* + * The care function is the tautology, so just return f. + */ + mgr->heap.stats.adhoc_ops.returns.trivial++; + return (f); + } + + assert(c != BDD_ZERO(mgr)); /* operation is undefined for don't care everywhere */ + + /* + * Check if we have already computed the result for f,c. + */ + if (bdd_adhoccache_lookup(mgr, f, c, /* v */ 0, &ret.node)) { + /* + * The answer was already in the cache, so just return it. + */ + mgr->heap.stats.adhoc_ops.returns.cached++; + return (ret.node); + } + + /* + * Start the safeframe. + */ + bdd_safeframe_start(mgr, frame); + bdd_safenode_link(mgr, safe_f, f); + bdd_safenode_link(mgr, safe_c, c); + bdd_safenode_declare(mgr, ret); + bdd_safenode_declare(mgr, f_T); + bdd_safenode_declare(mgr, f_E); + bdd_safenode_declare(mgr, c_T); + bdd_safenode_declare(mgr, c_E); + bdd_safenode_declare(mgr, var); + bdd_safenode_declare(mgr, co_T); + bdd_safenode_declare(mgr, co_E); + bdd_safenode_declare(mgr, new_f); + bdd_safenode_declare(mgr, new_c); + bdd_safenode_declare(mgr, sum); + + /* + * Dereference the id of the top node, and the then and else branches, for each of f and c. + */ + fId = BDD_REGULAR(f)->id; + cId = BDD_REGULAR(c)->id; + bdd_get_branches(f, &f_T.node, &f_E.node); + bdd_get_branches(c, &c_T.node, &c_E.node); + + /* + * Based on topId, determine the then and else branches to use for the recursion, for f and c. + */ + topId = MIN(fId, cId); + if (topId < cId) { + /* c is independent of fId; thus, the two cofactors of c by fId are the same */ + c_T.node = c; + c_E.node = c; + } + if (topId < fId) { + /* f is independent of cId; thus, the two cofactors of f by cId are the same */ + f_T.node = f; + f_E.node = f; + } + + /* + * Try to match functions in a predetermined order. If a match is made, then skip the + * rest of the match attempts. Using multiple IFs and the match_made flag allows for easier + * to understand code. + */ + match_made = FALSE; + if ((fId > cId) && (no_new_vars == TRUE)) { + /* + * f is independent of cId; keep it that way + */ + match_made = TRUE; + sum.node = bdd__ITE_(mgr, c_T.node, BDD_ONE(mgr), c_E.node); + ret.node = min_sibling(mgr, f, sum.node, mtype, compl, no_new_vars); + } + + if (match_made == FALSE) { + if (bdd_min_is_match(mgr, mtype, FALSE, f_T.node, c_T.node, f_E.node, c_E.node)) { + /* + * Match T to E. + */ + match_made = TRUE; + bdd_min_match_result(mgr, mtype, FALSE, f_T.node, c_T.node, f_E.node, c_E.node, &new_f.node, &new_c.node); + ret.node = min_sibling(mgr, new_f.node, new_c.node, mtype, compl, no_new_vars); + } + } + + if ((match_made == FALSE) && (mtype != BDD_MIN_TSM)) { /* BDD_MIN_TSM is symmetric */ + if (bdd_min_is_match(mgr, mtype, FALSE, f_E.node, c_E.node, f_T.node, c_T.node)) { + /* + * Match E to T. + */ + match_made = TRUE; + bdd_min_match_result(mgr, mtype, FALSE, f_E.node, c_E.node, f_T.node, c_T.node, &new_f.node, &new_c.node); + ret.node = min_sibling(mgr, new_f.node, new_c.node, mtype, compl, no_new_vars); + } + } + + if ((match_made == FALSE) && (compl == TRUE)) { + if (bdd_min_is_match(mgr, mtype, TRUE, f_T.node, c_T.node, f_E.node, c_E.node)) { + /* + * Match T to complement of E. + */ + match_made = TRUE; + bdd_min_match_result(mgr, mtype, TRUE, f_T.node, c_T.node, f_E.node, c_E.node, &new_f.node, &new_c.node); + co_E.node = min_sibling(mgr, new_f.node, new_c.node, mtype, compl, no_new_vars); + var.node = bdd_find_or_add(mgr, topId, BDD_ONE(mgr), BDD_ZERO(mgr)); + ret.node = bdd__ITE_(mgr, var.node, BDD_NOT(co_E.node), co_E.node); + } + } + + if ((match_made == FALSE) && (compl == TRUE) && (mtype != BDD_MIN_TSM)) { + if (bdd_min_is_match(mgr, mtype, TRUE, f_E.node, c_E.node, f_T.node, c_T.node)) { + /* + * Match E to complement of T. + */ + match_made = TRUE; + bdd_min_match_result(mgr, mtype, TRUE, f_E.node, c_E.node, f_T.node, c_T.node, &new_f.node, &new_c.node); + co_T.node = min_sibling(mgr, new_f.node, new_c.node, mtype, compl, no_new_vars); + var.node = bdd_find_or_add(mgr, topId, BDD_ONE(mgr), BDD_ZERO(mgr)); + ret.node = bdd__ITE_(mgr, var.node, co_T.node, BDD_NOT(co_T.node)); + } + } + + if (match_made == FALSE) { + /* + * No match can be made. Compute ITE(topId, min_sibling(f_T, c_T), min_sibling(f_E, c_E)). + */ + co_T.node = min_sibling(mgr, f_T.node, c_T.node, mtype, compl, no_new_vars); + co_E.node = min_sibling(mgr, f_E.node, c_E.node, mtype, compl, no_new_vars); + var.node = bdd_find_or_add(mgr, topId, BDD_ONE(mgr), BDD_ZERO(mgr)); + ret.node = bdd__ITE_(mgr, var.node, co_T.node, co_E.node); + } + + /* + * Insert the result, kill the safeframe, and return. + */ + bdd_adhoccache_insert(mgr, f, c, /* v */ 0, ret.node); + mgr->heap.stats.adhoc_ops.returns.full++; + + bdd_safeframe_end(mgr); + return (ret.node); +} diff --git a/sis/bdd_ucb/bdd_min_util.c b/sis/bdd_ucb/bdd_min_util.c new file mode 100644 index 0000000..694c9bd --- /dev/null +++ b/sis/bdd_ucb/bdd_min_util.c @@ -0,0 +1,199 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_min_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: bdd_min_util.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.1 1993/07/27 20:14:50 sis + * Initial revision + * + * Revision 1.1 1993/07/27 19:31:15 shiple + * Initial revision + * + * + */ +#include "util.h" +#include "array.h" +#include "st.h" +#include "bdd.h" +#include "bdd_int.h" + +/* + * determine if [f1,c1] matches [f2,c2] under the specified match type + * in {BDD_MIN_TSM, BDD_MIN_OSM, BDD_MIN_OSDM}. + * NOTE WELL: We are not calling any routines inside this function which + * would use the adhoc cache; doing so would interfere with the current use + * of the adhoc cache. + */ +boolean +bdd_min_is_match(manager, match_type, compl, f1, c1, f2, c2) +bdd_manager *manager; +bdd_min_match_type_t match_type; +boolean compl; +bdd_node *f1; +bdd_node *c1; +bdd_node *f2; +bdd_node *c2; +{ + boolean ret, temp1, temp2; + bdd_safeframe frame; + bdd_safenode safe_f1, safe_c1, safe_f2, safe_c2, diff, rhs; + + /* + * Set up the safeframe. + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_link(manager, safe_f1, f1); + bdd_safenode_link(manager, safe_c1, c1); + bdd_safenode_link(manager, safe_f2, f2); + bdd_safenode_link(manager, safe_c2, c2); + bdd_safenode_declare(manager, diff); + bdd_safenode_declare(manager, rhs); + + /* + * Perform the appropriate test, depending on the match_type and complement flag. + */ + if (match_type == BDD_MIN_OSDM) { + ret = (c1 == BDD_ZERO(manager)); + } else { + if (compl == FALSE) { + diff.node = bdd__ITE_(manager, f1, BDD_NOT(f2), f2); /* f1 XOR f2 */ + } else { /* compl == TRUE i.e. try to match f1 to complement of f2 */ + diff.node = bdd__ITE_(manager, f1, f2, BDD_NOT(f2)); /* f1 XNOR f2 */ + } + + if (match_type == BDD_MIN_OSM) { + rhs.node = BDD_NOT(c1); + temp1 = (bdd__ITE_constant(manager, diff.node, rhs.node, BDD_ONE(manager)) == bdd_constant_one) + ? TRUE : FALSE; /* diff => rhs */ + temp2 = (bdd__ITE_constant(manager, c1, c2, BDD_ONE(manager)) == bdd_constant_one) + ? TRUE : FALSE; /* c1 => c2, which is equiv to !c1 <= !c2 */ + ret = temp1 && temp2; + } else if (match_type == BDD_MIN_TSM) { + rhs.node = bdd__ITE_(manager, c1, BDD_NOT(c2), BDD_ONE(manager)); /* !c1 + !c2 */ + ret = (bdd__ITE_constant(manager, diff.node, rhs.node, BDD_ONE(manager)) == bdd_constant_one) + ? TRUE : FALSE; /* diff => rhs */ + } else { + fail("HEUR_FAIL, bdd_min_is_match: illegal match type"); + } + } + + /* + * Kill the safeframe and return. + */ + bdd_safeframe_end(manager); + return (ret); +} + + +/* + * return the result of matching [f1,c1] to [f2,c2] using match_type in + * {BDD_MIN_TSM, BDD_MIN_OSM, BDD_MIN_OSDM}. + */ +void +bdd_min_match_result(manager, match_type, compl, f1, c1, f2, c2, new_f, new_c) +bdd_manager *manager; +bdd_min_match_type_t match_type; +boolean compl; +bdd_node *f1; +bdd_node *c1; +bdd_node *f2; +bdd_node *c2; +bdd_node **new_f; /* return */ +bdd_node **new_c; /* return */ +{ + bdd_safeframe frame; + bdd_safenode safe_f1, safe_c1, safe_f2, safe_c2, temp1, temp2; + + /* + * Set up the safeframe. + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_link(manager, safe_f1, f1); + bdd_safenode_link(manager, safe_c1, c1); + bdd_safenode_link(manager, safe_f2, f2); + bdd_safenode_link(manager, safe_c2, c2); + bdd_safenode_declare(manager, temp1); + bdd_safenode_declare(manager, temp2); + + /* + * Based on the matching type and complement flag, compute the new f and c. + */ + if ((match_type == BDD_MIN_OSM) || (match_type == BDD_MIN_OSDM)) { + *new_f = f2; + *new_c = c2; + } else if (match_type == BDD_MIN_TSM) { + if (compl == FALSE) { + temp1.node = bdd__ITE_(manager, f1, c1, BDD_ZERO(manager)); /* f1 * c1 */ + } else { /* compl == TRUE i.e. match f1 to complement of f2 */ + temp1.node = bdd__ITE_(manager, BDD_NOT(f1), c1, BDD_ZERO(manager)); /* !f1 * c1 */ + } + + temp2.node = bdd__ITE_(manager, f2, c2, BDD_ZERO(manager)); /* f2 * c2 */ + *new_f = bdd__ITE_(manager, temp1.node, BDD_ONE(manager), temp2.node); /* temp1 + temp2 */ + *new_c = bdd__ITE_(manager, c1, BDD_ONE(manager), c2); /* c1 + c2 */ + } else { + fail("HEUR_FAIL, bdd_min_match_result: illegal match type"); + } + + /* + * Kill the safeframe and return. + */ + bdd_safeframe_end(manager); + return; +} + +/* + * Recursively determine if f is a cube. f is a cube if there is a single + * path to the constant one. + */ +static boolean +is_cube(manager, f) +bdd_manager *manager; +bdd_node *f; +{ + bdd_node *f0, *f1; + + BDD_ASSERT(f != BDD_ZERO(manager)); + + if (f == BDD_ONE(manager)) { + return TRUE; + } + + bdd_get_branches(f, &f1, &f0); + + /* + * Exactly one branch of f must point to ZERO to be a cube. + */ + if (f1 == BDD_ZERO(manager)) { + return (is_cube(manager, f0)); + } else if (f0 == BDD_ZERO(manager)) { + return (is_cube(manager, f1)); + } else { /* not a cube, because neither branch is zero */ + return FALSE; + } +} + +/* + * Return TRUE if f is a cube, else return FALSE. + */ +boolean +bdd_is_cube(f) +bdd_t *f; +{ + bdd_manager *manager; + + if (f == NIL(bdd_t)) { + fail("bdd_is_cube: invalid BDD"); + } + BDD_ASSERT( ! f->free ); + + manager = f->bdd; + return (is_cube(manager, f->node)); +} + diff --git a/sis/bdd_ucb/bdd_print.c b/sis/bdd_ucb/bdd_print.c new file mode 100644 index 0000000..d726190 --- /dev/null +++ b/sis/bdd_ucb/bdd_print.c @@ -0,0 +1,180 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_print.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_print.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd_print.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 02:41:07 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Fixed bug in function id_name. For case where BDD_DEBUG_UID was true, node + * pointer was not being regularized before it was dereferenced. + * + * Revision 1.1 1992/07/29 00:26:51 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:28 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:33 shiple + * Initial revision + * + * + */ + +static void print(); +static string id_name(); + +/* + * bdd_print - print a bdd + * + * return nothing, just do it. + */ +void +bdd_print(f) +bdd_t *f; +{ + bdd_manager *manager; + st_table *table; /* used to ensure that we don't print anything twice */ + int j; + + if (f == NIL(bdd_t)) + fail("bdd_print: invalid BDD"); + + BDD_ASSERT( ! f->free ); + + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + manager = f->bdd; + + for (j=0; jbdd.nvariables; j++) { + char variable_name[50]; /* actually only for mis-independent operation */ + + (void) sprintf(variable_name, "v#%d", j); + (void) fprintf(stdout, "\tindex %d is %s\n", j, variable_name); + } + + table = st_init_table(st_ptrcmp, st_ptrhash); + (void) print(f->node, manager, table); + (void) st_free_table(table); + + (void) fputc('\n', stdout); +} + + +/* + * print - bdd print recursively + * + * return nothing, just do it. + */ +static void +print(f, manager, table) +bdd_node *f; /* the node to print */ +bdd_manager *manager; +st_table *table; /* table recording what has been printed so far */ +{ + bdd_node *f_reg; + boolean T, E; + + /* + * This should never occur + */ + if (f == NIL(bdd_node)) + return; + + /* + * If we've reached a constant, then we're done + */ + f_reg = BDD_REGULAR(f); + if (f_reg == BDD_ONE(manager)) { + (void) fprintf(stdout, "ID = %d\n", f == BDD_ONE(manager) ? 1: 0); + return; + } + + /* + * If it was already printed, don't continue any further + */ + if (st_is_member(table, (refany) f_reg)) + return; + + (void) st_insert(table, (refany) f_reg, NIL(any)); + + (void) fprintf(stdout, "ID = %s\tindex = %d\t", id_name(f), f_reg->id); + + if (BDD_IS_CONSTANT(manager, f_reg->T)) { + (void) fprintf(stdout, "T = %d\t\t", f_reg->T == BDD_ONE(manager) ? 1: 0); + T = TRUE; + } else { + (void) fprintf(stdout, "T = %s\t", id_name(f_reg->T)); + T = FALSE; + } + + if (BDD_IS_CONSTANT(manager, f_reg->E)) { + (void) fprintf(stdout, "E = %d\n", f_reg->E == BDD_ONE(manager) ? 1: 0); + E = TRUE; + } else { + (void) fprintf(stdout, "E = %s\n", id_name(f_reg->E)); + E = FALSE; + } + + /* + * Recur if appropriate + */ + if ( ! E ) + (void) print(BDD_REGULAR(f_reg->E), manager, table); + if ( ! T ) + (void) print(BDD_REGULAR(f_reg->T), manager, table); +} + +static string +id_name(f) +bdd_node *f; +{ + static char buf[100]; + int uid; + bdd_node *f_reg; + + f_reg = BDD_REGULAR(f); + +#if defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + uid = f_reg->uniqueId; +#else /* } else { */ + uid = (int) f_reg / sizeof(bdd_node); +#endif /* } */ + + sprintf(buf, "%c%#x", BDD_IS_COMPLEMENT(f) ? '!' : ' ', uid); + + return (buf); +} diff --git a/sis/bdd_ucb/bdd_quantify.c b/sis/bdd_ucb/bdd_quantify.c new file mode 100644 index 0000000..d2d66b3 --- /dev/null +++ b/sis/bdd_ucb/bdd_quantify.c @@ -0,0 +1,202 @@ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +static bdd_t *bdd_quantify(); + +/* + * bdd_smooth - the smoothing function + */ +bdd_t * +bdd_smooth(f, var_array) +bdd_t *f; +array_t *var_array; /* of bdd_t* */ +{ + return bdd_quantify(f, var_array, BDD_EXISTS); +} + +/* + * bdd_consensus - the consensus function + */ +bdd_t * +bdd_consensus(f, var_array) +bdd_t *f; +array_t *var_array; /* of bdd_t* */ +{ + return bdd_quantify(f, var_array, BDD_FORALL); +} + +/* + * bdd_quantify - the quantifying function + * + * return the new bdd (external pointer) + */ +static bdd_t * +bdd_quantify(f, var_array, quant_type) +bdd_t *f; +array_t *var_array; /* of bdd_t* */ +bdd_quantify_type_t quant_type; +{ + bdd_manager *manager; + bdd_safeframe frame; + bdd_safenode real_f, ret; + array_t *vars; + bdd_t *h; + + if (f == NIL(bdd_t)) { + fail ("bdd_quantify: invalid BDD"); + } + + BDD_ASSERT( ! f->free ); + + manager = f->bdd; + + /* + * After the input is checked for correctness, start the safe frame + * f and g are already external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, real_f); + bdd_safenode_declare(manager, ret); + + real_f.node = f->node; + + vars = bdd_get_sorted_varids(var_array); + (void) bdd_adhoccache_init(manager); + + ret.node = bdd_internal_quantify(manager, f->node, 0, vars, quant_type); + + /* + * End the safe frame and return the result + */ + (void) bdd_adhoccache_uninit(manager); + (void) array_free(vars); + bdd_safeframe_end(manager); + h = bdd_make_external_pointer(manager, ret.node, "bdd_quantify"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_%s(%d, { ", + bdd_index_of_external_pointer(h), + ((quant_type == BDD_EXISTS) ? "smooth" : "consensus"), + bdd_index_of_external_pointer(f)); + { + int i; + + for (i=0; idebug.flight_recorder.log, "%d%s", + bdd_index_of_external_pointer(v), + i+1 == array_n(var_array) ? " } )\n": ", "); + } + } +#endif /* } */ + + return h; +} + +/* + * bdd_internal_quantify - recursively perform the quantifying + * This function name is prefaced by "bdd_internal_" because other routines in the + * BDD package call this function. + * + * return the result of the reorganization + */ +bdd_node * +bdd_internal_quantify(manager, f, index, vars, quant_type) +bdd_manager *manager; +bdd_node *f; +int index; +array_t *vars; +bdd_quantify_type_t quant_type; +{ + bdd_safeframe frame; + bdd_safenode safe_f; + bdd_safenode f_T, f_E; + bdd_safenode qnt_T, qnt_E; + bdd_safenode ret, var; + bdd_variableId fId, top_varId, last_varId; + + bdd_safeframe_start(manager, frame); + bdd_safenode_link(manager, safe_f, f); + bdd_safenode_declare(manager, ret); + bdd_safenode_declare(manager, f_T); + bdd_safenode_declare(manager, f_E); + bdd_safenode_declare(manager, qnt_T); + bdd_safenode_declare(manager, qnt_E); + bdd_safenode_declare(manager, var); + + manager->heap.stats.adhoc_ops.calls++; + + if (index >= array_n(vars)) { + /* + * no more variables to quantify + */ + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager); + return f; + } + + fId = BDD_REGULAR(f)->id; + last_varId = array_fetch(int, vars, array_n(vars) - 1); + + if (fId > last_varId) { + /* + * If f's id above the last possible quantifying variable, return f. + * Also takes care of the case f == CONSTANT. + */ + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager); + return f; + } + + if (bdd_adhoccache_lookup(manager, f, NIL(bdd_node), index, &ret.node)) { + /* + * The answer was already in the cache, so just return it. + */ + manager->heap.stats.adhoc_ops.returns.cached++; + bdd_safeframe_end(manager); + return (ret.node); + } + + (void) bdd_get_branches(f, &f_T.node, &f_E.node); + + /* from now on, everything has to be protected */ + top_varId = array_fetch(int, vars, index); + if (fId > top_varId) { + ret.node = bdd_internal_quantify(manager, f, index + 1, vars, quant_type); + } else if (fId == top_varId) { + /* + * If EXISTS: quantify(f_T, vars + 1) OR quantify(f_E, vars + 1) + * If FORALL: quantify(f_T, vars + 1) AND quantify(f_E, vars + 1) + */ + qnt_T.node = bdd_internal_quantify(manager, f_T.node, index + 1, vars, quant_type); + qnt_E.node = bdd_internal_quantify(manager, f_E.node, index + 1, vars, quant_type); + if (quant_type == BDD_EXISTS) { + ret.node = bdd__ITE_(manager, qnt_T.node, BDD_ONE(manager), qnt_E.node); + } else if (quant_type == BDD_FORALL) { + ret.node = bdd__ITE_(manager, qnt_T.node, qnt_E.node, BDD_ZERO(manager)); + } else { + fail("bdd_internal_smooth: unknown quantify method"); + } + } else { /* fId < top_varId */ + /* + * ITE(fId, quantify(f_T, vars), quantify(f_E, vars)) + */ + qnt_T.node = bdd_internal_quantify(manager, f_T.node, index, vars, quant_type); + qnt_E.node = bdd_internal_quantify(manager, f_E.node, index, vars, quant_type); + var.node = bdd_find_or_add(manager, fId, BDD_ONE(manager), BDD_ZERO(manager)); + ret.node = bdd__ITE_(manager, var.node, qnt_T.node, qnt_E.node); + } + + (void) bdd_adhoccache_insert(manager, f, NIL(bdd_node), index, ret.node); + manager->heap.stats.adhoc_ops.returns.full++; + bdd_safeframe_end(manager); + return (ret.node); +} diff --git a/sis/bdd_ucb/bdd_start.c b/sis/bdd_ucb/bdd_start.c new file mode 100644 index 0000000..65cbff8 --- /dev/null +++ b/sis/bdd_ucb/bdd_start.c @@ -0,0 +1,317 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_start.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for MAXPATHLEN */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_start.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd_start.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 02:46:41 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Initialized new fields added to manager and stats data structures. Added use of bdd_mgr_init. + * Changed ITE and ITE_const caches to be arrays of pointers. Added bdd_register_daemon. + * + * Revision 1.1 1992/07/29 00:26:53 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:29 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:34 shiple + * Initial revision + * + * + */ + +/* + * bdd_set_mgr_init_dflts - initialize the input bdd_mgr_init with the default settings + */ +void +bdd_set_mgr_init_dflts(mgr_init) +bdd_mgr_init *mgr_init; +{ + mgr_init->ITE_cache.on = BDD_DFLT_ITE_ON; + mgr_init->ITE_cache.resize_at = BDD_DFLT_ITE_RESIZE_AT; + mgr_init->ITE_cache.max_size = BDD_DFLT_ITE_MAX_SIZE; + mgr_init->ITE_const_cache.on = BDD_DFLT_ITE_CONST_ON; + mgr_init->ITE_const_cache.resize_at = BDD_DFLT_ITE_CONST_RESIZE_AT; + mgr_init->ITE_const_cache.max_size = BDD_DFLT_ITE_CONST_MAX_SIZE; + mgr_init->adhoc_cache.on = BDD_DFLT_ADHOC_ON; + mgr_init->adhoc_cache.resize_at = BDD_DFLT_ADHOC_RESIZE_AT; + mgr_init->adhoc_cache.max_size = BDD_DFLT_ADHOC_MAX_SIZE; + mgr_init->garbage_collector.on = BDD_DFLT_GARB_COLLECT_ON; + mgr_init->memory.daemon = BDD_DFLT_DAEMON; + mgr_init->memory.limit = BDD_DFLT_MEMORY_LIMIT; + mgr_init->nodes.ratio = BDD_DFLT_NODE_RATIO; + mgr_init->nodes.init_blocks = BDD_DFLT_INIT_BLOCKS; +} + +/* + * bdd_start_with_params - initialize a bdd manager with the supplied parameters + * + * return the new bdd manager + */ +bdd_manager * +bdd_start_with_params(nvariables, mgr_init) +int nvariables; /* the maximum number of variables allowable in this bdd manager */ +bdd_mgr_init *mgr_init; +{ + bdd_manager *manager; + int i, h; + + manager = ALLOC(bdd_manager, 1); + if (manager == NIL(bdd_manager)) + (void) bdd_memfail(NIL(bdd_manager), "bdd_start"); + + manager->undef1 = 0; /* for debugging purposes */ + + /* + * Initialize the heap part of the bdd_manager + */ + + manager->heap.hashtable.nkeys = 0; + manager->heap.hashtable.nbuckets = BDD_HASHTABLE_INITIAL_SIZE; + manager->heap.hashtable.buckets = ALLOC(bdd_node *, manager->heap.hashtable.nbuckets); + if (manager->heap.hashtable.buckets == NIL(bdd_node *)) + (void) bdd_memfail(NIL(bdd_manager), "bdd_start"); + manager->heap.hashtable.rehash_at_nkeys = manager->heap.hashtable.nbuckets * BDD_HASHTABLE_MAXCHAINLEN; + for (i=0; iheap.hashtable.nbuckets; i++) { + manager->heap.hashtable.buckets[i] = NIL(bdd_node); + } + + manager->heap.external_refs.pointer.block = NIL(bdd_bddBlock); + manager->heap.external_refs.pointer.index = 0; + manager->heap.external_refs.nmap = 0; + manager->heap.external_refs.free = 0; + manager->heap.external_refs.map = NIL(bdd_bddBlock); + + manager->heap.internal_refs.frames = NIL(bdd_safeframe); + + manager->heap.cache.itetable.on = mgr_init->ITE_cache.on; + manager->heap.cache.itetable.invalidate_on_gc = FALSE; + manager->heap.cache.itetable.resize_at = mgr_init->ITE_cache.resize_at; + manager->heap.cache.itetable.max_size = mgr_init->ITE_cache.max_size; + manager->heap.cache.itetable.nbuckets = BDD_CACHE_INITIAL_SIZE; + manager->heap.cache.itetable.nentries = 0; + manager->heap.cache.itetable.buckets = ALLOC(bdd_hashcache_entry *, manager->heap.cache.itetable.nbuckets); + if (manager->heap.cache.itetable.buckets == NIL(bdd_hashcache_entry *)) { + (void) bdd_memfail(NIL(bdd_manager), "bdd_start"); + } + for (i = 0; i < manager->heap.cache.itetable.nbuckets; i++) { + manager->heap.cache.itetable.buckets[i] = NIL(bdd_hashcache_entry); + } + + manager->heap.cache.consttable.on = mgr_init->ITE_const_cache.on; + manager->heap.cache.consttable.invalidate_on_gc = FALSE; + manager->heap.cache.consttable.resize_at = mgr_init->ITE_const_cache.resize_at; + manager->heap.cache.consttable.max_size = mgr_init->ITE_const_cache.max_size; + manager->heap.cache.consttable.nbuckets = BDD_CACHE_INITIAL_SIZE; + manager->heap.cache.consttable.nentries = 0; + manager->heap.cache.consttable.buckets = ALLOC(bdd_constcache_entry *, manager->heap.cache.consttable.nbuckets); + if (manager->heap.cache.consttable.buckets == NIL(bdd_constcache_entry *)) { + (void) bdd_memfail(NIL(bdd_manager), "bdd_start"); + } + for (i = 0; i < manager->heap.cache.consttable.nbuckets; i++) { + manager->heap.cache.consttable.buckets[i] = NIL(bdd_constcache_entry); + } + + manager->heap.cache.adhoc.on = mgr_init->adhoc_cache.on; /* if defined, caching is on */ + manager->heap.cache.adhoc.max_size = mgr_init->adhoc_cache.max_size; + manager->heap.cache.adhoc.table = NIL(st_table); /* initially undefined */ + + for (h=0; hheap.half); h++) { + manager->heap.half[h].inuse.top = NIL(bdd_nodeBlock); + manager->heap.half[h].inuse.tail = &manager->heap.half[h].inuse.top; + manager->heap.half[h].free = NIL(bdd_nodeBlock); + } + + manager->heap.init_node_blocks = mgr_init->nodes.init_blocks; + manager->heap.pointer.block = NIL(bdd_nodeBlock); + manager->heap.pointer.index = 0; + + manager->heap.gc.on = mgr_init->garbage_collector.on; + manager->heap.gc.halfspace = 0; /* start at halfspace 0 */ + manager->heap.gc.node_ratio = mgr_init->nodes.ratio; + manager->heap.gc.status.open_generators = 0; + +#if defined(BDD_DEBUG) /* { */ + /* + * Debug stuff ... + */ +#if defined(BDD_DEBUG_AGE) || defined(BDD_DEBUG_LIFESPAN) /* { */ + manager->debug.gc.age = 0; +#endif /* } */ +#if defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + manager->debug.gc.uniqueId = 0; +#endif /* } */ +#endif /* } */ + + manager->heap.gc.during.start.index = 0; + manager->heap.gc.during.start.block = NIL(bdd_nodeBlock); + manager->memory.daemon = mgr_init->memory.daemon; + manager->memory.limit = mgr_init->memory.limit; + + /* + * Clear out the stats + */ + manager->heap.stats.cache.hashtable.hits = 0; + manager->heap.stats.cache.hashtable.misses = 0; + manager->heap.stats.cache.hashtable.collisions = 0; + manager->heap.stats.cache.hashtable.inserts = 0; + + manager->heap.stats.cache.itetable = manager->heap.stats.cache.hashtable; + manager->heap.stats.cache.consttable = manager->heap.stats.cache.hashtable; + manager->heap.stats.cache.adhoc = manager->heap.stats.cache.hashtable; + + manager->heap.stats.ITE_ops.calls = 0; + manager->heap.stats.ITE_ops.returns.trivial = 0; + manager->heap.stats.ITE_ops.returns.cached = 0; + manager->heap.stats.ITE_ops.returns.full = 0; + + manager->heap.stats.ITE_constant_ops = manager->heap.stats.ITE_ops; + manager->heap.stats.adhoc_ops = manager->heap.stats.ITE_ops; + + manager->heap.stats.blocks.total = 0; + + manager->heap.stats.nodes.used = 0; + manager->heap.stats.nodes.unused = 0; + manager->heap.stats.nodes.total = 0; + manager->heap.stats.nodes.peak = 0; + + manager->heap.stats.extptrs.used = 0; + manager->heap.stats.extptrs.total = manager->heap.external_refs.nmap; + manager->heap.stats.extptrs.unused = manager->heap.stats.extptrs.total; + manager->heap.stats.extptrs.blocks = 0; + + manager->heap.stats.gc.times = 0; + manager->heap.stats.gc.nodes_collected = 0; + manager->heap.stats.gc.runtime = 0; + + manager->heap.stats.memory.first_sbrk = manager->heap.stats.memory.last_sbrk = (int) sbrk(0); + manager->heap.stats.memory.manager = 0; + manager->heap.stats.memory.nodes = 0; + manager->heap.stats.memory.hashtable = 0; + manager->heap.stats.memory.ext_ptrs = 0; + manager->heap.stats.memory.ITE_cache = 0; + manager->heap.stats.memory.ITE_const_cache = 0; + manager->heap.stats.memory.adhoc_cache = 0; + manager->heap.stats.memory.total = 0; + +#if defined(BDD_DEBUG) /* { */ +#if defined(BDD_DEBUG_LIFESPAN) /* { */ + /* this must be before any calls to find_or_add or (transitively) new_node */ + { + char tracefile[MAXPATHLEN]; + + (void) sprintf(tracefile, DEBUG_LIFESPAN_TRACEFILE, getpid()); + manager->debug.lifespan.trace = fopen(tracefile, "w"); + (void) fprintf(stderr, "tracefile is %s\n", tracefile); + } + BDD_ASSERT(manager->debug.lifespan.trace != NIL(FILE)); + + /* + * Start the recording by indicating that we're at generation 0 + */ + (void) fprintf(manager->debug.lifespan.trace, "g %d\n", manager->debug.gc.age); +#endif /* } */ +#if defined(BDD_FLIGHT_RECORDER) /* { */ + /* this must be before any bdd-manipulating calls are made */ + { + char logfile[MAXPATHLEN]; + + (void) sprintf(logfile, FLIGHT_RECORDER_LOGFILE, getpid()); + manager->debug.flight_recorder.log = fopen(logfile, "w"); + (void) fprintf(stderr, "logfile is %s\n", logfile); + } + BDD_ASSERT(manager->debug.flight_recorder.log != NIL(FILE)); +#endif /* } */ +#endif /* } */ + + /* + * Now initialize all of the bdd-algorithm stuff. This first call to find_or_add causes + * manager->heap.init_node_blocks to be allocated. + */ + manager->bdd.one = bdd_find_or_add(manager, /* variableId */ BDD_ONE_ID, NIL(bdd_node), NIL(bdd_node)); + manager->bdd.nvariables = nvariables; + + /* + * With the understanding that zeroing out the structure will + * mean niling out all of the pointers inside the structure. + */ + bzero(&manager->hooks, sizeof (manager->hooks)); + +#if defined(BDD_DEBUG) /* { */ +#if defined(BDD_NO_GC) /* { */ + /* this is independent of defined(DEBUG) */ + manager->heap.gc.on = FALSE; +#endif /* } */ +#endif /* } */ + + return (manager); +} + +/* + * bdd_start - initialize a bdd manager + * + * Given the number of variables, create and initialize a bdd_manager with + * the default settings. + * + * return the new bdd manager + */ +bdd_manager * +bdd_start(nvariables) +int nvariables; /* the maximum number of variables allowable in this bdd manager */ +{ + bdd_mgr_init mgr_init; + + (void) bdd_set_mgr_init_dflts(&mgr_init); + + return (bdd_start_with_params(nvariables, &mgr_init)); +} + +/* + * bdd_register_daemon + * + * Register the function to be called when the memory limit is exceeded. + */ +void +bdd_register_daemon(manager, daemon) +bdd_manager *manager; +void (*daemon)(); +{ + manager->memory.daemon = daemon; + return; +} + diff --git a/sis/bdd_ucb/bdd_substit.c b/sis/bdd_ucb/bdd_substit.c new file mode 100644 index 0000000..4b7b63b --- /dev/null +++ b/sis/bdd_ucb/bdd_substit.c @@ -0,0 +1,298 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_substit.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_substit.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd_substit.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.7 1993/02/25 01:09:39 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.7 1993/02/25 01:09:39 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.3 1993/01/11 23:42:14 shiple + * Made change to call to st_lookup for DEC Alpha compatibility. + * + * Revision 1.2 1992/09/19 02:49:15 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Added use of adhoc_ops stats. + * + * Revision 1.1 1992/07/29 00:26:53 shiple + * Initial revision + * + * Revision 1.4 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.3 1992/04/09 04:55:03 sis + * Fixed a core leak in bdd_substitute(). + * + * Revision 1.3 1992/04/09 04:55:03 sis + * Fixed a core leak in bdd_substitute(). + * + * Revision 1.2 1992/04/06 23:34:31 sis + * Fixed a core leak in bdd_substitute. + * + * Revision 1.1 92/01/08 17:34:33 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:35 shiple + * Initial revision + * + * + */ + +static bdd_node *substitute(); +static int cmp(); /* like strcmp, but for integers */ + +/* + * bdd_substitute - substitute all old_array vars into with new_array vars + * + * given two arrays of variables a and b consisting of member values + * (a1 .. an) and (b1 .. bn), replace all occurrences of ai by bi. + * + * This could be done iteratively with bdd_compose but would require n + * passes instead of one. Thus this algorithm is only a performance optimization. + * + * first extract the var_id's and sort them then call the recursive routine + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_substitute(f, old_array, new_array) +bdd_t *f; +array_t *old_array; /* of bdd_t */ +array_t *new_array; /* of bdd_t */ +{ + bdd_safeframe frame; + bdd_safenode ret; + bdd_manager *manager; + bdd_t *e; + int i, old_var, new_var; + array_t *old_vars; + array_t *new_vars; + st_table *map; + + if (f == NIL(bdd_t)) + fail("bdd_substitute: invalid BDD"); + + BDD_ASSERT( ! f->free ); + + manager = f->bdd; + + /* + * Start the safe frame now that we know the input is correct. + * f and g are external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, ret); + + /* sort the old_vars / keep the correspondance with new_vars */ + BDD_ASSERT(array_n(old_array) == array_n(new_array)); + + map = st_init_table(st_ptrcmp, st_ptrhash); + + old_vars = bdd_get_varids(old_array); + new_vars = bdd_get_varids(new_array); + + for (i=0; inode, 0, old_vars, new_vars); + + /* + * Free the cache, end the safe frame and return the (safe) result + */ + (void) bdd_adhoccache_uninit(manager); + e = bdd_make_external_pointer(manager, ret.node, "bdd_substitute"); + bdd_safeframe_end(manager); + (void) array_free(new_vars); + (void) array_free(old_vars); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_substitute(%d, { ", + bdd_index_of_external_pointer(e), + bdd_index_of_external_pointer(f)); + { + int i; + + for (i=0; idebug.flight_recorder.log, "%d%s", + bdd_index_of_external_pointer(v), + i+1 == array_n(old_array) ? " }, ": ", "); + } + } + { + int i; + + for (i=0; idebug.flight_recorder.log, "%d%s", + bdd_index_of_external_pointer(v), + i+1 == array_n(new_array) ? " } )\n": ", "); + } + } +#endif /* } */ + + return (e); +} + +/* + * substitute - recursively perform the substitution + * + * cache f and the index + * returns the node subsitute(f, old_index, old_vars, new_vars) + * + * return the bdd_node* + */ +static bdd_node * +substitute(manager, f, old_index, old_vars, new_vars) +bdd_manager *manager; +bdd_node *f; +int old_index; +array_t *old_vars; +array_t *new_vars; +{ + bdd_safeframe frame; + bdd_safenode safe_f, ret, g, f_T, f_E, new_var, su_T, su_E; + bdd_variableId fId, top_varId, last_varId, new_varId; + bdd_int val; + int next_index; + + bdd_safeframe_start(manager, frame); + bdd_safenode_link(manager, safe_f, f); + bdd_safenode_declare(manager, ret); + bdd_safenode_declare(manager, g); + bdd_safenode_declare(manager, f_T); + bdd_safenode_declare(manager, f_E); + bdd_safenode_declare(manager, new_var); + bdd_safenode_declare(manager, su_T); + bdd_safenode_declare(manager, su_E); + + manager->heap.stats.adhoc_ops.calls++; + + if (old_index >= array_n(old_vars)) { + /* + * If the old index is beyond the substitution + * range, then return f it trivially. + */ + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager); + return (f); + } + + fId = BDD_REGULAR(f)->id; + + last_varId = array_fetch(int, old_vars, array_n(old_vars) - 1); + if (fId > last_varId) { + /* + * If f's id is above the last possible substitution + * then just return f trivially. Takes care of f == CONSTANT + */ + manager->heap.stats.adhoc_ops.returns.trivial++; + bdd_safeframe_end(manager); + return (f); + } + + /* + * key = {f, nil, old_index} + */ + g.node = NIL(bdd_node); + val = old_index; + + if (bdd_adhoccache_lookup(manager, f, g.node, val, &ret.node)) { + /* + * The answer was already in the cache, so just return it. + */ + manager->heap.stats.adhoc_ops.returns.cached++; + bdd_safeframe_end(manager); + return (ret.node); + } + + /* from now on, everything has to be protected */ + top_varId = array_fetch(int, old_vars, old_index); + if (fId > top_varId) { + ret.node = substitute(manager, f, old_index + 1, old_vars, new_vars); + } else { + if (fId < top_varId) { + next_index = old_index; + new_varId = fId; + } else { /* fId == top_varId */ + next_index = old_index + 1; + new_varId = array_fetch(int, new_vars, old_index); + } + (void) bdd_get_branches(f, &f_T.node, &f_E.node); + + su_T.node = substitute(manager, f_T.node, next_index, old_vars, new_vars); + su_E.node = substitute(manager, f_E.node, next_index, old_vars, new_vars); + + /* + * varId is the value (v, 1, 0) + */ + new_var.node = bdd_find_or_add(manager, new_varId, BDD_ONE(manager), BDD_ZERO(manager)); + ret.node = bdd__ITE_(manager, new_var.node, su_T.node, su_E.node); + } + + (void) bdd_adhoccache_insert(manager, f, g.node, val, ret.node); + manager->heap.stats.adhoc_ops.returns.full++; + + bdd_safeframe_end(manager); + return (ret.node); +} + +/* + * cmp - like strcmp, but for integers + * + * return {-1, 0, 1} on {<, =, >} + */ +static int +cmp(val1, val2) +int *val1; /* by reference */ +int *val2; /* by reference */ +{ + return (*val1 - *val2); +} diff --git a/sis/bdd_ucb/bdd_support.c b/sis/bdd_ucb/bdd_support.c new file mode 100644 index 0000000..75ed76d --- /dev/null +++ b/sis/bdd_ucb/bdd_support.c @@ -0,0 +1,158 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_support.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: bdd_support.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.1 1993/02/25 01:06:24 sis + * Initial revision + * + * Revision 1.1 1993/02/25 01:06:24 sis + * Initial revision + * + * Revision 1.1 1993/02/22 21:34:48 shiple + * Initial revision + * + * + */ +#include +#include "util.h" +#include "array.h" +#include "st.h" +#include "var_set.h" +#include "bdd.h" +#include "bdd_int.h" + +typedef struct { + double count; /* result */ + int index; /* index in vars array */ +} count_cache_t; + +static void extract_bdd_support(); + + /* returns the support (in terms of primary inputs) of a BDD */ + /* the result is returned as a bit array */ + /* bdd read-only so no need for protection */ + +var_set_t *bdd_get_support(fn) +bdd_t *fn; +{ + bdd_manager *manager = fn->bdd; + st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); + var_set_t *result = var_set_new((int) manager->bdd.nvariables); + + (void) extract_bdd_support(result, fn->node, fn->bdd, visited); + (void) st_free_table(visited); + return result; +} + +static void extract_bdd_support(set, fn, manager, visited) +var_set_t *set; +bdd_node *fn; +bdd_manager *manager; +st_table *visited; +{ + bdd_node *zero = BDD_ZERO(manager); + bdd_node *one = BDD_ONE(manager); + bdd_node *f0, *f1; + unsigned int topf; + + if (fn == zero || fn == one) return; + if (st_lookup(visited, (char *) fn, NIL(char *))) return; + topf = BDD_REGULAR(fn)->id; + (void) var_set_set_elt(set, (int) topf); + (void) bdd_get_branches(fn, &f1, &f0); + (void) extract_bdd_support(set, f1, manager, visited); + (void) extract_bdd_support(set, f0, manager, visited); + (void) st_insert(visited, (char *) fn, NIL(char)); +} + + +static double bdd_do_count_onset(); + + /* counts the number of minterms in the onset of a bdd */ + /* bdd read-only so no need for protection */ + /* var_array is an array of variables (as bdd_t *'s) we care about */ + +double bdd_count_onset(fn, var_array) +bdd_t *fn; +array_t *var_array; +{ + bdd_node *node; + bdd_manager *bdd; + double result; + st_generator *gen; + char *key, *value; + array_t *vars; + st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); + + assert(fn != NIL(bdd_t)); + assert(var_array != NIL(array_t)); + bdd = fn->bdd; + node = fn->node; + vars = bdd_get_sorted_varids(var_array); + if (array_n(vars) == 0) { + result = 0.0; + } else { + result = bdd_do_count_onset(node, bdd, 0, vars, visited); + } + st_foreach_item(visited, gen,(char **) &key,(char **) &value) { + FREE(value); + } + (void) st_free_table(visited); + (void) array_free(vars); + return result; +} + + + /* we put in the cache only the entries where top_var == topf */ + /* vars is an array listing the variables that have to be considered */ + /* it is a fatal error if a variable in f does not appear in vars */ + /* the count is relative to 2^array_n(vars) */ + +static double bdd_do_count_onset(f, bdd, top_index, vars, visited) +bdd_node *f; +bdd_manager *bdd; +int top_index; +array_t *vars; +st_table *visited; +{ + int topf, top_var; + bdd_node *one = BDD_ONE(bdd); + bdd_node *zero = BDD_ZERO(bdd); + bdd_node *f1, *f0; + count_cache_t *value; + double result; + + if (st_lookup(visited, (char *) f, (char **) &value)) { + assert(f != one && f != zero); + assert(top_index <= value->index); + return value->count * pow((double) 2.0, (double) value->index - top_index); + } + if (f == zero) { + return 0.0; + } else if (f == one) { + return pow((double) 2, (double) array_n(vars) - top_index); + } else { + (void) bdd_get_branches(f, &f1, &f0); + topf = BDD_REGULAR(f)->id; + top_var = array_fetch(int, vars, top_index); + assert(top_var <= topf); + if (topf == top_var) { + result = bdd_do_count_onset(f1, bdd, top_index + 1, vars, visited) + + bdd_do_count_onset(f0, bdd, top_index + 1, vars, visited); + value = ALLOC(count_cache_t, 1); + value->count = result; + value->index = top_index; + (void) st_insert(visited, (char *) f, (char *) value); + return result; + } else { + return 2 * bdd_do_count_onset(f, bdd, top_index + 1, vars, visited); + } + } +} diff --git a/sis/bdd_ucb/bdd_tovar.c b/sis/bdd_ucb/bdd_tovar.c new file mode 100644 index 0000000..27468d4 --- /dev/null +++ b/sis/bdd_ucb/bdd_tovar.c @@ -0,0 +1,127 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_tovar.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_tovar.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd_tovar.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 03:29:12 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. + * + * Revision 1.1 1992/07/29 00:26:54 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:33 sis + * Initial revision + * + * Revision 1.2 91/03/28 14:45:20 shiple + * replaced include of mis.h with 5 other include files; now consistent with + * other .c files + * + * Revision 1.1 91/03/27 14:35:36 shiple + * Initial revision + * + * + */ + +static int get_var_id(); +static int int_compare(); + + /* bdd read-only so no need for protection */ + /* provides two functions */ + /* one, given an array of bdd_t *, representing variables */ + /* extract the var_id and put them back in an array */ + + /* if var_array is non nil, extract the var-id from it */ + /* if var_array is nil, return an array of ints from 0 to total_n_vars */ + +array_t *bdd_get_sorted_varids(var_array) +array_t *var_array; +{ + array_t *result = bdd_get_varids(var_array); + (void) array_sort(result, int_compare); + return result; +} + +array_t *bdd_get_varids(var_array) +array_t *var_array; +{ + int i; + bdd_t *var; + array_t *result = array_alloc(int, 0); + + for (i = 0; i < array_n(var_array); i++) { + var = array_fetch(bdd_t *, var_array, i); + (void) array_insert_last(int, result, get_var_id(var)); + } + return result; +} + +int bdd_varid_cmp(obj1, obj2) +char *obj1; +{ + bdd_t *f1 = (bdd_t *) obj1; + bdd_t *f2 = (bdd_t *) obj2; + + return get_var_id(f1) - get_var_id(f2); +} + + /* checks that the BDD is a variable node (positive literal) */ + /* and if it is the case, returns its ID */ + +static int get_var_id(var) +bdd_t *var; +{ + bdd_manager *bdd = var->bdd; + bdd_node *f = var->node; + bdd_node *f0, *f1; + + assert(f == BDD_REGULAR(f)); + (void) bdd_get_branches(f, &f1, &f0); + assert(f1 == BDD_ONE(bdd)); + assert(f0 == BDD_ZERO(bdd)); + return f->id; +} + + + /* needed for sorting arrays of var_id's */ + +static int int_compare(obj1, obj2) +char *obj1; +char *obj2; +{ + return *((int *) obj1) - *((int *) obj2); +} + diff --git a/sis/bdd_ucb/bdd_util.c b/sis/bdd_ucb/bdd_util.c new file mode 100644 index 0000000..8c8b1a5 --- /dev/null +++ b/sis/bdd_ucb/bdd_util.c @@ -0,0 +1,734 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/bdd_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: bdd_util.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.7 1993/06/30 00:14:37 shiple + * Added definition of new function bdd_dynamic_reordering. + * + * Revision 1.6 1993/06/28 22:34:05 shiple + * Added definition of new function bdd_num_vars. + * + * Revision 1.5 1993/06/22 00:42:45 shiple + * Made it illegal to free a bdd_t more than once. + * + * Revision 1.4 1993/06/04 15:42:51 shiple + * Added functions bdd_get_manager, bdd_get_external_hooks, bdd_top_var_id, and bdd_get_node. + * + * Revision 1.3 1993/01/11 23:48:44 shiple + * Incorrect comment in function bdd_size removed. + * + * Revision 1.2 1992/09/19 02:50:47 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Subtracted one from return value of bdd_size because it was wrong. Added get_mem_stats function. + * In bdd_get_branches, return NIL for then and else pointers if argument is the constant 0. + * Added bdd_will_exceed_mem_limit function. + * + * Revision 1.1 1992/07/29 00:26:55 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:34 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:36 shiple + * Initial revision + * + * + */ + +#define BDD_ONE_MEGABYTE 1048576 + +static void get_mem_stats(); + +/* + * bdd_create_variable - create a new variable and add it to the bdd + * + * A bdd formula of the form (v, 1, 0) is returned. + * The 'v' is a unique new variable. + * + * return a bdd_t* + */ +bdd_t * +bdd_create_variable(manager) +bdd_manager *manager; +{ + bdd_t *var; + + var = bdd_get_variable(manager, manager->bdd.nvariables++); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_create_variable(manager)\n", + bdd_index_of_external_pointer(var)); +#endif /* } */ + + return (var); +} + +/* + * bdd_dup - return a copy of the given bdd + * + * Actually what this does is allocates a new external + * pointer for the user. It is the user's responsibility + * then to manage the allocation and deallocation of + * these external pointers. + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_dup(f) +bdd_t *f; +{ + bdd_manager *manager; + bdd_t *f1; + + if (f == NIL(bdd_t)) + return (NIL(bdd_t)); /* robustness */ + + BDD_ASSERT( ! f->free ); + + manager = f->bdd; + + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + f1 = bdd_make_external_pointer(f->bdd, f->node, "bdd_dup"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_dup(%d)\n", + bdd_index_of_external_pointer(f1), + bdd_index_of_external_pointer(f)); +#endif /* } */ + + return (f1); +} + +/* + * bdd_free - free the given bdd_t + * + * WATCHOUT - don't call with BDDs assigned to a node -- use bdd_f_noderee. + * WATCHOUT - there is no way to assertion-check the above condition either + * the only possible error message is core-dumped (later) + * + * return nothing, just do it. + */ +void +bdd_free(f) +bdd_t *f; +{ + bdd_manager *manager; + + if (f == NIL(bdd_t)) { + fail("bdd_free: trying to free a NIL bdd_t"); + } + + if (f->free == TRUE) { + fail("bdd_free: trying to free a freed bdd_t"); + } + + manager = f->bdd; + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "bdd_free(%d)\n", + bdd_index_of_external_pointer(f)); +#endif /* } */ + + (void) bdd_destroy_external_pointer(f); +} + +/* + * bdd_else - return the else-side of a bdd + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_else(f) +bdd_t *f; +{ + bdd_safeframe frame; + bdd_safenode reg_f, ret; + bdd_manager *manager; + bdd_t *e; + + if (f == NIL(bdd_t)) + fail("bdd_else: invalid BDD"); + + BDD_ASSERT( ! f->free ); + + if (BDD_IS_CONSTANT(f->bdd, f->node)) + fail("bdd_else: constant BDD"); + + manager = f->bdd; + + /* + * After the input is checked for correctness, start the safe frame + * f is already an external pointer so it need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, reg_f); + bdd_safenode_declare(manager, ret); + + reg_f.node = BDD_REGULAR(f->node); + ret.node = BDD_IS_COMPLEMENT(f->node) ? BDD_NOT(reg_f.node->E) : reg_f.node->E; + + /* + * End the safe frame and return the result + */ + bdd_safeframe_end(manager); + e = bdd_make_external_pointer(manager, ret.node, "bdd_else"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_else(%d)\n", + bdd_index_of_external_pointer(e), + bdd_index_of_external_pointer(f)); +#endif /* } */ + + return (e); +} + +/* + * bdd_then - return the then-side of a bdd + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_then(f) +bdd_t *f; +{ + bdd_safeframe frame; + bdd_safenode reg_f, ret; + bdd_manager *manager; + bdd_t *t; + + if (f == NIL(bdd_t)) + fail("bdd_then: invalid BDD"); + + BDD_ASSERT( ! f->free ); + + if (BDD_IS_CONSTANT(f->bdd, f->node)) + fail("bdd_then: constant BDD"); + + manager = f->bdd; + + /* + * After the input is checked for correctness, start the safe frame + * f is already an external pointer so it need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, reg_f); + bdd_safenode_declare(manager, ret); + + reg_f.node = BDD_REGULAR(f->node); + ret.node = BDD_IS_COMPLEMENT(f->node) ? BDD_NOT(reg_f.node->T) : reg_f.node->T; + + /* + * End the safe frame and return the result + */ + bdd_safeframe_end(manager); + t = bdd_make_external_pointer(manager, ret.node, "bdd_then"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_then(%d)\n", + bdd_index_of_external_pointer(t), + bdd_index_of_external_pointer(f)); +#endif /* } */ + + return (t); +} + +/* + * bdd_get_branches - get the branches of a node + * + * return nothing, just do it. + */ +void +bdd_get_branches(f, f_T, f_E) +bdd_node *f; +bdd_node **f_T; /* return */ +bdd_node **f_E; /* return */ +{ + bdd_node *reg_f; + int is_constant; + + reg_f = BDD_REGULAR(f); + + /* + * If f is the constant 0, we just want to return NIL for the then + * and else branches. Since we can't access the manager from this + * routine, we simply check the id of the node. + */ + is_constant = (reg_f->id == BDD_ONE_ID) ? TRUE : FALSE; + + if (BDD_IS_COMPLEMENT(f) && !(is_constant)) { + *f_T = BDD_NOT(reg_f->T); + *f_E = BDD_NOT(reg_f->E); + } else { + *f_T = reg_f->T; + *f_E = reg_f->E; + } +} + +/* + * bdd_top_var - return the top variable of the bdd + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_top_var(f) +bdd_t *f; +{ + bdd_safeframe frame; + bdd_safenode reg_f, ret; + bdd_t *v; + bdd_manager *manager; + + if (f == NIL(bdd_t)) + fail("bdd_top_var: invalid BDD"); + + BDD_ASSERT( ! f->free ); + + if (f->node == BDD_ONE(f->bdd)) + return (bdd_one(f->bdd)); + + if (f->node == BDD_ZERO(f->bdd)) + return (bdd_zero(f->bdd)); + + manager = f->bdd; + + /* + * After the input is checked for correctness, start the safe frame + * f and g are already external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, reg_f); + bdd_safenode_declare(manager, ret); + + reg_f.node = BDD_REGULAR(f->node); + ret.node = bdd_find_or_add(manager, reg_f.node->id, BDD_ONE(manager), BDD_ZERO(manager)); + + /* + * End the safe frame and return the result + */ + bdd_safeframe_end(manager); + v = bdd_make_external_pointer(manager, ret.node, "bdd_top_var"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_top_var(%d)\n", + bdd_index_of_external_pointer(v), + bdd_index_of_external_pointer(f)); +#endif /* } */ + + return (v); +} + +/* + * bdd_top_var_id - return the id of the top variable of the bdd + */ +bdd_variableId +bdd_top_var_id(f) +bdd_t *f; +{ + + if (f == NIL(bdd_t)) + fail("bdd_top_var_id: invalid BDD"); + + BDD_ASSERT( ! f->free ); + + return (BDD_REGULAR(f->node)->id); +} + +/* + * bdd_get_variable - get or create a new variable and add it to the bdd + * + * The variable had better be in the range 0 .. nvariables else a failure occurs. + * A bdd of the form (v, 1, 0) is returned. This is the only acceptable way of + * getting or creating variables in the manager. It should be noted that the + * value of bdd.nvariables was established in bdd_start at manager initialization + * time and is not changed over the life of the manager. This is for reasons of + * strong checking; ensure that the user doesn't wildly create variables. + * + * return a bdd_t* + */ +bdd_t * +bdd_get_variable(manager, variable_i) +bdd_manager *manager; +bdd_variableId variable_i; +{ + bdd_safeframe frame; + bdd_safenode v; + bdd_t *var; + + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, v); + + BDD_ASSERT(variable_i < manager->bdd.nvariables); + + v.node = bdd_find_or_add(manager, variable_i, BDD_ONE(manager), BDD_ZERO(manager)); + + bdd_safeframe_end(manager); + + var = bdd_make_external_pointer(manager, v.node, "bdd_get_variable"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_get_variable(manager, %d)\n", + bdd_index_of_external_pointer(var), variable_i); +#endif /* } */ + + return (var); +} + +/* + * bdd_get_stats - get the statistics from the bdd package + * + * return nothing, just do it. + */ +void +bdd_get_stats(manager, stats) +bdd_manager *manager; +bdd_stats *stats; /* return */ +{ + BDD_ASSERT(manager != NIL(bdd_manager)); + + (void) get_mem_stats(manager); + *stats = manager->heap.stats; +} + +/* + * bdd_size - return the size of the bdd (in nodes) + * + * Compute the number of nodes in the bdd by traversal (e.g counting) + * + */ +int +bdd_size(f) +bdd_t *f; +{ + int count; + bdd_gen *gen; + bdd_node *node; + + if (f == NIL(bdd_t)) + fail("bdd_size: illegal BDD"); + + BDD_ASSERT( ! f->free ); + + if (f->node == NIL(bdd_node)) { + static already_warned = 0; + if (! already_warned) { + already_warned = 1; + (void) printf("WARNING: size of nil bdd computed????\n"); + } + return (0); + } + + count = 0; + foreach_bdd_node(f, gen, node) { + count++; + } + + return (count); +} + +/* + * bdd__fail - because the fail() macro is inside a block + * + * And I need a fail function that can be inside an expression + * + * don't return, just do it + */ +int /* must return an int so it can be in an expression */ +bdd__fail(__file__, __line__, message, failed) +string __file__; +int __line__; +string message; +string failed; /* may be NIL(char) indicating don't print it */ +{ + (void) fprintf(stderr, "\ +Fatal error in file %s, line %d\n\ +\tmessage: %s\n\ +", __file__, __line__, message); + + if (failed != NIL(char)) { + (void) fprintf(stderr, "\ +\tassertion: %s\n\ +", failed); + } + + (void) fflush(stdout); /* not stderr - it is unbuffered */ + abort(); +} + +/* + * bdd_memfail - declare a memory allocation failure + * + * Print out the statistics, so the guy knows why he died! + * + * don't return, just do it + */ +void +bdd_memfail(manager, function) +bdd_manager *manager; /* may be NIL(bdd_manager) in case of bdd_start() */ +string function; +{ + bdd_stats stats; + + /* + * WATCHOUT - assume NOTHING about the manager except that you can + * go in and recover the statistics from it. During garbage_collection + * the manager is in a state if semi-inconsistence, so it is not + * possible to do many operations on it. + */ + + /* + * If there was a bdd_manager, then get some stats before death + */ + if (manager != NIL(bdd_manager)) { + (void) fprintf(stderr, "\nBDD Manager Death Statistics\n\n"); + (void) bdd_get_stats(manager, &stats); + (void) bdd_print_stats(stats, stderr); + } + + (void) fprintf(stderr, "Fatal error: memory allocation failure in %s\n", function); + (void) fflush(stdout); + exit(1); +} + +/* + * get_mem_stats + * + * Compute the memory used by the BDD manager and fill in the appropriate + * fields of the stats.memory data structure. + */ +static void +get_mem_stats(manager) +bdd_manager *manager; +{ + bdd_stats *stats; + + /* + * Get the current stats for the manager. + */ + stats = &manager->heap.stats; + + /* + * Update last_sbrk. + */ + stats->memory.last_sbrk = (int) sbrk(0); + + /* + * Memory for the manager itself. + */ + stats->memory.manager = sizeof(bdd_manager); + + /* + * Memory used by bdd_nodes. Multiply by 2 since there are two halfspaces. + */ + stats->memory.nodes = (stats->blocks.total * 2) * sizeof(bdd_nodeBlock); + + /* + * Memory used by the unique table. + */ + stats->memory.hashtable = manager->heap.hashtable.nbuckets * sizeof(bdd_node **); + + /* + * Memory used by external pointers. + */ + stats->memory.ext_ptrs = stats->extptrs.blocks * sizeof(bdd_bddBlock); + + /* + * Memory used by ITE table entries and ITE table buckets. + */ + stats->memory.ITE_cache = (manager->heap.cache.itetable.nbuckets * sizeof(bdd_hashcache_entry *)) + + (manager->heap.cache.itetable.nentries * sizeof(bdd_hashcache_entry)); + + /* + * Memory used by consttable entries and consttable buckets. + */ + stats->memory.ITE_const_cache = (manager->heap.cache.consttable.nbuckets * sizeof(bdd_constcache_entry *)) + + (manager->heap.cache.consttable.nentries * sizeof(bdd_constcache_entry)); + + /* + * Memory used by the adhoc table: table + buckets + entries. + */ + if (manager->heap.cache.adhoc.table == NIL(st_table)) { + stats->memory.adhoc_cache = 0; + } else { + stats->memory.adhoc_cache = (sizeof(st_table) + + (manager->heap.cache.adhoc.table->num_bins * sizeof(st_table_entry *)) + + (st_count(manager->heap.cache.adhoc.table) * (sizeof(st_table_entry) + sizeof(bdd_adhoccache_key))) ); + } + + /* + * Total memory used. + */ + stats->memory.total = stats->memory.manager + stats->memory.nodes + + stats->memory.hashtable + stats->memory.ext_ptrs + stats->memory.ITE_cache + + stats->memory.ITE_const_cache + stats->memory.adhoc_cache; + +} + + +/* + * bdd_will_exceed_mem_limit + * + * Test to see if allocating alloc_size will cause the manager's memory limit to + * be exceeded. Return TRUE if limit will be exceeded, else FALSE. If memory limit + * will be exceeded and if call_daemon is TRUE, then don't return; instead, call the daemon. + */ +boolean +bdd_will_exceed_mem_limit(manager, alloc_size, call_daemon) +bdd_manager *manager; +int alloc_size; +boolean call_daemon; +{ + + /* + * If there is no memory limit, then return FALSE. + */ + if (manager->memory.limit == BDD_NO_LIMIT) { + return FALSE; + } + + /* + * Compute the memory statistics for the manager. TODO: if get_mem_stats is taking too much time, + * then we should update the memory stats incrementally each time we do an allocation. + */ + (void) get_mem_stats(manager); + + /* + * If allocating alloc_size bytes will not cause the limit to be exceeded, then return FALSE. + */ + if ((manager->heap.stats.memory.total + alloc_size) < (manager->memory.limit * BDD_ONE_MEGABYTE)) { + return FALSE; + } else { + /* + * Allocating alloc_size bytes will cause the memory limit to be exceeded. If call_daemon is + * FALSE, then just return TRUE. Else, clean up, and then call the daemon. + */ + if (call_daemon == FALSE) { + return TRUE; + } else { + /* + * Reset the safeframe pointer of the manager. All of the data structures associated with the + * safeframe mechanism are automatic (e.g. stack) variables which are on the stack somewhere. + * Thus, we simply need to tell the manager that there are no safeframes. + */ + manager->heap.internal_refs.frames = NIL(bdd_safeframe); + + /* + * Free the adhoc table if it is in use. + */ + if (manager->heap.cache.adhoc.table != NIL(st_table)) { + (void) bdd_adhoccache_uninit(manager); + } + + /* + * Call the garbage collector to get rid of the current computation, and to try + * to free up additional space. + */ + (void) bdd_garbage_collect(manager); + + /* + * Call the daemon specified by the application. + */ + if (manager->memory.daemon != NIL(void)) { + (*(manager->memory.daemon)) (manager); + } else { + fail("bdd_will_exceed_mem_limit: memory limit set, but no daemon registered"); + } + } + } +} + + +/* + * Get the manager of the bdd_t. + */ +bdd_manager * +bdd_get_manager(f) +bdd_t *f; +{ + if (f == NIL(bdd_t)) { + fail("bdd_get_manager: invalid BDD"); + } + + BDD_ASSERT( ! f->free ); + + return f->bdd; +} + +/* + * Return a pointer to the external_hooks data structure of the manager. + */ +bdd_external_hooks * +bdd_get_external_hooks(manager) +bdd_manager *manager; +{ + return &(manager->hooks); +} + + +/* + * Return the regularized bdd_node which the bdd_t points to. Also, + * return whether or not the node pointer was complemented. + */ +bdd_node * +bdd_get_node(f, is_complemented) +bdd_t *f; +boolean *is_complemented; /* return */ +{ + if (f == NIL(bdd_t)) + fail("bdd_equal: invalid BDD"); + + BDD_ASSERT( ! f->free ); + + *is_complemented = BDD_IS_COMPLEMENT(f->node); + return (BDD_REGULAR(f->node)); +} + +/* + * Return the number of variables that the bdd_manager knows of. + */ +unsigned int +bdd_num_vars(manager) +bdd_manager *manager; +{ + return (manager->bdd.nvariables); +} + +/* + * Shell for dynamic variable reordering. + */ +void +bdd_dynamic_reordering(manager, algorithm_type) +bdd_manager *manager; +bdd_reorder_type_t algorithm_type; +{ + (void) printf("WARNING: Dynamic variable reordering not implemented in the Berkeley BDD package.\n"); +} diff --git a/sis/bdd_ucb/boolean_ops.c b/sis/bdd_ucb/boolean_ops.c new file mode 100644 index 0000000..cfd6a25 --- /dev/null +++ b/sis/bdd_ucb/boolean_ops.c @@ -0,0 +1,488 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/boolean_ops.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/boolean_ops.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: boolean_ops.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 01:47:17 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. + * + * Revision 1.1 1992/07/29 00:26:56 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:34 sis + * Initial revision + * + * Revision 1.1 91/04/11 20:59:01 shiple + * Initial revision + * + * + */ + +/* + * bdd_and - returns the and of two bdd's + * + * bdd_ITE Identity: F * G = ITE(F, G, 0) + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_and(f, g, f_phase, g_phase) +bdd_t *f; +bdd_t *g; +boolean f_phase; /* if ! f_phase then negate f */ +boolean g_phase; /* if ! g_phase then negate g */ +{ + bdd_safeframe frame; + bdd_safenode real_f, real_g, ret; + bdd_manager *manager; + bdd_t *h; + + if (f == NIL(bdd_t) || g == NIL(bdd_t)) + fail("bdd_and: invalid BDD"); + + BDD_ASSERT( ! f->free ); + BDD_ASSERT( ! g->free ); + + if (f->bdd != g->bdd) + fail("bdd_and: different bdd managers"); + + manager = f->bdd; /* either this or g->bdd will do */ + + /* + * After the input is checked for correctness, start the safe frame + * f and g are already external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, real_f); + bdd_safenode_declare(manager, real_g); + bdd_safenode_declare(manager, ret); + + real_f.node = f_phase ? f->node: BDD_NOT(f->node); + real_g.node = g_phase ? g->node: BDD_NOT(g->node); + + ret.node = bdd__ITE_(manager, real_f.node, real_g.node, BDD_ZERO(manager)); + + /* + * End the safe frame and return the result + */ + bdd_safeframe_end(manager); + h = bdd_make_external_pointer(manager, ret.node, "bdd_and"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_and(%d, %d)\n", + bdd_index_of_external_pointer(h), + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(g)); +#endif /* } */ + + return (h); +} + +/* + * bdd_not - returns the not of the given bdd. + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_not(f) +bdd_t *f; +{ + bdd_manager *manager; + bdd_t *g; + + if (f == NIL(bdd_t)) + fail("bdd_not: invalid BDD"); + + BDD_ASSERT( ! f->free ); + + manager = f->bdd; + + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + g = bdd_make_external_pointer(f->bdd, BDD_NOT(f->node), "bdd_not"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_not(%d)\n", + bdd_index_of_external_pointer(g), + bdd_index_of_external_pointer(f)); +#endif /* } */ + + return (g); +} + +/* + * bdd_or - returns the or of two bdd's + * + * bdd_ITE Identity: F + G = ITE(F, 1, G) + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_or(f, g, f_phase, g_phase) +bdd_t *f; +bdd_t *g; +boolean f_phase; /* if ! f_phase then negate f */ +boolean g_phase; /* if ! g_phase then negate g */ +{ + bdd_safeframe frame; + bdd_safenode real_f, real_g, ret; + bdd_manager *manager; + bdd_t *h; + + if (f == NIL(bdd_t) || g == NIL(bdd_t)) + fail("bdd_or: invalid BDD"); + + BDD_ASSERT( ! f->free ); + BDD_ASSERT( ! g->free ); + + if (f->bdd != g->bdd) + fail("bdd_or: different bdd managers"); + + manager = f->bdd; /* either this or g->bdd will do */ + + /* + * After the input is checked for correctness, start the safe frame + * f and g are already external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, real_f); + bdd_safenode_declare(manager, real_g); + bdd_safenode_declare(manager, ret); + + real_f.node = f_phase ? f->node: BDD_NOT(f->node); + real_g.node = g_phase ? g->node: BDD_NOT(g->node); + + ret.node = bdd__ITE_(manager, real_f.node, BDD_ONE(manager), real_g.node); + + /* + * End the safe frame and return the result + */ + bdd_safeframe_end(manager); + h = bdd_make_external_pointer(manager, ret.node, "bdd_or"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_or(%d, %d)\n", + bdd_index_of_external_pointer(h), + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(g)); +#endif /* } */ + + return (h); +} + +/* + * bdd_xor - returns the xor of two bdd's + * + * bdd_ITE Identity: F xor G = ITE(F, !G, G) + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_xor(f, g) /* F xor G = ITE(F, !G, G) */ +bdd_t *f; +bdd_t *g; +{ + bdd_safeframe frame; + bdd_safenode ret; + bdd_manager *manager; + bdd_t *h; + + if (f == NIL(bdd_t) || g == NIL(bdd_t)) + fail("bdd_xor: invalid BDD"); + + BDD_ASSERT( ! f->free ); + BDD_ASSERT( ! g->free ); + + if (f->bdd != g->bdd) + fail("bdd_xor: different bdd managers"); + + manager = f->bdd; /* either this or g->bdd will do */ + + /* + * After the input is checked for correctness, start the safe frame + * f and g are already external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, ret); + + ret.node = bdd__ITE_(manager, f->node, BDD_NOT(g->node), g->node); + + /* + * End the safe frame and return the result + */ + bdd_safeframe_end(manager); + h = bdd_make_external_pointer(manager, ret.node, "bdd_xor"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_xor(%d, %d)\n", + bdd_index_of_external_pointer(h), + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(g)); +#endif /* } */ + + return (h); +} + +/* + * bdd_xnor - returns the xnor of two bdd's + * + * bdd_ITE Identity: !(F xor G) = ITE(F, G, !G) + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_xnor(f, g) /* !(F xor G) = ITE(F, G, !G) */ +bdd_t *f; +bdd_t *g; +{ + bdd_safeframe frame; + bdd_safenode ret; + bdd_manager *manager; + bdd_t *h; + + if (f == NIL(bdd_t) || g == NIL(bdd_t)) + fail("bdd_xnor: invalid BDD"); + + if (f->bdd != g->bdd) + fail("bdd_xnor: different bdd managers"); + + manager = f->bdd; /* either this or g->bdd will do */ + + /* + * After the input is checked for correctness, start the safe frame + * f and g are already external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, ret); + + ret.node = bdd__ITE_(manager, f->node, g->node, BDD_NOT(g->node)); + + /* + * End the safe frame and return the result + */ + bdd_safeframe_end(manager); + h = bdd_make_external_pointer(manager, ret.node, "bdd_xnor"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_xnor(%d, %d)\n", + bdd_index_of_external_pointer(h), + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(g)); +#endif /* } */ + + return (h); +} + +/* + * bdd_one - return a new copy of the 'one' constant + * + * return the new bdd (external pointer) + */ +bdd_t * +bdd_one(manager) +bdd_manager *manager; +{ + bdd_t *one; + + if (manager == NIL(bdd_manager)) + fail("bdd_one: bad bdd manager"); + + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + one = bdd_make_external_pointer(manager, BDD_ONE(manager), "bdd_one"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_one(manager)\n", + bdd_index_of_external_pointer(one)); +#endif /* } */ + + return (one); +} + +/* + * bdd_zero - return a new copy of the 'zero' constant + * + * return the new manager (external pointer) + */ +bdd_t * +bdd_zero(manager) +bdd_manager *manager; +{ + bdd_t *zero; + + if (manager == NIL(bdd_manager)) + fail("bdd_zero: bad bdd manager"); + + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + zero = bdd_make_external_pointer(manager, BDD_ZERO(manager), "bdd_zero"); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "%d <- bdd_zero(manager)\n", + bdd_index_of_external_pointer(zero)); +#endif /* } */ + + return (zero); +} + +/* + * bdd_is_tautology - is the bdd a tautology? + * + * Just see if the bdd is equal to a constant (one or zero) + * + * return {TRUE, FALSE} on {is, is not}. + */ +boolean +bdd_is_tautology(f, phase) +bdd_t *f; +boolean phase; +{ + bdd_manager *manager; + bdd_node *constant; + boolean ret; + + if (f == NIL(bdd_t)) + fail("bdd_is_tautology: invalid BDD"); + + BDD_ASSERT( ! f->free ); + + manager = f->bdd; + + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + constant = phase ? BDD_ONE(f->bdd): BDD_ZERO(f->bdd); + ret = f->node == constant ? TRUE: FALSE; + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "bdd_is_tautology(%d, %d)\n", + bdd_index_of_external_pointer(f), phase); +#endif /* } */ + + return (ret); +} + +/* + * bdd_equal - whether the two bdds are the same + * + * return {TRUE, FALSE} on {is, is not}. + */ +boolean +bdd_equal(f, g) +bdd_t *f; +bdd_t *g; +{ + bdd_manager *manager; + boolean ret; + + if (f == NIL(bdd_t) || g == NIL(bdd_t)) + fail("bdd_equal: invalid BDD"); + + BDD_ASSERT( ! f->free ); + BDD_ASSERT( ! g->free ); + + if (f->bdd != g->bdd) + fail("bdd_equal: different bdd managers"); + + manager = f->bdd; /* or g->bdd */ + + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + ret = f->node == g->node ? TRUE: FALSE; + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "bdd_equal(%d, %d)\n", + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(g)); +#endif /* } */ + + return (ret); +} + +/* + * bdd_leq - returns the leq of two bdd's + * + * ITE Identity: f implies g <=> ITE_constant(F, G, 1) = 1 + * + * return {TRUE, FALSE} on {is, is not}. + */ +boolean +bdd_leq(f, g, f_phase, g_phase) +bdd_t *f; +bdd_t *g; +boolean f_phase; /* if ! f_phase then negate f */ +boolean g_phase; /* if ! g_phase then negate g */ +{ + bdd_safeframe frame; + bdd_safenode real_f, real_g; + bdd_manager *manager; + boolean ret; + + if (f == NIL(bdd_t) || g == NIL(bdd_t)) + fail("bdd_leq: invalid BDD"); + + BDD_ASSERT( ! f->free ); + BDD_ASSERT( ! g->free ); + + if (f->bdd != g->bdd) + fail("bdd_leq: different bdd managers"); + + manager = f->bdd; /* either this or g->bdd will do */ + + /* + * After the input is checked for correctness, start the safe frame + * f and g are already external pointers so they need not be protected + */ + bdd_safeframe_start(manager, frame); + bdd_safenode_declare(manager, real_f); + bdd_safenode_declare(manager, real_g); + + real_f.node = f_phase ? f->node: BDD_NOT(f->node); + real_g.node = g_phase ? g->node: BDD_NOT(g->node); + + ret = bdd__ITE_constant(manager, real_f.node, real_g.node, BDD_ONE(manager)) == bdd_constant_one ? TRUE: FALSE; + + bdd_safeframe_end(manager); + +#if defined(BDD_FLIGHT_RECORDER) /* { */ + (void) fprintf(manager->debug.flight_recorder.log, "bdd_leq(%d, %d, %d, %d)\n", + bdd_index_of_external_pointer(f), + bdd_index_of_external_pointer(g), + f_phase, g_phase); +#endif /* } */ + + return (ret); +} diff --git a/sis/bdd_ucb/config.c b/sis/bdd_ucb/config.c new file mode 100644 index 0000000..d0137dd --- /dev/null +++ b/sis/bdd_ucb/config.c @@ -0,0 +1,55 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/config.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/config.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: config.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 01:47:33 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. + * + * Revision 1.1 1992/07/29 00:26:57 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:35 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:37 shiple + * Initial revision + * + * + */ + +/* global variables for the bdd package go here (none for now) */ diff --git a/sis/bdd_ucb/const_cache.c b/sis/bdd_ucb/const_cache.c new file mode 100644 index 0000000..915e509 --- /dev/null +++ b/sis/bdd_ucb/const_cache.c @@ -0,0 +1,272 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/const_cache.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/const_cache.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: const_cache.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.5 1993/05/04 15:30:57 sis + * BDD package updates. Tom Shiple 5/4/93. + * + * Revision 1.4 1993/05/03 20:29:26 shiple + * In insert routine, changed policy on what to do if a new key cannot be + * allocated because it would cause the memory limit to be exceeded. + * Before, just returned, without inserting. Now, insert, even if memory + * limit will be exceeded. + * + * Revision 1.3 1992/09/29 19:36:29 shiple + * Fixed bug in conditional to resize cache; ints were not being cast to floats + * + * Revision 1.2 1992/09/19 02:54:21 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added resize_consttable function. + * Changed ITE and ITE_const caches to be arrays of pointers. Add usage of + * bdd_will_exceed_mem_limit in bdd_constcache_insert and resize_consttable. + * + * Revision 1.1 1992/07/29 00:26:58 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:35 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:38 shiple + * Initial revision + * + * + */ + +static void resize_consttable(); + +/* + * bdd_constcache_insert - perform an insertion into the constcache + * + * return nothing, just do it. + */ +void +bdd_constcache_insert(manager, ITE_f, ITE_g, ITE_h, data) +bdd_manager *manager; +bdd_node *ITE_f; +bdd_node *ITE_g; +bdd_node *ITE_h; +bdd_constant_status data; +{ + int pos; + bdd_constcache_entry *entry; + + BDD_ASSERT_NOTNIL(ITE_f); + BDD_ASSERT_NOTNIL(ITE_g); + BDD_ASSERT_NOTNIL(ITE_h); + + if ( ! manager->heap.cache.consttable.on ) { + /* + * Has no effect if caching is off. + */ + return; + } + + pos = bdd_const_hash(manager, ITE_f, ITE_g, ITE_h); + entry = manager->heap.cache.consttable.buckets[pos]; + + if (entry != NIL(bdd_constcache_entry)) { + /* + * An entry already exists at pos. Since we are using an open-addressing + * scheme, we will just reuse the memory of this entry. Number of entries + * stays constant. + */ + manager->heap.stats.cache.consttable.collisions++; + } else { + /* + * Must allocate a new entry, since one does not already exist at pos. It's possible + * that allocating a bdd_hashcache_entry will cause the manager's + * memory limit to be exceeded. However, we allow this to happen, because the alternative + * is that we don't cache this call. Not caching new calls could be deadly for runtime. + */ + entry = ALLOC(bdd_constcache_entry, 1); + if (entry == NIL(bdd_constcache_entry)) { + (void) bdd_memfail(manager, "bdd_constcache_insert"); + } + manager->heap.cache.consttable.buckets[pos] = entry; + manager->heap.cache.consttable.nentries++; + } + + entry->ITE.f = ITE_f; + entry->ITE.g = ITE_g; + entry->ITE.h = ITE_h; + entry->data = data; + + manager->heap.stats.cache.consttable.inserts++; + + /* + * Check to see if table needs resizing. We base the decision on the ratio of the number of entries to the number + * of buckets. + */ + if ( (unsigned int) (((float) manager->heap.cache.consttable.nentries + / (float) manager->heap.cache.consttable.nbuckets) * 100) + > manager->heap.cache.consttable.resize_at) { + (void) resize_consttable(manager); + } +} + +/* + * bdd_constcache_lookup - perform a lookup in the cache + * + * return {TRUE, FALSE} on {found, not found}. + */ +boolean +bdd_constcache_lookup(manager, f, g, h, value) +bdd_manager *manager; +bdd_node *f; +bdd_node *g; +bdd_node *h; +bdd_constant_status *value; /* return */ +{ + + int pos; + bdd_constcache_entry *entry; + + if ( ! manager->heap.cache.consttable.on ) { + /* + * Always fails if caching is off. + */ + return (FALSE); + } + + pos = bdd_const_hash(manager, f, g, h); + entry = manager->heap.cache.consttable.buckets[pos]; + + if (entry != NIL(bdd_constcache_entry)) { + /* + * Entry exists at pos. See if it matches. If not (a miss) return. If it does match + * (a hit), then will drop out of IF and set value. + */ + if (entry->data == bdd_status_unknown ||(entry->ITE.f != f || entry->ITE.g != g || entry->ITE.h != h)) { + manager->heap.stats.cache.consttable.misses++; + return (FALSE); + } + } else { + /* + * No entry exists at pos. Definitely a miss. + */ + manager->heap.stats.cache.consttable.misses++; + return (FALSE); + } + + manager->heap.stats.cache.consttable.hits++; + + *value = entry->data; + return (TRUE); +} + +/* + * resize_consttable + * + * Make the ITE constant cache larger. Perform a rehash to map all of the old + * stuff into this new larger world. Note that since we don't maintain collision chains, + * some stuff may be lost. + */ +static void +resize_consttable(manager) +bdd_manager *manager; +{ + unsigned int old_nbuckets, next_hash_prime; + bdd_constcache_entry **old_buckets, *old_entry; + int i, pos; + + /* + * If the max_size has already been exceeded, then just return. + */ + if (manager->heap.cache.consttable.nbuckets > manager->heap.cache.consttable.max_size) { + return; + } + + /* + * Get the next hash prime. If allocating a new table will cause the manager memory limit to + * be exceeded, then just return. Trading off time in favor of space. + */ + next_hash_prime = bdd_get_next_hash_prime(manager->heap.cache.consttable.nbuckets); + if (bdd_will_exceed_mem_limit(manager, (next_hash_prime * sizeof(bdd_constcache_entry *)), FALSE) == TRUE) { + return; + } + + /* + * Save the old buckets. + */ + old_nbuckets = manager->heap.cache.consttable.nbuckets; + old_buckets = manager->heap.cache.consttable.buckets; + + /* + * Get the new size and allocate the new table. We are growing by roughly a factor of two. + * If there isn't sufficient memory, don't fail: the cache + * is meant to enhance performance, but we can still continue even if we can't resize. + */ + manager->heap.cache.consttable.nbuckets = next_hash_prime; + manager->heap.cache.consttable.buckets = ALLOC(bdd_constcache_entry *, manager->heap.cache.consttable.nbuckets); + if (manager->heap.cache.consttable.buckets == NIL(bdd_constcache_entry *)) { + manager->heap.cache.consttable.nbuckets = old_nbuckets; + manager->heap.cache.consttable.buckets = old_buckets; + return; + } + + /* + * Initialize all the entries to NIL. + */ + for (i = 0; i < manager->heap.cache.consttable.nbuckets; i++) { + manager->heap.cache.consttable.buckets[i] = NIL(bdd_constcache_entry); + } + + /* + * Remap all of the ITE cache entries to the new larger cache. + */ + manager->heap.cache.consttable.nentries = 0; + for (i = 0; i < old_nbuckets; i++) { + old_entry = old_buckets[i]; + if (old_entry != NIL(bdd_constcache_entry)) { + + /* + * Get the hash position for the entry in the new cache. If the position is already + * occupied, then old_entry will not be rehashed; it's lost; If the position is not + * occupied, then simply set the new cache bucket pointer to old_entry. + */ + pos = bdd_constcache_entry_hash(manager, old_entry); + if (manager->heap.cache.consttable.buckets[pos] != NIL(bdd_constcache_entry)) { + FREE(old_entry); + } else { + manager->heap.cache.consttable.buckets[pos] = old_entry; + manager->heap.cache.consttable.nentries++; + } + } + } + + /* + * Free the array of buckets. Note that the entries of the table were simply + * moved over to the new table. + */ + FREE(old_buckets); + +} + diff --git a/sis/bdd_ucb/dmp_ext_ptrs.c b/sis/bdd_ucb/dmp_ext_ptrs.c new file mode 100644 index 0000000..a2c47da --- /dev/null +++ b/sis/bdd_ucb/dmp_ext_ptrs.c @@ -0,0 +1,168 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/dmp_ext_ptrs.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/dmp_ext_ptrs.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: dmp_ext_ptrs.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 02:56:08 shiple + * Version 2.4 + * > Prefaced compile time debug switches with BDD_. Changed IF cond from bdd->free to !bdd->free. + * + * Revision 1.1 1992/07/29 00:26:59 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:36 sis + * Initial revision + * + * Revision 1.1 91/04/11 20:59:26 shiple + * Initial revision + * + * + */ + +/* + * bdd_dump_external_pointers - dump all outstanding external pointers + * + * For debugging, we must be able to dump all of the external pointers + * which are live and give some indication as to where they came from + * and who allocated them. Also, it is good if an indication of the size + * of the bdd (partially) held down by the pointer. + * + * return nothing, just do it. + */ +void +bdd_dump_external_pointers(manager, file) +bdd_manager *manager; +FILE *file; +{ + char value_buf[1000]; /* big enuf? */ + string origin; + bdd_bddBlock *bblock; + bdd_t *bnode; + int bb_i, i, create_bdd, other_bdd; + +#if defined(BDD_DEBUG_EXT_ALL) && defined(BDD_AUTOMATED_STATISTICS_GATHERING) /* { */ + (void) fprintf(file, "all-external-pointers: start\n"); +#endif /* } */ + + /* + * Foreach subheap in the map + */ + create_bdd = 0; + other_bdd = 0; + for (bblock=manager->heap.external_refs.map, bb_i=0; + bblock != NIL(bdd_bddBlock); bblock=bblock->next, bb_i++) { + /* + * Foreach member of the subheap + */ + for (i=0; isubheap); i++) { + bnode = &bblock->subheap[i]; + + /* + * If its not free, then print it out + */ + if (!bnode->free) { + /* + * Get some idea of the size of the thing held + */ + if (bnode->node == BDD_ZERO(manager)) { + strcpy(value_buf, "the zero"); + } else if (bnode->node == BDD_ONE(manager)) { + strcpy(value_buf, "the one"); + } else { + int size; + + size = bdd_size(bnode); + sprintf(value_buf, "bdd of %d node%s", size, size == 1 ? "": "s"); + } + + /* + * Get some idea of WHO allocated this + */ +#if defined(BDD_DEBUG_EXT) /* { */ + /* if debugging external pointers, then bnode-> origin exists */ + origin = bnode->origin; +#else /* } else { */ + /* otherwise it doesn't exist, and we have to just guess */ + origin = "unknown"; /* because it was never tracked */ +#endif /* } */ + + if (strcmp(origin, "bdd_create_bdd") == 0) { + /* + * Don't print these b/c there are usually alot + */ + create_bdd++; + } else { + /* + * The actual printing ... + */ + other_bdd++; + +#if defined(BDD_DEBUG_EXT_ALL) /* { */ +#if defined(BDD_AUTOMATED_STATISTICS_GATHERING) /* { */ + (void) fprintf(file, "\ +all-external-pointers: bdd_t: %d free: %s node: %s origin: %s\n\ +", i + bb_i * sizeof_el (bblock->subheap), + bnode->free ? "true": "false", + value_buf, origin); +#else /* } else { */ + (void) fprintf(file, "\ +bdd_t[%d] = { free: %s, node: %s, origin: %s }\n\ +", i + bb_i * sizeof_el (bblock->subheap), + bnode->free ? "true": "false", + value_buf, origin); +#endif /* } */ +#endif /* } */ + } + } + } + } + +#if defined(BDD_DEBUG_EXT_ALL) && defined(BDD_AUTOMATED_STATISTICS_GATHERING) /* { */ + (void) fprintf(file, "all-external-pointers: end\n"); +#endif /* } */ + +#if defined(BDD_AUTOMATED_STATISTICS_GATHERING) /* { */ + (void) fprintf(file, "\ +external-pointers: bdd_create_bdd: %d: other: %d\n\ +", create_bdd, other_bdd); +#else /* } else { */ + (void) fprintf(file, "\ +Outstanding External Pointers\n\ + due to bdd_create_bdd %d\n\ + due to other operations %d\n\ +", create_bdd, other_bdd); +#endif /* } */ +} diff --git a/sis/bdd_ucb/dmp_mgr_stat.c b/sis/bdd_ucb/dmp_mgr_stat.c new file mode 100644 index 0000000..cea2322 --- /dev/null +++ b/sis/bdd_ucb/dmp_mgr_stat.c @@ -0,0 +1,249 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/dmp_mgr_stat.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/dmp_mgr_stat.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: dmp_mgr_stat.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 02:58:50 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Totally revamped printing of statistics. Added all the new fields in stats. + * Changed ITE and ITE_const caches to be arrays of pointers. + * + * Revision 1.1 1992/07/29 00:26:59 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:36 sis + * Initial revision + * + * Revision 1.1 91/04/11 20:59:38 shiple + * Initial revision + * + * + */ + +/* + * bdd_dump_manager_stats - dump the manager statistics out + * + * return nothing, just do it. + */ +void +bdd_dump_manager_stats(manager) +bdd_manager *manager; +{ + bdd_stats stats; + int total_hashtable_queries; + int total_itetable_lookups; + int total_consttable_lookups; + int total_adhoc_lookups; + int num_frames; + int num_nodes; + int tot_frame_mem; + bdd_safeframe *sf; + bdd_safenode *sn; + int overall_memory; + int total_sbrk; + + /* + * Get the manager's stats. + */ + (void) bdd_get_stats(manager, &stats); + + /* + * Make intermediate calculations. + */ + total_hashtable_queries = stats.cache.hashtable.hits + stats.cache.hashtable.misses; + total_itetable_lookups = stats.cache.itetable.hits + stats.cache.itetable.misses; + total_consttable_lookups = stats.cache.consttable.hits + stats.cache.consttable.misses; + total_adhoc_lookups = stats.cache.adhoc.hits + stats.cache.adhoc.misses; + + /* + * Memory used by safeframes. + */ + num_frames = 0; + num_nodes = 0; + for (sf = manager->heap.internal_refs.frames; sf != NIL(bdd_safeframe); sf = sf->prev) { + num_frames++; + for (sn = sf->nodes; sn != NIL(bdd_safenode); sn = sn->next) { + num_nodes++; + } + } + tot_frame_mem = num_frames * sizeof(bdd_safeframe) + num_nodes * sizeof(bdd_safenode); + + /* + * Total memory usage. + */ + overall_memory = stats.memory.total + tot_frame_mem; + + /* + * Calculate the total sbrk. + */ + total_sbrk = stats.memory.last_sbrk - stats.memory.first_sbrk; + +#if defined(BDD_AUTOMATED_STATISTICS_GATHERING) /* { */ + /* + * Write out the stuff in a way which is easy to parse. Also, include some extra info. + */ + (void) fprintf(stderr, "\ +stats: start\n\ +stats: bdd_nodeBlock %d\n\ +stats: bdd_node used: %d, unused: %d, total: %d, peak: %d\n\ +stats: bdd_t used: %d, unused: %d, total: %d\n\ +stats: hash table total: %d, hits: %d (%4.1f%%), misses: %d (%4.1f%%)\n\ +stats: ITE ops total: %d, trivial: %d (%4.1f%%), cached: %d (%4.1f%%), full: %d (%4.1f%%)\n\ +stats: ITE table lookups: %d, misses: %d (%4.1f%%)\n\ +stats: ITE table insertions: %d, collisions: %d (%4.1f%%)\n\ +stats: ITE table entries: %d, percent of buckets: %4.1f%%\n\ +stats: ITE_const ops total: %d, trivial: %d (%4.1f%%), cached: %d (%4.1f%%), full: %d (%4.1f%%)\n\ +stats: ITE_const table lookups: %d, misses: %d (%4.1f%%)\n\ +stats: ITE_const table insertions: %d, collisions: %d (%4.1f%%)\n\ +stats: ITE_const table entries: %d, percent of buckets: %4.1f%%\n\ +stats: adhoc ops total: %d, trivial: %d (%4.1f%%), cached: %d (%4.1f%%), full: %d (%4.1f%%)\n\ +stats: adhoc table lookups: %d, misses: %d (%4.1f%%)\n\ +stats: garbage-collections: %d\n\ +stats: nodes collected: %d\n\ +stats: gc runtime: %.2f sec\n\ +stats: end\n\n\ +mem: start (all figures in bytes)\n\ +mem: manager = %9d\n\ +mem: bdd_nodes = %9d\n\ +mem: unique table bckts = %9d\n\ +mem: external ptrs = %9d\n\ +mem: ITE buckets = %9d\n\ +mem: ITE entries = %9d\n\ +mem: consttable buckets = %9d\n\ +mem: consttable entries = %9d\n\ +mem: adhoc table = %9d\n\ +mem: safe frames = %9d\n\ +mem: overall = %9d\n\ +mem: total sbrk = %9d\n\ +mem: total overhead = %9d (%d%%)\n\ +mem: end\n\ +", + stats.blocks.total, + stats.nodes.used, stats.nodes.unused, stats.nodes.total, stats.nodes.peak, + stats.extptrs.used, stats.extptrs.unused, stats.extptrs.total, + + total_hashtable_queries, + stats.cache.hashtable.hits, + bdd_get_percentage(stats.cache.hashtable.hits, total_hashtable_queries), + stats.cache.hashtable.misses, + bdd_get_percentage(stats.cache.hashtable.misses, total_hashtable_queries), + + stats.ITE_ops.calls, + stats.ITE_ops.returns.trivial, + bdd_get_percentage(stats.ITE_ops.returns.trivial, stats.ITE_ops.calls), + stats.ITE_ops.returns.cached, + bdd_get_percentage(stats.ITE_ops.returns.cached, stats.ITE_ops.calls), + stats.ITE_ops.returns.full, + bdd_get_percentage(stats.ITE_ops.returns.full, stats.ITE_ops.calls), + + total_itetable_lookups, + stats.cache.itetable.misses, + bdd_get_percentage(stats.cache.itetable.misses, total_itetable_lookups), + + stats.cache.itetable.inserts, + stats.cache.itetable.collisions, + bdd_get_percentage(stats.cache.itetable.collisions, stats.cache.itetable.inserts), + manager->heap.cache.itetable.nentries, + bdd_get_percentage(manager->heap.cache.itetable.nentries, manager->heap.cache.itetable.nbuckets), + + stats.ITE_constant_ops.calls, + stats.ITE_constant_ops.returns.trivial, + bdd_get_percentage(stats.ITE_constant_ops.returns.trivial, stats.ITE_constant_ops.calls), + stats.ITE_constant_ops.returns.cached, + bdd_get_percentage(stats.ITE_constant_ops.returns.cached, stats.ITE_constant_ops.calls), + stats.ITE_constant_ops.returns.full, + bdd_get_percentage(stats.ITE_constant_ops.returns.full, stats.ITE_constant_ops.calls), + + total_consttable_lookups, + stats.cache.consttable.misses, + bdd_get_percentage(stats.cache.consttable.misses, total_consttable_lookups), + + stats.cache.consttable.inserts, + stats.cache.consttable.collisions, + bdd_get_percentage(stats.cache.consttable.collisions, stats.cache.consttable.inserts), + manager->heap.cache.consttable.nentries, + bdd_get_percentage(manager->heap.cache.consttable.nentries, manager->heap.cache.consttable.nbuckets), + + stats.adhoc_ops.calls, + stats.adhoc_ops.returns.trivial, + bdd_get_percentage(stats.adhoc_ops.returns.trivial, stats.adhoc_ops.calls), + stats.adhoc_ops.returns.cached, + bdd_get_percentage(stats.adhoc_ops.returns.cached, stats.adhoc_ops.calls), + stats.adhoc_ops.returns.full, + bdd_get_percentage(stats.adhoc_ops.returns.full, stats.adhoc_ops.calls), + + total_adhoc_lookups, + stats.cache.adhoc.misses, + bdd_get_percentage(stats.cache.adhoc.misses, total_adhoc_lookups), + + stats.gc.times, + stats.gc.nodes_collected, + ((double) stats.gc.runtime / 1000), + + stats.memory.manager, + stats.memory.nodes, + stats.memory.hashtable, + stats.memory.ext_ptrs, + (manager->heap.cache.itetable.nbuckets * sizeof(bdd_hashcache_entry *)), + (manager->heap.cache.itetable.nentries * sizeof(bdd_hashcache_entry)), + (manager->heap.cache.consttable.nbuckets * sizeof(bdd_constcache_entry *)), + (manager->heap.cache.consttable.nentries * sizeof(bdd_constcache_entry)), + stats.memory.adhoc_cache, + tot_frame_mem, + overall_memory, + total_sbrk, + (total_sbrk - overall_memory), + (int) (((total_sbrk - overall_memory) * 100) / overall_memory)); + +#if defined(BDD_MEMORY_USAGE) /* { */ + /* + * Get info from ps. + */ + system("ps -v | egrep 'TIME|sis'"); /* header line and the process in which we are interested */ +#endif /* } */ + +#else /* } else { */ + /* + * Just do the pretty thing of printing out all the + * statistics in a nice pretty (e.g. human readable) way. + */ + (void) bdd_print_stats(stats, stdout); +#endif /* } */ +} + + + diff --git a/sis/bdd_ucb/dmp_node_age.c b/sis/bdd_ucb/dmp_node_age.c new file mode 100644 index 0000000..515eb43 --- /dev/null +++ b/sis/bdd_ucb/dmp_node_age.c @@ -0,0 +1,122 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/dmp_node_age.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/dmp_node_age.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: dmp_node_age.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 01:47:52 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. + * + * Revision 1.1 1992/07/29 00:27:00 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:37 sis + * Initial revision + * + * Revision 1.1 91/04/11 20:59:48 shiple + * Initial revision + * + * + */ + +/* + * bdd_dump_node_ages - dump the ages of all the nodes (summary) + * + * For debugging, we must be able to determine the relative frequency + * of node ages in the heap. This is used to validate the generational + * strategy which says that old things stay and young things die young. + * + * return nothing, just do it. + */ +void +bdd_dump_node_ages(manager, file) +bdd_manager *manager; +FILE *file; +{ + int ages[1000]; /* TODO - big enuf? */ + bdd_nodeBlock *block; + bdd_node *node; + int i; + +#ifndef BDD_DEBUG_AGE /* { */ + (void) fprintf(stderr, "\ +bdd_dump_node_ages: the bdd package is not compiled with DEBUG_AGE\n\ +\tso calling this function cannot produce any results\n\ +"); +#else /* } else { */ + for (i=0; iheap.half[manager->heap.gc.halfspace].inuse.top; + block != NIL(bdd_nodeBlock); block=block->next) { + /* + * Foreach member of the subheap + */ + for (i=0; iused; i++) { + node = &block->subheap[i]; + + /* + * If its free, then print it out + */ + ages[node->age]++; + } + } + +#if defined(BDD_AUTOMATED_STATISTICS_GATHERING) /* { */ + (void) fprintf(file, "age-summary: start\n"); + for (i=0; i /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/external_ptr.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: external_ptr.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 03:01:31 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Added and cleaned up comments. Changed a fail to a bdd_memfail. Added use of bddBlock count. + * Removed all use of "used" field of the structure bdd_bddBlock, from the functions + * bdd_make_external_pointer and new_block. This cleans up a bug fix made previously where + * bdd_t's were not being reused because the used field was not being decremented when a + * bdd_t was freed. Rather than finding a proper implementation for this feature, we are + * abandoning it, at the risk of a slight performance penalty. + * + * Revision 1.1 1992/07/29 00:27:01 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:37 sis + * Initial revision + * + * Revision 1.1 91/04/11 21:00:01 shiple + * Initial revision + * + * + */ + +static void new_block(); + +/* + * bdd_make_external_pointer - make an external pointer + * + * return the external pointer + */ +bdd_t * +bdd_make_external_pointer(manager, node, origin) +bdd_manager *manager; +bdd_node *node; /* may be NIL(bdd_node) */ +string origin; /* a static string - neither allocated nor freed (must be persistent across _all_ time) */ +{ + int i; + bdd_t *new; + + /* + * If there are known not to be any blocks then get one. + * This way the following initialization condition will + * always be known to set the pointer.block != NIL + */ + if (manager->heap.external_refs.free == 0) { + (void) new_block(manager); + } + + BDD_ASSERT(manager->heap.external_refs.free > 0); + + /* + * If the pointer is not defined, then start at the beginning + */ + if (manager->heap.external_refs.pointer.block == NIL(bdd_bddBlock)) { + manager->heap.external_refs.pointer.block = manager->heap.external_refs.map; + manager->heap.external_refs.pointer.index = 0; + } + + BDD_ASSERT(manager->heap.external_refs.pointer.block != NIL(bdd_bddBlock)); + BDD_ASSERT(manager->heap.external_refs.free > 0); + + /* + * Run through the external references using the roving pointer. + * Do not go around more than once (this is controlled by stopping at the total number of + * bdd_t in the map, namely manager->heap.external_refs.nmap). If you find a free one, use it. + * If a free one is not found, then new_block is called after the for loop. + * Note that the index i is never explicitly used in the for loop. It simply keeps track of how + * many bdd_t entries we have examined thus far. + */ + for (i=0; iheap.external_refs.nmap; i++) { + /* + * If the pointer index is at the end of the current block, then move to the next block. + */ + if (manager->heap.external_refs.pointer.index == + sizeof_el (manager->heap.external_refs.pointer.block->subheap)) { + + manager->heap.external_refs.pointer.block = manager->heap.external_refs.pointer.block->next; + manager->heap.external_refs.pointer.index = 0; + + /* + * If the pointer has fallen off the end of the list, then start over. Remember, the list + * of block is not circularly linked. + */ + if (manager->heap.external_refs.pointer.block == NIL(bdd_bddBlock)) { + manager->heap.external_refs.pointer.block = manager->heap.external_refs.map; + } + } + + if ( ! manager->heap.external_refs.pointer.block->subheap[manager->heap.external_refs.pointer.index].free ) { + /* + * It is not free, so go on to the next one + */ + manager->heap.external_refs.pointer.index++; + } else { + /* + * It is free + */ + new = &manager->heap.external_refs.pointer.block->subheap[manager->heap.external_refs.pointer.index++]; + + /* set the values in the external pointer */ + new->free = FALSE; + new->node = node; + new->bdd = manager; +#if defined(BDD_DEBUG_EXT) /* { */ + new->origin = origin; +#endif /* } */ + + /* decrement the number of free external pointers */ + manager->heap.external_refs.free--; + + manager->heap.stats.extptrs.used++; + manager->heap.stats.extptrs.unused--; + + return (new); + } + } + + /* + * No free bdd_ts are available. Allocate a new block. + */ + (void) new_block(manager); + BDD_ASSERT(manager->heap.external_refs.free > 0); + + /* + * Just make a tail-recursive call + * You know it will succeed b/c of the above assertion that free > 0 + */ + return (bdd_make_external_pointer(manager, node, origin)); +} + +/* + * bdd_destroy_external_pointer - destroy an external pointer + * + * return nothing, just do it. + */ +void +bdd_destroy_external_pointer(ext_f) +bdd_t *ext_f; +{ + BDD_ASSERT(ext_f != NIL(bdd_t)); + if (ext_f->free) + return; /* the guy shouldn't be doing this, but no point in failing on it */ + + /* boost the number of free external pointers */ + ext_f->bdd->heap.external_refs.free++; + + /* + * Update the stats. + */ + ext_f->bdd->heap.stats.extptrs.used--; + ext_f->bdd->heap.stats.extptrs.unused++; + + /* destroy the values in the external pointer */ + ext_f->free = TRUE; + ext_f->node = NIL(bdd_node); + ext_f->bdd = NIL(bdd_manager); +} + +/* + * new_block - add a new block to the map + * + * Side-effect the new block onto the beginning of the list + * + * return nothing, just do it. + */ +static void +new_block(manager) +bdd_manager *manager; +{ + bdd_bddBlock *block; + int i; + + /* + * Make a new block. + */ + block = ALLOC(bdd_bddBlock, 1); + if (block == NIL(bdd_bddBlock)) { + (void) bdd_memfail(manager, "new_block"); + } + manager->heap.stats.extptrs.blocks++; + + /* + * Initialize all the entries of the block. + */ + for (i=0; isubheap); i++) { + block->subheap[i].free = TRUE; + block->subheap[i].node = NIL(bdd_node); + block->subheap[i].bdd = NIL(bdd_manager); + } + + /* + * Add the new block to the beginning of the list. + */ + block->next = manager->heap.external_refs.map; + manager->heap.external_refs.map = block; + + /* increment the counts */ + manager->heap.external_refs.free += sizeof_el (block->subheap); + manager->heap.external_refs.nmap += sizeof_el (block->subheap); + + /* make the pointer point to the beginning */ + manager->heap.external_refs.pointer.block = block; + manager->heap.external_refs.pointer.index = 0; + + /* increment the stats */ + manager->heap.stats.extptrs.unused += sizeof_el (block->subheap); + manager->heap.stats.extptrs.total += sizeof_el (block->subheap); +} + +#if defined(BDD_FLIGHT_RECORDER) /* { */ +/* + * bdd_index_of_external_pointer - get the index of the thing + * + * return the index of the thing + */ +int +bdd_index_of_external_pointer(f) +bdd_t *f; +{ + bdd_manager *manager; + bdd_bddBlock *block; + + BDD_ASSERT( ! f->free ); + BDD_ASSERT(f->bdd != NIL(bdd_manager)); + + manager = f->bdd; + + /* + * Find the block which contains f. Then return f's position within the block. + */ + for (block=manager->heap.external_refs.map; block != NIL(bdd_bddBlock); block=block->next) { + if (&block->subheap[0] <= f && f < &block->subheap[sizeof_el (block->subheap)]) + return (((int) f - (int) &block->subheap[0]) / sizeof (block->subheap[0])); + } + + BDD_FAIL("bdd_index_of_external_pointer could not find the bdd_t!"); + /*NOTREACHED*/ +} +#endif /* } */ diff --git a/sis/bdd_ucb/find_or_add.c b/sis/bdd_ucb/find_or_add.c new file mode 100644 index 0000000..b7193e7 --- /dev/null +++ b/sis/bdd_ucb/find_or_add.c @@ -0,0 +1,138 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/find_or_add.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/find_or_add.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:01 $ + * $Log: find_or_add.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:01 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 03:05:06 shiple + * > Version 2.4 + * Prefaced compile time debug switches with BDD_. Renamed resize_tables to resize_hashtable. + * Added code to update hash hits/misses; moved/added comments. + * + * Revision 1.1 1992/07/29 00:27:02 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:38 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:41 shiple + * Initial revision + * + * + */ + +/* + * bdd_find_or_add - find a node in the hashtable or add it + * + * Find a node whose id is given and which has T, E for its data. + * If no such node is in the table, then make a new one. + * + * return the (possibly new) node in the hashtable + */ +bdd_node * +bdd_find_or_add(manager, variableId, T, E) +bdd_manager *manager; +bdd_variableId variableId; +bdd_node *T; +bdd_node *E; +{ + bdd_safeframe frame; + bdd_safenode safe_T, safe_E, + new, chain, ret; + int pos; + + BDD_ASSERT(T != NIL(bdd_node) || variableId == BDD_ONE_ID); + BDD_ASSERT_NOT_BROKEN_HEART(T); + BDD_ASSERT( ! BDD_IS_COMPLEMENT(T) ); + + BDD_ASSERT(E != NIL(bdd_node) || variableId == BDD_ONE_ID); + BDD_ASSERT_NOT_BROKEN_HEART(E); + /* ASSERT: BDD_IS_COMPLEMENT(E) || ! BDD_IS_COMPLEMENT(E) */ + + bdd_safeframe_start(manager, frame); + bdd_safenode_link(manager, safe_T, T); + bdd_safenode_link(manager, safe_E, E); + bdd_safenode_declare(manager, new); + bdd_safenode_declare(manager, chain); + bdd_safenode_declare(manager, ret); + + /* + * Search the chain (short, its length is supposed + * to be less than BDD_HASHTABLE_MAXCHAINLEN). + */ + + pos = bdd_raw_node_hash(manager, variableId, T, E); + + for (chain.node=manager->heap.hashtable.buckets[pos]; + chain.node != NIL(bdd_node); chain.node=chain.node->next) { + + if (chain.node->id == variableId && chain.node->T == T && chain.node->E == E) { + /* + * Found it, blow the frame and return the thing found. + * Update the stats. + */ + bdd_safeframe_end(manager); + manager->heap.stats.cache.hashtable.hits++; + return (chain.node); + } + } + + /* + * Its not there, so add it, but recall that adding a new node to + * the hashtable may cause a garbage-collection. So, we must ensure + * that all values that we want preserved across the gc are tied down. + * + * If one more entry will cause the table to explode, + * then make the table bigger before going on. + */ + if (manager->heap.hashtable.nkeys+1 >= manager->heap.hashtable.rehash_at_nkeys) { + (void) bdd_resize_hashtable(manager); /* definitely don't do THIS if gc is occurring */ + } + + ret.node = bdd_new_node(manager, variableId, T, E, NIL(bdd_node)); + + /* + * Link in the new node. Recompute pos just in case a gc happenned (which would screw up the pos). + */ + pos = bdd_raw_node_hash(manager, variableId, T, E); + + ret.node->next = manager->heap.hashtable.buckets[pos]; + manager->heap.hashtable.buckets[pos] = ret.node; + manager->heap.hashtable.nkeys++; + manager->heap.stats.cache.hashtable.misses++; + + bdd_safeframe_end(manager); + return (ret.node); +} diff --git a/sis/bdd_ucb/garb_collect.c b/sis/bdd_ucb/garb_collect.c new file mode 100644 index 0000000..e3f2d07 --- /dev/null +++ b/sis/bdd_ucb/garb_collect.c @@ -0,0 +1,849 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/garb_collect.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/garb_collect.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: garb_collect.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.4 1993/05/04 15:30:57 sis + * BDD package updates. Tom Shiple 5/4/93. + * + * Revision 1.3 1993/05/03 20:34:08 shiple + * Fixed bug in scan_newhalf, which caused some entries not to be scanned + * over during the second call to scan_newhalf. + * + * Revision 1.2 1992/09/19 03:13:57 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Removed some dead code. In relocate, changed location of declaration of reg_old. + * Fixed bugs in scan_hashcache and scan_constcache. Before, node pointers + * were not being regularized before they were checked for BROKEN_HEART, causing some good entries + * to be killed. In scan_adhoccache, fixed core leak if item wasn't copied over. Also, now + * scan adhoc_cache after garbage collection, rather than at beginning. Changed ITE and ITE_const + * caches to be arrays of pointers. Remember value of manager->heap.cache.*.on for garbage collection. + * Moved static function declarations to top of file. In scan_hashcache and scan_constcache, first + * check if there are no entries in the cache; st check if there are no entries in the cache. + * + * Revision 1.1 1992/07/29 00:27:03 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:38 sis + * Initial revision + * + * Revision 1.2 91/05/10 22:14:13 shiple + * Fixed a bug in bdd_garbage_collect. New buckets for the hashtable + * were being needlessly created on each gc, and old buckets were not + * being freed. Now, we just reuse old buckets. + * + * Revision 1.1 91/03/27 14:35:41 shiple + * Initial revision + * + * + */ + +static void flip_spaces(); +static void scan_manager(); +static void scan_newhalf(); +static void scan_cache(); +static bdd_node *relocate(); +static void scan_adhoccache(); +static void scan_hashcache(); +static void scan_constcache(); + +void +bdd_set_gc_mode(bdd, no_gc) +bdd_manager *bdd; +boolean no_gc; /* this is inverted for historical reasons */ +{ + bdd->heap.gc.on = ! no_gc; + +#if defined(BDD_DEBUG) /* { */ + fprintf(stderr, "set_gc_mode: garbage-collection is now %s\n", bdd->heap.gc.on ? "on": "off"); +#endif /* } */ +} + +#if defined(BDD_DEBUG_LIFESPAN) /* { */ +static void discover_terminations(); +#endif /* } */ + +/* + * bdd_garbage_collect - perform a garbage-collection + * + * A simple stop-and-copy garbage-collection is performed. + * There is only a single generation at this point, so the + * stop-and-copy is rather straightforward. + * + * return nothing, just do it. + */ +void +bdd_garbage_collect(manager) +bdd_manager *manager; +{ + static boolean busyp = FALSE; + int i; + long time; + boolean itetable_on, consttable_on, adhoc_on; + unsigned int prev_nodes_used; + + if ( ! manager->heap.gc.on ) { +#if defined(BDD_DEBUG_GC) /* { */ + printf("garbage_collect: the garbage-collector is not enabled (skipping)\n"); +#endif /* } */ + return; + } + + /* + * Mark the amount of time spent garbage collecting. + */ + time = util_cpu_time(); + + /* + * Note the number of nodes currently in use. + */ + prev_nodes_used = manager->heap.stats.nodes.used; + + /* + * Defensive programming. + */ + if (busyp) { + fail("bdd_garbage_collect: the garbage-collector is already running"); + } + + /* + * Not handling this case now. + */ + if (manager->heap.gc.status.open_generators > 0) { + fail("bdd_garbage_collect: there are open generators during the garbage collection"); + } + +#if defined(BDD_DEBUG_GC) /* { */ + (void) printf("before garbage collection #%d ...\n", manager->heap.stats.gc.times+1); + (void) bdd_assert_heap_correct(manager); +#endif /* } */ + + busyp = TRUE; + + /* + * Defensive progamming. Turn off caching while garbage collection; prevents + * any attempt to insert or lookup in the caches. Remember the current values. + */ + itetable_on = manager->heap.cache.itetable.on; + consttable_on = manager->heap.cache.consttable.on; + adhoc_on = manager->heap.cache.adhoc.on; + manager->heap.cache.itetable.on = FALSE; + manager->heap.cache.consttable.on = FALSE; + manager->heap.cache.adhoc.on = FALSE; + + /* + * Flip sense of old space and new space. + */ + (void) flip_spaces(manager); + + /* + * Relocate all bdd_nodes directly pointed to by root pointers, into new space. + */ + (void) scan_manager(manager); + + manager->heap.gc.during.start.block = manager->heap.half[manager->heap.gc.halfspace].inuse.top; + manager->heap.gc.during.start.index = 0; + + /* + * Reset the hashtable. The function scan_newhalf rehashes all the nodes into the table. + * Note that since garbage collection possibly reduces the number of bdd_nodes, maybe the + * size of this table should be reduced. + */ + manager->heap.hashtable.nkeys = 0; + for (i = 0; i < manager->heap.hashtable.nbuckets; i++) { + manager->heap.hashtable.buckets[i] = NIL(bdd_node); + } + + (void) scan_newhalf(manager); + (void) scan_cache(manager); + + /* + * In the current implementation, scan_cache does not relocate any nodes. Therefore, there + * are no new additional nodes in new space to scan. Thus, the following call to scan_newhalf + * is superflous. + */ + (void) scan_newhalf(manager); + + manager->heap.stats.gc.times++; + manager->heap.cache.itetable.on = itetable_on; + manager->heap.cache.consttable.on = consttable_on; + manager->heap.cache.adhoc.on = adhoc_on; + manager->heap.stats.gc.nodes_collected += (prev_nodes_used - manager->heap.stats.nodes.used); + busyp = FALSE; + +#if defined(BDD_DEBUG) /* { */ +#if defined(BDD_DEBUG_GC) || defined(BDD_DEBUG_GC_STATS) /* { */ + (void) printf("... after garbage collection #%d\n", manager->heap.stats.gc.times); + (void) bdd_dump_manager_stats(manager); +#if defined(BDD_DEBUG_GC) /* { */ + (void) bdd_assert_heap_correct(manager); +#endif /* } */ +#endif /* } */ +#if defined(BDD_DEBUG_AGE) || defined(BDD_DEBUG_LIFESPAN) /* { */ + manager->debug.gc.age++; /* one gc older now ... */ +#endif /* } */ +#if defined(BDD_DEBUG_LIFESPAN) /* { */ + /* + * Process terminations and then log the fact that it + * is one age older now (for the newly created ones next time) + */ + (void) discover_terminations(manager); + (void) fprintf(manager->debug.lifespan.trace, "g %d\n", manager->debug.gc.age); +#endif /* } */ +#endif /* } */ + + /* + * Accumulate the CPU time. + */ + manager->heap.stats.gc.runtime += util_cpu_time() - time; + +} + +/* + * flip_spaces - do exactly that, invert the sense of oldspace and newspace + * + * return nothing, just do it. + */ +static void +flip_spaces(manager) +bdd_manager *manager; +{ + /* + * Flip the halfspace + */ + manager->heap.gc.halfspace = ! manager->heap.gc.halfspace; + + /* + * NOTE: The whole point of having unique id's is that they are in + * fact unique over the life of the (conceptual) object. So you can + * identify an object by its uniqueId at all times. Note that with + * each (copying) garbage-collection the data is copied into a new + * bdd_node, BUT the object is not given a new uniqueId. The uniqueId's + * thus are a denotation of the value in a node. Thus, there is no need + * to reset manager->debug.gc.uniqueId at this point. + */ + + /* + * Concatenate the free list onto the tail of the inuse list + * Then flip the sense of the inuse list and the free list + * thereby making everything on the free list. + */ + *manager->heap.half[manager->heap.gc.halfspace].inuse.tail = + manager->heap.half[manager->heap.gc.halfspace].free; + manager->heap.half[manager->heap.gc.halfspace].free = + manager->heap.half[manager->heap.gc.halfspace].inuse.top; + + manager->heap.half[manager->heap.gc.halfspace].inuse.top = NIL(bdd_nodeBlock); + manager->heap.half[manager->heap.gc.halfspace].inuse.tail = + &manager->heap.half[manager->heap.gc.halfspace].inuse.top; + + manager->heap.pointer.block = NIL(bdd_nodeBlock); + manager->heap.pointer.index = 0; + + manager->heap.stats.nodes.used = 0; + manager->heap.stats.nodes.unused = manager->heap.stats.nodes.total; + + /* + * The hashtable and caches are not touched until + * AFTER all of the garbage-collection is done. + */ +} + + +/* + * scan_manager - scan all root pointers in the manager + * + * The old buckets must be destroyed and ALL bdd_node objects + * must be rehashed into a new hashtable. This is because the + * position in the hashtable is a hashfunction of the object + * address. The address moves in a copying garbage-collector + * so objects must be rehashed into the new table. + * + * Take all the stuff which needs to be saved and put it in the + * flipped stuffd. This way the garbage collector can operate + * using bdd_find_or_add using a clean hashtable; the old hashtable + * is saved in the flipped stuff. + * + * Root pointers: + * bdd.one - the one + * heap.external_refs - external references held by the user + * heap.internal_refs - internal references on the stack + * + * return nothing, just do it. + */ +static void +scan_manager(manager) +bdd_manager *manager; +{ + int i; + bdd_safeframe *sf; + bdd_safenode *sn; + bdd_bddBlock *b; + + /* + * The one one + */ + manager->bdd.one = relocate(manager, manager->bdd.one); + + /* + * DO NOT use the hash table as a set of root pointers. Think about it. + * You would be using the data structure which contains ALL cells in the + * heap as the set of root pointers into the heap. There would be no + * garbage generated at all. + * + * The hash table therefore is NOT a root pointer + * + * Hash Table + */ + + /* + * External references + */ + for (b=manager->heap.external_refs.map; b != NIL(bdd_bddBlock); b=b->next) { + for (i=0; isubheap); i++) { + if ( ! b->subheap[i].free ) + b->subheap[i].node = relocate(manager, b->subheap[i].node); + } + } + + /* + * Internal references + */ + for (sf=manager->heap.internal_refs.frames; sf != NIL(bdd_safeframe); sf=sf->prev) { + for (sn=sf->nodes; sn != NIL(bdd_safenode); sn=sn->next) { + /* get them both without worry (one or the other will be nil */ + if (sn->arg != NIL(bdd_node *)) + *sn->arg = relocate(manager, *sn->arg); + sn->node = relocate(manager, sn->node); + } + } + + /* + * DO NOT use the ITE, ITE_const, or adhoc caches as a root pointers right now. + * Wait until after the scan of the newhalf and then + * search for forwarded pointers in the cache. Wherever + * there are such, then keep those nodes; others are + * nilled out because the objects referenced are dead. + * + * See scan_cache() below and how it is used on conjunction + * with a second pass of scan_newhalf above. + * + */ +} + +/* + * scan_newhalf - scan the new half of memory faulting in stuff + * + * The transitive fanin of objects is faulted in. + * + * NOTE (and note it well): this function must change drastically if + * any of a number of preconditions are violated: + * 1) there are multiple types of objects on multiple page types + * 2) multiple generations are used + * + * There is only one object type now (the bdd_node*), and so the relocate + * and scan functions are effectively trivial; the scan function for + * example is completely inlined here and is only a figment of the paradigm. + * + * If multiple pages types are used, then multiple passes over the page + * frontier must be made in order to get the transitive closure on the space + * + * If multiple generations are used, then much needs to be rethought. + * + * return nothing, just do it. + */ +static void +scan_newhalf(manager) +bdd_manager *manager; +{ + bdd_nodeBlock *block; + bdd_node *node; + boolean pastp; + int i, limit, pos; + + BDD_ASSERT(manager->heap.gc.during.start.block != NIL(bdd_nodeBlock)); + + /* + * The newhalf scan + */ + pastp = FALSE; /* get inside the loop on the 1st go-around */ + + for (block=manager->heap.gc.during.start.block; ! pastp; block=block->next) { + pastp = block == manager->heap.pointer.block ? TRUE: FALSE; + limit = pastp ? manager->heap.pointer.index: sizeof_el (block->subheap); + + for (i=manager->heap.gc.during.start.index; isubheap[i]; + +#if defined(BDD_DEBUG_GC) /* { */ + BDD_ASSERT(node->halfspace == manager->heap.gc.halfspace); +#endif /* } */ + + /* + * Relocate T and E + */ + node->T = relocate(manager, node->T); + node->E = relocate(manager, node->E); + + /* + * Relink the node (which is now completely defined) + * into the hashtable; this gets all nodes in the newspace + */ + pos = bdd_node_hash(manager, node); + node->next = manager->heap.hashtable.buckets[pos]; + manager->heap.hashtable.buckets[pos] = node; + manager->heap.hashtable.nkeys++; + + /* + * We must evaluate this again because + * relocate() changed pointer.{block,index} + */ + pastp = block == manager->heap.pointer.block ? TRUE: FALSE; + limit = pastp ? manager->heap.pointer.index: sizeof_el (block->subheap); + } + manager->heap.gc.during.start.index = 0; + } + + manager->heap.gc.during.start.block = manager->heap.pointer.block; + manager->heap.gc.during.start.index = manager->heap.pointer.index; +} + +/* + * scan_cache - scan the cache to kill dead entries + * + * WATCHOUT - The cache must be scanned passively to ensure that + * it does not become a source of root pointers (besides this phase + * occurs a bit late for that). + * + * The deal is that we want to invalidate cache entries which do + * not consist entirely of forwarded pointers. These entries were obviously + * not forwarded by being needed elsewhere; they are dead. + * + * return nothing, just do it. + */ +static void +scan_cache(manager) +bdd_manager *manager; +{ + /* + * Scan all the caches. + */ + (void) scan_hashcache(manager); + (void) scan_constcache(manager); + (void) scan_adhoccache(manager); +} + +static void +scan_hashcache(manager) +bdd_manager *manager; +{ + boolean unused; + int i, pos; + bdd_hashcache_entry tmp; + bdd_hashcache_entry *e, *old_e, **old_buckets; + bdd_node *reg_old_f, *reg_old_g, *reg_old_h, *reg_old_data; + + /* + * If there are no entries in the cache, then there is nothing to scan. + */ + if (manager->heap.cache.itetable.nentries == 0) { + return; + } + + if (manager->heap.cache.itetable.invalidate_on_gc) { + /* + * If just invalidating, then invalidate (only) + */ +#if defined(BDD_DEBUG_GC) /* { */ + (void) printf("... invalidating itetable cache\n"); +#endif /* } */ + + for (i = 0; i < manager->heap.cache.itetable.nbuckets; i++) { + e = manager->heap.cache.itetable.buckets[i]; + if (e != NIL(bdd_hashcache_entry)) { + FREE(e); + manager->heap.cache.itetable.buckets[i] = NIL(bdd_hashcache_entry); + } + } + } else { + /* + * Otherwise the cache must be updated through a rehashing + * because all of the keys in the itetable have been changed. + */ + + /* + * Save the old one + */ + old_buckets = manager->heap.cache.itetable.buckets; + + /* + * Make a new clean one so we can rehash into it + */ + manager->heap.cache.itetable.buckets = ALLOC(bdd_hashcache_entry *, manager->heap.cache.itetable.nbuckets); + if (manager->heap.cache.itetable.buckets == NIL(bdd_hashcache_entry *)) + (void) bdd_memfail(manager, "scan_hashcache"); + for (i = 0; i < manager->heap.cache.itetable.nbuckets; i++) { + manager->heap.cache.itetable.buckets[i] = NIL(bdd_hashcache_entry); + } + + /* + * ... then try to keep as many of the old cache entries as possible + */ + manager->heap.cache.itetable.nentries = 0; + for (i = 0; i < manager->heap.cache.itetable.nbuckets; i++) { + old_e = old_buckets[i]; /* to make it textually easier to read */ + if (old_e != NIL(bdd_hashcache_entry)) { + + /* + * If ALL of the four pointers were forwarded, then we will keep this entry. + * (Note: An alternate policy would be to keep the entry if ANY of the four pointers + * were forwarded. In this case, non-forwarded pointers would be relocated, + * thus necessitating an additional call to scan_newhalf after the call to scan_cache.) + * + * We must regularize the node pointers before we check for BROKEN_HEART. + */ + reg_old_f = BDD_REGULAR(old_e->ITE.f); + reg_old_g = BDD_REGULAR(old_e->ITE.g); + reg_old_h = BDD_REGULAR(old_e->ITE.h); + reg_old_data = BDD_REGULAR(old_e->data); + + if (reg_old_data != NIL(bdd_node) && + (BDD_BROKEN_HEART(reg_old_f) && BDD_BROKEN_HEART(reg_old_g) && + BDD_BROKEN_HEART(reg_old_h) && BDD_BROKEN_HEART(reg_old_data))) { + /* + * Since broken heart is set on all 4 nodes, relocate will just + * use the forward pointer, and set the proper phase of the pointer. + */ + tmp.ITE.f = relocate(manager, old_e->ITE.f); + tmp.ITE.g = relocate(manager, old_e->ITE.g); + tmp.ITE.h = relocate(manager, old_e->ITE.h); + tmp.data = relocate(manager, old_e->data); + + /* + * Canonicalize the ITE with the same algorithm that was used + * to canonicalize the ITE inputs when the cache was created. + */ + (void) bdd_ite_canonicalize_ite_inputs(manager, &tmp.ITE.f, &tmp.ITE.g, &tmp.ITE.h, &unused); + + /* + * Get the hash position for the entry in the new cache. If the position is already + * occupied, then old_e will not be rehashed; it's lost; If the position is not + * occupied, then we can simply reuse the memory of the old entry. We cannot use + * bdd_hashcache_insert because it doesn't work when the cache is turned off. + */ + pos = bdd_ITE_hash(manager, tmp.ITE.f, tmp.ITE.g, tmp.ITE.h); + if (manager->heap.cache.itetable.buckets[pos] != NIL(bdd_hashcache_entry)) { + FREE(old_e); + } else { + *old_e = tmp; + manager->heap.cache.itetable.buckets[pos] = old_e; + manager->heap.cache.itetable.nentries++; + } + } else { + /* + * old_e points to some stale data, and thus cannot be kept. Free memory. + */ + FREE(old_e); + } + } /* close: if (old_e != NIL(bdd_hashcache_entry)) { */ + } /* close: for (i = 0; i < manager->heap.cache.itetable.nbuckets; i++) { */ + + /* + * We are done rehashing. Get rid of the old_buckets. + */ + FREE(old_buckets); + } +} + +static void +scan_constcache(manager) +bdd_manager *manager; +{ + boolean unused; + int i, pos; + bdd_constcache_entry tmp; + bdd_constcache_entry *e, *old_e, **old_buckets; + bdd_node *reg_old_f, *reg_old_g, *reg_old_h; + + /* + * If there are no entries in the cache, then there is nothing to scan. + */ + if (manager->heap.cache.consttable.nentries == 0) { + return; + } + + if (manager->heap.cache.consttable.invalidate_on_gc) { + /* + * If just invalidating, then invalidate (only) + */ +#if defined(BDD_DEBUG_GC) /* { */ + (void) printf("... invalidating consttable cache\n"); +#endif /* } */ + + for (i = 0; i < manager->heap.cache.consttable.nbuckets; i++) { + e = manager->heap.cache.consttable.buckets[i]; + if (e != NIL(bdd_constcache_entry)) { + FREE(e); + manager->heap.cache.consttable.buckets[i] = NIL(bdd_constcache_entry); + } + } + } else { + /* + * Otherwise the cache must be updated through a rehashing + * because all of the keys in the consttable have been changed. + */ + + /* + * Save the old one + */ + old_buckets = manager->heap.cache.consttable.buckets; + + /* + * Make a new clean one so we can rehash into it + */ + manager->heap.cache.consttable.buckets = ALLOC(bdd_constcache_entry *, manager->heap.cache.consttable.nbuckets); + if (manager->heap.cache.consttable.buckets == NIL(bdd_constcache_entry *)) { + (void) bdd_memfail(manager, "scan_constcache"); + } + for (i = 0; i < manager->heap.cache.consttable.nbuckets; i++) { + manager->heap.cache.consttable.buckets[i] = NIL(bdd_constcache_entry); + } + + /* + * ... then try to keep as many of the old cache entries as possible + */ + manager->heap.cache.consttable.nentries = 0; + for (i = 0; i < manager->heap.cache.consttable.nbuckets; i++) { + old_e = old_buckets[i]; /* to make it textually easier to read */ + if (old_e != NIL(bdd_constcache_entry)) { + + /* + * If ALL of the three pointers were forwarded, then we will keep this entry. + * (Note: An alternate policy would be to keep the entry if ANY of the three pointers + * were forwarded. In this case, non-forwarded pointers would be relocated, + * thus necessitating an additional call to scan_newhalf after the call to scan_cache.) + * + * We must regularize the node pointers before we check for BROKEN_HEART. + */ + reg_old_f = BDD_REGULAR(old_e->ITE.f); + reg_old_g = BDD_REGULAR(old_e->ITE.g); + reg_old_h = BDD_REGULAR(old_e->ITE.h); + + if (old_e->data != bdd_status_unknown && + (BDD_BROKEN_HEART(reg_old_f) && BDD_BROKEN_HEART(reg_old_g) && BDD_BROKEN_HEART(reg_old_h) )) { + /* + * Since broken heart is set on all 3 nodes, relocate will just + * use the forward pointer, and set the proper phase of the pointer. + */ + tmp.ITE.f = relocate(manager, old_e->ITE.f); + tmp.ITE.g = relocate(manager, old_e->ITE.g); + tmp.ITE.h = relocate(manager, old_e->ITE.h); + tmp.data = old_e->data; + + /* + * Canonicalize the ITE with the same algorithm that was used + * to canonicalize the ITE inputs when the cache was created. + */ + (void) bdd_ite_canonicalize_ite_inputs(manager, &tmp.ITE.f, &tmp.ITE.g, &tmp.ITE.h, &unused); + + /* + * Get the hash position for the entry in the new cache. If the position is already + * occupied, then old_e will not be rehashed; it's lost; If the position is not + * occupied, then we can simply reuse the memory of the old entry. + */ + pos = bdd_const_hash(manager, tmp.ITE.f, tmp.ITE.g, tmp.ITE.h); + if (manager->heap.cache.consttable.buckets[pos] != NIL(bdd_constcache_entry)) { + FREE(old_e); + } else { + *old_e = tmp; + manager->heap.cache.consttable.buckets[pos] = old_e; + manager->heap.cache.consttable.nentries++; + } + } else { + /* + * Entry cannot be kept. Free memory. + */ + FREE(old_e); + } + } /* close: if (old_e != NIL(bdd_constcache_entry)) { */ + } /* close: for (i = 0; i < manager->heap.cache.consttable.nbuckets; i++) { */ + + /* + * We are done rehashing. Get rid of the old_buckets. + */ + FREE(old_buckets); + } +} + +static void +scan_adhoccache(manager) +bdd_manager *manager; /* adhoc.table is not NIL */ +{ + st_table *old; + st_generator *gen; + bdd_adhoccache_key *k; + bdd_node *v; + bdd_node *reg_old_f, *reg_old_g, *reg_old_v; + + + if (manager->heap.cache.adhoc.table == NIL(st_table)) + return; /* nothing to do */ + + /* + * Save the current table (for later traversal) and get a new adhoc + * cache. Then stick all the entries in the old adhoc cache in to + * the new adhoc cache. Destroy the old table (but not its keys + * (which are now still in use). + */ + old = manager->heap.cache.adhoc.table; + manager->heap.cache.adhoc.table = NIL(st_table); + + (void) bdd_adhoccache_init(manager); /* get a new one */ + + gen = st_init_gen(old); + + while (st_gen(gen, (refany*) &k, (refany*) &v)) { + /* + * We must regularize the node pointers before we check for BROKEN_HEART. + */ + reg_old_f = BDD_REGULAR(k->f); + reg_old_g = BDD_REGULAR(k->g); + reg_old_v = BDD_REGULAR(v); + + if (BDD_BROKEN_HEART(reg_old_f) && BDD_BROKEN_HEART(reg_old_g) && + (reg_old_v == NIL(bdd_node) || BDD_BROKEN_HEART(reg_old_v))) { + /* + * Policy: if ALL of the entries in this cache have been + * forwarded, then keep the cache entry in whole. + */ + k->f = relocate(manager, k->f); + k->g = relocate(manager, k->g); + v = relocate(manager, v); + (void) st_insert(manager->heap.cache.adhoc.table, (refany) k, (refany) v); + } else { + /* + * Else, simply don't copy the cache entry over to the new table. + */ + FREE(k); + } + } + + (void) st_free_gen(gen); + (void) st_free_table(old); /* but DON'T free its keys or values */ +} + +/* + * relocate - the all-important copy function copying from oldspace to newspace + * + * This function can take either regular or complemented pointers as argument. + * The result pointer is returned in the same phase as the caller. The + * object referred to is copied to the new space and a forwarding pointer is + * created; a broken heart. This broken heart is always in the positive phase + * and it is up to the caller to refer to the new object in whatever phase + * is desired. + * + * return the new object in the new space + */ +static bdd_node * +relocate(manager, old) +bdd_manager *manager; +bdd_node *old; /* may be NIL(bdd_node), a regular or complemented pointer */ +{ + bdd_node *new, *reg_old; + boolean complemented; + + if (old == NIL(bdd_node)) { + /* + * This isn't really an object, so it must be special-cased + */ + new = NIL(bdd_node); + complemented = FALSE; + } else { + /* + * The broken hearts must deal with regular pointers + */ + reg_old = BDD_REGULAR(old); + complemented = BDD_IS_COMPLEMENT(old); + + if (BDD_BROKEN_HEART(reg_old)) { + /* + * A forwarded object; take the forwarded value + */ + new = BDD_FORWARD_POINTER(reg_old); + } else { + /* + * Must copy over to the new space with the (re)allocate function + * So, use a special find_or_add operation that always copies. + */ + new = bdd_new_node(manager, reg_old->id, reg_old->T, reg_old->E, reg_old); + BDD_SET_FORWARD_POINTER(reg_old, new); + } + } + + BDD_ASSERT_NOT_BROKEN_HEART(new); + BDD_ASSERT_REGNODE(new); + + new = ! complemented ? new: BDD_NOT(new); + + return (new); +} + +#if defined(BDD_DEBUG_LIFESPAN) /* { */ +/* + * discover_terminations - discover and log lifespans which terminated + * + * return nothing, just do it. + */ +static void +discover_terminations(manager) +bdd_manager *manager; +{ + bdd_nodeBlock *block; + bdd_node *node; + int old_halfspace, i; + + old_halfspace = ! manager->heap.gc.halfspace; + + for (block=manager->heap.half[old_halfspace].inuse.top; + block != NIL(bdd_nodeBlock); block=block->next) { + for (i=0; iused; i++) { + node = &block->subheap[i]; + + /* + * If its not a broken heart, then it died (end of story). + */ + if ( ! BDD_BROKEN_HEART(node) ) { + fprintf(manager->debug.lifespan.trace, "d %d %d\n", node->uniqueId, node->age); + } + } + } +} +#endif /* } */ diff --git a/sis/bdd_ucb/hash_cache.c b/sis/bdd_ucb/hash_cache.c new file mode 100644 index 0000000..d802a6a --- /dev/null +++ b/sis/bdd_ucb/hash_cache.c @@ -0,0 +1,280 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/hash_cache.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/hash_cache.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: hash_cache.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.5 1993/05/04 15:30:57 sis + * BDD package updates. Tom Shiple 5/4/93. + * + * Revision 1.4 1993/05/03 20:28:37 shiple + * In insert routine, changed policy on what to do if a new key cannot be + * allocated because it would cause the memory limit to be exceeded. + * Before, just returned, without inserting. Now, insert, even if memory + * limit will be exceeded. + * + * Revision 1.3 1992/09/29 19:37:32 shiple + * Fixed bug in conditional to resize cache; ints were not being cast to floats + * + * Revision 1.2 1992/09/19 03:16:52 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added comment on hashtable vs. itetable. + * Changed ITE and ITE_const caches to be arrays of pointers. Added resize_itetable function. + * Add usage of bdd_will_exceed_mem_limit in bdd_hashcache_insert and resize_itetable. + * + * Revision 1.1 1992/07/29 00:27:04 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:39 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:42 shiple + * Initial revision + * + * + */ + +/* + * NOTE: The "hashcache" should really have been named the "itecache", since it caches + * results of ITE operations. The name "hashtable" has been changed to "itetable" in two + * places: bdd_stats->cache.itetable and manager->heap.cache.itetable. However, many instances + * of the term hashcache, such as the functions names below, persist. Also, note that "hashtable" + * is sometimes used to refer to the primary table for bdd_nodes that maintains uniqueness. + */ + +static void resize_itetable(); + +/* + * bdd_hashcache_insert - perform an insertion into the cache + * + * return nothing, just do it. + */ +void +bdd_hashcache_insert(manager, ITE_f, ITE_g, ITE_h, data) +bdd_manager *manager; +bdd_node *ITE_f; +bdd_node *ITE_g; +bdd_node *ITE_h; +bdd_node *data; +{ + int pos; + bdd_hashcache_entry *entry; + + BDD_ASSERT_NOTNIL(ITE_f); + BDD_ASSERT_NOTNIL(ITE_g); + BDD_ASSERT_NOTNIL(ITE_h); + BDD_ASSERT_NOTNIL(data); + + if ( ! manager->heap.cache.itetable.on ) { + /* + * Has no effect if caching is off. + */ + return; + } + + pos = bdd_ITE_hash(manager, ITE_f, ITE_g, ITE_h); + entry = manager->heap.cache.itetable.buckets[pos]; + + if (entry != NIL(bdd_hashcache_entry)) { + /* + * An entry already exists at pos. Since we are using an open-addressing + * scheme, we will just reuse the memory of this entry. Number of entries + * stays constant. + */ + manager->heap.stats.cache.itetable.collisions++; + } else { + /* + * Must allocate a new entry, since one does not already exist at pos. It's possible + * that allocating a bdd_hashcache_entry will cause the manager's + * memory limit to be exceeded. However, we allow this to happen, because the alternative + * is that we don't cache this call. Not caching new calls could be deadly for runtime. + */ + entry = ALLOC(bdd_hashcache_entry, 1); + if (entry == NIL(bdd_hashcache_entry)) { + (void) bdd_memfail(manager, "bdd_hashcache_insert"); + } + manager->heap.cache.itetable.buckets[pos] = entry; + manager->heap.cache.itetable.nentries++; + } + + entry->ITE.f = ITE_f; + entry->ITE.g = ITE_g; + entry->ITE.h = ITE_h; + entry->data = data; + + manager->heap.stats.cache.itetable.inserts++; + + /* + * Check to see if table needs resizing. We base the decision on the ratio of the number of entries to the number + * of buckets. + */ + if ( (unsigned int) (((float) manager->heap.cache.itetable.nentries + / (float) manager->heap.cache.itetable.nbuckets) * 100) + > manager->heap.cache.itetable.resize_at) { + (void) resize_itetable(manager); + } +} + +/* + * bdd_hashcache_lookup - perform a lookup in the cache + * + * return {TRUE, FALSE} on {found, not found}. + */ +boolean +bdd_hashcache_lookup(manager, f, g, h, value) +bdd_manager *manager; +bdd_node *f; +bdd_node *g; +bdd_node *h; +bdd_node **value; /* return */ +{ + int pos; + bdd_hashcache_entry *entry; + + if ( ! manager->heap.cache.itetable.on ) { + /* + * Always fails if caching is off. + */ + return (FALSE); + } + + pos = bdd_ITE_hash(manager, f, g, h); + entry = manager->heap.cache.itetable.buckets[pos]; + + if (entry != NIL(bdd_hashcache_entry)) { + /* + * Entry exists at pos. See if it matches. If not (a miss) return. If it does match + * (a hit), then will drop out of IF and set value. + */ + if (entry->data == NIL(bdd_node) || (entry->ITE.f != f || entry->ITE.g != g || entry->ITE.h != h)) { + manager->heap.stats.cache.itetable.misses++; + return (FALSE); + } + } else { + /* + * No entry exists at pos. Definitely a miss. + */ + manager->heap.stats.cache.itetable.misses++; + return (FALSE); + } + + manager->heap.stats.cache.itetable.hits++; + + *value = entry->data; + return (TRUE); +} + +/* + * resize_itetable + * + * Make the ITE cache larger. Perform a rehash to map all of the old + * stuff into this new larger world. Note that since we don't maintain collision chains, + * some stuff may be lost. + */ +static void +resize_itetable(manager) +bdd_manager *manager; +{ + unsigned int old_nbuckets, next_hash_prime; + bdd_hashcache_entry **old_buckets, *old_entry; + int i, pos; + + /* + * If the max_size has already been exceeded, then just return. + */ + if (manager->heap.cache.itetable.nbuckets > manager->heap.cache.itetable.max_size) { + return; + } + + /* + * Get the next hash prime. If allocating a new table will cause the manager memory limit to + * be exceeded, then just return. Trading off time in favor of space. + */ + next_hash_prime = bdd_get_next_hash_prime(manager->heap.cache.itetable.nbuckets); + if (bdd_will_exceed_mem_limit(manager, (next_hash_prime * sizeof(bdd_hashcache_entry *)), FALSE) == TRUE) { + return; + } + + /* + * Save the old buckets. + */ + old_nbuckets = manager->heap.cache.itetable.nbuckets; + old_buckets = manager->heap.cache.itetable.buckets; + + /* + * Get the new size and allocate the new table. We are growing by roughly a factor of two. + * If there isn't sufficient memory, don't fail: the cache + * is meant to enhance performance, but we can still continue even if we can't resize. + */ + manager->heap.cache.itetable.nbuckets = next_hash_prime; + manager->heap.cache.itetable.buckets = ALLOC(bdd_hashcache_entry *, manager->heap.cache.itetable.nbuckets); + if (manager->heap.cache.itetable.buckets == NIL(bdd_hashcache_entry *)) { + manager->heap.cache.itetable.nbuckets = old_nbuckets; + manager->heap.cache.itetable.buckets = old_buckets; + return; + } + + /* + * Initialize all the entries to NIL. + */ + for (i = 0; i < manager->heap.cache.itetable.nbuckets; i++) { + manager->heap.cache.itetable.buckets[i] = NIL(bdd_hashcache_entry); + } + + /* + * Remap all of the ITE cache entries to the new larger cache. + */ + manager->heap.cache.itetable.nentries = 0; + for (i = 0; i < old_nbuckets; i++) { + old_entry = old_buckets[i]; + if (old_entry != NIL(bdd_hashcache_entry)) { + + /* + * Get the hash position for the entry in the new cache. If the position is already + * occupied, then old_entry will not be rehashed; it's lost; If the position is not + * occupied, then simply set the new cache bucket pointer to old_entry. + */ + pos = bdd_hashcache_entry_hash(manager, old_entry); + if (manager->heap.cache.itetable.buckets[pos] != NIL(bdd_hashcache_entry)) { + FREE(old_entry); + } else { + manager->heap.cache.itetable.buckets[pos] = old_entry; + manager->heap.cache.itetable.nentries++; + } + } + } + + /* + * Free the array of buckets. Note that the entries of the table were simply + * moved over to the new table. + */ + FREE(old_buckets); + +} + diff --git a/sis/bdd_ucb/ite.c b/sis/bdd_ucb/ite.c new file mode 100644 index 0000000..2b0db96 --- /dev/null +++ b/sis/bdd_ucb/ite.c @@ -0,0 +1,518 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/ite.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/ite.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: ite.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.4 1993/07/19 18:03:50 shiple + * Fixed calls to bdd_ite_quick_cofactor, which are compiled only when DEBUG flags are on. + * + * Revision 1.3 1993/01/22 21:39:31 shiple + * Cleaned up some comments. + * + * Revision 1.2 1992/09/19 01:48:12 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. + * + * Revision 1.1 1992/07/29 00:27:06 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:39 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:43 shiple + * Initial revision + * + * + */ + +/* + * bdd__ITE_ - perform the ITE recursion + * + * WATCHOUT - do NOT use ``return (r)'' in here unless bdd_safeframe_end() + * has been used to deallocate the safeframe. Unfortunately we are not + * using C++ and so we cannot have the compiler do this for us. This routine + * must be coded carefully to avoid not deallocating frames and the like. + * The whole goal here is to safeguard ourselves in case the garbage collector + * is called during the (long) recursive call to bdd__ITE_() + * + * ITE Identities + * ITE(1, G, H) = G + * ITE(0, G, H) = H + * ITE(F, G, G) = G + * ITE(F, 1, 0) = F + * ... and others in canonicalize_ite_inputs ... + * + * return the canonical bdd_node* held by the manager + */ +bdd_node * +bdd__ITE_(manager, f, g, h) +bdd_manager *manager; +bdd_node *f; +bdd_node *g; +bdd_node *h; +{ + bdd_safeframe frame; + bdd_safenode safe_f, safe_g, safe_h; + bdd_safenode ret; + bdd_safenode reg_f, f_v, f_nv; + bdd_safenode reg_g, g_v, g_nv; + bdd_safenode reg_h, h_v, h_nv; + bdd_safenode ite_T, ite_E; + bdd_variableId varId; + boolean complement; + + BDD_ASSERT_NOTNIL(f); + BDD_ASSERT_NOTNIL(g); + BDD_ASSERT_NOTNIL(h); + + bdd_safeframe_start(manager, frame); + bdd_safenode_link(manager, safe_f, f); + bdd_safenode_link(manager, safe_g, g); + bdd_safenode_link(manager, safe_h, h); + bdd_safenode_declare(manager, ret); + bdd_safenode_declare(manager, reg_f); + bdd_safenode_declare(manager, f_v); + bdd_safenode_declare(manager, f_nv); + bdd_safenode_declare(manager, reg_g); + bdd_safenode_declare(manager, g_v); + bdd_safenode_declare(manager, g_nv); + bdd_safenode_declare(manager, reg_h); + bdd_safenode_declare(manager, h_v); + bdd_safenode_declare(manager, h_nv); + bdd_safenode_declare(manager, ite_T); + bdd_safenode_declare(manager, ite_E); + + manager->heap.stats.ITE_ops.calls++; + + /* + * Handle the trivial cases when f is a constant. + */ + if (f == BDD_ONE(manager)) { + /* + * ITE(1, G, H) = G + */ + manager->heap.stats.ITE_ops.returns.trivial++; + bdd_safeframe_end(manager); + return (g); + } + if (f == BDD_ZERO(manager)) { + /* + * ITE(0, G, H) = H + */ + manager->heap.stats.ITE_ops.returns.trivial++; + bdd_safeframe_end(manager); + return (h); + } + +#if ! defined(BDD_INLINE_ITE) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + (void) bdd_ite_var_to_const(manager, f, &g, &h); +#else /* } else { */ + BDD_ASSERT_NOTNIL(f); + + /* + * Equivalent to call to bdd_ite_var_to_const(manager, f, &g, &h). + * See bdd_ite_var_to_const for documentation. + */ + if (f == g) { + /* + * ITE(F, F, H) = ITE(F, 1, H) = F + H + */ + g = BDD_ONE(manager); + } else if (f == BDD_NOT(g)) { + /* + * ITE(F, !F, H) = ITE(F, 0, H) = !F * H + */ + g = BDD_ZERO(manager); + } + + if (f == h) { + /* + * ITE(F, G, F) = ITE(F, G, 0) = F * G + */ + h = BDD_ZERO(manager); + } else if (f == BDD_NOT(h)) { + /* + * ITE(F, G, !F) = ITE(F, G, 1) = !F + G + */ + h = BDD_ONE(manager); + } +#endif /* } */ + /* g and/or h may have been converted to constants */ + + if (g == h) { + /* + * ITE(F, G, G) = G + */ + manager->heap.stats.ITE_ops.returns.trivial++; + bdd_safeframe_end(manager); + return (g); + } + if (g == BDD_ONE(manager) && h == BDD_ZERO(manager)) { + /* + * ITE(F, 1, 0) = F + */ + manager->heap.stats.ITE_ops.returns.trivial++; + bdd_safeframe_end(manager); + return (f); + } + if (g == BDD_ZERO(manager) && h == BDD_ONE(manager)) { + /* + * ITE(F, 0, 1) = !F + */ + manager->heap.stats.ITE_ops.returns.trivial++; + bdd_safeframe_end(manager); + return (BDD_NOT(f)); + } + + /* + * It's not the case that both g and h are are constants; thus, + * at most one is a constant (either g or h). + */ + +#if ! defined(BDD_INLINE_ITE) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + (void) bdd_ite_canonicalize_ite_inputs(manager, &f, &g, &h, &complement); +#else /* } else { */ + BDD_ASSERT_NOTNIL(f); + BDD_ASSERT_NOTNIL(g); + BDD_ASSERT_NOTNIL(h); + + /* + * Equivalent to call to bdd_ite_canonicalize_ite_inputs(manager, &f, &g, &h, &complement). + * See bdd_ite_canonicalize_ite_inputs for documentation. No function calls are made here + * so that the code is as fast as possible. + */ + if (BDD_IS_CONSTANT(manager, g)) { + /* + * ITE(F, c, H) + * where c is either zero or one + */ + if (BDD_REGULAR(f)->id > BDD_REGULAR(h)->id || + (BDD_REGULAR(f)->id == BDD_REGULAR(h)->id && (int) f > (int) h)) { + /* + * ``F > H'' implies a rewrite by the rule + */ + if (g == BDD_ONE(manager)) { + /* + * ITE(F, 1, H) = ITE(H, 1, F) + */ + { bdd_node *tmp; + tmp = h; + h = f; + f = tmp; } + } else { /* g == BDD_ZERO(manager) */ + /* + * ITE(F, 0, H) = ITE(!H, 0, !F) + */ + { bdd_node *tmp; + tmp = h; + h = f; + f = tmp; } + f = BDD_NOT(f); + h = BDD_NOT(h); + } + } + } else if (BDD_IS_CONSTANT(manager, h)) { + /* + * ITE(F, G, c) + * where c is either zero or one + */ + if (BDD_REGULAR(f)->id > BDD_REGULAR(g)->id || + (BDD_REGULAR(f)->id == BDD_REGULAR(g)->id && (int) f > (int) g)) { + /* + * ``F > G'' implies a rewrite by the rule + */ + if (h == BDD_ONE(manager)) { + /* + * ITE(F, G, 1) = ITE(!G, !F, 1) + */ + { bdd_node *tmp; + tmp = g; + g = f; + f = tmp; } + f = BDD_NOT(f); + g = BDD_NOT(g); + } else { /* h == BDD_ONE(manager) */ + /* + * ITE(F, G, 0) = ITE(G, F, 0) + */ + { bdd_node *tmp; + tmp = g; + g = f; + f = tmp; } + } + } + } else if (g == BDD_NOT(h)) { + /* + * ITE(F, G, !G) + */ + if (BDD_REGULAR(f)->id > BDD_REGULAR(g)->id || + (BDD_REGULAR(f)->id == BDD_REGULAR(g)->id && (int) f > (int) g)) { + /* + * ``F > G'' implies a rewrite by the rule + * + * ITE(F, G, !G) = ITE(G, F, !F) + */ + { bdd_node *tmp; + tmp = f; + f = g; + g = tmp; } + h = BDD_NOT(g); + } + } + + /* + * Adjust pointers so that the first 2 arguments to ITE are regular. + * This canonicalizes the ordering of the ITE inputs some more. + */ + if (BDD_IS_COMPLEMENT(f)) { + /* + * ITE(!F, G, H) = ITE(F, H, G) + */ + f = BDD_NOT(f); + { bdd_node *tmp; + tmp = g; + g = h; + h = tmp; } + } + + if ( ! BDD_IS_COMPLEMENT(g) ) { + /* + * ITE(F, G, H) + * where H may be complemented or not + */ + complement = FALSE; + + BDD_ASSERT_REGNODE(f); + BDD_ASSERT_REGNODE(g); + } else { /* BDD_IS_COMPLEMENT(g) */ + /* + * ITE(F, !G, H) = ! ITE(F, G, !H) + */ + complement = TRUE; + + g = BDD_NOT(g); + h = BDD_NOT(h); + } + + BDD_ASSERT_REGNODE(f); + BDD_ASSERT_REGNODE(g); +#endif /* } */ + + BDD_ASSERT( ! BDD_IS_COMPLEMENT(f) ); + BDD_ASSERT( ! BDD_IS_COMPLEMENT(g) ); + /* ASSERT: BDD_IS_COMPLEMENT(h) || ! BDD_IS_COMPLEMENT(h) */ + + reg_f.node = BDD_REGULAR(f); + reg_g.node = BDD_REGULAR(g); + reg_h.node = BDD_REGULAR(h); + + /* + * A shortcut can be noted here: + * + * ITE(F, G, H) = (v, G, H), if F = (v, 1, 0) and v < top(G, H). + */ + varId = MIN(reg_g.node->id, reg_h.node->id); + + if (reg_f.node->id < varId && + reg_f.node->T == BDD_ONE(manager) && + reg_f.node->E == BDD_ZERO(manager)) { + /* + * f is the trivial case: ITE(v, 1, 0) + */ + manager->heap.stats.ITE_ops.returns.trivial++; + ret.node = bdd_find_or_add(manager, reg_f.node->id, g, h); + bdd_safeframe_end(manager); + return ( ! complement ? ret.node: BDD_NOT(ret.node)); + } + + /* + * Perform a cache lookup; if it was a hit, then return straightaway. + */ + if (bdd_hashcache_lookup(manager, f, g, h, &ret.node)) { + /* + * A hit, so blow off the frame, and return (complementing or not). + */ + manager->heap.stats.ITE_ops.returns.cached++; + bdd_safeframe_end(manager); + return ( ! complement ? ret.node: BDD_NOT(ret.node)); + } + + /* + * Caching didn't work out for us so we need to go and do the recursive step. + */ + + varId = MIN3(reg_f.node->id, reg_g.node->id, reg_h.node->id); + + /* + * The pattern: + * f_v - f cofactored by v + * f_nv - f cofactored by v bar + */ +#if ! defined(BDD_INLINE_ITE_CONSTANT) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + (void) bdd_ite_quick_cofactor(manager, f, varId, &(f_v.node), &(f_nv.node)); + (void) bdd_ite_quick_cofactor(manager, g, varId, &(g_v.node), &(g_nv.node)); + (void) bdd_ite_quick_cofactor(manager, h, varId, &(h_v.node), &(h_nv.node)); +#else /* } else { */ + + /* + * Equivalent to bdd_ite_quick_cofactor(manager, f, varId, &f_v, &f_nv); + */ + { + bdd_node *reg_f; + + BDD_ASSERT_NOTNIL(f); + + reg_f = BDD_REGULAR(f); + + if (reg_f->id == varId) { + /* + * If f's variable is varId, then do a bit + * of work to cofactor the bdd at f + */ + BDD_ASSERT( ! BDD_IS_CONSTANT(manager, f) ); /* can't do this on zero or one */ + + if (BDD_IS_COMPLEMENT(f)) { + f_v.node = BDD_NOT(reg_f->T); + f_nv.node = BDD_NOT(reg_f->E); + } else { + f_v.node = reg_f->T; + f_nv.node = reg_f->E; + } + } else { + /* + * If f's variable is not varId, then no work need be done. + */ + f_v.node = f; + f_nv.node = f; + } + + BDD_ASSERT_NOTNIL(f_v.node); + BDD_ASSERT_NOTNIL(f_nv.node); + } + + /* + * Equivalent to bdd_ite_quick_cofactor(manager, g, varId, &g_v, &g_nv); + */ + { + bdd_node *reg_g; + + BDD_ASSERT_NOTNIL(g); + + reg_g = BDD_REGULAR(g); + + if (reg_g->id == varId) { + /* + * If g's variable is varId, then do a bit + * of work to cofactor the bdd at g + */ + BDD_ASSERT( ! BDD_IS_CONSTANT(manager, g) ); /* can't do this on zero or one */ + + if (BDD_IS_COMPLEMENT(g)) { + g_v.node = BDD_NOT(reg_g->T); + g_nv.node = BDD_NOT(reg_g->E); + } else { + g_v.node = reg_g->T; + g_nv.node = reg_g->E; + } + } else { + /* + * If g's variable is not varId, then no work need be done. + */ + g_v.node = g; + g_nv.node = g; + } + + BDD_ASSERT_NOTNIL(g_v.node); + BDD_ASSERT_NOTNIL(g_nv.node); + } + + /* + * Equivalent to bdd_ite_quick_cofactor(manager, h, varId, &h_v, &h_nv); + */ + { + bdd_node *reg_h; + + BDD_ASSERT_NOTNIL(h); + + reg_h = BDD_REGULAR(h); + + if (reg_h->id == varId) { + /* + * If h's variable is varId, then do a bit + * of work to cofactor the bdd at h + */ + BDD_ASSERT( ! BDD_IS_CONSTANT(manager, h) ); /* can't do this on zero or one */ + + if (BDD_IS_COMPLEMENT(h)) { + h_v.node = BDD_NOT(reg_h->T); + h_nv.node = BDD_NOT(reg_h->E); + } else { + h_v.node = reg_h->T; + h_nv.node = reg_h->E; + } + } else { + /* + * If h's variable is not varId, then no work need be done. + */ + h_v.node = h; + h_nv.node = h; + } + + BDD_ASSERT_NOTNIL(h_v.node); + BDD_ASSERT_NOTNIL(h_nv.node); + } +#endif /* } */ + + ite_T.node = bdd__ITE_(manager, f_v.node, g_v.node, h_v.node); + ite_E.node = bdd__ITE_(manager, f_nv.node, g_nv.node, h_nv.node); + + if (ite_T.node == ite_E.node) { + ret.node = ite_T.node; /* either ite_T or ite_E */ + } else { + ret.node = bdd_find_or_add(manager, varId, ite_T.node, ite_E.node); + } + + (void) bdd_hashcache_insert(manager, f, g, h, ret.node); + + BDD_ASSERT_NOTNIL(ret.node); + + /* + * complement refers to how the user should refer to this bdd; + * if complement is set then the caller will refer to this bdd + * by its complemented name, otherwise by the uncomplemented name + */ + if (complement) { + ret.node = BDD_NOT(ret.node); + } + + manager->heap.stats.ITE_ops.returns.full++; + bdd_safeframe_end(manager); + return (ret.node); +} diff --git a/sis/bdd_ucb/ite_common.c b/sis/bdd_ucb/ite_common.c new file mode 100644 index 0000000..4bb4cb3 --- /dev/null +++ b/sis/bdd_ucb/ite_common.c @@ -0,0 +1,353 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/ite_common.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/ite_common.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: ite_common.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 03:18:26 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Fixed a typo in a comment. + * + * Revision 1.1 1992/07/29 00:27:07 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:39 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:43 shiple + * Initial revision + * + * + */ + +/* + * bdd_ite_quick_cofactor - perform a quick cofactoring of f + * + * return the f_v and f_nv cofactors + */ +void +bdd_ite_quick_cofactor(manager, f, varId, pf_v, pf_nv) +bdd_manager *manager; +bdd_node *f; +bdd_variableId varId; +bdd_node **pf_v; /* return - f cofactored by varId */ +bdd_node **pf_nv; /* return - f cofactored by varId bar */ +{ + bdd_node *reg_f; + + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + BDD_ASSERT_NOTNIL(f); + + reg_f = BDD_REGULAR(f); + + if (reg_f->id == varId) { + /* + * If f's variable is varId, then do a bit + * of work to cofactor the bdd at f + */ + BDD_ASSERT( ! BDD_IS_CONSTANT(manager, f) ); /* can't do this on zero or one */ + + if (BDD_IS_COMPLEMENT(f)) { + *pf_v = BDD_NOT(reg_f->T); + *pf_nv = BDD_NOT(reg_f->E); + } else { + *pf_v = reg_f->T; + *pf_nv = reg_f->E; + } + } else { + /* + * If f's variable is not varId, then no work need be done. + */ + *pf_v = f; + *pf_nv = f; + } + + BDD_ASSERT_NOTNIL(*pf_v); + BDD_ASSERT_NOTNIL(*pf_nv); +} + +/* + * bdd_ite_var_to_const - see if it is possible to replace variables by constants + * + * Replace variables with constants if possible (part of canonical form). + * + * ITE Identities + * ITE(F, G, F) = ITE(F, G, 0) = F * G + * ITE(F, G, !F) = ITE(F, G, 1) = !F + G + * ITE(F, F, H) = ITE(F, 1, H) = F + H + * ITE(F, !F, H) = ITE(F, 0, H) = !F * H + * + * return nothing, just do it. + */ +void +bdd_ite_var_to_const(manager, f, pg, ph) +bdd_manager *manager; +bdd_node *f; /* value */ +bdd_node **pg; /* value/return */ +bdd_node **ph; /* value/return */ +{ + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + BDD_ASSERT_NOTNIL(f); + + if (f == *pg) { + /* + * ITE(F, F, H) = ITE(F, 1, H) = F + H + */ + *pg = BDD_ONE(manager); + } else if (f == BDD_NOT(*pg)) { + /* + * ITE(F, !F, H) = ITE(F, 0, H) = !F * H + */ + *pg = BDD_ZERO(manager); + } + + if (f == *ph) { + /* + * ITE(F, G, F) = ITE(F, G, 0) = F * G + */ + *ph = BDD_ZERO(manager); + } else if (f == BDD_NOT(*ph)) { + /* + * ITE(F, G, !F) = ITE(F, G, 1) = !F + G + */ + *ph = BDD_ONE(manager); + } +} + +static boolean greaterthan_equalp(); +static void swap(); + +/* + * bdd_ite_canonicalize_ite_inputs - pick a unique member from among equivalent expressions + * + * This reduces 2 variable expressions to canonical form (p. 16, 17) + * + * The purpose of this routine (as is described on page 16) is to canonicalize + * the inputs to the ITE function so that there can be as many cache hits as + * possible. This canonicalization is a performance improvement only; all that + * is required of this routine is that it does not rewrite any ITE input into + * an incorrect form. + * + * The code below is organized into what is believed to be the most efficient + * manner possible, given the listing of the ITE rewrite rules: a tree of if/else pairs. + * + * return nothing, just do it. + */ +void +bdd_ite_canonicalize_ite_inputs(manager, pf, pg, ph, pcomplement) +bdd_manager *manager; +bdd_node **pf; /* value/return */ +bdd_node **pg; /* value/return */ +bdd_node **ph; /* value/return */ +boolean *pcomplement; /* return */ +{ + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + BDD_ASSERT(pf != NIL(bdd_node *)); + BDD_ASSERT_NOTNIL(*pf); + + BDD_ASSERT(pg != NIL(bdd_node *)); + BDD_ASSERT_NOTNIL(*pg); + + BDD_ASSERT(ph != NIL(bdd_node *)); + BDD_ASSERT_NOTNIL(*ph); + + if (BDD_IS_CONSTANT(manager, *pg)) { + /* + * ITE(F, c, H) + * where c is either zero or one + */ + if (greaterthan_equalp(*pf, *ph)) { + /* + * ``F > H'' implies a rewrite by the rule + */ + if (*pg == BDD_ONE(manager)) { + /* + * ITE(F, 1, H) = ITE(H, 1, F) + */ + swap(ph, pf); + } else { /* *pg == BDD_ZERO(manager) */ + /* + * ITE(F, 0, H) = ITE(!H, 0, !F) + */ + swap(ph, pf); + *pf = BDD_NOT(*pf); + *ph = BDD_NOT(*ph); + } + } + } else if (BDD_IS_CONSTANT(manager, *ph)) { + /* + * ITE(F, G, c) + * where c is either zero or one + */ + if (greaterthan_equalp(*pf, *pg)) { + /* + * ``F > G'' implies a rewrite by the rule + */ + if (*ph == BDD_ONE(manager)) { + /* + * ITE(F, G, 1) = ITE(!G, !F, 1) + */ + swap(pg, pf); + *pf = BDD_NOT(*pf); + *pg = BDD_NOT(*pg); + } else { /* *ph == BDD_ONE(manager) */ + /* + * ITE(F, G, 0) = ITE(G, F, 0) + */ + swap(pg, pf); + } + } + } else if (*pg == BDD_NOT(*ph)) { + /* + * ITE(F, G, !G) + */ + if (greaterthan_equalp(*pf, *pg)) { + /* + * ``F > G'' implies a rewrite by the rule + * + * ITE(F, G, !G) = ITE(G, F, !F) + */ + swap(pf, pg); + *ph = BDD_NOT(*pg); + } + } + + /* + * Adjust pointers so that the first 2 arguments to ITE are regular. + * This canonicalizes the ordering of the ITE inputs some more. + */ + if (BDD_IS_COMPLEMENT(*pf)) { + /* + * ITE(!F, G, H) = ITE(F, H, G) + */ + *pf = BDD_NOT(*pf); + swap(pg, ph); + } + + if ( ! BDD_IS_COMPLEMENT(*pg) ) { + /* + * ITE(F, G, H) + * where H may be complemented or not + */ + *pcomplement = FALSE; + + BDD_ASSERT_REGNODE(*pf); + BDD_ASSERT_REGNODE(*pg); + } else { /* BDD_IS_COMPLEMENT(*pg) */ + /* + * ITE(F, !G, H) = ! ITE(F, G, !H) + */ + *pcomplement = TRUE; + + *pg = BDD_NOT(*pg); + *ph = BDD_NOT(*ph); + } + + BDD_ASSERT_REGNODE(*pf); + BDD_ASSERT_REGNODE(*pg); +} + +/* + * greaterthan_equalp - induce a partial ordering on nodes + * + * Compare first by the integer value of the variableId + * If the variableId's are the same, then use the complementation + * indication on the original function (f, or g). + * Complementation is ``greater than'' uncomplementation. + * + * return {TRUE, FALSE} on {is, is not}. + */ +static boolean +greaterthan_equalp(f, g) +bdd_node *f; +bdd_node *g; +{ + bdd_node *reg_f, *reg_g; + + BDD_ASSERT_NOTNIL(f); + BDD_ASSERT_NOTNIL(g); + + reg_f = BDD_REGULAR(f); + reg_g = BDD_REGULAR(g); + + if (reg_f->id > reg_g->id) { + /* + * If the nodes are different, + * then f is clearly greater than g. + */ + return (TRUE); + } + + if (reg_f->id == reg_g->id) { + /* + * The variableId's are equal (they refer to the same variable), + * so pick an arbitrary ordering for the two. This is based + * on some unique (yet arbitrary) property of the node, such + * as its uniqueId or memory location (another uniqueId). + */ + boolean arbitraryp; + +#if defined(BDD_DEBUG_UID) && ! defined(BDD_DEBUG_LIFESPAN) /* { */ + arbitraryp = reg_f->uniqueId > reg_g->uniqueId; +#else /* } else { */ + arbitraryp = (int) f > (int) g; +#endif /* } */ + + if (arbitraryp); + return (TRUE); + } + + return (FALSE); +} + +/* + * swap - very simple, just flip f and g + * + * return nothing, just do it. + */ +static void +swap(pf, pg) +bdd_node **pf; /* value/return */ +bdd_node **pg; /* value/return */ +{ + bdd_node *tmp; /* swap f and h */ + + tmp = *pg; + *pg = *pf; + *pf = tmp; +} diff --git a/sis/bdd_ucb/ite_constant.c b/sis/bdd_ucb/ite_constant.c new file mode 100644 index 0000000..883bb98 --- /dev/null +++ b/sis/bdd_ucb/ite_constant.c @@ -0,0 +1,571 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/ite_constant.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/ite_constant.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: ite_constant.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 01:48:31 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. + * + * Revision 1.1 1992/07/29 00:27:08 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:40 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:44 shiple + * Initial revision + * + * + */ + +static bdd_constant_status grock_constantness(); +static bdd_constant_status grock_status(); + +/* + * bdd__ITE_constant - the ITE operation special-cased for constants + * + * ITE Identities + * ITE(1, G, H) => G + * ITE(0, G, H) => H + * ITE(F, 1, 0) || ITE(F, 0, 1) => non_const + * + * return {bdd_constant_one, bdd_constant_zero, bdd_nonconstant} + */ +bdd_constant_status +bdd__ITE_constant(manager, f, g, h) +bdd_manager *manager; +bdd_node *f; +bdd_node *g; +bdd_node *h; +{ + bdd_node *ret; + bdd_node *reg_f, *f_v, *f_nv; + bdd_node *reg_g, *g_v, *g_nv; + bdd_node *reg_h, *h_v, *h_nv; + bdd_variableId varId; + boolean complement; + bdd_constant_status ret_status, ite_T_status, ite_E_status; + + /* WATCHOUT - no safe frame is declared here (b/c its not needed) */ + + manager->heap.stats.ITE_constant_ops.calls++; + + if (f == BDD_ONE(manager)) { + /* + * ITE(1, G, H) => G + */ + manager->heap.stats.ITE_constant_ops.returns.trivial++; +#if ! defined(BDD_INLINE_ITE_CONSTANT) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + return (grock_constantness(manager, g, FALSE)); +#else /* } else { */ + if (g == BDD_ZERO(manager)) { + ret_status = bdd_constant_zero; + } else if (g == BDD_ONE(manager)) { + ret_status = bdd_constant_one; + } else { + ret_status = bdd_nonconstant; + } + + return (ret_status); +#endif /* } */ + } + + if (f == BDD_ZERO(manager)) { + /* + * ITE(0, G, H) => H + */ + manager->heap.stats.ITE_constant_ops.returns.trivial++; +#if ! defined(BDD_INLINE_ITE_CONSTANT) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + return (grock_constantness(manager, h, FALSE)); +#else /* } else { */ + if (h == BDD_ZERO(manager)) { + ret_status = bdd_constant_zero; + } else if (h == BDD_ONE(manager)) { + ret_status = bdd_constant_one; + } else { + ret_status = bdd_nonconstant; + } + + return (ret_status); +#endif /* } */ + } + + /* + * Because f is known not to be either the zero + * or the one, it is known to be not a constant. + */ +#if ! defined(BDD_INLINE_ITE_CONSTANT) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + (void) bdd_ite_var_to_const(manager, f, &g, &h); +#else /* } else { */ + BDD_ASSERT_NOTNIL(f); + + if (f == g) { + /* + * ITE(F, F, H) = ITE(F, 1, H) = F + H + */ + g = BDD_ONE(manager); + } else if (f == BDD_NOT(g)) { + /* + * ITE(F, !F, H) = ITE(F, 0, H) = !F * H + */ + g = BDD_ZERO(manager); + } + + if (f == h) { + /* + * ITE(F, G, F) = ITE(F, G, 0) = F * G + */ + h = BDD_ZERO(manager); + } else if (f == BDD_NOT(h)) { + /* + * ITE(F, G, !F) = ITE(F, G, 1) = !F + G + */ + h = BDD_ONE(manager); + } +#endif /* } */ + + /* g and/or h may have been converted to constants */ + + if (g == h) { + /* + * ITE(F, G, G) => G + */ + manager->heap.stats.ITE_constant_ops.returns.trivial++; + +#if ! defined(BDD_INLINE_ITE_CONSTANT) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + return (grock_constantness(manager, g, FALSE)); +#else /* } else { */ + if (g == BDD_ZERO(manager)) { + ret_status = bdd_constant_zero; + } else if (g == BDD_ONE(manager)) { + ret_status = bdd_constant_one; + } else { + ret_status = bdd_nonconstant; + } + + return (ret_status); +#endif /* } */ + } + if (BDD_IS_CONSTANT(manager, g) && BDD_IS_CONSTANT(manager, h)) { + /* + * ITE(F, 1, 0) || ITE(F, 0, 1) => non_const + */ + manager->heap.stats.ITE_constant_ops.returns.trivial++; + return (bdd_nonconstant); + } + +#if ! defined(BDD_INLINE_ITE_CONSTANT) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + (void) bdd_ite_canonicalize_ite_inputs(manager, &f, &g, &h, &complement); +#else /* } else { */ + BDD_ASSERT_NOTNIL(f); + BDD_ASSERT_NOTNIL(g); + BDD_ASSERT_NOTNIL(h); + + if (BDD_IS_CONSTANT(manager, g)) { + /* + * ITE(F, c, H) + * where c is either zero or one + */ + if (BDD_REGULAR(f)->id > BDD_REGULAR(h)->id || + (BDD_REGULAR(f)->id == BDD_REGULAR(h)->id && (int) f > (int) h)) { + /* + * ``F > H'' implies a rewrite by the rule + */ + if (g == BDD_ONE(manager)) { + /* + * ITE(F, 1, H) = ITE(H, 1, F) + */ + { bdd_node *tmp; + tmp = f; + f = h; + h = tmp; } + } else { /* g == BDD_ZERO(manager) */ + /* + * ITE(F, 0, H) = ITE(!H, 0, !F) + */ + { bdd_node *tmp; + tmp = h; + h = f; + f = tmp; } + f = BDD_NOT(f); + h = BDD_NOT(h); + } + } + } else if (BDD_IS_CONSTANT(manager, h)) { + /* + * ITE(F, G, c) + * where c is either zero or one + */ + if (BDD_REGULAR(f)->id > BDD_REGULAR(g)->id || + (BDD_REGULAR(f)->id == BDD_REGULAR(g)->id && (int) f > (int) g)) { + /* + * ``F > G'' implies a rewrite by the rule + */ + if (h == BDD_ONE(manager)) { + /* + * ITE(F, G, 1) = ITE(!G, !F, 1) + */ + { bdd_node *tmp; + tmp = g; + g = f; + f = tmp; } + f = BDD_NOT(f); + g = BDD_NOT(g); + } else { /* h == BDD_ONE(manager) */ + /* + * ITE(F, G, 0) = ITE(G, F, 0) + */ + { bdd_node *tmp; + tmp = g; + g = f; + f = tmp; } + } + } + } else if (g == BDD_NOT(h)) { + /* + * ITE(F, G, !G) + */ + if (BDD_REGULAR(f)->id > BDD_REGULAR(g)->id || + (BDD_REGULAR(f)->id == BDD_REGULAR(g)->id && (int) f > (int) g)) { + /* + * ``F > G'' implies a rewrite by the rule + * + * ITE(F, G, !G) = ITE(G, F, !F) + */ + { bdd_node *tmp; + tmp = f; + f = g; + g = tmp; } + h = BDD_NOT(g); + } + } + + /* + * Adjust pointers so that the first 2 arguments to ITE are regular. + * This canonicalizes the ordering of the ITE inputs some more. + */ + if (BDD_IS_COMPLEMENT(f)) { + /* + * ITE(!F, G, H) = ITE(F, H, G) + */ + f = BDD_NOT(f); + { bdd_node *tmp; + tmp = g; + g = h; + h = tmp; } + } + + if ( ! BDD_IS_COMPLEMENT(g) ) { + /* + * ITE(F, G, H) + * where H may be complemented or not + */ + complement = FALSE; + + BDD_ASSERT_REGNODE(f); + BDD_ASSERT_REGNODE(g); + } else { /* BDD_IS_COMPLEMENT(g) */ + /* + * ITE(F, !G, H) = ! ITE(F, G, !H) + */ + complement = TRUE; + + g = BDD_NOT(g); + h = BDD_NOT(h); + } + + BDD_ASSERT_REGNODE(f); + BDD_ASSERT_REGNODE(g); +#endif /* } */ + + reg_f = BDD_REGULAR(f); + reg_g = BDD_REGULAR(g); + reg_h = BDD_REGULAR(h); + + /* + * Perform a cache lookup; may be the value + * has already been computed. + */ + if (bdd_constcache_lookup(manager, f, g, h, &ret_status)) { + /* + * Fine, a hit, just return what we know about it. + */ + manager->heap.stats.ITE_constant_ops.returns.cached++; +#if ! defined(BDD_INLINE_ITE_CONSTANT) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + return (grock_status(ret_status, complement)); +#else /* } else { */ + if (complement) { + switch (ret_status) { + case bdd_constant_zero: + ret_status = bdd_constant_one; + break; + case bdd_constant_one: + ret_status = bdd_constant_zero; + break; + case bdd_nonconstant: + /* leave it alone */ + break; + } + } + + return (ret_status); +#endif /* } */ + } + + if (bdd_hashcache_lookup(manager, f, g, h, &ret)) { + /* + * Fine, a hit, just return what we know about it. + */ + manager->heap.stats.ITE_constant_ops.returns.cached++; +#if ! defined(BDD_INLINE_ITE_CONSTANT) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + return (grock_constantness(manager, ret, complement)); +#else /* } else { */ + if (ret == BDD_ZERO(manager)) { + ret_status = complement ? bdd_constant_one: bdd_constant_zero; + } else if (ret == BDD_ONE(manager)) { + ret_status = complement ? bdd_constant_zero: bdd_constant_one; + } else { + ret_status = bdd_nonconstant; + } + + return (ret_status); +#endif /* } */ + } + + /* + * Caching didn't work out for us so we + * need to go and do the recursive step. + */ + + /* v = top_varId(reg_f, reg_g, reg_h) */ + varId = MIN3(reg_f->id, reg_g->id, reg_h->id); + + /* + * The pattern: + * f_v - f cofactored by v + * f_nv - f cofactored by v bar + */ +#if ! defined(BDD_INLINE_ITE_CONSTANT) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + (void) bdd_ite_quick_cofactor(manager, f, varId, &f_v, &f_nv); + (void) bdd_ite_quick_cofactor(manager, g, varId, &g_v, &g_nv); + (void) bdd_ite_quick_cofactor(manager, h, varId, &h_v, &h_nv); +#else /* } else { */ + { + bdd_node *reg_f; + + BDD_ASSERT_NOTNIL(f); + + reg_f = BDD_REGULAR(f); + + if (reg_f->id == varId) { + /* + * If f's variable is varId, then do a bit + * of work to cofactor the bdd at f + */ + BDD_ASSERT( ! BDD_IS_CONSTANT(manager, f) ); /* can't do this on zero or one */ + + if (BDD_IS_COMPLEMENT(f)) { + f_v = BDD_NOT(reg_f->T); + f_nv = BDD_NOT(reg_f->E); + } else { + f_v = reg_f->T; + f_nv = reg_f->E; + } + } else { + /* + * If f's variable is not varId, then no work need be done. + */ + f_v = f; + f_nv = f; + } + + BDD_ASSERT_NOTNIL(f_v); + BDD_ASSERT_NOTNIL(f_nv); +} + { + bdd_node *reg_g; + + BDD_ASSERT_NOTNIL(g); + + reg_g = BDD_REGULAR(g); + + if (reg_g->id == varId) { + /* + * If g's variable is varId, then do a bit + * of work to cofactor the bdd at g + */ + BDD_ASSERT( ! BDD_IS_CONSTANT(manager, g) ); /* can't do this on zero or one */ + + if (BDD_IS_COMPLEMENT(g)) { + g_v = BDD_NOT(reg_g->T); + g_nv = BDD_NOT(reg_g->E); + } else { + g_v = reg_g->T; + g_nv = reg_g->E; + } + } else { + /* + * If g's variable is not varId, then no work need be done. + */ + g_v = g; + g_nv = g; + } + + BDD_ASSERT_NOTNIL(g_v); + BDD_ASSERT_NOTNIL(g_nv); +} + { + bdd_node *reg_h; + + BDD_ASSERT_NOTNIL(h); + + reg_h = BDD_REGULAR(h); + + if (reg_h->id == varId) { + /* + * If h's variable is varId, then do a bit + * of work to cofactor the bdd at h + */ + BDD_ASSERT( ! BDD_IS_CONSTANT(manager, h) ); /* can't do this on zero or one */ + + if (BDD_IS_COMPLEMENT(h)) { + h_v = BDD_NOT(reg_h->T); + h_nv = BDD_NOT(reg_h->E); + } else { + h_v = reg_h->T; + h_nv = reg_h->E; + } + } else { + /* + * If h's variable is not varId, then no work need be done. + */ + h_v = h; + h_nv = h; + } + + BDD_ASSERT_NOTNIL(h_v); + BDD_ASSERT_NOTNIL(h_nv); +} +#endif /* } */ + + ite_T_status = bdd__ITE_constant(manager, f_v, g_v, h_v); + if (ite_T_status == bdd_nonconstant) { + /* + * Its a nonconstant + */ + manager->heap.stats.ITE_constant_ops.returns.full++; + (void) bdd_constcache_insert(manager, f, g, h, bdd_nonconstant); + return (bdd_nonconstant); + } + + ite_E_status = bdd__ITE_constant(manager, f_nv, g_nv, h_nv); + if (ite_E_status == bdd_nonconstant || ite_T_status != ite_E_status) { + /* + * Its a nonconstant again ... + */ + manager->heap.stats.ITE_constant_ops.returns.full++; + (void) bdd_constcache_insert(manager, f, g, h, bdd_nonconstant); + return (bdd_nonconstant); + } + + ret_status = ite_T_status; /* or equivalently ite_E_status */ + + (void) bdd_constcache_insert(manager, f, g, h, ret_status); + + manager->heap.stats.ITE_constant_ops.returns.full++; + +#if ! defined(BDD_INLINE_ITE_CONSTANT) || defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + return (grock_status(ret_status, complement)); +#else /* } else { */ + if (complement) { + switch (ret_status) { + case bdd_constant_zero: + ret_status = bdd_constant_one; + break; + case bdd_constant_one: + ret_status = bdd_constant_zero; + break; + case bdd_nonconstant: + /* leave it alone */ + break; + } + } + + return (ret_status); +#endif /* } */ +} + +static bdd_constant_status +grock_constantness(manager, f, complement) +bdd_manager *manager; +bdd_node *f; +boolean complement; +{ + bdd_constant_status status; + + if (f == BDD_ZERO(manager)) { + status = bdd_constant_zero; + } else if (f == BDD_ONE(manager)) { + status = bdd_constant_one; + } else { + status = bdd_nonconstant; + } + + return (grock_status(status, complement)); +} + +static bdd_constant_status +grock_status(status, complement) +bdd_constant_status status; +boolean complement; +{ + if (complement) { + switch (status) { + case bdd_constant_zero: + status = bdd_constant_one; + break; + case bdd_constant_one: + status = bdd_constant_zero; + break; + case bdd_nonconstant: + /* leave it alone */ + break; + } + } + + return (status); +} diff --git a/sis/bdd_ucb/new_node.c b/sis/bdd_ucb/new_node.c new file mode 100644 index 0000000..4167b18 --- /dev/null +++ b/sis/bdd_ucb/new_node.c @@ -0,0 +1,389 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/new_node.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/new_node.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: new_node.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.4 1993/02/25 01:09:39 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.4 1993/02/25 01:09:39 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.3 1993/01/16 01:19:23 shiple + * Added comment noting that the BDD package assumes ALLOC returns NIL when it can't + * allocate more memory. + * + * Revision 1.2 1992/09/19 03:19:08 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added peak node usage. + * Fixed bug in function new_block which caused an additional node block + * to be added to the free list at the start of each garbage collection. + * Changed name new_block to get_node_block, added function get_block_from_free_list. + * Added use of manager->heap.init_node_blocks and manager->heap.gc.node_ratio. + * Add usage of bdd_will_exceed_mem_limit in add_block_to_free_list. + * + * Revision 1.1 1992/07/29 00:27:10 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:40 sis + * Initial revision + * + * Revision 1.1 91/03/27 14:35:45 shiple + * Initial revision + * + * + */ + +static void get_node_block(); +static int add_block_to_free_list(); +static void get_block_from_free_list(); + + +/* + * bdd_new_node - get a new node and fill in its value + * + * The new node is not put in any hash table or cache + * + * return the new node + */ +bdd_node * +bdd_new_node(manager, variableId, T, E, old) +bdd_manager *manager; +bdd_variableId variableId; +bdd_node *T; +bdd_node *E; +bdd_node *old; /* NIL for a new node, non-nil during gc (only used to communicate debug info) */ +{ + bdd_safeframe frame; + bdd_safenode safe_T, safe_E, safe_old, + new; + int index; + + /* + * WATCHOUT - be sure not to call the version of ``safe frame end'' + * which does frame assertion checks. This routine is called inside + * of the garbage-collector, and so the frames are in an inconsistent + * state by definition. + */ + bdd_safeframe__start(manager, frame); + bdd_safenode__link(manager, safe_T, T); + bdd_safenode__link(manager, safe_E, E); + bdd_safenode__link(manager, safe_old, old); + bdd_safenode__declare(manager, new); + + /* + * If this is the first block, or, the block is full, + * then get a new block for the heap. This means getting a block from + * the free list, if it is nonempty, or allocating a new block. If + * this function is called from relocate within bdd_garbage_collect, then + * it will always be the case that the free list is nonempty. That's because + * the number of objects collected must be less than or equal to the original + * number of objects. + */ + if (manager->heap.pointer.block == NIL(bdd_nodeBlock) || + manager->heap.pointer.index >= sizeof_el (manager->heap.pointer.block->subheap)) { + + /* + * It should never occur that we are during gc and the free list is empty. + */ + BDD_ASSERT(!((old!=NIL(bdd_node))&&(manager->heap.half[manager->heap.gc.halfspace].free==NIL(bdd_nodeBlock)))); + (void) get_node_block(manager); + } + + index = manager->heap.pointer.index++; + manager->heap.pointer.block->used++; + new.node = &manager->heap.pointer.block->subheap[index]; + + new.node->id = variableId; + new.node->T = T; + new.node->E = E; + new.node->next = NIL(bdd_node); + + /* + * Read between the #ifdefs carefully. What is going on here is + * rather simple, but the ifdefs get too much in the way to make + * it very readable. + * + * if (old == nil) { + * - then not during gc so ... + * - assign the current gc generation + * - assign a new uniqueId + * - log the creation of the object + * } else { + * - else it is during a gc + * - copy over the previous uniqueId + * - copy over the previus age (of creation) + * - do not log any creation (b/c it really wasn't) + * } + */ + if (old == NIL(bdd_node)) { /* not during gc */ +#if defined(BDD_DEBUG_AGE) || defined(BDD_DEBUG_LIFESPAN) /* { */ + new.node->age = manager->debug.gc.age; +#endif /* } */ +#if defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + new.node->uniqueId = manager->debug.gc.uniqueId++; +#endif /* } */ +#if defined(BDD_DEBUG_LIFESPAN) /* { */ + fprintf(manager->debug.lifespan.trace, "c %d\n", new.node->uniqueId); +#endif /* } */ + } else { /* during gc */ +#if defined(BDD_DEBUG_AGE) || defined(BDD_DEBUG_LIFESPAN) /* { */ + new.node->age = old->age; +#endif /* } */ +#if defined(BDD_DEBUG_UID) || defined(BDD_DEBUG_LIFESPAN) /* { */ + new.node->uniqueId = old->uniqueId; +#endif /* } */ + } + +#if defined(BDD_DEBUG_GC) /* { */ + new.node->halfspace = manager->heap.gc.halfspace; +#endif /* } */ + + manager->heap.stats.nodes.used++; + manager->heap.stats.nodes.peak = MAX(manager->heap.stats.nodes.peak, manager->heap.stats.nodes.used); + manager->heap.stats.nodes.unused--; + + /* + * WATCHOUT - be sure not to call the version of ``safe frame end'' + * which does frame assertion checks. This routine is called inside + * of the garbage-collector, and so the frames are in an inconsistent + * state by definition. + */ + bdd_safeframe__end(manager); + return (new.node); +} + +static void +get_node_block(manager) +bdd_manager *manager; +{ + boolean request_status, return_status; + int i; + + if (manager->heap.half[manager->heap.gc.halfspace].free != NIL(bdd_nodeBlock)) { + /* + * If the free list is not empty, then just take a block off the free list. + * If we are garbage collecting and relocating objects, then this condition should + * always be satisfied. + */ + (void) get_block_from_free_list(manager); + } else { + if (manager->heap.half[manager->heap.gc.halfspace].inuse.top == NIL(bdd_nodeBlock)) { + /* + * The free list is empty and the inuse list is empty. Thus, add manager->heap.init_node_blocks to + * the free list, and then take one off the free list (a little bit redundant). + * Use the request_status flag to make sure that we get at least one block. + */ + request_status = FALSE; + for (i = 1; i <= manager->heap.init_node_blocks; i++) { + return_status = add_block_to_free_list(manager, request_status); + + /* + * If no more blocks can be allocated, then stop asking for more. + */ + if (return_status == FALSE) { + break; + } + request_status = TRUE; /* getting more becomes optional */ + } + (void) get_block_from_free_list(manager); + } else { + /* + * The free list is empty, and the inuse list is full. Time to garbage collect. + */ + (void) bdd_garbage_collect(manager); + + /* + * We want to provide a buffer for the heap to grow. Otherwise, the heap + * could be, say 98% full, and we will be garbage collecting very frequently. + */ + + /* + * If no garbage was collected, then the inuse list will be filled up and the + * free list will be empty. In this case, we must get at least one new block, + * so we set request_status to FALSE. Otherwise, getting more blocks is optional. + */ + if ((manager->heap.pointer.index >= sizeof_el (manager->heap.pointer.block->subheap)) + && (manager->heap.half[manager->heap.gc.halfspace].free == NIL(bdd_nodeBlock))) { + request_status = FALSE; + } else { + request_status = TRUE; + } + + /* + * Policy: While the ratio of used to unused nodes is greater than manager->heap.gc.node_ratio, + * keep adding blocks to the free list as long as they are available. This is to provide room for growth. + */ + while (manager->heap.stats.nodes.used > (manager->heap.stats.nodes.unused * manager->heap.gc.node_ratio)) { + return_status = add_block_to_free_list(manager, request_status); + + /* + * If no more blocks can be allocated, then stop asking for more. + */ + if (return_status == FALSE) { + break; + } + request_status = TRUE; /* getting more becomes optional */ + } + + /* + * If the inuse list is filled up, then at this point, we are guaranteed to have at least + * one block on the free list. In this case, take a block off the free list. If the inuse + * list is not filled up, then the next bdd_node will be allocated in the current inuse block. + */ + if (manager->heap.pointer.index >= sizeof_el (manager->heap.pointer.block->subheap)) { + (void) get_block_from_free_list(manager); + } + } + } /* close: if (manager->heap.half[manager->heap.gc.halfspace].free != NIL(bdd_nodeBlock)) { */ + return; +} + +/* + * Assume there is at least one block on the free list. Take a block off the free list + * and put it onto the inuse list. Set the manager to allocate next bdd_node in the + * first slot of the block taken from the free list. + */ +static void +get_block_from_free_list(manager) +bdd_manager *manager; +{ + bdd_nodeBlock *f; + + /* + * We assume that there is at least one block on the free list. + */ + BDD_ASSERT(manager->heap.half[manager->heap.gc.halfspace].free != NIL(bdd_nodeBlock)); + + /* + * Take the next block off of the head of the free list, and update the free list pointer. + */ + f = manager->heap.half[manager->heap.gc.halfspace].free; + manager->heap.half[manager->heap.gc.halfspace].free = f->next; + + /* + * Initialize it. + */ + f->used = 0; + f->next = NIL(bdd_nodeBlock); + + /* + * Update the inuse pointers. + */ + *manager->heap.half[manager->heap.gc.halfspace].inuse.tail = f; + manager->heap.half[manager->heap.gc.halfspace].inuse.tail = &f->next; + + /* + * Tell manager where to allocate next bdd_node. + */ + manager->heap.pointer.block = f; + manager->heap.pointer.index = 0; + + /* + * Do not modify any of stats.blocks.total, stats.nodes.unused or stats.nodes.total + * because neither changed when a block on the free list is used; these stats + * were changed in add_block_to_free_list(). + */ +} + +/* + * add_block_to_free_list + * + * Make two new blocks and stick one in each halfspace's free list + * + */ +static int +add_block_to_free_list(manager, optionalp) +bdd_manager *manager; +boolean optionalp; /* if memory allocation fails, then don't call fail() */ +{ + bdd_nodeBlock *b[2]; + int h; + + /* + * Check to see if allocating 2 more blocks will cause the manager memory limit to be exceeded. + * If so, and if optionalp is set, then just return FALSE, indicating that we were not + * successful in allocating more blocks. If optionalp is FALSE, then call bdd_will_exceed_mem_limit + * again, this time indicating that we want to quit this computation. + */ + if (bdd_will_exceed_mem_limit(manager, (2 * sizeof(bdd_nodeBlock)), FALSE) == TRUE) { + if (optionalp) { + return FALSE; + } else { + (void) bdd_will_exceed_mem_limit(manager, (2 * sizeof(bdd_nodeBlock)), TRUE); + } + } + + /* + * Allocate the blocks. Note that the code following this block assumes that ALLOC will + * return a NIL pointer if it wasn't able to allocate the requested amount of memory + * (actually, all calls to ALLOC in the BDD package make this assumption). If this + * assumption is violated, then, in the following case, bdd_memfail won't be called. + */ + b[0] = (bdd_nodeBlock *) ALLOC(bdd_nodeBlock, 1); + b[1] = (bdd_nodeBlock *) ALLOC(bdd_nodeBlock, 1); + + if (b[0] == NIL(bdd_nodeBlock) || b[1] == NIL(bdd_nodeBlock)) { + /* + * We've blown the memory limit; back of the greedy approach + * Could be that we've got enough to go on already... + */ + if (optionalp) { + if (b[0] != NIL(bdd_nodeBlock)) + FREE(b[0]); + if (b[1] != NIL(bdd_nodeBlock)) + FREE(b[1]); + /* + * We were NOT successful in allocating a new pair of blocks, but the optionalp + * flag is set. + */ + return FALSE; + } else { + (void) bdd_memfail(manager, "add_block_to_free_list"); + } + } + + for (h=0; hheap.half); h++) { + b[h]->used = 0; + b[h]->next = NIL(bdd_nodeBlock); + + b[h]->next = manager->heap.half[h].free; + manager->heap.half[h].free = b[h]; + } + + manager->heap.stats.nodes.unused += sizeof_el (manager->heap.pointer.block->subheap); + manager->heap.stats.nodes.total += sizeof_el (manager->heap.pointer.block->subheap); + manager->heap.stats.blocks.total++; + + /* + * We were successful in allocating a new pair of blocks. + */ + return TRUE; +} diff --git a/sis/bdd_ucb/print_stats.c b/sis/bdd_ucb/print_stats.c new file mode 100644 index 0000000..7c623b7 --- /dev/null +++ b/sis/bdd_ucb/print_stats.c @@ -0,0 +1,202 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/print_stats.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/print_stats.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: print_stats.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 03:22:22 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added bdd_get_percentage function. + * Incorporate memory stats. Totally revamped printing of statistics. Added all the new fields in stats. + * + * Revision 1.1 1992/07/29 00:27:11 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:41 sis + * Initial revision + * + * Revision 1.1 91/04/11 20:59:14 shiple + * Initial revision + * + * + */ + +/* + * Calculate the numerator as a percentage of the denominator. Assumes inputs are ints. + * Return 0.0 if denominator is zero. + */ +float +bdd_get_percentage(numerator, denominator) +int numerator; +int denominator; +{ + if (denominator == 0) { + return 0.0; + } else { + return (((float)numerator/denominator)*100); + } +} + +/* + * bdd_print_stats - print the given statistics + * + * return nothing, just do it. + */ +void +bdd_print_stats(stats, file) +bdd_stats stats; +FILE *file; /* probably misout */ +{ + + int total_hashtable_queries; + int total_itetable_lookups; + int total_consttable_lookups; + int total_adhoc_lookups; + + /* + * Make intermediate calculations. + */ + total_hashtable_queries = stats.cache.hashtable.hits + stats.cache.hashtable.misses; + total_itetable_lookups = stats.cache.itetable.hits + stats.cache.itetable.misses; + total_consttable_lookups = stats.cache.consttable.hits + stats.cache.consttable.misses; + total_adhoc_lookups = stats.cache.adhoc.hits + stats.cache.adhoc.misses; + + /* + * Print out the stats. + */ + fprintf(file, "\ +BDD Package Statistics\n\ +\n\ +Blocks (bdd_nodeBlock): %d\n\ +\n\ +Nodes (bdd_node):\n\ + used unused total peak\n\ + %8d %8d %8d %8d\n\ +\n\ +Extptr (bdd_t):\n\ + used unused total\n\ + %8d %8d %8d\n\ +\n\ +Hashtable:\n\ + hits: %8d (%4.1f%%)\n\ + misses: %8d (%4.1f%%)\n\ + total: %8d (find_or_add calls)\n\ +\n\ +Caches: ITE ITE_const adhoc\n\ + Total calls: %8d %8d %8d\n\ + trivial: %9.1f%% %9.1f%% %9.1f%%\n\ + cached: %9.1f%% %9.1f%% %9.1f%%\n\ + full: %9.1f%% %9.1f%% %9.1f%%\n\ + Total lookups: %8d %8d %8d\n\ + misses: %9.1f%% %9.1f%% %9.1f%%\n\ + Total inserts: %8d %8d --\n\ + collisions: %9.1f%% %9.1f%% --\n\ +\n\ +Garbage Collections:\n\ + collections: %d\n\ + total nodes collected: %d\n\ + total time: %.2f sec\n\ +\n\ +Memory Usage (bytes):\n\ + manager: %9d\n\ + bdd_nodes: %9d\n\ + hashtable: %9d\n\ + extptrs (bdd_t): %9d\n\ + ITE cache: %9d\n\ + ITE_const cache: %9d\n\ + adhoc cache: %9d\n\ + total: %9d\n\ +", + stats.blocks.total, + + stats.nodes.used, + stats.nodes.unused, + stats.nodes.total, + stats.nodes.peak, + + stats.extptrs.used, + stats.extptrs.unused, + stats.extptrs.total, + + stats.cache.hashtable.hits, + bdd_get_percentage(stats.cache.hashtable.hits, total_hashtable_queries), + stats.cache.hashtable.misses, + bdd_get_percentage(stats.cache.hashtable.misses, total_hashtable_queries), + total_hashtable_queries, + + stats.ITE_ops.calls, + stats.ITE_constant_ops.calls, + stats.adhoc_ops.calls, + + bdd_get_percentage(stats.ITE_ops.returns.trivial, stats.ITE_ops.calls), + bdd_get_percentage(stats.ITE_constant_ops.returns.trivial, stats.ITE_constant_ops.calls), + bdd_get_percentage(stats.adhoc_ops.returns.trivial, stats.adhoc_ops.calls), + + bdd_get_percentage(stats.ITE_ops.returns.cached, stats.ITE_ops.calls), + bdd_get_percentage(stats.ITE_constant_ops.returns.cached, stats.ITE_constant_ops.calls), + bdd_get_percentage(stats.adhoc_ops.returns.cached, stats.adhoc_ops.calls), + + bdd_get_percentage(stats.ITE_ops.returns.full, stats.ITE_ops.calls), + bdd_get_percentage(stats.ITE_constant_ops.returns.full, stats.ITE_constant_ops.calls), + bdd_get_percentage(stats.adhoc_ops.returns.full, stats.adhoc_ops.calls), + + total_itetable_lookups, + total_consttable_lookups, + total_adhoc_lookups, + + bdd_get_percentage(stats.cache.itetable.misses, total_itetable_lookups), + bdd_get_percentage(stats.cache.consttable.misses, total_consttable_lookups), + bdd_get_percentage(stats.cache.adhoc.misses, total_adhoc_lookups), + + stats.cache.itetable.inserts, + stats.cache.consttable.inserts, + + bdd_get_percentage(stats.cache.itetable.collisions, stats.cache.itetable.inserts), + bdd_get_percentage(stats.cache.consttable.collisions, stats.cache.consttable.inserts), + + stats.gc.times, + stats.gc.nodes_collected, + ((double) stats.gc.runtime / 1000), + + stats.memory.manager, + stats.memory.nodes, + stats.memory.hashtable, + stats.memory.ext_ptrs, + stats.memory.ITE_cache, + stats.memory.ITE_const_cache, + stats.memory.adhoc_cache, + stats.memory.total); +} + diff --git a/sis/bdd_ucb/resize_table.c b/sis/bdd_ucb/resize_table.c new file mode 100644 index 0000000..a013072 --- /dev/null +++ b/sis/bdd_ucb/resize_table.c @@ -0,0 +1,189 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/resize_table.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * + */ +#include /* for BDD_DEBUG_LIFESPAN */ + +#include "util.h" +#include "array.h" +#include "st.h" + +#include "bdd.h" +#include "bdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/bdd_ucb/resize_table.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:02 $ + * $Log: resize_table.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:02 pchong + * imported + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.3 1992/09/21 23:30:31 sis + * Updates from Tom Shiple - this is BDD package release 2.4. + * + * Revision 1.2 1992/09/19 03:26:02 shiple + * Version 2.4 + * Prefaced compile time debug switches with BDD_. Added typecast to void to some function calls. + * Added new prime calculation for hash table sizes. Relocated the functionality of resizing of ITE + * and ITE constant caches. Renamed bdd_resize_tables to bdd_resize_hashtable, and cleaned it up. + * Added usage of bdd_will_exceed_mem_limit in bdd_resize_hashtable. + * + * Revision 1.1 1992/07/29 00:27:11 shiple + * Initial revision + * + * Revision 1.2 1992/05/06 18:51:03 sis + * SIS release 1.1 + * + * Revision 1.1 92/01/08 17:34:41 sis + * Initial revision + * + * Revision 1.1 91/04/11 21:00:10 shiple + * Initial revision + * + * + */ + +#define BDD_NUM_HASH_PRIMES 28 + +/* + * bdd_resize_hashtable - resize the hashtable and make it bigger + * + * Grow the hashtable by its grow factor and grow the cache by its + * grow factor also. Perform a rehash/recache to map all of the old + * stuff into this new larger world. + * + * return nothing, just do it. + */ +void +bdd_resize_hashtable(manager) +bdd_manager *manager; +{ + unsigned int old_nbuckets, next_hash_prime; + bdd_node **old_buckets; + int i, pos; + bdd_node *n, *next_n; + + + /* + * Get the next hash prime. If allocating a new table will cause the manager memory limit to + * be exceeded, then just return. We are trading off time in favor of space; the collision chains + * could become very long. + */ + next_hash_prime = bdd_get_next_hash_prime(manager->heap.hashtable.nbuckets); + if (bdd_will_exceed_mem_limit(manager, (next_hash_prime * sizeof(bdd_node *)), FALSE) == TRUE) { + return; + } + + /* + * Enlarge and clear out the new hashtable. + */ + old_nbuckets = manager->heap.hashtable.nbuckets; + old_buckets = manager->heap.hashtable.buckets; + manager->heap.hashtable.nbuckets = next_hash_prime; + manager->heap.hashtable.rehash_at_nkeys = manager->heap.hashtable.nbuckets * BDD_HASHTABLE_MAXCHAINLEN; + manager->heap.hashtable.buckets = ALLOC(bdd_node *, manager->heap.hashtable.nbuckets); + if (manager->heap.hashtable.buckets == NIL(bdd_node *)) { + (void) bdd_memfail(manager, "bdd_resize_hashtable"); + } + + /* + * Set all the buckets to NIL (so that the gc doesn't traverse them needlessly). + */ + for (i = 0; i < manager->heap.hashtable.nbuckets; i++) { + manager->heap.hashtable.buckets[i] = NIL(bdd_node); + } + + /* + * Remap all of the hashtable entries to the new larger hashtable. + */ + for (i = 0; i < old_nbuckets; i++) { + for (n = old_buckets[i]; n != NIL(bdd_node); n = next_n) { + next_n = n->next; + + pos = bdd_node_hash(manager, n); + + /* link the old data it onto the new bucket list */ + n->next = manager->heap.hashtable.buckets[pos]; + manager->heap.hashtable.buckets[pos] = n; + } + } + + /* + * Free the array of buckets. Note that the entries of the table were simply + * moved over to the new table. + */ + FREE(old_buckets); +} + +/* + * Get the next size for the hashtable. Here, size is defined as the number of buckets. + * This routine makes several assumptions: + * 1) The initial table size is one of the numbers in the array primes, and all + * subsequent sizes are found using this routine. + * 2) A bucket is at least 4 bytes. + * 3) A grow factor of roughly two is desired. + * + * The primes listed are the greatest primes less than successive powers of two, with a safty + * buffer of 4 to account for the malloc overhead. Thus, for 2^7, the largest prime less than + * 2^7-4, which is 113, is used. + */ + +unsigned int bdd_get_next_hash_prime(current_size) +unsigned int current_size; +{ + int i; + static unsigned int primes[BDD_NUM_HASH_PRIMES] = { + 3, + 11, + 23, + 59, + 113, + 251, + 503, + 1019, + 2039, + 4091, + 8179, + 16369, + 32749, + 65521, + 131063, + 262139, + 524269, + 1048571, + 2097143, + 4194287, + 8388593, + 16777199, + 33554393, + 67108859, + 134217689, + 268435399, + 536870879, + 1073741789}; + + for (i = 0; i < BDD_NUM_HASH_PRIMES - 1; i++) { + if (current_size == primes[i]) { +#if defined(BDD_MEMORY_USAGE) /* { */ + (void) fprintf(stdout, "hashtable size = %d\n", primes[i+1]); +#endif + return primes[i+1]; + } + } + + fail("bdd_get_next_hash_prime: current size not found"); +} + + diff --git a/sis/clock/Makefile.am b/sis/clock/Makefile.am new file mode 100644 index 0000000..53d2306 --- /dev/null +++ b/sis/clock/Makefile.am @@ -0,0 +1,7 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libclock.a +libclock_a_SOURCES = clock.c clock_util.c com_clock.c +pkginclude_HEADERS = clock.h +dist_doc_DATA = clock.doc diff --git a/sis/clock/Makefile.in b/sis/clock/Makefile.in new file mode 100644 index 0000000..922361a --- /dev/null +++ b/sis/clock/Makefile.in @@ -0,0 +1,419 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libclock_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/clock +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libclock_a_AR = $(AR) $(ARFLAGS) +libclock_a_LIBADD = +am_libclock_a_OBJECTS = clock.$(OBJEXT) clock_util.$(OBJEXT) \ + com_clock.$(OBJEXT) +libclock_a_OBJECTS = $(am_libclock_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libclock_a_SOURCES) +DIST_SOURCES = $(libclock_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libclock.a +libclock_a_SOURCES = clock.c clock_util.c com_clock.c +pkginclude_HEADERS = clock.h +dist_doc_DATA = clock.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/clock/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/clock/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libclock.a: $(libclock_a_OBJECTS) $(libclock_a_DEPENDENCIES) + -rm -f libclock.a + $(libclock_a_AR) libclock.a $(libclock_a_OBJECTS) $(libclock_a_LIBADD) + $(RANLIB) libclock.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/clock/clock.c b/sis/clock/clock.c new file mode 100644 index 0000000..44c979f --- /dev/null +++ b/sis/clock/clock.c @@ -0,0 +1,691 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/clock/clock.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "clock.h" + +#define EPS 1.0e-12 /* EPSILON for checking floating point equality */ +#define clock_dup_param(new,old,p) \ + ((void)clock_set_parameter(new,p,clock_get_parameter(old,p))) + +/* + * Create the clock signal entry.. It saves the string passed to it + */ +sis_clock_t * +clock_create(name) +char *name; +{ + int i, j; + sis_clock_t *clock; + + clock = ALLOC(sis_clock_t, 1); + clock->name = util_strsav(name); + clock->network = NIL(network_t); + + for(i = RISE_TRANSITION; i <= FALL_TRANSITION; i++){/* RISE and FALL edge */ + clock->edges[i].clock = clock; + clock->edges[i].transition = i; + for(j = 0; j <= 1; j++){ /* SPECIFICATION and WORKING */ + clock->value[i][j].nominal = CLOCK_NOT_SET; + clock->value[i][j].upper_range = CLOCK_NOT_SET; + clock->value[i][j].lower_range = CLOCK_NOT_SET; + clock->dependency[i][j] = lsCreate(); + } + } + + return clock; +} + +/* + * Free the storage associated with the entry for the clock + */ +void +clock_free(clock) +sis_clock_t *clock; +{ + int i, j; + + FREE(clock->name); + for(i = RISE_TRANSITION; i <= FALL_TRANSITION; i++){/* RISE and FALL edge */ + for(j = 0; j <= 1; j++){ /* SPECIFICATION and WORKING */ + LS_ASSERT(lsDestroy(clock->dependency[i][j], (void(*)())0)); + } + } + FREE(clock); +} + +/* + * Adds the clock to the network structure + * Returns 1 if this is a new clock signal, 0 if a clock with the + * same name is already present. Does not overwrite the previous + * definition + */ +int +clock_add_to_network(network, clock) +network_t *network; +sis_clock_t *clock; +{ + lsHandle handle; + + if (clock_get_by_name(network, clock->name) != NIL(sis_clock_t)){ + return 0; + } else { + LS_ASSERT(lsNewEnd(CLOCK(network)->clock_defn, (lsGeneric)clock, &handle)); + clock->network = network; + clock->net_handle = handle; + return 1; + } +} + +void +clock_set_cycletime(network, value) +network_t *network; +double value; +{ + int flag = clock_get_current_setting_index(network); + CLOCK(network)->cycle_time[flag] = value; +} + +double +clock_get_cycletime(network) +network_t *network; +{ + int flag = clock_get_current_setting_index(network); + return (CLOCK(network)->cycle_time[flag]); +} + +/* + * Deletes the clock from the network structure. Returns 1 if sucess + * Frees the memory associated with the clock structure if successful. + */ +int +clock_delete_from_network(network, clock) +network_t *network; +sis_clock_t *clock; +{ + int i, j; + lsGen gen; + char *data; + clock_setting_t setting; + sis_clock_t *current_clk; + clock_edge_t edge, new_edge; + + if (network != clock->network){ + error_append("Clock is not part of network\n"); + return 0; + } + + edge.clock = clock; + setting = clock_get_current_setting(network); + + clock_set_current_setting(network, SPECIFICATION); + foreach_clock(network, gen, current_clk){ + if (current_clk != clock){ + new_edge.clock = current_clk; + for (i=RISE_TRANSITION; i <= FALL_TRANSITION; i++){ + edge.transition = i; + for (j=RISE_TRANSITION; j <= FALL_TRANSITION; j++){ + new_edge.transition = j; + clock_remove_dependency(edge, new_edge); + } + } + } + } + clock_set_current_setting(network, WORKING); + foreach_clock(network, gen, current_clk){ + if (current_clk != clock){ + new_edge.clock = current_clk; + for (i=RISE_TRANSITION; i <= FALL_TRANSITION; i++){ + edge.transition = i; + for (j=RISE_TRANSITION; j <= FALL_TRANSITION; j++){ + new_edge.transition = j; + clock_remove_dependency(edge, new_edge); + } + } + } + } + clock_set_current_setting(network, setting); + + gen = lsGenHandle(clock->net_handle, &data, LS_AFTER); + assert((sis_clock_t *) data == clock); /* Paranoid */ + LS_ASSERT(lsDelBefore(gen, (lsGeneric *) ¤t_clk)); + clock_free(current_clk); + LS_ASSERT(lsFinish(gen)); + + return 1; +} + +/* + * Free all the storage associated with the clock data structure + */ +void +network_clock_free(network) +network_t *network; +{ + int i; + lsGen gen; + sis_clock_t *clock; + array_t *clock_array; + + clock_array = array_alloc(sis_clock_t *, 4); + foreach_clock(network, gen, clock){ + array_insert_last(sis_clock_t *, clock_array, clock); + } + for(i = 0; i < array_n(clock_array); i++){ + clock = array_fetch(sis_clock_t *, clock_array, i); + assert(clock_delete_from_network(network, clock)); + } + LS_ASSERT(lsDestroy(CLOCK(network)->clock_defn, (void(*)())0)); + FREE(network->CLOCK_SLOT); + array_free(clock_array); +} + +/* + * When duplicating a network copy the relevant fields for the clocks + * Note that the network_clock_t strucure iin the network is already allocated + */ +void +network_clock_dup(old, new) +network_t *old, *new; +{ + int i, j; + char *dummy; + lsGen gen, gen2; + clock_setting_t setting; + sis_clock_t *old_clk, *new_clk; + clock_edge_t *edge, old_edge, dup_edge, new_edge; + + /* + * Right now copy the clocking parameters + */ + setting = clock_get_current_setting(old); + foreach_clock(old, gen, old_clk){ + new_clk = clock_create(clock_name(old_clk)); + (void)clock_add_to_network(new, new_clk); + old_edge.clock = old_clk; + new_edge.clock = new_clk; + for(j = 0; j <= 1; j++){ /* SPECIFICATION and WORKING */ +#ifdef _IBMR2 + clock_set_current_setting(new, (enum clock_setting_enum) j); + clock_set_current_setting(old, (enum clock_setting_enum) j); +#else + clock_set_current_setting(new, (clock_setting_t) j); + clock_set_current_setting(old, (clock_setting_t) j); +#endif + clock_set_cycletime(new, clock_get_cycletime(old)); + for(i = RISE_TRANSITION; i <= FALL_TRANSITION; i++){ + old_edge.transition = new_edge.transition = i; + clock_dup_param(new_edge, old_edge, CLOCK_NOMINAL_POSITION); + clock_dup_param(new_edge, old_edge, CLOCK_UPPER_RANGE); + clock_dup_param(new_edge, old_edge, CLOCK_LOWER_RANGE); + } + } + } + /* + * Now add the dependencies.. Generate old dependencies and figure out the + * new clocks with those names. Then add dependencies. + */ + foreach_clock(old, gen, old_clk){ + new_clk = clock_get_by_name(new, clock_name(old_clk)); + assert(new_clk != NIL(sis_clock_t)); + dup_edge.clock = new_clk; + old_edge.clock = old_clk; + for(j = 0; j <= 1; j++){ /* SPECIFICATION and WORKING */ +#ifdef _IBMR2 + clock_set_current_setting(new, (enum clock_setting_enum) j); + clock_set_current_setting(old, (enum clock_setting_enum) j); +#else + clock_set_current_setting(new, (clock_setting_t) j); + clock_set_current_setting(old, (clock_setting_t) j); +#endif + for(i = RISE_TRANSITION; i <= FALL_TRANSITION; i++){ + dup_edge.transition = old_edge.transition = i; + gen2 = clock_gen_dependency(old_edge); + while(lsNext(gen2, &dummy, LS_NH) == LS_OK){ + edge = (clock_edge_t *)dummy; + new_edge.transition = edge->transition; + new_edge.clock = clock_get_by_name(new, clock_name(edge->clock)); + assert(new_edge.clock != NIL(sis_clock_t)); + assert(clock_add_dependency(dup_edge, new_edge)); + } + (void)lsFinish(gen2); + } + } + } + clock_set_current_setting(old, setting); + clock_set_current_setting(new, setting); +} + +/* + * When creating a new network, this routine initializes the clock field + */ +void +network_clock_alloc(network) +network_t *network; +{ + network_clock_t *clk; + + clk = ALLOC(network_clock_t, 1); + network->CLOCK_SLOT = (char *)clk; + CLOCK(network)->clock_defn = lsCreate(); + clock_set_current_setting(network, WORKING); + clock_set_cycletime(network, CLOCK_NOT_SET); + clock_set_current_setting(network, SPECIFICATION); + clock_set_cycletime(network, CLOCK_NOT_SET); +} + +/* + * If edge2 depends on edge1 return TRUE + */ +static int +clock_is_dependent(edge1, edge2) +clock_edge_t edge1, edge2; +{ + lsGen gen; + int status; + char *dummy; + clock_edge_t *new_edge; + + if (edge1.clock == edge2.clock && edge1.transition == edge2.transition) + return TRUE; + + status = FALSE; + gen = clock_gen_dependency(edge1); + while (lsNext(gen, &dummy, LS_NH) == LS_OK){ + new_edge = (clock_edge_t *)dummy; + if (new_edge->clock == edge2.clock && + new_edge->transition == edge2.transition){ + status = TRUE; + break; + } + } + LS_ASSERT(lsFinish(gen)); + + return status; +} +static void +clock_add_no_check_dependency(setting, edge1, edge2) +clock_setting_t setting; +clock_edge_t edge1, edge2; +{ + int j = (int)setting; + + (void)lsNewEnd(edge1.clock->dependency[edge1.transition][j], + (lsGeneric)&(edge2.clock->edges[edge2.transition]), LS_NH); + (void)lsNewEnd(edge2.clock->dependency[edge2.transition][j], + (lsGeneric)&(edge1.clock->edges[edge1.transition]), LS_NH); +} + +/* + * Add the dependency between specified edges.. Returns 0 if error. + */ +int +clock_add_dependency(edge1, edge2) +clock_edge_t edge1, edge2; +{ + int j; + char *dummy; + lsGen gen1, gen2; + clock_edge_t *new_edge1, *new_edge2; + + if (edge1.clock->network != edge2.clock->network) { /* Cannot do it */ + return 0; + } + if (edge1.clock == edge2.clock && edge1.transition == edge2.transition) { + /* No dependency between and edge and itself */ + return 1; + } + j = clock_get_current_setting_index(edge1.clock->network); + + if (ABS(clock_get_parameter(edge1, CLOCK_NOMINAL_POSITION) - + clock_get_parameter(edge2, CLOCK_NOMINAL_POSITION)) > EPS){ + /* Incompatible nominal edge times */ + return 0; + } + + if (clock_is_dependent(edge1, edge2)){ /* No more work needed */ + return 1; + } + + clock_add_no_check_dependency(j, edge1, edge2); + + /* + * Now for the transitive update of the lists... + * The current scheme is a bit excessive but so what + * First add required dependencies between prev members in the list + */ + gen1 = clock_gen_dependency(edge1); + while(lsNext(gen1, &dummy, LS_NH) == LS_OK){ + new_edge1 = (clock_edge_t *)dummy; + + if (new_edge1->clock == edge2.clock && + new_edge1->transition == edge2.transition) { + /* This was the dependency just added */ + continue; + } + + if (!clock_is_dependent(edge2, *new_edge1)){ + clock_add_no_check_dependency(j, edge2, *new_edge1); + } + } + (void)lsFinish(gen1); + /* + * Among members of the other list + */ + gen2 = clock_gen_dependency(edge2); + while(lsNext(gen2, &dummy, LS_NH) == LS_OK){ + new_edge2 = (clock_edge_t *)dummy; + + if (new_edge2->clock == edge1.clock && + new_edge2->transition == edge1.transition) { + /* This was the dependency just added */ + continue; + } + + if (!clock_is_dependent(edge1, *new_edge2)){ + clock_add_no_check_dependency(j, edge1, *new_edge2); + } + } + (void)lsFinish(gen2); + + /* + * Make dependencies between the two lists + */ + gen2 = clock_gen_dependency(edge2); + while(lsNext(gen2, &dummy, LS_NH) == LS_OK){ + new_edge2 = (clock_edge_t *)dummy; + + if (new_edge2->clock == edge1.clock && + new_edge2->transition == edge1.transition) { + /* This was the dependency just added */ + continue; + } + gen1 = clock_gen_dependency(edge1); + while(lsNext(gen1, &dummy, LS_NH) == LS_OK){ + new_edge1 = (clock_edge_t *)dummy; + if (new_edge1->clock == edge2.clock && + new_edge1->transition == edge2.transition) { + continue; + } + if (!clock_is_dependent(*new_edge1, *new_edge2)){ + clock_add_no_check_dependency(j, *new_edge1, *new_edge2); + } + } + (void)lsFinish(gen1); + } + (void)lsFinish(gen2); + + return 1; +} + +/* + * Removes dependencies between two events. + */ +void +clock_remove_dependency(edge1, edge2) +clock_edge_t edge1, edge2; +{ + lsGen gen; + int delete; + char *dummy; + clock_edge_t *new_edge; + + /* + * Delete dependency of edge2 stored in edge1.. Since clock_is_dependent + * returns TRUE if edge1 == edge2 we want to check that cond beforehand + */ + if (edge1.clock == edge2.clock && edge1.transition == edge2.transition){ + return; + } + + /* Delete edge2 from edge1 */ + delete = 0; + gen = clock_gen_dependency(edge1); + while (lsNext(gen, &dummy, LS_NH) == LS_OK){ + new_edge = (clock_edge_t *)dummy; + if (new_edge->clock == edge2.clock && + new_edge->transition == edge2.transition){ + LS_ASSERT(lsDelBefore(gen, (lsGeneric *)&new_edge)); + delete++; + break; + } + } + (void)lsFinish(gen); + + /* Delete edge1 from edge2 */ + gen = clock_gen_dependency(edge2); + while (lsNext(gen, &dummy, LS_NH) == LS_OK){ + new_edge = (clock_edge_t *)dummy; + if (new_edge->clock == edge1.clock && + new_edge->transition == edge1.transition){ + LS_ASSERT(lsDelBefore(gen, (lsGeneric *)&new_edge)); + delete++; + break; + } + } + + /* Check if adequate deleteions have been made */ + if (delete != 0 && delete != 2){ + fail("SERIOUS ERROR: asymmetric dependency lists\n"); + } + (void)lsFinish(gen); +} + +/* + * Returns the generator for the dependent events of edge + */ +lsGen +clock_gen_dependency(edge) +clock_edge_t edge; +{ + int j; + if (edge.clock->network == NIL(network_t)){ + fail("Edge not part of network\n"); + } + j = clock_get_current_setting_index(edge.clock->network); + return lsStart(edge.clock->dependency[edge.transition][j]); +} + +/* + * Given the name of a clock returns the corresponding clock structure. + * Returns NIL(sis_clock_t) if none is found + */ +sis_clock_t * +clock_get_by_name(network, clk_name) +network_t *network; +char *clk_name; +{ + lsGen gen; + char *dummy; + sis_clock_t *clock; + + gen = lsStart(CLOCK(network)->clock_defn); + while (lsNext(gen, &dummy, LS_NH) == LS_OK) { + clock = (sis_clock_t *)dummy; + if (!strcmp(clock->name, clk_name)){ + (void)lsFinish(gen); + return clock; + /* NOTREACHED */ + } + } + (void)lsFinish(gen); + return NIL(sis_clock_t); +} + +/* + * Returns the name of a clock. Do not free the returned string + */ +char * +clock_name(clock) +sis_clock_t *clock; +{ + return clock->name; +} + +/* + * Sets the flag in the data structure specifying the clock data that will + * be retreived or set.. "mode" can either be SPECIFICATION or WORKING + */ +void +clock_set_current_setting(network, mode) +network_t *network; +clock_setting_t mode; +{ + CLOCK(network)->flag = mode; +} + +/* + * Returns the current value of the clock data flag + */ +clock_setting_t +clock_get_current_setting(network) +network_t *network; +{ + return CLOCK(network)->flag; +} + +/* + * Returns the current value of the clock data flag that can be used + * to index the data structure .... + */ +int +clock_get_current_setting_index(network) +network_t *network; +{ + clock_setting_t flag = CLOCK(network)->flag; + + if (flag == SPECIFICATION){ + return 0; + } else if (flag == WORKING) { + return 1; + } else { + /* Should never happen -- return -1 to cause an error on accesing */ + return -1; + } +} + +/* + * Return the number of clocks in the netwrk + */ +int +network_num_clock(network) +network_t *network; +{ + return lsLength(CLOCK(network)->clock_defn); +} + +int +clock_num_dependent_edges(edge) +clock_edge_t edge; +{ + int flag, num; + network_t *net; + + if ((net = edge.clock->network) == NIL(network_t)){ + return 0; + } + flag = clock_get_current_setting_index(net); + num = lsLength(edge.clock->dependency[edge.transition][flag]); + + return num; +} + +/* + * The user can set parameters for the edges on a clock. The + * clock must be part of a network for this to work (Since it + * expects to find the SPECIFICATION/WORKING flag on the network) + */ +int +clock_set_parameter(clock_edge, parameter, value) +clock_edge_t clock_edge; +clock_param_t parameter; +double value; +{ + lsGen gen; + network_t *network; + int which_edge, flag; + clock_edge_t *new_edge; + + if ((network = clock_edge.clock->network) == NIL(network_t)) { + error_append("Clock not part of network\n"); + return 0; + } + + flag = clock_get_current_setting_index(network); + which_edge = clock_edge.transition; + + switch (parameter){ + case CLOCK_NOMINAL_POSITION: + clock_edge.clock->value[which_edge][flag].nominal = value; + /* + * Also need to shift the dependent events + */ + gen = clock_gen_dependency(clock_edge); + while(lsNext(gen, (char **)&new_edge, LS_NH) == LS_OK){ + /* + * Cannot use clock_set_parameter() + * -- will cause unbounded recursion + */ + new_edge->clock->value[new_edge->transition][flag].nominal = value; + } + (void)lsFinish(gen); + break; + case CLOCK_LOWER_RANGE: + clock_edge.clock->value[which_edge][flag].lower_range = value; + break; + case CLOCK_UPPER_RANGE: + clock_edge.clock->value[which_edge][flag].upper_range = value; + break; + default: + fail("bad enum value in clock_set_parameter"); + /* NOTREACHED */ + } + return 1; +} + +double +clock_get_parameter(clock_edge, parameter) +clock_edge_t clock_edge; +clock_param_t parameter; +{ + network_t *network; + int which_edge, flag; + double t, cycle; + + if ((network = clock_edge.clock->network) == NIL(network_t)) { + fail("Clock not part of a network\n"); + } + + flag = clock_get_current_setting_index(network); + cycle = CLOCK(network)->cycle_time[flag]; + which_edge = clock_edge.transition; + + switch (parameter){ + case CLOCK_NOMINAL_POSITION: + return clock_edge.clock->value[which_edge][flag].nominal; + case CLOCK_LOWER_RANGE: + return clock_edge.clock->value[which_edge][flag].lower_range; + case CLOCK_UPPER_RANGE: + return clock_edge.clock->value[which_edge][flag].upper_range; + case CLOCK_ABSOLUTE_VALUE: + if (cycle == CLOCK_NOT_SET) { + return CLOCK_NOT_SET; + } else { + t = clock_edge.clock->value[which_edge][flag].nominal * cycle; + t /= 100.0; + return t; + } + default: + fail("bad enum value in clock_get_parameter"); + /* NOTREACHED */ + } +} +#undef EPS /* undefine EPSILION */ +#endif /* SIS */ diff --git a/sis/clock/clock.doc b/sis/clock/clock.doc new file mode 100644 index 0000000..7ac6190 --- /dev/null +++ b/sis/clock/clock.doc @@ -0,0 +1,250 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/clock/clock.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +The clock package is the interface between the data structures +implementing the clocks and the routines that manipulate or use +information about the clocks. The clock definition is an +integral part of the network. + There are two sets of clocking data --- The user's +specification and the current working values that are determined +by the program. The choice between the two sets is made by setting +a flag using the routine clock_set_current_setting(). + The clocks are represented by the nominal values for the +rising and falling edges. The specification in the blif file will +also denote dependencies between the different phase. The nominal +values are expressed as fractions of the clock cycle. The skew in +the values is represented as absolute deviations. The value of the +clock cycle is either user-specified or automatically generated. + +typedef struct clock_edge_struct { + sis_clock_t *clock; + int transition; /* one of RISE_TRANSITION or FALL_TRANSITION */ +} clock_edge_t; + + Here is brief description of the exported routines. +------------------------------------------------------------------- + +sis_clock_t * +clock_create(name) +char *name; + Create the clock signal entry. It saves the string passed to it. + +void +clock_free(clock) +sis_clock_t *clock; + Free the storage associated with the entry for the clock + +int +clock_add_to_network(network, clock) +network_t *network; +sis_clock_t *clock; + Adds the clock to the network structure + Returns 1 if this is a new clock signal, 0 if a clock with the + same name is already present. Does not overwrite the existing + definition. + +int +clock_delete_from_network(network, clock) +network_t *network; +sis_clock_t *clock; + Deletes the clock from the network structure. Frees the memory + associated with the clock structure. Returns 1 if success -- 0 + if clock is not part of the network (the error message can be + obtained from error_string()) + +int +clock_add_dependency(edge1, edge2) +clock_edge_t edge1, edge2; + Creates dependencies between two events --- edge1 and edge2. + This routine will check if the edge "edge1" has the same nominal + time as that of edge "edge2". If they do then the two edges are + considered as a single event and changing the nominal value of one + will cause a change in the other too. If the nominal times do not + agree or the clocks are not part of the same network, returns 0. + +void +clock_remove_dependency(edge1, edge2) +clock_edge_t edge1, edge2; + Removes dependencies between two events --- edge1 and edge2. After + this routine has been called the two events edge1 and edge2 are no + longer coupled and can be manipulated independently (e.g. by calling + clock_set_parameter() to modify one event without affecting the other). + +lsGen +clock_gen_dependency(clock_edge) +clock_edge_t *clock_edge; + Produces a generator to access all the dependent clock edges when + one edge is given. The elements generated by looping over the + generator are of type "clock_edge_t". Do not free any of the generated + clock_edge_t structures. + + As an example of the use of the generator to generate all the clock + events that depend on the rising edge of clock_signal CLK_0 + + lsGen gen; + char *dummy; + clock_edge_t edge, *new_edge; + + edge.clock = CLK_0; /* CLK_0 is of type (sis_clock_t *) */ + /* can be one of RISE_TRANSITION or FALL_TRANSITION */ + edge.transition = RISE_TRANSITION; + gen = clock_gen_dependency(edge); + while (lsNext(gen, &dummy, LS_NH) == LS_OK){ + new_edge = (clock_edge_t *)dummy; + /* + * do something with new_edge (DO NOT FREE) + */ + } + (void)lsFinish(gen); + +sis_clock_t * +clock_get_by_name(network, clk_name) +network_t *network; +char *clk_name; + Given the name of a clock signal, returns the corresponding + clock structure. Returns NIL(sis_clock_t) if none is found + +foreach_clock(network, gen, clock) +network_t *network; +lsGen gen; +sis_clock_t *clock; + This is a macro expansion to allow the user to generate all the + clocks in the network. The use is similar to the macros foreach_node + etc. provided with the network package. + +char * +clock_name(clock) +sis_clock_t *clock; + Returns the name of a clock. Do not free the returned string. + +typedef enum clock_setting_enum clock_setting_t +enum clock_setting_enum { + SPECIFICATION, WORKING + }; + +void +clock_set_current_setting(network, mode) +network_t *network; +clock_setting_t mode; + Sets the flag in the data structure specifying the clock data + that will be retreived or set. "mode" is an enumerated type + that can either be SPECIFICATION or WORKING + +clock_setting_t +clock_get_current_setting(network) + Returns the current value of the clock data flag. + +int +network_num_clock(network) +network_t *network; + Returns the number of clocks in the network. + + +void +clock_set_cycletime(network, value) +network_t *network; +double value; + Sets the value of the cycle time. One can set either the + SPECIFICATION or WORKING value --- depends on the setting + of a flag (clock_set_current_setting()). + +double +clock_get_cycletime(network) +network_t *network; + Returns the setting of the cycle_time. The value returned is + either the SPECIFICATION or WORKING --- depends on the setting + of a flag (clock_set_current_setting()). If the returned value + is negative then the cycle time has not been set. + + +typedef enum clock_param_enum clock_param_t; +enum clock_param_enum{ + CLOCK_NOMINAL_POSITION, CLOCK_ABSOLUTE_VALUE, + CLOCK_LOWER_RANGE, CLOCK_UPPER_RANGE + }; + +int +clock_num_dependent_edges(clock_edge) +clock_edge_t clock_edge; + Returns the number of edges that depend on the specified "clock_edge". + The set of dependent edges means that changing the nominal value for + one edge will cause it to change for all the dependent edges. + + +int +clock_set_parameter(clock_edge, parameter, value) +clock_edge_t clock_edge; +clock_param_t parameter; +double value; + The user can set parameters for the edges on a clock. The user + can only set the parameters for the current setting of the clock + flag (SPECIFICATION or WORKING). Thus the user must be aware of + the current setting before calling this routine. This poses the + constraint that the clock (part of clock_edge) be already in the + network. + The routine returns 1 if successful, 0 if error (error occurs + when the clock is not part of a network). The clock_edge_t + structure specifies the clock and the edge (RISE_TRANSITION or + FALL_TRANSITION) for which data is being set. + + The parameters that can be set are --- + + CLOCK_NOMINAL_POSITION specifies the relation of the edge in the + clock cycle. The clock cycle can be arbitrarily broken and edges + specified as a percentage of the clock cycle. (Thus an edge midway + in the clock cycle has a nominal position of 50.0). + NOTE: when setting this parameter all dependent edges get modified too. + + CLOCK_LOWER_RANGE allows the user to set the amount by which the + edge can preceed the nominal value. This is set only for the edge + specified (i.e. the dependent edge values are not modified). + + CLOCK_UPPER_RANGE allows the user to specify the amount by which + an edge can succeed the nominal value. This is set only for the + edge specified. + +double +clock_get_parameter(clock_edge, parameter) +clock_edge_t clock_edge; +clock_param_t parameter; + Returns the value of the particular clocking parameter. The + parameter value returned depends on the setting of the clock + flag (SPECIFICATION, WORKING). The clock_edge structure specifies + the clock and the edge (RISE_TRANSITION or FALL_TRANSITION) being + queried. + + In addition to the parameters that can be set by the user, + one can also query the following parameters --- + + CLOCK_ABSOLUTE returns the absolute time of the occurence of the + clock edge. This is done by finding the clock_cycle duration + from the network and translating the percentage specification of + the nominal time into an absolute value. If the return value is + negative, there is an error (possibly the clock cycle duration + has not been set). + +The clock package also provides a means of identifying the delay on the +control input of latches. Currently only one routine is provided. In +future this set of routines will be extented to provide more detailed +information as the users desire. + +sis_clock_t * +clock_get_transitive_clock(network, node, model, phasep, offset) +network_t *network; +node_t *node; +delay_model_t model; +input_phase_t *phasep; +delay_time_t *offset; + Given a node in the network, find the relevant clock signal that it + is generated from. This is useful when the control input of a latch is + known and delay data regarding it is needed. "offset" return the delay + from the clock to the actual control node and "phasep" returns the + phase relationship of the node and the respective clock input. The + delay is computed according to the delay model "model". Returns + NIL(sis_clock_t) if a clock signal is not found in the transitive fanin. diff --git a/sis/clock/clock.h b/sis/clock/clock.h new file mode 100644 index 0000000..9d1aed4 --- /dev/null +++ b/sis/clock/clock.h @@ -0,0 +1,117 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/clock/clock.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#ifndef CLOCK_H +#define CLOCK_H + +/* + * Data structures + */ + +#define CLOCK_SLOT clock +#define CLOCK(network) ((network_clock_t *)((network)->CLOCK_SLOT)) + +#define RISE_TRANSITION 0 +#define FALL_TRANSITION 1 + +#define CLOCK_NOT_SET -1.0 + +typedef enum clock_setting_enum clock_setting_t; +enum clock_setting_enum { + SPECIFICATION = 0, + WORKING = 1 + }; + +typedef enum clock_param_enum clock_param_t; +enum clock_param_enum { + CLOCK_NOMINAL_POSITION, CLOCK_ABSOLUTE_VALUE, + CLOCK_LOWER_RANGE, CLOCK_UPPER_RANGE + }; + +/* + * Structure to store the parameters of an edge + */ +typedef struct clock_val clock_val_t ; +struct clock_val { + double nominal; /* Nominal value (fraction of cycle-time) */ + double lower_range; /* Absolute deviation on lower side */ + double upper_range; /* Absolute deviation on upped side */ + }; + +/* + * Structure to report dependencies of the clock edges + */ +typedef struct clock_edge clock_edge_t ; +typedef struct clock_struct sis_clock_t; + +struct clock_edge{ + sis_clock_t *clock; + int transition; /* RISE_TRANSITION or FALL_TRANSITION */ + }; + +/* + * A clock structure + */ +struct clock_struct { + char *name; /* Name of clock signal */ + lsHandle net_handle; /* Handle inside network clock_defn */ + network_t *network; /* Pointer to the network */ + lsList dependency[2][2]; /* Dependeny lists of the two edges */ + clock_edge_t edges[2]; /* Clock edges -- for dependency code */ + clock_val_t value[2][2]; /* Clock values ----- [i][j] */ + /* i = RISE_TRANSITION or FALL_TRANSITION */ + /* j = SPECIFICATION or WORKING */ + }; + + +typedef struct network_clock_struct network_clock_t; +struct network_clock_struct { + clock_setting_t flag; /* SPECIFICATION or WORKING */ + double cycle_time[2]; /* Stores the cycle time */ + lsList clock_defn; /* Linked list of "sis_clock_t" structures */ + }; + +/* + * Macro to go through all the clocks + */ +#define foreach_clock(network, gen, clock) \ + for(gen = lsStart(CLOCK(network)->clock_defn); \ + (lsNext(gen, (lsGeneric *) &clock, LS_NH) == LS_OK) \ + || ((void) lsFinish(gen), 0); ) +/* + * List of exported routines + */ +EXTERN int clock_add_to_network ARGS((network_t *, sis_clock_t *)); +EXTERN int clock_set_parameter ARGS((clock_edge_t, enum clock_param_enum, double)); +EXTERN int clock_add_dependency ARGS((clock_edge_t, clock_edge_t)); +EXTERN int clock_delete_from_network ARGS((network_t *, sis_clock_t *)); +EXTERN void clock_set_cycletime ARGS((network_t *, double)); +EXTERN void clock_free ARGS((sis_clock_t *)); +EXTERN void network_clock_dup ARGS((network_t *, network_t *)); +EXTERN void network_clock_free ARGS((network_t *)); +EXTERN int network_num_clock ARGS((network_t *)); +EXTERN int clock_num_dependent_edges ARGS((clock_edge_t)); +EXTERN void network_clock_alloc ARGS((network_t *)); +EXTERN void clock_remove_dependency ARGS((clock_edge_t, clock_edge_t)); +EXTERN void clock_set_current_setting ARGS((network_t *, enum clock_setting_enum)); +EXTERN char *clock_name ARGS((sis_clock_t *)); +EXTERN lsGen clock_gen_dependency ARGS((clock_edge_t)); +EXTERN sis_clock_t *clock_get_by_name ARGS((network_t *, char *)); +EXTERN sis_clock_t *clock_create ARGS((char *)); +EXTERN double clock_get_parameter ARGS((clock_edge_t, enum clock_param_enum)); +EXTERN double clock_get_cycletime ARGS((network_t *)); +EXTERN clock_setting_t clock_get_current_setting ARGS((network_t *)); + +/* + * The following routines are internal to the clock package -- + * they are placed here to avoid creation of another file clock_int.h + */ +EXTERN int clock_get_current_setting_index ARGS((network_t *)); + +#endif /* CLOCK_H */ diff --git a/sis/clock/clock_util.c b/sis/clock/clock_util.c new file mode 100644 index 0000000..e669a40 --- /dev/null +++ b/sis/clock/clock_util.c @@ -0,0 +1,91 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/clock/clock_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "clock.h" + +static sis_clock_t *clock_get_transitive_recur(); + +/* + * Given a node in the network, find the relevant clock signal that it + * is generated from. "offset" return the delay of from the clock to the + * actual control node and "phasep" returns the phase relationship of the + * node and the respective clock input. + */ +sis_clock_t * +clock_get_transitive_clock(network, node, model, offset, phasep) +network_t *network; +node_t *node; +delay_model_t model; +delay_time_t *offset; +input_phase_t *phasep; +{ + delay_time_t t; + input_phase_t phase; + sis_clock_t *clock; + + t.rise = t.fall = 0.0; + phase = POS_UNATE; + + clock = clock_get_transitive_recur(network, node, model, &t, &phase); + + *phasep = phase; + *offset = t; + return clock; +} + +static sis_clock_t * +clock_get_transitive_recur(network, node, model, offset, phasep) +network_t *network; +node_t *node; +delay_model_t model; +delay_time_t *offset; +input_phase_t *phasep; +{ + int i; + node_t *fanin; + sis_clock_t *clock; + input_phase_t phase; + delay_time_t delay; + + if (node->type == PRIMARY_OUTPUT){ + node = node_get_fanin(node, 0); + } + + if (node->type == PRIMARY_INPUT){ + return clock_get_by_name(network, node_long_name(node)); + } + + foreach_fanin(node, i, fanin){ + if ((clock = clock_get_transitive_recur(network, fanin, model, offset, phasep)) + != NIL(sis_clock_t)){ + delay = delay_node_pin(node, i, model); + offset->rise += delay.rise; + offset->fall += delay.fall; + /* + * Get the correct phase + */ + phase = node_input_phase(node, fanin); + if (phase == BINATE){ + *phasep = BINATE; + } else if (phase == NEG_UNATE){ + if (*phasep == POS_UNATE){ + *phasep = NEG_UNATE; + } else if (*phasep == NEG_UNATE){ + *phasep = POS_UNATE; + } + } + + return clock; + } + } + return NIL(sis_clock_t); +} +#endif /* SIS */ diff --git a/sis/clock/com_clock.c b/sis/clock/com_clock.c new file mode 100644 index 0000000..106b887 --- /dev/null +++ b/sis/clock/com_clock.c @@ -0,0 +1,101 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/clock/com_clock.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "clock.h" + +/* ARGSUSED */ +com_print_clock(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + lsGen gen, gen2; + sis_clock_t *clock; + int i, num_dep; + clock_edge_t edge, *new_edge; + clock_setting_t flag; + + error_init(); + util_getopt_reset(); + + if (network_num_clock(*network) == 0) return 0; + flag = clock_get_current_setting(*network); + + (void)fprintf(misout,"\t(A value of %.2f means unspecified)\n", CLOCK_NOT_SET); + (void)fprintf(misout,"%s cycle_time = %6.2f\n", + (flag == SPECIFICATION ? "SPECIFIED" : "WORKING"), + clock_get_cycletime(*network)); + + foreach_clock(*network, gen, clock){ + edge.clock = clock; + for (i = RISE_TRANSITION; i <= FALL_TRANSITION; i++){ + edge.transition = i; + (void)fprintf(misout,"%s%s, Nominal=%4.2f, Range=(%5.2f,%-5.2f)\n", + (i == RISE_TRANSITION ? "r'":"f'"), clock_name(clock), + clock_get_parameter(edge, CLOCK_NOMINAL_POSITION), + clock_get_parameter(edge, CLOCK_LOWER_RANGE), + clock_get_parameter(edge, CLOCK_UPPER_RANGE)); + + num_dep = clock_num_dependent_edges(edge); + if ( num_dep > 0){ + (void)fprintf(misout,"\tDependent edges --"); + gen2 = clock_gen_dependency(edge); + while (lsNext(gen2, (char **)&new_edge, LS_NH) == LS_OK){ + (void)fprintf(misout," %s%s", + (new_edge->transition == RISE_TRANSITION ? "r'":"f'"), + clock_name(new_edge->clock)); + } + LS_ASSERT(lsFinish(gen2)); + (void)fprintf(misout,"\n"); + } + } + } + + return 0; +} + +/* ARGSUSED */ +com_chng_clock(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + clock_setting_t setting; + + error_init(); + util_getopt_reset(); + + setting = CLOCK(*network)->flag; + if (setting == SPECIFICATION){ + CLOCK(*network)->flag = WORKING; + } else if (setting == WORKING){ + CLOCK(*network)->flag = SPECIFICATION; + } else { + (void)fprintf(miserr,"Unknown value for clock setting\n"); + return 0; + } + setting = CLOCK(*network)->flag; + + (void)fprintf(misout,"Switching to setting %s\n", + (setting == SPECIFICATION ? "SPECIFICATION" : "WORKING")); + return 0; + +} + +init_clock() +{ + (void)com_add_command("print_clock", com_print_clock, 0); + (void)com_add_command("chng_clock", com_chng_clock, 0); +} +end_clock() +{ +} +#endif /* SIS */ diff --git a/sis/command/Makefile.am b/sis/command/Makefile.am new file mode 100644 index 0000000..f126878 --- /dev/null +++ b/sis/command/Makefile.am @@ -0,0 +1,9 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include -I$(top_srcdir)/port + +noinst_LIBRARIES = libcommand.a +libcommand_a_SOURCES = addcom.c alias.c cmd_set.c command.c commisc.c \ + filec.c get_nodes.c get_true_po.c help.c open_file.c source.c undo.c \ + com_int.h +pkginclude_HEADERS = command.h +dist_doc_DATA = command.doc diff --git a/sis/command/Makefile.in b/sis/command/Makefile.in new file mode 100644 index 0000000..f0dae83 --- /dev/null +++ b/sis/command/Makefile.in @@ -0,0 +1,425 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libcommand_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/command +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libcommand_a_AR = $(AR) $(ARFLAGS) +libcommand_a_LIBADD = +am_libcommand_a_OBJECTS = addcom.$(OBJEXT) alias.$(OBJEXT) \ + cmd_set.$(OBJEXT) command.$(OBJEXT) commisc.$(OBJEXT) \ + filec.$(OBJEXT) get_nodes.$(OBJEXT) get_true_po.$(OBJEXT) \ + help.$(OBJEXT) open_file.$(OBJEXT) source.$(OBJEXT) \ + undo.$(OBJEXT) +libcommand_a_OBJECTS = $(am_libcommand_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libcommand_a_SOURCES) +DIST_SOURCES = $(libcommand_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include -I$(top_srcdir)/port +noinst_LIBRARIES = libcommand.a +libcommand_a_SOURCES = addcom.c alias.c cmd_set.c command.c commisc.c \ + filec.c get_nodes.c get_true_po.c help.c open_file.c source.c undo.c \ + com_int.h + +pkginclude_HEADERS = command.h +dist_doc_DATA = command.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/command/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/command/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libcommand.a: $(libcommand_a_OBJECTS) $(libcommand_a_DEPENDENCIES) + -rm -f libcommand.a + $(libcommand_a_AR) libcommand.a $(libcommand_a_OBJECTS) $(libcommand_a_LIBADD) + $(RANLIB) libcommand.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/command/addcom.c b/sis/command/addcom.c new file mode 100644 index 0000000..51677ad --- /dev/null +++ b/sis/command/addcom.c @@ -0,0 +1,49 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/addcom.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#include "sis.h" +#include "com_int.h" + +avl_tree *command_table; + + +/* ARGSUSED */ +void +com_add_command(name, func_fp, changes) +char *name; +PFI func_fp; +int changes; +{ + char *key, *value; + command_descr_t *descr; + + key = name; + if (avl_delete(command_table, &key, &value)) { + /* delete existing definition for this command */ + (void) fprintf(miserr, "warning: redefining '%s'\n", name); + com_command_free(value); + } + + descr = ALLOC(command_descr_t, 1); + descr->name = util_strsav(name); + descr->command_fp = func_fp; + descr->changes_network = changes; + assert(! avl_insert(command_table, descr->name, (char *) descr)); +} + + +void +com_command_free(value) +char *value; +{ + command_descr_t *command = (command_descr_t *) value; + + FREE(command->name); /* same as key */ + FREE(command); +} diff --git a/sis/command/alias.c b/sis/command/alias.c new file mode 100644 index 0000000..dadb76d --- /dev/null +++ b/sis/command/alias.c @@ -0,0 +1,119 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/alias.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#include "sis.h" +#include "com_int.h" + +avl_tree *alias_table; + + +static void +print_alias(value) +char *value; +{ + int i; + alias_descr_t *alias; + + alias = (alias_descr_t *) value; + (void) fprintf(misout, "%s\t", alias->name); + for(i = 0; i < alias->argc; i++) { + (void) fprintf(misout, " %s", alias->argv[i]); + } + (void) fprintf(misout, "\n"); +} + + +/* ARGSUSED */ +com_alias(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i; + char *key, *value; + alias_descr_t *alias; + avl_generator *gen; + + if (argc == 1) { + avl_foreach_item(alias_table, gen, AVL_FORWARD, &key, &value) { + print_alias(value); + } + return 0; + + } else if (argc == 2) { + if (avl_lookup(alias_table, argv[1], &value)) { + print_alias(value); + } + return 0; + } + + /* delete any existing alias */ + key = argv[1]; + if (avl_delete(alias_table, &key, &value)) { + com_alias_free(value); + } + + alias = ALLOC(alias_descr_t, 1); + alias->name = util_strsav(argv[1]); + alias->argc = argc - 2; + alias->argv = ALLOC(char *, alias->argc); + for(i = 2; i < argc; i++) { + alias->argv[i-2] = util_strsav(argv[i]); + } + assert(! avl_insert(alias_table, alias->name, (char *) alias)); + return 0; +} + +/* ARGSUSED */ +com_unalias(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i; + char *key, *value; + + if (argc < 2) { + (void) fprintf(miserr, "usage: unalias name1 name2 ...\n"); + return 1; + } + + for(i = 1; i < argc; i++) { + key = argv[i]; + if (avl_delete(alias_table, &key, &value)) { + com_alias_free(value); + } + } + return 0; +} + +void +com_free_argv(argc, argv) +int argc; +char **argv; +{ + int i; + + for(i = 0; i < argc; i++) { + FREE(argv[i]); + } + FREE(argv); +} + + +void +com_alias_free(value) +char *value; +{ + alias_descr_t *alias = (alias_descr_t *) value; + + com_free_argv(alias->argc, alias->argv); + FREE(alias->name); /* same as key */ + FREE(alias); +} diff --git a/sis/command/cmd_set.c b/sis/command/cmd_set.c new file mode 100644 index 0000000..4b8b2f5 --- /dev/null +++ b/sis/command/cmd_set.c @@ -0,0 +1,116 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/cmd_set.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#include "sis.h" +#include "com_int.h" + +avl_tree *flag_table; + + +/* ARGSUSED */ +com_set_variable(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + char *flag_value, *key, *value, *set_cmd; + avl_generator *gen; + + if (argc == 0 || argc > 3) { + (void) fprintf(miserr, "usage: set [name] [value]\n"); + return 1; + + } else if (argc == 1) { + avl_foreach_item(flag_table, gen, AVL_FORWARD, &key, &value) { + (void) fprintf(misout, "%s\t%s\n", key, value); + } + return 0; + + } else { + key = argv[1]; + if (avl_delete(flag_table, &key, &value)) { + FREE(key); + FREE(value); + } + + flag_value = argc == 2 ? util_strsav("") : util_strsav(argv[2]); + + (void) avl_insert(flag_table, util_strsav(argv[1]), flag_value); + + if (com_graphics_enabled()) { + /* Let graphical front-end know about new value. */ + set_cmd = ALLOC (char, strlen(argv[1])+strlen(flag_value)+2); + strcat(strcat(strcpy(set_cmd,argv[1]),"\t"),flag_value); + com_graphics_exec ("sis","sis","set",set_cmd); + FREE (set_cmd); + } + + if ((strcmp(argv[1], "sisout") == 0) || + (strcmp(argv[1], "misout") == 0)) { + if (misout != stdout) (void) fclose(misout); + if (strcmp(flag_value, "") == 0) flag_value = "-"; + misout = com_open_file(flag_value, "w", NIL(char *), 0); + if (misout == NULL) misout = stdout; + } + if ((strcmp(argv[1], "siserr") == 0) || + (strcmp(argv[1], "miserr") == 0)) { + if (miserr != stderr) (void) fclose(miserr); + if (strcmp(flag_value, "") == 0) flag_value = "-"; + miserr = com_open_file(flag_value, "w", NIL(char *), 0); + if (miserr == NULL) miserr = stderr; + } + if (strcmp(argv[1], "history") == 0) { + if (sishist != NIL(FILE)) (void) fclose(sishist); + if (strcmp(flag_value, "") == 0) { + sishist = NIL(FILE); + } else { + sishist = com_open_file(flag_value, "w", NIL(char *), 0); + if (sishist == NULL) sishist = NIL(FILE); + } + } + return 0; + } +} + +/* ARGSUSED */ +com_unset_variable(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i; + char *key, *value; + + if (argc < 2) { + (void) fprintf(miserr, "usage: unset val1 val2 ...\n"); + return 1; + } + + for(i = 1; i < argc; i++) { + key = argv[i]; + if (avl_delete(flag_table, &key, &value)) { + FREE(key); + FREE(value); + } + } + return 0; +} + +char * +com_get_flag(flag) +char *flag; +{ + char *value; + + if (avl_lookup(flag_table, flag, &value)) { + return value; + } else { + return NIL(char); + } +} diff --git a/sis/command/com_int.h b/sis/command/com_int.h new file mode 100644 index 0000000..34db567 --- /dev/null +++ b/sis/command/com_int.h @@ -0,0 +1,72 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/com_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#include +#include + +#define MAX_STR 1024 + +typedef int (*PFI)(); + +typedef struct command_descr_struct command_descr_t; +struct command_descr_struct { + char *name; + PFI command_fp; + int changes_network; +}; + + +typedef struct alias_descr_struct alias_descr_t; +struct alias_descr_struct { + char *name; + int argc; + char **argv; +}; + + +typedef struct network_info_struct network_info_t; +struct network_info_struct { + network_t *network; + network_t *original; + lsList history; +}; + +/* Strings for communicating with a graphical front end, used in commisc.c */ + +#define COM_GRAPHICS_MSG_START "#START-GRAPHICS-COMMAND\n" +#define COM_GRAPHICS_MSG_END "#END-GRAPHICS-COMMAND\n" + +extern char sis_hist_char; +extern char sis_shell_char; + +extern avl_tree *command_table; +extern avl_tree *flag_table; +extern avl_tree *alias_table; +extern network_t *backup_network; + +extern int com_alias(); +extern int com_unalias(); +extern int com_execute(); +extern int com_help(); +extern int com_time(); +extern int com_echo(); +extern int com_quit(); +extern int com_set_variable(); +extern int com_unset_variable(); +extern int com_source(); +extern int com_undo(); + +extern void com_free_argv(); +extern void com_alias_free(); +extern void com_command_free(); + +extern char *fgets_filec(); +extern char *hist_subst(); +extern void print_prompt(); + diff --git a/sis/command/command.c b/sis/command/command.c new file mode 100644 index 0000000..9a9f9b8 --- /dev/null +++ b/sis/command/command.c @@ -0,0 +1,307 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/command.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2005/03/08 03:50:51 $ + * + */ +#include "sis.h" +#include "com_int.h" +#include "config.h" + +network_t *backup_network; +char sis_shell_char = '!'; /* can be reset using the "set shell_char" */ + +static int autoexec; /* indicates currently in autoexec */ +static jmp_buf env; + +static int com_dispatch(); +static int apply_alias(); +static char *split_line(); +static int check_shell_escape(); + + +#ifdef _IBMR2 +/* ARGSUSED */ +static RETSIGTYPE +sigterm() +{ + (void) signal(SIGINT, SIG_IGN); /* ignore further ctl-c */ + longjmp(env, 1); +} +#else +/* ARGSUSED */ +static RETSIGTYPE +sigterm(sig, code, scp) +{ + (void) signal(SIGINT, SIG_IGN); /* ignore further ctl-c */ + longjmp(env, 1); +} +#endif + + +com_execute(network, command) +network_t **network; +char *command; +{ + int status, argc; + int loop; + char *commandp, **argv; + + (void) signal(SIGINT, SIG_IGN); + commandp = command; + do { + if (check_shell_escape(commandp, &status)) break; + commandp = split_line(commandp, &argc, &argv); + loop = 0; + status = apply_alias(network, &argc, &argv, &loop); + if (status == 0) { + status = com_dispatch(network, argc, argv); + } + com_free_argv(argc, argv); + } while (status == 0 && *commandp != '\0'); + return status; +} + +static int +com_dispatch(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int status; + char *value; + command_descr_t *descr; + + if (argc == 0) { /* empty command */ + return 0; + } + + if (! avl_lookup(command_table, argv[0], &value)) { + (void) fprintf(miserr, "unknown command '%s'\n", argv[0]); + return 1; + } + + descr = (command_descr_t *) value; + if (setjmp(env)) { + /* return from control-c -- restore the network */ + if (descr->changes_network) { + *network = backup_network; + backup_network = NIL(network_t); + } + return 1; + } + + if (descr->changes_network) { + if (backup_network != NIL(network_t)) { + network_free(backup_network); + } + backup_network = network_dup(*network); + } + + (void) signal(SIGINT, sigterm); + status = (*descr->command_fp)(network, argc, argv); + + /* automatic execution of arbitrary command after each command */ + /* usually this is a passive command ... */ + if (status == 0 && ! autoexec) { + if (avl_lookup(flag_table, "autoexec", &value)) { + autoexec = 1; + status = com_execute(network, value); + autoexec = 0; + } + } + + (void) signal(SIGINT, SIG_IGN); + return status; +} + +/* + * Apply alias. + * If perform a history substitution in expanding an alias, remove all the + * orginal trailing arguments. e.g + * > alias t rl \!:1 + * > t lion.blif would otherwise expand to rl lion.blif lion.blif + */ +static int +apply_alias(network, argcp, argvp, loop) +network_t **network; +int *argcp; +char ***argvp; +int *loop; +{ + int i, argc, stopit, added, offset, did_subst, subst, status, newc, j; + char *arg, **argv, **newv; + alias_descr_t *alias; + + argc = *argcp; + argv = *argvp; + stopit = 0; + for(; *loop < 20; (*loop)++) { + if (argc == 0) { + return 0; + } + if (stopit != 0 || avl_lookup(alias_table, argv[0], (char **) &alias) == 0) { + return 0; + } + if (strcmp(argv[0], alias->argv[0]) == 0) { + stopit = 1; + } + FREE(argv[0]); + added = alias->argc - 1; + + /* shift all the arguments to the right */ + if (added != 0) { + argv = REALLOC(char *, argv, argc + added); + for (i = argc - 1; i >= 1; i--) { + argv[i + added] = argv[i]; + } + for (i = 1; i <= added; i++) { + argv[i] = NIL(char); + } + argc += added; + } + subst = 0; + for (i = 0, offset = 0; i < alias->argc; i++, offset++) { + arg = hist_subst(alias->argv[i], &did_subst); + if (arg == NIL(char)) { + *argcp = argc; + *argvp = argv; + return(1); + } + if (did_subst != 0) { + subst = 1; + } + status = 0; + do { + arg = split_line(arg, &newc, &newv); + /* + * If there's a complete `;' terminated command in `arg', + * when split_line() returns arg[0] != '\0'. + */ + if (arg[0] == '\0') { /* just a bunch of words */ + break; + } + status = apply_alias(network, &newc, &newv, loop); + if (status == 0) { + status = com_dispatch(network, newc, newv); + } + com_free_argv(newc, newv); + } while (status == 0); + if (status != 0) { + *argcp = argc; + *argvp = argv; + return(1); + } + added = newc - 1; + if (added != 0) { + argv = REALLOC(char *, argv, argc + added); + for (j = argc - 1; j > offset; j--) { + argv[j + added] = argv[j]; + } + argc += added; + } + for (j = 0; j <= added; j++) { + argv[j + offset] = newv[j]; + } + FREE(newv); + offset += added; + } + if (subst == 1) { + for (i = offset; i < argc; i++) { + FREE(argv[i]); + } + argc = offset; + } + *argcp = argc; + *argvp = argv; + } + + (void) fprintf(siserr, "error -- alias loop\n"); + return 1; +} + +static char * +split_line(command, argc, argv) +char *command; +int *argc; +char ***argv; +{ + register char *p, *start, c; + register int i, j; + register char *new_arg; + array_t *argv_array; + int single_quote, double_quote; + + argv_array = array_alloc(char *, 5); + + p = command; + for(;;) { + /* skip leading white space */ + while (isspace(*p)) { + p++; + } + + /* skip until end of this token */ + single_quote = double_quote = 0; + for(start = p; (c = *p) != '\0'; p++) { + if (c == ';' || c == '#' || isspace(c)) { + if (! single_quote && ! double_quote) { + break; + } + } + if (c == '\'') { + single_quote = ! single_quote; + } + if (c == '"') { + double_quote = ! double_quote; + } + } + if (single_quote || double_quote) { + (void) fprintf(miserr, "ignoring unbalanced quote ...\n"); + } + if (start == p) break; + + new_arg = ALLOC(char, p - start + 1); + j = 0; + for(i = 0; i < p - start; i++) { + c = start[i]; + if (c != '\'' && c != '\"') { + new_arg[j++] = isspace(c) ? ' ' : start[i]; + } + } + new_arg[j] = '\0'; + array_insert_last(char *, argv_array, new_arg); + } + + *argc = array_n(argv_array); + *argv = array_data(char *, argv_array); + array_free(argv_array); + if (*p == ';') { + p++; + } else if (*p == '#') { + for(; *p != 0; p++) ; /* skip to end of line */ + } + return p; +} + +static int +check_shell_escape(p, status) +char *p; +int *status; +{ + char *value; + while (isspace(*p)) { + p++; + } + if ((value = com_get_flag("shell_char")) != NIL(char)){ + sis_shell_char = *value; + } + if (*p == sis_shell_char) { + *status = system(p+1); + return 1; + } + return 0; +} diff --git a/sis/command/command.doc b/sis/command/command.doc new file mode 100644 index 0000000..434e040 --- /dev/null +++ b/sis/command/command.doc @@ -0,0 +1,155 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/command.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +void +com_add_command(name, func, changes_network) +char *name; +int (*func)(); +int changes_network; + + Adds a command to the command table. If name already defines an + existing command, its definition is replaced. func is a function + pointer to code of the form: + + com_quit(network, argc, argv) + network_t **network; + int argc; + char **argv; + { + return EOF; + } + + Note the double de-reference on the network which is passed to + the command; this allows the command to replace the current + network. argv[0] will generally be the command name, and + argv[1] ... argv[argc-1] are the arguments for the command. + + getopt() can be used to parse the arguments, but getopt_reset() + must be used before calling getopt(). See getopt(3) for more + details. + + The command function should return 0 for normal operation, 1 + for any error. The changes_network flag is used to + automatically save the network before executing the command (in + order to support undo). + + An example command function which parses performs argument + parsing can be found in test/proto.c. + + + + +array_t * +com_get_nodes(network, argc, argv) +network_t *network; +int argc; +char **argv; + + Converts the arguments into a vector of nodes. '*' stands for all + nodes (including each primary input node, and each primary output + node). Functional notation allows i() for all primary inputs, + and i(node) for all fanin's to node. Also, o() for all primary + outputs, and o(node) for all fanouts of a node. + + + + +array_t * +com_get_true_nodes(network, argc, argv) +network_t *network; +int argc; +char **argv; + + Converts the arguments into a vector of nodes. '*' stands for all + nodes (including each primary input node, and each primary output + node). Functional notation allows i() for all primary inputs, + and i(node) for all fanin's to node. Also, o() for all TRUE primary + outputs, and o(node) for all fanouts of a node. NOTE: Actual primary + output nodes are returned, NOT their fanin node. + + + + +char * +com_get_flag(flag) +char *flag; + + The command parser maintains a table of named values. These + are manipulated using the 'set' and 'unset' commands. The + value of the named flag is returned, or NIL(char) is returned + if the flag has not been set. + + + + +FILE * +com_open_file(filename, mode, real_filename, silent) +char *filename; +char *mode; +char **real_filename; +int silent; + + Opens the file with the given mode (see fopen()). Tilde + expansion (~user/ or ~/) is performed on the filename, and "-" + is allowed as a synonym for stdin (or stdout, depending on the + mode). If the file cannot be opened, a message is reported + using perror(); the silent flag, if true, suppresses this error + action. In either case, A NULL file pointer is returned if any + error occurs. The filename (after tilde expansion) is returned in + the pointer real_filename, if real_filename is non-empty. This + is a pointer which should be free'd when you are done with it. + + + +com_execute(network, line) +network_t **network; +char *line; + + Execute a command line. This is the top-level of the command + interpreter, and supports multiple commands (separated by ;), + alias substitution, etc. For many simple operations, com_execute() + is the easiest way to accomplish a given task. + + Example: read a network from a file: + + network = network_alloc; + com_execute(&network, "read_blif filename"); + + Note that network must already exist. Use network_alloc() to + create an empty network first. + +int com_graphics_enabled() + + Returns 1 if sis is in graphics mode, 0 otherwise. + +FILE *com_graphics_open(type,title,cmd) +char *type; +char *title; +char *cmd; + + Initiate a graphics command sent to a window of the given type, + with the given name. Returns the stream which should be used + to send command-specific data to the graphical front end. + +void com_graphics_close(stream) +FILE *stream; + + Indicate the end of the command-specific data and wait for + an acknowledgement from the graphics front end that the data + was received. + +void com_graphics_exec(type,title,cmd,data) +char *type; +char *title; +char *cmd; +char *data; + + Convenience function for issuing a graphics command with very + simple data. Equivalent to a com_graphics_open/fprintf/ + com_graphics_close sequence. diff --git a/sis/command/command.h b/sis/command/command.h new file mode 100644 index 0000000..74d281f --- /dev/null +++ b/sis/command/command.h @@ -0,0 +1,28 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/command.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#ifndef COMMAND_H +#define COMMAND_H + +EXTERN array_t *com_get_nodes ARGS((network_t *, int, char **)); +EXTERN array_t *com_get_true_nodes ARGS((network_t *, int, char **)); +EXTERN array_t *com_get_true_io_nodes ARGS((network_t *, int, char **)); +EXTERN char *com_get_flag ARGS((char*)); +EXTERN void com_add_command ARGS((char*, int (*)(), int)); +EXTERN FILE *com_open_file ARGS((char *, char *, char **, int)); +EXTERN int com_execute ARGS((network_t **, char *)); + +/* Functions to send graphics commands and data to a graphical front end. */ + +EXTERN int com_graphics_enabled ARGS(()); +EXTERN FILE *com_graphics_open ARGS((char *, char *, char *)); +EXTERN void com_graphics_close ARGS((FILE *)); +EXTERN void com_graphics_exec ARGS((char *, char *, char *, char *)); + +#endif /* COMMAND_H */ diff --git a/sis/command/commisc.c b/sis/command/commisc.c new file mode 100644 index 0000000..b873043 --- /dev/null +++ b/sis/command/commisc.c @@ -0,0 +1,354 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/commisc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#include "sis.h" +#include "com_int.h" + + /* If graphics commands are enabled, this is */ + /* the stream where they should be written to. */ + +static FILE *com_graphics_stream = NULL; +static int com_graphics_is_opened = 0; + + + +/* ARGSUSED */ +com_time(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + static long last_time = 0; + long time; + + if (argc != 1) goto usage; + + time = util_cpu_time(); + (void) fprintf(sisout, + "elapse: %2.1f seconds, total: %2.1f seconds\n", + (time - last_time) / 1000.0, time / 1000.0); + last_time = time; + return 0; + +usage: + (void) fprintf(siserr, "usage: time\n"); + return 1; +} + +/* ARGSUSED */ +com_usage(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + if (argc != 1) { + (void) fprintf(siserr, "usage: usage -- give CPU usage statistics\n"); + return 1; + } + + util_print_cpu_stats(sisout); + return 0; +} + +/* ARGSUSED */ +com_echo(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i; + + for(i = 1; i < argc; i++) { + (void) fprintf(sisout, "%s ", argv[i]); + } + (void) fprintf(sisout, "\n"); + return 0; +} + + +/* + * A return value of -1 indicates a quick quit, -2 return frees the memory + */ +com_quit(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + if (argc == 2 && strncmp(argv[1], "-s", 2) == 0) { + return -2; + } + return -1; +} + + +/* ARGSUSED */ +static int +com_infinite_loop(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + *network = 0; + for (;;) ; +} + + +/* ARGSUSED */ +static int +com_save_image(network, argc, argv) +network_t *network; +int argc; +char **argv; +{ + FILE *fp; + char *file1, *file2; + + if (argc != 2) { + (void) fprintf(stderr, "usage: save filename\n"); + return 1; + } + + /* get current executable name by searching the path ... */ + file1 = util_path_search(program_name); + if (file1 == 0) { + (void) fprintf(siserr, "cannot locate current executable\n"); + return 1; + } + + /* users name for the new executable -- perform tilde-expansion */ + fp = com_open_file(argv[1], "w", &file2, /* silent */ 0); + if (fp == NULL) return 1; + if (fp != stdout) (void) fclose(fp); + + if (! util_save_image(file1, file2)) { + (void) fprintf(stderr, "error occured during save ...\n"); + return 1; + } + FREE(file1); + FREE(file2); + return 0; +} + +/* ARGSUSED */ +com_which(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + FILE *fp; + char *filename; + + if (argc != 2) return 1; + + fp = com_open_file(argv[1], "r", &filename, 0); + if (fp != 0) { + (void) fprintf(sisout, "%s\n", filename); + (void) fclose(fp); + } + FREE(filename); + return 0; +} + +/* ARGSUSED */ +com_best(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + static int bst_count = -1; + static network_t *bst_network; + int count = 0; + node_t *node; + lsGen gen; + + foreach_node(*network, gen, node) + if (node->type == INTERNAL) + count += factor_num_literal(node); + + if (bst_count < 0) { + bst_network = network_dup(*network); + bst_count = count; + } + else if (count <= bst_count) { + network_free(bst_network); + bst_network = network_dup(*network); + bst_count = count; + } else { + network_free(*network); + *network = network_dup(bst_network); + } + return 0; +} +/*ARGSUSED*/ +com_history(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i, num, lineno; + int size; + if (argc > 3) { +usage: + (void) fprintf(siserr, "usage: history [-h] [num]\n"); + return(1); + } + num = 30; + lineno = 1; + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + if (argv[i][1] == 'h') { + lineno = 0; + } + else { + goto usage; + } + } + else { + num = atoi(argv[i]); + if (num <= 0) { + goto usage; + } + } + } + size = array_n(command_hist); + num = (num < size) ? num : size; + for (i = size - num; i < size; i++) { + if (lineno != 0) { + (void) fprintf(sisout, "%d\t", i + 1); + } + (void) fprintf(sisout, "%s\n", array_fetch(char *, command_hist, i)); + } + return(0); +} + +int com_graphics_enabled () +{ + /* Returns 1 if graphics commands are enabled. Other packages should + not add graphics commands if this function returns 0. */ + + return (com_graphics_stream != NULL); +} + +FILE *com_graphics_open (type,title,cmd) +char *type; +char *title; +char *cmd; +{ + /* Start a graphics command and return the stream to use. */ + + assert (!com_graphics_is_opened); + assert (com_graphics_stream != NULL); + com_graphics_is_opened = 1; + fputs (COM_GRAPHICS_MSG_START, com_graphics_stream); + fprintf (com_graphics_stream,"%s\t%s\t%s\n", type,cmd,title); + return com_graphics_stream; +} + +void com_graphics_close (stream) +FILE *stream; +{ + /* Finish the graphics command with a graphics trailer. */ + + assert (stream == com_graphics_stream); + fputs (COM_GRAPHICS_MSG_END,stream); + fflush (stream); + com_graphics_is_opened = 0; +} + +void com_graphics_exec (type,title,cmd,data) +char *type; +char *title; +char *cmd; +char *data; +{ + /* Convenience routine for sending simple graphics commands. */ + + if (com_graphics_enabled()) { + FILE *fp = com_graphics_open (type,title,cmd); + fputs (data,fp); fputc ('\n',fp); + com_graphics_close (fp); + } +} + +void com_graphics_help () +{ + /* If graphics is enabled, send list of help topics. */ + + avl_generator *gen; + char *key; + FILE *fp; + + if (!com_graphics_enabled()) return; + fp = com_graphics_open ("sis","sis","commands"); + avl_foreach_item (command_table, gen, AVL_FORWARD, &key, NIL(char *)) { + fprintf(fp,"%s\n",key); + } + com_graphics_close (fp); +} + +/* graphics_flag is the file descriptor for graphics commands, zero means + graphics is disabled. Other packages can call com_graphics_enabled to + selectively add graphics commands. */ + +init_command (graphics_flag) +int graphics_flag; +{ + char *path; + char *lib_name; + FILE *gfp; + + if (graphics_flag != 0) { + com_graphics_stream = (graphics_flag==1) ? stdout : stderr; + /* Open the main sis command window. */ + gfp = com_graphics_open ("cmd","cmd","new"); + fprintf(gfp,".version\t%s\n",sis_version()); + com_graphics_close (gfp); + } + + command_table = avl_init_table(strcmp); + flag_table = avl_init_table(strcmp); + alias_table = avl_init_table(strcmp); + + com_add_command("alias", com_alias, 0); + com_add_command("echo", com_echo, 0); + com_add_command("help", com_help, 0); + com_add_command("quit", com_quit, 0); + com_add_command("save", com_save_image, 0); + com_add_command("source", com_source, 0); + com_add_command("_iloop", com_infinite_loop, 1); + com_add_command("undo", com_undo, 0); + com_add_command("set", com_set_variable, 0); + com_add_command("unalias", com_unalias, 0); + com_add_command("unset", com_unset_variable, 0); + com_add_command("time", com_time, 0); + com_add_command("usage", com_usage, 0); + com_add_command("history", com_history, 0); + com_add_command("_which", com_which, 0); + com_add_command("_best", com_best, 1); + + /* set the default open_path */ + lib_name = sis_library(); + path = ALLOC(char, strlen(lib_name) + 20); + sprintf(path, "set open_path .:%s", lib_name); + com_execute (NULL,path); + FREE(lib_name); + FREE (path); +} + + +end_command() +{ + avl_free_table(flag_table, free, free); + avl_free_table(command_table, (void (*)()) 0, com_command_free); + avl_free_table(alias_table, (void (*)()) 0, com_alias_free); + if (backup_network != NIL(network_t)) { + network_free(backup_network); + } + error_cleanup(); +} diff --git a/sis/command/filec.c b/sis/command/filec.c new file mode 100644 index 0000000..24d25ba --- /dev/null +++ b/sis/command/filec.c @@ -0,0 +1,593 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/filec.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/27 10:33:57 $ + * + */ +#include "autoconf.h" +#include /* Part of util.h if PORT_H is not defined */ + /* Still needs to be included for sun4 compile */ +#include "sis.h" +#if defined(USE_TERMIO) +#include +#else +#include +#endif +#include "com_int.h" + +#define ESC '\033' + +#define BEEP '\007' +#define HIST '%' +#define SUBST '^' + +char sis_hist_char = HIST; /* can be changed by "set hist_char" */ + +static char *seperator = " \t\n;"; + +/* DAK: these are used outside file completion code */ +#define STDIN 0 +#define STDOUT 1 + +/* Do not have access to file-completion in the HPUX systems ... */ + +#if defined(hpux) || defined(SYSTYPE_BSD43) || defined(SYSTYPE_SYSV) +char * +fgets_filec(buf, size, stream, prompt) +char *buf; +int size; +FILE *stream; +char *prompt; +{ + if (prompt != NIL(char)){ + (void) print_prompt(prompt); + (void) fflush(stdout); + } + + return (fgets(buf, size, stream)); +} + +#else + +/* + * Words are seperated by any of the characters in `seperator'. The seperator + * is used to distinguish words from each other in file completion and history + * substitution. The recommeded seperator string is " \t\n;". + */ + +static int cmp(); +static int match(); +static int getnum(); + +/* + * Duplicates the function of fgets, but also provides file completion in the + * same style as csh. + * + * Input is read from `stream' and returned in `buf'. Up to `size' bytes + * will be placed into `buf'. If `stream' is not stdin, is equivalent to + * calling fgets(buf, size, stream). + * + * `prompt' is the prompt you want to appear at the beginning of the line. + * The caller does not have to print the prompt string before calling this + * routine. The prompt has to be reprinted if the user hits ^D. + * + * The file completion routines are derived from the source code for csh, + * which is copyrighted by the Regents of the University of California. + */ +char * +fgets_filec(buf, size, stream, prompt) +char *buf; +int size; +FILE *stream; +char *prompt; +{ + int n_read, i, len, maxlen, col, sno, modname; +#if defined(USE_TERMIO) + struct termios tchars, oldtchars; +#else + struct tchars tchars, oldtchars; +#endif + DIR *dir; + struct dirent *dp; +#if !defined(_IBMR2) + int omask; +#ifndef __STDC__ + struct sgttyb tty, oldtty; /* To mask interuupts */ +#endif +#endif + char *last_word, *file, *path, *name, *line; + char last_char, found[MAXNAMLEN]; + array_t *names; +#if !defined(__STDC__) + int pending = LPENDIN; +#endif + if (prompt != NIL(char)){ + (void) print_prompt(prompt); + (void) fflush(stdout); + } + + sno = fileno(stream); + if (sno != STDIN || !isatty(sno)){ + return (fgets(buf, size, stream)); + } else if (com_get_flag("filec") == NIL(char)) { + /* Get rid of the trailing newline */ + line = fgets(buf, size, stream); + if (line != NULL) { + len = strlen(line); + if (len > 0 && line[len-1] == '\n') { + line[len-1] = '\0'; + } + } + return line; + } + /* Allow hitting ESCAPE to break a read() */ +#if defined(USE_TERMIO) + tcgetattr (sno, &tchars); + oldtchars = tchars; + tchars.c_cc[VEOL] = ESC; + tcsetattr(sno, TCSANOW, &tchars); +#else + (void) ioctl(sno, TIOCGETC, (char *) &tchars); + oldtchars = tchars; + tchars.t_brkc = ESC; + (void) ioctl(sno, TIOCSETC, (char *) &tchars); +#endif + + while ((n_read = read(sno, buf, size)) > 0) { + buf[n_read] = '\0'; + last_word = &buf[n_read - 1]; + last_char = *last_word; + if (last_char == '\n' || n_read == size) { +#if defined(USE_TERMIO) + tcsetattr(sno, TCSANOW, &oldtchars); +#else + (void) ioctl(sno, TIOCSETC, (char *) &oldtchars); +#endif + *last_word = '\0'; + return(buf); + } + if (last_char == ESC) { + *last_word-- = '\0'; + (void) fprintf(stdout, "\b\b \b\b"); + } + else { + names = array_alloc(char *, 10); + (void) fputc('\n', stdout); + } + for (; last_word >= buf; --last_word) { + if (strchr(seperator, *last_word) != NIL(char)) { + break; + } + } + last_word++; + file = strrchr(buf, '/'); + if (file == NIL(char)) { + file = last_word; + modname = 0; + path = "."; + } + else { + *file++ = '\0'; + modname = 1; + path = (*last_word == '~') ? util_tilde_expand(last_word) : + last_word; + } + len = strlen(file); + dir = opendir(path); + if (dir == NIL(DIR) || len > MAXNAMLEN) { + (void) fputc(BEEP, stdout); + } + else { + *found = '\0'; + maxlen = 0; + while ((dp = readdir(dir)) != NIL(struct dirent)) { + if (strncmp(file, dp->d_name, len) == 0) { + if (last_char == ESC) { + if (match(dp->d_name, found, file) == 0) { + break; + } + } + else if (len != 0 || *(dp->d_name) != '.') { + if (maxlen < NAMLEN(dp)) { + maxlen = NAMLEN(dp); + } + array_insert_last(char *, names, util_strsav(dp->d_name)); + } + } + } + (void) closedir(dir); + if (last_char == ESC) { + if (*found == '\0' || strcmp(found, file) == 0) { + (void) fputc(BEEP, stdout); + } + else { + (void) strcpy(file, found); + (void) fprintf(stdout, "%s", &buf[n_read - 1]); + } + } + else { + maxlen += 2; + col = maxlen; + array_sort(names, cmp); + for (i = 0; i < array_n(names); i++) { + name = array_fetch(char *, names, i); + (void) fprintf(stdout, "%-*s", maxlen, name); + FREE(name); + col += maxlen; + if (col >= 80) { + col = maxlen; + (void) fputc('\n', stdout); + } + } + array_free(names); + if (col != maxlen) { + (void) fputc('\n', stdout); + } + } + } + (void) fflush(stdout); + if (modname != 0) { + if (path != last_word) { + FREE(path); + } + *--file = '/'; + } + +#if !defined(_IBMR2) && !defined(__STDC__) + /* mask interrupts temporarily */ + omask = sigblock(sigmask(SIGINT)); + (void) ioctl(STDOUT, TIOCGETP, (char *)&tty); + oldtty = tty; + tty.sg_flags &= ~(ECHO|CRMOD); + (void) ioctl(STDOUT, TIOCSETN, (char *)&tty); +#endif + + /* reprint prompt */ + (void) write(STDOUT, "\r", 1); + print_prompt(prompt); + + /* shove chars from buf back into the input queue */ +#if !defined(__CYGWIN__) + for (i = 0; buf[i]; i++) { + (void) ioctl(STDOUT, TIOCSTI, &buf[i]); + } +#endif +#if !defined(_IBMR2) && !defined(__STDC__) + /* restore interrupts */ + (void) ioctl(STDOUT, TIOCSETN, (char *)&oldtty); + (void) sigsetmask(omask); + (void) ioctl(STDOUT, TIOCLBIS, (char *) &pending); +#endif + } + /* restore read() behavior */ +#if defined(USE_TERMIO) + tcsetattr(sno, TCSANOW, &oldtchars); +#else + (void) ioctl(sno, TIOCSETC, (char *) &oldtchars); +#endif + return(NIL(char)); +} + +static int +cmp(s1, s2) +char **s1, **s2; +{ + return(strcmp(*s1, *s2)); +} + +static int +match(newmatch, lastmatch, actual) +char *newmatch, *lastmatch, *actual; +{ + int i = 0; + + if (*actual == '\0' && *newmatch == '.') { + return(1); + } + if (*lastmatch == '\0') { + (void) strcpy(lastmatch, newmatch); + return(1); + } + while (*newmatch++ == *lastmatch) { + lastmatch++; + i++; + } + *lastmatch = '\0'; + return(i); +} +#endif /* defined(hpux) */ + +static char *do_subst(); +static char *bad_event(); +static char *getarg(); + +#if defined(SYSTYPE_BSD43) +#include +/* BUG: this should be in a library somewhere. + */ +char * +strstr(s, pat) +const char *s, *pat; +{ + int len; + + len = strlen(pat); + for (; *s != '\0'; ++s) + if (*s == *pat && memcmp(s, pat, len) == 0) + return (char *)s; /* UGH */ + return NULL; +} +#endif + +/* + * Simple history substitution routine. + * + * Not, repeat NOT, the complete csh history substitution mechanism. + * + * In the following ^ is the SUBST character and ! is the HIST character. + * Deals with: + * !! last command + * !stuff last command that began with "stuff" + * !* all but 0'th argument of last command + * !$ last argument of last command + * !:n n'th argument of last command + * !n repeat the n'th command + * !-n repeat n'th previous command + * ^old^new replace "old" w/ "new" in previous command + * + * Trailing spaces are significant. + * Removes all initial spaces. + * + * Returns `line' if no changes were made. + * Returns pointer to a static buffer if any changes were made. + * Sets `changed' to 1 if a history substitution took place, o/w set to 0. + * Returns NULL if error occured; + */ +char * +hist_subst(line, changed) +char *line; +int *changed; +{ + static char buf[1024], c; + char *value; + char *last, *old, *new, *start, *b, *l; + int n, len, i, num, internal_change; + + *changed = 0; + internal_change = 0; + while (isspace(*line)) { + line++; + } + if (*line == '\0') { + return(line); + } + n = array_n(command_hist); + last = (n > 0) ? array_fetch(char *, command_hist, n - 1) : ""; + + b = buf; + if (*line == SUBST) { + old = line + 1; + new = strchr(old, SUBST); + if (new == NIL(char)) { + goto bad_modify; + } + *new++ = '\0'; /* makes change in contents of line */ + start = strstr(last, old); + if (start == NIL(char)) { + *--new = SUBST; +bad_modify: + (void) fprintf(stderr, "Modifier failed\n"); + return(NIL(char)); + } + while (last != start) { + *b++ = *last++; + } + b = do_subst(b, new); + last += strlen(old); + while (*b++ = *last++) { + } + *changed = 1; + return(buf); + } + + if ((value = com_get_flag("history_char")) != NIL(char)){ + sis_hist_char = *value; + } + + for (l = line; *b = *l; l++) { + if (*l == sis_hist_char) { + /* + * If a \ immediately preceeds a HIST char, pass just HIST char + * Otherwise pass both \ and the character. + */ + if (l > line && l[-1] == '\\') { + b[-1] = sis_hist_char; + internal_change = 1; + continue; + } + if (n == 0) { + return(bad_event(0)); + } + l++; + /* Cannot use a switch since the history char is a variable !!! */ + if (*l == sis_hist_char){ + /* replace !! in line with last */ + b = do_subst(b, last); + } else if (*l == '$'){ + /* replace !$ in line with last arg of last */ + b = do_subst(b, getarg(last, -1)); + } else if (*l == '*'){ + b = do_subst(b, getarg(last, -2)); + } else if (*l == ':'){ + /* replace !:n in line with n'th arg of last */ + l++; + num = getnum(&l); + new = getarg(last, num); + if (new == NIL(char)) { + (void) fprintf(stderr, "Bad %c arg selector\n", sis_hist_char); + return(NIL(char)); + } + b = do_subst(b, new); + } else if (*l == '-'){ + /* replace !-n in line with n'th prev cmd */ + l++; + num = getnum(&l); + if (num > n || num == 0) { + return(bad_event(n - num + 1)); + } + b = do_subst(b, array_fetch(char *, command_hist, n - num)); + } else { + /* replace !n in line with n'th command */ + if (isdigit(*l)) { + num = getnum(&l); + if (num > n || num == 0) { + return(bad_event(num)); + } + b = do_subst(b, array_fetch(char *, command_hist, num - 1)); + } + else { /* replace !boo w/ last cmd beginning w/ boo */ + start = l; + while (*l && strchr(seperator, *l) == NIL(char)) { + l++; + } + c = *l; + *l = '\0'; + len = strlen(start); + for (i = n - 1; i >= 0; i--) { + old = array_fetch(char *, command_hist, i); + if (strncmp(old, start, len) == 0) { + b = do_subst(b, old); + break; + } + } + if (i < 0) { + (void) fprintf(stderr, "Event not found: %s\n", start); + *l = c; + return(NIL(char)); + } + *l-- = c; + + } + } + *changed = 1; + } + else { + b++; + } + } + if (*changed != 0 || internal_change != 0) { + return(buf); + } + return(line); +} + +static int +getnum(linep) +char **linep; +{ + int num = 0; + char *line = *linep; + + for (; isdigit(*line); line++) { + num *= 10; + num += *line - '0'; + } + *linep = line - 1; + return(num); +} + +static char * +getarg(line, num) +char *line; +int num; +{ + static char buf[128]; + char *b, *c; + int i; + + if (num == -1) { + i = 123456; + } + else if (num == -2) { + i = 1; + } + else { + i = num; + } + + c = line; + do { + b = line = c; + while (*line && strchr(seperator, *line) == NIL(char)) { + line++; + } + c = line; + while (*c && strchr(seperator, *c) != NIL(char)) { + c++; + } + if (*c == '\0') { + break; + } + } while (--i >= 0); + + if (i > 0) { + if (num == -1) { + return(b); + } + return(NIL(char)); + } + if (num < 0) { + return(b); + } + c = buf; + do { + *c++ = *b++; + } while (b < line && c < &buf[127]); + *c = '\0'; + return(buf); +} + +static char * +bad_event(n) +int n; +{ + (void) fprintf(stderr, "Event %d not found\n", n); + return(NIL(char)); +} + +static char * +do_subst(dest, new) +char *dest, *new; +{ + while (*dest = *new++) { + dest++; + } + return(dest); +} + + +void +print_prompt(prompt) +char *prompt; +{ + char buf[256]; + + if (prompt == NIL(char)) return; + + while (*prompt != '\0') { + if (*prompt == sis_hist_char) { + (void) sprintf(buf, "%d", array_n(command_hist) + 1); + (void) write(STDOUT, buf, (int) strlen(buf)); + } + else { + (void) write(STDOUT, prompt, 1); + } + prompt++; + } +} + + + diff --git a/sis/command/get_nodes.c b/sis/command/get_nodes.c new file mode 100644 index 0000000..1c86cd5 --- /dev/null +++ b/sis/command/get_nodes.c @@ -0,0 +1,131 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/get_nodes.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#include "sis.h" +#include "com_int.h" + +static char *get_arg(); +static node_t *get_node_by_name(); + + +array_t * +com_get_nodes(network, argc, argv) +network_t *network; +int argc; +char **argv; +{ + array_t *node_list; + int i, j; + char *arg; + node_t *node, *p; + lsGen gen; + + node_list = array_alloc(node_t *, 32); + + if (argc == 1) { + foreach_node(network, gen, p) { + array_insert_last(node_t *, node_list, p); + } + + } else { + for(i = 1; i < argc; i++) { + if (strcmp(argv[i], "*") == 0) { + foreach_node(network, gen, p) { + array_insert_last(node_t *, node_list, p); + } + + } else if (strncmp(argv[i], "i(", 2) == 0) { + arg = get_arg(argv[i]); + if (strcmp(arg, "") == 0) { + foreach_primary_input(network, gen, p) { + array_insert_last(node_t *, node_list, p); + } + } else { + node = get_node_by_name(network, arg); + if (node == NIL(node_t)) { + (void) fprintf(miserr, "'%s' not found\n", arg); + } else { + foreach_fanin(node, j, p) { + array_insert_last(node_t *, node_list, p); + } + } + } + FREE(arg); + + } else if (strncmp(argv[i], "o(", 2) == 0) { + arg = get_arg(argv[i]); + if (strcmp(arg, "") == 0) { + foreach_primary_output(network, gen, p) { + p = node_get_fanin(p, 0); + array_insert_last(node_t *, node_list, p); + } + } else { + node = get_node_by_name(network, arg); + if (node == NIL(node_t)) { + (void) fprintf(miserr, "'%s' not found\n", arg); + } else { + foreach_fanout(node, gen, p) { + array_insert_last(node_t *, node_list, p); + } + } + } + FREE(arg); + + } else { + p = get_node_by_name(network, argv[i]); + if (p == NIL(node_t)) { + (void) fprintf(miserr, "'%s' not found\n", argv[i]); + } else { + array_insert_last(node_t *, node_list, p); + } + } + } + } + return node_list; +} + + +static char * +get_arg(strng) +char *strng; +{ + char *paren, *arg; + + paren = strchr(strng, '('); + assert(paren != 0); + arg = util_strsav(paren+1); + arg[strlen(arg)-1] = '\0'; + return arg; +} + + +static node_t * +get_node_by_name(network, name) +network_t *network; +char *name; +{ + int found; + char *dummy; + node_t *node; + + if (name_mode == LONG_NAME_MODE) { + found = st_lookup(network->name_table, name, &dummy); + } else { + found = st_lookup(network->short_name_table, name, &dummy); + } + if (found) { + node = (node_t *) dummy; + if (node->type == PRIMARY_OUTPUT) { + node = node_get_fanin(node, 0); + } + return node; + } else { + return NIL(node_t); + } +} diff --git a/sis/command/get_true_po.c b/sis/command/get_true_po.c new file mode 100644 index 0000000..5b8ba66 --- /dev/null +++ b/sis/command/get_true_po.c @@ -0,0 +1,212 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/get_true_po.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#include "sis.h" + +static char *get_arg(); +static node_t *get_true_node_by_name(); + + +array_t * +com_get_true_nodes(network, argc, argv) +network_t *network; +int argc; +char **argv; +{ + array_t *node_list; + int i, j; + char *arg; + node_t *node, *p; + lsGen gen; + + node_list = array_alloc(node_t *, 32); + + if (argc == 1) { + foreach_node(network, gen, p) { + array_insert_last(node_t *, node_list, p); + } + + } else { + for(i = 1; i < argc; i++) { + if (strcmp(argv[i], "*") == 0) { + foreach_node(network, gen, p) { + array_insert_last(node_t *, node_list, p); + } + + } else if (strncmp(argv[i], "i(", 2) == 0) { + arg = get_arg(argv[i]); + if (strcmp(arg, "") == 0) { + foreach_primary_input(network, gen, p) { + array_insert_last(node_t *, node_list, p); + } + } else { + node = get_true_node_by_name(network, arg); + if (node == NIL(node_t)) { + (void) fprintf(miserr, "'%s' not found\n", arg); + } else { + foreach_fanin(node, j, p) { + array_insert_last(node_t *, node_list, p); + } + } + } + FREE(arg); + + } else if (strncmp(argv[i], "o(", 2) == 0) { + arg = get_arg(argv[i]); + if (strcmp(arg, "") == 0) { + foreach_primary_output(network, gen, p) { + array_insert_last(node_t *, node_list, p); + } + } else { + node = get_true_node_by_name(network, arg); + if (node == NIL(node_t)) { + (void) fprintf(miserr, "'%s' not found\n", arg); + } else { + foreach_fanout(node, gen, p) { + array_insert_last(node_t *, node_list, p); + } + } + } + FREE(arg); + + } else { + p = get_true_node_by_name(network, argv[i]); + if (p == NIL(node_t)) { + (void) fprintf(miserr, "'%s' not found\n", argv[i]); + } else { + array_insert_last(node_t *, node_list, p); + } + } + } + } + return node_list; +} + + +/* Performs just like com_get_true_nodes for MISII, but for SIS it retrieves + only real pi/po nodes from i() and o(). That is, the latch pi and po + nodes are filtered out. */ + +array_t * +com_get_true_io_nodes(network, argc, argv) +network_t *network; +int argc; +char **argv; +{ + array_t *node_list; + int i, j; + char *arg; + node_t *node, *p; + lsGen gen; + + node_list = array_alloc(node_t *, 32); + + if (argc == 1) { + foreach_node(network, gen, p) { + array_insert_last(node_t *, node_list, p); + } + + } else { + for(i = 1; i < argc; i++) { + if (strcmp(argv[i], "*") == 0) { + foreach_node(network, gen, p) { + array_insert_last(node_t *, node_list, p); + } + + } else if (strncmp(argv[i], "i(", 2) == 0) { + arg = get_arg(argv[i]); + if (strcmp(arg, "") == 0) { + foreach_primary_input(network, gen, p) { +#ifdef SIS + if (network_is_real_pi(network, p)) +#endif + array_insert_last(node_t *, node_list, p); + } + } else { + node = get_true_node_by_name(network, arg); + if (node == NIL(node_t)) { + (void) fprintf(miserr, "'%s' not found\n", arg); + } else { + foreach_fanin(node, j, p) { + array_insert_last(node_t *, node_list, p); + } + } + } + FREE(arg); + + } else if (strncmp(argv[i], "o(", 2) == 0) { + arg = get_arg(argv[i]); + if (strcmp(arg, "") == 0) { + foreach_primary_output(network, gen, p) { +#ifdef SIS + if (network_is_real_po(network, p)) +#endif + array_insert_last(node_t *, node_list, p); + } + } else { + node = get_true_node_by_name(network, arg); + if (node == NIL(node_t)) { + (void) fprintf(miserr, "'%s' not found\n", arg); + } else { + foreach_fanout(node, gen, p) { + array_insert_last(node_t *, node_list, p); + } + } + } + FREE(arg); + + } else { + p = get_true_node_by_name(network, argv[i]); + if (p == NIL(node_t)) { + (void) fprintf(miserr, "'%s' not found\n", argv[i]); + } else { + array_insert_last(node_t *, node_list, p); + } + } + } + } + return node_list; +} + + +static char * +get_arg(strng) +char *strng; +{ + char *paren, *arg; + + paren = strchr(strng, '('); + assert(paren != 0); + arg = util_strsav(paren+1); + arg[strlen(arg)-1] = '\0'; + return arg; +} + + +static node_t * +get_true_node_by_name(network, name) +network_t *network; +char *name; +{ + int found; + char *dummy; + node_t *node; + + if (name_mode == LONG_NAME_MODE) { + found = st_lookup(network->name_table, name, &dummy); + } else { + found = st_lookup(network->short_name_table, name, &dummy); + } + if (found) { + node = (node_t *) dummy; + return node; + } else { + return NIL(node_t); + } +} diff --git a/sis/command/help.c b/sis/command/help.c new file mode 100644 index 0000000..4441d0e --- /dev/null +++ b/sis/command/help.c @@ -0,0 +1,91 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/help.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/27 10:33:58 $ + * + */ +#include "sis.h" +#include "com_int.h" + + +static char * +command_alias_help(command) +char *command; +{ + char *value; + alias_descr_t *alias; + + if (!avl_lookup(alias_table, command, &value)) { + return command; + } + alias = (alias_descr_t *) value; + return alias->argv[0]; +} + +/* ARGSUSED */ +com_help(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, i, all; + char *geom = NULL; + char *key; + avl_generator *gen; + char buffer[1024]; + char *command; + char *lib_name; + FILE *gfp; + + util_getopt_reset(); + all = 0; + while ((c = util_getopt(argc, argv, "ag:")) != EOF) { + switch(c) { + case 'a': all = 1; break; + case 'g': geom = util_optarg; break; + default: goto usage; + } + } + + if (!all && com_graphics_enabled()) { + gfp = com_graphics_open ("help","help","new"); + if (geom) fprintf(gfp,".geometry\t%s\n",geom); + if (argc - util_optind == 1) { + command = command_alias_help(argv[util_optind]); + } else { + command = "help"; + } + fprintf(gfp,".topic\t%s\n",command); + com_graphics_close (gfp); + } else if (argc - util_optind == 0) { + i = 0; + avl_foreach_item(command_table, gen, AVL_FORWARD, &key, NIL(char *)) { + if ((key[0] == '_') == all) { + (void) fprintf(sisout, "%-15s", key); + if ((++i%5) == 0) (void) fprintf(sisout, "\n"); + } + } + if ((i%5) != 0) (void) fprintf(sisout, "\n"); + } else if (argc - util_optind == 1) { + command = command_alias_help(argv[util_optind]); + lib_name = sis_library(); +#if defined(__CYGWIN__) + (void) sprintf(buffer, "less %s/help/%s.fmt", lib_name, command); +#else + (void) sprintf(buffer, "more %s/help/%s.fmt", lib_name, command); +#endif + (void) system(buffer); + FREE(lib_name); + } else { + goto usage; + } + + return 0; + +usage: + (void) fprintf(siserr, "usage: help [-a] [command]\n"); + return 1; +} diff --git a/sis/command/open_file.c b/sis/command/open_file.c new file mode 100644 index 0000000..148530b --- /dev/null +++ b/sis/command/open_file.c @@ -0,0 +1,72 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/open_file.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#include "sis.h" +#include "com_int.h" + + +FILE * +com_open_file(filename, mode, real_filename_p, silent) +char *filename; +char *mode; +char **real_filename_p; +int silent; +{ + char *real_filename, *path, *user_path; + char *lib_name; + FILE *fp; + + if (strcmp(filename, "-") == 0) { + if (strcmp(mode, "w") == 0) { + real_filename = util_strsav("stdout"); + fp = stdout; + } else { + real_filename = util_strsav("stdin"); + fp = stdin; + } + } else { + real_filename = NIL(char); + if (strcmp(mode, "r") == 0) { + user_path = com_get_flag("open_path"); + if (user_path != NIL(char)) { + lib_name = sis_library(); + path = ALLOC(char, strlen(user_path)+strlen(lib_name)+10); + (void) sprintf(path, "%s:%s", user_path, lib_name); +/* If the filename begins with ./, ../, ~/, or /, AND the file doesn't + actually exist, then SIS will look in the open path (which includes + the sis library) for the file. This could lead to unexpected behavior: + the user is looking for ./msu.genlib, and since that isn't there, the + users gets sis_lib/msu.genlib, and no error is reported. The following + pseudo code fixes this: + + if (the beginning of file_name is : ./ || ../ || ~/ || /) { + real_filename = util_file_search(filename, NIL(char), "r"); + } else +*/ + real_filename = util_file_search(filename, path, "r"); + FREE(path); + FREE(lib_name); + } + } + if (real_filename == NIL(char)) { + real_filename = util_tilde_expand(filename); + } + if ((fp = fopen(real_filename, mode)) == NULL) { + if (! silent) { + perror(real_filename); + } + } + } + if (real_filename_p != 0) { + *real_filename_p = real_filename; + } else { + FREE(real_filename); + } + return fp; +} diff --git a/sis/command/source.c b/sis/command/source.c new file mode 100644 index 0000000..2a59016 --- /dev/null +++ b/sis/command/source.c @@ -0,0 +1,224 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/source.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#include "sis.h" +#include "com_int.h" + +static int end_loop(); + +com_source(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, echo, prompt, silent, status, interactive, quit_count, lp_count = -1; + int lp_lits, lp_time, lp_file_index, did_subst; + char *prompt_string, *real_filename, line[MAX_STR], *command; + delay_model_t model; + FILE *fp; + + model = DELAY_MODEL_UNIT; + interactive = silent = prompt = echo = lp_lits = lp_time = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "ipsxltm:")) != EOF) { + switch(c) { + case 'i': /* a hack to distinguish EOF from stdin */ + interactive = 1; + break; + case 'p': + prompt = 1; + break; + case 's': + silent = 1; + break; + case 'x': + echo = 1; + break; + case 'l': + lp_lits = 1; + break; + case 't': + lp_time = 1; + break; + case 'm': + model = delay_get_model_from_name(util_optarg); + if (model == DELAY_MODEL_UNKNOWN){ + (void)fprintf(siserr, "Unknown delay model %s\n", util_optarg); + goto usage; + } + break; + default: + goto usage; + } + } + +/* Since the source command can accept arguments we will ignore this check */ +/* if (argc - util_optind != 1) goto usage; */ + + lp_file_index = util_optind; + do { + lp_count ++; /* increment the loop counter */ + + fp = com_open_file(argv[lp_file_index], "r", &real_filename, silent); + if (fp == NULL) { + FREE(real_filename); + return ! silent; /* error return if not silent */ + } + + quit_count = 0; + do { + if (prompt) { + prompt_string = com_get_flag("prompt"); +#ifdef SIS + if (prompt_string == NIL(char)) prompt_string = "sis> "; +#else + if (prompt_string == NIL(char)) prompt_string = "misII> "; +#endif +/* (void) fprintf(stdout, "%s", prompt_string); */ + } else { + prompt_string = NIL(char); + } + + /* clear errors -- e.g., EOF reached from stdin */ + clearerr(fp); + + /* read another command line */ + if (fgets_filec(line, MAX_STR, fp, prompt_string) == NULL) { + if (interactive) { + if (quit_count++ < 5) { + (void) fprintf(miserr, "\nUse \"quit\" to leave sis.\n"); + continue; + } + status = -1; /* fake a 'quit' */ + } else { + status = 0; /* successful end of 'source' ; loop? */ + } + break; + } + quit_count = 0; + + if (echo) { + (void) fprintf(misout, "%s", line); + } + command = hist_subst(line, &did_subst); + if (command == NIL(char)) { + status = 1; + break; + } + if (did_subst) { + if (interactive) { + (void) fprintf(stdout, "%s\n", command); + } + } + if (command != line) { + (void) strcpy(line, command); + } + if (interactive && *line != '\0') { + array_insert_last(char *, command_hist, util_strsav(line)); + if (sishist != NIL(FILE)) { + (void) fprintf(sishist, "%s\n", line); + (void) fflush(sishist); + } + } + + status = com_execute(network, line); + } while (status == 0); + + if (fp != stdin) { + if (status > 0) { + (void) fprintf(miserr, "aborting 'source %s'\n", real_filename); + } + (void) fclose(fp); + } + FREE(real_filename); + + } while ((status == 0) && (lp_lits || lp_time) && + ((lp_count <= 0) || !end_loop(network, lp_lits, lp_time, model))); + + return status; + +usage: + (void) fprintf(miserr, "source [-psx] filename\n"); + (void) fprintf(miserr, "\t-p supply prompt before reading each line\n"); + (void) fprintf(miserr, "\t-s silently ignore nonexistant file\n"); + (void) fprintf(miserr, "\t-x echo each line as it is executed\n"); + (void) fprintf(miserr, "\t-l loop while literal count decreases\n"); + (void) fprintf(miserr, "\t-t loop white the arrival time decreases\n"); + (void) fprintf(miserr, "\t-m model : delay model to measure arrival time with\n"); + return 1; +} + +#define SCR_EQ(a,b) (ABS((a)-(b)) < 0.001) /* Floating point equality */ + +/* ARGSUSED */ +static int +end_loop(network, lp_lits, lp_time, model) +network_t **network; +int lp_lits, lp_time; +delay_model_t model; +{ + static int prev_count = -1; + static double prev_delay = -1.0; + static network_t *prev_network = NIL(network_t); + int count = 0; + double delay; + node_t *node; + lsGen gen; + + foreach_node(*network, gen, node) { + if (node->type == INTERNAL) + count += factor_num_literal(node); + } + if (lp_lits) { + if (prev_count < 0) { + prev_network = network_dup(*network); + prev_count = count; + return 0; + } + else if (count < prev_count) { + network_free(prev_network); + prev_network = network_dup(*network); + prev_count = count; + return 0; + } else { + network_free(*network); + *network = prev_network; + prev_network = NIL(network_t); + prev_count = -1; + return 1; + } + } else if (lp_time) { + (void)delay_trace(*network, model); + (void)delay_latest_output(*network, &delay); + if (prev_delay < 0) { + prev_network = network_dup(*network); + prev_delay = delay; + prev_count = count; + return 0; + } + else if ((delay < prev_delay) || + (SCR_EQ(delay,prev_delay) && (count < prev_count)) ) { + network_free(prev_network); + prev_network = network_dup(*network); + prev_delay = delay; + prev_count = count; + return 0; + } else { + network_free(*network); + *network = prev_network; + prev_network = NIL(network_t); + prev_delay = -1; + prev_count = -1; + return 1; + } + } + return 1; +} + +#undef SCR_EQ diff --git a/sis/command/undo.c b/sis/command/undo.c new file mode 100644 index 0000000..f5a08c1 --- /dev/null +++ b/sis/command/undo.c @@ -0,0 +1,36 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/command/undo.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:18 $ + * + */ +#include "sis.h" +#include "com_int.h" + + +/* ARGSUSED */ +com_undo(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *temp; + + if (argc != 1) { + (void) fprintf(miserr, "usage: undo\n"); + return 1; + } + + if (backup_network == NIL(network_t)) { + (void) fprintf(miserr, "undo: no network currently saved\n"); + return 1; + } else { + temp = *network; + *network = backup_network; + backup_network = temp; + return 0; + } +} diff --git a/sis/decomp/Makefile.am b/sis/decomp/Makefile.am new file mode 100644 index 0000000..98eaa6f --- /dev/null +++ b/sis/decomp/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libdecomp.a +libdecomp_a_SOURCES = com_dec.c dec_alg.c dec_sm.c dec_tech.c dec_util.c \ + decomp.c disj.c partition.c decomp_int.h +pkginclude_HEADERS = decomp.h +dist_doc_DATA = decomp.doc diff --git a/sis/decomp/Makefile.in b/sis/decomp/Makefile.in new file mode 100644 index 0000000..0922a39 --- /dev/null +++ b/sis/decomp/Makefile.in @@ -0,0 +1,422 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libdecomp_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/decomp +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libdecomp_a_AR = $(AR) $(ARFLAGS) +libdecomp_a_LIBADD = +am_libdecomp_a_OBJECTS = com_dec.$(OBJEXT) dec_alg.$(OBJEXT) \ + dec_sm.$(OBJEXT) dec_tech.$(OBJEXT) dec_util.$(OBJEXT) \ + decomp.$(OBJEXT) disj.$(OBJEXT) partition.$(OBJEXT) +libdecomp_a_OBJECTS = $(am_libdecomp_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libdecomp_a_SOURCES) +DIST_SOURCES = $(libdecomp_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libdecomp.a +libdecomp_a_SOURCES = com_dec.c dec_alg.c dec_sm.c dec_tech.c dec_util.c \ + decomp.c disj.c partition.c decomp_int.h + +pkginclude_HEADERS = decomp.h +dist_doc_DATA = decomp.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/decomp/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/decomp/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libdecomp.a: $(libdecomp_a_OBJECTS) $(libdecomp_a_DEPENDENCIES) + -rm -f libdecomp.a + $(libdecomp_a_AR) libdecomp.a $(libdecomp_a_OBJECTS) $(libdecomp_a_LIBADD) + $(RANLIB) libdecomp.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/decomp/com_dec.c b/sis/decomp/com_dec.c new file mode 100644 index 0000000..a49d7c8 --- /dev/null +++ b/sis/decomp/com_dec.c @@ -0,0 +1,139 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/com_dec.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "sis.h" +#include "decomp.h" +#include "decomp_int.h" + +static void td_usage(); +static void decomp_usage(); + +int +com_decomp(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, method; + array_t *nodevec; + node_t *np; + int i; + + method = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "dgq")) != EOF) { + switch (c) { + case 'q': + method = 0; + break; + case 'g': + method = 1; + break; + case 'd': + method = 2; + break; + default: + decomp_usage(); + return 1; + } + } + + nodevec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + for(i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + if (np->type == INTERNAL) { + switch (method) { + case 0: + decomp_quick_node(*network, np); + break; + case 1: + decomp_good_node(*network, np); + break; + case 2: + decomp_disj_node(*network, np); + break; + default: + ; + } + } + } + array_free(nodevec); + return 0; +} + +int +com_tdecomp(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, and_limit, or_limit; + + and_limit = 0; + or_limit = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "a:o:")) != EOF) { + switch (c) { + case 'a': + if ((and_limit = atoi(util_optarg)) < 2) { + td_usage(); + return 1; + } + break; + case 'o': + if ((or_limit = atoi(util_optarg)) < 2) { + td_usage(); + return 1; + } + break; + default: + td_usage(); + return 1; + } + } + + if ( and_limit < 2 && or_limit < 2) { + td_usage(); + return 1; + } else if (argc - util_optind == 0) { + decomp_tech_network(*network, and_limit, or_limit); + } else { + td_usage(); + return 1; + } + + return 0; +} + +init_decomp() +{ + com_add_command("decomp", com_decomp, 1); + com_add_command("tech_decomp", com_tdecomp, 1); +} + +end_decomp() +{ +} + +static void +td_usage() +{ + (void) fprintf(miserr, "usage: tech_decomp [-a and] [-o or]\n"); + (void) fprintf(miserr, " -a and \tAnd gate with fanin limit 'and'\n"); + (void) fprintf(miserr, " -o or \tOr gate with fanin limit 'or'\n"); +} + +static void +decomp_usage() +{ + (void) fprintf(miserr, "usage: decomp [-dqg] [node-list]\n"); + (void) fprintf(miserr, " -q\t\tQuick decomposition (default)\n"); + (void) fprintf(miserr, " -g\t\tGood decomposition\n"); + (void) fprintf(miserr, " -d\t\tDisjoint decomposition\n"); +} diff --git a/sis/decomp/dec_alg.c b/sis/decomp/dec_alg.c new file mode 100644 index 0000000..d1ca9a2 --- /dev/null +++ b/sis/decomp/dec_alg.c @@ -0,0 +1,39 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/dec_alg.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "sis.h" +#include "decomp.h" +#include "decomp_int.h" + + +array_t * +decomp_recur(f, gen_divisor) +node_t *f; +node_t *(*gen_divisor)(); +{ + node_t *g; + array_t *fa, *ga; + + if ((g = (*gen_divisor)(f)) != NIL(node_t)) { + if (node_substitute(f, g, 1)) { + fa = decomp_recur(f, gen_divisor); + ga = decomp_recur(g, gen_divisor); + array_append(fa, ga); + array_free(ga); + return fa; + } else { + fail("Internal error: divisor can't be substituted\n"); + return NIL(array_t); + } + } else { + fa = array_alloc(node_t *, 0); + array_insert_last(node_t *, fa, f); + return fa; + } +} diff --git a/sis/decomp/dec_sm.c b/sis/decomp/dec_sm.c new file mode 100644 index 0000000..a5753f4 --- /dev/null +++ b/sis/decomp/dec_sm.c @@ -0,0 +1,129 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/dec_sm.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "sis.h" +#include "decomp.h" +#include "decomp_int.h" + +sm_matrix * +dec_node_to_sm(f) +node_t *f; +{ + sm_matrix *M; + sm_element *element; + sm_col *column; + node_cube_t cube; + node_literal_t literal; + node_t *fanin; + int i, j; + + M = sm_alloc(); + for(i = 0; i < node_num_cube(f); i++) { + cube = node_get_cube(f, i); + foreach_fanin(f, j, fanin) { + literal = node_get_literal(cube, j); + switch (literal) { + case ONE: + element = sm_insert(M, i, j); + sm_put(element, 1); + column = sm_get_col(M, j); + sm_put(column, fanin); + break; + case ZERO: + element = sm_insert(M, i, j); + sm_put(element, 0); + column = sm_get_col(M, j); + sm_put(column, fanin); + break; + case TWO: + break; + default: + fail("bad literal"); + /* NOTREACHED */ + } + } + } + return M; +} + +node_t * +dec_sm_to_node(M) +sm_matrix *M; +{ + node_t *and, *or, *lit, *temp, *fanin; + sm_row *row; + sm_col *col; + sm_element *element; + + or = node_constant(0); + sm_foreach_row(M, row) { + and = node_constant(1); + sm_foreach_row_element(row, element) { + col = sm_get_col(M, element->col_num); + fanin = sm_get(node_t *, col); + switch (sm_get(int, element)) { + case 1: + lit = node_literal(fanin, 1); + break; + case 0: + lit = node_literal(fanin, 0); + break; + default: + fail("bad sm_element_data"); + /* NOTREACHED */ + } + temp = node_and(and, lit); + node_free(lit); + node_free(and); + and = temp; + } + temp = node_or(or, and); + node_free(or); + node_free(and); + or = temp; + } + + return or; +} + +void +dec_sm_print(M) +sm_matrix *M; +{ + sm_col *col; + sm_element *element; + int i, j; + + for (i = 0; i < M->nrows; i++) { + for (j = 0; j < M->ncols; j++) { + element = sm_find(M, i, j); + if (element == NIL(sm_element)) { + (void) fprintf(misout, " ."); + } else { + switch (sm_get(int, element)) { + case 0: + (void) fprintf(misout, " 0"); + break; + case 1: + (void) fprintf(misout, " 1"); + break; + default: + fail("bad sm_element_data"); + /* NOTREACHED */ + } + } + } + (void) fprintf(misout, "\n"); + } + + sm_foreach_col(M, col) { + (void) fprintf(misout, "%3s", node_name(sm_get(node_t *, col))); + } + (void) fprintf(misout, "\n"); +} diff --git a/sis/decomp/dec_tech.c b/sis/decomp/dec_tech.c new file mode 100644 index 0000000..14555c7 --- /dev/null +++ b/sis/decomp/dec_tech.c @@ -0,0 +1,257 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/dec_tech.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "sis.h" +#include "decomp.h" +#include "decomp_int.h" + +static void decomp_and_or(); +static void decomp_or(); +static void decomp_and(); +static void balanced_tree(); + +void +decomp_tech_network(network, and_limit, or_limit) +network_t *network; +int and_limit, or_limit; +{ + lsGen gen; + node_t *node, *f; + array_t *fa; + int i; + + /* Check for a special case: f = a + a' will cause tech_decomp to */ + /* fail unless it is replaced by a constant. */ + foreach_node(network, gen, node) { + if (node->type == INTERNAL) { + if (node_function(node) == NODE_OR) { + foreach_fanin(node, i, f) { + if (node_input_phase(node, f) == BINATE) { + node_replace(node, node_constant(1)); + break; + } + } + } + } + } + fa = network_dfs(network); + for (i = array_n(fa) - 1; i >= 0; i--) { + f = array_fetch(node_t *, fa, i); + if (f->type == INTERNAL) { + decomp_and_or(network, f); + } + } + array_free(fa); + + fa = network_dfs(network); + for (i = array_n(fa) - 1; i >= 0; i--) { + f = array_fetch(node_t *, fa, i); + if (f->type == INTERNAL) { + if (node_function(f) == NODE_OR && or_limit <= 0) { + (void) node_invert(f); + } else if (node_function(f) == NODE_AND && and_limit <= 0) { + (void) node_invert(f); + } + } + } + + array_free(fa); + fa = network_dfs(network); + for (i = array_n(fa) - 1; i >= 0; i--) { + f = array_fetch(node_t *, fa, i); + if (f->type == INTERNAL) { + switch (node_function(f)) { + case NODE_AND: + decomp_and(network, f, and_limit); + break; + case NODE_OR: + decomp_or(network, f, or_limit); + break; + default: + ; + } + } + } + array_free(fa); + + (void) network_sweep(network); +} + +static void +decomp_and_or(network, f) +network_t *network; +node_t *f; +{ + node_t *g, *t, *clit, *c; + int i; + + if (node_function(f) != NODE_COMPLEX) { + return; + } + + g = node_constant(0); + for (i = node_num_cube(f)-1; i>= 0; i--) { + c = dec_node_cube(f, i); + network_add_node(network, c); + clit = node_literal(c, 1); + t = node_or(g, clit); + node_free(clit); + node_free(g); + g = t; + } + node_replace(f, g); +} + +static void +decomp_and(network, f, and_limit) +network_t *network; +node_t *f; +int and_limit; +{ + array_t *nodes, *leaves; + node_t *root, *leaf, *fanin, *node; + int i; + + if (and_limit <= 0) { + fail("Error: wrong fanin limit for AND gate"); + } + + if (node_function(f) != NODE_AND) { + fail("Error: function type is not AND in decomp_and"); + } + +balanced_tree(node_num_fanin(f), and_limit, node_and, &root, &nodes, &leaves); + + /* connect the leaves */ + for (i = array_n(leaves)-1; i >= 0; i--) { + leaf = array_fetch(node_t *, leaves, i); + fanin = node_get_fanin(f, i); + switch (node_input_phase(f, node_get_fanin(f, i))) { + case POS_UNATE: + node_replace(leaf, node_literal(fanin, 1)); + break; + case NEG_UNATE: + node_replace(leaf, node_literal(fanin, 0)); + break; + default: + fail("Error: wrong phase of a input in decomp_and"); + } + } + + /* replace f */ + for (i = array_n(nodes)-1; i >= 0; i--) { + node = array_fetch(node_t *, nodes, i); + if (node == root) { + node_replace(f, node); + } else { + network_add_node(network, node); + } + } + + array_free(nodes); + array_free(leaves); +} + +static void +decomp_or(network, f, or_limit) +network_t *network; +node_t *f; +int or_limit; +{ + array_t *nodes, *leaves; + node_t *root, *leaf, *fanin, *node; + int i; + + if (or_limit <= 0) { + fail("Error: wrong fanin limit for OR gate"); + } + + if (node_function(f) != NODE_OR) { + fail("Error: function type is not OR in decomp_or"); + } + +balanced_tree(node_num_fanin(f), or_limit, node_or, &root, &nodes, &leaves); + + /* connect the leaves */ + for (i = array_n(leaves)-1; i >= 0; i--) { + leaf = array_fetch(node_t *, leaves, i); + fanin = node_get_fanin(f, i); + switch (node_input_phase(f, node_get_fanin(f, i))) { + case POS_UNATE: + node_replace(leaf, node_literal(fanin, 1)); + break; + case NEG_UNATE: + node_replace(leaf, node_literal(fanin, 0)); + break; + default: + fail("Error: wrong phase of a input in decomp_or"); + } + } + + /* replace f */ + for (i = array_n(nodes)-1; i >= 0; i--) { + node = array_fetch(node_t *, nodes, i); + if (node == root) { + node_replace(f, node); + } else { + network_add_node(network, node); + } + } + + array_free(nodes); + array_free(leaves); +} + +static void +balanced_tree(n, m, node_func, root, nodes, leaves) +int n; /* number of leaves */ +int m; /* branching factor */ +node_t *(*node_func)(); /* function at a node */ +node_t **root; /* points to the root of the tree */ +array_t **nodes; /* points to all nodes */ +array_t **leaves; /* points to the leaves */ +{ + node_t *np, *rt; + array_t *ns, *lv; + int d, s; + bool first; + + if (n == 1) { + *root = node_alloc(); + *nodes = array_alloc(node_t *, 0); + array_insert_last(node_t *, *nodes, *root); + *leaves = array_alloc(node_t *, 0); + array_insert_last(node_t *, *leaves, *root); + } else { + first = TRUE; + d = (n + m - 1) / m; + while (n > 0) { + s = MIN(d, n); + n = n - d; + balanced_tree(s, m, node_func, &rt, &ns, &lv); + if (first) { + *root = node_literal(rt, 1); + *nodes = array_alloc(node_t *, 0); + array_insert_last(node_t *, *nodes, *root); + array_append((*nodes), ns); + array_free(ns); + *leaves = lv; + first = FALSE; + } else { + np = node_literal(rt, 1); + node_replace(*root, (*node_func)(*root, np)); + node_free(np); + array_append((*nodes), ns); + array_append((*leaves), lv); + array_free(ns); + array_free(lv); + } + } + } +} diff --git a/sis/decomp/dec_util.c b/sis/decomp/dec_util.c new file mode 100644 index 0000000..6d6cdd0 --- /dev/null +++ b/sis/decomp/dec_util.c @@ -0,0 +1,59 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/dec_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "sis.h" +#include "decomp.h" +#include "decomp_int.h" + +node_t * +decomp_quick_kernel(f) +node_t *f; +{ + return ex_find_divisor_quick(f); +} + +node_t * +decomp_good_kernel(f) +node_t *f; +{ + return ex_find_divisor(f, 1, 1); +} + +node_t * +dec_node_cube(f, i) +node_t *f; +int i; +{ + node_cube_t cube; + node_t *c, *fanin, *tlit, *t; + int j; + + c = node_constant(1); + cube = node_get_cube(f, i); + foreach_fanin(f, j, fanin) { + switch (node_get_literal(cube, j)) { + case ZERO: + tlit = node_literal(fanin, 0); + t = node_and(c, tlit); + node_free(tlit); node_free(c); + c = t; + break; + case ONE: + tlit = node_literal(fanin, 1); + t = node_and(c, tlit); + node_free(tlit); node_free(c); + c = t; + break; + default: + ; + } + } + + return c; +} diff --git a/sis/decomp/decomp.c b/sis/decomp/decomp.c new file mode 100644 index 0000000..58f2328 --- /dev/null +++ b/sis/decomp/decomp.c @@ -0,0 +1,134 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/decomp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "sis.h" +#include "decomp.h" +#include "decomp_int.h" + +void +decomp_quick_network(network) +network_t *network; +{ + lsGen gen; + node_t *f; + + foreach_node(network, gen, f) { + decomp_quick_node(network, f); + } +} + + +void +decomp_quick_node(network, f) +network_t *network; +node_t *f; +{ + array_t *fa; + int i; + + if (f->type == INTERNAL) { + fa = decomp_quick(f); + if (array_n(fa) > 1) { + node_replace(f, array_fetch(node_t *, fa, 0)); + for(i = 1; i < array_n(fa); i++) { + network_add_node(network, array_fetch(node_t *, fa, i)); + } + } else { + node_free(array_fetch(node_t *, fa, 0)); + } + array_free(fa); + } +} + +void +decomp_good_network(network) +network_t *network; +{ + lsGen gen; + node_t *f; + + foreach_node(network, gen, f) { + decomp_good_node(network, f); + } +} + + +void +decomp_good_node(network, f) +network_t *network; +node_t *f; +{ + int i; + array_t *fa; + + if (f->type == INTERNAL) { + fa = decomp_good(f); + if (array_n(fa) > 1) { + node_replace(f, array_fetch(node_t *, fa, 0)); + for(i = 1; i < array_n(fa); i++) { + network_add_node(network, array_fetch(node_t *, fa, i)); + } + } else { + node_free(array_fetch(node_t *, fa, 0)); + } + array_free(fa); + } +} + +void +decomp_disj_network(network) +network_t *network; +{ + lsGen gen; + node_t *f; + + foreach_node(network, gen, f) { + decomp_disj_node(network, f); + } +} + + +void +decomp_disj_node(network, f) +network_t *network; +node_t *f; +{ + int i; + array_t *fa; + + if (f->type == INTERNAL) { + fa = decomp_disj(f); + if (array_n(fa) > 1) { + node_replace(f, array_fetch(node_t *, fa, 0)); + for(i = 1; i < array_n(fa); i++) { + network_add_node(network, array_fetch(node_t *, fa, i)); + } + } else { + node_free(array_fetch(node_t *, fa, 0)); + } + array_free(fa); + } +} + +array_t * +decomp_quick(f) +node_t *f; +{ + node_scc(f); + return decomp_recur(node_dup(f), decomp_quick_kernel); +} + + +array_t * +decomp_good(f) +node_t *f; +{ + node_scc(f); + return decomp_recur(node_dup(f), decomp_good_kernel); +} diff --git a/sis/decomp/decomp.doc b/sis/decomp/decomp.doc new file mode 100644 index 0000000..882156b --- /dev/null +++ b/sis/decomp/decomp.doc @@ -0,0 +1,124 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/decomp.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +Summary: + decomp_quick_network(); + decomp_good_network(); + decomp_disj_network(); + decomp_quick_node(); + decomp_good_node() + decomp_disj_node() + decomp_quick(); + decomp_good(); + decomp_disj(); + + +void +decomp_quick_network(network) +network_t *network; + Decompose all functions in the network using quick + decomposition algorithm (QD). See MIS paper for the + complete description of the algorithm. The new + functions are inserted into the network. + + +void +decomp_good_network(network) +network_t *network; + Decompose all functions in the network using good + decomposition algorithm (GD). See MIS paper for the + complete description of the algorithm. The new + functions are inserted into the network. + + +void +decomp_disj_network(network) +network_t *network; + Decompose all functions in the network using disjoint + decomposition algorithm (DD). See decomp_disj for + for information about the algorithm. The new functions + are inserted into the network. + + +void +decomp_tech_network(network, and_limit, or_limit) +network_t *network; + Decomposes the network into AND and OR gates where the + number of fanins of AND gates is less than or equal to + and_limit and that of OR gates is less than or equal to + or_limit. If and_limit (or_limit) is less than or equal + to 0, the resulting network only consists of OR (AND) + gates. Calling this routine with both and_limit and + or_limit less than or equal to 0 is a series error. + THIS ROUTINE DOES NOT DO KERNEL DECOMPOSITION. + + +void +decomp_quick_node(network, f) +network_t *network; +node_t *f; + Decompose f using quick decomposition algorithm (QD). + See MIS paper for the complete description of the + algorithm. The new functions are inserted into the + network. + + +void +decomp_good_node(network, f) +network_t *network; +node_t *f; + Decompose f using good decomposition algorithm (GD). + See MIS paper for the complete description of the + algorithm. The new functions are inserted into the + network. + + +void +decomp_disj_node(network, f) +network_t *network; +node_t *f; + Decompose f using disjoint decomposition algorithm (DD). + See decomp_disj for more information about the + algorithm. The new functions are inserted into the + network. + + +array_t * +decomp_quick(f) +node_t *f; + Returns an array of nodes which forms the decomposition + of f using quick decomposition algorithm (QD). See MIS + paper for the complete description of the algorithm. + f does not have to be in the network. The root of the + decomposition is guaranteed to be the first element in + the result. + + +array_t * +decomp_good(f) +node_t *f; + Returns an array of nodes which forms the decomposition + of f using good decomposition algorithm (GD). See MIS + paper for the complete description of the algorithm. + f does not have to be in the network. The root of the + decomposition is guaranteed to be the first element in + the result. + + +array_t * +decomp_disj(f) +node_t *f; + Returns an array of nodes which forms the decomposition + of f using disjoint decomposition algorithm (DD). + It partitions the cubes of f into sets of cubes having + disjoint variable support and creates a node for each + partition of cubes and a node (the new f) which is the + OR of all the partitions. f does not have to be in the + network. The root of the decomposition is guaranteed to + be the first element in the result. diff --git a/sis/decomp/decomp.h b/sis/decomp/decomp.h new file mode 100644 index 0000000..ee45379 --- /dev/null +++ b/sis/decomp/decomp.h @@ -0,0 +1,27 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/decomp.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#ifndef DECOMP_H +#define DECOMP_H + +EXTERN void decomp_quick_network ARGS((network_t *)); +EXTERN void decomp_quick_node ARGS((network_t *, node_t *)); +EXTERN array_t *decomp_quick ARGS((node_t *)); + +EXTERN void decomp_good_network ARGS((network_t *)); +EXTERN void decomp_good_node ARGS((network_t *, node_t *)); +EXTERN array_t *decomp_good ARGS((node_t *)); + +EXTERN void decomp_disj_network ARGS((network_t *)); +EXTERN void decomp_disj_node ARGS((network_t *, node_t *)); +EXTERN array_t *decomp_disj ARGS((node_t *)); + +EXTERN void decomp_tech_network ARGS((network_t *, int, int)); + +#endif diff --git a/sis/decomp/decomp_int.h b/sis/decomp/decomp_int.h new file mode 100644 index 0000000..ed68d73 --- /dev/null +++ b/sis/decomp/decomp_int.h @@ -0,0 +1,19 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/decomp_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +extern node_t *decomp_quick_kernel(); +extern node_t *decomp_good_kernel(); +extern array_t *decomp_recur(); +extern array_t *my_array_append(); +extern array_t *decomp_tech_recur(); +extern node_t *dec_node_cube(); +extern int dec_block_partition(); + +extern sm_matrix *dec_node_to_sm(); +extern node_t *dec_sm_to_node(); diff --git a/sis/decomp/disj.c b/sis/decomp/disj.c new file mode 100644 index 0000000..5a26b6a --- /dev/null +++ b/sis/decomp/disj.c @@ -0,0 +1,66 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/disj.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "sis.h" +#include "decomp.h" +#include "decomp_int.h" + + +array_t * +decomp_disj(f) +node_t *f; +{ + array_t *fa; + sm_matrix *M, *L, *R; + node_t *or, *part, *lit, *temp; + + fa = array_alloc(node_t *, 0); + M = dec_node_to_sm(f); + if (dec_block_partition(M, &L, &R)) { + + /* first partition */ + part = dec_sm_to_node(L); + or = node_literal(part, 1); + array_insert_last(node_t *, fa, or); + array_insert_last(node_t *, fa, part); + sm_free(L); + sm_free(M); + M = R; + + /* the rest partition */ + while (dec_block_partition(M, &L, &R)) { + part = dec_sm_to_node(L); + array_insert_last(node_t *, fa, part); + lit = node_literal(part, 1); + temp = node_or(or, lit); + node_free(or); + node_free(lit); + or = temp; + sm_free(L); + sm_free(M); + M = R; + } + + /* last partition */ + part = dec_sm_to_node(M); + array_insert_last(node_t *, fa, part); + lit = node_literal(part, 1); + temp = node_or(or, lit); + node_free(or); + node_free(lit); + array_insert(node_t *, fa, 0, temp); /* root */ + sm_free(M); + + } else { + sm_free(M); + array_insert_last(node_t *, fa, node_dup(f)); + } + + return fa; +} diff --git a/sis/decomp/partition.c b/sis/decomp/partition.c new file mode 100644 index 0000000..5cc0481 --- /dev/null +++ b/sis/decomp/partition.c @@ -0,0 +1,145 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/decomp/partition.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "sis.h" + +static int visit_col(); + +static int +visit_row(A, prow, rows_visited, cols_visited) +sm_matrix *A; +sm_row *prow; +int *rows_visited; +int *cols_visited; +{ + sm_element *p; + sm_col *pcol; + + if (! prow->flag) { + prow->flag = 1; + (*rows_visited)++; + if (*rows_visited == A->nrows) { + return 1; + } + sm_foreach_row_element(prow, p) { + pcol = sm_get_col(A, p->col_num); + if (! pcol->flag) { + if (visit_col(A, pcol, rows_visited, cols_visited)) { + return 1; + } + } + } + } + return 0; +} + + +static int +visit_col(A, pcol, rows_visited, cols_visited) +sm_matrix *A; +sm_col *pcol; +int *rows_visited; +int *cols_visited; +{ + sm_element *p; + sm_row *prow; + + if (! pcol->flag) { + pcol->flag = 1; + (*cols_visited)++; + if (*cols_visited == A->ncols) { + return 1; + } + sm_foreach_col_element(pcol, p) { + prow = sm_get_row(A, p->row_num); + if (! prow->flag) { + if (visit_row(A, prow, rows_visited, cols_visited)) { + return 1; + } + } + } + } + return 0; +} + +static sm_row * +copy_row(A, prow) +register sm_matrix *A; +register sm_row *prow; +{ + register sm_element *p; + register sm_element *element; + + sm_foreach_row_element(prow, p) { + element = sm_insert(A, p->row_num, p->col_num); + sm_put(element, sm_get(char *, p)); + } + return sm_get_row(A, prow->row_num); +} + +static void +block_copy(A, L, R) +register sm_matrix *A; +register sm_matrix **L; +register sm_matrix **R; +{ + register sm_row *prow; + register sm_col *pcol; + register sm_row *nrow; + + sm_foreach_row(A, prow) { + if (prow->flag) { + nrow = copy_row(*L, prow); + } else { + nrow = copy_row(*R, prow); + } + sm_put(nrow, sm_get(char *, prow)); + } + + sm_foreach_col((*L), pcol) { + sm_put(pcol, sm_get(char *, sm_get_col(A, pcol->col_num))); + } + sm_foreach_col((*R), pcol) { + sm_put(pcol, sm_get(char *, sm_get_col(A, pcol->col_num))); + } +} + +int +dec_block_partition(A, L, R) +sm_matrix *A; +sm_matrix **L, **R; +{ + int cols_visited, rows_visited; + register sm_row *prow; + register sm_col *pcol; + + /* Avoid the trivial case */ + if (A->nrows == 0) { + return 0; + } + + /* Reset the visited flags for each row and column */ + sm_foreach_row(A, prow) { + prow->flag = 0; + } + sm_foreach_col(A, pcol) { + pcol->flag = 0; + } + + cols_visited = rows_visited = 0; + if (visit_row(A, A->first_row, &rows_visited, &cols_visited)) { + /* we found all of the rows */ + return 0; + } else { + *L = sm_alloc(); + *R = sm_alloc(); + block_copy(A, L, R); + return 1; + } +} diff --git a/sis/delay/Makefile.am b/sis/delay/Makefile.am new file mode 100644 index 0000000..59b6fae --- /dev/null +++ b/sis/delay/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libdelay.a +libdelay_a_SOURCES = com_delay.c delay.c mapdelay.c tdc_delay.c \ + delay_int.h tdc_int.h +pkginclude_HEADERS = delay.h +dist_doc_DATA = delay.doc diff --git a/sis/delay/Makefile.in b/sis/delay/Makefile.in new file mode 100644 index 0000000..91e0d1b --- /dev/null +++ b/sis/delay/Makefile.in @@ -0,0 +1,421 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libdelay_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/delay +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libdelay_a_AR = $(AR) $(ARFLAGS) +libdelay_a_LIBADD = +am_libdelay_a_OBJECTS = com_delay.$(OBJEXT) delay.$(OBJEXT) \ + mapdelay.$(OBJEXT) tdc_delay.$(OBJEXT) +libdelay_a_OBJECTS = $(am_libdelay_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libdelay_a_SOURCES) +DIST_SOURCES = $(libdelay_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libdelay.a +libdelay_a_SOURCES = com_delay.c delay.c mapdelay.c tdc_delay.c \ + delay_int.h tdc_int.h + +pkginclude_HEADERS = delay.h +dist_doc_DATA = delay.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/delay/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/delay/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libdelay.a: $(libdelay_a_OBJECTS) $(libdelay_a_DEPENDENCIES) + -rm -f libdelay.a + $(libdelay_a_AR) libdelay.a $(libdelay_a_OBJECTS) $(libdelay_a_LIBADD) + $(RANLIB) libdelay.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/delay/com_delay.c b/sis/delay/com_delay.c new file mode 100644 index 0000000..aba5327 --- /dev/null +++ b/sis/delay/com_delay.c @@ -0,0 +1,548 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/delay/com_delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "sis.h" +#include "delay_int.h" + +static int delay_sort_flag; + +static int +delay_sort(node1_p, node2_p) +char **node1_p, **node2_p; +{ + node_t *node1 = *(node_t **) node1_p; + node_t *node2 = *(node_t **) node2_p; + double diff; + delay_time_t delay1, delay2; + + switch(delay_sort_flag) { + case 0: + delay1 = delay_arrival_time(node1); + delay2 = delay_arrival_time(node2); + diff = MAX(delay1.rise, delay1.fall) - MAX(delay2.rise, delay2.fall); + break; + case 1: + delay1 = delay_required_time(node1); + delay2 = delay_required_time(node2); + diff = MAX(delay2.rise, delay2.fall) - MAX(delay1.rise, delay1.fall); + break; + case 2: + delay1 = delay_slack_time(node1); + delay2 = delay_slack_time(node2); + diff = MAX(delay2.rise, delay2.fall) - MAX(delay1.rise, delay1.fall); + break; + case 3: + diff = DELAY(node1)->load - DELAY(node2)->load; + break; + default: + fail("bad delay sort flag"); + /* NOTREACHED */ + } + + if (diff > 0) { + return -1; + } else if (diff == 0) { + return 0; + } else { + return 1; + } +} + + + +#define PRINT_VALUE(n) \ + if (n == DELAY_NOT_SET) \ + (void)fprintf(sisout, "%s", DELAY_NOT_SET_STRING); \ + else \ + (void)fprintf(sisout, "%5.2f ", n); + +#define PRINT_DEFAULT(parm) \ + value = delay_get_default_parameter(net, parm); PRINT_VALUE(value) + +static int +com_print_delay_constraints(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + int i; + node_t *node; + double value; /* used in the PRINT_DEFAULT macro */ + delay_time_t t; + network_t *net = *network; + double f; + + (void) fprintf(sisout, "\t\tA setting of %s means value not specified\n", DELAY_NOT_SET_STRING); + + (void) fprintf(sisout, "Default settings:\n\t\tinput arrival=( "); + PRINT_DEFAULT(DELAY_DEFAULT_ARRIVAL_RISE); + PRINT_DEFAULT(DELAY_DEFAULT_ARRIVAL_FALL); + (void) fprintf(sisout, ")\n\t\tinput drive=( "); + PRINT_DEFAULT(DELAY_DEFAULT_DRIVE_RISE); + PRINT_DEFAULT(DELAY_DEFAULT_DRIVE_FALL); + (void) fprintf(sisout, ")\n\t\tmax input load="); + PRINT_DEFAULT(DELAY_DEFAULT_MAX_INPUT_LOAD); + (void) fprintf(sisout, "\n\t\toutput load="); + PRINT_DEFAULT(DELAY_DEFAULT_OUTPUT_LOAD); + (void) fprintf(sisout, "\n\t\toutput required=( "); + PRINT_DEFAULT(DELAY_DEFAULT_REQUIRED_RISE); + PRINT_DEFAULT(DELAY_DEFAULT_REQUIRED_FALL); + (void) fprintf(sisout, ")\n"); + delay_print_wire_loads(net, sisout); + + node_vec = com_get_nodes(net, argc, argv); + + for(i = 0; i < array_n(node_vec); ++i) { + node = array_fetch(node_t *, node_vec, i); +#ifdef SIS + if(network_is_real_pi(*network, node)) { +#else + if(node->type == PRIMARY_INPUT) { +#endif /* SIS */ + (void) fprintf(sisout, "Settings for input %s:\tarrival=( ", + node_name(node)); + t.rise = t.fall = DELAY_NOT_SET; + (void)delay_get_pi_arrival_time(node, &t); + PRINT_VALUE(t.rise); PRINT_VALUE(t.fall); + (void) fprintf(sisout, ")\tdrive=( "); + t.rise = t.fall = DELAY_NOT_SET; + (void)delay_get_pi_drive(node, &t); + PRINT_VALUE(t.rise); PRINT_VALUE(t.fall); + (void) fprintf(sisout, ")\tmax input load="); + f = DELAY_NOT_SET; + (void)delay_get_pi_load_limit(node, &f); + PRINT_VALUE(f); + (void) fprintf(sisout, "\n"); +#ifdef SIS + } else if(network_is_real_po(*network, node)) { +#else + } else if(node->type == PRIMARY_OUTPUT) { +#endif /* SIS */ + (void) fprintf(sisout, "Settings for output %s:\tload=", + node_name(node)); + value = DELAY_NOT_SET; + (void)delay_get_po_load(node, &value); + PRINT_VALUE(value); + (void) fprintf(sisout, "\trequired=( "); + t.rise = t.fall = DELAY_NOT_SET; + (void)delay_get_po_required_time(node, &t); + PRINT_VALUE(t.rise); PRINT_VALUE(t.fall); + (void) fprintf(sisout, ")\n"); + } + } + array_free(node_vec); + return 0; +} + + + +static int +com_print_delay(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i, c, j, aflag, rflag, sflag, lflag, some_flag, print_max; + array_t *node_vec; + node_t *node; + char *model_filename; + delay_time_t arrival, required, slack; + delay_model_t model; + + aflag = 0; + rflag = 0; + sflag = 0; + lflag = 0; + some_flag = 0; + print_max = INFINITY; + delay_sort_flag = -1; + model = DELAY_MODEL_LIBRARY; + model_filename = NIL(char); + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "alm:p:f:rs")) != EOF) { + switch(c) { + case 'f': + model_filename = util_strsav(util_optarg); + break; + case 'a': + some_flag = 1; + aflag = 1; + if (delay_sort_flag == -1) delay_sort_flag = 0; + break; + case 'm': + model = delay_get_model_from_name(util_optarg); + if (model == DELAY_MODEL_UNKNOWN) goto usage; + break; + case 'l': + some_flag = 1; + lflag = 1; + if (delay_sort_flag == -1) delay_sort_flag = 3; + break; + case 'p': + print_max = atoi(util_optarg); + break; + case 'r': + some_flag = 1; + rflag = 1; + if (delay_sort_flag == -1) delay_sort_flag = 1; + break; + case 's': + some_flag = 1; + sflag = 1; + if (delay_sort_flag == -1) delay_sort_flag = 2; + break; + default: + goto usage; + } + } + + node_vec = com_get_true_nodes(*network, argc-util_optind+1, argv+util_optind-1); + if (array_n(node_vec) < 1) goto usage; + + switch (model) { + case DELAY_MODEL_LIBRARY: + if (lib_network_is_mapped(*network)) { + (void) fprintf(sisout, " ... using library delay model\n"); + if (! delay_trace(*network, DELAY_MODEL_LIBRARY)) { + (void) fprintf(siserr, "%s", error_string()); + array_free(node_vec); + return 1; + } + } else { + (void) fprintf(siserr, + "network not mapped, cannot use library delay model\n"); + array_free(node_vec); + return 1; + } + break; + case DELAY_MODEL_MAPPED: + if (lib_network_is_mapped(*network)) { + (void) fprintf(sisout, + "...network mapped, using library delay model\n"); + if (! delay_trace(*network, DELAY_MODEL_LIBRARY)) { + (void) fprintf(siserr, "%s", error_string()); + array_free(node_vec); + return 1; + } + } else { + (void) fprintf(siserr, + "...network not mapped, using mapped delay model\n"); + if (! delay_trace(*network, DELAY_MODEL_MAPPED)) { + (void) fprintf(siserr, "%s", error_string()); + array_free(node_vec); + return 1; + } + } + break; + + + case DELAY_MODEL_UNIT_FANOUT: + (void) fprintf(sisout, " ... using unit delay model (with fanout)\n"); + if (! delay_trace(*network, DELAY_MODEL_UNIT_FANOUT)) { + (void) fprintf(siserr, "%s", error_string()); + array_free(node_vec); + return 1; + } + break; + + case DELAY_MODEL_UNIT: + (void) fprintf(sisout, " ... using unit delay model (levels)\n"); + if (! delay_trace(*network, DELAY_MODEL_UNIT)) { + (void) fprintf(siserr, "%s", error_string()); + array_free(node_vec); + return 1; + } + break; + + case DELAY_MODEL_TDC: + (void) fprintf(sisout, " ... using tdc delay model with fanout\n"); + delay_set_tdc_params(model_filename); + if (! delay_trace(*network, DELAY_MODEL_TDC)) { + (void) fprintf(siserr, "%s", error_string()); + array_free(node_vec); + return 1; + } + break; + + default: + array_free(node_vec); + goto usage; /* shouldn't happen ? */ + } + + + if (delay_sort_flag != -1) { + array_sort(node_vec, delay_sort); + } + + for(i = 0, j = 0; (j < print_max) && (i < array_n(node_vec)); i++) { + node = array_fetch(node_t *, node_vec, i); + + /* + * Print data on the primary output only once. When multiple + * primary outputs share the same internal node, we will print + * the primary outputs as well as the internal node + */ + if (argc == util_optind && node_function(node) == NODE_PO && + node_num_fanout(node_get_fanin(node,0)) == 1 && + node_type(node_get_fanin(node,0)) == INTERNAL) continue; + else j++; + + arrival = delay_arrival_time(node); + required = delay_required_time(node); + slack = delay_slack_time(node); + + (void) fprintf(sisout, "%-10s: ", node_name(node)); + if (! some_flag || aflag) { + if (arrival.rise < -(INFINITY/2) || arrival.fall < -(INFINITY/2)){ + (void) fprintf(sisout, "arrival=( -INF -INF) "); + } else { + (void) fprintf(sisout, "arrival=(%5.2f %5.2f) ", + arrival.rise, arrival.fall); + } + } + if (! some_flag || rflag) { + if (required.rise < -(INFINITY/2) || required.fall < -(INFINITY/2)){ + (void) fprintf(sisout, "required=(0 0) "); + } else { + (void) fprintf(sisout, "required=(%5.2f %5.2f) ", + required.rise, required.fall); + } + } + if (! some_flag || sflag) { + if (slack.rise > (INFINITY/2) || slack.fall > (INFINITY/2)){ + (void) fprintf(sisout, "slack=( INF INF) "); + } else { + (void) fprintf(sisout, "slack=(%5.2f %5.2f) ", + slack.rise, slack.fall); + } + } + if (lflag) { + (void) fprintf(sisout, "load=%6.3f", DELAY(node)->load); + } + (void) fprintf(sisout, "\n"); + } + if (model_filename != NIL(char)){ + FREE(model_filename); + } + array_free(node_vec); + return 0; + +usage: + (void) fprintf(siserr, + "print_delay [-alrs] [-m model] [-f file] [-p n] n1 n2 ...\n"); + (void) fprintf(siserr, " -a\t\tprint arrival times\n"); + (void) fprintf(siserr, " -l\t\tprint output loads\n"); + (void) fprintf(siserr, " -r\t\tprint required times\n"); + (void) fprintf(siserr, " -s\t\tprint slack times\n"); + (void) fprintf(siserr, + " -m model\tchoose delay model (unit, unit-fanout, library, mapped, tdc)\n"); + (void) fprintf(siserr, + " -f file\t Force parameters to be read from file (for tdc model)\n"); + (void) fprintf(siserr, " -p n\tonly print top 'n' values\n"); + return 1; +} + +enum parm_enum {ATIME, RTIME, LOAD, DRIVE, DEFAULT_RTIME, DEFAULT_ATIME, + DEFAULT_LOAD, DEFAULT_DRIVE, DEFAULT_WIRE, MAX_INPUT_LOAD}; +#define INPUTS 1 +#define OUTPUTS 2 + +static int +com_set_delay(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i, c, set = 0, nodetype = 0, found = 0; + array_t *node_vec; + node_t *node; + delay_param_t rise_parm, fall_parm; + double parm_val; + enum parm_enum set_parameter; + + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "?a:d:i:l:r:A:D:I:L:R:S:W:")) != EOF) { + switch(c) { + case 'a': + set_parameter = ATIME; + ++set; + found = 1; + nodetype = INPUTS; + break; + case 'd': + set_parameter = DRIVE; + ++set; + found = 1; + nodetype = INPUTS; + break; + case 'i': + set_parameter = MAX_INPUT_LOAD; + ++set; + found = 1; + nodetype = INPUTS; + break; + case 'l': + set_parameter = LOAD; + ++set; + found = 1; + nodetype = OUTPUTS; + break; + case 'r': + set_parameter = RTIME; + ++set; + found = 1; + nodetype = OUTPUTS; + break; + case 'A': + case 'D': + case 'I': + case 'L': + case 'R': + case 'S': + case 'W': + if((parm_val = atof(util_optarg)) == HUGE) goto usage; + if(parm_val < 0.0) parm_val = DELAY_VALUE_NOT_GIVEN; + switch(c) { + case 'A': + delay_set_default_parameter(*network, DELAY_DEFAULT_ARRIVAL_RISE, parm_val); + delay_set_default_parameter(*network, DELAY_DEFAULT_ARRIVAL_FALL, parm_val); + break; + case 'D': + delay_set_default_parameter(*network, DELAY_DEFAULT_DRIVE_RISE, parm_val); + delay_set_default_parameter(*network, DELAY_DEFAULT_DRIVE_FALL, parm_val); + break; + case 'I': + delay_set_default_parameter(*network, DELAY_DEFAULT_MAX_INPUT_LOAD, parm_val); + break; + case 'L': + delay_set_default_parameter(*network, DELAY_DEFAULT_OUTPUT_LOAD, parm_val); + break; + case 'R': + delay_set_default_parameter(*network, DELAY_DEFAULT_REQUIRED_RISE, parm_val); + delay_set_default_parameter(*network, DELAY_DEFAULT_REQUIRED_FALL, parm_val); + break; + case 'S': + delay_set_default_parameter(*network, DELAY_WIRE_LOAD_SLOPE, parm_val); + break; + case 'W': + delay_set_default_parameter(*network, DELAY_ADD_WIRE_LOAD, parm_val); + break; + } + break; + default: + goto usage; + } + + if(set > 1) goto usage; + + if(found) { + if((parm_val = atof(util_optarg)) == HUGE) goto usage; + if(parm_val < 0.0) parm_val = DELAY_VALUE_NOT_GIVEN; + } + + found = 0; + } + + node_vec = com_get_true_nodes(*network, argc-util_optind+1, argv+util_optind-1); + + if(set) { + if(array_n(node_vec) == 0) goto usage; + + for(i = 0; i < array_n(node_vec); ++i) { + node = array_fetch(node_t *, node_vec, i); + if(nodetype == INPUTS) { + if(node_function(node) != NODE_PI) goto usage; + } else if(nodetype == OUTPUTS) { + if(node_function(node) != NODE_PO) goto usage; + } else { + goto usage; + } + } + + switch(set_parameter) { + case ATIME: + if(nodetype == OUTPUTS) goto usage; + rise_parm = DELAY_ARRIVAL_RISE; + fall_parm = DELAY_ARRIVAL_FALL; + break; + case DRIVE: + if(nodetype == OUTPUTS) goto usage; + rise_parm = DELAY_DRIVE_RISE; + fall_parm = DELAY_DRIVE_FALL; + break; + case MAX_INPUT_LOAD: + rise_parm = fall_parm = DELAY_MAX_INPUT_LOAD; + break; + case LOAD: + if(nodetype == INPUTS) goto usage; + rise_parm = fall_parm = DELAY_OUTPUT_LOAD; + break; + case RTIME: + if(nodetype == INPUTS) goto usage; + rise_parm = DELAY_REQUIRED_RISE; + fall_parm = DELAY_REQUIRED_FALL; + break; + default: + abort(); /* not reached */ + } + + + for(i = 0; i < array_n(node_vec); ++i) { + node = array_fetch(node_t *, node_vec, i); + delay_set_parameter(node, rise_parm, parm_val); + delay_set_parameter(node, fall_parm, parm_val); + } + } + + array_free(node_vec); + return 0; + + usage: + (void) fprintf(siserr, + "set_delay [-a|d|i|l|r f] [-A f] [-D f] [-I f] [-L f] [-R f] [-S f] [-W f] [o1 o2 ... | i1 i2 ...]\n"); + (void) fprintf(siserr, " -a f\t\tset arrival times to f\n"); + (void) fprintf(siserr, " -d f\t\tset drives from primary inputs to f\n"); + (void) fprintf(siserr, " -i f\t\tset max load limit on primary inputs to f\n"); + (void) fprintf(siserr, " -l f\t\tset loads on primary outputs to f\n"); + (void) fprintf(siserr, " -r f\t\tset required times to f\n"); + (void) fprintf(siserr, " -A f\t\tset default arrival time to f\n"); + (void) fprintf(siserr, " -D f\t\tset default input drive to f\n"); + (void) fprintf(siserr, " -I f\t\tset default max input load to f\n"); + (void) fprintf(siserr, " -L f\t\tset default output to f\n"); + (void) fprintf(siserr, " -R f\t\tset default required time to f\n"); + (void) fprintf(siserr, " -S f\t\tSet the wire load slope to f\n"); + (void) fprintf(siserr, " -W f\t\tSet the next wire load to f\n"); + (void) fprintf(siserr, "specify at most one of a,r,l,i,d\n"); + (void) fprintf(siserr, "i1...in a vector of primary inputs\n"); + (void) fprintf(siserr, "o1...on a vector of primary outputs\n"); + (void) fprintf(siserr, "NOTE: a negative value means that the parameter is unspecified\n"); + return 1; +} + + +init_delay() +{ + com_add_command("print_delay", com_print_delay, /* changes-network */ 0); + com_add_command("set_delay", com_set_delay, /* changes-network */ 0); + com_add_command("constraints", com_print_delay_constraints, + /* changes-network */ 0); + + node_register_daemon(DAEMON_ALLOC, delay_alloc); + node_register_daemon(DAEMON_FREE, delay_free); + node_register_daemon(DAEMON_DUP, delay_dup); + node_register_daemon(DAEMON_INVALID, delay_invalid); + +} + + +end_delay() +{ +} diff --git a/sis/delay/delay.c b/sis/delay/delay.c new file mode 100644 index 0000000..9cafda0 --- /dev/null +++ b/sis/delay/delay.c @@ -0,0 +1,2142 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/delay/delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +/* + * The purpose of this package is the computation of node and network delays + * in SIS. Delays are returned as delay_time_t structures, which contain two + * doubles, rise and fall. + * + * This package is designed to manipulate the basic timing package. In + * particular, routines are provided to compute the delay of a node for both + * rising and falling times, to reset the delay model to a specialized + * function, if desired, or to provide parameters to the default delay model. + */ +#include "sis.h" +#include "tdc_int.h" +#include "delay_int.h" +#include + +static jmp_buf delay_botch; + +static void set_arrival_time(); +static void set_required_time(); +static void set_fanout_load(); +static void compute_mapped_params(); +static void delay_error(); +static void allocate_pin_params(); +static delay_time_t compute_delay(); +static network_t *map_node_to_network(); +static void delay_force_pininfo(); +static void modelcpy(); +#if !defined(lint) && !defined(SABER) +static void print_pin_delays(); +#endif +static delay_pin_t *io_delay(); +static delay_time_t pi_arrival_time(); +static delay_time_t po_required_time(); + +/* + * These static vars are here just to provide the constants. No network + * information is stored into them. + */ +static delay_pin_t unit_delay_model = { + /* block */ {1.0, 1.0}, + /* drive */ {0.0, 0.0}, + /* phase */ PHASE_NONINVERTING, + /* load */ 1.0, + /* maxload */ INFINITY +}; + +static delay_pin_t unit_delay_model_with_fanout = { + /* block */ {1.0, 1.0}, + /* drive */ {0.2, 0.2}, + /* phase */ PHASE_NONINVERTING, + /* load */ 1.0, + /* maxload */ INFINITY +}; + +static delay_pin_t unspecified_pipo_delay_model = { + /* block */ {DELAY_VALUE_NOT_GIVEN, DELAY_VALUE_NOT_GIVEN}, + /* drive */ {DELAY_VALUE_NOT_GIVEN, DELAY_VALUE_NOT_GIVEN}, + /* phase */ PHASE_NONINVERTING, + /* load */ DELAY_NOT_SET, + /* maxload */ DELAY_NOT_SET, + /* user_time */ {DELAY_VALUE_NOT_GIVEN, DELAY_VALUE_NOT_GIVEN} +}; + +/* + * "REASONABLE" values to assume for the parameters of a model when nothing + * is specified by the user + */ +static delay_pin_t backup_default_pipo_model = { + /* block */ {0.0, 0.0}, + /* drive */ {0.0, 0.0}, + /* phase */ PHASE_NONINVERTING, + /* load */ 0.0, + /* maxload */ INFINITY, + /* user_time */ {0.0, 0.0} +}; + +static delay_time_t time_not_given = { + DELAY_VALUE_NOT_GIVEN, DELAY_VALUE_NOT_GIVEN +}; + +static double delay_value_not_given = DELAY_VALUE_NOT_GIVEN; + +#undef DELAY_VALUE_NOT_GIVEN +#define DELAY_VALUE_NOT_GIVEN delay_value_not_given + +int +delay_trace(network, model) +network_t *network; +delay_model_t model; +{ + int i; + node_t *node; + array_t *nodevec; + double latest; + lsGen gen; + delay_node_t *delay; + + error_init(); + if (setjmp(delay_botch)) { + return 0; + } + + if (DEF_DELAY(network) == NIL(delay_network_t)) { + delay_network_alloc(network); + } + + /* compute the load on each driver */ + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + set_fanout_load(node, model); + } + + /* Compute arrival times */ + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + set_arrival_time(node, model); + } + array_free(nodevec); + + /* Find latest output */ + (void) delay_latest_output(network, &latest); + + /* compute required times */ + nodevec = network_dfs_from_input(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + set_required_time(node, latest, model); + } + array_free(nodevec); + + /* finally, compute the slacks */ + foreach_node (network, gen, node) { + delay = DELAY(node); + delay->slack.rise = delay->required.rise - delay->arrival.rise; + delay->slack.fall = delay->required.fall - delay->arrival.fall; + } + + return 1; +} + +delay_model_t +delay_get_model_from_name(name) +char *name; +{ + delay_model_t model; + + if (strcmp(name, "unit") == 0) { + model = DELAY_MODEL_UNIT; + } else if (strcmp(name, "unit-fanout") == 0) { + model = DELAY_MODEL_UNIT_FANOUT; + } else if (strcmp(name, "library") == 0) { + model = DELAY_MODEL_LIBRARY; + } else if (strcmp(name, "mapped") == 0) { + model = DELAY_MODEL_MAPPED; + } else if (strcmp(name, "tdc") == 0) { + model = DELAY_MODEL_TDC; + } else { + model = DELAY_MODEL_UNKNOWN; + } + return model; +} + + +void +delay_print_wire_loads(network, fp) +network_t *network; +FILE *fp; +{ + int i, n; + double load; + delay_wire_load_table_t wire_load_table; + + if (DEF_DELAY(network) == NIL(delay_network_t)) { + delay_network_alloc(network); + } + wire_load_table = DEF_DELAY(network)->wire_load_table; + + (void) fprintf (fp, "\t\twire_load slope= "); + if (wire_load_table.slope == DELAY_NOT_SET) + (void)fprintf(sisout,"%s\n", DELAY_NOT_SET_STRING); + else + (void)fprintf(sisout, "%5.3f\n", wire_load_table.slope); + n = wire_load_table.num_pins_set; + + if (n > 0) { + (void) fprintf(fp, "\t\tfanout(wire_load)="); + for (i = 0; i < n;) { + load = array_fetch(double, wire_load_table.pins, i); + (void) fprintf(fp, " %d(%5.3f)", ++i, load); + } + (void) fputc('\n', fp); + } +} + +static void +delay_print_blif_slif_wire_loads(network, fp, slif_flag) +network_t *network; +FILE *fp; +int slif_flag; +{ + int i; + array_t *pins; + delay_network_t *delay; + void io_fputs_break(), io_fputc_break(); +#ifdef SIS + void io_fprintf_break(); +#else + char *buffer[16]; +#endif /* SIS */ + + delay = DEF_DELAY(network); + if (delay == NIL(delay_network_t)) { + return; + } + pins = delay->wire_load_table.pins; + if (pins == NIL(array_t)) { + return; + } + io_fputs_break(fp, (slif_flag == 0) ? ".wire" : ".global_attribute wire"); + + for (i = 0; i < array_n(pins); i++) { +#ifdef SIS + io_fprintf_break(fp, " %4.2f", array_fetch(double, pins, i)); +# else + (void) sprintf(buffer, " %4.2f", array_fetch(double, pins, i)); + io_fputs_break(fp, buffer); +#endif /* SIS */ + } + io_fputc_break(fp, '\n'); +} + +void +delay_print_blif_wire_loads(network, fp) +network_t *network; +FILE *fp; +{ + delay_print_blif_slif_wire_loads(network, fp, 0); +} + +void +delay_print_slif_wire_loads(network, fp) +network_t *network; +FILE *fp; +{ + delay_print_blif_slif_wire_loads(network, fp, 1); +} + +#define ARRIVAL(time, new_time) _arrival(&(time), (new_time)) + +static void +_arrival(time, new_time) +double *time, new_time; +{ + if (new_time > *time) { + *time = new_time; + } +} + +static void +set_arrival_time(node, model) +register node_t *node; +delay_model_t model; +{ + register int i; + register node_t *fanin; + delay_pin_t *pin_delay; + delay_time_t delay, *node_arrival, fanin_arrival; + delay_node_t *node_delay; + pin_phase_t phase; + + node_delay = DELAY(node); + + if (node_type(node) == PRIMARY_INPUT) { + node_delay->arrival = pi_arrival_time(node); + + pin_delay = get_pin_delay(node, /* pin */ 0, model); + delay = compute_delay(node, pin_delay, model); + + node_delay->arrival.rise += delay.rise; + node_delay->arrival.fall += delay.fall; + return; + } + else if (node_type(node) == PRIMARY_OUTPUT) { + fanin = node_get_fanin(node, 0); + node_delay->arrival.rise = DELAY(fanin)->arrival.rise; + node_delay->arrival.fall = DELAY(fanin)->arrival.fall; + return; + } + + node_arrival = &node_delay->arrival; + node_arrival->rise = -INFINITY; + node_arrival->fall = -INFINITY; + + foreach_fanin (node, i, fanin) { + pin_delay = get_pin_delay(node, i, model); + delay = compute_delay(node, pin_delay, model); + + fanin_arrival = DELAY(fanin)->arrival; + phase = pin_delay->phase; + if (phase == PHASE_NOT_GIVEN) { + delay_error("set_arrival_time: bad pin phase\n"); + } + if (phase == PHASE_INVERTING || phase == PHASE_NEITHER) { + ARRIVAL(node_arrival->rise, fanin_arrival.fall + delay.rise); + ARRIVAL(node_arrival->fall, fanin_arrival.rise + delay.fall); + } + if (phase == PHASE_NONINVERTING || phase == PHASE_NEITHER) { + ARRIVAL(node_arrival->rise, fanin_arrival.rise + delay.rise); + ARRIVAL(node_arrival->fall, fanin_arrival.fall + delay.fall); + } + } +} + +/* Compute the arrival time for a primary input. */ + +static delay_time_t +pi_arrival_time(node) +node_t *node; +{ + delay_time_t delay; + delay_pin_t *pin_delay; + + pin_delay = DELAY(node)->pin_delay; + delay = DEF_DELAY(node_network(node))->default_arrival; + + if (pin_delay != 0 && + pin_delay->user_time.rise != DELAY_VALUE_NOT_GIVEN && + pin_delay->user_time.fall != DELAY_VALUE_NOT_GIVEN) { + return(pin_delay->user_time); + } + else if (delay.rise != DELAY_VALUE_NOT_GIVEN && + delay.fall != DELAY_VALUE_NOT_GIVEN) { + return(delay); + } + else { + delay.rise = 0; + delay.fall = 0; + return(delay); + } +} + + +#define REQUIRED(time, new_time) _required(&(time), (new_time)) + +static void +_required(time, new_time) +double *time, new_time; +{ + if (new_time < *time) { + *time = new_time; + } +} + +static void +set_required_time(node, latest, model) +node_t *node; +double latest; +delay_model_t model; +{ + int pin; + node_t *fanout; + delay_pin_t *pin_delay; + delay_time_t delay, *node_required, fanout_required; + delay_node_t *node_delay; + pin_phase_t phase; + lsGen gen; + + node_delay = DELAY(node); + if (node_type(node) == PRIMARY_OUTPUT) { + node_delay->required = po_required_time(node, latest); + return; + } + + node_required = &node_delay->required; + node_required->rise = INFINITY; + node_required->fall = INFINITY; + + foreach_fanout_pin(node, gen, fanout, pin) { + fanout_required = DELAY(fanout)->required; + if (node_type(fanout) == PRIMARY_OUTPUT) { + REQUIRED(node_required->rise, fanout_required.rise); + REQUIRED(node_required->fall, fanout_required.fall); + continue; + } + + pin_delay = get_pin_delay(fanout, pin, model); + delay = compute_delay(fanout, pin_delay, model); + phase = pin_delay->phase; + if (phase == PHASE_NOT_GIVEN) { + delay_error("set_required_time: bad pin phase\n"); + } + if (phase == PHASE_INVERTING || phase == PHASE_NEITHER) { + REQUIRED(node_required->rise, fanout_required.fall - delay.fall); + REQUIRED(node_required->fall, fanout_required.rise - delay.rise); + } + if (phase == PHASE_NONINVERTING || phase == PHASE_NEITHER) { + REQUIRED(node_required->rise, fanout_required.rise - delay.rise); + REQUIRED(node_required->fall, fanout_required.fall - delay.fall); + } + } +} + +/* + * After a delay trace, returns the required time at the "fanin_index" of + * node. Can be different from the required time of the "fanin_index" fanin + */ +int +delay_wire_required_time(node, fanin_index, model, req) +node_t *node; +int fanin_index; +delay_model_t model; +delay_time_t *req; +{ + delay_pin_t *pin_delay; + delay_time_t delay, ip_req; + pin_phase_t phase; + + if (node->type != PRIMARY_INPUT && + (fanin_index < 0 || fanin_index >= node_num_fanin(node)) ){ + return 0; + + } + if (node->type == PRIMARY_OUTPUT){ + *req = delay_required_time(node); + return 1; + } + + pin_delay = get_pin_delay(node, fanin_index, model); + delay = compute_delay(node, pin_delay, model); + if (node->type == PRIMARY_INPUT){ + phase = PHASE_NONINVERTING; + } else { + phase = pin_delay->phase; + if (phase == PHASE_NOT_GIVEN) { + return 0; + } + } + + *req = delay_required_time(node); + ip_req.rise = INFINITY; + ip_req.fall = INFINITY; + + if (phase == PHASE_INVERTING || phase == PHASE_NEITHER) { + REQUIRED(ip_req.rise, req->fall - delay.fall); + REQUIRED(ip_req.fall, req->rise - delay.rise); + } + if (phase == PHASE_NONINVERTING || phase == PHASE_NEITHER) { + REQUIRED(ip_req.rise, req->rise - delay.rise); + REQUIRED(ip_req.fall, req->fall - delay.fall); + } + + *req = ip_req; + + return 1; +} +/* + * After a delay trace, returns the slack time at the "fanin_index" of + * node. Can be different from the slack time of the "fanin_index" fanin + */ +int +delay_wire_slack_time(node, fanin_index, model, slack) +node_t *node; +int fanin_index; +delay_model_t model; +delay_time_t *slack; +{ + delay_time_t req, arr; + + if (node->type == PRIMARY_INPUT) { + arr = delay_arrival_time(node); + } else { + arr = delay_arrival_time(node_get_fanin(node, fanin_index)); + } + if (delay_wire_required_time(node, fanin_index, model, &req)){ + slack->rise = req.rise - arr.rise; + slack->fall = req.fall - arr.fall; + return 1; + } else { + return 0; + } +} + +/* Compute the required time at a primary output */ + +static delay_time_t +po_required_time(node, latest) +node_t *node; +double latest; +{ + delay_time_t delay; + delay_pin_t *pin_delay; + + pin_delay = DELAY(node)->pin_delay; + delay = DEF_DELAY(node_network(node))->default_required; + + if (pin_delay != NIL(delay_pin_t) && + pin_delay->user_time.rise != DELAY_VALUE_NOT_GIVEN && + pin_delay->user_time.fall != DELAY_VALUE_NOT_GIVEN) { + return(pin_delay->user_time); + } + else if (delay.rise != DELAY_VALUE_NOT_GIVEN && + delay.fall != DELAY_VALUE_NOT_GIVEN) { + return(delay); + } + else { + delay.rise = latest; + delay.fall = latest; + return(delay); + } +} + + + +void +delay_compute_atime(node, model, load) +node_t *node; +delay_model_t model; +double load; +{ + DELAY(node)->load = load; + DELAY(node)->pin_params_valid = DELAY_MODEL_UNKNOWN; + set_arrival_time(node, model); +} + +static void +set_fanout_load(node, model) +node_t *node; +delay_model_t model; +{ + int pin; + lsGen gen; + double load; + node_t *fanout; + delay_pin_t *pin_delay; + + /* Sum the output capacitance (load of each pin we fanout to) */ + + DELAY(node)->load = + compute_wire_load(node_network(node), node_num_fanout(node)); + if (model != DELAY_MODEL_TDC){ + foreach_fanout_pin (node, gen, fanout, pin) { + if (fanout->type == PRIMARY_OUTPUT){ + load = delay_get_default_parameter(node_network(fanout), + DELAY_DEFAULT_OUTPUT_LOAD); + if (load == DELAY_NOT_SET) load = 0.0; + (void)delay_get_po_load(fanout, &load); + DELAY(node)->load += load; + } else { + pin_delay = get_pin_delay(fanout, pin, model); + DELAY(node)->load += pin_delay->load; + } + } + } else { + /* + * For the TDC model we have no need to compute the fanout load + */ + DELAY(node)->load = 0.0; + } +} + +/* + * Non-invasive version of the set_fanout_load() command. It will return + * the load at the fanouts without storing them with the node + */ +double +delay_compute_fo_load(node, model) +node_t *node; +delay_model_t model; +{ + int pin; + lsGen gen; + double op_load, load; + node_t *fanout; + delay_pin_t *pin_delay; + + /* Sum the output capacitance (load of each pin we fanout to) */ + + op_load = compute_wire_load(node_network(node), node_num_fanout(node)); + foreach_fanout_pin (node, gen, fanout, pin) { + if (fanout->type == PRIMARY_OUTPUT){ + load = delay_get_default_parameter(node_network(fanout), DELAY_DEFAULT_OUTPUT_LOAD); + if (load == DELAY_NOT_SET) load = 0.0; + (void)delay_get_po_load(fanout, &load); + op_load += load; + } else { + pin_delay = get_pin_delay(fanout, pin, model); + op_load += pin_delay->load; + } + } + return op_load; +} + +/* + * The following strategy is used to get the wire load: + * If the array has a value for that fanout, use it + * else compute it by a linear model depending on slope + * else if slope not spec, extrapolate from values given. + */ +double +compute_wire_load(network, pins) +network_t *network; +int pins; +{ + int n; + double val; + delay_network_t *delay; + delay_wire_load_table_t wire_load_table; + + if (pins == 0 || network == NIL(network_t)) { + return 0.0; + } + if (pins < 0) { + delay_error("compute_wire_load: node with non-positive fanout"); + } + + delay = DEF_DELAY(network); + if (delay == NIL(delay_network_t)) { + delay_network_alloc(network); + delay = DEF_DELAY(network); + } + wire_load_table = delay->wire_load_table; + n = wire_load_table.num_pins_set; + if (pins > n) { + if (wire_load_table.slope > 0.0) { + return(wire_load_table.slope * pins); + } + else { + if (n == 0) { + return(0.0); + } + val = array_fetch(double, wire_load_table.pins, n - 1); + if (n == 1) { + return(val); + } + else { + return(val * (1 + (pins - n)) - (pins - n) + * array_fetch(double, wire_load_table.pins, n - 2)); + } + } + } + else { + return(array_fetch(double, wire_load_table.pins, pins - 1)); + } +} + + +/* + * Get the pin delay parameters for a node. This is highly model-dependent + * code. This returns a delay_pin_t *, and should contain all the necessary + * information to for compute_delay to compute the delay through this pin. + * Further, the code in this routine for each model MUST fill in the capacitive + * load slot (a double) and the phase slot (of type pin_phase_t) in the + * returned delay_pin_t. These slots are read by model-independent code. + */ +delay_pin_t * +get_pin_delay(node, pin, model) +node_t *node; +int pin; +delay_model_t model; +{ + char errmsg[1024]; + delay_pin_t *delay; + input_phase_t phase; + /* Need structure to modify the models based on the phase of the gate */ + static delay_pin_t internal_delay_model; + + if (node_type(node) == PRIMARY_INPUT) { + return(io_delay(node, model)); + } + if (node_type(node) == PRIMARY_OUTPUT) { + return(io_delay(node, model)); + } + + switch(model) { + case DELAY_MODEL_UNIT: + internal_delay_model.block = unit_delay_model.block; + internal_delay_model.drive = unit_delay_model.drive; + internal_delay_model.load = unit_delay_model.load; + internal_delay_model.max_load = unit_delay_model.max_load; + /* Set the PHASE based on the function at the node */ + phase = node_input_phase(node, node_get_fanin(node, pin)); + if (phase == POS_UNATE){ + internal_delay_model.phase = PHASE_NONINVERTING; + } else if (phase == NEG_UNATE){ + internal_delay_model.phase = PHASE_INVERTING; + } else { + internal_delay_model.phase = PHASE_NEITHER; + } + delay = &internal_delay_model; + break; + + case DELAY_MODEL_UNIT_FANOUT: + internal_delay_model.block = unit_delay_model_with_fanout.block; + internal_delay_model.drive = unit_delay_model_with_fanout.drive; + internal_delay_model.load = unit_delay_model_with_fanout.load; + internal_delay_model.max_load = unit_delay_model_with_fanout.max_load; + /* Set the PHASE based on the function at the node */ + phase = node_input_phase(node, node_get_fanin(node, pin)); + if (phase == POS_UNATE){ + internal_delay_model.phase = PHASE_NONINVERTING; + } else if (phase == NEG_UNATE){ + internal_delay_model.phase = PHASE_INVERTING; + } else { + internal_delay_model.phase = PHASE_NEITHER; + } + delay = &internal_delay_model; + break; + + case DELAY_MODEL_LIBRARY: + delay = (delay_pin_t *) lib_get_pin_delay(node, pin); + if (delay == NIL(delay_pin_t)) { + (void) sprintf(errmsg, + "cannot use library model: node '%s' not mapped\n", + node_name(node)); + delay_error(errmsg); + /* NOTREACHED */ + } + break; + + case DELAY_MODEL_MAPPED: + delay = (delay_pin_t *) lib_get_pin_delay(node, pin); + if (delay == NIL(delay_pin_t)) { + /* + * Node is not mapped. First check to see if delays have been + * computed. If not, compute them. Also checks to see if we can + * use existing array. + */ + if (DELAY(node)->pin_params_valid == DELAY_MODEL_UNKNOWN) { + +#ifdef DEBUG + printf("Computing mapped parameters for node %s\n",node_name(node)); +#endif + allocate_pin_params(node); + compute_mapped_params(node, 0.0); + DELAY(node)->pin_params_valid = DELAY_MODEL_MAPPED; + } + delay = DELAY(node)->pin_params[pin]; + } + break; + case DELAY_MODEL_TDC: + if (DELAY(node)->pin_params_valid != DELAY_MODEL_TDC) { +#ifdef DEBUG + printf("Computing tdc parameters for node %s\n",node_name(node)); +#endif + allocate_pin_params(node); + /* Use complex tdc model with fanout */ + compute_tdc_params(node, 2); + DELAY(node)->pin_params_valid = DELAY_MODEL_TDC; + } + delay = DELAY(node)->pin_params[pin]; + break; + default: + delay_error("get_pin_delay: bad model type"); + /* NOTREACHED */ + } + return(delay); +} + +/* + * Compute the delays on the io pins of the network. Model-dependent + */ +static delay_pin_t * +io_delay(node, model) +node_t *node; +delay_model_t model; +{ + double val; + delay_time_t drive; + static delay_pin_t pipo_delay_model; /* structure to pass data */ + + switch(model) { + case DELAY_MODEL_UNIT: + return(&unit_delay_model); + case DELAY_MODEL_UNIT_FANOUT: + pipo_delay_model.block = unit_delay_model_with_fanout.block; + pipo_delay_model.drive = unit_delay_model_with_fanout.drive; + pipo_delay_model.phase = unit_delay_model_with_fanout.phase; + pipo_delay_model.load = unit_delay_model_with_fanout.load; + pipo_delay_model.max_load = unit_delay_model_with_fanout.max_load; + if (delay_get_pi_drive(node, &drive)) { + pipo_delay_model.drive = drive; + } else { + val = delay_get_default_parameter(node_network(node), + DELAY_DEFAULT_DRIVE_RISE); + if (val != DELAY_NOT_SET) pipo_delay_model.drive.rise = val; + val = delay_get_default_parameter(node_network(node), + DELAY_DEFAULT_DRIVE_FALL); + if (val != DELAY_NOT_SET) pipo_delay_model.drive.fall = val; + } + return(&pipo_delay_model); + case DELAY_MODEL_LIBRARY: + case DELAY_MODEL_MAPPED: + case DELAY_MODEL_TDC: + if (DELAY(node)->pin_delay != NIL(delay_pin_t)) { + pipo_delay_model = *(DELAY(node)->pin_delay); + modelcpy(&pipo_delay_model, DELAY(node)->pin_delay, node); + } else { + modelcpy(&pipo_delay_model, &unspecified_pipo_delay_model, node); + } + return(&pipo_delay_model); + default: + fail("io_delay: bad model"); + /*NOTREACHED*/ + } +} + +/* + * Fill in slots with default values where the DELAY_VALUE is NOT_GIVEN. + * Since the defaults are settable, they too may be NOT_GIVEN, so we need a + * backup. + */ +static void +modelcpy(newpin, pin, node) +delay_pin_t *newpin, *pin; +node_t *node; +{ + delay_network_t *net_delay; + delay_pin_t default_pipo_model; + double value; + pin_phase_t phase; + + if ((net_delay = DEF_DELAY(node_network(node))) != NIL(delay_network_t)){ + default_pipo_model = net_delay->pipo_model; + } else { + default_pipo_model = unspecified_pipo_delay_model; + } + + if (pin->block.rise == DELAY_VALUE_NOT_GIVEN) { + value = default_pipo_model.block.rise; + newpin->block.rise = (value == DELAY_VALUE_NOT_GIVEN) ? + backup_default_pipo_model.block.rise : + value; + } + if (pin->block.fall == DELAY_VALUE_NOT_GIVEN) { + value = default_pipo_model.block.fall; + newpin->block.fall = (value == DELAY_VALUE_NOT_GIVEN) ? + backup_default_pipo_model.block.fall : + value; + } + if (pin->drive.rise == DELAY_VALUE_NOT_GIVEN) { + value = default_pipo_model.drive.rise; + newpin->drive.rise = (value == DELAY_VALUE_NOT_GIVEN) ? + backup_default_pipo_model.drive.rise : + value; + } + if (pin->drive.fall == DELAY_VALUE_NOT_GIVEN) { + value = default_pipo_model.drive.fall; + newpin->drive.fall = (value == DELAY_VALUE_NOT_GIVEN) ? + backup_default_pipo_model.drive.fall : + value; + } + if (pin->load == DELAY_VALUE_NOT_GIVEN) { + value = default_pipo_model.load; + newpin->load = (value == DELAY_VALUE_NOT_GIVEN) ? + backup_default_pipo_model.load : + value; + } + if (pin->max_load == DELAY_VALUE_NOT_GIVEN) { + value = default_pipo_model.max_load; + newpin->max_load = (value == DELAY_VALUE_NOT_GIVEN) ? + backup_default_pipo_model.max_load : + value; + } + if (pin->phase == PHASE_NOT_GIVEN) { + phase = default_pipo_model.phase; + newpin->phase = (phase == PHASE_NOT_GIVEN) ? + backup_default_pipo_model.phase : + phase; + } +} + +/* + * Allocate storage for new pin params, attempting to reuse storage where + * possible. The number of fanins is the number of delays we need, number of + * allocated parameters is the number we have. If we have allocated none, + * then just do a standard storage allocation. If we have too few, copy the + * storage we do have and allocate the rest. If we have too many, copy what + * we need and free the rest. If we have just the right number (I suspect, + * the usual case), then do nothing. + */ +static void +allocate_pin_params(node) +node_t *node; +{ + int nparams, n_old_params, i; + delay_pin_t **old_pins, **new_pins; + delay_node_t *delay; + + nparams = node_num_fanin(node); + delay = DELAY(node); + n_old_params = delay->num_pin_params; + + if (delay->pin_params == NIL(delay_pin_t *)) { + delay->num_pin_params = nparams; + new_pins = ALLOC(delay_pin_t *, nparams); + for (i = 0; i < nparams; i++) { + new_pins[i] = ALLOC(delay_pin_t, 1); + } + delay->pin_params = new_pins; + } + else if (nparams != n_old_params) { + old_pins = delay->pin_params; + new_pins = ALLOC(delay_pin_t *, nparams); + + if (n_old_params < nparams) { + for (i = 0; i < n_old_params; i++) { + new_pins[i] = old_pins[i]; + } + for (i = n_old_params; i < nparams; i++) { + new_pins[i] = ALLOC(delay_pin_t, 1); + } + } + else { + for (i = 0; i < nparams; i++) { + new_pins[i] = old_pins[i]; + } + for (i = nparams; i < n_old_params; ++i) { + FREE(old_pins[i]); + } + } + FREE(old_pins); + delay->pin_params = new_pins; + /* BUG FIX: by KJ --- Set the field for the no. of parameters */ + delay->num_pin_params = nparams; + } +} + +/* + * Compute the block, drive and load parameters for node by mapping it naively + * into a network and then doing a delay trace to derive the parameters. This + * is a very inefficient approach, but it is simple and easy to understand. + * Must be recoded if it turns out to be very inefficient. + */ +static void +compute_mapped_params(node, mode) +node_t *node; +double mode; +{ + network_t *network; + int i, found = 0; + delay_pin_t *pin, *pin1; + lsGen gen, gen1; + node_t *this_node, *out_node, *fanin, *p, *q, *r; + char *name; + delay_time_t *user_time; + + network = map_node_to_network(node, mode); + if (network == NIL(network_t)) { + delay_error(NIL(char)); + } + + /* + * Strategy here is to assume that all the delay at reaching the output is + * due to the ith input pin. Hence, we begin by setting the arrival times + * of all inputs to -INFINITY and the output loads driven to be 0. This + * means (again, for linear models) that the delay across the node is + * ENTIRELY due to the set delay for the ith pin. + */ + + foreach_primary_output (network, gen, out_node) { /* only one */ + DELAY(out_node)->load = 0; + } + + foreach_primary_input (network, gen, this_node) { + delay_force_pininfo(this_node); + user_time = &DELAY(this_node)->pin_delay->user_time; + user_time->rise = -INFINITY; + user_time->fall = -INFINITY; + } + + foreach_primary_input (network, gen, this_node) { + name = node_name(this_node); + found = 0; + + /* + * Find the pin which corresponds to input this_node of the mapped + * network + */ + foreach_fanin (node, i, fanin) { + if(strcmp(name, node_long_name(fanin)) == 0) { + found = 1; + break; + } + } + + if (found == 0) { + delay_error("Severe internal error in mapped delay model"); + } + + pin = DELAY(node)->pin_params[i]; + /* + * Compute the phase. computes node = pf + qf' + r (f == fanin). + * Node is inverting iff q != 0; both if p != 0, q != 0; noninverting + * otherwise. + */ + node_algebraic_cofactor(node, fanin, &p, &q, &r); + + if (node_function(q) == NODE_0) { + pin->phase = PHASE_NONINVERTING; + } + else if (node_function(p) == NODE_0) { + pin->phase = PHASE_INVERTING; + } + else { + pin->phase = PHASE_NEITHER; + } + + node_free(p); + node_free(q); + node_free(r); + + user_time = &DELAY(this_node)->pin_delay->user_time; + user_time->rise = 0; + user_time->fall = 0; + + /* + * Compute block parameter. This is the delay result when the network + * output is driving a load of 0. The drive parameter, similarly, is + * equal to the drive parameter of the node driving the output. + */ + (void) delay_trace(network, DELAY_MODEL_LIBRARY); + + foreach_primary_output (network, gen1, out_node) { + /* should only be one */ + + pin->block = delay_arrival_time(out_node); + /* + * It turns out that the drive parameter for each pin of node is + * equal to the drive parameter of the (single) fanin of the + * output node of the mapped network. Get this fanin. We do it + * through a foreach loop because that's the easiest way to do it, + * but we ought to go through this loop only once. Ditto for the + * outer loop + */ + pin1 = get_pin_delay(out_node, 0, DELAY_MODEL_LIBRARY); + pin -> drive = pin1 -> drive; + } + + /* Compute the load. This is a little tricky, so watch the comment */ + + pin->load = DELAY(this_node)->load; + + /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Naive and WRONG. The load on this_node (a PI) is merely the + load on the buffer it drives. What we want is the load driven by + that buffer. The following code gets it: */ + + + /* + foreach_fanout_pin(this_node, gen1, p, i) { + pin -> load = DELAY(p) -> load; + } + */ + + + +#ifdef DEBUG + printf("Pin parameters for node %s, pin %s\n", node_name(node), + node_name(fanin)); + printf("pin %d br %f bf %f dr %f df %f phase %s load %f alt_load %f\n", + i, pin -> block.rise, pin -> block.fall, + pin -> drive.rise, pin -> drive.fall, + (pin -> phase == PHASE_INVERTING?"neg": + (pin -> phase == PHASE_NONINVERTING?"pos":"both")), + pin -> load, DELAY(this_node) -> load); +#endif + + + /* reset this node's user time given to be -INFINITY for next + iteration */ + + user_time->rise = -INFINITY; + user_time->fall = -INFINITY; + } + network_free(network); +} + +/* + * Essentially similar to compute mapped params -- but also returns the + * mapped network. Put on request of the speedup package where a node may + * be replaced by its decomposition + */ +network_t * +delay_generate_decomposition(node, mode) +node_t *node; +double mode; +{ + network_t *network; + int i, found = 0; + delay_pin_t *pin, *pin1; + lsGen gen, gen1; + node_t *this_node, *out_node, *fanin, *p, *q, *r; + char *name; + delay_time_t *user_time; + + /* Just in case one did not allocate the storage for the mapped model */ + allocate_pin_params(node); + if ((network = map_node_to_network(node, mode)) == NIL(network_t)) + delay_error(NIL(char)); + + /* + * Strategy here is to assume that all the delay at reaching the output is + * due to the ith input pin. Hence, we begin by setting the arrival times + * of all inputs to -INFINITY and the output loads driven to be 0. This + * means (again, for linear models) that the delay across the node is + * ENTIRELY due to the set delay for the ith pin. + */ + + foreach_primary_output(network, gen, out_node) { /* only one */ + DELAY(out_node)->load = 0; + } + + foreach_primary_input(network, gen, this_node) { + delay_force_pininfo(this_node); + /* + delay_set_parameter(this_node, DELAY_ARRIVAL_RISE, -INFINITY); + delay_set_parameter(this_node, DELAY_ARRIVAL_FALL, -INFINITY); + */ + user_time = &DELAY(this_node)->pin_delay->user_time; + user_time->rise = -INFINITY; + user_time->fall = -INFINITY; + } + + foreach_primary_input(network, gen, this_node){ + name = node_name(this_node); + found = 0; + + /* + * Find the pin which corresponds to input this_node of the mapped + * network + */ + foreach_fanin(node, i, fanin) { + if (strcmp(name, node_name(fanin)) == 0) { + found = 1; + break; + } + } + if (found == 0) { + delay_error("Severe internal error in mapped delay model"); + } + + pin = DELAY(node)->pin_params[i]; + + /* + * Compute the phase. Computes node = pf + qf' + r (f == fanin). + * Node is inverting iff q != 0; both if p != 0, q != 0; noninverting + * otherwise + */ + node_algebraic_cofactor(node, fanin, &p, &q, &r); + + if (node_function(q) == NODE_0) { + pin->phase = PHASE_NONINVERTING; + } + else if (node_function(p) == NODE_0) { + pin->phase = PHASE_INVERTING; + } + else { + pin->phase = PHASE_NEITHER; + } + + node_free(p); + node_free(q); + node_free(r); + + user_time = &DELAY(this_node)->pin_delay->user_time; + user_time->rise = 0; + user_time->fall = 0; + + /* + * Compute block parameter. This is the delay result when the network + * output is driving a load of 0. The drive parameter, similarly, is + * equal to the drive parameter of the node driving the output. + */ + (void) delay_trace(network, DELAY_MODEL_LIBRARY); + + foreach_primary_output(network, gen1, out_node) { /* only one */ + pin->block = delay_arrival_time(out_node); + /* + * It turns out that the drive parameter for each pin of node is + * equal to the drive parameter of the (single) fanin of the + * output node of the mapped network. Get this fanin. We do it + * through a foreach loop because that's the easiest way to do it, + * but we ought to go through this loop only once. Ditto for the + * outer loop + */ + pin1 = get_pin_delay(out_node, 0, DELAY_MODEL_LIBRARY); + pin->drive = pin1->drive; + + } + + /* Compute the load. This is a little tricky, so watch the comment */ + + pin -> load = DELAY(this_node) -> load; + + /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Naive and WRONG. The load on this_node (a PI) is merely the + load on the buffer it drives. What we want is the load driven by + that buffer. The following code gets it: */ + + + /* + foreach_fanout_pin(this_node, gen1, p, i) { + pin -> load = DELAY(p) -> load; + } + */ + + +#ifdef DEBUG + printf("Pin parameters for node %s, pin %s\n", node_name(node), + node_name(fanin)); + printf("pin %d br %f bf %f dr %f df %f phase %s load %f alt_load %f\n", + i, pin -> block.rise, pin -> block.fall, + pin -> drive.rise, pin -> drive.fall, + (pin -> phase == PHASE_INVERTING?"neg": + (pin -> phase == PHASE_NONINVERTING?"pos":"both")), + pin -> load, DELAY(this_node) -> load); +#endif + + + /* reset this node's user time given to be -INFINITY for next + iteration */ + + user_time = &DELAY(this_node)->pin_delay->user_time; + user_time->rise = -INFINITY; + user_time->fall = -INFINITY; + } + return(network); +} + +/* Model dependent code */ +static delay_time_t +compute_delay(node, pin_delay, model) +node_t *node; +delay_pin_t *pin_delay; +delay_model_t model; +{ + delay_time_t delay; + + switch(model) { + case DELAY_MODEL_UNIT: + case DELAY_MODEL_UNIT_FANOUT: + case DELAY_MODEL_LIBRARY: + case DELAY_MODEL_MAPPED: + case DELAY_MODEL_TDC: + delay.rise = pin_delay->drive.rise * DELAY(node)->load; + delay.fall = pin_delay->drive.fall * DELAY(node)->load; + if (node_type(node) != PRIMARY_INPUT) { + delay.rise += pin_delay->block.rise; + delay.fall += pin_delay->block.fall; + } + break; + default: + delay_error("compute_delay: bad model type"); + /* NOTREACHED */ + } + return delay; +} + +static void +delay_error(s) +char *s; +{ + if (s != NIL(char)) { + error_append(s); + } + longjmp(delay_botch, 1); +} + +delay_time_t +delay_node_pin(node, pin_num, model) +node_t *node; +int pin_num; +delay_model_t model; +{ + delay_pin_t *pin_delay; + delay_time_t delay; + + delay.rise = delay.fall = 0.0; + + if (node_type(node) == PRIMARY_OUTPUT) { + return(delay); + } + set_fanout_load(node, model); + + pin_delay = get_pin_delay(node, pin_num, model); + return(compute_delay(node, pin_delay, model)); +} + +delay_time_t +delay_fanout_contribution(node, pin_num, fanout, model) +node_t *node, *fanout; +int pin_num; +delay_model_t model; +{ + delay_pin_t *pin_delay; + delay_time_t delay, delay1, *delay_ptr; + double load; + int i, num; + + delay.rise = delay.fall = 0.0; + i = node_get_fanin_index(fanout, node); + delay_ptr = &delay; + + if (i == -1) { + return(delay); + } + + /* + set_fanout_load(node, model); + */ + + num = node_num_fanout(node); + load = (DELAY(node)->load - get_pin_delay(fanout, i, model)->load) + + (compute_wire_load(node_network(node), num) - compute_wire_load(node_network(node), num - 1)); + + pin_delay = get_pin_delay(node, pin_num, model); + delay1 = compute_delay(node, pin_delay, model); + delay = delay_map_simulate(1, &delay_ptr, (char **) &pin_delay, load); + delay1.rise -= delay.rise; + delay1.fall -= delay.fall; + return(delay1); +} + +#define DELAY_NODE_CHECK(network, node, fname) \ + network = network_of_node(node);\ + if(!network_has_been_traced(network)) {\ + fail("fname called before trace done\n");\ + } else if (network_has_been_modified(network)) {\ + (void)fprintf(siserr,\ + "Warning: network modified between delay_trace and fname\n");\ + } + + +delay_time_t +delay_arrival_time(node) +node_t *node; +{ + /* Goes in when I get the name of the fns from RR + + network_t *network; + + DELAY_NODE_CHECK(network, node, delay_arrival_time); + */ + return(DELAY(node)->arrival); +} + + +delay_time_t +delay_required_time(node) +node_t *node; +{ + /* Goes in when I get the name of the fns from RR + + network_t *network; + + DELAY_NODE_CHECK(network, node, delay_required_time); + */ + return(DELAY(node)->required); +} + + +delay_time_t +delay_slack_time(node) +node_t *node; +{ + /* Goes in when I get the name of the fns from RR + + network_t *network; + + DELAY_NODE_CHECK(network, node, delay_slack_time); + */ + return(DELAY(node)->slack); +} + +double +delay_load(node) +node_t *node; +{ + /* Goes in when I get the name of the fns from RR + + network_t *network; + + DELAY_NODE_CHECK(network, node, delay_load); + */ + + return(DELAY(node)->load); +} + +node_t * +delay_latest_output(network, latest_p) +network_t *network; +double *latest_p; +{ + node_t *po, *last_output; + lsGen gen; + double latest; + delay_time_t arrival; + + /* Goes in when I get the name of the fns from RR + DELAY_NODE_CHECK(network, node, delay_latest_output); + */ + + /* Find latest output */ + latest = - INFINITY; + last_output = 0; + + foreach_primary_output (network, gen, po) { + arrival = DELAY(po)->arrival; + if (arrival.rise > latest) { + latest = arrival.rise; + last_output = po; + } + if (arrival.fall > latest) { + latest = arrival.fall; + last_output = po; + } + } + + *latest_p = latest; + return(last_output); +} + + +static void +delay_force_pininfo(node) +node_t *node; +{ + delay_pin_t *pin_delay; + + assert(node != NIL(node_t)); + if (DELAY(node) == NIL(delay_node_t)) { + delay_alloc(node); + } + if (DELAY(node)->pin_delay == NIL(delay_pin_t)) { + DELAY(node)->pin_delay = pin_delay = ALLOC(delay_pin_t, 1); + pin_delay->block = time_not_given; + pin_delay->drive = time_not_given; + /* BUG FIX: by KJ --- Earlier the phase was not initialized */ + pin_delay->phase = PHASE_NOT_GIVEN; + pin_delay->load = DELAY_VALUE_NOT_GIVEN; + pin_delay->max_load = DELAY_VALUE_NOT_GIVEN; + pin_delay->user_time = time_not_given; + } +} + +void +delay_set_default_parameter(network, param, value) +network_t *network; +delay_param_t param; +double value; +{ + delay_network_t *delay; + delay_wire_load_table_t *wire_load_table; + + delay = DEF_DELAY(network); + if (delay == NIL(delay_network_t)) { + delay_network_alloc(network); + delay = DEF_DELAY(network); + } + + wire_load_table = &delay->wire_load_table; + switch(param) { + case DELAY_ADD_WIRE_LOAD: + if (value < 0) { + if (wire_load_table->pins != NIL(array_t)) { + array_free(wire_load_table->pins); + } + wire_load_table->pins = NIL(array_t); + wire_load_table->num_pins_set = 0; + } + else { + if (wire_load_table->pins == NIL(array_t)) { + wire_load_table->pins = array_alloc(double, 10); + } + array_insert_last(double, wire_load_table->pins, value); + wire_load_table->num_pins_set++; + } + return; + case DELAY_WIRE_LOAD_SLOPE: + wire_load_table->slope = value; + return; + case DELAY_DEFAULT_DRIVE_RISE: + delay->pipo_model.drive.rise = value; + return; + case DELAY_DEFAULT_DRIVE_FALL: + delay->pipo_model.drive.fall = value; + return; + + case DELAY_DEFAULT_OUTPUT_LOAD: + delay->pipo_model.load = value; + return; + case DELAY_DEFAULT_MAX_INPUT_LOAD: + delay->pipo_model.max_load = value; + return; + + case DELAY_DEFAULT_ARRIVAL_RISE: + delay->default_arrival.rise = value; + return; + case DELAY_DEFAULT_ARRIVAL_FALL: + delay->default_arrival.fall = value; + return; + + case DELAY_DEFAULT_REQUIRED_RISE: + delay->default_required.rise = value; + return; + case DELAY_DEFAULT_REQUIRED_FALL: + delay->default_required.fall = value; + return; + + default: + fail("bad param in delay_set_default_parameter"); + } +} + +void +delay_set_parameter(node, param, value) +node_t *node; +delay_param_t param; +double value; +{ + delay_pin_t *pin_delay; + + delay_force_pininfo(node); + pin_delay = DELAY(node)->pin_delay; + + switch(param) { + case DELAY_BLOCK_RISE: + pin_delay->block.rise = value; + break; + case DELAY_BLOCK_FALL: + pin_delay->block.fall = value; + break; + case DELAY_DRIVE_RISE: + pin_delay->drive.rise = value; + break; + case DELAY_DRIVE_FALL: + pin_delay->drive.fall = value; + break; + case DELAY_OUTPUT_LOAD: + case DELAY_INPUT_LOAD: + pin_delay->load = value; + break; + case DELAY_MAX_INPUT_LOAD: + pin_delay->max_load = value; + break; + case DELAY_PHASE: + if (value == DELAY_PHASE_INVERTING) { + pin_delay->phase = PHASE_INVERTING; + } + else if (value == DELAY_PHASE_NONINVERTING) { + pin_delay->phase = PHASE_NONINVERTING; + } + else if (value == DELAY_PHASE_NEITHER) { + pin_delay->phase = PHASE_NEITHER; + } + else { + fail("bad phase in delay_set_parameter"); + } + break; + + case DELAY_ARRIVAL_RISE: + case DELAY_REQUIRED_RISE: + pin_delay->user_time.rise = value; + break; + + case DELAY_ARRIVAL_FALL: + case DELAY_REQUIRED_FALL: + pin_delay->user_time.fall = value; + break; + + default: + fail("bad enum value in delay_set_parameter"); + /* NOTREACHED */ + } +} + +double +delay_get_default_parameter(network, param) +network_t *network; +delay_param_t param; +{ + delay_network_t *delay; + + delay = DEF_DELAY(network); + if (delay == NIL(delay_network_t)) { + delay_network_alloc(network); + delay = DEF_DELAY(network); + } + switch(param) { + case DELAY_DEFAULT_ARRIVAL_RISE: + return delay->default_arrival.rise; + case DELAY_DEFAULT_ARRIVAL_FALL: + return delay->default_arrival.fall; + case DELAY_DEFAULT_REQUIRED_RISE: + return delay->default_required.rise; + case DELAY_DEFAULT_REQUIRED_FALL: + return delay->default_required.fall; + case DELAY_DEFAULT_OUTPUT_LOAD: + return delay->pipo_model.load; + case DELAY_DEFAULT_MAX_INPUT_LOAD: + return delay->pipo_model.max_load; + case DELAY_DEFAULT_DRIVE_RISE: + return delay->pipo_model.drive.rise; + case DELAY_DEFAULT_DRIVE_FALL: + return delay->pipo_model.drive.fall; + case DELAY_WIRE_LOAD_SLOPE: + return delay->wire_load_table.slope; + default: + fail("bad param in delay_get_global_parameter"); + } + /*NOTREACHED*/ +} + +double +delay_get_parameter(node, param) +node_t *node; +delay_param_t param; +{ + pin_phase_t phase; + delay_pin_t *pin_delay; + + delay_force_pininfo(node); + pin_delay = DELAY(node)->pin_delay; + + switch(param) { + case DELAY_BLOCK_RISE: + return(pin_delay->block.rise); + case DELAY_BLOCK_FALL: + return(pin_delay->block.fall); + case DELAY_DRIVE_RISE: + return(pin_delay->drive.rise); + case DELAY_DRIVE_FALL: + return(pin_delay->drive.fall); + case DELAY_OUTPUT_LOAD: + case DELAY_INPUT_LOAD: + return(pin_delay->load); + case DELAY_MAX_INPUT_LOAD: + return(pin_delay->max_load); + case DELAY_PHASE: + phase = pin_delay->phase; + if (phase == PHASE_INVERTING) { + return(DELAY_PHASE_INVERTING); + } + else if (phase == PHASE_NONINVERTING) { + return(DELAY_PHASE_NONINVERTING); + } + else if (phase == PHASE_NEITHER) { + return(DELAY_PHASE_NEITHER); + } + else { + fail("bad phase value in delay_get_parameter"); + /* NOTREACHED */ + } + + case DELAY_ARRIVAL_RISE: + case DELAY_REQUIRED_RISE: + return(pin_delay->user_time.rise); + + case DELAY_ARRIVAL_FALL: + case DELAY_REQUIRED_FALL: + return(pin_delay->user_time.fall); + + default: + fail("bad enum in delay_get_parameter"); + /* NOTREACHED */ + } +} + +void +delay_alloc(node) +node_t *node; +{ + delay_node_t *delay; + + delay = ALLOC(delay_node_t, 1); + node->DELAY_SLOT = (char *) delay; + delay->pin_delay = NIL(delay_pin_t); + delay->pin_params_valid = DELAY_MODEL_UNKNOWN; + delay->num_pin_params = 0; + delay->pin_params = NIL(delay_pin_t *); +#ifdef SIS + delay->synch_clock_name = NIL(char); +#endif /* SIS */ +} + +void +delay_free(node) +node_t *node; +{ + int i; + delay_node_t *delay; + + delay = DELAY(node); + FREE(delay->pin_delay); + if (delay->num_pin_params != 0 && delay->pin_params != NIL(delay_pin_t *)) { + for (i = 0; i < delay->num_pin_params; i++) { + /* + if (delay->pin_params[i] != &unspecified_pipo_delay_model) { + */ + FREE(delay->pin_params[i]); + /* + } + */ + } + FREE(delay->pin_params); + } +#ifdef SIS + FREE(delay->synch_clock_name); +#endif /* SIS */ + FREE(node->DELAY_SLOT); +} + +void +delay_dup(oldnode, newnode) +node_t *oldnode, *newnode; +{ + int nparms, i; + delay_node_t *old, *new; + + new = DELAY(newnode); + old = DELAY(oldnode); + *new = *old; + + if (old->pin_params_valid != DELAY_MODEL_UNKNOWN) { + nparms = new->num_pin_params; + new->pin_params = ALLOC(delay_pin_t *, nparms); + for (i = 0; i < nparms; ++i) { + new->pin_params[i] = ALLOC(delay_pin_t, 1); + *new->pin_params[i] = *old->pin_params[i]; + } + } + else { + new->pin_params = NIL(delay_pin_t *); + new->num_pin_params = 0; + } + + if (old->pin_delay != NIL(delay_pin_t)) { + new->pin_delay = ALLOC(delay_pin_t, 1); + *new->pin_delay = *old->pin_delay; + } +#ifdef SIS + if (old->synch_clock_name != NIL(char)) { + new->synch_clock_name = util_strsav(old->synch_clock_name); + } +#endif /* SIS */ +} + +/* + * Need to invalidate the mapped parameters for this node + */ +void +delay_invalid(node) +node_t *node; +{ + /* BUG FIX: by KJ -- earlier this routine did nothing */ + DELAY(node)->pin_params_valid = DELAY_MODEL_UNKNOWN; +} + + +void +delay_network_alloc(network) +network_t *network; +{ + delay_network_t *delay; + + delay = ALLOC(delay_network_t, 1); + network->DEF_DELAY_SLOT = (char *) delay; + delay->default_arrival = time_not_given; + delay->default_required = time_not_given; + + delay->wire_load_table.slope = DELAY_VALUE_NOT_GIVEN; + delay->wire_load_table.num_pins_set = 0; + delay->wire_load_table.pins = NIL(array_t); + + delay->pipo_model = unspecified_pipo_delay_model; +} + +void +delay_network_free(network) +network_t *network; +{ + array_t *pins; + + if (DEF_DELAY(network) != NIL(delay_network_t)) { + pins = DEF_DELAY(network)->wire_load_table.pins; + if (pins != NIL(array_t)) { + array_free(pins); + } + FREE(network->DEF_DELAY_SLOT); + } +} + +void +delay_network_dup(new, old) +network_t *new, *old; +{ + array_t *oldpins; + + delay_network_free(new); + if (DEF_DELAY(old) == NIL(delay_network_t)) { + new->DEF_DELAY_SLOT = NIL(char); + return; + } + new->DEF_DELAY_SLOT = (char *) ALLOC(delay_network_t, 1); + *DEF_DELAY(new) = *DEF_DELAY(old); + + oldpins = DEF_DELAY(old)->wire_load_table.pins; + DEF_DELAY(new)->wire_load_table.pins = (oldpins != NIL(array_t)) ? + array_dup(oldpins) : + NIL(array_t); +} + +/* + * Mild hack: take the pin_delay records from the primary inputs, and + * give these away to the library package; the library package will return + * these, as requested via lib_get_pin_delay(node, pin); + * + * We don't care if pin_delay == 0 for some pin; but the library package + * probably does ... + */ +char ** +delay_giveaway_pin_delay(network) +network_t *network; +{ + lsGen gen; + node_t *node; + int i; + char **delay_info; + delay_pin_t *pin_delay; + + delay_info = ALLOC(char *, network_num_pi(network)); + i = 0; + foreach_primary_input(network, gen, node) { + pin_delay = DELAY(node)->pin_delay; + if (pin_delay == NIL(delay_pin_t)) { + delay_info[i++] = NIL(char); + } + else { + modelcpy(pin_delay, pin_delay, node); + delay_info[i++] = (char *) pin_delay; + DELAY(node)->pin_delay = NIL(delay_pin_t); + } + } + return(delay_info); +} + +/* + * Routines to query the pin_delay_t structure. + * Intended for use by the mapper + */ +double +delay_get_load(pin_delay) +char *pin_delay; +{ + return(((delay_pin_t *) pin_delay)->load); +} + +delay_time_t +delay_get_drive(pin_delay) +char *pin_delay; +{ + return(((delay_pin_t *) pin_delay)->drive); +} + +delay_time_t +delay_get_block(pin_delay) +char *pin_delay; +{ + return(((delay_pin_t *) pin_delay)->block); +} + +double +delay_get_load_limit(pin_delay) +char *pin_delay; +{ + return(((delay_pin_t *) pin_delay)->max_load); +} + + +static network_t * +map_node_to_network(node, mode) +node_t *node; +double mode; +{ + network_t *net1, *net2; + library_t *library; + + if ((library = lib_get_library()) == NIL(library_t)) { + delay_error("Mapped Delay model: no current library\n"); + return(NIL(network_t)); /* Not reached -- in to keep lint happy */ + } else { + net1 = network_create_from_node(node); + net2 = map_network(net1, library, mode, 1, 0); /* user spec mode & inverters */ + network_free(net1); + return net2; + } +} + +/* + * Routines to query the primary outputs/inputs for user-specified data + * + * Could be done by delay_get_parameter calls -- packaged for convenience + * Return 1 if value is set, 0 otherwisw + */ +int +delay_get_po_load(node, load) +node_t *node; +double *load; +{ + double l; + if (node_type(node) != PRIMARY_OUTPUT) { + return(0); + } + + l = delay_get_parameter(node, DELAY_OUTPUT_LOAD); + if (l != DELAY_VALUE_NOT_GIVEN) { + *load = l; + return(1); + } + return(0); +} + +int +delay_get_pi_drive(node, drive) +node_t *node; +delay_time_t *drive; +{ + delay_time_t t; + if (node_type(node) != PRIMARY_INPUT) { + return(0); + } + t.rise = delay_get_parameter(node, DELAY_DRIVE_RISE); + t.fall = delay_get_parameter(node, DELAY_DRIVE_FALL); + if (t.rise != DELAY_VALUE_NOT_GIVEN && t.fall != DELAY_VALUE_NOT_GIVEN) { + *drive = t; + return(1); + } + return(0); +} + +int +delay_get_pi_load_limit(node, load_limit) +node_t *node; +double *load_limit; +{ + double l; + if (node_type(node) != PRIMARY_INPUT) { + return(0); + } + l = delay_get_parameter(node, DELAY_MAX_INPUT_LOAD); + if (l != DELAY_VALUE_NOT_GIVEN) { + *load_limit = l; + return(1); + } + return(0); +} + +int delay_get_pi_arrival_time(node, arrival) +node_t *node; +delay_time_t *arrival; +{ + delay_time_t t; + if (node_type(node) != PRIMARY_INPUT) { + return(0); + } + t.rise = delay_get_parameter(node, DELAY_ARRIVAL_RISE); + t.fall = delay_get_parameter(node, DELAY_ARRIVAL_FALL); + if (t.rise != DELAY_VALUE_NOT_GIVEN && t.fall != DELAY_VALUE_NOT_GIVEN) { + *arrival = t; + return(1); + } + return(0); +} + +int +delay_get_po_required_time(node, required) +node_t *node; +delay_time_t *required; +{ + delay_time_t t; + if (node_type(node) != PRIMARY_OUTPUT) { + return(0); + } + t.rise = delay_get_parameter(node, DELAY_REQUIRED_RISE); + t.fall = delay_get_parameter(node, DELAY_REQUIRED_FALL); + if (t.rise != DELAY_VALUE_NOT_GIVEN && t.fall != DELAY_VALUE_NOT_GIVEN) { + *required = t; + return(1); + } + return(0); +} + +/* Debugging code. Not currently used. */ + +#if !defined(lint) && !defined(SABER) +static void +print_pin_delays(node, model) +node_t *node; +delay_model_t model; +{ + int i; + int pin; + double load; + node_t *fanout; + delay_pin_t *pin_delay; + lsGen gen; + + + printf("Delay calculation for node %s:\n",node_name(node)); + + for(i = 0; i < node_num_fanin(node); ++i) { + pin_delay = get_pin_delay(node, i, model); + printf("pin %d br %f bf %f dr %f df %f phase %s load %f\n", + i, pin_delay -> block.rise, pin_delay -> block.fall, + pin_delay -> drive.rise, pin_delay -> drive.fall, + (pin_delay -> phase == PHASE_INVERTING?"neg": + (pin_delay -> phase == PHASE_NONINVERTING?"pos":"both")), + pin_delay -> load); + } + + + load = compute_wire_load(node_network(node), node_num_fanout(node)); + foreach_fanout_pin(node, gen, fanout, pin) { + pin_delay = get_pin_delay(fanout, pin, model); + load += pin_delay->load; + } + + printf("load calculation for node %s: stored %f calculated %f\n", + node_name(node), DELAY(node)->load, load); +} +#endif /* lint and saber */ + +#ifdef SIS +/* + * Routine to get the synchronization data regarding PO/PI nodes + * returns 0 if not synchronized, 1 if it is + * "flag" returns whether the delay-data refers to occurance before or after + * the clock pulse. The delay data can be obtained from the routines + * delay_get_pi_arrival_time() and delay_get_po_required_time() + */ +int +delay_get_synch_edge(node, edgep, flag) +node_t *node; +clock_edge_t *edgep; +int *flag; +{ + char *name; + sis_clock_t *clock; + network_t *network; + + if (node_type(node) == INTERNAL) { + return(0); + } + if ((name = DELAY(node)->synch_clock_name) == NIL(char)) { + return(0); + } + if ((network = node_network(node)) == NIL(network_t)) { + return(0); + } + if ((clock = clock_get_by_name(network, name)) == NIL(sis_clock_t)) { + return(0); + } + edgep->clock = clock; + edgep->transition = DELAY(node)->synch_clock_edge; + *flag = DELAY(node)->synch_relative_flag; + + return(1); +} + +/* + * Routine to copy the synchronization edge information from the fanin + * of a po_node to the po_node itself. Meant for use by the io package + */ + +void +delay_copy_terminal_constraints(po_node) +node_t *po_node; +{ + char *name; + node_t *node; + double value; + network_t *network; + + assert(node_type(po_node) == PRIMARY_OUTPUT); + node = node_get_fanin(po_node, 0); + + /* Copy the loads and the required times at the outputs */ + value = delay_get_parameter(node, DELAY_OUTPUT_LOAD); + delay_set_parameter(po_node, DELAY_OUTPUT_LOAD, value); + value = delay_get_parameter(node, DELAY_REQUIRED_RISE); + delay_set_parameter(po_node, DELAY_REQUIRED_RISE, value); + value = delay_get_parameter(node, DELAY_REQUIRED_FALL); + delay_set_parameter(po_node, DELAY_REQUIRED_FALL, value); + + if ((name = DELAY(node)->synch_clock_name) == NIL(char)) { + return; + } + if ((network = node_network(node)) == NIL(network_t)) { + return; + } + if (clock_get_by_name(network, name) == NIL(sis_clock_t)) { + return; + } + + /* Copy the synchronization data */ + DELAY(po_node)->synch_clock_name = util_strsav(name); + DELAY(po_node)->synch_clock_edge = DELAY(node)->synch_clock_edge; + DELAY(po_node)->synch_relative_flag = DELAY(node)->synch_relative_flag; + +} + + +/* + * Routine to set the synchronization data regarding PO/PI nodes + * returns 0 if it cannot set the values .... + * "flag" is one of BEFORE_CLOCK_EDGE or AFTER_CLOCK_EDGE and indicates + * whether the delay-data refers to occurance before or after + * the clock pulse. The delay data can be set by the routine + * delay_set_parameter() using the appropriate calls. + */ +int +delay_set_synch_edge(node, edge, flag) +node_t *node; +clock_edge_t edge; +int flag; /* BEFORE_CLOCK_EDGE or AFTER_CLOCK_EDGE */ +{ + DELAY(node)->synch_clock_name = util_strsav(clock_name(edge.clock)); + DELAY(node)->synch_clock_edge = edge.transition; + DELAY(node)->synch_relative_flag = flag; + return(1); +} +#endif /* SIS */ diff --git a/sis/delay/delay.doc b/sis/delay/delay.doc new file mode 100644 index 0000000..1b3a57c --- /dev/null +++ b/sis/delay/delay.doc @@ -0,0 +1,481 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/delay/delay.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +typedef enum delay_model_enum delay_model_t; +enum delay_model_enum { + DELAY_MODEL_UNIT, DELAY_MODEL_LIBRARY, DELAY_MODEL_UNIT_FANOUT, + DELAY_MODEL_MAPPED, DELAY_MODEL_UNKNOWN, DELAY_MODEL_TDC +}; + +typedef struct time_struct delay_time_t; +struct time_struct { + double rise; + double fall; +}; + +int +delay_trace(network, model) +network_t *network; +delay_model_t model; + Performs a complete delay trace for a network, using the specified + model. + + DELAY_MODEL_UNIT is a simple unit-delay model with 1.0 ns delay + for each node (independent of it size !). + Each primary input is assumed to arrive at time 0, and + each primary output is required at the time of the latest output. + (**hack** this should be fixed by mapping user-specified required + arrival times into this unit system ...) + + DELAY_MODEL_UNIT_FANOUT is a simple unit-delay model with 1.0 + ns delay for each node (independent of size), plus a .2 ns + delay per fanout. Each primary input is assumed to arrive at + time 0, and each primary output is required at the time of the + latest output. + + DELAY_MODEL_LIBRARY assumes the network is mapped, and performs + a delay trace using the library model information. The basic delay + model used by DELAY_MODEL_LIBRARY is a linear model; the delay across + a pin i is given by the equation + + delay(i) = block(i) + drive(i) * load + + Where load is the total capacitive load driven by this gate. The + block and drive parameters may vary for rising or falling edges, and + are obtained from the technology mapping package. It is an error + to use DELAY_MODEL_LIBRARY if the network (or any portion of it) is + unmapped. + + DELAY_MODEL_MAPPED is a superset of DELAY_MODEL_LIBRARY. If the + network is entirely mapped, then DELAY_MODEL_MAPPED computes the + same result as DELAY_MODEL_LIBRARY. If some node in the network is + not mapped, then DELAY_MODEL_MAPPED maps this node into a subnetwork + and then calls delay_trace recursively on this subnetwork to compute + the information in its delay_pin structure. + + DELAY_MODEL_TDC is a model based on the Timing-Driven-Cofactoring + of the nodes in the network. Based on the arrival time information, + the node is decomposed into a cofactoring tree. The delay through + this tree is used to compute the information in the delay_pin + structure of the node. NOTE: the routine delay_set_tdc_params() + must be called before a delay_trace() is done using this model. + + Returns 1 if successful, or 0 if an error occured. error_string() + can be used to get error information, if any. Most probable cause + for error return is attempt to use DELAY_MODEL_LIBRARY when the + network is not mapped. + + ** CAVEAT ** + + delay_trace computes and stores a large amount of information at each + node, which information is used by the remainder of the package. + Changes to the network can invalidate this stored information. No + check is ever made to ensure that the stored information is valid, so + users of this package should do a new delay_trace if it is suspected + that the network may have changed since the last delay_trace was done. + Eventually, an incremental timing simulation package should relax this + requirement. + +void +delay_set_tdc_params(fname) +char *fname; + Reads the coefficients for the TDC model (K_0, K_1, K_2) from the + file named "fname". In case the file cannot be read or propoerly + parsed the delfault values are used. Setting the fname to be + NIL(char) cause the defaults to be used. A line with tree numeric + values in the beginning is taken to represent the coefficients. + +delay_model_t +delay_get_model_from_name(name) +char *name; + Returns the delay model based on the command line argument for the + delay model ("unit", "unit-fanout", "mapped", "library", "tdc"). + Returns DELAY_MODEL_UNKNOWN in case an unrecognized model is specified. + +delay_time_t +delay_node_pin(node, pin_num, model) +node_t *node; +int pin_num; +delay_model_t model; + After a delay_trace is done, computes the incremental delay across + pin pin_num of node under model. The pin number is a synonym for + the fanin index (the pin number of fanin fanin of node node is the + number returned by node_get_fanin_index(node, fanin). The routine will + compute the load at the fanouts. + +delay_time_t +delay_fanout_contribution(node, pin_num, fanout, model) +node_t *node, *fanout; +int pin_num; +delay_model_t model; + Computes the total contribution of fanout to the delay across pin + pin_num of node node under model. (In other words, + delay_fanout_contribution computes the difference between the reported + delay across pin pin_num and what such a delay would be if fanout and + its associated capactive load were removed from the network). fanout + must be a fanout of node, and a delay_trace under model must have been + done for the output from this routine to make any sense at all. + +delay_pin_t * +get_pin_delay(node, pin, model) +node_t *node; +int pin; +delay_model_t model; + This routine returns a structure containing the linear delay model for + the node from its "pin" input under the specified delay model. The + model can then be queried using the routines specified. + + This routine was meant to be an internal routine of the delay package. + However, after many requests it is being exported. + IMPORTANT NOTE: The routine returns a static structure. This structure + will get overwritten by a calls to the functions delay_node_pin(), + delay_trace(). Hence to be safe, copy the data from the returned + structure into variables as soon as you call the get_pin_delay routine. + +delay_time_t +delay_arrival_time(node) +node_t *node; + After a delay trace, this can be used to get the arrival time at + a node. + + +delay_time_t +delay_required_time(node) +node_t *node; + After a delay trace, this can be used to get the required time at + a node. + +int +delay_wire_required_time(node, fanin_index, model, req) +node_t *node; +int fanin_index; +delay_model_t model; +delay_time_t *req; + After a delay trace it can be used to get the required time at the + "fanin_index" input of node "node". This is useful to compute the + required times at wires (rather than at nodes). Returns 0 if there is + some error (fanin_index out of bound etc.) + +int +delay_wire_slack_time(node, fanin_index, model, slack) +node_t *node; +int fanin_index; +delay_model_t model; +delay_time_t *rslack; + After a delay trace it can be used to get the slack time at the + "fanin_index" input of node "node". This is useful to compute the + slack times at wires (rather than at nodes). Returns 0 if there is + some error (fanin_index out of bound etc.) + + +delay_time_t +delay_slack_time(node) +node_t *node; + After a delay trace, this can be used to get the slack time at a node. + +double +delay_load(node) +node_t *node; + After a delay trace, this can be used to get the load driven by node. + + +int +delay_required_time(node, fanin, model, req_p) +node_t *node; +delay_model_t model; +delay_time_t *req_p; + After a delay trace, this can be used to get the required time at + wire that goes from the node "fanin" to the node "node". The required + time of the wire is returned by filling out the "req_p" structure. + In case of an error the routine returns 0 and contents of "req_p" + are unchanged. + +double +compute_wire_load(network, n) +network_t *network; +int n; + Returns the contribution of the wiring load for n fanouts. The + wire load can be specified as discrete values (set_delay -W) or + as a linear load (set_delay -S). + +node_t * +delay_latest_output(network, arrival_time) +network_t *network; +double *arrival_time; + After a delay trace, this can be used to find which output has the + latest arrival time (that is, the maximum of the arrival rising + and the arrival falling.) + +int +delay_get_po_load(f, load) +node_t *f; +double *load; + If the user has specified a load at the primary output node f, + the routine will fill its value in the "load" field and return 1. + Returns 0 if no value is specified by the user. + +int +delay_get_pi_drive(f, drive) +node_t *f; +delay_time_t *drive; + If the user has specified a drive at the primary input node f, + the routine will fill its value in the "drive" field and return 1. + Returns 0 if no primary input drive is specified by the user for f. + +int +delay_get_pi_load_limit(f, max_load) +node_t *f; +double *max_load; + If the user has specified a maximum load that the primary input node f + can drive, the routine will fill its value in the "max_load" field and + return 1. Returns 0 if no primary maximuym_load constraint is + specified for the primary input. + +int delay_get_pi_arrival_time(f, arrival) +node_t *f; +delay_time_t *arrival; + If the user has specified an arrival time at the primary input + node f, the routine will fill its value in the "arrival" field + and return 1. Returns 0 if no arrival time is specified for f. + +int +delay_get_po_required_time(f, required) +node_t *f; +delay_time_t *required; + If the user has specified an arrival time at the primary output + node f, the routine will fill its value in the "required" field + and return 1. Returns 0 if no required time is specified for f. + + +The following routines couple the delay package with the clock package... +They allow the user to set and get constraints at PI/PO nodes such that +thay are relative to clock edges. These are meant for interface with +timing analysis tools. + +int +delay_get_synch_edge(node, edgep, flag) +node_t *node; +clock_edge_t *edge_p; +int *flag; + Routine to get the synchronization data regarding PO/PI nodes. + Returns 0 if not synchronized, 1 if it is. "flag" returns whether the + delay-data refers to occurance before or after the clock pulse. The + delay data can be obtained from the routines delay_get_pi_arrival_time() + and delay_get_po_required_time().... The interpretation of the before + and after constructs is left to the timing analysis package... + +int +delay_set_synch_edge(node, edge, flag) +node_t *node; +clock_edge_t edge; +int flag; /* BEFORE_CLOCK_EDGE or AFTER_CLOCK_EDGE */ + + Routine to set the synchronization data regarding PO/PI nodes. + returns 0 if it cannot set the values (node is an internal node). + "flag" is one of BEFORE_CLOCK_EDGE or AFTER_CLOCK_EDGE and indicates + whether the delay-data refers to occurance before or after the clock + edge. The values of the arrival and required times can be set by the + routine delay_set_parameter() using the appropriate parameters. + + + +network_t * +delay_generate_decomposition(node, mode) +node_t *node; +double mode; + This can be used to get a network that is equivalent to the node. + The parameter "mode" specifies whether the decomposition is for + minimum area (mode == 0) or for minimum delay (mode == 1). The + correspondence between the inputs of the node and the network is + by node_long_name(). For the node, the delay parameters are computed + and stored with the node itself. The mapping of the node is + carried out assuming the fanout load in the original network. + +void +delay_compute_atime(node, model, load) +node_t *node; +delay_model_t model; +double load; + Computes the output arrival time under the given model for the node + node whose output drives a capacitive load given by load, and stores + it to be retrieved by subsequent calls to delay_arrival_time. The + arrival times of the fanins of node are presumed precomputed, either by + previous calls to delay_compute_atime or by a previous call to + delay_trace. + + This routine is specifically designed for use by the performance design + package, and, though exported, is not designed for general use. + Package users should use this routine with some caution. Multiple + calls to this routine are emphatically not a euphemism for a single + call to delay_trace followed by calls to delay_arrival_time. Further, + this routine invalidates all precomputed information for this node + computed by the last delay_trace; users are warned that delay + information on the network containing node, any of its fanins, or any + of its fanouts, should be treated as invalid following a call to + delay_compute_atime. + + +int +delay_incremental_trace(network) +network_t *network; + Update the delay information if required (the network has changed + since the last full delay_trace was done). This routine has the same + effect as calling delay_trace *except* that it attempts to avoid + excessive computation; in general, this routine attempts to avoid + recomputing delay values that have not changed. + This routine should almost always be faster than doing another + delay_trace, and should be accurate. An exception to this rule + is if a primary output has been added to the network since the last + delay_trace. If this has occured, a new delay_trace should be + done. Returns 0 if an error is detected. In addition to the + delay_trace errors this routine returns 0 if no full delay_trace + has been run. + + THIS ROUTINE IS NOT YET IMPLEMENTED. + + + + +The remaining routines are specifically designed for use by the library and +i/o packages, specifically to set and read appropriate parameters on the input +and output nodes of a circuit. Further, these routines do no +error-checking to determine if the relevant node is in fact an input or +output node (this information is not guaranteed stable when the i/o package is +performing). These routines should only be called by these packages or +by users who thoroughly understand their variant of the linear delay model. + + +delay_param_t { + DELAY_PHASE, + DELAY_BLOCK_RISE, DELAY_BLOCK_FALL, + DELAY_DRIVE_RISE, DELAY_DRIVE_FALL, + DELAY_INPUT_LOAD, DELAY_OUTPUT_LOAD, DELAY_MAX_INPUT_LOAD, + DELAY_ARRIVAL_RISE, DELAY_ARRIVAL_FALL, + DELAY_REQUIRED_RISE, DELAY_REQUIRED_FALL, + + DELAY_ADD_WIRE_LOAD, DELAY_WIRE_LOAD_SLOPE, + DELAY_DEFAULT_DRIVE_RISE, DELAY_DEFAULT_DRIVE_FALL, + DELAY_DEFAULT_OUTPUT_LOAD, DELAY_DEFAULT_MAX_INPUTLOAD, + DELAY_DEFAULT_ARRIVAL_RISE, DELAY_DEFAULT_ARRIVAL_FALL + DELAY_DEFAULT_REQUIRED_RISE, DELAY_DEFAULT_REQUIRED_FALL +}; + + +#define DELAY_NOT_SET + +#define DELAY_PHASE_INVERTING +#define DELAY_PHASE_NONINVERTING +#define DELAY_PHASE_NEITHER + + +void +delay_set_parameter(node, key, value) +node_t *node; +delay_param_t key; +double value; + Set parameter 'key' of 'node' to 'value'. This is not for + general use, but rather is a routine expected for use only by + the library and i/o package. This replaces any previous valued + stored for that parameter on this node. + + DELAY_NOT_SET can be used to force a value to its 'not given' state. + + For DELAY_PHASE, the types DELAY_PHASE_INVERTING, + DELAY_PHASE_NONINVERTING, and DELAY_PHASE_NEITHER set the + approrpiate phase. + + For DELAY_ADD_WIRE_LOAD, a value less than 0 clears the wire + load table; otherwise, the value is appended to the table. + +void +delay_set_default_parameter(network, key, value) +network_t *network; +delay_param_t key; +double value; + Similar to delay_set_parameter() but is used to store default delay + information associated with a network. + The wire load table, the default arrival times, default required + times, default input drive, and default output load are such global + parameters and are stored with a network (this is a departure from + mis2.1 where they were global variables that could be destroyed + when new networks were read in). + + +double +delay_get_parameter(node, key) +node_t *node; +delay_param_t key; + Get parameter 'key' of 'node'. This is not for general use, + but rather is a routine used by the i/o package. Returns + DELAY_NOT_SET if the value has not been set. It is currently not + possible to get the values of the wire load table. + +double +delay_get_default_parameter(network, key) +network_t *network; +delay_param_t key; + Get the default parameter 'key' of 'network'. This is not for general + use, but rather is a routine used by the i/o package. Returns + DELAY_NOT_SET if the value has not been set. It is currently not + possible to get the values of the wire load table although the + wire_load_slope can be retrieved. + + +char ** +delay_giveaway_pin_info(network) +network_t *network; + Package up the delay paramters for each primary input of the + network into a generic array. This is passed back to the + library package, and stored with the gate description. It is + returned, upon request, to the delay package to support the + DELAY_MODEL_LIBRARY delay model. + +double +delay_get_load(pin_delay) +char *pin_delay; + Extracts the load from the corresponding structure and returns it. + Intended for use by the mapping package. + +double +delay_get_load_limit(pin_delay) +char *pin_delay; + Extracts the maximum_load that can be driven from the corresponding + structure and returns it. Intended for use by the mapping package. + +delay_time_t +delay_get_drive(pin_delay) +char *pin_delay; + Extracts the drive from the corresponding structure and returns it. + Intended for use by the mapping package. + +delay_time_t +delay_get_block(pin_delay) +char *pin_delay; + Extracts the block delay (intrinsic) from the corresponding structure + and returns it. Intended for use by the mapping package. + +delay_time_t +delay_map_simulate(nfanins, fanin, model_params, load) +int nfanins; +delay_time_t **fanin; +char **model_params; +double load; + Computes an output arrival time for an implicit node whose fanins have + arrival times given by the array fanin and block and drive parameters + given by the array model_params, and whose output drives a capacitive + load given by load. This routine is entirely independent of any + node or network, and of any precomputed values stored by delay_trace; + hence it can be called entirely independent of the caveat mentioned + above. + + This routine is specifically designed for use by the technology mapper + and, though exported, is not designed for general use. Package users + should use this routine with some caution. In particular, the third + parameter is a highly-formatted internal structure whose contents are + private to the delay package. diff --git a/sis/delay/delay.h b/sis/delay/delay.h new file mode 100644 index 0000000..03ed980 --- /dev/null +++ b/sis/delay/delay.h @@ -0,0 +1,129 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/delay/delay.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#ifndef DELAY_H +#define DELAY_H + +typedef struct time_struct { + double rise; + double fall; +} delay_time_t; + +typedef enum pin_phase_enum { + PHASE_NOT_GIVEN, PHASE_INVERTING, PHASE_NONINVERTING, PHASE_NEITHER +} pin_phase_t; + +/* + * The delay_pin_t structure ..... + * Specifies the delay model between a pair of pins + */ +typedef struct delay_pin_struct { + delay_time_t block; + delay_time_t drive; + pin_phase_t phase; + double load; + double max_load; + delay_time_t user_time; +} delay_pin_t; + +typedef enum delay_model_enum { + DELAY_MODEL_UNIT, DELAY_MODEL_LIBRARY, DELAY_MODEL_UNIT_FANOUT, + DELAY_MODEL_MAPPED, DELAY_MODEL_UNKNOWN, DELAY_MODEL_TDC +} delay_model_t; + +EXTERN int delay_trace ARGS((network_t *, delay_model_t)); +EXTERN delay_model_t delay_get_model_from_name ARGS((char *)); +EXTERN delay_pin_t *get_pin_delay ARGS((node_t *, int, delay_model_t)); +EXTERN node_t *delay_latest_output ARGS((network_t *, double *)); +EXTERN network_t *delay_generate_decomposition ARGS((node_t *, double)); + +EXTERN delay_time_t delay_node_pin ARGS((node_t *, int, delay_model_t)); +EXTERN delay_time_t delay_fanout_contribution ARGS((node_t *, int, node_t *, delay_model_t)); +EXTERN int delay_wire_required_time ARGS((node_t *, int, delay_model_t, delay_time_t *)); +EXTERN delay_time_t delay_required_time ARGS((node_t *)); +EXTERN delay_time_t delay_arrival_time ARGS((node_t *)); +EXTERN delay_time_t delay_slack_time ARGS((node_t *)); +EXTERN double delay_load ARGS((node_t *)); +EXTERN double delay_compute_fo_load ARGS((node_t *, delay_model_t)); +EXTERN double compute_wire_load ARGS((network_t *, int)); + +typedef enum delay_param_enum { + DELAY_BLOCK_RISE, DELAY_BLOCK_FALL, + DELAY_DRIVE_RISE, DELAY_DRIVE_FALL, + DELAY_PHASE, + DELAY_OUTPUT_LOAD, + DELAY_INPUT_LOAD, DELAY_MAX_INPUT_LOAD, + DELAY_ARRIVAL_RISE, DELAY_ARRIVAL_FALL, + DELAY_REQUIRED_RISE, DELAY_REQUIRED_FALL, + + DELAY_ADD_WIRE_LOAD, DELAY_WIRE_LOAD_SLOPE, + DELAY_DEFAULT_DRIVE_RISE, DELAY_DEFAULT_DRIVE_FALL, + DELAY_DEFAULT_OUTPUT_LOAD, + DELAY_DEFAULT_ARRIVAL_RISE, DELAY_DEFAULT_ARRIVAL_FALL, + DELAY_DEFAULT_REQUIRED_RISE, DELAY_DEFAULT_REQUIRED_FALL, + DELAY_DEFAULT_MAX_INPUT_LOAD +} delay_param_t; + +#ifdef SIS +/* For modelling the synchronization of the primary inputs/outputs */ +#define BEFORE_CLOCK_EDGE 0 +#define AFTER_CLOCK_EDGE 1 +#endif /* SIS */ + +#define DELAY_NOT_SET -1234567.0 +#define DELAY_VALUE_NOT_GIVEN DELAY_NOT_SET +#define DELAY_NOT_SET_STRING "UNSET " +#define DELAY_PHASE_NOT_GIVEN -1 + +#define DELAY_PHASE_INVERTING 0.0 +#define DELAY_PHASE_NONINVERTING 1.0 +#define DELAY_PHASE_NEITHER 2.0 + +EXTERN void delay_set_tdc_params ARGS((char *)); +EXTERN void delay_set_parameter ARGS((node_t *, delay_param_t, double)); +EXTERN double delay_get_parameter ARGS((node_t *, delay_param_t)); +EXTERN void delay_set_default_parameter ARGS((network_t *, delay_param_t, double)); +EXTERN double delay_get_default_parameter ARGS((network_t *, delay_param_t)); + +/* Routines to interface with the mapper */ +EXTERN delay_time_t delay_map_simulate(); /* special mapping routine */ +EXTERN char **delay_giveaway_pin_delay ARGS((network_t *)); /* library read-in hack */ +EXTERN double delay_get_load ARGS((char *)); +EXTERN double delay_get_load_limit ARGS((char *)); +EXTERN delay_time_t delay_get_drive ARGS((char *)); +EXTERN delay_time_t delay_get_block ARGS((char *)); + +/* Routines to query user-specified data regarding the environment */ +EXTERN int delay_get_pi_drive ARGS((node_t *, delay_time_t *)); +EXTERN int delay_get_pi_load_limit ARGS((node_t *, double *)); +EXTERN int delay_get_pi_arrival_time ARGS((node_t *, delay_time_t *)); +EXTERN int delay_get_po_load ARGS((node_t *, double *)); +EXTERN int delay_get_po_required_time ARGS((node_t *, delay_time_t *)); +#ifdef SIS +EXTERN int delay_set_synch_edge ARGS((node_t *, clock_edge_t, int)); +EXTERN int delay_get_synch_edge ARGS((node_t *, clock_edge_t *, int *)); +#endif /* SIS */ + +/* io package */ +EXTERN void delay_print_blif_wire_loads ARGS((network_t *, FILE *)); +EXTERN void delay_print_slif_wire_loads ARGS((network_t *, FILE *)); + +#ifdef SIS +EXTERN void delay_copy_terminal_constraints ARGS((node_t *)); +#endif /* SIS */ + +/* networks */ +EXTERN void delay_network_alloc ARGS((network_t *)); +EXTERN void delay_network_free ARGS((network_t *)); +EXTERN void delay_network_dup ARGS((network_t *, network_t *)); + +/* For the speed package */ +EXTERN network_t * tdc_factor_network ARGS((network_t *)); + +#endif diff --git a/sis/delay/delay_int.h b/sis/delay/delay_int.h new file mode 100644 index 0000000..5057a1a --- /dev/null +++ b/sis/delay/delay_int.h @@ -0,0 +1,65 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/delay/delay_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "delay.h" + +#define DELAY_SLOT delay +#define DELAY(node) ((delay_node_t *) node->DELAY_SLOT) + +#define DEF_DELAY_SLOT default_delay +#define DEF_DELAY(network) ((delay_network_t *) network->DEF_DELAY_SLOT) + +/* + * Each node is annotated with a 'delay_node_t'; this stores the arrival, + * required, and slack times for each node. Also, for PRIMARY_INPUT and + * PRIMARY_OUTPUT nodes, the pair (time, time_given) allows the specification + * of input arrival and output required times, respectively. Finally, a delay + * model slot is reserved for PRIMARY_INPUT and PRIMARY_OUTPUT nodes; if + * present, it stores the input-rise factor and output-load factors. + */ + +typedef struct delay_node_struct { + delay_time_t arrival; + delay_time_t required; + delay_time_t slack; + delay_model_t pin_params_valid; + int num_pin_params; + delay_pin_t **pin_params; + delay_pin_t *pin_delay; + double load; +#ifdef SIS + char *synch_clock_name; /* clock_name w.r.t. arr & req times spec. */ + int synch_clock_edge; /* RISE_TRANSITION or FALL_TRANSITION */ + int synch_relative_flag; /* BEFORE_CLOCK_EDGE or AFTER_CLOCK_EDGE */ +#endif /* SIS */ +} delay_node_t; + +typedef struct delay_wire_load_struct { + double slope; + int num_pins_set; + array_t *pins; +} delay_wire_load_table_t; + +typedef struct delay_network_struct { + delay_time_t default_arrival; + delay_time_t default_required; + delay_wire_load_table_t wire_load_table; + delay_pin_t pipo_model; +} delay_network_t; + +/* used in com_delay.c */ +extern void delay_dup(); +extern void delay_free(); +extern void delay_alloc(); +extern void delay_invalid(); + +/* Interface to the timing driven cofactoring (tdc) model */ +extern void compute_tdc_parms(); + +extern void delay_print_wire_loads(); diff --git a/sis/delay/mapdelay.c b/sis/delay/mapdelay.c new file mode 100644 index 0000000..ddb4415 --- /dev/null +++ b/sis/delay/mapdelay.c @@ -0,0 +1,72 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/delay/mapdelay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +#include "sis.h" +#include "delay_int.h" + + +#define ARRIVAL(time, new_time) \ + if (new_time > time) time = new_time; + + +delay_time_t +delay_map_simulate(nin, pin_arrivals, model, load) +int nin; +delay_time_t **pin_arrivals; +char **model; +double load; +{ + register int i; + register delay_pin_t *pin_delay, **lib_delay_model; + delay_time_t delay, arrival, *pin_arrival; + + lib_delay_model = (delay_pin_t **) model; + if (lib_delay_model == 0) { + fail("no delay model -- should have been caught earlier"); + } + + arrival.rise = - INFINITY; + arrival.fall = - INFINITY; + + for(i = nin-1; i >= 0; i--) { + pin_delay = lib_delay_model[i]; + if (pin_delay == 0) { + fail("no pin delay -- should have been caught earlier"); + } + + pin_arrival = pin_arrivals[i]; + if (pin_arrival == 0) { + fail("no pin_arrival time ?"); + } + + delay.rise = pin_delay->block.rise + pin_delay->drive.rise * load; + delay.fall = pin_delay->block.fall + pin_delay->drive.fall * load; + + switch(pin_delay->phase) { + case PHASE_INVERTING: + ARRIVAL(arrival.rise, pin_arrival->fall + delay.rise); + ARRIVAL(arrival.fall, pin_arrival->rise + delay.fall); + break; + + case PHASE_NONINVERTING: + ARRIVAL(arrival.rise, pin_arrival->rise + delay.rise); + ARRIVAL(arrival.fall, pin_arrival->fall + delay.fall); + break; + + case PHASE_NEITHER: + ARRIVAL(arrival.rise, pin_arrival->fall + delay.rise); + ARRIVAL(arrival.fall, pin_arrival->rise + delay.fall); + ARRIVAL(arrival.rise, pin_arrival->rise + delay.rise); + ARRIVAL(arrival.fall, pin_arrival->fall + delay.fall); + break; + } + } + + return arrival; +} diff --git a/sis/delay/tdc_delay.c b/sis/delay/tdc_delay.c new file mode 100644 index 0000000..5f46bdd --- /dev/null +++ b/sis/delay/tdc_delay.c @@ -0,0 +1,1114 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/delay/tdc_delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +/* + * Utility functions for timing driven cofactor. + * Author: Paul Gutwin Date: 12/03/90 + */ + +#include "sis.h" +#include "tdc_int.h" +#include "delay_int.h" + +#define TDC_MAXLINE 255 +/* Macro Definition */ +#define LOG2(val) (log10(val)/.30103) + +static double delay_eqn(); +static double tdc_get_slack(); +static double tdc_get_flslack(); +static double do_delay_to_output(); +static double tdc_group_delay(); +static network_t *tdc_bdd_to_network(); +static void do_girdle(); +static void tdc_free_info(); +static void tdc_sort_inputs(); +static void do_tdc_bdd_node_list(); +static tdc_info_t *tdc_alloc_info(); +static st_table *tdc_bdd_node_list(); +static int girdle(); +static int count_bdd_fct_lines(); +static int do_count_bdd_fct_lines(); + +static struct tdc_param_struct { + double K_0; + double K_1; + double K_2; + } tdc_model_params; + +static struct tdc_param_struct tdc_default_parameters = { + /* K_0 */ 0.35, + /* K_1 */ 0.6, + /* K_2 */ 0.5 + }; + +/* + * Compute delay values based on TDC model. + * Option is a flag that indicates which level of the tdc model + * to use. options = 0 indicates the simplest tdc model should + * be used. options = 1 indicates that the fanout of the node + * should modify the delay values. + * options = 2 indicates that complexity and fanout are considers. + */ + +void +compute_tdc_params(node, options) +node_t *node; +int options; +{ + + int i, j; + double fanout_delay, temp_delay; + tdc_info_t *info; + pin_member_t *current_member, *new_member; + pin_group_t *current_group, *new_group; + +#ifdef TDC_DEBUG + (void)fprintf(sisout, "->Computing tdc params for node %s\n",node_name(node)); +#endif + + info = tdc_alloc_info(options); + tdc_sort_inputs(node, info); + + /* calculate the delay for each group to the output */ + info->group_list_head->delay_to_output = + do_delay_to_output(info->group_list_head); + + /* + * If options = 1,2, we need to get the fanout count and lump that delay + * at the output. + */ + if ((options == 1)||(options == 2)) { + fanout_delay = ((double) node_num_fanout(node)) * .2; + } else { + fanout_delay = 0; + } + + /* + * calculate the delay for each of the input pins of this node + * and set up the pin_params + */ + current_group = info->group_list_head; + while(current_group != NULL) { + current_member = current_group->latest_pin; + for( i=0; i < current_group->group_size; i++) { + j = current_member->pin_number; + temp_delay = current_group->delay_to_output + fanout_delay; + DELAY(node)->pin_params[j]->block.rise = temp_delay; + DELAY(node)->pin_params[j]->block.fall = temp_delay; + DELAY(node)->pin_params[j]->drive.rise = 1; + DELAY(node)->pin_params[j]->drive.fall = 1; + DELAY(node)->pin_params[j]->phase = PHASE_INVERTING; +#ifdef TDC_DEBUG + (void)fprintf(sisout, "PARAMETERS FROM INPUT %d\n", j); + (void)fprintf(sisout, "b = %g load = %g\n", + temp_delay, DELAY(node)->pin_params[j]->load); +#endif + current_member= current_member->prev; + } + current_group = current_group->next; + } + DELAY(node)->pin_params_valid = DELAY_MODEL_TDC; + +#ifdef DEBUG2 + /* + printf("Slack Difference\n"); + for (current_group = info->group_list_head, j = 1; current_group != NULL; + current_group = current_group->next, j++){ + (void)fprintf(sisout, "Slack difference for group %d = %f\n", j, + (current_group->total_slack - tdc_get_flslack(current_group))); + } + */ +#endif + + /* + * OK, all done! Free the BDDs, and all other structures!! + */ + tdc_free_info(info); + + return; +} + +/* + * Allocate and initialize the data structure for the tdc routines + */ +static tdc_info_t * +tdc_alloc_info(options) +int options; +{ + tdc_info_t *info; + + info = ALLOC(tdc_info_t, 1); + info->options = options; + info->bdd_mgr = NULL; + info->my_bdd = NULL; + info->sorted_list = NULL; + info->group_list_head = NULL; + + return info; +} + +static void +tdc_free_info(info) +tdc_info_t *info; +{ + pin_member_t *current_member, *new_member; + pin_group_t *current_group, *new_group; + + ntbdd_end_manager(info->bdd_mgr); + st_free_table(info->leaves); + for (current_member = info->sorted_list; current_member != NULL; ){ + new_member = current_member->next; + FREE(current_member); + current_member = new_member; + } + for (current_group = info->group_list_head; current_group != NULL; ){ + new_group = current_group->next; + FREE(current_group); + current_group = new_group; + } + FREE(info); +} + + +/* + * Interface routine: Allows the user to set different values for + * the coefficients. + */ +void +delay_set_tdc_params(fname) +char *fname; +{ + FILE *fp; + int i, found_params; + double d0, d1, d2; + char *real_filename, line[TDC_MAXLINE]; + + if (fname != NIL(char)){ + fp = com_open_file(fname, "r", &real_filename, 0); + if (fp != NIL(FILE)){ + found_params = FALSE; + while (fgets(line, TDC_MAXLINE, fp) != NULL){ + i = sscanf(line, "%lf %lf %lf", &d0, &d1, &d2); + if (i == 3){ + found_params = TRUE; + break; + } + } + if (found_params){ + tdc_model_params.K_0 = d0; + tdc_model_params.K_1 = d1; + tdc_model_params.K_2 = d2; + } else { + (void)fprintf(siserr, "Could not parse parameters: Using defaults\n"); + tdc_model_params = tdc_default_parameters; + } + (void) fclose(fp); + } else { + (void)fprintf(siserr, "ERROR: cannot open %s for TDC parameters\n", + real_filename); + (void)fprintf(siserr, " Using the default TDC parameters\n"); + tdc_model_params = tdc_default_parameters; + } + FREE(real_filename); + } else { + tdc_model_params = tdc_default_parameters; + } + + (void)fprintf(sisout, "TDC parameters are %f %f %f\n", + tdc_model_params.K_0, tdc_model_params.K_1, tdc_model_params.K_2); +} + +/* + * Count function lines crossing a cut in the specified bdd from the specific + * group. + */ + +static int +count_bdd_fct_lines(my_bdd, source_group) +bdd_t *my_bdd; +pin_group_t *source_group; +{ + bdd_t *then_node; + bdd_t *my_bdd_top_node; + st_table *visited; + int fct_line_count, first_src, last_src, first_dest, last_dest; + +#ifdef TDC_DEBUG + (void) fprintf(sisout, "Computing bdd function lines for bdd %x\n", my_bdd); +#endif + /* check to see if this is the last group. If so, return zero. */ + if (source_group->next == NULL) { +#ifdef TDC_DEBUG + (void) fprintf(sisout, "source_group->next == NULL\n"); +#endif + return(0); + } + + /* initialize stuff */ + visited = st_init_table(st_ptrcmp, st_ptrhash); + first_src = source_group->first; + last_src = source_group->last; + first_dest = (source_group->next)->first; + last_dest = (source_group->next)->last; + + /* count the children out of this group */ + fct_line_count = do_count_bdd_fct_lines(my_bdd, first_src, last_src, + first_dest, last_dest, visited); + + st_free_table(visited); + + return fct_line_count; + +} + +/* + * Recursive routine to count the number of nodes in the destination group + * that are touched by a function line out of the source group. + * + * First, check to see if we have been visited. If so, return 0. + * If we are one or zero, return 0. + * Next, see if we are in the destination group and the caller is in the + * source group. If so, mark self as visited, and return 1. + * If we are in the srouce group, set source group flag and recurse. + * If not in the source group, clear source group flag and recurse. + * + */ + +static int +do_count_bdd_fct_lines(my_bdd_node, first_src, last_src, + first_dest, last_dest, visited, source_grp) +bdd_t *my_bdd_node; +int first_src, last_src, first_dest, last_dest; +st_table *visited; +boolean source_grp; +{ + boolean in_src; + bdd_node *bdd_reg; + bdd_t *then_node, *else_node; + int then_count, else_count, return_count, my_bdd_node_id; + + bdd_reg = bdd_get_node(my_bdd_node, &in_src); + + /* + * If the node has been visited then we dont do anything + */ + if(st_is_member(visited, (char *) bdd_reg)) { /* yes if true */ +#ifdef TDC_DEBUG + (void) fprintf(sisout, "Found visited node, %x\n", bdd_reg); +#endif + return(0); + } + /* + * am I a one or zero node? If so, bail out! + */ + if(bdd_is_tautology(my_bdd_node, 1) || bdd_is_tautology(my_bdd_node, 0)) { + return(0); + } + + my_bdd_node_id = bdd_top_var_id(my_bdd_node); + + /* + * Am I in the dest. group and the source_grp flag set? + * If so, mark self as visited, and return count of 1 + */ + if (first_dest <= (int) my_bdd_node_id + && last_dest >= (int) my_bdd_node_id + && source_grp) { +#ifdef TDC_DEBUG + (void) fprintf(sisout, "Found target node, %x\n", bdd_reg); +#endif + return_count = 1; + (void)st_insert(visited, (char *) bdd_reg, (char *) &return_count); + return(1); + } + + /* Am I in the source group? */ + in_src = (first_src <= (int)my_bdd_node_id) && + (last_src >= (int)my_bdd_node_id); + + /* get the children pointers */ + then_node = bdd_then(my_bdd_node); + else_node = bdd_else(my_bdd_node); + + /* + * now go for the recursion + */ + then_count = do_count_bdd_fct_lines(then_node, first_src, last_src, + first_dest, last_dest, visited, in_src); + else_count = do_count_bdd_fct_lines(else_node, first_src, last_src, + first_dest, last_dest, visited, in_src); + + /* sum up the results and return */ + return_count = then_count + else_count; +#ifdef DEBUG2 + (void) fprintf(sisout, "Return count = %d\n", return_count); +#endif + return(return_count); +} + +static double +do_delay_to_output(current_group) +pin_group_t *current_group; +{ + double temp_delay; + + if (current_group == NULL) return(0); + + temp_delay = current_group->group_delay + do_delay_to_output(current_group->next); + +/* HACK! (Sorry about that) */ + current_group->delay_to_output = temp_delay; + + return(temp_delay); +} + +/* + This routine will calculate the total slack for the group specified. + If new_pin is specified, it will be treated as the latest pin in the + group. +*/ +static double +tdc_get_slack(group, new_pin) +pin_group_t *group; +pin_member_t *new_pin; +{ + int i; + double slack; + pin_member_t *last_node, *current_node; + delay_node_t *last_node_delay, *current_node_delay; + + slack = 0; + if (new_pin != NULL) { + last_node_delay = DELAY(new_pin->source_node); + current_node = group->latest_pin; + } else { + last_node = group->latest_pin; + current_node = last_node->prev; + last_node_delay = DELAY(last_node->source_node); + } + + for(i=1; i < group->group_size; i++) { + current_node_delay = DELAY(current_node->source_node); + slack += (last_node_delay->arrival.rise - current_node_delay->arrival.rise); + current_node = current_node->prev; + } + + if (group->prev != NULL) { + slack += (last_node_delay->arrival.rise - (group->prev)->arr_est); + } + + return(slack); +} +/* + This routine will calculate the slack for the group + taking into account the number of function lines going from one group + to another. +*/ +static double +tdc_get_flslack(bdd, group) +bdd_t *bdd; +pin_group_t *group; +{ + int i; + double slack, prev_group_output_arrival; + pin_member_t *last_node, *current_node; + delay_node_t *last_node_delay, *prev_last_node_delay, *current_node_delay; + + slack = 0; + last_node = group->latest_pin; + current_node = last_node->prev; + last_node_delay = DELAY(last_node->source_node); + + /* + * Here we just calculate the slack due to the variables in the group + */ + for(i=1; igroup_size; i++) { + current_node_delay = DELAY(current_node->source_node); + slack += (last_node_delay->arrival.rise - current_node_delay->arrival.rise); + current_node = current_node->prev; + } + + /* + * Here we calculate the slack due to the function lines crossing + */ + if (group->prev != NULL) { + prev_last_node_delay = DELAY(group->prev->latest_pin->source_node); + prev_group_output_arrival = prev_last_node_delay->arrival.rise + group->prev->group_delay; + slack += (group->prev->fct_count)*(last_node_delay->arrival.rise - prev_group_output_arrival); + } + + return(slack); +} +/* + This routine calculates the delay for a particular mux based on the + number of function lines crossing into the function. + If options = 2, we need to worry about the complexity. +*/ +static double +tdc_group_delay(bdd, group, options) +bdd_t *bdd; +pin_group_t *group; +int options; +{ + + pin_group_t *prev_group; + int complexity, fct_line_count, temp_fct_count; +/* + If this is not the first group, go get the function line count for + the previous group, and save it in the previous group structure. +*/ +#ifdef TDC_DEBUG + (void)fprintf(sisout, "Computing delay for group %d -> %d\n", + group->first, group->last); +#endif + prev_group = group->prev; + fct_line_count = 0; + if (prev_group != NULL) { + fct_line_count = count_bdd_fct_lines(bdd, prev_group); + prev_group->fct_count = fct_line_count; + } +/* + This is a hack. I need to keep the function line count correct, and + this is a good place to do it. The above case will take care of + everyting except the first group. So, let's just take care of this + little piece of housekeeping +*/ + temp_fct_count = count_bdd_fct_lines(bdd, group); + group->fct_count = temp_fct_count; +#ifdef TDC_DEBUG + (void)fprintf(sisout, "fct_line_count = %d\n", temp_fct_count); +#endif + +/* + If options is 2, we should get the girdle size and use it as a measure of + the complexity ONLY for the first group. +*/ + complexity = 1; + if ((2 == options) && (prev_group == NULL) ) { + complexity = girdle(bdd, group); + } + group->girdle = complexity; + + group->group_delay = delay_eqn((group->group_size + fct_line_count),complexity); + + return(group->group_delay); +} + + +/* + This routine will calculate the delay of the MUX based on the number + of input pins. +*/ +static double +delay_eqn(count, complexity) +int count, complexity; +{ + double delay,t1,t2,t3; + + t1 = t2 = 0; + if(complexity > 1) { + t2 = tdc_model_params.K_2 * LOG2(complexity); + } + if (count > 1) { + t1 = tdc_model_params.K_1 * LOG2(count); + } + delay = tdc_model_params.K_0 + t1 + t2; + + return(delay); +} + +/* + This is the recursive part of the girdle counting routine. +*/ +static void +do_girdle(bdd, first_src, last_src, visited, counter) +bdd_t *bdd; +int first_src, last_src; +st_table *visited, *counter; +{ + bdd_t *then_node, *else_node; + bdd_node *bdd_reg; + int bdd_node_id,count; + boolean dummy; + + bdd_reg = bdd_get_node(bdd, &dummy); + + /* am I a one or zero node? If so, bail out! */ + if(bdd_is_tautology(bdd, 1) || bdd_is_tautology(bdd, 0)) { + return; + } + /* have I been visited? If so, bail out! */ + if(st_is_member(visited, (char *) bdd_reg)) { /* yes if true */ + return; + } + + bdd_node_id = bdd_top_var_id(bdd); + + /* don't care about anything below the bottom of our group */ + if (bdd_node_id > last_src) { + return; + } + + /* mark self as visited, and increment count for this node_id */ + (void)st_insert(visited, (char *) bdd_reg, (char *) bdd_node_id); + count = 0; + (void)st_lookup_int(counter, (char *) bdd_node_id, &count); + count++; + (void)st_insert(counter, (char *) bdd_node_id, (char *) count); + + /* get the children pointers */ + then_node = bdd_then(bdd); + else_node = bdd_else(bdd); + + /* recurse on the children */ + do_girdle(then_node, first_src, last_src, visited, counter); + do_girdle(else_node, first_src, last_src, visited, counter); + + return; +} +/* + This routine returns the size of the girdle of the group of interest +*/ +static int +girdle(bdd, group) +bdd_t *bdd; +pin_group_t *group; +{ + st_table *visited,*counter; + int i, count, girdle_count, first_src, last_src; + + /* initialize stuff */ + visited = st_init_table(st_ptrcmp, st_ptrhash); + counter = st_init_table(st_numcmp, st_numhash); + first_src = group->first; + last_src = group->last; + + /* Go do the recursion step */ + do_girdle(bdd, first_src, last_src, visited, counter); + + /* count up the results */ + girdle_count = 0; + for (i=first_src; i <= last_src && (last_src > 0); i++) { + assert(st_lookup_int(counter, (char *) i, &count)); + if(count > girdle_count) girdle_count = count; + } + + /* return what we found */ + st_free_table(visited); + st_free_table(counter); + return girdle_count; +} + +/* + * Sort inputs for node based on arrival times. + * (Timing Driven Cofactor) + * Option (in tdc_info_t) is a flag that indicates which level of the tdc model + * to use. options = 0 indicates the simplest tdc model should + * be used. options = 1 indicates that the fanout of the node + * should modify the delay values. + * options = 2 indicates that complexity and fanout are considers. + */ + +static void +tdc_sort_inputs(node,info) +node_t *node; +tdc_info_t *info; +{ + int i, j, fanin_count, fct_count, fanout_count, group_count; + double new_group_slack,temp_delay; + pin_member_t *sorted_list, *new_member, *current_member, *last_pin; + pin_group_t *group_list_head, *current_group, *new_group; + + node_t *fanin; + st_table *leaves; + bdd_manager *bdd_mgr; + bdd_t *my_bdd; + delay_time_t new_arr_time; + delay_node_t *next_node_delay, *node_delay, *fanin_delay; + +#ifdef TDC_DEBUG + (void) fprintf(sisout, "->Sorting and grouping inputs (tdc) for node %s\n", + node_name(node)); +#endif + +/* Create a sorted list of input signals */ + sorted_list = NULL; + node_delay = NIL(delay_node_t); + + fanin_count = node_num_fanin(node); + foreach_fanin(node, i, fanin) { + /* first get some storage for next input signal */ + new_member = ALLOC(pin_member_t, 1); + new_member->next = NULL; + new_member->source_node = fanin; + new_member->pin_number = i; + /* don't forget where the head is and other stuff... */ + if (sorted_list == NULL) { + sorted_list = new_member; + new_member->prev = NULL; + } + + if (new_member == sorted_list) { + node_delay = DELAY(new_member->source_node); + continue; + } + /* + * find the right place to put it + */ + current_member = sorted_list; /* start at the head */ + while(current_member != NULL) { + node_delay = DELAY(current_member->source_node); + fanin_delay = DELAY(fanin); + if(fanin_delay->arrival.rise >= node_delay->arrival.rise) { + if (current_member->next == NULL) { + current_member->next = new_member; + new_member->prev = current_member; + break; + } else { + next_node_delay = DELAY((current_member->next)->source_node); + if(fanin_delay->arrival.rise <= next_node_delay->arrival.rise) { + new_member->next = current_member->next; + (current_member->next)->prev = new_member; + current_member->next = new_member; + new_member->prev = current_member; + break; + } /* if (delay fanin < delay next member) */ + current_member = current_member->next; /* not this one */ + } + } else { /* smaller than the smallest */ + sorted_list->prev = new_member; + new_member->next = sorted_list; + sorted_list = new_member; + sorted_list->prev = NULL; + break; + } + } + } + + /* + * Input signals now sorted in sorted_list. Create the BDD so we can + * make up the groups. + * Since the sorted list in earliest to latest, and we want a BDD with + * the latest node at the top of the BDD, we need to stick the nodes + * in the leaves table in reverse order. + */ + + /* place the sorted list in a hash table for bdd construction */ + leaves = st_init_table(st_ptrcmp, st_ptrhash); + current_member = sorted_list; + while(current_member != NULL && current_member->next != NULL) current_member = current_member->next; + i = 0; + while(current_member != NULL) { + (void)st_insert(leaves, (char *)current_member->source_node, (char *)i); + current_member->pin_number = i; + i++; + last_pin = current_member; /* save this for later */ + current_member = current_member->prev; + } + + /* now create the BDD! */ + bdd_mgr = ntbdd_start_manager(st_count(leaves)); + my_bdd = ntbdd_node_to_bdd(node, bdd_mgr, leaves); /* Finally! */ + + /* We are currently doing the grouping based on a very simple hueristic: + Create a new group if the arrival time at the output of the tdc is + less than the arrival time of the signal in question. Otherwise, + keep it in the same group. + */ + /* + * Now we need to make up the groups. + * Put the first pin in first group, and all others in the second group. + */ + group_list_head = ALLOC(pin_group_t, 1); + group_list_head->next = NULL; + current_group = group_list_head; + current_group->prev = NULL; + current_member = sorted_list; + /* + * Put the first input pin in the first group + */ + if (current_member != NULL) { + current_group->group_size = 1; + current_group->first = current_member->pin_number; + current_group->last = current_member->pin_number; + current_group->latest_pin = current_member; + current_group->arr_est = 0; + current_group->total_slack = 0; + current_member = current_member->next; + group_count = 1; + } + + /* put all the other pins in the last group */ + if(current_member != NULL) { + new_group = ALLOC(pin_group_t, 1); + new_group->next = NULL; + new_group->prev = current_group; + new_group->group_size = fanin_count - 1; + if(current_member->next != NULL) { + new_group->first = current_member->next->pin_number; + } + else { + new_group->first = 0; + } + new_group->last = 0; + new_group->latest_pin = last_pin; + new_group->total_slack = 0; + new_group->arr_est = 0; + current_group->next = new_group; + group_count++; + } else { + new_group = NULL; + } + + /* Get the delays for these two groups to start with */ + current_group->group_delay = tdc_group_delay(my_bdd,current_group,info->options); + current_group->arr_est = (node_delay == NIL(delay_node_t) ? + DELAY_NOT_SET : node_delay->arrival.rise) + + current_group->group_delay; + if(new_group != NULL) { + new_group->group_delay = tdc_group_delay(my_bdd,new_group,info->options); + new_group->arr_est = node_delay->arrival.rise + new_group->group_delay; + } + + /* now start looping through the sorted input pins */ + while(current_member != NULL) { + node_delay = DELAY(current_member->source_node); + if (node_delay->arrival.rise > current_group->arr_est) { + /* + * create new group for signal + */ + new_group = ALLOC(pin_group_t, 1); + new_group->next = current_group->next; + current_group->next->prev = new_group; /* point the catchall group back */ + new_group->prev = current_group; + new_group->group_size = 1; + new_group->first = current_member->pin_number; + new_group->last = current_member->pin_number; + new_group->latest_pin = current_member; + new_group->total_slack = 0; + new_group->arr_est = 0; + current_group->next = new_group; + current_group = current_group->next; + group_count++; + /* + * move the new pin out of the catchall group + */ + current_group->next->first--; + + /* get delay for this new group */ + current_group->group_delay = tdc_group_delay(my_bdd,current_group,info->options); + current_group->arr_est = node_delay->arrival.rise + current_group->group_delay; + } else { + /* move the new pin out of the catchall group to this group */ + current_group->last = current_member->pin_number; + current_group->group_size++; + current_group->latest_pin = current_member; + current_group->next->first--; + + /* get delay for this new group */ + current_group->group_delay = tdc_group_delay(my_bdd,current_group,info->options); + current_group->arr_est = node_delay->arrival.rise + current_group->group_delay; + } + current_member = current_member->next; + } /* while(current_member) */ + + /* + * At this point, current_group->next should point to the empty + * catchall group. This needs to be removed + */ + FREE(current_group->next); + current_group->next = NULL; + group_count--; + + /* + * We want to loop through all the groups and get good arrival times + * and function line counts on everything + */ + current_group = group_list_head; + while(current_group != NULL) { + current_group->group_delay = tdc_group_delay(my_bdd,current_group,info->options); + current_group->arr_est = (node_delay == NIL(delay_node_t) ? + DELAY_NOT_SET : node_delay->arrival.rise) + + current_group->group_delay; + current_group = current_group->next; + } + + /* get the girdle width of each group */ +/* + if (2 == info->options) { + current_group = group_list_head; + while (current_group != NULL) { + current_group->girdle = girdle(my_bdd, current_group); + current_group = current_group->next; + } + } +*/ +#ifdef TDC_DEBUG + j = 1; + (void)fprintf(sisout, "Created %d groups for this node.\n",group_count); + current_group = group_list_head; + while (current_group != NULL) { + (void)fprintf(sisout, "Group %d\n",j); + j++; + (void)fprintf(sisout, "Select group size for this group: %d\n", + current_group->group_size); + (void)fprintf(sisout, " Starting pin for select group: %d\n", + current_group->first); + (void)fprintf(sisout, " Ending pin for select group: %d\n", + current_group->last); + (void)fprintf(sisout, "Function line count for this group: %d\n", + current_group->fct_count); + (void)fprintf(sisout, " Girdle width for this group: %d\n", + current_group->girdle); + (void)fprintf(sisout, "Delay for this group: %f\n", + current_group->group_delay); + current_member = current_group->latest_pin; + for(i=0; igroup_size; i++) { + node_delay = DELAY(current_member->source_node); + (void)fprintf(sisout, " Pin %s arrival time: %f\n", node_name(current_member->source_node), node_delay->arrival.rise); + current_member = current_member->prev; + } + current_group = current_group->next; + } +#endif + + /* OK, all done! */ + /* return the lists and bdd stuff to caller. */ + info->bdd_mgr = bdd_mgr; + info->my_bdd = my_bdd; + info->sorted_list = sorted_list; + info->group_list_head = group_list_head; + info->leaves = leaves; + + return; +} + +/* + * routine to convert bdd specified in info->my_bdd to a network of mux's + * as defined by the equivelence groups. + */ +static network_t * +tdc_bdd_to_network(info, network) +tdc_info_t *info; +network_t *network; +{ + int i, j, node_id; + char *pi_name; + lsGen node_gen; + st_generator *gen; + st_table *id2node_list, *visited, *leaves_bar; + node_t *node, *node_pi, *node_g, *node_f; + pin_group_t *current_group; + bdd_t *my_bdd; + bdd_node *bdd_reg; + + array_t *node_names, *node_array; + network_t *new_net; + +#ifdef TDC_DEBUG + printf("Source BDD\n"); + bdd_print(info->my_bdd); +#endif + + /* initialize stuff */ + node_names = array_alloc(char *, 0); + st_foreach_item_int(info->leaves, gen, (char **) &node, &node_id) { +#ifdef TDC_DEBUG + printf("node name %s is node number %d\n",node_name(node), node_id); +#endif + array_insert(char *, node_names, node_id, node_name(node)); + } + + new_net = ntbdd_bdd_single_to_network(info->my_bdd, "bdd_out", node_names); +/* now collapse groups together */ + current_group = info->group_list_head; + while(current_group != NULL && current_group->group_size > 0) { + for(i= current_group->last+1; i <= current_group->first; i++) { + pi_name = array_fetch(char *, node_names, i); + node_pi = network_find_node(new_net, pi_name); + foreach_fanout(node_pi, node_gen, node_g) { + if(node_num_fanout(node_g) > 0) { + node_f = node_get_fanout(node_g, 0); + } +#ifdef TDC_DEBUG + printf(" Collapse %s into %s \n",node_name(node_g),node_name(node_f)); +#endif + if(node_f != NULL) node_collapse(node_f, node_g); + } + } + current_group = current_group->next; + } + + network_sweep(new_net); +#ifdef TDC_DEBUG + node_array = network_dfs(new_net); + printf("Nodes in new BDD network\n"); + node_array = network_dfs(new_net); + for(i=0; igroup_list_head. If a node in the + BDD is reaced by an arc that comes from another group, an entry will + be made in the hash table. +*/ +static st_table * +tdc_bdd_node_list(info, my_bdd) +tdc_info_t *info; +bdd_t *my_bdd; +{ + int i, num_vars; + bdd_node *bdd_reg; + st_table *new_table, *visited; + pin_group_t *current_group; + + num_vars = st_count(info->leaves); + new_table = st_init_table(st_numcmp, st_numhash); + visited = st_init_table(st_ptrcmp, st_ptrhash); + + do_tdc_bdd_node_list(info, my_bdd, visited, new_table, -1); + + st_free_table(visited); + + return(new_table); +} + +static void +do_tdc_bdd_node_list(info, my_bdd, visited, new_table, parent_id) +tdc_info_t *info; +bdd_t *my_bdd; +st_table *visited; +st_table *new_table; +int parent_id; +{ + int dummy, bdd_node_id, parent_group_num, current_group_num, group_num; + bdd_t *then_bdd_node, *else_bdd_node; + bdd_node *bdd_reg; + array_t *curr_array; + pin_group_t *current_group; + boolean bdummy; + + bdd_reg = bdd_get_node(my_bdd, &bdummy); + if((!st_lookup(visited, (char *) bdd_reg, (char **) &dummy)) + && !(bdd_is_tautology(my_bdd, 1) || bdd_is_tautology(my_bdd, 0))) { + + bdd_node_id = bdd_top_var_id(my_bdd); + current_group = info->group_list_head; + parent_group_num = current_group_num = group_num = 0; + while(current_group != NULL) { + if((bdd_node_id <= current_group->first) + && (bdd_node_id >= current_group->last)) { + current_group_num = group_num; + } + if((parent_id <= current_group->first) + && (parent_id >= current_group->last)) { + parent_group_num = group_num; + } + group_num++; + current_group = current_group->next; + } + + if(current_group_num != parent_group_num) { + /* Add current node */ + if(st_lookup(new_table, (char *)bdd_node_id, (char **)&curr_array)){ + array_insert_last(bdd_t *, curr_array, my_bdd); + (void)st_insert(visited, (char *) bdd_reg, (char *) dummy); + } else { + curr_array = array_alloc(bdd_t *, 0); + array_insert_last(bdd_t *, curr_array, my_bdd); + (void)st_insert(new_table, (char *) bdd_node_id, (char *) curr_array); + (void)st_insert(visited, (char *) bdd_reg, (char *) dummy); + } + } + + /* get the children pointers and recurse on them */ + then_bdd_node = bdd_then(my_bdd); + else_bdd_node = bdd_else(my_bdd); + do_tdc_bdd_node_list(info, then_bdd_node, visited, new_table, bdd_node_id); + do_tdc_bdd_node_list(info, else_bdd_node, visited, new_table, bdd_node_id); + } + + return; +} + +/* + * NOTE: the routine assumes that "delay_set_tdc_params()" has been called + * before this routine to properly set the coefficients for the delay equations + */ +network_t * +tdc_factor_network(network) +network_t *network; +{ + char *name; + lsGen gen; + tdc_info_t *info; + node_t *curr_node, *new_node, *po, *pi, *new_pi, *new_po; + double val; + delay_time_t temp; + network_t *new_net; + + delay_trace(network, DELAY_MODEL_TDC); + + info = tdc_alloc_info( /* options */2); + po = network_get_po(network, 0); + curr_node = node_get_fanin(po, 0); + + tdc_sort_inputs(curr_node, info); + name = util_strsav(node_long_name(po)); + new_net = tdc_bdd_to_network(info, network); + new_node = network_get_po(new_net, 0); + network_change_node_name(new_net, new_node, name); + + /* + * Also update the delay information at the primary inputs and outputs + */ + val = delay_get_default_parameter(network, DELAY_WIRE_LOAD_SLOPE); + delay_set_default_parameter(new_net, DELAY_WIRE_LOAD_SLOPE, val); + + foreach_primary_input(network, gen, pi){ + new_pi = network_find_node(new_net, node_long_name(pi)); + if (new_pi != NIL(node_t)){ + if (delay_get_pi_arrival_time(pi, &temp)) { + delay_set_parameter(new_pi, DELAY_ARRIVAL_RISE, temp.rise); + delay_set_parameter(new_pi, DELAY_ARRIVAL_FALL, temp.fall); + } + if (delay_get_pi_drive(pi, &temp)) { + delay_set_parameter(new_pi, DELAY_DRIVE_RISE, temp.rise); + delay_set_parameter(new_pi, DELAY_DRIVE_FALL, temp.fall); + } + } + } + foreach_primary_output(network, gen, po){ + new_po = network_find_node(new_net, node_long_name(po)); + if (new_po != NIL(node_t)){ + if (delay_get_po_required_time(po, &temp)) { + delay_set_parameter(new_po, DELAY_REQUIRED_RISE, temp.rise); + delay_set_parameter(new_po, DELAY_REQUIRED_FALL, temp.fall); + } + if (delay_get_po_load(po, &(temp.rise))) { + delay_set_parameter(new_po, DELAY_OUTPUT_LOAD, temp.rise); + } + } + } + + tdc_free_info(info); + return(new_net); +} + +#undef TDC_MAXLINE diff --git a/sis/delay/tdc_int.h b/sis/delay/tdc_int.h new file mode 100644 index 0000000..e4fac95 --- /dev/null +++ b/sis/delay/tdc_int.h @@ -0,0 +1,53 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/delay/tdc_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:19 $ + * + */ +/* + * tdc model stuff. + */ + +/* tdc_util.c declares */ +extern int bdd_node_id(); +extern void delay_set_tdc_params(); + +/* Structures for tdc delay model */ +struct pin_member { + struct pin_member *prev; + node_t *source_node; + int pin_number; + struct pin_member *next; + } ; +typedef struct pin_member pin_member_t; + +struct pin_group { + struct pin_group *prev; + double delay_to_output, + group_delay, /* Delay for this multiplexer */ + total_slack, /* Slack contribution for this group */ + arr_est; /* Temporary estimate of arrival time */ + /* Use riseing edge */ + int fct_count, /* num. of function lines to next group */ + group_size, /* number of pins in group */ + first, /* ID of first group member */ + last, /* ID of last group member */ + /* IDs are the same as in leaves */ + girdle; /* Girdle width */ + struct pin_member *latest_pin; + struct pin_group *next; + } ; +typedef struct pin_group pin_group_t; + +struct tdc_info { + int options; /* Used to pass options around */ + pin_group_t *group_list_head; /* List of pin groups */ + pin_member_t *sorted_list;/* Sorted list of pins */ + bdd_manager *bdd_mgr; /* BDD manager */ + bdd_t *my_bdd; /* BDD for node indicated node */ + st_table *leaves; /* relates node to id number */ + }; +typedef struct tdc_info tdc_info_t; diff --git a/sis/doc/Makefile.am b/sis/doc/Makefile.am new file mode 100644 index 0000000..fca5548 --- /dev/null +++ b/sis/doc/Makefile.am @@ -0,0 +1,6 @@ +histdir = @SIS_HISTDIR@ + +dist_man5_MANS = slif.5 +dist_hist_DATA = blif.ps + +EXTRA_DIST = PROG README SPEC blif.aux blif.dvi blif.log blif.tex diff --git a/sis/doc/Makefile.in b/sis/doc/Makefile.in new file mode 100644 index 0000000..e334250 --- /dev/null +++ b/sis/doc/Makefile.in @@ -0,0 +1,365 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/doc +DIST_COMMON = README $(dist_hist_DATA) $(dist_man5_MANS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +man5dir = $(mandir)/man5 +am__installdirs = "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(histdir)" +NROFF = nroff +MANS = $(dist_man5_MANS) +dist_histDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_hist_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +histdir = @SIS_HISTDIR@ +dist_man5_MANS = slif.5 +dist_hist_DATA = blif.ps +EXTRA_DIST = PROG README SPEC blif.aux blif.dvi blif.log blif.tex +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/doc/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/doc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +install-man5: $(man5_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man5dir)" || $(mkdir_p) "$(DESTDIR)$(man5dir)" + @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 5*) ;; \ + *) ext='5' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \ + done +uninstall-man5: + @$(NORMAL_UNINSTALL) + @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 5*) ;; \ + *) ext='5' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man5dir)/$$inst"; \ + done +install-dist_histDATA: $(dist_hist_DATA) + @$(NORMAL_INSTALL) + test -z "$(histdir)" || $(mkdir_p) "$(DESTDIR)$(histdir)" + @list='$(dist_hist_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_histDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(histdir)/$$f'"; \ + $(dist_histDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(histdir)/$$f"; \ + done + +uninstall-dist_histDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_hist_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(histdir)/$$f'"; \ + rm -f "$(DESTDIR)$(histdir)/$$f"; \ + done +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(MANS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(histdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_histDATA install-man + +install-exec-am: + +install-info: install-info-am + +install-man: install-man5 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_histDATA uninstall-info-am uninstall-man + +uninstall-man: uninstall-man5 + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-dist_histDATA install-exec install-exec-am \ + install-info install-info-am install-man install-man5 \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-dist_histDATA uninstall-info-am uninstall-man \ + uninstall-man5 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/doc/PROG b/sis/doc/PROG new file mode 100644 index 0000000..48edcb7 --- /dev/null +++ b/sis/doc/PROG @@ -0,0 +1,286 @@ + Random thoughts on Programming in SIS + + Kanwar Jit Singh + +Here are some thoughts that stand out in terms of my experiences with +programming in SIS. In my opinion, SIS is a well designed piece of +software. However, there are some nuances and conventions that are +followed and so being aware of these, may help you avoid lot of time +trying to debug your code --- you'd rather be debugging algorithms than +the use of data structures. + + ********** Creation/deletion *************** + + Creation of a node simply creates a node_t structure and + populates the essential fields --- the function stored at the node + and the fanins that it depends on. As one might expect, a fanin + of the node (say A) does not recognize the created node (P) as a + valid fanout UNTIL P is explicitly added to the network (N) that + contains A. Thus observe + 1) It is illegal to add a node to a network if its fanins are not + part of the SAME network. + 2) If a node (P) is deleted from the network, all the fanins (A) + are able to record the fact that P is no longer a fanout of A. + However, all the fanouts of P will still think that P is a valid + fanin. Be careful ... + + Duplication of a node (N) simply creates a new node (say N1) that is + a copy of node N. Essential information (function and fanin-lists) are + copied and the fields that have deamons registered are also copied. In + addition the name of the duplicated node is the same as node N. Thus + 1) It is not possible to simply do + network_add_node(node_network(N), node_dup(N)); + to create a copy of the node N in the network. Doing this will mean + creating another node in the network with the same name. This is + NOT ALLOWED --- EVERY NODE IN THE NETWORK MUST HAVE A UNIQUE NAME. + You may choose not to assign it a name. In that case when a node is + added to the network it will be automatically assigned a "madeup" + name. "madeup" names are assigned only for nodes that have a NULL + entry in the name field. Thus you will have to FREE the "name" field + of the node N1 that has been created by duplication before it can be + added to the same network. + N1 = node_dup(N); FREE(N1->name); + network_add_node(node_network(N), N1); + NOTE: the utility macro FREE() has been used which calls the unix + routine free() and then sets the pointer being free to be NULL. + + 2) Remember, the duplicated node, while not part of any network, has + fanins that (possibly) reside in some network. Thus it cannot be + added to another network as it is. The fanin-pointers will have to + changed. This too is a HACK. The Exercise at the end will illustrate + this. + + Fanins of a node can be moved using the routine node_patch_fanin(). + However, since moving a fanin involved removing references from the + fanin node, the old_fanin and the new_fanin of node must be in the + same network as the node whose fanin is being moved. + + If a node belongs to a network then freeing it using node_free() + does not delete it from the network. The network will still have a + reference to the node and your program will crash if you attempt to + now free the network (which you should eventually do). On the other + hand network_free() will delete all the nodes from the network as + well as free all the node_t structures. Now this memory can be used by + other parts of the code. Clearly, if you have a node that has a fanin + in the network that is deleted, you may see garbage in that reference. + + ********** Naming Convention *************** + + The naming conventions in SIS are somewhat confusing. This is an + attempt to explain the philosophy behind the convention. If nothing + else, they might help you understand what is happening. The initial + convention (when only combinational logic was allowed) was to store the + name of a node that was driving a PO with the PO node. This was done so + that irrespective of how the network was optimized (as long as the PO + node was not destroyed) the name of the internal node driving the + output node could be recovered. Since the name of the internal node could + be arbitrarily changed a routine node_name() was provided that would + construct a name that would be meaningful to the user. Thus if internal + node X fed a primary output node Y with y->name = "foo", then + node_name(X) = "{foo}" = pointer to a static storage area + What that means is, that the routine node_name() constructs the string + "{foo}" in a statically allocated array and returns a pointer to that + storage. Thus multiple calls of node_name() may overwrite the storage. + Thus if X and Z feed different outputs, say "foo" and "bar", then the code + fragment + name1 = node_name(X); + name2 = node_name(Z); + fprintf(sisout, "%s and %s are outputs\n", name1, name2); + will produce as output + bar and bar are outputs. + Also, the routine node_name() concatenates the names of the outputs + if a node drives more than one output. Thus if node X drives PO nodes + with names "foo" and "bar" then node_name(X) will return the string + "{foo,bar}". Thus IT IS INACCEPTABLE TO USE THE VALUE RETURNED BY + node_name() TO HASH QUANTITIES OR EXPECT TO FIND NODES IN THE NETWORK + WITH THOSE NAMES. To overcome the the routine node_long_name() has + been provided which simply accesses the name field in the node_t + data structure. However, do not free this string unless you know + what you are doing (which is unlikely if you are reading this). + Things became more complicated when the decision to represented + latches as a pair of PI/PO nodes was taken. So, the idea was to + represent a D-flip/flop that was between nodes A and B as a pair of + nodes --- a primary-output node X that was a fanout on node A and a + primary-input node Y that was a fanin of node B. The pair of PI/PO nodes + was stored in a latch_t structure. Now, the question was "If node A + was also a true PO of the network, where should the name be stored --- at + the true PO or at the latch or the internal node ?". Since latches + and internal nodes can be destroyed/modified, it is easiest to store + the name with the true PO. However, when creating a latch, when the PO + is created the name would be transferred to the PO that was part of the + latch. To avoid this, a special routine "network_add_fake_primary_output()" + is provided which is to be used only to create dummy primary_output nodes + (PO nodes that are not circuit outputs but are added to represent latches + or to preserve nodes that act as control of latches). This routine does + not transfer the name from the internal node to the primary output. To + distinguish between different types of primary outputs the following + strategy should be used ---- + + if (network_is_real_po(network, node)) { + /* TRUE Primary output of the network --- one that appears as a + * formal terminal of this model + */ + } else if (network_is_control(network, node) != NIL(node_t)) { + /* "fake" PO node added to represent a latch */ + } else { + /* "fake" PO node added to preserve the functionality of the + * logic that is the "control" signal of a clock. To represent + * gated/inverted clocks */ + } + A similar strategy is used to isolate TRUE primary inputs (these include + the signals that have been declared as .clocks in the blif file) and + "dummy" primary inputs that simply represent the output terminal of + latches. In order to distinguish a "clock" input from a "data" input, + use the following code segment for nodes that are of type PRIMARY_INPUT + if (clock_get_by_name(network, node->name) != NIL(sis_clock_t)) { + /* "node" is a CLOCK input of the circuit */ + } + + ********** Generarators *************** + + Beware of what you do in the generator macros foreach_fanout() and + foreach_node() etc. These generators access lists and if you happen to + change the lists while generation you may see more than what you + bargained for. As an example consider this piece of code, which simply + deletes all inverters at the fanout of a node and adds new ones, a + contrived case, but instructional nevertheless. + + foreach_fanout(node, gen, fo) { + network_delete_node(network, fo); + network_add_node(network, node_literal(node, 0)); + } + This will loop forever. The reason being that the new inverter node + (created using the node_literal() command) gets added to the end of the + fanout_list of node. Thus it will be generated as part of the foreach_ + fanout macro. The proper way to do such a thing is to store all the fanouts + in a dynamic array and then traverse that array. Similarly, one has to be + careful about adding/deleting nodes to a network that is being traversed + by using a "foreach_node" macro. Deletion of nodes can be accomplished by + the routine network_delete_node_gen(). + + ********** On coding style *************** + Since SIS is a large piece of software with many packages, it is + important that you be aware of the architecture and its consequence on + programming style. Just a couple of things to keep in mind --- + 1) There is always a "current network" in SIS that is passed to every + routine that is registered using the com_add_command() procedure. When + invoked, you get a pointer to the network. Remember the double + indirection to the network_t data structure in the top level routine + that you use to interface with the interactive shell. Also, this + routine must never return a negative value --- this will cause the + interactive shell to terminate. + 2) Free all the memory that is allocated as part of the processing before + returning to the interactive shell. If you fail to do this, you may + needlessly cause subsequent operations to be slow due to swapping. + "Core leaks" --- memory that has been allocated and not freed --- can + be found by linking against a special library libc_mp.a and then + using the program "mprof" to produce an ascii listing of the leaks. + Currently (as of 2/3/93) the library resides in + /projects/local/local/mips/lib/libc_mp.a + and the mprof executable is + /projects/local/local/mips/bin/mprof + 3) When converting a routine that is called from the interactive shell to + an exported procedure, make sure that proper initializations have + been carried out. + 4) Always provide reasonable defaults for your code. + 5) If you have functions that need a lot of arguments, try to package + the arguments into a structure that gets passed from routine to + routine. This avoids having to change the function call and the + definition when the argument list needs to be expanded. Take a + look at the "map", "bdd", "speed" packages for the way the + structures bin_global_t, bdd_manager_t, speed_global_t are set-up + and used over and over. + 6) Comment your code with USEFUL comments that help the reader understand + what the code fragment does. + 7) Read the file /projects/octtools/octtools/common/doc/programmerGuide + for a standard and acceptable way of indenting code that is fairly + common throughout the CAD group. + + ********** Illustrative Example *************** + + Having said all this lets see how one will accomplish the following + task ---- + "Given a network and a list of nodes, construct a network that + contains only those nodes. Make PI/PO nodes appropriately" + + + /* Various declarations go here */ + new_net = network_alloc(); + corresp_table = st_init_table(st_ptrcmp, st_ptrhash); + /* + * duplicate the nodes and maintain corrspondence between the originbal + * node and its duplicate copy. Since the nodes are to be added into + * another network there will be no name conflicts. + */ + for (i = array_n(node_list); i-- > 0; ) { + node = array_fetch(node_t *, node_list, i); + dup_node = node_dup(node); + st_insert(corresp_table, (char *)node, (char *)dup_node); + } + /* + * Now start inserting the nodes. The order of inserting the nodes is + * important. We have to insert a node only after all its possible fanin + * nodes have been added. SO the BIG ASSUMPTION, is that the node_list + * has nodes in Depth-first-traversal from the inputs to the outputs. + * Notice that during duplication we can duplicate them in any order --- + * it is only the addition to a network that has to be done in this order. + */ + for (i = 0; i < array_n(node_list); i++) { + node = array_fetch(node_t *, node_list, i); + st_lookup(corresp_table, (char *)node, (char **)&dup_node); + foreach_fanin(dup_node, j, orig_in) { + if (st_lookup(corresp_table, (char *)orig_in, (char **)&new_in)){ + + } else { + /* + * "node" has a fanin that is not part of the list. We should + * simply connect that input to a primary input. Note that we + * might already have added a PI when processing another node + */ + new_in = network_find_node(new_net, node_long_name(orig_in)); + if (new_in == NIL(node_t)) { + new_in = node_alloc(); + network_add_primary_input(new_net, new_in); + network_change_node_name(new_net, new_in, + node_long_name(orig_in)); + } + } + /* + * At this stage new_in corresponds to a node in "new_net" that is + * supposed to be the "j"th fanin of dup_node. Unfortunately the + * only way to do this is to access the data-structure directly + */ + dup_node->fanin[j] = new_in; + } + /* + * Addition of the "dup_node" will result in also updating all the + * fanout pointers of its fanins, i.e. the fanins of "dup_node" will + * now recognize "dup_node" as a fanout + */ + network_add_node(new_net, dup_node); + } + /* + * Now all the nodes that do not fanout to any place are promoted + * to be primary outputs. + */ + foreach_node(new_net, gen, node) { + if (node_num_fanout(node) == 0) { + po_node = network_add_primary_output(new_net, node); + /* + * Remember --- The name that was stored with node->name is + * transferred to po->name and a new madeup name is assigned to + * node->name. So, if you want to merge this network "new_net" with + * the original network "network" --- do not expect to find the + * corresponding internal node as node->name. + * Use po_name->name instead. + */ + } + } + /* + Finally --- you might want to find out how you can + 1) Annotate the new_net with the default delay information of network + 2) Re-establish latch connections that might be part of node_list + 3) Set up the Clocks and Control nodes + 4) Rewrite the last part of adding PO's if there were some in the + node_list to start with + */ diff --git a/sis/doc/README b/sis/doc/README new file mode 100644 index 0000000..510ed74 --- /dev/null +++ b/sis/doc/README @@ -0,0 +1,87 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/doc/README,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +misII Packages -- + atpg -- generates test vectors + command -- command parser + decomp -- decomposition routines + delay -- delay evaluator + error -- simple error message builder + extract -- kernel- and cube- extraction + factor -- algebraic factoring + gcd -- factorization package + genlib -- parses genlib format for libraries + graphics-- plotting routines + library -- maniuplates specific cell libraries + map -- technology mapping (interface to come) + mincov -- weighted minimum cover package + minimize-- 2-level minimization of nodes + network -- manipulates Boolean network + node -- manipulates nodes in a network + ntbdd -- handles bdd structures, dependent on network + order -- handles bdd ordering routines + phase -- phase assignment + pld -- algorithms for synthesis of pld's + resub -- algebraic resubstitution + sim -- simulation (for verification) + simplify-- two-level minimization package (uses espresso) + speed -- speed resynthesis package + test -- basic test package + +SIS packages -- + astg -- asynchronous circuit synthesis + clock -- handle system clocks + graph -- general graph package + latch -- handles circuit latches + retime -- algorithms for retiming the network + seqbdd -- fsm verification using implicit state enumeration + stg -- uses the graph package for maintaining an stg + timing -- determines optimal clocking schemes + +general packages -- + array -- handles arrays of data structures + avl -- handles avl data structures + bdd -- handles bdd data structures, independent of network + espresso-- handles two-level minimization + list -- handles linked lists of data structures + maxflow -- algorithms for doing maxflow in a graph + sparse -- sparse matrix package + st -- hash table package + util -- package with various utilities for programming + +Packages with no exported functions: + io -- network input and output routines + main -- the main program driver + octio -- i/o for the oct data base + genlib -- library generator + lsort -- linked-list sorting routine (obsolete) + +Directories (which are not packages): + doc -- documentation (sym-links back to package directories) + ex -- examples directory + include -- include files (sym-links back to package directories) + lib -- libraries of compiled SIS code + sis_lib -- miscellaneous library information + +Files: + blif.tex -- TeX description of blif format + slif.1 -- man page for the SLIF (Stanford Logic Interchange + Format) I/O format + PROG -- SIS programming notes written by KJ Singh + SPEC -- description of specification for state assignment + and state minimization programs + +Note : Symbolic link for all files go to directory with the same name +except the following + + dagger.doc goes to graphics + graph_static.doc goes to graph + library.doc goes to map + nodeindex.doc goes to node + diff --git a/sis/doc/SPEC b/sis/doc/SPEC new file mode 100644 index 0000000..ca7bad7 --- /dev/null +++ b/sis/doc/SPEC @@ -0,0 +1,124 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/doc/SPEC,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +********************* state assignment program format ************* + +Format for State Assignment Programs to follow for incorporation in SIS: + +1) State Assignment Program Requirements + + - The input format is the enhanced KISS2 format (KISS2 with the + added construct .r symbolic name to indicate the reset state). + Input should be taken from stdin. + + - The output format is the enhanced BLIF format. Output should be + directed to stdout. The output information must contain the + resulting encoding (via the .code construct). A multi-level + network may be specified in the output BLIF, in which case the order + of the inputs (in the .inputs command) must correspond to the + order of the bits in the encoding. If no multi-level network is + specified, one is created using the state transition graph and + the encoding. + + - All options are specified on the command line. There is a package + available called the "options" package for making it easy for + the programmer to handle command-line options. The following + options are to be provided by each state assignment program: + + -e : with an argument, indicates the encoding algorithm to be used + -e h : indicates that a one-hot encoding is to be generated + -e r : indicates that random encoding is to be generated. + -n # : # indicates the number of random encodings that are + generated -- the best is selected. + -i : with an integer argument indicates the number of bits to + use in the symbolic input encoding + -s : with an integer argument indicates the number of bits to + use in the symbolic state encoding + -o : with an integer argument indicates the number of bits to + use in the symbolic state encoding + -h : returns a usage message (the options package returns a + usage message when optUsage() is called) + -v : verbose mode -- prints out information about the encoding + process. Information should be printed to stderr only. + + The -e option MUST be used to indicate the encoding algorithm + used. One-hot and random encodings don't have to be provided + by the state assignment program, but if they are, they must + be specified by -e h and -e r respectively. Similarly, the + number of encoding bits doesn't have to be an option to the + program, but if it is, it must be specified with -i for the input + bits, -s for the state bits, and -o for the output bits. + The -h option must be provided. + + - Any temporarily created files should be created in /tmp, not + in the current directory, since the user may not have write + permission in the current directory. There is command called + mktemp that can be used to obtain an unused temporary filename. + This package should be used to avoid naming a file the same + name as an existing file in /tmp. Any temporarily created + files should be removed immediately. An example follows: + + FILE *file; + char buffer[] = "/tmp/SISXXXXXX"; + + mktemp(buffer); + file = fopen(buffer, "w+"); + unlink(buffer); + + /* write information to the file */ + + fflush(file); + rewind(file); + fscanf(file, "%s", string); + fclose(file); + + This example creates a temporary file name with the mktemp + command, opens the file for both reading and writing, then + unlinks the file (which ensures that the file is removed even + if the program fails). The file is then read by first executing + fflush (which ensures that all buffered data that may not have + been written to the file yet is written), rewinding + the file pointer to the beginning of the file, and reading. + Finally, the file is closed when it is no longer needed. + + - A non-zero exit code should be returned if there is an error + during execution, and a 0 exit code returned if no error occurs. + The program must finish with a call to exit (rather than a call + to return). The program should return a non-zero exit code + whenever a valid network or STG is NOT written out (i.e. even + when, for example, the user gives an invalid option and no + computation is done). + + - The errors encountered by the program should be sent to stderr + rather than stdout. + + - Any programs the state assignment program calls (i.e. espresso) + should be documented in the manual page. The programs that are + called should be standard, released versions. Any calls to external + programs should not be hard-wired to a particular path in the + code (instead, a variable should be passed down from the top-level + Makefile to the code indicating a path in which to find the + program; or better, a system call should be used, assuming that + the program can be found in the user's path). + +2) General Requirements + + - All programs should be lint-free and contain a manual page + (.1 file). + + - The Makefile for the program should be compliant with the octtools + Makefiles. The program create-octtools-makefile can be used to + create a Makefile with the proper format. + +********************* state minimization program format ************* + +Format for State Minimization Programs to follow for incorporation in SIS: + +The format is the same as that for state assignment programs, except that +the output format is KISS2 for state minimization. diff --git a/sis/doc/blif.aux b/sis/doc/blif.aux new file mode 100644 index 0000000..1293897 --- /dev/null +++ b/sis/doc/blif.aux @@ -0,0 +1,11 @@ +\relax +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1}Models}{1}} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {2}Logic Gates}{2}} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {3}External Don't Cares}{3}} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {4}Flip flops and latches}{4}} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {5}Library Gates}{4}} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {6}Model (subcircuit) references}{6}} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {7}Subfile References}{6}} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {8}Finite State Machine Descriptions}{7}} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {9}Clock Constraints}{9}} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {10}Delay Constraints}{10}} diff --git a/sis/doc/blif.dvi b/sis/doc/blif.dvi new file mode 100644 index 0000000..e810b54 Binary files /dev/null and b/sis/doc/blif.dvi differ diff --git a/sis/doc/blif.log b/sis/doc/blif.log new file mode 100644 index 0000000..d6e989e --- /dev/null +++ b/sis/doc/blif.log @@ -0,0 +1,35 @@ +This is TeX, C Version 3.14t3 (format=lplain 92.7.6) 19 JAN 1994 10:48 +**blif.tex +(blif.tex +LaTeX Version 2.09 <25 March 1992> +(/usr/sww/lib/tex/inputs/article.sty +Standard Document Style `article' <14 Jan 92>. +(/usr/sww/lib/tex/inputs/art11.sty) +\c@part=\count79 +\c@section=\count80 +\c@subsection=\count81 +\c@subsubsection=\count82 +\c@paragraph=\count83 +\c@subparagraph=\count84 +\c@figure=\count85 +\c@table=\count86 +) (/usr/sww/lib/tex/inputs/fullpage.sty +Style Option FULLPAGE Version 2 as of 15 Dec 1988 +) (/usr/sww/lib/tex/inputs/times.sty (/usr/sww/lib/tex/inputs/psfonts.sty +\@cmrfam=\fam11 +\@cmrscale=\count87 +\aadimen=\dimen99 +)) +(blif.aux) [1 + +] [2] [3] [4] [5] [6] [7] [8] [9] [10] (blif.aux) ) +Here is how much of TeX's memory you used: + 263 strings out of 4456 + 2245 string characters out of 63158 + 33772 words of memory out of 262141 + 2180 multiletter control sequences out of 9500 + 36216 words of font info for 102 fonts, out of 72000 for 255 + 14 hyphenation exceptions out of 607 + 14i,7n,24p,157b,376s stack positions out of 300i,40n,60p,3000b,4000s + +Output written on blif.dvi (10 pages, 34752 bytes). diff --git a/sis/doc/blif.ps b/sis/doc/blif.ps new file mode 100644 index 0000000..1f799ce Binary files /dev/null and b/sis/doc/blif.ps differ diff --git a/sis/doc/blif.tex b/sis/doc/blif.tex new file mode 100644 index 0000000..1fc706a --- /dev/null +++ b/sis/doc/blif.tex @@ -0,0 +1,843 @@ +%/* +% * Revision Control Information +% * +% * $Source: /users/pchong/CVS/sis/sis/doc/blif.tex,v $ +% * $Author: pchong $ +% * $Revision: 1.1.1.1 $ +% * $Date: 2004/02/07 10:14:20 $ +% * +% */ +% Document Type: LaTeX +% Master File: blif.tex +% +% + + +\documentstyle[fullpage,times,11pt]{article} +\addtolength{\topmargin}{-13mm} +\addtolength{\textwidth}{10mm} +\addtolength{\textheight}{10mm} +\addtolength{\oddsidemargin}{-5mm} + + % define an environment .8 spacing (80% of single spacing) + \def\pespace{\def\baselinestretch{.8}\small} + \def\endpespace{} +%\fi + +\newcommand{\BLIF}{{\sc blif}} + +\newenvironment{code}% +{% + \begin{pespace}\nopagebreak[3]\begin{verbatim}% +}% +{% + \end{pespace}% +}% + +\title{ + Berkeley Logic Interchange Format (\BLIF ) +} + +\author{ + University of California\\ + Berkeley +} + +\begin{document} + +\maketitle + +The goal of \BLIF\ is to describe a logic-level hierarchical circuit in +textual form. A circuit is an arbitrary combinational or sequential network +of logic functions. A circuit can be viewed as a directed graph of +combinational logic nodes and sequential logic elements. Each node has a +two-level, single-output logic function associated with it. Each feedback +loop must contain at least one latch. Each net (or signal) has only a +single driver, and either the signal or the gate which drives the signal can +be named without ambiguity. + +In the following, angle-brackets surround nonterminals, and square-brackets +surround optional constructs. + +\section{Models} + +A model is a flattened hierarchical circuit. A \BLIF\ file can contain many +models and references to models described in other \BLIF\ files. A model is +declared as follows: +\begin{code} + .model + .inputs + .outputs + .clock + + . + . + . + + .end +\end{verbatim}\end{code} + +\begin{description} +\item {\em decl-model-name} is a string giving the name of the model. + +\item {\em decl-input-list} is a white-space-separated list of strings +(terminated by the end of the line) giving the formal input terminals for the +model being declared. If this is the first or only model, then these signals +can be identified as the primary inputs of the circuit. Multiple {\em +.inputs} lines are allowed, and the lists of inputs are concatenated. + +\item {\em decl-output-list} is a white-space-separated list of strings +(terminated by the end of the line) giving the formal output terminals for +the model being declared. If this is the first or only model, then these +signals can be identified as the primary outputs of the circuit. Multiple +{\em .outputs} lines are allowed, and the lists of outputs are concatenated. + +\item {\em decl-clock-list} is a white-space-separated list of strings +(terminated by the end of the line) giving the clocks for the model being +declared. Multiple {\em .clock} lines are allowed, and the lists of clocks +are concatenated. + +\item {\em command} is one of: +\begin{pespace}\nopagebreak[3]\begin{tabular} {l l l} +{\verb||} & {\verb||} & {\verb||} \\ +{\verb||} & {\verb||} & {\verb||} \\ +{\verb||} & {\verb||} +\end{tabular}\end{pespace} + +Each {\em command} is described in the following sections. +\end{description} + +The \BLIF\ parser allows the {\em .model, .inputs, .outputs, .clock} and +{\em .end} statements to be optional. If {\em .model} is not specified, the +{\em decl-model-name} is assigned the name of the \BLIF\ file being read. +It is an error to use the same string for {\em decl-model-name} in more than +one model. If {\em .inputs} is not specified, it can be inferred from the +signals which are not the outputs of any other logic block. Similarly, {\em +.outputs} can be inferred from the signals which are not the inputs to any +other blocks. If any {\em .inputs} or {\em .outputs} are given, no +inference is made; a node that is not an output and does not fanout produces +a warning message. + +If {\em .clock} is not specified (e.g., for purely combinational circuits) +there are no clocks. {\em .end} is implied at end of file or upon +encountering another {\em .model}. + +{\bf Important}: the first model encountered in the main \BLIF\ file is the +one returned to the user. The only {\em .clock, clock-constraint,} and {\em +timing-constraint} constructs retained are the ones in the first model. All +subsequent models can be incorporated into the first model using the {\em +model-reference} construct. + +Anywhere in the file a `{\verb|#|}' (hash) begins a comment that extends to +the end of the current line. +Note that the character `{\verb|#|}' cannot be used in any signal names. +A `\verb|\|' (backslash) as the last character +of a non-comment line indicates concatenation of the subsequent line to the +current line. No whitespace should follow the `\verb|\|'. + +Example: +\begin{code} + .model simple + .inputs a b + .outputs c + .names a b c # .names described later + 11 1 + .end + + + # unnamed model + .names a b \ + c # `\' here only to demonstrate its use + 11 1 +\end{verbatim}\end{code} + +Both models ``simple'' and the unnamed model describe the same circuit. + +\section{Logic Gates} + +A {\em logic-gate} associates a logic function with a signal in the model, +which can be used as an input to other logic functions. A {\em logic-gate} +is declared as follows: +\begin{code} + .names ... + +\end{verbatim}\end{code} + +\begin{description} +\item {\em output} is a string giving the name of the gate being defined. + +\item {\em in-1, in-2, ... in-n} are strings giving the names of the inputs +to the logic gate being defined. + +\item {\em single-output-cover} is, formally, an n-input, 1-output PLA +description of the logic function corresponding to the logic gate. \{0, 1, +--\} is used in the n-bit wide ``input plane'' and \{0, 1\} is used in +the 1-bit wide ``output plane''. The {\sc on}-set is specified with 1's in +the ``output plane,'' and the {\sc off}-set is specified with 0's in the +``output plane.'' +The {\sc dc}-set is specified for primary output nodes only, +by using the construct {\em .exdc}. +\end{description} + +A sample {\em logic-gate} with its {\em single-output-cover}: +\begin{code} + .names v3 v6 j u78 v13.15 + 1--0 1 + -1-1 1 + 0-11 1 +\end{verbatim}\end{code} + +In a given row of the {\em single-output-cover}, ``1'' means the input is +used in uncomplemented form, ``0'' means the input is complemented, and +``--'' means not used. Elements of a row are {\sc and}ed together, and then +all rows are {\sc or}ed. + +As a result, if the last column (the ``output plane'') of the {\em +single-output-cover} is all 1's, the first n columns (the ``input plane'') +of the {\em single-output-cover} can be viewed as the truth table for the +logic gate named by the string {\em output}. The order of the inputs in the +{\em single-output-cover} is the same as the order of the strings {\em in-1, +in-2, ..., in-n} in the {\em .names} line. A space between the columns of +the ``input plane'' and the ``output plane'' is required. + +The translation of the above sample {\em logic-gate} into a sum-of-products +notation would be as follows: +\begin{code} + v13.15 = (v3 u78') + (v6 u78) + (v3' j u78) +\end{verbatim}\end{code} +To assign the constant ``0'' to some logic gate {\verb|j|}, use the +following construct: +\begin{code} + .names j +\end{verbatim}\end{code} +To assign the constant ``1'', use the following: +\begin{code} + .names j + 1 +\end{verbatim}\end{code} + +The string {\em output} can be used as the input to another {\em logic-gate} +before the {\em logic-gate} for {\em output} is itself defined. + +For a more complete description of the PLA input format, see {\em +espresso(5)}. + +\section{External Don't Cares} + +External don't cares are specified as a separate network within +a model, and are specified at the end of the model specification. +Each external don't care function, which is specified by a {\em .names} +construct, must be associated with a primary +output of the main model and specified as a function +of the primary inputs of the main model (hierarchical specification +of external don't cares is currently not supported). + +The external don't cares are specified as follows: +\begin{code} + .exdc + .names ... + +\end{verbatim}\end{code} + +\begin{description} +\item {\.exdc} indicates that the following {\em .names} constructs +apply to the external don't care network. +\item {\em output} is a string giving the name of the primary output for +which the conditions are don't cares. + +\item {\em in-1, in-2, ... in-n} are strings giving the names of the primary +inputs which the don't care conditions are expressed in terms of. + +\item {\em single-output-cover} is an n-input, 1-output PLA +description of the logic function corresponding to the don't care +conditions for the output. +\end{description} + +The following is an example circuit with external don't cares: +\begin{code} + .model a + .inputs x y + .outputs j + .subckt b x=x y=y j=j + .exdc + .names x j + 1 1 + .end + + .model b + .inputs x y + .outputs j + .names x y j + 11 1 + .end +\end{verbatim}\end{code} + +The translation of the above example into a sum-of-products +notation would be as follows: +\begin{code} + j = x * y; + external d.c. for j = x; +\end{verbatim}\end{code} + +\section{Flip flops and latches} + +A {\em generic-latch} is used to create a delay element in a +model. It represents one bit of memory or state information. The {\em +generic-latch} construct can be used to create any type of latch or +flip-flop (see also the {\em library-gate} section). A {\em generic-latch} +is declared as follows: + +\begin{code} + .latch [ ] [] +\end{verbatim}\end{code} + +\begin{description} +\item {\em input} is the data input to the latch. + +\item {\em output} is the output of the latch. + +\item {\em type} is one of \{fe, re, ah, al, as\}, which correspond to +``falling edge,'' ``rising edge,'' ``active high,'' ``active low,'' or +``asynchronous.'' + +\item {\em control} is the clocking signal for the latch. It can be a {\em +.clock} of the model, the output of any function in the model, or the word +``NIL'' for no clock. + +\item {\em init-val} is the initial state of the latch, which can be one of +\{0, 1, 2, 3\}. ``2'' stands for ``don't care'' and ``3'' is ``unknown.'' +Unspecified, it is assumed ``3.'' +\end{description} + +If a latch does not have a controlling clock specified, it is assumed that +it is actually controlled by a single global clock. The behavior of this +global clock may be interpreted differently by the various algorithms that +may manipulate the model after the model has been read in. Therefore, the +user should be aware of these varying interpretations if latches are +specified with no controlling clocks. + +{\bf Important}: All feedback loops in a model must go through a {\em +generic-latch}. Purely combinational-logic cycles are not allowed. + +Examples: +\begin{code} + .inputs d # a clocked flip-flop + .output q + .clock c + .latch d q re c 0 + .end + + .inputs in # a very simple sequential circuit + .outputs out + .latch out in 0 + .names in out + 0 1 + .end +\end{verbatim}\end{code} + +\section{Library Gates} + +A {\em library-gate} creates an instance of a technology-dependent logic gate +and associates it with a node that represents the output of +the logic gate. The logic function of the +gate and its known technology dependent delays, drives, etc. are stored with +the {\em library-gate}. A {\em library-gate} is one of the following: + +\begin{code} + .gate + .mlatch [] +\end{verbatim}\end{code} + +\begin{description} +\item {\em name} is the name of the {\em .gate} or {\em .mlatch} to +instantiate. A gate or latch with this name must be present in the current +working library. + +\item {\em formal-actual-list} is a mapping between the formal parameters of +{\em name} (the terminals of the {\em library-gate}) and the actual +parameters of the current model (any signals in this model). The format for +a {\em formal-actual-list} is a white-space-separated sequence of assignment +statements of the form: + +\begin{code} +formal1=actual1 formal2=actual2 ... +\end{verbatim}\end{code} + +All of the formal parameters of {\em name} must be specified in the {\em +formal-actual-list} and the single output of {\em name} must be the last one +in the list. + +\item {\em control} is the clocking signal for the mlatch, which can be +either a {\em .clock} of the model, the output of any function in the model, +or the word ``NIL'' for no clock. + +\item {\em init-val} is the initial state of the mlatch, which can be one of +\{0, 1, 2, 3\}. ``2'' stands for ``don't care'' and ``3'' is ``unknown.'' +Unspecified, it is assumed ``3.'' +\end{description} + +A {\em .gate} refers to a two-level representation of an arbitrary input, +single output gate in a library. A {\em .gate} appears under a +technology-independent interpretation as if it were a single {\em +logic-gate}. + +A {\em .mlatch} refers to a latch (not necessarily a D flip flop) in a +library. A {\em .mlatch} appears under a technology-independent +interpretation as if it were a single {\em generic-latch} and possibly a +single {\em logic-gate} feeding the data input of that {\em generic-latch}. + +{\em .gate}s and {\em .mlatch}es are used to describe circuits that have been +implemented using a specific library of standard logic functions and their +technology-dependent properties. The library of {\em library-gate}s must be +read in before a \BLIF\ file containing {\em .gate} or {\em .mlatch} +constructs is read in. + +The string {\em name} refers to a particular gate or latch in the library. +The names ``nand2,'' +``inv,'' and ``jk\_rising\_edge'' in the following examples are +descriptive names for gates in the library. The following \BLIF\ +description: +\begin{code} + .inputs v1 v2 + .outputs j + .gate nand2 A=v1 B=v2 O=x # given: formals of this gate are A, B, O + .gate inv A=x O=j # given: formals of this gate are A & O + .end +\end{verbatim}\end{code} +could also be specified in a technology-independent way (assuming ``nand2'' +is a 2-input {\sc nand} gate and ``inv'' is an {\sc inverter}) as follows: +\begin{code} + .inputs v1 v2 + .outputs j + .names v1 v2 x + 0- 1 + -0 1 + .names x j + 0 1 + .end +\end{verbatim}\end{code} +Similarly: +\begin{code} + .inputs j kbar + .outputs out + .clock clk + .mlatch jk_rising_edge J=j K=k Q=q clk 1 # given: formals are J, K, Q + .names q out + 0 1 + .names kbar k + 0 1 + .end +\end{verbatim}\end{code} +could have been specified in a technology-independent way (assuming +``jk\_rising\_edge'' is a JK rising-edge-triggered flip flop) as follows: +\begin{code} + .inputs j kbar + .outputs out + .clock clk + .latch temp q re clk 1 # the .latch + .names j k q temp # the .names feeding the D input of the .latch + -01 1 + 1-0 1 + .names q out + 0 1 + .names kbar k + 0 1 + .end +\end{verbatim}\end{code} + +\section{Model (subcircuit) references} + +A {\em model-reference} is used to insert the logic functions of one model +into the body of another. It is defined as follows: +\begin{code} + .subckt +\end{verbatim}\end{code} + +\begin{description} +\item {\em model-name} is a string giving the name of the model being +inserted. It need not be previously defined in this file, but should be +defined somewhere in either this file, a {\em .search} file, or a master +file that is {\em .search}ing this file. (see {\em .search} below) + +\item {\em formal-actual-list} is a mapping between the formal terminals +(the {\em decl-input-list, decl-output-list,} and {\em decl-clock-list}) of +the called model {\em model-name} and the actual parameters of the current +model. The actual parameters may be any signals in the current model. The +format for a {\em formal-actual-list} is the same as its format in a {\em +library-gate}. +\end{description} + +A {\em .subckt} construct can be viewed as creating a copy of the logic +functions of the called model {\em model-name}, including all of {\em +model-name}'s {\em generic-latch}es, in the calling model. The hierarchical +nature of the \BLIF\ description of the model does not have to be +preserved. Subcircuits can be nested, but cannot be self-referential or +create a cyclic dependency. + +Unlike a {\em library-gate}, a {\em model-reference} is not limited to one +output. + +The formals need not be specified in the same order as they are defined in +the {\em decl-input-list, decl-output-list,} or {\em decl-clock-list}; +elements of the lists can be intermingled in any order, provided the names +are given correctly. Warning messages are printed if elements of the {\em +decl-input-list} or {\em decl-clock-list} are not driven by an actual +parameter or if elements of the {\em decl-output-list} do not fan out to an +actual parameter. Elements of the {\em decl-clock-list} and {\em +decl-input-list} may be driven by any logic function of the calling model. + +Example: rather than rewriting the entire \BLIF\ description for a commonly +used subcircuit several times, the subcircuit can be described once and +called as many times as necessary: +\begin{code} + .model 4bitadder + .inputs A3 A2 A1 A0 B3 B2 B1 B0 CIN + .outputs COUT S3 S2 S1 S0 + .subckt fulladder a=A0 b=B0 cin=CIN s=S0 cout=CARRY1 + .subckt fulladder a=A3 b=B3 cin=CARRY3 s=S3 cout=COUT + .subckt fulladder b=B1 a=A1 cin=CARRY1 s=XX cout=CARRY2 + .subckt fulladder a=JJ b=B2 cin=CARRY2 s=S2 cout=CARRY3 + # for the sake of example, + .names XX S1 # formal output `s' does not fanout to a primary output + 1 1 + .names A2 JJ # formal input `a' does not fanin from a primary input + 1 1 + .end + + .model fulladder + .inputs a b cin + .outputs s cout + .names a b k + 10 1 + 01 1 + .names k cin s + 10 1 + 01 1 + .names a b cin cout + 11- 1 + 1-1 1 + -11 1 + .end +\end{verbatim}\end{code} + +\section{Subfile References} +A {\em subfile-reference} is: +\begin{code} + .search +\end{verbatim}\end{code} + +\begin{description} +\item {\em file-name} gives the name of the file to search. +\end{description} + +A {\em subfile-reference} directs the \BLIF\ reader to read in and define +all the models in file {\em file-name}. A {\em subfile-reference} does not +have to be inside of a {\em .model}. {\em subfile-reference}s can be +nested. + +Search files would usually be used to hold all the subcircuits referred to +in {\em model-reference}s, while the master file merely searches all the +subfiles and instantiates all the subcircuits it needs. + +A {\em subfile-reference} is not equivalent to including the body of subfile +{\em file-name} in the current file. It does not patch fragments of \BLIF\ +into the current file; it pauses reading the current file, reads {\em +file-name} as an independent, self-contained file, then returns to reading +the current file. + +The first {\em .model} in the master file is always the one returned to the +user, regardless of any {\em subfile-reference}s than may precede it. + +\section{Finite State Machine Descriptions} + +A sequential circuit can be specified in \BLIF\ logic form, as a finite +state machine, or both. An {\em fsm-description} is used to insert a finite +state machine description of the current model. It is intended to represent +the same sequential circuit as the current model (which contains logic), but +in FSM form. The format of an {\em fsm-description} is: +\begin{code} + .start_kiss + .i + .o + [.p ] + [.s ] + [.r ] + + . + . + . + + .end_kiss + [.latch_order ] + [] +\end{verbatim}\end{code} + +\begin{description} +\item {\em num-inputs} is the number of inputs to the FSM, which should +agree with the number of inputs in the {\em .inputs} construct for the +current model. + +\item {\em num-outputs} is the number of outputs of the FSM, which should +agree with the number of outputs in the {\em .outputs} construct for the +current model. + +\item {\em num-terms} is the number of ``{\verb|<|}input{\verb|>|} +{\verb|<|}current-state{\verb|>|} {\verb|<|}next-state{\verb|>|} +{\verb|<|}output{\verb|>|}'' 4-tuples that follow in the FSM description. + +\item {\em num-states} is the number of distinct states that appear in +``{\verb|<|}current-state{\verb|>|}'' and ``{\verb|<|}next-state{\verb|>|}'' +columns. + +\item {\em reset-state} is the symbolic name for the reset state for the +FSM; it should appear somewhere in the ``{\verb|<|}current-state{\verb|>|}'' +column. + +\item {\em input} is a sequence of {\em num-inputs} members of \{0, 1, --\}. + +\item {\em output} is a sequence of {\em num-outputs} members of \{0, 1, --\}. + +\item {\em current-state} and {\em next-state} are symbolic names for the +current state and next state transitions of the FSM. + +\item {\em latch-order-list} is a white-space-separated sequence of latch +outputs. + +\item {\em code-mapping} is newline separated sequence of: +\begin{code} +.code +\end{verbatim}\end{code} +\end{description} + +{\em num-terms} and {\em num-states} do not have to be specified. If the +{\em reset-state} is not given, it is assigned to be the first state +encountered in the ``{\verb|<|}current-state{\verb|>|}'' column. + +The ordering of the bits in the {\em input} and {\em output} fields will be +the same as the ordering of the variables in the {\em .inputs} and {\em +.outputs} constructs if both an {\em fsm-description} and logic functions +are given. + +{\em latch-order-list} and {\em code-mapping} are meant to be used when both +an {\em fsm-description} and a logical description of the model are given. +The two constructs together provide a correspondence between the latches in +the logical description and the state variables in the {\em +fsm-description}. In a {\em code-mapping}, {\em symbolic-name} consists of +a symbolic name from the ``{\verb|<|}current-state{\verb|>|}'' or +``{\verb|<|}next-state{\verb|>|}'' columns, and {\em encoded-name} is the +pattern of bits (\{0, 1\}) that represent the state encoding for {\em +symbolic-name}. The {\em code-mapping} should only be given if both an {\em +fsm-description} and logic functions are given. {\em .latch-order} +establishes a mapping between the bits of the {\em encoded-name}s of the +{\em code-mapping} construct and the latches of the network. The order of +the bits in the encoded names will be the same as the order of the latch +outputs in the {\em latch-order-list}. There should be the same number of +bits in the {\em encoded-name} as there are latches if both an {\em +fsm-description} and a logical description are specified. + +If both {\em logic-gate}s and an {\em fsm-description} of the model are +given, the {\em logic-gate} description of the model should be consistent +with the {\em fsm-description}, that is, they should describe the same +circuit. If they are not consistent there will be no sensible way to +interpret the model, which should then cause an error to be returned. + +If only the {\em fsm-description} of the network is given, it may be run +through a state assignment routine and given a logic implementation. A sole +{\em fsm-description}, having no logic implementation, cannot be inserted +into another model by a {\em model-reference}; the state assigned network, +or a network containing both {\em logic-gate}s and an {\em fsm-description} +can. + +Example of an {\em fsm-description}: +\begin{code} + .model 101 # outputs 1 whenever last 3 inputs were 1, 0, 1 + .start_kiss + .i 1 + .o 1 + 0 st0 st0 0 + 1 st0 st1 0 + 0 st1 st2 0 + 1 st1 st1 0 + 0 st2 st0 0 + 1 st2 st3 1 + 0 st3 st2 0 + 1 st3 st1 0 + .end_kiss + .end +\end{verbatim}\end{code} +Above example with a consistent {\em fsm-description} and logical +description: +\begin{code} + .model + .inputs v0 + .outputs v3.2 + .latch [6] v1 0 + .latch [7] v2 0 + .start_kiss + .i 1 + .o 1 + .p 8 + .s 4 + .r st0 + 0 st0 st0 0 + 1 st0 st1 0 + 0 st1 st2 0 + 1 st1 st1 0 + 0 st2 st0 0 + 1 st2 st3 1 + 0 st3 st2 0 + 1 st3 st1 0 + .end_kiss + .latch_order v1 v2 + .code st0 00 + .code st1 11 + .code st2 01 + .code st3 10 + .names v0 [6] + 1 1 + .names v0 v1 v2 [7] + -1- 1 + 1-0 1 + .names v0 v1 v2 v3.2 + 101 1 + .end +\end{verbatim}\end{code} + +\section{Clock Constraints} + +A {\em clock-constraint} is used to set up the behavior of the simulated +clocks, and to specify how clock events (rising or falling edges) occur +relative to one another. A {\em clock-constraint} is one or more of the +following: +\begin{code} + .cycle + .clock_event [ ... ] +\end{verbatim}\end{code} + +\begin{description} +\item {\em cycle-time} is a floating point number giving the clock cycle +time for the model. It is a unitless number that is to be interpreted by +the user. + +\item {\em event-percent} is a floating point number representing a +percentage of the clock cycle time at which a specific {\em .clock\_event} +occurs. Fifty percent is written as ``50.0.'' + +\item {\em event-1} through {\em event-n} are one of the following: +\begin{code} +' +(' ) +\end{verbatim}\end{code} +where {\em rise-fall} is either ``r'' or ``f'' and stands for the rising or +falling edge of the clock and {\em clock-name} is a clock from the {\em +.clock} construct. The apostrophe between {\em rise-fall} and {\em +clock-name} is a seperator, and serves no purpose in and of itself. + +\item {\em before} and {\em after} are floating point numbers in the same +``units'' as the {\em cycle-time} and are used to define the ``skew'' in the +clock edges. {\em before} represents maximum amount of time before the +nominal time that the edge can arrive; {\em after} represents the maximum +amount of time after the nominal time that the edge can arrive. The nominal +time is {\em event-percent}{\verb|%|} of the {\em cycle-time}. In the +unparenthesized form for the {\em clock-event}, {\em before} and {\em after} +are assumed ``0.0.'' +\end{description} + +All events, {\em event-1 ... event-n}, specified in a single {\em +.clock\_event} are to be linked together. A routine changing any one edge +should also modify the occurrence time of all the related clock edges. + +Example 1: +\begin{code} + .clock clock1 clock2 + .clock_event 50.0 r'clock1 (f'clock2 2.0 5.0) +\end{verbatim}\end{code} + +Example 2: +\begin{code} + .clock clock1 clock2 + .clock_event 50.0 r'clock1 + .clock_event 50.0 (f'clock2 2.0 5.0) +\end{verbatim}\end{code} + +Both examples specify a nominal time of 50{\verb|%|} of the cycle time, that +the rising edge of clock1 must occur at exactly the nominal time, and that +the falling edge of clock2 may occur from 2.0 units before to 5.0 units +after the nominal time. + +In Example 1, if r'clock1 is later moved to a different nominal time by some +routine then f'clock2 should also be changed. However, in Example 2 changing +r'clock1 would not affect f'clock2 even though they originally have the same +value of {\em event-percent}. + +\section{Delay Constraints} + +A {\em delay-constraint} is used to specify parameters to more accurately +compute the amount of time signals take to propagate from one point to +another in a model. A {\em delay-constraint} is one or more of : +\begin{code} + .area + .delay + .wire_load_slope + .wire + .input_arrival [ ] + .default_input_arrival + .output_required [ ] + .default_output_required + .input_drive + .default_input_drive + .max_input_load + .default_max_input_load + .output_load + .default_output_load +\end{verbatim}\end{code} + +\begin{description} +\item {\em rise}, {\em fall}, {\em drive}, and {\em load} are all floating +point numbers giving the rise time, fall time, input drive, and output load. + +\item {\em in-name} is a primary input and {\em out-name} is a primary +output. + +\item {\em before-after} can be one of \{b, a\}, corresponding to ``before'' +or ``after,'' and {\em event} has the same format as the unparenthesized +form of {\em event-1} in a {\em clock-constraint}. + +\item {\em .area} sets the area of the model to be {\em area}. + +\item {\em .delay} sets the delay for input {\em in-name}. {\em phase} is +one of ``{\sc inv},'' ``{\sc noninv},'' or ``{\sc unknown}'' for inverting, +non-inverting, or neither. {\em max-load} is a floating point number for +the maximum load. {\em brise, drise, bfall,} and {\em dfall} are floating +point numbers giving the block rise, drive rise, block fall, and drive fall +for {\em in-name}. + +\item {\em .wire\_load\_slope} sets the wire load slope for the model. + +\item {\em .wire} sets the wire loads for the model from the list of floating +point numbers in the {\em wire-load-list}. + +\item {\em .input\_arrival} sets the input arrival time for the input {\em +in-name}. If the optional arguments are specified, then the input arrival +time is relative to the {\em event}. + +\item {\em .output\_required} sets the output required time for the output +{\em out-name}. If the optional arguments are specified, then the output +required time is relative to the {\em event}. + +\item {\em .input\_drive} sets the input drive for the input {\em in-name}. + +\item {\em .max\_input\_load} sets the maximum load that the input {\em in-name} can handle. + +\item {\em .output\_load} sets the output load for the output {\em out-name}. + +\item {\em .default\_input\_arrival, .default\_output\_required, +.default\_input\_drive, .default\_output\_load} set the corresponding default +values for all the inputs/outputs whose values are not specifically set. +\end{description} + +There is no actual unit for all the timing and load numbers. Special +attention should be given when specifying and interpreting the values. The +timing numbers are assumed to be in the same ``unit'' as the {\em +cycle-time} in the {\em .cycle} construct. +\end{document} diff --git a/sis/doc/slif.5 b/sis/doc/slif.5 new file mode 100644 index 0000000..fd88935 --- /dev/null +++ b/sis/doc/slif.5 @@ -0,0 +1,636 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/doc/slif.5,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1 $ +.\" * $Date: 2004/03/14 02:46:05 $ +.\" * +.\" +.TH SLIF 5CAD "5 August 1988" +.SH NAME +SLIF \- Stanford Logic Intermediate Format +.SH DESCRIPTION +.I SLIF +is a concise format used by tools in the +.I Stanford Synthesis Project +to describe logic circuits and their interconnections. +It is an hierarchical, non-procedural notation that is +described in ASCII files. +.SH SYNTAX +.I SLIF +is a free-format notation; i.e., statements may begin at any point on a +line, and whitespace may be used freely. Each statement must be terminated +by a semicolon. Statements may appear in any order within the description of +a model, with the restriction that inputs, outputs, inouts and types must +be declared before they are used and that the last statement in the model +description must be the +.I .endmodel +statement (see the COMMANDS section below for more details). +.PP +.B Identifiers +are character strings restricted to alphanumeric characters and the +following symbols: +.nf +.ti +15 +: ^ % [ ] _ . / ~ - +.fi +Variables, model names and instance names are all identifiers. +There are two special variables, "1" and "0", which represent the +logic values TRUE and FALSE, respectively. +.PP +.B Commands +in +.I SLIF +are command words preceded by a period (e.g., +.I .library). +and are summarized in the next +section. Any declaration that does not begin with a command is a +.B logic statement +and has the form +.nf +.ti +15 +.I var = expression ; +.fi +where +.I var +is an identifier and +.I expression +is an expression in Boolean form, consisting of variables and +.B operators. +The operators +.B +, * +and +.B ' +represent Boolean addition, multiplication and inversion (i.e., AND, OR and +NOT), respectively; the `*' operator is optional and may be omitted. e.g., +.nf +.ti +10 +out = reset' + clock * (in0' + (in1 * in2)) ; +is equivalent to +.ti +10 +out = reset' + clock (in0' + in1 in2) ; +.fi +An expression, like a literal, may be complemented using the prime (i.e., +apostrophe) symbol; e.g., +.ti +15 +x = (a (b + c)' + d)' ; +.PP +By default, the +.I expression +represents the +.I ON SET +of the variable +.I var. +Two symbols, +.B ' +and +.B ~ +are appended to +.I var +to indicate the +.I expression +is its +.I OFF SET +or +.I DON'T CARE SET +respectively. +The +.B ~ +can also be used in the +.I expression +to indicate the +.I DON'T CARE SET +of a variable. +Used alone, +.B ~ +means the global +.I DON'T CARE SET +of the surrounding model. + +.PP +There are two +.B built-in functions. +The arguments of these functions must be variables +(not expressions). The built-in functions are: +.TP +.B D(a,c,e) +A flow-through D-type latch, which has input +.I a, +is clocked by +.I c, +and is optionally enabled by signal +.I e. +.TP +.B T(a,b) +A tristate latch whose output is +.I a +when +.I b +is true, or high-impedance otherwise. +.PP +The use of a built-in function is indicated by the +.B `@' +symbol; e.g., +.nf +.ti +15 +out1 = @ D (sig1, clock') ; +.fi +In addition to built-in functions, library functions may be called; these +are defined as a separate model (see +.I .library +below). +.PP +.B Comments +are identified by the symbol `#'. This symbol indicates that the remainder +of the line is to be ignored by any program reading the +.I SLIF +description. +.SH COMMANDS +.TP +.BI .attribute " type_name variable_name parameters "; +Specifies parameters for one variable (or one instance), named +.I variable_name. +The parameters consist of a sequence of strings, integers and floats, +defined in the type +.I type_name. +If the type used allows for a variable number of parameters, the +corresponding list has to be enclosed in parentheses "(" and ")". +.TP +.BI .call " instance_name model_name ( inputs ; inouts ; outputs ) "; +Creates an instance +.I instance_name +of the +.I SLIF +model +.I model_name, +which may be described in the same file or in a file specified by a +.I .search +statement. The called model may be a library element. Variables are +linked according to the parameter listing; +.I inputs, inouts +and +.I outputs +are lists of variables separated by commas, which must agree in number and +order with those in the called model. +.TP +.BI .date " time_stamp "; +Specify the time of the last modification (optional). +The +.I time_stamp +format is +.I YYMMDDHHmmSS +where YY is the year, MM the month, DD the day, HH the hour, mm the minutes, +and SS the seconds. Each element of the +.I time_stamp +is a two-digit number. +.TP +.BI .endmodel " name "; +Terminates the model. Each model has to be terminated by this declaration. +There may be more than one model within the same file. +.TP +.BI .global_attribute " type_name parameters "; +Specifies parameters valid for an entire model. +.TP +.BI .include " file_name "; +Indicates that the information in +.I file_name +will be read as if it was part of the current file. +.TP +.BI .inouts " var1 var2 ... varn "; +Declares variables +.I var1 ... varn +as global bidirectional ``inouts.'' +.TP +.BI .inputs " var1 var2 ... varn "; +Declares variables +.I var1 ... varn +as global inputs. +.TP +.B .library ; +Identifies the model as a library element. +.TP +.BI .model " name "; +Indicates the beginning of a new model and assigns it name +.I name. +Each model has to be declared using this declaration. Multiple models +may be described in a single file. +.TP +.BI .net " var1 var2 ... varn "; +Lists variables that are connected together. The net will be named after one +of the variables. If there are global inputs, outputs or inouts then the net +will be inherit one of their names; otherwise it will be named after +.I var1. +.TP +.BI .outputs " var1 var2 ... varn "; +Declares variables +.I var1 ... varn +as global outputs. +.TP +.BI .search " file_name "; +Indicates that models included in +.I file_name +may be used, if they are needed. Users are encouraged to use the absolute +path to the file. +.TP +.BI .type " type_name spec1 spec2 ... specn "; +Declares a type +.I type_name +as a sequence of specifications +.I spec1 spec2 ... specn +where +.I spec +is any of +.I %d %f %s +(integer, float or string). A number may be used in front of a +.I spec, +to tell how many +.I specs +are to be used. +A +.I spec +or set of +.I specs +can also be included inside parentheses, to indicate +a variable number of that +.I spec +(or set of +.I specs +). +A type is used whenever a +.I .attribute +or +.I .global_attribute +command is used. The type defines all the information that follows +the type name. For +.I .attribute, +a string HAS to be inserted between the type name and the typed +information. This string indicates the variable (or instance) to +which the attribute will be attached. +.SH EXAMPLE +.sp +.nf +.cs R 22 +.B fileA: + + .model main ; # definition of model "main" + .inputs a b c d ; # inputs list + .outputs w x y z ; # outputs list + .inouts t ; # inouts list + .include fileC ; # fileC will be inserted here + .search fileB ; # fileB may contain needed + # models + .type FORMAT1 2 %s %d ; # type definition + .type FORMAT2 (%s (%f)); + .attribute FORMAT2 r (a (2.0)); # annotation of signal "r" + .attribute FORMAT1 inst0 z b 5 ; # annotation of instance "inst0" + q = a b ; r = a b' + a' b ; # logic equations + x = r' ; s = a' b' c' ; + y = d + d' (s + c q) ; + w = @ T (y, enable) ; # tristate latch + .net enable clock r ; # all 3 signals are the same net + .call inst0 OR2 (b, c; ; z) ; # OR-gate described externally + .call inst1 d_latch (c, clock; ;w); # D-latch described externally + .endmodel main ; # end definition (model "main") + +.B fileB: + + # Externally-called models. Calling model must have + # argument lists of correct size and in correct order. + .model d_latch ; + .inputs a b ; + .outputs t ; + t = @ D(a,b) ; # built-in function + .endmodel d_latch ; + + .model OR2; + .inputs x y; + .outputs z; + .library; # identifies as a library element + .endmodel OR2; + +.B fileC: + + # Information that will be inserted in model main + + .type FORMAT1 2 %s %d ; # types may be redefined if all + .type FORMAT2 (%s (%f)); # definitions are consistent + + .global_attribute FORMAT1 cap low 5; + .global_attribute FORMAT2 (min_res (3.0) typ_res (5.0 0.2)); + .global_attribute FORMAT2 (delay (0.1 0.3 1.0 2.1)); + +.cs R +.fi +.sp +.SH COMMENTS +.I SLIF +is an evolving format, and is subject to changes. Problems, comments +and suggestions should be addressed to mailhot@Mojave.Stanford.EDU. +.SH SEE ALSO +sliftools(5CAD), hercules(1CAD), minerva(1CAD), sliftooct(1CAD) + +.SH AUTHORS +.nf +Giovanni DeMicheli +Philip Johnson +David Ku +Frederic Mailhot +.fi +.TH SLIF 5CAD "5 August 1988" +.SH NAME +SLIF \- Stanford Logic Intermediate Format +.SH DESCRIPTION +.I SLIF +is a concise format used by tools in the +.I Stanford Synthesis Project +to describe logic circuits and their interconnections. +It is an hierarchical, non-procedural notation that is +described in ASCII files. +.SH SYNTAX +.I SLIF +is a free-format notation; i.e., statements may begin at any point on a +line, and whitespace may be used freely. Each statement must be terminated +by a semicolon. Statements may appear in any order within the description of +a model, with the restriction that inputs, outputs, inouts and types must +be declared before they are used and that the last statement in the model +description must be the +.I .endmodel +statement (see the COMMANDS section below for more details). +.PP +.B Identifiers +are character strings restricted to alphanumeric characters and the +following symbols: +.nf +.ti +15 +: ^ % [ ] _ . / ~ - +.fi +Variables, model names and instance names are all identifiers. +There are two special variables, "1" and "0", which represent the +logic values TRUE and FALSE, respectively. +.PP +.B Commands +in +.I SLIF +are command words preceded by a period (e.g., +.I .library). +and are summarized in the next +section. Any declaration that does not begin with a command is a +.B logic statement +and has the form +.nf +.ti +15 +.I var = expression ; +.fi +where +.I var +is an identifier and +.I expression +is an expression in Boolean form, consisting of variables and +.B operators. +The operators +.B +, * +and +.B ' +represent Boolean addition, multiplication and inversion (i.e., AND, OR and +NOT), respectively; the `*' operator is optional and may be omitted. e.g., +.nf +.ti +10 +out = reset' + clock * (in0' + (in1 * in2)) ; +is equivalent to +.ti +10 +out = reset' + clock (in0' + in1 in2) ; +.fi +An expression, like a literal, may be complemented using the prime (i.e., +apostrophe) symbol; e.g., +.ti +15 +x = (a (b + c)' + d)' ; +.PP +There are two +.B built-in functions. +The arguments of these functions must be variables +(not expressions). The built-in functions are: +.TP +.B D(a,c,e) +A flow-through D-type latch, which has input +.I a, +is clocked by +.I c, +and is optionally enabled by signal +.I e. +.TP +.B T(a,b) +A tristate latch whose output is +.I a +when +.I b +is true, or high-impedance otherwise. +.PP +The use of a built-in function is indicated by the +.B `@' +symbol; e.g., +.nf +.ti +15 +out1 = @ D (sig1, clock') ; +.fi +In addition to built-in functions, library functions may be called; these +are defined as a separate model (see +.I .library +below). +.PP +.B Comments +are identified by the symbol `#'. This symbol indicates that the remainder +of the line is to be ignored by any program reading the +.I SLIF +description. +.SH COMMANDS +.TP +.BI .attribute " type_name variable_name parameters "; +Specifies parameters for one variable (or one instance), named +.I variable_name. +The parameters consist of a sequence of strings, integers and floats, +defined in the type +.I type_name. +If the type used allows for a variable number of parameters, the +corresponding list has to be enclosed in parentheses "(" and ")". +.TP +.BI .call " instance_name model_name ( inputs ; inouts ; outputs ) "; +Creates an instance +.I instance_name +of the +.I SLIF +model +.I model_name, +which may be described in the same file or in a file specified by a +.I .search +statement. The called model may be a library element. Variables are +linked according to the parameter listing; +.I inputs, inouts +and +.I outputs +are lists of variables separated by commas, which must agree in number and +order with those in the called model. +.TP +.BI .date " time_stamp "; +Specify the time of the last modification (optional). +The +.I time_stamp +format is +.I YYMMDDHHmmSS +where YY is the year, MM the month, DD the day, HH the hour, mm the minutes, +and SS the seconds. Each element of the +.I time_stamp +is a two-digit number. +.TP +.BI .endmodel " name "; +Terminates the model. Each model has to be terminated by this declaration. +There may be more than one model within the same file. +.TP +.BI .global_attribute " type_name parameters "; +Specifies parameters valid for an entire model. +.TP +.BI .include " file_name "; +Indicates that the information in +.I file_name +will be read as if it was part of the current file. +.TP +.BI .inouts " var1 var2 ... varn "; +Declares variables +.I var1 ... varn +as global bidirectional ``inouts.'' +.TP +.BI .inputs " var1 var2 ... varn "; +Declares variables +.I var1 ... varn +as global inputs. +.TP +.B .library ; +Identifies the model as a library element. +.TP +.BI .model " name "; +Indicates the beginning of a new model and assigns it name +.I name. +Each model has to be declared using this declaration. Multiple models +may be described in a single file. +.TP +.BI .net " var1 var2 ... varn "; +Lists variables that are connected together. The net will be named after one +of the variables. If there are global inputs, outputs or inouts then the net +will be inherit one of their names; otherwise it will be named after +.I var1. +.TP +.BI .outputs " var1 var2 ... varn "; +Declares variables +.I var1 ... varn +as global outputs. +.TP +.BI .search " file_name "; +Indicates that models included in +.I file_name +may be used, if they are needed. Users are encouraged to use the absolute +path to the file. +.TP +.BI .type " type_name spec1 spec2 ... specn "; +Declares a type +.I type_name +as a sequence of specifications +.I spec1 spec2 ... specn +where +.I spec +is any of +.I %d %f %s +(integer, float or string). A number may be used in front of a +.I spec, +to tell how many +.I specs +are to be used. +A +.I spec +or set of +.I specs +can also be included inside parentheses, to indicate +a variable number of that +.I spec +(or set of +.I specs +). +A type is used whenever a +.I .attribute +or +.I .global_attribute +command is used. The type defines all the information that follows +the type name. For +.I .attribute, +a string HAS to be inserted between the type name and the typed +information. This string indicates the variable (or instance) to +which the attribute will be attached. +.SH EXAMPLE +.sp +.nf +.cs R 22 +.B fileA: + + .model main ; # definition of model "main" + .inputs a b c d ; # inputs list + .outputs w x y z ; # outputs list + .inouts t ; # inouts list + .include fileC ; # fileC will be inserted here + .search fileB ; # fileB may contain needed + # models + .type FORMAT1 2 %s %d ; # type definition + .type FORMAT2 (%s (%f)); + .attribute FORMAT2 r (a (2.0)); # annotation of signal "r" + .attribute FORMAT1 inst0 z b 5 ; # annotation of instance "inst0" + q = a b ; r = a b' + a' b ; # logic equations + x = r' ; s = a' b' c' ; + y = d + d' (s + c q) ; + w = @ T (y, enable) ; # tristate latch + .net enable clock r ; # all 3 signals are the same net + .call inst0 OR2 (b, c; ; z) ; # OR-gate described externally + .call inst1 d_latch (c, clock; ;w); # D-latch described externally + .endmodel main ; # end definition (model "main") + +.B fileB: + + # Externally-called models. Calling model must have + # argument lists of correct size and in correct order. + .model d_latch ; + .inputs a b ; + .outputs t ; + t = @ D(a,b) ; # built-in function + .endmodel d_latch ; + + .model OR2; + .inputs x y; + .outputs z; + .library; # identifies as a library element + .endmodel OR2; + +.B fileC: + + # Information that will be inserted in model main + + .type FORMAT1 2 %s %d ; # types may be redefined if all + .type FORMAT2 (%s (%f)); # definitions are consistent + + .global_attribute FORMAT1 cap low 5; + .global_attribute FORMAT2 (min_res (3.0) typ_res (5.0 0.2)); + .global_attribute FORMAT2 (delay (0.1 0.3 1.0 2.1)); + +.cs R +.fi +.sp +.SH COMMENTS +.I SLIF +is an evolving format, and is subject to changes. Problems, comments +and suggestions should be addressed to mailhot@Mojave.Stanford.EDU. +.SH SEE ALSO +sliftools(5CAD), hercules(1CAD), minerva(1CAD), sliftooct(1CAD) + +.SH AUTHORS +.nf +Giovanni DeMicheli +Philip Johnson +David Ku +Frederic Mailhot +.fi diff --git a/sis/enc/Makefile.am b/sis/enc/Makefile.am new file mode 100644 index 0000000..438d521 --- /dev/null +++ b/sis/enc/Makefile.am @@ -0,0 +1,10 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libenc.a +libenc_a_SOURCES = com_enc.c dic.c dic_to_sm.c gen_eqn.c input.c \ + enc_int.h +pkginclude_HEADERS = enc.h +dist_doc_DATA = enc.doc + +EXTRA_DIST = interface.c diff --git a/sis/enc/Makefile.in b/sis/enc/Makefile.in new file mode 100644 index 0000000..5484ca8 --- /dev/null +++ b/sis/enc/Makefile.in @@ -0,0 +1,422 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libenc_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/enc +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libenc_a_AR = $(AR) $(ARFLAGS) +libenc_a_LIBADD = +am_libenc_a_OBJECTS = com_enc.$(OBJEXT) dic.$(OBJEXT) \ + dic_to_sm.$(OBJEXT) gen_eqn.$(OBJEXT) input.$(OBJEXT) +libenc_a_OBJECTS = $(am_libenc_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libenc_a_SOURCES) +DIST_SOURCES = $(libenc_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libenc.a +libenc_a_SOURCES = com_enc.c dic.c dic_to_sm.c gen_eqn.c input.c \ + enc_int.h + +pkginclude_HEADERS = enc.h +dist_doc_DATA = enc.doc +EXTRA_DIST = interface.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/enc/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/enc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libenc.a: $(libenc_a_OBJECTS) $(libenc_a_DEPENDENCIES) + -rm -f libenc.a + $(libenc_a_AR) libenc.a $(libenc_a_OBJECTS) $(libenc_a_LIBADD) + $(RANLIB) libenc.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/enc/com_enc.c b/sis/enc/com_enc.c new file mode 100644 index 0000000..4138d37 --- /dev/null +++ b/sis/enc/com_enc.c @@ -0,0 +1,37 @@ +#include "sis.h" +#include "enc_int.h" + +#define EQN 5 +#define ITER 6 + +static void infeasible_cnt(); + +bool enc_debug = 0; + + +static void +infeasible_cnt(list, bound) +dic_family_t *list; +int bound; +{ + pset lastp, p; + int less, cnt1, cnt2, i, base; + unsigned int val; + + less = 0; + lastp = list->dic + list->dcount * list->dic_size; + for (p = list->dic; p < lastp; p += list->dic_size) { + cnt1 = 0; + cnt2 = 0; + foreach_set_element(lhs_dic(p), i, val, base) { + cnt1 ++; + } + foreach_set_element(rhs_dic(p), i, val, base) { + cnt2 ++; + } + if (cnt1 > bound || cnt2 > bound) { + less ++; + } + } + (void) fprintf(sisout, "Reduce list by %-1d\n", less); +} diff --git a/sis/enc/dic.c b/sis/enc/dic.c new file mode 100644 index 0000000..9a974e4 --- /dev/null +++ b/sis/enc/dic.c @@ -0,0 +1,246 @@ +#include "sis.h" +#include "enc_int.h" + +dic_family_t * +dic_family_alloc(num, nelem) +int nelem; +{ + dic_family_t *A; + int setsize; + + setsize = SET_SIZE(nelem); + A = ALLOC(dic_family_t, 1); + A->dcapacity = num; + A->dcount = 0; + A->dic_size = 2 * setsize; + A->dset_elem = nelem; + A->dset_size = setsize; + A->dic = ALLOC(unsigned int, num * A->dic_size); + return A; +} + +void +dic_family_free(D) +dic_family_t *D; +{ + (void) dic_free(D->dic); + (void) FREE(D); +} + +dic_family_t * +dic_family_copy(D) +dic_family_t *D; +{ + dic_family_t *A; + pset p, s, last; + + A = ALLOC(dic_family_t, 1); + A->dcapacity = D->dcapacity; + A->dcount = D->dcount; + A->dic_size = D->dic_size; + A->dset_elem = D->dset_elem; + A->dset_size = D->dset_size; + A->dic = ALLOC(unsigned int, A->dcapacity * A->dic_size); + last = D->dic + D->dic_size * D->dcount; + for (p = D->dic, s = A->dic; p < last; p ++, s ++) { + *s = *p; + } + return A; +} + +void +dic_family_print(D) +dic_family_t *D; +{ + pset p, last; + + if (D->dcount == 0) + return; + last = D->dic + D->dcount * D->dic_size; + for (p = D->dic; p < last; p += D->dic_size) { + (void) dic_print(p, D->dset_elem); + } + return; +} + +/* add a dichotomy to a dichotomy family */ +void +dic_family_add(A, s) +dic_family_t *A; +pset s; +{ + pset p; + + if (A->dcount >= A->dcapacity) { + A->dcapacity = A->dcapacity + A->dcapacity/2 + 1; + A->dic = REALLOC(unsigned int, A->dic, A->dcapacity*A->dic_size); + } + p = GETDIC(A, A->dcount++); + INLINEset_copy(lhs_dic(p), lhs_dic(s)); + INLINEset_copy(rhs_dic(p), rhs_dic(s)); +} + +/* add a dichotomy to a dichotomy family if it doesn't exist */ +void +dic_family_add_contain(A, s) +dic_family_t *A; +pset s; +{ + pset p; + int i; + + /* do not add if it already exists */ + for (i = 0; i < A->dcount; i ++) { + if (dicp_equal(s, GETDIC(A, i))) { + return; + } + } + + if (A->dcount >= A->dcapacity) { + A->dcapacity = A->dcapacity + A->dcapacity/2 + 1; + A->dic = REALLOC(unsigned int, A->dic, A->dcapacity*A->dic_size); + } + p = GETDIC(A, A->dcount++); + INLINEset_copy(lhs_dic(p), lhs_dic(s)); + INLINEset_copy(rhs_dic(p), rhs_dic(s)); +} + +/* add a dichotomy to a dichotomy family if it isn't implied */ +void +dic_family_add_irred(A, s) +dic_family_t *A; +pset s; +{ + pset p; + int i; + + /* do not add if it already exists */ + for (i = 0; i < A->dcount; i ++) { + p = GETDIC(A, i); + if (dicp_implies(s, p)) { + return; + } + else if (dicp_implies(p, s)) { + set_copy(lhs_dic(p), lhs_dic(s)); + set_copy(rhs_dic(p), rhs_dic(s)); + return; + } + } + + if (A->dcount >= A->dcapacity) { + A->dcapacity = A->dcapacity + A->dcapacity/2 + 1; + A->dic = REALLOC(unsigned int, A->dic, A->dcapacity*A->dic_size); + } + p = GETDIC(A, A->dcount++); + INLINEset_copy(lhs_dic(p), lhs_dic(s)); + INLINEset_copy(rhs_dic(p), rhs_dic(s)); +} + +pset +dic_new(nelem) +int nelem; +{ + pset p; + int setsize, i; + + setsize = SET_SIZE(nelem); + p = ALLOC(unsigned int, 2 * setsize); + i = 2 * setsize - 1; + do { + p[i] = 0; + } + while(--i >= 0); + *p = setsize - 1; + *(p + setsize) = setsize - 1; + return p; +} + +void +dic_free(dic) +pset dic; +{ + FREE(dic); +} + +void +dic_print(dic, nelem) +pset dic; +int nelem; +{ + fprintf(sisout, "%s;", pbv1(lhs_dic(dic), nelem)); + fprintf(sisout, "%s\n", pbv1(rhs_dic(dic), nelem)); +} + +bool +is_prime(dic, nelem) +pset dic; +int nelem; +{ + pset d; + bool flag; + + d = dic_new(nelem); + (void) set_or(lhs_dic(d), lhs_dic(dic), rhs_dic(dic)); + flag = setp_full(lhs_dic(d), nelem); + (void) dic_free(d); + return flag; +} + +/* is p1 contained in p2 */ +bool +dicp_implies(p1, p2) +pset p1; +pset p2; +{ + return(setp_implies(lhs_dic(p1), lhs_dic(p2)) && + setp_implies(rhs_dic(p1), rhs_dic(p2))); +} + +/* is p1 contained in p2 in either direction */ +bool +dicp_covers(p1, p2) +pset p1; +pset p2; +{ + return((setp_implies(lhs_dic(p1), lhs_dic(p2)) && + setp_implies(rhs_dic(p1), rhs_dic(p2))) || + (setp_implies(lhs_dic(p1), rhs_dic(p2)) && + setp_implies(rhs_dic(p1), lhs_dic(p2)))); +} + +bool +dicp_equal(p1, p2) +pset p1; +pset p2; +{ + return(setp_equal(lhs_dic(p1), lhs_dic(p2)) && + setp_equal(rhs_dic(p1), rhs_dic(p2))); +} + +dic_family_t * +dic_cross_product(dlist1, dlist2) +dic_family_t *dlist1; +dic_family_t *dlist2; +{ + dic_family_t *new; + pset lastp1, lastp2, p1, p2, merge; + int n; + + n = dlist1->dset_elem; + new = dic_family_alloc(ALLOCSIZE, n); + lastp1 = dlist1->dic + dlist1->dcount * dlist1->dic_size; + lastp2 = dlist2->dic + dlist2->dcount * dlist2->dic_size; + for (p1 = dlist1->dic; p1 < lastp1; p1 += dlist1->dic_size) { + for (p2 = dlist2->dic; p2 < lastp2; p2 += dlist2->dic_size) { + /* + if ((merge = dic_merge(p1, p2)) != NULL) { + if (is_feasible(merge)) { + (void) dic_family_add(new, merge); + (void) dic_free(merge); + } + } + */ + } + } + return new; +} diff --git a/sis/enc/dic_to_sm.c b/sis/enc/dic_to_sm.c new file mode 100644 index 0000000..f189977 --- /dev/null +++ b/sis/enc/dic_to_sm.c @@ -0,0 +1,56 @@ +#include "sis.h" +#include "enc_int.h" + +sm_matrix * +dic_to_sm(prime_list, seed_list) +dic_family_t *prime_list; +dic_family_t *seed_list; +{ + sm_matrix *M; + sm_col *col; + pset p, lastp, s, lasts; + int r, c; + bool insert; + + M = sm_alloc(); + lastp = prime_list->dic + prime_list->dcount * prime_list->dic_size; + lasts = seed_list->dic + seed_list->dcount * seed_list->dic_size; + + for(p = prime_list->dic, c = 0; p < lastp; + p += prime_list->dic_size, c ++) { + insert = FALSE; + for(s = seed_list->dic, r =0; s < lasts; + s += seed_list->dic_size, r ++) { + if(dicp_covers(s, p)) { + (void) sm_insert(M, r, c); + insert = TRUE; + } + } + if(insert) { + col = sm_get_col(M, c); + (void) sm_put(col, (char *) p); + } + } + return M; +} + +void +print_min_cover(M, cover, prime_list) +sm_matrix *M; +sm_row *cover; +dic_family_t *prime_list; +{ + sm_col *col; + sm_element *p; + pset d; + int n; + + n = prime_list->dset_elem; + fprintf(sisout, "\nMinimum cover is \n"); + sm_foreach_row_element(cover, p) { + col = sm_get_col(M, p->col_num); + d = sm_get(pset, col); + (void) fprintf(sisout, "%s ; ", pbv1(lhs_dic(d), n)); + (void) fprintf(sisout, "%s\n", pbv1(rhs_dic(d), n)); + } +} diff --git a/sis/enc/enc.doc b/sis/enc/enc.doc new file mode 100644 index 0000000..6f5319c --- /dev/null +++ b/sis/enc/enc.doc @@ -0,0 +1,13 @@ +Alex Saldanha's Exact Dichotomy Solver: + +(a,b | c,d) +Input Format: +input: 1100- + +-> program automatically generates seed dichotomies +a | c, d +b | c, d ... + +misII> _test -d (debug) -r (don't remove vars) -e (exact) input_file + + diff --git a/sis/enc/enc.h b/sis/enc/enc.h new file mode 100644 index 0000000..17dcd69 --- /dev/null +++ b/sis/enc/enc.h @@ -0,0 +1,32 @@ +#define ALLOCSIZE 500 +#define LIMIT 5000 + +/* each dichotomy is a contatenation of two sets - one for the lhs and + * one for the rhs */ +typedef struct dic_family { + int dcapacity; /* total number of dichotomies */ + int dcount; /* number of dichotomies */ + int dic_size; /* size of a dic in ints */ + int dset_elem; /* number of elements in each set of the dic */ + int dset_size; /* size of a set in ints - dic size is twice this */ + pset dic; /* pointer to first dichotomy */ +} dic_family_t; + +typedef struct cnf { + int var1; /* first variable */ + int var2; /* second variable */ +} cnf_t; + +#define lhs_dic(dic) (dic) +#define rhs_dic(dic) ((dic)+LOOPCOPY(dic)+1) + +#define GETDIC(family, index) ((family)->dic + (family)->dic_size*index) + +#define MERGE1 1 +#define MERGE2 2 +extern pset dic_new (); +extern dic_family_t *dic_family_alloc (); +extern dic_family_t *gen_uniq(); +extern dic_family_t *gen_eqn(); +extern sm_matrix *dic_to_sm(); +extern dic_family_t *reduce_seeds(); diff --git a/sis/enc/enc_int.h b/sis/enc/enc_int.h new file mode 100644 index 0000000..7f10840 --- /dev/null +++ b/sis/enc/enc_int.h @@ -0,0 +1,18 @@ +#define SOP_ALLOC 100 + +extern void input_cons (); +extern int filter_cons (); +extern int read_cons (); +extern dic_family_t *gen_iter (); +extern void dic_family_free (); +extern dic_family_t *dic_family_copy (); +extern void dic_family_print (); +extern void dic_family_add (); +extern void dic_family_add_contain (); +extern void dic_family_add_irred (); +extern void dic_free (); +extern void dic_print (); +extern bool is_prime (); +extern bool dicp_implies (); +extern bool dicp_equal (); +extern void print_min_cover(); diff --git a/sis/enc/gen_eqn.c b/sis/enc/gen_eqn.c new file mode 100644 index 0000000..2a4438b --- /dev/null +++ b/sis/enc/gen_eqn.c @@ -0,0 +1,305 @@ +#include "sis.h" +#include "enc_int.h" + +extern bool enc_debug; + +static void cnf_array_free(); +static pset_family cnf_expand(); +static int cnf_split(); +static pset_family cnf_merge(); +static bool special_cases(); +static dic_family_t *cnf_to_prime(); + +/* prime generation by generating a CNF form and using the URP to + * obtain a SOP */ +dic_family_t * +gen_eqn(dic_list, climit) +dic_family_t *dic_list; +int climit; +{ + pset_family eqn_cov; + array_t *eqn_arr; + cnf_t *cnf; + pset p1, p2; + int n, i, j, *count; + bool f1, f2; + + eqn_arr = array_alloc(cnf_t *, ALLOCSIZE); + n = dic_list->dcount; + /* set up count of variables */ + count = ALLOC(int, n); + for (i = 0; i < n; i ++) { + count[i] = 0; + } + for (i = 0; i < n; i ++) { + p1 = GETDIC(dic_list, i); + for (j = i + 1; j < n; j ++) { + p2 = GETDIC(dic_list, j); + + f1 = setp_disjoint(lhs_dic(p1), rhs_dic(p2)); + f2 = setp_disjoint(rhs_dic(p1), lhs_dic(p2)); + + /* cannot merge these two dichotomies */ + if (!f1 || !f2) { + cnf = ALLOC(cnf_t, 1); + cnf->var1 = i; + cnf->var2 = j; + count[i] ++; + count[j] ++; + (void) array_insert_last(cnf_t *, eqn_arr, cnf); + } + } + } + +/* + (void) fprintf(sisout, "There are %-1d pairwise incompatibilities\n", + array_n(eqn_arr)); +*/ + + /* now apply URP to cnf_arr to get an SOP form */ + eqn_cov = cnf_expand(eqn_arr, count, n, climit); + FREE(count); + + /* interpret cover to obtain list of prime dichotomies */ +/* + (void) fprintf(sisout, "\nFinal cover size is %d\n", eqn_cov->count); +*/ + return cnf_to_prime(dic_list, eqn_cov, n); +} + +static pset_family +cnf_expand(cnf_arr, count, vars, limit) +array_t *cnf_arr; +int *count; +int vars; +int limit; +{ + pset_family cov1, sop_cov; + pset tmp, rhs_prod; + array_t *lhs_arr; + cnf_t *cnf; + int n, split_var; + + /* + if (enc_debug) { + (void) fprintf(sisout, "cnf_expand:\n"); + for (n = 0 ; n < array_n(cnf_arr); n ++) { + cnf = array_fetch(cnf_t *, cnf_arr, n); + (void) fprintf(sisout, "(%-1d + %-1d)", cnf->var1, cnf->var2); + } + (void) fprintf(sisout, "\n"); + } + */ + n = array_n(cnf_arr); + if (n == 0) { + (void) cnf_array_free(cnf_arr); + sop_cov = sf_new(1, vars); + tmp = set_new(vars); + sop_cov = sf_addset(sop_cov, tmp); + set_free(tmp); + return sop_cov; + } + + /* now apply URP */ + if (!special_cases(n, count, vars, &sop_cov)) { + /* do a split and recur */ + split_var = cnf_split(cnf_arr, count, vars, &lhs_arr, &rhs_prod); + (void) cnf_array_free(cnf_arr); + /* + if (enc_debug) { + (void) fprintf(sisout, "split = %-1d\n", split_var); + } + */ + cov1 = cnf_expand(lhs_arr, count, vars, limit); + sop_cov = cnf_merge(vars, split_var, rhs_prod, cov1); + set_free(rhs_prod); + sf_free(cov1); + } + else { + (void) cnf_array_free(cnf_arr); + } + if (enc_debug) { + (void) fprintf(sisout, " %-1d", sop_cov->count); + (void) fflush(sisout); + /* (void) sf_bm_print(sop_cov); */ + } + if (sop_cov->count >= limit) { + (void) fprintf(sisout, "Cover size exceeded\n"); + exit(0); + } + return sop_cov; +} + +/* free the cnf forms and then the array of pointers */ +static void +cnf_array_free(cnf_arr) +array_t *cnf_arr; +{ + cnf_t *cnf; + int n, i; + + n = array_n(cnf_arr); + for (i = 0; i < n; i ++) { + cnf = array_fetch(cnf_t *, cnf_arr, i); + FREE(cnf); + } + array_free(cnf_arr); +} + +/* choose a splitting variable and compute the left and right hand branches + * of the tree. also update the variables that get multiplied on the right + * hand side. the splitting variable is returned by the function */ +static int +cnf_split(cnf_arr, count, vars, lhs_arr, rhs_prod) +array_t *cnf_arr; +int *count; +int vars; +array_t **lhs_arr; +pset *rhs_prod; +{ + cnf_t *cnf, *cnf_l; + int n, i, max, max_i; + + /* find most frequently occurring variable */ + max = -1; + for (i = 0; i < vars; i ++) { + if (count[i] > max) { + max = count[i]; + max_i = i; + } + } + + *lhs_arr = array_alloc(cnf_t *, 0); + *rhs_prod = set_new(vars); + n = array_n(cnf_arr); + for (i = 0; i < n; i ++) { + cnf = array_fetch(cnf_t *, cnf_arr, i); + if (cnf->var1 == max_i) { + count[max_i] --; + count[cnf->var2] --; + (void) set_insert((*rhs_prod), cnf->var2); + } + else if (cnf->var2 == max_i) { + count[max_i] --; + count[cnf->var1] --; + (void) set_insert((*rhs_prod), cnf->var1); + } + else { + cnf_l = ALLOC(cnf_t, 1); + cnf_l->var1 = cnf->var1; + cnf_l->var2 = cnf->var2; + (void) array_insert_last(cnf_t *, *lhs_arr, cnf_l); + } + } + return max_i; +} + +/* merge the left and right covers - some check for merging with redundancy + * removal. merging with single cube containment is done */ +static pset_family +cnf_merge(vars, split_var, rhs_prod, cov_l) +int vars; +int split_var; +pset rhs_prod; +pset_family cov_l; +{ + pset_family sop; + pset last, p, tmp; + bool rem_contain; + + sop = sf_save(cov_l); + + /* cofactor - or rhs_prod elements */ + rem_contain = FALSE; + foreach_set(sop, last, p) { + + /* set flag if rhs_prod is contained by any set */ + if (setp_implies(p, rhs_prod)) { + rem_contain = TRUE; + sf_free(sop); + sop = sf_new(cov_l->count, vars); + sop = sf_addset(sop, rhs_prod); + break; + } + set_or(p, p, rhs_prod); + } + if (!rem_contain) { + sop = sf_rev_contain(sop); + } + + /* add lhs side */ + tmp = set_new(vars); + foreach_set(cov_l, last, p) { + if (setp_implies(rhs_prod, p)) { + continue; + } + set_copy(tmp, p); + set_insert(tmp, split_var); + sop = sf_addset(sop, tmp); + } + set_free(tmp); + return sop; +} + +static bool +special_cases(n_terms, count, vars, sop) +int n_terms; +int *count; +int vars; +pset_family *sop; +{ + pset tmp; + int i, j; + + for (i = 0; i < vars; i ++) { + if (count[i] == n_terms) { + *sop = sf_new(2, vars); + tmp = set_new(vars); + set_insert(tmp, i); + *sop = sf_addset(*sop, tmp); + set_clear(tmp, vars); + for (j = 0; j < vars; j ++) { + if ((count[j] != 0) && (j != i)) { + set_insert(tmp, j); + } + } + *sop = sf_addset(*sop, tmp); + set_free(tmp); + return TRUE; + } + } + return FALSE; +} + +static dic_family_t * +cnf_to_prime(dic_list, cov, n) +dic_family_t *dic_list; +pcover cov; +int n; +{ + dic_family_t *new; + pset full, dic, d, last, p, pcomp; + int i, base; + unsigned int val; + + new = dic_family_alloc(n, dic_list->dset_elem); + full = set_full(cov->sf_size); + pcomp = set_new(cov->sf_size); + dic = dic_new(dic_list->dset_elem); + foreach_set(cov, last, p) { + (void) set_clear(lhs_dic(dic), dic_list->dset_elem); + (void) set_clear(rhs_dic(dic), dic_list->dset_elem); + (void) set_xor(pcomp, full, p); + foreach_set_element(pcomp, i, val, base) { + d = GETDIC(dic_list, base); + (void) set_or(lhs_dic(dic), lhs_dic(dic), lhs_dic(d)); + (void) set_or(rhs_dic(dic), rhs_dic(dic), rhs_dic(d)); + } + (void) dic_family_add(new, dic); + } + set_free(full); + set_free(pcomp); + dic_free(dic); + sf_free(cov); + return new; +} diff --git a/sis/enc/input.c b/sis/enc/input.c new file mode 100644 index 0000000..8348752 --- /dev/null +++ b/sis/enc/input.c @@ -0,0 +1,317 @@ +#include "sis.h" +#include "enc_int.h" + +#define MAXLINE 256 + +/* remove those state variables that do not play any role */ +int +filter_cons(file1, file2) +char *file1; +char *file2; +{ + FILE *fp, *fpout; + char *line, *symbols; + int iter, i, n; + bool *used; + + line = ALLOC(char, MAXLINE+1); + symbols = ALLOC(char, MAXLINE+1); + iter = 1; + + if ((fp = fopen(file1, "r")) == NULL) { + (void) fprintf(siserr, "unable to open constraint file %s\n", file1); + return FALSE; + } + + while(fgets(line, MAXLINE, fp) != NIL(char)) { + + if (strlen(line) >= MAXLINE) { + (void) fprintf(siserr, + "WARNING: Line too long to handle currently : ignored\n"); + continue; + } + + /* pick up mv_constraint */ + if (sscanf(line, "input: %s\n", symbols) == 1) { + if (iter == 1) { + n = strlen(symbols); + used = ALLOC(bool, n); + for (i = 0; i < n; i ++) { + used[i] = FALSE; + } + } + else if (n != strlen(symbols)) { + (void) fprintf(siserr, + "Varying mv-constraint length : aborting\n"); + exit(-1); + } + + for (i = 0; i < n; i ++) { + if (symbols[i] == '1') { + used[i] = TRUE; + } + else if (symbols[i] == '-') { + } + else if (symbols[i] != '0') { + (void) fprintf(siserr, + "ERROR: incorrect mv-constraint %s : aborting\n", + symbols); + exit(-1); + } + } + } + iter ++; + } + + fclose(fp); + if ((fp = fopen(file1, "r")) == NULL) { + (void) fprintf(siserr, "unable to open constraint file %s\n", file1); + return FALSE; + } + if ((fpout = fopen(file2, "w")) == NULL) { + (void) fprintf(siserr, "unable to write constraints file %s\n", file2); + return FALSE; + } + + /* rewrite output file without unused state variables */ + while(fgets(line, MAXLINE, fp) != NIL(char)) { + + /* pick up mv_constraint */ + if (sscanf(line, "input: %s\n", symbols) == 1) { + (void) fprintf(fpout, "input: "); + for (i = 0; i < n; i ++) { + if (used[i]) { + (void) fprintf(fpout, "%c", symbols[i]); + } + } + (void) fprintf(fpout, "\n"); + } + } + + fclose(fp); + fclose(fpout); + if (iter != 1) { + FREE(used); + } + FREE(line); + FREE(symbols); + return TRUE; +} + +/* form seed dichotomies from mv-constraints */ +int +read_cons(file, dic_list) +char *file; +dic_family_t **dic_list; +{ + FILE *fp; + dic_family_t *list; + pset lhs_set, dic; + char *line, *symbols, *rhs; + int iter, i, n; + + line = ALLOC(char, MAXLINE+1); + symbols = ALLOC(char, MAXLINE+1); + rhs = ALLOC(char, MAXLINE+1); + *dic_list = NIL(dic_family_t); + iter = 1; + + if ((fp = fopen(file, "r")) == NULL) { + (void) fprintf(siserr, "unable to open constraint file %s\n", file); + return FALSE; + } + + while(fgets(line, MAXLINE, fp) != NIL(char)) { + + if (strlen(line) >= MAXLINE) { + (void) fprintf(siserr, + "WARNING: Line too long to handle currently : ignored\n"); + continue; + } + + /* pick up mv_constraint */ + if (sscanf(line, "input: %s\n", symbols) == 1) { + if (iter == 1) { + n = strlen(symbols); + list = dic_family_alloc(ALLOCSIZE, n); + } + else if (n != strlen(symbols)) { + (void) fprintf(siserr, + "Varying mv-constraint length : aborting\n"); + exit(-1); + } + + lhs_set = set_new(n); + for (i = 0; i < n; i ++) { + if (symbols[i] == '1') { + rhs[i] = 0; + (void) set_insert(lhs_set, i); + } + else if (symbols[i] == '-') { + rhs[i] = 0; + } + else if (symbols[i] == '0') { + rhs[i] = 1; + } + else { + (void) fprintf(siserr, + "ERROR: incorrect mv-constraint %s : aborting\n", + symbols); + exit(-1); + } + } + + /* now get seed dichotomies and form set data structure */ + for (i = 0; i < n; i ++) { + if (rhs[i] == 1) { + /* add new dichotomy */ + dic = dic_new(n); + (void) set_copy(lhs_dic(dic), lhs_set); + (void) set_insert(rhs_dic(dic), i); + (void) dic_family_add_irred(list, dic); + (void) set_clear(lhs_dic(dic), n); + (void) set_copy(rhs_dic(dic), lhs_set); + (void) set_insert(lhs_dic(dic), i); + (void) dic_family_add_irred(list, dic); + (void) dic_free(dic); + } + } + (void) set_free(lhs_set); + iter ++; + } + } + + FREE(line); + FREE(symbols); + FREE(rhs); + fclose(fp); + + *dic_list = list; + return TRUE; +} + +dic_family_t * +gen_uniq(list) +dic_family_t *list; +{ + dic_family_t *new; + pset lastp, p, p1, p2, dic; + int n, i, j, base1, base2; + unsigned int val1, val2; + bool **implied; + + n = list->dset_elem; + new = dic_family_copy(list); + implied = ALLOC(bool *, n); + for (i = 0; i < n; i ++) { + implied[i] = ALLOC(bool, n); + for (j = 0; j < n; j ++) { + implied[i][j] = FALSE; + } + } + lastp = list->dic + list->dcount * list->dic_size; + for (p = list->dic; p < lastp; p += list->dic_size) { + p1 = lhs_dic(p); + p2 = rhs_dic(p); + foreach_set_element(p1, i, val1, base1) { + foreach_set_element(p2, j, val2, base2) { + if (base1 < base2) { + implied[base1][base2] = TRUE; + } + else { + implied[base2][base1] = TRUE; + } + } + } + } + dic = dic_new(n); + for (i = 0; i < n; i ++) { + for (j = i + 1; j < n; j ++) { + if (!implied[i][j]) { + (void) set_clear(lhs_dic(dic), n); + (void) set_clear(rhs_dic(dic), n); + (void) set_insert(lhs_dic(dic), i); + (void) set_insert(rhs_dic(dic), j); + (void) dic_family_add(new, dic); + (void) set_clear(lhs_dic(dic), n); + (void) set_clear(rhs_dic(dic), n); + (void) set_insert(lhs_dic(dic), j); + (void) set_insert(rhs_dic(dic), i); + (void) dic_family_add(new, dic); + } + } + } + dic_free(dic); + for (i = 0; i < n; i ++) { + FREE(implied[i]); + } + FREE(implied); + return new; +} + +dic_family_t * +reduce_seeds(list) +dic_family_t *list; +{ + dic_family_t *new1, *new2; + pset lastp, p, cp; + int n, k, *cnt, max, max_i, i; + + /* first remove implied seeds */ + lastp = list->dic + list->dcount * list->dic_size; + for (p = list->dic; p < lastp; p += list->dic_size) { + SET(p, ACTIVE); + } + k = 0; + for (p = list->dic; p < lastp; p += list->dic_size) { + if (TESTP(p, ACTIVE)) { + for (cp = p + list->dic_size; cp < lastp; cp += list->dic_size) { + if (dicp_implies(cp, p)) { + RESET(cp, ACTIVE); + k ++; + } + } + } + } + n = list->dset_elem; + new1 = dic_family_alloc(list->dcount - k, n); + for (p = list->dic; p < lastp; p += list->dic_size) { + if (TESTP(p, ACTIVE)) { + (void) dic_family_add(new1, p); + } + } + + /* anchor most frequent state at origin */ + cnt = ALLOC(int, n); + for (i = 0; i < n; i ++) { + cnt[i] = 0; + } + lastp = new1->dic + new1->dcount * new1->dic_size; + for (p = new1->dic; p < lastp; p += new1->dic_size) { + for (i = 0; i < n; i ++) { + if (is_in_set(p, i)) { + cnt[i] ++; + } + } + } + max = cnt[0]; + max_i = 0; + for (i = 1; i < n; i++) { + if (cnt[i] > max) { + max = cnt[i]; + max_i = i; + } + } + new2 = dic_family_alloc(max, n); + + /* retain all seeds either without max_i or in correct lhs or rhs set */ + lastp = new1->dic + new1->dcount * new1->dic_size; + for (p = new1->dic; p < lastp; p += new1->dic_size) { + if (!is_in_set(lhs_dic(p), max_i)) { + (void) dic_family_add(new2, p); + } + } + FREE(cnt); + (void) dic_family_free(new1); + return new2; +} diff --git a/sis/enc/interface.c b/sis/enc/interface.c new file mode 100644 index 0000000..b799969 --- /dev/null +++ b/sis/enc/interface.c @@ -0,0 +1,85 @@ +#include "sis.h" +#include "enc_int.h" + +extern bool enc_debug; + +/* ARGSUSED */ +int +com_enc_sat(cons, nsymb, codes) +cons_t **cons; +int nsymb; +char ***codes; +{ + dic_family_t *seed_list, *dic_list, *prime_list, *uncover_list; + dic_family_t *filter_list, *satisfy_list, *temp_list1; + sm_matrix *table; + sm_row *cover; + bool **dom_closure; + int i, code_length; + + long start_time, elapse_time, util_cpu_time(); + + enc_debug = FALSE; + + start_time = util_cpu_time(); + dom_closure = transitive_closure(cons, nsymb); + for (i = 0; i < nsymb; i ++) { + if (dom_closure[i][i]) { + free_closure(dom_closure, nsymb); + return 0; + } + } + + (void) read_cons(nsymb + 1, nsymb, cons, &seed_list); + if ((seed_list == NIL(dic_family_t)) || (seed_list->dcount == 0)) { + (void) fprintf(stdout, "No constraints\n"); + } + + dic_list = reduce_seeds(gen_uniq(seed_list)); + (void) dic_family_free(seed_list); + temp_list1 = pre_filter_dic(dom_closure, dic_list, cons); + if (enc_debug) { + fprintf(stdout, "Raised seeds are\n"); + dic_family_print(temp_list1); + fprintf(stdout, "END Raised seeds are\n"); + } + filter_list = reduce_seeds(temp_list1); + if (enc_debug) { + fprintf(stdout, "Reduced seeds are\n"); + dic_family_print(filter_list); + } + prime_list = gen_eqn(filter_list, LIMIT); + (void) dic_family_free(filter_list); + satisfy_list = filter_dic(dom_closure, prime_list, cons); + free_closure(dom_closure, nsymb); + (void) dic_family_free(prime_list); + printf("===***===Valid primes are %d\n", satisfy_list->dcount); + + uncover_list = dic_to_sm(&table, satisfy_list, dic_list); + if (uncover_list->dcount != 0) { + if (enc_debug) { + (void) fprintf(stdout, "uncovered seeds are:\n"); + (void) dic_family_print(uncover_list); + (void) fprintf(stdout, "face constraints not satisfiable\n"); + } + (void) dic_family_free(dic_list); + (void) dic_family_free(satisfy_list); + (void) dic_family_free(uncover_list); + sm_free(table); + return 0; + } + + cover = sm_minimum_cover(table, NIL(int), 1 /* heuristic */, 0); + code_length = cover->length; + *codes = derive_codes(table, cover, nsymb); + + (void) dic_family_free(uncover_list); + (void) dic_family_free(dic_list); + (void) dic_family_free(satisfy_list); + sm_row_free(cover); + sm_free(table); + elapse_time = util_cpu_time() - start_time; + printf("===***===Encoding time %s\n", util_print_time(elapse_time)); + return code_length; +} + diff --git a/sis/error/Makefile.am b/sis/error/Makefile.am new file mode 100644 index 0000000..444beae --- /dev/null +++ b/sis/error/Makefile.am @@ -0,0 +1,7 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = liberror.a +liberror_a_SOURCES = error.c +pkginclude_HEADERS = error.h +dist_doc_DATA = error.doc diff --git a/sis/error/Makefile.in b/sis/error/Makefile.in new file mode 100644 index 0000000..c2fa0c4 --- /dev/null +++ b/sis/error/Makefile.in @@ -0,0 +1,418 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(liberror_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/error +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +liberror_a_AR = $(AR) $(ARFLAGS) +liberror_a_LIBADD = +am_liberror_a_OBJECTS = error.$(OBJEXT) +liberror_a_OBJECTS = $(am_liberror_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(liberror_a_SOURCES) +DIST_SOURCES = $(liberror_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = liberror.a +liberror_a_SOURCES = error.c +pkginclude_HEADERS = error.h +dist_doc_DATA = error.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/error/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/error/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +liberror.a: $(liberror_a_OBJECTS) $(liberror_a_DEPENDENCIES) + -rm -f liberror.a + $(liberror_a_AR) liberror.a $(liberror_a_OBJECTS) $(liberror_a_LIBADD) + $(RANLIB) liberror.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/error/error.c b/sis/error/error.c new file mode 100644 index 0000000..7baa811 --- /dev/null +++ b/sis/error/error.c @@ -0,0 +1,59 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/error/error.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +#include "sis.h" + +static char *error_str = 0; +static int error_str_len, error_str_maxlen; + + +void +error_init() +{ + if (error_str != 0) { + FREE(error_str); + } + error_str_len = 0; + error_str_maxlen = 100; + error_str = ALLOC(char, error_str_maxlen); + *error_str = '\0'; +} + + +void +error_append(s) +char *s; +{ + int slen; + + slen = strlen(s); + if (error_str_len + slen + 1 > error_str_maxlen) { + error_str_maxlen = (error_str_len + slen) * 2; /* cstevens@ic */ + error_str = REALLOC(char, error_str, error_str_maxlen); + } + (void) strcpy(error_str + error_str_len, s); + error_str_len += slen; +} + + +char * +error_string() +{ + return error_str; +} + + +void +error_cleanup() +{ + FREE(error_str); + error_str_len = 0; + error_str_maxlen = 0; + error_str = 0; +} diff --git a/sis/error/error.doc b/sis/error/error.doc new file mode 100644 index 0000000..543a390 --- /dev/null +++ b/sis/error/error.doc @@ -0,0 +1,26 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/error/error.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +void +error_init() + + Set the error string to empty. + + +void +error_append(s) +char *s; + + Append the string 's' to the error string. + + +char * +error_string() + + Return the current error string. diff --git a/sis/error/error.h b/sis/error/error.h new file mode 100644 index 0000000..0ba6890 --- /dev/null +++ b/sis/error/error.h @@ -0,0 +1,13 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/error/error.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +EXTERN void error_init ARGS((void)); +EXTERN void error_append ARGS((char *)); +EXTERN char *error_string ARGS((void)); +EXTERN void error_cleanup ARGS((void)); diff --git a/sis/espresso/Makefile.am b/sis/espresso/Makefile.am new file mode 100644 index 0000000..1254fbc --- /dev/null +++ b/sis/espresso/Makefile.am @@ -0,0 +1,8 @@ +AM_CPPFLAGS = -I$(top_srcdir)/port -I../include + +noinst_LIBRARIES = libespresso.a +libespresso_a_SOURCES = cofactor.c compl.c contain.c cubestr.c cvrin.c \ + cvrm.c cvrmisc.c cvrout.c equiv.c espresso.c essen.c exact.c \ + expand.c gasp.c globals.c hack.c irred.c map.c opo.c pair.c primes.c \ + reduce.c set.c setc.c sharp.c sminterf.c sparse.c unate.c verify.c +pkginclude_HEADERS = espresso.h diff --git a/sis/espresso/Makefile.in b/sis/espresso/Makefile.in new file mode 100644 index 0000000..946a9a0 --- /dev/null +++ b/sis/espresso/Makefile.in @@ -0,0 +1,407 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +SOURCES = $(libespresso_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/espresso +DIST_COMMON = $(pkginclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libespresso_a_AR = $(AR) $(ARFLAGS) +libespresso_a_LIBADD = +am_libespresso_a_OBJECTS = cofactor.$(OBJEXT) compl.$(OBJEXT) \ + contain.$(OBJEXT) cubestr.$(OBJEXT) cvrin.$(OBJEXT) \ + cvrm.$(OBJEXT) cvrmisc.$(OBJEXT) cvrout.$(OBJEXT) \ + equiv.$(OBJEXT) espresso.$(OBJEXT) essen.$(OBJEXT) \ + exact.$(OBJEXT) expand.$(OBJEXT) gasp.$(OBJEXT) \ + globals.$(OBJEXT) hack.$(OBJEXT) irred.$(OBJEXT) map.$(OBJEXT) \ + opo.$(OBJEXT) pair.$(OBJEXT) primes.$(OBJEXT) reduce.$(OBJEXT) \ + set.$(OBJEXT) setc.$(OBJEXT) sharp.$(OBJEXT) \ + sminterf.$(OBJEXT) sparse.$(OBJEXT) unate.$(OBJEXT) \ + verify.$(OBJEXT) +libespresso_a_OBJECTS = $(am_libespresso_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libespresso_a_SOURCES) +DIST_SOURCES = $(libespresso_a_SOURCES) +am__installdirs = "$(DESTDIR)$(pkgincludedir)" +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I$(top_srcdir)/port -I../include +noinst_LIBRARIES = libespresso.a +libespresso_a_SOURCES = cofactor.c compl.c contain.c cubestr.c cvrin.c \ + cvrm.c cvrmisc.c cvrout.c equiv.c espresso.c essen.c exact.c \ + expand.c gasp.c globals.c hack.c irred.c map.c opo.c pair.c primes.c \ + reduce.c set.c setc.c sharp.c sminterf.c sparse.c unate.c verify.c + +pkginclude_HEADERS = espresso.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/espresso/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/espresso/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libespresso.a: $(libespresso_a_OBJECTS) $(libespresso_a_DEPENDENCIES) + -rm -f libespresso.a + $(libespresso_a_AR) libespresso.a $(libespresso_a_OBJECTS) $(libespresso_a_LIBADD) + $(RANLIB) libespresso.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-pkgincludeHEADERS \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/espresso/cofactor.c b/sis/espresso/cofactor.c new file mode 100644 index 0000000..003602b --- /dev/null +++ b/sis/espresso/cofactor.c @@ -0,0 +1,382 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/cofactor.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +#include "espresso.h" + +/* + The cofactor of a cover against a cube "c" is a cover formed by the + cofactor of each cube in the cover against c. The cofactor of two + cubes is null if they are distance 1 or more apart. If they are + distance zero apart, the cofactor is the restriction of the cube + to the minterms of c. + + The cube list contains the following information: + + T[0] = pointer to a cube identifying the variables that have + been cofactored against + T[1] = pointer to just beyond the sentinel (i.e., T[n] in this case) + T[2] + . + . = pointers to cubes + . + T[n-2] + T[n-1] = NULL pointer (sentinel) + + + Cofactoring involves repeated application of "cdist0" to check if a + cube of the cover intersects the cofactored cube. This can be + slow, especially for the recursive descent of the espresso + routines. Therefore, a special cofactor routine "scofactor" is + provided which assumes the cofactor is only in a single variable. +*/ + + +/* cofactor -- compute the cofactor of a cover with respect to a cube */ +pcube *cofactor(T, c) +IN pcube *T; +IN register pcube c; +{ + pcube temp = cube.temp[0], *Tc_save, *Tc, *T1; + register pcube p; + int listlen; + + listlen = CUBELISTSIZE(T) + 5; + + /* Allocate a new list of cube pointers (max size is previous size) */ + Tc_save = Tc = ALLOC(pcube, listlen); + + /* pass on which variables have been cofactored against */ + *Tc++ = set_or(new_cube(), T[0], set_diff(temp, cube.fullset, c)); + Tc++; + + /* Loop for each cube in the list, determine suitability, and save */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (p != c) { + +#ifdef NO_INLINE + if (! cdist0(p, c)) goto false; +#else + {register int w,last;register unsigned int x;if((last=cube.inword)!=-1) + {x=p[last]&c[last];if(~(x|x>>1)&cube.inmask)goto false;for(w=1;w>1)&DISJOINT)goto false;}}}{register int w,var,last; + register pcube mask;for(var=cube.num_binary_vars;var= 0; i--) + count[i] = 0; + } + + /* Count the number of zeros in each column */ + { register int i, *cnt; + register unsigned int val; + register pcube p, cof = T[0], full = cube.fullset; + for(T1 = T+2; (p = *T1++) != NULL; ) + for(i = LOOP(p); i > 0; i--) + if (val = full[i] & ~ (p[i] | cof[i])) { + cnt = count + ((i-1) << LOGBPI); +#if BPI == 32 + if (val & 0xFF000000) { + if (val & 0x80000000) cnt[31]++; + if (val & 0x40000000) cnt[30]++; + if (val & 0x20000000) cnt[29]++; + if (val & 0x10000000) cnt[28]++; + if (val & 0x08000000) cnt[27]++; + if (val & 0x04000000) cnt[26]++; + if (val & 0x02000000) cnt[25]++; + if (val & 0x01000000) cnt[24]++; + } + if (val & 0x00FF0000) { + if (val & 0x00800000) cnt[23]++; + if (val & 0x00400000) cnt[22]++; + if (val & 0x00200000) cnt[21]++; + if (val & 0x00100000) cnt[20]++; + if (val & 0x00080000) cnt[19]++; + if (val & 0x00040000) cnt[18]++; + if (val & 0x00020000) cnt[17]++; + if (val & 0x00010000) cnt[16]++; + } +#endif + if (val & 0xFF00) { + if (val & 0x8000) cnt[15]++; + if (val & 0x4000) cnt[14]++; + if (val & 0x2000) cnt[13]++; + if (val & 0x1000) cnt[12]++; + if (val & 0x0800) cnt[11]++; + if (val & 0x0400) cnt[10]++; + if (val & 0x0200) cnt[ 9]++; + if (val & 0x0100) cnt[ 8]++; + } + if (val & 0x00FF) { + if (val & 0x0080) cnt[ 7]++; + if (val & 0x0040) cnt[ 6]++; + if (val & 0x0020) cnt[ 5]++; + if (val & 0x0010) cnt[ 4]++; + if (val & 0x0008) cnt[ 3]++; + if (val & 0x0004) cnt[ 2]++; + if (val & 0x0002) cnt[ 1]++; + if (val & 0x0001) cnt[ 0]++; + } + } + } + + /* + * Perform counts for each variable: + * cdata.var_zeros[var] = number of zeros in the variable + * cdata.parts_active[var] = number of active parts for each variable + * cdata.vars_active = number of variables which are active + * cdata.vars_unate = number of variables which are active and unate + * + * best -- the variable which is best for splitting based on: + * mostactive -- most # active parts in any variable + * mostzero -- most # zeros in any variable + * mostbalanced -- minimum over the maximum # zeros / part / variable + */ + + { register int var, i, lastbit, active, maxactive; + int best = -1, mostactive = 0, mostzero = 0, mostbalanced = 32000; + cdata.vars_unate = cdata.vars_active = 0; + + for(var = 0; var < cube.num_vars; var++) { + if (var < cube.num_binary_vars) { /* special hack for binary vars */ + i = count[var*2]; + lastbit = count[var*2 + 1]; + active = (i > 0) + (lastbit > 0); + cdata.var_zeros[var] = i + lastbit; + maxactive = MAX(i, lastbit); + } else { + maxactive = active = cdata.var_zeros[var] = 0; + lastbit = cube.last_part[var]; + for(i = cube.first_part[var]; i <= lastbit; i++) { + cdata.var_zeros[var] += count[i]; + active += (count[i] > 0); + if (active > maxactive) maxactive = active; + } + } + + /* first priority is to maximize the number of active parts */ + /* for binary case, this will usually select the output first */ + if (active > mostactive) + best = var, mostactive = active, mostzero = cdata.var_zeros[best], + mostbalanced = maxactive; + else if (active == mostactive) + /* secondary condition is to maximize the number zeros */ + /* for binary variables, this is the same as minimum # of 2's */ + if (cdata.var_zeros[var] > mostzero) + best = var, mostzero = cdata.var_zeros[best], + mostbalanced = maxactive; + else if (cdata.var_zeros[var] == mostzero) + /* third condition is to pick a balanced variable */ + /* for binary vars, this means roughly equal # 0's and 1's */ + if (maxactive < mostbalanced) + best = var, mostbalanced = maxactive; + + cdata.parts_active[var] = active; + cdata.is_unate[var] = (active == 1); + cdata.vars_active += (active > 0); + cdata.vars_unate += (active == 1); + } + cdata.best = best; + } +} + +int binate_split_select(T, cleft, cright, debug_flag) +IN pcube *T; +IN register pcube cleft, cright; +IN int debug_flag; +{ + int best = cdata.best; + register int i, lastbit = cube.last_part[best], halfbit = 0; + register pcube cof=T[0]; + + /* Create the cubes to cofactor against */ + (void) set_diff(cleft, cube.fullset, cube.var_mask[best]); + (void) set_diff(cright, cube.fullset, cube.var_mask[best]); + for(i = cube.first_part[best]; i <= lastbit; i++) + if (! is_in_set(cof,i)) + halfbit++; + for(i = cube.first_part[best], halfbit = halfbit/2; halfbit > 0; i++) + if (! is_in_set(cof,i)) + halfbit--, set_insert(cleft, i); + for(; i <= lastbit; i++) + if (! is_in_set(cof,i)) + set_insert(cright, i); + + if (debug & debug_flag) { + (void) printf("BINATE_SPLIT_SELECT: split against %d\n", best); + if (verbose_debug) + (void) printf("cl=%s\ncr=%s\n", pc1(cleft), pc2(cright)); + } + return best; +} + + +pcube *cube1list(A) +pcover A; +{ + register pcube last, p, *plist, *list; + + list = plist = ALLOC(pcube, A->count + 3); + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + *plist++ = NULL; /* sentinel */ + list[1] = (pcube) plist; + return list; +} + + +pcube *cube2list(A, B) +pcover A, B; +{ + register pcube last, p, *plist, *list; + + list = plist = ALLOC(pcube, A->count + B->count + 3); + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + foreach_set(B, last, p) { + *plist++ = p; + } + *plist++ = NULL; + list[1] = (pcube) plist; + return list; +} + + +pcube *cube3list(A, B, C) +pcover A, B, C; +{ + register pcube last, p, *plist, *list; + + plist = ALLOC(pcube, A->count + B->count + C->count + 3); + list = plist; + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + foreach_set(B, last, p) { + *plist++ = p; + } + foreach_set(C, last, p) { + *plist++ = p; + } + *plist++ = NULL; + list[1] = (pcube) plist; + return list; +} + + +pcover cubeunlist(A1) +pcube *A1; +{ + register int i; + register pcube p, pdest, cof = A1[0]; + register pcover A; + + A = new_cover(CUBELISTSIZE(A1)); + for(i = 2; (p = A1[i]) != NULL; i++) { + pdest = GETSET(A, i-2); + INLINEset_or(pdest, p, cof); + } + A->count = CUBELISTSIZE(A1); + return A; +} + +simplify_cubelist(T) +pcube *T; +{ + register pcube *Tdest; + register int i, ncubes; + + (void) set_copy(cube.temp[0], T[0]); /* retrieve cofactor */ + + ncubes = CUBELISTSIZE(T); + qsort((char *) (T+2), ncubes, sizeof(pset), (int (*)()) d1_order); + + Tdest = T+2; + /* *Tdest++ = T[2]; */ + for(i = 3; i < ncubes; i++) { + if (d1_order(&T[i-1], &T[i]) != 0) { + *Tdest++ = T[i]; + } + } + + *Tdest++ = NULL; /* sentinel */ + Tdest[1] = (pcube) Tdest; /* save pointer to last */ +} diff --git a/sis/espresso/compl.c b/sis/espresso/compl.c new file mode 100644 index 0000000..72a8cee --- /dev/null +++ b/sis/espresso/compl.c @@ -0,0 +1,680 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/compl.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +/* + * module: compl.c + * purpose: compute the complement of a multiple-valued function + * + * The "unate recursive paradigm" is used. After a set of special + * cases are examined, the function is split on the "most active + * variable". These two halves are complemented recursively, and then + * the results are merged. + * + * Changes (from Version 2.1 to Version 2.2) + * 1. Minor bug in compl_lifting -- cubes in the left half were + * not marked as active, so that when merging a leaf from the left + * hand side, the active flags were essentially random. This led + * to minor impredictability problem, but never affected the + * accuracy of the results. + */ + +#include "espresso.h" + +#define USE_COMPL_LIFT 0 +#define USE_COMPL_LIFT_ONSET 1 +#define USE_COMPL_LIFT_ONSET_COMPLEX 2 +#define NO_LIFTING 3 + +static bool compl_special_cases(); +static pcover compl_merge(); +static void compl_d1merge(); +static pcover compl_cube(); +static void compl_lift(); +static void compl_lift_onset(); +static void compl_lift_onset_complex(); +static bool simp_comp_special_cases(); +static bool simplify_special_cases(); + + +/* complement -- compute the complement of T */ +pcover complement(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tbar, Tl, Tr; + int lifting; + static int compl_level = 0; + + if (debug & COMPL) + debug_print(T, "COMPLEMENT", compl_level++); + + if (compl_special_cases(T, &Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + Tl = complement(scofactor(T, cl, best)); + Tr = complement(scofactor(T, cr, best)); + + if (Tr->count*Tl->count > (Tr->count+Tl->count)*CUBELISTSIZE(T)) { + lifting = USE_COMPL_LIFT_ONSET; + } else { + lifting = USE_COMPL_LIFT; + } + Tbar = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) + debug1_print(Tbar, "exit COMPLEMENT", --compl_level); + return Tbar; +} + +static bool compl_special_cases(T, Tbar) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tbar; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcover A, ceil_compl; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tbar = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tbar = compl_cube(set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies complement is null) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tbar = new_cover(0); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + ceil_compl = compl_cube(ceil); + (void) set_or(cof, cof, set_diff(ceil, cube.fullset, ceil)); + set_free(ceil); + *Tbar = sf_append(complement(T), ceil_compl); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tbar = new_cover(0); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = map_cover_to_unate(T); + free_cubelist(T); + A = unate_compl(A); + *Tbar = map_unate_to_cover(A); + sf_free(A); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +/* + * compl_merge -- merge the two cofactors around the splitting + * variable + * + * The merge operation involves intersecting each cube of the left + * cofactor with cl, and intersecting each cube of the right cofactor + * with cr. The union of these two covers is the merged result. + * + * In order to reduce the number of cubes, a distance-1 merge is + * performed (note that two cubes can only combine distance-1 in the + * splitting variable). Also, a simple expand is performed in the + * splitting variable (simple implies the covering check for the + * expansion is not full containment, but single-cube containment). + */ + +static pcover compl_merge(T1, L, R, cl, cr, var, lifting) +pcube *T1; /* Original ON-set */ +pcover L, R; /* Complement from each recursion branch */ +register pcube cl, cr; /* cubes used for cofactoring */ +int var; /* splitting variable */ +int lifting; /* whether to perform lifting or not */ +{ + register pcube p, last, pt; + pcover T, Tbar; + pcube *L1, *R1; + + if (debug & COMPL) { + (void) printf("compl_merge: left %d, right %d\n", L->count, R->count); + (void) printf("%s (cl)\n%s (cr)\nLeft is\n", pc1(cl), pc2(cr)); + cprint(L); + (void) printf("Right is\n"); + cprint(R); + } + + /* Intersect each cube with the cofactored cube */ + foreach_set(L, last, p) { + INLINEset_and(p, p, cl); + SET(p, ACTIVE); + } + foreach_set(R, last, p) { + INLINEset_and(p, p, cr); + SET(p, ACTIVE); + } + + /* Sort the arrays for a distance-1 merge */ + (void) set_copy(cube.temp[0], cube.var_mask[var]); + qsort((char *) (L1 = sf_list(L)), L->count, sizeof(pset), (int (*)()) d1_order); + qsort((char *) (R1 = sf_list(R)), R->count, sizeof(pset), (int (*)()) d1_order); + + /* Perform distance-1 merge */ + compl_d1merge(L1, R1); + + /* Perform lifting */ + switch(lifting) { + case USE_COMPL_LIFT_ONSET: + T = cubeunlist(T1); + compl_lift_onset(L1, T, cr, var); + compl_lift_onset(R1, T, cl, var); + free_cover(T); + break; + case USE_COMPL_LIFT_ONSET_COMPLEX: + T = cubeunlist(T1); + compl_lift_onset_complex(L1, T, var); + compl_lift_onset_complex(R1, T, var); + free_cover(T); + break; + case USE_COMPL_LIFT: + compl_lift(L1, R1, cr, var); + compl_lift(R1, L1, cl, var); + break; + case NO_LIFTING: + break; + default: + ; + } + FREE(L1); + FREE(R1); + + /* Re-create the merged cover */ + Tbar = new_cover(L->count + R->count); + pt = Tbar->data; + foreach_set(L, last, p) { + INLINEset_copy(pt, p); + Tbar->count++; + pt += Tbar->wsize; + } + foreach_active_set(R, last, p) { + INLINEset_copy(pt, p); + Tbar->count++; + pt += Tbar->wsize; + } + + if (debug & COMPL) { + (void) printf("Result %d\n", Tbar->count); + if (verbose_debug) + cprint(Tbar); + } + + free_cover(L); + free_cover(R); + return Tbar; +} + +/* + * compl_lift_simple -- expand in the splitting variable using single + * cube containment against the other recursion branch to check + * validity of the expansion, and expanding all (or none) of the + * splitting variable. + */ +static void compl_lift(A1, B1, bcube, var) +pcube *A1, *B1, bcube; +int var; +{ + register pcube a, b, *B2, lift=cube.temp[4], liftor=cube.temp[5]; + pcube mask = cube.var_mask[var]; + + (void) set_and(liftor, bcube, mask); + + /* for each cube in the first array ... */ + for(; (a = *A1++) != NULL; ) { + if (TESTP(a, ACTIVE)) { + + /* create a lift of this cube in the merging coord */ + (void) set_merge(lift, bcube, a, mask); + + /* for each cube in the second array */ + for(B2 = B1; (b = *B2++) != NULL; ) { + INLINEsetp_implies(lift, b, /* when_false => */ continue); + /* when_true => fall through to next statement */ + + /* cube of A1 was contained by some cube of B1, so raise */ + INLINEset_or(a, a, liftor); + break; + } + } + } +} + + + +/* + * compl_lift_onset -- expand in the splitting variable using a + * distance-1 check against the original on-set; expand all (or + * none) of the splitting variable. Each cube of A1 is expanded + * against the original on-set T. + */ +static void compl_lift_onset(A1, T, bcube, var) +pcube *A1; +pcover T; +pcube bcube; +int var; +{ + register pcube a, last, p, lift=cube.temp[4], mask=cube.var_mask[var]; + + /* for each active cube from one branch of the complement */ + for(; (a = *A1++) != NULL; ) { + if (TESTP(a, ACTIVE)) { + + /* create a lift of this cube in the merging coord */ + INLINEset_and(lift, bcube, mask); /* isolate parts to raise */ + INLINEset_or(lift, a, lift); /* raise these parts in a */ + + /* for each cube in the ON-set, check for intersection */ + foreach_set(T, last, p) { + if (cdist0(p, lift)) { + goto nolift; + } + } + INLINEset_copy(a, lift); /* save the raising */ + SET(a, ACTIVE); +nolift : ; + } + } +} + +/* + * compl_lift_complex -- expand in the splitting variable, but expand all + * parts which can possibly expand. + * T is the original ON-set + * A1 is either the left or right cofactor + */ +static void compl_lift_onset_complex(A1, T, var) +pcube *A1; /* array of pointers to new result */ +pcover T; /* original ON-set */ +int var; /* which variable we split on */ +{ + register int dist; + register pcube last, p, a, xlower; + + /* for each cube in the complement */ + xlower = new_cube(); + for(; (a = *A1++) != NULL; ) { + + if (TESTP(a, ACTIVE)) { + + /* Find which parts of the splitting variable are forced low */ + INLINEset_clear(xlower, cube.size); + foreach_set(T, last, p) { + if ((dist = cdist01(p, a)) < 2) { + if (dist == 0) { + fatal("compl: ON-set and OFF-set are not orthogonal"); + } else { + (void) force_lower(xlower, p, a); + } + } + } + + (void) set_diff(xlower, cube.var_mask[var], xlower); + (void) set_or(a, a, xlower); + free_cube(xlower); + } + } +} + + + +/* + * compl_d1merge -- distance-1 merge in the splitting variable + */ +static void compl_d1merge(L1, R1) +register pcube *L1, *R1; +{ + register pcube pl, pr; + + /* Find equal cubes between the two cofactors */ + for(pl = *L1, pr = *R1; (pl != NULL) && (pr != NULL); ) + switch (d1_order(L1, R1)) { + case 1: + pr = *(++R1); break; /* advance right pointer */ + case -1: + pl = *(++L1); break; /* advance left pointer */ + case 0: + RESET(pr, ACTIVE); + INLINEset_or(pl, pl, pr); + pr = *(++R1); + default: + ; + } +} + + + +/* compl_cube -- return the complement of a single cube (De Morgan's law) */ +static pcover compl_cube(p) +register pcube p; +{ + register pcube diff=cube.temp[7], pdest, mask, full=cube.fullset; + int var; + pcover R; + + /* Allocate worst-case size cover (to avoid checking overflow) */ + R = new_cover(cube.num_vars); + + /* Compute bit-wise complement of the cube */ + INLINEset_diff(diff, full, p); + + for(var = 0; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + /* If the bit-wise complement is not empty in var ... */ + if (! setp_disjoint(diff, mask)) { + pdest = GETSET(R, R->count++); + INLINEset_merge(pdest, diff, full, mask); + } + } + return R; +} + +/* simp_comp -- quick simplification of T */ +void simp_comp(T, Tnew, Tbar) +pcube *T; /* T will be disposed of */ +pcover *Tnew; +pcover *Tbar; +{ + register pcube cl, cr; + register int best; + pcover Tl, Tr, Tlbar, Trbar; + int lifting; + static int simplify_level = 0; + + if (debug & COMPL) + debug_print(T, "SIMPCOMP", simplify_level++); + + if (simp_comp_special_cases(T, Tnew, Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + simp_comp(scofactor(T, cl, best), &Tl, &Tlbar); + simp_comp(scofactor(T, cr, best), &Tr, &Trbar); + + lifting = USE_COMPL_LIFT; + *Tnew = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + lifting = USE_COMPL_LIFT; + *Tbar = compl_merge(T, Tlbar, Trbar, cl, cr, best, lifting); + + /* All of this work for nothing ? Let's hope not ... */ + if ((*Tnew)->count > CUBELISTSIZE(T)) { + sf_free(*Tnew); + *Tnew = cubeunlist(T); + } + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) { + debug1_print(*Tnew, "exit SIMPCOMP (new)", simplify_level); + debug1_print(*Tbar, "exit SIMPCOMP (compl)", simplify_level); + simplify_level--; + } +} + +static bool simp_comp_special_cases(T, Tnew, Tbar) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +pcover *Tbar; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover (function is empty) */ + if (T[2] == NULL) { + *Tnew = new_cover(1); + *Tbar = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + (void) set_or(cof, cof, T[2]); + *Tnew = sf_addset(new_cover(1), cof); + *Tbar = compl_cube(cof); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + *Tbar = new_cover(1); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + set_free(p); + simp_comp(T, Tnew, Tbar); + + /* Adjust the ON-set */ + A = *Tnew; + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + + /* Compute the new complement */ + *Tbar = sf_append(*Tbar, compl_cube(ceil)); + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + *Tbar = new_cover(1); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + /* Make the cover minimum by single-cube containment */ + A = cubeunlist(T); + *Tnew = sf_contain(A); + + /* Now form a minimum representation of the complement */ + A = map_cover_to_unate(T); + A = unate_compl(A); + *Tbar = map_unate_to_cover(A); + sf_free(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +/* simplify -- quick simplification of T */ +pcover simplify(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tbar, Tl, Tr; + int lifting; + static int simplify_level = 0; + + if (debug & COMPL) { + debug_print(T, "SIMPLIFY", simplify_level++); + } + + if (simplify_special_cases(T, &Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + Tl = simplify(scofactor(T, cl, best)); + Tr = simplify(scofactor(T, cr, best)); + + lifting = USE_COMPL_LIFT; + Tbar = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + /* All of this work for nothing ? Let's hope not ... */ + if (Tbar->count > CUBELISTSIZE(T)) { + sf_free(Tbar); + Tbar = cubeunlist(T); + } + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) { + debug1_print(Tbar, "exit SIMPLIFY", --simplify_level); + } + return Tbar; +} + +static bool simplify_special_cases(T, Tnew) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tnew = new_cover(0); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tnew = sf_addset(new_cover(1), set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + free_cube(p); + + A = simplify(T); + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + *Tnew = A; + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = cubeunlist(T); + *Tnew = sf_contain(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} diff --git a/sis/espresso/contain.c b/sis/espresso/contain.c new file mode 100644 index 0000000..04129ee --- /dev/null +++ b/sis/espresso/contain.c @@ -0,0 +1,441 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/contain.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +/* + contain.c -- set containment routines + + These are complex routines for performing containment over a + family of sets, but they have the advantage of being much faster + than a straightforward n*n routine. + + First the cubes are sorted by size, and as a secondary key they are + sorted so that if two cubes are equal they end up adjacent. We can + than quickly remove equal cubes from further consideration by + comparing each cube to its neighbor. Finally, because the cubes + are sorted by size, we need only check cubes which are larger (or + smaller) than a given cube for containment. +*/ + +#include "espresso.h" + + +/* + sf_contain -- perform containment on a set family (delete sets which + are contained by some larger set in the family). No assumptions are + made about A, and the result will be returned in decreasing order of + set size. +*/ +pset_family sf_contain(A) +INOUT pset_family A; /* disposes of A */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort into descending order */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + cnt = rm_contain(A1); /* remove contained sets */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_rev_contain -- perform containment on a set family (delete sets which + contain some smaller set in the family). No assumptions are made about + A, and the result will be returned in increasing order of set size +*/ +pset_family sf_rev_contain(A) +INOUT pset_family A; /* disposes of A */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, ascend); /* sort into ascending order */ + cnt = rm_equal(A1, ascend); /* remove duplicates */ + cnt = rm_rev_contain(A1); /* remove containing sets */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_ind_contain -- perform containment on a set family (delete sets which + are contained by some larger set in the family). No assumptions are + made about A, and the result will be returned in decreasing order of + set size. Also maintains a set of row_indices to track which rows + disappear and how the rows end up permuted. +*/ +pset_family sf_ind_contain(A, row_indices) +INOUT pset_family A; /* disposes of A */ +INOUT int *row_indices; /* updated with the new values */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort into descending order */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + cnt = rm_contain(A1); /* remove contained sets */ + R = sf_ind_unlist(A1, cnt, A->sf_size, row_indices, A->data); + sf_free(A); + return R; +} + + +/* sf_dupl -- delete duplicate sets in a set family */ +pset_family sf_dupl(A) +INOUT pset_family A; /* disposes of A */ +{ + register int cnt; + register pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort the set family */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_union -- form the contained union of two set families (delete + sets which are contained by some larger set in the family). A and + B are assumed already sorted in decreasing order of set size (and + the SIZE field is assumed to contain the set size), and the result + will be returned sorted likewise. +*/ +pset_family sf_union(A, B) +INOUT pset_family A, B; /* disposes of A and B */ +{ + int cnt; + pset_family R; + pset *A1 = sf_list(A), *B1 = sf_list(B), *E1; + + E1 = ALLOC(pset, MAX(A->count, B->count) + 1); + cnt = rm2_equal(A1, B1, E1, descend); + cnt += rm2_contain(A1, B1) + rm2_contain(B1, A1); + R = sf_merge(A1, B1, E1, cnt, A->sf_size); + sf_free(A); sf_free(B); + return R; +} + + +/* + dist_merge -- consider all sets to be "or"-ed with "mask" and then + delete duplicates from the set family. +*/ +pset_family dist_merge(A, mask) +INOUT pset_family A; /* disposes of A */ +IN pset mask; /* defines variables to mask out */ +{ + pset *A1; + int cnt; + pset_family R; + + (void) set_copy(cube.temp[0], mask); + A1 = sf_sort(A, d1_order); + cnt = d1_rm_equal(A1, d1_order); + R = sf_unlist(A1, cnt, A->sf_size); + sf_free(A); + return R; +} + + +/* + d1merge -- perform an efficient distance-1 merge of cubes of A +*/ +pset_family d1merge(A, var) +INOUT pset_family A; /* disposes of A */ +IN int var; +{ + return dist_merge(A, cube.var_mask[var]); +} + + + +/* d1_rm_equal -- distance-1 merge (merge cubes which are equal under a mask) */ +int d1_rm_equal(A1, compare) +register pset *A1; /* array of set pointers */ +int (*compare)(); /* comparison function */ +{ + register int i, j, dest; + + dest = 0; + if (A1[0] != (pcube) NULL) { + for(i = 0, j = 1; A1[j] != (pcube) NULL; j++) + if ( (*compare)(&A1[i], &A1[j]) == 0) { + /* if sets are equal (under the mask) merge them */ + (void) set_or(A1[i], A1[i], A1[j]); + } else { + /* sets are unequal, so save the set i */ + A1[dest++] = A1[i]; + i = j; + } + A1[dest++] = A1[i]; + } + A1[dest] = (pcube) NULL; + return dest; +} + + +/* rm_equal -- scan a sorted array of set pointers for duplicate sets */ +int rm_equal(A1, compare) +INOUT pset *A1; /* updated in place */ +IN int (*compare)(); +{ + register pset *p, *pdest = A1; + + if (*A1 != NULL) { /* If more than one set */ + for(p = A1+1; *p != NULL; p++) + if ((*compare)(p, p-1) != 0) + *pdest++ = *(p-1); + *pdest++ = *(p-1); + *pdest = NULL; + } + return pdest - A1; +} + + +/* rm_contain -- perform containment over a sorted array of set pointers */ +int rm_contain(A1) +INOUT pset *A1; /* updated in place */ +{ + register pset *pa, *pb, *pcheck, a, b; + pset *pdest = A1; + int last_size = -1; + + /* Loop for all cubes of A1 */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* Update the check pointer if the size has changed */ + if (SIZE(a) != last_size) + last_size = SIZE(a), pcheck = pdest; + for(pb = A1; pb != pcheck; ) { + b = *pb++; + INLINEsetp_implies(a, b, /* when_false => */ continue); + goto lnext1; + } + /* set a was not contained by some larger set, so save it */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; + return pdest - A1; +} + + +/* rm_rev_contain -- perform rcontainment over a sorted array of set pointers */ +int rm_rev_contain(A1) +INOUT pset *A1; /* updated in place */ +{ + register pset *pa, *pb, *pcheck, a, b; + pset *pdest = A1; + int last_size = -1; + + /* Loop for all cubes of A1 */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* Update the check pointer if the size has changed */ + if (SIZE(a) != last_size) + last_size = SIZE(a), pcheck = pdest; + for(pb = A1; pb != pcheck; ) { + b = *pb++; + INLINEsetp_implies(b, a, /* when_false => */ continue); + goto lnext1; + } + /* the set a did not contain some smaller set, so save it */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; + return pdest - A1; +} + + +/* rm2_equal -- check two sorted arrays of set pointers for equal cubes */ +int rm2_equal(A1, B1, E1, compare) +INOUT register pset *A1, *B1; /* updated in place */ +OUT pset *E1; +IN int (*compare)(); +{ + register pset *pda = A1, *pdb = B1, *pde = E1; + + /* Walk through the arrays advancing pointer to larger cube */ + for(; *A1 != NULL && *B1 != NULL; ) + switch((*compare)(A1, B1)) { + case -1: /* "a" comes before "b" */ + *pda++ = *A1++; break; + case 0: /* equal cubes */ + *pde++ = *A1++; B1++; break; + case 1: /* "a" is to follow "b" */ + *pdb++ = *B1++; break; + } + + /* Finish moving down the pointers of A and B */ + while (*A1 != NULL) + *pda++ = *A1++; + while (*B1 != NULL) + *pdb++ = *B1++; + *pda = *pdb = *pde = NULL; + + return pde - E1; +} + + +/* rm2_contain -- perform containment between two arrays of set pointers */ +int rm2_contain(A1, B1) +INOUT pset *A1; /* updated in place */ +IN pset *B1; /* unchanged */ +{ + register pset *pa, *pb, a, b, *pdest = A1; + + /* for each set in the first array ... */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* for each set in the second array which is larger ... */ + for(pb = B1; (b = *pb++) != NULL && SIZE(b) > SIZE(a); ) { + INLINEsetp_implies(a, b, /* when_false => */ continue); + /* set was contained in some set of B, so don't save pointer */ + goto lnext1; + } + /* set wasn't contained in any set of B, so save the pointer */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; /* sentinel */ + return pdest - A1; /* # elements in A1 */ +} + + + +/* sf_sort -- sort the sets of A */ +pset *sf_sort(A, compare) +IN pset_family A; +IN int (*compare)(); +{ + register pset p, last, *pdest, *A1; + + /* Create a single array pointing to each cube of A */ + pdest = A1 = ALLOC(pset, A->count + 1); + foreach_set(A, last, p) { + PUTSIZE(p, set_ord(p)); /* compute the set size */ + *pdest++ = p; /* save the pointer */ + } + *pdest = NULL; /* Sentinel -- never seen by sort */ + + /* Sort cubes by size */ + qsort((char *) A1, A->count, sizeof(pset), compare); + return A1; +} + + +/* sf_list -- make a list of pointers to the sets in a set family */ +pset *sf_list(A) +IN register pset_family A; +{ + register pset p, last, *pdest, *A1; + + /* Create a single array pointing to each cube of A */ + pdest = A1 = ALLOC(pset, A->count + 1); + foreach_set(A, last, p) + *pdest++ = p; /* save the pointer */ + *pdest = NULL; /* Sentinel */ + return A1; +} + + +/* sf_unlist -- make a set family out of a list of pointers to sets */ +pset_family sf_unlist(A1, totcnt, size) +IN pset *A1; +IN int totcnt, size; +{ + register pset pr, p, *pa; + pset_family R = sf_new(totcnt, size); + + R->count = totcnt; + for(pr = R->data, pa = A1; (p = *pa++) != NULL; pr += R->wsize) + INLINEset_copy(pr, p); + FREE(A1); + return R; +} + + +/* sf_ind_unlist -- make a set family out of a list of pointers to sets */ +pset_family sf_ind_unlist(A1, totcnt, size, row_indices, pfirst) +IN pset *A1; +IN int totcnt, size; +INOUT int *row_indices; +IN register pset pfirst; +{ + register pset pr, p, *pa; + register int i, *new_row_indices; + pset_family R = sf_new(totcnt, size); + + R->count = totcnt; + new_row_indices = ALLOC(int, totcnt); + for(pr = R->data, pa = A1, i=0; (p = *pa++) != NULL; pr += R->wsize, i++) { + INLINEset_copy(pr, p); + new_row_indices[i] = row_indices[(p - pfirst)/R->wsize]; + } + for(i = 0; i < totcnt; i++) + row_indices[i] = new_row_indices[i]; + FREE(new_row_indices); + FREE(A1); + return R; +} + + +/* sf_merge -- merge three sorted lists of set pointers */ +pset_family sf_merge(A1, B1, E1, totcnt, size) +INOUT pset *A1, *B1, *E1; /* will be disposed of */ +IN int totcnt, size; +{ + register pset pr, ps, *pmin, *pmid, *pmax; + pset_family R; + pset *temp[3], *swap; + int i, j, n; + + /* Allocate the result set_family */ + R = sf_new(totcnt, size); + R->count = totcnt; + pr = R->data; + + /* Quick bubble sort to order the top member of the three arrays */ + n = 3; temp[0] = A1; temp[1] = B1; temp[2] = E1; + for(i = 0; i < n-1; i++) + for(j = i+1; j < n; j++) + if (desc1(*temp[i], *temp[j]) > 0) { + swap = temp[j]; + temp[j] = temp[i]; + temp[i] = swap; + } + pmin = temp[0]; pmid = temp[1]; pmax = temp[2]; + + /* Save the minimum element, then update pmin, pmid, pmax */ + while (*pmin != (pset) NULL) { + ps = *pmin++; + INLINEset_copy(pr, ps); + pr += R->wsize; + if (desc1(*pmin, *pmax) > 0) { + swap = pmax; pmax = pmin; pmin = pmid; pmid = swap; + } else if (desc1(*pmin, *pmid) > 0) { + swap = pmin; pmin = pmid; pmid = swap; + } + } + + FREE(A1); + FREE(B1); + FREE(E1); + return R; +} diff --git a/sis/espresso/cubestr.c b/sis/espresso/cubestr.c new file mode 100644 index 0000000..2dd5229 --- /dev/null +++ b/sis/espresso/cubestr.c @@ -0,0 +1,152 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/cubestr.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +/* + Module: cubestr.c -- routines for managing the global cube structure +*/ + +#include "espresso.h" + +/* + cube_setup -- assume that the fields "num_vars", "num_binary_vars", and + part_size[num_binary_vars .. num_vars-1] are setup, and initialize the + rest of cube and cdata. + + If a part_size is < 0, then the field size is abs(part_size) and the + field read from the input is symbolic. +*/ +void cube_setup() +{ + register int i, var; + register pcube p; + + if (cube.num_binary_vars < 0 || cube.num_vars < cube.num_binary_vars) + fatal("cube size is silly, error in .i/.o or .mv"); + + cube.num_mv_vars = cube.num_vars - cube.num_binary_vars; + cube.output = cube.num_mv_vars > 0 ? cube.num_vars - 1 : -1; + + cube.size = 0; + cube.first_part = ALLOC(int, cube.num_vars); + cube.last_part = ALLOC(int, cube.num_vars); + cube.first_word = ALLOC(int, cube.num_vars); + cube.last_word = ALLOC(int, cube.num_vars); + for(var = 0; var < cube.num_vars; var++) { + if (var < cube.num_binary_vars) + cube.part_size[var] = 2; + cube.first_part[var] = cube.size; + cube.first_word[var] = WHICH_WORD(cube.size); + cube.size += ABS(cube.part_size[var]); + cube.last_part[var] = cube.size - 1; + cube.last_word[var] = WHICH_WORD(cube.size - 1); + } + + cube.var_mask = ALLOC(pset, cube.num_vars); + cube.sparse = ALLOC(int, cube.num_vars); + cube.binary_mask = new_cube(); + cube.mv_mask = new_cube(); + for(var = 0; var < cube.num_vars; var++) { + p = cube.var_mask[var] = new_cube(); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + set_insert(p, i); + if (var < cube.num_binary_vars) { + INLINEset_or(cube.binary_mask, cube.binary_mask, p); + cube.sparse[var] = 0; + } else { + INLINEset_or(cube.mv_mask, cube.mv_mask, p); + cube.sparse[var] = 1; + } + } + if (cube.num_binary_vars == 0) + cube.inword = -1; + else { + cube.inword = cube.last_word[cube.num_binary_vars - 1]; + cube.inmask = cube.binary_mask[cube.inword] & DISJOINT; + } + + cube.temp = ALLOC(pset, CUBE_TEMP); + for(i = 0; i < CUBE_TEMP; i++) + cube.temp[i] = new_cube(); + cube.fullset = set_fill(new_cube(), cube.size); + cube.emptyset = new_cube(); + + cdata.part_zeros = ALLOC(int, cube.size); + cdata.var_zeros = ALLOC(int, cube.num_vars); + cdata.parts_active = ALLOC(int, cube.num_vars); + cdata.is_unate = ALLOC(int, cube.num_vars); +} + +/* + setdown_cube -- free memory allocated for the cube/cdata structs + (free's all but the part_size array) + + (I wanted to call this cube_setdown, but that violates the 8-character + external routine limit on the IBM !) +*/ +void setdown_cube() +{ + register int i, var; + + FREE(cube.first_part); + FREE(cube.last_part); + FREE(cube.first_word); + FREE(cube.last_word); + FREE(cube.sparse); + + free_cube(cube.binary_mask); + free_cube(cube.mv_mask); + free_cube(cube.fullset); + free_cube(cube.emptyset); + for(var = 0; var < cube.num_vars; var++) + free_cube(cube.var_mask[var]); + FREE(cube.var_mask); + + for(i = 0; i < CUBE_TEMP; i++) + free_cube(cube.temp[i]); + FREE(cube.temp); + + FREE(cdata.part_zeros); + FREE(cdata.var_zeros); + FREE(cdata.parts_active); + FREE(cdata.is_unate); + + cube.first_part = cube.last_part = (int *) NULL; + cube.first_word = cube.last_word = (int *) NULL; + cube.sparse = (int *) NULL; + cube.binary_mask = cube.mv_mask = (pcube) NULL; + cube.fullset = cube.emptyset = (pcube) NULL; + cube.var_mask = cube.temp = (pcube *) NULL; + + cdata.part_zeros = cdata.var_zeros = cdata.parts_active = (int *) NULL; + cdata.is_unate = (bool *) NULL; +} + + +void save_cube_struct() +{ + temp_cube_save = cube; /* structure copy ! */ + temp_cdata_save = cdata; /* "" */ + + cube.first_part = cube.last_part = (int *) NULL; + cube.first_word = cube.last_word = (int *) NULL; + cube.part_size = (int *) NULL; + cube.binary_mask = cube.mv_mask = (pcube) NULL; + cube.fullset = cube.emptyset = (pcube) NULL; + cube.var_mask = cube.temp = (pcube *) NULL; + + cdata.part_zeros = cdata.var_zeros = cdata.parts_active = (int *) NULL; + cdata.is_unate = (bool *) NULL; +} + + +void restore_cube_struct() +{ + cube = temp_cube_save; /* structure copy ! */ + cdata = temp_cdata_save; /* "" */ +} diff --git a/sis/espresso/cvrin.c b/sis/espresso/cvrin.c new file mode 100644 index 0000000..cf1c61c --- /dev/null +++ b/sis/espresso/cvrin.c @@ -0,0 +1,828 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/cvrin.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +/* + module: cvrin.c + purpose: cube and cover input routines +*/ + +#include "sis.h" + +static bool line_length_error; +static bool last_was_newline; +static int lineno; + +static int io_getc (fp) +FILE *fp; +{ + /* Like getc(3s) but handles input prompt and line number. */ + + int c; + char *prompt2; + + if (last_was_newline && fp == stdin) { + prompt2 = com_get_flag ("prompt2"); + if (prompt2 != NULL) fputs (prompt2,stdout); + } + c = getc(fp); + last_was_newline = (c == '\n'); + if (last_was_newline) { + lineno++; + } else if (c == EOF && fp == stdin && com_get_flag("prompt2")) { + fputs("\n",stdout); + } + return c; +} + +void skip_line (fpin, fpout, echo) +register FILE *fpin, *fpout; +register bool echo; +{ + register int ch; + while ((ch=io_getc(fpin)) != EOF && ch != '\n') + if (echo) + putc((char) ch, fpout); + if (echo) + putc('\n', fpout); +} + +char *get_word(fp, word) +register FILE *fp; +register char *word; +{ + register int ch, i = 0; + while ((ch = io_getc(fp)) != EOF && isspace(ch)) + ; + + word[i++] = ch; + while ((ch = io_getc(fp)) != EOF && ! isspace(ch)) + word[i++] = ch; + word[i++] = '\0'; + return word; +} + +/* + * Yes, I know this routine is a mess + */ +void read_cube(fp, PLA) +register FILE *fp; +pPLA PLA; +{ + register int var, i; + pcube cf = cube.temp[0], cr = cube.temp[1], cd = cube.temp[2]; + bool savef = FALSE, saved = FALSE, saver = FALSE; + char token[256]; /* for kiss read hack */ + int varx, first, last, offset; /* for kiss read hack */ + + (void) set_clear(cf, cube.size); + + /* Loop and read binary variables */ + for(var = 0; var < cube.num_binary_vars; var++) + switch(io_getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + (void) fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + var--; + break; + case ' ': case '|': case '\t': + var--; + break; + case '2': case '-': + set_insert(cf, var*2+1); + case '0': + set_insert(cf, var*2); + break; + case '1': + set_insert(cf, var*2+1); + break; + case '?': + break; + default: + goto bad_char; + } + + + /* Loop for the all but one of the multiple-valued variables */ + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) + + /* Read a symbolic multiple-valued variable */ + if (cube.part_size[var] < 0) { + (void) fscanf(fp, "%s", token); + if (equal(token, "-") || equal(token, "ANY")) { + if (kiss && var == cube.num_vars - 2) { + /* leave it empty */ + } else { + /* make it full */ + (void) set_or(cf, cf, cube.var_mask[var]); + } + } else if (equal(token, "~")) { + ; + /* leave it empty ... (?) */ + } else { + if (kiss && var == cube.num_vars - 2) + varx = var - 1, offset = ABS(cube.part_size[var-1]); + else + varx = var, offset = 0; + /* Find the symbolic label in the label table */ + first = cube.first_part[varx]; + last = cube.last_part[varx]; + for(i = first; i <= last; i++) + if (PLA->label[i] == (char *) NULL) { + PLA->label[i] = util_strsav(token); /* add new label */ + set_insert(cf, i+offset); + break; + } else if (equal(PLA->label[i], token)) { + set_insert(cf, i+offset); /* use column i */ + break; + } + if (i > last) { + (void) fprintf(stderr, +"declared size of variable %d (counting from variable 0) is too small\n", var); + exit(-1); + } + } + + } else for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + switch (io_getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + (void) fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + i--; + break; + case ' ': case '|': case '\t': + i--; + break; + case '1': + set_insert(cf, i); + case '0': + break; + default: + goto bad_char; + } + + /* Loop for last multiple-valued variable */ + if (kiss) { + saver = savef = TRUE; + (void) set_xor(cr, cf, cube.var_mask[cube.num_vars - 2]); + } else + (void) set_copy(cr, cf); + (void) set_copy(cd, cf); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + switch (io_getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + (void) fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + i--; + break; + case ' ': case '|': case '\t': + i--; + break; + case '4': case '1': + if (PLA->pla_type & F_type) + set_insert(cf, i), savef = TRUE; + break; + case '3': case '0': + if (PLA->pla_type & R_type) + set_insert(cr, i), saver = TRUE; + break; + case '2': case '-': + if (PLA->pla_type & D_type) + set_insert(cd, i), saved = TRUE; + case '~': + break; + default: + goto bad_char; + } + if (savef) PLA->F = sf_addset(PLA->F, cf); + if (saved) PLA->D = sf_addset(PLA->D, cd); + if (saver) PLA->R = sf_addset(PLA->R, cr); + return; + +bad_char: + (void) fprintf(stderr, "(warning): input line #%d ignored\n", lineno); + skip_line(fp, stdout, TRUE); + return; +} +void parse_pla(fp, PLA) +IN FILE *fp; +INOUT pPLA PLA; +{ + int i, var, ch, np, last; + char word[256]; + + lineno = 1; + last_was_newline = TRUE; + line_length_error = FALSE; + +loop: + switch(ch = io_getc(fp)) { + case EOF: + return; + + case '\n': case ' ': case '\t': case '\f': case '\r': + break; + + case '#': + (void) ungetc(ch, fp); + skip_line(fp, stdout, echo_comments); + break; + + case '.': + /* .i gives the cube input size (binary-functions only) */ + if (equal(get_word(fp, word), "i")) { + if (cube.fullset != NULL) { + (void) fprintf(stderr, "extra .i ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (fscanf(fp, "%d", &cube.num_binary_vars) != 1) + fatal("error reading .i"); + cube.num_vars = cube.num_binary_vars + 1; + cube.part_size = ALLOC(int, cube.num_vars); + } + + /* .o gives the cube output size (binary-functions only) */ + } else if (equal(word, "o")) { + if (cube.fullset != NULL) { + (void) fprintf(stderr, "extra .o ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (cube.part_size == NULL) + fatal(".o cannot appear before .i"); + if (fscanf(fp, "%d", &(cube.part_size[cube.num_vars-1]))!=1) + fatal("error reading .o"); + cube_setup(); + PLA_labels(PLA); + } + + /* .mv gives the cube size for a multiple-valued function */ + } else if (equal(word, "mv")) { + if (cube.fullset != NULL) { + (void) fprintf(stderr, "extra .mv ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (cube.part_size != NULL) + fatal("cannot mix .i and .mv"); + if (fscanf(fp,"%d %d", + &cube.num_vars,&cube.num_binary_vars) != 2) + fatal("error reading .mv"); + if (cube.num_binary_vars < 0) +fatal("num_binary_vars (second field of .mv) cannot be negative"); + if (cube.num_vars < cube.num_binary_vars) + fatal( +"num_vars (1st field of .mv) must exceed num_binary_vars (2nd field of .mv)"); + cube.part_size = ALLOC(int, cube.num_vars); + for(var=cube.num_binary_vars; var < cube.num_vars; var++) + if (fscanf(fp, "%d", &(cube.part_size[var])) != 1) + fatal("error reading .mv"); + cube_setup(); + PLA_labels(PLA); + } + + /* .p gives the number of product terms -- we ignore it */ + } else if (equal(word, "p")) + (void) fscanf(fp, "%d", &np); + /* .e and .end specify the end of the file */ + else if (equal(word, "e") || equal(word,"end")) { + if (cube.fullset == NULL) { + /* fatal("unknown PLA size, need .i/.o or .mv");*/ + } else if (PLA->F == NULL) { + PLA->F = new_cover(10); + PLA->D = new_cover(10); + PLA->R = new_cover(10); + } + return; + } + /* .kiss turns on the kiss-hack option */ + else if (equal(word, "kiss")) + kiss = TRUE; + + /* .type specifies a logical type for the PLA */ + else if (equal(word, "type")) { + (void) get_word(fp, word); + for(i = 0; pla_types[i].key != 0; i++) + if (equal(pla_types[i].key + 1, word)) { + PLA->pla_type = pla_types[i].value; + break; + } + if (pla_types[i].key == 0) + fatal("unknown type in .type command"); + + /* parse the labels */ + } else if (equal(word, "ilb")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .ilb or .ob"); + if (PLA->label == NULL) + PLA_labels(PLA); + for(var = 0; var < cube.num_binary_vars; var++) { + (void) get_word(fp, word); + i = cube.first_part[var]; + PLA->label[i+1] = util_strsav(word); + PLA->label[i] = ALLOC(char, strlen(word) + 6); + (void) sprintf(PLA->label[i], "%s.bar", word); + } + } else if (equal(word, "ob")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .ilb or .ob"); + if (PLA->label == NULL) + PLA_labels(PLA); + var = cube.num_vars - 1; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + (void) get_word(fp, word); + PLA->label[i] = util_strsav(word); + } + /* .label assigns labels to multiple-valued variables */ + } else if (equal(word, "label")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .label"); + if (PLA->label == NULL) + PLA_labels(PLA); + if (fscanf(fp, "var=%d", &var) != 1) + fatal("Error reading labels"); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + (void) get_word(fp, word); + PLA->label[i] = util_strsav(word); + } + + } else if (equal(word, "symbolic")) { + symbolic_t *newlist, *p1; + if (read_symbolic(fp, PLA, word, &newlist)) { + if (PLA->symbolic == NIL(symbolic_t)) { + PLA->symbolic = newlist; + } else { + for(p1=PLA->symbolic;p1->next!=NIL(symbolic_t); + p1=p1->next){ + } + p1->next = newlist; + } + } else { + fatal("error reading .symbolic"); + } + + } else if (equal(word, "symbolic-output")) { + symbolic_t *newlist, *p1; + if (read_symbolic(fp, PLA, word, &newlist)) { + if (PLA->symbolic_output == NIL(symbolic_t)) { + PLA->symbolic_output = newlist; + } else { + for(p1=PLA->symbolic_output;p1->next!=NIL(symbolic_t); + p1=p1->next){ + } + p1->next = newlist; + } + } else { + fatal("error reading .symbolic-output"); + } + + /* .phase allows a choice of output phases */ + } else if (equal(word, "phase")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .phase"); + if (PLA->phase != NULL) { + (void) fprintf(stderr, "extra .phase ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + do ch = io_getc(fp); while (ch == ' ' || ch == '\t'); + (void) ungetc(ch, fp); + PLA->phase = set_save(cube.fullset); + last = cube.last_part[cube.num_vars - 1]; + for(i=cube.first_part[cube.num_vars - 1]; i <= last; i++) + if ((ch = io_getc(fp)) == '0') + set_remove(PLA->phase, i); + else if (ch != '1') + fatal("only 0 or 1 allowed in phase description"); + } + + /* .pair allows for bit-pairing input variables */ + } else if (equal(word, "pair")) { + int j; + if (PLA->pair != NULL) { + (void) fprintf(stderr, "extra .pair ignored\n"); + } else { + ppair pair; + PLA->pair = pair = ALLOC(pair_t, 1); + if (fscanf(fp, "%d", &(pair->cnt)) != 1) + fatal("syntax error in .pair"); + pair->var1 = ALLOC(int, pair->cnt); + pair->var2 = ALLOC(int, pair->cnt); + for(i = 0; i < pair->cnt; i++) { + (void) get_word(fp, word); + if (word[0] == '(') (void) strcpy(word, word+1); + if (label_index(PLA, word, &var, &j)) { + pair->var1[i] = var+1; + } else { + fatal("syntax error in .pair"); + } + + (void) get_word(fp, word); + if (word[strlen(word)-1] == ')') { + word[strlen(word)-1]='\0'; + } + if (label_index(PLA, word, &var, &j)) { + pair->var2[i] = var+1; + } else { + fatal("syntax error in .pair"); + } + } + } + + } else { + if (echo_unknown_commands) + (void) printf("%c%s ", ch, word); + skip_line(fp, stdout, echo_unknown_commands); + } + break; + default: + (void) ungetc(ch, fp); + if (cube.fullset == NULL) { +/* fatal("unknown PLA size, need .i/.o or .mv");*/ + if (echo_comments) + putchar('#'); + skip_line(fp, stdout, echo_comments); + break; + } + if (PLA->F == NULL) { + PLA->F = new_cover(10); + PLA->D = new_cover(10); + PLA->R = new_cover(10); + } + read_cube(fp, PLA); + } + goto loop; +} +/* + read_pla -- read a PLA from a file + + Input stops when ".e" is encountered in the input file, or upon reaching + end of file. + + Returns the PLA in the variable PLA after massaging the "symbolic" + representation into a positional cube notation of the ON-set, OFF-set, + and the DC-set. + + needs_dcset and needs_offset control the computation of the OFF-set + and DC-set (i.e., if either needs to be computed, then it will be + computed via complement only if the corresponding option is TRUE.) + pla_type specifies the interpretation to be used when reading the + PLA. + + The phase of the output functions is adjusted according to the + global option "pos" or according to an imbedded .phase option in + the input file. Note that either phase option implies that the + OFF-set be computed regardless of whether the caller needs it + explicitly or not. + + Bit pairing of the binary variables is performed according to an + imbedded .pair option in the input file. + + The global cube structure also reflects the sizes of the PLA which + was just read. If these fields have already been set, then any + subsequent PLA must conform to these sizes. + + The global flags trace and summary control the output produced + during the read. + + Returns a status code as a result: + EOF (-1) : End of file reached before any data was read + > 0 : Operation successful +*/ + +int read_pla(fp, needs_dcset, needs_offset, pla_type, PLA_return) +IN FILE *fp; +IN bool needs_dcset, needs_offset; +IN int pla_type; +OUT pPLA *PLA_return; +{ + pPLA PLA; + int i, second, third; + long time; + cost_t cost; + + /* Allocate and initialize the PLA structure */ + PLA = *PLA_return = new_PLA(); + PLA->pla_type = pla_type; + + /* Read the pla */ + time = ptime(); + parse_pla(fp, PLA); + + /* Check for nothing on the file -- implies reached EOF */ + if (PLA->F == NULL) { + return EOF; + } + + /* This hack merges the next-state field with the outputs */ + for(i = 0; i < cube.num_vars; i++) { + cube.part_size[i] = ABS(cube.part_size[i]); + } + if (kiss) { + third = cube.num_vars - 3; + second = cube.num_vars - 2; + if (cube.part_size[third] != cube.part_size[second]) { + (void) fprintf(stderr," with .kiss option, third to last and second\n"); + (void) fprintf(stderr, "to last variables must be the same size.\n"); + return EOF; + } + for(i = 0; i < cube.part_size[second]; i++) { + PLA->label[i + cube.first_part[second]] = + util_strsav(PLA->label[i + cube.first_part[third]]); + } + cube.part_size[second] += cube.part_size[cube.num_vars-1]; + cube.num_vars--; + setdown_cube(); + cube_setup(); + } + + if (trace) { + totals(time, READ_TIME, PLA->F, &cost); + } + + /* Decide how to break PLA into ON-set, OFF-set and DC-set */ + time = ptime(); + if (pos || PLA->phase != NULL || PLA->symbolic_output != NIL(symbolic_t)) { + needs_offset = TRUE; + } + if (needs_offset && (PLA->pla_type==F_type || PLA->pla_type==FD_type)) { + free_cover(PLA->R); + PLA->R = complement(cube2list(PLA->F, PLA->D)); + } else if (needs_dcset && PLA->pla_type == FR_type) { + pcover X; + free_cover(PLA->D); + /* hack, why not? */ + X = d1merge(sf_join(PLA->F, PLA->R), cube.num_vars - 1); + PLA->D = complement(cube1list(X)); + free_cover(X); + } else if (PLA->pla_type == R_type || PLA->pla_type == DR_type) { + free_cover(PLA->F); + PLA->F = complement(cube2list(PLA->D, PLA->R)); + } + + if (trace) { + totals(time, COMPL_TIME, PLA->R, &cost); + } + + /* Check for phase rearrangement of the functions */ + if (pos) { + pcover onset = PLA->F; + PLA->F = PLA->R; + PLA->R = onset; + PLA->phase = new_cube(); + (void) set_diff(PLA->phase, cube.fullset, cube.var_mask[cube.num_vars-1]); + } else if (PLA->phase != NULL) { + (void) set_phase(PLA); + } + + /* Setup minimization for two-bit decoders */ + if (PLA->pair != (ppair) NULL) { + set_pair(PLA); + } + + if (PLA->symbolic != NIL(symbolic_t)) { + EXEC(map_symbolic(PLA), "MAP-INPUT ", PLA->F); + } + if (PLA->symbolic_output != NIL(symbolic_t)) { + EXEC(map_output_symbolic(PLA), "MAP-OUTPUT ", PLA->F); + if (needs_offset) { + free_cover(PLA->R); +EXECUTE(PLA->R=complement(cube2list(PLA->F,PLA->D)), COMPL_TIME, PLA->R, cost); + } + } + + return 1; +} + +void PLA_summary(PLA) +pPLA PLA; +{ + int var, i; + symbolic_list_t *p2; + symbolic_t *p1; + + (void) printf("# PLA is %s", PLA->filename); + if (cube.num_binary_vars == cube.num_vars - 1) + (void) printf(" with %d inputs and %d outputs\n", + cube.num_binary_vars, cube.part_size[cube.num_vars - 1]); + else { + (void) printf(" with %d variables (%d binary, mv sizes", + cube.num_vars, cube.num_binary_vars); + for(var = cube.num_binary_vars; var < cube.num_vars; var++) + (void) printf(" %d", cube.part_size[var]); + (void) printf(")\n"); + } + (void) printf("# ON-set cost is %s\n", print_cost(PLA->F)); + (void) printf("# OFF-set cost is %s\n", print_cost(PLA->R)); + (void) printf("# DC-set cost is %s\n", print_cost(PLA->D)); + if (PLA->phase != NULL) + (void) printf("# phase is %s\n", pc1(PLA->phase)); + if (PLA->pair != NULL) { + (void) printf("# two-bit decoders:"); + for(i = 0; i < PLA->pair->cnt; i++) + (void) printf(" (%d %d)", PLA->pair->var1[i], PLA->pair->var2[i]); + (void) printf("\n"); + } + if (PLA->symbolic != NIL(symbolic_t)) { + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + (void) printf("# symbolic: "); + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + (void) printf(" %d", p2->variable); + } + (void) printf("\n"); + } + } + if (PLA->symbolic_output != NIL(symbolic_t)) { + for(p1 = PLA->symbolic_output; p1 != NIL(symbolic_t); p1 = p1->next) { + (void) printf("# output symbolic: "); + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + (void) printf(" %d", p2->pos); + } + (void) printf("\n"); + } + } + (void) fflush(stdout); +} + + +pPLA new_PLA() +{ + pPLA PLA; + + PLA = ALLOC(PLA_t, 1); + PLA->F = PLA->D = PLA->R = (pcover) NULL; + PLA->phase = (pcube) NULL; + PLA->pair = (ppair) NULL; + PLA->label = (char **) NULL; + PLA->filename = (char *) NULL; + PLA->pla_type = 0; + PLA->symbolic = NIL(symbolic_t); + PLA->symbolic_output = NIL(symbolic_t); + return PLA; +} + + +PLA_labels(PLA) +pPLA PLA; +{ + int i; + + PLA->label = ALLOC(char *, cube.size); + for(i = 0; i < cube.size; i++) + PLA->label[i] = (char *) NULL; +} + + +void free_PLA(PLA) +pPLA PLA; +{ + symbolic_list_t *p2, *p2next; + symbolic_t *p1, *p1next; + int i; + + if (PLA->F != (pcover) NULL) + free_cover(PLA->F); + if (PLA->R != (pcover) NULL) + free_cover(PLA->R); + if (PLA->D != (pcover) NULL) + free_cover(PLA->D); + if (PLA->phase != (pcube) NULL) + free_cube(PLA->phase); + if (PLA->pair != (ppair) NULL) { + FREE(PLA->pair->var1); + FREE(PLA->pair->var2); + FREE(PLA->pair); + } + if (PLA->label != NULL) { + for(i = 0; i < cube.size; i++) + if (PLA->label[i] != NULL) + FREE(PLA->label[i]); + FREE(PLA->label); + } + if (PLA->filename != NULL) { + FREE(PLA->filename); + } + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1next) { + for(p2 = p1->symbolic_list; p2 != NIL(symbolic_list_t); p2 = p2next) { + p2next = p2->next; + FREE(p2); + } + p1next = p1->next; + FREE(p1); + } + PLA->symbolic = NIL(symbolic_t); + for(p1 = PLA->symbolic_output; p1 != NIL(symbolic_t); p1 = p1next) { + for(p2 = p1->symbolic_list; p2 != NIL(symbolic_list_t); p2 = p2next) { + p2next = p2->next; + FREE(p2); + } + p1next = p1->next; + FREE(p1); + } + PLA->symbolic_output = NIL(symbolic_t); + FREE(PLA); +} + + +int read_symbolic(fp, PLA, word, retval) +FILE *fp; +pPLA PLA; +char *word; /* scratch string for words */ +symbolic_t **retval; +{ + symbolic_list_t *listp, *prev_listp; + symbolic_label_t *labelp, *prev_labelp; + symbolic_t *newlist; + int i, var; + + newlist = ALLOC(symbolic_t, 1); + newlist->next = NIL(symbolic_t); + newlist->symbolic_list = NIL(symbolic_list_t); + newlist->symbolic_list_length = 0; + newlist->symbolic_label = NIL(symbolic_label_t); + newlist->symbolic_label_length = 0; + prev_listp = NIL(symbolic_list_t); + prev_labelp = NIL(symbolic_label_t); + + for(;;) { + (void) get_word(fp, word); + if (equal(word, ";")) + break; + if (label_index(PLA, word, &var, &i)) { + listp = ALLOC(symbolic_list_t, 1); + listp->variable = var; + listp->pos = i; + listp->next = NIL(symbolic_list_t); + if (prev_listp == NIL(symbolic_list_t)) { + newlist->symbolic_list = listp; + } else { + prev_listp->next = listp; + } + prev_listp = listp; + newlist->symbolic_list_length++; + } else { + return FALSE; + } + } + + for(;;) { + (void) get_word(fp, word); + if (equal(word, ";")) + break; + labelp = ALLOC(symbolic_label_t, 1); + labelp->label = util_strsav(word); + labelp->next = NIL(symbolic_label_t); + if (prev_labelp == NIL(symbolic_label_t)) { + newlist->symbolic_label = labelp; + } else { + prev_labelp->next = labelp; + } + prev_labelp = labelp; + newlist->symbolic_label_length++; + } + + *retval = newlist; + return TRUE; +} + + +int label_index(PLA, word, varp, ip) +pPLA PLA; +char *word; +int *varp; +int *ip; +{ + int var, i; + + if (PLA->label == NIL(char *) || PLA->label[0] == NIL(char)) { + if (sscanf(word, "%d", varp) == 1) { + *ip = *varp; + return TRUE; + } + } else { + for(var = 0; var < cube.num_vars; var++) { + for(i = 0; i < cube.part_size[var]; i++) { + if (equal(PLA->label[cube.first_part[var]+i], word)) { + *varp = var; + *ip = i; + return TRUE; + } + } + } + } + return FALSE; +} diff --git a/sis/espresso/cvrm.c b/sis/espresso/cvrm.c new file mode 100644 index 0000000..f12ef5a --- /dev/null +++ b/sis/espresso/cvrm.c @@ -0,0 +1,539 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/cvrm.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:20 $ + * + */ +/* + module: cvrm.c + Purpose: miscellaneous cover manipulation + a) verify two covers are equal, check consistency of a cover + b) unravel a multiple-valued cover into minterms + c) sort covers +*/ + +#include "espresso.h" + + +static void cb_unravel(c, start, end, startbase, B1) +IN register pcube c; +IN int start, end; +IN pcube startbase; +INOUT pcover B1; +{ + pcube base = cube.temp[0], p, last; + int expansion, place, skip, var, size, offset; + register int i, j, k, n; + + /* Determine how many cubes it will blow up into, and create a mask + for those parts that have only a single coordinate + */ + expansion = 1; + (void) set_copy(base, startbase); + for(var = start; var <= end; var++) { + if ((size = set_dist(c, cube.var_mask[var])) < 2) { + (void) set_or(base, base, cube.var_mask[var]); + } else { + expansion *= size; + } + } + (void) set_and(base, c, base); + + /* Add the unravelled sets starting at the last element of B1 */ + offset = B1->count; + B1->count += expansion; + foreach_remaining_set(B1, last, GETSET(B1, offset-1), p) { + INLINEset_copy(p, base); + } + + place = expansion; + for(var = start; var <= end; var++) { + if ((size = set_dist(c, cube.var_mask[var])) > 1) { + skip = place; + place = place / size; + n = 0; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (is_in_set(c, i)) { + for(j = n; j < expansion; j += skip) { + for(k = 0; k < place; k++) { + p = GETSET(B1, j+k+offset); + (void) set_insert(p, i); + } + } + n += place; + } + } + } + } +} + + +pcover unravel_range(B, start, end) +IN pcover B; +IN int start, end; +{ + pcover B1; + int var, total_size, expansion, size; + register pcube p, last, startbase = cube.temp[1]; + + /* Create the starting base for those variables not being unravelled */ + (void) set_copy(startbase, cube.emptyset); + for(var = 0; var < start; var++) + (void) set_or(startbase, startbase, cube.var_mask[var]); + for(var = end+1; var < cube.num_vars; var++) + (void) set_or(startbase, startbase, cube.var_mask[var]); + + /* Determine how many cubes it will blow up into */ + total_size = 0; + foreach_set(B, last, p) { + expansion = 1; + for(var = start; var <= end; var++) + if ((size = set_dist(p, cube.var_mask[var])) >= 2) + if ((expansion *= size) > 1000000) + fatal("unreasonable expansion in unravel"); + total_size += expansion; + } + + /* We can now allocate a cover of exactly the correct size */ + B1 = new_cover(total_size); + foreach_set(B, last, p) { + cb_unravel(p, start, end, startbase, B1); + } + free_cover(B); + return B1; +} + + +pcover unravel(B, start) +IN pcover B; +IN int start; +{ + return unravel_range(B, start, cube.num_vars-1); +} + +/* lex_sort -- sort cubes in a standard lexical fashion */ +pcover lex_sort(T) +pcover T; +{ + pcover T1 = sf_unlist(sf_sort(T, lex_order), T->count, T->sf_size); + free_cover(T); + return T1; +} + + +/* size_sort -- sort cubes by their size */ +pcover size_sort(T) +pcover T; +{ + pcover T1 = sf_unlist(sf_sort(T, descend), T->count, T->sf_size); + free_cover(T); + return T1; +} + + +/* mini_sort -- sort cubes according to the heuristics of mini */ +pcover mini_sort(F, compare) +pcover F; +int (*compare)(); +{ + register int *count, cnt, n = cube.size, i; + register pcube p, last; + pcover F_sorted; + pcube *F1; + + /* Perform a column sum over the set family */ + count = sf_count(F); + + /* weight is "inner product of the cube and the column sums" */ + foreach_set(F, last, p) { + cnt = 0; + for(i = 0; i < n; i++) + if (is_in_set(p, i)) + cnt += count[i]; + PUTSIZE(p, cnt); + } + FREE(count); + + /* use qsort to sort the array */ + qsort((char *) (F1 = sf_list(F)), F->count, sizeof(pcube), compare); + F_sorted = sf_unlist(F1, F->count, F->sf_size); + free_cover(F); + + return F_sorted; +} + + +/* sort_reduce -- Espresso strategy for ordering the cubes before reduction */ +pcover sort_reduce(T) +IN pcover T; +{ + register pcube p, last, largest = NULL; + register int bestsize = -1, size, n = cube.num_vars; + pcover T_sorted; + pcube *T1; + + if (T->count == 0) + return T; + + /* find largest cube */ + foreach_set(T, last, p) + if ((size = set_ord(p)) > bestsize) + largest = p, bestsize = size; + + foreach_set(T, last, p) + PUTSIZE(p, ((n - cdist(largest,p)) << 7) + MIN(set_ord(p),127)); + + qsort((char *) (T1 = sf_list(T)), T->count, sizeof(pcube), (int (*)()) descend); + T_sorted = sf_unlist(T1, T->count, T->sf_size); + free_cover(T); + + return T_sorted; +} + +pcover random_order(F) +register pcover F; +{ + pset temp; + register int i, k; +#ifdef RANDOM + long random(); +#endif + + temp = set_new(F->sf_size); + for(i = F->count - 1; i > 0; i--) { + /* Choose a random number between 0 and i */ +#ifdef RANDOM + k = random() % i; +#else + /* this is not meant to be really used; just provides an easy + "out" if random() and srandom() aren't around + */ + k = (i*23 + 997) % i; +#endif + /* swap sets i and k */ + (void) set_copy(temp, GETSET(F, k)); + (void) set_copy(GETSET(F, k), GETSET(F, i)); + (void) set_copy(GETSET(F, i), temp); + } + set_free(temp); + return F; +} + +/* + * cubelist_partition -- take a cubelist T and see if it has any components; + * if so, return cubelist's of the two partitions A and B; the return value + * is the size of the partition; if not, A and B + * are undefined and the return value is 0 + */ +int cubelist_partition(T, A, B, comp_debug) +pcube *T; /* a list of cubes */ +pcube **A, **B; /* cubelist of partition and remainder */ +unsigned int comp_debug; +{ + register pcube *T1, p, seed, cof; + pcube *A1, *B1; + bool change; + int count, numcube; + + numcube = CUBELISTSIZE(T); + + /* Mark all cubes -- covered cubes belong to the partition */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + RESET(p, COVERED); + } + + /* + * Extract a partition from the cubelist T; start with the first cube as a + * seed, and then pull in all cubes which share a variable with the seed; + * iterate until no new cubes are brought into the partition. + */ + seed = set_save(T[2]); + cof = T[0]; + SET(T[2], COVERED); + count = 1; + + do { + change = FALSE; + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (! TESTP(p, COVERED) && ccommon(p, seed, cof)) { + INLINEset_and(seed, seed, p); + SET(p, COVERED); + change = TRUE; + count++; + } + + } + } while (change); + + set_free(seed); + + if (comp_debug) { + (void) printf("COMPONENT_REDUCTION: split into %d %d\n", + count, numcube - count); + } + + if (count != numcube) { + /* Allocate and setup the cubelist's for the two partitions */ + *A = A1 = ALLOC(pcube, numcube+3); + *B = B1 = ALLOC(pcube, numcube+3); + (*A)[0] = set_save(T[0]); + (*B)[0] = set_save(T[0]); + A1 = *A + 2; + B1 = *B + 2; + + /* Loop over the cubes in T and distribute to A and B */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (TESTP(p, COVERED)) { + *A1++ = p; + } else { + *B1++ = p; + } + } + + /* Stuff needed at the end of the cubelist's */ + *A1++ = NULL; + (*A)[1] = (pcube) A1; + *B1++ = NULL; + (*B)[1] = (pcube) B1; + } + + return numcube - count; +} + +/* + * quick cofactor against a single output function + */ +pcover cof_output(T, i) +pcover T; +register int i; +{ + pcover T1; + register pcube p, last, pdest, mask; + + mask = cube.var_mask[cube.output]; + T1 = new_cover(T->count); + foreach_set(T, last, p) { + if (is_in_set(p, i)) { + pdest = GETSET(T1, T1->count++); + INLINEset_or(pdest, p, mask); + RESET(pdest, PRIME); + } + } + return T1; +} + + +/* + * quick intersection against a single output function + */ +pcover uncof_output(T, i) +pcover T; +int i; +{ + register pcube p, last, mask; + + if (T == NULL) { + return T; + } + + mask = cube.var_mask[cube.output]; + foreach_set(T, last, p) { + INLINEset_diff(p, p, mask); + set_insert(p, i); + } + return T; +} + + +/* + * A generic routine to perform an operation for each output function + * + * func() is called with a PLA for each output function (with the output + * part effectively removed). + * func1() is called after reforming the equivalent output function + * + * Each function returns TRUE if process is to continue + */ +foreach_output_function(PLA, func, func1) +pPLA PLA; +int (*func)(); +int (*func1)(); +{ + pPLA PLA1; + int i; + + /* Loop for each output function */ + for(i = 0; i < cube.part_size[cube.output]; i++) { + + /* cofactor on the output part */ + PLA1 = new_PLA(); + PLA1->F = cof_output(PLA->F, i + cube.first_part[cube.output]); + PLA1->R = cof_output(PLA->R, i + cube.first_part[cube.output]); + PLA1->D = cof_output(PLA->D, i + cube.first_part[cube.output]); + + /* Call a routine to do something with the cover */ + if ((*func)(PLA1, i) == 0) { + free_PLA(PLA1); + return; + } + + /* intersect with the particular output part again */ + PLA1->F = uncof_output(PLA1->F, i + cube.first_part[cube.output]); + PLA1->R = uncof_output(PLA1->R, i + cube.first_part[cube.output]); + PLA1->D = uncof_output(PLA1->D, i + cube.first_part[cube.output]); + + /* Call a routine to do something with the final result */ + if ((*func1)(PLA1, i) == 0) { + free_PLA(PLA1); + return; + } + + /* Cleanup for next go-around */ + free_PLA(PLA1); + + + } +} + +static pcover Fmin; +static pcube phase; + +/* + * minimize each output function individually + */ +void so_espresso(PLA, strategy) +pPLA PLA; +int strategy; +{ + Fmin = new_cover(PLA->F->count); + if (strategy == 0) { + foreach_output_function(PLA, so_do_espresso, so_save); + } else { + foreach_output_function(PLA, so_do_exact, so_save); + } + sf_free(PLA->F); + PLA->F = Fmin; +} + + +/* + * minimize each output function, choose function or complement based on the + * one with the fewer number of terms + */ +void so_both_espresso(PLA, strategy) +pPLA PLA; +int strategy; +{ + phase = set_save(cube.fullset); + Fmin = new_cover(PLA->F->count); + if (strategy == 0) { + foreach_output_function(PLA, so_both_do_espresso, so_both_save); + } else { + foreach_output_function(PLA, so_both_do_exact, so_both_save); + } + sf_free(PLA->F); + PLA->F = Fmin; + PLA->phase = phase; +} + + +int so_do_espresso(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + skip_make_sparse = 1; + (void) sprintf(word, "ESPRESSO-POS(%d)", i); + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), word, PLA->F); + return 1; +} + + +int so_do_exact(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + skip_make_sparse = 1; + (void) sprintf(word, "EXACT-POS(%d)", i); + EXEC_S(PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1), word, PLA->F); + return 1; +} + + +/*ARGSUSED*/ +int so_save(PLA, i) +pPLA PLA; +int i; +{ + Fmin = sf_append(Fmin, PLA->F); /* disposes of PLA->F */ + PLA->F = NULL; + return 1; +} + + +int so_both_do_espresso(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + (void) sprintf(word, "ESPRESSO-POS(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), word, PLA->F); + + /* minimize the single-output function (off-set) */ + (void) sprintf(word, "ESPRESSO-NEG(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->R = espresso(PLA->R, PLA->D, PLA->F), word, PLA->R); + + return 1; +} + + +int so_both_do_exact(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + (void) sprintf(word, "EXACT-POS(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1), word, PLA->F); + + /* minimize the single-output function (off-set) */ + (void) sprintf(word, "EXACT-NEG(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->R = minimize_exact(PLA->R, PLA->D, PLA->F, 1), word, PLA->R); + + return 1; +} + + +int so_both_save(PLA, i) +pPLA PLA; +int i; +{ + if (PLA->F->count > PLA->R->count) { + sf_free(PLA->F); + PLA->F = PLA->R; + PLA->R = NULL; + i += cube.first_part[cube.output]; + set_remove(phase, i); + } else { + sf_free(PLA->R); + PLA->R = NULL; + } + Fmin = sf_append(Fmin, PLA->F); + PLA->F = NULL; + return 1; +} diff --git a/sis/espresso/cvrmisc.c b/sis/espresso/cvrmisc.c new file mode 100644 index 0000000..0b1d9bc --- /dev/null +++ b/sis/espresso/cvrmisc.c @@ -0,0 +1,142 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/cvrmisc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + + +/* cost -- compute the cost of a cover */ +void cover_cost(F, cost) +IN pcover F; +INOUT pcost cost; +{ + register pcube p, last; + pcube *T; + int var; + + /* use the routine used by cofactor to decide splitting variables */ + massive_count(T = cube1list(F)); + free_cubelist(T); + + cost->cubes = F->count; + cost->total = cost->in = cost->out = cost->mv = cost->primes = 0; + + /* Count transistors (zeros) for each binary variable (inputs) */ + for(var = 0; var < cube.num_binary_vars; var++) + cost->in += cdata.var_zeros[var]; + + /* Count transistors for each mv variable based on sparse/dense */ + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) + if (cube.sparse[var]) + cost->mv += F->count * cube.part_size[var] - cdata.var_zeros[var]; + else + cost->mv += cdata.var_zeros[var]; + + /* Count the transistors (ones) for the output variable */ + if (cube.num_binary_vars != cube.num_vars) { + var = cube.num_vars - 1; + cost->out = F->count * cube.part_size[var] - cdata.var_zeros[var]; + } + + /* Count the number of nonprime cubes */ + foreach_set(F, last, p) + cost->primes += TESTP(p, PRIME) != 0; + + /* Count the total number of literals */ + cost->total = cost->in + cost->out + cost->mv; +} + + +/* fmt_cost -- return a string which reports the "cost" of a cover */ +char *fmt_cost(cost) +IN pcost cost; +{ + static char s[200]; + + if (cube.num_binary_vars == cube.num_vars - 1) + (void) sprintf(s, "c=%d(%d) in=%d out=%d tot=%d", + cost->cubes, cost->cubes - cost->primes, cost->in, + cost->out, cost->total); + else + (void) sprintf(s, "c=%d(%d) in=%d mv=%d out=%d", + cost->cubes, cost->cubes - cost->primes, cost->in, + cost->mv, cost->out); + return s; +} + + +char *print_cost(F) +IN pcover F; +{ + cost_t cost; + cover_cost(F, &cost); + return fmt_cost(&cost); +} + + +/* copy_cost -- copy a cost function from s to d */ +void copy_cost(s, d) +pcost s, d; +{ + d->cubes = s->cubes; + d->in = s->in; + d->out = s->out; + d->mv = s->mv; + d->total = s->total; + d->primes = s->primes; +} + + +/* size_stamp -- print single line giving the size of a cover */ +void size_stamp(T, name) +IN pcover T; +IN char *name; +{ + (void) printf("# %s\tCost is %s\n", name, print_cost(T)); + (void) fflush(stdout); +} + + +/* print_trace -- print a line reporting size and time after a function */ +void print_trace(T, name, time) +pcover T; +char *name; +long time; +{ + (void) printf("# %s\tTime was %s, cost is %s\n", + name, print_time(time), print_cost(T)); + (void) fflush(stdout); +} + + +/* totals -- add time spent in the function into the totals */ +void totals(time, i, T, cost) +long time; +int i; +pcover T; +pcost cost; +{ + time = ptime() - time; + total_time[i] += time; + total_calls[i]++; + cover_cost(T, cost); + if (trace) { + (void) printf("# %s\tTime was %s, cost is %s\n", + total_name[i], print_time(time), fmt_cost(cost)); + (void) fflush(stdout); + } +} + + +/* fatal -- report fatal error message and take a dive */ +void fatal(s) +char *s; +{ + (void) fprintf(stderr, "espresso: %s\n", s); + exit(1); +} diff --git a/sis/espresso/cvrout.c b/sis/espresso/cvrout.c new file mode 100644 index 0000000..f8e290b --- /dev/null +++ b/sis/espresso/cvrout.c @@ -0,0 +1,597 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/cvrout.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + module: cvrout.c + purpose: cube and cover output routines +*/ + +#include "espresso.h" + +void fprint_pla(fp, PLA, output_type) +INOUT FILE *fp; +IN pPLA PLA; +IN int output_type; +{ + int num; + register pcube last, p; + + if ((output_type & CONSTRAINTS_type) != 0) { + output_symbolic_constraints(fp, PLA, 0); + output_type &= ~ CONSTRAINTS_type; + if (output_type == 0) { + return; + } + } + + if ((output_type & SYMBOLIC_CONSTRAINTS_type) != 0) { + output_symbolic_constraints(fp, PLA, 1); + output_type &= ~ SYMBOLIC_CONSTRAINTS_type; + if (output_type == 0) { + return; + } + } + + if (output_type == PLEASURE_type) { + pls_output(PLA); + } else if (output_type == EQNTOTT_type) { + eqn_output(PLA); + } else if (output_type == KISS_type) { + kiss_output(fp, PLA); + } else { + fpr_header(fp, PLA, output_type); + + num = 0; + if (output_type & F_type) num += (PLA->F)->count; + if (output_type & D_type) num += (PLA->D)->count; + if (output_type & R_type) num += (PLA->R)->count; + (void) fprintf(fp, ".p %d\n", num); + + /* quick patch 01/17/85 to support TPLA ! */ + if (output_type == F_type) { + foreach_set(PLA->F, last, p) { + print_cube(fp, p, "01"); + } + (void) fprintf(fp, ".e\n"); + } else { + if (output_type & F_type) { + foreach_set(PLA->F, last, p) { + print_cube(fp, p, "~1"); + } + } + if (output_type & D_type) { + foreach_set(PLA->D, last, p) { + print_cube(fp, p, "~2"); + } + } + if (output_type & R_type) { + foreach_set(PLA->R, last, p) { + print_cube(fp, p, "~0"); + } + } + (void) fprintf(fp, ".end\n"); + } + } +} + +void fpr_header(fp, PLA, output_type) +FILE *fp; +pPLA PLA; +int output_type; +{ + register int i, var; + int first, last; + + /* .type keyword gives logical type */ + if (output_type != F_type) { + (void) fprintf(fp, ".type "); + if (output_type & F_type) putc('f', fp); + if (output_type & D_type) putc('d', fp); + if (output_type & R_type) putc('r', fp); + putc('\n', fp); + } + + /* Check for binary or multiple-valued labels */ + if (cube.num_mv_vars <= 1) { + (void) fprintf(fp, ".i %d\n", cube.num_binary_vars); + if (cube.output != -1) + (void) fprintf(fp, ".o %d\n", cube.part_size[cube.output]); + } else { + (void) fprintf(fp, ".mv %d %d", cube.num_vars, cube.num_binary_vars); + for(var = cube.num_binary_vars; var < cube.num_vars; var++) + (void) fprintf(fp, " %d", cube.part_size[var]); + (void) fprintf(fp, "\n"); + } + + /* binary valued labels */ + if (PLA->label != NIL(char *) && PLA->label[1] != NIL(char) + && cube.num_binary_vars > 0) { + (void) fprintf(fp, ".ilb"); + for(var = 0; var < cube.num_binary_vars; var++) + (void) fprintf(fp, " %s", INLABEL(var)); + putc('\n', fp); + } + + /* output-part (last multiple-valued variable) labels */ + if (PLA->label != NIL(char *) && + PLA->label[cube.first_part[cube.output]] != NIL(char) + && cube.output != -1) { + (void) fprintf(fp, ".ob"); + for(i = 0; i < cube.part_size[cube.output]; i++) + (void) fprintf(fp, " %s", OUTLABEL(i)); + putc('\n', fp); + } + + /* multiple-valued labels */ + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) { + first = cube.first_part[var]; + last = cube.last_part[var]; + if (PLA->label != NULL && PLA->label[first] != NULL) { + (void) fprintf(fp, ".label var=%d", var); + for(i = first; i <= last; i++) { + (void) fprintf(fp, " %s", PLA->label[i]); + } + putc('\n', fp); + } + } + + if (PLA->phase != (pcube) NULL) { + first = cube.first_part[cube.output]; + last = cube.last_part[cube.output]; + (void) fprintf(fp, "#.phase "); + for(i = first; i <= last; i++) + putc(is_in_set(PLA->phase,i) ? '1' : '0', fp); + (void) fprintf(fp, "\n"); + } +} + +void pls_output(PLA) +IN pPLA PLA; +{ + register pcube last, p; + + (void) printf(".option unmerged\n"); + makeup_labels(PLA); + pls_label(PLA, stdout); + pls_group(PLA, stdout); + (void) printf(".p %d\n", PLA->F->count); + foreach_set(PLA->F, last, p) { + print_expanded_cube(stdout, p, PLA->phase); + } + (void) printf(".end\n"); +} + + +void pls_group(PLA, fp) +pPLA PLA; +FILE *fp; +{ + int var, i, col, len; + + (void) fprintf(fp, "\n.group"); + col = 6; + for(var = 0; var < cube.num_vars-1; var++) { + (void) fprintf(fp, " ("), col += 2; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + len = strlen(PLA->label[i]); + if (col + len > 75) + (void) fprintf(fp, " \\\n"), col = 0; + else if (i != 0) + putc(' ', fp), col += 1; + (void) fprintf(fp, "%s", PLA->label[i]), col += len; + } + (void) fprintf(fp, ")"), col += 1; + } + (void) fprintf(fp, "\n"); +} + + +void pls_label(PLA, fp) +pPLA PLA; +FILE *fp; +{ + int var, i, col, len; + + (void) fprintf(fp, ".label"); + col = 6; + for(var = 0; var < cube.num_vars; var++) + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + len = strlen(PLA->label[i]); + if (col + len > 75) + (void) fprintf(fp, " \\\n"), col = 0; + else + putc(' ', fp), col += 1; + (void) fprintf(fp, "%s", PLA->label[i]), col += len; + } +} + + + +/* + eqntott output mode -- output algebraic equations +*/ +void eqn_output(PLA) +pPLA PLA; +{ + register pcube p, last; + register int i, var, col, len; + int x; + bool firstand, firstor; + + if (cube.output == -1) + fatal("Cannot have no-output function for EQNTOTT output mode"); + if (cube.num_mv_vars != 1) + fatal("Must have binary-valued function for EQNTOTT output mode"); + makeup_labels(PLA); + + /* Write a single equation for each output */ + for(i = 0; i < cube.part_size[cube.output]; i++) { + (void) printf("%s = ", OUTLABEL(i)); + col = strlen(OUTLABEL(i)) + 3; + firstor = TRUE; + + /* Write product terms for each cube in this output */ + foreach_set(PLA->F, last, p) + if (is_in_set(p, i + cube.first_part[cube.output])) { + if (firstor) + (void) printf("("), col += 1; + else + (void) printf(" | ("), col += 4; + firstor = FALSE; + firstand = TRUE; + + /* print out a product term */ + for(var = 0; var < cube.num_binary_vars; var++) + if ((x=GETINPUT(p, var)) != DASH) { + len = strlen(INLABEL(var)); + if (col+len > 72) + (void) printf("\n "), col = 4; + if (! firstand) + (void) printf("&"), col += 1; + firstand = FALSE; + if (x == ZERO) + (void) printf("!"), col += 1; + (void) printf("%s", INLABEL(var)), col += len; + } + (void) printf(")"), col += 1; + } + (void) printf(";\n\n"); + } +} + + +char *fmt_cube(c, out_map, s) +register pcube c; +register char *out_map, *s; +{ + register int i, var, last, len = 0; + + for(var = 0; var < cube.num_binary_vars; var++) { + s[len++] = "?01-" [GETINPUT(c, var)]; + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + s[len++] = ' '; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + s[len++] = "01" [is_in_set(c, i) != 0]; + } + } + if (cube.output != -1) { + last = cube.last_part[cube.output]; + s[len++] = ' '; + for(i = cube.first_part[cube.output]; i <= last; i++) { + s[len++] = out_map [is_in_set(c, i) != 0]; + } + } + s[len] = '\0'; + return s; +} + + +void print_cube(fp, c, out_map) +register FILE *fp; +register pcube c; +register char *out_map; +{ + register int i, var, ch; + int last; + + for(var = 0; var < cube.num_binary_vars; var++) { + ch = "?01-" [GETINPUT(c, var)]; + putc(ch, fp); + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "01" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + if (cube.output != -1) { + last = cube.last_part[cube.output]; + putc(' ', fp); + for(i = cube.first_part[cube.output]; i <= last; i++) { + ch = out_map [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + putc('\n', fp); +} + + +void print_expanded_cube(fp, c, phase) +register FILE *fp; +register pcube c; +pcube phase; +{ + register int i, var, ch; + char *out_map; + + for(var = 0; var < cube.num_binary_vars; var++) { + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "~1" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "1~" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + if (cube.output != -1) { + var = cube.num_vars - 1; + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (phase == (pcube) NULL || is_in_set(phase, i)) { + out_map = "~1"; + } else { + out_map = "~0"; + } + ch = out_map[is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + putc('\n', fp); +} + + +char *pc1(c) pcube c; +{static char s1[256];return fmt_cube(c, "01", s1);} +char *pc2(c) pcube c; +{static char s2[256];return fmt_cube(c, "01", s2);} + + +void debug_print(T, name, level) +pcube *T; +char *name; +int level; +{ + register pcube *T1, p, temp; + register int cnt; + + cnt = CUBELISTSIZE(T); + temp = new_cube(); + if (verbose_debug && level == 0) + (void) printf("\n"); + (void) printf("%s[%d]: ord(T)=%d\n", name, level, cnt); + if (verbose_debug) { + (void) printf("cofactor=%s\n", pc1(T[0])); + for(T1 = T+2, cnt = 1; (p = *T1++) != (pcube) NULL; cnt++) + (void) printf("%4d. %s\n", cnt, pc1(set_or(temp, p, T[0]))); + } + free_cube(temp); +} + + +void debug1_print(T, name, num) +pcover T; +char *name; +int num; +{ + register int cnt = 1; + register pcube p, last; + + if (verbose_debug && num == 0) + (void) printf("\n"); + (void) printf("%s[%d]: ord(T)=%d\n", name, num, T->count); + if (verbose_debug) + foreach_set(T, last, p) + (void) printf("%4d. %s\n", cnt++, pc1(p)); +} + + +void cprint(T) +pcover T; +{ + register pcube p, last; + + foreach_set(T, last, p) + (void) printf("%s\n", pc1(p)); +} + + +int makeup_labels(PLA) +pPLA PLA; +{ + int var, i, ind; + + if (PLA->label == (char **) NULL) + PLA_labels(PLA); + + for(var = 0; var < cube.num_vars; var++) + for(i = 0; i < cube.part_size[var]; i++) { + ind = cube.first_part[var] + i; + if (PLA->label[ind] == (char *) NULL) { + PLA->label[ind] = ALLOC(char, 15); + if (var < cube.num_binary_vars) + if ((i % 2) == 0) + (void) sprintf(PLA->label[ind], "v%d.bar", var); + else + (void) sprintf(PLA->label[ind], "v%d", var); + else + (void) sprintf(PLA->label[ind], "v%d.%d", var, i); + } + } +} + + +kiss_output(fp, PLA) +FILE *fp; +pPLA PLA; +{ + register pset last, p; + + foreach_set(PLA->F, last, p) { + kiss_print_cube(fp, PLA, p, "~1"); + } + foreach_set(PLA->D, last, p) { + kiss_print_cube(fp, PLA, p, "~2"); + } +} + + +kiss_print_cube(fp, PLA, p, out_string) +FILE *fp; +pPLA PLA; +pcube p; +char *out_string; +{ + register int i, var; + int part, x; + + for(var = 0; var < cube.num_binary_vars; var++) { + x = "?01-" [GETINPUT(p, var)]; + putc(x, fp); + } + + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + putc(' ', fp); + if (setp_implies(cube.var_mask[var], p)) { + putc('-', fp); + } else { + part = -1; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (is_in_set(p, i)) { + if (part != -1) { + fatal("more than 1 part in a symbolic variable\n"); + } + part = i; + } + } + if (part == -1) { + putc('~', fp); /* no parts, hope its an output ... */ + } else { + (void) fputs(PLA->label[part], fp); + } + } + } + + if ((var = cube.output) != -1) { + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + x = out_string [is_in_set(p, i) != 0]; + putc(x, fp); + } + } + + putc('\n', fp); +} + +output_symbolic_constraints(fp, PLA, output_symbolic) +FILE *fp; +pPLA PLA; +int output_symbolic; +{ + pset_family A; + register int i, j; + int size, var, npermute, *permute, *weight, noweight; + + if ((cube.num_vars - cube.num_binary_vars) <= 1) { + return; + } + makeup_labels(PLA); + + for(var=cube.num_binary_vars; var < cube.num_vars-1; var++) { + + /* pull out the columns for variable "var" */ + npermute = cube.part_size[var]; + permute = ALLOC(int, npermute); + for(i=0; i < npermute; i++) { + permute[i] = cube.first_part[var] + i; + } + A = sf_permute(sf_save(PLA->F), permute, npermute); + FREE(permute); + + + /* Delete the singletons and the full sets */ + noweight = 0; + for(i = 0; i < A->count; i++) { + size = set_ord(GETSET(A,i)); + if (size == 1 || size == A->sf_size) { + sf_delset(A, i--); + noweight++; + } + } + + + /* Count how many times each is duplicated */ + weight = ALLOC(int, A->count); + for(i = 0; i < A->count; i++) { + RESET(GETSET(A, i), COVERED); + } + for(i = 0; i < A->count; i++) { + weight[i] = 0; + if (! TESTP(GETSET(A,i), COVERED)) { + weight[i] = 1; + for(j = i+1; j < A->count; j++) { + if (setp_equal(GETSET(A,i), GETSET(A,j))) { + weight[i]++; + SET(GETSET(A,j), COVERED); + } + } + } + } + + + /* Print out the contraints */ + if (! output_symbolic) { + (void) fprintf(fp, + "# Symbolic constraints for variable %d (Numeric form)\n", var); + (void) fprintf(fp, "# unconstrained weight = %d\n", noweight); + (void) fprintf(fp, "num_codes=%d\n", cube.part_size[var]); + for(i = 0; i < A->count; i++) { + if (weight[i] > 0) { + (void) fprintf(fp, "weight=%d: ", weight[i]); + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(GETSET(A,i), j)) { + (void) fprintf(fp, " %d", j); + } + } + (void) fprintf(fp, "\n"); + } + } + } else { + (void) fprintf(fp, + "# Symbolic constraints for variable %d (Symbolic form)\n", var); + for(i = 0; i < A->count; i++) { + if (weight[i] > 0) { + (void) fprintf(fp, "# w=%d: (", weight[i]); + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(GETSET(A,i), j)) { + (void) fprintf(fp, " %s", + PLA->label[cube.first_part[var]+j]); + } + } + (void) fprintf(fp, " )\n"); + } + } + FREE(weight); + } + } +} diff --git a/sis/espresso/equiv.c b/sis/espresso/equiv.c new file mode 100644 index 0000000..5bf1b4b --- /dev/null +++ b/sis/espresso/equiv.c @@ -0,0 +1,94 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/equiv.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + + +find_equiv_outputs(PLA) +pPLA PLA; +{ + int i, j, ipart, jpart, some_equiv; + pcover *R, *F; + + some_equiv = FALSE; + + makeup_labels(PLA); + + F = ALLOC(pcover, cube.part_size[cube.output]); + R = ALLOC(pcover, cube.part_size[cube.output]); + + for(i = 0; i < cube.part_size[cube.output]; i++) { + ipart = cube.first_part[cube.output] + i; + R[i] = cof_output(PLA->R, ipart); + F[i] = complement(cube1list(R[i])); + } + + for(i = 0; i < cube.part_size[cube.output]-1; i++) { + for(j = i+1; j < cube.part_size[cube.output]; j++) { + ipart = cube.first_part[cube.output] + i; + jpart = cube.first_part[cube.output] + j; + + if (check_equiv(F[i], F[j])) { + (void) printf("# Outputs %d and %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(F[i], R[j])) { + (void) printf("# Outputs %d and NOT %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(R[i], F[j])) { + (void) printf("# Outputs NOT %d and %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(R[i], R[j])) { + (void) printf("# Outputs NOT %d and NOT %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } + } + } + + if (! some_equiv) { + (void) printf("# No outputs are equivalent\n"); + } + + for(i = 0; i < cube.part_size[cube.output]; i++) { + free_cover(F[i]); + free_cover(R[i]); + } + FREE(F); + FREE(R); +} + + + +int check_equiv(f1, f2) +pcover f1, f2; +{ + register pcube *f1list, *f2list; + register pcube p, last; + + f1list = cube1list(f1); + foreach_set(f2, last, p) { + if (! cube_is_covered(f1list, p)) { + return FALSE; + } + } + free_cubelist(f1list); + + f2list = cube1list(f2); + foreach_set(f1, last, p) { + if (! cube_is_covered(f2list, p)) { + return FALSE; + } + } + free_cubelist(f2list); + + return TRUE; +} diff --git a/sis/espresso/espresso.c b/sis/espresso/espresso.c new file mode 100644 index 0000000..b76695d --- /dev/null +++ b/sis/espresso/espresso.c @@ -0,0 +1,139 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/espresso.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + * Module: espresso.c + * Purpose: The main espresso algorithm + * + * Returns a minimized version of the ON-set of a function + * + * The following global variables affect the operation of Espresso: + * + * MISCELLANEOUS: + * trace + * print trace information as the minimization progresses + * + * remove_essential + * remove essential primes + * + * single_expand + * if true, stop after first expand/irredundant + * + * LAST_GASP or SUPER_GASP strategy: + * use_super_gasp + * uses the super_gasp strategy rather than last_gasp + * + * SETUP strategy: + * recompute_onset + * recompute onset using the complement before starting + * + * unwrap_onset + * unwrap the function output part before first expand + * + * MAKE_SPARSE strategy: + * force_irredundant + * iterates make_sparse to force a minimal solution (used + * indirectly by make_sparse) + * + * skip_make_sparse + * skip the make_sparse step (used by opo only) + */ + +#include "espresso.h" + +pcover espresso(F, D1, R) +pcover F, D1, R; +{ + pcover E, D, Fsave; + pset last, p; + cost_t cost, best_cost; + +begin: + Fsave = sf_save(F); /* save original function */ + D = sf_save(D1); /* make a scratch copy of D */ + + /* Setup has always been a problem */ + if (recompute_onset) { + EXEC(E = simplify(cube1list(F)), "SIMPLIFY ", E); + free_cover(F); + F = E; + } + cover_cost(F, &cost); + if (unwrap_onset && (cube.part_size[cube.num_vars - 1] > 1) + && (cost.out != cost.cubes*cube.part_size[cube.num_vars-1]) + && (cost.out < 5000)) + EXEC(F = sf_contain(unravel(F, cube.num_vars - 1)), "SETUP ", F); + + /* Initial expand and irredundant */ + foreach_set(F, last, p) { + RESET(p, PRIME); + } + EXECUTE(F = expand(F, R, FALSE), EXPAND_TIME, F, cost); + EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); + + if (! single_expand) { + if (remove_essential) { + EXECUTE(E = essential(&F, &D), ESSEN_TIME, E, cost); + } else { + E = new_cover(0); + } + + cover_cost(F, &cost); + do { + + /* Repeat inner loop until solution becomes "stable" */ + do { + copy_cost(&cost, &best_cost); + EXECUTE(F = reduce(F, D), REDUCE_TIME, F, cost); + EXECUTE(F = expand(F, R, FALSE), EXPAND_TIME, F, cost); + EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); + } while (cost.cubes < best_cost.cubes); + + /* Perturb solution to see if we can continue to iterate */ + copy_cost(&cost, &best_cost); + if (use_super_gasp) { + F = super_gasp(F, D, R, &cost); + if (cost.cubes >= best_cost.cubes) + break; + } else { + F = last_gasp(F, D, R, &cost); + } + + } while (cost.cubes < best_cost.cubes || + (cost.cubes == best_cost.cubes && cost.total < best_cost.total)); + + /* Append the essential cubes to F */ + F = sf_append(F, E); /* disposes of E */ + if (trace) size_stamp(F, "ADJUST "); + } + + /* Free the D which we used */ + free_cover(D); + + /* Attempt to make the PLA matrix sparse */ + if (! skip_make_sparse) { + F = make_sparse(F, D1, R); + } + + /* + * Check to make sure function is actually smaller !! + * This can only happen because of the initial unravel. If we fail, + * then run the whole thing again without the unravel. + */ + if (Fsave->count < F->count) { + free_cover(F); + F = Fsave; + unwrap_onset = FALSE; + goto begin; + } else { + free_cover(Fsave); + } + + return F; +} diff --git a/sis/espresso/espresso.h b/sis/espresso/espresso.h new file mode 100644 index 0000000..9353411 --- /dev/null +++ b/sis/espresso/espresso.h @@ -0,0 +1,796 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/espresso.h,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/13 22:25:21 $ + * + */ +/* + * espresso.h -- header file for Espresso-mv + */ + +#include "ansi.h" +#include +#include "sparse.h" +#include "mincov.h" +#include "util.h" + +#ifdef IBM_WATC +#define void int +#include "short.h" +#endif + +#ifdef IBMPC /* set default options for IBM/PC */ +#define NO_INLINE +#define BPI 16 +#endif + +/*-----THIS USED TO BE set.h----- */ + +/* + * set.h -- definitions for packed arrays of bits + * + * This header file describes the data structures which comprise a + * facility for efficiently implementing packed arrays of bits + * (otherwise known as sets, cf. Pascal). + * + * A set is a vector of bits and is implemented here as an array of + * unsigned integers. The low order bits of set[0] give the index of + * the last word of set data. The higher order bits of set[0] are + * used to store data associated with the set. The set data is + * contained in elements set[1] ... set[LOOP(set)] as a packed bit + * array. + * + * A family of sets is a two-dimensional matrix of bits and is + * implemented with the data type "set_family". + * + * BPI == 32 and BPI == 16 have been tested and work. + */ + + +/* Define host machine characteristics of "unsigned int" */ +#ifndef BPI +#define BPI 32 /* # bits per integer */ +#endif + +#if BPI == 32 +#define LOGBPI 5 /* log(BPI)/log(2) */ +#else +#define LOGBPI 4 /* log(BPI)/log(2) */ +#endif + +/* Define the set type */ +typedef unsigned int *pset; + +/* Define the set family type -- an array of sets */ +typedef struct set_family { + int wsize; /* Size of each set in 'ints' */ + int sf_size; /* User declared set size */ + int capacity; /* Number of sets allocated */ + int count; /* The number of sets in the family */ + int active_count; /* Number of "active" sets */ + pset data; /* Pointer to the set data */ + struct set_family *next; /* For garbage collection */ +} set_family_t, *pset_family; + +/* Macros to set and test single elements */ +#define WHICH_WORD(element) (((element) >> LOGBPI) + 1) +#define WHICH_BIT(element) ((element) & (BPI-1)) + +/* # of ints needed to allocate a set with "size" elements */ +#if BPI == 32 +#define SET_SIZE(size) ((size) <= BPI ? 2 : (WHICH_WORD((size)-1) + 1)) +#else +#define SET_SIZE(size) ((size) <= BPI ? 3 : (WHICH_WORD((size)-1) + 2)) +#endif + +/* + * Three fields are maintained in the first word of the set + * LOOP is the index of the last word used for set data + * LOOPCOPY is the index of the last word in the set + * SIZE is available for general use (e.g., recording # elements in set) + * NELEM retrieves the number of elements in the set + */ +#define LOOP(set) (set[0] & 0x03ff) +#define PUTLOOP(set, i) (set[0] &= ~0x03ff, set[0] |= (i)) +#if BPI == 32 +#define LOOPCOPY(set) LOOP(set) +#define SIZE(set) (set[0] >> 16) +#define PUTSIZE(set, size) (set[0] &= 0xffff, set[0] |= ((size) << 16)) +#else +#define LOOPCOPY(set) (LOOP(set) + 1) +#define SIZE(set) (set[LOOP(set)+1]) +#define PUTSIZE(set, size) ((set[LOOP(set)+1]) = (size)) +#endif + +#define NELEM(set) (BPI * LOOP(set)) +#define LOOPINIT(size) ((size <= BPI) ? 1 : WHICH_WORD((size)-1)) + +/* + * FLAGS store general information about the set + */ +#define SET(set, flag) (set[0] |= (flag)) +#define RESET(set, flag) (set[0] &= ~ (flag)) +#define TESTP(set, flag) (set[0] & (flag)) + +/* Flag definitions are ... */ +#define PRIME 0x8000 /* cube is prime */ +#define NONESSEN 0x4000 /* cube cannot be essential prime */ +#define ACTIVE 0x2000 /* cube is still active */ +#define REDUND 0x1000 /* cube is redundant(at this point) */ +#define COVERED 0x0800 /* cube has been covered */ +#define RELESSEN 0x0400 /* cube is relatively essential */ + +/* Most efficient way to look at all members of a set family */ +#define foreach_set(R, last, p)\ + for(p=R->data,last=p+R->count*R->wsize;pwsize) +#define foreach_remaining_set(R, last, pfirst, p)\ + for(p=pfirst+R->wsize,last=R->data+R->count*R->wsize;pwsize) +#define foreach_active_set(R, last, p)\ + foreach_set(R,last,p) if (TESTP(p, ACTIVE)) + +/* Another way that also keeps the index of the current set member in i */ +#define foreachi_set(R, i, p)\ + for(p=R->data,i=0;icount;p+=R->wsize,i++) +#define foreachi_active_set(R, i, p)\ + foreachi_set(R,i,p) if (TESTP(p, ACTIVE)) + +/* Looping over all elements in a set: + * foreach_set_element(pset p, int i, unsigned val, int base) { + * . + * . + * . + * } + */ +#define foreach_set_element(p, i, val, base) \ + for(i = LOOP(p); i > 0; ) \ + for(val = p[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) \ + if (val & 1) + +/* Return a pointer to a given member of a set family */ +#define GETSET(family, index) ((family)->data + (family)->wsize * (index)) + +/* Allocate and deallocate sets */ +#define set_new(size) set_clear(ALLOC(unsigned int, SET_SIZE(size)), size) +#define set_full(size) set_fill(ALLOC(unsigned int, SET_SIZE(size)), size) +#define set_save(r) set_copy(ALLOC(unsigned int, SET_SIZE(NELEM(r))), r) +#define set_free(r) FREE(r) + +/* Check for set membership, remove set element and insert set element */ +#define is_in_set(set, e) (set[WHICH_WORD(e)] & (1 << WHICH_BIT(e))) +#define set_remove(set, e) (set[WHICH_WORD(e)] &= ~ (1 << WHICH_BIT(e))) +#define set_insert(set, e) (set[WHICH_WORD(e)] |= 1 << WHICH_BIT(e)) + +/* Inline code substitution for those places that REALLY need it on a VAX */ +#ifdef NO_INLINE +#define INLINEset_copy(r, a) (void) set_copy(r,a) +#define INLINEset_clear(r, size) (void) set_clear(r, size) +#define INLINEset_fill(r, size) (void) set_fill(r, size) +#define INLINEset_and(r, a, b) (void) set_and(r, a, b) +#define INLINEset_or(r, a, b) (void) set_or(r, a, b) +#define INLINEset_diff(r, a, b) (void) set_diff(r, a, b) +#define INLINEset_ndiff(r, a, b, f) (void) set_ndiff(r, a, b, f) +#define INLINEset_xor(r, a, b) (void) set_xor(r, a, b) +#define INLINEset_xnor(r, a, b, f) (void) set_xnor(r, a, b, f) +#define INLINEset_merge(r, a, b, mask) (void) set_merge(r, a, b, mask) +#define INLINEsetp_implies(a, b, when_false) \ + if (! setp_implies(a,b)) when_false +#define INLINEsetp_disjoint(a, b, when_false) \ + if (! setp_disjoint(a,b)) when_false +#define INLINEsetp_equal(a, b, when_false) \ + if (! setp_equal(a,b)) when_false + +#else + +#define INLINEset_copy(r, a)\ + {register int i_=LOOPCOPY(a); do r[i_]=a[i_]; while (--i_>=0);} +#define INLINEset_clear(r, size)\ + {register int i_=LOOPINIT(size); *r=i_; do r[i_] = 0; while (--i_ > 0);} +#define INLINEset_fill(r, size)\ + {register int i_=LOOPINIT(size); *r=i_; \ + r[i_]=((unsigned int)(~0))>>(i_*BPI-size); while(--i_>0) r[i_]=~0;} +#define INLINEset_and(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] & b[i_]; while (--i_>0);} +#define INLINEset_or(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] | b[i_]; while (--i_>0);} +#define INLINEset_diff(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] & ~ b[i_]; while (--i_>0);} +#define INLINEset_ndiff(r, a, b, fullset)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = fullset[i_] & (a[i_] | ~ b[i_]); while (--i_>0);} +#ifdef IBM_WATC +#define INLINEset_xor(r, a, b) (void) set_xor(r, a, b) +#define INLINEset_xnor(r, a, b, f) (void) set_xnor(r, a, b, f) +#else +#define INLINEset_xor(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] ^ b[i_]; while (--i_>0);} +#define INLINEset_xnor(r, a, b, fullset)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = fullset[i_] & ~ (a[i_] ^ b[i_]); while (--i_>0);} +#endif +#define INLINEset_merge(r, a, b, mask)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = (a[i_]&mask[i_]) | (b[i_]&~mask[i_]); while (--i_>0);} +#define INLINEsetp_implies(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]&~b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} +#define INLINEsetp_disjoint(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]&b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} +#define INLINEsetp_equal(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]!=b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} + +#endif /* NO_INLINE */ + +#if BPI == 32 +#define count_ones(v)\ + (bit_count[v & 255] + bit_count[(v >> 8) & 255]\ + + bit_count[(v >> 16) & 255] + bit_count[(v >> 24) & 255]) +#else +#define count_ones(v) (bit_count[v & 255] + bit_count[(v >> 8) & 255]) +#endif + +/* Table for efficient bit counting */ +extern int bit_count[256]; +/*----- END OF set.h ----- */ + +/* Define a boolean type */ +#define bool int +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#define MAYBE 2 +#define print_bool(x) ((x) == 0 ? "FALSE" : ((x) == 1 ? "TRUE" : "MAYBE")) + +/* Map many cube/cover types/routines into equivalent set types/routines */ +#define pcube pset +#define new_cube() set_new(cube.size) +#define free_cube(r) set_free(r) +#define pcover pset_family +#define new_cover(i) sf_new(i, cube.size) +#define free_cover(r) sf_free(r) +#define free_cubelist(T) FREE(T[0]); FREE(T); + + +/* cost_t describes the cost of a cover */ +typedef struct cost_struct { + int cubes; /* number of cubes in the cover */ + int in; /* transistor count, binary-valued variables */ + int out; /* transistor count, output part */ + int mv; /* transistor count, multiple-valued vars */ + int total; /* total number of transistors */ + int primes; /* number of prime cubes */ +} cost_t, *pcost; + + +/* pair_t describes bit-paired variables */ +typedef struct pair_struct { + int cnt; + int *var1; + int *var2; +} pair_t, *ppair; + + +/* symbolic_list_t describes a single ".symbolic" line */ +typedef struct symbolic_list_struct { + int variable; + int pos; + struct symbolic_list_struct *next; +} symbolic_list_t; + + +/* symbolic_list_t describes a single ".symbolic" line */ +typedef struct symbolic_label_struct { + char *label; + struct symbolic_label_struct *next; +} symbolic_label_t; + + +/* symbolic_t describes a linked list of ".symbolic" lines */ +typedef struct symbolic_struct { + symbolic_list_t *symbolic_list; /* linked list of items */ + int symbolic_list_length; /* length of symbolic_list list */ + symbolic_label_t *symbolic_label; /* linked list of new names */ + int symbolic_label_length; /* length of symbolic_label list */ + struct symbolic_struct *next; +} symbolic_t; + + +/* PLA_t stores the logical representation of a PLA */ +typedef struct { + pcover F, D, R; /* on-set, off-set and dc-set */ + char *filename; /* filename */ + int pla_type; /* logical PLA format */ + pcube phase; /* phase to split into on-set and off-set */ + ppair pair; /* how to pair variables */ + char **label; /* labels for the columns */ + symbolic_t *symbolic; /* allow binary->symbolic mapping */ + symbolic_t *symbolic_output;/* allow symbolic output mapping */ +} PLA_t, *pPLA; + +#define equal(a,b) (strcmp(a,b) == 0) + +/* This is a hack which I wish I hadn't done, but too painful to change */ +#define CUBELISTSIZE(T) (((pcube *) T[1] - T) - 3) + +/* For documentation purposes */ +#define IN +#define OUT +#define INOUT + +/* The pla_type field describes the input and output format of the PLA */ +#define F_type 1 +#define D_type 2 +#define R_type 4 +#define PLEASURE_type 8 /* output format */ +#define EQNTOTT_type 16 /* output format algebraic eqns */ +#define KISS_type 128 /* output format kiss */ +#define CONSTRAINTS_type 256 /* output the constraints (numeric) */ +#define SYMBOLIC_CONSTRAINTS_type 512 /* output the constraints (symbolic) */ +#define FD_type (F_type | D_type) +#define FR_type (F_type | R_type) +#define DR_type (D_type | R_type) +#define FDR_type (F_type | D_type | R_type) + +/* Definitions for the debug variable */ +#define COMPL 0x0001 +#define ESSEN 0x0002 +#define EXPAND 0x0004 +#define EXPAND1 0x0008 +#define GASP 0x0010 +#define IRRED 0x0020 +#define REDUCE 0x0040 +#define REDUCE1 0x0080 +#define SPARSE 0x0100 +#define TAUT 0x0200 +#define EXACT 0x0400 +#define MINCOV 0x0800 +#define MINCOV1 0x1000 +#define SHARP 0x2000 +#define IRRED1 0x4000 + +#define ESPRESSO_VERSION\ + "UC Berkeley, Espresso Version #2.3, Release date 01/31/88" + +/* Define constants used for recording program statistics */ +#define TIME_COUNT 16 +#define READ_TIME 0 +#define COMPL_TIME 1 +#define ONSET_TIME 2 +#define ESSEN_TIME 3 +#define EXPAND_TIME 4 +#define IRRED_TIME 5 +#define REDUCE_TIME 6 +#define GEXPAND_TIME 7 +#define GIRRED_TIME 8 +#define GREDUCE_TIME 9 +#define PRIMES_TIME 10 +#define MINCOV_TIME 11 +#define MV_REDUCE_TIME 12 +#define RAISE_IN_TIME 13 +#define VERIFY_TIME 14 +#define WRITE_TIME 15 + + +/* For those who like to think about PLAs, macros to get at inputs/outputs */ +#define NUMINPUTS cube.num_binary_vars +#define NUMOUTPUTS cube.part_size[cube.num_vars - 1] + +#define POSITIVE_PHASE(pos)\ + (is_in_set(PLA->phase, cube.first_part[cube.output]+pos) != 0) + +#define INLABEL(var) PLA->label[cube.first_part[var] + 1] +#define OUTLABEL(pos) PLA->label[cube.first_part[cube.output] + pos] + +#define GETINPUT(c, pos)\ + ((c[WHICH_WORD(2*pos)] >> WHICH_BIT(2*pos)) & 3) +#define GETOUTPUT(c, pos)\ + (is_in_set(c, cube.first_part[cube.output] + pos) != 0) + +#define PUTINPUT(c, pos, value)\ + c[WHICH_WORD(2*pos)] = (c[WHICH_WORD(2*pos)] & ~(3 << WHICH_BIT(2*pos)))\ + | (value << WHICH_BIT(2*pos)) +#define PUTOUTPUT(c, pos, value)\ + c[WHICH_WORD(pos)] = (c[WHICH_WORD(pos)] & ~(1 << WHICH_BIT(pos)))\ + | (value << WHICH_BIT(pos)) + +#define TWO 3 +#define DASH 3 +#define ONE 2 +#define ZERO 1 + + +#define EXEC(fct, name, S)\ + {long t=ptime();fct;if(trace)print_trace(S,name,ptime()-t);} +#define EXEC_S(fct, name, S)\ + {long t=ptime();fct;if(summary)print_trace(S,name,ptime()-t);} +#define EXECUTE(fct,i,S,cost)\ + {long t=ptime();fct;totals(t,i,S,&(cost));} + +/* + * Global Variable Declarations + */ + +extern unsigned int debug; /* debug parameter */ +extern bool verbose_debug; /* -v: whether to print a lot */ +extern char *total_name[TIME_COUNT]; /* basic function names */ +extern long total_time[TIME_COUNT]; /* time spent in basic fcts */ +extern int total_calls[TIME_COUNT]; /* # calls to each fct */ + +extern bool echo_comments; /* turned off by -eat option */ +extern bool echo_unknown_commands; /* always true ?? */ +extern bool force_irredundant; /* -nirr command line option */ +extern bool skip_make_sparse; +extern bool kiss; /* -kiss command line option */ +extern bool pos; /* -pos command line option */ +extern bool print_solution; /* -x command line option */ +extern bool recompute_onset; /* -onset command line option */ +extern bool remove_essential; /* -ness command line option */ +extern bool single_expand; /* -fast command line option */ +extern bool summary; /* -s command line option */ +extern bool trace; /* -t command line option */ +extern bool unwrap_onset; /* -nunwrap command line option */ +extern bool use_random_order; /* -random command line option */ +extern bool use_super_gasp; /* -strong command line option */ +extern char *filename; /* filename PLA was read from */ +extern bool debug_exact_minimization; /* dumps info for -do exact */ + + +/* + * pla_types are the input and output types for reading/writing a PLA + */ +struct pla_types_struct { + char *key; + int value; +}; + + +/* + * The cube structure is a global structure which contains information + * on how a set maps into a cube -- i.e., number of parts per variable, + * number of variables, etc. Also, many fields are pre-computed to + * speed up various primitive operations. + */ +#define CUBE_TEMP 10 + +struct cube_struct { + int size; /* set size of a cube */ + int num_vars; /* number of variables in a cube */ + int num_binary_vars; /* number of binary variables */ + int *first_part; /* first element of each variable */ + int *last_part; /* first element of each variable */ + int *part_size; /* number of elements in each variable */ + int *first_word; /* first word for each variable */ + int *last_word; /* last word for each variable */ + pset binary_mask; /* Mask to extract binary variables */ + pset mv_mask; /* mask to get mv parts */ + pset *var_mask; /* mask to extract a variable */ + pset *temp; /* an array of temporary sets */ + pset fullset; /* a full cube */ + pset emptyset; /* an empty cube */ + unsigned int inmask; /* mask to get odd word of binary part */ + int inword; /* which word number for above */ + int *sparse; /* should this variable be sparse? */ + int num_mv_vars; /* number of multiple-valued variables */ + int output; /* which variable is "output" (-1 if none) */ +}; + +struct cdata_struct { + int *part_zeros; /* count of zeros for each element */ + int *var_zeros; /* count of zeros for each variable */ + int *parts_active; /* number of "active" parts for each var */ + bool *is_unate; /* indicates given var is unate */ + int vars_active; /* number of "active" variables */ + int vars_unate; /* number of unate variables */ + int best; /* best "binate" variable */ +}; + + +extern struct pla_types_struct pla_types[]; +extern struct cube_struct cube, temp_cube_save; +extern struct cdata_struct cdata, temp_cdata_save; + +#ifdef lint +#define DISJOINT 0x5555 +#else +#if BPI == 32 +#define DISJOINT 0x55555555 +#else +#define DISJOINT 0x5555 +#endif +#endif + +/* function declarations */ + +typedef int (*ESP_PFI)(); + +/* cofactor.c */ EXTERN int binate_split_select ARGS((pcube *, pcube, + pcube, int)); +/* cofactor.c */ EXTERN pcover cubeunlist ARGS((pcube *)); +/* cofactor.c */ EXTERN pcube *cofactor ARGS((pcube *, pcube)); +/* cofactor.c */ EXTERN pcube *cube1list ARGS((pcover)); +/* cofactor.c */ EXTERN pcube *cube2list ARGS((pcover, pcover)); +/* cofactor.c */ EXTERN pcube *cube3list ARGS((pcover, pcover, pcover)); +/* cofactor.c */ EXTERN pcube *scofactor ARGS((pcube *, pcube, int)); +/* cofactor.c */ EXTERN void massive_count ARGS((pcube *)); +/* compl.c */ EXTERN pcover complement ARGS((pcube *)); +/* compl.c */ EXTERN pcover simplify ARGS((pcube *)); +/* compl.c */ EXTERN void simp_comp ARGS((pcube *, pcover *, pcover *)); +/* contain.c */ EXTERN int d1_rm_equal ARGS((pset *, ESP_PFI)); +/* contain.c */ EXTERN int rm2_contain ARGS((pset *, pset *)); +/* contain.c */ EXTERN int rm2_equal ARGS((pset *, pset *, pset *, ESP_PFI)); +/* contain.c */ EXTERN int rm_contain ARGS((pset *)); +/* contain.c */ EXTERN int rm_equal ARGS((pset *, ESP_PFI)); +/* contain.c */ EXTERN int rm_rev_contain ARGS((pset *)); +/* contain.c */ EXTERN pset *sf_list ARGS((pset_family)); +/* contain.c */ EXTERN pset *sf_sort ARGS((pset_family, ESP_PFI)); +/* contain.c */ EXTERN pset_family d1merge ARGS((pset_family, int)); +/* contain.c */ EXTERN pset_family dist_merge ARGS((pset_family, pset)); +/* contain.c */ EXTERN pset_family sf_contain ARGS((pset_family)); +/* contain.c */ EXTERN pset_family sf_dupl ARGS((pset_family)); +/* contain.c */ EXTERN pset_family sf_ind_contain ARGS((pset_family, + int *)); +/* contain.c */ EXTERN pset_family sf_ind_unlist ARGS((pset *, int, int, + int *, pset)); +/* contain.c */ EXTERN pset_family sf_merge ARGS((pset *, pset *, pset *, + int, int)); +/* contain.c */ EXTERN pset_family sf_rev_contain ARGS((pset_family)); +/* contain.c */ EXTERN pset_family sf_union ARGS((pset_family, pset_family)); +/* contain.c */ EXTERN pset_family sf_unlist ARGS((pset *, int, int)); +/* cubestr.c */ EXTERN void cube_setup ARGS(()); +/* cubestr.c */ EXTERN void restore_cube_struct ARGS(()); +/* cubestr.c */ EXTERN void save_cube_struct ARGS(()); +/* cubestr.c */ EXTERN void setdown_cube ARGS(()); +/* cvrin.c */ EXTERN int PLA_labels ARGS((pPLA)); +/* cvrin.c */ EXTERN char *get_word ARGS((FILE *, char *)); +/* cvrin.c */ EXTERN int label_index ARGS((pPLA, char *, int *, int *)); +/* cvrin.c */ EXTERN int read_pla ARGS((FILE *, bool, bool, int, pPLA *)); +/* cvrin.c */ EXTERN int read_symbolic ARGS((FILE *, pPLA, char *, symbolic_t **)); +/* cvrin.c */ EXTERN pPLA new_PLA ARGS(()); +/* cvrin.c */ EXTERN void PLA_summary ARGS((pPLA)); +/* cvrin.c */ EXTERN void free_PLA ARGS((pPLA)); +/* cvrin.c */ EXTERN void parse_pla ARGS((FILE *, pPLA)); +/* cvrin.c */ EXTERN void read_cube ARGS((FILE *, pPLA)); +/* cvrin.c */ EXTERN void skip_line ARGS((FILE *, FILE *, bool)); +/* cvrm.c */ EXTERN int foreach_output_function ARGS((pPLA, ESP_PFI, ESP_PFI )); +/* cvrm.c */ EXTERN int cubelist_partition ARGS((pcube *, pcube **, pcube **, + unsigned int)); +/* cvrm.c */ EXTERN int so_both_do_espresso ARGS((pPLA, int)); +/* cvrm.c */ EXTERN int so_both_do_exact ARGS((pPLA, int)); +/* cvrm.c */ EXTERN int so_both_save ARGS((pPLA, int)); +/* cvrm.c */ EXTERN int so_do_espresso ARGS((pPLA, int)); +/* cvrm.c */ EXTERN int so_do_exact ARGS((pPLA, int)); +/* cvrm.c */ EXTERN int so_save ARGS((pPLA, int)); +/* cvrm.c */ EXTERN pcover cof_output ARGS((pcover, int)); +/* cvrm.c */ EXTERN pcover lex_sort ARGS((pcover)); +/* cvrm.c */ EXTERN pcover mini_sort ARGS((pcover, ESP_PFI)); +/* cvrm.c */ EXTERN pcover random_order ARGS((pcover)); +/* cvrm.c */ EXTERN pcover size_sort ARGS((pcover)); +/* cvrm.c */ EXTERN pcover sort_reduce ARGS((pcover)); +/* cvrm.c */ EXTERN pcover uncof_output ARGS((pcover, int)); +/* cvrm.c */ EXTERN pcover unravel ARGS((pcover, int)); +/* cvrm.c */ EXTERN pcover unravel_range ARGS((pcover, int, int)); +/* cvrm.c */ EXTERN void so_both_espresso ARGS((pPLA, int)); +/* cvrm.c */ EXTERN void so_espresso ARGS((pPLA, int)); +/* cvrmisc.c */ EXTERN char *fmt_cost ARGS((pcost)); +/* cvrmisc.c */ EXTERN char *print_cost ARGS((pcover)); +/* cvrmisc.c */ EXTERN void copy_cost ARGS((pcost, pcost)); +/* cvrmisc.c */ EXTERN void cover_cost ARGS((pcover, pcost)); +/* cvrmisc.c */ EXTERN void fatal ARGS((char *)); +/* cvrmisc.c */ EXTERN void print_trace ARGS((pcover, char *, long)); +/* cvrmisc.c */ EXTERN void size_stamp ARGS((pcover, char *)); +/* cvrmisc.c */ EXTERN void totals ARGS((long, int, pcover, pcost)); +/* cvrout.c */ EXTERN char *fmt_cube ARGS((pcube, char *, char *)); +/* cvrout.c */ EXTERN char *fmt_expanded_cube ARGS(()); +/* cvrout.c */ EXTERN char *pc1 ARGS((pcube)); +/* cvrout.c */ EXTERN char *pc2 ARGS((pcube)); +/* cvrout.c */ EXTERN char *pc3 ARGS((pcube)); +/* cvrout.c */ EXTERN int makeup_labels ARGS((pPLA)); +/* cvrout.c */ EXTERN int kiss_output ARGS((FILE *, pPLA)); +/* cvrout.c */ EXTERN int kiss_print_cube ARGS((FILE *, pPLA, pcube, char *)); +/* cvrout.c */ EXTERN int output_symbolic_constraints ARGS((FILE *, pPLA, int)); +/* cvrout.c */ EXTERN void cprint ARGS((pcover)); +/* cvrout.c */ EXTERN void debug1_print ARGS((pcover, char *, int)); +/* cvrout.c */ EXTERN void sf_debug_print ARGS((pcube *, char *, int)); +/* cvrout.c */ EXTERN void eqn_output ARGS((pPLA)); +/* cvrout.c */ EXTERN void fpr_header ARGS((FILE *, pPLA, int)); +/* cvrout.c */ EXTERN void fprint_pla ARGS((FILE *, pPLA, int)); +/* cvrout.c */ EXTERN void pls_group ARGS((pPLA, FILE *)); +/* cvrout.c */ EXTERN void pls_label ARGS((pPLA, FILE *)); +/* cvrout.c */ EXTERN void pls_output ARGS((pPLA)); +/* cvrout.c */ EXTERN void print_cube ARGS((FILE *, pcube, char *)); +/* cvrout.c */ EXTERN void print_expanded_cube ARGS((FILE *, pcube, pcube)); +/* cvrout.c */ EXTERN void debug_print ARGS((pcube *, char *, int)); +/* equiv.c */ EXTERN int find_equiv_outputs ARGS((pPLA)); +/* equiv.c */ EXTERN int check_equiv ARGS((pcover, pcover)); +/* espresso.c */ EXTERN pcover espresso ARGS((pcover, pcover, pcover)); +/* essen.c */ EXTERN bool essen_cube ARGS((pcover, pcover, pcube)); +/* essen.c */ EXTERN pcover cb_consensus ARGS((pcover, pcube)); +/* essen.c */ EXTERN pcover cb_consensus_dist0 ARGS((pcover, pcube, pcube)); +/* essen.c */ EXTERN pcover essential ARGS((pcover *, pcover *)); +/* exact.c */ EXTERN pcover minimize_exact ARGS((pcover, pcover, pcover, + int)); +/* exact.c */ EXTERN pcover minimize_exact_literals ARGS((pcover, pcover, + pcover, int)); +/* expand.c */ EXTERN bool feasibly_covered ARGS((pcover, pcube, pcube, + pcube)); +/* expand.c */ EXTERN int most_frequent ARGS((pcover, pcube)); +/* expand.c */ EXTERN pcover all_primes ARGS((pcover, pcover)); +/* expand.c */ EXTERN pcover expand ARGS((pcover, pcover, bool)); +/* expand.c */ EXTERN pcover find_all_primes ARGS((pcover, pcube, pcube)); +/* expand.c */ EXTERN void elim_lowering ARGS((pcover, pcover, pcube, pcube)); +/* expand.c */ EXTERN void essen_parts ARGS((pcover, pcover, pcube, pcube)); +/* expand.c */ EXTERN void essen_raising ARGS((pcover, pcube, pcube)); +/* expand.c */ EXTERN void expand1 ARGS((pcover, pcover, pcube, + pcube, pcube, pcube, pcube, + int *, pcube)); +/* expand.c */ EXTERN void mincov ARGS((pcover, pcube, pcube)); +/* expand.c */ EXTERN void select_feasible ARGS((pcover, pcover, + pcube, pcube, pcube, int *)); +/* expand.c */ EXTERN void setup_BB_CC ARGS((pcover, pcover)); +/* gasp.c */ EXTERN pcover expand_gasp ARGS((pcover, pcover, pcover, pcover)); +/* gasp.c */ EXTERN pcover irred_gasp ARGS((pcover, pcover, pcover)); +/* gasp.c */ EXTERN pcover last_gasp ARGS((pcover, pcover, pcover, + cost_t *cost)); +/* gasp.c */ EXTERN pcover super_gasp ARGS((pcover, pcover, pcover, + cost_t *cost)); +/* gasp.c */ EXTERN void expand1_gasp ARGS((pcover, pcover, pcover, + pcover, int, pcover *)); +/* hack.c */ EXTERN int find_dc_inputs ARGS((pPLA, symbolic_list_t *, int, int, pcover *, pcover *)); +/* hack.c */ EXTERN int find_inputs ARGS((pcover, pPLA, symbolic_list_t *, + int, int, pcover *, pcover *)); +/* hack.c */ EXTERN int form_bitvector ARGS((pset, int, int, + symbolic_list_t *)); +/* hack.c */ EXTERN int map_dcset ARGS((pPLA)); +/* hack.c */ EXTERN int map_output_symbolic ARGS((pPLA)); +/* hack.c */ EXTERN int map_symbolic ARGS((pPLA)); +/* hack.c */ EXTERN pcover map_symbolic_cover ARGS((pcover, + symbolic_list_t *, int)); +/* hack.c */ EXTERN int symbolic_hack_labels ARGS((pPLA, symbolic_t*, + pset, int, int, int)); +/* irred.c */ EXTERN bool cube_is_covered ARGS((pcube *, pcube)); +/* irred.c */ EXTERN bool taut_special_cases ARGS((pcube *)); +/* irred.c */ EXTERN bool tautology ARGS((pcube *)); +/* irred.c */ EXTERN pcover irredundant ARGS((pcover, pcover)); +/* irred.c */ EXTERN void mark_irredundant ARGS((pcover, pcover)); +/* irred.c */ EXTERN void irred_split_cover ARGS((pcover, pcover, + pcover *, pcover *, pcover *)); +/* irred.c */ EXTERN sm_matrix *irred_derive_table ARGS((pcover, pcover, + pcover)); +/* map.c */ EXTERN pset minterms ARGS((pcover)); +/* map.c */ EXTERN void explode ARGS((int, int)); +/* map.c */ EXTERN void map ARGS((pcover)); +/* opo.c */ EXTERN int output_phase_setup ARGS((pPLA, int)); +/* opo.c */ EXTERN pPLA set_phase ARGS((pPLA)); +/* opo.c */ EXTERN pcover opo ARGS((pcube, pcover, pcover, pcover, + int)); +/* opo.c */ EXTERN pcube find_phase ARGS((pPLA, int, pcube)); +/* opo.c */ EXTERN pset_family find_covers ARGS((pcover, pcover, pset, int)); +/* opo.c */ EXTERN pset_family form_cover_table ARGS((pcover, pcover, + pset, int, int)); +/* opo.c */ EXTERN pset_family opo_leaf ARGS((pcover, pset, int, int)); +/* opo.c */ EXTERN pset_family opo_recur ARGS((pcover, pcover, pcube, int, + int, int)); +/* opo.c */ EXTERN void opoall ARGS((pPLA, int, int, int)); +/* opo.c */ EXTERN void phase_assignment ARGS((pPLA, int)); +/* opo.c */ EXTERN void repeated_phase_assignment ARGS((pPLA)); +/* pair.c */ EXTERN int generate_all_pairs ARGS((ppair, int, pset, ESP_PFI)); +/* pair.c */ EXTERN int **find_pairing_cost ARGS((pPLA, int)); +/* pair.c */ EXTERN int find_best_cost ARGS((ppair)); +/* pair.c */ EXTERN int greedy_best_cost ARGS((int **, ppair *)); +/* pair.c */ EXTERN int minimize_pair ARGS((ppair)); +/* pair.c */ EXTERN int pair_free ARGS((ppair)); +/* pair.c */ EXTERN int pair_all ARGS((pPLA, int)); +/* pair.c */ EXTERN pcover delvar ARGS((pcover, bool *)); +/* pair.c */ EXTERN pcover pairvar ARGS((pcover, ppair)); +/* pair.c */ EXTERN ppair pair_best_cost ARGS((int **)); +/* pair.c */ EXTERN ppair pair_new ARGS((int)); +/* pair.c */ EXTERN ppair pair_save ARGS((ppair, int)); +/* pair.c */ EXTERN int print_pair ARGS((ppair)); +/* pair.c */ EXTERN void find_optimal_pairing ARGS((pPLA, int)); +/* pair.c */ EXTERN void set_pair ARGS((pPLA)); +/* pair.c */ EXTERN void set_pair1 ARGS((pPLA, bool)); +/* primes.c */ EXTERN pcover primes_consensus ARGS((pcube *)); +/* reduce.c */ EXTERN bool sccc_special_cases ARGS((pcube *, pcube *)); +/* reduce.c */ EXTERN pcover reduce ARGS((pcover, pcover)); +/* reduce.c */ EXTERN pcube reduce_cube ARGS((pcube *, pcube)); +/* reduce.c */ EXTERN pcube sccc ARGS((pcube *)); +/* reduce.c */ EXTERN pcube sccc_cube ARGS((pcube, pcube)); +/* reduce.c */ EXTERN pcube sccc_merge ARGS((pcube, pcube, pcube, pcube)); +/* set.c */ EXTERN bool set_andp ARGS((pset, pset, pset)); +/* set.c */ EXTERN bool set_orp ARGS((pset, pset, pset)); +/* set.c */ EXTERN bool setp_disjoint ARGS((pset, pset)); +/* set.c */ EXTERN bool setp_empty ARGS((pset)); +/* set.c */ EXTERN bool setp_equal ARGS((pset, pset)); +/* set.c */ EXTERN bool setp_full ARGS((pset, int)); +/* set.c */ EXTERN bool setp_implies ARGS((pset, pset)); +/* set.c */ EXTERN char *pbv1 ARGS((pset, int)); +/* set.c */ EXTERN char *ps1 ARGS((pset)); +/* set.c */ EXTERN int *sf_count ARGS((pset_family)); +/* set.c */ EXTERN int *sf_count_restricted ARGS((pset_family, pset)); +/* set.c */ EXTERN int bit_index ARGS((unsigned int)); +/* set.c */ EXTERN int set_dist ARGS((pset, pset)); +/* set.c */ EXTERN int set_ord ARGS((pset)); +/* set.c */ EXTERN void set_adjcnt ARGS((pset, int *, int)); +/* set.c */ EXTERN pset set_and ARGS((pset, pset, pset)); +/* set.c */ EXTERN pset set_clear ARGS((pset, int)); +/* set.c */ EXTERN pset set_copy ARGS((pset, pset)); +/* set.c */ EXTERN pset set_diff ARGS((pset, pset, pset)); +/* set.c */ EXTERN pset set_fill ARGS((pset, int)); +/* set.c */ EXTERN pset set_merge ARGS((pset, pset, pset, pset)); +/* set.c */ EXTERN pset set_or ARGS((pset, pset, pset)); +/* set.c */ EXTERN pset set_xor ARGS((pset, pset, pset)); +/* set.c */ EXTERN pset sf_and ARGS((pset_family)); +/* set.c */ EXTERN pset sf_or ARGS((pset_family)); +/* set.c */ EXTERN pset_family sf_active ARGS((pset_family)); +/* set.c */ EXTERN pset_family sf_addcol ARGS((pset_family, int, int)); +/* set.c */ EXTERN pset_family sf_addset ARGS((pset_family, pset)); +/* set.c */ EXTERN pset_family sf_append ARGS((pset_family, pset_family)); +/* set.c */ EXTERN pset_family sf_bm_read ARGS((FILE *)); +/* set.c */ EXTERN pset_family sf_compress ARGS((pset_family, pset)); +/* set.c */ EXTERN pset_family sf_copy ARGS((pset_family, pset_family)); +/* set.c */ EXTERN pset_family sf_copy_col ARGS((pset_family, int, + pset_family, int)); +/* set.c */ EXTERN pset_family sf_delc ARGS((pset_family, int, int)); +/* set.c */ EXTERN pset_family sf_delcol ARGS((pset_family, int, int)); +/* set.c */ EXTERN pset_family sf_inactive ARGS((pset_family)); +/* set.c */ EXTERN pset_family sf_join ARGS((pset_family, pset_family)); +/* set.c */ EXTERN pset_family sf_new ARGS((int, int)); +/* set.c */ EXTERN pset_family sf_permute ARGS((pset_family, int *, int)); +/* set.c */ EXTERN pset_family sf_read ARGS((FILE *)); +/* set.c */ EXTERN pset_family sf_save ARGS((pset_family)); +/* set.c */ EXTERN pset_family sf_transpose ARGS((pset_family)); +/* set.c */ EXTERN void set_write ARGS((FILE *, pset)); +/* set.c */ EXTERN void sf_bm_print ARGS((pset_family)); +/* set.c */ EXTERN void sf_cleanup ARGS(()); +/* set.c */ EXTERN void sf_delset ARGS((pset_family, int)); +/* set.c */ EXTERN void sf_free ARGS((pset_family)); +/* set.c */ EXTERN void sf_print ARGS((pset_family)); +/* set.c */ EXTERN void sf_write ARGS((FILE *, pset_family)); +/* setc.c */ EXTERN bool ccommon ARGS((pcube, pcube, pcube)); +/* setc.c */ EXTERN bool cdist0 ARGS((pcube, pcube)); +/* setc.c */ EXTERN bool full_row ARGS((pcube, pcube)); +/* setc.c */ EXTERN int ascend ARGS((pset *, pset *)); +/* setc.c */ EXTERN int cactive ARGS((pcube)); +/* setc.c */ EXTERN int cdist ARGS((pset, pset)); +/* setc.c */ EXTERN int cdist01 ARGS((pset, pset)); +/* setc.c */ EXTERN int d1_order ARGS((pset *, pset *)); +/* setc.c */ EXTERN int desc1 ARGS((pset, pset)); +/* setc.c */ EXTERN int descend ARGS((pset *, pset *)); +/* setc.c */ EXTERN int lex_order ARGS((pset *, pset *)); +/* setc.c */ EXTERN pset force_lower ARGS((pset, pset, pset)); +/* setc.c */ EXTERN void consensus ARGS((pcube, pcube, pcube)); +/* sharp.c */ EXTERN pcover cb1_dsharp ARGS((pcover, pcube)); +/* sharp.c */ EXTERN pcover cb_dsharp ARGS((pcube, pcover)); +/* sharp.c */ EXTERN pcover cb_recur_sharp ARGS((pcube, pcover, int, int, int)); +/* sharp.c */ EXTERN pcover cb_sharp ARGS((pcube, pcover)); +/* sharp.c */ EXTERN pcover cv_dsharp ARGS((pcover, pcover)); +/* sharp.c */ EXTERN pcover cv_intersect ARGS((pcover, pcover)); +/* sharp.c */ EXTERN pcover cv_sharp ARGS((pcover, pcover)); +/* sharp.c */ EXTERN pcover dsharp ARGS((pcube, pcube)); +/* sharp.c */ EXTERN pcover make_disjoint ARGS((pcover)); +/* sharp.c */ EXTERN pcover sharp ARGS((pcube, pcube)); +/* sminterf.c */pset do_sm_minimum_cover ARGS((pset_family)); +/* sparse.c */ EXTERN pcover make_sparse ARGS((pcover, pcover, pcover)); +/* sparse.c */ EXTERN pcover mv_reduce ARGS((pcover, pcover)); +/* unate.c */ EXTERN pcover find_all_minimal_covers_petrick ARGS(()); +/* unate.c */ EXTERN pcover map_cover_to_unate ARGS((pcube *)); +/* unate.c */ EXTERN pcover map_unate_to_cover ARGS((pset_family)); +/* unate.c */ EXTERN pset_family exact_minimum_cover ARGS((pset_family)); +/* unate.c */ EXTERN pset_family unate_compl ARGS((pset_family)); +/* unate.c */ EXTERN pset_family unate_complement ARGS((pset_family)); +/* unate.c */ EXTERN pset_family unate_intersect ARGS((pset_family, pset_family, bool)); +/* verify.c */ EXTERN int PLA_permute ARGS((pPLA, pPLA)); +/* verify.c */ EXTERN bool PLA_verify ARGS((pPLA, pPLA)); +/* verify.c */ EXTERN bool check_consistency ARGS((pPLA)); +/* verify.c */ EXTERN bool verify ARGS((pcover, pcover, pcover)); diff --git a/sis/espresso/essen.c b/sis/espresso/essen.c new file mode 100644 index 0000000..dba54c0 --- /dev/null +++ b/sis/espresso/essen.c @@ -0,0 +1,181 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/essen.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + module: essen.c + purpose: Find essential primes in a multiple-valued function +*/ + +#include "espresso.h" + +/* + essential -- return a cover consisting of the cubes of F which are + essential prime implicants (with respect to F u D); Further, remove + these cubes from the ON-set F, and add them to the OFF-set D. + + Sometimes EXPAND can determine that a cube is not an essential prime. + If so, it will set the "NONESSEN" flag in the cube. + + We count on IRREDUNDANT to have set the flag RELESSEN to indicate + that a prime was relatively essential (i.e., covers some minterm + not contained in any other prime in the current cover), or to have + reset the flag to indicate that a prime was relatively redundant + (i.e., all minterms covered by other primes in the current cover). + Of course, after executing irredundant, all of the primes in the + cover are relatively essential, but we can mark the primes which + were redundant at the start of irredundant and avoid an extra check + on these primes for essentiality. +*/ + +pcover essential(Fp, Dp) +IN pcover *Fp, *Dp; +{ + register pcube last, p; + pcover E, F = *Fp, D = *Dp; + + /* set all cubes in F active */ + (void) sf_active(F); + + /* Might as well start out with some cubes in E */ + E = new_cover(10); + + foreach_set(F, last, p) { + /* don't test a prime which EXPAND says is nonessential */ + if (! TESTP(p, NONESSEN)) { + /* only test a prime which was relatively essential */ + if (TESTP(p, RELESSEN)) { + /* Check essentiality */ + if (essen_cube(F, D, p)) { + if (debug & ESSEN) + (void) printf("ESSENTIAL: %s\n", pc1(p)); + E = sf_addset(E, p); + RESET(p, ACTIVE); + F->active_count--; + } + } + } + } + + *Fp = sf_inactive(F); /* delete the inactive cubes from F */ + *Dp = sf_join(D, E); /* add the essentials to D */ + sf_free(D); + return E; +} + +/* + essen_cube -- check if a single cube is essential or not + + The prime c is essential iff + + consensus((F u D) # c, c) u D + + does not contain c. +*/ +bool essen_cube(F, D, c) +IN pcover F, D; +IN pcube c; +{ + pcover H, FD; + pcube *H1; + bool essen; + + /* Append F and D together, and take the sharp-consensus with c */ + FD = sf_join(F, D); + H = cb_consensus(FD, c); + free_cover(FD); + + /* Add the don't care set, and see if this covers c */ + H1 = cube2list(H, D); + essen = ! cube_is_covered(H1, c); + free_cubelist(H1); + + free_cover(H); + return essen; +} + + +/* + * cb_consensus -- compute consensus(T # c, c) + */ +pcover cb_consensus(T, c) +register pcover T; +register pcube c; +{ + register pcube temp, last, p; + register pcover R; + + R = new_cover(T->count*2); + temp = new_cube(); + foreach_set(T, last, p) { + if (p != c) { + switch (cdist01(p, c)) { + case 0: + /* distance-0 needs special care */ + R = cb_consensus_dist0(R, p, c); + break; + + case 1: + /* distance-1 is easy because no sharping required */ + consensus(temp, p, c); + R = sf_addset(R, temp); + break; + default: + ; + } + } + } + set_free(temp); + return R; +} + + +/* + * form the sharp-consensus for p and c when they intersect + * What we are forming is consensus(p # c, c). + */ +pcover cb_consensus_dist0(R, p, c) +pcover R; +register pcube p, c; +{ + int var; + bool got_one; + register pcube temp, mask; + register pcube p_diff_c=cube.temp[0], p_and_c=cube.temp[1]; + + /* If c contains p, then this gives us no information for essential test */ + if (setp_implies(p, c)) { + return R; + } + + /* For the multiple-valued variables */ + temp = new_cube(); + got_one = FALSE; + INLINEset_diff(p_diff_c, p, c); + INLINEset_and(p_and_c, p, c); + + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + /* Check if c(var) is contained in p(var) -- if so, no news */ + mask = cube.var_mask[var]; + if (! setp_disjoint(p_diff_c, mask)) { + INLINEset_merge(temp, c, p_and_c, mask); + R = sf_addset(R, temp); + got_one = TRUE; + } + } + + /* if no cube so far, add one for the intersection */ + if (! got_one && cube.num_binary_vars > 0) { + /* Add a single cube for the intersection of p and c */ + INLINEset_and(temp, p, c); + R = sf_addset(R, temp); + } + + set_free(temp); + return R; +} diff --git a/sis/espresso/exact.c b/sis/espresso/exact.c new file mode 100644 index 0000000..3ae09d0 --- /dev/null +++ b/sis/espresso/exact.c @@ -0,0 +1,181 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/exact.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + + +static void dump_irredundant(); +static pcover do_minimize(); + + +/* + * minimize_exact -- main entry point for exact minimization + * + * Global flags which affect this routine are: + * + * debug + * skip_make_sparse + */ + +pcover +minimize_exact(F, D, R, exact_cover) +pcover F, D, R; +int exact_cover; +{ + return do_minimize(F, D, R, exact_cover, /*weighted*/ 0); +} + + +pcover +minimize_exact_literals(F, D, R, exact_cover) +pcover F, D, R; +int exact_cover; +{ + return do_minimize(F, D, R, exact_cover, /*weighted*/ 1); +} + + + +static pcover +do_minimize(F, D, R, exact_cover, weighted) +pcover F, D, R; +int exact_cover; +int weighted; +{ + pcover newF, E, Rt, Rp; + pset p, last; + int heur, level, *weights, i; + sm_matrix *table; + sm_row *cover; + sm_element *pe; + int debug_save = debug; + + if (debug & EXACT) { + debug |= (IRRED | MINCOV); + } +#if defined(sun) || defined(bsd4_2) /* hack ... */ + if (debug & MINCOV) { + setlinebuf(stdout); + } +#endif + level = (debug & MINCOV) ? 4 : 0; + heur = ! exact_cover; + + /* Generate all prime implicants */ + EXEC(F = primes_consensus(cube2list(F, D)), "PRIMES ", F); + + /* Setup the prime implicant table */ + EXEC(irred_split_cover(F, D, &E, &Rt, &Rp), "ESSENTIALS ", E); + EXEC(table = irred_derive_table(D, E, Rp), "PI-TABLE ", Rp); + + /* Solve either a weighted or nonweighted covering problem */ + if (weighted) { + /* correct only for all 2-valued variables */ + weights = ALLOC(int, F->count); + foreach_set(Rp, last, p) { + weights[SIZE(p)] = cube.size - set_ord(p); + /* We have added the 0's in the output part instead of the 1's. + This loop corrects the literal count. */ + for (i = cube.first_part[cube.output]; + i <= cube.last_part[cube.output]; i++) { + is_in_set(p, i) ? weights[SIZE(p)]++ : weights[SIZE(p)]--; + } + } + } else { + weights = NIL(int); + } + EXEC(cover=sm_minimum_cover(table,weights,heur,level), "MINCOV ", F); + if (weights != 0) { + FREE(weights); + } + + if (debug & EXACT) { + dump_irredundant(E, Rt, Rp, table); + } + + /* Form the result cover */ + newF = new_cover(100); + foreach_set(E, last, p) { + newF = sf_addset(newF, p); + } + sm_foreach_row_element(cover, pe) { + newF = sf_addset(newF, GETSET(F, pe->col_num)); + } + + free_cover(E); + free_cover(Rt); + free_cover(Rp); + sm_free(table); + sm_row_free(cover); + free_cover(F); + + /* Attempt to make the results more sparse */ + debug &= ~ (IRRED | SHARP | MINCOV); + if (! skip_make_sparse && R != 0) { + newF = make_sparse(newF, D, R); + } + + debug = debug_save; + return newF; +} + +static void +dump_irredundant(E, Rt, Rp, table) +pcover E, Rt, Rp; +sm_matrix *table; +{ + FILE *fp_pi_table, *fp_primes; + pPLA PLA; + pset last, p; + char *file; + + if (filename == 0 || strcmp(filename, "(stdin)") == 0) { + fp_pi_table = fp_primes = stdout; + } else { + file = ALLOC(char, strlen(filename)+20); + (void) sprintf(file, "%s.primes", filename); + if ((fp_primes = fopen(file, "w")) == NULL) { + (void) fprintf(stderr, "espresso: Unable to open %s\n", file); + fp_primes = stdout; + } + (void) sprintf(file, "%s.pi", filename); + if ((fp_pi_table = fopen(file, "w")) == NULL) { + (void) fprintf(stderr, "espresso: Unable to open %s\n", file); + fp_pi_table = stdout; + } + FREE(file); + } + + PLA = new_PLA(); + PLA_labels(PLA); + + fpr_header(fp_primes, PLA, F_type); + free_PLA(PLA); + + (void) fprintf(fp_primes, "# Essential primes are\n"); + foreach_set(E, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + (void) fprintf(fp_primes, "# Totally redundant primes are\n"); + foreach_set(Rt, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + (void) fprintf(fp_primes, "# Partially redundant primes are\n"); + foreach_set(Rp, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + if (fp_primes != stdout) { + (void) fclose(fp_primes); + } + + sm_write(fp_pi_table, table); + if (fp_pi_table != stdout) { + (void) fclose(fp_pi_table); + } +} diff --git a/sis/espresso/expand.c b/sis/espresso/expand.c new file mode 100644 index 0000000..05e9997 --- /dev/null +++ b/sis/espresso/expand.c @@ -0,0 +1,689 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/expand.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + module: expand.c + purpose: Perform the Espresso-II Expansion Step + + The idea is to take each nonprime cube of the on-set and expand it + into a prime implicant such that we can cover as many other cubes + of the on-set. If no cube of the on-set can be covered, then we + expand each cube into a large prime implicant by transforming the + problem into a minimum covering problem which is solved by the + heuristics of minimum_cover. + + These routines revolve around having a representation of the + OFF-set. (In contrast to the Espresso-II manuscript, we do NOT + require an "unwrapped" version of the OFF-set). + + Some conventions on variable names: + + SUPER_CUBE is the supercube of all cubes which can be covered + by an expansion of the cube being expanded + + OVEREXPANDED_CUBE is the cube which would result from expanding + all parts which can expand individually of the cube being expanded + + RAISE is the current expansion of the current cube + + FREESET is the set of parts which haven't been raised or lowered yet. + + INIT_LOWER is a set of parts to be removed from the free parts before + starting the expansion +*/ + +#include "espresso.h" + +/* + expand -- expand each nonprime cube of F into a prime implicant + + If nonsparse is true, only the non-sparse variables will be expanded; + this is done by forcing all of the sparse variables out of the free set. +*/ + +pcover expand(F, R, nonsparse) +INOUT pcover F; +IN pcover R; +IN bool nonsparse; /* expand non-sparse variables only */ +{ + register pcube last, p; + pcube RAISE, FREESET, INIT_LOWER, SUPER_CUBE, OVEREXPANDED_CUBE; + int var, num_covered; + bool change; + + /* Order the cubes according to "chewing-away from the edges" of mini */ + if (use_random_order) + F = random_order(F); + else + F = mini_sort(F, ascend); + + /* Allocate memory for variables needed by expand1() */ + RAISE = new_cube(); + FREESET = new_cube(); + INIT_LOWER = new_cube(); + SUPER_CUBE = new_cube(); + OVEREXPANDED_CUBE = new_cube(); + + /* Setup the initial lowering set (differs only for nonsparse) */ + if (nonsparse) + for(var = 0; var < cube.num_vars; var++) + if (cube.sparse[var]) + (void) set_or(INIT_LOWER, INIT_LOWER, cube.var_mask[var]); + + /* Mark all cubes as not covered, and maybe essential */ + foreach_set(F, last, p) { + RESET(p, COVERED); + RESET(p, NONESSEN); + } + + /* Try to expand each nonprime and noncovered cube */ + foreach_set(F, last, p) { + /* do not expand if PRIME or if covered by previous expansion */ + if (! TESTP(p, PRIME) && ! TESTP(p, COVERED)) { + + /* expand the cube p, result is RAISE */ + expand1(R, F, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + INIT_LOWER, &num_covered, p); + if (debug & EXPAND) + (void) printf("EXPAND: %s (covered %d)\n", pc1(p), num_covered); + (void) set_copy(p, RAISE); + SET(p, PRIME); + RESET(p, COVERED); /* not really necessary */ + + /* See if we generated an inessential prime */ + if (num_covered == 0 && ! setp_equal(p, OVEREXPANDED_CUBE)) { + SET(p, NONESSEN); + } + } + } + + /* Delete any cubes of F which became covered during the expansion */ + F->active_count = 0; + change = FALSE; + foreach_set(F, last, p) { + if (TESTP(p, COVERED)) { + RESET(p, ACTIVE); + change = TRUE; + } else { + SET(p, ACTIVE); + F->active_count++; + } + } + if (change) + F = sf_inactive(F); + + free_cube(RAISE); + free_cube(FREESET); + free_cube(INIT_LOWER); + free_cube(SUPER_CUBE); + free_cube(OVEREXPANDED_CUBE); + return F; +} + +/* + expand1 -- Expand a single cube against the OFF-set +*/ +void expand1(BB, CC, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + INIT_LOWER, num_covered, c) +pcover BB; /* Blocking matrix (OFF-set) */ +pcover CC; /* Covering matrix (ON-set) */ +pcube RAISE; /* The current parts which have been raised */ +pcube FREESET; /* The current parts which are free */ +pcube OVEREXPANDED_CUBE; /* Overexpanded cube of c */ +pcube SUPER_CUBE; /* Supercube of all cubes of CC we cover */ +pcube INIT_LOWER; /* Parts to initially remove from FREESET */ +int *num_covered; /* Number of cubes of CC which are covered */ +pcube c; /* The cube to be expanded */ +{ + int bestindex; + + if (debug & EXPAND1) + (void) printf("\nEXPAND1: \t%s\n", pc1(c)); + + /* initialize BB and CC */ + SET(c, PRIME); /* don't try to cover ourself */ + setup_BB_CC(BB, CC); + + /* initialize count of # cubes covered, and the supercube of them */ + *num_covered = 0; + (void) set_copy(SUPER_CUBE, c); + + /* Initialize the lowering, raising and unassigned sets */ + (void) set_copy(RAISE, c); + (void) set_diff(FREESET, cube.fullset, RAISE); + + /* If some parts are forced into lowering set, remove them */ + if (! setp_empty(INIT_LOWER)) { + (void) set_diff(FREESET, FREESET, INIT_LOWER); + elim_lowering(BB, CC, RAISE, FREESET); + } + + /* Determine what can be raised, and return the over-expanded cube */ + essen_parts(BB, CC, RAISE, FREESET); + (void) set_or(OVEREXPANDED_CUBE, RAISE, FREESET); + + /* While there are still cubes which can be covered, cover them ! */ + if (CC->active_count > 0) { + select_feasible(BB, CC, RAISE, FREESET, SUPER_CUBE, num_covered); + } + + /* While there are still cubes covered by the overexpanded cube ... */ + while (CC->active_count > 0) { + bestindex = most_frequent(CC, FREESET); + set_insert(RAISE, bestindex); + set_remove(FREESET, bestindex); + essen_parts(BB, CC, RAISE, FREESET); + } + + /* Finally, when all else fails, choose the largest possible prime */ + /* We will loop only if we decide unravelling OFF-set is too expensive */ + while (BB->active_count > 0) { + mincov(BB, RAISE, FREESET); + } + + /* Raise any remaining free coordinates */ + (void) set_or(RAISE, RAISE, FREESET); +} + +/* + essen_parts -- determine which parts are forced into the lowering + set to insure that the cube be orthognal to the OFF-set. + + If any cube of the OFF-set is distance 1 from the raising cube, + then we must lower all parts of the conflicting variable. (If the + cube is distance 0, we detect this error here.) + + If there are essentially lowered parts, we can remove from consideration + any cubes of the OFF-set which are more than distance 1 from the + overexpanded cube of RAISE. +*/ + +void essen_parts(BB, CC, RAISE, FREESET) +pcover BB, CC; +pcube RAISE, FREESET; +{ + register pcube p, r = RAISE; + pcube lastp, xlower = cube.temp[0]; + int dist; + + (void) set_copy(xlower, cube.emptyset); + + foreach_active_set(BB, lastp, p) { +#ifdef NO_INLINE + if ((dist = cdist01(p, r)) > 1) goto exit_if; +#else + {register int w,last;register unsigned int x;dist=0;if((last=cube.inword)!=-1) +{x=p[last]&r[last];if(x=~(x|x>>1)&cube.inmask)if((dist=count_ones(x))>1)goto +exit_if;for(w=1;w>1)&DISJOINT)if(dist==1||( +dist+=count_ones(x))>1)goto exit_if;}}}{register int w,var,last;register pcube +mask;for(var=cube.num_binary_vars;var1)goto exit_if;nextvar:;}} +#endif + if (dist == 0) { + fatal("ON-set and OFF-set are not orthogonal"); + } else { + (void) force_lower(xlower, p, r); + BB->active_count--; + RESET(p, ACTIVE); + } +exit_if: ; + } + + if (! setp_empty(xlower)) { + (void) set_diff(FREESET, FREESET, xlower);/* remove from free set */ + elim_lowering(BB, CC, RAISE, FREESET); + } + + if (debug & EXPAND1) + (void) printf("ESSEN_PARTS:\tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); +} + +/* + essen_raising -- determine which parts may always be added to + the raising set without restricting further expansions + + General rule: if some part is not blocked by any cube of BB, then + this part can always be raised. +*/ + +void essen_raising(BB, RAISE, FREESET) +register pcover BB; +pcube RAISE, FREESET; +{ + register pcube last, p, xraise = cube.temp[0]; + + /* Form union of all cubes of BB, and then take complement wrt FREESET */ + (void) set_copy(xraise, cube.emptyset); + foreach_active_set(BB, last, p) + INLINEset_or(xraise, xraise, p); + (void) set_diff(xraise, FREESET, xraise); + + (void) set_or(RAISE, RAISE, xraise); /* add to raising set */ + (void) set_diff(FREESET, FREESET, xraise); /* remove from free set */ + + if (debug & EXPAND1) + (void) printf("ESSEN_RAISING:\tRAISE=%s FREESET=%s\n", + pc1(RAISE), pc2(FREESET)); +} + +/* + elim_lowering -- after removing parts from FREESET, we can reduce the + size of both BB and CC. + + We mark as inactive any cube of BB which does not intersect the + overexpanded cube (i.e., RAISE + FREESET). Likewise, we remove + from CC any cube which is not covered by the overexpanded cube. +*/ + +void elim_lowering(BB, CC, RAISE, FREESET) +pcover BB, CC; +pcube RAISE, FREESET; +{ + register pcube p, r = set_or(cube.temp[0], RAISE, FREESET); + pcube last; + + /* + * Remove sets of BB which are orthogonal to future expansions + */ + foreach_active_set(BB, last, p) { +#ifdef NO_INLINE + if (! cdist0(p, r)) +#else + {register int w,lastw;register unsigned int x;if((lastw=cube.inword)!=-1){x=p[ +lastw]&r[lastw];if(~(x|x>>1)&cube.inmask)goto false;for(w=1;w>1)&DISJOINT)goto false;}}}{register int w,var,lastw;register +pcube mask;for(var=cube.num_binary_vars;varactive_count--, RESET(p, ACTIVE); + } + + + /* + * Remove sets of CC which cannot be covered by future expansions + */ + if (CC != (pcover) NULL) { + foreach_active_set(CC, last, p) { +#ifdef NO_INLINE + if (! setp_implies(p, r)) +#else + INLINEsetp_implies(p, r, /* when false => */ goto false1); + /* when true => go to end of loop */ continue; + false1: +#endif + CC->active_count--, RESET(p, ACTIVE); + } + } +} + +/* + most_frequent -- When all else fails, select a reasonable part to raise + The active cubes of CC are the cubes which are covered by the + overexpanded cube of the original cube (however, we know that none + of them can actually be covered by a feasible expansion of the + original cube). We resort to the MINI strategy of selecting to + raise the part which will cover the same part in the most cubes of CC. +*/ +int most_frequent(CC, FREESET) +pcover CC; +pcube FREESET; +{ + register int i, best_part, best_count, *count; + register pset p, last; + + /* Count occurences of each variable */ + count = ALLOC(int, cube.size); + for(i = 0; i < cube.size; i++) + count[i] = 0; + if (CC != (pcover) NULL) + foreach_active_set(CC, last, p) + set_adjcnt(p, count, 1); + + /* Now find which free part occurs most often */ + best_count = best_part = -1; + for(i = 0; i < cube.size; i++) + if (is_in_set(FREESET,i) && count[i] > best_count) { + best_part = i; + best_count = count[i]; + } + FREE(count); + + if (debug & EXPAND1) + (void) printf("MOST_FREQUENT:\tbest=%d FREESET=%s\n", best_part, pc2(FREESET)); + return best_part; +} + +/* + setup_BB_CC -- set up the blocking and covering set families; + + Note that the blocking family is merely the set of cubes of R, and + that CC is the set of cubes of F which might possibly be covered + (i.e., nonprime cubes, and cubes not already covered) +*/ + +void setup_BB_CC(BB, CC) +register pcover BB, CC; +{ + register pcube p, last; + + /* Create the block and cover set families */ + BB->active_count = BB->count; + foreach_set(BB, last, p) + SET(p, ACTIVE); + + if (CC != (pcover) NULL) { + CC->active_count = CC->count; + foreach_set(CC, last, p) + if (TESTP(p, COVERED) || TESTP(p, PRIME)) + CC->active_count--, RESET(p, ACTIVE); + else + SET(p, ACTIVE); + } +} + +/* + select_feasible -- Determine if there are cubes which can be covered, + and if so, raise those parts necessary to cover as many as possible. + + We really don't check to maximize the number that can be covered; + instead, we check, for each fcc, how many other fcc remain fcc + after expanding to cover the fcc. (Essentially one-level lookahead). +*/ + +void select_feasible(BB, CC, RAISE, FREESET, SUPER_CUBE, num_covered) +pcover BB, CC; +pcube RAISE, FREESET, SUPER_CUBE; +int *num_covered; +{ + register pcube p, last, bestfeas, *feas; + register int i, j; + pcube *feas_new_lower; + int bestcount, bestsize, count, size, numfeas, lastfeas; + pcover new_lower; + + /* Start out with all cubes covered by the over-expanded cube as + * the "possibly" feasibly-covered cubes (pfcc) + */ + feas = ALLOC(pcube, CC->active_count); + numfeas = 0; + foreach_active_set(CC, last, p) + feas[numfeas++] = p; + + /* Setup extra cubes to record parts forced low after a covering */ + feas_new_lower = ALLOC(pcube, CC->active_count); + new_lower = new_cover(numfeas); + for(i = 0; i < numfeas; i++) + feas_new_lower[i] = GETSET(new_lower, i); + + +loop: + /* Find the essentially raised parts -- this might cover some cubes + for us, without having to find out if they are fcc or not + */ + essen_raising(BB, RAISE, FREESET); + + /* Now check all "possibly" feasibly covered cubes to check feasibility */ + lastfeas = numfeas; + numfeas = 0; + for(i = 0; i < lastfeas; i++) { + p = feas[i]; + + /* Check active because essen_parts might have removed it */ + if (TESTP(p, ACTIVE)) { + + /* See if the cube is already covered by RAISE -- + * this can happen because of essen_raising() or because of + * the previous "loop" + */ + if (setp_implies(p, RAISE)) { + (*num_covered) += 1; + (void) set_or(SUPER_CUBE, SUPER_CUBE, p); + CC->active_count--; + RESET(p, ACTIVE); + SET(p, COVERED); + /* otherwise, test if it is feasibly covered */ + } else if (feasibly_covered(BB,p,RAISE,feas_new_lower[numfeas])) { + feas[numfeas] = p; /* save the fcc */ + numfeas++; + } + } + } + if (debug & EXPAND1) + (void) printf("SELECT_FEASIBLE: started with %d pfcc, ended with %d fcc\n", + lastfeas, numfeas); + + /* Exit here if there are no feasibly covered cubes */ + if (numfeas == 0) { + FREE(feas); + FREE(feas_new_lower); + free_cover(new_lower); + return; + } + + /* Now find which is the best feasibly covered cube */ + bestcount = 0; + bestsize = 9999; + for(i = 0; i < numfeas; i++) { + size = set_dist(feas[i], FREESET); /* # of newly raised parts */ + count = 0; /* # of other cubes which remain fcc after raising */ + +#define NEW +#ifdef NEW + for(j = 0; j < numfeas; j++) + if (setp_disjoint(feas_new_lower[i], feas[j])) + count++; +#else + for(j = 0; j < numfeas; j++) + if (setp_implies(feas[j], feas[i])) + count++; +#endif + if (count > bestcount) { + bestcount = count; + bestfeas = feas[i]; + bestsize = size; + } else if (count == bestcount && size < bestsize) { + bestfeas = feas[i]; + bestsize = size; + } + } + + /* Add the necessary parts to the raising set */ + (void) set_or(RAISE, RAISE, bestfeas); + (void) set_diff(FREESET, FREESET, RAISE); + if (debug & EXPAND1) + (void) printf("FEASIBLE: \tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); + essen_parts(BB, CC, RAISE, FREESET); + goto loop; +/* NOTREACHED */ +} + +/* + feasibly_covered -- determine if the cube c is feasibly covered + (i.e., if it is possible to raise all of the necessary variables + while still insuring orthogonality with R). Also, if c is feasibly + covered, then compute the new set of parts which are forced into + the lowering set. +*/ + +bool feasibly_covered(BB, c, RAISE, new_lower) +pcover BB; +pcube c, RAISE, new_lower; +{ + register pcube p, r = set_or(cube.temp[0], RAISE, c); + int dist; + pcube lastp; + + (void) set_copy(new_lower, cube.emptyset); + foreach_active_set(BB, lastp, p) { +#ifdef NO_INLINE + if ((dist = cdist01(p, r)) > 1) goto exit_if; +#else + {register int w,last;register unsigned int x;dist=0;if((last=cube.inword)!=-1) +{x=p[last]&r[last];if(x=~(x|x>>1)&cube.inmask)if((dist=count_ones(x))>1)goto +exit_if;for(w=1;w>1)&DISJOINT)if(dist==1||( +dist+=count_ones(x))>1)goto exit_if;}}}{register int w,var,last;register pcube +mask;for(var=cube.num_binary_vars;var1)goto exit_if;nextvar:;}} +#endif + if (dist == 0) + return FALSE; + else + (void) force_lower(new_lower, p, r); + exit_if: ; + } + return TRUE; +} + +/* + mincov -- transform the problem of expanding a cube to a maximally- + large prime implicant into the problem of selecting a minimum + cardinality cover over a family of sets. + + When we get to this point, we must unravel the remaining off-set. + This may be painful. +*/ + +void mincov(BB, RAISE, FREESET) +pcover BB; +pcube RAISE, FREESET; +{ + int expansion, nset, var, dist; + pset_family B; + register pcube xraise=cube.temp[0], xlower, p, last, plower; + +#ifdef RANDOM_MINCOV + dist = random() % set_ord(FREESET); + for(var = 0; var < cube.size && dist >= 0; var++) { + if (is_in_set(FREESET, var)) { + dist--; + } + } + + set_insert(RAISE, var); + set_remove(FREESET, var); + (void) essen_parts(BB, /*CC*/ (pcover) NULL, RAISE, FREESET); +#else + + /* Create B which are those cubes which we must avoid intersecting */ + B = new_cover(BB->active_count); + foreach_active_set(BB, last, p) { + plower = set_copy(GETSET(B, B->count++), cube.emptyset); + (void) force_lower(plower, p, RAISE); + } + + /* Determine how many sets it will blow up into after the unravel */ + nset = 0; + foreach_set(B, last, p) { + expansion = 1; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + if ((dist=set_dist(p, cube.var_mask[var])) > 1) { + expansion *= dist; + if (expansion > 500) goto heuristic_mincov; + } + } + nset += expansion; + if (nset > 500) goto heuristic_mincov; + } + + B = unravel(B, cube.num_binary_vars); + xlower = do_sm_minimum_cover(B); + + /* Add any remaining free parts to the raising set */ + (void) set_or(RAISE, RAISE, set_diff(xraise, FREESET, xlower)); + (void) set_copy(FREESET, cube.emptyset); /* free set is empty */ + BB->active_count = 0; /* BB satisfied */ + if (debug & EXPAND1) { + (void) printf("MINCOV: \tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); + } + sf_free(B); + set_free(xlower); + return; + +heuristic_mincov: + sf_free(B); + /* most_frequent will pick first free part */ + set_insert(RAISE, most_frequent(/*CC*/ (pcover) NULL, FREESET)); + (void) set_diff(FREESET, FREESET, RAISE); + essen_parts(BB, /*CC*/ (pcover) NULL, RAISE, FREESET); + return; +#endif +} + +/* + find_all_primes -- find all of the primes which cover the + currently reduced BB +*/ +pcover find_all_primes(BB, RAISE, FREESET) +pcover BB; +register pcube RAISE, FREESET; +{ + register pset last, p, plower; + pset_family B, B1; + + if (BB->active_count == 0) { + B1 = new_cover(1); + p = GETSET(B1, B1->count++); + (void) set_copy(p, RAISE); + SET(p, PRIME); + } else { + B = new_cover(BB->active_count); + foreach_active_set(BB, last, p) { + plower = set_copy(GETSET(B, B->count++), cube.emptyset); + (void) force_lower(plower, p, RAISE); + } + B = sf_rev_contain(unravel(B, cube.num_binary_vars)); + B1 = exact_minimum_cover(B); + foreach_set(B1, last, p) { + INLINEset_diff(p, FREESET, p); + INLINEset_or(p, p, RAISE); + SET(p, PRIME); + } + free_cover(B); + } + return B1; +} + +/* + all_primes -- foreach cube in F, generate all of the primes + which cover the cube. +*/ + +pcover all_primes(F, R) +pcover F, R; +{ + register pcube last, p, RAISE, FREESET; + pcover Fall_primes, B1; + + FREESET = new_cube(); + RAISE = new_cube(); + Fall_primes = new_cover(F->count); + + foreach_set(F, last, p) { + if (TESTP(p, PRIME)) { + Fall_primes = sf_addset(Fall_primes, p); + } else { + /* Setup for call to essential parts */ + (void) set_copy(RAISE, p); + (void) set_diff(FREESET, cube.fullset, RAISE); + setup_BB_CC(R, /* CC */ (pcover) NULL); + essen_parts(R, /* CC */ (pcover) NULL, RAISE, FREESET); + + /* Find all of the primes, and add them to the prime set */ + B1 = find_all_primes(R, RAISE, FREESET); + Fall_primes = sf_append(Fall_primes, B1); + } + } + + set_free(RAISE); + set_free(FREESET); + return Fall_primes; +} diff --git a/sis/espresso/gasp.c b/sis/espresso/gasp.c new file mode 100644 index 0000000..7d158bf --- /dev/null +++ b/sis/espresso/gasp.c @@ -0,0 +1,228 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/gasp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + module: gasp.c + + The "last_gasp" heuristic computes the reduction of each cube in + the cover (without replacement) and then performs an expansion of + these cubes. The cubes which expand to cover some other cube are + added to the original cover and irredundant finds a minimal subset. + + If one of the reduced cubes expands to cover some other reduced + cube, then the new prime thus generated is a candidate for reducing + the size of the cover. + + super_gasp is a variation on this strategy which extracts a minimal + subset from the set of all prime implicants which cover all + maximally reduced cubes. +*/ + +#include "espresso.h" + + +/* + * reduce_gasp -- compute the maximal reduction of each cube of F + * + * If a cube does not reduce, it remains prime; otherwise, it is marked + * as nonprime. If the cube is redundant (should NEVER happen here) we + * just crap out ... + * + * A cover with all of the cubes of F is returned. Those that did + * reduce are marked "NONPRIME"; those that reduced are marked "PRIME". + * The cubes are in the same order as in F. + */ +static pcover reduce_gasp(F, D) +pcover F, D; +{ + pcube p, last, cunder, *FD; + pcover G; + + G = new_cover(F->count); + FD = cube2list(F, D); + + /* Reduce cubes of F without replacement */ + foreach_set(F, last, p) { + cunder = reduce_cube(FD, p); + if (setp_empty(cunder)) { + fatal("empty reduction in reduce_gasp, shouldn't happen"); + } else if (setp_equal(cunder, p)) { + SET(cunder, PRIME); /* just to make sure */ + G = sf_addset(G, p); /* it did not reduce ... */ + } else { + RESET(cunder, PRIME); /* it reduced ... */ + G = sf_addset(G, cunder); + } + if (debug & GASP) { + (void) printf("REDUCE_GASP: %s reduced to %s\n", pc1(p), pc2(cunder)); + } + free_cube(cunder); + } + + free_cubelist(FD); + return G; +} + +/* + * expand_gasp -- expand each nonprime cube of F into a prime implicant + * + * The gasp strategy differs in that only those cubes which expand to + * cover some other cube are saved; also, all cubes are expanded + * regardless of whether they become covered or not. + */ + +pcover expand_gasp(F, D, R, Foriginal) +INOUT pcover F; +IN pcover D; +IN pcover R; +IN pcover Foriginal; +{ + int c1index; + pcover G; + + /* Try to expand each nonprime and noncovered cube */ + G = new_cover(10); + for(c1index = 0; c1index < F->count; c1index++) { + expand1_gasp(F, D, R, Foriginal, c1index, &G); + } + G = sf_dupl(G); + G = expand(G, R, /*nonsparse*/ FALSE); /* Make them prime ! */ + return G; +} + + + +/* + * expand1 -- Expand a single cube against the OFF-set, using the gasp strategy + */ +void expand1_gasp(F, D, R, Foriginal, c1index, G) +pcover F; /* reduced cubes of ON-set */ +pcover D; /* DC-set */ +pcover R; /* OFF-set */ +pcover Foriginal; /* ON-set before reduction (same order as F) */ +int c1index; /* which index of F (or Freduced) to be checked */ +pcover *G; +{ + register int c2index; + register pcube p, last, c2under; + pcube RAISE, FREESET, temp, *FD, c2essential; + pcover F1; + + if (debug & EXPAND1) { + (void) printf("\nEXPAND1_GASP: \t%s\n", pc1(GETSET(F, c1index))); + } + + RAISE = new_cube(); + FREESET = new_cube(); + temp = new_cube(); + + /* Initialize the OFF-set */ + R->active_count = R->count; + foreach_set(R, last, p) { + SET(p, ACTIVE); + } + /* Initialize the reduced ON-set, all nonprime cubes become active */ + F->active_count = F->count; + foreachi_set(F, c2index, c2under) { + if (c1index == c2index || TESTP(c2under, PRIME)) { + F->active_count--; + RESET(c2under, ACTIVE); + } else { + SET(c2under, ACTIVE); + } + } + + /* Initialize the raising and unassigned sets */ + (void) set_copy(RAISE, GETSET(F, c1index)); + (void) set_diff(FREESET, cube.fullset, RAISE); + + /* Determine parts which must be lowered */ + essen_parts(R, F, RAISE, FREESET); + + /* Determine parts which can always be raised */ + essen_raising(R, RAISE, FREESET); + + /* See which, if any, of the reduced cubes we can cover */ + foreachi_set(F, c2index, c2under) { + if (TESTP(c2under, ACTIVE)) { + /* See if this cube can be covered by an expansion */ + if (setp_implies(c2under, RAISE) || + feasibly_covered(R, c2under, RAISE, temp)) { + + /* See if c1under can expanded to cover c2 reduced against + * (F - c1) u c1under; if so, c2 can definitely be removed ! + */ + + /* Copy F and replace c1 with c1under */ + F1 = sf_save(Foriginal); + (void) set_copy(GETSET(F1, c1index), GETSET(F, c1index)); + + /* Reduce c2 against ((F - c1) u c1under) */ + FD = cube2list(F1, D); + c2essential = reduce_cube(FD, GETSET(F1, c2index)); + free_cubelist(FD); + sf_free(F1); + + /* See if c2essential is covered by an expansion of c1under */ + if (feasibly_covered(R, c2essential, RAISE, temp)) { + (void) set_or(temp, RAISE, c2essential); + RESET(temp, PRIME); /* cube not prime */ + *G = sf_addset(*G, temp); + } + set_free(c2essential); + } + } + } + + free_cube(RAISE); + free_cube(FREESET); + free_cube(temp); +} + +/* irred_gasp -- Add new primes to F and find an irredundant subset */ +pcover irred_gasp(F, D, G) +pcover F, D, G; /* G is disposed of */ +{ + if (G->count != 0) + F = irredundant(sf_append(F, G), D); + else + free_cover(G); + return F; +} + + +/* last_gasp */ +pcover last_gasp(F, D, R, cost) +pcover F, D, R; +cost_t *cost; +{ + pcover G, G1; + + EXECUTE(G = reduce_gasp(F, D), GREDUCE_TIME, G, *cost); + EXECUTE(G1 = expand_gasp(G, D, R, F), GEXPAND_TIME, G1, *cost); + free_cover(G); + EXECUTE(F = irred_gasp(F, D, G1), GIRRED_TIME, F, *cost); + return F; +} + + +/* super_gasp */ +pcover super_gasp(F, D, R, cost) +pcover F, D, R; +cost_t *cost; +{ + pcover G, G1; + + EXECUTE(G = reduce_gasp(F, D), GREDUCE_TIME, G, *cost); + EXECUTE(G1 = all_primes(G, R), GEXPAND_TIME, G1, *cost); + free_cover(G); + EXEC(G = sf_dupl(sf_append(F, G1)), "NEWPRIMES", G); + EXECUTE(F = irredundant(G, D), IRRED_TIME, F, *cost); + return F; +} diff --git a/sis/espresso/globals.c b/sis/espresso/globals.c new file mode 100644 index 0000000..fa56632 --- /dev/null +++ b/sis/espresso/globals.c @@ -0,0 +1,76 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/globals.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + +/* + * Global Variable Declarations + */ + +unsigned int debug; /* debug parameter */ +bool verbose_debug; /* -v: whether to print a lot */ +char *total_name[TIME_COUNT]; /* basic function names */ +long total_time[TIME_COUNT]; /* time spent in basic fcts */ +int total_calls[TIME_COUNT]; /* # calls to each fct */ + +bool echo_comments; /* turned off by -eat option */ +bool echo_unknown_commands; /* always true ?? */ +bool force_irredundant; /* -nirr command line option */ +bool skip_make_sparse; +bool kiss; /* -kiss command line option */ +bool pos; /* -pos command line option */ +bool print_solution; /* -x command line option */ +bool recompute_onset; /* -onset command line option */ +bool remove_essential; /* -ness command line option */ +bool single_expand; /* -fast command line option */ +bool summary; /* -s command line option */ +bool trace; /* -t command line option */ +bool unwrap_onset; /* -nunwrap command line option */ +bool use_random_order; /* -random command line option */ +bool use_super_gasp; /* -strong command line option */ +char *filename; /* filename PLA was read from */ + +struct pla_types_struct pla_types[] = { + "-f", F_type, + "-r", R_type, + "-d", D_type, + "-fd", FD_type, + "-fr", FR_type, + "-dr", DR_type, + "-fdr", FDR_type, + "-fc", F_type | CONSTRAINTS_type, + "-rc", R_type | CONSTRAINTS_type, + "-dc", D_type | CONSTRAINTS_type, + "-fdc", FD_type | CONSTRAINTS_type, + "-frc", FR_type | CONSTRAINTS_type, + "-drc", DR_type | CONSTRAINTS_type, + "-fdrc", FDR_type | CONSTRAINTS_type, + "-pleasure", PLEASURE_type, + "-eqn", EQNTOTT_type, + "-eqntott", EQNTOTT_type, + "-kiss", KISS_type, + "-cons", CONSTRAINTS_type, + "-scons", SYMBOLIC_CONSTRAINTS_type, + 0, 0 +}; + + +struct cube_struct cube, temp_cube_save; +struct cdata_struct cdata, temp_cdata_save; + +int bit_count[256] = { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 +}; diff --git a/sis/espresso/hack.c b/sis/espresso/hack.c new file mode 100644 index 0000000..c09982b --- /dev/null +++ b/sis/espresso/hack.c @@ -0,0 +1,641 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/hack.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + +map_dcset(PLA) +pPLA PLA; +{ + int var, i; + pcover Tplus, Tminus, Tplusbar, Tminusbar; + pcover newf, term1, term2, dcset, dcsetbar; + pcube cplus, cminus, last, p; + + if (PLA->label == NIL(char *) || PLA->label[0] == NIL(char)) + return; + + /* try to find a binary variable named "DONT_CARE" */ + var = -1; + for(i = 0; i < cube.num_binary_vars * 2; i++) { + if (strncmp(PLA->label[i], "DONT_CARE", 9) == 0 || + strncmp(PLA->label[i], "DONTCARE", 8) == 0 || + strncmp(PLA->label[i], "dont_care", 9) == 0 || + strncmp(PLA->label[i], "dontcare", 8) == 0) { + var = i/2; + break; + } + } + if (var == -1) { + return; + } + + /* form the cofactor cubes for the don't-care variable */ + cplus = set_save(cube.fullset); + cminus = set_save(cube.fullset); + set_remove(cplus, var*2); + set_remove(cminus, var*2 + 1); + + /* form the don't-care set */ + EXEC(simp_comp(cofactor(cube1list(PLA->F), cplus), &Tplus, &Tplusbar), + "simpcomp+", Tplus); + EXEC(simp_comp(cofactor(cube1list(PLA->F), cminus), &Tminus, &Tminusbar), + "simpcomp-", Tminus); + EXEC(term1 = cv_intersect(Tplus, Tminusbar), "term1 ", term1); + EXEC(term2 = cv_intersect(Tminus, Tplusbar), "term2 ", term2); + EXEC(dcset = sf_union(term1, term2), "union ", dcset); + EXEC(simp_comp(cube1list(dcset), &PLA->D, &dcsetbar), "simplify", PLA->D); + EXEC(newf = cv_intersect(PLA->F, dcsetbar), "separate ", PLA->F); + free_cover(PLA->F); + PLA->F = newf; + free_cover(Tplus); + free_cover(Tminus); + free_cover(Tplusbar); + free_cover(Tminusbar); + free_cover(dcsetbar); + + /* remove any cubes dependent on the DONT_CARE variable */ + (void) sf_active(PLA->F); + foreach_set(PLA->F, last, p) { + if (! is_in_set(p, var*2) || ! is_in_set(p, var*2+1)) { + RESET(p, ACTIVE); + } + } + PLA->F = sf_inactive(PLA->F); + + /* resize the cube and delete the don't-care variable */ + setdown_cube(); + for(i = 2*var+2; i < cube.size; i++) { + PLA->label[i-2] = PLA->label[i]; + } + for(i = var+1; i < cube.num_vars; i++) { + cube.part_size[i-1] = cube.part_size[i]; + } + cube.num_binary_vars--; + cube.num_vars--; + cube_setup(); + PLA->F = sf_delc(PLA->F, 2*var, 2*var+1); + PLA->D = sf_delc(PLA->D, 2*var, 2*var+1); +} + +map_output_symbolic(PLA) +pPLA PLA; +{ + pset_family newF, newD; + pset compress; + symbolic_t *p1; + symbolic_list_t *p2; + int i, bit, tot_size, base, old_size; + + /* Remove the DC-set from the ON-set (is this necessary ??) */ + if (PLA->D->count > 0) { + sf_free(PLA->F); + PLA->F = complement(cube2list(PLA->D, PLA->R)); + } + + /* tot_size = width added for all symbolic variables */ + tot_size = 0; + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + if (p2->pos<0 || p2->pos>=cube.part_size[cube.output]) { + fatal("symbolic-output index out of range"); +/* } else if (p2->variable != cube.output) { + fatal("symbolic-output label must be an output");*/ + } + } + tot_size += 1 << p1->symbolic_list_length; + } + + /* adjust the indices to skip over new outputs */ + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + p2->pos += tot_size; + } + } + + /* resize the cube structure -- add enough for the one-hot outputs */ + old_size = cube.size; + cube.part_size[cube.output] += tot_size; + setdown_cube(); + cube_setup(); + + /* insert space in the output part for the one-hot output */ + base = cube.first_part[cube.output]; + PLA->F = sf_addcol(PLA->F, base, tot_size); + PLA->D = sf_addcol(PLA->D, base, tot_size); + PLA->R = sf_addcol(PLA->R, base, tot_size); + + /* do the real work */ + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + newF = new_cover(100); + newD = new_cover(100); + find_inputs(NIL(set_family_t), PLA, p1->symbolic_list, base, 0, + &newF, &newD); +/* + * Not sure what this means + find_dc_inputs(PLA, p1->symbolic_list, + base, 1 << p1->symbolic_list_length, &newF, &newD); + */ + free_cover(PLA->F); + PLA->F = newF; +/* + * retain OLD DC-set -- but we've lost the don't-care arc information + * (it defaults to branch to the zero state) + free_cover(PLA->D); + PLA->D = newD; + */ + free_cover(newD); + base += 1 << p1->symbolic_list_length; + } + + /* delete the old outputs, and resize the cube */ + compress = set_full(newF->sf_size); + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + bit = cube.first_part[cube.output] + p2->pos; + set_remove(compress, bit); + } + } + cube.part_size[cube.output] -= newF->sf_size - set_ord(compress); + setdown_cube(); + cube_setup(); + PLA->F = sf_compress(PLA->F, compress); + PLA->D = sf_compress(PLA->D, compress); + if (cube.size != PLA->F->sf_size) fatal("error"); + + /* Quick minimization */ + PLA->F = sf_contain(PLA->F); + PLA->D = sf_contain(PLA->D); + for(i = 0; i < cube.num_vars; i++) { + PLA->F = d1merge(PLA->F, i); + PLA->D = d1merge(PLA->D, i); + } + PLA->F = sf_contain(PLA->F); + PLA->D = sf_contain(PLA->D); + + free_cover(PLA->R); + PLA->R = new_cover(0); + + symbolic_hack_labels(PLA, PLA->symbolic_output, + compress, cube.size, old_size, tot_size); + set_free(compress); +} + + +find_inputs(A, PLA, list, base, value, newF, newD) +pcover A; +pPLA PLA; +symbolic_list_t *list; +int base, value; +pcover *newF, *newD; +{ + pcover S, S1; + register pset last, p; + + /* + * A represents th 'input' values for which the outputs assume + * the integer value 'value + */ + if (list == NIL(symbolic_list_t)) { + /* + * Simulate these inputs against the on-set; then, insert into the + * new on-set a 1 in the proper position + */ + S = cv_intersect(A, PLA->F); + foreach_set(S, last, p) { + set_insert(p, base + value); + } + *newF = sf_append(*newF, S); + + /* + * 'simulate' these inputs against the don't-care set + S = cv_intersect(A, PLA->D); + *newD = sf_append(*newD, S); + */ + + } else { + /* intersect and recur with the OFF-set */ + S = cof_output(PLA->R, cube.first_part[cube.output] + list->pos); + if (A != NIL(set_family_t)) { + S1 = cv_intersect(A, S); + free_cover(S); + S = S1; + } + find_inputs(S, PLA, list->next, base, value*2, newF, newD); + free_cover(S); + + /* intersect and recur with the ON-set */ + S = cof_output(PLA->F, cube.first_part[cube.output] + list->pos); + if (A != NIL(set_family_t)) { + S1 = cv_intersect(A, S); + free_cover(S); + S = S1; + } + find_inputs(S, PLA, list->next, base, value*2 + 1, newF, newD); + free_cover(S); + } +} + + +#if 0 +find_dc_inputs(PLA, list, base, maxval, newF, newD) +pPLA PLA; +symbolic_list_t *list; +int base, maxval; +pcover *newF, *newD; +{ + pcover A, S, S1; + symbolic_list_t *p2; + register pset p, last; + register int i; + + /* painfully find the points for which the symbolic output is dc */ + A = NIL(set_family_t); + for(p2=list; p2!=NIL(symbolic_list_t); p2=p2->next) { + S = cof_output(PLA->D, cube.first_part[cube.output] + p2->pos); + if (A == NIL(set_family_t)) { + A = S; + } else { + S1 = cv_intersect(A, S); + free_cover(S); + free_cover(A); + A = S1; + } + } + + S = cv_intersect(A, PLA->F); + *newF = sf_append(*newF, S); + + S = cv_intersect(A, PLA->D); + foreach_set(S, last, p) { + for(i = base; i < base + maxval; i++) { + set_insert(p, i); + } + } + *newD = sf_append(*newD, S); + free_cover(A); +} +#endif + +map_symbolic(PLA) +pPLA PLA; +{ + symbolic_t *p1; + symbolic_list_t *p2; + int var, base, num_vars, num_binary_vars, *new_part_size; + int new_size, size_added, num_deleted_vars, num_added_vars, newvar; + pset compress; + + /* Verify legal values are in the symbolic lists */ + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + if (p2->variable < 0 || p2->variable >= cube.num_binary_vars) { + fatal(".symbolic requires binary variables"); + } + } + } + + /* + * size_added = width added for all symbolic variables + * num_deleted_vars = # binary variables to be deleted + * num_added_vars = # new mv variables + * compress = a cube which will be used to compress the set families + */ + size_added = 0; + num_added_vars = 0; + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + size_added += 1 << p1->symbolic_list_length; + num_added_vars++; + } + compress = set_full(PLA->F->sf_size + size_added); + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + set_remove(compress, p2->variable*2); + set_remove(compress, p2->variable*2+1); + } + } + num_deleted_vars = ((PLA->F->sf_size + size_added) - set_ord(compress))/2; + + /* compute the new cube constants */ + num_vars = cube.num_vars - num_deleted_vars + num_added_vars; + num_binary_vars = cube.num_binary_vars - num_deleted_vars; + new_size = cube.size - num_deleted_vars*2 + size_added; + new_part_size = ALLOC(int, num_vars); + new_part_size[num_vars-1] = cube.part_size[cube.num_vars-1]; + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) { + new_part_size[var-num_deleted_vars] = cube.part_size[var]; + } + + /* re-size the covers, opening room for the new mv variables */ + base = cube.first_part[cube.output]; + PLA->F = sf_addcol(PLA->F, base, size_added); + PLA->D = sf_addcol(PLA->D, base, size_added); + PLA->R = sf_addcol(PLA->R, base, size_added); + + /* compute the values for the new mv variables */ + newvar = (cube.num_vars - 1) - num_deleted_vars; + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + PLA->F = map_symbolic_cover(PLA->F, p1->symbolic_list, base); + PLA->D = map_symbolic_cover(PLA->D, p1->symbolic_list, base); + PLA->R = map_symbolic_cover(PLA->R, p1->symbolic_list, base); + base += 1 << p1->symbolic_list_length; + new_part_size[newvar++] = 1 << p1->symbolic_list_length; + } + + /* delete the binary variables which disappear */ + PLA->F = sf_compress(PLA->F, compress); + PLA->D = sf_compress(PLA->D, compress); + PLA->R = sf_compress(PLA->R, compress); + + symbolic_hack_labels(PLA, PLA->symbolic, compress, + new_size, cube.size, size_added); + setdown_cube(); + FREE(cube.part_size); + cube.num_vars = num_vars; + cube.num_binary_vars = num_binary_vars; + cube.part_size = new_part_size; + cube_setup(); + set_free(compress); +} + + +pcover map_symbolic_cover(T, list, base) +pcover T; +symbolic_list_t *list; +int base; +{ + pset last, p; + foreach_set(T, last, p) { + form_bitvector(p, base, 0, list); + } + return T; +} + + +form_bitvector(p, base, value, list) +pset p; /* old cube, looking at binary variables */ +int base; /* where in mv cube the new variable starts */ +int value; /* current value for this recursion */ +symbolic_list_t *list; /* current place in the symbolic list */ +{ + if (list == NIL(symbolic_list_t)) { + set_insert(p, base + value); + } else { + switch(GETINPUT(p, list->variable)) { + case ZERO: + form_bitvector(p, base, value*2, list->next); + break; + case ONE: + form_bitvector(p, base, value*2+1, list->next); + break; + case TWO: + form_bitvector(p, base, value*2, list->next); + form_bitvector(p, base, value*2+1, list->next); + break; + default: + fatal("bad cube in form_bitvector"); + } + } +} + + +symbolic_hack_labels(PLA, list, compress, new_size, old_size, size_added) +pPLA PLA; +symbolic_t *list; +pset compress; +int new_size, old_size, size_added; +{ + int i, base; + char **oldlabel; + symbolic_t *p1; + symbolic_label_t *p3; + + /* hack with the labels */ + if ((oldlabel = PLA->label) == NIL(char *)) + return; + PLA->label = ALLOC(char *, new_size); + for(i = 0; i < new_size; i++) { + PLA->label[i] = NIL(char); + } + + /* copy the binary variable labels and unchanged mv variable labels */ + base = 0; + for(i = 0; i < cube.first_part[cube.output]; i++) { + if (is_in_set(compress, i)) { + PLA->label[base++] = oldlabel[i]; + } else { + if (oldlabel[i] != NIL(char)) { + FREE(oldlabel[i]); + } + } + } + + /* add the user-defined labels for the symbolic outputs */ + for(p1 = list; p1 != NIL(symbolic_t); p1 = p1->next) { + p3 = p1->symbolic_label; + for(i = 0; i < (1 << p1->symbolic_list_length); i++) { + if (p3 == NIL(symbolic_label_t)) { + PLA->label[base+i] = ALLOC(char, 10); + (void) sprintf(PLA->label[base+i], "X%d", i); + } else { + PLA->label[base+i] = p3->label; + p3 = p3->next; + } + } + base += 1 << p1->symbolic_list_length; + } + + /* copy the labels for the binary outputs which remain */ + for(i = cube.first_part[cube.output]; i < old_size; i++) { + if (is_in_set(compress, i + size_added)) { + PLA->label[base++] = oldlabel[i]; + } else { + if (oldlabel[i] != NIL(char)) { + FREE(oldlabel[i]); + } + } + } + FREE(oldlabel); +} + +static pcover fsm_simplify(F) +pcover F; +{ + pcover D, R; + D = new_cover(0); + R = complement(cube1list(F)); + F = espresso(F, D, R); + free_cover(D); + free_cover(R); + return F; +} + + +disassemble_fsm(PLA, verbose_mode) +pPLA PLA; +int verbose_mode; +{ + int nin, nstates, nout; + int before, after, present_state, next_state, i, j; + pcube next_state_mask, present_state_mask, state_mask, p, p1, last; + pcover go_nowhere, F, tF; + + /* We make the DISGUSTING assumption that the first 'n' outputs have + * been created by .symbolic-output, and represent a one-hot encoding + * of the next state. 'n' is the size of the second-to-last multiple- + * valued variable (i.e., before the outputs + */ + + if (cube.num_vars - cube.num_binary_vars != 2) { + (void) fprintf(stderr, + "use .symbolic and .symbolic-output to specify\n"); + (void) fprintf(stderr, + "the present state and next state field information\n"); + fatal("disassemble_pla: need two multiple-valued variables\n"); + } + + nin = cube.num_binary_vars; + nstates = cube.part_size[cube.num_binary_vars]; + nout = cube.part_size[cube.num_vars - 1]; + if (nout < nstates) { + (void) fprintf(stderr, + "use .symbolic and .symbolic-output to specify\n"); + (void) fprintf(stderr, + "the present state and next state field information\n"); + fatal("disassemble_pla: # outputs < # states\n"); + } + + + present_state = cube.first_part[cube.num_binary_vars]; + present_state_mask = new_cube(); + for(i = 0; i < nstates; i++) { + set_insert(present_state_mask, i + present_state); + } + + next_state = cube.first_part[cube.num_binary_vars+1]; + next_state_mask = new_cube(); + for(i = 0; i < nstates; i++) { + set_insert(next_state_mask, i + next_state); + } + + state_mask = set_or(new_cube(), next_state_mask, present_state_mask); + + F = new_cover(10); + + + /* + * check for arcs which go from ANY state to state #i + */ + for(i = 0; i < nstates; i++) { + tF = new_cover(10); + foreach_set(PLA->F, last, p) { + if (setp_implies(present_state_mask, p)) { /* from any state ! */ + if (is_in_set(p, next_state + i)) { + tF = sf_addset(tF, p); + } + } + } + before = tF->count; + if (before > 0) { + tF = fsm_simplify(tF); + /* don't allow the next state to disappear ... */ + foreach_set(tF, last, p) { + set_insert(p, next_state + i); + } + after = tF->count; + F = sf_append(F, tF); + if (verbose_mode) { + (void) printf("# state EVERY to %d, before=%d after=%d\n", + i, before, after); + } + } + } + + + /* + * some 'arcs' may NOT have a next state -- handle these + * we must unravel the present state part + */ + go_nowhere = new_cover(10); + foreach_set(PLA->F, last, p) { + if (setp_disjoint(p, next_state_mask)) { /* no next state !! */ + go_nowhere = sf_addset(go_nowhere, p); + } + } + before = go_nowhere->count; + go_nowhere = unravel_range(go_nowhere, + cube.num_binary_vars, cube.num_binary_vars); + after = go_nowhere->count; + F = sf_append(F, go_nowhere); + if (verbose_mode) { + (void) printf("# state ANY to NOWHERE, before=%d after=%d\n", before, after); + } + + + /* + * minimize cover for all arcs from state #i to state #j + */ + for(i = 0; i < nstates; i++) { + for(j = 0; j < nstates; j++) { + tF = new_cover(10); + foreach_set(PLA->F, last, p) { + /* not EVERY state */ + if (! setp_implies(present_state_mask, p)) { + if (is_in_set(p, present_state + i)) { + if (is_in_set(p, next_state + j)) { + p1 = set_save(p); + (void) set_diff(p1, p1, state_mask); + set_insert(p1, present_state + i); + set_insert(p1, next_state + j); + tF = sf_addset(tF, p1); + set_free(p1); + } + } + } + } + before = tF->count; + if (before > 0) { + tF = fsm_simplify(tF); + /* don't allow the next state to disappear ... */ + foreach_set(tF, last, p) { + set_insert(p, next_state + j); + } + after = tF->count; + F = sf_append(F, tF); + if (verbose_mode) { + (void) printf("# state %d to %d, before=%d after=%d\n", + i, j, before, after); + } + } + } + } + + + free_cube(state_mask); + free_cube(present_state_mask); + free_cube(next_state_mask); + + free_cover(PLA->F); + PLA->F = F; + free_cover(PLA->D); + PLA->D = new_cover(0); + + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = nin; + cube.num_vars = nin + 3; + cube.part_size = ALLOC(int, cube.num_vars); + cube.part_size[cube.num_binary_vars] = nstates; + cube.part_size[cube.num_binary_vars+1] = nstates; + cube.part_size[cube.num_binary_vars+2] = nout - nstates; + cube_setup(); + + foreach_set(PLA->F, last, p) { + kiss_print_cube(stdout, PLA, p, "~1"); + } +} diff --git a/sis/espresso/irred.c b/sis/espresso/irred.c new file mode 100644 index 0000000..0e23189 --- /dev/null +++ b/sis/espresso/irred.c @@ -0,0 +1,440 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/irred.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + +static void fcube_is_covered(); +static void ftautology(); +static bool ftaut_special_cases(); + + +static int Rp_current; + +/* + * irredundant -- Return a minimal subset of F + */ + +pcover +irredundant(F, D) +pcover F, D; +{ + mark_irredundant(F, D); + return sf_inactive(F); +} + + +/* + * mark_irredundant -- find redundant cubes, and mark them "INACTIVE" + */ + +void +mark_irredundant(F, D) +pcover F, D; +{ + pcover E, Rt, Rp; + pset p, p1, last; + sm_matrix *table; + sm_row *cover; + sm_element *pe; + + /* extract a minimum cover */ + irred_split_cover(F, D, &E, &Rt, &Rp); + table = irred_derive_table(D, E, Rp); + cover = sm_minimum_cover(table, NIL(int), /* heuristic */ 1, /* debug */ 0); + + /* mark the cubes for the result */ + foreach_set(F, last, p) { + RESET(p, ACTIVE); + RESET(p, RELESSEN); + } + foreach_set(E, last, p) { + p1 = GETSET(F, SIZE(p)); + assert(setp_equal(p1, p)); + SET(p1, ACTIVE); + SET(p1, RELESSEN); /* for essen(), mark as rel. ess. */ + } + sm_foreach_row_element(cover, pe) { + p1 = GETSET(F, pe->col_num); + SET(p1, ACTIVE); + } + + if (debug & IRRED) { + (void) printf("# IRRED: F=%d E=%d R=%d Rt=%d Rp=%d Rc=%d Final=%d Bound=%d\n", + F->count, E->count, Rt->count+Rp->count, Rt->count, Rp->count, + cover->length, E->count + cover->length, 0); + } + + free_cover(E); + free_cover(Rt); + free_cover(Rp); + sm_free(table); + sm_row_free(cover); +} + +/* + * irred_split_cover -- find E, Rt, and Rp from the cover F, D + * + * E -- relatively essential cubes + * Rt -- totally redundant cubes + * Rp -- partially redundant cubes + */ + +void +irred_split_cover(F, D, E, Rt, Rp) +pcover F, D; +pcover *E, *Rt, *Rp; +{ + register pcube p, last; + register int index; + pcover R; + pcube *FD, *ED; + + /* number the cubes of F -- these numbers track into E, Rp, Rt, etc. */ + index = 0; + foreach_set(F, last, p) { + PUTSIZE(p, index); + index++; + } + + *E = new_cover(10); + *Rt = new_cover(10); + *Rp = new_cover(10); + R = new_cover(10); + + /* Split F into E and R */ + FD = cube2list(F, D); + foreach_set(F, last, p) { + if (cube_is_covered(FD, p)) { + R = sf_addset(R, p); + } else { + *E = sf_addset(*E, p); + } + if (debug & IRRED1) { + (void) printf("IRRED1: zr=%d ze=%d to-go=%d time=%s\n", + R->count, (*E)->count, F->count - (R->count + (*E)->count), + print_time(ptime())); + } + } + free_cubelist(FD); + + /* Split R into Rt and Rp */ + ED = cube2list(*E, D); + foreach_set(R, last, p) { + if (cube_is_covered(ED, p)) { + *Rt = sf_addset(*Rt, p); + } else { + *Rp = sf_addset(*Rp, p); + } + if (debug & IRRED1) { + (void) printf("IRRED1: zr=%d zrt=%d to-go=%d time=%s\n", + (*Rp)->count, (*Rt)->count, + R->count - ((*Rp)->count +(*Rt)->count), print_time(ptime())); + } + } + free_cubelist(ED); + + free_cover(R); +} + +/* + * irred_derive_table -- given the covers D, E and the set of + * partially redundant primes Rp, build a covering table showing + * possible selections of primes to cover Rp. + */ + +sm_matrix * +irred_derive_table(D, E, Rp) +pcover D, E, Rp; +{ + register pcube last, p, *list; + sm_matrix *table; + int size_last_dominance, i; + + /* Mark each cube in DE as not part of the redundant set */ + foreach_set(D, last, p) { + RESET(p, REDUND); + } + foreach_set(E, last, p) { + RESET(p, REDUND); + } + + /* Mark each cube in Rp as partially redundant */ + foreach_set(Rp, last, p) { + SET(p, REDUND); /* belongs to redundant set */ + } + + /* For each cube in Rp, find ways to cover its minterms */ + list = cube3list(D, E, Rp); + table = sm_alloc(); + size_last_dominance = 0; + i = 0; + foreach_set(Rp, last, p) { + Rp_current = SIZE(p); + fcube_is_covered(list, p, table); + RESET(p, REDUND); /* can now consider this cube redundant */ + if (debug & IRRED1) { + (void) printf("IRRED1: %d of %d to-go=%d, table=%dx%d time=%s\n", + i, Rp->count, Rp->count - i, + table->nrows, table->ncols, print_time(ptime())); + } + /* try to keep memory limits down by reducing table as we go along */ + if (table->nrows - size_last_dominance > 1000) { + (void) sm_row_dominance(table); + size_last_dominance = table->nrows; + if (debug & IRRED1) { + (void) printf("IRRED1: delete redundant rows, now %dx%d\n", + table->nrows, table->ncols); + } + } + i++; + } + free_cubelist(list); + + return table; +} + +/* cube_is_covered -- determine if a cubelist "covers" a single cube */ +bool +cube_is_covered(T, c) +pcube *T, c; +{ + return tautology(cofactor(T,c)); +} + + + +/* tautology -- answer the tautology question for T */ +bool +tautology(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best, result; + static int taut_level = 0; + + if (debug & TAUT) { + debug_print(T, "TAUTOLOGY", taut_level++); + } + + if ((result = taut_special_cases(T)) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, TAUT); + result = tautology(scofactor(T, cl, best)) && + tautology(scofactor(T, cr, best)); + free_cubelist(T); + free_cube(cl); + free_cube(cr); + } + + if (debug & TAUT) { + (void) printf("exit TAUTOLOGY[%d]: %s\n", --taut_level, print_bool(result)); + } + return result; +} + +/* + * taut_special_cases -- check special cases for tautology + */ + +bool +taut_special_cases(T) +pcube *T; /* will be disposed if answer is determined */ +{ + register pcube *T1, *Tsave, p, ceil=cube.temp[0], temp=cube.temp[1]; + pcube *A, *B; + int var; + + /* Check for a row of all 1's which implies tautology */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, T[0])) { + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which implies no tautology */ +start: + INLINEset_copy(ceil, T[0]); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + free_cubelist(T); + return FALSE; + } + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If function is unate (and no row of all 1's), then no tautology */ + if (cdata.vars_unate == cdata.vars_active) { + free_cubelist(T); + return FALSE; + + /* If active in a single variable (and no column of 0's) then tautology */ + } else if (cdata.vars_active == 1) { + free_cubelist(T); + return TRUE; + + /* Check for unate variables, and reduce cover if there are any */ + } else if (cdata.vars_unate != 0) { + /* Form a cube "ceil" with full variables in the unate variables */ + (void) set_copy(ceil, cube.emptyset); + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + INLINEset_or(ceil, ceil, cube.var_mask[var]); + } + } + + /* Save only those cubes that are "full" in all unate variables */ + for(Tsave = T1 = T+2; (p = *T1++) != 0; ) { + if (setp_implies(ceil, set_or(temp, p, T[0]))) { + *Tsave++ = p; + } + } + *Tsave++ = NULL; + T[1] = (pcube) Tsave; + + if (debug & TAUT) { + (void) printf("UNATE_REDUCTION: %d unate variables, reduced to %d\n", + cdata.vars_unate, CUBELISTSIZE(T)); + } + goto start; + + /* Check for component reduction */ + } else if (cdata.var_zeros[cdata.best] < CUBELISTSIZE(T) / 2) { + if (cubelist_partition(T, &A, &B, debug & TAUT) == 0) { + return MAYBE; + } else { + free_cubelist(T); + if (tautology(A)) { + free_cubelist(B); + return TRUE; + } else { + return tautology(B); + } + } + } + + /* We tried as hard as we could, but must recurse from here on */ + return MAYBE; +} + +/* fcube_is_covered -- determine exactly how a cubelist "covers" a cube */ +static void +fcube_is_covered(T, c, table) +pcube *T, c; +sm_matrix *table; +{ + ftautology(cofactor(T,c), table); +} + + +/* ftautology -- find ways to make a tautology */ +static void +ftautology(T, table) +pcube *T; /* T will be disposed of */ +sm_matrix *table; +{ + register pcube cl, cr; + register int best; + static int ftaut_level = 0; + + if (debug & TAUT) { + debug_print(T, "FIND_TAUTOLOGY", ftaut_level++); + } + + if (ftaut_special_cases(T, table) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, TAUT); + + ftautology(scofactor(T, cl, best), table); + ftautology(scofactor(T, cr, best), table); + + free_cubelist(T); + free_cube(cl); + free_cube(cr); + } + + if (debug & TAUT) { + (void) printf("exit FIND_TAUTOLOGY[%d]: table is %d by %d\n", + --ftaut_level, table->nrows, table->ncols); + } +} + +static bool +ftaut_special_cases(T, table) +pcube *T; /* will be disposed if answer is determined */ +sm_matrix *table; +{ + register pcube *T1, *Tsave, p, temp = cube.temp[0], ceil = cube.temp[1]; + int var, rownum; + + /* Check for a row of all 1's in the essential cubes */ + for(T1 = T+2; (p = *T1++) != 0; ) { + if (! TESTP(p, REDUND)) { + if (full_row(p, T[0])) { + /* subspace is covered by essentials -- no new rows for table */ + free_cubelist(T); + return TRUE; + } + } + } + + /* Collect column counts, determine unate variables, etc. */ +start: + massive_count(T); + + /* If function is unate, find the rows of all 1's */ + if (cdata.vars_unate == cdata.vars_active) { + /* find which nonessentials cover this subspace */ + rownum = table->last_row ? table->last_row->row_num+1 : 0; + (void) sm_insert(table, rownum, Rp_current); + for(T1 = T+2; (p = *T1++) != 0; ) { + if (TESTP(p, REDUND)) { + /* See if a redundant cube covers this leaf */ + if (full_row(p, T[0])) { + (void) sm_insert(table, rownum, (int) SIZE(p)); + } + } + } + free_cubelist(T); + return TRUE; + + /* Perform unate reduction if there are any unate variables */ + } else if (cdata.vars_unate != 0) { + /* Form a cube "ceil" with full variables in the unate variables */ + (void) set_copy(ceil, cube.emptyset); + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + INLINEset_or(ceil, ceil, cube.var_mask[var]); + } + } + + /* Save only those cubes that are "full" in all unate variables */ + for(Tsave = T1 = T+2; (p = *T1++) != 0; ) { + if (setp_implies(ceil, set_or(temp, p, T[0]))) { + *Tsave++ = p; + } + } + *Tsave++ = 0; + T[1] = (pcube) Tsave; + + if (debug & TAUT) { + (void) printf("UNATE_REDUCTION: %d unate variables, reduced to %d\n", + cdata.vars_unate, CUBELISTSIZE(T)); + } + goto start; + } + + /* Not much we can do about it */ + return MAYBE; +} diff --git a/sis/espresso/map.c b/sis/espresso/map.c new file mode 100644 index 0000000..dfd79f8 --- /dev/null +++ b/sis/espresso/map.c @@ -0,0 +1,115 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/map.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + +static pcube Gcube; +static pset Gminterm; + +pset minterms(T) +pcover T; +{ + int size, var; + register pcube last; + + size = 1; + for(var = 0; var < cube.num_vars; var++) + size *= cube.part_size[var]; + Gminterm = set_new(size); + + foreach_set(T, last, Gcube) + explode(cube.num_vars-1, 0); + + return Gminterm; +} + + +void explode(var, z) +int var, z; +{ + int i, last = cube.last_part[var]; + for(i=cube.first_part[var], z *= cube.part_size[var]; i<=last; i++, z++) + if (is_in_set(Gcube, i)) + if (var == 0) + set_insert(Gminterm, z); + else + explode(var-1, z); +} + + +static int mapindex[16][16] = { + 0, 1, 3, 2, 16, 17, 19, 18, 80, 81, 83, 82, 64, 65, 67, 66, + 4, 5, 7, 6, 20, 21, 23, 22, 84, 85, 87, 86, 68, 69, 71, 70, + 12, 13, 15, 14, 28, 29, 31, 30, 92, 93, 95, 94, 76, 77, 79, 78, + 8, 9, 11, 10, 24, 25, 27, 26, 88, 89, 91, 90, 72, 73, 75, 74, + + 32, 33, 35, 34, 48, 49, 51, 50, 112,113,115,114, 96, 97, 99, 98, + 36, 37, 39, 38, 52, 53, 55, 54, 116,117,119,118, 100,101,103,102, + 44, 45, 47, 46, 60, 61, 63, 62, 124,125,127,126, 108,109,111,110, + 40, 41, 43, 42, 56, 57, 59, 58, 120,121,123,122, 104,105,107,106, + + + 160,161,163,162, 176,177,179,178, 240,241,243,242, 224,225,227,226, + 164,165,167,166, 180,181,183,182, 244,245,247,246, 228,229,231,230, + 172,173,175,174, 188,189,191,190, 252,253,255,254, 236,237,239,238, + 168,169,171,170, 184,185,187,186, 248,249,251,250, 232,233,235,234, + + 128,129,131,130, 144,145,147,146, 208,209,211,210, 192,193,195,194, + 132,133,135,134, 148,149,151,150, 212,213,215,214, 196,197,199,198, + 140,141,143,142, 156,157,159,158, 220,221,223,222, 204,205,207,206, + 136,137,139,138, 152,153,155,154, 216,217,219,218, 200,201,203,202 +}; + +#define POWER2(n) (1 << n) +void map(T) +pcover T; +{ + int j, k, l, other_input_offset, output_offset, outnum, ind; + int largest_input_ind, numout; + char c; + pset m; + bool some_output; + + m = minterms(T); + largest_input_ind = POWER2(cube.num_binary_vars); + numout = cube.part_size[cube.num_vars-1]; + + for(outnum = 0; outnum < numout; outnum++) { + output_offset = outnum * largest_input_ind; + (void) printf("\n\nOutput space # %d\n", outnum); + for(l = 0; l <= MAX(cube.num_binary_vars - 8, 0); l++) { + other_input_offset = l * 256; + for(k = 0; k < 16; k++) { + some_output = FALSE; + for(j = 0; j < 16; j++) { + ind = mapindex[k][j] + other_input_offset; + if (ind < largest_input_ind) { + c = is_in_set(m, ind+output_offset) ? '1' : '.'; + putchar(c); + some_output = TRUE; + } + if ((j+1)%4 == 0) + putchar(' '); + if ((j+1)%8 == 0) + (void) printf(" "); + } + if (some_output) + putchar('\n'); + if ((k+1)%4 == 0) { + if (k != 15 && mapindex[k+1][0] >= largest_input_ind) + break; + putchar('\n'); + } + if ((k+1)%8 == 0) + putchar('\n'); + } + } + } + set_free(m); +} diff --git a/sis/espresso/opo.c b/sis/espresso/opo.c new file mode 100644 index 0000000..b730541 --- /dev/null +++ b/sis/espresso/opo.c @@ -0,0 +1,625 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/opo.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + +/* + * Phase assignment technique (T. Sasao): + * + * 1. create a function with 2*m outputs which implements the + * original function and its complement for each output + * + * 2. minimize this function + * + * 3. choose the minimum number of prime implicants from the + * result of step 2 which are needed to realize either a function + * or its complement for each output + * + * Step 3 is performed in a rather crude way -- by simply multiplying + * out a large expression of the form: + * + * I = (ab + cdef)(acd + bgh) ... + * + * which is a product of m expressions where each expression has two + * product terms -- one representing which primes are needed for the + * function, and one representing which primes are needed for the + * complement. The largest product term resulting shows which primes + * to keep to implement one function or the other for each output. + * For problems with many outputs, this may grind to a + * halt. + * + * Untried: form complement of I and use unate_complement ... + * + * I have unsuccessfully tried several modifications to the basic + * algorithm. The first is quite simple: use Sasao's technique, but + * only commit to a single output at a time (rather than all + * outputs). The goal would be that the later minimizations can "take + * into account" the partial assignment at each step. This is + * expensive (m+1 minimizations rather than 2), and the results are + * discouraging. + * + * The second modification is rather complicated. The result from the + * minimization in step 2 is guaranteed to be minimal. Hence, for + * each output, the set of primes with a 1 in that output are both + * necessary and sufficient to implement the function. Espresso + * achieves the minimality using the routine MAKE_SPARSE. The + * modification is to prevent MAKE_SPARSE from running. Hence, there + * are potentially many subsets of the set of primes with a 1 in a + * column which can be used to implement that output. We use + * IRREDUNDANT to enumerate all possible subsets and then proceed as + * before. + */ + +static int opo_no_make_sparse; +static int opo_repeated; +static int opo_exact; +static void esp_minimize(); + +void phase_assignment(PLA, opo_strategy) +pPLA PLA; +int opo_strategy; +{ + opo_no_make_sparse = opo_strategy % 2; + skip_make_sparse = opo_no_make_sparse; + opo_repeated = (opo_strategy / 2) % 2; + opo_exact = (opo_strategy / 4) % 2; + + /* Determine a phase assignment */ + if (PLA->phase != NULL) { + FREE(PLA->phase); + } + + if (opo_repeated) { + PLA->phase = set_save(cube.fullset); + repeated_phase_assignment(PLA); + } else { + PLA->phase = find_phase(PLA, 0, (pcube) NULL); + } + + /* Now minimize with this assignment */ + skip_make_sparse = FALSE; + (void) set_phase(PLA); + esp_minimize(PLA); +} + +/* + * repeated_phase_assignment -- an alternate strategy which commits + * to a single phase assignment a step at a time. Performs m + 1 + * minimizations ! + */ +void repeated_phase_assignment(PLA) +pPLA PLA; +{ + int i; + pcube phase; + + for(i = 0; i < cube.part_size[cube.output]; i++) { + + /* Find best assignment for all undecided outputs */ + phase = find_phase(PLA, i, PLA->phase); + + /* Commit for only a single output ... */ + if (! is_in_set(phase, cube.first_part[cube.output] + i)) { + set_remove(PLA->phase, cube.first_part[cube.output] + i); + } + + if (trace || summary) { + (void) printf("\nOPO loop for output #%d\n", i); + (void) printf("PLA->phase is %s\n", pc1(PLA->phase)); + (void) printf("phase is %s\n", pc1(phase)); + } + set_free(phase); + } +} + + +/* + * find_phase -- find a phase assignment for the PLA for all outputs starting + * with output number first_output. + */ +pcube find_phase(PLA, first_output, phase1) +pPLA PLA; +int first_output; +pcube phase1; +{ + pcube phase; + pPLA PLA1; + + phase = set_save(cube.fullset); + + /* setup the double-phase characteristic function, resize the cube */ + PLA1 = new_PLA(); + PLA1->F = sf_save(PLA->F); + PLA1->R = sf_save(PLA->R); + PLA1->D = sf_save(PLA->D); + if (phase1 != NULL) { + PLA1->phase = set_save(phase1); + (void) set_phase(PLA1); + } + EXEC_S(output_phase_setup(PLA1, first_output), "OPO-SETUP ", PLA1->F); + + /* minimize the double-phase function */ + esp_minimize(PLA1); + + /* set the proper phases according to what gives a minimum solution */ + EXEC_S(PLA1->F = opo(phase, PLA1->F, PLA1->D, PLA1->R, first_output), + "OPO ", PLA1->F); + free_PLA(PLA1); + + /* set the cube structure to reflect the old size */ + setdown_cube(); + cube.part_size[cube.output] -= + (cube.part_size[cube.output] - first_output) / 2; + cube_setup(); + + return phase; +} + +/* + * opo -- multiply the expression out to determine a minimum subset of + * primes. + */ + +/*ARGSUSED*/ +pcover opo(phase, T, D, R, first_output) +pcube phase; +pcover T, D, R; +int first_output; +{ + int offset, output, i, last_output, ind; + pset pdest, select, p, p1, last, last1, not_covered, tmp; + pset_family temp, T1, T2; + + /* must select all primes for outputs [0 .. first_output-1] */ + select = set_full(T->count); + for(output = 0; output < first_output; output++) { + ind = cube.first_part[cube.output] + output; + foreachi_set(T, i, p) { + if (is_in_set(p, ind)) { + set_remove(select, i); + } + } + } + + /* Recursively perform the intersections */ + offset = (cube.part_size[cube.output] - first_output) / 2; + last_output = first_output + offset - 1; + temp = opo_recur(T, D, select, offset, first_output, last_output); + + /* largest set is on top -- select primes which are inferred from it */ + pdest = temp->data; + T1 = new_cover(T->count); + foreachi_set(T, i, p) { + if (! is_in_set(pdest, i)) { + T1 = sf_addset(T1, p); + } + } + + set_free(select); + sf_free(temp); + + /* finding phases is difficult -- see which functions are not covered */ + T2 = complement(cube1list(T1)); + not_covered = new_cube(); + tmp = new_cube(); + foreach_set(T, last, p) { + foreach_set(T2, last1, p1) { + if (cdist0(p, p1)) { + (void) set_or(not_covered, not_covered, set_and(tmp, p, p1)); + } + } + } + free_cover(T); + free_cover(T2); + set_free(tmp); + + /* Now reflect the phase choice in a single cube */ + for(output = first_output; output <= last_output; output++) { + ind = cube.first_part[cube.output] + output; + if (is_in_set(not_covered, ind)) { + if (is_in_set(not_covered, ind + offset)) { + fatal("error in output phase assignment"); + } else { + set_remove(phase, ind); + } + } + } + set_free(not_covered); + return T1; +} + +pset_family opo_recur(T, D, select, offset, first, last) +pcover T, D; +pcube select; +int offset, first, last; +{ + static int level = 0; + int middle; + pset_family sl, sr, temp; + + level++; + if (first == last) { +#if 0 + if (opo_no_make_sparse) { + temp = form_cover_table(T, D, select, first, first + offset); + } else { + temp = opo_leaf(T, select, first, first + offset); + } +#else + temp = opo_leaf(T, select, first, first + offset); +#endif + } else { + middle = (first + last) / 2; + sl = opo_recur(T, D, select, offset, first, middle); + sr = opo_recur(T, D, select, offset, middle+1, last); + temp = unate_intersect(sl, sr, level == 1); + if (trace) { + (void) printf("# OPO[%d]: %4d = %4d x %4d, time = %s\n", level - 1, + temp->count, sl->count, sr->count, print_time(ptime())); + (void) fflush(stdout); + } + free_cover(sl); + free_cover(sr); + } + level--; + return temp; +} + + +pset_family opo_leaf(T, select, out1, out2) +register pcover T; +pset select; +int out1, out2; +{ + register pset_family temp; + register pset p, pdest; + register int i; + + out1 += cube.first_part[cube.output]; + out2 += cube.first_part[cube.output]; + + /* Allocate space for the result */ + temp = sf_new(2, T->count); + + /* Find which primes are needed for the ON-set of this fct */ + pdest = GETSET(temp, temp->count++); + (void) set_copy(pdest, select); + foreachi_set(T, i, p) { + if (is_in_set(p, out1)) { + set_remove(pdest, i); + } + } + + /* Find which primes are needed for the OFF-set of this fct */ + pdest = GETSET(temp, temp->count++); + (void) set_copy(pdest, select); + foreachi_set(T, i, p) { + if (is_in_set(p, out2)) { + set_remove(pdest, i); + } + } + + return temp; +} + +#if 0 +pset_family form_cover_table(F, D, select, f, fbar) +pcover F, D; +pset select; +int f, fbar; /* indices of f and fbar in the output part */ +{ + register int i; + register pcube p; + pset_family f_table, fbar_table; + + /* setup required for fcube_is_covered */ + Rp_size = F->count; + Rp_start = set_new(Rp_size); + foreachi_set(F, i, p) { + PUTSIZE(p, i); + } + foreachi_set(D, i, p) { + RESET(p, REDUND); + } + + f_table = find_covers(F, D, select, f); + fbar_table = find_covers(F, D, select, fbar); + f_table = sf_append(f_table, fbar_table); + + set_free(Rp_start); + return f_table; +} + + +pset_family find_covers(F, D, select, n) +pcover F, D; +register pset select; +int n; +{ + register pset p, last, new; + pcover F1; + pcube *Flist; + pset_family f_table, table; + int i; + + n += cube.first_part[cube.output]; + + /* save cubes in this output, and remove the output variable */ + F1 = new_cover(F->count); + foreach_set(F, last, p) + if (is_in_set(p, n)) { + new = GETSET(F1, F1->count++); + (void) set_or(new, p, cube.var_mask[cube.output]); + PUTSIZE(new, SIZE(p)); + SET(new, REDUND); + } + + /* Find ways (sop form) to fail to cover output indexed by n */ + Flist = cube2list(F1, D); + table = sf_new(10, Rp_size); + foreach_set(F1, last, p) { + (void) set_fill(Rp_start, Rp_size); + set_remove(Rp_start, SIZE(p)); + table = sf_append(table, fcube_is_covered(Flist, p)); + RESET(p, REDUND); + } + (void) set_fill(Rp_start, Rp_size); + foreach_set(table, last, p) { + (void) set_diff(p, Rp_start, p); + } + + /* complement this to get possible ways to cover the function */ + for(i = 0; i < Rp_size; i++) { + if (! is_in_set(select, i)) { + p = set_new(Rp_size); + set_insert(p, i); + table = sf_addset(table, p); + set_free(p); + } + } + f_table = unate_compl(table); + + /* what a pain, but we need bitwise complement of this */ + (void) set_fill(Rp_start, Rp_size); + foreach_set(f_table, last, p) { + (void) set_diff(p, Rp_start, p); + } + + free_cubelist(Flist); + sf_free(F1); + return f_table; +} +#endif + +/* + * Take a PLA (ON-set, OFF-set and DC-set) and create the + * "double-phase characteristic function" which is merely a new + * function which has twice as many outputs and realizes both the + * function and the complement. + * + * The cube structure is assumed to represent the PLA upon entering. + * It will be modified to represent the double-phase function upon + * exit. + * + * Only the outputs numbered starting with "first_output" are + * duplicated in the output part + */ + +output_phase_setup(PLA, first_output) +INOUT pPLA PLA; +int first_output; +{ + pcover F, R, D; + pcube mask, mask1, last; + int first_part, offset; + bool save; + register pcube p, pr, pf; + register int i, last_part; + + if (cube.output == -1) + fatal("output_phase_setup: must have an output"); + + F = PLA->F; + D = PLA->D; + R = PLA->R; + first_part = cube.first_part[cube.output] + first_output; + last_part = cube.last_part[cube.output]; + offset = cube.part_size[cube.output] - first_output; + + /* Change the output size, setup the cube structure */ + setdown_cube(); + cube.part_size[cube.output] += offset; + cube_setup(); + + /* Create a mask to select that part of the cube which isn't changing */ + mask = set_save(cube.fullset); + for(i = first_part; i < cube.size; i++) + set_remove(mask, i); + mask1 = set_save(mask); + for(i = cube.first_part[cube.output]; i < first_part; i++) { + set_remove(mask1, i); + } + + PLA->F = new_cover(F->count + R->count); + PLA->R = new_cover(F->count + R->count); + PLA->D = new_cover(D->count); + + foreach_set(F, last, p) { + pf = GETSET(PLA->F, (PLA->F)->count++); + pr = GETSET(PLA->R, (PLA->R)->count++); + INLINEset_and(pf, mask, p); + INLINEset_and(pr, mask1, p); + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + set_insert(pf, i); + save = FALSE; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + save = TRUE, set_insert(pr, i+offset); + if (! save) PLA->R->count--; + } + + foreach_set(R, last, p) { + pf = GETSET(PLA->F, (PLA->F)->count++); + pr = GETSET(PLA->R, (PLA->R)->count++); + INLINEset_and(pf, mask1, p); + INLINEset_and(pr, mask, p); + save = FALSE; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + save = TRUE, set_insert(pf, i+offset); + if (! save) PLA->F->count--; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + set_insert(pr, i); + } + + foreach_set(D, last, p) { + pf = GETSET(PLA->D, (PLA->D)->count++); + INLINEset_and(pf, mask, p); + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) { + set_insert(pf, i); + set_insert(pf, i+offset); + } + } + + free_cover(F); + free_cover(D); + free_cover(R); + set_free(mask); + set_free(mask1); +} + +/* + * set_phase -- given a "cube" which describes which phases of the output + * are to be implemented, compute the appropriate on-set and off-set + */ +pPLA set_phase(PLA) +INOUT pPLA PLA; +{ + pcover F1, R1; + register pcube last, p, outmask; + register pcube temp=cube.temp[0], phase=PLA->phase, phase1=cube.temp[1]; + + outmask = cube.var_mask[cube.num_vars - 1]; + (void) set_diff(phase1, outmask, phase); + (void) set_or(phase1, set_diff(temp, cube.fullset, outmask), phase1); + F1 = new_cover((PLA->F)->count + (PLA->R)->count); + R1 = new_cover((PLA->F)->count + (PLA->R)->count); + + foreach_set(PLA->F, last, p) { + if (! setp_disjoint(set_and(temp, p, phase), outmask)) + (void) set_copy(GETSET(F1, F1->count++), temp); + if (! setp_disjoint(set_and(temp, p, phase1), outmask)) + (void) set_copy(GETSET(R1, R1->count++), temp); + } + foreach_set(PLA->R, last, p) { + if (! setp_disjoint(set_and(temp, p, phase), outmask)) + (void) set_copy(GETSET(R1, R1->count++), temp); + if (! setp_disjoint(set_and(temp, p, phase1), outmask)) + (void) set_copy(GETSET(F1, F1->count++), temp); + } + free_cover(PLA->F); + free_cover(PLA->R); + PLA->F = F1; + PLA->R = R1; + return PLA; +} + +#define POW2(x) (1 << (x)) + +void opoall(PLA, first_output, last_output, opo_strategy) +pPLA PLA; +int first_output, last_output; +int opo_strategy; +{ + pcover F, D, R, best_F, best_D, best_R; + int i, j, ind, num; + pcube bestphase; + + opo_exact = opo_strategy; + + if (PLA->phase != NULL) { + set_free(PLA->phase); + } + + bestphase = set_save(cube.fullset); + best_F = sf_save(PLA->F); + best_D = sf_save(PLA->D); + best_R = sf_save(PLA->R); + + for(i = 0; i < POW2(last_output - first_output + 1); i++) { + + /* save the initial PLA covers */ + F = sf_save(PLA->F); + D = sf_save(PLA->D); + R = sf_save(PLA->R); + + /* compute the phase cube for this iteration */ + PLA->phase = set_save(cube.fullset); + num = i; + for(j = last_output; j >= first_output; j--) { + if (num % 2 == 0) { + ind = cube.first_part[cube.output] + j; + set_remove(PLA->phase, ind); + } + num /= 2; + } + + /* set the phase and minimize */ + (void) set_phase(PLA); + (void) printf("# phase is %s\n", pc1(PLA->phase)); + summary = TRUE; + esp_minimize(PLA); + + /* see if this is the best so far */ + if (PLA->F->count < best_F->count) { + /* save new best solution */ + (void) set_copy(bestphase, PLA->phase); + sf_free(best_F); + sf_free(best_D); + sf_free(best_R); + best_F = PLA->F; + best_D = PLA->D; + best_R = PLA->R; + } else { + /* throw away the solution */ + free_cover(PLA->F); + free_cover(PLA->D); + free_cover(PLA->R); + } + set_free(PLA->phase); + + /* restore the initial PLA covers */ + PLA->F = F; + PLA->D = D; + PLA->R = R; + } + + /* one more minimization to restore the best answer */ + PLA->phase = bestphase; + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = best_F; + PLA->D = best_D; + PLA->R = best_R; +} + +static void +esp_minimize(PLA) +pPLA PLA; +{ + if (opo_exact) { + EXEC_S(PLA->F = minimize_exact(PLA->F,PLA->D,PLA->R,1), "EXACT", PLA->F); + } else { + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), "ESPRESSO ",PLA->F); + } +} diff --git a/sis/espresso/pair.c b/sis/espresso/pair.c new file mode 100644 index 0000000..cefd8a6 --- /dev/null +++ b/sis/espresso/pair.c @@ -0,0 +1,675 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/pair.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + +void set_pair(PLA) +pPLA PLA; +{ + set_pair1(PLA, TRUE); +} + +void set_pair1(PLA, adjust_labels) +pPLA PLA; +bool adjust_labels; +{ + int i, var, *paired, newvar; + int old_num_vars, old_num_binary_vars, old_size, old_mv_start; + int *new_part_size, new_num_vars, new_num_binary_vars, new_mv_start; + ppair pair = PLA->pair; + char scratch[1000], **oldlabel, *var1, *var1bar, *var2, *var2bar; + + if (adjust_labels) + makeup_labels(PLA); + + /* Check the pair structure for valid entries and see which binary + variables are left unpaired + */ + paired = ALLOC(bool, cube.num_binary_vars); + for(var = 0; var < cube.num_binary_vars; var++) + paired[var] = FALSE; + for(i = 0; i < pair->cnt; i++) + if ((pair->var1[i] > 0 && pair->var1[i] <= cube.num_binary_vars) && + (pair->var2[i] > 0 && pair->var2[i] <= cube.num_binary_vars)) { + paired[pair->var1[i]-1] = TRUE; + paired[pair->var2[i]-1] = TRUE; + } else + fatal("can only pair binary-valued variables"); + + PLA->F = delvar(pairvar(PLA->F, pair), paired); + PLA->R = delvar(pairvar(PLA->R, pair), paired); + PLA->D = delvar(pairvar(PLA->D, pair), paired); + + /* Now painfully adjust the cube size */ + old_size = cube.size; + old_num_vars = cube.num_vars; + old_num_binary_vars = cube.num_binary_vars; + old_mv_start = cube.first_part[cube.num_binary_vars]; + /* Create the new cube.part_size vector and setup the cube structure */ + new_num_binary_vars = 0; + for(var = 0; var < old_num_binary_vars; var++) + new_num_binary_vars += (paired[var] == FALSE); + new_num_vars = new_num_binary_vars + pair->cnt; + new_num_vars += old_num_vars - old_num_binary_vars; + new_part_size = ALLOC(int, new_num_vars); + for(var = 0; var < pair->cnt; var++) + new_part_size[new_num_binary_vars + var] = 4; + for(var = 0; var < old_num_vars - old_num_binary_vars; var++) + new_part_size[new_num_binary_vars + pair->cnt + var] = + cube.part_size[old_num_binary_vars + var]; + setdown_cube(); + FREE(cube.part_size); + cube.num_vars = new_num_vars; + cube.num_binary_vars = new_num_binary_vars; + cube.part_size = new_part_size; + cube_setup(); + + /* hack with the labels to get them correct */ + if (adjust_labels) { + oldlabel = PLA->label; + PLA->label = ALLOC(char *, cube.size); + for(var = 0; var < pair->cnt; var++) { + newvar = cube.num_binary_vars*2 + var*4; + var1 = oldlabel[ (pair->var1[var]-1) * 2 + 1]; + var2 = oldlabel[ (pair->var2[var]-1) * 2 + 1]; + var1bar = oldlabel[ (pair->var1[var]-1) * 2]; + var2bar = oldlabel[ (pair->var2[var]-1) * 2]; + (void) sprintf(scratch, "%s+%s", var1bar, var2bar); + PLA->label[newvar] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1bar, var2); + PLA->label[newvar+1] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1, var2bar); + PLA->label[newvar+2] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1, var2); + PLA->label[newvar+3] = util_strsav(scratch); + } + /* Copy the old labels for the unpaired binary vars */ + i = 0; + for(var = 0; var < old_num_binary_vars; var++) { + if (paired[var] == FALSE) { + PLA->label[2*i] = oldlabel[2*var]; + PLA->label[2*i+1] = oldlabel[2*var+1]; + oldlabel[2*var] = oldlabel[2*var+1] = (char *) NULL; + i++; + } + } + /* Copy the old labels for the remaining unpaired vars */ + new_mv_start = cube.num_binary_vars*2 + pair->cnt*4; + for(i = old_mv_start; i < old_size; i++) { + PLA->label[new_mv_start + i - old_mv_start] = oldlabel[i]; + oldlabel[i] = (char *) NULL; + } + /* free remaining entries in oldlabel */ + for(i = 0; i < old_size; i++) + if (oldlabel[i] != (char *) NULL) + FREE(oldlabel[i]); + FREE(oldlabel); + } + + /* the paired variables should not be sparse (cf. mv_reduce/raise_in)*/ + for(var = 0; var < pair->cnt; var++) + cube.sparse[cube.num_binary_vars + var] = 0; + FREE(paired); +} + +pcover pairvar(A, pair) +pcover A; +ppair pair; +{ + register pcube last, p; + register int val, p1, p2, b1, b0; + int insert_col, pairnum; + + insert_col = cube.first_part[cube.num_vars - 1]; + + /* stretch the cover matrix to make room for the paired variables */ + A = sf_delcol(A, insert_col, -4*pair->cnt); + + /* compute the paired values */ + foreach_set(A, last, p) { + for(pairnum = 0; pairnum < pair->cnt; pairnum++) { + p1 = cube.first_part[pair->var1[pairnum] - 1]; + p2 = cube.first_part[pair->var2[pairnum] - 1]; + b1 = is_in_set(p, p2+1); + b0 = is_in_set(p, p2); + val = insert_col + pairnum * 4; + if (/* a0 */ is_in_set(p, p1)) { + if (b0) + set_insert(p, val + 3); + if (b1) + set_insert(p, val + 2); + } + if (/* a1 */ is_in_set(p, p1+1)) { + if (b0) + set_insert(p, val + 1); + if (b1) + set_insert(p, val); + } + } + } + return A; +} + + +/* delvar -- delete variables from A, minimize the number of column shifts */ +pcover delvar(A, paired) +pcover A; +bool paired[]; +{ + bool run; + int first_run, run_length, var, offset = 0; + + run = FALSE; run_length = 0; + for(var = 0; var < cube.num_binary_vars; var++) + if (paired[var]) + if (run) + run_length += cube.part_size[var]; + else { + run = TRUE; + first_run = cube.first_part[var]; + run_length = cube.part_size[var]; + } + else + if (run) { + A = sf_delcol(A, first_run-offset, run_length); + run = FALSE; + offset += run_length; + } + if (run) + A = sf_delcol(A, first_run-offset, run_length); + return A; +} + +/* + find_optimal_pairing -- find which binary variables should be paired + to maximally reduce the number of terms + + This is essentially the technique outlined by T. Sasao in the + Trans. on Comp., Oct 1984. We estimate the cost of pairing each + pair individually using 1 of 4 strategies: (1) algebraic division + of F by the pair (exactly T. Sasao technique); (2) strong division + of F by the paired variables (using REDUCE/EXPAND/ IRREDUNDANT from + espresso); (3) full minimization using espresso; (4) exact + minimization. These are in order of both increasing accuracy and + increasing difficulty (!) + + Once the n squared pairs have been evaluated, T. Sasao proposes a + graph covering of nodes by disjoint edges. For now, I solve this + problem exhaustively (complexity = (n-1)*(n-3)*...*3*1 for n + variables when n is even). Note that solving this problem exactly + is the same as evaluating the cost function for all possible + pairings. + + n pairs + + 1, 2 1 + 3, 4 3 + 5, 6 15 + 7, 8 105 + 9,10 945 + 11,12 10,395 + 13,14 135,135 + 15,16 2,027,025 + 17,18 34,459,425 + 19,20 654,729,075 +*/ +void find_optimal_pairing(PLA, strategy) +pPLA PLA; +int strategy; +{ + int i, j, **cost_array; + + cost_array = find_pairing_cost(PLA, strategy); + + if (summary) { + (void) printf(" "); + for(i = 0; i < cube.num_binary_vars; i++) + (void) printf("%3d ", i+1); + (void) printf("\n"); + for(i = 0; i < cube.num_binary_vars; i++) { + (void) printf("%3d ", i+1); + for(j = 0; j < cube.num_binary_vars; j++) + (void) printf("%3d ", cost_array[i][j]); + (void) printf("\n"); + } + } + + if (cube.num_binary_vars <= 14) { + PLA->pair = pair_best_cost(cost_array); + } else { + (void) greedy_best_cost(cost_array, &(PLA->pair)); + } + (void) printf("# "); + print_pair(PLA->pair); + + for(i = 0; i < cube.num_binary_vars; i++) + FREE(cost_array[i]); + FREE(cost_array); + + set_pair(PLA); + EXEC_S(PLA->F=espresso(PLA->F,PLA->D,PLA->R),"ESPRESSO ",PLA->F); +} + +int **find_pairing_cost(PLA, strategy) +pPLA PLA; +int strategy; +{ + int var1, var2, **cost_array; + int i, j, xnum_binary_vars, xnum_vars, *xpart_size, cost; + pcover T, Fsave, Dsave, Rsave; + pset mask; +/* char *s;*/ + + /* data is returned in the cost array */ + cost_array = ALLOC(int *, cube.num_binary_vars); + for(i = 0; i < cube.num_binary_vars; i++) + cost_array[i] = ALLOC(int, cube.num_binary_vars); + for(i = 0; i < cube.num_binary_vars; i++) + for(j = 0; j < cube.num_binary_vars; j++) + cost_array[i][j] = 0; + + /* Setup the pair structure for pairing variables together */ + PLA->pair = pair_new(1); + PLA->pair->cnt = 1; + + for(var1 = 0; var1 < cube.num_binary_vars-1; var1++) { + for(var2 = var1+1; var2 < cube.num_binary_vars; var2++) { + /* if anything but simple strategy, perform setup */ + if (strategy > 0) { + /* save the original covers */ + Fsave = sf_save(PLA->F); + Dsave = sf_save(PLA->D); + Rsave = sf_save(PLA->R); + + /* save the original cube structure */ + xnum_binary_vars = cube.num_binary_vars; + xnum_vars = cube.num_vars; + xpart_size = ALLOC(int, cube.num_vars); + for(i = 0; i < cube.num_vars; i++) + xpart_size[i] = cube.part_size[i]; + + /* pair two variables together */ + PLA->pair->var1[0] = var1 + 1; + PLA->pair->var2[0] = var2 + 1; + set_pair1(PLA, /* adjust_labels */ FALSE); + } + + + /* decide how to best estimate worth of this pairing */ + switch(strategy) { + case 3: + /*s = "exact minimization";*/ + PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1); + cost = Fsave->count - PLA->F->count; + break; + case 2: + /*s = "full minimization";*/ + PLA->F = espresso(PLA->F, PLA->D, PLA->R); + cost = Fsave->count - PLA->F->count; + break; + case 1: + /*s = "strong division";*/ + PLA->F = reduce(PLA->F, PLA->D); + PLA->F = expand(PLA->F, PLA->R, FALSE); + PLA->F = irredundant(PLA->F, PLA->D); + cost = Fsave->count - PLA->F->count; + break; + case 0: + /*s = "weak division";*/ + mask = new_cube(); + (void) set_or(mask, cube.var_mask[var1], cube.var_mask[var2]); + T = dist_merge(sf_save(PLA->F), mask); + cost = PLA->F->count - T->count; + sf_free(T); + set_free(mask); + } + + cost_array[var1][var2] = cost; + + if (strategy > 0) { + /* restore the original cube structure -- free the new ones */ + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = xnum_binary_vars; + cube.num_vars = xnum_vars; + cube.part_size = xpart_size; + cube_setup(); + + /* restore the original cover(s) -- free the new ones */ + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = Fsave; + PLA->D = Dsave; + PLA->R = Rsave; + } + } + } + + pair_free(PLA->pair); + PLA->pair = NULL; + return cost_array; +} + +static int best_cost; +static int **cost_array; +static ppair best_pair; +static pset best_phase; +static pPLA global_PLA; +static pcover best_F, best_D, best_R; +static int pair_minim_strategy; + + +print_pair(pair) +ppair pair; +{ + int i; + + (void) printf("pair is"); + for(i = 0; i < pair->cnt; i++) + (void) printf (" (%d %d)", pair->var1[i], pair->var2[i]); + (void) printf("\n"); +} + + +int greedy_best_cost(cost_array_local, pair_p) +int **cost_array_local; +ppair *pair_p; +{ + int i, j, besti, bestj, maxcost, total_cost; + pset cand; + ppair pair; + + pair = pair_new(cube.num_binary_vars); + cand = set_full(cube.num_binary_vars); + total_cost = 0; + + while (set_ord(cand) >= 2) { + maxcost = -1; + for(i = 0; i < cube.num_binary_vars; i++) { + if (is_in_set(cand, i)) { + for(j = i+1; j < cube.num_binary_vars; j++) { + if (is_in_set(cand, j)) { + if (cost_array_local[i][j] > maxcost) { + maxcost = cost_array_local[i][j]; + besti = i; + bestj = j; + } + } + } + } + } + pair->var1[pair->cnt] = besti+1; + pair->var2[pair->cnt] = bestj+1; + pair->cnt++; + set_remove(cand, besti); + set_remove(cand, bestj); + total_cost += maxcost; + } + set_free(cand); + *pair_p = pair; + return total_cost; +} + + +ppair pair_best_cost(cost_array_local) +int **cost_array_local; +{ + ppair pair; + pset candidate; + + best_cost = -1; + best_pair = NULL; + cost_array = cost_array_local; + + pair = pair_new(cube.num_binary_vars); + candidate = set_full(cube.num_binary_vars); + generate_all_pairs(pair, cube.num_binary_vars, candidate, find_best_cost); + pair_free(pair); + set_free(candidate); + return best_pair; +} + + +int find_best_cost(pair) +register ppair pair; +{ + register int i, cost; + + cost = 0; + for(i = 0; i < pair->cnt; i++) + cost += cost_array[pair->var1[i]-1][pair->var2[i]-1]; + if (cost > best_cost) { + best_cost = cost; + best_pair = pair_save(pair, pair->cnt); + } + if ((debug & MINCOV) && trace) { + (void) printf("cost is %d ", cost); + print_pair(pair); + } +} + +/* + pair_all: brute-force approach to try all possible pairings + + pair_strategy is: + 2) for espresso + 3) for minimize_exact + 4) for phase assignment +*/ + +pair_all(PLA, pair_strategy) +pPLA PLA; +int pair_strategy; +{ + ppair pair; + pset candidate; + + global_PLA = PLA; + pair_minim_strategy = pair_strategy; + best_cost = PLA->F->count + 1; + best_pair = NULL; + best_phase = NULL; + best_F = best_D = best_R = NULL; + pair = pair_new(cube.num_binary_vars); + candidate = set_fill(set_new(cube.num_binary_vars), cube.num_binary_vars); + + generate_all_pairs(pair, cube.num_binary_vars, candidate, minimize_pair); + + pair_free(pair); + set_free(candidate); + + PLA->pair = best_pair; + PLA->phase = best_phase; +/* not really necessary + if (phase != NULL) + (void) set_phase(PLA->phase); +*/ + set_pair(PLA); + (void) printf("# "); + print_pair(PLA->pair); + + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = best_F; + PLA->D = best_D; + PLA->R = best_R; +} + + +/* + * minimize_pair -- called as each pair is generated + */ +int minimize_pair(pair) +ppair pair; +{ + pcover Fsave, Dsave, Rsave; + int i, xnum_binary_vars, xnum_vars, *xpart_size; + + /* save the original covers */ + Fsave = sf_save(global_PLA->F); + Dsave = sf_save(global_PLA->D); + Rsave = sf_save(global_PLA->R); + + /* save the original cube structure */ + xnum_binary_vars = cube.num_binary_vars; + xnum_vars = cube.num_vars; + xpart_size = ALLOC(int, cube.num_vars); + for(i = 0; i < cube.num_vars; i++) + xpart_size[i] = cube.part_size[i]; + + /* setup the paired variables */ + global_PLA->pair = pair; + set_pair1(global_PLA, /* adjust_labels */ FALSE); + + /* call the minimizer */ + if (summary) + print_pair(pair); + switch(pair_minim_strategy) { + case 2: + EXEC_S(phase_assignment(global_PLA,0), "OPO ", global_PLA->F); + if (summary) + (void) printf("# phase is %s\n", pc1(global_PLA->phase)); + break; + case 1: + EXEC_S(global_PLA->F = minimize_exact(global_PLA->F, global_PLA->D, + global_PLA->R, 1), "EXACT ", global_PLA->F); + break; + case 0: + EXEC_S(global_PLA->F = espresso(global_PLA->F, global_PLA->D, + global_PLA->R), "ESPRESSO ", global_PLA->F); + break; + default: + break; + } + + /* see if we have a new best solution */ + if (global_PLA->F->count < best_cost) { + best_cost = global_PLA->F->count; + best_pair = pair_save(pair, pair->cnt); + best_phase = global_PLA->phase!=NULL?set_save(global_PLA->phase):NULL; + if (best_F != NULL) sf_free(best_F); + if (best_D != NULL) sf_free(best_D); + if (best_R != NULL) sf_free(best_R); + best_F = sf_save(global_PLA->F); + best_D = sf_save(global_PLA->D); + best_R = sf_save(global_PLA->R); + } + + /* restore the original cube structure -- free the new ones */ + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = xnum_binary_vars; + cube.num_vars = xnum_vars; + cube.part_size = xpart_size; + cube_setup(); + + /* restore the original cover(s) -- free the new ones */ + sf_free(global_PLA->F); + sf_free(global_PLA->D); + sf_free(global_PLA->R); + global_PLA->F = Fsave; + global_PLA->D = Dsave; + global_PLA->R = Rsave; + global_PLA->pair = NULL; + global_PLA->phase = NULL; +} + +generate_all_pairs(pair, n, candidate, action) +ppair pair; +int n; +pset candidate; +int (*action)(); +{ + int i, j; + pset recur_candidate; + ppair recur_pair; + + if (set_ord(candidate) < 2) { + (*action)(pair); + return; + } + + recur_pair = pair_save(pair, n); + recur_candidate = set_save(candidate); + + /* Find first variable still in the candidate set */ + for(i = 0; i < n; i++) + if (is_in_set(candidate, i)) + break; + + /* Try all pairs of i with other variables */ + for(j = i+1; j < n; j++) + if (is_in_set(candidate, j)) { + /* pair (i j) -- remove from candidate set for future pairings */ + set_remove(recur_candidate, i); + set_remove(recur_candidate, j); + + /* add to the pair array */ + recur_pair->var1[recur_pair->cnt] = i+1; + recur_pair->var2[recur_pair->cnt] = j+1; + recur_pair->cnt++; + + /* recur looking for the end ... */ + generate_all_pairs(recur_pair, n, recur_candidate, action); + + /* now break this pair, and restore candidate set */ + recur_pair->cnt--; + set_insert(recur_candidate, i); + set_insert(recur_candidate, j); + } + + /* if odd, generate all pairs which do NOT include i */ + if ((set_ord(candidate) % 2) == 1) { + set_remove(recur_candidate, i); + generate_all_pairs(recur_pair, n, recur_candidate, action); + } + + pair_free(recur_pair); + set_free(recur_candidate); +} + +ppair pair_new(n) +register int n; +{ + register ppair pair1; + + pair1 = ALLOC(pair_t, 1); + pair1->cnt = 0; + pair1->var1 = ALLOC(int, n); + pair1->var2 = ALLOC(int, n); + return pair1; +} + + +ppair pair_save(pair, n) +register ppair pair; +register int n; +{ + register int k; + register ppair pair1; + + pair1 = pair_new(n); + pair1->cnt = pair->cnt; + for(k = 0; k < pair->cnt; k++) { + pair1->var1[k] = pair->var1[k]; + pair1->var2[k] = pair->var2[k]; + } + return pair1; +} + + +int pair_free(pair) +register ppair pair; +{ + FREE(pair->var1); + FREE(pair->var2); + FREE(pair); +} diff --git a/sis/espresso/primes.c b/sis/espresso/primes.c new file mode 100644 index 0000000..26452a2 --- /dev/null +++ b/sis/espresso/primes.c @@ -0,0 +1,170 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/primes.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + +static bool primes_consensus_special_cases(); +static pcover primes_consensus_merge(); +static pcover and_with_cofactor(); + + +/* primes_consensus -- generate primes using consensus */ +pcover primes_consensus(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tnew, Tl, Tr; + + if (primes_consensus_special_cases(T, &Tnew) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + Tl = primes_consensus(scofactor(T, cl, best)); + Tr = primes_consensus(scofactor(T, cr, best)); + Tnew = primes_consensus_merge(Tl, Tr, cl, cr); + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + return Tnew; +} + +static bool +primes_consensus_special_cases(T, Tnew) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tnew = new_cover(0); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tnew = sf_addset(new_cover(1), set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + free_cube(p); + + A = primes_consensus(T); + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + *Tnew = A; + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = cubeunlist(T); + *Tnew = sf_contain(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +static pcover +primes_consensus_merge(Tl, Tr, cl, cr) +pcover Tl, Tr; +pcube cl, cr; +{ + register pcube pl, pr, lastl, lastr, pt; + pcover T, Tsave; + + Tl = and_with_cofactor(Tl, cl); + Tr = and_with_cofactor(Tr, cr); + + T = sf_new(500, Tl->sf_size); + pt = T->data; + Tsave = sf_contain(sf_join(Tl, Tr)); + + foreach_set(Tl, lastl, pl) { + foreach_set(Tr, lastr, pr) { + if (cdist01(pl, pr) == 1) { + consensus(pt, pl, pr); + if (++T->count >= T->capacity) { + Tsave = sf_union(Tsave, sf_contain(T)); + T = sf_new(500, Tl->sf_size); + pt = T->data; + } else { + pt += T->wsize; + } + } + } + } + free_cover(Tl); + free_cover(Tr); + + Tsave = sf_union(Tsave, sf_contain(T)); + return Tsave; +} + + +static pcover +and_with_cofactor(A, cof) +pset_family A; +register pset cof; +{ + register pset last, p; + + foreach_set(A, last, p) { + INLINEset_and(p, p, cof); + if (cdist(p, cube.fullset) > 0) { + RESET(p, ACTIVE); + } else { + SET(p, ACTIVE); + } + } + return sf_inactive(A); +} diff --git a/sis/espresso/reduce.c b/sis/espresso/reduce.c new file mode 100644 index 0000000..92f263d --- /dev/null +++ b/sis/espresso/reduce.c @@ -0,0 +1,258 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/reduce.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + module: reduce.c + purpose: Perform the Espresso-II reduction step + + Reduction is a technique used to explore larger regions of the + optimization space. We replace each cube of F with a smaller + cube while still maintaining a cover of the same logic function. +*/ + +#include "espresso.h" + +static bool toggle = TRUE; + + +/* + reduce -- replace each cube in F with its reduction + + The reduction of a cube is the smallest cube contained in the cube + which can replace the cube in the original cover without changing + the cover. This is equivalent to the super cube of all of the + essential points in the cube. This can be computed directly. + + The problem is that the order in which the cubes are reduced can + greatly affect the final result. We alternate between two ordering + strategies: + + (1) Order the cubes in ascending order of distance from the + largest cube breaking ties by ordering cubes of equal distance + in descending order of size (sort_reduce) + + (2) Order the cubes in descending order of the inner-product of + the cube and the column sums (mini_sort) + + The real workhorse of this section is the routine SCCC which is + used to find the Smallest Cube Containing the Complement of a cover. + Reduction as proposed by Espresso-II takes a cube and computes its + maximal reduction as the intersection between the cube and the + smallest cube containing the complement of (F u D - {c}) cofactored + against c. + + As usual, the unate-recursive paradigm is used to compute SCCC. + The SCCC of a unate cover is trivial to compute, and thus we perform + Shannon Cofactor expansion attempting to drive the cover to be unate + as fast as possible. +*/ + +pcover reduce(F, D) +INOUT pcover F; +IN pcover D; +{ + register pcube last, p, cunder, *FD; + + /* Order the cubes */ + if (use_random_order) + F = random_order(F); + else { + F = toggle ? sort_reduce(F) : mini_sort(F, descend); + toggle = ! toggle; + } + + /* Try to reduce each cube */ + FD = cube2list(F, D); + foreach_set(F, last, p) { + cunder = reduce_cube(FD, p); /* reduce the cube */ + if (setp_equal(cunder, p)) { /* see if it actually did */ + SET(p, ACTIVE); /* cube remains active */ + SET(p, PRIME); /* cube remains prime ? */ + } else { + if (debug & REDUCE) { + (void) printf("REDUCE: %s to %s %s\n", + pc1(p), pc2(cunder), print_time(ptime())); + } + (void) set_copy(p, cunder); /* save reduced version */ + RESET(p, PRIME); /* cube is no longer prime */ + if (setp_empty(cunder)) + RESET(p, ACTIVE); /* if null, kill the cube */ + else + SET(p, ACTIVE); /* cube is active */ + } + free_cube(cunder); + } + free_cubelist(FD); + + /* Delete any cubes of F which reduced to the empty cube */ + return sf_inactive(F); +} + +/* reduce_cube -- find the maximal reduction of a cube */ +pcube reduce_cube(FD, p) +IN pcube *FD, p; +{ + pcube cunder; + + cunder = sccc(cofactor(FD, p)); + return set_and(cunder, cunder, p); +} + + +/* sccc -- find Smallest Cube Containing the Complement of a cover */ +pcube sccc(T) +INOUT pcube *T; /* T will be disposed of */ +{ + pcube r; + register pcube cl, cr; + register int best; + static int sccc_level = 0; + + if (debug & REDUCE1) { + debug_print(T, "SCCC", sccc_level++); + } + + if (sccc_special_cases(T, &r) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, REDUCE1); + r = sccc_merge(sccc(scofactor(T, cl, best)), + sccc(scofactor(T, cr, best)), cl, cr); + free_cubelist(T); + } + + if (debug & REDUCE1) + (void) printf("SCCC[%d]: result is %s\n", --sccc_level, pc1(r)); + return r; +} + + +pcube sccc_merge(left, right, cl, cr) +INOUT register pcube left, right; /* will be disposed of ... */ +INOUT register pcube cl, cr; /* will be disposed of ... */ +{ + INLINEset_and(left, left, cl); + INLINEset_and(right, right, cr); + INLINEset_or(left, left, right); + free_cube(right); + free_cube(cl); + free_cube(cr); + return left; +} + + +/* + sccc_cube -- find the smallest cube containing the complement of a cube + + By DeMorgan's law and the fact that the smallest cube containing a + cover is the "or" of the positional cubes, it is simple to see that + the SCCC is the universe if the cube has more than two active + variables. If there is only a single active variable, then the + SCCC is merely the bitwise complement of the cube in that + variable. A last special case is no active variables, in which + case the SCCC is empty. + + This is "anded" with the incoming cube result. +*/ +pcube sccc_cube(result, p) +register pcube result, p; +{ + register pcube temp=cube.temp[0], mask; + int var; + + if ((var = cactive(p)) >= 0) { + mask = cube.var_mask[var]; + INLINEset_xor(temp, p, mask); + INLINEset_and(result, result, temp); + } + return result; +} + +/* + * sccc_special_cases -- check the special cases for sccc + */ + +bool sccc_special_cases(T, result) +INOUT pcube *T; /* will be disposed if answer is determined */ +OUT pcube *result; /* returned only if answer determined */ +{ + register pcube *T1, p, temp = cube.temp[1], ceil, cof = T[0]; + pcube *A, *B; + + /* empty cover => complement is universe => SCCC is universe */ + if (T[2] == NULL) { + *result = set_save(cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* row of 1's => complement is empty => SCCC is empty */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *result = new_cube(); + free_cubelist(T); + return TRUE; + } + } + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If cover is unate (or single cube), apply simple rules to find SCCCU */ + if (cdata.vars_unate == cdata.vars_active || T[3] == NULL) { + *result = set_save(cube.fullset); + for(T1 = T+2; (p = *T1++) != NULL; ) { + (void) sccc_cube(*result, set_or(temp, p, cof)); + } + free_cubelist(T); + return TRUE; + } + + /* Check for column of 0's (which can be easily factored( */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + *result = sccc_cube(set_save(cube.fullset), ceil); + if (setp_equal(*result, cube.fullset)) { + free_cube(ceil); + } else { + *result = sccc_merge(sccc(cofactor(T,ceil)), + set_save(cube.fullset), ceil, *result); + } + free_cubelist(T); + return TRUE; + } + free_cube(ceil); + + /* Single active column at this point => tautology => SCCC is empty */ + if (cdata.vars_active == 1) { + *result = new_cube(); + free_cubelist(T); + return TRUE; + } + + /* Check for components */ + if (cdata.var_zeros[cdata.best] < CUBELISTSIZE(T)/2) { + if (cubelist_partition(T, &A, &B, debug & REDUCE1) == 0) { + return MAYBE; + } else { + free_cubelist(T); + *result = sccc(A); + ceil = sccc(B); + (void) set_and(*result, *result, ceil); + set_free(ceil); + return TRUE; + } + } + + /* Not much we can do about it */ + return MAYBE; +} diff --git a/sis/espresso/set.c b/sis/espresso/set.c new file mode 100644 index 0000000..7384170 --- /dev/null +++ b/sis/espresso/set.c @@ -0,0 +1,820 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/set.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + * set.c -- routines for maniuplating sets and set families + */ + +/* LINTLIBRARY */ + +#include "espresso.h" +static pset_family set_family_garbage = NULL; + +static int intcpy(d, s, n) +register unsigned int *d, *s; +register long n; +{ + register int i; + for(i = 0; i < n; i++) { + *d++ = *s++; + } +} + + +/* bit_index -- find first bit (from LSB) in a word (MSB=bit n, LSB=bit 0) */ +int bit_index(a) +register unsigned int a; +{ + register int i; + if (a == 0) + return -1; + for(i = 0; (a & 1) == 0; a >>= 1, i++) + ; + return i; +} + + +/* set_ord -- count number of elements in a set */ +int set_ord(a) +register pset a; +{ + register int i, sum = 0; + register unsigned int val; + for(i = LOOP(a); i > 0; i--) + if ((val = a[i]) != 0) + sum += count_ones(val); + return sum; +} + +/* set_dist -- distance between two sets (# elements in common) */ +int set_dist(a, b) +register pset a, b; +{ + register int i, sum = 0; + register unsigned int val; + for(i = LOOP(a); i > 0; i--) + if ((val = a[i] & b[i]) != 0) + sum += count_ones(val); + return sum; +} + +/* set_clear -- make "r" the empty set of "size" elements */ +pset set_clear(r, size) +register pset r; +int size; +{ + register int i = LOOPINIT(size); + *r = i; do r[i] = 0; while (--i > 0); + return r; +} + +/* set_fill -- make "r" the universal set of "size" elements */ +pset set_fill(r, size) +register pset r; +register int size; +{ + register int i = LOOPINIT(size); + *r = i; + r[i] = ~ (unsigned) 0; + r[i] >>= i * BPI - size; + while (--i > 0) + r[i] = ~ (unsigned) 0; + return r; +} + +/* set_copy -- copy set a into set r */ +pset set_copy(r, a) +register pset r, a; +{ + register int i = LOOPCOPY(a); + do r[i] = a[i]; while (--i >= 0); + return r; +} + +/* set_and -- compute intersection of sets "a" and "b" */ +pset set_and(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] & b[i]; while (--i > 0); + return r; +} + +/* set_or -- compute union of sets "a" and "b" */ +pset set_or(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] | b[i]; while (--i > 0); + return r; +} + +/* set_diff -- compute difference of sets "a" and "b" */ +pset set_diff(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] & ~b[i]; while (--i > 0); + return r; +} + +/* set_xor -- compute exclusive-or of sets "a" and "b" */ +pset set_xor(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); +#ifdef IBM_WATC + PUTLOOP(r,i); do r[i] = (a[i]&~b[i]) | (~a[i]&b[i]); while (--i > 0); +#else + PUTLOOP(r,i); do r[i] = a[i] ^ b[i]; while (--i > 0); +#endif + return r; +} + +/* set_merge -- compute "a" & "mask" | "b" & ~ "mask" */ +pset set_merge(r, a, b, mask) +register pset r, a, b, mask; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = (a[i]&mask[i]) | (b[i]&~mask[i]); while (--i > 0); + return r; +} + +/* set_andp -- compute intersection of sets "a" and "b" , TRUE if nonempty */ +bool set_andp(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + register unsigned int x = 0; + PUTLOOP(r,i); do {r[i] = a[i] & b[i]; x |= r[i];} while (--i > 0); + return x != 0; +} + +/* set_orp -- compute union of sets "a" and "b" , TRUE if nonempty */ +bool set_orp(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + register unsigned int x = 0; + PUTLOOP(r,i); do {r[i] = a[i] | b[i]; x |= r[i];} while (--i > 0); + return x != 0; +} + +/* setp_empty -- check if the set "a" is empty */ +bool setp_empty(a) +register pset a; +{ + register int i = LOOP(a); + do if (a[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_full -- check if the set "a" is the full set of "size" elements */ +bool setp_full(a, size) +register pset a; +register int size; +{ + register int i = LOOP(a); + register unsigned int test; + test = ~ (unsigned) 0; + test >>= i * BPI - size; + if (a[i] != test) + return FALSE; + while (--i > 0) + if (a[i] != (~(unsigned) 0)) + return FALSE; + return TRUE; +} + +/* setp_equal -- check if the set "a" equals set "b" */ +bool setp_equal(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] != b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_disjoint -- check if intersection of "a" and "b" is empty */ +bool setp_disjoint(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] & b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_implies -- check if "a" implies "b" ("b" contains "a") */ +bool setp_implies(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] & ~b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* sf_or -- form the "or" of all sets in a set family */ +pset sf_or(A) +pset_family A; +{ + register pset or, last, p; + + or = set_new(A->sf_size); + foreach_set(A, last, p) + INLINEset_or(or, or, p); + return or; +} + +/* sf_and -- form the "and" of all sets in a set family */ +pset sf_and(A) +pset_family A; +{ + register pset and, last, p; + + and = set_fill(set_new(A->sf_size), A->sf_size); + foreach_set(A, last, p) + INLINEset_and(and, and, p); + return and; +} + +/* sf_active -- make all members of the set family active */ +pset_family sf_active(A) +pset_family A; +{ + register pset p, last; + foreach_set(A, last, p) { + SET(p, ACTIVE); + } + A->active_count = A->count; + return A; +} + + +/* sf_inactive -- remove all inactive cubes in a set family */ +pset_family sf_inactive(A) +pset_family A; +{ + register pset p, last, pdest; + + pdest = A->data; + foreach_set(A, last, p) { + if (TESTP(p, ACTIVE)) { + if (pdest != p) { + INLINEset_copy(pdest, p); + } + pdest += A->wsize; + } else { + A->count--; + } + } + return A; +} + + +/* sf_copy -- copy a set family */ +pset_family sf_copy(R, A) +pset_family R, A; +{ + R->sf_size = A->sf_size; + R->wsize = A->wsize; +/*R->capacity = A->count;*/ +/*R->data = REALLOC(unsigned int, R->data, (long) R->capacity * R->wsize);*/ + R->count = A->count; + R->active_count = A->active_count; + intcpy(R->data, A->data, (long) A->wsize * A->count); + return R; +} + + +/* sf_join -- join A and B into a single set_family */ +pset_family sf_join(A, B) +pset_family A, B; +{ + pset_family R; + long asize = A->count * A->wsize; + long bsize = B->count * B->wsize; + + if (A->sf_size != B->sf_size) fatal("sf_join: sf_size mismatch"); + R = sf_new(A->count + B->count, A->sf_size); + R->count = A->count + B->count; + R->active_count = A->active_count + B->active_count; + intcpy(R->data, A->data, asize); + intcpy(R->data + asize, B->data, bsize); + return R; +} + + +/* sf_append -- append the sets of B to the end of A, and dispose of B */ +pset_family sf_append(A, B) +pset_family A, B; +{ + long asize = A->count * A->wsize; + long bsize = B->count * B->wsize; + + if (A->sf_size != B->sf_size) fatal("sf_append: sf_size mismatch"); + A->capacity = A->count + B->count; + A->data = REALLOC(unsigned int, A->data, (long) A->capacity * A->wsize); + intcpy(A->data + asize, B->data, bsize); + A->count += B->count; + A->active_count += B->active_count; + sf_free(B); + return A; +} + + +/* sf_new -- allocate "num" sets of "size" elements each */ +pset_family sf_new(num, size) +int num, size; +{ + pset_family A; + if (set_family_garbage == NULL) { + A = ALLOC(set_family_t, 1); + } else { + A = set_family_garbage; + set_family_garbage = A->next; + } + A->sf_size = size; + A->wsize = SET_SIZE(size); + A->capacity = num; + A->data = ALLOC(unsigned int, (long) A->capacity * A->wsize); + A->count = 0; + A->active_count = 0; + return A; +} + + +/* sf_save -- create a duplicate copy of a set family */ +pset_family sf_save(A) +register pset_family A; +{ + return sf_copy(sf_new(A->count, A->sf_size), A); +} + + +/* sf_free -- free the storage allocated for a set family */ +void sf_free(A) +pset_family A; +{ + FREE(A->data); + A->next = set_family_garbage; + set_family_garbage = A; +} + + +/* sf_cleanup -- free all of the set families from the garbage list */ +void sf_cleanup() +{ + register pset_family p, pnext; + for(p = set_family_garbage; p != (pset_family) NULL; p = pnext) { + pnext = p->next; + FREE(p); + } + set_family_garbage = (pset_family) NULL; +} + + +/* sf_addset -- add a set to the end of a set family */ +pset_family sf_addset(A, s) +pset_family A; +pset s; +{ + register pset p; + + if (A->count >= A->capacity) { + A->capacity = A->capacity + A->capacity/2 + 1; + A->data = REALLOC(unsigned int, A->data, (long) A->capacity * A->wsize); + } + p = GETSET(A, A->count++); + INLINEset_copy(p, s); + return A; +} + +/* sf_delset -- delete a set from a set family */ +void sf_delset(A, i) +pset_family A; +int i; +{ (void) set_copy(GETSET(A,i), GETSET(A, --A->count));} + +/* sf_print -- print a set_family as a set (list the element numbers) */ +void sf_print(A) +pset_family A; +{ + char *ps1(); + register pset p; + register int i; + foreachi_set(A, i, p) + (void) printf("A[%d] = %s\n", i, ps1(p)); +} + +/* sf_bm_print -- print a set_family as a bit-matrix */ +void sf_bm_print(A) +pset_family A; +{ + char *pbv1(); + register pset p; + register int i; + foreachi_set(A, i, p) + (void) printf("[%4d] %s\n", i, pbv1(p, A->sf_size)); +} + + +/* sf_write -- output a set family in an unintelligable manner */ +void sf_write(fp, A) +FILE *fp; +pset_family A; +{ + register pset p, last; + (void) fprintf(fp, "%d %d\n", A->count, A->sf_size); + foreach_set(A, last, p) + set_write(fp, p); + (void) fflush(fp); +} + + +/* sf_read -- read a set family written by sf_write */ +pset_family sf_read(fp) +FILE *fp; +{ + int i, j; + register pset p, last; + pset_family A; + + (void) fscanf(fp, "%d %d\n", &i, &j); + A = sf_new(i, j); + A->count = i; + foreach_set(A, last, p) { + (void) fscanf(fp, "%x", p); + for(j = 1; j <= LOOP(p); j++) + (void) fscanf(fp, "%x", p+j); + } + return A; +} + + +/* set_write -- output a set in an unintelligable manner */ +void set_write(fp, a) +register FILE *fp; +register pset a; +{ + register int n = LOOP(a), j; + + for(j = 0; j <= n; j++) { + (void) fprintf(fp, "%x ", a[j]); + if ((j+1) % 8 == 0 && j != n) + (void) fprintf(fp, "\n\t"); + } + (void) fprintf(fp, "\n"); +} + + +/* sf_bm_read -- read a set family written by sf_bm_print (almost) */ +pset_family sf_bm_read(fp) +FILE *fp; +{ + int i, j, rows, cols; + register pset pdest; + pset_family A; + + (void) fscanf(fp, "%d %d\n", &rows, &cols); + A = sf_new(rows, cols); + for(i = 0; i < rows; i++) { + pdest = GETSET(A, A->count++); + (void) set_clear(pdest, A->sf_size); + for(j = 0; j < cols; j++) { + switch(getc(fp)) { + case '0': + break; + case '1': + set_insert(pdest, j); + break; + default: + fatal("Error reading set family"); + } + } + if (getc(fp) != '\n') { + fatal("Error reading set family (at end of line)"); + } + } + return A; +} + + + +/* ps1 -- convert a set into a printable string */ +#define largest_string 120 +static char s1[largest_string]; +char *ps1(a) +register pset a; +{ + register int i, num, l, len = 0, n = NELEM(a); + char temp[20]; + bool first = TRUE; + + s1[len++] = '['; + for(i = 0; i < n; i++) + if (is_in_set(a,i)) { + if (! first) + s1[len++] = ','; + first = FALSE; num = i; + /* Generate digits (reverse order) */ + l = 0; do temp[l++] = num % 10 + '0'; while ((num /= 10) > 0); + /* Copy them back in correct order */ + do s1[len++] = temp[--l]; while (l > 0); + if (len > largest_string-15) { + s1[len++] = '.'; s1[len++] = '.'; s1[len++] = '.'; + break; + } + } + + s1[len++] = ']'; + s1[len++] = '\0'; + return s1; +} + +/* pbv1 -- print bit-vector */ +char *pbv1(s, n) +pset s; +int n; +{ + register int i; + for(i = 0; i < n; i++) + s1[i] = is_in_set(s,i) ? '1' : '0'; + s1[n] = '\0'; + return s1; +} + + +/* set_adjcnt -- adjust the counts for a set by "weight" */ +void +set_adjcnt(a, count, weight) +register pset a; +register int *count, weight; +{ + register int i, base; + register unsigned int val; + + for(i = LOOP(a); i > 0; ) { + for(val = a[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) { + if (val & 1) { + count[base] += weight; + } + } + } +} + + + +/* sf_count -- perform a column sum over a set family */ +int *sf_count(A) +pset_family A; +{ + register pset p, last; + register int i, base, *count; + register unsigned int val; + + count = ALLOC(int, A->sf_size); + for(i = A->sf_size - 1; i >= 0; i--) { + count[i] = 0; + } + + foreach_set(A, last, p) { + for(i = LOOP(p); i > 0; ) { + for(val = p[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) { + if (val & 1) { + count[base]++; + } + } + } + } + return count; +} + + +/* sf_count_restricted -- perform a column sum over a set family, restricting + * to only the columns which are in r; also, the columns are weighted by the + * number of elements which are in each row + */ +int *sf_count_restricted(A, r) +pset_family A; +register pset r; +{ + register pset p; + register int i, base, *count; + register unsigned int val; + int weight; + pset last; + + count = ALLOC(int, A->sf_size); + for(i = A->sf_size - 1; i >= 0; i--) { + count[i] = 0; + } + + /* Loop for each set */ + foreach_set(A, last, p) { + weight = 1024 / (set_ord(p) - 1); + for(i = LOOP(p); i > 0; ) { + for(val=p[i]&r[i], base= --i<>= 1) { + if (val & 1) { + count[base] += weight; + } + } + } + } + return count; +} + + +/* + * sf_delc -- delete columns first ... last of A + */ +pset_family sf_delc(A, first, last) +pset_family A; +int first, last; +{ + return sf_delcol(A, first, last-first + 1); +} + + +/* + * sf_addcol -- add columns to a set family; includes a quick check to see + * if there is already enough room (and hence, can avoid copying) + */ +pset_family sf_addcol(A, firstcol, n) +pset_family A; +int firstcol, n; +{ + int maxsize; + + /* Check if adding columns at the end ... */ + if (firstcol == A->sf_size) { + /* If so, check if there is already enough room */ + maxsize = BPI * LOOPINIT(A->sf_size); + if ((A->sf_size + n) <= maxsize) { + A->sf_size += n; + return A; + } + } + return sf_delcol(A, firstcol, -n); +} + +/* + * sf_delcol -- add/delete columns to/from a set family + * + * if n > 0 then n columns starting from firstcol are deleted if n < 0 + * then n blank columns are inserted starting at firstcol + * (i.e., the first new column number is firstcol) + * + * This is done by copying columns in the array which is a relatively + * slow operation. + */ +pset_family sf_delcol(A, firstcol, n) +pset_family A; +register int firstcol, n; +{ + register pset p, last, pdest; + register int i; + pset_family B; + + B = sf_new(A->count, A->sf_size - n); + foreach_set(A, last, p) { + pdest = GETSET(B, B->count++); + INLINEset_clear(pdest, B->sf_size); + for(i = 0; i < firstcol; i++) + if (is_in_set(p, i)) + set_insert(pdest, i); + for(i = n > 0 ? firstcol + n : firstcol; i < A->sf_size; i++) + if (is_in_set(p, i)) + set_insert(pdest, i - n); + } + sf_free(A); + return B; +} + + +/* + * sf_copy_col -- copy column "srccol" from "src" to column "dstcol" of "dst" + */ +pset_family sf_copy_col(dst, dstcol, src, srccol) +pset_family dst, src; +int dstcol, srccol; +{ + register pset last, p, pdest; + register int word_test, word_set; + unsigned int bit_set, bit_test; + + /* CHEAT! form these constants outside the loop */ + word_test = WHICH_WORD(srccol); + bit_test = 1 << WHICH_BIT(srccol); + word_set = WHICH_WORD(dstcol); + bit_set = 1 << WHICH_BIT(dstcol); + + pdest = dst->data; + foreach_set(src, last, p) { + if ((p[word_test] & bit_test) != 0) + pdest[word_set] |= bit_set; +/* + * equivalent code for this is ... + * if (is_in_set(p, srccol)) set_insert(pdest, destcol); + */ + pdest += dst->wsize; + } + return dst; +} + + + +/* + * sf_compress -- delete columns from a matrix + */ +pset_family sf_compress(A, c) +pset_family A; /* will be freed */ +register pset c; +{ + register pset p; + register int i, bcol; + pset_family B; + + /* create a clean set family for the result */ + B = sf_new(A->count, set_ord(c)); + for(i = 0; i < A->count; i++) { + p = GETSET(B, B->count++); + INLINEset_clear(p, B->sf_size); + } + + /* copy each column of A which has a 1 in c */ + bcol = 0; + for(i = 0; i < A->sf_size; i++) { + if (is_in_set(c, i)) { + (void) sf_copy_col(B, bcol++, A, i); + } + } + sf_free(A); + return B; +} + + + +/* + * sf_transpose -- transpose a bit matrix + * + * There are trickier ways of doing this, but this works. + */ +pset_family sf_transpose(A) +pset_family A; +{ + pset_family B; + register pset p; + register int i, j; + + B = sf_new(A->sf_size, A->count); + B->count = A->sf_size; + foreachi_set(B, i, p) { + INLINEset_clear(p, B->sf_size); + } + foreachi_set(A, i, p) { + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(p, j)) { + set_insert(GETSET(B, j), i); + } + } + } + sf_free(A); + return B; +} + + +/* + * sf_permute -- permute the columns of a set_family + * + * permute is an array of integers containing column numbers of A which + * are to be retained. + */ +pset_family sf_permute(A, permute, npermute) +pset_family A; +register int *permute, npermute; +{ + pset_family B; + register pset p, last, pdest; + register int j; + + B = sf_new(A->count, npermute); + B->count = A->count; + foreach_set(B, last, p) + INLINEset_clear(p, npermute); + + pdest = B->data; + foreach_set(A, last, p) { + for(j = 0; j < npermute; j++) + if (is_in_set(p, permute[j])) + set_insert(pdest, j); + pdest += B->wsize; + } + sf_free(A); + return B; +} diff --git a/sis/espresso/setc.c b/sis/espresso/setc.c new file mode 100644 index 0000000..16914a3 --- /dev/null +++ b/sis/espresso/setc.c @@ -0,0 +1,483 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/setc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + setc.c -- massive bit-hacking for performing special "cube"-type + operations on a set + + The basic trick used for binary valued variables is the following: + + If a[w] and b[w] contain a full word of binary variables, then: + + 1) to get the full word of their intersection, we use + + x = a[w] & b[w]; + + + 2) to see if the intersection is null in any variables, we examine + + x = ~(x | x >> 1) & DISJOINT; + + this will have a single 1 in each binary variable for which + the intersection is null. In particular, if this is zero, + then there are no disjoint variables; or, if this is nonzero, + then there is at least one disjoint variable. A "count_ones" + over x will tell in how many variables they have an null + intersection. + + + 3) to get a mask which selects the disjoint variables, we use + + (x | x << 1) + + this provides a selector which can be used to see where + they have an null intersection + + + cdist return distance between two cubes + cdist0 return true if two cubes are distance 0 apart + cdist01 return distance, or 2 if distance exceeds 1 + consensus compute consensus of two cubes distance 1 apart + force_lower expand hack (for now), related to consensus +*/ + +#include "espresso.h" + +/* see if the cube has a full row of 1's (with respect to cof) */ +bool full_row(p, cof) +IN register pcube p, cof; +{ + register int i = LOOP(p); + do if ((p[i] | cof[i]) != cube.fullset[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* + cdist0 -- return TRUE if a and b are distance 0 apart +*/ + +bool cdist0(a, b) +register pcube a, b; +{ + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (~(x | x >> 1) & cube.inmask) + return FALSE; /* disjoint in some variable */ + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (~(x | x >> 1) & DISJOINT) + return FALSE; /* disjoint in some variable */ + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + return FALSE; /* disjoint in this variable */ + nextvar: ; + } + } + return TRUE; +} + +/* + cdist01 -- return the "distance" between two cubes (defined as the + number of null variables in their intersection). If the distance + exceeds 1, the value 2 is returned. +*/ + +int cdist01(a, b) +register pset a, b; +{ + int dist = 0; + + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~ (x | x >> 1) & cube.inmask) + if ((dist = count_ones(x)) > 1) + return 2; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~ (x | x >> 1) & DISJOINT) + if (dist == 1 || (dist += count_ones(x)) > 1) + return 2; + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + if (++dist > 1) + return 2; + nextvar: ; + } + } + return dist; +} + +/* + cdist -- return the "distance" between two cubes (defined as the + number of null variables in their intersection). +*/ + +int cdist(a, b) +register pset a, b; +{ + int dist = 0; + + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~ (x | x >> 1) & cube.inmask) + dist = count_ones(x); + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~ (x | x >> 1) & DISJOINT) + dist += count_ones(x); + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + dist++; + nextvar: ; + } + } + return dist; +} + +/* + force_lower -- Determine which variables of a do not intersect b. +*/ + +pset force_lower(xlower, a, b) +INOUT pset xlower; +IN register pset a, b; +{ + + { /* Check binary variables (if any) */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~(x | x >> 1) & cube.inmask) + xlower[last] |= (x | (x << 1)) & a[last]; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~(x | x >> 1) & DISJOINT) + xlower[w] |= (x | (x << 1)) & a[w]; + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + for(w = cube.first_word[var]; w <= last; w++) + xlower[w] |= a[w] & mask[w]; + nextvar: ; + } + } + return xlower; +} + +/* + consensus -- multiple-valued consensus + + Although this looks very messy, the idea is to compute for r the + "and" of the cubes a and b for each variable, unless the "and" is + null in a variable, in which case the "or" of a and b is computed + for this variable. + + Because we don't check how many variables are null in the + intersection of a and b, the returned value for r really only + represents the consensus when a and b are distance 1 apart. +*/ + +void consensus(r, a, b) +INOUT pcube r; +IN register pcube a, b; +{ + INLINEset_clear(r, cube.size); + + { /* Check binary variables (if any) */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + r[last] = x = a[last] & b[last]; + if (x = ~(x | x >> 1) & cube.inmask) + r[last] |= (x | (x << 1)) & (a[last] | b[last]); + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + r[w] = x = a[w] & b[w]; + if (x = ~(x | x >> 1) & DISJOINT) + r[w] |= (x | (x << 1)) & (a[w] | b[w]); + } + } + } + + + { /* Check the multiple-valued variables */ + bool empty; int var; unsigned int x; + register int w, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + last = cube.last_word[var]; + empty = TRUE; + for(w = cube.first_word[var]; w <= last; w++) + if (x = a[w] & b[w] & mask[w]) + empty = FALSE, r[w] |= x; + if (empty) + for(w = cube.first_word[var]; w <= last; w++) + r[w] |= mask[w] & (a[w] | b[w]); + } + } +} + +/* + cactive -- return the index of the single active variable in + the cube, or return -1 if there are none or more than 2. +*/ + +int cactive(a) +register pcube a; +{ + int active = -1, dist = 0, bit_index(); + + { /* Check binary variables */ + register int w, last; + register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last]; + if (x = ~ (x & x >> 1) & cube.inmask) { + if ((dist = count_ones(x)) > 1) + return -1; /* more than 2 active variables */ + active = (last-1)*(BPI/2) + bit_index(x) / 2; + } + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w]; + if (x = ~ (x & x >> 1) & DISJOINT) { + if ((dist += count_ones(x)) > 1) + return -1; /* more than 2 active variables */ + active = (w-1)*(BPI/2) + bit_index(x) / 2; + } + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; + register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~ a[w]) { + if (++dist > 1) + return -1; + active = var; + break; + } + } + } + return active; +} + +/* + ccommon -- return TRUE if a and b are share "active" variables + active variables include variables that are empty; +*/ + +bool ccommon(a, b, cof) +register pcube a, b, cof; +{ + { /* Check binary variables */ + int last; + register int w; + register unsigned int x, y; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] | cof[last]; + y = b[last] | cof[last]; + if (~(x & x>>1) & ~(y & y>>1) & cube.inmask) + return TRUE; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] | cof[w]; + y = b[w] | cof[w]; + if (~(x & x>>1) & ~(y & y>>1) & DISJOINT) + return TRUE; + } + } + } + + { /* Check the multiple-valued variables */ + int var; + register int w, last; + register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + /* Check for some part missing from a */ + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~a[w] & ~cof[w]) { + + /* If so, check for some part missing from b */ + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~b[w] & ~cof[w]) + return TRUE; /* both active */ + break; + } + } + } + return FALSE; +} + +/* + These routines compare two sets (cubes) for the qsort() routine and + return: + + -1 if set a is to precede set b + 0 if set a and set b are equal + 1 if set a is to follow set b + + Usually the SIZE field of the set is assumed to contain the size + of the set (which will save recomputing the set size during the + sort). For distance-1 merging, the global variable cube.temp[0] is + a mask which mask's-out the merging variable. +*/ + +/* descend -- comparison for descending sort on set size */ +int descend(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + if (SIZE(a1) > SIZE(b1)) return -1; + else if (SIZE(a1) < SIZE(b1)) return 1; + else { + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return -1; else if (a1[i] < b1[i]) return 1; + while (--i > 0); + } + return 0; +} + +/* ascend -- comparison for ascending sort on set size */ +int ascend(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + if (SIZE(a1) > SIZE(b1)) return 1; + else if (SIZE(a1) < SIZE(b1)) return -1; + else { + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return 1; else if (a1[i] < b1[i]) return -1; + while (--i > 0); + } + return 0; +} + + +/* lex_order -- comparison for "lexical" ordering of cubes */ +int lex_order(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return -1; else if (a1[i] < b1[i]) return 1; + while (--i > 0); + return 0; +} + + +/* d1_order -- comparison for distance-1 merge routine */ +int d1_order(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b, c1 = cube.temp[0]; + register int i = LOOP(a1); + register unsigned int x1, x2; + do + if ((x1 = a1[i] | c1[i]) > (x2 = b1[i] | c1[i])) return -1; + else if (x1 < x2) return 1; + while (--i > 0); + return 0; +} + + +/* desc1 -- comparison (without indirection) for descending sort */ +/* also has effect of handling NULL pointers,and a NULL pointer has smallest +order */ +int desc1(a, b) +register pset a, b; +{ + if (a == (pset) NULL) + return (b == (pset) NULL) ? 0 : 1; + else if (b == (pset) NULL) + return -1; + if (SIZE(a) > SIZE(b)) return -1; + else if (SIZE(a) < SIZE(b)) return 1; + else { + register int i = LOOP(a); + do + if (a[i] > b[i]) return -1; else if (a[i] < b[i]) return 1; + while (--i > 0); + } + return 0; +} diff --git a/sis/espresso/sharp.c b/sis/espresso/sharp.c new file mode 100644 index 0000000..d94ab7f --- /dev/null +++ b/sis/espresso/sharp.c @@ -0,0 +1,247 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/sharp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + sharp.c -- perform sharp, disjoint sharp, and intersection +*/ + +#include "espresso.h" + +long start_time; + + +/* cv_sharp -- form the sharp product between two covers */ +pcover cv_sharp(A, B) +pcover A, B; +{ + pcube last, p; + pcover T; + + T = new_cover(0); + foreach_set(A, last, p) + T = sf_union(T, cb_sharp(p, B)); + return T; +} + + +/* cb_sharp -- form the sharp product between a cube and a cover */ +pcover cb_sharp(c, T) +pcube c; +pcover T; +{ + if (T->count == 0) { + T = sf_addset(new_cover(1), c); + } else { + start_time = ptime(); + T = cb_recur_sharp(c, T, 0, T->count-1, 0); + } + return T; +} + + +/* recursive formulation to provide balanced merging */ +pcover cb_recur_sharp(c, T, first, last, level) +pcube c; +pcover T; +int first, last, level; +{ + pcover temp, left, right; + int middle; + + if (first == last) { + temp = sharp(c, GETSET(T, first)); + } else { + middle = (first + last) / 2; + left = cb_recur_sharp(c, T, first, middle, level+1); + right = cb_recur_sharp(c, T, middle+1, last, level+1); + temp = cv_intersect(left, right); + if ((debug & SHARP) && level < 4) { + (void) printf("# SHARP[%d]: %4d = %4d x %4d, time = %s\n", + level, temp->count, left->count, right->count, + print_time(ptime() - start_time)); + (void) fflush(stdout); + } + free_cover(left); + free_cover(right); + } + return temp; +} + + +/* sharp -- form the sharp product between two cubes */ +pcover sharp(a, b) +pcube a, b; +{ + register int var; + register pcube d=cube.temp[0], temp=cube.temp[1], temp1=cube.temp[2]; + pcover r = new_cover(cube.num_vars); + + if (cdist0(a, b)) { + (void) set_diff(d, a, b); + for(var = 0; var < cube.num_vars; var++) { + if (! setp_empty(set_and(temp, d, cube.var_mask[var]))) { + (void) set_diff(temp1, a, cube.var_mask[var]); + (void) set_or(GETSET(r, r->count++), temp, temp1); + } + } + } else { + r = sf_addset(r, a); + } + return r; +} + +pcover make_disjoint(A) +pcover A; +{ + pcover R, new; + register pset last, p; + + R = new_cover(0); + foreach_set(A, last, p) { + new = cb_dsharp(p, R); + R = sf_append(R, new); + } + return R; +} + + +/* cv_dsharp -- disjoint-sharp product between two covers */ +pcover cv_dsharp(A, B) +pcover A, B; +{ + register pcube last, p; + pcover T; + + T = new_cover(0); + foreach_set(A, last, p) { + T = sf_union(T, cb_dsharp(p, B)); + } + return T; +} + + +/* cb1_dsharp -- disjoint-sharp product between a cover and a cube */ +pcover cb1_dsharp(T, c) +pcover T; +pcube c; +{ + pcube last, p; + pcover R; + + R = new_cover(T->count); + foreach_set(T, last, p) { + R = sf_union(R, dsharp(p, c)); + } + return R; +} + + +/* cb_dsharp -- disjoint-sharp product between a cube and a cover */ +pcover cb_dsharp(c, T) +pcube c; +pcover T; +{ + pcube last, p; + pcover Y, Y1; + + if (T->count == 0) { + Y = sf_addset(new_cover(1), c); + } else { + Y = new_cover(T->count); + (void) set_copy(GETSET(Y,Y->count++), c); + foreach_set(T, last, p) { + Y1 = cb1_dsharp(Y, p); + free_cover(Y); + Y = Y1; + } + } + return Y; +} + + +/* dsharp -- form the disjoint-sharp product between two cubes */ +pcover dsharp(a, b) +pcube a, b; +{ + register pcube mask, diff, and, temp, temp1 = cube.temp[0]; + int var; + pcover r; + + r = new_cover(cube.num_vars); + + if (cdist0(a, b)) { + diff = set_diff(new_cube(), a, b); + and = set_and(new_cube(), a, b); + mask = new_cube(); + for(var = 0; var < cube.num_vars; var++) { + /* check if position var of "a and not b" is not empty */ + if (! setp_disjoint(diff, cube.var_mask[var])) { + + /* coordinate var equals the difference between a and b */ + temp = GETSET(r, r->count++); + (void) set_and(temp, diff, cube.var_mask[var]); + + /* coordinates 0 ... var-1 equal the intersection */ + INLINEset_and(temp1, and, mask); + INLINEset_or(temp, temp, temp1); + + /* coordinates var+1 .. cube.num_vars equal a */ + (void) set_or(mask, mask, cube.var_mask[var]); + INLINEset_diff(temp1, a, mask); + INLINEset_or(temp, temp, temp1); + } + } + free_cube(diff); + free_cube(and); + free_cube(mask); + } else { + r = sf_addset(r, a); + } + return r; +} + +/* cv_intersect -- form the intersection of two covers */ + +#define MAGIC 500 /* save 500 cubes before containment */ + +pcover cv_intersect(A, B) +pcover A, B; +{ + register pcube pi, pj, lasti, lastj, pt; + pcover T, Tsave = NULL; + + /* How large should each temporary result cover be ? */ + T = new_cover(MAGIC); + pt = T->data; + + /* Form pairwise intersection of each cube of A with each cube of B */ + foreach_set(A, lasti, pi) { + foreach_set(B, lastj, pj) { + if (cdist0(pi, pj)) { + (void) set_and(pt, pi, pj); + if (++T->count >= T->capacity) { + if (Tsave == NULL) + Tsave = sf_contain(T); + else + Tsave = sf_union(Tsave, sf_contain(T)); + T = new_cover(MAGIC); + pt = T->data; + } else + pt += T->wsize; + } + } + } + + + if (Tsave == NULL) + Tsave = sf_contain(T); + else + Tsave = sf_union(Tsave, sf_contain(T)); + return Tsave; +} diff --git a/sis/espresso/sminterf.c b/sis/espresso/sminterf.c new file mode 100644 index 0000000..4169c8c --- /dev/null +++ b/sis/espresso/sminterf.c @@ -0,0 +1,44 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/sminterf.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +#include "espresso.h" + + +pset +do_sm_minimum_cover(A) +pset_family A; +{ + sm_matrix *M; + sm_row *sparse_cover; + sm_element *pe; + pset cover; + register int i, base, rownum; + register unsigned val; + register pset last, p; + + M = sm_alloc(); + rownum = 0; + foreach_set(A, last, p) { + foreach_set_element(p, i, val, base) { + (void) sm_insert(M, rownum, base); + } + rownum++; + } + + sparse_cover = sm_minimum_cover(M, NIL(int), 1, 0); + sm_free(M); + + cover = set_new(A->sf_size); + sm_foreach_row_element(sparse_cover, pe) { + set_insert(cover, pe->col_num); + } + sm_row_free(sparse_cover); + + return cover; +} diff --git a/sis/espresso/sparse.c b/sis/espresso/sparse.c new file mode 100644 index 0000000..fc97c3a --- /dev/null +++ b/sis/espresso/sparse.c @@ -0,0 +1,146 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/sparse.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + module: sparse.c + + make_sparse is a last-step cleanup to reduce the total number + of literals in the cover. + + This is done by reducing the "sparse" variables (using a modified + version of irredundant rather than reduce), followed by expanding + the "dense" variables (using modified version of expand). +*/ + +#include "espresso.h" + +pcover make_sparse(F, D, R) +pcover F, D, R; +{ + cost_t cost, best_cost; + + cover_cost(F, &best_cost); + + do { + EXECUTE(F = mv_reduce(F, D), MV_REDUCE_TIME, F, cost); + if (cost.total == best_cost.total) + break; + copy_cost(&cost, &best_cost); + + EXECUTE(F = expand(F, R, TRUE), RAISE_IN_TIME, F, cost); + if (cost.total == best_cost.total) + break; + copy_cost(&cost, &best_cost); + } while (force_irredundant); + + return F; +} + +/* + mv_reduce -- perform an "optimal" reduction of the variables which + we desire to be sparse + + This could be done using "reduce" and then saving just the desired + part of the reduction. Instead, this version uses IRRED to find + which cubes of an output are redundant. Note that this gets around + the cube-ordering problem. + + In normal use, it is expected that the cover is irredundant and + hence no cubes will be reduced to the empty cube (however, this is + checked for and such cubes will be deleted) +*/ + +pcover +mv_reduce(F, D) +pcover F, D; +{ + register int i, var; + register pcube p, p1, last; + int index; + pcover F1, D1; + pcube *F_cube_table; + + /* loop for each multiple-valued variable */ + for(var = 0; var < cube.num_vars; var++) { + + if (cube.sparse[var]) { + + /* loop for each part of the variable */ + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + + /* remember mapping of F1 cubes back to F cubes */ + F_cube_table = ALLOC(pcube, F->count); + + /* 'cofactor' against part #i of variable #var */ + F1 = new_cover(F->count); + foreach_set(F, last, p) { + if (is_in_set(p, i)) { + F_cube_table[F1->count] = p; + p1 = GETSET(F1, F1->count++); + (void) set_diff(p1, p, cube.var_mask[var]); + set_insert(p1, i); + } + } + + /* 'cofactor' against part #i of variable #var */ + /* not really necessary -- just more efficient ? */ + D1 = new_cover(D->count); + foreach_set(D, last, p) { + if (is_in_set(p, i)) { + p1 = GETSET(D1, D1->count++); + (void) set_diff(p1, p, cube.var_mask[var]); + set_insert(p1, i); + } + } + + mark_irredundant(F1, D1); + + /* now remove part i from cubes which are redundant */ + index = 0; + foreach_set(F1, last, p1) { + if (! TESTP(p1, ACTIVE)) { + p = F_cube_table[index]; + + /* don't reduce a variable which is full + * (unless it is the output variable) + */ + if (var == cube.num_vars-1 || + ! setp_implies(cube.var_mask[var], p)) { + set_remove(p, i); + } + RESET(p, PRIME); + } + index++; + } + + free_cover(F1); + free_cover(D1); + FREE(F_cube_table); + } + } + } + + /* Check if any cubes disappeared */ + (void) sf_active(F); + for(var = 0; var < cube.num_vars; var++) { + if (cube.sparse[var]) { + foreach_active_set(F, last, p) { + if (setp_disjoint(p, cube.var_mask[var])) { + RESET(p, ACTIVE); + F->active_count--; + } + } + } + } + + if (F->count != F->active_count) { + F = sf_inactive(F); + } + return F; +} diff --git a/sis/espresso/unate.c b/sis/espresso/unate.c new file mode 100644 index 0000000..2b81a47 --- /dev/null +++ b/sis/espresso/unate.c @@ -0,0 +1,441 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/unate.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + * unate.c -- routines for dealing with unate functions + */ + +#include "espresso.h" + +static pset_family abs_covered(); +static pset_family abs_covered_many(); +static int abs_select_restricted(); + +pcover map_cover_to_unate(T) +pcube *T; +{ + register unsigned int word_test, word_set, bit_test, bit_set; + register pcube p, pA; + pset_family A; + pcube *T1; + int ncol, i; + + A = sf_new(CUBELISTSIZE(T), cdata.vars_unate); + A->count = CUBELISTSIZE(T); + foreachi_set(A, i, p) { + (void) set_clear(p, A->sf_size); + } + ncol = 0; + + for(i = 0; i < cube.size; i++) { + if (cdata.part_zeros[i] > 0) { + assert(ncol <= cdata.vars_unate); + + /* Copy a column from T to A */ + word_test = WHICH_WORD(i); + bit_test = 1 << WHICH_BIT(i); + word_set = WHICH_WORD(ncol); + bit_set = 1 << WHICH_BIT(ncol); + + pA = A->data; + for(T1 = T+2; (p = *T1++) != 0; ) { + if ((p[word_test] & bit_test) == 0) { + pA[word_set] |= bit_set; + } + pA += A->wsize; + } + + ncol++; + } + } + + return A; +} + +pcover map_unate_to_cover(A) +pset_family A; +{ + register int i, ncol, lp; + register pcube p, pB; + int var, nunate, *unate; + pcube last; + pset_family B; + + B = sf_new(A->count, cube.size); + B->count = A->count; + + /* Find the unate variables */ + unate = ALLOC(int, cube.num_vars); + nunate = 0; + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + unate[nunate++] = var; + } + } + + /* Loop for each set of A */ + pB = B->data; + foreach_set(A, last, p) { + + /* Initialize this set of B */ + INLINEset_fill(pB, cube.size); + + /* Now loop for the unate variables; if the part is in A, + * then this variable of B should be a single 1 in the unate + * part. + */ + for(ncol = 0; ncol < nunate; ncol++) { + if (is_in_set(p, ncol)) { + lp = cube.last_part[unate[ncol]]; + for(i = cube.first_part[unate[ncol]]; i <= lp; i++) { + if (cdata.part_zeros[i] == 0) { + set_remove(pB, i); + } + } + } + } + pB += B->wsize; + } + + FREE(unate); + return B; +} + +/* + * unate_compl + */ + +pset_family unate_compl(A) +pset_family A; +{ + register pset p, last; + + /* Make sure A is single-cube containment minimal */ +/* A = sf_rev_contain(A);*/ + + foreach_set(A, last, p) { + PUTSIZE(p, set_ord(p)); + } + + /* Recursively find the complement */ + A = unate_complement(A); + + /* Now, we can guarantee a minimal result by containing the result */ + A = sf_rev_contain(A); + return A; +} + + +/* + * Assume SIZE(p) records the size of each set + */ +pset_family unate_complement(A) +pset_family A; /* disposes of A */ +{ + pset_family Abar; + register pset p, p1, restrict; + register int i; + int max_i, min_set_ord, j; + + /* Check for no sets in the matrix -- complement is the universe */ + if (A->count == 0) { + sf_free(A); + Abar = sf_new(1, A->sf_size); + (void) set_clear(GETSET(Abar, Abar->count++), A->sf_size); + + /* Check for a single set in the maxtrix -- compute de Morgan complement */ + } else if (A->count == 1) { + p = A->data; + Abar = sf_new(A->sf_size, A->sf_size); + for(i = 0; i < A->sf_size; i++) { + if (is_in_set(p, i)) { + p1 = set_clear(GETSET(Abar, Abar->count++), A->sf_size); + set_insert(p1, i); + } + } + sf_free(A); + + } else { + + /* Select splitting variable as the variable which belongs to a set + * of the smallest size, and which has greatest column count + */ + restrict = set_new(A->sf_size); + min_set_ord = A->sf_size + 1; + foreachi_set(A, i, p) { + if (SIZE(p) < min_set_ord) { + (void) set_copy(restrict, p); + min_set_ord = SIZE(p); + } else if (SIZE(p) == min_set_ord) { + (void) set_or(restrict, restrict, p); + } + } + + /* Check for no data (shouldn't happen ?) */ + if (min_set_ord == 0) { + A->count = 0; + Abar = A; + + /* Check for "essential" columns */ + } else if (min_set_ord == 1) { + Abar = unate_complement(abs_covered_many(A, restrict)); + sf_free(A); + foreachi_set(Abar, i, p) { + (void) set_or(p, p, restrict); + } + + /* else, recur as usual */ + } else { + max_i = abs_select_restricted(A, restrict); + + /* Select those rows of A which are not covered by max_i, + * recursively find all minimal covers of these rows, and + * then add back in max_i + */ + Abar = unate_complement(abs_covered(A, max_i)); + foreachi_set(Abar, i, p) { + set_insert(p, max_i); + } + + /* Now recur on A with all zero's on column max_i */ + foreachi_set(A, i, p) { + if (is_in_set(p, max_i)) { + set_remove(p, max_i); + j = SIZE(p) - 1; + PUTSIZE(p, j); + } + } + + Abar = sf_append(Abar, unate_complement(A)); + } + set_free(restrict); + } + + return Abar; +} + +pset_family exact_minimum_cover(T) +IN pset_family T; +{ + register pset p, last, p1; + register int i, n; + int lev, lvl; + pset nlast; + pset_family temp; + long start = ptime(); + struct { + pset_family sf; + int level; + } stack[32]; /* 32 suffices for 2 ** 32 cubes ! */ + + if (T->count <= 0) + return sf_new(1, T->sf_size); + for(n = T->count, lev = 0; n != 0; n >>= 1, lev++) ; + + /* A simple heuristic ordering */ + T = lex_sort(sf_save(T)); + + /* Push a full set on the stack to get things started */ + n = 1; + stack[0].sf = sf_new(1, T->sf_size); + stack[0].level = lev; + (void) set_fill(GETSET(stack[0].sf, stack[0].sf->count++), T->sf_size); + + nlast = GETSET(T, T->count - 1); + foreach_set(T, last, p) { + + /* "unstack" the set into a family */ + temp = sf_new(set_ord(p), T->sf_size); + for(i = 0; i < T->sf_size; i++) + if (is_in_set(p, i)) { + p1 = set_fill(GETSET(temp, temp->count++), T->sf_size); + set_remove(p1, i); + } + stack[n].sf = temp; + stack[n++].level = lev; + + /* Pop the stack and perform (leveled) intersections */ + while (n > 1 && (stack[n-1].level==stack[n-2].level || p == nlast)) { + temp = unate_intersect(stack[n-1].sf, stack[n-2].sf, FALSE); + lvl = MIN(stack[n-1].level, stack[n-2].level) - 1; + if (debug & MINCOV && lvl < 10) { + (void) printf("# EXACT_MINCOV[%d]: %4d = %4d x %4d, time = %s\n", + lvl, temp->count, stack[n-1].sf->count, + stack[n-2].sf->count, print_time(ptime() - start)); + (void) fflush(stdout); + } + sf_free(stack[n-2].sf); + sf_free(stack[n-1].sf); + stack[n-2].sf = temp; + stack[n-2].level = lvl; + n--; + } + } + + temp = stack[0].sf; + p1 = set_fill(set_new(T->sf_size), T->sf_size); + foreach_set(temp, last, p) + INLINEset_diff(p, p1, p); + set_free(p1); + if (debug & MINCOV1) { + (void) printf("MINCOV: family of all minimal coverings is\n"); + sf_print(temp); + } + sf_free(T); /* this is the copy of T we made ... */ + return temp; +} + +/* + * unate_intersect -- intersect two unate covers + * + * If largest_only is TRUE, then only the largest cube(s) are returned + */ + +#define MAGIC 500 /* save 500 cubes before containment */ + +pset_family unate_intersect(A, B, largest_only) +pset_family A, B; +bool largest_only; +{ + register pset pi, pj, lasti, lastj, pt; + pset_family T, Tsave; + bool save; + int maxord, ord; + + /* How large should each temporary result cover be ? */ + T = sf_new(MAGIC, A->sf_size); + Tsave = NULL; + maxord = 0; + pt = T->data; + + /* Form pairwise intersection of each set of A with each cube of B */ + foreach_set(A, lasti, pi) { + + foreach_set(B, lastj, pj) { + + save = set_andp(pt, pi, pj); + + /* Check if we want the largest only */ + if (save && largest_only) { + if ((ord = set_ord(pt)) > maxord) { + /* discard Tsave and T */ + if (Tsave != NULL) { + sf_free(Tsave); + Tsave = NULL; + } + pt = T->data; + T->count = 0; + /* Re-create pt (which was just thrown away) */ + (void) set_and(pt, pi, pj); + maxord = ord; + } else if (ord < maxord) { + save = FALSE; + } + } + + if (save) { + if (++T->count >= T->capacity) { + T = sf_contain(T); + Tsave = (Tsave == NULL) ? T : sf_union(Tsave, T); + T = sf_new(MAGIC, A->sf_size); + pt = T->data; + } else { + pt += T->wsize; + } + } + } + } + + + /* Contain the final result and merge it into Tsave */ + T = sf_contain(T); + Tsave = (Tsave == NULL) ? T : sf_union(Tsave, T); + + return Tsave; +} + +/* + * abs_covered -- after selecting a new column for the selected set, + * create a new matrix which is only those rows which are still uncovered + */ +static pset_family +abs_covered(A, pick) +pset_family A; +register int pick; +{ + register pset last, p, pdest; + register pset_family Aprime; + + Aprime = sf_new(A->count, A->sf_size); + pdest = Aprime->data; + foreach_set(A, last, p) + if (! is_in_set(p, pick)) { + INLINEset_copy(pdest, p); + Aprime->count++; + pdest += Aprime->wsize; + } + return Aprime; +} + + +/* + * abs_covered_many -- after selecting many columns for ther selected set, + * create a new matrix which is only those rows which are still uncovered + */ +static pset_family +abs_covered_many(A, pick_set) +pset_family A; +register pset pick_set; +{ + register pset last, p, pdest; + register pset_family Aprime; + + Aprime = sf_new(A->count, A->sf_size); + pdest = Aprime->data; + foreach_set(A, last, p) + if (setp_disjoint(p, pick_set)) { + INLINEset_copy(pdest, p); + Aprime->count++; + pdest += Aprime->wsize; + } + return Aprime; +} + + +/* + * abs_select_restricted -- select the column of maximum column count which + * also belongs to the set "restrict"; weight each column of a set as + * 1 / (set_ord(p) - 1). + */ +static int +abs_select_restricted(A, restrict) +pset_family A; +pset restrict; +{ + register int i, best_var, best_count, *count; + + /* Sum the elements in these columns */ + count = sf_count_restricted(A, restrict); + + /* Find which variable has maximum weight */ + best_var = -1; + best_count = 0; + for(i = 0; i < A->sf_size; i++) { + if (count[i] > best_count) { + best_var = i; + best_count = count[i]; + } + } + FREE(count); + + if (best_var == -1) + fatal("abs_select_restricted: should not have best_var == -1"); + + return best_var; +} diff --git a/sis/espresso/verify.c b/sis/espresso/verify.c new file mode 100644 index 0000000..fd90aad --- /dev/null +++ b/sis/espresso/verify.c @@ -0,0 +1,193 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/espresso/verify.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:21 $ + * + */ +/* + */ + +#include "espresso.h" + +/* + * verify -- check that all minterms of F are contained in (Fold u Dold) + * and that all minterms of Fold are contained in (F u Dold). + */ +bool verify(F, Fold, Dold) +pcover F, Fold, Dold; +{ + pcube p, last, *FD; + bool verify_error = FALSE; + + /* Make sure the function didn't grow too large */ + FD = cube2list(Fold, Dold); + foreach_set(F, last, p) + if (! cube_is_covered(FD, p)) { + (void) printf("some minterm in F is not covered by Fold u Dold\n"); + verify_error = TRUE; + if (verbose_debug) (void) printf("%s\n", pc1(p)); else break; + } + free_cubelist(FD); + + /* Make sure minimized function covers the original function */ + FD = cube2list(F, Dold); + foreach_set(Fold, last, p) + if (! cube_is_covered(FD, p)) { + (void) printf("some minterm in Fold is not covered by F u Dold\n"); + verify_error = TRUE; + if (verbose_debug) (void) printf("%s\n", pc1(p)); else break; + } + free_cubelist(FD); + + return verify_error; +} + + + +/* + * PLA_verify -- verify that two PLA's are identical + * + * If names are given, row and column permutations are done to make + * the comparison meaningful. + * + */ +bool PLA_verify(PLA1, PLA2) +pPLA PLA1, PLA2; +{ + /* Check if both have names given; if so, attempt to permute to + * match the names + */ + if (PLA1->label != NULL && PLA1->label[0] != NULL && + PLA2->label != NULL && PLA2->label[0] != NULL) { + PLA_permute(PLA1, PLA2); + } else { + (void) fprintf(stderr, "Warning: cannot permute columns without names\n"); + return TRUE; + } + + if (PLA1->F->sf_size != PLA2->F->sf_size) { + (void) fprintf(stderr, "PLA_verify: PLA's are not the same size\n"); + return TRUE; + } + + return verify(PLA2->F, PLA1->F, PLA1->D); +} + + + +/* + * Permute the columns of PLA1 so that they match the order of PLA2 + * Discard any columns of PLA1 which are not in PLA2 + * Association is strictly by the names of the columns of the cover. + */ +PLA_permute(PLA1, PLA2) +pPLA PLA1, PLA2; +{ + register int i, j, *permute, npermute; + register char *labi; + char **label; + + /* determine which columns of PLA1 to save, and place these in the list + * "permute"; the order in this list is the final output order + */ + npermute = 0; + permute = ALLOC(int, PLA2->F->sf_size); + for(i = 0; i < PLA2->F->sf_size; i++) { + labi = PLA2->label[i]; + for(j = 0; j < PLA1->F->sf_size; j++) { + if (strcmp(labi, PLA1->label[j]) == 0) { + permute[npermute++] = j; + break; + } + } + } + + /* permute columns */ + if (PLA1->F != NULL) { + PLA1->F = sf_permute(PLA1->F, permute, npermute); + } + if (PLA1->R != NULL) { + PLA1->R = sf_permute(PLA1->R, permute, npermute); + } + if (PLA1->D != NULL) { + PLA1->D = sf_permute(PLA1->D, permute, npermute); + } + + /* permute the labels */ + label = ALLOC(char *, cube.size); + for(i = 0; i < npermute; i++) { + label[i] = PLA1->label[permute[i]]; + } + for(i = npermute; i < cube.size; i++) { + label[i] = NULL; + } + FREE(PLA1->label); + PLA1->label = label; + + FREE(permute); +} + + + +/* + * check_consistency -- test that the ON-set, OFF-set and DC-set form + * a partition of the boolean space. + */ +bool check_consistency(PLA) +pPLA PLA; +{ + bool verify_error = FALSE; + pcover T; + + T = cv_intersect(PLA->F, PLA->D); + if (T->count == 0) + (void) printf("ON-SET and DC-SET are disjoint\n"); + else { + (void) printf("Some minterm(s) belong to both the ON-SET and DC-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + T = cv_intersect(PLA->F, PLA->R); + if (T->count == 0) + (void) printf("ON-SET and OFF-SET are disjoint\n"); + else { + (void) printf("Some minterm(s) belong to both the ON-SET and OFF-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + T = cv_intersect(PLA->D, PLA->R); + if (T->count == 0) + (void) printf("DC-SET and OFF-SET are disjoint\n"); + else { + (void) printf("Some minterm(s) belong to both the OFF-SET and DC-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + if (tautology(cube3list(PLA->F, PLA->D, PLA->R))) + (void) printf("Union of ON-SET, OFF-SET and DC-SET is the universe\n"); + else { + T = complement(cube3list(PLA->F, PLA->D, PLA->R)); + (void) printf("There are minterms left unspecified !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + free_cover(T); + } + (void) fflush(stdout); + return verify_error; +} diff --git a/sis/extract/Makefile.am b/sis/extract/Makefile.am new file mode 100644 index 0000000..542aa28 --- /dev/null +++ b/sis/extract/Makefile.am @@ -0,0 +1,11 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libextract.a +libextract_a_SOURCES = best_subk.c com_ex.c conv.c cube.c cubeindex.c \ + ddivisor.c fast_extract.c gdivisor.c gen_2c_kernel.c genkern.c \ + greedycol.c greedyrow.c heap.c kernel.c misc.c pingpong.c qdivisor.c \ + rect.c sdivisor.c value.c \ + extract_int.h fast_extract_int.h heap.h +pkginclude_HEADERS = extract.h +dist_doc_DATA = extract.doc diff --git a/sis/extract/Makefile.in b/sis/extract/Makefile.in new file mode 100644 index 0000000..f4b6bb2 --- /dev/null +++ b/sis/extract/Makefile.in @@ -0,0 +1,429 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libextract_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/extract +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libextract_a_AR = $(AR) $(ARFLAGS) +libextract_a_LIBADD = +am_libextract_a_OBJECTS = best_subk.$(OBJEXT) com_ex.$(OBJEXT) \ + conv.$(OBJEXT) cube.$(OBJEXT) cubeindex.$(OBJEXT) \ + ddivisor.$(OBJEXT) fast_extract.$(OBJEXT) gdivisor.$(OBJEXT) \ + gen_2c_kernel.$(OBJEXT) genkern.$(OBJEXT) greedycol.$(OBJEXT) \ + greedyrow.$(OBJEXT) heap.$(OBJEXT) kernel.$(OBJEXT) \ + misc.$(OBJEXT) pingpong.$(OBJEXT) qdivisor.$(OBJEXT) \ + rect.$(OBJEXT) sdivisor.$(OBJEXT) value.$(OBJEXT) +libextract_a_OBJECTS = $(am_libextract_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libextract_a_SOURCES) +DIST_SOURCES = $(libextract_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libextract.a +libextract_a_SOURCES = best_subk.c com_ex.c conv.c cube.c cubeindex.c \ + ddivisor.c fast_extract.c gdivisor.c gen_2c_kernel.c genkern.c \ + greedycol.c greedyrow.c heap.c kernel.c misc.c pingpong.c qdivisor.c \ + rect.c sdivisor.c value.c \ + extract_int.h fast_extract_int.h heap.h + +pkginclude_HEADERS = extract.h +dist_doc_DATA = extract.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/extract/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/extract/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libextract.a: $(libextract_a_OBJECTS) $(libextract_a_DEPENDENCIES) + -rm -f libextract.a + $(libextract_a_AR) libextract.a $(libextract_a_OBJECTS) $(libextract_a_LIBADD) + $(RANLIB) libextract.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/extract/best_subk.c b/sis/extract/best_subk.c new file mode 100644 index 0000000..87beb5e --- /dev/null +++ b/sis/extract/best_subk.c @@ -0,0 +1,210 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/best_subk.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + + +typedef struct best_subkernel_struct best_subkernel_state_t; +struct best_subkernel_struct { + rect_t *best_rect; + array_t *row_cost; + array_t *col_cost; + sm_matrix *kernel_cube_matrix; + int first_rect; +}; + +/* + * Helper function to sort through all prime rectangles in the kernel- + * cube matrix and return the rectangle with the best cost, where the cost + * is measured as literals in the SOP form for each function + * + * We compute literals in SOP form by counting the 'value' of each cube + * which would be covered by this kernel. The value reflects the + * number of literals in the cube. Note that some of the values may + * be 0 (indicating they have already been covered by another rectangle). + */ + + +/* ARGSUSED */ +static int +best_subkernel_sop(co_rect, rect, state_p) +sm_matrix *co_rect; +register rect_t *rect; +char *state_p; +{ + register int ks, cks; + register sm_element *p, *p1, *p2; + value_cell_t *value_cell; + best_subkernel_state_t *state; + int ncks; + + /* fetch the state */ + state = (best_subkernel_state_t *) state_p; + + /* ignore empty rectangles */ + if (rect->rows->length == 0 || rect->cols->length == 0) { + rect->value = 0; + return 1; + } + + /* count # literals in the co-kernel cubes */ + cks = 0; + sm_foreach_col_element(rect->rows, p) { + cks += array_fetch(int, state->row_cost, p->row_num) - 1; + } + ncks = rect->rows->length; + + /* count # literals in the kernel cubes */ + ks = 0; + sm_foreach_row_element(rect->cols, p) { + ks += array_fetch(int, state->col_cost, p->col_num); + } + + /* compute the real rectangle value */ + rect->value = 0; + sm_foreach_col_element(rect->rows, p1) { + sm_foreach_row_element(rect->cols, p2) { + p = sm_find(state->kernel_cube_matrix, p1->row_num, p2->col_num); + assert(p != 0 && p->user_word != 0); + value_cell = (value_cell_t *) p->user_word; + rect->value += value_cell->value; + } + } + rect->value -= ks + cks + ncks; + + /* first rectangle becomes the best, otherwise must beat previous */ + if (state->first_rect || rect->value > state->best_rect->value) { + rect_free(state->best_rect); + state->best_rect = rect_dup(rect); + state->first_rect = 0; + } + + return 1; +} + +/* + * find the BEST value rectangle in the kernel-cube matrix by generating + * all prime rectangles and choosing the best + * + * cost function is literals in factored form (approx.) + */ + + +/* ARGSUSED */ +static int +best_subkernel_factor(co_rect, rect, state_p) +sm_matrix *co_rect; +register rect_t *rect; +char *state_p; +{ + register sm_element *p, *p1, *p2; + st_table *fanout; + value_cell_t *value_cell; + best_subkernel_state_t *state; + char *key; + int ks; + + state = (best_subkernel_state_t *) state_p; + + /* ignore empty rectangles */ + if (rect->rows->length == 0 || rect->cols->length == 0) { + rect->value = 0; + return 1; + } + + /* count # literals in the kernel cubes */ + ks = 0; + sm_foreach_row_element(rect->cols, p) { + ks += array_fetch(int, state->col_cost, p->col_num); + } + + /* find all unique functions it feeds */ + fanout = st_init_table(st_numcmp, st_numhash); + sm_foreach_col_element(rect->rows, p1) { + sm_foreach_row_element(rect->cols, p2) { + p = sm_find(state->kernel_cube_matrix, p1->row_num, p2->col_num); + value_cell = (value_cell_t *) p->user_word; + key = (char *) value_cell->sis_index; + (void) st_insert(fanout, key, NIL(char)); + } + } + + rect->value = (st_count(fanout) - 1) * (ks - 1) - 1; + + /* first rectangle becomes the best, otherwise must beat previous */ + if (state->first_rect || rect->value > state->best_rect->value) { + rect_free(state->best_rect); + state->best_rect = rect_dup(rect); + state->first_rect = 0; + } + + st_free_table(fanout); + return 1; +} + +static rect_t * +best_subkernel(kernel_cube_matrix, row_cost, col_cost, func) +sm_matrix *kernel_cube_matrix; +array_t *row_cost, *col_cost; +int (*func)(); +{ + sm_row *prow; + sm_element *p; + rect_t *rect; + best_subkernel_state_t *state; + + state = ALLOC(best_subkernel_state_t, 1); + state->best_rect = rect_alloc(); + state->row_cost = row_cost; + state->col_cost = col_cost; + state->kernel_cube_matrix = kernel_cube_matrix; + state->first_rect = 1; + gen_all_rectangles(kernel_cube_matrix, func, (char *) state); + + /* consider each row as a separate rectangle */ + sm_foreach_row(kernel_cube_matrix, prow) { + rect = rect_alloc(); + (void) sm_col_insert(rect->rows, prow->row_num); + sm_foreach_row_element(prow, p) { + (void) sm_row_insert(rect->cols, p->col_num); + } + (void) (*func)(NIL(sm_matrix), rect, (char *) state); + rect_free(rect); + } + + rect = state->best_rect; + FREE(state); + return rect; +} + +rect_t * +choose_subkernel(A, row_cost, col_cost, option) +sm_matrix *A; +array_t *row_cost, *col_cost; +int option; +{ + rect_t *rect = 0; + + switch (option) { + case 0: + rect = ping_pong(A, row_cost, col_cost); + break; + case 1: + rect = best_subkernel(A, row_cost, col_cost, best_subkernel_sop); + break; + case 2: + rect = best_subkernel(A, row_cost, col_cost, best_subkernel_factor); + break; + default: + fail("bad option in choose_subkernel"); + break; + } + return rect; +} diff --git a/sis/extract/com_ex.c b/sis/extract/com_ex.c new file mode 100644 index 0000000..e3d2c87 --- /dev/null +++ b/sis/extract/com_ex.c @@ -0,0 +1,628 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/com_ex.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" +#include "heap.h" +#include "fast_extract_int.h" + +static int com_fast_extract(); +static st_table *find_required_time(); +static void remove_unwanted_nodes(); + +int ONE_PASS = 0; +int FX_DELETE = 0; +int LENGTH1 = 5; +int LENGTH2 = 5; +int OBJECT_SIZE = 50000; +int DONT_USE_WEIGHT_ZERO = 1; + +static int +com_cube_extract(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + lsGen gen; + sm_matrix *cube_literal_matrix; + int thres, use_best_subcube, c; + node_t *node; + + use_best_subcube = 0; + use_complement = 0; /* global */ + cube_extract_debug = 0; /* global */ + thres = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "bcdft:v:")) != EOF) { + switch(c) { + case 'b': + use_best_subcube = 1; + break; + case 'c': + use_complement = 1; + break; + case 'd': + cube_extract_debug = 1; + break; + case 'f': + use_best_subcube = 2; + break; + case 't': + thres = atoi(util_optarg); + break; + case 'v': + cube_extract_debug = atoi(util_optarg); + break; + default: + goto usage; + } + } + if (argc - util_optind != 0) goto usage; + + ex_setup_globals(*network, 0); + + /* create the cube-literal matrix */ + cube_literal_matrix = sm_alloc(); + foreach_node(*network, gen, node) { + switch(node_function(node)) { + case NODE_PI: + case NODE_PO: + case NODE_0: + case NODE_1: + case NODE_INV: + case NODE_BUF: + break; + + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + ex_node_to_sm(node, cube_literal_matrix); + break; + default: + ; + } + } + + /* extract cubes */ + (void) sparse_cube_extract(cube_literal_matrix, thres, use_best_subcube); + + free_value_cells(cube_literal_matrix); + sm_free(cube_literal_matrix); + ex_free_globals(0); + return 0; + +usage: + (void) fprintf(siserr, + "usage: gcx [-bcdf] [-t thresh]\n"); + (void) fprintf(siserr, + " -b\t\tuses best subcube (rather than pingpong)\n"); + (void) fprintf(siserr, + " -c\t\tuses complement during division\n"); + (void) fprintf(siserr, + " -d\t\tenables debug\n"); + (void) fprintf(siserr, + " -f\t\tuses factored literals for value\n"); + (void) fprintf(siserr, + " -t thres\tset threshold value for extraction\n"); + return 1; +} + +static int +com_kernel_extract(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + sm_matrix *func; + node_t *node; + int use_best_subkernel, use_all_kernels, use_overlap, one_pass; + int need_duplicate, value, thres, c, index; + lsGen gen; + + one_pass = 0; + use_all_kernels = 0; + use_best_subkernel = 0; + use_complement = 0; /* global */ + kernel_extract_debug = 0; /* global */ + use_overlap = 0; + need_duplicate = 0; + thres = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "1abcdfot:v:")) != EOF) { + switch(c) { + case '1': + one_pass = 1; + break; + case 'a': + use_all_kernels = 1; + break; + case 'b': + use_best_subkernel = 1; + break; + case 'c': + use_complement = 1; + break; + case 'd': + kernel_extract_debug = 1; + break; + case 'f': + use_best_subkernel = 2; + break; + case 'o': + use_overlap = 1; + need_duplicate = 1; + break; + case 't': + thres = atoi(util_optarg); + break; + case 'v': + kernel_extract_debug = atoi(util_optarg); + break; + default: + goto usage; + } + } + + if (argc - util_optind != 0) goto usage; + + do { + ex_setup_globals(*network, need_duplicate); + + kernel_extract_init(); + foreach_node(*network, gen, node) { + switch(node_function(node)) { + case NODE_PI: + case NODE_PO: + case NODE_0: + case NODE_1: + case NODE_INV: + case NODE_BUF: + break; + + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + func = sm_alloc(); + ex_node_to_sm(node, func); + index = nodeindex_indexof(global_node_index, node); + kernel_extract(func, index, use_all_kernels); + free_value_cells(func); + sm_free(func); + break; + default: + ; + } + } + + if (use_overlap) { + value = overlapping_kernel_extract(thres, use_best_subkernel); + } else { + value = sparse_kernel_extract(thres, use_best_subkernel); + } + kernel_extract_free(); + + ex_free_globals(need_duplicate); + } while (! one_pass && value > 0); + + return 0; + +usage: + (void) fprintf(siserr, + "usage: gkx [-1abcdfo] [-t thresh]\n"); + (void) fprintf(siserr, + " -1\t\tone pass over network\n"); + (void) fprintf(siserr, + " -a\t\tuse all kernels (rather than level 0)\n"); + (void) fprintf(siserr, + " -b\t\tuse best subkernel (rather than pingpong)\n"); + (void) fprintf(siserr, + " -c\t\tuse complement during division\n"); + (void) fprintf(siserr, + " -d\t\tenables debug\n"); + (void) fprintf(siserr, + " -f\t\tuse factored literals for value\n"); + (void) fprintf(siserr, + " -o\t\tallow overlapping factors\n"); + (void) fprintf(siserr, + " -t n\tset threshold value for extraction\n"); + return 1; +} + +/* ARGSUSED */ +static int +print_kernel(kernel, co_kernel, state) +node_t *kernel; +node_t *co_kernel; +char *state; +{ + (void) fprintf(sisout, "("); + node_print_rhs(sisout, co_kernel); + (void) fprintf(sisout, ") * ("); + node_print_rhs(sisout, kernel); + (void) fprintf(sisout, ")\n"); + node_free(kernel); + node_free(co_kernel); + return 1; +} + + +static int +com_print_kernel(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + node_t *node; + array_t *node_vec; + int c, i, subkernel, subkernel_level; + + subkernel = 0; + subkernel_level = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "as")) != EOF) { + switch(c) { + case 'a': + subkernel_level = 1; + break; + case 's': + subkernel = 1; + break; + default: + goto usage; + } + } + + node_vec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (node->type == PRIMARY_INPUT) continue; + if (node->type == PRIMARY_OUTPUT) continue; + if (subkernel) { + (void) fprintf(sisout, "Subkernels of %s\n", node_name(node)); + ex_subkernel_gen(node, print_kernel, subkernel_level, NIL(char)); + } else { + (void) fprintf(sisout, "Kernels of %s\n", node_name(node)); + ex_kernel_gen(node, print_kernel, NIL(char)); + } + } + array_free(node_vec); + return 0; + +usage: + (void) fprintf(siserr, "usage: print_kernel [-as] n1 n2 ...\n"); + (void) fprintf(siserr, + " -a\t\tgenerate kernels of all levels\n"); + (void) fprintf(siserr, + " -s\t\tgenerate subkernels rather than kernels\n"); + return 1; +} + +static int +com_gdiv(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + node_t *node, *divisor; + array_t *node_vec; + int i; + + node_vec = com_get_nodes(*network, argc, argv); + if (array_n(node_vec) < 1) goto usage; + + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (node->type == PRIMARY_INPUT) continue; + if (node->type == PRIMARY_OUTPUT) continue; + if (strcmp(argv[0], "_gdiv") == 0) { + (void) fprintf(sisout, "good divisor of %s is: ", node_name(node)); + divisor = ex_find_divisor(node, 0, 1); + } else { + (void) fprintf(sisout, "quick divisor of %s is: ", node_name(node)); + divisor = ex_find_divisor_quick(node); + } + if (divisor == 0) { + (void) fprintf(sisout, " (no multiple-cube divisors)\n"); + } else { + node_print_rhs(sisout, divisor); + (void) fprintf(sisout, "\n"); + node_free(divisor); + } + } + array_free(node_vec); + return 0; + +usage: + (void) fprintf(siserr, "usage: %s n1 n2 ...\n", argv[0]); + return 1; +} + +init_extract() +{ + com_add_command("gkx", com_kernel_extract, 1); + com_add_command("gcx", com_cube_extract, 1); + com_add_command("print_kernel", com_print_kernel, 1); + com_add_command("_gdiv", com_gdiv, 0); + com_add_command("_qdiv", com_gdiv, 0); + com_add_command("fx",com_fast_extract , 1); +} + +end_extract() +{ + sm_cleanup(); +} + + + +static int com_fast_extract(network,argc,argv) +network_t **network; +int argc; +char **argv; +{ + sm_matrix *cube_literal_matrix; + ddset_t *ddivisor_set; + node_t *node; + array_t *node_set; + int i, c, row, index, objnum, cubenum, loop, iterate; + int PRESERVE_LEVEL = 0; + lsGen gen; + sm_row *prow; + st_table *level_table, *required_table; + int max_level, po_level; + char *dummy; + node_t *po; + extern st_table *find_node_level(); + + /* Global variables should never have been used! Must initialize + them for extract. */ + ONE_PASS = 0; + FX_DELETE = 0; + LENGTH1 = 5; + LENGTH2 = 5; + OBJECT_SIZE = 50000; + DONT_USE_WEIGHT_ZERO = 1; + util_getopt_reset(); + while ((c = util_getopt(argc,argv,"b:f:s:lo:z")) != EOF) { + switch(c) { + case 'o' : + ONE_PASS = 1; + break; + case 'l' : + PRESERVE_LEVEL = 1; + break; + case 'b' : + ONE_PASS = FX_DELETE = 1; + OBJECT_SIZE = atoi(util_optarg); + break; + case 'f' : + if (FX_DELETE == 0) break; + LENGTH1 = atoi(util_optarg); + break; + case 's' : + if (FX_DELETE == 0) break; + LENGTH2 = atoi(util_optarg); + break; + case 'z' : + DONT_USE_WEIGHT_ZERO = 0; + break; + default : + goto usage; + } + } + + if (argc - util_optind != 0) goto usage; + + loop = 0; + iterate = 1; + do { + row = 0; iterate--; + if (PRESERVE_LEVEL){ + level_table= find_node_level(*network); + max_level = 0; + foreach_primary_output (*network, gen, po) { + assert(st_lookup(level_table, (char *) po, &dummy)); + po_level = (int) dummy; + if (max_level < po_level) + max_level = po_level; + } + required_table = find_required_time(*network, max_level); + } + + cube_literal_matrix = sm_alloc(); + ddivisor_set = ddset_alloc_init(); + + /* global setting the node index in the network */ + ex_setup_globals(*network, 0); + + objnum = 0; + node_set = array_alloc(node_t *, 0); + foreach_node(*network, gen, node) { + switch(node_function(node)) { + case NODE_PI: + case NODE_PO: + case NODE_0: + case NODE_1: + case NODE_INV: + case NODE_BUF: + break; + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + (void) array_insert_last(node_t *, node_set, node); + cubenum = node_num_cube(node); + objnum += ((cubenum - 1) * cubenum) / 2; + break; + default: + ; + } + } + + FX_DELETE = (objnum >= OBJECT_SIZE) ? 1 : 0; + if (FX_DELETE == 1) { + ONE_PASS = 1; + if (loop == 0) { + loop = 1; iterate = 5; + } + } else { + if (iterate > 0) ONE_PASS = 0; + } + for (i = 0; i < array_n(node_set); i++) { + node = array_fetch(node_t *, node_set, i); + fx_node_to_sm(node, cube_literal_matrix); + index = nodeindex_indexof(global_node_index, node); + extract_ddivisor(cube_literal_matrix,index,row,ddivisor_set); + row = cube_literal_matrix->nrows; + } + (void) array_free(node_set); + + /* greeedy concurrent algorithm for finding best double cube divisor or + * single cube divisor. + */ + fast_extract(cube_literal_matrix,ddivisor_set); + if (PRESERVE_LEVEL){ + remove_unwanted_nodes(*network, level_table, required_table); + st_free_table(level_table); + st_free_table(required_table); + } + network_sweep(*network); + + ddset_free(ddivisor_set); + sm_foreach_row(cube_literal_matrix, prow) { + (void) sm_cube_free((sm_cube_t *) prow->user_word); + } + (void) sm_free(cube_literal_matrix); + ex_free_globals(0); + if (iterate > 0) { + (void) eliminate(*network, 0, 1000); + (void) eliminate(*network, 5, 1000); + } + } while ((loop == 1) && (iterate > 0)); + + return 0; + +usage: + (void) fprintf(siserr, "usage: fx [-o] [-b limit] [-l] [-z]\n"); + (void) fprintf(siserr, " -o\t\t fast 0-level 2-cube kernel extraction\n"); + (void) fprintf(siserr, " \t\t default is complete kernel extraction\n"); + (void) fprintf(siserr, " -b\t\t upper bound for the number of divisors, default is 50000 \n"); + (void) fprintf(siserr, + " -l\t\t preserves the level of each node, used for timing optimization\n"); + (void) fprintf(siserr, " -z\t\t extract zero-weight factors also\n"); + return 1; +} + +static st_table *find_required_time(network, max_level) +network_t *network; +int max_level; +{ + st_table *node_required_table; + array_t *nodevec; + lsGen gen; + int i; + node_t *np, *fanout; + int level, tmp; + char *dummy; + + node_required_table = st_init_table(st_ptrcmp, st_ptrhash); + nodevec = network_dfs_from_input(network); + for(i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + if (node_function(np) == NODE_PI) + continue; + level = max_level; + if (node_function(np) == NODE_PO){ + st_insert(node_required_table, (char *) np, (char *) level); + continue; + } + foreach_fanout(np, gen, fanout){ + assert(st_lookup(node_required_table, (char *) fanout, &dummy)); + tmp= (int) dummy; + if (level > tmp) + level = tmp; + } + level--; + assert(level >= 0); + st_insert(node_required_table, (char *) np, (char *) level); + } + array_free(nodevec); + return(node_required_table); +} + +/* After extraction remove all the new nodes which cause the level some output go + * beyond the max_level orginally computed for the network. We have already assigned + * an allowed level to each node in the network. The new level can not be greater + * than the allowed level. + */ +static void remove_unwanted_nodes(network, level_table, required_table) +network_t *network; +st_table *level_table; +st_table *required_table; +{ + array_t *nodevec; + node_t *np, *fanin; + int tmp; + char *dummy; + int current_level, allowed_level; + int i, l; + int numin; + + nodevec = network_dfs(network); + for(i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + if (node_function(np) == NODE_PI) + continue; + current_level = 0; + foreach_fanin(np, l, fanin){ + if (node_function(fanin) == NODE_PI){ + tmp = 0; + }else{ + assert(st_lookup(level_table, (char *) fanin, &dummy)); + tmp= (int) dummy; + } + if (current_level < tmp) + current_level = tmp; + } + current_level++; + if(st_lookup(required_table, (char *) np, &dummy)){ + allowed_level = (int) dummy; + for (;current_level > allowed_level;){ +/*collapse nodes in np whose level is above what is allowed */ + numin = node_num_fanin(np); + for(l=0; l< numin; l++){ + fanin= node_get_fanin(np, l); + if (node_function(fanin) == NODE_PI) + continue; + assert(st_lookup(level_table, (char *) fanin, &dummy)); + tmp= (int) dummy; + if (tmp > (allowed_level - 1)){ + node_collapse(np, fanin); + assert(!st_lookup(required_table, (char *) fanin, &dummy)); + numin = node_num_fanin(np); + } + } +/* update current level again.*/ + current_level = 0; + foreach_fanin(np, l, fanin){ + if (node_function(fanin) == NODE_PI){ + tmp = 0; + }else{ + assert(st_lookup(level_table, (char *) fanin, &dummy)); + tmp= (int) dummy; + } + if (current_level < tmp) + current_level = tmp; + } + current_level++; + } + } + st_insert(level_table, (char *) np, (char *) current_level); + } + array_free(nodevec); +} diff --git a/sis/extract/conv.c b/sis/extract/conv.c new file mode 100644 index 0000000..c4445ba --- /dev/null +++ b/sis/extract/conv.c @@ -0,0 +1,352 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/conv.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + +network_t *global_network; +nodeindex_t *global_node_index; +array_t *global_old_fct; +int use_complement; + + +/* + * Mapping between the sparse matrix and the nodes in the matrix. + * Currently this is done with a set of variables global to the extract + * package: + * + * global_network -- the network being operated on + * global_node_index -- mappnig between column numbers and nodes + * global_old_fct -- duplicates of the original nodes, indexed by above + */ + +void +ex_setup_globals(network, dup_fcts) +network_t *network; +int dup_fcts; /* if 1, also save the original functions */ +{ + int index; + node_t *node, *node1; + lsGen gen; + + global_network = network; + global_node_index = nodeindex_alloc(); + if (dup_fcts) { + global_old_fct = array_alloc(node_t *, 0); + } else { + global_old_fct = 0; + } + + foreach_node(network, gen, node) { + if (node->type != PRIMARY_OUTPUT) { + index = nodeindex_insert(global_node_index, node); + if (dup_fcts) { + node1 = node_dup(node); + array_insert(node_t *, global_old_fct, index, node1); + } + } + } +} + +void +ex_setup_globals_single(node) +node_t *node; +{ + int i; + node_t *fanin; + + global_network = NIL(network_t); + global_node_index = nodeindex_alloc(); + foreach_fanin(node, i, fanin) { + (void) nodeindex_insert(global_node_index, fanin); + } + (void) nodeindex_insert(global_node_index, node); + global_old_fct = NIL(array_t); +} + +void +ex_free_globals(dup_fcts) +int dup_fcts; +{ + int i; + node_t *node1; + + if (dup_fcts) { + for(i = 0; i < array_n(global_old_fct); i++) { + node1 = array_fetch(node_t *, global_old_fct, i); + node_free(node1); + } + array_free(global_old_fct); + } + nodeindex_free(global_node_index); +} + + +char * +ex_map_index_to_name(i) +int i; +{ + return node_name(nodeindex_nodeof(global_node_index, i)); +} + +/* + * convert a network node into a sparse matrix representation of its + * logic function. + */ + +void +ex_node_to_sm(node, M) +register node_t *node; +register sm_matrix *M; +{ + register pset last, p; + register int i, row; + int *fanin_index; + node_t *fanin; + sm_element *pelement; + value_cell_t *value_cell; + + foreach_set(node->F, last, p) { + row = M->nrows; + + fanin_index = ALLOC(int, node->nin); + foreach_fanin(node, i, fanin) { + fanin_index[i] = 2 * nodeindex_indexof(global_node_index, fanin); + assert(fanin_index[i] >= 0); + } + + foreach_fanin(node, i, fanin) { + switch (GETINPUT(p, i)) { + case ZERO: + pelement = sm_insert(M, row, fanin_index[i] + 1); + break; + case ONE: + pelement = sm_insert(M, row, fanin_index[i]); + break; + case TWO: + pelement = NIL(sm_element); + break; + } + + if (pelement != NIL(sm_element)) { + value_cell = value_cell_alloc(); + value_cell->sis_index = + nodeindex_indexof(global_node_index, node); + assert(value_cell->sis_index >= 0); + value_cell->cube_number = pelement->row_num; + value_cell->value = 1; + pelement->user_word = (char *) value_cell; + } + } + + FREE(fanin_index); + } +} + +sm_matrix * +ex_network_to_sm(network) +network_t *network; +{ + node_t *node; + sm_matrix *M; + lsGen gen; + + /* Convert the network into one sparse matrix */ + M = sm_alloc(); + foreach_node(network, gen, node) { + if (node->type == INTERNAL) { + ex_node_to_sm(node, M); + } + } + return M; +} + +/* + * map a sparse-matrix representation of a function back into a 'node' + */ + +node_t * +ex_sm_to_node(func) +sm_matrix *func; +{ + int i, nin; + node_t *node, *fanin_node, **fanin; + pset setp, fullset; + pset_family F; + sm_col *pcol; + sm_row *prow; + sm_element *p; + + /* + * Determine the fanin points; + * set pcol->flag to be the column number in the set family + */ + node = node_alloc(); + nin = 0; + fanin = ALLOC(node_t *, 2*func->ncols); /* worst case */ + sm_foreach_col(func, pcol) { + fanin_node = nodeindex_nodeof(global_node_index, pcol->col_num / 2); + if ((pcol->col_num % 2) == 0) { + pcol->flag = 2 * nin; + fanin[nin++] = fanin_node; + } else { + if (nin == 0 || fanin[nin-1] != fanin_node) { + pcol->flag = 2 * nin + 1; + fanin[nin++] = fanin_node; + } else { + pcol->flag = 2 * (nin-1) + 1; + } + } + } + + /* Create the set family */ + F = sf_new(func->nrows, nin * 2); + fullset = set_full(nin * 2); + sm_foreach_row(func, prow) { + setp = GETSET(F, F->count++); + (void) set_clear(setp, nin * 2); + sm_foreach_row_element(prow, p) { + i = sm_get_col(func, p->col_num)->flag; + set_insert(setp, i); + } + (void) set_diff(setp, fullset, setp); + } + set_free(fullset); + + node_replace_internal(node, fanin, nin, F); + return node; /* node already minimum base */ +} + +static int +ex_divide_each_fanout(fanout, cubes, newnode, debug) +array_t *fanout; +array_t *cubes; +node_t *newnode; +{ + int i, changed, count, fanout_index; + pset_family old_F, dups; + node_t *node, *old_fct, *t1; + sm_row *dup_cubes; + sm_element *p; + + if (debug > 1) { + (void) fprintf(sisout, "\nnew factor is"); + node_print(sisout, newnode); + } + + count = 0; + for(i = 0; i < array_n(fanout); i++) { + fanout_index = array_fetch(int, fanout, i); + node = nodeindex_nodeof(global_node_index, fanout_index); + assert(node != 0); + + if (debug > 1) { + (void) fprintf(sisout, "fanout #%d is %s\n", i, node_name(node)); + (void) fprintf(sisout, "literals = %d\n", node_num_literal(node)); + if (debug > 2) { + node_print(sisout, node); + } + } + + if (cubes != NIL(array_t)) { + /* duplicate some cubes from the original function */ + dup_cubes = array_fetch(sm_row *, cubes, i); + if (dup_cubes->length > 0) { + + if (debug > 1) { + (void) fprintf(sisout, "covers cubes "); + sm_row_print(sisout, dup_cubes); + (void) fprintf(sisout, "\n"); + } + + old_fct = array_fetch(node_t *, global_old_fct, fanout_index); + dups = sf_new(10, old_fct->nin * 2); + sm_foreach_row_element(dup_cubes, p) { + dups = sf_addset(dups, GETSET(old_fct->F, p->col_num)); + } + + old_F = old_fct->F; + old_fct->F = dups; + + if (debug > 1) { + (void) fprintf(sisout, "duplicating these cubes ...\n"); + node_print(sisout, old_fct); + } + + t1 = node_or(node, old_fct); + node_replace(node, t1); + sf_free(dups); + old_fct->F = old_F; + + if (debug > 2) { + (void) fprintf(sisout, "after adding redundant cubes\n"); + node_print(sisout, node); + } + } + } + + changed = node_substitute(node, newnode, use_complement); + count += changed; + + if (debug > 1) { + if (! changed) { + (void) fprintf(sisout, "***** DID NOT DIVIDE *****\n"); + } + if (debug > 2) { + (void) fprintf(sisout, "After weak division\n"); + node_print(sisout, node); + (void) fprintf(sisout, "literals = %d\n", node_num_literal(node)); + } + } + } + return count; +} + +/* + * insert sparse matrix function into the network + * + * fanout is an array giving the indices of the nodes which this + * function is expected to divide; + * cubes actually gives the cubes of the function that are expected + * to be covered by the division + */ + +int +ex_divide_function_into_network(func, fanout, cubes, debug) +sm_matrix *func; +array_t *fanout; +array_t *cubes; +int debug; +{ + node_t *node; + int index, count; + + /* convert the sparse matrix into a network node */ + node = ex_sm_to_node(func); + + /* perform the division into each node it divides */ + count = ex_divide_each_fanout(fanout, cubes, node, debug); + + /* for now, lets give warning if it divides less than we thought */ + if (debug && (count != array_n(fanout))) { + (void) fprintf(sisout, + "warning: divided only %d of %d\n", count, array_n(fanout)); + } + + if (count > 0) { + network_add_node(global_network, node); + index = nodeindex_insert(global_node_index, node); + } else { + node_free(node); + index = -1; + } + + /* BUG ! overlapping retangles may need a original_func for this guy ? */ + return index; +} diff --git a/sis/extract/cube.c b/sis/extract/cube.c new file mode 100644 index 0000000..53e7c89 --- /dev/null +++ b/sis/extract/cube.c @@ -0,0 +1,326 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/cube.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + + +static void clear_rect(); +static void update_cube_literal_matrix(); +static rect_t *choose_subcube(); + +static rect_t *best_rect; +static sm_matrix *cube_literal_matrix; + +#define SOP_VALUE(x, y) (((x) - 1) * ((y) - 1) - 1) + + + +int +sparse_cube_extract(A, value_threshold, use_best_subcube) +sm_matrix *A; +int value_threshold; +int use_best_subcube; +{ + sm_row *prow; + sm_col *pcol; + rect_t *rect; + array_t *row_cost, *col_cost; + int total_value; + + /* cost for each row is 1 */ + row_cost = array_alloc(int, 0); + sm_foreach_row(A, prow) { + array_insert(int, row_cost, prow->row_num, 1); + } + + /* cost for each column is 1 */ + col_cost = array_alloc(int, 0); + sm_foreach_col(A, pcol) { + array_insert(int, col_cost, pcol->col_num, 1); + } + + if (cube_extract_debug) { + (void) fprintf(sisout, + "cube_extract: cube literal matrix is %d by %d cols, %d literals\n", + A->nrows, A->ncols, sm_num_elements(A)); + } + + total_value = 0; + do { + rect = choose_subcube(A, row_cost, col_cost, use_best_subcube); + if (rect->rows->length < 2 || rect->cols->length < 2 + || rect->value <= value_threshold) { + rect_free(rect); + break; + } + + update_cube_literal_matrix(A, row_cost, col_cost, rect); + clear_rect(A, rect); + total_value += rect->value; + + if (cube_extract_debug) { + (void) fprintf(sisout, + "%d by %d value=%d literals=%d\n", + rect->rows->length, rect->cols->length, rect->value, + sm_num_elements(A)); + } + + rect_free(rect); + } while (A->nrows > 0); + + array_free(row_cost); + array_free(col_cost); + return total_value; +} + +static void +update_cube_literal_matrix(A, row_cost, col_cost, rect) +sm_matrix *A; +array_t *row_cost, *col_cost; +rect_t *rect; +{ + sm_element *p, *p1, *p2; + sm_matrix *func; + array_t *fanout; + int new_colnum, new_rownum, new_index; + value_cell_t *value_cell, *old_value_cell; + + /* Insert the new cube into the network and divide it out */ + func = sm_alloc(); + sm_copy_row(func, 0, rect->cols); + fanout = find_rectangle_fanout(A, rect); + new_index = ex_divide_function_into_network(func, fanout, + NIL(array_t), cube_extract_debug); + array_free(fanout); + sm_free(func); + + /* add a new column */ + new_colnum = new_index * 2; /* assume positive phase ? */ + array_insert(int, col_cost, new_colnum, 1); + sm_foreach_col_element(rect->rows, p) { + p2 = sm_get_row(A, p->row_num)->first_col; + old_value_cell = (value_cell_t *) p2->user_word; + p1 = sm_insert(A, p->row_num, new_colnum); + value_cell = value_cell_alloc(); + value_cell->value = 1; + value_cell->sis_index = old_value_cell->sis_index; + value_cell->cube_number = old_value_cell->cube_number; + p1->user_word = (char *) value_cell; + } + + /* add a new row */ + new_rownum = A->last_row->row_num + 1; + array_insert(int, row_cost, new_rownum, 1); + sm_foreach_row_element(rect->cols, p) { + p1 = sm_insert(A, new_rownum, p->col_num); + value_cell = value_cell_alloc(); + value_cell->value = 1; + value_cell->sis_index = new_index; + value_cell->cube_number = 0; + p1->user_word = (char *) value_cell; + } +} + +#if 0 +static int +int_cmp(x, y) +char **x, **y; +{ + int ix = *(int *) x, iy = *(int *) y; + return iy - ix; +} + + +static int +bound_rect_size_fancy(co_rect, rect) +sm_matrix *co_rect; +rect_t *rect; +{ + register int i, n, *col_length, *row_length; + int bound, nbound, new_rows, new_cols; + sm_row *prow; + sm_col *pcol; + + bound = 0; + if (co_rect->nrows > 0) { + + /* get the row cardinalities and sort them */ + row_length = ALLOC(int, co_rect->nrows); + n = 0; + sm_foreach_row(co_rect, prow) { + row_length[n++] = prow->length; + } + qsort((char *) row_length, co_rect->nrows, sizeof(int), int_cmp); + + /* get the column cardinalities and sort them */ + col_length = ALLOC(int, co_rect->ncols); + n = 0; + sm_foreach_col(co_rect, pcol) { + col_length[n++] = pcol->length; + } + qsort((char *) col_length, co_rect->ncols, sizeof(int), int_cmp); + + for(i = 0; i < co_rect->ncols; i++) { + /* check the array reference -- should not fail */ + assert(col_length[i] <= co_rect->nrows); + + new_rows = col_length[i]; + new_cols = row_length[col_length[i]-1] + rect->cols->length; + nbound = SOP_VALUE(new_rows, new_cols); + if (nbound > bound) bound = nbound; + } + + FREE(row_length); + FREE(col_length); + } + return bound; +} +#endif + +static int +bound_rect_size_simple(co_rect, rect) +sm_matrix *co_rect; +rect_t *rect; +{ + sm_row *prow; + sm_col *pcol; + int bound; + + /* compute a bound for remaining part */ + if (co_rect->nrows > 0) { + prow = sm_longest_row(co_rect); + pcol = sm_longest_col(co_rect); + bound = SOP_VALUE(rect->cols->length + prow->length, pcol->length); + } else { + bound = 0; + } + + return bound; +} + + +/* ARGSUSED */ +static int +best_subcube_helper(co_rect, rect, state) +sm_matrix *co_rect; +rect_t *rect; +char *state; +{ + int bound; + + rect->value = SOP_VALUE(rect->rows->length, rect->cols->length); + if (best_rect->rows->length == 0 || rect->value > best_rect->value) { + rect_free(best_rect); + best_rect = rect_dup(rect); + } + bound = bound_rect_size_simple(co_rect, rect); + return bound > best_rect->value; +} + + +static rect_t * +best_subcube(A) +sm_matrix *A; +{ + best_rect = rect_alloc(); + gen_all_rectangles(A, best_subcube_helper, NIL(char)); + return best_rect; +} + +/* ARGSUSED */ +static int +best_subcube_factored_helper(co_rect, rect, state) +sm_matrix *co_rect; +rect_t *rect; +char *state; +{ + sm_element *p1; + sm_row *prow; + value_cell_t *value_cell; + char *key; + st_table *func_table; + + /* Find which functions are contained by the rectangle */ + func_table = st_init_table(st_numcmp, st_numhash); + sm_foreach_col_element(rect->rows, p1) { + + /* the first element in the row identifies the row's function */ + prow = sm_get_row(cube_literal_matrix, p1->row_num); + value_cell = (value_cell_t *) prow->first_col->user_word; + key = (char *) value_cell->sis_index; + (void) st_insert(func_table, key, NIL(char)); + } + + rect->value = (rect->cols->length - 1)*(st_count(func_table) - 1) - 1; + st_free_table(func_table); + + if (best_rect->rows->length == 0 || rect->value > best_rect->value) { + rect_free(best_rect); + best_rect = rect_dup(rect); + } + + return 1; +} + + +static rect_t * +best_subcube_factored(A) +sm_matrix *A; +{ + cube_literal_matrix = A; + best_rect = rect_alloc(); + gen_all_rectangles(A, best_subcube_factored_helper, NIL(char)); + return best_rect; +} + +static rect_t * +choose_subcube(A, row_cost, col_cost, option) +sm_matrix *A; +array_t *row_cost, *col_cost; +int option; +{ + rect_t *rect; + + switch(option) { + case 0: + rect = ping_pong(A, row_cost, col_cost); + break; + + case 1: + rect = best_subcube(A); + break; + + case 2: + rect = best_subcube_factored(A); + break; + + default: + fail("bad option in choose_subcube"); + break; + } + + return rect; +} + +static void +clear_rect(A, rect) +sm_matrix *A; +rect_t *rect; +{ + register sm_element *p1, *p2, *p; + + sm_foreach_col_element(rect->rows, p1) { + sm_foreach_row_element(rect->cols, p2) { + p = sm_find(A, p1->row_num, p2->col_num); + value_cell_free((value_cell_t *) p->user_word); + sm_remove_element(A, p); + } + } +} diff --git a/sis/extract/cubeindex.c b/sis/extract/cubeindex.c new file mode 100644 index 0000000..0116b36 --- /dev/null +++ b/sis/extract/cubeindex.c @@ -0,0 +1,78 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/cubeindex.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + + +/* + * cubeindex functions -- hash table of cubes <-> integers + */ + + +cubeindex_t * +cubeindex_alloc() +{ + cubeindex_t *table; + + table = ALLOC(cubeindex_t, 1); + table->cube_to_integer = st_init_table(sm_row_compare, sm_row_hash); + table->integer_to_cube = array_alloc(sm_row *, 0); + return table; +} + + +void +cubeindex_free(table) +cubeindex_t *table; +{ + st_generator *gen; + char *key; + + gen = st_init_gen(table->cube_to_integer); + while (st_gen(gen, &key, NIL(char *))) { + sm_row_free((sm_row *) key); + } + st_free_gen(gen); + + st_free_table(table->cube_to_integer); + array_free(table->integer_to_cube); + FREE(table); +} + + +int +cubeindex_getindex(table, cube) +cubeindex_t *table; +sm_row *cube; +{ + int index; + char *value; + sm_row *cube_save; + + if (st_lookup(table->cube_to_integer, (char *) cube, &value)) { + index = (int) value; + } else { + index = st_count(table->cube_to_integer); + cube_save = sm_row_dup(cube); + (void) st_insert(table->cube_to_integer, + (char *) cube_save, (char *) index); + array_insert(sm_row *, table->integer_to_cube, index, cube_save); + } + return index; +} + + +sm_row * +cubeindex_getcube(table, index) +cubeindex_t *table; +int index; +{ + return array_fetch(sm_row *, table->integer_to_cube, index); +} diff --git a/sis/extract/ddivisor.c b/sis/extract/ddivisor.c new file mode 100644 index 0000000..a187f68 --- /dev/null +++ b/sis/extract/ddivisor.c @@ -0,0 +1,673 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/ddivisor.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" +#include "heap.h" +#include "fast_extract_int.h" + + +/* Memory allocation and free for ddivisor_t */ + +ddivisor_t * +ddivisor_alloc() +{ + register ddivisor_t *ddivisor; + + ddivisor = ALLOC(ddivisor_t, 1); + + ddivisor->cube1 = ddivisor->cube2 = NIL(sm_row); + DTYPE(ddivisor) = Dother; + ddivisor->weight_status = NEW; + WEIGHT(ddivisor) = ddivisor->level = 0; + STATUS(ddivisor) = NONCHECK; + ddivisor->handle = ddivisor->sthandle = ddivisor->div_index = NULL; + + return ddivisor; +} + +void +ddivisor_free(ddivisor) +register ddivisor_t *ddivisor; +{ + if (ddivisor->div_index) { + lsDestroy(ddivisor->div_index, 0); + } + if (ddivisor->cube1) { + (void) sm_row_free(ddivisor->cube1); + (void) sm_row_free(ddivisor->cube2); + } + FREE(ddivisor); +} + +/* Memory allocation and free for ddivisor_cell_t */ + +ddivisor_cell_t * +ddivisor_cell_alloc() +{ + register ddivisor_cell_t *ddivisor_cell; + + ddivisor_cell = ALLOC(ddivisor_cell_t, 1); + + ddivisor_cell->cube1 = ddivisor_cell->cube2 = NIL(sm_row); + ddivisor_cell->handle1 = ddivisor_cell->handle2 = NULL; + ddivisor_cell->baselength = 0; + DIVISOR(ddivisor_cell) = NIL(ddivisor_t); + ddivisor_cell->handle = NULL; + ddivisor_cell->phase = 0; + ddivisor_cell->sis_id = -1; + + return ddivisor_cell; +} + +void +ddivisor_cell_free(ddivisor_cell) +ddivisor_cell_t *ddivisor_cell; +{ + FREE(ddivisor_cell); +} + +/* Memory allocation and initialization for ddset_t */ + +ddset_t * +ddset_alloc_init() +{ + + register ddset_t *ddivisor_set; + + ddivisor_set = ALLOC(ddset_t , 1); + + ddivisor_set->DDset = lsCreate(); + ddivisor_set->node_cube_set = sm_row_alloc(); + ddivisor_set->D112_set = sm_alloc(); + ddivisor_set->D222_set = sm_alloc(); + ddivisor_set->D223_set = sm_alloc(); + ddivisor_set->D224_set = sm_alloc(); + ddivisor_set->Dother_set = sm_alloc(); + + return ddivisor_set; +} + +static void +table_cleanup(table) +sm_matrix *table; +{ + register sm_row *row; + register sm_element *p; + + sm_foreach_row(table, row) { + sm_foreach_row_element(row, p) { + lsDestroy((lsList) p->user_word, 0); + } + } + (void) sm_free(table); +} + + +/* Do cleanup after every substitution. */ +static void +ddset_cleanup(ddivisor_set) +ddset_t *ddivisor_set; +{ + register sm_element *p; + register sm_row *row; + + (void) table_cleanup(ddivisor_set->D112_set); + (void) table_cleanup(ddivisor_set->D222_set); + (void) table_cleanup(ddivisor_set->D223_set); + (void) table_cleanup(ddivisor_set->D224_set); + sm_foreach_row(ddivisor_set->Dother_set, row) { + sm_foreach_row_element(row, p) { + (void) table_cleanup((sm_matrix *) p->user_word); + } + } + (void) sm_free(ddivisor_set->Dother_set); +} + +void +ddset_free(ddivisor_set) +ddset_t *ddivisor_set; +{ + lsGen gen1, gen2; + ddivisor_t *divisor; + ddivisor_cell_t *dd_cell; + register sm_element *p; + + lsForeachItem(ddivisor_set->DDset, gen1, divisor) { + lsForeachItem(divisor->div_index, gen2, dd_cell) { + (void) ddivisor_cell_free(dd_cell); + } + (void) ddivisor_free(divisor); + } + lsDestroy(ddivisor_set->DDset, 0); + sm_foreach_row_element(ddivisor_set->node_cube_set, p) { + lsDestroy((lsList) p->user_word, 0); + } + (void) sm_row_free(ddivisor_set->node_cube_set); + (void) ddset_cleanup(ddivisor_set); + FREE(ddivisor_set); +} + + +/* Memeory alloaction for sm_cube_t */ +sm_cube_t * +sm_cube_alloc() +{ + register sm_cube_t *sm_cube; + + sm_cube = ALLOC(sm_cube_t, 1); + sm_cube->div_set = lsCreate(); + sm_cube->cubehandle = NULL; + sm_cube->sis_id = -1; + + return sm_cube; +} + +void +sm_cube_free(sm_cube) +register sm_cube_t *sm_cube; +{ + lsDestroy(sm_cube->div_set,0); + FREE(sm_cube); +} + + +/* Do operation {c1} \ {c2} */ +void +clear_row_element(c1,c2) +register sm_row *c1, *c2; +{ + register sm_element *p; + + sm_foreach_row_element(c2,p){ + (void) sm_row_remove(c1,p->col_num); + } +} + + +/* Generate double-cube divisor and store info. in corresponding dd_cell. */ + +ddivisor_t * +gen_ddivisor(cube1,cube2,dd_cell) +sm_row *cube1, *cube2; +ddivisor_cell_t *dd_cell; +{ + sm_row *base; + register ddivisor_t *divisor; + + divisor = ddivisor_alloc(); + base = sm_row_and(cube1,cube2); + divisor->cube1 = sm_row_dup(cube1); + divisor->cube2 = sm_row_dup(cube2); + + /* If there is intersection between cube1 and cube2 */ + + dd_cell->baselength = base->length; + if (base->length > 0) { + (void) clear_row_element(divisor->cube1,base); + (void) clear_row_element(divisor->cube2,base); + } + dd_cell->cube1 = cube1; + dd_cell->cube2 = cube2; + (void) sm_row_free(base); + + return divisor; +} + +/* Count the number of variables in D222 or D223. */ +static int +variable_count(divisor) +ddivisor_t *divisor; +{ + int count = 4; + int i,j,t1[2],t2[2]; + + t1[0] = (divisor->cube1->first_col->col_num)/2; + t1[1] = (divisor->cube1->last_col->col_num)/2; + t2[0] = (divisor->cube2->first_col->col_num)/2; + t2[1] = (divisor->cube2->last_col->col_num)/2; + for (i=0; i < 2; i++) { + for (j=0; j < 2; j++) { + if (t1[i] == t2[j]) { + count--; + break; + } + } + } + return count; +} + + +/* Decide the type of divisor and set (key1, key2) */ +int +decide_dtype(div) +register ddivisor_t *div; +{ + sm_row *temp; + + if ((div->cube1->length == 1) && (div->cube2->length == 1)) { + if (div->cube1->first_col->col_num > div->cube2->first_col->col_num){ + temp = div->cube1; + div->cube1 = div->cube2; + div->cube2 = temp; + } + return D112; + } + if ((div->cube1->length == 2) && (div->cube2->length == 2)) { + if (div->cube1->first_col->col_num > div->cube2->first_col->col_num){ + temp = div->cube1; + div->cube1 = div->cube2; + div->cube2 = temp; + } + switch(variable_count(div)) { + case 2 : + return D222; + case 3 : + return D223; + case 4 : + return D224; + default: + ; + } + } + if (div->cube1->length == div->cube2->length) { + if (div->cube1->first_col->col_num > div->cube2->first_col->col_num){ + temp = div->cube1; + div->cube1 = div->cube2; + div->cube2 = temp; + } + } + return Dother; +} + +/* Dother type divisor check */ +static int +check_Dother(div1, div2) +ddivisor_t *div1, *div2; +{ + if (div1->cube2->first_col->col_num != div2->cube2->first_col->col_num) { + return 0; + } + if (sm_row_compare(div1->cube1,div2->cube1) == 0) { + if (sm_row_compare(div1->cube2,div2->cube2) == 0){ + return 1; + } else { + return 0; + } + } + return 0; +} + +static int +check_D222(div1,div2,phase) +ddivisor_t *div1, *div2; +int *phase; +{ + if ((div1->cube1->first_col->col_num == div2->cube1->first_col->col_num) && + (div1->cube1->last_col->col_num == div2->cube1->last_col->col_num)){ + *phase = 0; + } else { + *phase = 1; + } + return 1; +} + + +/* D223 divisor check */ + +static int +check_D223(div1,div2,phase) +ddivisor_t *div1, *div2; +int *phase; +{ + int con1, con2, con3, con4, col; + sm_row *cube1 = div1->cube1; + sm_row *cube2 = div1->cube2; + sm_row *cube3 = div2->cube1; + sm_row *cube4 = div2->cube2; + + con1 = cube1->first_col->col_num == cube3->first_col->col_num; + con2 = cube1->last_col->col_num == cube3->last_col->col_num; + + *phase = 0; + switch(con1+con2) { + case 2 : + if (sm_row_compare(cube2, cube4) == 0) { + return 1; + } else { + return 0; + } + case 1 : + if ((cube2->first_col->col_num/2 != cube4->first_col->col_num/2) || + (cube2->last_col->col_num/2 != cube4->last_col->col_num/2)) { + return 0; + } + col = (con1==1) ? cube1->first_col->col_num : cube1->last_col->col_num; + ((col % 2) == 0) ? col++ : col--; + if (sm_row_find(cube4, col) == 0) { + return 0; + } + con3 = abs(cube2->first_col->col_num - cube4->first_col->col_num); + con4 = abs(cube2->last_col->col_num - cube4->last_col->col_num); + if ((con3+con4) == 1) { + *phase = 1; + return 1; + } + return 0; + case 0 : + return 0; + default: + ; + } +} + + +/* Check if the div1 and div2 are equal, if div1, div2 are belong to + * one of D222 or D223, then check the complement too. + */ +int +check_exist(div1,div2,phase) +ddivisor_t *div1, *div2; +int *phase; +{ + + *phase = 0; + + switch(DTYPE(div1)) { + case D112 : + return 1; + case D222 : + return check_D222(div1, div2, phase); + case D223 : + return check_D223(div1,div2, phase); + default : + return check_Dother(div1, div2); + } +} + + +/* Look up the table by the (key1, key2). If not existed, create an element + * by (key1, key2), return NIL, else return the array_t associated with + * this element. + */ + +static lsList +lookup_ddset(divisor,table,key1,key2) +ddivisor_t *divisor; +sm_matrix *table; +int key1, key2; +{ + register sm_element *p1, *p2; + lsHandle handle; + + if ((p1 = sm_find(table,key1,key2)) == NIL(sm_element)) { + p2 = sm_insert(table,key1,key2); + p2->user_word = (char *) lsCreate(); + lsNewEnd((lsList) p2->user_word, (lsGeneric) divisor, &handle); + divisor->sthandle = handle; + return NULL; + } else { + if (lsLength((lsList) p1->user_word) == 0) { + lsNewEnd((lsList) p1->user_word, (lsGeneric) divisor, &handle); + divisor->sthandle = handle; + return NULL; + } else { + return (lsList) p1->user_word; + } + } +} + +static lsList +lookup_ddset_other(divisor,table) +ddivisor_t *divisor; +sm_matrix *table; +{ + register sm_element *p1, *p2, *p3; + lsHandle handle; + int key1 = divisor->cube1->length; + int key2 = divisor->cube2->length; + + if ((p1 = sm_find(table,key1,key2)) == NIL(sm_element)) { + p2 = sm_insert(table,key1,key2); + p2->user_word = (char *) sm_alloc(); + p3 = sm_insert((sm_matrix *)p2->user_word, + divisor->cube1->last_col->col_num, + divisor->cube2->last_col->col_num); + p3->user_word = (char *) lsCreate(); + lsNewEnd((lsList) p3->user_word,(lsGeneric) divisor, &handle); + divisor->sthandle = handle; + return NULL; + } else { + if ((p2 = sm_find((sm_matrix *)p1->user_word, + divisor->cube1->last_col->col_num, + divisor->cube2->last_col->col_num)) == NIL(sm_element)) { + + p3 = sm_insert((sm_matrix *)p1->user_word, + divisor->cube1->last_col->col_num, + divisor->cube2->last_col->col_num); + p3->user_word = (char *) lsCreate(); + lsNewEnd((lsList) p3->user_word,(lsGeneric)divisor,&handle); + divisor->sthandle = handle; + return NULL; + } else { + if (lsLength((lsList) p2->user_word) == 0) { + lsNewEnd((lsList)p2->user_word,(lsGeneric) divisor, &handle); + divisor->sthandle = handle; + return NULL; + } else { + return (lsList) p2->user_word; + } + } + } +} + + +void +hash_ddset_table(divisor, check_set) +ddivisor_t *divisor; +lsList check_set; +{ + lsHandle handle; + + if (check_set) { + lsNewEnd(check_set, (lsGeneric) divisor, &handle); + divisor->sthandle = handle; + } +} + + +/* Choose corresponding check_set by (Dtype, key1, key2) */ + +lsList +choose_check_set(divisor, ddivisor_set) +register ddivisor_t *divisor; +ddset_t *ddivisor_set; +{ + lsList check_set; + int key1, key2; + + switch(DTYPE(divisor)) { + case D112 : + key1 = divisor->cube1->first_col->col_num; + key2 = divisor->cube2->last_col->col_num; + check_set = lookup_ddset(divisor,ddivisor_set->D112_set,key1,key2); + break; + case D222 : + key1 = (divisor->cube1->first_col->col_num)/2; + key2 = (divisor->cube1->last_col->col_num)/2; + check_set = lookup_ddset(divisor,ddivisor_set->D222_set,key1,key2); + break; + case D223 : + key1 = (divisor->cube1->first_col->col_num)/2; + key2 = (divisor->cube1->last_col->col_num)/2; + check_set = lookup_ddset(divisor,ddivisor_set->D223_set,key1,key2); + break; + case D224 : + key1 = divisor->cube1->last_col->col_num; + key2 = divisor->cube2->last_col->col_num; + check_set = lookup_ddset(divisor, ddivisor_set->D224_set,key1,key2); + break; + case Dother : + check_set = lookup_ddset_other(divisor, ddivisor_set->Dother_set); + break; + default: + ; + } + + return (lsList) check_set; +} + +/* If the divisor has already been in the set of double cube divisor, + * then store the information which indicates where the divisor comes + * from. + * else store the divisor in the double-cube divisor set. + */ + +ddivisor_t * +check_append(div,ddivisor_set,dd_cell) +register ddivisor_t *div; +ddset_t *ddivisor_set; +ddivisor_cell_t *dd_cell; +{ + int phase = 0; + ddivisor_t *dd; + lsGen gen; + lsHandle handle1, handle2; + lsList check_set; + + /* We only check the complement of D222, or D223 */ + + DTYPE(div) = decide_dtype(div); + + /* if empty in the double cube divisor set, then create the set. */ + + if (lsLength(ddivisor_set->DDset) == 0) { + check_set = choose_check_set(div, ddivisor_set); + (void) hash_ddset_table(div,check_set); + lsNewEnd(ddivisor_set->DDset,(lsGeneric) div, &handle1); + div->handle = handle1; + div->div_index = lsCreate(); + lsNewEnd(div->div_index,(lsGeneric) dd_cell, &handle2); + dd_cell->handle = handle2; + return div; + } + + /* if not empty in the double cube divisor set, then check if the + * divisor exists in the set. + */ + + check_set = choose_check_set(div,ddivisor_set); + if (check_set) { + lsForeachItem(check_set, gen, dd) { + if (check_exist(div,dd,&(phase)) == 1) { + dd_cell->phase = phase; + lsNewEnd(dd->div_index,(lsGeneric)dd_cell,&handle2); + dd_cell->handle = handle2; + (void) ddivisor_free(div); + lsFinish(gen); + return dd; + } + } + } + + /* for check_set == NULL and not found */ + (void) hash_ddset_table(div, check_set); + lsNewEnd(ddivisor_set->DDset,(lsGeneric) div, &handle1); + div->handle = handle1; + div->div_index = lsCreate(); + lsNewEnd(div->div_index,(lsGeneric) dd_cell, &handle2); + dd_cell->handle = handle2; + return div; +} + + +/* Extract double-cube divisors, and put them in the ddivisor_set. + * Index represents unique number to represent node in sis. + * Row represents current row in sparse matrix. + */ +int +extract_ddivisor(B,index,row,ddivisor_set) +sm_matrix *B; +int index; +int row; +ddset_t *ddivisor_set; +{ + sm_row *cube1, *cube2; + sm_element *pnode; + ddivisor_t *divisor, *div; + ddivisor_cell_t *dd_cell; + sm_cube_t *sm_cube1, *sm_cube2; + lsHandle handle, handle1, handle2; + int i,j; + + extern int twocube_timeout_occured; + + if ((B->nrows - row) == 1) { + cube1 = sm_get_row(B,row); + sm_cube1 = sm_cube_alloc(); + sm_cube1->sis_id = index; + cube1->user_word = (char *) sm_cube1; + return 0; + } + + pnode = sm_row_insert(ddivisor_set->node_cube_set, index); + pnode->user_word = (char *) lsCreate(); + + /* Store all cubes in the node */ + for (i = row; i < B->nrows; i++) { + cube1 = sm_get_row(B,i); + lsNewEnd((lsList)pnode->user_word,(lsGeneric)cube1, &handle); + sm_cube1 = sm_cube_alloc(); + sm_cube1->sis_id = index; + sm_cube1->cubehandle = handle; + cube1->user_word = (char *) sm_cube1; + } + + /* Generate double-cube divisors. */ + for (i = row; i < B->nrows-1; i++) { + cube1 = sm_get_row(B,i); + sm_cube1 = (sm_cube_t *) cube1->user_word; + for (j = i+1; j < B->nrows; j++) { + cube2 = sm_get_row(B,j); + dd_cell = ddivisor_cell_alloc(); + dd_cell->sis_id = index; + + /* Without loss of generality, we can let the literals in + * the first cube is less than that of the second cube. + */ + if (cube1->length < cube2->length) { + divisor = gen_ddivisor(cube1,cube2,dd_cell); + } else { + divisor = gen_ddivisor(cube2,cube1,dd_cell); + } + if (FX_DELETE == 1) { + if ((divisor->cube1->length > LENGTH1) || + (divisor->cube2->length > LENGTH2)){ + (void) ddivisor_cell_free(dd_cell); + (void) ddivisor_free(divisor); + continue; + } + } + div = check_append(divisor,ddivisor_set,dd_cell); + DIVISOR(dd_cell) = div; + sm_cube2 = (sm_cube_t *) cube2->user_word; + + lsNewEnd(sm_cube1->div_set,(lsGeneric)dd_cell, &handle1); + dd_cell->handle1 = handle1; + lsNewEnd(sm_cube2->div_set,(lsGeneric)dd_cell, &handle2); + dd_cell->handle2 = handle2; + + if (twocube_timeout_occured) { + /* Enough time has elapsed... do not generate any more */ + return; + } + } + } +} + diff --git a/sis/extract/extract.doc b/sis/extract/extract.doc new file mode 100644 index 0000000..620d0d0 --- /dev/null +++ b/sis/extract/extract.doc @@ -0,0 +1,115 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/extract.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +ex_kernel_gen(node, func, state) +node_t *node; +int (*func)(); +char *state; + + Calls the users function `func' once for each kernel of the function + `node'. `state' is passed along to contain user-defined state + information during generation. The function func is declared as: + + int + func(kernel, cokernel, state) + node_t *kernel; + node_t *cokernel; + char *state; + + + func is called once for each (kernel, cokernel) pair of the function. + Note that in this context, the cokernel is then always just + a single cube. + + The return value from func indicates whether to continue generating + kernels. If the return value is nonzero, kernel generation is + continued; if the return value is zero, the kernel generation is + stopped. + + + + +ex_subkernel_gen(node, func, level, state) +node_t *node; +int (*func)(); +int level; +char *state; + + Calls the users function `func' once for each prime kernel + intersection (i.e., each subkernel) of the function `node'. + Subkernels are generated by first generating all kernels, + forming the kernel-cube matrix, and then generating all prime + rectangles of the kernel-cube matrix. `level' controls the + level of kernels generated when creating the kernel-cube + matrix; currently, the only allowed values are 0 (for level 0 + kernels), or 1 (for all kernels). `state' is passed along to + contain user-defined state information during generation. The + function func is declared as: + + int + func(kernel, cokernel, state) + node_t *kernel; + node_t *cokernel; + char *state; + + func is called once for each (kernel, cokernel) pair of the function. + Note that in this context, the cokernel may consist of many cubes. + + The return value from func indicates whether to continue generating + kernels. If the return value is nonzero, subkernel generation is + continued; if the reeturn value is zero, the kernel generation is + stopped. + + + +node_t * +ex_find_divisor(node, level, method) +node_t *node; +int level; +int method; + + Find a good divisor of the function `node'. This is done by + generating kernels, forming the kernel-cube matrix, and then + finding a good-cost prime rectangle of this matrix. + + Level controls the level of kernels which are considered: + + level = 0: only level-0 kernels of node are used + level = 1: all kernels of node are used + + Method controls selection of prime rectangles from the kernel-cube + matrix: + + method = 0: ping_pong (fastest) + method = 1: best-valued prime rectangle (SOP metric) + + If `node' has no divisors other than itself (i.e., if it is a + level-0 kernel) then NIL(node_t) is returned instead. + + + +node_t * +ex_find_divisor_quick(node) +node_t *node; + + Find a divisor of the function `node' quickly. This is done by + generating and returning the first kernel of the function `node'. + If `node' has no divisors other than itself (i.e., if it is a + level-0 kernel) then NIL(node_t) is returned instead. + + +int fast_extract(B, ddivisor_set) +sm_matrix *B; +ddset_t *ddivisor_set; + + Greeedy concurrent algorithm for finding best double cube divisor or + single cube divisor. Finds all the double cube and single cube divisors + of the nodes in the network. Associates a cost function to each node. + Extract the node with the best cost function greedily. + diff --git a/sis/extract/extract.h b/sis/extract/extract.h new file mode 100644 index 0000000..a2b5eec --- /dev/null +++ b/sis/extract/extract.h @@ -0,0 +1,36 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/extract.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +extern void ex_kernel_gen(); +extern void ex_subkernel_gen(); +extern node_t *ex_find_divisor(); +extern node_t *ex_find_divisor_quick(); + +/* Some definitions for making the structures in fast_extract exportable */ + +#define SHORT short int +#define UNSIGNED unsigned char + +/* Define the data structure a double cube diviosr */ +typedef struct double_cube_divisor_struct ddivisor_t; +struct double_cube_divisor_struct { + sm_row *cube1; /* the first cube of the double-cube divisor */ + sm_row *cube2; /* the second cube of the double-cube divisor */ + lsHandle handle; /* lsHandle to double-cube divisor set */ + lsHandle sthandle; /* lsHandle to corresponoding searching table */ + lsList div_index; /* indicate where the divisor comes from */ + SHORT weight; /* the weight of double-cube divisor */ + UNSIGNED dtype; /* the type of double-cube divisor */ + UNSIGNED weight_status; /* indicate the weight can be changed or not */ + UNSIGNED status; /* indicate whether the divisor is changed or not */ + UNSIGNED level; /* indicates the level of 2-cube kernels */ +}; + + +#define fx_get_div_handle(p) ((p)->handle) diff --git a/sis/extract/extract_int.h b/sis/extract/extract_int.h new file mode 100644 index 0000000..37ec31f --- /dev/null +++ b/sis/extract/extract_int.h @@ -0,0 +1,114 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/extract_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +/* + * a rectangle is a collection of rows, columns and has a value + */ +typedef struct rect_struct rect_t; +struct rect_struct { + sm_col *rows; + sm_row *cols; + int value; +}; + + +/* + * each element of the sparse matrix contains a 'value' and identifies + * where it came from + */ +typedef struct value_cell_struct value_cell_t; +struct value_cell_struct { + int value; /* # literals in this cube */ + int sis_index; /* which sis function */ + int cube_number; /* which cube of that function */ + int ref_count; /* number of times referenced */ +}; +#define VALUE(p) ((value_cell_t *) (p)->user_word)->value + + +/* + * a quick way to associate cubes (i.e., sm_row *) to small integers + * and back. Used to build the kernel_cube matrix + */ +typedef struct cubeindex_struct cubeindex_t; +struct cubeindex_struct { + st_table *cube_to_integer; + array_t *integer_to_cube; +}; + + + +/* greedyrow.c, greedycol.c, pingpong.c */ +extern rect_t *greedy_row(); +extern rect_t *greedy_col(); +extern rect_t *ping_pong(); + +/* cube_extract */ +extern int sparse_cube_extract(); + +/* kernel.c */ +extern void kernel_extract_init(); +extern void kernel_extract(); +extern void kernel_extract_end(); +extern void kernel_extract_free(); +extern int sparse_kernel_extract(); +extern int overlapping_kernel_extract(); +extern int ex_is_level0_kernel(); +extern sm_matrix *ex_rect_to_kernel(); +extern sm_matrix *ex_rect_to_cokernel(); + +extern sm_matrix *kernel_cube_matrix; /* hack */ +extern array_t *co_kernel_table; /* hack */ +extern array_t *global_row_cost; /* hack */ +extern array_t *global_col_cost; /* hack */ + +/* best_subk.c */ +extern rect_t *choose_subkernel(); + +/* rect.c */ +extern void gen_all_rectangles(); +extern void rect_free(); +extern rect_t *rect_alloc(); +extern rect_t *rect_dup(); + +/* value.c */ +extern value_cell_t *value_cell_alloc(); +extern void value_cell_free(); +extern void free_value_cells(); + +/* sisc.c */ +extern array_t *find_rectangle_fanout(); +extern array_t *find_rectangle_fanout_cubes(); + +/* cubeindex.c */ +extern cubeindex_t *cubeindex_alloc(); +extern void cubeindex_free(); +extern int cubeindex_getindex(); +extern sm_row *cubeindex_getcube(); + +/* conv.c */ +extern int ex_divide_function_into_network(); +extern void ex_node_to_sm(); +extern sm_matrix *ex_network_to_sm(); +extern node_t *ex_sm_to_node(); +extern void ex_setup_globals(); +extern void ex_setup_globals_single(); +extern void ex_free_globals(); +extern char *ex_map_index_to_name(); + +extern int greedy_row_debug; +extern int greedy_col_debug; +extern int ping_pong_debug; +extern int cube_extract_debug; +extern int kernel_extract_debug; + +extern network_t *global_network; +extern nodeindex_t *global_node_index; +extern array_t *global_old_fct; +extern int use_complement; diff --git a/sis/extract/fast_extract.c b/sis/extract/fast_extract.c new file mode 100644 index 0000000..0a02603 --- /dev/null +++ b/sis/extract/fast_extract.c @@ -0,0 +1,1084 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/fast_extract.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" +#include "heap.h" +#include "fast_extract_int.h" + +static int debugging = 1; +static void sd_modify(); + +/* Map a network node to a sparse matrix representation. */ +void +fx_node_to_sm(node, M) +register node_t *node; +register sm_matrix *M; +{ + register pset last, p; + register int i, row; + int *fanin_index; + node_t *fanin; + sm_element *pelement; + + foreach_set(node->F, last, p) { + row = M->nrows; + + fanin_index = ALLOC(int, node->nin); + foreach_fanin(node, i, fanin) { + fanin_index[i] = 2 * nodeindex_indexof(global_node_index, fanin); + } + + foreach_fanin(node, i, fanin) { + switch (GETINPUT(p, i)) { + case ZERO: + pelement = sm_insert(M, row, fanin_index[i] + 1); + break; + case ONE: + pelement = sm_insert(M, row, fanin_index[i]); + break; + case TWO: + pelement = NIL(sm_element); + break; + } + } + + FREE(fanin_index); + } +} + + +/* Map a sparse matrix representation to a network node. */ +node_t * +fx_sm_to_node(func) +sm_matrix *func; +{ + int i, nin; + node_t *node, *fanin_node, **fanin; + pset setp, fullset; + pset_family F; + sm_col *pcol; + sm_row *prow; + sm_element *p; + + /* + * Determine the fanin points; + * set pcol->flag to be the column number in the set family + */ + node = node_alloc(); + nin = 0; + fanin = ALLOC(node_t *, 2*func->ncols); + sm_foreach_col(func, pcol) { + fanin_node = nodeindex_nodeof(global_node_index, pcol->col_num / 2); + if ((pcol->col_num % 2) == 0) { + pcol->flag = 2 * nin; + fanin[nin++] = fanin_node; + } else { + if (nin == 0 || fanin[nin-1] != fanin_node) { + pcol->flag = 2 * nin + 1; + fanin[nin++] = fanin_node; + } else { + pcol->flag = 2 * (nin-1) + 1; + } + } + } + + /* Create the set family */ + F = sf_new(func->nrows, nin * 2); + fullset = set_full(nin * 2); + sm_foreach_row(func, prow) { + setp = GETSET(F, F->count++); + (void) set_clear(setp, nin * 2); + sm_foreach_row_element(prow, p) { + i = sm_get_col(func, p->col_num)->flag; + set_insert(setp, i); + } + (void) set_diff(setp, fullset, setp); + } + set_free(fullset); + node_replace_internal(node, fanin, nin, F); + return node; +} + + +/* Divide each fanout */ +static int +fx_divide_each_fanout(fanout, newnode, complement) +array_t *fanout; +node_t *newnode; +int complement; +{ + int i, changed, count, fanout_index; + node_t *node; + + if (debugging > 1) { + (void) fprintf(sisout, "\nnew factor is"); + (void) node_print(sisout, newnode); + } + + for(i = count = 0; i < array_n(fanout); i++) { + fanout_index = array_fetch(int, fanout, i); + node = nodeindex_nodeof(global_node_index, fanout_index); + changed = node_substitute(node, newnode, complement); + count += changed; + + } + return count; +} + +/* Map D112 to rectangle data structure. */ +static rect_t * +D112_to_S2(B, divisor) +sm_matrix *B; +ddivisor_t *divisor; +{ + rect_t *rect; + sm_col *col1, *col2, *col3; + register int col_num1 = divisor->cube1->first_col->col_num; + register int col_num2 = divisor->cube2->first_col->col_num; + + (col_num1 % 2 == 0) ? col_num1++ : col_num1-- ; + (col_num2 % 2 == 0) ? col_num2++ : col_num2-- ; + col1 = sm_get_col(B,col_num1); + col2 = sm_get_col(B,col_num2); + if ((col1) && (col2)) { + col3 = sm_col_and(col1, col2); + if (col3->length == 0) { + (void) sm_col_free(col3); + return NIL(rect_t); + } else { + rect = ALLOC(rect_t, 1); + rect->cols = sm_row_alloc(); + rect->rows = col3; + sm_row_insert(rect->cols, col_num1); + sm_row_insert(rect->cols, col_num2); + return rect; + } + } else { + return NIL(rect_t); + } +} + + +/* Calculate the weight of D112 divisor. */ +static int +calc_weight_D112(B,divisor) +sm_matrix *B; +ddivisor_t *divisor; +{ + sm_col *col1, *col2, *col3; + register int col_num1 = divisor->cube1->first_col->col_num; + register int col_num2 = divisor->cube2->first_col->col_num; + int weight; + + (col_num1 % 2 == 0) ? col_num1++ : col_num1-- ; + (col_num2 % 2 == 0) ? col_num2++ : col_num2-- ; + col1 = sm_get_col(B,col_num1); + col2 = sm_get_col(B,col_num2); + if ((col1) && (col2)) { + col3 = sm_col_and(col1,col2); + weight = col3->length; + (void) sm_col_free(col3); + return weight; + } else { + return 0; + } +} + + +/* Calculate the weight of each double-cube divisor. + * Choose the best divisor from double-cube divisor set. + */ +static ddivisor_t * +choose_best_divisor(B,ddivisor_set, wdmax) +sm_matrix *B; +lsList ddivisor_set; +int *wdmax; +{ + int maxweight = -1; + int weight; + char *data; + lsGen gen1, gen2; + ddivisor_t *divisor, *bestdivisor; + ddivisor_cell_t *dd_cell; + + if (DONT_USE_WEIGHT_ZERO) { + maxweight = 0; + } + bestdivisor = NIL(ddivisor_t); + lsForeachItem(ddivisor_set, gen1, divisor){ + /* If empty, then remove it out. */ + if (lsLength(divisor->div_index) == 0) { + lsRemoveItem(divisor->handle, &data); + lsRemoveItem(divisor->sthandle, &data); + (void) ddivisor_free(divisor); + continue; + } + + /* If divisor is D112, calculate the weight of its complement. */ + if (DTYPE(divisor) == D112) { + weight = calc_weight_D112(B, divisor); + } else { + weight = 0; + } + + /* If weight doesn't need to recalculate, then skip. */ + switch(divisor->weight_status) { + register int w; + case CHANGED : + case NEW : + w = (lsLength(divisor->div_index) - 1) * + (divisor->cube1->length + divisor->cube2->length); + lsForeachItem(divisor->div_index, gen2, dd_cell) { + w += dd_cell->baselength; + } + w -= lsLength(divisor->div_index); + WEIGHT(divisor) = w; + divisor->weight_status = OLD; + case OLD : + weight += WEIGHT(divisor); + break; + default: + ; + } + + /* Choose the best double-cube divisor, and throw unworthy candidates */ + if (weight < DONT_USE_WEIGHT_ZERO) { + lsRemoveItem(divisor->handle, &data); + lsRemoveItem(divisor->sthandle, &data); + lsForeachItem(divisor->div_index, gen2, dd_cell) { + lsRemoveItem(dd_cell->handle1, &data); + lsRemoveItem(dd_cell->handle2, &data); + (void) ddivisor_cell_free(dd_cell); + } + (void) ddivisor_free(divisor); + } else { + STATUS(divisor) = NONCHECK; + if (maxweight < weight) { + maxweight = weight; + bestdivisor = divisor; + } + } + } + + *wdmax = maxweight; + return bestdivisor; +} + +/* exported function (used in gen_2c_kernel.c) + * compute the weight of a 2-cube divisor + */ +int +fx_compute_divisor_weight(func, divisor) +sm_matrix *func; +ddivisor_t *divisor; +{ + int weight, w; + lsGen gen; + ddivisor_cell_t *dd_cell; + + /* If divisor is D112, calculate the weight of its complement */ + if (DTYPE(divisor) == D112) { + weight = calc_weight_D112(func, divisor); + } else { + weight = 0; + } + w = (lsLength(divisor->div_index) - 1) * + (divisor->cube1->length + divisor->cube2->length); + lsForeachItem(divisor->div_index, gen, dd_cell) { + w += dd_cell->baselength; + } + w -= lsLength(divisor->div_index); + + weight += w; + + return weight; +} + + +/* Finding the fanouts of the double-cube divisor */ +static array_t * +find_ddivisor_fanout(divisor) +ddivisor_t *divisor; +{ + ddivisor_cell_t *dd_cell; + st_table *fanout_table; + st_generator *gen; + lsGen gen1; + array_t *fanouts; + char *key; + + /* + * Find all of the functions (and cubes) it fans out to + */ + + fanout_table = st_init_table(st_numcmp, st_numhash); + + lsForeachItem(divisor->div_index, gen1, dd_cell) { + key = (char *) dd_cell->sis_id; + (void) st_insert(fanout_table, key, NIL(char)); + } + fanouts = array_alloc(char *, 0); + st_foreach_item(fanout_table, gen, &key, NIL(char *)) { + array_insert_last(char *, fanouts, key); + } + (void) st_free_table(fanout_table); + + return fanouts; +} + + +/* Finding the fanouts of the single-cube divisor */ +static array_t * +find_sdivisor_fanout(B, rect) +sm_matrix *B; +rect_t *rect; +{ + register sm_element *p; + sm_row *row; + sm_cube_t *sm_cube; + st_table *fanout_table; + st_generator *gen; + array_t *fanouts; + char *key; + + /* Find all of the functions it fans out to */ + + fanout_table = st_init_table(st_numcmp, st_numhash); + sm_foreach_col_element(rect->rows, p) { + row = sm_get_row(B,p->row_num); + sm_cube = (sm_cube_t *)row->user_word; + key = (char *) sm_cube->sis_id; + (void) st_insert(fanout_table, key, NIL(char)); + } + + fanouts = array_alloc(char *, 0); + st_foreach_item(fanout_table, gen, &key, NIL(char *)) { + (void) array_insert_last(char *, fanouts, key); + } + (void) st_free_table(fanout_table); + + return fanouts; +} + +/* Update the sparse matrix after substituting single cube divisor */ +static void +sd_update_matrix(B,rect) +sm_matrix *B; +rect_t *rect; +{ + register sm_element *p1, *p2, *p; + + /* Clear rectangle */ + sm_foreach_col_element(rect->rows, p1) { + sm_foreach_row_element(rect->cols, p2) { + p = sm_find(B, p1->row_num, p2->col_num); + sm_remove_element(B, p); + } + } +} + + +/* Reexpress network after substituting a singl-cube divisor. + * dd112_on : indicate either a single-cube divisor or a complement of D112. + * index : sis_id of the current divisor. + * newcolumn : new column number in the sparse matrix. + */ +static void +sd_reexpress(B,rect,dd112_on,index,newcolumn) +sm_matrix *B; +rect_t *rect; +int dd112_on; +int index; +int *newcolumn; +{ + sm_element *p; + sm_matrix *func; + array_t *fanout; + int new_colnum, new_index, count; + node_t *node; + + func = sm_alloc(); + sm_copy_row(func, 0, rect->cols); + if (dd112_on == 0) { + node = fx_sm_to_node(func); + } else { + node = nodeindex_nodeof(global_node_index, index); + } + + fanout = find_sdivisor_fanout(B, rect); + count = fx_divide_each_fanout(fanout, node, dd112_on); + + if ((debugging) && (count != array_n(fanout))) { + (void) fprintf(sisout, + "warning: divided only %d of %d\n", count, array_n(fanout)); + (void) fprintf(sisout,"In sd_reexpress\n"); + } + + if (dd112_on == 0) { + if (count > 0) { + (void) network_add_node(global_network, node); + new_index = nodeindex_insert(global_node_index, node); + } else { + node_free(node); + new_index = -1; + } + } else { + new_index = index; + } + + (void) array_free(fanout); + (void) sm_free(func); + + /* Create new column in the sm and insert in proper positions */ + *newcolumn = new_colnum = new_index * 2 + dd112_on; + sm_foreach_col_element(rect->rows, p) { + (void) sm_insert(B, p->row_num, new_colnum); + } +} + + +/* Doing the substitution in sparse matrix and reexpression in sis for + * double-cube divisor. Return an array which stores the new rows. + * node_index stores the sis_id of this new node. + */ +static array_t * +dd_reexpress(B,divisor,node_index) +sm_matrix *B; +ddivisor_t *divisor; +int *node_index; +{ + sm_matrix *func; + array_t *fanout, *newcubes; + int row, new_colnum, new_index, count, complement; + sm_row *cube, *base; + sm_cube_t *sm_cube; + lsGen gen; + node_t *node; + ddivisor_cell_t *dd_cell; + + /* reexpression */ + + func = sm_alloc(); + (void) sm_copy_row(func, 0, divisor->cube1); + (void) sm_copy_row(func, 1, divisor->cube2); + node = fx_sm_to_node(func); + fanout = find_ddivisor_fanout(divisor); + + complement = ((DTYPE(divisor) == D222) || (DTYPE(divisor) == D223)); + count = fx_divide_each_fanout(fanout, node, complement); + + if ((debugging) && (count != array_n(fanout))) { + (void) fprintf(sisout, + "warning: divided only %d of %d\n", count, array_n(fanout)); + (void) fprintf(sisout,"In dd_reexpress\n"); + } + (void) array_free(fanout); + (void) sm_free(func); + + if (count > 0) { + (void) network_add_node(global_network, node); + new_index = nodeindex_insert(global_node_index, node); + } else { + (void) node_free(node); + new_index = -1; + } + if (DTYPE(divisor) == D112) *node_index = new_index; + + /* add a new column */ + + new_colnum = new_index * 2; + newcubes = array_alloc(sm_row *, 0); + + /* Update the sparse matrix after substituting double-cube divisor. */ + + row = B->last_row->row_num; + (void) sm_copy_row(B,++row,divisor->cube1); + cube = sm_get_row(B, row); + sm_cube = sm_cube_alloc(); + sm_cube->sis_id = new_index; + cube->user_word = (char *) sm_cube; + row = B->last_row->row_num; + (void) sm_copy_row(B,++row,divisor->cube2); + cube = sm_get_row(B, row); + sm_cube = sm_cube_alloc(); + sm_cube->sis_id = new_index; + cube->user_word = (char *) sm_cube; + + lsForeachItem(divisor->div_index, gen, dd_cell) { + base = sm_row_and(dd_cell->cube1, dd_cell->cube2); + (void) sm_copy_row(B, ++row, base); + (void) sm_row_free(base); + sm_cube = sm_cube_alloc(); + (void) sm_insert(B, row, new_colnum + dd_cell->phase); + cube = sm_get_row(B, row); + sm_cube->sis_id = dd_cell->sis_id; + cube->user_word = (char *) sm_cube; + (void) array_insert_last(sm_row *, newcubes, cube); + } + return newcubes; +} + + +/* Recompute the weight of double-cube divisors after substituting double + * cube divisor. newcubes stores new rows. + */ +static void +dd_modify(B,div,node_index, newcubes,ddivisor_set) +sm_matrix *B; +ddivisor_t *div; +int node_index; +array_t *newcubes; +ddset_t *ddivisor_set; +{ + lsGen gen1, gen2; + sm_row *cube1, *cube2; + sm_element *pnode; + sm_cube_t *sm_cube1, *sm_cube2; + ddivisor_t *divisor, *divisor1; + ddivisor_cell_t *dd1, *dd2, *dd_cell; + array_t *del_set; + lsHandle handle, handle1, handle2; + rect_t *rect; + char *data; + int i, j, newcolumn; + int phase, found; + lsList check_set; + + /* del_set : the ddivisor_cells needed to be discarded. */ + del_set = array_alloc(ddivisor_cell_t *, 0); + + lsForeachItem(div->div_index, gen1, dd1) { + sm_cube1 = (sm_cube_t *) dd1->cube1->user_word; + sm_cube2 = (sm_cube_t *) dd1->cube2->user_word; + lsRemoveItem(dd1->handle1, &data); + lsRemoveItem(dd1->handle2, &data); + (void) array_insert_last(ddivisor_cell_t *, del_set, dd1); + lsForeachItem(sm_cube1->div_set, gen2, dd2) { + lsRemoveItem(dd2->handle1, &data); + lsRemoveItem(dd2->handle2, &data); + (void) array_insert_last(ddivisor_cell_t *, del_set, dd2); + } + lsForeachItem(sm_cube2->div_set, gen2, dd2) { + lsRemoveItem(dd2->handle1, &data); + lsRemoveItem(dd2->handle2, &data); + (void) array_insert_last(ddivisor_cell_t *, del_set, dd2); + } + lsRemoveItem(sm_cube1->cubehandle, &data); + lsRemoveItem(sm_cube2->cubehandle, &data); + (void) sm_cube_free(sm_cube1); + (void) sm_cube_free(sm_cube2); + (void) sm_delrow(B, dd1->cube1->row_num); + (void) sm_delrow(B, dd1->cube2->row_num); + } + + if (ONE_PASS == 0) { + for (i = 0; i < array_n(del_set); i++) { + dd_cell = array_fetch(ddivisor_cell_t *, del_set, i); + divisor = DIVISOR(dd_cell); + if (divisor != div) { + lsRemoveItem(dd_cell->handle, &data); + if (lsLength(divisor->div_index) == 0) { + lsRemoveItem(divisor->sthandle, &data); + lsRemoveItem(divisor->handle, &data); + (void) ddivisor_free(divisor); + } else { + divisor->weight_status = CHANGED; + } + (void) ddivisor_cell_free(dd_cell); + } else { + lsRemoveItem(dd_cell->handle, &data); + (void) ddivisor_cell_free(dd_cell); + } + } + } else { + for (i = 0; i < array_n(del_set); i++) { + dd_cell = array_fetch(ddivisor_cell_t *, del_set, i); + divisor = DIVISOR(dd_cell); + lsRemoveItem(dd_cell->handle, &data); + divisor->weight_status = CHANGED; + (void) ddivisor_cell_free(dd_cell); + } + } + + + (void) array_free(del_set); + + if (DTYPE(div) == D112) { + rect = D112_to_S2(B,div); + lsRemoveItem(div->sthandle, &data); + lsRemoveItem(div->handle, &data); + (void) ddivisor_free(div); + if (rect) { + (void) sd_reexpress(B,rect,1,node_index, &newcolumn); + (void) sd_update_matrix(B,rect); + (void) sd_modify(B,rect,ddivisor_set, newcolumn); + (void) rect_free(rect); + } + } else { + lsRemoveItem(div->sthandle, &data); + lsRemoveItem(div->handle, &data); + (void) ddivisor_free(div); + } + if (ONE_PASS == 0) { + for (i = 0; i < array_n(newcubes); i++) { + cube1 = array_fetch(sm_row *, newcubes, i); + sm_cube1 = (sm_cube_t *) cube1->user_word; + pnode = sm_row_find(ddivisor_set->node_cube_set, sm_cube1->sis_id); + if (lsLength((lsList) pnode->user_word) == 0) { + lsNewEnd((lsList)pnode->user_word,(lsGeneric)cube1,&handle); + sm_cube1->cubehandle = handle; + continue; + } + lsForeachItem((lsList) pnode->user_word, gen1, cube2) { + sm_cube2 = (sm_cube_t *) cube2->user_word; + dd_cell = ddivisor_cell_alloc(); + dd_cell->sis_id = sm_cube2->sis_id; + if (cube1->length < cube2->length) { + divisor = gen_ddivisor(cube1,cube2,dd_cell); + } else { + divisor = gen_ddivisor(cube2,cube1,dd_cell); + } + divisor1 = check_append(divisor,ddivisor_set,dd_cell); + DIVISOR(dd_cell) = divisor1; + lsNewEnd(sm_cube1->div_set,(lsGeneric)dd_cell, &handle1); + dd_cell->handle1 = handle1; + lsNewEnd(sm_cube2->div_set,(lsGeneric)dd_cell, &handle2); + dd_cell->handle2 = handle2; + } + lsNewEnd((lsList)pnode->user_word,(lsGeneric)cube1,&handle); + sm_cube1->cubehandle = handle; + } + } else { + for (i = 0; i < array_n(newcubes); i++) { + cube1 = array_fetch(sm_row *, newcubes, i); + sm_cube1 = (sm_cube_t *) cube1->user_word; + pnode = sm_row_find(ddivisor_set->node_cube_set,sm_cube1->sis_id); + lsNewEnd((lsList)pnode->user_word,(lsGeneric)cube1,&handle); + sm_cube1->cubehandle = handle; + for (j = i+1; j < array_n(newcubes); j++) { + cube2 = array_fetch(sm_row *, newcubes, j); + sm_cube2 = (sm_cube_t *) cube2->user_word; + if (sm_cube1->sis_id == sm_cube2->sis_id) { + dd_cell = ddivisor_cell_alloc(); + dd_cell->sis_id = sm_cube2->sis_id; + if (cube1->length < cube2->length) { + divisor = gen_ddivisor(cube1,cube2,dd_cell); + } else { + divisor = gen_ddivisor(cube2,cube1,dd_cell); + } + DTYPE(divisor) = decide_dtype(divisor); + found = 0; + check_set = choose_check_set(divisor,ddivisor_set); + if (check_set) { + lsForeachItem(check_set,gen1,divisor1){ + if (check_exist(divisor,divisor1,&phase) == 1) { + dd_cell->phase = phase; + lsNewEnd(divisor1->div_index,(lsGeneric)dd_cell,&handle); + dd_cell->handle = handle; + DIVISOR(dd_cell) = divisor1; + lsNewEnd(sm_cube1->div_set,(lsGeneric)dd_cell,&handle1); + dd_cell->handle1 = handle1; + lsNewEnd(sm_cube2->div_set,(lsGeneric)dd_cell,&handle2); + dd_cell->handle2 = handle2; + found = 1; + lsFinish(gen1); + break; + } + } + if (found == 0) (void) ddivisor_cell_free(dd_cell); + (void) ddivisor_free(divisor); + } else { + lsRemoveItem(divisor->sthandle,&data); + (void) ddivisor_free(divisor); + (void) ddivisor_cell_free(dd_cell); + } + } + } + } + } + + (void) array_free(newcubes); + +} + + +/* Reconstruct old double-cube divisors after substituting a single-cube + * divisor. + */ +static void +sd_mod_old_divisor(divisor,ddivisor_set) +ddivisor_t *divisor; +ddset_t *ddivisor_set; +{ + ddivisor_cell_t *cell; + sm_row *cube, *base; + lsList list; + lsHandle handle; + char *data; + + if (lsLength(divisor->div_index) == 0) { + lsRemoveItem(divisor->handle, &data); + (void) ddivisor_free(divisor); + } else { + lsFirstItem(divisor->div_index, (lsGeneric *) &cell, &handle); + (void) sm_row_free(divisor->cube1); + (void) sm_row_free(divisor->cube2); + divisor->cube1 = sm_row_dup(cell->cube1); + divisor->cube2 = sm_row_dup(cell->cube2); + base = sm_row_and(divisor->cube1, divisor->cube2); + (void) clear_row_element(divisor->cube1, base); + (void) clear_row_element(divisor->cube2, base); + (void) sm_row_free(base); + if (divisor->cube1->length > divisor->cube2->length) { + cube = divisor->cube1; + divisor->cube1 = divisor->cube2; + divisor->cube2 = cube; + } + DTYPE(divisor) = decide_dtype(divisor); + list = choose_check_set(divisor, ddivisor_set); + (void) hash_ddset_table(divisor, list); + } +} + + +/* Create new double-cube divisors after substituting a single-cube divisor. */ +static void +sd_mod_new_divisor(divisor,ddivisor_set) +ddivisor_t *divisor; +ddset_t *ddivisor_set; +{ + ddivisor_cell_t *cell; + sm_row *cube, *base; + lsList list; + lsHandle handle; + + + if (lsLength(divisor->div_index) == 0) { + lsDestroy(divisor->div_index, 0); + FREE(divisor); + } else { + lsFirstItem(divisor->div_index, (lsGeneric *) &cell, &handle); + divisor->cube1 = sm_row_dup(cell->cube1); + divisor->cube2 = sm_row_dup(cell->cube2); + base = sm_row_and(divisor->cube1, divisor->cube2); + (void)clear_row_element(divisor->cube1,base); + (void)clear_row_element(divisor->cube2,base); + (void)sm_row_free(base); + lsNewEnd(ddivisor_set->DDset,(lsGeneric)divisor,&handle); + divisor->handle = handle; + if (divisor->cube1->length > divisor->cube2->length) { + cube = divisor->cube1; + divisor->cube1 = divisor->cube2; + divisor->cube2 = cube; + } + DTYPE(divisor) = decide_dtype(divisor); + list = choose_check_set(divisor, ddivisor_set); + (void) hash_ddset_table(divisor, list); + } +} + + +/* The extracted single-cube divisor is in between base and divisor. + * There are three possiblities for D223 and D223, i.e., the old divisor, and + * two new divisors. + * There are two possiblities for D112,D222 or Dother, i.e,, the old divisor, + * and a new divisor. + */ +static void +sd_mod_INBETWEEN(dd_cell, ddivisor_set, colnum) +ddivisor_cell_t *dd_cell; +ddset_t *ddivisor_set; +int colnum; +{ + ddivisor_t *olddivisor, *divisor, *divisor1; + lsHandle handle; + char *data; + lsGen gen; + ddivisor_cell_t *cell; + + olddivisor = DIVISOR(dd_cell); + divisor = ddivisor_alloc(); + divisor->div_index = lsCreate(); + STATUS(divisor) = INBETWEEN; + olddivisor->weight_status = CHANGED; + + switch(DTYPE(olddivisor)) { + case D222 : + case D223 : + divisor1 = ddivisor_alloc(); + divisor1->div_index = lsCreate(); + STATUS(divisor1) = INBETWEEN; + lsForeachItem(olddivisor->div_index, gen, cell) { + if ((sm_row_find(cell->cube1,colnum) != 0) || + (sm_row_find(cell->cube2,colnum) != 0)) { + lsRemoveItem(cell->handle,&data); + (cell->baselength)--; + if (cell->phase == 0) { + DIVISOR(cell) = divisor; + lsNewEnd(divisor->div_index,(lsGeneric)cell,&handle); + } else { + DIVISOR(cell) = divisor1; + cell->phase = 0; + lsNewEnd(divisor1->div_index,(lsGeneric)cell,&handle); + } + cell->handle = handle; + } + } + if (lsLength(olddivisor->div_index) == 0) { + lsRemoveItem(olddivisor->sthandle,&data); + lsRemoveItem(olddivisor->handle,&data); + (void) ddivisor_free(olddivisor); + } + (void) sd_mod_new_divisor(divisor,ddivisor_set); + (void) sd_mod_new_divisor(divisor1,ddivisor_set); + return ; + default: + lsForeachItem(olddivisor->div_index, gen, cell) { + if ((sm_row_find(cell->cube1, colnum) != 0) || + (sm_row_find(cell->cube2, colnum) != 0)) { + (cell->baselength)--; + lsRemoveItem(cell->handle,&data); + lsNewEnd(divisor->div_index,(lsGeneric)cell,&handle); + cell->handle = handle; + DIVISOR(cell) = divisor; + } + } + if (lsLength(olddivisor->div_index) == 0) { + lsRemoveItem(olddivisor->sthandle,&data); + lsRemoveItem(olddivisor->handle,&data); + (void) ddivisor_free(olddivisor); + } + (void) sd_mod_new_divisor(divisor,ddivisor_set); + return ; + } +} + + +/* The extracted single-cube divisor is in divisor part. + * There are two possiblities for D222, D223, i.e., two new divisors. + * There are one possiblities for D224 or Dother, i.e., one new divisor. + */ +static void +sd_mod_INDIVISOR(dd_cell, ddivisor_set) +ddivisor_cell_t *dd_cell; +ddset_t *ddivisor_set; +{ + + ddivisor_t *divisor, *divisor1; + lsGen gen; + lsHandle handle; + char *data; + ddivisor_cell_t *cell; + + divisor = DIVISOR(dd_cell); + STATUS(divisor) = INDIVISOR; + divisor1 = NIL(ddivisor_t); + + lsRemoveItem(divisor->sthandle, &data); + divisor->weight_status = CHANGED; + + if ((DTYPE(divisor) == D222) || (DTYPE(divisor) == D223)) { + divisor1 = ddivisor_alloc(); + divisor1->div_index = lsCreate(); + STATUS(divisor1) = INDIVISOR; + lsForeachItem(divisor->div_index, gen, cell) { + if (cell->phase) { + lsRemoveItem(cell->handle, &data); + lsNewEnd(divisor1->div_index,(lsGeneric)cell, &handle); + cell->handle = handle; + cell->phase = 0; + DIVISOR(cell) = divisor1; + } + } + (void) sd_mod_new_divisor(divisor1,ddivisor_set); + } + (void) sd_mod_old_divisor(divisor,ddivisor_set); +} + + +/* Consider the possible effects after extracting single-cube divisor. */ +int +sd_check_affected(dd_cell, ddivisor_set, newcolumn) +ddivisor_cell_t *dd_cell; +ddset_t *ddivisor_set; +int newcolumn; +{ + ddivisor_t *divisor; + sm_row *base; + int con1, con2; + + divisor = DIVISOR(dd_cell); + + switch(STATUS(divisor)) { + case NONCHECK : + con1 = (sm_row_find(dd_cell->cube1,newcolumn) == 0) ? 0 : 1; + con2 = (sm_row_find(dd_cell->cube2,newcolumn) == 0) ? 0 : 1; + switch(con1 + con2) { + case 2 : + /* IN BASE */ + (dd_cell->baselength)--; + STATUS(divisor) = INBASE; + (WEIGHT(divisor))--; + return 0; + case 1 : + /* IN BETWEEN or INDIVISOR */ + base = sm_row_and(dd_cell->cube1, dd_cell->cube2); + if (base->length < dd_cell->baselength) { + STATUS(divisor) = INBETWEEN; + (void)sd_mod_INBETWEEN(dd_cell,ddivisor_set,newcolumn); + } else if (base->length == dd_cell->baselength) { + STATUS(divisor) = INDIVISOR; + (void)sd_mod_INDIVISOR(dd_cell, ddivisor_set); + } else { + fail("This is impossible\n"); + } + (void) sm_row_free(base); + return 0; + case 0 : + fail("This is not impossible \n"); + } + case INBASE : + (dd_cell->baselength)--; + (WEIGHT(divisor))--; + return 0; + case INBETWEEN : + case INDIVISOR : + return 0; + default: + ; + } +} + + +/* Modification on double-cube divisor set after extracting an single-cube + * divisor or complement divisor of D112. + */ +static void +sd_modify(B,rect, ddivisor_set, newcolumn) +sm_matrix *B; +rect_t *rect; +ddset_t *ddivisor_set; +int newcolumn; +{ + lsGen gen; + lsHandle handle; + sm_cube_t *sm_cube, *sm_cube1, *sm_cube2; + ddivisor_cell_t *dd_cell; + array_t *del_set; + char *data; + sm_element *p; + sm_row *cube; + int i; + + del_set = array_alloc(ddivisor_cell_t *, 0); + + sm_foreach_col_element(rect->rows, p) { + cube = sm_get_row(B, p->row_num); + sm_cube = (sm_cube_t *) cube->user_word; + if (lsLength(sm_cube->div_set)) { + lsForeachItem(sm_cube->div_set, gen, dd_cell) { + lsRemoveItem(dd_cell->handle1, &data); + lsRemoveItem(dd_cell->handle2, &data); + (void)array_insert_last(ddivisor_cell_t *, del_set, dd_cell); + } + } + } + if (array_n(del_set) == 0) { + (void) array_free(del_set); + return; + } + + for (i = 0; i < array_n(del_set); i++) { + dd_cell = array_fetch(ddivisor_cell_t *, del_set, i); + sm_cube1 = (sm_cube_t *) dd_cell->cube1->user_word; + sm_cube2 = (sm_cube_t *) dd_cell->cube2->user_word; + lsNewEnd(sm_cube1->div_set,(lsGeneric)dd_cell,&handle); + dd_cell->handle1 = handle; + lsNewEnd(sm_cube2->div_set,(lsGeneric)dd_cell,&handle); + dd_cell->handle2 = handle; + (void) sd_check_affected(dd_cell, ddivisor_set, newcolumn); + } + + (void) array_free(del_set); + +} + + +/* Change sdivisor_t structure to rect_t structure */ +static rect_t * +sdiv_to_rect(B,sdiv) +sm_matrix *B; +sdivisor_t *sdiv; +{ + rect_t *rect; + + rect = ALLOC(rect_t, 1); + rect->rows = sm_col_and(sm_get_col(B,sdiv->col1),sm_get_col(B,sdiv->col2)); + rect->cols = sm_row_alloc(); + sm_row_insert(rect->cols, sdiv->col1); + sm_row_insert(rect->cols, sdiv->col2); + FREE(sdiv); + return rect; +} + +/* main program */ +int +fast_extract(B,ddivisor_set) +sm_matrix *B; +ddset_t *ddivisor_set; +{ + int wdmax; + ddivisor_t *divisor1; + sdivisor_t *divisor2; + sdset_t *sdset; + rect_t *rect; + + int index, loop, newcolumn; + array_t *newcubes; + + index = 0 ; loop = 1; + sdset = sdset_alloc(); + + do { + + /* Choose the best double-cube divisor. */ + if (lsLength(ddivisor_set->DDset)) { + divisor1 = choose_best_divisor(B,ddivisor_set->DDset,&wdmax); + } else { + wdmax = -1; + } + + /* Choose the best single-cube divisor. */ + divisor2 = extract_sdivisor(B, sdset, wdmax); + + /* Choose the best divisor. */ + if (divisor2 == NIL(sdivisor_t)) { + if ((divisor1 == NIL(ddivisor_t)) || (wdmax < 0)) { + loop = 0; + } else { + newcubes = dd_reexpress(B,divisor1, &index); + (void) dd_modify(B,divisor1,index,newcubes,ddivisor_set); + } + } else { + if ((COIN(divisor2) - 2) < 0) { + loop = 0; + } else { + rect = sdiv_to_rect(B,divisor2); + (void) sd_reexpress(B,rect,0, index, &newcolumn); + (void) sd_update_matrix(B,rect); + (void) sd_modify(B,rect,ddivisor_set, newcolumn); + (void) rect_free(rect); + } + } + } while (loop); + + (void) sdset_free(sdset); +} + diff --git a/sis/extract/fast_extract_int.h b/sis/extract/fast_extract_int.h new file mode 100644 index 0000000..977b1ab --- /dev/null +++ b/sis/extract/fast_extract_int.h @@ -0,0 +1,156 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/fast_extract_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +/* + * Definitions local to package 'fast_extract' go here + */ + +/* SHORT and UNSIGNED are now defined in extract.h */ + +/* Define types of double cube divisors */ +#define D112 0 +#define D222 1 +#define D223 2 +#define D224 3 +#define Dother 4 + +/* Define different status for weights in divisors */ +#define OLD 0 +#define NEW 1 +#define CHANGED 2 + +/* Define different status of doube-cube divisor after extracting + * single-cube divisor + */ +#define NONCHECK 0 +#define INBASE 1 +#define INBETWEEN 2 +#define INDIVISOR 3 + +#define HANDLE(p) ((p)->handle) +#define WEIGHT(p) ((p)->weight) +#define DTYPE(p) ((p)->dtype) +#define STATUS(p) ((p)->status) + +/* + * The data structure for the ddivisor_t structure resides in extract.h + * This structure is used in some of the speed_up code (HACK)... + */ + +/* Define the cell data structure of a double-cube divisor */ +typedef struct ddivisor_cell_struct ddivisor_cell_t; +struct ddivisor_cell_struct { + sm_row *cube1; /* the pointer of the first cube */ + sm_row *cube2; /* the pointer of the second cube */ + lsHandle handle1; /* lsHandle to the list in cube1. */ + lsHandle handle2; /* lsHandle to the list in cube2 */ + lsHandle handle; /* lsHandle to the corresponding list */ + ddivisor_t *div; /* the address of the corresponding divisor */ + int sis_id; /* the id in sis */ + UNSIGNED phase; /* the phase of this doubler-cube divisor */ + UNSIGNED baselength; /* the baselength */ +}; + +#define DIVISOR(p) ((p)->div) + + +/* Define the data structure of a single-cube divisor. */ +typedef struct single_cube_divisor_struct sdivisor_t; +struct single_cube_divisor_struct { + SHORT col1; /* the 1st column number of a single-cube divisor */ + SHORT col2; /* the 2nd column number of a single-cube divisor */ + SHORT coin; /* the coincidence of a single-cube divisor */ +}; + +#define COIN(p) ((p)->coin) + + +/* Define the data structure of double-cube divisor set. */ +typedef struct ddivisor_set_struct ddset_t; +struct ddivisor_set_struct { + lsList DDset; /* storing all double-cube divisors. */ + sm_row *node_cube_set; /* storing the cubes for each node in sis */ + sm_matrix *D112_set; /* storing D112 type divisors */ + sm_matrix *D222_set; /* storing D222 type divisors */ + sm_matrix *D223_set; /* storing D223 type divisors */ + sm_matrix *D224_set; /* storing D224 type divisors */ + sm_matrix *Dother_set; /* storing other types divisors */ +}; + +/* Define the data structure of single-cube divisor set. */ +typedef struct sdivisor_set_struct sdset_t; +struct sdivisor_set_struct { + heap_t *heap; /* storing all single-cube divisor */ + int index; /* the largest column number considered so far */ + lsList columns; /* the cols unconsidered */ + lsList col_set; /* the cols considered */ +}; + +/* Define the data structure of col_cell */ +typedef struct col_cell_struct col_cell_t; +struct col_cell_struct { + SHORT num; /* column number */ + int length; /* column length */ + lsHandle handle; /* lsHandle */ +}; + +/* Define the data structure for each cube in sparse matrix. */ +typedef struct sm_cube_cell_struct sm_cube_t; +struct sm_cube_cell_struct { + lsList div_set; /* storing the dd_cells affected by this cube */ + lsHandle cubehandle; /* pointing to the corresponding node_cube_set */ + int sis_id; /* the id in sis */ +}; + + +/* com_fx.c */ +extern int ONE_PASS; +extern int FX_DELETE; +extern int LENGTH1; +extern int LENGTH2; +extern int DONT_USE_WEIGHT_ZERO; + +/* ddivisor.c */ +extern int extract_ddivisor(); +extern ddivisor_t *check_append(); +extern void hash_ddset_table(); +extern lsList choose_check_set(); +static lsList lookup_ddset_other(); +static lsList lookup_ddset(); +extern int check_exist(); +extern ddivisor_t *gen_ddivisor(); +extern int decide_dtype(); +extern void clear_row_element(); + +/* memory allocation and free in ddivsior.c */ +extern ddivisor_t *ddivisor_alloc(); +extern void ddivisor_free(); +extern ddivisor_cell_t *ddivisor_cell_alloc(); +extern void ddivisor_cell_free(); +extern ddset_t *ddset_alloc_init(); +extern void ddset_free(); +extern sm_cube_t *sm_cube_alloc(); +extern void sm_cube_free(); + +/* fast_extract.c */ +extern void fx_node_to_sm(); +extern node_t *fx_sm_to_node(); +extern int fast_extract(); +extern void calc_weight(); + +/* sdivisor.c */ +static sdivisor_t *sdivisor_alloc(); +static void sdivisor_free(); +extern sdset_t *sdset_alloc(); +extern void sdset_free(); +static col_cell_t *col_cell_alloc(); +static void col_cell_free(); +extern sdivisor_t *extract_sdivisor(); +extern sdivisor_t *sdivsisor_alloc(); +extern void sdivisor_free(); diff --git a/sis/extract/gdivisor.c b/sis/extract/gdivisor.c new file mode 100644 index 0000000..1b90322 --- /dev/null +++ b/sis/extract/gdivisor.c @@ -0,0 +1,66 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/gdivisor.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + + +node_t * +ex_find_divisor(node, level, method) +node_t *node; +int level; +int method; +{ + sm_matrix *node_func, *kernel_sm; + sm_row *co_kernel; + node_t *divisor; + rect_t *rect; + int rownum; + + /* setup */ + ex_setup_globals_single(node); + kernel_extract_init(); + node_func = sm_alloc(); + ex_node_to_sm(node, node_func); + kernel_extract(node_func, /* sis_index */ 0, level); + free_value_cells(node_func); + sm_free(node_func); + kernel_extract_end(); + + /* check if the function is kernel-free */ + if (kernel_cube_matrix->nrows == 0) { + /* shouldn't ever happen ? */ + divisor = NIL(node_t); + goto cleanup; + } else if (kernel_cube_matrix->nrows == 1) { + rownum = kernel_cube_matrix->first_row->row_num; + co_kernel = array_fetch(sm_row *, co_kernel_table, rownum); + if (co_kernel->length == 0) { + divisor = NIL(node_t); + goto cleanup; + } + } + + rect = choose_subkernel(kernel_cube_matrix, + global_row_cost, global_col_cost, method); + divisor = 0; + if (rect->cols->length > 0 && rect->rows->length > 0) { + kernel_sm = ex_rect_to_kernel(rect); + divisor = ex_sm_to_node(kernel_sm); + sm_free(kernel_sm); + } + rect_free(rect); + + /* cleanup */ +cleanup: + kernel_extract_free(); + ex_free_globals(0); + + return divisor; +} diff --git a/sis/extract/gen_2c_kernel.c b/sis/extract/gen_2c_kernel.c new file mode 100644 index 0000000..6f0de27 --- /dev/null +++ b/sis/extract/gen_2c_kernel.c @@ -0,0 +1,115 @@ +#include "sis.h" +#include "extract_int.h" +#include "heap.h" +#include "fast_extract_int.h" + + +/* generate all 2-cube kernels for a node */ +static ddset_t * +fx_node_2c_kernels(node_func, index) +sm_matrix *node_func; +int index; +{ + lsGen gen; + ddset_t *ddset; + ddivisor_t *divisor; + + ddset = ddset_alloc_init(); + (void) extract_ddivisor(node_func, index, 0, ddset); + lsForeachItem(ddset->DDset, gen, divisor) { + WEIGHT(divisor) = fx_compute_divisor_weight(node_func, divisor); + } + + return ddset; +} + + +/* tranform a 2-cube divisor to a node */ +static node_t * +fx_ddivisor_to_node(divisor) +ddivisor_t *divisor; +{ + sm_matrix *func; + node_t *node; + + func = sm_alloc(); + (void) sm_copy_row(func, 0, divisor->cube1); + (void) sm_copy_row(func, 1, divisor->cube2); + node = fx_sm_to_node(func); + sm_free(func); + + return node; +} + + +/* select the best 2-cube divisor based on the provided weighting function */ +node_t * +fx_2c_kernel_best(node, function, state) +node_t *node; +int (*function)(); +char *state; +{ + sm_matrix *node_func; + ddset_t *ddset; + ddivisor_t *divisor; + int status, node_index; + lsGen gen; + lsHandle *handle; + sm_row *prow; + node_t *node_2c; + + /* setup */ + ex_setup_globals_single(node); + + switch(node_function(node)) { + case NODE_PI: + case NODE_PO: + case NODE_0: + case NODE_1: + case NODE_INV: + case NODE_BUF: + return NIL(node_t); + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + node_func = sm_alloc(); + (void) fx_node_to_sm(node, node_func); + node_index = nodeindex_indexof(global_node_index, node); + ddset = fx_node_2c_kernels(node_func, node_index); + } + + /* evaluate every 2-cube divisor */ + handle = LS_NH; + lsForeachItem(ddset->DDset, gen, divisor) { + node_2c = fx_ddivisor_to_node(divisor); + status = (*function)(divisor, node_2c, &handle, state); + (void) node_free(node_2c); + if (status == 0){ +/* + fprintf(sisout,"?"); + fflush(sisout); +*/ + handle = LS_NH; + lsFinish(gen); + break; + } + } + + /* get the lsHandle from state data structure */ + if (handle != LS_NH){ + divisor = (ddivisor_t *)lsFetchHandle(*handle); + node_2c = fx_ddivisor_to_node(divisor); + } else { + node_2c = NIL(node_t); + } + + /* cleanup */ + (void) ddset_free(ddset); + sm_foreach_row(node_func, prow) { + (void) sm_cube_free((sm_cube_t *) prow->user_word); + } + (void) sm_free(node_func); + ex_free_globals(0); + + return node_2c; +} diff --git a/sis/extract/genkern.c b/sis/extract/genkern.c new file mode 100644 index 0000000..f0a71ac --- /dev/null +++ b/sis/extract/genkern.c @@ -0,0 +1,143 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/genkern.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + +static int gen_kernels_got_one(); +static int gen_subkernels_got_one(); + + +typedef struct gen_kernel_state_struct gen_kernel_state_t; +struct gen_kernel_state_struct { + int (*user_func)(); + char *user_state; +}; + + +void +ex_kernel_gen(node, func, state) +node_t *node; +int (*func)(); +char *state; +{ + sm_matrix *node_func; + gen_kernel_state_t *my_state; + + my_state = ALLOC(gen_kernel_state_t, 1); + my_state->user_func = func; + my_state->user_state = state; + + /* setup */ + ex_setup_globals_single(node); + node_func = sm_alloc(); + ex_node_to_sm(node, node_func); + + gen_all_rectangles(node_func, gen_kernels_got_one, (char *) my_state); + + /* cleanup */ + free_value_cells(node_func); + sm_free(node_func); + ex_free_globals(0); + FREE(my_state); +} + + + +static int +gen_kernels_got_one(co_rect, rect, state_p) +sm_matrix *co_rect; +register rect_t *rect; +char *state_p; +{ + gen_kernel_state_t *state; + sm_matrix *dummy; + node_t *kernel, *cokernel; + + state = (gen_kernel_state_t *) state_p; + + /* map the kernel ('co_rect') into a real node */ + kernel = ex_sm_to_node(co_rect); + + /* map the co-kernel ('rect') into a real node */ + dummy = sm_alloc(); + sm_copy_row(dummy, 0, rect->cols); + cokernel = ex_sm_to_node(dummy); + sm_free(dummy); + + /* hack for the fact that sparse matrix can't represent 1 */ + if (node_function(cokernel) == NODE_0) { + node_free(cokernel); + cokernel = node_constant(1); + } + + return (*state->user_func)(kernel, cokernel, state->user_state); +} + +void +ex_subkernel_gen(node, func, level, state) +node_t *node; +int (*func)(); +int level; +char *state; +{ + sm_matrix *node_func; + gen_kernel_state_t *my_state; + + my_state = ALLOC(gen_kernel_state_t, 1); + my_state->user_func = func; + my_state->user_state = state; + + /* setup */ + ex_setup_globals_single(node); + kernel_extract_init(); + node_func = sm_alloc(); + ex_node_to_sm(node, node_func); + kernel_extract(node_func, /* sis_index */ 0, level); + free_value_cells(node_func); + sm_free(node_func); + kernel_extract_end(); + + gen_all_rectangles(kernel_cube_matrix, gen_subkernels_got_one, + (char *) my_state); + + /* cleanup */ + kernel_extract_free(); + ex_free_globals(0); + FREE(my_state); +} + + + +/* ARGSUSED */ +static int +gen_subkernels_got_one(co_rect, rect, state_p) +sm_matrix *co_rect; +register rect_t *rect; +char *state_p; +{ + gen_kernel_state_t *state; + node_t *kernel, *cokernel; + sm_matrix *kernel_sm, *cokernel_sm; + + state = (gen_kernel_state_t *) state_p; + + if (rect->cols->length == 0 || rect->rows->length == 0) return 1; + + kernel_sm = ex_rect_to_kernel(rect); + kernel = ex_sm_to_node(kernel_sm); + + cokernel_sm = ex_rect_to_cokernel(rect); + cokernel = ex_sm_to_node(cokernel_sm); + + sm_free(kernel_sm); + sm_free(cokernel_sm); + + return (*state->user_func)(kernel, cokernel, state->user_state); +} diff --git a/sis/extract/greedycol.c b/sis/extract/greedycol.c new file mode 100644 index 0000000..1c19b26 --- /dev/null +++ b/sis/extract/greedycol.c @@ -0,0 +1,197 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/greedycol.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + + +static int +check_rect_value(A, col_cost, row_cost, rect) +sm_matrix *A; +array_t *col_cost, *row_cost; +rect_t *rect; +{ + register sm_element *p1, *p2, *p3; + register int value; + + value = 0; + sm_foreach_row_element(rect->cols, p1) { + sm_foreach_col_element(rect->rows, p2) { + p3 = sm_find(A, p2->row_num, p1->col_num); + assert(p3 != NIL(sm_element)); + value += VALUE(p3); + } + } + sm_foreach_row_element(rect->cols, p1) { + value -= array_fetch(int, col_cost, p1->col_num); + } + sm_foreach_col_element(rect->rows, p1) { + value -= array_fetch(int, row_cost, p1->row_num); + } + return value; +} + +static sm_col * +find_max_col_intersection(A, col_cost, rect, row_values) +sm_matrix *A; +array_t *col_cost; +rect_t *rect; +int *row_values; +{ + register sm_element *p, *p1; + register sm_row *prow; + register int *col_values; + sm_col *best_col, *seed; + int value, max_value; + + if (A->ncols == 0) return 0; + + seed = rect->rows; + col_values = ALLOC(int, A->last_col->col_num + 1); + + /* Set each col 'value' to be its cost */ + sm_foreach_col_element(seed, p) { + prow = sm_get_row(A, p->row_num); + sm_foreach_row_element(prow, p1) { + col_values[p1->col_num] = - array_fetch(int, col_cost, p1->col_num); + } + } + + /* Compute for each col the final value if it is added to rectangle */ + sm_foreach_col_element(seed, p) { + prow = sm_get_row(A, p->row_num); + sm_foreach_row_element(prow, p1) { + col_values[p1->col_num] += VALUE(p1) + row_values[prow->row_num]; + } + } + + + /* + * now find the best (which is not also in rect_cols) + */ + max_value = 0; + best_col = NIL(sm_col); + sm_foreach_col_element(seed, p) { + prow = sm_get_row(A, p->row_num); + sm_foreach_row_element(prow, p1) { + value = col_values[p1->col_num]; + if (value > max_value) { + if (! sm_row_find(rect->cols, p1->col_num)) { + max_value = value; + best_col = sm_get_col(A, p1->col_num); + } + } + } + } + + FREE(col_values); + return best_col; +} + +/* + * greedy algorithm to find a 'good' rectangle which contains at least + * one rowumn of 'seed' + * + * The cost of a rectangle is computed incrementally. + */ + + +rect_t * +greedy_col(A, col_cost, row_cost, seed) +sm_matrix *A; +array_t *col_cost, *row_cost; +sm_col *seed; +{ + sm_element *p; + sm_col *save, *pcol; + rect_t *best_rect, *rect; + int total_col_cost, *row_values; + + best_rect = rect_alloc(); + if (A->ncols == 0) return best_rect; + + /* make 'seed' the initial rectangle */ + rect = rect_alloc(); + sm_foreach_col_element(seed, p) { + (void) sm_col_insert(rect->rows, p->row_num); + } + (void) sm_row_insert(rect->cols, seed->col_num); + + /* Setup the initial value for each rowumn */ + row_values = ALLOC(int, A->last_row->row_num + 1); + sm_foreach_col_element(seed, p) { + row_values[p->row_num] = VALUE(p) - + array_fetch(int, row_cost, p->row_num); + } + + /* Setup the initial rectangle value */ + total_col_cost = array_fetch(int, col_cost, seed->col_num); + rect->value = - total_col_cost; + sm_foreach_col_element(rect->rows, p) { + rect->value += row_values[p->row_num]; + } + + + /* + * loop until the rectangle is only a single rowumn (or until + * no cols intersect the current rectangle) + */ + + pcol = find_max_col_intersection(A, col_cost, rect, row_values); + + while (pcol != 0 && rect->rows->length > 1) { + + if (greedy_col_debug) { + (void) printf("greedy_col: rectangle is %d by %d, value=%d\n", + rect->cols->length, rect->rows->length, rect->value); + assert(check_rect_value(A, col_cost, row_cost, rect)==rect->value); + } + + /* update which cols are in the rectangle */ + (void) sm_row_insert(rect->cols, pcol->col_num); + + /* update the cost of the selected cols */ + total_col_cost += array_fetch(int, col_cost, pcol->col_num); + + /* update which rowumns are in the rectangle */ + save = rect->rows; + rect->rows = sm_col_and(rect->rows, pcol); + sm_col_free(save); + + /* update the 'cost/value' for each rowumn */ + sm_foreach_col_element(pcol, p) { + row_values[p->row_num] += VALUE(p); + } + + /* update the rectangle value */ + rect->value = - total_col_cost; + sm_foreach_col_element(rect->rows, p) { + rect->value += row_values[p->row_num]; + } + + /* See if this is the best rectangle so far ... */ + if (rect->value > best_rect->value) { + rect_free(best_rect); + best_rect = rect_dup(rect); + } + + /* Find the next best col */ + pcol = find_max_col_intersection(A, col_cost, rect, row_values); + } + + rect_free(rect); + + if (greedy_col_debug) { + (void) printf("greedy_col: best rectangle is %d by %d value=%d\n", + best_rect->cols->length, best_rect->rows->length, best_rect->value); + } + + FREE(row_values); + return best_rect; +} diff --git a/sis/extract/greedyrow.c b/sis/extract/greedyrow.c new file mode 100644 index 0000000..1eb38ea --- /dev/null +++ b/sis/extract/greedyrow.c @@ -0,0 +1,197 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/greedyrow.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + + +static int +check_rect_value(A, row_cost, col_cost, rect) +sm_matrix *A; +array_t *row_cost, *col_cost; +rect_t *rect; +{ + register sm_element *p1, *p2, *p3; + register int value; + + value = 0; + sm_foreach_col_element(rect->rows, p1) { + sm_foreach_row_element(rect->cols, p2) { + p3 = sm_find(A, p1->row_num, p2->col_num); + assert(p3 != NIL(sm_element)); + value += VALUE(p3); + } + } + sm_foreach_col_element(rect->rows, p1) { + value -= array_fetch(int, row_cost, p1->row_num); + } + sm_foreach_row_element(rect->cols, p1) { + value -= array_fetch(int, col_cost, p1->col_num); + } + return value; +} + +static sm_row * +find_max_row_intersection(A, row_cost, rect, col_values) +sm_matrix *A; +array_t *row_cost; +rect_t *rect; +int *col_values; +{ + register sm_element *p, *p1; + register sm_col *pcol; + register int *row_values; + sm_row *best_row, *seed; + int value, max_value; + + if (A->nrows == 0) return 0; + + seed = rect->cols; + row_values = ALLOC(int, A->last_row->row_num + 1); + + /* Set each row 'value' to be its cost */ + sm_foreach_row_element(seed, p) { + pcol = sm_get_col(A, p->col_num); + sm_foreach_col_element(pcol, p1) { + row_values[p1->row_num] = - array_fetch(int, row_cost, p1->row_num); + } + } + + /* Compute for each row the final value if it is added to rectangle */ + sm_foreach_row_element(seed, p) { + pcol = sm_get_col(A, p->col_num); + sm_foreach_col_element(pcol, p1) { + row_values[p1->row_num] += VALUE(p1) + col_values[pcol->col_num]; + } + } + + + /* + * now find the best (which is not also in rect_rows) + */ + max_value = 0; + best_row = NIL(sm_row); + sm_foreach_row_element(seed, p) { + pcol = sm_get_col(A, p->col_num); + sm_foreach_col_element(pcol, p1) { + value = row_values[p1->row_num]; + if (value > max_value) { + if (! sm_col_find(rect->rows, p1->row_num)) { + max_value = value; + best_row = sm_get_row(A, p1->row_num); + } + } + } + } + + FREE(row_values); + return best_row; +} + +/* + * greedy algorithm to find a 'good' rectangle which contains at least + * one column of 'seed' + * + * The cost of a rectangle is computed incrementally. + */ + + +rect_t * +greedy_row(A, row_cost, col_cost, seed) +sm_matrix *A; +array_t *row_cost, *col_cost; +sm_row *seed; +{ + sm_element *p; + sm_row *save, *prow; + rect_t *best_rect, *rect; + int total_row_cost, *col_values; + + best_rect = rect_alloc(); + if (A->nrows == 0) return best_rect; + + /* make 'seed' the initial rectangle */ + rect = rect_alloc(); + sm_foreach_row_element(seed, p) { + (void) sm_row_insert(rect->cols, p->col_num); + } + (void) sm_col_insert(rect->rows, seed->row_num); + + /* Setup the initial value for each column */ + col_values = ALLOC(int, A->last_col->col_num + 1); + sm_foreach_row_element(seed, p) { + col_values[p->col_num] = VALUE(p) - + array_fetch(int, col_cost, p->col_num); + } + + /* Setup the initial rectangle value */ + total_row_cost = array_fetch(int, row_cost, seed->row_num); + rect->value = - total_row_cost; + sm_foreach_row_element(rect->cols, p) { + rect->value += col_values[p->col_num]; + } + + + /* + * loop until the rectangle is only a single column (or until + * no rows intersect the current rectangle) + */ + + prow = find_max_row_intersection(A, row_cost, rect, col_values); + + while (prow != 0 && rect->cols->length > 1) { + + if (greedy_row_debug) { + (void) printf("greedy_row: rectangle is %d by %d, value=%d\n", + rect->rows->length, rect->cols->length, rect->value); + assert(check_rect_value(A, row_cost, col_cost, rect)==rect->value); + } + + /* update which rows are in the rectangle */ + (void) sm_col_insert(rect->rows, prow->row_num); + + /* update the cost of the selected rows */ + total_row_cost += array_fetch(int, row_cost, prow->row_num); + + /* update which columns are in the rectangle */ + save = rect->cols; + rect->cols = sm_row_and(rect->cols, prow); + sm_row_free(save); + + /* update the 'cost/value' for each column */ + sm_foreach_row_element(prow, p) { + col_values[p->col_num] += VALUE(p); + } + + /* update the rectangle value */ + rect->value = - total_row_cost; + sm_foreach_row_element(rect->cols, p) { + rect->value += col_values[p->col_num]; + } + + /* See if this is the best rectangle so far ... */ + if (rect->value > best_rect->value) { + rect_free(best_rect); + best_rect = rect_dup(rect); + } + + /* Find the next best row */ + prow = find_max_row_intersection(A, row_cost, rect, col_values); + } + + rect_free(rect); + + if (greedy_row_debug) { + (void) printf("greedy_row: best rectangle is %d by %d value=%d\n", + best_rect->rows->length, best_rect->cols->length, best_rect->value); + } + + FREE(col_values); + return best_rect; +} diff --git a/sis/extract/heap.c b/sis/extract/heap.c new file mode 100644 index 0000000..e08395c --- /dev/null +++ b/sis/extract/heap.c @@ -0,0 +1,150 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/heap.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "heap.h" + +/* Author : Huey-Yih Wang */ +/* Date : Nov 1. 1990 */ +/* Dynamic 2-heap data structure */ + +/* Allocate and free the entry of heap */ +heap_entry_t * +heap_entry_alloc() +{ + register heap_entry_t *entry; + + entry = ALLOC(heap_entry_t, 1); + entry->key = -1; + entry->item = NIL(char); + return entry; +} + +void +heap_entry_free(entry) +heap_entry_t *entry; +{ + FREE(entry); +} + +/* Allocate and free heap */ +heap_t * +heap_alloc() +{ + int i; + int size = 10; + register heap_t *heap; + + heap = ALLOC(heap_t, 1); + heap->heapnum = 0; + heap->heapsize = size; + heap->tree = ALLOC(heap_entry_t *, size); + heap->tree[0] = heap_entry_alloc(); + heap->tree[0]->key = INFINITY; + for (i = 1; i < size; i++) { + heap->tree[i] = NIL(heap_entry_t); + } + return heap; +} + +void +heap_free(heap,delFunc) +register heap_t *heap; +void (*delFunc)(); +{ + int i; + + for (i = 0; i <= heap->heapnum; i++) { + if (heap->tree[i]->item) (*delFunc)(heap->tree[i]->item); + (void) heap_entry_free(heap->tree[i]); + } + FREE(heap->tree); + FREE(heap); +} + +heap_entry_t * +findmax_heap(heap) +register heap_t *heap; +{ + if (heap->heapnum == 0) { + return NIL(heap_entry_t); + } else { + return heap->tree[1]; + } +} + +/* Swap entry s1 and s2 */ +void +swap_entry(s1, s2) +heap_entry_t *s1, *s2; +{ + heap_entry_t temp; + + temp = *s1; + *s1 = *s2; + *s2 = temp; +} + +/* Dynamically increase the size of heap */ +void +resize_heap(heap) +register heap_t *heap; +{ + heap->heapsize *= 2; + heap->tree = REALLOC(heap_entry_t *, heap->tree, heap->heapsize); +} + +/* Insert a new entry in the heap */ +void +insert_heap(heap, entry) +register heap_t *heap; +register heap_entry_t *entry; +{ + int current, parent; + + if ((++heap->heapnum) >= heap->heapsize) (void) resize_heap(heap); + current = (heap->heapnum); + heap->tree[current] = entry; + parent = current/2; + while ((heap->tree[parent])->key < (heap->tree[current])->key) { + swap_entry(heap->tree[parent], heap->tree[current]); + current = parent; + parent = current/2; + } +} + + +/* Delete the topest in the heap and return this entry, if empty(heap) then + * return NILL. + */ +heap_entry_t * +deletemax_heap(heap) +register heap_t *heap; +{ + int current = 1; + int child = 2; + heap_entry_t *entry; + + if (heap->heapnum == 0) return NIL(heap_entry_t); + entry = heap->tree[1]; + heap->tree[1] = heap->tree[(heap->heapnum)--]; + + while (child <= heap->heapnum) { + if ((child < heap->heapnum) && + (heap->tree[child+1]->key > heap->tree[child]->key)) child++; + if (heap->tree[current]->key < heap->tree[child]->key) { + swap_entry(heap->tree[current], heap->tree[child]); + current = child; + child = 2 * current; + } else { + break; + } + } + return entry; +} diff --git a/sis/extract/heap.h b/sis/extract/heap.h new file mode 100644 index 0000000..f25f9be --- /dev/null +++ b/sis/extract/heap.h @@ -0,0 +1,38 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/heap.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +/* Author : Huey-Yih Wang */ +/* Date : Nov 1. 1990 */ +/* Dynamic 2-heap data structure */ + +/* Entry in the heap */ +typedef struct heap_entry_struct heap_entry_t; +struct heap_entry_struct { + int key; /* Comparison key */ + char *item; /* Item pointer */ +}; + +/* Heap structure */ +typedef struct heap_struct heap_t; +struct heap_struct { + int heapnum; /* Currently the number of objects in the heap. */ + int heapsize; /* Currently allowed size of the heap */ + heap_entry_t **tree; /* Heap tree structure */ +}; + +/* heap.c */ +extern heap_entry_t *heap_entry_alloc(); +extern void heap_entry_free(); +extern heap_t *heap_alloc(); +extern void heap_free(); +extern heap_entry_t *findmax_heap(); +extern void swap_entry(); +extern void resize_heap(); +extern void insert_heap(); +extern heap_entry_t *deletemax_heap(); diff --git a/sis/extract/kernel.c b/sis/extract/kernel.c new file mode 100644 index 0000000..c50a2f2 --- /dev/null +++ b/sis/extract/kernel.c @@ -0,0 +1,569 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/kernel.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + + +int cube_extract_debug; +int kernel_extract_debug; +int greedy_col_debug; +int greedy_row_debug; +int ping_pong_debug; + + +static void dump_fct(); +static void dump_cube(); +static void dump_literal(); +static void dump_subkernel(); +static void dump_kernel_table(); +static void dump_kernel(); +static int record_kernel(); +static void clear_kernel_rect(); + + +/* + * kernel_cube_table -- maps between kernel cubes and columns of the + * kernel-cube matrix. + */ +static cubeindex_t *kernel_cube_table; + + +/* + * co_kernel_table -- maps between the co-kernel cubes and the rows of + * the kernel-cube matrix. (It is simply an array because we never need + * to find the index given a cube) + */ +array_t *co_kernel_table; + + +/* + * kernel_cube_matrix -- a sparse matrix with 1 row for each kernel of + * each function. Each row has an associated co-kernel, and each column + * has an associated kernel cube. Each entry contains a 'value_cell' + * which gives the value of the cube covered by that entry, and which + * gives the function and cube number. Each cube of a function is represented + * by only 1 value_cell even though it may appear multiple times in the + * sparse matrix (that is, it may be covered by many different kernels). + * Thus, the aliasing effect of covering a cube is easily detected. + */ +sm_matrix *kernel_cube_matrix; + + +/* + * costs for each kernel cube (row_cost) and each co-kernel cube (col_cost) + */ +array_t *global_row_cost; +array_t *global_col_cost; + +static value_cell_t **function_cubes; + +void +kernel_extract_init() +{ + kernel_cube_table = cubeindex_alloc(); + co_kernel_table = array_alloc(sm_row *, 0); + kernel_cube_matrix = sm_alloc(); +} + + +void +kernel_extract(A, sis_index, use_all_kernels) +sm_matrix *A; +int sis_index; +int use_all_kernels; +{ + sm_row *prow; + + if (A->nrows == 0) return; /* ignore empty functions */ + + /* allocate 1 value_cell for each cube in the function */ + function_cubes = ALLOC(value_cell_t *, A->last_row->row_num + 1); + sm_foreach_row(A, prow) { + function_cubes[prow->row_num] = value_cell_alloc(); + function_cubes[prow->row_num]->sis_index = sis_index; + function_cubes[prow->row_num]->cube_number = prow->row_num; + function_cubes[prow->row_num]->value = prow->length; + } + + /* generate the kernels of the function (including A itself) */ + gen_all_rectangles(A, record_kernel, (char *) use_all_kernels); + + /* Free the values cells -- remember, they are reference counted */ + sm_foreach_row(A, prow) { + value_cell_free(function_cubes[prow->row_num]); + } + FREE(function_cubes); +} + + +void +kernel_extract_end() +{ + sm_row *prow; + sm_col *pcol; + sm_row *kernel_cube, *co_kernel; + int k; + + /* setup the row cost array (the cost of each co-kernel) */ + global_row_cost = array_alloc(int, 0); + sm_foreach_row(kernel_cube_matrix, prow) { + co_kernel = array_fetch(sm_row *, co_kernel_table, prow->row_num); + k = co_kernel->length + 1; + array_insert(int, global_row_cost, prow->row_num, k); + } + + /* setup the column cost array (the cost of each kernel-cube) */ + global_col_cost = array_alloc(int, 0); + sm_foreach_col(kernel_cube_matrix, pcol) { + kernel_cube = cubeindex_getcube(kernel_cube_table, pcol->col_num); + array_insert(int, global_col_cost, pcol->col_num, kernel_cube->length); + } +} + + +void +kernel_extract_free() +{ + int i; + + cubeindex_free(kernel_cube_table); + + for(i = 0; i < array_n(co_kernel_table); i++) { + sm_row_free(array_fetch(sm_row *, co_kernel_table, i)); + } + array_free(co_kernel_table); + free_value_cells(kernel_cube_matrix); + sm_free(kernel_cube_matrix); + + array_free(global_row_cost); + array_free(global_col_cost); +} + +static int +record_kernel(co_rect, rect, state) +sm_matrix *co_rect; +rect_t *rect; +char *state; +{ + register int rownum, colnum; + register sm_row *prow; + sm_row *row; + sm_element *p; + int use_all_kernels = (int) state; + + if (use_all_kernels || ex_is_level0_kernel(co_rect)) { + + /* Record the kernel as a row in the kernel_cube matrix */ + rownum = kernel_cube_matrix->nrows; + sm_foreach_row(co_rect, prow) { + + /* find the column for this kernel cube */ + colnum = cubeindex_getindex(kernel_cube_table, prow); + p = sm_insert(kernel_cube_matrix, rownum, colnum); + + /* set the 'value_cell' for this entry -- bump reference count */ + function_cubes[prow->row_num]->ref_count++; + p->user_word = (char *) function_cubes[prow->row_num]; + } + + /* Save the co_kernel */ + row = sm_row_dup(rect->cols); + array_insert(sm_row *, co_kernel_table, rownum, row); + } + return 1; +} + +/* + * sparse_kernel_extract + * + * use_best_subkernel + * == 0 uses pingpong to select a good value rectangle + * == 1 uses best_subkernel to select the best value rectangle + * == 2 uses best_subkernel (and # literals in factored form) + * + * nonoverlapping: all entries of the kernel_cube_matrix which contain + * a particular value cell are removed before selecting the next subkernel + */ + +int +sparse_kernel_extract(value_threshold, use_best_subkernel) +int value_threshold, use_best_subkernel; +{ + array_t *fanout; + sm_row *kernel_cube; + sm_matrix *func; + sm_element *p; + rect_t *rect; + int nonzero, total, total_value; + double sparsity; + + if (kernel_extract_debug) { + if (kernel_extract_debug == 99) dump_kernel_table(); + nonzero = sm_num_elements(kernel_cube_matrix); + total = kernel_cube_matrix->nrows * kernel_cube_matrix->ncols; + sparsity = (double) nonzero / (double) total * 100.0; + (void) fprintf(sisout, + "kernel-cube matrix is %d by %d (%d nonzero, %4.3f%% sparse)\n", + kernel_cube_matrix->nrows, kernel_cube_matrix->ncols, + nonzero, sparsity); + } + + kernel_extract_end(); + + /* Extract the kernels */ + total_value = 0; + do { + rect = choose_subkernel(kernel_cube_matrix, + global_row_cost, global_col_cost, use_best_subkernel); + if (rect->rows->length == 0 || rect->cols->length == 0 || + rect->value <= value_threshold) { + rect_free(rect); + break; + } + + /* construct a sparse-matrix representing the function */ + func = sm_alloc(); + sm_foreach_row_element(rect->cols, p) { + kernel_cube = cubeindex_getcube(kernel_cube_table, p->col_num); + sm_copy_row(func, func->nrows, kernel_cube); + } + + /* add it to the network */ +#if 1 + fanout = find_rectangle_fanout(kernel_cube_matrix, rect); + (void) ex_divide_function_into_network(func, fanout, + NIL(array_t), kernel_extract_debug); +#else +sometimes for debugging thsi is better + fanout = find_rectangle_fanout_cubes(kernel_cube_matrix, rect, &cubes); + (void) ex_divide_function_into_network(func, fanout, cubes); + array_free(cubes); +#endif + array_free(fanout); + sm_free(func); + + if (kernel_extract_debug) { + (void) fprintf(sisout, + "subkernel rectangle is %d by %d with value %d\n", + rect->rows->length, rect->cols->length, rect->value); + if (kernel_extract_debug > 1) { + dump_subkernel(rect); + } + } + + clear_kernel_rect(kernel_cube_matrix, rect); + total_value += rect->value; + rect_free(rect); + } while (kernel_cube_matrix->nrows > 0); /* make lint happy */ + + return total_value; +} + +int +ex_is_level0_kernel(A) +sm_matrix *A; +{ + register sm_col *pcol; + + if (A->nrows <= 1) { + return 0; + } else { + sm_foreach_col(A, pcol) { + if (pcol->length > 1) { + return 0; + } + } + return 1; + } +} + + + +static void +clear_kernel_rect(A, rect) +sm_matrix *A; +rect_t *rect; +{ + register sm_element *p1, *p2, *p; + register sm_row *prow; + sm_row *next_row; + st_table *value_table; + + value_table = st_init_table(st_ptrcmp, st_ptrhash); + + sm_foreach_col_element(rect->rows, p1) { + sm_foreach_row_element(rect->cols, p2) { + p = sm_find(A, p1->row_num, p2->col_num); + assert(p != NIL(sm_element)); + (void) st_insert(value_table, p->user_word, NIL(char)); + value_cell_free((value_cell_t *) p->user_word); + sm_remove_element(A, p); + } + } + + for(prow = A->first_row; prow != 0; prow = next_row) { + next_row = prow->next_row; + for(p = prow->first_col; p != 0; p = p1) { + p1 = p->next_col; + if (st_lookup(value_table, p->user_word, NIL(char *))) { + value_cell_free((value_cell_t *) p->user_word); + sm_remove_element(A, p); + } + } + } + st_free_table(value_table); +} + +/* + * overlapping kernel extraction + */ + +static void overlapping_clear_rect(); + + +int +overlapping_kernel_extract(value_threshold, use_best_subkernel) +int value_threshold, use_best_subkernel; +{ + array_t *fanout, *cubes; + sm_row *kernel_cube; + sm_matrix *func; + sm_element *p; + rect_t *rect; + int nonzero, total, total_value; + double sparsity; + + if (kernel_extract_debug) { + nonzero = sm_num_elements(kernel_cube_matrix); + total = kernel_cube_matrix->nrows * kernel_cube_matrix->ncols; + sparsity = (double) nonzero / (double) total * 100.0; + (void) fprintf(sisout, + "kernel-cube matrix is %d by %d (%d nonzero, %4.3f%% sparse)\n", + kernel_cube_matrix->nrows, kernel_cube_matrix->ncols, + nonzero, sparsity); + } + + kernel_extract_end(); + + /* Extract the kernels */ + total_value = 0; + do { + rect = choose_subkernel(kernel_cube_matrix, + global_row_cost, global_col_cost, use_best_subkernel); + if (rect->rows->length == 0 || rect->cols->length == 0 || + rect->value <= value_threshold) { + rect_free(rect); + break; + } + + /* construct a sparse-matrix representing the function */ + func = sm_alloc(); + sm_foreach_row_element(rect->cols, p) { + kernel_cube = cubeindex_getcube(kernel_cube_table, p->col_num); + sm_copy_row(func, func->nrows, kernel_cube); + } + + /* add it to the network */ + fanout = find_rectangle_fanout_cubes(kernel_cube_matrix, rect, &cubes); + (void) ex_divide_function_into_network(func, fanout, + cubes, kernel_extract_debug); + array_free(fanout); + sm_free(func); + + if (kernel_extract_debug) { + (void) fprintf(sisout, + "subkernel rectangle is %d by %d with value %d\n", + rect->rows->length, rect->cols->length, rect->value); + if (kernel_extract_debug > 1) { + dump_subkernel(rect); + } + } + + overlapping_clear_rect(kernel_cube_matrix, rect); + total_value += rect->value; + rect_free(rect); + } while (kernel_cube_matrix->nrows > 0); + + return total_value; +} + +static void +overlapping_clear_rect(A, rect) +sm_matrix *A; +rect_t *rect; +{ + register sm_element *p1, *p2, *p; + + sm_foreach_col_element(rect->rows, p1) { + sm_foreach_row_element(rect->cols, p2) { + p = sm_find(A, p1->row_num, p2->col_num); + assert(p != NIL(sm_element)); + VALUE(p) = 0; + } + } +} + +static void +dump_literal(fp, index) +FILE *fp; +int index; +{ + (void) fputs(ex_map_index_to_name(index/2), fp); + if ((index%2) == 1) putc('\'', fp); +} + + +static void +dump_cube(fp, cube) +FILE *fp; +sm_row *cube; +{ + sm_element *p; + int first; + + first = 1; + sm_foreach_row_element(cube, p) { + if (! first) putc(' ', fp); + dump_literal(fp, p->col_num); + first = 0; + } +} + + +static void +dump_fct(fp, fct) +FILE *fp; +sm_matrix *fct; +{ + sm_row *cube; + int first; + + first = 1; + sm_foreach_row(fct, cube) { + if (! first) (void) fputs(" + ", fp); + dump_cube(fp, cube); + first = 0; + } +} + +static void +dump_kernel(fp, kernel) +FILE *fp; +sm_row *kernel; +{ + sm_row *kernel_cube; + sm_element *p; + int first; + + first = 1; + sm_foreach_row_element(kernel, p) { + if (! first) (void) fputs(" + ", fp); + kernel_cube = cubeindex_getcube(kernel_cube_table, p->col_num); + dump_cube(fp, kernel_cube); + first = 0; + } +} + + +static void +dump_subkernel(rect) +rect_t *rect; +{ + sm_matrix *func, *func1; + + func = ex_rect_to_kernel(rect); + func1 = ex_rect_to_cokernel(rect); + + (void) fprintf(sisout, "subkernel: "); + dump_fct(sisout, func); + (void) fprintf(sisout, "\n"); + (void) fprintf(sisout, "co-kernel: "); + dump_fct(sisout, func1); + (void) fprintf(sisout, "\n"); + + sm_free(func); + sm_free(func1); +} + +static void +dump_kernel_table() +{ + sm_row *kernel, *co_kernel, *kernel_cube; + sm_element *p; + value_cell_t *value_cell; + + (void) fprintf(sisout, "Kernel cube matrix is\n"); + sm_print(sisout, kernel_cube_matrix); + + (void) fprintf(sisout, "\nKernels are\n"); + sm_foreach_row(kernel_cube_matrix, kernel) { + (void) fprintf(sisout, "kernel %3d: ", kernel->row_num); + dump_kernel(sisout, kernel); + (void) fprintf(sisout, " (co-kernel="); + co_kernel = array_fetch(sm_row *, co_kernel_table, kernel->row_num); + dump_cube(sisout, co_kernel); + (void) fprintf(sisout, ")\n"); + } + + (void) fprintf(sisout, "\nkernels are (gross detail)\n"); + sm_foreach_row(kernel_cube_matrix, kernel) { + (void) fprintf(sisout, "kernel %d: co-kernel: ", kernel->row_num); + co_kernel = array_fetch(sm_row *, co_kernel_table, kernel->row_num); + dump_cube(sisout, co_kernel); + (void) fprintf(sisout, "\n"); + + sm_foreach_row_element(kernel, p) { + value_cell = (value_cell_t *) p->user_word; + (void) fprintf(sisout, + " col=%3d sis-fct=%-10s cube=%2d literals=%2d: ", + p->col_num, ex_map_index_to_name(value_cell->sis_index), + value_cell->cube_number, value_cell->value); + kernel_cube = cubeindex_getcube(kernel_cube_table, p->col_num); + dump_cube(sisout, kernel_cube); + (void) fprintf(sisout, "\n"); + } + } + (void) fprintf(sisout, "\n"); +} + +sm_matrix * +ex_rect_to_kernel(rect) +rect_t *rect; +{ + sm_matrix *func; + sm_row *cube; + sm_element *p; + + /* construct a sparse-matrix representing the kernel */ + func = sm_alloc(); + sm_foreach_row_element(rect->cols, p) { + cube = cubeindex_getcube(kernel_cube_table, p->col_num); + sm_copy_row(func, func->nrows, cube); + } + return func; +} + + +sm_matrix * +ex_rect_to_cokernel(rect) +rect_t *rect; +{ + sm_matrix *func; + sm_row *cube; + sm_element *p; + + /* construct a sparse-matrix representing the co-kernel */ + func = sm_alloc(); + sm_foreach_col_element(rect->rows, p) { + cube = array_fetch(sm_row *, co_kernel_table, p->row_num); + sm_copy_row(func, func->nrows, cube); + } + return func; +} diff --git a/sis/extract/misc.c b/sis/extract/misc.c new file mode 100644 index 0000000..5a1c92d --- /dev/null +++ b/sis/extract/misc.c @@ -0,0 +1,113 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/misc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + + +/* + * return a vector of the unique fanouts involved in a rectangle + * + * That is, find all unique references to a sis_index inside the value + * cell for every element in the rectangle + */ + +array_t * +find_rectangle_fanout(A, rect) +sm_matrix *A; +rect_t *rect; +{ + register sm_element *p1, *p2, *p; + st_table *fanout_table; + st_generator *gen; + array_t *fanouts; + value_cell_t *value_cell; + char *key; + + /* + * Find all of the functions it fans out to + */ + fanout_table = st_init_table(st_numcmp, st_numhash); + sm_foreach_col_element(rect->rows, p1) { + sm_foreach_row_element(rect->cols, p2) { + p = sm_find(A, p1->row_num, p2->col_num); + value_cell = (value_cell_t *) p->user_word; + key = (char *) value_cell->sis_index; + (void) st_insert(fanout_table, key, NIL(char)); + } + } + + /* + * now pull the unique functions out and put them in an array + */ + fanouts = array_alloc(char *, 0); + st_foreach_item(fanout_table, gen, &key, NIL(char *)) { + array_insert_last(char *, fanouts, key); + } + st_free_table(fanout_table); + + return fanouts; +} + +/* + * return a vector of the unique fanouts involved in a rectangle, and also + * return a vector of the cubes which are involved in this rectangle + * + * That is, find all unique references to a sis_index inside the value + * cell for every element in the rectangle + */ + +array_t * +find_rectangle_fanout_cubes(A, rect, cubes) +sm_matrix *A; +rect_t *rect; +array_t **cubes; +{ + register sm_element *p1, *p2, *p; + sm_row *row; + st_table *fanout_table; + st_generator *gen; + array_t *fanouts; + value_cell_t *value_cell; + char *key, *value; + + /* + * Find all of the functions (and cubes) it fans out to + */ + fanout_table = st_init_table(st_numcmp, st_numhash); + sm_foreach_col_element(rect->rows, p1) { + sm_foreach_row_element(rect->cols, p2) { + p = sm_find(A, p1->row_num, p2->col_num); + value_cell = (value_cell_t *) p->user_word; + key = (char *) value_cell->sis_index; + if (st_lookup(fanout_table, key, &value)) { + row = (sm_row *) value; + } else { + row = sm_row_alloc(); + value = (char *) row; + (void) st_insert(fanout_table, key, value); + } + + (void) sm_row_insert(row, value_cell->cube_number); + } + } + + /* + * put the fanout functions into an array along with the covered cubes + */ + fanouts = array_alloc(int, 0); + *cubes = array_alloc(sm_row *, 0); + st_foreach_item(fanout_table, gen, &key, &value) { + array_insert_last(char *, fanouts, key); + array_insert_last(char *, *cubes, value); + } + st_free_table(fanout_table); + + return fanouts; +} diff --git a/sis/extract/pingpong.c b/sis/extract/pingpong.c new file mode 100644 index 0000000..5d1bc40 --- /dev/null +++ b/sis/extract/pingpong.c @@ -0,0 +1,256 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/pingpong.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + +#define PING_MAXINT (1 << 30) + + +static int +row_value(prow, row_cost) +sm_row *prow; +array_t *row_cost; +{ + register sm_element *p; + register int value; + + value = - array_fetch(int, row_cost, prow->row_num); + sm_foreach_row_element(prow, p) { + value = value + VALUE(p); + } + return value; +} + + +static sm_row * +choose_row_seed(A, row_cost) +sm_matrix *A; +array_t *row_cost; +{ + register int value, max_value; + sm_row *prow, *best_row; + + /* choose row with maximum value */ + max_value = - PING_MAXINT; + best_row = NIL(sm_row); + sm_foreach_row(A, prow) { + value = row_value(prow, row_cost); + if (value > max_value) { + max_value = value; + best_row = prow; + } + } + return best_row; +} + + +static sm_row * +choose_next_row_seed(A, row_cost, rect) +sm_matrix *A; +array_t *row_cost; +rect_t *rect; +{ + register int value, max_value; + register sm_element *p; + sm_row *prow, *best_row; + + /* choose row (in rect->rows) with maximum value */ + max_value = - PING_MAXINT; + best_row = NIL(sm_row); + sm_foreach_col_element(rect->rows, p) { + prow = sm_get_row(A, p->row_num); + value = row_value(prow, row_cost); + if (value > max_value) { + max_value = value; + best_row = prow; + } + } + return best_row; +} + +static int +col_value(pcol, col_cost) +sm_col *pcol; +array_t *col_cost; +{ + register sm_element *p; + register int value; + + value = - array_fetch(int, col_cost, pcol->col_num); + sm_foreach_col_element(pcol, p) { + value = value + VALUE(p); + } + return value; +} + + +static sm_col * +choose_col_seed(A, col_cost) +sm_matrix *A; +array_t *col_cost; +{ + register int value, max_value; + sm_col *pcol, *best_col; + + /* choose col with maximum value */ + max_value = - PING_MAXINT; + best_col = NIL(sm_col); + sm_foreach_col(A, pcol) { + value = col_value(pcol, col_cost); + if (value > max_value) { + max_value = value; + best_col = pcol; + } + } + return best_col; +} + + +static sm_col * +choose_next_col_seed(A, col_cost, rect) +sm_matrix *A; +array_t *col_cost; +rect_t *rect; +{ + register int value, max_value; + register sm_element *p; + sm_col *pcol, *best_col; + + /* choose col (in rect->cols) with maximum value */ + max_value = - PING_MAXINT; + best_col = NIL(sm_col); + sm_foreach_row_element(rect->cols, p) { + pcol = sm_get_col(A, p->col_num); + value = col_value(pcol, col_cost); + if (value > max_value) { + max_value = value; + best_col = pcol; + } + } + return best_col; +} + +static int +update_best(rect1, rect2, best_rect) +rect_t *rect1, *rect2, **best_rect; +{ + int got_new_best; + + got_new_best = 0; + if (rect1->value >= rect2->value) { + rect_free(rect2); + if (rect1->value > (*best_rect)->value) { + rect_free(*best_rect); + *best_rect = rect1; + } else { + rect_free(rect1); + } + } else { + /* rectangle 2 beats rectangle 1 -- good news */ + rect_free(rect1); + if (rect2->value > (*best_rect)->value) { + rect_free(*best_rect); + *best_rect = rect2; + got_new_best = 1; + } else { + rect_free(rect2); + } + } + return got_new_best; +} + +static rect_t * +ping_pong_improve(A, row_cost, col_cost, best_rect) +sm_matrix *A; +array_t *row_cost, *col_cost; +rect_t *best_rect; +{ + rect_t *rect1, *rect2; + sm_row *best_row; + sm_col *best_col; + int got_new_best; + + rect2 = best_rect; + do { + best_row = choose_next_row_seed(A, row_cost, rect2); + if (best_row == NIL(sm_row)) return best_rect; + rect1 = greedy_row(A, row_cost, col_cost, best_row); + if (ping_pong_debug) { + (void) printf("ping_pong: ... pinging rows %d by %d value=%d\n", + rect1->rows->length, rect1->cols->length, rect1->value); + } + if (rect1->value < 1) { + rect_free(rect1); + break; + } + + best_col = choose_next_col_seed(A, col_cost, rect1); + if (best_col == NIL(sm_col)) return best_rect; + rect2 = greedy_col(A, col_cost, row_cost, best_col); + if (ping_pong_debug) { + (void) printf("ping_pong: ... pinging cols %d by %d value=%d\n", + rect2->rows->length, rect2->cols->length, rect2->value); + } + + got_new_best = update_best(rect1, rect2, &best_rect); + } while (got_new_best); + + return best_rect; +} + + +static rect_t * +ping_pong_onepass(A, row_cost, col_cost) +sm_matrix *A; +array_t *row_cost, *col_cost; +{ + sm_row *row_seed; + sm_col *col_seed; + rect_t *rect1, *rect2; + + row_seed = choose_row_seed(A, row_cost); + if (row_seed == NIL(sm_row)) return rect_alloc(); + rect1 = greedy_row(A, row_cost, col_cost, row_seed); + if (ping_pong_debug) { + (void) printf("ping_pong: row pass gives %d by %d value=%d\n", + rect1->rows->length, rect1->cols->length, rect1->value); + } + + col_seed = choose_col_seed(A, col_cost); + if (col_seed == NIL(sm_col)) return rect1; + rect2 = greedy_col(A, col_cost, row_cost, col_seed); + if (ping_pong_debug) { + (void) printf("ping_pong: col pass gives %d by %d value=%d\n", + rect2->rows->length, rect2->cols->length, rect2->value); + } + + if (rect1->value > rect2->value) { + rect_free(rect2); + return rect1; + } else { + rect_free(rect1); + return rect2; + } +} + + +rect_t * +ping_pong(A, row_cost, col_cost) +sm_matrix *A; +array_t *row_cost, *col_cost; +{ + rect_t *best_rect; + + best_rect = ping_pong_onepass(A, row_cost, col_cost); + if (best_rect->rows->length > 0 && best_rect->cols->length > 0) { + best_rect = ping_pong_improve(A, row_cost, col_cost, best_rect); + } + return best_rect; +} diff --git a/sis/extract/qdivisor.c b/sis/extract/qdivisor.c new file mode 100644 index 0000000..1533df2 --- /dev/null +++ b/sis/extract/qdivisor.c @@ -0,0 +1,48 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/qdivisor.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" + +node_t * +ex_find_divisor_quick(node) +node_t *node; +{ + register int *count, i; + int best, pos, phase, loops; + node_t *q, *f, *lit; + + f = node_dup(node); + for(loops = 0; ; loops++) { + count = node_literal_count(f); + best = 0; + for(i = 2*node_num_fanin(f)-1; i >= 0; i--) { + if (count[i] > best) { + best = count[i]; + pos = i/2; + phase = 1 - i%2; + } + } + FREE(count); + + if (best <= 1) break; + + lit = node_literal(node_get_fanin(f, pos), phase); + q = node_div(f, lit, NIL(node_t *)); + node_free(f); + node_free(lit); + f = q; + } + + if (loops == 0) { + node_free(f); + return 0; + } else { + return f; + } +} diff --git a/sis/extract/rect.c b/sis/extract/rect.c new file mode 100644 index 0000000..9f160b3 --- /dev/null +++ b/sis/extract/rect.c @@ -0,0 +1,137 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/rect.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:22 $ + * + */ +#include "sis.h" +#include "extract_int.h" + + +static void +gen_all_rect(M, rect, col, record, state) +sm_matrix *M; +rect_t *rect; +int col; +int (*record)(); +char *state; +{ + register sm_col *c, *pcol, *pcolnext; + register sm_element *p1; + sm_matrix *M1; + rect_t rect1; + int already_generated; + + /* Loop for all columns in the matrix (from 'col' onwards) */ + sm_foreach_col(M, c) { + if (c->length < 2 || c->col_num < col) continue; + + /* Copy all rows with a 1 in column 'c' */ + M1 = sm_alloc_size(M->last_row->row_num, M->last_col->col_num); + sm_foreach_col_element(c, p1) { + sm_copy_row(M1, p1->row_num, sm_get_row(M, p1->row_num)); + } + + /* + * new partial rectangle + */ + rect1.rows = sm_col_dup(c); + rect1.cols = sm_row_dup(rect->cols); + + /* + * factor out all columns of 'M1' which are all 1 + */ + already_generated = 0; + for(pcol = M1->first_col; pcol != 0; pcol = pcolnext) { + pcolnext = pcol->next_col; + if (pcol->length == c->length) { + if (pcol->col_num < c->col_num) { + already_generated = 1; + break; + } + (void) sm_row_insert(rect1.cols, pcol->col_num); + sm_delcol(M1, pcol->col_num); + } + } + + if (! already_generated) { + if ((*record)(M1, &rect1, state)) { + gen_all_rect(M1, &rect1, c->col_num, record, state); + } + } + + sm_row_free(rect1.cols); + sm_col_free(rect1.rows); + sm_free(M1); + } +} + +static int +has_full_column(M) +sm_matrix *M; +{ + register sm_col *pcol; + + sm_foreach_col(M, pcol) { + if (pcol->length == M->nrows) { + return 1; + } + } + return 0; +} + + +void +gen_all_rectangles(M, record, state) +sm_matrix *M; +int (*record)(); +char *state; +{ + rect_t *rect; + + rect = rect_alloc(); + gen_all_rect(M, rect, 0, record, state); + if (! has_full_column(M)) { + (*record)(M, rect, state); + } + rect_free(rect); +} + +rect_t * +rect_alloc() +{ + rect_t *rect; + + rect = ALLOC(rect_t, 1); + rect->rows = sm_col_alloc(); + rect->cols = sm_row_alloc(); + rect->value = 0; + return rect; +} + + +void +rect_free(rect) +rect_t *rect; +{ + sm_row_free(rect->cols); + sm_col_free(rect->rows); + FREE(rect); +} + + +rect_t * +rect_dup(old_rect) +rect_t *old_rect; +{ + rect_t *rect; + + rect = ALLOC(rect_t, 1); + rect->rows = sm_col_dup(old_rect->rows); + rect->cols = sm_row_dup(old_rect->cols); + rect->value = old_rect->value; + return rect; +} diff --git a/sis/extract/sdivisor.c b/sis/extract/sdivisor.c new file mode 100644 index 0000000..00317e9 --- /dev/null +++ b/sis/extract/sdivisor.c @@ -0,0 +1,440 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/sdivisor.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +#include "sis.h" +#include "extract_int.h" +#include "heap.h" +#include "fast_extract_int.h" + + +/* Memory allocation and free of sdivisor_t */ + +static sdivisor_t * +sdivisor_alloc() +{ + register sdivisor_t *sdivisor; + + sdivisor = ALLOC(sdivisor_t, 1); + sdivisor->col1 = sdivisor->col2 = -1; + sdivisor->coin = 0; + + return sdivisor; + +} + +static void +sdivisor_free(sdivisor) +char *sdivisor; +{ + sdivisor_t *sd = (sdivisor_t *) sdivisor; + + FREE(sd); +} + +/* Memory allocation and free of sdset_t */ + +sdset_t * +sdset_alloc() +{ + register sdset_t *sdset; + + sdset = ALLOC(sdset_t, 1); + sdset->index = -1; + sdset->columns = lsCreate(); + sdset->col_set = lsCreate(); + sdset->heap = heap_alloc(); + + return sdset; +} + +void +sdset_free(sdset) +sdset_t *sdset; +{ + void sdivisor_free(); + + lsDestroy(sdset->columns, free); + lsDestroy(sdset->col_set, free); + (void) heap_free(sdset->heap,sdivisor_free); + FREE(sdset); +} + +/* Memory allocation and free of col_cell_t */ + +static col_cell_t * +col_cell_alloc() +{ + register col_cell_t *col_cell; + + col_cell = ALLOC(col_cell_t, 1); + col_cell->num = col_cell->length = 0; + col_cell->handle = NULL; + + return col_cell; +} + + +static void +col_cell_free(col_cell) +col_cell_t *col_cell; +{ + FREE(col_cell); +} + +/* compare function which will sort array elements in increasing order */ + +static int +compare(obj1,obj2) +lsGeneric obj1, obj2; +{ + register sm_col *col1 = (sm_col *)obj1; + register sm_col *col2 = (sm_col *)obj2; + + return (col1->length - col2->length); +} + + +/* Find the unconsidered columns in the cube-literal matrix. */ +static void +find_unconsidered_cols(B, sdset) +sm_matrix *B; +sdset_t *sdset; +{ + int index = sdset->index; + lsGen gen; + lsHandle handle; + col_cell_t *col_cell; + sm_col *pcol; + char *data; + int i, compare(); + + /* If previous unconsidered cols set is not empty, then clean unavailable + * cols, else if there is no new cols, then return. + */ + + if (lsLength(sdset->columns)){ + lsForeachItem(sdset->columns, gen, col_cell) { + if (B->cols[col_cell->num] == 0) { + lsRemoveItem(col_cell->handle, &data); + FREE(col_cell); + } + } + } else { + if (index == B->last_col->col_num) return ; + } + + if (index == B->last_col->col_num) { + lsSort(sdset->columns, compare); + return ; + } + + /* Find the first column number not considered so far */ + + if (index < 0) { + pcol = B->first_col; + } else { + pcol = sm_get_col(B,index); + if (pcol != 0) { + pcol = pcol->next_col; + } else { + for (i = index; (pcol = B->cols[i]) == 0; i++); + } + } + + /* Append new columns to sdset->columns. */ + + for (; pcol != 0; pcol = pcol->next_col) { + col_cell = col_cell_alloc(); + col_cell->num = pcol->col_num; + col_cell->length = pcol->length; + lsNewEnd(sdset->columns, (lsGeneric) col_cell,&handle); + col_cell->handle = handle; + } + sdset->index = B->last_col->col_num; + lsSort(sdset->columns, compare); +} + + +/* Extract the columns which has coincidence k. */ +static array_t * +cols_extract(columns, k) +lsList columns; +int k; +{ + int flag = 1; + array_t *set; + col_cell_t *col_cell; + lsHandle handle; + char *data; + + set = array_alloc(col_cell_t *, 0); + + do { + lsLastItem(columns, (lsGeneric *) &col_cell, &handle); + if (col_cell) { + if (col_cell->length == k) { + (void) array_insert_last(col_cell_t *, set, col_cell); + lsRemoveItem(handle,&data); + } else { + flag = 0; + } + } else { + flag = 0; + } + } while (flag); + + return set; +} + + +/* Find all possible pairs in set, and compute coincidence, then store in + * the sdset->heap. + */ +static void +coin1_compute(B, set, sdset) +sm_matrix *B; +array_t *set; +sdset_t *sdset; +{ + int i, j; + sdivisor_t *sd; + sm_col *col, *col1, *col2; + heap_entry_t *entry; + col_cell_t *col_cell1, *col_cell2; + + if (array_n(set) == 1) return ; + + for (i=0; i < array_n(set)-1; i++) { + col_cell1 = array_fetch(col_cell_t *, set, i); + col1 = sm_get_col(B, col_cell1->num); + for (j=i+1; j < array_n(set); j++) { + sd = sdivisor_alloc(); + sd->col1 = col_cell1->num; + col_cell2 = array_fetch(col_cell_t *, set, j); + col2 = sm_get_col(B, col_cell2->num); + sd->col2 = col_cell2->num; + col = sm_col_and(col1, col2); + if ((sd->coin = col->length) > 2) { + entry = heap_entry_alloc(); + entry->key = sd->coin; + entry->item = (char *) sd; + (void) insert_heap(sdset->heap, entry); + } else { + (void) sdivisor_free((char *)sd); + } + (void) sm_col_free(col); + } + } +} + + +/* Find all possible pairs of set and sdset->col_set, compute coincidence, + * then store in sdset->heap. + */ +static void +coin2_compute(B, set, sdset) +sm_matrix *B; +array_t *set; +sdset_t *sdset; +{ + int i; + sdivisor_t *sd; + sm_col *col, *col1, *col2; + col_cell_t *col_cell1, *col_cell2; + heap_entry_t *entry; + lsGen gen; + char *data; + + if ((array_n(set)== 0) || (lsLength(sdset->col_set) == 0)) return ; + + for (i = 0; i < array_n(set); i++) { + col_cell1 = array_fetch(col_cell_t *, set, i); + col1 = sm_get_col(B, col_cell1->num); + lsForeachItem(sdset->col_set, gen, col_cell2) { + col2 = sm_get_col(B, col_cell2->num); + if (col2) { + sd = sdivisor_alloc(); + sd->col1 = col_cell1->num; + sd->col2 = col_cell2->num; + col = sm_col_and(col1, col2); + if ((sd->coin = col->length) > 2) { + entry = heap_entry_alloc(); + entry->key = sd->coin; + entry->item = (char *) sd; + (void) insert_heap(sdset->heap, entry); + } else { + (void) sdivisor_free((char *) sd); + } + (void) sm_col_free(col); + } else { + lsRemoveItem(col_cell2->handle, &data); + (void) col_cell_free((col_cell_t *) data); + } + } + } +} + +/* Append T into sdset->col_set. */ + +static void +sdset_append(sdset, T) +sdset_t *sdset; +array_t *T; +{ + col_cell_t *col_cell; + lsHandle handle; + int i; + + for (i = 0; i < array_n(T); i++) { + col_cell = array_fetch(col_cell_t *, T, i); + lsNewEnd(sdset->col_set, (lsGeneric) col_cell, &handle); + col_cell->handle = handle; + } +} + +/* Extracting single-cube divisor with exact two literals. + * B : cube_literal_matrix. + * sdset : single-cube divisor set. + * wdmax : the current maximum weight of double-cube divisor. + */ +static sdivisor_t * +find_sdivisor(B,sdset,wdmax) +sm_matrix *B; +sdset_t *sdset; +int wdmax; +{ + lsHandle handle; + sm_col *col; + heap_entry_t *maxheap, *entry; + sdivisor_t *candidate; + col_cell_t *col_cell; + array_t *T; + int k = 0; + int threshold = 0; + int HEAP_CHECK, NOITERATION; + sm_col *col1, *col2; + + + do { /* Iteration */ + /* k = maximum number of literals found in any column not considered + * so far. + */ + NOITERATION = 0; + if (lsLength(sdset->columns)) { + lsLastItem(sdset->columns, (lsGeneric *) &col_cell, &handle); + k = col_cell->length; + if ((k-2) > wdmax) { + T = cols_extract(sdset->columns, k); + (void) coin1_compute(B, T, sdset); + (void) coin2_compute(B, T, sdset); + (void) sdset_append(sdset, T); + (void) array_free(T); + } else { + NOITERATION = 1; + /* Look the top of heap, if weight is less than wdmax, + * then there is no better single-cube divisor. + */ + maxheap = findmax_heap(sdset->heap); + if (maxheap == NIL(heap_entry_t)) { + return NIL(sdivisor_t); + } else { + if ((maxheap->key - 2) <= wdmax) { + return NIL(sdivisor_t); + } + } + } + } else { + NOITERATION = 1; k = 0; + } + + /* threshold = (maxheap) */ + + HEAP_CHECK = 1; + + /* Find best single-cube divisor, and update top entry if it's not + * maximum. + */ + + do { /* Heap update */ + maxheap = deletemax_heap(sdset->heap); + if (maxheap == NIL(heap_entry_t)) { + if (NOITERATION) { + return NIL(sdivisor_t); + } else { + threshold = HEAP_CHECK = 0; + } + } else { + /* Get the top entry in the heap, and see if it has the + * same weight as previous weight or not. If yes, then + * choose it as divisor, else update and push it back into + * heap. + */ + candidate = (sdivisor_t *)maxheap->item; + (void) heap_entry_free(maxheap); + col1 = sm_get_col(B, candidate->col1); + col2 = sm_get_col(B, candidate->col2); + if ((col1) && (col2)) { + col = sm_col_and(col1, col2); + /* If candidate has the same weight as previous weight, + * it must imply that the top entry has max weight. + */ + if (col->length >= candidate->coin) { + threshold = candidate->coin = col->length; + HEAP_CHECK = 0; + (void) sm_col_free(col); + + if ((threshold >= k) && ((threshold - 2) > wdmax)) { + return candidate; + } else { + if (threshold <= 2) { + (void) sdivisor_free((char *) candidate); + } else { + entry = heap_entry_alloc(); + entry->key = candidate->coin; + entry->item = (char *) candidate; + (void) insert_heap(sdset->heap, entry); + } + } + } else { + /* If candidate still have the possibility to be + * divisor, then push it back, else throw it away. + */ + if (col->length > 2) { + entry = heap_entry_alloc(); + candidate->coin = entry->key = col->length; + entry->item = (char *) candidate; + (void) insert_heap(sdset->heap, entry); + } else { + (void) sdivisor_free((char *) candidate); + } + (void) sm_col_free(col); + } + } else { + HEAP_CHECK = 1; + (void) sdivisor_free((char *)candidate); + } + } + } while (HEAP_CHECK); + } while (NOITERATION == 0); + + return NIL(sdivisor_t); +} + + +sdivisor_t * +extract_sdivisor(B, sdset, wdmax) +sm_matrix *B; +sdset_t *sdset; +int wdmax; +{ + if (B->nrows == 0) return NIL(sdivisor_t); + + (void) find_unconsidered_cols(B, sdset); + return find_sdivisor(B,sdset,wdmax); +} diff --git a/sis/extract/value.c b/sis/extract/value.c new file mode 100644 index 0000000..3ad6275 --- /dev/null +++ b/sis/extract/value.c @@ -0,0 +1,50 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/extract/value.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +#include "sis.h" +#include "extract_int.h" + + +value_cell_t * +value_cell_alloc() +{ + value_cell_t *value_cell; + + value_cell = ALLOC(value_cell_t, 1); + value_cell->cube_number = 0; + value_cell->sis_index = -1; + value_cell->value = 1; + value_cell->ref_count = 1; + return value_cell; +} + + +void +value_cell_free(value_cell) +value_cell_t *value_cell; +{ + if (--value_cell->ref_count == 0) { + FREE(value_cell); + } +} + + +void +free_value_cells(A) +sm_matrix *A; +{ + register sm_row *prow; + register sm_element *p; + + sm_foreach_row(A, prow) { + sm_foreach_row_element(prow, p) { + value_cell_free((value_cell_t *) p->user_word); + } + } +} diff --git a/sis/factor/Makefile.am b/sis/factor/Makefile.am new file mode 100644 index 0000000..85c3924 --- /dev/null +++ b/sis/factor/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libfactor.a +libfactor_a_SOURCES = alg_ft.c com_ft.c elim.c factor.c ft_print.c \ + ft_util.c ft_value.c factor_int.h +pkginclude_HEADERS = factor.h +dist_doc_DATA = factor.doc diff --git a/sis/factor/Makefile.in b/sis/factor/Makefile.in new file mode 100644 index 0000000..bbb5bd3 --- /dev/null +++ b/sis/factor/Makefile.in @@ -0,0 +1,422 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libfactor_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/factor +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libfactor_a_AR = $(AR) $(ARFLAGS) +libfactor_a_LIBADD = +am_libfactor_a_OBJECTS = alg_ft.$(OBJEXT) com_ft.$(OBJEXT) \ + elim.$(OBJEXT) factor.$(OBJEXT) ft_print.$(OBJEXT) \ + ft_util.$(OBJEXT) ft_value.$(OBJEXT) +libfactor_a_OBJECTS = $(am_libfactor_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libfactor_a_SOURCES) +DIST_SOURCES = $(libfactor_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libfactor.a +libfactor_a_SOURCES = alg_ft.c com_ft.c elim.c factor.c ft_print.c \ + ft_util.c ft_value.c factor_int.h + +pkginclude_HEADERS = factor.h +dist_doc_DATA = factor.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/factor/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/factor/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libfactor.a: $(libfactor_a_OBJECTS) $(libfactor_a_DEPENDENCIES) + -rm -f libfactor.a + $(libfactor_a_AR) libfactor.a $(libfactor_a_OBJECTS) $(libfactor_a_LIBADD) + $(RANLIB) libfactor.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/factor/alg_ft.c b/sis/factor/alg_ft.c new file mode 100644 index 0000000..e9520c5 --- /dev/null +++ b/sis/factor/alg_ft.c @@ -0,0 +1,102 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/factor/alg_ft.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +/* + * alg_factor: algebraic factoring. + */ + +#include "sis.h" +#include "factor.h" +#include "factor_int.h" + +static void factor_special(); +static void factor_general(); + +/* + * 1. Algebraic factoring of f using the factor generated by gen. + * 2. f will become the root of the s-p tree for the factored form of f. + */ +void +factor_recur(f, gen_factor) +node_t *f; +node_t *(*gen_factor)(); +{ + node_t *k, *ck; + + if ((k = (*gen_factor)(f)) != NIL(node_t)) { + + ck = node_div(f, k, NIL(node_t *)); /* find the co-kernel */ + node_free(k); + + if (node_num_cube(ck) == 1) { + factor_special(f, ck, gen_factor); /* special case: f = c*q+r */ + } else { + factor_general(f, ck, gen_factor); /* general case: f = c*p*q+r */ + } + + node_free(ck); + } +} + +static void +factor_special(f, ck, gen_factor) +node_t *f, *ck; +node_t *(*gen_factor)(); +{ + node_t *bestl, *p1, *c1, *c2, *p; + + /* f = bestl*p1 + ...; p1 contains k for which ck is the co-kernel */ + bestl = factor_best_literal(f, ck); + p1 = node_div(f, bestl, NIL(node_t *)); + + /* f = c2*p + ...; p is cube-free */ + c1 = node_largest_cube_divisor(p1); + c2 = node_and(bestl, c1); + p = node_div(f, c2, NIL(node_t *)); + + node_free(p1); + node_free(c1); + node_free(c2); + node_free(bestl); + + (void) node_substitute(f, p, 0); + factor_recur(f, gen_factor); + factor_recur(p, gen_factor); + +} + +static void +factor_general(f, ck, gen_factor) +node_t *f, *ck; +node_t *(*gen_factor)(); +{ + node_t *c1, *p, *q1, *c2, *q; + + /* f = c1*p + ...; c1*p = ck */ + c1 = node_largest_cube_divisor(ck); + p = node_div(ck, c1, NIL(node_t *)); + + /* f = q1*p + ...; q1 containts ck */ + q1 = node_div(f, p, NIL(node_t *)); + + /* f = c2*q*p + ...; c2*q = q1 */ + c2 = node_largest_cube_divisor(q1); + q = node_div(q1, c2, NIL(node_t *)); + + node_free(c1); + node_free(q1); + node_free(c2); + + (void) node_substitute(f, p, 0); + (void) node_substitute(f, q, 0); + + factor_recur(f, gen_factor); + factor_recur(p, gen_factor); + factor_recur(q, gen_factor); +} diff --git a/sis/factor/com_ft.c b/sis/factor/com_ft.c new file mode 100644 index 0000000..6067cdb --- /dev/null +++ b/sis/factor/com_ft.c @@ -0,0 +1,382 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/factor/com_ft.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +#include "sis.h" +#include "factor.h" +#include "factor_int.h" + +#define PV_ANY 0 +#define PV_DESCENDING 1 +#define PV_ASCENDING 2 + +static node_t *first_fanin(); +static void factor_usage(); +static int el_valid_val(); + +int +com_factor(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, method; + array_t *nodevec; + node_t *np; + int i; + + method = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "bgq")) != EOF) { + switch (c) { + case 'q': + method = 0; + break; + case 'g': + method = 1; + break; + case 'b': + method = 2; + break; + default: + factor_usage(); + return 1; + } + } + + if (argc - util_optind == 0) { + factor_usage(); + return 1; + } + + nodevec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + for(i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + if (np->type == INTERNAL) { + switch (method) { + case 0: + factor_quick(np); + break; + case 1: + factor_good(np); + break; + case 2: + (void) fprintf(misout, "boolean factoring is not available\n"); + array_free(nodevec); + return 1; + } + } + } + array_free(nodevec); + return 0; +} + +int +com_pf(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *nodevec; + int i, n; + node_t *np, *fanin; + + nodevec = com_get_nodes(*network, argc, argv); + n = array_n(nodevec); + for(i = 0; i < n; i++) { + np = array_fetch(node_t *, nodevec, i); + switch (np->type) { + case PRIMARY_INPUT: + break; + case PRIMARY_OUTPUT: + fanin = first_fanin(np); + if (fanin->type == PRIMARY_INPUT) { + (void) fprintf(misout, " %s = ", node_name(np)); + (void) fprintf(misout, "%s\n", node_name(fanin)); + } + break; + default: + (void) fprintf(misout, " %s = ", node_name(np)); + factor_print(misout, np); + (void) fprintf(misout, "\n"); + } + } + array_free(nodevec); + return 0; +} + +int +com_pv(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *nodevec; + int i, j, n, num; + int order, c; + node_t *np; + + order = PV_ANY; + num = INFINITY; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "p:ad")) != EOF) { + switch (c) { + case 'p': + num = atoi(util_optarg); + break; + case 'a': + order = PV_ASCENDING; + break; + case 'd': + order = PV_DESCENDING; + break; + default: + (void) fprintf(misout, "usage: print_value [-pr] [node-list]\n"); + (void) fprintf(misout, " -p\tn\tOnly print top 'n' values\n"); + (void) fprintf(misout, " -d\t\tPrint values in in"); + (void) fprintf(misout, "descending order\n"); + (void) fprintf(misout, " -a\t\tPrint values in in"); + (void) fprintf(misout, "ascending order\n"); + return 1; + } + } + + nodevec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + + switch (order) { + case PV_ASCENDING: + array_sort(nodevec, value_cmp_inc); + break; + case PV_DESCENDING: + array_sort(nodevec, value_cmp_dec); + break; + case PV_ANY: + break; + } + + n = array_n(nodevec); + j = 0; + for(i = 0; i < n && j < num ; i++) { + np = array_fetch(node_t *, nodevec, i); + switch (np->type) { + case PRIMARY_INPUT: + case PRIMARY_OUTPUT: + break; + default: + value_print(misout, np); + j++; + } + } + array_free(nodevec); + return 0; +} + +int +com_pft(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *nodevec; + int i, n; + node_t *np; + + nodevec = com_get_nodes(*network, argc, argv); + n = array_n(nodevec); + for(i = 0; i < n; i++) { + np = array_fetch(node_t *, nodevec, i); + switch (np->type) { + case PRIMARY_INPUT: + case PRIMARY_OUTPUT: + break; + default: + (void) fprintf(misout, "--- %s ---\n", node_name(np)); + if (np->factored == NIL(char)) { + (void) fprintf(misout, "empty.\n"); + } else { + ft_print(np, (ft_t *) np->factored, 0); + } + } + } + array_free(nodevec); + return 0; +} + +static char * +my_node_long_name(node) +node_t *node; +{ + if (name_mode == LONG_NAME_MODE) { + if (node->name == NIL(char)) node_assign_name(node); + } else { + if (node->short_name == NIL(char)) node_assign_short_name(node); + } + + return node->name; +} + +int +com_factor_conv(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *nodevec, *fa; + int i, j, k; + node_t *f, *np, *fanin; + + nodevec = com_get_nodes(*network, argc, argv); + for(i = 0; i < array_n(nodevec); i++) { + f = array_fetch(node_t *, nodevec, i); + if (f->type == INTERNAL) { + (void) fprintf(misout, " %s = ", node_name(f)); + factor_print(misout, f); + (void) fprintf(misout, "\n"); + fa = factor_to_nodes(f); + for (j = 0; j < array_n(fa); j++) { + np = array_fetch(node_t *, fa, j); + switch (node_function(np)) { + case NODE_AND: + (void) fprintf(misout, "\t%s = AND(", my_node_long_name(np)); + foreach_fanin(np, k, fanin) { + (void) fprintf(misout, " %s", + my_node_long_name(fanin)); + } + (void) fprintf(misout, ")\n"); + break; + case NODE_OR: + (void) fprintf(misout, "\t%s = OR(", my_node_long_name(np)); + foreach_fanin(np, k, fanin) { + (void) fprintf(misout, " %s", + my_node_long_name(fanin)); + } + (void) fprintf(misout, ")\n"); + break; + case NODE_BUF: + fanin = node_get_fanin(np, 0); + (void) fprintf(misout, "\t%s = BUF", my_node_long_name(np)); + (void) fprintf(misout, "(%s)\n", + my_node_long_name(fanin)); + break; + case NODE_INV: + fanin = node_get_fanin(np, 0); + (void) fprintf(misout, "\t%s = INV", my_node_long_name(np)); + (void) fprintf(misout, "(%s)\n", + my_node_long_name(fanin)); + break; + case NODE_0: + (void) fprintf(misout, "\t%s = 0\n", my_node_long_name(np)); + break; + case NODE_1: + (void) fprintf(misout, "\t%s = 1\n", my_node_long_name(np)); + break; + default: + (void) fprintf(misout, "illegal node function\n"); + return 1; + } + node_free(np); + } + array_free(fa); + (void) fprintf(misout, "\n"); + } + } + array_free(nodevec); + return 0; +} + +int +com_eliminate(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int limit, value; + + limit = 1000; + if (argc == 2) { + if (el_valid_val(argv[1])){ + value = atoi(argv[1]); + } else goto usage; + } else if (argc == 4 && strcmp(argv[1], "-l") == 0) { + if (el_valid_val(argv[2])){ + limit = atoi(argv[2]); + } else goto usage; + if (el_valid_val(argv[3])){ + value = atoi(argv[3]); + } else goto usage; + } else goto usage; + + eliminate(*network, value, limit); + return 0; +usage: + (void) fprintf(miserr, "usage: eliminate [-l limit] value\n"); + return 1; +} + +static int +el_valid_val(s) +char *s; +{ + int i, first; + + first = (*s == '-' ? 1 : 0); + for (i = first; i < strlen(s); i++) { + if (!isdigit(*(s+i))) return 0; + } + return 1; +} + + +init_factor() +{ + set_line_width(); + + node_register_daemon(DAEMON_ALLOC, factor_alloc); + node_register_daemon(DAEMON_FREE, factor_free); + node_register_daemon(DAEMON_DUP, factor_dup); + node_register_daemon(DAEMON_INVALID, factor_invalid); + + com_add_command("print_value", com_pv, 0); + com_add_command("print_factor", com_pf, 0); + com_add_command("factor", com_factor, 1); + com_add_command("eliminate", com_eliminate, 1); + + com_add_command("_pft", com_pft, 0); + com_add_command("_conv", com_factor_conv, 0); +} + +end_factor() +{ +} + +static node_t * +first_fanin(np) +node_t *np; +{ + node_t *fanin, *first; + int i; + + first = NIL(node_t); + foreach_fanin(np, i, fanin) { + if (i == 0) { + first = fanin; + } + } + + return first; +} + + +static void +factor_usage() +{ + (void) fprintf(miserr, "usage: factor [-qgb] node-list\n"); + (void) fprintf(miserr, " -q\t\tQuick factoring (default)\n"); + (void) fprintf(miserr, " -g\t\tGood factoring\n"); + (void) fprintf(miserr, " -b\t\tBoolean factoring\n"); +} diff --git a/sis/factor/elim.c b/sis/factor/elim.c new file mode 100644 index 0000000..6da948e --- /dev/null +++ b/sis/factor/elim.c @@ -0,0 +1,309 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/factor/elim.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/05/05 22:34:59 $ + * + */ +/* + * eliminate: selective collapsing + * routines provided: + * eliminate(); + */ + +#include "sis.h" +#include "factor.h" +#include "factor_int.h" + +/* + * eliminate all nodes with value less than or equal to thresh + */ + +static double clp_est(); +static double cmp_est(); +static double cov_est(); +static double cov_leaf_est(); +static double cov_inv_est(); +static double cov_and_est(); +static double cov_or_est(); + +void +eliminate(network, thresh, limit) +network_t *network; +int thresh, limit; +{ + array_t *nodevec; + int i, j; + bool elimok, eliminating = TRUE; + node_t *np, *fanout, *fanin; + lsGen gen; + st_table *dont_elim; + char *dummy; + int newlimit, tmplimit; + extern array_t *order_nodes_elim(); + + dont_elim = st_init_table(st_ptrcmp, st_ptrhash); + while (eliminating) { + + (void) network_cleanup(network); + eliminating = FALSE; + + nodevec= order_nodes_elim(network); + + newlimit = 0; + for(i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + tmplimit= 2 * node_num_cube(np); + if (newlimit < tmplimit) + newlimit= tmplimit; + } + if (limit > newlimit) + limit = newlimit; + for(i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + if (node_function(np) == NODE_PI) + continue; + elimok = TRUE; + if(node_value(np) <= thresh){ + if(!st_lookup(dont_elim, (char *)np, &dummy)){ + foreach_fanout(np, gen, fanout) { + if(node_function(fanout) == NODE_PO){ + elimok = FALSE; + (void)st_insert(dont_elim, (char *)np, + (char *)1); + (void)lsFinish(gen); + break; + } + if(clp_est(fanout, np) > limit){ + elimok = FALSE; + (void)st_insert(dont_elim, (char *)np, + (char *)1); + (void)lsFinish(gen); + break; + } + } + + /* if collapsing np into any fanout could + potentially cause the fanout cover to explode + then will not eliminate `np' + also, will not eliminate if `np' fans out to a + primary output + */ + + if(elimok){ + foreach_fanout(np, gen, fanout) { + if (node_collapse(fanout, np)) { + eliminating = TRUE; + foreach_fanin(fanout, j, fanin){ + (void)st_delete(dont_elim, + (char **)&fanin, &dummy); + } + (void)st_delete(dont_elim, + (char **) &fanout, &dummy); + } + } + } + } + } + } + array_free(nodevec); + } + st_free_table(dont_elim); +} + +/* this rotuine returns a quick (and rough) estimate of the size + of the cover of `fanout' if `np' were to be collapsed into + it. +*/ + +static double +clp_est(fanout, np) +node_t *fanout, *np; +{ + double cmp_size; + + switch(node_input_phase(fanout, np)){ + case PHASE_UNKNOWN: + return node_num_cube(fanout); + case NEG_UNATE: + case BINATE: + cmp_size = cmp_est((ft_t *)np->factored); + break; + default: + /* will not need the complement so cmp_size + doesn't matter. + */ + cmp_size = 0; + break; + } + + return(cov_est(fanout, np, (ft_t *)fanout->factored, cmp_size)); +} + +/* recursive routine that estimates the size of the cover + using the factored form. called from clp_est. +*/ + +static double +cov_est(fanout, np, root, cmp_size) +node_t *fanout, *np; +ft_t *root; +double cmp_size; +{ + switch(root->type){ + case FACTOR_LEAF : + return(cov_leaf_est(fanout, np, root, cmp_size)); + case FACTOR_INV : + return(cov_inv_est(fanout, np, root, cmp_size)); + case FACTOR_AND : + return(cov_and_est(fanout, np, root, cmp_size)); + case FACTOR_OR : + return(cov_or_est(fanout, np, root, cmp_size)); + default: + /* shouldn't happen */ + return 0; + } +} + +/* quick estimate of the cover size of the complement of a node, + based on the factored form. +*/ + +static double +cmp_est(f) +ft_t *f; +{ + double cmp_size; + ft_t *p; + + switch(f->type){ + case FACTOR_1: + return 0; + case FACTOR_0: + case FACTOR_LEAF: + case FACTOR_INV: + return 1; + case FACTOR_AND: + cmp_size = 0; + for(p = f->next_level; p != NIL(ft_t); p = + p->same_level){ + cmp_size += cmp_est(p); + } + break; + case FACTOR_OR: + cmp_size = 1; + for(p = f->next_level; p != NIL(ft_t); p = + p->same_level){ + cmp_size *= cmp_est(p); + } + break; + default: + /* shouldn't reach here */ + cmp_size = -1; + break; + } + + return cmp_size; +} + +static double +cov_inv_est(fanout, np, root, cmp_size) +node_t *fanout, *np; +ft_t *root; +double cmp_size; +{ + if(np == node_get_fanin(fanout, root->next_level->index)){ + return cmp_size; + } else { + return 1; + } +} + +/*ARGSUSED*/ +static double +cov_leaf_est(fanout, np, root, cmp_size) +node_t *fanout, *np; +ft_t *root; +double cmp_size; +{ + if(np == node_get_fanin(fanout, root->index)){ + return node_num_cube(np); + } else { + return 1; + } +} + +static double +cov_and_est(fanout, np, root, cmp_size) +node_t *fanout, *np; +ft_t *root; +double cmp_size; +{ + double cov_size, sub_cover; + ft_t *p; + + cov_size = 1; + for(p = root->next_level; p != NIL(ft_t); p = p->same_level){ + switch(p->type){ + case FACTOR_LEAF: + sub_cover = cov_leaf_est(fanout, np, p, + cmp_size); + break; + case FACTOR_INV: + sub_cover = cov_inv_est(fanout, np, p, + cmp_size); + break; + case FACTOR_OR: + sub_cover = cov_or_est(fanout, np, p, + cmp_size); + break; + case FACTOR_AND: + sub_cover = cov_and_est(fanout, np, p, + cmp_size); + break; + default: + sub_cover = 0; /* shouldn't happen */ + } + cov_size *= sub_cover; + } + return cov_size; + +} + +static double +cov_or_est(fanout, np, root, cmp_size) +node_t *fanout, *np; +ft_t *root; +double cmp_size; +{ + double cov_size, sub_cover; + ft_t *p; + + cov_size = 0; + for(p = root->next_level; p != NIL(ft_t); p = p->same_level){ + switch(p->type){ + case FACTOR_LEAF: + sub_cover = cov_leaf_est(fanout, np, p, + cmp_size); + break; + case FACTOR_INV: + sub_cover = cov_inv_est(fanout, np, p, + cmp_size); + break; + case FACTOR_OR: + sub_cover = cov_or_est(fanout, np, p, + cmp_size); + break; + case FACTOR_AND: + sub_cover = cov_and_est(fanout, np, p, + cmp_size); + break; + default: + sub_cover = 1; /* shouldn't happen */ + } + cov_size += sub_cover; + } + return cov_size; +} diff --git a/sis/factor/factor.c b/sis/factor/factor.c new file mode 100644 index 0000000..df0b364 --- /dev/null +++ b/sis/factor/factor.c @@ -0,0 +1,66 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/factor/factor.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +/* + * factor: factoring routine + * routines provided: + * factor(); + */ + +#include "sis.h" +#include "factor.h" +#include "factor_int.h" + +/* + * factors nodep if nodep->factored is not NULL. + */ +void +factor(f) +node_t *f; +{ + if (f->factored == NIL(char)) { + factor_quick(f); + } +} + +/* + * quick factoring + */ +void +factor_quick(f) +node_t *f; +{ + node_t *np; + + factor_free(f); + node_scc(f); + np = node_dup(f); + np->type = UNASSIGNED; + factor_recur(np, factor_quick_kernel); + f->factored = (char *) factor_nt_to_ft(f, np); + factor_nt_free(np); +} + +/* + * good factoring + */ +void +factor_good(f) +node_t *f; +{ + node_t *np; + + factor_free(f); + node_scc(f); + np = node_dup(f); + np->type = UNASSIGNED; + factor_recur(np, factor_best_kernel); + f->factored = (char *) factor_nt_to_ft(f, np); + factor_nt_free(np); +} diff --git a/sis/factor/factor.doc b/sis/factor/factor.doc new file mode 100644 index 0000000..07e7574 --- /dev/null +++ b/sis/factor/factor.doc @@ -0,0 +1,102 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/factor/factor.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +Summary: + factor(); + factor_quick(); + factor_good(); + factor_print(); + factor_value(); + factor_num_literal(); + factor_to_nodes(); + eliminate(); + + +void +factor(f) +node_t *f; + Returns immediately if the factored form of f already exists. + Otherwise, factorizes f using quick factoring algorithm. + + +void +factor_quick(f) +node_t *f; + Factorizes f using quick factoring (QF) algorithm. The previous + factored form of f, if it exists, is freed. + + +void +factor_good(f) +node_t *f; + Factorizes f using good factoring (GF) algorithm. The previous + factored form of f, if it exists, is freed. + + +void +factor_print(fp, f) +FILE *fp; +node_t *f; + Prints the factored form of f (i.e. "a(b + c) + d"). + Does not append a trailing newline. Uses node_name(), + and hence depends on the current setting of + long names versus short names. + If f is constant 0, "-0-" is printed. + If f is constant 1, "-1-" is printed. + If the factored form of f does not exist, the factored + form is generated using quick factoring(QF). + + +int +factor_node_value(f) +node_t *f; + Returns the value of f. The value of f is + is number of literals in the factored saved by f in + the network. See MIS paper for precise definition. + Quick factoring (QF) is used wherever the factored + form is not available. + + +int +factor_num_literal(f) +node_t *f; + Returns the number of literals in the factored form of f. + If the factored form is not available, quick factoring (QF) + is used to generate one. + +int +factor_num_used(f, g) +node_t *f, *g; + Returns the number of times g appears in the + factored form of f. Both g and g' are counted. + (e.g. if f = a g + b g', function returns 2) + + +array_t * +factor_to_nodes(f) +node_t *f; + Returns an array of nodes representing the factored tree + of f. The root of the tree is the first element in + the array. All the nodes in the array are either of type + NODE_AND, NODE_OR, NODE_INV, NODE_BUF, NODE_0, or NODE_1. + + For example: if f = a (b + c'), the returned array is + 0: X = a t1 + 1: t1 = b + t2' + 2: t2 = c' + + +void +eliminate(network, thresh) +network_t *network; +int thresh + Eliminates all the nodes in the network whose's value is + less than or equal to thresh. The value of a node is + defined as the number of literals saved in the network by + the node. See MIS paper for precise definition. diff --git a/sis/factor/factor.h b/sis/factor/factor.h new file mode 100644 index 0000000..4d1a64d --- /dev/null +++ b/sis/factor/factor.h @@ -0,0 +1,31 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/factor/factor.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +#ifndef FACTOR_H +#define FACTOR_H + +EXTERN void factor ARGS((node_t *)); +EXTERN void factor_quick ARGS((node_t *)); +EXTERN void factor_good ARGS((node_t *)); + +EXTERN void factor_free ARGS((node_t *)); +EXTERN void factor_dup ARGS((node_t *, node_t *)); +EXTERN void factor_alloc ARGS((node_t *)); +EXTERN void factor_invalid ARGS((node_t *)); + +EXTERN void factor_print ARGS((FILE *, node_t *)); +EXTERN int node_value ARGS((node_t *)); +EXTERN int factor_num_literal ARGS((node_t *)); +EXTERN int factor_num_used ARGS((node_t *, node_t *)); + +EXTERN void eliminate ARGS((network_t *, int, int)); + +EXTERN array_t *factor_to_nodes ARGS((node_t *)); + +#endif diff --git a/sis/factor/factor_int.h b/sis/factor/factor_int.h new file mode 100644 index 0000000..e28dd30 --- /dev/null +++ b/sis/factor/factor_int.h @@ -0,0 +1,43 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/factor/factor_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +typedef enum trav_order_enum trav_order; +enum trav_order_enum { + FACTOR_TRAV_IN_ORDER, FACTOR_TRAV_POST_ORDER +}; + +typedef enum factor_type_enum factor_type; +enum factor_type_enum { + FACTOR_0, FACTOR_1, FACTOR_AND, FACTOR_OR, + FACTOR_INV, FACTOR_LEAF, FACTOR_UNKNOWN +}; + + +typedef struct ft_struct { + factor_type type; + int index; + int len; + struct ft_struct *next_level; + struct ft_struct *same_level; +} ft_t; + + +extern void factor_recur(); +extern node_t *factor_best_literal(); +extern node_t *factor_quick_kernel(); +extern node_t *factor_best_kernel(); +extern void factor_traverse(); +extern void factor_nt_free(); +extern void value_print(); +extern ft_t *factor_nt_to_ft(); +extern void ft_print(); +extern void set_line_width(); +extern void eliminate(); +extern int value_cmp_inc(); +extern int value_cmp_dec(); diff --git a/sis/factor/ft_print.c b/sis/factor/ft_print.c new file mode 100644 index 0000000..37513b5 --- /dev/null +++ b/sis/factor/ft_print.c @@ -0,0 +1,267 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/factor/ft_print.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +#include "sis.h" +#include "factor.h" +#include "factor_int.h" + +static void ft_tree_print(); +static void ft_and_print(); +static void ft_or_print(); +static void ft_leaf_print(); +static void ft_inv_print(); +static int ft_len(); +static int line_width; + +void +factor_print(fp, f) +FILE *fp; +node_t *f; +{ + int length = 0; + + if (f->factored == NIL(char)) { + factor_quick(f); + } + + ft_tree_print(fp, f, (ft_t *) f->factored, &length); +} + +static void +ft_tree_print(fp, node, f, len) +FILE *fp; +node_t *node; +ft_t *f; +int *len; +{ + switch ((int) f->type) { + case FACTOR_0: + (void) fprintf(fp, "-0-"); + break; + case FACTOR_1: + (void) fprintf(fp, "-1-"); + break; + case FACTOR_AND: + ft_and_print(fp, node, f, len); + break; + case FACTOR_OR: + ft_or_print(fp, node, f, len); + break; + case FACTOR_INV: + ft_inv_print(fp, node, f, len); + break; + case FACTOR_LEAF: + ft_leaf_print(fp, node, f, len); + break; + default: + (void) fprintf(miserr, "ft internal error, wrong type\n"); + exit(-1); + } +} + +static void +ft_leaf_print(fp, node, f, len) +FILE *fp; +node_t *node; +ft_t *f; +int *len; +{ + node_t *np, *node_get_fanin(); + + np = node_get_fanin(node, f->index); + if ( (strlen(node_name(np)) + (*len)) > line_width ) { + (void) fprintf(fp, "\n\t"); + *len = 0; + } + + (void) fprintf(fp, "%s", node_name(np)); + *len += strlen(node_name(np)); +} + +static void +ft_inv_print(fp, node, f, len) +FILE *fp; +node_t *node; +ft_t *f; +int *len; +{ + ft_tree_print(fp, node, f->next_level, len); + (void) fprintf(fp, "'"); + *len += 1; +} + +static void +ft_or_print(fp, node, f, len) +FILE *fp; +node_t *node; +ft_t *f; +int *len; +{ + ft_t *p; + bool first = TRUE; + + for(p = f->next_level; p != NIL(ft_t); p = p->same_level) { + if (first) { + first = FALSE; + } else { + (void) fprintf(fp, " + "); + *len += 3; + } + ft_tree_print(fp, node, p, len); + } +} + +static void +ft_and_print(fp, node, f, len) +FILE *fp; +node_t *node; +ft_t *f; +int *len; +{ + ft_t *p; + int first = TRUE; + + for(p = f->next_level; p != NIL(ft_t); p = p->same_level) { + if (first) { + first = FALSE; + } else { + (void) fprintf(fp, " "); + *len += 1; + } + if (p->type == FACTOR_OR) { + (void) fprintf(fp, "("); + ft_tree_print(fp, node, p, len); + (void) fprintf(fp, ")"); + } else { + ft_tree_print(fp, node, p, len); + } + } +} + +static char *and_name = "AND"; +static char *or_name = "OR"; +static char *inv_name = "INV"; +static char *zero_name = "-0-"; +static char *one_name = "-1-"; +static char *unknown_name = "???"; +static char *ft_name(); + +void +ft_print(r, f, level) +node_t *r; +ft_t *f; +int level; +{ + ft_t *p; + + if (f != NIL(ft_t)) { + + (void) fprintf(misout, "%d: %s\t", level, ft_name(r, f)); + for (p=f->next_level; p != NIL(ft_t); p = p->same_level) { + (void) fprintf(misout, "\t%s", ft_name(r, p)); + } + (void) fprintf(misout, "\n"); + + for (p=f->next_level; p != NIL(ft_t); p = p->same_level) { + ft_print(r, p, level+1); + } + } +} + +static char * +ft_name(r, f) +node_t *r; +ft_t *f; +{ + char *name; + + switch (f->type) { + case FACTOR_0: + name = zero_name; + break; + case FACTOR_1: + name = one_name; + break; + case FACTOR_AND: + name = and_name; + break; + case FACTOR_OR: + name = or_name; + break; + case FACTOR_INV: + name = inv_name; + break; + case FACTOR_LEAF: + name = node_name(node_get_fanin(r, f->index)); + break; + default: + name = unknown_name; + } + + return name; +} + +/* + * pretty printer of factored form + */ +/* ARGSUSED */ +void +ft_len_init(r, f) +node_t *r; +ft_t *f; +{ + factor_traverse(r, ft_len, NIL(char), FACTOR_TRAV_POST_ORDER); +} + +/* ARGSUSED */ +static int +ft_len(r, f, stat) +node_t *r; +ft_t *f; +char *stat; +{ + ft_t *p; + + switch (f->type) { + case FACTOR_0: + f->len = 3; + break; + case FACTOR_1: + f->len = 3; + break; + case FACTOR_LEAF: + f->len = strlen(node_name(node_get_fanin(r, f->index))); + break; + case FACTOR_INV: + f->len = f->next_level->len + 1; + break; + case FACTOR_AND: + f->len = -1; + for(p = f->next_level; p != NIL(ft_t); p = p->same_level) { + f->len = f->len + p->len + 1; + } + break; + case FACTOR_OR: + f->len = -1; + for(p = f->next_level; p != NIL(ft_t); p = p->same_level) { + f->len = f->len + p->len + 3; + } + break; + default: + fail("Error: wrong factor type in ft_len\n"); + } + + return 0; +} + +void +set_line_width() +{ + line_width = 60; +} diff --git a/sis/factor/ft_util.c b/sis/factor/ft_util.c new file mode 100644 index 0000000..489afc6 --- /dev/null +++ b/sis/factor/ft_util.c @@ -0,0 +1,450 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/factor/ft_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +/* + * factor_util: utilities to handle factor tree in which each + * node is ft_t. + */ + +#include "sis.h" +#include "factor.h" +#include "factor_int.h" + +static ft_t *ft_dup(); +static ft_t *ft_new(); +static void ft_free(); +static ft_t *node_to_ft(); + +void +factor_alloc(f) +node_t *f; +{ + f->factored = NIL(char); +} + +void +factor_free(f) +node_t *f; +{ + if (f->factored != NIL(char)) { + ft_free((ft_t *) f->factored); + f->factored = NIL(char); + } +} + +void +factor_invalid(f) +node_t *f; +{ + factor_free(f); +} + +void +factor_dup(old, new) +node_t *old, *new; +{ + factor_free(new); + new->factored = (char *) ft_dup((ft_t *) old->factored); +} + +static void +ft_free(root) +ft_t *root; +{ + if (root != NIL(ft_t)) { + ft_free(root->next_level); + ft_free(root->same_level); + FREE(root); + } +} + +static ft_t * +ft_dup(f) +ft_t *f; +{ + ft_t *newp; + + if (f == NIL(ft_t)) { + return f; + } else { + newp = ALLOC(ft_t, 1); + newp->type = f->type; + newp->index = f->index; + newp->len = f->len; + newp->next_level = ft_dup(f->next_level); + newp->same_level = ft_dup(f->same_level); + return newp; + } +} + +static ft_t * +ft_new(ft_type, ft_index, ft_len, ft_same, ft_next) +factor_type ft_type; +int ft_index; +int ft_len; +ft_t *ft_same; +ft_t *ft_next; +{ + ft_t *p; + p = ALLOC(ft_t, 1); + p->type = ft_type; + p->index = ft_index; + p->len = ft_len; + p->same_level = ft_same; + p->next_level = ft_next; + return p; +} + +void +factor_traverse(f, func, stat, order) +node_t *f; +int (*func)(); +char *stat; +trav_order order; +{ + factor(f); + (void) ft_traverse_recur(f, (ft_t *) f->factored, func, stat, order); +} + +int +ft_traverse_recur(f, root, func, stat, order) +node_t *f; +ft_t *root; +int (*func)(); +char *stat; +trav_order order; +{ + if (order == FACTOR_TRAV_IN_ORDER) { + if ((*func)(f, root, stat) == 1) { + return 1; + } + } + + if (root->next_level != NIL(ft_t)) { + if (ft_traverse_recur(f, root->next_level, func, stat, order) != 0) { + return 1; + } + } + + if (root->same_level != NIL(ft_t)) { + if (ft_traverse_recur(f, root->same_level, func, stat, order) != 0) { + return 1; + } + } + + if (order == FACTOR_TRAV_POST_ORDER) { + if ((*func)(f, root, stat) == 1) { + return 1; + } + } + + return 0; +} + +/* + * nt2ft: convert node_t tree to ft_t tree. + */ +ft_t * +factor_nt_to_ft(f, nt) +node_t *f; /* original node */ +node_t *nt; /* root of the factored node_t tree */ +{ + switch (node_function(nt)) { + case NODE_0: + return ft_new(FACTOR_0, -1, 0, NIL(ft_t), NIL(ft_t)); + case NODE_1: + return ft_new(FACTOR_1, -1, 0, NIL(ft_t), NIL(ft_t)); + default: + return node_to_ft(f, nt); + } +} + +static ft_t * +node_to_ft(f, np) +node_t *f; +node_t *np; +{ + node_cube_t cube; + node_literal_t literal; + node_t *fanin; + ft_t *lit, *and, *or, *temp, *cur_and, *cur_or; + int i, j; + + if (np->type != UNASSIGNED) { + i = node_get_fanin_index(f, np); + return ft_new(FACTOR_LEAF, i, 0, NIL(ft_t), NIL(ft_t)); + } + + or = cur_or = NIL(ft_t); + for (i = node_num_cube(np) - 1; i >= 0; i--) { + and = cur_and = NIL(ft_t); + cube = node_get_cube(np, i); + foreach_fanin(np, j, fanin) { + literal = node_get_literal(cube, j); + switch(literal) { + case ZERO: + temp = node_to_ft(f, fanin); + lit = ft_new(FACTOR_INV, -1, 0, NIL(ft_t), temp); + if (cur_and == NIL(ft_t)) { + and = cur_and = lit; + } else { + cur_and->same_level = lit; + cur_and = lit; + } + break; + case ONE: + lit = node_to_ft(f, fanin); + if (cur_and == NIL(ft_t)) { + and = cur_and = lit; + } else { + cur_and->same_level = lit; + cur_and = lit; + } + } + } + + if (and == NIL(ft_t)) { /* no literal case, should never happen */ + fail("Error: function is not SCC minimum"); + } else if (and->same_level != NIL(ft_t)) { /* 1 literal case */ + and = ft_new(FACTOR_AND, -1, 0, NIL(ft_t), and); + } + + if (cur_or == NIL(ft_t)) { + or = cur_or = and; + } else { + cur_or->same_level = and; + cur_or = and; + } + } + + if (or == NIL(ft_t)) { /* no cube case, should never happen */ + fail("Error: function is not SCC minimum"); + } else if (or->same_level != NIL(ft_t)) { /* 1 cube case */ + or = ft_new(FACTOR_OR, -1, 0, NIL(ft_t), or); + } + + return or; +} + +void +factor_nt_free(nodep) +node_t *nodep; +{ + int i; + node_t *np; + + if (nodep->type == UNASSIGNED) { + foreach_fanin(nodep, i, np) { + factor_nt_free(np); + } + node_free(nodep); + } +} + +/* + * find the best literal of c in f. + */ +node_t * +factor_best_literal(f, c) +node_t *f, *c; +{ + node_t *bp = NIL(node_t), *fip, *cip; + int *f_count, *c_count; + int b_count = -1; + int ci, fi, phase = 1; + + f_count = node_literal_count(f); + c_count = node_literal_count(c); + + foreach_fanin(f, fi, fip) { + foreach_fanin(c, ci, cip) { + if (fip == cip) { + if (c_count[2*ci] > 0 && f_count[2*fi] > b_count) { + bp = cip; + phase = 1; /* ???????? */ + b_count = f_count[2*fi]; + } + if (c_count[2*ci+1] > 0 && f_count[2*fi+1] > b_count) { + bp = cip; + phase = 0; /* ???????? */ + b_count = f_count[2*fi+1]; + } + } + } + } + + FREE(f_count); + FREE(c_count); + + switch (phase) { + case 0: + return node_literal(bp, 0); + case 1: + return node_literal(bp, 1); + default: + (void) fprintf(miserr, "Error: internal error in best_literal\n"); + return NIL(node_t); + } +} + +node_t * +factor_quick_kernel(f) +node_t *f; +{ + return ex_find_divisor_quick(f); +} + +node_t * +factor_best_kernel(f) +node_t *f; +{ + return ex_find_divisor(f, 1, 1); +} + +static array_t *ft_conv(); +static array_t *ft_and_conv(); +static array_t *ft_or_conv(); +static array_t *ft_inv_conv(); + +array_t * +factor_to_nodes(f) +node_t *f; +{ + node_t *r; + array_t *fa; + + factor(f); + if (node_function(f) == NODE_BUF) { + fa = array_alloc(node_t *, 0); + array_insert_last(node_t *, fa, node_literal(node_get_fanin(f, 0), 1)); + } else { + fa = ft_conv(f, (ft_t *) f->factored, &r); + } + + return fa; +} + +static array_t * +ft_conv(nf, f, root) +node_t *nf; +ft_t *f; +node_t **root; +{ + array_t *fa; + + switch (f->type) { + case FACTOR_0: + fa = array_alloc(node_t *, 0); + *root = node_constant(0); + array_insert_last(node_t *, fa, *root); + break; + case FACTOR_1: + fa = array_alloc(node_t *, 0); + *root = node_constant(1); + array_insert_last(node_t *, fa, *root); + break; + case FACTOR_AND: + fa = ft_and_conv(nf, f, root); + break; + case FACTOR_OR: + fa = ft_or_conv(nf, f, root); + break; + case FACTOR_INV: + fa = ft_inv_conv(nf, f, root); + break; + case FACTOR_LEAF: + fa = array_alloc(node_t *, 0); + *root = node_get_fanin(nf, f->index); + break; + default: + fail("factor_to_nodes: wrong node type"); + exit(-1); + } + + return fa; +} + +static array_t * +ft_or_conv(nf, f, root) +node_t *nf; +ft_t *f; +node_t **root; +{ + array_t *fa, *tfa; + node_t *or, *lit, *temp, *r; + ft_t *p; + + or = node_constant(0); + fa = array_alloc(node_t *, 0); + array_insert_last(node_t *, fa, or); + + for (p = f->next_level; p != NIL(ft_t); p = p->same_level) { + tfa = ft_conv(nf, p, &r); + lit = node_literal(r, 1); + temp = node_or(or, lit); + node_free(or); + node_free(lit); + or = temp; + array_append(fa, tfa); + array_free(tfa); + } + + array_insert(node_t *, fa, 0, or); + *root = or; + return fa; +} + +static array_t * +ft_and_conv(nf, f, root) +node_t *nf; +ft_t *f; +node_t **root; +{ + array_t *fa, *tfa; + node_t *and, *lit, *temp, *r; + ft_t *p; + + and = node_constant(1); + fa = array_alloc(node_t *, 0); + array_insert_last(node_t *, fa, and); + + for (p = f->next_level; p != NIL(ft_t); p = p->same_level) { + tfa = ft_conv(nf, p, &r); + lit = node_literal(r, 1); + temp = node_and(and, lit); + node_free(and); + node_free(lit); + and = temp; + array_append(fa, tfa); + array_free(tfa); + } + + array_insert(node_t *, fa, 0, and); + *root = and; + return fa; +} + +static array_t * +ft_inv_conv(nf, f, root) +node_t *nf; +ft_t *f; +node_t **root; +{ + array_t *fa, *t; + node_t *r; + + fa = array_alloc(node_t *, 0); + t = ft_conv(nf, f->next_level, &r); + *root = node_literal(r, 0); + array_insert_last(node_t *, fa, *root); + array_append(fa, t); + array_free(t); + + return fa; +} diff --git a/sis/factor/ft_value.c b/sis/factor/ft_value.c new file mode 100644 index 0000000..615cdf8 --- /dev/null +++ b/sis/factor/ft_value.c @@ -0,0 +1,174 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/factor/ft_value.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +/* + * routines to compute the values + */ + +#include "sis.h" +#include "factor.h" +#include "factor_int.h" + +static int literal_sum(); +static int factor_count(); + +/* + * Definition: + * The value of a node is defined to be the number of literals + * saved by the existence of the node. + * Formular: + * value = num_used * num_lit - num_used - num_lit + * where + * num_used is the number of times the node is used in both the positive + * and negative phase. + * num_lit is the number of literals in the factored form of the node. + */ +int node_value(nodep) +node_t *nodep; +{ + bool is_primary_output = FALSE; + int num_used; /* number of time the function used in factored form */ + int num_lit; /* number of literals in the factored form */ + node_t *np; + int value; + lsGen gen; + + if (nodep->type == PRIMARY_INPUT || nodep->type == PRIMARY_OUTPUT) { + return INFINITY; + } + + /* if all outputs of this nodes are primary output, its value is oo */ + value = INFINITY; + foreach_fanout(nodep, gen, np) { + if (nodep->type != PRIMARY_OUTPUT) { + value = 0; + } + } + if (value != 0) { + return value; + } + + /* compute the number of times the function is used */ + num_used = 0; + foreach_fanout(nodep, gen, np) { + if (np->type != PRIMARY_OUTPUT) { + num_used += factor_num_used(np, nodep); + } else { + is_primary_output = TRUE; + } + } + + num_lit = factor_num_literal(nodep); + + value = num_used * num_lit - num_used - num_lit; + + /* + * if the node fans out to a primary output, it cannot be eliminated. + * So, add num_lit to the value. + */ + if (is_primary_output) { + value += num_lit; + } + + return value; +} + +typedef struct stat_struct { + int index; + int count; +} stat_t; + +int +factor_num_used(o, i) +node_t *o, *i; +{ + stat_t s; + + factor(o); + s.index = node_get_fanin_index(o, i); + s.count = 0; + factor_traverse(o, factor_count, (char *) &s, FACTOR_TRAV_IN_ORDER); + return s.count; +} + +/* ARGSUSED */ +static int +factor_count(r, f, stat) +node_t *r; +ft_t *f; +char *stat; +{ + stat_t *s; + + s = (stat_t *) stat; + if (f->type == FACTOR_LEAF && f->index == s->index) { + s->count += 1; + } + return 0; +} + +int +factor_num_literal(f) +node_t *f; +{ + int sum = 0; + + if (f->type == PRIMARY_INPUT || f->type == PRIMARY_OUTPUT) { + return 0; + } + + factor(f); + factor_traverse(f, literal_sum, (char *) &sum, FACTOR_TRAV_IN_ORDER); + return sum; +} + +/* ARGSUSED */ +static int +literal_sum(r, np, sum) +node_t *r; +ft_t *np; +char *sum; +{ + int *s; + + s = (int *) sum; + if (np->type == FACTOR_LEAF) { + *s += 1; + } + return 0; +} + +void +value_print(fp, np) +FILE *fp; +node_t *np; +{ + int value; + + value = node_value(np); + if (value >= INFINITY) { + (void) fprintf(fp, "%s:\t(inf)\n", node_name(np)); + } else { + (void) fprintf(fp, "%s:\t%d\n", node_name(np), value); + } +} + +int +value_cmp_inc(p1, p2) +char **p1, **p2; +{ + return node_value((node_t *) *p1) - node_value((node_t *) *p2); +} + +int +value_cmp_dec(p1, p2) +char **p1, **p2; +{ + return node_value((node_t *) *p2) - node_value((node_t *) *p1); +} diff --git a/sis/gcd/Makefile.am b/sis/gcd/Makefile.am new file mode 100644 index 0000000..61efd21 --- /dev/null +++ b/sis/gcd/Makefile.am @@ -0,0 +1,7 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libgcd.a +libgcd_a_SOURCES = com_gcd.c gcd.c gcd_int.h +pkginclude_HEADERS = gcd.h +dist_doc_DATA = gcd.doc diff --git a/sis/gcd/Makefile.in b/sis/gcd/Makefile.in new file mode 100644 index 0000000..35e639c --- /dev/null +++ b/sis/gcd/Makefile.in @@ -0,0 +1,418 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libgcd_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/gcd +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libgcd_a_AR = $(AR) $(ARFLAGS) +libgcd_a_LIBADD = +am_libgcd_a_OBJECTS = com_gcd.$(OBJEXT) gcd.$(OBJEXT) +libgcd_a_OBJECTS = $(am_libgcd_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libgcd_a_SOURCES) +DIST_SOURCES = $(libgcd_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libgcd.a +libgcd_a_SOURCES = com_gcd.c gcd.c gcd_int.h +pkginclude_HEADERS = gcd.h +dist_doc_DATA = gcd.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/gcd/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/gcd/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libgcd.a: $(libgcd_a_OBJECTS) $(libgcd_a_DEPENDENCIES) + -rm -f libgcd.a + $(libgcd_a_AR) libgcd.a $(libgcd_a_OBJECTS) $(libgcd_a_LIBADD) + $(RANLIB) libgcd.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/gcd/com_gcd.c b/sis/gcd/com_gcd.c new file mode 100644 index 0000000..d92bb8a --- /dev/null +++ b/sis/gcd/com_gcd.c @@ -0,0 +1,100 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/gcd/com_gcd.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +#include "sis.h" +#include "gcd.h" +#include "gcd_int.h" + +static int +com_print_gcd(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i; + array_t *node_vec; + node_t *node; + + node_vec = com_get_nodes(*network, argc, argv); + if (array_n(node_vec) < 1) goto usage; + + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (node_function(node) == NODE_PI) goto usage; + if (node_function(node) == NODE_1) { + (void)fprintf(misout,"-1-\n"); + array_free(node_vec); + return 0; + } + } + + node = gcd_nodevec(node_vec); + array_free(node_vec); + node_print_rhs(misout,node); + (void)fprintf(misout, "\n"); + return 0; + +usage: + (void) fprintf(miserr, + "_gcd n1 n2 ...\n"); + + (void) fprintf(miserr, + " where none of n1, n2,..., nn are primary inputs\n"); + return 1; +} + +static int +com_print_factor(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i, j; + array_t *node_vec; + array_t *factor_vec; + node_t *node, *factor_node; + + node_vec = com_get_nodes(*network, argc, argv); + if (array_n(node_vec) < 1) goto usage; + + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + factor_vec = gcd_prime_factorize(node); + (void) + fprintf(misout, "Prime factorization for node %s\n", node_name(node)); + for(j = 0; j < array_n(factor_vec); ++j) { + factor_node = array_fetch(node_t *, factor_vec, j); + node_print_rhs(misout,factor_node); + node_free(factor_node); + (void)fprintf(misout,"\n"); + } + array_free(factor_vec); + } + + + array_free(node_vec); + return 0; + +usage: + (void) fprintf(miserr, + "_prime_factor n1 n2 ...\n"); + + return 1; +} + +init_gcd() +{ + com_add_command("_gcd", com_print_gcd, /* changes-network */ 0); + com_add_command("_prime_factor", com_print_factor, /* changes-network */ 0); +} + + +end_gcd() +{ +} diff --git a/sis/gcd/gcd.c b/sis/gcd/gcd.c new file mode 100644 index 0000000..33233ca --- /dev/null +++ b/sis/gcd/gcd.c @@ -0,0 +1,309 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/gcd/gcd.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +#include "sis.h" +#include "gcd.h" +#include "gcd_int.h" +#define min(x,y) (x < y?x:y) + +array_t * +gcd_prime_factorize(f) +node_t *f; +{ + array_t *result = array_alloc(node_t *, 0); + node_t *p, *cofactor; + + + assert(f != NIL(node_t)); + + if((node_function(f) == NODE_PI) || (node_num_cube(f) <= 1)) { + array_insert_last(node_t *, result, node_dup(f)); + return result; + } + + + p = node_largest_cube_divisor(f); + array_insert_last(node_t *, result, p); + + f = node_div(f, p, NIL(node_t *)); + + while(node_function(f) != NODE_1) { + p = find_prime_factor(f, &cofactor); + array_insert_last(node_t *, result, p); + node_free(f); + f = cofactor; + } + node_free(f); + return result; +} + +node_t * +gcd_nodevec(nodevec) +array_t *nodevec; +{ + int i, n, best_num, m, j, best_index, new_num, last_loop; + node_t *best_node, **node_array, *next_cube, *next_result, *r, + *div, *result, *node, *cur_divisor; + array_t *gcdvec; + + assert(nodevec != NIL(array_t)); + assert((n = array_n(nodevec)) != 0); + + node_array = array_data(node_t *, nodevec); + + /* Now go through the array, "deleting" 0 and nil elements by cycling them + to the end of the array and decrementing the end index */ + + for(i = 0; i < n; ++i) + if(node_array[i] == NIL(node_t) || + node_function(node_array[i]) == NODE_0) + node_array[i--] = node_array[n--]; + + assert(n != 0); /* n == 0 means no nonzero elements in the array */ + + if(n == 1) return node_dup(node_array[0]); + + /* OK. Find the best node to fully prime factor, and while we're at it + we'll pull out the common cube from the array. We'll also make every + node cube-free. This results in duplicating every node in the array, + so they'll have to be freed when we return */ + + result = node_largest_cube_divisor(node_array[0]); + + best_node = node_array[0] = node_div(node_array[0], result, NIL(node_t *)); + + best_num = node_num_cube(best_node); + + best_index = 0; + + for(i = 1; i < n; ++i) { + node = node_array[i]; + if(node_function(node) == NODE_1) { + for(j = 0; j < i; ++j) node_free(node_array[j]); + FREE(node_array); + node_free(result); + return node_constant(1); + } + next_cube = node_largest_cube_divisor(node_array[i]); + node_array[i] = node_div(node_array[i], next_cube, NIL(node_t *)); + + if((node_function(result) != NODE_1) && + (node_function(next_cube) != NODE_1)) { + next_result = node_or(result, next_cube); + node_free(result); + result = node_largest_cube_divisor(next_result); + node_free(next_result); + } + node_free(next_cube); + + if((new_num = node_num_cube(node)) < best_num) { + best_num = new_num; + best_node = node; + best_index = i; + } + + } + + node_array[best_index] = node_array[0]; + node_array[0] = best_node; + + gcdvec = gcd_prime_factorize(best_node); + + m = array_n(gcdvec); + last_loop = 0; + + for(i = 1; (i < m) && !last_loop; ++i) { + cur_divisor = array_fetch(node_t *, gcdvec, i); + for(j = 1; j < n; ++j) { + div = node_div(node_array[j], cur_divisor, &r); + if(node_function(r) == NODE_0) { + node_free(node_array[j]); + node_free(r); + node_array[j] = div; + if(node_function(div) == NODE_1) last_loop = 1; + } else { + node_free(r); + break; + } + } + if( j == n ) { + next_result = node_and(result, cur_divisor); + node_free(result); + result = next_result; + } + } + + for(i = 0; i < n; ++i) node_free(node_array[i]); + + FREE(node_array); + + for(i = 0; i < m; ++i) node_free(array_fetch(node_t *,gcdvec, i)); + array_free(gcdvec); + + return result; +} + +static node_t * +find_prime_factor(f, cofactor) +node_t *f; +node_t **cofactor; +{ + node_t *fanin, *best_fanin, *g, *q, *r; + int best, num_cubes, i, *lit_count, lit_num, lit_val, phase, best_phase; + + /* Easy cases */ + + if ((num_cubes = node_num_cube(f)) <= 1) { + *cofactor = node_constant(1); + return node_dup(f); + } + + /* find the best variable to split around */ + + best = num_cubes; + best_fanin = (node_t *) 0; + + lit_count = node_literal_count(f); + + foreach_fanin(f, i, fanin) { + lit_num = 2*i; + + /* Look at both phases of a variable, positive (phase 1) first, + and negative (phase 0) second */ + + for(phase = 1; phase >= 0; --phase) { + lit_val = min(lit_count[lit_num], num_cubes - lit_count[lit_num]); + if((lit_val < best) && (lit_val != 0)) { + best = lit_val; + best_fanin = fanin; + best_phase = phase; + } + ++lit_num; + } + } + + /* Now that the variable is found, split. We error-check here to ensure + that we really have found a literal, but I can't imagine how we + couldn't */ + + assert(best_fanin != (node_t *) 0); + + /* make a node to contain the literal of the best_fanin */ + + best_fanin = node_literal(best_fanin, best_phase); + + q = node_div(f, best_fanin, &r); + + node_free(best_fanin); + + g = internal_gcd(q, r); + + node_free(q); + node_free(r); + + q = node_div(f, g, &r); + + /* r should be 0, so free it. We are done. The prime factor is q, the + cofactor is g */ + + node_free(r); + + *cofactor = g; + + return q; +} + +/* Compute the gcd of two nodes by fully prime factoring the smaller, and then + determining which factors divide the larger */ + +node_t *internal_gcd(q, r) +node_t *q, *r; +{ + node_t *u, *u_cube, *v, *v_cube, *p, *next_u, *result; + int q_size, r_size; + + + q_size = node_num_cube(q); + r_size = node_num_cube(r); + + /* Strictly speaking, should check that either q or r is == 1. However, + here we can take advantage of the fact that we have obtained q and r, + above, from f = qx + r, whence r != 1. If internal_gcd is ever to be + used from any other place, this should be changed */ + + if(node_function(q) == NODE_1) { + return(node_dup(q)); + } + + if(q_size < r_size) { + u = make_cube_free(q, &u_cube); + v = make_cube_free(r, &v_cube); + } else { + u = make_cube_free(r, &v_cube); + v = make_cube_free(q, &u_cube); + } + + /* The initial result is just the largest cube which divides u_cube and + v_cube evenly. This is the largest_cube_divisor of u_cube + v_cube, + a nice formulation due to RR */ + + r = node_or(u_cube, v_cube); + result = node_largest_cube_divisor(r); + + node_free(u_cube); + node_free(v_cube); + node_free(r); + + /* Find the gcd by fully prime-factoring the smaller function. The gcd is + then the product of those prime factors which divide v evenly */ + + while(node_function(u) != NODE_1) { + p = find_prime_factor(u, &next_u); + q = node_div(v, p, &r); + + /* if p exactly divides v (r == 0), then p is a common prime factor. + Set v = v/p, result = result * p with usual cleanup */ + + if(node_function(r) == NODE_0) { + node_free(v); + v = q; + node_free(r); + r = node_and(result, p); + node_free(result); + result = r; + } else { + node_free(r); + } + + /* clean up and prepare for the next iteration. u = u/p; */ + + node_free(u); + node_free(p); + u = next_u; + } + + return result; +} + +/* return f/c, c is the largest cube evenly dividing f, c is returned in the + second argument. Should disappear when Rick puts this into the library */ + +node_t *make_cube_free(f, f_cube) +node_t *f; +node_t **f_cube; +{ + node_t *r; + + *f_cube = node_largest_cube_divisor(f); + f = node_div(f, *f_cube, &r); + node_free(r); + return f; +} + + diff --git a/sis/gcd/gcd.doc b/sis/gcd/gcd.doc new file mode 100644 index 0000000..5314c8e --- /dev/null +++ b/sis/gcd/gcd.doc @@ -0,0 +1,26 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/gcd/gcd.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +Summary: + gcd_prime_factorize(); + gcd_nodevec(); + +array_t * +gcd_prime_factorize(f) +node_t *f; + Returns a vector of nodes, each of which is a prime factor of f. The + first node in the vector is the cube divisor of f, (the node 1 if f is + cube-free). Error if f == 0 or f is nil. + + +node_t * +gcd_nodevec(nodelist) +array_t *nodevec; + Given a vector of nodes, f1,..fn, returns their greatest common + divisor. Error if the vector is empty, or if every fi == 0. diff --git a/sis/gcd/gcd.h b/sis/gcd/gcd.h new file mode 100644 index 0000000..1e99249 --- /dev/null +++ b/sis/gcd/gcd.h @@ -0,0 +1,16 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/gcd/gcd.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +#ifndef GCD_H +#define GCD_H + +EXTERN array_t *gcd_prime_factorize ARGS((node_t *)); +EXTERN node_t *gcd_nodevec ARGS((array_t *)); + +#endif diff --git a/sis/gcd/gcd_int.h b/sis/gcd/gcd_int.h new file mode 100644 index 0000000..f23fed5 --- /dev/null +++ b/sis/gcd/gcd_int.h @@ -0,0 +1,16 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/gcd/gcd_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:23 $ + * + */ +/* + * internal definitions for gcd + */ + +static int com_print_gcd(); +static node_t *find_prime_factor(); +extern node_t *internal_gcd(), *make_cube_free(); diff --git a/sis/genlib/Makefile.am b/sis/genlib/Makefile.am new file mode 100644 index 0000000..342e919 --- /dev/null +++ b/sis/genlib/Makefile.am @@ -0,0 +1,23 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +AM_YFLAGS = -d + +BUILT_SOURCES = readlib.c readlib.h readliblex.c +CLEANFILES = $(BUILT_SOURCES) + +noinst_LIBRARIES = libgenlib.a +libgenlib_a_SOURCES = aoi.c com_genlib.c comb.c comb.h count.c genlib.c \ + genlib.h genlib_int.h io.c nand.c permute.c sptree.c sptree.h \ + readlib.y readliblex.l +dist_doc_DATA = genlib.doc + +readlib.h: readlib.c +readlib.c readlib.h: readlib.y + $(YACC) $(YFLAGS) $(AM_YFLAGS) $< + sed 's/yy/GENLIB_yy/g' y.tab.c > readlib.c + sed 's/yy/GENLIB_yy/g' y.tab.h > readlib.h + $(RM) y.tab.c y.tab.h +readliblex.c: readliblex.l readlib.h + $(LEX) $(LFLAGS) $(AM_LFLAGS) $< + sed 's/yy/GENLIB_yy/g' lex.yy.c > readliblex.c + $(RM) lex.yy.c diff --git a/sis/genlib/Makefile.in b/sis/genlib/Makefile.in new file mode 100644 index 0000000..e65b867 --- /dev/null +++ b/sis/genlib/Makefile.in @@ -0,0 +1,450 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +SOURCES = $(libgenlib_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/genlib +DIST_COMMON = $(dist_doc_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in readlib.c readlib.h readliblex.c +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libgenlib_a_AR = $(AR) $(ARFLAGS) +libgenlib_a_LIBADD = +am_libgenlib_a_OBJECTS = aoi.$(OBJEXT) com_genlib.$(OBJEXT) \ + comb.$(OBJEXT) count.$(OBJEXT) genlib.$(OBJEXT) io.$(OBJEXT) \ + nand.$(OBJEXT) permute.$(OBJEXT) sptree.$(OBJEXT) \ + readlib.$(OBJEXT) readliblex.$(OBJEXT) +libgenlib_a_OBJECTS = $(am_libgenlib_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) +YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) +SOURCES = $(libgenlib_a_SOURCES) +DIST_SOURCES = $(libgenlib_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +AM_YFLAGS = -d +BUILT_SOURCES = readlib.c readlib.h readliblex.c +CLEANFILES = $(BUILT_SOURCES) +noinst_LIBRARIES = libgenlib.a +libgenlib_a_SOURCES = aoi.c com_genlib.c comb.c comb.h count.c genlib.c \ + genlib.h genlib_int.h io.c nand.c permute.c sptree.c sptree.h \ + readlib.y readliblex.l + +dist_doc_DATA = genlib.doc +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .l .o .obj .y +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/genlib/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/genlib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libgenlib.a: $(libgenlib_a_OBJECTS) $(libgenlib_a_DEPENDENCIES) + -rm -f libgenlib.a + $(libgenlib_a_AR) libgenlib.a $(libgenlib_a_OBJECTS) $(libgenlib_a_LIBADD) + $(RANLIB) libgenlib.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.l.c: + $(LEXCOMPILE) $< + sed '/^#/ s|$(LEX_OUTPUT_ROOT)\.c|$@|' $(LEX_OUTPUT_ROOT).c >$@ + rm -f $(LEX_OUTPUT_ROOT).c + +.y.c: + $(YACCCOMPILE) $< + if test -f y.tab.h; then \ + to=`echo "$*_H" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`; \ + sed "/^#/ s/Y_TAB_H/$$to/g" y.tab.h >$*.ht; \ + rm -f y.tab.h; \ + if cmp -s $*.ht $*.h; then \ + rm -f $*.ht ;\ + else \ + mv $*.ht $*.h; \ + fi; \ + fi + if test -f y.output; then \ + mv y.output $*.output; \ + fi + sed '/^#/ s|y\.tab\.c|$@|' y.tab.c >$@t && mv $@t $@ + rm -f y.tab.c +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(docdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f readlib.c + -rm -f readliblex.c + -rm -f readlib.h + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-dist_docDATA \ + uninstall-info-am + + +readlib.h: readlib.c +readlib.c readlib.h: readlib.y + $(YACC) $(YFLAGS) $(AM_YFLAGS) $< + sed 's/yy/GENLIB_yy/g' y.tab.c > readlib.c + sed 's/yy/GENLIB_yy/g' y.tab.h > readlib.h + $(RM) y.tab.c y.tab.h +readliblex.c: readliblex.l readlib.h + $(LEX) $(LFLAGS) $(AM_LFLAGS) $< + sed 's/yy/GENLIB_yy/g' lex.yy.c > readliblex.c + $(RM) lex.yy.c +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/genlib/aoi.c b/sis/genlib/aoi.c new file mode 100644 index 0000000..e86a109 --- /dev/null +++ b/sis/genlib/aoi.c @@ -0,0 +1,166 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/aoi.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)aoi.c 1.1 */ +/* last modified on 5/29/91 at 12:35:18 */ +#include "genlib_int.h" + + +static int +s_sort(x, y) +char *x, *y; +{ + tree_node_t *tree1 = *(tree_node_t **) x, *tree2 = *(tree_node_t **) y; + + return tree1->s - tree2->s; +} + + +static int +p_sort(x, y) +char *x, *y; +{ + tree_node_t *tree1 = *(tree_node_t **) x, *tree2 = *(tree_node_t **) y; + + return tree1->p - tree2->p; +} + +int +gl_gen_complex_gates(level, s, p, root_type, forms) +int level, s, p; +tree_node_type_t root_type; +tree_node_t ***forms; +{ + int i, j, k, *value, num1, nforms, *nforms1; + tree_node_t *tree, **forms1; + partition_t *part; + combination_t *unique; + avl_tree *hash; + + /* There is only a single level-0 form (or single form for s=1,p=1) */ + if (level <= 0 || (s <= 1 && p <= 1)) { + *forms = ALLOC(tree_node_t *, 1); + tree = gl_alloc_leaf(NIL(char)); + tree->type = root_type; + tree->s = tree->p = 1; + tree->level = 0; + (*forms)[0] = tree; + return 1; + } + + /* setup a table to identify unique forms */ + hash = gl_hash_init(); + + /* generate the single level-0 form */ + tree = gl_alloc_leaf(NIL(char)); + tree->type = root_type; + (void) gl_hash_find_or_add(hash, tree); + + /* Loop for all partitions of either 's' or 'p' */ + if (root_type == AND_NODE) { + part = gl_init_gen_partition(s); + } else { + part = gl_init_gen_partition(p); + } + + while (gl_next_partition(part, &value, &k)) { + + /* Recursively generate all forms for the largest partition value */ + if (root_type == AND_NODE) { + num1 = gl_gen_complex_gates(level-1, part->value[0], p, + OR_NODE, &forms1); + } else { + num1 = gl_gen_complex_gates(level-1, s, part->value[0], + AND_NODE, &forms1); + } + + /* Sort the sub-trees by 's' or 'p' */ + if (root_type == AND_NODE) { + qsort((char *) forms1, num1, sizeof(tree_node_t *), s_sort); + nforms1 = ALLOC(int, k); + for(j = 0; j < k; j++) { + nforms1[j] = 0; + } + for(i = 0; i < num1; i++) { + for(j = 0; j < k; j++) { + if (forms1[i]->s <= part->value[j]) { + nforms1[j]++; + } + } + } + } else { + qsort((char *) forms1, num1, sizeof(tree_node_t *), p_sort); + nforms1 = ALLOC(int, k); + for(j = 0; j < k; j++) { + nforms1[j] = 0; + } + for(i = 0; i < num1; i++) { + for(j = 0; j < k; j++) { + if (forms1[i]->p <= part->value[j]) { + nforms1[j]++; + } + } + } + } + + + unique = gl_init_gen_combination(nforms1, k); + while (gl_next_nonincreasing_combination(unique, &value)) { + tree = gl_alloc_node(k); + tree->type = root_type; + for(i = 0; i < k; i++) { + tree->sons[i] = gl_dup_tree(forms1[value[i]]); + } + + /* add tree to output only if it is unique */ + /* note that 'hash_find_or_add also sets the (s,p) values */ + if (! gl_hash_find_or_add(hash, tree)) { + /* is not a new tree, discard it */ + gl_free_tree(tree); + } + } + gl_free_gen_combination(unique); + + for(i = 0; i < num1; i++) { + gl_free_tree(forms1[i]); + } + FREE(forms1); + FREE(nforms1); + + } + gl_free_gen_partition(part); + + nforms = gl_hash_end(hash, forms); + return nforms; +} + +int +gl_generate_complex_gates(level, s, p, forms) +int level, s, p; +tree_node_t ***forms; +{ + int num1, num2, i; + tree_node_t **forms1, **forms2; + + num1 = gl_gen_complex_gates(level, s, p, AND_NODE, &forms1); + num2 = gl_gen_complex_gates(level, s, p, OR_NODE, &forms2); + *forms = ALLOC(tree_node_t *, num1 + num2); + for(i = 0; i < num1; i++) { + (*forms)[i] = forms1[i]; + } + + /* hack -- drop the inverter from the OR-node trees */ + for(i = 1; i < num2; i++) { + (*forms)[num1 + i - 1] = forms2[i]; + } + FREE(forms1); + FREE(forms2); + + return num1 + num2 - 1; +} diff --git a/sis/genlib/com_genlib.c b/sis/genlib/com_genlib.c new file mode 100644 index 0000000..f4afd5c --- /dev/null +++ b/sis/genlib/com_genlib.c @@ -0,0 +1,90 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/com_genlib.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)com_genlib.c 1.1 */ +/* last modified on 7/2/91 at 01:34:28 */ +#include "sis.h" +#include "genlib_int.h" + +static int +com_genlib_print(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, use_nand; + char *infile, *real_infile; + char *outfile, *real_outfile; + FILE *fp, *outfp; + + use_nand = 0; /* default is nor */ + outfile = NIL(char); + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "do:")) != EOF) { + switch (c) { + case 'd': + use_nand = 1; + break; + case 'o': + outfile = util_optarg; + break; + default: + goto usage; + } + } + if (argc - util_optind != 1) goto usage; + + infile = argv[util_optind]; + fp = com_open_file(infile, "r", &real_infile, 0); + if (fp == NULL) goto error_return; + + if (outfile == NIL(char)) { + outfp = sisout; + } else { + outfp = com_open_file(outfile, "w", &real_outfile, 0); + if (outfp == NULL) { + FREE(real_outfile); + goto error_return; + } + } + if (! genlib_parse_library(fp, real_infile, outfp, ! use_nand)) { + (void)fprintf(siserr, "%s", error_string()); + (void)fclose(fp); + goto error_return; + } + + FREE(real_infile); + if (outfp != sisout) { + FREE(real_outfile); + (void) fclose(outfp); + } + return 0; + + usage: + (void) fprintf(siserr, "_genlib_print [-d] [-o outfile] lib.genlib\n"); + (void) fprintf(siserr, "\t-d : use nand gates\n"); + (void) fprintf(siserr, "\t-o outfile : outputs to outfile instead of sisout\n"); + return 1; + + error_return: + FREE(real_infile); + return 1; +} + +init_genlib() +{ + com_add_command("_genlib_print", com_genlib_print, /* changes_network */ 0); +} + +end_genlib() +{ +} + + diff --git a/sis/genlib/comb.c b/sis/genlib/comb.c new file mode 100644 index 0000000..f92fafa --- /dev/null +++ b/sis/genlib/comb.c @@ -0,0 +1,244 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/comb.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)comb.c 1.1 */ +/* last modified on 5/29/91 at 12:35:19 */ +#include "genlib_int.h" + +combination_t * +gl_init_gen_combination(value, n) +int *value; +int n; +{ + int i; + combination_t *comb; + + comb = ALLOC(combination_t, 1); + comb->n = n; + comb->value = ALLOC(int, n); + comb->state = ALLOC(int, n); + for(i = 0; i < n; i++) { + comb->state[i] = 0; + comb->value[i] = value[i]; + } + comb->state[0] = -1; + return comb; +} + + +void +gl_free_gen_combination(comb) +combination_t *comb; +{ + FREE(comb->value); + FREE(comb->state); + FREE(comb); +} + + +int +gl_next_combination(comb, vector) +combination_t *comb; +int **vector; +{ + int k; + + for(k = 0; k < comb->n; k++) { + /* advance position k */ + comb->state[k]++; + + /* Check for overflow in position k */ + if (comb->state[k] >= comb->value[k]) { + comb->state[k] = 0; + } else { + *vector = comb->state; + return 1; + } + } + return 0; /* no more possibilities */ +} + + +int +gl_next_nondecreasing_combination(comb, vector) +combination_t *comb; +int **vector; +{ + int k, nondecreasing; + + do { + if (! gl_next_combination(comb, vector)) { + return 0; + } + + nondecreasing = 1; + for(k = 1; k < comb->n; k++) { + if (comb->state[k-1] > comb->state[k]) { + nondecreasing = 0; + break; + } + } + } while (! nondecreasing); + return 1; +} + + +int +gl_next_nonincreasing_combination(comb, vector) +combination_t *comb; +int **vector; +{ + int k, nonincreasing; + + do { + if (! gl_next_combination(comb, vector)) { + return 0; + } + + nonincreasing = 1; + for(k = 1; k < comb->n; k++) { + if (comb->state[k-1] < comb->state[k]) { + nonincreasing = 0; + break; + } + } + } while (! nonincreasing); + return 1; +} + +partition_t * +gl_init_gen_partition(s) +int s; +{ + int i; + partition_t *part; + + part = ALLOC(partition_t, 1); + part->nvalue = s; + part->value = ALLOC(int, part->nvalue); + for(i = 0; i < part->nvalue; i++) { + part->value[i] = 0; + } + part->value[0] = 0; + if (s > 1) part->value[1] = 1; + part->non_zero = 1; + part->sum = 1; + part->maxsum = s; + return part; +} + + +void +gl_free_gen_partition(part) +partition_t *part; +{ + FREE(part->value); + FREE(part); +} + + +int +gl_next_partition_less_than(part, value, n) +partition_t *part; +int **value; /* array of values in partition */ +int *n; /* number of values */ +{ + int k, l, new_value; + + for(k = 0; k < part->nvalue; k++) { + /* advance position k */ + if (part->value[k] == 0) part->non_zero++; + part->value[k]++; + part->sum++; + + /* check that the sum is <= s */ + if (part->sum <= part->maxsum) { + *n = part->non_zero; + *value = part->value; + return 1; + + } else { + if (k == part->nvalue - 1) return 0; + + /* get set to advance the next counter */ + for(l = 0; l <= k; l++) { + new_value = part->value[k+1] + 1; + part->sum = part->sum - part->value[l] + new_value; + part->value[l] = new_value; + } + } + } + return 0; /* no more partitions */ +} + + +int +gl_next_partition(part, value, n) +partition_t *part; +int **value; +int *n; +{ + while (gl_next_partition_less_than(part, value, n)) { + if (part->sum == part->maxsum) { /* cheat */ + return 1; + } + } + return 0; +} + +#ifdef TEST +#include + +void exit(); + +void +usage(s) +char *s; +{ + (void) fprintf(stderr, "usage: %s n l1 l2 ... ln\n", s); + exit(2); +} + + +main(argc, argv) +int argc; +char **argv; +{ + int i, n, array[40], *vector; + combination_t *comb; + + if (argc < 2) usage(argv[0]); + n = atoi(argv[1]); + if (argc < n+2) usage(argv[0]); + + for(i = 0; i < n; i++) { + array[i] = atoi(argv[i+2]); + } + + (void) printf("Combinations are\n"); + comb = gl_init_gen_combination(array, n); + while (gl_next_combination(comb, &vector)) { + for(i = 0; i < n; i++) { + (void) printf(" %d", vector[i]); + } + (void) printf("\n"); + } + gl_free_gen_combination(comb); + + (void) printf("Nondecreasing combinations are\n"); + comb = gl_init_gen_combination(array, n); + while (gl_next_nondecreasing_combination(comb, &vector)) { + for(i = 0; i < n; i++) { + (void) printf(" %d", vector[i]); + } + (void) printf("\n"); + } + gl_free_gen_combination(comb); +} +#endif diff --git a/sis/genlib/comb.h b/sis/genlib/comb.h new file mode 100644 index 0000000..317931d --- /dev/null +++ b/sis/genlib/comb.h @@ -0,0 +1,37 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/comb.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)comb.h 1.1 */ +/* last modified on 5/29/91 at 12:35:20 */ +typedef struct partition_struct partition_t; +struct partition_struct { + int *value; + int nvalue; + int non_zero; + int sum; + int maxsum; +}; + + +typedef struct combination_struct combination_t; +struct combination_struct { + int *value; + int *state; + int n; +}; + + + +combination_t *gl_init_gen_combination(); +int gl_next_combination(), gl_next_nondecreasing_combination(); +void gl_free_gen_combination(); + +partition_t *gl_init_gen_partition(); +int gl_next_partition_less_than(), gl_next_partition(); +void gl_free_gen_partition(); diff --git a/sis/genlib/count.c b/sis/genlib/count.c new file mode 100644 index 0000000..0c8a598 --- /dev/null +++ b/sis/genlib/count.c @@ -0,0 +1,136 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/count.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)count.c 1.1 */ +/* last modified on 5/29/91 at 12:35:21 */ +#include "genlib_int.h" + +static int f[40][20][20]; + + +static int +count_it(value, n) +int *value; +int n; +{ + int i, l, sum, smallest, *value1; + + if (n == 1) { + sum = value[0]; + } else { + smallest = value[n-1]; + sum = 0; + for(i = 0; i < smallest; i++) { + value1 = ALLOC(int, n-1); + for(l = 0; l < n-1; l++) { + value1[l] = value[l] - i; + } + sum += count_it(value1, n-1); + FREE(value1); + } + } + return sum; +} + +static int +hack_adjust(n, s, p) +int n, s, p; +{ + int sum, temp[100]; + + sum = 0; + + switch (s) { + case 0: + case 1: + case 2: + case 3: + break; + case 4: + /* 1 3, 2 2 -- subtract 1 2 */ + temp[0] = gl_number_of_gates(n-1, p, 2); + temp[1] = gl_number_of_gates(n-1, p, 1); + sum += count_it(temp, 2); + break; + + case 5: + /* 1 4, 2 3 -- subtract 1 3 */ + temp[0] = gl_number_of_gates(n-1, p, 3); + temp[1] = gl_number_of_gates(n-1, p, 1); + sum += count_it(temp, 2); + + /* 1 2 2, 1 1 3 -- subtract 1 1 2 */ + temp[0] = gl_number_of_gates(n-1, p, 2); + temp[1] = gl_number_of_gates(n-1, p, 1); + temp[2] = gl_number_of_gates(n-1, p, 1); + sum += count_it(temp, 3); + break; + + case 6: + /* 1 5, 2 4, 3 3 -- subtract 1 4, 2 3, 1 3, add 1 3 */ + temp[0] = gl_number_of_gates(n-1, p, 4); + temp[1] = gl_number_of_gates(n-1, p, 1); + sum += count_it(temp, 2); + temp[0] = gl_number_of_gates(n-1, p, 3); + temp[1] = gl_number_of_gates(n-1, p, 2); + sum += count_it(temp, 2); + + /* 2 2 2, 1 2 3, 1 1 4 -- subtract 1 2 2, 1 1 2, 1 1 3, add 1 1 2 */ + temp[0] = gl_number_of_gates(n-1, p, 2); + temp[1] = gl_number_of_gates(n-1, p, 2); + temp[2] = gl_number_of_gates(n-1, p, 1); + sum += count_it(temp, 3); + temp[0] = gl_number_of_gates(n-1, p, 3); + temp[1] = gl_number_of_gates(n-1, p, 1); + temp[2] = gl_number_of_gates(n-1, p, 1); + sum += count_it(temp, 3); + + /* 1 1 2 2, 1 1 1 3 -- subtract 1 1 1 2 */ + temp[0] = gl_number_of_gates(n-1, p, 2); + temp[1] = gl_number_of_gates(n-1, p, 1); + temp[2] = gl_number_of_gates(n-1, p, 1); + temp[3] = gl_number_of_gates(n-1, p, 1); + sum += count_it(temp, 4); + break; + + default: + (void) fprintf(stderr, "s >= 7 not supported.\n"); + exit(1); + } + return sum; +} + +int +gl_number_of_gates(n, s, p) +{ + int i, k, sum, *value, *temp; + partition_t *part; + + if (f[n][s][p] == 0) { + if (n == 0) { + sum = 1; + + } else { + sum = 1; + part = gl_init_gen_partition(s); + while (gl_next_partition(part, &value, &k)) { + temp = ALLOC(int, k); + for(i = 0; i < k; i++) { + temp[i] = gl_number_of_gates(n-1, p, value[i]); + } + sum += count_it(temp, k); + FREE(temp); + } + gl_free_gen_partition(part); + sum -= hack_adjust(n, s, p); + } + f[n][s][p] = sum; + } + return f[n][s][p]; +} diff --git a/sis/genlib/genlib.c b/sis/genlib/genlib.c new file mode 100644 index 0000000..fb4308c --- /dev/null +++ b/sis/genlib/genlib.c @@ -0,0 +1,373 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/genlib.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)genlib.c 1.1 */ +/* last modified on 5/29/91 at 12:35:22 */ +#include "genlib_int.h" + +static int check_internal_phase(); +static int set_functions(); + + +static int +leaf_compare(t1, t2) +char **t1, **t2; +{ + tree_node_t *tree1 = *(tree_node_t **) t1; + tree_node_t *tree2 = *(tree_node_t **) t2; + + return strcmp(tree1->name, tree2->name); +} + + + +int +gl_convert_gate_to_blif(name, area, function, pins, use_nor) +char *name; +double area; +function_t *function; +pin_info_t *pins; +int use_nor; +{ + pin_info_t *pin, *pinnext; + tree_node_t **list, **leafs; + int i, j, nlist, nleafs; + FILE *fpout = gl_out_file; + + if (! check_internal_phase(function->tree, 0)) { + return 0; + } + + if (function->tree->type == ZERO_NODE || function->tree->type == ONE_NODE) { + /* special case for constants */ + nlist = 1; + list = ALLOC(tree_node_t *, 1); + list[0] = gl_dup_tree(function->tree); + + } else { + /* make the tree strictly alternate AND/OR */ + gl_make_well_formed(function->tree); + + /* generate all nand or nor gate forms */ + nlist = gl_nand_gate_forms(function->tree, &list, use_nor); + + /* set all tree nodes to a specific type */ + for(i = 0; i < nlist; i++) { + set_functions(list[i], use_nor); + } + } + + /* get the leaf names */ + nleafs = gl_get_unique_leaf_pointers(function->tree, &leafs); + qsort((char *) leafs, nleafs, sizeof(tree_node_t *), leaf_compare); + + for(i = 0; i < nlist; i++) { + gl_assign_node_names(list[i]); + FREE(list[i]->name); + list[i]->name = util_strsav(function->name); + + (void) fprintf(fpout, "# (%d of %d) %s-FORM of ", + i+1, nlist, use_nor ? "NOR" : "NAND"); + gl_print_tree(fpout, function->tree); + (void) fprintf(fpout, "\n"); + (void) fprintf(fpout, ".model %s\n", name); + + gl_write_blif(fpout, list[i], use_nor, NIL(latch_info_t)); + + (void) fprintf(fpout, ".area %3.2f\n", area); + + for(pin = pins; pin != 0; pin = pin->next) { + if (strcmp(pin->name, "*") == 0) { + if (pin != pins || pin->next != 0) { /* only 1 allowed */ + read_error("improper use of pin wildcard '*'"); + return 0; + } + for(j = 0; j < nleafs; j++) { + (void) fprintf(fpout, + ".delay %s %s %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f\n", + leafs[j]->name, pin->phase, pin->value[0], + pin->value[1], pin->value[2], pin->value[3], + pin->value[4], pin->value[5]); + } + } else { + for(j = 0; j < nleafs; j++) { + if (strcmp(pin->name, leafs[j]->name) == 0) { + break; + } + } + if (j == nleafs) { + read_error("pin (in delay info) not found"); + return 0; + } + (void) fprintf(fpout, + ".delay %s %s %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f\n", + pin->name, pin->phase, pin->value[0], + pin->value[1], pin->value[2], pin->value[3], + pin->value[4], pin->value[5]); + } + } + + (void) fprintf(fpout, ".end\n\n"); + + gl_free_tree(list[i]); + } + FREE(list); + FREE(leafs); + + /* free memory used */ + for(pin = pins; pin != 0; pin = pinnext) { + pinnext = pin->next; + FREE(pin->name); + FREE(pin->phase); + FREE(pin); + } + gl_free_tree(function->tree); + FREE(function->name); + FREE(function); + FREE(name); + return 1; +} + +/* sequential support */ +int +gl_convert_latch_to_blif(name, area, function, pins, use_nor, latch, clock, constraints) +char *name; +double area; +function_t *function; +pin_info_t *pins; +int use_nor; +latch_info_t *latch; /* sequential support */ +pin_info_t *clock; /* sequential support */ +constraint_info_t *constraints; /* sequential support */ +{ + pin_info_t *pin, *pinnext; + tree_node_t **list, **leafs; + int i, j, nlist, nleafs; + FILE *fpout = gl_out_file; + constraint_info_t *constr, *constrnext; + + if (! check_internal_phase(function->tree, 0)) { + return 0; + } + + if (function->tree->type == ZERO_NODE || function->tree->type == ONE_NODE) { + /* special case for constants */ + nlist = 1; + list = ALLOC(tree_node_t *, 1); + list[0] = gl_dup_tree(function->tree); + + } else { + /* make the tree strictly alternate AND/OR */ + gl_make_well_formed(function->tree); + + /* generate all nand or nor gate forms */ + nlist = gl_nand_gate_forms(function->tree, &list, use_nor); + + /* set all tree nodes to a specific type */ + for(i = 0; i < nlist; i++) { + set_functions(list[i], use_nor); + } + } + + /* get the leaf names */ + nleafs = gl_get_unique_leaf_pointers(function->tree, &leafs); + qsort((char *) leafs, nleafs, sizeof(tree_node_t *), leaf_compare); + + for(i = 0; i < nlist; i++) { + gl_assign_node_names(list[i]); + FREE(list[i]->name); + list[i]->name = util_strsav(function->name); + + (void) fprintf(fpout, "# (%d of %d) %s-FORM of ", + i+1, nlist, use_nor ? "NOR" : "NAND"); + gl_print_tree(fpout, function->tree); + (void) fprintf(fpout, "\n"); + (void) fprintf(fpout, ".model %s\n", name); + + gl_write_blif(fpout, list[i], use_nor, latch); + + (void) fprintf(fpout, ".area %3.2f\n", area); + + for(pin = pins; pin != 0; pin = pin->next) { + if (strcmp(pin->name, "*") == 0) { + if (pin != pins || pin->next != 0) { /* only 1 allowed */ + read_error("improper use of pin wildcard '*'"); + return 0; + } + for(j = 0; j < nleafs; j++) { + /* sequential support */ + /* don't print delay info for latch output */ + if (strcmp(leafs[j]->name, latch->out)==0) continue; + (void) fprintf(fpout, + ".delay %s %s %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f\n", + leafs[j]->name, pin->phase, pin->value[0], + pin->value[1], pin->value[2], pin->value[3], + pin->value[4], pin->value[5]); + } + } else { + for(j = 0; j < nleafs; j++) { + if (strcmp(pin->name, leafs[j]->name) == 0) { + break; + } + } + if (j == nleafs) { + read_error("pin (in delay info) not found"); + return 0; + } + /* sequential support */ + /* don't print delay info for latch output */ + if (strcmp(pin->name, latch->out)!=0) { + (void) fprintf(fpout, + ".delay %s %s %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f\n", + pin->name, pin->phase, pin->value[0], + pin->value[1], pin->value[2], pin->value[3], + pin->value[4], pin->value[5]); + } + } + } + + /* sequential support */ + /* take care of the clock signal */ + if (clock != NIL(pin_info_t)) { + (void) fprintf(fpout, ".clock %s\n", clock->name); + (void) fprintf(fpout, + ".delay %s %s %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f\n", + clock->name, clock->phase, clock->value[0], + clock->value[1], clock->value[2], clock->value[3], + clock->value[4], clock->value[5]); + } else { + if (latch != NIL(latch_info_t) && strcmp(latch->type,"as") != 0) { + read_error("no clock delay info found for synchronous latch"); + return 0; + } + } + /* take care of setup/hold times */ + if (constraints != NIL(constraint_info_t)) { + for(constr = constraints; constr != 0; constr = constr->next) { + if (strcmp(constr->name, "*") == 0) { + if (constr != constraints || constr->next != 0) { /* only 1 allowed */ + read_error ("improper use of pin wildcard '*'"); + return 0; + } + for (j = 0; j < nleafs; j++) { + /* sequential support */ + /* don't print delay info for latch output */ + if (strcmp(leafs[j]->name, latch->out)==0) continue; + (void) fprintf(fpout, + ".input_arrival %s %4.3f %4.3f\n", + leafs[j]->name, constr->setup, constr->hold); + } + } else { + for(j = 0; j < nleafs; j++) { + if (strcmp(constr->name, leafs[j]->name) == 0) { + break; + } + } + if (j == nleafs) { + read_error("constr (in delay info) not found"); + return 0; + } + if (strcmp(constr->name, latch->out)!=0) { + (void) fprintf(fpout, + ".input_arrival %s %4.3f %4.3f\n", + constr->name, constr->setup, constr->hold); + } + } + } + } else { + /* no setup/hold times are specified; use 0.0 */ + for (j = 0; j < nleafs; j++) { + /* don't print delay info for latch output */ + if (strcmp(leafs[j]->name, latch->out)==0) continue; + (void) fprintf(fpout, ".input_arrival %s 0.0 0.0\n", leafs[j]->name); + } + } + + /* take care of latch connections */ + /* .latch requires input output type clock initial-value */ + /* use 0 for initial-value; it's not used anyway */ + (void) fprintf(fpout, ".latch %s %s %s %s 0\n", latch->in, latch->out, latch->type, + clock==NIL(pin_info_t)?"NIL":clock->name); + + (void) fprintf(fpout, ".end\n\n"); + + gl_free_tree(list[i]); + } + FREE(list); + FREE(leafs); + + /* free memory used */ + for(pin = pins; pin != 0; pin = pinnext) { + pinnext = pin->next; + FREE(pin->name); + FREE(pin->phase); + FREE(pin); + } + gl_free_tree(function->tree); + FREE(function->name); + FREE(function); + FREE(name); + /* sequential support */ + if (clock != NIL(pin_info_t)) { + FREE(clock->name); + FREE(clock->phase); + FREE(clock); + } + for(constr = constraints; constr != 0; constr = constrnext) { + constrnext = constr->next; + FREE(constr->name); + FREE(constr); + } + FREE(latch->in); + FREE(latch->out); + FREE(latch->type); + FREE(latch); + return 1; +} + +static int +check_internal_phase(tree, level) +tree_node_t *tree; +int level; +{ + int i; + + if (tree->nsons != 0) { + for(i = 0; i < tree->nsons; i++) { + if (! check_internal_phase(tree->sons[i], level+1)) { + return 0; /* error in some child */ + } + } + /* if (level > 0 && tree->phase != 1) { + * read_error("inversion allowed only at root and leaves of function"); + * return 0; + * } + */ + if (level > 0 && (tree->type == ZERO_NODE || tree->type == ONE_NODE)) { + read_error("0 and 1 are allowed only at the root of a function"); + return 0; + } + + } + return 1; +} + + +static int +set_functions(tree, use_nor) +tree_node_t *tree; +int use_nor; +{ + int i; + + for(i = 0; i < tree->nsons; i++) { + set_functions(tree->sons[i], use_nor); + } + tree->type = use_nor ? NOR_NODE : NAND_NODE; +} diff --git a/sis/genlib/genlib.doc b/sis/genlib/genlib.doc new file mode 100644 index 0000000..0631f1d --- /dev/null +++ b/sis/genlib/genlib.doc @@ -0,0 +1,191 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/genlib.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)genlib.doc 1.1 */ +/* last modified on 5/29/91 at 12:36:49 */ + +genlib.doc +Richard Rudell +10/28/87 +12/29/87 Rev. 1 +Cho Moon +12/14/88 Sequential Extension +2/26/90 Revisions + +COMBINATIONAL GATE SPECIFICATION + +A cell is specified in the following format: + + GATE + + . + . + + + is the name of the cell in the cell library. The resulting +net-list will be in terms of these names. + + defines the relative area cost of the cell. It is a floating +point number, and may be in any unit system convenient for the user. + + is an equation written in conventional algebraic +notation using the operators '+' for OR, '*' or nothing (space) for AND, +'!' or ''' (post-fixed) for NOT, and parentheses for grouping. The +names of the literals in the equation define the input pin names +for the cell; the name on the left hand side of the equation defines +the output of the cell. The equation terminates with a semicolon. + +Only single-output cells may be specified. The '!' operator may only +be used on the input literals, or on the final output; it is not +allowed internal to an expression. (This constraint may disappear in +the future). + +Also, the actual factored form is significant when a logic function has +multiple factored forms. In principle, all factored forms could be +derived for a given logic function automatically; this is not yet +implemented, so each must be specified separately. Note that factored +forms which differ by a permutation of the input variables (or by De +Morgan's law) are not considered unique. + + +Each has the format: + + PIN + + + + must be the name of a pin in the , +or it can be * to specify identical timing information for all pins. + + is INV, NONINV, or UNKNOWN corresponding to whether the +logic function is negative-unate, positive-unate, or binate in +this input variable respectively. This is required for the separate +rise-fall delay model. (In principle, this information is easily +derived from the logic function; this field may disappear in the future). + + gives the input load of this pin. It is a floating point +value, in arbitrary units convenient for the user. + + specifies a loading constraint for the cell. It is a +floating point value specifying the maximum load allowed on the output. + + and are the rise-time parameters +for the timing model. They are floating point values, typically in +the units nanoseconds, and nanoseconds/unit-load repsectively. + + and are the fall-time parameters +for the timing model. They are floating point values, typically in +the units nanoseconds, and nanoseconds/unit-load repsectively. + +All of the delay information is specified on a pin-by-pin basis. The +meaning is the delay information for the most critical pin is used +to determine the delay for the gate. + +LATCH SPECIFICATION + +Latches are specified as follows: + + LATCH + + . + . + + + [] + [] + +, , and +are the same as in the combinational case. + is required but is optional. + is necessary for synchronous latches and +flip-flops. + + has the following format: + + SEQ + + must be the name of the output of the cell. +Thus, is described as a function of +in the . +A special name "ANY" can be used for to specify +to the mapper that needs not be a signal name in the +. This is useful for describing D-type flip-flops +and latches. can be ACTIVE_HIGH or ACTIVE_LOW for transparent latches; +RISING_EDGE or FALLING_EDGE for edge-triggered flip-flops; or ASYNCH +for asychronous latches. + + gives the propagation delay from the clock +pin to the output. Its format is as follows: + + CONTROL + + + + gives the setup and hold time constraints +with respect to the clock signal. The format is: + + CONSTRAINT + +If not specified, the values of 0.0 are assumed. + +--------------------------------------------------------------------------- +Example 0 of latch specification + + LATCH "d-latch" 80 Q=D; + PIN D NONINV 1 999 1 .2 1 .2 + SEQ Q ANY ACTIVE_HIGH + CONTROL CLK 1 999 1 .2 1 .2 + CONSTRAINT D 0.2 0.2 + +--------------------------------------------------------------------------- +Example 1 of + + O = !(!I1 * I2); + +is legal and defines a NAND gate with 1 inverted input; it could also +be specified as + + O = I1 + !I2; + +There is no advantage or disadvantage to either representation; only 1 +need be given. + + +--------------------------------------------------------------------------- +Example 2 of + + O = !((I1 * I2) + !(I3 + I4)); + +is incorrectly specified. It must be re-written as either: + + O = !((I1 * I2) + (!I3 * !I4)); + +or + + O = (!I1 + !I2)*(I3 + I4); + +Again, there is no advantage or disadvantage to either representation as +they differ only by De Morgan's law. Only 1 need be given. Note that +there are no other factored forms for this equation. + + +--------------------------------------------------------------------------- +Example 3 of + + O = a*b + a*c + b*c; + +is one specification of a majority gate. Another possible specification +(which IS considered different) is: + + O = a*(b + c) + b*c; + +Any permutation of the input variables does not provide a new specification; +hence, these are the only two useful representations for a majority +gate logic function. Both should be provided to the technology mapping +program, until further notice. diff --git a/sis/genlib/genlib.h b/sis/genlib/genlib.h new file mode 100644 index 0000000..8421ea7 --- /dev/null +++ b/sis/genlib/genlib.h @@ -0,0 +1,14 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/genlib.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)genlib.h 1.1 */ +/* last modified on 5/29/91 at 12:35:24 */ +/* exported functions to mis ... */ + +extern int genlib_parse_library(); diff --git a/sis/genlib/genlib_int.h b/sis/genlib/genlib_int.h new file mode 100644 index 0000000..5b92092 --- /dev/null +++ b/sis/genlib/genlib_int.h @@ -0,0 +1,52 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/genlib_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)genlib_int.h 1.1 */ +/* last modified on 5/29/91 at 12:35:25 */ +#include +#include "sis.h" +#include "genlib.h" +#include "sptree.h" +#include "comb.h" + + +typedef struct function_struct function_t; +struct function_struct { + char *name; + tree_node_t *tree; + function_t *next; /* someday, multiple-output */ +}; + + +typedef struct pin_info_struct pin_info_t; +struct pin_info_struct { + char *name; + char *phase; + double value[10]; + pin_info_t *next; +}; + +/* sequential support */ +typedef struct latch_info_struct latch_info_t; +struct latch_info_struct { + char *in; + char *out; + char *type; +}; + +typedef struct constraint_info_struct constraint_info_t; +struct constraint_info_struct { + char *name; + double setup; + double hold; + constraint_info_t *next; +}; + +extern FILE *gl_out_file; +extern int read_lineno; /* hack ! */ diff --git a/sis/genlib/io.c b/sis/genlib/io.c new file mode 100644 index 0000000..e3b2d15 --- /dev/null +++ b/sis/genlib/io.c @@ -0,0 +1,260 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/io.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)io.c 1.1 */ +/* last modified on 5/29/91 at 12:35:27 */ +#include "genlib_int.h" + + +void +gl_table_by_level(s_max, p_max) +int s_max, p_max; +{ + int n, s, p, num; + + (void) printf(" "); + for(n = 0; n <= 10; n++) { + (void) printf(" %7d", n); + } + (void) printf("\n"); + + for(s = 1; s <= s_max; s++) { + for(p = 1; p <= p_max; p++) { + num = gl_number_of_gates(s+p, s, p); + (void) printf("%d %d (%9d): ", s, p, num); + for(n = 0; n <= 10; n++) { + num = gl_number_of_gates(n, s, p) ; + if (n > 0) { + num -= gl_number_of_gates(n-1, s, p) ; + } + if (num > 0) { + (void) printf(" %7d", num); + } else { + (void) printf(" %7s", " "); + } + } + (void) printf("\n"); + } + } +} + + +void +gl_table_of_gate_count(s_max, p_max) +{ + int s, p, level, num; + + (void) printf(" "); + for(s = 1; s <= s_max; s++) { + (void) printf(" %9d", s); + } + (void) printf("\n"); + for(s = 1; s <= s_max; s++) { + (void) printf("%d : ", s); + for(p = 1; p <= p_max; p++) { + level = s+p-2; + num = gl_number_of_gates(level, s, p) + gl_number_of_gates(level,p,s) - 1; + (void) printf(" %9d", num); + } + (void) printf("\n"); + } +} + + +void +gl_table_of_nand_forms(s_max, p_max) +int s_max, p_max; +{ + int s, p, level, num; + + (void) printf(" "); + for(s = 1; s <= s_max; s++) { + (void) printf(" %9d", s); + } + (void) printf("\n"); + for(s = 1; s <= s_max; s++) { + (void) printf("%d : ", s); + for(p = 1; p <= p_max; p++) { + level = s + p - 2; + num = gl_number_of_nand_forms(level, s, p); + (void) printf(" %9d", num); + } + (void) printf("\n"); + } +} + +int +gl_num_leafs(tree) +tree_node_t *tree; +{ + int i, sum; + + sum = 0; + for(i = 0; i < tree->nsons; i++) { + sum += gl_num_leafs(tree->sons[i]); + } + return sum + (tree->nsons == 0); +} + + +void +gl_print_all_gates_genlib(level, s, p, invert_output) +int level, s, p, invert_output; +{ + tree_node_t **list, *tree; + int i, nlist; + + if (level < 0) level = s+p; + nlist = gl_generate_complex_gates(level, s, p, &list); + + for(i = 0; i < nlist; i++) { + list[i]->phase = ! invert_output; + } + + for(i = 0; i < nlist; i++) { + tree = list[i]; + (void) printf("GATE \""); + gl_print_tree(stdout, tree); + (void) printf("\" %d O=", gl_num_leafs(tree)+1); + gl_print_tree_algebraic(stdout, tree); + (void) printf(";\n"); + (void) printf("PIN * INV 1 999 1.0 0.2 1.0 0.2\n"); + gl_free_tree(tree); + } + FREE(list); +} + +void +gl_print_all_gates(level, s, p) +int level, s, p; +{ + tree_node_t **list, *tree; + int i, nlist; + + if (level < 0) level = s+p; + nlist = gl_generate_complex_gates(level, s, p, &list); + + for(i = 0; i < nlist; i++) { + tree = list[i]; + (void) printf("level=%d s=%d p=%d ", + tree->level, tree->s, tree->p); + gl_print_tree(stdout, tree); + (void) printf("\n"); + } + (void) printf("Total forms = %d\n", nlist); + + for(i = 0; i < nlist; i++) { + gl_free_tree(list[i]); + } + FREE(list); +} + + +void +gl_print_all_nand_forms(level, s, p, use_nor_gate, invert_output) +int level, s, p; +int use_nor_gate, invert_output; +{ + tree_node_t **list, **list1, *tree, *nand_tree; + int i, j, nlist, nlist1; + + if (level < 0) level = s+p; + nlist = gl_generate_complex_gates(level, s, p, &list); + + for(i = 0; i < nlist; i++) { + tree = list[i]; + tree->phase = ! invert_output; + gl_assign_leaf_names(tree); + nlist1 = gl_nand_gate_forms(tree, &list1, use_nor_gate); + + for(j = 0; j < nlist1; j++) { + nand_tree = list1[j]; + gl_assign_node_names(nand_tree); + + (void) printf(".model %s", invert_output ? "!(" : ""); + gl_print_tree(stdout, tree); + (void) printf("%s\n", invert_output ? ")" : ""); + + /* + (void) printf("# (%d of %d) %s-FORM\n", + j+1, nlist1, use_nor_gate ? "NOR" : "NAND"); + */ + gl_write_blif(stdout, nand_tree, use_nor_gate, NIL(latch_info_t)); + (void) printf(".end\n"); + } + + for(j = 0; j < nlist1; j++) { + gl_free_tree(list1[j]); + } + FREE(list1); + } + + for(i = 0; i < nlist; i++) { + gl_free_tree(list[i]); + } + FREE(list); +} + +int +gl_number_of_nand_forms(level, s, p) +{ + tree_node_t **list, **list1; + int i, j, count, nlist, nlist1; + + if (level < 0) level = s+p; + nlist = gl_generate_complex_gates(level, s, p, &list); + + count = 0; + for(i = 0; i < nlist; i++) { + nlist1 = gl_nand_gate_forms(list[i], &list1, 0); + count += nlist1; + for(j = 0; j < nlist1; j++) { + gl_free_tree(list1[j]); + } + FREE(list1); + } + + for(i = 0; i < nlist; i++) { + gl_free_tree(list[i]); + } + FREE(list); + return count; +} + +void +gl_print_nand_forms(string, use_nor_gate) +char *string; +int use_nor_gate; +{ + int i, nlist; + tree_node_t **list, *tree; + char *output_name; + + if (! gl_convert_expression_to_tree(string, &tree, &output_name)) { + (void) fprintf(stderr, "%s", error_string()); + exit(1); + } + gl_make_well_formed(tree); + + nlist = gl_nand_gate_forms(tree, &list, use_nor_gate); + + for(i = 0; i < nlist; i++) { + gl_assign_node_names(list[i]); + FREE(list[i]->name); + list[i]->name = util_strsav(output_name); + + (void) printf(".model "); + gl_print_tree(stdout, tree); + (void) printf("\n"); + gl_write_blif(stdout, list[i], use_nor_gate, NIL(latch_info_t)); + (void) printf(".end\n"); + gl_free_tree(list[i]); + } + gl_free_tree(tree); +} diff --git a/sis/genlib/nand.c b/sis/genlib/nand.c new file mode 100644 index 0000000..123e0cd --- /dev/null +++ b/sis/genlib/nand.c @@ -0,0 +1,358 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/nand.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)nand.c 1.1 */ +/* last modified on 5/29/91 at 12:35:28 */ +#include "util.h" /* for ASSERT !! */ +#include "genlib_int.h" + +static void +set_node_type(tree, type) +tree_node_t *tree; +tree_node_type_t type; +{ + int i; + + if (tree != 0) { + for(i = 0; i < tree->nsons; i++) { + set_node_type(tree->sons[i], type); + } + tree->phase = 1; + tree->type = type; + } +} + +#define DUMP_TABLES + + +static void +gl_write_blif_tables(fp, tree, use_nor_gate) +register FILE *fp; +tree_node_t *tree; +int use_nor_gate; +{ + register int i; + + for(i = 0; i < tree->nsons; i++) { + gl_write_blif_tables(fp, tree->sons[i], use_nor_gate); + } + + if (tree->nsons != 0) { + (void) fprintf(fp, ".names"); + for(i = 0; i < tree->nsons; i++) { + (void) putc(' ', fp); + (void) fputs(tree->sons[i]->name, fp); + } + (void) putc(' ', fp); + (void) fputs(tree->name, fp); + (void) putc('\n', fp); + +#ifdef DUMP_TABLES + if (use_nor_gate) { /* in theory, tree->type == NOR_NODE */ + for(i = 0; i < tree->nsons; i++) { + (void) putc('0', fp); + } + (void) putc(' ', fp); + (void) putc('1', fp); + (void) putc('\n', fp); + } else { + register int j; + for(i = 0; i < tree->nsons; i++) { + for(j = 0; j < tree->nsons; j++) { + if (i == j) { + (void) putc('0', fp); + } else { + (void) putc('-', fp); + } + } + (void) putc(' ', fp); + (void) putc('1', fp); + (void) putc('\n', fp); + } + } +#endif + } +} + + +static int +leaf_compare(t1, t2) +char **t1, **t2; +{ + tree_node_t *tree1 = *(tree_node_t **) t1; + tree_node_t *tree2 = *(tree_node_t **) t2; + + return strcmp(tree1->name, tree2->name); +} + + +static void +gl_write_blif_inputs(fp, tree, latch) +FILE *fp; +tree_node_t *tree; +latch_info_t *latch; /* sequential support */ +{ + int i, nleafs; + tree_node_t **leafs; + + nleafs = gl_get_unique_leaf_pointers(tree, &leafs); + qsort((char *) leafs, nleafs, sizeof(tree_node_t *), leaf_compare); + for(i = 0; i < nleafs; i++) { + + /* seqential support */ + /* Don't count latch output as a PI */ + if (latch != NIL(latch_info_t)) { + if ( strcmp(leafs[i]->name, latch->out) == 0 ) continue; + } + (void) putc(' ', fp); + (void) fputs(leafs[i]->name, fp); + } + FREE(leafs); +} + + +void +gl_write_blif(fp, tree, use_nor_gate, latch) +FILE *fp; +tree_node_t *tree; +int use_nor_gate; +latch_info_t *latch; /* sequential support */ +{ + if (tree->type == ZERO_NODE) { + (void) fprintf(fp, ".outputs %s\n", tree->name); + (void) fprintf(fp, ".names %s\n", tree->name); + } else if (tree->type == ONE_NODE) { + (void) fprintf(fp, ".outputs %s\n", tree->name); + (void) fprintf(fp, ".names %s\n 1\n", tree->name); + } else { + (void) fprintf(fp, ".inputs"); + gl_write_blif_inputs(fp, tree, latch); + (void) fprintf(fp, "\n"); + /* sequential support */ + /* Don't count latch input as a real PO */ + if (latch == NIL(latch_info_t)) { + (void) fprintf(fp, ".outputs %s\n", tree->name); + } + gl_write_blif_tables(fp, tree, use_nor_gate); + } +} + +/* + * make all binary-trees with 'n' leaves + * this is contained inside a permutation generator which tries all + * possible permutations of the leaves; hence, we can take the + * given order of the leaves as fixed + */ + +static array_t * +make_tree_recur(leafs, nleafs, level) +tree_node_t **leafs; +int nleafs; +int level; +{ + int i, j, k; + array_t *forms, *forms1, *forms2; + tree_node_t *node, *root, *son1, *son2; + + assert(nleafs > 0); + + forms = array_alloc(tree_node_t *, 0); + + if (nleafs == 1) { + root = gl_dup_tree(leafs[0]); /* tee-hee */ + array_insert_last(tree_node_t *, forms, root); + + } else { + for(i = 1; i <= nleafs/2; i++) { + forms1 = make_tree_recur(leafs, i, level + 1); + forms2 = make_tree_recur(leafs + i, nleafs - i, level + 1); + + for(j = 0; j < array_n(forms1); j++) { + for(k = 0; k < array_n(forms2); k++) { + node = gl_alloc_node(2); + son1 = gl_dup_tree(array_fetch(tree_node_t *, forms1, j)); + son2 = gl_dup_tree(array_fetch(tree_node_t *, forms2, k)); + node->sons[0] = son1; + node->sons[1] = son2; + + /* add extra inverter on all levels except top */ + if (level > 0) { + root = gl_alloc_node(1); + root->sons[0] = node; + array_insert_last(tree_node_t *, forms, root); + } else { + array_insert_last(tree_node_t *, forms, node); + } + } + } + + /* cleanup */ + for(j = 0; j < array_n(forms1); j++) { + gl_free_tree(array_fetch(tree_node_t *, forms1, j)); + } + for(k = 0; k < array_n(forms2); k++) { + gl_free_tree(array_fetch(tree_node_t *, forms2, k)); + } + array_free(forms1); + array_free(forms2); + } + } + return forms; +} + +static void +make_tree(list_in, n, state_in) +char **list_in; +int n; +char *state_in; +{ + tree_node_t *tree, **list = (tree_node_t **) list_in; + avl_tree *hash_table = (avl_tree *) state_in; + array_t *forms; + int i; + + forms = make_tree_recur(list, n, 0); + for(i = 0; i < array_n(forms); i++) { + tree = array_fetch(tree_node_t *, forms, i); + if (! gl_hash_find_or_add(hash_table, tree)) { + gl_free_tree(tree); + } + } + array_free(forms); +} + +static int +gl_nand_gate_forms_recur(tree, list, use_nor_gate) +tree_node_t *tree; +tree_node_t ***list; +int use_nor_gate; +{ + int i, j, n, nlist[32], *indices, invert_input, all_sons_isomorphic; + tree_node_t *node, **xlist[32], *temp_list[32]; + avl_tree *hash_table; + combination_t *comb; + + if (tree->nsons == 0) { + /* + * only problem with leafs is watching the extra inverters ... + */ + invert_input = tree->phase == 0; + if (((tree->type == OR_NODE) == use_nor_gate) != invert_input) { + node = gl_alloc_node(1); + node->sons[0] = gl_alloc_leaf(tree->name); + } else { + node = gl_alloc_leaf(tree->name); + } + *list = ALLOC(tree_node_t *, 1); + (*list)[0] = node; + n = 1; + + } else { + /* + * First generate all forms for our children + */ + for(i = 0; i < tree->nsons; i++) { + nlist[i] = gl_nand_gate_forms_recur(tree->sons[i], &(xlist[i]), + use_nor_gate); + } + + /* + * then, try all possible 'combinations' of one form from each child + */ + hash_table = gl_hash_init(); + comb = gl_init_gen_combination(nlist, (int) tree->nsons); + while (gl_next_combination(comb, &indices)) { + /* + * then, try all possible permutations of the child forms; bottom + * line is to call 'make_tree' to make all binary-trees with + * n leafs + */ + for(i = 0; i < tree->nsons; i++) { + temp_list[i] = xlist[i][indices[i]]; + } + + /* hack !!! check if all of our children are isomorphic -- if so, + * we can avoid 'permute' at this step; this makes the special + * case of a 6-wide or 8-wide nand gate go MUCH MUCH faster + * (8! = 40,320 ...); even 4-wide should be helped ... + */ + all_sons_isomorphic = 1; + for(i = 1; i < tree->nsons; i++) { + if (gl_compare_tree(temp_list[i-1], temp_list[i]) != 0) { + all_sons_isomorphic = 0; + break; + } + } + + if (all_sons_isomorphic) { + make_tree((char **) temp_list, + (int) tree->nsons, (char *) hash_table); + } else { + gl_permute((char **) temp_list, (int) tree->nsons, + make_tree, (char *) hash_table); + } + } + gl_free_gen_combination(comb); + + for(i = 0; i < tree->nsons; i++) { + for(j = 0; j < nlist[i]; j++) { + gl_free_tree(xlist[i][j]); + } + FREE(xlist[i]); + } + + n = gl_hash_end(hash_table, list); + } + + return n; +} + +int +gl_nand_gate_forms(tree, list, use_nor_gate) +tree_node_t *tree; +tree_node_t ***list; +int use_nor_gate; +{ + int i, n, invert_output; + tree_node_t *node; + + /* special case inverter and buffer */ + if (tree->nsons == 0) { + if (tree->phase == 1) { + node = gl_alloc_node(1); + node->sons[0] = gl_alloc_node(1); + node->sons[0]->sons[0] = gl_alloc_leaf(tree->name); + } else { + node = gl_alloc_node(1); + node->sons[0] = gl_alloc_leaf(tree->name); + } + *list = ALLOC(tree_node_t *, 1); + (*list)[0] = node; + n = 1; + } else { + invert_output = tree->phase == 0; + n = gl_nand_gate_forms_recur(tree, list, use_nor_gate); + + /* Check for extra inverter at root node */ + for(i = 0; i < n; i++) { + if (((tree->type == OR_NODE) != use_nor_gate) == invert_output) { + node = gl_alloc_node(1); + node->sons[0] = (*list)[i]; + (*list)[i] = node; + } + } + } + + /* set all internal types/phases */ + for(i = 0; i < n; i++) { + set_node_type((*list)[i], use_nor_gate ? NOR_NODE : NAND_NODE); + } + + return n; +} diff --git a/sis/genlib/permute.c b/sis/genlib/permute.c new file mode 100644 index 0000000..53d892a --- /dev/null +++ b/sis/genlib/permute.c @@ -0,0 +1,95 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/permute.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)permute.c 1.1 */ +/* last modified on 5/29/91 at 12:35:30 */ +#include "genlib_int.h" + +static void gl_permute_recur(); + + +gl_permute(array, n, fct, state) +char **array; +int n; +void (*fct)(); +char *state; +{ + gl_permute_recur(array, n, n, fct, state); +} + + +static void +gl_permute_recur(array, m, n, fct, state) +char **array; +int m; +int n; +void (*fct)(); +char *state; +{ + int i; + char *t; + + if (m <= 1) { + (*fct)(array-n+1, n, state); + } else { + for(i = 0; i < m; i++) { + /* Swap first element with ith element */ + t = array[i]; + array[i] = array[0]; + array[0] = t; + + /* recur for last m-1 elements */ + gl_permute_recur(array+1, m-1, n, fct, state); + + /* swap it back */ + t = array[i]; + array[i] = array[0]; + array[0] = t; + } + } +} + + +#ifdef TEST +#include + +int gl_print_it(); + + +main(argc, argv) +char **argv; +{ + int i, n, array[40]; + + if (argc == 2) { + n = atoi(argv[1]); + } else { + printf("usage: permute n\n"); + exit(2); + } + + for(i = 0; i < n; i++) { + array[i] = i+1; + } + + gl_permute((char **) array, n, gl_print_it, (char *) 0); +} + + +gl_print_it(array, n) +char **array; +int n; +{ + int i; + for(i = 0; i < n; i++) { + printf(" %d", array[i]); + } + printf("\n"); +} +#endif diff --git a/sis/genlib/readlib.c b/sis/genlib/readlib.c new file mode 100644 index 0000000..9addf9a --- /dev/null +++ b/sis/genlib/readlib.c @@ -0,0 +1,1494 @@ +/* A Bison parser, made from readlib.y + by GNU bison 1.35. */ + +#define YYBISON 1 /* Identify Bison output. */ + +# define OPR_OR 257 +# define OPR_AND 258 +# define CONST1 259 +# define CONST0 260 +# define IDENTIFIER 261 +# define LPAREN 262 +# define REAL 263 +# define OPR_NOT 264 +# define OPR_NOT_POST 265 +# define GATE 266 +# define PIN 267 +# define SEMI 268 +# define ASSIGN 269 +# define RPAREN 270 +# define LATCH 271 +# define CONTROL 272 +# define CONSTRAINT 273 +# define SEQ 274 + +#line 10 "readlib.y" + +/* file @(#)readlib.y 1.2 */ +/* last modified on 6/13/91 at 17:46:40 */ +#include +#include "genlib_int.h" +#include "config.h" + +#undef GENLIB_yywrap +static int input(); +static int unput(); +static int GENLIB_yywrap(); + +FILE *gl_out_file; +#if YYTEXT_POINTER +extern char *GENLIB_yytext; +#else +extern char GENLIB_yytext[]; +#endif + +static int global_use_nor; +static function_t *global_fct; + +extern int library_setup_string(char *); +extern int library_setup_file(FILE *, char *); + + +#line 37 "readlib.y" +#ifndef YYSTYPE +typedef union { + tree_node_t *nodeval; + char *strval; + double realval; + pin_info_t *pinval; + function_t *functionval; + latch_info_t *latchval; + constraint_info_t *constrval; +} GENLIB_yystype; +# define YYSTYPE GENLIB_yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + + +#define YYFINAL 71 +#define YYFLAG -32768 +#define YYNTBASE 21 + +/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ +#define YYTRANSLATE(x) ((unsigned)(x) <= 274 ? GENLIB_yytranslate[x] : 37) + +/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ +static const char GENLIB_yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20 +}; + +#if YYDEBUG +static const short GENLIB_yyprhs[] = +{ + 0, 0, 2, 4, 5, 8, 14, 23, 24, 27, + 37, 39, 41, 43, 48, 52, 56, 59, 63, 66, + 69, 71, 73, 75, 77, 79, 81, 82, 91, 92, + 95, 100, 105 +}; +static const short GENLIB_yyrhs[] = +{ + 22, 0, 28, 0, 0, 22, 23, 0, 12, 30, + 31, 28, 24, 0, 17, 30, 31, 28, 24, 35, + 32, 33, 0, 0, 24, 25, 0, 13, 27, 26, + 31, 31, 31, 31, 31, 31, 0, 30, 0, 30, + 0, 4, 0, 30, 15, 29, 14, 0, 29, 3, + 29, 0, 29, 4, 29, 0, 29, 29, 0, 8, + 29, 16, 0, 10, 29, 0, 29, 11, 0, 30, + 0, 6, 0, 5, 0, 7, 0, 9, 0, 9, + 0, 0, 18, 30, 31, 31, 31, 31, 31, 31, + 0, 0, 33, 34, 0, 19, 27, 31, 31, 0, + 20, 30, 30, 36, 0, 7, 0 +}; + +#endif + +#if YYDEBUG +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const short GENLIB_yyrline[] = +{ + 0, 65, 66, 70, 71, 74, 79, 86, 88, 92, + 104, 117, 119, 123, 132, 140, 148, 156, 160, 165, + 170, 177, 183, 191, 193, 198, 202, 204, 218, 220, + 227, 237, 246 +}; +#endif + + +#if (YYDEBUG) || defined YYERROR_VERBOSE + +/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ +static const char *const GENLIB_yytname[] = +{ + "$", "error", "$undefined.", "OPR_OR", "OPR_AND", "CONST1", "CONST0", + "IDENTIFIER", "LPAREN", "REAL", "OPR_NOT", "OPR_NOT_POST", "GATE", + "PIN", "SEMI", "ASSIGN", "RPAREN", "LATCH", "CONTROL", "CONSTRAINT", + "SEQ", "hack", "gates", "gate_info", "pins", "pin_info", "pin_phase", + "pin_name", "function", "expr", "name", "real", "clock", "constraints", + "constraint", "latch", "type", 0 +}; +#endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const short GENLIB_yyr1[] = +{ + 0, 21, 21, 22, 22, 23, 23, 24, 24, 25, + 26, 27, 27, 28, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 30, 30, 31, 32, 32, 33, 33, + 34, 35, 36 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const short GENLIB_yyr2[] = +{ + 0, 1, 1, 0, 2, 5, 8, 0, 2, 9, + 1, 1, 1, 4, 3, 3, 2, 3, 2, 2, + 1, 1, 1, 1, 1, 1, 0, 8, 0, 2, + 4, 4, 1 +}; + +/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ +static const short GENLIB_yydefact[] = +{ + 3, 23, 24, 1, 2, 0, 0, 0, 4, 0, + 0, 0, 22, 21, 0, 0, 0, 20, 25, 0, + 0, 0, 18, 0, 0, 19, 13, 16, 7, 7, + 17, 14, 15, 5, 0, 0, 8, 0, 26, 12, + 0, 11, 0, 0, 28, 0, 10, 0, 0, 6, + 0, 32, 31, 0, 0, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 30, 0, 0, 9, 27, 0, + 0, 0 +}; + +static const short GENLIB_yydefgoto[] = +{ + 69, 3, 8, 33, 36, 45, 40, 4, 27, 17, + 19, 44, 49, 55, 38, 52 +}; + +static const short GENLIB_yypact[] = +{ + -5,-32768,-32768, -3,-32768, 8, -5, -5,-32768, 94, + -4, -4,-32768,-32768, 94, 94, 76,-32768,-32768, -5, + -5, 62,-32768, 94, 94,-32768,-32768, 7,-32768,-32768, + -32768, 87, 7, -1, -10, 4,-32768, -5, 6,-32768, + -5,-32768, -5, -5,-32768, -4,-32768, 15, -4, 10, + -4,-32768,-32768, -4, 4,-32768, -4, -4, -4, -4, + -4, -4, -4, -4,-32768, -4, -4,-32768,-32768, 25, + 26,-32768 +}; + +static const short GENLIB_yypgoto[] = +{ + -32768,-32768,-32768, 1,-32768,-32768, -23, 0, -8, 21, + -11,-32768,-32768,-32768,-32768,-32768 +}; + + +#define YYLAST 104 + + +static const short GENLIB_yytable[] = +{ + 20, 16, 1, 35, 2, 18, 21, 22, 39, 6, + 37, 1, 35, 2, 7, 31, 32, 15, 25, 28, + 29, 5, 51, 9, 43, 70, 71, 10, 11, 54, + 34, 58, 0, 0, 50, 0, 0, 53, 0, 56, + 5, 5, 57, 0, 0, 59, 60, 61, 62, 63, + 64, 65, 66, 0, 67, 68, 41, 0, 42, 0, + 0, 46, 0, 47, 48, 23, 24, 12, 13, 1, + 14, 2, 15, 25, 0, 41, 0, 0, 30, 23, + 24, 12, 13, 1, 14, 2, 15, 25, 0, 0, + 26, 24, 12, 13, 1, 14, 2, 15, 25, 12, + 13, 1, 14, 2, 15 +}; + +static const short GENLIB_yycheck[] = +{ + 11, 9, 7, 13, 9, 9, 14, 15, 4, 12, + 20, 7, 13, 9, 17, 23, 24, 10, 11, 19, + 20, 0, 7, 15, 18, 0, 0, 6, 7, 19, + 29, 54, -1, -1, 45, -1, -1, 48, -1, 50, + 19, 20, 53, -1, -1, 56, 57, 58, 59, 60, + 61, 62, 63, -1, 65, 66, 35, -1, 37, -1, + -1, 40, -1, 42, 43, 3, 4, 5, 6, 7, + 8, 9, 10, 11, -1, 54, -1, -1, 16, 3, + 4, 5, 6, 7, 8, 9, 10, 11, -1, -1, + 14, 4, 5, 6, 7, 8, 9, 10, 11, 5, + 6, 7, 8, 9, 10 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/share/bison/bison.simple" + +/* Skeleton output parser for bison, + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software + Foundation, Inc. + + 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, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser when + the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* All symbols defined below should begin with GENLIB_yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +#if ! defined (GENLIB_yyoverflow) || defined (YYERROR_VERBOSE) + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (GENLIB_yyoverflow) || defined (YYERROR_VERBOSE) */ + + +#if (! defined (GENLIB_yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union GENLIB_yyalloc +{ + short GENLIB_yyss; + YYSTYPE GENLIB_yyvs; +# if YYLSP_NEEDED + YYLTYPE GENLIB_yyls; +# endif +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAX (sizeof (union GENLIB_yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# if YYLSP_NEEDED +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAX) +# else +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAX) +# endif + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T GENLIB_yyi; \ + for (GENLIB_yyi = 0; GENLIB_yyi < (Count); GENLIB_yyi++) \ + (To)[GENLIB_yyi] = (From)[GENLIB_yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T GENLIB_yynewbytes; \ + YYCOPY (&GENLIB_yyptr->Stack, Stack, GENLIB_yysize); \ + Stack = &GENLIB_yyptr->Stack; \ + GENLIB_yynewbytes = GENLIB_yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ + GENLIB_yyptr += GENLIB_yynewbytes / sizeof (*GENLIB_yyptr); \ + } \ + while (0) + +#endif + + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define GENLIB_yyerrok (GENLIB_yyerrstatus = 0) +#define GENLIB_yyclearin (GENLIB_yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto GENLIB_yyacceptlab +#define YYABORT goto GENLIB_yyabortlab +#define YYERROR goto GENLIB_yyerrlab1 +/* Like YYERROR except do call GENLIB_yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto GENLIB_yyerrlab +#define YYRECOVERING() (!!GENLIB_yyerrstatus) +#define YYBACKUP(Token, Value) \ +do \ + if (GENLIB_yychar == YYEMPTY && GENLIB_yylen == 1) \ + { \ + GENLIB_yychar = (Token); \ + GENLIB_yylval = (Value); \ + GENLIB_yychar1 = YYTRANSLATE (GENLIB_yychar); \ + YYPOPSTACK; \ + goto GENLIB_yybackup; \ + } \ + else \ + { \ + GENLIB_yyerror ("syntax error: cannot back up"); \ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). + + When YYLLOC_DEFAULT is run, CURRENT is set the location of the + first token. By default, to implement support for ranges, extend + its range to the last symbol. */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + + +/* YYLEX -- calling `GENLIB_yylex' with the right arguments. */ + +#if YYPURE +# if YYLSP_NEEDED +# ifdef YYLEX_PARAM +# define YYLEX GENLIB_yylex (&GENLIB_yylval, &GENLIB_yylloc, YYLEX_PARAM) +# else +# define YYLEX GENLIB_yylex (&GENLIB_yylval, &GENLIB_yylloc) +# endif +# else /* !YYLSP_NEEDED */ +# ifdef YYLEX_PARAM +# define YYLEX GENLIB_yylex (&GENLIB_yylval, YYLEX_PARAM) +# else +# define YYLEX GENLIB_yylex (&GENLIB_yylval) +# endif +# endif /* !YYLSP_NEEDED */ +#else /* !YYPURE */ +# define YYLEX GENLIB_yylex () +#endif /* !YYPURE */ + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (GENLIB_yydebug) \ + YYFPRINTF Args; \ +} while (0) +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int GENLIB_yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +#endif /* !YYDEBUG */ + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +#ifdef YYERROR_VERBOSE + +# ifndef GENLIB_yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define GENLIB_yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +GENLIB_yystrlen (const char *GENLIB_yystr) +# else +GENLIB_yystrlen (GENLIB_yystr) + const char *GENLIB_yystr; +# endif +{ + register const char *GENLIB_yys = GENLIB_yystr; + + while (*GENLIB_yys++ != '\0') + continue; + + return GENLIB_yys - GENLIB_yystr - 1; +} +# endif +# endif + +# ifndef GENLIB_yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define GENLIB_yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +GENLIB_yystpcpy (char *GENLIB_yydest, const char *GENLIB_yysrc) +# else +GENLIB_yystpcpy (GENLIB_yydest, GENLIB_yysrc) + char *GENLIB_yydest; + const char *GENLIB_yysrc; +# endif +{ + register char *GENLIB_yyd = GENLIB_yydest; + register const char *GENLIB_yys = GENLIB_yysrc; + + while ((*GENLIB_yyd++ = *GENLIB_yys++) != '\0') + continue; + + return GENLIB_yyd - 1; +} +# endif +# endif +#endif + +#line 315 "/usr/share/bison/bison.simple" + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into GENLIB_yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +# define YYPARSE_PARAM_DECL +# else +# define YYPARSE_PARAM_ARG YYPARSE_PARAM +# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +# endif +#else /* !YYPARSE_PARAM */ +# define YYPARSE_PARAM_ARG +# define YYPARSE_PARAM_DECL +#endif /* !YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +# ifdef YYPARSE_PARAM +int GENLIB_yyparse (void *); +# else +int GENLIB_yyparse (void); +# endif +#endif + +/* YY_DECL_VARIABLES -- depending whether we use a pure parser, + variables are global, or local to YYPARSE. */ + +#define YY_DECL_NON_LSP_VARIABLES \ +/* The lookahead symbol. */ \ +int GENLIB_yychar; \ + \ +/* The semantic value of the lookahead symbol. */ \ +YYSTYPE GENLIB_yylval; \ + \ +/* Number of parse errors so far. */ \ +int GENLIB_yynerrs; + +#if YYLSP_NEEDED +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES \ + \ +/* Location data for the lookahead symbol. */ \ +YYLTYPE GENLIB_yylloc; +#else +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES +#endif + + +/* If nonreentrant, generate the variables here. */ + +#if !YYPURE +YY_DECL_VARIABLES +#endif /* !YYPURE */ + +int +GENLIB_yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + /* If reentrant, generate the variables here. */ +#if YYPURE + YY_DECL_VARIABLES +#endif /* !YYPURE */ + + register int GENLIB_yystate; + register int GENLIB_yyn; + int GENLIB_yyresult; + /* Number of tokens to shift before error messages enabled. */ + int GENLIB_yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int GENLIB_yychar1 = 0; + + /* Three stacks and their tools: + `GENLIB_yyss': related to states, + `GENLIB_yyvs': related to semantic values, + `GENLIB_yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow GENLIB_yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short GENLIB_yyssa[YYINITDEPTH]; + short *GENLIB_yyss = GENLIB_yyssa; + register short *GENLIB_yyssp; + + /* The semantic value stack. */ + YYSTYPE GENLIB_yyvsa[YYINITDEPTH]; + YYSTYPE *GENLIB_yyvs = GENLIB_yyvsa; + register YYSTYPE *GENLIB_yyvsp; + +#if YYLSP_NEEDED + /* The location stack. */ + YYLTYPE GENLIB_yylsa[YYINITDEPTH]; + YYLTYPE *GENLIB_yyls = GENLIB_yylsa; + YYLTYPE *GENLIB_yylsp; +#endif + +#if YYLSP_NEEDED +# define YYPOPSTACK (GENLIB_yyvsp--, GENLIB_yyssp--, GENLIB_yylsp--) +#else +# define YYPOPSTACK (GENLIB_yyvsp--, GENLIB_yyssp--) +#endif + + YYSIZE_T GENLIB_yystacksize = YYINITDEPTH; + + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE GENLIB_yyval; +#if YYLSP_NEEDED + YYLTYPE GENLIB_yyloc; +#endif + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int GENLIB_yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + GENLIB_yystate = 0; + GENLIB_yyerrstatus = 0; + GENLIB_yynerrs = 0; + GENLIB_yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + GENLIB_yyssp = GENLIB_yyss; + GENLIB_yyvsp = GENLIB_yyvs; +#if YYLSP_NEEDED + GENLIB_yylsp = GENLIB_yyls; +#endif + goto GENLIB_yysetstate; + +/*------------------------------------------------------------. +| GENLIB_yynewstate -- Push a new state, which is found in GENLIB_yystate. | +`------------------------------------------------------------*/ + GENLIB_yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + GENLIB_yyssp++; + + GENLIB_yysetstate: + *GENLIB_yyssp = GENLIB_yystate; + + if (GENLIB_yyssp >= GENLIB_yyss + GENLIB_yystacksize - 1) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T GENLIB_yysize = GENLIB_yyssp - GENLIB_yyss + 1; + +#ifdef GENLIB_yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *GENLIB_yyvs1 = GENLIB_yyvs; + short *GENLIB_yyss1 = GENLIB_yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. */ +# if YYLSP_NEEDED + YYLTYPE *GENLIB_yyls1 = GENLIB_yyls; + /* This used to be a conditional around just the two extra args, + but that might be undefined if GENLIB_yyoverflow is a macro. */ + GENLIB_yyoverflow ("parser stack overflow", + &GENLIB_yyss1, GENLIB_yysize * sizeof (*GENLIB_yyssp), + &GENLIB_yyvs1, GENLIB_yysize * sizeof (*GENLIB_yyvsp), + &GENLIB_yyls1, GENLIB_yysize * sizeof (*GENLIB_yylsp), + &GENLIB_yystacksize); + GENLIB_yyls = GENLIB_yyls1; +# else + GENLIB_yyoverflow ("parser stack overflow", + &GENLIB_yyss1, GENLIB_yysize * sizeof (*GENLIB_yyssp), + &GENLIB_yyvs1, GENLIB_yysize * sizeof (*GENLIB_yyvsp), + &GENLIB_yystacksize); +# endif + GENLIB_yyss = GENLIB_yyss1; + GENLIB_yyvs = GENLIB_yyvs1; + } +#else /* no GENLIB_yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto GENLIB_yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (GENLIB_yystacksize >= YYMAXDEPTH) + goto GENLIB_yyoverflowlab; + GENLIB_yystacksize *= 2; + if (GENLIB_yystacksize > YYMAXDEPTH) + GENLIB_yystacksize = YYMAXDEPTH; + + { + short *GENLIB_yyss1 = GENLIB_yyss; + union GENLIB_yyalloc *GENLIB_yyptr = + (union GENLIB_yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (GENLIB_yystacksize)); + if (! GENLIB_yyptr) + goto GENLIB_yyoverflowlab; + YYSTACK_RELOCATE (GENLIB_yyss); + YYSTACK_RELOCATE (GENLIB_yyvs); +# if YYLSP_NEEDED + YYSTACK_RELOCATE (GENLIB_yyls); +# endif +# undef YYSTACK_RELOCATE + if (GENLIB_yyss1 != GENLIB_yyssa) + YYSTACK_FREE (GENLIB_yyss1); + } +# endif +#endif /* no GENLIB_yyoverflow */ + + GENLIB_yyssp = GENLIB_yyss + GENLIB_yysize - 1; + GENLIB_yyvsp = GENLIB_yyvs + GENLIB_yysize - 1; +#if YYLSP_NEEDED + GENLIB_yylsp = GENLIB_yyls + GENLIB_yysize - 1; +#endif + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) GENLIB_yystacksize)); + + if (GENLIB_yyssp >= GENLIB_yyss + GENLIB_yystacksize - 1) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", GENLIB_yystate)); + + goto GENLIB_yybackup; + + +/*-----------. +| GENLIB_yybackup. | +`-----------*/ +GENLIB_yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* GENLIB_yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + GENLIB_yyn = GENLIB_yypact[GENLIB_yystate]; + if (GENLIB_yyn == YYFLAG) + goto GENLIB_yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* GENLIB_yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (GENLIB_yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + GENLIB_yychar = YYLEX; + } + + /* Convert token to internal form (in GENLIB_yychar1) for indexing tables with */ + + if (GENLIB_yychar <= 0) /* This means end of input. */ + { + GENLIB_yychar1 = 0; + GENLIB_yychar = YYEOF; /* Don't call YYLEX any more */ + + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + GENLIB_yychar1 = YYTRANSLATE (GENLIB_yychar); + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables + which are defined only if `YYDEBUG' is set. */ + if (GENLIB_yydebug) + { + YYFPRINTF (stderr, "Next token is %d (%s", + GENLIB_yychar, GENLIB_yytname[GENLIB_yychar1]); + /* Give the individual parser a way to print the precise + meaning of a token, for further debugging info. */ +# ifdef YYPRINT + YYPRINT (stderr, GENLIB_yychar, GENLIB_yylval); +# endif + YYFPRINTF (stderr, ")\n"); + } +#endif + } + + GENLIB_yyn += GENLIB_yychar1; + if (GENLIB_yyn < 0 || GENLIB_yyn > YYLAST || GENLIB_yycheck[GENLIB_yyn] != GENLIB_yychar1) + goto GENLIB_yydefault; + + GENLIB_yyn = GENLIB_yytable[GENLIB_yyn]; + + /* GENLIB_yyn is what to do for this token type in this state. + Negative => reduce, -GENLIB_yyn is rule number. + Positive => shift, GENLIB_yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (GENLIB_yyn < 0) + { + if (GENLIB_yyn == YYFLAG) + goto GENLIB_yyerrlab; + GENLIB_yyn = -GENLIB_yyn; + goto GENLIB_yyreduce; + } + else if (GENLIB_yyn == 0) + goto GENLIB_yyerrlab; + + if (GENLIB_yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %d (%s), ", + GENLIB_yychar, GENLIB_yytname[GENLIB_yychar1])); + + /* Discard the token being shifted unless it is eof. */ + if (GENLIB_yychar != YYEOF) + GENLIB_yychar = YYEMPTY; + + *++GENLIB_yyvsp = GENLIB_yylval; +#if YYLSP_NEEDED + *++GENLIB_yylsp = GENLIB_yylloc; +#endif + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (GENLIB_yyerrstatus) + GENLIB_yyerrstatus--; + + GENLIB_yystate = GENLIB_yyn; + goto GENLIB_yynewstate; + + +/*-----------------------------------------------------------. +| GENLIB_yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +GENLIB_yydefault: + GENLIB_yyn = GENLIB_yydefact[GENLIB_yystate]; + if (GENLIB_yyn == 0) + goto GENLIB_yyerrlab; + goto GENLIB_yyreduce; + + +/*-----------------------------. +| GENLIB_yyreduce -- Do a reduction. | +`-----------------------------*/ +GENLIB_yyreduce: + /* GENLIB_yyn is the number of a rule to reduce with. */ + GENLIB_yylen = GENLIB_yyr2[GENLIB_yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to the semantic value of + the lookahead token. This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + GENLIB_yyval = GENLIB_yyvsp[1-GENLIB_yylen]; + +#if YYLSP_NEEDED + /* Similarly for the default location. Let the user run additional + commands if for instance locations are ranges. */ + GENLIB_yyloc = GENLIB_yylsp[1-GENLIB_yylen]; + YYLLOC_DEFAULT (GENLIB_yyloc, (GENLIB_yylsp - GENLIB_yylen), GENLIB_yylen); +#endif + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables which + are defined only if `YYDEBUG' is set. */ + if (GENLIB_yydebug) + { + int GENLIB_yyi; + + YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", + GENLIB_yyn, GENLIB_yyrline[GENLIB_yyn]); + + /* Print the symbols being reduced, and their result. */ + for (GENLIB_yyi = GENLIB_yyprhs[GENLIB_yyn]; GENLIB_yyrhs[GENLIB_yyi] > 0; GENLIB_yyi++) + YYFPRINTF (stderr, "%s ", GENLIB_yytname[GENLIB_yyrhs[GENLIB_yyi]]); + YYFPRINTF (stderr, " -> %s\n", GENLIB_yytname[GENLIB_yyr1[GENLIB_yyn]]); + } +#endif + + switch (GENLIB_yyn) { + +case 2: +#line 67 "readlib.y" +{global_fct = GENLIB_yyvsp[0].functionval; } + break; +case 5: +#line 75 "readlib.y" +{ + if (! gl_convert_gate_to_blif(GENLIB_yyvsp[-3].strval,GENLIB_yyvsp[-2].realval,GENLIB_yyvsp[-1].functionval,GENLIB_yyvsp[0].pinval,global_use_nor)) + GENLIB_yyerror(NIL(char)); + } + break; +case 6: +#line 80 "readlib.y" +{ + if (! gl_convert_latch_to_blif(GENLIB_yyvsp[-6].strval,GENLIB_yyvsp[-5].realval,GENLIB_yyvsp[-4].functionval,GENLIB_yyvsp[-3].pinval,global_use_nor,GENLIB_yyvsp[-2].latchval,GENLIB_yyvsp[-1].pinval,GENLIB_yyvsp[0].constrval)) + GENLIB_yyerror(NIL(char)); + } + break; +case 7: +#line 87 "readlib.y" +{ GENLIB_yyval.pinval = 0; } + break; +case 8: +#line 89 "readlib.y" +{ GENLIB_yyvsp[0].pinval->next = GENLIB_yyvsp[-1].pinval; GENLIB_yyval.pinval = GENLIB_yyvsp[0].pinval;} + break; +case 9: +#line 93 "readlib.y" +{ + GENLIB_yyval.pinval = ALLOC(pin_info_t, 1); + GENLIB_yyval.pinval->name = GENLIB_yyvsp[-7].strval; + GENLIB_yyval.pinval->phase = GENLIB_yyvsp[-6].strval; + GENLIB_yyval.pinval->value[0] = GENLIB_yyvsp[-5].realval; GENLIB_yyval.pinval->value[1] = GENLIB_yyvsp[-4].realval; + GENLIB_yyval.pinval->value[2] = GENLIB_yyvsp[-3].realval; GENLIB_yyval.pinval->value[3] = GENLIB_yyvsp[-2].realval; + GENLIB_yyval.pinval->value[4] = GENLIB_yyvsp[-1].realval; GENLIB_yyval.pinval->value[5] = GENLIB_yyvsp[0].realval; + GENLIB_yyval.pinval->next = 0; + } + break; +case 10: +#line 105 "readlib.y" +{ + if (strcmp(GENLIB_yyvsp[0].strval, "INV") != 0) { + if (strcmp(GENLIB_yyvsp[0].strval, "NONINV") != 0) { + if (strcmp(GENLIB_yyvsp[0].strval, "UNKNOWN") != 0) { + GENLIB_yyerror("bad pin phase"); + } + } + } + GENLIB_yyval.strval = GENLIB_yyvsp[0].strval; + } + break; +case 11: +#line 118 "readlib.y" +{ GENLIB_yyval.strval = GENLIB_yyvsp[0].strval; } + break; +case 12: +#line 120 "readlib.y" +{ GENLIB_yyval.strval = util_strsav(GENLIB_yytext); } + break; +case 13: +#line 124 "readlib.y" +{ + GENLIB_yyval.functionval = ALLOC(function_t, 1); + GENLIB_yyval.functionval->name = GENLIB_yyvsp[-3].strval; + GENLIB_yyval.functionval->tree = GENLIB_yyvsp[-1].nodeval; + GENLIB_yyval.functionval->next = 0; + } + break; +case 14: +#line 133 "readlib.y" +{ + GENLIB_yyval.nodeval = gl_alloc_node(2); + GENLIB_yyval.nodeval->phase = 1; + GENLIB_yyval.nodeval->sons[0] = GENLIB_yyvsp[-2].nodeval; + GENLIB_yyval.nodeval->sons[1] = GENLIB_yyvsp[0].nodeval; + GENLIB_yyval.nodeval->type = OR_NODE; + } + break; +case 15: +#line 141 "readlib.y" +{ + GENLIB_yyval.nodeval = gl_alloc_node(2); + GENLIB_yyval.nodeval->phase = 1; + GENLIB_yyval.nodeval->sons[0] = GENLIB_yyvsp[-2].nodeval; + GENLIB_yyval.nodeval->sons[1] = GENLIB_yyvsp[0].nodeval; + GENLIB_yyval.nodeval->type = AND_NODE; + } + break; +case 16: +#line 149 "readlib.y" +{ + GENLIB_yyval.nodeval = gl_alloc_node(2); + GENLIB_yyval.nodeval->phase = 1; + GENLIB_yyval.nodeval->sons[0] = GENLIB_yyvsp[-1].nodeval; + GENLIB_yyval.nodeval->sons[1] = GENLIB_yyvsp[0].nodeval; + GENLIB_yyval.nodeval->type = AND_NODE; + } + break; +case 17: +#line 157 "readlib.y" +{ + GENLIB_yyval.nodeval = GENLIB_yyvsp[-1].nodeval; + } + break; +case 18: +#line 161 "readlib.y" +{ + GENLIB_yyval.nodeval = GENLIB_yyvsp[0].nodeval; + GENLIB_yyval.nodeval->phase = 0; + } + break; +case 19: +#line 166 "readlib.y" +{ + GENLIB_yyval.nodeval = GENLIB_yyvsp[-1].nodeval; + GENLIB_yyval.nodeval->phase = 0; + } + break; +case 20: +#line 171 "readlib.y" +{ + GENLIB_yyval.nodeval = gl_alloc_leaf(GENLIB_yyvsp[0].strval); + FREE(GENLIB_yyvsp[0].strval); + GENLIB_yyval.nodeval->type = LEAF_NODE; /* hack */ + GENLIB_yyval.nodeval->phase = 1; + } + break; +case 21: +#line 178 "readlib.y" +{ + GENLIB_yyval.nodeval = gl_alloc_leaf("0"); + GENLIB_yyval.nodeval->phase = 1; + GENLIB_yyval.nodeval->type = ZERO_NODE; + } + break; +case 22: +#line 184 "readlib.y" +{ + GENLIB_yyval.nodeval = gl_alloc_leaf("1"); + GENLIB_yyval.nodeval->phase = 1; + GENLIB_yyval.nodeval->type = ONE_NODE; + } + break; +case 23: +#line 192 "readlib.y" +{ GENLIB_yyval.strval = util_strsav(GENLIB_yytext); } + break; +case 24: +#line 195 "readlib.y" +{ GENLIB_yyval.strval = util_strsav(GENLIB_yytext); } + break; +case 25: +#line 199 "readlib.y" +{ GENLIB_yyval.realval = atof(GENLIB_yytext); } + break; +case 26: +#line 203 "readlib.y" +{ GENLIB_yyval.pinval = 0;} + break; +case 27: +#line 205 "readlib.y" +{ GENLIB_yyval.pinval = ALLOC(pin_info_t, 1); + GENLIB_yyval.pinval->name = GENLIB_yyvsp[-6].strval; + GENLIB_yyval.pinval->phase = util_strsav("UNKNOWN"); + GENLIB_yyval.pinval->value[0] = GENLIB_yyvsp[-5].realval; + GENLIB_yyval.pinval->value[1] = GENLIB_yyvsp[-4].realval; + GENLIB_yyval.pinval->value[2] = GENLIB_yyvsp[-3].realval; + GENLIB_yyval.pinval->value[3] = GENLIB_yyvsp[-2].realval; + GENLIB_yyval.pinval->value[4] = GENLIB_yyvsp[-1].realval; + GENLIB_yyval.pinval->value[5] = GENLIB_yyvsp[0].realval; + GENLIB_yyval.pinval->next = 0; + } + break; +case 28: +#line 219 "readlib.y" +{ GENLIB_yyval.constrval = 0; } + break; +case 29: +#line 221 "readlib.y" +{ + GENLIB_yyvsp[0].constrval->next = GENLIB_yyvsp[-1].constrval; + GENLIB_yyval.constrval = GENLIB_yyvsp[0].constrval; + } + break; +case 30: +#line 228 "readlib.y" +{ + GENLIB_yyval.constrval = ALLOC(constraint_info_t, 1); + GENLIB_yyval.constrval->name = GENLIB_yyvsp[-2].strval; + GENLIB_yyval.constrval->setup = GENLIB_yyvsp[-1].realval; + GENLIB_yyval.constrval->hold = GENLIB_yyvsp[0].realval; + GENLIB_yyval.constrval->next = 0; + } + break; +case 31: +#line 238 "readlib.y" +{ + GENLIB_yyval.latchval = ALLOC(latch_info_t, 1); + GENLIB_yyval.latchval->in = GENLIB_yyvsp[-2].strval; + GENLIB_yyval.latchval->out = GENLIB_yyvsp[-1].strval; + GENLIB_yyval.latchval->type = GENLIB_yyvsp[0].strval; + } + break; +case 32: +#line 247 "readlib.y" +{ + if (strcmp(GENLIB_yytext, "RISING_EDGE") == 0) { + GENLIB_yyval.strval = util_strsav("re"); + } else if (strcmp(GENLIB_yytext, "FALLING_EDGE") == 0) { + GENLIB_yyval.strval = util_strsav("fe"); + } else if (strcmp(GENLIB_yytext, "ACTIVE_HIGH") == 0) { + GENLIB_yyval.strval = util_strsav("ah"); + } else if (strcmp(GENLIB_yytext, "ACTIVE_LOW") == 0) { + GENLIB_yyval.strval = util_strsav("al"); + } else if (strcmp(GENLIB_yytext, "ASYNCH") == 0) { + GENLIB_yyval.strval = util_strsav("as"); + } else { + GENLIB_yyerror("latch type can only be re/fe/ah/al/as"); + } + } + break; +} + +#line 705 "/usr/share/bison/bison.simple" + + + GENLIB_yyvsp -= GENLIB_yylen; + GENLIB_yyssp -= GENLIB_yylen; +#if YYLSP_NEEDED + GENLIB_yylsp -= GENLIB_yylen; +#endif + +#if YYDEBUG + if (GENLIB_yydebug) + { + short *GENLIB_yyssp1 = GENLIB_yyss - 1; + YYFPRINTF (stderr, "state stack now"); + while (GENLIB_yyssp1 != GENLIB_yyssp) + YYFPRINTF (stderr, " %d", *++GENLIB_yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + + *++GENLIB_yyvsp = GENLIB_yyval; +#if YYLSP_NEEDED + *++GENLIB_yylsp = GENLIB_yyloc; +#endif + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + GENLIB_yyn = GENLIB_yyr1[GENLIB_yyn]; + + GENLIB_yystate = GENLIB_yypgoto[GENLIB_yyn - YYNTBASE] + *GENLIB_yyssp; + if (GENLIB_yystate >= 0 && GENLIB_yystate <= YYLAST && GENLIB_yycheck[GENLIB_yystate] == *GENLIB_yyssp) + GENLIB_yystate = GENLIB_yytable[GENLIB_yystate]; + else + GENLIB_yystate = GENLIB_yydefgoto[GENLIB_yyn - YYNTBASE]; + + goto GENLIB_yynewstate; + + +/*------------------------------------. +| GENLIB_yyerrlab -- here on detecting error | +`------------------------------------*/ +GENLIB_yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!GENLIB_yyerrstatus) + { + ++GENLIB_yynerrs; + +#ifdef YYERROR_VERBOSE + GENLIB_yyn = GENLIB_yypact[GENLIB_yystate]; + + if (GENLIB_yyn > YYFLAG && GENLIB_yyn < YYLAST) + { + YYSIZE_T GENLIB_yysize = 0; + char *GENLIB_yymsg; + int GENLIB_yyx, GENLIB_yycount; + + GENLIB_yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (GENLIB_yyx = GENLIB_yyn < 0 ? -GENLIB_yyn : 0; + GENLIB_yyx < (int) (sizeof (GENLIB_yytname) / sizeof (char *)); GENLIB_yyx++) + if (GENLIB_yycheck[GENLIB_yyx + GENLIB_yyn] == GENLIB_yyx) + GENLIB_yysize += GENLIB_yystrlen (GENLIB_yytname[GENLIB_yyx]) + 15, GENLIB_yycount++; + GENLIB_yysize += GENLIB_yystrlen ("parse error, unexpected ") + 1; + GENLIB_yysize += GENLIB_yystrlen (GENLIB_yytname[YYTRANSLATE (GENLIB_yychar)]); + GENLIB_yymsg = (char *) YYSTACK_ALLOC (GENLIB_yysize); + if (GENLIB_yymsg != 0) + { + char *GENLIB_yyp = GENLIB_yystpcpy (GENLIB_yymsg, "parse error, unexpected "); + GENLIB_yyp = GENLIB_yystpcpy (GENLIB_yyp, GENLIB_yytname[YYTRANSLATE (GENLIB_yychar)]); + + if (GENLIB_yycount < 5) + { + GENLIB_yycount = 0; + for (GENLIB_yyx = GENLIB_yyn < 0 ? -GENLIB_yyn : 0; + GENLIB_yyx < (int) (sizeof (GENLIB_yytname) / sizeof (char *)); + GENLIB_yyx++) + if (GENLIB_yycheck[GENLIB_yyx + GENLIB_yyn] == GENLIB_yyx) + { + const char *GENLIB_yyq = ! GENLIB_yycount ? ", expecting " : " or "; + GENLIB_yyp = GENLIB_yystpcpy (GENLIB_yyp, GENLIB_yyq); + GENLIB_yyp = GENLIB_yystpcpy (GENLIB_yyp, GENLIB_yytname[GENLIB_yyx]); + GENLIB_yycount++; + } + } + GENLIB_yyerror (GENLIB_yymsg); + YYSTACK_FREE (GENLIB_yymsg); + } + else + GENLIB_yyerror ("parse error; also virtual memory exhausted"); + } + else +#endif /* defined (YYERROR_VERBOSE) */ + GENLIB_yyerror ("parse error"); + } + goto GENLIB_yyerrlab1; + + +/*--------------------------------------------------. +| GENLIB_yyerrlab1 -- error raised explicitly by an action | +`--------------------------------------------------*/ +GENLIB_yyerrlab1: + if (GENLIB_yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* return failure if at end of input */ + if (GENLIB_yychar == YYEOF) + YYABORT; + YYDPRINTF ((stderr, "Discarding token %d (%s).\n", + GENLIB_yychar, GENLIB_yytname[GENLIB_yychar1])); + GENLIB_yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + + GENLIB_yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto GENLIB_yyerrhandle; + + +/*-------------------------------------------------------------------. +| GENLIB_yyerrdefault -- current state does not do anything special for the | +| error token. | +`-------------------------------------------------------------------*/ +GENLIB_yyerrdefault: +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + + /* If its default is to accept any token, ok. Otherwise pop it. */ + GENLIB_yyn = GENLIB_yydefact[GENLIB_yystate]; + if (GENLIB_yyn) + goto GENLIB_yydefault; +#endif + + +/*---------------------------------------------------------------. +| GENLIB_yyerrpop -- pop the current state because it cannot handle the | +| error token | +`---------------------------------------------------------------*/ +GENLIB_yyerrpop: + if (GENLIB_yyssp == GENLIB_yyss) + YYABORT; + GENLIB_yyvsp--; + GENLIB_yystate = *--GENLIB_yyssp; +#if YYLSP_NEEDED + GENLIB_yylsp--; +#endif + +#if YYDEBUG + if (GENLIB_yydebug) + { + short *GENLIB_yyssp1 = GENLIB_yyss - 1; + YYFPRINTF (stderr, "Error: state stack now"); + while (GENLIB_yyssp1 != GENLIB_yyssp) + YYFPRINTF (stderr, " %d", *++GENLIB_yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + +/*--------------. +| GENLIB_yyerrhandle. | +`--------------*/ +GENLIB_yyerrhandle: + GENLIB_yyn = GENLIB_yypact[GENLIB_yystate]; + if (GENLIB_yyn == YYFLAG) + goto GENLIB_yyerrdefault; + + GENLIB_yyn += YYTERROR; + if (GENLIB_yyn < 0 || GENLIB_yyn > YYLAST || GENLIB_yycheck[GENLIB_yyn] != YYTERROR) + goto GENLIB_yyerrdefault; + + GENLIB_yyn = GENLIB_yytable[GENLIB_yyn]; + if (GENLIB_yyn < 0) + { + if (GENLIB_yyn == YYFLAG) + goto GENLIB_yyerrpop; + GENLIB_yyn = -GENLIB_yyn; + goto GENLIB_yyreduce; + } + else if (GENLIB_yyn == 0) + goto GENLIB_yyerrpop; + + if (GENLIB_yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++GENLIB_yyvsp = GENLIB_yylval; +#if YYLSP_NEEDED + *++GENLIB_yylsp = GENLIB_yylloc; +#endif + + GENLIB_yystate = GENLIB_yyn; + goto GENLIB_yynewstate; + + +/*-------------------------------------. +| GENLIB_yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +GENLIB_yyacceptlab: + GENLIB_yyresult = 0; + goto GENLIB_yyreturn; + +/*-----------------------------------. +| GENLIB_yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +GENLIB_yyabortlab: + GENLIB_yyresult = 1; + goto GENLIB_yyreturn; + +/*---------------------------------------------. +| GENLIB_yyoverflowab -- parser overflow comes here. | +`---------------------------------------------*/ +GENLIB_yyoverflowlab: + GENLIB_yyerror ("parser stack overflow"); + GENLIB_yyresult = 2; + /* Fall through. */ + +GENLIB_yyreturn: +#ifndef GENLIB_yyoverflow + if (GENLIB_yyss != GENLIB_yyssa) + YYSTACK_FREE (GENLIB_yyss); +#endif + return GENLIB_yyresult; +} +#line 264 "readlib.y" + +static jmp_buf jmpbuf; + +int +GENLIB_yyerror(errmsg) +char *errmsg; +{ + if (errmsg != 0) read_error(errmsg); + longjmp(jmpbuf, 1); +} + +int +gl_convert_genlib_to_blif(filename, use_nor) +char *filename; +int use_nor; +{ + FILE *fp; + + error_init(); + if ((fp = fopen(filename, "r")) == NULL) { + perror(filename); + return 0; + } + library_setup_file(fp, filename); + gl_out_file = stdout; + + global_fct = 0; /* not used here, just to check for error */ + global_use_nor = use_nor; + + if (setjmp(jmpbuf)) { + return 0; + } else { + (void) GENLIB_yyparse(); + if (global_fct != 0) GENLIB_yyerror("syntax error"); + return 1; + } +} + +int +genlib_parse_library(infp, infilename, outfp, use_nor) +FILE *infp; +char *infilename; +FILE *outfp; +int use_nor; +{ + error_init(); + library_setup_file(infp, infilename); + gl_out_file = outfp; + global_fct = 0; /* not used here, just to check for error */ + global_use_nor = use_nor; + + if (setjmp(jmpbuf)) { + return 0; + } else { + (void) GENLIB_yyparse(); + if (global_fct != 0) GENLIB_yyerror("syntax error"); + return 1; + } +} + +int +gl_convert_expression_to_tree(string, tree, name) +char *string; +tree_node_t **tree; +char **name; +{ + error_init(); + global_fct = 0; + library_setup_string(string); + + if (setjmp(jmpbuf)) { + return 0; + } else { + (void) GENLIB_yyparse(); + if (global_fct == 0) GENLIB_yyerror("syntax error"); + *tree = global_fct->tree; + *name = global_fct->name; + return 1; + } +} diff --git a/sis/genlib/readlib.h b/sis/genlib/readlib.h new file mode 100644 index 0000000..5a4ef2e --- /dev/null +++ b/sis/genlib/readlib.h @@ -0,0 +1,39 @@ +#ifndef BISON_Y_TAB_H +# define BISON_Y_TAB_H + +#ifndef YYSTYPE +typedef union { + tree_node_t *nodeval; + char *strval; + double realval; + pin_info_t *pinval; + function_t *functionval; + latch_info_t *latchval; + constraint_info_t *constrval; +} GENLIB_yystype; +# define YYSTYPE GENLIB_yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +# define OPR_OR 257 +# define OPR_AND 258 +# define CONST1 259 +# define CONST0 260 +# define IDENTIFIER 261 +# define LPAREN 262 +# define REAL 263 +# define OPR_NOT 264 +# define OPR_NOT_POST 265 +# define GATE 266 +# define PIN 267 +# define SEMI 268 +# define ASSIGN 269 +# define RPAREN 270 +# define LATCH 271 +# define CONTROL 272 +# define CONSTRAINT 273 +# define SEQ 274 + + +extern YYSTYPE GENLIB_yylval; + +#endif /* not BISON_Y_TAB_H */ diff --git a/sis/genlib/readlib.y b/sis/genlib/readlib.y new file mode 100644 index 0000000..1df605f --- /dev/null +++ b/sis/genlib/readlib.y @@ -0,0 +1,343 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/readlib.y,v $ + * $Author: pchong $ + * $Revision: 1.6 $ + * $Date: 2004/03/14 17:14:13 $ + * + */ +%{ +/* file @(#)readlib.y 1.2 */ +/* last modified on 6/13/91 at 17:46:40 */ +#include +#include "genlib_int.h" +#include "config.h" + +#undef yywrap +static int input(); +static int unput(); +static int yywrap(); + +FILE *gl_out_file; +#if YYTEXT_POINTER +extern char *yytext; +#else +extern char yytext[]; +#endif + +static int global_use_nor; +static function_t *global_fct; + +extern int library_setup_string(char *); +extern int library_setup_file(FILE *, char *); + +%} + +%union { + tree_node_t *nodeval; + char *strval; + double realval; + pin_info_t *pinval; + function_t *functionval; + latch_info_t *latchval; + constraint_info_t *constrval; +} + + +%type expr +%type name pin_name pin_phase +%type real +%type pins pin_info +%type function +%type clock +%type constraint constraints +%type type +%type latch +%left OPR_OR +%left OPR_AND CONST1 CONST0 IDENTIFIER LPAREN REAL +%left OPR_NOT OPR_NOT_POST +%token GATE PIN SEMI ASSIGN RPAREN +%token LATCH CONTROL CONSTRAINT SEQ +%start hack + +%% +hack : gates + | function + {global_fct = $1; } + ; + +gates : /* empty */ + | gates gate_info + ; + +gate_info: GATE name real function pins + { + if (! gl_convert_gate_to_blif($2,$3,$4,$5,global_use_nor)) + yyerror(NIL(char)); + } + | LATCH name real function pins latch clock constraints + { + if (! gl_convert_latch_to_blif($2,$3,$4,$5,global_use_nor,$6,$7,$8)) + yyerror(NIL(char)); + } + ; + +pins : /* empty */ + { $$ = 0; } + | pins pin_info + { $2->next = $1; $$ = $2;} + ; + +pin_info: PIN pin_name pin_phase real real real real real real + { + $$ = ALLOC(pin_info_t, 1); + $$->name = $2; + $$->phase = $3; + $$->value[0] = $4; $$->value[1] = $5; + $$->value[2] = $6; $$->value[3] = $7; + $$->value[4] = $8; $$->value[5] = $9; + $$->next = 0; + } + ; + +pin_phase: name + { + if (strcmp($1, "INV") != 0) { + if (strcmp($1, "NONINV") != 0) { + if (strcmp($1, "UNKNOWN") != 0) { + yyerror("bad pin phase"); + } + } + } + $$ = $1; + } + ; + +pin_name: name + { $$ = $1; } + | OPR_AND + { $$ = util_strsav(yytext); } + ; + +function: name ASSIGN expr SEMI + { + $$ = ALLOC(function_t, 1); + $$->name = $1; + $$->tree = $3; + $$->next = 0; + } + ; + +expr : expr OPR_OR expr + { + $$ = gl_alloc_node(2); + $$->phase = 1; + $$->sons[0] = $1; + $$->sons[1] = $3; + $$->type = OR_NODE; + } + | expr OPR_AND expr + { + $$ = gl_alloc_node(2); + $$->phase = 1; + $$->sons[0] = $1; + $$->sons[1] = $3; + $$->type = AND_NODE; + } + | expr expr %prec OPR_AND + { + $$ = gl_alloc_node(2); + $$->phase = 1; + $$->sons[0] = $1; + $$->sons[1] = $2; + $$->type = AND_NODE; + } + | LPAREN expr RPAREN + { + $$ = $2; + } + | OPR_NOT expr + { + $$ = $2; + $$->phase = 0; + } + | expr OPR_NOT_POST + { + $$ = $1; + $$->phase = 0; + } + | name + { + $$ = gl_alloc_leaf($1); + FREE($1); + $$->type = LEAF_NODE; /* hack */ + $$->phase = 1; + } + | CONST0 + { + $$ = gl_alloc_leaf("0"); + $$->phase = 1; + $$->type = ZERO_NODE; + } + | CONST1 + { + $$ = gl_alloc_leaf("1"); + $$->phase = 1; + $$->type = ONE_NODE; + } + ; + +name : IDENTIFIER + { $$ = util_strsav(yytext); } + | + REAL + { $$ = util_strsav(yytext); } + ; + +real : REAL + { $$ = atof(yytext); } + ; + +clock : /* empty */ + { $$ = 0;} + | CONTROL name real real real real real real + { $$ = ALLOC(pin_info_t, 1); + $$->name = $2; + $$->phase = util_strsav("UNKNOWN"); + $$->value[0] = $3; + $$->value[1] = $4; + $$->value[2] = $5; + $$->value[3] = $6; + $$->value[4] = $7; + $$->value[5] = $8; + $$->next = 0; + } + ; + +constraints: /* empty */ + { $$ = 0; } + | constraints constraint + { + $2->next = $1; + $$ = $2; + } + ; + +constraint: CONSTRAINT pin_name real real + { + $$ = ALLOC(constraint_info_t, 1); + $$->name = $2; + $$->setup = $3; + $$->hold = $4; + $$->next = 0; + } + ; + +latch : SEQ name name type + { + $$ = ALLOC(latch_info_t, 1); + $$->in = $2; + $$->out = $3; + $$->type = $4; + } + ; + +type : IDENTIFIER + { + if (strcmp(yytext, "RISING_EDGE") == 0) { + $$ = util_strsav("re"); + } else if (strcmp(yytext, "FALLING_EDGE") == 0) { + $$ = util_strsav("fe"); + } else if (strcmp(yytext, "ACTIVE_HIGH") == 0) { + $$ = util_strsav("ah"); + } else if (strcmp(yytext, "ACTIVE_LOW") == 0) { + $$ = util_strsav("al"); + } else if (strcmp(yytext, "ASYNCH") == 0) { + $$ = util_strsav("as"); + } else { + yyerror("latch type can only be re/fe/ah/al/as"); + } + } + ; + +%% +static jmp_buf jmpbuf; + +int +yyerror(errmsg) +char *errmsg; +{ + if (errmsg != 0) read_error(errmsg); + longjmp(jmpbuf, 1); +} + +int +gl_convert_genlib_to_blif(filename, use_nor) +char *filename; +int use_nor; +{ + FILE *fp; + + error_init(); + if ((fp = fopen(filename, "r")) == NULL) { + perror(filename); + return 0; + } + library_setup_file(fp, filename); + gl_out_file = stdout; + + global_fct = 0; /* not used here, just to check for error */ + global_use_nor = use_nor; + + if (setjmp(jmpbuf)) { + return 0; + } else { + (void) yyparse(); + if (global_fct != 0) yyerror("syntax error"); + return 1; + } +} + +int +genlib_parse_library(infp, infilename, outfp, use_nor) +FILE *infp; +char *infilename; +FILE *outfp; +int use_nor; +{ + error_init(); + library_setup_file(infp, infilename); + gl_out_file = outfp; + global_fct = 0; /* not used here, just to check for error */ + global_use_nor = use_nor; + + if (setjmp(jmpbuf)) { + return 0; + } else { + (void) yyparse(); + if (global_fct != 0) yyerror("syntax error"); + return 1; + } +} + +int +gl_convert_expression_to_tree(string, tree, name) +char *string; +tree_node_t **tree; +char **name; +{ + error_init(); + global_fct = 0; + library_setup_string(string); + + if (setjmp(jmpbuf)) { + return 0; + } else { + (void) yyparse(); + if (global_fct == 0) yyerror("syntax error"); + *tree = global_fct->tree; + *name = global_fct->name; + return 1; + } +} diff --git a/sis/genlib/readliblex.c b/sis/genlib/readliblex.c new file mode 100644 index 0000000..3ebd022 --- /dev/null +++ b/sis/genlib/readliblex.c @@ -0,0 +1,1792 @@ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include +#include + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include +#include +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define GENLIB_yyconst const +#else +#define GENLIB_yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN GENLIB_yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((GENLIB_yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE GENLIB_yyrestart( GENLIB_yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct GENLIB_yy_buffer_state *YY_BUFFER_STATE; + +extern int GENLIB_yyleng; +extern FILE *GENLIB_yyin, *GENLIB_yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * GENLIB_yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the GENLIB_yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define GENLIB_yyless(n) \ + do \ + { \ + /* Undo effects of setting up GENLIB_yytext. */ \ + *GENLIB_yy_cp = GENLIB_yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + GENLIB_yy_c_buf_p = GENLIB_yy_cp = GENLIB_yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up GENLIB_yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) GENLIB_yyunput( c, GENLIB_yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int GENLIB_yy_size_t; + + +struct GENLIB_yy_buffer_state + { + FILE *GENLIB_yy_input_file; + + char *GENLIB_yy_ch_buf; /* input buffer */ + char *GENLIB_yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + GENLIB_yy_size_t GENLIB_yy_buf_size; + + /* Number of characters read into GENLIB_yy_ch_buf, not including EOB + * characters. + */ + int GENLIB_yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int GENLIB_yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int GENLIB_yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int GENLIB_yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int GENLIB_yy_fill_buffer; + + int GENLIB_yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via GENLIB_yyrestart()), so that the user can continue scanning by + * just pointing GENLIB_yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE GENLIB_yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER GENLIB_yy_current_buffer + + +/* GENLIB_yy_hold_char holds the character lost when GENLIB_yytext is formed. */ +static char GENLIB_yy_hold_char; + +static int GENLIB_yy_n_chars; /* number of characters read into GENLIB_yy_ch_buf */ + + +int GENLIB_yyleng; + +/* Points to current character in buffer. */ +static char *GENLIB_yy_c_buf_p = (char *) 0; +static int GENLIB_yy_init = 1; /* whether we need to initialize */ +static int GENLIB_yy_start = 0; /* start state number */ + +/* Flag which is used to allow GENLIB_yywrap()'s to do buffer switches + * instead of setting up a fresh GENLIB_yyin. A bit of a hack ... + */ +static int GENLIB_yy_did_buffer_switch_on_eof; + +void GENLIB_yyrestart YY_PROTO(( FILE *input_file )); + +void GENLIB_yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void GENLIB_yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE GENLIB_yy_create_buffer YY_PROTO(( FILE *file, int size )); +void GENLIB_yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void GENLIB_yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void GENLIB_yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER GENLIB_yy_flush_buffer( GENLIB_yy_current_buffer ) + +YY_BUFFER_STATE GENLIB_yy_scan_buffer YY_PROTO(( char *base, GENLIB_yy_size_t size )); +YY_BUFFER_STATE GENLIB_yy_scan_string YY_PROTO(( GENLIB_yyconst char *GENLIB_yy_str )); +YY_BUFFER_STATE GENLIB_yy_scan_bytes YY_PROTO(( GENLIB_yyconst char *bytes, int len )); + +static void *GENLIB_yy_flex_alloc YY_PROTO(( GENLIB_yy_size_t )); +static void *GENLIB_yy_flex_realloc YY_PROTO(( void *, GENLIB_yy_size_t )); +static void GENLIB_yy_flex_free YY_PROTO(( void * )); + +#define GENLIB_yy_new_buffer GENLIB_yy_create_buffer + +#define GENLIB_yy_set_interactive(is_interactive) \ + { \ + if ( ! GENLIB_yy_current_buffer ) \ + GENLIB_yy_current_buffer = GENLIB_yy_create_buffer( GENLIB_yyin, YY_BUF_SIZE ); \ + GENLIB_yy_current_buffer->GENLIB_yy_is_interactive = is_interactive; \ + } + +#define GENLIB_yy_set_bol(at_bol) \ + { \ + if ( ! GENLIB_yy_current_buffer ) \ + GENLIB_yy_current_buffer = GENLIB_yy_create_buffer( GENLIB_yyin, YY_BUF_SIZE ); \ + GENLIB_yy_current_buffer->GENLIB_yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (GENLIB_yy_current_buffer->GENLIB_yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *GENLIB_yyin = (FILE *) 0, *GENLIB_yyout = (FILE *) 0; +typedef int GENLIB_yy_state_type; +extern char *GENLIB_yytext; +#define GENLIB_yytext_ptr GENLIB_yytext + +static GENLIB_yy_state_type GENLIB_yy_get_previous_state YY_PROTO(( void )); +static GENLIB_yy_state_type GENLIB_yy_try_NUL_trans YY_PROTO(( GENLIB_yy_state_type current_state )); +static int GENLIB_yy_get_next_buffer YY_PROTO(( void )); +static void GENLIB_yy_fatal_error YY_PROTO(( GENLIB_yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up GENLIB_yytext. + */ +#define YY_DO_BEFORE_ACTION \ + GENLIB_yytext_ptr = GENLIB_yy_bp; \ + GENLIB_yyleng = (int) (GENLIB_yy_cp - GENLIB_yy_bp); \ + GENLIB_yy_hold_char = *GENLIB_yy_cp; \ + *GENLIB_yy_cp = '\0'; \ + GENLIB_yy_c_buf_p = GENLIB_yy_cp; + +#define YY_NUM_RULES 23 +#define YY_END_OF_BUFFER 24 +static GENLIB_yyconst short int GENLIB_yy_accept[73] = + { 0, + 0, 0, 24, 22, 20, 20, 6, 22, 21, 7, + 2, 3, 9, 8, 19, 22, 19, 4, 5, 19, + 19, 19, 19, 19, 19, 20, 0, 21, 0, 0, + 19, 19, 0, 18, 0, 19, 19, 19, 19, 19, + 19, 19, 1, 0, 0, 0, 0, 19, 19, 19, + 19, 19, 11, 15, 0, 19, 19, 10, 19, 19, + 19, 12, 16, 17, 19, 19, 19, 13, 19, 19, + 14, 0 + } ; + +static GENLIB_yyconst int GENLIB_yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 6, 1, 1, 1, 7, 8, + 9, 10, 11, 1, 12, 13, 1, 14, 15, 16, + 16, 16, 16, 16, 16, 16, 16, 1, 17, 1, + 18, 1, 1, 1, 19, 20, 21, 20, 22, 20, + 23, 24, 25, 20, 20, 26, 20, 27, 28, 29, + 30, 31, 32, 33, 20, 20, 20, 20, 20, 20, + 1, 1, 1, 1, 20, 1, 20, 20, 20, 20, + + 34, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static GENLIB_yyconst int GENLIB_yy_meta[35] = + { 0, + 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, + 1, 4, 4, 4, 4, 4, 1, 1, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4 + } ; + +static GENLIB_yyconst short int GENLIB_yy_base[76] = + { 0, + 0, 0, 173, 174, 33, 35, 174, 0, 0, 174, + 174, 174, 174, 26, 30, 33, 48, 174, 174, 159, + 39, 40, 41, 43, 44, 69, 164, 0, 59, 81, + 153, 0, 114, 174, 62, 0, 138, 42, 52, 66, + 73, 68, 174, 0, 76, 0, 90, 90, 107, 80, + 67, 101, 149, 148, 118, 94, 95, 147, 111, 124, + 112, 146, 145, 144, 128, 118, 98, 133, 129, 130, + 132, 174, 163, 167, 54 + } ; + +static GENLIB_yyconst short int GENLIB_yy_def[76] = + { 0, + 72, 1, 72, 72, 72, 72, 72, 73, 74, 72, + 72, 72, 72, 72, 75, 72, 75, 72, 72, 75, + 75, 75, 75, 75, 75, 72, 73, 74, 72, 72, + 75, 17, 72, 72, 33, 17, 75, 75, 75, 75, + 75, 75, 72, 30, 72, 35, 72, 37, 37, 75, + 75, 75, 75, 75, 72, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 0, 72, 72, 72 + } ; + +static GENLIB_yyconst short int GENLIB_yy_nxt[209] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 17, 17, 18, 19, 20, 20, + 21, 20, 22, 20, 20, 23, 20, 20, 24, 20, + 20, 25, 20, 20, 26, 26, 26, 26, 29, 30, + 30, 30, 29, 32, 32, 32, 33, 33, 33, 34, + 34, 72, 72, 72, 72, 72, 72, 31, 39, 40, + 35, 36, 36, 36, 72, 42, 38, 41, 50, 37, + 26, 26, 33, 33, 33, 46, 46, 46, 72, 72, + 72, 37, 34, 34, 51, 72, 47, 47, 58, 55, + 55, 55, 72, 35, 44, 44, 44, 54, 52, 53, + + 72, 31, 45, 55, 55, 55, 72, 72, 34, 34, + 72, 56, 57, 72, 45, 34, 34, 72, 31, 34, + 34, 59, 69, 72, 72, 61, 60, 33, 33, 33, + 72, 55, 55, 55, 62, 45, 72, 63, 64, 66, + 72, 72, 72, 68, 72, 72, 67, 45, 47, 48, + 72, 49, 49, 49, 65, 70, 72, 72, 72, 72, + 72, 72, 71, 27, 27, 72, 27, 28, 43, 28, + 28, 72, 72, 3, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + + 72, 72, 72, 72, 72, 72, 72, 72 + } ; + +static GENLIB_yyconst short int GENLIB_yy_chk[209] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5, 5, 6, 6, 14, 14, + 14, 14, 15, 15, 15, 15, 16, 16, 16, 17, + 17, 21, 22, 23, 38, 24, 25, 75, 22, 23, + 17, 17, 17, 17, 39, 25, 21, 24, 38, 17, + 26, 26, 29, 29, 29, 35, 35, 35, 40, 51, + 42, 17, 30, 30, 39, 41, 45, 45, 51, 45, + 45, 45, 50, 30, 30, 30, 30, 42, 40, 41, + + 48, 48, 30, 47, 47, 47, 56, 57, 49, 49, + 67, 50, 50, 52, 30, 33, 33, 49, 49, 55, + 55, 52, 67, 59, 61, 57, 56, 33, 33, 33, + 66, 55, 55, 55, 59, 33, 60, 60, 60, 61, + 65, 69, 70, 66, 71, 68, 65, 33, 37, 37, + 37, 37, 37, 37, 60, 69, 64, 63, 62, 58, + 54, 53, 70, 73, 73, 31, 73, 74, 27, 74, + 74, 20, 3, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + + 72, 72, 72, 72, 72, 72, 72, 72 + } ; + +static GENLIB_yy_state_type GENLIB_yy_last_accepting_state; +static char *GENLIB_yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define GENLIB_yymore() GENLIB_yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *GENLIB_yytext; +#line 1 "readliblex.l" +#define INITIAL 0 +#line 2 "readliblex.l" +/* file @(#)readliblex.l 1.1 */ +/* last modified on 5/29/91 at 12:35:32 */ +#include "genlib_int.h" +#include "readlib.h" +#undef input +#undef unput +#ifdef FLEX_SCANNER +#undef YY_INPUT +#define YY_INPUT(buf,result,max) (result = genlib_input(buf, max)) +#endif + +static char *file_string; +static int file_mode; +static int nbuffer; +static char buffer[20]; + +/*alnum [-A-Za-z0-9_.<>$%^&|{}[\]:,?/@]*/ +#line 449 "lex.GENLIB_yy.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int GENLIB_yywrap YY_PROTO(( void )); +#else +extern int GENLIB_yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void GENLIB_yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef GENLIB_yytext_ptr +static void GENLIB_yy_flex_strncpy YY_PROTO(( char *, GENLIB_yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int GENLIB_yy_flex_strlen YY_PROTO(( GENLIB_yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int GENLIB_yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int GENLIB_yy_start_stack_ptr = 0; +static int GENLIB_yy_start_stack_depth = 0; +static int *GENLIB_yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void GENLIB_yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void GENLIB_yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int GENLIB_yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( GENLIB_yytext, GENLIB_yyleng, 1, GENLIB_yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( GENLIB_yy_current_buffer->GENLIB_yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( GENLIB_yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( GENLIB_yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, GENLIB_yyin )) == 0) \ + && ferror( GENLIB_yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "GENLIB_yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef GENLIB_yyterminate +#define GENLIB_yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) GENLIB_yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int GENLIB_yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after GENLIB_yytext and GENLIB_yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register GENLIB_yy_state_type GENLIB_yy_current_state; + register char *GENLIB_yy_cp = NULL, *GENLIB_yy_bp = NULL; + register int GENLIB_yy_act; + +#line 28 "readliblex.l" + + +#line 603 "lex.GENLIB_yy.c" + + if ( GENLIB_yy_init ) + { + GENLIB_yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! GENLIB_yy_start ) + GENLIB_yy_start = 1; /* first start state */ + + if ( ! GENLIB_yyin ) + GENLIB_yyin = stdin; + + if ( ! GENLIB_yyout ) + GENLIB_yyout = stdout; + + if ( ! GENLIB_yy_current_buffer ) + GENLIB_yy_current_buffer = + GENLIB_yy_create_buffer( GENLIB_yyin, YY_BUF_SIZE ); + + GENLIB_yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + GENLIB_yy_cp = GENLIB_yy_c_buf_p; + + /* Support of GENLIB_yytext. */ + *GENLIB_yy_cp = GENLIB_yy_hold_char; + + /* GENLIB_yy_bp points to the position in GENLIB_yy_ch_buf of the start of + * the current run. + */ + GENLIB_yy_bp = GENLIB_yy_cp; + + GENLIB_yy_current_state = GENLIB_yy_start; +GENLIB_yy_match: + do + { + register YY_CHAR GENLIB_yy_c = GENLIB_yy_ec[YY_SC_TO_UI(*GENLIB_yy_cp)]; + if ( GENLIB_yy_accept[GENLIB_yy_current_state] ) + { + GENLIB_yy_last_accepting_state = GENLIB_yy_current_state; + GENLIB_yy_last_accepting_cpos = GENLIB_yy_cp; + } + while ( GENLIB_yy_chk[GENLIB_yy_base[GENLIB_yy_current_state] + GENLIB_yy_c] != GENLIB_yy_current_state ) + { + GENLIB_yy_current_state = (int) GENLIB_yy_def[GENLIB_yy_current_state]; + if ( GENLIB_yy_current_state >= 73 ) + GENLIB_yy_c = GENLIB_yy_meta[(unsigned int) GENLIB_yy_c]; + } + GENLIB_yy_current_state = GENLIB_yy_nxt[GENLIB_yy_base[GENLIB_yy_current_state] + (unsigned int) GENLIB_yy_c]; + ++GENLIB_yy_cp; + } + while ( GENLIB_yy_base[GENLIB_yy_current_state] != 174 ); + +GENLIB_yy_find_action: + GENLIB_yy_act = GENLIB_yy_accept[GENLIB_yy_current_state]; + if ( GENLIB_yy_act == 0 ) + { /* have to back up */ + GENLIB_yy_cp = GENLIB_yy_last_accepting_cpos; + GENLIB_yy_current_state = GENLIB_yy_last_accepting_state; + GENLIB_yy_act = GENLIB_yy_accept[GENLIB_yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( GENLIB_yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *GENLIB_yy_cp = GENLIB_yy_hold_char; + GENLIB_yy_cp = GENLIB_yy_last_accepting_cpos; + GENLIB_yy_current_state = GENLIB_yy_last_accepting_state; + goto GENLIB_yy_find_action; + +case 1: +YY_RULE_SETUP +#line 30 "readliblex.l" +{ + int i; + GENLIB_yytext[GENLIB_yyleng-1] = '\0'; + for(i = 0; i < GENLIB_yyleng; i++) GENLIB_yytext[i] = GENLIB_yytext[i+1]; + GENLIB_yyleng -= 2; + return IDENTIFIER; + } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 38 "readliblex.l" +{ return LPAREN; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 39 "readliblex.l" +{ return RPAREN; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 40 "readliblex.l" +{ return SEMI; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 41 "readliblex.l" +{ return ASSIGN; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 42 "readliblex.l" +{ return OPR_NOT; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 43 "readliblex.l" +{ return OPR_NOT_POST; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 44 "readliblex.l" +{ return OPR_OR; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 45 "readliblex.l" +{ return OPR_AND; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 47 "readliblex.l" +{ return GATE; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 48 "readliblex.l" +{ return PIN; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 49 "readliblex.l" +{ return LATCH; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 50 "readliblex.l" +{ return CONTROL; } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 51 "readliblex.l" +{ return CONSTRAINT; } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 52 "readliblex.l" +{ return SEQ; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 53 "readliblex.l" +{ return CONST0; } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 54 "readliblex.l" +{ return CONST1; } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 55 "readliblex.l" +{ return REAL;} + YY_BREAK +case 19: +YY_RULE_SETUP +#line 56 "readliblex.l" +{ return IDENTIFIER; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 57 "readliblex.l" +; + YY_BREAK +case 21: +YY_RULE_SETUP +#line 58 "readliblex.l" +; /* comments */ + YY_BREAK +case 22: +YY_RULE_SETUP +#line 60 "readliblex.l" +{ GENLIB_yyerror("bad character"); } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 62 "readliblex.l" +ECHO; + YY_BREAK +#line 807 "lex.GENLIB_yy.c" +case YY_STATE_EOF(INITIAL): + GENLIB_yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int GENLIB_yy_amount_of_matched_text = (int) (GENLIB_yy_cp - GENLIB_yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *GENLIB_yy_cp = GENLIB_yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( GENLIB_yy_current_buffer->GENLIB_yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed GENLIB_yyin at a new source and called + * GENLIB_yylex(). If so, then we have to assure + * consistency between GENLIB_yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + GENLIB_yy_n_chars = GENLIB_yy_current_buffer->GENLIB_yy_n_chars; + GENLIB_yy_current_buffer->GENLIB_yy_input_file = GENLIB_yyin; + GENLIB_yy_current_buffer->GENLIB_yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for GENLIB_yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since GENLIB_yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( GENLIB_yy_c_buf_p <= &GENLIB_yy_current_buffer->GENLIB_yy_ch_buf[GENLIB_yy_n_chars] ) + { /* This was really a NUL. */ + GENLIB_yy_state_type GENLIB_yy_next_state; + + GENLIB_yy_c_buf_p = GENLIB_yytext_ptr + GENLIB_yy_amount_of_matched_text; + + GENLIB_yy_current_state = GENLIB_yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * GENLIB_yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + GENLIB_yy_next_state = GENLIB_yy_try_NUL_trans( GENLIB_yy_current_state ); + + GENLIB_yy_bp = GENLIB_yytext_ptr + YY_MORE_ADJ; + + if ( GENLIB_yy_next_state ) + { + /* Consume the NUL. */ + GENLIB_yy_cp = ++GENLIB_yy_c_buf_p; + GENLIB_yy_current_state = GENLIB_yy_next_state; + goto GENLIB_yy_match; + } + + else + { + GENLIB_yy_cp = GENLIB_yy_c_buf_p; + goto GENLIB_yy_find_action; + } + } + + else switch ( GENLIB_yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + GENLIB_yy_did_buffer_switch_on_eof = 0; + + if ( GENLIB_yywrap() ) + { + /* Note: because we've taken care in + * GENLIB_yy_get_next_buffer() to have set up + * GENLIB_yytext, we can now set up + * GENLIB_yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + GENLIB_yy_c_buf_p = GENLIB_yytext_ptr + YY_MORE_ADJ; + + GENLIB_yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! GENLIB_yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + GENLIB_yy_c_buf_p = + GENLIB_yytext_ptr + GENLIB_yy_amount_of_matched_text; + + GENLIB_yy_current_state = GENLIB_yy_get_previous_state(); + + GENLIB_yy_cp = GENLIB_yy_c_buf_p; + GENLIB_yy_bp = GENLIB_yytext_ptr + YY_MORE_ADJ; + goto GENLIB_yy_match; + + case EOB_ACT_LAST_MATCH: + GENLIB_yy_c_buf_p = + &GENLIB_yy_current_buffer->GENLIB_yy_ch_buf[GENLIB_yy_n_chars]; + + GENLIB_yy_current_state = GENLIB_yy_get_previous_state(); + + GENLIB_yy_cp = GENLIB_yy_c_buf_p; + GENLIB_yy_bp = GENLIB_yytext_ptr + YY_MORE_ADJ; + goto GENLIB_yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of GENLIB_yylex */ + + +/* GENLIB_yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int GENLIB_yy_get_next_buffer() + { + register char *dest = GENLIB_yy_current_buffer->GENLIB_yy_ch_buf; + register char *source = GENLIB_yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( GENLIB_yy_c_buf_p > &GENLIB_yy_current_buffer->GENLIB_yy_ch_buf[GENLIB_yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( GENLIB_yy_current_buffer->GENLIB_yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( GENLIB_yy_c_buf_p - GENLIB_yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (GENLIB_yy_c_buf_p - GENLIB_yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( GENLIB_yy_current_buffer->GENLIB_yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + GENLIB_yy_current_buffer->GENLIB_yy_n_chars = GENLIB_yy_n_chars = 0; + + else + { + int num_to_read = + GENLIB_yy_current_buffer->GENLIB_yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = GENLIB_yy_current_buffer; + + int GENLIB_yy_c_buf_p_offset = + (int) (GENLIB_yy_c_buf_p - b->GENLIB_yy_ch_buf); + + if ( b->GENLIB_yy_is_our_buffer ) + { + int new_size = b->GENLIB_yy_buf_size * 2; + + if ( new_size <= 0 ) + b->GENLIB_yy_buf_size += b->GENLIB_yy_buf_size / 8; + else + b->GENLIB_yy_buf_size *= 2; + + b->GENLIB_yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + GENLIB_yy_flex_realloc( (void *) b->GENLIB_yy_ch_buf, + b->GENLIB_yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->GENLIB_yy_ch_buf = 0; + + if ( ! b->GENLIB_yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + GENLIB_yy_c_buf_p = &b->GENLIB_yy_ch_buf[GENLIB_yy_c_buf_p_offset]; + + num_to_read = GENLIB_yy_current_buffer->GENLIB_yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&GENLIB_yy_current_buffer->GENLIB_yy_ch_buf[number_to_move]), + GENLIB_yy_n_chars, num_to_read ); + + GENLIB_yy_current_buffer->GENLIB_yy_n_chars = GENLIB_yy_n_chars; + } + + if ( GENLIB_yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + GENLIB_yyrestart( GENLIB_yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + GENLIB_yy_current_buffer->GENLIB_yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + GENLIB_yy_n_chars += number_to_move; + GENLIB_yy_current_buffer->GENLIB_yy_ch_buf[GENLIB_yy_n_chars] = YY_END_OF_BUFFER_CHAR; + GENLIB_yy_current_buffer->GENLIB_yy_ch_buf[GENLIB_yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + GENLIB_yytext_ptr = &GENLIB_yy_current_buffer->GENLIB_yy_ch_buf[0]; + + return ret_val; + } + + +/* GENLIB_yy_get_previous_state - get the state just before the EOB char was reached */ + +static GENLIB_yy_state_type GENLIB_yy_get_previous_state() + { + register GENLIB_yy_state_type GENLIB_yy_current_state; + register char *GENLIB_yy_cp; + + GENLIB_yy_current_state = GENLIB_yy_start; + + for ( GENLIB_yy_cp = GENLIB_yytext_ptr + YY_MORE_ADJ; GENLIB_yy_cp < GENLIB_yy_c_buf_p; ++GENLIB_yy_cp ) + { + register YY_CHAR GENLIB_yy_c = (*GENLIB_yy_cp ? GENLIB_yy_ec[YY_SC_TO_UI(*GENLIB_yy_cp)] : 1); + if ( GENLIB_yy_accept[GENLIB_yy_current_state] ) + { + GENLIB_yy_last_accepting_state = GENLIB_yy_current_state; + GENLIB_yy_last_accepting_cpos = GENLIB_yy_cp; + } + while ( GENLIB_yy_chk[GENLIB_yy_base[GENLIB_yy_current_state] + GENLIB_yy_c] != GENLIB_yy_current_state ) + { + GENLIB_yy_current_state = (int) GENLIB_yy_def[GENLIB_yy_current_state]; + if ( GENLIB_yy_current_state >= 73 ) + GENLIB_yy_c = GENLIB_yy_meta[(unsigned int) GENLIB_yy_c]; + } + GENLIB_yy_current_state = GENLIB_yy_nxt[GENLIB_yy_base[GENLIB_yy_current_state] + (unsigned int) GENLIB_yy_c]; + } + + return GENLIB_yy_current_state; + } + + +/* GENLIB_yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = GENLIB_yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static GENLIB_yy_state_type GENLIB_yy_try_NUL_trans( GENLIB_yy_state_type GENLIB_yy_current_state ) +#else +static GENLIB_yy_state_type GENLIB_yy_try_NUL_trans( GENLIB_yy_current_state ) +GENLIB_yy_state_type GENLIB_yy_current_state; +#endif + { + register int GENLIB_yy_is_jam; + register char *GENLIB_yy_cp = GENLIB_yy_c_buf_p; + + register YY_CHAR GENLIB_yy_c = 1; + if ( GENLIB_yy_accept[GENLIB_yy_current_state] ) + { + GENLIB_yy_last_accepting_state = GENLIB_yy_current_state; + GENLIB_yy_last_accepting_cpos = GENLIB_yy_cp; + } + while ( GENLIB_yy_chk[GENLIB_yy_base[GENLIB_yy_current_state] + GENLIB_yy_c] != GENLIB_yy_current_state ) + { + GENLIB_yy_current_state = (int) GENLIB_yy_def[GENLIB_yy_current_state]; + if ( GENLIB_yy_current_state >= 73 ) + GENLIB_yy_c = GENLIB_yy_meta[(unsigned int) GENLIB_yy_c]; + } + GENLIB_yy_current_state = GENLIB_yy_nxt[GENLIB_yy_base[GENLIB_yy_current_state] + (unsigned int) GENLIB_yy_c]; + GENLIB_yy_is_jam = (GENLIB_yy_current_state == 72); + + return GENLIB_yy_is_jam ? 0 : GENLIB_yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void GENLIB_yyunput( int c, register char *GENLIB_yy_bp ) +#else +static void GENLIB_yyunput( c, GENLIB_yy_bp ) +int c; +register char *GENLIB_yy_bp; +#endif + { + register char *GENLIB_yy_cp = GENLIB_yy_c_buf_p; + + /* undo effects of setting up GENLIB_yytext */ + *GENLIB_yy_cp = GENLIB_yy_hold_char; + + if ( GENLIB_yy_cp < GENLIB_yy_current_buffer->GENLIB_yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = GENLIB_yy_n_chars + 2; + register char *dest = &GENLIB_yy_current_buffer->GENLIB_yy_ch_buf[ + GENLIB_yy_current_buffer->GENLIB_yy_buf_size + 2]; + register char *source = + &GENLIB_yy_current_buffer->GENLIB_yy_ch_buf[number_to_move]; + + while ( source > GENLIB_yy_current_buffer->GENLIB_yy_ch_buf ) + *--dest = *--source; + + GENLIB_yy_cp += (int) (dest - source); + GENLIB_yy_bp += (int) (dest - source); + GENLIB_yy_current_buffer->GENLIB_yy_n_chars = + GENLIB_yy_n_chars = GENLIB_yy_current_buffer->GENLIB_yy_buf_size; + + if ( GENLIB_yy_cp < GENLIB_yy_current_buffer->GENLIB_yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--GENLIB_yy_cp = (char) c; + + + GENLIB_yytext_ptr = GENLIB_yy_bp; + GENLIB_yy_hold_char = *GENLIB_yy_cp; + GENLIB_yy_c_buf_p = GENLIB_yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int GENLIB_yyinput() +#else +static int input() +#endif + { + int c; + + *GENLIB_yy_c_buf_p = GENLIB_yy_hold_char; + + if ( *GENLIB_yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* GENLIB_yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( GENLIB_yy_c_buf_p < &GENLIB_yy_current_buffer->GENLIB_yy_ch_buf[GENLIB_yy_n_chars] ) + /* This was really a NUL. */ + *GENLIB_yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = GENLIB_yy_c_buf_p - GENLIB_yytext_ptr; + ++GENLIB_yy_c_buf_p; + + switch ( GENLIB_yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because GENLIB_yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + GENLIB_yyrestart( GENLIB_yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( GENLIB_yywrap() ) + return EOF; + + if ( ! GENLIB_yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return GENLIB_yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + GENLIB_yy_c_buf_p = GENLIB_yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) GENLIB_yy_c_buf_p; /* cast for 8-bit char's */ + *GENLIB_yy_c_buf_p = '\0'; /* preserve GENLIB_yytext */ + GENLIB_yy_hold_char = *++GENLIB_yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void GENLIB_yyrestart( FILE *input_file ) +#else +void GENLIB_yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! GENLIB_yy_current_buffer ) + GENLIB_yy_current_buffer = GENLIB_yy_create_buffer( GENLIB_yyin, YY_BUF_SIZE ); + + GENLIB_yy_init_buffer( GENLIB_yy_current_buffer, input_file ); + GENLIB_yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void GENLIB_yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void GENLIB_yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( GENLIB_yy_current_buffer == new_buffer ) + return; + + if ( GENLIB_yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *GENLIB_yy_c_buf_p = GENLIB_yy_hold_char; + GENLIB_yy_current_buffer->GENLIB_yy_buf_pos = GENLIB_yy_c_buf_p; + GENLIB_yy_current_buffer->GENLIB_yy_n_chars = GENLIB_yy_n_chars; + } + + GENLIB_yy_current_buffer = new_buffer; + GENLIB_yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (GENLIB_yywrap()) processing, but the only time this flag + * is looked at is after GENLIB_yywrap() is called, so it's safe + * to go ahead and always set it. + */ + GENLIB_yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void GENLIB_yy_load_buffer_state( void ) +#else +void GENLIB_yy_load_buffer_state() +#endif + { + GENLIB_yy_n_chars = GENLIB_yy_current_buffer->GENLIB_yy_n_chars; + GENLIB_yytext_ptr = GENLIB_yy_c_buf_p = GENLIB_yy_current_buffer->GENLIB_yy_buf_pos; + GENLIB_yyin = GENLIB_yy_current_buffer->GENLIB_yy_input_file; + GENLIB_yy_hold_char = *GENLIB_yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE GENLIB_yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE GENLIB_yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) GENLIB_yy_flex_alloc( sizeof( struct GENLIB_yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in GENLIB_yy_create_buffer()" ); + + b->GENLIB_yy_buf_size = size; + + /* GENLIB_yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->GENLIB_yy_ch_buf = (char *) GENLIB_yy_flex_alloc( b->GENLIB_yy_buf_size + 2 ); + if ( ! b->GENLIB_yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in GENLIB_yy_create_buffer()" ); + + b->GENLIB_yy_is_our_buffer = 1; + + GENLIB_yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void GENLIB_yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void GENLIB_yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == GENLIB_yy_current_buffer ) + GENLIB_yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->GENLIB_yy_is_our_buffer ) + GENLIB_yy_flex_free( (void *) b->GENLIB_yy_ch_buf ); + + GENLIB_yy_flex_free( (void *) b ); + } + + + +#ifdef YY_USE_PROTOS +void GENLIB_yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void GENLIB_yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + GENLIB_yy_flush_buffer( b ); + + b->GENLIB_yy_input_file = file; + b->GENLIB_yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->GENLIB_yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->GENLIB_yy_is_interactive = 0; +#else + b->GENLIB_yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void GENLIB_yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void GENLIB_yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->GENLIB_yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->GENLIB_yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->GENLIB_yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->GENLIB_yy_buf_pos = &b->GENLIB_yy_ch_buf[0]; + + b->GENLIB_yy_at_bol = 1; + b->GENLIB_yy_buffer_status = YY_BUFFER_NEW; + + if ( b == GENLIB_yy_current_buffer ) + GENLIB_yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE GENLIB_yy_scan_buffer( char *base, GENLIB_yy_size_t size ) +#else +YY_BUFFER_STATE GENLIB_yy_scan_buffer( base, size ) +char *base; +GENLIB_yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) GENLIB_yy_flex_alloc( sizeof( struct GENLIB_yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in GENLIB_yy_scan_buffer()" ); + + b->GENLIB_yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->GENLIB_yy_buf_pos = b->GENLIB_yy_ch_buf = base; + b->GENLIB_yy_is_our_buffer = 0; + b->GENLIB_yy_input_file = 0; + b->GENLIB_yy_n_chars = b->GENLIB_yy_buf_size; + b->GENLIB_yy_is_interactive = 0; + b->GENLIB_yy_at_bol = 1; + b->GENLIB_yy_fill_buffer = 0; + b->GENLIB_yy_buffer_status = YY_BUFFER_NEW; + + GENLIB_yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE GENLIB_yy_scan_string( GENLIB_yyconst char *GENLIB_yy_str ) +#else +YY_BUFFER_STATE GENLIB_yy_scan_string( GENLIB_yy_str ) +GENLIB_yyconst char *GENLIB_yy_str; +#endif + { + int len; + for ( len = 0; GENLIB_yy_str[len]; ++len ) + ; + + return GENLIB_yy_scan_bytes( GENLIB_yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE GENLIB_yy_scan_bytes( GENLIB_yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE GENLIB_yy_scan_bytes( bytes, len ) +GENLIB_yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + GENLIB_yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) GENLIB_yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in GENLIB_yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = GENLIB_yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in GENLIB_yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->GENLIB_yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void GENLIB_yy_push_state( int new_state ) +#else +static void GENLIB_yy_push_state( new_state ) +int new_state; +#endif + { + if ( GENLIB_yy_start_stack_ptr >= GENLIB_yy_start_stack_depth ) + { + GENLIB_yy_size_t new_size; + + GENLIB_yy_start_stack_depth += YY_START_STACK_INCR; + new_size = GENLIB_yy_start_stack_depth * sizeof( int ); + + if ( ! GENLIB_yy_start_stack ) + GENLIB_yy_start_stack = (int *) GENLIB_yy_flex_alloc( new_size ); + + else + GENLIB_yy_start_stack = (int *) GENLIB_yy_flex_realloc( + (void *) GENLIB_yy_start_stack, new_size ); + + if ( ! GENLIB_yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + GENLIB_yy_start_stack[GENLIB_yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void GENLIB_yy_pop_state() + { + if ( --GENLIB_yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(GENLIB_yy_start_stack[GENLIB_yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int GENLIB_yy_top_state() + { + return GENLIB_yy_start_stack[GENLIB_yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void GENLIB_yy_fatal_error( GENLIB_yyconst char msg[] ) +#else +static void GENLIB_yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine GENLIB_yyless() so it works in section 3 code. */ + +#undef GENLIB_yyless +#define GENLIB_yyless(n) \ + do \ + { \ + /* Undo effects of setting up GENLIB_yytext. */ \ + GENLIB_yytext[GENLIB_yyleng] = GENLIB_yy_hold_char; \ + GENLIB_yy_c_buf_p = GENLIB_yytext + n; \ + GENLIB_yy_hold_char = *GENLIB_yy_c_buf_p; \ + *GENLIB_yy_c_buf_p = '\0'; \ + GENLIB_yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef GENLIB_yytext_ptr +#ifdef YY_USE_PROTOS +static void GENLIB_yy_flex_strncpy( char *s1, GENLIB_yyconst char *s2, int n ) +#else +static void GENLIB_yy_flex_strncpy( s1, s2, n ) +char *s1; +GENLIB_yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int GENLIB_yy_flex_strlen( GENLIB_yyconst char *s ) +#else +static int GENLIB_yy_flex_strlen( s ) +GENLIB_yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *GENLIB_yy_flex_alloc( GENLIB_yy_size_t size ) +#else +static void *GENLIB_yy_flex_alloc( size ) +GENLIB_yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *GENLIB_yy_flex_realloc( void *ptr, GENLIB_yy_size_t size ) +#else +static void *GENLIB_yy_flex_realloc( ptr, size ) +void *ptr; +GENLIB_yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void GENLIB_yy_flex_free( void *ptr ) +#else +static void GENLIB_yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + GENLIB_yylex(); + return 0; + } +#endif +#line 62 "readliblex.l" + + +#if 0 /* #ifndef FLEX_SCANNER */ +static int +input() +{ + register int c; + + if (nbuffer > 0) { + c = buffer[--nbuffer]; + } else { + if (file_mode) { + c = getc(GENLIB_yyin); + } else { + c = *file_string; + if (c != 0) file_string++; + } + } + if (c == '\n') read_lineno++; + if (c == EOF) c = 0; + return c; +} + + +static int +unput(c) +int c; +{ + if (nbuffer < 20) buffer[nbuffer++] = c; + if (c == '\n') read_lineno--; + return c; +} +#else + +char *genlib_inp_ptr; +char *genlib_inp_lim; + +int genlib_input(char* buf, int max_size) +{ + char c; + int i, n; + + if (! file_mode) { + if (max_size > (genlib_inp_lim - genlib_inp_ptr)) + n = genlib_inp_lim - genlib_inp_ptr; + else + n = max_size; + if (n > 0) { + for (i = 0; i < n; i++) + if (buf[i] == '\n') { + read_lineno++; + i++; + break; + } + memcpy (buf, genlib_inp_ptr, i); + genlib_inp_ptr += i; + } + } else { + c = getc(GENLIB_yyin); + if (c == '\n') read_lineno++; + buf[0] = (c == EOF) ? (n = 0, YY_NULL) : (n = 1, c); + } + return n; +} +#endif + +int +library_setup_file(fp, filename) +FILE *fp; +char *filename; +{ + GENLIB_yyin = fp; +#if 1 /* #ifdef FLEX_SCANNER */ + GENLIB_yy_switch_to_buffer( GENLIB_yy_create_buffer( GENLIB_yyin, YY_BUF_SIZE ) ); + GENLIB_yyrestart(GENLIB_yyin); + BEGIN(INITIAL); +#endif + file_mode = 1; + nbuffer = 0; + read_register_filename(filename); +} + +int +library_setup_string(string) +char *string; +{ + file_string = string; + file_mode = 0; +#if 1 /* #ifdef FLEX_SCANNER */ + GENLIB_yy_switch_to_buffer( + GENLIB_yy_create_buffer( GENLIB_yyin, YY_BUF_SIZE ) ); + GENLIB_yyrestart(GENLIB_yyin); + genlib_inp_lim = string + strlen(string); + genlib_inp_ptr = string; +#endif + nbuffer = 0; + read_register_filename(NIL(char)); +} + +#undef GENLIB_yywrap +int +GENLIB_yywrap() +{ + return 1; +} diff --git a/sis/genlib/readliblex.l b/sis/genlib/readliblex.l new file mode 100644 index 0000000..662c8c5 --- /dev/null +++ b/sis/genlib/readliblex.l @@ -0,0 +1,166 @@ +%{ +/* file @(#)readliblex.l 1.1 */ +/* last modified on 5/29/91 at 12:35:32 */ +#include "genlib_int.h" +#include "readlib.h" +#undef input +#undef unput +#ifdef FLEX_SCANNER +#undef YY_INPUT +#define YY_INPUT(buf,result,max) (result = genlib_input(buf, max)) +#endif + +static char *file_string; +static int file_mode; +static int nbuffer; +static char buffer[20]; + +/*alnum [-A-Za-z0-9_.<>$%^&|{}[\]:,?/@]*/ +%} + +blank [ \n\t] +alnum [-A-Za-z0-9_] +mant1 ([0-9]+\.?[0-9]*) +mant2 ([0-9]*\.[0-9]+) +exp ([eE][-+]?[0-9]+) +float ([-+]?({mant1}|{mant2}){exp}?) + +%% + +\"[^"]+\" { + int i; + yytext[yyleng-1] = '\0'; + for(i = 0; i < yyleng; i++) yytext[i] = yytext[i+1]; + yyleng -= 2; + return IDENTIFIER; + } + +"(" { return LPAREN; } +")" { return RPAREN; } +";" { return SEMI; } +"=" { return ASSIGN; } +"!" { return OPR_NOT; } +"'" { return OPR_NOT_POST; } +"+" { return OPR_OR; } +"*" { return OPR_AND; } + +GATE { return GATE; } +PIN { return PIN; } +LATCH { return LATCH; } +CONTROL { return CONTROL; } +CONSTRAINT { return CONSTRAINT; } +SEQ { return SEQ; } +"CONST0" { return CONST0; } +"CONST1" { return CONST1; } +{float}{blank} { return REAL;} +{alnum}+ { return IDENTIFIER; } +{blank}+ ; +#.* ; /* comments */ + +. { yyerror("bad character"); } + +%% + +#if 0 /* #ifndef FLEX_SCANNER */ +static int +input() +{ + register int c; + + if (nbuffer > 0) { + c = buffer[--nbuffer]; + } else { + if (file_mode) { + c = getc(yyin); + } else { + c = *file_string; + if (c != 0) file_string++; + } + } + if (c == '\n') read_lineno++; + if (c == EOF) c = 0; + return c; +} + + +static int +unput(c) +int c; +{ + if (nbuffer < 20) buffer[nbuffer++] = c; + if (c == '\n') read_lineno--; + return c; +} +#else + +char *genlib_inp_ptr; +char *genlib_inp_lim; + +int genlib_input(char* buf, int max_size) +{ + char c; + int i, n; + + if (! file_mode) { + if (max_size > (genlib_inp_lim - genlib_inp_ptr)) + n = genlib_inp_lim - genlib_inp_ptr; + else + n = max_size; + if (n > 0) { + for (i = 0; i < n; i++) + if (buf[i] == '\n') { + read_lineno++; + i++; + break; + } + memcpy (buf, genlib_inp_ptr, i); + genlib_inp_ptr += i; + } + } else { + c = getc(yyin); + if (c == '\n') read_lineno++; + buf[0] = (c == EOF) ? (n = 0, YY_NULL) : (n = 1, c); + } + return n; +} +#endif + +int +library_setup_file(fp, filename) +FILE *fp; +char *filename; +{ + yyin = fp; +#if 1 /* #ifdef FLEX_SCANNER */ + yy_switch_to_buffer( yy_create_buffer( yyin, YY_BUF_SIZE ) ); + yyrestart(yyin); + BEGIN(INITIAL); +#endif + file_mode = 1; + nbuffer = 0; + read_register_filename(filename); +} + +int +library_setup_string(string) +char *string; +{ + file_string = string; + file_mode = 0; +#if 1 /* #ifdef FLEX_SCANNER */ + yy_switch_to_buffer( + yy_create_buffer( yyin, YY_BUF_SIZE ) ); + yyrestart(yyin); + genlib_inp_lim = string + strlen(string); + genlib_inp_ptr = string; +#endif + nbuffer = 0; + read_register_filename(NIL(char)); +} + +#undef yywrap +int +yywrap() +{ + return 1; +} diff --git a/sis/genlib/sptree.c b/sis/genlib/sptree.c new file mode 100644 index 0000000..c636871 --- /dev/null +++ b/sis/genlib/sptree.c @@ -0,0 +1,506 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/sptree.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)sptree.c 1.1 */ +/* last modified on 5/29/91 at 12:35:33 */ +#include "genlib_int.h" + + +tree_node_t * +gl_alloc_leaf(name) +char *name; +{ + tree_node_t *node; + + node = gl_alloc_node(0); + if (name != NIL(char)) { + node->name = util_strsav(name); + } + return node; +} + + +tree_node_t * +gl_alloc_node(nsons) +int nsons; +{ + tree_node_t *node; + + node = ALLOC(tree_node_t, 1); + node->nsons = nsons; + node->type = OR_NODE; + node->name = NIL(char); + node->phase = 1; + if (nsons > 0) { + node->sons = ALLOC(tree_node_t *, nsons); + } else { + node->sons = NIL(tree_node_t *); + } + return node; +} + + +void +gl_free_node(node) +tree_node_t *node; +{ + if (node->sons != NIL(tree_node_t *)) FREE(node->sons); + if (node->name != NIL(char)) FREE(node->name); + FREE(node); +} + +tree_node_t * +gl_dup_tree(tree) +tree_node_t *tree; +{ + int i; + tree_node_t *node; + + node = gl_alloc_node((int) tree->nsons); + node->type = tree->type; + if (tree->name != NIL(char)) { + node->name = util_strsav(tree->name); + } + for(i = 0; i < tree->nsons; i++) { + node->sons[i] = gl_dup_tree(tree->sons[i]); + } + return node; +} + + +void +gl_free_tree(tree) +tree_node_t *tree; +{ + int i; + + for(i = 0; i < tree->nsons; i++) { + gl_free_tree(tree->sons[i]); + } + gl_free_node(tree); +} + + +tree_node_type_t +gl_reverse_type(type) +tree_node_type_t type; +{ + return (type == OR_NODE) ? AND_NODE : OR_NODE; +} + + +void +gl_dualize_node(tree) +tree_node_t *tree; +{ + tree->type = gl_reverse_type(tree->type); +} + +void +gl_invert_tree(tree) +tree_node_t *tree; +{ + int i; + + if (tree->phase) { + if (tree->nsons) { + for(i = 0; i < tree->nsons; i++) { + gl_invert_tree(tree->sons[i]); + } + gl_dualize_node(tree); + } + else { + tree->phase = 0; + } + } + else { + tree->phase = 1; + } +} + +void +gl_dualize_tree(tree) +tree_node_t *tree; +{ + int i; + + for(i = 0; i < tree->nsons; i++) { + gl_dualize_tree(tree->sons[i]); + } + gl_dualize_node(tree); +} + + +void +gl_make_well_formed(tree) +tree_node_t *tree; +{ + int i, j, new_nsons; + tree_node_t **new_sons, *son; + + if (! tree->phase && tree->nsons) { + tree->phase = 1; + gl_invert_tree(tree); + } +check_sons: + for(i = 0; i < tree->nsons; i++) { + son = tree->sons[i]; + if (! son->phase && son->nsons) { + son->phase = 1; + gl_invert_tree(son); + } + if (son->nsons == 0) { + son->type = gl_reverse_type(tree->type); + + /* his children are my children */ + } else if (tree->type == son->type) { + new_sons = ALLOC(tree_node_t *, tree->nsons + son->nsons - 1); + new_nsons = 0; + for(j = 0; j < i; j++) { + new_sons[new_nsons++] = tree->sons[j]; + } + for(j = 0; j < son->nsons; j++) { + new_sons[new_nsons++] = son->sons[j]; + } + for(j = i+1; j < tree->nsons; j++) { + new_sons[new_nsons++] = tree->sons[j]; + } + gl_free_node(son); + FREE(tree->sons); + tree->sons = new_sons; + tree->nsons = new_nsons; + goto check_sons; + } + } + + for(i = 0; i < tree->nsons; i++) { + gl_make_well_formed(tree->sons[i]); + } +} + +void +gl_compute_level(tree, s, p, level) +tree_node_t *tree; +int *s, *p, *level; +{ + int i, p1, s1, level1; + + if (tree->nsons == 0) { + *s = 1; + *p = 1; + *level = 0; + } else { + *s = *p = *level = 0; + for(i = 0; i < tree->nsons; i++) { + gl_compute_level(tree->sons[i], &s1, &p1, &level1); + if (tree->type == AND_NODE) { + *s += s1; + if (p1 > *p) *p = p1; + } else { + *p += p1; + if (s1 > *s) *s = s1; + } + if (level1 > *level) *level = level1; + } + *level += 1; + } +} + +void +gl_print_tree_recur(fp, tree, level) +FILE *fp; +tree_node_t *tree; +int level; +{ + int i; + + if (tree->nsons == 0) { + if (! tree->phase) { + putc('!', fp); + } + (void) fputs(tree->name, fp); + } else { + if (tree->type == OR_NODE && level > 0) (void) putc('(', fp); + for(i = 0; i < tree->nsons; i++) { + gl_print_tree_recur(fp, tree->sons[i], level+1); + if (tree->type == OR_NODE && i != tree->nsons - 1) { + (void) putc('+', fp); + } + } + if (tree->type == OR_NODE && level > 0) (void) putc(')', fp); + } +} + + +void +gl_print_tree(fp, tree) +FILE *fp; +tree_node_t *tree; +{ + gl_assign_leaf_names(tree); + if (tree->phase || tree->nsons == 0) { + gl_print_tree_recur(fp, tree, 0); + } else { + (void) putc('(', fp); + gl_print_tree_recur(fp, tree, 0); + (void) putc(')', fp); + (void) putc('\'', fp); + } +} + +void +gl_print_tree_recur_algebraic(fp, tree, level) +FILE *fp; +tree_node_t *tree; +int level; +{ + int i; + + if (tree->nsons == 0) { + if (! tree->phase) { + putc('!', fp); + } + (void) fputs(tree->name, fp); + } else { + if (tree->type == OR_NODE && level > 0) (void) putc('(', fp); + for(i = 0; i < tree->nsons; i++) { + gl_print_tree_recur_algebraic(fp, tree->sons[i], level+1); + if (tree->type == OR_NODE && i != tree->nsons - 1) { + (void) putc('+', fp); + } + if (tree->type == AND_NODE && i != tree->nsons - 1) { + (void) putc('*', fp); + } + } + if (tree->type == OR_NODE && level > 0) (void) putc(')', fp); + } +} + + +void +gl_print_tree_algebraic(fp, tree) +FILE *fp; +tree_node_t *tree; +{ + gl_assign_leaf_names(tree); + if (tree->phase || tree->nsons == 0) { + gl_print_tree_recur_algebraic(fp, tree, 0); + } else { + (void) putc('!', fp); + (void) putc('(', fp); + gl_print_tree_recur_algebraic(fp, tree, 0); + (void) putc(')', fp); + } +} + +int +gl_qsort_compare_tree(t1, t2) +tree_node_t **t1, **t2; +{ + return gl_compare_tree(*t1, *t2); +} + + +int +gl_compare_tree(tree1, tree2) +tree_node_t *tree1, *tree2; +{ + int result, i; + + if (tree1->nsons != tree2->nsons) { + return tree1->nsons - tree2->nsons; + } else { + for(i = 0; i < tree1->nsons; i++) { + if (result = gl_compare_tree(tree1->sons[i], tree2->sons[i])) { + return result; + } + } + } + + return 0; +} + + +void +gl_canonical_tree(tree) +tree_node_t *tree; +{ + int i; + + for(i = 0; i < tree->nsons; i++) { + gl_canonical_tree(tree->sons[i]); + } + qsort((char *) tree->sons, (int) tree->nsons, + sizeof(tree_node_t *), gl_qsort_compare_tree); +} + +static tree_node_t **g_forms; +static int g_num; + + +avl_tree * +gl_hash_init() +{ + return avl_init_table(gl_compare_tree); +} + + +/* ARGSUSED */ +void +gl_hash_save(tree, value) +char *tree; +char *value; +{ + g_forms[g_num++] = (tree_node_t *) tree; +} + + +int +gl_hash_end(hash, forms) +avl_tree *hash; +tree_node_t ***forms; +{ + g_num = 0; + g_forms = *forms = ALLOC(tree_node_t *, avl_count(hash)); + avl_foreach(hash, gl_hash_save, AVL_FORWARD); + avl_free_table(hash, (void(*)()) 0, (void(*)()) 0); + return g_num; +} + + +int +gl_hash_find_or_add(hash, tree) +avl_tree *hash; +tree_node_t *tree; +{ + int s, p, level; + + gl_canonical_tree(tree); + gl_compute_level(tree, &s, &p, &level); + tree->s = s; + tree->p = p; + tree->level = level; + if (avl_lookup(hash, (char *) tree, NIL(char *))) { + return 0; + } else { + (void) avl_insert(hash, (char *) tree, NIL(char)); + return 1; + } +} + +static void +gl_assign_node_names_recur(tree, count) +tree_node_t *tree; +int *count; +{ + int i; + + for(i = 0; i < tree->nsons; i++) { + gl_assign_node_names_recur(tree->sons[i], count); + } + if (tree->name == NIL(char)) { + tree->name = ALLOC(char, 20); + (void) sprintf(tree->name, "_%d", (*count)++); + } +} + + +void +gl_assign_node_names(tree) +tree_node_t *tree; +{ + int count = 0; + + gl_assign_node_names_recur(tree, &count); +} + + +static void +gl_assign_leaf_names_recur(tree, count) +tree_node_t *tree; +int *count; +{ + int i; + + if (tree->nsons == 0 && tree->name == NIL(char)) { + tree->name = ALLOC(char, 5); + tree->name[0] = "abcdefghijklmnopqrstuvwxyz"[(*count)++]; + tree->name[1] = '\0'; + } else { + for(i = 0; i < tree->nsons; i++) { + gl_assign_leaf_names_recur(tree->sons[i], count); + } + } +} + + +void +gl_assign_leaf_names(tree) +tree_node_t *tree; +{ + int count = 0; + + gl_assign_leaf_names_recur(tree, &count); +} + +static void +gl_get_unique_leaf_pointers_recur(tree, unique_names) +tree_node_t *tree; +st_table *unique_names; +{ + int i; + char **slotp; + + if (tree->nsons == 0) { + (void) st_find_or_add(unique_names, tree->name, &slotp); + *slotp = (char *) tree; + } else { + for(i = 0; i < tree->nsons; i++) { + gl_get_unique_leaf_pointers_recur(tree->sons[i], unique_names); + } + } +} + + +int +gl_get_unique_leaf_pointers(tree, leafs) +tree_node_t *tree; +tree_node_t ***leafs; +{ + st_table *unique_names; + st_generator *gen; + char *key, *value; + int nleafs = 0; + + unique_names = st_init_table(strcmp, st_strhash); + gl_get_unique_leaf_pointers_recur(tree, unique_names); + *leafs = ALLOC(tree_node_t *, st_count(unique_names)); + st_foreach_item(unique_names, gen, &key, &value) { + (*leafs)[nleafs++] = (tree_node_t *) value; + } + st_free_table(unique_names); + return nleafs; +} + +gl_tree_dump(tree) +tree_node_t *tree; +{ + int i; + + if (tree->nsons == 0) { + (void) printf("LEAF : %s %s-NODE\n", + tree->name, tree->type == OR_NODE ? "OR" : "AND"); + } else { + (void) printf("nsons=%d type=%s\n", + tree->nsons, tree->type == OR_NODE ? "OR" : "AND"); + for(i = 0; i < tree->nsons; i++) { + gl_tree_dump(tree->sons[i]); + } + } +} diff --git a/sis/genlib/sptree.h b/sis/genlib/sptree.h new file mode 100644 index 0000000..7c66299 --- /dev/null +++ b/sis/genlib/sptree.h @@ -0,0 +1,60 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/genlib/sptree.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +/* file @(#)sptree.h 1.1 */ +/* last modified on 5/29/91 at 12:35:35 */ +#define tree_node_type_t unsigned +#define OR_NODE (tree_node_type_t) 0 +#define AND_NODE (tree_node_type_t) 1 +#define NOR_NODE (tree_node_type_t) 2 +#define NAND_NODE (tree_node_type_t) 3 +#define ZERO_NODE (tree_node_type_t) 4 +#define ONE_NODE (tree_node_type_t) 5 +#define LEAF_NODE (tree_node_type_t) 6 + + +typedef struct tree_node_struct tree_node_t; +struct tree_node_struct { + int nsons; /* number of sons (0 implies leaf) */ + unsigned type:3; /* NAND/NOR or OR/AND (nonleaf only) */ + unsigned phase:1; /* 0==inverted, 1==normal (leaf and root only) */ + unsigned s:8; /* series stacking level */ + unsigned p:8; /* parallel stacking level */ + unsigned level:8; /* level of the gate */ + tree_node_t **sons; /* array of child pointers (nonleaf only)*/ + char *name; /* name */ +}; + + +/* tree.c */ +extern tree_node_t *gl_alloc_node(), *gl_alloc_leaf(), *gl_dup_tree(); +extern void gl_free_tree(), gl_reverse_tree(), gl_print_tree(); +extern void gl_compute_level(); +extern void gl_print_tree_algebraic(); +extern void gl_canonical_tree(), gl_assign_leaf_names(), gl_assign_node_names(); +extern void gl_hash_save(), gl_make_well_formed(); +extern int gl_hash_end(), gl_hash_find_or_add(), gl_compare_tree(); +extern int gl_get_unique_leaf_pointers(); +extern avl_tree *gl_hash_init(); + +/* io.c */ +extern void gl_print_all_gates(), gl_print_all_nand_forms(); +extern void gl_print_nand_forms(), gl_print_all_gates_genlib(); +extern void gl_table_of_gate_count(), gl_table_of_nand_forms(); + +/* nand.c */ +extern void gl_write_blif(); +extern int gl_nand_gate_forms(); + +/* aoi.c */ +extern int gl_gen_complex_gates(), gl_generate_complex_gates(); + +/* genlib.c */ +extern int genlib(); +extern char read_error_string[]; diff --git a/sis/graph/Makefile.am b/sis/graph/Makefile.am new file mode 100644 index 0000000..b4ee355 --- /dev/null +++ b/sis/graph/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libgraph.a +libgraph_a_SOURCES = com_graph.c graph.c graph.doc graph_dfs.c graph_s.c \ + graph_int.h graph_static_int.h +pkginclude_HEADERS = graph.h graph_static.h +dist_doc_DATA = graph.doc graph_static.doc diff --git a/sis/graph/Makefile.in b/sis/graph/Makefile.in new file mode 100644 index 0000000..00da5c3 --- /dev/null +++ b/sis/graph/Makefile.in @@ -0,0 +1,421 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libgraph_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/graph +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libgraph_a_AR = $(AR) $(ARFLAGS) +libgraph_a_LIBADD = +am_libgraph_a_OBJECTS = com_graph.$(OBJEXT) graph.$(OBJEXT) \ + graph_dfs.$(OBJEXT) graph_s.$(OBJEXT) +libgraph_a_OBJECTS = $(am_libgraph_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libgraph_a_SOURCES) +DIST_SOURCES = $(libgraph_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libgraph.a +libgraph_a_SOURCES = com_graph.c graph.c graph.doc graph_dfs.c graph_s.c \ + graph_int.h graph_static_int.h + +pkginclude_HEADERS = graph.h graph_static.h +dist_doc_DATA = graph.doc graph_static.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/graph/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/graph/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libgraph.a: $(libgraph_a_OBJECTS) $(libgraph_a_DEPENDENCIES) + -rm -f libgraph.a + $(libgraph_a_AR) libgraph.a $(libgraph_a_OBJECTS) $(libgraph_a_LIBADD) + $(RANLIB) libgraph.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/graph/com_graph.c b/sis/graph/com_graph.c new file mode 100644 index 0000000..3042e4e --- /dev/null +++ b/sis/graph/com_graph.c @@ -0,0 +1,242 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graph/com_graph.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +#ifdef SIS +#include "sis.h" + +static char *month[] = {"Jan", "Feb", "March", "april", "may", "June", + "july", "Aug", "Sept", "Oct", "nov", "Dec" +}; + +#define voidNULL (void (*)()) NULL +#define gGenericNULL (gGeneric (*)()) NULL + +static void +strfree(thing) +gGeneric thing; +{ + FREE(thing); +} + +static int +graph_test() +{ + graph_t *g1, *g2; + int i, j; + vertex_t *v[10]; + lsGen gen, gen2; + vertex_t *vert; + edge_t *edge; + + g1 = g_alloc(); + + for (i = 0; i < 10; i++) { + v[i] = g_add_vertex(g1); + v[i]->user_data = (gGeneric) i; + } + for (i = 0; i < 9; i++) { + for (j = i + 1; j < 10; j++) { + (void) g_add_edge(v[i],v[j]); + } + } + (void) g_add_edge(v[5],v[5]); /* self loop */ + + (void) lsFirstItem(g_get_out_edges(v[4]),(lsGeneric *) &edge,LS_NH); + g_delete_edge(edge,voidNULL); + + g_delete_vertex(v[8],voidNULL,voidNULL); + + g_add_vertex(g1)->user_data = (gGeneric) 10; /* unconnected vertex */ + + g2 = g_dup(g1,gGenericNULL,gGenericNULL,gGenericNULL); + foreach_vertex (g2,gen,vert) { + (void) fprintf(misout,"\nCopy of %d\ngoes to: ",vert->user_data); + foreach_out_edge (vert,gen2,edge) { + (void) fprintf(misout,"%d ",g_e_dest(edge)->user_data); + } + (void) fprintf(misout,"\ncomes from: "); + foreach_in_edge (vert,gen2,edge) { + (void) fprintf(misout,"%d ",g_e_source(edge)->user_data); + } + } + (void) fputc('\n',misout); + g_check(g1); + g_check(g2); + g_free(g1,voidNULL,voidNULL,voidNULL); + g_free(g2,voidNULL,voidNULL,voidNULL); + + g1 = g_alloc(); + for (i = 0; i < 12; i++) { + g_add_vertex(g1)->user_data = (gGeneric) month[i]; + } + g2 = g_dup(g1,gGenericNULL,(gGeneric (*)()) util_strsav,gGenericNULL); + foreach_vertex (g1,gen,vert) { + ((char *) vert->user_data)[0] = '\0'; + } + foreach_vertex (g2,gen,vert) { /* strings copied by strsav */ + (void) fprintf(misout, "%s\n", (char *) vert->user_data); + } + g_free(g1, voidNULL, voidNULL, voidNULL); /* don't free static strings */ + g_free(g2, voidNULL, strfree, voidNULL); /* free copies */ + return(0); +} + +static void +edge_free(thing) +gGeneric thing; +{ + FREE(((gGeneric *) thing)[2]); +} + +static gGeneric +edge_copy(thing) +gGeneric thing; +{ + gGeneric *new = ALLOC(gGeneric,4); + gGeneric *old = (gGeneric *) thing; + + new[0] = old[0]; + new[1] = old[1]; + new[2] = (gGeneric) util_strsav((char *) old[2]); + new[3] = old[3]; + return((gGeneric) new); +} + + +static int +graph_static_test() +{ + graph_t *g1, *g2; + int i,j,x; + vertex_t *v[10], *v1, *v2; + edge_t *e, *edge; + lsGen gen; + + g1 = g_alloc_static(3,2,4); + + for (i = 0; i < 10; i++) { + v[i] = g_add_vertex_static(g1); + g_set_v_slot_static(v[i],0,(gGeneric) i); + g_set_v_slot_static(v[i],1,(gGeneric) (2 * i)); + } + x = 0; + for (i = 0; i < 9; i++) { + for (j = i + 1; j < 10; j++) { + e = g_add_edge_static(v[i],v[j]); + g_set_e_slot_static(e,2,(gGeneric) util_strsav(month[i])); + g_set_e_slot_static(e,1,(gGeneric) x++); + } + } + g_delete_vertex_static(v[3],voidNULL,edge_free); /* kill v[3] */ + (void) lsLastItem(g_get_out_edges(v[6]),(lsGeneric *) &edge,LS_NH); + g_delete_edge_static(edge,edge_free); /* kill last edge of v[6] */ + + g_set_g_slot_static(g1,1,(gGeneric) 'f'); + g2 = g_dup_static(g1,gGenericNULL,gGenericNULL,edge_copy); + + v1 = g_add_vertex_static(g2); + g_copy_v_slots_static(v[2],v1,gGenericNULL); + + foreach_edge (g2,gen,edge) { + v1 = g_e_source(edge); + v2 = g_e_dest(edge); + (void) fprintf(misout, + "%d (%s) connects %d & %d\n",g_get_e_slot_static(edge,1), + g_get_e_slot_static(edge,2),g_get_v_slot_static(v1,0), + g_get_v_slot_static(v2,0)); + } + g_free_static(g1,voidNULL,voidNULL,edge_free); + g_free_static(g2,voidNULL,voidNULL,edge_free); + return(0); +} + +static int +reverso(a,b) +char *a,*b; +{ + return((int) ((vertex_t *) b)->user_data - (int) ((vertex_t *) a)->user_data); +} + +static int +graph_dfs_test() +{ + int i; + vertex_t *v[10]; + array_t *arr; + graph_t *g; + vertex_t *x; + + g = g_alloc(); + for (i = 0; i < 10; i++) { + v[i] = g_add_vertex(g); + v[i]->user_data = (gGeneric) i; + } + (void) g_add_edge(v[3],v[4]); + (void) g_add_edge(v[0],v[3]); + (void) g_add_edge(v[0],v[6]); + (void) g_add_edge(v[0],v[2]); + (void) g_add_edge(v[1],v[3]); + (void) g_add_edge(v[6],v[3]); + (void) g_add_edge(v[2],v[5]); + (void) g_add_edge(v[2],v[3]); + (void) g_add_edge(v[3],v[5]); + (void) g_add_edge(v[6],v[2]); + + (void) g_add_edge(v[7],v[8]); + (void) g_add_edge(v[9],v[7]); + (void) g_add_edge(v[9],v[8]); + arr = g_dfs(g); + (void) fprintf(misout,"Depth first sort\n"); + for (i = 0; i < 10; i++) { + x = array_fetch(vertex_t *,arr,i); + (void) fprintf(misout,"%d\n",x->user_data); + } + array_free(arr); + (void) fprintf(misout,"\nReverse sort\n"); + arr = g_graph_sort(g,reverso); + for (i = 0; i < 10; i++) { + x = array_fetch(vertex_t *,arr,i); + (void) fprintf(misout,"%d\n",x->user_data); + } + array_free(arr); + g_free(g,voidNULL,voidNULL,voidNULL); + return(0); +} + +init_graph() +{ + extern int g_unique_id; + + g_unique_id = 0; + com_add_command("_graph_test",graph_test,0); + com_add_command("_graph_static_test",graph_static_test,0); + com_add_command("_graph_dfs_test",graph_dfs_test,0); +} + +end_graph() +{ +} + +/* + + ______ 1 + / \ / + / v v + | 0 ---> 3 ----> 4 9 --> 8 + | | \ ^\ | ^ + | | \ | \ | / + | | \ | \ | / + \ | \ | \ | / + \v v| v v/ + 6 ---> 2 --> 5 7 + + This is the graph represented in test_graph_dfs +*/ +#endif /* SIS */ + diff --git a/sis/graph/graph.c b/sis/graph/graph.c new file mode 100644 index 0000000..ea8752d --- /dev/null +++ b/sis/graph/graph.c @@ -0,0 +1,416 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graph/graph.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "graph_int.h" + +int g_unique_id; + +graph_t * +g_alloc() +{ + graph_t_int *graph = ALLOC(graph_t_int,1); + + graph->user_data = (gGeneric) NULL; + graph->v_list = lsCreate(); + graph->e_list = lsCreate(); + + return((graph_t *) graph); +} + +void +g_free(g,f_free_g,f_free_v,f_free_e) +graph_t *g; +void (*f_free_g)(); +void (*f_free_v)(); +void (*f_free_e)(); +{ + lsGen gen; + vertex_t *v; + edge_t *e; + + if (g == NIL(graph_t)) { + return; + } + if (f_free_g != (void (*)()) NULL) { + (*f_free_g)(g->user_data); + } + foreach_vertex (g,gen,v) { + if (f_free_v != (void (*)()) NULL) { + (*f_free_v)(v->user_data); + } + (void) lsDestroy(g_get_in_edges(v),(void (*)()) NULL); + (void) lsDestroy(g_get_out_edges(v),(void (*)()) NULL); + FREE(v); + } + foreach_edge (g,gen,e) { + if (f_free_e != (void (*)()) NULL) { + (*f_free_e)(e->user_data); + } + FREE(e); + } + (void) lsDestroy(g_get_vertices(g),(void (*)()) NULL); + (void) lsDestroy(g_get_edges(g),(void (*)()) NULL); + FREE(g); +} + +void +g_check(g) +graph_t *g; +{ + vertex_t *v, *source, *dest; + edge_t *e, *test; + lsGen gen, gen2; + int found; + + if (g == NIL(graph_t)) { + return; + } + foreach_edge (g,gen,e) { + source = g_e_source(e); + dest = g_e_dest(e); + if (source == NIL(vertex_t)) { + fail("g_check: Edge has no source"); + } + if (dest == NIL(vertex_t)) { + fail("g_check: Edge has no destination"); + } + if (g_vertex_graph(source) != g_vertex_graph(dest)) { + fail("g_check: Edge connects different graphs"); + } + found = FALSE; + foreach_out_edge (source,gen2,test) { + if (test == e) { + found = TRUE; + (void) lsFinish(gen2); + break; + } + } + if (found == FALSE) { + fail("g_check: Vertex does not point back to edge"); + } + found = FALSE; + foreach_in_edge (dest,gen2,test) { + if (test == e) { + found = TRUE; + (void) lsFinish(gen2); + break; + } + } + if (found == FALSE) { + fail("g_check: Vertex does not point back to edge"); + } + } + foreach_vertex (g,gen,v) { + if (g_vertex_graph(v) != g) { + fail("g_check: Vertex not a member of graph"); + } + if (lsLength(g_get_in_edges(v)) + lsLength(g_get_out_edges(v)) == 0) { + (void) fprintf(miserr,"Warning: g_check: Unconnected vertex\n"); + continue; + } + foreach_in_edge(v,gen2,test) { + if (g_e_dest(test) != v) { + fail("g_check: Edge does not point back to vertex"); + } + } + foreach_out_edge(v,gen2,test) { + if (g_e_source(test) != v) { + fail("g_check: Edge does not point back to vertex"); + } + } + } +} + +graph_t * +g_dup(g,f_copy_g,f_copy_v,f_copy_e) +graph_t *g; +gGeneric (*f_copy_g)(); +gGeneric (*f_copy_v)(); +gGeneric (*f_copy_e)(); +{ + graph_t *new; + vertex_t *v, *new_v, *from, *to; + edge_t *e, *new_e; + st_table *ptrtable = st_init_table(st_ptrcmp,st_ptrhash); + lsGen gen; + + new = g_alloc(); + if (g == NIL(graph_t)) { + return(new); + } + + if (f_copy_g == (gGeneric (*)()) NULL) { + new->user_data = g->user_data; + } + else { + new->user_data = (*f_copy_g)(g->user_data); + } + foreach_vertex (g,gen,v) { + new_v = g_add_vertex(new); + if (f_copy_v == (gGeneric (*)()) NULL) { + new_v->user_data = v->user_data; + } + else { + new_v->user_data = (*f_copy_v)(v->user_data); + } + (void) st_insert(ptrtable,(char *) v,(char *) new_v); + } + foreach_edge (g,gen,e) { + (void) st_lookup(ptrtable,(char *) g_e_source(e),(char **) &from); + (void) st_lookup(ptrtable,(char *) g_e_dest(e),(char **) &to); + new_e = g_add_edge(from,to); + if (f_copy_e == (gGeneric (*)()) NULL) { + new_e->user_data = e->user_data; + } + else { + new_e->user_data = (*f_copy_e)(e->user_data); + } + } + st_free_table(ptrtable); + return(new); +} + +array_t * +g_graph_sort(g,cmp) +graph_t *g; +int (*cmp)(); +{ + int i; + lsGen gen; + vertex_t *v; + array_t *v_array; + + i = 0; + v_array = array_alloc(vertex_t *,0); + + foreach_vertex (g,gen,v) { + array_insert(vertex_t *,v_array,i++,v); + } + array_sort(v_array,cmp); + return(v_array); +} + +lsList +g_get_edges(g) +graph_t *g; +{ + if (g == NIL(graph_t)) { + fail("g_get_edges: Null graph"); + } + return(((graph_t_int *) g)->e_list); +} + +lsList +g_get_in_edges(v) +vertex_t *v; +{ + if (v == NIL(vertex_t)) { + fail("g_get_in_edges: Null vertex"); + } + return(((vertex_t_int *) v)->in_list); +} + +lsList +g_get_out_edges(v) +vertex_t *v; +{ + if (v == NIL(vertex_t)) { + fail("g_get_out_edges: Null vertex"); + } + return(((vertex_t_int *) v)->out_list); +} + +edge_t * +g_add_edge(v1,v2) +vertex_t *v1, *v2; +{ + edge_t_int *edge; + lsHandle handle; + graph_t *g; + + if (v1 == NIL(vertex_t) || v2 == NIL(vertex_t)) { + fail("g_add_edge: Null vertex"); + } + g = g_vertex_graph(v1); + if (g != g_vertex_graph(v2)) { + fail("g_add_edge: Edge connects different graphs"); + } + edge = ALLOC(edge_t_int,1); + (void) lsNewEnd(g_get_edges(g),(lsGeneric) edge,&handle); + edge->user_data = (gGeneric) NULL; + edge->from = (vertex_t_int *) v1; + edge->to = (vertex_t_int *) v2; + edge->id = g_unique_id++; + edge->handle = handle; + (void) lsNewEnd(g_get_out_edges(v1),(lsGeneric) edge,LS_NH); + (void) lsNewEnd(g_get_in_edges(v2),(lsGeneric) edge,LS_NH); + + return((edge_t *) edge); +} + +static void +g_del_from_list(list,item) +lsList list; +lsGeneric item; +{ + lsGen gen; + lsGeneric looking,dummy; + lsHandle handle; + + gen = lsStart(list); + while (lsNext(gen,&looking,&handle) != LS_NOMORE) { + if (item == looking) { + if (lsRemoveItem(handle,&dummy) != LS_OK) { + fail("g_del_from_list: Can't remove edge"); + } + break; + } + } + (void) lsFinish(gen); +} + +void +g_delete_edge(e,f_free_e) +edge_t *e; +void (*f_free_e)(); +{ + lsGeneric junk; + + if (e == NIL(edge_t)) { + fail("g_delete_edge: Null edge"); + } + g_del_from_list(g_get_out_edges(g_e_source(e)),(lsGeneric) e); + g_del_from_list(g_get_in_edges(g_e_dest(e)),(lsGeneric) e); + + (void) lsRemoveItem(((edge_t_int *) e)->handle,&junk); + if (f_free_e != (void (*)()) NULL) { + (*f_free_e)(e->user_data); + } + FREE(e); +} + +graph_t * +g_edge_graph(e) +edge_t *e; +{ + if (e == NIL(edge_t)) { + fail("g_edge_graph: Null edge"); + } + return((graph_t *) (((edge_t_int *) e)->to->g)); +} + +vertex_t * +g_e_source(e) +edge_t *e; +{ + if (e == NIL(edge_t)) { + fail("g_e_source: Null edge"); + } + return((vertex_t *) (((edge_t_int *) e)->from)); +} + +vertex_t * +g_e_dest(e) +edge_t *e; +{ + if (e == NIL(edge_t)) { + fail("g_e_dest: Null edge"); + } + return((vertex_t *) (((edge_t_int *) e)->to)); +} + + +lsList +g_get_vertices(g) +graph_t *g; +{ + if (g == NIL(graph_t)) { + fail("g_get_vertices: Null graph"); + } + return(((graph_t_int *) g)->v_list); +} + +vertex_t * +g_add_vertex(g) +graph_t *g; +{ + lsHandle handle; + vertex_t_int *vert; + + if (g == NIL(graph_t)) { + fail("g_add_vertex: Null graph"); + } + vert = ALLOC(vertex_t_int,1); + if (lsNewEnd(g_get_vertices(g),(lsGeneric) vert,&handle) != LS_OK) { + fail("g_add_vertex: Can't add vertex"); + } + vert->user_data = (gGeneric) NULL; + vert->g = (graph_t_int *) g; + vert->in_list = lsCreate(); + vert->out_list = lsCreate(); + vert->id = g_unique_id++; + vert->handle = handle; + return((vertex_t *) vert); +} + +void +g_delete_vertex(v,f_free_v,f_free_e) +vertex_t *v; +void (*f_free_v)(); +void (*f_free_e)(); +{ + edge_t *e; + lsGeneric junk; + lsGen gen; + + if (v == NIL(vertex_t)) { + fail("g_delete_vertex: Null vertex"); + } + if (f_free_v != (void (*)()) NULL) { + (*f_free_v)(v->user_data); + } + foreach_in_edge (v,gen,e) { + g_del_from_list(g_get_out_edges(g_e_source(e)),(lsGeneric) e); + if (f_free_e != (void (*)()) NULL) { + (*f_free_e)(e->user_data); + } + if (lsRemoveItem(((edge_t_int *) e)->handle,&junk) != LS_OK) { + fail("g_delete_vertex: Can't remove edge from graph"); + } + FREE(e); + } + foreach_out_edge (v,gen,e) { + g_del_from_list(g_get_in_edges(g_e_dest(e)),(lsGeneric) e); + if (f_free_e != (void (*)()) NULL) { + (*f_free_e)(e->user_data); + } + if (lsRemoveItem(((edge_t_int *) e)->handle,&junk) != LS_OK) { + fail("g_delete_vertex: Can't remove edge from graph"); + } + FREE(e); + } + (void) lsDestroy(g_get_out_edges(v),(void (*)()) NULL); + (void) lsDestroy(g_get_in_edges(v),(void (*)()) NULL); + (void) lsRemoveItem(((vertex_t_int *) v)->handle,&junk); + FREE(v); +} + +graph_t * +g_vertex_graph(v) +vertex_t *v; +{ + if (v == NIL(vertex_t)) { + fail("g_vertex_graph: Null vertex"); + } + return((graph_t *) ((vertex_t_int *) v)->g); +} +#endif /* SIS */ + diff --git a/sis/graph/graph.doc b/sis/graph/graph.doc new file mode 100644 index 0000000..cdee82a --- /dev/null +++ b/sis/graph/graph.doc @@ -0,0 +1,252 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graph/graph.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +Requires list.h, graph.h, graph_static.h, graph_int.h, and graph_static_int.h. + +A directed graph package. + +`in_edges' represent the incoming edges and `out_edges' represent the +outgoing edges of a given vertex. This package can be used for undirected +graphs, but then generating over all edges incident to a vertex means +generating over both the in_edges and out_edges. + + +graph_t * +g_alloc(); + + Allocate and return a graph. + +void +g_free(g, f_free_g, f_free_v, f_free_e); +graph_t *g; +void (*f_free_g)(gGeneric); +void (*f_free_v)(gGeneric); +void (*f_free_e)(gGeneric); + + Free the storage associated with a graph, including the vertices and + the edges. The user_data associated with the graph, each vertex, + and each edge is freed by the user-supplied functions f_free_g, + f_free_v, and f_free_e. + +void +g_check(g); +graph_t *g; + + Check the graph for consistency by checking that the connectivity + information contained on the vertices and edges is consistent. + Error traps on serious errors that indicate corrupt graphs. Prints + a warning message on possible errors, such as unconnected vertices. + +graph_t * +g_dup(g, f_copy_g, f_copy_v, f_copy_e) +graph_t *g; +gGeneric (*f_copy_g)(gGeneric); +gGeneric (*f_copy_v)(gGeneric); +gGeneric (*f_copy_e)(gGeneric); + + Return a copy of the graph g. The graph, its vertices and edges, + and the connectivity information is copied. The user_data on the + graph, each vertex, and each edge is copied by the user-supplied + functions f_copy_g, f_copy_v, and f_copy_e. If NULL is passed as a + copy function, the user_data fields are copied by an assignment + statement (new->user_data = old->user_data). The functions take as + an argument the user_data field. + +array_t * +g_dfs(g) +graph_t *g; + + Returns an array consisting of a depth first sort on the vertices of + the graph. Error traps if the graph if cyclic. + +int +g_is_acyclic(g) +graph_t *g; + + Returns TRUE if graph is acyclic. + Returns FALSE otherwise. + +array_t * +g_graph_sort(g,compare) +graph_t *g; +int (*compare)(vertex_t *a, vertex_t *b); + + Returns a sorted array of the vertices in the graph. + + The compare() function is passed pointers to the vertices (not the + user data field). It should should return a negative number if + a < b, zero if a == b, and a positive number if a > b. + + Sample compare() body for sorting into increasing order on user_data: + { + int aval = (int) a->user_data; + int bval = (int) b->user_data; + return(aval - bval); + } + + +lsList +g_get_vertices(g) +graph_t *g; + + Return a list containing all the vertices of the given graph. + All of the list package functions may be performed on this + list; however, no functions that modify the list should be used + as the list is part of the graph structure (instead, the list + should be copied and only the copy modified). + +lsList +g_get_edges(g) +graph_t *g; + + Return a list containing all the edges of the given graph. + All of the list package functions may be performed on this + list; however, no functions that modify the list should be used + as the list is part of the graph structure (instead, the list + should be copied and only the copy modified). + +foreach_vertex(graph, lsGen, vertex) +foreach_edge(graph, lsGen, edge) + + Macros that loop through all the vertices or edges of a graph. If + you break out of a loop, lsFinish should be called on the generator. + + +/* vertices */ + +vertex_t * +g_add_vertex(g) +graph_t *g; + + Allocate a vertex and add it to the graph. Return the new + vertex. + +void +g_delete_vertex(v, f_free_v, f_free_e) +vertex_t *v; +void (*f_free_v)(gGeneric); +void (*f_free_e)(gGeneric); + + Free the storage associated with a vertex, including the vertex + itself and its edges. The user_data associated with the vertex and + each of its edges is freed via the user-supplied functions f_free_v + and f_free_e, which take as an argument the user_data field. If + NULL is passed as a free function, the respective user_data field is + not freed. + +graph_t * +g_vertex_graph(v) +vertex_t *v; + + Return the graph that the given vertex belongs to. + +lsList +g_get_in_edges(v) +vertex_t *v; + + Return a list containing all the in_edges of the given vertex. + All of the list package functions may be performed on this + list; however, no functions that modify the list should be + used as the list is part of the graph structure (instead, the + list should be copied and only the copy modified). + +lsList +g_get_out_edges(v) +vertex_t *v; + + Return a list containing all the out_edges of the given vertex. + All of the list package functions may be performed on this + list; however, no functions that modify the list should be + used as the list is part of the graph structure (instead, the + list should be copied and only the copy modified). + +foreach_in_edge(vertex, lsGen, edge) +foreach_out_edge(vertex, lsGen, edge) + + Macros that loop through all the specified directed edges of a + vertex. If you break out of a loop, lsFinish should be called on + the generator. + + +/* edges */ + +edge_t * +g_add_edge(v1, v2) +vertex *v1, *v2; + + Add a directed edge from v1 to v2. The new edge is returned. v1 + and v2 must belong to the same graph. + +void +g_delete_edge(e, f_free_e) +edge_t *edge; +void (*f_free_e)(gGeneric); + + Free the storage associated with an edge. The user_data is freed + via the user-supplied function f_free_e which takes as an argument + the user_data field. If NULL is passed as the free function, the + user_data field is not freed. + +graph_t * +g_edge_graph(e) +edge_t *e; + + Return the graph that the given edge belongs to. + +vertex_t * +g_e_source(e) +edge_t *e; + + Return the source vertex of the given directed edge. + +vertex_t * +g_e_dest(e) +edge_t *e; + + Return the destination vertex of the given directed edge. + +------------------------------------------------- +Files: + +com_graph.c: Code for graph_test(), graph_static_test(), graph_dfs_test(), + init_graph(), and end_graph(). + com_add_commands() for above test procedures. + +graph.c: g_alloc(), g_free(), g_check(), g_dup(), and g_graph_sort(). + g_get_edges(), g_get_in_edges(), g_get_out_edges(), + g_add_edge(), g_delete_edge(), g_edge_graph(), g_e_source(), + and g_e_dest(). + g_get_vertices(), g_add_vertex(), g_delete_vertex(), and + g_vertex_graph(). + +graph.h: External declarations for functions in graph.c. + Macro definitions for foreach_vertex(), foreach_edge(), + foreach_out_edge(), foreach_in_edge(). + Typedefs for graph_t, edge_t, and vertex_t structures. + +graph_dfs.c: Code for g_dfs() and g_is_acyclic(). + +graph_int.h: Typedefs for graph_t_int, edge_t_int, and vertex_t_int + structures. + +graph_s.c: g_alloc_static(), g_free_static(), g_dup_static(), + g_set_g_slot_static(), g_get_g_slot_static(), and + g_copy_g_slots_static(). + g_add_edge_static(), g_delete_edge_static(), + g_set_e_slot_static(), g_get_e_slot_static(), and + g_copy_e_slots_static(). + g_add_vertex_static(), g_delete_vertex_static(), + g_set_v_slot_static(), g_get_v_slot_static(), and + g_copy_v_slots_static(). + +graph_static.h: Externs for functions in graph_s.c, vertex_s.c, and edge_s.c. + +graph_static_int.h: Typedef for g_field_t. + + diff --git a/sis/graph/graph.h b/sis/graph/graph.h new file mode 100644 index 0000000..144ab82 --- /dev/null +++ b/sis/graph/graph.h @@ -0,0 +1,70 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graph/graph.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +typedef char *gGeneric; + +typedef struct graph_struct { + gGeneric user_data; +} graph_t; + +typedef struct vertex_struct { + gGeneric user_data; +} vertex_t; + +typedef struct edge_struct { + gGeneric user_data; +} edge_t; + +typedef void (*GRAPH_PFV)(); +typedef gGeneric (*GRAPH_PFG)(); + +EXTERN graph_t *g_alloc ARGS((void)); +EXTERN void g_free ARGS((graph_t *, void(*)(), void(*)(), void(*)())); +EXTERN void g_check ARGS((graph_t *)); +EXTERN graph_t *g_dup ARGS((graph_t *, gGeneric(*)(), gGeneric(*)(), gGeneric(*)())); + +EXTERN lsList g_get_vertices ARGS((graph_t *)); + +#define foreach_vertex(g, lgen, v) \ + for (lgen = lsStart(g_get_vertices(g)); \ + lsNext(lgen, (lsGeneric *) &v, LS_NH) == LS_OK \ + || ((void) lsFinish(lgen), 0); ) + +#define foreach_edge(g, lgen, e) \ + for (lgen = lsStart(g_get_edges(g)); \ + lsNext(lgen, (lsGeneric *) &e, LS_NH) == LS_OK \ + || ((void) lsFinish(lgen), 0); ) + +EXTERN vertex_t *g_add_vertex ARGS((graph_t *)); +EXTERN void g_delete_vertex ARGS((vertex_t *, void (*)(), void (*)())); +EXTERN graph_t *g_vertex_graph ARGS((vertex_t *)); + +EXTERN lsList g_get_edges ARGS((graph_t *)); +EXTERN lsList g_get_in_edges ARGS((vertex_t *)); +EXTERN lsList g_get_out_edges ARGS((vertex_t *)); + +#define foreach_in_edge(v, lgen, e) \ + for (lgen = lsStart(g_get_in_edges(v)); \ + lsNext(lgen, (lsGeneric *) &e, LS_NH) == LS_OK \ + || ((void) lsFinish(lgen), 0); ) + +#define foreach_out_edge(v, lgen, e) \ + for (lgen = lsStart(g_get_out_edges(v)); \ + lsNext(lgen, (lsGeneric *) &e, LS_NH) == LS_OK \ + || ((void) lsFinish(lgen), 0); ) + +EXTERN edge_t *g_add_edge ARGS((vertex_t *, vertex_t *)); +EXTERN void g_delete_edge ARGS((edge_t *, void (*)())); +EXTERN graph_t *g_edge_graph ARGS((edge_t *)); +EXTERN vertex_t *g_e_source ARGS((edge_t *)); +EXTERN vertex_t *g_e_dest ARGS((edge_t *)); + +EXTERN array_t *g_dfs ARGS((graph_t *)); +EXTERN int g_is_acyclic ARGS((graph_t *)); +EXTERN array_t *g_graph_sort ARGS((graph_t *, int (*)())); diff --git a/sis/graph/graph_dfs.c b/sis/graph/graph_dfs.c new file mode 100644 index 0000000..7c84be3 --- /dev/null +++ b/sis/graph/graph_dfs.c @@ -0,0 +1,126 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graph/graph_dfs.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "graph_int.h" + +static vertex_t * +find_an_end_vertex(v,visit_list) +vertex_t *v; +st_table *visit_list; +{ + edge_t *e; + vertex_t *dest; + lsGen gen; + + if (lsLength(g_get_out_edges(v)) == 0) { + return(v); + } + foreach_out_edge (v,gen,e) { + (void) lsFinish(gen); + dest = g_e_dest(e); + if (st_insert(visit_list,(char *) dest,(char *) 0) == 1) { + return(NIL(vertex_t)); + } + return(find_an_end_vertex(dest,visit_list)); + /* NOTREACHED */ + } + /* no free out_edges */ + return(NIL(vertex_t)); +} + +static int +dfs_recurr(v, dfs_list, dfs_array) +vertex_t *v; +st_table *dfs_list; +array_t *dfs_array; +{ + edge_t *e; + lsGen gen; + int val; + + if (st_lookup_int(dfs_list,(char *) v, &val)) { + return(val == 0); + } + (void) st_insert(dfs_list,(char *) v,(char *) 1); + + foreach_in_edge (v,gen,e) { + if (!dfs_recurr(g_e_source(e),dfs_list,dfs_array)) { + return(0); + } + } + (void) st_insert(dfs_list,(char *) v,(char *) 0); + array_insert_last(vertex_t *,dfs_array,v); + return(1); +} + +static array_t * +g_dfs_int(g) +graph_t *g; +{ + vertex_t *v; + lsGen gen; + array_t *dfs_array; + st_table *visit_list,*dfs_list; + int cycle = FALSE; + + dfs_array = array_alloc(vertex_t *,0); + visit_list = st_init_table(st_ptrcmp,st_ptrhash); + dfs_list = st_init_table(st_ptrcmp,st_ptrhash); + + foreach_vertex (g,gen,v) { + if (!st_is_member(dfs_list,(char *) v)) { + (void) st_insert(visit_list,(char *) v,(char *) 0); + v = find_an_end_vertex(v,visit_list); + if (v == NIL(vertex_t) || !dfs_recurr(v,dfs_list,dfs_array)) { + cycle = TRUE; + (void) lsFinish(gen); + break; + } + } + } + + st_free_table(visit_list); + st_free_table(dfs_list); + if (cycle == TRUE) { + array_free(dfs_array); + return(NIL(array_t)); + } + return(dfs_array); +} + +array_t * +g_dfs(g) +graph_t *g; +{ + array_t *x; + + x = g_dfs_int(g); + if (x == NIL(array_t)) { + fail("g_dfs: Graph has cycle"); + } + return(x); +} + +int +g_is_acyclic(g) +graph_t *g; +{ + array_t *x; + + x = g_dfs_int(g); + if (x) { + array_free(x); + return(TRUE); + } + return(FALSE); +} +#endif /* SIS */ + diff --git a/sis/graph/graph_int.h b/sis/graph/graph_int.h new file mode 100644 index 0000000..9c20d14 --- /dev/null +++ b/sis/graph/graph_int.h @@ -0,0 +1,34 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graph/graph_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +typedef struct graph_struct_int { + gGeneric user_data; + lsList v_list; + lsList e_list; +} graph_t_int; + +typedef struct vertex_struct_int { + gGeneric user_data; + graph_t_int *g; + lsList in_list; + lsList out_list; + int id; + lsHandle handle; /* for quick deletion in the graph v_list */ +} vertex_t_int; + +typedef struct edge_struct_int { + gGeneric user_data; + vertex_t_int *from; + vertex_t_int *to; + int id; + lsHandle handle; /* for quick deletion in the graph e_list */ +} edge_t_int; + +extern void del_from_list(); +extern int g_unique_id; diff --git a/sis/graph/graph_s.c b/sis/graph/graph_s.c new file mode 100644 index 0000000..2e28e8e --- /dev/null +++ b/sis/graph/graph_s.c @@ -0,0 +1,399 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graph/graph_s.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "graph_int.h" +#include "graph_static_int.h" + +#define g_field(graph) ((g_field_t *) (graph)->user_data) + +graph_t * +g_alloc_static(ng, nv, ne) +int ng, nv, ne; +{ + graph_t *g; + g_field_t *gf;; + + g = g_alloc(); + gf = ALLOC(g_field_t,1); + gf->num_g_slots = ng; + gf->num_v_slots = nv; + gf->num_e_slots = ne; + gf->user_data = (gGeneric) ALLOC(gGeneric, ng); + + g->user_data = (gGeneric) gf; + return(g); +} + +void +g_free_static(g, f_free_g, f_free_v, f_free_e) +graph_t *g; +void (*f_free_g)(); +void (*f_free_v)(); +void (*f_free_e)(); +{ + vertex_t *v; + edge_t *e; + lsGen gen; + lsGeneric junk; + + if (g == NIL(graph_t)) { + return; + } + if (f_free_g != (void (*)()) NULL) { + (*f_free_g)(g_field(g)->user_data); + } + FREE(g_field(g)->user_data); + FREE(g->user_data); + + foreach_vertex(g,gen,v) { + if (f_free_v != (void (*)()) NULL) { + (*f_free_v)(v->user_data); + } + FREE(v->user_data); + (void) lsDestroy(g_get_in_edges(v),(void (*)()) NULL); + (void) lsDestroy(g_get_out_edges(v),(void (*)()) NULL); + (void) lsRemoveItem(((vertex_t_int *) v)->handle,&junk); + FREE(v); + } + foreach_edge(g,gen,e) { + if (f_free_e != (void (*)()) NULL) { + (*f_free_e)(e->user_data); + } + FREE(e->user_data); + (void) lsRemoveItem(((edge_t_int *) e)->handle,&junk); + FREE(e); + } + g_free(g,(void (*)()) NULL,(void (*)()) NULL,(void (*)()) NULL); +} + +static graph_t *theGraph; + +static gGeneric +copy_v_slots(user_data) +gGeneric user_data; +{ + int i; + int num_v_slots = g_field(theGraph)->num_v_slots; + gGeneric *new = ALLOC(gGeneric,num_v_slots); + + for (i = 0; i < num_v_slots; i++) { + new[i] = ((gGeneric *) user_data)[i]; + } + return((gGeneric) new); +} + +static gGeneric +copy_e_slots(user_data) +gGeneric user_data; +{ + int i; + int num_e_slots = g_field(theGraph)->num_e_slots; + gGeneric *new = ALLOC(gGeneric,num_e_slots); + + for (i = 0; i < num_e_slots; i++) { + new[i] = ((gGeneric *) user_data)[i]; + } + return((gGeneric) new); +} + +graph_t * +g_dup_static(g, f_copy_g, f_copy_v, f_copy_e) +graph_t *g; +gGeneric (*f_copy_g)(); +gGeneric (*f_copy_v)(); +gGeneric (*f_copy_e)(); +{ + g_field_t *gf, *gf2; + graph_t *g2; + gGeneric *new; + int i; + + if (f_copy_v == (gGeneric (*)()) NULL) { + theGraph = g; + f_copy_v = copy_v_slots; + } + if (f_copy_e == (gGeneric (*)()) NULL) { + theGraph = g; + f_copy_e = copy_e_slots; + } + g2 = g_dup(g,(gGeneric (*)()) NULL,f_copy_v,f_copy_e); + if (g == NIL(graph_t)) { + return(g2); + } + + gf = g_field(g); + gf2 = ALLOC(g_field_t,1); + gf2->num_g_slots = gf->num_g_slots; + gf2->num_v_slots = gf->num_v_slots; + gf2->num_e_slots = gf->num_e_slots; + if (f_copy_g == (gGeneric (*)()) NULL) { + new = ALLOC(gGeneric,gf->num_g_slots); + for (i = gf->num_g_slots - 1; i >= 0; i--) { + new[i] = ((gGeneric *) gf->user_data)[i]; + } + gf2->user_data = (gGeneric) new; + } + else { + gf2->user_data = (*f_copy_g)(gf->user_data); + } + g2->user_data = (gGeneric) gf2; + return(g2); +} + + +void +g_set_g_slot_static(g, i, val) +graph_t *g; +int i; +gGeneric val; +{ + if (g == NIL(graph_t)) { + fail("g_set_g_slot_static: Null graph"); + } + ((gGeneric *) g_field(g)->user_data)[i] = val; + return; +} + + +gGeneric +g_get_g_slot_static(g, i) +graph_t *g; +int i; +{ + if (g == NIL(graph_t)) { + fail("g_get_g_slot_static: Null graph"); + } + return ((gGeneric *) g_field(g)->user_data)[i]; +} + +void +g_copy_g_slots_static(g1,g2,f_copy_g) +graph_t *g1, *g2; +gGeneric (*f_copy_g)(); +{ + g_field_t *gf1,*gf2; + gGeneric slots1,*slots2; + int n; + + if (g1 == NIL(graph_t) || g2 == NIL(graph_t)) { + fail("g_copy_g_slots_static: Null graph"); + } + gf1 = g_field(g1); + gf2 = g_field(g2); + n = gf1->num_g_slots; + + if (n != gf2->num_g_slots) { + fail("g_copy_g_slots_static: Graphs have different numbers of slots"); + } + slots1 = gf1->user_data; + slots2 = (gGeneric *) gf2->user_data; + if (f_copy_g == (gGeneric (*)()) NULL) { + for (n-- ; n >= 0; n--) { + slots2[n] = ((gGeneric *) slots1)[n]; + } + } + else { + FREE(slots2); + gf2->user_data = (*f_copy_g)(slots1); + } +} + + +edge_t * +g_add_edge_static(v1, v2) +vertex_t *v1, *v2; +{ + edge_t *e; + g_field_t *gf; + + if (v1 == NIL(vertex_t) || v2 == NIL(vertex_t)) { + fail("g_add_edge_static: Null vertex"); + } + e = g_add_edge(v1, v2); + gf = g_field(g_edge_graph(e)); + e->user_data = (gGeneric) ALLOC(gGeneric, gf->num_e_slots); + return(e); +} + + +void +g_delete_edge_static(e, f_free_e) +edge_t *e; +void (*f_free_e)(); +{ + if (e == NIL(edge_t)) { + fail("g_delete_edge_static: Null edge"); + } + if (f_free_e != (void (*)()) NULL) { + (*f_free_e)(e->user_data); + } + FREE(e->user_data); + g_delete_edge(e,(void (*)()) NULL); +} + + +void +g_set_e_slot_static(e, i, val) +edge_t *e; +int i; +gGeneric val; +{ + if (e == NIL(edge_t)) { + fail("g_set_e_slot_static: Null edge"); + } + ((gGeneric *) e->user_data)[i] = val; +} + + +gGeneric +g_get_e_slot_static(e, i) +edge_t *e; +int i; +{ + if (e == NIL(edge_t)) { + fail("g_get_e_slot_static: Null edge"); + } + return((gGeneric *) e->user_data)[i]; +} + +void +g_copy_e_slots_static(e1,e2,f_copy_e) +edge_t *e1, *e2; +gGeneric (*f_copy_e)(); +{ + int n; + gGeneric slots1,*slots2; + + if (e1 == NIL(edge_t) || e2 == NIL(edge_t)) { + fail("g_copy_e_slots_static: Null edge"); + } + n = g_field(g_edge_graph(e1))->num_e_slots; + + if (n != g_field(g_edge_graph(e2))->num_e_slots) { + fail("g_copy_e_slots_static: Edges have differing numbers of slots"); + } + slots1 = e1->user_data; + slots2 = (gGeneric *) e2->user_data; + if (f_copy_e == (gGeneric (*)()) NULL) { + for (n--; n >= 0; n--) { + slots2[n] = ((gGeneric *) slots1)[n]; + } + } + else { + FREE(slots2); + e2->user_data = (*f_copy_e)(slots1); + } +} + + +vertex_t * +g_add_vertex_static(g) +graph_t *g; +{ + g_field_t *gf; + vertex_t *v; + + if (g == NIL(graph_t)) { + fail("g_add_vertex_static: Null graph"); + } + gf = g_field(g); + v = g_add_vertex(g); + v->user_data = (gGeneric) ALLOC(gGeneric, gf->num_v_slots); + return(v); +} + + +void +g_delete_vertex_static(v,f_free_v,f_free_e) +vertex_t *v; +void (*f_free_v)(); +void (*f_free_e)(); +{ + edge_t *e; + lsGen gen; + + if (v == NIL(vertex_t)) { + fail("g_delete_vertex_static: Null vertex"); + } + foreach_in_edge(v, gen, e) { + if (f_free_e != (void (*)()) NULL) { + (*f_free_e)(e->user_data); + } + FREE(e->user_data); + } + foreach_out_edge(v, gen, e) { + if (f_free_e != (void (*)()) NULL) { + (*f_free_e)(e->user_data); + } + FREE(e->user_data); + } + if (f_free_v != (void (*)()) NULL) { + (*f_free_v)(v->user_data); + } + FREE(v->user_data); + g_delete_vertex(v, (void (*)()) NULL, (void (*)()) NULL); +} + + +void +g_set_v_slot_static(v, i, val) +vertex_t *v; +int i; +gGeneric val; +{ + if (v == NIL(vertex_t)) { + fail("g_set_v_slot_static: Null vertex"); + } + ((gGeneric *) v->user_data)[i] = val; +} + + +gGeneric +g_get_v_slot_static(v, i) +vertex_t *v; +int i; +{ + if (v == NIL(vertex_t)) { + fail("g_get_v_slot_static: Null vertex"); + } + return ((gGeneric *) v->user_data)[i]; +} + +void +g_copy_v_slots_static(v1,v2,f_copy_v) +vertex_t *v1, *v2; +gGeneric (*f_copy_v)(); +{ + int n; + gGeneric slots1,*slots2; + + if (v1 == NIL(vertex_t) || v2 == NIL(vertex_t)) { + fail("g_copy_v_slots_static: Null vertex"); + } + n = g_field(g_vertex_graph(v1))->num_v_slots; + + if (n != g_field(g_vertex_graph(v2))->num_v_slots) { + fail("g_copy_v_slots_static: Vertices have differing numbers of slots"); + } + slots1 = v1->user_data; + slots2 = (gGeneric *) v2->user_data; + if (f_copy_v == (gGeneric (*)()) NULL) { + for (n--; n >= 0; n--) { + slots2[n] = ((gGeneric *) slots1)[n]; + } + } + else { + FREE(slots2); + v2->user_data = (*f_copy_v)(slots1); + } +} +#endif /* SIS */ + diff --git a/sis/graph/graph_static.doc b/sis/graph/graph_static.doc new file mode 100644 index 0000000..3c3f313 --- /dev/null +++ b/sis/graph/graph_static.doc @@ -0,0 +1,187 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graph/graph_static.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:27 $ + * + */ +graph_t * +g_alloc_static(ng, nv, ne) +int ng, nv, ne; + + Allocate and return a static graph. Allocate ng slots for the graph + properties. Allow nv slots for the vertex properties, and ne slots + for the edge properties. + +void +g_free_static(g, f_free_g, f_free_v, f_free_e) +graph_t *g; +void (*f_free_g)(gGeneric); +void (*f_free_v)(gGeneric); +void (*f_free_e)(gGeneric); + + Free the storage associated with a static graph, including the + vertices, edges, and the slot pointers associated with the graph + properties. The user_data associated with the graph, each vertex, + and each edge is freed by the user-supplied functions f_free_g, + f_free_v, and f_free_e, which take as an argument the user_data + field. These functions must _not_ free the user_data field itself, + just the slots in the user_data that need to be freed. If NULL is + passed as a free function, the slots of the corresponding user_data + field are not freed. + +graph_t * +g_dup_static(g, f_copy_g, f_copy_v, f_copy_e) +graph_t *g; +gGeneric (*f_copy_g)(gGeneric); +gGeneric (*f_copy_v)(gGeneric); +gGeneric (*f_copy_e)(gGeneric); + + Return a copy of the static graph g. The graph, its vertices and + edges, and the connectivity information is copied, as well as the + number of graph, vertex, and edge slots. The user_data on the + graph, each vertex, and each edge is copied via the user-supplied + functions f_copy_g, f_copy_v, and f_copy_e, which take as an + argument the user_data field. If NULL is passed as a copy function, + the individual slots are copied with assignment statements + (new->user_data[0] = old->user_data[0], etc). If a copy function is + supplied, it must allocate a block of gGeneric large enough to hold + the slot information and copy each of the individual slots. + +void +g_set_g_slot_static(g, i, val) +graph_t *g; +int i; +gGeneric val; + + Set the ith slot in the graph g to val. + +gGeneric +g_get_g_slot_static(g, i) +graph_t *g; +int i; + + Return the value of the ith slot in the graph g. + +void +g_copy_g_slots_static(g1, g2, f_copy_g) +graph_t *g1, *g2; +gGeneric (*f_copy_g)(gGeneric); + + Copy the slots (in the user_data field) from g1 to g2. g1 and g2 + must have the same number of slots. The actual data pointed to by + the slots is copied by f_copy_g, which takes as an argument the + user_data field. If f_copy_g is specified, it must allocate a block + of gGeneric large enough to hold the slot information and copy each + of the individual slots. If f_copy_g is NULL, the individual slots + are copied with assignment statements (new->user_data[0] = + old->user_data[0], etc). + +/* vertices */ + +vertex_t * +g_add_vertex_static(g) +graph_t *g; + + Add a new vertex to the graph g, and return the new vertex. + +void +g_delete_vertex_static(v, f_free_v, f_free_e) +vertex_t *v; +void (*f_free_v)(gGeneric); +void (*f_free_e)(gGeneric); + + Free the storage associated with a vertex, including the vertex + itself and its edges. Free the storage associated with the vertex + slot pointers. The user_data associated with the vertex and each of + its edges is freed by the user-supplied functions f_free_v and + f_free_e, which take as an argument the user_data field. These + functions should not free the user_data field itself, just the slots + in the user_data that need to be freed. If NULL is passed as a free + function, the slots of the corresponding user_data field are not + freed. + +void +g_set_v_slot_static(v, i, val) +vertex_t *v; +int i; +gGeneric val; + + Set the ith slot of vertex v to val. + +gGeneric +g_get_v_slot_static(v, i) +vertex_t *v; +int i; + + Return the value of the ith slot of vertex v. + +void +g_copy_v_slots_static(v1, v2, f_copy_v) +vertex_t *v1, *v2; +gGeneric (*f_copy_v)(gGeneric); + + Copy the slots (in the user_data field) from v1 to v2. v1 and v2 + must have the same number of slots. The actual data pointed to by + the slots is copied by f_copy_v, which takes as an argument the + user_data field. If f_copy_v is specified, it must allocate a block + of gGeneric large enough to hold the slot information and copy each + of the individual slots. If f_copy_v is NULL, then the individual + slots are copied with assignment statements (new->user_data[0] = + old->user_data[0], etc). + +/* edges */ + +edge_t * +g_add_edge_static(v1, v2) +vertex_t *v1, *v2; + + Add a directed edge from v1 to v2. The new edge is returned. v1 + and v2 must belong to the same graph. + +void +g_delete_edge_static(e, f_free_e) +edge_t *e; +void (*f_free_e)(gGeneric); + + Free the storage associated with an edge, including the edge itself + and the storage associated with its slot pointers. The user_data is + freed by the user-supplied function f_free_e, which takes as an + argument the user_data field. f_free_e does not free the user_data + field itself, but only the slots in the user_data field that need to + be freed. If f_free_e is NULL the slots of the user_data field are + not freed. + +void +g_set_e_slot_static(e, i, val) +edge_t *e; +int i; +gGeneric val; + + Set the ith slot of edge e to val. + +gGeneric +g_get_e_slot_static(e, i) +vertex_t *e; +int i; + + Return the value of the ith slot of edge e. + +void +g_copy_e_slots_static(e1, e2, f_copy_e) +edge_t *e1, *e2; +gGeneric (*f_copy_e)(gGeneric); + + Copy the slots (in the user_data_field) from e1 to e2. e1 and e2 + must have the same number of slots. The actual data pointed to by + the slots is copied by f_copy_e, which takes as an argument the + user_data field. If f_copy_e is specified, it must allocate a block + of gGeneric large enough to hold the slot information and copy each + of the individual slots to the new location. If f_copy_e is NULL, + the individual slots are copied with assignment statements + (new->user_data[0] = old->user_data[0], etc). + +------------------------------------------------------- +For a description of files and installation instructions, see graph.doc. diff --git a/sis/graph/graph_static.h b/sis/graph/graph_static.h new file mode 100644 index 0000000..470c2d3 --- /dev/null +++ b/sis/graph/graph_static.h @@ -0,0 +1,27 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graph/graph_static.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:27 $ + * + */ +/******************************* graph_static.h ************************/ + +EXTERN graph_t *g_alloc_static ARGS((int, int, int)); +EXTERN void g_free_static ARGS((graph_t *, void (*)(), void (*)(), void (*)())); +EXTERN graph_t *g_dup_static ARGS((graph_t *, char *(*)(), char *(*)(), char *(*)())); +EXTERN void g_set_g_slot_static ARGS((graph_t *, int, char *)); +EXTERN char *g_get_g_slot_static ARGS((graph_t *, int)); +EXTERN void g_copy_g_slots_static ARGS((graph_t *, graph_t *, char *(*)())); +EXTERN vertex_t *g_add_vertex_static ARGS((graph_t *)); +EXTERN void g_delete_vertex_static ARGS((vertex_t *, void (*)(), void (*)())); +EXTERN void g_set_v_slot_static ARGS((vertex_t *, int, char *)); +EXTERN char *g_get_v_slot_static ARGS((vertex_t *, int)); +EXTERN void g_copy_v_slots_static ARGS((vertex_t *, vertex_t *, char *(*)())); +EXTERN edge_t *g_add_edge_static ARGS((vertex_t *, vertex_t *)); +EXTERN void g_delete_edge_static ARGS((edge_t *, void (*)())); +EXTERN void g_set_e_slot_static ARGS((edge_t *, int, char *)); +EXTERN char *g_get_e_slot_static ARGS((edge_t *, int)); +EXTERN void g_copy_e_slots_static ARGS((edge_t *, edge_t *, char *(*)())); diff --git a/sis/graph/graph_static_int.h b/sis/graph/graph_static_int.h new file mode 100644 index 0000000..c00188f --- /dev/null +++ b/sis/graph/graph_static_int.h @@ -0,0 +1,17 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graph/graph_static_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:27 $ + * + */ +/******************************** graph_static_int.h ********************/ + +typedef struct g_field_struct { + int num_g_slots; + int num_v_slots; + int num_e_slots; + gGeneric user_data; +} g_field_t; diff --git a/sis/graphics/Makefile.am b/sis/graphics/Makefile.am new file mode 100644 index 0000000..cc263be --- /dev/null +++ b/sis/graphics/Makefile.am @@ -0,0 +1,7 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libgraphics.a +libgraphics_a_SOURCES = com_graphics.c +pkginclude_HEADERS = graphics.h +dist_doc_DATA = graphics.doc diff --git a/sis/graphics/Makefile.in b/sis/graphics/Makefile.in new file mode 100644 index 0000000..fa5525e --- /dev/null +++ b/sis/graphics/Makefile.in @@ -0,0 +1,418 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libgraphics_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/graphics +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libgraphics_a_AR = $(AR) $(ARFLAGS) +libgraphics_a_LIBADD = +am_libgraphics_a_OBJECTS = com_graphics.$(OBJEXT) +libgraphics_a_OBJECTS = $(am_libgraphics_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libgraphics_a_SOURCES) +DIST_SOURCES = $(libgraphics_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libgraphics.a +libgraphics_a_SOURCES = com_graphics.c +pkginclude_HEADERS = graphics.h +dist_doc_DATA = graphics.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/graphics/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/graphics/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libgraphics.a: $(libgraphics_a_OBJECTS) $(libgraphics_a_DEPENDENCIES) + -rm -f libgraphics.a + $(libgraphics_a_AR) libgraphics.a $(libgraphics_a_OBJECTS) $(libgraphics_a_LIBADD) + $(RANLIB) libgraphics.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/graphics/com_graphics.c b/sis/graphics/com_graphics.c new file mode 100644 index 0000000..a17f666 --- /dev/null +++ b/sis/graphics/com_graphics.c @@ -0,0 +1,26 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graphics/com_graphics.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/02/09 07:35:29 $ + * + */ +/* com_graphics.c -- sis general graphics commands. + + Currently there are no general purpose graphics commands. File graphics.doc + describes how sis interacts with a graphical front end. The interface is + based on the existing tty command-line interface so that either interface + can be used without recompiling sis. + */ + +#include "sis.h" + +void init_graphics (void) +{ +} + +void end_graphics (void) +{ +} diff --git a/sis/graphics/graphics.doc b/sis/graphics/graphics.doc new file mode 100644 index 0000000..33a3126 --- /dev/null +++ b/sis/graphics/graphics.doc @@ -0,0 +1,249 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graphics/graphics.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:27 $ + * + */ + +graphics.doc -- SIS graphical front-end interface specification. + +OVERVIEW + + A graphical interface to SIS is based on implementing the graphical front + end as a separate program which runs SIS as a child process and interfaces + with SIS using the existing command-line interface. The SIS child process + is started with the -X option to enable the SIS graphics commands. + + Advantages: + + * No X11 code needs to be linked with SIS. + * The interface is responsive even when SIS is doing a long computation. + * Any copy of SIS can be run either using the regular TTY command line + (especially for debugging) and then can be run under a graphical + interface for demos without recompiling. + * Multiple graphical interfaces (using different toolkits for example) + can be developed without affecting SIS. + * Portability problems associated with the graphical interface are + eliminated from SIS itself. + + Disadvantages: + + * Adding a new interface feature often requires modifying two programs. + * The graphics interface adds a few portability problems of its own + such as the use of ptys. + + The program XSIS is such a graphical interface using the Athena Widget set + of the MIT X11R4 release. Some of the features of XSIS are described here + because they are relevant to any other graphical front-end which might be + developed (using another toolkit for example). The remainder of this + document will use XSIS, but applies equally to any other interface. + +GRAPHICS COMMANDS + + Graphics commands are sent to XSIS as ordinary text. They are interpreted + by XSIS instead of being displayed to the user. Commands have four parts: + + The type of window the command is being sent to. + + What command to send to the window, e.g. close, highlight. + + The title of the window, since there may be more than one + of the same type. + + <data> Arbitrary command-specific data. The amount of data can + be quite large such as the complete description of a + network, or very small such as what help topic to display. + To simplify parsing, single tab characters should be used to + separate tokens in the graphics data, and the data should be + line oriented. + + The end of this document describes the defined types and commands. + The titles for most windows are arbitrary. For example, the title used + for blif windows is the network name. Titles may not have newline + characters in them. The single sis entity always has title "sis". + + XSIS silently ignores any graphics commands that it does not recognize. + This makes it possible to run older versions of XSIS with new versions + of SIS. Thus new commands can be added to either XSIS or SIS first without + "breaking" the software. If XSIS is run with the -debug option, then it + will print warnings to stdout for any ignored commands (as well as a lot + of other diagnostic information). + +SIS GRAPHICS SUPPORT + + To enable graphics features in SIS, run it with the -X flag (this is + normally only done by a graphical interface): + + sis -X <fileno> + + The command package in SIS uses the argument <fileno> to select which + stream to use for sending graphics commands. Value 1 is stdout, 2 is + stderr, and 0 means disable graphics (the default if -X is not used). + When graphics is disabled, SIS will not generate any special graphics + commands. For debugging purposes, you can specify the -X option directly + to see the raw output from SIS in graphics mode. + + The command package provides four basic functions for handling graphics in + SIS: + + int com_graphics_enabled (); + + Returns 1 if graphics is enabled. Other packages can use this to + optionally add special graphics commands. See the io package + command plot_blif for example. + + FILE *com_graphics_open (type,title,command) + char *type; + char *title; + char *command; + + Start a graphics command. Any command-specific data should be + written to the file stream which is returned, using ordinary + stdio calls. Remember to separate tokens with tabs. + + void com_graphics_close (stream) + FILE *stream; + + Finish a graphics command. Calls to graphics_open/close cannot + be nested, and an assertion will fail if a second open is tried + without an intervening close. The stream must be the one returned + by com_graphics_open. + + void com_graphics_exec (type,title,command,data) + char *type; + char *title; + char *command; + char *data; + + Convenience function for graphics commands which have very simple + data. This is equivalent to a graphics_open/fprintf/graphics_close + sequence. + +COMMAND FORMAT + + Normally you do not need to know the detailed format of a graphics command + header since the SIS command package handles this for you. + + Each graphics command starts with a special header line, followed by + one line containing the type, command, and title for the graphics command. + Next any command-specific data is written, followed finally by a special + trailer line. For example, the graphics command to open the xsis cmd + window looks like: + + ^G#GRAPHICS_START# + cmd new cmd + .version U.C. Berkeley SIS 1.1 + ^G#GRAPHICS_END# + + The header and trailer are generated by the com_graphics_open/_close + calls. Remember that all tokens are separated by tabs to avoid problems + with embedded spaces. The ^G is added to help make the graphics header + and trailer distinct from normal SIS output. + +ADDING NEW COMMANDS + + Adding a new graphics command for SIS to send to XSIS requires the + following steps: + + 1) If a new window type is being created, assign it a type name and add + it to the list below. + + 2) For each command, define the data associated with the command and + enter its description below. + + 3) Add code to SIS to issue the new graphics command, using the command + package functions described above. + + 4) Modify the graphical interface XSIS to read the new command and + execute the new command. This step is usually most of the work. + + Adding a new command for XSIS to send to SIS is done the same way as adding + any other command to SIS. However, if the command is only for graphics + use, then in SIS initialization you should test com_graphics_enabled() to + decide if the command will be added (using com_add_command). This way + when SIS is run in normal tty mode, the useless graphics commands are not + even available. + +TESTING NEW COMMANDS + + Since graphics commands are just embedded in the regular SIS output, it is + easy to test new graphics commands even before SIS has been modified. + Put the complete graphics commands in a file, including the graphics header + and trailer (see above). Then start XSIS and use "!cat <filename>". XSIS + will see the graphics header and will automatically try to interpret the + following text as a graphics command. This can be used to develop and test + a new graphics command before changing SIS. + +SIS WINDOW TYPES + + The following are the defined types for SIS graphics commands: + + sis This entity manages the communication between XSIS and SIS, and + the creation of new windows. Normally this entity does not have + a window associated with it, but you can still sent it commands. + It has a role similar to the command package in SIS. + + cmd This window handles the command line for input, and a text display + for SIS non-graphical output. SIS automatically opens one of these + when graphics mode is enabled. + + help A help window displays a SIS formatted help file. + + blif Used to display a graphical representation of a SIS network, in + the format of the old SIS "plot" command. + + The rest of this file informally describes the commands for each window. + Remember tokens are separated with tabs, although they are shown as + a single space here for legibility. + +SIS WINDOW COMMANDS + + set + <flag> <value> + + unset + <flag> + + commands + <sis-cmd1> + <sis-cmd2> + ... + +COMMAND WINDOW COMMANDS + + new + .version <sis-version> + + close + +BLIF WINDOW COMMANDS + + new + .geometry <X-geometry> + .inputs <node1> <node2> ... + .outputs <node1> <node2> ... + .node <name> <in1> <in2> ... + .label <name> <label> + + replace + (same as new) + + highlight + .clear <label> + .on + .off + .nodes <node1> <node2> ... + .command <group> <sis-command> <label> <help-text> + + close + +HELP WINDOW COMMANDS + + new + .geometry <X-geometry> + .topic <sis-command> + + close diff --git a/sis/graphics/graphics.h b/sis/graphics/graphics.h new file mode 100644 index 0000000..1ab3fb7 --- /dev/null +++ b/sis/graphics/graphics.h @@ -0,0 +1,16 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/graphics/graphics.h,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/02/09 07:35:29 $ + * + */ +#ifndef GRAPHICS_H +#define GRAPHICS_H + +extern void init_graphics (void); +extern void end_graphics (void); + +#endif diff --git a/sis/include/Makefile.am b/sis/include/Makefile.am new file mode 100644 index 0000000..da48724 --- /dev/null +++ b/sis/include/Makefile.am @@ -0,0 +1,238 @@ +BUILT_SOURCES = array.h astg.h atpg.h sat.h avl.h bdd.h clock.h command.h \ + decomp.h delay.h enc.h error.h espresso.h extract.h factor.h gcd.h \ + graph.h graph_static.h graphics.h io.h latch.h library.h spMatrix.h \ + spConfig.h list.h lsort.h luniq.h map.h maxflow.h mincov.h minimize.h \ + network.h node.h nodeindex.h ntbdd.h order.h phase.h pld.h \ + power.h resub.h retime.h seqbdd.h simplify.h sis.h sparse.h speed.h \ + st.h stg.h util.h ansi.h var_set.h + +install: $(BUILT_SOURCES) +CLEANFILES = $(BUILT_SOURCES) + +if SIS_COND_CMUBDD +bdd.h: $(top_srcdir)/sis/bdd_cmu/bdd.h + $(RM) $@ + $(LN_S) $< $@ +endif + +if SIS_COND_UCBBDD +bdd.h: $(top_srcdir)/sis/bdd_ucb/bdd.h + $(RM) $@ + $(LN_S) $< $@ +endif + +if SIS_COND_CUDD +bdd.h: ../bdd_cudd/bdd.h + $(RM) $@ + $(LN_S) $< $@ + +../bdd_cudd/bdd.h: + cd ../bdd_cudd && $(MAKE) bdd.h + +st.h: ../bdd_cudd/st.h + $(RM) $@ + $(LN_S) $< $@ + +../bdd_cudd/st.h: + cd ../bdd_cudd && $(MAKE) st.h +else +st.h: $(top_srcdir)/sis/st/st.h + $(RM) $@ + $(LN_S) $< $@ +endif + +array.h: $(top_srcdir)/sis/array/array.h + $(RM) $@ + $(LN_S) $< $@ + +astg.h: $(top_srcdir)/sis/astg/astg.h + $(RM) $@ + $(LN_S) $< $@ + +atpg.h: $(top_srcdir)/sis/atpg/atpg.h + $(RM) $@ + $(LN_S) $< $@ + +sat.h: $(top_srcdir)/sis/atpg/sat.h + $(RM) $@ + $(LN_S) $< $@ + +avl.h: $(top_srcdir)/sis/avl/avl.h + $(RM) $@ + $(LN_S) $< $@ + +clock.h: $(top_srcdir)/sis/clock/clock.h + $(RM) $@ + $(LN_S) $< $@ + +command.h: $(top_srcdir)/sis/command/command.h + $(RM) $@ + $(LN_S) $< $@ + +decomp.h: $(top_srcdir)/sis/decomp/decomp.h + $(RM) $@ + $(LN_S) $< $@ + +delay.h: $(top_srcdir)/sis/delay/delay.h + $(RM) $@ + $(LN_S) $< $@ + +enc.h: $(top_srcdir)/sis/enc/enc.h + $(RM) $@ + $(LN_S) $< $@ + +error.h: $(top_srcdir)/sis/error/error.h + $(RM) $@ + $(LN_S) $< $@ + +espresso.h: $(top_srcdir)/sis/espresso/espresso.h + $(RM) $@ + $(LN_S) $< $@ + +extract.h: $(top_srcdir)/sis/extract/extract.h + $(RM) $@ + $(LN_S) $< $@ + +factor.h: $(top_srcdir)/sis/factor/factor.h + $(RM) $@ + $(LN_S) $< $@ + +gcd.h: $(top_srcdir)/sis/gcd/gcd.h + $(RM) $@ + $(LN_S) $< $@ + +graph.h: $(top_srcdir)/sis/graph/graph.h + $(RM) $@ + $(LN_S) $< $@ + +graph_static.h: $(top_srcdir)/sis/graph/graph_static.h + $(RM) $@ + $(LN_S) $< $@ + +graphics.h: $(top_srcdir)/sis/graphics/graphics.h + $(RM) $@ + $(LN_S) $< $@ + +io.h: $(top_srcdir)/sis/io/io.h + $(RM) $@ + $(LN_S) $< $@ + +latch.h: $(top_srcdir)/sis/latch/latch.h + $(RM) $@ + $(LN_S) $< $@ + +spMatrix.h: $(top_srcdir)/sis/linsolv/spMatrix.h + $(RM) $@ + $(LN_S) $< $@ + +spConfig.h: $(top_srcdir)/sis/linsolv/spConfig.h + $(RM) $@ + $(LN_S) $< $@ + +list.h: $(top_srcdir)/sis/list/list.h + $(RM) $@ + $(LN_S) $< $@ + +lsort.h: $(top_srcdir)/sis/lsort/lsort.h + $(RM) $@ + $(LN_S) $< $@ + +luniq.h: $(top_srcdir)/sis/lsort/luniq.h + $(RM) $@ + $(LN_S) $< $@ + +library.h: $(top_srcdir)/sis/map/library.h + $(RM) $@ + $(LN_S) $< $@ + +map.h: $(top_srcdir)/sis/map/map.h + $(RM) $@ + $(LN_S) $< $@ + +maxflow.h: $(top_srcdir)/sis/maxflow/maxflow.h + $(RM) $@ + $(LN_S) $< $@ + +mincov.h: $(top_srcdir)/sis/mincov/mincov.h + $(RM) $@ + $(LN_S) $< $@ + +minimize.h: $(top_srcdir)/sis/minimize/minimize.h + $(RM) $@ + $(LN_S) $< $@ + +network.h: $(top_srcdir)/sis/network/network.h + $(RM) $@ + $(LN_S) $< $@ + +node.h: $(top_srcdir)/sis/node/node.h + $(RM) $@ + $(LN_S) $< $@ + +nodeindex.h: $(top_srcdir)/sis/node/nodeindex.h + $(RM) $@ + $(LN_S) $< $@ + +ntbdd.h: $(top_srcdir)/sis/ntbdd/ntbdd.h + $(RM) $@ + $(LN_S) $< $@ + +order.h: $(top_srcdir)/sis/order/order.h + $(RM) $@ + $(LN_S) $< $@ + +phase.h: $(top_srcdir)/sis/phase/phase.h + $(RM) $@ + $(LN_S) $< $@ + +pld.h: $(top_srcdir)/sis/pld/pld.h + $(RM) $@ + $(LN_S) $< $@ + +power.h: $(top_srcdir)/sis/power/power.h + $(RM) $@ + $(LN_S) $< $@ + +resub.h: $(top_srcdir)/sis/resub/resub.h + $(RM) $@ + $(LN_S) $< $@ + +retime.h: $(top_srcdir)/sis/retime/retime.h + $(RM) $@ + $(LN_S) $< $@ + +seqbdd.h: $(top_srcdir)/sis/seqbdd/seqbdd.h + $(RM) $@ + $(LN_S) $< $@ + +simplify.h: $(top_srcdir)/sis/simplify/simplify.h + $(RM) $@ + $(LN_S) $< $@ + +sis.h: $(top_srcdir)/sis/main/sis.h + $(RM) $@ + $(LN_S) $< $@ + +sparse.h: $(top_srcdir)/sis/sparse/sparse.h + $(RM) $@ + $(LN_S) $< $@ + +speed.h: $(top_srcdir)/sis/speed/speed.h + $(RM) $@ + $(LN_S) $< $@ + +stg.h: $(top_srcdir)/sis/stg/stg.h + $(RM) $@ + $(LN_S) $< $@ + +ansi.h: $(top_srcdir)/sis/util/ansi.h + $(RM) $@ + $(LN_S) $< $@ + +util.h: $(top_srcdir)/sis/util/util.h + $(RM) $@ + $(LN_S) $< $@ + +var_set.h: $(top_srcdir)/sis/var_set/var_set.h + $(RM) $@ + $(LN_S) $< $@ diff --git a/sis/include/Makefile.in b/sis/include/Makefile.in new file mode 100644 index 0000000..c3ae964 --- /dev/null +++ b/sis/include/Makefile.in @@ -0,0 +1,519 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/include +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +BUILT_SOURCES = array.h astg.h atpg.h sat.h avl.h bdd.h clock.h command.h \ + decomp.h delay.h enc.h error.h espresso.h extract.h factor.h gcd.h \ + graph.h graph_static.h graphics.h io.h latch.h library.h spMatrix.h \ + spConfig.h list.h lsort.h luniq.h map.h maxflow.h mincov.h minimize.h \ + network.h node.h nodeindex.h ntbdd.h order.h phase.h pld.h \ + power.h resub.h retime.h seqbdd.h simplify.h sis.h sparse.h speed.h \ + st.h stg.h util.h ansi.h var_set.h + +CLEANFILES = $(BUILT_SOURCES) +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/include/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/include/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile +installdirs: +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-info-am + + +install: $(BUILT_SOURCES) + +@SIS_COND_CMUBDD_TRUE@bdd.h: $(top_srcdir)/sis/bdd_cmu/bdd.h +@SIS_COND_CMUBDD_TRUE@ $(RM) $@ +@SIS_COND_CMUBDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_UCBBDD_TRUE@bdd.h: $(top_srcdir)/sis/bdd_ucb/bdd.h +@SIS_COND_UCBBDD_TRUE@ $(RM) $@ +@SIS_COND_UCBBDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@bdd.h: ../bdd_cudd/bdd.h +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@../bdd_cudd/bdd.h: +@SIS_COND_CUDD_TRUE@ cd ../bdd_cudd && $(MAKE) bdd.h + +@SIS_COND_CUDD_TRUE@st.h: ../bdd_cudd/st.h +@SIS_COND_CUDD_TRUE@ $(RM) $@ +@SIS_COND_CUDD_TRUE@ $(LN_S) $< $@ + +@SIS_COND_CUDD_TRUE@../bdd_cudd/st.h: +@SIS_COND_CUDD_TRUE@ cd ../bdd_cudd && $(MAKE) st.h +@SIS_COND_CUDD_FALSE@st.h: $(top_srcdir)/sis/st/st.h +@SIS_COND_CUDD_FALSE@ $(RM) $@ +@SIS_COND_CUDD_FALSE@ $(LN_S) $< $@ + +array.h: $(top_srcdir)/sis/array/array.h + $(RM) $@ + $(LN_S) $< $@ + +astg.h: $(top_srcdir)/sis/astg/astg.h + $(RM) $@ + $(LN_S) $< $@ + +atpg.h: $(top_srcdir)/sis/atpg/atpg.h + $(RM) $@ + $(LN_S) $< $@ + +sat.h: $(top_srcdir)/sis/atpg/sat.h + $(RM) $@ + $(LN_S) $< $@ + +avl.h: $(top_srcdir)/sis/avl/avl.h + $(RM) $@ + $(LN_S) $< $@ + +clock.h: $(top_srcdir)/sis/clock/clock.h + $(RM) $@ + $(LN_S) $< $@ + +command.h: $(top_srcdir)/sis/command/command.h + $(RM) $@ + $(LN_S) $< $@ + +decomp.h: $(top_srcdir)/sis/decomp/decomp.h + $(RM) $@ + $(LN_S) $< $@ + +delay.h: $(top_srcdir)/sis/delay/delay.h + $(RM) $@ + $(LN_S) $< $@ + +enc.h: $(top_srcdir)/sis/enc/enc.h + $(RM) $@ + $(LN_S) $< $@ + +error.h: $(top_srcdir)/sis/error/error.h + $(RM) $@ + $(LN_S) $< $@ + +espresso.h: $(top_srcdir)/sis/espresso/espresso.h + $(RM) $@ + $(LN_S) $< $@ + +extract.h: $(top_srcdir)/sis/extract/extract.h + $(RM) $@ + $(LN_S) $< $@ + +factor.h: $(top_srcdir)/sis/factor/factor.h + $(RM) $@ + $(LN_S) $< $@ + +gcd.h: $(top_srcdir)/sis/gcd/gcd.h + $(RM) $@ + $(LN_S) $< $@ + +graph.h: $(top_srcdir)/sis/graph/graph.h + $(RM) $@ + $(LN_S) $< $@ + +graph_static.h: $(top_srcdir)/sis/graph/graph_static.h + $(RM) $@ + $(LN_S) $< $@ + +graphics.h: $(top_srcdir)/sis/graphics/graphics.h + $(RM) $@ + $(LN_S) $< $@ + +io.h: $(top_srcdir)/sis/io/io.h + $(RM) $@ + $(LN_S) $< $@ + +latch.h: $(top_srcdir)/sis/latch/latch.h + $(RM) $@ + $(LN_S) $< $@ + +spMatrix.h: $(top_srcdir)/sis/linsolv/spMatrix.h + $(RM) $@ + $(LN_S) $< $@ + +spConfig.h: $(top_srcdir)/sis/linsolv/spConfig.h + $(RM) $@ + $(LN_S) $< $@ + +list.h: $(top_srcdir)/sis/list/list.h + $(RM) $@ + $(LN_S) $< $@ + +lsort.h: $(top_srcdir)/sis/lsort/lsort.h + $(RM) $@ + $(LN_S) $< $@ + +luniq.h: $(top_srcdir)/sis/lsort/luniq.h + $(RM) $@ + $(LN_S) $< $@ + +library.h: $(top_srcdir)/sis/map/library.h + $(RM) $@ + $(LN_S) $< $@ + +map.h: $(top_srcdir)/sis/map/map.h + $(RM) $@ + $(LN_S) $< $@ + +maxflow.h: $(top_srcdir)/sis/maxflow/maxflow.h + $(RM) $@ + $(LN_S) $< $@ + +mincov.h: $(top_srcdir)/sis/mincov/mincov.h + $(RM) $@ + $(LN_S) $< $@ + +minimize.h: $(top_srcdir)/sis/minimize/minimize.h + $(RM) $@ + $(LN_S) $< $@ + +network.h: $(top_srcdir)/sis/network/network.h + $(RM) $@ + $(LN_S) $< $@ + +node.h: $(top_srcdir)/sis/node/node.h + $(RM) $@ + $(LN_S) $< $@ + +nodeindex.h: $(top_srcdir)/sis/node/nodeindex.h + $(RM) $@ + $(LN_S) $< $@ + +ntbdd.h: $(top_srcdir)/sis/ntbdd/ntbdd.h + $(RM) $@ + $(LN_S) $< $@ + +order.h: $(top_srcdir)/sis/order/order.h + $(RM) $@ + $(LN_S) $< $@ + +phase.h: $(top_srcdir)/sis/phase/phase.h + $(RM) $@ + $(LN_S) $< $@ + +pld.h: $(top_srcdir)/sis/pld/pld.h + $(RM) $@ + $(LN_S) $< $@ + +power.h: $(top_srcdir)/sis/power/power.h + $(RM) $@ + $(LN_S) $< $@ + +resub.h: $(top_srcdir)/sis/resub/resub.h + $(RM) $@ + $(LN_S) $< $@ + +retime.h: $(top_srcdir)/sis/retime/retime.h + $(RM) $@ + $(LN_S) $< $@ + +seqbdd.h: $(top_srcdir)/sis/seqbdd/seqbdd.h + $(RM) $@ + $(LN_S) $< $@ + +simplify.h: $(top_srcdir)/sis/simplify/simplify.h + $(RM) $@ + $(LN_S) $< $@ + +sis.h: $(top_srcdir)/sis/main/sis.h + $(RM) $@ + $(LN_S) $< $@ + +sparse.h: $(top_srcdir)/sis/sparse/sparse.h + $(RM) $@ + $(LN_S) $< $@ + +speed.h: $(top_srcdir)/sis/speed/speed.h + $(RM) $@ + $(LN_S) $< $@ + +stg.h: $(top_srcdir)/sis/stg/stg.h + $(RM) $@ + $(LN_S) $< $@ + +ansi.h: $(top_srcdir)/sis/util/ansi.h + $(RM) $@ + $(LN_S) $< $@ + +util.h: $(top_srcdir)/sis/util/util.h + $(RM) $@ + $(LN_S) $< $@ + +var_set.h: $(top_srcdir)/sis/var_set/var_set.h + $(RM) $@ + $(LN_S) $< $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/io/Makefile.am b/sis/io/Makefile.am new file mode 100644 index 0000000..52dabc6 --- /dev/null +++ b/sis/io/Makefile.am @@ -0,0 +1,25 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +AM_YFLAGS = -d + +BUILT_SOURCES = read_eqn.c read_eqn.h eqnlex.c +CLEANFILES = $(BUILT_SOURCES) + +noinst_LIBRARIES = libio.a +libio_a_SOURCES = com_io.c plot_blif.c read_blif.c read_kiss.c read_pla.c \ + read_slif.c read_util.c write_bdnet.c write_blif.c write_eqn.c \ + write_kiss.c write_pla.c write_slif.c write_util.c io_int.h \ + read_eqn.y eqnlex.l +pkginclude_HEADERS = io.h +dist_doc_DATA = io.doc + +read_eqn.h: read_eqn.c +read_eqn.c read_eqn.h: read_eqn.y + $(YACC) $(YFLAGS) $(AM_YFLAGS) $< + sed 's/yy/EQN_yy/g' y.tab.c > read_eqn.c + sed 's/yy/EQN_yy/g' y.tab.h > read_eqn.h + $(RM) y.tab.c y.tab.h +eqnlex.c: eqnlex.l read_eqn.h + $(LEX) $(LFLAGS) $(AM_LFLAGS) $< + sed 's/yy/EQN_yy/g' lex.yy.c > eqnlex.c + $(RM) lex.yy.c diff --git a/sis/io/Makefile.in b/sis/io/Makefile.in new file mode 100644 index 0000000..0b4dcc9 --- /dev/null +++ b/sis/io/Makefile.in @@ -0,0 +1,477 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libio_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/io +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in eqnlex.c \ + read_eqn.c read_eqn.h +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libio_a_AR = $(AR) $(ARFLAGS) +libio_a_LIBADD = +am_libio_a_OBJECTS = com_io.$(OBJEXT) plot_blif.$(OBJEXT) \ + read_blif.$(OBJEXT) read_kiss.$(OBJEXT) read_pla.$(OBJEXT) \ + read_slif.$(OBJEXT) read_util.$(OBJEXT) write_bdnet.$(OBJEXT) \ + write_blif.$(OBJEXT) write_eqn.$(OBJEXT) write_kiss.$(OBJEXT) \ + write_pla.$(OBJEXT) write_slif.$(OBJEXT) write_util.$(OBJEXT) \ + read_eqn.$(OBJEXT) eqnlex.$(OBJEXT) +libio_a_OBJECTS = $(am_libio_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) +YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) +SOURCES = $(libio_a_SOURCES) +DIST_SOURCES = $(libio_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +AM_YFLAGS = -d +BUILT_SOURCES = read_eqn.c read_eqn.h eqnlex.c +CLEANFILES = $(BUILT_SOURCES) +noinst_LIBRARIES = libio.a +libio_a_SOURCES = com_io.c plot_blif.c read_blif.c read_kiss.c read_pla.c \ + read_slif.c read_util.c write_bdnet.c write_blif.c write_eqn.c \ + write_kiss.c write_pla.c write_slif.c write_util.c io_int.h \ + read_eqn.y eqnlex.l + +pkginclude_HEADERS = io.h +dist_doc_DATA = io.doc +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .l .o .obj .y +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/io/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/io/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libio.a: $(libio_a_OBJECTS) $(libio_a_DEPENDENCIES) + -rm -f libio.a + $(libio_a_AR) libio.a $(libio_a_OBJECTS) $(libio_a_LIBADD) + $(RANLIB) libio.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.l.c: + $(LEXCOMPILE) $< + sed '/^#/ s|$(LEX_OUTPUT_ROOT)\.c|$@|' $(LEX_OUTPUT_ROOT).c >$@ + rm -f $(LEX_OUTPUT_ROOT).c + +.y.c: + $(YACCCOMPILE) $< + if test -f y.tab.h; then \ + to=`echo "$*_H" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`; \ + sed "/^#/ s/Y_TAB_H/$$to/g" y.tab.h >$*.ht; \ + rm -f y.tab.h; \ + if cmp -s $*.ht $*.h; then \ + rm -f $*.ht ;\ + else \ + mv $*.ht $*.h; \ + fi; \ + fi + if test -f y.output; then \ + mv y.output $*.output; \ + fi + sed '/^#/ s|y\.tab\.c|$@|' y.tab.c >$@t && mv $@t $@ + rm -f y.tab.c +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f eqnlex.c + -rm -f read_eqn.h + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -rm -f read_eqn.c +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + + +read_eqn.h: read_eqn.c +read_eqn.c read_eqn.h: read_eqn.y + $(YACC) $(YFLAGS) $(AM_YFLAGS) $< + sed 's/yy/EQN_yy/g' y.tab.c > read_eqn.c + sed 's/yy/EQN_yy/g' y.tab.h > read_eqn.h + $(RM) y.tab.c y.tab.h +eqnlex.c: eqnlex.l read_eqn.h + $(LEX) $(LFLAGS) $(AM_LFLAGS) $< + sed 's/yy/EQN_yy/g' lex.yy.c > eqnlex.c + $(RM) lex.yy.c +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/io/com_io.c b/sis/io/com_io.c new file mode 100644 index 0000000..1b732ed --- /dev/null +++ b/sis/io/com_io.c @@ -0,0 +1,1168 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/com_io.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * + */ +#include "sis.h" +#include "io_int.h" + +static int +com_read(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i, c, append, single_output, status; + char *fname, *error, *real_filename; + network_t *new_network; + FILE *fp; +#ifdef SIS + graph_t *stg; +#endif /* SIS */ + + append = 0; + single_output = 1; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "acs")) != EOF) { + switch(c) { + case 'a': + append = 1; + break; + case 's': + single_output = 1; + break; + case 'c': + single_output = 0; + break; + default: + goto usage; + } + } + + if (argc - util_optind == 0) { + fname = "-"; + } + else if (argc - util_optind == 1) { + fname = argv[util_optind]; + } + else { + goto usage; + } + + fp = com_open_file(fname, "r", &real_filename, /* silent */ 0); + if (fp == NIL(FILE)) { + FREE(real_filename); + return 1; + } + + error_init(); + read_register_filename(real_filename); + new_network = 0; + + if (strcmp(argv[0], "read_blif") == 0) { + read_lineno = 0; + i = read_blif(fp, &new_network); + if (i == EOF) { + (void) fprintf(siserr, "read_blif: no network found\n"); + new_network = NIL(network_t); + } + else if (i != 1) { + new_network = NIL(network_t); + } + + } +#ifdef SIS + else if (strcmp(argv[0], "read_slif") == 0) { + new_network = read_slif(fp); + } +#endif /* SIS */ + else if (strcmp(argv[0], "read_eqn") == 0) { + new_network = read_eqn(fp); + } + else if (strcmp(argv[0], "read_pla") == 0) { + new_network = sis_read_pla(fp, single_output); + if (new_network == NIL(network_t)) { + (void) fprintf(siserr, "read_pla: error reading PLA\n"); + } + } +#ifdef SIS + else if (strcmp(argv[0],"read_kiss") == 0) { + read_lineno = 0; + if (!read_kiss(fp, &stg)) { + (void) fprintf(siserr,"read_kiss: error reading\n"); + new_network = NIL(network_t); + } + else if (stg != NIL(graph_t)) { + new_network = network_alloc(); + read_filename_to_netname(new_network, read_filename); + network_set_stg(new_network,stg); + } + } +#endif /* SIS */ + else { + fail("com_read: called with bad argv[0]"); + } + + error = error_string(); + if (error[0] != '\0') { + (void) fprintf(siserr, "%s", error); + } + if (new_network != NIL(network_t)) { + if (append != 0) { + error_init(); + if (network_append(*network, new_network) == 0) { + (void) fprintf(siserr, "%s", error_string()); + } + network_free(new_network); + } + else { + network_free(*network); + *network = new_network; + } + network_reset_short_name(*network); + status = 0; + } + else { + status = 1; + } + + FREE(real_filename); + read_register_filename(NIL(char)); + if (fp != stdin) { + (void) fclose(fp); + } + return(status); + +usage: + (void) fprintf(siserr, "usage: %s [-a] [file]\n", argv[0]); + (void) fprintf(siserr, " -a\t\tappend to current network\n"); + if (strcmp(argv[0], "read_pla") == 0) { + (void) fprintf(siserr, " -s\t\tread PLA as single-output\n"); + } + return(1); +} + +static int +com_write(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, short_name, net_list, status, delays_flag, wslif; + FILE *fp; + network_t *dc_network; + + short_name = 0; + net_list = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "snd")) != EOF) { + switch(c) { + case 's': + short_name = 1; + break; + case 'n': + net_list = 1; + break; + case 'd': + delays_flag = 1; + break; + default: + goto usage; + } + } + + /* open the destination file */ + if (argc - util_optind == 0) { + fp = com_open_file("-", "w", NIL(char *), /* silent */0); + } + else if (argc - util_optind == 1) { + fp = com_open_file(argv[util_optind], "w", NIL(char *), /* silent */0); + } + else { + goto usage; + } + if (fp == NIL(FILE)) { + return(1); + } + + /* allow error reporting */ + error_init(); + dc_network = network_dc_network(*network); + + if (strcmp(argv[0], "write_blif") == 0) { + write_blif(fp, *network, short_name, net_list); + status = 1; + } + else if (strcmp(argv[0], "write_eqn") == 0) { +#ifdef SIS + if (network_num_latch(*network)) { + (void) fprintf(sisout, "Warning: only combinational portion is being written.\n"); + } +#endif /* SIS */ + write_eqn(fp, *network, short_name); + if (dc_network != NIL(network_t)) { + io_fputs_break(fp, "\nDon't care:\n"); + write_eqn(fp, dc_network, short_name); + io_fputc_break(fp, '\n'); + } + status = 1; + } +#ifdef SIS + else if (strcmp(argv[0], "write_slif") == 0) { + (void) fprintf(siserr, "WARNING:\n\n"); +/* (void) fprintf(siserr, +"The following messages reflect inadequacies of SLIF, not any user fault.\n\n");*/ + if (delays_flag == 0) { + (void) fprintf(siserr, +" Delay information is not being printed because a standard has not been\n"); + + (void) fprintf(siserr, +"established for SLIF. Specify -d on the command line to force printing of delays.\n\n"); + } + (void) fprintf(siserr, +" Clock events have no equivalent SLIF structure and will not be printed.\n"); + (void) fprintf(siserr, +"Synch edges, which depend on clock edges, will also not be printed.\n\n"); + + (void) fprintf(siserr, +" SLIF supports only rising edge D flip-flops. Every latch is printed as a\n"); + (void) fprintf(siserr, +"rising edge D-ff. Also, SLIF does not store the reset state for a latch.\n\n"); + + write_slif(fp, *network, short_name, net_list, delays_flag); + if (dc_network != NIL(network_t)) { + io_fputs_break(fp, "\nDon't care:\n"); + write_slif(fp, dc_network, short_name, net_list, 0); + io_fputc_break(fp, '\n'); + } + status = 1; + } +#endif /* SIS */ + else if (strcmp(argv[0], "write_pla") == 0) { +#ifdef SIS + if (network_num_latch(*network)) { + (void) fprintf(sisout, "Warning: only combinational portion is being written.\n"); + } +#endif /* SIS */ + write_pla(fp, *network); + status = 1; + } + else if (strcmp(argv[0], "write_bdnet") == 0) { + status = write_bdnet(fp, *network); + } +#ifdef SIS + else if (strcmp(argv[0],"write_kiss") == 0) { + status = write_kiss(fp,network_stg(*network)); + } +#endif /* SIS */ + else { + (void) fprintf(siserr, " ... how did I get here ?\n"); + return(1); + } + + if (fp != stdout) { + (void) fclose(fp); + } + + if (status == 0) { + (void) fprintf(siserr, "%s", error_string()); + return(1); + } + return(0); + +usage: + (void) fprintf(siserr, "usage: %s [-s] [filename]\n", argv[0]); + (void) fprintf(siserr, " -s\t\tuse network short-names\n"); + wslif = strcmp(argv[0], "write_slif"); + if (strcmp(argv[0], "write_blif") == 0 || wslif == 0) { + (void) fprintf(siserr, " -n\t\tuse net-list format when possible\n"); + } + if (wslif == 0) { + (void) fprintf(siserr, + " -d\t\tprint the slif-format delay information\n"); + } + return(1); +} + + +/* Generates pds descriptions for single output CLBs, i.e. LUTs. */ + +#define node_short_name(n) n->short_name +extern char *node_decide_name(); + +static int +com_pds(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, short_name, combinational_flag; + FILE *fp; + /* Init */ + error_init(); + util_getopt_reset(); + debug = 0; + short_name = 0; + combinational_flag = 0; + name_mode = LONG_NAME_MODE; + /* Default params */ + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "cds")) != EOF) { + switch (c) { + case'c': + combinational_flag = 1; + break; + case'd': + debug = 1; + break; + case's': + short_name = 1; + name_mode = SHORT_NAME_MODE; + break; + default: + goto usage; + } + } + if(argc - util_optind == 0){ + fp = com_open_file("-", "w", NIL(char *), /* silent */0); + }else if((argc - util_optind) == 1) { + fp = com_open_file(argv[util_optind], "w", NIL(char *), /* silent */0); + } else { + goto usage; + } + + (void)write_palasm(fp, *network, short_name, combinational_flag); + if((argc - util_optind) == 1){ + fclose(fp); + } + return 0; + + usage: + (void)fprintf(sisout,"usage: %s [-csd] [filename]\n", argv[0]); + (void)fprintf(sisout,"-c\t\ttreat the network as a combinational one - do not print latch eqns\n"); + (void)fprintf(sisout,"-s\t\tuse network short-name\n"); + return 1; +} + + +write_palasm(fp, network, short_name, combinational_flag) +FILE *fp; +network_t *network; +int short_name, combinational_flag; /* combinational_flag = 1 => do not write out latch equations */ +{ + node_t *po, *pi, *node; + lsGen gen; + int i; +#ifdef SIS + latch_t *latch; + node_t *input, *output; + char *input_name, *output_name; +#endif + + (void)fprintf(fp, "CHIP dummy LCA\n"); + (void)fprintf(fp,"\n"); + + (void)fprintf(fp, ";PINLIST\n"); + i = 0; + + foreach_primary_input(network, gen, pi){ +#ifdef SIS + if (!combinational_flag) { + if (!network_is_real_pi(network, pi)) continue; + } +#endif + (void)fprintf(fp, "%s ", node_decide_name(pi, short_name)); + i++; + if( i > 9){ + (void)fprintf(fp, "\n"); + i = 0; + } + } + + foreach_primary_output(network, gen, po){ +#ifdef SIS + if (!combinational_flag) { + if (!network_is_real_po(network, po)) continue; + } +#endif + (void)fprintf(fp, "%s ", node_decide_name(po, short_name)); + i++; + if( i > 9){ + (void)fprintf(fp, "\n"); + i = 0; + } + } + + (void)fprintf(fp, "\n"); +#ifdef SIS + if (!combinational_flag) { + if (network_num_latch(network) > 0) { + (void) fprintf(fp, "clock\n"); + } + } +#endif + (void)fprintf(fp, "EQUATIONS\n"); + + foreach_node(network, gen, node){ + (void)write_pds_sop(fp, node, short_name); + } +#ifdef SIS + if (!combinational_flag) { + /* write out the flip-flop equations */ + /*-----------------------------------*/ + foreach_latch(network, gen, latch) { + input = latch_get_input(latch); + output = latch_get_output(latch); + input_name = node_decide_name(input, short_name); + output_name = node_decide_name(output, short_name); + fprintf(fp, "%s := %s\n", output_name, input_name); + fprintf(fp, "%s.CLKF = clock\n", output_name); + } + } +#endif + +} + +write_pds_sop(fp, node, short_name) +FILE *fp; +node_t *node; +int short_name; +{ + int first_cube, first_literal; + int i, j; + node_cube_t cube; + node_literal_t literal; + node_t *fanin; + extern int io_node_should_be_printed(); + + if (io_node_should_be_printed(node) == 0) { + return; + } + + (void)fprintf(fp, "%s = ", node_decide_name(node, short_name)); + switch(node_function(node)){ + case NODE_0: + (void)fprintf(fp, "GND\n"); + return; + case NODE_1: + (void)fprintf(fp, "VCC\n"); + return; + case NODE_PO: + (void)fprintf(fp, "%s\n", + node_decide_name(node_get_fanin(node, 0), short_name)); + return; + } + first_cube = 1; + for(i = node_num_cube(node)-1; i >= 0; i--){ + if(!first_cube){ + (void)fprintf(fp, " + "); + } + cube = node_get_cube(node, i); + + first_literal = 1; + foreach_fanin(node, j, fanin){ + literal = node_get_literal(cube, j); + switch(literal){ + case ZERO: + case ONE: + if(!first_literal){ + (void)fprintf(fp, " * "); + } + if(literal == ZERO) (void)fprintf(fp, "/"); + (void)fprintf(fp, "%s", node_decide_name(fanin, short_name)); + first_literal = 0; + break; + } + + } + first_cube = 0; + } + (void)fprintf(fp, "\n"); +} + + +int +po_fanout_count(n) +node_t *n; +{ + node_t *fo; + lsGen gen; + int po_count; + + po_count = 0; + foreach_fanout(n, gen, fo){ + if(node_function(fo) == NODE_PO) po_count++; + } + return po_count; +} + + +char * +node_decide_name(node, short_name) +node_t *node; +int short_name; +{ + extern char *io_name(); + + return io_name(node, short_name); +} + +static int +com_print(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *net, *dc_net; + node_t *node, *po, *pin, *pnode; + node_t *fanin; + array_t *node_vec; + int c, i, negative, print_dc; + int po_cnt; + lsGen gen; + char *name; + + negative = 0; + print_dc = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "nd")) != EOF) { + switch(c) { + case 'n': + negative = 1; + break; + case 'd': + print_dc = 1; + break; + default: + goto usage; + } + } + + if (print_dc) { + dc_net = network_dc_network(*network); + if (dc_net == NIL(network_t)) { + return(0); + } + net = network_dup(dc_net); +#ifdef SIS + foreach_primary_output(*network, gen, po){ + if (network_is_real_po(*network, po)) + continue; + if (!(node = network_find_node(net, po->name))) + continue; + if (node_function(node) != NODE_PO) + continue; + pin = po->fanin[0]; + if (node_function(pin) == NODE_PI){ + fanin = node->fanin[0]; + network_delete_node(net, node); + if (node_num_fanout(fanin) == 1) + network_delete_node(net, fanin); + continue; + } + po_cnt = io_rpo_fanout_count(pin, &pnode); + if (po_cnt != 0){ + fanin = node->fanin[0]; + network_delete_node(net, node); + if (node_num_fanout(fanin) == 0) + network_delete_node(net, fanin); + continue; + } + name = util_strsav(pin->name); + if (!network_find_node(net, name)) { + /* If the name were in the dc_network, that means that a + DC function for this latch was already found. The user + can give two constructs ".latch a b" ".latch a c" to + create two latches, but can only give one DC set for + these two latches. extract_seq_dc will produce a DC + set for each of these latches, but the DC set will be + the same. */ + network_change_node_name(net, node, name); + } else { + network_delete_node(net, node); + } + } +#endif /* SIS */ + } else { + net = *network; + } + node_vec = com_get_nodes(net, argc-util_optind+1, argv+util_optind-1); + if (array_n(node_vec) < 1) { + goto usage; + } + + for (i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (negative) { + node_print_negative(sisout, node); + } + else { + node_print(sisout, node); + } + } + array_free(node_vec); + if (print_dc){ + network_free(net); + } + + return(0); + +usage: + (void) fprintf(siserr, "usage: print [-d] [-n] n1 n2 ...\n"); + return 1; +} + +/* ARGSUSED */ +com_print_stats(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *net; + node_t *p, *node; + int i, c, pi, po, nodes, lits, lits_fac, factored_lits, print_dc; +#ifdef SIS + int latches, ns; + graph_t *g = NIL(graph_t); +#endif /* SIS */ + lsGen gen; + array_t *node_vec; + + factored_lits = 0; + print_dc = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "fd")) != EOF) { + switch(c) { + case 'f': + factored_lits = 1; + break; + case 'd': + print_dc = 1; + break; + default: + goto usage; + } + } + + if (print_dc != 0) { + net = network_dc_network(*network); + if (net == NIL(network_t)) { + return(0); + } + } + else { + net = *network; + } + + if (argc - util_optind >= 1) { + node_vec = com_get_nodes(net, argc-util_optind+1, argv+util_optind-1); + if (array_n(node_vec) < 1) { + goto usage; + } + for (i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (node_type(node) == PRIMARY_INPUT) { + (void) fprintf(sisout, "%-10s (primary input)\n", + node_name(node)); + } + else if (node_type(node) == PRIMARY_OUTPUT) { + (void) fprintf(sisout, "%-10s (primary output)\n", + node_name(node)); + } + else { + (void) fprintf(sisout, "%-10s %d terms, %d literals\n", + node_name(node), node_num_cube(node), + node_num_literal(node)); + } + } + array_free(node_vec); + + } + else { + pi = network_num_pi(net); + po = network_num_po(net); + nodes = network_num_internal(net); +#ifdef SIS + latches = network_num_latch(net); + if ((g = network_stg(net)) != NIL(graph_t)) { + ns = stg_get_num_states(g); + pi = stg_get_num_inputs(g); + po = stg_get_num_outputs(g); + } else { + pi = pi - latches; + po = po - latches; + } +#endif /* SIS */ + + lits = 0; + lits_fac = 0; + foreach_node (net, gen, p) { + lits += node_num_literal(p); + if (factored_lits) { + lits_fac += factor_num_literal(p); + } + + } + +#ifdef SIS + (void) fprintf(sisout, + "%-14s\tpi=%2d\tpo=%2d\tnodes=%3d\tlatches=%2d\nlits(sop)=%4d", + network_name(net), pi, po, nodes, latches, lits); +#else + (void) fprintf(sisout, + "%-14s\tpi=%2d\tpo=%2d\tnodes=%3d\tlits(sop)=%4d", + network_name(net), pi, po, nodes, lits); +#endif /* SIS */ + + if (factored_lits) { + (void) fprintf(sisout, "\tlits(fac)=%4d", lits_fac); + } +#ifdef SIS + if (g != NIL(graph_t)) { + (void) fprintf(sisout, "\t#states(STG)=%4d", ns); + } +#endif + (void) fprintf(sisout, "\n"); + } + return(0); + +usage: + (void) fprintf(siserr, "print_stats [-d] [-f] [n1 n2 ...]\n"); + return(1); +} + +static int +com_print_io(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *net; + lsGen gen; + node_t *node, *p; + node_t *fanin, *pnode; + int po_cnt; + array_t *node_vec; + int c, i, j, print_dc; + + print_dc = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "d")) != EOF) { + switch(c) { + case 'd': + print_dc = 1; + break; + default: + goto usage; + } + } + + if (print_dc) { + net = network_dc_network(*network); + if (net == NIL(network_t)) { + return(0); + } + } + else { + net = *network; + } + + if (argc - util_optind >= 1) { + node_vec = com_get_nodes(net, argc-util_optind+1, argv+util_optind-1); + for (i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + (void) fprintf(sisout, "%s\n", node_name(node)); + (void) fprintf(sisout, " inputs: "); + foreach_fanin(node, j, p) { + (void) fprintf(sisout, " %s", node_name(p)); + } + (void) fprintf(sisout, "\n"); + (void) fprintf(sisout, " outputs: "); + foreach_fanout (node, gen, p) { + (void) fprintf(sisout, " %s", node_name(p)); + } + (void) fprintf(sisout, "\n"); + } + array_free(node_vec); + } + else { + (void) fprintf(sisout, "primary inputs: "); + foreach_primary_input (net, gen, p) { + (void) fprintf(sisout, " %s", node_name(p)); + } + (void) fprintf(sisout, "\n"); + (void) fprintf(sisout, "primary outputs: "); + foreach_primary_output (net, gen, p) { + if (print_dc){ + if (node = network_find_node(*network, p->name)){ + fanin = node->fanin[0]; +#ifdef SIS + if (!network_is_real_po(*network, node)){ + po_cnt = io_rpo_fanout_count(fanin, &pnode); + if ((po_cnt != 0) && (node_function(fanin) != NODE_PI)){ + (void) fprintf(sisout, " {%s} (latch input)", pnode->name); + continue; + } + } +#endif /* SIS */ + (void) fprintf(sisout, " %s", node_name(node)); + continue; + } + (void) fprintf(sisout, " \n Error: %s not in care network \n", node_name(p)); + continue; + } + fanin = p->fanin[0]; +#ifdef SIS + if (!network_is_real_po(net, p)){ + po_cnt = io_rpo_fanout_count(fanin, &pnode); + if ((po_cnt != 0)){ + (void) fprintf(sisout, " {%s} (latch input)", pnode->name); + continue; + } + } +#endif /* SIS */ + (void) fprintf(sisout, " %s", node_name(p)); + } + (void) fprintf(sisout, "\n"); + } + return(0); +usage: + (void) fprintf(siserr, "print_io [-d] [n1 n2 ...]\n"); + return(1); +} + +/* ARGSUSED */ +static int +com_chname(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + if (argc != 1) { + (void) fprintf(siserr, "usage: chname\n"); + return(1); + } + + if (name_mode == LONG_NAME_MODE) { + name_mode = SHORT_NAME_MODE; + (void) fprintf(sisout, "changing to short-name mode\n"); + } + else { + name_mode = LONG_NAME_MODE; + (void) fprintf(sisout, "changing to long-name mode\n"); + } + return(0); +} + +static int +com_reset_name(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, short_names, long_names; + + short_names = long_names = 1; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "sl")) != EOF) { + switch(c) { + case 's': + long_names = 0; + break; + case 'l': + short_names = 0; + break; + default: + goto usage; + } + } + if (argc != util_optind) goto usage; + + if (short_names) { + network_reset_short_name(*network); + } + if (long_names) { + network_reset_long_name(*network); + } + return(0); + +usage: + (void) fprintf(siserr, "usage: reset_names [-sl]\n"); + (void) fprintf(siserr, "\t-s reset only short names\n"); + (void) fprintf(siserr, "\t-l reset only long, made-up names\n"); + return(1); +} + +/* ARGSUSED */ +static int +com_print_altname(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *node; + int i; + + if (argc < 2) { + (void) fprintf(siserr, "usage: print_altname n1 n2 ...\n"); + return(1); + } + + node_vec = com_get_nodes(*network, argc, argv); + for (i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + (void) fprintf(sisout, "%s = %s\n", node->name, node->short_name); + } + array_free(node_vec); + return(0); +} + +/* ARGSUSED */ +com_bdsyn(old_network, argc, argv) +network_t **old_network; /* never used ... */ +int argc; +char **argv; +{ + lsGen gen; + int i, min_node; + network_t *network; + node_t *node; + + if (argc == 1) { + min_node = 1; + } + else if (argc == 2) { + min_node = 0; + } + else { + (void) fprintf(siserr, "usage: bdsyn [1]\n"); + (void) fprintf(siserr, "\t\t1 implies don't minimize each node\n"); + return 1; + } + + error_init(); + read_register_filename("(stdin)"); + network = 0; + do { + i = read_blif(stdin, &network); + if (i == EOF) { + break; + } + else if (i != 1) { + (void) fprintf(siserr, "%s", error_string()); + return 1; + } + + (void) network_collapse(network); + if (min_node) { + foreach_node(network, gen, node) { + if (node_type(node) == INTERNAL) { + (void) node_simplify_replace(node, + NIL(node_t), NODE_SIM_ESPRESSO); + } + } + } + write_blif_for_bdsyn(stdout, network); + network_free(network); + (void) fflush(stdout); + } while (! feof(stdin)); + + return(0); +} + + + /* + *---------------------------------------------------------------------- + * + * com_force_init_state_to_zero -- INTERNAL ROUTINE + * + * Forces the initial state to be all zeroes + * by adding inverters around latches initially at 1 + * Very handy when latches cannot be initialized at 1 + * in a given technology (e.g. certain types of FPGAs). + * + * Results: + * + * Side effects: + * removes the don't care network if any. + * + *---------------------------------------------------------------------- + */ + +static int invert_polarity(); +static void free_dc_network(); + +#ifdef SIS +static int com_force_init_state_to_zero(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + latch_t *latch; + lsGen gen; + array_t *node_vec; + int value, status; + node_t *pi, *po; + + node_vec = array_alloc(node_t *, 0); + foreach_latch(*network, gen, latch) { + value = latch_get_initial_value(latch); + if (value == 0) continue; + pi = latch_get_output(latch); + array_insert_last(node_t *, node_vec, pi); + po = latch_get_input(latch); + array_insert_last(node_t *, node_vec, po); + latch_set_initial_value(latch, 0); + } + status = invert_polarity(*network, node_vec); + array_free(node_vec); + network_sweep(*network); + free_dc_network(*network); + return status; +} +#endif /* SIS */ + +static void free_dc_network(network) +network_t *network; +{ + network_free(network->dc_network); + network->dc_network = NIL(network_t); +} + + + /* inverts the polarity of the PI/PO in 'node_vec' */ + +static int invert_polarity(network, node_vec) +network_t *network; +array_t *node_vec; +{ + int i; + node_t *inv, *node; + lsGen gen; + node_t *fanout, *fanin; + + for (i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (node->type == PRIMARY_INPUT) { + inv = node_literal(node, 0); + foreach_fanout(node, gen, fanout) { + assert(node_patch_fanin(fanout, node, inv)); + node_scc(fanout); + } + } else if (node->type == PRIMARY_OUTPUT) { + fanin = node_get_fanin(node, 0); + inv = node_literal(fanin, 0); + assert(node_patch_fanin(node, fanin, inv)); + node_scc(node); + } else { + (void) fprintf(siserr, "\"com_io.c:invert_polarity()\" called for node != PI or PO"); + return 1; + } + network_add_node(network, inv); + } + return 0; +} + + + /* + *---------------------------------------------------------------------- + * + * Change the polarity (active high <-> active low) + * of specified external PIPO. + * + * Results: + * + * Side effects: + * Removes the don't care network if any. + * + *---------------------------------------------------------------------- + */ + +static int +com_invert_io(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i, status; + node_t *node; + array_t *node_vec; + + if (argc < 2) goto usage; + node_vec = com_get_true_io_nodes(*network, argc, argv); + + /* check input consistency */ + for (i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); +#ifdef SIS + if (! network_is_real_pi(*network, node) && ! network_is_real_po(*network, node)) { +#else + if (node_function(node) != NODE_PI && node_function(node) != NODE_PO) { +#endif /* SIS */ + (void) fprintf(siserr, "Error: node %s is not an external PI or PO\n", node_name(node)); + return 1; + } + } + + /* do the work */ + status = invert_polarity(*network, node_vec); + + /* cleanup */ + array_free(node_vec); + network_sweep(*network); + free_dc_network(*network); + return status; + + usage: + (void) fprintf(siserr, "usage: invert_io n1 n2 ...\n"); + return 1; +} + + + +init_io() +{ + com_add_command("bdsyn", com_bdsyn, 0); + com_add_command("read_blif", com_read, 1); + com_add_command("read_pla", com_read, 1); + com_add_command("read_eqn", com_read, 1); +#ifdef SIS + com_add_command("read_kiss",com_read, 1); + com_add_command("read_slif", com_read, 1); +#endif /* SIS */ + com_add_command("write_bdnet", com_write, 0); + com_add_command("write_blif", com_write, 0); + com_add_command("write_eqn", com_write, 0); + com_add_command("write_pla", com_write, 0); + com_add_command("write_pds", com_pds, 0); +#ifdef SIS + com_add_command("write_kiss",com_write,0); + com_add_command("write_slif", com_write, 0); +#endif /* SIS */ + com_add_command("print", com_print, 0); + com_add_command("print_io", com_print_io, 0); + com_add_command("print_stats", com_print_stats, 0); + com_add_command("chng_name", com_chname, 0); + com_add_command("reset_name", com_reset_name, 0); + com_add_command("print_altname", com_print_altname, 0); + com_add_command("invert_io", com_invert_io, 1); +#ifdef SIS + com_add_command("force_init_0", com_force_init_state_to_zero, 1); +#endif /* SIS */ + + if (com_graphics_enabled()) { + com_add_command("plot_blif", com_plot_blif, 0); + } +} + +end_io() +{ + read_register_filename(NIL(char)); +} + diff --git a/sis/io/eqnlex.c b/sis/io/eqnlex.c new file mode 100644 index 0000000..a0612f1 --- /dev/null +++ b/sis/io/eqnlex.c @@ -0,0 +1,1745 @@ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include <stdio.h> +#include <unistd.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include <io.h> +#include <stdlib.h> +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define EQN_yyconst const +#else +#define EQN_yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN EQN_yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((EQN_yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE EQN_yyrestart( EQN_yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct EQN_yy_buffer_state *YY_BUFFER_STATE; + +extern int EQN_yyleng; +extern FILE *EQN_yyin, *EQN_yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * EQN_yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the EQN_yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define EQN_yyless(n) \ + do \ + { \ + /* Undo effects of setting up EQN_yytext. */ \ + *EQN_yy_cp = EQN_yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + EQN_yy_c_buf_p = EQN_yy_cp = EQN_yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up EQN_yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) EQN_yyunput( c, EQN_yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int EQN_yy_size_t; + + +struct EQN_yy_buffer_state + { + FILE *EQN_yy_input_file; + + char *EQN_yy_ch_buf; /* input buffer */ + char *EQN_yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + EQN_yy_size_t EQN_yy_buf_size; + + /* Number of characters read into EQN_yy_ch_buf, not including EOB + * characters. + */ + int EQN_yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int EQN_yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int EQN_yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int EQN_yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int EQN_yy_fill_buffer; + + int EQN_yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via EQN_yyrestart()), so that the user can continue scanning by + * just pointing EQN_yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE EQN_yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER EQN_yy_current_buffer + + +/* EQN_yy_hold_char holds the character lost when EQN_yytext is formed. */ +static char EQN_yy_hold_char; + +static int EQN_yy_n_chars; /* number of characters read into EQN_yy_ch_buf */ + + +int EQN_yyleng; + +/* Points to current character in buffer. */ +static char *EQN_yy_c_buf_p = (char *) 0; +static int EQN_yy_init = 1; /* whether we need to initialize */ +static int EQN_yy_start = 0; /* start state number */ + +/* Flag which is used to allow EQN_yywrap()'s to do buffer switches + * instead of setting up a fresh EQN_yyin. A bit of a hack ... + */ +static int EQN_yy_did_buffer_switch_on_eof; + +void EQN_yyrestart YY_PROTO(( FILE *input_file )); + +void EQN_yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void EQN_yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE EQN_yy_create_buffer YY_PROTO(( FILE *file, int size )); +void EQN_yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void EQN_yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void EQN_yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER EQN_yy_flush_buffer( EQN_yy_current_buffer ) + +YY_BUFFER_STATE EQN_yy_scan_buffer YY_PROTO(( char *base, EQN_yy_size_t size )); +YY_BUFFER_STATE EQN_yy_scan_string YY_PROTO(( EQN_yyconst char *EQN_yy_str )); +YY_BUFFER_STATE EQN_yy_scan_bytes YY_PROTO(( EQN_yyconst char *bytes, int len )); + +static void *EQN_yy_flex_alloc YY_PROTO(( EQN_yy_size_t )); +static void *EQN_yy_flex_realloc YY_PROTO(( void *, EQN_yy_size_t )); +static void EQN_yy_flex_free YY_PROTO(( void * )); + +#define EQN_yy_new_buffer EQN_yy_create_buffer + +#define EQN_yy_set_interactive(is_interactive) \ + { \ + if ( ! EQN_yy_current_buffer ) \ + EQN_yy_current_buffer = EQN_yy_create_buffer( EQN_yyin, YY_BUF_SIZE ); \ + EQN_yy_current_buffer->EQN_yy_is_interactive = is_interactive; \ + } + +#define EQN_yy_set_bol(at_bol) \ + { \ + if ( ! EQN_yy_current_buffer ) \ + EQN_yy_current_buffer = EQN_yy_create_buffer( EQN_yyin, YY_BUF_SIZE ); \ + EQN_yy_current_buffer->EQN_yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (EQN_yy_current_buffer->EQN_yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *EQN_yyin = (FILE *) 0, *EQN_yyout = (FILE *) 0; +typedef int EQN_yy_state_type; +extern char *EQN_yytext; +#define EQN_yytext_ptr EQN_yytext + +static EQN_yy_state_type EQN_yy_get_previous_state YY_PROTO(( void )); +static EQN_yy_state_type EQN_yy_try_NUL_trans YY_PROTO(( EQN_yy_state_type current_state )); +static int EQN_yy_get_next_buffer YY_PROTO(( void )); +static void EQN_yy_fatal_error YY_PROTO(( EQN_yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up EQN_yytext. + */ +#define YY_DO_BEFORE_ACTION \ + EQN_yytext_ptr = EQN_yy_bp; \ + EQN_yyleng = (int) (EQN_yy_cp - EQN_yy_bp); \ + EQN_yy_hold_char = *EQN_yy_cp; \ + *EQN_yy_cp = '\0'; \ + EQN_yy_c_buf_p = EQN_yy_cp; + +#define YY_NUM_RULES 19 +#define YY_END_OF_BUFFER 20 +static EQN_yyconst short int EQN_yy_accept[29] = + { 0, + 1, 1, 20, 18, 16, 16, 7, 18, 17, 1, + 12, 8, 3, 4, 14, 15, 5, 6, 11, 13, + 16, 10, 0, 17, 1, 9, 2, 0 + } ; + +static EQN_yyconst int EQN_yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 6, 7, 7, 8, 9, 10, + 11, 12, 13, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 14, 7, + 15, 7, 1, 1, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 1, 7, 16, 7, 1, 7, 7, 7, 7, + + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 1, 17, 1, 7, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static EQN_yyconst int EQN_yy_meta[18] = + { 0, + 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 + } ; + +static EQN_yyconst short int EQN_yy_base[31] = + { 0, + 0, 0, 33, 34, 16, 18, 17, 0, 0, 24, + 34, 34, 34, 34, 34, 34, 34, 15, 34, 34, + 20, 34, 24, 0, 20, 34, 34, 34, 23, 25 + } ; + +static EQN_yyconst short int EQN_yy_def[31] = + { 0, + 28, 1, 28, 28, 28, 28, 28, 29, 30, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 29, 30, 28, 28, 28, 0, 28, 28 + } ; + +static EQN_yyconst short int EQN_yy_nxt[52] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 21, 21, + 21, 21, 21, 23, 23, 24, 25, 24, 27, 26, + 25, 22, 28, 3, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28 + } ; + +static EQN_yyconst short int EQN_yy_chk[52] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5, 5, 6, + 6, 21, 21, 29, 29, 30, 25, 30, 23, 18, + 10, 7, 3, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28 + } ; + +static EQN_yy_state_type EQN_yy_last_accepting_state; +static char *EQN_yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define EQN_yymore() EQN_yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *EQN_yytext; +#line 1 "eqnlex.l" +#define INITIAL 0 +#line 2 "eqnlex.l" +#include "sis.h" +#include "io_int.h" +#include "read_eqn.h" +#undef input +#undef unput +#ifdef FLEX_SCANNER +#undef YY_INPUT +#define YY_INPUT(buf,result,max) (result = eqn_input(buf, max)) +#endif + +static char *string; +static int file_mode; +static int nbuffer; +static char buffer[20]; +static int last_was_newline; + +extern int EQN_yyerror(char *); +#line 398 "lex.EQN_yy.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int EQN_yywrap YY_PROTO(( void )); +#else +extern int EQN_yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void EQN_yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef EQN_yytext_ptr +static void EQN_yy_flex_strncpy YY_PROTO(( char *, EQN_yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int EQN_yy_flex_strlen YY_PROTO(( EQN_yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int EQN_yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int EQN_yy_start_stack_ptr = 0; +static int EQN_yy_start_stack_depth = 0; +static int *EQN_yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void EQN_yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void EQN_yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int EQN_yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include <stdlib.h> +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( EQN_yytext, EQN_yyleng, 1, EQN_yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( EQN_yy_current_buffer->EQN_yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( EQN_yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( EQN_yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, EQN_yyin )) == 0) \ + && ferror( EQN_yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "EQN_yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef EQN_yyterminate +#define EQN_yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) EQN_yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int EQN_yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after EQN_yytext and EQN_yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register EQN_yy_state_type EQN_yy_current_state; + register char *EQN_yy_cp = NULL, *EQN_yy_bp = NULL; + register int EQN_yy_act; + +#line 26 "eqnlex.l" + + +#line 552 "lex.EQN_yy.c" + + if ( EQN_yy_init ) + { + EQN_yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! EQN_yy_start ) + EQN_yy_start = 1; /* first start state */ + + if ( ! EQN_yyin ) + EQN_yyin = stdin; + + if ( ! EQN_yyout ) + EQN_yyout = stdout; + + if ( ! EQN_yy_current_buffer ) + EQN_yy_current_buffer = + EQN_yy_create_buffer( EQN_yyin, YY_BUF_SIZE ); + + EQN_yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + EQN_yy_cp = EQN_yy_c_buf_p; + + /* Support of EQN_yytext. */ + *EQN_yy_cp = EQN_yy_hold_char; + + /* EQN_yy_bp points to the position in EQN_yy_ch_buf of the start of + * the current run. + */ + EQN_yy_bp = EQN_yy_cp; + + EQN_yy_current_state = EQN_yy_start; +EQN_yy_match: + do + { + register YY_CHAR EQN_yy_c = EQN_yy_ec[YY_SC_TO_UI(*EQN_yy_cp)]; + if ( EQN_yy_accept[EQN_yy_current_state] ) + { + EQN_yy_last_accepting_state = EQN_yy_current_state; + EQN_yy_last_accepting_cpos = EQN_yy_cp; + } + while ( EQN_yy_chk[EQN_yy_base[EQN_yy_current_state] + EQN_yy_c] != EQN_yy_current_state ) + { + EQN_yy_current_state = (int) EQN_yy_def[EQN_yy_current_state]; + if ( EQN_yy_current_state >= 29 ) + EQN_yy_c = EQN_yy_meta[(unsigned int) EQN_yy_c]; + } + EQN_yy_current_state = EQN_yy_nxt[EQN_yy_base[EQN_yy_current_state] + (unsigned int) EQN_yy_c]; + ++EQN_yy_cp; + } + while ( EQN_yy_base[EQN_yy_current_state] != 34 ); + +EQN_yy_find_action: + EQN_yy_act = EQN_yy_accept[EQN_yy_current_state]; + if ( EQN_yy_act == 0 ) + { /* have to back up */ + EQN_yy_cp = EQN_yy_last_accepting_cpos; + EQN_yy_current_state = EQN_yy_last_accepting_state; + EQN_yy_act = EQN_yy_accept[EQN_yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( EQN_yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *EQN_yy_cp = EQN_yy_hold_char; + EQN_yy_cp = EQN_yy_last_accepting_cpos; + EQN_yy_current_state = EQN_yy_last_accepting_state; + goto EQN_yy_find_action; + +case 1: +YY_RULE_SETUP +#line 28 "eqnlex.l" +{ + if (strcmp(EQN_yytext, "0") == 0) { + return CONST_ZERO; + } else if(strcmp(EQN_yytext, "1") == 0) { + return CONST_ONE; + } else if (strcmp(EQN_yytext, "NAME") == 0) { + return NAME; + } else if (strcmp(EQN_yytext, "INORDER") == 0) { + return INORDER; + } else if (strcmp(EQN_yytext, "OUTORDER") == 0) { + return OUTORDER; + } else if (strcmp(EQN_yytext, "END") == 0) { + return END; + } else { + return IDENTIFIER; + } + } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 47 "eqnlex.l" +{ + int i; + + EQN_yytext[EQN_yyleng-1] = '\0'; + for(i = 0; i < EQN_yyleng; i++) { + EQN_yytext[i] = EQN_yytext[i+1]; + } + EQN_yyleng -= 2; + return IDENTIFIER; + } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 57 "eqnlex.l" +{ return LPAREN; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 58 "eqnlex.l" +{ return RPAREN; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 59 "eqnlex.l" +{ return SEMI; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 60 "eqnlex.l" +{ return ASSIGN; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 62 "eqnlex.l" +{ return OPR_NOT; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 63 "eqnlex.l" +{ return OPR_NOT_POST; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 64 "eqnlex.l" +{ return OPR_XNOR; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 65 "eqnlex.l" +{ return OPR_XOR; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 66 "eqnlex.l" +{ return OPR_XOR; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 67 "eqnlex.l" +{ return OPR_AND; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 68 "eqnlex.l" +{ return OPR_OR; } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 69 "eqnlex.l" +{ return OPR_AND; } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 70 "eqnlex.l" +{ return OPR_OR; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 72 "eqnlex.l" +; + YY_BREAK +case 17: +YY_RULE_SETUP +#line 73 "eqnlex.l" +; /* comments */ + YY_BREAK +case 18: +YY_RULE_SETUP +#line 74 "eqnlex.l" +{ EQN_yyerror("bad character"); } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 76 "eqnlex.l" +ECHO; + YY_BREAK +#line 755 "lex.EQN_yy.c" +case YY_STATE_EOF(INITIAL): + EQN_yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int EQN_yy_amount_of_matched_text = (int) (EQN_yy_cp - EQN_yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *EQN_yy_cp = EQN_yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( EQN_yy_current_buffer->EQN_yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed EQN_yyin at a new source and called + * EQN_yylex(). If so, then we have to assure + * consistency between EQN_yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + EQN_yy_n_chars = EQN_yy_current_buffer->EQN_yy_n_chars; + EQN_yy_current_buffer->EQN_yy_input_file = EQN_yyin; + EQN_yy_current_buffer->EQN_yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for EQN_yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since EQN_yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( EQN_yy_c_buf_p <= &EQN_yy_current_buffer->EQN_yy_ch_buf[EQN_yy_n_chars] ) + { /* This was really a NUL. */ + EQN_yy_state_type EQN_yy_next_state; + + EQN_yy_c_buf_p = EQN_yytext_ptr + EQN_yy_amount_of_matched_text; + + EQN_yy_current_state = EQN_yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * EQN_yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + EQN_yy_next_state = EQN_yy_try_NUL_trans( EQN_yy_current_state ); + + EQN_yy_bp = EQN_yytext_ptr + YY_MORE_ADJ; + + if ( EQN_yy_next_state ) + { + /* Consume the NUL. */ + EQN_yy_cp = ++EQN_yy_c_buf_p; + EQN_yy_current_state = EQN_yy_next_state; + goto EQN_yy_match; + } + + else + { + EQN_yy_cp = EQN_yy_c_buf_p; + goto EQN_yy_find_action; + } + } + + else switch ( EQN_yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + EQN_yy_did_buffer_switch_on_eof = 0; + + if ( EQN_yywrap() ) + { + /* Note: because we've taken care in + * EQN_yy_get_next_buffer() to have set up + * EQN_yytext, we can now set up + * EQN_yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + EQN_yy_c_buf_p = EQN_yytext_ptr + YY_MORE_ADJ; + + EQN_yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! EQN_yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + EQN_yy_c_buf_p = + EQN_yytext_ptr + EQN_yy_amount_of_matched_text; + + EQN_yy_current_state = EQN_yy_get_previous_state(); + + EQN_yy_cp = EQN_yy_c_buf_p; + EQN_yy_bp = EQN_yytext_ptr + YY_MORE_ADJ; + goto EQN_yy_match; + + case EOB_ACT_LAST_MATCH: + EQN_yy_c_buf_p = + &EQN_yy_current_buffer->EQN_yy_ch_buf[EQN_yy_n_chars]; + + EQN_yy_current_state = EQN_yy_get_previous_state(); + + EQN_yy_cp = EQN_yy_c_buf_p; + EQN_yy_bp = EQN_yytext_ptr + YY_MORE_ADJ; + goto EQN_yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of EQN_yylex */ + + +/* EQN_yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int EQN_yy_get_next_buffer() + { + register char *dest = EQN_yy_current_buffer->EQN_yy_ch_buf; + register char *source = EQN_yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( EQN_yy_c_buf_p > &EQN_yy_current_buffer->EQN_yy_ch_buf[EQN_yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( EQN_yy_current_buffer->EQN_yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( EQN_yy_c_buf_p - EQN_yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (EQN_yy_c_buf_p - EQN_yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( EQN_yy_current_buffer->EQN_yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + EQN_yy_current_buffer->EQN_yy_n_chars = EQN_yy_n_chars = 0; + + else + { + int num_to_read = + EQN_yy_current_buffer->EQN_yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = EQN_yy_current_buffer; + + int EQN_yy_c_buf_p_offset = + (int) (EQN_yy_c_buf_p - b->EQN_yy_ch_buf); + + if ( b->EQN_yy_is_our_buffer ) + { + int new_size = b->EQN_yy_buf_size * 2; + + if ( new_size <= 0 ) + b->EQN_yy_buf_size += b->EQN_yy_buf_size / 8; + else + b->EQN_yy_buf_size *= 2; + + b->EQN_yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + EQN_yy_flex_realloc( (void *) b->EQN_yy_ch_buf, + b->EQN_yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->EQN_yy_ch_buf = 0; + + if ( ! b->EQN_yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + EQN_yy_c_buf_p = &b->EQN_yy_ch_buf[EQN_yy_c_buf_p_offset]; + + num_to_read = EQN_yy_current_buffer->EQN_yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&EQN_yy_current_buffer->EQN_yy_ch_buf[number_to_move]), + EQN_yy_n_chars, num_to_read ); + + EQN_yy_current_buffer->EQN_yy_n_chars = EQN_yy_n_chars; + } + + if ( EQN_yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + EQN_yyrestart( EQN_yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + EQN_yy_current_buffer->EQN_yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + EQN_yy_n_chars += number_to_move; + EQN_yy_current_buffer->EQN_yy_ch_buf[EQN_yy_n_chars] = YY_END_OF_BUFFER_CHAR; + EQN_yy_current_buffer->EQN_yy_ch_buf[EQN_yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + EQN_yytext_ptr = &EQN_yy_current_buffer->EQN_yy_ch_buf[0]; + + return ret_val; + } + + +/* EQN_yy_get_previous_state - get the state just before the EOB char was reached */ + +static EQN_yy_state_type EQN_yy_get_previous_state() + { + register EQN_yy_state_type EQN_yy_current_state; + register char *EQN_yy_cp; + + EQN_yy_current_state = EQN_yy_start; + + for ( EQN_yy_cp = EQN_yytext_ptr + YY_MORE_ADJ; EQN_yy_cp < EQN_yy_c_buf_p; ++EQN_yy_cp ) + { + register YY_CHAR EQN_yy_c = (*EQN_yy_cp ? EQN_yy_ec[YY_SC_TO_UI(*EQN_yy_cp)] : 1); + if ( EQN_yy_accept[EQN_yy_current_state] ) + { + EQN_yy_last_accepting_state = EQN_yy_current_state; + EQN_yy_last_accepting_cpos = EQN_yy_cp; + } + while ( EQN_yy_chk[EQN_yy_base[EQN_yy_current_state] + EQN_yy_c] != EQN_yy_current_state ) + { + EQN_yy_current_state = (int) EQN_yy_def[EQN_yy_current_state]; + if ( EQN_yy_current_state >= 29 ) + EQN_yy_c = EQN_yy_meta[(unsigned int) EQN_yy_c]; + } + EQN_yy_current_state = EQN_yy_nxt[EQN_yy_base[EQN_yy_current_state] + (unsigned int) EQN_yy_c]; + } + + return EQN_yy_current_state; + } + + +/* EQN_yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = EQN_yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static EQN_yy_state_type EQN_yy_try_NUL_trans( EQN_yy_state_type EQN_yy_current_state ) +#else +static EQN_yy_state_type EQN_yy_try_NUL_trans( EQN_yy_current_state ) +EQN_yy_state_type EQN_yy_current_state; +#endif + { + register int EQN_yy_is_jam; + register char *EQN_yy_cp = EQN_yy_c_buf_p; + + register YY_CHAR EQN_yy_c = 1; + if ( EQN_yy_accept[EQN_yy_current_state] ) + { + EQN_yy_last_accepting_state = EQN_yy_current_state; + EQN_yy_last_accepting_cpos = EQN_yy_cp; + } + while ( EQN_yy_chk[EQN_yy_base[EQN_yy_current_state] + EQN_yy_c] != EQN_yy_current_state ) + { + EQN_yy_current_state = (int) EQN_yy_def[EQN_yy_current_state]; + if ( EQN_yy_current_state >= 29 ) + EQN_yy_c = EQN_yy_meta[(unsigned int) EQN_yy_c]; + } + EQN_yy_current_state = EQN_yy_nxt[EQN_yy_base[EQN_yy_current_state] + (unsigned int) EQN_yy_c]; + EQN_yy_is_jam = (EQN_yy_current_state == 28); + + return EQN_yy_is_jam ? 0 : EQN_yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void EQN_yyunput( int c, register char *EQN_yy_bp ) +#else +static void EQN_yyunput( c, EQN_yy_bp ) +int c; +register char *EQN_yy_bp; +#endif + { + register char *EQN_yy_cp = EQN_yy_c_buf_p; + + /* undo effects of setting up EQN_yytext */ + *EQN_yy_cp = EQN_yy_hold_char; + + if ( EQN_yy_cp < EQN_yy_current_buffer->EQN_yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = EQN_yy_n_chars + 2; + register char *dest = &EQN_yy_current_buffer->EQN_yy_ch_buf[ + EQN_yy_current_buffer->EQN_yy_buf_size + 2]; + register char *source = + &EQN_yy_current_buffer->EQN_yy_ch_buf[number_to_move]; + + while ( source > EQN_yy_current_buffer->EQN_yy_ch_buf ) + *--dest = *--source; + + EQN_yy_cp += (int) (dest - source); + EQN_yy_bp += (int) (dest - source); + EQN_yy_current_buffer->EQN_yy_n_chars = + EQN_yy_n_chars = EQN_yy_current_buffer->EQN_yy_buf_size; + + if ( EQN_yy_cp < EQN_yy_current_buffer->EQN_yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--EQN_yy_cp = (char) c; + + + EQN_yytext_ptr = EQN_yy_bp; + EQN_yy_hold_char = *EQN_yy_cp; + EQN_yy_c_buf_p = EQN_yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int EQN_yyinput() +#else +static int input() +#endif + { + int c; + + *EQN_yy_c_buf_p = EQN_yy_hold_char; + + if ( *EQN_yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* EQN_yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( EQN_yy_c_buf_p < &EQN_yy_current_buffer->EQN_yy_ch_buf[EQN_yy_n_chars] ) + /* This was really a NUL. */ + *EQN_yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = EQN_yy_c_buf_p - EQN_yytext_ptr; + ++EQN_yy_c_buf_p; + + switch ( EQN_yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because EQN_yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + EQN_yyrestart( EQN_yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( EQN_yywrap() ) + return EOF; + + if ( ! EQN_yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return EQN_yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + EQN_yy_c_buf_p = EQN_yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) EQN_yy_c_buf_p; /* cast for 8-bit char's */ + *EQN_yy_c_buf_p = '\0'; /* preserve EQN_yytext */ + EQN_yy_hold_char = *++EQN_yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void EQN_yyrestart( FILE *input_file ) +#else +void EQN_yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! EQN_yy_current_buffer ) + EQN_yy_current_buffer = EQN_yy_create_buffer( EQN_yyin, YY_BUF_SIZE ); + + EQN_yy_init_buffer( EQN_yy_current_buffer, input_file ); + EQN_yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void EQN_yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void EQN_yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( EQN_yy_current_buffer == new_buffer ) + return; + + if ( EQN_yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *EQN_yy_c_buf_p = EQN_yy_hold_char; + EQN_yy_current_buffer->EQN_yy_buf_pos = EQN_yy_c_buf_p; + EQN_yy_current_buffer->EQN_yy_n_chars = EQN_yy_n_chars; + } + + EQN_yy_current_buffer = new_buffer; + EQN_yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (EQN_yywrap()) processing, but the only time this flag + * is looked at is after EQN_yywrap() is called, so it's safe + * to go ahead and always set it. + */ + EQN_yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void EQN_yy_load_buffer_state( void ) +#else +void EQN_yy_load_buffer_state() +#endif + { + EQN_yy_n_chars = EQN_yy_current_buffer->EQN_yy_n_chars; + EQN_yytext_ptr = EQN_yy_c_buf_p = EQN_yy_current_buffer->EQN_yy_buf_pos; + EQN_yyin = EQN_yy_current_buffer->EQN_yy_input_file; + EQN_yy_hold_char = *EQN_yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE EQN_yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE EQN_yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) EQN_yy_flex_alloc( sizeof( struct EQN_yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in EQN_yy_create_buffer()" ); + + b->EQN_yy_buf_size = size; + + /* EQN_yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->EQN_yy_ch_buf = (char *) EQN_yy_flex_alloc( b->EQN_yy_buf_size + 2 ); + if ( ! b->EQN_yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in EQN_yy_create_buffer()" ); + + b->EQN_yy_is_our_buffer = 1; + + EQN_yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void EQN_yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void EQN_yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == EQN_yy_current_buffer ) + EQN_yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->EQN_yy_is_our_buffer ) + EQN_yy_flex_free( (void *) b->EQN_yy_ch_buf ); + + EQN_yy_flex_free( (void *) b ); + } + + + +#ifdef YY_USE_PROTOS +void EQN_yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void EQN_yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + EQN_yy_flush_buffer( b ); + + b->EQN_yy_input_file = file; + b->EQN_yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->EQN_yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->EQN_yy_is_interactive = 0; +#else + b->EQN_yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void EQN_yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void EQN_yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->EQN_yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->EQN_yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->EQN_yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->EQN_yy_buf_pos = &b->EQN_yy_ch_buf[0]; + + b->EQN_yy_at_bol = 1; + b->EQN_yy_buffer_status = YY_BUFFER_NEW; + + if ( b == EQN_yy_current_buffer ) + EQN_yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE EQN_yy_scan_buffer( char *base, EQN_yy_size_t size ) +#else +YY_BUFFER_STATE EQN_yy_scan_buffer( base, size ) +char *base; +EQN_yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) EQN_yy_flex_alloc( sizeof( struct EQN_yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in EQN_yy_scan_buffer()" ); + + b->EQN_yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->EQN_yy_buf_pos = b->EQN_yy_ch_buf = base; + b->EQN_yy_is_our_buffer = 0; + b->EQN_yy_input_file = 0; + b->EQN_yy_n_chars = b->EQN_yy_buf_size; + b->EQN_yy_is_interactive = 0; + b->EQN_yy_at_bol = 1; + b->EQN_yy_fill_buffer = 0; + b->EQN_yy_buffer_status = YY_BUFFER_NEW; + + EQN_yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE EQN_yy_scan_string( EQN_yyconst char *EQN_yy_str ) +#else +YY_BUFFER_STATE EQN_yy_scan_string( EQN_yy_str ) +EQN_yyconst char *EQN_yy_str; +#endif + { + int len; + for ( len = 0; EQN_yy_str[len]; ++len ) + ; + + return EQN_yy_scan_bytes( EQN_yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE EQN_yy_scan_bytes( EQN_yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE EQN_yy_scan_bytes( bytes, len ) +EQN_yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + EQN_yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) EQN_yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in EQN_yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = EQN_yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in EQN_yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->EQN_yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void EQN_yy_push_state( int new_state ) +#else +static void EQN_yy_push_state( new_state ) +int new_state; +#endif + { + if ( EQN_yy_start_stack_ptr >= EQN_yy_start_stack_depth ) + { + EQN_yy_size_t new_size; + + EQN_yy_start_stack_depth += YY_START_STACK_INCR; + new_size = EQN_yy_start_stack_depth * sizeof( int ); + + if ( ! EQN_yy_start_stack ) + EQN_yy_start_stack = (int *) EQN_yy_flex_alloc( new_size ); + + else + EQN_yy_start_stack = (int *) EQN_yy_flex_realloc( + (void *) EQN_yy_start_stack, new_size ); + + if ( ! EQN_yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + EQN_yy_start_stack[EQN_yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void EQN_yy_pop_state() + { + if ( --EQN_yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(EQN_yy_start_stack[EQN_yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int EQN_yy_top_state() + { + return EQN_yy_start_stack[EQN_yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void EQN_yy_fatal_error( EQN_yyconst char msg[] ) +#else +static void EQN_yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine EQN_yyless() so it works in section 3 code. */ + +#undef EQN_yyless +#define EQN_yyless(n) \ + do \ + { \ + /* Undo effects of setting up EQN_yytext. */ \ + EQN_yytext[EQN_yyleng] = EQN_yy_hold_char; \ + EQN_yy_c_buf_p = EQN_yytext + n; \ + EQN_yy_hold_char = *EQN_yy_c_buf_p; \ + *EQN_yy_c_buf_p = '\0'; \ + EQN_yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef EQN_yytext_ptr +#ifdef YY_USE_PROTOS +static void EQN_yy_flex_strncpy( char *s1, EQN_yyconst char *s2, int n ) +#else +static void EQN_yy_flex_strncpy( s1, s2, n ) +char *s1; +EQN_yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int EQN_yy_flex_strlen( EQN_yyconst char *s ) +#else +static int EQN_yy_flex_strlen( s ) +EQN_yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *EQN_yy_flex_alloc( EQN_yy_size_t size ) +#else +static void *EQN_yy_flex_alloc( size ) +EQN_yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *EQN_yy_flex_realloc( void *ptr, EQN_yy_size_t size ) +#else +static void *EQN_yy_flex_realloc( ptr, size ) +void *ptr; +EQN_yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void EQN_yy_flex_free( void *ptr ) +#else +static void EQN_yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + EQN_yylex(); + return 0; + } +#endif +#line 76 "eqnlex.l" + + +#if 0 /* #ifndef FLEX_SCANNER */ +static int +input() +{ + register int c; + register char *prompt; + + if (nbuffer > 0) { + c = buffer[--nbuffer]; + } else if (file_mode) { + if (last_was_newline && EQN_yyin == stdin) { + prompt = com_get_flag("prompt2"); + if (prompt != NULL) fputs(prompt,stdout); + } + c = getc(EQN_yyin); + } else { + c = *string; + if (c != 0) string++; + } + + last_was_newline = (c == '\n'); + if (last_was_newline) read_lineno++; + if (c == EOF) c = 0; + return c; +} + +static int +unput(c) +int c; +{ + if (nbuffer < 20) buffer[nbuffer++] = c; + if (c == '\n') read_lineno--; +} +#else + +char *eqn_inp_ptr; +char* eqn_inp_lim; + +int eqn_input(char* buf, int max_size) +{ + char c; + int i, n; + + if (! file_mode) { + if (max_size > (eqn_inp_lim - eqn_inp_ptr)) + n = eqn_inp_lim - eqn_inp_ptr; + else + n= max_size; + if (n > 0) { + for (i = 0; i < n; i++) + if (eqn_inp_ptr[i] == '\n') { + read_lineno++; + i++; + break; + } + memcpy (buf, eqn_inp_ptr, i); + eqn_inp_ptr += i; + } + } else { + c = getc(EQN_yyin); + if (c == '\n') + read_lineno++; + buf[0] = (c == EOF) ? (n = 0, YY_NULL) : (n = 1, c); + } + return n; +} + +#endif + +int +equation_setup_string(s) +char *s; +{ + read_register_filename(NIL(char)); + file_mode = 0; + string = s; +#if 1 /* #ifdef FLEX_SCANNER */ + EQN_yy_switch_to_buffer( + EQN_yy_create_buffer( EQN_yyin, YY_BUF_SIZE ) ); + EQN_yyrestart(EQN_yyin); + eqn_inp_lim = string + strlen(string); + eqn_inp_ptr = string; +#endif + nbuffer = 0; +} + +int +equation_setup_file(fp) +FILE *fp; +{ + EQN_yyin = fp; +#if 1 /* #ifdef FLEX_SCANNER */ + EQN_yy_switch_to_buffer( + EQN_yy_create_buffer( EQN_yyin, YY_BUF_SIZE ) ); + EQN_yyrestart(EQN_yyin); + BEGIN(INITIAL); +#endif + file_mode = 1; + nbuffer = 0; + last_was_newline = 1; +} + +#undef EQN_yywrap +int +EQN_yywrap() +{ + return 1; +} diff --git a/sis/io/eqnlex.l b/sis/io/eqnlex.l new file mode 100644 index 0000000..5c76a77 --- /dev/null +++ b/sis/io/eqnlex.l @@ -0,0 +1,185 @@ +%{ +#include "sis.h" +#include "io_int.h" +#include "read_eqn.h" +#undef input +#undef unput +#ifdef FLEX_SCANNER +#undef YY_INPUT +#define YY_INPUT(buf,result,max) (result = eqn_input(buf, max)) +#endif + +static char *string; +static int file_mode; +static int nbuffer; +static char buffer[20]; +static int last_was_newline; + +extern int yyerror(char *); +%} + +blank [ \n\t] + +alpha [A-Za-z] +alnum [A-Za-z0-9_.,<>$%[\]:~/-] + +%% + +({alnum}*) { + if (strcmp(yytext, "0") == 0) { + return CONST_ZERO; + } else if(strcmp(yytext, "1") == 0) { + return CONST_ONE; + } else if (strcmp(yytext, "NAME") == 0) { + return NAME; + } else if (strcmp(yytext, "INORDER") == 0) { + return INORDER; + } else if (strcmp(yytext, "OUTORDER") == 0) { + return OUTORDER; + } else if (strcmp(yytext, "END") == 0) { + return END; + } else { + return IDENTIFIER; + } + } + + +\"[^"]+\" { + int i; + + yytext[yyleng-1] = '\0'; + for(i = 0; i < yyleng; i++) { + yytext[i] = yytext[i+1]; + } + yyleng -= 2; + return IDENTIFIER; + } +"(" { return LPAREN; } +")" { return RPAREN; } +";" { return SEMI; } +"=" { return ASSIGN; } + +"!" { return OPR_NOT; } +"'" { return OPR_NOT_POST; } +"==" { return OPR_XNOR; } +"!=" { return OPR_XOR; } +"^" { return OPR_XOR; } +"&" { return OPR_AND; } +"|" { return OPR_OR; } +"*" { return OPR_AND; } +"+" { return OPR_OR; } + +{blank}+ ; +#.* ; /* comments */ +. { yyerror("bad character"); } + +%% + +#if 0 /* #ifndef FLEX_SCANNER */ +static int +input() +{ + register int c; + register char *prompt; + + if (nbuffer > 0) { + c = buffer[--nbuffer]; + } else if (file_mode) { + if (last_was_newline && yyin == stdin) { + prompt = com_get_flag("prompt2"); + if (prompt != NULL) fputs(prompt,stdout); + } + c = getc(yyin); + } else { + c = *string; + if (c != 0) string++; + } + + last_was_newline = (c == '\n'); + if (last_was_newline) read_lineno++; + if (c == EOF) c = 0; + return c; +} + +static int +unput(c) +int c; +{ + if (nbuffer < 20) buffer[nbuffer++] = c; + if (c == '\n') read_lineno--; +} +#else + +char *eqn_inp_ptr; +char* eqn_inp_lim; + +int eqn_input(char* buf, int max_size) +{ + char c; + int i, n; + + if (! file_mode) { + if (max_size > (eqn_inp_lim - eqn_inp_ptr)) + n = eqn_inp_lim - eqn_inp_ptr; + else + n= max_size; + if (n > 0) { + for (i = 0; i < n; i++) + if (eqn_inp_ptr[i] == '\n') { + read_lineno++; + i++; + break; + } + memcpy (buf, eqn_inp_ptr, i); + eqn_inp_ptr += i; + } + } else { + c = getc(yyin); + if (c == '\n') + read_lineno++; + buf[0] = (c == EOF) ? (n = 0, YY_NULL) : (n = 1, c); + } + return n; +} + +#endif + +int +equation_setup_string(s) +char *s; +{ + read_register_filename(NIL(char)); + file_mode = 0; + string = s; +#if 1 /* #ifdef FLEX_SCANNER */ + yy_switch_to_buffer( + yy_create_buffer( yyin, YY_BUF_SIZE ) ); + yyrestart(yyin); + eqn_inp_lim = string + strlen(string); + eqn_inp_ptr = string; +#endif + nbuffer = 0; +} + +int +equation_setup_file(fp) +FILE *fp; +{ + yyin = fp; +#if 1 /* #ifdef FLEX_SCANNER */ + yy_switch_to_buffer( + yy_create_buffer( yyin, YY_BUF_SIZE ) ); + yyrestart(yyin); + BEGIN(INITIAL); +#endif + file_mode = 1; + nbuffer = 0; + last_was_newline = 1; +} + +#undef yywrap +int +yywrap() +{ + return 1; +} diff --git a/sis/io/io.doc b/sis/io/io.doc new file mode 100644 index 0000000..b560dcb --- /dev/null +++ b/sis/io/io.doc @@ -0,0 +1,91 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/io.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * + */ +int +read_blif(fp, network) +FILE *fp; +network_t **network; + Read a network from the open file given by fp. The network is + returned in 'network'. If end of file is reached before reading + a network, then -1 is returned; if a network is successfully read in, + 1 is returned. If any errors occur, 0 is returned. In any case, + error_string() has appended to it any error messages. Note that + warning only messages (i.e., "X does not fanout") cause a return value + of 1 indicating success; error_string() should always be examined + if this information is desired. + + read_blif has hacks to accept most of the 'LIF' format. + + +network_t * +read_eqn(fp) +FILE *fp; + Read eqntott-style equations from the open file given by fp. + See sis man-page for the command read_eqn for more + information on the format of equations parsed. Returns + NIL(network_t) if any errors occur during the parse; + error_string() then gives more information as what happened. + Note that error_string() should be initialized (using + error_init()) before calling read_eqn. To support parsing Oct + logic equations, a single s-expression (as defined by the Oct + LOGICFUNCTION property) is also parsed as a legal statement. + Note that the Oct LOGICFUNCTION does NOT supply the output + name; hence, one will be made up. + + +network_t * +read_eqn_string(string) +char *string; + Read eqntott-style equations from the string 'string'. See above + for more information. + +void +write_blif(fp, network, short_name, net_list) +FILE *fp; +network_t *network; +int short_name; +int net_list; + Write a network in BLIF format to the open file given by fp. + 'network' is the network to be written. 'short_name' encrypts + the data using the short-name for each node, rather than + the long-name. 'net-list' forces blif to write a traditional + gate-style netlist for those nodes which are already mapped. + + +void +write_lif(fp, network, short_name) +FILE *fp; +network_t *network; +int short_name; + Write a network in LIF format to the open file given by fp. + 'network' is the network to be written. 'short_name' encrypts + the data using the short-name for each node, rather than + the long-name. + + +void +write_pla(fp, network) +FILE *fp; +network_t *network; + Write a network in espresso PLA format to the open file given by fp. + + +int +write_bdnet(fp, network) +FILE *fp; +network_t *network; + Write a network in Oct bdnet format to the open file given by fp. + Returns 0 if unsuccessful; error_string() is set in this case. + Currently, this occurs only if the network is not mapped. + +void +read_register_filename(filename) +char *filename; + Give the reader a filename to be used when reporting error messages. + If NIL(char), the filename is not prepended to the output message. diff --git a/sis/io/io.h b/sis/io/io.h new file mode 100644 index 0000000..744c60b --- /dev/null +++ b/sis/io/io.h @@ -0,0 +1,33 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/io.h,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/02/09 07:06:11 $ + * + */ +#ifndef IO_H +#define IO_H + +EXTERN void write_blif ARGS((FILE *, network_t *, int, int)); +EXTERN void write_pla ARGS((FILE *, network_t *)); +EXTERN void write_eqn ARGS((FILE *, network_t *, int)); + +#ifdef SIS +EXTERN int write_kiss ARGS((FILE *, graph_t *)); +EXTERN int read_kiss ARGS((FILE *, graph_t **)); +EXTERN network_t *read_slif ARGS((FILE *)); +#endif /* SIS */ + +EXTERN int read_blif ARGS((FILE *, network_t **)); +EXTERN network_t *sis_read_pla ARGS((FILE *, int)); +EXTERN network_t *read_eqn ARGS((FILE *)); +EXTERN network_t *read_eqn_string ARGS((char *)); + +EXTERN void read_register_filename ARGS((char *)); + + /* Has variable # arguments -- problems with prototype */ +EXTERN void read_error (char *, ...); + +#endif diff --git a/sis/io/io_int.h b/sis/io/io_int.h new file mode 100644 index 0000000..0a93a40 --- /dev/null +++ b/sis/io/io_int.h @@ -0,0 +1,72 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/io_int.h,v $ + * $Author: pchong $ + * $Revision: 1.4 $ + * $Date: 2004/03/14 02:46:06 $ + * + */ +extern void io_fprintf_break(FILE *, char*, ...); +extern void io_fputs_break(); +extern void io_fputc_break(); +extern void io_fput_params(); + +extern void write_sop(); + +extern char *io_node_name(); +extern char *io_name(); +extern void io_write_name(); +extern void io_write_node(); +extern void io_write_gate(); +extern int io_po_fanout_count(); +extern int io_rpo_fanout_count(); +extern int io_lpo_fanout_count(); +extern int io_node_should_be_printed(); + +extern void read_filename_to_netname(); +extern node_t *read_find_or_create_node(); +extern node_t *read_slif_find_or_create_node(); +extern int read_check_io_list(); +extern void read_hack_outputs(); +extern void read_cleanup_buffers(); +#ifdef SIS +extern void read_delay_cleanup(); +extern void read_change_madeup_name(); +#endif /* SIS */ +extern node_t *read_add_fake_primary_output(); + +extern void write_blif_for_bdsyn(); +extern void write_blif_slif_delay(); + +extern int read_lineno; +extern char *read_filename; + +extern int com_write_slif(); +extern int com_plot_blif(); + +extern char *gettoken(); +#define MAX_WORD 1024 + +typedef struct { + array_t *actuals; /* Array of nodes: inputs, then outputs */ + char **formals; /* Array of formals */ + int inputs; /* How many entries in `actuals' are inputs */ + char *netname; /* Network to patch this network into */ +} patchinfo; + +typedef struct { /* Data field in the models table */ + network_t *network; /* The network */ + lsList po_list; /* The po_list for the network */ + lsList latch_order_list; /* Ordering for latches in stg */ + lsList patch_lists; /* Who depends on me */ + int depends_on; /* How many I depend on */ + int library; /* Is this going to be put in library? */ +} modelinfo; + +extern modelinfo *read_find_or_create_model(); +#ifdef SIS +extern int slif_add_to_library(); +#endif /* SIS */ +extern int read_blif_slif(); + diff --git a/sis/io/plot_blif.c b/sis/io/plot_blif.c new file mode 100644 index 0000000..dca19e1 --- /dev/null +++ b/sis/io/plot_blif.c @@ -0,0 +1,144 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/plot_blif.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * + */ +/* + * plot_blif.c -- transmit blif data to graphical front end. + * + * Since BLIF is already easy to parse, the graphics data for the BLIF + * representation of a network is just the BLIF output itself. + */ + +#include "sis.h" +#include "io_int.h" + +void io_plot_network (fp,network,internal) +FILE *fp; +network_t *network; +int internal; +{ + /* Write a description of the network for plotting. Use names which + will be guaranteed unique for each node. */ + + lsGen gen; + int igen; + char *long_name, *pretty_name; + node_t *node, *fanin; +#ifdef SIS + latch_t *latch; +#endif /* SIS */ + + fprintf(fp,".model\t%s\n",network_name(network)); + + fputs (".inputs",fp); + foreach_primary_input (network,gen,node) { +#ifdef SIS + if (network_is_real_pi(network,node)) { +#else + if (node->type == PRIMARY_INPUT) { +#endif /* SIS */ + fprintf(fp,"\t%s",node_long_name(node)); + } + } + fputs ("\n",fp); + + fputs (".outputs",fp); + foreach_primary_output (network,gen,node) { +#ifdef SIS + if (network_is_real_po(network,node)) { +#else + if (node->type == PRIMARY_INPUT) { +#endif /* SIS */ + fprintf(fp,"\t%s",node_long_name(node)); + } + } + fputs ("\n",fp); + + foreach_node (network,gen,node) { + if (node_num_fanin(node) == 0) continue; + long_name = node_long_name(node); + pretty_name = node_name(node); + fprintf(fp,".node\t%s",node_long_name(node)); + foreach_fanin (node,igen,fanin) { + fprintf(fp,"\t%s",node_long_name(fanin)); + } + fputs ("\n",fp); + if (!internal && strcmp(long_name,pretty_name) != 0) { + fprintf(fp,".label\t%s\t%s\n",long_name,pretty_name); + } + } + +#ifdef SIS + foreach_latch (network,gen,latch) { + fanin = latch_get_input (latch); + node = latch_get_output (latch); + fprintf(fp,".latch\t%s\t%s\n", + node_long_name(fanin), node_long_name(node)); + } +#endif /* SIS */ +} + +int com_plot_blif (network_p,argc,argv) +network_t **network_p; +int argc; +char **argv; +{ + int c, result = 0; + int replace = 0, close = 0, internal = 0, dc_net = 0; + char *geom = NULL; + char *plot_name = network_name(*network_p); + FILE *fp; + + util_getopt_reset (); + while ((c=util_getopt(argc,argv,"n:dikrg:")) != EOF) { + switch (c) { + case 'i': internal = 1; break; + case 'k': close = 1; break; + case 'r': replace = 1; break; + case 'g': geom = util_optarg; break; + case 'n': plot_name = util_optarg; break; + case 'd': dc_net = 1; break; + default : result = 1; break; + } + } + + if (result || *network_p == NULL) { + fprintf(sisout,"usage: %s [-n name] [-i] [-k] [-g geom] [-r]\n",argv[0]); + fputs(" -k\t\tclose plot window.\n",sisout); + fputs(" -r\t\treplace plot with updated network.\n",sisout); + fputs(" -i\t\tuse internal node names.\n",sisout); + fputs(" -g geom\tinitial geometry, WxH+X+Y formats\n",sisout); + fputs(" -n name\tuse name instead of network name.\n",sisout); + return result; + } + + if (close) { + com_graphics_exec ("blif",plot_name,"close", NIL(char)); + } + else if (replace) { + fp = com_graphics_open ("blif",plot_name,"replace"); + if (dc_net) { + io_plot_network(fp, (*network_p)->dc_network, internal); + } else { + io_plot_network (fp, *network_p, internal); + } + com_graphics_close (fp); + } + else { + fp = com_graphics_open ("blif",plot_name,"new"); + if (geom) fprintf(fp,".geometry\t%s\n",geom); + if (dc_net) { + io_plot_network (fp, (*network_p)->dc_network, internal); + } else { + io_plot_network (fp, *network_p, internal); + } + com_graphics_close (fp); + } + + return result; +} diff --git a/sis/io/read_blif.c b/sis/io/read_blif.c new file mode 100644 index 0000000..2506aa3 --- /dev/null +++ b/sis/io/read_blif.c @@ -0,0 +1,1096 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/read_blif.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * + */ +#include "sis.h" +#include "io_int.h" + +/* + * bug list: + * - blif cannot describe a single gate which feeds multiple outputs + */ + +static int read_node_list(); +static int read_cover(); +static int read_blif_gate(); +extern int read_line(); + +#ifdef SIS +static int read_blif_subckt(); + +static int read_blif_latch(); +static int read_blif_clock(); +static int read_blif_clock_event(); +static int read_blif_code(); +#endif + +/* ### hack, reach in and grab this from the node package */ +extern void node_replace_internal(); + +static int print_stuff = 0; /* debugging */ + +/* + * Mini input processor for blif files. (Also could be used by read_kiss) + * Reads the next newline or EOF terminated string from `fp' into `line'. + * + * Returns EOF if nothing was placed in `line' and EOF has been reached. + * Blank lines are eliminated and not returned in `line'. + * '\' followed immediately by a newline is treated as a single space. + * Comments begin with a '#' at any position on a line and end with newline. + * + * In `line' each word is seperated by exactly one space, and there are no + * initial or terminal spaces. This is the necessary condition for + * gettoken() to work. + */ + +io_do_prompt2 (fp) +FILE *fp; +{ + char *prompt2; + + if (fp == stdin) { + prompt2 = com_get_flag ("prompt2"); + if (prompt2 != NULL) fputs (prompt2,stdout); + } +} + +int +read_line(fp, linep, lenp) +FILE *fp; +char **linep; +int *lenp; +{ + int count, c; + char *line; + int len; + + count = 0; + len = *lenp; + line = *linep; + if (read_lineno == 0) io_do_prompt2(fp); + + while ((c = getc(fp)) != EOF) { + if (count >= len) { + len += MAX_WORD; + *linep = REALLOC(char, *linep, len); + line = &(*linep)[count]; + *lenp = len; + } + if (c == '\\') { + if ((c = getc(fp)) == '\n') { + read_lineno++; + io_do_prompt2 (fp); + c = ' '; + } + } + else if (c == '#') { + while ((c = getc(fp)) != EOF && c != '\n') { + } + if (c == EOF) { + return(EOF); + } + } + if (c == '\n' && count != 0) { /* got a non empty line */ + read_lineno++; + io_do_prompt2 (fp); + if (line[-1] == ' ') { + line--; + } + *line = '\0'; + if (print_stuff != 0) { + (void) printf("%s\n", *linep); + } + break; + } + if (isspace(c)) { + if (c == '\n') { + read_lineno++; + io_do_prompt2 (fp); + } + if (count == 0 || line[-1] == ' ') { + continue; + } + c = ' '; + } + *line++ = c; + count++; + } + return((count == 0) ? EOF : !EOF); +} + +/* + * Special variable just used by lib_read_blif() when reading in libraries. + */ +static int just_the_first = 0; + +/* needed when returning from a .exdc */ +char exdc_ret[128]; + +/* + * read_blif: read a blif description of a network. + * + * returns: + * -1 if end-of-file reached before a network has been read (not EOF !) + * 0 if an error occured during reading + * 1 if no errors + * + * Always check error_string() for any error/warning messages + * + * We return immediately on any fatal error with error_string() containing + * a somewhat useful error message. + */ +static int +read_blif_loop(fp, models, search_files, first_network) +FILE *fp; +st_table *models, *search_files; +network_t **first_network; +{ + int c, i, nlist, nin, nout, nterm, got_something, line_len; + char *line, *word, *rest, *got_model_name; + node_t *output, *node, **list; + lsList po_list; + network_t *network; + int error_status, in_model, fake_model_names; + modelinfo *entry; +#ifdef SIS + double cycle_time; + graph_t *stg; + lsList latch_order_list; +#endif /* SIS */ + + /* Initialize the network */ + got_something = 0; + + if (first_network != NIL(network_t *)) { + *first_network = NIL(network_t); + } + + network = NIL(network_t); + +#ifdef SIS + latch_order_list = NULL; +#endif /* SIS */ + + /* + * We record the primary outputs on a special list because of the + * difficulties of mapping blif into our network structure which includes + * an extra 'PO' node. + */ + error_status = 1; + in_model = 0; + got_model_name = NIL(char); + exdc_ret[0] = '\0'; + fake_model_names = 0; + + line_len = 0; + line = NIL(char); + + while (read_line(fp, &line, &line_len) != EOF) { +loop: + word = gettoken(line, &rest); + if (*word == '.') { + word++; + + /* + * These can appear outside of model definition + */ + if (strcmp(word, "model") == 0 || strcmp(word, "circuit") == 0) { + got_model_name = gettoken(NIL(char), NIL(char *)); + if (network != NIL(network_t) && just_the_first != 0) { + strcpy(exdc_ret, got_model_name); + break; + } + in_model = 1; + goto got_model; + + } +#ifdef SIS + else if (strcmp(word, "search") == 0) { + word = gettoken(NIL(char), NIL(char *)); + error_status = read_search_file(word, models, search_files, + read_blif_loop); + if (error_status != 1) { /* propagate an error */ + break; + } + continue; + } +#endif /* SIS */ + /* + * Everything down here has to be inside a model. If there + * isn't a model, create one. Illegal to have two unnamed + * models in one file. + */ + if (strcmp(word, "exdc") == 0) { + if (in_model == 0) { + read_error("external don't care w/o associated network"); + error_status = 0; + break; + } + i = read_blif_first(fp, &network->dc_network); + if (i != 1) { + read_error("bad/missing external don't care network"); + network->dc_network = NIL(network_t); + error_status = 0; + break; + } + if (exdc_ret[0] == '\0') { + continue; + } + got_model_name = exdc_ret; + in_model = 1; + goto got_model; + } + + if (in_model == 0) { +got_model: if (got_model_name == NIL(char)) { + if (fake_model_names != 0) { + read_error("too many unnamed models"); + error_status = 0; + break; + } + fake_model_names++; + got_model_name = strrchr(read_filename, '/'); + if (got_model_name == NIL(char)) { + got_model_name = read_filename; + } + else { + got_model_name++; + } + } + entry = read_find_or_create_model(got_model_name, models); + + if (entry->network != NIL(network_t)) { + read_error("model %s already defined", got_model_name); + error_status = 0; + break; + } + + entry->network = network_alloc(); + network_set_name(entry->network, got_model_name); + + got_something = 1; + network = entry->network; + po_list = entry->po_list; + if (first_network != NIL(network_t *)) { + if (*first_network == NIL(network_t)) { + *first_network = network; + } + } + if (in_model == 1) { + continue; + } + in_model = 1; + + } + if (strcmp(word, "names") == 0 || strcmp(word, "cover") == 0) { + if (strcmp(word, "cover") == 0) { + if (sscanf(rest, "%d %d %d", &nin, &nout, &nterm) != 3) { + read_error(".cover requires nin, nout, nterm"); + error_status = 0; + break; + } + /* gettoken must be called to move the pointer to */ + /* the input stream up to the node names */ + for (i = 0; i<=2; i++) { + word = gettoken(NIL(char), NIL(char *)); + } + if (nout != 1) { + read_error("only single-output .cover allowed"); + error_status = 0; + break; + } + } + got_something = 1; + nlist = read_node_list(network, &list); + if (nlist == 0) { + read_error("Too few names following .names"); + error_status = 0; + break; + } + nlist--; + output = list[nlist]; + if (node_function(output) != NODE_UNDEFINED) { + read_error("fatal: output '%s' is multiply defined", + node_name(output)); + error_status = 0; + break; + } + + i = read_cover(fp, output, list, nlist, &line, &line_len); + if (i == EOF) { + break; + } + else if (i == 0) { + error_status = 0; + break; + } + goto loop; /* don't want to read in the next line of file */ + + } + else if (strcmp(word, "gate") == 0) { /* library model */ + got_something = 1; + if (read_blif_gate(network, 0) == 0) { + error_status = 0; + break; + } + + } +#ifdef SIS + else if (strcmp(word, "subckt") == 0) { + got_something = 1; + if (read_blif_subckt(network, models) == 0) { + error_status = 0; + break; + } + entry->depends_on++; + } +#endif /* SIS */ + else if (strcmp(word, "inputs") == 0) { + got_something = 1; + while ((word = gettoken(NIL(char), NIL(char *))) != 0) { + node = read_find_or_create_node(network, word); + if (node_function(node) != NODE_UNDEFINED) { + read_error("input '%s' is multiply defined", word); + error_status = 0; + break; + } + network_change_node_type(network, node, PRIMARY_INPUT); + } + + } + else if (strcmp(word, "outputs") == 0) { + got_something = 1; + while ((word = gettoken(NIL(char), NIL(char *))) != 0) { + node = read_find_or_create_node(network, word); + (void) lsNewEnd(po_list, (lsGeneric) node, LS_NH); + } + +#ifdef SIS + + } else if (strcmp(word, "latch") == 0) { + got_something = 1; + if (read_blif_latch(network) == 0) { + error_status = 0; + break; + } + + } else if (strcmp(word, "mlatch") == 0) { + got_something = 1; + if (read_blif_gate(network, 1) == 0) { + error_status = 0; + break; + } + + } else if (strcmp(word, "start_kiss") == 0) { + got_something = 1; + + if (read_kiss(fp, &stg) == 0) { + error_status = 0; + break; + } + network_set_stg(network, stg); + + } else if (strcmp(word, "latch_order") == 0) { + if (entry->latch_order_list == NULL) { + entry->latch_order_list = lsCreate(); + } + latch_order_list = entry->latch_order_list; + while ((word = gettoken(NIL(char), NIL(char *))) != 0) { + node = read_find_or_create_node(network, word); + (void) lsNewEnd(latch_order_list, (lsGeneric) node, LS_NH); + } + + } else if (strcmp(word, "code") == 0) { + if (read_blif_code(network) == 0) { + error_status = 0; + break; + } + + } else if (strcmp(word, "cycle") == 0) { + if (sscanf(rest, "%lf", &cycle_time) != 1) { + read_error(".cycle requires single real argument"); + error_status = 0; + break; + } + clock_set_cycletime(network, cycle_time); + + } else if (strcmp(word, "clock") == 0 || + strcmp(word, "clocks") == 0) { + if (read_blif_clock(network) == 0) { + error_status = 0; + break; + } + + } else if (strcmp(word, "clock_event") == 0) { + if (read_blif_clock_event(network) == 0) { + error_status = 0; + break; + } + +#endif /* SIS */ + } else if (strcmp(word, "end") == 0) { + in_model = 0; + if (just_the_first != 0) { + break; + } + + } + else { + c = read_delay(network, po_list, word, rest, 00); + if (c == -1) { + /* echo line with unknown keyword */ + word--; + goto huh; + } + else if (c == 0) { + /* error parsing delay-related keyword */ + error_status = 0; + break; + } + } + } + else { +huh: + (void) fprintf(siserr, "\"%s\", line %d: %s %s\n", read_filename, + read_lineno, word, rest); + } + } + + if (got_something == 0) { + error_status = -1; + } + FREE(line); + return(error_status); +} + +/* + * The exported routine for everyone's use. + */ +int +read_blif(fp, networkp) +FILE *fp; +network_t **networkp; +{ + int status; + + just_the_first = 0; + status = read_blif_slif(fp, networkp, read_blif_loop); + if (status != 0 && *networkp != NIL(network_t)) { + read_cleanup_buffers(*networkp); + } + return status; +} + +/* + * Just read the first .model defined in the given file. Used by + * lib_read_blif(). + */ +int +read_blif_first(fp, networkp) +FILE *fp; +network_t **networkp; +{ + int i; + + just_the_first = 1; + i = read_blif_slif(fp, networkp, read_blif_loop); + just_the_first = 0; + return i; +} + +/* + * Accumulate nodes from the input stream. + * + * Nodes are inserted into `network' & accumulated onto dynamically allocated + * `list'. `list' should be freed after use. + * Returns the number of nodes processed. + */ +static int +read_node_list(network, list) +network_t *network; +node_t ***list; +{ + int nlist, list_max; + char *word; + node_t *node; + + list_max = 10; + *list = ALLOC(node_t *, list_max); + nlist = 0; + while ((word = gettoken(NIL(char), NIL(char *))) != NIL(char)) { + node = read_find_or_create_node(network, word); + if (nlist >= list_max) { + list_max *= 2; + *list = REALLOC(node_t *, *list, list_max); + } + (*list)[nlist++] = node; + } + return(nlist); +} + +/* + * Reads in a single output cover. Currently either the ON-set or the OFF-set + * may be specified; DC-set is not supported. Reads until it finds a line + * beginning with ".", which means it has read one line too many. Uses the + * `linep' and `lenp' variables to return the extra line and its length. + */ +static int +read_cover(fp, node, fanin, ninput, linep, lenp) +FILE *fp; +node_t *node; +node_t **fanin; +int ninput; +char **linep; /* reads one line too many. returns it here */ +int *lenp; +{ + register int i, c; + register pset pdest; + pset_family f; + char *word, *rest; + int is_normal, is_compl; + + is_compl = 0; /* records some table has "0" output */ + is_normal = 0; /* records some table has "1" output */ + + f = sf_new(8, ninput * 2); + + while ((c = read_line(fp, linep, lenp)) != EOF) { + if (**linep == '.') { /* end table on a command */ + break; /* command passed back in line_p */ + } + word = gettoken(*linep, &rest); + if (word == NIL(char)) { + goto bad_char; + } + if (ninput > 0) { + if (strlen(word) != ninput || rest == NIL(char)) { + goto bad_char; + } + pdest = set_new(ninput * 2); + for (i = 0; i < ninput; i++) { + switch (word[i]) { + case '0': + set_insert(pdest, 2 * i); + break; + case '1': + set_insert(pdest, 2 * i + 1); + break; + case '2': + case '-': + set_insert(pdest, 2 * i); + set_insert(pdest, 2 * i + 1); + break; + default: + goto bad_char; + } + } + if (strcmp(rest, "1") == 0) { + if (is_compl) { + read_error("must give F or R, but not both"); + return(0); + } + f = sf_addset(f, pdest); + set_free(pdest); + is_normal = 1; + } else if (strcmp(rest, "0") == 0) { + if (is_normal) { + read_error("must give F or R, but not both"); + return(0); + } + f = sf_addset(f, pdest); + set_free(pdest); + is_compl = 1; + } else { + goto bad_char; + } + + } else { + if (strcmp(word, "1") == 0) { + f->count = 1; /* the '1' function */ + } else if (strcmp(word, "0") == 0) { + /* the '0' function */ + } else { + goto bad_char; + } + } + } + + node_replace_internal(node, fanin, ninput, f); + if (is_compl) { + node_replace(node, node_not(node)); + } + node_scc(node); /* make it scc-minimal, dup_free, etc. */ + return((c == EOF) ? EOF : 1); + +bad_char: + read_error("bad character in PLA table"); + return(0); +} + + +/* + * Accumulate space seperated strings of characters (words) from the input + * stream. + * + * Elements of `wordlist' point into the tokenized input string; the elements + * should not be freed. `wordlist' should be freed after use. + * Returns the number of words read. + */ +static int +read_wordlist(wordlist) +char ***wordlist; +{ + int i = 0; + int list_max = 10; + char *word; + + *wordlist = ALLOC(char *, list_max); + while ((word = gettoken(NIL(char), NIL(char *))) != NIL(char)) { + if (i == list_max) { + list_max *= 2; + *wordlist = REALLOC(char *, *wordlist, list_max); + } + (*wordlist)[i++] = word; + } + return(i); +} + +#ifdef SIS +/* + * Make `network' depend on something. + * + * formats for .subckt: + * + * .subckt bozo formal1=actual1 formal2=actual2 ... + */ +static int +read_blif_subckt(network, models) +network_t *network; +st_table *models; +{ + char *name, *actual, **word_list; + modelinfo *ent; + patchinfo *patch; + node_t *node; + int nwords, i; + + name = gettoken(NIL(char), NIL(char *)); + if (name == NIL(char)) { + read_error("missing name in subckt"); + return(0); + } + if (strchr(name, '=') != NIL(char)) { + (void) fprintf(siserr, "\"%s\", line %d: calling subckt %s (contains `=')\n", + read_filename, read_lineno, name); + } + ent = read_find_or_create_model(name, models); + + nwords = read_wordlist(&word_list); + + patch = ALLOC(patchinfo, 1); + patch->actuals = array_alloc(node_t *, 10); + patch->formals = ALLOC(char *, nwords); + patch->inputs = -1; + patch->netname = network_name(network); + + for (i = 0; i < nwords; i++) { + actual = strchr(word_list[i], '='); + if (actual == NIL(char) || (*actual++ = '\0', *actual == '\0')) { + read_error("bad format for formal=actual in .subckt: %s", + word_list[i]); + FREE(word_list); + return(0); + } + node = read_find_or_create_node(network, actual); + array_insert_last(node_t *, patch->actuals, node); + } + for (i = 0; i < nwords; i++) { + patch->formals[i] = util_strsav(word_list[i]); + } + FREE(word_list); + (void) lsNewEnd(ent->patch_lists, (lsGeneric) patch, LS_NH); + return(1); +} + +#endif /* SIS */ + +/* + * Reads in a ".gate" or ".mlatch". `is_mlatch' == 0 if reading in a ".gate". + */ +static int +read_blif_gate(network, is_mlatch) +network_t *network; +int is_mlatch; +{ + char *name, *actual, *word; + array_t *actual_array; + char **word_list; + node_t *node, *tmp_node, **actual_data; + library_t *library; + lib_gate_t *gate; + int i, nwords; + static char *gm[] = {".gate", ".mlatch"}; +#ifdef SIS + node_t *control; + latch_t *latch; + int value; +#endif /* SIS */ + + /* get the current library */ + library = lib_get_library(); + if (library == NIL(library_t)) { + read_error("cannot process %s without a library", gm[is_mlatch]); + return(0); + } + + /* read the gate name */ + name = gettoken(NIL(char), NIL(char *)); + if (name == NIL(char)) { + read_error("missing gate name in %s", gm[is_mlatch]); + return(0); + } + gate = lib_get_gate(library, name); + if (gate == NIL(lib_gate_t)) { + read_error("cannot find gate '%s' in the library", name); + return(0); + } + + nwords = read_wordlist(&word_list); + +#ifdef SIS + if (is_mlatch != 0) { + nwords--; + value = *word_list[nwords] - '0'; + if (value < 0 || value > 9) { + read_error("warning: no latch value specified (undefined assumed)"); + value = 3; + } + else if (value > 3) { + read_error("latch value can only be 0, 1, 2, or 3"); + FREE(word_list); + return(0); + } + else { + nwords--; + } + if (strcmp(word_list[nwords], "NIL") == 0) { + control = NIL(node_t); + } + else { + control = read_find_or_create_node(network, word_list[nwords]); + } + } +#endif /* SIS */ + + actual_array = array_alloc(node_t *, 10); + + for (i = 0; i < nwords; i++) { + word = word_list[i]; + actual = strchr(word, '='); + if (actual == NIL(char) || (*actual++ = '\0', *actual == '\0')) { + read_error("bad format for formal=actual in %s: %s", + gm[is_mlatch], word_list[i]); + FREE(word_list); + return(0); + } + node = read_find_or_create_node(network, actual); + array_insert_last(node_t *, actual_array, node); + } + + actual_data = array_data(node_t *, actual_array); + array_free(actual_array); + + nwords--; + node = actual_data[nwords]; /* ### output pin name not checked ! */ + +#ifdef SIS + if (is_mlatch != 0) { + if (node_type(node) == PRIMARY_INPUT || node->F != 0) { + read_error("node %s already defined", node_name(node)); + FREE(word_list); + FREE(actual_data); + return(0); + } + else { + network_change_node_type(network, node, PRIMARY_INPUT); + } + } +#endif /* SIS */ + + if (lib_set_gate(node, gate, word_list, actual_data, nwords) == 0) { + read_error("error loading gate '%s' (have the correct library?)", + name); + FREE(word_list); + FREE(actual_data); + return(0); + } + FREE(word_list); + +#ifdef SIS + /* + * HACK:: To handle the case of nodes added when the input to an + * mlatch is a primary input. The name of the internal node added + * may conflict with the name of some node yet to be considered + */ + if (is_mlatch) { + tmp_node = latch_get_input(latch_from_node(node)); + tmp_node = node_get_fanin(tmp_node, 0); + assert(tmp_node->type == INTERNAL); + read_change_madeup_name(network, tmp_node); + } +#endif /* SIS */ + + +#ifdef SIS + if (is_mlatch != 0) { + latch = latch_from_node(node); + read_change_madeup_name(network, latch_get_input(latch)); + if (control != NIL(node_t)) { + node = network_get_control(network, control); + if (node == NIL(node_t)) { + node = network_add_fake_primary_output(network, control); + read_change_madeup_name(network, node); + } + control = node; + } + latch_set_control(latch, control); + latch_set_initial_value(latch, value); + latch_set_current_value(latch, value); + } +#endif /* SIS */ + + FREE(actual_data); + return(1); +} + +#ifdef SIS +/* + * An unspecified latch value is set to 3. + * Allow input of 0, 1, 2, or 3 for latch value, 2=DONT_CARE, 3=UNSPECIFIED + */ +static int +read_blif_latch(network) +network_t *network; +{ + int n_params, value; + char **word_list; + node_t *input, *output, *hack_po, *control, *n; + latch_t *latch; + latch_synch_t type; + + n_params = read_wordlist(&word_list); + + if (n_params < 2) { + read_error("latch input and output must be specified"); + FREE(word_list); + return(0); + } + if (n_params > 5) { + read_error("too many parameters for .latch"); + FREE(word_list); + return(0); + } + + input = read_find_or_create_node(network, word_list[0]); + output = read_find_or_create_node(network, word_list[1]); + + if ((n_params & 01) == 0) { /* 2 or 4 */ + read_error("warning: no latch value specified (undefined assumed)"); + value = 3; + type = UNKNOWN; + control = NIL(node_t); + } + else { /* 3 or 5 */ + value = *word_list[n_params - 1] - '0'; + if (value < 0 || value > 3) { + read_error("latch value can only be 0, 1, 2, or 3"); + FREE(word_list); + return(0); + } + if (n_params == 3) { + type = UNKNOWN; + control = NIL(node_t); + } + } + if (n_params >= 4) { + if (strcmp(word_list[3], "NIL") == 0) { + control = NIL(node_t); + } + else { + control = read_find_or_create_node(network, word_list[3]); + } + if (strcmp(word_list[2], "fe") == 0) type = FALLING_EDGE; + else if (strcmp(word_list[2], "re") == 0) type = RISING_EDGE; + else if (strcmp(word_list[2], "ah") == 0) type = ACTIVE_HIGH; + else if (strcmp(word_list[2], "al") == 0) type = ACTIVE_LOW; + else if (strcmp(word_list[2], "as") == 0) type = ASYNCH; + else { + read_error("latch type can only be re/fe/ah/al/as"); + FREE(word_list); + return(0); + } + } + FREE(word_list); + + if (node_type(output) == PRIMARY_INPUT || output->F != 0) { + read_error("latch output %s is already defined", node_name(output)); + return(0); + } + network_change_node_type(network, output, PRIMARY_INPUT); + + hack_po = network_add_fake_primary_output(network, input); + read_change_madeup_name(network, hack_po); + + network_create_latch(network, &latch, hack_po, output); + latch_set_initial_value(latch, value); + latch_set_current_value(latch, value); + latch_set_type(latch, type); + + if (control != NIL(node_t)) { + n = network_get_control(network, control); + if (n == NIL(node_t)) { + n = network_add_fake_primary_output(network, control); + read_change_madeup_name(network, n); + } + control = n; + } + latch_set_control(latch, control); + + return(1); +} + +static int +read_blif_clock(network) +network_t *network; +{ + int i, nlist; + node_t *node; + char **word_list; + sis_clock_t *clock; + + nlist = read_wordlist(&word_list); + for (i = 0; i < nlist; i++) { + node = read_find_or_create_node(network, word_list[i]); + if (node_function(node) != NODE_UNDEFINED) { + read_error("clock %s is multiply defined", node_name(node)); + FREE(word_list); + return(0); + } + network_change_node_type(network, node, PRIMARY_INPUT); + clock = clock_create(node_long_name(node)); + if (!clock_add_to_network(network, clock)) { + read_error("clock %s is already part of the network", + clock_name(clock)); + clock_free(clock); + FREE(word_list); + return(0); + } + } + FREE(word_list); + return (1); +} + +static int +read_blif_clock_event(network) +network_t *network; +{ + double nominal, min, max; + int first = 1; + char *word, *rest; + clock_edge_t first_edge, edge; + + word = gettoken(NIL(char), &rest); + if (sscanf(word, "%lf", &nominal) != 1) { + read_error(".clock_event must have event time as first argument"); + return(0); + } + + /* parse clock events */ + + while ((word = gettoken(rest, &rest)) != NIL(char)) { + if (*word == '(') { /* min and max specified */ + word++; + if (sscanf(rest, "%lf %lf", &min, &max) != 2) { + read_error("min and max values incorrectly specified for clock edge %s", + word); + return(0); + } + rest = strchr(rest, ')'); + if (rest == NIL(char)) { + read_error("warning: missing parentheses in event specifcation for clock edge %s", + word); + return(0); + } + (void) gettoken(rest, &rest); + } + else { /* min and max not specified */ + min = max = 0; + } + if (*word == 'r') { + edge.transition = RISE_TRANSITION; + } + else if (*word == 'f') { + edge.transition = FALL_TRANSITION; + } + else { + read_error("transition must be r or f in .clock_event %s", word); + return(0); + } + + if ((edge.clock = clock_get_by_name(network, word + 2)) == 0) { + read_error("clock %s not found in clock_list", word + 2); + return(0); + } + (void)clock_set_parameter(edge, CLOCK_NOMINAL_POSITION, nominal); + (void)clock_set_parameter(edge, CLOCK_LOWER_RANGE, min); + (void)clock_set_parameter(edge, CLOCK_UPPER_RANGE, max); + + if (first) { + first = 0; + first_edge.transition = edge.transition; + first_edge.clock = edge.clock; + } + else { + (void) clock_add_dependency(first_edge, edge); + } + } + return(1); +} + +static int +read_blif_code(network) +network_t *network; +{ + int nlist; + char **word_list; + graph_t *stg; + vertex_t *v; + + nlist = read_wordlist(&word_list); + if (nlist != 2) { + read_error(".code should have exactly 2 arguments"); + FREE(word_list); + return(0); + } + if ((stg = network_stg(network)) == NIL(graph_t)) { + read_error("stg not present, cannot set code"); + FREE(word_list); + return(0); + } + if ((v = stg_get_state_by_name(stg, word_list[0])) == NIL(vertex_t)) { + read_error("state %s not present, code cannot be set", word_list[0]); + FREE(word_list); + return(0); + } + stg_set_state_encoding(v, word_list[1]); + FREE(word_list); + return(1); +} + +#endif /* SIS */ + diff --git a/sis/io/read_eqn.c b/sis/io/read_eqn.c new file mode 100644 index 0000000..a727bd6 --- /dev/null +++ b/sis/io/read_eqn.c @@ -0,0 +1,1459 @@ +/* A Bison parser, made from read_eqn.y + by GNU bison 1.35. */ + +#define YYBISON 1 /* Identify Bison output. */ + +# define OPR_OR 257 +# define OPR_AND 258 +# define CONST_ZERO 259 +# define CONST_ONE 260 +# define IDENTIFIER 261 +# define LPAREN 262 +# define OPR_XOR 263 +# define OPR_XNOR 264 +# define OPR_NOT 265 +# define OPR_NOT_POST 266 +# define NAME 267 +# define INORDER 268 +# define OUTORDER 269 +# define PASS 270 +# define ASSIGN 271 +# define SEMI 272 +# define RPAREN 273 +# define END 274 + +#line 10 "read_eqn.y" + +#include "sis.h" +#include "io_int.h" +#include <setjmp.h> +#include "config.h" + +#if YYTEXT_POINTER +extern char *EQN_yytext; +#else +extern char EQN_yytext[]; +#endif + +static network_t *global_network; +static lsList po_list; + +int EQN_yyerror(); +#if 0 /* #ifndef FLEX_SCANNER */ +#undef EQN_yywrap +static int input(); +static int unput(); +static int EQN_yywrap(); +#endif + +extern int equation_setup_string(char *); +extern int equation_setup_file(FILE *); + +static void +do_assign(name, expr) +char *name; +node_t *expr; +{ + char errmsg[1024]; + node_t *node; + + node = read_find_or_create_node(global_network, name); + if (node_function(node) != NODE_UNDEFINED) { + (void) sprintf(errmsg, "Attempt to redefine '%s'\n", name); + EQN_yyerror(errmsg); /* never returns */ + } + FREE(name); + node_replace(node, expr); +} + +static node_t * +do_sexpr_list(list, func) +array_t *list; +node_t *(*func)(); +{ + int i; + node_t *node, *node1, *node2; + + node1 = array_fetch(node_t *, list, 0); + node = node_dup(node1); + node_free(node1); + for(i = 1; i < array_n(list); i++) { + node1 = node; + node2 = array_fetch(node_t *, list, i); + node = (*func)(node1, node2); + node_free(node1); + node_free(node2); + } + array_free(list); + return node; +} + + +#line 77 "read_eqn.y" +#ifndef YYSTYPE +typedef union { + char *strval; + node_t *node; + array_t *array; +} EQN_yystype; +# define YYSTYPE EQN_yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + + +#define YYFINAL 70 +#define YYFLAG -32768 +#define YYNTBASE 21 + +/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ +#define YYTRANSLATE(x) ((unsigned)(x) <= 274 ? EQN_yytranslate[x] : 30) + +/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ +static const char EQN_yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20 +}; + +#if YYDEBUG +static const short EQN_yyprhs[] = +{ + 0, 0, 1, 3, 7, 9, 12, 16, 17, 21, + 25, 29, 33, 39, 43, 47, 50, 54, 58, 61, + 64, 66, 68, 72, 74, 79, 84, 89, 91, 93, + 97, 101, 103, 105, 108, 110, 111, 114, 115 +}; +static const short EQN_yyrhs[] = +{ + -1, 22, 0, 22, 20, 18, 0, 25, 0, 23, + 18, 0, 22, 23, 18, 0, 0, 13, 17, 27, + 0, 14, 17, 28, 0, 15, 17, 29, 0, 27, + 17, 24, 0, 8, 17, 27, 25, 19, 0, 24, + 3, 24, 0, 24, 4, 24, 0, 24, 24, 0, + 24, 9, 24, 0, 24, 10, 24, 0, 24, 12, + 0, 11, 24, 0, 5, 0, 6, 0, 8, 24, + 19, 0, 27, 0, 8, 4, 26, 19, 0, 8, + 3, 26, 19, 0, 8, 11, 25, 19, 0, 5, + 0, 6, 0, 8, 5, 19, 0, 8, 6, 19, + 0, 27, 0, 25, 0, 26, 25, 0, 7, 0, + 0, 28, 27, 0, 0, 29, 27, 0 +}; + +#endif + +#if YYDEBUG +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const short EQN_yyrline[] = +{ + 0, 94, 95, 96, 97, 101, 102, 105, 106, 112, + 114, 116, 119, 124, 127, 130, 133, 136, 139, 142, + 145, 148, 151, 154, 164, 167, 170, 173, 176, 179, + 182, 185, 195, 200, 206, 211, 212, 229, 230 +}; +#endif + + +#if (YYDEBUG) || defined YYERROR_VERBOSE + +/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ +static const char *const EQN_yytname[] = +{ + "$", "error", "$undefined.", "OPR_OR", "OPR_AND", "CONST_ZERO", + "CONST_ONE", "IDENTIFIER", "LPAREN", "OPR_XOR", "OPR_XNOR", "OPR_NOT", + "OPR_NOT_POST", "NAME", "INORDER", "OUTORDER", "PASS", "ASSIGN", "SEMI", + "RPAREN", "END", "program", "prog", "stat", "expr", "sexpr", + "sexpr_list", "identifier", "input_list", "output_list", 0 +}; +#endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const short EQN_yyr1[] = +{ + 0, 21, 21, 21, 21, 22, 22, 23, 23, 23, + 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, + 25, 25, 26, 26, 27, 28, 28, 29, 29 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const short EQN_yyr2[] = +{ + 0, 0, 1, 3, 1, 2, 3, 0, 3, 3, + 3, 3, 5, 3, 3, 2, 3, 3, 2, 2, + 1, 1, 3, 1, 4, 4, 4, 1, 1, 3, + 3, 1, 1, 2, 1, 0, 2, 0, 2 +}; + +/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ +static const short EQN_yydefact[] = +{ + 1, 27, 28, 34, 0, 0, 0, 0, 2, 0, + 4, 31, 0, 0, 0, 0, 0, 0, 0, 35, + 37, 0, 0, 0, 0, 5, 0, 0, 32, 0, + 31, 0, 29, 30, 0, 0, 8, 9, 10, 3, + 6, 20, 21, 0, 0, 11, 23, 25, 33, 24, + 26, 0, 36, 38, 0, 19, 0, 0, 0, 0, + 18, 15, 12, 22, 13, 14, 16, 17, 0, 0, + 0 +}; + +static const short EQN_yydefgoto[] = +{ + 68, 8, 9, 61, 28, 29, 46, 37, 38 +}; + +static const short EQN_yypact[] = +{ + -4,-32768,-32768,-32768, 56, 2, 3, 6, 70, 4, + -32768, 7, 36, 36, 11, 44, 36, 57, 57,-32768, + -32768, 49, 54, 58, 7,-32768, 109, 107,-32768, 20, + -32768, 63,-32768,-32768, 55, 36,-32768, 57, 57,-32768, + -32768,-32768,-32768, 109, 109, 88,-32768,-32768,-32768,-32768, + -32768, 60,-32768,-32768, 46,-32768, 109, 109, 109, 109, + -32768, 112,-32768,-32768, 97, 112, -5, -5, 75, 80, + -32768 +}; + +static const short EQN_yypgoto[] = +{ + -32768,-32768, 73, -11, 5, 74, 0,-32768,-32768 +}; + + +#define YYLAST 124 + + +static const short EQN_yytable[] = +{ + 11, 1, 2, 3, 4, 10, 44, 60, 24, 5, + 6, 7, 30, 30, -7, 45, 30, 35, 36, 18, + 19, 34, 25, 20, 26, 1, 2, 3, 27, 30, + 32, 30, 54, 55, 48, 30, 48, 52, 53, 47, + 51, 1, 2, 3, 27, 64, 65, 66, 67, 56, + 57, 41, 42, 3, 43, 58, 59, 44, 60, 12, + 13, 14, 15, 33, 3, 63, 17, 16, 1, 2, + 3, 27, 39, 17, 50, 69, 40, 3, 21, 62, + 70, 23, 49, 5, 6, 7, 0, 31, -7, 0, + 22, 56, 57, 41, 42, 3, 43, 58, 59, 44, + 60, 57, 41, 42, 3, 43, 58, 59, 44, 60, + 12, 13, 14, 15, 41, 42, 3, 43, 16, 0, + 44, 58, 59, 44, 60 +}; + +static const short EQN_yycheck[] = +{ + 0, 5, 6, 7, 8, 0, 11, 12, 8, 13, + 14, 15, 12, 13, 18, 26, 16, 17, 18, 17, + 17, 16, 18, 17, 17, 5, 6, 7, 8, 29, + 19, 31, 43, 44, 29, 35, 31, 37, 38, 19, + 35, 5, 6, 7, 8, 56, 57, 58, 59, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 3, + 4, 5, 6, 19, 7, 19, 17, 11, 5, 6, + 7, 8, 18, 17, 19, 0, 18, 7, 8, 19, + 0, 8, 19, 13, 14, 15, -1, 13, 18, -1, + 20, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 3, 4, 5, 6, 5, 6, 7, 8, 11, -1, + 11, 9, 10, 11, 12 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/share/bison/bison.simple" + +/* Skeleton output parser for bison, + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software + Foundation, Inc. + + 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, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser when + the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* All symbols defined below should begin with EQN_yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +#if ! defined (EQN_yyoverflow) || defined (YYERROR_VERBOSE) + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (EQN_yyoverflow) || defined (YYERROR_VERBOSE) */ + + +#if (! defined (EQN_yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union EQN_yyalloc +{ + short EQN_yyss; + YYSTYPE EQN_yyvs; +# if YYLSP_NEEDED + YYLTYPE EQN_yyls; +# endif +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAX (sizeof (union EQN_yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# if YYLSP_NEEDED +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAX) +# else +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAX) +# endif + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T EQN_yyi; \ + for (EQN_yyi = 0; EQN_yyi < (Count); EQN_yyi++) \ + (To)[EQN_yyi] = (From)[EQN_yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T EQN_yynewbytes; \ + YYCOPY (&EQN_yyptr->Stack, Stack, EQN_yysize); \ + Stack = &EQN_yyptr->Stack; \ + EQN_yynewbytes = EQN_yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ + EQN_yyptr += EQN_yynewbytes / sizeof (*EQN_yyptr); \ + } \ + while (0) + +#endif + + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define EQN_yyerrok (EQN_yyerrstatus = 0) +#define EQN_yyclearin (EQN_yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto EQN_yyacceptlab +#define YYABORT goto EQN_yyabortlab +#define YYERROR goto EQN_yyerrlab1 +/* Like YYERROR except do call EQN_yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto EQN_yyerrlab +#define YYRECOVERING() (!!EQN_yyerrstatus) +#define YYBACKUP(Token, Value) \ +do \ + if (EQN_yychar == YYEMPTY && EQN_yylen == 1) \ + { \ + EQN_yychar = (Token); \ + EQN_yylval = (Value); \ + EQN_yychar1 = YYTRANSLATE (EQN_yychar); \ + YYPOPSTACK; \ + goto EQN_yybackup; \ + } \ + else \ + { \ + EQN_yyerror ("syntax error: cannot back up"); \ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). + + When YYLLOC_DEFAULT is run, CURRENT is set the location of the + first token. By default, to implement support for ranges, extend + its range to the last symbol. */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + + +/* YYLEX -- calling `EQN_yylex' with the right arguments. */ + +#if YYPURE +# if YYLSP_NEEDED +# ifdef YYLEX_PARAM +# define YYLEX EQN_yylex (&EQN_yylval, &EQN_yylloc, YYLEX_PARAM) +# else +# define YYLEX EQN_yylex (&EQN_yylval, &EQN_yylloc) +# endif +# else /* !YYLSP_NEEDED */ +# ifdef YYLEX_PARAM +# define YYLEX EQN_yylex (&EQN_yylval, YYLEX_PARAM) +# else +# define YYLEX EQN_yylex (&EQN_yylval) +# endif +# endif /* !YYLSP_NEEDED */ +#else /* !YYPURE */ +# define YYLEX EQN_yylex () +#endif /* !YYPURE */ + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (EQN_yydebug) \ + YYFPRINTF Args; \ +} while (0) +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int EQN_yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +#endif /* !YYDEBUG */ + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +#ifdef YYERROR_VERBOSE + +# ifndef EQN_yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define EQN_yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +EQN_yystrlen (const char *EQN_yystr) +# else +EQN_yystrlen (EQN_yystr) + const char *EQN_yystr; +# endif +{ + register const char *EQN_yys = EQN_yystr; + + while (*EQN_yys++ != '\0') + continue; + + return EQN_yys - EQN_yystr - 1; +} +# endif +# endif + +# ifndef EQN_yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define EQN_yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +EQN_yystpcpy (char *EQN_yydest, const char *EQN_yysrc) +# else +EQN_yystpcpy (EQN_yydest, EQN_yysrc) + char *EQN_yydest; + const char *EQN_yysrc; +# endif +{ + register char *EQN_yyd = EQN_yydest; + register const char *EQN_yys = EQN_yysrc; + + while ((*EQN_yyd++ = *EQN_yys++) != '\0') + continue; + + return EQN_yyd - 1; +} +# endif +# endif +#endif + +#line 315 "/usr/share/bison/bison.simple" + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into EQN_yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +# define YYPARSE_PARAM_DECL +# else +# define YYPARSE_PARAM_ARG YYPARSE_PARAM +# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +# endif +#else /* !YYPARSE_PARAM */ +# define YYPARSE_PARAM_ARG +# define YYPARSE_PARAM_DECL +#endif /* !YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +# ifdef YYPARSE_PARAM +int EQN_yyparse (void *); +# else +int EQN_yyparse (void); +# endif +#endif + +/* YY_DECL_VARIABLES -- depending whether we use a pure parser, + variables are global, or local to YYPARSE. */ + +#define YY_DECL_NON_LSP_VARIABLES \ +/* The lookahead symbol. */ \ +int EQN_yychar; \ + \ +/* The semantic value of the lookahead symbol. */ \ +YYSTYPE EQN_yylval; \ + \ +/* Number of parse errors so far. */ \ +int EQN_yynerrs; + +#if YYLSP_NEEDED +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES \ + \ +/* Location data for the lookahead symbol. */ \ +YYLTYPE EQN_yylloc; +#else +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES +#endif + + +/* If nonreentrant, generate the variables here. */ + +#if !YYPURE +YY_DECL_VARIABLES +#endif /* !YYPURE */ + +int +EQN_yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + /* If reentrant, generate the variables here. */ +#if YYPURE + YY_DECL_VARIABLES +#endif /* !YYPURE */ + + register int EQN_yystate; + register int EQN_yyn; + int EQN_yyresult; + /* Number of tokens to shift before error messages enabled. */ + int EQN_yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int EQN_yychar1 = 0; + + /* Three stacks and their tools: + `EQN_yyss': related to states, + `EQN_yyvs': related to semantic values, + `EQN_yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow EQN_yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short EQN_yyssa[YYINITDEPTH]; + short *EQN_yyss = EQN_yyssa; + register short *EQN_yyssp; + + /* The semantic value stack. */ + YYSTYPE EQN_yyvsa[YYINITDEPTH]; + YYSTYPE *EQN_yyvs = EQN_yyvsa; + register YYSTYPE *EQN_yyvsp; + +#if YYLSP_NEEDED + /* The location stack. */ + YYLTYPE EQN_yylsa[YYINITDEPTH]; + YYLTYPE *EQN_yyls = EQN_yylsa; + YYLTYPE *EQN_yylsp; +#endif + +#if YYLSP_NEEDED +# define YYPOPSTACK (EQN_yyvsp--, EQN_yyssp--, EQN_yylsp--) +#else +# define YYPOPSTACK (EQN_yyvsp--, EQN_yyssp--) +#endif + + YYSIZE_T EQN_yystacksize = YYINITDEPTH; + + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE EQN_yyval; +#if YYLSP_NEEDED + YYLTYPE EQN_yyloc; +#endif + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int EQN_yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + EQN_yystate = 0; + EQN_yyerrstatus = 0; + EQN_yynerrs = 0; + EQN_yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + EQN_yyssp = EQN_yyss; + EQN_yyvsp = EQN_yyvs; +#if YYLSP_NEEDED + EQN_yylsp = EQN_yyls; +#endif + goto EQN_yysetstate; + +/*------------------------------------------------------------. +| EQN_yynewstate -- Push a new state, which is found in EQN_yystate. | +`------------------------------------------------------------*/ + EQN_yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + EQN_yyssp++; + + EQN_yysetstate: + *EQN_yyssp = EQN_yystate; + + if (EQN_yyssp >= EQN_yyss + EQN_yystacksize - 1) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T EQN_yysize = EQN_yyssp - EQN_yyss + 1; + +#ifdef EQN_yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *EQN_yyvs1 = EQN_yyvs; + short *EQN_yyss1 = EQN_yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. */ +# if YYLSP_NEEDED + YYLTYPE *EQN_yyls1 = EQN_yyls; + /* This used to be a conditional around just the two extra args, + but that might be undefined if EQN_yyoverflow is a macro. */ + EQN_yyoverflow ("parser stack overflow", + &EQN_yyss1, EQN_yysize * sizeof (*EQN_yyssp), + &EQN_yyvs1, EQN_yysize * sizeof (*EQN_yyvsp), + &EQN_yyls1, EQN_yysize * sizeof (*EQN_yylsp), + &EQN_yystacksize); + EQN_yyls = EQN_yyls1; +# else + EQN_yyoverflow ("parser stack overflow", + &EQN_yyss1, EQN_yysize * sizeof (*EQN_yyssp), + &EQN_yyvs1, EQN_yysize * sizeof (*EQN_yyvsp), + &EQN_yystacksize); +# endif + EQN_yyss = EQN_yyss1; + EQN_yyvs = EQN_yyvs1; + } +#else /* no EQN_yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto EQN_yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (EQN_yystacksize >= YYMAXDEPTH) + goto EQN_yyoverflowlab; + EQN_yystacksize *= 2; + if (EQN_yystacksize > YYMAXDEPTH) + EQN_yystacksize = YYMAXDEPTH; + + { + short *EQN_yyss1 = EQN_yyss; + union EQN_yyalloc *EQN_yyptr = + (union EQN_yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (EQN_yystacksize)); + if (! EQN_yyptr) + goto EQN_yyoverflowlab; + YYSTACK_RELOCATE (EQN_yyss); + YYSTACK_RELOCATE (EQN_yyvs); +# if YYLSP_NEEDED + YYSTACK_RELOCATE (EQN_yyls); +# endif +# undef YYSTACK_RELOCATE + if (EQN_yyss1 != EQN_yyssa) + YYSTACK_FREE (EQN_yyss1); + } +# endif +#endif /* no EQN_yyoverflow */ + + EQN_yyssp = EQN_yyss + EQN_yysize - 1; + EQN_yyvsp = EQN_yyvs + EQN_yysize - 1; +#if YYLSP_NEEDED + EQN_yylsp = EQN_yyls + EQN_yysize - 1; +#endif + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) EQN_yystacksize)); + + if (EQN_yyssp >= EQN_yyss + EQN_yystacksize - 1) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", EQN_yystate)); + + goto EQN_yybackup; + + +/*-----------. +| EQN_yybackup. | +`-----------*/ +EQN_yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* EQN_yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + EQN_yyn = EQN_yypact[EQN_yystate]; + if (EQN_yyn == YYFLAG) + goto EQN_yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* EQN_yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (EQN_yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + EQN_yychar = YYLEX; + } + + /* Convert token to internal form (in EQN_yychar1) for indexing tables with */ + + if (EQN_yychar <= 0) /* This means end of input. */ + { + EQN_yychar1 = 0; + EQN_yychar = YYEOF; /* Don't call YYLEX any more */ + + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + EQN_yychar1 = YYTRANSLATE (EQN_yychar); + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables + which are defined only if `YYDEBUG' is set. */ + if (EQN_yydebug) + { + YYFPRINTF (stderr, "Next token is %d (%s", + EQN_yychar, EQN_yytname[EQN_yychar1]); + /* Give the individual parser a way to print the precise + meaning of a token, for further debugging info. */ +# ifdef YYPRINT + YYPRINT (stderr, EQN_yychar, EQN_yylval); +# endif + YYFPRINTF (stderr, ")\n"); + } +#endif + } + + EQN_yyn += EQN_yychar1; + if (EQN_yyn < 0 || EQN_yyn > YYLAST || EQN_yycheck[EQN_yyn] != EQN_yychar1) + goto EQN_yydefault; + + EQN_yyn = EQN_yytable[EQN_yyn]; + + /* EQN_yyn is what to do for this token type in this state. + Negative => reduce, -EQN_yyn is rule number. + Positive => shift, EQN_yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (EQN_yyn < 0) + { + if (EQN_yyn == YYFLAG) + goto EQN_yyerrlab; + EQN_yyn = -EQN_yyn; + goto EQN_yyreduce; + } + else if (EQN_yyn == 0) + goto EQN_yyerrlab; + + if (EQN_yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %d (%s), ", + EQN_yychar, EQN_yytname[EQN_yychar1])); + + /* Discard the token being shifted unless it is eof. */ + if (EQN_yychar != YYEOF) + EQN_yychar = YYEMPTY; + + *++EQN_yyvsp = EQN_yylval; +#if YYLSP_NEEDED + *++EQN_yylsp = EQN_yylloc; +#endif + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (EQN_yyerrstatus) + EQN_yyerrstatus--; + + EQN_yystate = EQN_yyn; + goto EQN_yynewstate; + + +/*-----------------------------------------------------------. +| EQN_yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +EQN_yydefault: + EQN_yyn = EQN_yydefact[EQN_yystate]; + if (EQN_yyn == 0) + goto EQN_yyerrlab; + goto EQN_yyreduce; + + +/*-----------------------------. +| EQN_yyreduce -- Do a reduction. | +`-----------------------------*/ +EQN_yyreduce: + /* EQN_yyn is the number of a rule to reduce with. */ + EQN_yylen = EQN_yyr2[EQN_yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to the semantic value of + the lookahead token. This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + EQN_yyval = EQN_yyvsp[1-EQN_yylen]; + +#if YYLSP_NEEDED + /* Similarly for the default location. Let the user run additional + commands if for instance locations are ranges. */ + EQN_yyloc = EQN_yylsp[1-EQN_yylen]; + YYLLOC_DEFAULT (EQN_yyloc, (EQN_yylsp - EQN_yylen), EQN_yylen); +#endif + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables which + are defined only if `YYDEBUG' is set. */ + if (EQN_yydebug) + { + int EQN_yyi; + + YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", + EQN_yyn, EQN_yyrline[EQN_yyn]); + + /* Print the symbols being reduced, and their result. */ + for (EQN_yyi = EQN_yyprhs[EQN_yyn]; EQN_yyrhs[EQN_yyi] > 0; EQN_yyi++) + YYFPRINTF (stderr, "%s ", EQN_yytname[EQN_yyrhs[EQN_yyi]]); + YYFPRINTF (stderr, " -> %s\n", EQN_yytname[EQN_yyr1[EQN_yyn]]); + } +#endif + + switch (EQN_yyn) { + +case 4: +#line 98 "read_eqn.y" +{ do_assign(util_strsav("SILLY"), EQN_yyvsp[0].node); } + break; +case 8: +#line 107 "read_eqn.y" +{ + network_set_name(global_network, EQN_yyvsp[0].strval); + FREE(EQN_yyvsp[0].strval); + } + break; +case 11: +#line 117 "read_eqn.y" +{ do_assign(EQN_yyvsp[-2].strval, EQN_yyvsp[0].node); } + break; +case 12: +#line 120 "read_eqn.y" +{ do_assign(EQN_yyvsp[-2].strval, EQN_yyvsp[-1].node); } + break; +case 13: +#line 125 "read_eqn.y" +{ EQN_yyval.node = node_or(EQN_yyvsp[-2].node, EQN_yyvsp[0].node); node_free(EQN_yyvsp[-2].node); node_free(EQN_yyvsp[0].node);} + break; +case 14: +#line 128 "read_eqn.y" +{ EQN_yyval.node = node_and(EQN_yyvsp[-2].node, EQN_yyvsp[0].node); node_free(EQN_yyvsp[-2].node); node_free(EQN_yyvsp[0].node);} + break; +case 15: +#line 131 "read_eqn.y" +{ EQN_yyval.node = node_and(EQN_yyvsp[-1].node, EQN_yyvsp[0].node); node_free(EQN_yyvsp[-1].node); node_free(EQN_yyvsp[0].node);} + break; +case 16: +#line 134 "read_eqn.y" +{ EQN_yyval.node = node_xor(EQN_yyvsp[-2].node, EQN_yyvsp[0].node); node_free(EQN_yyvsp[-2].node); node_free(EQN_yyvsp[0].node);} + break; +case 17: +#line 137 "read_eqn.y" +{ EQN_yyval.node = node_xnor(EQN_yyvsp[-2].node, EQN_yyvsp[0].node); node_free(EQN_yyvsp[-2].node); node_free(EQN_yyvsp[0].node);} + break; +case 18: +#line 140 "read_eqn.y" +{ EQN_yyval.node = node_not(EQN_yyvsp[-1].node); node_free(EQN_yyvsp[-1].node); } + break; +case 19: +#line 143 "read_eqn.y" +{ EQN_yyval.node = node_not(EQN_yyvsp[0].node); node_free(EQN_yyvsp[0].node); } + break; +case 20: +#line 146 "read_eqn.y" +{ EQN_yyval.node = node_constant(0); } + break; +case 21: +#line 149 "read_eqn.y" +{ EQN_yyval.node = node_constant(1); } + break; +case 22: +#line 152 "read_eqn.y" +{ EQN_yyval.node = EQN_yyvsp[-1].node; } + break; +case 23: +#line 155 "read_eqn.y" +{ + node_t *node; + node = read_find_or_create_node(global_network, EQN_yyvsp[0].strval); + EQN_yyval.node = node_literal(node, 1); + FREE(EQN_yyvsp[0].strval); + } + break; +case 24: +#line 165 "read_eqn.y" +{ EQN_yyval.node = do_sexpr_list(EQN_yyvsp[-1].array, node_and); } + break; +case 25: +#line 168 "read_eqn.y" +{ EQN_yyval.node = do_sexpr_list(EQN_yyvsp[-1].array, node_or); } + break; +case 26: +#line 171 "read_eqn.y" +{ EQN_yyval.node = node_not(EQN_yyvsp[-1].node); node_free(EQN_yyvsp[-1].node); } + break; +case 27: +#line 174 "read_eqn.y" +{ EQN_yyval.node = node_constant(0); } + break; +case 28: +#line 177 "read_eqn.y" +{ EQN_yyval.node = node_constant(1); } + break; +case 29: +#line 180 "read_eqn.y" +{ EQN_yyval.node = node_constant(0); } + break; +case 30: +#line 183 "read_eqn.y" +{ EQN_yyval.node = node_constant(1); } + break; +case 31: +#line 186 "read_eqn.y" +{ + node_t *node; + node = read_find_or_create_node(global_network, EQN_yyvsp[0].strval); + EQN_yyval.node = node_literal(node, 1); + FREE(EQN_yyvsp[0].strval); + } + break; +case 32: +#line 196 "read_eqn.y" +{ + EQN_yyval.array = array_alloc(node_t *, 10); + array_insert_last(node_t *, EQN_yyval.array, EQN_yyvsp[0].node); + } + break; +case 33: +#line 201 "read_eqn.y" +{ + array_insert_last(node_t *, EQN_yyvsp[-1].array, EQN_yyvsp[0].node); + } + break; +case 34: +#line 207 "read_eqn.y" +{ EQN_yyval.strval = util_strsav(EQN_yytext); } + break; +case 36: +#line 213 "read_eqn.y" +{ + node_t *node; + char errmsg[1024]; + node = read_find_or_create_node(global_network, EQN_yyvsp[0].strval); + if (node_function(node) != NODE_UNDEFINED) { + (void) sprintf(errmsg, + "Attempt to redefine '%s'\n", EQN_yyvsp[0].strval); + EQN_yyerror(errmsg); /* never returns */ + } + network_change_node_type(global_network, + node, PRIMARY_INPUT); + FREE(EQN_yyvsp[0].strval); + } + break; +case 38: +#line 231 "read_eqn.y" +{ + node_t *node; + node = read_find_or_create_node(global_network, EQN_yyvsp[0].strval); + LS_ASSERT(lsNewEnd(po_list, (lsGeneric) node, LS_NH)); + FREE(EQN_yyvsp[0].strval); + } + break; +} + +#line 705 "/usr/share/bison/bison.simple" + + + EQN_yyvsp -= EQN_yylen; + EQN_yyssp -= EQN_yylen; +#if YYLSP_NEEDED + EQN_yylsp -= EQN_yylen; +#endif + +#if YYDEBUG + if (EQN_yydebug) + { + short *EQN_yyssp1 = EQN_yyss - 1; + YYFPRINTF (stderr, "state stack now"); + while (EQN_yyssp1 != EQN_yyssp) + YYFPRINTF (stderr, " %d", *++EQN_yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + + *++EQN_yyvsp = EQN_yyval; +#if YYLSP_NEEDED + *++EQN_yylsp = EQN_yyloc; +#endif + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + EQN_yyn = EQN_yyr1[EQN_yyn]; + + EQN_yystate = EQN_yypgoto[EQN_yyn - YYNTBASE] + *EQN_yyssp; + if (EQN_yystate >= 0 && EQN_yystate <= YYLAST && EQN_yycheck[EQN_yystate] == *EQN_yyssp) + EQN_yystate = EQN_yytable[EQN_yystate]; + else + EQN_yystate = EQN_yydefgoto[EQN_yyn - YYNTBASE]; + + goto EQN_yynewstate; + + +/*------------------------------------. +| EQN_yyerrlab -- here on detecting error | +`------------------------------------*/ +EQN_yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!EQN_yyerrstatus) + { + ++EQN_yynerrs; + +#ifdef YYERROR_VERBOSE + EQN_yyn = EQN_yypact[EQN_yystate]; + + if (EQN_yyn > YYFLAG && EQN_yyn < YYLAST) + { + YYSIZE_T EQN_yysize = 0; + char *EQN_yymsg; + int EQN_yyx, EQN_yycount; + + EQN_yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (EQN_yyx = EQN_yyn < 0 ? -EQN_yyn : 0; + EQN_yyx < (int) (sizeof (EQN_yytname) / sizeof (char *)); EQN_yyx++) + if (EQN_yycheck[EQN_yyx + EQN_yyn] == EQN_yyx) + EQN_yysize += EQN_yystrlen (EQN_yytname[EQN_yyx]) + 15, EQN_yycount++; + EQN_yysize += EQN_yystrlen ("parse error, unexpected ") + 1; + EQN_yysize += EQN_yystrlen (EQN_yytname[YYTRANSLATE (EQN_yychar)]); + EQN_yymsg = (char *) YYSTACK_ALLOC (EQN_yysize); + if (EQN_yymsg != 0) + { + char *EQN_yyp = EQN_yystpcpy (EQN_yymsg, "parse error, unexpected "); + EQN_yyp = EQN_yystpcpy (EQN_yyp, EQN_yytname[YYTRANSLATE (EQN_yychar)]); + + if (EQN_yycount < 5) + { + EQN_yycount = 0; + for (EQN_yyx = EQN_yyn < 0 ? -EQN_yyn : 0; + EQN_yyx < (int) (sizeof (EQN_yytname) / sizeof (char *)); + EQN_yyx++) + if (EQN_yycheck[EQN_yyx + EQN_yyn] == EQN_yyx) + { + const char *EQN_yyq = ! EQN_yycount ? ", expecting " : " or "; + EQN_yyp = EQN_yystpcpy (EQN_yyp, EQN_yyq); + EQN_yyp = EQN_yystpcpy (EQN_yyp, EQN_yytname[EQN_yyx]); + EQN_yycount++; + } + } + EQN_yyerror (EQN_yymsg); + YYSTACK_FREE (EQN_yymsg); + } + else + EQN_yyerror ("parse error; also virtual memory exhausted"); + } + else +#endif /* defined (YYERROR_VERBOSE) */ + EQN_yyerror ("parse error"); + } + goto EQN_yyerrlab1; + + +/*--------------------------------------------------. +| EQN_yyerrlab1 -- error raised explicitly by an action | +`--------------------------------------------------*/ +EQN_yyerrlab1: + if (EQN_yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* return failure if at end of input */ + if (EQN_yychar == YYEOF) + YYABORT; + YYDPRINTF ((stderr, "Discarding token %d (%s).\n", + EQN_yychar, EQN_yytname[EQN_yychar1])); + EQN_yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + + EQN_yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto EQN_yyerrhandle; + + +/*-------------------------------------------------------------------. +| EQN_yyerrdefault -- current state does not do anything special for the | +| error token. | +`-------------------------------------------------------------------*/ +EQN_yyerrdefault: +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + + /* If its default is to accept any token, ok. Otherwise pop it. */ + EQN_yyn = EQN_yydefact[EQN_yystate]; + if (EQN_yyn) + goto EQN_yydefault; +#endif + + +/*---------------------------------------------------------------. +| EQN_yyerrpop -- pop the current state because it cannot handle the | +| error token | +`---------------------------------------------------------------*/ +EQN_yyerrpop: + if (EQN_yyssp == EQN_yyss) + YYABORT; + EQN_yyvsp--; + EQN_yystate = *--EQN_yyssp; +#if YYLSP_NEEDED + EQN_yylsp--; +#endif + +#if YYDEBUG + if (EQN_yydebug) + { + short *EQN_yyssp1 = EQN_yyss - 1; + YYFPRINTF (stderr, "Error: state stack now"); + while (EQN_yyssp1 != EQN_yyssp) + YYFPRINTF (stderr, " %d", *++EQN_yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + +/*--------------. +| EQN_yyerrhandle. | +`--------------*/ +EQN_yyerrhandle: + EQN_yyn = EQN_yypact[EQN_yystate]; + if (EQN_yyn == YYFLAG) + goto EQN_yyerrdefault; + + EQN_yyn += YYTERROR; + if (EQN_yyn < 0 || EQN_yyn > YYLAST || EQN_yycheck[EQN_yyn] != YYTERROR) + goto EQN_yyerrdefault; + + EQN_yyn = EQN_yytable[EQN_yyn]; + if (EQN_yyn < 0) + { + if (EQN_yyn == YYFLAG) + goto EQN_yyerrpop; + EQN_yyn = -EQN_yyn; + goto EQN_yyreduce; + } + else if (EQN_yyn == 0) + goto EQN_yyerrpop; + + if (EQN_yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++EQN_yyvsp = EQN_yylval; +#if YYLSP_NEEDED + *++EQN_yylsp = EQN_yylloc; +#endif + + EQN_yystate = EQN_yyn; + goto EQN_yynewstate; + + +/*-------------------------------------. +| EQN_yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +EQN_yyacceptlab: + EQN_yyresult = 0; + goto EQN_yyreturn; + +/*-----------------------------------. +| EQN_yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +EQN_yyabortlab: + EQN_yyresult = 1; + goto EQN_yyreturn; + +/*---------------------------------------------. +| EQN_yyoverflowab -- parser overflow comes here. | +`---------------------------------------------*/ +EQN_yyoverflowlab: + EQN_yyerror ("parser stack overflow"); + EQN_yyresult = 2; + /* Fall through. */ + +EQN_yyreturn: +#ifndef EQN_yyoverflow + if (EQN_yyss != EQN_yyssa) + YYSTACK_FREE (EQN_yyss); +#endif + return EQN_yyresult; +} +#line 239 "read_eqn.y" + + +static jmp_buf jmpbuf; + +int +EQN_yyerror(errmsg) +char *errmsg; +{ + read_error(errmsg); + longjmp(jmpbuf, 1); +} + + +network_t * +read_eqn(fp) +FILE *fp; +{ + error_init(); + + if (setjmp(jmpbuf)) { + /* syntax error -- return from EQN_yyerror() */ + LS_ASSERT(lsDestroy(po_list, (void (*)()) 0)); + network_free(global_network); + return 0; + + } else { + global_network = network_alloc(); + read_filename_to_netname(global_network, read_filename); + po_list = lsCreate(); + equation_setup_file(fp); + (void) EQN_yyparse(); + + if (!read_check_io_list(global_network, po_list)) { + network_free(global_network); + return 0; + } + read_hack_outputs(global_network, po_list); + LS_ASSERT(lsDestroy(po_list, (void (*)()) 0)); + + if (! network_is_acyclic(global_network)) { + network_free(global_network); + return 0; + } + + return global_network; + } +} + +network_t * +read_eqn_string(s) +char *s; +{ + error_init(); + + if (setjmp(jmpbuf)) { + /* syntax error -- return from EQN_yyerror() */ + LS_ASSERT(lsDestroy(po_list, (void (*)()) 0)); + network_free(global_network); + return 0; + + } else { + global_network = network_alloc(); + po_list = lsCreate(); + equation_setup_string(s); + (void) EQN_yyparse(); + + if (!read_check_io_list(global_network, po_list)) { + network_free(global_network); + return 0; + } + read_hack_outputs(global_network, po_list); + LS_ASSERT(lsDestroy(po_list, (void (*)()) 0)); + + if (! network_is_acyclic(global_network)) { + network_free(global_network); + return 0; + } + + return global_network; + } +} diff --git a/sis/io/read_eqn.h b/sis/io/read_eqn.h new file mode 100644 index 0000000..90cc356 --- /dev/null +++ b/sis/io/read_eqn.h @@ -0,0 +1,35 @@ +#ifndef BISON_Y_TAB_H +# define BISON_Y_TAB_H + +#ifndef YYSTYPE +typedef union { + char *strval; + node_t *node; + array_t *array; +} EQN_yystype; +# define YYSTYPE EQN_yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +# define OPR_OR 257 +# define OPR_AND 258 +# define CONST_ZERO 259 +# define CONST_ONE 260 +# define IDENTIFIER 261 +# define LPAREN 262 +# define OPR_XOR 263 +# define OPR_XNOR 264 +# define OPR_NOT 265 +# define OPR_NOT_POST 266 +# define NAME 267 +# define INORDER 268 +# define OUTORDER 269 +# define PASS 270 +# define ASSIGN 271 +# define SEMI 272 +# define RPAREN 273 +# define END 274 + + +extern YYSTYPE EQN_yylval; + +#endif /* not BISON_Y_TAB_H */ diff --git a/sis/io/read_eqn.y b/sis/io/read_eqn.y new file mode 100644 index 0000000..c729b1c --- /dev/null +++ b/sis/io/read_eqn.y @@ -0,0 +1,319 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/read_eqn.y,v $ + * $Author: pchong $ + * $Revision: 1.6 $ + * $Date: 2004/03/14 17:14:13 $ + * + */ +%{ +#include "sis.h" +#include "io_int.h" +#include <setjmp.h> +#include "config.h" + +#if YYTEXT_POINTER +extern char *yytext; +#else +extern char yytext[]; +#endif + +static network_t *global_network; +static lsList po_list; + +int yyerror(); +#if 0 /* #ifndef FLEX_SCANNER */ +#undef yywrap +static int input(); +static int unput(); +static int yywrap(); +#endif + +extern int equation_setup_string(char *); +extern int equation_setup_file(FILE *); + +static void +do_assign(name, expr) +char *name; +node_t *expr; +{ + char errmsg[1024]; + node_t *node; + + node = read_find_or_create_node(global_network, name); + if (node_function(node) != NODE_UNDEFINED) { + (void) sprintf(errmsg, "Attempt to redefine '%s'\n", name); + yyerror(errmsg); /* never returns */ + } + FREE(name); + node_replace(node, expr); +} + +static node_t * +do_sexpr_list(list, func) +array_t *list; +node_t *(*func)(); +{ + int i; + node_t *node, *node1, *node2; + + node1 = array_fetch(node_t *, list, 0); + node = node_dup(node1); + node_free(node1); + for(i = 1; i < array_n(list); i++) { + node1 = node; + node2 = array_fetch(node_t *, list, i); + node = (*func)(node1, node2); + node_free(node1); + node_free(node2); + } + array_free(list); + return node; +} + +%} + +%union { + char *strval; + node_t *node; + array_t *array; +} + +%type <strval> identifier +%type <node> expr sexpr +%type <array> sexpr_list +%left OPR_OR +%left OPR_AND CONST_ZERO CONST_ONE IDENTIFIER LPAREN +%left OPR_XOR OPR_XNOR +%left OPR_NOT OPR_NOT_POST +%token NAME INORDER OUTORDER PASS ASSIGN SEMI LPAREN RPAREN END +%start program + +%% +program : /* EMPTY */ + | prog + | prog END SEMI + | sexpr + { do_assign(util_strsav("SILLY"), $1); } + ; + +prog : stat SEMI + | prog stat SEMI + ; + +stat : /* empty */ + | NAME ASSIGN identifier + { + network_set_name(global_network, $3); + FREE($3); + } + + | INORDER ASSIGN input_list + + | OUTORDER ASSIGN output_list + + | identifier ASSIGN expr + { do_assign($1, $3); } + + | LPAREN ASSIGN identifier sexpr RPAREN + { do_assign($3, $4); } + ; + + +expr : expr OPR_OR expr + { $$ = node_or($1, $3); node_free($1); node_free($3);} + + | expr OPR_AND expr + { $$ = node_and($1, $3); node_free($1); node_free($3);} + + | expr expr %prec OPR_AND + { $$ = node_and($1, $2); node_free($1); node_free($2);} + + | expr OPR_XOR expr + { $$ = node_xor($1, $3); node_free($1); node_free($3);} + + | expr OPR_XNOR expr + { $$ = node_xnor($1, $3); node_free($1); node_free($3);} + + | expr OPR_NOT_POST + { $$ = node_not($1); node_free($1); } + + | OPR_NOT expr + { $$ = node_not($2); node_free($2); } + + | CONST_ZERO + { $$ = node_constant(0); } + + | CONST_ONE + { $$ = node_constant(1); } + + | LPAREN expr RPAREN + { $$ = $2; } + + | identifier + { + node_t *node; + node = read_find_or_create_node(global_network, $1); + $$ = node_literal(node, 1); + FREE($1); + } + ; + + +sexpr : LPAREN OPR_AND sexpr_list RPAREN + { $$ = do_sexpr_list($3, node_and); } + + | LPAREN OPR_OR sexpr_list RPAREN + { $$ = do_sexpr_list($3, node_or); } + + | LPAREN OPR_NOT sexpr RPAREN + { $$ = node_not($3); node_free($3); } + + | CONST_ZERO + { $$ = node_constant(0); } + + | CONST_ONE + { $$ = node_constant(1); } + + | LPAREN CONST_ZERO RPAREN + { $$ = node_constant(0); } + + | LPAREN CONST_ONE RPAREN + { $$ = node_constant(1); } + + | identifier + { + node_t *node; + node = read_find_or_create_node(global_network, $1); + $$ = node_literal(node, 1); + FREE($1); + } + ; + + +sexpr_list: sexpr + { + $$ = array_alloc(node_t *, 10); + array_insert_last(node_t *, $$, $1); + } + | sexpr_list sexpr + { + array_insert_last(node_t *, $1, $2); + } + ; + +identifier: IDENTIFIER + { $$ = util_strsav(yytext); } + ; + + +input_list: /* empty */ + | input_list identifier + { + node_t *node; + char errmsg[1024]; + node = read_find_or_create_node(global_network, $2); + if (node_function(node) != NODE_UNDEFINED) { + (void) sprintf(errmsg, + "Attempt to redefine '%s'\n", $2); + yyerror(errmsg); /* never returns */ + } + network_change_node_type(global_network, + node, PRIMARY_INPUT); + FREE($2); + } + ; + + +output_list: /* empty */ + | output_list identifier + { + node_t *node; + node = read_find_or_create_node(global_network, $2); + LS_ASSERT(lsNewEnd(po_list, (lsGeneric) node, LS_NH)); + FREE($2); + } + ; + +%% + +static jmp_buf jmpbuf; + +int +yyerror(errmsg) +char *errmsg; +{ + read_error(errmsg); + longjmp(jmpbuf, 1); +} + + +network_t * +read_eqn(fp) +FILE *fp; +{ + error_init(); + + if (setjmp(jmpbuf)) { + /* syntax error -- return from yyerror() */ + LS_ASSERT(lsDestroy(po_list, (void (*)()) 0)); + network_free(global_network); + return 0; + + } else { + global_network = network_alloc(); + read_filename_to_netname(global_network, read_filename); + po_list = lsCreate(); + equation_setup_file(fp); + (void) yyparse(); + + if (!read_check_io_list(global_network, po_list)) { + network_free(global_network); + return 0; + } + read_hack_outputs(global_network, po_list); + LS_ASSERT(lsDestroy(po_list, (void (*)()) 0)); + + if (! network_is_acyclic(global_network)) { + network_free(global_network); + return 0; + } + + return global_network; + } +} + +network_t * +read_eqn_string(s) +char *s; +{ + error_init(); + + if (setjmp(jmpbuf)) { + /* syntax error -- return from yyerror() */ + LS_ASSERT(lsDestroy(po_list, (void (*)()) 0)); + network_free(global_network); + return 0; + + } else { + global_network = network_alloc(); + po_list = lsCreate(); + equation_setup_string(s); + (void) yyparse(); + + if (!read_check_io_list(global_network, po_list)) { + network_free(global_network); + return 0; + } + read_hack_outputs(global_network, po_list); + LS_ASSERT(lsDestroy(po_list, (void (*)()) 0)); + + if (! network_is_acyclic(global_network)) { + network_free(global_network); + return 0; + } + + return global_network; + } +} diff --git a/sis/io/read_kiss.c b/sis/io/read_kiss.c new file mode 100644 index 0000000..814e526 --- /dev/null +++ b/sis/io/read_kiss.c @@ -0,0 +1,235 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/read_kiss.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * + */ +#ifdef SIS +#include "sis.h" + +extern void read_error(); +extern int read_lineno; +extern char *read_filename; + +#define GETC(c,fp) (((((c) = getc(fp)) == '\n') ? read_lineno++ \ + : 0) , c) +static int +rk_read_line(str,fp) +char *str; +FILE *fp; +{ + int c; + +top: + while (GETC(c,fp) != EOF && isspace(c)) { + } + + if (c == EOF) { + return(EOF); + } + if (c == '#') { + while (GETC(c,fp) != EOF && c != '\n') { + } + goto top; + } + + do { + *str++ = c; + } while (GETC(c,fp) != EOF && c != '\n'); + + --str; + while (isspace(*str)) { + --str; + } + + str[1] = '\0'; + return(!EOF); +} + +int +read_kiss(f, g) +FILE *f; +graph_t **g; +{ + int c, index, num; + int status[4]; + char buf[512],err[512]; + static char *errmsg[] = {"inputs","products","states","outputs"}; + + int products,states, num_i, num_o; + st_table *state_table; + graph_t *stg; + char input[512],state[512],next[512],output[512]; + char *temp; + char start[512]; + vertex_t *instate, *outstate; + vertex_t *v; + edge_t *e; + lsGen gen; + extern int stg_testing; + + state_table = st_init_table(strcmp,st_strhash); + stg = stg_alloc(); + + status[0] = 0; + status[1] = 0; + status[2] = 0; + status[3] = 0; + + start[0] = '\0'; + while (rk_read_line(buf,f) != EOF) { + if (*buf != '.') { + break; + } + if (buf[1] == 'r') { + if (sscanf(buf, "%s %s", err, start) != 2) { + (void) sprintf(err, "Missing argument to header option .r"); + goto bad_exit; + } + } else { + if (isspace(buf[2])) { + c = buf[1]; + switch(c) { + case 'i': index = 0; break; + case 'p': index = 1; break; + case 's': index = 2; break; + case 'o': index = 3; break; + default: (void) sprintf(err,"Invalid header option .%c",c); + goto bad_exit; + } + if (status[index] != 0) { + (void) sprintf(err,"Header option .%c specified twice",c); + goto bad_exit; + + } + if (sscanf(buf,"%s %d",err,&num) != 2 || num < 1) { + (void) sprintf(err,"Missing/bad argument to header option .%c",c); + goto bad_exit; + } + status[index] = num; + } + else { + (void) fprintf(miserr, "%s\n", buf); + continue; + } + } + } + + /* index 1 and 2 are optional */ + if (status[0] == 0) { + (void) sprintf(err,"%s not specified in header",errmsg[0]); + goto bad_exit; + } else if (status[3] == 0) { + (void) sprintf(err,"%s not specified in header",errmsg[3]); + goto bad_exit; + } + + products = states = 0; + + do { + if(buf[0] == '.'){ /* end of state table */ + if(buf[1] != 'e'){ + (void)sprintf(err, "kiss input must end with .end_kiss\n reading aborted"); + goto bad_exit; + } else break; + } + + if (sscanf(buf,"%s %s %s %s %s",input,state,next,output,err) != 4) { + (void) sprintf(err,"Invalid line: %s",buf); + goto bad_exit; + } + if (!st_lookup(state_table,state,(char **) &instate)) { + instate = g_add_vertex_static(stg); + states++; + temp = util_strsav(state); + g_set_v_slot_static(instate,STATE_STRING,(gGeneric) temp); + g_set_v_slot_static(instate,ENCODING_STRING, (gGeneric) 0); + (void) st_insert(state_table,temp,(char *) instate); + } + if (!st_lookup(state_table,next,(char **) &outstate)) { + outstate = g_add_vertex_static(stg); + states++; + temp = util_strsav(next); + g_set_v_slot_static(outstate,STATE_STRING,(gGeneric) temp); + g_set_v_slot_static(outstate,ENCODING_STRING,(gGeneric) 0); + (void) st_insert(state_table,temp,(char *) outstate); + } + if (products == 0 && start[0] == '\0') { + g_set_g_slot_static(stg,START,(gGeneric) instate); + g_set_g_slot_static(stg,CURRENT,(gGeneric) instate); + (void) strcpy(start, stg_get_state_name(instate)); + } + if (products == 0) { + num_i = strlen(input); + num_o = strlen(output); + } + if (strlen(input) != num_i) { + (void) sprintf(err,"\nInvalid number of inputs, line: %s",buf); + goto bad_exit; + } + if (strlen(output) != num_o) { + (void) sprintf(err,"\nInvalid number of outputs, line: %s",buf); + goto bad_exit; + } + e = g_add_edge_static(instate,outstate); + g_set_e_slot_static(e,INPUT_STRING,(gGeneric) util_strsav(input)); + g_set_e_slot_static(e,OUTPUT_STRING,(gGeneric) util_strsav(output)); + products++; + } while (rk_read_line(buf,f) != EOF); + + if (status[0] != num_i) { + (void) fprintf(sisout, "Number of inputs given is not correct.\n"); + (void) fprintf(sisout, ".i line ignored\n"); + } + if (status[3] != num_o) { + (void) fprintf(sisout, "Number of outputs given is not correct.\n"); + (void) fprintf(sisout, ".o line ignored\n"); + } + g_set_g_slot_static(stg,NUM_INPUTS,(gGeneric) num_i); + g_set_g_slot_static(stg,NUM_OUTPUTS,(gGeneric) num_o); + g_set_g_slot_static(stg,NUM_STATES,(gGeneric) states); + g_set_g_slot_static(stg,NUM_PRODUCTS,(gGeneric) products); + + if (start[0] != '\0') { + if (!strcmp(start, "ANY") || !strcmp(start, "*")) { + stg_foreach_state(stg, gen, v) { + temp = stg_get_state_name(v); + if ((strcmp(temp, "ANY")) && (strcmp(temp, "*"))) { + g_set_g_slot_static(stg, START, (gGeneric) v); + g_set_g_slot_static(stg, CURRENT, (gGeneric) v); + lsFinish(gen); + break; + } + } + } else { + if ((v = stg_get_state_by_name(stg, start)) == NIL(vertex_t)) { + (void) sprintf(err, "Start state given is not a valid state"); + goto bad_exit; + } + g_set_g_slot_static(stg, START, (gGeneric) v); + g_set_g_slot_static(stg, CURRENT, (gGeneric) v); + } + } + + if (!stg_check(stg)) { + (void) sprintf(err, "STG failed stg_check\n"); + goto bad_exit; + } + + st_free_table(state_table); + + *g = stg; + return 1; + +bad_exit: + read_error(err); + st_free_table(state_table); + stg_free(stg); + stg = NIL(graph_t); + *g = NIL(graph_t); + return 0; +} +#endif /* SIS */ diff --git a/sis/io/read_pla.c b/sis/io/read_pla.c new file mode 100644 index 0000000..ae785f6 --- /dev/null +++ b/sis/io/read_pla.c @@ -0,0 +1,49 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/read_pla.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * + */ +#include "sis.h" +#include "io_int.h" + +network_t * +sis_read_pla(fp, single_output) +FILE *fp; +int single_output; +{ + pPLA PLA; + network_t *network; + network_t *dc_network; + + if ((PLA = espresso_read_pla(fp)) == 0) { + return 0; + } + if (single_output) { + if ((network = pla_to_network_single(PLA)) != 0) { + read_filename_to_netname(network, read_filename); + dc_network = pla_to_dcnetwork_single(PLA); + if (dc_network != NIL (network_t)){ + read_filename_to_netname(dc_network, read_filename); + network_sweep(dc_network); + network_collapse(dc_network); + } + network->dc_network = dc_network; + } + } else { + if ((network = pla_to_network(PLA)) != 0) { + read_filename_to_netname(network, read_filename); + dc_network = pla_to_dcnetwork_single(PLA); + if (dc_network != NIL (network_t)){ + read_filename_to_netname(dc_network, read_filename); + } + network->dc_network = dc_network; + } + } + discard_pla(PLA); + + return network; +} diff --git a/sis/io/read_slif.c b/sis/io/read_slif.c new file mode 100644 index 0000000..2d6b141 --- /dev/null +++ b/sis/io/read_slif.c @@ -0,0 +1,680 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/read_slif.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/14 08:35:22 $ + * + */ +#ifdef SIS + +#include "sis.h" +#include "io_int.h" + +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +#define INCLUDE_MAX 6 /* max include nesting */ + +static int read_slif_nodelist(); +static int read_slif_latch(); + +static int +read_statement(fp,str,len) +FILE *fp; +char *str; +int len; +{ + int c, last, count; + char *start = str; + + last = ' '; + count = 0; + len -= 3; /* safety margin */ + + while (count < len && (c = getc(fp)) != EOF) { + if (c == '#') { + while ((c = getc(fp)) != EOF && c != '\n') { + } + if (c == EOF) { + return(EOF); + } + /* fall into isspace */ + } + if (isspace(c)) { + if (c == '\n') { + read_lineno++; + } + if (last == ' ') { + continue; + } + c = ' '; + } + else if (c == ';') { + if (count > 0 && *start == '.') { /* command: throw out ';' */ + if (last == ' ') { + str--; + } + } + else { /* eqn: keep ';' */ + *str++ = ';'; + } + *str = '\0'; + return(!EOF); + } + else if (c == '(' || c == ')' || c == ',') { + if (last != ' ') { + *str++ = ' '; count++; + } + *str++ = c; *str++ = ' '; count += 2; last = ' '; + continue; + } + *str++ = c; count++; last = c; + } + if (count != 0) { + read_error("incomplete last line"); + } + return(EOF); +} + +typedef struct { + FILE *fp; + int lineno; + char *name; +} slif_context; + +/* + * Returns: + * 0 if encountered an error. + * 1 otherwise + * + * If first_model = NIL(network_t *) then first_model points to the + * first model in the file. If no models were encountered, then + * first_model points to NIL(network_t). + */ +static int +read_slif_loop(fp, models, search_files, first_model) +FILE *fp; +st_table *models, *search_files; +network_t **first_model; +{ + int in_model, include_depth, have_function, i, exit_status, global; + char line[MAX_WORD], buf[MAX_WORD]; + slif_context saved_context[INCLUDE_MAX], *save; + modelinfo *entry; + char *command, *arg1, *name, *rest; + network_t *network, *net; + node_t *node, *po, *n2, *n3; + lsList po_list; + lsGen gen; + + in_model = 0; + include_depth = 0; + network = NIL(network_t); + exit_status = 1; + + if (first_model != NIL(network_t *)) { + *first_model = NIL(network_t); + } + + while ((i = read_statement(fp, line, sizeof(line))) != EOF || include_depth > 0) { + if (i == EOF) { + + /* restore context on end of include file */ + + FREE(read_filename); + if (fp != stdin) { + (void) fclose(fp); + } + save = &saved_context[--include_depth]; + fp = save->fp; + read_lineno = save->lineno; + read_filename = save->name; + } + + else if (*line == ';' || *line == '\0') { + read_error("null statement"); + } + else if (*line == '.') { + command = gettoken(line, NIL(char *)); /* get first word in line */ + command++; /* skip past initial '.' */ + arg1 = gettoken(NIL(char), &rest); /* next token */ + + /* These commands can appear outside of model declaration */ + + if (strcmp(command, "model") == 0) { + if (in_model != 0) { + read_error(".model encountered within another .model"); + exit_status = 0; + break; + } + if (arg1 == NIL(char)) { + read_error("missing name in .model construct"); + exit_status = 0; + break; + } + + entry = read_find_or_create_model(arg1, models); + + if (entry->network != NIL(network_t)) { + read_error("model %s already defined", arg1); + exit_status = 0; + break; + } + + entry->network = network_alloc(); + network_set_name(entry->network, arg1); /* auto strsav */ + + in_model = 1; + network = entry->network; + po_list = entry->po_list; + + if (first_model != NIL(network_t *) && *first_model == NIL(network_t)) { + *first_model = network; + } + } + + else if (strcmp(command, "include") == 0) { + if (include_depth >= INCLUDE_MAX) { + read_error("maximum include depth exceeded"); + exit_status = 0; + break; + } + if (arg1 == NIL(char)) { + read_error("no file name specified after .include"); + exit_status = 0; + break; + } + + /* + * Save current context, then treat the include file as if it + * were a part of this file. + */ + save = &saved_context[include_depth++]; + save->fp = fp; + save->lineno = read_lineno; + save->name = read_filename; + + fp = com_open_file(arg1, "r", &name, 1); + + if (fp == NIL(FILE)) { + FREE(name); + read_error("include file %s not found", arg1); + exit_status = 0; + break; + } + read_lineno = 1; + read_filename = name; + } + + else if (strcmp(command, "search") == 0) { + exit_status = read_search_file(arg1, models, search_files, + read_slif_loop); + if (exit_status == 0) { /* propagate an error */ + break; + } + } + + /* must be inside a model for all following commands */ + + else if (in_model == 0) { + read_error("Illegal statement outside of .model: %s", line); + exit_status = 0; + break; + } + + else { + if (!strcmp(command, "attribute") || !strcmp(command, "global_attribute")) { + if (arg1 == NIL(char)) { + read_error("no attribute type specified"); + exit_status = 0; + break; + } + global = (strcmp(command, "global_attribute") == 0); + i = read_delay(network, po_list, arg1, rest, global + 10); + if (i < 1) { + if (i == -1) { + read_error("illegal %s: %s", command, rest); + } + exit_status = 0; + break; + } + } + + else if (strcmp(command, "call") == 0) { + if (read_slif_call(fp, network, models, arg1) == 0) { + exit_status = 0; + break; + } + entry->depends_on++; + } + + else if (strcmp(command, "endmodel") == 0) { + in_model = 0; /* not in a model def anymore */ + if (entry->library == 1 && lsLength(po_list) != 1) { + read_error("library module can only have 1 primary output"); + exit_status = 0; + } + } + + else if (strcmp(command, "inouts") == 0) { + read_error("inouts not allowed"); + exit_status = 0; + break; + } + + else if (strcmp(command, "inputs") == 0) { + while (arg1 != NIL(char)) { + node = read_find_or_create_node(network, arg1); + if (node_function(node) != NODE_UNDEFINED) { + read_error("node %s multiply defined", arg1); + exit_status = 0; + break; + } + network_change_node_type(network, node, PRIMARY_INPUT); + arg1 = gettoken(NIL(char),NIL(char *)); + } + } + + else if (strcmp(command, "library") == 0) { + entry->library = 1; + continue; + } + + else if (strcmp(command, "net") == 0) { + node = NIL(node_t); + have_function = 0; + + while (arg1 != NIL(char)) { + n2 = read_slif_find_or_create_node(network, arg1, 0); + if (node == NIL(node_t)) { + node = n2; + } + else { + if (node_function(n2) != NODE_UNDEFINED) { + if (have_function == 1) { + (void) strcpy(buf, node_name(node)); + read_error(".net: %s & %s already have functions", + buf, node_name(n2)); + exit_status = 0; + break; + } + have_function = 1; + n3 = n2; n2 = node; node = n3; + } + + /* make n2 (no node func) = node (possibly node func) */ + + n3 = node_literal(node, 1); + node_replace(n2, n3); + } + arg1 = gettoken(NIL(char), NIL(char *)); + } + } + + else if (strcmp(command, "outputs") == 0) { + while (arg1 != NIL(char)) { + node = read_find_or_create_node(network, arg1); + (void) lsNewEnd(po_list, (lsGeneric) node, LS_NH); + arg1 = gettoken(NIL(char), NIL(char *)); + } + } + + else { + (void) fprintf(siserr, "\"%s\", line %d: %s ignored\n", + read_filename, read_lineno, command - 1); + } + } + } + else { + if (in_model == 0) { + read_error("Illegal statement outside of .model: %s", line); + exit_status = 0; + break; + } + name = strchr(line, '@'); + if (name != NIL(char)) { /* found a latch */ + if (read_slif_latch(network, line, name) == 0) { + exit_status = 0; + break; + } + continue; + } + name = read_filename; + i = read_lineno; + read_filename = NIL(char); + net = read_eqn_string(line); + read_filename = name; + read_lineno = i; + + if (net == NIL(network_t)) { + read_error("%s", line); + exit_status = 0; + break; + } + + po = network_get_po(net, 0); + node = read_find_or_create_node(network, node_long_name(po)); + + po = node_get_fanin(po, 0); + n3 = node_dup(po); + node_replace(node, n3); /* new node = old po */ + + if (node_num_fanin(po) != 0) { /* not constant */ + foreach_primary_input (net, gen, n2) { + n3 = read_find_or_create_node(network, node_long_name(n2)); + (void) node_patch_fanin(node, n2, n3); + } + } + + network_free(net); + } + } + if (exit_status != 0 && in_model != 0) { + read_error("Missing .endmodel"); + exit_status = 0; + } + + while (include_depth > 0) { /* unwind any saved stacks */ + FREE(read_filename); + if (fp != stdin) { + (void) fclose(fp); + } + save = &saved_context[--include_depth]; + fp = save->fp; + read_filename = save->name; + } + return(exit_status); +} + +network_t * +read_slif(fp) +FILE *fp; +{ + network_t *network; + + if (read_blif_slif(fp, &network, read_slif_loop) != 1) { + return(NIL(network_t)); + } + read_cleanup_buffers(network); + return(network); +} + +/* + * 0 error + * 1 no error + */ +int +read_slif_call(fp, network, models, name) +FILE *fp; +network_t *network; +st_table *models; +char *name; +{ + char *word, *last, line[MAX_WORD]; + array_t *actuals; + char *rest; + int error_stat, inputs, inouts; + modelinfo *ent; + patchinfo *patch; + + /* + * get the last argument before the '(' as the model name. + */ + + if (name == NIL(char)) { + read_error("missing model name for call"); + return(0); + } + last = name; + while ((word = gettoken(NIL(char), &rest)) != NIL(char)) { + if (*word == '(') { + name = last; + break; + } + else { + last = word; + } + } + + ent = read_find_or_create_model(name, models); /* entry for called */ + + patch = ALLOC(patchinfo, 1); + patch->actuals = NIL(array_t); + patch->formals = NIL(char *); + patch->inputs = 0; + patch->netname = network_name(network); + (void) lsNewEnd(ent->patch_lists, (lsGeneric) patch, LS_NH); + + actuals = array_alloc(node_t *, 10); + error_stat = 1; + inputs = read_slif_nodelist(network, rest, actuals, 0 /* input */); + + if (read_statement(fp, line, MAX_WORD) == EOF) { + read_error("ran out of arguments in .call"); + error_stat = 0; + } + else { + inouts = read_slif_nodelist(network, line, actuals, 0 /* anything */); + if (inouts != 0) { + read_error("no inouts allowed"); + error_stat = 0; + } + else if (read_statement(fp, line, MAX_WORD) == EOF) { + read_error("ran out of arguments in .call"); + error_stat = 0; + } + else { + (void) read_slif_nodelist(network, line, actuals, 1 /* output */); + } + } + + if (error_stat == 0) { + array_free(actuals); + } + else { + patch->actuals = actuals; + patch->inputs = inputs; + } + return(error_stat); +} + +static int +read_slif_nodelist(network, line, actuals, flag) +network_t *network; +char *line; +array_t *actuals; +int flag; /* Describes the configuration depending on context to be */ + /* created for complemented nodes encountered */ +{ + node_t *node; + char *word = strtok(line, " ,"); + int i = 0; + + while (word != NIL(char)) { + if (*word == ')' || *word == ';') { + break; + } + node = read_slif_find_or_create_node(network, word, flag); + array_insert_last(node_t *, actuals, node); + word = strtok(NIL(char), " ,"); + i++; + } + return(i); +} + +static int +read_slif_latch(net, line, pos) +network_t *net; +char *line, *pos; +{ + + char *word, *rest; + node_t *input, *output, *clock, *hack_po, *enable, *n1, *n2, *n3, *n4; + array_t *array; + int i; + latch_t *latch; + sis_clock_t *ck; + + pos++; + if (*pos == 'T') { + read_error("T flip flop not supported"); + return(0); + } + if (*pos != 'D') { + read_error("unknown flip flop: %s", pos); + return(0); + } + word = gettoken(line, &rest); + if (*rest != '=') { + +bad_format: + read_error("bad format for latch"); + return(0); + } + output = read_slif_find_or_create_node(net, word, 1); + + do { + pos++; + } while (*pos != '\0' && *pos != '('); + + if (pos == '\0') { + goto bad_format; + } + + array = array_alloc(node_t *, 0); + + i = read_slif_nodelist(net, ++pos, array, 0); + if (i < 2 || i > 3) { + read_error("invalid number of inputs to D flip flop"); + array_free(array); + return(0); + } + + input = array_fetch(node_t *, array, 0); + clock = array_fetch(node_t *, array, 1); + if (i == 3) { + enable = array_fetch(node_t *, array, 2); + } + array_free(array); + + if (node_type(output) == PRIMARY_INPUT || output->F != 0) { + read_error("latch output %s is already defined", node_name(output)); + return(0); + } + + network_change_node_type(net, output, PRIMARY_INPUT); + + if (i == 3) { /* enabled latch--fiddle w/ data input */ + n1 = node_literal(enable, 1); + n2 = node_literal(input, 1); + n3 = node_and(n1, n2); + node_free(n1); + node_free(n2); + + n1 = node_literal(enable, 0); + n2 = node_literal(output, 1); + n4 = node_and(n1, n2); + node_free(n1); + node_free(n2); + + input = node_or(n3, n4); /* enable input + enable' output */ + node_free(n3); + node_free(n4); + + network_add_node(net, input); + read_change_madeup_name(net, input); + } + + hack_po = network_add_fake_primary_output(net, input); + read_change_madeup_name(net, hack_po); + + n1 = network_get_control(net, clock); + if (n1 == NIL(node_t)) { + n1 = network_add_fake_primary_output(net, clock); + read_change_madeup_name(net, n1); + } + + if (node_type(clock) == PRIMARY_INPUT) { + ck = clock_get_by_name(net, node_long_name(clock)); + if (ck == NIL(sis_clock_t)) { + ck = clock_create(node_long_name(clock)); + (void) clock_add_to_network(net, ck); + } + } + + network_create_latch(net, &latch, hack_po, output); + latch_set_initial_value(latch, 0); + latch_set_current_value(latch, 0); + latch_set_type(latch, RISING_EDGE); + + latch_set_control(latch, n1); + + return(1); +} + + +#define DEFAULT_DELAY_ENTRY "INV 1 999 1 .2 1 .2" + + +/* + * 0 error + * 1 ok + */ +int +slif_add_to_library(network) +network_t *network; +{ + FILE *fp; + char *name, buf[128]; + node_t *node; + double input, area; + lsGen gen; + int line = read_lineno; + static char *phasename[] = {"INV", "NONINV", "UNKNOWN"}; + char stempname[20]; + int sfd; + + (void) network_collapse(network); + strcpy(stempname, "/tmp/fileXXXXXX"); + sfd = mkstemp(stempname); + fp = fdopen(sfd, "w+"); + if (fp == NIL(FILE)) { + read_error("error opening temporary file"); + return(0); + } + + area = (network->area_given == 0) ? 1 : network->area; + (void) fprintf(fp, "GATE\t\"%s\"\t%g\t", network_name(network), area); + + node = node_get_fanin(network_get_po(network, 0), 0); + write_sop(fp, node, 0, 1); + + foreach_primary_input (network, gen, node) { + (void) fprintf(fp, "PIN\t%s ", node_long_name(node)); + input = delay_get_parameter(node, DELAY_INPUT_LOAD); + if (input == DELAY_NOT_SET) { + (void) fprintf(fp, "%s\n", DEFAULT_DELAY_ENTRY); + } + else { + (void) fprintf(fp, "%s %g %g %g %g %g %g\n", + phasename[(int) delay_get_parameter(node, DELAY_PHASE)], + input, + delay_get_parameter(node, DELAY_MAX_INPUT_LOAD), + delay_get_parameter(node, DELAY_BLOCK_RISE), + delay_get_parameter(node, DELAY_DRIVE_RISE), + delay_get_parameter(node, DELAY_BLOCK_FALL), + delay_get_parameter(node, DELAY_DRIVE_FALL)); + } + } + (void) fclose(fp); + (void) sprintf(buf, "read_library -a %s", name); + (void) com_execute(&network, buf); + (void) unlink(name); + read_lineno = line; + return(1); +} + +#endif /* SIS */ diff --git a/sis/io/read_util.c b/sis/io/read_util.c new file mode 100644 index 0000000..87b5dea --- /dev/null +++ b/sis/io/read_util.c @@ -0,0 +1,1673 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/read_util.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/02/09 07:06:12 $ + * + */ +#include "sis.h" +#include "io_int.h" + +/* from map/map_int.h */ +extern lib_gate_t *choose_smallest_gate(); + +int read_lineno; +char *read_filename; +void dc_network_check(); + +static int is_in_list(); +static void compute_relax(); +static int read_special_case_for_stg(); +static void node_map_copy(); + +/* no changes allowed to rcil, re, rftn, rfocn, rho, rrf */ + +/*VARARGS1*/ +void +read_error(char *fmt, ...) +{ + va_list args; + char buf[MAX_WORD]; + + va_start(args, fmt); + if (read_filename != NIL(char)) { + (void) sprintf(buf, "\"%s\", line %d: ", read_filename, read_lineno); + error_append(buf); + } + (void) vsprintf(buf, fmt, args); + error_append(buf); + error_append("\n"); + va_end(args); +} + + +void +read_register_filename(fname) +char *fname; +{ + read_lineno = 1; + if (read_filename != NIL(char)) { + FREE(read_filename); + } + read_filename = fname ? util_strsav(fname) : 0; +} + +/* + * HACK to support the user specifying manes with trailing "'". + * Depending on the context can do two things (hence the flag) + * Assume that the string s == "foo'" then + * If flag == 0 then ( node = foo; foo' = !node;) + * If flag == 1 then ( node = foo'; foo = !node;) + * + * Flag == 1 essentially when the output of a call is named "name'" + */ +node_t * +read_slif_find_or_create_node(network, s, flag) +network_t *network; +char *s; +int flag; +{ + int len; + int complement = FALSE; + node_t *node, *pos_node, *temp_node; + + len = strlen(s); + if (len > 1 && s[len-1] == '\047'){ + complement = TRUE; + } + if ((node = network_find_node(network, s)) == 0) { + if (complement){ + /* First search for the node with the positive function */ + s[len-1] = '\0'; + pos_node = read_find_or_create_node(network, s); + s[len-1] = '\047'; + } + if (complement && !flag){ + node = node_literal(pos_node, 0); + } else { + node = node_alloc(); + } + node->name = util_strsav(s); + network_add_node(network, node); + if (complement && flag){ + temp_node = node_literal(node, 0); + node_replace(pos_node, temp_node); + } + } + /* + * need to recognize names "0" and "1" as constants. These nodes have + * been given names "0" and "1" and so we will not duplicate them on + * successive references. + */ + if (strcmp(s, "0") == 0){ + temp_node = node_constant(0); + node_replace(node, temp_node); + } else if (strcmp(s, "1") == 0){ + temp_node = node_constant(1); + node_replace(node, temp_node); + } + + if(node_type(node) == PRIMARY_OUTPUT) + node = node_get_fanin(node, 0); + return node; +} + +node_t * +read_find_or_create_node(network, s) +network_t *network; +char *s; +{ + node_t *node; + + if ((node = network_find_node(network, s)) == 0) { + node = node_alloc(); + node->name = util_strsav(s); + network_add_node(network, node); + } + if(node_type(node) == PRIMARY_OUTPUT) + node = node_get_fanin(node, 0); + return node; +} + +#ifdef SIS +/* + * Go change the internal node name to make sure that the name cannot clash + * with user names that might come later. Does this by putting a " " as the + * first character of the name. + */ +void +read_change_madeup_name(network, node) +network_t *network; +node_t *node; +{ + char buf[32]; + int index; + + if (node_is_madeup_name(node_long_name(node), &index)) { + (void) sprintf(buf, " %d", index); + network_change_node_name(network, node, util_strsav(buf)); + } +} +#endif /* SIS */ + +int +read_check_io_list(network, po_list, print_warning) +network_t *network; +lsList po_list; +int print_warning; +{ + int relax_i, relax_o; + node_t *node; + lsGen gen; + node_type_t type; + lib_gate_t *gate; + char *error; + int mapped_flag = 0; + + /* Check for nodes not driven or not faning out */ + /* check if .inputs or .outputs not specified */ + + (void) compute_relax(network, po_list, &relax_i, &relax_o); + + if (lib_network_is_mapped(network)) mapped_flag = 1; + foreach_node (network, gen, node) { + type = node_type(node); + if (node->F == 0 && type == INTERNAL) { + if (relax_i != 0) { + network_change_node_type(network, node, PRIMARY_INPUT); + } + else { + if (print_warning) + read_error("Warning: network `%s', node \"%s\" is not driven (zero assumed)", + network_name(network), io_node_name(node)); + node_replace(node, node_constant(0)); + if (mapped_flag) { + error = util_strsav(error_string()); + gate = choose_smallest_gate(lib_get_library(), "f=0;"); + error_init(); + error_append(error); + if (gate == NIL(lib_gate_t)) { + error_append("Unable to map constant 0 node\n"); + return 0; + } else { + lib_set_gate(node, gate, NIL(char *), NIL(node_t *), 0); + } + } + } + } + else if (type != PRIMARY_OUTPUT && node_num_fanout(node) == 0 && + is_in_list(po_list, node) == 0) { + if (relax_o != 0) { + (void) lsNewEnd(po_list, (lsGeneric) node, LS_NH); + } + else { + if (print_warning) + read_error("Warning: network `%s', node \"%s\" does not fanout", + network_name(network), io_node_name(node)); + } + } + } + return 1; +} + +void +read_hack_outputs(network, po_list) +network_t *network; +lsList po_list; +{ + lsGen gen; + node_t *po, *node; + char *name, *po_name; + + /* hack the primary outputs -- create the real PO nodes */ + + lsForeachItem(po_list, gen, node) { + po = network_add_primary_output(network, node); +#ifdef SIS + if (node->type == PRIMARY_INPUT && + network_latch_end(node) == NIL(node_t)){ +#else + if (node->type == PRIMARY_INPUT) { +#endif + po_name = node_long_name(po); + name = ALLOC(char, strlen(po_name)+4); + (void)sprintf(name, "IN-%s", po_name); + (void) fprintf(siserr, "Warning: input and output named \"%s\": renaming input \"%s\"\n", + po_name, name); + network_change_node_name(network, node, name); + } + } +} + +/* + * remove technology independent buffers that are inputs to PO nodes + * EXCEPTION CONDITION FOR SIS: + * We want to retain the buffers if the latch output (PI node "fanin") + * could be input to the exdc network. We want the buffer to provide proper + * naming for the latch output (it could be feeding a true primary output) + */ +void +read_cleanup_buffers(network) +network_t *network; +{ + + int i; + lsGen gen, gen1; + node_t *po, *node, *fanin, *fo, **fo_array; + + foreach_primary_output(network, gen, po){ + node = node_get_fanin(po, 0); + if (node_function(node) == NODE_BUF && + lib_gate_of(node) == NIL(lib_gate_t)) { + fanin = node_get_fanin(node, 0); +#ifdef SIS + if ((network_latch_end(fanin) == NIL(node_t))){ +#endif /* SIS */ + fo_array = ALLOC(node_t *, node_num_fanout(node)); + i = 0; + foreach_fanout(node, gen1, fo) { + fo_array[i++] = fo; + } + for (; i-- > 0;) { + assert(node_patch_fanin(fo_array[i], node, fanin)); + } + FREE(fo_array); + network_delete_node(network, node); +#ifdef SIS + } +#endif /* SIS */ + } + } +} + + +#ifdef SIS +void +read_check_control_signals(network) +network_t *network; +{ + lsGen gen; + latch_t *latch; + node_function_t func; + node_t *control, *node; + char *name; + st_table *table; + + table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_latch (network, gen, latch) { + control = latch_get_control(latch); + if (control != NIL(node_t)) { + if (!st_is_member(table, (char *)control)) { + node = node_get_fanin(control, 0); + func = node_function(node); + if (func == NODE_1 || func == NODE_0) { + read_error("Warning: network `%s', latch control `%s' is constant (disconnecting)", + network_name(network), io_node_name(control)); + latch_set_control(latch, NIL(node_t)); + (void) st_insert(table, (char *)control, NIL(char)); + name = util_strsav(node_long_name(control)); + network_delete_node(network, control); + network_change_node_name(network, node, name); + } + } else { + latch_set_control(latch, NIL(node_t)); + } + } + } + st_free_table(table); +} +#endif /* SIS */ + +static int +is_in_list(list, node) +lsList list; +node_t *node; +{ + node_t *p; + lsGen gen; + + lsForeachItem(list, gen, p) { + if (p == node) { + LS_ASSERT(lsFinish(gen)); + return 1; + } + } + return 0; +} + +void +read_filename_to_netname(network, filename) +network_t *network; +char *filename; +{ + char *name, *base; + + base = strrchr(filename, '/'); + name = (base == 0) ? filename : base + 1; + network_set_name(network, name); +} + +static void +compute_relax(network, po_list, prelax_i, prelax_o) +network_t *network; +lsList po_list; +int *prelax_i, *prelax_o; +{ + lsGen gen; + node_t *pi; + + *prelax_i = 1; + + /* + * If any real PIs exist, then .inputs were specified. + */ + foreach_primary_input (network, gen, pi) { +#ifdef SIS + if (network_is_real_pi(network, pi) != 0 && + clock_get_by_name(network, node_long_name(pi)) == 0) { +#endif /* SIS */ + *prelax_i = 0; + (void) lsFinish(gen); + break; +#ifdef SIS + } +#endif /* SIS */ + } + *prelax_o = (lsLength(po_list) == 0); +} + +/* + * Returns the next space seperated word in the string `str'. + * Duplicates function of strtok, but returns pointer to rest of string + * if `rest' is non-null. + */ +char * +gettoken(str, rest) +char *str, **rest; +{ + static char *r = NIL(char); + + if (str == NIL(char)) { + str = r; + if (r == NIL(char)) { + return(NIL(char)); + } + } + else { + r = str; + if (*r == '\0') { + r = NIL(char); + return(NIL(char)); + } + } + + do { /* skip to next blank */ + r++; + } while (*r != '\0' && *r != ' '); + + if (*r == '\0') { /* end of string */ + r = NIL(char); + } + else { + *r++ = '\0'; + } + if (rest != NIL(char *)) { + *rest = r; + } + return(str); +} + +/************** read_delay **************/ + +static void read_delay_set_parameters(); +static node_t *read_input_node(); +static node_t *read_output_node(); +static int read_delay_common(); + +/* + * check a blif keyword for a delay-related keyword OR + * check a slif global or local attribute + * + * returns -1 if not delay related, 0 if delay-related and an error occured, + * or 1 if delay-related and no error. + * + * `slif_global' packs two binary values into one var (# is in decimal) + * `slif_global' = 00 ==> not reading slif + * = 10 ==> slif, .attribute + * = 11 ==> slif, .global_attribute + */ +int +read_delay(network, po_list, word, rest, slif_global) +network_t *network; +lsList po_list; +char *word, *rest; +int slif_global; +{ + double br, bf, dr, df; + double area, load, max_load, phase; + node_t *node; + int def; + lsGen gen; + delay_param_t d1, d2; + + if (strcmp(word, "area") == 0 || strcmp(word, "cost") == 0) { + if (slif_global == 10) { + read_error("area is a global attribute"); /* slif error */ + return(0); + } + if (sscanf(rest, "%lf", &area) != 1) { + read_error("error reading number after area"); + return(0); + } + if (network->area_given) { + read_error("area given twice for same model"); + return(0); + } + network->area_given = 1; + network->area = area; + return(1); + } + + else if (strcmp(word, "delay") == 0) { + if (slif_global == 11) { /* set delay for all inputs */ + } + else { /* current arg is the one to set */ + node = read_input_node(&rest, network, word); + if (node == NIL(node_t)) { + return(0); + } + } + if (sscanf(rest, "%s %lf %lf %lf %lf %lf %lf", word, &load, &max_load, + &br, &dr, &bf, &df) != 7) { + read_error("need phase, load, max_load, and 4 delay values in delay"); + return(0); + } + if (strcmp(word, "INV") == 0) { + phase = DELAY_PHASE_INVERTING; + } + else if (strcmp(word, "NONINV") == 0) { + phase = DELAY_PHASE_NONINVERTING; + } + else if (strcmp(word, "UNKNOWN") == 0) { + phase = DELAY_PHASE_NEITHER; + } + else { + read_error("bad phase specification in .delay"); + return(0); + } + + if (slif_global == 11) { + foreach_primary_input (network, gen, node) { + read_delay_set_parameters(node, br, bf, dr, df, load, + max_load, phase); + } + } + else { + read_delay_set_parameters(node, br, bf, dr, df, load, max_load, + phase); + } + return(1); + } + + else if (strcmp(word, "wire_load_slope") == 0) { + if (slif_global == 10) { + read_error("wire_load_slope is a global attribute"); + } + if (sscanf(rest, "%lf", &load) != 1) { + read_error("expect load value in wire_load_slope"); + return(0); + } + delay_set_default_parameter(network, DELAY_WIRE_LOAD_SLOPE, load); + return(1); + } + + else if (strcmp(word, "wire") == 0 ) { + /* discard any existing wire load table */ + delay_set_default_parameter(network, DELAY_ADD_WIRE_LOAD, -1.0); + + /* read the wire loads */ + while ((word = gettoken(NIL(char), NIL(char *))) != NIL(char)) { + load = atof(word); + delay_set_default_parameter(network, DELAY_ADD_WIRE_LOAD, load); + } + return(1); + } + + else { + if (strncmp(word, "default_", 8) == 0) { + def = 1; + word += 8; + } + else { + def = (slif_global == 11); + } + + node = NIL(node_t); + if (strcmp(word, "input_arrival") == 0) { + if (def == 0) { + if ((node = read_input_node(&rest, network, word)) == 0) { + return(0); + } + d1 = DELAY_ARRIVAL_RISE; + d2 = DELAY_ARRIVAL_FALL; + } + else { + d1 = DELAY_DEFAULT_ARRIVAL_RISE; + d2 = DELAY_DEFAULT_ARRIVAL_FALL; + } +#ifdef SIS + return(read_delay_common(node, network, word, rest, 4, d1, d2)); +#else + return(read_delay_common(node, network, word, rest, 2, d1, d2)); +#endif /* SIS */ + } + + else if (strcmp(word, "output_required") == 0) { + if (def == 0) { + if ((node = read_output_node(&rest, po_list, word)) == 0) { + return(0); + } + d1 = DELAY_REQUIRED_RISE; + d2 = DELAY_REQUIRED_FALL; + } + else { + d1 = DELAY_DEFAULT_REQUIRED_RISE; + d2 = DELAY_DEFAULT_REQUIRED_FALL; + } +#ifdef SIS + return(read_delay_common(node, network, word, rest, 4, d1, d2)); +#else + return(read_delay_common(node, network, word, rest, 2, d1, d2)); +#endif /* SIS */ + } + + else if (strcmp(word, "input_drive") == 0) { + if (def == 0) { + if ((node = read_input_node(&rest, network, word)) == 0) { + return(0); + } + d1 = DELAY_DRIVE_RISE; + d2 = DELAY_DRIVE_FALL; + } + else { + d1 = DELAY_DEFAULT_DRIVE_RISE; + d2 = DELAY_DEFAULT_DRIVE_FALL; + } + return(read_delay_common(node, network, word, rest, 2, d1, d2)); + } + + else if (strcmp(word, "output_load") == 0) { + if (def == 0) { + if ((node = read_output_node(&rest, po_list, word)) == 0) { + return(0); + } + d1 = DELAY_OUTPUT_LOAD; + } + else { + d1 = DELAY_DEFAULT_OUTPUT_LOAD; + } + return(read_delay_common(node, network, word, rest, 1, d1, d2)); + } + + else if (strcmp(word, "max_input_load") == 0) { + if (def == 0) { + if ((node = read_input_node(&rest, network, word)) == 0) { + return(0); + } + d1 = DELAY_MAX_INPUT_LOAD; + } + else { + d1 = DELAY_DEFAULT_MAX_INPUT_LOAD; + } + return(read_delay_common(node, network, word, rest, 1, d1, d2)); + } + } + return(-1); +} + +static void +read_delay_set_parameters(node, br, bf, dr, df, load, max_load, phase) +node_t *node; +double br, bf, dr, df, load, max_load, phase; +{ + delay_set_parameter(node, DELAY_BLOCK_RISE, br); + delay_set_parameter(node, DELAY_BLOCK_FALL, bf); + delay_set_parameter(node, DELAY_DRIVE_RISE, dr); + delay_set_parameter(node, DELAY_DRIVE_FALL, df); + delay_set_parameter(node, DELAY_INPUT_LOAD, load); + delay_set_parameter(node, DELAY_MAX_INPUT_LOAD, max_load); + delay_set_parameter(node, DELAY_PHASE, phase); +} + +/* + * If node = NULL, then setting global attribute, otherwise setting attribute + * for that specific node. + * + * 0 error + * 1 no error + */ +/*VARARGS7*/ +static int +read_delay_common(node, network, word, rest, num, d1, d2) +node_t *node; +network_t *network; +char *word, *rest; +int num; +delay_param_t d1, d2; +{ + double v1, v2; + char befaft[MAX_WORD], edge[MAX_WORD]; + int i; +#ifdef SIS + clock_edge_t cedge; +#endif /* SIS */ + + if (rest == NIL(char)) { + read_error("wrong number arguments to %s", word); + return(0); + } + + i = sscanf(rest, "%lf %lf %s %s", &v1, &v2, befaft, edge); + if (num != i) { +#ifdef SIS + if (num != 4 || i != 2) { + read_error("wrong number arguments to %s", word); + return(0); + } +#else + read_error("wrong number arguments to %s", word); + return(0); +#endif /* SIS */ + } + +#ifdef SIS + if (i == 4) { + if (node == NIL(node_t)) { + read_error("cannot specify transition for .global_%s", word); + return(0); + } + if (*edge == 'r') { + cedge.transition = RISE_TRANSITION; + } + else if (*edge == 'f') { + cedge.transition = FALL_TRANSITION; + } + else { + read_error("transition must be `r' or `f' in %s", word); + return(0); + } + if ((cedge.clock = clock_get_by_name(network, edge + 2)) == 0) { + read_error("clock %s not found in %s", edge + 2, word); + return(0); + } + if (*befaft == 'b') { + delay_set_synch_edge(node, cedge, BEFORE_CLOCK_EDGE); + } + else if (*befaft == 'a') { + delay_set_synch_edge(node, cedge, AFTER_CLOCK_EDGE); + } + else { + read_error("synch edge must be `b' or `a' in %s", word); + return(0); + } + } +#endif /* SIS */ + if (node == NIL(node_t)) { + delay_set_default_parameter(network, d1, v1); + } + else { + delay_set_parameter(node, d1, v1); + } + if (num > 1) { + if (node == NIL(node_t)) { + delay_set_default_parameter(network, d2, v2); + } + else { + delay_set_parameter(node, d2, v2); + } + } + return(1); +} + +static node_t * +read_input_node(rest, network, errmsg) +char **rest; +network_t *network; +char *errmsg; +{ + node_t *node; + char *word; + + if ((word = gettoken(NIL(char), rest)) == NIL(char)) { + read_error("missing name in %s", errmsg); + return(NIL(node_t)); + } + node = network_find_node(network, word); + if (node == NIL(node_t) || node_type(node) != PRIMARY_INPUT) { + read_error("node '%s' not defined as input node in %s", word, errmsg); + return(NIL(node_t)); + } + return(node); +} + +static node_t * +read_output_node(rest, po_list, errmsg) +char **rest; +lsList po_list; +char *errmsg; +{ + node_t *node; + lsGen gen; + char *word; + + if ((word = gettoken(NIL(char), rest)) == NIL(char)) { + read_error("missing name in %s", errmsg); + return(NIL(node_t)); + } + lsForeachItem(po_list, gen, node) { + if (strcmp(node->name, word) == 0) { + LS_ASSERT(lsFinish(gen)); + return(node); + } + } + read_error("node '%s' not defined as output node in %s", word, errmsg); + return(NIL(node_t)); +} + + +#ifdef SIS +/********** read_delay_cleanup ***********/ + +void +read_delay_cleanup(network) +network_t *network; +{ + lsGen gen; + node_t *node, *fanin; + + /* copy any output information from its fanin to the output node */ + foreach_primary_output(network, gen, node) { + if (network_is_real_po(network, node)) { + delay_copy_terminal_constraints(node); + fanin = node_get_fanin(node, 0); + if (network_latch_end(fanin) != NIL(node_t)){ + /* + * The output required time was stored at the PI representing + * a latch output. We should scrap that setting + */ + delay_set_parameter(fanin, DELAY_ARRIVAL_RISE, DELAY_NOT_SET); + delay_set_parameter(fanin, DELAY_ARRIVAL_FALL, DELAY_NOT_SET); + } + } + } +} + + +int +read_search_file(filename, models, search_files, reader) +char *filename; +st_table *models, *search_files; +int (*reader)(); +{ + char *name; + FILE *fp; + int line, status; + network_t *dummy; + + if (filename == NIL(char)) { + read_error("missing file name for search"); + return(0); + } + name = read_filename; + fp = com_open_file(filename, "r", &read_filename, 1); + if (fp == NIL(FILE)) { + FREE(read_filename); + read_filename = name; + read_error("search file %s not found", filename); + return(0); + } + if (!st_lookup(search_files, filename, NIL(char *))) { + st_insert(search_files, util_strsav(filename), NIL(char)); + } else { + return(1); + } + line = read_lineno; + read_lineno = 1; + status = (*reader)(fp, models, search_files, &dummy); + FREE(read_filename); + if (fp != stdin) { + (void) fclose(fp); + } + read_filename = name; + read_lineno = line; + return(status); +} +#endif /* SIS */ + +/* + * Creates or finds a modelinfo record. + * Inserts it into the `models' table if new one is created. + * + * Also allocates a po_list, and a patch_list for the entry. + */ +modelinfo * +read_find_or_create_model(name, models) +char *name; +st_table *models; +{ + modelinfo *entry; + + if (st_lookup(models, name, (char **) &entry) == 1) { + return(entry); + } + entry = ALLOC(modelinfo,1); + entry->network = NIL(network_t); + entry->po_list = lsCreate(); + entry->library = 0; + entry->patch_lists = lsCreate(); + entry->latch_order_list = NULL; + (void) st_insert(models, util_strsav(name), (char *) entry); + entry->depends_on = 0; + + return(entry); +} + + +#ifdef SIS +/* + * The following routine returns 1 if the user only specified the + * .inputs and .outputs hoping that those names would be stored with the STG + * In this case all the PI nodes have no fanout --- that's what we will check + */ +static int +read_special_case_for_stg(network) +network_t *network; +{ + lsGen gen; + node_t *node; + foreach_node(network, gen, node){ + if (node->type == PRIMARY_INPUT && node_num_fanout(node) > 0){ + lsFinish(gen); + return FALSE; + } + } + return TRUE; +} +static int +read_set_latch_order(network, latch_order_list) +network_t *network; +lsList latch_order_list; +{ + lsGen gen; + node_t *p; + latch_t *l; + graph_t *stg; + lsList newlatch; + char *name; + int i, order; + array_t *names, *node_array; + + stg = network_stg(network); + /* + * For the special case when the STG is specified with the PI and PO + * declarations. The input names were stored earlier (as part + * of the .start_kiss processing we did a network_set_stg(). At that + * time the PO nodes were not present. Hence we have to do it again... + * We don't want stg_save_names to print out the error messages + * again though. + */ + if (stg != NIL(graph_t)) { + names = stg_get_names(stg, 0); + if (names != NIL(array_t)) { + for (i = array_n(names); i-- > 0; ){ + name = array_fetch(char *, names, i); + FREE(name); + } + (void) array_free(names); + } + stg_set_names(stg, NIL(array_t), 0); + names = stg_get_names(stg, 1); + if (names != NIL(array_t)) { + for (i = array_n(names); i-- > 0; ){ + name = array_fetch(char *, names, i); + FREE(name); + } + (void) array_free(names); + } + stg_set_names(stg, NIL(array_t), 1); + if (stg_save_names(network, stg, 0)) { + node_array = network_dfs_from_input(network); + for (i = 0; i < array_n(node_array); i++) { + p = array_fetch(node_t *, node_array, i); + network_delete_node(network, p); + } + array_free(node_array); + } + } + + order = (latch_order_list != 0) ? (lsLength(latch_order_list) != 0) : 0; + name = network_name(network); + + if (stg == NIL(graph_t) || lsLength(network->nodes) == 0) { + if (order != 0) { + read_error("model `%s': .latch_order unnecessary", name); + } + return(1); + } + /* + * stg & network given... Need to handle the special case when only + * the .inputs and .outputs are specified alongwith a STG + */ + if (order == 0 && !read_special_case_for_stg(network)){ + read_error("model `%s': .latch_order & .code must be given w/ stg", + name); + return(0); + } + /* + * Order the latches + */ + + if (latch_order_list != 0) { + newlatch = lsCreate(); + + lsForeachItem (latch_order_list, gen, p) { + l = latch_from_node(p); + if (l == NIL(latch_t)) { + read_error("model `%s': %s is not the output of a latch", name, + node_name(p)); + (void) lsFinish(gen); + return(0); + } + (void) lsNewEnd(newlatch, (lsGeneric) l, LS_NH); + } + (void) lsDestroy(latch_order_list, (void (*)()) 0); + (void) lsDestroy(network->latch, (void (*)()) 0); + network->latch = newlatch; + } + return(1); +} +#endif /* SIS */ + +static enum st_retval read_patch_network(); + +enum patch_retval { + NO_PATCHED, PATCH_ERROR, PATCH_OK +}; + +typedef struct { + st_table *models; /* data in */ + network_t *master; /* data in */ + enum patch_retval patch_return; /* data out */ +} st_foreach_data; + +static void +patch_free(patch) +patchinfo *patch; +{ + int i; + char **formals = patch->formals; + + if (formals != NIL(char *)) { + for (i = array_n(patch->actuals) - 1; i >= 0; i--) { + FREE(formals[i]); + } + FREE(formals); + } + if (patch->actuals != NIL(array_t)) { + array_free(patch->actuals); + } + FREE(patch); +} + +int +read_blif_slif(fp, networkp, reader) +FILE *fp; +network_t **networkp; +int (*reader)(); +{ + st_table *models = st_init_table(strcmp, st_strhash); + st_table *search_files = st_init_table(strcmp, st_strhash); + int status; + char *name; + st_generator *stgen; + modelinfo *entry; + network_t *network = NIL(network_t); + st_foreach_data sfd; +#ifdef SIS + graph_t *stg; + vertex_t *v; + int encode_length; + int i; +#endif /* SIS */ + + status = (*reader)(fp, models, search_files, &network); + + /* Search files keeps track of which files we've already seen so we + don't look at one file more than once. */ + + st_foreach_item(search_files, stgen, &name, NIL(char *)) { + FREE(name); + } + st_free_table(search_files); + + /* patch all the holes */ + + sfd.master = network; + sfd.patch_return = PATCH_OK; + if (network == NIL(network_t) || status != 1) { + /* propogate error */ + + network = NIL(network_t); + sfd.master = NIL(network_t); + } + else { + sfd.models = models; + FREE(read_filename); + do { + sfd.patch_return = NO_PATCHED; + st_foreach(models, read_patch_network, (char *) &sfd); + if (sfd.patch_return == NO_PATCHED) { + read_error("Cyclic model dependency detected, probably involving:"); + st_foreach_item (models, stgen, &name, NIL(char *)) { + read_error(name); + } + break; + } + } while (sfd.patch_return != PATCH_ERROR && st_count(models) != 0); + } + + if (sfd.patch_return != PATCH_OK) { + network = NIL(network_t); + } +#ifdef SIS + else if (network != NIL(network_t)) { + + network_replace_io_fake_names(network); + } +#endif /* SIS */ + + /* delete all the temporary networks not needed anymore */ + + st_foreach_item (models, stgen, &name, (char **) &entry) { + if (entry->network != network) { + network_free(entry->network); + } + if (entry->po_list != 0) { + (void) lsDestroy(entry->po_list, (void (*)()) 0); + } + if (entry->latch_order_list != 0) { + (void) lsDestroy(entry->latch_order_list, (void (*)()) 0); + } + if (entry->patch_lists != 0) { + (void) lsDestroy(entry->patch_lists, patch_free); + } + FREE(name); + FREE(entry); + } + st_free_table(models); + +#ifdef SIS + /* Need to fix the stg so that any state labelled "ANY" or "*" */ + /* has an encoding string of all 2's */ + /* First check the stg */ + + if (network != NIL(network_t)) { + stg = network_stg(network); + if (stg != NIL(graph_t)) { + v = stg_get_start(stg); + name = stg_get_state_encoding(v); + if (name != NIL(char)) { + encode_length = strlen(name); + } else { + encode_length = 0; + } + v = stg_get_state_by_name(stg, "ANY"); + if (v != NIL(vertex_t)) { + if ((encode_length != 0) && + (stg_get_state_encoding(v) == NIL(char))) { + name = ALLOC(char, encode_length+1); + for (i = 0; i < encode_length; i++) { + name[i] = '2'; + } + name[encode_length] = '\0'; + stg_set_state_encoding(v, name); + FREE(name); + } + } + v = stg_get_state_by_name(stg, "*"); + if (v != NIL(vertex_t)) { + if ((encode_length != 0) && + (stg_get_state_encoding(v) == NIL(char))) { + name = ALLOC(char, encode_length+1); + for (i = 0; i < encode_length; i++) { + name[i] = '2'; + } + name[encode_length] = '\0'; + stg_set_state_encoding(v, name); + FREE(name); + } + } + } +#ifdef DEBUG + if (!network_stg_check(network)) { + read_error("network does not cover stg"); + network_free(network); + status = 0; + } +#endif + } +#endif /* SIS */ + if (network != NIL(network_t)) { + if (!network_check(network)) { + read_error("network failed network_check"); + network_free(network); + status = 0; + } + } +/* Correct the naming in the don't care network. The fake primary outputs are renamed to their + * corresponding primary output names in the care network. + */ + if (network != NIL(network_t)) { + if (network->dc_network != NIL(network_t)) { + dc_network_check(network, &status); + } + } + *networkp = network; + return(status); +} + +#ifdef SIS +static node_t * +find_or_create_mapped_node(net, map, node) +network_t *net; +st_table *map; +node_t *node; +{ + node_t *found; + char *name; + + if (st_lookup(map, (char *) node, (char **) &found) == 0) { + found = node_alloc(); + network_add_node(net, found); + (void) st_insert(map, (char *) node, (char *) found); + + name = node_long_name(node); + if (network_find_node(net, name) == NIL(node_t)) { + network_change_node_name(net, found, util_strsav(name)); + } + } + return(found); +} + +static int +is_real_pio(net, node) +network_t *net; +node_t *node; +{ + if (network_is_real_pi(net, node) != 0) { + return(1); + } + return(network_is_real_po(net, node)); +} + +#endif /* SIS */ + +/* + * If the network of `entry' does not depend on anything, then patches + * that network into all the networks associated with the patch_lists + * of `entry'. Also cleans up the outputs of that network. + * + * The network of `entry' is not collapsed before insertion into the + * surrounding networks. + * + * `entry' is removed from the `models' table after it has been patched in. + * + * `entry->network' is either inserted into the library or all the storage + * associated with `entry->network' is freed depending on `entry->library'. + */ +static enum st_retval +read_patch_network(sname, entry, sfd) +char *sname; +modelinfo *entry; +st_foreach_data *sfd; +{ + network_t *snet; + lsList po_list; + library_t *library; + lib_gate_t *gate; +#ifdef SIS + lsGen gen, netgen; + network_t *bnet; + int inputs, outputs, n, ins, k, num_false, num_controls; + array_t *bactuals; + modelinfo *bentry; + node_t *new_node, *bnode, *bfanin, *snode, *sfanin, *bpi; + node_t *scontrol, *bcontrol; + patchinfo *bpatch; + st_table *controls; + latch_t *slatch, *blatch; + node_type_t type; + st_table *models, *nmap; + char **bformals, *formal, *bname; +#endif /* SIS */ + + /* + * snet is the small network being inserted. + * bnet is the big network being inserted into. + */ + + /* If null network, look in library--error if not found */ + + snet = entry->network; + if (snet == NIL(network_t)) { + library = lib_get_library(); + if (library != NIL(library_t)) { + gate = lib_get_gate(library, sname); + } + if (library == NIL(library_t) || gate == NIL(lib_gate_t)) { + read_error("can't find model `%s' in files or library", sname); + sfd->patch_return = PATCH_ERROR; + return(ST_STOP); + } + } + else if (entry->depends_on > 0) { + return(ST_CONTINUE); + } + + /* Clean up po_list and check network is not cyclic */ + + po_list = entry->po_list; + if (snet != NIL(network_t)) { + /* If this is a special case where names are saved on the stg for the + coming network, don't print warning messages. */ + if (!read_check_io_list(snet, po_list, !read_special_case_for_stg(snet))) { + sfd->patch_return = PATCH_ERROR; + return(ST_STOP); + } + read_hack_outputs(snet, po_list); +#ifdef SIS + read_check_control_signals(snet); +#endif /* SIS */ + } + (void) lsDestroy(po_list, (void (*)()) 0); + entry->po_list = NULL; + + if (snet != NIL(network_t)) { +#ifdef SIS + if (read_set_latch_order(snet, entry->latch_order_list) == 0) { + sfd->patch_return = PATCH_ERROR; + return(ST_STOP); + } + entry->latch_order_list = NULL; +#endif /* SIS */ + + if (network_check(snet) == 0) { + read_error("model `%s': network_check failed", sname); + sfd->patch_return = PATCH_ERROR; + return(ST_STOP); + } + + if (network_is_acyclic(snet) == 0) { + read_error("network `%s' contains a cycle", sname); + sfd->patch_return = PATCH_ERROR; + return(ST_STOP); + } + +#ifdef SIS + read_delay_cleanup(snet); +#endif + + /* Insert this network into the library */ + +#ifdef SIS + if (entry->library != 0) { /* only for slif (so far) */ + if (slif_add_to_library(snet) == 0) { + sfd->patch_return = PATCH_ERROR; + return(ST_STOP); + } + } +#endif /* SIS */ + } + else { + snet = gate->network; + } + +#ifdef SIS + + /* + * Figure out all the false PIs & POs that come from the latches and + * clocks. + */ + + if (lsLength(entry->patch_lists) > 0) { + num_false = 0; + controls = st_init_table(st_ptrcmp, st_ptrhash); + + foreach_latch (snet, gen, slatch) { + num_false++; + snode = latch_get_control(slatch); + if (snode != NIL(node_t)) { + (void) st_insert(controls, (char *) snode, NIL(char)); + } + } + num_controls = st_count(controls); + + outputs = network_num_po(snet) - num_false - num_controls; + inputs = network_num_pi(snet) - num_false; + models = sfd->models; + } + + /* + * For each network that depends on this network ... + */ + + lsForeachItem (entry->patch_lists, gen, bpatch) { + (void) st_lookup(models, bpatch->netname, (char **) &bentry); + bnet = bentry->network; + bname = network_name(bnet); + bactuals = bpatch->actuals; + bentry->depends_on--; + + /* + * Build mapping between PIs, POs, and clocks of two networks. + */ + + nmap = st_init_table(st_ptrcmp, st_ptrhash); + + bformals = bpatch->formals; + + /* + * formal=actual format + */ + + if (bformals != NIL(char *)) { + + for (k = array_n(bactuals); --k >= 0; ) { + bnode = array_fetch(node_t *, bactuals, k); + formal = bformals[k]; + snode = network_find_node(snet, formal); + if (snode == NIL(node_t) || is_real_pio(snet, snode) == 0) { + read_error("model `%s', \".subckt %s\": formal argument \"%s\" not part of `%s'", + bname, sname, formal, sname); + sfd->patch_return = PATCH_ERROR; + continue; + } + if (node_type(snode) == PRIMARY_OUTPUT) { + if (node_function(bnode) != NODE_UNDEFINED) { + read_error("model `%s', \".subckt %s\": in \"%s=%s\", \"%s\" is output but \"%s\" already has function", + bname, sname, formal, io_node_name(bnode), formal, + io_node_name(bnode)); + sfd->patch_return = PATCH_ERROR; + } + (void) st_insert(nmap, (char *) snode, NIL(char)); + snode = node_get_fanin(snode, 0); + } + if (st_insert(nmap, (char *) snode, (char *) bnode) != 0) { + read_error("model `%s', \".subckt %s\": formal argument \"%s\" specified twice", + bname, sname, formal); + sfd->patch_return = PATCH_ERROR; + } + FREE(formal); + } + FREE(bpatch->formals); + if (sfd->patch_return == PATCH_ERROR) { + (void) lsFinish(gen); + st_free_table(nmap); + return(ST_STOP); + } + } + + /* + * just actual arguments (SLIF) + */ + + else { + + n = array_n(bactuals); + ins = bpatch->inputs; + if (ins == -1) { /* # inputs not specified */ + if (n != inputs + outputs) { /* have wrong total # signals */ + (void) fprintf(siserr, + "Warning: wrong number inputs or outputs to `%s' in `%s'\n", + sname, bname); + } + } + else if (inputs != ins || outputs != (n - ins)) { + (void) fprintf(siserr, "Warning: wrong number of %s to `%s' in `%s'\n", + ((inputs == ins) ? "outputs" : "inputs"), sname, + bname); + } + k = 0; + foreach_primary_input (snet, netgen, snode) { + if (network_latch_end(snode) == NIL(node_t)){ + bnode = array_fetch(node_t *, bactuals, k++); + (void) st_insert(nmap, (char *) snode, (char *) bnode); + } + } + foreach_primary_output (snet, netgen, snode) { + if (network_latch_end(snode) == NIL(node_t) && + !st_is_member(controls, (char *)snode)){ + bnode = array_fetch(node_t *, bactuals, k++); + snode = node_get_fanin(snode, 0); + (void) st_insert(nmap, (char *) snode, (char *) bnode); + } + } + /* clocks ?? */ + } + + /* + * For each node of the network ... + */ + + foreach_node (snet, netgen, snode) { + type = node_type(snode); + if (type != INTERNAL && is_real_pio(snet, snode) == 0) { + slatch = latch_from_node(snode); + if (type == PRIMARY_INPUT || slatch == NIL(latch_t)) { + continue; + } + sfanin = node_get_fanin(snode, 0); + bfanin = find_or_create_mapped_node(bnet, nmap, sfanin); + bnode = network_add_fake_primary_output(bnet, bfanin); + + bpi = find_or_create_mapped_node(bnet, nmap, latch_get_output(slatch)); + network_change_node_type(bnet, bpi, PRIMARY_INPUT); + + network_create_latch(bnet, &blatch, bnode, bpi); + latch_set_initial_value(blatch, latch_get_initial_value(slatch)); + latch_set_current_value(blatch, latch_get_current_value(slatch)); + latch_set_type(blatch, latch_get_type(slatch)); + latch_set_gate(blatch, latch_get_gate(slatch)); + scontrol = latch_get_control(slatch); + if (scontrol != NIL(node_t)) { + scontrol = node_get_fanin(scontrol, 0); + bcontrol = find_or_create_mapped_node(bnet, nmap, scontrol); + + bnode = network_get_control(bnet, bcontrol); + if (bnode == NIL(node_t)) { + bnode = network_add_fake_primary_output(bnet, bcontrol); + } + } + else { + bnode = NIL(node_t); + } + latch_set_control(blatch, bnode); + continue; + } + + switch (type) { + case PRIMARY_INPUT: + if (st_is_member(nmap, (char *) snode) == 0) { + (void) fprintf(siserr, + "Warning: `%s', \".subckt %s\": formal input \"%s\" not driven\n", + bname, sname, io_node_name(snode)); + } + break; + case PRIMARY_OUTPUT: + /* + * This test is wrong: The PO node was never used as a key to an + * entry in the hash table... So the test is bound to fail.... + */ + /* + if (st_is_member(nmap, (char *) snode) == 0 && + network_is_real_po(snet, snode) != 0) { + (void) fprintf(siserr, + "Warning: `%s', \".subckt %s\": formal output \"%s\" does not fanout\n", + bname, sname, io_node_name(snode)); + } + */ + break; + case INTERNAL: + bnode = find_or_create_mapped_node(bnet, nmap, snode); + new_node = node_dup(snode); + node_replace(bnode, new_node); + foreach_fanin (snode, n, sfanin) { + bfanin = find_or_create_mapped_node(bnet, nmap, sfanin); + (void) node_patch_fanin(bnode, sfanin, bfanin); + } + node_map_copy(snode, bnode); + + /* Run node_scc on each interface node in the hierarchy. This is + because the interface nodes could have the function a*a'. If this + is true, then when "print" is run which calls node_make_common_base, + the number of fanins is one, but the function has no cubes. This + causes an error. Running node_scc on the interface nodes fixes + this. Note that while reading the networks, node_scc is called on + all the internal nodes, so this is consistent. */ + /* For mapped circuits, this is still a problem, but it always has + been. We don't want to change the mapping to fix the problem. */ + + if (lib_gate_of(bnode) == NIL(lib_gate_t)) { + node_scc(bnode); + } + + } + } + array_free(bactuals); + bpatch->actuals = NIL(array_t); + st_free_table(nmap); + } + + if (lsLength(entry->patch_lists) > 0) { + st_free_table(controls); + } + +#endif /* SIS */ + + (void) lsDestroy(entry->patch_lists, patch_free); + entry->patch_lists = NULL; + + snet = entry->network; + if (snet != sfd->master) { + network_free(snet); + } + + FREE(entry); + FREE(sname); + sfd->patch_return = PATCH_OK; + return(ST_DELETE); +} + + +#ifdef SIS +static void +node_map_copy(from, to) +node_t *from, *to; +{ + int nin, i; + node_t *fanin; + lib_gate_t *gate; + node_t **actuals; + char **formals; + + gate = lib_gate_of(from); + if (gate == NIL(lib_gate_t)) { + return; + } else { + nin = node_num_fanin(to); + actuals = ALLOC(node_t *, nin); + formals = ALLOC(char *, nin); + foreach_fanin(to, i, fanin) { + actuals[i] = fanin; + formals[i] = lib_gate_pin_name(gate, i, 1); + } + assert(lib_set_gate(to, gate, formals, actuals, nin)); + FREE(actuals); + FREE(formals); + } +} +#endif + + +void +dc_network_check(network, status) +network_t *network; +int *status; +{ + network_t *dc_net; + int po_cnt; + node_t *node, *po, *pnode; + node_t *dcpo; + node_t *pi, *dcfanin; + lsGen gen; + char *name; + + dc_net = network->dc_network; +#ifdef SIS + foreach_primary_output(network, gen, po){ + if(network_is_real_po(network, po)){ + continue; + } + node = po->fanin[0]; + name = io_name(po, 0); + po_cnt = io_rpo_fanout_count(node, &pnode); + if (node_function(node) == NODE_PI){ + continue; + } + if (po_cnt == 0){ + /* name of the latch is stored in the fanin of po*/ + if (!(dcpo = network_find_node(dc_net, node->name))){ + continue; + } + if (node_function(dcpo) == NODE_PO){ + name = util_strsav(po->name); + network_change_node_name(dc_net, dcpo, name); + continue; + }else{ + read_error("fatal: %s is not a primary output in the external don't care network", node->name); + *status = 0; + network_free(network); + return; + } + } + /*name of the latch is stored in a real po*/ + if (!(dcpo = network_find_node(dc_net, pnode->name))){ + continue; + } + dcfanin = node_get_fanin(dcpo, 0); + node = node_literal(dcfanin, 1); + node->name = util_strsav(po->name); + network_add_node(dc_net, node); + (void) network_add_primary_output(dc_net, node); + } +#endif /* SIS */ + foreach_primary_output(dc_net, gen, dcpo){ + if (!(network_find_node(network, dcpo->name))){ + read_error("fatal: output %s appears only in the external don't care network.\n", + dcpo->name); + *status = 0; + network_free(network); + return; + } + } + foreach_primary_input(dc_net, gen, pi){ + if (network_find_node(network, pi->name)) + continue; + read_error("fatal: input %s appears only in the external don't care network.\n", pi->name); + *status = 0; + network_free(network); + return; + } +} diff --git a/sis/io/write_bdnet.c b/sis/io/write_bdnet.c new file mode 100644 index 0000000..046663f --- /dev/null +++ b/sis/io/write_bdnet.c @@ -0,0 +1,149 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/write_bdnet.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * + */ +#include "sis.h" + + +static void write_instance_name(); + +write_bdnet(fp, network) +FILE *fp; +network_t *network; +{ + int i; + lsGen gen; + char *flag, *path, *viewname; + node_t *node, *fanin; + lib_gate_t *gate; +#ifdef SIS + int pin_index; + latch_t *latch; + node_t *control; +#endif /* SIS */ + + if (! lib_network_is_mapped(network)) { + error_append("write_bdnet: network not mapped, cannot write netlist\n"); + return 0; + } + + path = com_get_flag("OCT-CELL-PATH"); + viewname = com_get_flag("OCT-CELL-VIEW"); + if (viewname == 0) viewname = "physical"; + + (void) fprintf(fp, "MODEL \"%s\";\n", network_name(network)); + if ((flag = com_get_flag("OCT-TECHNOLOGY")) != 0) { + (void) fprintf(fp, " TECHNOLOGY %s;\n", flag); + } + if ((flag = com_get_flag("OCT-VIEWTYPE")) != 0) { + (void) fprintf(fp, " VIEWTYPE %s;\n", flag); + } + if ((flag = com_get_flag("OCT-EDITSTYLE")) != 0) { + (void) fprintf(fp, " EDITSTYLE %s;\n", flag); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "INPUT"); + foreach_primary_input(network, gen, node) { +#ifdef SIS + if (!network_is_real_pi(network, node)) continue; +#endif /* SIS */ + (void) fprintf(fp, "\n\t\"%s\"\t:\t\"%s\"", node->name, node->name); + } + (void) fprintf(fp, ";\n\n"); + + (void) fprintf(fp, "OUTPUT"); + foreach_primary_output(network, gen, node) { +#ifdef SIS + if (!network_is_real_po(network, node)) continue; +#endif /* SIS */ + (void) fprintf(fp, "\n\t\"%s\"\t:\t\"%s\"", + node->name, node_get_fanin(node, 0)->name); + } + (void) fprintf(fp, ";\n\n"); + + foreach_node(network, gen, node) { + if (node->type == INTERNAL) { + write_instance_name(fp, path, viewname, node); + gate = lib_gate_of(node); +#ifdef SIS + if (lib_gate_type(gate) == COMBINATIONAL) { +#endif /* SIS */ + foreach_fanin(node, i, fanin) { + (void) fprintf(fp, "\t\"%s\"\t:\t", + lib_gate_pin_name(gate, i, /*inflag*/ 1)); + (void) fprintf(fp, "\"%s\";\n", fanin->name); + } + (void) fprintf(fp, "\t\"%s\"\t:\t", + lib_gate_pin_name(gate, 0, /*inflag*/ 0)); + (void) fprintf(fp, "\"%s\";\n\n", node->name); +#ifdef SIS + } else { + /* Sequential support added by KJSingh --- 8/24/93 */ + pin_index = lib_gate_latch_pin(gate); + foreach_fanin(node, i, fanin) { + if (i == pin_index) continue; + (void) fprintf(fp, "\t\"%s\"\t:\t", + lib_gate_pin_name(gate, i, /*inflag*/ 1)); + (void) fprintf(fp, "\"%s\";\n", fanin->name); + } + /* Also connect up the control input */ + latch = latch_from_node(node_get_fanout(node, 0)); + if (lib_gate_type(gate) != ASYNCH) { + if ((control = latch_get_control(latch)) != NIL(node_t)){ + control = node_get_fanin(control, 0); + (void) fprintf(fp, "\t\"%s\"\t:\t\"%s\";\n", + lib_gate_pin_name(gate, 0, /*inflag*/ 2), + control->name); + } else { + (void) fprintf(fp, "\t\"%s\"\t:\tUNCONNECTED;\n", + lib_gate_pin_name(gate, 0, /*inflag*/ 2)); + } + } + /* The output name is the name of the PI corresponding to + latch o/p */ + (void) fprintf(fp, "\t\"%s\"\t:\t", + lib_gate_pin_name(gate, 0, /*inflag*/ 0)); + (void) fprintf(fp, "\"%s\";\n\n", + node_long_name(latch_get_output(latch))); + } +#endif /* SIS */ + } + } + + (void) fprintf(fp, "ENDMODEL;\n"); + return 1; +} + + +static void +write_instance_name(fp, path, viewname, node) +FILE *fp; +char *path; +char *viewname; +node_t *node; +{ + char *gate, *view; + + gate = util_strsav(lib_gate_name(lib_gate_of(node))); + view = strchr(gate, ':'); + if (view == 0) { + view = viewname; + } else { + *view++ = '\0'; + } + if (path == 0 || gate[0] == '/' || gate[0] == '~') { + (void) fprintf(fp, "INSTANCE \"%s\":\"%s\"\n", gate, view); + } else { + (void) fprintf(fp, "INSTANCE \"%s/%s\":\"%s\"\n", path, gate, view); + } + FREE(gate); +} + + + diff --git a/sis/io/write_blif.c b/sis/io/write_blif.c new file mode 100644 index 0000000..1dc3021 --- /dev/null +++ b/sis/io/write_blif.c @@ -0,0 +1,555 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/write_blif.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * + */ +#include "sis.h" +#include "io_int.h" + +static void do_write_blif(); +static void write_blif_nodes(); +static void write_blif_delay(); + +#ifdef SIS +static void write_blif_latches(); +static write_codes(); +static write_blif_clocks(); +static st_table *write_add_buffers(); +#endif /* SIS */ + +static void write_gen_event(); + +void +write_blif_for_bdsyn(fp, network) +FILE *fp; +network_t *network; +{ + io_fput_params("\\\n", 32000); + do_write_blif(fp, network, 0, 0); +} + + +void +write_blif(fp, network, short_flag, netlist_flag) +FILE *fp; +network_t *network; +int short_flag; +int netlist_flag; +{ + io_fput_params("\\\n", 78); + do_write_blif(fp, network, short_flag, netlist_flag); +} + + +static void +do_write_blif(fp, network, short_flag, netlist_flag) +register FILE *fp; +network_t *network; +int short_flag; +int netlist_flag; +{ + node_t *p; + lsGen gen; + node_t *node, *po, *fanin, *pnode; + node_t *nodein; + network_t *dc_net; + char *name; + int po_cnt; +#ifdef SIS + graph_t *stg; + st_generator *stgen; + node_t *pi_node, *po_node, *buf_node; + st_table *added_nodes; + latch_t *latch; +#endif /* SIS */ + + /* + * HACK: To preserve the names of latches in the case when the latch + * output is also a true output. The latch output may be referred to in + * the dont care network and so we need that name... Add buffers between + * latch output (PI's) and true PO's ... Later remove so that the + * network is unchanged. + */ +#ifdef SIS + added_nodes = write_add_buffers(network); +#endif /* SIS */ + + io_fprintf_break(fp, ".model %s\n.inputs", network_name(network)); + /* + * Don't print out clocks and latch outputs + */ + foreach_primary_input (network, gen, p) { +#ifdef SIS + if (network_is_real_pi(network, p) != 0 && + clock_get_by_name(network, node_long_name(p)) == 0) { + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); + } +#else + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); +#endif /* SIS */ + + } + + io_fputc_break(fp, '\n'); + io_fputs_break(fp, ".outputs"); + /* + * Don't print out control outputs and latch_inputs + */ + foreach_primary_output (network, gen, p) { +#ifdef SIS + if (network_is_real_po(network, p) != 0) { + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); + } +#else + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); +#endif /* SIS */ + + } + + io_fputc_break(fp, '\n'); + +#ifdef SIS + write_blif_clocks(fp, network, short_flag); +#endif + + write_blif_delay(fp, network, short_flag); + +#ifdef SIS + write_blif_latches(fp, network, short_flag, netlist_flag); + + stg = network_stg(network); + if (stg != NIL(graph_t)) { + io_fputs_break(fp, ".start_kiss\n"); + (void) write_kiss(fp, stg); + io_fputs_break(fp, ".end_kiss\n.latch_order"); + + foreach_latch (network, gen, latch) { + io_fputc_break(fp, ' '); + io_write_name(fp, latch_get_output(latch), short_flag); + } + io_fputc_break(fp, '\n'); + + write_codes(fp, stg); + } +#endif /* SIS */ + + write_blif_nodes(fp, network, netlist_flag, short_flag); + + if (network->dc_network != NIL(network_t)) { + io_fprintf_break(fp, ".exdc \n.inputs"); + dc_net = network_dup(network->dc_network); + +/* Get correct names for the fake PO's corresponding to the latches. */ +#ifdef SIS + foreach_primary_output(network, gen, po){ + if (network_is_real_po(network, po)) + continue; + if (!(node = network_find_node(dc_net, po->name))) + continue; + fanin = po->fanin[0]; + if (node_function(fanin) == NODE_PI){ + nodein = node->fanin[0]; + network_delete_node(dc_net, node); + if (node_num_fanout(nodein) == 1) + network_delete_node(dc_net, nodein); + continue; + } + po_cnt = io_rpo_fanout_count(fanin, &pnode); + if (po_cnt != 0){ + nodein = node->fanin[0]; + network_delete_node(dc_net, node); + if (node_num_fanout(nodein) == 0) + network_delete_node(dc_net, nodein); + continue; + } + + /* Try to preserve as much dont-care as possible. + * For now this is only possible for D-type latches. */ + if (netlist_flag) { + switch(lib_gate_type(lib_gate_of(fanin))) { + case RISING_EDGE: + case FALLING_EDGE: + case ACTIVE_HIGH: + case ACTIVE_LOW: + case ASYNCH: + if (node_function(fanin) == NODE_BUF) { + /* D-type FF */ + fanin = fanin->fanin[0]; + } else { + /* we have no way of propagating the dont-care + * info for complex latches */ + (void)fprintf(siserr, "warning: can't preserve dont-care info for complex latch %s\n", + fanin->name); + nodein = node->fanin[0]; + network_delete_node(dc_net, node); + if (node_num_fanout(nodein) == 0) + network_delete_node(dc_net, nodein); + continue; + } + break; + } + } + name = util_strsav(fanin->name); + if (!network_find_node(dc_net, name)) { + /* If the name were in the dc_network, that means that a + DC function for this latch was already found. The user + can give two constructs ".latch a b" ".latch a c" to + create two latches, but can only give one DC set for these + two latches. extract_seq_dc will produce a DC set for each + of these latches, but the DC set will be the same. */ + network_change_node_name(dc_net, node, name); + } else { + network_delete_node(dc_net, node); + } + } + network_cleanup(dc_net); +#endif /* SIS */ + + foreach_primary_input (dc_net, gen, p) { +#ifdef SIS + if (network_is_real_pi(dc_net, p) != 0 ){ + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); + } +#else + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); +#endif /* SIS */ + } + + io_fputc_break(fp, '\n'); + io_fputs_break(fp, ".outputs"); + foreach_primary_output (dc_net, gen, p) { +#ifdef SIS + if (network_is_real_po(dc_net, p) != 0) { + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); + } +#else + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); +#endif /* SIS */ + } + io_fputc_break(fp, '\n'); + + + write_blif_nodes(fp, dc_net, netlist_flag, short_flag); + network_free(dc_net); + } + io_fputs_break(fp, ".end\n"); + +#ifdef SIS + /* + * Remove the extra nodes added to preserve latch names in the DC network + */ + st_foreach_item(added_nodes, stgen, (char **)&buf_node, (char **)&po_node){ + pi_node = node_get_fanin(buf_node, 0); + node_patch_fanin(po_node, buf_node, pi_node); + network_delete_node(network, buf_node); + } + st_free_table(added_nodes); +#endif /* SIS */ +} + +static void +write_blif_nodes(fp, network, netlist_flag, short_flag) +FILE *fp; +network_t *network; +int netlist_flag, short_flag; +{ + lsGen gen; + node_t *p; + + foreach_node (network, gen, p) { + if (netlist_flag != 0 && lib_gate_of(p) != NIL(lib_gate_t)) { +#ifdef SIS + if (io_lpo_fanout_count(p, NIL(node_t *)) == 0) { + /* + * Avoid the dummy nodes due to the latches + */ + io_write_gate(fp, p, short_flag); + io_fputc_break(fp, '\n'); + } +#else + io_write_gate(fp, p, short_flag); + io_fputc_break(fp, '\n'); +#endif /* SIS */ + } + else { + io_write_node(fp, p, short_flag); + } + } +} + +static void +write_blif_delay(fp, network, short_flag) +FILE *fp; +network_t *network; +int short_flag; +{ + write_blif_slif_delay(fp, network, 0, short_flag); +} + +#ifdef SIS + +static void +write_blif_latches(fp, network, short_flag, netlist_flag) +FILE *fp; +network_t *network; +int short_flag, netlist_flag; +{ + lsGen gen; + latch_t *latch; + node_t *node, *control; + + foreach_latch (network, gen, latch) { + control = latch_get_control(latch); + if (netlist_flag != 0 && latch_get_gate(latch) != NIL(lib_gate_t)) { + node = node_get_fanin(latch_get_input(latch), 0); + io_write_gate(fp, node, short_flag); + io_fputc_break(fp, ' '); + if (control != NIL(node_t)) { + io_write_name(fp, control, short_flag); + } + else { + io_fputs_break(fp, "NIL"); + } + io_fputc_break(fp, ' '); + io_fputc_break(fp, latch_get_initial_value(latch) + '0'); + io_fputc_break(fp, '\n'); + } + else { + io_fputs_break(fp, ".latch "); + io_write_name(fp, latch_get_input(latch), short_flag); + io_fputc_break(fp, ' '); + io_write_name(fp, latch_get_output(latch), short_flag); + io_fputc_break(fp, ' '); + switch (latch_get_type(latch)) { + case UNKNOWN: + break; + case RISING_EDGE: + io_fputs_break(fp, "re"); + break; + case FALLING_EDGE: + io_fputs_break(fp, "fe"); + break; + case ACTIVE_HIGH: + io_fputs_break(fp, "ah"); + break; + case ACTIVE_LOW: + io_fputs_break(fp, "al"); + break; + case ASYNCH: + io_fputs_break(fp, "as"); + break; + } + io_fputc_break(fp, ' '); + if (control != NIL(node_t)) { + io_write_name(fp, control, short_flag); + } + else if (latch_get_type(latch) != UNKNOWN) { + io_fputs_break(fp, "NIL"); + } + io_fputc_break(fp, ' '); + io_fputc_break(fp, latch_get_initial_value(latch) + '0'); + io_fputc_break(fp, '\n'); + } + } +} + +static +write_codes(fp, stg) +FILE *fp; +graph_t *stg; +{ + vertex_t *state; + lsGen gen; + char *code, *name; + + stg_foreach_state(stg, gen, state){ + if((code = stg_get_state_encoding(state)) != NIL(char)){ + name = stg_get_state_name(state); + io_fputs_break(fp, ".code "); + io_fputs_break(fp, name); + io_fputc_break(fp, ' '); + io_fputs_break(fp, code); + io_fputc_break(fp, '\n'); + } + } +} + +static +write_blif_clocks(fp, network, short_flag) +FILE *fp; +network_t *network; +int short_flag; +{ + + int first = 1; + lsGen gen; + sis_clock_t *clock; + node_t *node; + double cycle; + st_table *done_table; + int trans; + + foreach_clock (network, gen, clock) { + if (first != 0) { + io_fputs_break(fp, ".clock"); + first = 0; + } + io_fputc_break(fp, ' '); + assert((node = network_find_node(network, clock_name(clock))) != NIL(node_t)); + io_write_name(fp, node, short_flag); + /* + io_fputs_break(fp, clock_name(clock)); + */ + } + if (first == 0) { + io_fputc_break(fp, '\n'); + } + + cycle = clock_get_cycletime(network); + if (cycle > 0) { + io_fprintf_break(fp, ".cycle %.2lf\n", cycle); + } + + done_table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_clock (network, gen, clock) { + if (st_lookup_int(done_table, (char *) clock, &trans) != 0) { + switch (trans) { + case 3: + break; + case 2: + write_gen_event(fp, clock, RISE_TRANSITION, done_table, + short_flag); + break; + default: + write_gen_event(fp, clock, FALL_TRANSITION, done_table, + short_flag); + break; + } + } + else { + write_gen_event(fp, clock, RISE_TRANSITION, done_table, short_flag); + (void) st_lookup_int(done_table, (char *) clock, &trans); + if (trans != 3) { + write_gen_event(fp, clock, FALL_TRANSITION, done_table, + short_flag); + } + } + } + st_free_table(done_table); +} +/* + * Utility routine that will get the name of the node representing the clock + * This is required since short names may be used during writing. So we + * cannot use the names stored with the sis_clock_t structures + */ +static char * +io_clock_name(clock, short_flag) +sis_clock_t *clock; +int short_flag; +{ + node_t *node; + + node = network_find_node(clock->network, clock_name(clock)); + assert(node != NIL(node_t)); + return io_name(node, short_flag); +} + +static void +write_gen_event(fp, clock, transition, done_table, short_flag) +FILE *fp; +sis_clock_t *clock; +int transition; +st_table *done_table; +int short_flag; +{ + clock_edge_t edge, new_edge; + lsGen gen; + char *dummy; + int done; + char prefix; + + edge.transition = transition; + edge.clock = clock; + + if (clock_get_parameter(edge, CLOCK_NOMINAL_POSITION) < 0) { + return; + } + io_fputs_break(fp, ".clock_event "); + prefix = (edge.transition == RISE_TRANSITION) ? 'r' : 'f'; + io_fprintf_break(fp, "%.2lf (%c'%s %.2lf %.2lf)", + clock_get_parameter(edge, CLOCK_NOMINAL_POSITION), + prefix, + io_clock_name(clock, short_flag), + clock_get_parameter(edge, CLOCK_LOWER_RANGE), + clock_get_parameter(edge, CLOCK_UPPER_RANGE)); + + if (st_lookup(done_table, (char *)(edge.clock), &dummy)) { + done = 3; + } + else { + done = (edge.transition == RISE_TRANSITION) ? 1: 2; + } + (void) st_insert(done_table, (char *)(edge.clock), (char *)done); + + gen = clock_gen_dependency(edge); + while (lsNext(gen, &dummy, LS_NH) == LS_OK) { + new_edge = *((clock_edge_t *)dummy); + prefix = new_edge.transition == RISE_TRANSITION ? 'r' : 'f'; + io_fprintf_break(fp, " (%c'%s %.2lf %.2lf)", + prefix, + io_clock_name(new_edge.clock, short_flag), + clock_get_parameter(new_edge, CLOCK_LOWER_RANGE), + clock_get_parameter(new_edge, CLOCK_UPPER_RANGE)); + if (st_lookup(done_table, (char *)(new_edge.clock), &dummy)) { + done = 3; + } + else { + done = (new_edge.transition == RISE_TRANSITION) ? 1 : 2; + } + (void) st_insert(done_table, (char *)(new_edge.clock), (char *)done); + } + (void) lsFinish(gen); + io_fputc_break(fp, '\n'); +} + +static st_table * +write_add_buffers(network) +network_t *network; +{ + lsGen gen, gen1; + latch_t *latch; + node_t *pi, *po, *node; + st_table *added_nodes; + + added_nodes = st_init_table(st_ptrcmp, st_ptrhash); + + if (network->dc_network == NIL(network_t)){ + return added_nodes; + } + + foreach_latch(network, gen, latch){ + pi = latch_get_output(latch); + foreach_fanout(pi, gen1, po){ + if (network_is_real_po(network, po)){ + node = node_literal(pi, 1); + network_add_node(network, node); + node_patch_fanin(po, pi, node); + (void)st_insert(added_nodes, (char *)node, (char *)po); + } + } + } + return added_nodes; +} +#endif /* SIS */ diff --git a/sis/io/write_eqn.c b/sis/io/write_eqn.c new file mode 100644 index 0000000..dbdc1b3 --- /dev/null +++ b/sis/io/write_eqn.c @@ -0,0 +1,115 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/write_eqn.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * + */ +#include "sis.h" +#include "io_int.h" + +void +write_eqn(fp, network, short_name) +FILE *fp; +network_t *network; +int short_name; +{ + lsGen gen; + node_t *node; + + io_fput_params("\n", 78); + + io_fputs_break(fp, "INORDER ="); + foreach_primary_input(network, gen, node) { + io_fputc_break(fp, ' '); + io_write_name(fp, node, short_name); + } + io_fputs_break(fp, ";\n"); + + io_fputs_break(fp, "OUTORDER ="); + foreach_primary_output(network, gen, node) { + io_fputc_break(fp, ' '); + io_write_name(fp, node, short_name); + } + io_fputs_break(fp, ";\n"); + + foreach_node(network, gen, node) { + write_sop(fp, node, short_name, 0); + } +} + + +void /* cstevens@ic */ +write_sop(fp, node, short_name, slif_flag) +FILE *fp; +node_t *node; +int short_name; +int slif_flag; +{ + register int i, j; + int first_cube, first_lit; + node_cube_t cube; + node_literal_t literal; + node_t *fanin; + + if (io_node_should_be_printed(node) == 0) { + return; + } + + io_write_name(fp, node, short_name); + io_fputs_break(fp, " = "); + + switch(node_function(node)) { + case NODE_0: + io_fputs_break(fp, "0;\n"); + return; + case NODE_1: + io_fputs_break(fp, "1;\n"); + return; + case NODE_PO: + io_write_name(fp, node_get_fanin(node, 0), short_name); + io_fputs_break(fp, ";\n"); + return; + } + + first_cube = 1; + for(i = node_num_cube(node)-1; i >= 0; i--) { + if (! first_cube) { + io_fputs_break(fp, " + "); + } + cube = node_get_cube(node, i); + + first_lit = 1; + foreach_fanin(node, j, fanin) { + literal = node_get_literal(cube, j); + switch(literal) { + case ZERO: + case ONE: + if (!slif_flag) { + if (! first_lit) { + io_fputc_break(fp, '*'); + } + if (literal == ZERO) { + io_fputc_break(fp, '!'); + } + } else { + if (! first_lit) { + io_fputc_break(fp, ' '); + } + } + io_write_name(fp, fanin, short_name); + if (slif_flag) { + if (literal == ZERO) { + io_fputc_break(fp, '\''); + } + } + first_lit = 0; + break; + } + } + first_cube = 0; + } + io_fputs_break(fp, ";\n"); +} diff --git a/sis/io/write_kiss.c b/sis/io/write_kiss.c new file mode 100644 index 0000000..68ad739 --- /dev/null +++ b/sis/io/write_kiss.c @@ -0,0 +1,46 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/write_kiss.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +#ifdef SIS +#include "sis.h" + +int +write_kiss(fp,stg) +FILE *fp; +graph_t *stg; +{ + lsGen gen, gen2; + vertex_t *v; + edge_t *e; + char *vert_name; + + if (stg == (graph_t *) NULL) { + (void) fprintf(miserr,"write_kiss: no stg specified\n"); + return(0); + } + + (void) fprintf(fp,".i %d\n.o %d\n.p %d\n.s %d\n", + stg_get_num_inputs(stg), + stg_get_num_outputs(stg), + stg_get_num_products(stg), + stg_get_num_states(stg)); + v = stg_get_start(stg); + (void) fprintf(fp, ".r %s\n", stg_get_state_name(v)); + foreach_vertex (stg,gen,v) { + vert_name = stg_get_state_name(v); + foreach_out_edge (v,gen2,e) { + (void) fprintf(fp,"%s %s %s %s\n", + stg_edge_input_string(e), vert_name, + stg_get_state_name(stg_edge_to_state(e)), + stg_edge_output_string(e)); + } + } + return(1); +} +#endif /* SIS */ diff --git a/sis/io/write_pla.c b/sis/io/write_pla.c new file mode 100644 index 0000000..e2a95dc --- /dev/null +++ b/sis/io/write_pla.c @@ -0,0 +1,32 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/write_pla.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +#include "sis.h" +#include "io_int.h" + + +void +write_pla(fp, network) +FILE *fp; +network_t *network; +{ + pPLA PLA; + + PLA = network_to_pla(network); + if (PLA == 0) return; + + /* Let espresso do the dirty work */ + if (PLA->D) { + fprint_pla(fp, PLA, FD_type); + } + else { + fprint_pla(fp, PLA, F_type); + } + discard_pla(PLA); +} diff --git a/sis/io/write_slif.c b/sis/io/write_slif.c new file mode 100644 index 0000000..cbaa6eb --- /dev/null +++ b/sis/io/write_slif.c @@ -0,0 +1,357 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/write_slif.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +#include "sis.h" +#include "io_int.h" + +/* + * Simply modified write_blif to output using slif keywords. + */ + +static void write_slif_node(); +static void write_slif_delay(); +static int write_slif_ignore_node(); +#ifdef SIS +static void write_slif_latches(); +#endif /* SIS */ + +int +write_slif(fp, network, short_flag, netlist_flag, delay_flag) +FILE *fp; +network_t *network; +int short_flag, netlist_flag, delay_flag; +{ + lsGen gen; + node_t *p; + st_table *ignore_table; + + io_fprintf_break(fp, ".model %s;\n.inputs", network_name(network)); + /* + * Do not print out latch outputs (print clocks as just inputs) + */ + foreach_primary_input (network, gen, p) { +#ifdef SIS + if (latch_from_node(p) == NIL(latch_t)) { + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); + + } +#else + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); +#endif /* SIS */ + + } + + io_fputs_break(fp, ";\n.outputs"); + /* + * Don't print out control outputs and latch_inputs + */ + foreach_primary_output (network, gen, p) { +#ifdef SIS + if (network_is_real_po(network, p) != 0) { + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); + } +#else + io_fputc_break(fp, ' '); + io_write_name(fp, p, short_flag); +#endif /* SIS */ + + } + io_fputs_break(fp, ";\n"); + + if (delay_flag != 0) { + write_slif_delay(fp, network); + } + + /* + * We should also not write out inverters in the case when the + * node or its fanin has a name that has an "'" at the end. + * The inverter will be inferred by the read_slif() routines + * We will also swap names in the case the inverter has the + * uninverted name "foo" and its fanin is named "foo'" + * Also constant nodes with names "0" and "1" cause problems in + * reading in eqn strings of the type "0 = 0;" + */ + ignore_table = st_init_table(st_ptrcmp, st_ptrhash); + if (short_flag == 0) { + foreach_node (network, gen, p) { + if (write_slif_ignore_node(p)){ + (void)st_insert(ignore_table, (char *)p, NIL(char)); + } + } + } + +#ifdef SIS + + write_slif_latches(fp, network, short_flag, netlist_flag); + + foreach_node (network, gen, p) { + if (!st_is_member(ignore_table, (char *)p)){ + if (netlist_flag != 0 && lib_gate_of(p) != NIL(lib_gate_t)) { + if (io_lpo_fanout_count(p, NIL(node_t *)) == 0) { + write_slif_node(fp, p, netlist_flag, short_flag, NIL(node_t)); + } + } + else { + write_slif_node(fp, p, netlist_flag, short_flag, NIL(node_t)); + } + } + } + +#else + + foreach_node (network, gen, p) { + if (!st_is_member(ignore_table, (char *)p)){ + write_slif_node(fp, p, netlist_flag, short_flag); + } + } + +#endif /* SIS */ + + io_fprintf_break(fp, ".endmodel %s;\n", network_name(network)); + st_free_table(ignore_table); +} + +#ifdef SIS + +static void +write_slif_node(fp, node, netlist_flag, short_flag, latch_in) +FILE *fp; +node_t *node; +int netlist_flag, short_flag; +node_t *latch_in; + +#else + +static void +write_slif_node(fp, node, netlist_flag, short_flag) +FILE *fp; +node_t *node; +int netlist_flag, short_flag; + +#endif /* SIS */ +{ + int i; + node_t *fanin; + char *name; + lib_gate_t *gate; + + if (io_node_should_be_printed(node) == 0) { + return; + } + gate = lib_gate_of(node); + + if (netlist_flag == 0 || gate == NIL(lib_gate_t)) { + write_sop(fp, node, short_flag, 1); + } + else { + name = lib_gate_name(gate); + io_fprintf_break(fp, ".call %s %s (", name, name); +#ifdef SIS + foreach_fanin (node, i, fanin) { + if (lib_gate_latch_pin(gate) != i) { + if (i > 0) { + io_fputs_break(fp, ", "); + } + io_fputs_break(fp, io_name(fanin, short_flag)); + } + } + if (latch_in != NIL(node_t)) { + node = latch_get_output(latch_from_node(latch_in)); + } +#else + foreach_fanin (node, i, fanin) { + if (i > 0) { + io_fputs_break(fp, ", "); + } + io_fputs_break(fp, io_name(fanin, short_flag)); + } +#endif /* SIS */ + io_fprintf_break(fp, " ; ; %s);\n", io_name(node, short_flag)); + } +} + +static void +write_slif_delay(fp, network) +FILE *fp; +network_t *network; +{ + write_blif_slif_delay(fp, network, 1); +} + +#ifdef SIS + +static void +write_slif_latches(fp, network, short_flag, netlist_flag) +FILE *fp; +network_t *network; +int netlist_flag, short_flag; +{ + lsGen gen; + latch_t *latch; + node_t *latchin, *node, *control; + + foreach_latch (network, gen, latch) { + if (netlist_flag != 0 && latch_get_gate(latch) != NIL(lib_gate_t)) { + latchin = latch_get_input(latch); + node = node_get_fanin(latchin, 0); + write_slif_node(fp, node, 1, short_flag, latchin); + } + else { + io_write_name(fp, latch_get_output(latch), short_flag); + io_fputs_break(fp, " = @D("); + io_write_name(fp, latch_get_input(latch), short_flag); + io_fputs_break(fp, ", "); + control = latch_get_control(latch); + if (control == NULL) { + io_fputs_break(fp, "NIL"); + } + else { + io_write_name(fp, control, short_flag); + } + io_fputs_break(fp, ");\n"); + } + } +} + +#endif /* SIS */ + +/* + * Return 1 if we do want this inverter to be printed + */ +static int +write_slif_ignore_node(node) +node_t *node; +{ + node_t *fanin; + int len1, len2; + char *name1, *name2, *sav1, *sav2; + int ignore = FALSE; + + if (node->type != INTERNAL){ + return ignore; + } else if (node_function(node) == NODE_INV){ + name1 = node_long_name(node); len1 = strlen(name1); + fanin = node_get_fanin(node, 0); + name2 = node_long_name(fanin); len2 = strlen(name2); + + if (name1[len1-1] == '\047'){ + name1[len1-1] = '\0'; + if (strcmp(name1, name2) == 0){ + ignore = TRUE; + } + name1[len1-1] = '\047'; + } else if (name2[len2-1] == '\047'){ + name2[len2-1] = '\0'; + if (strcmp(name1, name2) == 0){ + ignore = TRUE; + } + name2[len2-1] = '\047'; + if (ignore){ + /* + * Keep the name with the "'" at the inverting node --- First give the + * node a name that will not clash with the manes being added + */ + sav1 = util_strsav(name1); + sav2 = util_strsav(name2); + network_change_node_name(node_network(node), node, util_strsav("#temp")); + network_change_node_name(node_network(node), fanin, sav1); + network_change_node_name(node_network(node), node, sav2); + } + } + } else if (node_function(node) == NODE_0 && + (strcmp(node_long_name(node), "0") == 0)){ + ignore = TRUE; + } else if (node_function(node) == NODE_1 && + (strcmp(node_long_name(node), "1") == 0)){ + ignore = TRUE; + } + return ignore; +} + + +#if 0 + +char * +replace_chars_in(node_name) +char *node_name; +{ + /* MisII allows some charcaters in its variable names + * that are not allowed in SLIF. + * This routine scans variable names and replaces those characters + * by other ones. It currently replaces + * '-' by ':', + * '(' by '[' and + * ')' by ']'. + */ + static char *buffer = NULL; + int t1 = 0; + + if (buffer == NULL) + { + buffer = ALLOC(char, strlen(node_name) + 2); + } + else if (strlen(buffer) < strlen(node_name)) + { + if (buffer != NULL) FREE(buffer); + buffer = ALLOC(char, strlen(node_name) + 2); + } + + while (node_name[t1] != '\0') + { + if (node_name[t1] == '-') + { + buffer[t1] = ':'; + } + else if (node_name[t1] == ')') + { + buffer[t1] = ']'; + } + else if (node_name[t1] == '(') + { + buffer[t1] = '['; + } + else + { + buffer[t1] = node_name[t1]; + } + t1++; + } + buffer[t1] = '\0'; + + return(buffer); +} + +void +io_write_slif_name(fp, node, short_flag) +FILE *fp; +node_t *node; +int short_flag; +{ + node_t *po; + + if (node->type == INTERNAL && io_po_fanout_count(node, &po) == 1) { + io_fputs_break(fp, short_flag ? po->short_name : replace_chars_in(po->name)); + } else { + io_fputs_break(fp, short_flag ? node->short_name : replace_chars_in(node->name)); + } +} + +int +own_strcmp(p,q) +char *p, *q; +{ + if ((p == NULL) || (q == NULL)) return -1; + + return(strcmp(p,q)); +} + +#endif /* 0 */ diff --git a/sis/io/write_util.c b/sis/io/write_util.c new file mode 100644 index 0000000..0b36265 --- /dev/null +++ b/sis/io/write_util.c @@ -0,0 +1,615 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/io/write_util.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/02/09 07:06:12 $ + * + */ +#include "sis.h" +#include "io_int.h" + + +static void +write_cover(fp, p) +FILE *fp; +node_t *p; +{ + register pset last, ps; + register int c, i; + + if (p->type == PRIMARY_OUTPUT) { + io_fputs_break(fp, "1 1\n"); + } + else { + foreach_set (p->F, last, ps) { + for (i = 0; i < p->nin; i++) { + c = "?01-"[GETINPUT(ps,i)]; + io_fputc_break(fp, c); + } + io_fputs_break(fp, " 1\n"); + } + } +} + +int +io_po_fanout_count(node, first) +node_t *node; +node_t **first; +{ + register int po_cnt; + register node_t *p; + lsGen gen; + + po_cnt = 0; + foreach_fanout(node, gen, p) { + if (p->type == PRIMARY_OUTPUT) { + if (first != NIL(node_t *) && po_cnt == 0) { + *first = p; + } + po_cnt++; + } + } + return po_cnt; +} + +#ifdef SIS +int +io_rpo_fanout_count(node, first) +node_t *node; +node_t **first; +{ + register int rpo_cnt; + register node_t *p; + lsGen gen; + network_t *network; + + network = node_network(node); + rpo_cnt = 0; + foreach_fanout(node, gen, p) { + if (network_is_real_po(network, p) != 0) { + if (first != NIL(node_t *) && rpo_cnt == 0) { + *first = p; + } + rpo_cnt++; + } + } + return rpo_cnt; +} + +int +io_lpo_fanout_count(node, first) +node_t *node; +node_t **first; +{ + register int lpo_cnt; + register node_t *p; + lsGen gen; + + lpo_cnt = 0; + foreach_fanout(node, gen, p) { + if (p->type == PRIMARY_OUTPUT && network_latch_end(p) != NIL(node_t)) { + if (first != 0 && lpo_cnt == 0) { + *first = p; + } + lpo_cnt++; + } + } + return lpo_cnt; +} +#endif /* SIS */ + +char * +io_name(node, short_flag) +node_t *node; +int short_flag; +{ + node_t *fo; +#ifdef SIS + node_type_t type; + network_t *network; + + type = node_type(node); + network = node_network(node); + + if (type == PRIMARY_OUTPUT) { + if (network_is_real_po(network, node) != 0) { + goto got_name; + } + else { + node = node_get_fanin(node, 0); + type = node_type(node); + } + } + if (type == PRIMARY_INPUT) { + if (network_is_real_pi(network, node) != 0) { + goto got_name; + } + } + if (io_rpo_fanout_count(node, &fo) == 1) { + node = fo; + } +got_name: + +#else + if (node_type(node) == INTERNAL) { + if (io_po_fanout_count(node, &fo) == 1) { + node = fo; + } + } +#endif /* SIS */ + + return(short_flag ? node->short_name : node->name); +} + +char * +io_node_name(node) +node_t *node; +{ + return(io_name(node, 0)); +} + +void +io_write_name(fp, node, short_flag) +FILE *fp; +node_t *node; +int short_flag; +{ + io_fputs_break(fp, io_name(node, short_flag)); +} + +/* + * During file write, some nodes shouldn't be printed, because they are + * artifacts of the sis network representation. + * + * 1. PIs are never printed + * 2. If node is a PO, only print node if all of: + * a. node is a real PO (not a latch input). + * b. fanin of node is internal and the fanin feeds > 1 real POs + * c. fanin of node is a real PI feeding > 1 real POs. + */ +int +io_node_should_be_printed(node) +node_t *node; +{ + node_type_t type; + node_t *fanin; +#ifdef SIS + network_t *network; + int rpo; +#endif /* SIS */ + + type = node_type(node); + + /* never print inputs ... */ + if (type == PRIMARY_INPUT) { + return(0); + } + + if (type == PRIMARY_OUTPUT) { + + /* print outputs only if fed by inputs, or if fed by > 1 node */ + +#ifdef SIS + network = node_network(node); + + /* never print latch inputs */ + if (network_is_real_po(network, node) == 0) { + return(0); + } + fanin = node_get_fanin(node, 0); + type = node_type(fanin); + + rpo = io_rpo_fanout_count(fanin, NIL(node_t *)); + if (type != PRIMARY_INPUT) { + if (rpo == 1) { + return(0); + } + } + /* just a sec, is this a real PI? */ + else if (rpo <= 1 && network_is_real_pi(network, fanin) == 0) { + return(0); + } + +#else + + fanin = node_get_fanin(node, 0); + if (node_type(fanin) != PRIMARY_INPUT) { + if (io_po_fanout_count(fanin, NIL(node_t *)) == 1) { + return(0); + } + } + +#endif /* SIS */ + } + return(1); +} + +static void +io_write_func(fp, n, short_flag, mapped) +FILE *fp; +node_t *n; +int short_flag; +int mapped; +{ + int i; + node_t *fanin; + lib_gate_t *gate; +#ifdef SIS + node_t *lpo; + int mlatch; +#endif /* SIS */ + + if (io_node_should_be_printed(n) == 0) { + return; + } + gate = lib_gate_of(n); + + if (mapped == 0 || gate == NIL(lib_gate_t)) { + io_fputs_break(fp, ".names"); + foreach_fanin(n, i, fanin) { + io_fputc_break(fp, ' '); + io_write_name(fp, fanin, short_flag); + } + io_fputc_break(fp, ' '); + io_write_name(fp, n, short_flag); + io_fputc_break(fp, '\n'); + + write_cover(fp, n); + } + else { + +#ifdef SIS + mlatch = io_lpo_fanout_count(n, &lpo); + if (mlatch == 0) { + io_fputs_break(fp, ".gate "); + } + else { + io_fputs_break(fp, ".mlatch "); + } + io_fputs_break(fp, lib_gate_name(gate)); + foreach_fanin (n, i, fanin) { + /* + * Do not output internal feedback pin from Qnext + */ + if (lib_gate_latch_pin(gate) != i) { + io_fprintf_break(fp, " %s=%s", lib_gate_pin_name(gate, i, /*in*/ 1), + io_name(fanin, short_flag)); + } + } + if (mlatch != 0) { /* latch gate */ + n = latch_get_output(latch_from_node(lpo)); + } + +#else + io_fprintf_break(fp, ".gate %s", lib_gate_name(gate)); + foreach_fanin (n, i, fanin) { + io_fprintf_break(fp, " %s=%s", lib_gate_pin_name(gate, i, 1), + io_name(fanin, short_flag)); + } + + +#endif /* SIS */ + + io_fprintf_break(fp, " %s=%s", lib_gate_pin_name(gate, 0, /*in*/ 0), + io_name(n, short_flag)); + } +} + +void +io_write_node(fp, node, short_flag) +FILE *fp; +node_t *node; +int short_flag; +{ + io_write_func(fp, node, short_flag, 0); +} + +void +io_write_gate(fp, node, short_flag) +FILE *fp; +node_t *node; +int short_flag; +{ + io_write_func(fp, node, short_flag, 1); +} + + +static int colnum; +static char *io_break_string = 0; +static int io_break_column = 32000; + + +/* + * write a string to a file, keeping track of current column number; + * force a newline to keep all lines < 80 columns (when possible) + */ + +/*VARARGS2*/ +void +io_fprintf_break(FILE *fp, char *fmt, ...) +{ + va_list args; + char buf[MAX_WORD]; + + va_start(args, fmt); + (void) vsprintf(buf, fmt, args); + io_fputs_break(fp, buf); + va_end(args); +} + +void +io_fputs_break(fp, s) +register FILE *fp; +register char *s; +{ + char *p; + + if (colnum+strlen(s) > io_break_column) { + if (io_break_string != 0) { + for(p = io_break_string; *p; p++) { + (void) putc(*p, fp); + colnum = (*p == '\n') ? 0 : colnum + 1; + } + } + } + for( ; *s; s++) { + (void) putc(*s, fp); + colnum = (*s == '\n') ? 0 : colnum + 1; + } +} + +void +io_fputc_break(fp, c) +FILE *fp; +int c; +{ + (void) putc(c, fp); + colnum = (c == '\n') ? 0 : colnum + 1; +} + + +void +io_fput_params(s, count) +char *s; +int count; +{ + io_break_string = s; + io_break_column = count; + colnum = 0; +} + + + +static int get_default_delay_param(); +static int get_delay_param(); + +#ifdef SIS +static void write_synch_edge(); +#endif /* SIS */ + +void +write_blif_slif_delay(fp, network, slif, short_flag) +FILE *fp; +network_t *network; +int slif; +int short_flag; +{ + delay_time_t delay; + node_t *pi, *po; + lsGen gen; + char *method; + char term; + + method = (slif == 0) ? "default_" : "global_attribute "; + term = (slif == 0) ? ' ' : ';'; + + if (slif){ + /* Also need to write out the type declarations for SLIF */ + io_fprintf_break(fp, ".type input_arrival %%f %%f ;\n"); + io_fprintf_break(fp, ".type output_required %%f %%f ;\n"); + io_fprintf_break(fp, ".type input_drive %%f %%f ;\n"); + io_fprintf_break(fp, ".type output_load %%f ;\n"); + } + + if (get_default_delay_param(network, DELAY_DEFAULT_ARRIVAL_RISE, &delay)) { + io_fprintf_break(fp, ".%sinput_arrival %4.2f %4.2f%c\n", method, + delay.rise, delay.fall, term); + } + if (get_default_delay_param(network, DELAY_DEFAULT_REQUIRED_RISE, &delay)) { + io_fprintf_break(fp, ".%soutput_required %4.2f %4.2f%c\n", method, + delay.rise, delay.fall, term); + } + if (get_default_delay_param(network, DELAY_DEFAULT_DRIVE_RISE, &delay)) { + io_fprintf_break(fp, ".%sinput_drive %4.2f %4.2f%c\n", method, + delay.rise, delay.fall, term); + } + if (get_default_delay_param(network, DELAY_DEFAULT_OUTPUT_LOAD, &delay)) { + io_fprintf_break(fp, ".%soutput_load %4.2f%c\n", method, delay.rise, + term); + } + if (get_default_delay_param(network, DELAY_DEFAULT_MAX_INPUT_LOAD, &delay)){ + io_fprintf_break(fp, ".%smax_input_load %4.2f%c\n", method, delay.rise, + term); + } + + if (slif == 0) { + method = ""; + } + + if (get_default_delay_param(network, DELAY_WIRE_LOAD_SLOPE, &delay)) { + io_fprintf_break(fp, ".%swire_load_slope %4.2f%c\n", method, + delay.rise, term); + } + + if (slif == 0) { + delay_print_blif_wire_loads(network, fp); + } +/* + else { + delay_print_slif_wire_loads(network, fp); + } +*/ + + if (slif != 0) { + method = "attribute "; + } + foreach_primary_input(network, gen, pi) { +#ifdef SIS + if (network_is_real_pi(network, pi) != 0) { +#endif /* SIS */ + if (get_delay_param(pi, DELAY_ARRIVAL_RISE, &delay)) { + io_fprintf_break(fp, ".%sinput_arrival %s %4.2f %4.2f", + method, io_name(pi, short_flag), delay.rise, delay.fall); +#ifdef SIS + if (slif == 0) { + write_synch_edge(fp, pi, short_flag); + } +#endif /* SIS */ + io_fputc_break(fp, term); + io_fputc_break(fp, '\n'); + } + if (get_delay_param(pi, DELAY_DRIVE_RISE, &delay)) { + io_fprintf_break(fp, ".%sinput_drive %s %4.2f %4.2f%c\n", + method, io_name(pi, short_flag), delay.rise, delay.fall, term); + } + if (get_delay_param(pi, DELAY_MAX_INPUT_LOAD, &delay)) { + io_fprintf_break(fp, ".%smax_input_load %s %4.2f%c\n", + method, io_name(pi, short_flag), delay.rise, term); + } +#ifdef SIS + } +#endif /* SIS */ + } + foreach_primary_output(network, gen, po) { +#ifdef SIS + if (network_is_real_po(network, po) != 0) { +#endif /* SIS */ + if (get_delay_param(po, DELAY_REQUIRED_RISE, &delay)) { + io_fprintf_break(fp, ".%soutput_required %s %4.2f %4.2f", + method, io_name(po, short_flag), delay.rise, delay.fall); +#ifdef SIS + if (slif == 0) { + write_synch_edge(fp, po, short_flag); + } +#endif /* SIS */ + io_fputc_break(fp, term); + io_fputc_break(fp, '\n'); + } + if (get_delay_param(po, DELAY_OUTPUT_LOAD, &delay)) { + io_fprintf_break(fp, ".%soutput_load %s %4.2f%c\n", method, + io_name(po, short_flag), delay.rise, term); + } +#ifdef SIS + } +#endif /* SIS */ + } +} + +#ifdef SIS + +static void +write_synch_edge(fp, pio, short_flag) +FILE *fp; +node_t *pio; +int short_flag; +{ + clock_edge_t edge; + int flag; + node_t *node; + + if (delay_get_synch_edge(pio, &edge, &flag) != 0) { + if ((node = network_find_node(node_network(pio), clock_name(edge.clock))) == NIL(node_t)) { + fail("Clock specified in sychronization edge is not in network"); + } + io_fprintf_break(fp, " %c %c'%s", + ((flag == BEFORE_CLOCK_EDGE) ? 'b' : 'a'), + ((edge.transition == RISE_TRANSITION) ? 'r' : 'f'), + io_name(node, short_flag)); + } +} +#endif /* SIS */ + +static int +get_default_delay_param(network, param, delay) +network_t *network; +delay_param_t param; +delay_time_t *delay; +{ + switch(param) { + case DELAY_DEFAULT_ARRIVAL_RISE: + delay->rise = delay_get_default_parameter(network, + DELAY_DEFAULT_ARRIVAL_RISE); + delay->fall = delay_get_default_parameter(network, + DELAY_DEFAULT_ARRIVAL_FALL); + break; + case DELAY_DEFAULT_DRIVE_RISE: + delay->rise = delay_get_default_parameter(network, + DELAY_DEFAULT_DRIVE_RISE); + delay->fall = delay_get_default_parameter(network, + DELAY_DEFAULT_DRIVE_FALL); + break; + case DELAY_DEFAULT_REQUIRED_RISE: + delay->rise = delay_get_default_parameter(network, + DELAY_DEFAULT_REQUIRED_RISE); + delay->fall = delay_get_default_parameter(network, + DELAY_DEFAULT_REQUIRED_FALL); + break; + case DELAY_DEFAULT_OUTPUT_LOAD: + delay->rise = delay_get_default_parameter(network, + DELAY_DEFAULT_OUTPUT_LOAD); + delay->fall = 0; + break; + case DELAY_DEFAULT_MAX_INPUT_LOAD: + delay->rise = delay_get_default_parameter(network, + DELAY_DEFAULT_MAX_INPUT_LOAD); + delay->fall = 0; + break; + case DELAY_WIRE_LOAD_SLOPE: + delay->rise = delay_get_default_parameter(network, + DELAY_WIRE_LOAD_SLOPE); + delay->fall = 0; + break; + } + + if (delay->rise == DELAY_NOT_SET || delay->fall == DELAY_NOT_SET) { + return(0); + } + return(1); +} + +static int +get_delay_param(node, param, delay) +node_t *node; +delay_param_t param; +delay_time_t *delay; +{ + switch(param) { + case DELAY_ARRIVAL_RISE: + delay->rise = delay_get_parameter(node, DELAY_ARRIVAL_RISE); + delay->fall = delay_get_parameter(node, DELAY_ARRIVAL_FALL); + break; + case DELAY_DRIVE_RISE: + delay->rise = delay_get_parameter(node, DELAY_DRIVE_RISE); + delay->fall = delay_get_parameter(node, DELAY_DRIVE_FALL); + break; + case DELAY_REQUIRED_RISE: + delay->rise = delay_get_parameter(node, DELAY_REQUIRED_RISE); + delay->fall = delay_get_parameter(node, DELAY_REQUIRED_FALL); + break; + case DELAY_OUTPUT_LOAD: + delay->rise = delay_get_parameter(node, DELAY_OUTPUT_LOAD); + delay->fall = 0; + break; + case DELAY_MAX_INPUT_LOAD: + delay->rise = delay_get_parameter(node, DELAY_MAX_INPUT_LOAD); + delay->fall = 0; + break; + } + + if (delay->rise == DELAY_NOT_SET || delay->fall == DELAY_NOT_SET) { + return 0; + } + return(1); +} diff --git a/sis/latch/Makefile.am b/sis/latch/Makefile.am new file mode 100644 index 0000000..1c0f3fa --- /dev/null +++ b/sis/latch/Makefile.am @@ -0,0 +1,7 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = liblatch.a +liblatch_a_SOURCES = com_latch.c latch.c +pkginclude_HEADERS = latch.h +dist_doc_DATA = latch.doc diff --git a/sis/latch/Makefile.in b/sis/latch/Makefile.in new file mode 100644 index 0000000..b0ba653 --- /dev/null +++ b/sis/latch/Makefile.in @@ -0,0 +1,418 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(liblatch_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/latch +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +liblatch_a_AR = $(AR) $(ARFLAGS) +liblatch_a_LIBADD = +am_liblatch_a_OBJECTS = com_latch.$(OBJEXT) latch.$(OBJEXT) +liblatch_a_OBJECTS = $(am_liblatch_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(liblatch_a_SOURCES) +DIST_SOURCES = $(liblatch_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = liblatch.a +liblatch_a_SOURCES = com_latch.c latch.c +pkginclude_HEADERS = latch.h +dist_doc_DATA = latch.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/latch/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/latch/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +liblatch.a: $(liblatch_a_OBJECTS) $(liblatch_a_DEPENDENCIES) + -rm -f liblatch.a + $(liblatch_a_AR) liblatch.a $(liblatch_a_OBJECTS) $(liblatch_a_LIBADD) + $(RANLIB) liblatch.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/latch/com_latch.c b/sis/latch/com_latch.c new file mode 100644 index 0000000..7df3ea6 --- /dev/null +++ b/sis/latch/com_latch.c @@ -0,0 +1,124 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/latch/com_latch.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +#ifdef SIS +#include "sis.h" + +static int +com_print_latch(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + latch_t *l; + latch_synch_t latch_type; + node_t *p; + node_t *control; + array_t *node_vec; + int i; + lsGen gen; + char *buf; + int summary = 0; + int c; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "s")) != EOF) { + switch(c) { + case 's': + summary = 1; + break; + default: + goto usage; + } + } + + node_vec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + if ((argc == 1) || ((argc == 2) && (summary))) { + foreach_latch(*network, gen, l) { + latch_type = latch_get_type(l); + if (latch_type == ACTIVE_HIGH) buf = "ah"; + if (latch_type == ACTIVE_LOW) buf = "al"; + if (latch_type == RISING_EDGE) buf = "re"; + if (latch_type == FALLING_EDGE) buf = "fe"; + if (latch_type == COMBINATIONAL) buf = "co"; + if (latch_type == ASYNCH) buf = "as"; + if (latch_type == UNKNOWN) buf = "un"; + (void) fprintf(sisout, "input: %s output: %s", + node_name(latch_get_input(l)), + node_name(latch_get_output(l))); + (void) fprintf(sisout, " init val: %d cur val: %d", + latch_get_initial_value(l), + latch_get_current_value(l)); + if (!summary) { + control = latch_get_control(l); + if (control != NIL(node_t)) { + (void) fprintf(sisout, " type: %s control: %s", buf, + node_name(control)); + } else { + (void) fprintf(sisout, " type: %s control: none", buf); + } + } + (void) fprintf(misout, "\n"); + } + (void) array_free(node_vec); + return 0; + } + for (i = 0; i < array_n(node_vec); i++){ + p = array_fetch(node_t *, node_vec, i); + l = latch_from_node(p); + if ((l = latch_from_node(p)) != NIL(latch_t)) { + latch_type = latch_get_type(l); + if (latch_type == ACTIVE_HIGH) buf = "ah"; + if (latch_type == ACTIVE_LOW) buf = "al"; + if (latch_type == RISING_EDGE) buf = "re"; + if (latch_type == FALLING_EDGE) buf = "fe"; + if (latch_type == COMBINATIONAL) buf = "co"; + if (latch_type == ASYNCH) buf = "as"; + if (latch_type == UNKNOWN) buf = "un"; + (void) fprintf(misout, "input: %s output: %s", + node_name(latch_get_input(l)), + node_name(latch_get_output(l))); + (void) fprintf(misout, " init val: %d cur val: %d", + latch_get_initial_value(l), + latch_get_current_value(l)); + if (!summary) { + control = latch_get_control(l); + if (control != NIL(node_t)) { + (void) fprintf(misout, " type: %s control: %s", buf, + node_name(control)); + } else { + (void) fprintf(misout, " type: %s control: none", buf); + } + } + (void) fprintf(misout, "\n"); + } else { + (void) fprintf(misout, + "\tNode %s is not a latch input or output\n", + node_name(p)); + } + } + array_free(node_vec); + return 0; + + usage: + + (void) fprintf(miserr, "usage: print_latch [-s] n1 n2 ... \n"); + return 1; +} + + +init_latch() +{ + com_add_command("print_latch", com_print_latch, 0); +} + +end_latch() +{ +} +#endif /* SIS */ diff --git a/sis/latch/latch.c b/sis/latch/latch.c new file mode 100644 index 0000000..0c0bfe0 --- /dev/null +++ b/sis/latch/latch.c @@ -0,0 +1,88 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/latch/latch.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +#ifdef SIS +#include "sis.h" + + +latch_t * +latch_alloc() +{ + latch_t *l; + + l = ALLOC(latch_t, 1); + l->latch_input = NIL(node_t); + l->latch_output = NIL(node_t); + l->initial_value = 3; + l->current_value = 3; + l->synch_type = UNKNOWN; + l->gate = NIL(lib_gate_t); + l->control = NIL(node_t); + l->undef1 = NIL(char); + return l; +} + +void +latch_free(l) +latch_t *l; +{ + if (l != NIL(latch_t)) { + FREE(l); + } +} + + +void +latch_set_control(latch, control) +latch_t *latch; +node_t *control; +{ + network_t *network; + + if (control != NIL(node_t)) { + network = node_network(control); + if (network == NIL(network_t)) { + fail("latch_set_control: node not part of network"); + } + (void) st_insert(network->latch_table, (char *) control, NIL(char)); + } + latch->control = control; +} + + +latch_t * +latch_from_node(n) +node_t *n; +{ + network_t *network; + latch_t *latch; + + network = node_network(n); + if (network == NIL(network_t)) { + fail("latch_from_node: node not part of a network"); + } + if (st_lookup(network->latch_table, (char *) n, (char **) &latch)) { + return latch; + } else { + return NIL(latch_t); + } +} + + +int +latch_equal(l1, l2) +latch_t *l1, *l2; +{ + if (latch_get_initial_value(l1) != latch_get_initial_value(l2)) return 0; + if (latch_get_type(l1) != latch_get_type(l2)) return 0; + if (latch_get_control(l1) != latch_get_control(l2)) return 0; + if (latch_get_gate(l1) != latch_get_gate(l2)) return 0; + return 1; +} +#endif /* SIS */ diff --git a/sis/latch/latch.doc b/sis/latch/latch.doc new file mode 100644 index 0000000..8f636cb --- /dev/null +++ b/sis/latch/latch.doc @@ -0,0 +1,131 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/latch/latch.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +latch_t * +latch_alloc() + + Allocate and return a new latch structure. + +void +latch_free(l) +latch_t *l; + + Free the latch structure for latch l. + +void +latch_set_input(l, n) +latch_t *l; +node_t *n; + + Set the input node of the latch l to node n. + +node_t * +latch_get_input(l) +latch_t *l; + + Return a pointer to the input node of the latch l. + +void +latch_set_output(l, n) +latch_t *l; +node_t *n; + + Set the output node of the latch l to node n. + +node_t * +latch_get_output(l) +latch_t *l; + + Return a pointer to the output node of the latch l. + +void +latch_set_initial_value(l, v) +latch_t *l; +int v; + + Takes a latch structure and sets the initial state value to v. + +int +latch_get_initial_value(l) +latch_t *l; + + Returns the value in the latch structure corresponding to the + initial state. + +void +latch_set_current_value(l, v) +latch_t *l; +int v; + + Takes a latch structure and sets the current state value to v. + +int +latch_get_current_value(l) +latch_t *l; + + Returns the value in the latch structure corresponding to the + current state. + +void +latch_set_type(l, t) +latch_t *l; +latch_synch_t t; + + Set the type of the latch l to t. The type is one of ACTIVE_HIGH, + ACTIVE_LOW, RISING_EDGE, FALLING_EDGE, and UNKNOWN. + +latch_synch_t +latch_get_type(l) +latch_t *l; + + Return the type of the latch l. + +void +latch_set_gate(l, g) +latch_t *l; +lib_gate_t *gate; + + Set the library gate that the latch l points to in a mapped network + to gate g. + +lib_gate_t * +latch_get_gate(l) +latch_t *l; + + Return the gate that the latch l points to. + +void +latch_set_control(l, g) +latch_t *l; +node_t *g; + + Set the gate that controls the latch l to gate g. + +node_t * +latch_get_control(l) +latch_t *l; + + Return the node that serves as the control for latch l. + +latch_t * +latch_from_node(node) +node_t *node; + + Returns the latch associated with the node, if it exists. Otherwise, + it returns NIL. It is a serious error if `node' is not part of + a network. + + +int +latch_equal(l1, l2) +latch_t *l1, *l2; + + Returns a 1 if all the fields of the two latches are identical, and + a 0 otherwise. This is used to merge two identical latches that + have the same data fanin signal. diff --git a/sis/latch/latch.h b/sis/latch/latch.h new file mode 100644 index 0000000..5bb9302 --- /dev/null +++ b/sis/latch/latch.h @@ -0,0 +1,77 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/latch/latch.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +typedef enum latch_synch_enum latch_synch_t; +enum latch_synch_enum { + ACTIVE_HIGH, ACTIVE_LOW, RISING_EDGE, FALLING_EDGE, COMBINATIONAL, + ASYNCH, UNKNOWN +}; + +typedef struct latch_struct latch_t; +struct latch_struct { + node_t *latch_input; /* must be a PRIMARY_OUTPUT */ + node_t *latch_output; /* must be a PRIMARY_INPUT */ + int initial_value; /* initial or reset state */ + int current_value; /* current state */ + latch_synch_t synch_type; /* type of latch */ + struct lib_gate_struct *gate; /* Reference to the library implementation */ + node_t *control; /* Pointer to the controlling gate */ + char *undef1; /* undefined 1, for the programer's use */ +}; + +EXTERN latch_t *latch_alloc ARGS((void)); +EXTERN void latch_free ARGS((latch_t *)); + +#define latch_set_input(l, n) \ + (void) ((l)->latch_input = n) + +#define latch_get_input(l) \ + (l)->latch_input + +#define latch_set_output(l, n) \ + (void) ((l)->latch_output = n) + +#define latch_get_output(l) \ + (l)->latch_output + +#define latch_set_initial_value(l, i) \ + (void) ((l)->initial_value = i) + +#define latch_get_initial_value(l) \ + (l)->initial_value + +#define latch_set_current_value(l, i) \ + (void) ((l)->current_value = i) + +#define latch_get_current_value(l) \ + (l)->current_value + +#define latch_set_type(l, t) \ + (void) ((l)->synch_type = t) + +#define latch_get_type(l) \ + (l)->synch_type + +#define latch_set_gate(l, g) \ + (void) ((l)->gate = g) + +#define latch_get_gate(l) \ + (l)->gate + +EXTERN void latch_set_control ARGS((latch_t *, node_t *)); + +#define latch_get_control(l) \ + (l)->control + +EXTERN latch_t *latch_from_node ARGS((node_t *)); + +EXTERN void network_create_latch ARGS((network_t *, latch_t **,node_t *,node_t *)); +EXTERN void network_delete_latch ARGS((network_t *,latch_t *)); +EXTERN void network_delete_latch_gen ARGS((network_t *,lsGen)); +EXTERN int latch_equal ARGS((latch_t *, latch_t *)); diff --git a/sis/linsolv/Makefile.am b/sis/linsolv/Makefile.am new file mode 100644 index 0000000..7b80efa --- /dev/null +++ b/sis/linsolv/Makefile.am @@ -0,0 +1,7 @@ +noinst_LIBRARIES = liblinsolv.a +liblinsolv_a_SOURCES = spAllocate.c spBuild.c spDefs.h \ + spFactor.c spOutput.c spSolve.c spUtils.c +pkginclude_HEADERS = spConfig.h spMatrix.h + +EXTRA_DIST = doc/advert.1 doc/advert.ms doc/install.ms doc/spDoc \ + doc/spDoc.ms diff --git a/sis/linsolv/Makefile.in b/sis/linsolv/Makefile.in new file mode 100644 index 0000000..afa0d96 --- /dev/null +++ b/sis/linsolv/Makefile.in @@ -0,0 +1,401 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +SOURCES = $(liblinsolv_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/linsolv +DIST_COMMON = $(pkginclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +liblinsolv_a_AR = $(AR) $(ARFLAGS) +liblinsolv_a_LIBADD = +am_liblinsolv_a_OBJECTS = spAllocate.$(OBJEXT) spBuild.$(OBJEXT) \ + spFactor.$(OBJEXT) spOutput.$(OBJEXT) spSolve.$(OBJEXT) \ + spUtils.$(OBJEXT) +liblinsolv_a_OBJECTS = $(am_liblinsolv_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(liblinsolv_a_SOURCES) +DIST_SOURCES = $(liblinsolv_a_SOURCES) +am__installdirs = "$(DESTDIR)$(pkgincludedir)" +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +noinst_LIBRARIES = liblinsolv.a +liblinsolv_a_SOURCES = spAllocate.c spBuild.c spDefs.h \ + spFactor.c spOutput.c spSolve.c spUtils.c + +pkginclude_HEADERS = spConfig.h spMatrix.h +EXTRA_DIST = doc/advert.1 doc/advert.ms doc/install.ms doc/spDoc \ + doc/spDoc.ms + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/linsolv/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/linsolv/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +liblinsolv.a: $(liblinsolv_a_OBJECTS) $(liblinsolv_a_DEPENDENCIES) + -rm -f liblinsolv.a + $(liblinsolv_a_AR) liblinsolv.a $(liblinsolv_a_OBJECTS) $(liblinsolv_a_LIBADD) + $(RANLIB) liblinsolv.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(mkdir_p) $(distdir)/doc + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-pkgincludeHEADERS \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/linsolv/doc/advert.1 b/sis/linsolv/doc/advert.1 new file mode 100644 index 0000000..e58260c --- /dev/null +++ b/sis/linsolv/doc/advert.1 @@ -0,0 +1,80 @@ +.ds f. advert.ms +.LP +.po 1.5i +.nr PO 1.5i +.rs +.ls 1 +.EQ +delim @@ +.EN + +.LG +.LG +.I +.ce 2 +Sparse1.3 +.sp .1i +A Sparse Linear Equation Solver +.NL +.NL +.sp 0.25i +.LG +.R +.ce 2 +.I Kenneth\ S.\ Kundert +.I Alberto\ Sangiovanni-Vincentelli +.NL +.sp 0.25i +.PP +\fISparse1.3\fP is a flexible package of subroutines written in C used +to quickly and accurately solve large sparse systems of linear +equations. The package is able to handle arbitrary real and complex +square matrix equations. Besides being able to solve linear systems, +it is also able to quickly solve transposed systems, find determinants, +and estimate errors due to ill-conditioning in the system of equations +and instability in the computations. \fISparse\fR also provides a test +program that is able read matrix equations from a file, solve them, and +print useful information about the equation and its solution. +.PP +\fISparse1.3\fR is generally as fast or faster than other popular +sparse matrix packages when solving many matrices of similar +structure. \fISparse\fR does not require or assume symmetry and is +able to perform numerical pivoting to avoid unnecessary error in the +solution. It handles its own memory allocation, which allows the user +to forgo the hassle of providing adequate memory. It also has a +natural, flexible, and efficient interface to the calling program. +.PP +\fISparse\fR was originally written for use in circuit simulators and +is particularly apt at handling node- and modified-node admittance +matrices. The systems of linear generated in a circuit simulator stem +from solving large systems of nonlinear equations using Newton's method +and integrating large stiff systems of ordinary differential +equations. However, \fISparse\fR is also suitable for other uses, one +in particular is solving the very large systems of linear equations +resulting from the numerical solution of partial differential +equations. +.PP +The \fISparse1.3\fR package is currently available from the Department +of Electrical Engineering and Computer Sciences of the University of +California, Berkeley. It was written in the C programming language by +Kenneth Kundert and versions exist for the \s-1UNIX\s+1 and +\s-1VAX/VMS\s+1 operating systems. Be sure to specify the version when +ordering. \fISparse1.3\fR has replaced \fISparse1.2\fR; providing +greater capability and speed, and a more refined interface to the +calling program. Besides the native \fISparse1.3\fR interface, two +others are also provided. The first is a \fISparse1.2\fR interface, +to make \fISparse1.3\fR backward compatible. The second allows +\fISparse.13\fR to be called from FORTRAN programs. +.PP +\fISparse\fR is available for a $150.00 charge. The package includes +the source code on tape, the user's guide, and a large selection of +test matrices. To obtain a copy of \fISparse\fR, send a check or money +order payable to the \fIRegents of the University of California\fR to: +.sp 0.25 +.nf + EECS Industrial Liaison Program + 461 Cory Hall + University of California + Berkeley, CA 94720 +.LP +Please allow four weeks for delivery. diff --git a/sis/linsolv/doc/advert.ms b/sis/linsolv/doc/advert.ms new file mode 100644 index 0000000..f20d86d --- /dev/null +++ b/sis/linsolv/doc/advert.ms @@ -0,0 +1,79 @@ +.LP +.po 1.5i +.nr PO 1.5i +.rs +.ls 1 +.EQ +delim @@ +.EN + +.LG +.LG +.I +.ce 2 +Sparse1.3 +.sp .1i +A Sparse Linear Equation Solver +.NL +.NL +.sp 0.25i +.LG +.R +.ce 2 +.I Kenneth\ S.\ Kundert +.I Alberto\ Sangiovanni-Vincentelli +.NL +.sp 0.25i +.PP +\fISparse1.3\fP is a flexible package of subroutines written in C used +to quickly and accurately solve large sparse systems of linear +equations. The package is able to handle arbitrary real and complex +square matrix equations. Besides being able to solve linear systems, +it is also able to quickly solve transposed systems, find determinants, +and estimate errors due to ill-conditioning in the system of equations +and instability in the computations. \fISparse\fR also provides a test +program that is able read matrix equations from a file, solve them, and +print useful information about the equation and its solution. +.PP +\fISparse1.3\fR is generally as fast or faster than other popular +sparse matrix packages when solving many matrices of similar +structure. \fISparse\fR does not require or assume symmetry and is +able to perform numerical pivoting to avoid unnecessary error in the +solution. It handles its own memory allocation, which allows the user +to forgo the hassle of providing adequate memory. It also has a +natural, flexible, and efficient interface to the calling program. +.PP +\fISparse\fR was originally written for use in circuit simulators and +is particularly apt at handling node- and modified-node admittance +matrices. The systems of linear generated in a circuit simulator stem +from solving large systems of nonlinear equations using Newton's method +and integrating large stiff systems of ordinary differential +equations. However, \fISparse\fR is also suitable for other uses, one +in particular is solving the very large systems of linear equations +resulting from the numerical solution of partial differential +equations. +.PP +The \fISparse1.3\fR package is currently available from the Department +of Electrical Engineering and Computer Sciences of the University of +California, Berkeley. It was written in the C programming language by +Kenneth Kundert and versions exist for the \s-1UNIX\s+1 and +\s-1VAX/VMS\s+1 operating systems. Be sure to specify the version when +ordering. \fISparse1.3\fR has replaced \fISparse1.2\fR; providing +greater capability and speed, and a more refined interface to the +calling program. Besides the native \fISparse1.3\fR interface, two +others are also provided. The first is a \fISparse1.2\fR interface, +to make \fISparse1.3\fR backward compatible. The second allows +\fISparse.13\fR to be called from FORTRAN programs. +.PP +\fISparse\fR is available for a $150.00 charge. The package includes +the source code on tape, the user's guide, and a large selection of +test matrices. To obtain a copy of \fISparse\fR, send a check or money +order payable to the \fIRegents of the University of California\fR to: +.sp 0.25 +.nf + EECS Industrial Liaison Program + 461 Cory Hall + University of California + Berkeley, CA 94720 +.LP +Please allow four weeks for delivery. diff --git a/sis/linsolv/doc/install.ms b/sis/linsolv/doc/install.ms new file mode 100644 index 0000000..862f532 --- /dev/null +++ b/sis/linsolv/doc/install.ms @@ -0,0 +1,116 @@ + +.LP +.EQ +delim $$ +.EN +.if t .po 1.5i +.if t .nr PO 1.5i +.if n .ll 7.5i +.if n .nr LL 7.5i +.rs +.ls 1 +.LP +.LG +.LG +.ce +.I "Sparse1.3 Installation Notes" +.NL +.NL +.sp .25i +.LP +.LG +.B "General Description" +.LP +When \fISparse1.3\fR is loaded from tape, a directory structure will be +created. The head directory is \fBsparse\fR, it contains source and +various utility files. The \fBdoc\fR subdirectory contains the users +manual and the \fBmatrices\fR subdirectory contains a collection of +test matrices and their solution. +.LP +Before compiling, the file \fBspConfig.h\fR should be modified to suit +your needs. Initially, I recommend turning on the DEBUG option and +testing the error state of \fISparse\fR after each call to a +\fISparse\fR routine. After things are working smoothly you can remove +most of the error checking. Also in \fBspConfig.h\fR is the machine +constants. These should be checked and modified before compiling if +you are not using a \s-1VAX\s+1. +.LP +\fISparse\fR is compiled by using the makefile provided. This is a +script file that automatically compiles each file and creates an object +file for all of \fISparse\fR. Also created is an executable test +program called \fBsparse\fR. +.LP +The \fISparse1.3\fR manual is contained in \fBspDoc\fR and +\fBspDoc.ms\fR. \fBspDoc\fR is preformatted and readable on line. +\fBspDoc.ms\fR is a raw \fItroff\fR file. +.sp .25i +.LP +.B UNIX +.LP +The +\fItar\fR +program was used to write +\fISparse\fR +on the tape at 1600 bpi. To read it, simply type: +.IP +.B "tar x" +.LP +This will load \fISparse\fR into the current directory and +automatically create the proper subdirectories. To compile, move into +the \fBsparse\fR directory and type: +.IP +.B make +.LP +To create a printed manual, move into the \fBdoc\fR subdirectory and type: +.IP +.B "make" +.LP +You may have to modify the make file to indicate the name of the printer +the document should be printed on. +.sp .25i +.LP +.B +VMS +.LP +\fISparse\fR was written on the tape in the ansi format at 1600 bpi and +so is readable by \fIcopy\fR. Once the tape has been read, a series of +files with nonsensical names will exist plus the file +\fBUNPACK.COM\fR. This file, when executed, creates the directory +hierarchy and moves the \fISparse\fR files into the proper directory +and gives them the proper names. Thus, \fISparse\fR is installed with +the following command sequence: +.IP +.B "MOUNT MFA0: SPARSE" +.br +.B "COPY MFA0:*.* *.*.*" +.br +.B "@UNPACK" +.LP +The file \fBUNPACK.COM\fR is then no longer needed. +.LP +Before compiling, it is necessary to edit the file \fBMAKE.COM\fR. The +last line of the file must be changed so that the correct directory +name for \fISparse\fR is given. This last line must be executed each +time you relogin and plan to use the \fISparse\fR test program; you may +want to copy it into \fBLOGIN.COM\fR. To compile, type: +.IP +.B @MAKE +.sp .75i +.LP +.B "Good Luck ..." +.LP +Every effort has been made to make \fISparse\fR +a pleasant program to work with. I hope you find it so. If you have +any comments, criticisms, or praise, I would like to hear from you. I +would be especially be interested in reports on any bugs you may find, +however I cannot promise to reply. + +.nf +Ken Kundert +Dept. of Electrical Engineering and Computer Sciences +University of California +Berkeley, California 94720 +June 1988 + +sparse@ic.berkeley.edu +ucbvax!ic!sparse diff --git a/sis/linsolv/doc/spDoc b/sis/linsolv/doc/spDoc new file mode 100644 index 0000000..1e77d7c --- /dev/null +++ b/sis/linsolv/doc/spDoc @@ -0,0 +1,5212 @@ + + + + + + + + + + + + + + + + + + + Sparse User's Guide + + A Sparse Linear Equation Solver + + + Version 1.3a + + 1 April 1988 + + + + + + Kenneth S. Kundert + Alberto Sangiovanni-Vincentelli + + + + + + + Department of + Electrical Engineering and Computer Sciences + University of California, Berkeley + Berkeley, Calif. 94720 + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + + + +1: INTRODUCTION + + Sparse1.3 is a flexible package of subroutines written in C used to +quickly and accurately solve large sparse systems of linear equations. The +package is able to handle arbitrary real and complex square matrix equa- +tions. Besides being able to solve linear systems, it is also able to +quickly solve transposed systems, find determinants, and estimate errors +due to ill-conditioning in the system of equations and instability in the +computations. Sparse also provides a test program that is able read matrix +equations from a file, solve them, and print useful information about the +equation and its solution. + + Sparse1.3 is generally as fast or faster than other popular sparse +matrix packages when solving many matrices of similar structure. Sparse +does not require or assume symmetry and is able to perform numerical pivot- +ing to avoid unnecessary error in the solution. It handles its own memory +allocation, which allows the user to forgo the hassle of providing adequate +memory. It also has a natural, flexible, and efficient interface to the +calling program. + + Sparse was originally written for use in circuit simulators and is +particularly apt at handling node- and modified-node admittance matrices. +The systems of linear generated in a circuit simulator stem from solving +large systems of nonlinear equations using Newton's method and integrating +large stiff systems of ordinary differential equations. However, Sparse is +also suitable for other uses, one in particular is solving the very large +systems of linear equations resulting from the numerical solution of par- +tial differential equations. + + +1.1: Features of Sparse1.3 + + Beyond the basic capability of being able to create, factor and solve +systems of equations, this package features several other capabilities that +enhance its utility. These features are: + +o Ability to handle both real and complex systems of equations. Both + types may resident and active at the same time. In fact, the same + matrix may alternate between being real and complex. + +o Ability to quickly solve the transposed system. This feature is use- + ful when computing the sensitivity of a circuit using the adjoint + method. + +o Memory for elements in the matrix is allocated dynamically, so the + size of the matrix is only limited by the amount of memory available + to Sparse and the range of the integer data type, which is used to + hold matrix indices. + +o Ability to efficiently compute the condition number of the matrix and + an a posteriori estimate of the error caused by growth in the size of + the elements during the factorization. + +o Much of the matrix initialization can be performed by Sparse, + + + + June 23, 1988 + + + + + + - 2 - + + + providing advantages in speed and simplified coding of the calling + program. + +o Ability to preorder modified node admittance matrices to enhance accu- + racy and speed. + +o Ability to exploit sparsity in the right-hand side vector to reduce + unnecessary computation. + +o Ability to scale matrices prior to factoring to reduce uncertainty in + the solution. + +o The ability to create and build a matrix without knowing its final + size. + +o The ability to add elements, and rows and columns, to a matrix after + the matrix has been reordered. + +o The ability to delete rows and columns from a matrix. + +o The ability to strip the fill-ins from a matrix. This can improve the + efficiency of a subsequent reordering. + +o The ability to handle matrices that have rows and columns missing from + their input description. + +o Ability to output the matrix in forms readable by either by people or + by the Sparse package. Basic statistics on the matrix can also be + output. + +o By default all arithmetic operations and number storage use double + precision. Thus, Sparse usually gives accurate results, even on + highly ill-conditioned systems. If so desired, Sparse can be easily + configured to use single precision arithmetic. + + +1.2: Enhancements of Sparse1.3 over Sparse1.2 + + Most notable of the enhancements provided by Sparse1.3 is that it is +considerably faster on dense matrices. Also, external names have been made +unique to 7 characters and the Sparse prefix sp has been prepended to all +externally accessible names to avoid conflicts. In addition, a routine +that efficiently estimates the condition number of a matrix has been added +and the code that estimates the growth in the factorization has been split +off from the actual factorization so that it is computed only when needed. + + It is now possible for the user program to store information in the +matrix elements. It is also possible to provide a subroutine to Sparse +that uses that information to initialize the matrix. This can greatly sim- +plify the user's code. + + Though the interface between Sparse1.3 and the calling program has +changed considerable from previous version of Sparse, it is possible to +compile additional code that provides backward compatibility to Sparse1.2 + + + + June 23, 1988 + + + + + + - 3 - + + +at the expense of a slight loss of efficiency by setting a compiler option. +Sparse1.3 now also has an FORTRAN interface. Routines written in FORTRAN +can access almost all of the features Sparse1.3. + + +1.3: Copyright Information + + Sparse1.3 has been copyrighted. Permission to use, copy, modify, and +distribute this software and its documentation for any purpose and without +fee is hereby granted, provided that the copyright notice appear in all +copies, and Sparse and the University of California, Berkeley are refer- +enced in all documentation for the program or product in which Sparse is to +be installed. The authors and the University of California make no +representations as to the suitability of the software for any purpose. It +is provided `as is', without express or implied warranty. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 4 - + + +2: PRIMER + +2.1: Solving Matrix Equations + + Sparse contains a collection of C subprograms that can be used to +solve linear algebraic systems of equations. These systems are of the +form: + + Ax = b +where A is an nxn matrix, x is the vector of n unknowns and b is the vector +of n right-hand side terms. Through out this package A is denoted Matrix, +x is denoted Solution and b is denoted RHS (for right-hand side). The sys- +tem is solved using LU factorization, so the actual solution process is +broken into two steps, the factorization or decomposition of the matrix, +performed by spFactor(), and the forward and backward substitution, per- +formed by spSolve(). spFactor() factors the given matrix into upper and +lower triangular matrices independent of the right-hand side. Once this is +done, the solution vector can be determined efficiently for any number of +right-hand sides without refactoring the matrix. + + This package exploits the fact that large matrices usually are sparse +by not storing or operating on elements in the matrix that are zero. Stor- +ing zero elements is avoided by organizing the matrix into an orthogonal +linked-list. Thus, to access an element if only its indices are known +requires stepping through the list, which is slow. This function is per- +formed by the routine spGetElement(). It is used to initially enter data +into a matrix and to build the linked-list. Because it is common to +repeatedly solve matrices with identical zero/nonzero structure, it is pos- +sible to reuse the linked-list. Thus, the linked list is left in memory +and the element values are simply cleared by spClear() before the linked- +list is reused. To speed the entering of the element values into succes- +sive matrices, spGetElement() returns a pointer to the element in the +matrix. This pointer can then be used to place data directly into the +matrix without having to traverse through the linked-list. + + The order in which the rows and columns of the matrix are factored is +very important. It directly affects the amount of time required for the +factorization and the forward and backward substitution. It also affects +the accuracy of the result. The process of choosing this order is time +consuming, but fortunately it usually only has to be done once for each +particular matrix structure encountered. When a matrix with a new +zero/nonzero structure is to be factored, it is done by using spOr- +derAndFactor(). Subsequent matrices of the same structure are factored +with spFactor(). The latter routine does not have the ability to reorder +matrix, but it is considerably faster. It may be that a order chosen may +be unsuitable for subsequent factorizations. If this is known to be true a +priori, it is possible to use spOrderAndFactor() for the subsequent factor- +izations, with a noticeable speed penalty. spOrderAndFactor() monitors the +numerical stability of the factorization and will modify an existing order- +ing to maintain stability. Otherwise, an a posteriori measure of the +numerical stability of the factorization can be computed, and the matrix +reordered if necessary. + + The Sparse routines allow several matrices of different structures to + + + + June 23, 1988 + + + + + + - 5 - + + +be resident at once. When a matrix of a new structure is encountered, the +user calls spCreate(). This routine creates the basic frame for the +linked-list and returns a pointer to this frame. This pointer is then +passed as an argument to the other Sparse routines to indicate which matrix +is to be operated on. The number of matrices that can be kept in memory at +once is only limited by the amount of memory available to the user and the +size of the matrices. When a matrix frame is no longer needed, the memory +can be reclaimed by calling spDestroy(). + + A more complete discussion of sparse systems of equations, methods for +solving them, their error mechanisms, and the algorithms used in Sparse can +be found in Kundert [kundert86]. A particular emphasis is placed on +matrices resulting from circuit simulators. + + +2.2: Error Control + + There are two separate mechanisms that can cause errors during the +factoring and solution of a system of equations. The first is ill- +conditioning in the system. A system of equations is ill-conditioned if +the solution is excessively sensitive to disturbances in the input data, +which occurs when the system is nearly singular. If a system is ill- +conditioned then uncertainty in the result is unavoidable, even if A is +accurately factored into L and U. When ill-conditioning is a problem, the +problem as stated is probably ill-posed and the system should be reformu- +lated such that it is not so ill-conditioned. It is possible to measure +the ill-conditioning of matrix using spCondition(). This function returns +an estimate of the reciprocal of the condition number of the matrix (K(A)) +[strang80]. The condition number can be used when computing a bound on the +error in the solution using the following inequality [golub83]. + + ||dx|| (||dA|| ||db||) + ------ < K(A) (------ + ------) + higher order terms + ||x|| (||A|| ||b|| ) + +where dA and db are the uncertainties in the matrix and right-hand side +vector and are assumed small. + + The second mechanism that causes uncertainty is the build up of round- +off error. Roundoff error can become excessive if there is sufficient +growth in the size of the elements during the factorization. Growth is +controlled by careful pivoting. In Sparse, the pivoting is controlled by +the relative threshold parameter. In conventional full matrix techniques +the pivot is chosen to be the largest element in a column. When working +with sparse matrices it is important to choose pivots to minimize the +reduction in sparsity. The best pivot to retain sparsity is often not the +best pivot to retain accuracy. Thus, some compromise must be made. In +threshold pivoting, as used in this package, the best pivot to retain spar- +sity is used unless it is smaller than the relative threshold times the +largest element in the column. Thus, a relative threshold close to one +emphasizes accuracy so it will produce a minimum amount of growth, unfor- +tunately it also slows the factorization. A very small relative threshold +emphasizes maintenance of sparsity and so speeds the factorization, but can +result in a large amount of growth. In our experience, we have found that +a relative threshold of 0.001 seems to result in a satisfactory compromise +between speed and accuracy, though other authors suggest a more conserva- +tive value of 0.1 [duff86]. + + + June 23, 1988 + + + + + + - 6 - + + + The growth that occurred during a factorization can be computed by +taking the ratio of the largest matrix element in any stage of the factori- +zation to the largest matrix element before factorization. The two numbers +are estimated using spLargestElement(). If the growth is found to be +excessive after spOrderAndFactor(), then the relative threshold should be +increased and the matrix reconstructed and refactored. Once the matrix has +been ordered and factored without suffering too much growth, the amount of +growth that occurred should be recorded. If, on subsequent factorizations, +as performed by spFactor(), the amount of growth becomes significantly +larger, then the matrix should be reconstructed and reordered using the +same relative threshold with spOrderAndFactor(). If the growth is still +excessive, then the relative threshold should be raised again. + + +2.3: Building the Matrix + + It is not necessary to specify the size of the matrix before beginning +to add elements to it. When the compiler option EXPANDABLE is turned on it +is possible to initially specify the size of the matrix to any size equal +to or smaller than the final size of the matrix. Specifically, the matrix +size may be initially specified as zero. If this is done then, as the ele- +ments are entered into the matrix, the matrix is enlarged as needed. This +feature is particularly useful in circuit simulators because it allows the +building of the matrix as the circuit description is parsed. Note that +once the matrix has been reordered by the routines spMNA Preorder(), spFac- +tor() or spOrderAndFactor() the size of the matrix becomes fixed and may no +longer be enlarged unless the compiler option TRANSLATE is enabled. + + The TRANSLATE option allows Sparse to translate a non-packed set of +row and column numbers to an internal packed set. In other words, there +may be rows and columns missing from the external description of the +matrix. This feature provides two benefits. First, if two matrices are +identical in structure, except for a few missing rows and columns in one, +then the TRANSLATE option allows them to be treated identically. Simi- +larly, rows and columns may be deleted from a matrix after it has been +built and operated upon. Deletion of rows and columns is performed by the +function spDeleteRowAndCol(). Second, it allows the use of the functions +spGetElement(), spGetAdmittance(), spGetQuad(), and spGetOnes() after the +matrix has been reordered. These functions access the matrix by using row +and column indices, which have to be translated to internal indices once +the matrix is reordered. Thus, when TRANSLATE is used in conjunction with +the EXPANDABLE option, rows and columns may be added to a matrix after it +has been reordered. + + Another provided feature that is useful with circuit simulators is the +ability to add elements to the matrix in row zero or column zero. These +elements will have no affect on the matrix or the results. The benefit of +this is that when working with a nodal formulation, grounded components do +not have to be treated special when building the matrix. + + + + + + + + + June 23, 1988 + + + + + + - 7 - + + +2.4: Initializing the Matrix + + Once a matrix has been factored, it is necessary to clear the matrix +before it can be reloaded with new values. The straight forward way of +doing that is to call spClear(), which sets the value of every element in +the matrix to zero. Sparse also provides a more flexible way to clear the +matrix. Using spInitialize(), it is possible to clear and reload at least +part of the matrix in one step. + + Sparse allows the user to keep initialization information with each +structurally nonzero matrix element. Each element has a pointer that is +set and used by the user. The user can set this pointer using spInstallIn- +itInfo() and may read it using spGetInitInfo(). The function spInitial- +ize() is a user customizable way to initialize the matrix. Passed to this +routine is a function pointer. spInitialize() sweeps through every element +in the matrix and checks the pInitInfo pointer (the user supplied pointer). +If the pInitInfo is NULL, which is true unless the user changes it (always +true for fill-ins), then the element is zeroed. Otherwise, the function +pointer is called and passed the pInitInfo pointer as well as the element +pointer and the external row and column numbers, allowing the user to ini- +tialize the matrix element and the right-hand side. + + Why spInitialize() would be used over spClear() can be illustrated by +way of an example. Consider a circuit simulator that handles linear and +nonlinear resistors and capacitors performing a transient analysis. For +the linear resistors, a constant value is loaded into the matrix at each +time step and for each Newton iteration. For the linear capacitor, a value +is loaded into the matrix that is constant over Newton iterations, but is a +function of the time step and the integration method. The nonlinear com- +ponents contribute values to the matrix that change on every time step and +Newton iteration. + + Sparse allows the user to attach a data structure to each element in +the matrix. For this example, the user might attach a structure that held +several pieces of information, such as the conductance of the linear resis- +tor, the capacitance of the linear capacitor, the capacitance of the non- +linear capacitor, and perhaps past values of capacitances. The user also +provides a subroutine to spInitialize() that is called for each user- +created element in the matrix. This routine would, using the information +in the attached data structure, initialize the matrix element and perhaps +the right-hand side vector. + + In this example, the user supplied routine might load the linear con- +ductance into the matrix and multiply it by some voltage to find a current +that could be loaded into the right-hand side vector. For the capacitors, +the routine would first apply an integration method and then load the +matrix and the right-hand side. + + This approach is useful for two reasons. First, much of the work of +the device code in the simulator can be off-loaded onto the matrix package. +Since there are usually many devices, this usually results overall in a +simpler system. Second, the integration method can be hidden from the +simulator device code. Thus the integration method can be changed simply +by changing the routine handed to spInitialize(), resulting in a much + + + + June 23, 1988 + + + + + + - 8 - + + +cleaner and more easily maintained simulator. + + +2.5: Indices + + By far the most common errors made when using Sparse are related to +array indices. Sparse itself contributes to the problem by having several +different indexing schemes. There are three different options that affect +index bounds or the way indices are interpreted. The first is +ARRAY OFFSET, which only affects array indices. ARRAY OFFSET is a compiler +flag that selects whether arrays start at index zero or index one. Note +that if ARRAY OFFSET is zero then RHS[0] corresponds to row one in the +matrix and Solution[0] corresponds to column one. Further note that when +ARRAY OFFSET is set to one, then the allocated length of the arrays handed +to the Sparse routines should be at least the external size of the matrix +plus one. The main utility of ARRAY OFFSET is that it allows natural array +indexing when Sparse is coupled to programs in other languages. For exam- +ple; in FORTRAN arrays always start at one whereas in C array always start +at zero. Thus the first entry in a FORTRAN array corresponds to the +zero'th entry in a C array. Setting ARRAY OFFSET to zero allows the arrays +in FORTRAN to start at one rather than two. For the rest of this discus- +sion, assume that ARRAY OFFSET is set so that arrays start at one in the +program that calls Sparse. + + The second option that affects indices is EXPANDABLE. When EXPANDABLE +is set false the upper bound on array and matrix indices is Size, where +Size is a parameter handed to spCreate(). When EXPANDABLE set true, then +there is essentially no upper bound on array indices. Indeed, the size of +the matrix is determined by the largest row or column number handed to +Sparse. The upper bound on the array indices then equals the final size +determined by Sparse. This size can be determined by calling spGetSize(). + + + The final option that affects indices is TRANSLATE. This option was +provided to allow row and columns to be deleted, but it also allows row and +column numbers to be missing from the input description for a matrix. This +means that the size of the matrix is not determined by the largest row or +column number entered into the matrix. Rather, the size is determined by +the total number of rows or column entered. For example, if the elements +[2,3], [5,3], and [7,2] are entered into the matrix, the internal size of +the matrix becomes four while the external size is seven. The internal +size equals the number of rows and columns in the matrix while the external +size equals the largest row or column number entered into the matrix. Note +that if a row is entered into the matrix, then its corresponding column is +also entered, and vice versa. The indices used in the RHS and Solution +vectors correspond to the row and column indices in the matrix. Thus, for +this example, valid data is expected in RHS at locations 2, 3, 5 and 7. +Data at other locations is ignored. Similarly, valid data is returned in +Solution at locations 2, 3, 5, and 7. The other locations are left +unmolested. This shows that the length of the arrays correspond to the +external size of the matrix. Again, this value can be determined by spGet- +Size(). + + + + + + June 23, 1988 + + + + + + - 9 - + + +2.6: Configuring Sparse + + It is possible at compile-time to customize Sparse for your particular +application. This is done by changing the compiler options, which are kept +in the personality file, spConfig.h. There are three classes of choices +available. First are the Sparse options, which specify the dominant per- +sonality characteristics, such as if real and/or complex systems of equa- +tions are to be handled. The second class is the Sparse constants, such as +the default pivot threshold and the amount of memory initially allocated +per matrix. The last class is the machine constants. These numbers must +be updated when Sparse is ported to another machine. + + As an aid in the setup and testing of Sparse a test routine and +several test matrices and their solutions have been provided. The test +routine is capable of reading files generated by spFileMatrix() and +spFileVector(). + + By default Sparse stores all real numbers and performs all computa- +tions using double precision arithmetic. This can be changed by changing +the definition of spREAL from double to float. spREAL is defined in +spExports.h. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 10 - + + +3: INTRODUCTION TO THE SPARSE ROUTINES + +In this section the routines are grouped by function and briefly described. + +3.1: Creating the Matrix + +spCreate() + Allocates and initializes the data structure for a matrix. Necessari- + ly the first routine run for any particular matrix. + +spDestroy() + Destroys the data structure for a matrix and frees the memory. + +spSetReal() +spSetComplex() + These routines toggle a flag internal to Sparse that indicates that + the matrix is either real or complex. This is useful if both real and + complex matrices of identical structure are expected. + + +3.2: Building the Matrix + +spGetElement() + Assures that the specified element exists in the matrix data structure + and returns a pointer to it. + +spGetAdmittance() +spGetQuad() +spGetOnes() + These routines add a group of four related elements to the matrix. + spGetAdmittance() adds the four elements associated with a two termi- + nal admittance. spGetQuad() is a more general routine that is useful + for entering controlled sources to the matrix. spGetOnes() adds the + four structural ones to the matrix that are often encountered with + elements that do not have admittance representations. + +spDeleteRowAndCol() + This function is used to delete a row and column from the matrix. + + +3.3: Clearing the Matrix + +spClear() + Sets every element in the matrix to zero. + +spInitialize() + Runs a user provided initialization routine on each element in the ma- + trix. This routine would be used in lieu of spClear(). + +spGetInitInfo() +spInstallInitInfo() + These routines allow the user to install and read a user-provided + pointer to initialization data for a particular matrix element. + + + + + June 23, 1988 + + + + + + - 11 - + + + +spStripFills() + This routine returns a matrix to a semi-virgin state by removing all + fill-ins. This can be useful if a matrix is to be reordered and it + has changed significantly since it was previously ordered. This may + be the case if a few rows and columns have been added or deleted or if + the previous ordering was done on a matrix that was numerically quite + different than the matrix currently being factored. Stripping and + reordering a matrix may speed subsequent factorization if the current + ordering is inferior, whereas simply reordering will generally only + enhance accuracy and not speed. + + +3.4: Placing Data in the Matrix + +spADD REAL ELEMENT() +spADD IMAG ELEMENT() +spADD COMPLEX ELEMENT() + Adds a value to a particular matrix element. + +spADD REAL QUAD() +spADD IMAG QUAD() +spADD COMPLEX QUAD() + Adds a value to a group of four matrix elements. + + +3.5: Influencing the Factorization + +spMNA Preorder() + This routine preorders modified node admittance matrices so that + Sparse can take full advantage of their structure. In particular, + this routine tries to remove zeros from the diagonal so that diagonal + pivoting can be used more successfully. + +spPartition() + Sparse partitions the matrix in an attempt to make spFactor() run as + fast as possible. The partitioning is a relatively expensive opera- + tion that is not needed in all cases. spPartition() allows the user + specify a simpler and faster partitioning. + +spScale() + It is sometimes desirable to scale the rows and columns of a matrix in + to achieve a better pivoting order. This is particularly true in + modified node admittance matrices, where the size of the elements in a + matrix can easily vary through ten to twelve orders of magnitude. + This routine performs scaling on a matrix. + + +3.6: Factoring the Matrix + +spOrderAndFactor() + This routine chooses a pivot order for the matrix and factors it into + LU form. It handles both the initial factorization and subsequent + factorizations when a reordering is desired. + + + + June 23, 1988 + + + + + + - 12 - + + + +spFactor() + Factors a matrix that has already been ordered by spOrderAndFactor(). + If spFactor() is passed a matrix that needs ordering, it will automat- + ically pass the matrix to spOrderAndFactor(). + + +3.7: Solving the Matrix Equation + +spSolve() + Solves the matrix equation + + Ax = b + given the matrix A factored into LU form and b. + +spSolveTransposed() + When working with adjoint systems, such as in sensitivity analysis, it + is desirable to quickly solve + + T + A x = b + Once A has been factored into LU form, this routine can be used to + solve the transposed system without having to suffer the cost of fac- + toring the matrix again. + + +3.8: Numerical Error Estimation + +spCondition() + Estimates the L-infinity condition number of the matrix. This number + is a measure of the ill-conditioning in the matrix equation. It is + also useful for making estimates of the error in the solution. + +spNorm() + Returns the L-infinity norm (the maximum absolute row sum) of an un- + factored matrix. + +spPseudoCondition() + Returns the ratio of the largest pivot to the smallest pivot of a fac- + tored matrix. This is a rough indicator of ill-conditioning in the + matrix. + +spLargestElement() + If passed an unfactored matrix, this routine returns the absolute + value of the largest element in the matrix. If passed a factored ma- + trix, it returns an estimate of the largest element that occurred in + any of the reduced submatrices during the factorization. The ratio of + these two numbers (factored/unfactored) is the growth, which is used + to determine if the pivoting order is numerically satisfactory. + +spRoundoff() + Returns a bound on the magnitude of the largest element in E = A-LU, + where E represents error in the matrix resulting from roundoff error + during the factorization. + + + + + June 23, 1988 + + + + + + - 13 - + + +3.9: Matrix Operations + +spDeterminant() + This routine simply calculates and returns the determinant of the fac- + tored matrix. + +spMultiply() + This routine multiplys the matrix by a vector on the right. This is + useful for forming the product Ax = b in order to determine if a cal- + culated solution is correct. + +spMultTransposed() + Multiplys the transposed matrix by a vector on the right. This is + useful for forming the product A sup {roman T} x = b in order to + determine if a calculated solution is correct. + + +3.10: Matrix Statistics and Documentation + +spError() + Determines the error status of a particular matrix. While most of the + Sparse routines do return an indication that an error has occurred, + some do not and so spError() provides the only way of uncovering these + errors. + +spWhereSingular() + Returns the row and column number where the matrix was detected as + singular or where a zero pivot was found. + +spGetSize() + A function that returns the size of the matrix. Either the internal + or external size of the matrix is returned. The internal size of the + matrix is the actual size of the matrix whereas the external size is + the value of the largest row or column number. These two numbers may + differ if the TRANSLATE option is used. + +spElementCount() +spFillinCount() + Functions that return the total number of elements in the matrix, and + the number of fill-ins in the matrix. These functions are useful for + gathering statistics on matrices. + +spPrint() + This routine outputs the matrix as well as some statistics to standard + output in a format that is readable by people. The matrix can be + printed in either a compressed or standard format. In the standard + format, a numeric value is given for each structurally nonzero ele- + ment, whereas in the compressed format, only the existence or nonex- + istence of an element is indicated. This routine is not suitable for + use on large matrices. + + + + + + + + June 23, 1988 + + + + + + - 14 - + + + +spFileMatrix() +spFileVector() + These two routines send a copy of the matrix and its right-hand side + vector to a file. This file can then be read by the test program that + is included with Sparse. Only those elements of the matrix that are + structurally nonzero are output, so very large matrices can be sent to + a file. + +spFileStats() + This routine calculates and sends some useful statistics concerning a + matrix to a file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 15 - + + +4: SPARSE ROUTINES + +This section contains a complete list of the Sparse routines that are +available to the user. Each routine is described as to its function and +how to use it. The routines are listed in alphabetic order. + + + + + +4.1: spClear() + +Sets every element in the matrix to zero. The Sparse error state is +cleared to spOKAY in this routine. + +void spClear( Matrix ) + +o Argument: + + Matrix input (char *) + Pointer to matrix that is to be cleared. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 16 - + + + + + +4.2: spCondition() + +spCondition() computes an estimate of the condition number using a varia- +tion on the LINPACK condition number estimation algorithm. This quantity +is an measure of ill-conditioning in the matrix. To avoid problems with +overflow, the reciprocal of the condition number is returned. If this +number is small, and if the matrix is scaled such that uncertainties in the +RHS and the matrix entries are equilibrated, then the matrix is ill- +conditioned. If the this number is near one, the matrix is well condi- +tioned. This routine must only be used after a matrix has been factored by +spOrderAndFactor() or spFactor() and before it is cleared by spClear() or +spInitialize(). + +Unlike the LINPACK condition number estimator, this routines returns the L +infinity condition number. This is an artifact of Sparse placing ones on +the diagonal of the upper triangular matrix rather than the lower. This +difference should be of no importance. + +spREAL spCondition( Matrix, NormOfMatrix, Error ) + +o Returns: + An estimate of the L infinity condition number of the matrix. + +o Arguments: + + Matrix input (char *) + The matrix for which the condition number is desired. + + NormOfMatrix input (spREAL) + The L-infinity norm of the unfactored matrix as computed by + spNorm(). + + Error output (int *) + Used to return the error code. + +o Possible errors: + spSINGULAR + spNO MEMORY + Error is not cleared in this routine. + +o Compiler options that must be set for this routine to exist: + CONDITION + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 17 - + + + + + +4.3: spCreate() + +Allocates and initializes the data structures associated with a matrix. +This routine is necessarily the first routine run for any particular ma- +trix. + +char *spCreate( Size, Complex, Error ) + +o Returned: + A pointer to the matrix is returned cast into the form of a pointer to + a character. This pointer is then passed and used by the other matrix + routines to refer to a particular matrix. If an error occurs, the + NULL pointer is returned. + +o Arguments: + + Size input (int) + Size of matrix. When the compiler option EXPANDABLE is turned + on, Size is used as a lower bound on the size of the matrix. + Size must not be negative. + + Complex input (int) + Type of matrix. If Complex is 0 then the matrix is real, other- + wise the matrix will be complex. Note that if the routines are + not set up to handle the type of matrix requested, then a spPANIC + error will occur. + + Error output (int *) + Returns error flag, needed because function spError() will not + work correctly if spCreate() returns NULL. + +o Possible errors: + spNO MEMORY + spPANIC + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 18 - + + + + + +4.4: spDeleteRowAndCol() + +This function is used to delete a row and column from the matrix. The ele- +ments removed from the matrix are never used again and are not freed until +the matrix is destroyed and so the pointers to these elements remain valid. + +void spDeleteRowAndCol( Matrix, Row, Col ) + +o Arguments: + + Matrix input (char *) + The matrix from which the row and column are to be deleted. + + Row input (int) + The row to be deleted. + + Col input (int) + The column to be deleted. + +o Compiler options that must be set for this routine to exist: + DELETE + TRANSLATE + + + + + +4.5: spDestroy() + +Destroys a matrix frame and reclaims the memory. + +void spDestroy( Matrix ) + +o Argument: + + Matrix input (char *) + Pointer to the matrix frame which is to be removed from memory. + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 19 - + + + + + +4.6: spDeterminant() + +This routine in capable of calculating the determinant of the matrix once +the LU factorization has been performed. Hence, only use this routine +after spFactor() or spOrderAndFactor() and before spClear() or spInitial- +ize(). Note that the determinants of matrices can be very large or very +small. On large matrices, the determinant can be far larger or smaller +than can be represented by a floating point number. For this reason the +mantissa and exponent of the determinant are returned separately. + +void spDeterminant( Matrix, Exponent, Determinant ) +void spDeterminant( Matrix, Exponent, Determinant, iDeterminant ) + +o Arguments: + + Matrix input (char *) + The matrix for which the determinant is desired. + + Exponent output (int *) + The logarithm base 10 of the scale factor for the determinant. + To find the actual determinant, Exponent should be added to the + exponent of Determinant and iDeterminant. + + Determinant output (spREAL *) + The real portion of the determinant. If the matrix is real, then + the magnitude of this number is scaled to be greater than or + equal to 1.0 and less than 10.0. Otherwise the magnitude of the + complex determinant will be scaled such. + + iDeterminant output (spREAL *) + The imaginary portion of the determinant. When the matrix is + real this pointer need not be supplied; nothing will be returned. + +o Compiler options that must be set for this routine to exist: + DETERMINANT + +o Bugs: + The sign of determinant may be in error if rows and columns have been + added or deleted from matrix. + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 20 - + + + + + +4.7: spElementCount() + +Returns the total number of structurally nonzero elements in the matrix. + +int spElementCount( Matrix ) + +o Returns: + The total number of structurally nonzero elements. + +o Argument: + + Matrix input (char *) + Pointer to the matrix. + + + + + +4.8: spError() + +This function returns the error status of a matrix. + +int MatrixError( Matrix ) + +o Returned: + The error status of the given matrix. + +o Argument: + + Matrix input (char *) + The matrix for which the error status is desired. + +o Possible errors: + spOKAY + spILL CONDITIONED + spZERO PIVOT + spSINGULAR + spNO MEMORY + spPANIC + Error is not cleared in this routine. + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 21 - + + + + + +4.9: spFactor() + +This routine factors the matrix into LU form and is the companion routine +to spOrderAndFactor(). Unlike spOrderAndFactor(), spFactor() cannot change +the ordering. Its utility is that it is considerably faster. The standard +way to use these two routines is to first use spOrderAndFactor() for the +initial factorization. For subsequent factorizations, spFactor() is used. +If spFactor() is called for the initial factorization of the matrix, then +it will automatically call spOrderAndFactor() with the default thresholds. +If spFactor() finds a zero on the diagonal, it will terminate early and +complain. This does not necessarily mean that matrix is singular. Before +a matrix is condemned as being singular, it should be run through spOr- +derAndFactor(), which can reorder the matrix and remove the offensive zero +from the diagonal. + +int spFactor( Matrix ) + +o Returned: + The error code is returned. Possible errors are listed below. + +o Argument: + + Matrix input (char *) + Pointer to matrix to be factored. + +o Possible errors: + spZERO PIVOT + spNO MEMORY + spSINGULAR + spILL CONDITIONED + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 22 - + + + + +4.10: spFileMatrix() + +Writes matrix to file in format suitable to be read back in by the matrix +test program. Normally, spFileMatrix() should be executed before the ma- +trix is factored, otherwise matrix is output in factored form. If the ma- +trix is sent to a file without the header or data, it will be in a form +that is easily plotted by typical plotting programs. + +int spFileMatrix( Matrix, File, Label, Reordered, Data, Header ) + +o Returns: + One is returned if routine was successful, otherwise zero is returned. + The calling function can query errno (the system global error vari- + able) as to the reason why this routine failed. + +o Arguments: + + Matrix input (char *) + Pointer to matrix that is to be sent to file. + + File input (char *) + Name of output file. + + Label input (char *) + String that is transferred to file and used as a label. String + should fit on one line and have no embedded line feeds. + + Reordered input (int) + Specifies whether the matrix should be output using the original + order or in reordered form. Zero specifies original order. + + Data input (int) + Indicates that the element values should be output along with the + indices for each element. Element values are not output if Data + is zero. This parameter must be nonzero if matrix is to be read + by the Sparse test program. + + Header input (int) + If nonzero a header is output that includes that size of the ma- + trix and the label. This parameter must be nonzero if matrix is + to be read by the Sparse test program. + +o Compiler options that must be set for this routine to exist: + DOCUMENTATION + + + + + + + + + + + + June 23, 1988 + + + + + + - 23 - + + + + + +4.11: spFileStats() + +Appends useful information concerning the matrix to the end of a file. If +file does not exist, it is created. This file should not be the same as +one used to hold the matrix or vector if the matrix is to be read by the +Sparse test program. Should be executed after the matrix is factored. + +int spFileStats( Matrix, File, Label ) + +o Returns: + One is returned if routine was successful, otherwise zero is returned. + The calling function can query errno (the system global error vari- + able) as to the reason why this routine failed. + +o Arguments: + + Matrix input (char *) + Pointer to matrix for which statistics are desired. + + File input (char *) + Name of output file. + + Label input (char *) + String that is transferred to file and is used as a label. String + should fit on one line and have no embedded line feeds. + +o Compiler options that must be set for this routine to exist: + DOCUMENTATION + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 24 - + + + + + +4.12: spFileVector() + +Appends the RHS vector to the end of a file in a format suitable to be read +back in by the matrix test program. If file does not exist, it is created. +To be compatible with the test program, if spFileVector() is run, it must +be run after spFileMatrix() and use the same file. + +int spFileVector( Matrix, File, RHS ) +int spFileVector( Matrix, File, RHS, iRHS ) + +o Returns: + One is returned if routine was successful, otherwise zero is returned. + The calling function can query errno (the system global error vari- + able) as to the reason why this routine failed. + +o Arguments: + + Matrix input (char *) + Pointer to matrix that corresponds to the vector to be output. + + File input (char *) + Name of file where output is to be written. + + RHS input (spREAL[]) + The right-hand side vector. RHS contains only the real portion + of the right-hand side vector if the matrix is complex and + spSEPARATED COMPLEX VECTORS is set true. + + iRHS input (spREAL[]) + Right-hand side vector, imaginary portion. Not necessary if ma- + trix is real or if spSEPARATED COMPLEX VECTORS is set false. + +o Compiler options that must be set for this routine to exist: + DOCUMENTATION + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 25 - + + + + + +4.13: spFillinCount() + +Returns the total number of fill-ins in the matrix. A fill-in is an ele- +ment that is originally structurally zero, but becomes nonzero during the +factorization. + +int spFillinCount( Matrix ) + +o Returns: + The total number of fill-ins. + +o Argument: + + Matrix input (char *) + Pointer to the matrix. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 26 - + + + + + +4.14: spGetAdmittance() + +Performs same function as spGetElement() except rather than one element, +all four matrix elements for a floating admittance are reserved. This rou- +tine also works if the admittance is grounded (zero is the ground node). +This function returns a group of pointers to the four elements through Tem- +plate, which is an output. They are used by the spADD QUAD() macros to +directly access matrix elements during subsequent loads of the matrix. +spGetAdmittance() arranges the pointers in Template so that the +spADD QUAD() routines add the admittance to the elements at [Node1,Node1] +and [Node2,Node2] and subtract the admittance from the elements at +[Node1,Node2] and [Node2,Node1]. This routine is only to be used before +spMNA Preorder(), spFactor() or spOrderAndFactor() unless the compiler flag +TRANSLATE is enabled. + +int spGetAdmittance( Matrix, Node1, Node2, Template ) + +o Returned: + The error code is returned. Possible errors are listed below. + spGetAdmittance() does not clear the error state, so it is possible to + ignore the return code of each spGetAdmittance() call, and check for + errors after constructing the whole matrix by calling spError(). + +o Arguments: + + Matrix input (char *) + Pointer to the matrix that admittance is to be installed. + + Node1 input (int) + One node number for the admittance. Node1 must be in the range + [0..Size] unless either the TRANSLATE or EXPANDABLE compiler + flags are set true. In either case Node1 must not be negative. + + Node2 input (int) + Other node number for the admittance. Node2 must be in the range + [0..Size] unless either the TRANSLATE or EXPANDABLE compiler + flags are set true. In either case Node2 must not be negative. + + Template output (struct spTemplate *) + Collection of pointers to four elements that are later used to + directly address elements. User must supply the template, this + routine will fill it. + +o Possible errors: + spNO MEMORY + Error is not cleared in this routine. + +o Compiler options that must be set for this routine to exist: + QUAD ELEMENT + + + + + + + June 23, 1988 + + + + + + - 27 - + + + + + +4.15: spGetElement() + +Reserves an element at [Row,Col] and returns a pointer to it. If element +is not found then it is created and spliced into matrix. A pointer to the +real portion of the element is returned. This pointer is later used by the +spADD ELEMENT() macros to directly access the element. This routine is +only to be used before spMNA Preorder(), spFactor() or spOrderAndFactor() +unless the compiler option TRANSLATE is set true. + +spREAL *spGetElement( Matrix, Row, Col ) + +o Returned: + Returns a pointer to the element. This pointer is then used to + directly access the element during successive builds. Returns NULL if + insufficient memory is available. spGetElement() does not clear the + error state, so it is possible to ignore the return code of each + spGetElement() call, and check for errors after constructing the whole + matrix by calling spError(). + +o Arguments: + + Matrix input (char *) + Pointer to the matrix that the element is to be added to. + + Row input (int) + Row index for element. Row must be in the range [0..Size] unless + either the TRANSLATE or EXPANDABLE compiler flags are set true. + In either case Row must not be negative though it may be zero. + If zero then the element is not entered into the matrix, but is + otherwise treated normally. + + Col input (int) + Column index for element. Col must be in the range [0..Size] un- + less either the TRANSLATE or EXPANDABLE compiler flags are set + true. In either case Col must not be negative though it may be + zero. If zero then the element is not entered into the matrix, + but is otherwise treated normally. + +o Possible errors: + spNO MEMORY + Error is not cleared in this routine. + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 28 - + + + + + +4.16: spGetInitInfo() + +With the INITIALIZE compiler option enabled Sparse allows the user to keep +initialization information with each structurally nonzero matrix element. +Each element has a pointer (referred to as pInitInfo) that is set and used +by the user. This routine returns pInitInfo from a particular matrix ele- +ment. + +char *spGetInitInfo( pElement ) + +o Returned: + The user installed pointer pInitInfo. + +o Argument: + + pElement input (spREAL *) + Pointer to the element to which pInitInfo is attached. + +o Compiler options that must be set for this routine to exist: + INITIALIZE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 29 - + + + + +4.17: spGetOnes() + +Performs a similar function to spGetAdmittance() except that the four +reserved matrix elements are assumed to be structural ones generated by +components without admittance representations during a modified nodal +analysis. Positive ones are placed at [Pos,Eqn] and [Eqn,Pos] and negative +ones are placed at [Neg,Eqn] and [Eqn,Neg]. This function returns a group +of pointers to the four elements through Template, which is an output. +They are used by the spADD QUAD() macros to add the ones directly to the +matrix elements during subsequent loads of the matrix. This routine is +only to be used before spMNA Preorder(), spFactor() or spOrderAndFactor() +unless the compiler flag TRANSLATE is set true. + +int spGetOnes( Matrix, Pos, Neg, Eqn, Template ) + +o Returned: + The error code is returned. Possible errors are listed below. + spGetOnes() does not clear the error state, so it is possible to ig- + nore the return code of each spGetOnes() call, and check for errors + after constructing the whole matrix by calling spError(). + +o Arguments: + + Matrix input (char *) + Pointer to the matrix that ones are to be entered in. + + Pos input (int) + Number of positive node. Must be in the range of [0..Size] un- + less either the options EXPANDABLE or TRANSLATE are used. Zero + is the ground row. In no case may Pos be less than zero. + + Neg input (int) + Number of negative node. Must be in the range of [0..Size] un- + less either the options EXPANDABLE or TRANSLATE are used. Zero is + the ground row. In no case may Neg be less than zero. + + Eqn input (int) + Row that contains the branch equation. Must be in the range of + [1..Size] unless either the options EXPANDABLE or TRANSLATE are + used. In no case may Eqn be less than one. + + Template output (struct spTemplate *) + Collection of pointers to four elements that are later used to + directly address elements. User must supply the template, this + routine will fill it. + +o Possible errors: + spNO MEMORY + Error is not cleared in this routine. + +o Compiler options that must be set for this routine to exist: + QUAD ELEMENT + + + + June 23, 1988 + + + + + + - 30 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 31 - + + + + + +4.18: spGetQuad() + +Similar to spGetAdmittance(), except that spGetAdmittance() only handles +2-terminal components, whereas spGetQuad() handles simple 4-terminals as +well. These 4-terminals are simply generalized 2-terminals with the option +of having the sense terminals different from the source and sink terminals. +spGetQuad() installs four elements into the matrix and returns their +pointers in the Template structure, which is an output. The pointers are +arranged in Template such that when passed to one of the spADD QUAD() mac- +ros along with an admittance, the admittance will be added to the elements +at [Row1,Col1] and [Row2,Col2] and subtracted from the elements at +[Row1,Col2] and [Row2,Col1]. The routine works fine if any of the rows and +columns are zero. This routine is only to be used before spMNA Preorder(), +spFactor() or spOrderAndFactor() unless TRANSLATE is set true. + +int spGetQuad( Matrix, Row1, Row2, Col1, Col2, Template ) + +o Returned: + The error code is returned. Possible errors are listed below. spGet- + Quad() does not clear the error state, so it is possible to ignore the + return code of each spGetQuad() call, and check for errors after con- + structing the whole matrix by calling spError(). + +o Arguments: + + Matrix input (char *) + Pointer to the matrix that quad is to be entered in. + + Row1 input (int) + First row index for the elements. Row1 must be in the range + [0..Size] unless either the TRANSLATE or EXPANDABLE compiler + flags are set true. In either case Row1 must not be negative. + + Row2 input (int) + Second row index for the elements. Row2 must be in the range + [0..Size] unless either the TRANSLATE or EXPANDABLE compiler + flags are set true. In either case Row2 must not be negative. + + Col1 input (int) + First column index for the elements. Col1 must be in the range + [0..Size] unless either the TRANSLATE or EXPANDABLE compiler + flags are set true. In either case Col1 must not be negative. + + Col2 input (int) + Second column index for the elements. Col2 must be in the range + [0..Size] unless either the TRANSLATE or EXPANDABLE compiler + flags are set true. In either case Col2 must not be negative. + + Template output (struct spTemplate *) + Collection of pointers to four elements that are later used to + directly address elements. User must supply the template, this + routine will fill it. + + + + June 23, 1988 + + + + + + - 32 - + + +o Possible errors: + spNO MEMORY + Error is not cleared in this routine. + +o Compiler options that must be set for this routine to exist: + QUAD ELEMENT + + + + + +4.19: spGetSize() + +Returns the size of the matrix, either the internal or external size of the +matrix is returned. The internal size is the actual number of rows and +columns in the matrix. The external size is equal to the largest row or +column number. These numbers will be the same unless the TRANSLATE option +is enabled. + +int spGetSize( Matrix, External ) + +o Returned: + The size of the matrix. + +o Arguments: + + Matrix input (char *) + Pointer to the matrix for which the size is desired. + + External input (int) + If External is nonzero, the external size of the matrix is re- + turned, otherwise the internal size of the matrix is returned. + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 33 - + + + + + +4.20: spInitialize() + +spInitialize() is a user customizable way to initialize the matrix. Passed +to this routine is a function pointer. spInitialize() sweeps through every +element in the matrix and checks the pInitInfo pointer (the user supplied +pointer). If the pInitInfo is NULL, which is true unless the user changes +it (always true for fill-ins), then the element is zeroed. Otherwise, the +function pointer is called and passed the pInitInfo pointer as well as the +element pointer and the external row and column numbers allowing the user +to set the value of each element and perhaps the right-hand side vector. + +The user function (pInit()) is expected to return a nonzero integer if +there is a fatal error and zero otherwise. Upon encountering a nonzero re- +turn code, spInitialize() terminates and returns the error code. + +The Sparse error state is cleared to spOKAY in this routine. + +int spInitialize( Matrix, pInit ) + +o Returns: + The error code returned by pInit. + +o Arguments: + + Matrix input (char *) + Pointer to the matrix that is to be initialized. + + pInit input ((*int)()) + Pointer to a function that, given a pointer to an element, a + pointer to the users data structure containing initialization in- + formation for that element, and the row and column number of the + element, initializes it. + + +int pInit( pElement, pInitInfo, Row, Col ) + +o Returns: + Nonzero if fatal error, zero otherwise. + +o Arguments: + + pElement input (spREAL *) + The pointer to the real portion of the element. The real portion + can be accessed using either *pElement or pElement[0]. The ima- + ginary portion can be accessed using either *(pElement+1) or + pElement[1]. + + pInitInfo input (char *) + The user-installed pointer to the initialization data structure. + + Row input (int) + The external row number of the element. + + + + June 23, 1988 + + + + + + - 34 - + + + Col input (int) + The external column number of the element. + +o Compiler options that must be set for this routine to exist: + INITIALIZE + + + + + +4.21: spInstallInitInfo() + +With the INITIALIZE compiler option enabled Sparse allows the user to keep +initialization information with each structurally nonzero matrix element. +Each element has a pointer (referred to as pInitInfo) that is set and used +by the user. This routine installs the pointer pInitInfo into a particular +matrix element. + +void spInstallInitInfo( pElement, pInitInfo ) + +o Arguments: + + pElement input (spREAL *) + Pointer to the element to which pInitInfo is to be attached. + + pInitInfo input (char *) + The pointer pInitInfo. + +o Compiler options that must be set for this routine to exist: + INITIALIZE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 35 - + + + + + +4.22: spLargestElement() + +If this routine is called before the matrix is factored, it returns the ab- +solute value of the largest element in the matrix. If called after the ma- +trix has been factored, it returns a lower bound on the absolute value of +the largest element that occurred in any of the reduced submatrices during +the factorization. The ratio of these two numbers (factored/unfactored) is +the growth, which can be used to determine if the pivoting order is ade- +quate. A large growth implies that considerable error has been made in the +factorization and that it is probably a good idea to reorder the matrix. +If a large growth in encountered after using spFactor(), reconstruct the +matrix and refactor using spOrderAndFactor(). If a large growth is encoun- +tered after using spOrderAndFactor(), refactor using spOrderAndFactor() +with the pivot threshold increased, say to 0.1. + +spREAL spLargestElement( Matrix ) + +o Returns: + If matrix is unfactored, returns the magnitude of the largest element + in the matrix. If the matrix is factored, a bound on the magnitude of + the largest element in any of the reduced submatrices is returned. + +o Argument: + + Matrix input (char *) + Pointer to the matrix. + +o Compiler options that must be set for this routine to exist: + STABILITY + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 36 - + + + + + +4.23: spMNA Preorder() + +This routine massages modified node admittance matrices to improve the per- +formance of spOrderAndFactor(). It tries to remove structural zeros from +the diagonal by exploiting the fact that the row and column associated with +a zero diagonal usually have structural ones placed symmetrically. For +this routine to work, the structural ones must be exactly equal to either +one or negative one. This routine should be used only on modified node ad- +mittance matrices and must be executed after the matrix has been built but +before spScale(), spNorm(), spMultiply(), spFactor(), spOrderAndFactor() or +spDeleteRowAndCol() are executed. It should be executed for the initial +factorization only. + +void spMNA Preorder( Matrix ) + +o Argument: + + Matrix input (char *) + + Pointer to the matrix to be preordered. + +o Compiler options that must be set for this routine to exist: + MODIFIED NODAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 37 - + + + + +4.24: spMultiply() + +Multiplies Matrix by Solution on the right to find RHS. Assumes matrix has +not been factored. This routine can be used as a test to see if solutions +are correct. + +void spMultiply( Matrix, RHS, Solution ) +void spMultiply( Matrix, RHS, Solution, iRHS, iSolution ) + +o Arguments: + + Matrix input (char *) + Pointer to the matrix. + + RHS output (spREAL[]) + RHS is the right hand side vector. This is what is being solved + for. RHS contains only the real portion of the right-hand side + if spSEPARATED COMPLEX VECTORS is set true. + + Solution input (spREAL[]) + Solution is the vector being multiplied by the matrix. Solution + contains only the real portion of that vector if + spSEPARATED COMPLEX VECTORS is set true. + + iRHS output (spREAL[]) + iRHS is the imaginary portion of the right hand side. This is + what is being solved for. It is only necessary to supply iRHS if + the matrix is complex and spSEPARATED COMPLEX VECTORS is set + true. + + iSolution input (spREAL[]) + iSolution is the imaginary portion of the vector being multiplied + by the matrix. It is only necessary to supply iRHS if the matrix + is complex and spSEPARATED COMPLEX VECTORS is set true. + +o Compiler options that must be set for this routine to exist: + MULTIPLICATION + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 38 - + + + + + +4.25: spMultTransposed() + +Multiplies transposed Matrix by Solution on the right to find RHS. Assumes +matrix has not been factored. This routine can be used as a test to see if +solutions are correct. + +void spMultTransposed( Matrix, RHS, Solution ) +void spMultTransposed( Matrix, RHS, Solution, iRHS, iSolution ) + +o Arguments: + + Matrix input (char *) + Pointer to the matrix. + + RHS output (spREAL[]) + RHS is the right hand side vector. This is what is being solved + for. RHS contains only the real portion of the right-hand side + if spSEPARATED COMPLEX VECTORS is set true. + + Solution input (spREAL[]) + Solution is the vector being multiplied by the matrix. Solution + contains only the real portion of that vector if + spSEPARATED COMPLEX VECTORS is set true. + + iRHS output (spREAL[]) + iRHS is the imaginary portion of the right hand side. This is + what is being solved for. It is only necessary to supply iRHS if + the matrix is complex and spSEPARATED COMPLEX VECTORS is set + true. + + iSolution input (spREAL[]) + iSolution is the imaginary portion of the vector being multiplied + by the matrix. It is only necessary to supply iRHS if the matrix + is complex and spSEPARATED COMPLEX VECTORS is set true. + +o Compiler options that must be set for this routine to exist: + MULTIPLICATION + TRANSPOSE + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 39 - + + + + + +4.26: spNorm() + +Computes and returns the L-infinity norm of an unfactored matrix. This +number is used in computing the condition number of the matrix. It is a +fatal error to pass this routine a factored matrix. + +spREAL spNorm( Matrix ) + +o Returns: + The largest absolute row sum (the L-infinity norm) of the matrix. + +o Argument: + + Matrix input (char *) + Pointer to the matrix. + +o Compiler options that must be set for this routine to exist: + CONDITION + + + + + +4.27: spOrderAndFactor() + +This routine chooses a pivot order for the matrix and factors it into LU +form. It handles both the initial factorization and subsequent factoriza- +tions when a reordering or threshold pivoting is desired. This is handled +in a manner that is transparent to the user. + +int spOrderAndFactor( Matrix, RHS, Threshold, AbsoluteThreshold, DiagPivot- +ing ) + +o Returned: + The error code is returned. Possible errors are listed below. + +o Arguments: + + Matrix input (char *) + Pointer to matrix to be factored. + + RHS input (spREAL[]) + Representative RHS vector that is used to determine pivoting + order when the right-hand side vector is sparse. If a term in + RHS is zero, it is assumed that it will usually be zero. Con- + versely, a nonzero term in RHS indicates that the term will often + be nonzero. If RHS is a NULL pointer then the right-hand side + vector is assumed to be full and it is not used when determining + the pivoting order. + + Threshold input (spREAL) + This is the pivot threshold, which should be between zero and + one. If it is one then the pivoting method becomes complete + + + + June 23, 1988 + + + + + + - 40 - + + + pivoting, which is very slow and tends to fill up the matrix. If + it is set close to zero the pivoting method becomes strict Mar- + kowitz with no threshold. The pivot threshold is used to elim- + inate pivot candidates that would cause excessive element growth + if they were used. Element growth is the cause of roundoff + error, which can occur even in well-conditioned matrices. Set- + ting the threshold large will reduce element growth and roundoff + error, but setting it too large will cause execution time to be + excessive and will result in a large number of fill-ins. If this + occurs, accuracy can actually be degraded because of the large + number of operations required on the matrix due to the large + number of fill-ins. A good value for diagonal pivoting seems to + be 0.001 while a good value for complete pivoting appears to be + 0.1. The default is chosen by giving a value larger than one or + less than or equal to zero. Once the pivot threshold is set, the + value becomes the new default for later calls to spOrderAndFac- + tor. The threshold value should be increased and the matrix re- + solved if growth is found to be excessive. Changing the pivot + threshold does not improve performance on matrices where growth + is low, as is often the case with ill-conditioned matrices. The + default value of Threshold was choosen for use with nearly diago- + nally dominant matrices such as node- and modified-node admit- + tance matrices. For these matrices it is usually best to use + diagonal pivoting. For matrices without a strong diagonal, it is + usually best to use a larger threshold, such as 0.01 or 0.1. + + AbsoluteThreshold input (spREAL) + The absolute magnitude an element must have to be considered as a + pivot candidate, except as a last resort. This number should be + set significantly smaller than the smallest diagonal element that + is is expected to be placed in the matrix. If there is no rea- + sonable prediction for the lower bound on these elements, then + AbsoluteThreshold should be set to zero. AbsoluteThreshold is + used to reduce the possibility of choosing as a pivot an element + that has suffered heavy cancellation and as a result mainly con- + sists of roundoff error. Note that if AbsoluteThreshold is set + too large, it could drastically increase the time required to + factor and solve the matrix. AbsoluteThreshold should be nonne- + gative. If no element in the matrix is larger than Absolu- + teThreshold, the warning spILL CONDITIONED is returned. + + DiagPivoting input (int) + A flag indicating that pivot selection should be confined to the + diagonal if possible. If DiagPivoting is nonzero and if + DIAGONAL PIVOTING is enabled pivots will be chosen only from the + diagonal unless there are no diagonal elements that satisfy the + threshold criteria. Otherwise, the entire reduced submatrix is + searched when looking for a pivot. The diagonal pivoting in + Sparse is efficient and well refined, while the complete pivoting + is not. For symmetric and near symmetric matrices, it is best to + use diagonal pivoting because it results in the best performance + when reordering the matrix and when factoring the matrix without + ordering. If there is a considerable amount of nonsymmetry in + the matrix, then complete pivoting may result in a better + + + + June 23, 1988 + + + + + + - 41 - + + + equation ordering simply because there are more pivot candidates + to choose from. A better ordering results in faster subsequent + factorizations. However, the initial pivot selection process + takes considerably longer for complete pivoting. + +o Possible errors: + spNO MEMORY + spSINGULAR + spILL CONDITIONED + + + + + +4.28: spPartition() + +This routine determines the cost to factor each row using both direct and +indirect addressing and decides, on a row-by-row basis, which addressing +mode is fastest. This information is used in spFactor() to speed the fac- +torization. + +When factoring a previously ordered matrix using spFactor(), fISparse +operates on a row-at-a-time basis. For speed, on each step, the row being +updated is copied into a full vector and the operations are performed on +that vector. This can be done one of two ways, either using direct ad- +dressing or indirect addressing. Direct addressing is fastest when the ma- +trix is relatively dense and indirect addressing is best when the matrix is +quite sparse. The user selects the type of partition used with Mode. If +Mode is set to spDIRECT PARTITION, then the all rows are placed in the +direct addressing partition. Similarly, if Mode is set to +spINDIRECT PARTITION, then the all rows are placed in the indirect address- +ing partition. By setting Mode to spAUTO PARTITION, the user allows Sparse +to select the partition for each row individually. spFactor() generally +runs faster if Sparse is allowed to choose its own partitioning, however +choosing a partition is expensive. The time required to choose a partition +is of the same order of the cost to factor the matrix. If you plan to fac- +tor a large number of matrices with the same structure, it is best to let +Sparse choose the partition. Otherwise, you should choose the partition +based on the predicted density of the matrix. By default (i.e., if spPar- +tition() is never called), Sparse chooses the partition for each row indi- +vidually. + +void spPartition( Matrix, Mode ) + +o Arguments: + + Matrix input (char *) + Pointer to matrix to be partitioned. + + Mode input (int) + Mode must be one of three special codes: spDIRECT PARTITION, + spINDIRECT PARTITION, or spAUTO PARTITION. + + + + + + + June 23, 1988 + + + + + + - 42 - + + + + + +4.29: spPrint() + +Formats and send the matrix to standard output. Some elementary statistics +are also output. The matrix is output in a format that is readable by peo- +ple. This routine should not be used on large matrices. + +void spPrint( Matrix, PrintReordered, Data, Header ) + +o Arguments: + + Matrix input (char *) + Pointer to matrix to be printed. + + PrintReordered input (int) + Indicates whether the matrix should be printed out in its origi- + nal form, as input by the user, or whether it should be printed + in its reordered form, as used internally by the matrix routines. + A zero indicates that the matrix should be printed as inputed, a + one indicates that it should be printed reordered. + + Data input (int) + Boolean flag that when false indicates that output should be + compressed such that only the existence of an element should be + indicated rather than giving the actual value. Thus 10 times as + many elements can be printed on a row. A zero indicates that the + matrix should be printed compressed. A one signifies that the + matrix should be printed in all its glory. + + Header input (int) + A flag indicating that extra information should be printed, such + as row and column numbers. + +o Compiler options that must be set for this routine to exist: + DOCUMENTATION + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 43 - + + + + + +4.30: spPseudoCondition() + +Computes the magnitude of the ratio of the largest to the smallest pivots. +This quantity is an indicator of ill-conditioning in the matrix. If this +ratio is large, and if the matrix is scaled such that uncertainties in the +right-hand side vector and the matrix entries are equilibrated, then the +matrix is ill-conditioned. However, a small ratio does not necessarily im- +ply that the matrix is well-conditioned. This routine must only be used +after a matrix has been factored by spOrderAndFactor() or spFactor() and +before it is cleared by spClear() or spInitialize(). The pseudocondition +is faster to compute than the condition number calculated by spCondition(), +but is not as informative. + +spREAL spPseudoCondition( Matrix ) + +o Returns: + The magnitude of the ratio of the largest to smallest pivot used dur- + ing previous factorization. If the matrix was singular, zero is re- + turned. + +o Argument: + + Matrix input (char *) + Pointer to matrix. + +o Compiler options that must be set for this routine to exist: + PSEUDOCONDITION + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 44 - + + + + + +4.31: spRoundoff() + +Returns a bound on the magnitude of the largest element in E = A-LU, where +E represents error in the matrix resulting from roundoff during the factor- +ization. + +spREAL spRoundoff( Matrix, Rho ) + +o Returns: + Returns a bound on the magnitude of the largest element in E = A-LU. + +o Arguments: + + Matrix input (char *) + Pointer to matrix. Matrix must be factored. + + Rho input (spREAL) + The bound on the magnitude of the largest element in any of the + reduced submatrices. This is the number computed by the function + spLargestElement() when given a factored matrix. If this number + is negative, the bound will be computed automatically. + +o Compiler options that must be set for this routine to exist: + STABILITY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 45 - + + + + +4.32: spScale() + +This function scales the matrix to enhance the possibility of finding a +good pivoting order. Note that scaling enhances accuracy of the solution +only if it affects the pivoting order, so it only makes sense to scale the +matrix before spOrderAndFactor(). There are several things to take into +account when choosing the scale factors. First, the scale factors are +directly multiplied times the elements in the matrix. To prevent roundoff, +each scale factor should be equal to an integer power of the number base of +the machine. Since most machines operate in base two, scale factors should +be a power of two. Second, the matrix should be scaled such that the ma- +trix of element uncertainties is equilibrated. Third, this function multi- +plies the scale factors times the elements, so if one row tends to have un- +certainties 1000 times smaller than the other rows, then its scale factor +should be 1024, not 1/1024. Fourth, to save time, this function does not +scale rows or columns if their scale factors are equal to one. Thus, the +scale factors should be normalized to the most common scale factor. Rows +and columns should be normalized separately. For example, if the size of +the matrix is 100 and 10 rows tend to have uncertainties near 1e-6 and the +remaining 90 have uncertainties near 1e-12, then the scale factor for the +10 should be 1/1,048,576 and the scale factors for the remaining 90 should +be 1. Fifth, since this routine directly operates on the matrix, it is +necessary to apply the scale factors to the RHS and Solution vectors. It +may be easier to simply use spOrderAndFactor() on a scaled matrix to choose +the pivoting order, and then throw away the matrix. Subsequent factoriza- +tions, performed with spFactor(), will not need to have the RHS and Solu- +tion vectors descaled. + +void spScale( Matrix, RHS ScaleFactors, SolutionScaleFactors ) + +o Arguments: + + Matrix input (char *) + Pointer to the matrix to be scaled. + + RHS ScaleFactors input (spREAL[]) + The array of RHS scale factors. These factors scale the rows. + All scale factors are real-valued. + + SolutionScaleFactors input (spREAL[]) + The array of Solution scale factors. These factors scale the + columns. All scale factors are real-valued. + +o Compiler options that must be set for this routine to exist: + SCALING + + + + + + + + + + + June 23, 1988 + + + + + + - 46 - + + + + + +4.33: spSetComplex() + +The type of the matrix may then be toggled back and forth between complex +and real. This function changes the type of matrix to complex. For the +matrix to be set complex, the compiler option spCOMPLEX must be set true. + +void spSetComplex( Matrix ) + +o Argument: + + Matrix input (char *) + + The matrix that is to be to be complex. + + + + + +4.34: spSetReal() + +The type of the matrix may then be toggled back and forth between complex +and real. This function changes the type of matrix to real. For the ma- +trix to be set real, the compiler option REAL must be set true. + +void spSetReal( Matrix ) + +o Argument: + + Matrix input (char *) + The matrix that is to be real. + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 47 - + + + + + +4.35: spSolve() + +Performs the forward and backward elimination to find the unknown Solution +vector from RHS and the factored matrix. + +void spSolve( Matrix, RHS, Solution ) +void spSolve( Matrix, RHS, Solution, iRHS, iSolution ) + +o Arguments: + + Matrix input (char *) + Pointer to matrix. + + RHS input (spREAL[]) + RHS is the input data array, the right-hand side vector. RHS con- + tains only the real portion of the right-hand side vector if + spSEPARATED COMPLEX VECTORS is set true. RHS is undisturbed and + may be reused for other solves. + + Solution output (spREAL[]) + Solution is the output data array, the unknown vector. This rou- + tine is constructed such that RHS and Solution can be the same + array. Solution contains only the real portion of the unknown + vector if spSEPARATED COMPLEX VECTORS is set true. + + iRHS input (spREAL[]) + iRHS is the imaginary portion of the input data array, the + right-hand side vector. This data is undisturbed and may be + reused for other solves. This argument is unnecessary if the ma- + trix is real or spSEPARATED COMPLEX VECTORS is set false. + + iSolution output (spREAL[]) + iSolution is the imaginary portion of the output data array. + This routine is constructed such that iRHS and iSolution can be + the same array. This argument is unnecessary if the matrix is + real or spSEPARATED COMPLEX VECTORS is set false. + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 48 - + + + + + +4.36: spSolveTransposed() + +Performs the forward and backward elimination to find the unknown Solution +vector from RHS and the transposed factored matrix. This routine is useful +when performing sensitivity analysis on a circuit using the adjoint method. + +void spSolveTransposed( Matrix, RHS, Solution ) +void spSolveTransposed( Matrix, RHS, Solution, iRHS, iSolution ) + +o Arguments: + + Matrix input (char *) + Pointer to matrix. + + RHS input (spREAL[]) + RHS is the input data array, the right-hand side vector. RHS + contains only the real portion of the right-hand side vector if + spSEPARATED COMPLEX VECTORS is set true. RHS is undisturbed and + may be reused for other solves. + + Solution output (spREAL[]) + Solution is the output data array, the unknown vector. This rou- + tine is constructed such that RHS and Solution can be the same + array. Solution contains only the real portion of the unknown + vector if spSEPARATED COMPLEX VECTORS is set true. + + iRHS input (spREAL[]) + iRHS is the imaginary portion of the input data array, the + right-hand side vector. This data is undisturbed and may be + reused for other solves. This parameter is unnecessary if the + matrix is real or spSEPARATED COMPLEX VECTORS is set false. + + iSolution output (spREAL[]) + iSolution is the imaginary portion of the output data array. + This routine is constructed such that iRHS and iSolution can be + the same array. This parameter is unnecessary if the matrix is + real or spSEPARATED COMPLEX VECTORS is set false. + +o Compiler options that must be set for this routine to exist: + TRANSPOSE + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 49 - + + + + + +4.37: spStripFills() + +spStripFills() strips all accumulated fill-ins from a matrix. This is +often a useful thing to do before reordering a matrix to help insure that +subsequent factorizations will be as efficient as possible. + +void spStripFills( Matrix ) + +o Argument: + + Matrix input (char *) + The matrix to be stripped. + +o Compiler options that must be set for this routine to exist: + STRIP + + + + + +4.38: spWhereSingular() + +This function returns the row and column number where the matrix was +detected as singular or where a zero pivot was found. + +void spWhereSingular( Matrix, Row, Col ) + +o Arguments: + + Matrix input (char *) + Pointer to matrix. + + Row output (int *) + The row number. + + Row output (int *) + The column number. + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 50 - + + +5: MACRO FUNCTIONS +These macro functions are used to quickly enter data into the matrix using +pointers. These pointers are originally acquired by the user from +spGetElement(), spGetAdmittance(), spGetQuad(), and spGetOnes() during the +initial loading of the matrix. These macros work correctly even if the +elements they are to add data to are in row or column zero. + + The macros reside in the file spExports.h. To use them, this file +must be included in the file of the calling routine and that routine must +be written in C. + + +5.1: spADD REAL ELEMENT() + +Macro function that adds a real value to an element in the matrix by a +pointer. + +spADD REAL ELEMENT( pElement , Real ) + +o Arguments: + + pElement input (spREAL *) + A pointer to the element to which Real is to be added. + + Real input (spREAL) + The real value that is to be added to the element. + + + + + +5.2: spADD IMAG ELEMENT() + +Macro function that adds a imaginary value to an element in the matrix by a +pointer. + +spADD IMAG ELEMENT( pElement , Imag ) + +o Arguments: + + pElement input (spREAL *) + A pointer to the element to which Imag is to be added. + + Imag input (spREAL) + The imaginary value that is to be added to the element. + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 51 - + + + + + +5.3: spADD COMPLEX ELEMENT() + +Macro function that adds a complex value to an element in the matrix by a +pointer. + +spADD COMPLEX ELEMENT( pElement, Real, Imag ) + +o Arguments: + + pElement input (spREAL *) + A pointer to the element to which Real and Imag are to be added. + + Real input (spREAL) + The real value that is to be added to the element. + + Imag input (spREAL) + The imaginary value that is to be added to the element. + + + + + +5.4: spADD REAL QUAD() + +Macro that adds a real value to the four elements specified by Template. +The value is added to the first two elements in Template, and subtracted +from the last two. + +spADD REAL QUAD( Template, Real ) + +o Arguments: + + Template input (struct spTemplate) + Data structure containing the pointers to four matrix elements. + + Real input (spREAL) + Real value to be added to the elements. + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 52 - + + + + + +5.5: spADD IMAG QUAD() + +Macro that adds an imaginary value to the four elements specified by Tem- +plate. The value is added to the first two elements in Template, and sub- +tracted from the last two. + +spADD IMAG QUAD( Template, Imag ) + +o Arguments: + + Template input (struct spTemplate) + Data structure containing the pointers to four matrix elements. + + Imag input (spREAL) + Imaginary value to be added to the elements. + + + + + +5.6: spADD COMPLEX QUAD() + +Macro that adds a complex value to the four elements specified by Template. +The value is added to the first two elements in Template, and subtracted +from the last two. + +spADD COMPLEX QUAD( Template, Real, Imag ) + +o Arguments: + + Template input (struct spTemplate) + Data structure containing the pointers to four matrix elements. + + Real input (spREAL) + Real value to be added to the elements. + + Imag input (spREAL) + Imaginary value to be added to the elements. + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 53 - + + +6: CONFIGURING SPARSE + + Sparse has a extensive set of options and parameters that can be set +at compile time to alter the personality of the program. They also are +used to eliminate routines that are not needed so as to reduce the amount +of memory required to hold the object code. These options and parameters +consist of macros definitions and are contained in the file spConfig.h. To +configure Sparse, spConfig.h must be edited and then Sparse must be recom- +piled. + + Some terminology should be defined. The Markowitz row count is the +number of non-zero elements in a row excluding the one being considered as +pivot. There is one Markowitz row count for every row. The Markowitz +column count is defined similarly for columns. The Markowitz product for +an element is the product of its row and column counts. It is a measure of +how much work would be required on the next step of the factorization if +that element were chosen to be pivot. A small Markowitz product is desir- +able. For a more detailed explanation, see Kundert [kundert86]. + + +6.1: Sparse Options + +REAL + +This specifies that the routines are expected to handle real systems of +equations. The routines can be compiled to handle both real and complex +systems at the same time, but there is a slight speed and memory advantage +if the routines are complied to handle only real systems of equations. + + +spCOMPLEX + +This specifies that the routines will be complied to handle complex systems +of equations. + + +EXPANDABLE + +Setting this compiler flag true makes the matrix expandable before it has +been reordered. If the matrix is expandable, then if an element is added +that would be considered out of bounds in the current matrix, the size of +the matrix is increased to hold that element. As a result, the size of the +matrix need not be known before the matrix is built. The matrix can be al- +located with size zero and expanded. It is possible to expand the size of +a matrix after it is been reordered if TRANSLATE and EXPANDABLE are both +set true. + + + + + + + + + + + + + June 23, 1988 + + + + + + - 54 - + + + +TRANSLATE + +This option allows the set of external row and column numbers to be non- +packed. In other words, the row and column numbers need not be contiguous. +The priced paid for this flexibility is that when TRANSLATE is set true, +the time required to initially build the matrix will be greater because the +external row and column number must be translated into internal +equivalents. This translation brings about other benefits though. First, +the spGetElement(), spGetAdmittance(), spGetQuad(), and spGetOnes() rou- +tines may be used after the matrix has been factored. Further, elements, +and even rows and columns, may be added to the matrix, and rows and columns +may be deleted from the matrix, after it has been reordered. Note that +when the set of row and column number is not a packed set, neither are the +RHS and Solution vectors. Thus the size of these vectors must be at least +as large as the external size, which is the value of the largest given row +or column numbers. + + +INITIALIZE + +Causes the spInitialize(), spGetInitInfo(), and spInstallInitInfo() rou- +tines to be compiled. These routines allow the user to store and read one +pointer in each nonzero element in the matrix. spInitialize() then calls a +user specified function for each structural nonzero in the matrix, and in- +cludes this pointer as well as the external row and column numbers as argu- +ments. This allows the user to write custom matrix and right-hand side +vector initialization routines. + + +DIAGONAL PIVOTING + +Many matrices, and in particular node- and modified-node admittance ma- +trices, tend to be nearly symmetric and nearly diagonally dominant. For +these matrices, it is a good idea to select pivots from the diagonal. With +this option enabled, this is exactly what happens, though if no satisfacto- +ry pivot can be found on the diagonal, an off-diagonal pivot will be used. +If this option is disabled, Sparse does not preferentially search the diag- +onal. Because of this, Sparse has a wider variety of pivot candidates +available, and so presumably fewer fill-ins will be created. However, the +initial pivot selection process will take considerably longer. If working +with node admittance matrices, or other matrices with a strong diagonal, it +is probably best to use DIAGONAL PIVOTING for two reasons. First, accuracy +will be better because pivots will be chosen from the large diagonal ele- +ments, thus reducing the chance of growth and hence, roundoff. Second, a +near optimal ordering will be chosen quickly. If the class of matrices you +are working with does not have a strong diagonal, do not use +DIAGONAL PIVOTING, but consider using a larger threshold. When +DIAGONAL PIVOTING is turned off, the following options and constants are +not used: MODIFIED MARKOWITZ, MAX MARKOWITZ TIES, and TIES MULTIPLIER. + + + + + + + + + June 23, 1988 + + + + + + - 55 - + + + +ARRAY OFFSET + +This determines whether arrays start at an index of zero or one. This op- +tion is necessitated by the fact that standard C convention dictates that +arrays begin with an index of zero but the standard mathematic convention +states that arrays begin with an index of one. So if you prefer to start +your arrays with zero, or you're calling Sparse from some other programming +language, use an ARRAY OFFSET of 0. Otherwise, use an ARRAY OFFSET of 1. +Note that if you use an offset of one, the arrays that you pass to Sparse +must have an allocated length of one plus the external size of the matrix. +ARRAY OFFSET must be either 0 or 1, no other offsets are valid. + + +spSEPARATED COMPLEX VECTORS + +This specifies the format for complex vectors. If this is set false then a +complex vector is made up of one double sized array of spREALs in which the +real and imaginary numbers are placed alternately in the array. In other +words, the first entry would be Complex[1].Real, then comes +Complex[1].Imag, then Complex[2].Real, etc. If spSEPARATED COMPLEX VECTORS +is set true, then each complex vector is represented by two arrays of +spREALs, one with the real terms, the other with the imaginary. + + +MODIFIED MARKOWITZ + +This specifies that the modified Markowitz method of pivot selection is to +be used. The modified Markowitz method differs from standard Markowitz in +two ways. First, under modified Markowitz, the search for a pivot can be +terminated early if a adequate (in terms of sparsity) pivot candidate is +found. Thus, when using modified Markowitz, the initial factorization can +be faster, but at the expense of a suboptimal pivoting order that may slow +subsequent factorizations. The second difference is in the way modified +Markowitz breaks Markowitz ties. When two or more elements are pivot can- +didates and they all have the same Markowitz product, then the tie is bro- +ken by choosing the element that is best numerically. The numerically best +element is the one with the largest ratio of its magnitude to the magnitude +of the largest element in the same column, excluding itself. The modified +Markowitz method results in marginally better accuracy. + + +DELETE + +This specifies that the spDeleteRowAndCol() routine should be compiled. +Note that for this routine to be compiled, both DELETE and TRANSLATE should +be set true. + + +STRIP + +This specifies that the spStripFills() routine should be compiled. + + + + + + + + June 23, 1988 + + + + + + - 56 - + + + +MODIFIED NODAL + +This specifies that the spMNA Preorder(), the routine that preorders modi- +fied node admittance matrices, should be compiled. This routine results in +greater speed and accuracy if used with this type of matrix. + + +QUAD ELEMENT + +This specifies that the routines that allow four related elements to be en- +tered into the matrix at once should be compiled. The routines affected by +QUAD ELEMENT are spGetAdmittance(), spGetQuad(), and spGetOnes(). + + +TRANSPOSE + +This specifies that spSolveTranspose() and perhaps spMultTransposed(), +which operate on the matrix as if it was transposed, should be compiled. + +SCALING + +This specifies that the routine that performs scaling on the matrix should +be complied. Scaling is not strongly supported. The routine to scale the +matrix is provided, but no routines are provided to scale and descale the +RHS and Solution vectors. It is suggested that if scaling is desired, it +only be performed when the pivot order is being chosen, which is done in +spOrderAndFactor(). This, and when the condition number of the matrix is +calculated with spCondition(), are the only times scaling has an effect. +The scaling may then either be removed from the solution by the user or the +scaled factored matrix may simply be thrown away. + + +DOCUMENTATION + +This specifies that routines that are used to document the matrix, +spPrint(), spFileMatrix(), spFileVector(), and spFileStats(), should be +compiled. + + +DETERMINANT + +This specifies that the spDeterminant() routine should be complied. + + +STABILITY + +This specifies that spLargestElement() and spRoundoff() should be compiled. +These routines are used to check the stability (and hence the quality of +the pivoting) of the factorization by computing a bound on the size of the +element is the matrix E = A-LU. If this bound is very high after applying +spOrderAndFactor(), then the pivot threshold should be raised. If the +bound increases greatly after using spFactor(), then the matrix should +probably be reordered. + + + + + + June 23, 1988 + + + + + + - 57 - + + + +CONDITION + +This specifies that spCondition() and spNorm(), the code that computes a +good estimate of the condition number of the matrix, should be compiled. + + +PSEUDOCONDITION + +This specifies that spPseudoCondition(), the code that computes a crude and +easily fooled indicator of the ill-conditioning in the matrix, should be +compiled. + + +MULTIPLICATION + +This specifies that spMultiply() and perhaps spMultTransposed(), the rou- +tines that multiply an unfactored matrix by a vector, should be compiled. + + +FORTRAN + +This specifies that the FORTRAN interface to Sparse1.3 should be compiled. +The ARRAY OFFSET option should be set to NO when interfacing to FORTRAN +programs. + + +DEBUG + +This specifies that additional error checking should be compiled. The type +of errors checked are those that are common when the matrix routines are +first integrated into a user's program. Once the routines have been in- +tegrated in and are running smoothly, this option should be turned off. +With DEBUG enabled, Sparse is very defensive. If a Sparse routine is +called improperly, a message will be printed describing the file and line +number where the error was found and execution is aborted. One thing that +Sparse is particularly picky about is calling certain functions after an +error has occurred. If an error has occurred, do not call +spMNA Preorder(), spScale(), spOrderAndFactor(), spFactor(), spSolve(), or +spSolveTransposed() until the error has been cleared by spClear() or spIni- +tialize(). + + +spCOMPATIBILITY + +This specifies that Sparse1.3 should be configured to be upward compatible +from Sparse1.2. This option is not suggested for use in new software. +Sparse1.3, when configured to be compatible with Sparse1.2, is not com- +pletely compatible. In particular, if recompiling the calling program, it +is necessary to change the names of the Sparse1.2 include files. This op- +tion will go away on any future version of Sparse. + + + + + + + + + + June 23, 1988 + + + + + + - 58 - + + +6.2: Sparse Constants + + These constants are used throughout the sparse matrix routines. They +should be set to suit the type of matrices being solved. + + +DEFAULT THRESHOLD + +The threshold used if the user enters an invalid threshold. Also the +threshold used by spFactor() when calling spOrderAndFactor(). The default +threshold should not be less than or equal to zero nor larger than one. + + +DIAG PIVOTING AS DEFAULT + +This indicates whether spOrderAndFactor() should use diagonal pivoting as +default. This issue only arises when spOrderAndFactor() is called from +spFactor(). + + +SPACE FOR ELEMENTS + +This number multiplied by the size of the matrix equals the number of ele- +ments for which memory is initially allocated in spCreate(). + + +SPACE FOR FILL INS + +This number multiplied by the size of the matrix equals the number of ele- +ments for which memory is initially allocated and specifically reserved for +fill-ins in spCreate(). + + +ELEMENTS PER ALLOCATION + +The number of matrix elements requested from the malloc utility on each +call to it. Setting this value greater than one reduces the amount of +overhead spent in this system call. + + +MINIMUM ALLOCATED SIZE + +The minimum allocated size of a matrix. Note that this does not limit the +minimum size of a matrix. This just prevents having to resize a matrix +many times if the matrix is expandable, large and allocated with an es- +timated size of zero. This number must not be less than one. + + +EXPANSION FACTOR + +The minimum increase in the allocated size of the matrix when it is expand- +ed. This number must be greater than one but shouldn't be much larger than +two. + + + + + + + + + June 23, 1988 + + + + + + - 59 - + + + +MAX MARKOWITZ TIES + +This number is used for two slightly different things, both of which relate +to the search for the best pivot. First, it is the maximum number of ele- +ments that are Markowitz tied that will be sifted through when trying to +find the one that is numerically the best. Second, it creates an upper +bound on how large a Markowitz product can be before it eliminates the pos- +sibility of early termination of the pivot search. In other words, if the +product of the smallest Markowitz product yet found and TIES MULTIPLIER is +greater than MAX MARKOWITZ TIES, then no early termination takes place. +Set MAX MARKOWITZ TIES to some small value if no early termination of the +pivot search is desired. An array of spREALs is allocated of size +MAX MARKOWITZ TIES so it must be positive and shouldn't be too large. + + +TIES MULTIPLIER + +Specifies the number of Markowitz ties that are allowed to occur before the +search for the pivot is terminated early. Set to some large value if no +early termination of the pivot search is desired. This number is multi- +plied by the Markowitz product to determine how many ties are required for +early termination. This means that more elements will be searched before +early termination if a large number of fill-ins could be created by accept- +ing what is currently considered the best choice for the pivot. Setting +this number to zero effectively eliminates all pivoting, which should be +avoided. This number must be positive. + + +DEFAULT PARTITION + +Which partition mode is used by spPartition() as default. Possibilities +include: + + spDIRECT PARTITION - each row used direct addressing, best for a few + relatively dense matrices. + + spINDIRECT PARTITION - each row used indirect addressing, best for a + few very sparse matrices. + + spAUTO PARTITION - direct or indirect addressing is chosen on a row- + by-row basis, carries a large overhead, but speeds up both dense + and sparse matrices, best if there is a large number of matrices + that can use the same ordering. + + +PRINTER WIDTH + +Gives the number of characters printable in one page width. Set to 80 for +terminals and 132 for line printers. + + + + + + + + + + June 23, 1988 + + + + + + - 60 - + + +6.3: Machine Constants + +These numbers must be updated when the program is ported to a new machine. + + +MACHINE RESOLUTION + +This is the smallest positive real double precision number e such that +1 + e = 1. + + +LARGEST REAL + +The largest positive real number representable by a double. + + +SMALLEST REAL + +The smallest positive real number representable by a double. + + +LARGEST SHORT INTEGER + +The largest positive integer representable by a short. + + +LARGEST LONG INTEGER + +The largest positive integer representable by a long. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 61 - + + +7: EXPORTS + +7.1: Error Codes + + Errors are indicated with a integer error code. Macros definitions +for these error codes are set up and placed in the file spMatrix.h. They +may be imported into the users program to give readable names to the possi- +ble matrix errors. The possible error codes and there corresponding macros +are: + + + +spOKAY - 0 + +No error has occurred. + +spSMALL PIVOT - 1 + +When reordering the matrix, no element was found which satisfies the abso- +lute threshold criteria. The largest element in the matrix was chosen as +pivot. Nonfatal. + +spZERO DIAG - 2 + +Fatal error. A zero was encountered on the diagonal of the matrix. This +does not necessarily imply that the matrix is singular. When this error +occurs, the matrix should be reconstructed and factored using spOr- +derAndFactor(). + +spSINGULAR - 3 + +Fatal error. Matrix is singular, so no unique solution exists. + +spNO MEMORY - 4 + +Fatal error. Indicates that not enough memory is available from the system +to handle the matrix. + +spPANIC - 5 + +Fatal error indicating that the routines are being asked to do something +nonsensical or something they are not prepared for. This error may occur +when the matrix is specified to be real and the routines are not compiled +for real matrices, or when the matrix is specified to be complex and the +routines are not compiled to handle complex matrices. + +spFATAL - 2 + +Not an error flag, but rather the dividing line between fatal errors and +warnings. + + + + + + + + + June 23, 1988 + + + + + + - 62 - + + +7.2: Data Structures + + There is only one data structure that may need to be imported from +Sparse by the user. This data structure is used to hold pointers to four +related elements in matrix. It is used in conjunction with the routines + spGetAdmittance() + spGetOnes() + spGetQuad() + +spGetAdmittance(), spGetOnes(), and spGetQuad() stuff the structure which +is later used by the spADD QUAD() macros. It is also possible for the user +to collect four pointers returned by spGetElement() and stuff them into the +template. The spADD QUAD() macros add a value into Element1 and Element2 +and subtract the value from Element3 and Element4. The structure is: + + +struct spTemplate +{ spREAL *Element1; + spREAL *Element2; + spREAL *Element3Negated; + spREAL *Element4Negated; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 63 - + + +8: FORTRAN COMPATIBILITY + + The Sparse1.3 package contains routines that interface to a calling +program written in FORTRAN. Almost every externally available Sparse1.3 +routine has a counterpart defined with the same name except that the `sp' +prefix is changed to `sf'. The spADD ELEMENT() and spADD QUAD() macros are +also replaced with the sfAdd1() and sfAdd4() functions. + + Any interface between two languages is going to have portibility prob- +lems, this one is no exception. To ease porting the FORTRAN interface file +to different operating systems, the names of the interface functions can be +easily redefined (search for `Routine Renaming' in spFortran.c). When +interfacing to a FORTRAN program, the FORTRAN option should be set to YES +and the ARRAY OFFSET option should be set to NO (see spConfig.h). For +details on the return value and argument list of a particular interface +routine, see the file spFortran.c. + + A simple example of a FORTRAN program that calls Sparse follows. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 64 - + + +Example: + integer matrix, error, sfCreate, sfGetElement, spFactor + integer element(10) + double precision rhs(4), solution(4) + c + c create matrix + matrix = sfCreate(4,0,error) + c + c reserve elements + element(1) = sfGetElement(matrix,1,1) + element(2) = sfGetElement(matrix,1,2) + element(3) = sfGetElement(matrix,2,1) + element(4) = sfGetElement(matrix,2,2) + element(5) = sfGetElement(matrix,2,3) + element(6) = sfGetElement(matrix,3,2) + element(7) = sfGetElement(matrix,3,3) + element(8) = sfGetElement(matrix,3,4) + element(9) = sfGetElement(matrix,4,3) + element(10) = sfGetElement(matrix,4,4) + c + c clear matrix + call sfClear(matrix) + c + c load matrix + call sfAdd1Real(element(1), 2d0) + call sfAdd1Real(element(2), -1d0) + call sfAdd1Real(element(3), -1d0) + call sfAdd1Real(element(4), 3d0) + call sfAdd1Real(element(5), -1d0) + call sfAdd1Real(element(6), -1d0) + call sfAdd1Real(element(7), 3d0) + call sfAdd1Real(element(8), -1d0) + call sfAdd1Real(element(9), -1d0) + call sfAdd1Real(element(10), 3d0) + call sfprint(matrix, .false., .false., .true.) + rhs(1) = 34d0 + rhs(2) = 0d0 + rhs(3) = 0d0 + rhs(4) = 0d0 + c + c factor matrix + error = sfFactor(matrix) + c + c solve matrix + call sfSolve(matrix, rhs, solution) + write (6, 10) solution(1), solution(2), solution(3), solution(4) + 10 format (f 10.2) + end + + + + + + + + + + June 23, 1988 + + + + + + - 65 - + + +9: SPARSE TEST PROGRAM + + The Sparse package includes a test program that is able to read matrix +equations from text files and print their solution along with matrix +statistics and timing information. The program can also generate files +containing stripped versions of the unfactored and factored matrix suitable +for plotting using standard plotting programs, such as the UNIX graph and +plot commands. + +The Sparse test program is invoked using the following syntax. + + sparse [options] [file1] [file2] ... + + Options: + -s Print solution only. + -r x Use x as relative threshold. + -a x Use x as absolute threshold. + -n n Print first n terms of solution vector. + -i n Repeat build/factor/solve n times for better + timing results. + -b n Use column n of matrix as right-hand side + vector. + -p Create plot files ``filename.bef'' and + ``filename.aft''. + -c Use complete (as opposed to diagonal) pivot- + ing. + -x Treat real matrix as complex with imaginary + part zero. + -t Solve transposed system. + -u Print usage message. + + +The presence of certain options is dependent on whether the appropriate +Sparse option has been enabled. + +If no input files are specified, sparse reads from the standard input. The +syntax of the input file is as follows. The matrix begins with one line of +arbitrary text that acts as the label, followed by a line with the integer +size of the matrix and either the real or complex keywords. After the +header is an arbitrary number of lines that describe the structural +nonzeros in the matrix. These lines have the form row column data, where +row and column are integers and data is either one real number for real +matrices or a real/imaginary pair of numbers for complex matrices. Only +one structural nonzero is described per line and the section ends when +either row or column are zero. Following the matrix, an optional right- +hand side vector can be described. The vector is given one element per +line, the number of element must equal the size of the matrix. Only one +matrix and one vector are allowed per file, and the vector, if given, must +follow the matrix. + + + + + + + + + June 23, 1988 + + + + + + - 66 - + + +Example: + mat0 - Simple matrix. + 4 real + 1 1 2.0 + 1 2 -1.0 + 2 1 -1.0 + 2 2 3.0 + 2 3 -1.0 + 3 2 -1.0 + 3 3 3.0 + 3 4 -1.0 + 4 3 -1.0 + 4 4 3.0 + 0 0 0.0 + 34.0 + 0.0 + 0.0 + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 67 - + + +10: SPARSE FILES + + The following is a list of the files contained in the Sparse package +and a brief description of their contents. Of the files, only spConfig.h +is expected to be modified by the user and only spMatrix.h need be imported +into the program that calls Sparse. + + +spAlloc.c + +This file contains the routines for allocating and deallocating objects as- +sociated with the matrices, including the matrices themselves. + +o User accessible functions contained in this module: + spCreate() + spDestroy() + spError() + spWhereSingular() + spGetSize() + spSetReal() + spSetComplex() + spFillinCount() + spElementCount() + + +spBuild.c + +This file contains the routines for clearing and loading the matrix. + +o User accessible functions contained in this module: + spClear() + spGetAdmittance() + spGetElement() + spGetInitInfo() + spGetOnes() + spGetQuad() + spInitialize() + spInstallInitInfo() + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 68 - + + + +spCompat.c + +This file contains the routines for making Sparse1.3 upward compatible from +Sparse1.2. These routines are not suggested for use in new software. +These routines will not be available in future versions of Sparse. + +o User accessible functions contained in this module: + AddAdmittanceToMatrix() + AddComplexElementToMatrix() + AddComplexQuadElementToMatrix() + AddElementToMatrix() + AddImagElementToMatrix() + AddImagQuadElementToMatrix() + AddOnesToMatrix() + AddQuadToMatrix() + AddRealElementToMatrix() + AddRealQuadElementToMatrix() + CleanMatrix() + ClearMatrix() + ClearMatrixError() + CreateMatrix() + DecomposeMatrix() + DeleteRowAndColFromMatrix() + DestroyMatrix() + Determinant() + GetMatrixSize() + MatrixElementCount() + MatrixError() + MatrixFillinCount() + MatrixRoundoffError() + MultiplyMatrix() + OrderAndDecomposeMatrix() + OutputMatrixToFile() + PreorderForModifiedNodal() + PrintMatrix() + ScaleMatrix() + SetMatrixComplex() + SetMatrixReal() + SolveMatrix() + SolveTransposedMatrix() + + +spConfig.h + +This file contains the options that are used to customize the package. For +example, it is possible to specify whether only real or complex systems of +equations are to be solved. Also included in this file are the various +constants used by the Sparse package, such as the amount of memory initial- +ly allocated for each matrix and the largest real number represented by the +machine. The user is expected to modify this file to maximize the perfor- +mance of the routines with his/her matrices. + + + + + + June 23, 1988 + + + + + + - 69 - + + + +spDefs.h + +This module contains common data structure definitions and macros for the +sparse matrix routines. These definitions are meant to remain hidden from +the program that calls the sparse matrix routines. + + +spDoc + +This reference manual. spDoc contains the manual in a form that is read- +able on-line and spDoc.ms contains the manual in a form that is suitable +for input into the text formatting program troff using the -ms macros. + + +spFactor.c + +This file contains the routines for factoring matrices into LU form. + +o User accessible functions contained in this module: + spFactor() + spOrderAndFactor() + spPartition() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 70 - + + + +spFortran.c + +This file contains the routines for interfacing Sparse1.3 to a program +written in FORTRAN. The function and argument lists of the routines in +this file are almost identical to their C equivalents except that they are +suitable for calling from a FORTRAN program. The names of these routines +use the `sf' prefix to distinguish them from their C counterparts. + +o User accessible functions contained in this module: + sfAdd1Complex() + sfAdd1Imag() + sfAdd1Real() + sfAdd4Complex() + sfAdd4Imag() + sfAdd4Real() + sfClear() + sfCondition() + sfCreate() + sfDeleteRowAndCol() + sfDestroy() + sfDeterminant() + sfElementCount() + sfError() + sfFactor() + sfFileMatrix() + sfFileStats() + sfFileVector() + sfFillinCount() + sfGetAdmittance() + sfGetElement() + sfGetOnes() + sfGetQuad() + sfGetSize() + sfLargestElement() + sfMNA Preorder() + sfMultTransposed() + sfMultiply() + sfNorm() + sfOrderAndFactor() + sfPartition() + sfPrint() + sfPseudoCondition() + sfRoundoff() + sfScale() + sfSetComplex() + sfSetReal() + sfSolve() + sfSolveTransposed() + sfStripFills() + sfWhereSingular() + + + + + + + June 23, 1988 + + + + + + - 71 - + + + +spMatrix.h + +This file contains definitions that are useful to the calling program. In +particular, this file contains error keyword definitions, some macro func- +tions that are used to quickly enter data into the matrix, the definition +of a data structure that acts as a template for entering admittances into +the matrix, and the type declarations of the various Sparse functions. + + +spOutput.c + +This file contains the output-to-file and output-to-screen routines for the +matrix package. They are capable of outputting the matrix in either a form +readable by people or a form readable by the Sparse test program. + +o User accessible functions contained in this module: + spFileMatrix() + spFileStats() + spFileVector() + spPrint() + + +spRevision + +The history of updates for the program. This file also includes ordering +information for the Sparse package. + + +spSolve.c + +This module contains the forward and backward substitution routines. + +o User accessible functions contained in this module: + spSolve() + spSolveTransposed() + + +spTest.c + +This module contains a test program for the sparse matrix routines. It is +able to read matrices from files and solve them. Because of the large +number of options and capabilities built into Sparse, it is impossible to +have one test routine thoroughly exercise Sparse. Thus, emphasis is on ex- +ercising as many capabilities as is reasonable while also providing a use- +ful tool. + + + + + + + + + + + + June 23, 1988 + + + + + + - 72 - + + + +spUtil.c + +This module contains various optional utility routines. + +o User accessible functions contained in this module: + spCondition() + spDeleteRowAndCol() + spDeterminant() + spLargestElement() + spMNA Preorder() + spMultiply() + spMultTransposed() + spNorm() + spPseudoCondition() + spRoundoff() + spScale() + spStripFills() + + +Makefile + +This file is used in conjunction with the UNIX program make to compile the +matrix routines and their test program. + + +make.com + +This file is used to automatically compile Sparse under the VMS operating +system. It needs to modified slightly before being used, see the installa- +tion notes. + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + - 73 - + + +REFERENCES + +[duff86] I. S. Duff, A. M. Erisman, J. K. Reid. Direct Methods for + Sparse Matrices. Oxford University Press, 1986. + +[golub86] G. H. Golub, C. F. V. Van Loan. Matrix Computations. The + Johns Hopkins University Press, 1983. + +[kundert86] Kenneth S. Kundert. Sparse matrix techniques. In Circuit + Analysis, Simulation and Design, Albert Ruehli (editor). + North-Holland, 1986. + +[strang80] Gilbert Strang. Linear Algebra and Its Applications. + Academic Press, 1980. + + +Acknowledgements + + We would like to acknowledge and thank the those people that contri- +buted ideas that were incorporated into Sparse. In particular, Jacob +White, Kartikeya Mayaram, Don Webber, Tom Quarles, Howard Ko and Beresford +Parlett. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + + + + + + + + + + + Table of Contents + + + + +1: Introduction ..................................................... 1 + + 1.1: Features of Sparse1.3 .................................. 1 + + 1.2: Enhancements of Sparse1.3 over Sparse1.2 ............... 2 + + 1.3: Copyright Information .................................. 3 + +2: Primer ........................................................... 4 + + 2.1: Solving Matrix Equations ............................... 4 + + 2.2: Error Control .......................................... 5 + + 2.3: Building the Matrix .................................... 6 + + 2.4: Initializing the Matrix ................................ 7 + + 2.5: Indices ................................................ 8 + + 2.6: Configuring Sparse ..................................... 9 + +3: Introduction to the Sparse Routines .............................. 10 + + 3.1: Creating the Matrix .................................... 10 + + 3.2: Building the Matrix .................................... 10 + + 3.3: Clearing the Matrix .................................... 10 + + 3.4: Placing Data in the Matrix ............................. 11 + + 3.5: Influencing the Factorization .......................... 11 + + 3.6: Factoring the Matrix ................................... 11 + + 3.7: Solving the Matrix Equation ............................ 12 + + 3.8: Numerical Error Estimation ............................. 12 + + 3.9: Matrix Operations ...................................... 13 + + 3.10: Matrix Statistics and Documentation ................... 13 + +4: Routines ......................................................... 15 + + + + + June 23, 1988 + + + + + + + + + 4.1: spClear() .............................................. 15 + + 4.2: spCondition() .......................................... 16 + + 4.3: spCreate() ............................................. 17 + + 4.4: spDeleteRowAndCol() .................................... 18 + + 4.5: spDestroy() ............................................ 18 + + 4.6: spDeterminant() ........................................ 19 + + 4.7: spElementCount() ....................................... 20 + + 4.8: spError() .............................................. 20 + + 4.9: spFactor() ............................................. 21 + + 4.10: spFileMatrix() ........................................ 22 + + 4.11: spFileStats() ......................................... 23 + + 4.12: spFileVector() ........................................ 24 + + 4.13: spFillinCount() ....................................... 25 + + 4.14: spGetAdmittance() ..................................... 26 + + 4.15: spGetElement() ........................................ 27 + + 4.16: spGetInitInfo() ....................................... 28 + + 4.17: spGetOnes() ........................................... 30 + + 4.18: spGetQuad() ........................................... 32 + + 4.19: spGetSize() ........................................... 32 + + 4.20: spInitialize() ........................................ 34 + + 4.21: spInstallInitInfo() ................................... 34 + + 4.22: spLargestElement() .................................... 35 + + 4.23: spMNA Preorder() ...................................... 36 + + 4.24: spMultiply() .......................................... 37 + + 4.25: spMultTransposed() .................................... 38 + + 4.26: spNorm() .............................................. 39 + + 4.27: spOrderAndFactor() .................................... 39 + + + + + June 23, 1988 + + + + + + + + + 4.28: spPartition() ......................................... 42 + + 4.29: spPrint() ............................................. 42 + + 4.30: spPseudoCondition() ................................... 43 + + 4.31: spRoundoff() .......................................... 44 + + 4.32: spScale() ............................................. 45 + + 4.33: spSetComplex() ........................................ 46 + + 4.34: spSetReal() ........................................... 46 + + 4.35: spSolve() ............................................. 47 + + 4.36: spSolveTransposed() ................................... 48 + + 4.37: spStripFills() ........................................ 49 + + 4.38: spWhereSingular() ..................................... 49 + +5: Macro Functions .................................................. 50 + + 5.1: spADD REAL ELEMENT() ................................... 50 + + 5.2: spADD IMAG ELEMENT() ................................... 50 + + 5.3: spADD COMPLEX ELEMENT() ................................ 51 + + 5.4: spADD REAL QUAD() ...................................... 51 + + 5.5: spADD IMAG QUAD() ...................................... 52 + + 5.6: spADD COMPLEX QUAD() ................................... 52 + +6: Configuring Sparse ............................................... 53 + + 6.1: Sparse Options ......................................... 53 + + 6.2: Sparse Constants ....................................... 58 + + 6.3: Machine Constants ...................................... 60 + +7: Exports .......................................................... 61 + + 7.1: Error Codes ............................................ 61 + + 7.2: Data Structures ........................................ 62 + +8: FORTRAN Compatibility ............................................ 63 + +9: Sparse Test Program .............................................. 65 + + + + + June 23, 1988 + + + + + + + + +10: Sparse Files .................................................... 67 + +References ........................................................... 73 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + June 23, 1988 + + diff --git a/sis/linsolv/doc/spDoc.ms b/sis/linsolv/doc/spDoc.ms new file mode 100644 index 0000000..cf0a448 --- /dev/null +++ b/sis/linsolv/doc/spDoc.ms @@ -0,0 +1,4063 @@ +.LP +.pn 1 +.if t .nr PS 11 +.if t .nr VS 13 +.if t .po 1.5i +.if t .nr PO 1.5i +.if n .ll 7.5i +.if n .nr LL 7.5i +.rs +.ls 1 +.\ +.\ +.\ >>> Revision information: +.\ $Author: pchong $ +.\ $Date: 2004/02/07 10:15:05 $ +.\ $Revision: 1.1.1.1 $ +.\ +.\ +.\ Define registers for section and subsection +.nr sc 0 1 +.nr ss 0 1 +.\ +.\ +.\ Define macro for separating procedure descriptions +.de Lb +.KS +.nf +.ta 6i +.tc \(ru + +.tc +.LP +.sp 0.3v +.ta 6iR +\s+2\fB\\n(sc.\\n+(ss:\ \ \\$1(\|)\fR\s-2 \" \s+4\fI\\$1()\fR\s-4 +.ta 0.5i +.LP +.. +.de Le +.LP +.ta 6i +.tc \(ru + +.tc +.KE +.sp 0.3v +.. +.EQ +delim $$ +gsize 11 +tdefine norm % \^ \(br fwd 10 \(br % +ndefine norm % || % +ndefine delta % d % +ndefine epsilon % e % +ndefine kappa % K % +.EN +.hw SEP-AR-ATED_-COM-PLEX_-VEC-TORS +.\ +.\ +.\ Begin the document + +.ps 24 +.sp 1.75i +.ce +.B "Sparse User's Guide" +.ps +.sp .2i +.LG +.LG +.LG +.I +.ce 1 +A Sparse Linear Equation Solver +.NL +.NL +.R +.sp 0.25i +.ce +Version 1.3a +.sp .05i +.ce 1 +1 April 1988 +.NL +.sp 0.75i +.R +.LG +.R +.ce 2 +.I "Kenneth S. Kundert" +.I "Alberto Sangiovanni-Vincentelli" +.sp 1.0i +.ce 4 +Department of +.sp 0.25v +Electrical Engineering and Computer Sciences +.sp 0.25v +University of California, Berkeley +.sp 0.25v +Berkeley, Calif. 94720 +.NL +.bp +.RT +.ne 1i +.LG +.B "\n+(sc: INTRODUCTION" +.NL +.XS \n% \" Save section title for table of contents +\n(sc: Introduction +.XE +.PP +\fISparse1.3\fP is a flexible package of subroutines written in C used +to quickly and accurately solve large sparse systems of linear +equations. The package is able to handle arbitrary real and complex +square matrix equations. Besides being able to solve linear systems, +it is also able to quickly solve transposed systems, find determinants, +and estimate errors due to ill-conditioning in the system of equations +and instability in the computations. \fISparse\fR also provides a test +program that is able read matrix equations from a file, solve them, and +print useful information about the equation and its solution. +.PP +\fISparse1.3\fR is generally as fast or faster than other popular +sparse matrix packages when solving many matrices of similar +structure. \fISparse\fR does not require or assume symmetry and is +able to perform numerical pivoting to avoid unnecessary error in the +solution. It handles its own memory allocation, which allows the user +to forgo the hassle of providing adequate memory. It also has a +natural, flexible, and efficient interface to the calling program. +.PP +\fISparse\fR was originally written for use in circuit simulators and +is particularly apt at handling node- and modified-node admittance +matrices. The systems of linear generated in a circuit simulator stem +from solving large systems of nonlinear equations using Newton's method +and integrating large stiff systems of ordinary differential +equations. However, \fISparse\fR is also suitable for other uses, one +in particular is solving the very large systems of linear equations +resulting from the numerical solution of partial differential +equations. +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Features of Sparse1.3" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Features of Sparse1.3 +.XE +.PP +Beyond the basic capability of being able to create, factor and +solve systems of equations, this package features several other capabilities +that enhance its utility. These features are: +.IP \(bu +Ability to handle both real and complex systems of equations. Both types +may resident and active at the same time. In fact, the same matrix +may alternate between being real and complex. +.IP \(bu +Ability to quickly solve the transposed system. This feature is useful +when computing the sensitivity of a circuit using the adjoint method. +.IP \(bu +Memory for elements in the matrix is allocated dynamically, so the +size of the matrix is only limited by the amount of memory available +to \fISparse\fP and the range of the integer data type, which is used to +hold matrix indices. +.IP \(bu +Ability to efficiently compute the condition number of the matrix and +an a posteriori estimate of the error caused by growth in the size of +the elements during the factorization. +.IP \(bu +Much of the matrix initialization can be performed by \fISparse\fP, +providing advantages in speed and simplified coding of the calling +program. +.IP \(bu +Ability to preorder modified node admittance matrices to enhance +accuracy and speed. +.IP \(bu +Ability to exploit sparsity in the right-hand side vector to +reduce unnecessary computation. +.IP \(bu +Ability to scale matrices prior to factoring to reduce uncertainty +in the solution. +.IP \(bu +The ability to create and build a matrix without knowing its final size. +.IP \(bu +The ability to add elements, and rows and columns, +to a matrix after the matrix has been reordered. +.IP \(bu +The ability to delete rows and columns from a matrix. +.IP \(bu +The ability to strip the fill-ins from a matrix. This can improve the +efficiency of a subsequent reordering. +.IP \(bu +The ability to handle matrices that have rows and columns missing from +their input description. +.IP \(bu +Ability to output the matrix in forms readable by either by people or +by the \fISparse\fP package. Basic statistics on the matrix can also be +output. +.IP \(bu +By default all arithmetic operations and number storage use double precision. +Thus, \fISparse\fP usually gives accurate results, even on highly +ill-conditioned systems. If so desired, \fISparse\fP can be easily +configured to use single precision arithmetic. +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Enhancements of Sparse1.3 over Sparse1.2" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Enhancements of Sparse1.3 over Sparse1.2 +.XE +.PP +Most notable of the enhancements provided by \fISparse1.3\fR is that +it is considerably faster on dense matrices. Also, external names +have been made unique to 7 characters and the \fISparse\fR prefix +\fBsp\fR has been prepended to all externally accessible names to +avoid conflicts. In addition, a routine that efficiently estimates +the condition number of a matrix has been added and the code that +estimates the growth in the factorization has been split off from the +actual factorization so that it is computed only when needed. +.PP +It is now possible for the user program to store information in the +matrix elements. It is also possible to provide a subroutine to +\fISparse\fP that uses that information to initialize the matrix. This +can greatly simplify the user's code. +.PP +Though the interface between \fISparse1.3\fR and the calling program +has changed considerable from previous versions of \fISparse\fR, it is +possible to compile additional code that provides backward compatibility +to \fISparse1.2\fR at the expense of a slight loss of efficiency by +setting a compiler option. \fISparse1.3\fR now also has an FORTRAN +interface. Routines written in FORTRAN can access almost all of the +features \fISparse1.3\fR. +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Copyright Information" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Copyright Information +.XE +.PP +\fISparse1.3\fP has been copyrighted. Permission to use, copy, modify, +and distribute this software and its documentation without fee is hereby +granted, provided that the copyright notice appear in all copies and +that the authors, \fISparse\fP, and the University of California at +Berkeley are referenced in all documentation for the program or product +in which \fISparse\fP is to be installed. The authors and the +University of California make no representations as to the suitability +of the software for any purpose. It is provided `as is', without +express or implied warranty. +.bp +.nr ss 0 1 \" Reset subsection +.RT +.ne 1.5i +.LG +.B "\n+(sc: PRIMER" +.NL +.XS \n% \" Save section title for table of contents +\n(sc: Primer +.XE +.sp +.RT +.LG +.B "\n(sc.\n+(ss: Solving Matrix Equations" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Solving Matrix Equations +.XE +.PP +\fISparse\fP contains a collection of C subprograms that can be used to solve +linear algebraic systems of equations. These systems are of the form: +.EQ I +bold { Ax ~=~ b } +.EN +where $bold A$ is an $n times n$ matrix, $bold x$ is the vector of $n$ +unknowns and $bold b$ is the vector of $n$ right-hand side terms. +Through out this package $bold A$ is denoted \fIMatrix\fP, $bold x$ is +denoted \fISolution\fP and $bold b$ is denoted \fIRHS\fP (for +right-hand side). The system is solved using LU factorization, so the +actual solution process is broken into two steps, the factorization or +decomposition of the matrix, performed by \fIspFactor()\fP, and the +forward and backward substitution, performed by \fIspSolve()\fP. +\fIspFactor()\fP factors the given matrix into upper and lower +triangular matrices independent of the right-hand side. Once this is +done, the solution vector can be determined efficiently for any number +of right-hand sides without refactoring the matrix. +.PP +This package exploits the fact that large matrices usually are sparse +by not storing or operating on elements in the matrix that are zero. +Storing zero elements is avoided by organizing the matrix into an +orthogonal linked-list. Thus, to access an element if only its indices +are known requires stepping through the list, which is slow. This +function is performed by the routine \fIspGetElement()\fP. It is used to +initially enter data into a matrix and to build the linked-list. +Because it is common to repeatedly solve matrices with identical +zero/nonzero structure, it is possible to reuse the linked-list. Thus, +the linked list is left in memory and the element values are simply +cleared by \fIspClear()\fP before the linked-list is reused. To speed the +entering of the element values into successive matrices, +\fIspGetElement()\fP returns a pointer to the element in the matrix. +This pointer can then be used to place data directly into the matrix +without having to traverse through the linked-list. +.PP +The order in which the rows and columns of the matrix are factored is +very important. It directly affects the amount of time required for +the factorization and the forward and backward substitution. It also +affects the accuracy of the result. The process of choosing this order +is time consuming, but fortunately it usually only has to be done once +for each particular matrix structure encountered. When a matrix with a +new zero/nonzero structure is to be factored, it is done by using +\fIspOrderAndFactor()\fP. Subsequent matrices of the same structure are +factored with \fIspFactor()\fP. The latter routine does not have the +ability to reorder matrix, but it is considerably faster. It may be +that a order chosen may be unsuitable for subsequent factorizations. +If this is known to be true a priori, it is possible to use +\fIspOrderAndFactor()\fP for the subsequent factorizations, with a +noticeable speed penalty. \fIspOrderAndFactor()\fP monitors the numerical +stability of the factorization and will modify an existing ordering to +maintain stability. Otherwise, an a posteriori measure of the numerical +stability of the factorization can be computed, and the matrix +reordered if necessary. +.PP +The \fISparse\fP routines allow several matrices of different +structures to be resident at once. When a matrix of a new structure is +encountered, the user calls \fIspCreate()\fP. This routine creates the +basic frame for the linked-list and returns a pointer to this frame. +This pointer is then passed as an argument to the other \fISparse\fP +routines to indicate which matrix is to be operated on. The number of +matrices that can be kept in memory at once is only limited by the +amount of memory available to the user and the size of the matrices. +When a matrix frame is no longer needed, the memory can be reclaimed by +calling \fIspDestroy()\fP. +.PP +A more complete discussion of sparse systems of equations, methods +for solving them, their error mechanisms, and the algorithms used in +\fISparse\fP can be found in Kundert [kundert86]. A particular emphasis +is placed on matrices resulting from circuit simulators. +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Error Control" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Error Control +.XE +.PP +There are two separate mechanisms that can cause errors during the +factoring and solution of a system of equations. The first is +ill-conditioning in the system. A system of equations is +ill-conditioned if the solution is excessively sensitive to +disturbances in the input data, which occurs when the system is nearly +singular. If a system is ill-conditioned then uncertainty in the +result is unavoidable, even if $bold A$ is accurately factored into +$bold L$ and $bold U$. When ill-conditioning is a problem, the problem +as stated is probably ill-posed and the system should be reformulated +such that it is not so ill-conditioned. It is possible to measure the +ill-conditioning of matrix using \fIspCondition()\fP. This function +returns an estimate of the reciprocal of the condition number of the +matrix ($kappa ( bold A )$) [strang80]. The condition number can be +used when computing a bound on the error in the solution using the +following inequality [golub83]. +.EQ +{norm delta bold x norm} over {norm bold x norm} ~<=~ kappa ( bold A) +left ( {norm delta bold A norm} over {norm bold A norm} ~+~ +{norm delta bold b norm} over {norm bold b norm} right ) ~+~ "higher order terms" +.EN +where $delta bold A$ and $delta bold b$ are the uncertainties in the +matrix and right-hand side vector and are assumed small. +.PP +The second mechanism that causes uncertainty is the build up of +roundoff error. Roundoff error can become excessive if there is +sufficient growth in the size of the elements during the +factorization. Growth is controlled by careful pivoting. In +\fISparse\fP, the pivoting is controlled by the +relative threshold parameter. In conventional full matrix techniques the +pivot is chosen to be the largest element in a column. When working +with sparse matrices it is important to choose pivots to minimize the +reduction in sparsity. The best pivot to retain sparsity is often not the +best pivot to retain accuracy. Thus, some compromise must be made. In +threshold pivoting, as used in this package, the best pivot to retain +sparsity is used unless it is smaller than the relative threshold +times the largest element in the column. Thus, a relative threshold close +to one emphasizes accuracy so it will produce a minimum +amount of growth, unfortunately it also slows the factorization. A +very small relative threshold emphasizes maintenance of sparsity and so +speeds the factorization, but can result in a +large amount of growth. In our experience, we have found that a relative +threshold of 0.001 seems to result in a satisfactory compromise between +speed and accuracy, though other authors suggest a more conservative +value of 0.1 [duff86]. +.PP +The growth that occurred during a factorization can be computed by +taking the ratio of the largest matrix element in any stage of the +factorization to the largest matrix element before factorization. The +two numbers are estimated using \fIspLargestElement()\fP. If the growth +is found to be excessive after \fIspOrderAndFactor()\fP, then the +relative threshold should be increased and the matrix reconstructed and +refactored. Once the matrix has been ordered and factored without +suffering too much growth, the amount of growth that occurred should be +recorded. If, on subsequent factorizations, as performed by +\fIspFactor()\fP, the amount of growth becomes significantly larger, then +the matrix should be reconstructed and reordered using the same +relative threshold with \fIspOrderAndFactor()\fP. If the growth is still +excessive, then the relative threshold should be raised again. +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Building the Matrix" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Building the Matrix +.XE +.PP +It is not necessary to specify the size of the matrix before beginning +to add elements to it. When the compiler option EXPANDABLE is turned +on it is possible to initially specify the size of the matrix to any +size equal to or smaller than the final size of the matrix. +Specifically, the matrix size may be initially specified as zero. If +this is done then, as the elements are entered into the matrix, the +matrix is enlarged as needed. This feature is particularly useful in +circuit simulators because it allows the building of the matrix as the +circuit description is parsed. Note that once the matrix has been +reordered by the routines \fIspMNA_Preorder()\fP, \fIspFactor()\fP or +\fIspOrderAndFactor()\fP the size of the matrix becomes fixed and may no +longer be enlarged unless the compiler option TRANSLATE is enabled. +.PP +The TRANSLATE option allows \fISparse\fP to translate a non-packed set +of row and column numbers to an internal packed set. In other words, +there may be rows and columns missing from the external description of +the matrix. This feature provides two benefits. First, if two +matrices are identical in structure, except for a few missing rows and +columns in one, then the TRANSLATE option allows them to be treated +identically. Similarly, rows and columns may be deleted from a matrix +after it has been built and operated upon. Deletion of rows and +columns is performed by the function \fIspDeleteRowAndCol()\fP. Second, +it allows the use of the functions \fIspGetElement()\fP, +\fIspGetAdmittance()\fP, \fIspGetQuad()\fP, and \fIspGetOnes()\fP after the +matrix has been reordered. These functions access the matrix by using +row and column indices, which have to be translated to internal indices +once the matrix is reordered. Thus, when TRANSLATE is used in +conjunction with the EXPANDABLE option, rows and columns may be added +to a matrix after it has been reordered. +.PP +Another provided feature that is useful with circuit simulators is the +ability to add elements to the matrix in row zero or column zero. +These elements will have no affect on the matrix or the results. The +benefit of this is that when working with a nodal formulation, grounded +components do not have to be treated special when building the matrix. +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Initializing the Matrix" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Initializing the Matrix +.XE +.PP +Once a matrix has been factored, it is necessary to clear the matrix +before it can be reloaded with new values. The straight forward way of +doing that is to call \fIspClear()\fP, which sets the value of every +element in the matrix to zero. \fISparse\fP also provides a more +flexible way to clear the matrix. Using \fIspInitialize()\fP, it is +possible to clear and reload at least part of the matrix in one step. +.PP +\fISparse\fR allows the user to keep initialization information with +each structurally nonzero matrix element. Each element has a pointer +that is set and used by the user. The user can set this pointer using +\fIspInstallInitInfo()\fR and may read it using \fIspGetInitInfo()\fR. +The function \fIspInitialize()\fR is a user customizable way to +initialize the matrix. Passed to this routine is a function pointer. +\fIspInitialize()\fR sweeps through every element in the matrix and +checks the \fIpInitInfo\fR pointer (the user supplied pointer). If the +\fIpInitInfo\fR is NULL, which is true unless the user changes it +(always true for fill-ins), then the element is zeroed. Otherwise, the +function pointer is called and passed the \fIpInitInfo\fR pointer as +well as the element pointer and the external row and column numbers, +allowing the user to initialize the matrix element and the right-hand +side. +.PP +Why \fIspInitialize()\fR would be used over \fIspClear()\fR can be +illustrated by way of an example. Consider a circuit simulator that +handles linear and nonlinear resistors and capacitors performing a +transient analysis. For the linear resistors, a constant value is +loaded into the matrix at each time step and for each Newton +iteration. For the linear capacitor, a value is loaded into the matrix +that is constant over Newton iterations, but is a function of the time +step and the integration method. The nonlinear components contribute +values to the matrix that change on every time step and Newton +iteration. +.PP +\fISparse\fP allows the user to attach a data structure to each element +in the matrix. For this example, the user might attach a structure +that held several pieces of information, such as the conductance of the +linear resistor, the capacitance of the linear capacitor, the +capacitance of the nonlinear capacitor, and perhaps past values of +capacitances. The user also provides a subroutine to +\fIspInitialize()\fP that is called for each user-created element in the +matrix. This routine would, using the information in the attached data +structure, initialize the matrix element and perhaps the right-hand +side vector. +.PP +In this example, the user supplied routine might load the linear +conductance into the matrix and multiply it by some voltage to find a +current that could be loaded into the right-hand side vector. For the +capacitors, the routine would first apply an integration method and +then load the matrix and the right-hand side. +.PP +This approach is useful for two reasons. First, much of the work of +the device code in the simulator can be off-loaded onto the matrix +package. Since there are usually many devices, this usually results +overall in a simpler system. Second, the integration method can be +hidden from the simulator device code. Thus the integration method can +be changed simply by changing the routine handed to \fIspInitialize()\fP, +resulting in a much cleaner and more easily maintained simulator. +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Indices" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Indices +.XE +.PP +By far the most common errors made when using \fISparse\fR are related +to array indices. \fISparse\fR itself contributes to the problem by +having several different indexing schemes. There are three different +options that affect index bounds or the way indices are interpreted. +The first is ARRAY_OFFSET, which only affects array indices. +ARRAY_OFFSET is a compiler flag that selects whether arrays start at +index zero or index one. Note that if ARRAY_OFFSET is zero then +\fIRHS\fP[0] corresponds to row one in the matrix and \fISolution\fP[0] +corresponds to column one. Further note that when ARRAY_OFFSET is set +to one, then the allocated length of the arrays handed to the +\fISparse\fR routines should be at least the external size of the matrix +plus one. The main utility of ARRAY_OFFSET is that it allows natural +array indexing when \fISparse\fR is coupled to programs in other +languages. For example; in FORTRAN arrays always start at one whereas +in C array always start at zero. Thus the first entry in a FORTRAN +array corresponds to the zero'th entry in a C array. Setting +ARRAY_OFFSET to zero allows the arrays in FORTRAN to start at one rather +than two. For the rest of this discussion, assume that ARRAY_OFFSET is +set so that arrays start at one in the program that calls \fISparse\fR. +.sp 0.3v +.PP +The second option that affects indices is EXPANDABLE. When EXPANDABLE +is set false the upper bound on array and matrix indices is \fISize\fP, +where \fISize\fP is a parameter handed to \fIspCreate()\fP. When +EXPANDABLE set true, then there is essentially no upper bound on array +indices. Indeed, the size of the matrix is determined by the largest +row or column number handed to \fISparse\fR. The upper bound on the +array indices then equals the final size determined by \fISparse\fR. +This size can be determined by calling \fIspGetSize()\fP. +.sp 0.3v +.PP +The final option that affects indices is TRANSLATE. This option was +provided to allow row and columns to be deleted, but it also allows row +and column numbers to be missing from the input description for a +matrix. This means that the size of the matrix is not determined by +the largest row or column number entered into the matrix. Rather, the +size is determined by the total number of rows or column entered. For +example, if the elements [2,3], [5,3], and [7,2] are entered into the +matrix, the internal size of the matrix becomes four while the external +size is seven. The internal size equals the number of rows and columns +in the matrix while the external size equals the largest row or column +number entered into the matrix. Note that if a row is entered into the +matrix, then its corresponding column is also entered, and vice versa. +The indices used in the \fIRHS\fP and \fISolution\fP vectors +correspond to the row and column indices in the matrix. Thus, for this +example, valid data is expected in \fIRHS\fP at locations 2, 3, 5 +and 7. Data at other locations is ignored. Similarly, valid data is +returned in \fISolution\fP at locations 2, 3, 5, and 7. The other +locations are left unmolested. This shows that the length of the +arrays correspond to the external size of the matrix. Again, this +value can be determined by \fIspGetSize()\fP. +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Configuring Sparse" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Configuring Sparse +.XE +.PP +It is possible at compile-time to customize \fISparse\fR for your +particular application. This is done by changing the compiler options, +which are kept in the personality file, \fBspConfig.h\fP. There are +three classes of choices available. First are the \fISparse\fP options, +which specify the dominant personality characteristics, such as if real +and/or complex systems of equations are to be handled. The second +class is the \fISparse\fP constants, such as the default pivot threshold and +the amount of memory initially allocated per matrix. The last class is +the machine constants. These numbers must be updated when \fISparse\fP +is ported to another machine. +.PP +As an aid in the setup and testing of \fISparse\fP a test routine and +several test matrices and their solutions have been provided. The test +routine is capable of reading files generated by \fIspFileMatrix()\fP +and \fIspFileVector()\fP. +.PP +By default \fISparse\fP stores all real numbers and performs all +computations using double precision arithmetic. This can be changed by +changing the definition of \fIspREAL\fP from \fBdouble\fP to +\fBfloat\fP. \fIspREAL\fP is defined in \fBspExports.h\fP. +.bp +.nr ss 0 1 \" Reset subsection +.RT +.ne 1.5i +.LG +.B "\n+(sc: INTRODUCTION TO THE SPARSE ROUTINES" +.NL +.XS \n% \" Save section title for table of contents +\n(sc: Introduction to the Sparse Routines +.XE +.sp +In this section the routines are grouped by function and briefly described. + +.KS +.RT +.LG +.B "\n(sc.\n+(ss: Creating the Matrix" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Creating the Matrix +.XE +.LP +.I spCreate() +.RS +.br +Allocates and initializes the data structure for a matrix. Necessarily the +first routine run for any particular matrix. +.RE +.KE +.KS +.LP +.I spDestroy() +.RS +.br +Destroys the data structure for a matrix and frees the memory. +.RE +.KE +.KS +.LP +.I spSetReal() +.br +.I spSetComplex() +.RS +.br +These routines toggle a flag internal to \fISparse\fP that indicates +that the matrix is either real or complex. This is useful if both real +and complex matrices of identical structure are expected. +.RE +.KE +.sp 2 +.KS +.RT +.LG +.B "\n(sc.\n+(ss: Building the Matrix" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Building the Matrix +.XE +.LP +.I spGetElement() +.RS +.br +Assures that the specified element exists in the matrix data structure +and returns a pointer to it. +.RE +.KE +.KS +.LP +.I spGetAdmittance() +.br +.I spGetQuad() +.br +.I spGetOnes() +.RS +.br +These routines add a group of four related elements to the matrix. +\fIspGetAdmittance()\fP adds the four elements associated with a two +terminal admittance. \fIspGetQuad()\fP is a more general routine that is +useful for entering controlled sources to the matrix. \fIspGetOnes()\fP +adds the four structural ones to the matrix that are often encountered +with elements that do not have admittance representations. +.RE +.KE +.KS +.LP +.I spDeleteRowAndCol() +.RS +.br +This function is used to delete a row and column from the matrix. +.RE +.KE +.sp 2 +.KS +.RT +.LG +.B "\n(sc.\n+(ss: Clearing the Matrix" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Clearing the Matrix +.XE +.LP +.I spClear() +.RS +.br +Sets every element in the matrix to zero. +.RE +.KE +.KS +.LP +.I spInitialize() +.RS +.br +Runs a user provided initialization routine on each element in the matrix. +This routine would be used in lieu of \fIspClear()\fR. +.RE +.KE +.KS +.LP +.I spGetInitInfo() +.br +.I spInstallInitInfo() +.RS +.br +These routines allow the user to install and read a user-provided pointer +to initialization data for a particular matrix element. +.RE +.KE +.KS +.LP +.I spStripFills() +.RS +.br +This routine returns a matrix to a semi-virgin state by removing all +fill-ins. This can be useful if a matrix is to be reordered and it has +changed significantly since it was previously ordered. This may be the +case if a few rows and columns have been added or deleted or if the +previous ordering was done on a matrix that was numerically quite +different than the matrix currently being factored. Stripping and +reordering a matrix may speed subsequent factorization if the current +ordering is inferior, whereas simply reordering will generally only +enhance accuracy and not speed. +.RE +.KE +.sp 2 +.KS +.RT +.LG +.B "\n(sc.\n+(ss: Placing Data in the Matrix" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Placing Data in the Matrix +.XE +.LP +.I spADD_REAL_ELEMENT() +.br +.I spADD_IMAG_ELEMENT() +.br +.I spADD_COMPLEX_ELEMENT() +.RS +.br +Adds a value to a particular matrix element. +.RE +.KE +.KS +.LP +.I spADD_REAL_QUAD() +.br +.I spADD_IMAG_QUAD() +.br +.I spADD_COMPLEX_QUAD() +.RS +.br +Adds a value to a group of four matrix elements. +.RE +.KE +.sp 2 +.KS +.RT +.LG +.B "\n(sc.\n+(ss: Influencing the Factorization" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Influencing the Factorization +.XE +.LP +.I spMNA_Preorder() +.RS +.br +This routine preorders modified node admittance matrices so that +\fISparse\fP can take full advantage of their structure. In +particular, this routine tries to remove zeros from the diagonal so +that diagonal pivoting can be used more successfully. +.RE +.KE +.KS +.LP +.I spPartition() +.RS +.br +\fISparse\fR partitions the matrix in an attempt to make \fIspFactor()\fP +run as fast as possible. The partitioning is a relatively expensive +operation that is not needed in all cases. \fIspPartition()\fR allows +the user specify a simpler and faster partitioning. +.RE +.KE +.KS +.LP +.I spScale() +.br +.RS +It is sometimes desirable to scale the rows and columns of a matrix in +to achieve a better pivoting order. This is particularly true in +modified node admittance matrices, where the size of the elements in a +matrix can easily vary through ten to twelve orders of magnitude. This +routine performs scaling on a matrix. +.RE +.KE +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Factoring the Matrix" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Factoring the Matrix +.XE +.KS +.LP +.I spOrderAndFactor() +.RS +.br +This routine chooses a pivot order for the matrix and factors it into +LU form. It handles both the initial factorization and subsequent +factorizations when a reordering is desired. +.RE +.KE +.KS +.LP +.I spFactor() +.RS +.br +Factors a matrix that has already been ordered by \fIspOrderAndFactor()\fR. +If \fIspFactor()\fR is passed a matrix that needs ordering, it will +automatically pass the matrix to \fIspOrderAndFactor()\fR. +.RE +.KE +.sp 2 +.KS +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Solving the Matrix Equation" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Solving the Matrix Equation +.XE +.LP +.I spSolve() +.br +.RS +Solves the matrix equation +.EQ I +bold "A" bold x ~=~ bold b +.EN +given the matrix $bold A$ factored into LU form and $bold b$. +.RE +.KE +.KS +.LP +.I spSolveTransposed() +.br +.RS +When working with adjoint systems, such as in sensitivity analysis, it +is desirable to quickly solve +.EQ I +bold "A" sup roman T bold x ~=~ bold b +.EN +Once $bold A$ has been factored into LU form, this +routine can be used to solve the transposed system without having to +suffer the cost of factoring the matrix again. +.RE +.KE +.sp 2 +.KS +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Numerical Error Estimation" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Numerical Error Estimation +.XE +.LP +.I spCondition() +.RS +.br +Estimates the L-infinity condition number of the matrix. This number is +a measure of the ill-conditioning in the matrix equation. It is also useful +for making estimates of the error in the solution. +.RE +.KE +.KS +.LP +.I spNorm() +.RS +.br +Returns the L-infinity norm (the maximum absolute row sum) of an unfactored +matrix. +.RE +.KE +.KS +.LP +.I spPseudoCondition() +.RS +.br +Returns the ratio of the largest pivot to the smallest pivot of a factored +matrix. This is a rough indicator of ill-conditioning in the matrix. +.RE +.KE +.KS +.LP +.I spLargestElement() +.RS +.br +If passed an unfactored matrix, this routine returns the absolute value of +the largest element in the matrix. If passed a factored matrix, it returns +an estimate of the largest element that occurred in any of the reduced +submatrices during the factorization. The ratio of these two numbers +(factored/unfactored) is the growth, which is used to determine if the +pivoting order is numerically satisfactory. +.RE +.KE +.KS +.LP +.I spRoundoff() +.RS +.br +Returns a bound on the magnitude of the largest element in +$bold E ~=~ bold A - bold LU$, where $bold E$ represents error in +the matrix resulting from roundoff error during the factorization. +.RE +.KE +.sp 2 +.KS +.RT +.LG +.B "\n(sc.\n+(ss: Matrix Operations" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Matrix Operations +.XE +.LP +.I spDeterminant() +.RS +.br +This routine simply calculates and returns the determinant of the +factored matrix. +.RE +.KE +.KS +.LP +.I spMultiply() +.br +.RS +This routine multiplys the matrix by a vector on the +right. This is useful for forming the product $ bold "Ax" ~=~ bold b $ +in order to determine if a calculated solution is correct. +.RE +.KE +.KS +.LP +.I spMultTransposed() +.br +.RS +Multiplys the transposed matrix by a vector on the right. This is useful +for forming the product $ bold "A sup {roman T} x" ~=~ bold b $ +in order to determine if a calculated solution is correct. +.RE +.KE +.KS +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Matrix Statistics and Documentation" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Matrix Statistics and Documentation +.XE +.LP +.I spError() +.RS +.br +Determines the error status of a particular matrix. While most of the +\fISparse\fR routines do return an indication that an error has +occurred, some do not and so \fIspError()\fP provides the only way of +uncovering these errors. +.RE +.KE +.KS +.LP +.I spWhereSingular() +.RS +.br +Returns the row and column number where the matrix was detected as +singular or where a zero pivot was found. +.RE +.KE +.KS +.LP +.I spGetSize() +.RS +.br +A function that returns the size of the matrix. Either the internal or +external size of the matrix is returned. The internal size of the +matrix is the actual size of the matrix whereas the external size is +the value of the largest row or column number. These two numbers may +differ if the TRANSLATE option is used. +.RE +.KE +.KS +.LP +.I spElementCount() +.br +.I spFillinCount() +.RS +.br +Functions that return the total number of elements in the matrix, and the +number of fill-ins in the matrix. These functions are useful for gathering +statistics on matrices. +.RE +.KE +.KS +.LP +.I spPrint() +.RS +.br +This routine outputs the matrix as well as some statistics to standard +output in a format that is readable by people. The matrix can be +printed in either a compressed or standard format. In the standard +format, a numeric value is given for each structurally nonzero element, +whereas in the compressed format, only the existence or nonexistence of +an element is indicated. This routine is not suitable for use on large +matrices. +.RE +.KE +.KS +.LP +.I spFileMatrix() +.br +.I spFileVector() +.RS +.br +These two routines send a copy of the matrix and its right-hand side +vector to a file. This file can then be read by the test program that +is included with \fISparse\fP. Only those elements of the matrix that +are structurally nonzero are output, so very large matrices can be sent +to a file. +.RE +.KE +.KS +.LP +.I spFileStats() +.RS +.br +This routine calculates and sends some useful statistics concerning a +matrix to a file. +.RE +.KE +.bp +.nr ss 0 1 \" Reset subsection +.RT +.ne 1.5i +.LG +.B "\n+(sc: SPARSE ROUTINES" +.NL +.XS \n% \" Save section title for table of contents +\n(sc: Routines +.XE +.sp +This section contains a complete list of the \fISparse\fR routines that are +available to the user. Each routine is described as to its +function and how to use it. The routines are listed in alphabetic +order. +.sp 2 +.Lb spClear +Sets every element in the matrix to zero. The \fISparse\fR error state +is cleared to spOKAY in this routine. +.sp 0.3v +\fBvoid\fI spClear( Matrix )\fR +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix that is to be cleared. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspClear()\fP +.XE +.Lb spCondition +\fIspCondition()\fP computes an estimate of the condition number using a +variation on the LINPACK condition number estimation algorithm. This +quantity is an measure of ill-conditioning in the matrix. To avoid +problems with overflow, the reciprocal of the condition number is +returned. If this number is small, and if the matrix is scaled such +that uncertainties in the RHS and the matrix entries are equilibrated, +then the matrix is ill-conditioned. If the this number is near one, +the matrix is well conditioned. This routine must only be used after a +matrix has been factored by \fIspOrderAndFactor()\fR or \fIspFactor()\fR +and before it is cleared by \fIspClear()\fR or \fIspInitialize()\fR. +.LP +Unlike the LINPACK condition number estimator, this routines returns +the L infinity condition number. This is an artifact of Sparse placing +ones on the diagonal of the upper triangular matrix rather than the +lower. This difference should be of no importance. +.sp 0.3v +.nf +\fIspREAL spCondition( Matrix, NormOfMatrix, Error ) +.XP +\(bu Returns: +.br +An estimate of the L infinity condition number of the matrix. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +The matrix for which the condition number is desired. +.XP +\fINormOfMatrix\fP input (spREAL) +.br +The L-infinity norm of the unfactored matrix as computed by \fIspNorm()\fP. +.XP +\fIError\fP output (\fBint *\fP) +.br +Used to return the error code. +.RE +.XP +\(bu Possible errors: +.nf +spSINGULAR +spNO_MEMORY +Error is not cleared in this routine. +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +CONDITION +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspCondition()\fP +.XE +.Lb spCreate +Allocates and initializes the data structures associated with a matrix. This +routine is necessarily the first routine run for any particular matrix. +.sp 0.3v +.nf +\fBchar *\fIspCreate( Size, Complex, Error )\fR +.XP +\(bu Returned: +.br +A pointer to the matrix is returned cast into the form of a pointer to +a character. This pointer is then passed and used by the other matrix +routines to refer to a particular matrix. If an error occurs, the NULL +pointer is returned. +.XP +\(bu Arguments: +.RS +.XP +\fISize\fP input (\fBint\fP) +.br +Size of matrix. When the compiler option EXPANDABLE is turned on, +\fISize\fP is used as a lower bound on the size of the matrix. +\fISize\fP must not be negative. +.XP +\fIComplex\fP input (\fBint\fP) +.br +Type of matrix. If \fIComplex\fP is 0 then the matrix is real, +otherwise the matrix will be complex. Note that if the routines are +not set up to handle the type of matrix requested, then a spPANIC error +will occur. +.XP +\fIError\fP output (\fBint *\fP) +.br +Returns error flag, needed because function \fIspError()\fP will not +work correctly if \fIspCreate()\fP returns NULL. +.RE +.XP +\(bu Possible errors: +.nf +spNO_MEMORY +spPANIC +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspCreate()\fP +.XE +.Lb spDeleteRowAndCol +This function is used to delete a row and column from the matrix. The +elements removed from the matrix are never used again and are not freed +until the matrix is destroyed and so the pointers to these elements remain +valid. +.sp 0.3v +.nf +\fBvoid\fI spDeleteRowAndCol( Matrix, Row, Col )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +The matrix from which the row and column are to be deleted. +.XP +\fIRow\fP input (\fBint\fP) +.br +The row to be deleted. +.XP +\fICol\fP input (\fBint\fP) +.br +The column to be deleted. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +DELETE +TRANSLATE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspDeleteRowAndCol()\fP +.XE +.Lb spDestroy +Destroys a matrix frame and reclaims the memory. +.sp 0.3v +.nf +\fBvoid\fI spDestroy( Matrix )\fR +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix frame which is to be removed from memory. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspDestroy()\fP +.XE +.Lb spDeterminant +This routine in capable of calculating the determinant of the matrix +once the LU factorization has been performed. Hence, only use this +routine after \fIspFactor()\fP or \fIspOrderAndFactor()\fP and before +\fIspClear()\fP or \fIspInitialize()\fR. Note that the determinants +of matrices can be very large or very small. On large matrices, the +determinant can be far larger or smaller than can be represented by a +floating point number. For this reason the mantissa and exponent of +the determinant are returned separately. +.sp 0.3v +.nf +\fBvoid\fI spDeterminant( Matrix, Exponent, Determinant )\fR +.br +\fBvoid\fI spDeterminant( Matrix, Exponent, Determinant, iDeterminant )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +The matrix for which the determinant is desired. +.XP +\fIExponent\fP output (\fBint *\fP) +.br +The logarithm base 10 of the scale factor for the determinant. To find +the actual determinant, Exponent should be added to the exponent of +\fIDeterminant\fP and \fIiDeterminant\fP. +.XP +\fIDeterminant\fP output (spREAL \fB*\fR) +.br +The real portion of the determinant. If the matrix is real, then the +magnitude of this number is scaled to be greater than or equal to 1.0 +and less than 10.0. Otherwise the magnitude of the complex determinant +will be scaled such. +.XP +\fIiDeterminant\fP output (spREAL \fB*\fR) +.br +The imaginary portion of the determinant. When the matrix is real +this pointer need not be supplied; nothing will be returned. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +DETERMINANT +.XP +\(bu Bugs: +.br +The sign of determinant may be in error if rows and columns have been added +or deleted from matrix. +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspDeterminant()\fP +.XE +.Lb spElementCount +Returns the total number of structurally nonzero elements in the matrix. +.sp 0.3v +.nf +\fBint\fI spElementCount( Matrix )\fR +.XP +\(bu Returns: +.br +The total number of structurally nonzero elements. +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspElementCount()\fP +.XE +.Lb spError +This function returns the error status of a matrix. +.sp 0.3v +.nf +\fBint\fI MatrixError( Matrix )\fR +.XP +\(bu Returned: +.br +The error status of the given matrix. +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +The matrix for which the error status is desired. +.RE +.XP +\(bu Possible errors: +.nf +spOKAY +spILL_CONDITIONED +spZERO_PIVOT +spSINGULAR +spNO_MEMORY +spPANIC +Error is not cleared in this routine. +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspError()\fP +.XE +.Lb spFactor +This routine factors the matrix into LU form and is the companion +routine to \fIspOrderAndFactor()\fP. Unlike \fIspOrderAndFactor()\fP, +\fIspFactor()\fP cannot change the ordering. Its utility is that it is +considerably faster. The standard way to use these two routines is to +first use \fIspOrderAndFactor()\fP for the initial factorization. For +subsequent factorizations, \fIspFactor()\fP is used. If +\fIspFactor()\fP is called for the initial factorization of the matrix, +then it will automatically call \fIspOrderAndFactor()\fP with the +default thresholds. If \fIspFactor()\fP finds a zero on the diagonal, +it will terminate early and complain. This does not necessarily mean +that matrix is singular. Before a matrix is condemned as being +singular, it should be run through \fIspOrderAndFactor()\fP, which can +reorder the matrix and remove the offensive zero from the diagonal. +.sp 0.3v +.nf +\fBint\fI spFactor( Matrix )\fR +.XP +\(bu Returned: +.br +The error code is returned. Possible errors are listed below. +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix to be factored. +.RE +.XP +\(bu Possible errors: +.nf +spZERO_PIVOT +spNO_MEMORY +spSINGULAR +spILL_CONDITIONED +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspFactor()\fP +.XE +.Lb spFileMatrix +Writes matrix to file in format suitable to be read back in by the +matrix test program. Normally, \fIspFileMatrix()\fP should be executed +before the matrix is factored, otherwise matrix is output in factored +form. If the matrix is sent to a file without the header or data, it +will be in a form that is easily plotted by typical plotting programs. +.sp 0.3v +.nf +\fBint\fI spFileMatrix( Matrix, File, Label, Reordered, Data, Header )\fR +.XP +\(bu Returns: +.br +One is returned if routine was successful, otherwise zero is returned. +The calling function can query \fIerrno\fR (the system global error +variable) as to the reason why this routine failed. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix that is to be sent to file. +.XP +\fIFile\fP input (\fBchar *\fP) +.br +Name of output file. +.XP +\fILabel\fP input (\fBchar *\fP) +.br +String that is transferred to file and used as a label. String should +fit on one line and have no embedded line feeds. +.XP +\fIReordered\fP input (\fBint\fP) +.br +Specifies whether the matrix should be output using the original order +or in reordered form. Zero specifies original order. +.XP +\fIData\fP input (\fBint\fP) +.br +Indicates that the element values should be output along with the +indices for each element. Element values are not output if \fIData\fP +is zero. This parameter must be nonzero if matrix is to be read by the +\fISparse\fR test program. +.XP +\fIHeader\fP input (\fBint\fP) +.br +If nonzero a header is output that includes that size of the matrix and +the label. This parameter must be nonzero if matrix is to be read by +the \fISparse\fP test program. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +DOCUMENTATION +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspFileMatrix()\fP +.XE +.Lb spFileStats +Appends useful information concerning the matrix to the end of a file. +If file does not exist, it is created. This file should not be the same +as one used to hold the matrix or vector if the matrix is to be read by +the \fISparse\fP test program. Should be executed after the matrix is +factored. +.sp 0.3v +.nf +\fBint\fI spFileStats( Matrix, File, Label )\fR +.XP +\(bu Returns: +.br +One is returned if routine was successful, otherwise zero is returned. +The calling function can query \fIerrno\fR (the system global error +variable) as to the reason why this routine failed. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix for which statistics are desired. +.XP +\fIFile\fP input (\fBchar *\fP) +.br +Name of output file. +.XP +\fILabel\fP input (\fBchar *\fP) +.br +String that is transferred to file and is used as a label. String +should fit on one line and have no embedded line feeds. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +DOCUMENTATION +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspFileStats()\fP +.XE +.Lb spFileVector +Appends the \fIRHS\fP vector to the end of a file in a format suitable +to be read back in by the matrix test program. If file does not exist, +it is created. To be compatible with the test program, if +\fIspFileVector()\fP is run, it must be run after \fIspFileMatrix()\fP +and use the same file. +.sp 0.3v +.nf +\fBint\fI spFileVector( Matrix, File, RHS )\fR +.br +\fBint\fI spFileVector( Matrix, File, RHS, iRHS )\fR +.XP +\(bu Returns: +.br +One is returned if routine was successful, otherwise zero is returned. +The calling function can query \fIerrno\fR (the system global error +variable) as to the reason why this routine failed. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix that corresponds to the vector to be output. +.XP +\fIFile\fP input (\fBchar *\fP) +.br +Name of file where output is to be written. +.XP +\fIRHS\fP input (spREAL[]) +.br +The right-hand side vector. \fIRHS\fP contains only the real portion +of the right-hand side vector if the matrix is complex and +spSEPARATED_COMPLEX_VECTORS is set true. +.XP +\fIiRHS\fP input (spREAL[]) +.br +Right-hand side vector, imaginary portion. Not necessary if matrix is +real or if spSEPARATED_COMPLEX_VECTORS is set false. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +DOCUMENTATION +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspFileVector()\fP +.XE +.Lb spFillinCount +Returns the total number of fill-ins in the matrix. A fill-in is an +element that is originally structurally zero, but becomes nonzero during the +factorization. +.sp 0.3v +.nf +\fBint\fI spFillinCount( Matrix )\fR +.XP +\(bu Returns: +.br +The total number of fill-ins. +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspFillinCount()\fP +.XE +.Lb spGetAdmittance +Performs same function as \fIspGetElement()\fP except rather than one +element, all four matrix elements for a floating admittance are +reserved. This routine also works if the admittance is grounded (zero +is the ground node). This function returns a group of pointers to the +four elements through \fITemplate\fP, which is an output. They are +used by the \fIspADD_QUAD()\fP macros to directly access matrix +elements during subsequent loads of the matrix. +\fIspGetAdmittance()\fR arranges the pointers in \fITemplate\fR so that +the \fIspADD_QUAD()\fR routines add the admittance to the elements at +[\fINode1,Node1\fP] and [\fINode2,Node2\fP] and subtract the admittance +from the elements at [\fINode1,Node2\fP] and [\fINode2,Node1\fP]. This +routine is only to be used before \fIspMNA_Preorder()\fP, +\fIspFactor()\fP or \fIspOrderAndFactor()\fP unless the compiler flag +TRANSLATE is enabled. +.sp 0.3v +.nf +\fBint\fI spGetAdmittance( Matrix, Node1, Node2, Template )\fR +.XP +\(bu Returned: +.br +The error code is returned. Possible errors are listed below. +\fIspGetAdmittance()\fR does not clear the error state, so it is +possible to ignore the return code of each \fIspGetAdmittance()\fR +call, and check for errors after constructing the whole matrix by +calling \fIspError()\fR. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix that admittance is to be installed. +.XP +\fINode1\fP input (\fBint\fP) +.br +One node number for the admittance. \fINode1\fP must be in the range +[0..\fISize\fP] unless either the TRANSLATE or EXPANDABLE compiler +flags are set true. In either case \fINode1\fP must not be negative. +.XP +\fINode2\fP input (\fBint\fP) +.br +Other node number for the admittance. \fINode2\fP must be in the range +[0..\fISize\fP] unless either the TRANSLATE or EXPANDABLE compiler +flags are set true. In either case \fINode2\fP must not be negative. +.XP +\fITemplate\fP output (\fBstruct \fIspTemplate\fB *\fR) +.br +Collection of pointers to four elements that are later used to directly +address elements. User must supply the template, this routine will +fill it. +.RE +.XP +\(bu Possible errors: +.nf +spNO_MEMORY +Error is not cleared in this routine. +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +QUAD_ELEMENT +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspGetAdmittance()\fP +.XE +.Lb spGetElement +Reserves an element at [\fIRow,Col\fP] and returns a pointer to it. If +element is not found then it is created and spliced into matrix. A +pointer to the real portion of the element is returned. This pointer +is later used by the \fIspADD_ELEMENT()\fR macros to directly access +the element. This routine is only to be used before +\fIspMNA_Preorder()\fP, \fIspFactor()\fP or \fIspOrderAndFactor()\fP +unless the compiler option TRANSLATE is set true. +.sp 0.3v +.nf +spREAL \fB*\fIspGetElement( Matrix, Row, Col )\fR +.XP +\(bu Returned: +.br +Returns a pointer to the element. This pointer is then used to +directly access the element during successive builds. Returns NULL if +insufficient memory is available. \fIspGetElement()\fR does not clear +the error state, so it is possible to ignore the return code of each +\fIspGetElement()\fR call, and check for errors after constructing the +whole matrix by calling \fIspError()\fR. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix that the element is to be added to. +.XP +\fIRow\fP input (\fBint\fP) +.br +Row index for element. \fIRow\fP must be in the range [0..\fISize\fR] +unless either the TRANSLATE or EXPANDABLE compiler flags are set true. +In either case \fIRow\fP must not be negative though it may be zero. +If zero then the element is not entered into the matrix, but is otherwise +treated normally. +.XP +\fICol\fP input (\fBint\fP) +.br +Column index for element. \fICol\fP must be in the range [0..\fISize\fR] +unless either the TRANSLATE or EXPANDABLE compiler flags are set true. +In either case \fICol\fP must not be negative though it may be zero. +If zero then the element is not entered into the matrix, but is +otherwise treated normally. +.RE +.XP +\(bu Possible errors: +.nf +spNO_MEMORY +Error is not cleared in this routine. +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspGetElement()\fP +.XE +.Lb spGetInitInfo +With the INITIALIZE compiler option enabled \fISparse\fP allows the +user to keep initialization information with each structurally nonzero +matrix element. Each element has a pointer (referred to as +\fIpInitInfo\fR) that is set and used by the user. This routine returns +\fIpInitInfo\fR from a particular matrix element. +.sp 0.3v +.nf +\fBchar *\fIspGetInitInfo( pElement )\fR +.XP +\(bu Returned: +.br +The user installed pointer \fIpInitInfo\fR. +.XP +\(bu Argument: +.RS +.XP +\fIpElement\fR input (spREAL \fB*\fR) +.br +Pointer to the element to which \fIpInitInfo\fR is attached. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +INITIALIZE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspGetInitInfo()\fP +.XE +.Lb spGetOnes +Performs a similar function to \fIspGetAdmittance()\fP except that the +four reserved matrix elements are assumed to be structural ones +generated by components without admittance representations during a +modified nodal analysis. Positive ones are placed at [\fIPos,Eqn\fP] +and [\fIEqn,Pos\fP] and negative ones are placed at [\fINeg,Eqn\fP] and +[\fIEqn,Neg\fP]. This function returns a group of pointers to the four +elements through \fITemplate\fP, which is an output. They are used by +the \fIspADD_QUAD()\fP macros to add the ones directly to the matrix +elements during subsequent loads of the matrix. This routine is only +to be used before \fIspMNA_Preorder()\fP, \fIspFactor()\fP or +\fIspOrderAndFactor()\fP unless the compiler flag TRANSLATE is set +true. +.sp 0.3v +.nf +\fBint\fI spGetOnes( Matrix, Pos, Neg, Eqn, Template )\fR +.XP +\(bu Returned: +.br +The error code is returned. Possible errors are listed below. +\fIspGetOnes()\fR does not clear the error state, so it is possible to +ignore the return code of each \fIspGetOnes()\fR call, and check for +errors after constructing the whole matrix by calling \fIspError()\fR. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix that ones are to be entered in. +.XP +\fIPos\fP input (\fBint\fP) +.br +Number of positive node. Must be in the range of [0..\fISize\fR] +unless either the options EXPANDABLE or TRANSLATE are used. Zero is the +ground row. In no case may \fIPos\fP be less than zero. +.XP +\fINeg\fP input (\fBint\fP) +.br +Number of negative node. Must be in the range of [0..\fISize\fP] +unless either the options EXPANDABLE or TRANSLATE are used. Zero is the +ground row. In no case may \fINeg\fP be less than zero. +.XP +\fIEqn\fP input (\fBint\fP) +.br +Row that contains the branch equation. Must be in the range of [1..\fISize\fP] +unless either the options EXPANDABLE or TRANSLATE are used. In no case may +\fIEqn\fP be less than one. +.XP +\fITemplate\fP output (\fBstruct \fIspTemplate\fB *\fR) +.br +Collection of pointers to four elements that are later used to directly +address elements. User must supply the template, this routine will +fill it. +.RE +.XP +\(bu Possible errors: +.nf +spNO_MEMORY +Error is not cleared in this routine. +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +QUAD_ELEMENT +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspGetOnes()\fP +.XE +.Lb spGetQuad +Similar to \fIspGetAdmittance()\fP, except that \fIspGetAdmittance()\fP +only handles 2-terminal components, whereas \fIspGetQuad()\fP handles +simple 4-terminals as well. These 4-terminals are simply generalized +2-terminals with the option of having the sense terminals different +from the source and sink terminals. \fIspGetQuad()\fP installs four +elements into the matrix and returns their pointers in the +\fITemplate\fR structure, which is an output. The pointers are +arranged in \fITemplate\fR such that when passed to one of the +\fIspADD_QUAD()\fR macros along with an admittance, the admittance will be +added to the elements at [\fIRow1,Col1\fP] and [\fIRow2,Col2\fP] and +subtracted from the elements at [\fIRow1,Col2\fP] and +[\fIRow2,Col1\fP]. The routine works fine if any of the rows and +columns are zero. This routine is only to be used before +\fIspMNA_Preorder()\fP, \fIspFactor()\fP or \fIspOrderAndFactor()\fP +unless TRANSLATE is set true. +.sp 0.3v +.nf +\fBint\fI spGetQuad( Matrix, Row1, Row2, Col1, Col2, Template )\fR +.XP +\(bu Returned: +.br +The error code is returned. Possible errors are listed below. +\fIspGetQuad()\fR does not clear the error state, so it is possible to +ignore the return code of each \fIspGetQuad()\fR call, and check for +errors after constructing the whole matrix by calling \fIspError()\fR. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix that quad is to be entered in. +.XP +\fIRow1\fP input (\fBint\fP) +.br +First row index for the elements. \fIRow1\fP must be in the range +[0..\fISize\fP] unless either the TRANSLATE or EXPANDABLE compiler flags are +set true. In either case \fIRow1\fP must not be negative. +.XP +\fIRow2\fP input (\fBint\fP) +.br +Second row index for the elements. \fIRow2\fP must be in the range +[0..\fISize\fP] unless either the TRANSLATE or EXPANDABLE compiler flags are +set true. In either case \fIRow2\fP must not be negative. +.XP +\fICol1\fP input (\fBint\fP) +.br +First column index for the elements. \fICol1\fP must be in the range +[0..\fISize\fP] unless either the TRANSLATE or EXPANDABLE compiler flags are +set true. In either case \fICol1\fP must not be negative. +.XP +\fICol2\fP input (\fBint\fP) +.br +Second column index for the elements. \fICol2\fP must be in the range +[0..\fISize\fP] unless either the TRANSLATE or EXPANDABLE compiler flags are +set true. In either case \fICol2\fP must not be negative. +.XP +\fITemplate\fP output (\fBstruct \fIspTemplate\fB *\fR) +.br +Collection of pointers to four elements that are later used to directly +address elements. User must supply the template, this routine will +fill it. +.RE +.XP +\(bu Possible errors: +.nf +spNO_MEMORY +Error is not cleared in this routine. +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +QUAD_ELEMENT +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspGetQuad()\fP +.XE +.Lb spGetSize +Returns the size of the matrix, either the internal or external size of +the matrix is returned. The internal size is the actual number of rows +and columns in the matrix. The external size is equal to the largest +row or column number. These numbers will be the same unless the +TRANSLATE option is enabled. +.sp 0.3v +.nf +\fBint\fI spGetSize( Matrix, External )\fR +.XP +\(bu Returned: +.br +The size of the matrix. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix for which the size is desired. +.XP +\fIExternal\fP input (\fBint\fP) +.br +If \fIExternal\fR is nonzero, the external size of the matrix is returned, +otherwise the internal size of the matrix is returned. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspGetSize()\fP +.XE +.Lb spInitialize +\fIspInitialize()\fR is a user customizable way to initialize the +matrix. Passed to this routine is a function pointer. +\fIspInitialize()\fR sweeps through every element in the matrix and +checks the \fIpInitInfo\fR pointer (the user supplied pointer). If the +\fIpInitInfo\fR is NULL, which is true unless the user changes it +(always true for fill-ins), then the element is zeroed. Otherwise, the +function pointer is called and passed the \fIpInitInfo\fR pointer as +well as the element pointer and the external row and column numbers +allowing the user to set the value of each element and perhaps the +right-hand side vector. +.LP +The user function (\fIpInit()\fR) is expected to return a nonzero integer +if there is a fatal error and zero otherwise. Upon encountering a nonzero +return code, \fIspInitialize()\fR terminates and returns the error code. +.LP +The \fISparse\fR error state is cleared to spOKAY in this routine. +.sp 0.3v +.nf +\fBint\fI spInitialize( Matrix, pInit )\fR +.XP +\(bu Returns: +.br +The error code returned by \fIpInit\fR. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix that is to be initialized. +.XP +\fIpInit\fP input (\fB(*int)()\fP) +.br +Pointer to a function that, given a pointer to an element, a pointer to +the users data structure containing initialization information for that +element, and the row and column number of the element, initializes it. +.RE + +.LP +\fBint\fI pInit( pElement, pInitInfo, Row, Col )\fR +.XP +\(bu Returns: +.br +Nonzero if fatal error, zero otherwise. +.XP +\(bu Arguments: +.RS +.XP +\fIpElement\fP input (spREAL \fB*\fP) +.br +The pointer to the real portion of the element. The real portion can +be accessed using either \fI*pElement\fR or \fIpElement[0]\fR. The +imaginary portion can be accessed using either \fI*(pElement+1)\fR or +\fIpElement[1]\fR. +.XP +\fIpInitInfo\fP input (\fBchar *\fP) +.br +The user-installed pointer to the initialization data structure. +.XP +\fIRow\fP input (\fBint\fP) +.br +The external row number of the element. +.XP +\fICol\fP input (\fBint\fP) +.br +The external column number of the element. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +INITIALIZE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspInitialize()\fP +.XE +.Lb spInstallInitInfo +With the INITIALIZE compiler option enabled \fISparse\fP allows the +user to keep initialization information with each structurally nonzero +matrix element. Each element has a pointer (referred to as +\fIpInitInfo\fR) that is set and used by the user. This routine installs +the pointer \fIpInitInfo\fR into a particular matrix element. +.sp 0.3v +.nf +\fBvoid\fI spInstallInitInfo( pElement, pInitInfo )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIpElement\fR input (spREAL \fB*\fR) +.br +Pointer to the element to which \fIpInitInfo\fR is to be attached. +.XP +\fIpInitInfo\fR input (\fBchar *\fR) +.br +The pointer \fIpInitInfo\fR. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +INITIALIZE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspInstallInitInfo()\fP +.XE +.Lb spLargestElement +If this routine is called before the matrix is factored, it returns the +absolute value of the largest element in the matrix. If called after +the matrix has been factored, it returns a lower bound on the absolute +value of the largest element that occurred in any of the reduced +submatrices during the factorization. The ratio of these two numbers +(factored/unfactored) is the growth, which can be used to determine if +the pivoting order is adequate. A large growth implies that +considerable error has been made in the factorization and that it is +probably a good idea to reorder the matrix. If a large growth in +encountered after using \fIspFactor()\fR, reconstruct the matrix and +refactor using \fIspOrderAndFactor()\fR. If a large growth is +encountered after using \fIspOrderAndFactor()\fR, refactor using +\fIspOrderAndFactor()\fR with the pivot threshold increased, say to +0.1. +.sp 0.3v +.nf +spREAL\fI spLargestElement( Matrix )\fR +.XP +\(bu Returns: +.br +If matrix is unfactored, returns the magnitude of the largest element in +the matrix. If the matrix is factored, a bound on the magnitude of the +largest element in any of the reduced submatrices is returned. +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fR input (\fBchar *\fR) +.br +Pointer to the matrix. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +STABILITY +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspLargestElement()\fP +.XE +.Lb spMNA_Preorder +This routine massages modified node admittance matrices to improve the +performance of \fIspOrderAndFactor()\fP. It tries to remove structural +zeros from the diagonal by exploiting the fact that the row and column +associated with a zero diagonal usually have structural ones placed +symmetrically. For this routine to work, the structural ones must be +exactly equal to either one or negative one. This routine should be +used only on modified node admittance matrices and must be executed +after the matrix has been built but before \fIspScale()\fP, \fIspNorm()\fP, +\fIspMultiply()\fP, \fIspFactor()\fP, \fIspOrderAndFactor()\fP or +\fIspDeleteRowAndCol()\fP are executed. It should be executed for the +initial factorization only. +.sp 0.3v +.nf +\fBvoid\fI spMNA_Preorder( Matrix )\fR +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.IP +Pointer to the matrix to be preordered. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +MODIFIED_NODAL +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspMNA_Preorder()\fP +.XE +.Lb spMultiply +Multiplies \fIMatrix\fP by \fISolution\fP on the right to find \fIRHS\fP. +Assumes matrix has not been factored. This routine can be used as a +test to see if solutions are correct. +.sp 0.3v +\fBvoid\fI spMultiply( Matrix, RHS, Solution )\fR +.br +\fBvoid\fI spMultiply( Matrix, RHS, Solution, iRHS, iSolution )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix. +.XP +\fIRHS\fP output (spREAL[]) +.br +\fIRHS\fP is the right hand side vector. This is what is being +solved for. \fIRHS\fP contains only the real portion of the +right-hand side if spSEPARATED_COMPLEX_VECTORS is set true. +.XP +\fISolution\fP input (spREAL[]) +.br +\fISolution\fP is the vector being multiplied by the matrix. +\fISolution\fP contains only the real portion of that vector if +spSEPARATED_COMPLEX_VECTORS is set true. +.XP +\fIiRHS\fP output (spREAL[]) +.br +\fIiRHS\fP is the imaginary portion of the right hand side. This +is what is being solved for. It is only necessary to supply +\fIiRHS\fP if the matrix is complex and +spSEPARATED_COMPLEX_VECTORS is set true. +.XP +\fIiSolution\fP input (spREAL[]) +.br +\fIiSolution\fP is the imaginary portion of the vector being +multiplied by the matrix. It is only necessary to supply +\fIiRHS\fP if the matrix is complex and +spSEPARATED_COMPLEX_VECTORS is set true. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +MULTIPLICATION +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspMultiply()\fP +.XE +.Lb spMultTransposed +Multiplies transposed \fIMatrix\fP by \fISolution\fP on the right to +find \fIRHS\fP. Assumes matrix has not been factored. This routine can +be used as a test to see if solutions are correct. +.sp 0.3v +\fBvoid\fI spMultTransposed( Matrix, RHS, Solution )\fR +.br +\fBvoid\fI spMultTransposed( Matrix, RHS, Solution, iRHS, iSolution )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix. +.XP +\fIRHS\fP output (spREAL[]) +.br +\fIRHS\fP is the right hand side vector. This is what is being +solved for. \fIRHS\fP contains only the real portion of the +right-hand side if spSEPARATED_COMPLEX_VECTORS is set true. +.XP +\fISolution\fP input (spREAL[]) +.br +\fISolution\fP is the vector being multiplied by the matrix. +\fISolution\fP contains only the real portion of that vector if +spSEPARATED_COMPLEX_VECTORS is set true. +.XP +\fIiRHS\fP output (spREAL[]) +.br +\fIiRHS\fP is the imaginary portion of the right hand side. This +is what is being solved for. It is only necessary to supply +\fIiRHS\fP if the matrix is complex and +spSEPARATED_COMPLEX_VECTORS is set true. +.XP +\fIiSolution\fP input (spREAL[]) +.br +\fIiSolution\fP is the imaginary portion of the vector being +multiplied by the matrix. It is only necessary to supply +\fIiRHS\fP if the matrix is complex and +spSEPARATED_COMPLEX_VECTORS is set true. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +MULTIPLICATION +TRANSPOSE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspMultTransposed()\fP +.XE +.Lb spNorm +Computes and returns the L-infinity norm of an unfactored matrix. +This number is used in computing the condition number of the matrix. +It is a fatal error to pass this routine a factored matrix. +.sp 0.3v +spREAL\fI spNorm( Matrix )\fR +.XP +\(bu Returns: +.br +The largest absolute row sum (the L-infinity norm) of the matrix. +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +CONDITION +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspNorm()\fP +.XE +.Lb spOrderAndFactor +This routine chooses a pivot order for the matrix and factors it into LU +form. It handles both the initial factorization and subsequent +factorizations when a reordering or threshold pivoting is desired. This +is handled in a manner that is transparent to the user. +.sp 0.3v +\fBint\fI spOrderAndFactor( Matrix, RHS, Threshold, AbsoluteThreshold, DiagPivoting )\fR +.KE +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspOrderAndFactor()\fP +.XE +.XP +\(bu Returned: +.br +The error code is returned. Possible errors are listed below. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix to be factored. +.XP +\fIRHS\fP input (spREAL[]) +.br +Representative \fIRHS\fP vector that is used to determine pivoting order +when the right-hand side vector is sparse. If a term in \fIRHS\fP +is zero, it is assumed that it will usually be zero. Conversely, a +nonzero term in \fIRHS\fP indicates that the term will often be +nonzero. If \fIRHS\fP is a NULL pointer then the right-hand side vector is +assumed to be full and it is not used when determining the pivoting +order. +.XP +\fIThreshold\fR input (spREAL) +.br +This is the pivot threshold, which should be between zero and one. If +it is one then the pivoting method becomes complete pivoting, which is +very slow and tends to fill up the matrix. If it is set close to zero +the pivoting method becomes strict Markowitz with no threshold. The +pivot threshold is used to eliminate pivot candidates that would cause +excessive element growth if they were used. Element growth is the cause +of roundoff error, which can occur even in well-conditioned matrices. +Setting the threshold large will reduce element growth and roundoff +error, but setting it too large will cause execution time to be +excessive and will result in a large number of fill-ins. If this +occurs, accuracy can actually be degraded because of the large number of +operations required on the matrix due to the large number of fill-ins. +A good value for diagonal pivoting seems to be 0.001 while a good value +for complete pivoting appears to be 0.1. The default is chosen by +giving a value larger than one or less than or equal to zero. Once the +pivot threshold is set, the value becomes the new default for later +calls to \fIspOrderAndFactor\fR. The threshold value should be +increased and the matrix re-solved if growth is found to be excessive. +Changing the pivot threshold does not improve performance on matrices +where growth is low, as is often the case with ill-conditioned matrices. +The default value of \fIThreshold\fR was choosen for use with nearly +diagonally dominant matrices such as node- and modified-node admittance +matrices. For these matrices it is usually best to use diagonal +pivoting. For matrices without a strong diagonal, it is usually best to +use a larger threshold, such as 0.01 or 0.1. +.XP +\fIAbsoluteThreshold\fP input (spREAL) +.br +The absolute magnitude an element must have to be considered as a pivot +candidate, except as a last resort. This number should be set +significantly smaller than the smallest diagonal element that is is +expected to be placed in the matrix. If there is no reasonable +prediction for the lower bound on these elements, then +\fIAbsoluteThreshold\fP should be set to zero. \fIAbsoluteThreshold\fP +is used to reduce the possibility of choosing as a pivot an element +that has suffered heavy cancellation and as a result mainly consists of +roundoff error. Note that if \fIAbsoluteThreshold\fP is set too large, +it could drastically increase the time required to factor and solve +the matrix. \fIAbsoluteThreshold\fP should be nonnegative. +If no element in the matrix is larger than \fIAbsoluteThreshold\fR, the +warning spILL_CONDITIONED is returned. +.XP +\fIDiagPivoting\fP input (int) +.br +A flag indicating that pivot selection should be confined to the +diagonal if possible. If \fIDiagPivoting\fR is nonzero and if +DIAGONAL_PIVOTING is enabled pivots will be chosen only from the +diagonal unless there are no diagonal elements that satisfy the +threshold criteria. Otherwise, the entire reduced submatrix is +searched when looking for a pivot. The diagonal pivoting in +\fISparse\fR is efficient and well refined, while the complete +pivoting is not. For symmetric and near symmetric matrices, it is best +to use diagonal pivoting because it results in the best performance +when reordering the matrix and when factoring the matrix without +ordering. If there is a considerable amount of nonsymmetry in the +matrix, then complete pivoting may result in a better equation +ordering simply because there are more pivot candidates to choose +from. A better ordering results in faster subsequent factorizations. +However, the initial pivot selection process takes considerably longer +for complete pivoting. +.RE +.KS +.XP +\(bu Possible errors: +.nf +spNO_MEMORY +spSINGULAR +spILL_CONDITIONED +.Le +.RE +.Lb spPartition +This routine determines the cost to factor each row using both direct +and indirect addressing and decides, on a row-by-row basis, which +addressing mode is fastest. This information is used in +\fIspFactor()\fR to speed the factorization. +.LP +When factoring a previously ordered matrix using \fIspFactor()\fR, +f\ISparse\fR operates on a row-at-a-time basis. For speed, on each +step, the row being updated is copied into a full vector and the +operations are performed on that vector. This can be done one of two +ways, either using direct addressing or indirect addressing. Direct +addressing is fastest when the matrix is relatively dense and indirect +addressing is best when the matrix is quite sparse. The user selects +the type of partition used with \fIMode\fR. If \fIMode\fR is set to +spDIRECT_PARTITION, then the all rows are placed in the direct +addressing partition. Similarly, if \fIMode\fR is set to +spINDIRECT_PARTITION, then the all rows are placed in the indirect +addressing partition. By setting \fIMode\fR to spAUTO_PARTITION, the +user allows \fISparse\fR to select the partition for each row +individually. \fIspFactor()\fR generally runs faster if \fISparse\fR +is allowed to choose its own partitioning, however choosing a partition +is expensive. The time required to choose a partition is of the same +order of the cost to factor the matrix. If you plan to factor a large +number of matrices with the same structure, it is best to let +\fISparse\fR choose the partition. Otherwise, you should choose the +partition based on the predicted density of the matrix. By default +(i.e., if \fIspPartition()\fR is never called), \fISparse\fR chooses +the partition for each row individually. +.sp 0.3v +\fBvoid\fI spPartition( Matrix, Mode )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix to be partitioned. +.XP +\fIMode\fP input (\fBint\fR) +.br +Mode must be one of three special codes: spDIRECT_PARTITION, +spINDIRECT_PARTITION, or spAUTO_PARTITION. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspPartition()\fP +.XE +.Lb spPrint +Formats and send the matrix to standard output. Some elementary +statistics are also output. The matrix is output in a format that is +readable by people. This routine should not be used on large matrices. +.sp 0.3v +\fBvoid\fI spPrint( Matrix, PrintReordered, Data, Header )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix to be printed. +.XP +\fIPrintReordered\fP input (\fBint\fP) +.br +Indicates whether the matrix should be printed out in its original +form, as input by the user, or whether it should be printed in its +reordered form, as used internally by the matrix routines. A zero +indicates that the matrix should be printed as inputed, a one indicates +that it should be printed reordered. +.XP +\fIData\fP input (\fBint\fP) +.br +Boolean flag that when false indicates that output should be compressed +such that only the existence of an element should be indicated rather +than giving the actual value. Thus 10 times as many elements can be +printed on a row. A zero indicates that the matrix should be printed +compressed. A one signifies that the matrix should be printed in all +its glory. +.XP +\fIHeader\fP input (\fBint\fP) +.br +A flag indicating that extra information should be printed, such as +row and column numbers. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +DOCUMENTATION +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspPrint()\fP +.XE +.Lb spPseudoCondition +Computes the magnitude of the ratio of the largest to the smallest +pivots. This quantity is an indicator of ill-conditioning in the +matrix. If this ratio is large, and if the matrix is scaled such that +uncertainties in the right-hand side vector and the matrix entries are +equilibrated, then the matrix is ill-conditioned. However, a small +ratio does not necessarily imply that the matrix is well-conditioned. +This routine must only be used after a matrix has been factored by +\fIspOrderAndFactor()\fR or \fIspFactor()\fR and before it is cleared +by \fIspClear()\fR or \fIspInitialize()\fR. The pseudocondition is +faster to compute than the condition number calculated by +\fIspCondition()\fR, but is not as informative. +.sp 0.3v +spREAL \fI spPseudoCondition( Matrix )\fR +.XP +\(bu Returns: +.br +The magnitude of the ratio of the largest to smallest +pivot used during previous factorization. If the matrix was singular, +zero is returned. +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +PSEUDOCONDITION +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspPseudoCondition()\fP +.XE +.Lb spRoundoff +Returns a bound on the magnitude of the largest element in +$bold E ~=~ bold A - bold LU$, where $bold E$ represents error in the +matrix resulting from roundoff during the factorization. +.sp 0.3v +spREAL \fI spRoundoff( Matrix, Rho )\fR +.XP +\(bu Returns: +.br +Returns a bound on the magnitude of the largest element in +$bold E ~=~ bold A - bold LU$. +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix. Matrix must be factored. +.XP +\fIRho\fP input (spREAL) +.br +The bound on the magnitude of the largest element in any of the reduced +submatrices. This is the number computed by the function +\fIspLargestElement()\fR when given a factored matrix. If this number +is negative, the bound will be computed automatically. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +STABILITY +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspRoundoff()\fP +.XE +.Lb spScale +This function scales the matrix to enhance the possibility of finding a +good pivoting order. Note that scaling enhances accuracy of the +solution only if it affects the pivoting order, so it only makes sense +to scale the matrix before \fIspOrderAndFactor()\fP. There are several +things to take into account when choosing the scale factors. First, +the scale factors are directly multiplied times the elements in the +matrix. To prevent roundoff, each scale factor should be equal to an +integer power of the number base of the machine. Since most machines +operate in base two, scale factors should be a power of two. Second, +the matrix should be scaled such that the matrix of element +uncertainties is equilibrated. Third, this function multiplies the +scale factors times the elements, so if one row tends to have +uncertainties 1000 times smaller than the other rows, then its scale +factor should be 1024, not 1/1024. Fourth, to save time, this function +does not scale rows or columns if their scale factors are equal to +one. Thus, the scale factors should be normalized to the most common +scale factor. Rows and columns should be normalized separately. For +example, if the size of the matrix is 100 and 10 rows tend to have +uncertainties near 1e-6 and the remaining 90 have uncertainties near +1e-12, then the scale factor for the 10 should be 1/1,048,576 and the +scale factors for the remaining 90 should be 1. Fifth, since this +routine directly operates on the matrix, it is necessary to apply the +scale factors to the \fIRHS\fP and \fISolution\fP vectors. It may be +easier to simply use \fIspOrderAndFactor()\fP on a scaled matrix to +choose the pivoting order, and then throw away the matrix. Subsequent +factorizations, performed with \fIspFactor()\fP, will not need to have +the \fIRHS\fP and \fISolution\fP vectors descaled. +.sp 0.3v +\fBvoid\fI spScale( Matrix, RHS_ScaleFactors, SolutionScaleFactors )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to the matrix to be scaled. +.XP +\fIRHS_ScaleFactors\fP input (spREAL[]) +.br +The array of RHS scale factors. These factors scale the rows. All +scale factors are real-valued. +.XP +\fISolutionScaleFactors\fP input (spREAL[]) +.br +The array of Solution scale factors. These factors scale the columns. +All scale factors are real-valued. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +SCALING +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspScale()\fP +.XE +.Lb spSetComplex +The type of the matrix may then be toggled back and forth between +complex and real. This function changes the type of matrix to +complex. For the matrix to be set complex, the compiler option spCOMPLEX +must be set true. +.sp 0.3v +\fBvoid\fI spSetComplex( Matrix )\fR +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.IP +The matrix that is to be to be complex. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspSetComplex()\fP +.XE +.Lb spSetReal +The type of the matrix may then be toggled back and forth between +complex and real. This function changes the type of matrix to +real. For the matrix to be set real, the compiler option REAL +must be set true. +.sp 0.3v +\fBvoid\fI spSetReal( Matrix )\fR +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +The matrix that is to be real. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspSetReal()\fP +.XE +.Lb spSolve +Performs the forward and backward elimination to find the unknown +\fISolution\fP vector from \fIRHS\fP and the factored matrix. +.sp 0.3v +\fBvoid\fI spSolve( Matrix, RHS, Solution )\fR +.br +\fBvoid\fI spSolve( Matrix, RHS, Solution, iRHS, iSolution )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix. +.XP +\fIRHS\fP input (spREAL[]) +.br +\fIRHS\fP is the input data array, the right-hand side vector. +\fIRHS\fP contains only the real portion of the right-hand side vector if +spSEPARATED_COMPLEX_VECTORS is set true. \fIRHS\fP is undisturbed and may +be reused for other solves. +.XP +\fISolution\fP output (spREAL[]) +.br +\fISolution\fP is the output data array, the unknown vector. This +routine is constructed such that \fIRHS\fP and \fISolution\fP can be +the same array. \fISolution\fP contains only the real portion of the +unknown vector if spSEPARATED_COMPLEX_VECTORS is set true. +.XP +\fIiRHS\fP input (spREAL[]) +.br +\fIiRHS\fP is the imaginary portion of the input data array, the +right-hand side vector. This data is undisturbed and may be reused for other +solves. This argument is unnecessary if the matrix is real or +spSEPARATED_COMPLEX_VECTORS is set false. +.XP +\fIiSolution\fP output (spREAL[]) +.br +\fIiSolution\fP is the imaginary portion of the output data array. +This routine is constructed such that \fIiRHS\fP and +\fIiSolution\fP can be the same array. This argument is +unnecessary if the matrix is real or spSEPARATED_COMPLEX_VECTORS is +set false. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspSolve()\fP +.XE +.Lb spSolveTransposed +Performs the forward and backward elimination to find the unknown +\fISolution\fP vector from \fIRHS\fP and the transposed factored +matrix. This routine is useful when performing sensitivity analysis on +a circuit using the adjoint method. +.sp 0.3v +\fBvoid\fI spSolveTransposed( Matrix, RHS, Solution )\fR +.br +\fBvoid\fI spSolveTransposed( Matrix, RHS, Solution, iRHS, iSolution )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix. +.XP +\fIRHS\fP input (spREAL[]) +.br +\fIRHS\fP is the input data array, the right-hand side vector. +\fIRHS\fP contains only the real portion of the right-hand side +vector if spSEPARATED_COMPLEX_VECTORS is set true. \fIRHS\fP is +undisturbed and may be reused for other solves. +.XP +\fISolution\fP output (spREAL[]) +.br +\fISolution\fP is the output data array, the unknown vector. This +routine is constructed such that \fIRHS\fP and \fISolution\fP can be +the same array. \fISolution\fP contains only the real portion of the +unknown vector if spSEPARATED_COMPLEX_VECTORS is set true. +.XP +\fIiRHS\fP input (spREAL[]) +.br +\fIiRHS\fP is the imaginary portion of the input data array, the +right-hand side vector. This data is undisturbed and may be reused for other +solves. This parameter is unnecessary if the matrix is real or +spSEPARATED_COMPLEX_VECTORS is set false. +.XP +\fIiSolution\fP output (spREAL[]) +.br +\fIiSolution\fP is the imaginary portion of the output data array. +This routine is constructed such that \fIiRHS\fP and +\fIiSolution\fP can be the same array. This parameter is +unnecessary if the matrix is real or spSEPARATED_COMPLEX_VECTORS is +set false. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +TRANSPOSE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspSolveTransposed()\fP +.XE +.Lb spStripFills +\fIspStripFills()\fP strips all accumulated fill-ins from a matrix. This +is often a useful thing to do before reordering a matrix to help insure +that subsequent factorizations will be as efficient as possible. +.sp 0.3v +.nf +\fBvoid\fI spStripFills( Matrix )\fR +.XP +\(bu Argument: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +The matrix to be stripped. +.RE +.XP +\(bu Compiler options that must be set for this routine to exist: +.nf +STRIP +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspStripFills()\fP +.XE +.Lb spWhereSingular +This function returns the row and column number where the matrix was +detected as singular or where a zero pivot was found. +.sp 0.3v +\fBvoid\fI spWhereSingular( Matrix, Row, Col )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIMatrix\fP input (\fBchar *\fP) +.br +Pointer to matrix. +.XP +\fIRow\fP output (\fBint *\fP) +.br +The row number. +.XP +\fIRow\fP output (\fBint *\fP) +.br +The column number. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspWhereSingular()\fP +.XE +.bp +.nr ss 0 1 \" Reset subsection +.RT +.ne 1.5i +.LG +.B "\n+(sc: MACRO FUNCTIONS" +.NL +.XS \n% \" Save section title for table of contents +\n(sc: Macro Functions +.XE +These macro functions are used to quickly enter data into the matrix +using pointers. These pointers are originally acquired by the user +from \fIspGetElement()\fP, \fIspGetAdmittance()\fP, \fIspGetQuad()\fP, +and \fIspGetOnes()\fP during the initial loading of the +matrix. These macros work correctly even if the elements they are to add +data to are in row or column zero. +.PP +The macros reside in the file \fBspExports.h\fP. To use them, +this file must be included in the file of the calling routine and that +routine must be written in C. +.Lb spADD_REAL_ELEMENT +Macro function that adds a real value to an element in the matrix by a pointer. +.sp 0.3v +\fIspADD_REAL_ELEMENT( pElement , Real )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIpElement\fP input (spREAL \fB*\fP) +.br +A pointer to the element to which \fIReal\fR is to be added. +.XP +\fIReal\fP input (spREAL) +.br +The real value that is to be added to the element. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspADD_REAL_ELEMENT()\fP +.XE +.Lb spADD_IMAG_ELEMENT +Macro function that adds a imaginary value to an element in the matrix +by a pointer. +.sp 0.3v +\fIspADD_IMAG_ELEMENT( pElement , Imag )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIpElement\fP input (spREAL \fB*\fP) +.br +A pointer to the element to which \fIImag\fR is to be added. +.XP +\fIImag\fP input (spREAL) +.br +The imaginary value that is to be added to the element. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspADD_IMAG_ELEMENT()\fP +.XE +.Lb spADD_COMPLEX_ELEMENT +Macro function that adds a complex value to an element in the matrix +by a pointer. +.sp 0.3v +\fIspADD_COMPLEX_ELEMENT( pElement, Real, Imag )\fR +.XP +\(bu Arguments: +.RS +.XP +\fIpElement\fP input (spREAL \fB *\fP) +.br +A pointer to the element to which \fIReal\fR and \fIImag\fR are to be added. +.XP +\fIReal\fP input (spREAL) +.br +The real value that is to be added to the element. +.XP +\fIImag\fP input (spREAL) +.br +The imaginary value that is to be added to the element. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspADD_COMPLEX_ELEMENT()\fP +.XE +.Lb spADD_REAL_QUAD +Macro that adds a real value to the four elements specified by +\fITemplate\fP. The value is added to the first two elements in +\fITemplate\fR, and subtracted from the last two. +.sp 0.3v +\fIspADD_REAL_QUAD( Template, Real )\fR +.XP +\(bu Arguments: +.RS +.XP +\fITemplate\fP input (\fBstruct \fIspTemplate\fR) +.br +Data structure containing the pointers to four matrix elements. +.XP +\fIReal\fP input (spREAL) +.br +Real value to be added to the elements. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspADD_REAL_QUAD()\fP +.XE +.Lb spADD_IMAG_QUAD +Macro that adds an imaginary value to the four elements specified by +\fITemplate\fP. The value is added to the first two elements in +\fITemplate\fR, and subtracted from the last two. +.sp 0.3v +\fIspADD_IMAG_QUAD( Template, Imag )\fR +.XP +\(bu Arguments: +.RS +.XP +\fITemplate\fP input (\fBstruct \fIspTemplate\fR) +.br +Data structure containing the pointers to four matrix elements. +.XP +\fIImag\fP input (spREAL) +.br +Imaginary value to be added to the elements. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspADD_IMAG_QUAD()\fP +.XE +.Lb spADD_COMPLEX_QUAD +Macro that adds a complex value to the four elements specified by +\fITemplate\fP. The value is added to the first two elements in +\fITemplate\fR, and subtracted from the last two. +.sp 0.3v +\fIspADD_COMPLEX_QUAD( Template, Real, Imag )\fR +.XP +\(bu Arguments: +.RS +.XP +\fITemplate\fP input (\fBstruct \fIspTemplate\fR) +.br +Data structure containing the pointers to four matrix elements. +.XP +\fIReal\fP input (spREAL) +.br +Real value to be added to the elements. +.XP +\fIImag\fP input (spREAL) +.br +Imaginary value to be added to the elements. +.RE +.Le +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: \fIspADD_COMPLEX_QUAD()\fP +.XE +.bp +.nr ss 0 1 \" Reset subsection +.RT +.ne 1.5i +.LG +.B "\n+(sc: CONFIGURING SPARSE" +.NL +.XS \n% \" Save section title for table of contents +\n(sc: Configuring \fISparse\fR +.XE +.PP +\fISparse\fR has a extensive set of options and parameters that can be +set at compile time to alter the personality of the program. They also are +used to eliminate routines that are not needed so as to reduce the +amount of memory required to hold the object code. These options and +parameters consist of macros definitions and are contained in the +file \fBspConfig.h\fR. To configure \fISparse\fR, \fBspConfig.h\fP must be +edited and then \fISparse\fP must be recompiled. +.PP +Some terminology should be defined. The Markowitz row count is the number +of non-zero elements in a row excluding the one being considered as pivot. +There is one Markowitz row count for every row. The Markowitz column count +is defined similarly for columns. The Markowitz product for an element +is the product of its row and column counts. It is a measure of how much +work would be required on the next step of the factorization if that +element were chosen to be pivot. A small Markowitz product is desirable. +For a more detailed explanation, see Kundert [kundert86]. +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Sparse Options" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Sparse Options +.XE +.KS +.LP +REAL +.LP +This specifies that the routines are expected to handle real systems +of equations. The routines can be compiled to handle both real and +complex systems at the same time, but there is a slight speed and +memory advantage if the routines are complied to handle only real +systems of equations. +.KE +.sp 0.6v +.KS +.LP +spCOMPLEX +.LP +This specifies that the routines will be complied to handle complex +systems of equations. +.KE +.sp 0.6v +.KS +.LP +EXPANDABLE +.LP +Setting this compiler flag true makes the matrix expandable +before it has been reordered. If the matrix is expandable, +then if an element is added that would be considered out of bounds +in the current matrix, the size of the matrix is increased to hold +that element. As a result, the size of the matrix need not be known +before the matrix is built. The matrix can be allocated with size +zero and expanded. It is possible to expand the size of a matrix +after it is been reordered if TRANSLATE and EXPANDABLE are both set true. +.KE +.sp 0.6v +.KS +.LP +TRANSLATE +.LP +This option allows the set of external row and column numbers to be +non-packed. In other words, the row and column numbers need not be +contiguous. The priced paid for this flexibility is that when +TRANSLATE is set true, the time required to initially build the matrix +will be greater because the external row and column number must be +translated into internal equivalents. This translation brings about +other benefits though. First, the \fIspGetElement()\fR, +\fIspGetAdmittance()\fR, \fIspGetQuad()\fR, and \fIspGetOnes()\fR +routines may be used after the matrix has been factored. Further, +elements, and even rows and columns, may be added to the matrix, and +rows and columns may be deleted from the matrix, after it has been +reordered. Note that when the set of row and column number is not a +packed set, neither are the \fIRHS\fP and \fISolution\fP vectors. Thus +the size of these vectors must be at least as large as the external +size, which is the value of the largest given row or column numbers. +.KE +.sp 0.6v +.KS +.LP +INITIALIZE +.LP +Causes the \fIspInitialize()\fR, \fIspGetInitInfo()\fR, and +\fIspInstallInitInfo()\fR routines to be compiled. These routines +allow the user to store and read one pointer in each nonzero element in +the matrix. \fIspInitialize()\fR then calls a user specified function +for each structural nonzero in the matrix, and includes this pointer as +well as the external row and column numbers as arguments. This allows +the user to write custom matrix and right-hand side vector +initialization routines. +.KE +.sp 0.6v +.KS +.LP +DIAGONAL_PIVOTING +.LP +Many matrices, and in particular node- and modified-node admittance +matrices, tend to be nearly symmetric and nearly diagonally dominant. +For these matrices, it is a good idea to select pivots from the +diagonal. With this option enabled, this is exactly what happens, +though if no satisfactory pivot can be found on the diagonal, an +off-diagonal pivot will be used. If this option is disabled, +\fISparse\fR does not preferentially search the diagonal. Because of +this, \fISparse\fR has a wider variety of pivot candidates available, +and so presumably fewer fill-ins will be created. However, the initial +pivot selection process will take considerably longer. If working with +node admittance matrices, or other matrices with a strong diagonal, it +is probably best to use DIAGONAL_PIVOTING for two reasons. First, +accuracy will be better because pivots will be chosen from the large +diagonal elements, thus reducing the chance of growth and hence, +roundoff. Second, a near optimal ordering will be chosen quickly. If +the class of matrices you are working with does not have a strong +diagonal, do not use DIAGONAL_PIVOTING, but consider using a larger +threshold. When DIAGONAL_PIVOTING is turned off, the following options +and constants are not used: MODIFIED_MARKOWITZ, MAX_MARKOWITZ_TIES, and +TIES_MULTIPLIER. +.KE +.sp 0.6v +.KS +.LP +ARRAY_OFFSET +.LP +This determines whether arrays start at an index of zero or one. This +option is necessitated by the fact that standard C convention dictates +that arrays begin with an index of zero but the standard mathematic +convention states that arrays begin with an index of one. So if you +prefer to start your arrays with zero, or you're calling \fISparse\fP +from some other programming language, use an ARRAY_OFFSET of 0. +Otherwise, use an ARRAY_OFFSET of 1. Note that if you use an offset of +one, the arrays that you pass to \fISparse\fR must have an allocated +length of one plus the external size of the matrix. ARRAY_OFFSET must +be either 0 or 1, no other offsets are valid. +.KE +.sp 0.6v +.KS +.LP +spSEPARATED_COMPLEX_VECTORS +.LP +This specifies the format for complex vectors. If this is set false +then a complex vector is made up of one double sized array of spREALs +in which the real and imaginary numbers are placed alternately in the +array. In other words, the first entry would be \fIComplex[1].Real\fP, +then comes \fIComplex[1].Imag\fP, then \fIComplex[2].Real\fP, etc. If +spSEPARATED_COMPLEX_VECTORS is set true, then each complex vector is +represented by two arrays of spREALs, one with the real terms, the +other with the imaginary. +.KE +.sp 0.6v +.KS +.LP +MODIFIED_MARKOWITZ +.LP +This specifies that the modified Markowitz method of pivot +selection is to be used. The modified Markowitz method differs +from standard Markowitz in two ways. First, under modified +Markowitz, the search for a pivot can be terminated early if a +adequate (in terms of sparsity) pivot candidate is found. +Thus, when using modified Markowitz, the initial factorization +can be faster, but at the expense of a suboptimal pivoting +order that may slow subsequent factorizations. The second +difference is in the way modified Markowitz breaks Markowitz +ties. When two or more elements are pivot candidates and they +all have the same Markowitz product, then the tie is broken by +choosing the element that is best numerically. The numerically +best element is the one with the largest ratio of its magnitude +to the magnitude of the largest element in the same column, +excluding itself. The modified Markowitz method results in +marginally better accuracy. +.KE +.sp 0.6v +.KS +.LP +DELETE +.LP +This specifies that the \fIspDeleteRowAndCol()\fP routine should +be compiled. Note that for this routine to be compiled, both DELETE +and TRANSLATE should be set true. +.KE +.sp 0.6v +.KS +.LP +STRIP +.LP +This specifies that the \fIspStripFills()\fP routine should be compiled. +.KE +.sp 0.6v +.KS +.LP +MODIFIED_NODAL +.LP +This specifies that the \fIspMNA_Preorder()\fR, the routine that +preorders modified node admittance matrices, should be compiled. +This routine results in greater speed and accuracy if used with this +type of matrix. +.KE +.sp 0.6v +.KS +.LP +QUAD_ELEMENT +.LP +This specifies that the routines that allow four related elements to be +entered into the matrix at once should be compiled. The routines affected by +QUAD_ELEMENT are \fIspGetAdmittance()\fP, \fIspGetQuad()\fP, and +\fIspGetOnes()\fP. +.KE +.sp 0.6v +.KS +.LP +TRANSPOSE +.LP +This specifies that \fIspSolveTranspose()\fR and perhaps +\fIspMultTransposed()\fR, which operate on +the matrix as if it was transposed, should be compiled. +.KE +.sp 0.6v +.KS +.LP +SCALING +.LP +This specifies that the routine that performs scaling on the matrix +should be complied. Scaling is not strongly supported. The routine to +scale the matrix is provided, but no routines are provided to scale and +descale the \fIRHS\fP and \fISolution\fP vectors. It is suggested that +if scaling is desired, it only be performed when the pivot order is +being chosen, which is done in \fIspOrderAndFactor()\fP. This, and +when the condition number of the matrix is calculated with +\fIspCondition()\fR, are the only times scaling has an effect. The +scaling may then either be removed from the solution by the user or the +scaled factored matrix may simply be thrown away. +.KE +.sp 0.6v +.KS +.LP +DOCUMENTATION +.LP +This specifies that routines that are used to document the matrix, +\fIspPrint()\fP, \fIspFileMatrix()\fP, \fIspFileVector()\fP, and +\fIspFileStats()\fP, should be compiled. +.KE +.sp 0.6v +.KS +.LP +DETERMINANT +.LP +This specifies that the \fIspDeterminant()\fR routine should be complied. +.KE +.sp 0.6v +.KS +.LP +STABILITY +.LP +This specifies that \fIspLargestElement()\fR and \fIspRoundoff()\fR +should be compiled. These routines are used to check the stability +(and hence the quality of the pivoting) of the factorization by +computing a bound on the size of the element is the matrix $bold E ~=~ +bold A - bold LU$. If this bound is very high after applying +\fIspOrderAndFactor()\fR, then the pivot threshold should be raised. +If the bound increases greatly after using \fIspFactor()\fR, then the +matrix should probably be reordered. +.KE +.sp 0.6v +.KS +.LP +CONDITION +.LP +This specifies that \fIspCondition()\fR and \fIspNorm()\fR, the code +that computes a good estimate of the condition number of the matrix, +should be compiled. +.KE +.sp 0.6v +.KS +.LP +PSEUDOCONDITION +.LP +This specifies that \fIspPseudoCondition()\fR, the code that computes +a crude and easily fooled indicator of the ill-conditioning in the matrix, +should be compiled. +.KE +.sp 0.6v +.KS +.LP +MULTIPLICATION +.LP +This specifies that \fIspMultiply()\fR and perhaps \fIspMultTransposed()\fR, +the routines that multiply an unfactored matrix by a vector, should be compiled. +.KE +.sp 0.6v +.KS +.LP +FORTRAN +.LP +This specifies that the FORTRAN interface to Sparse1.3 should be +compiled. The ARRAY_OFFSET option should be set to NO when interfacing +to FORTRAN programs. +.KE +.sp 0.6v +.KS +.LP +DEBUG +.LP +This specifies that additional error checking should be compiled. +The type of errors checked are those that are common when the +matrix routines are first integrated into a user's program. Once +the routines have been integrated in and are running smoothly, this +option should be turned off. With DEBUG enabled, \fISparse\fP is +very defensive. If a \fISparse\fP routine is called improperly, +a message will be printed describing the file and line number where +the error was found and execution is aborted. One thing that \fISparse\fR +is particularly picky about is calling certain functions after an error +has occurred. If an error has occurred, do not call \fIspMNA_Preorder()\fR, +\fIspScale()\fR, \fIspOrderAndFactor()\fR, \fIspFactor()\fR, +\fIspSolve()\fR, or \fIspSolveTransposed()\fR until the error has been +cleared by \fIspClear()\fR or \fIspInitialize()\fR. +.KE +.sp 0.6v +.KS +.LP +spCOMPATIBILITY +.LP +This specifies that Sparse1.3 should be configured to be upward +compatible from Sparse1.2. This option is not suggested for use +in new software. Sparse1.3, when configured to be compatible with +Sparse1.2, is not completely compatible. In particular, if +recompiling the calling program, it is necessary to change the names +of the \fISparse1.2\fR include files. This option will go away on any future +version of \fISparse\fR. +.KE +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Sparse Constants" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Sparse Constants +.XE +.PP +These constants are used throughout the sparse matrix routines. They +should be set to suit the type of matrices being solved. +.sp 0.6v +.KS +.LP +DEFAULT_THRESHOLD +.LP +The threshold used if the user enters an invalid threshold. Also the +threshold used by \fIspFactor()\fP when calling +\fIspOrderAndFactor()\fP. The default threshold should not be less +than or equal to zero nor larger than one. +.KE +.sp 0.6v +.KS +.LP +DIAG_PIVOTING_AS_DEFAULT +.LP +This indicates whether \fIspOrderAndFactor()\fP should use diagonal +pivoting as default. This issue only arises when \fIspOrderAndFactor()\fP +is called from \fIspFactor()\fP. +.KE +.sp 0.6v +.KS +.LP +SPACE_FOR_ELEMENTS +.LP +This number multiplied by the size of the matrix equals the number +of elements for which memory is initially allocated in \fIspCreate()\fP. +.KE +.sp 0.6v +.KS +.LP +SPACE_FOR_FILL_INS +.LP +This number multiplied by the size of the matrix equals the number +of elements for which memory is initially allocated and specifically +reserved for fill-ins in \fIspCreate()\fP. +.KE +.sp 0.6v +.KS +.LP +ELEMENTS_PER_ALLOCATION +.LP +The number of matrix elements requested from the \fImalloc\fP utility +on each call to it. Setting this value greater than one reduces the +amount of overhead spent in this system call. +.KE +.sp 0.6v +.KS +.LP +MINIMUM_ALLOCATED_SIZE +.LP +The minimum allocated size of a matrix. Note that this does not +limit the minimum size of a matrix. This just prevents having to +resize a matrix many times if the matrix is expandable, large and +allocated with an estimated size of zero. This number must not +be less than one. +.KE +.sp 0.6v +.KS +.LP +EXPANSION_FACTOR +.LP +The minimum increase in the allocated size of the matrix when it is +expanded. This number must be greater than one but shouldn't be much +larger than two. +.KE +.sp 0.6v +.KS +.LP +MAX_MARKOWITZ_TIES +.LP +This number is used for two slightly different things, both of which +relate to the search for the best pivot. First, it is the maximum +number of elements that are Markowitz tied that will be sifted +through when trying to find the one that is numerically the best. +Second, it creates an upper bound on how large a Markowitz product +can be before it eliminates the possibility of early termination +of the pivot search. In other words, if the product of the smallest +Markowitz product yet found and TIES_MULTIPLIER is greater than +MAX_MARKOWITZ_TIES, then no early termination takes place. Set +MAX_MARKOWITZ_TIES to some small value if no early termination of +the pivot search is desired. An array of spREALs is allocated of size +MAX_MARKOWITZ_TIES so it must be positive and shouldn't be too large. +.KE +.sp 0.6v +.KS +.LP +TIES_MULTIPLIER +.LP +Specifies the number of Markowitz ties that are allowed to occur before +the search for the pivot is terminated early. Set to some large value +if no early termination of the pivot search is desired. This number is +multiplied by the Markowitz product to determine how many ties are +required for early termination. This means that more elements will be +searched before early termination if a large number of fill-ins could +be created by accepting what is currently considered the best choice +for the pivot. Setting this number to zero effectively eliminates all +pivoting, which should be avoided. This number must be positive. +.KE +.sp 0.6v +.KS +.LP +DEFAULT_PARTITION +.LP +Which partition mode is used by \fIspPartition()\fR as default. +Possibilities include: +.RS +.XP +spDIRECT_PARTITION \(em each row used direct addressing, best for +a few relatively dense matrices. +.XP +spINDIRECT_PARTITION \(em each row used indirect addressing, best +for a few very sparse matrices. +.XP +spAUTO_PARTITION \(em direct or indirect addressing is chosen on +a row-by-row basis, carries a large overhead, but speeds up +both dense and sparse matrices, best if there is a large +number of matrices that can use the same ordering. +.RE +.KE +.sp 0.6v +.KS +.LP +PRINTER_WIDTH +.LP +Gives the number of characters printable in one page width. +Set to 80 for terminals and 132 for line printers. +.KE +.sp 2 +.ne 1.5i +.RT +.LG +.B "\n(sc.\n+(ss: Machine Constants" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Machine Constants +.XE +.LP +These numbers +.UL must +be updated when the program is ported to a new machine. +.sp 0.6v +.KS +.LP +MACHINE_RESOLUTION +.LP +This is the smallest positive real double precision +number $epsilon$ such that $ 1 ~ + ~ epsilon ~ != ~ 1 $. +.KE +.sp 0.6v +.KS +.LP +LARGEST_REAL +.LP +The largest positive real number representable by a \fBdouble\fR. +.KE +.sp 0.6v +.KS +.LP +SMALLEST_REAL +.LP +The smallest positive real number representable by a \fBdouble\fR. +.KE +.sp 0.6v +.KS +.LP +LARGEST_SHORT_INTEGER +.LP +The largest positive integer representable by a \fBshort\fR. +.KE +.sp 0.6v +.KS +.LP +LARGEST_LONG_INTEGER +.LP +The largest positive integer representable by a \fBlong\fR. +.KE +.bp +.LP +.nr ss 0 1 \" Reset subsection +.RT +.ne 1.5i +.LG +.B "\n+(sc: EXPORTS" +.NL +.XS \n% \" Save section title for table of contents +\n(sc: Exports +.XE + +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Error Codes" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Error Codes +.XE +.PP +Errors are indicated with a integer error code. Macros definitions for +these error codes are set up and placed in the file \fBspMatrix.h\fP. +They may be imported into the users program to give readable +names to the possible matrix errors. The possible error codes and +there corresponding macros are: +.sp 0.25i +.KS +.LP +spOKAY \(em 0 +.LP +No error has occurred. +.KE +.KS +.LP +spSMALL_PIVOT \(em 1 +.LP +When reordering the matrix, no element was found which satisfies the +absolute threshold criteria. The largest element in the matrix was chosen +as pivot. Nonfatal. +.KE +.KS +.LP +spZERO_DIAG \(em 2 +.LP +Fatal error. A zero was encountered on the diagonal of the matrix. This +does not necessarily imply that the matrix is singular. When this error +occurs, the matrix should be reconstructed and factored using +\fIspOrderAndFactor()\fR. +.KE +.KS +.LP +spSINGULAR \(em 3 +.LP +Fatal error. Matrix is singular, so no unique solution exists. +.KE +.KS +.LP +spNO_MEMORY \(em 4 +.LP +Fatal error. Indicates that not enough memory is available from the system +to handle the matrix. +.KE +.KS +.LP +spPANIC \(em 5 +.LP +Fatal error indicating that the routines are being asked to do +something nonsensical or something they are not prepared for. This +error may occur when the matrix is specified to be real and the +routines are not compiled for real matrices, or when the matrix is +specified to be complex and the routines are not compiled to handle +complex matrices. +.KE +.KS +.LP +spFATAL \(em 2 +.LP +Not an error flag, but rather the dividing line between fatal errors +and warnings. +.KE +.sp 2 +.RT +.ne 1i +.LG +.B "\n(sc.\n+(ss: Data Structures" +.NL +.XS \n% \" Save section title for table of contents + \n(sc.\n(ss: Data Structures +.XE +.PP +There is only one data structure that may need to be imported from +\fISparse\fR by the user. This data structure is used to hold pointers +to four related elements in matrix. It is used in conjunction with the +routines +.nf + \fIspGetAdmittance()\fP + \fIspGetOnes()\fP + \fIspGetQuad()\fP +.LP +\fIspGetAdmittance()\fP, \fIspGetOnes()\fP, and \fIspGetQuad()\fP stuff +the structure which is later used by the \fIspADD_QUAD()\fP macros. It +is also possible for the user to collect four pointers returned by +\fIspGetElement()\fP and stuff them into the template. The +\fIspADD_QUAD()\fP macros add a value into \fIElement1\fP and +\fIElement2\fP and subtract the value from \fIElement3\fP and +\fIElement4\fP. The structure is: +.KS +.sp 0.25i +.nf +\fBstruct\fP \fIspTemplate\fP +{ spREAL *\fIElement1\fP; + spREAL *\fIElement2\fP; + spREAL *\fIElement3Negated\fP; + spREAL *\fIElement4Negated\fP; +}; +.KE +.bp +.LP +.nr ss 0 1 \" Reset subsection +.RT +.ne 1.5i +.LG +.B "\n+(sc: FORTRAN COMPATIBILITY" +.NL +.XS \n% \" Save section title for table of contents +\n(sc: FORTRAN Compatibility +.XE +.PP +The \fISparse1.3\fR package contains routines that interface to a +calling program written in FORTRAN. Almost every externally available +\fISparse1.3\fR routine has a counterpart defined with the same name +except that the `sp' prefix is changed to `sf'. The +\fIspADD_ELEMENT()\fR and \fIspADD_QUAD()\fR macros are also replaced +with the \fIsfAdd1()\fR and \fIsfAdd4()\fR functions. +.PP +Any interface between two languages is going to have portibility +problems, this one is no exception. To ease porting the FORTRAN +interface file to different operating systems, the names of the +interface functions can be easily redefined (search for `Routine +Renaming' in \fBspFortran.c\fR). When interfacing to a FORTRAN program, +the FORTRAN option should be set to YES and the ARRAY_OFFSET option +should be set to NO (see \fBspConfig.h\fR). For details on the return +value and argument list of a particular interface routine, see the +file \fBspFortran.c\fR. +.PP +A simple example of a FORTRAN program that calls \fISparse\fR follows. + +.KS +.B Example: +.RS +.nf + integer matrix, error, sfCreate, sfGetElement, spFactor + integer element(10) + double precision rhs(4), solution(4) +c +c create matrix + matrix = sfCreate(4,0,error) +c +c reserve elements + element(1) = sfGetElement(matrix,1,1) + element(2) = sfGetElement(matrix,1,2) + element(3) = sfGetElement(matrix,2,1) + element(4) = sfGetElement(matrix,2,2) + element(5) = sfGetElement(matrix,2,3) + element(6) = sfGetElement(matrix,3,2) + element(7) = sfGetElement(matrix,3,3) + element(8) = sfGetElement(matrix,3,4) + element(9) = sfGetElement(matrix,4,3) + element(10) = sfGetElement(matrix,4,4) +c +c clear matrix + call sfClear(matrix) +c +c load matrix + call sfAdd1Real(element(1), 2d0) + call sfAdd1Real(element(2), \-1d0) + call sfAdd1Real(element(3), \-1d0) + call sfAdd1Real(element(4), 3d0) + call sfAdd1Real(element(5), \-1d0) + call sfAdd1Real(element(6), \-1d0) + call sfAdd1Real(element(7), 3d0) + call sfAdd1Real(element(8), \-1d0) + call sfAdd1Real(element(9), \-1d0) + call sfAdd1Real(element(10), 3d0) + call sfPrint(matrix, .false., .false., .true.) + rhs(1) = 34d0 + rhs(2) = 0d0 + rhs(3) = 0d0 + rhs(4) = 0d0 +c +c factor matrix + error = sfFactor(matrix) +c +c solve matrix + call sfSolve(matrix, rhs, solution) + write (6, 10) solution(1), solution(2), solution(3), solution(4) + 10 format (f 10.2) + end +.fi +.KE +.RE +.bp +.LP +.nr ss 0 1 \" Reset subsection +.RT +.ne 1.5i +.LG +.B "\n+(sc: SPARSE TEST PROGRAM" +.NL +.XS \n% \" Save section title for table of contents +\n(sc: \fISparse\fR Test Program +.XE +.PP +The \fISparse\fR package includes a test program that is able to read +matrix equations from text files and print their solution along with +matrix statistics and timing information. The program can also generate +files containing stripped versions of the unfactored and factored matrix +suitable for plotting using standard plotting programs, such as the +\s-1UNIX\s+1 graph and plot commands. +.LP +The \fISparse\fR test program is invoked using the following syntax. +.ne 2.25i +.IP +\fBsparse\fR [\fIoptions\fR] [\fIfile1\fR] [\fIfile2\fR] ... +.TS +l +l lw(4.5i). +Options: +\fB\-s\fR T{ +Print solution only. +T} +\fB\-r\fI x\fR T{ +Use \fIx\fR as relative threshold. +T} +\fB\-a\fI x\fR T{ +Use \fIx\fR as absolute threshold. +T} +\fB\-n\fI n\fR T{ +Print first \fIn\fR terms of solution vector. +T} +\fB\-i\fI n\fR T{ +Repeat build/factor/solve \fIn\fR times for better timing results. +T} +\fB\-b\fI n\fR T{ +Use column \fIn\fR of matrix as right-hand side vector. +T} +\fB\-p\fR T{ +Create plot files ``\fIfilename\fB.bef\fR'' and ``\fIfilename\fB.aft\fR''. +T} +\fB\-c\fR T{ +Use complete (as opposed to diagonal) pivoting. +T} +\fB\-x\fR T{ +Treat real matrix as complex with imaginary part zero. +T} +\fB\-t\fR T{ +Solve transposed system. +T} +\fB\-u\fR T{ +Print usage message. +T} +.TE +.LP +The presence of certain options is dependent on whether the appropriate +\fISparse\fR option has been enabled. +.LP +If no input files are specified, \fBsparse\fP reads from the standard +input. The syntax of the input file is as follows. The matrix begins +with one line of arbitrary text that acts as the label, followed by a +line with the integer size of the matrix and either the \fBreal\fR or +\fBcomplex\fR keywords. After the header is an arbitrary number of +lines that describe the structural nonzeros in the matrix. These lines +have the form \fIrow column data\fP, where \fIrow\fR and \fIcolumn\fR +are integers and \fIdata\fP is either one real number for real matrices +or a real/imaginary pair of numbers for complex matrices. Only one +structural nonzero is described per line and the section ends when +either \fIrow\fR or \fIcolumn\fR are zero. Following the matrix, an +optional right-hand side vector can be described. The vector is given +one element per line, the number of element must equal the size of the +matrix. Only one matrix and one vector are allowed per file, and the +vector, if given, must follow the matrix. + +.KS +.B Example: +.RS +.nf +mat0 \(em Simple matrix. +4 real +1 1 2.0 +1 2 -1.0 +2 1 -1.0 +2 2 3.0 +2 3 -1.0 +3 2 -1.0 +3 3 3.0 +3 4 -1.0 +4 3 -1.0 +4 4 3.0 +0 0 0.0 +34.0 +0.0 +0.0 +0.0 +.fi +.KE +.RE +.bp +.LP +.nr ss 0 1 \" Reset subsection +.RT +.ne 1.5i +.LG +.B "\n+(sc: SPARSE FILES" +.NL +.XS \n% \" Save section title for table of contents +\n(sc: \fISparse\fR Files +.XE +.PP +The following is a list of the files contained in the \fISparse\fR +package and a brief description of their contents. Of the files, only +\fBspConfig.h\fP is expected to be modified by the user and only +\fBspMatrix.h\fP need be imported into the program that calls \fISparse\fR. + +.KS +.LP +\fBspAlloc.c\fR +.LP +This file contains the routines for allocating and deallocating objects +associated with the matrices, including the matrices themselves. +.XP +\(bu User accessible functions contained in this module: +.nf +.I +spCreate() +spDestroy() +spError() +spWhereSingular() +spGetSize() +spSetReal() +spSetComplex() +spFillinCount() +spElementCount() +.R +.KE + +.KS +.LP +\fBspBuild.c\fR +.LP +This file contains the routines for clearing and loading the matrix. +.XP +\(bu User accessible functions contained in this module: +.nf +.I +spClear() +spGetAdmittance() +spGetElement() +spGetInitInfo() +spGetOnes() +spGetQuad() +spInitialize() +spInstallInitInfo() +.R +.KE + +.KS +.LP +\fBspCompat.c\fR +.LP +This file contains the routines for making \fISparse1.3\fR upward compatible +from \fISparse1.2\fP. These routines are not suggested for use in new +software. These routines will not be available in future versions of +\fISparse\fR. +.XP +\(bu User accessible functions contained in this module: +.nf +.I +AddAdmittanceToMatrix() +AddComplexElementToMatrix() +AddComplexQuadElementToMatrix() +AddElementToMatrix() +AddImagElementToMatrix() +AddImagQuadElementToMatrix() +AddOnesToMatrix() +AddQuadToMatrix() +AddRealElementToMatrix() +AddRealQuadElementToMatrix() +CleanMatrix() +ClearMatrix() +ClearMatrixError() +CreateMatrix() +DecomposeMatrix() +DeleteRowAndColFromMatrix() +DestroyMatrix() +Determinant() +GetMatrixSize() +MatrixElementCount() +MatrixError() +MatrixFillinCount() +MatrixRoundoffError() +MultiplyMatrix() +OrderAndDecomposeMatrix() +OutputMatrixToFile() +PreorderForModifiedNodal() +PrintMatrix() +ScaleMatrix() +SetMatrixComplex() +SetMatrixReal() +SolveMatrix() +SolveTransposedMatrix() +.R +.KE + +.KS +.LP +\fBspConfig.h\fR +.LP +This file contains the options that are used to customize the package. +For example, it is possible to specify whether only real or complex +systems of equations are to be solved. Also included in this file are +the various constants used by the \fISparse\fR package, such as the +amount of memory initially allocated for each matrix and the largest +real number represented by the machine. The user is expected to modify +this file to maximize the performance of the routines with his/her +matrices. +.KE + +.KS +.LP +\fBspDefs.h\fR +.LP +This module contains common data structure definitions and macros for +the sparse matrix routines. These definitions are meant to remain +hidden from the program that calls the sparse matrix routines. +.KE + +.KS +.LP +\fBspDoc\fR +.LP +This reference manual. \fBspDoc\fP contains the manual in a form +that is readable on-line and \fBspDoc.ms\fP contains the manual in a +form that is suitable for input into the text formatting program +\fItroff\fP using the -ms macros. +.KE + +.KS +.LP +\fBspFactor.c\fR +.LP +This file contains the routines for factoring matrices into LU form. +.XP +\(bu User accessible functions contained in this module: +.nf +.I +spFactor() +spOrderAndFactor() +spPartition() +.R +.KE + +.KS +.LP +\fBspFortran.c\fR +.LP +This file contains the routines for interfacing \fISparse1.3\fR to a +program written in FORTRAN. The function and argument lists of the +routines in this file are almost identical to their C equivalents +except that they are suitable for calling from a FORTRAN program. +The names of these routines use the `sf' prefix to distinguish them +from their C counterparts. +.XP +\(bu User accessible functions contained in this module: +.nf +.I +sfAdd1Complex() +sfAdd1Imag() +sfAdd1Real() +sfAdd4Complex() +sfAdd4Imag() +sfAdd4Real() +sfClear() +sfCondition() +sfCreate() +sfDeleteRowAndCol() +sfDestroy() +sfDeterminant() +sfElementCount() +sfError() +sfFactor() +sfFileMatrix() +sfFileStats() +sfFileVector() +sfFillinCount() +sfGetAdmittance() +sfGetElement() +sfGetOnes() +sfGetQuad() +sfGetSize() +sfLargestElement() +sfMNA_Preorder() +sfMultTransposed() +sfMultiply() +sfNorm() +sfOrderAndFactor() +sfPartition() +sfPrint() +sfPseudoCondition() +sfRoundoff() +sfScale() +sfSetComplex() +sfSetReal() +sfSolve() +sfSolveTransposed() +sfStripFills() +sfWhereSingular() +.R +.KE + +.KS +.LP +\fBspMatrix.h\fR +.NL +.LP +This file contains definitions that are useful to the calling program. +In particular, this file contains error keyword definitions, some macro +functions that are used to quickly enter data into the matrix, the +definition of a data structure that acts as a template for entering +admittances into the matrix, and the type declarations of the various +\fISparse\fR functions. +.KE + +.KS +.LP +\fBspOutput.c\fR +.LP +This file contains the output-to-file and output-to-screen routines for +the matrix package. They are capable of outputting the matrix in either a +form readable by people or a form readable by the \fISparse\fR test program. +.XP +\(bu User accessible functions contained in this module: +.nf +.I +spFileMatrix() +spFileStats() +spFileVector() +spPrint() +.R +.KE + +.KS +.LP +\fBspRevision\fR +.LP +The history of updates for the program. This file also includes ordering +information for the \fISparse\fR package. +.KE + +.KS +.LP +\fBspSolve.c\fR +.LP +This module contains the forward and backward substitution routines. +.XP +\(bu User accessible functions contained in this module: +.nf +.I +spSolve() +spSolveTransposed() +.R +.KE + +.KS +.LP +\fBspTest.c\fR +.LP +This module contains a test program for the sparse matrix routines. +It is able to read matrices from files and solve them. Because of +the large number of options and capabilities built into \fISparse\fR, +it is impossible to have one test routine thoroughly exercise +\fISparse\fR. Thus, emphasis is on exercising as many capabilities as +is reasonable while also providing a useful tool. +.KE + +.KS +.LP +\fBspUtil.c\fR +.LP +This module contains various optional utility routines. +.XP +\(bu User accessible functions contained in this module: +.nf +.I +spCondition() +spDeleteRowAndCol() +spDeterminant() +spLargestElement() +spMNA_Preorder() +spMultiply() +spMultTransposed() +spNorm() +spPseudoCondition() +spRoundoff() +spScale() +spStripFills() +.R +.KE + +.KS +.LP +\fBMakefile\fR +.LP +This file is used in conjunction with the UNIX program \fBmake\fR to +compile the matrix routines and their test program. +.KE + +.KS +.LP +.B make.com +.LP +This file is used to automatically compile \fISparse\fR under the VMS +operating system. It needs to modified slightly before being used, see +the installation notes. +.KE +.bp +.LP +.LG +.B "REFERENCES" +.NL +.XS \n% +References +.XE +.KS +.IP [duff86] 15 +I. S. Duff, A. M. Erisman, J. K. Reid. +\fIDirect Methods for Sparse Matrices\fP. +Oxford University Press, 1986. +.KE +.KS +.IP [golub86] 15 +G. H. Golub, C. F. V. Van Loan. +\fIMatrix Computations\fP. +The Johns Hopkins University Press, 1983. +.KE +.KS +.IP [kundert86] 15 +Kenneth S. Kundert. +Sparse matrix techniques. +In \fICircuit Analysis, Simulation and Design\fP, Albert Ruehli +(editor). North-Holland, 1986. +.KE +.KS +.IP [strang80] 15 +Gilbert Strang. +\fILinear Algebra and Its Applications\fP. +Academic Press, 1980. +.KE +.sp 2 +.LG +.B Acknowledgements +.NL +.ad +.PP +We would like to acknowledge and thank the those people that +contributed ideas that were incorporated into \fISparse\fP. In +particular, Jacob White, Kartikeya Mayaram, Don Webber, +Tom Quarles, Howard Ko and Beresford Parlett. + +.ds CH \" stop printing page number +.bp +.PX + diff --git a/sis/linsolv/spAllocate.c b/sis/linsolv/spAllocate.c new file mode 100644 index 0000000..5ae2b71 --- /dev/null +++ b/sis/linsolv/spAllocate.c @@ -0,0 +1,882 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/linsolv/spAllocate.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:04 $ + * + */ +/* + * MATRIX ALLOCATION MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains the allocation and deallocation routines for the + * sparse matrix routines. + * + * >>> User accessible functions contained in this file: + * spCreate + * spDestroy + * spError + * spWhereSingular + * spGetSize + * spSetReal + * spSetComplex + * spFillinCount + * spElementCount + * + * >>> Other functions contained in this file: + * spcGetElement + * InitializeElementBlocks + * spcGetFillin + * RecordAllocation + * AllocateBlockOfAllocationList + * EnlargeMatrix + * ExpandTranslationArrays + */ + +static void InitializeElementBlocks(); +static void RecordAllocation(); +static void AllocateBlockOfAllocationList(); + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifndef lint +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header: /users/pchong/CVS/sis/sis/linsolv/spAllocate.c,v 1.1.1.1 2004/02/07 10:15:04 pchong Exp $"; +#endif + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spConfig.h" +#include "spMatrix.h" +#include "spDefs.h" + + + + + + +/* + * MATRIX ALLOCATION + * + * Allocates and initializes the data structures associated with a matrix. + * + * >>> Returned: + * A pointer to the matrix is returned cast into the form of a pointer to + * a character. This pointer is then passed and used by the other matrix + * routines to refer to a particular matrix. If an error occurs, the NULL + * pointer is returned. + * + * >>> Arguments: + * Size <input> (int) + * Size of matrix or estimate of size of matrix if matrix is EXPANDABLE. + * Complex <input> (int) + * Type of matrix. If Complex is 0 then the matrix is real, otherwise + * the matrix will be complex. Note that if the routines are not set up + * to handle the type of matrix requested, then a spPANIC error will occur. + * Further note that if a matrix will be both real and complex, it must + * be specified here as being complex. + * pError <output> (int *) + * Returns error flag, needed because function spError() will not work + * correctly if spCreate() returns NULL. + * + * >>> Local variables: + * AllocatedSize (int) + * The size of the matrix being allocated. + * Matrix (MatrixPtr) + * A pointer to the matrix frame being created. + * + * >>> Possible errors: + * spNO_MEMORY + * spPANIC + * Error is cleared in this routine. + */ + +char * +spCreate( Size, Complex, pError ) + +int Size, *pError; +BOOLEAN Complex; +{ +register unsigned SizePlusOne; +register MatrixPtr Matrix; +register int I; +int AllocatedSize; + +/* Begin `spCreate'. */ +/* Clear error flag. */ + *pError = spOKAY; + +/* Test for valid size. */ + if ((Size < 0) OR (Size == 0 AND NOT EXPANDABLE)) + { *pError = spPANIC; + return NULL; + } + +/* Test for valid type. */ +#if NOT spCOMPLEX + if (Complex) + { *pError = spPANIC; + return NULL; + } +#endif +#if NOT REAL + if (NOT Complex) + { *pError = spPANIC; + return NULL; + } +#endif + +/* Create Matrix. */ + AllocatedSize = MAX( Size, MINIMUM_ALLOCATED_SIZE ); + SizePlusOne = (unsigned)(AllocatedSize + 1); + + if ((Matrix = ALLOC(struct MatrixFrame, 1)) == NULL) + { *pError = spNO_MEMORY; + return NULL; + } + +/* Initialize matrix */ + Matrix->ID = SPARSE_ID; + Matrix->Complex = Complex; + Matrix->PreviousMatrixWasComplex = Complex; + Matrix->Factored = NO; + Matrix->Elements = 0; + Matrix->Error = *pError; + Matrix->Fillins = 0; + Matrix->Reordered = NO; + Matrix->NeedsOrdering = YES; + Matrix->NumberOfInterchangesIsOdd = NO; + Matrix->Partitioned = NO; + Matrix->RowsLinked = NO; + Matrix->InternalVectorsAllocated = NO; + Matrix->SingularCol = 0; + Matrix->SingularRow = 0; + Matrix->Size = Size; + Matrix->AllocatedSize = AllocatedSize; + Matrix->ExtSize = Size; + Matrix->AllocatedExtSize = AllocatedSize; + Matrix->CurrentSize = 0; + Matrix->ExtToIntColMap = NULL; + Matrix->ExtToIntRowMap = NULL; + Matrix->IntToExtColMap = NULL; + Matrix->IntToExtRowMap = NULL; + Matrix->MarkowitzRow = NULL; + Matrix->MarkowitzCol = NULL; + Matrix->MarkowitzProd = NULL; + Matrix->DoCmplxDirect = NULL; + Matrix->DoRealDirect = NULL; + Matrix->Intermediate = NULL; + Matrix->RelThreshold = DEFAULT_THRESHOLD; + Matrix->AbsThreshold = 0.0; + + Matrix->TopOfAllocationList = NULL; + Matrix->RecordsRemaining = 0; + Matrix->ElementsRemaining = 0; + Matrix->FillinsRemaining = 0; + + RecordAllocation( Matrix, (char *)Matrix ); + if (Matrix->Error == spNO_MEMORY) goto MemoryError; + +/* Take out the trash. */ + Matrix->TrashCan.Real = 0.0; +#if spCOMPLEX + Matrix->TrashCan.Imag = 0.0; +#endif + Matrix->TrashCan.Row = 0; + Matrix->TrashCan.Col = 0; + Matrix->TrashCan.NextInRow = NULL; + Matrix->TrashCan.NextInCol = NULL; +#if INITIALIZE + Matrix->TrashCan.pInitInfo = NULL; +#endif + +/* Allocate space in memory for Diag pointer vector. */ + CALLOC( Matrix->Diag, ElementPtr, SizePlusOne); + if (Matrix->Diag == NULL) + goto MemoryError; + +/* Allocate space in memory for FirstInCol pointer vector. */ + CALLOC( Matrix->FirstInCol, ElementPtr, SizePlusOne); + if (Matrix->FirstInCol == NULL) + goto MemoryError; + +/* Allocate space in memory for FirstInRow pointer vector. */ + CALLOC( Matrix->FirstInRow, ElementPtr, SizePlusOne); + if (Matrix->FirstInRow == NULL) + goto MemoryError; + +/* Allocate space in memory for IntToExtColMap vector. */ + if (( Matrix->IntToExtColMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Allocate space in memory for IntToExtRowMap vector. */ + if (( Matrix->IntToExtRowMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Initialize MapIntToExt vectors. */ + for (I = 1; I <= AllocatedSize; I++) + { Matrix->IntToExtRowMap[I] = I; + Matrix->IntToExtColMap[I] = I; + } + +#if TRANSLATE +/* Allocate space in memory for ExtToIntColMap vector. */ + if (( Matrix->ExtToIntColMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Allocate space in memory for ExtToIntRowMap vector. */ + if (( Matrix->ExtToIntRowMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Initialize MapExtToInt vectors. */ + for (I = 1; I <= AllocatedSize; I++) + { Matrix->ExtToIntColMap[I] = -1; + Matrix->ExtToIntRowMap[I] = -1; + } + Matrix->ExtToIntColMap[0] = 0; + Matrix->ExtToIntRowMap[0] = 0; +#endif + +/* Allocate space for fill-ins and initial set of elements. */ + InitializeElementBlocks( Matrix, SPACE_FOR_ELEMENTS*AllocatedSize, + SPACE_FOR_FILL_INS*AllocatedSize ); + if (Matrix->Error == spNO_MEMORY) + goto MemoryError; + + return (char *)Matrix; + +MemoryError: + +/* Deallocate matrix and return no pointer to matrix if there is not enough + memory. */ + *pError = spNO_MEMORY; + spDestroy( (char *)Matrix); + return NULL; +} + + + + + + + + + +/* + * ELEMENT ALLOCATION + * + * This routine allocates space for matrix elements. It requests large blocks + * of storage from the system and doles out individual elements as required. + * This technique, as opposed to allocating elements individually, tends to + * speed the allocation process. + * + * >>> Returned: + * A pointer to an element. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * + * >>> Local variables: + * pElement (ElementPtr) + * A pointer to the first element in the group of elements being allocated. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +ElementPtr +spcGetElement( Matrix ) + +MatrixPtr Matrix; +{ +ElementPtr pElement; + +/* Begin `spcGetElement'. */ + +/* Allocate block of MatrixElements if necessary. */ + if (Matrix->ElementsRemaining == 0) + { pElement = ALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION); + RecordAllocation( Matrix, (char *)pElement ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->ElementsRemaining = ELEMENTS_PER_ALLOCATION; + Matrix->NextAvailElement = pElement; + } + +/* Update Element counter and return pointer to Element. */ + Matrix->ElementsRemaining--; + return Matrix->NextAvailElement++; + +} + + + + + + + + +/* + * ELEMENT ALLOCATION INITIALIZATION + * + * This routine allocates space for matrix fill-ins and an initial set of + * elements. Besides being faster than allocating space for elements one + * at a time, it tends to keep the fill-ins physically close to the other + * matrix elements in the computer memory. This keeps virtual memory paging + * to a minimum. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * InitialNumberOfElements <input> (int) + * This number is used as the size of the block of memory, in + * MatrixElements, reserved for elements. If more than this number of + * elements are generated, then more space is allocated later. + * NumberOfFillinsExpected <input> (int) + * This number is used as the size of the block of memory, in + * MatrixElements, reserved for fill-ins. If more than this number of + * fill-ins are generated, then more space is allocated, but they may + * not be physically close in computer's memory. + * + * >>> Local variables: + * pElement (ElementPtr) + * A pointer to the first element in the group of elements being allocated. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +InitializeElementBlocks( Matrix, InitialNumberOfElements, + NumberOfFillinsExpected ) + +MatrixPtr Matrix; +int InitialNumberOfElements, NumberOfFillinsExpected; +{ +ElementPtr pElement; + +/* Begin `InitializeElementBlocks'. */ + +/* Allocate block of MatrixElements for elements. */ + pElement = ALLOC(struct MatrixElement, InitialNumberOfElements); + RecordAllocation( Matrix, (char *)pElement ); + if (Matrix->Error == spNO_MEMORY) return; + Matrix->ElementsRemaining = InitialNumberOfElements; + Matrix->NextAvailElement = pElement; + +/* Allocate block of MatrixElements for fill-ins. */ + pElement = ALLOC(struct MatrixElement, NumberOfFillinsExpected); + RecordAllocation( Matrix, (char *)pElement ); + if (Matrix->Error == spNO_MEMORY) return; + Matrix->FillinsRemaining = NumberOfFillinsExpected; + Matrix->NextAvailFillin = pElement; + +/* Allocate a fill-in list structure. */ + Matrix->FirstFillinListNode = ALLOC(struct FillinListNodeStruct,1); + RecordAllocation( Matrix, (char *)Matrix->FirstFillinListNode ); + if (Matrix->Error == spNO_MEMORY) return; + Matrix->LastFillinListNode = Matrix->FirstFillinListNode; + + Matrix->FirstFillinListNode->pFillinList = pElement; + Matrix->FirstFillinListNode->NumberOfFillinsInList =NumberOfFillinsExpected; + Matrix->FirstFillinListNode->Next = NULL; + + return; +} + + + + + + + + + + +/* + * FILL-IN ALLOCATION + * + * This routine allocates space for matrix fill-ins. It requests large blocks + * of storage from the system and doles out individual elements as required. + * This technique, as opposed to allocating elements individually, tends to + * speed the allocation process. + * + * >>> Returned: + * A pointer to the fill-in. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +ElementPtr +spcGetFillin( Matrix ) + +MatrixPtr Matrix; +{ +struct FillinListNodeStruct *pListNode; +ElementPtr pFillins; + +/* Begin `spcGetFillin'. */ + +#if NOT STRIP OR LINT + if (Matrix->FillinsRemaining == 0) + return spcGetElement( Matrix ); +#endif +#if STRIP OR LINT + + if (Matrix->FillinsRemaining == 0) + { pListNode = Matrix->LastFillinListNode; + +/* First see if there are any stripped fill-ins left. */ + if (pListNode->Next != NULL) + { Matrix->LastFillinListNode = pListNode = pListNode->Next; + Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList; + Matrix->NextAvailFillin = pListNode->pFillinList; + } + else + { +/* Allocate block of fill-ins. */ + pFillins = ALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION); + RecordAllocation( Matrix, (char *)pFillins ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->FillinsRemaining = ELEMENTS_PER_ALLOCATION; + Matrix->NextAvailFillin = pFillins; + +/* Allocate a fill-in list structure. */ + pListNode->Next = ALLOC(struct FillinListNodeStruct,1); + RecordAllocation( Matrix, (char *)pListNode->Next ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->LastFillinListNode = pListNode = pListNode->Next; + + pListNode->pFillinList = pFillins; + pListNode->NumberOfFillinsInList = ELEMENTS_PER_ALLOCATION; + pListNode->Next = NULL; + } + } +#endif + +/* Update Fill-in counter and return pointer to Fill-in. */ + Matrix->FillinsRemaining--; + return Matrix->NextAvailFillin++; +} + + + + + + + + + +/* + * RECORD A MEMORY ALLOCATION + * + * This routine is used to record all memory allocations so that the memory + * can be freed later. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * AllocatedPtr <input> (char *) + * The pointer returned by malloc or calloc. These pointers are saved in + * a list so that they can be easily freed. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +RecordAllocation( Matrix, AllocatedPtr ) + +MatrixPtr Matrix; +char *AllocatedPtr; +{ +/* Begin `RecordAllocation'. */ +/* + * If Allocated pointer is NULL, assume that malloc returned a NULL pointer, + * which indicates a spNO_MEMORY error. + */ + if (AllocatedPtr == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* Allocate block of MatrixElements if necessary. */ + if (Matrix->RecordsRemaining == 0) + { AllocateBlockOfAllocationList( Matrix ); + if (Matrix->Error == spNO_MEMORY) + { FREE(AllocatedPtr); + return; + } + } + +/* Add Allocated pointer to Allocation List. */ + (++Matrix->TopOfAllocationList)->AllocatedPtr = AllocatedPtr; + Matrix->RecordsRemaining--; + return; + +} + + + + + + + + +/* + * ADD A BLOCK OF SLOTS TO ALLOCATION LIST + * + * This routine increases the size of the allocation list. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * + * >>> Local variables: + * ListPtr (AllocationListPtr) + * Pointer to the list that contains the pointers to segments of memory + * that were allocated by the operating system for the current matrix. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +AllocateBlockOfAllocationList( Matrix ) + +MatrixPtr Matrix; +{ +register int I; +register AllocationListPtr ListPtr; + +/* Begin `AllocateBlockOfAllocationList'. */ +/* Allocate block of records for allocation list. */ + ListPtr = ALLOC(struct AllocationRecord, (ELEMENTS_PER_ALLOCATION+1)); + if (ListPtr == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* String entries of allocation list into singly linked list. List is linked + such that any record points to the one before it. */ + + ListPtr->NextRecord = Matrix->TopOfAllocationList; + Matrix->TopOfAllocationList = ListPtr; + ListPtr += ELEMENTS_PER_ALLOCATION; + for (I = ELEMENTS_PER_ALLOCATION; I > 0; I--) + { ListPtr->NextRecord = ListPtr - 1; + ListPtr--; + } + +/* Record allocation of space for allocation list on allocation list. */ + Matrix->TopOfAllocationList->AllocatedPtr = (char *)ListPtr; + Matrix->RecordsRemaining = ELEMENTS_PER_ALLOCATION; + + return; +} + + + + + + + + +/* + * MATRIX DEALLOCATION + * + * Deallocates pointers and elements of Matrix. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to the matrix frame which is to be removed from memory. + * + * >>> Local variables: + * ListPtr (AllocationListPtr) + * Pointer into the linked list of pointers to allocated data structures. + * Points to pointer to structure to be freed. + * NextListPtr (AllocationListPtr) + * Pointer into the linked list of pointers to allocated data structures. + * Points to the next pointer to structure to be freed. This is needed + * because the data structure to be freed could include the current node + * in the allocation list. + */ + +void +spDestroy( eMatrix ) + +register char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register AllocationListPtr ListPtr, NextListPtr; + + +/* Begin `spDestroy'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +/* Deallocate the vectors that are located in the matrix frame. */ + FREE( Matrix->IntToExtColMap ); + FREE( Matrix->IntToExtRowMap ); + FREE( Matrix->ExtToIntColMap ); + FREE( Matrix->ExtToIntRowMap ); + FREE( Matrix->Diag ); + FREE( Matrix->FirstInRow ); + FREE( Matrix->FirstInCol ); + FREE( Matrix->MarkowitzRow ); + FREE( Matrix->MarkowitzCol ); + FREE( Matrix->MarkowitzProd ); + FREE( Matrix->DoCmplxDirect ); + FREE( Matrix->DoRealDirect ); + FREE( Matrix->Intermediate ); + +/* Sequentially step through the list of allocated pointers freeing pointers + * along the way. */ + ListPtr = Matrix->TopOfAllocationList; + while (ListPtr != NULL) + { NextListPtr = ListPtr->NextRecord; + FREE( ListPtr->AllocatedPtr ); + ListPtr = NextListPtr; + } + return; +} + + + + + + + +/* + * RETURN MATRIX ERROR STATUS + * + * This function is used to determine the error status of the given matrix. + * + * >>> Returned: + * The error status of the given matrix. + * + * >>> Arguments: + * eMatrix <input> (char *) + * The matrix for which the error status is desired. + */ + +int +spError( eMatrix ) + +char *eMatrix; +{ +/* Begin `spError'. */ + + if (eMatrix != NULL) + { ASSERT(((MatrixPtr)eMatrix)->ID == SPARSE_ID); + return ((MatrixPtr)eMatrix)->Error; + } + else return spNO_MEMORY; /* This error may actually be spPANIC, + * no way to tell. */ +} + + + + + + + + + +/* + * WHERE IS MATRIX SINGULAR + * + * This function returns the row and column number where the matrix was + * detected as singular or where a zero was detected on the diagonal. + * + * >>> Arguments: + * eMatrix <input> (char *) + * The matrix for which the error status is desired. + * pRow <output> (int *) + * The row number. + * pCol <output> (int *) + * The column number. + */ + +void +spWhereSingular( eMatrix, pRow, pCol ) + +char *eMatrix; +int *pRow, *pCol; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; + +/* Begin `spWhereSingular'. */ + ASSERT( IS_SPARSE( Matrix ) ); + + if (Matrix->Error == spSINGULAR OR Matrix->Error == spZERO_DIAG) + { *pRow = Matrix->SingularRow; + *pCol = Matrix->SingularCol; + } + else *pRow = *pCol = 0; + return; +} + + + + + + +/* + * MATRIX SIZE + * + * Returns the size of the matrix. Either the internal or external size of + * the matrix is returned. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to matrix. + * External <input> (BOOLEAN) + * If External is set true, the external size , i.e., the value of the + * largest external row or column number encountered is returned. + * Otherwise the true size of the matrix is returned. These two sizes + * may differ if the TRANSLATE option is set true. + */ + +int +spGetSize( eMatrix, External ) + +char *eMatrix; +BOOLEAN External; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; + +/* Begin `spGetSize'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +#if TRANSLATE + if (External) + return Matrix->ExtSize; + else + return Matrix->Size; +#else + return Matrix->Size; +#endif +} + + + + + + + + +/* + * SET MATRIX COMPLEX OR REAL + * + * Forces matrix to be either real or complex. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to matrix. + */ + +void +spSetReal( eMatrix ) + +char *eMatrix; +{ +/* Begin `spSetReal'. */ + + ASSERT( IS_SPARSE( (MatrixPtr)eMatrix ) AND REAL); + ((MatrixPtr)eMatrix)->Complex = NO; + return; +} + + +void +spSetComplex( eMatrix ) + +char *eMatrix; +{ +/* Begin `spSetComplex'. */ + + ASSERT( IS_SPARSE( (MatrixPtr)eMatrix ) AND spCOMPLEX); + ((MatrixPtr)eMatrix)->Complex = YES; + return; +} + + + + + + + + + +/* + * ELEMENT OR FILL-IN COUNT + * + * Two functions used to return simple statistics. Either the number + * of total elements, or the number of fill-ins can be returned. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to matrix. + */ + +int +spFillinCount( eMatrix ) + +char *eMatrix; +{ +/* Begin `spFillinCount'. */ + + ASSERT( IS_SPARSE( (MatrixPtr)eMatrix ) ); + return ((MatrixPtr)eMatrix)->Fillins; +} + + +int +spElementCount( eMatrix ) + +char *eMatrix; +{ +/* Begin `spElementCount'. */ + + ASSERT( IS_SPARSE( (MatrixPtr)eMatrix ) ); + return ((MatrixPtr)eMatrix)->Elements; +} diff --git a/sis/linsolv/spBuild.c b/sis/linsolv/spBuild.c new file mode 100644 index 0000000..fadb9eb --- /dev/null +++ b/sis/linsolv/spBuild.c @@ -0,0 +1,1177 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/linsolv/spBuild.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:04 $ + * + */ +/* + * MATRIX BUILD MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains the routines associated with clearing, loading and + * preprocessing the matrix for the sparse matrix routines. + * + * >>> User accessible functions contained in this file: + * spClear + * spGetElement + * spGetAdmittance + * spGetQuad + * spGetOnes + * spInstallInitInfo + * spGetInitInfo + * spInitialize + * + * >>> Other functions contained in this file: + * spcFindElementInCol + * Translate + * spcCreateElement + * spcLinkRows + * EnlargeMatrix + * ExpandTranslationArrays + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifndef lint +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header: /users/pchong/CVS/sis/sis/linsolv/spBuild.c,v 1.1.1.1 2004/02/07 10:15:04 pchong Exp $"; +#endif + + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spConfig.h" +#include "spMatrix.h" +#include "spDefs.h" + + + + + + +/* + * CLEAR MATRIX + * + * Sets every element of the matrix to zero and clears the error flag. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix that is to be cleared. + * + * >>> Local variables: + * pElement (ElementPtr) + * A pointer to the element being cleared. + */ + +void +spClear( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int I; + +/* Begin `spClear'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +/* Clear matrix. */ +#if spCOMPLEX + if (Matrix->PreviousMatrixWasComplex OR Matrix->Complex) + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { pElement->Real = 0.0; + pElement->Imag = 0.0; + pElement = pElement->NextInCol; + } + } + } + else +#endif + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { pElement->Real = 0.0; + pElement = pElement->NextInCol; + } + } + } + +/* Empty the trash. */ + Matrix->TrashCan.Real = 0.0; +#if spCOMPLEX + Matrix->TrashCan.Imag = 0.0; +#endif + + Matrix->Error = spOKAY; + Matrix->Factored = NO; + Matrix->SingularCol = 0; + Matrix->SingularRow = 0; + Matrix->PreviousMatrixWasComplex = Matrix->Complex; + return; +} + + + + + + + + + + + +/* + * SINGLE ELEMENT ADDITION TO MATRIX BY INDEX + * + * Finds element [Row,Col] and returns a pointer to it. If element is + * not found then it is created and spliced into matrix. This routine + * is only to be used after spCreate() and before spMNA_Preorder(), + * spFactor() or spOrderAndFactor(). Returns a pointer to the + * Real portion of a MatrixElement. This pointer is later used by + * spADD_xxx_ELEMENT to directly access element. + * + * >>> Returns: + * Returns a pointer to the element. This pointer is then used to directly + * access the element during successive builds. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to the matrix that the element is to be added to. + * Row <input> (int) + * Row index for element. Must be in the range of [0..Size] unless + * the options EXPANDABLE or TRANSLATE are used. Elements placed in + * row zero are discarded. In no case may Row be less than zero. + * Col <input> (int) + * Column index for element. Must be in the range of [0..Size] unless + * the options EXPANDABLE or TRANSLATE are used. Elements placed in + * column zero are discarded. In no case may Col be less than zero. + * + * >>> Local variables: + * pElement (RealNumber *) + * Pointer to the element. + * + * >>> Possible errors: + * spNO_MEMORY + * Error is not cleared in this routine. + */ + +RealNumber * +spGetElement( eMatrix, Row, Col ) + +char *eMatrix; +int Row, Col; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +RealNumber *pElement; +ElementPtr spcFindElementInCol(); +void Translate(); + +/* Begin `spGetElement'. */ + ASSERT( IS_SPARSE( Matrix ) AND Row >= 0 AND Col >= 0 ); + + if ((Row == 0) OR (Col == 0)) + return &Matrix->TrashCan.Real; + +#if NOT TRANSLATE + ASSERT(Matrix->NeedsOrdering); +#endif + +#if TRANSLATE + Translate( Matrix, &Row, &Col ); + if (Matrix->Error == spNO_MEMORY) return NULL; +#endif + +#if NOT TRANSLATE +#if NOT EXPANDABLE + ASSERT(Row <= Matrix->Size AND Col <= Matrix->Size); +#endif + +#if EXPANDABLE +/* Re-size Matrix if necessary. */ + if ((Row > Matrix->Size) OR (Col > Matrix->Size)) + EnlargeMatrix( Matrix, MAX(Row, Col) ); + if (Matrix->Error == spNO_MEMORY) return NULL; +#endif +#endif + +/* + * The condition part of the following if statement tests to see if the + * element resides along the diagonal, if it does then it tests to see + * if the element has been created yet (Diag pointer not NULL). The + * pointer to the element is then assigned to Element after it is cast + * into a pointer to a RealNumber. This casting makes the pointer into + * a pointer to Real. This statement depends on the fact that Real + * is the first record in the MatrixElement structure. + */ + + if ((Row != Col) OR ((pElement = (RealNumber *)Matrix->Diag[Row]) == NULL)) + { +/* + * Element does not exist or does not reside along diagonal. Search + * column for element. As in the if statement above, the pointer to the + * element which is returned by spcFindElementInCol is cast into a + * pointer to Real, a RealNumber. + */ + pElement = (RealNumber*)spcFindElementInCol( Matrix, + &(Matrix->FirstInCol[Col]), + Row, Col, YES ); + } + return pElement; +} + + + + + + + + + + + +/* + * FIND ELEMENT BY SEARCHING COLUMN + * + * Searches column starting at element specified at PtrAddr and finds element + * in Row. If Element does not exists, it is created. The pointer to the + * element is returned. + * + * >>> Returned: + * A pointer to the desired element: + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to Matrix. + * LastAddr <input-output> (ElementPtr *) + * Address of pointer that initially points to the element in Col at which + * the search is started. The pointer in this location may be changed if + * a fill-in is required in and adjacent element. For this reason it is + * important that LastAddr be the address of a FirstInCol or a NextInCol + * rather than a temporary variable. + * Row <input> (int) + * Row being searched for. + * Col (int) + * Column being searched. + * CreateIfMissing <input> (BOOLEAN) + * Indicates what to do if element is not found, create one or return a + * NULL pointer. + * + * Local variables: + * pElement (ElementPtr) + * Pointer used to search through matrix. + */ + +ElementPtr +spcFindElementInCol( Matrix, LastAddr, Row, Col, CreateIfMissing ) + +MatrixPtr Matrix; +register ElementPtr *LastAddr; +register int Row; +int Col; +BOOLEAN CreateIfMissing; +{ +register ElementPtr pElement; +ElementPtr spcCreateElement(); + +/* Begin `spcFindElementInCol'. */ + pElement = *LastAddr; + +/* Search for element. */ + while (pElement != NULL) + { if (pElement->Row < Row) + { +/* Have not reached element yet. */ + LastAddr = &(pElement->NextInCol); + pElement = pElement->NextInCol; + } + else if (pElement->Row == Row) + { +/* Reached element. */ + return pElement; + } + else break; /* while loop */ + } + +/* Element does not exist and must be created. */ + if (CreateIfMissing) + return spcCreateElement( Matrix, Row, Col, LastAddr, NO ); + else return NULL; +} + + + + + + + + +#if TRANSLATE + +/* + * TRANSLATE EXTERNAL INDICES TO INTERNAL + * + * Convert internal row and column numbers to internal row and column numbers. + * Also updates Ext/Int maps. + * + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * Row <input/output> (int *) + * Upon entry Row is either a external row number of an external node + * number. Upon entry, the internal equivalent is supplied. + * Col <input/output> (int *) + * Upon entry Column is either a external column number of an external node + * number. Upon entry, the internal equivalent is supplied. + * + * >>> Local variables: + * ExtCol (int) + * Temporary variable used to hold the external column or node number + * during the external to internal column number translation. + * ExtRow (int) + * Temporary variable used to hold the external row or node number during + * the external to internal row number translation. + * IntCol (int) + * Temporary variable used to hold the internal column or node number + * during the external to internal column number translation. + * IntRow (int) + * Temporary variable used to hold the internal row or node number during + * the external to internal row number translation. + */ + +static void +Translate( Matrix, Row, Col ) + +MatrixPtr Matrix; +int *Row, *Col; +{ +register int IntRow, IntCol, ExtRow, ExtCol; + +/* Begin `Translate'. */ + ExtRow = *Row; + ExtCol = *Col; + +/* Expand translation arrays if necessary. */ + if ((ExtRow > Matrix->AllocatedExtSize) OR + (ExtCol > Matrix->AllocatedExtSize)) + { + ExpandTranslationArrays( Matrix, MAX(ExtRow, ExtCol) ); + if (Matrix->Error == spNO_MEMORY) return; + } + +/* Set ExtSize if necessary. */ + if ((ExtRow > Matrix->ExtSize) OR (ExtCol > Matrix->ExtSize)) + Matrix->ExtSize = MAX(ExtRow, ExtCol); + +/* Translate external row or node number to internal row or node number. */ + if ((IntRow = Matrix->ExtToIntRowMap[ExtRow]) == -1) + { Matrix->ExtToIntRowMap[ExtRow] = ++Matrix->CurrentSize; + Matrix->ExtToIntColMap[ExtRow] = Matrix->CurrentSize; + IntRow = Matrix->CurrentSize; + +#if NOT EXPANDABLE + ASSERT(IntRow <= Matrix->Size); +#endif + +#if EXPANDABLE +/* Re-size Matrix if necessary. */ + if (IntRow > Matrix->Size) + EnlargeMatrix( Matrix, IntRow ); + if (Matrix->Error == spNO_MEMORY) return; +#endif + + Matrix->IntToExtRowMap[IntRow] = ExtRow; + Matrix->IntToExtColMap[IntRow] = ExtRow; + } + +/* Translate external column or node number to internal column or node number.*/ + if ((IntCol = Matrix->ExtToIntColMap[ExtCol]) == -1) + { Matrix->ExtToIntRowMap[ExtCol] = ++Matrix->CurrentSize; + Matrix->ExtToIntColMap[ExtCol] = Matrix->CurrentSize; + IntCol = Matrix->CurrentSize; + +#if NOT EXPANDABLE + ASSERT(IntCol <= Matrix->Size); +#endif + +#if EXPANDABLE +/* Re-size Matrix if necessary. */ + if (IntCol > Matrix->Size) + EnlargeMatrix( Matrix, IntCol ); + if (Matrix->Error == spNO_MEMORY) return; +#endif + + Matrix->IntToExtRowMap[IntCol] = ExtCol; + Matrix->IntToExtColMap[IntCol] = ExtCol; + } + + *Row = IntRow; + *Col = IntCol; + return; +} +#endif + + + + + + +#if QUAD_ELEMENT +/* + * ADDITION OF ADMITTANCE TO MATRIX BY INDEX + * + * Performs same function as spGetElement except rather than one + * element, all four Matrix elements for a floating component are + * added. This routine also works if component is grounded. Positive + * elements are placed at [Node1,Node2] and [Node2,Node1]. This + * routine is only to be used after spCreate() and before + * spMNA_Preorder(), spFactor() or spOrderAndFactor(). + * + * >>> Returns: + * Error code. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to the matrix that component is to be entered in. + * Node1 <input> (int) + * Row and column indices for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Node zero is the + * ground node. In no case may Node1 be less than zero. + * Node2 <input> (int) + * Row and column indices for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Node zero is the + * ground node. In no case may Node2 be less than zero. + * Template <output> (struct spTemplate *) + * Collection of pointers to four elements that are later used to directly + * address elements. User must supply the template, this routine will + * fill it. + * + * Possible errors: + * spNO_MEMORY + * Error is not cleared in this routine. + */ + +int +spGetAdmittance( Matrix, Node1, Node2, Template ) + +char *Matrix; +int Node1, Node2; +struct spTemplate *Template; +{ + +/* Begin `spGetAdmittance'. */ + Template->Element1 = spGetElement(Matrix, Node1, Node1 ); + Template->Element2 = spGetElement(Matrix, Node2, Node2 ); + Template->Element3Negated = spGetElement( Matrix, Node2, Node1 ); + Template->Element4Negated = spGetElement( Matrix, Node1, Node2 ); + if + ( (Template->Element1 == NULL) + OR (Template->Element2 == NULL) + OR (Template->Element3Negated == NULL) + OR (Template->Element4Negated == NULL) + ) return spNO_MEMORY; + + if (Node1 == 0) + SWAP( RealNumber*, Template->Element1, Template->Element2 ); + + return spOKAY; +} +#endif /* QUAD_ELEMENT */ + + + + + + + + + +#if QUAD_ELEMENT +/* + * ADDITION OF FOUR ELEMENTS TO MATRIX BY INDEX + * + * Similar to spGetAdmittance, except that spGetAdmittance only + * handles 2-terminal components, whereas spGetQuad handles simple + * 4-terminals as well. These 4-terminals are simply generalized + * 2-terminals with the option of having the sense terminals different + * from the source and sink terminals. spGetQuad adds four + * elements to the matrix. Positive elements occur at Row1,Col1 + * Row2,Col2 while negative elements occur at Row1,Col2 and Row2,Col1. + * The routine works fine if any of the rows and columns are zero. + * This routine is only to be used after spCreate() and before + * spMNA_Preorder(), spFactor() or spOrderAndFactor() + * unless TRANSLATE is set true. + * + * >>> Returns: + * Error code. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to the matrix that component is to be entered in. + * Row1 <input> (int) + * First row index for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground row. In no case may Row1 be less than zero. + * Row2 <input> (int) + * Second row index for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground row. In no case may Row2 be less than zero. + * Col1 <input> (int) + * First column index for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground column. In no case may Col1 be less than zero. + * Col2 <input> (int) + * Second column index for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground column. In no case may Col2 be less than zero. + * Template <output> (struct spTemplate *) + * Collection of pointers to four elements that are later used to directly + * address elements. User must supply the template, this routine will + * fill it. + * Real <input> (RealNumber) + * Real data to be added to elements. + * Imag <input> (RealNumber) + * Imag data to be added to elements. If matrix is real, this argument + * may be deleted. + * + * Possible errors: + * spNO_MEMORY + * Error is not cleared in this routine. + */ + +int +spGetQuad( Matrix, Row1, Row2, Col1, Col2, Template ) + +char *Matrix; +int Row1, Row2, Col1, Col2; +struct spTemplate *Template; +{ +/* Begin `spGetQuad'. */ + Template->Element1 = spGetElement( Matrix, Row1, Col1); + Template->Element2 = spGetElement( Matrix, Row2, Col2 ); + Template->Element3Negated = spGetElement( Matrix, Row2, Col1 ); + Template->Element4Negated = spGetElement( Matrix, Row1, Col2 ); + if + ( (Template->Element1 == NULL) + OR (Template->Element2 == NULL) + OR (Template->Element3Negated == NULL) + OR (Template->Element4Negated == NULL) + ) return spNO_MEMORY; + + if (Template->Element1 == &((MatrixPtr)Matrix)->TrashCan.Real) + SWAP( RealNumber *, Template->Element1, Template->Element2 ); + + return spOKAY; +} +#endif /* QUAD_ELEMENT */ + + + + + + + + + +#if QUAD_ELEMENT +/* + * ADDITION OF FOUR STRUCTURAL ONES TO MATRIX BY INDEX + * + * Performs similar function to spGetQuad() except this routine is + * meant for components that do not have an admittance representation. + * + * The following stamp is used: + * Pos Neg Eqn + * Pos [ . . 1 ] + * Neg [ . . -1 ] + * Eqn [ 1 -1 . ] + * + * >>> Returns: + * Error code. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to the matrix that component is to be entered in. + * Pos <input> (int) + * See stamp above. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground row. In no case may Pos be less than zero. + * Neg <input> (int) + * See stamp above. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground row. In no case may Neg be less than zero. + * Eqn <input> (int) + * See stamp above. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground row. In no case may Eqn be less than zero. + * Template <output> (struct spTemplate *) + * Collection of pointers to four elements that are later used to directly + * address elements. User must supply the template, this routine will + * fill it. + * + * Possible errors: + * spNO_MEMORY + * Error is not cleared in this routine. + */ + +int +spGetOnes(Matrix, Pos, Neg, Eqn, Template) + +char *Matrix; +int Pos, Neg, Eqn; +struct spTemplate *Template; +{ +/* Begin `spGetOnes'. */ + Template->Element4Negated = spGetElement( Matrix, Neg, Eqn ); + Template->Element3Negated = spGetElement( Matrix, Eqn, Neg ); + Template->Element2 = spGetElement( Matrix, Pos, Eqn ); + Template->Element1 = spGetElement( Matrix, Eqn, Pos ); + if + ( (Template->Element1 == NULL) + OR (Template->Element2 == NULL) + OR (Template->Element3Negated == NULL) + OR (Template->Element4Negated == NULL) + ) return spNO_MEMORY; + + spADD_REAL_QUAD( *Template, 1.0 ); + return spOKAY; +} +#endif /* QUAD_ELEMENT */ + + + + + + + +/* + * + * CREATE AND SPLICE ELEMENT INTO MATRIX + * + * This routine is used to create new matrix elements and splice them into the + * matrix. + * + * >>> Returned: + * A pointer to the element that was created is returned. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * Row <input> (int) + * Row index for element. + * Col <input> (int) + * Column index for element. + * LastAddr <input-output> (ElementPtr *) + * This contains the address of the pointer to the element just above the + * one being created. It is used to speed the search and it is updated with + * address of the created element. + * Fillin <input> (BOOLEAN) + * Flag that indicates if created element is to be a fill-in. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer to an element in the matrix. It is used to refer to the newly + * created element and to restring the pointers of the element's row and + * column. + * pLastElement (ElementPtr) + * Pointer to the element in the matrix that was just previously pointed + * to by pElement. It is used to restring the pointers of the element's + * row and column. + * pCreatedElement (ElementPtr) + * Pointer to the desired element, the one that was just created. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +ElementPtr +spcCreateElement( Matrix, Row, Col, LastAddr, Fillin ) + +MatrixPtr Matrix; +int Row; +register int Col; +register ElementPtr *LastAddr; +BOOLEAN Fillin; +{ +register ElementPtr pElement, pLastElement; +ElementPtr pCreatedElement, spcGetElement(), spcGetFillin(); + +/* Begin `spcCreateElement'. */ + + if (Matrix->RowsLinked) + { +/* Row pointers cannot be ignored. */ + if (Fillin) + { pElement = spcGetFillin( Matrix ); + Matrix->Fillins++; + } + else + { pElement = spcGetElement( Matrix ); + Matrix->NeedsOrdering = YES; + } + if (pElement == NULL) return NULL; + +/* If element is on diagonal, store pointer in Diag. */ + if (Row == Col) Matrix->Diag[Row] = pElement; + +/* Initialize Element. */ + pCreatedElement = pElement; + pElement->Row = Row; + pElement->Col = Col; + pElement->Real = 0.0; +#if spCOMPLEX + pElement->Imag = 0.0; +#endif +#if INITIALIZE + pElement->pInitInfo = NULL; +#endif + +/* Splice element into column. */ + pElement->NextInCol = *LastAddr; + *LastAddr = pElement; + + /* Search row for proper element position. */ + pElement = Matrix->FirstInRow[Row]; + pLastElement = NULL; + while (pElement != NULL) + { +/* Search for element row position. */ + if (pElement->Col < Col) + { +/* Have not reached desired element. */ + pLastElement = pElement; + pElement = pElement->NextInRow; + } + else pElement = NULL; + } + +/* Splice element into row. */ + pElement = pCreatedElement; + if (pLastElement == NULL) + { +/* Element is first in row. */ + pElement->NextInRow = Matrix->FirstInRow[Row]; + Matrix->FirstInRow[Row] = pElement; + } + else +/* Element is not first in row. */ + { + pElement->NextInRow = pLastElement->NextInRow; + pLastElement->NextInRow = pElement; + } + + } + else + { +/* + * Matrix has not been factored yet. Thus get element rather than fill-in. + * Also, row pointers can be ignored. + */ + +/* Allocate memory for Element. */ + pElement = spcGetElement( Matrix ); + if (pElement == NULL) return NULL; + +/* If element is on diagonal, store pointer in Diag. */ + if (Row == Col) Matrix->Diag[Row] = pElement; + +/* Initialize Element. */ + pCreatedElement = pElement; + pElement->Row = Row; +#if DEBUG + pElement->Col = Col; +#endif + pElement->Real = 0.0; +#if spCOMPLEX + pElement->Imag = 0.0; +#endif +#if INITIALIZE + pElement->pInitInfo = NULL; +#endif + +/* Splice element into column. */ + pElement->NextInCol = *LastAddr; + *LastAddr = pElement; + } + + Matrix->Elements++; + return pCreatedElement; +} + + + + + + + + +/* + * + * LINK ROWS + * + * This routine is used to generate the row links. The spGetElement() + * routines do not create row links, which are needed by the spFactor() + * routines. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * FirstInRowEntry (ElementPtr *) + * A pointer into the FirstInRow array. Points to the FirstInRow entry + * currently being operated upon. + * FirstInRowArray (ArrayOfElementPtrs) + * A pointer to the FirstInRow array. Same as Matrix->FirstInRow but + * resides in a register and requires less indirection so is faster to + * use. + * Col (int) + * Column currently being operated upon. + */ + +spcLinkRows( Matrix ) + +MatrixPtr Matrix; +{ +register ElementPtr pElement, *FirstInRowEntry; +register ArrayOfElementPtrs FirstInRowArray; +register int Col; + +/* Begin `spcLinkRows'. */ + FirstInRowArray = Matrix->FirstInRow; + for (Col = Matrix->Size; Col >= 1; Col--) + { +/* Generate row links for the elements in the Col'th column. */ + pElement = Matrix->FirstInCol[Col]; + + while (pElement != NULL) + { pElement->Col = Col; + FirstInRowEntry = &FirstInRowArray[pElement->Row]; + pElement->NextInRow = *FirstInRowEntry; + *FirstInRowEntry = pElement; + pElement = pElement->NextInCol; + } + } + Matrix->RowsLinked = YES; + return; +} + + + + + + + + +/* + * ENLARGE MATRIX + * + * Increases the size of the matrix. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * NewSize <input> (int) + * The new size of the matrix. + * + * >>> Local variables: + * OldAllocatedSize (int) + * The allocated size of the matrix before it is expanded. + */ + +static +EnlargeMatrix( Matrix, NewSize ) + +MatrixPtr Matrix; +register int NewSize; +{ +register int I, OldAllocatedSize = Matrix->AllocatedSize; + +/* Begin `EnlargeMatrix'. */ + Matrix->Size = NewSize; + + if (NewSize <= OldAllocatedSize) + return; + +/* Expand the matrix frame. */ + NewSize = MAX( NewSize, EXPANSION_FACTOR * OldAllocatedSize ); + Matrix->AllocatedSize = NewSize; + + if (( REALLOC(Matrix->IntToExtColMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->IntToExtRowMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->Diag, ElementPtr, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->FirstInCol, ElementPtr, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->FirstInRow, ElementPtr, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* + * Destroy the Markowitz and Intermediate vectors, they will be recreated + * in spOrderAndFactor(). + */ + FREE( Matrix->MarkowitzRow ); + FREE( Matrix->MarkowitzCol ); + FREE( Matrix->MarkowitzProd ); + FREE( Matrix->DoRealDirect ); + FREE( Matrix->DoCmplxDirect ); + FREE( Matrix->Intermediate ); + Matrix->InternalVectorsAllocated = NO; + +/* Initialize the new portion of the vectors. */ + for (I = OldAllocatedSize+1; I <= NewSize; I++) + { Matrix->IntToExtColMap[I] = I; + Matrix->IntToExtRowMap[I] = I; + Matrix->Diag[I] = NULL; + Matrix->FirstInRow[I] = NULL; + Matrix->FirstInCol[I] = NULL; + } + + return; +} + + + + + + + + +#if TRANSLATE + +/* + * EXPAND TRANSLATION ARRAYS + * + * Increases the size arrays that are used to translate external to internal + * row and column numbers. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * NewSize <input> (int) + * The new size of the translation arrays. + * + * >>> Local variables: + * OldAllocatedSize (int) + * The allocated size of the translation arrays before being expanded. + */ + +static +ExpandTranslationArrays( Matrix, NewSize ) + +MatrixPtr Matrix; +register int NewSize; +{ +register int I, OldAllocatedSize = Matrix->AllocatedExtSize; + +/* Begin `ExpandTranslationArrays'. */ + Matrix->ExtSize = NewSize; + + if (NewSize <= OldAllocatedSize) + return; + +/* Expand the translation arrays ExtToIntRowMap and ExtToIntColMap. */ + NewSize = MAX( NewSize, EXPANSION_FACTOR * OldAllocatedSize ); + Matrix->AllocatedExtSize = NewSize; + + if (( REALLOC(Matrix->ExtToIntRowMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->ExtToIntColMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* Initialize the new portion of the vectors. */ + for (I = OldAllocatedSize+1; I <= NewSize; I++) + { Matrix->ExtToIntRowMap[I] = -1; + Matrix->ExtToIntColMap[I] = -1; + } + + return; +} +#endif + + + + + + + + + +#if INITIALIZE +/* + * INITIALIZE MATRIX + * + * With the INITIALIZE compiler option (see spConfig.h) set true, + * Sparse allows the user to keep initialization information with each + * structurally nonzero matrix element. Each element has a pointer + * that is set and used by the user. The user can set this pointer + * using spInstallInitInfo and may be read using spGetInitInfo. Both + * may be used only after the element exists. The function + * spInitialize() is a user customizable way to initialize the matrix. + * Passed to this routine is a function pointer. spInitialize() sweeps + * through every element in the matrix and checks the pInitInfo + * pointer (the user supplied pointer). If the pInitInfo is NULL, + * which is true unless the user changes it (almost always true for + * fill-ins), then the element is zeroed. Otherwise, the function + * pointer is called and passed the pInitInfo pointer as well as the + * element pointer and the external row and column numbers. If the + * user sets the value of each element, then spInitialize() replaces + * spClear(). + * + * The user function is expected to return a nonzero integer if there + * is a fatal error and zero otherwise. Upon encountering a nonzero + * return code, spInitialize() terminates and returns the error code. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * + * >>> Possible Errors: + * Returns nonzero if error, zero otherwise. + */ + +void +spInstallInitInfo( pElement, pInitInfo ) + +RealNumber *pElement; +char *pInitInfo; +{ +/* Begin `spInstallInitInfo'. */ + ASSERT(pElement != NULL); + + ((ElementPtr)pElement)->pInitInfo = pInitInfo; +} + + +char * +spGetInitInfo( pElement ) + +RealNumber *pElement; +{ +/* Begin `spGetInitInfo'. */ + ASSERT(pElement != NULL); + + return (char *)((ElementPtr)pElement)->pInitInfo; +} + + +int +spInitialize( eMatrix, pInit ) + +char *eMatrix; +int (*pInit)(); +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +int J, Error, Col; + +/* Begin `spInitialize'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +#if spCOMPLEX +/* Clear imaginary part of matrix if matrix is real but was complex. */ + if (Matrix->PreviousMatrixWasComplex AND NOT Matrix->Complex) + { for (J = Matrix->Size; J > 0; J--) + { pElement = Matrix->FirstInCol[J]; + while (pElement != NULL) + { pElement->Imag = 0.0; + pElement = pElement->NextInCol; + } + } + } +#endif /* spCOMPLEX */ + +/* Initialize the matrix. */ + for (J = Matrix->Size; J > 0; J--) + { pElement = Matrix->FirstInCol[J]; + Col = Matrix->IntToExtColMap[J]; + while (pElement != NULL) + { if (pElement->pInitInfo == NULL) + { pElement->Real = 0.0; +# if spCOMPLEX + pElement->Imag = 0.0; +# endif + } + else + { Error = (*pInit)((RealNumber *)pElement, pElement->pInitInfo, + Matrix->IntToExtRowMap[pElement->Row], Col); + if (Error) + { Matrix->Error = spFATAL; + return Error; + } + + } + pElement = pElement->NextInCol; + } + } + +/* Empty the trash. */ + Matrix->TrashCan.Real = 0.0; +#if spCOMPLEX + Matrix->TrashCan.Imag = 0.0; +#endif + + Matrix->Error = spOKAY; + Matrix->Factored = NO; + Matrix->SingularCol = 0; + Matrix->SingularRow = 0; + Matrix->PreviousMatrixWasComplex = Matrix->Complex; + return 0; +} +#endif /* INITIALIZE */ diff --git a/sis/linsolv/spConfig.h b/sis/linsolv/spConfig.h new file mode 100644 index 0000000..20a1fe0 --- /dev/null +++ b/sis/linsolv/spConfig.h @@ -0,0 +1,531 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/linsolv/spConfig.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:04 $ + * + */ +/* + * CONFIGURATION MACRO DEFINITIONS for sparse matrix routines + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * U.C. Berkeley + * + * This file contains macros for the sparse matrix routines that are used + * to define the personality of the routines. The user is expected to + * modify this file to maximize the performance of the routines with + * his/her matrices. + * + * Macros are distinguished by using solely capital letters in their + * identifiers. This contrasts with C defined identifiers which are + * strictly lower case, and program variable and procedure names which use + * both upper and lower case. + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + * + * $Date: 2004/02/07 10:15:04 $ + * $Revision: 1.1.1.1 $ + */ + + +#ifndef spCONFIG_DEFS +#define spCONFIG_DEFS + + + + +#ifdef spINSIDE_SPARSE +/* + * OPTIONS + * + * These are compiler options. Set each option to one to compile that + * section of the code. If a feature is not desired, set the macro + * to NO. Recommendations are given in brackets, [ignore them]. + * + * >>> Option descriptions: + * Arithmetic Precision + * The precision of the arithmetic used by Sparse can be set by + * changing changing the spREAL macro. This macro is + * contained in the file spMatrix.h. It is strongly suggested to + * used double precision with circuit simulators. Note that + * because C always performs arithmetic operations in double + * precision, the only benefit to using single precision is that + * less storage is required. There is often a noticeable speed + * penalty when using single precision. Sparse internally refers + * to a spREAL as a RealNumber. + * REAL + * This specifies that the routines are expected to handle real + * systems of equations. The routines can be compiled to handle + * both real and complex systems at the same time, but there is a + * slight speed and memory advantage if the routines are complied + * to handle only real systems of equations. + * spCOMPLEX + * This specifies that the routines will be complied to handle + * complex systems of equations. + * EXPANDABLE + * Setting this compiler flag true (1) makes the matrix + * expandable before it has been factored. If the matrix is + * expandable, then if an element is added that would be + * considered out of bounds in the current matrix, the size of + * the matrix is increased to hold that element. As a result, + * the size of the matrix need not be known before the matrix is + * built. The matrix can be allocated with size zero and + * expanded. + * TRANSLATE + * This option allows the set of external row and column numbers + * to be non-packed. In other words, the row and column numbers + * do not have to be contiguous. The priced paid for this + * flexibility is that when TRANSLATE is set true, the time + * required to initially build the matrix will be greater because + * the external row and column number must be translated into + * internal equivalents. This translation brings about other + * benefits though. First, the spGetElement() and + * spGetAdmittance() routines may be used after the matrix has + * been factored. Further, elements, and even rows and columns, + * may be added to the matrix, and row and columns may be deleted + * from the matrix, after it has been factored. Note that when + * the set of row and column number is not a packed set, neither + * are the RHS and Solution vectors. Thus the size of these + * vectors must be at least as large as the external size, which + * is the value of the largest given row or column numbers. + * INITIALIZE + * Causes the spInitialize(), spGetInitInfo(), and + * spInstallInitInfo() routines to be compiled. These routines + * allow the user to store and read one pointer in each nonzero + * element in the matrix. spInitialize() then calls a user + * specified function for each structural nonzero in the matrix, + * and includes this pointer as well as the external row and + * column numbers as arguments. This allows the user to write + * custom matrix initialization routines. + * DIAGONAL_PIVOTING + * Many matrices, and in particular node- and modified-node + * admittance matrices, tend to be nearly symmetric and nearly + * diagonally dominant. For these matrices, it is a good idea to + * select pivots from the diagonal. With this option enabled, + * this is exactly what happens, though if no satisfactory pivot + * can be found on the diagonal, an off-diagonal pivot will be + * used. If this option is disabled, Sparse does not + * preferentially search the diagonal. Because of this, Sparse + * has a wider variety of pivot candidates available, and so + * presumably fewer fill-ins will be created. However, the + * initial pivot selection process will take considerably longer. + * If working with node admittance matrices, or other matrices + * with a strong diagonal, it is probably best to use + * DIAGONAL_PIVOTING for two reasons. First, accuracy will be + * better because pivots will be chosen from the large diagonal + * elements, thus reducing the chance of growth. Second, a near + * optimal ordering will be chosen quickly. If the class of + * matrices you are working with does not have a strong diagonal, + * do not use DIAGONAL_PIVOTING, but consider using a larger + * threshold. When DIAGONAL_PIVOTING is turned off, the following + * options and constants are not used: MODIFIED_MARKOWITZ, + * MAX_MARKOWITZ_TIES, and TIES_MULTIPLIER. + * ARRAY_OFFSET + * This determines whether arrays start at an index of zero or one. + * This option is necessitated by the fact that standard C + * convention dictates that arrays begin with an index of zero but + * the standard mathematic convention states that arrays begin with + * an index of one. So if you prefer to start your arrays with + * zero, or your calling Sparse from FORTRAN, set ARRAY_OFFSET to + * NO or 0. Otherwise, set ARRAY_OFFSET to YES or 1. Note that if + * you use an offset of one, the arrays that you pass to Sparse + * must have an allocated length of one plus the size of the + * matrix. ARRAY_OFFSET must be either 0 or 1, no other offsets + * are valid. + * spSEPARATED_COMPLEX_VECTORS + * This specifies the format for complex vectors. If this is set + * false then a complex vector is made up of one double sized + * array of RealNumber's in which the real and imaginary numbers + * are placed in the alternately array in the array. In other + * words, the first entry would be Complex[1].Real, then comes + * Complex[1].Imag, then Complex[1].Real, etc. If + * spSEPARATED_COMPLEX_VECTORS is set true, then each complex + * vector is represented by two arrays of RealNumbers, one with + * the real terms, the other with the imaginary. [NO] + * MODIFIED_MARKOWITZ + * This specifies that the modified Markowitz method of pivot + * selection is to be used. The modified Markowitz method differs + * from standard Markowitz in two ways. First, under modified + * Markowitz, the search for a pivot can be terminated early if a + * adequate (in terms of sparsity) pivot candidate is found. + * Thus, when using modified Markowitz, the initial factorization + * can be faster, but at the expense of a suboptimal pivoting + * order that may slow subsequent factorizations. The second + * difference is in the way modified Markowitz breaks Markowitz + * ties. When two or more elements are pivot candidates and they + * all have the same Markowitz product, then the tie is broken by + * choosing the element that is best numerically. The numerically + * best element is the one with the largest ratio of its magnitude + * to the magnitude of the largest element in the same column, + * excluding itself. The modified Markowitz method results in + * marginally better accuracy. This option is most appropriate + * for use when working with very large matrices where the initial + * factor time represents an unacceptable burden. [NO] + * DELETE + * This specifies that the spDeleteRowAndCol() routine + * should be compiled. Note that for this routine to be + * compiled, both DELETE and TRANSLATE should be set true. + * STRIP + * This specifies that the spStripFills() routine should be compiled. + * MODIFIED_NODAL + * This specifies that the routine that preorders modified node + * admittance matrices should be compiled. This routine results + * in greater speed and accuracy if used with this type of + * matrix. + * QUAD_ELEMENT + * This specifies that the routines that allow four related + * elements to be entered into the matrix at once should be + * compiled. These elements are usually related to an + * admittance. The routines affected by QUAD_ELEMENT are the + * spGetAdmittance, spGetQuad and spGetOnes routines. + * TRANSPOSE + * This specifies that the routines that solve the matrix as if + * it was transposed should be compiled. These routines are + * useful when performing sensitivity analysis using the adjoint + * method. + * SCALING + * This specifies that the routine that performs scaling on the + * matrix should be complied. Scaling is not strongly + * supported. The routine to scale the matrix is provided, but + * no routines are provided to scale and descale the RHS and + * Solution vectors. It is suggested that if scaling is desired, + * it only be preformed when the pivot order is being chosen [in + * spOrderAndFactor()]. This is the only time scaling has + * an effect. The scaling may then either be removed from the + * solution by the user or the scaled factors may simply be + * thrown away. [NO] + * DOCUMENTATION + * This specifies that routines that are used to document the + * matrix, such as spPrint() and spFileMatrix(), should be + * compiled. + * DETERMINANT + * This specifies that the routine spDeterminant() should be complied. + * STABILITY + * This specifies that spLargestElement() and spRoundoff() should + * be compiled. These routines are used to check the stability (and + * hence the quality of the pivoting) of the factorization by + * computing a bound on the size of the element is the matrix E = + * A - LU. If this bound is very high after applying + * spOrderAndFactor(), then the pivot threshold should be raised. + * If the bound increases greatly after using spFactor(), then the + * matrix should probably be reordered. + * CONDITION + * This specifies that spCondition() and spNorm(), the code that + * computes a good estimate of the condition number of the matrix, + * should be compiled. + * PSEUDOCONDITION + * This specifies that spPseudoCondition(), the code that computes + * a crude and easily fooled indicator of ill-conditioning in the + * matrix, should be compiled. + * MULTIPLICATION + * This specifies that the routines to multiply the unfactored + * matrix by a vector should be compiled. + * FORTRAN + * This specifies that the FORTRAN interface routines should be + * compiled. When interfacing to FORTRAN programs, the ARRAY_OFFSET + * options should be set to NO. + * DEBUG + * This specifies that additional error checking will be compiled. + * The type of error checked are those that are common when the + * matrix routines are first integrated into a user's program. Once + * the routines have been integrated in and are running smoothly, this + * option should be turned off. + * spCOMPATIBILITY + * This specifies that Sparse1.3 should be configured to be upward + * compatible from Sparse1.2. This option is not suggested for use + * in new software. Sparse1.3, when configured to be compatible with + * Sparse1.2, is not completely compatible. In particular, if + * recompiling the calling program, it is necessary to change the + * of the Sparse include files. This option will go away in future + * versions of Sparse. [0] + */ + +/* Begin options. */ +#define REAL YES +#define EXPANDABLE NO +#define TRANSLATE NO +#define INITIALIZE NO +#define DIAGONAL_PIVOTING NO +#define ARRAY_OFFSET NO +#define MODIFIED_MARKOWITZ NO /* Not used: no DIAG_PIVOT */ +#define DELETE NO +#define STRIP NO +#define MODIFIED_NODAL NO +#define QUAD_ELEMENT NO +#define TRANSPOSE NO +#define SCALING NO +#define DOCUMENTATION NO +#define MULTIPLICATION NO +#define DETERMINANT NO +#define STABILITY NO +#define CONDITION NO +#define PSEUDOCONDITION NO +#define FORTRAN NO +#define DEBUG No + +/* + * The following options affect Sparse exports and so are exported as a + * side effect. For this reason they use the `sp' prefix. The boolean + * constants YES an NO are not defined in spMatrix.h to avoid conflicts + * with user code, so use 0 for NO and 1 for YES. + */ +#endif /* spINSIDE_SPARSE */ +#define spCOMPLEX 0 +#define spSEPARATED_COMPLEX_VECTORS 0 /* Not used! */ +#define spCOMPATIBILITY 0 +#ifdef spINSIDE_SPARSE + + + + + + + +/* + * MATRIX CONSTANTS + * + * These constants are used throughout the sparse matrix routines. They + * should be set to suit the type of matrix being solved. Recommendations + * are given in brackets. + * + * Some terminology should be defined. The Markowitz row count is the number + * of non-zero elements in a row excluding the one being considered as pivot. + * There is one Markowitz row count for every row. The Markowitz column + * is defined similarly for columns. The Markowitz product for an element + * is the product of its row and column counts. It is a measure of how much + * work would be required on the next step of the factorization if that + * element were chosen to be pivot. A small Markowitz product is desirable. + * + * >>> Constants descriptions: + * DEFAULT_THRESHOLD + * The relative threshold used if the user enters an invalid + * threshold. Also the threshold used by spFactor() when + * calling spOrderAndFactor(). The default threshold should + * not be less than or equal to zero nor larger than one. [0.001] + * DIAG_PIVOTING_AS_DEFAULT + * This indicates whether spOrderAndFactor() should use diagonal + * pivoting as default. This issue only arises when + * spOrderAndFactor() is called from spFactor(). + * SPACE_FOR_ELEMENTS + * This number multiplied by the size of the matrix equals the number + * of elements for which memory is initially allocated in + * spCreate(). [6] + * SPACE_FOR_FILL_INS + * This number multiplied by the size of the matrix equals the number + * of elements for which memory is initially allocated and specifically + * reserved for fill-ins in spCreate(). [4] + * ELEMENTS_PER_ALLOCATION + * The number of matrix elements requested from the malloc utility on + * each call to it. Setting this value greater than 1 reduces the + * amount of overhead spent in this system call. On a virtual memory + * machine, its good to allocate slightly less than a page worth of + * elements at a time (or some multiple thereof). + * [For the VAX, for real only use 41, otherwise use 31] + * MINIMUM_ALLOCATED_SIZE + * The minimum allocated size of a matrix. Note that this does not + * limit the minimum size of a matrix. This just prevents having to + * resize a matrix many times if the matrix is expandable, large and + * allocated with an estimated size of zero. This number should not + * be less than one. + * EXPANSION_FACTOR + * The amount the allocated size of the matrix is increased when it + * is expanded. + * MAX_MARKOWITZ_TIES + * This number is used for two slightly different things, both of which + * relate to the search for the best pivot. First, it is the maximum + * number of elements that are Markowitz tied that will be sifted + * through when trying to find the one that is numerically the best. + * Second, it creates an upper bound on how large a Markowitz product + * can be before it eliminates the possibility of early termination + * of the pivot search. In other words, if the product of the smallest + * Markowitz product yet found and TIES_MULTIPLIER is greater than + * MAX_MARKOWITZ_TIES, then no early termination takes place. + * Set MAX_MARKOWITZ_TIES to some small value if no early termination of + * the pivot search is desired. An array of RealNumbers is allocated + * of size MAX_MARKOWITZ_TIES so it must be positive and shouldn't + * be too large. Active when MODIFIED_MARKOWITZ is 1 (true). [100] + * TIES_MULTIPLIER + * Specifies the number of Markowitz ties that are allowed to occur + * before the search for the pivot is terminated early. Set to some + * large value if no early termination of the pivot search is desired. + * This number is multiplied times the Markowitz product to determine + * how many ties are required for early termination. This means that + * more elements will be searched before early termination if a large + * number of fill-ins could be created by accepting what is currently + * considered the best choice for the pivot. Active when + * MODIFIED_MARKOWITZ is 1 (true). Setting this number to zero + * effectively eliminates all pivoting, which should be avoided. + * This number must be positive. TIES_MULTIPLIER is also used when + * diagonal pivoting breaks down. [5] + * DEFAULT_PARTITION + * Which partition mode is used by spPartition() as default. + * Possibilities include + * spDIRECT_PARTITION -- each row used direct addressing, best for + * a few relatively dense matrices. + * spINDIRECT_PARTITION -- each row used indirect addressing, best + * for a few very sparse matrices. + * spAUTO_PARTITION -- direct or indirect addressing is chosen on + * a row-by-row basis, carries a large overhead, but speeds up + * both dense and sparse matrices, best if there is a large + * number of matrices that can use the same ordering. + */ + +/* Begin constants. */ +#define DEFAULT_THRESHOLD 1.0e-3 +#define DIAG_PIVOTING_AS_DEFAULT YES +#define SPACE_FOR_ELEMENTS 6 +#define SPACE_FOR_FILL_INS 4 +#define ELEMENTS_PER_ALLOCATION 31 +#define MINIMUM_ALLOCATED_SIZE 6 +#define EXPANSION_FACTOR 1.5 +#define MAX_MARKOWITZ_TIES 100 /* Not used: no DIAG_PIVOT */ +#define TIES_MULTIPLIER 5 /* Not used: no DIAG_PIVOT */ +#define DEFAULT_PARTITION spAUTO_PARTITION + + + + + + +/* + * PRINTER WIDTH + * + * This macro characterize the printer for the spPrint() routine. + * + * >>> Macros: + * PRINTER_WIDTH + * The number of characters per page width. Set to 80 for terminal, + * 132 for line printer. + */ + +/* Begin printer constants. */ +#define PRINTER_WIDTH 80 + + + + + + +/* + * MACHINE CONSTANTS + * + * These numbers must be updated when the program is ported to a new machine. + */ + +/* Begin machine constants. */ + +#ifdef __GNUC__ +/* + * This code is currently deleted because most ANSI standard C compilers + * do not provide the standard header files yet. + */ +# include <limits.h> +# include <float.h> +# define MACHINE_RESOLUTION DBL_EPSILON +# define LARGEST_REAL DBL_MAX +# define SMALLEST_REAL DBL_MIN +# define LARGEST_SHORT_INTEGER SHRT_MAX +# define LARGEST_LONG_INTEGER LONG_MAX +#else /* NOT defined(__STDC__) */ + +/* VAX machine constants */ +#ifdef vax +# define MACHINE_RESOLUTION 6.93889e-18 +# define LARGEST_REAL 1.70141e+38 +# define SMALLEST_REAL 2.938743e-39 +# define LARGEST_SHORT_INTEGER 32766 +# define LARGEST_LONG_INTEGER 2147483646 +#endif + +/* hp9000 machine constants */ +#ifdef hpux +/* These values are correct for hp9000/300. Should be correct for others. */ +# define MACHINE_RESOLUTION 8.9e-15 +# define LARGEST_REAL 1.79769313486231e+308 +# define SMALLEST_REAL 2.22507385850721e-308 +# define LARGEST_SHORT_INTEGER 32766 +# define LARGEST_LONG_INTEGER 2147483646 +#endif + +/* Sun machine constants */ +#ifdef sun +/* These values are rumored to be the correct values. */ +# define MACHINE_RESOLUTION 8.9e-15 +# define LARGEST_REAL 1.79769313486231e+308 +# define SMALLEST_REAL 2.22507385850721e-308 +# define LARGEST_SHORT_INTEGER 32767 +# define LARGEST_LONG_INTEGER 2147483647 +#endif + +/* DECstation machine constants */ +#ifdef mips +/* These values are rumored to be the correct values. */ +# define MACHINE_RESOLUTION 2.3e-16 +# define LARGEST_REAL 1.79769313486231e+308 +# define SMALLEST_REAL 2.22507385850721e-308 +# define LARGEST_SHORT_INTEGER 32767 +# define LARGEST_LONG_INTEGER 2147483647 +#endif + +/* Alpha machine constants */ +#ifdef __alpha +/* These values are rumored to be the correct values. */ +# define MACHINE_RESOLUTION 2.3e-16 +# define LARGEST_REAL 1.79769313486231e+308 +# define SMALLEST_REAL 2.22507385850721e-308 +# define LARGEST_SHORT_INTEGER 32767 +# define LARGEST_LONG_INTEGER 9223372036854775807 +#endif + +/* IBM6000 machine constants */ +#ifdef _IBMR2 +/* These values are rumored to be the correct values. */ +# define MACHINE_RESOLUTION 2.3e-16 +# define LARGEST_REAL 1.79769313486231e+308 +# define SMALLEST_REAL 2.22507385850721e-308 +# define LARGEST_SHORT_INTEGER 32767 +# define LARGEST_LONG_INTEGER 2147483647 +#endif +#endif /* NOT defined(__STDC__) */ + + + + + + +/* + * ANNOTATION + * + * This macro changes the amount of annotation produced by the matrix + * routines. The annotation is used as a debugging aid. Change the number + * associated with ANNOTATE to change the amount of annotation produced by + * the program. + */ + +/* Begin annotation definitions. */ +#define ANNOTATE NONE + +#define NONE 0 +#define ON_STRANGE_BEHAVIOR 1 +#define FULL 2 + +#endif /* spINSIDE_SPARSE */ +#endif /* spCONFIG_DEFS */ diff --git a/sis/linsolv/spDefs.h b/sis/linsolv/spDefs.h new file mode 100644 index 0000000..ec3499a --- /dev/null +++ b/sis/linsolv/spDefs.h @@ -0,0 +1,886 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/linsolv/spDefs.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:04 $ + * + */ +/* + * DATA STRUCTURE AND MACRO DEFINITIONS for Sparse. + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains common type definitions and macros for the sparse + * matrix routines. These definitions are of no interest to the user. + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + * + * $Date: 2004/02/07 10:15:04 $ + * $Revision: 1.1.1.1 $ + */ + + + + +/* + * IMPORTS + */ + +#include <stdio.h> + + +/* + * If running lint, change some of the compiler options to get a more + * complete inspection. + */ + +#ifdef lint +#undef REAL +#undef spCOMPLEX +#undef EXPANDABLE +#undef TRANSLATE +#undef INITIALIZE +#undef DELETE +#undef STRIP +#undef MODIFIED_NODAL +#undef QUAD_ELEMENT +#undef TRANSPOSE +#undef SCALING +#undef DOCUMENTATION +#undef MULTIPLICATION +#undef DETERMINANT +#undef CONDITION +#undef PSEUDOCONDITION +#undef FORTRAN +#undef DEBUG +#undef spCOMPATIBILITY + +#define REAL YES +#define spCOMPLEX YES +#define EXPANDABLE YES +#define TRANSLATE YES +#define INITIALIZE YES +#define DELETE YES +#define STRIP YES +#define MODIFIED_NODAL YES +#define QUAD_ELEMENT YES +#define TRANSPOSE YES +#define SCALING YES +#define DOCUMENTATION YES +#define MULTIPLICATION YES +#define DETERMINANT YES +#define CONDITION YES +#define PSEUDOCONDITION YES +#define FORTRAN YES +#define DEBUG YES +#define spCOMPATIBILITY YES + +#define LINT YES +#else /* not lint */ +#define LINT NO +#endif /* not lint */ + + + + + + + +/* + * MACRO DEFINITIONS + * + * Macros are distinguished by using solely capital letters in their + * identifiers. This contrasts with C defined identifiers which are strictly + * lower case, and program variable and procedure names which use both upper + * and lower case. + */ + +/* Begin macros. */ + +/* Boolean data type */ +#define BOOLEAN int +#define NO 0 +#define YES 1 +#define NOT ! +#define AND && +#define OR || + +/* NULL pointer */ +#ifndef NULL +#define NULL 0 +#endif + +#define SPARSE_ID 0x772773 /* Arbitrary (is Sparse on phone). */ +#define IS_SPARSE(matrix) ((matrix) != NULL && \ + (matrix)->ID == SPARSE_ID) +#define IS_VALID(matrix) ((matrix) != NULL && \ + (matrix)->ID == SPARSE_ID && \ + (matrix)->Error >= spOKAY && \ + (matrix)->Error < spFATAL) +#define IS_FACTORED(matrix) ((matrix)->Factored && !(matrix)->NeedsOrdering) + +/* Macro commands */ +/* Macro functions that return the maximum or minimum independent of type. */ +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +/* Macro function that returns the absolute value of a floating point number. */ +#define ABS(a) ((a) < 0.0 ? -(a) : (a)) + +/* Macro function that returns the square of a number. */ +#define SQR(a) ((a)*(a)) + +/* Macro procedure that swaps two entities. */ +#define SWAP(type, a, b) {type swapx; swapx = a; a = b; b = swapx;} + +/* Macro function that returns the approx absolute value of a complex number. */ +#if spCOMPLEX +#define ELEMENT_MAG(ptr) (ABS((ptr)->Real) + ABS((ptr)->Imag)) +#else +#define ELEMENT_MAG(ptr) ((ptr)->Real < 0.0 ? -(ptr)->Real : (ptr)->Real) +#endif + +/* Complex assignment statements. */ +#define CMPLX_ASSIGN(to,from) \ +{ (to).Real = (from).Real; \ + (to).Imag = (from).Imag; \ +} +#define CMPLX_CONJ_ASSIGN(to,from) \ +{ (to).Real = (from).Real; \ + (to).Imag = -(from).Imag; \ +} +#define CMPLX_NEGATE_ASSIGN(to,from) \ +{ (to).Real = -(from).Real; \ + (to).Imag = -(from).Imag; \ +} +#define CMPLX_CONJ_NEGATE_ASSIGN(to,from) \ +{ (to).Real = -(from).Real; \ + (to).Imag = (from).Imag; \ +} +#define CMPLX_CONJ(a) (a).Imag = -(a).Imag +#define CMPLX_NEGATE(a) \ +{ (a).Real = -(a).Real; \ + (a).Imag = -(a).Imag; \ +} + +/* Macro that returns the approx magnitude (L-1 norm) of a complex number. */ +#define CMPLX_1_NORM(a) (ABS((a).Real) + ABS((a).Imag)) + +/* Macro that returns the approx magnitude (L-infinity norm) of a complex. */ +#define CMPLX_INF_NORM(a) (MAX (ABS((a).Real),ABS((a).Imag))) + +/* Macro function that returns the magnitude (L-2 norm) of a complex number. */ +#define CMPLX_2_NORM(a) (sqrt((a).Real*(a).Real + (a).Imag*(a).Imag)) + +/* Macro function that performs complex addition. */ +#define CMPLX_ADD(to,from_a,from_b) \ +{ (to).Real = (from_a).Real + (from_b).Real; \ + (to).Imag = (from_a).Imag + (from_b).Imag; \ +} + +/* Macro function that performs complex subtraction. */ +#define CMPLX_SUBT(to,from_a,from_b) \ +{ (to).Real = (from_a).Real - (from_b).Real; \ + (to).Imag = (from_a).Imag - (from_b).Imag; \ +} + +/* Macro function that is equivalent to += operator for complex numbers. */ +#define CMPLX_ADD_ASSIGN(to,from) \ +{ (to).Real += (from).Real; \ + (to).Imag += (from).Imag; \ +} + +/* Macro function that is equivalent to -= operator for complex numbers. */ +#define CMPLX_SUBT_ASSIGN(to,from) \ +{ (to).Real -= (from).Real; \ + (to).Imag -= (from).Imag; \ +} + +/* Macro function that multiplies a complex number by a scalar. */ +#define SCLR_MULT(to,sclr,cmplx) \ +{ (to).Real = (sclr) * (cmplx).Real; \ + (to).Imag = (sclr) * (cmplx).Imag; \ +} + +/* Macro function that multiply-assigns a complex number by a scalar. */ +#define SCLR_MULT_ASSIGN(to,sclr) \ +{ (to).Real *= (sclr); \ + (to).Imag *= (sclr); \ +} + +/* Macro function that multiplies two complex numbers. */ +#define CMPLX_MULT(to,from_a,from_b) \ +{ (to).Real = (from_a).Real * (from_b).Real - \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag = (from_a).Real * (from_b).Imag + \ + (from_a).Imag * (from_b).Real; \ +} + +/* Macro function that implements to *= from for complex numbers. */ +#define CMPLX_MULT_ASSIGN(to,from) \ +{ RealNumber to_real_ = (to).Real; \ + (to).Real = to_real_ * (from).Real - \ + (to).Imag * (from).Imag; \ + (to).Imag = to_real_ * (from).Imag + \ + (to).Imag * (from).Real; \ +} + +/* Macro function that multiplies two complex numbers, the first of which is + * conjugated. */ +#define CMPLX_CONJ_MULT(to,from_a,from_b) \ +{ (to).Real = (from_a).Real * (from_b).Real + \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag = (from_a).Real * (from_b).Imag - \ + (from_a).Imag * (from_b).Real; \ +} + +/* Macro function that multiplies two complex numbers and then adds them + * to another. to = add + mult_a * mult_b */ +#define CMPLX_MULT_ADD(to,mult_a,mult_b,add) \ +{ (to).Real = (mult_a).Real * (mult_b).Real - \ + (mult_a).Imag * (mult_b).Imag + (add).Real; \ + (to).Imag = (mult_a).Real * (mult_b).Imag + \ + (mult_a).Imag * (mult_b).Real + (add).Imag; \ +} + +/* Macro function that subtracts the product of two complex numbers from + * another. to = subt - mult_a * mult_b */ +#define CMPLX_MULT_SUBT(to,mult_a,mult_b,subt) \ +{ (to).Real = (subt).Real - (mult_a).Real * (mult_b).Real + \ + (mult_a).Imag * (mult_b).Imag; \ + (to).Imag = (subt).Imag - (mult_a).Real * (mult_b).Imag - \ + (mult_a).Imag * (mult_b).Real; \ +} + +/* Macro function that multiplies two complex numbers and then adds them + * to another. to = add + mult_a* * mult_b where mult_a* represents mult_a + * conjugate. */ +#define CMPLX_CONJ_MULT_ADD(to,mult_a,mult_b,add) \ +{ (to).Real = (mult_a).Real * (mult_b).Real + \ + (mult_a).Imag * (mult_b).Imag + (add).Real; \ + (to).Imag = (mult_a).Real * (mult_b).Imag - \ + (mult_a).Imag * (mult_b).Real + (add).Imag; \ +} + +/* Macro function that multiplies two complex numbers and then adds them + * to another. to += mult_a * mult_b */ +#define CMPLX_MULT_ADD_ASSIGN(to,from_a,from_b) \ +{ (to).Real += (from_a).Real * (from_b).Real - \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag += (from_a).Real * (from_b).Imag + \ + (from_a).Imag * (from_b).Real; \ +} + +/* Macro function that multiplies two complex numbers and then subtracts them + * from another. */ +#define CMPLX_MULT_SUBT_ASSIGN(to,from_a,from_b) \ +{ (to).Real -= (from_a).Real * (from_b).Real - \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag -= (from_a).Real * (from_b).Imag + \ + (from_a).Imag * (from_b).Real; \ +} + +/* Macro function that multiplies two complex numbers and then adds them + * to the destination. to += from_a* * from_b where from_a* represents from_a + * conjugate. */ +#define CMPLX_CONJ_MULT_ADD_ASSIGN(to,from_a,from_b) \ +{ (to).Real += (from_a).Real * (from_b).Real + \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag += (from_a).Real * (from_b).Imag - \ + (from_a).Imag * (from_b).Real; \ +} + +/* Macro function that multiplies two complex numbers and then subtracts them + * from the destination. to -= from_a* * from_b where from_a* represents from_a + * conjugate. */ +#define CMPLX_CONJ_MULT_SUBT_ASSIGN(to,from_a,from_b) \ +{ (to).Real -= (from_a).Real * (from_b).Real + \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag -= (from_a).Real * (from_b).Imag - \ + (from_a).Imag * (from_b).Real; \ +} + +/* + * Macro functions that provide complex division. + */ + +/* Complex division: to = num / den */ +#define CMPLX_DIV(to,num,den) \ +{ RealNumber r_, s_; \ + if (((den).Real >= (den).Imag AND (den).Real > -(den).Imag) OR \ + ((den).Real < (den).Imag AND (den).Real <= -(den).Imag)) \ + { r_ = (den).Imag / (den).Real; \ + s_ = (den).Real + r_*(den).Imag; \ + (to).Real = ((num).Real + r_*(num).Imag)/s_; \ + (to).Imag = ((num).Imag - r_*(num).Real)/s_; \ + } \ + else \ + { r_ = (den).Real / (den).Imag; \ + s_ = (den).Imag + r_*(den).Real; \ + (to).Real = (r_*(num).Real + (num).Imag)/s_; \ + (to).Imag = (r_*(num).Imag - (num).Real)/s_; \ + } \ +} + +/* Complex division and assignment: num /= den */ +#define CMPLX_DIV_ASSIGN(num,den) \ +{ RealNumber r_, s_, t_; \ + if (((den).Real >= (den).Imag AND (den).Real > -(den).Imag) OR \ + ((den).Real < (den).Imag AND (den).Real <= -(den).Imag)) \ + { r_ = (den).Imag / (den).Real; \ + s_ = (den).Real + r_*(den).Imag; \ + t_ = ((num).Real + r_*(num).Imag)/s_; \ + (num).Imag = ((num).Imag - r_*(num).Real)/s_; \ + (num).Real = t_; \ + } \ + else \ + { r_ = (den).Real / (den).Imag; \ + s_ = (den).Imag + r_*(den).Real; \ + t_ = (r_*(num).Real + (num).Imag)/s_; \ + (num).Imag = (r_*(num).Imag - (num).Real)/s_; \ + (num).Real = t_; \ + } \ +} + +/* Complex reciprocation: to = 1.0 / den */ +#define CMPLX_RECIPROCAL(to,den) \ +{ RealNumber r_; \ + if (((den).Real >= (den).Imag AND (den).Real > -(den).Imag) OR \ + ((den).Real < (den).Imag AND (den).Real <= -(den).Imag)) \ + { r_ = (den).Imag / (den).Real; \ + (to).Imag = -r_*((to).Real = 1.0/((den).Real + r_*(den).Imag)); \ + } \ + else \ + { r_ = (den).Real / (den).Imag; \ + (to).Real = -r_*((to).Imag = -1.0/((den).Imag + r_*(den).Real));\ + } \ +} + + + + + + +/* + * ASSERT and ABORT + * + * Macro used to assert that if the code is working correctly, then + * a condition must be true. If not, then execution is terminated + * and an error message is issued stating that there is an internal + * error and giving the file and line number. These assertions are + * not evaluated unless the DEBUG flag is true. + */ + +#if DEBUG +#define ASSERT(condition) if (NOT(condition)) ABORT() +#else +#define ASSERT(condition) +#endif + +#if DEBUG +#define ABORT() \ +{ (void)fflush(stdout); \ + (void)fprintf(stderr, "sparse: panic in file `%s' at line %d.\n", \ + __FILE__, __LINE__); \ + (void)fflush(stderr); \ + abort(); \ +} +#else +#define ABORT() +#endif + + + + + +/* + * IMAGINARY VECTORS + * + * The imaginary vectors iRHS and iSolution are only needed when the + * options spCOMPLEX and spSEPARATED_COMPLEX_VECTORS are set. The following + * macro makes it easy to include or exclude these vectors as needed. + */ + +#if spCOMPLEX AND spSEPARATED_COMPLEX_VECTORS +#define IMAG_VECTORS , iRHS, iSolution +#define IMAG_RHS , iRHS +#else +#define IMAG_VECTORS +#define IMAG_RHS +#endif + + + + + + +/* + * MEMORY ALLOCATION + */ + +extern char *malloc(), *calloc(), *realloc(); +#ifdef ultrix + extern void free(); + extern void abort(); +#else + extern free(); + extern abort(); +#endif + +#define ALLOC(type,number) ((type *)malloc((unsigned)(sizeof(type)*(number)))) +#define REALLOC(ptr,type,number) \ + ptr = (type *)realloc((char *)ptr,(unsigned)(sizeof(type)*(number))) +#define FREE(ptr) { if ((ptr) != NULL) free((char *)(ptr)); (ptr) = NULL; } + + +/* Calloc that properly handles allocating a cleared vector. */ +#define CALLOC(ptr,type,number) \ +{ int i; ptr = ALLOC(type, number); \ + if (ptr != (type *)NULL) \ + for(i=(number)-1;i>=0; i--) ptr[i] = (type) 0; \ +} + + + + + + + +/* + * REAL NUMBER + */ + +/* Begin `RealNumber'. */ + +typedef spREAL RealNumber, *RealVector; + + + + + + + + +/* + * COMPLEX NUMBER DATA STRUCTURE + * + * >>> Structure fields: + * Real (RealNumber) + * The real portion of the number. Real must be the first + * field in this structure. + * Imag (RealNumber) + * The imaginary portion of the number. This field must follow + * immediately after Real. + */ + +/* Begin `ComplexNumber'. */ + +typedef struct +{ RealNumber Real; + RealNumber Imag; +} ComplexNumber, *ComplexVector; + + + + + + + + +/* + * MATRIX ELEMENT DATA STRUCTURE + * + * Every nonzero element in the matrix is stored in a dynamically allocated + * MatrixElement structure. These structures are linked together in an + * orthogonal linked list. Two different MatrixElement structures exist. + * One is used when only real matrices are expected, it is missing an entry + * for imaginary data. The other is used if complex matrices are expected. + * It contains an entry for imaginary data. + * + * >>> Structure fields: + * Real (RealNumber) + * The real portion of the value of the element. Real must be the first + * field in this structure. + * Imag (RealNumber) + * The imaginary portion of the value of the element. If the matrix + * routines are not compiled to handle complex matrices, then this + * field does not exist. If it exists, it must follow immediately after + * Real. + * Row (int) + * The row number of the element. + * Col (int) + * The column number of the element. + * NextInRow (struct MatrixElement *) + * NextInRow contains a pointer to the next element in the row to the + * right of this element. If this element is the last nonzero in the + * row then NextInRow contains NULL. + * NextInCol (struct MatrixElement *) + * NextInCol contains a pointer to the next element in the column below + * this element. If this element is the last nonzero in the column then + * NextInCol contains NULL. + * pInitInfo (char *) + * Pointer to user data used for initialization of the matrix element. + * Initialized to NULL. + * + * >>> Type definitions: + * ElementPtr + * A pointer to a MatrixElement. + * ArrayOfElementPtrs + * An array of ElementPtrs. Used for FirstInRow, FirstInCol and + * Diag pointer arrays. + */ + +/* Begin `MatrixElement'. */ + +struct MatrixElement +{ RealNumber Real; +#if spCOMPLEX + RealNumber Imag; +#endif + int Row; + int Col; + struct MatrixElement *NextInRow; + struct MatrixElement *NextInCol; +#if INITIALIZE + char *pInitInfo; +#endif +}; + +typedef struct MatrixElement *ElementPtr; +typedef ElementPtr *ArrayOfElementPtrs; + + + + + + + + +/* + * ALLOCATION DATA STRUCTURE + * + * The sparse matrix routines keep track of all memory that is allocated by + * the operating system so the memory can later be freed. This is done by + * saving the pointers to all the chunks of memory that are allocated to a + * particular matrix in an allocation list. That list is organized as a + * linked list so that it can grow without a priori bounds. + * + * >>> Structure fields: + * AllocatedPtr (char *) + * Pointer to chunk of memory that has been allocated for the matrix. + * NextRecord (struct AllocationRecord *) + * Pointer to the next allocation record. + */ + +/* Begin `AllocationRecord'. */ +struct AllocationRecord +{ char *AllocatedPtr; + struct AllocationRecord *NextRecord; +}; + +typedef struct AllocationRecord *AllocationListPtr; + + + + + + + + + +/* + * FILL-IN LIST DATA STRUCTURE + * + * The sparse matrix routines keep track of all fill-ins separately from + * user specified elements so they may be removed by spStripFills(). Fill-ins + * are allocated in bunched in what is called a fill-in lists. The data + * structure defined below is used to organize these fill-in lists into a + * linked-list. + * + * >>> Structure fields: + * pFillinList (ElementPtr) + * Pointer to a fill-in list, or a bunch of fill-ins arranged contiguously + * in memory. + * NumberOfFillinsInList (int) + * Seems pretty self explanatory to me. + * Next (struct FillinListNodeStruct *) + * Pointer to the next fill-in list structures. + */ + +/* Begin `FillinListNodeStruct'. */ +struct FillinListNodeStruct +{ ElementPtr pFillinList; + int NumberOfFillinsInList; + struct FillinListNodeStruct *Next; +}; + + + + + + + + + + +/* + * MATRIX FRAME DATA STRUCTURE + * + * This structure contains all the pointers that support the orthogonal + * linked list that contains the matrix elements. Also included in this + * structure are other numbers and pointers that are used globally by the + * sparse matrix routines and are associated with one particular matrix. + * + * >>> Type definitions: + * MatrixPtr + * A pointer to MatrixFrame. Essentially, a pointer to the matrix. + * + * >>> Structure fields: + * AbsThreshold (RealNumber) + * The absolute magnitude an element must have to be considered as a + * pivot candidate, except as a last resort. + * AllocatedExtSize (int) + * The allocated size of the arrays used to translate external row and + * column numbers to their internal values. + * AllocatedSize (int) + * The currently allocated size of the matrix; the size the matrix can + * grow to when EXPANDABLE is set true and AllocatedSize is the largest + * the matrix can get without requiring that the matrix frame be + * reallocated. + * Complex (BOOLEAN) + * The flag which indicates whether the matrix is complex (true) or + * real. + * CurrentSize (int) + * This number is used during the building of the matrix when the + * TRANSLATE option is set true. It indicates the number of internal + * rows and columns that have elements in them. + * Diag (ArrayOfElementPtrs) + * Array of pointers that points to the diagonal elements. + * DoCmplxDirect (BOOLEAN *) + * Array of flags, one for each column in matrix. If a flag is true + * then corresponding column in a complex matrix should be eliminated + * in spFactor() using direct addressing (rather than indirect + * addressing). + * DoRealDirect (BOOLEAN *) + * Array of flags, one for each column in matrix. If a flag is true + * then corresponding column in a real matrix should be eliminated + * in spFactor() using direct addressing (rather than indirect + * addressing). + * Elements (int) + * The number of original elements (total elements minus fill ins) + * present in matrix. + * Error (int) + * The error status of the sparse matrix package. + * ExtSize (int) + * The value of the largest external row or column number encountered. + * ExtToIntColMap (int []) + * An array that is used to convert external columns number to internal + * external column numbers. Present only if TRANSLATE option is set true. + * ExtToIntRowMap (int []) + * An array that is used to convert external row numbers to internal + * external row numbers. Present only if TRANSLATE option is set true. + * Factored (BOOLEAN) + * Indicates if matrix has been factored. This flag is set true in + * spFactor() and spOrderAndFactor() and set false in spCreate() + * and spClear(). + * Fillins (int) + * The number of fill-ins created during the factorization the matrix. + * FirstInCol (ArrayOfElementPtrs) + * Array of pointers that point to the first nonzero element of the + * column corresponding to the index. + * FirstInRow (ArrayOfElementPtrs) + * Array of pointers that point to the first nonzero element of the row + * corresponding to the index. + * ID (unsigned long int) + * A constant that provides the sparse data structure with a signature. + * When DEBUG is true, all externally available sparse routines check + * this signature to assure they are operating on a valid matrix. + * Intermediate (RealVector) + * Temporary storage used in the spSolve routines. Intermediate is an + * array used during forward and backward substitution. It is + * commonly called y when the forward and backward substitution process is + * denoted Ax = b => Ly = b and Ux = y. + * InternalVectorsAllocated (BOOLEAN) + * A flag that indicates whether the markowitz vectors and the + * Intermediate vector have been created. + * These vectors are created in CreateInternalVectors(). + * IntToExtColMap (int []) + * An array that is used to convert internal column numbers to external + * external column numbers. + * IntToExtRowMap (int []) + * An array that is used to convert internal row numbers to external + * external row numbers. + * MarkowitzCol (int []) + * An array that contains the count of the non-zero elements excluding + * the pivots for each column. Used to generate and update MarkowitzProd. + * MarkowitzProd (long []) + * The array of the products of the Markowitz row and column counts. The + * element with the smallest product is the best pivot to use to maintain + * sparsity. + * MarkowitzRow (int []) + * An array that contains the count of the non-zero elements excluding + * the pivots for each row. Used to generate and update MarkowitzProd. + * MaxRowCountInLowerTri (int) + * The maximum number of off-diagonal element in the rows of L, the + * lower triangular matrix. This quantity is used when computing an + * estimate of the roundoff error in the matrix. + * NeedsOrdering (BOOLEAN) + * This is a flag that signifies that the matrix needs to be ordered + * or reordered. NeedsOrdering is set true in spCreate() and + * spGetElement() or spGetAdmittance() if new elements are added to the + * matrix after it has been previously factored. It is set false in + * spOrderAndFactor(). + * NumberOfInterchangesIsOdd (BOOLEAN) + * Flag that indicates the sum of row and column interchange counts + * is an odd number. Used when determining the sign of the determinant. + * Partitioned (BOOLEAN) + * This flag indicates that the columns of the matrix have been + * partitioned into two groups. Those that will be addressed directly + * and those that will be addressed indirectly in spFactor(). + * PivotsOriginalCol (int) + * Column pivot was chosen from. + * PivotsOriginalRow (int) + * Row pivot was chosen from. + * PivotSelectionMethod (char) + * Character that indicates which pivot search method was successful. + * PreviousMatrixWasComplex (BOOLEAN) + * This flag in needed to determine how to clear the matrix. When + * dealing with real matrices, it is important that the imaginary terms + * in the matrix elements be zero. Thus, if the previous matrix was + * complex, then the current matrix will be cleared as if it were complex + * even if it is real. + * RelThreshold (RealNumber) + * The magnitude an element must have relative to others in its row + * to be considered as a pivot candidate, except as a last resort. + * Reordered (BOOLEAN) + * This flag signifies that the matrix has been reordered. It + * is cleared in spCreate(), set in spMNA_Preorder() and + * spOrderAndFactor() and is used in spPrint(). + * RowsLinked (BOOLEAN) + * A flag that indicates whether the row pointers exist. The AddByIndex + * routines do not generate the row pointers, which are needed by some + * of the other routines, such as spOrderAndFactor() and spScale(). + * The row pointers are generated in the function spcLinkRows(). + * SingularCol (int) + * Normally zero, but if matrix is found to be singular, SingularCol is + * assigned the external column number of pivot that was zero. + * SingularRow (int) + * Normally zero, but if matrix is found to be singular, SingularRow is + * assigned the external row number of pivot that was zero. + * Singletons (int) + * The number of singletons available for pivoting. Note that if row I + * and column I both contain singletons, only one of them is counted. + * Size (int) + * Number of rows and columns in the matrix. Does not change as matrix + * is factored. + * TrashCan (MatrixElement) + * This is a dummy MatrixElement that is used to by the user to stuff + * data related to the zero row or column. In other words, when the user + * adds an element in row zero or column zero, then the matrix returns + * a pointer to TrashCan. In this way the user can have a uniform way + * data into the matrix independent of whether a component is connected + * to ground. + * + * >>> The remaining fields are related to memory allocation. + * TopOfAllocationList (AllocationListPtr) + * Pointer which points to the top entry in a list. The list contains + * all the pointers to the segments of memory that have been allocated + * to this matrix. This is used when the memory is to be freed on + * deallocation of the matrix. + * RecordsRemaining (int) + * Number of slots left in the list of allocations. + * NextAvailElement (ElementPtr) + * Pointer to the next available element which has been allocated but as + * yet is unused. Matrix elements are allocated in groups of + * ELEMENTS_PER_ALLOCATION in order to speed element allocation and + * freeing. + * ElementsRemaining (int) + * Number of unused elements left in last block of elements allocated. + * NextAvailFillin (ElementPtr) + * Pointer to the next available fill-in which has been allocated but + * as yet is unused. Fill-ins are allocated in a group in order to keep + * them physically close in memory to the rest of the matrix. + * FillinsRemaining (int) + * Number of unused fill-ins left in the last block of fill-ins + * allocated. + * FirstFillinListNode (FillinListNodeStruct *) + * A pointer to the head of the linked-list that keeps track of the + * lists of fill-ins. + * LastFillinListNode (FillinListNodeStruct *) + * A pointer to the tail of the linked-list that keeps track of the + * lists of fill-ins. + */ + +/* Begin `MatrixFrame'. */ +struct MatrixFrame +{ RealNumber AbsThreshold; + int AllocatedSize; + int AllocatedExtSize; + BOOLEAN Complex; + int CurrentSize; + ArrayOfElementPtrs Diag; + BOOLEAN *DoCmplxDirect; + BOOLEAN *DoRealDirect; + int Elements; + int Error; + int ExtSize; + int *ExtToIntColMap; + int *ExtToIntRowMap; + BOOLEAN Factored; + int Fillins; + ArrayOfElementPtrs FirstInCol; + ArrayOfElementPtrs FirstInRow; + unsigned long ID; + RealVector Intermediate; + BOOLEAN InternalVectorsAllocated; + int *IntToExtColMap; + int *IntToExtRowMap; + int *MarkowitzRow; + int *MarkowitzCol; + long *MarkowitzProd; + int MaxRowCountInLowerTri; + BOOLEAN NeedsOrdering; + BOOLEAN NumberOfInterchangesIsOdd; + BOOLEAN Partitioned; + int PivotsOriginalCol; + int PivotsOriginalRow; + char PivotSelectionMethod; + BOOLEAN PreviousMatrixWasComplex; + RealNumber RelThreshold; + BOOLEAN Reordered; + BOOLEAN RowsLinked; + int SingularCol; + int SingularRow; + int Singletons; + int Size; + struct MatrixElement TrashCan; + + AllocationListPtr TopOfAllocationList; + int RecordsRemaining; + ElementPtr NextAvailElement; + int ElementsRemaining; + ElementPtr NextAvailFillin; + int FillinsRemaining; + struct FillinListNodeStruct *FirstFillinListNode; + struct FillinListNodeStruct *LastFillinListNode; +}; +typedef struct MatrixFrame *MatrixPtr; diff --git a/sis/linsolv/spFactor.c b/sis/linsolv/spFactor.c new file mode 100644 index 0000000..d64e080 --- /dev/null +++ b/sis/linsolv/spFactor.c @@ -0,0 +1,3141 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/linsolv/spFactor.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:04 $ + * + */ +/* + * MATRIX FACTORIZATION MODULE + * + * Author: Advising Professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains the routines to factor the matrix into LU form. + * + * >>> User accessible functions contained in this file: + * spOrderAndFactor + * spFactor + * spPartition + * + * >>> Other functions contained in this file: + * FactorComplexMatrix CreateInternalVectors + * CountMarkowitz MarkowitzProducts + * SearchForPivot SearchForSingleton + * QuicklySearchDiagonal SearchDiagonal + * SearchEntireMatrix FindLargestInCol + * FindBiggestInColExclude ExchangeRowsAndCols + * spcRowExchange spcColExchange + * ExchangeColElements ExchangeRowElements + * RealRowColElimination ComplexRowColElimination + * UpdateMarkowitzNumbers CreateFillin + * MatrixIsSingular ZeroPivot + * WriteStatus + */ + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifndef lint +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header: /users/pchong/CVS/sis/sis/linsolv/spFactor.c,v 1.1.1.1 2004/02/07 10:15:04 pchong Exp $"; +#endif + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spConfig.h" +#include "spMatrix.h" +#include "spDefs.h" + +static void CreateInternalVectors(); +static void CountMarkowitz(); +static void MarkowitzProducts(); +static ElementPtr SearchForPivot(); +static ElementPtr SearchForSingleton(); +static ElementPtr SearchEntireMatrix(); +static RealNumber FindLargestInCol(); +static RealNumber FindBiggestInColExclude(); +static void ExchangeRowsAndCols(); +static void ExchangeColElements(); +static void ExchangeRowElements(); +static void RealRowColElimination(); +static void ComplexRowColElimination(); +static void UpdateMarkowitzNumbers(); +static ElementPtr CreateFillin(); +static int MatrixIsSingular(); +static int ZeroPivot(); + + + +/* + * ORDER AND FACTOR MATRIX + * + * This routine chooses a pivot order for the matrix and factors it + * into LU form. It handles both the initial factorization and subsequent + * factorizations when a reordering is desired. This is handled in a manner + * that is transparent to the user. The routine uses a variation of + * Gauss's method where the pivots are associated with L and the + * diagonal terms of U are one. + * + * >>> Returned: + * The error code is returned. Possible errors are listed below. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * RHS <input> (RealVector) + * Representative right-hand side vector that is used to determine + * pivoting order when the right hand side vector is sparse. If + * RHS is a NULL pointer then the RHS vector is assumed to + * be full and it is not used when determining the pivoting + * order. + * RelThreshold <input> (RealNumber) + * This number determines what the pivot relative threshold will + * be. It should be between zero and one. If it is one then the + * pivoting method becomes complete pivoting, which is very slow + * and tends to fill up the matrix. If it is set close to zero + * the pivoting method becomes strict Markowitz with no + * threshold. The pivot threshold is used to eliminate pivot + * candidates that would cause excessive element growth if they + * were used. Element growth is the cause of roundoff error. + * Element growth occurs even in well-conditioned matrices. + * Setting the RelThreshold large will reduce element growth and + * roundoff error, but setting it too large will cause execution + * time to be excessive and will result in a large number of + * fill-ins. If this occurs, accuracy can actually be degraded + * because of the large number of operations required on the + * matrix due to the large number of fill-ins. A good value seems + * to be 0.001. The default is chosen by giving a value larger + * than one or less than or equal to zero. This value should be + * increased and the matrix resolved if growth is found to be + * excessive. Changing the pivot threshold does not improve + * performance on matrices where growth is low, as is often the + * case with ill-conditioned matrices. Once a valid threshold is + * given, it becomes the new default. The default value of + * RelThreshold was choosen for use with nearly diagonally + * dominant matrices such as node- and modified-node admittance + * matrices. For these matrices it is usually best to use + * diagonal pivoting. For matrices without a strong diagonal, it + * is usually best to use a larger threshold, such as 0.01 or + * 0.1. + * AbsThreshold <input> (RealNumber) + * The absolute magnitude an element must have to be considered + * as a pivot candidate, except as a last resort. This number + * should be set significantly smaller than the smallest diagonal + * element that is is expected to be placed in the matrix. If + * there is no reasonable prediction for the lower bound on these + * elements, then AbsThreshold should be set to zero. + * AbsThreshold is used to reduce the possibility of choosing as a + * pivot an element that has suffered heavy cancellation and as a + * result mainly consists of roundoff error. Once a valid + * threshold is given, it becomes the new default. + * DiagPivoting <input> (BOOLEAN) + * A flag indicating that pivot selection should be confined to the + * diagonal if possible. If DiagPivoting is nonzero and if + * DIAGONAL_PIVOTING is enabled pivots will be chosen only from + * the diagonal unless there are no diagonal elements that satisfy + * the threshold criteria. Otherwise, the entire reduced + * submatrix is searched when looking for a pivot. The diagonal + * pivoting in Sparse is efficient and well refined, while the + * off-diagonal pivoting is not. For symmetric and near symmetric + * matrices, it is best to use diagonal pivoting because it + * results in the best performance when reordering the matrix and + * when factoring the matrix without ordering. If there is a + * considerable amount of nonsymmetry in the matrix, then + * off-diagonal pivoting may result in a better equation ordering + * simply because there are more pivot candidates to choose from. + * A better ordering results in faster subsequent factorizations. + * However, the initial pivot selection process takes considerably + * longer for off-diagonal pivoting. + * + * >>> Local variables: + * pPivot (ElementPtr) + * Pointer to the element being used as a pivot. + * ReorderingRequired (BOOLEAN) + * Flag that indicates whether reordering is required. + * + * >>> Possible errors: + * spNO_MEMORY + * spSINGULAR + * spSMALL_PIVOT + * Error is cleared in this function. + */ + +int +spOrderAndFactor( eMatrix, RHS, RelThreshold, AbsThreshold, DiagPivoting ) + +char *eMatrix; +RealNumber RHS[], RelThreshold, AbsThreshold; +BOOLEAN DiagPivoting; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +ElementPtr pPivot; +int Step, Size, ReorderingRequired; +ElementPtr SearchForPivot(); +RealNumber LargestInCol, FindLargestInCol(); + +/* Begin `spOrderAndFactor'. */ + ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored); + + Matrix->Error = spOKAY; + Size = Matrix->Size; + if (RelThreshold <= 0.0) RelThreshold = Matrix->RelThreshold; + if (RelThreshold > 1.0) RelThreshold = Matrix->RelThreshold; + Matrix->RelThreshold = RelThreshold; + if (AbsThreshold < 0.0) AbsThreshold = Matrix->AbsThreshold; + Matrix->AbsThreshold = AbsThreshold; + ReorderingRequired = NO; + + if (NOT Matrix->NeedsOrdering) + { +/* Matrix has been factored before and reordering is not required. */ + for (Step = 1; Step <= Size; Step++) + { pPivot = Matrix->Diag[Step]; + LargestInCol = FindLargestInCol(pPivot->NextInCol); + if ((LargestInCol * RelThreshold < ELEMENT_MAG(pPivot))) + { if (Matrix->Complex) + ComplexRowColElimination( Matrix, pPivot ); + else + RealRowColElimination( Matrix, pPivot ); + } + else + { ReorderingRequired = YES; + break; /* for loop */ + } + } + if (NOT ReorderingRequired) + goto Done; + else + { +/* + * A pivot was not large enough to maintain accuracy, + * so a partial reordering is required. + */ + +#if ANNOTATE >= ON_STRANGE_BEHAVIOR + printf("Reordering, Step = %1d\n", Step); +#endif + } + } /* End of if(NOT Matrix->NeedsOrdering) */ + else + { +/* + * This is the first time the matrix has been factored. These few statements + * indicate to the rest of the code that a full reodering is required rather + * than a partial reordering, which occurs during a failure of a fast + * factorization. + */ + Step = 1; + if (NOT Matrix->RowsLinked) + spcLinkRows( Matrix ); + if (NOT Matrix->InternalVectorsAllocated) + CreateInternalVectors( Matrix ); + if (Matrix->Error >= spFATAL) + return Matrix->Error; + } + +/* Form initial Markowitz products. */ + CountMarkowitz( Matrix, RHS, Step ); + MarkowitzProducts( Matrix, Step ); + Matrix->MaxRowCountInLowerTri = -1; + +/* Perform reordering and factorization. */ + for (; Step <= Size; Step++) + { pPivot = SearchForPivot( Matrix, Step, DiagPivoting ); + if (pPivot == NULL) return MatrixIsSingular( Matrix, Step ); + ExchangeRowsAndCols( Matrix, pPivot, Step ); + + if (Matrix->Complex) + ComplexRowColElimination( Matrix, pPivot ); + else + RealRowColElimination( Matrix, pPivot ); + + if (Matrix->Error >= spFATAL) return Matrix->Error; + UpdateMarkowitzNumbers( Matrix, pPivot ); + +#if ANNOTATE == FULL + WriteStatus( Matrix, Step ); +#endif + } + +Done: + Matrix->NeedsOrdering = NO; + Matrix->Reordered = YES; + Matrix->Factored = YES; + + return Matrix->Error; +} + + + + + + + +/* + * FACTOR MATRIX + * + * This routine is the companion routine to spOrderAndFactor(). + * Unlike spOrderAndFactor(), spFactor() cannot change the ordering. + * It is also faster than spOrderAndFactor(). The standard way of + * using these two routines is to first use spOrderAndFactor() for the + * initial factorization. For subsequent factorizations, spFactor() + * is used if there is some assurance that little growth will occur + * (say for example, that the matrix is diagonally dominant). If + * spFactor() is called for the initial factorization of the matrix, + * then spOrderAndFactor() is automatically called with the default + * threshold. This routine uses "row at a time" LU factorization. + * Pivots are associated with the lower triangular matrix and the + * diagonals of the upper triangular matrix are ones. + * + * >>> Returned: + * The error code is returned. Possible errors are listed below. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * + * >>> Possible errors: + * spNO_MEMORY + * spSINGULAR + * spZERO_DIAG + * spSMALL_PIVOT + * Error is cleared in this function. + */ + +int +spFactor( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register ElementPtr pColumn; +register int Step, Size; +RealNumber Mult; + +/* Begin `spFactor'. */ + ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored); + + if (Matrix->NeedsOrdering) + { return spOrderAndFactor( eMatrix, (RealVector)NULL, + 0.0, 0.0, DIAG_PIVOTING_AS_DEFAULT ); + } + if (NOT Matrix->Partitioned) spPartition( eMatrix, spDEFAULT_PARTITION ); +#if spCOMPLEX + if (Matrix->Complex) return FactorComplexMatrix( Matrix ); +#endif + +#if REAL + Size = Matrix->Size; + + if (Matrix->Diag[1]->Real == 0.0) return ZeroPivot( Matrix, 1 ); + Matrix->Diag[1]->Real = 1.0 / Matrix->Diag[1]->Real; + +/* Start factorization. */ + for (Step = 2; Step <= Size; Step++) + { if (Matrix->DoRealDirect[Step]) + { /* Update column using direct addressing scatter-gather. */ + register RealNumber *Dest = (RealNumber *)Matrix->Intermediate; + +/* Scatter. */ + pElement = Matrix->FirstInCol[Step]; + while (pElement != NULL) + { Dest[pElement->Row] = pElement->Real; + pElement = pElement->NextInCol; + } + +/* Update column. */ + pColumn = Matrix->FirstInCol[Step]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; + pColumn->Real = Dest[pColumn->Row] * pElement->Real; + while ((pElement = pElement->NextInCol) != NULL) + Dest[pElement->Row] -= pColumn->Real * pElement->Real; + pColumn = pColumn->NextInCol; + } + +/* Gather. */ + pElement = Matrix->Diag[Step]->NextInCol; + while (pElement != NULL) + { pElement->Real = Dest[pElement->Row]; + pElement = pElement->NextInCol; + } + +/* Check for singular matrix. */ + if (Dest[Step] == 0.0) return ZeroPivot( Matrix, Step ); + Matrix->Diag[Step]->Real = 1.0 / Dest[Step]; + } + else + { /* Update column using indirect addressing scatter-gather. */ + register RealNumber **pDest = (RealNumber **)Matrix->Intermediate; + +/* Scatter. */ + pElement = Matrix->FirstInCol[Step]; + while (pElement != NULL) + { pDest[pElement->Row] = &pElement->Real; + pElement = pElement->NextInCol; + } + +/* Update column. */ + pColumn = Matrix->FirstInCol[Step]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; + Mult = (*pDest[pColumn->Row] *= pElement->Real); + while ((pElement = pElement->NextInCol) != NULL) + *pDest[pElement->Row] -= Mult * pElement->Real; + pColumn = pColumn->NextInCol; + } + +/* Check for singular matrix. */ + if (Matrix->Diag[Step]->Real == 0.0) + return ZeroPivot( Matrix, Step ); + Matrix->Diag[Step]->Real = 1.0 / Matrix->Diag[Step]->Real; + } + } + + Matrix->Factored = YES; + return (Matrix->Error = spOKAY); +#endif /* REAL */ +} + + + + + + +#if spCOMPLEX +/* + * FACTOR COMPLEX MATRIX + * + * This routine is the companion routine to spFactor(), it + * handles complex matrices. It is otherwise identical. + * + * >>> Returned: + * The error code is returned. Possible errors are listed below. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * + * >>> Possible errors: + * spSINGULAR + * Error is cleared in this function. + */ + +static int +FactorComplexMatrix( Matrix ) + +MatrixPtr Matrix; +{ +register ElementPtr pElement; +register ElementPtr pColumn; +register int Step, Size; +ComplexNumber Mult, Pivot; + +/* Begin `FactorComplexMatrix'. */ + ASSERT(Matrix->Complex); + + Size = Matrix->Size; + pElement = Matrix->Diag[1]; + if (ELEMENT_MAG(pElement) == 0.0) return ZeroPivot( Matrix, 1 ); +/* Cmplx expr: *pPivot = 1.0 / *pPivot. */ + CMPLX_RECIPROCAL( *pElement, *pElement ); + +/* Start factorization. */ + for (Step = 2; Step <= Size; Step++) + { if (Matrix->DoCmplxDirect[Step]) + { /* Update column using direct addressing scatter-gather. */ + register ComplexNumber *Dest; + Dest = (ComplexNumber *)Matrix->Intermediate; + +/* Scatter. */ + pElement = Matrix->FirstInCol[Step]; + while (pElement != NULL) + { Dest[pElement->Row] = *(ComplexNumber *)pElement; + pElement = pElement->NextInCol; + } + +/* Update column. */ + pColumn = Matrix->FirstInCol[Step]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; + /* Cmplx expr: Mult = Dest[pColumn->Row] * (1.0 / *pPivot). */ + CMPLX_MULT(Mult, Dest[pColumn->Row], *pElement); + CMPLX_ASSIGN(*pColumn, Mult); + while ((pElement = pElement->NextInCol) != NULL) + { /* Cmplx expr: Dest[pElement->Row] -= Mult * pElement */ + CMPLX_MULT_SUBT_ASSIGN(Dest[pElement->Row],Mult,*pElement); + } + pColumn = pColumn->NextInCol; + } + +/* Gather. */ + pElement = Matrix->Diag[Step]->NextInCol; + while (pElement != NULL) + { *(ComplexNumber *)pElement = Dest[pElement->Row]; + pElement = pElement->NextInCol; + } + +/* Check for singular matrix. */ + Pivot = Dest[Step]; + if (CMPLX_1_NORM(Pivot) == 0.0) return ZeroPivot( Matrix, Step ); + CMPLX_RECIPROCAL( *Matrix->Diag[Step], Pivot ); + } + else + { /* Update column using direct addressing scatter-gather. */ + register ComplexNumber **pDest; + pDest = (ComplexNumber **)Matrix->Intermediate; + +/* Scatter. */ + pElement = Matrix->FirstInCol[Step]; + while (pElement != NULL) + { pDest[pElement->Row] = (ComplexNumber *)pElement; + pElement = pElement->NextInCol; + } + +/* Update column. */ + pColumn = Matrix->FirstInCol[Step]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; + /* Cmplx expr: Mult = *pDest[pColumn->Row] * (1.0 / *pPivot). */ + CMPLX_MULT(Mult, *pDest[pColumn->Row], *pElement); + CMPLX_ASSIGN(*pDest[pColumn->Row], Mult); + while ((pElement = pElement->NextInCol) != NULL) + { /* Cmplx expr: *pDest[pElement->Row] -= Mult * pElement */ + CMPLX_MULT_SUBT_ASSIGN(*pDest[pElement->Row],Mult,*pElement); + } + pColumn = pColumn->NextInCol; + } + +/* Check for singular matrix. */ + pElement = Matrix->Diag[Step]; + if (ELEMENT_MAG(pElement) == 0.0) return ZeroPivot( Matrix, Step ); + CMPLX_RECIPROCAL( *pElement, *pElement ); + } + } + + Matrix->Factored = YES; + return (Matrix->Error = spOKAY); +} +#endif /* spCOMPLEX */ + + + + + + +/* + * PARTITION MATRIX + * + * This routine determines the cost to factor each row using both + * direct and indirect addressing and decides, on a row-by-row basis, + * which addressing mode is fastest. This information is used in + * spFactor() to speed the factorization. + * + * When factoring a previously ordered matrix using spFactor(), Sparse + * operates on a row-at-a-time basis. For speed, on each step, the + * row being updated is copied into a full vector and the operations + * are performed on that vector. This can be done one of two ways, + * either using direct addressing or indirect addressing. Direct + * addressing is fastest when the matrix is relatively dense and + * indirect addressing is best when the matrix is quite sparse. The + * user selects the type of partition used with Mode. If Mode is set + * to spDIRECT_PARTITION, then the all rows are placed in the direct + * addressing partition. Similarly, if Mode is set to + * spINDIRECT_PARTITION, then the all rows are placed in the indirect + * addressing partition. By setting Mode to spAUTO_PARTITION, the + * user allows Sparse to select the partition for each row + * individually. spFactor() generally runs faster if Sparse is + * allowed to choose its own partitioning, however choosing a + * partition is expensive. The time required to choose a partition is + * of the same order of the cost to factor the matrix. If you plan to + * factor a large number of matrices with the same structure, it is + * best to let Sparse choose the partition. Otherwise, you should + * choose the partition based on the predicted density of the matrix. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * Mode <input> (int) + * Mode must be one of three special codes: spDIRECT_PARTITION, + * spINDIRECT_PARTITION, or spAUTO_PARTITION. + */ + +void +spPartition( eMatrix, Mode ) + +char *eMatrix; +int Mode; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement, pColumn; +register int Step, Size; +register int *Nc, *No, *Nm; +BOOLEAN *DoRealDirect, *DoCmplxDirect; + +/* Begin `spPartition'. */ + ASSERT( IS_SPARSE( Matrix ) ); + if (Matrix->Partitioned) return; + Size = Matrix->Size; + DoRealDirect = Matrix->DoRealDirect; + DoCmplxDirect = Matrix->DoCmplxDirect; + Matrix->Partitioned = YES; + +/* If partition is specified by the user, this is easy. */ + if (Mode == spDEFAULT_PARTITION) Mode = DEFAULT_PARTITION; + if (Mode == spDIRECT_PARTITION) + { for (Step = 1; Step <= Size; Step++) +#if REAL + DoRealDirect[Step] = YES; +#endif +#if spCOMPLEX + DoCmplxDirect[Step] = YES; +#endif + return; + } + else if (Mode == spINDIRECT_PARTITION) + { for (Step = 1; Step <= Size; Step++) +#if REAL + DoRealDirect[Step] = NO; +#endif +#if spCOMPLEX + DoCmplxDirect[Step] = NO; +#endif + return; + } + else ASSERT( Mode == spAUTO_PARTITION ); + +/* Otherwise, count all operations needed in when factoring matrix. */ + Nc = (int *)Matrix->MarkowitzRow; + No = (int *)Matrix->MarkowitzCol; + Nm = (int *)Matrix->MarkowitzProd; + +/* Start mock-factorization. */ + for (Step = 1; Step <= Size; Step++) + { Nc[Step] = No[Step] = Nm[Step] = 0; + + pElement = Matrix->FirstInCol[Step]; + while (pElement != NULL) + { Nc[Step]++; + pElement = pElement->NextInCol; + } + + pColumn = Matrix->FirstInCol[Step]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; + Nm[Step]++; + while ((pElement = pElement->NextInCol) != NULL) + No[Step]++; + pColumn = pColumn->NextInCol; + } + } + + for (Step = 1; Step <= Size; Step++) + { +/* + * The following are just estimates based on a count on the number of + * machine instructions used on each machine to perform the various + * tasks. It was assumed that each machine instruction required the + * same amount of time (I don't believe this is true for the VAX, and + * have no idea if this is true for the 68000 family). For optimum + * performance, these numbers should be tuned to the machine. + * Nc is the number of nonzero elements in the column. + * Nm is the number of multipliers in the column. + * No is the number of operations in the inner loop. + */ + +#define generic +#ifdef hp9000s300 +#if REAL + DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]); +#endif +#if spCOMPLEX + /* On the hp350, it is never profitable to use direct for complex. */ + DoCmplxDirect[Step] = NO; +#endif +#undef generic +#endif + +#ifdef vax +#if REAL + DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]); +#endif +#if spCOMPLEX + DoCmplxDirect[Step] = (Nm[Step] + No[Step] > 7*Nc[Step] - 4*Nm[Step]); +#endif +#undef generic +#endif + +#ifdef generic +#if REAL + DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]); +#endif +#if spCOMPLEX + DoCmplxDirect[Step] = (Nm[Step] + No[Step] > 7*Nc[Step] - 4*Nm[Step]); +#endif +#undef generic +#endif + } + +#if (ANNOTATE == FULL) + { int Ops = 0; + for (Step = 1; Step <= Size; Step++) + Ops += No[Step]; + printf("Operation count for inner loop of factorization = %d.\n", Ops); + } +#endif + return; +} + + + + + + + +/* + * CREATE INTERNAL VECTORS + * + * Creates the Markowitz and Intermediate vectors. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * + * >>> Local variables: + * SizePlusOne (unsigned) + * Size of the arrays to be allocated. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +CreateInternalVectors( Matrix ) + +MatrixPtr Matrix; +{ +int Size; + +/* Begin `CreateInternalVectors'. */ +/* Create Markowitz arrays. */ + Size= Matrix->Size; + + if (Matrix->MarkowitzRow == NULL) + { if (( Matrix->MarkowitzRow = ALLOC(int, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } + if (Matrix->MarkowitzCol == NULL) + { if (( Matrix->MarkowitzCol = ALLOC(int, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } + if (Matrix->MarkowitzProd == NULL) + { if (( Matrix->MarkowitzProd = ALLOC(long, Size+2)) == NULL) + Matrix->Error = spNO_MEMORY; + } + +/* Create DoDirect vectors for use in spFactor(). */ +#if REAL + if (Matrix->DoRealDirect == NULL) + { if (( Matrix->DoRealDirect = ALLOC(BOOLEAN, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } +#endif +#if spCOMPLEX + if (Matrix->DoCmplxDirect == NULL) + { if (( Matrix->DoCmplxDirect = ALLOC(BOOLEAN, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } +#endif + +/* Create Intermediate vectors for use in MatrixSolve. */ +#if spCOMPLEX + if (Matrix->Intermediate == NULL) + { if ((Matrix->Intermediate = ALLOC(RealNumber,2*(Size+1))) == NULL) + Matrix->Error = spNO_MEMORY; + } +#else + if (Matrix->Intermediate == NULL) + { if ((Matrix->Intermediate = ALLOC(RealNumber, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } +#endif + + if (Matrix->Error != spNO_MEMORY) + Matrix->InternalVectorsAllocated = YES; + return; +} + + + + + + + +/* + * COUNT MARKOWITZ + * + * Scans Matrix to determine the Markowitz counts for each row and column. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * RHS <input> (RealVector) + * Representative right-hand side vector that is used to determine + * pivoting order when the right hand side vector is sparse. If + * RHS is a NULL pointer then the RHS vector is assumed to be full + * and it is not used when determining the pivoting order. + * Step <input> (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * Count (int) + * Temporary counting variable. + * ExtRow (int) + * The external row number that corresponds to I. + * pElement (ElementPtr) + * Pointer to matrix elements. + * Size (int) + * The size of the matrix. + */ + +static void +CountMarkowitz( Matrix, RHS, Step ) + +MatrixPtr Matrix; +register RealVector RHS; +int Step; +{ +register int Count, I, Size = Matrix->Size; +register ElementPtr pElement; +int ExtRow; + +/* Begin `CountMarkowitz'. */ + +/* Correct array pointer for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS OR NOT spCOMPLEX + if (RHS != NULL) --RHS; +#else + if (RHS != NULL) + { if (Matrix->Complex) RHS -= 2; + else --RHS; + } +#endif +#endif + +/* Generate MarkowitzRow Count for each row. */ + for (I = Step; I <= Size; I++) + { +/* Set Count to -1 initially to remove count due to pivot element. */ + Count = -1; + pElement = Matrix->FirstInRow[I]; + while (pElement != NULL AND pElement->Col < Step) + pElement = pElement->NextInRow; + while (pElement != NULL) + { Count++; + pElement = pElement->NextInRow; + } + +/* Include nonzero elements in the RHS vector. */ + ExtRow = Matrix->IntToExtRowMap[I]; + +#if spSEPARATED_COMPLEX_VECTORS OR NOT spCOMPLEX + if (RHS != NULL) + if (RHS[ExtRow] != 0.0) Count++; +#else + if (RHS != NULL) + { if (Matrix->Complex) + { if ((RHS[2*ExtRow] != 0.0) OR (RHS[2*ExtRow+1] != 0.0)) + Count++; + } + else if (RHS[I] != 0.0) Count++; + } +#endif + Matrix->MarkowitzRow[I] = Count; + } + +/* Generate the MarkowitzCol count for each column. */ + for (I = Step; I <= Size; I++) + { +/* Set Count to -1 initially to remove count due to pivot element. */ + Count = -1; + pElement = Matrix->FirstInCol[I]; + while (pElement != NULL AND pElement->Row < Step) + pElement = pElement->NextInCol; + while (pElement != NULL) + { Count++; + pElement = pElement->NextInCol; + } + Matrix->MarkowitzCol[I] = Count; + } + return; +} + + + + + + + + + + +/* + * MARKOWITZ PRODUCTS + * + * Calculates MarkowitzProduct for each diagonal element from the Markowitz + * counts. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * Step <input> (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local Variables: + * pMarkowitzProduct (long *) + * Pointer that points into MarkowitzProduct array. Is used to + * sequentially access entries quickly. + * pMarkowitzRow (int *) + * Pointer that points into MarkowitzRow array. Is used to sequentially + * access entries quickly. + * pMarkowitzCol (int *) + * Pointer that points into MarkowitzCol array. Is used to sequentially + * access entries quickly. + * Product (long) + * Temporary storage for Markowitz product./ + * Size (int) + * The size of the matrix. + */ + +static void +MarkowitzProducts( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +register int I, *pMarkowitzRow, *pMarkowitzCol; +register long Product, *pMarkowitzProduct; +register int Size = Matrix->Size; +double fProduct; + +/* Begin `MarkowitzProducts'. */ + Matrix->Singletons = 0; + + pMarkowitzProduct = &(Matrix->MarkowitzProd[Step]); + pMarkowitzRow = &(Matrix->MarkowitzRow[Step]); + pMarkowitzCol = &(Matrix->MarkowitzCol[Step]); + + for (I = Step; I <= Size; I++) + { +/* If chance of overflow, use real numbers. */ + if ((*pMarkowitzRow > LARGEST_SHORT_INTEGER AND *pMarkowitzCol != 0) OR + (*pMarkowitzCol > LARGEST_SHORT_INTEGER AND *pMarkowitzRow != 0)) + { fProduct = (double)(*pMarkowitzRow++) * (double)(*pMarkowitzCol++); + if (fProduct >= LARGEST_LONG_INTEGER) + *pMarkowitzProduct++ = LARGEST_LONG_INTEGER; + else + *pMarkowitzProduct++ = fProduct; + } + else + { Product = *pMarkowitzRow++ * *pMarkowitzCol++; + if ((*pMarkowitzProduct++ = Product) == 0) + Matrix->Singletons++; + } + } + return; +} + + + + + + + + + + + +/* + * SEARCH FOR BEST PIVOT + * + * Performs a search to determine the element with the lowest Markowitz + * Product that is also acceptable. An acceptable element is one that is + * larger than the AbsThreshold and at least as large as RelThreshold times + * the largest element in the same column. The first step is to look for + * singletons if any exist. If none are found, then all the diagonals are + * searched. The diagonal is searched once quickly using the assumption that + * elements on the diagonal are large compared to other elements in their + * column, and so the pivot can be chosen only on the basis of the Markowitz + * criterion. After a element has been chosen to be pivot on the basis of + * its Markowitz product, it is checked to see if it is large enough. + * Waiting to the end of the Markowitz search to check the size of a pivot + * candidate saves considerable time, but is not guaranteed to find an + * acceptable pivot. Thus if unsuccessful a second pass of the diagonal is + * made. This second pass checks to see if an element is large enough during + * the search, not after it. If still no acceptable pivot candidate has + * been found, the search expands to cover the entire matrix. + * + * >>> Returned: + * A pointer to the element chosen to be pivot. If every element in the + * matrix is zero, then NULL is returned. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * Step <input> (int) + * The row and column number of the beginning of the reduced submatrix. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to element that has been chosen to be the pivot. + * + * >>> Possible errors: + * spSINGULAR + * spSMALL_PIVOT + */ + +static ElementPtr +SearchForPivot( Matrix, Step, DiagPivoting ) + +MatrixPtr Matrix; +int Step, DiagPivoting; +{ +register ElementPtr ChosenPivot; +ElementPtr SearchForSingleton(); +ElementPtr QuicklySearchDiagonal(); +ElementPtr SearchDiagonal(); +ElementPtr SearchEntireMatrix(); + +/* Begin `SearchForPivot'. */ + +/* If singletons exist, look for an acceptable one to use as pivot. */ + if (Matrix->Singletons) + { ChosenPivot = SearchForSingleton( Matrix, Step ); + if (ChosenPivot != NULL) + { Matrix->PivotSelectionMethod = 's'; + return ChosenPivot; + } + } + +#if DIAGONAL_PIVOTING + if (DiagPivoting) + { +/* + * Either no singletons exist or they weren't acceptable. Take quick first + * pass at searching diagonal. First search for element on diagonal of + * remaining submatrix with smallest Markowitz product, then check to see + * if it okay numerically. If not, QuicklySearchDiagonal fails. + */ + ChosenPivot = QuicklySearchDiagonal( Matrix, Step ); + if (ChosenPivot != NULL) + { Matrix->PivotSelectionMethod = 'q'; + return ChosenPivot; + } + +/* + * Quick search of diagonal failed, carefully search diagonal and check each + * pivot candidate numerically before even tentatively accepting it. + */ + ChosenPivot = SearchDiagonal( Matrix, Step ); + if (ChosenPivot != NULL) + { Matrix->PivotSelectionMethod = 'd'; + return ChosenPivot; + } + } +#endif /* DIAGONAL_PIVOTING */ + +/* No acceptable pivot found yet, search entire matrix. */ + ChosenPivot = SearchEntireMatrix( Matrix, Step ); + Matrix->PivotSelectionMethod = 'e'; + + return ChosenPivot; +} + + + + + + + + + +/* + * SEARCH FOR SINGLETON TO USE AS PIVOT + * + * Performs a search to find a singleton to use as the pivot. The + * first acceptable singleton is used. A singleton is acceptable if + * it is larger in magnitude than the AbsThreshold and larger + * than RelThreshold times the largest of any other elements in the same + * column. It may seem that a singleton need not satisfy the + * relative threshold criterion, however it is necessary to prevent + * excessive growth in the RHS from resulting in overflow during the + * forward and backward substitution. A singleton does not need to + * be on the diagonal to be selected. + * + * >>> Returned: + * A pointer to the singleton chosen to be pivot. In no singleton is + * acceptable, return NULL. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * Step <input> (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to element that has been chosen to be the pivot. + * PivotMag (RealNumber) + * Magnitude of ChosenPivot. + * Singletons (int) + * The count of the number of singletons that can be used as pivots. + * A local version of Matrix->Singletons. + * pMarkowitzProduct (long *) + * Pointer that points into MarkowitzProduct array. It is used to quickly + * access successive Markowitz products. + */ + +static ElementPtr +SearchForSingleton( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +register ElementPtr ChosenPivot; +register int I; +register long *pMarkowitzProduct; +int Singletons; +RealNumber PivotMag, FindBiggestInColExclude(); + +/* Begin `SearchForSingleton'. */ +/* Initialize pointer that is to scan through MarkowitzProduct vector. */ + pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+1]); + Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step]; + +/* Decrement the count of available singletons, on the assumption that an + * acceptable one will be found. */ + Singletons = Matrix->Singletons--; + +/* + * Assure that following while loop will always terminate, this is just + * preventive medicine, if things are working right this should never + * be needed. + */ + Matrix->MarkowitzProd[Step-1] = 0; + + while (Singletons-- > 0) + { +/* Singletons exist, find them. */ + +/* + * This is tricky. Am using a pointer to sequentially step through the + * MarkowitzProduct array. Search terminates when singleton (Product = 0) + * is found. Note that the conditional in the while statement + * ( *pMarkowitzProduct ) is true as long as the MarkowitzProduct is not + * equal to zero. The row (and column) index on the diagonal is then + * calculated by subtracting the pointer to the Markowitz product of + * the first diagonal from the pointer to the Markowitz product of the + * desired element, the singleton. + * + * Search proceeds from the end (high row and column numbers) to the + * beginning (low row and column numbers) so that rows and columns with + * large Markowitz products will tend to be move to the bottom of the + * matrix. However, choosing Diag[Step] is desirable because it would + * require no row and column interchanges, so inspect it first by + * putting its Markowitz product at the end of the MarkowitzProd + * vector. + */ + + while ( *pMarkowitzProduct-- ) + { /* + * N bottles of beer on the wall; + * N bottles of beer. + * you take one down and pass it around; + * N-1 bottles of beer on the wall. + */ + } + I = pMarkowitzProduct - Matrix->MarkowitzProd + 1; + +/* Assure that I is valid. */ + if (I < Step) break; /* while (Singletons-- > 0) */ + if (I > Matrix->Size) I = Step; + +/* Singleton has been found in either/both row or/and column I. */ + if ((ChosenPivot = Matrix->Diag[I]) != NULL) + { +/* Singleton lies on the diagonal. */ + PivotMag = ELEMENT_MAG(ChosenPivot); + if + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, ChosenPivot, Step ) + ) return ChosenPivot; + } + else + { +/* Singleton does not lie on diagonal, find it. */ + if (Matrix->MarkowitzCol[I] == 0) + { ChosenPivot = Matrix->FirstInCol[I]; + while ((ChosenPivot != NULL) AND (ChosenPivot->Row < Step)) + ChosenPivot = ChosenPivot->NextInCol; + PivotMag = ELEMENT_MAG(ChosenPivot); + if + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, ChosenPivot, + Step ) + ) return ChosenPivot; + else + { if (Matrix->MarkowitzRow[I] == 0) + { ChosenPivot = Matrix->FirstInRow[I]; + while((ChosenPivot != NULL) AND (ChosenPivot->Col<Step)) + ChosenPivot = ChosenPivot->NextInRow; + PivotMag = ELEMENT_MAG(ChosenPivot); + if + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, + ChosenPivot, + Step ) + ) return ChosenPivot; + } + } + } + else + { ChosenPivot = Matrix->FirstInRow[I]; + while ((ChosenPivot != NULL) AND (ChosenPivot->Col < Step)) + ChosenPivot = ChosenPivot->NextInRow; + PivotMag = ELEMENT_MAG(ChosenPivot); + if + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, ChosenPivot, + Step ) + ) return ChosenPivot; + } + } +/* Singleton not acceptable (too small), try another. */ + } /* end of while(lSingletons>0) */ + +/* + * All singletons were unacceptable. Restore Matrix->Singletons count. + * Initial assumption that an acceptable singleton would be found was wrong. + */ + Matrix->Singletons++; + return NULL; +} + + + + + + + + + + + + +#if DIAGONAL_PIVOTING +#if MODIFIED_MARKOWITZ +/* + * QUICK SEARCH OF DIAGONAL FOR PIVOT WITH MODIFIED MARKOWITZ CRITERION + * + * Searches the diagonal looking for the best pivot. For a pivot to be + * acceptable it must be larger than the pivot RelThreshold times the largest + * element in its reduced column. Among the acceptable diagonals, the + * one with the smallest MarkowitzProduct is sought. Search terminates + * early if a diagonal is found with a MarkowitzProduct of one and its + * magnitude is larger than the other elements in its row and column. + * Since its MarkowitzProduct is one, there is only one other element in + * both its row and column, and, as a condition for early termination, + * these elements must be located symmetricly in the matrix. If a tie + * occurs between elements of equal MarkowitzProduct, then the element with + * the largest ratio between its magnitude and the largest element in its + * column is used. The search will be terminated after a given number of + * ties have occurred and the best (largest ratio) of the tied element will + * be used as the pivot. The number of ties that will trigger an early + * termination is MinMarkowitzProduct * TIES_MULTIPLIER. + * + * >>> Returned: + * A pointer to the diagonal element chosen to be pivot. If no diagonal is + * acceptable, a NULL is returned. + * + * >>> Arguments: + * Step <input> (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to the element that has been chosen to be the pivot. + * LargestOffDiagonal (RealNumber) + * Magnitude of the largest of the off-diagonal terms associated with + * a diagonal with MarkowitzProduct equal to one. + * Magnitude (RealNumber) + * Absolute value of diagonal element. + * MaxRatio (RealNumber) + * Among the elements tied with the smallest Markowitz product, MaxRatio + * is the best (smallest) ratio of LargestInCol to the diagonal Magnitude + * found so far. The smaller the ratio, the better numerically the + * element will be as pivot. + * MinMarkowitzProduct (long) + * Smallest Markowitz product found of pivot candidates that lie along + * diagonal. + * NumberOfTies (int) + * A count of the number of Markowitz ties that have occurred at current + * MarkowitzProduct. + * pDiag (ElementPtr) + * Pointer to current diagonal element. + * pMarkowitzProduct (long *) + * Pointer that points into MarkowitzProduct array. It is used to quickly + * access successive Markowitz products. + * Ratio (RealNumber) + * For the current pivot candidate, Ratio is the ratio of the largest + * element in its column (excluding itself) to its magnitude. + * TiedElements (ElementPtr[]) + * Array of pointers to the elements with the minimum Markowitz + * product. + * pOtherInCol (ElementPtr) + * When there is only one other element in a column other than the + * diagonal, pOtherInCol is used to point to it. Used when Markowitz + * product is to determine if off diagonals are placed symmetricly. + * pOtherInRow (ElementPtr) + * When there is only one other element in a row other than the diagonal, + * pOtherInRow is used to point to it. Used when Markowitz product is + * to determine if off diagonals are placed symmetricly. + */ + +static ElementPtr +QuicklySearchDiagonal( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +register long MinMarkowitzProduct, *pMarkowitzProduct; +register ElementPtr pDiag, pOtherInRow, pOtherInCol; +int I, NumberOfTies; +ElementPtr ChosenPivot, TiedElements[MAX_MARKOWITZ_TIES + 1]; +RealNumber Magnitude, LargestInCol, Ratio, MaxRatio; +RealNumber LargestOffDiagonal; +RealNumber FindBiggestInColExclude(); + +/* Begin `QuicklySearchDiagonal'. */ + NumberOfTies = -1; + MinMarkowitzProduct = LARGEST_LONG_INTEGER; + pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+2]); + Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step]; + +/* Assure that following while loop will always terminate. */ + Matrix->MarkowitzProd[Step-1] = -1; + +/* + * This is tricky. Am using a pointer in the inner while loop to + * sequentially step through the MarkowitzProduct array. Search + * terminates when the Markowitz product of zero placed at location + * Step-1 is found. The row (and column) index on the diagonal is then + * calculated by subtracting the pointer to the Markowitz product of + * the first diagonal from the pointer to the Markowitz product of the + * desired element. The outer for loop is infinite, broken by using + * break. + * + * Search proceeds from the end (high row and column numbers) to the + * beginning (low row and column numbers) so that rows and columns with + * large Markowitz products will tend to be move to the bottom of the + * matrix. However, choosing Diag[Step] is desirable because it would + * require no row and column interchanges, so inspect it first by + * putting its Markowitz product at the end of the MarkowitzProd + * vector. + */ + + for(;;) /* Endless for loop. */ + { while (MinMarkowitzProduct < *(--pMarkowitzProduct)) + { /* + * N bottles of beer on the wall; + * N bottles of beer. + * You take one down and pass it around; + * N-1 bottles of beer on the wall. + */ + } + + I = pMarkowitzProduct - Matrix->MarkowitzProd; + +/* Assure that I is valid; if I < Step, terminate search. */ + if (I < Step) break; /* Endless for loop */ + if (I > Matrix->Size) I = Step; + + if ((pDiag = Matrix->Diag[I]) == NULL) + continue; /* Endless for loop */ + if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold) + continue; /* Endless for loop */ + + if (*pMarkowitzProduct == 1) + { +/* Case where only one element exists in row and column other than diagonal. */ + +/* Find off diagonal elements. */ + pOtherInRow = pDiag->NextInRow; + pOtherInCol = pDiag->NextInCol; + if (pOtherInRow == NULL AND pOtherInCol == NULL) + { pOtherInRow = Matrix->FirstInRow[I]; + while(pOtherInRow != NULL) + { if (pOtherInRow->Col >= Step AND pOtherInRow->Col != I) + break; + pOtherInRow = pOtherInRow->NextInRow; + } + pOtherInCol = Matrix->FirstInCol[I]; + while(pOtherInCol != NULL) + { if (pOtherInCol->Row >= Step AND pOtherInCol->Row != I) + break; + pOtherInCol = pOtherInCol->NextInCol; + } + } + +/* Accept diagonal as pivot if diagonal is larger than off diagonals and the + * off diagonals are placed symmetricly. */ + if (pOtherInRow != NULL AND pOtherInCol != NULL) + { if (pOtherInRow->Col == pOtherInCol->Row) + { LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow), + ELEMENT_MAG(pOtherInCol)); + if (Magnitude >= LargestOffDiagonal) + { +/* Accept pivot, it is unlikely to contribute excess error. */ + return pDiag; + } + } + } + } + + if (*pMarkowitzProduct < MinMarkowitzProduct) + { +/* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */ + TiedElements[0] = pDiag; + MinMarkowitzProduct = *pMarkowitzProduct; + NumberOfTies = 0; + } + else + { +/* This case handles Markowitz ties. */ + if (NumberOfTies < MAX_MARKOWITZ_TIES) + { TiedElements[++NumberOfTies] = pDiag; + if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER) + break; /* Endless for loop */ + } + } + } /* End of endless for loop. */ + +/* Test to see if any element was chosen as a pivot candidate. */ + if (NumberOfTies < 0) + return NULL; + +/* Determine which of tied elements is best numerically. */ + ChosenPivot = NULL; + MaxRatio = 1.0 / Matrix->RelThreshold; + + for (I = 0; I <= NumberOfTies; I++) + { pDiag = TiedElements[I]; + Magnitude = ELEMENT_MAG(pDiag); + LargestInCol = FindBiggestInColExclude( Matrix, pDiag, Step ); + Ratio = LargestInCol / Magnitude; + if (Ratio < MaxRatio) + { ChosenPivot = pDiag; + MaxRatio = Ratio; + } + } + return ChosenPivot; +} + + + + + + + + + + +#else /* Not MODIFIED_MARKOWITZ */ +/* + * QUICK SEARCH OF DIAGONAL FOR PIVOT WITH CONVENTIONAL MARKOWITZ + * CRITERION + * + * Searches the diagonal looking for the best pivot. For a pivot to be + * acceptable it must be larger than the pivot RelThreshold times the largest + * element in its reduced column. Among the acceptable diagonals, the + * one with the smallest MarkowitzProduct is sought. Search terminates + * early if a diagonal is found with a MarkowitzProduct of one and its + * magnitude is larger than the other elements in its row and column. + * Since its MarkowitzProduct is one, there is only one other element in + * both its row and column, and, as a condition for early termination, + * these elements must be located symmetricly in the matrix. + * + * >>> Returned: + * A pointer to the diagonal element chosen to be pivot. If no diagonal is + * acceptable, a NULL is returned. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * Step <input> (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to the element that has been chosen to be the pivot. + * LargestOffDiagonal (RealNumber) + * Magnitude of the largest of the off-diagonal terms associated with + * a diagonal with MarkowitzProduct equal to one. + * Magnitude (RealNumber) + * Absolute value of diagonal element. + * MinMarkowitzProduct (long) + * Smallest Markowitz product found of pivot candidates which are + * acceptable. + * pDiag (ElementPtr) + * Pointer to current diagonal element. + * pMarkowitzProduct (long *) + * Pointer that points into MarkowitzProduct array. It is used to quickly + * access successive Markowitz products. + * pOtherInCol (ElementPtr) + * When there is only one other element in a column other than the + * diagonal, pOtherInCol is used to point to it. Used when Markowitz + * product is to determine if off diagonals are placed symmetricly. + * pOtherInRow (ElementPtr) + * When there is only one other element in a row other than the diagonal, + * pOtherInRow is used to point to it. Used when Markowitz product is + * to determine if off diagonals are placed symmetricly. + */ + +static ElementPtr +QuicklySearchDiagonal( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +register long MinMarkowitzProduct, *pMarkowitzProduct; +register ElementPtr pDiag; +int I; +ElementPtr ChosenPivot, pOtherInRow, pOtherInCol; +RealNumber Magnitude, LargestInCol, LargestOffDiagonal; +RealNumber FindBiggestInColExclude(); + +/* Begin `QuicklySearchDiagonal'. */ + ChosenPivot = NULL; + MinMarkowitzProduct = LARGEST_LONG_INTEGER; + pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+2]); + Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step]; + +/* Assure that following while loop will always terminate. */ + Matrix->MarkowitzProd[Step-1] = -1; + +/* + * This is tricky. Am using a pointer in the inner while loop to + * sequentially step through the MarkowitzProduct array. Search + * terminates when the Markowitz product of zero placed at location + * Step-1 is found. The row (and column) index on the diagonal is then + * calculated by subtracting the pointer to the Markowitz product of + * the first diagonal from the pointer to the Markowitz product of the + * desired element. The outer for loop is infinite, broken by using + * break. + * + * Search proceeds from the end (high row and column numbers) to the + * beginning (low row and column numbers) so that rows and columns with + * large Markowitz products will tend to be move to the bottom of the + * matrix. However, choosing Diag[Step] is desirable because it would + * require no row and column interchanges, so inspect it first by + * putting its Markowitz product at the end of the MarkowitzProd + * vector. + */ + + for (;;) /* Endless for loop. */ + { while (*(--pMarkowitzProduct) >= MinMarkowitzProduct) + { /* Just passing through. */ + } + + I = pMarkowitzProduct - Matrix->MarkowitzProd; + +/* Assure that I is valid; if I < Step, terminate search. */ + if (I < Step) break; /* Endless for loop */ + if (I > Matrix->Size) I = Step; + + if ((pDiag = Matrix->Diag[I]) == NULL) + continue; /* Endless for loop */ + if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold) + continue; /* Endless for loop */ + + if (*pMarkowitzProduct == 1) + { +/* Case where only one element exists in row and column other than diagonal. */ + +/* Find off-diagonal elements. */ + pOtherInRow = pDiag->NextInRow; + pOtherInCol = pDiag->NextInCol; + if (pOtherInRow == NULL AND pOtherInCol == NULL) + { pOtherInRow = Matrix->FirstInRow[I]; + while(pOtherInRow != NULL) + { if (pOtherInRow->Col >= Step AND pOtherInRow->Col != I) + break; + pOtherInRow = pOtherInRow->NextInRow; + } + pOtherInCol = Matrix->FirstInCol[I]; + while(pOtherInCol != NULL) + { if (pOtherInCol->Row >= Step AND pOtherInCol->Row != I) + break; + pOtherInCol = pOtherInCol->NextInCol; + } + } + +/* Accept diagonal as pivot if diagonal is larger than off-diagonals and the + * off-diagonals are placed symmetricly. */ + if (pOtherInRow != NULL AND pOtherInCol != NULL) + { if (pOtherInRow->Col == pOtherInCol->Row) + { LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow), + ELEMENT_MAG(pOtherInCol)); + if (Magnitude >= LargestOffDiagonal) + { +/* Accept pivot, it is unlikely to contribute excess error. */ + return pDiag; + } + } + } + } + + MinMarkowitzProduct = *pMarkowitzProduct; + ChosenPivot = pDiag; + } /* End of endless for loop. */ + + if (ChosenPivot != NULL) + { LargestInCol = FindBiggestInColExclude( Matrix, ChosenPivot, Step ); + if( ELEMENT_MAG(ChosenPivot) <= Matrix->RelThreshold * LargestInCol ) + ChosenPivot = NULL; + } + return ChosenPivot; +} +#endif /* Not MODIFIED_MARKOWITZ */ + + + + + + + + + +/* + * SEARCH DIAGONAL FOR PIVOT WITH MODIFIED MARKOWITZ CRITERION + * + * Searches the diagonal looking for the best pivot. For a pivot to be + * acceptable it must be larger than the pivot RelThreshold times the largest + * element in its reduced column. Among the acceptable diagonals, the + * one with the smallest MarkowitzProduct is sought. If a tie occurs + * between elements of equal MarkowitzProduct, then the element with + * the largest ratio between its magnitude and the largest element in its + * column is used. The search will be terminated after a given number of + * ties have occurred and the best (smallest ratio) of the tied element will + * be used as the pivot. The number of ties that will trigger an early + * termination is MinMarkowitzProduct * TIES_MULTIPLIER. + * + * >>> Returned: + * A pointer to the diagonal element chosen to be pivot. If no diagonal is + * acceptable, a NULL is returned. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * Step <input> (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to the element that has been chosen to be the pivot. + * Size (int) + * Local version of size which is placed in a register to increase speed. + * Magnitude (RealNumber) + * Absolute value of diagonal element. + * MinMarkowitzProduct (long) + * Smallest Markowitz product found of those pivot candidates which are + * acceptable. + * NumberOfTies (int) + * A count of the number of Markowitz ties that have occurred at current + * MarkowitzProduct. + * pDiag (ElementPtr) + * Pointer to current diagonal element. + * pMarkowitzProduct (long*) + * Pointer that points into MarkowitzProduct array. It is used to quickly + * access successive Markowitz products. + * Ratio (RealNumber) + * For the current pivot candidate, Ratio is the + * Ratio of the largest element in its column to its magnitude. + * RatioOfAccepted (RealNumber) + * For the best pivot candidate found so far, RatioOfAccepted is the + * Ratio of the largest element in its column to its magnitude. + */ + +static ElementPtr +SearchDiagonal( Matrix, Step ) + +MatrixPtr Matrix; +register int Step; +{ +register int J; +register long MinMarkowitzProduct, *pMarkowitzProduct; +register int I; +register ElementPtr pDiag; +int NumberOfTies, Size = Matrix->Size; +ElementPtr ChosenPivot; +RealNumber Magnitude, Ratio, RatioOfAccepted, LargestInCol; +RealNumber FindBiggestInColExclude(); + +/* Begin `SearchDiagonal'. */ + ChosenPivot = NULL; + MinMarkowitzProduct = LARGEST_LONG_INTEGER; + pMarkowitzProduct = &(Matrix->MarkowitzProd[Size+2]); + Matrix->MarkowitzProd[Size+1] = Matrix->MarkowitzProd[Step]; + +/* Start search of diagonal. */ + for (J = Size+1; J > Step; J--) + { + if (*(--pMarkowitzProduct) > MinMarkowitzProduct) + continue; /* for loop */ + if (J > Matrix->Size) + I = Step; + else + I = J; + if ((pDiag = Matrix->Diag[I]) == NULL) + continue; /* for loop */ + if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold) + continue; /* for loop */ + +/* Test to see if diagonal's magnitude is acceptable. */ + LargestInCol = FindBiggestInColExclude( Matrix, pDiag, Step ); + if (Magnitude <= Matrix->RelThreshold * LargestInCol) + continue; /* for loop */ + + if (*pMarkowitzProduct < MinMarkowitzProduct) + { +/* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */ + ChosenPivot = pDiag; + MinMarkowitzProduct = *pMarkowitzProduct; + RatioOfAccepted = LargestInCol / Magnitude; + NumberOfTies = 0; + } + else + { +/* This case handles Markowitz ties. */ + NumberOfTies++; + Ratio = LargestInCol / Magnitude; + if (Ratio < RatioOfAccepted) + { ChosenPivot = pDiag; + RatioOfAccepted = Ratio; + } + if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER) + return ChosenPivot; + } + } /* End of for(Step) */ + return ChosenPivot; +} +#endif /* DIAGONAL_PIVOTING */ + + + + + + + + + + +/* + * SEARCH ENTIRE MATRIX FOR BEST PIVOT + * + * Performs a search over the entire matrix looking for the acceptable + * element with the lowest MarkowitzProduct. If there are several that + * are tied for the smallest MarkowitzProduct, the tie is broken by using + * the ratio of the magnitude of the element being considered to the largest + * element in the same column. If no element is acceptable then the largest + * element in the reduced submatrix is used as the pivot and the + * matrix is declared to be spSMALL_PIVOT. If the largest element is + * zero, the matrix is declared to be spSINGULAR. + * + * >>> Returned: + * A pointer to the diagonal element chosen to be pivot. If no element is + * found, then NULL is returned and the matrix is spSINGULAR. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * Step <input> (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to the element that has been chosen to be the pivot. + * LargestElementMag (RealNumber) + * Magnitude of the largest element yet found in the reduced submatrix. + * Size (int) + * Local version of Size; placed in a register for speed. + * Magnitude (RealNumber) + * Absolute value of diagonal element. + * MinMarkowitzProduct (long) + * Smallest Markowitz product found of pivot candidates which are + * acceptable. + * NumberOfTies (int) + * A count of the number of Markowitz ties that have occurred at current + * MarkowitzProduct. + * pElement (ElementPtr) + * Pointer to current element. + * pLargestElement (ElementPtr) + * Pointer to the largest element yet found in the reduced submatrix. + * Product (long) + * Markowitz product for the current row and column. + * Ratio (RealNumber) + * For the current pivot candidate, Ratio is the + * Ratio of the largest element in its column to its magnitude. + * RatioOfAccepted (RealNumber) + * For the best pivot candidate found so far, RatioOfAccepted is the + * Ratio of the largest element in its column to its magnitude. + * + * >>> Possible errors: + * spSINGULAR + * spSMALL_PIVOT + */ + +static ElementPtr +SearchEntireMatrix( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +register int I, Size = Matrix->Size; +register ElementPtr pElement; +int NumberOfTies; +long Product, MinMarkowitzProduct; +ElementPtr ChosenPivot, pLargestElement; +RealNumber Magnitude, LargestElementMag, Ratio, RatioOfAccepted, LargestInCol; +RealNumber FindLargestInCol(); + +/* Begin `SearchEntireMatrix'. */ + ChosenPivot = NULL; + LargestElementMag = 0.0; + MinMarkowitzProduct = LARGEST_LONG_INTEGER; + +/* Start search of matrix on column by column basis. */ + for (I = Step; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; + + while (pElement != NULL AND pElement->Row < Step) + pElement = pElement->NextInCol; + + if((LargestInCol = FindLargestInCol(pElement)) == 0.0) + continue; /* for loop */ + + while (pElement != NULL) + { +/* Check to see if element is the largest encountered so far. If so, record + its magnitude and address. */ + if ((Magnitude = ELEMENT_MAG(pElement)) > LargestElementMag) + { LargestElementMag = Magnitude; + pLargestElement = pElement; + } +/* Calculate element's MarkowitzProduct. */ + Product = Matrix->MarkowitzRow[pElement->Row] * + Matrix->MarkowitzCol[pElement->Col]; + +/* Test to see if element is acceptable as a pivot candidate. */ + if ((Product <= MinMarkowitzProduct) AND + (Magnitude > Matrix->RelThreshold * LargestInCol) AND + (Magnitude > Matrix->AbsThreshold)) + { +/* Test to see if element has lowest MarkowitzProduct yet found, or whether it + is tied with an element found earlier. */ + if (Product < MinMarkowitzProduct) + { +/* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */ + ChosenPivot = pElement; + MinMarkowitzProduct = Product; + RatioOfAccepted = LargestInCol / Magnitude; + NumberOfTies = 0; + } + else + { +/* This case handles Markowitz ties. */ + NumberOfTies++; + Ratio = LargestInCol / Magnitude; + if (Ratio < RatioOfAccepted) + { ChosenPivot = pElement; + RatioOfAccepted = Ratio; + } + if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER) + return ChosenPivot; + } + } + pElement = pElement->NextInCol; + } /* End of while(pElement != NULL) */ + } /* End of for(Step) */ + + if (ChosenPivot != NULL) return ChosenPivot; + + if (LargestElementMag == 0.0) + { Matrix->Error = spSINGULAR; + return NULL; + } + + Matrix->Error = spSMALL_PIVOT; + return pLargestElement; +} + + + + + + + + + + + + +/* + * DETERMINE THE MAGNITUDE OF THE LARGEST ELEMENT IN A COLUMN + * + * This routine searches a column and returns the magnitude of the largest + * element. This routine begins the search at the element pointed to by + * pElement, the parameter. + * + * The search is conducted by starting at the element specified by a pointer, + * which should be one below the diagonal, and moving down the column. On + * the way down the column, the magnitudes of the elements are tested to see + * if they are the largest yet found. + * + * >>> Returned: + * The magnitude of the largest element in the column below and including + * the one pointed to by the input parameter. + * + * >>> Arguments: + * pElement <input> (ElementPtr) + * The pointer to the first element to be tested. Also, used by the + * routine to access all lower elements in the column. + * + * >>> Local variables: + * Largest (RealNumber) + * The magnitude of the largest element. + * Magnitude (RealNumber) + * The magnitude of the currently active element. + */ + +static RealNumber +FindLargestInCol( pElement ) + +register ElementPtr pElement; +{ +RealNumber Magnitude, Largest = 0.0; + +/* Begin `FindLargestInCol'. */ +/* Search column for largest element beginning at Element. */ + while (pElement != NULL) + { if ((Magnitude = ELEMENT_MAG(pElement)) > Largest) + Largest = Magnitude; + pElement = pElement->NextInCol; + } + + return Largest; +} + + + + + + + + + + +/* + * DETERMINE THE MAGNITUDE OF THE LARGEST ELEMENT IN A COLUMN + * EXCLUDING AN ELEMENT + * + * This routine searches a column and returns the magnitude of the largest + * element. One given element is specifically excluded from the search. + * + * The search is conducted by starting at the first element in the column + * and moving down the column until the active part of the matrix is entered, + * i.e. the reduced submatrix. The rest of the column is then traversed + * looking for the largest element. + * + * >>> Returned: + * The magnitude of the largest element in the active portion of the column, + * excluding the specified element, is returned. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * pElement <input> (ElementPtr) + * The pointer to the element that is to be excluded from search. Column + * to be searched is one that contains this element. Also used to + * access the elements in the column. + * Step <input> (int) + * Index of the diagonal currently being eliminated. Indicates where + * the active part of the matrix begins. + * + * >>> Local variables: + * Col (int) + * The number of the column to be searched. Also the column number of + * the element to be avoided in the search. + * Largest (RealNumber) + * The magnitude of the largest element. + * Magnitude (RealNumber) + * The magnitude of the currently active element. + * Row (int) + * The row number of element to be excluded from the search. + */ + +static RealNumber +FindBiggestInColExclude( Matrix, pElement, Step ) + +MatrixPtr Matrix; +register ElementPtr pElement; +register int Step; +{ +register int Row; +int Col; +RealNumber Largest, Magnitude; + +/* Begin `FindBiggestInColExclude'. */ + Row = pElement->Row; + Col = pElement->Col; + pElement = Matrix->FirstInCol[Col]; + +/* Travel down column until reduced submatrix is entered. */ + while ((pElement != NULL) AND (pElement->Row < Step)) + pElement = pElement->NextInCol; + +/* Initialize the variable Largest. */ + if (pElement->Row != Row) + Largest = ELEMENT_MAG(pElement); + else + Largest = 0.0; + +/* Search rest of column for largest element, avoiding excluded element. */ + while ((pElement = pElement->NextInCol) != NULL) + { if ((Magnitude = ELEMENT_MAG(pElement)) > Largest) + { if (pElement->Row != Row) + Largest = Magnitude; + } + } + + return Largest; +} + + + + + + + + + + +/* + * EXCHANGE ROWS AND COLUMNS + * + * Exchanges two rows and two columns so that the selected pivot is moved to + * the upper left corner of the remaining submatrix. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * pPivot <input> (ElementPtr) + * Pointer to the current pivot. + * Step <input> (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * Col (int) + * Column where the pivot was found. + * Row (int) + * Row where the pivot was found. + * OldMarkowitzProd_Col (long) + * Markowitz product associated with the diagonal element in the row + * the pivot was found in. + * OldMarkowitzProd_Row (long) + * Markowitz product associated with the diagonal element in the column + * the pivot was found in. + * OldMarkowitzProd_Step (long) + * Markowitz product associated with the diagonal element that is being + * moved so that the pivot can be placed in the upper left-hand corner + * of the reduced submatrix. + */ + +static void +ExchangeRowsAndCols( Matrix, pPivot, Step ) + +MatrixPtr Matrix; +ElementPtr pPivot; +register int Step; +{ +register int Row, Col; +long OldMarkowitzProd_Step, OldMarkowitzProd_Row, OldMarkowitzProd_Col; +ElementPtr spcFindElementInCol(); + +/* Begin `ExchangeRowsAndCols'. */ + Row = pPivot->Row; + Col = pPivot->Col; + Matrix->PivotsOriginalRow = Row; + Matrix->PivotsOriginalCol = Col; + + if ((Row == Step) AND (Col == Step)) return; + +/* Exchange rows and columns. */ + if (Row == Col) + { spcRowExchange( Matrix, Step, Row ); + spcColExchange( Matrix, Step, Col ); + SWAP( long, Matrix->MarkowitzProd[Step], Matrix->MarkowitzProd[Row] ); + SWAP( ElementPtr, Matrix->Diag[Row], Matrix->Diag[Step] ); + } + else + { + +/* Initialize variables that hold old Markowitz products. */ + OldMarkowitzProd_Step = Matrix->MarkowitzProd[Step]; + OldMarkowitzProd_Row = Matrix->MarkowitzProd[Row]; + OldMarkowitzProd_Col = Matrix->MarkowitzProd[Col]; + +/* Exchange rows. */ + if (Row != Step) + { spcRowExchange( Matrix, Step, Row ); + Matrix->NumberOfInterchangesIsOdd = + NOT Matrix->NumberOfInterchangesIsOdd; + Matrix->MarkowitzProd[Row] = Matrix->MarkowitzRow[Row] * + Matrix->MarkowitzCol[Row]; + +/* Update singleton count. */ + if ((Matrix->MarkowitzProd[Row]==0) != (OldMarkowitzProd_Row==0)) + { if (OldMarkowitzProd_Row == 0) + Matrix->Singletons--; + else + Matrix->Singletons++; + } + } + +/* Exchange columns. */ + if (Col != Step) + { spcColExchange( Matrix, Step, Col ); + Matrix->NumberOfInterchangesIsOdd = + NOT Matrix->NumberOfInterchangesIsOdd; + Matrix->MarkowitzProd[Col] = Matrix->MarkowitzCol[Col] * + Matrix->MarkowitzRow[Col]; + +/* Update singleton count. */ + if ((Matrix->MarkowitzProd[Col]==0) != (OldMarkowitzProd_Col==0)) + { if (OldMarkowitzProd_Col == 0) + Matrix->Singletons--; + else + Matrix->Singletons++; + } + + Matrix->Diag[Col] = spcFindElementInCol( Matrix, + Matrix->FirstInCol+Col, + Col, Col, NO ); + } + if (Row != Step) + { Matrix->Diag[Row] = spcFindElementInCol( Matrix, + Matrix->FirstInCol+Row, + Row, Row, NO ); + } + Matrix->Diag[Step] = spcFindElementInCol( Matrix, + Matrix->FirstInCol+Step, + Step, Step, NO ); + +/* Update singleton count. */ + Matrix->MarkowitzProd[Step] = Matrix->MarkowitzCol[Step] * + Matrix->MarkowitzRow[Step]; + if ((Matrix->MarkowitzProd[Step]==0) != (OldMarkowitzProd_Step==0)) + { if (OldMarkowitzProd_Step == 0) + Matrix->Singletons--; + else + Matrix->Singletons++; + } + } + return; +} + + + + + + + + + +/* + * EXCHANGE ROWS + * + * Performs all required operations to exchange two rows. Those operations + * include: swap FirstInRow pointers, fixing up the NextInCol pointers, + * swapping row indexes in MatrixElements, and swapping Markowitz row + * counts. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * Row1 <input> (int) + * Row index of one of the rows, becomes the smallest index. + * Row2 <input> (int) + * Row index of the other row, becomes the largest index. + * + * Local variables: + * Column (int) + * Column in which row elements are currently being exchanged. + * Row1Ptr (ElementPtr) + * Pointer to an element in Row1. + * Row2Ptr (ElementPtr) + * Pointer to an element in Row2. + * Element1 (ElementPtr) + * Pointer to the element in Row1 to be exchanged. + * Element2 (ElementPtr) + * Pointer to the element in Row2 to be exchanged. + */ + +spcRowExchange( Matrix, Row1, Row2 ) + +MatrixPtr Matrix; +int Row1, Row2; +{ +register ElementPtr Row1Ptr, Row2Ptr; +int Column; +ElementPtr Element1, Element2; + +/* Begin `spcRowExchange'. */ + if (Row1 > Row2) SWAP(int, Row1, Row2); + + Row1Ptr = Matrix->FirstInRow[Row1]; + Row2Ptr = Matrix->FirstInRow[Row2]; + while (Row1Ptr != NULL OR Row2Ptr != NULL) + { +/* Exchange elements in rows while traveling from left to right. */ + if (Row1Ptr == NULL) + { Column = Row2Ptr->Col; + Element1 = NULL; + Element2 = Row2Ptr; + Row2Ptr = Row2Ptr->NextInRow; + } + else if (Row2Ptr == NULL) + { Column = Row1Ptr->Col; + Element1 = Row1Ptr; + Element2 = NULL; + Row1Ptr = Row1Ptr->NextInRow; + } + else if (Row1Ptr->Col < Row2Ptr->Col) + { Column = Row1Ptr->Col; + Element1 = Row1Ptr; + Element2 = NULL; + Row1Ptr = Row1Ptr->NextInRow; + } + else if (Row1Ptr->Col > Row2Ptr->Col) + { Column = Row2Ptr->Col; + Element1 = NULL; + Element2 = Row2Ptr; + Row2Ptr = Row2Ptr->NextInRow; + } + else /* Row1Ptr->Col == Row2Ptr->Col */ + { Column = Row1Ptr->Col; + Element1 = Row1Ptr; + Element2 = Row2Ptr; + Row1Ptr = Row1Ptr->NextInRow; + Row2Ptr = Row2Ptr->NextInRow; + } + + ExchangeColElements( Matrix, Row1, Element1, Row2, Element2, Column); + } /* end of while(Row1Ptr != NULL OR Row2Ptr != NULL) */ + + if (Matrix->InternalVectorsAllocated) + SWAP( int, Matrix->MarkowitzRow[Row1], Matrix->MarkowitzRow[Row2]); + SWAP( ElementPtr, Matrix->FirstInRow[Row1], Matrix->FirstInRow[Row2]); + SWAP( int, Matrix->IntToExtRowMap[Row1], Matrix->IntToExtRowMap[Row2]); +#if TRANSLATE + Matrix->ExtToIntRowMap[ Matrix->IntToExtRowMap[Row1] ] = Row1; + Matrix->ExtToIntRowMap[ Matrix->IntToExtRowMap[Row2] ] = Row2; +#endif + + return; +} + + + + + + + + + +/* + * EXCHANGE COLUMNS + * + * Performs all required operations to exchange two columns. Those operations + * include: swap FirstInCol pointers, fixing up the NextInRow pointers, + * swapping column indexes in MatrixElements, and swapping Markowitz + * column counts. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * Col1 <input> (int) + * Column index of one of the columns, becomes the smallest index. + * Col2 <input> (int) + * Column index of the other column, becomes the largest index + * + * Local variables: + * Row (int) + * Row in which column elements are currently being exchanged. + * Col1Ptr (ElementPtr) + * Pointer to an element in Col1. + * Col2Ptr (ElementPtr) + * Pointer to an element in Col2. + * Element1 (ElementPtr) + * Pointer to the element in Col1 to be exchanged. + * Element2 (ElementPtr) + * Pointer to the element in Col2 to be exchanged. + */ + +spcColExchange( Matrix, Col1, Col2 ) + +MatrixPtr Matrix; +int Col1, Col2; +{ +register ElementPtr Col1Ptr, Col2Ptr; +int Row; +ElementPtr Element1, Element2; + +/* Begin `spcColExchange'. */ + if (Col1 > Col2) SWAP(int, Col1, Col2); + + Col1Ptr = Matrix->FirstInCol[Col1]; + Col2Ptr = Matrix->FirstInCol[Col2]; + while (Col1Ptr != NULL OR Col2Ptr != NULL) + { +/* Exchange elements in rows while traveling from top to bottom. */ + if (Col1Ptr == NULL) + { Row = Col2Ptr->Row; + Element1 = NULL; + Element2 = Col2Ptr; + Col2Ptr = Col2Ptr->NextInCol; + } + else if (Col2Ptr == NULL) + { Row = Col1Ptr->Row; + Element1 = Col1Ptr; + Element2 = NULL; + Col1Ptr = Col1Ptr->NextInCol; + } + else if (Col1Ptr->Row < Col2Ptr->Row) + { Row = Col1Ptr->Row; + Element1 = Col1Ptr; + Element2 = NULL; + Col1Ptr = Col1Ptr->NextInCol; + } + else if (Col1Ptr->Row > Col2Ptr->Row) + { Row = Col2Ptr->Row; + Element1 = NULL; + Element2 = Col2Ptr; + Col2Ptr = Col2Ptr->NextInCol; + } + else /* Col1Ptr->Row == Col2Ptr->Row */ + { Row = Col1Ptr->Row; + Element1 = Col1Ptr; + Element2 = Col2Ptr; + Col1Ptr = Col1Ptr->NextInCol; + Col2Ptr = Col2Ptr->NextInCol; + } + + ExchangeRowElements( Matrix, Col1, Element1, Col2, Element2, Row); + } /* end of while(Col1Ptr != NULL OR Col2Ptr != NULL) */ + + if (Matrix->InternalVectorsAllocated) + SWAP( int, Matrix->MarkowitzCol[Col1], Matrix->MarkowitzCol[Col2]); + SWAP( ElementPtr, Matrix->FirstInCol[Col1], Matrix->FirstInCol[Col2]); + SWAP( int, Matrix->IntToExtColMap[Col1], Matrix->IntToExtColMap[Col2]); +#if TRANSLATE + Matrix->ExtToIntColMap[ Matrix->IntToExtColMap[Col1] ] = Col1; + Matrix->ExtToIntColMap[ Matrix->IntToExtColMap[Col2] ] = Col2; +#endif + + return; +} + + + + + + + +/* + * EXCHANGE TWO ELEMENTS IN A COLUMN + * + * Performs all required operations to exchange two elements in a column. + * Those operations are: restring NextInCol pointers and swapping row indexes + * in the MatrixElements. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * Row1 <input> (int) + * Row of top element to be exchanged. + * Element1 <input> (ElementPtr) + * Pointer to top element to be exchanged. + * Row2 <input> (int) + * Row of bottom element to be exchanged. + * Element2 <input> (ElementPtr) + * Pointer to bottom element to be exchanged. + * Column <input> (int) + * Column that exchange is to take place in. + * + * >>> Local variables: + * ElementAboveRow1 (ElementPtr *) + * Location of pointer which points to the element above Element1. This + * pointer is modified so that it points to correct element on exit. + * ElementAboveRow2 (ElementPtr *) + * Location of pointer which points to the element above Element2. This + * pointer is modified so that it points to correct element on exit. + * ElementBelowRow1 (ElementPtr) + * Pointer to element below Element1. + * ElementBelowRow2 (ElementPtr) + * Pointer to element below Element2. + * pElement (ElementPtr) + * Pointer used to traverse the column. + */ + +static void +ExchangeColElements( Matrix, Row1, Element1, Row2, Element2, Column ) + +MatrixPtr Matrix; +register ElementPtr Element1, Element2; +int Row1, Row2, Column; +{ +ElementPtr *ElementAboveRow1, *ElementAboveRow2; +ElementPtr ElementBelowRow1, ElementBelowRow2; +register ElementPtr pElement; + +/* Begin `ExchangeColElements'. */ +/* Search to find the ElementAboveRow1. */ + ElementAboveRow1 = &(Matrix->FirstInCol[Column]); + pElement = *ElementAboveRow1; + while (pElement->Row < Row1) + { ElementAboveRow1 = &(pElement->NextInCol); + pElement = *ElementAboveRow1; + } + if (Element1 != NULL) + { ElementBelowRow1 = Element1->NextInCol; + if (Element2 == NULL) + { +/* Element2 does not exist, move Element1 down to Row2. */ + if ( ElementBelowRow1 != NULL AND ElementBelowRow1->Row < Row2 ) + { +/* Element1 must be removed from linked list and moved. */ + *ElementAboveRow1 = ElementBelowRow1; + +/* Search column for Row2. */ + pElement = ElementBelowRow1; + do + { ElementAboveRow2 = &(pElement->NextInCol); + pElement = *ElementAboveRow2; + } while (pElement != NULL AND pElement->Row < Row2); + +/* Place Element1 in Row2. */ + *ElementAboveRow2 = Element1; + Element1->NextInCol = pElement; + *ElementAboveRow1 =ElementBelowRow1; + } + Element1->Row = Row2; + } + else + { +/* Element2 does exist, and the two elements must be exchanged. */ + if ( ElementBelowRow1->Row == Row2) + { +/* Element2 is just below Element1, exchange them. */ + Element1->NextInCol = Element2->NextInCol; + Element2->NextInCol = Element1; + *ElementAboveRow1 = Element2; + } + else + { +/* Element2 is not just below Element1 and must be searched for. */ + pElement = ElementBelowRow1; + do + { ElementAboveRow2 = &(pElement->NextInCol); + pElement = *ElementAboveRow2; + } while (pElement->Row < Row2); + + ElementBelowRow2 = Element2->NextInCol; + +/* Switch Element1 and Element2. */ + *ElementAboveRow1 = Element2; + Element2->NextInCol = ElementBelowRow1; + *ElementAboveRow2 = Element1; + Element1->NextInCol = ElementBelowRow2; + } + Element1->Row = Row2; + Element2->Row = Row1; + } + } + else + { +/* Element1 does not exist. */ + ElementBelowRow1 = pElement; + +/* Find Element2. */ + if (ElementBelowRow1->Row != Row2) + { do + { ElementAboveRow2 = &(pElement->NextInCol); + pElement = *ElementAboveRow2; + } while (pElement->Row < Row2); + + ElementBelowRow2 = Element2->NextInCol; + +/* Move Element2 to Row1. */ + *ElementAboveRow2 = Element2->NextInCol; + *ElementAboveRow1 = Element2; + Element2->NextInCol = ElementBelowRow1; + } + Element2->Row = Row1; + } + return; +} + + + + + + + +/* + * EXCHANGE TWO ELEMENTS IN A ROW + * + * Performs all required operations to exchange two elements in a row. + * Those operations are: restring NextInRow pointers and swapping column + * indexes in the MatrixElements. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * Col1 <input> (int) + * Col of left-most element to be exchanged. + * Element1 <input> (ElementPtr) + * Pointer to left-most element to be exchanged. + * Col2 <input> (int) + * Col of right-most element to be exchanged. + * Element2 <input> (ElementPtr) + * Pointer to right-most element to be exchanged. + * Row <input> (int) + * Row that exchange is to take place in. + * + * >>> Local variables: + * ElementLeftOfCol1 (ElementPtr *) + * Location of pointer which points to the element to the left of + * Element1. This pointer is modified so that it points to correct + * element on exit. + * ElementLeftOfCol2 (ElementPtr *) + * Location of pointer which points to the element to the left of + * Element2. This pointer is modified so that it points to correct + * element on exit. + * ElementRightOfCol1 (ElementPtr) + * Pointer to element right of Element1. + * ElementRightOfCol2 (ElementPtr) + * Pointer to element right of Element2. + * pElement (ElementPtr) + * Pointer used to traverse the row. + */ + +static void +ExchangeRowElements( Matrix, Col1, Element1, Col2, Element2, Row ) + +MatrixPtr Matrix; +int Col1, Col2, Row; +register ElementPtr Element1, Element2; +{ +ElementPtr *ElementLeftOfCol1, *ElementLeftOfCol2; +ElementPtr ElementRightOfCol1, ElementRightOfCol2; +register ElementPtr pElement; + +/* Begin `ExchangeRowElements'. */ +/* Search to find the ElementLeftOfCol1. */ + ElementLeftOfCol1 = &(Matrix->FirstInRow[Row]); + pElement = *ElementLeftOfCol1; + while (pElement->Col < Col1) + { ElementLeftOfCol1 = &(pElement->NextInRow); + pElement = *ElementLeftOfCol1; + } + if (Element1 != NULL) + { ElementRightOfCol1 = Element1->NextInRow; + if (Element2 == NULL) + { +/* Element2 does not exist, move Element1 to right to Col2. */ + if ( ElementRightOfCol1 != NULL AND ElementRightOfCol1->Col < Col2 ) + { +/* Element1 must be removed from linked list and moved. */ + *ElementLeftOfCol1 = ElementRightOfCol1; + +/* Search Row for Col2. */ + pElement = ElementRightOfCol1; + do + { ElementLeftOfCol2 = &(pElement->NextInRow); + pElement = *ElementLeftOfCol2; + } while (pElement != NULL AND pElement->Col < Col2); + +/* Place Element1 in Col2. */ + *ElementLeftOfCol2 = Element1; + Element1->NextInRow = pElement; + *ElementLeftOfCol1 =ElementRightOfCol1; + } + Element1->Col = Col2; + } + else + { +/* Element2 does exist, and the two elements must be exchanged. */ + if ( ElementRightOfCol1->Col == Col2) + { +/* Element2 is just right of Element1, exchange them. */ + Element1->NextInRow = Element2->NextInRow; + Element2->NextInRow = Element1; + *ElementLeftOfCol1 = Element2; + } + else + { +/* Element2 is not just right of Element1 and must be searched for. */ + pElement = ElementRightOfCol1; + do + { ElementLeftOfCol2 = &(pElement->NextInRow); + pElement = *ElementLeftOfCol2; + } while (pElement->Col < Col2); + + ElementRightOfCol2 = Element2->NextInRow; + +/* Switch Element1 and Element2. */ + *ElementLeftOfCol1 = Element2; + Element2->NextInRow = ElementRightOfCol1; + *ElementLeftOfCol2 = Element1; + Element1->NextInRow = ElementRightOfCol2; + } + Element1->Col = Col2; + Element2->Col = Col1; + } + } + else + { +/* Element1 does not exist. */ + ElementRightOfCol1 = pElement; + +/* Find Element2. */ + if (ElementRightOfCol1->Col != Col2) + { do + { ElementLeftOfCol2 = &(pElement->NextInRow); + pElement = *ElementLeftOfCol2; + } while (pElement->Col < Col2); + + ElementRightOfCol2 = Element2->NextInRow; + +/* Move Element2 to Col1. */ + *ElementLeftOfCol2 = Element2->NextInRow; + *ElementLeftOfCol1 = Element2; + Element2->NextInRow = ElementRightOfCol1; + } + Element2->Col = Col1; + } + return; +} + + + + + + + + + + + +/* + * PERFORM ROW AND COLUMN ELIMINATION ON REAL MATRIX + * + * Eliminates a single row and column of the matrix and leaves single row of + * the upper triangular matrix and a single column of the lower triangular + * matrix in its wake. Uses Gauss's method. + * + * >>> Argument: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * pPivot <input> (ElementPtr) + * Pointer to the current pivot. + * + * >>> Local variables: + * pLower (ElementPtr) + * Points to matrix element in lower triangular column. + * pSub (ElementPtr) + * Points to elements in the reduced submatrix. + * Row (int) + * Row index. + * pUpper (ElementPtr) + * Points to matrix element in upper triangular row. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +RealRowColElimination( Matrix, pPivot ) + +MatrixPtr Matrix; +register ElementPtr pPivot; +{ +#if REAL +register ElementPtr pSub; +register int Row; +register ElementPtr pLower, pUpper; +extern ElementPtr CreateFillin(); + +/* Begin `RealRowColElimination'. */ + +/* Test for zero pivot. */ + if (ABS(pPivot->Real) == 0.0) + { (void)MatrixIsSingular( Matrix, pPivot->Row ); + return; + } + pPivot->Real = 1.0 / pPivot->Real; + + pUpper = pPivot->NextInRow; + while (pUpper != NULL) + { +/* Calculate upper triangular element. */ + pUpper->Real *= pPivot->Real; + + pSub = pUpper->NextInCol; + pLower = pPivot->NextInCol; + while (pLower != NULL) + { Row = pLower->Row; + +/* Find element in row that lines up with current lower triangular element. */ + while (pSub != NULL AND pSub->Row < Row) + pSub = pSub->NextInCol; + +/* Test to see if desired element was not found, if not, create fill-in. */ + if (pSub == NULL OR pSub->Row > Row) + { pSub = CreateFillin( Matrix, Row, pUpper->Col ); + if (pSub == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + } + pSub->Real -= pUpper->Real * pLower->Real; + pSub = pSub->NextInCol; + pLower = pLower->NextInCol; + } + pUpper = pUpper->NextInRow; + } + return; +#endif /* REAL */ +} + + + + + + + + + +/* + * PERFORM ROW AND COLUMN ELIMINATION ON COMPLEX MATRIX + * + * Eliminates a single row and column of the matrix and leaves single row of + * the upper triangular matrix and a single column of the lower triangular + * matrix in its wake. Uses Gauss's method. + * + * >>> Argument: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * pPivot <input> (ElementPtr) + * Pointer to the current pivot. + * + * >>> Local variables: + * pLower (ElementPtr) + * Points to matrix element in lower triangular column. + * pSub (ElementPtr) + * Points to elements in the reduced submatrix. + * Row (int) + * Row index. + * pUpper (ElementPtr) + * Points to matrix element in upper triangular row. + * + * Possible errors: + * spNO_MEMORY + */ + +static void +ComplexRowColElimination( Matrix, pPivot ) + +MatrixPtr Matrix; +register ElementPtr pPivot; +{ +#if spCOMPLEX +register ElementPtr pSub; +register int Row; +register ElementPtr pLower, pUpper; +ElementPtr CreateFillin(); + +/* Begin `ComplexRowColElimination'. */ + +/* Test for zero pivot. */ + if (ELEMENT_MAG(pPivot) == 0.0) + { (void)MatrixIsSingular( Matrix, pPivot->Row ); + return; + } + CMPLX_RECIPROCAL(*pPivot, *pPivot); + + pUpper = pPivot->NextInRow; + while (pUpper != NULL) + { +/* Calculate upper triangular element. */ +/* Cmplx expr: *pUpper = *pUpper * (1.0 / *pPivot). */ + CMPLX_MULT_ASSIGN(*pUpper, *pPivot); + + pSub = pUpper->NextInCol; + pLower = pPivot->NextInCol; + while (pLower != NULL) + { Row = pLower->Row; + +/* Find element in row that lines up with current lower triangular element. */ + while (pSub != NULL AND pSub->Row < Row) + pSub = pSub->NextInCol; + +/* Test to see if desired element was not found, if not, create fill-in. */ + if (pSub == NULL OR pSub->Row > Row) + { pSub = CreateFillin( Matrix, Row, pUpper->Col ); + if (pSub == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + } + +/* Cmplx expr: pElement -= *pUpper * pLower. */ + CMPLX_MULT_SUBT_ASSIGN(*pSub, *pUpper, *pLower); + pSub = pSub->NextInCol; + pLower = pLower->NextInCol; + } + pUpper = pUpper->NextInRow; + } + return; +#endif /* spCOMPLEX */ +} + + + + + +/* + * UPDATE MARKOWITZ NUMBERS + * + * Updates the Markowitz numbers after a row and column have been eliminated. + * Also updates singleton count. + * + * >>> Argument: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * pPivot <input> (ElementPtr) + * Pointer to the current pivot. + * + * >>> Local variables: + * Row (int) + * Row index. + * Col (int) + * Column index. + * ColPtr (ElementPtr) + * Points to matrix element in upper triangular column. + * RowPtr (ElementPtr) + * Points to matrix element in lower triangular row. + */ + +static void +UpdateMarkowitzNumbers( Matrix, pPivot ) + +MatrixPtr Matrix; +ElementPtr pPivot; +{ +register int Row, Col; +register ElementPtr ColPtr, RowPtr; +register int *MarkoRow = Matrix->MarkowitzRow, *MarkoCol = Matrix->MarkowitzCol; +double Product; + +/* Begin `UpdateMarkowitzNumbers'. */ + +/* Update Markowitz numbers. */ + for (ColPtr = pPivot->NextInCol; ColPtr != NULL; ColPtr = ColPtr->NextInCol) + { Row = ColPtr->Row; + --MarkoRow[Row]; + +/* Form Markowitz product while being cautious of overflows. */ + if ((MarkoRow[Row] > LARGEST_SHORT_INTEGER AND MarkoCol[Row] != 0) OR + (MarkoCol[Row] > LARGEST_SHORT_INTEGER AND MarkoRow[Row] != 0)) + { Product = MarkoCol[Row] * MarkoRow[Row]; + if (Product >= LARGEST_LONG_INTEGER) + Matrix->MarkowitzProd[Row] = LARGEST_LONG_INTEGER; + else + Matrix->MarkowitzProd[Row] = Product; + } + else Matrix->MarkowitzProd[Row] = MarkoRow[Row] * MarkoCol[Row]; + if (MarkoRow[Row] == 0) + Matrix->Singletons++; + } + + for (RowPtr = pPivot->NextInRow; RowPtr != NULL; RowPtr = RowPtr->NextInRow) + { Col = RowPtr->Col; + --MarkoCol[Col]; + +/* Form Markowitz product while being cautious of overflows. */ + if ((MarkoRow[Col] > LARGEST_SHORT_INTEGER AND MarkoCol[Col] != 0) OR + (MarkoCol[Col] > LARGEST_SHORT_INTEGER AND MarkoRow[Col] != 0)) + { Product = MarkoCol[Col] * MarkoRow[Col]; + if (Product >= LARGEST_LONG_INTEGER) + Matrix->MarkowitzProd[Col] = LARGEST_LONG_INTEGER; + else + Matrix->MarkowitzProd[Col] = Product; + } + else Matrix->MarkowitzProd[Col] = MarkoRow[Col] * MarkoCol[Col]; + if ((MarkoCol[Col] == 0) AND (MarkoRow[Col] != 0)) + Matrix->Singletons++; + } + return; +} + + + + + + + + +/* + * CREATE FILL-IN + * + * This routine is used to create fill-ins and splice them into the + * matrix. + * + * >>> Returns: + * Pointer to fill-in. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * Col <input> (int) + * Column index for element. + * Row <input> (int) + * Row index for element. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * ppElementAbove (ElementPtr *) + * This contains the address of the pointer to the element just above the + * one being created. It is used to speed the search and it is updated + * with address of the created element. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static ElementPtr +CreateFillin( Matrix, Row, Col ) + +MatrixPtr Matrix; +register int Row; +int Col; +{ +register ElementPtr pElement, *ppElementAbove; +ElementPtr spcCreateElement(); + +/* Begin `CreateFillin'. */ + +/* Find Element above fill-in. */ + ppElementAbove = &Matrix->FirstInCol[Col]; + pElement = *ppElementAbove; + while (pElement != NULL) + { if (pElement->Row < Row) + { ppElementAbove = &pElement->NextInCol; + pElement = *ppElementAbove; + } + else break; /* while loop */ + } + +/* End of search, create the element. */ + pElement = spcCreateElement( Matrix, Row, Col, ppElementAbove, YES ); + +/* Update Markowitz counts and products. */ + Matrix->MarkowitzProd[Row] = ++Matrix->MarkowitzRow[Row] * + Matrix->MarkowitzCol[Row]; + if ((Matrix->MarkowitzRow[Row] == 1) AND (Matrix->MarkowitzCol[Row] != 0)) + Matrix->Singletons--; + Matrix->MarkowitzProd[Col] = ++Matrix->MarkowitzCol[Col] * + Matrix->MarkowitzRow[Col]; + if ((Matrix->MarkowitzRow[Col] != 0) AND (Matrix->MarkowitzCol[Col] == 1)) + Matrix->Singletons--; + + return pElement; +} + + + + + + + + +/* + * ZERO PIVOT ENCOUNTERED + * + * This routine is called when a singular matrix is found. It then + * records the current row and column and exits. + * + * >>> Returned: + * The error code spSINGULAR or spZERO_DIAG is returned. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to matrix. + * Step <input> (int) + * Index of diagonal that is zero. + */ + +static int +MatrixIsSingular( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +/* Begin `MatrixIsSingular'. */ + + Matrix->SingularRow = Matrix->IntToExtRowMap[ Step ]; + Matrix->SingularCol = Matrix->IntToExtColMap[ Step ]; + return (Matrix->Error = spSINGULAR); +} + + +static int +ZeroPivot( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +/* Begin `ZeroPivot'. */ + + Matrix->SingularRow = Matrix->IntToExtRowMap[ Step ]; + Matrix->SingularCol = Matrix->IntToExtColMap[ Step ]; + return (Matrix->Error = spZERO_DIAG); +} + + + + + + +#if ANNOTATE == FULL + +/* + * + * WRITE STATUS + * + * Write a summary of important variables to standard output. + */ + +static +WriteStatus( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +int I; + +/* Begin `WriteStatus'. */ + + printf("Step = %1d ", Step); + printf("Pivot found at %1d,%1d using ", Matrix->PivotsOriginalRow, + Matrix->PivotsOriginalCol); + switch(Matrix->PivotSelectionMethod) + { case 's': printf("SearchForSingleton\n"); break; + case 'q': printf("QuicklySearchDiagonal\n"); break; + case 'd': printf("SearchDiagonal\n"); break; + case 'e': printf("SearchEntireMatrix\n"); break; + } + + printf("MarkowitzRow = "); + for (I = 1; I <= Matrix->Size; I++) + printf("%2d ", Matrix->MarkowitzRow[I]); + printf("\n"); + + printf("MarkowitzCol = "); + for (I = 1; I <= Matrix->Size; I++) + printf("%2d ", Matrix->MarkowitzCol[I]); + printf("\n"); + + printf("MarkowitzProduct = "); + for (I = 1; I <= Matrix->Size; I++) + printf("%2d ", Matrix->MarkowitzProd[I]); + printf("\n"); + + printf("Singletons = %2d\n", Matrix->Singletons); + + printf("IntToExtRowMap = "); + for (I = 1; I <= Matrix->Size; I++) + printf("%2d ", Matrix->IntToExtRowMap[I]); + printf("\n"); + + printf("IntToExtColMap = "); + for (I = 1; I <= Matrix->Size; I++) + printf("%2d ", Matrix->IntToExtColMap[I]); + printf("\n"); + + printf("ExtToIntRowMap = "); + for (I = 1; I <= Matrix->ExtSize; I++) + printf("%2d ", Matrix->ExtToIntRowMap[I]); + printf("\n"); + + printf("ExtToIntColMap = "); + for (I = 1; I <= Matrix->ExtSize; I++) + printf("%2d ", Matrix->ExtToIntColMap[I]); + printf("\n\n"); + +/* spPrint((char *)Matrix, NO, YES); */ + + return; + +} +#endif /* ANNOTATE == FULL */ diff --git a/sis/linsolv/spMatrix.h b/sis/linsolv/spMatrix.h new file mode 100644 index 0000000..423a143 --- /dev/null +++ b/sis/linsolv/spMatrix.h @@ -0,0 +1,443 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/linsolv/spMatrix.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:05 $ + * + */ +/* + * EXPORTS for sparse matrix routines. + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains definitions that are useful to the calling + * program. In particular, this file contains error keyword + * definitions, some macro functions that are used to quickly enter + * data into the matrix and the type definition of a data structure + * that acts as a template for entering admittances into the matrix. + * Also included is the type definitions for the various functions + * available to the user. + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + * + * $Date: 2004/02/07 10:15:05 $ + * $Revision: 1.1.1.1 $ + */ + + + + +#ifndef spOKAY + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + */ + +#include "spConfig.h" + + + + + + +/* + * ERROR KEYWORDS + * + * The actual numbers used in the error codes are not sacred, they can be + * changed under the condition that the codes for the nonfatal errors are + * less than the code for spFATAL and similarly the codes for the fatal + * errors are greater than that for spFATAL. + * + * >>> Error descriptions: + * spOKAY + * No error has occurred. + * spSMALL_PIVOT + * When reordering the matrix, no element was found which satisfies the + * absolute threshold criteria. The largest element in the matrix was + * chosen as pivot. Non-fatal. + * spZERO_DIAG + * Fatal error. A zero was encountered on the diagonal the matrix. This + * does not necessarily imply that the matrix is singular. When this + * error occurs, the matrix should be reconstructed and factored using + * spOrderAndFactor(). In spCOMPATIBILITY mode, spZERO_DIAG is + * indistinguishable from spSINGULAR. + * spSINGULAR + * Fatal error. Matrix is singular, so no unique solution exists. + * spNO_MEMORY + * Fatal error. Indicates that not enough memory is available to handle + * the matrix. + * spPANIC + * Fatal error indicating that the routines are not prepared to + * handle the matrix that has been requested. This may occur when + * the matrix is specified to be real and the routines are not + * compiled for real matrices, or when the matrix is specified to + * be complex and the routines are not compiled to handle complex + * matrices. + * spFATAL + * Not an error flag, but rather the dividing line between fatal errors + * and warnings. + */ + +/* Begin error macros. */ +#define spOKAY 0 +#define spSMALL_PIVOT 1 +#define spZERO_DIAG 2 +#define spSINGULAR 3 +#define spNO_MEMORY 4 +#define spPANIC 5 + +#define spFATAL 2 + + +#if spCOMPATIBILITY +#define NO_ERROR spOKAY +#define UNDER_FLOW spOKAY +#define OVER_FLOW spOKAY +#define ILL_CONDITIONED spSMALL_PIVOT +#define SINGULAR spSINGULAR +#define NO_MEMORY spNO_MEMORY +#define RANGE spPANIC + +#define FATAL spFATAL + +#undef spZERO_DIAG +#define spZERO_DIAG spSINGULAR +#endif /* spCOMPATIBILITY */ + + + + + +/* + * KEYWORD DEFINITIONS + * + * Here we define what precision arithmetic Sparse will use. Double + * precision is suggested as being most appropriate for circuit + * simulation and for C. However, it is possible to change spREAL + * to a float for single precision arithmetic. Note that in C, single + * precision arithmetic is often slower than double precision. Sparse + * internally refers to spREALs as RealNumbers. + * + * Some C compilers, notably the old VMS compiler, do not handle the keyword + * "void" correctly. If this is true for your compiler, remove the + * comment delimiters from the redefinition of void to int below. + */ + +#define spREAL double +/* #define void int */ + +#if spCOMPATIBILITY +#define SPARSE_REAL spREAL +#endif + + + +/* + * PARTITION TYPES + * + * When factoring a previously ordered matrix using spFactor(), Sparse + * operates on a row-at-a-time basis. For speed, on each step, the row + * being updated is copied into a full vector and the operations are + * performed on that vector. This can be done one of two ways, either + * using direct addressing or indirect addressing. Direct addressing + * is fastest when the matrix is relatively dense and indirect addressing + * is quite sparse. The user can select which partitioning mode is used. + * The following keywords are passed to spPartition() and indicate that + * Sparse should use only direct addressing, only indirect addressing, or + * that it should choose the best mode on a row-by-row basis. The time + * required to choose a partition is of the same order of the cost to factor + * the matrix. + * + * If you plan to factor a large number of matrices with the same structure, + * it is best to let Sparse choose the partition. Otherwise, you should + * choose the partition based on the predicted density of the matrix. + */ + +/* Begin partition keywords. */ + +#define spDEFAULT_PARTITION 0 +#define spDIRECT_PARTITION 1 +#define spINDIRECT_PARTITION 2 +#define spAUTO_PARTITION 3 + + + + + +/* + * MACRO FUNCTION DEFINITIONS + * + * >>> Macro descriptions: + * spADD_REAL_ELEMENT + * Macro function that adds data to a real element in the matrix by a + * pointer. + * spADD_IMAG_ELEMENT + * Macro function that adds data to a imaginary element in the matrix by + * a pointer. + * spADD_COMPLEX_ELEMENT + * Macro function that adds data to a complex element in the matrix by a + * pointer. + * spADD_REAL_QUAD + * Macro function that adds data to each of the four real matrix elements + * specified by the given template. + * spADD_IMAG_QUAD + * Macro function that adds data to each of the four imaginary matrix + * elements specified by the given template. + * spADD_COMPLEX_QUAD + * Macro function that adds data to each of the four complex matrix + * elements specified by the given template. + */ + +/* Begin Macros. */ +#define spADD_REAL_ELEMENT(element,real) *(element) += real + +#define spADD_IMAG_ELEMENT(element,imag) *(element+1) += imag + +#define spADD_COMPLEX_ELEMENT(element,real,imag) \ +{ *(element) += real; \ + *(element+1) += imag; \ +} + +#define spADD_REAL_QUAD(template,real) \ +{ *((template).Element1) += real; \ + *((template).Element2) += real; \ + *((template).Element3Negated) -= real; \ + *((template).Element4Negated) -= real; \ +} + +#define spADD_IMAG_QUAD(template,imag) \ +{ *((template).Element1+1) += imag; \ + *((template).Element2+1) += imag; \ + *((template).Element3Negated+1) -= imag; \ + *((template).Element4Negated+1) -= imag; \ +} + +#define spADD_COMPLEX_QUAD(template,real,imag) \ +{ *((template).Element1) += real; \ + *((template).Element2) += real; \ + *((template).Element3Negated) -= real; \ + *((template).Element4Negated) -= real; \ + *((template).Element1+1) += imag; \ + *((template).Element2+1) += imag; \ + *((template).Element3Negated+1) -= imag; \ + *((template).Element4Negated+1) -= imag; \ +} + +#if spCOMPATIBILITY +#define ADD_REAL_ELEMENT_TO_MATRIX spADD_REAL_ELEMENT +#define ADD_IMAG_ELEMENT_TO_MATRIX spADD_IMAG_ELEMENT +#define ADD_COMPLEX_ELEMENT_TO_MATRIX spADD_COMPLEX_ELEMENT +#define ADD_REAL_QUAD_ELEMENT_TO_MATRIX spADD_REAL_ELEMENT +#define ADD_IMAG_QUAD_ELEMENT_TO_MATRIX spADD_IMAG_ELEMENT +#define ADD_COMPLEX_QUAD_ELEMENT_TO_MATRIX spADD_COMPLEX_ELEMENT +#endif + + + + + + +/* + * TYPE DEFINITION FOR COMPONENT TEMPLATE + * + * This data structure is used to hold pointers to four related elements in + * matrix. It is used in conjunction with the routines + * spGetAdmittance + * spGetQuad + * spGetOnes + * These routines stuff the structure which is later used by the spADD_QUAD + * macro functions above. It is also possible for the user to collect four + * pointers returned by spGetElement and stuff them into the template. + * The spADD_QUAD routines stuff data into the matrix in locations specified + * by Element1 and Element2 without changing the data. The data is negated + * before being placed in Element3 and Element4. + */ + +#if spCOMPATIBILITY +#define spTemplate TemplateStruct +#endif + +/* Begin `spTemplate'. */ +struct spTemplate +{ spREAL *Element1 ; + spREAL *Element2 ; + spREAL *Element3Negated; + spREAL *Element4Negated; +}; + + + + + +/* + * FUNCTION TYPE DEFINITIONS + * + * The type of every user accessible function is declared here. + */ + +/* Begin function declarations. */ + +#ifdef __STDC__ + +/* For compilers that understand function prototypes. */ + +extern void spClear( char* ); +extern spREAL spCondition( char*, spREAL, int* ); +extern char *spCreate( int, int, int* ); +extern void spDeleteRowAndCol( char*, int, int ); +extern void spDestroy( char* ); +extern int spElementCount( char* ); +extern int spError( char* ); +extern int spFactor( char* ); +extern int spFileMatrix( char*, char*, char*, int, int, int ); +extern int spFileStats( char*, char*, char* ); +extern int spFillinCount( char* ); +extern int spGetAdmittance( char*, int, int, struct spTemplate* ); +extern spREAL *spGetElement( char*, int, int ); +extern char *spGetInitInfo( spREAL* ); +extern int spGetOnes( char*, int, int, int, struct spTemplate* ); +extern int spGetQuad( char*, int, int, int, int, struct spTemplate* ); +extern int spGetSize( char*, int ); +extern int spInitialize( char*, int (*)() ); +extern void spInstallInitInfo( spREAL*, char* ); +extern spREAL spLargestElement( char* ); +extern void spMNA_Preorder( char* ); +extern spREAL spNorm( char* ); +extern int spOrderAndFactor( char*, spREAL[], spREAL, spREAL, int ); +extern void spPartition( char*, int ); +extern void spPrint( char*, int, int, int ); +extern spREAL spPseudoCondition( char* ); +extern spREAL spRoundoff( char*, spREAL ); +extern void spScale( char*, spREAL[], spREAL[] ); +extern void spSetComplex( char* ); +extern void spSetReal( char* ); +extern void spStripFills( char* ); +extern void spWhereSingular( char*, int*, int* ); + +/* Functions with argument lists that are dependent on options. */ + +#if spCOMPLEX +extern void spDeterminant ( char*, int*, spREAL*, spREAL* ); +#else /* NOT spCOMPLEX */ +extern void spDeterminant ( char*, int*, spREAL* ); +#endif /* NOT spCOMPLEX */ +#if spCOMPLEX && spSEPARATED_COMPLEX_VECTORS +extern int spFileVector( char*, char* , spREAL[], spREAL[]); +extern void spMultiply( char*, spREAL[], spREAL[], spREAL[], spREAL[] ); +extern void spMultTransposed(char*,spREAL[],spREAL[],spREAL[],spREAL[]); +extern void spSolve( char*, spREAL[], spREAL[], spREAL[], spREAL[] ); +extern void spSolveTransposed(char*,spREAL[],spREAL[],spREAL[],spREAL[]); +#else /* NOT (spCOMPLEX && spSEPARATED_COMPLEX_VECTORS) */ +extern int spFileVector( char*, char* , spREAL[] ); +extern void spMultiply( char*, spREAL[], spREAL[] ); +extern void spMultTransposed( char*, spREAL[], spREAL[] ); +extern void spSolve( char*, spREAL[], spREAL[] ); +extern void spSolveTransposed( char*, spREAL[], spREAL[] ); +#endif /* NOT (spCOMPLEX && spSEPARATED_COMPLEX_VECTORS) */ + +#else /* NOT defined(__STDC__) */ + +/* For compilers that do not understand function prototypes. */ + +extern void spClear(); +extern spREAL spCondition(); +extern char *spCreate(); +extern void spDeleteRowAndCol(); +extern void spDestroy(); +extern void spDeterminant (); +extern int spElementCount(); +extern int spError(); +extern int spFactor(); +extern int spFileMatrix(); +extern int spFileStats(); +extern int spFileVector(); +extern int spFillinCount(); +extern int spGetAdmittance(); +extern spREAL *spGetElement(); +extern char *spGetInitInfo(); +extern int spGetOnes(); +extern int spGetQuad(); +extern int spGetSize(); +extern int spInitialize(); +extern void spInstallInitInfo(); +extern spREAL spLargestElement(); +extern void spMNA_Preorder(); +extern void spMultiply(); +extern void spMultTransposed(); +extern spREAL spNorm(); +extern int spOrderAndFactor(); +extern void spPartition(); +extern void spPrint(); +extern spREAL spPseudoCondition(); +extern spREAL spRoundoff(); +extern void spScale(); +extern void spSetComplex(); +extern void spSetReal(); +extern void spSolve(); +extern void spSolveTransposed(); +extern void spStripFills(); +extern void spWhereSingular(); +#endif /* defined(__STDC__) */ + +#if spCOMPATIBILITY +extern char *AllocateMatrix(); +extern spREAL *AddElementToMatrix(); +extern void AddRealElementToMatrix(); +extern void AddImagElementToMatrix(); +extern void AddComplexElementToMatrix(); +extern void AddAdmittanceToMatrix(); +extern void AddOnesToMatrix(); +extern void AddQuadToMatrix(); +extern void AddRealQuadElementToMatrix(); +extern void AddImagQuadElementToMatrix(); +extern void AddComplexQuadElementToMatrix(); +extern void CleanMatrix(); +extern void ClearMatrix(); +extern int ClearMatrixError(); +extern void DeallocateMatrix(); +extern void DeleteRowAndColFromMatrix(); +extern void Determinant(); +extern int DecomposeMatrix(); +extern int GetMatrixSize(); +extern int MatrixElementCount(); +extern int MatrixFillinCount(); +extern void MatrixMultiply(); +extern spREAL MatrixRoundoffError(); +extern int MatrixError(); +extern int OrderAndDecomposeMatrix(); +extern void OutputMatrixToFile(); +extern void OutputStatisticsToFile(); +extern void OutputVectorToFile(); +extern void PreorderForModifiedNodal(); +extern void PrintMatrix(); +extern void SetMatrixComplex(); +extern void SetMatrixReal(); +extern void SolveMatrix(); +extern void SolveTransposedMatrix(); +extern void ScaleMatrix(); +#endif /* spCOMPATIBILITY */ + +#endif /* spOKAY */ diff --git a/sis/linsolv/spOutput.c b/sis/linsolv/spOutput.c new file mode 100644 index 0000000..6abae48 --- /dev/null +++ b/sis/linsolv/spOutput.c @@ -0,0 +1,767 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/linsolv/spOutput.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:05 $ + * + */ +/* + * MATRIX OUTPUT MODULE + * + * Author: Advisor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains the output-to-file and output-to-screen routines for + * the matrix package. + * + * >>> User accessible functions contained in this file: + * spPrint + * spFileMatrix + * spFileVector + * spFileStats + * + * >>> Other functions contained in this file: + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifndef lint +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88 by Kenneth S. Kundert"; +static char RCSid[] = + "$Header: /users/pchong/CVS/sis/sis/linsolv/spOutput.c,v 1.1.1.1 2004/02/07 10:15:05 pchong Exp $"; +#endif + + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spConfig.h" +#include "spMatrix.h" +#include "spDefs.h" + + + + + +#if DOCUMENTATION + +/* + * PRINT MATRIX + * + * Formats and send the matrix to standard output. Some elementary + * statistics are also output. The matrix is output in a format that is + * readable by people. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * PrintReordered <input> (int) + * Indicates whether the matrix should be printed out in its original + * form, as input by the user, or whether it should be printed in its + * reordered form, as used by the matrix routines. A zero indicates that + * the matrix should be printed as inputed, a one indicates that it + * should be printed reordered. + * Data <input> (int) + * Boolean flag that when false indicates that output should be + * compressed such that only the existence of an element should be + * indicated rather than giving the actual value. Thus 11 times as + * many can be printed on a row. A zero signifies that the matrix + * should be printed compressed. A one indicates that the matrix + * should be printed in all its glory. + * Header <input> (int) + * Flag indicating that extra information should be given, such as row + * and column numbers. + * + * >>> Local variables: + * Col (int) + * Column being printed. + * ElementCount (int) + * Variable used to count the number of nonzero elements in the matrix. + * LargestElement (RealNumber) + * The magnitude of the largest element in the matrix. + * LargestDiag (RealNumber) + * The magnitude of the largest diagonal in the matrix. + * Magnitude (RealNumber) + * The absolute value of the matrix element being printed. + * PrintOrdToIntColMap (int []) + * A translation array that maps the order that columns will be + * printed in (if not PrintReordered) to the internal column numbers. + * PrintOrdToIntRowMap (int []) + * A translation array that maps the order that rows will be + * printed in (if not PrintReordered) to the internal row numbers. + * pElement (ElementPtr) + * Pointer to the element in the matrix that is to be printed. + * pImagElements (ElementPtr [ ]) + * Array of pointers to elements in the matrix. These pointers point + * to the elements whose real values have just been printed. They are + * used to quickly access those same elements so their imaginary values + * can be printed. + * Row (int) + * Row being printed. + * Size (int) + * The size of the matrix. + * SmallestDiag (RealNumber) + * The magnitude of the smallest diagonal in the matrix. + * SmallestElement (RealNumber) + * The magnitude of the smallest element in the matrix excluding zero + * elements. + * StartCol (int) + * The column number of the first column to be printed in the group of + * columns currently being printed. + * StopCol (int) + * The column number of the last column to be printed in the group of + * columns currently being printed. + * Top (int) + * The largest expected external row or column number. + */ + +void +spPrint( eMatrix, PrintReordered, Data, Header ) + +char *eMatrix; +int PrintReordered, Data, Header; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int J = 0; +int I, Row, Col, Size, Top, StartCol = 1, StopCol, Columns, ElementCount = 0; +double Magnitude, SmallestDiag, SmallestElement; +double LargestElement = 0.0, LargestDiag = 0.0; +ElementPtr pElement, pImagElements[PRINTER_WIDTH/10+1]; +int *PrintOrdToIntRowMap, *PrintOrdToIntColMap; + +/* Begin `spPrint'. */ + ASSERT( IS_SPARSE( Matrix ) ); + Size = Matrix->Size; + +/* Create a packed external to internal row and column translation array. */ +# if TRANSLATE + Top = Matrix->AllocatedExtSize; +#else + Top = Matrix->AllocatedSize; +#endif + CALLOC( PrintOrdToIntRowMap, int, Top + 1 ); + CALLOC( PrintOrdToIntColMap, int, Top + 1 ); + if ( PrintOrdToIntRowMap == NULL OR PrintOrdToIntColMap == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + for (I = 1; I <= Size; I++) + { PrintOrdToIntRowMap[ Matrix->IntToExtRowMap[I] ] = I; + PrintOrdToIntColMap[ Matrix->IntToExtColMap[I] ] = I; + } + +/* Pack the arrays. */ + for (J = 1, I = 1; I <= Top; I++) + { if (PrintOrdToIntRowMap[I] != 0) + PrintOrdToIntRowMap[ J++ ] = PrintOrdToIntRowMap[ I ]; + } + for (J = 1, I = 1; I <= Top; I++) + { if (PrintOrdToIntColMap[I] != 0) + PrintOrdToIntColMap[ J++ ] = PrintOrdToIntColMap[ I ]; + } + +/* Print header. */ + if (Header) + { printf("MATRIX SUMMARY\n\n"); + printf("Size of matrix = %1u x %1u.\n", Size, Size); + if ( Matrix->Reordered AND PrintReordered ) + printf("Matrix has been reordered.\n"); + putchar('\n'); + + if ( Matrix->Factored ) + printf("Matrix after factorization:\n"); + else + printf("Matrix before factorization:\n"); + + SmallestElement = LARGEST_REAL; + SmallestDiag = SmallestElement; + } + +/* Determine how many columns to use. */ + Columns = PRINTER_WIDTH; + if (Header) Columns -= 5; + if (Data) Columns = (Columns+1) / 10; + +/* + * Print matrix by printing groups of complete columns until all the columns + * are printed. + */ + J = 0; + while ( J <= Size ) + +/* Calculate index of last column to printed in this group. */ + { StopCol = StartCol + Columns - 1; + if (StopCol > Size) + StopCol = Size; + +/* Label the columns. */ + if (Header) + { if (Data) + { printf(" "); + for (I = StartCol; I <= StopCol; I++) + { if (PrintReordered) + Col = I; + else + Col = PrintOrdToIntColMap[I]; + printf(" %9d", Matrix->IntToExtColMap[ Col ]); + } + printf("\n\n"); + } + else + { if (PrintReordered) + printf("Columns %1d to %1d.\n",StartCol,StopCol); + else + { printf("Columns %1d to %1d.\n", + Matrix->IntToExtColMap[ PrintOrdToIntColMap[StartCol] ], + Matrix->IntToExtColMap[ PrintOrdToIntColMap[StopCol] ]); + } + } + } + +/* Print every row ... */ + for (I = 1; I <= Size; I++) + { if (PrintReordered) + Row = I; + else + Row = PrintOrdToIntRowMap[I]; + + if (Header) + { if (PrintReordered AND NOT Data) + printf("%4d", I); + else + printf("%4d", Matrix->IntToExtRowMap[ Row ]); + if (NOT Data) putchar(' '); + } + +/* ... in each column of the group. */ + for (J = StartCol; J <= StopCol; J++) + { if (PrintReordered) + Col = J; + else + Col = PrintOrdToIntColMap[J]; + + pElement = Matrix->FirstInCol[Col]; + while(pElement != NULL AND pElement->Row != Row) + pElement = pElement->NextInCol; + + if (Data) + pImagElements[J - StartCol] = pElement; + + if (pElement != NULL) + +/* Case where element exists */ + { if (Data) + printf(" %9.3lg", (double)pElement->Real); + else + putchar('x'); + +/* Update status variables */ + if ( (Magnitude = ELEMENT_MAG(pElement)) > LargestElement ) + LargestElement = Magnitude; + if ((Magnitude < SmallestElement) AND (Magnitude != 0.0)) + SmallestElement = Magnitude; + ElementCount++; + } + +/* Case where element is structurally zero */ + else + { if (Data) + printf(" ..."); + else + putchar('.'); + } + } + putchar('\n'); + +#if spCOMPLEX + if (Matrix->Complex AND Data) + { printf(" "); + for (J = StartCol; J <= StopCol; J++) + { if (pImagElements[J - StartCol] != NULL) + { printf(" %8.2lgj", + (double)pImagElements[J-StartCol]->Imag); + } + else printf(" "); + } + putchar('\n'); + } +#endif /* spCOMPLEX */ + } + +/* Calculate index of first column in next group. */ + StartCol = StopCol; + StartCol++; + putchar('\n'); + } + if (Header) + { printf("\nLargest element in matrix = %-1.4lg.\n", LargestElement); + printf("Smallest element in matrix = %-1.4lg.\n", SmallestElement); + +/* Search for largest and smallest diagonal values */ + for (I = 1; I <= Size; I++) + { if (Matrix->Diag[I] != NULL) + { Magnitude = ELEMENT_MAG( Matrix->Diag[I] ); + if ( Magnitude > LargestDiag ) LargestDiag = Magnitude; + if ( Magnitude < SmallestDiag ) SmallestDiag = Magnitude; + } + } + + /* Print the largest and smallest diagonal values */ + if ( Matrix->Factored ) + { printf("\nLargest diagonal element = %-1.4lg.\n", LargestDiag); + printf("Smallest diagonal element = %-1.4lg.\n", SmallestDiag); + } + else + { printf("\nLargest pivot element = %-1.4lg.\n", LargestDiag); + printf("Smallest pivot element = %-1.4lg.\n", SmallestDiag); + } + + /* Calculate and print sparsity and number of fill-ins created. */ + printf("\nDensity = %2.2lf%%.\n", ((double)(ElementCount * 100)) / + ((double)(Size * Size))); + if (NOT Matrix->NeedsOrdering) + printf("Number of fill-ins = %1d.\n", Matrix->Fillins); + } + putchar('\n'); + (void)fflush(stdout); + + FREE(PrintOrdToIntColMap); + FREE(PrintOrdToIntRowMap); + return; +} + + + + + + + + + + + +/* + * OUTPUT MATRIX TO FILE + * + * Writes matrix to file in format suitable to be read back in by the + * matrix test program. + * + * >>> Returns: + * One is returned if routine was successful, otherwise zero is returned. + * The calling function can query errno (the system global error variable) + * as to the reason why this routine failed. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * File <input> (char *) + * Name of file into which matrix is to be written. + * Label <input> (char *) + * String that is transferred to file and is used as a label. + * Reordered <input> (BOOLEAN) + * Specifies whether matrix should be output in reordered form, + * or in original order. + * Data <input> (BOOLEAN) + * Indicates that the element values should be output along with + * the indices for each element. This parameter must be true if + * matrix is to be read by the sparse test program. + * Header <input> (BOOLEAN) + * Indicates that header is desired. This parameter must be true if + * matrix is to be read by the sparse test program. + * + * >>> Local variables: + * Col (int) + * The original column number of the element being output. + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * pMatrixFile (FILE *) + * File pointer to the matrix file. + * Row (int) + * The original row number of the element being output. + * Size (int) + * The size of the matrix. + */ + +int +spFileMatrix( eMatrix, File, Label, Reordered, Data, Header ) + +char *eMatrix, *Label, *File; +int Reordered, Data, Header; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I, Size; +register ElementPtr pElement; +int Row, Col, Err; +FILE *pMatrixFile, *fopen(); + +/* Begin `spFileMatrix'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +/* Open file matrix file in write mode. */ + if ((pMatrixFile = fopen(File, "w")) == NULL) + return 0; + +/* Output header. */ + Size = Matrix->Size; + if (Header) + { if (Matrix->Factored AND Data) + { Err = fprintf + ( pMatrixFile, + "Warning : The following matrix is factored in to LU form.\n" + ); + } + if (Err < 0) return 0; + if (fprintf(pMatrixFile, "%s\n", Label) < 0) return 0; + Err = fprintf( pMatrixFile, "%d\t%s\n", Size, + (Matrix->Complex ? "complex" : "real")); + if (Err < 0) return 0; + } + +/* Output matrix. */ + if (NOT Data) + { for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { if (Reordered) + { Row = pElement->Row; + Col = I; + } + else + { Row = Matrix->IntToExtRowMap[pElement->Row]; + Col = Matrix->IntToExtColMap[I]; + } + pElement = pElement->NextInCol; + if (fprintf(pMatrixFile, "%d\t%d\n", Row, Col) < 0) return 0; + } + } +/* Output terminator, a line of zeros. */ + if (Header) + if (fprintf(pMatrixFile, "0\t0\n") < 0) return 0; + } + +#if spCOMPLEX + if (Data AND Matrix->Complex) + { for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { if (Reordered) + { Row = pElement->Row; + Col = I; + } + else + { Row = Matrix->IntToExtRowMap[pElement->Row]; + Col = Matrix->IntToExtColMap[I]; + } + Err = fprintf + ( pMatrixFile,"%d\t%d\t%-.15lg\t%-.15lg\n", + Row, Col, (double)pElement->Real, (double)pElement->Imag + ); + if (Err < 0) return 0; + pElement = pElement->NextInCol; + } + } +/* Output terminator, a line of zeros. */ + if (Header) + if (fprintf(pMatrixFile,"0\t0\t0.0\t0.0\n") < 0) return 0; + + } +#endif /* spCOMPLEX */ + +#if REAL + if (Data AND NOT Matrix->Complex) + { for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { Row = Matrix->IntToExtRowMap[pElement->Row]; + Col = Matrix->IntToExtColMap[I]; + Err = fprintf + ( pMatrixFile,"%d\t%d\t%-.15lg\n", + Row, Col, (double)pElement->Real + ); + if (Err < 0) return 0; + pElement = pElement->NextInCol; + } + } +/* Output terminator, a line of zeros. */ + if (Header) + if (fprintf(pMatrixFile,"0\t0\t0.0\n") < 0) return 0; + + } +#endif /* REAL */ + +/* Close file. */ + if (fclose(pMatrixFile) < 0) return 0; + return 1; +} + + + + + + + +/* + * OUTPUT SOURCE VECTOR TO FILE + * + * Writes vector to file in format suitable to be read back in by the + * matrix test program. This routine should be executed after the function + * spFileMatrix. + * + * >>> Returns: + * One is returned if routine was successful, otherwise zero is returned. + * The calling function can query errno (the system global error variable) + * as to the reason why this routine failed. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * File <input> (char *) + * Name of file into which matrix is to be written. + * RHS <input> (RealNumber []) + * Right-hand side vector. This is only the real portion if + * spSEPARATED_COMPLEX_VECTORS is true. + * iRHS <input> (RealNumber []) + * Right-hand side vector, imaginary portion. Not necessary if matrix + * is real or if spSEPARATED_COMPLEX_VECTORS is set false. + * + * >>> Local variables: + * pMatrixFile (FILE *) + * File pointer to the matrix file. + * Size (int) + * The size of the matrix. + * + * >>> Obscure Macros + * IMAG_RHS + * Replaces itself with `, iRHS' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +int +spFileVector( eMatrix, File, RHS IMAG_RHS ) + +char *eMatrix, *File; +RealVector RHS IMAG_RHS; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I, Size, Err; +FILE *pMatrixFile; +FILE *fopen(); + +/* Begin `spFileVector'. */ + ASSERT( IS_SPARSE( Matrix ) AND RHS != NULL) + +/* Open File in append mode. */ + if ((pMatrixFile = fopen(File,"a")) == NULL) + return 0; + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spCOMPLEX + if (Matrix->Complex) + { +#if spSEPARATED_COMPLEX_VECTORS + ASSERT(iRHS != NULL) + --RHS; + --iRHS; +#else + RHS -= 2; +#endif + } + else +#endif /* spCOMPLEX */ + --RHS; +#endif /* NOT ARRAY_OFFSET */ + + +/* Output vector. */ + Size = Matrix->Size; +#if spCOMPLEX + if (Matrix->Complex) + { +#if spSEPARATED_COMPLEX_VECTORS + for (I = 1; I <= Size; I++) + { Err = fprintf + ( pMatrixFile, "%-.15lg\t%-.15lg\n", + (double)RHS[I], (double)iRHS[I] + ); + if (Err < 0) return 0; + } +#else + for (I = 1; I <= Size; I++) + { Err = fprintf + ( pMatrixFile, "%-.15lg\t%-.15lg\n", + (double)RHS[2*I], (double)RHS[2*I+1] + ); + if (Err < 0) return 0; + } +#endif + } +#endif /* spCOMPLEX */ +#if REAL AND spCOMPLEX + else +#endif +#if REAL + { for (I = 1; I <= Size; I++) + { if (fprintf(pMatrixFile, "%-.15lg\n", (double)RHS[I]) < 0) + return 0; + } + } +#endif /* REAL */ + +/* Close file. */ + if (fclose(pMatrixFile) < 0) return 0; + return 1; +} + + + + + + + + + +/* + * OUTPUT STATISTICS TO FILE + * + * Writes useful information concerning the matrix to a file. Should be + * executed after the matrix is factored. + * + * >>> Returns: + * One is returned if routine was successful, otherwise zero is returned. + * The calling function can query errno (the system global error variable) + * as to the reason why this routine failed. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * File <input> (char *) + * Name of file into which matrix is to be written. + * Label <input> (char *) + * String that is transferred to file and is used as a label. + * + * >>> Local variables: + * Data (RealNumber) + * The value of the matrix element being output. + * LargestElement (RealNumber) + * The largest element in the matrix. + * NumberOfElements (int) + * Number of nonzero elements in the matrix. + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * pStatsFile (FILE *) + * File pointer to the statistics file. + * Size (int) + * The size of the matrix. + * SmallestElement (RealNumber) + * The smallest element in the matrix excluding zero elements. + */ + +int +spFileStats( eMatrix, File, Label ) + +char *eMatrix, *File, *Label; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int Size, I; +register ElementPtr pElement; +int NumberOfElements; +RealNumber Data, LargestElement, SmallestElement; +FILE *pStatsFile, *fopen(); + +/* Begin `spFileStats'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +/* Open File in append mode. */ + if ((pStatsFile = fopen(File, "a")) == NULL) + return 0; + +/* Output statistics. */ + Size = Matrix->Size; + if (NOT Matrix->Factored) + fprintf(pStatsFile, "Matrix has not been factored.\n"); + fprintf(pStatsFile, "||| Starting new matrix |||\n"); + fprintf(pStatsFile, "%s\n", Label); + if (Matrix->Complex) + fprintf(pStatsFile, "Matrix is complex.\n"); + else + fprintf(pStatsFile, "Matrix is real.\n"); + fprintf(pStatsFile," Size = %d\n",Size); + +/* Search matrix. */ + NumberOfElements = 0; + LargestElement = 0.0; + SmallestElement = LARGEST_REAL; + + for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { NumberOfElements++; + Data = ELEMENT_MAG(pElement); + if (Data > LargestElement) + LargestElement = Data; + if (Data < SmallestElement AND Data != 0.0) + SmallestElement = Data; + pElement = pElement->NextInCol; + } + } + + SmallestElement = MIN( SmallestElement, LargestElement ); + +/* Output remaining statistics. */ + fprintf(pStatsFile, " Initial number of elements = %d\n", + NumberOfElements - Matrix->Fillins); + fprintf(pStatsFile, + " Initial average number of elements per row = %lf\n", + (double)(NumberOfElements - Matrix->Fillins) / (double)Size); + fprintf(pStatsFile, " Fill-ins = %d\n",Matrix->Fillins); + fprintf(pStatsFile, " Average number of fill-ins per row = %lf%%\n", + (double)Matrix->Fillins / (double)Size); + fprintf(pStatsFile, " Total number of elements = %d\n", + NumberOfElements); + fprintf(pStatsFile, " Average number of elements per row = %lf\n", + (double)NumberOfElements / (double)Size); + fprintf(pStatsFile," Density = %lf%%\n", + (double)(100.0*NumberOfElements)/(double)(Size*Size)); + fprintf(pStatsFile," Relative Threshold = %e\n", Matrix->RelThreshold); + fprintf(pStatsFile," Absolute Threshold = %e\n", Matrix->AbsThreshold); + fprintf(pStatsFile," Largest Element = %e\n", LargestElement); + fprintf(pStatsFile," Smallest Element = %e\n\n\n", SmallestElement); + +/* Close file. */ + (void)fclose(pStatsFile); + return 1; +} +#endif /* DOCUMENTATION */ diff --git a/sis/linsolv/spSolve.c b/sis/linsolv/spSolve.c new file mode 100644 index 0000000..8e06ceb --- /dev/null +++ b/sis/linsolv/spSolve.c @@ -0,0 +1,697 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/linsolv/spSolve.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:05 $ + * + */ +/* + * MATRIX SOLVE MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains the forward and backward substitution routines for + * the sparse matrix routines. + * + * >>> User accessible functions contained in this file: + * spSolve + * spSolveTransposed + * + * >>> Other functions contained in this file: + * SolveComplexMatrix + * SolveComplexTransposedMatrix + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifndef lint +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header: /users/pchong/CVS/sis/sis/linsolv/spSolve.c,v 1.1.1.1 2004/02/07 10:15:05 pchong Exp $"; +#endif + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spConfig.h" +#include "spMatrix.h" +#include "spDefs.h" + + + + + +/* + * SOLVE MATRIX EQUATION + * + * Performs forward elimination and back substitution to find the + * unknown vector from the RHS vector and factored matrix. This + * routine assumes that the pivots are associated with the lower + * triangular (L) matrix and that the diagonal of the upper triangular + * (U) matrix consists of ones. This routine arranges the computation + * in different way than is traditionally used in order to exploit the + * sparsity of the right-hand side. See the reference in spRevision. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * RHS <input> (RealVector) + * RHS is the input data array, the right hand side. This data is + * undisturbed and may be reused for other solves. + * Solution <output> (RealVector) + * Solution is the output data array. This routine is constructed such that + * RHS and Solution can be the same array. + * iRHS <input> (RealVector) + * iRHS is the imaginary portion of the input data array, the right + * hand side. This data is undisturbed and may be reused for other solves. + * This argument is only necessary if matrix is complex and if + * spSEPARATED_COMPLEX_VECTOR is set true. + * iSolution <output> (RealVector) + * iSolution is the imaginary portion of the output data array. This + * routine is constructed such that iRHS and iSolution can be + * the same array. This argument is only necessary if matrix is complex + * and if spSEPARATED_COMPLEX_VECTOR is set true. + * + * >>> Local variables: + * Intermediate (RealVector) + * Temporary storage for use in forward elimination and backward + * substitution. Commonly referred to as c, when the LU factorization + * equations are given as Ax = b, Lc = b, Ux = c Local version of + * Matrix->Intermediate, which was created during the initial + * factorization in function CreateInternalVectors() in the matrix + * factorization module. + * pElement (ElementPtr) + * Pointer used to address elements in both the lower and upper triangle + * matrices. + * pExtOrder (int *) + * Pointer used to sequentially access each entry in IntToExtRowMap + * and IntToExtColMap arrays. Used to quickly scramble and unscramble + * RHS and Solution to account for row and column interchanges. + * pPivot (ElementPtr) + * Pointer that points to current pivot or diagonal element. + * Size (int) + * Size of matrix. Made local to reduce indirection. + * Temp (RealNumber) + * Temporary storage for entries in arrays. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +/*VARARGS3*/ + +void +spSolve( eMatrix, RHS, Solution IMAG_VECTORS ) + +char *eMatrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register RealVector Intermediate; +register RealNumber Temp; +register int I, *pExtOrder, Size; +ElementPtr pPivot; +void SolveComplexMatrix(); + +/* Begin `spSolve'. */ + ASSERT( IS_VALID(Matrix) AND IS_FACTORED(Matrix) ); + +#if spCOMPLEX + if (Matrix->Complex) + { SolveComplexMatrix( Matrix, RHS, Solution IMAG_VECTORS ); + return; + } +#endif + +#if REAL + Intermediate = Matrix->Intermediate; + Size = Matrix->Size; + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector. */ + pExtOrder = &Matrix->IntToExtRowMap[Size]; + for (I = Size; I > 0; I--) + Intermediate[I] = RHS[*(pExtOrder--)]; + +/* Forward elimination. Solves Lc = b.*/ + for (I = 1; I <= Size; I++) + { +/* This step of the elimination is skipped if Temp equals zero. */ + if ((Temp = Intermediate[I]) != 0.0) + { pPivot = Matrix->Diag[I]; + Intermediate[I] = (Temp *= pPivot->Real); + + pElement = pPivot->NextInCol; + while (pElement != NULL) + { Intermediate[pElement->Row] -= Temp * pElement->Real; + pElement = pElement->NextInCol; + } + } + } + +/* Backward Substitution. Solves Ux = c.*/ + for (I = Size; I > 0; I--) + { Temp = Intermediate[I]; + pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { Temp -= pElement->Real * Intermediate[pElement->Col]; + pElement = pElement->NextInRow; + } + Intermediate[I] = Temp; + } + +/* Unscramble Intermediate vector while placing data in to Solution vector. */ + pExtOrder = &Matrix->IntToExtColMap[Size]; + for (I = Size; I > 0; I--) + Solution[*(pExtOrder--)] = Intermediate[I]; + + return; +#endif /* REAL */ +} + + + + + + + + + + + +#if spCOMPLEX +/* + * SOLVE COMPLEX MATRIX EQUATION + * + * Performs forward elimination and back substitution to find the + * unknown vector from the RHS vector and factored matrix. This + * routine assumes that the pivots are associated with the lower + * triangular (L) matrix and that the diagonal of the upper triangular + * (U) matrix consists of ones. This routine arranges the computation + * in different way than is traditionally used in order to exploit the + * sparsity of the right-hand side. See the reference in spRevision. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * RHS <input> (RealVector) + * RHS is the real portion of the input data array, the right hand + * side. This data is undisturbed and may be reused for other solves. + * Solution <output> (RealVector) + * Solution is the real portion of the output data array. This routine + * is constructed such that RHS and Solution can be the same + * array. + * iRHS <input> (RealVector) + * iRHS is the imaginary portion of the input data array, the right + * hand side. This data is undisturbed and may be reused for other solves. + * If spSEPARATED_COMPLEX_VECTOR is set false, there is no need to + * supply this array. + * iSolution <output> (RealVector) + * iSolution is the imaginary portion of the output data array. This + * routine is constructed such that iRHS and iSolution can be + * the same array. If spSEPARATED_COMPLEX_VECTOR is set false, there is no + * need to supply this array. + * + * >>> Local variables: + * Intermediate (ComplexVector) + * Temporary storage for use in forward elimination and backward + * substitution. Commonly referred to as c, when the LU factorization + * equations are given as Ax = b, Lc = b, Ux = c. + * Local version of Matrix->Intermediate, which was created during + * the initial factorization in function CreateInternalVectors() in the + * matrix factorization module. + * pElement (ElementPtr) + * Pointer used to address elements in both the lower and upper triangle + * matrices. + * pExtOrder (int *) + * Pointer used to sequentially access each entry in IntToExtRowMap + * and IntToExtColMap arrays. Used to quickly scramble and unscramble + * RHS and Solution to account for row and column interchanges. + * pPivot (ElementPtr) + * Pointer that points to current pivot or diagonal element. + * Size (int) + * Size of matrix. Made local to reduce indirection. + * Temp (ComplexNumber) + * Temporary storage for entries in arrays. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +static void +SolveComplexMatrix( Matrix, RHS, Solution IMAG_VECTORS ) + +MatrixPtr Matrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register ComplexVector Intermediate; +register int I, *pExtOrder, Size; +ElementPtr pPivot; +register ComplexVector ExtVector; +ComplexNumber Temp; + +/* Begin `SolveComplexMatrix'. */ + + Size = Matrix->Size; + Intermediate = (ComplexVector)Matrix->Intermediate; + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector. */ + pExtOrder = &Matrix->IntToExtRowMap[Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Size; I > 0; I--) + { Intermediate[I].Real = RHS[*(pExtOrder)]; + Intermediate[I].Imag = iRHS[*(pExtOrder--)]; + } +#else + ExtVector = (ComplexVector)RHS; + for (I = Size; I > 0; I--) + Intermediate[I] = ExtVector[*(pExtOrder--)]; +#endif + +/* Forward substitution. Solves Lc = b.*/ + for (I = 1; I <= Size; I++) + { Temp = Intermediate[I]; + +/* This step of the substitution is skipped if Temp equals zero. */ + if ((Temp.Real != 0.0) OR (Temp.Imag != 0.0)) + { pPivot = Matrix->Diag[I]; +/* Cmplx expr: Temp *= (1.0 / Pivot). */ + CMPLX_MULT_ASSIGN(Temp, *pPivot); + Intermediate[I] = Temp; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { +/* Cmplx expr: Intermediate[Element->Row] -= Temp * *Element. */ + CMPLX_MULT_SUBT_ASSIGN(Intermediate[pElement->Row], + Temp, *pElement); + pElement = pElement->NextInCol; + } + } + } + +/* Backward Substitution. Solves Ux = c.*/ + for (I = Size; I > 0; I--) + { Temp = Intermediate[I]; + pElement = Matrix->Diag[I]->NextInRow; + + while (pElement != NULL) + { +/* Cmplx expr: Temp -= *Element * Intermediate[Element->Col]. */ + CMPLX_MULT_SUBT_ASSIGN(Temp, *pElement,Intermediate[pElement->Col]); + pElement = pElement->NextInRow; + } + Intermediate[I] = Temp; + } + +/* Unscramble Intermediate vector while placing data in to Solution vector. */ + pExtOrder = &Matrix->IntToExtColMap[Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Size; I > 0; I--) + { Solution[*(pExtOrder)] = Intermediate[I].Real; + iSolution[*(pExtOrder--)] = Intermediate[I].Imag; + } +#else + ExtVector = (ComplexVector)Solution; + for (I = Size; I > 0; I--) + ExtVector[*(pExtOrder--)] = Intermediate[I]; +#endif + + return; +} +#endif /* spCOMPLEX */ + + + + + + + + + + + + + + +#if TRANSPOSE +/* + * SOLVE TRANSPOSED MATRIX EQUATION + * + * Performs forward elimination and back substitution to find the + * unknown vector from the RHS vector and transposed factored + * matrix. This routine is useful when performing sensitivity analysis + * on a circuit using the adjoint method. This routine assumes that + * the pivots are associated with the untransposed lower triangular + * (L) matrix and that the diagonal of the untransposed upper + * triangular (U) matrix consists of ones. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * RHS <input> (RealVector) + * RHS is the input data array, the right hand side. This data is + * undisturbed and may be reused for other solves. + * Solution <output> (RealVector) + * Solution is the output data array. This routine is constructed such that + * RHS and Solution can be the same array. + * iRHS <input> (RealVector) + * iRHS is the imaginary portion of the input data array, the right + * hand side. This data is undisturbed and may be reused for other solves. + * If spSEPARATED_COMPLEX_VECTOR is set false, or if matrix is real, there + * is no need to supply this array. + * iSolution <output> (RealVector) + * iSolution is the imaginary portion of the output data array. This + * routine is constructed such that iRHS and iSolution can be + * the same array. If spSEPARATED_COMPLEX_VECTOR is set false, or if + * matrix is real, there is no need to supply this array. + * + * >>> Local variables: + * Intermediate (RealVector) + * Temporary storage for use in forward elimination and backward + * substitution. Commonly referred to as c, when the LU factorization + * equations are given as Ax = b, Lc = b, Ux = c. Local version of + * Matrix->Intermediate, which was created during the initial + * factorization in function CreateInternalVectors() in the matrix + * factorization module. + * pElement (ElementPtr) + * Pointer used to address elements in both the lower and upper triangle + * matrices. + * pExtOrder (int *) + * Pointer used to sequentially access each entry in IntToExtRowMap + * and IntToExtRowMap arrays. Used to quickly scramble and unscramble + * RHS and Solution to account for row and column interchanges. + * pPivot (ElementPtr) + * Pointer that points to current pivot or diagonal element. + * Size (int) + * Size of matrix. Made local to reduce indirection. + * Temp (RealNumber) + * Temporary storage for entries in arrays. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +/*VARARGS3*/ + +void +spSolveTransposed( eMatrix, RHS, Solution IMAG_VECTORS ) + +char *eMatrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register RealVector Intermediate; +register int I, *pExtOrder, Size; +ElementPtr pPivot; +RealNumber Temp; +void SolveComplexTransposedMatrix(); + +/* Begin `spSolveTransposed'. */ + ASSERT( IS_VALID(Matrix) AND IS_FACTORED(Matrix) ); + +#if spCOMPLEX + if (Matrix->Complex) + { SolveComplexTransposedMatrix( Matrix, RHS, Solution IMAG_VECTORS ); + return; + } +#endif + +#if REAL + Size = Matrix->Size; + Intermediate = Matrix->Intermediate; + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector. */ + pExtOrder = &Matrix->IntToExtColMap[Size]; + for (I = Size; I > 0; I--) + Intermediate[I] = RHS[*(pExtOrder--)]; + +/* Forward elimination. */ + for (I = 1; I <= Size; I++) + { +/* This step of the elimination is skipped if Temp equals zero. */ + if ((Temp = Intermediate[I]) != 0.0) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { Intermediate[pElement->Col] -= Temp * pElement->Real; + pElement = pElement->NextInRow; + } + + } + } + +/* Backward Substitution. */ + for (I = Size; I > 0; I--) + { pPivot = Matrix->Diag[I]; + Temp = Intermediate[I]; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { Temp -= pElement->Real * Intermediate[pElement->Row]; + pElement = pElement->NextInCol; + } + Intermediate[I] = Temp * pPivot->Real; + } + +/* Unscramble Intermediate vector while placing data in to Solution vector. */ + pExtOrder = &Matrix->IntToExtRowMap[Size]; + for (I = Size; I > 0; I--) + Solution[*(pExtOrder--)] = Intermediate[I]; + + return; +#endif /* REAL */ +} +#endif /* TRANSPOSE */ + + + + + + + + + + +#if TRANSPOSE AND spCOMPLEX +/* + * SOLVE COMPLEX TRANSPOSED MATRIX EQUATION + * + * Performs forward elimination and back substitution to find the + * unknown vector from the RHS vector and transposed factored + * matrix. This routine is useful when performing sensitivity analysis + * on a circuit using the adjoint method. This routine assumes that + * the pivots are associated with the untransposed lower triangular + * (L) matrix and that the diagonal of the untransposed upper + * triangular (U) matrix consists of ones. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to matrix. + * RHS <input> (RealVector) + * RHS is the input data array, the right hand + * side. This data is undisturbed and may be reused for other solves. + * This vector is only the real portion if the matrix is complex and + * spSEPARATED_COMPLEX_VECTORS is set true. + * Solution <output> (RealVector) + * Solution is the real portion of the output data array. This routine + * is constructed such that RHS and Solution can be the same array. + * This vector is only the real portion if the matrix is complex and + * spSEPARATED_COMPLEX_VECTORS is set true. + * iRHS <input> (RealVector) + * iRHS is the imaginary portion of the input data array, the right + * hand side. This data is undisturbed and may be reused for other solves. + * If either spCOMPLEX or spSEPARATED_COMPLEX_VECTOR is set false, there + * is no need to supply this array. + * iSolution <output> (RealVector) + * iSolution is the imaginary portion of the output data array. This + * routine is constructed such that iRHS and iSolution can be + * the same array. If spCOMPLEX or spSEPARATED_COMPLEX_VECTOR is set + * false, there is no need to supply this array. + * + * >>> Local variables: + * Intermediate (ComplexVector) + * Temporary storage for use in forward elimination and backward + * substitution. Commonly referred to as c, when the LU factorization + * equations are given as Ax = b, Lc = b, Ux = c. Local version of + * Matrix->Intermediate, which was created during + * the initial factorization in function CreateInternalVectors() in the + * matrix factorization module. + * pElement (ElementPtr) + * Pointer used to address elements in both the lower and upper triangle + * matrices. + * pExtOrder (int *) + * Pointer used to sequentially access each entry in IntToExtRowMap + * and IntToExtColMap arrays. Used to quickly scramble and unscramble + * RHS and Solution to account for row and column interchanges. + * pPivot (ElementPtr) + * Pointer that points to current pivot or diagonal element. + * Size (int) + * Size of matrix. Made local to reduce indirection. + * Temp (ComplexNumber) + * Temporary storage for entries in arrays. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +static void +SolveComplexTransposedMatrix(Matrix, RHS, Solution IMAG_VECTORS ) + +MatrixPtr Matrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register ComplexVector Intermediate; +register int I, *pExtOrder, Size; +register ComplexVector ExtVector; +ElementPtr pPivot; +ComplexNumber Temp; + +/* Begin `SolveComplexTransposedMatrix'. */ + + Size = Matrix->Size; + Intermediate = (ComplexVector)Matrix->Intermediate; + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector. */ + pExtOrder = &Matrix->IntToExtColMap[Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Size; I > 0; I--) + { Intermediate[I].Real = RHS[*(pExtOrder)]; + Intermediate[I].Imag = iRHS[*(pExtOrder--)]; + } +#else + ExtVector = (ComplexVector)RHS; + for (I = Size; I > 0; I--) + Intermediate[I] = ExtVector[*(pExtOrder--)]; +#endif + +/* Forward elimination. */ + for (I = 1; I <= Size; I++) + { Temp = Intermediate[I]; + +/* This step of the elimination is skipped if Temp equals zero. */ + if ((Temp.Real != 0.0) OR (Temp.Imag != 0.0)) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { +/* Cmplx expr: Intermediate[Element->Col] -= Temp * *Element. */ + CMPLX_MULT_SUBT_ASSIGN( Intermediate[pElement->Col], + Temp, *pElement); + pElement = pElement->NextInRow; + } + } + } + +/* Backward Substitution. */ + for (I = Size; I > 0; I--) + { pPivot = Matrix->Diag[I]; + Temp = Intermediate[I]; + pElement = pPivot->NextInCol; + + while (pElement != NULL) + { +/* Cmplx expr: Temp -= Intermediate[Element->Row] * *Element. */ + CMPLX_MULT_SUBT_ASSIGN(Temp,Intermediate[pElement->Row],*pElement); + + pElement = pElement->NextInCol; + } +/* Cmplx expr: Intermediate = Temp * (1.0 / *pPivot). */ + CMPLX_MULT(Intermediate[I], Temp, *pPivot); + } + +/* Unscramble Intermediate vector while placing data in to Solution vector. */ + pExtOrder = &Matrix->IntToExtRowMap[Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Size; I > 0; I--) + { Solution[*(pExtOrder)] = Intermediate[I].Real; + iSolution[*(pExtOrder--)] = Intermediate[I].Imag; + } +#else + ExtVector = (ComplexVector)Solution; + for (I = Size; I > 0; I--) + ExtVector[*(pExtOrder--)] = Intermediate[I]; +#endif + + return; +} +#endif /* TRANSPOSE AND spCOMPLEX */ diff --git a/sis/linsolv/spUtils.c b/sis/linsolv/spUtils.c new file mode 100644 index 0000000..ae5c2fc --- /dev/null +++ b/sis/linsolv/spUtils.c @@ -0,0 +1,2132 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/linsolv/spUtils.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:05 $ + * + */ +/* + * MATRIX UTILITY MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains various optional utility routines. + * + * >>> User accessible functions contained in this file: + * spMNA_Preorder + * spScale + * spMultiply + * spMultTransposed + * spDeterminant + * spStrip + * spDeleteRowAndCol + * spPseudoCondition + * spCondition + * spNorm + * spLargestElement + * spRoundoff + * + * >>> Other functions contained in this file: + * CountTwins + * SwapCols + * ScaleComplexMatrix + * ComplexMatrixMultiply + * ComplexCondition + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifndef lint +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header: /users/pchong/CVS/sis/sis/linsolv/spUtils.c,v 1.1.1.1 2004/02/07 10:15:05 pchong Exp $"; +#endif + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spConfig.h" +#include "spMatrix.h" +#include "spDefs.h" + + + + + + +#if MODIFIED_NODAL +/* + * PREORDER MODIFIED NODE ADMITTANCE MATRIX TO REMOVE ZEROS FROM DIAGONAL + * + * This routine massages modified node admittance matrices to remove + * zeros from the diagonal. It takes advantage of the fact that the + * row and column associated with a zero diagonal usually have + * structural ones placed symmetricly. This routine should be used + * only on modified node admittance matrices and should be executed + * after the matrix has been built but before the factorization + * begins. It should be executed for the initial factorization only + * and should be executed before the rows have been linked. Thus it + * should be run before using spScale(), spMultiply(), + * spDeleteRowAndCol(), or spNorm(). + * + * This routine exploits the fact that the structural ones are placed + * in the matrix in symmetric twins. For example, the stamps for + * grounded and a floating voltage sources are + * grounded: floating: + * [ x x 1 ] [ x x 1 ] + * [ x x ] [ x x -1 ] + * [ 1 ] [ 1 -1 ] + * Notice for the grounded source, there is one set of twins, and for + * the floating, there are two sets. We remove the zero from the diagonal + * by swapping the rows associated with a set of twins. For example: + * grounded: floating 1: floating 2: + * [ 1 ] [ 1 -1 ] [ x x 1 ] + * [ x x ] [ x x -1 ] [ 1 -1 ] + * [ x x 1 ] [ x x 1 ] [ x x -1 ] + * + * It is important to deal with any zero diagonals that only have one + * set of twins before dealing with those that have more than one because + * swapping row destroys the symmetry of any twins in the rows being + * swapped, which may limit future moves. Consider + * [ x x 1 ] + * [ x x -1 1 ] + * [ 1 -1 ] + * [ 1 ] + * There is one set of twins for diagonal 4 and two for diagonal 3. + * Dealing with diagonal 4 first requires swapping rows 2 and 4. + * [ x x 1 ] + * [ 1 ] + * [ 1 -1 ] + * [ x x -1 1 ] + * We can now deal with diagonal 3 by swapping rows 1 and 3. + * [ 1 -1 ] + * [ 1 ] + * [ x x 1 ] + * [ x x -1 1 ] + * And we are done, there are no zeros left on the diagonal. However, if + * we originally dealt with diagonal 3 first, we could swap rows 2 and 3 + * [ x x 1 ] + * [ 1 -1 ] + * [ x x -1 1 ] + * [ 1 ] + * Diagonal 4 no longer has a symmetric twin and we cannot continue. + * + * So we always take care of lone twins first. When none remain, we + * choose arbitrarily a set of twins for a diagonal with more than one set + * and swap the rows corresponding to that twin. We then deal with any + * lone twins that were created and repeat the procedure until no + * zero diagonals with symmetric twins remain. + * + * In this particular implementation, columns are swapped rather than rows. + * The algorithm used in this function was developed by Ken Kundert and + * Tom Quarles. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to the matrix to be preordered. + * + * >>> Local variables; + * J (int) + * Column with zero diagonal being currently considered. + * pTwin1 (ElementPtr) + * Pointer to the twin found in the column belonging to the zero diagonal. + * pTwin2 (ElementPtr) + * Pointer to the twin found in the row belonging to the zero diagonal. + * belonging to the zero diagonal. + * AnotherPassNeeded (BOOLEAN) + * Flag indicating that at least one zero diagonal with symmetric twins + * remain. + * StartAt (int) + * Column number of first zero diagonal with symmetric twins. + * Swapped (BOOLEAN) + * Flag indicating that columns were swapped on this pass. + * Twins (int) + * Number of symmetric twins corresponding to current zero diagonal. + */ + +void +spMNA_Preorder( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int J, Size; +ElementPtr pTwin1, pTwin2; +int Twins, StartAt = 1; +BOOLEAN Swapped, AnotherPassNeeded; + +/* Begin `spMNA_Preorder'. */ + ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored ); + + if (Matrix->RowsLinked) return; + Size = Matrix->Size; + Matrix->Reordered = YES; + + do + { AnotherPassNeeded = Swapped = NO; + +/* Search for zero diagonals with lone twins. */ + for (J = StartAt; J <= Size; J++) + { if (Matrix->Diag[J] == NULL) + { Twins = CountTwins( Matrix, J, &pTwin1, &pTwin2 ); + if (Twins == 1) + { /* Lone twins found, swap rows. */ + SwapCols( Matrix, pTwin1, pTwin2 ); + Swapped = YES; + } + else if ((Twins > 1) AND NOT AnotherPassNeeded) + { AnotherPassNeeded = YES; + StartAt = J; + } + } + } + +/* All lone twins are gone, look for zero diagonals with multiple twins. */ + if (AnotherPassNeeded) + { for (J = StartAt; NOT Swapped AND (J <= Size); J++) + { if (Matrix->Diag[J] == NULL) + { Twins = CountTwins( Matrix, J, &pTwin1, &pTwin2 ); + SwapCols( Matrix, pTwin1, pTwin2 ); + Swapped = YES; + } + } + } + } while (AnotherPassNeeded); + return; +} + + + + +/* + * COUNT TWINS + * + * This function counts the number of symmetric twins associated with + * a zero diagonal and returns one set of twins if any exist. The + * count is terminated early at two. + */ + +static int +CountTwins( Matrix, Col, ppTwin1, ppTwin2 ) + +MatrixPtr Matrix; +int Col; +ElementPtr *ppTwin1, *ppTwin2; +{ +int Row, Twins = 0; +ElementPtr pTwin1, pTwin2; + +/* Begin `CountTwins'. */ + + pTwin1 = Matrix->FirstInCol[Col]; + while (pTwin1 != NULL) + { if (ABS(pTwin1->Real) == 1.0) + { Row = pTwin1->Row; + pTwin2 = Matrix->FirstInCol[Row]; + while ((pTwin2 != NULL) AND (pTwin2->Row != Col)) + pTwin2 = pTwin2->NextInCol; + if ((pTwin2 != NULL) AND (ABS(pTwin2->Real) == 1.0)) + { /* Found symmetric twins. */ + if (++Twins >= 2) return Twins; + (*ppTwin1 = pTwin1)->Col = Col; + (*ppTwin2 = pTwin2)->Col = Row; + } + } + pTwin1 = pTwin1->NextInCol; + } + return Twins; +} + + + + +/* + * SWAP COLUMNS + * + * This function swaps two columns and is applicable before the rows are + * linked. + */ + +static +SwapCols( Matrix, pTwin1, pTwin2 ) + +MatrixPtr Matrix; +ElementPtr pTwin1, pTwin2; +{ +int Col1 = pTwin1->Col, Col2 = pTwin2->Col; + +/* Begin `SwapCols'. */ + + SWAP (ElementPtr, Matrix->FirstInCol[Col1], Matrix->FirstInCol[Col2]); + SWAP (int, Matrix->IntToExtColMap[Col1], Matrix->IntToExtColMap[Col2]); +#if TRANSLATE + Matrix->ExtToIntColMap[Matrix->IntToExtColMap[Col2]]=Col2; + Matrix->ExtToIntColMap[Matrix->IntToExtColMap[Col1]]=Col1; +#endif + + Matrix->Diag[Col1] = pTwin2; + Matrix->Diag[Col2] = pTwin1; + Matrix->NumberOfInterchangesIsOdd = NOT Matrix->NumberOfInterchangesIsOdd; + return; +} +#endif /* MODIFIED_NODAL */ + + + + + + + + + +#if SCALING +/* + * SCALE MATRIX + * + * This function scales the matrix to enhance the possibility of + * finding a good pivoting order. Note that scaling enhances accuracy + * of the solution only if it affects the pivoting order, so it makes + * no sense to scale the matrix before spFactor(). If scaling is + * desired it should be done before spOrderAndFactor(). There + * are several things to take into account when choosing the scale + * factors. First, the scale factors are directly multiplied against + * the elements in the matrix. To prevent roundoff, each scale factor + * should be equal to an integer power of the number base of the + * machine. Since most machines operate in base two, scale factors + * should be a power of two. Second, the matrix should be scaled such + * that the matrix of element uncertainties is equilibrated. Third, + * this function multiplies the scale factors by the elements, so if + * one row tends to have uncertainties 1000 times smaller than the + * other rows, then its scale factor should be 1024, not 1/1024. + * Fourth, to save time, this function does not scale rows or columns + * if their scale factors are equal to one. Thus, the scale factors + * should be normalized to the most common scale factor. Rows and + * columns should be normalized separately. For example, if the size + * of the matrix is 100 and 10 rows tend to have uncertainties near + * 1e-6 and the remaining 90 have uncertainties near 1e-12, then the + * scale factor for the 10 should be 1/1,048,576 and the scale factors + * for the remaining 90 should be 1. Fifth, since this routine + * directly operates on the matrix, it is necessary to apply the scale + * factors to the RHS and Solution vectors. It may be easier to + * simply use spOrderAndFactor() on a scaled matrix to choose the + * pivoting order, and then throw away the matrix. Subsequent + * factorizations, performed with spFactor(), will not need to have + * the RHS and Solution vectors descaled. Lastly, this function + * should not be executed before the function spMNA_Preorder. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to the matrix to be scaled. + * SolutionScaleFactors <input> (RealVector) + * The array of Solution scale factors. These factors scale the columns. + * All scale factors are real valued. + * RHS_ScaleFactors <input> (RealVector) + * The array of RHS scale factors. These factors scale the rows. + * All scale factors are real valued. + * + * >>> Local variables: + * lSize (int) + * Local version of the size of the matrix. + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * pExtOrder (int *) + * Pointer into either IntToExtRowMap or IntToExtColMap vector. Used to + * compensate for any row or column swaps that have been performed. + * ScaleFactor (RealNumber) + * The scale factor being used on the current row or column. + */ + +void +spScale( eMatrix, RHS_ScaleFactors, SolutionScaleFactors ) + +char *eMatrix; +register RealVector RHS_ScaleFactors, SolutionScaleFactors; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int I, lSize, *pExtOrder; +RealNumber ScaleFactor; +void ScaleComplexMatrix(); + +/* Begin `spScale'. */ + ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored ); + if (NOT Matrix->RowsLinked) spcLinkRows( Matrix ); + +#if spCOMPLEX + if (Matrix->Complex) + { ScaleComplexMatrix( Matrix, RHS_ScaleFactors, SolutionScaleFactors ); + return; + } +#endif + +#if REAL + lSize = Matrix->Size; + +/* Correct pointers to arrays for ARRAY_OFFSET */ +#if NOT ARRAY_OFFSET + --RHS_ScaleFactors; + --SolutionScaleFactors; +#endif + +/* Scale Rows */ + pExtOrder = &Matrix->IntToExtRowMap[1]; + for (I = 1; I <= lSize; I++) + { if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInRow[I]; + + while (pElement != NULL) + { pElement->Real *= ScaleFactor; + pElement = pElement->NextInRow; + } + } + } + +/* Scale Columns */ + pExtOrder = &Matrix->IntToExtColMap[1]; + for (I = 1; I <= lSize; I++) + { if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInCol[I]; + + while (pElement != NULL) + { pElement->Real *= ScaleFactor; + pElement = pElement->NextInCol; + } + } + } + return; + +#endif /* REAL */ +} +#endif /* SCALING */ + + + + + + + + + +#if spCOMPLEX AND SCALING +/* + * SCALE COMPLEX MATRIX + * + * This function scales the matrix to enhance the possibility of + * finding a good pivoting order. Note that scaling enhances accuracy + * of the solution only if it affects the pivoting order, so it makes + * no sense to scale the matrix before spFactor(). If scaling is + * desired it should be done before spOrderAndFactor(). There + * are several things to take into account when choosing the scale + * factors. First, the scale factors are directly multiplied against + * the elements in the matrix. To prevent roundoff, each scale factor + * should be equal to an integer power of the number base of the + * machine. Since most machines operate in base two, scale factors + * should be a power of two. Second, the matrix should be scaled such + * that the matrix of element uncertainties is equilibrated. Third, + * this function multiplies the scale factors by the elements, so if + * one row tends to have uncertainties 1000 times smaller than the + * other rows, then its scale factor should be 1024, not 1/1024. + * Fourth, to save time, this function does not scale rows or columns + * if their scale factors are equal to one. Thus, the scale factors + * should be normalized to the most common scale factor. Rows and + * columns should be normalized separately. For example, if the size + * of the matrix is 100 and 10 rows tend to have uncertainties near + * 1e-6 and the remaining 90 have uncertainties near 1e-12, then the + * scale factor for the 10 should be 1/1,048,576 and the scale factors + * for the remaining 90 should be 1. Fifth, since this routine + * directly operates on the matrix, it is necessary to apply the scale + * factors to the RHS and Solution vectors. It may be easier to + * simply use spOrderAndFactor() on a scaled matrix to choose the + * pivoting order, and then throw away the matrix. Subsequent + * factorizations, performed with spFactor(), will not need to have + * the RHS and Solution vectors descaled. Lastly, this function + * should not be executed before the function spMNA_Preorder. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to the matrix to be scaled. + * SolutionScaleFactors <input> (RealVector) + * The array of Solution scale factors. These factors scale the columns. + * All scale factors are real valued. + * RHS_ScaleFactors <input> (RealVector) + * The array of RHS scale factors. These factors scale the rows. + * All scale factors are real valued. + * + * >>> Local variables: + * lSize (int) + * Local version of the size of the matrix. + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * pExtOrder (int *) + * Pointer into either IntToExtRowMap or IntToExtColMap vector. Used to + * compensate for any row or column swaps that have been performed. + * ScaleFactor (RealNumber) + * The scale factor being used on the current row or column. + */ + +static void +ScaleComplexMatrix( Matrix, RHS_ScaleFactors, SolutionScaleFactors ) + +MatrixPtr Matrix; +register RealVector RHS_ScaleFactors, SolutionScaleFactors; +{ +register ElementPtr pElement; +register int I, lSize, *pExtOrder; +RealNumber ScaleFactor; + +/* Begin `ScaleComplexMatrix'. */ + lSize = Matrix->Size; + +/* Correct pointers to arrays for ARRAY_OFFSET */ +#if NOT ARRAY_OFFSET + --RHS_ScaleFactors; + --SolutionScaleFactors; +#endif + +/* Scale Rows */ + pExtOrder = &Matrix->IntToExtRowMap[1]; + for (I = 1; I <= lSize; I++) + { if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInRow[I]; + + while (pElement != NULL) + { pElement->Real *= ScaleFactor; + pElement->Imag *= ScaleFactor; + pElement = pElement->NextInRow; + } + } + } + +/* Scale Columns */ + pExtOrder = &Matrix->IntToExtColMap[1]; + for (I = 1; I <= lSize; I++) + { if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInCol[I]; + + while (pElement != NULL) + { pElement->Real *= ScaleFactor; + pElement->Imag *= ScaleFactor; + pElement = pElement->NextInCol; + } + } + } + return; +} +#endif /* SCALING AND spCOMPLEX */ + + + + + + + + +#if MULTIPLICATION +/* + * MATRIX MULTIPLICATION + * + * Multiplies matrix by solution vector to find source vector. + * Assumes matrix has not been factored. This routine can be used + * as a test to see if solutions are correct. It should not be used + * before spMNA_Preorder(). + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to the matrix. + * RHS <output> (RealVector) + * RHS is the right hand side. This is what is being solved for. + * Solution <input> (RealVector) + * Solution is the vector being multiplied by the matrix. + * iRHS <output> (RealVector) + * iRHS is the imaginary portion of the right hand side. This is + * what is being solved for. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. + * iSolution <input> (RealVector) + * iSolution is the imaginary portion of the vector being multiplied + * by the matrix. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +void +spMultiply( eMatrix, RHS, Solution IMAG_VECTORS ) + +char *eMatrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register RealVector Vector; +register RealNumber Sum; +register int I, *pExtOrder; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +extern void ComplexMatrixMultiply(); + +/* Begin `spMultiply'. */ + ASSERT( IS_SPARSE( Matrix ) AND NOT Matrix->Factored ); + if (NOT Matrix->RowsLinked) spcLinkRows(Matrix); + +#if spCOMPLEX + if (Matrix->Complex) + { ComplexMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS ); + return; + } +#endif + +#if REAL +#if NOT ARRAY_OFFSET +/* Correct array pointers for ARRAY_OFFSET. */ + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ + Vector = Matrix->Intermediate; + pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + Vector[I] = Solution[*(pExtOrder--)]; + + pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; + Sum = 0.0; + + while (pElement != NULL) + { Sum += pElement->Real * Vector[pElement->Col]; + pElement = pElement->NextInRow; + } + RHS[*pExtOrder--] = Sum; + } + return; +#endif /* REAL */ +} +#endif /* MULTIPLICATION */ + + + + + + + +#if spCOMPLEX AND MULTIPLICATION +/* + * COMPLEX MATRIX MULTIPLICATION + * + * Multiplies matrix by solution vector to find source vector. + * Assumes matrix has not been factored. This routine can be used + * as a test to see if solutions are correct. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to the matrix. + * RHS <output> (RealVector) + * RHS is the right hand side. This is what is being solved for. + * This is only the real portion of the right-hand side if the matrix + * is complex and spSEPARATED_COMPLEX_VECTORS is set true. + * Solution <input> (RealVector) + * Solution is the vector being multiplied by the matrix. This is only + * the real portion if the matrix is complex and + * spSEPARATED_COMPLEX_VECTORS is set true. + * iRHS <output> (RealVector) + * iRHS is the imaginary portion of the right hand side. This is + * what is being solved for. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. + * iSolution <input> (RealVector) + * iSolution is the imaginary portion of the vector being multiplied + * by the matrix. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +static void +ComplexMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS ) + +MatrixPtr Matrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register ComplexVector Vector; +register ComplexNumber Sum; +register int I, *pExtOrder; + +/* Begin `ComplexMatrixMultiply'. */ + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ + Vector = (ComplexVector)Matrix->Intermediate; + pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Matrix->Size; I > 0; I--) + { Vector[I].Real = Solution[*pExtOrder]; + Vector[I].Imag = iSolution[*(pExtOrder--)]; + } +#else + for (I = Matrix->Size; I > 0; I--) + Vector[I] = ((ComplexVector)Solution)[*(pExtOrder--)]; +#endif + + pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; + Sum.Real = Sum.Imag = 0.0; + + while (pElement != NULL) + { /* Cmplx expression : Sum += Element * Vector[Col] */ + CMPLX_MULT_ADD_ASSIGN( Sum, *pElement, Vector[pElement->Col] ); + pElement = pElement->NextInRow; + } + +#if spSEPARATED_COMPLEX_VECTORS + RHS[*pExtOrder] = Sum.Real; + iRHS[*pExtOrder--] = Sum.Imag; +#else + ((ComplexVector)RHS)[*pExtOrder--] = Sum; +#endif + } + return; +} +#endif /* spCOMPLEX AND MULTIPLICATION */ + + + + + + + + +#if MULTIPLICATION AND TRANSPOSE +/* + * TRANSPOSED MATRIX MULTIPLICATION + * + * Multiplies transposed matrix by solution vector to find source vector. + * Assumes matrix has not been factored. This routine can be used + * as a test to see if solutions are correct. It should not be used + * before spMNA_Preorder(). + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to the matrix. + * RHS <output> (RealVector) + * RHS is the right hand side. This is what is being solved for. + * Solution <input> (RealVector) + * Solution is the vector being multiplied by the matrix. + * iRHS <output> (RealVector) + * iRHS is the imaginary portion of the right hand side. This is + * what is being solved for. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. + * iSolution <input> (RealVector) + * iSolution is the imaginary portion of the vector being multiplied + * by the matrix. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +void +spMultTransposed( eMatrix, RHS, Solution IMAG_VECTORS ) + +char *eMatrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register RealVector Vector; +register RealNumber Sum; +register int I, *pExtOrder; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +extern void ComplexTransposedMatrixMultiply(); + +/* Begin `spMultTransposed'. */ + ASSERT( IS_SPARSE( Matrix ) AND NOT Matrix->Factored ); + +#if spCOMPLEX + if (Matrix->Complex) + { ComplexTransposedMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS ); + return; + } +#endif + +#if REAL +#if NOT ARRAY_OFFSET +/* Correct array pointers for ARRAY_OFFSET. */ + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ + Vector = Matrix->Intermediate; + pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + Vector[I] = Solution[*(pExtOrder--)]; + + pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInCol[I]; + Sum = 0.0; + + while (pElement != NULL) + { Sum += pElement->Real * Vector[pElement->Row]; + pElement = pElement->NextInCol; + } + RHS[*pExtOrder--] = Sum; + } + return; +#endif /* REAL */ +} +#endif /* MULTIPLICATION AND TRANSPOSE */ + + + + + + + +#if spCOMPLEX AND MULTIPLICATION AND TRANSPOSE +/* + * COMPLEX TRANSPOSED MATRIX MULTIPLICATION + * + * Multiplies transposed matrix by solution vector to find source vector. + * Assumes matrix has not been factored. This routine can be used + * as a test to see if solutions are correct. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to the matrix. + * RHS <output> (RealVector) + * RHS is the right hand side. This is what is being solved for. + * This is only the real portion of the right-hand side if the matrix + * is complex and spSEPARATED_COMPLEX_VECTORS is set true. + * Solution <input> (RealVector) + * Solution is the vector being multiplied by the matrix. This is only + * the real portion if the matrix is complex and + * spSEPARATED_COMPLEX_VECTORS is set true. + * iRHS <output> (RealVector) + * iRHS is the imaginary portion of the right hand side. This is + * what is being solved for. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. + * iSolution <input> (RealVector) + * iSolution is the imaginary portion of the vector being multiplied + * by the matrix. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is true. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +static void +ComplexTransposedMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS ) + +MatrixPtr Matrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register ComplexVector Vector; +register ComplexNumber Sum; +register int I, *pExtOrder; + +/* Begin `ComplexMatrixMultiply'. */ + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ + Vector = (ComplexVector)Matrix->Intermediate; + pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Matrix->Size; I > 0; I--) + { Vector[I].Real = Solution[*pExtOrder]; + Vector[I].Imag = iSolution[*(pExtOrder--)]; + } +#else + for (I = Matrix->Size; I > 0; I--) + Vector[I] = ((ComplexVector)Solution)[*(pExtOrder--)]; +#endif + + pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInCol[I]; + Sum.Real = Sum.Imag = 0.0; + + while (pElement != NULL) + { /* Cmplx expression : Sum += Element * Vector[Row] */ + CMPLX_MULT_ADD_ASSIGN( Sum, *pElement, Vector[pElement->Row] ); + pElement = pElement->NextInCol; + } + +#if spSEPARATED_COMPLEX_VECTORS + RHS[*pExtOrder] = Sum.Real; + iRHS[*pExtOrder--] = Sum.Imag; +#else + ((ComplexVector)RHS)[*pExtOrder--] = Sum; +#endif + } + return; +} +#endif /* spCOMPLEX AND MULTIPLICATION AND TRANSPOSE */ + + + + + + + + +#if DETERMINANT +/* + * CALCULATE DETERMINANT + * + * This routine in capable of calculating the determinant of the + * matrix once the LU factorization has been performed. Hence, only + * use this routine after spFactor() and before spClear(). + * The determinant equals the product of all the diagonal elements of + * the lower triangular matrix L, except that this product may need + * negating. Whether the product or the negative product equals the + * determinant is determined by the number of row and column + * interchanges performed. Note that the determinants of matrices can + * be very large or very small. On large matrices, the determinant + * can be far larger or smaller than can be represented by a floating + * point number. For this reason the determinant is scaled to a + * reasonable value and the logarithm of the scale factor is returned. + * + * >>> Arguments: + * eMatrix <input> (char *) + * A pointer to the matrix for which the determinant is desired. + * pExponent <output> (int *) + * The logarithm base 10 of the scale factor for the determinant. To find + * the actual determinant, Exponent should be added to the exponent of + * Determinant. + * pDeterminant <output> (RealNumber *) + * The real portion of the determinant. This number is scaled to be + * greater than or equal to 1.0 and less than 10.0. + * piDeterminant <output> (RealNumber *) + * The imaginary portion of the determinant. When the matrix is real + * this pointer need not be supplied, nothing will be returned. This + * number is scaled to be greater than or equal to 1.0 and less than 10.0. + * + * >>> Local variables: + * Norm (RealNumber) + * L-infinity norm of a complex number. + * Size (int) + * Local storage for Matrix->Size. Placed in a register for speed. + * Temp (RealNumber) + * Temporary storage for real portion of determinant. + */ + +#if spCOMPLEX +void +spDeterminant( eMatrix, pExponent, pDeterminant, piDeterminant ) +RealNumber *piDeterminant; +#else +void +spDeterminant( eMatrix, pExponent, pDeterminant ) +#endif + +char *eMatrix; +register RealNumber *pDeterminant; +int *pExponent; +{ +register MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I, Size; +RealNumber Norm, nr, ni; +ComplexNumber Pivot, cDeterminant; + +#define NORM(a) (nr = ABS((a).Real), ni = ABS((a).Imag), MAX (nr,ni)) + +/* Begin `spDeterminant'. */ + ASSERT( IS_SPARSE( Matrix ) AND IS_FACTORED(Matrix) ); + *pExponent = 0; + + if (Matrix->Error == spSINGULAR) + { *pDeterminant = 0.0; +#if spCOMPLEX + if (Matrix->Complex) *piDeterminant = 0.0; +#endif + return; + } + + Size = Matrix->Size; + I = 0; + +#if spCOMPLEX + if (Matrix->Complex) /* Complex Case. */ + { cDeterminant.Real = 1.0; + cDeterminant.Imag = 0.0; + + while (++I <= Size) + { CMPLX_RECIPROCAL( Pivot, *Matrix->Diag[I] ); + CMPLX_MULT_ASSIGN( cDeterminant, Pivot ); + +/* Scale Determinant. */ + Norm = NORM( cDeterminant ); + if (Norm != 0.0) + { while (Norm >= 1.0e12) + { cDeterminant.Real *= 1.0e-12; + cDeterminant.Imag *= 1.0e-12; + *pExponent += 12; + Norm = NORM( cDeterminant ); + } + while (Norm < 1.0e-12) + { cDeterminant.Real *= 1.0e12; + cDeterminant.Imag *= 1.0e12; + *pExponent -= 12; + Norm = NORM( cDeterminant ); + } + } + } + +/* Scale Determinant again, this time to be between 1.0 <= x < 10.0. */ + Norm = NORM( cDeterminant ); + if (Norm != 0.0) + { while (Norm >= 10.0) + { cDeterminant.Real *= 0.1; + cDeterminant.Imag *= 0.1; + (*pExponent)++; + Norm = NORM( cDeterminant ); + } + while (Norm < 1.0) + { cDeterminant.Real *= 10.0; + cDeterminant.Imag *= 10.0; + (*pExponent)--; + Norm = NORM( cDeterminant ); + } + } + if (Matrix->NumberOfInterchangesIsOdd) + CMPLX_NEGATE( cDeterminant ); + + *pDeterminant = cDeterminant.Real; + *piDeterminant = cDeterminant.Imag; + } +#endif /* spCOMPLEX */ +#if REAL AND spCOMPLEX + else +#endif +#if REAL + { /* Real Case. */ + *pDeterminant = 1.0; + + while (++I <= Size) + { *pDeterminant /= Matrix->Diag[I]->Real; + +/* Scale Determinant. */ + if (*pDeterminant != 0.0) + { while (ABS(*pDeterminant) >= 1.0e12) + { *pDeterminant *= 1.0e-12; + *pExponent += 12; + } + while (ABS(*pDeterminant) < 1.0e-12) + { *pDeterminant *= 1.0e12; + *pExponent -= 12; + } + } + } + +/* Scale Determinant again, this time to be between 1.0 <= x < 10.0. */ + if (*pDeterminant != 0.0) + { while (ABS(*pDeterminant) >= 10.0) + { *pDeterminant *= 0.1; + (*pExponent)++; + } + while (ABS(*pDeterminant) < 1.0) + { *pDeterminant *= 10.0; + (*pExponent)--; + } + } + if (Matrix->NumberOfInterchangesIsOdd) + *pDeterminant = -*pDeterminant; + } +#endif /* REAL */ +} +#endif /* DETERMINANT */ + + + + + + + + +#if STRIP + +/* + * STRIP FILL-INS FROM MATRIX + * + * Strips the matrix of all fill-ins. + * + * >>> Arguments: + * Matrix <input> (char *) + * Pointer to the matrix to be stripped. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer that is used to step through the matrix. + * ppElement (ElementPtr *) + * Pointer to the location of an ElementPtr. This location will be + * updated if a fill-in is stripped from the matrix. + * pFillin (ElementPtr) + * Pointer used to step through the lists of fill-ins while marking them. + * pLastFillin (ElementPtr) + * A pointer to the last fill-in in the list. Used to terminate a loop. + * pListNode (struct FillinListNodeStruct *) + * A pointer to a node in the FillinList linked-list. + */ + +void +spStripFills( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +struct FillinListNodeStruct *pListNode; + +/* Begin `spStripFills'. */ + ASSERT( IS_SPARSE( Matrix ) ); + if (Matrix->Fillins == 0) return; + Matrix->NeedsOrdering = YES; + Matrix->Elements -= Matrix->Fillins; + Matrix->Fillins = 0; + +/* Mark the fill-ins. */ + { register ElementPtr pFillin, pLastFillin; + + pListNode = Matrix->LastFillinListNode = Matrix->FirstFillinListNode; + Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList; + Matrix->NextAvailFillin = pListNode->pFillinList; + + while (pListNode != NULL) + { pFillin = pListNode->pFillinList; + pLastFillin = &(pFillin[ pListNode->NumberOfFillinsInList - 1 ]); + while (pFillin <= pLastFillin) + (pFillin++)->Row = 0; + pListNode = pListNode->Next; + } + } + +/* Unlink fill-ins by searching for elements marked with Row = 0. */ + { register ElementPtr pElement, *ppElement; + register int I, Size = Matrix->Size; + +/* Unlink fill-ins in all columns. */ + for (I = 1; I <= Size; I++) + { ppElement = &(Matrix->FirstInCol[I]); + while ((pElement = *ppElement) != NULL) + { if (pElement->Row == 0) + { *ppElement = pElement->NextInCol; /* Unlink fill-in. */ + if (Matrix->Diag[pElement->Col] == pElement) + Matrix->Diag[pElement->Col] = NULL; + } + else + ppElement = &pElement->NextInCol; /* Skip element. */ + } + } + +/* Unlink fill-ins in all rows. */ + for (I = 1; I <= Size; I++) + { ppElement = &(Matrix->FirstInRow[I]); + while ((pElement = *ppElement) != NULL) + { if (pElement->Row == 0) + *ppElement = pElement->NextInRow; /* Unlink fill-in. */ + else + ppElement = &pElement->NextInRow; /* Skip element. */ + } + } + } + return; +} +#endif + + + + + + + +#if TRANSLATE AND DELETE +/* + * DELETE A ROW AND COLUMN FROM THE MATRIX + * + * Deletes a row and a column from a matrix. + * + * Sparse will abort if an attempt is made to delete a row or column that + * doesn't exist. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to the matrix in which the row and column are to be deleted. + * Row <input> (int) + * Row to be deleted. + * Col <input> (int) + * Column to be deleted. + * + * >>> Local variables: + * ExtCol (int) + * The external column that is being deleted. + * ExtRow (int) + * The external row that is being deleted. + * pElement (ElementPtr) + * Pointer to an element in the matrix. Used when scanning rows and + * columns in order to eliminate elements from the last row or column. + * ppElement (ElementPtr *) + * Pointer to the location of an ElementPtr. This location will be + * filled with a NULL pointer if it is the new last element in its row + * or column. + * pElement (ElementPtr) + * Pointer to an element in the last row or column of the matrix. + * Size (int) + * The local version Matrix->Size, the size of the matrix. + */ + +void +spDeleteRowAndCol( eMatrix, Row, Col ) + +char *eMatrix; +int Row, Col; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement, *ppElement, pLastElement; +int Size, ExtRow, ExtCol; +ElementPtr spcFindElementInCol(); + +/* Begin `spDeleteRowAndCol'. */ + + ASSERT( IS_SPARSE(Matrix) AND Row > 0 AND Col > 0 ); + ASSERT( Row <= Matrix->ExtSize AND Col <= Matrix->ExtSize ); + + Size = Matrix->Size; + ExtRow = Row; + ExtCol = Col; + if (NOT Matrix->RowsLinked) spcLinkRows( Matrix ); + + Row = Matrix->ExtToIntRowMap[Row]; + Col = Matrix->ExtToIntColMap[Col]; + ASSERT( Row > 0 AND Col > 0 ); + +/* Move Row so that it is the last row in the matrix. */ + if (Row != Size) spcRowExchange( Matrix, Row, Size ); + +/* Move Col so that it is the last column in the matrix. */ + if (Col != Size) spcColExchange( Matrix, Col, Size ); + +/* Correct Diag pointers. */ + if (Row == Col) + SWAP( ElementPtr, Matrix->Diag[Row], Matrix->Diag[Size] ) + else + { Matrix->Diag[Row] = spcFindElementInCol( Matrix, Matrix->FirstInCol+Row, + Row, Row, NO ); + Matrix->Diag[Col] = spcFindElementInCol( Matrix, Matrix->FirstInCol+Col, + Col, Col, NO ); + } + +/* + * Delete last row and column of the matrix. + */ +/* Break the column links to every element in the last row. */ + pLastElement = Matrix->FirstInRow[ Size ]; + while (pLastElement != NULL) + { ppElement = &(Matrix->FirstInCol[ pLastElement->Col ]); + while ((pElement = *ppElement) != NULL) + { if (pElement == pLastElement) + *ppElement = NULL; /* Unlink last element in column. */ + else + ppElement = &pElement->NextInCol; /* Skip element. */ + } + pLastElement = pLastElement->NextInRow; + } + +/* Break the row links to every element in the last column. */ + pLastElement = Matrix->FirstInCol[ Size ]; + while (pLastElement != NULL) + { ppElement = &(Matrix->FirstInRow[ pLastElement->Row ]); + while ((pElement = *ppElement) != NULL) + { if (pElement == pLastElement) + *ppElement = NULL; /* Unlink last element in row. */ + else + ppElement = &pElement->NextInRow; /* Skip element. */ + } + pLastElement = pLastElement->NextInCol; + } + +/* Clean up some details. */ + Matrix->Size = Size - 1; + Matrix->Diag[Size] = NULL; + Matrix->FirstInRow[Size] = NULL; + Matrix->FirstInCol[Size] = NULL; + Matrix->CurrentSize--; + Matrix->ExtToIntRowMap[ExtRow] = -1; + Matrix->ExtToIntColMap[ExtCol] = -1; + Matrix->NeedsOrdering = YES; + + return; +} +#endif + + + + + + + + +#if PSEUDOCONDITION +/* + * CALCULATE PSEUDOCONDITION + * + * Computes the magnitude of the ratio of the largest to the smallest + * pivots. This quantity is an indicator of ill-conditioning in the + * matrix. If this ratio is large, and if the matrix is scaled such + * that uncertainties in the RHS and the matrix entries are + * equilibrated, then the matrix is ill-conditioned. However, a small + * ratio does not necessarily imply that the matrix is + * well-conditioned. This routine must only be used after a matrix has + * been factored by spOrderAndFactor() or spFactor() and before it is + * cleared by spClear() or spInitialize(). The pseudocondition is + * faster to compute than the condition number calculated by + * spCondition(), but is not as informative. + * + * >>> Returns: + * The magnitude of the ratio of the largest to smallest pivot used during + * previous factorization. If the matrix was singular, zero is returned. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to the matrix. + */ + +RealNumber +spPseudoCondition( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I; +register ArrayOfElementPtrs Diag; +RealNumber MaxPivot, MinPivot, Mag; + +/* Begin `spPseudoCondition'. */ + + ASSERT( IS_SPARSE(Matrix) AND IS_FACTORED(Matrix) ); + if (Matrix->Error == spSINGULAR OR Matrix->Error == spZERO_DIAG) + return 0.0; + + Diag = Matrix->Diag; + MaxPivot = MinPivot = ELEMENT_MAG( Diag[1] ); + for (I = 2; I <= Matrix->Size; I++) + { Mag = ELEMENT_MAG( Diag[I] ); + if (Mag > MaxPivot) + MaxPivot = Mag; + else if (Mag < MinPivot) + MinPivot = Mag; + } + ASSERT( MaxPivot > 0.0); + return MaxPivot / MinPivot; +} +#endif + + + + + + + + +#if CONDITION +/* + * ESTIMATE CONDITION NUMBER + * + * Computes an estimate of the condition number using a variation on + * the LINPACK condition number estimation algorithm. This quantity is + * an indicator of ill-conditioning in the matrix. To avoid problems + * with overflow, the reciprocal of the condition number is returned. + * If this number is small, and if the matrix is scaled such that + * uncertainties in the RHS and the matrix entries are equilibrated, + * then the matrix is ill-conditioned. If the this number is near + * one, the matrix is well conditioned. This routine must only be + * used after a matrix has been factored by spOrderAndFactor() or + * spFactor() and before it is cleared by spClear() or spInitialize(). + * + * Unlike the LINPACK condition number estimator, this routines + * returns the L infinity condition number. This is an artifact of + * Sparse placing ones on the diagonal of the upper triangular matrix + * rather than the lower. This difference should be of no importance. + * + * References: + * A.K. Cline, C.B. Moler, G.W. Stewart, J.H. Wilkinson. An estimate + * for the condition number of a matrix. SIAM Journal on Numerical + * Analysis. Vol. 16, No. 2, pages 368-375, April 1979. + * + * J.J. Dongarra, C.B. Moler, J.R. Bunch, G.W. Stewart. LINPACK + * User's Guide. SIAM, 1979. + * + * Roger G. Grimes, John G. Lewis. Condition number estimation for + * sparse matrices. SIAM Journal on Scientific and Statistical + * Computing. Vol. 2, No. 4, pages 384-388, December 1981. + * + * Dianne Prost O'Leary. Estimating matrix condition numbers. SIAM + * Journal on Scientific and Statistical Computing. Vol. 1, No. 2, + * pages 205-209, June 1980. + * + * >>> Returns: + * The reciprocal of the condition number. If the matrix was singular, + * zero is returned. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to the matrix. + * NormOfMatrix <input> (RealNumber) + * The L-infinity norm of the unfactored matrix as computed by + * spNorm(). + * pError <output> (int *) + * Used to return error code. + * + * >>> Possible errors: + * spSINGULAR + * spNO_MEMORY + */ + +RealNumber +spCondition( eMatrix, NormOfMatrix, pError ) + +char *eMatrix; +RealNumber NormOfMatrix; +int *pError; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register RealVector T, Tm; +register int I, K, Row; +ElementPtr pPivot; +int Size; +RealNumber E, Em, Wp, Wm, ASp, ASm, ASw, ASy, ASv, ASz, MaxY, ScaleFactor; +RealNumber Linpack, OLeary, InvNormOfInverse, ComplexCondition(); +#define SLACK 1e4 + +/* Begin `spCondition'. */ + + ASSERT( IS_SPARSE(Matrix) AND IS_FACTORED(Matrix) ); + *pError = Matrix->Error; + if (Matrix->Error >= spFATAL) return 0.0; + if (NormOfMatrix == 0.0) + { *pError = spSINGULAR; + return 0.0; + } + +#if spCOMPLEX + if (Matrix->Complex) + return ComplexCondition( Matrix, NormOfMatrix, pError ); +#endif + +#if REAL + Size = Matrix->Size; + T = Matrix->Intermediate; +#if spCOMPLEX + Tm = Matrix->Intermediate + Size; +#else + Tm = ALLOC( RealNumber, Size+1 ); + if (Tm == NULL) + { *pError = spNO_MEMORY; + return 0.0; + } +#endif + for (I = Size; I > 0; I--) T[I] = 0.0; + +/* + * Part 1. Ay = e. + * Solve Ay = LUy = e where e consists of +1 and -1 terms with the sign + * chosen to maximize the size of w in Lw = e. Since the terms in w can + * get very large, scaling is used to avoid overflow. + */ + +/* Forward elimination. Solves Lw = e while choosing e. */ + E = 1.0; + for (I = 1; I <= Size; I++) + { pPivot = Matrix->Diag[I]; + if (T[I] < 0.0) Em = -E; else Em = E; + Wm = (Em + T[I]) * pPivot->Real; + if (ABS(Wm) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(Wm) ); + for (K = Size; K > 0; K--) T[K] *= ScaleFactor; + E *= ScaleFactor; + Em *= ScaleFactor; + Wm = (Em + T[I]) * pPivot->Real; + } + Wp = (T[I] - Em) * pPivot->Real; + ASp = ABS(T[I] - Em); + ASm = ABS(Em + T[I]); + +/* Update T for both values of W, minus value is placed in Tm. */ + pElement = pPivot->NextInCol; + while (pElement != NULL) + { Row = pElement->Row; + Tm[Row] = T[Row] - (Wm * pElement->Real); + T[Row] -= (Wp * pElement->Real); + ASp += ABS(T[Row]); + ASm += ABS(Tm[Row]); + pElement = pElement->NextInCol; + } + +/* If minus value causes more growth, overwrite T with its values. */ + if (ASm > ASp) + { T[I] = Wm; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { T[pElement->Row] = Tm[pElement->Row]; + pElement = pElement->NextInCol; + } + } + else T[I] = Wp; + } + +/* Compute 1-norm of T, which now contains w, and scale ||T|| to 1/SLACK. */ + for (ASw = 0.0, I = Size; I > 0; I--) ASw += ABS(T[I]); + ScaleFactor = 1.0 / (SLACK * ASw); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) T[I] *= ScaleFactor; + E *= ScaleFactor; + } + +/* Backward Substitution. Solves Uy = w.*/ + for (I = Size; I >= 1; I--) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { T[I] -= pElement->Real * T[pElement->Col]; + pElement = pElement->NextInRow; + } + if (ABS(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) ); + for (K = Size; K > 0; K--) T[K] *= ScaleFactor; + E *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains y, and scale ||T|| to 1/SLACK. */ + for (ASy = 0.0, I = Size; I > 0; I--) ASy += ABS(T[I]); + ScaleFactor = 1.0 / (SLACK * ASy); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) T[I] *= ScaleFactor; + ASy = 1.0 / SLACK; + E *= ScaleFactor; + } + +/* Compute infinity-norm of T for O'Leary's estimate. */ + for (MaxY = 0.0, I = Size; I > 0; I--) + if (MaxY < ABS(T[I])) MaxY = ABS(T[I]); + +/* + * Part 2. A* z = y where the * represents the transpose. + * Recall that A = LU implies A* = U* L*. + */ + +/* Forward elimination, U* v = y. */ + for (I = 1; I <= Size; I++) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { T[pElement->Col] -= T[I] * pElement->Real; + pElement = pElement->NextInRow; + } + if (ABS(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) ); + for (K = Size; K > 0; K--) T[K] *= ScaleFactor; + ASy *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains v, and scale ||T|| to 1/SLACK. */ + for (ASv = 0.0, I = Size; I > 0; I--) ASv += ABS(T[I]); + ScaleFactor = 1.0 / (SLACK * ASv); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) T[I] *= ScaleFactor; + ASy *= ScaleFactor; + } + +/* Backward Substitution, L* z = v. */ + for (I = Size; I >= 1; I--) + { pPivot = Matrix->Diag[I]; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { T[I] -= pElement->Real * T[pElement->Row]; + pElement = pElement->NextInCol; + } + T[I] *= pPivot->Real; + if (ABS(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) ); + for (K = Size; K > 0; K--) T[K] *= ScaleFactor; + ASy *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains z. */ + for (ASz = 0.0, I = Size; I > 0; I--) ASz += ABS(T[I]); + +#if NOT spCOMPLEX + FREE( Tm ); +#endif + + Linpack = ASy / ASz; + OLeary = E / MaxY; + InvNormOfInverse = MIN( Linpack, OLeary ); + return InvNormOfInverse / NormOfMatrix; +#endif /* REAL */ +} + + + + + +#if spCOMPLEX +/* + * ESTIMATE CONDITION NUMBER + * + * Complex version of spCondition(). + * + * >>> Returns: + * The reciprocal of the condition number. + * + * >>> Arguments: + * Matrix <input> (MatrixPtr) + * Pointer to the matrix. + * NormOfMatrix <input> (RealNumber) + * The L-infinity norm of the unfactored matrix as computed by + * spNorm(). + * pError <output> (int *) + * Used to return error code. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static RealNumber +ComplexCondition( Matrix, NormOfMatrix, pError ) + +MatrixPtr Matrix; +RealNumber NormOfMatrix; +int *pError; +{ +register ElementPtr pElement; +register ComplexVector T, Tm; +register int I, K, Row; +ElementPtr pPivot; +int Size; +RealNumber E, Em, ASp, ASm, ASw, ASy, ASv, ASz, MaxY, ScaleFactor; +RealNumber Linpack, OLeary, InvNormOfInverse; +ComplexNumber Wp, Wm; + +/* Begin `ComplexCondition'. */ + + Size = Matrix->Size; + T = (ComplexVector)Matrix->Intermediate; + Tm = ALLOC( ComplexNumber, Size+1 ); + if (Tm == NULL) + { *pError = spNO_MEMORY; + return 0.0; + } + for (I = Size; I > 0; I--) T[I].Real = T[I].Imag = 0.0; + +/* + * Part 1. Ay = e. + * Solve Ay = LUy = e where e consists of +1 and -1 terms with the sign + * chosen to maximize the size of w in Lw = e. Since the terms in w can + * get very large, scaling is used to avoid overflow. + */ + +/* Forward elimination. Solves Lw = e while choosing e. */ + E = 1.0; + for (I = 1; I <= Size; I++) + { pPivot = Matrix->Diag[I]; + if (T[I].Real < 0.0) Em = -E; else Em = E; + Wm = T[I]; + Wm.Real += Em; + ASm = CMPLX_1_NORM( Wm ); + CMPLX_MULT_ASSIGN( Wm, *pPivot ); + if (CMPLX_1_NORM(Wm) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(Wm) ); + for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor ); + E *= ScaleFactor; + Em *= ScaleFactor; + ASm *= ScaleFactor; + SCLR_MULT_ASSIGN( Wm, ScaleFactor ); + } + Wp = T[I]; + Wp.Real -= Em; + ASp = CMPLX_1_NORM( Wp ); + CMPLX_MULT_ASSIGN( Wp, *pPivot ); + +/* Update T for both values of W, minus value is placed in Tm. */ + pElement = pPivot->NextInCol; + while (pElement != NULL) + { Row = pElement->Row; + /* Cmplx expr: Tm[Row] = T[Row] - (Wp * *pElement). */ + CMPLX_MULT_SUBT( Tm[Row], Wm, *pElement, T[Row] ); + /* Cmplx expr: T[Row] -= Wp * *pElement. */ + CMPLX_MULT_SUBT_ASSIGN( T[Row], Wm, *pElement ); + ASp += CMPLX_1_NORM(T[Row]); + ASm += CMPLX_1_NORM(Tm[Row]); + pElement = pElement->NextInCol; + } + +/* If minus value causes more growth, overwrite T with its values. */ + if (ASm > ASp) + { T[I] = Wm; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { T[pElement->Row] = Tm[pElement->Row]; + pElement = pElement->NextInCol; + } + } + else T[I] = Wp; + } + +/* Compute 1-norm of T, which now contains w, and scale ||T|| to 1/SLACK. */ + for (ASw = 0.0, I = Size; I > 0; I--) ASw += CMPLX_1_NORM(T[I]); + ScaleFactor = 1.0 / (SLACK * ASw); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor ); + E *= ScaleFactor; + } + +/* Backward Substitution. Solves Uy = w.*/ + for (I = Size; I >= 1; I--) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { /* Cmplx expr: T[I] -= T[pElement->Col] * *pElement. */ + CMPLX_MULT_SUBT_ASSIGN( T[I], T[pElement->Col], *pElement ); + pElement = pElement->NextInRow; + } + if (CMPLX_1_NORM(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) ); + for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor ); + E *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains y, and scale ||T|| to 1/SLACK. */ + for (ASy = 0.0, I = Size; I > 0; I--) ASy += CMPLX_1_NORM(T[I]); + ScaleFactor = 1.0 / (SLACK * ASy); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor ); + ASy = 1.0 / SLACK; + E *= ScaleFactor; + } + +/* Compute infinity-norm of T for O'Leary's estimate. */ + for (MaxY = 0.0, I = Size; I > 0; I--) + if (MaxY < CMPLX_1_NORM(T[I])) MaxY = CMPLX_1_NORM(T[I]); + +/* + * Part 2. A* z = y where the * represents the transpose. + * Recall that A = LU implies A* = U* L*. + */ + +/* Forward elimination, U* v = y. */ + for (I = 1; I <= Size; I++) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { /* Cmplx expr: T[pElement->Col] -= T[I] * *pElement. */ + CMPLX_MULT_SUBT_ASSIGN( T[pElement->Col], T[I], *pElement ); + pElement = pElement->NextInRow; + } + if (CMPLX_1_NORM(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) ); + for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor ); + ASy *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains v, and scale ||T|| to 1/SLACK. */ + for (ASv = 0.0, I = Size; I > 0; I--) ASv += CMPLX_1_NORM(T[I]); + ScaleFactor = 1.0 / (SLACK * ASv); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor ); + ASy *= ScaleFactor; + } + +/* Backward Substitution, L* z = v. */ + for (I = Size; I >= 1; I--) + { pPivot = Matrix->Diag[I]; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { /* Cmplx expr: T[I] -= T[pElement->Row] * *pElement. */ + CMPLX_MULT_SUBT_ASSIGN( T[I], T[pElement->Row], *pElement ); + pElement = pElement->NextInCol; + } + CMPLX_MULT_ASSIGN( T[I], *pPivot ); + if (CMPLX_1_NORM(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) ); + for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor ); + ASy *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains z. */ + for (ASz = 0.0, I = Size; I > 0; I--) ASz += CMPLX_1_NORM(T[I]); + + FREE( Tm ); + + Linpack = ASy / ASz; + OLeary = E / MaxY; + InvNormOfInverse = MIN( Linpack, OLeary ); + return InvNormOfInverse / NormOfMatrix; +} +#endif /* spCOMPLEX */ + + + + + +/* + * L-INFINITY MATRIX NORM + * + * Computes the L-infinity norm of an unfactored matrix. It is a fatal + * error to pass this routine a factored matrix. + * + * One difficulty is that the rows may not be linked. + * + * >>> Returns: + * The largest absolute row sum of matrix. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to the matrix. + */ + +RealNumber +spNorm( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int I; +RealNumber Max = 0.0, AbsRowSum; + +/* Begin `spNorm'. */ + ASSERT( IS_SPARSE(Matrix) AND NOT IS_FACTORED(Matrix) ); + if (NOT Matrix->RowsLinked) spcLinkRows( Matrix ); + +/* Compute row sums. */ +#if REAL + if (NOT Matrix->Complex) + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; + AbsRowSum = 0.0; + while (pElement != NULL) + { AbsRowSum += ABS( pElement->Real ); + pElement = pElement->NextInRow; + } + if (Max < AbsRowSum) Max = AbsRowSum; + } + } +#endif +#if spCOMPLEX + if (Matrix->Complex) + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; + AbsRowSum = 0.0; + while (pElement != NULL) + { AbsRowSum += CMPLX_1_NORM( *pElement ); + pElement = pElement->NextInRow; + } + if (Max < AbsRowSum) Max = AbsRowSum; + } + } +#endif + return Max; +} +#endif /* CONDITION */ + + + + + + +#if STABILITY +/* + * STABILITY OF FACTORIZATION + * + * The following routines are used to gauge the stability of a + * factorization. If the factorization is determined to be too unstable, + * then the matrix should be reordered. The routines compute quantities + * that are needed in the computation of a bound on the error attributed + * to any one element in the matrix during the factorization. In other + * words, there is a matrix E = [e_ij] of error terms such that A+E = LU. + * This routine finds a bound on |e_ij|. Erisman & Reid [1] showed that + * |e_ij| < 3.01 u rho m_ij, where u is the machine rounding unit, + * rho = max a_ij where the max is taken over every row i, column j, and + * step k, and m_ij is the number of multiplications required in the + * computation of l_ij if i > j or u_ij otherwise. Barlow [2] showed that + * rho < max_i || l_i ||_p max_j || u_j ||_q where 1/p + 1/q = 1. + * + * The first routine finds the magnitude on the largest element in the + * matrix. If the matrix has not yet been factored, the largest + * element is found by direct search. If the matrix is factored, a + * bound on the largest element in any of the reduced submatrices is + * computed using Barlow with p = oo and q = 1. The ratio of these + * two numbers is the growth, which can be used to determine if the + * pivoting order is adequate. A large growth implies that + * considerable error has been made in the factorization and that it + * is probably a good idea to reorder the matrix. If a large growth + * in encountered after using spFactor(), reconstruct the matrix and + * refactor using spOrderAndFactor(). If a large growth is + * encountered after using spOrderAndFactor(), refactor using + * spOrderAndFactor() with the pivot threshold increased, say to 0.1. + * + * Using only the size of the matrix as an upper bound on m_ij and + * Barlow's bound, the user can estimate the size of the matrix error + * terms e_ij using the bound of Erisman and Reid. The second routine + * computes a tighter bound (with more work) based on work by Gear + * [3], |e_ij| < 1.01 u rho (t c^3 + (1 + t)c^2) where t is the + * threshold and c is the maximum number of off-diagonal elements in + * any row of L. The expensive part of computing this bound is + * determining the maximum number of off-diagonals in L, which changes + * only when the order of the matrix changes. This number is computed + * and saved, and only recomputed if the matrix is reordered. + * + * [1] A. M. Erisman, J. K. Reid. Monitoring the stability of the + * triangular factorization of a sparse matrix. Numerische + * Mathematik. Vol. 22, No. 3, 1974, pp 183-186. + * + * [2] J. L. Barlow. A note on monitoring the stability of triangular + * decomposition of sparse matrices. "SIAM Journal of Scientific + * and Statistical Computing." Vol. 7, No. 1, January 1986, pp 166-168. + * + * [3] I. S. Duff, A. M. Erisman, J. K. Reid. "Direct Methods for Sparse + * Matrices." Oxford 1986. pp 99. + */ + +/* + * LARGEST ELEMENT IN MATRIX + * + * >>> Returns: + * If matrix is not factored, returns the magnitude of the largest element in + * the matrix. If the matrix is factored, a bound on the magnitude of the + * largest element in any of the reduced submatrices is returned. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to the matrix. + */ + +RealNumber +spLargestElement( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I; +RealNumber Mag, AbsColSum, Max = 0.0, MaxRow = 0.0, MaxCol = 0.0; +RealNumber Pivot; +ComplexNumber cPivot; +register ElementPtr pElement, pDiag; + +/* Begin `spLargestElement'. */ + ASSERT( IS_SPARSE(Matrix) ); + +#if REAL + if (Matrix->Factored AND NOT Matrix->Complex) + { if (Matrix->Error == spSINGULAR) return 0.0; + +/* Find the bound on the size of the largest element over all factorization. */ + for (I = 1; I <= Matrix->Size; I++) + { pDiag = Matrix->Diag[I]; + +/* Lower triangular matrix. */ + Pivot = 1.0 / pDiag->Real; + Mag = ABS( Pivot ); + if (Mag > MaxRow) MaxRow = Mag; + pElement = Matrix->FirstInRow[I]; + while (pElement != pDiag) + { Mag = ABS( pElement->Real ); + if (Mag > MaxRow) MaxRow = Mag; + pElement = pElement->NextInRow; + } + +/* Upper triangular matrix. */ + pElement = Matrix->FirstInCol[I]; + AbsColSum = 1.0; /* Diagonal of U is unity. */ + while (pElement != pDiag) + { AbsColSum += ABS( pElement->Real ); + pElement = pElement->NextInCol; + } + if (AbsColSum > MaxCol) MaxCol = AbsColSum; + } + } + else if (NOT Matrix->Complex) + { for (I = 1; I <= Matrix->Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { Mag = ABS( pElement->Real ); + if (Mag > Max) Max = Mag; + pElement = pElement->NextInCol; + } + } + return Max; + } +#endif +#if spCOMPLEX + if (Matrix->Factored AND Matrix->Complex) + { if (Matrix->Error == spSINGULAR) return 0.0; + +/* Find the bound on the size of the largest element over all factorization. */ + for (I = 1; I <= Matrix->Size; I++) + { pDiag = Matrix->Diag[I]; + +/* Lower triangular matrix. */ + CMPLX_RECIPROCAL( cPivot, *pDiag ); + Mag = CMPLX_1_NORM( cPivot ); + if (Mag > MaxRow) MaxRow = Mag; + pElement = Matrix->FirstInRow[I]; + while (pElement != pDiag) + { Mag = CMPLX_1_NORM( *pElement ); + if (Mag > MaxRow) MaxRow = Mag; + pElement = pElement->NextInRow; + } + +/* Upper triangular matrix. */ + pElement = Matrix->FirstInCol[I]; + AbsColSum = 1.0; /* Diagonal of U is unity. */ + while (pElement != pDiag) + { AbsColSum += CMPLX_1_NORM( *pElement ); + pElement = pElement->NextInCol; + } + if (AbsColSum > MaxCol) MaxCol = AbsColSum; + } + } + else if (Matrix->Complex) + { for (I = 1; I <= Matrix->Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { Mag = CMPLX_1_NORM( *pElement ); + if (Mag > Max) Max = Mag; + pElement = pElement->NextInCol; + } + } + return Max; + } +#endif + return MaxRow * MaxCol; +} + + + + +/* + * MATRIX ROUNDOFF ERROR + * + * >>> Returns: + * Returns a bound on the magnitude of the largest element in E = A - LU. + * + * >>> Arguments: + * eMatrix <input> (char *) + * Pointer to the matrix. + * Rho <input> (RealNumber) + * The bound on the magnitude of the largest element in any of the + * reduced submatrices. This is the number computed by the function + * spLargestElement() when given a factored matrix. If this number is + * negative, the bound will be computed automatically. + */ + +RealNumber +spRoundoff( eMatrix, Rho ) + +char *eMatrix; +RealNumber Rho; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int Count, I, MaxCount = 0; +RealNumber Reid, Gear; + +/* Begin `spRoundoff'. */ + ASSERT( IS_SPARSE(Matrix) AND IS_FACTORED(Matrix) ); + +/* Compute Barlow's bound if it is not given. */ + if (Rho < 0.0) Rho = spLargestElement( eMatrix ); + +/* Find the maximum number of off-diagonals in L if not previously computed. */ + if (Matrix->MaxRowCountInLowerTri < 0) + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; + Count = 0; + while (pElement->Col < I) + { Count++; + pElement = pElement->NextInRow; + } + if (Count > MaxCount) MaxCount = Count; + } + Matrix->MaxRowCountInLowerTri = MaxCount; + } + else MaxCount = Matrix->MaxRowCountInLowerTri; + +/* Compute error bound. */ + Gear = 1.01*((MaxCount + 1) * Matrix->RelThreshold + 1.0) * SQR(MaxCount); + Reid = 3.01 * Matrix->Size; + + if (Gear < Reid) + return (MACHINE_RESOLUTION * Rho * Gear); + else + return (MACHINE_RESOLUTION * Rho * Reid); +} +#endif diff --git a/sis/list/Makefile.am b/sis/list/Makefile.am new file mode 100644 index 0000000..5e3a48e --- /dev/null +++ b/sis/list/Makefile.am @@ -0,0 +1,7 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = liblist.a +liblist_a_SOURCES = list.c +pkginclude_HEADERS = list.h +dist_doc_DATA = list.doc diff --git a/sis/list/Makefile.in b/sis/list/Makefile.in new file mode 100644 index 0000000..4b62f19 --- /dev/null +++ b/sis/list/Makefile.in @@ -0,0 +1,418 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(liblist_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/list +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +liblist_a_AR = $(AR) $(ARFLAGS) +liblist_a_LIBADD = +am_liblist_a_OBJECTS = list.$(OBJEXT) +liblist_a_OBJECTS = $(am_liblist_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(liblist_a_SOURCES) +DIST_SOURCES = $(liblist_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = liblist.a +liblist_a_SOURCES = list.c +pkginclude_HEADERS = list.h +dist_doc_DATA = list.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/list/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/list/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +liblist.a: $(liblist_a_OBJECTS) $(liblist_a_DEPENDENCIES) + -rm -f liblist.a + $(liblist_a_AR) liblist.a $(liblist_a_OBJECTS) $(liblist_a_LIBADD) + $(RANLIB) liblist.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/list/list.c b/sis/list/list.c new file mode 100644 index 0000000..aa54850 --- /dev/null +++ b/sis/list/list.c @@ -0,0 +1,898 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/list/list.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +/* + * List Management Package + * + * David Harrison + * University of California, Berkeley, 1985 + * + * This package implements a simple generic linked list data type. It + * uses a doubly linked list structure and provides some standard operations + * for storing and retrieving data from the list. + */ + +#include "util.h" +#include "list.h" /* Self declaration */ + +#define alloc(type) (type *) malloc(sizeof(type)) + +/* + * The list identifier is in reality a pointer to the following list + * descriptor structure. Lists are doubly linked with both top and + * bottom pointers stored in the list descriptor. The length + * of the list is also stored in the descriptor. + */ + +typedef struct list_elem { /* One list element */ + struct list_desc *mainList; /* List descriptor */ + struct list_elem *prevPtr; /* Previous element */ + struct list_elem *nextPtr; /* Next list element */ + lsGeneric userData; /* User pointer */ +} lsElem; + +typedef struct list_desc { /* List descriptor record */ + lsElem *topPtr, *botPtr; /* Pointer to top and bottom of list */ + int length; /* Length of list */ +} lsDesc; + + +/* + * Generators are in reality pointers to the generation descriptor + * defined below. A generator has a current spot which is *between* + * two items. Thus, a generator consists of two pointers: record + * before spot and record after spot. A pointer to the main list + * is included so the top and bottom pointers of the list can be + * modified if needed. + */ + +typedef struct gen_desc { /* Generator Descriptor */ + lsDesc *mainList; /* Pointer to list descriptor */ + lsElem *beforeSpot; /* Item before the current spot */ + lsElem *afterSpot; /* Item after the current spot */ +} lsGenInternal; + +/* + * Handles are in reality pointers to lsElem records. They are + * cheap to generate and need not be disposed. + */ + + + +/* + * List Creation and Deletion + */ + +lsList lsCreate() +/* + * Creates a new linked list and returns its handle. The handle is used + * by all other list manipulation routines and should not be discarded. + */ +{ + lsDesc *newList; + + newList = alloc(lsDesc); + newList->topPtr = newList->botPtr = NIL(lsElem); + newList->length = 0; + return( (lsList) newList ); +} + +lsStatus lsDestroy(list, delFunc) +lsList list; /* List to destroy */ +void (*delFunc)(); /* Routine to release user data */ +/* + * Frees all resources associated with the specified list. It frees memory + * associated with all elements of the list and then deletes the list. + * User data is released by calling 'delFunc' with the pointer as the + * argument. Accessing a list after its destruction is a no-no. + */ +{ + lsDesc *realList; + lsElem *index, *temp; + + realList = (lsDesc *) list; + /* Get rid of elements */ + index = realList->topPtr; + while (index != NIL(lsElem)) { + temp = index; index = index->nextPtr; + if (delFunc) + (*delFunc)(temp->userData); + free((lsGeneric) temp); + } + /* Get rid of descriptor */ + free((lsGeneric) realList); + return(LS_OK); +} + + +/* + * Copying lists + */ + +static lsGeneric lsIdentity(data) +lsGeneric data; +/* Identity copy function */ +{ + return data; +} + +lsList lsCopy(list, copyFunc) +lsList list; /* List to be copied */ +lsGeneric (*copyFunc)(); /* Routine to copy user data */ +/* + * Returns a copy of list `list'. If `copyFunc' is non-zero, + * it will be called for each item in `list' and the pointer it + * returns will be used in place of the original user data for the + * item in the newly created list. The form of `copyFunc' should be: + * lsGeneric copyFunc(data) + * lsGeneric data; + * This is normally used to make copies of the user data in the new list. + * If no `copyFunc' is provided, an identity function is used. + */ +{ + lsList newList; + lsGen gen; + lsGeneric data; + + if (!copyFunc) copyFunc = lsIdentity; + newList = lsCreate(); + gen = lsStart(list); + while (lsNext(gen, &data, LS_NH) == LS_OK) { + (void) lsNewEnd(newList, (*copyFunc)(data), LS_NH); + } + lsFinish(gen); + return newList; +} + + +/* + * Adding New Elements to the Beginning and End of a List + */ + +lsStatus lsNewBegin(list, data, itemHandle) +lsList list; /* List to add element to */ +lsGeneric data; /* Arbitrary pointer to data */ +lsHandle *itemHandle; /* Handle to data (returned) */ +/* + * Adds a new item to the start of a previously created linked list. + * If 'itemHandle' is non-zero, it will be filled with a handle + * which can be used to generate a generator positioned at the + * item without generating through the list. + */ +{ + lsDesc *realList = (lsDesc *) list; + lsElem *newElem; + + newElem = alloc(lsElem); + newElem->userData = data; + newElem->nextPtr = realList->topPtr; + newElem->prevPtr = NIL(lsElem); + newElem->mainList = realList; + if (realList->topPtr == NIL(lsElem)) { + /* The new item is both the top and bottom element */ + realList->botPtr = newElem; + } else { + /* There was a top element - make its prev correct */ + realList->topPtr->prevPtr = newElem; + } + realList->topPtr = newElem; + realList->length += 1; + if (itemHandle) *itemHandle = (lsHandle) newElem; + return(LS_OK); +} + +lsStatus lsNewEnd(list, data, itemHandle) +lsList list; /* List to append element to */ +lsGeneric data; /* Arbitrary pointer to data */ +lsHandle *itemHandle; /* Handle to data (returned) */ +/* + * Adds a new item to the end of a previously created linked list. + * This routine appends the item in constant time and + * can be used freely without guilt. + */ +{ + lsDesc *realList = (lsDesc *) list; + lsElem *newElem; + + newElem = alloc(lsElem); + newElem->userData = data; + newElem->prevPtr = realList->botPtr; + newElem->nextPtr = NIL(lsElem); + newElem->mainList = realList; + if (realList->topPtr == NIL(lsElem)) + realList->topPtr = newElem; + if (realList->botPtr != NIL(lsElem)) + realList->botPtr->nextPtr = newElem; + realList->botPtr = newElem; + realList->length += 1; + if (itemHandle) *itemHandle = (lsHandle) newElem; + return(LS_OK); +} + +/* + * Retrieving the first and last items of a list + */ + +lsStatus lsFirstItem(list, data, itemHandle) +lsList list; /* List to get item from */ +lsGeneric *data; /* User data (returned) */ +lsHandle *itemHandle; /* Handle to data (returned) */ +/* + * Returns the first item in the list. If the list is empty, + * it returns LS_NOMORE. Otherwise, it returns LS_OK. + * If 'itemHandle' is non-zero, it will be filled with a + * handle which may be used to generate a generator. + */ +{ + lsDesc *realList = (lsDesc *) list; + + if (realList->topPtr != NIL(lsElem)) { + *data = realList->topPtr->userData; + if (itemHandle) *itemHandle = (lsHandle) (realList->topPtr); + return(LS_OK); + } else { + *data = (lsGeneric) 0; + if (itemHandle) *itemHandle = (lsHandle) 0; + return(LS_NOMORE); + } +} + +lsStatus lsLastItem(list, data, itemHandle) +lsList list; /* List to get item from */ +lsGeneric *data; /* User data (returned) */ +lsHandle *itemHandle; /* Handle to data (returned) */ +/* + * Returns the last item of a list. If the list is empty, + * the routine returns LS_NOMORE. Otherwise, 'data' will + * be set to the last item and the routine will return LS_OK. + * If 'itemHandle' is non-zero, it will be filled with a + * handle which can be used to generate a generator postioned + * at this item. + */ +{ + lsDesc *realList = (lsDesc *) list; + + if (realList->botPtr != NIL(lsElem)) { + *data = realList->botPtr->userData; + if (itemHandle) *itemHandle = (lsHandle) (realList->botPtr); + return(LS_OK); + } else { + *data = (lsGeneric) 0; + if (itemHandle) *itemHandle = (lsHandle) 0; + return(LS_NOMORE); + } +} + + + +/* Length of a list */ + +int lsLength(list) +lsList list; /* List to get the length of */ +/* + * Returns the length of the list. The list must have been + * already created using lsCreate. + */ +{ + lsDesc *realList = (lsDesc *) list; + + return(realList->length); +} + + + +/* + * Deleting first and last items of a list + */ + +lsStatus lsDelBegin(list, data) +lsList list; /* List to delete item from */ +lsGeneric *data; /* First item (returned) */ +/* + * This routine deletes the first item of a list. The user + * data associated with the item is returned so the caller + * may dispose of it. Returns LS_NOMORE if there is no + * item to delete. + */ +{ + lsDesc *realList = (lsDesc *) list; + lsElem *temp; + + if (realList->topPtr == NIL(lsElem)) { + /* Nothing to delete */ + *data = (lsGeneric) 0; + return LS_NOMORE; + } else { + *data = realList->topPtr->userData; + temp = realList->topPtr; + realList->topPtr = realList->topPtr->nextPtr; + if (temp->nextPtr != NIL(lsElem)) { + /* There is something after the first item */ + temp->nextPtr->prevPtr = NIL(lsElem); + } else { + /* Nothing after it - bottom becomes null as well */ + realList->botPtr = NIL(lsElem); + } + free((lsGeneric) temp); + realList->length -= 1; + } + return LS_OK; +} + + +lsStatus lsDelEnd(list, data) +lsList list; /* List to delete item from */ +lsGeneric *data; /* Last item (returned) */ +/* + * This routine deletes the last item of a list. The user + * data associated with the item is returned so the caller + * may dispose of it. Returns LS_NOMORE if there is nothing + * to delete. + */ +{ + lsDesc *realList = (lsDesc *) list; + lsElem *temp; + + if (realList->botPtr == NIL(lsElem)) { + /* Nothing to delete */ + *data = (lsGeneric) 0; + return LS_NOMORE; + } else { + *data = realList->botPtr->userData; + temp = realList->botPtr; + realList->botPtr = realList->botPtr->prevPtr; + if (temp->prevPtr != NIL(lsElem)) { + /* There is something before the last item */ + temp->prevPtr->nextPtr = NIL(lsElem); + } else { + /* Nothing before it - top becomes null as well */ + realList->topPtr = NIL(lsElem); + } + free((lsGeneric) temp); + realList->length -= 1; + } + return LS_OK; +} + + +/* + * List Generation Routines + * + * nowPtr is the element just before the next one to be generated + */ + +lsGen lsStart(list) +lsList list; /* List to generate items from */ +/* + * This routine defines a generator which is used to step through + * each item of the list. It returns a generator handle which should + * be used when calling lsNext, lsPrev, lsInBefore, lsInAfter, lsDelete, + * or lsFinish. + */ +{ + lsDesc *realList = (lsDesc *) list; + lsGenInternal *newGen; + + newGen = alloc(lsGenInternal); + newGen->mainList = realList; + newGen->beforeSpot = NIL(lsElem); + newGen->afterSpot = realList->topPtr; + return ( (lsGen) newGen ); +} + +lsGen lsEnd(list) +lsList list; /* List to generate items from */ +/* + * This routine defines a generator which is used to step through + * each item of a list. The generator is initialized to the end + * of the list. + */ +{ + lsDesc *realList = (lsDesc *) list; + lsGenInternal *newGen; + + newGen = alloc(lsGenInternal); + newGen->mainList = realList; + newGen->beforeSpot = realList->botPtr; + newGen->afterSpot = NIL(lsElem); + return (lsGen) newGen; +} + +lsGen lsGenHandle(itemHandle, data, option) +lsHandle itemHandle; /* Handle of an item */ +lsGeneric *data; /* Data associated with item */ +int option; /* LS_BEFORE or LS_AFTER */ +/* + * This routine produces a generator given a handle. Handles + * are produced whenever an item is added to a list. The generator + * produced by this routine may be used when calling any of + * the standard generation routines. NOTE: the generator + * should be freed using lsFinish. The 'option' parameter + * determines whether the generator spot is before or after + * the handle item. + */ +{ + lsElem *realItem = (lsElem *) itemHandle; + lsGenInternal *newGen; + + newGen = alloc(lsGenInternal); + newGen->mainList = realItem->mainList; + *data = realItem->userData; + if (option & LS_BEFORE) { + newGen->beforeSpot = realItem->prevPtr; + newGen->afterSpot = realItem; + } else if (option & LS_AFTER) { + newGen->beforeSpot = realItem; + newGen->afterSpot = realItem->nextPtr; + } else { + free((lsGeneric) newGen); + newGen = (lsGenInternal *) 0; + } + return ( (lsGen) newGen ); +} + + +lsStatus lsNext(generator, data, itemHandle) +lsGen generator; /* Generator handle */ +lsGeneric *data; /* User data (return) */ +lsHandle *itemHandle; /* Handle to item (return) */ +/* + * Generates the item after the item previously generated by lsNext + * or lsPrev. It returns a pointer to the user data structure in 'data'. + * 'itemHandle' may be used to get a generation handle without + * generating through the list to find the item. If there are no more + * elements to generate, the routine returns LS_NOMORE (normally it + * returns LS_OK). lsNext DOES NOT automatically clean up after all + * elements have been generated. lsFinish must be called explicitly to do this. + */ +{ + register lsGenInternal *realGen = (lsGenInternal *) generator; + + if (realGen->afterSpot == NIL(lsElem)) { + /* No more stuff to generate */ + *data = (lsGeneric) 0; + if (itemHandle) *itemHandle = (lsHandle) 0; + return LS_NOMORE; + } else { + *data = realGen->afterSpot->userData; + if (itemHandle) *itemHandle = (lsHandle) (realGen->afterSpot); + /* Move the pointers down one */ + realGen->beforeSpot = realGen->afterSpot; + realGen->afterSpot = realGen->afterSpot->nextPtr; + return LS_OK; + } +} + + +lsStatus lsPrev(generator, data, itemHandle) +lsGen generator; /* Generator handle */ +lsGeneric *data; /* User data (return) */ +lsHandle *itemHandle; /* Handle to item (return) */ +/* + * Generates the item before the item previously generated by lsNext + * or lsPrev. It returns a pointer to the user data structure in 'data'. + * 'itemHandle' may be used to get a generation handle without + * generating through the list to find the item. If there are no more + * elements to generate, the routine returns LS_NOMORE (normally it + * returns LS_OK). lsPrev DOES NOT automatically clean up after all + * elements have been generated. lsFinish must be called explicitly to do this. + */ +{ + register lsGenInternal *realGen = (lsGenInternal *) generator; + + if (realGen->beforeSpot == NIL(lsElem)) { + /* No more stuff to generate */ + *data = (lsGeneric) 0; + if (itemHandle) *itemHandle = (lsHandle) 0; + return LS_NOMORE; + } else { + *data = realGen->beforeSpot->userData; + if (itemHandle) *itemHandle = (lsHandle) (realGen->beforeSpot); + /* Move the pointers down one */ + realGen->afterSpot = realGen->beforeSpot; + realGen->beforeSpot = realGen->beforeSpot->prevPtr; + return LS_OK; + } + +} + +lsStatus lsInBefore(generator, data, itemHandle) +lsGen generator; /* Generator handle */ +lsGeneric data; /* Arbitrary pointer to data */ +lsHandle *itemHandle; /* Handle to item (return) */ +/* + * Inserts an element BEFORE the current spot. The item generated + * by lsNext will be unchanged; the inserted item will be generated + * by lsPrev. This modifies the list. 'itemHandle' may be used at + * a later time to produce a generation handle without generating + * through the list. + */ +{ + lsGenInternal *realGen = (lsGenInternal *) generator; + lsElem *newElem; + + if (realGen->beforeSpot == NIL(lsElem)) { + /* Item added to the beginning of the list */ + (void) lsNewBegin((lsList) realGen->mainList, data, itemHandle); + realGen->beforeSpot = realGen->mainList->topPtr; + return LS_OK; + } else if (realGen->afterSpot == NIL(lsElem)) { + /* Item added to the end of the list */ + (void) lsNewEnd((lsList) realGen->mainList, data, itemHandle); + realGen->afterSpot = realGen->mainList->botPtr; + return LS_OK; + } else { + /* Item added in the middle of the list */ + newElem = alloc(lsElem); + newElem->mainList = realGen->mainList; + newElem->prevPtr = realGen->beforeSpot; + newElem->nextPtr = realGen->afterSpot; + newElem->userData = data; + realGen->beforeSpot->nextPtr = newElem; + realGen->afterSpot->prevPtr = newElem; + realGen->beforeSpot = newElem; + realGen->mainList->length += 1; + if (itemHandle) *itemHandle = (lsHandle) newElem; + return LS_OK; + } +} + +lsStatus lsInAfter(generator, data, itemHandle) +lsGen generator; /* Generator handle */ +lsGeneric data; /* Arbitrary pointer to data */ +lsHandle *itemHandle; /* Handle to item (return) */ +/* + * Inserts an element AFTER the current spot. The next item generated + * by lsNext will be the new element. The next item generated by + * lsPrev is unchanged. This modifies the list. 'itemHandle' may + * be used at a later time to generate a generation handle without + * searching through the list to find the item. + */ +{ + lsGenInternal *realGen = (lsGenInternal *) generator; + lsElem *newElem; + + if (realGen->beforeSpot == NIL(lsElem)) { + /* Item added to the beginning of the list */ + (void) lsNewBegin((lsList) realGen->mainList, data, itemHandle); + realGen->beforeSpot = realGen->mainList->topPtr; + return LS_OK; + } else if (realGen->afterSpot == NIL(lsElem)) { + /* Item added to the end of the list */ + (void) lsNewEnd((lsList) realGen->mainList, data, itemHandle); + realGen->afterSpot = realGen->mainList->botPtr; + return LS_OK; + } else { + /* Item added in the middle of the list */ + newElem = alloc(lsElem); + newElem->mainList = realGen->mainList; + newElem->prevPtr = realGen->beforeSpot; + newElem->nextPtr = realGen->afterSpot; + newElem->userData = data; + realGen->beforeSpot->nextPtr = newElem; + realGen->afterSpot->prevPtr = newElem; + realGen->afterSpot = newElem; + realGen->mainList->length += 1; + if (itemHandle) *itemHandle = (lsHandle) newElem; + return LS_OK; + } +} + + +lsStatus lsDelBefore(generator, data) +lsGen generator; /* Generator handle */ +lsGeneric *data; /* Deleted item (returned) */ +/* + * Removes the item before the current spot. The next call to lsPrev + * will return the item before the deleted item. The next call to lsNext + * will be uneffected. This modifies the list. The routine returns + * LS_BADSTATE if the user tries to call the routine and there is + * no item before the current spot. This routine returns the userData + * of the deleted item so it may be freed (if necessary). + */ +{ + lsGenInternal *realGen = (lsGenInternal *) generator; + lsElem *doomedItem; + + if (realGen->beforeSpot == NIL(lsElem)) { + /* No item to delete */ + *data = (lsGeneric) 0; + return LS_BADSTATE; + } else if (realGen->beforeSpot == realGen->mainList->topPtr) { + /* Delete the first item of the list */ + realGen->beforeSpot = realGen->beforeSpot->prevPtr; + return lsDelBegin((lsList) realGen->mainList, data); + } else if (realGen->beforeSpot == realGen->mainList->botPtr) { + /* Delete the last item of the list */ + realGen->beforeSpot = realGen->beforeSpot->prevPtr; + return lsDelEnd((lsList) realGen->mainList, data); + } else { + /* Normal mid list deletion */ + doomedItem = realGen->beforeSpot; + doomedItem->prevPtr->nextPtr = doomedItem->nextPtr; + doomedItem->nextPtr->prevPtr = doomedItem->prevPtr; + realGen->beforeSpot = doomedItem->prevPtr; + realGen->mainList->length -= 1; + *data = doomedItem->userData; + free((lsGeneric) doomedItem); + return LS_OK; + } +} + + +lsStatus lsDelAfter(generator, data) +lsGen generator; /* Generator handle */ +lsGeneric *data; /* Deleted item (returned) */ +/* + * Removes the item after the current spot. The next call to lsNext + * will return the item after the deleted item. The next call to lsPrev + * will be uneffected. This modifies the list. The routine returns + * LS_BADSTATE if the user tries to call the routine and there is + * no item after the current spot. This routine returns the userData + * of the deleted item so it may be freed (if necessary). + */ +{ + lsGenInternal *realGen = (lsGenInternal *) generator; + lsElem *doomedItem; + + if (realGen->afterSpot == NIL(lsElem)) { + /* No item to delete */ + *data = (lsGeneric) 0; + return LS_BADSTATE; + } else if (realGen->afterSpot == realGen->mainList->topPtr) { + /* Delete the first item of the list */ + realGen->afterSpot = realGen->afterSpot->nextPtr; + return lsDelBegin((lsList) realGen->mainList, data); + } else if (realGen->afterSpot == realGen->mainList->botPtr) { + /* Delete the last item of the list */ + realGen->afterSpot = realGen->afterSpot->nextPtr; + return lsDelEnd((lsList) realGen->mainList, data); + } else { + /* Normal mid list deletion */ + doomedItem = realGen->afterSpot; + doomedItem->prevPtr->nextPtr = doomedItem->nextPtr; + doomedItem->nextPtr->prevPtr = doomedItem->prevPtr; + realGen->afterSpot = doomedItem->nextPtr; + realGen->mainList->length -= 1; + *data = doomedItem->userData; + free((lsGeneric) doomedItem); + return LS_OK; + } +} + + + +lsStatus lsFinish(generator) +lsGen generator; /* Generator handle */ +/* + * Marks the completion of a generation of list items. This routine should + * be called after calls to lsNext to free resources used by the + * generator. This rule applies even if all items of a list are + * generated by lsNext. + */ +{ + lsGenInternal *realGen = (lsGenInternal *) generator; + + free((lsGeneric) realGen); + return(LS_OK); +} + + + +/* + * Functional list generation + * + * An alternate form of generating through items of a list is provided. + * The routines below generatae through all items of a list in a given + * direction and call a user provided function for each one. + */ + +static lsStatus lsGenForm(); + +lsStatus lsForeach(list, userFunc, arg) +lsList list; /* List to generate through */ +lsStatus (*userFunc)(); /* User provided function */ +lsGeneric arg; /* User provided data */ +/* + * This routine generates all items in `list' from the first item + * to the last calling `userFunc' for each item. The function + * should have the following form: + * lsStatus userFunc(data, arg) + * lsGeneric data; + * lsGeneric arg; + * `data' will be the user data associated with the item generated. + * `arg' will be the same pointer provided to lsForeach. The + * routine should return LS_OK to continue the generation, LS_STOP + * to stop generating items, and LS_DELETE to delete the item + * from the list. If the generation was stopped prematurely, + * the routine will return LS_STOP. If the user provided function + * does not return an appropriate value, the routine will return + * LS_BADPARAM. + */ +{ + return lsGenForm(userFunc, arg, lsStart(list), lsNext, lsDelBefore); +} + + +lsStatus lsBackeach(list, userFunc, arg) +lsList list; /* List to generate through */ +lsStatus (*userFunc)(); /* User provided function */ +lsGeneric arg; /* User provided data */ +/* + * This routine is just like lsForeach except it generates + * all items in `list' from the last item to the first. + */ +{ + return lsGenForm(userFunc, arg, lsEnd(list), lsPrev, lsDelAfter); +} + + + +static lsStatus lsGenForm(userFunc, arg, gen, gen_func, del_func) +lsStatus (*userFunc)(); /* User provided function */ +lsGeneric arg; /* Data to pass to function */ +lsGen gen; /* Generator to use */ +lsStatus (*gen_func)(); /* Generator function to use */ +lsStatus (*del_func)(); /* Deletion function to use */ +/* + * This is the function used to implement the two functional + * generation interfaces to lists. + */ +{ + lsGeneric data; + + while ((*gen_func)(gen, &data, LS_NH) == LS_OK) { + switch ((*userFunc)(data, arg)) { + case LS_OK: + /* Nothing */ + break; + case LS_STOP: + (void) lsFinish(gen); + return LS_STOP; + case LS_DELETE: + (*del_func)(gen, &data); + break; + default: + return LS_BADPARAM; + } + } + (void) lsFinish(gen); + return LS_OK; +} + + +lsList lsQueryHandle(itemHandle) +lsHandle itemHandle; /* Handle of an item */ +/* + * This routine returns the associated list of the specified + * handle. Returns 0 if there were problems. + */ +{ + lsElem *realHandle = (lsElem *) itemHandle; + + if (realHandle) { + return (lsList) realHandle->mainList; + } else { + return (lsList) 0; + } +} + +lsGeneric lsFetchHandle(itemHandle) +lsHandle itemHandle; +/* + * This routine returns the user data of the item associated with + * `itemHandle'. + */ +{ + return ((lsElem *) itemHandle)->userData; +} + +lsStatus lsRemoveItem(itemHandle, userData) +lsHandle itemHandle; /* Handle of an item */ +lsGeneric *userData; /* Returned data */ +/* + * This routine removes the item associated with `handle' from + * its list and returns the user data associated with the item + * for reclaimation purposes. Note this modifies the list + * that originally contained `item'. + */ +{ + lsElem *realItem = (lsElem *) itemHandle; + lsGenInternal gen; + + gen.mainList = realItem->mainList; + gen.beforeSpot = realItem->prevPtr; + gen.afterSpot = realItem; + return lsDelAfter((lsGen) &gen, userData); +} + + +/* List sorting support */ +#define TYPE lsElem +#define SORT lsSortItems +#define NEXT nextPtr +#define FIELD userData +#include "lsort.h" /* Merge sort by R. Rudell */ + +lsStatus lsSort(list, compare) +lsList list; /* List to sort */ +int (*compare)(); /* Comparison function */ +/* + * This routine sorts `list' using `compare' as the comparison + * function between items in the list. `compare' has the following form: + * int compare(item1, item2) + * lsGeneric item1, item2; + * The routine should return -1 if item1 is less than item2, 0 if + * they are equal, and 1 if item1 is greater than item2. + * The routine uses a generic merge sort written by Rick Rudell. + */ +{ + lsDesc *realList = (lsDesc *) list; + lsElem *idx, *lastElem; + + realList->topPtr = lsSortItems(realList->topPtr, compare, + realList->length); + + /* Forward pointers are correct - fix backward pointers */ + lastElem = (lsElem *) 0; + for (idx = realList->topPtr; idx != (lsElem *) 0; idx = idx->nextPtr) { + idx->prevPtr = lastElem; + lastElem = idx; + } + /* lastElem is last item in list */ + realList->botPtr = lastElem; + return LS_OK; +} + + + +lsStatus lsUniq(list, compare, delFunc) +lsList list; /* List to remove duplicates from */ +int (*compare)(); /* Item comparison function */ +void (*delFunc)(); /* Function to release user data */ +/* + * This routine takes a sorted list and removes all duplicates + * from it. `compare' has the following form: + * int compare(item1, item2) + * lsGeneric item1, item2; + * The routine should return -1 if item1 is less than item2, 0 if + * they are equal, and 1 if item1 is greater than item2. `delFunc' + * will be called with a pointer to a user data item for each + * duplicate destroyed. `delFunc' can be zero if no clean up + * is required. + */ +{ + lsGeneric this_item, last_item; + lsGenInternal realGen; + lsDesc *realList = (lsDesc *) list; + + if (realList->length > 1) { + last_item = realList->topPtr->userData; + + /* Inline creation of generator */ + realGen.mainList = realList; + realGen.beforeSpot = realList->topPtr; + realGen.afterSpot = realList->topPtr->nextPtr; + + while (realGen.afterSpot) { + this_item = realGen.afterSpot->userData; + if ((*compare)(this_item, last_item) == 0) { + /* Duplicate -- eliminate */ + (void) lsDelAfter((lsGen) &realGen, &this_item); + if (delFunc) (*delFunc)(this_item); + } else { + /* Move generator forward */ + realGen.beforeSpot = realGen.afterSpot; + realGen.afterSpot = realGen.afterSpot->nextPtr; + last_item = this_item; + } + } + } + return LS_OK; +} diff --git a/sis/list/list.doc b/sis/list/list.doc new file mode 100644 index 0000000..0adf899 --- /dev/null +++ b/sis/list/list.doc @@ -0,0 +1,376 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/list/list.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ + +List Management Package + +David Harrison +University of California, Berkeley, 1985 + +This package implements a simple generic linked list data type. It +uses a doubly linked list structure and provides some standard operations +for storing and retrieving data from the list. + +Programs using this package should include the file list.h found +in ~cad/include. The linkage line for a user program called `myprog' +would look like: + + cc -g -o myprog myprog.o /cad/lib/liblist.a + +Status Codes +------------ + +Most of the routines described below return lsStatus (an integer +return code). The possible return codes are described below: + +LS_OK Routine completed successfully + +LS_BADSTATE Generator is in a bad state +LS_BADPARAM Bad parameter value to function +LS_NOMORE No more items to generate + +Note that LS_OK is zero. Thus, routine return values should be +explicitly compared against LS_OK for success. + +Item Handles +------------ + +Routines which return items of a list optionally return a `handle'. +This handle can be stored in user data structures and later used to +quickly access the item without generating through the list. If you +do not wish to use handles, you can pass the zero handle `(lsHandle *) 0' +to the routine. For brevity, the LS_NH macro may be used to specify +no handle to routines which return a handle. + +List Creation, Deletion, and Copying +------------------------------------ + +lsList lsCreate() + + Creates a new linked list and returns its handle. The handle + is used by all other list manipulation routines and should not + be discarded. + +lsStatus lsDestroy(list, delFunc) +lsList list; /* List to destroy */ +void (*delFunc)(); /* Routine to release user data */ + + Frees all resources associated with the specified list. It + frees memory associated with all elements of the list and then + deletes the list. User data is released by calling `delFunc' + with the pointer as the argument. If no `delFunc' is provided + (i.e. `delFunc' is zero), the items in the list are not + freed. Accessing a list after its destruction is a no-no. + +lsList lsCopy(list, copyFunc) +lsList list; /* List to copy */ +lsGeneric (*copyFunc)(); /* Routine to copy user data */ + + Returns a copy of list `list'. If `copyFunc' is non-zero, + it will be called for each item in `list' and the pointer it + returns will be used in place of the original user data for the + item in the newly created list. The form of `copyFunc' should be: + lsGeneric copyFunc(data) + lsGeneric data; + This is normally used to make copies of the user data in the + new list. If no `copyFunc' is provided, the routine will use + an identity function. + +Adding New Elements to the Beginning and End of a List +------------------------------------------------------ + +lsStatus lsNewBegin(list, data, itemHandle) +lsList list; /* List to add element to */ +lsGeneric data; /* Arbitrary pointer to data */ +lsHandle *itemHandle; /* Handle to data (returned) */ + + Adds a new item to the start of a previously created linked + list. If 'itemHandle' is non-zero, it will be filled with a + handle which can be used to generate a generator positioned + at the item without generating through the list. + +lsStatus lsNewEnd(list, data, itemHandle) +lsList list; /* List to append element to */ +lsGeneric data; /* Arbitrary pointer to data */ +lsHandle *itemHandle; /* Handle to data (returned) */ + + Adds a new item to the end of a previously created linked + list. This routine appends the item in constant time and + can be used freely without guilt. + +Retrieving the first and last items of a list +--------------------------------------------- + +lsStatus lsFirstItem(list, data, itemHandle) +lsList list; /* List to get item from */ +lsGeneric *data; /* User data (returned) */ +lsHandle *itemHandle; /* Handle to data (returned) */ + + Returns the first item in the list. If the list is empty, + it returns LS_NOMORE. Otherwise, it returns LS_OK. + If 'itemHandle' is non-zero, it will be filled with a + handle which may be used to generate a generator. + +lsStatus lsLastItem(list, data, itemHandle) +lsList list; /* List to get item from */ +lsGeneric *data; /* User data (returned) */ +lsHandle *itemHandle; /* Handle to data (returned) */ + + Returns the last item of a list. If the list is empty, + the routine returns LS_NOMORE. Otherwise, 'data' will + be set to the last item and the routine will return LS_OK. + If 'itemHandle' is non-zero, it will be filled with a + handle which can be used to generate a generator postioned + at this item. Accessing the last item of a list is a constant + time operation. + + +Deleting first and last items of a list +--------------------------------------- + +lsStatus lsDelBegin(list, data) +lsList list; /* List to delete item from */ +lsGeneric *data; /* First item (returned) */ + + This routine deletes the first item of a list. If `data' is + non-zero, it will be filled with a pointer to the user data + for the item (which may then be disposed). The routine + returns LS_NOMORE if there are no items in the list to delete. + +lsStatus lsDelEnd(list, data) +lsList list; /* List to delete item from */ +lsGeneric *data; /* Last item (returned) */ + + This routine deletes the last item of a list. If `data' is + non-zero, it will be filled with a pointer to the user data + for the item (which may then be disposed). The routine + returns LS_NOMORE if there are no items in the list to delete. + Deleting the last item of a list is a constant time operation. + +Length of a List +---------------- + +int lsLength(list) +lsList list; /* List to get the length of */ + + Returns the length of the list. The list must have been + already created using lsCreate. Obtaining the length of the + list is a constant time operation. + + +List Generation Routines +------------------------ + +lsGen lsStart(list) +lsList list; /* List to generate items from */ + + This routine defines a generator which is used to step through + each item of the list. The generator is initialized to the + beginning of the list. It returns a generator handle which + should be used when calling lsNext, lsPrev, lsInBefore, + lsInAfter, lsDelBefore, lsDelAfter, or lsFinish. + +lsGen lsEnd(list) +lsList list; /* List to generate items from */ + + This routine returns a generator which can be used to step + through each item of `list'. The generator is initialized to + the end of the list. This can be used to generate through + items in reverse order. + +lsGen lsGenHandle(itemHandle, data, option) +lsHandle itemHandle; /* Handle of an item */ +lsGeneric *data; /* Data associated with item */ +int option; /* LS_BEFORE or LS_AFTER */ + + This routine produces a generator given a handle. Handles are + produced whenever an item is added to a list. The generator + produced by this routine may be used when calling any of the + standard generation routines. NOTE: the generator should be + freed using lsFinish. The 'option' parameter determines + whether the generator spot is before or after the handle item. + +lsStatus lsNext(generator, data, itemHandle) +lsGen generator; /* Generator handle */ +lsGeneric *data; /* User data (return) */ +lsHandle *itemHandle; /* Handle to item (return) */ + + Generates the item after the item previously generated by + lsNext or lsPrev. It returns a pointer to the user data + structure in 'data'. 'itemHandle' may be used to get a + generation handle without generating through the list to find + the item. If there are no more elements to generate, the + routine returns LS_NOMORE (normally it returns LS_OK). + lsNext DOES NOT automatically clean up after all elements have + been generated. lsFinish must be called explicitly to do + this. (Note: an item is generated twice when an lsNext is + followed by an lsPrev and vice versa.) + +lsStatus lsPrev(generator, data, itemHandle) +lsGen generator; /* Generator handle */ +lsGeneric *data; /* User data (return) */ +lsHandle *itemHandle; /* Handle to item (return) */ + + Generates the item before the item previously generated by + lsNext or lsPrev. It returns a pointer to the user data + structure in 'data'. 'itemHandle' may be used to get a + generation handle without generating through the list to find + the item. If there are no more elements to generate, the + routine returns LS_NOMORE (normally it returns LS_OK). + lsPrev DOES NOT automatically clean up after all elements have + been generated. lsFinish must be called explicitly to do + this. (Note: an item is generated twice when an lsNext is + followed by an lsPrev and vice versa.) + +lsStatus lsInBefore(generator, data, itemHandle) +lsGen generator; /* Generator handle */ +lsGeneric data; /* Arbitrary pointer to data */ +lsHandle *itemHandle; /* Handle to item (return) */ + + Inserts an element BEFORE the current spot. The item + generated by lsNext will be unchanged; the inserted item will + be generated by lsPrev. This modifies the list. 'itemHandle' + may be used at a later time to produce a generation handle + without generating through the list. + +lsStatus lsInAfter(generator, data, itemHandle) +lsGen generator; /* Generator handle */ +lsGeneric data; /* Arbitrary pointer to data */ +lsHandle *itemHandle; /* Handle to item (return) */ + + Inserts an element AFTER the current spot. The next item + generated by lsNext will be the new element. The next item + generated by lsPrev is unchanged. This modifies the list. + 'itemHandle' may be used at a later time to generate a + generation handle without searching through the list to find + the item. + +lsStatus lsDelBefore(generator, data) +lsGen generator; /* Generator handle */ +lsGeneric *data; /* Deleted item (returned) */ + + Removes the item before the current spot. The next call to + lsPrev will return the item before the deleted item. The next + call to lsNext will be unaffected. This modifies the list. + The routine returns LS_BADSTATE if the user tries to call the + routine and there is no item before the current spot. This + routine returns the userData of the deleted item so it may be + freed (if necessary). + +lsStatus lsDelAfter(generator, data) +lsGen generator; /* Generator handle */ +lsGeneric *data; /* Deleted item (returned) */ + + Removes the item after the current spot. The next call to + lsNext will return the item after the deleted item. The next + call to lsPrev will be unaffected. This modifies the list. + The routine returns LS_BADSTATE if the user tries to call the + routine and there is no item after the current spot. This + routine returns the userData of the deleted item so it may be + freed (if necessary). + +lsStatus lsFinish(generator) +lsGen generator; /* Generator handle */ + + Marks the completion of a generation of list items. This + routine should be called after calls to lsNext to free + resources used by the generator. This rule applies even if + all items of a list are generated by lsNext. + + + +Functional List Generation +-------------------------- + +lsStatus lsForeach(list, userFunc, arg) +lsList list; /* List to generate through */ +lsStatus (*userFunc)(); /* User provided function */ +lsGeneric arg; /* User provided data */ + + This routine generates all items in `list' from the first item + to the last calling `userFunc' for each item. The function + should have the following form: + lsStatus userFunc(data, arg) + lsGeneric data; + lsGeneric arg; + `data' will be the user data associated with the item generated. + `arg' will be the same pointer provided to lsForeach. The + routine should return LS_OK to continue the generation, LS_STOP + to stop generating items, and LS_DELETE to delete the item + from the list. If the generation was stopped prematurely, + the routine will return LS_STOP. If the user provided function + does not return an appropriate value, the routine will return + LS_BADPARAM. + +lsStatus lsBackeach(list, userFunc, arg) +lsList list; /* List to generate through */ +lsStatus (*userFunc)(); /* User provided function */ +lsGeneric arg; /* User provided data */ + + This routine is just like lsForeach except it generates + all items in `list' from the last item to the first. + + + +Direct Handle Manipulation Routines +----------------------------------- + +lsList lsQueryHandle(itemHandle) +lsHandle itemHandle; /* Handle of an item */ + + This routine returns the associated list of the specified + handle. Returns 0 if there were problems. + +lsGeneric lsFetchHandle(itemHandle) +lsHandle itemHandle; /* Handle of an item */ + + Returns the data associated with `handle'. Returns 0 if + their were problems. + +lsStatus lsRemoveItem(itemHandle, userData) +lsHandle itemHandle; /* Handle of an item */ +lsGeneric *userData; /* Returned data */ + + This routine removes the item associated with `handle' from + its list and returns the user data associated with the item + for reclaimation purposes. Note this modifies the list + that originally contained `item'. + + +Sorting Operations +------------------ + +lsStatus lsSort(list, compare) +lsList list; /* List to sort */ +int (*compare)(); /* Comparison function */ + + This routine sorts `list' using `compare' as the comparison + function between items in the list. `compare' has the following form: + int compare(item1, item2) + lsGeneric item1, item2; + The routine should return -1 if item1 is less than item2, 0 if + they are equal, and 1 if item1 is greater than item2. The routine + uses a generic merge sort written by Rick Rudell which runs in + O(n log n) time. + +lsStatus lsUniq(list, compare, delFunc) +lsList list; /* List to remove duplicates from */ +int (*compare)(); /* Item comparison function */ +void (*delFunc)(); /* Function to release user data */ + + This routine takes a sorted list and removes all duplicates + from it. `compare' has the following form: + int compare(item1, item2) + lsGeneric item1, item2; + The routine should return -1 if item1 is less than item2, 0 if + they are equal, and 1 if item1 is greater than item2. `delFunc' + will be called with a pointer to a user data item for each + duplicate destroyed. `delFunc' can be zero if no clean up + is required. + diff --git a/sis/list/list.h b/sis/list/list.h new file mode 100644 index 0000000..cf397a6 --- /dev/null +++ b/sis/list/list.h @@ -0,0 +1,115 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/list/list.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +/* + * List Management Package Header File + * + * David Harrison + * University of California, 1985 + * + * This file contains public type definitions for the List Managment + * package implemented in list.c. This is stand alone package. + */ + +#ifndef LS_DEFINED +#define LS_DEFINED + +/* This can be typedef'ed to void if supported */ +typedef struct ls_dummy_defn { + int dummy; /* Not used */ +} ls_dummy; + +typedef ls_dummy *lsList; /* List handle */ +typedef ls_dummy *lsGen; /* List generator handle */ +typedef ls_dummy *lsHandle; /* Handle to an item */ +typedef int lsStatus; /* Return codes */ +typedef char *lsGeneric; /* Generic pointer */ + +#define LS_NIL 0 /* Nil for lsList */ + +#define LS_BADSTATE -3 /* Bad generator state */ +#define LS_BADPARAM -2 /* Bad parameter value */ +#define LS_NOMORE -1 /* No more items */ + +#define LS_OK 0 + +#define LS_BEFORE 1 /* Set spot before object */ +#define LS_AFTER 2 /* Set spot after object */ +#define LS_STOP 3 /* Stop generating items */ +#define LS_DELETE 4 /* Delete generated item */ + +/* + * For all those routines that take a handle, this macro can be + * used when no handle is required. + */ + +#define LS_NH (lsHandle *) 0 + +typedef lsGeneric (*LS_PFLSG)(); + +EXTERN lsList lsCreate ARGS((void)); + /* Create a new list */ +EXTERN lsStatus lsDestroy ARGS((lsList, void (*)())); + /* Delete a previously created list */ +EXTERN lsList lsCopy ARGS((lsList, LS_PFLSG)); + /* Copies the contents of a list */ + +EXTERN lsStatus lsFirstItem ARGS((lsList, lsGeneric *, lsHandle *)); + /* Gets the first item of a list */ +EXTERN lsStatus lsLastItem ARGS((lsList, lsGeneric *, lsHandle *)); + /* Gets the last item of a list */ + +EXTERN lsStatus lsNewBegin ARGS((lsList, lsGeneric, lsHandle *)); + /* Add item to start of list */ +EXTERN lsStatus lsNewEnd ARGS((lsList, lsGeneric, lsHandle *)); + /* Add item to end of list */ + +EXTERN lsStatus lsDelBegin ARGS((lsList, lsGeneric *)); + /* Delete first item of a list */ +EXTERN lsStatus lsDelEnd ARGS((lsList, lsGeneric *)); + /* Delete last item of a list */ + +EXTERN int lsLength ARGS((lsList)); + /* Returns the length of the list */ + +EXTERN lsGen lsStart ARGS((lsList)); + /* Begin generation of items in a list */ +EXTERN lsGen lsEnd ARGS((lsList)); + /* Begin generation at end of list */ +EXTERN lsGen lsGenHandle ARGS((lsHandle, lsGeneric *, int)); + /* Produces a generator given a handle */ +EXTERN lsStatus lsNext ARGS((lsGen, lsGeneric *, lsHandle *)); + /* Generate next item in sequence */ +EXTERN lsStatus lsPrev ARGS((lsGen, lsGeneric *, lsHandle *)); + /* Generate previous item in sequence */ +EXTERN lsStatus lsInBefore ARGS((lsGen, lsGeneric, lsHandle *)); + /* Insert an item before the most recently generated by lsNext */ +EXTERN lsStatus lsInAfter ARGS((lsGen, lsGeneric, lsHandle *)); + /* Insert an item after the most recently generated by lsNext */ +EXTERN lsStatus lsDelBefore ARGS((lsGen, lsGeneric *)); + /* Delete the item before the current spot */ +EXTERN lsStatus lsDelAfter ARGS((lsGen, lsGeneric *)); + /* Delete the item after the current spot */ +EXTERN lsStatus lsFinish ARGS((lsGen)); + /* End generation of items in a list */ + +EXTERN lsList lsQueryHandle ARGS((lsHandle)); + /* Returns the list of a handle */ +EXTERN lsGeneric lsFetchHandle ARGS((lsHandle)); + /* Returns data associated with handle */ +EXTERN lsStatus lsRemoveItem ARGS((lsHandle, lsGeneric *)); + /* Removes item associated with handle from list */ + +EXTERN lsStatus lsSort ARGS((lsList, int (*)())); + + /* Sorts a list */ +EXTERN lsStatus lsUniq ARGS((lsList, int (*)(), void (*)() )); + /* Removes duplicates from a sorted list */ + +#endif diff --git a/sis/lsort/Makefile.am b/sis/lsort/Makefile.am new file mode 100644 index 0000000..7eb18fc --- /dev/null +++ b/sis/lsort/Makefile.am @@ -0,0 +1 @@ +pkginclude_HEADERS = lsort.h luniq.h diff --git a/sis/lsort/Makefile.in b/sis/lsort/Makefile.in new file mode 100644 index 0000000..235b8db --- /dev/null +++ b/sis/lsort/Makefile.in @@ -0,0 +1,354 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/lsort +DIST_COMMON = $(pkginclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +am__installdirs = "$(DESTDIR)$(pkgincludedir)" +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +pkginclude_HEADERS = lsort.h luniq.h +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/lsort/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/lsort/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + ctags distclean distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags uninstall uninstall-am uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/lsort/lsort.h b/sis/lsort/lsort.h new file mode 100644 index 0000000..147b408 --- /dev/null +++ b/sis/lsort/lsort.h @@ -0,0 +1,159 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/lsort/lsort.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +/* + * Generic linked-list sorting package + * Richard Rudell, UC Berkeley, 4/1/87 + * + * Use: + * #define TYPE the linked-list type (a struct or typedef) + * #define SORT sorting routine (see below) + * #include "lsort.h" + * + * Optional: + * #define NEXT 'next' field name in the linked-list structure + * #define DECL_SORT 'static' or undefined + * #define DECL_SORT1 'static' or undefined + * #define SORT1 optional sorting routine interface + * #define FIELD select subfield of the structure for compare + * #define DIRECT_COMPARE in-line expand the compare routine + * + * This defines up to two routines: + * DECL_SORT TYPE * + * SORT1(list, compare) + * TYPE *list; + * int (*compare)(TYPE *x, TYPE *y); + * sort the linked list 'list' according to the compare function + * 'compare' + * + * DECL_SORT1 TYPE * + * SORT(list, compare, length) + * TYPE *list; + * int (*compare)(TYPE *x, TYPE *y); + * int length; + * sort the linked list 'list' according to the compare function + * 'compare'. length is the length of the linked list. + * + * Both routines gracefully handle length == 0 (in which case, list == 0 + * is also allowed). + * + * NEXT defines the name of the next field in the linked list. If not + * given, 'next' is assumed. + * + * By default, both routines are declared 'static'. This can be changed + * using '#define DECL_SORT' or '#define DECL_SORT1'. + * + * If FIELD is used, then a pointer to the particular field is passed + * to the comparison function (rather than a TYPE *). In this case, + * the compare function is called with: + * + * if ((*compare)(x->FIELD, y->FIELD)) { + * + * If DIRECT_COMPARE is used, then the 'FIELD' items are compared using + * a simple '>' (useful for scalars to save subroutine overhead) + */ + +#ifndef NEXT +#define NEXT next +#endif + +#ifndef DECL_SORT1 +#define DECL_SORT1 static +#endif + +#ifndef DECL_SORT +#define DECL_SORT static +#endif + +DECL_SORT TYPE *SORT(); + + +#ifdef SORT1 + +DECL_SORT1 TYPE * +SORT1(list_in, compare) +TYPE *list_in; +int (*compare)(); +{ + register int cnt; + register TYPE *p; + + /* Find the length of the list */ + for(p = list_in, cnt = 0; p != 0; p = p->NEXT, cnt++) + ; + return SORT(list_in, compare, cnt); +} + +#endif + +DECL_SORT TYPE * +SORT(list_in, compare, cnt) +TYPE *list_in; +int (*compare)(); +int cnt; +{ + register TYPE *p, **plast, *list1, *list2; + register int i; + + if (cnt > 1) { + /* break the list in half */ + for(p = list_in, i = cnt/2-1; i > 0; p = p->NEXT, i--) + ; + list1 = list_in; + list2 = p->NEXT; + p->NEXT = 0; + + /* Recursively sort the sub-lists (unless only 1 element) */ + if ((i = cnt/2) > 1) { + list1 = SORT(list1, compare, i); + } + if ((i = cnt - i) > 1) { + list2 = SORT(list2, compare, i); + } + + /* Merge the two sorted sub-lists */ + plast = &list_in; + for(;;) { +#ifdef FIELD +#ifdef DIRECT_COMPARE + if (list1->FIELD < list2->FIELD) { +#else + if ((*compare)(list1->FIELD, list2->FIELD) <= 0) { +#endif +#else + if ((*compare)(list1, list2) <= 0) { +#endif + *plast = list1; + plast = &(list1->NEXT); + if ((list1 = list1->NEXT) == 0) { + *plast = list2; + break; + } + } else { + *plast = list2; + plast = &(list2->NEXT); + if ((list2 = list2->NEXT) == 0) { + *plast = list1; + break; + } + } + } + } + + return list_in; +} + +#undef TYPE +#undef SORT +#undef SORT1 +#undef DECL_SORT +#undef DECL_SORT1 +#undef FIELD +#undef DIRECT_COMPARE +#undef NEXT diff --git a/sis/lsort/luniq.h b/sis/lsort/luniq.h new file mode 100644 index 0000000..707e71b --- /dev/null +++ b/sis/lsort/luniq.h @@ -0,0 +1,96 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/lsort/luniq.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:29 $ + * + */ +/* + * Generic linked-list uniqifier package + * Richard Rudell, UC Berkeley, 4/1/87 + * + * Use: + * #define UNIQ routine_name + * #define TYPE typedef for structure of the linked-list + * #include "luniq.h" + * + * Optional: + * #define NEXT 'next' field for the linked-list + * #define FREQ 'frequency' field (to maintain histogram) + * #define DECL_UNIQ 'static' or undefined + * + * This defines a routine: + * DECL_UNIQ TYPE * + * UNIQ(list, compare, free) + * TYPE *list; + * int (*compare)(TYPE *x, TYPE *y); + * void free(TYPE *); + * + * Deletes duplicates from the list 'list'; calls 'free' (if + * non-zero) to dispose of each element in the list. + * + * The routines gracefully handle length == 0 (in which case, list == 0 + * is also allowed). + * + * By default, the routine is declared 'static'. This can be changed + * using '#define DECL_UNIQ'. + */ + +#ifndef NEXT +#define NEXT next +#endif + +#ifndef DECL_UNIQ +#define DECL_UNIQ static +#endif + + +DECL_UNIQ TYPE * +UNIQ(list, compare, free_routine) +TYPE *list; /* linked-list of objects */ +int (*compare)(); /* how to compare two objects */ +void (*free_routine)(); /* dispose of duplicate objects */ +{ + register TYPE *p1, *p2; + +#ifdef FREQ + for(p1 = list; p1 != 0; p1 = p1->next) { + p1->FREQ = 1; + } +#endif + + if (list != 0) { + p1 = list; + while ((p2 = p1->NEXT) != 0) { + +#ifdef FIELD +#ifdef DIRECT_COMPARE + if (p1->FIELD == p2->FIELD) { +#else + if ((*compare)(p1->FIELD, p2->FIELD) == 0) { +#endif +#else + if ((*compare)(p1, p2) == 0) { +#endif + p1->NEXT = p2->NEXT; +#ifdef FREQ + p1->FREQ++; +#endif + if (free_routine != 0) (*free_routine)(p2); + } else { + p1 = p2; + } + } + p1->NEXT = 0; + } + return list; +} + +#undef UNIQ +#undef FREQ +#undef NEXT +#undef FIELD +#undef DIRECT_COMPARE +#undef DECL_UNIQ diff --git a/sis/main/Makefile.am b/sis/main/Makefile.am new file mode 100644 index 0000000..9807d7f --- /dev/null +++ b/sis/main/Makefile.am @@ -0,0 +1,9 @@ +docdir = @SIS_DOCDIR@ +MYDATE = $(shell date '+%Y-%m-%d %H:%M:%S') +AM_CPPFLAGS = -DSIS '-DCUR_DATE="$(MYDATE)"' \ +'-DLIBRARY="@SIS_SISLIBDIR@"' -I../include + +noinst_LIBRARIES = libmain.a +libmain_a_SOURCES = sis.c sis_glbs.c sis_init.c version.c +pkginclude_HEADERS = sis.h +dist_doc_DATA = sis.doc diff --git a/sis/main/Makefile.in b/sis/main/Makefile.in new file mode 100644 index 0000000..a3816fb --- /dev/null +++ b/sis/main/Makefile.in @@ -0,0 +1,422 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libmain_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/main +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libmain_a_AR = $(AR) $(ARFLAGS) +libmain_a_LIBADD = +am_libmain_a_OBJECTS = sis.$(OBJEXT) sis_glbs.$(OBJEXT) \ + sis_init.$(OBJEXT) version.$(OBJEXT) +libmain_a_OBJECTS = $(am_libmain_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libmain_a_SOURCES) +DIST_SOURCES = $(libmain_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +MYDATE = $(shell date '+%Y-%m-%d %H:%M:%S') +AM_CPPFLAGS = -DSIS '-DCUR_DATE="$(MYDATE)"' \ +'-DLIBRARY="@SIS_SISLIBDIR@"' -I../include + +noinst_LIBRARIES = libmain.a +libmain_a_SOURCES = sis.c sis_glbs.c sis_init.c version.c +pkginclude_HEADERS = sis.h +dist_doc_DATA = sis.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/main/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/main/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libmain.a: $(libmain_a_OBJECTS) $(libmain_a_DEPENDENCIES) + -rm -f libmain.a + $(libmain_a_AR) libmain.a $(libmain_a_OBJECTS) $(libmain_a_LIBADD) + $(RANLIB) libmain.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/main/sis.c b/sis/main/sis.c new file mode 100644 index 0000000..3a5bdfc --- /dev/null +++ b/sis/main/sis.c @@ -0,0 +1,329 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/main/sis.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +#include "sis.h" + +#include <sys/stat.h> + +extern void init_sis(); +extern void end_sis(); + +static int main_has_restarted = 0; +static network_t *network; /* allows for restart ... */ + + +static int +source_sisrc(network) +network_t **network; +{ + char *cmdline; + char *lib_name; + char *homefile; + struct stat home, cur; + int s1, s2; /* Flags for checking the stat() call */ + int status0, status1, status2, status3, status4, status5; + + lib_name = sis_library(); + cmdline = ALLOC(char, strlen(lib_name) + 20); + + (void) sprintf(cmdline, "source -s %s/.misrc", lib_name); + status0 = com_execute(network, cmdline); + (void) sprintf(cmdline, "source -s %s/.sisrc", lib_name); + status1 = com_execute(network, cmdline); + status3 = com_execute(network, "source -s ~/.sisrc"); + + homefile = util_tilde_expand("~/.misrc"); + s1 = stat(homefile, &home); + s2 = stat(".misrc", &cur); + status2 = status4 = TRUE; + if ((s1 == 0) && (s2 == 0) && (home.st_ino == cur.st_ino)){ + /* ~/.misrc == .misrc : Source the file only once */ + status2 = com_execute(network, "source -s ~/.misrc"); + } else { + if (s1 == 0) { /* ~/.misrc exists and can be opened */ + status2 = com_execute(network, "source -s ~/.misrc"); + } + if (s2 == 0) { /* ./.misrc exists and can be opened */ + status4 = com_execute(network, "source -s .misrc"); + } + } + FREE(homefile); + + homefile = util_tilde_expand("~/.sisrc"); + s1 = stat(homefile, &home); + s2 = stat(".sisrc", &cur); + status3 = status5 = TRUE; + if ((s1 == 0) && (s2 == 0) && (home.st_ino == cur.st_ino)){ + /* ~/.sisrc == .sisrc : Source the file only once */ + status3 = com_execute(network, "source -s ~/.sisrc"); + } else { + if (s1 == 0) { + status3 = com_execute(network, "source -s ~/.sisrc"); + } + if (s2 == 0) { + status5 = com_execute(network, "source -s .sisrc"); + } + } + FREE(homefile); + + FREE(cmdline); + FREE(lib_name); + return status0 && status1 && status2 && status3 && status4 && status5; +} + + +static void +usage(prog) +char *prog; +{ + char *lib_name; + + (void) fprintf(miserr, "%s\n", sis_version()); + (void) fprintf(miserr, +"usage: %s [-sx] [-c cmd] [-f script] [-o file] [-t type] [-T type] [file]\n", + prog); +#ifdef SIS + (void) fprintf(miserr, + " -c cmd\texecute SIS commands `cmd'\n"); + (void) fprintf(miserr, + " -f file\texecute SIS commands from a file\n"); +#else + (void) fprintf(miserr, + " -c cmd\texecute MIS commands `cmd'\n"); + (void) fprintf(miserr, + " -f file\texecute MIS commands from a file\n"); +#endif + (void) fprintf(miserr, + " -o file\tspecify output filename (default is -)\n"); + lib_name = sis_library(); +#ifdef SIS + (void) fprintf(miserr, + " -s\t\tsuppress initial 'source %s/.sisrc'\n", sis_library()); +#else + (void) fprintf(miserr, + " -s\t\tsuppress initial 'source %s/.misrc'\n", sis_library()); +#endif + FREE(lib_name); +#ifdef SIS + (void) fprintf(miserr, + " -t type\tspecify input type (blif, eqn, kiss, oct, pla, slif, or none)\n"); + (void) fprintf(miserr, + " -T type\tspecify output type (blif, eqn, kiss, oct, pla, slif, or none)\n"); +#else + (void) fprintf(miserr, + " -t type\tspecify input type (bdnet, blif, eqn, oct, pla, or none)\n"); + (void) fprintf(miserr, + " -T type\tspecify output type (bdnet, blif, eqn, oct, pla, or none)\n"); +#endif + (void) fprintf(miserr, + " -x\t\tequivalent to '-t none -T none'\n"); + exit(2); +} + + +static int +check_type(s) +char *s; +{ + if (strcmp(s, "bdnet") == 0) { + return 1; + } else if (strcmp(s, "blif") == 0) { + return 1; + } else if (strcmp(s, "eqn") == 0) { + return 1; +#ifdef SIS + } else if (strcmp(s, "kiss") == 0) { + return 1; +#endif + } else if (strcmp(s, "oct") == 0) { + return 1; + } else if (strcmp(s, "pla") == 0) { + return 1; +#ifdef SIS + } else if (strcmp(s, "slif") == 0) { + return 1; +#endif + } else if (strcmp(s, "none") == 0) { + return 1; + } else { + (void) fprintf(miserr, "unknown type %s\n", s); + return 0; + } +} + +main(argc, argv) +int argc; +char **argv; +{ + int c, status, batch, initial_source, initial_read, final_write; + int graphics_flag, quit_flag; + char readcmd[20], writecmd[20]; + char *dummy, *cmdline, *cmdline1, *infile, *outfile; + + program_name = argv[0]; + + /* Must check for -X flag before init_sis. May be able to move + second option loop here, after someone makes sure that won't + break anything. prs 9/91. */ + + graphics_flag = 0; + quit_flag = -1; /* Quick quit */ + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "c:f:o:st:T:xX:")) != EOF) { + if (c == 'X') graphics_flag = atoi (util_optarg); + } + + if (main_has_restarted) { + (void) fprintf(stderr, "Restarting frozen image ...\n"); + } else { + main_has_restarted = 1; + init_sis (graphics_flag); + network = network_alloc(); + } + + cmdline = util_strsav(""); + (void) strcpy(readcmd, "read_blif"); + (void) strcpy(writecmd, "write_blif"); + infile = "-"; + outfile = "-"; + command_hist = array_alloc(char *, 0); + initial_source = 1; + initial_read = 1; + final_write = 1; + batch = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "c:f:o:st:T:xX:")) != EOF) { + switch(c) { + case 'c': + FREE(cmdline); + cmdline = util_strsav(util_optarg); + batch = 1; + break; + + case 'f': + FREE(cmdline); + cmdline = ALLOC(char, strlen(util_optarg) + 20); + (void) sprintf(cmdline, "source %s", util_optarg); + batch = 1; + break; + + case 'o': + outfile = util_optarg; + break; + + case 's': + initial_source = 0; + break; + + case 't': + if (check_type(util_optarg)) { + if (strcmp(util_optarg, "none") == 0) { + initial_read = 0; + } else { + (void) sprintf(readcmd, "read_%s", util_optarg); + } + } else { + usage(argv[0]); + } + batch = 1; + break; + + case 'T': + if (check_type(util_optarg)) { + if (strcmp(util_optarg, "none") == 0) { + final_write = 0; + } else { + (void) sprintf(writecmd, "write_%s", util_optarg); + } + } else { + usage(argv[0]); + } + batch = 1; + break; + + case 'x': + final_write = 0; + initial_read = 0; + batch = 1; + break; + + case 'X': + /* Handled in previous option loop. */ + break; + + default: + usage(argv[0]); + } + } + + if (! batch) { + /* interactive use ... */ + if (argc - util_optind != 0) { + (void) fprintf(miserr, "warning -- trailing arguments ignored\n"); + } + + (void) fprintf(misout, "%s\n", sis_version()); + if (initial_source) { + (void) source_sisrc(&network); + } + while ((quit_flag = com_execute(&network, "source -ip -")) >= 0) + ; + status = 0; + + } else { + + /* read initial network */ + if (argc - util_optind == 0) { + infile = "-"; + } else if (argc - util_optind == 1) { + infile = argv[util_optind]; + } else { + usage(argv[0]); + } + + if (initial_source) { + (void) source_sisrc(&network); + } + + status = 0; + if (initial_read) { + cmdline1 = ALLOC(char, strlen(infile) + 20); + (void) sprintf(cmdline1, "%s %s", readcmd, infile); + status = com_execute(&network, cmdline1); + FREE(cmdline1); + } + + if (status == 0) { + status = com_execute(&network, cmdline); + if ((status == 0 || status == -1) && final_write) { + cmdline1 = ALLOC(char, strlen(outfile) + 20); + (void) sprintf(cmdline1, "%s %s", writecmd, outfile); + status = com_execute(&network, cmdline1); + FREE(cmdline1); + } + } + + } + + FREE(cmdline); + for (c = array_n(command_hist); c-- > 0; ){ + dummy = array_fetch(char *, command_hist, c); + FREE(dummy); + } + array_free(command_hist); + /* Value of "quit_flag" is determined by the "quit" command */ + if (quit_flag == -1 || quit_flag == -2) { + status = 0; + } + if (quit_flag == -2) { + network_free(network); + end_sis(); + } + exit(status); +} diff --git a/sis/main/sis.doc b/sis/main/sis.doc new file mode 100644 index 0000000..dd73a1d --- /dev/null +++ b/sis/main/sis.doc @@ -0,0 +1,19 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/main/sis.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +char * +sis_version() + Returns a static string giving the MIS version and compile timestamp. + + +char * +sis_library() + Returns a static string giving the directory which contains the + standard SIS library. Used to find things like the default .sisrc, + the default optimization script, the on-line help files, etc. diff --git a/sis/main/sis.h b/sis/main/sis.h new file mode 100644 index 0000000..f14c281 --- /dev/null +++ b/sis/main/sis.h @@ -0,0 +1,86 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/main/sis.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +#ifndef SIS_H +#define SIS_H + +/* espresso brings in sparse.h, mincov.h, util.h */ +#include "espresso.h" + +#include "avl.h" +#include "enc.h" +#include "st.h" +#include "array.h" +#include "list.h" +#include "sat.h" +#include "spMatrix.h" +#include "var_set.h" +#ifdef SIS +#include "graph.h" +#include "graph_static.h" +#endif /* SIS */ + +#include "error.h" +#include "node.h" +#include "nodeindex.h" + +#ifdef SIS +#include "stg.h" +#include "astg.h" +#endif /* SIS */ +#include "network.h" +#include "command.h" +#include "io.h" + +#include "factor.h" +#include "decomp.h" +#include "resub.h" +#include "phase.h" +#include "simplify.h" +#include "minimize.h" +#include "graphics.h" + +#include "extract.h" +#ifdef SIS +#include "clock.h" +#include "latch.h" +#include "retime.h" +#endif /* SIS */ + +#include "delay.h" +#include "library.h" +#include "map.h" +#include "pld.h" + +#include "bdd.h" +#include "order.h" +#include "ntbdd.h" + +#ifdef SIS +#include "seqbdd.h" +#endif /* SIS */ + +#include "gcd.h" +#include "maxflow.h" +#include "speed.h" + +extern FILE *sisout; +extern FILE *siserr; +extern FILE *sishist; +extern array_t *command_hist; +extern char *program_name; +extern char *sis_version(); +extern char *sis_library(); + +#define misout sisout +#define miserr siserr + +#define INFINITY (1 << 30) + +#endif diff --git a/sis/main/sis_glbs.c b/sis/main/sis_glbs.c new file mode 100644 index 0000000..ad7d3a0 --- /dev/null +++ b/sis/main/sis_glbs.c @@ -0,0 +1,19 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/main/sis_glbs.c,v $ + * $Author: pchong $ + * $Revision: 1.3 $ + * $Date: 2004/02/18 18:38:31 $ + * + */ +#include <stdio.h> +#include "ansi.h" +#include "array.h" + +FILE *siserr = 0; +FILE *sisout = 0; +char *program_name = 0; + +FILE *sishist = 0; +array_t *command_hist = 0; diff --git a/sis/main/sis_init.c b/sis/main/sis_init.c new file mode 100644 index 0000000..e34bd93 --- /dev/null +++ b/sis/main/sis_init.c @@ -0,0 +1,119 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/main/sis_init.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:30 $ + * + */ +#include "sis.h" + +void +init_sis(graphics_flag) +int graphics_flag; +{ +#if defined(bsd4_2) || defined(sun) /* hack, but its nice to have ... */ + setlinebuf(stdout); + setlinebuf(stderr); +#endif +#ifdef OCT +#ifdef SIS + errProgramName("SIS - Version 1.2"); +#else + errProgramName("MIS - Version 2.2"); +#endif + errCore(1); +#endif + + sisout = stdout; + siserr = stderr; + sishist = NIL(FILE); + init_command(graphics_flag); /* must be first */ + init_node(); + init_network(); + init_io(); + init_extract(); + init_factor(); + init_decomp(); + init_resub(); + init_delay(); + init_map(); + init_genlib(); + init_phase(); + init_pld(); + init_sim(); + init_simplify(); + init_gcd(); +#ifdef OCT + init_octio(); +#endif + init_ntbdd(); + init_maxflow(); + init_speed(); + init_atpg(); + init_graphics(); +#ifdef SIS + init_latch(); + init_power(); + init_retime(); + init_graph(); + init_seqbdd(); + init_stg(); + init_clock(); + init_astg(); + init_timing(); +#endif + init_test(); + + com_graphics_help(); +} + + +void +end_sis() +{ + end_test(); +#ifdef SIS + end_timing(); + end_astg(); /* Has daemons and uses node package. */ + end_clock(); + end_stg(); + end_seqbdd(); + end_graph(); + end_retime(); + end_power(); + end_latch(); +#endif /* SIS */ + end_graphics(); + end_atpg(); + end_speed(); + end_maxflow(); + end_ntbdd(); +#ifdef OCT + end_octio(); +#endif + end_gcd(); + end_simplify(); + end_sim(); + end_phase(); + end_pld(); + end_genlib(); + end_map(); + end_delay(); + end_resub(); + end_decomp(); + end_factor(); + end_extract(); + end_io(); + end_network(); + end_command(); + end_node(); /* Should be last (to discard daemons). */ + if (sisout != stdout) (void) fclose(sisout); + if (siserr != stderr) (void) fclose(siserr); + if (sishist != NIL(FILE)) (void) fclose(sishist); + sisout = stdout; + siserr = stderr; + sishist = NIL(FILE); + sf_cleanup(); +} diff --git a/sis/main/version.c b/sis/main/version.c new file mode 100644 index 0000000..37bb80d --- /dev/null +++ b/sis/main/version.c @@ -0,0 +1,84 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/main/version.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2005/03/08 05:37:40 $ + * + */ +#include "sis.h" +#include "config.h" + + +#ifndef CUR_DATE +#define CUR_DATE "<compile date not supplied>" +#endif + +#ifndef CUR_VER +#ifdef SIS +#define CUR_VER "UC Berkeley, " PACKAGE_STRING +#else +#define CUR_VER "UC Berkeley, MIS Release 2.2" +#endif +#endif + +#ifndef LIBRARY +#define LIBRARY "/projects/sis/sis/common/sis_lib" +#endif + + +/* + * Returns the date in a brief format assuming its coming from + * the program `date'. + */ +static char * +proc_date(datestr) +char *datestr; +{ + static char result[25]; + char day[10], month[10], zone[10], *at; + int date, hour, minute, second, year; + + if (sscanf(datestr, "%s %s %2d %2d:%2d:%2d %s %4d", + day, month, &date, &hour, &minute, &second, zone, &year) == 8) { + if (hour >= 12) { + if (hour >= 13) hour -= 12; + at = "PM"; + } else { + if (hour == 0) hour = 12; + at = "AM"; + } + (void) sprintf(result, "%d-%3s-%02d at %d:%02d %s", + date, month, year % 100, hour, minute, at); + return result; + } else { + return datestr; + } +} + + + +/* + * Returns the current SIS version string to the caller. + */ + +char * +sis_version() +{ + static char version[1024]; + + (void) sprintf(version, "%s (compiled %s)", CUR_VER, proc_date(CUR_DATE)); + return version; +} + + +/* + * Returns the SIS library path (usually ~cad/lib/sis/lib) to the caller + */ + +char * +sis_library() +{ + return util_tilde_expand(LIBRARY); +} diff --git a/sis/map/Makefile.am b/sis/map/Makefile.am new file mode 100644 index 0000000..d4f6ea6 --- /dev/null +++ b/sis/map/Makefile.am @@ -0,0 +1,18 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libmap.a +libmap_a_SOURCES = addinv.c bin_delay.c bottom_up.c chkform.c cluster.c \ + com_map.c fanout_delay.c fanout_dump.c fanout_est.c fanout_log.c \ + fanout_opt.c fanout_tree.c fanout_util.c gate_link.c hackit.c library.c \ + libutil.c lt_trees.c map_delay.c map_interface.c maputil.c match.c \ + mix_lt_trees.c multi_array.c noalg.c prim.c pwl.c replace.c top_down.c \ + tree.c treemap.c treesize.c two_level.c virtual_del.c virtual_net.c \ + bin_delay_static.h bin_int.h cluster.h cluster_static.h fanout_alg.h \ + fanout_alg_macro.h fanout_delay.h fanout_delay_static.h \ + fanout_est_static.h fanout_int.h fanout_opt_static.h \ + fanout_tree_static.h gate_link.h lib_int.h map_defs.h \ + map_delay.h map_int.h map_interface_static.h map_macros.h multi_array.h \ + pwl.h pwl_static.h +pkginclude_HEADERS = library.h map.h +dist_doc_DATA = library.doc map.doc diff --git a/sis/map/Makefile.in b/sis/map/Makefile.in new file mode 100644 index 0000000..3426096 --- /dev/null +++ b/sis/map/Makefile.in @@ -0,0 +1,442 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libmap_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/map +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libmap_a_AR = $(AR) $(ARFLAGS) +libmap_a_LIBADD = +am_libmap_a_OBJECTS = addinv.$(OBJEXT) bin_delay.$(OBJEXT) \ + bottom_up.$(OBJEXT) chkform.$(OBJEXT) cluster.$(OBJEXT) \ + com_map.$(OBJEXT) fanout_delay.$(OBJEXT) fanout_dump.$(OBJEXT) \ + fanout_est.$(OBJEXT) fanout_log.$(OBJEXT) fanout_opt.$(OBJEXT) \ + fanout_tree.$(OBJEXT) fanout_util.$(OBJEXT) \ + gate_link.$(OBJEXT) hackit.$(OBJEXT) library.$(OBJEXT) \ + libutil.$(OBJEXT) lt_trees.$(OBJEXT) map_delay.$(OBJEXT) \ + map_interface.$(OBJEXT) maputil.$(OBJEXT) match.$(OBJEXT) \ + mix_lt_trees.$(OBJEXT) multi_array.$(OBJEXT) noalg.$(OBJEXT) \ + prim.$(OBJEXT) pwl.$(OBJEXT) replace.$(OBJEXT) \ + top_down.$(OBJEXT) tree.$(OBJEXT) treemap.$(OBJEXT) \ + treesize.$(OBJEXT) two_level.$(OBJEXT) virtual_del.$(OBJEXT) \ + virtual_net.$(OBJEXT) +libmap_a_OBJECTS = $(am_libmap_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libmap_a_SOURCES) +DIST_SOURCES = $(libmap_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libmap.a +libmap_a_SOURCES = addinv.c bin_delay.c bottom_up.c chkform.c cluster.c \ + com_map.c fanout_delay.c fanout_dump.c fanout_est.c fanout_log.c \ + fanout_opt.c fanout_tree.c fanout_util.c gate_link.c hackit.c library.c \ + libutil.c lt_trees.c map_delay.c map_interface.c maputil.c match.c \ + mix_lt_trees.c multi_array.c noalg.c prim.c pwl.c replace.c top_down.c \ + tree.c treemap.c treesize.c two_level.c virtual_del.c virtual_net.c \ + bin_delay_static.h bin_int.h cluster.h cluster_static.h fanout_alg.h \ + fanout_alg_macro.h fanout_delay.h fanout_delay_static.h \ + fanout_est_static.h fanout_int.h fanout_opt_static.h \ + fanout_tree_static.h gate_link.h lib_int.h map_defs.h \ + map_delay.h map_int.h map_interface_static.h map_macros.h multi_array.h \ + pwl.h pwl_static.h + +pkginclude_HEADERS = library.h map.h +dist_doc_DATA = library.doc map.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/map/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/map/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libmap.a: $(libmap_a_OBJECTS) $(libmap_a_DEPENDENCIES) + -rm -f libmap.a + $(libmap_a_AR) libmap.a $(libmap_a_OBJECTS) $(libmap_a_LIBADD) + $(RANLIB) libmap.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/map/addinv.c b/sis/map/addinv.c new file mode 100644 index 0000000..40b5d30 --- /dev/null +++ b/sis/map/addinv.c @@ -0,0 +1,260 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/addinv.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)addinv.c 1.4 */ +/* last modified on 9/17/91 at 14:29:24 */ +#include "sis.h" +#include "map_int.h" + + +static node_t * +create_inverter(nodelist, fanin) +lsList nodelist; +node_t *fanin; +{ + node_t *inv; + + inv = node_alloc(); + node_replace(inv, node_literal(fanin, 0)); + LS_ASSERT(lsNewEnd(nodelist, (char *) inv, LS_NH)); + return inv; +} + + +static int +feeds_po(node) +node_t *node; +{ + lsGen gen; + node_t *fanout; + + foreach_fanout(node, gen, fanout) { + if (fanout->type == PRIMARY_OUTPUT) { + LS_ASSERT(lsFinish(gen)); + return 1; + } + } + return 0; +} + +static int +feeds_latch(node) +node_t *node; +{ +#ifndef SIS + return 0; +#else + lsGen gen; + node_t *fanout; + + foreach_fanout(node, gen, fanout) { + if (fanout->type == PRIMARY_OUTPUT) { + if (latch_from_node(fanout) != NIL(latch_t)) { + LS_ASSERT(lsFinish(gen)); + return 1; + } + } + } + return 0; +#endif /* SIS */ +} + +static void +add_inverters(nodelist, node, deleted) +lsList nodelist; +node_t *node; +st_table *deleted; +{ + int i; + node_t *inv1, *inv2, *inv, *fanout, *other_inv; + array_t *output_inv; + lsGen gen; + + /* Find if the node already has an inverter at the output */ + output_inv = array_alloc(node_t *, 0); + foreach_fanout(node, gen, fanout) { + if (node_function(fanout) == NODE_INV) { + array_insert_last(node_t *, output_inv, fanout); + } + } + + /* Create an inverter if none found so far */ + if (array_n(output_inv) == 0) { + inv = create_inverter(nodelist, node); + } else { + inv = array_fetch(node_t *, output_inv, 0); + } + + /* Handle the positive-phase fanouts (i.e., fanouts of 'node') */ + foreach_fanout(node, gen, fanout) { + if (node_function(fanout) != NODE_INV) { + inv1 = create_inverter(nodelist, inv); + assert(node_patch_fanin(fanout, node, inv1)); + } + } + + /* Handle the negative-phase fanouts (i.e., fanouts of original inverter) */ + /* and put them as fanout of 'inv' */ + /* all inverter nodes but 'inv' are then removed */ + for (i = 0; i < array_n(output_inv); i++) { + other_inv = array_fetch(node_t *, output_inv, i); + foreach_fanout(other_inv, gen, fanout) { + if (node_function(fanout) != NODE_INV && fanout->type != PRIMARY_OUTPUT) { + inv1 = create_inverter(nodelist, inv); + inv2 = create_inverter(nodelist, inv1); + assert(node_patch_fanin(fanout, other_inv, inv2)); + } else if (other_inv != inv) { + assert(node_patch_fanin(fanout, other_inv, inv)); + } + } + if (other_inv != inv) { + assert(node_num_fanout(other_inv) == 0); + assert(node_function(other_inv) == NODE_INV); + st_insert(deleted, (char *) other_inv, NIL(char)); + } + } + array_free(output_inv); +} + +void +map_add_inverter(network, add_at_pipo) +network_t *network; +int add_at_pipo; +{ + lsList nodelist; + st_table *deleted; + node_t *node; + int need_inv; + lsGen gen; + st_generator *del_gen; + + nodelist = lsCreate(); + deleted = st_init_table(st_ptrcmp, st_ptrhash); + + foreach_node(network, gen, node) { + if (st_lookup(deleted, (char *) node, NIL(char *))) continue; + switch(node_function(node)) { + case NODE_PI: + need_inv = node_num_fanout(node) > 1 || add_at_pipo; + break; + case NODE_PO: + case NODE_INV: + need_inv = 0; + break; + case NODE_0: + case NODE_1: + need_inv = 0; + break; + case NODE_AND: + case NODE_OR: + /* special case for single-fanout outputs on primitives */ + if (node_num_fanout(node) == 1 && feeds_po(node)) { + need_inv = feeds_latch(node)?0:add_at_pipo; + } else { + need_inv = 1; + } + break; + default: + fail("map_add_inverter: what is this doing here ?"); + /* NOTREACHED */ + } + if (need_inv) { + add_inverters(nodelist, node, deleted); + } + } + + lsForeachItem(nodelist, gen, node) { + network_add_node(network, node); + } + st_foreach_item(deleted, del_gen, (char **) &node, NIL(char *)) { + network_delete_node(node->network, node); + } + st_free_table(deleted); + LS_ASSERT(lsDestroy(nodelist, (void (*)()) 0)); +} + +void +map_remove_inverter(network, report_data) +network_t *network; +VoidFn report_data; +{ + int i, j, num_fanout; + node_t *inv1, *inv2, *node, *fanout, *fanout1; + node_t **fanouts; + array_t *nodes; + lsGen gen, gen1; + + if (report_data) { + fprintf(sisout, ">>> before removing serial inverters <<<\n"); + (*report_data)(network); + } + /* step 1: check for sequential inverters */ + nodes = network_dfs(network); + for(i = 0; i < array_n(nodes); i++) { + inv2 = array_fetch(node_t *, nodes, i); + if (node_function(inv2) == NODE_INV) { + + /* see if the fanin is also an inverter ... */ + inv1 = node_get_fanin(inv2, 0); + if (node_function(inv1) == NODE_INV) { + node = node_get_fanin(inv1, 0); + num_fanout = node_num_fanout(inv2); + fanouts = ALLOC(node_t *, num_fanout); + j = 0; + foreach_fanout(inv2, gen, fanout) { + fanouts[j++] = fanout; + } + for (j = 0; j < num_fanout; j++) { + assert(node_patch_fanin(fanouts[j], inv2, node)); + } + FREE(fanouts); + network_delete_node(network, inv2); + } + } + } + array_free(nodes); + if (report_data) { + fprintf(sisout, ">>> before removing parallel inverters <<<\n"); + (*report_data)(network); + } + /* step 2: check for parallel inverters */ + nodes = network_dfs_from_input(network); + for(i = 0; i < array_n(nodes); i++) { + node = array_fetch(node_t *, nodes, i); + if (node_function(node) != NODE_INV) { + + /* find if more than 2 inverters fanout from 'node' */ + inv1 = NIL(node_t); + foreach_fanout(node, gen, fanout) { + if (node_function(fanout) == NODE_INV) { + if (inv1 == NIL(node_t)) { + inv1 = fanout; + } else { + /* move fanouts of 'fanout' to fanouts of inv1 */ + num_fanout = node_num_fanout(fanout); + fanouts = ALLOC(node_t *, num_fanout); + j = 0; + foreach_fanout(fanout, gen1, fanout1) { + fanouts[j++] = fanout1; + } + for (j = 0 ; j < num_fanout; j++) { + assert(node_patch_fanin(fanouts[j], fanout, inv1)); + } + FREE(fanouts); + network_delete_node(network, fanout); + } + } + } + } + } + array_free(nodes); + + /* cleanup dangling nodes (?) -- are there any ?? */ + (void) network_cleanup(network); +} diff --git a/sis/map/bin_delay.c b/sis/map/bin_delay.c new file mode 100644 index 0000000..c5753fa --- /dev/null +++ b/sis/map/bin_delay.c @@ -0,0 +1,1119 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/bin_delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)bin_delay.c 1.8 */ +/* last modified on 7/24/91 at 16:46:37 */ +#include "sis.h" +#include <math.h> +#include "map_macros.h" +#include "map_int.h" +#include "bin_int.h" +#include "map_delay.h" +#include "fanout_int.h" +#include "fanout_delay.h" + +static bin_global_t global; +#include "bin_delay_static.h" + +static char errmsg[1024]; +#ifdef SIS +static void hack_po(); +#endif /* SIS */ + + /* performs minimum delay tree covering using piece-wise linear functions */ + /* to model the achievable arrival times at each node as a function of the */ + /* load. If the network was originally annotated, makes sure the loads at */ + /* multiple fanout point is not any larger than the current load */ + + + /* EXTERNAL INTERFACE */ + + /* ARGSUSED */ +int bin_delay_area_tree_match(network, library, globals) +network_t *network; +library_t *library; +bin_global_t globals; +{ + (void) fprintf(siserr, "ERROR: '-n x' with 0 < x < 1 no longer supported\n"); + return 0; +} + +int bin_delay_tree_match(network, library, globals) +network_t *network; +library_t *library; +bin_global_t globals; +{ + global = globals; + global.library = library; + init_delay_bucket_storage(); + bin_for_all_nodes_inputs_first(network, bin_alloc); + if (!compute_best_match(network)) { + return 0; + } +#ifdef SIS + hack_po(network); +#endif /* SIS */ + bin_for_all_nodes_outputs_first(network, select_best_gate); +/* + if (global.fanout_iterate) { + fanout_est_save_fanin_fanout_indices(network); + } +*/ + if (global.verbose > 1) { + print_po_estimated_arrival_times(network); + } + bin_for_all_nodes_inputs_first(network, bin_free); + free_delay_bucket_storage(); + return 1; +} + + /* some utilities */ + +void bin_for_all_nodes_inputs_first(network,fn) +network_t *network; +VoidFn fn; +{ + int i; + array_t *nodevec; + node_t *node; + + nodevec = network_dfs(network); + for(i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + (*fn)(node); + } + array_free(nodevec); +} + +void bin_for_all_nodes_outputs_first(network,fn) +network_t *network; +VoidFn fn; +{ + int i; + array_t *nodevec; + node_t *node; + + nodevec = network_dfs_from_input(network); + for(i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + (*fn)(node); + } + array_free(nodevec); +} + + + /* INTERNAL INTERFACE */ + + /* HOW delay_bucket_t's ARE USED */ + +/* + * The delay information at a node is stored in BIN(node)->pwl + * This only contains a pwl_delay_t pwl entry (and an area_bucket) + * + * typedef struct delay_bucket_struct { + * lib_gate_t *gate; + * int ninputs; + * node_t **save_binding; + * struct { + * pwl_t *rise; + * pwl_t *fall; + * } pwl; + * delay_bucket_t *next; // used in chain of buckets to free them all + * }; + * + * Once the bucket is computed for that gate, it is added to the pwl stored at + * the node by computing the max of bucket->pwl.rise and bucket->pwl.fall + * and storing the result in the node with bin_delay_compute_pwl_delay_min. + * + * The main trick that makes it all work is that the pwl stored in a bucket contains + * a data field for each segment of the PWL function. And for each segment, + * this data field is just a pointer to the bucket itself. Now, when several + * pwl's are merged using delay_min, only the best segments are saved. + * and their data fields are pointing to the bucket (i.e. the gate info) + * that realizes this minimum for a given load. Simple and elegant. + * + * ATTENTION! The buckets keep the distinction between rise and fall. Not + * the pwl stored at the node. The pwl stored at the node computes the gate + * that has the smallest MAX(rise,fall). Once the gate is selected, we can get + * from the bucket the rise and fall info for that gate. Use bin_delay_compute_pwl_delay for that. + */ + + + /* if the node was obtained from a fanout tree, it should stay mapped the way it is */ + /* we just compute its pwl so that we get an uniform interface for the gate selection part */ + /* otherwise, standard tree mapping stuff apply */ + /* WARNING: a multiple fanout node can be an internal node, a PI or a constant node. */ + +static int +compute_best_match(network) +network_t *network; +{ + lsGen gen; + prim_t *prim; + delay_bucket_t *bucket; + array_t *nodevec; + int i; + node_t *node; +#ifdef SIS + latch_t *latch; +#endif /* SIS */ + + nodevec = network_dfs(network); + for(i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); +#ifdef SIS + if (node->type == PRIMARY_INPUT) continue; + if (node->type == PRIMARY_OUTPUT && !IS_LATCH_END(node)) continue; +#else + if (node->type != INTERNAL) continue; +#endif /* SIS */ + if (node_num_fanin(node) == 0) { + bucket = compute_constant_gate_bucket(node); + bin_delay_update_node_pwl(node, bucket); + continue; + } +#ifdef SIS + latch = NIL(latch_t); + /* set latch type to rising-edge if it is not already set */ + if (IS_LATCH_END(node)) { + latch = latch_from_node(node); + if (latch == NIL(latch_t)) { + (void) sprintf(errmsg, "latch node '%s' has no latch structure\n", + node_name(node)); + error_append(errmsg); + return 0; + } + } +#endif /* SIS */ + lsForeachItem(global.library->patterns, gen, prim) { + gen_all_matches(node, prim, find_best_delay, global.verbose > 5, + global.allow_internal_fanout, global.fanout_limit); + } + if (BIN(node)->pwl->n_points == 0) { +#ifdef SIS + if (latch == NIL(latch_t) || latch_get_type(latch) == ASYNCH) { +#endif /* SIS */ + (void) sprintf(errmsg, + "library error: no gate matches at %s\n", node_name(node)); + error_append(errmsg); + return 0; +#ifdef SIS + } else { + latch_synch_t latch_type; + + /* Synchronous latch - try an opposite polarity latch */ + latch_type = latch_get_type(latch); + switch ((int)latch_type) { + case (int) RISING_EDGE: + latch_set_type(latch, FALLING_EDGE); + break; + case (int) FALLING_EDGE: + latch_set_type(latch, RISING_EDGE); + break; + case (int) ACTIVE_HIGH: + latch_set_type(latch, ACTIVE_LOW); + break; + case (int) ACTIVE_LOW: + latch_set_type(latch, ACTIVE_HIGH); + break; + default: + fail("do_tree_match: bad latch type"); + break; + } + lsForeachItem(global.library->patterns, gen, prim) { + gen_all_matches(node, prim, find_best_delay, global.verbose > 5, + global.allow_internal_fanout, global.fanout_limit); + } + if (BIN(node)->pwl->n_points == 0) { + (void) sprintf(errmsg, + "library error: no latch matches at %s\n", node_name(node)); + error_append(errmsg); + return 0; + } else { + node_t *clock, *new_node, *fanin; + lib_gate_t *inv; + + if (! global.no_warning) + (void)fprintf(siserr, + "warning: no %s type latch matches at %s (opposite polarity latch used)\n", + (latch_type==RISING_EDGE)?"RISING_EDGE": + (latch_type==FALLING_EDGE)?"FALLING_EDGE": + (latch_type==ACTIVE_HIGH)?"ACTIVE_HIGH":"ACTIVE_LOW", node_name(node)); + /* Insert a small inverter at the clock */ + inv = choose_smallest_gate(global.library, "f=!a;"); + clock = latch_get_control(latch); + assert(clock != NIL(node_t) && node_type(clock) == PRIMARY_OUTPUT); + fanin = node_get_fanin(clock, 0); + new_node = node_alloc(); + node_replace(new_node, node_literal(fanin, 0)); + assert(node_patch_fanin(clock, fanin, new_node)); + network_add_node(network, new_node); + map_alloc(new_node); + MAP(new_node)->gate = inv; + MAP(new_node)->map_area = inv->area; + MAP(new_node)->map_arrival.rise = MAP(fanin)->map_arrival.rise; + MAP(new_node)->map_arrival.fall = MAP(fanin)->map_arrival.fall; + MAP(new_node)->ninputs = 1; + MAP(new_node)->save_binding = ALLOC(node_t *, 1); + MAP(new_node)->save_binding[0] = fanin; + } + } +#endif /* SIS */ + } + if (BIN(node)->fanout != NIL(multi_fanout_t)) { + fanout_est_compute_fanout_info(node, &global); + if (global.verbose > 1) { + delay_time_t arrival; + pin_info_t pin_info; + + (void) fprintf(sisout, "node %s: ", node->name); + pin_info.leaf = node; + pin_info.fanout_index = 0; + pin_info.pin_polarity = POLAR_X; + arrival = fanout_est_get_pin_arrival_time(&pin_info, 0.0); + (void) fprintf(sisout, "a(X)=(%2.3f,%2.3f) ", arrival.rise, arrival.fall); + pin_info.pin_polarity = POLAR_Y; + arrival = fanout_est_get_pin_arrival_time(&pin_info, 0.0); + (void) fprintf(sisout, "a(Y)=(%2.3f,%2.3f)\n", arrival.rise, arrival.fall); + } + } + } + array_free(nodevec); + return 1; +} + + /* goes through all the gates corresponding to the prim and record */ + /* their delay information in the BIN(node)->pwl routine */ + /* this means computing the arrival times at the input pins of the prim */ + /* then making a new pwl pair (rise/fall) per gate */ + /* then registrating it in the BIN(node)->pwl */ + /* NOTE: also computes the optimal area and sticks it into MAP entry */ + /* If the network is ANNOTATED already, add the following two modifications: */ + /* (1) if gate has an input pin with a fanout > 1, the gate gets an very large */ + /* arrival time, unless it is the current annotation */ + /* (2) if the gate is a wire, and its input pin or the intermediate node */ + /* has a fanout > 1, the wire gets a very large arrival time */ + +static pin_info_t DEFAULT_PIN_INFO = {{INFINITY, INFINITY}, 0, 0, -1, -1}; + +static int find_best_delay(prim) +prim_t *prim; +{ + int i; + lsGen gen; + lib_gate_t *gate; + node_t *node; + int ninputs; + delay_bucket_t *bucket; + pin_info_t *pin_info; + +#ifdef SIS + /* Make sure that we distinguish between combinational gates and latches. */ + if (seq_filter(prim, global.verbose)) { +#endif /* SIS */ + node = map_prim_get_root(prim); + + /* first make a copy of the input bindings */ + ninputs = prim->ninputs; + pin_info = ALLOC(pin_info_t, ninputs); + for (i = 0; i < ninputs; i++) { + pin_info[i] = DEFAULT_PIN_INFO; + pin_info[i].input = prim->inputs[i]->binding; + fanout_est_get_prim_pin_fanout(prim, i, &pin_info[i]); + } + + /* then try all gates associated to the prim */ + lsForeachItem(prim->gates, gen, gate) { + if (global.verbose > 2) { + (void) fprintf(sisout, "trying gate %s at node %s...\n", gate->name, node->name); + } + if (strcmp(gate->name, "**wire**") == 0) { + bucket = compute_wire_bucket(gate, pin_info[0].input); + } else { + bucket = bin_delay_compute_gate_bucket(gate, ninputs, pin_info); + } + bin_delay_update_node_pwl(node, bucket); + preserve_best_area(&(BIN(node)->area), gate, ninputs, pin_info); + } + FREE(pin_info); +#ifdef SIS + } +#endif /* SIS */ + return 1; +} + + /* computes the optimal area */ + +static void preserve_best_area(bucket, gate, ninputs, pin_info) +area_bucket_t *bucket; +lib_gate_t *gate; +int ninputs; +pin_info_t *pin_info; +{ + int i; + double area = gate->area; + + for (i = 0; i < ninputs; i++) { + area += get_area_from_pin_info(&pin_info[i]); + } + if (area >= bucket->area) return; + bucket->area = area; + bucket->gate = gate; + if (bucket->ninputs > 0) FREE(bucket->save_binding); + bucket->ninputs = ninputs; + if (bucket->ninputs == 0) return; + bucket->save_binding = ALLOC(node_t *, bucket->ninputs); + for (i = 0; i < bucket->ninputs; i++) { + bucket->save_binding[i] = get_input_from_pin_info(&pin_info[i]); + } +} + + /* simply copies the pwl of the source node */ + /* except if there is a node with multiple fanout in the middle */ + /* and some special wire optimization is active */ + /* Wires are forbidden to feed to a multiple fanout point */ + +static delay_bucket_t *compute_wire_bucket(gate, input) +lib_gate_t *gate; +node_t *input; +{ + delay_bucket_t *bucket; + int infinity_flag; + + infinity_flag = (BIN(input)->fanout != NIL(multi_fanout_t)) ? 1 : 0; + bucket = delay_bucket_alloc(WIRE_BUCKET); + bucket->gate = gate; + bucket->ninputs = 1; + bucket->save_binding = ALLOC(node_t *, 1); + bucket->save_binding[0] = input; + bucket->pin_info = ALLOC(pin_info_t, 1); + bucket->pin_info[0] = DEFAULT_PIN_INFO; + if (infinity_flag) { + bucket->pwl.rise = gen_infinitely_slow_pwl(); + } else { + bucket->pwl.rise = pwl_dup(BIN(input)->pwl); + } + bucket->pwl.fall = pwl_dup(bucket->pwl.rise); + return bucket; +} + +static pwl_t *gen_infinitely_slow_pwl() +{ + pwl_point_t point; + + point.x = 0.0; + point.y = INFINITY; + point.slope = INFINITY; + point.data = NIL(char); + return pwl_create_linear_max(1, &point); +} + + /* in case of constant node: starting time is set to 0.0 */ + /* slope and intrinsic is set to 0 */ + /* trust that nodes that are constant have been premapped */ + +static delay_bucket_t *compute_constant_gate_bucket(node) +node_t *node; +{ + delay_bucket_t *bucket; + + assert(MAP(node)->gate != NIL(lib_gate_t)); + bucket = delay_bucket_alloc(CONSTANT_BUCKET); + bucket->gate = MAP(node)->gate; + bucket->pwl.rise = gen_constant_pwl(); + bucket->pwl.fall = gen_constant_pwl(); + pwl_set_data(bucket->pwl.rise, (char *) bucket); + pwl_set_data(bucket->pwl.fall, (char *) bucket); + return bucket; +} + +static pwl_t *gen_constant_pwl() +{ + pwl_point_t point; + + point.x = 0.0; + point.y = 0.0; + point.slope = 0.0; + point.data = NIL(char); + return pwl_create_linear_max(1, &point); +} + + /* compute the pwl delay model at the node for that gate */ + /* The infinity_flag is set only if one of the input pins */ + /* has a fanout > 1 and the network is ANNNOTATED and current gate */ + /* is not the gate used in annotation */ + /* Why not just computing the pwl_delay for pin_node's that are not PI's? */ + /* because of rise and fall delays. The best pwl_delay may be obtained for different gates. */ + /* compute_consistent_pwl_delay guarantees a realizable, if not always optimal, value. */ + /* NOTE: exported to fanout_est.c */ + +delay_bucket_t *bin_delay_compute_gate_bucket(gate, ninputs, pin_info) +lib_gate_t *gate; +int ninputs; +pin_info_t *pin_info; +{ + int i; + double pin_load; + delay_bucket_t *bucket; + + /* alloc a bucket and set it up */ + bucket = delay_bucket_alloc(GATE_BUCKET); + bucket->gate = gate; + bucket->ninputs = ninputs; + bucket->save_binding = ALLOC(node_t *, ninputs); + bucket->pin_info = ALLOC(pin_info_t, ninputs); + + for (i = 0; i < ninputs; i++) { + bucket->save_binding[i] = get_input_from_pin_info(&pin_info[i]); + bucket->pin_info[i] = pin_info[i]; + pin_load = delay_get_load(gate->delay_info[i]); + pin_info[i].arrival = get_arrival_from_pin_info(&pin_info[i], pin_load); + if (global.verbose > 2) { + (void) fprintf(sisout, "pin %d ", i); + (void) fprintf(sisout, "a(%2.3f,%2.3f) l(%2.3f)\n", pin_info[i].arrival.rise, pin_info[i].arrival.fall, pin_load); + } + } + bucket->pwl = bin_delay_compute_gate_pwl(gate, ninputs, pin_info); + pwl_set_data(bucket->pwl.rise, (char *) bucket); + pwl_set_data(bucket->pwl.fall, (char *) bucket); + return bucket; +} + +delay_pwl_t bin_delay_compute_gate_pwl(gate, ninputs, pin_info) +lib_gate_t *gate; +int ninputs; +pin_info_t *pin_info; +{ + int n_points; + delay_pwl_t result; + int i, pt; + pwl_point_t *rise_points, *fall_points; + delay_pin_t *pin_delay, **lib_delay_model; + + /* count the number of points: two points per 'PHASE_NEITHER' pin */ + lib_delay_model = (delay_pin_t **) gate->delay_info; + for (n_points = 0, i = 0; i < ninputs; i++) { + pin_delay = lib_delay_model[i]; + n_points += (pin_delay->phase == PHASE_NEITHER) ? 2 : 1; + } + rise_points = ALLOC(pwl_point_t, n_points); + fall_points = ALLOC(pwl_point_t, n_points); + + /* store info in points; there is no data field at this point */ + for (pt = 0, i = 0; i < ninputs; i++) { + pin_delay = lib_delay_model[i]; + switch(pin_delay->phase) { + case PHASE_INVERTING: + rise_points[pt].x = 0.0; + rise_points[pt].y = pin_info[i].arrival.fall + pin_delay->block.rise; + rise_points[pt].slope = pin_delay->drive.rise; + rise_points[pt].data = NIL(char); + fall_points[pt].x = 0.0; + fall_points[pt].y = pin_info[i].arrival.rise + pin_delay->block.fall; + fall_points[pt].slope = pin_delay->drive.fall; + rise_points[pt].data = NIL(char); + pt++; + break; + case PHASE_NONINVERTING: + rise_points[pt].x = 0.0; + rise_points[pt].y = pin_info[i].arrival.rise + pin_delay->block.rise; + rise_points[pt].slope = pin_delay->drive.rise; + rise_points[pt].data = NIL(char); + fall_points[pt].x = 0.0; + fall_points[pt].y = pin_info[i].arrival.fall + pin_delay->block.fall; + fall_points[pt].slope = pin_delay->drive.fall; + rise_points[pt].data = NIL(char); + pt++; + break; + case PHASE_NEITHER: + rise_points[pt].x = 0.0; + rise_points[pt].y = pin_info[i].arrival.rise + pin_delay->block.rise; + rise_points[pt].slope = pin_delay->drive.rise; + rise_points[pt].data = NIL(char); + fall_points[pt].x = 0.0; + fall_points[pt].y = pin_info[i].arrival.fall + pin_delay->block.fall; + fall_points[pt].slope = pin_delay->drive.fall; + rise_points[pt].data = NIL(char); + pt++; + rise_points[pt].x = 0.0; + rise_points[pt].y = pin_info[i].arrival.fall + pin_delay->block.rise; + rise_points[pt].slope = pin_delay->drive.rise; + rise_points[pt].data = NIL(char); + fall_points[pt].x = 0.0; + fall_points[pt].y = pin_info[i].arrival.rise + pin_delay->block.fall; + fall_points[pt].slope = pin_delay->drive.fall; + rise_points[pt].data = NIL(char); + pt++; + break; + } + } + assert(pt == n_points); + result.rise = pwl_create_linear_max(n_points, rise_points); + result.fall = pwl_create_linear_max(n_points, fall_points); + FREE(rise_points); + FREE(fall_points); + return result; +} + +delay_time_t bin_delay_compute_pwl_delay(pwl, load) +pwl_t *pwl; +double load; +{ + delay_pwl_t delay_pwl; + + delay_pwl = bin_delay_select_active_pwl_delay(pwl, load); + assert(delay_pwl.rise != NIL(pwl_t)); + return bin_delay_compute_delay_pwl_delay(delay_pwl, load); +} + +delay_time_t bin_delay_compute_delay_pwl_delay(pwl, load) +delay_pwl_t pwl; +double load; +{ + pwl_point_t *p_rise; + pwl_point_t *p_fall; + delay_time_t result; + + p_rise = pwl_lookup(pwl.rise, load); + result.rise = pwl_point_eval(p_rise, load); + p_fall = pwl_lookup(pwl.fall, load); + result.fall = pwl_point_eval(p_fall, load); + return result; +} + + /* the pwl given here is associated to a node. */ + /* It contains the MIN of MAX(rise,fall) for each gate matching at that node */ + /* the first thing to do is to find the bucket corresponding to the best gate. */ + /* When this is done, there is two cases left: either the bucket is a gate, so we can go ahead and */ + /* compute the delay directly using the pwl.rise and pwl.fall in that bucket. Or the bucket is a */ + /* wire, and in that case, we continue recursively. Since in the case of a wire, pwl.rise == */ + /* pwl.fall we can simply recur on pwl.rise. */ + +delay_pwl_t bin_delay_select_active_pwl_delay(pwl, load) +pwl_t *pwl; +double load; +{ + pwl_point_t *point; + delay_bucket_t *bucket; + + point = pwl_lookup(pwl, load); + bucket = (delay_bucket_t *) pwl_point_data(point); + switch (bucket->type) { + case GATE_BUCKET: + case PI_BUCKET: + case CONSTANT_BUCKET: + return bucket->pwl; + case WIRE_BUCKET: + return bin_delay_select_active_pwl_delay(bucket->pwl.rise, load); + default: + fail("unexpected bucket type"); + /* NOTREACHED */ + } +} + + + /* given a new bucket, add the gate instance delay info to what is there in the node already */ + /* trivial, except for the debugging print outs really. */ + +void bin_delay_update_node_pwl(node, bucket) +node_t *node; +delay_bucket_t *bucket; +{ + pwl_t *max_pwl, *min_pwl; + + max_pwl = get_bucket_pwl_max(bucket); + min_pwl = pwl_min(BIN(node)->pwl, max_pwl); + if (global.verbose > 2) { + (void) fprintf(sisout, "new rise = "); + pwl_print(sisout, bucket->pwl.rise, delay_bucket_print); + (void) fprintf(sisout, "new fall = "); + pwl_print(sisout, bucket->pwl.fall, delay_bucket_print); + (void) fprintf(sisout, "max rise & fall = "); + pwl_print(sisout, max_pwl, delay_bucket_print); + (void) fprintf(sisout, "old = "); + pwl_print(sisout, BIN(node)->pwl, delay_bucket_print); + (void) fprintf(sisout, "new = "); + pwl_print(sisout, min_pwl, delay_bucket_print); + } + pwl_free(BIN(node)->pwl); + pwl_free(max_pwl); + BIN(node)->pwl = min_pwl; +} + + /* given the delay info at a bucket, produce a pwl that is the max */ + /* of the rise and fall info at that bucket */ + /* make sure that the max_pwl contains a pointer back to the bucket */ + /* we cannot put that pointer in bucket->pwl.{rise,fall} because */ + /* it would not work for wires: we need to keep back the info of gate origin */ + /* the pwl at a WIRE_BUCKET is just the copy of the BIN(node)->pwl of its input */ + /* thus there is no need to compute a max or sum. */ + +static pwl_t *get_bucket_pwl_max(bucket) +delay_bucket_t *bucket; +{ + pwl_t *max_pwl; + + if (bucket->type == WIRE_BUCKET) { + max_pwl = pwl_dup(bucket->pwl.rise); + } else if (global.cost_function == 0) { + max_pwl = pwl_max(bucket->pwl.rise, bucket->pwl.fall); + } else { + max_pwl = pwl_sum(bucket->pwl.rise, bucket->pwl.fall); + } + pwl_set_data(max_pwl, (char *) bucket); + return max_pwl; +} + +static void delay_bucket_print(fp, bucket) +FILE *fp; +delay_bucket_t *bucket; +{ + int i; + + if (bucket == NIL(delay_bucket_t)) { + (void) fprintf(fp, "--"); + } else if (bucket->type == PI_BUCKET) { + /* do nothing */ + } else { + (void) fprintf(fp, "gate=%s [", bucket->gate->name); + for (i = 0; i < bucket->ninputs; i++) { + (void) fprintf(fp, "%s ", bucket->save_binding[i]->name); + } + (void) fprintf(fp, "] 0x%x 0x%x", (int) bucket->pwl.rise, (int) bucket->pwl.fall); + } +} + + + /* GATE_SELECTION */ + + /* where the final selection of gates takes place */ + /* go through the network and select the best gates, given the loads */ + /* at the outputs. Put the resulting selection into the MAP fields */ + /* a node participates if root or pin of a final gate */ + /* otherwise its load stays to INFINITY and we can ignore it */ + +static void select_best_gate(node) +node_t *node; +{ + double load; + pwl_point_t *point; + delay_bucket_t *bucket; + node_function_t node_fn; + + if (BIN(node)->visited == 0) { + if (MAP(node)->gate != NIL(lib_gate_t)) { + MAP(node)->gate = NIL(lib_gate_t); + MAP(node)->ninputs = 0; + FREE(MAP(node)->save_binding); + MAP(node)->save_binding = NIL(node_t *); + } + return; + } + node_fn = node_function(node); + if (node_fn == NODE_0 || node_fn == NODE_1) return; + if (node_fn == NODE_PO) { + copy_bucket_to_map(node, NIL(delay_bucket_t)); + if (global.verbose > 1) map_report_node_data(node); + return; + } + if (node_fn == NODE_PI) { + if (global.verbose > 1) map_report_node_data(node); + return; + } + if (BIN(node)->fanout != NIL(multi_fanout_t)) { + load = BIN(node)->fanout->loads[BIN(node)->fanout->polarity]; + } else { + load = MAP(node)->load; + } + point = pwl_lookup(BIN(node)->pwl, load); + bucket = (delay_bucket_t *) pwl_point_data(point); + copy_bucket_to_map(node, bucket); + assert(MAP(node)->gate != NIL(lib_gate_t)); + if (global.verbose > 1) map_report_node_data(node); + increment_input_loads(node, bucket); +} + +/* install into MAP fields contents of selected bucket */ + +static void copy_bucket_to_map(node, bucket) +node_t *node; +delay_bucket_t *bucket; +{ + int i; + int n_inputs; + pin_info_t pin_info; + + n_inputs = (node->type == PRIMARY_OUTPUT) ? 1 : bucket->ninputs; + if (n_inputs > 0) { + if (MAP(node)->pin_info != NIL(fanin_fanout_t)) { + FREE(MAP(node)->pin_info); + MAP(node)->pin_info = NIL(fanin_fanout_t); + } + MAP(node)->pin_info = ALLOC(fanin_fanout_t, n_inputs); + } + + if (node->type == PRIMARY_OUTPUT) { + pin_info.input = node; + fanout_est_get_prim_pin_fanout(NIL(prim_t), 0, &pin_info); + MAP(node)->pin_info[0].pin_source = pin_info.leaf; + MAP(node)->pin_info[0].fanout_index = pin_info.fanout_index; + return; + } + + MAP(node)->gate = bucket->gate; + MAP(node)->map_arrival = bin_delay_compute_pwl_delay(BIN(node)->pwl, MAP(node)->load); + MAP(node)->ninputs = bucket->ninputs; + if (MAP(node)->save_binding != NIL(node_t *)) { + FREE(MAP(node)->save_binding); + } + if (bucket->ninputs > 0) { + MAP(node)->save_binding = ALLOC(node_t *, bucket->ninputs); + } + for (i = 0; i < bucket->ninputs; i++) { + MAP(node)->save_binding[i] = bucket->save_binding[i]; + BIN(bucket->save_binding[i])->visited = 1; + MAP(node)->pin_info[i].pin_source = bucket->pin_info[i].leaf; + MAP(node)->pin_info[i].fanout_index = bucket->pin_info[i].fanout_index; + } +} + +static void increment_input_loads(node, bucket) +node_t *node; +delay_bucket_t *bucket; +{ + int pin; + node_t *fanin; + +/* + * multiple fanout node: if best match is inverter, take the right load + * only case when node has n_fanouts > 1 and node is NODE_Y and node mapped as inverter + */ + + if (BIN(node)->fanout != NIL(multi_fanout_t) && bucket->ninputs == 1) { + assert(BIN(node)->fanout->polarity == POLAR_Y); + fanin = bucket->save_binding[0]; + if (fanin == MAP(node)->fanout_source) { + MAP(fanin)->load = BIN(node)->fanout->loads[POLAR_X]; + } else { + MAP(fanin)->load = delay_get_load(bucket->gate->delay_info[0]); + } + return; + } + +/* + * if we allow logic duplication and this node is a multiple fanout node + * we should make sure that the load of the other source is selected properly. + * This is only necessary when the node is not a constant or a PRIMARY_INPUT. + * A node cannot be a PRIMARY_INPUT or a constant here: should have been caught earlier. + */ + + if (BIN(node)->fanout != NIL(multi_fanout_t) && global.allow_duplication) { + assert(BIN(node)->fanout->polarity == POLAR_Y); + assert(BIN(node)->fanout->best_is_inverter); + fanin = node_get_fanin(node, 0); + MAP(fanin)->load = BIN(node)->fanout->loads[POLAR_X]; + return; + } + + /* wire: take the load at the node and propagate it through */ + if (bucket->ninputs == 1 && strcmp(bucket->gate->name, "**wire**") == 0) { + fanin = bucket->save_binding[0]; + MAP(fanin)->load += MAP(node)->load; + return; + } + + /* case of a complex gate */ + for (pin = 0; pin < bucket->ninputs; pin++) { + fanin = bucket->save_binding[pin]; + MAP(fanin)->load += delay_get_load(bucket->gate->delay_info[pin]); + } +} + + /* would be nice to have this arbitrary delay model at PI's */ + /* right now, we simply have a single point */ + +static void bin_init_pi(node) +node_t *node; +{ + delay_bucket_t *bucket; + + bucket = delay_bucket_alloc(PI_BUCKET); + bucket->pwl = bin_delay_get_pi_delay_pwl(node); + pwl_set_data(bucket->pwl.rise, (char *) bucket); + pwl_set_data(bucket->pwl.fall, (char *) bucket); + bin_delay_update_node_pwl(node, bucket); +} + +delay_pwl_t bin_delay_get_pi_delay_pwl(node) +node_t *node; +{ + delay_pwl_t result; + pwl_point_t rise_point; + pwl_point_t fall_point; + delay_time_t drive, arrival; + + assert(node->type == PRIMARY_INPUT); + drive = pipo_get_pi_drive(node); + arrival = pipo_get_pi_arrival(node); + rise_point.x = 0.0; + rise_point.y = arrival.rise; + rise_point.slope = drive.rise; + rise_point.data = NIL(char); + fall_point.x = 0.0; + fall_point.y = arrival.fall; + fall_point.slope = drive.fall; + fall_point.data = NIL(char); + result.rise = pwl_create_linear_max(1, &rise_point); + result.fall = pwl_create_linear_max(1, &fall_point); + return result; +} + + + /* MEMORY ALLOCATION ROUTINES */ + +static bin_t DEFAULT_BIN_STRUCT = {0, {0, 0, 0, 0.0}, 0, 0}; +static fanout_leaf_t DEFAULT_FANOUT_LEAF = {INFINITY, 0}; + + /* should be visited inputs first */ + /* the load is set to infinite unless the network is annotated */ + /* the node has multiple fanout and is mapped */ + +static void bin_alloc(node) +node_t *node; +{ + int i; + int p; + node_t *fanin; + node_t *fanout; + int n_fanouts; + node_function_t type; + + /* fanout consistency check */ + if (node_num_fanout(node) > 1 && node_num_fanin(node) > 0) { + assert(node_function(node) == NODE_INV); + fanin = node_get_fanin(node, 0); + type = node_function(fanin); + assert(type == NODE_PI || type == NODE_0 || type == NODE_1 || type == NODE_OR || type == NODE_AND); + } + + node->BIN_SLOT = (char *) ALLOC(bin_t, 1); + *(BIN(node)) = DEFAULT_BIN_STRUCT; + BIN(node)->pwl = pwl_create_empty(); + + MAP(node)->load = 0.0; + + /* take care of PO's first */ + if (node->type == PRIMARY_OUTPUT) { + BIN(node)->visited = 1; + MAP(node)->load = pipo_get_po_load(node); + fanin = node_get_fanin(node, 0); + BIN(fanin)->visited = 1; + MAP(fanin)->load += MAP(node)->load; + return; + } + + /* take care of PI's first: beware, a PI may have n_fanouts > 1 */ + if (node->type == PRIMARY_INPUT) { + bin_init_pi(node); + } + + /* take care of nodes with n_fanouts > 1 */ + n_fanouts = node_num_fanout(node); + if (n_fanouts > 1) { + BIN(node)->fanout = ALLOC(multi_fanout_t, 1); + BIN(node)->fanout->best_is_inverter = 0; + BIN(node)->fanout->n_fanouts = n_fanouts; + BIN(node)->fanout->buckets = NIL(fanout_bucket_t); + BIN(node)->fanout->index_table = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 0; i < n_fanouts; i++) { + fanout = node_get_fanout(node, i); + st_insert(BIN(node)->fanout->index_table, (char *) fanout, (char *) i); + } + BIN(node)->fanout->loads[POLAR_X] = INFINITY; + BIN(node)->fanout->loads[POLAR_Y] = INFINITY; + BIN(node)->fanout->polarity = (node_num_fanin(node) == 0) ? POLAR_X : POLAR_Y; + foreach_polarity(p) { + BIN(node)->fanout->leaves[p] = ALLOC(fanout_leaf_t, n_fanouts); + for (i = 0; i < n_fanouts; i++) { + BIN(node)->fanout->leaves[p][i] = DEFAULT_FANOUT_LEAF; + } + } + } +} + + /* the delay_bucket_t are freed elsewhere */ + +static void bin_free(node) +node_t *node; +{ + int p; + + pwl_free(BIN(node)->pwl); + if (BIN(node)->area.ninputs > 0) { + FREE(BIN(node)->area.save_binding); + } + if (BIN(node)->fanout) { + fanout_est_free_fanout_info(node); + st_free_table(BIN(node)->fanout->index_table); + foreach_polarity(p) { + FREE(BIN(node)->fanout->leaves[p]); + } + FREE(BIN(node)->fanout); + } + FREE(node->BIN_SLOT); + node->BIN_SLOT = NIL(char); +} + + /* need some way to allocate and free the buckets with gate information */ + +static delay_bucket_t *global_head_bucket; +static void init_delay_bucket_storage() +{ + global_head_bucket = NIL(delay_bucket_t); +} + +static void free_delay_bucket_storage() +{ + delay_bucket_t *head; + delay_bucket_t *next; + + for (head = global_head_bucket; head != NIL(delay_bucket_t); head = next) { + pwl_free(head->pwl.rise); + pwl_free(head->pwl.fall); + if (head->ninputs > 0) { + FREE(head->save_binding); + } + if (head->pin_info != NIL(pin_info_t)) { + FREE(head->pin_info); + } + next = head->next; + FREE(head); + } +} + +static delay_bucket_t *delay_bucket_alloc(type) +delay_bucket_type_t type; +{ + delay_bucket_t *bucket; + + bucket = ALLOC(delay_bucket_t, 1); + bucket->type = type; + bucket->pwl.rise = NIL(pwl_t); + bucket->pwl.fall = NIL(pwl_t); + bucket->gate = NIL(lib_gate_t); + bucket->ninputs = 0; + bucket->save_binding = NIL(node_t *); + bucket->pin_info = NIL(pin_info_t); + bucket->next = global_head_bucket; + global_head_bucket = bucket; + return bucket; +} + +static void print_po_estimated_arrival_times(network) +network_t *network; +{ + lsGen gen; + node_t *node; + + foreach_primary_output(network, gen, node) { + map_report_node_data(node); + } +} + + /* if no multiple fanout, no problem */ + /* if multiple fanout and signal of polarity POLAR_Y */ + /* (but convention, polarity of multiple fanout point) */ + /* then return the multiple fanout point */ + /* For POLAR_X signals, it depends. If multiple fanout point */ + /* is going to be implemented as an inverter, then can take its fanin */ + /* otherwise, we take the corresponding fanout */ + +static node_t *get_input_from_pin_info(pin_info) +pin_info_t *pin_info; +{ + if (pin_info->leaf == NIL(node_t)) { + return pin_info->input; + } else if (pin_info->pin_polarity == BIN(pin_info->leaf)->fanout->polarity) { + return pin_info->leaf; + } else if (BIN(pin_info->leaf)->fanout->best_is_inverter) { + return node_get_fanin(pin_info->leaf, 0); + } else { + return node_get_fanout(pin_info->leaf, pin_info->fanout_index); + } +} + +static double get_area_from_pin_info(pin_info) +pin_info_t *pin_info; +{ + if (pin_info->leaf == NIL(node_t)) { + return BIN(pin_info->input)->area.area; + } else { + return BIN(pin_info->leaf)->area.area / BIN(pin_info->leaf)->fanout->n_fanouts; + } +} + +static delay_time_t get_arrival_from_pin_info(pin_info, load) +pin_info_t *pin_info; +double load; +{ + if (pin_info->leaf == NIL(node_t)) { + return bin_delay_compute_pwl_delay(BIN(pin_info->input)->pwl, load); + } else { + return fanout_est_get_pin_arrival_time(pin_info, load); + } +} + +#ifdef SIS +/* After initial mapping, the function associated with + * latches are temporarily stored at PO/latch-input nodes. + * Now create an extra buffer node to move the func info to. + * Also modify the fanout of the new node + * such that it points to the real PO. + * Before: (internal node) -> real PO (no func) + * -> PO/latch-input (has latch func) + * -> PO/latch-input (has latch func) + * ... + * After: (internal node) -> real PO (no func) + * -> (internal node - has latch func) -> PO/latch-input (no func) + * -> (internal node - has latch func) -> PO/latch-input (no func) + * ... + */ +static void +hack_po(network) +network_t *network; +{ + lsGen gen; + node_t *po, *fanin, *new_node; + int i; + latch_t *latch; + + foreach_latch(network, gen, latch) { + po = latch_get_input(latch); + fanin = node_get_fanin(po, 0); + new_node = node_alloc(); + node_replace(new_node, node_literal(fanin, 1)); + assert(node_patch_fanin(po, fanin, new_node)); + network_add_node(network, new_node); + /* PO derives its output from its fanin node */ + /* Swap names to preserve the IO names*/ + network_swap_names(network, new_node, fanin); + map_alloc(new_node); + bin_alloc(new_node); + BIN(new_node)->pwl = pwl_dup(BIN(po)->pwl); + BIN(new_node)->area.gate = BIN(po)->area.gate; + BIN(new_node)->area.ninputs = BIN(po)->area.ninputs; + BIN(new_node)->area.save_binding = ALLOC(node_t *, BIN(po)->area.ninputs); + for (i = 0; i < BIN(po)->area.ninputs; i++) { + BIN(new_node)->area.save_binding[i] = BIN(po)->area.save_binding[i]; + } + BIN(new_node)->area.area = BIN(po)->area.area; + BIN(new_node)->visited = 1; + } +} +#endif /* SIS */ diff --git a/sis/map/bin_delay_static.h b/sis/map/bin_delay_static.h new file mode 100644 index 0000000..fbcd0df --- /dev/null +++ b/sis/map/bin_delay_static.h @@ -0,0 +1,33 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/bin_delay_static.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)bin_delay_static.h 1.3 */ +/* last modified on 5/2/91 at 17:24:39 */ +static delay_bucket_t *compute_constant_gate_bucket(); +static delay_bucket_t *compute_wire_bucket(); +static delay_bucket_t *delay_bucket_alloc(); +static delay_time_t get_arrival_from_pin_info(); +static double get_area_from_pin_info(); +static int find_best_delay(); +static node_t *get_input_from_pin_info(); +static pwl_t *gen_constant_pwl(); +static pwl_t *gen_infinitely_slow_pwl(); +static pwl_t *get_bucket_pwl_max(); +static void bin_alloc(); +static void bin_free(); +static void bin_init_pi(); +static int compute_best_match(); +static void copy_bucket_to_map(); +static void delay_bucket_print(); +static void free_delay_bucket_storage(); +static void increment_input_loads(); +static void init_delay_bucket_storage(); +static void preserve_best_area(); +static void print_po_estimated_arrival_times(); +static void select_best_gate(); diff --git a/sis/map/bin_int.h b/sis/map/bin_int.h new file mode 100644 index 0000000..c5581b1 --- /dev/null +++ b/sis/map/bin_int.h @@ -0,0 +1,111 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/bin_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)bin_int.h 1.3 */ +/* last modified on 5/14/91 at 23:07:37 */ +#ifndef BIN_INT_H +#define BIN_INT_H + + /* historically, for binned load values; now we use PWL's */ + +#define BIN_SLOT bin +#define BIN(node) ((bin_t *) (node)->BIN_SLOT) + +#include "pwl.h" + +typedef struct { + delay_time_t arrival; + node_t *input; + node_t *leaf; + int fanout_index; + int pin_polarity; +} pin_info_t; + +typedef enum { + WIRE_BUCKET, + GATE_BUCKET, + PI_BUCKET, + CONSTANT_BUCKET +} delay_bucket_type_t; + +typedef struct delay_bucket_struct delay_bucket_t; +struct delay_bucket_struct { + delay_bucket_type_t type; + lib_gate_t *gate; + int ninputs; + node_t **save_binding; + pin_info_t *pin_info; + delay_pwl_t pwl; + delay_bucket_t *next; /* used in chain of buckets to free them all */ +}; + +typedef struct { + lib_gate_t *gate; + int ninputs; + node_t **save_binding; + double area; +} area_bucket_t; + + /* fanout_bucket_t contains the information related to buffers in a fanout tree that are in direct */ + /* contact with leaves. The load at those buffers is the total load the buffer is expected to drive. */ + +typedef struct fanout_bucket_struct fanout_bucket_t; +struct fanout_bucket_struct { + double load; /* total load expected on that output terminal */ + delay_pwl_t pwl; /* delay info associated with that output terminal */ + fanout_bucket_t *next; /* for allocation/deallocation*/ +}; + +typedef struct { + double load; /* the load of an entry is the expected load at the corresponding leaf */ + fanout_bucket_t *bucket; /* point to entry in ../fanout_buckets */ +} fanout_leaf_t; + +#include "fanout_int.h" + +typedef struct { + int n_fanouts; + fanout_bucket_t *buckets; /* pointer to list of buckets allocated for that instance */ + fanout_leaf_t *leaves[POLAR_MAX]; /* [POLARITY(2)][n_fanouts] */ + double loads[POLAR_MAX]; /* the load at these sources (est.) */ + st_table *index_table; /* takes a fanout of this node, returns its fanout_index */ + int best_is_inverter; /* flag set if choice of gate at multi fanout point is an inverter */ + int polarity; /* polarity of this multiple fanout node (POLAR_X iff nfanin==0) */ +} multi_fanout_t; + +typedef struct { + pwl_t *pwl; + area_bucket_t area; + multi_fanout_t *fanout; + int visited; +} bin_t; + + /* from bin_delay.c */ + +extern delay_bucket_t *bin_delay_compute_gate_bucket(/* lib_gate_t *gate; int ninputs; pin_info_t *pin_info; */); +extern delay_pwl_t bin_delay_compute_gate_pwl(/* lib_gate_t *gate; int ninputs; pin_info_t *pin_info; */); +extern void bin_delay_update_node_pwl(/* node_t *node, delay_bucket_t *bucket */); +extern delay_time_t bin_delay_compute_pwl_delay(/* pwl_t *pwl; double load; */); +extern delay_pwl_t bin_delay_select_active_pwl_delay(/* pwl_t *pwl; double load; */); +extern void bin_delay_update_node_pwl(/* node_t *node; delay_bucket_t *bucket; */); +extern delay_pwl_t bin_delay_get_pi_delay_pwl(/* node_t *node; */); +extern delay_time_t bin_delay_compute_pwl_delay(/* pwl_t *pwl, double load */); +extern delay_time_t bin_delay_compute_delay_pwl_delay(/* delay_pwl_t pwl, double load */); + + + /* from fanout_est.c */ + +extern void fanout_est_get_prim_pin_fanout(/* prim_t *prim; int pin; pin_info_t *pin_info; */); +extern void fanout_est_compute_fanout_info(/* node_t *node; */); +extern fanout_bucket_t *fanout_est_fanout_bucket_alloc(/* multi_fanout_t *fanout */); +extern void fanout_est_free_fanout_info(/* node_t *node; */); +extern delay_time_t fanout_est_get_pin_arrival_time(/* pin_info_t *pin_info; double pin_load; */); + + +#endif /* BIN_INT_H */ diff --git a/sis/map/bottom_up.c b/sis/map/bottom_up.c new file mode 100644 index 0000000..7f62c3c --- /dev/null +++ b/sis/map/bottom_up.c @@ -0,0 +1,389 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/bottom_up.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)bottom_up.c 1.7 */ +/* last modified on 7/2/91 at 19:44:14 */ +/** +** MODIFICATION HISTORY: +** +** 01 27-May-91 klk New code to create a buffer tree that satisfies the fanout limit +** using the bottom_up algorithm. +** 01 10-Jun-91 klk Fixed a bug in the function build_tree_folim_bottom_up_rec(). +**/ +/* + * $Log: bottom_up.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:24 pchong + * imported + * + * Revision 1.2 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.2 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.1 1992/04/17 21:47:50 sis + * Initial revision + * + * Revision 1.1 1992/04/17 21:47:50 sis + * Initial revision + * + * Revision 1.1 92/01/08 17:40:31 sis + * Initial revision + * + * Revision 1.2 91/07/02 10:48:32 touati + * remove Pani's changes. Have been made global to all algorithms. + * + * Revision 1.1 91/06/28 14:48:00 touati + * Initial revision + * +*/ + + + +#include "sis.h" +#include <math.h> +#include "fanout_int.h" +#include "fanout_delay.h" + + +/* A node in the buffer tree data structure for the bottom_up algorithm */ +typedef struct bottom_up_struct bottom_up_t; +struct bottom_up_struct { + delay_time_t required; /* Required time at the source node of the tree */ + double area; /* area of the buffer */ + int gate_index; /* Index of the buffer in the library */ + array_t *children; /* Children of the node in the buffer tree */ + gate_link_t *link; /* Pointer to a sink node for a leaf node in the buffer tree */ +}; + +static bottom_up_t *build_tree_bottom_up_rec(); +static bottom_up_t *create_tree_node(); +static int bottom_up_optimize(); +static int compute_sink_index(); +static int get_polarity_with_latest_req_time(); +static st_table *fanout_info_extract(); +static void build_tree_bottom_up(); +static void create_node_for_sink(); +static void put_tree_in_fanout_tree_order(); +static void select_best_subgroup(); + + + /* CONTENTS */ + + /* Bottom up fanout optimization derived from combinational merging */ + +static n_gates_t n_gates; + + + /* EXTERNAL INTERFACE */ + + /* ARGSUSED */ +void bottom_up_init(network, alg) +network_t *network; +fanout_alg_t *alg; +{ + alg->optimize = bottom_up_optimize; +} + + + /* INTERNAL INTERFACE */ + +static int bottom_up_optimize(fanout_info, tree, cost) +opt_array_t *fanout_info; /* fanout_info[POLAR_X] lists the positive polarity sinks; POLAR_Y negative */ +array_t *tree; /* array in which the result tree is stored: format of fanout_tree.c */ +fanout_cost_t *cost; /* contains information on the result: required times, area */ +{ + int source_index; + array_t *local_tree, *best_tree; + fanout_cost_t local_cost; + + n_gates = fanout_delay_get_n_gates(); + cost->slack = MINUS_INFINITY; + cost->area = INFINITY; + best_tree = fanout_tree_alloc(); + foreach_source(n_gates, source_index) { + local_tree = fanout_tree_alloc(); + build_tree_bottom_up(fanout_info, source_index, local_tree, &local_cost); + if (GETMIN(cost->slack) < GETMIN(local_cost.slack)) { + array_free(best_tree); + best_tree = local_tree; + *cost = local_cost; + } else { + array_free(local_tree); + } + } + fanout_tree_copy(tree, best_tree); + array_free(best_tree); + return 1; +} + + +static void build_tree_bottom_up(fanout_info, source_index, tree, cost) +opt_array_t *fanout_info; +int source_index; +array_t *tree; +fanout_cost_t *cost; +{ + int i, p; + bottom_up_t *root, *node; + gate_link_t *link; + st_generator *gen; + st_table *table = st_init_table(st_numcmp, st_numhash); + + foreach_polarity(p) { + for (i = 0; i < fanout_info[p].n_elts; i++) { + link = array_fetch(gate_link_t *, fanout_info[p].required, i); + create_node_for_sink(link, table); + } + } + root = build_tree_bottom_up_rec(fanout_info, source_index, table); + cost->slack = root->required; + cost->area = root->area; + put_tree_in_fanout_tree_order(tree, root); + st_foreach_item(table, gen, (char **) &link, (char **) &node) { + assert(link == node->link); + if (link->node == NIL(node_t)) FREE(link); + array_free(node->children); + FREE(node); + } + st_free_table(table); +} + +static bottom_up_t *build_tree_bottom_up_rec(fanout_info, source_index, table) +opt_array_t *fanout_info; +int source_index; +st_table *table; +{ + int p, q; + int source_polarity; + int buffer_index, sink_index; + int no_buffer_ok; + bottom_up_t *node, *result; + opt_array_t new_fanout_info[2]; + + /* if only one output left, put it on the source node and terminate */ + source_polarity = fanout_delay_get_source_polarity(source_index); + p = source_polarity; + q = POLAR_INV(p); + if (fanout_info[p].n_elts == 1 && fanout_info[q].n_elts == 0) { + return create_tree_node(&fanout_info[p], 0, source_index, table); + } + + /* otherwise, determine which polarity to use next (latest req. time) */ + p = get_polarity_with_latest_req_time(fanout_info); + q = POLAR_INV(p); + + /* select the best group of late required and corresponding buffer_index */ + no_buffer_ok = (source_polarity == p && fanout_info[q].n_elts == 0); + select_best_subgroup(&fanout_info[p], source_index, no_buffer_ok, &buffer_index, &sink_index); + if (buffer_index == -1) { + assert(p == source_polarity && fanout_info[q].n_elts == 0); + return create_tree_node(&fanout_info[p], 0, source_index, table); + } + + /* if still work to do: create new_fanout_info properly, function of buffer polarity */ + node = create_tree_node(&fanout_info[p], sink_index, buffer_index, table); + if (is_inverter(n_gates, buffer_index)) { + new_fanout_info[p].links = fanout_info_extract(&fanout_info[p], 0, sink_index); + fanout_info_preprocess(&new_fanout_info[p]); + new_fanout_info[q].links = fanout_info_extract(&fanout_info[q], 0, fanout_info[q].n_elts); + st_insert(new_fanout_info[q].links, (char *) node->link, NIL(char)); + fanout_info_preprocess(&new_fanout_info[q]); + } else { + new_fanout_info[p].links = fanout_info_extract(&fanout_info[p], 0, sink_index); + st_insert(new_fanout_info[p].links, (char *) node->link, NIL(char)); + fanout_info_preprocess(&new_fanout_info[p]); + new_fanout_info[q].links = fanout_info_extract(&fanout_info[q], 0, fanout_info[q].n_elts); + fanout_info_preprocess(&new_fanout_info[q]); + } + result = build_tree_bottom_up_rec(new_fanout_info, source_index, table); + foreach_polarity (p) { fanout_info_free(&new_fanout_info[p], 0); } + return result; +} + + /* best_sink: [best_sink,n_elts-1] are under the new node */ + +static void select_best_subgroup(fanout_info, source_index, no_buffer_ok, best_buffer, best_sink) +opt_array_t *fanout_info; +int source_index; +int no_buffer_ok; +int *best_buffer; +int *best_sink; +{ + int buffer_index; + int k, best_k; + int local_sink; + double load, local_load; + delay_time_t best_required, local_required; + + load = fanout_info->total_load + map_compute_wire_load(fanout_info->n_elts); + *best_buffer = -1; + best_required = MINUS_INFINITY; + foreach_buffer(n_gates, buffer_index) { + if (fanout_info->n_elts == 1 && ! is_inverter(n_gates, buffer_index)) continue; + k = compute_best_number_of_inverters(source_index, buffer_index, load, fanout_info->n_elts); + local_sink = compute_sink_index(fanout_info, k); + local_load = fanout_info->total_load - fanout_info->cumul_load[local_sink]; + local_load += map_compute_wire_load(fanout_info->n_elts - local_sink); + local_required = fanout_info->min_required[local_sink]; + local_required = fanout_delay_backward_load_dependent(local_required, buffer_index, local_load); + local_required = fanout_delay_backward_intrinsic(local_required, buffer_index); + local_load = fanout_delay_get_buffer_load(buffer_index) * k; + local_load += map_compute_wire_load(k); + local_required = fanout_delay_backward_load_dependent(local_required, source_index, local_load); + if (GETMIN(best_required) < GETMIN(local_required)) { + best_k = k; + best_required = local_required; + *best_buffer = buffer_index; + *best_sink = local_sink; + } + } + if (no_buffer_ok && best_k == 1) { + assert(*best_sink == 0); + local_load = load; + local_required = fanout_info->min_required[0]; + local_required = fanout_delay_backward_load_dependent(local_required, source_index, local_load); + if (GETMIN(best_required) < GETMIN(local_required)) { + *best_buffer = -1; + *best_sink = 0; + } + } +} + + /* guarantees a reasonable level of progress */ + /* should at least take two sinks */ + +static int compute_sink_index(fanout_info, k) +opt_array_t *fanout_info; +int k; +{ + int i; + double load; + double load_threshold = fanout_info->total_load / k; + + assert(fanout_info->n_elts > 0); + if (fanout_info->n_elts == 1) return 0; + for (i = fanout_info->n_elts - 2; i >= 0; i--) { + load = fanout_info->total_load - fanout_info->cumul_load[i]; + if (load > load_threshold) + return i; + } + return 0; +} + +static st_table *fanout_info_extract(fanout_info, from, to) +opt_array_t *fanout_info; +int from; +int to; +{ + int i; + gate_link_t *link; + st_table *result = st_init_table(st_numcmp, st_numhash); + + for (i = from; i < to; i++) { + link = array_fetch(gate_link_t *, fanout_info->required, i); + st_insert(result, (char *) link, NIL(char)); + } + return result; +} + +static void put_tree_in_fanout_tree_order(tree, root) +array_t *tree; +bottom_up_t *root; +{ + int i; + bottom_up_t *node; + + if (array_n(root->children) == 0) { + fanout_tree_insert_sink(tree, root->link); + } else { + fanout_tree_insert_gate(tree, root->gate_index, array_n(root->children)); + for (i = 0; i < array_n(root->children); i++) { + node = array_fetch(bottom_up_t *, root->children, i); + put_tree_in_fanout_tree_order(tree, node); + } + } +} + +static bottom_up_t *create_tree_node(fanout_info, sink_index, source_index, table) +opt_array_t *fanout_info; +int sink_index; +int source_index; +st_table *table; +{ + int i; + double area; + double load; + delay_time_t required; + gate_link_t *link; + bottom_up_t *child; + bottom_up_t *result = ALLOC(bottom_up_t, 1); + + /* first, the gate_link_t */ + link = result->link = ALLOC(gate_link_t, 1); + link->node = NIL(node_t); + link->pin = -1; + required = fanout_info->min_required[sink_index]; + load = fanout_info->total_load - fanout_info->cumul_load[sink_index]; + load += map_compute_wire_load(fanout_info->n_elts - sink_index); + required = fanout_delay_backward_load_dependent(required, source_index, load); + if (is_buffer(n_gates, source_index)) { + link->required = fanout_delay_backward_intrinsic(required, source_index); + link->load = fanout_delay_get_buffer_load(source_index); + } else { + link->required = required; + link->load = 0.0; + } + + /* now, the node itself */ + result->required = result->link->required; + result->children = array_alloc(bottom_up_t *, 0); + area = 0.0; + for (i = sink_index; i < fanout_info->n_elts; i++) { + link = array_fetch(gate_link_t *, fanout_info->required, i); + assert(st_lookup(table, (char *) link, (char **) &child)); + array_insert_last(bottom_up_t *, result->children, child); + area += child->area; + } + result->gate_index = source_index; + result->area = area + fanout_delay_get_area(source_index); + st_insert(table, (char *) result->link, (char *) result); + return result; +} + +static void create_node_for_sink(link, table) +gate_link_t *link; +st_table *table; +{ + bottom_up_t *result = ALLOC(bottom_up_t, 1); + + result->link = link; + result->required = link->required; + result->area = 0.0; + result->children = array_alloc(bottom_up_t *, 0); + result->gate_index = -1; + st_insert(table, (char *) link, (char *) result); +} + +static int get_polarity_with_latest_req_time(fanout_info) +opt_array_t *fanout_info; +{ + int p, q; + gate_link_t *link; + delay_time_t required[2]; + + assert(fanout_info[POLAR_X].n_elts != 0 || fanout_info[POLAR_Y].n_elts != 0); + foreach_polarity(p) { + q = POLAR_INV(p); + if (fanout_info[p].n_elts == 0) return q; + link = array_fetch(gate_link_t *, fanout_info[p].required, fanout_info[p].n_elts - 1); + required[p] = link->required; + } + return (GETMIN(required[POLAR_X]) > GETMIN(required[POLAR_Y])) ? POLAR_X : POLAR_Y; +} diff --git a/sis/map/chkform.c b/sis/map/chkform.c new file mode 100644 index 0000000..f7bd7b8 --- /dev/null +++ b/sis/map/chkform.c @@ -0,0 +1,61 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/chkform.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)chkform.c 1.2 */ +/* last modified on 5/1/91 at 15:50:10 */ +#include "sis.h" +#include "map_int.h" + + +int +map_check_form(network, nand_flag) +network_t *network; +int nand_flag; +{ + lsGen gen; + node_t *p; + int i, *count; + node_function_t func; + char errmsg[1024]; + + foreach_node(network, gen, p) { + if (p->type == INTERNAL) { + if (node_num_fanin(p) > 2) goto bad_network; + func = node_function(p); + + if (func == NODE_0 || func == NODE_1) continue; + + if (nand_flag) { + if (func != NODE_INV && func != NODE_OR) { + goto bad_network; + } + } else { + if (func != NODE_INV && func != NODE_AND) { + goto bad_network; + } + } + + count = node_literal_count(p); + for(i = node_num_fanin(p)-1; i >= 0; i--) { + if (count[2*i] != 0) goto bad_network; /* pos phase */ + if (count[2*i+1] != 1) goto bad_network;/* neg phase */ + } + FREE(count); + } + } + return 1; + + +bad_network: + (void) sprintf(errmsg, + "\"%s\": '%s' is not a 1 or 2-input %s gate\n", + network_name(network), node_name(p), nand_flag ? "nand" : "nor"); + error_append(errmsg); + return 0; +} diff --git a/sis/map/cluster.c b/sis/map/cluster.c new file mode 100644 index 0000000..c8d086d --- /dev/null +++ b/sis/map/cluster.c @@ -0,0 +1,986 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/cluster.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ + /* file cluster.c release 1.8 */ + /* last modified: 7/22/91 at 12:36:15 */ +/* + * $Log: cluster.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:24 pchong + * imported + * + * Revision 1.7 1993/08/05 16:14:19 sis + * Added default case to switch statement so gcc version will work. + * + * Revision 1.6 1993/07/14 18:10:07 sis + * -f option added to reduce_depth (Herve Touati) + * + * Revision 1.6 1993/06/22 03:49:35 touati + * Add option -f to reduce_depth: poor man's version of flowmap for TLU FPGAs. + * + * Revision 1.5 22/.0/.1 .0:.4:.4 sis + * Updates for the Alpha port. + * + * Revision 1.4 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.3 1992/04/17 21:51:27 sis + * *** empty log message *** + * + * Revision 1.2 1992/03/10 19:15:36 sis + * Changed network_sweep to network_csweep so the latches + * are not removed during the sweep. + * + * Revision 1.2 1992/03/10 19:15:36 sis + * Changed network_sweep to network_csweep so the latches + * are not removed during the sweep. + * + * Revision 1.2 1992/03/02 23:58:59 cmoon + * changed network_sweep to network_csweep + * + * Revision 1.1 92/01/08 17:40:32 sis + * Initial revision + * + * Revision 1.1 91/07/02 10:49:29 touati + * Initial revision + * + */ +#include "sis.h" +#include "cluster.h" +#include "map_defs.h" + + /* this file implements Lawler's clustering algorithm */ + /* for a given limit in size of clusters, find a minimum depth */ + /* clustering. All nodes are supposed to be of size 1. */ + /* When all nodes are of the same size, clustering guarantees */ + /* that each cluster has only one external output (root of cluster) */ + /* then we collapse each cluster into its root node */ + +#define MAX_LEVEL INFINITY + + /* a cluster node is a ROOT_NODE iff it fan outs to a node with a larger label */ + +typedef enum { + NORMAL_NODE, ROOT_NODE + } clust_node_type_t; + +typedef struct { + int number; + st_table *nodes; /* tells the nodes that it contains */ + node_t *root; /* the root of the cluster */ + int label; /* the label, common to the nodes of the cluster */ +} cluster_t; + +typedef struct { + int label; + int max_label; /* needed by relabelling algorithm */ + int weight; + clust_node_type_t type; + array_t *clusters; /* list of clusters to which this node belongs (cluster_t *) */ +} clust_node_t; + + +#include "cluster_static.h" +static clust_options_t global_settings; + + + /* EXTERNAL INTERFACE */ + +network_t *cluster_under_constraint(network, options) +network_t *network; +clust_options_t *options; +{ + network_t *new_network = NIL(network_t); + global_settings = *options; + + switch (options->type) { + case SIZE_CONSTRAINT: + new_network = cluster_under_size_constraint(network, options); + break; + case DEPTH_CONSTRAINT: + new_network = cluster_under_depth_constraint(network, options); + break; + case SIZE_AS_DEPTH_CONSTRAINT: + new_network = cluster_under_size_as_depth_constraint(network, options); + break; + case CLUSTER_STATISTICS: + gather_cluster_statistics(network, options); + break; + case BEST_RATIO_CONSTRAINT: + new_network = cluster_under_best_ratio(network, options); + break; + case FANIN_CONSTRAINT: + new_network = cluster_under_size_constraint(network, options); + break; + default: + ; + } + return new_network; +} + + + /* INTERNAL INTERFACE */ + + /* Lawler's algorithm: given a max cluster size, returns the best labelling */ + /* form and collapse the clusters */ + /* if flag "relabel" is set, try to relabel nodes to control duplication of logic */ + /* without affecting delay */ + +static network_t *cluster_under_size_constraint(network, options) +network_t *network; +clust_options_t *options; +{ + int max_label; + array_t *nodevec; + array_t *clusters; /* array of cluster_t * */ + st_table *table; + + nodevec = network_dfs(network); + + table = clust_node_table_alloc(); + if (options->verbose >= 2) (void) fprintf(misout, "------ labelling nodes-------\n"); + max_label = label_nodes(table, nodevec, options->cluster_size, options->verbose); + if (options->verbose >= 1) (void) fprintf(misout, "*** # levels = %d\n", max_label + 1); + + if (options->relabel) { + relabel_nodes(table, nodevec, max_label, options->verbose); + } + + if (options->verbose >= 2) (void) fprintf(misout, "------ forming clusters-------\n"); + clusters = array_alloc(cluster_t *, 0); + form_clusters(table, nodevec, clusters); + clust_node_table_free(table); + + if (options->verbose >= 2) { + (void) fprintf(misout, "------ printing clusters-------\n"); + print_clusters(clusters); + } + + if (options->verbose >= 2) (void) fprintf(misout, "------ collapsing clusters-------\n"); + collapse_clusters(clusters, nodevec); + + /* remove intermediate nodes not roots of clusters */ + network_csweep(network); + + array_free(nodevec); + clusters_free(clusters); + + return network; +} + + + /* built above Lawler's algorithm: finds the minimum cluster size for which */ + /* the label can attain "depth"; select that cluster size and call Lawler's algorithm */ + +static network_t *cluster_under_depth_constraint(network, options) +network_t *network; +clust_options_t *options; +{ + array_t *nodevec; + int max_label; + int min_cluster_size; + int max_cluster_size; + clust_options_t new_options; + + nodevec = network_dfs(network); + + min_cluster_size = 1; + max_cluster_size = network_num_internal(network); + max_label = options->depth - 1; + + new_options = *options; + new_options.type = SIZE_CONSTRAINT; + new_options.cluster_size = lazy_binary_search(min_cluster_size, max_cluster_size, max_label, nodevec, best_labelling); + + if (options->verbose >= 1) (void) fprintf(misout, "*** max cluster size = %d\n", new_options.cluster_size); + array_free(nodevec); + + return cluster_under_size_constraint(network, &new_options); +} + + /* built above the previous one. Find the minimum size giving the same */ + /* depth as the size passed as argument and use it for Lawler's algorithm */ + +static network_t *cluster_under_size_as_depth_constraint(network, options) +network_t *network; +clust_options_t *options; +{ + array_t *nodevec; + int max_label; + int min_cluster_size; + int max_cluster_size; + clust_options_t new_options; + + nodevec = network_dfs(network); + + min_cluster_size = 1; + max_cluster_size = options->cluster_size; + max_label = best_labelling(nodevec, options->cluster_size); + + new_options = *options; + new_options.type = SIZE_CONSTRAINT; + new_options.cluster_size = lazy_binary_search(min_cluster_size, max_cluster_size, max_label, nodevec, best_labelling); + + if (options->verbose >= 1) (void) fprintf(misout, "*** max cluster size = %d\n", new_options.cluster_size); + array_free(nodevec); + + return cluster_under_size_constraint(network, &new_options); +} + +static void gather_cluster_statistics(network, options) +network_t *network; +clust_options_t *options; +{ + int i; + array_t *nodevec; + int min_cluster_size; + int max_cluster_size; + int max_label; + st_table *table; + double dup_ratio, red_dup_ratio; + array_t *clusters; + + nodevec = network_dfs(network); + + min_cluster_size = 1; + max_cluster_size = network_num_internal(network); + + for (i = min_cluster_size; i <= max_cluster_size; i++) { + table = clust_node_table_alloc(); + max_label = label_nodes(table, nodevec, i, options->verbose); + clusters = array_alloc(cluster_t *, 0); + form_clusters(table, nodevec, clusters); + dup_ratio = duplication_ratio(network, clusters); + clusters_free(clusters); + + reinit_cluster_info(table); + relabel_nodes(table, nodevec, max_label, options->verbose); + clusters = array_alloc(cluster_t *, 0); + form_clusters(table, nodevec, clusters); + red_dup_ratio = duplication_ratio(network, clusters); + clust_node_table_free(table); + clusters_free(clusters); + + (void) fprintf(misout, "cluster_size = %4d ", i); + (void) fprintf(misout, "# levels = %4d ", max_label + 1); + (void) fprintf(misout, "dup_ratio = %2.2f ", dup_ratio); + (void) fprintf(misout, "red_dup_ratio = %2.2f\n", red_dup_ratio); + + if (max_label == 0) break; + } + + array_free(nodevec); +} + + /* + * Heuristics to choose a good cluster size to cluster with. + * try labelling and clustering (but no collapsing, no modification of network) + * for all cluster sizes from 2 to the first cluster size leading to a duplication ratio + * larger than options->dup_ratio. Record the cluster_size corresponding to the smallest + * duplication ratio among those leading to the smallest value for max_label. + * If none, simply take cluster_size = 2. + * Then do the clustering for that size. + */ + +static network_t *cluster_under_best_ratio(network, options) +network_t *network; +clust_options_t *options; +{ + int i; + array_t *nodevec; + int min_cluster_size; + int max_cluster_size; + int max_label; + st_table *table; + double dup_ratio; + array_t *clusters; + int best_cluster_size; + int best_level; + double best_dup_ratio; + clust_options_t new_options; + + nodevec = network_dfs(network); + + min_cluster_size = 2; + max_cluster_size = network_num_internal(network); + + best_level = INFINITY; + best_dup_ratio = INFINITY; + best_cluster_size = -1; + + /* find the best size */ + + for (i = min_cluster_size; i <= max_cluster_size; i++) { + table = clust_node_table_alloc(); + max_label = label_nodes(table, nodevec, i, options->verbose); + relabel_nodes(table, nodevec, max_label, options->verbose); + clusters = array_alloc(cluster_t *, 0); + form_clusters(table, nodevec, clusters); + dup_ratio = duplication_ratio(network, clusters); + clust_node_table_free(table); + clusters_free(clusters); + + if (dup_ratio >= options->dup_ratio) break; + if (max_label == 0) break; + if (max_label < best_level || (max_label == best_level && dup_ratio < best_dup_ratio)) { + best_level = max_label; + best_dup_ratio = dup_ratio; + best_cluster_size = i; + } + } + + if (best_cluster_size == -1) best_cluster_size = 2; + array_free(nodevec); + + new_options = *options; + new_options.type = SIZE_CONSTRAINT; + new_options.cluster_size = best_cluster_size; + if (options->verbose >= 1) (void) fprintf(misout, "*** cluster size = %d\n", new_options.cluster_size); + + return cluster_under_size_constraint(network, &new_options); +} + + + /* LABELLING */ + + /* visits all internal nodes in topological order from inputs to outputs */ + /* allocate a clust_node_t for each node, and put the map "node --> clust_node" in 'table'. */ + + /* ARGSUSED */ +static int label_nodes(table, nodevec, cluster_size, verbose) +st_table *table; +array_t *nodevec; +int cluster_size; +int verbose; +{ + int i; + int label; + node_t *node; + int max_label = -1; + int nsize = array_n(nodevec); + clust_node_t *node_info; + + for (i = 0; i < nsize; i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + node_info = clust_node_alloc(table, node); + label = decide_label_node(table, node, node_info, cluster_size); + if (label > max_label) max_label = label; + } + return max_label; +} + + /* see comments on typedef clust_node_t */ + +static clust_node_t *clust_node_alloc(table, node) +st_table *table; +node_t *node; +{ + clust_node_t *node_info; + + node_info = ALLOC(clust_node_t, 1); + node_info->label = -1; + node_info->weight = 1; + node_info->type = NORMAL_NODE; + node_info->clusters = array_alloc(cluster_t *, 0); + st_insert(table, (char *) node, (char *) node_info); + return node_info; +} + + +/* + * The procedure looks at the node and its fanins and decides what + * label should be given to the node. It puts the label in the node. + * Returns a label (int) + */ + +static int decide_label_node(table, node, node_info, cluster_size) +st_table *table; +node_t *node; +clust_node_t *node_info; +int cluster_size; +{ + int max_fanin_label; + int total_weight; + + /* + * extract the largest label of any immediate fanin of node + */ + + max_fanin_label = get_max_fanin_label(table, node); + + /* + * max_fanin_label == -1 iff node is constant node or node with all fanins PI's + */ + + if (max_fanin_label == -1) { + node_info->label = 0; + return 0; + } + + /* + * sums the weight of all nodes in tfi of node with label 'max_fanin_label' + * the only difficulty is to make sure not to count the same node twice + * total_weight includes the weight of 'node'; need to set node_info->label + * to max_label so that total_weight is computed properly. + */ + + node_info->label = max_fanin_label; + total_weight = compute_tfi_weight_for_given_label(table, node, max_fanin_label); + + if (total_weight > cluster_size) { + node_info->label = max_fanin_label + 1; + } + + return node_info->label; +} + + /* + * returns -1 iff fanins of node are all PI or no fanin at all (constant node) + */ + +static int get_max_fanin_label(table, node) +st_table *table; +node_t *node; +{ + int i; + node_t *fanin; + clust_node_t *node_info; + int max_label = -1; + + foreach_fanin(node, i, fanin) { + if (fanin->type == PRIMARY_INPUT) continue; + assert(st_lookup(table, (char *) fanin, (char **) &node_info)); + max_label = MAX(max_label, node_info->label); + } + return max_label; +} + + + /* Relies on the fact that labels can only increase along a directed path */ + /* to reduce the search of the tfi */ + /* Usually the weight is the number of nodes in the cluster */ + /* however, under the option FANIN_CONSTRAINT */ + /* the weight is the number of distinct inputs */ + /* 'tfi_fanin' is only used under the option 'FANIN_CONSTRAINT' */ + +static int compute_tfi_weight_for_given_label(table, node, label) +st_table *table; +node_t *node; +int label; +{ + int weight = 0; + st_table *tfi_fanin = st_init_table(st_ptrcmp, st_ptrhash); + st_table *tfi_for_given_label = st_init_table(st_ptrcmp, st_ptrhash); + + compute_tfi_for_given_label_rec(table, node, label, tfi_for_given_label, tfi_fanin); + + if (global_settings.type == FANIN_CONSTRAINT) { + weight = st_count(tfi_fanin); + } else { + st_generator *gen; + clust_node_t *node_info; + st_foreach_item(tfi_for_given_label, gen, (char **) &node, (char **) &node_info) { + weight += node_info->weight; + } + } + st_free_table(tfi_for_given_label); + st_free_table(tfi_fanin); + return weight; +} + + + /* Only stores in 'visited' the internal nodes belonging to tfi of 'node' */ + /* and having 'label' as label. */ + /* Stores in 'visited_fanins' the fanins of the set of nodes in 'visited' */ + /* that do not belong to 'visited'. */ + +static void compute_tfi_for_given_label_rec(table, node, label, visited, visited_fanins) +st_table *table; +node_t *node; +int label; +st_table *visited; +st_table *visited_fanins; +{ + int i; + node_t *fanin; + clust_node_t *node_info; + + /* already visited */ + if (st_lookup(visited, (char *) node, NIL(char *))) return; + + /* special case of PI */ + if (node->type == PRIMARY_INPUT) { + st_insert(visited_fanins, (char *) node, NIL(char)); + return; + } + + assert(st_lookup(table, (char *) node, (char **) &node_info)); + + /* stop the recursion when a node with smaller label is found */ + if (node_info->label < label) { + st_insert(visited_fanins, (char *) node, NIL(char)); + return; + } + + /* the general case */ + st_insert(visited, (char *) node, (char *) node_info); + foreach_fanin(node, i, fanin) { + compute_tfi_for_given_label_rec(table, fanin, label, visited, visited_fanins); + } +} + + + /* RELABELLING */ + + /* + * try to split clusters to avoid too much logic duplication + * if not on the critical path. + * new_max_label is just there to check we have not done something wrong + * + * visit all INTERNAL nodes in topological order, from outputs to inputs + */ + +static void relabel_nodes(table, nodevec, max_label, verbose) +st_table *table; +array_t *nodevec; +int max_label; +int verbose; +{ + int i, j; + node_t *fanin; + node_t *node; + int fanin_label_limit; + clust_node_t *node_info; + clust_node_t *fanin_info; + int new_max_label = -1; + int n_nodes = array_n(nodevec); + + /* + * first need to initialize all the max_label fields + */ + + for (i = n_nodes - 1; i >= 0; i--) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + assert(st_lookup(table, (char *) node, (char **) &node_info)); + node_info->max_label = max_label; + } + + /* + * can update the node_info->label field only when + * node_info->label information has been used + */ + + for (i = n_nodes - 1; i >= 0; i--) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + assert(st_lookup(table, (char *) node, (char **) &node_info)); + foreach_fanin(node, j, fanin) { + if (fanin->type != INTERNAL) continue; + assert(st_lookup(table, (char *) fanin, (char **) &fanin_info)); + if (fanin_info->label == node_info->label) { + fanin_label_limit = node_info->max_label; + } else { + fanin_label_limit = node_info->max_label - 1; + } + fanin_info->max_label = MIN(fanin_info->max_label, fanin_label_limit); + } + + if (verbose) { /* debug */ + (void) fprintf(misout, "label of %s = %d", node_long_name(node), node_info->label); + if (node_info->label < node_info->max_label) (void) fprintf(misout, " -> %d\n", node_info->max_label); + (void) fprintf(misout, "\n"); + } + + node_info->label = node_info->max_label; + new_max_label = MAX(new_max_label, node_info->label); /* for consistency check */ + } + assert(new_max_label == max_label); +} + + + /* CLUSTERING */ + +/* + * visit internal nodes in topological order, from outputs to inputs + * + */ + +static void form_clusters(table, nodevec, clusters) +st_table *table; +array_t *nodevec; +array_t *clusters; +{ + int i; + lsGen gen; + node_t *node; + node_t *fanout; + int max_fanout_label; + cluster_t *new_cluster; + clust_node_t *node_info; + clust_node_t *fanout_info; + int n_nodes = array_n(nodevec); + + /* + * check whether a node has a fanout to another node with a larger label + * if yes, create a new cluster; if no, don't. Force cluster creation if fanouts to a PO + */ + + for (i = n_nodes - 1; i >= 0; i--) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + assert(st_lookup(table, (char *) node, (char **) &node_info)); + max_fanout_label = node_info->label; + foreach_fanout(node, gen, fanout) { + if (fanout->type == PRIMARY_OUTPUT) { + max_fanout_label = INFINITY; + continue; + } + assert(st_lookup(table, (char *) fanout, (char **) &fanout_info)); + max_fanout_label = MAX(max_fanout_label, fanout_info->label); + } + if (max_fanout_label > node_info->label) { + new_cluster = cluster_alloc(); + node_info->type = ROOT_NODE; + new_cluster->root = node; + new_cluster->label = node_info->label; + array_insert_last(cluster_t *, clusters, new_cluster); + put_tfi_in_cluster_rec(table, new_cluster, node, node_info->label); + } + } +} + +static void put_tfi_in_cluster_rec(table, cluster, node, label) +st_table *table; +cluster_t *cluster; +node_t *node; +int label; +{ + int i; + node_t *fanin; + clust_node_t *node_info; + + if (node->type == PRIMARY_INPUT) return; + if (st_lookup(cluster->nodes, (char *) node, NIL(char *))) return; + assert(st_lookup(table, (char *) node, (char **) &node_info)); + if (node_info->label < label) return; + st_insert(cluster->nodes, (char *) node, NIL(char)); + array_insert_last(cluster_t *, node_info->clusters, cluster); + + foreach_fanin(node, i, fanin) { + put_tfi_in_cluster_rec(table, cluster, fanin, label); + } +} + + + /* DUPLICATION ESTIMATE */ + + /* this only counts internal nodes */ + +static double duplication_ratio(network, clusters) +network_t *network; +array_t *clusters; +{ + int i; + cluster_t *cluster; + int before_clustering; + int after_clustering; + + before_clustering = network_num_internal(network); + after_clustering = 0; + for (i = 0; i < array_n(clusters); i++) { + cluster = array_fetch(cluster_t *, clusters, i); + after_clustering += st_count(cluster->nodes); + } + return (double) after_clustering / (double) before_clustering; +} + + + + /* COLLAPSING CLUSTERS */ + + + /* + * collapsing the clusters. + * to do the collapsing of each cluster, + * have to be careful to collapse them in topological order + * the closer to the PI's, the lower the index in 'nodevec' + */ + +static void collapse_clusters(clusters, nodevec) +array_t *clusters; +array_t *nodevec; +{ + int i; + node_t *node; + cluster_t *cluster; + st_table *topological_order = st_init_table(st_numcmp, st_numhash); + + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + st_insert(topological_order, (char *) node, (char *) i); + } + for (i = 0; i < array_n(clusters); i++) { + cluster = array_fetch(cluster_t *, clusters, i); + collapse_cluster(cluster, topological_order); + } + st_free_table(topological_order); +} + +typedef struct { + int order; + node_t *node; +} sorted_node_t; + + /* should put first those closer to PO */ + +static int sorted_node_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + sorted_node_t *c1 = (sorted_node_t *) obj1; + sorted_node_t *c2 = (sorted_node_t *) obj2; + + return - (c1->order - c2->order); +} + + /* extract all the nodes in a cluster into an array */ + /* sort the array in such a way to put first the nodes closest to the root */ + /* for consistency, check that the first node in the array is marked "root" */ + +/* +int +node_collapse(f, g) +node_t *f, *g; + Assuming g is an input to f, re-express f without using g. + Changes f in-place, g is unchanged. + +*/ + +static void collapse_cluster(cluster, topological_order) +cluster_t *cluster; +st_table *topological_order; +{ + int i; + st_generator *gen; + node_t *net_node; + int order; + sorted_node_t new_node; + sorted_node_t *root; + sorted_node_t *node; + int n_nodes = st_count(cluster->nodes); + array_t *nodes = array_alloc(sorted_node_t, n_nodes); + + assert(n_nodes > 0); + st_foreach_item(cluster->nodes, gen, (char **) &net_node, NIL(char *)) { + assert(st_lookup_int(topological_order, (char *) net_node, &order)); + new_node.node = net_node; + new_node.order = order; + array_insert_last(sorted_node_t, nodes, new_node); + } + array_sort(nodes, sorted_node_cmp); + + root = array_fetch_p(sorted_node_t, nodes, 0); + assert(cluster->root == root->node); + for (i = 1; i < n_nodes; i++) { + node = array_fetch_p(sorted_node_t, nodes, i); + node_collapse(root->node, node->node); + /* just a check */ + if (node_get_fanin_index(root->node, node->node) != -1) { + node_print(sisout, root->node); + node_print(sisout, node->node); + fail("incorrect collapsing: collapsed node still appears as fanin"); + } + } + + array_free(nodes); +} + + + /* BINARY SEARCH ON LABELLING PROCEDURE */ + + /* + * just an interface to allow binary search without concern for memory leaks + * returns the max label value obtained by Lawler's algorithm for the given cluster_size + */ + +static int best_labelling(nodevec, cluster_size) +array_t *nodevec; +int cluster_size; +{ + int max_label; + st_table *table = clust_node_table_alloc(); + + max_label = label_nodes(table, nodevec, cluster_size, 0); + clust_node_table_free(table); + return max_label; +} + + + /* + * given a function fn guaranteed to be non increasing + * find the smallest integer x between min and max such that fn(x) >= value + * the objective is to minimize the number of calls to fn + */ + +static int lazy_binary_search(min, max, value, nodevec, fn) +int min; +int max; +int value; +array_t *nodevec; +int (*fn)(); +{ + int middle; + int min_value; + int max_value; + int middle_value; + + assert(min <= max); + min_value = (*fn)(nodevec, min); + if (min_value <= value) return min; + max_value = (*fn)(nodevec, max); + if (max_value > value) return max; + for (;;) { + middle = min + (max - min) / 2; + if (middle == min) { + assert(max_value <= value); + return (min_value <= value) ? min : max; + } + middle_value = (*fn)(nodevec, middle); + if (middle_value > value) { + min = middle; + min_value = middle_value; + } else { + max = middle; + max_value = middle_value; + } + } +} + + + /* UTILITIES */ + + /* + * alloc and free the hash table containing info on nodes: used for labelling + */ + +static st_table *clust_node_table_alloc() +{ + return st_init_table(st_numcmp, st_numhash); +} + +static void clust_node_table_free(table) +st_table *table; +{ + node_t *node; + st_generator *gen; + clust_node_t *node_info; + + st_foreach_item(table, gen, (char **) &node, (char **) &node_info) { + clust_node_free(node_info); + } + st_free_table(table); +} + +static void clust_node_free(node_info) +clust_node_t *node_info; +{ + array_free(node_info->clusters); + FREE(node_info); +} + +static void reinit_cluster_info(table) +st_table *table; +{ + node_t *node; + st_generator *gen; + clust_node_t *node_info; + + st_foreach_item(table, gen, (char **) &node, (char **) &node_info) { + array_free(node_info->clusters); + node_info->clusters = array_alloc(cluster_t *, 0); + } +} + +static void clusters_free(clusters) +array_t *clusters; +{ + int i; + cluster_t *cluster; + + for (i = 0; i < array_n(clusters); i++) { + cluster = array_fetch(cluster_t *, clusters, i); + cluster_free(cluster); + } + array_free(clusters); +} + +static cluster_t *cluster_alloc() +{ + cluster_t *result = ALLOC(cluster_t, 1); + + result->nodes = st_init_table(st_numcmp, st_numhash); + result->root = NIL(node_t); + result->label = -1; + return result; +} + +static void cluster_free(cluster) +cluster_t *cluster; +{ + st_free_table(cluster->nodes); + FREE(cluster); +} + + + + + /* FOR DEBUGGING */ + +static void print_clusters(clusters) +array_t *clusters; +{ + int i; + cluster_t *cluster; + + for (i = 0; i < array_n(clusters); i++) { + cluster = array_fetch(cluster_t *, clusters, i); + print_cluster(cluster); + } +} + +static void print_cluster(cluster) +cluster_t *cluster; +{ + clust_node_type_t type; + node_t *node; + int num_nodes; + st_generator *gen; + char *dummy; + + (void) fprintf(misout, "cluster#%d ", cluster->number); + num_nodes = st_count(cluster->nodes); + (void) fprintf(misout, "(number of nodes = %d) =>", num_nodes); + st_foreach_item(cluster->nodes, gen, (char **) &node, &dummy) { + type = (clust_node_type_t) dummy; + switch (type) { + case NORMAL_NODE: + (void) fprintf(misout, " %s ", node->name); + break; + case ROOT_NODE: + (void) fprintf(misout, " %s:root ", node->name); + break; + default: + (void) fprintf(misout, "\nunexpected clust_node type\n"); + break; + } + } + (void) fprintf(misout, "\n\n"); +} + diff --git a/sis/map/cluster.h b/sis/map/cluster.h new file mode 100644 index 0000000..5096d03 --- /dev/null +++ b/sis/map/cluster.h @@ -0,0 +1,80 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/cluster.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ + /* file cluster.h release 1.2 */ + /* last modified: 7/2/91 at 19:44:29 */ +/* + * $Log: cluster.h,v $ + * Revision 1.1.1.1 2004/02/07 10:14:24 pchong + * imported + * + * Revision 1.5 1993/07/14 18:10:07 sis + * -f option added to reduce_depth (Herve Touati) + * + * Revision 1.4 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.4 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.3 1992/04/17 21:48:51 sis + * *** empty log message *** + * + * Revision 1.3 1992/04/17 21:48:51 sis + * *** empty log message *** + * + * Revision 1.2 1992/03/25 22:03:32 sis + * __args is replaced by ARGS + * + * Revision 1.2 1992/03/25 22:03:32 sis + * __args is replaced by ARGS + * + * Revision 1.2 1992/03/25 21:48:08 cmoon + * __args is replaced by ARGS + * + * Revision 1.1 92/01/08 17:40:33 sis + * Initial revision + * + * Revision 1.1 91/07/02 10:49:47 touati + * Initial revision + * + */ + +#ifndef CLUSTER_H +#define CLUSTER_H + +typedef enum { + DEPTH_CONSTRAINT, + SIZE_CONSTRAINT, + SIZE_AS_DEPTH_CONSTRAINT, + CLUSTER_STATISTICS, + BEST_RATIO_CONSTRAINT, + FANIN_CONSTRAINT +} clust_type_t; + +typedef struct { + clust_type_t type; + int cluster_size; + int depth; + int relabel; + int verbose; + double dup_ratio; +} clust_options_t; + +/* redundant - use ARGS defined in ansi.h +#ifdef __STDC__ +#define __args(x) (x) +#else +#define __args(x) () +#endif +*/ + +extern network_t *cluster_under_constraint ARGS((network_t *, clust_options_t *)); + +#endif /* CLUSTER_H */ diff --git a/sis/map/cluster_static.h b/sis/map/cluster_static.h new file mode 100644 index 0000000..c5cb4b4 --- /dev/null +++ b/sis/map/cluster_static.h @@ -0,0 +1,40 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/cluster_static.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)cluster_static.h 1.5 */ +/* last modified on 7/22/91 at 12:36:23 */ +static clust_node_t *clust_node_alloc(); +static cluster_t *cluster_alloc(); +static void cluster_free(); +static double duplication_ratio(); +static int best_labelling(); +static int compute_tfi_weight_for_given_label(); +static int decide_label_node(); +static int get_max_fanin_label(); +static int label_nodes(); +static int lazy_binary_search(); +static int sorted_node_cmp(); +static network_t *cluster_under_best_ratio(); +static network_t *cluster_under_depth_constraint(); +static network_t *cluster_under_size_as_depth_constraint(); +static network_t *cluster_under_size_constraint(); +static st_table *clust_node_table_alloc(); +static void clust_node_free(); +static void clust_node_table_free(); +static void clusters_free(); +static void collapse_cluster(); +static void collapse_clusters(); +static void compute_tfi_for_given_label_rec(); +static void form_clusters(); +static void gather_cluster_statistics(); +static void print_cluster(); +static void print_clusters(); +static void put_tfi_in_cluster_rec(); +static void reinit_cluster_info(); +static void relabel_nodes(); diff --git a/sis/map/com_map.c b/sis/map/com_map.c new file mode 100644 index 0000000..22d4903 --- /dev/null +++ b/sis/map/com_map.c @@ -0,0 +1,1404 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/com_map.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)com_map.c 1.22 */ +/* Last modified on Tue Jun 22 06:43:58 MET DST 1993 by touati */ +#include "sis.h" +#include "map_defs.h" +#include "map_int.h" +#include "lib_int.h" +#include "fanout_int.h" +#include "cluster.h" +#include "map_delay.h" + +static array_t *current_fanout_alg; +static void map_report_usage(); + +#ifdef SIS +st_table *network_type_table; +static void map_latch_table_dup(); +static node_t *map_copy_clock(); +#endif + +static int +com_replace(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + int verbose = 0; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "v:")) != EOF) { + switch(c) { + case 'v': + verbose = atoi(util_optarg); + break; + default: + goto usage; + } + } + replace_2or(*network, verbose); + return 0; + usage: + (void) fprintf(siserr, "replace [-v verbosity level]\n"); + return 1; +} + + /* perform premapping, mapping, fanout optimization... */ + +static int +com_map(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *new_network; + bin_global_t options; + + if (map_fill_options(&options, &argc, &argv)) { + fprintf(siserr, "%s", error_string()); + map_report_usage("map"); + return 1; + } + new_network = complete_map_interface(*network, &options); + if (new_network == 0) { + fprintf(siserr, "%s", error_string()); + return 1; + } + new_network->dc_network = network_dup((*network)->dc_network); +#ifdef SIS + new_network->stg = stg_dup((*network)->stg); + map_latch_table_dup(*network, new_network); +#endif + + network_free(*network); + *network = new_network; + return 0; +} + + /* builds a MAPPED network from an ANNOTATED network */ + +static int +com_build_map(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *new_network; + bin_global_t globals; + + if (map_fill_options(&globals, &argc, &argv)) { + fprintf(siserr, "%s", error_string()); + map_report_usage("map"); + return 1; + } + new_network = build_mapped_network_interface(*network, &globals); + if (new_network == NIL(network_t)) { + fprintf(siserr, "%s", error_string()); + return 1; + } + network_free(*network); + *network = new_network; + return 0; +} + +/* takes a RAW or an ANNOTATED network and returns an ANNOTATED network */ + /* only do tree mapping */ + +static int +com_tree_map(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *new_network; + bin_global_t options; + + if (map_fill_options(&options, &argc, &argv)) { + fprintf(siserr, "%s", error_string()); + map_report_usage("map"); + return 1; + } + new_network = tree_map_interface(*network, &options); + if (new_network == 0) { + fprintf(siserr, "%s", error_string()); + return 1; + } + if (new_network != *network) { + network_free(*network); + *network = new_network; + } + return 0; +} + + /* takes an ANNOTATED network and returns an ANNOTATED network */ + /* performs fanout optimization and, if specified, area recovery */ + +static int +com_fanout_opt(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *new_network; + bin_global_t options; + + if (map_fill_options(&options, &argc, &argv)) { + fprintf(siserr, "%s", error_string()); + map_report_usage("map"); + return 1; + } + new_network = fanout_opt_interface(*network, &options); + if (new_network == 0) { + fprintf(siserr, "%s", error_string()); + return 1; + } + if (new_network != *network) { + network_free(*network); + *network = new_network; + } + return 0; +} + + /* can be used to add/remove fanout algorithms from the list of active alg's */ + + /* ARGSUSED */ +static int +com_fanout_alg(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int no_options = 0; + int verbose = 0; + + if (current_fanout_alg == NIL(array_t)) { + current_fanout_alg = fanout_opt_get_fanout_alg(0, NIL(char *)); + } + argc--; argv++; + if (argc == 0) no_options = 1; + while (argc > 0 && argv[0][0] == '-') { + switch (argv[0][1]) { + case 'v': + verbose = 1; + break; + default: + goto usage; + } + argc--; + argv++; + } + if (! no_options) current_fanout_alg = fanout_opt_get_fanout_alg(argc, argv); + if (verbose || no_options) fanout_opt_print_fanout_alg(current_fanout_alg); + return 0; + usage: + fprintf(siserr, "usage: fanout_alg [-v] fanout_alg1 fanout_alg2 ...\n"); + fprintf(siserr, " -v\t verbose mode\n"); + return 1; +} + + /* can be used to give values to parameters of specific fanout algorithms */ + + /* ARGSUSED */ +static int +com_fanout_param(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int fanout_alg_index; + int verbose = 0; + + if (current_fanout_alg == NIL(array_t)) + current_fanout_alg = fanout_opt_get_fanout_alg(0, NIL(char *)); + argc--; argv++; + while (argc > 0 && argv[0][0] == '-') { + switch (argv[0][1]) { + case 'v': + verbose = 1; + break; + default: + goto usage; + } + argc--; + argv++; + } + fanout_opt_set_fanout_param(current_fanout_alg, argc, argv, &fanout_alg_index); + if (fanout_alg_index == -1) goto usage; + if (verbose) fanout_opt_print_fanout_param(current_fanout_alg, fanout_alg_index); + return 0; + usage: + fprintf(siserr, "usage: fanout_param [-v] fanout_alg property value\n"); + fprintf(siserr, " -v\t lists all (property, value) pairs associated with algorithm\n"); + fanout_opt_print_fanout_alg(current_fanout_alg); + return 1; +} + +static bin_global_t DEFAULT_OPTIONS = { + 0, /* int new_mode; // new_mode */ + 0.0, /* double new_mode_value; // 0.0->area ... 1.0->delay */ + 0, /* int load_bins_count; // historical */ + 0, /* int delay_bins_count; // historical */ + 0.0, /* double old_mode; // old map; area or delay optimize */ + 1, /* int inverter_optz; // inverter optimization heuristics */ + -1, /* int allow_internal_fanout; // degrees of internal fanouts allowed */ + 0, /* int print_stat; // print area/delay stats at the end */ + 0, /* int verbose; // verbosity level */ + 0, /* int raw; // raw mapping */ + 0.0, /* double thresh; // threshold used in old tree mapper */ + 0, /* library_t *library; // current library */ + 0, /* int fanout_optimize; // if set, the fanout optimizer is called */ + 0, /* int area_recover; // if set, area is recovered after fanout opt */ + 0, /* int peephole; // if set, call fanout peephole optimizer */ + 0, /* array_t *fanout_alg; // array of fanout algorithm descriptors */ + 0, /* int remove_inverters; // if set, remove redundant inverters after mapping */ + 0, /* int no_warning; // if set, does not print any warning message */ + 0, /* int ignore_pipo_data; // if set, ignore specific values set at PIPO's */ + RAW_NETWORK, /* network_type_t network_type; // type of the network when mapping is started */ + 2, /* int load_estimation; // 0-ignore fanout; 1-linear fanout; 2-load of fanout tree */ + 1, /* int ignore_polarity; // 0-add an inverter delay; 1-same arrival for both pol. */ + 0, /* int cost_function; // 0-MAX(rise,fall); 1-AVER(rise,fall) */ + 0, /* int n_iterations; // 0-do it once, 1-repeat once, etc... */ + 0, /* int fanout_iterate; // 1 if tree covering is called afterwards; 0 otherwise */ + 1, /* int opt_single_fanout; // 0/1 */ + 0, /* int fanout_log_on; // 0/1 */ + 0, /* int allow_duplication; // 0/1 */ + INFINITY, /* int fanout_limit; // limit fanout of internal nodes during matching */ + 1, /* int check_load_limit; // if set, check load limit during fanout opt */ + 1000, /* int penalty_factor; // factor by which load is multiplied when exceeds max load limit of a gate */ + 0 /* int all_gates_area_recover; // when set, recover area on all gates, not only buffers */ +}; + + int map_fill_options(options, argc_addr, argv_addr) +bin_global_t *options; +int *argc_addr; +char ***argv_addr; +{ + int c; + double mode; + int argc = *argc_addr; + char **argv = *argv_addr; + + error_init(); + *options = DEFAULT_OPTIONS; + if (current_fanout_alg == NIL(array_t)) { + current_fanout_alg = fanout_opt_get_fanout_alg(0, NIL(char *)); + } + options->fanout_alg = current_fanout_alg; + if ((options->library = lib_get_library()) == NIL(library_t)) { + error_append("map_interface: need to load a library with read_library\n"); + return 1; + } + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "Ab:B:c:dFGf:iI:l:L:m:n:pPrst:v:W")) != EOF) { + switch(c) { + case 'A': + options->area_recover = 1; + options->fanout_optimize = 1; + break; + case 'G': + options->all_gates_area_recover = 1; + options->area_recover = 1; + options->fanout_optimize = 1; + break; + case 'b': + options->penalty_factor = atoi(util_optarg); + if (options->penalty_factor < 0) { + error_append("map_interface: -b n: n should be non negative\n"); + return 1; + } + break; + case 'B': + options->check_load_limit = atoi(util_optarg); + if (options->check_load_limit != 0 && options->check_load_limit != 1) { + error_append("map_interface: -B n: n should be 0 or 1\n"); + return 1; + } + break; + case 'c': + options->cost_function = atoi(util_optarg); + if (options->cost_function != 0 && options->cost_function != 1) { + error_append("map_interface: -c n: n should be 0 or 1\n"); + return 1; + } + break; + case 'd': + options->allow_duplication = 1; + break; + case 'F': + options->fanout_optimize = 1; + break; + case 'f': + options->allow_internal_fanout = atoi(util_optarg); + break; + case 'i': + options->inverter_optz = 0; + break; + case 'I': + options->n_iterations = atoi(util_optarg); + break; + case 'l': + options->load_estimation = atoi(util_optarg); + if (options->load_estimation < 0 || options->load_estimation > 3) { + error_append("map_interface: -l n: n should be 0, 1, 2 or 3\n"); + return 1; + } + break; + case 'L': + options->fanout_limit = atoi(util_optarg); + if (options->load_estimation < 1) { + error_append("map_interface: -L n: n should be >= 1\n"); + return 1; + } + break; + case 'm': + options->old_mode = atof(util_optarg); + if (options->old_mode > 1.0000 || options->old_mode < 0) { + error_append("map_interface: -m n: n should be in interval (0,1)\n"); + return 1; + } + break; + case 'n': + options->new_mode = 1; + options->new_mode_value = atof(util_optarg); + mode = options->new_mode_value; + if (mode < 0.0 || mode > 1.0) { + error_append("map_interface: -n n: n should be in interval (0,1)\n"); + return 1; + } + if (mode == 0.0) { + options->new_mode = 0; + options->old_mode = 0.0; + } + break; + case 'p': + options->ignore_pipo_data = 1; + break; + case 'P': + options->ignore_polarity = 1 - options->ignore_polarity; + break; + case 'r': + options->raw = 1; + break; + case 's': + options->print_stat = 1; + break; + case 't': + options->old_mode = 2.0; + options->thresh = atof(util_optarg); + break; + case 'v': + options->verbose = atoi(util_optarg); + break; + case 'W': + options->no_warning = 1; + break; + default: + error_append("map_interface: unknown option\n"); + return 1; + } + } + +/* + removing inverters after old treemapping usually improves delay. + if (! options->fanout_optimize && options->new_mode == 0 && options->old_mode == 0.0) { +*/ + if (! options->fanout_optimize && options->new_mode == 0) { + options->remove_inverters = 1; + } + + if (options->allow_internal_fanout == -1) { /* determine the default for internal fanout: 11 for min area, 0 otherwise */ + options->allow_internal_fanout = 0; + if (! options->fanout_optimize && options->new_mode == 0 && options->old_mode == 0.0) { + options->allow_internal_fanout = 11; + } + } else { /* if -f option was specified non zero with the fanout optimizer, disallow it */ +/* do not disallow it any more: needed for experiments. + if (options->allow_internal_fanout != 0 && options->fanout_optimize) { + options->allow_internal_fanout = 0; + if (! options->no_warning) (void) fprintf(siserr, "WARNING: internal fanout disallowed with fanout optimization\n"); + } +*/ + } + *argc_addr = argc; + *argv_addr = argv; + return 0; +} + +static void map_report_usage(command_name) +char *command_name; +{ + (void) fprintf(siserr, "usage: %s\n", command_name); + (void) fprintf(siserr, "############################## VERBOSE OPTIONS ##############################\n"); + (void) fprintf(siserr, "\t-v n\tselect verbosity level; for debugging\n"); + (void) fprintf(siserr, "\t-W\tsuppresses warning messages\n"); + (void) fprintf(siserr, "\t-s\tprint stats at the end\n"); + (void) fprintf(siserr, "############################## BASIC OPTIONS ##############################\n"); + (void) fprintf(siserr, "\t-m n\told map mode: n=0.0: minimize area; n=1.0 minimize delay\n"); + (void) fprintf(siserr, "\t-n n\tnew map mode: n=1.0: better delay minimization\n"); + (void) fprintf(siserr, "\t-F\tfanout optimization for delay\n"); + (void) fprintf(siserr, "\t-A\tsecond fanout optimization pass: less area for no cost in delay\n"); + (void) fprintf(siserr, "\t-G\trecovers area after fanout optimization at no cost in delay by resizing all gates\n"); + (void) fprintf(siserr, "############################## ADVANCED OPTIONS ##############################\n"); + (void) fprintf(siserr, "\t-p\tignore PI/PO delay declarations; use global delay declarations instead\n"); + (void) fprintf(miserr, "\t-B n\tenforce load limit during fanout optimization: 0=no enforcement 1(default)=enforcement\n"); + (void) fprintf(miserr, "\t-b n\t use with -B: multiply load by n when load limit exceeded; default n=1000\n"); + (void) fprintf(siserr, "\t-c n\tcost function in '-n 1': n=0->MAX(rise,fall), n=1->AVER(rise,fall)\n"); + (void) fprintf(siserr, "\t-f n\tallow internal fanout (n = 0: none)\n"); + (void) fprintf(siserr, "\t-i\tinverter optimization\n"); + (void) fprintf(siserr, "############################## EXPERIMENTAL OPTIONS ##############################\n"); + (void) fprintf(siserr, "\t-l n\tn=0->load=load; n=1->load=load*n_fanouts; n=2->load=load*sqrt(n_fanouts)\n"); + (void) fprintf(siserr, "\t-L n\tn = fanout limit when allowing overlaps between covers \n"); + (void) fprintf(siserr, "\t-P\tadd inverter delay if difft polarity than source at fanout node\n"); + (void) fprintf(siserr, "\t-r\traw map\n"); + (void) fprintf(siserr, "\t-t n\told_mode with threshold n\n"); +} + + +/* ARGSUSED */ +static int +com_read_library(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + FILE *fp, *outfp; + char *filename, *real_filename; + int append, add_inverters, nand_flag, raw, c; + library_t *old_library; + + append = 0; /* default is no-append */ + raw = 0; /* default is genlib format */ + add_inverters = 1; /* default adds inverters */ + nand_flag = 0; /* default is nor */ + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "ainrbs")) != EOF) { + switch(c) { + case 'a': + append = 1; + break; + case 'i': + add_inverters = 0; + break; + case 'n': + nand_flag = 1; + break; + case 'r': + raw = 1; + break; + default: + goto usage; + } + } + if (argc - util_optind != 1) goto usage; + + /* save the old library */ + old_library = lib_current_library; + + filename = argv[util_optind]; + fp = com_open_file(filename, "r", &real_filename, /* silent */ 0); + if (fp == NULL) goto error_return; + + if (! append) { + lib_current_library = 0; + } + + /* run the library though genlib if not reading it raw */ + if (! raw) { + outfp = util_tmpfile(); + if (outfp == NULL) { + (void) fprintf(siserr, "Error opening temporary file\n"); + lib_current_library = old_library; + return 1; + } + if (! genlib_parse_library(fp, real_filename, outfp, ! nand_flag)) { + (void) fprintf(siserr, "%s", error_string()); + (void) fclose(fp); + goto error_return; + } + (void) fclose(fp); + rewind(outfp); + fp = outfp; + } + + /* read a new library */ + if (! lib_read_blif(fp, real_filename, + add_inverters, nand_flag, &lib_current_library)) { + (void) fclose(fp); + (void) fprintf(sisout, "%s", error_string()); + goto error_return; + } + + (void) fclose(fp); + FREE(real_filename); + if (append == 0 && old_library != 0) { + lib_free(old_library); + } + return 0; + + usage: + (void) fprintf(siserr, "usage: read_library [-adnr] filename\n"); + (void) fprintf(siserr, " -a\t\tappend to current library\n"); + (void) fprintf(siserr, " -i\t\tsuppress add inverters\n"); + (void) fprintf(siserr, " -n\t\tuse NAND gates (instead of NOR)\n"); + (void) fprintf(siserr, " -r\t\tread raw blif (rather than genlib)\n"); + return 1; + + error_return: + FREE(real_filename); + lib_current_library = old_library; + return 1; +} + +typedef struct gate_count_struct gate_count_t; +struct gate_count_struct { + char *name; + int count; + double area; +}; + + +static void +gate_summary(node_vec) +array_t *node_vec; +{ + int i, total_gates; + node_t *node; + gate_count_t *count; + lib_gate_t *gate; + char *gatename, *key, *value; + double total_area; + avl_generator *avlgen; + avl_tree *gate_count_table; + + gate_count_table = avl_init_table(strcmp); + + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (node->type == INTERNAL) { + gate = lib_gate_of(node); + if (gate == NIL(lib_gate_t)) { + gatename = "<none>"; + } else { + gatename = lib_gate_name(gate); + if (gatename == NIL(char)) gatename = "<none>"; + } + + if (avl_lookup(gate_count_table, gatename, &value)) { + count = (gate_count_t *) value; + count->count++; + } else { + count = ALLOC(gate_count_t, 1); + count->name = util_strsav(gatename); + count->count = 1; + count->area = lib_gate_area(gate); + value = (char *) count; + (void) avl_insert(gate_count_table, count->name, value); + } + } + } + + total_area = 0; + total_gates = 0; + avl_foreach_item(gate_count_table, avlgen, AVL_FORWARD, &key, &value) { + count = (gate_count_t *) value; + (void) fprintf(sisout, "%-15s : %4d (area=%4.2f)\n", + count->name, count->count, count->area); + total_area += count->count * count->area; + total_gates += count->count; + } + (void) fprintf(sisout, + "Total: %d gates, %4.2f area\n", total_gates, total_area); + avl_free_table(gate_count_table, free, free); +} + +static void +print_lib_gate_info(node, print_pins) +node_t *node; +int print_pins; +{ + int j; + node_t *fanin; + lib_gate_t *gate; + char *pinname, *gatename; + double area; + + if (node->type == INTERNAL) { + gate = lib_gate_of(node); + if (gate == NIL(lib_gate_t)) { + gatename = "<none>"; + area = 0.0; + } else { + gatename = lib_gate_name(gate); + area = lib_gate_area(gate); + } + + (void) fprintf(sisout, "%-10s %-15s %4.2f\t", + node_name(node), gatename, area); + if (print_pins && gate != NIL(lib_gate_t)) { + (void) fprintf(sisout, " ("); + foreach_fanin(node, j, fanin) { + pinname = lib_gate_pin_name(gate, j, /* inflag */ 1); + if (j != 0) (void) fprintf(sisout, " "); + (void) fprintf(sisout, "%s=%s", pinname, node_name(fanin)); + } + (void) fprintf(sisout, ")"); + } + (void) fprintf(sisout, "\n"); + } +} + +/* ARGSUSED */ +static int +com_print_gate(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + node_t *node; + array_t *node_vec; + int i, print_pins, summary, c; + + print_pins = 0; + summary = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "ps")) != EOF) { + switch(c) { + case 'p': + print_pins = 1; + break; + case 's': + summary = 1; + break; + default: + goto usage; + } + } + + node_vec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + if (array_n(node_vec) < 1) goto usage; + + if (summary) { + gate_summary(node_vec); + } else { + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + print_lib_gate_info(node, print_pins); + } + } + array_free(node_vec); + return 0; + + usage: + (void) fprintf(siserr, "usage: print_gate [-ps] n1 n2 ...\n"); + return 1; +} + +/* ARGSUSED */ +static int +com_treesize(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + if (argc != 1) goto usage; + + map_print_tree_size(sisout, *network); + return 0; + + usage: + (void) fprintf(siserr, "usage: _treesize\n"); + return 1; +} + +/* ARGSUSED */ +static int +com_eat_buffer(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + lsGen gen; + node_t *node; + + if (argc != 1) goto usage; + foreach_primary_output(*network, gen, node) { + (void) network_sweep_node(node); + } + (void) network_cleanup(*network); + return 0; + + usage: + (void) fprintf(siserr, "usage: _eat_buffer\n"); + return 1; +} + +/* ARGSUSED */ +static int +com_premap(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + library_t *library; + library = lib_get_library(); + + if (library == 0) { + (void) fprintf(siserr, "_premap: no current library\n"); + return 1; + } + if (! map_check_form(*network, library->nand_flag)) { + return 0; + } + + error_init(); + if (! do_tree_premap(*network, library)) { + (void) fprintf(siserr, "%s", error_string()); + } + return 0; +} + +static int +com_map_addinv(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int at_pipo, c; + + at_pipo = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "p")) != EOF) { + switch(c) { + case 'p': + at_pipo = 1; + break; + default: + goto usage; + } + } + if (argc - util_optind != 0) goto usage; + + map_add_inverter(*network, at_pipo); + return 0; + + usage: + (void) fprintf(siserr, "usage: _addinv [-p]\n"); + return 1; +} + +/* ARGSUSED */ +static int +com_map_reminv(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + if (argc != 1) { + (void) fprintf(siserr, "usage: _reminv\n"); + return 1; + } + if (lib_network_is_mapped(*network)) { + map_remove_inverter(*network, map_report_data_mapped); + map_report_data_mapped(*network); + } else { + (void)fprintf(sisout, ">>> removing extra series and parallel inverters <<<\n"); + map_remove_inverter(*network, (VoidFn) 0); + } + return 0; +} + +/* ARGSUSED */ +static int +com_buffer(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + if (argc != 1) { + (void) fprintf(siserr, "usage: _buffer\n"); + return 1; + } + if (lib_get_library() == 0) { + (void) fprintf(siserr, "print_library: no current library\n"); + return 1; + } + buffer_inputs(*network, lib_get_library()); + return 0; +} + +/* ARGSUSED */ +static int +com_dump_patterns(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + if (lib_get_library() == 0) { + (void) fprintf(siserr, "print_library: no current library\n"); + return 1; + } + + lib_dump(sisout, lib_get_library(), /* detail */ 1); + return 0; +} + +/* ARGSUSED */ +static int +com_print_library(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + lib_class_t *class; + network_t *net1; + library_t *library; +#ifdef SIS + latch_synch_t type; + int c, print_gates; + lsGen gen; + lib_gate_t *gate; +#endif + + library = lib_get_library(); + if (library == 0) { + (void) fprintf(siserr, "print_library: no current library\n"); + return 1; + } + +#ifdef SIS + /* sequential support */ + type = COMBINATIONAL; + print_gates = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "afhlrG")) != EOF) { + switch (c) { + case 'a': + type = ASYNCH; + break; + case 'f': + type = FALLING_EDGE; + break; + case 'h': + type = ACTIVE_HIGH; + break; + case 'l': + type = ACTIVE_LOW; + break; + case 'r': + type = RISING_EDGE; + break; + case 'G': + print_gates = 1; + break; + default: + goto usage; + } + } + if (print_gates) { + lsForeachItem(library->gates, gen, gate) { + lib_dump_gate(gate); + } + return 0; + } + + if (argc == util_optind) { + lib_dump(sisout, library, /* detail */ 0); + } else if (argc - util_optind == 1) { + net1 = read_eqn_string(argv[util_optind]); + if (net1 == 0) { + (void) fprintf(siserr, "%s", error_string()); + return 1; + } + class = lib_get_class_by_type(net1, library, type); + if (class == 0) { + (void) fprintf(siserr, + "print_library: cannot find class for given function\n"); + return 1; + } + lib_dump_class(sisout, class); + network_free(net1); + } else { + goto usage; + } + return 0; + usage: + (void) fprintf(siserr, "usage: print_library [-afhlrG] [function-string]\n"); + (void) fprintf(siserr, " -a\t\tasynchronous latches only\n"); + (void) fprintf(siserr, " -f\t\tfalling_edge latches only\n"); + (void) fprintf(siserr, " -h\t\tactive_high latches only\n"); + (void) fprintf(siserr, " -l\t\tactive_low latches only\n"); + (void) fprintf(siserr, " -r\t\trising_edge latches only\n"); + (void) fprintf(siserr, " -G\t\tprint library gate params\n"); + return 1; +#else + if (argc == 1) { + lib_dump(sisout, lib_get_library(), /* detail */ 0); + + } else if (argc == 2) { + net1 = read_eqn_string(argv[1]); + if (net1 == 0) { + fprintf(siserr, "%s", error_string()); + return 1; + } + class = lib_get_class(net1, lib_get_library()); + if (class == 0) { + fprintf(siserr, + "print_library: cannot find class for given function\n"); + return 0; + } + lib_dump_class(sisout, class); + network_free(net1); + + } else { + fprintf(siserr, "usage: print_library [function-string]\n"); + return 1; + } + return 0; +#endif +} + + /* extract data from a network. Contribution of Tzvi Ben-Tzur */ + + /* ARGSUSED */ +com_print_map_stats(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + lsGen gen; + int num_out=0, count=0, num_inv=0, num_buf=0; + double area=0.0; + delay_time_t t; + double temp, min_slack, total_slack; + node_t *node; + + if (! lib_network_is_mapped(*network)) { + (void)fprintf(sisout,"Network not mapped\n"); + return 1; + } + assert(delay_trace(*network, DELAY_MODEL_LIBRARY)); + + min_slack= 100000.0; + total_slack = 0.0; + + foreach_node(*network, gen, node){ + if (node->type == INTERNAL){ + count++; + area += lib_gate_area(lib_gate_of(node)); + if (node_function(node) == NODE_INV){ + num_inv++; + } else if (node_function(node) == NODE_BUF){ + num_buf++; + } + } else if (node->type == PRIMARY_OUTPUT){ + t = delay_slack_time(node); + temp = MIN(t.rise, t.fall); + if (temp < 0){ + num_out++; + min_slack = MIN(temp, min_slack); + total_slack += temp; + } + } + } + (void) fprintf(sisout,"Total Area\t\t= %6.2f\n", area); + (void) fprintf(sisout,"Gate Count\t\t= %d\n", count); + (void) fprintf(sisout,"Buffer Count\t\t= %d\n", num_buf); + (void) fprintf(sisout,"Inverter Count \t\t= %d\n", num_inv); + min_slack = (min_slack < 0 ? min_slack : 0); + total_slack = (total_slack < 0 ? total_slack : 0); + (void) fprintf(sisout,"Most Negative Slack\t= %6.2f\n", min_slack); + (void) fprintf(sisout,"Sum of Negative Slacks\t= %6.2f\n", total_slack); + (void) fprintf(sisout,"Number of Critical PO\t= %d\n", num_out); + return 0; +} + + /* reduces depth by clustering using Lawler's algorithm */ + +extern network_t *cluster_under_size_constraint(); +extern network_t *cluster_under_depth_constraint(); +extern network_t *cluster_under_size_as_depth_constraint(); + +com_reduce_depth(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + network_t *new_network; + clust_options_t options; + + /* default */ + options.type = SIZE_CONSTRAINT; + options.relabel = 0; + options.verbose = 0; + options.cluster_size = 8; + options.depth = -1; /* initialized to unspecified */ + options.dup_ratio = 2.0; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "bd:f:rR:s:S:v:g")) != EOF) { + switch(c) { + case 'b': + options.type = BEST_RATIO_CONSTRAINT; + options.relabel = 1; + break; + case 'R': + options.dup_ratio = atof(util_optarg); + if (options.dup_ratio < 1.0 || options.dup_ratio > INFINITY) goto usage; + break; + case 'd': + options.type = DEPTH_CONSTRAINT; + options.depth = atoi(util_optarg); + if (options.depth <= 0) goto usage; + break; + case 'f': + options.type = FANIN_CONSTRAINT; + options.cluster_size = atoi(util_optarg); + if (options.cluster_size <= 1) goto usage; + break; + case 'g': + options.type = CLUSTER_STATISTICS; + break; + case 'r': + options.relabel = 1; + break; + case 's': + options.type = SIZE_CONSTRAINT; + options.cluster_size = atoi(util_optarg); + if (options.cluster_size <= 0) goto usage; + break; + case 'S': + options.type = SIZE_AS_DEPTH_CONSTRAINT; + options.cluster_size = atoi(util_optarg); + if (options.cluster_size <= 0) goto usage; + break; + case 'v': + options.verbose = atoi(util_optarg); + break; + default: + goto usage; + } + } + if (argc - util_optind != 0) goto usage; + new_network = cluster_under_constraint(*network, &options); + if (new_network == NIL(network_t)) return 1; + *network = new_network; + return 0; + usage: + (void) fprintf(miserr, "usage: reduce_depth [-S n | -s n | -f n | -d n | -b | -g] [-R n.n] [-r] [-v n]\n"); + (void) fprintf(miserr, " -S n=max_cluster_size\tmaximum value of cluster_size; pick up the smallest one yielding the same depth\n"); + (void) fprintf(miserr, " -s n=cluster_size\tmaximum number of nodes in a cluster (Default = 8)\n"); + (void) fprintf(miserr, " -f n=fanin\tmaximum number of inputs (fanins) for a cluster\n"); + (void) fprintf(miserr, " -d n=max_level\tmaximum level of nodes in final network\n"); + (void) fprintf(miserr, " -b\tuses the best cluster size for dup ratio less than specified with -R\n"); + (void) fprintf(miserr, " -g\tprints out statistics on a cluster size basis; no clustering done\n"); + (void) fprintf(miserr, " -R n.n\tspecifies max dup ratio; default 2.0\n"); + (void) fprintf(miserr, " -r\trelabeling to reduce logic duplication without increasing # levels\n"); + (void) fprintf(miserr, " -v n=verbosity_level\tdebug mode\n"); + return 1; +} + + /* timeout command: set up an alarm and send an interrupt to the process */ + /* when alarm is raised. With "-k" option, forces a fault and kill the process */ + +#include <signal.h> +static void timeout_interrupt() +{ + int pid = getpid(); + + fprintf(siserr, "time out has occurred: process %d interrupted\n", pid); + kill(pid, SIGINT); +} +static void timeout_kill() +{ + int pid = getpid(); + + fprintf(siserr, "time out has occurred: process %d killed\n", pid); + kill(pid, SIGKILL); +} +static void timeout_noop() +{} + + /* ARGSUSED */ +static int +com_timeout(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + int timeout; + int kill_process = 0; + + if (argc == 1) { + (void) signal(SIGALRM, timeout_noop); + return 0; + } + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "t:k")) != EOF) { + switch(c) { + case 't': + timeout = atoi(util_optarg); + if (timeout <= 0 || timeout > 365 * 24 * 3600) goto usage; + break; + case 'k': + kill_process = 1; + break; + default: + goto usage; + } + } + if (kill_process) { + (void) signal(SIGALRM, timeout_kill); + } else { + (void) signal(SIGALRM, timeout_interrupt); + } + (void) alarm(timeout); + return 0; + usage: + (void) fprintf(siserr, "usage: timeout [-t time_limit (seconds)] [-k]\n"); + (void) fprintf(siserr, " -k\t kill the process instead of coming back to the prompt\n"); + return 1; + +} + + /* ARGSUSED */ + +static int +com_check_load_limit(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i, j; + lsGen gen, gen2; + node_t *node; + array_t *nodevec; + int index; + node_t *fanin, *fanout; + double load, max_load; + + foreach_node(*network, gen, node) { + if (node->type == PRIMARY_OUTPUT) continue; + if (node->type == PRIMARY_INPUT) continue; +#if defined(_IBMR2) || defined(__osf__) + if (MAP(node) == NIL(alt_map_t)) { +#else + if (MAP(node) == NIL(map_t)) { +#endif /* _IBMR2, __osf__ */ + (void) fprintf(siserr, "network not mapped\n"); + return 1; + } + /* needs to be modified to take into account the correct info */ + MAP(node)->load = 0.0; + } + + /* write a piece of code that allocates what is necessary */ + nodevec = network_dfs(*network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type == PRIMARY_OUTPUT) { + fanin = node_get_fanin(node, 0); + /* need to be computed properly */ + if (fanin->type != PRIMARY_INPUT) { + MAP(fanin)->load += 0.0; + } + } else { + foreach_fanin(node, index, fanin) { + if (fanin->type != PRIMARY_INPUT) { + MAP(fanin)->load += delay_get_load(MAP(node)->gate->delay_info[index]); + } + } + } + } + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + if (node_num_fanin(node) == 0) continue; /* skip constants for now */ + max_load = delay_get_load_limit(MAP(node)->gate->delay_info[0]); + if (MAP(node)->load > max_load) { + (void) fprintf(sisout, "Load at node %s for gate %s exceeded: allowed %2.3f actual %2.3f\n", + node->name, MAP(node)->gate->name, + max_load, + MAP(node)->load); + } + } + array_free(nodevec); + + /* check for PI load limit violations */ + foreach_primary_input(*network, gen, node) { + load = 0.0; + foreach_fanout(node, gen2, fanout) { + foreach_fanin(fanout, j, fanin) { + if (fanin == node) break; + } + if (node_type(fanout) != PRIMARY_OUTPUT) { + assert(MAP(fanout)->gate != NIL(lib_gate_t)); + load += delay_get_load(MAP(fanout)->gate->delay_info[j]); + } else { + load += pipo_get_po_load(fanout); + } + } + max_load = pipo_get_pi_load_limit(node); + if (load > max_load) { + (void) fprintf(sisout, "Load at PI %s exceeded: allowed %2.3f actual %2.3f\n", + node_name(node), max_load, load); + } + } + return 0; +} + +init_map() +{ + com_add_command("replace", com_replace, /* changes_network */ 1); + com_add_command("reduce_depth", com_reduce_depth, /* changes_network */ 1); + com_add_command("map", com_map, /* changes_network */ 1); + com_add_command("_build_map", com_build_map, /* changes_network */ 1); + com_add_command("_tree_map", com_tree_map, /* changes_network */ 1); + com_add_command("_fanout_opt", com_fanout_opt, /* changes_network */ 1); + com_add_command("fanout_alg", com_fanout_alg, /* changes_network */ 0); + com_add_command("fanout_param", com_fanout_param, /* changes_network */ 0); + com_add_command("read_library", com_read_library, /* changes_network */ 0); + com_add_command("print_gate", com_print_gate, /* changes_network */ 0); + com_add_command("print_library", com_print_library, /*changes_network*/ 0); + com_add_command("print_map_stats", com_print_map_stats, 0); + com_add_command("_dump_patterns", com_dump_patterns, /*changes_network*/ 0); + com_add_command("_addinv", com_map_addinv, /* changes_network */ 1); + com_add_command("_eat_buffer", com_eat_buffer, /* changes_network */ 1); + com_add_command("_reminv", com_map_reminv, /* changes_network */ 1); + com_add_command("_treesize", com_treesize, /* changes_network */ 0); + com_add_command("_premap", com_premap, /* changes_network */ 1); + com_add_command("_buffer", com_buffer, /* changes_network */ 1); + com_add_command("timeout", com_timeout, /* changes_network */ 0); + com_add_command("_check_load_limit", com_check_load_limit, /* changes_network */ 0); + + node_register_daemon(DAEMON_FREE, map_free); + node_register_daemon(DAEMON_INVALID, map_invalid); + node_register_daemon(DAEMON_DUP, map_dup); + +#ifdef SIS + /* store gate types in the library */ + /* used in library.c and prim.c */ + network_type_table = st_init_table(strcmp, st_strhash); +#endif /* SIS */ +} + +end_map() +{ + int i; + fanout_alg_t *alg; + st_generator *gen; + char *key, *value; + + if (lib_current_library != 0) { + lib_free(lib_current_library); + } + if (current_fanout_alg != NIL(array_t)) { + for (i = 0; i < array_n(current_fanout_alg); i++) { + alg = array_fetch_p(fanout_alg_t, current_fanout_alg, i); + if (alg->properties != NIL(array_t)) { + array_free(alg->properties); + } + } + array_free(current_fanout_alg); + } + +#ifdef SIS + /* free gate types */ + st_foreach_item(network_type_table, gen, &key, &value) { + FREE(key); + FREE(value); + } + st_free_table(network_type_table); +#endif /* SIS */ +} + + +#ifdef SIS +/* Sequential support */ +static void +map_latch_table_dup(old, new) +network_t *old, *new; +{ + lsGen gen; + node_t *po, *new_po; + node_t *pi, *new_pi; + latch_t *latch, *old_latch; + + /* Allocations */ + if (new->latch_table == NIL(st_table)) { + new->latch_table = st_init_table(st_ptrcmp, st_ptrhash); + } + if (new->latch == 0) { + new->latch = lsCreate(); + } + + /* + * Generate the po from the old network and add determine + * the correspondence by name. Then add to table. + */ + foreach_latch(old, gen, old_latch) { + po = latch_get_input(old_latch); + pi = latch_get_output(old_latch); + new_po = network_find_node(new, po->name); + new_pi = network_find_node(new, pi->name); + network_create_latch(new, &latch, new_po, new_pi); + latch_set_initial_value(latch, latch_get_initial_value(old_latch)); + latch_set_current_value(latch, latch_get_current_value(old_latch)); + latch_set_type(latch, latch_get_type(old_latch)); + latch_set_gate(latch, lib_gate_of(node_get_fanin(new_po, 0))); + latch_set_control(latch, map_copy_clock(new, old_latch)); + } + new->stg = stg_dup(old->stg); + network_clock_dup(old, new); +} + +/* copy the nodes associated with clock + * for gated clocks - easy (all the nodes are mapped + * and thus present in the new_network) + * for non-gated clocks - no internal node (need to + * create a PI/PO pair in the new network) + */ +static node_t* +map_copy_clock(new_network, old_latch) +network_t *new_network; +latch_t *old_latch; +{ + node_t *old_clock, *old_clock_fanin; + node_t *new_clock, *new_clock_fanin; + node_t **new_fanin; + + old_clock = latch_get_control(old_latch); + if (old_clock == NIL(node_t)) return NIL(node_t); + new_clock = network_find_node(new_network, old_clock->name); + if (new_clock != NIL(node_t)) return new_clock; + + /* make sure that there exists a PI/PO pair in the old network */ + assert(node_type(old_clock) == PRIMARY_OUTPUT && node_num_fanin(old_clock) == 1); + old_clock_fanin = node_get_fanin(old_clock, 0); + assert(node_type(old_clock_fanin) == PRIMARY_INPUT); + + /* check if clock fanin node already exists */ + new_clock_fanin = network_find_node(new_network, old_clock_fanin->name); + if (new_clock_fanin == NIL(node_t)) { + new_clock_fanin = node_dup(old_clock_fanin); + network_add_primary_input(new_network, new_clock_fanin); + } + new_fanin = ALLOC(node_t *, 1); + new_fanin[0] = new_clock_fanin; + new_clock = node_dup(old_clock); + node_replace_internal(new_clock, new_fanin, 1, NIL(set_family_t)); + network_add_node(new_network, new_clock); + return new_clock; +} + +#endif diff --git a/sis/map/fanout_alg.h b/sis/map/fanout_alg.h new file mode 100644 index 0000000..51c6767 --- /dev/null +++ b/sis/map/fanout_alg.h @@ -0,0 +1,36 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_alg.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_alg.h 1.4 */ +/* last modified on 7/2/91 at 19:44:21 */ +/* + * $Log: fanout_alg.h,v $ + * Revision 1.1.1.1 2004/02/07 10:14:24 pchong + * imported + * + * Revision 1.2 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.1 1992/04/17 21:50:04 sis + * Initial revision + * + * Revision 1.1 1992/04/17 21:50:04 sis + * Initial revision + * + * Revision 1.1 92/01/08 17:40:34 sis + * Initial revision + * + */ +#ifndef FANOUT_ALG_H +#define FANOUT_ALG_H + +#include "fanout_alg_macro.h" +#undef use + +#endif diff --git a/sis/map/fanout_alg_macro.h b/sis/map/fanout_alg_macro.h new file mode 100644 index 0000000..082e682 --- /dev/null +++ b/sis/map/fanout_alg_macro.h @@ -0,0 +1,34 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_alg_macro.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_alg_macro.h 1.3 */ +/* last modified on 6/28/91 at 17:21:06 */ + + /* Functions to initialize fanout optimization algorithms. */ + +extern void noalg_init(); +extern void lt_trees_init(); +extern void two_level_init(); +extern void fanout_dump_init(); +extern void mixed_lt_trees_init(); +extern void bottom_up_init(); +extern void balanced_init(); +extern void top_down_init(); + + /* Functions to update fanout optimization properties. */ + +extern void fanout_opt_update_size_threshold(); +extern void fanout_opt_update_peephole_flag(); +extern void lt_trees_set_max_n_gaps(); +extern void fanout_dump_set_dump_threshold(); +extern void mixed_lt_trees_set_max_n_gaps(); +extern void mixed_lt_trees_set_max_x_index(); +extern void mixed_lt_trees_set_max_y_index(); +extern void top_down_set_mode(); +extern void top_down_set_debug(); diff --git a/sis/map/fanout_delay.c b/sis/map/fanout_delay.c new file mode 100644 index 0000000..3387dee --- /dev/null +++ b/sis/map/fanout_delay.c @@ -0,0 +1,799 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_delay.c 1.8 */ +/* last modified on 7/3/91 at 14:51:37 */ +/* + * $Log: fanout_delay.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:24 pchong + * imported + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 21:53:13 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:40:35 sis + * Initial revision + * + * Revision 1.3 91/07/02 10:52:13 touati + * add support to check for load_limit violations. + * when violated, load is multiplied by a prespecified constant value. + * + * Revision 1.2 91/06/29 22:54:36 touati + * added support for non-inverting buffers. + * + * Revision 1.1 91/06/28 22:17:20 touati + * Initial revision + * + */ +#include "sis.h" +#include <math.h> +#include "map_int.h" +#include "fanout_int.h" +#include "fanout_delay.h" +#include "bin_int.h" + +typedef enum buffer_type_enum buffer_type_t; +enum buffer_type_enum {BUFFER_NORMAL, BUFFER_INVERT}; + +typedef struct delay_buffer_struct delay_buffer_t; +struct delay_buffer_struct { + buffer_type_t type; + double area; + double load; + delay_time_t alpha; + delay_time_t beta; + lib_gate_t *gate; +}; + +typedef enum source_type_enum source_type_t; +enum source_type_enum {SOURCE_PI, SOURCE_INTERNAL, SOURCE_PWL}; + +typedef struct delay_pi_struct delay_pi_t; +struct delay_pi_struct { + delay_time_t arrival; + delay_time_t drive; +}; + +typedef struct delay_internal_struct delay_internal_t; +struct delay_internal_struct { + int n_inputs; + char **delay_info; + delay_time_t **arrival_times; +}; + +typedef struct delay_source_struct delay_source_t; +struct delay_source_struct { + source_type_t type; + node_t *node; + int polarity; + delay_pi_t pi; + delay_internal_t internal; + pwl_t *pwl; +}; + +typedef enum gate_type_enum gate_type_t; +enum gate_type_enum {GATE_BUFFER, GATE_SOURCE}; + +typedef struct delay_gate_struct delay_gate_t; +struct delay_gate_struct { + gate_type_t type; + delay_buffer_t buffer; + delay_source_t source; + double load_limit; + DelayFn intrinsic; + DelayFn load_dependent; + DelayFn forward_intrinsic; + DelayFn forward_load_dependent; + PwlFn get_delay_pwl; +}; + +#include "fanout_delay_static.h" + +static n_gates_t n_gates; +static array_t *gate_array; +static bin_global_t globals; + + /* file containing the routines needed for delay estimation */ + /* by the fanout optimizer */ + + /* need code to initialize basic information */ + +void fanout_delay_init(options) +bin_global_t *options; +{ + int i; + library_t *library; + delay_gate_t *buffer; + + globals = *options; + library = lib_get_library(); + assert(library != NIL(library_t)); + gate_array = array_alloc(delay_gate_t *, 0); + add_buffers(library, "f=a;"); + n_gates.n_pos_buffers = array_n(gate_array); + add_buffers(library, "f=!a;"); + n_gates.n_buffers = n_gates.n_neg_buffers = array_n(gate_array); + n_gates.n_pos_sources = n_gates.n_neg_sources = n_gates.n_gates = n_gates.n_buffers; + for (i = 0; i < n_gates.n_buffers; i++) { + buffer = array_fetch(delay_gate_t *, gate_array, i); + delay_gate_initialize(buffer); + } +} + +void fanout_delay_end() +{ + int i; + delay_gate_t *buffer; + + for (i = 0; i < n_gates.n_buffers; i++) { + buffer = array_fetch(delay_gate_t *, gate_array, i); + delay_gate_free(buffer); + } + array_free(gate_array); +} + +void fanout_delay_add_source(source_node, source_polarity) +node_t *source_node; +int source_polarity; +{ + source_type_t type = (source_node->type == PRIMARY_INPUT) ? SOURCE_PI : SOURCE_INTERNAL; + fanout_delay_add_general_source(source_node, source_polarity, type); +} + +void fanout_delay_add_pwl_source(source_node, source_polarity) +node_t *source_node; +int source_polarity; +{ + source_type_t type = (source_node->type == PRIMARY_INPUT) ? SOURCE_PI : SOURCE_PWL; + fanout_delay_add_general_source(source_node, source_polarity, type); +} + + /* for 0 <= i < n_pos_sources, nodes[i] is a positive source */ + /* for n_pos_sources <= i < n_neg_sources, nodes[i] is a negative source */ + /* positive sources should always be added before negative sources */ + +static void fanout_delay_add_general_source(source_node, source_polarity, source_type) +node_t *source_node; +int source_polarity; +source_type_t source_type; +{ + delay_gate_t *source; + if (source_polarity == POLAR_X && n_gates.n_neg_sources > n_gates.n_pos_sources) + fail("fanout_delay_add_source: should add positive sources first"); + + source = ALLOC(delay_gate_t, 1); + source->type = GATE_SOURCE; + source->source.type = source_type; + source->source.node = source_node; + source->source.polarity = source_polarity; + delay_gate_initialize(source); + switch (source_polarity) { + case POLAR_X: + array_insert(delay_gate_t *, gate_array, n_gates.n_pos_sources, source); + n_gates.n_pos_sources++; + n_gates.n_neg_sources++; + n_gates.n_gates++; + break; + case POLAR_Y: + array_insert(delay_gate_t *, gate_array, n_gates.n_neg_sources, source); + n_gates.n_neg_sources++; + n_gates.n_gates++; + break; + default: + fail("illegal polarity in fanout_delay_add_source"); + /* NOTREACHED */ + } +} + +void fanout_delay_free_sources() +{ + int source_index; + delay_gate_t *source; + foreach_source(n_gates, source_index) { + source = array_fetch(delay_gate_t *, gate_array, source_index); + delay_gate_free(source); + } + n_gates.n_pos_sources = n_gates.n_neg_sources = n_gates.n_gates = n_gates.n_buffers; +} + +double fanout_delay_get_buffer_load(gate_index) +int gate_index; +{ + delay_gate_t *buffer = array_fetch(delay_gate_t *, gate_array, gate_index); + assert (buffer->type == GATE_BUFFER); + return buffer->buffer.load; +} + +delay_time_t fanout_delay_backward_intrinsic(required, gate_index) +delay_time_t required; +int gate_index; +{ + delay_gate_t *gate = array_fetch(delay_gate_t *, gate_array, gate_index); + return (*gate->intrinsic)(required, gate); +} + +delay_time_t fanout_delay_backward_load_dependent(required, gate_index, load) +delay_time_t required; +int gate_index; +double load; +{ + delay_gate_t *gate = array_fetch(delay_gate_t *, gate_array, gate_index); + if (globals.check_load_limit && load > gate->load_limit) { + load *= globals.penalty_factor; + } + return (*gate->load_dependent)(required, gate, load); +} + +delay_time_t fanout_delay_forward_intrinsic(arrival, gate_index) +delay_time_t arrival; +int gate_index; +{ + delay_gate_t *gate = array_fetch(delay_gate_t *, gate_array, gate_index); + return (*gate->forward_intrinsic)(arrival, gate); +} + +delay_time_t fanout_delay_forward_load_dependent(arrival, gate_index, load) +delay_time_t arrival; +int gate_index; +double load; +{ + delay_gate_t *gate = array_fetch(delay_gate_t *, gate_array, gate_index); + if (globals.check_load_limit && load > gate->load_limit) { + load *= globals.penalty_factor; + } + return (*gate->forward_load_dependent)(arrival, gate, load); +} + + /* this arrival time is after intrinsic has been computed, but before load dependent part */ + /* thus there is no need to worry about inversion. If gate_index is a gate, arrival should be */ + /* equal to ZERO_DELAY. */ + /* the load argument is necessary in case we need to handle a pwl source: we need to choose */ + /* which gate to use before returning the delay_pwl_t for that gate. */ + +delay_pwl_t fanout_delay_get_delay_pwl(gate_index, load, arrival) +int gate_index; +double load; +delay_time_t arrival; +{ + delay_gate_t *gate = array_fetch(delay_gate_t *, gate_array, gate_index); + return (*gate->get_delay_pwl)(gate, load, arrival); +} + + + /* used only by "two_level.c" */ + +int compute_best_number_of_inverters(source_index, buffer_index, load, max_n) +int source_index; /* index of the source gate (can be a buffer) */ +int buffer_index; /* index of the buffer gate */ +double load; /* total load for the two level tree; incorporates wire loads for max_n wires */ +int max_n; /* maximum number of intermediate nodes */ +{ + int from, to; + + if (source_index < n_gates.n_buffers) { + delay_time_t a, b, c; + delay_gate_t *source = array_fetch(delay_gate_t *, gate_array, source_index); + delay_gate_t *buffer = array_fetch(delay_gate_t *, gate_array, buffer_index); + + assert(source->type == GATE_BUFFER && buffer->type == GATE_BUFFER); + a.rise = source->buffer.beta.rise * (buffer->buffer.load + map_compute_wire_load(1)); + a.fall = source->buffer.beta.fall * (buffer->buffer.load + map_compute_wire_load(1)); + switch (buffer->buffer.type) { + case BUFFER_NORMAL: + b.rise = buffer->buffer.beta.rise * load; + b.fall = buffer->buffer.beta.fall * load; + break; + case BUFFER_INVERT: + b.rise = buffer->buffer.beta.fall * load; + b.fall = buffer->buffer.beta.rise * load; + break; + default: + fail("unexpected buffer type"); + /* NOTREACHED */ + } + if (FP_EQUAL(a.rise, 0.0)) { + c.rise = max_n; + } else { + c.rise = sqrt(b.rise / a.rise); + } + if (FP_EQUAL(a.fall, 0.0)) { + c.fall = max_n; + } else { + c.fall = sqrt(b.fall / a.fall); + } + from = (int) floor(GETMIN(c)); + to = (int) floor(GETMAX(c) + 1); + if (to > max_n) to = max_n; + if (from <= 0) from = 1; + if (from > to) from = to; + } else { + from = 1; + to = max_n; + } + return linear_search_best_number_of_inverters(source_index, buffer_index, load, max_n, from, to); +} + + +n_gates_t fanout_delay_get_n_gates() +{ + return n_gates; +} + +double fanout_delay_get_area(gate_index) +int gate_index; +{ + delay_gate_t *delay_gate = array_fetch(delay_gate_t *, gate_array, gate_index); + return (delay_gate->type == GATE_BUFFER) ? delay_gate->buffer.area : 0.0; +} + +node_t *fanout_delay_get_source_node(source_index) +int source_index; +{ + delay_gate_t *delay_gate = array_fetch(delay_gate_t *, gate_array, source_index); + assert(delay_gate->type == GATE_SOURCE); + return delay_gate->source.node; +} + +lib_gate_t *fanout_delay_get_gate(gate_index) +int gate_index; +{ + delay_gate_t *delay_gate = array_fetch(delay_gate_t *, gate_array, gate_index); + assert(delay_gate->type == GATE_BUFFER); + return delay_gate->buffer.gate; +} + +int fanout_delay_get_source_polarity(source_index) +int source_index; +{ + delay_gate_t *delay_gate = array_fetch(delay_gate_t *, gate_array, source_index); + assert(delay_gate->type == GATE_SOURCE); + return delay_gate->source.polarity; +} + +int fanout_delay_get_buffer_polarity(buffer_index) +int buffer_index; +{ + delay_gate_t *delay_gate = array_fetch(delay_gate_t *, gate_array, buffer_index); + assert(delay_gate->type == GATE_BUFFER); + return (delay_gate->buffer.type == BUFFER_NORMAL) ? POLAR_X : POLAR_Y; +} + +int fanout_delay_get_buffer_index(buffer) +lib_gate_t *buffer; +{ + int i; + delay_gate_t *delay_gate; + + for (i = 0; i < array_n(gate_array); i++) { + delay_gate = array_fetch(delay_gate_t *, gate_array, i); + if (delay_gate->type != GATE_BUFFER) continue; + if (delay_gate->buffer.gate == buffer) return i; + } + return -1; +} + +int fanout_delay_get_source_index(source) +node_t *source; +{ + int i; + delay_gate_t *delay_gate; + + for (i = 0; i < array_n(gate_array); i++) { + delay_gate = array_fetch(delay_gate_t *, gate_array, i); + if (delay_gate->type != GATE_SOURCE) continue; + if (delay_gate->source.node == source) return i; + } + return -1; +} + + + /* INTERNAL INTERFACE */ + +static void add_buffers(library, string) +library_t *library; +char *string; +{ + lsGen gen; + lib_gate_t *gate; + network_t *network; + lib_class_t *class; + + network = read_eqn_string(string); + if (network == NIL(network_t)) return; + class = lib_get_class(network, library); + if (class == NIL(lib_class_t)) { + network_free(network); + return; + } + gen = lib_gen_gates(class); + while (lsNext(gen, (char **) &gate, LS_NH) == LS_OK) { + delay_gate_t *buffer; + buffer = ALLOC(delay_gate_t, 1); + array_insert_last(delay_gate_t *, gate_array, buffer); + buffer->type = GATE_BUFFER; + buffer->buffer.gate = gate; + } + (void) lsFinish(gen); + network_free(network); +} + +static void delay_gate_initialize(delay_gate) +delay_gate_t *delay_gate; +{ + int i; + lib_gate_t *gate; + node_t *node; + + switch (delay_gate->type) { + case GATE_BUFFER: + gate = delay_gate->buffer.gate; + assert(gate != NIL(lib_gate_t)); + delay_gate->load_limit = delay_get_load_limit(gate->delay_info[0]); + delay_gate->buffer.area = gate->area; + delay_gate->buffer.load = delay_get_load(gate->delay_info[0]); + delay_gate->buffer.alpha = delay_get_block(gate->delay_info[0]); + delay_gate->buffer.beta = delay_get_drive(gate->delay_info[0]); + switch (delay_get_polarity(gate->delay_info[0])) { + case PHASE_INVERTING: + delay_gate->buffer.type = BUFFER_INVERT; + delay_gate->intrinsic = delay_intrinsic_neg_buffer; + delay_gate->load_dependent = delay_load_dependent_buffer; + delay_gate->forward_intrinsic = delay_forward_intrinsic_neg_buffer; + delay_gate->forward_load_dependent = delay_forward_load_dependent_buffer; + delay_gate->get_delay_pwl = delay_get_delay_pwl_buffer; + break; + case PHASE_NONINVERTING: + delay_gate->buffer.type = BUFFER_NORMAL; + delay_gate->intrinsic = delay_intrinsic_pos_buffer; + delay_gate->load_dependent = delay_load_dependent_buffer; + delay_gate->forward_intrinsic = delay_forward_intrinsic_pos_buffer; + delay_gate->forward_load_dependent = delay_forward_load_dependent_buffer; + delay_gate->get_delay_pwl = delay_get_delay_pwl_buffer; + break; + default: + fail("unexpected pin polarity"); + /* NOTREACHED */ + } + break; + case GATE_SOURCE: + node = delay_gate->source.node; + assert(node != NIL(node_t)); + switch (delay_gate->source.type) { + case SOURCE_PI: + delay_gate->source.type = SOURCE_PI; + delay_gate->load_limit = pipo_get_pi_load_limit(node); + delay_gate->source.pi.arrival = pipo_get_pi_arrival(node); + delay_gate->source.pi.drive = pipo_get_pi_drive(node); + delay_gate->intrinsic = delay_intrinsic_fatal_error; + delay_gate->load_dependent = delay_load_dependent_pi_source; + delay_gate->forward_intrinsic = delay_intrinsic_fatal_error; + delay_gate->forward_load_dependent = delay_forward_load_dependent_pi_source; + delay_gate->get_delay_pwl = delay_get_delay_pwl_pi; + break; + case SOURCE_INTERNAL: + delay_gate->source.type = SOURCE_INTERNAL; + assert(MAP(node)->gate != NIL(lib_gate_t)); + assert(MAP(node)->ninputs > 0); + delay_gate->load_limit = delay_get_load_limit(MAP(node)->gate->delay_info[0]); + delay_gate->source.internal.n_inputs = MAP(node)->ninputs; + delay_gate->source.internal.delay_info = MAP(node)->gate->delay_info; + delay_gate->source.internal.arrival_times = ALLOC(delay_time_t *, MAP(node)->ninputs); + for (i = 0; i < MAP(node)->ninputs; i++) { + delay_gate->source.internal.arrival_times[i] = &(MAP(node)->arrival_info[i]); + } + delay_gate->intrinsic = delay_intrinsic_fatal_error; + delay_gate->load_dependent = delay_load_dependent_internal_source; + delay_gate->forward_intrinsic = delay_intrinsic_fatal_error; + delay_gate->forward_load_dependent = delay_forward_load_dependent_internal_source; + delay_gate->get_delay_pwl = delay_get_delay_pwl_internal_source; + break; + case SOURCE_PWL: + node = delay_gate->source.node; + assert(node != NIL(node_t)); + assert(node->type != PRIMARY_INPUT); + assert(BIN(node) != NIL(bin_t)); + delay_gate->load_limit = INFINITY; + delay_gate->source.type = SOURCE_PWL; + delay_gate->source.pwl = BIN(node)->pwl; + delay_gate->intrinsic = delay_intrinsic_fatal_error; + delay_gate->load_dependent = delay_load_dependent_pwl_source; + delay_gate->forward_intrinsic = delay_intrinsic_fatal_error; + delay_gate->forward_load_dependent = delay_forward_load_dependent_pwl_source; + delay_gate->get_delay_pwl = delay_get_delay_pwl_pwl_source; + break; + default: + fail("unexpected delay_gate type"); + break; + } + break; + default: + fail("unexpected delay_gate type"); + break; + } +} + +static void delay_gate_free(delay_gate) +delay_gate_t *delay_gate; +{ + switch (delay_gate->type) { + case GATE_BUFFER: + break; + case GATE_SOURCE: + if (delay_gate->source.type == SOURCE_INTERNAL) { + FREE(delay_gate->source.internal.arrival_times); + } + break; + default: + fail("unexpected delay_gate type"); + /* NOTREACHED */ + } + FREE(delay_gate); +} + +static delay_time_t delay_load_dependent_buffer(required, buffer, load) +delay_time_t required; +delay_gate_t *buffer; +double load; +{ + delay_time_t result; + result.rise = required.rise - buffer->buffer.beta.rise * load; + result.fall = required.fall - buffer->buffer.beta.fall * load; + return result; +} + +static delay_time_t delay_forward_load_dependent_buffer(arrival, buffer, load) +delay_time_t arrival; +delay_gate_t *buffer; +double load; +{ + delay_time_t result; + result.rise = arrival.rise + buffer->buffer.beta.rise * load; + result.fall = arrival.fall + buffer->buffer.beta.fall * load; + return result; +} + +static delay_time_t delay_intrinsic_pos_buffer(required, buffer) +delay_time_t required; +delay_gate_t *buffer; +{ + delay_time_t result; + SETSUB(result, required, buffer->buffer.alpha); + return result; +} + +static delay_time_t delay_forward_intrinsic_pos_buffer(arrival, buffer) +delay_time_t arrival; +delay_gate_t *buffer; +{ + delay_time_t result; + SETADD(result, arrival, buffer->buffer.alpha); + return result; +} + +static delay_time_t delay_intrinsic_neg_buffer(required, buffer) +delay_time_t required; +delay_gate_t *buffer; +{ + delay_time_t result; + result.rise = required.fall - buffer->buffer.alpha.fall; + result.fall = required.rise - buffer->buffer.alpha.rise; + return result; +} + +static delay_time_t delay_forward_intrinsic_neg_buffer(arrival, buffer) +delay_time_t arrival; +delay_gate_t *buffer; +{ + delay_time_t result; + result.rise = arrival.fall + buffer->buffer.alpha.rise; + result.fall = arrival.rise + buffer->buffer.alpha.fall; + return result; +} + +static delay_time_t delay_load_dependent_pi_source(required, source, load) +delay_time_t required; +delay_gate_t *source; +double load; +{ + delay_time_t arrival; + delay_time_t result; + assert(source->type == GATE_SOURCE && source->source.type == SOURCE_PI); + arrival.rise = source->source.pi.drive.rise * load + source->source.pi.arrival.rise; + arrival.fall = source->source.pi.drive.fall * load + source->source.pi.arrival.fall; + SETSUB(result, required, arrival); + return result; +} + +static delay_time_t delay_forward_load_dependent_pi_source(arrival, source, load) +delay_time_t arrival; +delay_gate_t *source; +double load; +{ + assert(source->type == GATE_SOURCE && source->source.type == SOURCE_PI); + assert(IS_EQUAL(arrival, ZERO_DELAY)); + arrival.rise = source->source.pi.drive.rise * load + source->source.pi.arrival.rise; + arrival.fall = source->source.pi.drive.fall * load + source->source.pi.arrival.fall; + return arrival; +} + +static delay_time_t delay_load_dependent_internal_source(required, source, load) +delay_time_t required; +delay_gate_t *source; +double load; +{ + delay_time_t arrival; + delay_time_t result; + delay_internal_t *internal = &(source->source.internal); + + assert(source->type == GATE_SOURCE && source->source.type == SOURCE_INTERNAL); + arrival = delay_map_simulate(internal->n_inputs, internal->arrival_times, internal->delay_info, load); + SETSUB(result, required, arrival); + return result; +} + +static delay_time_t delay_load_dependent_pwl_source(required, source, load) +delay_time_t required; +delay_gate_t *source; +double load; +{ + delay_time_t arrival; + delay_time_t result; + + assert(source->type == GATE_SOURCE && source->source.type == SOURCE_PWL); + arrival = bin_delay_compute_pwl_delay(source->source.pwl, load); + SETSUB(result, required, arrival); + return result; +} + +static delay_time_t delay_forward_load_dependent_internal_source(arrival, source, load) +delay_time_t arrival; +delay_gate_t *source; +double load; +{ + delay_internal_t *internal = &(source->source.internal); + + assert(source->type == GATE_SOURCE && source->source.type == SOURCE_INTERNAL); + assert(IS_EQUAL(arrival, ZERO_DELAY)); + arrival = delay_map_simulate(internal->n_inputs, internal->arrival_times, internal->delay_info, load); + return arrival; +} + +static delay_time_t delay_forward_load_dependent_pwl_source(arrival, source, load) +delay_time_t arrival; +delay_gate_t *source; +double load; +{ + assert(source->type == GATE_SOURCE && source->source.type == SOURCE_PWL); + assert(IS_EQUAL(arrival, ZERO_DELAY)); + return bin_delay_compute_pwl_delay(source->source.pwl, load); +} + + /* ARGSUSED */ +static delay_time_t delay_intrinsic_fatal_error(required, buffer) +delay_time_t required; +delay_gate_t *buffer; +{ + fail("attempt to compute the intrinsic of a source"); + /* NOTREACHED */ +} + + /* ARGSUSED */ +static delay_pwl_t delay_get_delay_pwl_internal_source(gate, load, arrival) +delay_gate_t *gate; +double load; +delay_time_t arrival; +{ + int i; + node_t *source; + int ninputs; + pin_info_t *pin_info; + delay_pwl_t result; + + assert(IS_EQUAL(arrival, ZERO_DELAY)); + assert(gate->type == GATE_SOURCE && gate->source.type == SOURCE_INTERNAL); + source = gate->source.node; + ninputs = MAP(source)->ninputs; + pin_info = ALLOC(pin_info_t, ninputs); + for (i = 0; i < ninputs; i++) { + pin_info[i].arrival = *gate->source.internal.arrival_times[i]; + } + result = bin_delay_compute_gate_pwl(MAP(source)->gate, ninputs, pin_info); + FREE(pin_info); + return result; +} + + /* ARGSUSED */ +static delay_pwl_t delay_get_delay_pwl_pwl_source(gate, load, arrival) +delay_gate_t *gate; +double load; +delay_time_t arrival; +{ + delay_pwl_t result; + + assert(IS_EQUAL(arrival, ZERO_DELAY)); + assert(gate->type == GATE_SOURCE && gate->source.type == SOURCE_PWL); + result = bin_delay_select_active_pwl_delay(gate->source.pwl, load); + result.rise = pwl_dup(result.rise); + result.fall = pwl_dup(result.fall); + pwl_set_data(result.rise, NIL(char)); + pwl_set_data(result.fall, NIL(char)); + return result; +} + + /* ARGSUSED */ +static delay_pwl_t delay_get_delay_pwl_pi(gate, load, arrival) +delay_gate_t *gate; +double load; +delay_time_t arrival; +{ + assert(IS_EQUAL(arrival, ZERO_DELAY)); + assert(gate->type == GATE_SOURCE && gate->source.type == SOURCE_PI); + return bin_delay_get_pi_delay_pwl(gate->source.node); +} + + /* ARGSUSED */ +static delay_pwl_t delay_get_delay_pwl_buffer(gate, load, arrival) +delay_gate_t *gate; +double load; +delay_time_t arrival; +{ + delay_pwl_t result; + pwl_point_t rise_point, fall_point; + + assert(gate->type == GATE_BUFFER); + rise_point.x = 0.0; + rise_point.y = arrival.rise; + rise_point.slope = gate->buffer.beta.rise; + rise_point.data = NIL(char); + fall_point.x = 0.0; + fall_point.y = arrival.fall; + fall_point.slope = gate->buffer.beta.fall; + fall_point.data = NIL(char); + result.rise = pwl_create_linear_max(1, &rise_point); + result.fall = pwl_create_linear_max(1, &fall_point); + return result; +} + +static int linear_search_best_number_of_inverters(source_index, buffer_index, load, max_n, from, to) +int source_index; /* index of the source gate (can be a buffer) */ +int buffer_index; /* index of the buffer gate */ +double load; /* total load for the two level tree; incorporates wire loads for max_n wires */ +int max_n; /* maximum number of intermediate nodes */ +int from; +int to; +{ + int i; + delay_time_t required; + delay_gate_t *buffer = array_fetch(delay_gate_t *, gate_array, buffer_index); + int k = -1; + + assert(from <= to && from > 0 && to <= max_n); + if (from == to) return from; + required = MINUS_INFINITY; + for (i = from; i <= to; i++) { + double local_load; + delay_time_t local_required; + local_required = fanout_delay_backward_load_dependent(ZERO_DELAY, buffer_index, load / i); + local_required = fanout_delay_backward_intrinsic(local_required, buffer_index); + local_load = buffer->buffer.load * i + map_compute_wire_load(i); + local_required = fanout_delay_backward_load_dependent(local_required, source_index, local_load); + if (GETMIN(required) < GETMIN(local_required)) { + required = local_required; + k = i; + } + } + assert(k >= 0); + return k; +} diff --git a/sis/map/fanout_delay.h b/sis/map/fanout_delay.h new file mode 100644 index 0000000..5f7b9fc --- /dev/null +++ b/sis/map/fanout_delay.h @@ -0,0 +1,59 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_delay.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_delay.h 1.2 */ +/* last modified on 5/1/91 at 15:50:30 */ +#include "map_delay.h" +#include "pwl.h" + +typedef delay_time_t (*DelayFn)(); +typedef delay_pwl_t (*PwlFn)(); + +typedef struct n_gates_struct n_gates_t; +struct n_gates_struct { + int n_pos_buffers; /* indices for pos_buffers are: [0, n_pos_buffers( */ + int n_neg_buffers; /* indices for neg_buffers are: [n_pos_buffers,n_neg_buffers( */ + int n_buffers; /* n_buffers always == to n_neg_buffers */ + int n_pos_sources; /* indices for pos_sources are: [n_buffers,n_pos_sources( */ + int n_neg_sources; /* indices for neg_sources are: [n_pos_sources,n_neg_sources( */ + int n_gates; /* n_gates always == to n_neg_sources */ +}; + +extern void fanout_delay_init(/* */); +extern void fanout_delay_end(/* */); +extern void fanout_delay_add_source(/* node_t *source, int source_polarity */); +extern void fanout_delay_init_sources(/* */); +extern void fanout_delay_free_sources(/* */); +extern double fanout_delay_get_buffer_load(/* int gate_index */); +extern delay_time_t fanout_delay_backward_intrinsic(/* delay_time_t required, int gate_index */); +extern delay_time_t fanout_delay_backward_load_dependent(/* delay_time_t required, int gate_index, double load */); +extern delay_time_t fanout_delay_forward_intrinsic(/* delay_time_t arrival, int gate_index */); +extern delay_time_t fanout_delay_forward_load_dependent(/* delay_time_t arrival, int gate_index, double load */); +extern int compute_best_number_of_inverters(/* int source_index, int buffer_index, double load, int max_int_nodes */); +extern n_gates_t fanout_delay_get_n_gates(/* */); +extern double fanout_delay_get_area(/* int gate_index */); +extern node_t *fanout_delay_get_source_node(/* int gate_index */); +extern lib_gate_t *fanout_delay_get_gate(/* int gate_index */); +extern int fanout_delay_get_source_polarity(/* int source_index */); +extern int fanout_delay_get_buffer_polarity(/* int buffer_index */); + +extern int fanout_delay_get_buffer_index(/* lib_gate_t *buffer */); +extern int fanout_delay_get_source_index(/* node_t *node */); + +extern void fanout_delay_add_pwl_source(/* node_t *source, int source_polarity */); +extern delay_pwl_t fanout_delay_get_delay_pwl(/* int gate_index, delay_time_t arrival */); + +#define foreach_buffer(n_gates,gate) for((gate)=0; (gate)<(n_gates).n_buffers; (gate)++) +#define foreach_inverter(n_gates,gate) for((gate)=(n_gates).n_pos_buffers; (gate)<(n_gates).n_buffers; (gate)++) +#define foreach_source(n_gates,gate) for((gate)=(n_gates).n_buffers; (gate)<(n_gates).n_gates; (gate)++) +#define foreach_gate(n_gates,gate) for((gate)=0; (gate)<(n_gates).n_gates; (gate)++) + +#define is_source(n_gates,gate) ((gate) >= (n_gates).n_buffers && (gate) < (n_gates).n_gates) +#define is_buffer(n_gates,gate) ((gate) >= 0 && (gate) < (n_gates).n_buffers) +#define is_inverter(n_gates,gate) ((gate) >= (n_gates).n_pos_buffers && (gate) < (n_gates).n_buffers) diff --git a/sis/map/fanout_delay_static.h b/sis/map/fanout_delay_static.h new file mode 100644 index 0000000..b531e40 --- /dev/null +++ b/sis/map/fanout_delay_static.h @@ -0,0 +1,33 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_delay_static.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_delay_static.h 1.2 */ +/* last modified on 5/1/91 at 15:50:32 */ +static delay_pwl_t delay_get_delay_pwl_buffer(); +static delay_pwl_t delay_get_delay_pwl_internal_source(); +static delay_pwl_t delay_get_delay_pwl_pi(); +static delay_pwl_t delay_get_delay_pwl_pwl_source(); +static delay_time_t delay_forward_intrinsic_neg_buffer(); +static delay_time_t delay_forward_intrinsic_pos_buffer(); +static delay_time_t delay_forward_load_dependent_buffer(); +static delay_time_t delay_forward_load_dependent_internal_source(); +static delay_time_t delay_forward_load_dependent_pi_source(); +static delay_time_t delay_forward_load_dependent_pwl_source(); +static delay_time_t delay_intrinsic_fatal_error(); +static delay_time_t delay_intrinsic_neg_buffer(); +static delay_time_t delay_intrinsic_pos_buffer(); +static delay_time_t delay_load_dependent_buffer(); +static delay_time_t delay_load_dependent_internal_source(); +static delay_time_t delay_load_dependent_pi_source(); +static delay_time_t delay_load_dependent_pwl_source(); +static int linear_search_best_number_of_inverters(); +static void add_buffers(); +static void delay_gate_free(); +static void delay_gate_initialize(); +static void fanout_delay_add_general_source(); diff --git a/sis/map/fanout_dump.c b/sis/map/fanout_dump.c new file mode 100644 index 0000000..09c3d04 --- /dev/null +++ b/sis/map/fanout_dump.c @@ -0,0 +1,211 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_dump.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_dump.c 1.2 */ +/* last modified on 5/1/91 at 15:50:22 */ +#include <stdio.h> +#include "sis.h" +#include "map_int.h" +#include "lib_int.h" +#include "map_delay.h" +#include "fanout_int.h" +#include "fanout_delay.h" + +static int do_fanout_dump(); +static network_t *extract_fanout_network(); +static node_t *add_inverter_to_source(); +static void add_sinks(); +static void add_source_to_network(); + + + /* uses the same interface as a fanout optimizer */ + /* but actually dumps each fanout problem individually */ + /* into a blif file */ + /* the blif files are generated in sequence */ + +static char *current_network_name; + +void fanout_dump_init(network, alg) +network_t *network; +fanout_alg_t *alg; +{ + current_network_name = network_name(network); + alg->optimize = do_fanout_dump; +} + +static int DUMP_THRESHOLD = 40; + + /* ARGSUSED */ +void fanout_dump_set_dump_threshold(alg, property) +fanout_alg_t *alg; +alg_property_t *property; +{ + DUMP_THRESHOLD = property->value; +} + + + /* INTERNAL INTERFACE */ + + /* ARGSUSED */ + +static int do_fanout_dump(fanout_info, tree, cost) +opt_array_t *fanout_info; /* fanout_info[POLAR_X] lists the positive polarity sinks; POLAR_Y negative */ +array_t *tree; /* array in which the result tree is stored: format of fanout_tree.c */ +fanout_cost_t *cost; /* contains information on the result: required times, area */ +{ + static uniq_id = 0; + char *filename, *p; + network_t *network; + FILE *fp; + + cost->slack = MINUS_INFINITY; + cost->area = INFINITY; + network = extract_fanout_network(fanout_info); + if (network) { + if (current_network_name == NIL(char)) + current_network_name = "debug"; + filename = ALLOC(char, strlen(current_network_name) + 20); + sprintf(filename, "%s.%d.fanout", current_network_name, uniq_id); + p = strrchr(filename, '/'); + p = (p != NIL(char)) ? p + 1 : filename; + if ((fp = fopen(p, "w")) == NULL) { + fprintf(siserr, "can't open file %s\n", filename); + } else { + network_set_name(network, filename); + write_blif(fp, network, 0, 1); + (void) fclose(fp); + uniq_id++; + } + FREE(filename); + network_free(network); + } + return 0; +} + +static network_t *extract_fanout_network(fanout_info) +opt_array_t *fanout_info; +{ + int source_polarity; + node_t *source, *inverter; + network_t *network; + + if (fanout_info[POLAR_X].n_elts + fanout_info[POLAR_Y].n_elts < DUMP_THRESHOLD) return NIL(network_t); + network = network_alloc(); + add_source_to_network(network, &source, &source_polarity); + add_sinks(network, source, &fanout_info[source_polarity]); + if (fanout_info[POLAR_INV(source_polarity)].n_elts > 0) { + inverter = add_inverter_to_source(network, source); + add_sinks(network, inverter, &fanout_info[POLAR_INV(source_polarity)]); + } + return network; +} + + /* just take the first available source */ + +static void add_source_to_network(network, source, source_polarity) +network_t *network; +node_t **source; +int *source_polarity; +{ + int i, n_pi; + lsGen gen; + delay_time_t arrival; + delay_time_t drive; + node_t *node, *new_node, *pi; + node_t **new_nodes; + char **formals; + n_gates_t n_gates; + + n_gates = fanout_delay_get_n_gates(); + node = fanout_delay_get_source_node(n_gates.n_buffers); + *source_polarity = fanout_delay_get_source_polarity(n_gates.n_buffers); + if (node->type == PRIMARY_INPUT) { + *source = new_node = node_alloc(); + map_alloc(new_node); + new_node->name = util_strsav(node->name); + network_add_primary_input(network, new_node); + arrival = pipo_get_pi_arrival(node); + drive = pipo_get_pi_drive(node); + delay_set_parameter(new_node, DELAY_DRIVE_RISE, drive.rise); + delay_set_parameter(new_node, DELAY_DRIVE_FALL, drive.fall); + delay_set_parameter(new_node, DELAY_ARRIVAL_RISE, arrival.rise); + delay_set_parameter(new_node, DELAY_ARRIVAL_FALL, arrival.fall); + } else { + n_pi = MAP(node)->ninputs; + new_nodes = ALLOC(node_t *, n_pi); + for (i = 0; i < n_pi; i++) { + char buffer[10]; + new_nodes[i] = node_alloc(); + map_alloc(new_nodes[i]); + sprintf(buffer, "%d", i); + new_nodes[i]->name = util_strsav(buffer); + network_add_primary_input(network, new_nodes[i]); + arrival = MAP(MAP(node)->save_binding[i])->map_arrival; + drive = pipo_get_pi_drive(NIL(node_t)); + delay_set_parameter(new_nodes[i], DELAY_DRIVE_RISE, drive.rise); + delay_set_parameter(new_nodes[i], DELAY_DRIVE_FALL, drive.fall); + delay_set_parameter(new_nodes[i], DELAY_ARRIVAL_RISE, arrival.rise); + delay_set_parameter(new_nodes[i], DELAY_ARRIVAL_FALL, arrival.fall); + } + *source = new_node = node_alloc(); + map_alloc(new_node); + new_node->name = util_strsav(node->name); + formals = ALLOC(char *, n_pi); + i = 0; + foreach_primary_input(MAP(node)->gate->network, gen, pi) { + formals[i++] = pi->name; + } + assert(lib_set_gate(new_node, MAP(node)->gate, formals, new_nodes, n_pi)); + network_add_node(network, new_node); + FREE(formals); + FREE(new_nodes); + } +} + +static void add_sinks(network, source, fanout_info) +network_t *network; +node_t *source; +opt_array_t *fanout_info; +{ + int i; + node_t *po; + gate_link_t *link; + char *buffer; + + for (i = 0; i < fanout_info->n_elts; i++) { + link = array_fetch(gate_link_t *, fanout_info->required, i); + po = network_add_primary_output(network, source); + map_alloc(po); + buffer = ALLOC(char, strlen(link->node->name) + 10); + sprintf(buffer, "%s(%d)", link->node->name, link->pin); + network_change_node_name(network, po, util_strsav(buffer)); + FREE(buffer); + delay_set_parameter(po, DELAY_REQUIRED_RISE, link->required.rise); + delay_set_parameter(po, DELAY_REQUIRED_FALL, link->required.fall); + delay_set_parameter(po, DELAY_OUTPUT_LOAD, link->load); + } +} + +static node_t *add_inverter_to_source(network, source) +network_t *network; +node_t *source; +{ + node_t *inverter; + + inverter = node_literal(source, 0); + map_alloc(inverter); + MAP(inverter)->ninputs = 1; + MAP(inverter)->gate = lib_get_default_inverter(); + MAP(inverter)->save_binding = ALLOC(node_t *, 1); + MAP(inverter)->save_binding[0] = source; + inverter->name = util_strsav(".inv."); + network_add_node(network, inverter); + return inverter; +} + diff --git a/sis/map/fanout_est.c b/sis/map/fanout_est.c new file mode 100644 index 0000000..7b94c31 --- /dev/null +++ b/sis/map/fanout_est.c @@ -0,0 +1,698 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_est.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_est.c 1.4 */ +/* last modified on 7/2/91 at 19:44:23 */ +/* + * $Log: fanout_est.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:24 pchong + * imported + * + * Revision 1.6 1993/08/05 18:22:27 sis + * Bug fix : now handles libraries without 2-nand. + * + * Revision 1.2 1993/08/05 16:14:32 cmoon + * need to watch out for library without 2-NAND + * + * Revision 1.1 1993/08/05 15:34:20 cmoon + * Initial revision + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 21:53:13 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:40:37 sis + * Initial revision + * + * Revision 1.2 91/07/02 10:53:16 touati + * lint cleanup. + * + * Revision 1.1 91/06/30 16:38:50 touati + * Initial revision + * + */ +#include "sis.h" +#include "map_macros.h" +#include "map_int.h" +#include "bin_int.h" +#include "lib_int.h" +#include "fanout_int.h" +#include "fanout_delay.h" + +#include "fanout_est_static.h" + + /* this file takes as input an abstract specification */ + /* of a fanout tree and returns a data structure directly usable */ + /* for bin_delay.c to evaluate arrival times at tree leaves. */ + + /* here are the routines this file is expected to implement */ + +/* + * + * + * void fanout_est_get_prim_pin_fanout(prim, pin, pin_info) + * prim_t *prim; + * int pin; + * pin_info_t *pin_info; + * Given a prim describing a match and a pin number, figures out + * the leaf (== source), the fanout index and the polarity wrt to the source + * of a multiple fanout point. If the source is not a multiple fanout point + * everything is set up to NIL values. The prim should be currently + * within a match (i.e. its bindings should hold). + * + * void fanout_est_compute_fanout_info(node) + * node_t *node; + * Given a node that is asserted to be multiple fanout, we compute the + * information stored in BIN(node)->fanout used to estimate delays at + * a multiple fanout point. The routine fanout_est_get_est_fanout_leaves + * does most of the work. If a fanout tree is found at MAP(node)->fanout_tree + * it is used, otherwise a dummy one is made up and used. + * + * fanout_bucket_t *fanout_est_fanout_bucket_alloc(info) + * multi_fanout_t *info; + * Simply allocates a new bucket and links it to a linked list + * whose head is kept in info. Why? To free memory when done. + * + * void fanout_est_free_fanout_info(node) + * node_t *node; + * Does not actually free all the storage associated with BIN(node)->fanout. + * Only frees the storage allocated for the fanout buckets with calls to + * fanout_est_fanout_bucket_alloc. + * + * delay_time_t fanout_est_get_pin_arrival_time(pin_info, pin_load) + * pin_info_t *pin_info; + * double pin_load; + * Asserts that the pin_info corresponds to a pin fed by a leaf (a source) + * of fanout > 1. Takes the leaf, that should have BIN(leaf)->info already + * computed for it, to estimate the arrival time a the pin described by pin_info. + * This routine is the main functionality provided by "fanout_est.c". + * + */ + + + /* EXTERNAL INTERFACE */ + + /* given a prim describing a match, and a pin, figure out the leaf and the fanout index */ + /* tracks down the first multiple fanout point connected to input of that gate */ + /* through inverters only. If none, set pin_info->leaf to NIL. If there is one, keep in input_fanout */ + /* the fanout from where it came. If not given, need to use some more complicated technique */ + /* to figure out the correct fanout_index. */ + /* WARNING: if prim == NIL, means a PO */ + +void fanout_est_get_prim_pin_fanout(prim, pin, pin_info) +prim_t *prim; +int pin; +pin_info_t *pin_info; +{ + node_t *input; + node_t *input_fanout; + int polarity; + + if (prim == NIL(prim_t)) { + input_fanout = pin_info->input; + assert(input_fanout->type == PRIMARY_OUTPUT); + input = node_get_fanin(input_fanout, 0); + } else { + assert(pin >= 0 && pin < prim->ninputs); + input = pin_info->input; + input_fanout = fanout_est_get_pin_fanout_node(prim, pin); + } + polarity = POLAR_X; + while (node_function(input) == NODE_INV && node_num_fanout(input) == 1) { + input_fanout = input; + input = node_get_fanin(input, 0); + polarity = POLAR_INV(polarity); + } + if (node_num_fanout(input) == 1) { /* no multiple fanout point encountered: stop */ + pin_info->leaf = NIL(node_t); + pin_info->fanout_index = -1; + pin_info->pin_polarity = -1; + } else { + pin_info->leaf = input; + pin_info->fanout_index = fanout_est_get_fanout_index(input, input_fanout); + if (polarity == POLAR_X) { + pin_info->pin_polarity = BIN(input)->fanout->polarity; + } else { + pin_info->pin_polarity = POLAR_INV(BIN(input)->fanout->polarity); + } + } +} + + +/* + * Given a node that is asserted to be multiple fanout, we compute the + * information stored in BIN(node)->fanout used to estimate delays at + * a multiple fanout point. The routine fanout_est_get_est_fanout_leaves + * does most of the work. If a fanout tree is found at MAP(node)->fanout_tree + * it is used, otherwise a dummy one is made up and used. + */ + +static bin_global_t *global_options; + +void fanout_est_compute_fanout_info(node, options) +node_t *node; +bin_global_t *options; +{ + int polarity; + node_t *source; + delay_bucket_t *bucket; + pin_info_t pin_info; + lib_gate_t *default_inv; + int n_fanouts = node_num_fanout(node); + + global_options = options; + assert(n_fanouts > 1 && BIN(node)->fanout != NIL(multi_fanout_t)); + fanout_est_get_est_fanout_leaves(node); + source = MAP(node)->fanout_source; + + if (options->allow_duplication && BIN(node)->fanout->polarity == POLAR_Y) { + + /* + * If node is POLAR_X, there is no duplication possible: node is PI or constant. + * In that case, we skip this part of the code. + * Otherwise, if we allow duplication, it means we allow a tree to be duplicated + * to provide a signal in both phases (X and X'). Only one tree producing X + * and one tree producing X' is authorized. + * To get that effect, we just let the algorithm selects the gate that + * seems most appropriate. No forcing of inverters. + * The only effect of "best_is_inverter" on bin_delay.c is to allow, if set + * the use of the fanin of node as a possible source. Here we overload + * "best_is_inverter" to get the effect of duplication. + * NOTE: we need to assign a reasonable load to both sources in that case, + * otherwise the default (+ INFINITY) is used, and large inverters are forced + * everywhere, meaning no logic duplication anywhere. + */ + + BIN(node)->fanout->best_is_inverter = 1; + +/* CASE 1: full load as predicted by load heuristic on both trees */ + polarity = BIN(node)->fanout->polarity; + if (source == node) { + BIN(node)->fanout->loads[POLAR_INV(polarity)] = BIN(node)->fanout->loads[polarity]; + } else { + BIN(node)->fanout->loads[polarity] = BIN(node)->fanout->loads[POLAR_INV(polarity)]; + } + +/* CASE 2: no load: // + BIN(node)->fanout->loads[POLAR_X] = 0.0; + BIN(node)->fanout->loads[POLAR_Y] = 0.0; +*/ + +/* CASE 3: half load: // + polarity = BIN(node)->fanout->polarity; + if (source == node) { + load = BIN(node)->fanout->loads[polarity]; + } else { + load = BIN(node)->fanout->loads[POLAR_INV(polarity)]; + } + assert(load < INFINITY); + BIN(node)->fanout->loads[POLAR_INV(polarity)] = load / 2; + BIN(node)->fanout->loads[polarity] = load / 2; +*/ + +/* CASE 4: force the selections of non inverters // + polarity = BIN(node)->fanout->polarity; + if (node_num_fanin(node) > 0) { + assert(polarity == POLAR_Y); + if (source == node) { + load = BIN(node)->fanout->loads[polarity]; + } else { + load = BIN(node)->fanout->loads[POLAR_INV(polarity)]; + } + if (source == node) { + source = node_get_fanin(node, 0); + BIN(node)->fanout->loads[POLAR_INV(polarity)] = fanout_est_select_non_inverter(source, load); + } else { + BIN(node)->fanout->loads[polarity] = fanout_est_select_non_inverter(node, load); + } + } +*/ + + } else if (source == node) { + + /* + * node may be NODE_Y or the source itself (if PI or constant feeding a PO) + * in any case, its load has already been computed in fanout_est_get_est_fanout_leaves + * as the load of the fanout tree. + * the value of the other load is irrelevant. + */ + + BIN(node)->fanout->best_is_inverter = 0; + + } else { + assert(BIN(node)->fanout->polarity == POLAR_Y); + assert(node_function(node) == NODE_INV); + BIN(node)->fanout->best_is_inverter = 1; + + /* + * node Y is mapped to an inverter + * modify BIN(node)->pwl in order to make sure to get an inverter at that node. + * the correct BIN(node)->load[POLAR_X] was computed in fanout_est_get_est_fanout_leaves. + */ + + pwl_free(BIN(node)->pwl); + pin_info.leaf = NIL(node_t); + pin_info.input = node_get_fanin(node, 0); + BIN(node)->pwl = pwl_create_empty(); + default_inv = lib_get_default_inverter(); + bucket = bin_delay_compute_gate_bucket(default_inv, 1, &pin_info); + bin_delay_update_node_pwl(node, bucket); + BIN(node)->fanout->loads[POLAR_Y] = 0.0; + } +} + + /* alloc's a bucket and put it on the fanout_bucket list. */ + +fanout_bucket_t *fanout_est_fanout_bucket_alloc(info) +multi_fanout_t *info; +{ + fanout_bucket_t *result = ALLOC(fanout_bucket_t, 1); + result->next = info->buckets; + info->buckets = result; + return result; +} + +/* + * Simply allocates a new bucket and links it to a linked list + * whose head is kept in info. Why? To free memory when done. + */ + +void fanout_est_free_fanout_info(node) +node_t *node; +{ + assert(BIN(node)->fanout != NIL(multi_fanout_t)); + fanout_bucket_free(BIN(node)->fanout); +} + + + /* basically, find the right pwl in the fanout structure for that polarity, */ + /* that index and that load. Compensate for the load and returns the arrival time */ + /* ASSERTION: this pwl corresponds to the selection of a single gate here. */ + /* EXTENSIONS: check that pin_load <= leaf->load and otherwise return +infty */ + /* this will be done for the second phase, when we iterate the code. */ + +delay_time_t fanout_est_get_pin_arrival_time(pin_info, pin_load) +pin_info_t *pin_info; +double pin_load; +{ + double load; + fanout_leaf_t *leaf; + + assert(pin_info->leaf != NIL(node_t)); + assert(pin_info->pin_polarity == POLAR_X || pin_info->pin_polarity == POLAR_Y); + assert(pin_info->fanout_index >= 0 && pin_info->fanout_index < node_num_fanout(pin_info->leaf)); + leaf = &(BIN(pin_info->leaf)->fanout->leaves[pin_info->pin_polarity][pin_info->fanout_index]); + load = leaf->bucket->load + (pin_load - leaf->load); + return bin_delay_compute_delay_pwl_delay(leaf->bucket->pwl, load); +} + + + + /* INTERNAL INTERFACE */ + + + /* compute the fanout index of each pin, wrt to multiple fanout nodes */ + /* if node not multiple fanout, no information is computed */ + /* the real work is done by fanout_est_get_prim_pin_fanout */ + +static int get_fanin_fanout_indices(prim) +prim_t *prim; +{ + int i; + node_t *root; + pin_info_t pin_info; + + root = map_prim_get_root(prim); + for (i = 0; i < prim->ninputs; i++) { + if (MAP(root)->save_binding[i] != prim->inputs[i]->binding) return 1; + } + for (i = 0; i < prim->ninputs; i++) { + pin_info.input = MAP(root)->save_binding[i]; + fanout_est_get_prim_pin_fanout(prim, i, &pin_info); + MAP(root)->pin_info[i].pin_source = pin_info.leaf; + MAP(root)->pin_info[i].fanout_index = pin_info.fanout_index; + } + prim->data = (char *) -1; + return 0; +} + + +/* + * this routine is used when the pin of the prim (i.e. prim->inputs[pin]->binding) + * is a multiple fanout node_t node. We need to get the fanout of that node + * that is matched in the prim. This routine does that. The prim should be active: + * i.e. the call should be made only within an active gen_all_matches. + */ + +static node_t *fanout_est_get_pin_fanout_node(prim, pin) +prim_t *prim; +int pin; +{ + prim_node_t *node; + prim_edge_t *edge; + + node = prim->inputs[pin]; + assert(node->nfanout == 1); + for (edge = prim->edges; edge != NIL(prim_edge_t); edge = edge->next) { + if (edge->this_node == node) return edge->connected_node->binding; + } + return NIL(node_t); +} + +/* + * given a node and one of its fanouts, figures out which fanout index + * the fanout corresponds to. Needs to have BIN(node)->fanout allocated for that. + */ + +static int fanout_est_get_fanout_index(node, fanout) +node_t *node; +node_t *fanout; +{ + int fanout_index; + + assert(BIN(node)->fanout != NIL(multi_fanout_t)); + assert(st_lookup_int(BIN(node)->fanout->index_table, (char *) fanout, &fanout_index)); + return fanout_index; +} + + + + /* at this point, there is one tree that can service half of all possible leaves */ + /* the other half are those with reverse polarity */ + /* We first fill the delay information for leaves that are directly connected to this tree */ + /* then we add delay information for the reversed polarity leaves simply by adding an inverter */ + +static void fanout_est_get_est_fanout_leaves(node) +node_t *node; +{ + node_t *source; + array_t *fanout_tree; + int source_polarity; + + if (MAP(node)->fanout_tree == NIL(array_t)) { + fanout_est_create_dummy_fanout_tree(node); + } + source = MAP(node)->fanout_source; + fanout_tree = MAP(node)->fanout_tree; + assert(source != NIL(node_t)); + assert(fanout_tree != NIL(array_t)); + + source_polarity = fanout_est_get_source_polarity(node, source); + + fanout_delay_add_pwl_source(source, source_polarity); + fanout_tree_extract_fanout_leaves(BIN(node)->fanout, fanout_tree); + BIN(node)->fanout->loads[source_polarity] = fanout_tree_get_source_load(fanout_tree); + fanout_delay_free_sources(); + fanout_tree_free(fanout_tree, 1); + MAP(node)->fanout_tree = NIL(array_t); + fanout_est_extract_remaining_fanout_leaves(BIN(node)->fanout); +} + + +/* + * First, create a fanout info representing the problem. + * We are conservative here: create it with n the number of fanouts + * We try both polarities, but separately, one at a time. And a take the source + * that is globally the better one. + * As load, we use the load of the first input pin of the smallest NAND2 gate + * As required time, (0.0, 0.0) + * We then try to build the best fanout tree for that, trying both sources + * and recording the best result in BIN(node)->fanout. + */ + +static void fanout_est_create_dummy_fanout_tree(node) +node_t *node; +{ + int p, q; + int best_source_polarity; + int best_sink_polarity; + opt_array_t fanout_info[POLAR_MAX][POLAR_MAX]; + node_t *sources[POLAR_MAX]; + fanout_cost_t costs[POLAR_MAX][POLAR_MAX]; + array_t *trees[POLAR_MAX][POLAR_MAX]; + fanout_cost_t total_cost[POLAR_MAX]; + fanout_alg_t alg; + + if (node_num_fanin(node) > 0) { + sources[POLAR_X] = node_get_fanin(node, 0); + sources[POLAR_Y] = node; + } else { + sources[POLAR_X] = node; + sources[POLAR_Y] = NIL(node_t); + } + if (global_options->load_estimation == 1) { + noalg_init(NIL(network_t), &alg); + } else { + balanced_init(NIL(network_t), &alg); + } + foreach_polarity(p) { + fanout_est_compute_dummy_fanout_info(node, fanout_info[p], p); + foreach_polarity(q) { + trees[p][q] = fanout_tree_alloc(); + costs[p][q].slack = MINUS_INFINITY; + costs[p][q].area = INFINITY; + if (sources[q] == NIL(node_t)) continue; + fanout_delay_add_pwl_source(sources[q], q); + assert((*alg.optimize)(fanout_info[p], trees[p][q], &costs[p][q])); + fanout_tree_add_edges(trees[p][q]); + fanout_delay_free_sources(); + } + } + +/* + * take the source with the best performance + */ + + foreach_polarity(q) { + if (fanout_opt_is_better_cost(&costs[POLAR_X][q], &costs[POLAR_Y][q])) { + total_cost[q] = costs[POLAR_X][q]; + } else { + total_cost[q] = costs[POLAR_Y][q]; + } + } + + if (fanout_opt_is_better_cost(&total_cost[POLAR_X], &total_cost[POLAR_Y])) { + best_source_polarity = POLAR_X; + } else { + best_source_polarity = POLAR_Y; + } + MAP(node)->fanout_source = sources[best_source_polarity]; + + +/* + * for that better source, choose the better polarity: keep that tree only + */ + + if (fanout_opt_is_better_cost(&costs[POLAR_X][best_source_polarity], &costs[POLAR_Y][best_source_polarity])) { + best_sink_polarity = POLAR_X; + } else { + best_sink_polarity = POLAR_Y; + } + MAP(node)->fanout_tree = trees[best_sink_polarity][best_source_polarity]; + fanout_tree_save_links(MAP(node)->fanout_tree); + foreach_polarity(p) { + foreach_polarity(q) { + fanout_info_free(&fanout_info[p][q], 1); + if (p == best_sink_polarity && q == best_source_polarity) continue; + fanout_tree_free(trees[p][q], 0); + } + } +} + + /* polarity rule: if multi fanout source is INV -> POLAR_Y */ + /* otherwise it gets POLAR_X */ + +static int fanout_est_get_source_polarity(fanout_point, source) +node_t *fanout_point; +node_t *source; +{ + int fanout_polarity; + + assert(node_num_fanout(fanout_point) > 1); + fanout_polarity = BIN(fanout_point)->fanout->polarity; + return (source == fanout_point) ? fanout_polarity : POLAR_INV(fanout_polarity); +} + +static void fanout_est_extract_remaining_fanout_leaves(fanout) +multi_fanout_t *fanout; +{ + int i, p; + fanout_leaf_t *leaf[POLAR_MAX]; + int n_fanouts = fanout->n_fanouts; + int needed_polarity; + int existing_leaves; + + for (i = 0; i < n_fanouts; i++) { + existing_leaves = 0; + foreach_polarity(p) { + leaf[p] = &(fanout->leaves[p][i]); + if (leaf[p]->bucket != NIL(fanout_bucket_t)) { + existing_leaves++; + } + } + assert(existing_leaves == 1); + needed_polarity = (leaf[POLAR_X]->bucket == NIL(fanout_bucket_t)) ? POLAR_X : POLAR_Y; + fanout_est_extend_fanout_leaf(fanout, leaf[needed_polarity], leaf[POLAR_INV(needed_polarity)]); + } +} + + +/* + * put in the links entries of the form: (NIL(node_t), fanout_index) + * this kind of sinks is recognized by fanout_est_get_pin_fanout_index. + */ + +static void fanout_est_compute_dummy_fanout_info(node, fanout_info, polarity) +node_t *node; +opt_array_t *fanout_info; +int polarity; +{ + int i, p; + int n_fanouts; + lib_gate_t *default_nand2; + double default_load; + gate_link_t link; + gate_link_t *link_ptr; + + n_fanouts = BIN(node)->fanout->n_fanouts; + default_nand2 = choose_smallest_gate(lib_get_library(), "f=!(a*b);"); + if (default_nand2 == NIL(lib_gate_t)) { + default_nand2 = choose_smallest_gate(lib_get_library(), "f=(a*b);"); + if (default_nand2 == NIL(lib_gate_t)) { + default_nand2 = choose_smallest_gate(lib_get_library(), "f=!(a+b);"); + if (default_nand2 == NIL(lib_gate_t)) { + default_nand2 = choose_smallest_gate(lib_get_library(), "f=(a+b);"); + } + } + } + assert(default_nand2 != NIL(lib_gate_t)); + default_load = delay_get_load(default_nand2->delay_info[0]); + + link.node = NIL(node_t); + link.pin = 0; + link.load = default_load; + link.slack = 0.0; + link.required = ZERO_DELAY; + + foreach_polarity(p) { + fanout_info[p].links = st_init_table(st_ptrcmp, st_ptrhash); + if (p == polarity) { + for (i = 0; i < n_fanouts; i++) { + link_ptr = ALLOC(gate_link_t, 1); + *link_ptr = link; + link_ptr->pin = i; + st_insert(fanout_info[p].links, (char *) link_ptr, NIL(char)); + } + } + fanout_info_preprocess(&fanout_info[p]); + } +} + + +static void fanout_est_extend_fanout_leaf(fanout, new_leaf, old_leaf) +multi_fanout_t *fanout; +fanout_leaf_t *new_leaf; +fanout_leaf_t *old_leaf; +{ + int gate_index; + lib_gate_t *gate; + double load; + pin_info_t pin_info; + delay_pwl_t best_pwl; + delay_pwl_t pwl; + delay_time_t arrival, best_arrival; + n_gates_t n_gates; + + new_leaf->load = old_leaf->load; + new_leaf->bucket = fanout_est_fanout_bucket_alloc(fanout); + new_leaf->bucket->load = old_leaf->load; + + if (global_options->ignore_polarity) { + best_pwl.rise = pwl_dup(old_leaf->bucket->pwl.rise); + best_pwl.fall = pwl_dup(old_leaf->bucket->pwl.fall); + } else { + best_pwl.rise = pwl_create_empty(); + best_pwl.fall = pwl_create_empty(); + best_arrival = PLUS_INFINITY; + n_gates = fanout_delay_get_n_gates(); + foreach_inverter(n_gates, gate_index) { + gate = fanout_delay_get_gate(gate_index); + load = fanout_delay_get_buffer_load(gate_index); + load += old_leaf->bucket->load - old_leaf->load; + pin_info.arrival = bin_delay_compute_delay_pwl_delay(old_leaf->bucket->pwl, load); + pwl = bin_delay_compute_gate_pwl(gate, 1, &pin_info); + arrival = bin_delay_compute_delay_pwl_delay(pwl, old_leaf->load); + if (GETMAX(arrival) < GETMAX(best_arrival)) { + pwl_free(best_pwl.rise); + pwl_free(best_pwl.fall); + best_pwl = pwl; + best_arrival = arrival; + } else { + pwl_free(pwl.rise); + pwl_free(pwl.fall); + } + } + } + new_leaf->bucket->pwl = best_pwl; +} + + + /* free all the buckets associated with a multi_fanout_t structure */ + +static void fanout_bucket_free(info) +multi_fanout_t *info; +{ + fanout_bucket_t *head; + fanout_bucket_t *next; + + for (head = info->buckets; head != NIL(fanout_bucket_t); head = next) { + pwl_free(head->pwl.rise); + pwl_free(head->pwl.fall); + next = head->next; + FREE(head); + } +} + + /* given a node and a load, figure out the closest load to "load" */ + /* that selects a gate that is not an inverter */ + +static double fanout_est_select_non_inverter(node, load) +node_t *node; +double load; +{ + int i; + double best_load; + double distance; + double best_distance; + pwl_point_t *point; + delay_bucket_t *bucket; + pwl_t *pwl = BIN(node)->pwl; + + /* first check whether any load correction is necessary */ + point = pwl_lookup(pwl, load); + bucket = (delay_bucket_t *) pwl_point_data(point); + if (bucket->ninputs > 1) return load; + + /* if it is, limit the damage */ + best_load = load; + best_distance = INFINITY; + for (i = 0; i < pwl->n_points; i++) { + bucket = (delay_bucket_t *) pwl->points[i].data; + if (bucket->ninputs > 1) { + distance = load - pwl->points[i].x; + if (distance < 0) distance = - distance; + if (distance < best_distance) { + best_load = pwl->points[i].x; + } + } + } + return best_load; +} diff --git a/sis/map/fanout_est_static.h b/sis/map/fanout_est_static.h new file mode 100644 index 0000000..49bd055 --- /dev/null +++ b/sis/map/fanout_est_static.h @@ -0,0 +1,22 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_est_static.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_est_static.h 1.2 */ +/* last modified on 5/1/91 at 15:50:34 */ +static double fanout_est_select_non_inverter(); +static int fanout_est_get_fanout_index(); +static int fanout_est_get_source_polarity(); +static int get_fanin_fanout_indices(); +static node_t *fanout_est_get_pin_fanout_node(); +static void fanout_bucket_free(); +static void fanout_est_compute_dummy_fanout_info(); +static void fanout_est_create_dummy_fanout_tree(); +static void fanout_est_extend_fanout_leaf(); +static void fanout_est_extract_remaining_fanout_leaves(); +static void fanout_est_get_est_fanout_leaves(); diff --git a/sis/map/fanout_int.h b/sis/map/fanout_int.h new file mode 100644 index 0000000..7b42811 --- /dev/null +++ b/sis/map/fanout_int.h @@ -0,0 +1,174 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_int.h 1.5 */ +/* last modified on 7/1/91 at 22:37:04 */ +#ifndef FANOUT_INT_H +#define FANOUT_INT_H + +#include "multi_array.h" +#include "gate_link.h" +#include "map_defs.h" + +typedef multidim_t *(*MultidimFn)(); + +#define POLAR_X 0 +#define POLAR_Y 1 +#define POLAR_MAX 2 +#define POLAR_INV(polarity) (1 - (polarity)) +#define foreach_polarity(x)for((x)=POLAR_X;(x)<POLAR_MAX;(x)++) + +typedef struct single_source_struct single_source_t; +struct single_source_struct { + delay_time_t required; + double load; + int n_fanouts; + double area; +}; + +typedef struct selected_source_struct selected_source_t; +struct selected_source_struct { + int main_source; + int main_source_sink_polarity; + int buffer; +}; + +typedef struct opt_array_struct opt_array_t; +struct opt_array_struct { + int n_elts; + st_table *links; + array_t *required; /* ptrs to gate links, in increasing required time order */ + double *cumul_load; /* cumul_load[i] = load[0] + ... + load[i-1] in required time order */ + delay_time_t *min_required; /* min_required[i] = MIN(required[i],...,required[last]) in required time order */ + double total_load; /* always equal to cumul_load[n_elts - 1] when n_elts > 0 */ +}; + +typedef struct alg_property_struct alg_property_t; +struct alg_property_struct { + char *name; + int value; + VoidFn update_fn; +}; + +typedef struct fanout_alg_struct fanout_alg_t; +struct fanout_alg_struct { + char *name; + int on_flag; + int peephole_flag; + int min_size; /* under that size, not even called */ + array_t *properties; /* array of properties (alg_property_t) */ + VoidFn init; + IntFunc optimize; /* optimize the fanout problem, returns an array */ +}; + +typedef struct fanout_cost_struct fanout_cost_t; +struct fanout_cost_struct { + delay_time_t slack; + double area; +}; + + + /* exported from each fanout algorithm */ + +#include "map_macros.h" +#include "fanout_alg_macro.h" + + /* exported from FANOUT_UTIL.C */ + +extern delay_time_t MINUS_INFINITY; +extern delay_time_t PLUS_INFINITY; +extern delay_time_t ZERO_DELAY; + +extern single_source_t SINGLE_SOURCE_INIT_VALUE; + +extern int find_minimum_index(/* delay_time_t *array, int n */); +extern void generic_fanout_optimizer(/* opt_array_t *fanout_info, array_t *tree, fanout_cost_t *cost, + VoidFn optimize_one_source, VoidFn extract_merge_info, + VoidFn build_tree */); + + + /* exported from VIRTUAL_NETWORK.C */ + +extern void virtual_network_setup_gate_links(/* network_t *network */); +extern void virtual_network_remove_wires(/* network_t *network */); +extern void virtual_network_flatten(/* network_t *network */); +extern void virtual_network_remove_node(/* node_t *node */); +extern void virtual_network_add_to_gate_link(/* node_t *source, gate_link_t *link */); +extern void virtual_network_update_link_required_times(/* node_t *node, delay_time_t *required */); + + + /* exported from VIRTUAL_DELAY.C */ + +extern void virtual_delay_compute_arrival_times(/* network_t *network */); +extern void virtual_delay_arrival_times_rec(/* st_table *visited, node_t *node */); +extern void virtual_delay_set_po_negative_required(/* network_t *network */); +extern void virtual_delay_set_po_required(/* network_t *network */); +extern void virtual_delay_compute_node_required_time(/* node_t *node */); + + /* exported from FANOUT_OPT.C */ + +extern array_t *fanout_opt_get_fanout_alg(/* int n_entries, char **entries */); +extern void fanout_opt_print_fanout_alg(/* array_t *fanout_alg */); +extern void fanout_opt_set_fanout_param(/* array_t *fanout_alg, int n_entries, char **entries, int *alg_index */); +extern void fanout_opt_print_fanout_param(/* array_t *fanout_alg, int alg_index */); +extern void fanout_optimization(/* network_t *network, bin_global_t globals */); +extern void fanout_info_preprocess(/* opt_array_t *fanout_info (only one polarity at a time) */); +extern void fanout_info_free(/* opt_array_t *fanout_info (only one polarity at a time) */); +extern int fanout_opt_is_better_cost(/* fanout_cost_t *cost1, fanout_cost_t *cost2 */); +extern node_t *fanout_opt_get_root(/* */); +extern node_t *fanout_opt_get_root_inv(/* */); +extern double get_genlib_maxload (/* lib_gate_t* */); /* find the max load driven by a gate*/ +extern unsigned exceed_fanout_limit (/* node_t *, double*/); /* determine if the specified load exceeds the max. allowable load */ +extern double fanout_opt_get_max_load(/* node_t* */); /* find the max. allowable load on a node */ +extern double get_nth_smallest_inv_load(/* int (inverter type) */); /* find the max. allowable on an 'int'th smallest inverter*/ + + /* exported from FANOUT_TREE.C */ + +extern void fanout_tree_build(/* array_t *array, fanout_cost_t *cost, opt_array_t *fanout_info */); +extern array_t *fanout_tree_alloc(/* */); +extern void fanout_tree_free(/* array_t *array */); +extern void fanout_tree_save_links(/* array_t *array */); +extern void fanout_tree_add_edges(/* array_t *array */); +extern void fanout_tree_check(/* array_t *array, fanout_cost_t *cost */); +extern void fanout_tree_peephole_optimize(/* array_t *array, fanout_cost_t *cost */); +extern void fanout_tree_copy(/* array_t *to, array_t *from */); +extern void fanout_tree_insert_sink(/* array_t *array, gate_link_t *link */); +extern void fanout_tree_insert_gate(/* array_t *array, int gate_index, int arity */); + + + /* exported from NOALG.C */ + +extern void noalg_insert_sinks(/* tree, fanout_info, from, to */); + + /* exported from TWO_LEVEL.C */ + +typedef struct two_level_struct two_level_t; +struct two_level_struct { + int gate_index; /* gate to put at intermediate nodes (index into the buffer table) */ + int n_gates; /* number of intermediate nodes */ + delay_time_t required; /* required time at the source, not including source intrinsic */ + double area; +}; + +extern multidim_t *two_level_optimize_for_lt_trees(/* opt_array_t *fanout_info */); +extern void insert_two_level_tree(/* array_t *tree, opt_array_t *fanout_info, int sink_index, int source_index, two_level_t *entry */); + + /* exported from fanout_tree.c for fanout_est.c */ + +extern void fanout_tree_extract_fanout_leaves(/* multi_fanout_t *fanout; opt_array_t *fanout_info; array_t *array; */); +extern double fanout_tree_get_source_load(/* array_t *array */); + + + /* exported from fanout_log.c */ + +extern void fanout_log_init(/* bin_global_t *options; */); +extern void fanout_log_cleanup_network(/* network_t *network; */); +extern void fanout_log_register_node(/* node_t *node; */); + +#endif diff --git a/sis/map/fanout_log.c b/sis/map/fanout_log.c new file mode 100644 index 0000000..02b0881 --- /dev/null +++ b/sis/map/fanout_log.c @@ -0,0 +1,84 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_log.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_log.c 1.2 */ +/* last modified on 5/1/91 at 15:50:38 */ +#include "sis.h" +#include "map_macros.h" +#include "map_int.h" +#include "fanout_int.h" +#include "gate_link.h" + + /* this file keeps a log of all node creations during fanout optimization and undo them */ + /* nodes are created bottom up; so they can be destroyed in that order as well */ + +static void unmap_node(); + +static bin_global_t global; +static array_t *node_log; + + /* EXTERNAL INTERFACE */ + +void fanout_log_init(options) +bin_global_t *options; +{ + global = *options; + if (global.fanout_log_on) { + assert(node_log == NIL(array_t)); + node_log = array_alloc(node_t *, 0); + } +} + + /* remove all nodes in the log in order */ + /* then scan the network and remove all MAP annotations */ + +void fanout_log_cleanup_network(network) +network_t *network; +{ + int i; + node_t *node; + lsGen gen; + + assert(global.fanout_log_on); + for (i = array_n(node_log) - 1; i >= 0; i--) { + node = array_fetch(node_t *, node_log, i); + unmap_node(node); + assert(node_num_fanout(node) == 0); + network_delete_node(network, node); + } + array_free(node_log); + node_log = NIL(array_t); + foreach_node(network, gen, node) { + unmap_node(node); + } +} + +void fanout_log_register_node(node) +node_t *node; +{ + if (global.fanout_log_on) { + array_insert_last(node_t *, node_log, node); + } +} + + + /* INTERNAL INTERFACE */ + +static void unmap_node(node) +node_t *node; +{ + node_function_t node_fn; + + node_fn = node_function(node); + if (node_fn == NODE_PI || node_fn == NODE_0 || node_fn == NODE_1) return; + if (MAP(node)->ninputs > 0) FREE(MAP(node)->save_binding); + MAP(node)->gate = NIL(lib_gate_t); + MAP(node)->ninputs = 0; + MAP(node)->save_binding = NIL(node_t *); +} diff --git a/sis/map/fanout_opt.c b/sis/map/fanout_opt.c new file mode 100644 index 0000000..89a9813 --- /dev/null +++ b/sis/map/fanout_opt.c @@ -0,0 +1,1160 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_opt.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)fanout_opt.c 1.10 */ +/* last modified on 7/22/91 at 12:36:25 */ +/** +** MODIFICATION HISTORY: +** +** 01 02-Nov-90 cyt Changed #include "fanout_alg.macro.h" to "fanout_alg_macro.h" +** Added code to solve the fanout limit problem and #include delay_int +** 02 27-May-91 klk New code to handle fanout limit. +** 02 10-Jun-91 klk Changed primary input max drive to correspond to the second largest inverter +** in the library +**/ +/* + * $Log: fanout_opt.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:24 pchong + * imported + * + * Revision 1.4 1993/08/05 16:14:19 sis + * Added default case to switch statement so gcc version will work. + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 21:58:28 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:40:39 sis + * Initial revision + * + * Revision 1.5 91/07/03 23:23:00 touati + * (1): fixes by Cho to use simple lib_gate_type to identify latches. + * (2): bug fix: -G accepts constant nodes now. + * (3): bug fix: get the fanin of a PO through map_po_get_fanin + * (4): bug fix: use a more resilient test to compare floating point numbers: + * avoid numerical instabilities. + * + * Revision 1.4 91/07/02 10:54:05 touati + * added map -G option: resize all gates. + * + * Revision 1.3 91/06/30 22:28:56 touati + * added code to perform gate resizing for all gates. Works from outputs to inputs. + * + */ + +#include "sis.h" +#include <math.h> +#include "map_macros.h" +#include "map_int.h" +#include "fanout_int.h" +#include "fanout_delay.h" + +#include "fanout_opt_static.h" + +static bin_global_t global; + + + + /* EXTERNAL INTERFACE */ + +void fanout_opt_update_peephole_flag(alg, property) +fanout_alg_t *alg; +alg_property_t *property; +{ + alg->peephole_flag = property->value; +} + +void fanout_opt_update_size_threshold(alg, property) +fanout_alg_t *alg; +alg_property_t *property; +{ + alg->min_size = property->value; +} + + /* called by the command line option */ + +array_t *fanout_opt_get_fanout_alg(n_entries, entries) +int n_entries; +char **entries; +{ + int i, j; + fanout_alg_descr *descr_p; + fanout_prop_descr *prop_p; + fanout_alg_t fanout_alg; + fanout_alg_t *alg; + alg_property_t property; + static array_t *list_of_algs = NIL(array_t); + + if (list_of_algs == NIL(array_t)) { + + list_of_algs = array_alloc(fanout_alg_t, 0); + prop_p = fanout_properties; + + for (descr_p=fanout_algorithms; descr_p->alg_id != 0; descr_p++) { + fanout_alg.on_flag = descr_p->on_flag; + fanout_alg.name = descr_p->name; + fanout_alg.properties = array_alloc(alg_property_t, 0); + fanout_alg.init = descr_p->init_fn; + while (prop_p->alg_id == descr_p->alg_id) { + property.name = prop_p->name; + property.value = prop_p->value; + property.update_fn = prop_p->update_fn; + array_insert_last (alg_property_t, fanout_alg.properties, property); + prop_p++; + } + array_insert_last (fanout_alg_t, list_of_algs, fanout_alg); + } + } + + if (n_entries == 0) return list_of_algs; + + for (j = 0; j < array_n(list_of_algs); j++) { + alg = array_fetch_p(fanout_alg_t, list_of_algs, j); + alg->on_flag = (strcmp(alg->name, "noalg") == 0); + } + for (i = 0; i < n_entries; i++) { + for (j = 0; j < array_n(list_of_algs); j++) { + alg = array_fetch_p(fanout_alg_t, list_of_algs, j); + if (strcmp(alg->name, entries[i]) == 0) + alg->on_flag = 1; + } + } + return list_of_algs; +} + +void fanout_opt_print_fanout_alg(array) +array_t *array; +{ + int i; + fanout_alg_t *alg; + + fprintf(sisout, "fanout algs in use: "); + for (i = 0; i < array_n(array); i++) { + alg = array_fetch_p(fanout_alg_t, array, i); + if (alg->on_flag) fprintf(sisout, "\"%s\" ", alg->name); + } + fprintf(sisout, "\n"); + + fprintf(sisout, "fanout algs not in use: "); + for (i = 0; i < array_n(array); i++) { + alg = array_fetch_p(fanout_alg_t, array, i); + if (! alg->on_flag) fprintf(sisout, "\"%s\" ", alg->name); + } + fprintf(sisout, "\n"); +} + +void fanout_opt_set_fanout_param(array, n_entries, entries, alg_index) +array_t *array; +int n_entries; +char **entries; +int *alg_index; +{ + int i; + int entry_index; + fanout_alg_t *alg; + alg_property_t *property; + + *alg_index = -1; + if (n_entries == 0) return; + for (i = 0; i < array_n(array); i++) { + alg = array_fetch_p(fanout_alg_t, array, i); + if (strcmp(alg->name, entries[0]) == 0) { + *alg_index = i; + n_entries--; + entries++; + break; + } + } + if (n_entries == 0 || *alg_index == -1) return; + entry_index = -1; + for (i = 0; i < array_n(alg->properties); i++) { + property = array_fetch_p(alg_property_t, alg->properties, i); + if (strcmp(property->name, entries[0]) == 0) { + entry_index = i; + n_entries--; + entries++; + break; + } + } + if (n_entries != 1 || entry_index == -1) { + *alg_index = -1; + return; + } + property->value = atoi(entries[0]); +} + +void fanout_opt_print_fanout_param(array, index) +array_t *array; +int index; +{ + int i; + alg_property_t *property; + fanout_alg_t *alg = array_fetch_p(fanout_alg_t, array, index); + + fprintf(sisout, "property list of alg \"%s\"\n", alg->name); + for (i = 0; i < array_n(alg->properties); i++) { + property = array_fetch_p(alg_property_t, alg->properties, i); + fprintf(sisout, "%s --> %d\n", property->name, property->value); + } +} + + +void fanout_optimization(network, globals) +network_t *network; +bin_global_t globals; +{ + global = globals; + if (! global.fanout_optimize && ! global.area_recover) return; + + fanout_opt_init(network); + virtual_network_setup_gate_links(network, &globals); + virtual_network_remove_wires(network); + virtual_network_flatten(network); + virtual_delay_compute_arrival_times(network, globals); + virtual_delay_set_po_negative_required(network); + + bin_for_all_nodes_outputs_first(network, do_fanout_opt); + if (global.area_recover) { + virtual_delay_compute_arrival_times(network, globals); + virtual_network_flatten(network); + virtual_delay_set_po_required(network); + bin_for_all_nodes_outputs_first(network, do_fanout_opt); + if (global.all_gates_area_recover) { + virtual_delay_compute_arrival_times(network, globals); + virtual_delay_set_po_required(network); + virtual_net_for_all_nodes_outputs_first(network, compute_required_times); + init_gate_info(); + virtual_net_for_all_nodes_inputs_first(network, do_global_area_recover); + free_gate_info(); + } + } + fanout_opt_end(network); +} + + + /* INTERNAL INTERFACE */ + +static void fanout_opt_init(network) +network_t *network; +{ + int i; + int j; + fanout_alg_t *alg; + alg_property_t *property; + + fanout_log_init(&global); + for (i = 0; i < array_n(global.fanout_alg); i++) { + alg = array_fetch_p(fanout_alg_t, global.fanout_alg, i); + if (alg->on_flag) { + for (j = 0; j < array_n(alg->properties); j++) { + property = array_fetch_p(alg_property_t, alg->properties, j); + (*property->update_fn)(alg, property); + } + (*alg->init)(network, alg); + } + } +} + + + /* ARGSUSED */ +static void fanout_opt_end(network) +network_t *network; +{ + /* nothing */ +} + + +static void do_fanout_opt(node_x) + node_t *node_x; +{ +#ifdef SIS + /* no fanout optimization for latches */ + if (lib_gate_type(lib_gate_of(node_x)) != COMBINATIONAL && lib_gate_type(lib_gate_of(node_x)) != UNKNOWN ) { + virtual_delay_compute_node_required_time(node_x); + return; + } +#endif /* SIS */ + + switch (node_function(node_x)) { + case NODE_UNDEFINED: + /* former po removed */ + break; + case NODE_0: + case NODE_1: + if (! global.no_warning) (void) fprintf(siserr, "WARNING: constants should have been removed earlier\n"); + break; + case NODE_PO: + /* already processed */ + break; + case NODE_BUF: + fail("should not be any buffers in underlying network"); + break; + case NODE_INV: + if (MAP(node_x)->gate != NIL(lib_gate_t)) + virtual_delay_compute_node_required_time(node_x); + break; + case NODE_PI: + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + if (fanout_map_optimal(node_x) == 0) { + if (node_x->type == PRIMARY_INPUT || MAP(node_x)->gate != NIL(lib_gate_t)) + virtual_delay_compute_node_required_time(node_x); + } + break; + default: + ; + } +} + +#define SOURCE_X_ALONE 0 +#define SOURCE_Y_ALONE 1 +#define SOURCE_X_ON_X 2 +#define SOURCE_X_ON_Y 3 +#define SOURCE_MAX 4 + +typedef struct { + int type; /* any of the above #define, except SOURCE_MAX */ + array_t *trees[POLAR_MAX]; /* tree for sources[POLAR_X] and sources[POLAR_Y] */ + fanout_cost_t costs[POLAR_MAX]; /* cost of tree for each source */ + fanout_cost_t cost; /* aggregate cost */ +} fanout_sol_t; + + /* needed for K.J.'s code */ +static node_t *current_root_node; + + /* returns 1 iff fanout optimization was performed */ + +static int fanout_map_optimal(node_x) +node_t *node_x; +{ + int p, assign_x; + int n_fanouts; + node_t *node_y; + node_t *sources[2]; + array_t *best_tree; + int source_assign[POLAR_MAX]; + opt_array_t fanout_info[2]; + opt_array_t empty_fanout_info; + opt_array_t fanout_info_arg[2]; + fanout_sol_t fanout_sol[SOURCE_MAX]; + fanout_sol_t *assign_sol; + int best_sol; + + /* extract sink information */ + if (! extract_fanout_problem(node_x, sources, fanout_info)) return 0; + current_root_node = node_x; + + /* + * try the following combinations: + * (0) sources[POLAR_X] alone + * (1) sources[POLAR_Y] alone + * (2) sources[POLAR_X] for sinks of POLAR_X and sources[POLAR_Y] for sinks of POLAR_Y + * (3) sources[POLAR_X] for sinks of POLAR_Y and sources[POLAR_Y] for sinks of POLAR_X + * if only one polarity of sources, only (0) or (1) is attempted + * if only one polarity of sinks, only (0) and (1) are attempted + * To take tree area into account, we add MAP(source)->gate->area to the cost. + */ + + best_sol = SOURCE_MAX; + if (sources[POLAR_X] != NIL(node_t)) { + fanout_single_source_optimal(sources[POLAR_X], fanout_info, POLAR_X, &fanout_sol[SOURCE_X_ALONE]); + fanout_sol[SOURCE_X_ALONE].trees[POLAR_Y] = NIL(array_t); + fanout_sol[SOURCE_X_ALONE].cost = fanout_sol[SOURCE_X_ALONE].costs[POLAR_X]; + best_sol = SOURCE_X_ALONE; + } + if (sources[POLAR_Y] != NIL(node_t)) { + fanout_single_source_optimal(sources[POLAR_Y], fanout_info, POLAR_Y, &fanout_sol[SOURCE_Y_ALONE]); + fanout_sol[SOURCE_Y_ALONE].trees[POLAR_X] = NIL(array_t); + fanout_sol[SOURCE_Y_ALONE].cost = fanout_sol[SOURCE_Y_ALONE].costs[POLAR_Y]; + if (best_sol == SOURCE_MAX) { + best_sol = SOURCE_Y_ALONE; + } else if (fanout_opt_is_better_cost(&fanout_sol[SOURCE_X_ALONE].cost, &fanout_sol[SOURCE_Y_ALONE].cost)) { + fanout_tree_free(fanout_sol[SOURCE_Y_ALONE].trees[POLAR_Y], 0); + best_sol = SOURCE_X_ALONE; + } else { + fanout_tree_free(fanout_sol[SOURCE_X_ALONE].trees[POLAR_X], 0); + best_sol = SOURCE_Y_ALONE; + } + } + + if (sources[POLAR_X] != NIL(node_t) && sources[POLAR_Y] != NIL(node_t) + && fanout_info[POLAR_X].n_elts > 0 && fanout_info[POLAR_Y].n_elts > 0) { + +/* + * The complicated case where all possibilities need to be examined + * A lot of recomputation could be avoided by sharing the work at a lower + * level, but that would require major recoding. We play it safe here. + */ + + empty_fanout_info.links = st_init_table(st_ptrcmp, st_ptrhash); + fanout_info_preprocess(&empty_fanout_info); + source_assign[POLAR_X] = SOURCE_X_ON_X; + source_assign[POLAR_Y] = SOURCE_X_ON_Y; + + foreach_polarity(assign_x) { + assign_sol = &fanout_sol[source_assign[assign_x]]; + fanout_info_arg[POLAR_X] = fanout_info[POLAR_X]; + fanout_info_arg[POLAR_Y] = empty_fanout_info; + fanout_single_source_optimal(sources[assign_x], fanout_info_arg, assign_x, assign_sol); + fanout_info_arg[POLAR_X] = empty_fanout_info; + fanout_info_arg[POLAR_Y] = fanout_info[POLAR_Y]; + fanout_single_source_optimal(sources[POLAR_INV(assign_x)], fanout_info_arg, POLAR_INV(assign_x), assign_sol); + assign_sol->cost = fanout_opt_add_cost(&(assign_sol->costs[POLAR_X]), &(assign_sol->costs[POLAR_Y])); + foreach_polarity(p) { + if (MAP(sources[p])->gate) assign_sol->cost.area += MAP(sources[p])->gate->area; + } + if (fanout_opt_is_better_cost(&(fanout_sol[best_sol].cost), &(assign_sol->cost))) { + fanout_tree_free(assign_sol->trees[POLAR_X], 0); + fanout_tree_free(assign_sol->trees[POLAR_Y], 0); + } else { + foreach_polarity(p) { + if (fanout_sol[best_sol].trees[p]) fanout_tree_free(fanout_sol[best_sol].trees[p], 0); + } + best_sol = source_assign[assign_x]; + } + } + + fanout_info_free(&empty_fanout_info, 1); + } + +/* + * At this point, the best solution has been computed, and all the other trees + * have already been deallocated. + * Remove sources no longer in use. Be careful not to remove the other source + * in that process though. Do not call virtual_network_remove_node recursively. + * Not clear why it is done here, nor wht it is not done recursively after + * fanout tree construction. --> Check that later. + */ + + foreach_polarity(p) { + if (fanout_sol[best_sol].trees[p] != NIL(array_t)) { + fanout_delay_add_source(sources[p], p); + fanout_tree_build(fanout_sol[best_sol].trees[p]); + fanout_delay_free_sources(); + } + } + + n_fanouts = fanout_info[POLAR_X].n_elts + fanout_info[POLAR_Y].n_elts; + if (global.fanout_iterate && n_fanouts > 1) { + assert(sources[POLAR_X] == NIL(node_t) || sources[POLAR_Y] == NIL(node_t)); +/* + * assert(SOURCE_X_ALONE == POLAR_X && SOURCE_Y_ALONE == POLAR_Y); + */ + best_tree = fanout_sol[best_sol].trees[best_sol]; + fanout_tree_save_links(best_tree); + node_y = MAP(node_x)->node_y; + if (node_y != NIL(node_t) && node_num_fanout(node_y) > 1) { + MAP(node_y)->fanout_tree = best_tree; + MAP(node_y)->fanout_source = (sources[POLAR_X] == NIL(node_t)) ? sources[POLAR_Y] : sources[POLAR_X]; + } else { + assert(node_x != NIL(node_t) && node_num_fanout(node_x) > 1); + MAP(node_x)->fanout_tree = best_tree; + MAP(node_x)->fanout_source = (sources[POLAR_X] == NIL(node_t)) ? sources[POLAR_Y] : sources[POLAR_X]; + } + } + + /* clean up */ + + if (fanout_sol[best_sol].trees[POLAR_X] == NIL(array_t)) { + virtual_network_remove_node(node_x, 1); + } + if (fanout_sol[best_sol].trees[POLAR_Y] == NIL(array_t) && MAP(node_x)->node_y != NIL(node_t)) { + virtual_network_remove_node(MAP(node_x)->node_y, 1); + } + + foreach_polarity(p) { + if (! global.fanout_iterate && fanout_sol[best_sol].trees[p]) { + fanout_tree_free(fanout_sol[best_sol].trees[p], 0); + } + fanout_info_free(&fanout_info[p], 1); + } + return 1; +} + +static void fanout_single_source_optimal(source, fanout_info, source_polarity, fanout_sol) +node_t *source; +opt_array_t *fanout_info; +int source_polarity; +fanout_sol_t *fanout_sol; +{ + int i; + array_t **trees; + fanout_cost_t *costs; + fanout_alg_t *alg; + int best_sol; + fanout_cost_t best_cost; + int n_algs = array_n(global.fanout_alg); + + fanout_delay_add_source(source, source_polarity); + /* iterate through algorithms */ + trees = ALLOC(array_t *, n_algs); + costs = ALLOC(fanout_cost_t, n_algs); + + for (i = 0; i < n_algs; i++) { + alg = array_fetch_p(fanout_alg_t, global.fanout_alg, i); + trees[i] = fanout_tree_alloc(); + costs[i].slack = MINUS_INFINITY; + costs[i].area = INFINITY; + if (alg->min_size > fanout_info[POLAR_X].n_elts + fanout_info[POLAR_Y].n_elts) continue; + if (alg->on_flag && (*alg->optimize)(fanout_info, trees[i], &costs[i])) { + fanout_tree_add_edges(trees[i]); + fanout_tree_check(trees[i], &costs[i], fanout_info); + if (alg->peephole_flag) + fanout_tree_peephole_optimize(trees[i], &costs[i], fanout_info, global.verbose); +#ifdef DEBUG + (void)fprintf(sisout,"Algorithm name %s\n", alg->name); + (void)fprintf(sisout,"Source node: %s\n", source->name); + (void)fprintf(sisout,"fanout_info: %6.2f %6.2f\n", fanout_info[0].total_load, fanout_info[1].total_load); + (void)fprintf(sisout,"fanout buffer tree:\n"); + print_fanout_tree(fanout_tree_get_root_node(trees[i]), trees[i]); + (void)fprintf(sisout, "\n"); +#endif + } + } + + /* select best solution and build it */ + best_sol = -1; + best_cost.slack = MINUS_INFINITY; + best_cost.area = INFINITY; + for (i = 0; i < n_algs; i++) { + if (fanout_opt_is_better_cost(&costs[i], &best_cost)) { + best_cost = costs[i]; + best_sol = i; + } + } + + + assert(best_sol != -1); + +#ifdef DEBUG + alg = array_fetch_p(fanout_alg_t, global.fanout_alg, best_sol); + (void)fprintf(sisout,"source node: %s; Best algorithm: %s. ", source->name, alg->name); +#endif + + fanout_sol->trees[source_polarity] = trees[best_sol]; + fanout_sol->costs[source_polarity] = costs[best_sol]; + +#ifdef DEBUG + if (MAP(source)->gate != NULL) + (void)fprintf(sisout,". Gate type: %s\n\n", MAP(source)->gate->name); + else (void)fprintf(sisout,"\n\n"); +#endif + + + /* clean up */ + for (i = 0; i < n_algs; i++) { + if (i == best_sol) continue; + fanout_tree_free(trees[i], 0); + } + FREE(trees); + FREE(costs); + fanout_delay_free_sources(); +} + + + /* just a routine to call initialization routines */ + /* returns 0 and cleanup if there is not enough to optimize */ + +static int extract_fanout_problem(root, sources, fanout_info) +node_t *root; +node_t **sources; +opt_array_t *fanout_info; +{ + int p, q; + int n_fanouts; + + sources[POLAR_X] = root; + sources[POLAR_Y] = MAP(root)->node_y; + foreach_polarity(p) { + q = POLAR_INV(p); + fanout_info[p].links = extract_links(sources[p], sources[q]); + fanout_info_preprocess(&fanout_info[p]); + } + foreach_polarity(p) { + sources[p] = keep_external_source_only(sources[p]); + } + n_fanouts = fanout_info[POLAR_X].n_elts + fanout_info[POLAR_Y].n_elts; + if (n_fanouts > 1 || (n_fanouts >= 1 && global.opt_single_fanout)) return 1; + foreach_polarity(p) { fanout_info_free(&fanout_info[p], 1); } + return 0; +} + +static st_table *extract_links(source, exception) +node_t *source; +node_t *exception; +{ + gate_link_t link, *link_ptr; + st_table *result = st_init_table(st_ptrcmp, st_ptrhash); + + if (source == NIL(node_t)) return result; + if (gate_link_is_empty(source)) return result; + gate_link_first(source, &link); + do { + if (link.node == exception) continue; + link_ptr = ALLOC(gate_link_t, 1); + *link_ptr = link; + st_insert(result, (char *) link_ptr, NIL(char)); + } while (gate_link_next(source, &link)); + return result; +} + + + /* extract the sinks of same polarity as source */ + /* except if sink is the only possible local_node */ + +void fanout_info_preprocess(fanout_info) + opt_array_t *fanout_info; +{ + int n_elts; + int i = 0; + gate_link_t *key; + double acc_load; + delay_time_t required; + char *dummy_value = NIL(char); + st_generator *gen; + + n_elts = fanout_info->n_elts = st_count(fanout_info->links); + if (n_elts == 0) { + fanout_info->total_load = 0; + return; + } + fanout_info->required = array_alloc(gate_link_t *, n_elts); + st_foreach_item(fanout_info->links, gen, (char **) &key, &dummy_value) { + array_insert(gate_link_t *, fanout_info->required, i, key); + i++; + } + array_sort(fanout_info->required, compare_gate_links); + + fanout_info->cumul_load = ALLOC(double, n_elts + 1); + acc_load = 0.0; + for (i = 0; i < n_elts; i++) { + gate_link_t *link = array_fetch(gate_link_t *, fanout_info->required, i); + fanout_info->cumul_load[i] = acc_load; + acc_load += link->load; + } + fanout_info->total_load = fanout_info->cumul_load[n_elts] = acc_load; + + fanout_info->min_required = ALLOC(delay_time_t, n_elts); + required = PLUS_INFINITY; + for (i = n_elts - 1; i >= 0; i--) { + gate_link_t *link = array_fetch(gate_link_t *, fanout_info->required, i); + SETMIN(required, required, link->required); + fanout_info->min_required[i] = required; + } +} + + + /* keeps node if it is a source external to fanout tree */ +static node_t *keep_external_source_only(node) + node_t *node; +{ + if (node == NIL(node_t)) return node; + if (node->type == PRIMARY_INPUT) return node; + if (MAP(node)->gate == NIL(lib_gate_t)) return NIL(node_t); + if (MAP(node)->ninputs > 1) return node; + return NIL(node_t); +} + + + /* compares two gate links, by required times */ + +static int compare_gate_links(obj1, obj2) +char *obj1, *obj2; +{ + gate_link_t *g1 = *(gate_link_t **) obj1; + gate_link_t *g2 = *(gate_link_t **) obj2; + double cmp = GETMIN(g1->required) - GETMIN(g2->required); + if (cmp == 0.0) { + cmp = -(g1->load - g2->load); + if (cmp == 0.0) { + cmp = (g1->pin - g2->pin); + } + } + if (cmp < 0) return -1; + if (cmp > 0) return 1; + return 0; +} + + + /* the "free_link_flag" is for bottom_up */ + /* it should be 1 if used here in fanout_opt.c */ + /* and 0 if used in bottom_up.c to avoid freeing twice */ + +void fanout_info_free(fanout_info, free_link_flag) + opt_array_t *fanout_info; + int free_link_flag; +{ + gate_link_t *key; + char *dummy_value = NIL(char); + st_generator *gen; + + if (free_link_flag) { + st_foreach_item(fanout_info->links, gen, (char **) &key, &dummy_value) { + FREE(key); + } + } + st_free_table(fanout_info->links); + if (fanout_info->n_elts == 0) return; + array_free(fanout_info->required); + FREE(fanout_info->cumul_load); + FREE(fanout_info->min_required); +} + +int fanout_opt_is_better_cost(cost1, cost2) +fanout_cost_t *cost1; +fanout_cost_t *cost2; +{ + double slack1 = GETMIN(cost1->slack); + double slack2 = GETMIN(cost2->slack); + double diff = slack1 - slack2; + + if (FP_EQUAL(slack1, 0.0)) slack1 = 0.0; + if (FP_EQUAL(slack2, 0.0)) slack2 = 0.0; + if (FP_EQUAL(diff, 0.0)) diff = 0.0; + + if (slack2 < 0) { + return (diff > 0) ? 1 : 0; + } else if (slack1 < 0) { + return 0; + } else { + return (cost1->area < cost2->area) ? 1 : 0; + } +} + +static fanout_cost_t fanout_opt_add_cost(cost1, cost2) +fanout_cost_t *cost1; +fanout_cost_t *cost2; +{ + fanout_cost_t result; + + SETMIN(result.slack, cost1->slack, cost2->slack); + result.area = cost1->area + cost2->area; + return result; +} + + + /* exported to K.J.'s buffering algorithm */ + +node_t *fanout_opt_get_root() +{ + int p; + node_t *source; + node_t *sources[2]; + + sources[POLAR_X] = current_root_node; + sources[POLAR_Y] = MAP(current_root_node)->node_y; + foreach_polarity(p) { + source = keep_external_source_only(sources[p]); + if (source != NIL(node_t)) return source; + } + return NIL(node_t); +} + +node_t *fanout_opt_get_root_inv() +{ + int p; + node_t *source; + node_t *sources[2]; + + sources[POLAR_X] = current_root_node; + sources[POLAR_Y] = MAP(current_root_node)->node_y; + source = fanout_opt_get_root(); + foreach_polarity(p) { + if (source == sources[p]) + return sources[POLAR_INV(p)]; + } + return NIL(node_t); +} + + + + /* GLOBAL AREA RECOVERY: consider all the gates */ + +typedef struct { + int n_equiv_gates; + lib_gate_t **gates; +} gate_info_t; + +static st_table *gate_info; + + +static void init_gate_info() +{ + int i; + lib_class_t *class; + lib_gate_t *gate; + lsGen class_gen, gate_gen; + library_t *library; + gate_info_t *info; + + assert(gate_info == NIL(st_table)); + gate_info = st_init_table(st_ptrcmp, st_ptrhash); + assert((library = lib_get_library()) != NIL(library_t)); + lsForeachItem(library->classes, class_gen, class) { + info = ALLOC(gate_info_t, 1); + info->n_equiv_gates = lsLength(class->gates); + info->gates = ALLOC(lib_gate_t *, info->n_equiv_gates); + i = 0; + lsForeachItem(class->gates, gate_gen, gate) { + st_insert(gate_info, (char *) gate, (char *) info); + info->gates[i++] = gate; + } + } +} + +static void free_gate_info() +{ + int i; + st_generator *gen; + char *key; + gate_info_t *value; + array_t *values; + + values = array_alloc(gate_info_t *, 0); + st_foreach_item(gate_info, gen, &key, (char **) &value) { + if (value->gates != NIL(lib_gate_t *)) { + FREE(value->gates); + value->gates = NIL(lib_gate_t *); + array_insert_last(gate_info_t *, values, value); + } + } + st_free_table(gate_info); + for (i = 0; i < array_n(values); i++) { + value = array_fetch(gate_info_t *, values, i); + FREE(value); + } + array_free(values); + gate_info = NIL(st_table); +} + + +static void compute_required_times(node) +node_t *node; +{ +#ifdef SIS + /* skip latches */ + if (lib_gate_type(lib_gate_of(node)) != COMBINATIONAL && lib_gate_type(lib_gate_of(node)) != UNKNOWN ) { + virtual_delay_compute_node_required_time(node); + return; + } +#endif /* SIS */ + + switch (node_function(node)) { + case NODE_UNDEFINED: + /* former po removed */ + break; + case NODE_0: + case NODE_1: + fail("ERROR: constants should have been removed earlier\n"); + break; + case NODE_PO: + case NODE_PI: + /* nothing to do */ + break; + case NODE_BUF: + case NODE_INV: + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + if (MAP(node)->gate != NIL(lib_gate_t)) { + virtual_delay_compute_node_required_time(node); + } + break; + default: + ; + } +} + +static void do_global_area_recover(node) +node_t *node; +{ + gate_info_t *info; + +#ifdef SIS + /* skip latches */ + if (lib_gate_type(lib_gate_of(node)) != COMBINATIONAL && lib_gate_type(lib_gate_of(node)) != UNKNOWN ) { + recompute_arrival_times(node); + return; + } +#endif /* SIS */ + + switch (node_function(node)) { + case NODE_UNDEFINED: + /* former po removed */ + break; + case NODE_0: + case NODE_1: + if (! global.no_warning) (void) fprintf(siserr, "WARNING: constants should have been removed earlier\n"); + break; + case NODE_PO: + case NODE_PI: + /* nothing to do */ + break; + case NODE_BUF: + case NODE_INV: + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + if (MAP(node)->gate != NIL(lib_gate_t)) { + assert(st_lookup(gate_info, (char *) MAP(node)->gate, (char **) &info)); + if (info->n_equiv_gates > 1) { + resize_node(node, info); + } + recompute_arrival_times(node); + } + break; + default: + ; + } +} + +static void resize_node(node, info) +node_t *node; +gate_info_t *info; +{ + int i; + int best_index; + delay_time_t arrival, required; + fanout_cost_t *costs; + fanout_cost_t best_cost; + + required = MAP(node)->required; + costs = ALLOC(fanout_cost_t, info->n_equiv_gates); + for (i = 0; i < info->n_equiv_gates; i++) { + arrival = get_resized_node_arrival_time(node, info->gates[i]); + SETSUB(costs[i].slack, required, arrival); + costs[i].area = lib_gate_area(info->gates[i]); + } + best_index = -1; + best_cost.slack = MINUS_INFINITY; + best_cost.area = INFINITY; + for (i = 0; i < info->n_equiv_gates; i++) { + if (fanout_opt_is_better_cost(&costs[i], &best_cost)) { + best_cost = costs[i]; + best_index = i; + } + } + assert(best_index >= 0); + replace_node_gate(node, info->gates[best_index]); + FREE(costs); +} + + /* for a 'new_gate' candidate do: */ + /* recompute the arrival times at each input of 'node' */ + /* by taking into account the difference in load values */ + /* compute the arrival time at the output of new_gate and return that value */ + +static delay_time_t get_resized_node_arrival_time(node, new_gate) +node_t *node; +lib_gate_t *new_gate; +{ + int i; + delay_time_t *arrival_times; + delay_time_t **arrival_times_p; + double load_diff; + delay_time_t arrival; + double load, load_limit; + + if (new_gate == MAP(node)->gate) { + return MAP(node)->map_arrival; + } + arrival_times = ALLOC(delay_time_t, MAP(node)->ninputs); + arrival_times_p = ALLOC(delay_time_t *, MAP(node)->ninputs); + for (i = 0; i < MAP(node)->ninputs; i++) { + load_diff = delay_get_load(new_gate->delay_info[i]) - delay_get_load(MAP(node)->gate->delay_info[i]); + arrival_times[i] = get_reloaded_node_arrival_time(MAP(node)->save_binding[i], load_diff); + arrival_times_p[i] = &(arrival_times[i]); + } + load = MAP(node)->load; + load_limit = delay_get_load_limit(new_gate->delay_info[0]); + if (global.check_load_limit && load > load_limit) { + load *= global.penalty_factor; + } + arrival = delay_map_simulate(MAP(node)->ninputs, arrival_times_p, new_gate->delay_info, load); + FREE(arrival_times); + FREE(arrival_times_p); + return arrival; +} + + + /* recompute the arrival time at the node with load_diff as load */ + /* the arrival time information is supposed to have been saved in MAP(node)->arrival_info */ + /* when flag is set, new load value is kept in node */ + +static delay_time_t get_reloaded_node_arrival_time(node, load_diff) +node_t *node; +double load_diff; +{ + double load, load_limit; + + load = MAP(node)->load + load_diff; + if (node->type == PRIMARY_INPUT) { + load_limit = pipo_get_pi_load_limit(node); + } else { + load_limit = delay_get_load_limit(MAP(node)->gate->delay_info[0]); + } + if (global.check_load_limit && load > load_limit) { + load *= global.penalty_factor; + } + return recompute_map_arrival(node, load); +} + + + /* have to change the loads on the inputs and the gate_links appropriately for load info */ + /* do not need to compute the required times: done later */ + /* WARNING: may be wrong: what if same gate has several connections to the same node? */ + +static void replace_node_gate(node, new_gate) +node_t *node; +lib_gate_t *new_gate; +{ + int i; + node_t *input; + double load_diff; + + if (new_gate == MAP(node)->gate) return; + for (i = 0; i < MAP(node)->ninputs; i++) { + load_diff = delay_get_load(new_gate->delay_info[i]) - delay_get_load(MAP(node)->gate->delay_info[i]); + input = MAP(node)->save_binding[i]; + MAP(input)->load += load_diff; + MAP(input)->map_arrival = recompute_map_arrival(input, MAP(input)->load); + } + MAP(node)->gate = new_gate; +} + + /* FUNCTION: to be used when the output load has changed to recompute MAP(node)->map_arrival */ + +static delay_time_t recompute_map_arrival(node, load) +node_t *node; +double load; +{ + int i; + delay_time_t arrival, drive; + delay_time_t **arrival_times; + + assert(node->type != PRIMARY_OUTPUT); + if (node->type == PRIMARY_INPUT) { + arrival = pipo_get_pi_arrival(node); + drive = pipo_get_pi_drive(node); + arrival.rise += drive.rise * load; + arrival.fall += drive.fall * load; + } else { + arrival_times = ALLOC(delay_time_t *, MAP(node)->ninputs); + for (i = 0; i < MAP(node)->ninputs; i++) { + arrival_times[i] = &(MAP(node)->arrival_info[i]); + } + arrival = delay_map_simulate(MAP(node)->ninputs, arrival_times, MAP(node)->gate->delay_info, load); + FREE(arrival_times); + } + return arrival; +} + + + /* PROCEDURE: to be used when the arrival times of the inputs have changed to recompute */ + /* MAP(node)->arrival_info and MAP(node)->map_arrival */ + +static void recompute_arrival_times(node) +node_t *node; +{ + int i; + delay_time_t *arrival_times; + delay_time_t **arrival_times_p; + + arrival_times = ALLOC(delay_time_t, MAP(node)->ninputs); + arrival_times_p = ALLOC(delay_time_t *, MAP(node)->ninputs); + for (i = 0; i < MAP(node)->ninputs; i++) { + arrival_times[i] = MAP(MAP(node)->save_binding[i])->map_arrival; + arrival_times_p[i] = &(arrival_times[i]); + } + MAP(node)->map_arrival = delay_map_simulate(MAP(node)->ninputs, arrival_times_p, MAP(node)->gate->delay_info, MAP(node)->load); + FREE(MAP(node)->arrival_info); + MAP(node)->arrival_info = arrival_times; + FREE(arrival_times_p); +} + + + /* the next two routines are needed to guarantee that the nodes */ + /* are visited in the proper order. 'network_dfs' does not always */ + /* work on the virtual networks after fanout optimization */ + /* moreover, we can skip over nodes this way, so it can be faster */ + +static void virtual_net_for_all_nodes_outputs_first(network,fn) +network_t *network; +VoidFn fn; +{ + lsGen gen; + node_t *pi; + st_table *visited; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_input(network, gen, pi) { + outputs_first_rec(pi, fn, visited); + } + st_free_table(visited); +} + +static void outputs_first_rec(node, fn, visited) +node_t *node; +VoidFn fn; +st_table *visited; +{ + gate_link_t link; + + if (st_lookup(visited, (char *) node, NIL(char *))) return; + st_insert(visited, (char *) node, NIL(char)); + if (node->type != PRIMARY_OUTPUT) { + assert(node->type == PRIMARY_INPUT || MAP(node)->gate != NIL(lib_gate_t)); + if (gate_link_n_elts(node) > 0) { + gate_link_first(node, &link); + do { + outputs_first_rec(link.node, fn, visited); + } while (gate_link_next(node, &link)); + } + } + (*fn)(node); +} + +static void virtual_net_for_all_nodes_inputs_first(network,fn) +network_t *network; +VoidFn fn; +{ + lsGen gen; + node_t *po; + node_t *node; + st_table *visited; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_output(network, gen, po) { + node = map_po_get_fanin(po); + inputs_first_rec(node, fn, visited); + (*fn)(po); + } + st_free_table(visited); +} + +static void inputs_first_rec(node, fn, visited) +node_t *node; +VoidFn fn; +st_table *visited; +{ + int i; + + if (st_lookup(visited, (char *) node, NIL(char *))) return; + st_insert(visited, (char *) node, NIL(char)); + if (node->type != PRIMARY_INPUT) { + assert(MAP(node)->gate != NIL(lib_gate_t)); + for (i = 0; i < MAP(node)->ninputs; i++) { + inputs_first_rec(MAP(node)->save_binding[i], fn, visited); + } + } + (*fn)(node); +} diff --git a/sis/map/fanout_opt_static.h b/sis/map/fanout_opt_static.h new file mode 100644 index 0000000..ef51476 --- /dev/null +++ b/sis/map/fanout_opt_static.h @@ -0,0 +1,101 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_opt_static.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)fanout_opt_static.h 1.4 */ +/* last modified on 7/1/91 at 22:41:14 */ + +typedef struct fanout_alg_descr { + int alg_id; /* ID for identifying properties. */ + char *name; /* Name of algorithm. */ + void (*init_fn)(); /* Initialization function. */ + int on_flag; /* Some sort of flag. */ +} +fanout_alg_descr; + +typedef struct fanout_prop_descr { + int alg_id; /* ID of algorithm. */ + char *name; /* name of property. */ + int value; /* Value of property. */ + void (*update_fn)(); /* Function to update property. */ +} +fanout_prop_descr; + + +static fanout_alg_descr fanout_algorithms [] = { + + { 1, "noalg", noalg_init, 1 }, + { 2, "lt_trees", lt_trees_init, 1 }, + { 3, "two_level", two_level_init, 1 }, + { 4, "fanout_dump", fanout_dump_init, 0 }, + { 5, "mixed_lt_trees", mixed_lt_trees_init, 1 }, + { 6, "bottom_up", bottom_up_init, 1 }, + { 7, "balanced", balanced_init, 1 }, + { 8, "top_down", top_down_init, 0 }, + { 0 } +}; + +static fanout_prop_descr fanout_properties [] = { + + { 1, "min_size", 1, fanout_opt_update_size_threshold }, + { 1, "peephole", 1, fanout_opt_update_peephole_flag }, + + { 2, "min_size", 1, fanout_opt_update_size_threshold }, + { 2, "peephole", 1, fanout_opt_update_peephole_flag }, + { 2, "max_gaps", 5, lt_trees_set_max_n_gaps }, + + { 3, "min_size", 2, fanout_opt_update_size_threshold }, + { 3, "peephole", 1, fanout_opt_update_peephole_flag }, + + { 4, "min_size", 2, fanout_opt_update_size_threshold }, + { 4, "peephole", 0, fanout_opt_update_peephole_flag }, + { 4, "dump_threshold", 20, fanout_dump_set_dump_threshold }, + + { 5, "min_size", 1, fanout_opt_update_size_threshold }, + { 5, "peephole", 1, fanout_opt_update_peephole_flag }, + { 5, "max_gaps", 3, mixed_lt_trees_set_max_n_gaps }, + { 5, "max_x", 10, mixed_lt_trees_set_max_x_index }, + { 5, "max_y", 10, mixed_lt_trees_set_max_y_index }, + + { 6, "min_size", 2, fanout_opt_update_size_threshold }, + { 6, "peephole", 1, fanout_opt_update_peephole_flag }, + + { 7, "min_size", 2, fanout_opt_update_size_threshold }, + { 7, "peephole", 1, fanout_opt_update_peephole_flag }, + + { 8, "min_size", 2, fanout_opt_update_size_threshold }, + { 8, "peephole", 1, fanout_opt_update_peephole_flag }, + { 8, "mode", 6, top_down_set_mode }, + { 8, "debug", 0, top_down_set_debug }, + { 0 } +}; + +static delay_time_t get_reloaded_node_arrival_time(); +static delay_time_t get_resized_node_arrival_time(); +static delay_time_t recompute_map_arrival(); +static fanout_cost_t fanout_opt_add_cost(); +static int compare_gate_links(); +static int extract_fanout_problem(); +static int fanout_map_optimal(); +static node_t *keep_external_source_only(); +static st_table *extract_links(); +static void compute_required_times(); +static void do_fanout_opt(); +static void do_global_area_recover(); +static void fanout_opt_end(); +static void fanout_opt_init(); +static void fanout_single_source_optimal(); +static void free_gate_info(); +static void init_gate_info(); +static void inputs_first_rec(); +static void outputs_first_rec(); +static void recompute_arrival_times(); +static void replace_node_gate(); +static void resize_node(); +static void virtual_net_for_all_nodes_inputs_first(); +static void virtual_net_for_all_nodes_outputs_first(); diff --git a/sis/map/fanout_tree.c b/sis/map/fanout_tree.c new file mode 100644 index 0000000..d826b46 --- /dev/null +++ b/sis/map/fanout_tree.c @@ -0,0 +1,1767 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_tree.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/14 07:44:52 $ + * + */ +/* file @(#)fanout_tree.c 1.5 */ +/* last modified on 7/1/91 at 22:40:54 */ + +#include "sis.h" +#include "map_macros.h" +#include "map_int.h" +#include "fanout_int.h" +#include "fanout_delay.h" +#include "gate_link.h" +#include "bin_int.h" + +static n_gates_t n_gates; +typedef enum fanout_tree_enum fanout_tree_t; +enum fanout_tree_enum {SINK_NODE, BUFFER_NODE, SOURCE_NODE}; +typedef struct fanout_node_struct fanout_node_t; +struct fanout_node_struct { + fanout_tree_t type; + gate_link_t *link; + int gate_index; + int arity; + array_t *children; + node_t *node; + int polarity; + double load; +#ifdef DEBUG + delay_time_t save_required; +#endif /* DEBUG */ + delay_time_t required; + delay_time_t arrival; /* including intrinsic delay */ + double area; + array_t *peephole; + array_t *remove_opt; +}; + +static fanout_node_t DEFAULT_FANOUT_NODE = { + /* type */ SINK_NODE, + /* link */ NIL(gate_link_t), + /* gate_index */ -1, + /* arity */ 0, + /* children */ NIL(array_t), + /* node */ NIL(node_t), + /* polarity */ POLAR_X, + /* load */ 0.0, +#ifdef DEBUG + /* save_required */ {-INFINITY,-INFINITY}, +#endif + /* required */ {-INFINITY,-INFINITY}, + /* arrival */ { INFINITY, INFINITY}, + /* area */ INFINITY, + /* peephole */ NIL(array_t), + /* remove_opt */ NIL(array_t) +}; + +#include "fanout_tree_static.h" + + /* EXTERNAL INTERFACE */ + +array_t *fanout_tree_alloc() +{ + return array_alloc(fanout_node_t, 0); +} + + /* if flag free_links_p is 1, should also free the gate_links */ + +void fanout_tree_free(array, free_links_p) +array_t *array; +int free_links_p; +{ + int i; + fanout_node_t *node; + + for (i = 0; i < array_n(array); i++) { + node = array_fetch_p(fanout_node_t, array, i); + array_free(node->children); + if (free_links_p && node->type == SINK_NODE) { + FREE(node->link); + } + } + array_free(array); +} + + /* necessary if the tree is to survive its fanout environment */ + /* also, since the MAP(link->node)->save_binding is going to disappear */ + /* we need to replace it by the fanout number of the node */ + /* it is ugly to overload like this. See fanout_est_get_pin_fanout_index */ + /* a value of -1 for the fanout_index would indicate something was not computed properly */ + /* Always initialized to -1 (default value) to catch that kind of problems */ + +void fanout_tree_save_links(array) +array_t *array; +{ + int i; + gate_link_t *link; + fanout_node_t *node; + + for (i = 0; i < array_n(array); i++) { + node = array_fetch_p(fanout_node_t, array, i); + if (node->type == SINK_NODE) { + link = node->link; + node->link = ALLOC(gate_link_t, 1); + *(node->link) = *link; + if (link->node == NIL(node_t)) continue; /* was a dummy tree to start with. Nothing to do */ + assert(MAP(link->node)->pin_info != NIL(fanin_fanout_t)); + node->link->node = NIL(node_t); + if (link->node->type == PRIMARY_OUTPUT) { + node->link->pin = MAP(link->node)->pin_info[0].fanout_index; + } else { + node->link->pin = MAP(link->node)->pin_info[link->pin].fanout_index; + } + assert(node->link->pin != -1); + } + } +} + +void fanout_tree_copy(to, from) +array_t *to; +array_t *from; +{ + int i; + fanout_node_t *node; + + for (i = 0; i < array_n(from); i++) { + node = array_fetch_p(fanout_node_t, from, i); + array_insert(fanout_node_t, to, i, *node); + } +} + + + /* exported to avoid having to do it several times */ + /* probably should be made internal to that file */ + +void fanout_tree_add_edges(array) +array_t *array; +{ + int i, j, next_i; + fanout_node_t *node; + + for (i = 0; i < array_n(array); i = next_i) { + node = array_fetch_p(fanout_node_t, array, i); + assert(node->type == BUFFER_NODE); + node->type = SOURCE_NODE; + node->children = array_alloc(fanout_node_t *, 0); + next_i = i + 1; + for (j = 0; j < node->arity; j++) { + fanout_node_t *child; + child = array_fetch_p(fanout_node_t, array, next_i); + array_insert_last(fanout_node_t *, node->children, child); + next_i = add_edges_rec(array, next_i); + } + assert(node->arity == array_n(node->children)); + } +} + + + /* make sure the tree is consistent and the costs are as announced */ + +void fanout_tree_check(array, cost, fanout_info) +array_t *array; +fanout_cost_t *cost; +opt_array_t *fanout_info; +{ + array_t *trees = fanout_tree_get_roots(array); + n_gates = fanout_delay_get_n_gates(); + check_polarities(trees, fanout_info); + check_required(trees, cost->slack); + check_area(trees, cost->area); + array_free(trees); +} + + + /* try to find minimum area tree which meets the requirements */ + /* or if none, the one closest to meeting required times */ + +static int peephole_global_debug; +void fanout_tree_peephole_optimize(array, cost, fanout_info, debug) +array_t *array; +fanout_cost_t *cost; +opt_array_t *fanout_info; +int debug; +{ + array_t *nodes; + array_t *trees = fanout_tree_get_roots(array); + + peephole_global_debug = debug; + fanout_tree_alloc_peephole(trees); + fanout_tree_compute_arrival_times(trees); + nodes = get_forest_in_bottom_up_order(trees); + if (peephole_optimize(trees, nodes, cost)) { + build_peephole_trees(trees); + fanout_tree_check(array, cost, fanout_info); + } + fanout_tree_compute_arrival_times(trees); + fanout_tree_remove_unnecessary_buffers(trees, cost); + fanout_tree_check(array, cost, fanout_info); + fanout_free_peephole(nodes); + array_free(nodes); + array_free(trees); +} + + + /* finally build the tree */ + +void fanout_tree_build(array) +array_t *array; +{ + array_t *trees = fanout_tree_get_roots(array); + do_build_tree(trees, array); + free_unused_sources(trees); + array_free(trees); +} + + /* for sink nodes (i.e. leaves) */ + +void fanout_tree_insert_sink(array, link) +array_t *array; +gate_link_t *link; +{ + fanout_node_t node; + node = DEFAULT_FANOUT_NODE; + node.link = link; + array_insert_last(fanout_node_t, array, node); +} + + + /* to be used for source or intermediate nodes */ + /* arity can't be 0 (not a leaf) */ + +void fanout_tree_insert_gate(array, gate_index, arity) +array_t *array; +int gate_index; +int arity; +{ + fanout_node_t node; + assert(arity > 0); + node = DEFAULT_FANOUT_NODE; + node.type = BUFFER_NODE; + node.gate_index = gate_index; + node.arity = arity; + array_insert_last(fanout_node_t, array, node); +} + + + /* INTERNAL INTERFACE */ + +static int add_edges_rec(array, i) +array_t *array; +int i; +{ + int next_i, j; + fanout_node_t *node; + + node = array_fetch_p(fanout_node_t, array, i); + node->children = array_alloc(fanout_node_t *, 0); + next_i = i + 1; + switch (node->type) { + case SINK_NODE: + break; + case BUFFER_NODE: + for (j = 0; j < node->arity; j++) { + fanout_node_t *child; + child = array_fetch_p(fanout_node_t, array, next_i); + array_insert_last(fanout_node_t *, node->children, child); + next_i = add_edges_rec(array, next_i); + } + break; + default: + fail("unexpected node type in do_build_rooted_tree"); + break; + } + assert(node->arity == array_n(node->children)); + return next_i; +} + +static array_t *fanout_tree_get_roots(array) +array_t *array; +{ + int i; + fanout_node_t *node; + array_t *roots = array_alloc(fanout_node_t *, 0); + for (i = 0; i < array_n(array); i++) { + node = array_fetch_p(fanout_node_t, array, i); + if (node->type == SOURCE_NODE) + array_insert_last(fanout_node_t *, roots, node); + } + return roots; +} + + +static void do_build_tree(trees, array) +array_t *trees; +array_t *array; +{ + int i; + fanout_node_t *source; + + for (i = 0; i < array_n(trees); i++) { + source = array_fetch(fanout_node_t *, trees, i); + source->node = fanout_delay_get_source_node(source->gate_index); + gate_link_delete_all(source->node); + do_build_tree_rec(source, array); + } +} + +static void do_build_tree_rec(source, array) +fanout_node_t *source; +array_t *array; +{ + int i; + fanout_node_t *fanout_node; + + assert(array_n(source->children) > 0); + for (i = 0; i < array_n(source->children); i++) { + fanout_node = array_fetch(fanout_node_t *, source->children, i); + switch (fanout_node->type) { + case SINK_NODE: + virtual_network_add_to_gate_link(source->node, fanout_node->link); + break; + case BUFFER_NODE: + fanout_node->node = create_buffer(source->node, fanout_node->gate_index); + do_build_tree_rec(fanout_node, array); + break; + default: + fail("unexpected node type in do_build_rooted_tree"); + break; + } + } + virtual_delay_compute_node_required_time(source->node); +} + +static node_t *create_buffer(source, gate_index) +node_t *source; +int gate_index; +{ + gate_link_t new_link; + int phase; + node_t *new_node = node_alloc(); + +/* + assert(is_inverter(n_gates, gate_index)); + node_replace(new_node, node_literal(source, 0)); +*/ + phase = (is_inverter(n_gates, gate_index)) ? 0 : 1; + node_replace(new_node, node_literal(source, phase)); + network_add_node(node_network(source), new_node); + fanout_log_register_node(new_node); + map_alloc(new_node); + MAP(new_node)->gate = fanout_delay_get_gate(gate_index); + MAP(new_node)->ninputs = 1; + MAP(new_node)->save_binding = ALLOC(node_t *, 1); + MAP(new_node)->save_binding[0] = source; + MAP(new_node)->map_arrival = PLUS_INFINITY; + new_link.node = new_node; + new_link.pin = 0; + new_link.load = fanout_delay_get_buffer_load(gate_index); + new_link.required = MINUS_INFINITY; + gate_link_put(source, &new_link); + return new_node; +} + + /* the rest is to perform consistency checks on the input */ + +static void check_polarities(trees, fanout_info) +array_t *trees; +opt_array_t *fanout_info; +{ + int i, p; + gate_link_t *link; + fanout_node_t *source; + st_table *sink_table = st_init_table(st_ptrcmp, st_ptrhash); + + foreach_polarity(p) { + for (i = 0; i < fanout_info[p].n_elts; i++) { + link = array_fetch(gate_link_t *, fanout_info[p].required, i); + st_insert(sink_table, (char *) link, (char *) p); + } + } + for (i = 0; i < array_n(trees); i++) { + int source_polarity; + source = array_fetch(fanout_node_t *, trees, i); + source_polarity = fanout_delay_get_source_polarity(source->gate_index); + check_polarity_rec(source, source_polarity, sink_table); + } + assert (st_count(sink_table) == 0); + st_free_table(sink_table); +} + +static void check_polarity_rec(source, source_polarity, sink_table) +fanout_node_t *source; +int source_polarity; +st_table *sink_table; +{ + int i; + int sink_polarity; + int buffer_polarity; + fanout_node_t *fanout_node; + char *dummy; + + for (i = 0; i < array_n(source->children); i++) { + fanout_node = array_fetch(fanout_node_t *, source->children, i); + switch (fanout_node->type) { + case SINK_NODE: + assert(st_lookup_int(sink_table, (char *) fanout_node->link, &sink_polarity)); + assert(sink_polarity == source_polarity); + st_delete(sink_table, (char **) &fanout_node->link, &dummy); + break; + case BUFFER_NODE: + buffer_polarity = (fanout_delay_get_buffer_polarity(fanout_node->gate_index) == POLAR_X) ? source_polarity : POLAR_INV(source_polarity); + check_polarity_rec(fanout_node, buffer_polarity, sink_table); + break; + default: + fail("unexpected node type in check_polarity_rec"); + break; + } + } +} + +static void check_required(trees, ref_required) +array_t *trees; +delay_time_t ref_required; +{ + int i; + fanout_node_t *source; + delay_time_t required; + + required = PLUS_INFINITY; + for (i = 0; i < array_n(trees); i++) { + source = array_fetch(fanout_node_t *, trees, i); + source->required = check_required_rec(source); + SETMIN(required, required, source->required); + } + assert(IS_EQUAL(ref_required, required)); +} + +/* Exported to compute the delay thru a fanout_tree for the top_down alg. */ +delay_time_t +map_compute_fanout_tree_req_time(tree) +array_t *tree; +{ + fanout_node_t *source; + delay_time_t required; + + add_edges_rec(tree, 0); /* Build the tree */ + source = array_fetch_p(fanout_node_t, tree, 0); + required = check_required_rec(source); + return required; +} + +static delay_time_t check_required_rec(source) +fanout_node_t *source; +{ + int i; + delay_time_t required, local_required; + double load, local_load; + int n_fanouts; + fanout_node_t *fanout_node; + + required = PLUS_INFINITY; + load = 0.0; + n_fanouts = array_n(source->children); + for (i = 0; i < array_n(source->children); i++) { + fanout_node = array_fetch(fanout_node_t *, source->children, i); + switch (fanout_node->type) { + case SINK_NODE: + local_required = fanout_node->required = fanout_node->link->required; + local_load = fanout_node->link->load; + break; + case BUFFER_NODE: + fanout_node->required = check_required_rec(fanout_node); + local_required = fanout_delay_backward_intrinsic(fanout_node->required, fanout_node->gate_index); + local_load = fanout_delay_get_buffer_load(fanout_node->gate_index); + break; + default: + fail("unexpected node type in check_polarity_rec"); + break; + } + load += local_load; + SETMIN(required, required, local_required); + } + load += map_compute_wire_load(n_fanouts); +#ifdef DEBUG + source->save_required = required; +#endif + return fanout_delay_backward_load_dependent(required, source->gate_index, load); +} + +static void check_area(trees, ref_area) +array_t *trees; +double ref_area; +{ + int i; + array_t *nodes; + fanout_node_t *node; + double area = 0.0; + + nodes = get_forest_in_bottom_up_order(trees); + for (i = 0; i < array_n(nodes); i++) { + node = array_fetch(fanout_node_t *, nodes, i); + if (node->type == BUFFER_NODE || node->type == SOURCE_NODE) + area += fanout_delay_get_area(node->gate_index); + } + assert(FP_EQUAL(area, ref_area)); + array_free(nodes); +} + + /* FOR DEBUGGING: please call "add_edges" first */ + +void print_fanout_tree(trees, array) +array_t *trees; +array_t *array; +{ + int i; + fanout_node_t *source; + + for (i = 0; i < array_n(trees); i++) { + int source_polarity; + source = array_fetch(fanout_node_t *, trees, i); + source_polarity = fanout_delay_get_source_polarity(source->gate_index); + source->node = fanout_delay_get_source_node(source->gate_index); + (void) fprintf(sisout, "source(%s,p(%d),", source->node->name, source_polarity); +#ifdef DEBUG + (void) fprintf(sisout, "r(%2.3f,%2.3f)", source->save_required.rise, source->save_required.fall); +#endif + (void) fprintf(sisout, "s(%2.3f,%2.3f))\n", source->required.rise, source->required.fall); + print_tree_rec(source, source_polarity, array, 4); + } +} + +static void print_tree_rec(source, source_polarity, array, n_tabs) +fanout_node_t *source; +int source_polarity; +array_t *array; +int n_tabs; +{ + int i; + int buffer_polarity; + lib_gate_t *gate; + fanout_node_t *fanout_node; + delay_time_t required; + + for (i = 0; i < array_n(source->children); i++) { + fanout_node = array_fetch(fanout_node_t *, source->children, i); + switch (fanout_node->type) { + case SINK_NODE: + print_tabs(n_tabs); + if (fanout_node->link->node == NIL(node_t)) { + (void) fprintf(sisout, "sink(-%d-,p(%d),", fanout_node->link->pin, source_polarity); + } else { + (void) fprintf(sisout, "sink(%s,p(%d),", fanout_node->link->node->name, source_polarity); + } + (void) fprintf(sisout, "l(%2.3f),", fanout_node->link->load); + (void) fprintf(sisout, "r(%2.3f,%2.3f))\n", fanout_node->required.rise, fanout_node->required.fall); + break; + case BUFFER_NODE: + print_tabs(n_tabs); + gate = fanout_delay_get_gate(fanout_node->gate_index); + buffer_polarity = (fanout_delay_get_buffer_polarity(fanout_node->gate_index) == POLAR_X) ? source_polarity : POLAR_INV(source_polarity); + (void) fprintf(sisout, "buffer(%s,p(%d),", gate->name, buffer_polarity); + (void) fprintf(sisout, "l(%2.3f),", fanout_delay_get_buffer_load(fanout_node->gate_index)); + required = fanout_delay_backward_intrinsic(fanout_node->required, fanout_node->gate_index); + (void) fprintf(sisout, "r(%2.3f,%2.3f))\n", required.rise, required.fall); + print_tree_rec(fanout_node, buffer_polarity, array, n_tabs + 4); + break; + default: + fail("unexpected node type in check_polarity_rec"); + break; + } + } +} + +static void print_tabs(n_tabs) +int n_tabs; +{ + int i; + + assert(n_tabs >= 0); + for (i = 0; i < n_tabs; i++) + (void) fprintf(sisout, " "); +} + +static void free_unused_sources(trees) +array_t *trees; +{ + int i, source_index; + node_t *node; + char *dummy; + fanout_node_t *source; + st_table *used_sources = st_init_table(st_ptrcmp, st_ptrhash); + + for (i = 0; i < array_n(trees); i++) { + source = array_fetch(fanout_node_t *, trees, i); + source->node = fanout_delay_get_source_node(source->gate_index); + st_insert(used_sources, (char *) source->node, NIL(char)); + } + foreach_source(n_gates, source_index) { + node = fanout_delay_get_source_node(source_index); + if (! st_lookup(used_sources, (char *) node, &dummy)) + virtual_network_remove_node(node, 1); + } + st_free_table(used_sources); +} + +static array_t *get_forest_in_bottom_up_order(trees) +array_t *trees; +{ + int i; + fanout_node_t *source; + array_t *nodes = array_alloc(fanout_node_t *, 0); + + for (i = 0; i < array_n(trees); i++) { + source = array_fetch(fanout_node_t *, trees, i); + get_forest_in_bottom_up_order_rec(source, nodes); + array_insert_last(fanout_node_t *, nodes, source); + } + return nodes; +} + +static void get_forest_in_bottom_up_order_rec(source, nodes) +fanout_node_t *source; +array_t *nodes; +{ + int i; + fanout_node_t *fanout_node; + + for (i = 0; i < array_n(source->children); i++) { + fanout_node = array_fetch(fanout_node_t *, source->children, i); + switch (fanout_node->type) { + case SINK_NODE: + array_insert_last(fanout_node_t *, nodes, fanout_node); + break; + case BUFFER_NODE: + get_forest_in_bottom_up_order_rec(fanout_node, nodes); + array_insert_last(fanout_node_t *, nodes, fanout_node); + break; + default: + fail("unexpected node type"); + break; + } + } +} + +typedef struct peep_entry_struct peep_entry_t; +struct peep_entry_struct { + delay_time_t required; /* before intrinsic, after load dependent (except for sinks) */ + delay_time_t arrival; /* after intrinsic, before load dependent (except for sinks) */ + double load; + double area; + int buffer_index; + array_t *children_incr; +}; + +typedef struct peep_seq_struct peep_seq_t; +struct peep_seq_struct { + delay_time_t required; + double area; + int child_index; +}; + +static int peephole_optimize(trees, nodes, cost) +array_t *trees; +array_t *nodes; +fanout_cost_t *cost; +{ + int i, j; + fanout_node_t *node; + peep_entry_t *entry; + fanout_cost_t peephole_cost; + + for (i = 0; i < array_n(nodes); i++) { + node = array_fetch(fanout_node_t *, nodes, i); + if (node->type == SINK_NODE) continue; + for (j = 0; j < array_n(node->peephole); j++) { + entry = array_fetch_p(peep_entry_t, node->peephole, j); + peephole_optimize_node(node, entry); + } + } + if (peephole_is_better(trees, cost, &peephole_cost)) { + *cost = peephole_cost; + return 1; + } + return 0; +} + + + /* BEGIN OPTIMAL SIZING ALGORITHM FOR DELAY MINIMIZATION OF FANOUT TREES */ + +static void peephole_optimize_node(node, entry) +fanout_node_t *node; +peep_entry_t *entry; +{ + int i; + array_t *log; + int critical_child; + int *current_incr; + fanout_cost_t cost; + peep_seq_t seq_entry; + + log = array_alloc(peep_seq_t, 0); + current_incr = ALLOC(int, array_n(node->children)); + for (i = 0; i < array_n(node->children); i++) + current_incr[i] = 0; + + for (;;) { + if (! incr_critical_child(node, current_incr, &critical_child)) break; + current_incr[critical_child]++; + seq_entry.child_index = critical_child; + compute_current_cost(node, entry->buffer_index, current_incr, &cost); + seq_entry.required = cost.slack; + seq_entry.area = cost.area; + array_insert_last(peep_seq_t, log, seq_entry); + } + + select_best_log_entry(node, log, entry); + FREE(current_incr); + array_free(log); +} + +static int incr_critical_child(node, current_incr, critical_child_index) + fanout_node_t *node; + int *current_incr; + int *critical_child_index; +{ + int i; + delay_time_t required, local_required; + fanout_node_t *child, *critical_child; + peep_entry_t *child_entry; + + *critical_child_index = -1; + + /* find critical child */ + required = PLUS_INFINITY; + for (i = 0; i < array_n(node->children); i++) { + child = array_fetch(fanout_node_t *, node->children, i); + child_entry = array_fetch_p(peep_entry_t, child->peephole, current_incr[i]); + local_required = child_entry->required; + if (child_entry->buffer_index != -1) + local_required = fanout_delay_backward_intrinsic(local_required, child_entry->buffer_index); + if (GETMIN(required) > GETMIN(local_required)) { + required = local_required; + *critical_child_index = i; + } + } + + /* check whether can increment critical child */ + critical_child = array_fetch(fanout_node_t *, node->children, *critical_child_index); + return (current_incr[*critical_child_index] < array_n(critical_child->peephole) - 1); +} + +static void compute_current_cost(node, source_index, current_incr, cost) + fanout_node_t *node; /* some node in the fanout tree */ + int source_index; /* index of a possible gate at that node */ + int *current_incr; /* distribution of size increments to children */ + fanout_cost_t *cost; /* where the results are put: area, required */ +{ + int i; + delay_time_t required, local_required; + double load, area; + fanout_node_t *child; + peep_entry_t *child_entry; + + required = PLUS_INFINITY; + load = 0.0; + area = 0.0; + for (i = 0; i < array_n(node->children); i++) { + child = array_fetch(fanout_node_t *, node->children, i); + child_entry = array_fetch_p(peep_entry_t, child->peephole, current_incr[i]); + local_required = child_entry->required; + if (child_entry->buffer_index != -1) + local_required = fanout_delay_backward_intrinsic(local_required, child_entry->buffer_index); + SETMIN(required, required, local_required); + area += child_entry->area; + load += child_entry->load; + } + load += map_compute_wire_load(array_n(node->children)); + cost->slack = fanout_delay_backward_load_dependent(required, source_index, load); + cost->area = area + fanout_delay_get_area(source_index); +} + +static void select_best_log_entry(node, log, entry) + fanout_node_t *node; + array_t *log; + peep_entry_t *entry; +{ + int i; + int best_log_index; + fanout_cost_t best_cost, cost; + int *incr; + peep_seq_t *seq_entry; + + /* first compute cost with all sizes minimum */ + best_log_index = -1; + incr = ALLOC(int, array_n(node->children)); + for (i = 0; i < array_n(node->children); i++) + incr[i] = 0; + compute_current_cost(node, entry->buffer_index, incr, &best_cost); + SETSUB(best_cost.slack, best_cost.slack, entry->arrival); + + /* then select best cost */ + for (i = 0; i < array_n(log); i++) { + seq_entry = array_fetch_p(peep_seq_t, log, i); + SETSUB(cost.slack, seq_entry->required, entry->arrival); + cost.area = seq_entry->area; + if (! fanout_opt_is_better_cost(&best_cost, &cost)) { + best_cost = cost; + best_log_index = i; + } + } + + /* run the log up to the best cost entry */ + for (i = 0; i <= best_log_index; i++) { + seq_entry = array_fetch_p(peep_seq_t, log, i); + incr[seq_entry->child_index]++; + } + + /* save the best size incr assignment to children */ + for (i = 0; i < array_n(node->children); i++) + array_insert(int, entry->children_incr, i, incr[i]); + + /* compute the best cost */ + compute_current_cost(node, entry->buffer_index, incr, &best_cost); + FREE(incr); + entry->required = best_cost.slack; + entry->area = best_cost.area; +} + + /* END OPTIMAL SIZING ALGORITHM FOR DELAY MINIMIZATION OF FANOUT TREES */ + + +static void build_peephole_trees(trees) +array_t *trees; +{ + int i; + fanout_node_t *source; + peep_entry_t *entry; + + for (i = 0; i < array_n(trees); i++) { + source = array_fetch(fanout_node_t *, trees, i); + entry = array_fetch_p(peep_entry_t, source->peephole, 0); + build_peephole_tree_rec(source, entry); + source->required = entry->required; + source->area = entry->area; + } +} + +static void build_peephole_tree_rec(source, entry) +fanout_node_t *source; +peep_entry_t *entry; +{ + int i; + int child_incr; + peep_entry_t *child_entry; + fanout_node_t *fanout_node; + + for (i = 0; i < array_n(source->children); i++) { + fanout_node = array_fetch(fanout_node_t *, source->children, i); + switch (fanout_node->type) { + case SINK_NODE: + break; + case BUFFER_NODE: + child_incr = array_fetch(int, entry->children_incr, i); + child_entry = array_fetch_p(peep_entry_t, fanout_node->peephole, child_incr); + build_peephole_tree_rec(fanout_node, child_entry); + fanout_node->gate_index = child_entry->buffer_index; + fanout_node->required = child_entry->required; + fanout_node->area = child_entry->area; + break; + default: + fail("unexpected node type in do_build_rooted_tree"); + break; + } + } +} + +static int peephole_is_better(trees, cost, peephole_cost) +array_t *trees; +fanout_cost_t *cost; +fanout_cost_t *peephole_cost; +{ + int i; + fanout_node_t *node; + peep_entry_t *entry; + int peephole_is_better_p; + + peephole_cost->area = 0.0; + peephole_cost->slack = PLUS_INFINITY; + for (i = 0; i < array_n(trees); i++) { + node = array_fetch(fanout_node_t *, trees, i); + entry = array_fetch_p(peep_entry_t, node->peephole, 0); + peephole_cost->area += entry->area; + SETMIN(peephole_cost->slack, peephole_cost->slack, entry->required); + } + peephole_is_better_p = fanout_opt_is_better_cost(peephole_cost, cost); + if (peephole_global_debug == -1 || (peephole_global_debug && ! peephole_is_better_p)) { + (void) fprintf(sisout, "before peephole: a(%2.2f) s(%2.4f %2.4f)\t", cost->area, cost->slack.rise, cost->slack.fall); + (void) fprintf(sisout, "after peephole: a(%2.2f) s(%2.4f %2.4f)\n", peephole_cost->area, peephole_cost->slack.rise, peephole_cost->slack.fall); + } + return peephole_is_better_p; +} + + + /* ROUTINES FOR INITIALIZATION AND DEALLOCATION OF PEEPHOLE AND ARRIVAL FIELDS */ + +static void fanout_tree_alloc_peephole(trees) +array_t *trees; +{ + int i; + fanout_node_t *source; + + for (i = 0; i < array_n(trees); i++) { + source = array_fetch(fanout_node_t *, trees, i); + peephole_init_source(source); + alloc_peephole_rec(source); + } +} + +static void alloc_peephole_rec(source) +fanout_node_t *source; +{ + int i; + fanout_node_t *fanout_node; + + for (i = 0; i < array_n(source->children); i++) { + fanout_node = array_fetch(fanout_node_t *, source->children, i); + switch (fanout_node->type) { + case SINK_NODE: + peephole_init_sink(fanout_node); + break; + case BUFFER_NODE: + peephole_init_buffer(fanout_node); + alloc_peephole_rec(fanout_node); + break; + default: + fail("unexpected node type in alloc_peephole_rec"); + break; + } + } +} + +static void peephole_init_sink(node) +fanout_node_t *node; +{ + peep_entry_t entry; + + node->peephole = array_alloc(peep_entry_t, 1); + entry.required = node->link->required; + entry.arrival = PLUS_INFINITY; + entry.load = node->link->load; + entry.area = 0.0; + entry.buffer_index = -1; + entry.children_incr = array_alloc(int, 0); + array_insert(peep_entry_t, node->peephole, 0, entry); +} + +static void peephole_init_source(node) +fanout_node_t *node; +{ + peep_entry_t entry; + + node->peephole = array_alloc(peep_entry_t, 1); + entry.required = MINUS_INFINITY; + entry.load = 0.0; + entry.area = INFINITY; + entry.arrival = ZERO_DELAY; + entry.buffer_index = node->gate_index; + entry.children_incr = array_alloc(int, 0); + array_insert(peep_entry_t, node->peephole, 0, entry); +} + +static void peephole_init_buffer(node) +fanout_node_t *node; +{ + int i; + int from, to; + peep_entry_t entry; + + assert(is_buffer(n_gates, node->gate_index)); + if (is_inverter(n_gates, node->gate_index)) { + from = n_gates.n_pos_buffers; + to = n_gates.n_neg_buffers; + } else { + from = 0; + to = n_gates.n_pos_buffers; + } + node->peephole = array_alloc(peep_entry_t, to - from); + for (i = 0; i < to - from; i++) { + entry.buffer_index = i + from; + entry.load = fanout_delay_get_buffer_load(entry.buffer_index); + entry.required = MINUS_INFINITY; + entry.area = INFINITY; + entry.arrival = PLUS_INFINITY; + entry.children_incr = array_alloc(int, 0); + array_insert(peep_entry_t, node->peephole, i, entry); + } +} + +static void fanout_free_peephole(nodes) +array_t *nodes; +{ + int i, j; + fanout_node_t *node; + + for (i = 0; i < array_n(nodes); i++) { + node = array_fetch(fanout_node_t *, nodes, i); + for (j = 0; j < array_n(node->peephole); j++) { + peep_entry_t *entry = array_fetch_p(peep_entry_t, node->peephole, j); + array_free(entry->children_incr); + } + if (node->remove_opt) { + cleanup_remove_opt_node(node); + } + array_free(node->peephole); + } +} + + + /* COMPUTING ARRIVAL TIMES */ + +static void fanout_tree_compute_arrival_times(trees) +array_t *trees; +{ + int i; + double load; + fanout_node_t *source; + peep_entry_t *entry; + + for (i = 0; i < array_n(trees); i++) { + source = array_fetch(fanout_node_t *, trees, i); + entry = array_fetch_p(peep_entry_t, source->peephole, 0); + load = fanout_tree_get_node_load(source); + source->arrival = entry->arrival = ZERO_DELAY; + compute_arrival_times_rec(source, load); + } +} + +static void compute_arrival_times_rec(source, source_load) +fanout_node_t *source; +double source_load; +{ + int i, j; + double fanout_load; + delay_time_t fanout_arrival, local_arrival; + fanout_node_t *fanout_node; + peep_entry_t *entry; + + local_arrival = fanout_delay_forward_load_dependent(source->arrival, source->gate_index, source_load); + for (i = 0; i < array_n(source->children); i++) { + fanout_node = array_fetch(fanout_node_t *, source->children, i); + switch (fanout_node->type) { + case SINK_NODE: + entry = array_fetch_p(peep_entry_t, fanout_node->peephole, 0); + fanout_node->arrival = entry->arrival = local_arrival; + break; + case BUFFER_NODE: + for (j = 0; j < array_n(fanout_node->peephole); j++) { + entry = array_fetch_p(peep_entry_t, fanout_node->peephole, j); + fanout_load = source_load - fanout_delay_get_buffer_load(fanout_node->gate_index) + entry->load; + fanout_arrival = fanout_delay_forward_load_dependent(source->arrival, source->gate_index, fanout_load); + fanout_arrival = fanout_delay_forward_intrinsic(fanout_arrival, entry->buffer_index); + entry->arrival = fanout_arrival; + } + fanout_node->arrival = fanout_delay_forward_intrinsic(local_arrival, fanout_node->gate_index); + fanout_load = fanout_tree_get_node_load(fanout_node); + compute_arrival_times_rec(fanout_node, fanout_load); + break; + default: + fail("unexpected node type in alloc_peephole_rec"); + break; + } + } +} + +static double fanout_tree_get_node_load(node) +fanout_node_t *node; +{ + int i; + double load = 0.0; + fanout_node_t *fanout_node; + + if (node->type != SOURCE_NODE && node->type != BUFFER_NODE) + fail("unexpected node type in fanout_tree_get_node_load"); + + for (i = 0; i < array_n(node->children); i++) { + fanout_node = array_fetch(fanout_node_t *, node->children, i); + switch (fanout_node->type) { + case SINK_NODE: + load += fanout_node->link->load; + break; + case BUFFER_NODE: + load += fanout_delay_get_buffer_load(fanout_node->gate_index); + break; + default: + fail("unexpected node type in alloc_peephole_rec"); + break; + } + } + return load + map_compute_wire_load(array_n(node->children)); +} + + /* visit the tree from sinks to root */ + /* each time */ + +static void fanout_tree_remove_unnecessary_buffers(trees, cost) +array_t *trees; +fanout_cost_t *cost; +{ + int i; + fanout_node_t *source; + + for (i = 0; i < array_n(trees); i++) { + source = array_fetch(fanout_node_t *, trees, i); + source->polarity = fanout_delay_get_source_polarity(source->gate_index); + remove_unnecessary_buffers_rec(source); + remove_buffer_process_source(source); + } + cost->slack = PLUS_INFINITY; + cost->area = 0.0; + for (i = 0; i < array_n(trees); i++) { + source = array_fetch(fanout_node_t *, trees, i); + SETMIN(cost->slack, cost->slack, source->required); + cost->area += source->area; + } +} + +static void remove_unnecessary_buffers_rec(source) +fanout_node_t *source; +{ + int i; + fanout_node_t *fanout_node; + + for (i = 0; i < array_n(source->children); i++) { + fanout_node = array_fetch(fanout_node_t *, source->children, i); + switch (fanout_node->type) { + case SINK_NODE: + fanout_node->polarity = source->polarity; + remove_buffer_process_sink(fanout_node); + break; + case BUFFER_NODE: + fanout_node->polarity = (fanout_delay_get_buffer_polarity(fanout_node->gate_index) == POLAR_X) ? source->polarity : POLAR_INV(source->polarity); + remove_unnecessary_buffers_rec(fanout_node); + remove_buffer_process_buffer(fanout_node); + break; + default: + fail("unexpected node type in alloc_peephole_rec"); + break; + } + } +} + +typedef struct remove_opt_struct remove_opt_t; +struct remove_opt_struct { + delay_time_t required; /* aggregate for node & polarity; after intrinsic */ + double load; /* aggregate load, not including wire_load */ + st_table *links; /* list of nodes to be implemented */ +}; + +static void remove_buffer_process_sink(node) +fanout_node_t *node; +{ + int p; + remove_opt_t entry[2]; + + foreach_polarity(p) { + entry[p].load = 0.0; + entry[p].required = PLUS_INFINITY; + entry[p].links = st_init_table(st_ptrcmp, st_ptrhash); + } + p = node->polarity; + entry[p].required = node->link->required; + entry[p].load = node->link->load; + st_insert(entry[p].links, (char *) node, NIL(char)); + node->remove_opt = array_alloc(remove_opt_t, 2); + foreach_polarity(p) { + array_insert(remove_opt_t, node->remove_opt, p, entry[p]); + } + node->load = node->link->load; + node->required = node->link->required; + node->area = 0.0; +} + + /* remove_opt array is only used for flattening, not for merging */ + /* entring in this routine, we first check whether any child */ + /* does not have a remove_opt entry (in continue_flattening) */ + /* if all children have a remove_opt entry, we go ahead and try to flatten */ + /* if it succeeds, we remove the remove_opt array of the children */ + /* update the cost info of the node, and return with the node */ + /* annotated with a new remove_opt array */ + /* if we cannot flatten, we remove the remove_opt entries of the children */ + /* and try to merge the nodes greedily. If that succeeds, we recompute */ + /* the cost info associated with the node; otherwise we give up and return */ + /* If we cannot flatten, we do not allocate a remove_opt entry in any case */ + /* so there is no need to call cleanup_remove_opt_node */ + +static void remove_buffer_process_buffer(node) +fanout_node_t *node; +{ + int was_flattened; + compute_buffer_node_cost(node); + if (continue_flattening(node)) { + compute_flatten_info(node); + was_flattened = can_flatten_subtree(node); + cleanup_remove_opt_children_entries(node); + if (was_flattened) { + compute_buffer_node_cost(node); + return; + } + cleanup_remove_opt_node(node); + } + cleanup_remove_opt_children_entries(node); + if (can_merge_subtrees(node)) { + compute_buffer_node_cost(node); + } +} + + + /* a no answer means that one of subtree cannot be */ + /* optimized any more; in that case, give up optimizing */ + +static int continue_flattening(node) +fanout_node_t *node; +{ + int i; + fanout_node_t *child; + + for (i = 0; i < array_n(node->children); i++) { + child = array_fetch(fanout_node_t *, node->children, i); + if (child->remove_opt == NIL(array_t)) return 0; + } + return 1; +} + + /* gather on the node all the children of its children */ + /* those are not necessarily leaves */ + /* leaves (or sinks) are set up initially to be children of themselves */ + /* so there is no need for special case */ + +static void compute_flatten_info(node) +fanout_node_t *node; +{ + int i, p; + fanout_node_t *child; + remove_opt_t entry[2]; + remove_opt_t *child_entry; + char *key, *value; + st_generator *gen; + + foreach_polarity(p) { + entry[p].load = 0.0; + entry[p].required = PLUS_INFINITY; + entry[p].links = st_init_table(st_ptrcmp, st_ptrhash); + } + for (i = 0; i < array_n(node->children); i++) { + child = array_fetch(fanout_node_t *, node->children, i); + foreach_polarity(p) { + child_entry = array_fetch_p(remove_opt_t, child->remove_opt, p); + SETMIN(entry[p].required, entry[p].required, child_entry->required); + entry[p].load += child_entry->load; + st_foreach_item(child_entry->links, gen, &key, &value) { + st_insert(entry[p].links, key, value); + } + } + } + node->remove_opt = array_alloc(remove_opt_t, 2); + foreach_polarity(p) { + array_insert(remove_opt_t, node->remove_opt, p, entry[p]); + } +} + + /* check whether by flattening all nodes under "node" we can obtain a better cost */ + /* costs are compared on basis of area if meet delay constraint (node->arrival) */ + /* or on basis of delay otherwise.*/ + /* no_opt_cost is simply the cost at the node right now. */ + /* the best_new_cost is the cost obtained by collapsing all leaves onto "node" */ + /* if both polarities are present, one inverter is introduced and optimally sized */ + +static int can_flatten_subtree(node) +fanout_node_t *node; +{ + int best_gate_index; + delay_time_t slack; + fanout_cost_t cost, current_cost; + + if (already_flat_subtree(node)) return 1; + compute_no_opt_cost(node, ¤t_cost); + compute_best_new_cost(node, &cost, &best_gate_index); + if (fanout_opt_is_better_cost(¤t_cost, &cost)) return 0; + update_children_entries(node, best_gate_index); + SETSUB(slack, node->required, node->arrival); + assert(FP_EQUAL(node->area, cost.area)); + assert(IS_EQUAL(slack, cost.slack)); + return 1; +} + +static void compute_no_opt_cost(node, cost) +fanout_node_t *node; +fanout_cost_t *cost; +{ + SETSUB(cost->slack, node->required, node->arrival); + cost->area = node->area; +} + +static void compute_best_new_cost(node, cost, best_gate_index) +fanout_node_t *node; +fanout_cost_t *cost; +int *best_gate_index; +{ + int p, q; + remove_opt_t *entry[2]; + + foreach_polarity(p) { entry[p] = array_fetch_p(remove_opt_t, node->remove_opt, p); } + p = node->polarity; + q = POLAR_INV(p); + if (st_count(entry[q]->links) == 0) { + delay_time_t required; + double load = entry[p]->load; + load += map_compute_wire_load(st_count(entry[p]->links)); + required = fanout_delay_backward_load_dependent(entry[p]->required, node->gate_index, load); + SETSUB(cost->slack, required, node->arrival); + cost->area = fanout_delay_get_area(node->gate_index); + *best_gate_index = -1; + } else { + fanout_cost_t local_cost; + int gate_index; + double local_load; + delay_time_t local_required; + + cost->slack = MINUS_INFINITY; + cost->area = INFINITY; + foreach_inverter(n_gates, gate_index) { + local_load = entry[q]->load; + local_load += map_compute_wire_load(st_count(entry[q]->links)); + local_required = fanout_delay_backward_load_dependent(entry[q]->required, gate_index, local_load); + local_required = fanout_delay_backward_intrinsic(local_required, gate_index); + local_load = entry[p]->load + fanout_delay_get_buffer_load(gate_index); + local_load += map_compute_wire_load(st_count(entry[p]->links) + 1); + SETMIN(local_required, local_required, entry[p]->required); + local_required = fanout_delay_backward_load_dependent(local_required, node->gate_index, local_load); + SETSUB(local_cost.slack, local_required, node->arrival); + local_cost.area = fanout_delay_get_area(gate_index) + fanout_delay_get_area(node->gate_index); + if (fanout_opt_is_better_cost(&local_cost, cost)) { + *cost = local_cost; + *best_gate_index = gate_index; + } + } + } +} + +static void update_children_entries(node, best_gate_index) +fanout_node_t *node; +int best_gate_index; +{ + int p, q; + char *key, *value; + st_generator *gen; + remove_opt_t *entry[2]; + + foreach_polarity(p) { entry[p] = array_fetch_p(remove_opt_t, node->remove_opt, p); } + p = node->polarity; + q = POLAR_INV(p); + if (st_count(entry[q]->links) == 0) { + node->arity = st_count(entry[p]->links); + array_free(node->children); + node->children = array_alloc(fanout_node_t *, 0); + st_foreach_item(entry[p]->links, gen, &key, &value) { + array_insert_last(fanout_node_t *, node->children, (fanout_node_t *) key); + } + } else { + fanout_node_t *child = get_first_buffer_child(node); + assert (child != NIL(fanout_node_t)); + child->gate_index = best_gate_index; + child->arity = st_count(entry[q]->links); + child->polarity = q; + array_free(child->children); + child->children = array_alloc(fanout_node_t *, 0); + st_foreach_item(entry[q]->links, gen, &key, &value) { + array_insert_last(fanout_node_t *, child->children, (fanout_node_t *) key); + } + compute_buffer_node_cost(child); + node->arity = st_count(entry[p]->links) + 1; + array_free(node->children); + node->children = array_alloc(fanout_node_t *, 0); + array_insert_last(fanout_node_t *, node->children, child); + st_foreach_item(entry[p]->links, gen, &key, &value) { + array_insert_last(fanout_node_t *, node->children, (fanout_node_t *) key); + } + } + compute_buffer_node_cost(node); +} + +static fanout_node_t *get_first_buffer_child(node) +fanout_node_t *node; +{ + int i; + + for (i = 0; i < array_n(node->children); i++) { + fanout_node_t *local_child = array_fetch(fanout_node_t *, node->children, i); + if (local_child->type == BUFFER_NODE) return local_child; + } + return NIL(fanout_node_t); +} + +static int already_flat_subtree(node) +fanout_node_t *node; +{ + int i; + int n_buffer_children; + fanout_node_t *child; + fanout_node_t *last_buffer_child; + + n_buffer_children = 0; + last_buffer_child = NIL(fanout_node_t); + for (i = 0; i < array_n(node->children); i++) { + child = array_fetch(fanout_node_t *, node->children, i); + if (child->type == BUFFER_NODE) { + n_buffer_children++; + last_buffer_child = child; + } + } + if (n_buffer_children == 0) return 1; + if (n_buffer_children > 1) return 0; + node = last_buffer_child; + if (! is_inverter(n_gates, node->gate_index)) return 0; + n_buffer_children = 0; + for (i = 0; i < array_n(node->children); i++) { + child = array_fetch(fanout_node_t *, node->children, i); + if (child->type == BUFFER_NODE) + n_buffer_children++; + } + return (n_buffer_children == 0); +} + + + /* remove the "remove_opt_t" arrays from the children */ + /* so that there is no need for deallocating later on */ + /* actually: does not really work: if it is flattened */ + /* some nodes may become inaccessible: should be checked */ + /* and deallocated at the end */ + +static void cleanup_remove_opt_children_entries(node) +fanout_node_t *node; +{ + int i; + fanout_node_t *child; + + for (i = 0; i < array_n(node->children); i++) { + child = array_fetch(fanout_node_t *, node->children, i); + if (child->remove_opt != NIL(array_t)) + cleanup_remove_opt_node(child); + } +} + +static void cleanup_remove_opt_node(node) +fanout_node_t *node; +{ + int p; + + foreach_polarity(p) { + remove_opt_t *entry = array_fetch_p(remove_opt_t, node->remove_opt, p); + st_free_table(entry->links); + } + array_free(node->remove_opt); + node->remove_opt = NIL(array_t); +} + +static void remove_buffer_process_source(node) +fanout_node_t *node; +{ + remove_buffer_process_buffer(node); + if (node->remove_opt) + cleanup_remove_opt_node(node); +} + + /* updates area and required time entries */ + +static void compute_buffer_node_cost(node) +fanout_node_t *node; +{ + int i; + double area = 0.0; + double load = 0.0; + delay_time_t required, local_required; + fanout_node_t *child; + + required = PLUS_INFINITY; + for (i = 0; i < array_n(node->children); i++) { + child = array_fetch(fanout_node_t *, node->children, i); + area += child->area; + load += child->load; + local_required = child->required; + if (child->type == BUFFER_NODE) + local_required = fanout_delay_backward_intrinsic(local_required, child->gate_index); + SETMIN(required, required, local_required); + } + load += map_compute_wire_load(array_n(node->children)); + node->required = fanout_delay_backward_load_dependent(required, node->gate_index, load); + node->area = area + fanout_delay_get_area(node->gate_index); + node->load = (is_buffer(n_gates, node->gate_index)) ? fanout_delay_get_buffer_load(node->gate_index) : 0.0; +} + +typedef struct merge_struct merge_t; +struct merge_struct { + fanout_node_t *node; + int ignored; + int sink; +}; + +static int can_merge_subtrees(node) +fanout_node_t *node; +{ + int i; + int current_index, merge_index; + delay_time_t arrival; + fanout_node_t *child; + merge_t *current_node, *merge_node; + merge_t merge_entry; + array_t *node_array = array_alloc(merge_t, 0); + int modified = 0; + + for (i = 0; i < array_n(node->children); i++) { + child = array_fetch(fanout_node_t *, node->children, i); + merge_entry.node = child; + if (child->type == SINK_NODE) { + merge_entry.ignored = 1; + merge_entry.sink = 1; + } else { + merge_entry.ignored = 0; + merge_entry.sink = 0; + } + array_insert_last(merge_t, node_array, merge_entry); + } + arrival = recompute_arrival_time(node, node_array); + for (current_index = 0; current_index < array_n(node_array); current_index++) { + current_node = array_fetch_p(merge_t, node_array, current_index); + if (current_node->ignored) continue; + for (merge_index = current_index + 1; merge_index < array_n(node_array); merge_index++) { + merge_node = array_fetch_p(merge_t, node_array, merge_index); + if (merge_node->ignored) continue; + if (can_merge_node(current_node->node, merge_node->node, arrival)) { + merge_nodes(current_node->node, merge_node->node); + merge_node->ignored = 1; + arrival = recompute_arrival_time(node, node_array); + modified = 1; + } + } + } + adjust_node_children(node, node_array); + array_free(node_array); + return modified; +} + +static delay_time_t recompute_arrival_time(node, node_array) +fanout_node_t *node; +array_t *node_array; +{ + int i; + merge_t *merge_node; + double load = 0.0; + int n_nodes = 0; + + for (i = 0; i < array_n(node_array); i++) { + merge_node = array_fetch_p(merge_t, node_array, i); + if (merge_node->ignored && ! merge_node->sink) continue; + load += merge_node->node->load; + n_nodes++; + } + load += map_compute_wire_load(n_nodes); + return fanout_delay_forward_load_dependent(node->arrival, node->gate_index, load); +} + +static int can_merge_node(current_node, merge_node, arrival) +fanout_node_t *current_node; +fanout_node_t *merge_node; +delay_time_t arrival; +{ + double load; + delay_time_t required, slack; + int n_elts; + + if (current_node->polarity != merge_node->polarity) return 0; + arrival = fanout_delay_forward_intrinsic(arrival, current_node->gate_index); + load = 0.0; + required = PLUS_INFINITY; + add_children_cost(current_node->children, &required, &load); + add_children_cost(merge_node->children, &required, &load); + n_elts = array_n(current_node->children) + array_n(merge_node->children); + load += map_compute_wire_load(n_elts); + required = fanout_delay_backward_load_dependent(required, current_node->gate_index, load); + SETSUB(slack, required, arrival); + return (GETMIN(slack) >= 0.0); +} + +static void add_children_cost(array, required, load) +array_t *array; +delay_time_t *required; +double *load; +{ + double result_load; + delay_time_t result_required, local_required; + int i; + fanout_node_t *child; + + result_load = *load; + result_required = *required; + for (i = 0; i < array_n(array); i++) { + child = array_fetch(fanout_node_t *, array, i); + result_load += child->load; + local_required = child->required; + if (child->type == BUFFER_NODE) + local_required = fanout_delay_backward_intrinsic(local_required, child->gate_index); + SETMIN(result_required, result_required, local_required); + } + *load = result_load; + *required = result_required; +} + +static void merge_nodes(current_node, merge_node) +fanout_node_t *current_node; +fanout_node_t *merge_node; +{ + int i; + fanout_node_t *child; + array_t *current_children = current_node->children; + array_t *merge_children = merge_node->children; + array_t *new_children = array_alloc(fanout_node_t *, 0); + + for (i = 0; i < array_n(current_children); i++) { + child = array_fetch(fanout_node_t *, current_children, i); + assert(child->remove_opt == NIL(array_t)); + array_insert_last(fanout_node_t *, new_children, child); + } + for (i = 0; i < array_n(merge_children); i++) { + child = array_fetch(fanout_node_t *, merge_children, i); + assert(child->remove_opt == NIL(array_t)); + array_insert_last(fanout_node_t *, new_children, child); + } + array_free(current_children); + current_node->children = new_children; + current_node->arity = array_n(new_children); + compute_buffer_node_cost(current_node); +} + +static void adjust_node_children(node, child_array) +fanout_node_t *node; +array_t *child_array; +{ + int i; + merge_t *child_entry; + + array_t *new_children = array_alloc(fanout_node_t *, 0); + + for (i = 0; i < array_n(child_array); i++) { + child_entry = array_fetch_p(merge_t, child_array, i); + if (child_entry->ignored && ! child_entry->sink) continue; + array_insert_last(fanout_node_t *, new_children, child_entry->node); + } + array_free(node->children); + node->children = new_children; + assert(array_n(new_children) <= node->arity); + node->arity = array_n(new_children); +} + + + + /* INTERFACE to fanout_est.c */ + + +#include "bin_int.h" + + + /* the arrival time at a node includes the intrinsic delay but not the load dependent delay */ + /* the arrival time at a sink is the arrival time at pin input (no intrinsic) */ + +void fanout_tree_extract_fanout_leaves(fanout, array) +multi_fanout_t *fanout; +array_t *array; +{ + int i; + array_t *trees; + fanout_node_t *source; + double source_load; + int source_polarity; + + trees = fanout_tree_get_roots(array); + for (i = 0; i < array_n(trees); i++) { + source = array_fetch(fanout_node_t *, trees, i); + source_load = fanout_tree_get_node_load(source); + source_polarity = fanout_delay_get_source_polarity(source->gate_index); + source->arrival = ZERO_DELAY; + extract_fanout_leaves_rec(fanout, source, source_load, source_polarity); + } + array_free(trees); +} + +static void extract_fanout_leaves_rec(fanout, source, source_load, source_polarity) +multi_fanout_t *fanout; +fanout_node_t *source; +double source_load; +int source_polarity; +{ + int i; + gate_link_t *link; + int gate_polarity; + int fanout_polarity; + int fanout_index; + double fanout_load; + fanout_bucket_t *bucket; + fanout_node_t *fanout_node; + delay_time_t local_arrival; + + local_arrival = fanout_delay_forward_load_dependent(source->arrival, source->gate_index, source_load); + for (i = 0; i < array_n(source->children); i++) { + fanout_node = array_fetch(fanout_node_t *, source->children, i); + switch (fanout_node->type) { + case SINK_NODE: + link = fanout_node->link; + fanout_index = link->pin; /* overloaded: when tree saved, link->pin becomes fanout_index */ + bucket = fanout_est_fanout_bucket_alloc(fanout); + bucket->load = source_load; + bucket->pwl = fanout_delay_get_delay_pwl(source->gate_index, source_load, source->arrival); + fanout->leaves[source_polarity][fanout_index].bucket = bucket; + fanout->leaves[source_polarity][fanout_index].load = link->load; + fanout_node->arrival = local_arrival; + break; + case BUFFER_NODE: + fanout_node->arrival = fanout_delay_forward_intrinsic(local_arrival, fanout_node->gate_index); + fanout_load = fanout_tree_get_node_load(fanout_node); + gate_polarity = fanout_delay_get_buffer_polarity(fanout_node->gate_index); + fanout_polarity = (gate_polarity == POLAR_X) ? source_polarity : POLAR_INV(source_polarity); + extract_fanout_leaves_rec(fanout, fanout_node, fanout_load, fanout_polarity); + break; + default: + fail("unexpected node type in extract_fanout_leaves_rec"); + break; + } + } +} + + + /* suppose the tree has edges already */ + +double fanout_tree_get_source_load(array) +array_t *array; +{ + array_t *trees; + fanout_node_t *source; + double source_load; + + trees = fanout_tree_get_roots(array); + assert(array_n(trees) == 1); + source = array_fetch(fanout_node_t *, trees, 0); + source_load = fanout_tree_get_node_load(source); + array_free(trees); + return source_load; +} + +array_t *fanout_tree_get_root_node(array) +array_t *array; +{ + return (fanout_tree_get_roots(array)); +} diff --git a/sis/map/fanout_tree_static.h b/sis/map/fanout_tree_static.h new file mode 100644 index 0000000..d0ee1f4 --- /dev/null +++ b/sis/map/fanout_tree_static.h @@ -0,0 +1,66 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_tree_static.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)fanout_tree_static.h 1.2 */ +/* last modified on 5/1/91 at 15:50:58 */ +static array_t *fanout_tree_get_roots(); +static array_t *get_forest_in_bottom_up_order(); +static delay_time_t check_required_rec(); +static delay_time_t recompute_arrival_time(); +static double fanout_tree_get_node_load(); +static fanout_node_t *get_first_buffer_child(); +static int add_edges_rec(); +static int already_flat_subtree(); +static int can_flatten_subtree(); +static int can_merge_node(); +static int can_merge_subtrees(); +static int continue_flattening(); +static int incr_critical_child(); +static int peephole_is_better(); +static int peephole_optimize(); +static node_t *create_buffer(); +static void add_children_cost(); +static void adjust_node_children(); +static void alloc_peephole_rec(); +static void build_peephole_tree_rec(); +static void build_peephole_trees(); +static void check_area(); +static void check_polarities(); +static void check_polarity_rec(); +static void check_required(); +static void cleanup_remove_opt_children_entries(); +static void cleanup_remove_opt_node(); +static void compute_arrival_times_rec(); +static void compute_best_new_cost(); +static void compute_buffer_node_cost(); +static void compute_current_cost(); +static void compute_flatten_info(); +static void compute_no_opt_cost(); +static void do_build_tree(); +static void do_build_tree_rec(); +static void extract_fanout_leaves_rec(); +static void fanout_free_peephole(); +static void fanout_tree_alloc_peephole(); +static void fanout_tree_compute_arrival_times(); +static void fanout_tree_remove_unnecessary_buffers(); +static void free_unused_sources(); +static void get_forest_in_bottom_up_order_rec(); +static void merge_nodes(); +static void peephole_init_buffer(); +static void peephole_init_sink(); +static void peephole_init_source(); +static void peephole_optimize_node(); +static void print_tabs(); +static void print_tree_rec(); +static void remove_buffer_process_buffer(); +static void remove_buffer_process_sink(); +static void remove_buffer_process_source(); +static void remove_unnecessary_buffers_rec(); +static void select_best_log_entry(); +static void update_children_entries(); diff --git a/sis/map/fanout_util.c b/sis/map/fanout_util.c new file mode 100644 index 0000000..281909d --- /dev/null +++ b/sis/map/fanout_util.c @@ -0,0 +1,175 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/fanout_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)fanout_util.c 1.2 */ +/* last modified on 5/1/91 at 15:51:01 */ +#include "sis.h" +#include "fanout_int.h" +#include "fanout_delay.h" + +static void compute_merge_cost(); +static void get_best_one_source(); +static void select_best_source(); + + +static n_gates_t n_gates; + + + /* SOME USEFUL CONSTANTS */ + +delay_time_t MINUS_INFINITY = {-INFINITY, -INFINITY}; +delay_time_t PLUS_INFINITY = { INFINITY, INFINITY}; +delay_time_t ZERO_DELAY = { 0.0, 0.0}; + +single_source_t SINGLE_SOURCE_INIT_VALUE = {{-INFINITY, -INFINITY}, 0.0, 0, 0.0}; + + /* UTILITIES */ + +int find_minimum_index(array, n) +delay_time_t *array; +int n; +{ + int i; + int result; + delay_time_t best_so_far; + + best_so_far = MINUS_INFINITY; + for (i = 0; i < n; i++) { + if (GETMIN(best_so_far) < GETMIN(array[i])) { + best_so_far = array[i]; + result = i; + } + } + return result; +} + + +void generic_fanout_optimizer(fanout_info, tree, cost, optimize_one_source, extract_merge_info, build_tree) +opt_array_t *fanout_info; /* fanout_info[POLAR_X] lists the positive polarity sinks; POLAR_Y negative */ +array_t *tree; /* array in which the result tree is stored: format of fanout_tree.c */ +fanout_cost_t *cost; /* contains information on the result: required times, area */ +MultidimFn optimize_one_source; /* multidim_t *(opt_array_t *fanout_info) */ +VoidFn extract_merge_info; /* (opt_array_t *fanout_info, multidim_t *table, multidim_t *merge_table) */ +VoidFn build_tree; /* (opt_array_t *fanout_info, array_t *tree, selected_source_t *source, multidim_t *table) */ +{ + multidim_t *table; + multidim_t *merge_table; + selected_source_t source; + int indices[3]; + + n_gates = fanout_delay_get_n_gates(); + table = (*optimize_one_source)(fanout_info); + indices[0] = n_gates.n_gates; + indices[1] = POLAR_MAX; + indices[2] = POLAR_MAX; + merge_table = multidim_alloc(single_source_t, 3, indices); + multidim_init(single_source_t, merge_table, SINGLE_SOURCE_INIT_VALUE); + (*extract_merge_info)(fanout_info, table, merge_table); + select_best_source(merge_table, &source, cost); + (*build_tree)(fanout_info, tree, &source, table); + multidim_free(merge_table); + multidim_free(table); +} + + + /* INTERNAL INTERFACE */ + + /* FORMAT OF THE MERGE_TABLE */ + /* (n_gates.n_gates * POLAR_MAX * POLAR_MAX) -> (source_index, source_polarity, sink_polarity) */ + /* 2 cases: */ + /* (1) source_index is a source: in that case, source_polarity = polarity of the source */ + /* and required time and load returned by the entry correspond to the data at the output of the source */ + /* (2) source_index is a buffer: in that case, source_polarity is arbitrary */ + /* and required time and load returned correspond to the data at input of the buffer */ + /* this allows for an easy merge of different solutions */ + + /* FORMAT OF SOURCE */ + /* first entry: real source (not a buffer) */ + /* second entry: polarity of sinks directly connected to that source */ + /* third entry: a buffer (or inverter) that feeds the sinks of opposite polarity */ + + /* FORMAT OF COST */ + /* slack at the source and total area of solution */ + +static void select_best_source(merge_table, best_source, best_cost) +multidim_t *merge_table; +selected_source_t *best_source; +fanout_cost_t *best_cost; +{ + int source_index; + selected_source_t source; + fanout_cost_t cost; + n_gates = fanout_delay_get_n_gates(); + + best_cost->slack = MINUS_INFINITY; + best_cost->area = INFINITY; + foreach_source(n_gates, source_index) { + get_best_one_source(merge_table, source_index, &source, &cost); + if (GETMIN(best_cost->slack) < GETMIN(cost.slack)) { + *best_cost = cost; + *best_source = source; + } + } + assert(GETMIN(best_cost->slack) > - INFINITY); +} + +static void get_best_one_source(merge_table, source_index, best_source, best_cost) +multidim_t *merge_table; +int source_index; +selected_source_t *best_source; +fanout_cost_t *best_cost; +{ + int sink_polarity; + int source_polarity, buffer_polarity; + int buffer_index; + selected_source_t source; + fanout_cost_t cost; + single_source_t *source_entry, *buffer_entry; + + best_cost->slack = MINUS_INFINITY; + best_cost->area = INFINITY; + source.main_source = source_index; + source_polarity = fanout_delay_get_source_polarity(source_index); + foreach_polarity (sink_polarity) { + source.main_source_sink_polarity = sink_polarity; + source_entry = INDEX3P(single_source_t, merge_table, source_index, source_polarity, sink_polarity); + foreach_gate(n_gates, buffer_index) { + if (is_source(n_gates, buffer_index)) { + if (buffer_index != source_index) continue; + buffer_polarity = source_polarity; + } else { + buffer_polarity = (is_inverter(n_gates, buffer_index)) ? POLAR_INV(source_polarity) : source_polarity; + } + source.buffer = buffer_index; + buffer_entry = INDEX3P(single_source_t, merge_table, buffer_index, buffer_polarity, POLAR_INV(sink_polarity)); + compute_merge_cost(source_index, source_entry, buffer_entry, &cost); + if (GETMIN(best_cost->slack) < GETMIN(cost.slack)) { + *best_cost = cost; + *best_source = source; + } + } + } +} + + +static void compute_merge_cost(source_index, entry_x, entry_y, cost) +int source_index; +single_source_t *entry_x; +single_source_t *entry_y; +fanout_cost_t *cost; +{ + double load; + delay_time_t required; + + SETMIN(required, entry_x->required, entry_y->required); + load = entry_x->load + entry_y->load; + load += map_compute_wire_load(entry_x->n_fanouts + entry_y->n_fanouts); + cost->slack = fanout_delay_backward_load_dependent(required, source_index, load); + cost->area = entry_x->area + entry_y->area; +} diff --git a/sis/map/gate_link.c b/sis/map/gate_link.c new file mode 100644 index 0000000..61e7fb9 --- /dev/null +++ b/sis/map/gate_link.c @@ -0,0 +1,322 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/gate_link.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:24 $ + * + */ +/* file @(#)gate_link.c 1.5 */ +/* last modified on 6/27/91 at 15:12:57 */ +/** +** MODIFICATION HISTORY: +** +** 01 10-June-91 klk Changed the function fanout_print_node to global so that it can be called from outside +** for debugging purposes. +**/ +#include "sis.h" +#include <math.h> +#include "map_int.h" +#include "map_delay.h" +#include "map_macros.h" +#include "gate_link.h" + +static int gate_link_key_cmp(); +static int gate_link_key_hash(); + + /* implements basic routines to manipulate "gate_links" */ + /* that is, backward pointers from pins to roots of gates */ + +typedef struct gate_link_key_struct gate_link_key_t; +struct gate_link_key_struct { + node_t *node; /* root of the gate */ + int pin; /* pin number */ +}; + +typedef struct gate_link_value_struct gate_link_value_t; +struct gate_link_value_struct { + double load; /* load on this pin */ + double slack; /* used by bin_delay.c. Might disappear at some point */ + delay_time_t required; /* slack for this signal at this input pin */ +}; + +static delay_time_t PLUS_INFINITY = {INFINITY, INFINITY}; + + /* EXTERNAL INTERFACE */ + + /* allocates gate_link (hash table) */ + +void gate_link_init(node) +node_t *node; +{ + assert(MAP(node)->gate_link == NIL(st_table)); + MAP(node)->gate_link = st_init_table(gate_link_key_cmp, gate_link_key_hash); + MAP(node)->gen = NIL(st_generator); +} + + + /* sums the loads on the pins; takes wire capacitances into account */ + +double gate_link_compute_load(node) +node_t *node; +{ + double load = 0.0; + char *key, *value; + st_generator *gen; + register st_table *table = MAP(node)->gate_link; + int n_fanouts = 0; + + st_foreach_item(table, gen, &key, &value) { + load += ((gate_link_value_t *) value)->load; + n_fanouts++; + } + return load + map_compute_wire_load(n_fanouts); +} + +delay_time_t gate_link_compute_min_required(node) +node_t *node; +{ + delay_time_t required; + gate_link_key_t *key; + gate_link_value_t *value; + st_generator *gen; + register st_table *table = MAP(node)->gate_link; + + required = PLUS_INFINITY; + st_foreach_item(table, gen, (char **) &key, (char **) &value) { + SETMIN(required, required, value->required); + } + return required; +} + + +int gate_link_n_elts(node) +node_t *node; +{ + register st_table *table = MAP(node)->gate_link; + return st_count(table); +} + +int gate_link_is_empty(node) +node_t *node; +{ + return (gate_link_n_elts(node) == 0); +} + + + /* return 0 if empty */ + /* starts an iterator */ + /* gate_link_first(n, l); do {...} while (gate_link_next(n, l)); */ + /* supposes that storage has been allocated for *link */ + +int gate_link_first(node, link) +node_t *node; +gate_link_t *link; +{ + register st_table *table = MAP(node)->gate_link; + MAP(node)->gen = st_init_gen(table); + return gate_link_next(node, link); +} + +int gate_link_next(node, link) + node_t *node; + gate_link_t *link; +{ + char *key, *value; + st_generator *gen = MAP(node)->gen; + + if (gen == NIL(st_generator)) return 0; + if (st_gen(gen, &key, &value) == 0) { + st_free_gen(gen); + MAP(node)->gen = NIL(st_generator); + return 0; + } + link->node = ((gate_link_key_t *) key)->node; + link->pin = ((gate_link_key_t *) key)->pin; + link->load = ((gate_link_value_t *) value)->load; + link->slack = ((gate_link_value_t *) value)->slack; + link->required = ((gate_link_value_t *) value)->required; + return 1; +} + + + /* insert the link into the gate_link table of node */ + +void gate_link_put(node, link) +node_t *node; +gate_link_t *link; +{ + gate_link_key_t key; + gate_link_value_t *value; + register st_table *table = MAP(node)->gate_link; + + key.node = link->node; + key.pin = link->pin; + if (st_lookup(table, (char *) &key, (char **) &value)) { + value->load = link->load; + value->slack = link->slack; + value->required = link->required; + } else { + gate_link_key_t *new_key = ALLOC(gate_link_key_t, 1); + gate_link_value_t *new_value = ALLOC(gate_link_value_t, 1); + new_key->node = link->node; + new_key->pin = link->pin; + new_value->load = link->load; + new_value->slack = link->slack; + new_value->required = link->required; + st_insert(table, (char *) new_key, (char *) new_value); + } +} + + + /* link=(key,value); using the key part, fill up the value part */ + /* with what is recorded in the gate_link */ + /* returns 0 if no match */ + +int gate_link_get(node, link) +node_t *node; +gate_link_t *link; +{ + gate_link_key_t key; + char *value; + register st_table *table = MAP(node)->gate_link; + + key.node = link->node; + key.pin = link->pin; + if (st_lookup(table, (char *) &key, &value)) { + link->load = ((gate_link_value_t *) value)->load; + link->slack = ((gate_link_value_t *) value)->slack; + link->required = ((gate_link_value_t *) value)->required; + return 1; + } else { + return 0; + } +} + + + /* link=(key,value); remove gate_link entry associated with key if any */ + +void gate_link_remove(node, link) +node_t *node; +gate_link_t *link; +{ + gate_link_key_t key; + char *key_ptr; + char *value_ptr; + register st_table *table = MAP(node)->gate_link; + + key.node = link->node; + key.pin = link->pin; + key_ptr = (char *) &key; + if (st_delete(table, &key_ptr, &value_ptr)) { + FREE(key_ptr); + FREE(value_ptr); + } +} + + + /* free the gate_link table and allocate a new one with no data in it */ + +void gate_link_delete_all(node) +node_t *node; +{ + gate_link_free(node); + gate_link_init(node); +} + + + /* free the gate_link and all storage associated with it */ + +void gate_link_free(node) +node_t *node; +{ + char *key, *value; + st_generator *gen; + register st_table *table = MAP(node)->gate_link; + st_foreach_item(table, gen, &key, &value) { + FREE(key); FREE(value); + } + st_free_table(table); + MAP(node)->gate_link = NIL(st_table); +} + + + /* INTERNAL INTERFACE */ + +static int gate_link_key_cmp(key1, key2) + char *key1, *key2; +{ + register int i1, i2; + register gate_link_key_t *k1 = (gate_link_key_t *) key1; + register gate_link_key_t *k2 = (gate_link_key_t *) key2; + + i1 = (int) k1->node; i2 = (int) k2->node; + if (i1 - i2) return i1 - i2; + i1 = k1->pin; i2 = k2->pin; + return i1 - i2; +} + +static int gate_link_key_hash(key, modulus) + char *key; + int modulus; +{ + register gate_link_key_t *k = (gate_link_key_t *) key; + register unsigned int hash = (unsigned int) k->node; + hash += k->pin; + return hash % modulus; +} + + + /* for debugging */ + +#include "map_int.h" +void fanout_print_node(node) +node_t *node; +{ + if (node == NIL(node_t)) return; + fprintf(sisout, "node: %s(0x%x)\n", node->name, node); + fprintf(sisout, "l(%2.2f) ", MAP(node)->load); + fprintf(sisout, "a(%2.2f,%2.2f) ", MAP(node)->map_arrival.rise, MAP(node)->map_arrival.fall); + fprintf(sisout, "r(%2.2f,%2.2f)\n", MAP(node)->required.rise, MAP(node)->required.fall); + if (node->type == PRIMARY_INPUT) { + fprintf(sisout, "PI\n"); + } else if (node->type == PRIMARY_OUTPUT) { + fprintf(sisout, "PO\n"); + } else if (MAP(node)->gate == NIL(lib_gate_t)) { + fprintf(sisout, "no gate\n"); + } else { + int i; + fprintf(sisout, "gate(%s) ", MAP(node)->gate->name); + for (i = 0; i < MAP(node)->ninputs; i++) + fprintf(sisout, "%s(0x%x) ", MAP(node)->save_binding[i]->name, MAP(node)->save_binding[i]); + fprintf(sisout, "\n"); + } + if (MAP(node)->gate_link == NIL(st_table)) { + fprintf(sisout, "no gate link\n"); + } else if (gate_link_is_empty(node)) { + fprintf(sisout, "empty gate link\n"); + } else { + gate_link_t link; + gate_link_first(node, &link); + do { + fprintf(sisout, "--> node: %s(0x%x) ", (link.node)->name, link.node); + fprintf(sisout, "pin: %d ", link.pin); + fprintf(sisout, "l(%2.2f) ", link.load); + fprintf(sisout, "r(%2.2f,%2.2f)\n", link.required.rise, link.required.fall); + } while (gate_link_next(node, &link)); + } +} + + /* for debugging */ + +void fanout_print_network(network) +network_t *network; +{ + lsGen gen; + node_t *node; + + foreach_node(network, gen, node) { + fanout_print_node(node); + } +} diff --git a/sis/map/gate_link.h b/sis/map/gate_link.h new file mode 100644 index 0000000..8819741 --- /dev/null +++ b/sis/map/gate_link.h @@ -0,0 +1,38 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/gate_link.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)gate_link.h 1.3 */ +/* last modified on 6/27/91 at 15:13:33 */ +#ifndef GATE_LINK_H +#define GATE_LINK_H + +typedef struct gate_link_struct gate_link_t; +struct gate_link_struct { + node_t *node; /* root of the gate */ + int pin; /* pin number */ + double load; /* load on this pin */ + double slack; /* used by bin_delay.c for approx. slack computations; should disappear */ + delay_time_t required; /* required time for this signal at this input pin */ +}; + +extern void gate_link_init(/* node_t *node */); +extern double gate_link_compute_load(/* node_t *node */); +extern delay_time_t gate_link_compute_min_required(/* node_t *node */); +extern int gate_link_n_elts(/* node_t *node */); +extern int gate_link_is_empty(/* node_t *node */); +extern int gate_link_first(/* node_t *node, gate_link_t *link */); +extern int gate_link_next(/* node_t *node, gate_link_t *link */); +extern void gate_link_put(/* node_t *node, gate_link_t *link */); +extern int gate_link_get(/* node_t *node, gate_link_t *link */); +extern void gate_link_remove(/* node_t *node, gate_link_t *link */); +extern void gate_link_delete_all(/* node_t *node */); +extern void gate_link_free(/* node_t *node */); +extern void fanout_print_node(/* node_t *node */); + +#endif diff --git a/sis/map/hackit.c b/sis/map/hackit.c new file mode 100644 index 0000000..34a39f8 --- /dev/null +++ b/sis/map/hackit.c @@ -0,0 +1,141 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/hackit.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)hackit.c 1.2 */ +/* last modified on 5/1/91 at 15:51:06 */ +#include "sis.h" +#include "map_int.h" +#include "lib_int.h" + +static lib_gate_t * +choose_largest_gate(library, string) +library_t *library; +char *string; +{ + network_t *network; + lib_class_t *class; + lib_gate_t *gate, *best_gate; + lsGen gen; + double best_area; + + network = read_eqn_string(string); + if (network == 0) return 0; + class = lib_get_class(network, library); + if (class == 0) return 0; + + best_area = -1; + best_gate = 0; + gen = lib_gen_gates(class); + while (lsNext(gen, (char **) &gate, LS_NH) == LS_OK) { + if (lib_gate_area(gate) > best_area) { + best_area = lib_gate_area(gate); + best_gate = gate; + } + } + LS_ASSERT(lsFinish(gen)); + network_free(network); + return best_gate; +} + + +static node_t * +create_inverter(nodelist, fanin, inv_gate) +lsList nodelist; +node_t *fanin; +lib_gate_t *inv_gate; +{ + node_t *inv; + char *formals[1]; + node_t *actuals[1]; + + inv = node_alloc(); + actuals[0] = fanin; + formals[0] = lib_gate_pin_name(inv_gate, 0, 1); + assert(lib_set_gate(inv, inv_gate, formals, actuals, 1)); + LS_ASSERT(lsNewEnd(nodelist, (char *) inv, LS_NH)); + return inv; +} + + +static void +add_inverters(nodelist, node, inv_gate) +lsList nodelist; +node_t *node; +lib_gate_t *inv_gate; +{ + int new_inv; + node_t *inv1, *inv, *fanout; + lsGen gen; + + /* Find if the node already has an inverter at the output */ + inv = NIL(node_t); + foreach_fanout(node, gen, fanout) { + if (node_function(fanout) == NODE_INV) { + if (inv != NIL(node_t)) { + /* + (void) fprintf(stderr, + "Warning: node %s has fanout to >1 inverter\n", + node_name(node)); + */ + } else { + inv = fanout; + } + } + } + + /* Create an inverter if none found so far */ + new_inv = 0; + if (inv == NIL(node_t)) { + inv = create_inverter(nodelist, node, inv_gate); + new_inv = 1; + } + + /* Handle the positive-phase fanouts (i.e., fanouts of 'node') */ + inv1 = create_inverter(nodelist, inv, inv_gate); + foreach_fanout(node, gen, fanout) { + if (node_function(fanout) != NODE_INV) { + assert(node_patch_fanin(fanout, node, inv1)); + } + } + + /* Handle the positive-phase fanouts (i.e., fanouts of 'node') */ + if (! new_inv) { + inv1 = create_inverter(nodelist, inv1, inv_gate); + foreach_fanout(inv, gen, fanout) { + if (node_function(fanout) != NODE_INV) { + assert(node_patch_fanin(fanout, inv, inv1)); + } + } + } +} + + + +buffer_inputs(network, library) +network_t *network; +library_t *library; +{ + lib_gate_t *inv_gate; + lsList nodelist; + lsGen gen; + node_t *pi, *node; + + inv_gate = choose_largest_gate(library, "f = !a;"); + + nodelist = lsCreate(); + foreach_primary_input(network, gen, pi) { + add_inverters(nodelist, pi, inv_gate); + } + lsForeachItem(nodelist, gen, node) { + network_add_node(network, node); + } + LS_ASSERT(lsDestroy(nodelist, (void (*)()) 0)); + + (void) network_cleanup(network); +} diff --git a/sis/map/lib_int.h b/sis/map/lib_int.h new file mode 100644 index 0000000..2914bd5 --- /dev/null +++ b/sis/map/lib_int.h @@ -0,0 +1,38 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/lib_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)lib_int.h 1.4 */ +/* last modified on 7/2/91 at 19:44:31 */ +/* + * $Log: lib_int.h,v $ + * Revision 1.1.1.1 2004/02/07 10:14:25 pchong + * imported + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 21:58:28 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:40:43 sis + * Initial revision + * + */ + +extern library_t *lib_current_library; + +extern int lib_pattern_matches(); +extern int lib_read_blif(); +extern void lib_free(); +extern void lib_dump(); +extern void lib_dump_class(); +extern double lib_gate_area(); +extern lib_gate_t *lib_get_default_inverter(); +extern array_t *lib_get_prims_from_class(/* lib_class_t *class */); +extern void lib_dump_gate(); diff --git a/sis/map/library.c b/sis/map/library.c new file mode 100644 index 0000000..e2479a7 --- /dev/null +++ b/sis/map/library.c @@ -0,0 +1,995 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/library.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)library.c 1.14 */ +/* last modified on 9/17/91 at 14:30:10 */ +/* + * 01 10-Jun-90 klk Changed the procedure choose_nth_smallest_gate from static to global + */ +/* + * $Log: library.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:25 pchong + * imported + * + * Revision 1.8 1993/06/02 20:33:53 sis + * Changed functions like strsav to util_strsav to improve machine indepedence. + * + * Revision 1.8 1993/06/02 20:33:53 sis + * Changed functions like strsav to util_strsav to improve machine indepedence. + * + * Revision 1.7 1993/01/05 21:50:58 sis + * Core leak fix. + * + * Revision 1.6 1992/12/11 01:37:05 sis + * network_delete_latch now frees the latch data structure, so + * there is no need to free it here. + * + * Revision 1.5 1992/06/05 16:24:15 sis + * bug fix in find_or_create_pattern + * (this fixed a bug where read_blif coredumps after doing a read_library) + * bug fix in lib_reduce_network + * (this fixed the core dump on sun machines upon read_library) + * + * Revision 1.6 1992/06/03 20:53:33 cmoon + * lib_reduce_network sets latch control node to NIL. + * + * Revision 1.5 1992/05/30 01:04:47 cmoon + * find_or_create_pattern returns prim after doing lib_expand_network now. + * + * Revision 1.4 1992/05/15 21:01:27 cmoon + * keep SIS from aborting when library spec with inconsistent + * name convention is used (compare_network). + * + * Revision 1.3 1992/05/06 00:27:18 cmoon + * in lib_pattern_matches + * + * Revision 1.2 1992/03/03 00:02:51 cmoon + * changed network_sweep to network_csweep + * + * Revision 1.1 92/01/08 17:40:43 sis + * Initial revision + * + */ +#include "sis.h" +#include "map_int.h" + +static network_t *lib_wire(); +static int process_pattern(); +static int process_constant(); +static prim_t *find_or_create_pattern(); +static lib_gate_t *find_gate(); +static lib_gate_t *find_or_create_gate(); +static lib_class_t *find_class(); +static lib_class_t *find_or_create_class(); +static void derive_dual_classes(); +static network_t *dual_network(); +static void lib_reset_default_gates(); +static void lib_reset_prim_table(); + +/* sequential support */ +static char **lib_get_pin_delay_info(); +static char *node_real_name(); +static st_table *clock_table; + +#ifdef SIS +typedef struct lib_clock_t lib_clock_t; +struct lib_clock_t { + char *name; + delay_pin_t *delay; +}; + +static int lib_reduce_network(); +static int lib_expand_network(); +static int lib_get_latch_pin(); +static latch_time_t **lib_get_latch_time_info(); +static void lib_register_type(); +static void lib_save_clock_info(); +#endif /* SIS */ + +int +lib_read_blif(fp, filename, add_inverter, nand_flag, library_p) +FILE *fp; +char *filename; +int add_inverter; +int nand_flag; +library_t **library_p; +{ + int new_gates, c; + library_t *library; + network_t *network, *wire; + st_generator *gen; + char *key, *value; + + lib_reset_default_gates(); + lib_reset_prim_table(); +#ifdef SIS + clock_table = st_init_table(strcmp, st_strhash); +#endif /* SIS */ + library = *library_p; + if (library == 0) { + library = ALLOC(library_t, 1); + library->gates = lsCreate(); + library->classes = lsCreate(); + library->patterns = lsCreate(); + library->nand_flag = nand_flag; + library->add_inverter = add_inverter; + } + + new_gates = 0; + read_register_filename(filename); + while ((c = read_blif_first(fp, &network)) != -1) { + if (! c) return 0; + +#ifdef SIS + lib_register_type(network); +#endif /* SIS */ + + if (network_num_pi(network) == 0) { + /* process constant 0 or 1 cell */ + if (! process_constant(library, network)) { + return 0; + } + + } else { + /* make sure its a 2-input NAND (NOR) gate network */ + if (! map_check_form(network, library->nand_flag)) { + return 0; + } + + /* add double-inverter pair to all internal nodes */ + if (library->add_inverter) { + map_add_inverter(network, /* add_at_pipo */ 0); + } + + /* add the pattern and gate to the library */ + if (! process_pattern(library, network)) { + return 0; + } + } + new_gates = 1; + } + + /* Make sure the library has a wire primitive */ + wire = lib_wire(); + if (! find_gate(library, wire)) { +#ifdef SIS + lib_register_type(wire); +#endif /* SIS */ + if (! process_pattern(library, wire)) { + return 0; + } + new_gates = 1; + } else { + network_free(wire); + } + + if (new_gates) { + derive_dual_classes(library); + } + + *library_p = library; +#ifdef SIS + st_foreach_item(clock_table, gen, &key, &value) { + FREE(key); + FREE(value); + } + st_free_table(clock_table); +#endif /* SIS */ + return 1; +} + +static int +process_pattern(library, network) +library_t *library; +network_t *network; +{ + lib_class_t *class; + lib_gate_t *gate; + prim_t *prim; + + map_setup_network(network); + + prim = find_or_create_pattern(library, network); + if (! prim) return 0; + + gate = find_or_create_gate(library, network); + if (! gate) return 0; + + class = find_or_create_class(library, gate); + if (! class) return 0; + + LS_ASSERT(lsNewEnd(prim->gates, (char *) gate, LS_NH)); + + return 1; +} + + + +static int +process_constant(library, network) +library_t *library; +network_t *network; +{ + node_t *node; + node_function_t func; + lib_gate_t *gate; + lib_class_t *class; + + if (network_num_po(network) != 1) { + error_append("no-input function is not single-output ?\n"); + return 0; + } + node = node_get_fanin(network_get_po(network, 0), 0); + func = node_function(node); + if (func == NODE_0 || func == NODE_1) { + gate = find_or_create_gate(library, network); + if (! gate) return 0; + + class = find_or_create_class(library, gate); + if (! class) return 0; + } else { + error_append("no-input function is not a constant ?\n"); + return 0; + } + return 1; +} + +static int match_flag; + + +static int +found_match(prim) +prim_t *prim; +{ + int i; + + for(i = 0; i < prim->ninputs; i++) { + if (prim->inputs[i]->binding->type != PRIMARY_INPUT) { + return 1; /* not a match, continue search ... */ + } + } + match_flag = 1; + return 0; /* stop search now ... */ +} + + +int +lib_pattern_matches(network, prim, ignore_type) +network_t *network; +prim_t *prim; +int ignore_type; +{ + node_t *po; + + if (network_num_pi(network) != prim->ninputs) { + return 0; + } + if (network_num_po(network) != prim->noutputs) { + return 0; + } +#ifdef SIS + if (!ignore_type) { + if (network_gate_type(network) != prim->latch_type) { + return 0; + } + } + if (prim->latch_type == COMBINATIONAL) { + po = node_get_fanin(network_get_po(network, 0), 0); + } else { + po = network_get_po(network, 0); + } +#else + po = node_get_fanin(network_get_po(network, 0), 0); +#endif /* SIS */ + match_flag = 0; + gen_all_matches(po, prim, found_match, /* debug */ 0, /* allow_internal_fanout */ 0, /* fanout_limit */ INFINITY); + return match_flag; +} + + +static prim_t * +find_or_create_pattern(library, network) +library_t *library; +network_t *network; +{ + lsGen gen; + prim_t *prim; + +#ifdef SIS + /* remove unnecessary nodes for pattern matching */ + if (!lib_reduce_network(network)) { + return 0; + } +#endif /* SIS */ + + /* see if this is a new pattern, or duplicates some existing pattern */ + lsForeachItem(library->patterns, gen, prim) { + if (lib_pattern_matches(network, prim, /* consider type */ 0)) { + LS_ASSERT(lsFinish(gen)); +#ifdef SIS + if (!lib_expand_network(network)) return 0; +#endif /* SIS */ + return prim; + } + } + + if (! map_network_to_prim(network, &prim)) { + return 0; + } + +#ifdef SIS + /* add an internal node if necessary */ + if (!lib_expand_network(network)) { + return 0; + } +#endif /* SIS */ + + LS_ASSERT(lsNewEnd(library->patterns, (char *) prim, LS_NH)); + return prim; +} + +static lib_gate_t * +find_gate(library, network) +library_t *library; +network_t *network; +{ + lsGen gen; + lib_gate_t *gate; + char *netname; + + netname = network_name(network); + lsForeachItem(library->gates, gen, gate) { + if (strcmp(gate->name, netname) == 0) { + /* ### should check that area, delay, function are the same ... */ + LS_ASSERT(lsFinish(gen)); + return gate; + } + } + return 0; +} + + +static lib_gate_t * +find_or_create_gate(library, network) +library_t *library; +network_t *network; +{ + int i; + lib_gate_t *gate; + char errmsg[1024]; +#ifdef SIS + lib_clock_t *clock_info; +#endif /* SIS */ + + gate = find_gate(library, network); + if (gate == 0) { + /* collapse network, re-order fanin of each node */ + node_lib_process(network); + + gate = ALLOC(lib_gate_t, 1); + gate->name = util_strsav(network_name(network)); + gate->network = network; + gate->area = network->area; +#ifdef SIS + gate->type = network_gate_type(network); + gate->latch_pin = lib_get_latch_pin(network); + gate->latch_time_info = lib_get_latch_time_info(network); + if (st_lookup(clock_table, network_name(network), (char**) &clock_info)) { + gate->control_name = clock_info->name; + gate->clock_delay = clock_info->delay; + } else { + gate->control_name = NIL(char); + gate->clock_delay = NIL(delay_pin_t); + } +#endif /* SIS */ + gate->delay_info = lib_get_pin_delay_info(network); + gate->class_p = 0; + LS_ASSERT(lsNewEnd(library->gates, (char *) gate, LS_NH)); + + if (! network->area_given) { + (void) sprintf(errmsg, "'%s': area not given", gate->name); + read_error(errmsg); + return 0; + } + if (strcmp(network_name(network), "**wire**") != 0) { + for(i = network_num_pi(network)-1; i >= 0; i--) { + if (gate->delay_info[i] == 0) { + (void) sprintf(errmsg, + "'%s': missing delay information for pin '%s'", + gate->name, node_name(network_get_pi(network, i))); + read_error(errmsg); + return 0; + } +#ifdef SIS + if (gate->latch_pin == i) continue; + if (lib_gate_type(gate) != COMBINATIONAL && lib_gate_type(gate) != ASYNCH) { + if (gate->latch_time_info[i] == 0) { + (void) sprintf(errmsg, + "'%s': missing latch time for pin '%s'", + gate->name, node_name(network_get_pi(network, i))); + read_error(errmsg); + return 0; + } + } +#endif /* SIS */ + } + } + } else { + network_free(network); + } + return gate; +} + +/* + * compare two networks for equality (by name) of all outputs + * the networks should already be collapsed. + */ + +static int +compare_network(net1, net2) +network_t *net1, *net2; +{ + lsGen gen; + node_t *po1, *po2; + + if (network_num_pi(net1) != network_num_pi(net2)) { + return 1; + } + if (network_num_po(net1) != network_num_po(net2)) { + return 1; + } + +#ifdef SIS + /* sequential support */ + if (network_gate_type(net1) != network_gate_type(net2)) { + return 1; + } +#endif + + foreach_primary_output(net1, gen, po1) { + po2 = network_find_node(net2, po1->name); + if (po2 == 0 || node_type(po2) != PRIMARY_OUTPUT) { + LS_ASSERT(lsFinish(gen)); + return 1; + } + po1 = node_get_fanin(po1, 0); + po2 = node_get_fanin(po2, 0); + if (! node_equal_by_name(po1, po2)) { + LS_ASSERT(lsFinish(gen)); + return 1; + } + } + return 0; +} + +static lib_class_t * +find_class(library, network) +library_t *library; +network_t *network; +{ + lsGen gen; + lib_class_t *class; + + lsForeachItem(library->classes, gen, class) { + if (compare_network(network, class->network) == 0) { + LS_ASSERT(lsFinish(gen)); + return class; + } + } + return 0; +} + + +static lib_class_t * +find_or_create_class(library, gate) +library_t *library; +lib_gate_t *gate; +{ + lib_class_t *class_p; + + /* see if gate is already assigned to a class */ + if (gate->class_p != 0) { + return gate->class_p; + } + + class_p = find_class(library, gate->network); + if (class_p == NIL(lib_class_t)) { + class_p = ALLOC(lib_class_t, 1); + class_p->network = gate->network; + class_p->gates = lsCreate(); + class_p->dual_class = 0; + class_p->name = 0; + LS_ASSERT(lsNewEnd(library->classes, (char *) class_p, LS_NH)); + class_p->library = library; + } else { + network_free(gate->network); + gate->network = class_p->network; + } + + LS_ASSERT(lsNewEnd(class_p->gates, (char *) gate, LS_NH)); + gate->class_p = class_p; + return class_p; +} + +static void +derive_dual_classes(library) +library_t *library; +{ + lsGen gen; + lib_class_t *class; + network_t *dual; + + lsForeachItem(library->classes, gen, class) { + dual = dual_network(class->network); + (void) network_collapse(dual); + class->dual_class = find_class(library, dual); + network_free(dual); + } +} + + +static network_t * +dual_network(network) +network_t *network; +{ + node_t *pi, *po, *node, *inv; + network_t *new_network; + lsGen gen, gen1; + + new_network = network_dup(network); + + foreach_primary_input(new_network, gen, pi) { + inv = node_literal(pi, 0); + foreach_fanout(pi, gen1, node) { + assert(node_patch_fanin(node, pi, inv)); + } + network_add_node(new_network, inv); + } + + foreach_primary_output(new_network, gen, po) { + node = node_get_fanin(po, 0); + inv = node_literal(node, 0); + assert(node_patch_fanin(po, node, inv)); + network_add_node(new_network, inv); + } + + return new_network; +} + +static network_t * +lib_wire() +{ + network_t *wire; + + wire = read_eqn_string("NAME = \"**wire**\"; Z = ! o1; o1 = ! a;"); + wire->area_given = 1; + wire->area = 0.0; + assert(wire != 0); + return wire; +} + +static double get_gate_area(gate) +lib_gate_t *gate; +{ + if (gate == NIL(lib_gate_t)) return INFINITY; + return lib_gate_area(gate); +} + + +/* + * search the library for the 'smallest' gate with a given function + */ + +lib_gate_t * +choose_smallest_gate(library, string) +library_t *library; +char *string; +{ + return choose_nth_smallest_gate(library, string, 0); +} + + /* only order=0 (smallest) and order=1 (second smallest) currently implemented */ + +lib_gate_t *choose_nth_smallest_gate(library, string, order) +library_t *library; +char *string; +int order; +{ + network_t *network; + lib_class_t *class_p; + lib_gate_t *gate, *best_gate, *second_best_gate; + lsGen gen; + + network = read_eqn_string(string); + if (network == 0) return 0; + class_p = lib_get_class(network, library); + network_free(network); + if (class_p == 0) return 0; + + best_gate = NIL(lib_gate_t); + second_best_gate = NIL(lib_gate_t); + gen = lib_gen_gates(class_p); + while (lsNext(gen, (char **) &gate, LS_NH) == LS_OK) { + if (get_gate_area(gate) < get_gate_area(second_best_gate)) { + if (get_gate_area(gate) < get_gate_area(best_gate)) { + second_best_gate = best_gate; + best_gate = gate; + } else { + second_best_gate = gate; + } + } + } + (void) lsFinish(gen); + if (order == 0 || (order == 1 && second_best_gate == NIL(lib_gate_t))) { + return best_gate; + } else if (order == 1) { + return second_best_gate; + } else { + return NIL(lib_gate_t); + } +} + + /* default inverter; cached for efficiency but need to be reset */ + +static lib_gate_t *default_inverter = NIL(lib_gate_t); + +static void lib_reset_default_gates() +{ + default_inverter = NIL(lib_gate_t); +} + +lib_gate_t *lib_get_default_inverter() +{ + library_t *library; + + if (default_inverter == NIL(lib_gate_t)) { + assert(library = lib_get_library()); + default_inverter = choose_nth_smallest_gate(library, "f=!a;", 1); + assert(default_inverter != NIL(lib_gate_t)); + } + return default_inverter; +} + + /* map from classes to prim_t structures. Cached for efficiency. Need to be reset for every new library */ + +static st_table *lib_prim_table; + +static void lib_reset_prim_table() +{ + st_generator *gen; + lib_class_t *class_p; + array_t *prims; + + if (lib_prim_table == NIL(st_table)) return; + st_foreach_item(lib_prim_table, gen, (char **) &class_p, (char **) &prims) { + array_free(prims); + } + st_free_table(lib_prim_table); + lib_prim_table = NIL(st_table); +} + + + /* computes an array of prim_t *'s corresponding to a class */ + +array_t *lib_get_prims_from_class(class_p) +lib_class_t *class_p; +{ + array_t **slot; + library_t *library; + lsGen gen1, gen2; + lib_gate_t *gate; + prim_t *prim; + + if (lib_prim_table == NIL(st_table)) { + lib_prim_table = st_init_table(st_ptrcmp, st_ptrhash); + } + if (st_find_or_add(lib_prim_table, (char *) class_p, (char ***) &slot)) return *slot; + *slot = array_alloc(prim_t *, 0); + library = class_p->library; + lsForeachItem(library->patterns, gen1, prim) { + lsForeachItem(prim->gates, gen2, gate) { + if (gate->class_p == class_p) { + array_insert_last(prim_t *, *slot, prim); + lsFinish(gen2); + break; + } + } + } + return *slot; +} + +#ifdef SIS + +/* HACK: remove nodes which are not necessary + * for pattern matching. + * (e.g., "ANY" node, clock node, etc.) + */ +static int +lib_reduce_network(network) +network_t *network; +{ + node_t *node; + latch_t *latch; + node_t *clock, *latch_input; + char errmsg[1024]; + + assert(network_gate_type(network) != (int) UNKNOWN); + if (network_gate_type(network) != (int) COMBINATIONAL) { + latch_input = network_latch_input(network); + if (latch_input == NIL(node_t)) { + (void)sprintf(errmsg, "latch network '%s' has no latch input", network_name(network)); + read_error(errmsg); + return 0; + } + /* need a true PO name in prim */ + network_swap_names(network, latch_input, node_get_fanin(latch_input, 0)); + + /* remove nodes associated with the clock */ + latch = latch_from_node(latch_input); + if (latch == NIL(latch_t)) { + (void)sprintf(errmsg, "latch network '%s' has no latch", network_name(network)); + read_error(errmsg); + return 0; + } + clock = latch_get_control(latch); + if (clock != NIL(node_t)) { + /* save clock info and delete clock nodes */ + lib_save_clock_info(network, clock); + latch_set_control(latch, NIL(node_t)); + } + + /* remove "ANY" node */ + node = network_find_node(network, "ANY"); + if (node != NIL(node_t)) { + node_t *fanin = NIL(node_t); + + network_delete_latch(network, latch); + /* "ANY" node may have a fanin. + * In that case, remove the fanin as well. + */ + if (node_num_fanin(node) != 0) { + assert(node_num_fanin(node) == 1); + fanin = node_get_fanin(node, 0); + } + network_delete_node(network, node); + if (fanin != NIL(node_t)) network_delete_node(network, fanin); + + /* hack for D-type latches */ + if (network_num_pi(network) == 1) (void) network_csweep(network); + } + } + return 1; +} + +/* HACK: Basically, undo a change done by + * lib_reduce_network. + * Add an internal node in the network + * if the network has no internal node. + * D-type FF is represented by PI->PO + * after lib_reduce_network. + */ +static int +lib_expand_network(network) +network_t *network; +{ + node_t *pi, *internal, *po; + + if (network_num_internal(network) == 0) { + assert(network_num_po(network)==1); + po = network_get_po(network, 0); + pi = node_get_fanin(po, 0); + assert(node_type(pi) == PRIMARY_INPUT); + internal = node_alloc(); + node_replace(internal, node_literal(pi, 1)); + assert(node_patch_fanin(po, pi, internal)); + network_add_node(network, internal); + } + return 1; +} +#endif /* SIS */ + +/* + * latch output nodes should not affect delay computation. + * set all the delay parameters to 0 (this can alternatively be fixed + * inside the delay package) for latch output pins. + */ +static char ** +lib_get_pin_delay_info(network) +network_t *network; +{ +#ifdef SIS + lsGen gen; + node_t *node; + + if (network_gate_type(network) != (int) COMBINATIONAL) { + foreach_primary_input(network, gen, node) { + if (IS_LATCH_END(node)) { + delay_set_parameter(node, DELAY_BLOCK_RISE, 0.0); + delay_set_parameter(node, DELAY_BLOCK_FALL, 0.0); + delay_set_parameter(node, DELAY_DRIVE_RISE, 0.0); + delay_set_parameter(node, DELAY_DRIVE_FALL, 0.0); + delay_set_parameter(node, DELAY_INPUT_LOAD, 0.0); + delay_set_parameter(node, DELAY_MAX_INPUT_LOAD, 0.0); + delay_set_parameter(node, DELAY_PHASE, DELAY_PHASE_NEITHER); + } + } + } +#endif /* SIS */ + return(delay_giveaway_pin_delay(network)); +} + +#ifdef SIS +/* return the fanin index for the latch output pin + * if none exists, return -1 + */ +static int +lib_get_latch_pin(network) +network_t *network; +{ + lsGen gen; + node_t *pi, *latch_output; + int i; + + latch_output = NIL(node_t); + i = 0; + foreach_primary_input(network, gen, pi) { + if (IS_LATCH_END(pi)) { + assert(latch_output == NIL(node_t)); /* only one latch output */ + latch_output = pi; + LS_ASSERT(lsFinish(gen)); + break; + } + i++; + } + if (latch_output == NIL(node_t)) return -1; + return i; +} + +/* return the array of setup/hold times */ +static latch_time_t ** +lib_get_latch_time_info(network) +network_t *network; +{ + node_t *node; + latch_time_t **latch_time_array; + lsGen gen; + int i; + + switch(network_gate_type(network)) { + case (int) COMBINATIONAL: + case (int) ASYNCH: + return NIL(latch_time_t *); + default: + latch_time_array = ALLOC(latch_time_t *, network_num_pi(network)); + i = 0; + foreach_primary_input(network, gen, node) { + if (!IS_LATCH_END(node)) { + latch_time_array[i] = ALLOC(latch_time_t, 1); + latch_time_array[i]->setup = delay_get_parameter(node, DELAY_ARRIVAL_RISE); + latch_time_array[i]->hold = delay_get_parameter(node, DELAY_ARRIVAL_FALL); + } else { + latch_time_array[i] = NIL(latch_time_t); + } + i++; + } + } + return latch_time_array; +} + +/* save clock name and delay and then + * delete the clock nodes + */ +static void +lib_save_clock_info(network, clock) +network_t *network; +node_t *clock; +{ + lib_clock_t *clock_info; + node_t *clock_fanin; + double n; + + /* some sanity check */ + assert(node_type(clock) == PRIMARY_OUTPUT && node_num_fanin(clock) == 1); + clock_fanin = node_get_fanin(clock, 0); + assert(node_type(clock_fanin) == PRIMARY_INPUT && node_num_fanout(clock_fanin) == 1); + + if (!st_is_member(clock_table, network_name(network))) { + clock_info = ALLOC(lib_clock_t, 1); + clock_info->name = node_real_name(clock); + clock_info->delay = ALLOC(delay_pin_t, 1); + clock_info->delay->block.rise = delay_get_parameter(clock_fanin, DELAY_BLOCK_RISE); + clock_info->delay->block.fall = delay_get_parameter(clock_fanin, DELAY_BLOCK_FALL); + clock_info->delay->drive.rise = delay_get_parameter(clock_fanin, DELAY_DRIVE_RISE); + clock_info->delay->drive.fall = delay_get_parameter(clock_fanin, DELAY_DRIVE_FALL); + clock_info->delay->load = delay_get_parameter(clock_fanin, DELAY_INPUT_LOAD); + clock_info->delay->max_load = delay_get_parameter(clock_fanin, DELAY_MAX_INPUT_LOAD); + n = delay_get_parameter(clock_fanin, DELAY_PHASE); + if (n == DELAY_PHASE_INVERTING) { + clock_info->delay->phase = PHASE_INVERTING; + } else if (n == DELAY_PHASE_NONINVERTING) { + clock_info->delay->phase = PHASE_NONINVERTING; + } else if (n == DELAY_PHASE_NEITHER) { + clock_info->delay->phase = PHASE_NEITHER; + } else { + clock_info->delay->phase = PHASE_NOT_GIVEN; + } + assert(st_insert(clock_table, util_strsav(network_name(network)), (char *)clock_info)==0); + } + network_delete_node(network, clock); + network_delete_node(network, clock_fanin); +} + +static void +lib_register_type(network) +network_t *network; +{ + lsGen gen; + node_t *node; + node_t *latch_input = NIL(node_t); + int *type; + latch_t *latch; + + if (!st_is_member(network_type_table, network_name(network))) { + foreach_primary_output(network, gen, node) { + if (IS_LATCH_END(node)) { + assert(latch_input == NIL(node_t)); /* only one latch input per gate */ + latch_input = node; + LS_ASSERT(lsFinish(gen)); + break; + } + } + type = ALLOC(int, 1); + if (latch_input == NIL(node_t)) { + *type = (int) COMBINATIONAL; + } else { + latch = latch_from_node(latch_input); + assert(latch != NIL(latch_t)); + *type = (int) latch_get_type(latch); + } + assert(st_insert(network_type_table, util_strsav(network_name(network)), (char*)type)==0); + } +} + +#endif /* SIS */ + +/* returns the name of the node without {,[,],} */ +/* assumes a single node name (no "[23, 43]" type of name) */ +static char* +node_real_name(node) +node_t *node; +{ + char *name, *n; + int len, i; + + name = node_name(node); + len = strlen(name); + n = ALLOC(char, len); + if (name[0] == '{' || name[0] == '[') { + assert(name[len-1] == '}' || name[len-1] == ']'); + for (i = 1; i < len - 1; i++) { + n[i-1] = name[i]; + } + n[i-1] = '\0'; + } else { + (void) strcpy(n, name); + } + return n; +} + +/* for debugging purposes */ +st_print(table) +st_table *table; +{ + st_generator *gen; + char *key, *val; + + st_foreach_item(table, gen, &key, &val) { + printf("key = %s, value = %s\n", key, val); + } +} diff --git a/sis/map/library.doc b/sis/map/library.doc new file mode 100644 index 0000000..7a08905 --- /dev/null +++ b/sis/map/library.doc @@ -0,0 +1,263 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/library.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)library.doc 1.3 */ +/* last modified on 9/16/91 at 17:08:24 */ + +A library consists of a number of gates. All of the gates which have +the same logic functions are grouped into 'classes'. The basic data +types are library_t, lib_class_t, and lib_gate_t. It is verboten to +look inside these structures, because the organization of the data is +still being refined. + + +library_t * +lib_get_library() + Returns the 'current' library, or NIL(library_t) if a current + library has not been defined. + + +lsGen +lib_gen_classes(library) +library_t *library; + Initialize an lsGen generator for the class in a given library. + See generator usage example below. + + +lsGen +lib_gen_gates(class) +lib_class_t *class; + Initialize an lsGen generator for the gates in a given class. + See generator usage example below. + + +lib_class_t * +lib_get_class(network, library) +network_t *network; +library_t *library; + (For backward compatibility) + Given a 'network', find the COMBINATIONAL gate-class which has the same logic + function. Use lib_get_class_by_type for find other gate-classes. + Returns NIL(lib_class_t) if there is no such gate in + the library. A fast way to construct a network is using + read_eqn_string(). + +lib_gate_t * +lib_get_gate(library, name) +library_t *library; +char *name; + Get a gate by its name. Returns NIL(lib_gate_t) if no gate with + that name is found in 'library'. + +/* + * Attributes of a class + */ + +char * +lib_class_name(class) +lib_class_t *class; + Returns the name of a class. Currently, a class is named by the + name of its first gate (essentially, a randomly chosen gate). + + +lib_class_t * +lib_class_dual(class) +lib_class_t *class; + Returns the dual class of a class, or NIL(lib_class_t) if the + given class does not have any dual gates in the library. + + +network_t * +lib_class_network(class) +lib_class_t *class; + Return a 'network' which represents the logic function associated + with a class. Do not alter or free this network. + +/* + * Attributes of a gate + */ + +char * +lib_gate_name(gate) +lib_gate_t *gate; + Returns the name of a gate. Do not free or alter the return string. + + +char * +lib_gate_pin_name(gate, pin, inflag) +lib_gate_t *gate; +int pin; +int inflag; + Returns the name of a pin on a gate. Do not free or alter the + return string. Returns NIL(char) if 'pin' is more than the + number of pins on the gate. If 'inflag' is 1, then the n'th + input pin name is returned; if 0, then the n'th output pin name + is returned. If 'inflag' is 2, then the control (clock) pin + name is returned ('pin' is ignored in this case). + Pin numbers start at 0. + + +double +lib_gate_area(gate) +lib_gate_t *gate; + Return the area of a gate. + + +lib_class_t * +lib_gate_class(gate) +lib_gate_t *gate; + Returns the class of a gate. + + +int +lib_gate_num_in(gate) +lib_gate_t *gate; + Returns the number of inputs of the gate. + + +int +lib_gate_num_out(gate) +lib_gate_t *gate; + Returns the number of outputs of the gate. + +/* + * Mixing the library and node packages + */ + +lib_gate_t * +lib_gate_of(node) +node_t *node; + Return the gate which is currently implementing 'node'. Returns + NIL(lib_gate_t) if this node is not mapped. Note that PRIMARY_INPUT + and PRIMARY_OUTPUT nodes are never mapped; hence, lib_gate_of() + will always return NIL(char) for them. + + +int +lib_network_is_mapped(network) +network_t *network; + Returns 1 if the network is mapped (i.e., all nodes in the network + have an associated gate from a library), or 0 if not. + + +int +lib_set_gate(node, gate, formals, actuals, nin) +node_t *node; +lib_gate_t *gate; +char **formals; +node_t **actuals; +int nin; + This can be used to either (1) set the implementation + of the 'node' to be 'gate' or (2) create a latch + with the 'node' as the latch output and 'actuals' as + input pins to the latch. Usage (2) is assumed + if 'node' is a primary input,(1) otherwise. + + (1) This sets the implementation of the given node to be 'gate'. + This changes the logic function of the 'node', and sets the node as + 'mapped'. 'formals' is an array of names of the formal terminals of the gate + (i.e., the gate pin names). 'actuals' is an array of nodes in + the network (should be the same network that 'node' belongs to) + which is matched in 1-1 correspondance with 'formals'. + As a consistency check, 'nin' declares the + sizes of the arrays 'formals', and 'actuals'. 'nin' should be + equal to the number of primary inputs of gate->network. + Returns 1 on success, 0 if any error. Probable errors are: gate is + NIL(lib_gate_t), number of inputs declared via 'nin' does not + match the number of inputs on 'gate', the specified gate is not + single-output, or some name in 'formals' is not a pin on the + gate. error_string() is appended to in the case of an error. + + (2) This creates a latch connection with the 'node' as the latch + output and an internally created primary output as the latch input. + An internal node is also created and its implementation is + set to be 'gate'. 'formals' and 'actuals' are the same as + those defined in (1) except that they do not include latch output + pins. 'nin' in this case is equal to network_num_pi(gate->network) - 1 + for complex latches (latches with more than one input) and + 1 for D-type latches/flip-flops. The following fields of the newly + created latch structure (latch_t) are set: input, output, synch_type and gate. + The rest of the fields (initial value, current_value and control) must be + set by the calling program. + +Generator usage example: + lsGen gen, gen1; + library_t *library; + lib_class_t *class; + lib_gate_t *gate; char *dummy; + + library = lib_get_library(); + gen1 = lib_gen_classes(library); + while (lsNext(gen1, &dummy, LS_NH) == LS_OK) { + class = (lib_class_t *) dummy; + /* + * do something with class + */ + + gen2 = lib_gen_gates(class); + while (lsNext(gen2, &dummy, LS_NH) == LS_OK) { + gate = (lib_class_t *) dummy; + /* + * do something with gate + */ + } + (void) lsFinish(gen2); + } + (void) lsFinish(gen1); + + +/* sequential support */ +latch_synch_t +lib_gate_type(gate) +lib_gate_t *gate; + Given a library gate, return the type of the gate (i.e., COMBINATIONAL, + ACTIVE_HIGH, ACTIVE_LOW, RISING_EDGE, FALLING_EDGE, ASYNCH or UNKNOWN). + +int +lib_gate_latch_pin(gate) +lib_gate_t *gate; + Given a latch/flip-flop, return the fanin index corresponding to + the latch output pin. If no such fanin exists (combinational + gates and D-type latches/flip-flops) return -1. + +latch_time_t** +lib_gate_latch_time(gate) +lib_gate_t *gate; + Given a latch/flip-flop, return the timing information (setup/hold) + associated with the latch. + +delay_pin_t* +lib_gate_clock_delay(gate) +lib_gate_t *gate; + Given a latch/flip-flop, return the pin delay from the clock pin to the + output pin. + +lib_class_t * +lib_get_class_by_type(network, library, type) +network_t *network; +library_t *library; +latch_synch_t type; + Given a 'network', find the gate-class of appropriate type which + has the same logic function. Returns NIL(lib_class_t) if there is + no such gate in the library. A fast way to construct a network is using + read_eqn_string(). + + +lib_gate_t * +lib_choose_smallest_latch(library, string, type) +library_t *library; +char *string; +latch_synch_type type; + + Given an equation string, return the smallest combinational + gate or latch of appropriate type which has the logic function + specified in the string. For example, to find a smallest D-type + transparent latch which is active high, use + lib_choose_smallest_latch(library, "q=d;" ACTIVE_HIGH). + diff --git a/sis/map/library.h b/sis/map/library.h new file mode 100644 index 0000000..26e92a7 --- /dev/null +++ b/sis/map/library.h @@ -0,0 +1,107 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/library.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)library.h 1.2 */ +/* last modified on 5/1/91 at 15:51:12 */ +#ifndef LIBRARY_H +#define LIBRARY_H + + +typedef struct library_struct library_t; +struct library_struct { + lsList classes; /* list of lib_class_t class descriptions */ + lsList gates; /* list of lib_gate_t gate descriptions */ + lsList patterns; /* list of prim_t patterns */ + int nand_flag; + int add_inverter; +}; + + +typedef struct lib_class_struct lib_class_t; +struct lib_class_struct { + network_t *network; /* the logic function for the class */ + lib_class_t *dual_class; /* pointer to class for complement of fct */ + lsList gates; /* list of gates in this class */ + library_t *library; /* pointer back to library */ + char *name; /* reserved for future use */ +}; + +#ifdef SIS +/* sequential support */ +typedef struct latch_time_struct latch_time_t; +struct latch_time_struct { + double setup; + double hold; +}; +#endif + +typedef struct lib_gate_struct lib_gate_t; +struct lib_gate_struct { + network_t *network; /* exactly equal to gate->class->network */ + char *name; /* the gate name */ + char **delay_info; /* the input pin delays */ + double area; /* the gate area */ + int symmetric; /* it is more or less symmetric WRT input pins */ + lib_class_t *class_p; /* pointer back to the class */ + +#ifdef SIS + /* sequential support */ + int type; /* type of gate -- lib_gate_type returns latch_synch_t */ + int latch_pin; /* index for the latch output pin (-1 if none) */ + latch_time_t **latch_time_info; /* setup/hold times */ + delay_pin_t *clock_delay; /* delay from clock to output */ + char *control_name; /* name of the clock pin */ +#endif +}; + + +/* normal library functions */ +EXTERN library_t *lib_get_library ARGS((void)); +EXTERN lsGen lib_gen_classes ARGS((library_t *)); +EXTERN lsGen lib_gen_gates ARGS((lib_class_t *)); +EXTERN lib_class_t *lib_get_class ARGS((network_t *, library_t *)); +EXTERN char *lib_class_name ARGS((lib_class_t *)); +EXTERN network_t *lib_class_network ARGS((lib_class_t *)); +EXTERN lib_class_t *lib_class_dual ARGS((lib_class_t *)); +EXTERN lib_gate_t *lib_get_gate ARGS((library_t *, char *)); +EXTERN char *lib_gate_name ARGS((lib_gate_t *)); +EXTERN char *lib_gate_pin_name ARGS((lib_gate_t *, int, int)); +EXTERN double lib_gate_area ARGS((lib_gate_t *)); +EXTERN lib_class_t *lib_gate_class ARGS((lib_gate_t *)); +EXTERN int lib_gate_num_in ARGS((lib_gate_t *)); +EXTERN int lib_gate_num_out ARGS((lib_gate_t *)); + +#ifdef SIS +/* sequential support */ +#define lib_gate_type(g) (((g)==NIL(lib_gate_t))?UNKNOWN:(enum latch_synch_enum)(g)->type) +#define lib_gate_latch_pin(g) (((g)==NIL(lib_gate_t))?-1:(g)->latch_pin) +#define lib_gate_latch_time(g) (((g)==NIL(lib_gate_t))?NIL(latch_time_t*):(g)->latch_time_info) +#define lib_gate_clock_delay(g) (((g)==NIL(lib_gate_t))?NIL(delay_pin_t):(g)->clock_delay) +EXTERN lib_gate_t *lib_choose_smallest_latch ARGS((library_t *, char *, enum latch_synch_enum)); +#endif + +#ifdef SIS +EXTERN lib_class_t *lib_get_class_by_type ARGS((network_t *, library_t *, latch_synch_t)); +#else +EXTERN lib_class_t *lib_get_class_by_type ARGS((network_t *, library_t *)); +#endif + +/* for mapped nodes/networks */ +EXTERN lib_gate_t *lib_gate_of ARGS((node_t *)); +EXTERN int lib_network_is_mapped ARGS((network_t *)); +EXTERN int lib_set_gate ARGS((node_t *, lib_gate_t *, char **, node_t **, int)); + +/* obsolete */ +EXTERN char *lib_get_gate_name ARGS((node_t *)); +EXTERN char *lib_get_pin_name ARGS((node_t *, int)); +EXTERN char *lib_get_out_pin_name ARGS((node_t *, int)); +EXTERN char *lib_get_pin_delay ARGS((node_t *, int)); +EXTERN double lib_get_gate_area ARGS((node_t *)); + +#endif diff --git a/sis/map/libutil.c b/sis/map/libutil.c new file mode 100644 index 0000000..2420acd --- /dev/null +++ b/sis/map/libutil.c @@ -0,0 +1,633 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/libutil.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)libutil.c 1.8 */ +/* last modified on 9/16/91 at 17:07:18 */ +#include "sis.h" +#include "map_int.h" +#include "lib_int.h" + +library_t *lib_current_library; + + +library_t * +lib_get_library() +{ + return lib_current_library; +} + + +lsGen +lib_gen_classes(library) +library_t *library; +{ + return lsStart(library->classes); +} + + +lsGen +lib_gen_gates(class) +lib_class_t *class; +{ + return lsStart(class->gates); +} + + +lib_gate_t * +lib_get_gate(library, name) +library_t *library; +char *name; +{ + lib_gate_t *gate; + lsGen gen; + + lsForeachItem(library->gates, gen, gate) { + if (strcmp(gate->name, name) == 0) { + LS_ASSERT(lsFinish(gen)); + return gate; + } + } + return NIL(lib_gate_t); +} + +/* for backward compatibility */ +lib_class_t * +lib_get_class(network, library) +network_t *network; +library_t *library; +{ +#ifdef SIS + return lib_get_class_by_type(network, library, COMBINATIONAL); +#else + return lib_get_class_by_type(network, library); +#endif +} + +/* + * lib_class_t access functions + */ + +char * +lib_class_name(class) +lib_class_t *class; +{ + lib_gate_t *gate; + char *dummy; + + if (class == 0) return NIL(char); + if (lsFirstItem(class->gates, &dummy, LS_NH) == LS_OK) { + gate = (lib_gate_t *) dummy; + return gate->name; + } + return NIL(char); +} + + +lib_class_t * +lib_class_dual(class) +lib_class_t *class; +{ + return class->dual_class; +} + + +network_t * +lib_class_network(class) +lib_class_t *class; +{ + return class->network; +} + +/* + * lib_gate_t access functions + */ + +char * +lib_gate_name(gate) +lib_gate_t *gate; +{ + if (gate == 0) return NIL(char); + return gate->name; +} + + +char * +lib_gate_pin_name(gate, pin, inflag) +lib_gate_t *gate; +int pin; +int inflag; +{ + node_t *p; + + if (gate == 0) return NIL(char); + switch(inflag){ + case 0: + p = network_get_po(gate->network, pin); + break; + case 1: + p = network_get_pi(gate->network, pin); + break; +#ifdef SIS + case 2: + return (gate->control_name); +#endif + default: + p = NIL(node_t); + break; + } + return p ? p->name : NIL(char); +} + + +double +lib_gate_area(gate) +lib_gate_t *gate; +{ + if (gate == 0) return 0.0; + return gate->area; +} + + +lib_class_t * +lib_gate_class(gate) +lib_gate_t *gate; +{ + if (gate == 0) return NIL(lib_class_t); + return gate->class_p; +} + + +int +lib_gate_num_in(gate) +lib_gate_t *gate; +{ + if (gate == 0) return -1; + return network_num_pi(gate->network); +} + + +int +lib_gate_num_out(gate) +lib_gate_t *gate; +{ + if (gate == 0) return -1; + return network_num_po(gate->network); +} + + +/* + * misc functions + */ + +lib_gate_t * +lib_gate_of(node) +node_t *node; +{ + if (MAP(node) == 0) return NIL(lib_gate_t); + return MAP(node)->gate; +} + + +char * +lib_get_pin_delay(node, pin) +node_t *node; +int pin; +{ + if (MAP(node) == 0) return 0; + if (MAP(node)->gate == 0) return 0; + /* ### should check for out of bounds ? */ + return MAP(node)->gate->delay_info[pin]; +} + + + +int +lib_network_is_mapped(network) +network_t *network; +{ + network_type_t type; + + type = map_get_network_type(network); + return (type == MAPPED_NETWORK) ? 1 : 0; +} + +/* + * backwards compatibility + */ + +char * +lib_get_gate_name(node) +node_t *node; +{ + return lib_gate_name(lib_gate_of(node)); +} + + +char * +lib_get_pin_name(node, pin) +node_t *node; +int pin; +{ + return lib_gate_pin_name(lib_gate_of(node), pin, /* inflag */ 1); +} + + +char * +lib_get_out_pin_name(node, pin) +node_t *node; +int pin; +{ + return lib_gate_pin_name(lib_gate_of(node), pin, /* inflag */ 0); +} + + +double +lib_get_gate_area(node) +node_t *node; +{ + return lib_gate_area(lib_gate_of(node)); +} + +/* + * set the gate of a node -- assumes single-output gate + */ + +int +lib_set_gate(user_node, gate, formals, actuals, nin) +node_t *user_node; +lib_gate_t *gate; +char **formals; +node_t **actuals; +int nin; +{ + register int i, j; + node_t *node, *fanin, **new_fanin; + node_t *new_po; + char errmsg[1024]; +#ifdef SIS + node_t *new_node; /* sequential support */ + latch_t *latch; /* sequential support */ +#endif + int ninputs; + +#ifdef SIS + if (node_type(user_node) != PRIMARY_INPUT) { +#endif + if (nin != network_num_pi(gate->network)) { + error_append("lib_set_gate: number of inputs on gate is incorrect\n"); + return 0; + } + /* + if (network_num_po(gate->network) != 1) { + error_append("lib_set_gate: number of outputs on gate is incorrect\n"); + return 0; + } + */ + + new_fanin = ALLOC(node_t *, nin); + node = node_get_fanin(network_get_po(gate->network, 0), 0); + foreach_fanin(node, i, fanin) { + new_fanin[i] = NIL(node_t); + for(j = 0; j < nin; j++) { + if (strcmp(fanin->name, formals[j]) == 0) { + new_fanin[i] = actuals[j]; + break; + } + } + if (new_fanin[i] == 0) { + (void) sprintf(errmsg, + "lib_set_gate: pin '%s' not in formals list\n", fanin->name); + error_append(errmsg); + return 0; + } + } + + node_replace_internal(user_node, new_fanin, nin, sf_save(node->F)); + map_alloc(user_node); + MAP(user_node)->gate = gate; + return 1; +#ifdef SIS + } + /* sequential support : create a new PO, a new node, a new + * latch structure and set the new node to the given latch gate. + * input, output, type and gate fields of the latch structure + * are filled here. The rest of the fields must be filled + * by the calling program. + */ + + /* note that the feedback variable is not included in nin + */ + ninputs = nin + ( (lib_gate_latch_pin(gate)!=-1)?1:0 ); + if (ninputs != network_num_pi(gate->network)) { + error_append("lib_set_gate: number of inputs on gate is incorrect\n"); + return 0; + } + /* + * the user_node is a PI + * new_node -> [ PO, PI(user_node) ] + */ + new_node = node_alloc(); + network_add_node(node_network(user_node), new_node); + new_po = network_add_primary_output(node_network(user_node), new_node); + network_create_latch(node_network(user_node), &latch, new_po, user_node); + latch_set_gate(latch, gate); + latch_set_type(latch, lib_gate_type(gate)); + /* now set the new_node func to that of the given latch */ + new_fanin = ALLOC(node_t *, ninputs); + node = node_get_fanin(network_get_po(gate->network, 0), 0); + foreach_fanin(node, i, fanin) { + new_fanin[i] = NIL(node_t); + for (j = 0; j < ninputs; j++) { + if (strcmp(fanin->name, formals[j]) == 0) { + new_fanin[i] = actuals[j]; + break; + } + } + if (new_fanin[i] == 0) { + if (IS_LATCH_END(fanin)) { + new_fanin[i] = user_node; + } else { + (void) sprintf(errmsg, + "lib_set_gate: pin '%s' not in formals list\n", fanin->name); + error_append(errmsg); + return 0; + } + } + } + + node_replace_internal(new_node, new_fanin, ninputs, sf_save(node->F)); + map_alloc(new_node); + MAP(new_node)->gate = gate; + return 1; +#endif +} + +void +lib_free(library) +library_t *library; +{ + lsGen gen; + lib_gate_t *gate; + lib_class_t *class; + prim_t *prim; + int i; + + lsForeachItem(library->gates, gen, gate) { + for(i = network_num_pi(gate->network)-1; i >= 0; i--) { + FREE(gate->delay_info[i]); + } + FREE(gate->delay_info); +#ifdef SIS + if (gate->latch_time_info != NIL(latch_time_t *)) { + for (i = network_num_pi(gate->network)-1; i>=0; i--) { + if (gate->latch_time_info[i] != NIL(latch_time_t)) { + FREE(gate->latch_time_info[i]); + } + } + } + FREE(gate->latch_time_info); + if (gate->clock_delay != 0) { + FREE(gate->clock_delay); + } +#endif + FREE(gate->name); + FREE(gate); + } + LS_ASSERT(lsDestroy(library->gates, (void (*)()) 0)); + + lsForeachItem(library->classes, gen, class) { + network_free(class->network); + LS_ASSERT(lsDestroy(class->gates, (void (*)()) 0)); + FREE(class->name); + FREE(class); + } + LS_ASSERT(lsDestroy(library->classes, (void (*)()) 0)); + + lsForeachItem(library->patterns, gen, prim) { + prim_free(prim); + } + LS_ASSERT(lsDestroy(library->patterns, (void (*)()) 0)); + FREE(library); +} + +void +lib_dump(fp, library, detail) +FILE *fp; +library_t *library; +int detail; +{ + lsGen gen; + prim_t *prim; + lib_class_t *class; + + lsForeachItem(library->classes, gen, class) { + lib_dump_class(fp, class); + } + + (void) fprintf(fp, "\n"); + lsForeachItem(library->patterns, gen, prim) { + map_prim_dump(fp, prim, detail); + } +} + + + +void +lib_dump_class(fp, class) +FILE *fp; +lib_class_t *class; +{ + lsGen gen, gen1; + lib_gate_t *gate; + node_t *node; + char *dual_name; + + (void) fprintf(fp, "class: %s\n", lib_class_name(class)); + + lsForeachItem(class->gates, gen, gate) { + dual_name = lib_class_name(class->dual_class); + if (dual_name == 0) dual_name = "<none>"; + + (void) fprintf(fp, " gate: %-10s area: %5.2f dual_class: %s\n", + lib_gate_name(gate), lib_gate_area(gate), dual_name); + + foreach_primary_output(gate->network, gen1, node) { + (void) fprintf(fp, " "); + (void) node_print_negative(fp, node_get_fanin(node, 0)); + } + + assert(gate->class_p == class); + } + (void) fprintf(fp, "\n"); +} + +/* sequential support */ +lib_class_t * +#ifdef SIS +lib_get_class_by_type(network, library, type) +#else +lib_get_class_by_type(network, library) +#endif +network_t *network; +library_t *library; +#ifdef SIS +latch_synch_t type; +#endif +{ + lsGen gen; + lib_class_t *class_p; + lib_gate_t *gate; + network_t *net1; + node_t *node, *node1; + prim_t *prim; + char *dummy; + + if (library == NIL(library_t)) { + return NIL(lib_class_t); + } + /* Special hack as usual for constants */ + if (network_num_pi(network) == 0) { + node = node_get_fanin(network_get_po(network, 0), 0); + lsForeachItem(library->classes, gen, class_p) { + if (network_num_pi(class_p->network) == 0) { + node1 = node_get_fanin(network_get_po(class_p->network, 0), 0); + if (node_equal_by_name(node1, node)) { + LS_ASSERT(lsFinish(gen)); + return class_p; + } + } + } + return NIL(lib_class_t); + } + + net1 = network_dup(network); + decomp_quick_network(net1); + if (library->nand_flag) { + decomp_tech_network(net1, /* and_limit */ 0, /* or_limit */ 2); + } else { + decomp_tech_network(net1, /* and_limit */ 2, /* or_limit */ 0); + } + add_inv_network(net1); + if (library->add_inverter) { + map_add_inverter(net1, /* add_at_pipo */ 0); + } + + /* HACK: take care of buffers + * (buffer is represented by PI->INV->INV->PO in the library) + * (net1 looks like PI->PO) + */ +#ifdef SIS + if (type == COMBINATIONAL && network_num_pi(net1) == 1 && + network_num_internal(net1) == 0) { +#else + if (network_num_pi(net1) == 1 && network_num_internal(net1) == 0) { +#endif + node_t *po, *pi, *node1, *node2; + + po = network_get_po(net1, 0); + pi = node_get_fanin(po, 0); + node1 = node_alloc(); + node_replace(node1, node_literal(pi, 0)); + network_add_node(net1, node1); + node2 = node_alloc(); + node_replace(node2, node_literal(node1, 0)); + network_add_node(net1, node2); + assert(node_patch_fanin(po, pi, node2)); + } + map_setup_network(net1); /* needed for lib_pattern_matches() */ + + class_p = 0; + lsForeachItem(library->patterns, gen, prim) { +#ifdef SIS + if (prim->latch_type == type) { +#endif + if (lib_pattern_matches(net1, prim, /* ignore type */ 1)) { + LS_ASSERT(lsFirstItem(prim->gates, &dummy, LS_NH)); + gate = (lib_gate_t *) dummy; + if (strcmp(gate->name,"**wire**")!=0) { + class_p = gate->class_p; + LS_ASSERT(lsFinish(gen)); + break; + } + } +#ifdef SIS + } +#endif + } + network_free(net1); + return class_p; +} + +#ifdef SIS +lib_gate_t * +lib_choose_smallest_latch(library, string, latch_type) +library_t *library; +char *string; +latch_synch_t latch_type; +{ + network_t *network; + lib_class_t *class; + lib_gate_t *gate, *best_gate; + lsGen gen; + double best_area; + + network = read_eqn_string(string); + if (network == 0) return 0; + class = lib_get_class_by_type(network, library, latch_type); + network_free(network); + if (class == 0) return 0; + + best_area = INFINITY; + best_gate = 0; + gen = lib_gen_gates(class); + while (lsNext(gen, (char **) &gate, LS_NH) == LS_OK) { + if (lib_gate_area(gate) < best_area) { + best_area = lib_gate_area(gate); + best_gate = gate; + } + } + LS_ASSERT(lsFinish(gen)); + return best_gate; +} + +/* print params assoc. with a gate */ +void +lib_dump_gate(gate) +lib_gate_t *gate; +{ + int i; + + (void)fprintf(sisout, "%s : type=", gate->name); + switch(gate->type) { + case (int) COMBINATIONAL: (void) fprintf(sisout, "comb"); break; + case (int) ACTIVE_HIGH: (void)fprintf(sisout, "ah"); break; + case (int) ACTIVE_LOW: (void)fprintf(sisout, "al"); break; + case (int) RISING_EDGE: (void)fprintf(sisout, "re"); break; + case (int) FALLING_EDGE: (void)fprintf(sisout, "fe"); break; + case (int) ASYNCH: (void)fprintf(sisout, "as"); break; + default: (void)fprintf(sisout, "unknown"); break; + } + (void)fprintf(sisout, ", latch_pin # = %d, clock = %s\n", gate->latch_pin, + (gate->control_name != 0)?gate->control_name:"NIL"); + if (gate->latch_time_info != 0) { + for (i = 0; i < network_num_pi(gate->network); i++) { + if (gate->latch_time_info[i] != 0) { + (void)fprintf(sisout, " pin %d : setup = %4.2f, hold = %4.2f\n", i, + gate->latch_time_info[i]->setup, gate->latch_time_info[i]->hold); + } + } + } + if (gate->clock_delay != 0) { + (void)fprintf(sisout, " clock delay = %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f\n", + gate->clock_delay->block.rise, gate->clock_delay->block.fall, + gate->clock_delay->drive.rise, gate->clock_delay->drive.fall, + gate->clock_delay->load, gate->clock_delay->max_load); + } +} +#endif /* SIS */ diff --git a/sis/map/lt_trees.c b/sis/map/lt_trees.c new file mode 100644 index 0000000..451b9da --- /dev/null +++ b/sis/map/lt_trees.c @@ -0,0 +1,322 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/lt_trees.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)lt_trees.c 1.2 */ +/* last modified on 5/1/91 at 15:51:16 */ +#include "sis.h" +#include "fanout_int.h" +#include "fanout_delay.h" + +static int get_n_fanouts(); +static int lt_trees_optimize(); +static multidim_t *optimize_one_source(); +static void best_one_source(); +static void build_selected_tree(); +static void extract_merge_info(); +static void insert_lt_tree(); + + + /* CONTENTS */ + + /* LT-Trees based fanout optimization */ + +static n_gates_t n_gates; + +typedef struct lt_tree_struct lt_tree_t; +struct lt_tree_struct { + int balanced; /* boolean: whether this node is the root of a two level balanced tree or not */ + two_level_t *two_level; /* pointer to two_level_t descriptor (if balanced) */ + int gate_index; /* gate to put at intermediate nodes (if ! balanced) */ + int sink_index; /* sink_index - 1 is last sink directly under this node */ + delay_time_t required; /* required time at the source, not including source intrinsic */ + double area; /* area of subtree rooted here */ +}; + +static lt_tree_t LT_TREE_INIT_VALUE = {-1, 0, -1, -1, {-INFINITY, -INFINITY}, 0.0}; + +static int max_n_gaps = 5; + + + /* EXTERNAL INTERFACE */ + + /* ARGSUSED */ +void lt_trees_init(network, alg) +network_t *network; +fanout_alg_t *alg; +{ + alg->optimize = lt_trees_optimize; +} + + /* ARGSUSED */ +void lt_trees_set_max_n_gaps(alg, property) +fanout_alg_t *alg; +alg_property_t *property; +{ + max_n_gaps = property->value; +} + + + /* INTERNAL INTERFACE */ + +static multidim_t *two_level_table; + +static int lt_trees_optimize(fanout_info, tree, cost) +opt_array_t *fanout_info; /* fanout_info[POLAR_X] lists the positive polarity sinks; POLAR_Y negative */ +array_t *tree; /* array in which the result tree is stored: format of fanout_tree.c */ +fanout_cost_t *cost; /* contains information on the result: required times, area */ +{ + generic_fanout_optimizer(fanout_info, tree, cost, optimize_one_source, extract_merge_info, build_selected_tree); + multidim_free(two_level_table); + return 1; +} + +static multidim_t *optimize_one_source(fanout_info) +opt_array_t *fanout_info; +{ + multidim_t *table; + int indices[5]; + int max_sinks; + int source_index, source_polarity, sink_index, sink_polarity, n_gaps; + + n_gates = fanout_delay_get_n_gates(); + max_sinks = MAX(fanout_info[POLAR_X].n_elts, fanout_info[POLAR_Y].n_elts); + indices[0] = n_gates.n_gates; /* source index */ + indices[1] = POLAR_MAX; /* polarity at output of source */ + indices[2] = max_sinks; /* max sink index */ + indices[3] = POLAR_MAX; /* sink polarity */ + indices[4] = max_n_gaps; /* gaps used so far */ + table = multidim_alloc(lt_tree_t, 5, indices); + multidim_init(lt_tree_t, table, LT_TREE_INIT_VALUE); + two_level_table = two_level_optimize_for_lt_trees(fanout_info); + + foreach_polarity(sink_polarity) { + if (fanout_info[sink_polarity].n_elts == 0) continue; + for (sink_index = fanout_info[sink_polarity].n_elts - 1; sink_index >= 0; sink_index--) { + foreach_gate(n_gates, source_index) { + for (n_gaps = 0; n_gaps < max_n_gaps; n_gaps++) { + foreach_polarity(source_polarity) { + if (is_source(n_gates, source_index) && fanout_delay_get_source_polarity(source_index) != source_polarity) continue; + best_one_source(table, two_level_table, &fanout_info[sink_polarity], + source_index, source_polarity, sink_index, sink_polarity, n_gaps); + } + } + } + } + } + return table; +} + + + /* computes the best LT-tree for a given source, a given set of sinks */ + /* and a given polarity for both the output of the source and the input of the sinks */ + /* Sink interval of the form [sink_index,fanout_info->n_elts[ */ + +static void best_one_source(table, two_level_table, fanout_info, source_index, source_polarity, sink_index, sink_polarity, n_gaps) +multidim_t *table; +multidim_t *two_level_table; +opt_array_t *fanout_info; +int source_index; +int source_polarity; +int sink_index; +int sink_polarity; +int n_gaps; +{ + int sink; + int buffer_index, buffer_polarity, buffer_gaps; + lt_tree_t *buffer_entry; + int n_fanouts; + double load; + double local_area; + delay_time_t local_required; + two_level_t *two_level_entry = INDEX4P(two_level_t, two_level_table, source_index, source_polarity, sink_index, sink_polarity); + lt_tree_t *entry = INDEX5P(lt_tree_t, table, source_index, source_polarity, sink_index, sink_polarity, n_gaps); + + /* start with a two level implementation */ + entry->balanced = 1; + entry->two_level = two_level_entry; + entry->required = two_level_entry->required; + entry->area = two_level_entry->area; + + /* choose the best subdecomposition */ + for (sink = sink_index; sink <= fanout_info->n_elts; sink++) { + if (source_polarity != sink_polarity && sink > sink_index) continue; + foreach_buffer(n_gates, buffer_index) { + buffer_polarity = (is_inverter(n_gates, buffer_index)) ? POLAR_INV(source_polarity) : source_polarity; + buffer_gaps = (sink == sink_index && buffer_polarity == sink_polarity) ? n_gaps - 1 : n_gaps; + if (buffer_gaps < 0) continue; + if (sink < fanout_info->n_elts) { + buffer_entry = INDEX5P(lt_tree_t, table, buffer_index, buffer_polarity, sink, sink_polarity, buffer_gaps); + local_area = buffer_entry->area; + n_fanouts = 1; + load = fanout_delay_get_buffer_load(buffer_index); + local_required = fanout_delay_backward_intrinsic(buffer_entry->required, buffer_index); + } else { + local_area = 0.0; + n_fanouts = 0; + load = 0.0; + local_required = PLUS_INFINITY; + } + local_area += fanout_delay_get_area(source_index); + n_fanouts += sink - sink_index; + load += fanout_info->cumul_load[sink] - fanout_info->cumul_load[sink_index]; + load += map_compute_wire_load(n_fanouts); + if (sink > sink_index) SETMIN(local_required, local_required, fanout_info->min_required[sink_index]); + local_required = fanout_delay_backward_load_dependent(local_required, source_index, load); + if (GETMIN(entry->required) < GETMIN(local_required)) { + entry->balanced = 0; + entry->gate_index = buffer_index; + entry->sink_index = sink; + entry->required = local_required; + entry->area = local_area; + } + } + } +} + + /* needs corrective computation if source is root of tree: discard effect of drive at the source */ + +static void extract_merge_info(fanout_info, table, merge_table) +opt_array_t *fanout_info; +multidim_t *table; +multidim_t *merge_table; +{ + int source_index; + delay_time_t origin; + double load; + lt_tree_t *from; + single_source_t *to; + int source_polarity, sink_polarity; + + foreach_gate(n_gates, source_index) { + foreach_polarity(sink_polarity) { + foreach_polarity(source_polarity) { + from = INDEX5P(lt_tree_t, table, source_index, source_polarity, 0, sink_polarity, max_n_gaps - 1); + to = INDEX3P(single_source_t, merge_table, source_index, source_polarity, sink_polarity); + if (fanout_info[sink_polarity].n_elts == 0) { + to->required = PLUS_INFINITY; + } else if (is_buffer(n_gates,source_index)) { + to->load = fanout_delay_get_buffer_load(source_index); + to->n_fanouts = 1; + to->required = fanout_delay_backward_intrinsic(from->required, source_index); + to->area = from->area; + } else if (fanout_delay_get_source_polarity(source_index) == source_polarity) { + if (from->balanced) { + to->load = fanout_delay_get_buffer_load(from->two_level->gate_index) * from->two_level->n_gates; + to->n_fanouts = from->two_level->n_gates; + } else if (from->sink_index < fanout_info[sink_polarity].n_elts) { + to->load = fanout_info[sink_polarity].cumul_load[from->sink_index] + fanout_delay_get_buffer_load(from->gate_index); + to->n_fanouts = from->sink_index + 1; + } else { + to->load = fanout_info[sink_polarity].total_load; + to->n_fanouts = fanout_info[sink_polarity].n_elts; + } + load = to->load + map_compute_wire_load(to->n_fanouts); + origin = fanout_delay_backward_load_dependent(ZERO_DELAY, source_index, load); + SETSUB(to->required, from->required, origin); + to->area = from->area; + } + } + } + } +} + +static void build_selected_tree(fanout_info, tree, source, table) +opt_array_t *fanout_info; +array_t *tree; +selected_source_t *source; +multidim_t *table; +{ + int p, q; + int n_fanouts; + int n_gaps = max_n_gaps - 1; + int source_polarity, buffer_polarity; + + source_polarity = fanout_delay_get_source_polarity(source->main_source); + p = source->main_source_sink_polarity; + q = POLAR_INV(p); + if (fanout_info[q].n_elts > 0) { + if (is_source(n_gates, source->buffer)) { + assert(source->buffer == source->main_source); + n_fanouts = get_n_fanouts(&fanout_info[p], table, source->main_source, source_polarity, 0, p, n_gaps); + n_fanouts += get_n_fanouts(&fanout_info[q], table, source->main_source, source_polarity, 0, q, n_gaps); + fanout_tree_insert_gate(tree, source->main_source, n_fanouts); + insert_lt_tree(tree, table, &fanout_info[p], source->main_source, source_polarity, 0, p, n_gaps); + insert_lt_tree(tree, table, &fanout_info[q], source->main_source, source_polarity, 0, q, n_gaps); + } else { + n_fanouts = get_n_fanouts(&fanout_info[p], table, source->main_source, source_polarity, 0, p, n_gaps); + fanout_tree_insert_gate(tree, source->main_source, n_fanouts + 1); + insert_lt_tree(tree, table, &fanout_info[p], source->main_source, source_polarity, 0, p, n_gaps); + buffer_polarity = (is_inverter(n_gates, source->buffer)) ? POLAR_INV(source_polarity) : source_polarity; + n_fanouts = get_n_fanouts(&fanout_info[q], table, source->buffer, buffer_polarity, 0, q, n_gaps); + fanout_tree_insert_gate(tree, source->buffer, n_fanouts); + insert_lt_tree(tree, table, &fanout_info[q], source->buffer, buffer_polarity, 0, q, n_gaps); + } + } else { + n_fanouts = get_n_fanouts(&fanout_info[p], table, source->main_source, source_polarity, 0, p, n_gaps); + fanout_tree_insert_gate(tree, source->main_source, n_fanouts); + insert_lt_tree(tree, table, &fanout_info[p], source->main_source, source_polarity, 0, p, n_gaps); + } +} + +static int get_n_fanouts(fanout_info, table, source_index, source_polarity, sink_index, sink_polarity, n_gaps) +opt_array_t *fanout_info; +multidim_t *table; +int source_index; +int source_polarity; +int sink_index; +int sink_polarity; +int n_gaps; +{ + lt_tree_t *entry; + + if (fanout_info->n_elts == sink_index) return 0; + entry = INDEX5P(lt_tree_t, table, source_index, source_polarity, sink_index, sink_polarity, n_gaps); + if (entry->balanced) return entry->two_level->n_gates; + if (fanout_info->n_elts == entry->sink_index) return entry->sink_index - sink_index; + return entry->sink_index - sink_index + 1; +} + + +static void insert_lt_tree(tree, table, fanout_info, source_index, source_polarity, sink_index, sink_polarity, n_gaps) +array_t *tree; +multidim_t *table; +opt_array_t *fanout_info; +int source_index; +int source_polarity; +int sink_index; +int sink_polarity; +int n_gaps; +{ + int n_fanouts; + lt_tree_t *entry; + int buffer_index; + int buffer_polarity; + int buffer_gaps; + + if (sink_index == fanout_info->n_elts) return; + entry = INDEX5P(lt_tree_t, table, source_index, source_polarity, sink_index, sink_polarity, n_gaps); + switch (entry->balanced) { + case 0: + noalg_insert_sinks(tree, fanout_info, sink_index, entry->sink_index); + buffer_index = entry->gate_index; + buffer_polarity = (is_inverter(n_gates, buffer_index)) ? POLAR_INV(source_polarity) : source_polarity; + buffer_gaps = (entry->sink_index == sink_index && buffer_polarity == sink_polarity) ? n_gaps - 1 : n_gaps; + if (entry->sink_index == fanout_info->n_elts) return; + sink_index = entry->sink_index; + n_fanouts = get_n_fanouts(fanout_info, table, buffer_index, buffer_polarity, sink_index, sink_polarity, buffer_gaps); + fanout_tree_insert_gate(tree, buffer_index, n_fanouts); + insert_lt_tree(tree, table, fanout_info, buffer_index, buffer_polarity, sink_index, sink_polarity, buffer_gaps); + break; + case 1: + insert_two_level_tree(tree, fanout_info, sink_index, source_index, entry->two_level); + break; + default: + fail("illegal value of field lt_tree_t.balanced"); + } +} diff --git a/sis/map/map.doc b/sis/map/map.doc new file mode 100644 index 0000000..aa5168a --- /dev/null +++ b/sis/map/map.doc @@ -0,0 +1,67 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/map.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)map.doc 1.2 */ +/* last modified on 5/1/91 at 15:52:15 */ + +network_t * +map_network(network, library, mode, inv_optz, fanout_flag) +network_t *network; +library_t *library; +double mode; +int inv_optz; +int fanout_flag; + + Implement 'network' using gates from library. Uses the + tree-based technology mapping algorithm. Returns NIL(network_t) + if any error, in which case error_string() contains a description + of what went wrong. + + If 'mode' is '0', the area will be minimized. + If 'mode' is '1', the delay will be minimized. + If 'mode' is '2', the delay will be minimized on an estimate of the + critical path obtained from a trivial 2-input nand mapping. + If 'mode' is between '0' and '1', then a linear combination of the area + and delay is minimized. + + Setting 'inv_optz' to '1' ('0'), enables (disables) the + inverter optimization + + 'fanout_flag' is a mask of 4 flags: [b0,b1,b2,b3]. b0 is the least + significant bit of the word. For example, if fanout_flag equals 3, + this means that b0 and b1 are on, b2 and b3 off. + Setting 'b0' means that the area at a fanout point is estimated + as being the area of the subtree divided by the number of fanouts. + Otherwise, the area is assumed to be 0 at a multiple fanout point. + Setting 'b1' means that the mapper is allowed to introduce overlaps + (i.e. logic duplication). + 'b2' is unused. + Setting 'b3' allows multiple fanouts within gates (i.e. for XOR's, MUX'es). + The default value is 11 in area mode and 9 in delay mode. + +void +map_add_inverter(network, add_at_pipo) +network_t *network; +int add_at_pipo; + Add extra inverters nodes to the network such that every pair + of nand gates is separated by 2 or more inverters. + + Setting 'add_at_pipo' to 1 enables the insertion also at primary inputs + and outputs. + + + +void +map_remove_inverter(network, report_data) +network_t *network; +VoidFn report_data; + Remove redundant inverters from the network while keeping the + network mapped. If report_data is not NIL, the routine reports + debugging information by calling the report_data function with the + network as an argument. diff --git a/sis/map/map.h b/sis/map/map.h new file mode 100644 index 0000000..de97dae --- /dev/null +++ b/sis/map/map.h @@ -0,0 +1,20 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/map.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)map.h 1.4 */ +/* last modified on 7/25/91 at 11:41:14 */ +#ifndef MAP_H +#define MAP_H +typedef void (*VoidFn)(); + +EXTERN network_t *map_network ARGS((network_t *, library_t *, double, int, int)); +EXTERN void map_add_inverter ARGS((network_t *, int)); +EXTERN void map_remove_inverter ARGS((network_t *, void (*)())); +EXTERN void map_network_dup ARGS((network_t *)); +#endif /* MAP_H */ diff --git a/sis/map/map_defs.h b/sis/map/map_defs.h new file mode 100644 index 0000000..27e86ef --- /dev/null +++ b/sis/map/map_defs.h @@ -0,0 +1,39 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/map_defs.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)map_defs.h 1.6 */ +/* last modified on 7/25/91 at 11:34:53 */ +/* + * $Log: map_defs.h,v $ + * Revision 1.1.1.1 2004/02/07 10:14:25 pchong + * imported + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 21:58:28 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:40:46 sis + * Initial revision + * + * Revision 1.1 91/07/02 11:13:59 touati + * Initial revision + * + */ + +#ifndef MAP_DEFS_H +#define MAP_DEFS_H + +#define FP_EQUAL(a,b) (ABS((a)-(b)) < .0001) +#define LARGE 0x7fffffff + +typedef int (*IntFunc)(); + +#endif /* MAP_DEFS_H */ diff --git a/sis/map/map_delay.c b/sis/map/map_delay.c new file mode 100644 index 0000000..c4477c1 --- /dev/null +++ b/sis/map/map_delay.c @@ -0,0 +1,314 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/map_delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)map_delay.c 1.6 */ +/* last modified on 7/8/91 at 14:47:03 */ +#include "sis.h" +#include <math.h> +#include "map_int.h" +#include "lib_int.h" +#include "map_macros.h" +#include "map_delay.h" +#include "fanout_delay.h" + +static double compute_fanout_load_correction(); +static void map_set_current_network(); +static void precompute_fanout_load_correction(); + +#define ARRIVAL(time, new_time) if (new_time > time) time = new_time; + +void delay_map_compute_required_times(nin, model, node_required, load, required) +int nin; +char **model; +delay_time_t node_required; +double load; +delay_time_t *required; +{ + register int i; + register delay_pin_t *pin_delay, **lib_delay_model; + delay_time_t delay; + + lib_delay_model = (delay_pin_t **) model; + for(i = nin-1; i >= 0; i--) { + pin_delay = lib_delay_model[i]; + delay.rise = pin_delay->block.rise + pin_delay->drive.rise * load; + delay.fall = pin_delay->block.fall + pin_delay->drive.fall * load; + + switch(pin_delay->phase) { + case PHASE_INVERTING: + required[i].rise = node_required.fall - delay.fall; + required[i].fall = node_required.rise - delay.rise; + break; + case PHASE_NONINVERTING: + required[i].rise = node_required.rise - delay.rise; + required[i].fall = node_required.fall - delay.fall; + break; + case PHASE_NEITHER: + required[i].rise = MIN(node_required.rise - delay.rise, node_required.fall - delay.fall); + required[i].fall = required[i].rise; + break; + default: + ; + } + } +} + + /* TREATMENT OF PRIMARY INPUTS / OUTPUTS */ + +#define MAX_PRECOMPUTED_FANOUT_LOADS 20 + +typedef struct { + lib_gate_t *default_inv; + delay_time_t arrival; + delay_time_t drive; + double load; + double load_limit; + delay_time_t required; + int required_not_set; + double fanout_loads[MAX_PRECOMPUTED_FANOUT_LOADS]; +} pipo_t; + +static pipo_t DEFAULT_PIPO_SETTINGS; +static pipo_t pipo_settings; +static network_t *map_current_network; +static bin_global_t global; + +static void map_set_current_network(network) +network_t *network; +{ + assert(network != NIL(network_t)); + map_current_network = network; +} + + /* if ignore_pipo_data is set, remove all delay info from the network except wire load */ + +void map_alloc_delay_info(network, options) +network_t *network; +bin_global_t *options; +{ + lsGen gen; + node_t *pi, *po; + + global = *options; + map_set_current_network(network); + pipo_settings = DEFAULT_PIPO_SETTINGS; + pipo_settings.default_inv = lib_get_default_inverter(); + pipo_settings.drive = delay_get_drive(pipo_settings.default_inv->delay_info[0]); + pipo_settings.load = delay_get_load(pipo_settings.default_inv->delay_info[0]); + pipo_settings.load_limit = delay_get_load_limit(pipo_settings.default_inv->delay_info[0]); +/* which one is better? + pipo_settings.load_limit = INFINITY; +*/ + if (global.ignore_pipo_data) { + delay_set_default_parameter(network, DELAY_DEFAULT_DRIVE_RISE, DELAY_NOT_SET); + delay_set_default_parameter(network, DELAY_DEFAULT_DRIVE_FALL, DELAY_NOT_SET); + delay_set_default_parameter(network, DELAY_DEFAULT_ARRIVAL_RISE, DELAY_NOT_SET); + delay_set_default_parameter(network, DELAY_DEFAULT_ARRIVAL_FALL, DELAY_NOT_SET); + delay_set_default_parameter(network, DELAY_DEFAULT_REQUIRED_RISE, DELAY_NOT_SET); + delay_set_default_parameter(network, DELAY_DEFAULT_REQUIRED_FALL, DELAY_NOT_SET); + delay_set_default_parameter(network, DELAY_DEFAULT_OUTPUT_LOAD, DELAY_NOT_SET); + delay_set_default_parameter(network, DELAY_ADD_WIRE_LOAD, DELAY_NOT_SET); + delay_set_default_parameter(network, DELAY_WIRE_LOAD_SLOPE, DELAY_NOT_SET); + foreach_primary_input(network, gen, pi) { + delay_set_parameter(pi, DELAY_DRIVE_RISE, DELAY_NOT_SET); + delay_set_parameter(pi, DELAY_DRIVE_FALL, DELAY_NOT_SET); + delay_set_parameter(pi, DELAY_ARRIVAL_RISE, DELAY_NOT_SET); + delay_set_parameter(pi, DELAY_ARRIVAL_FALL, DELAY_NOT_SET); + delay_set_parameter(pi, DELAY_MAX_INPUT_LOAD, DELAY_NOT_SET); + } + foreach_primary_output(network, gen, po) { + delay_set_parameter(po, DELAY_REQUIRED_RISE, DELAY_NOT_SET); + delay_set_parameter(po, DELAY_REQUIRED_FALL, DELAY_NOT_SET); + delay_set_parameter(po, DELAY_OUTPUT_LOAD, DELAY_NOT_SET); + } + } + + if (delay_get_default_parameter(network, DELAY_DEFAULT_DRIVE_RISE) == DELAY_NOT_SET) { + if (! global.no_warning) { + (void) fprintf(siserr, "WARNING: uses as primary %s the value ", "input drive"); + (void) fprintf(siserr, "(%2.2f,%2.2f)\n", pipo_settings.drive.rise, pipo_settings.drive.fall); + } + delay_set_default_parameter(network, DELAY_DEFAULT_DRIVE_RISE, pipo_settings.drive.rise); + delay_set_default_parameter(network, DELAY_DEFAULT_DRIVE_FALL, pipo_settings.drive.fall); + } else { + pipo_settings.drive.rise = delay_get_default_parameter(network, DELAY_DEFAULT_DRIVE_RISE); + pipo_settings.drive.fall = delay_get_default_parameter(network, DELAY_DEFAULT_DRIVE_FALL); + } + if (delay_get_default_parameter(network, DELAY_DEFAULT_ARRIVAL_RISE) == DELAY_NOT_SET) { + if (! global.no_warning) { + (void) fprintf(siserr, "WARNING: uses as primary %s the value ", "input arrival"); + (void) fprintf(siserr, "(%2.2f,%2.2f)\n", pipo_settings.arrival.rise, pipo_settings.arrival.fall); + } + delay_set_default_parameter(network, DELAY_DEFAULT_ARRIVAL_RISE, pipo_settings.arrival.rise); + delay_set_default_parameter(network, DELAY_DEFAULT_ARRIVAL_FALL, pipo_settings.arrival.fall); + } else { + pipo_settings.arrival.rise = delay_get_default_parameter(network, DELAY_DEFAULT_ARRIVAL_RISE); + pipo_settings.arrival.fall = delay_get_default_parameter(network, DELAY_DEFAULT_ARRIVAL_FALL); + } + if (delay_get_default_parameter(network, DELAY_DEFAULT_MAX_INPUT_LOAD) == DELAY_NOT_SET) { + if (! global.no_warning) { + (void) fprintf(siserr, "WARNING: uses as primary %s the value ", "input max load limit"); + (void) fprintf(siserr, "(%2.2f)\n", pipo_settings.load_limit); + } + delay_set_default_parameter(network, DELAY_DEFAULT_MAX_INPUT_LOAD, pipo_settings.load_limit); + } else { + pipo_settings.load_limit = delay_get_default_parameter(network, DELAY_DEFAULT_MAX_INPUT_LOAD); + } + if (delay_get_default_parameter(network, DELAY_DEFAULT_REQUIRED_RISE) == DELAY_NOT_SET) { + pipo_settings.required_not_set = 1; + if (! global.no_warning) { + (void) fprintf(siserr, "WARNING: uses as primary %s the value ", "output required"); + (void) fprintf(siserr, "(%2.2f,%2.2f)\n", pipo_settings.required.rise, pipo_settings.required.fall); + } + delay_set_default_parameter(network, DELAY_DEFAULT_REQUIRED_RISE, pipo_settings.required.rise); + delay_set_default_parameter(network, DELAY_DEFAULT_REQUIRED_FALL, pipo_settings.required.fall); + } else { + pipo_settings.required.rise = delay_get_default_parameter(network, DELAY_DEFAULT_REQUIRED_RISE); + pipo_settings.required.fall = delay_get_default_parameter(network, DELAY_DEFAULT_REQUIRED_FALL); + } + if (delay_get_default_parameter(network, DELAY_DEFAULT_OUTPUT_LOAD) == DELAY_NOT_SET) { + if (! global.no_warning) { + (void) fprintf(siserr, "WARNING: uses as primary %s the value ", "output load"); + (void) fprintf(siserr, "%2.2f\n", pipo_settings.load); + } + delay_set_default_parameter(network, DELAY_DEFAULT_OUTPUT_LOAD, pipo_settings.load); + } else { + pipo_settings.load = delay_get_default_parameter(network, DELAY_DEFAULT_OUTPUT_LOAD); + } + fanout_delay_init(options); + precompute_fanout_load_correction(); +} + +void map_free_delay_info() +{ + fanout_delay_end(); +} + +void pipo_set_default_po_required(default_value) +delay_time_t default_value; +{ + if (pipo_settings.required_not_set) { + pipo_settings.required = default_value; + if (! global.no_warning) { + (void) fprintf(siserr, "WARNING: uses as primary %s the value ", "output required"); + (void) fprintf(siserr, "(%2.2f,%2.2f)\n", pipo_settings.required.rise, pipo_settings.required.fall); + } + delay_set_default_parameter(map_current_network, DELAY_DEFAULT_REQUIRED_RISE, pipo_settings.required.rise); + delay_set_default_parameter(map_current_network, DELAY_DEFAULT_REQUIRED_FALL, pipo_settings.required.fall); + } +} + +delay_time_t pipo_get_pi_arrival(node) +node_t *node; +{ + delay_time_t arrival; + if (delay_get_pi_arrival_time(node, &arrival)) return arrival; + return pipo_settings.arrival; +} + +delay_time_t pipo_get_pi_drive(node) +node_t *node; +{ + delay_time_t drive; + if (delay_get_pi_drive(node, &drive)) return drive; + return pipo_settings.drive; +} + +double pipo_get_pi_load_limit(node) +node_t *node; +{ + double load_limit; + if (delay_get_pi_load_limit(node, &load_limit)) return load_limit; + return pipo_settings.load_limit; +} + +delay_time_t pipo_get_po_required(node) +node_t *node; +{ + delay_time_t required; + if (delay_get_po_required_time(node, &required)) return required; + return pipo_settings.required; +} + +double pipo_get_po_load(node) +node_t *node; +{ + double load; + if (delay_get_po_load(node, &load)) return load; + return pipo_settings.load; +} + + /* should be in delay/delay.c really */ + +pin_phase_t delay_get_polarity(pin_delay) +char *pin_delay; +{ + return ((delay_pin_t *) pin_delay)->phase; +} + +double map_compute_wire_load(n_fanouts) +int n_fanouts; +{ + return compute_wire_load(map_current_network, n_fanouts); +} + + + /* used in bin_delay.c as a heuristic to estimate the load */ + /* at a multiple fanout point */ + +double map_compute_fanout_load_correction(n_fanouts) +int n_fanouts; +{ + assert(n_fanouts > 0); + if (n_fanouts < MAX_PRECOMPUTED_FANOUT_LOADS) return pipo_settings.fanout_loads[n_fanouts]; + return compute_fanout_load_correction(n_fanouts); +} + +static void precompute_fanout_load_correction() +{ + int i; + + for (i = 1; i < MAX_PRECOMPUTED_FANOUT_LOADS; i++) { + pipo_settings.fanout_loads[i] = compute_fanout_load_correction(i); + } +} + + /* ignore, for the moment, wire loads. Because the entire tree mapper ignore them */ + +static double compute_fanout_load_correction(n_fanouts) +int n_fanouts; +{ + int buffer_index; + double buffer_load; + double total_load; + int n_buffers; + double buffered_load; + + buffer_index = fanout_delay_get_buffer_index(pipo_settings.default_inv); + buffer_load = fanout_delay_get_buffer_load(buffer_index); + switch (global.load_estimation) { + case 0: + total_load = 0.0; + break; + case 1: + total_load = n_fanouts * buffer_load; + break; + case 2: + total_load = n_fanouts * buffer_load; + n_buffers = compute_best_number_of_inverters(buffer_index, buffer_index, total_load, n_fanouts); + buffered_load = n_buffers * buffer_load; + total_load = MIN(total_load, buffered_load); + break; + default: + (void) fprintf(siserr, "unrecognized value of global.load_estimation: %d\n", global.load_estimation); + fail(""); + break; + } + return total_load; +} diff --git a/sis/map/map_delay.h b/sis/map/map_delay.h new file mode 100644 index 0000000..f5c8e16 --- /dev/null +++ b/sis/map/map_delay.h @@ -0,0 +1,33 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/map_delay.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)map_delay.h 1.3 */ +/* last modified on 7/1/91 at 22:42:29 */ +#ifndef MAP_DELAY_H +#define MAP_DELAY_H + +extern void delay_map_compute_required_times(); +extern void delay_gate_arrival_times(); /* similar to delay_gate_simulate but faster for several loads */ +extern void delay_compute_pin_delays(); + +extern void map_alloc_delay_info(/* network, bin_global_t *options */); +extern void map_free_delay_info(/* */); +extern delay_time_t pipo_get_pi_arrival(/* node_t *node */); +extern delay_time_t pipo_get_pi_drive(/* node_t *node */); +extern delay_time_t pipo_get_po_required(/* node_t *node */); +extern double pipo_get_po_load(/* node_t *node */); +extern double pipo_get_pi_load_limit(/* node_t *node */); +extern void pipo_set_default_po_required(/* delay_time_t value */); +extern double map_compute_wire_load(/* int n_fanouts */); +extern double map_compute_fanout_load_correction(/* int n_fanouts, bin_global_t *options */); + + /* should be put in delay/delay.h */ +extern pin_phase_t delay_get_polarity(/* char *pin_delay */); + +#endif diff --git a/sis/map/map_int.h b/sis/map/map_int.h new file mode 100644 index 0000000..8432edb --- /dev/null +++ b/sis/map/map_int.h @@ -0,0 +1,255 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/map_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)map_int.h 1.11 */ +/* last modified on 8/8/91 at 17:02:06 */ +/* + * $Log: map_int.h,v $ + * Revision 1.1.1.1 2004/02/07 10:14:25 pchong + * imported + * + * Revision 1.4 22/.0/.1 .0:.4:.5 sis + * Updates for the Alpha port. + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 21:59:58 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:40:48 sis + * Initial revision + * + * Revision 1.2 91/07/02 11:16:50 touati + * make copies of MAP(node)->arrival_info instead of pointers: safer. + * add support for load_limit. + * add option for gate resizing. + * + * Revision 1.1 91/06/28 22:50:15 touati + * Initial revision + * + */ +#ifndef MAP_INT_H +#define MAP_INT_H + +#include "map_defs.h" +#include "lib_int.h" + +typedef struct prim_struct prim_t; +typedef struct prim_node_struct prim_node_t; +typedef struct prim_edge_struct prim_edge_t; + +typedef enum edge_dir_enum edge_dir_t; +enum edge_dir_enum {DIR_IN, DIR_OUT}; + +struct prim_struct { + int ninputs; + prim_node_t **inputs; /* direct pointers to primitive inputs */ + int noutputs; + prim_node_t **outputs; /* direct pointers to primitive outputs */ + prim_node_t *nodes; /* linked list of nodes for the primitive */ + prim_edge_t *edges; /* linked list of edge for the primitive */ + lsList gates; + char *data; /* just a hook to pass additional data */ +#ifdef SIS + int latch_type; /* sequential support */ +#endif +}; + + +struct prim_node_struct { + char *name; /* name of node (inputs and outputs only) */ + unsigned isomorphic_sons:1; + unsigned nfanin:15; + unsigned nfanout:15; + node_type_t type; + node_t *binding; /* used during matching: binding for node */ + prim_node_t *next; /* linked list of nodes */ +#ifdef SIS + unsigned latch_output:1; /* sequential support */ +#endif +}; + + +struct prim_edge_struct { + prim_node_t *this_node; + prim_node_t *connected_node; + edge_dir_t dir; + prim_edge_t *next; /* linked list of edges */ +}; + +typedef enum { + RAW_NETWORK, + ANNOTATED_NETWORK, + MAPPED_NETWORK, + INCONSISTENT_NETWORK, + EMPTY_NETWORK, + UNKNOWN_TYPE +} network_type_t; + +typedef struct { + node_t *pin_source; /* if pin source has multiple fanout; otherwise NIL(node_t) */ + int fanout_index; /* index of fanout of that pin source */ +} fanin_fanout_t; + +#if defined(_IBMR2) || defined(__osf__) +typedef struct alt_map_struct alt_map_t; +struct alt_map_struct { +#else +typedef struct map_struct map_t; +struct map_struct { +#endif + lib_gate_t *gate; /* best gate which matches */ + prim_node_t *binding; /* used during matching */ + node_t *match_node; /* used to re-build the graph */ + int ninputs; /* number of inputs for this gate */ + node_t **save_binding; /* bindings for the gate inputs */ + delay_time_t *arrival_info; /* copy of arrival times of inputs. used in fanout opt (array of size ninputs) */ + double map_area; /* current area cost function */ + delay_time_t map_arrival; /* current arrival time cost function */ + double load; /* record load on this pin (from last map) */ + int slack_is_critical; /* slack at node is 'critical' */ + int inverter_paid_for; + delay_time_t inverter_arrival; + int index; + delay_time_t required; + st_table *gate_link; /* used in bin_delay_build_network: bindings gate input -> gate root */ + st_generator *gen; /* to be used in conjunction with gate_link */ + node_t *node_y; /* used in bin_power.c to cache information */ + array_t *fanout_tree; + node_t *fanout_source; + fanin_fanout_t *pin_info; /* only allocated when necessary */ +}; + + /* to pass options */ + +typedef struct bin_global_struct bin_global_t; +struct bin_global_struct { + int new_mode; /* new_mode */ + double new_mode_value; /* 0.0->area ... 1.0->delay */ + int load_bins_count; /* for newmap delay and area/delay */ + int delay_bins_count; /* for newmap area/delay */ + double old_mode; /* old map; area or delay optimize */ + int inverter_optz; /* inverter optimization heuristics */ + int allow_internal_fanout; /* degrees of internal fanouts allowed */ + int print_stat; /* print area/delay stats at the end */ + int verbose; /* verbosity level */ + int raw; /* raw mapping */ + double thresh; /* threshold used in old tree mapper */ + library_t *library; /* current library */ + int fanout_optimize; /* if set, the fanout optimizer is called */ + int area_recover; /* if set, area is recovered after fanout opt */ + int peephole; /* if set, call fanout peephole optimizer */ + array_t *fanout_alg; /* array of fanout algorithm descriptors */ + int remove_inverters; /* if set, remove redundant inverters after mapping */ + int no_warning; /* if set, does not print any warning message */ + int ignore_pipo_data; /* if set, ignore specific values set at PIPO's */ + network_type_t network_type; /* type of the network when mapping is started */ + int load_estimation; /* 0-ignore fanout; 1-linear fanout; 2-load of two-level tree */ + int ignore_polarity; /* 0-add an inverter delay; 1-same arrival time for both polarities */ + int cost_function; /* 0-MAX(rise,fall); 1-AVER(rise,fall) */ + int n_iterations; /* 0-do it once, 1-repeat once, etc... */ + int fanout_iterate; /* 1 if tree covering is going to be called afterwards; 0 otherwise */ + int opt_single_fanout; /* 0/1 */ + int fanout_log_on; /* 0/1 */ + int allow_duplication; /* 0/1 */ + int fanout_limit; /* limit fanout of internal nodes during matching */ + int check_load_limit; /* if set, check fanout limit during fanout opt */ + int penalty_factor; /* if check_load_limit set, load exceeding gate limit is multiplied by penalty_factor */ + int all_gates_area_recover; /* when set, recover area on all gates, not only buffers */ +}; + +typedef struct match_struct match_t; +struct match_struct { + int ninputs; + int noutputs; + node_t **inputs; + node_t **outputs; + prim_t *prim; + lib_gate_t *gate; +}; + + +#define MAP_SLOT map +#if defined(_IBMR2) || defined(__osf__) +#define MAP(node) ((alt_map_t *) (node)->MAP_SLOT) +#else +#define MAP(node) ((map_t *) (node)->MAP_SLOT) +#endif + +#ifdef SIS +#define IS_LATCH_END(node) (network_latch_end((node))!=NIL(node_t)) +#endif + +extern void map_network_dup(); +extern int map_network_to_prim(); +extern st_table *map_find_isomorphisms(); +extern void prim_free(); +extern void prim_clear_binding(); +extern void map_prim_dump(); +extern int tree_map(); +extern void map_print_tree_size(); +extern node_t *map_prim_get_root(); +extern void map_alloc(), map_free(), map_invalid(); +extern void map_dup(), map_setup_network(); +extern void gen_all_matches(); +extern int map_check_form(); +extern int do_tree_premap(); +extern void map_prep(); +extern void patch_constant_cells(); +extern network_t *map_build_network (); +extern lib_gate_t *choose_smallest_gate(); +extern lib_gate_t *choose_nth_smallest_gate(); +extern node_t *map_po_get_fanin(); + + /* EXPORTED FROM "com_map.c" */ +extern int map_fill_options(); + + /* EXPORTED FROM "bin_delay.c" */ +extern int bin_delay_tree_match(); +extern int bin_delay_area_tree_match(); +extern void bin_for_all_nodes_inputs_first(/* network_t *network; VoidFn fn; */); +extern void bin_for_all_nodes_outputs_first(/* network_t *network;VoidFn fn; */); + + /* EXPORTED FROM "treemap.c" */ +extern network_t *do_old_tree_match(); +#ifdef SIS +extern int seq_filter(); +#endif /* SIS */ + + /* map_interface.c */ +extern network_t *complete_map_interface(); +extern network_t *build_mapped_network_interface(); +extern network_t *tree_map_interface(); +extern network_t *fanout_opt_interface(); +extern network_type_t map_get_network_type(/* network_t *network */); +extern void map_report_node_data(/* node_t *node */); +extern network_t *map_premap_network(); +extern void map_report_data_mapped(); + + /* from replace.c */ +extern void replace_2or(); + +#define is_tree_leaf(node) \ + (node->type == PRIMARY_INPUT || node_num_fanout(node) > 1) + +#define match_is_inverter(node, prim) \ + (prim->ninputs == 1 && prim->inputs[0]->binding == node_get_fanin(node, 0)) + +#define best_match_is_inverter(node) \ + (MAP(node)->ninputs == 1 && \ + MAP(node)->save_binding[0] == node_get_fanin(node, 0)) + +#ifdef SIS +extern int network_gate_type(); +extern node_t *network_latch_input(); +extern st_table *network_type_table; +#endif /* SIS */ + +#endif diff --git a/sis/map/map_interface.c b/sis/map/map_interface.c new file mode 100644 index 0000000..a067323 --- /dev/null +++ b/sis/map/map_interface.c @@ -0,0 +1,700 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/map_interface.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)map_interface.c 1.7 */ +/* last modified on 7/31/91 at 13:01:20 */ +#include "sis.h" +#include <math.h> +#include "map_macros.h" +#include "map_int.h" +#include "lib_int.h" +#include "map_delay.h" +#include "fanout_int.h" + +#include "map_interface_static.h" + + /* EXTERNAL INTERFACE */ + + /* takes a network and maps it. Ignores the state of the network (ANNOTATED, MAPPED, etc...) */ + +network_t *complete_map_interface(network, options) +network_t *network; +bin_global_t *options; +{ + int ok_status; + network_t *result; + network_type_t type; + library_t *library = options->library; + + error_init(); + + if (! map_check_library(network, options)) { + return NIL(network_t); + } + + options->network_type = type = map_get_network_type(network); + switch (type) { + case RAW_NETWORK: + break; + case ANNOTATED_NETWORK: + case MAPPED_NETWORK: + unmap_network(network, options); + break; + case EMPTY_NETWORK: + return NIL(network_t); + default: + error_append("map_interface: bad network type\n"); + return NIL(network_t); + } + + /* remove unnecessary nodes */ + network_csweep(network); + + /* initialize things properly for delay */ + map_alloc_delay_info(network, options); + + /* initialize the network */ + if (! map_premap_network(network, options)) { + error_append("map_interface: can't premap the network\n"); + map_free_delay_info(); + return NIL(network_t); + } + + /* perform tree mapping */ + if (options->n_iterations > 0) { + if (options->new_mode != 1 && ! FP_EQUAL(options->new_mode_value, 1.0)) { + error_append("map_interface: can't iterate any other option than '-n 1'\n"); + map_free_delay_info(); + return NIL(network_t); + } + options->fanout_optimize = 1; + options->area_recover = 0; + options->fanout_iterate = 1; + options->opt_single_fanout = 1; + options->fanout_log_on = 1; + while (options->n_iterations > 0) { + (void) bin_delay_tree_match(network, library, *options); + map_remove_unnecessary_annotations(network); + map_report_data_annotated(network, options); + options->ignore_polarity = 0; + fanout_optimization(network, *options); + map_remove_unnecessary_annotations(network); + map_report_data_annotated(network, options); + fanout_log_cleanup_network(network); + options->n_iterations--; + } + options->area_recover = 1; + options->fanout_iterate = 0; + options->opt_single_fanout = 1; + options->fanout_log_on = 0; + (void) bin_delay_tree_match(network, library, *options); + map_remove_unnecessary_annotations(network); + map_report_data_annotated(network, options); + fanout_optimization(network, *options); + } else { + if (options->new_mode == 0) { /* status == 1 iff everything is OK */ + ok_status = tree_map(network, library, *options); + } else if (FP_EQUAL(options->new_mode_value, 1.0)) { + ok_status = bin_delay_tree_match(network, library, *options); + } else { + ok_status = bin_delay_area_tree_match(network, library, *options); + } + if (! ok_status) { + error_append("map_interface: can't treemap the network\n"); + map_free_delay_info(); + return NIL(network_t); + } + if (options->fanout_optimize) fanout_optimization(network, *options); + } + result = build_network_from_annotations(network, options); + map_free_delay_info(); + return result; + +} + + /* this routine takes an annotated network and maps it */ + /* it also performs a basic consistency check for robustness */ + +network_t *build_mapped_network_interface(network, options) +network_t *network; +bin_global_t *options; +{ + network_type_t type; + + error_init(); + options->network_type = type = map_get_network_type(network); + if (type != ANNOTATED_NETWORK) { + error_append("build_annotated_network: expects an ANNOTATED network\n"); + return NIL(network_t); + } + return build_network_from_annotations(network, options); +} + +/* takes a RAW or an ANNOTATED network and returns an ANNOTATED network */ + /* only do tree mapping */ + +network_t *tree_map_interface(network, options) +network_t *network; +bin_global_t *options; +{ + int ok_status; + network_type_t type; + library_t *library = options->library; + + error_init(); + options->network_type = type = map_get_network_type(network); + switch (type) { + case RAW_NETWORK: + case ANNOTATED_NETWORK: + break; + case MAPPED_NETWORK: + error_append("map_interface: network is already mapped\n"); + return NIL(network_t); + case EMPTY_NETWORK: + return NIL(network_t); + default: + error_append("map_interface: bad network type\n"); + return NIL(network_t); + } + + /* initialize things properly for delay */ + map_alloc_delay_info(network, options); + + /* initialize the network */ + if (type == RAW_NETWORK) { + if (! map_premap_network(network, options)) { + error_append("map_interface: can't premap the network\n"); + return NIL(network_t); + } + } + + /* if ANNOTATED, only authorize '-n 1' for the moment: the others won't work */ + if (type == ANNOTATED_NETWORK) { + if (options->new_mode == 0 || (options->new_mode == 1 && ! FP_EQUAL(options->new_mode_value, 1.0))) { + if (! options->no_warning) + (void) fprintf(sisout, "WARNING: only '_tree_map -n 1' supported after fanout opt\n"); + options->new_mode = 1; + options->new_mode_value = 1.0; + } + } + + /* do the tree mapping */ + if (options->new_mode == 0) { /* status == 1 iff everything is OK */ + ok_status = tree_map(network, library, *options); + } else if (FP_EQUAL(options->new_mode_value, 1.0)) { + ok_status = bin_delay_tree_match(network, library, *options); + } else { + ok_status = bin_delay_area_tree_match(network, library, *options); + } + if (! ok_status) { + error_append("map_interface: can't treemap the network\n"); + return NIL(network_t); + } + + /* cleanup annotations */ + map_remove_unnecessary_annotations(network); + map_report_data_annotated(network, options); + + /* free delay info storage */ + map_free_delay_info(); + + return network; +} + + /* takes an ANNOTATED network and returns an ANNOTATED network */ + /* performs fanout optimization and, if specified, area recovery */ + +network_t *fanout_opt_interface(network, options) +network_t *network; +bin_global_t *options; +{ + network_type_t type; + + error_init(); + type = map_get_network_type(network); + if (type == EMPTY_NETWORK) return NIL(network_t); + if (type != ANNOTATED_NETWORK) { + error_append("fanout_opt_interface: expects an annotated network\n"); + return NIL(network_t); + } + + /* initialize things properly for delay */ + map_alloc_delay_info(network, options); + + fanout_optimization(network, *options); + map_remove_unnecessary_annotations(network); + map_report_data_annotated(network, options); + + /* free delay info storage */ + map_free_delay_info(); + + return network; +} + + /* returns the type of a network */ + +network_type_t map_get_network_type(network) +network_t *network; +{ + int is_mapped = 1; + int is_annotated = 1; + int all_constants = 1; + lsGen gen; + node_t *node; +#ifdef SIS + latch_t *latch; +#endif /* SIS */ + + if (network == NIL(network_t)) return EMPTY_NETWORK; + /* Hack: if all the internal nodes in a network are constants, return + RAW_NETWORK. */ + foreach_node(network, gen, node) { + if (node->type == INTERNAL) { + if (node_num_fanin(node) == 0) continue; /* handle the case of constants */ + all_constants = 0; + if (MAP(node) == 0) { + is_mapped = is_annotated = 0; + (void) lsFinish(gen); + break; + } else if (MAP(node)->gate == NIL(lib_gate_t)) { + is_mapped = 0; + } else if (MAP(node)->gate != NIL(lib_gate_t) && MAP(node)->save_binding == NIL(node_t *)) { + is_annotated = 0; + } else if (MAP(node)->gate != NIL(lib_gate_t) && MAP(node)->save_binding != NIL(node_t *)) { + is_mapped = 0; + } + } + } + if (all_constants) return RAW_NETWORK; +#ifdef SIS + foreach_latch(network, gen, latch) { + if (latch_get_gate(latch) == NIL(lib_gate_t)) { + is_mapped = 0; + } + node = latch_get_input(latch); + if (node_num_fanin(node) == 0 || + lib_gate_of(node_get_fanin(node, 0)) == NIL(lib_gate_t)) { + is_annotated = 0; + } + } +#endif /* SIS */ + if (is_mapped) return MAPPED_NETWORK; + if (is_annotated) return ANNOTATED_NETWORK; + return RAW_NETWORK; +} + + /* INTERNAL INTERFACE */ + + /* decompose into 2-input NAND gates if needed */ + /* add inverters if required */ + /* and premap with 2-input NAND gates */ + +network_t *map_premap_network(network, options) +network_t *network; +bin_global_t *options; +{ + library_t *library = options->library; + + /* If not 'raw' mapping, get it into 2-input nand gate form */ + if (! options->raw) { + map_prep(network, library); + } else { + add_inv_network(network); + } + + /* make sure it is the correct form */ + if (! map_check_form(network, library->nand_flag)) { + return NIL(network_t); + } + + /* add redundant inverters: should be consistent with the library */ + if (library->add_inverter) { + map_add_inverter(network, /* add_at_pipo */ 1); + } + + /* make sure there's at most 1 0-cell and 1 1-cell */ + patch_constant_cells(network); + + /* pre-map the circuit */ + if (! do_tree_premap(network, library)) { + return NIL(network_t); + } + return network; +} + + /* takes an ANNOTATED network, builds it, removes inverters if necessary */ + /* and report stats if required */ + +static network_t *build_network_from_annotations(network, options) +network_t *network; +bin_global_t *options; +{ + network_t *new_network = map_build_network(network); + + if (options->remove_inverters) { + if (options->print_stat) { + map_remove_inverter(new_network, map_report_data_mapped); + } else { + map_remove_inverter(new_network, (VoidFn) 0); + } + } + if (options->print_stat) map_report_data_mapped(new_network); + return new_network; +} + + /* traverse the network from PO to PI through the virtual network */ + /* and record all the nodes encountered there */ + /* unmap the others */ + +static void map_remove_unnecessary_annotations(network) +network_t *network; +{ + lsGen gen; + node_t *node, *fanin, *output; + st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); + + foreach_primary_output(network, gen, output) { + st_insert(visited, (char *) output, NIL(char)); + fanin = map_po_get_fanin(output); + visit_mapped_nodes(fanin, visited); + } + /* all nodes that would not appear in the mapping are reset */ + foreach_node(network, gen, node) { + if (st_lookup(visited, (char *) node, NIL(char *))) continue; + MAP(node)->gate = NIL(lib_gate_t); + MAP(node)->ninputs = 0; + FREE(MAP(node)->save_binding); + MAP(node)->save_binding = NIL(node_t *); + gate_link_delete_all(node); + } + st_free_table(visited); +} + +static void visit_mapped_nodes(node, visited) +node_t *node; +st_table *visited; +{ + int i; + node_function_t node_fn; + char **slot; + + if (st_find_or_add(visited, (char *) node, (char ***) &slot)) return; + *slot = NIL(char); + node_fn = node_function(node); + if (node_fn == NODE_PI || node_fn == NODE_0 || node_fn == NODE_1) return; + assert(MAP(node)->save_binding != NIL(node_t *)); + for (i = 0; i < MAP(node)->ninputs; i++) { + visit_mapped_nodes(MAP(node)->save_binding[i], visited); + } +} + +void map_report_data_mapped(network) +network_t *network; +{ + node_t *node; + lsGen gen; + + assert(delay_trace(network, DELAY_MODEL_LIBRARY)); + + foreach_primary_output(network, gen, node) { + MAP(node)->map_arrival = delay_arrival_time(node); + } + map_report_data(network); +} + + + /* the network should have been cleaned up before calling this routine */ + /* every gate is considered part of the final circuit */ + +static void map_report_data_annotated(network, options) +network_t *network; +bin_global_t *options; +{ + if (! options->print_stat) return; + map_compute_annotated_arrival_times(network, options); + if (options->verbose > 1) { + int i; + node_t *node; + array_t *nodevec = network_dfs(network); + + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + map_report_node_data(node); + } + array_free(nodevec); + } + map_report_data(network); +} + +static void map_report_data(network) +network_t *network; +{ + node_t *node; + lsGen gen; + double area = 0.0; + int n_failing_outputs; + delay_time_t arrival, required, slack; + delay_time_t max_slack, min_slack, sum_slack, max_arrival; + + n_failing_outputs = 0; + max_slack = MINUS_INFINITY; + min_slack = PLUS_INFINITY; + sum_slack = ZERO_DELAY; + max_arrival = MINUS_INFINITY; + + foreach_primary_output(network, gen, node) { + arrival = MAP(node)->map_arrival; + required = pipo_get_po_required(node); + SETSUB(slack, required, arrival); + if (GETMIN(slack) < 0) { + n_failing_outputs++; + sum_slack.rise += (slack.rise < 0) ? slack.rise : 0.0; + sum_slack.fall += (slack.fall < 0) ? slack.fall : 0.0; + } + SETMAX(max_slack, max_slack, slack); + SETMIN(min_slack, min_slack, slack); + SETMAX(max_arrival, max_arrival, arrival); + } + + foreach_node(network, gen, node) { + if (MAP(node)->gate != NIL(lib_gate_t)) { + area += lib_gate_area(MAP(node)->gate); + } + } + (void) fprintf(sisout, "# of outputs: %d\n", network_num_po(network)); + (void) fprintf(sisout, "total gate area: %2.2f\n", area); + (void) fprintf(sisout, "maximum arrival time: (%2.2f,%2.2f)\n", max_arrival.rise, max_arrival.fall); + (void) fprintf(sisout, "maximum po slack: (%2.2f,%2.2f)\n", max_slack.rise, max_slack.fall); + (void) fprintf(sisout, "minimum po slack: (%2.2f,%2.2f)\n", min_slack.rise, min_slack.fall); + (void) fprintf(sisout, "total neg slack: (%2.2f,%2.2f)\n", sum_slack.rise, sum_slack.fall); + (void) fprintf(sisout, "# of failing outputs: %d\n", n_failing_outputs); +} + + /* ARGSUSED */ +static void map_compute_annotated_arrival_times(network, options) +network_t *network; +bin_global_t *options; +{ + lsGen gen; + node_t *output, *fanin; + st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); + + map_compute_loads(network); + visited = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_output(network, gen, output) { + fanin = map_po_get_fanin(output); + virtual_delay_arrival_times_rec(visited, fanin); + MAP(output)->map_arrival = MAP(fanin)->map_arrival; + } + st_free_table(visited); +} + +static void map_compute_loads(network) +network_t *network; +{ + int i, j; + lsGen gen; + node_t *fanin, *node; + array_t *nodevec = network_dfs_from_input(network); + + foreach_node(network, gen, node) { + MAP(node)->load = 0.0; + } + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type == PRIMARY_OUTPUT) { + MAP(node)->load = pipo_get_po_load(node); + fanin = map_po_get_fanin(node); + MAP(fanin)->load += MAP(node)->load; + } else if (MAP(node)->gate == NIL(lib_gate_t)) { + /* do nothing */ + } else if (strcmp(MAP(node)->gate->name, "**wire**") == 0) { + fanin = MAP(node)->save_binding[0]; + MAP(fanin)->load += MAP(node)->load; + } else { + for (j = 0; j < MAP(node)->ninputs; j++) { + fanin = MAP(node)->save_binding[j]; + MAP(fanin)->load += delay_get_load(MAP(node)->gate->delay_info[j]); + } + } + } + array_free(nodevec); +} + + /* when calling the mapper on a mapped or annotated network directly */ + /* without using _fanout_opt or _tree_map the network is cleaned up of any */ + /* existing mapping info and the mapping is redone from scratch */ + /* actually nothing to do: map_alloc will simply free the MAP entry */ + /* if there is one */ + + /* ARGSUSED */ +static void unmap_network(network, options) +network_t *network; +bin_global_t *options; +{ + options->network_type = RAW_NETWORK; +} + +void map_report_node_data(node) +node_t *node; +{ + int i; + node_t *fanin; + delay_time_t arrival; + + if (node->type == INTERNAL && MAP(node)->gate == NIL(lib_gate_t)) return; + (void) fprintf(sisout, "node %s ", node->name); + arrival = MAP(node)->map_arrival; + (void) fprintf(sisout, "l(%2.3f) a(%2.3f,%2.3f) ", MAP(node)->load, arrival.rise, arrival.fall); + switch (node->type) { + case PRIMARY_INPUT: + (void) fprintf(sisout, "PI\n"); + break; + case PRIMARY_OUTPUT: + if (node_num_fanin(node) > 0) { + fanin = map_po_get_fanin(node); + (void) fprintf(sisout, "PO -> %s\n", fanin->name); + } else { + (void) fprintf(sisout, "PO\n"); + } + break; + case INTERNAL: + (void) fprintf(sisout, "%s -> ", MAP(node)->gate->name); + for (i = 0; i < MAP(node)->ninputs; i++) { + fanin = MAP(node)->save_binding[i]; + (void) fprintf(sisout, "%s ", fanin->name); + } + (void) fprintf(sisout, "\n"); + break; + default: + ; + } +} + +/* check library for completeness */ +static int +map_check_library(network, options) +network_t *network; +bin_global_t *options; +{ + library_t *library = options->library; + lib_gate_t *gate; + +#ifdef SIS + latch_t *latch; + lib_gate_t *d_ff_rising, *d_ff_falling; + lib_gate_t *d_latch_high, *d_latch_low; + lib_gate_t *d_asynch; + lsGen gen; + latch_synch_t default_type; +#endif /* SIS */ + + gate = choose_smallest_gate(library, "f=!a;"); + if (gate == NIL(lib_gate_t)) { + error_append("library_error: no inverter in the library\n"); + return 0; + } + gate = choose_smallest_gate(library, "f=!(a*b);"); + if (gate == NIL(lib_gate_t)) { + gate = choose_smallest_gate(library, "f=!(a+b);"); + if (gate == NIL(lib_gate_t)) { + gate = choose_smallest_gate(library, "f=a*b;"); + if (gate == NIL(lib_gate_t)) { + gate = choose_smallest_gate(library, "f=a+b;"); + if (gate == NIL(lib_gate_t)) { + error_append("library error: no 2-input nand in the library\n"); + return 0; + } + } + } + } + gate = choose_smallest_gate(library, "f=0;"); + if (gate == NIL(lib_gate_t)) { + error_append("library error: no constant 0 cell in the library\n"); + return 0; + } + gate = choose_smallest_gate(library, "f=1;"); + if (gate == NIL(lib_gate_t)) { + error_append("library error: no constant 1 cell in the library\n"); + return 0; + } + +#ifdef SIS + d_ff_rising = lib_choose_smallest_latch(library, "q=d;", RISING_EDGE); + d_ff_falling = lib_choose_smallest_latch(library, "q=d;", FALLING_EDGE); + d_latch_high = lib_choose_smallest_latch(library, "q=d;", ACTIVE_HIGH); + d_latch_low = lib_choose_smallest_latch(library, "q=d;", ACTIVE_LOW); + d_asynch = lib_choose_smallest_latch(library, "q=d;", ASYNCH); + + if (d_ff_rising != NIL(lib_gate_t)) default_type = RISING_EDGE; + else if (d_ff_falling != NIL(lib_gate_t)) default_type = FALLING_EDGE; + else if (d_latch_high != NIL(lib_gate_t)) default_type = ACTIVE_HIGH; + else if (d_latch_low != NIL(lib_gate_t)) default_type = ACTIVE_LOW; + else if (d_asynch != NIL(lib_gate_t)) default_type = ASYNCH; + else default_type = UNKNOWN; + + /* check if there are appropriate FFs/latches in the library */ + foreach_latch(network, gen, latch) { + switch (latch_get_type(latch)) { + case UNKNOWN: + if (default_type == UNKNOWN) { + error_append("library error: no D-type flip-flops/latches/delays in the library\n"); + goto error_return; + } else { + if (! options->no_warning) { + (void) fprintf(siserr, "warning: unknown latch type at node '%s' (%s assumed)\n", + node_name(latch_get_input(latch)), + (default_type == RISING_EDGE)?"RISING_EDGE": + (default_type == FALLING_EDGE)?"FALLING_EDGE": + (default_type == ACTIVE_HIGH)?"ACTIVE_HIGH": + (default_type == ACTIVE_LOW)?"ACTIVE_LOW":"ASYNCH"); + } + latch_set_type(latch, default_type); + } + break; + + case RISING_EDGE: + case FALLING_EDGE: + if (d_ff_rising == NIL(lib_gate_t) && d_ff_falling == NIL(lib_gate_t)) { + error_append("library error: no D-type edge-triggered flip-flops in the library\n"); + goto error_return; + } + break; + + case ACTIVE_HIGH: + case ACTIVE_LOW: + if (d_latch_high == NIL(lib_gate_t) && d_latch_low == NIL(lib_gate_t)) { + error_append("library error: no D-type transparent latches in the library\n"); + goto error_return; + } + break; + + case ASYNCH: + if (d_asynch == NIL(lib_gate_t)) { + if (! options->no_warning) { + (void)fprintf(siserr,"warning: no asynch delay in the library\n"); + } + } + break; + + default: + error_append("library_error: impossible latch type?\n"); + goto error_return; + } + } +#endif /* SIS */ + + return 1; + +#ifdef SIS + error_return: + LS_ASSERT(lsFinish(gen)); + return 0; +#endif /* SIS */ +} diff --git a/sis/map/map_interface_static.h b/sis/map/map_interface_static.h new file mode 100644 index 0000000..26cd88f --- /dev/null +++ b/sis/map/map_interface_static.h @@ -0,0 +1,20 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/map_interface_static.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)map_interface_static.h 1.3 */ +/* last modified on 7/31/91 at 13:01:23 */ +static network_t *build_network_from_annotations(); +static void map_compute_annotated_arrival_times(); +static void map_compute_loads(); +static void map_remove_unnecessary_annotations(); +static void map_report_data(); +static void map_report_data_annotated(); +static void unmap_network(); +static void visit_mapped_nodes(); +static int map_check_library(); diff --git a/sis/map/map_macros.h b/sis/map/map_macros.h new file mode 100644 index 0000000..62fcba8 --- /dev/null +++ b/sis/map/map_macros.h @@ -0,0 +1,29 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/map_macros.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)map_macros.h 1.2 */ +/* last modified on 5/1/91 at 15:51:27 */ +#ifndef MAP_MACROS_H +#define MAP_MACROS_H + +#include "map_defs.h" +#define DISCRETIZATION_FACTOR 100 + +#define SETSUB(a,b,c) ((a).rise=(b).rise-(c).rise, (a).fall=(b).fall-(c).fall) +#define SETADD(a,b,c) ((a).rise=(b).rise+(c).rise, (a).fall=(b).fall+(c).fall) +#define GETMIN(a) MIN((a).rise, (a).fall) +#define GETMAX(a) MAX((a).rise, (a).fall) +#define SETMIN(a,b,c) ((a).rise=MIN((b).rise, (c).rise), (a).fall=MIN((b).fall,(c).fall)) +#define SETMAX(a,b,c) ((a).rise=MAX((b).rise, (c).rise), (a).fall=MAX((b).fall,(c).fall)) +#define SETMAX2(a,b) ((a)=((a)>(b))?(a):(b)) +#define SETMIN2(a,b) ((a)=((a)<(b))?(a):(b)) +#define IS_EQUAL(a,b) (FP_EQUAL((a).rise,(b).rise) && FP_EQUAL((a).fall,(b).fall)) +#define IS_BETTER(a,b) ((a).rise>=(b).rise && (a).fall>=(b).fall) + +#endif diff --git a/sis/map/maputil.c b/sis/map/maputil.c new file mode 100644 index 0000000..4d1028e --- /dev/null +++ b/sis/map/maputil.c @@ -0,0 +1,223 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/maputil.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)maputil.c 1.8 */ +/* last modified on 8/8/91 at 17:02:09 */ +/* + * $Log: maputil.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:25 pchong + * imported + * + * Revision 1.5 1993/08/05 16:14:19 sis + * Added default case to switch statement so gcc version will work. + * + * Revision 1.4 22/.0/.1 .0:.4:.5 sis + * Updates for the Alpha port. + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 21:59:58 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:40:50 sis + * Initial revision + * + * Revision 1.2 91/07/02 11:18:01 touati + * replace MAP(node)->arrival_info from pointers to copies. + * Slower but safer. + * + * Revision 1.1 91/06/28 22:50:25 touati + * Initial revision + * + */ +#include "sis.h" +#include "map_int.h" +#include "gate_link.h" + +void +map_alloc(node) +node_t *node; +{ + if (MAP(node) != 0) map_free(node); +#if defined(_IBMR2) || defined(__osf__) + node->MAP_SLOT = (char *) ALLOC(alt_map_t, 1); +#else + node->MAP_SLOT = (char *) ALLOC(map_t, 1); +#endif + MAP(node)->gate = 0; + MAP(node)->ninputs = 0; + MAP(node)->save_binding = 0; + MAP(node)->arrival_info = NIL(delay_time_t); + MAP(node)->binding = 0; + MAP(node)->match_node = 0; + MAP(node)->inverter_paid_for = 0; + MAP(node)->slack_is_critical = 0; + MAP(node)->index = 0; + MAP(node)->load = 0.0; + MAP(node)->required.fall = INFINITY; + MAP(node)->required.rise = INFINITY; + MAP(node)->node_y = NIL(node_t); + MAP(node)->gate_link = NIL(st_table); + gate_link_init(node); + MAP(node)->fanout_tree = NIL(array_t); + MAP(node)->fanout_source = NIL(node_t); + MAP(node)->pin_info = NIL(fanin_fanout_t); +} + + +void +map_free(node) +node_t *node; +{ + if (MAP(node) != 0) { + gate_link_free(node); + if (MAP(node)->ninputs) { + FREE(MAP(node)->save_binding); + } + if (MAP(node)->pin_info) { + FREE(MAP(node)->pin_info); + } + if (MAP(node)->arrival_info) { + FREE(MAP(node)->arrival_info); + MAP(node)->arrival_info = NIL(delay_time_t); + } + FREE(node->MAP_SLOT); + node->MAP_SLOT = NIL(char); + } +} + +void map_dup(old, new) +node_t *old, *new; +{ + int i; + + if (MAP(old) == 0) return; + map_alloc(new); + gate_link_free(new); + *MAP(new) = *MAP(old); + if (MAP(old)->ninputs) { + MAP(new)->save_binding = ALLOC(node_t *, MAP(old)->ninputs); + for (i = 0; i < MAP(old)->ninputs; i++) { + MAP(new)->save_binding[i] = MAP(old)->save_binding[i]; + } + } + MAP(new)->pin_info = NIL(fanin_fanout_t); + MAP(new)->arrival_info = NIL(delay_time_t); + MAP(new)->gate_link = NIL(st_table); + gate_link_init(new); +} + + +void +map_invalid(node) +node_t *node; +{ + if (MAP(node) != 0) { + MAP(node)->gate = 0; + } +} + + +void +map_setup_network(network) +network_t *network; +{ + lsGen gen; + node_t *node; + + foreach_node(network, gen, node) { + map_alloc(node); + } +} + +void +map_prep(network, library) +network_t *network; +library_t *library; +{ + decomp_quick_network(network); + if (library->nand_flag) { + decomp_tech_network(network, /* and_limit */ 0, /* or_limit */ 2); + } else { + decomp_tech_network(network, /* and_limit */ 2, /* or_limit */ 0); + } + add_inv_network(network); +} + + /* this should be the new network */ + +void map_network_dup(network) +network_t *network; +{ + int i; + lsGen gen; + node_t *node; + + foreach_node(network, gen, node) { + if (MAP(node) == 0) continue; + if (MAP(node)->ninputs == 0) continue; + for (i = 0; i < MAP(node)->ninputs; i++) { + MAP(node)->save_binding[i] = (MAP(node)->save_binding[i])->copy; + } + } +} + + /* to take into account the new way of handling the input of a PO */ + +node_t *map_po_get_fanin(node) +node_t *node; +{ + assert(node->type == PRIMARY_OUTPUT); +#ifdef SIS + if ((MAP(node)->ninputs > 0) && !(IS_LATCH_END(node))) { +#else + if (MAP(node)->ninputs > 0) { +#endif /* SIS */ + return MAP(node)->save_binding[0]; + } else { + return node_get_fanin(node, 0); + } +} + +#ifdef SIS +/* sequential support */ + +/* obtain the gate type information of the network */ +int +network_gate_type(network) +network_t *network; +{ + int *type; + + if (st_lookup(network_type_table, network_name(network), (char**) &type)) { + return (*type); + } + return ((int) UNKNOWN); +} + +node_t * +network_latch_input(network) +network_t *network; +{ + lsGen gen; + node_t *po, *latch_input; + + latch_input = NIL(node_t); + foreach_primary_output(network, gen, po) { + if (IS_LATCH_END(po)) { + assert(latch_input == NIL(node_t)); /* only one latch input */ + latch_input = po; + LS_ASSERT(lsFinish(gen)); + break; + } + } + return latch_input; +} +#endif diff --git a/sis/map/match.c b/sis/map/match.c new file mode 100644 index 0000000..66cf5ef --- /dev/null +++ b/sis/map/match.c @@ -0,0 +1,168 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/match.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:25 $ + * + */ +/* file @(#)match.c 1.2 */ +/* last modified on 5/1/91 at 15:51:35 */ +#include "sis.h" +#include "map_int.h" + +#define DEBUG + +static int (*g_func)(); +static prim_t *g_prim; +static int g_allow_internal_fanout; +static int g_fanout_limit; +static int g_debug; + + +/* + * Graph matching algorithm. + */ + +static int +match(net_node, list) +register node_t *net_node; +register prim_edge_t *list; +{ + register int i, cont; + register prim_node_t *prim_node; + register node_t *matching_net_node; + node_t *fanin, *fanout; + int already_bound; + lsGen gen; + + /* Fetch primitive node from the edge list */ + prim_node = list->this_node; + + /* See if the binding of the primitive node is consistent */ + already_bound = 0; + if (MAP(net_node)->binding == NIL(prim_node_t)) { + + if (prim_node->binding != NIL(node_t)) { + return 1; + } + + /* Only makes sense if # inputs is the same */ + if (prim_node->type != PRIMARY_INPUT && + node_num_fanin(net_node) != prim_node->nfanin) { + return 1; + } + + /* Only makes sense if the # fanout is the same */ + if (g_allow_internal_fanout & 8) { + if (prim_node->type == INTERNAL && (list->next && list->next->this_node->type == INTERNAL) && + node_num_fanout(net_node) != prim_node->nfanout) { + return 1; + } + } else if (! (g_allow_internal_fanout & 2)) { + if (prim_node->type == INTERNAL && node_num_fanout(net_node) != prim_node->nfanout) { + return 1; + } + } else if (g_allow_internal_fanout & 2) { + if (prim_node->type == INTERNAL && node_num_fanout(net_node) > g_fanout_limit) { + return 1; + } + } + } else { + if (MAP(net_node)->binding != prim_node) { + return 1; + } + already_bound = 1; + /* could assert that prim_node->binding == MAP(net_node) */ + } + + /* Bind the nodes to each other (if they were not already bound) */ + if (! already_bound) { + prim_node->binding = net_node; + MAP(net_node)->binding = prim_node; + } + + if (g_debug) { + (void) fprintf(sisout, + "binding %s to %s\n", net_node->name, prim_node->name); + } + + /* Move to the next arc in the primitive graph */ + if ((list = list->next) == NIL(prim_edge_t)) { + /* Exhausted all arcs, must mean there's a match */ + cont = (*g_func)(g_prim); + + } else { + /* Attempt to match the matching graph node to all inputs and outputs */ + matching_net_node = list->connected_node->binding; + + if (list->dir == DIR_IN) { + if (list->connected_node->isomorphic_sons) { + + /* recur for only the first unbound son */ + foreach_fanin(matching_net_node, i, fanin) { + if (MAP(fanin)->binding == NIL(prim_node_t)) { + cont = match(fanin, list); + break; + } + } + + } else { + + /* recur for all inputs */ + foreach_fanin(matching_net_node, i, fanin) { + cont = match(fanin, list); + if (! cont) { + break; + } + } + } + + } else { + foreach_fanout(matching_net_node, gen, fanout) { + cont = match(fanout, list); + if (! cont) { + LS_ASSERT(lsFinish(gen)); + break; + } + } + } + } + + /* Unbind the nodes */ + if (! already_bound) { + prim_node->binding = NIL(node_t); + MAP(net_node)->binding = NIL(prim_node_t); + if (g_debug) { + (void) fprintf(sisout, + "unbinding %s from %s\n", net_node->name, prim_node->name); + } + } + + return cont; +} + +void +gen_all_matches(node, prim, func, debug, allow_internal_fanout, fanout_limit) +node_t *node; +prim_t *prim; +int (*func)(); +int debug; +int allow_internal_fanout; +int fanout_limit; +{ + g_func = func; + g_prim = prim; + g_debug = debug; + g_allow_internal_fanout = allow_internal_fanout; + g_fanout_limit = fanout_limit; + + if (debug) { + (void) fprintf(sisout, "entering gen_all_matches() ...\n"); + } + + (void) match(node, prim->edges); +} + + diff --git a/sis/map/mix_lt_trees.c b/sis/map/mix_lt_trees.c new file mode 100644 index 0000000..fa0e147 --- /dev/null +++ b/sis/map/mix_lt_trees.c @@ -0,0 +1,340 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/mix_lt_trees.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)mix_lt_trees.c 1.3 */ +/* last modified on 5/1/91 at 15:51:41 */ +#include "sis.h" +#include <math.h> +#include "fanout_int.h" +#include "fanout_delay.h" + +static int get_n_fanouts(); +static int mixed_lt_trees_optimize(); +static multidim_t *optimize_one_source(); +static void best_one_source(); +static void build_selected_tree(); +static void insert_mixed_lt_tree(); +static void select_best_source(); + + + /* CONTENTS */ + + /* LT-Trees based fanout optimization */ + +static n_gates_t n_gates; + +typedef struct lt_tree_struct lt_tree_t; +struct lt_tree_struct { + int balanced; /* boolean: whether this node is the root of a two level balanced tree or not */ + two_level_t *two_level; /* pointer to two_level_t descriptor (if balanced) */ + int gate_index; /* gate to put at intermediate nodes (if ! balanced) */ + int x_index; /* x_index - 1 is last sink directly under this node, if any */ + int y_index; /* y_index - 1 is last sink directly under this node, if any */ + delay_time_t required; /* required time at the source, not including source intrinsic */ + double area; /* area of subtree rooted here */ +}; + +static lt_tree_t LT_TREE_INIT_VALUE = {-1, 0, -1, -1, -1, {-INFINITY, -INFINITY}, 0.0}; + +static int max_n_gaps = 5; +static int max_x_index = 15; +static int max_y_index = 15; + + /* EXTERNAL INTERFACE */ + + /* ARGSUSED */ +void mixed_lt_trees_init(network, alg) +network_t *network; +fanout_alg_t *alg; +{ + alg->optimize = mixed_lt_trees_optimize; +} + + /* ARGSUSED */ +void mixed_lt_trees_set_max_n_gaps(alg, property) +fanout_alg_t *alg; +alg_property_t *property; +{ max_n_gaps = property->value; } + + /* ARGSUSED */ +void mixed_lt_trees_set_max_x_index(alg, property) +fanout_alg_t *alg; +alg_property_t *property; +{ max_x_index = property->value; } + + /* ARGSUSED */ +void mixed_lt_trees_set_max_y_index(alg, property) +fanout_alg_t *alg; +alg_property_t *property; +{ max_y_index = property->value; } + + + /* INTERNAL INTERFACE */ + +static multidim_t *two_level_table; + +static int mixed_lt_trees_optimize(fanout_info, tree, cost) +opt_array_t *fanout_info; /* fanout_info[POLAR_X] lists the positive polarity sinks; POLAR_Y negative */ +array_t *tree; /* array in which the result tree is stored: format of fanout_tree.c */ +fanout_cost_t *cost; /* contains information on the result: required times, area */ +{ + multidim_t *table; + selected_source_t source; + + cost->slack = MINUS_INFINITY; + cost->area = INFINITY; + if (fanout_info[POLAR_X].n_elts == 0) return 0; + if (fanout_info[POLAR_Y].n_elts == 0) return 0; + if (fanout_info[POLAR_X].n_elts > max_x_index && fanout_info[POLAR_Y].n_elts > max_y_index) return 0; + table = optimize_one_source(fanout_info); + select_best_source(table, &source, cost); + build_selected_tree(fanout_info, tree, &source, table); + multidim_free(two_level_table); + multidim_free(table); + return 1; +} + +static multidim_t *optimize_one_source(fanout_info) +opt_array_t *fanout_info; +{ + multidim_t *table; + int indices[5]; + int n_gaps; + int x_index, y_index; + int source_index, source_polarity; + + n_gates = fanout_delay_get_n_gates(); + indices[0] = n_gates.n_gates; /* source index */ + indices[1] = POLAR_MAX; /* polarity at output of source */ + indices[2] = fanout_info[POLAR_X].n_elts + 1; + indices[3] = fanout_info[POLAR_Y].n_elts + 1; + indices[4] = max_n_gaps; /* gaps used so far */ + table = multidim_alloc(lt_tree_t, 5, indices); + multidim_init(lt_tree_t, table, LT_TREE_INIT_VALUE); + two_level_table = two_level_optimize_for_lt_trees(fanout_info); + + assert(fanout_info[POLAR_X].n_elts > 0 && fanout_info[POLAR_Y].n_elts > 0); + for (x_index = fanout_info[POLAR_X].n_elts; x_index >= 0; x_index--) { + for (y_index = fanout_info[POLAR_Y].n_elts; y_index >= 0; y_index--) { + foreach_gate(n_gates, source_index) { + for (n_gaps = 0; n_gaps < max_n_gaps; n_gaps++) { + foreach_polarity(source_polarity) { + if (is_source(n_gates, source_index) && fanout_delay_get_source_polarity(source_index) != source_polarity) continue; + best_one_source(table, two_level_table, fanout_info, source_index, source_polarity, x_index, y_index, n_gaps); + } + } + } + } + } + return table; +} + + + /* computes the best LT-tree for a given source, a given set of sinks */ + +static void best_one_source(table, two_level_table, fanout_info, source_index, source_polarity, x_index, y_index, n_gaps) +multidim_t *table; +multidim_t *two_level_table; +opt_array_t *fanout_info; +int source_index; +int source_polarity; +int x_index; +int y_index; +int n_gaps; +{ + int p, q, p_sink, q_sink, sink, next_x, next_y; + int buffer_index, buffer_polarity, buffer_gaps; + lt_tree_t *buffer_entry; + int n_fanouts; + double load; + double local_area; + delay_time_t local_required; + two_level_t *two_level_entry; + lt_tree_t *entry = INDEX5P(lt_tree_t, table, source_index, source_polarity, x_index, y_index, n_gaps); + + if (x_index == fanout_info[POLAR_X].n_elts && y_index == fanout_info[POLAR_Y].n_elts) { + entry->balanced = 0; + entry->gate_index = -1; + entry->x_index = x_index; + entry->y_index = y_index; + entry->required = PLUS_INFINITY; + entry->area = 0.0; + return; + } + if (x_index == fanout_info[POLAR_X].n_elts) { + two_level_entry = INDEX4P(two_level_t, two_level_table, source_index, source_polarity, y_index, POLAR_Y); + } else if (y_index == fanout_info[POLAR_Y].n_elts) { + two_level_entry = INDEX4P(two_level_t, two_level_table, source_index, source_polarity, x_index, POLAR_X); + } else { + two_level_entry = NIL(two_level_t); + } + if (two_level_entry != NIL(two_level_t)) { + entry->balanced = 1; + entry->two_level = two_level_entry; + entry->required = two_level_entry->required; + entry->area = two_level_entry->area; + } + + /* choose the best subdecomposition */ + p = source_polarity; + q = POLAR_INV(source_polarity); + p_sink = (p == POLAR_X) ? x_index : y_index; + q_sink = (q == POLAR_X) ? x_index : y_index; + for (sink = p_sink; sink <= fanout_info[p].n_elts; sink++) { + foreach_buffer(n_gates, buffer_index) { + buffer_polarity = (is_inverter(n_gates, buffer_index)) ? q : p; + buffer_gaps = (sink == p_sink && sink < fanout_info[p].n_elts) ? n_gaps - 1 : n_gaps; + if (buffer_gaps < 0) continue; + next_x = (p == POLAR_X) ? sink : q_sink; + next_y = (p == POLAR_Y) ? sink : q_sink; + if (sink == fanout_info[p].n_elts && q_sink == fanout_info[q].n_elts) { + local_area = 0.0; + n_fanouts = 0; + load = 0.0; + local_required = PLUS_INFINITY; + } else { + buffer_entry = INDEX5P(lt_tree_t, table, buffer_index, buffer_polarity, next_x, next_y, buffer_gaps); + local_area = buffer_entry->area; + n_fanouts = 1; + load = fanout_delay_get_buffer_load(buffer_index); + local_required = fanout_delay_backward_intrinsic(buffer_entry->required, buffer_index); + } + local_area += fanout_delay_get_area(source_index); + n_fanouts += sink - p_sink; + load += fanout_info[p].cumul_load[sink] - fanout_info[p].cumul_load[p_sink]; + load += map_compute_wire_load(n_fanouts); + if (sink > p_sink) SETMIN(local_required, local_required, fanout_info[p].min_required[p_sink]); + local_required = fanout_delay_backward_load_dependent(local_required, source_index, load); + if (GETMIN(entry->required) < GETMIN(local_required)) { + entry->balanced = 0; + entry->gate_index = buffer_index; + entry->x_index = next_x; + entry->y_index = next_y; + entry->required = local_required; + entry->area = local_area; + } + } + } +} + +static void select_best_source(table, best_source, best_cost) +multidim_t *table; +selected_source_t *best_source; +fanout_cost_t *best_cost; +{ + int source_index; + int source_polarity; + lt_tree_t *entry; + + best_cost->slack = MINUS_INFINITY; + best_cost->area = INFINITY; + foreach_source(n_gates, source_index) { + source_polarity = fanout_delay_get_source_polarity(source_index); + entry = INDEX5P(lt_tree_t, table, source_index, source_polarity, 0, 0, max_n_gaps - 1); + if (GETMIN(best_cost->slack) < GETMIN(entry->required)) { + best_cost->slack = entry->required; + best_cost->area = entry->area; + best_source->main_source = source_index; + } + } + assert(GETMIN(best_cost->slack) > - INFINITY); +} + +static void build_selected_tree(fanout_info, tree, source, table) +opt_array_t *fanout_info; +array_t *tree; +selected_source_t *source; +multidim_t *table; +{ + int n_fanouts; + int source_polarity = fanout_delay_get_source_polarity(source->main_source); + + n_fanouts = get_n_fanouts(fanout_info, table, source->main_source, source_polarity, 0, 0, max_n_gaps - 1); + fanout_tree_insert_gate(tree, source->main_source, n_fanouts); + insert_mixed_lt_tree(tree, table, fanout_info, source->main_source, source_polarity, 0, 0, max_n_gaps - 1); +} + +static void insert_mixed_lt_tree(tree, table, fanout_info, source_index, source_polarity, x_index, y_index, n_gaps) +array_t *tree; +multidim_t *table; +opt_array_t *fanout_info; +int source_index; +int source_polarity; +int x_index; +int y_index; +int n_gaps; +{ + int p, q, p_sink, q_sink, sink; + int n_fanouts; + lt_tree_t *entry; + int buffer_index; + int buffer_polarity; + int buffer_gaps; + int buffer_x, buffer_y; + + if (x_index == fanout_info[POLAR_X].n_elts && y_index == fanout_info[POLAR_Y].n_elts) return; + entry = INDEX5P(lt_tree_t, table, source_index, source_polarity, x_index, y_index, n_gaps); + p = source_polarity; + q = POLAR_INV(p); + p_sink = (p == POLAR_X) ? x_index : y_index; + q_sink = (q == POLAR_X) ? x_index : y_index; + switch (entry->balanced) { + case 0: + sink = (p == POLAR_X) ? entry->x_index : entry->y_index; + assert(q_sink == ((q == POLAR_X) ? entry->x_index : entry->y_index)); + noalg_insert_sinks(tree, &fanout_info[p], p_sink, sink); + if (sink == fanout_info[p].n_elts && q_sink == fanout_info[q].n_elts) return; + buffer_index = entry->gate_index; + buffer_polarity = (is_inverter(n_gates, buffer_index)) ? q : p; + buffer_gaps = (sink == p_sink && sink < fanout_info[p].n_elts) ? n_gaps - 1 : n_gaps; + buffer_x = (p == POLAR_X) ? sink : q_sink; + buffer_y = (p == POLAR_Y) ? sink : q_sink; + n_fanouts = get_n_fanouts(fanout_info, table, buffer_index, buffer_polarity, buffer_x, buffer_y, buffer_gaps); + fanout_tree_insert_gate(tree, buffer_index, n_fanouts); + insert_mixed_lt_tree(tree, table, fanout_info, buffer_index, buffer_polarity, buffer_x, buffer_y, buffer_gaps); + break; + case 1: + if (p_sink == fanout_info[p].n_elts) { + assert(q_sink < fanout_info[q].n_elts); + insert_two_level_tree(tree, &fanout_info[q], q_sink, source_index, entry->two_level); + } else if (q_sink == fanout_info[q].n_elts) { + assert(p_sink < fanout_info[p].n_elts); + insert_two_level_tree(tree, &fanout_info[p], p_sink, source_index, entry->two_level); + } else { + fail("can't use two level when sinks of both polarities remain"); + } + break; + default: + fail("illegal value of field lt_tree_t.balanced"); + } +} + +static int get_n_fanouts(fanout_info, table, source_index, source_polarity, x_index, y_index, n_gaps) +opt_array_t *fanout_info; +multidim_t *table; +int source_index; +int source_polarity; +int x_index; +int y_index; +int n_gaps; +{ + int p, q, p_sink, q_sink, sink; + lt_tree_t *entry; + + if (x_index == fanout_info[POLAR_X].n_elts && y_index == fanout_info[POLAR_Y].n_elts) return 0; + entry = INDEX5P(lt_tree_t, table, source_index, source_polarity, x_index, y_index, n_gaps); + if (entry->balanced) return entry->two_level->n_gates; + p = source_polarity; + q = POLAR_INV(p); + p_sink = (p == POLAR_X) ? x_index : y_index; + q_sink = (q == POLAR_X) ? x_index : y_index; + sink = (p == POLAR_X) ? entry->x_index : entry->y_index; + if (sink == fanout_info[p].n_elts && q_sink == fanout_info[q].n_elts) return (sink - p_sink); + return sink - p_sink + 1; +} diff --git a/sis/map/multi_array.c b/sis/map/multi_array.c new file mode 100644 index 0000000..b810217 --- /dev/null +++ b/sis/map/multi_array.c @@ -0,0 +1,61 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/multi_array.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)multi_array.c 1.2 */ +/* last modified on 5/1/91 at 15:51:37 */ +#include "sis.h" +#include "multi_array.h" + +multidim_t *generic_multidim_alloc(type_size, n_indices, max_index) +int type_size; +int n_indices; +int *max_index; +{ + int i; + int size = type_size; + multidim_t *array = ALLOC(multidim_t, 1); + + array->n_indices = n_indices; + array->max_index = ALLOC(int, n_indices); + for (i = 0; i < n_indices; i++) { + array->max_index[i] = max_index[i]; + size *= max_index[i]; + } + assert(size > 0); + array->n_entries = size / type_size; + array->array = ALLOC(char, size); + array->type_size = type_size; + return array; +} + +void multidim_free(array) +multidim_t *array; +{ + FREE(array->array); + FREE(array->max_index); + FREE(array); +} + +int multidim_array_abort(code) +int code; +{ + fprintf(stderr, "multidim array error: "); + switch (code) { + case 0: + fprintf(stderr, "inconsistent object size"); + break; + case 1: + fprintf(stderr, "index out of bounds "); + break; + default: + fprintf(stderr, "unknown error"); + break; + } + fail("\n"); +} diff --git a/sis/map/multi_array.h b/sis/map/multi_array.h new file mode 100644 index 0000000..6a2c508 --- /dev/null +++ b/sis/map/multi_array.h @@ -0,0 +1,131 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/multi_array.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)multi_array.h 1.2 */ +/* last modified on 5/1/91 at 15:51:39 */ +#ifndef MULTDIM_ARRAY_H +#define MULTDIM_ARRAY_H + +typedef struct multidim_struct multidim_t; +struct multidim_struct { + int n_indices; + int *max_index; + int n_entries; + int type_size; + char *array; +}; + +extern multidim_t *generic_multidim_alloc(/* int type_size, int n_indices, int *max_index */); +extern void multidim_free(/* multidim_t * array */); + +#define multidim_alloc(TYPE, n_indices, max_index)\ + generic_multidim_alloc(sizeof(TYPE), n_indices, max_index) + +#define multidim_init(TYPE,ARRAY,INIT_VALUE)\ +{\ + int i;\ + for (i = 0; i < (ARRAY)->n_entries; i++)\ + ((TYPE *) (ARRAY)->array)[i] = INIT_VALUE;\ +} + +extern int multidim_array_abort(); + +#ifndef FAST_ARRAY + +#define INDEX2(TYPE,A,a,b)\ +((sizeof(TYPE) != (A)->type_size ? multidim_array_abort(0) : 0),\ + (((a) < 0 || (a) >= (A)->max_index[0]) ? multidim_array_abort(1) : 0),\ + (((b) < 0 || (b) >= (A)->max_index[1]) ? multidim_array_abort(1) : 0),\ + (((TYPE *) (A)->array)[ (a)*(A)->max_index[1]+(b)])) + +#define INDEX3(TYPE,A,a,b,c)\ +((sizeof(TYPE) != (A)->type_size ? multidim_array_abort(0) : 0),\ + (((a) < 0 || (a) >= (A)->max_index[0]) ? multidim_array_abort(1) : 0),\ + (((b) < 0 || (b) >= (A)->max_index[1]) ? multidim_array_abort(1) : 0),\ + (((c) < 0 || (c) >= (A)->max_index[2]) ? multidim_array_abort(1) : 0),\ + (((TYPE *) (A)->array)[ ((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c)])) + +#define INDEX4(TYPE,A,a,b,c,d)\ +((sizeof(TYPE) != (A)->type_size ? multidim_array_abort(0) : 0),\ + (((a) < 0 || (a) >= (A)->max_index[0]) ? multidim_array_abort(1) : 0),\ + (((b) < 0 || (b) >= (A)->max_index[1]) ? multidim_array_abort(1) : 0),\ + (((c) < 0 || (c) >= (A)->max_index[2]) ? multidim_array_abort(1) : 0),\ + (((d) < 0 || (d) >= (A)->max_index[3]) ? multidim_array_abort(1) : 0),\ + (((TYPE *) (A)->array)[ (((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c))*(A)->max_index[3]+(d)])) + +#define INDEX5(TYPE,A,a,b,c,d,e)\ +((sizeof(TYPE) != (A)->type_size ? multidim_array_abort(0) : 0),\ + (((a) < 0 || (a) >= (A)->max_index[0]) ? multidim_array_abort(1) : 0),\ + (((b) < 0 || (b) >= (A)->max_index[1]) ? multidim_array_abort(1) : 0),\ + (((c) < 0 || (c) >= (A)->max_index[2]) ? multidim_array_abort(1) : 0),\ + (((d) < 0 || (d) >= (A)->max_index[3]) ? multidim_array_abort(1) : 0),\ + (((e) < 0 || (e) >= (A)->max_index[4]) ? multidim_array_abort(1) : 0),\ + (((TYPE *) (A)->array)[((((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c))*(A)->max_index[3]+(d))*(A)->max_index[4]+(e)])) + +#define INDEX2P(TYPE,A,a,b)\ +(((sizeof(TYPE) != (A)->type_size ? multidim_array_abort(0) : 0),\ + (((a) < 0 || (a) >= (A)->max_index[0]) ? multidim_array_abort(1) : 0),\ + (((b) < 0 || (b) >= (A)->max_index[1]) ? multidim_array_abort(1) : 0)),\ + &(((TYPE *) (A)->array)[ (a)*(A)->max_index[1]+(b)])) + +#define INDEX3P(TYPE,A,a,b,c)\ +(((sizeof(TYPE) != (A)->type_size ? multidim_array_abort(0) : 0),\ + (((a) < 0 || (a) >= (A)->max_index[0]) ? multidim_array_abort(1) : 0),\ + (((b) < 0 || (b) >= (A)->max_index[1]) ? multidim_array_abort(1) : 0),\ + (((c) < 0 || (c) >= (A)->max_index[2]) ? multidim_array_abort(1) : 0)),\ + &(((TYPE *) (A)->array)[ ((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c)])) + +#define INDEX4P(TYPE,A,a,b,c,d)\ +(((sizeof(TYPE) != (A)->type_size ? multidim_array_abort(0) : 0),\ + (((a) < 0 || (a) >= (A)->max_index[0]) ? multidim_array_abort(1) : 0),\ + (((b) < 0 || (b) >= (A)->max_index[1]) ? multidim_array_abort(1) : 0),\ + (((c) < 0 || (c) >= (A)->max_index[2]) ? multidim_array_abort(1) : 0),\ + (((d) < 0 || (d) >= (A)->max_index[3]) ? multidim_array_abort(1) : 0)),\ + &(((TYPE *) (A)->array)[ (((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c))*(A)->max_index[3]+(d)])) + +#define INDEX5P(TYPE,A,a,b,c,d,e)\ +(((sizeof(TYPE) != (A)->type_size ? multidim_array_abort(0) : 0),\ + (((a) < 0 || (a) >= (A)->max_index[0]) ? multidim_array_abort(1) : 0),\ + (((b) < 0 || (b) >= (A)->max_index[1]) ? multidim_array_abort(1) : 0),\ + (((c) < 0 || (c) >= (A)->max_index[2]) ? multidim_array_abort(1) : 0),\ + (((d) < 0 || (d) >= (A)->max_index[3]) ? multidim_array_abort(1) : 0),\ + (((e) < 0 || (e) >= (A)->max_index[4]) ? multidim_array_abort(1) : 0)),\ + &(((TYPE *) (A)->array)[((((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c))*(A)->max_index[3]+(d))*(A)->max_index[4]+(e)])) + +#else /* i.e. ifdef FAST_ARRAY */ + +/* this is a lot faster than the check-me-all macros listed above: no seat belts! */ + +#define INDEX2(TYPE,A,a,b)\ +(((TYPE *) (A)->array)[ (a)*(A)->max_index[1]+(b)]) + +#define INDEX3(TYPE,A,a,b,c)\ +(((TYPE *) (A)->array)[ ((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c)]) + +#define INDEX4(TYPE,A,a,b,c,d)\ +(((TYPE *) (A)->array)[ (((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c))*(A)->max_index[3]+(d)]) + +#define INDEX5(TYPE,A,a,b,c,d,e)\ +(((TYPE *) (A)->array)[((((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c))*(A)->max_index[3]+(d))*(A)->max_index[4]+(e)]) + +#define INDEX2P(TYPE,A,a,b)\ +&(((TYPE *) (A)->array)[ (a)*(A)->max_index[1]+(b)]) + +#define INDEX3P(TYPE,A,a,b,c)\ +&(((TYPE *) (A)->array)[ ((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c)]) + +#define INDEX4P(TYPE,A,a,b,c,d)\ +&(((TYPE *) (A)->array)[ (((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c))*(A)->max_index[3]+(d)]) + +#define INDEX5P(TYPE,A,a,b,c,d,e)\ +&(((TYPE *) (A)->array)[((((a)*(A)->max_index[1]+(b))*(A)->max_index[2]+(c))*(A)->max_index[3]+(d))*(A)->max_index[4]+(e)]) + +#endif /* FAST_ARRAY */ + +#endif /* MULTIDIM_ARRAY_H */ diff --git a/sis/map/noalg.c b/sis/map/noalg.c new file mode 100644 index 0000000..5fb6cbe --- /dev/null +++ b/sis/map/noalg.c @@ -0,0 +1,185 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/noalg.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)noalg.c 1.2 */ +/* last modified on 5/1/91 at 15:51:43 */ +#include "sis.h" +#include "fanout_int.h" +#include "fanout_delay.h" + +static int noalg_optimize(); +static multidim_t *optimize_one_source(); +static void build_selected_tree(); +static void compute_best_one_source_one_polarity(); +static void extract_merge_info(); + +static n_gates_t n_gates; + +typedef struct noalg_struct noalg_t; +struct noalg_struct { + delay_time_t required; + double area; +}; + +static noalg_t NOALG_INIT_VALUE = {{-INFINITY,-INFINITY}, 0.0}; + + + /* CONTENTS */ + + /* this file contains the routines to compute fanout trees */ + /* composed of at most one inverter */ + + /* ARGSUSED */ +void noalg_init(network, alg) +network_t *network; +fanout_alg_t *alg; +{ + alg->optimize = noalg_optimize; +} + + /* INTERNAL INTERFACE */ + +static int noalg_optimize(fanout_info, tree, cost) +opt_array_t *fanout_info; /* fanout_info[POLAR_X] lists the positive polarity sinks; POLAR_Y negative */ +array_t *tree; /* array in which the result tree is stored: format of fanout_tree.c */ +fanout_cost_t *cost; /* contains information on the result: required times, area */ +{ + generic_fanout_optimizer(fanout_info, tree, cost, optimize_one_source, extract_merge_info, build_selected_tree); + return 1; +} + + /* computes the best solution for each (source,sink_polarity) separately */ + +static multidim_t *optimize_one_source(fanout_info) +opt_array_t *fanout_info; +{ + int source_index, source_polarity; + noalg_t *entry; + int indices[2]; + multidim_t *table; + + n_gates = fanout_delay_get_n_gates(); + indices[0] = n_gates.n_gates; + indices[1] = POLAR_MAX; + table = multidim_alloc(noalg_t, 2, indices); + multidim_init(noalg_t, table, NOALG_INIT_VALUE); + + foreach_gate(n_gates, source_index) { + foreach_polarity(source_polarity) { + if (is_source(n_gates, source_index) && fanout_delay_get_source_polarity(source_index) != source_polarity) continue; + entry = INDEX2P(noalg_t, table, source_index, source_polarity); + compute_best_one_source_one_polarity(&fanout_info[source_polarity], entry, source_index); + } + } + return table; +} + +static void compute_best_one_source_one_polarity(fanout_info, entry, source_index) +opt_array_t *fanout_info; +noalg_t *entry; +int source_index; +{ + delay_time_t required; + double load; + + if (fanout_info->n_elts == 0) { + entry->required = PLUS_INFINITY; + entry->area = 0.0; + return; + } + required = fanout_info->min_required[0]; + load = fanout_info->total_load + map_compute_wire_load(fanout_info->n_elts); + entry->required = fanout_delay_backward_load_dependent(required, source_index, load); + entry->area = fanout_delay_get_area(source_index); +} + + + /* extract info to interface with fanout_select_best_source */ + /* merge_table should be such that its entries are required times */ + /* at the output of a outside source */ + +static void extract_merge_info(fanout_info, table, merge_table) +opt_array_t *fanout_info; +multidim_t *table; +multidim_t *merge_table; +{ + int source_index; + noalg_t *from; + single_source_t *to; + int p; + + foreach_buffer(n_gates, source_index) { + foreach_polarity(p) { + from = INDEX2P(noalg_t, table, source_index, p); + to = INDEX3P(single_source_t, merge_table, source_index, p, p); + if (fanout_info[p].n_elts > 0) { + to->required = fanout_delay_backward_intrinsic(from->required, source_index); + to->load = fanout_delay_get_buffer_load(source_index); + to->n_fanouts = 1; + to->area = from->area; + } else { + to->required = PLUS_INFINITY; + } + } + } + + foreach_source(n_gates, source_index) { + p = fanout_delay_get_source_polarity(source_index); + to = INDEX3P(single_source_t, merge_table, source_index, p, p); + if (fanout_info[p].n_elts > 0) { + to->required = fanout_info[p].min_required[0]; + to->load = fanout_info[p].total_load; + to->n_fanouts = fanout_info[p].n_elts; + } else { + to->required = PLUS_INFINITY; + } + } +} + + + /* ARGSUSED */ + +static void build_selected_tree(fanout_info, tree, source, table) +opt_array_t *fanout_info; +array_t *tree; +selected_source_t *source; +multidim_t *table; +{ + int p, q; + + p = source->main_source_sink_polarity; + q = POLAR_INV(p); + if (fanout_info[q].n_elts > 0) { + if (is_source(n_gates, source->buffer)) { + fail("can't service two polarities from same output"); + } else { + fanout_tree_insert_gate(tree, source->main_source, fanout_info[p].n_elts + 1); + noalg_insert_sinks(tree, &fanout_info[p], 0, fanout_info[p].n_elts); + fanout_tree_insert_gate(tree, source->buffer, fanout_info[q].n_elts); + noalg_insert_sinks(tree, &fanout_info[q], 0, fanout_info[q].n_elts); + } + } else { + fanout_tree_insert_gate(tree, source->main_source, fanout_info[p].n_elts); + noalg_insert_sinks(tree, &fanout_info[p], 0, fanout_info[p].n_elts); + } +} + +void noalg_insert_sinks(tree, fanout_info, from, to) +array_t *tree; +opt_array_t *fanout_info; +int from; +int to; +{ + int sink; + + for (sink = from; sink < to; sink++) { + gate_link_t *leaf = array_fetch(gate_link_t *, fanout_info->required, sink); + fanout_tree_insert_sink(tree, leaf); + } +} diff --git a/sis/map/prim.c b/sis/map/prim.c new file mode 100644 index 0000000..98eb00f --- /dev/null +++ b/sis/map/prim.c @@ -0,0 +1,539 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/prim.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)prim.c 1.5 */ +/* last modified on 8/8/91 at 17:02:12 */ +#include "sis.h" +#include "map_int.h" + + +static prim_t *make_primitive(); +static int make_edge_list(); +static void reorder(); +static st_table *arc_hash_init(); +static int arc_find_or_add(); +static void arc_hash_end(); +static prim_t *prim_alloc(); + +static node_t *prim_first_po(); +static int prim_feeds_only_real_po(); + +static char errmsg[1024]; + + +int +map_network_to_prim(network, prim_p) +network_t *network; +prim_t **prim_p; +{ + prim_t *prim; + st_table *isomorphic_sons; + + /* find which nodes have isomorphic children */ + isomorphic_sons = map_find_isomorphisms(network); + + /* Map the network into the 'prim' structure used for matching */ + prim = make_primitive(network, isomorphic_sons); + st_free_table(isomorphic_sons); + + *prim_p = prim; + return prim != 0; +} + +/* + * Map a network into a primitive pattern used for matching + */ + +static prim_t * +make_primitive(network, isomorphic_sons) +network_t *network; +st_table *isomorphic_sons; +{ + node_t *node, *po; + prim_t *prim; + prim_node_t *prim_node; + lsGen gen; + int i; + + /* give each node of 'network' a map record -- we use 'binding' */ + map_setup_network(network); + + /* Allocate a header for the primitive information */ + prim = prim_alloc(); + +#ifdef SIS + prim->latch_type = network_gate_type(network); + if (prim->latch_type == (int) UNKNOWN) { + FREE(prim); + return NIL(prim_t); + } +#endif /* SIS */ + + /* only single-output gates for now */ + assert(network_num_po(network) == 1); + + /* Create a primitive node for each node in the network */ + foreach_node(network, gen, node) { +#ifdef SIS + if (node->type == INTERNAL || node->type == PRIMARY_INPUT || + (node->type == PRIMARY_OUTPUT && network_gate_type(network) != (int) COMBINATIONAL)) { +#else + if (node->type == INTERNAL || node->type == PRIMARY_INPUT) { +#endif /* SIS */ + + prim_node = ALLOC(prim_node_t, 1); + prim_node->type = node->type; + prim_node->nfanin = node_num_fanin(node); + prim_node->nfanout = node_num_fanout(node); + prim_node->binding = 0; + + /* Label PO/PI nodes. + * Combinational gate - internal node which feeds PO is labeled as PO + * Latch - a latch input node is labeled as PO. + */ +#ifdef SIS + if (node_type(node) == PRIMARY_OUTPUT && network_gate_type(network) != (int) COMBINATIONAL) { + prim_node->type = PRIMARY_OUTPUT; + prim_node->name = util_strsav(node->name); + } else if (prim_feeds_only_real_po(node, &po)) { +#else + if (prim_feeds_only_real_po(node, &po)) { +#endif /* SIS */ + prim_node->type = PRIMARY_OUTPUT; + prim_node->name = util_strsav(po->name); + } else if (prim_node->type == PRIMARY_INPUT) { + prim_node->name = util_strsav(node->name); + } else { + /* only required for debugging ... */ + prim_node->name = util_strsav(node->name); + } + + prim_node->isomorphic_sons = 0; +#ifdef SIS + /* do not check for isomorphic sons for latches */ + if (prim->latch_type == (int) COMBINATIONAL) { +#endif /* SIS */ + if (st_lookup(isomorphic_sons, (char *) node, NIL(char *))) { + prim_node->isomorphic_sons = 1; + } +#ifdef SIS + } + /* check for latch outputs */ + prim_node->latch_output = 0; + if ( IS_LATCH_END(node) && node_type(node) == PRIMARY_INPUT ) { + prim_node->latch_output = 1; + } +#endif /* SIS */ + + /* record the association between 'node' and 'prim_node' */ + MAP(node)->binding = prim_node; + + /* add to the linked list of nodes for the primitive */ + prim_node->next = prim->nodes; + prim->nodes = prim_node; + } + } + + /* save direct pointers to the inputs */ + prim->inputs = ALLOC(prim_node_t *, network_num_pi(network)); + i = 0; + foreach_primary_input(network, gen, node) { + prim->inputs[i++] = MAP(node)->binding; + } + prim->ninputs = i; /* sequential support */ + + /* save direct pointers to the outputs */ + /* We only support single-output gates now*/ + prim->outputs = ALLOC(prim_node_t *, 1); + prim->noutputs = 1; + foreach_primary_output(network, gen, node) { +#ifdef SIS + if (prim->latch_type == (int) COMBINATIONAL) { +#endif /* SIS */ + prim->outputs[0] = MAP(node_get_fanin(node, 0))->binding; +#ifdef SIS + } else { + prim->outputs[0] = MAP(node)->binding; + } +#endif /* SIS */ + } + + if (! make_edge_list(network, prim)) { + prim_free(prim); + return NIL(prim_t); + } else { + return prim; + } +} + +static prim_edge_t *last_edge; + +static int +make_edge_list(network, prim) +network_t *network; +prim_t *prim; +{ + st_table *visited, *arc_table; + prim_edge_t edge; + node_t *po, *node; + int retcode; + lsGen gen; + + if (network_num_po(network) < 1) { + (void) sprintf(errmsg, "network '%s' has no outputs ?", + network_name(network)); + read_error(errmsg); + return 0; + } + + /* get the first output. + */ + po = prim_first_po(network); + + /* visiting the first output should reach all nodes ... */ + visited = st_init_table(st_ptrcmp, st_ptrhash); + arc_table = arc_hash_init(); + last_edge = &edge; + reorder(po, NIL(node_t), DIR_IN, arc_table, visited); + prim->edges = edge.next; + arc_hash_end(arc_table); + + /* Check that all nodes were reached from the first output */ + retcode = 1; + foreach_node(network, gen, node) { + if (! st_lookup(visited, (char *) node, NIL(char *))) { + (void) sprintf(errmsg, "network '%s' is not connected", + network_name(network)); + read_error(errmsg); + retcode = 0; /* some node not visited */ + LS_ASSERT(lsFinish(gen)); + break; + } + } + st_free_table(visited); + + return retcode; +} + +static void +reorder(node, prev, dir, arc_table, visited) +node_t *node, *prev; +edge_dir_t dir; +st_table *arc_table; +st_table *visited; +{ + int i; + prim_edge_t *edge; + node_t *fanin, *fanout; + lsGen gen; + + /* Record new edge */ +#ifdef SIS + if ((node->type != PRIMARY_OUTPUT) || + (node->type == PRIMARY_OUTPUT && network_gate_type(node->network) != (int) COMBINATIONAL)) { +#else + if (node->type != PRIMARY_OUTPUT) { +#endif /* SIS */ + edge = ALLOC(prim_edge_t, 1); + edge->this_node = MAP(node)->binding; + edge->connected_node = prev == NIL(node_t) ? 0 : MAP(prev)->binding; + edge->dir = dir; + edge->next = NIL(prim_edge_t); + last_edge->next = edge; + last_edge = last_edge->next; + } + + /* Only need to visit all arcs from a node once */ + if (! st_find_or_add(visited, (char *) node, NIL(char **))) { + + /* Traverse all in-coming arcs (that haven't been visited yet) */ + foreach_fanin(node, i, fanin) { + if (! arc_find_or_add(arc_table, fanin, node)) { + reorder(fanin, node, DIR_IN, arc_table, visited); + } + } + + /* Traverse all out-going arcs (that haven't been visited yet) */ + foreach_fanout(node, gen, fanout) { + if (! arc_find_or_add(arc_table, node, fanout)) { + reorder(fanout, node, DIR_OUT, arc_table, visited); + } + } + } +} + +/* Create a hash table to identify the arcs which have been visited */ +typedef struct arc_struct arc_t; +struct arc_struct { + node_t *node1, *node2; +}; + + +static int +arc_compare(arc1_p, arc2_p) +char *arc1_p, *arc2_p; +{ + arc_t *arc1 = (arc_t *) arc1_p, *arc2 = (arc_t *) arc2_p; + + if (arc1->node1 == arc2->node1) { + return (int) arc1->node2 - (int) arc2->node2; + } else { + return (int) arc1->node1 - (int) arc2->node1; + } +} + + +static int +arc_hash(arc_p, modulus) +char *arc_p; +int modulus; +{ + arc_t *arc = (arc_t *) arc_p; + return ((unsigned) arc->node1 + (unsigned) arc->node2) % modulus; +} + + +static st_table * +arc_hash_init() +{ + return st_init_table(arc_compare, arc_hash); +} + + +static int +arc_find_or_add(table, node1, node2) +st_table *table; +node_t *node1, *node2; +{ + arc_t *arc; + + arc = ALLOC(arc_t, 1); + arc->node1 = node1; + arc->node2 = node2; + if (st_find_or_add(table, (char *) arc, NIL(char **))) { + FREE(arc); + return 1; /* already in table */ + } else { + return 0; /* not already in table */ + } +} + + +static void +arc_hash_end(table) +st_table *table; +{ + st_generator *gen; + arc_t *arc; + + st_foreach_item(table, gen, (char **) &arc, NIL(char *)) { + FREE(arc); + } + st_free_table(table); +} + +static prim_t * +prim_alloc() +{ + prim_t *prim; + + prim = ALLOC(prim_t, 1); + prim->ninputs = 0; + prim->inputs = NIL(prim_node_t *); + prim->noutputs = 0; + prim->outputs = NIL(prim_node_t *); + prim->nodes = NIL(prim_node_t); + prim->edges = NIL(prim_edge_t); + prim->gates = lsCreate(); +#ifdef SIS + prim->latch_type = (int) UNKNOWN; +#endif /* SIS */ + return prim; +} + + +void +prim_free(prim) +prim_t *prim; +{ + prim_edge_t *pe, *pe_next; + prim_node_t *pn, *pn_next; + + for(pn = prim->nodes; pn != 0; pn = pn_next) { + pn_next = pn->next; + FREE(pn->name); + FREE(pn); + } + + for(pe = prim->edges; pe != 0; pe = pe_next) { + pe_next = pe->next; + FREE(pe); + } + + FREE(prim->inputs); + FREE(prim->outputs); + LS_ASSERT(lsDestroy(prim->gates, (void (*)()) 0)); + FREE(prim); +} + + +void +prim_clear_binding(prim) +prim_t *prim; +{ + register prim_node_t *pn; + + for(pn = prim->nodes; pn != NIL(prim_node_t); pn = pn->next) { + pn->binding = NIL(node_t); + } +} + +static void +map_prim_dump_node(fp, pn) +FILE *fp; +prim_node_t *pn; +{ + (void) fprintf(fp, + "\tname=%-10s iso=%d nfanin=%2d nfanout=%2d type=%-3s binding=%08x\n", + pn->name == 0 ? "none" : pn->name, + pn->isomorphic_sons, pn->nfanin, pn->nfanout, + pn->type == PRIMARY_INPUT ? "PI" : + pn->type == PRIMARY_OUTPUT ? "PO" : "INT", + pn->binding); + +#ifdef SIS + (void) fprintf(fp, "\tlatch_output=%d\n", pn->latch_output); +#else + (void) fprintf(fp, "\n"); +#endif /* SIS */ +} + + +static void +map_prim_dump_edge(fp, pe) +FILE *fp; +prim_edge_t *pe; +{ + (void) fprintf(fp, " this_node=%08x connected=%08x dir=%s\n", + pe->this_node, pe->connected_node, + pe->dir == DIR_IN ? "IN" : "OUT"); + if (pe->this_node != 0) map_prim_dump_node(fp, pe->this_node); + if (pe->connected_node != 0) map_prim_dump_node(fp, pe->connected_node); +} + + +void +map_prim_dump(fp, prim, detail) +FILE *fp; +prim_t *prim; +int detail; +{ + lsGen gen; + lib_gate_t *gate; + int i; + prim_node_t *pn; + prim_edge_t *pe; + + (void) fprintf(fp, "matches:"); + lsForeachItem(prim->gates, gen, gate) { + (void) fprintf(fp, " %s", gate->name); + } +#ifdef SIS + /* sequential support */ + switch(prim->latch_type) { + case (int) ACTIVE_HIGH: (void) fprintf(fp, " [type=ACTIVE_HIGH]\n"); break; + case (int) ACTIVE_LOW: (void) fprintf(fp, " [type=ACTIVE_LOW]\n"); break; + case (int) RISING_EDGE: (void) fprintf(fp, " [type=RISING_EDGE]\n"); break; + case (int) FALLING_EDGE: (void) fprintf(fp, " [type=FALLING_EDGE]\n"); break; + case (int) COMBINATIONAL: (void) fprintf(fp, " [type=COMBINATIONAL]\n"); break; + case (int) ASYNCH: (void) fprintf(fp, " [type=ASYNCH]\n"); break; + default: (void) fprintf(fp, " [type=UNKNOWN]\n"); break; + } +#else + (void) fprintf(fp, "\n"); +#endif /* SIS */ + + if (detail) { + (void) fprintf(fp, "ninputs=%d", prim->ninputs); + for(i = 0; i < prim->ninputs; i++) { + map_prim_dump_node(fp, prim->inputs[i]); + } + + (void) fprintf(fp, "noutputs=%d\n", prim->noutputs); + for(i = 0; i < prim->noutputs; i++) { + map_prim_dump_node(fp, prim->outputs[i]); + } + + (void) fprintf(fp, "nodes ...\n"); + for(pn = prim->nodes; pn != 0; pn = pn->next) { + map_prim_dump_node(fp, pn); + } + (void) fprintf(fp, "edges ...\n"); + for(pe = prim->edges; pe != 0; pe = pe->next) { + map_prim_dump_edge(fp, pe); + } + } +} +/* + * given a primitive, find the 'root' of the matching graph node + */ + +node_t * +map_prim_get_root(prim) +prim_t *prim; +{ + return prim->edges->this_node->binding; +} + + +/* check if a node only feeds a real PO */ +static int +prim_feeds_only_real_po(node, po) +node_t *node; +node_t **po; +{ + lsGen gen; + node_t *fanout; + + *po = NIL(node_t); + foreach_fanout(node, gen, fanout) { + if (fanout->type == PRIMARY_OUTPUT) { +#ifdef SIS + if (network_gate_type(node->network) != (int) COMBINATIONAL) { + LS_ASSERT(lsFinish(gen)); + return 0; + } else { +#endif /* SIS */ + /* we should have only one real po */ + assert(*po == NIL(node_t)); + *po = fanout; +#ifdef SIS + } +#endif /* SIS */ + } + } + if (*po != NIL(node_t)) return 1; + return 0; +} + +static node_t * +prim_first_po(network) +network_t *network; +{ + lsGen gen; + node_t *po; + + foreach_primary_output(network, gen, po) { + LS_ASSERT(lsFinish(gen)); + break; + /* NOTREACHED */ + } + return po; +} + diff --git a/sis/map/pwl.c b/sis/map/pwl.c new file mode 100644 index 0000000..19cee0a --- /dev/null +++ b/sis/map/pwl.c @@ -0,0 +1,644 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/pwl.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)pwl.c 1.2 */ +/* last modified on 5/1/91 at 15:51:47 */ +#include "pwl.h" +#include "pwl_static.h" + + /* NOTE: PWL == Piece-Wise Linear function */ + + /* implements a package for piece-wise linear functions */ + /* makes the "optimal" mapper for delay a lot simpler */ + /* no need for discretization!!! */ + /* can throw away bin_util.c!!! */ + + /* This package could have been made a bit more generic */ + /* the essentials are there, the rest would just be cosmetics */ + + + /* computes the max of two pwl functions */ + +pwl_t *pwl_min(f1, f2) +pwl_t *f1; +pwl_t *f2; +{ + return pwl_compute_min(f1, f2); +} + +pwl_t *pwl_max(f1, f2) +pwl_t *f1; +pwl_t *f2; +{ + pwl_t *f; + change_sign(f1); + change_sign(f2); + f = pwl_compute_min(f1, f2); + change_sign(f1); + change_sign(f2); + change_sign(f); + return f; +} + +pwl_t *pwl_sum(f1, f2) +pwl_t *f1; +pwl_t *f2; +{ + return pwl_compute_sum(f1, f2); +} + + /* only positive shifts are allowed */ + +pwl_t *pwl_shift(f, shift) +pwl_t *f; +double shift; +{ + if (f->n_points == 0 || shift == 0.0) return pwl_dup(f); + assert(shift > 0.0); + return compute_pwl_shift(f, shift); +} + + + /* given a bunch of lines, return their linear max: */ + /* that is a sequence of points starting from x=0 */ + /* that represents the max of these lines */ + /* the termination condition is activated when we */ + /* have reached the line with highest slope */ + +pwl_t *pwl_create_linear_max(n_points, points) +int n_points; +pwl_point_t *points; +{ + return create_linear_max(n_points, points); +} + + + /* creates an empty pwl */ + +pwl_t *pwl_create_empty() +{ + pwl_t *result = ALLOC(pwl_t, 1); + result->n_points = 0; + result->points = NIL(pwl_point_t); + return result; +} + + + /* make a copy of a pwl_t */ + +pwl_t *pwl_dup(f) +pwl_t *f; +{ + int i; + pwl_t *new_f = ALLOC(pwl_t, 1); + + *new_f = *f; + if (f->n_points == 0) { + new_f->points = NIL(pwl_point_t); + } else { + new_f->points = ALLOC(pwl_point_t, new_f->n_points); + for (i = 0; i < new_f->n_points; i++) { + new_f->points[i] = f->points[i]; + } + } + return new_f; +} + + /* sort them if necessary */ + +pwl_t *pwl_create(points) +array_t *points; +{ + int i; + pwl_point_t *point; + pwl_t *result; + + if (points == NIL(array_t)) return pwl_create_empty(); + result = ALLOC(pwl_t, 1); + if (array_n(points) == 0) { + result->n_points = 0; + result->points = NIL(pwl_point_t); + } else { + result->n_points = array_n(points); + result->points = ALLOC(pwl_point_t, array_n(points)); + array_sort(points, pwl_point_cmp); + for (i = 0; i < result->n_points; i++) { + point = array_fetch_p(pwl_point_t, points, i); + result->points[i] = *point; + } + } + return result; +} + + /* think they are sorted and unique */ + /* very trusting. Should really be exported??? */ + +pwl_t *pwl_extract(points) +array_t *points; +{ + int i; + pwl_point_t *point; + pwl_t *result; + + if (points == NIL(array_t)) return pwl_create_empty(); + result = ALLOC(pwl_t, 1); + if (array_n(points) == 0) { + result->n_points = 0; + result->points = NIL(pwl_point_t); + } else { + result->n_points = array_n(points); + result->points = ALLOC(pwl_point_t, array_n(points)); + for (i = 0; i < result->n_points; i++) { + point = array_fetch_p(pwl_point_t, points, i); + result->points[i] = *point; + } + } + return result; +} + +void pwl_free(f) +pwl_t *f; +{ + assert (f != NIL(pwl_t)); + if (f->n_points > 0) { + FREE(f->points); + } + FREE(f); +} + +void pwl_print(fp, f, print_data) +FILE *fp; +pwl_t *f; +VoidFn print_data; +{ + int i; + + for (i = 0; i < f->n_points; i++) { + pwl_point_print(fp, &(f->points[i]), print_data); + } +} + + /* assert the same data to all these elements */ + +void pwl_set_data(pwl, data) +pwl_t *pwl; +char *data; +{ + int i; + + for (i = 0; i < pwl->n_points; i++) { + pwl->points[i].data = data; + } +} + + + + /* for a given "abscisse", returns the data */ + /* for the best solution there */ + +char *pwl_select(f, x) +pwl_t *f; +double x; +{ + pwl_point_t *point = pwl_binary_search(f, x); + return point->data; +} + + + /* lookup the interval including a given x */ + +pwl_point_t *pwl_lookup(f, x) +pwl_t *f; +double x; +{ + return pwl_binary_search(f, x); +} + +double pwl_point_eval(point, x) +pwl_point_t *point; +double x; +{ + return point->y + point->slope * (x - point->x); +} + + +char *pwl_point_data(point) +pwl_point_t *point; +{ + return point->data; +} + + + /* INTERNAL INTERFACE */ + +static pwl_point_t *pwl_binary_search(f, value) +pwl_t *f; +double value; +{ + int min, max, middle; + double min_value; + double max_value; + double middle_value; + + /* initialization and special cases */ + if (f->n_points == 0) return NIL(pwl_point_t); + if (f->n_points == 1) return &(f->points[0]); + min = 0; + min_value = f->points[min].x; + if (value <= min_value) return &(f->points[min]); + max = f->n_points - 1; + max_value = f->points[max].x; + if (max_value <= value) return &(f->points[max]); + + /* the binary search itself */ + for (;;) { + middle = min + (max - min) / 2; + if (middle == min) { + assert(value < max_value); + assert(value >= min_value); + break; + } + middle_value = f->points[middle].x; + if (value < middle_value) { + max = middle; + max_value = middle_value; + } else { + min = middle; + min_value = middle_value; + } + } + return &(f->points[min]); +} + + /* avoid copying an entry if prolongating the previous one would do as well */ + +static pwl_t *pwl_compute_min(f1, f2) +pwl_t *f1; +pwl_t *f2; +{ + int intersect_flag; + pwl_t *result; + int indices[2]; + pwl_t *fns[2]; + int select; + double x; + pwl_point_t point; + pwl_point_t *best_point; + array_t *points; + + if (f1->n_points == 0) return pwl_dup(f2); + if (f2->n_points == 0) return pwl_dup(f1); + fns[0] = f1; + fns[1] = f2; + points = array_alloc(pwl_point_t, 0); + point.slope = - INFINITY; + point.data = NIL(char); + first_point(fns, indices, &select, &x, &intersect_flag); + do { + best_point = &(fns[select]->points[indices[select]]); + if (point.data == best_point->data && point.slope == best_point->slope) continue; + point.x = x; + point.y = best_point->y + best_point->slope * (x - best_point->x); + point.slope = best_point->slope; + point.data = best_point->data; + array_insert_last(pwl_point_t, points, point); + } while (next_point(fns, indices, &select, &x, &intersect_flag)); + + /* copy the array points in the result */ + /* if two consecutive entries with same slope and same data */ + /* we do not need to keep the second one */ + result = pwl_extract(points); + array_free(points); + return result; +} + +static void first_point(fns, indices, select_p, x_p, intersect_flag_p) +pwl_t **fns; +int *indices; +int *select_p; +double *x_p; +int *intersect_flag_p; +{ + double diff; + + *x_p = 0.0; + indices[0] = indices[1] = 0; + diff = fns[0]->points[0].y - fns[1]->points[0].y; + if (diff == 0) { + diff = fns[0]->points[0].slope - fns[1]->points[0].slope; + } + *select_p = (diff <= 0) ? 0 : 1; + *intersect_flag_p = 0; +} + + + /* returns 1 iff there is something left, 0 otherwise */ + +static int next_point(fns, indices, select_p, x_p, intersect_flag_p) +pwl_t **fns; +int *indices; +int *select_p; +double *x_p; +int *intersect_flag_p; +{ + int i; + double diff; + double min; + double mins[2]; + double intersect; + pwl_point_t *seg[2]; + + /* first compute the next interesting x: */ + /* either the end of current interval or the intersection of the two current segments */ + /* if previous one was intersection, can't be intersection again: avoid recomputing */ + min = INFINITY; + for (i = 0; i < 2; i++) { + mins[i] = (fns[i]->n_points - 1 == indices[i]) ? INFINITY : fns[i]->points[indices[i] + 1].x; + min = MIN(min, mins[i]); + } + if (*intersect_flag_p) { + intersect = - INFINITY; + } else { + intersect = compute_intersect(&(fns[0]->points[indices[0]]), &(fns[1]->points[indices[1]])); + } + if (intersect > *x_p && intersect < min) { + *intersect_flag_p = 1; + *x_p = intersect; + } else if (mins[0] == INFINITY && mins[1] == INFINITY) { + return 0; + } else { + *intersect_flag_p = 0; + *x_p = min; + } + + /* now we need to determine which is the better fn */ + + if (*intersect_flag_p) { + /* after intersection point, the better one is the one with lower slope */ + diff = fns[0]->points[indices[0]].slope - fns[1]->points[indices[1]].slope; + assert(diff != 0); + *select_p = (diff < 0) ? 0 : 1; + return 1; + } + + /* need to go to next interval if it was reached */ + if (min >= mins[0]) indices[0]++; + if (min >= mins[1]) indices[1]++; + + /* the better one is the one that evaluates for less now */ + seg[0] = &(fns[0]->points[indices[0]]); + seg[1] = &(fns[1]->points[indices[1]]); + diff = (seg[0]->y + seg[0]->slope * (*x_p - seg[0]->x)) - (seg[1]->y + seg[1]->slope * (*x_p - seg[1]->x)); + if (diff == 0) { + /* if intersect at this point, the one with smaller slope wins */ + diff = seg[0]->slope - seg[1]->slope; + } + *select_p = (diff <= 0) ? 0 : 1; + return 1; +} + +static pwl_t *pwl_compute_sum(f1, f2) +pwl_t *f1; +pwl_t *f2; +{ + int i; + int select; + double diff; + int indices[2]; + pwl_t *fns[2]; + pwl_point_t *points[2]; + pwl_point_t point; + array_t *array_of_points; + pwl_t *result; + + if (f1->n_points == 0) return pwl_dup(f2); + if (f2->n_points == 0) return pwl_dup(f1); + + /* this code works only if starting points of the two functions are the same */ + assert(f1->points[0].x == f2->points[0].x); + + fns[0] = f1; + fns[1] = f2; + + /* put points in this array; build the result from that at the end */ + array_of_points = array_alloc(pwl_point_t, 0); + + /* pointers to the points in each fi */ + indices[0] = indices[1] = 0; + + /* if a point has been visited, the pointer is incremented */ + /* at the end. Indices outside the range */ + /* need special treatment to take care of remaining points */ + for (;;) { + if (indices[0] == fns[0]->n_points && indices[1] == fns[1]->n_points) break; + for (i = 0; i < 2; i++) { + if (indices[i] < fns[i]->n_points) { + points[i] = &(fns[i]->points[indices[i]]); + } else { + points[i] = &(fns[i]->points[indices[i]]); + } + } + diff = points[0]->x - points[1]->x; + select = (diff <= 0) ? 0 : 1; + if (indices[select] == fns[select]->n_points) select = 1 - select; + assert(indices[select] < fns[select]->n_points); + point.x = points[select]->x; + point.y = points[0]->y + (point.x - points[0]->x) * points[0]->slope; + point.y += points[1]->y + (point.x - points[1]->x) * points[1]->slope; + point.slope = points[0]->slope + points[1]->slope; + point.data = points[select]->data; + array_insert_last(pwl_point_t, array_of_points, point); + indices[select]++; + if (diff == 0) { + assert(indices[1 - select] < fns[1 - select]->n_points); + indices[1 - select]++; + } + } + + /* copy the array array_of_points in the result */ + result = pwl_extract(array_of_points); + array_free(array_of_points); + return result; +} + + +static void pwl_point_print(fp, point, print_data) +FILE *fp; +pwl_point_t *point; +VoidFn print_data; +{ + (void) fprintf(fp, "%2.2f %2.2f %2.2f ", point->x, point->y, point->slope); + (*print_data)(fp, point->data); + (void) fprintf(fp, "\n"); +} + +static int pwl_point_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + double diff; + pwl_point_t *p1 = (pwl_point_t *) obj1; + pwl_point_t *p2 = (pwl_point_t *) obj2; + + diff = p1->x - p2->x; + if (diff < 0) return -1; + if (diff > 0) return 1; + return 0; +} + + /* return the point where the two lines intersect */ + /* or - INFINITY if they are parallel */ +static double compute_intersect(p1, p2) +pwl_point_t *p1; +pwl_point_t *p2; +{ + if (p1->slope == p2->slope) return (double) - INFINITY; + return (((p2->y - p2->slope * p2->x) - (p1->y - p1->slope * p1->x)) / (p1->slope - p2->slope)); +} + + /* exact in the interval 0 <= x <= INFINITY */ + +static pwl_t *create_linear_max(n_lines, origins) +int n_lines; +pwl_point_t *origins; +{ + double x, next_x; + double max_slope; + double intersect; + int i; + int selected; + int *valid; + array_t *points; + pwl_point_t point; + pwl_t *result; + + valid = ALLOC(int, n_lines); + for (i = 0; i < n_lines; i++) { + valid[i] = 1; + } + x = 0.0; + points = array_alloc(pwl_point_t, 0); + max_slope = compute_max_slope(n_lines, origins); + + for (;;) { + /* take the largest line at this time that is still valid */ + /* if floating point were exact, there would be no need to check for validity */ + /* but the intersection point may be interestimated by the FP hardware */ + /* in that case we need to make sure that we do not select a line already selected */ + selected = compute_argmax_y(x, n_lines, origins, valid); + point.x = x; + point.y = origins[selected].y + origins[selected].slope * x; + point.slope = origins[selected].slope; + point.data = origins[selected].data; + array_insert_last(pwl_point_t, points, point); + valid[selected] = 0; + + /* if reached the largest slope, nothing will ever intersect it in the future */ + if (point.slope == max_slope) break; + + /* compute the next interesting point */ + next_x = INFINITY; + for (i = 0; i < n_lines; i++) { + if (! valid[i]) continue; + if (point.slope >= origins[i].slope) { + valid[i] = 0; + continue; + } + intersect = compute_intersect(&point, &origins[i]); + /* need to make some progress */ + if (intersect <= x) continue; + next_x = MIN(next_x, intersect); + } + /* this means intersection only after INFINITY: ignore the rest */ + if (next_x >= INFINITY) break; + x = next_x; + } + FREE(valid); + result = pwl_extract(points); + array_free(points); + return result; +} + +static double compute_max_slope(n_lines, points) +int n_lines; +pwl_point_t *points; +{ + int i; + double slope = - INFINITY; + + for (i = 0; i < n_lines; i++) { + slope = MAX(slope, points[i].slope); + } + return slope; +} + +static int compute_argmax_y(x, n_lines, points, valid) +double x; +int n_lines; +pwl_point_t *points; +int *valid; +{ + int i; + double y, tmp_y; + int argmax_y; + double slope; + + y = - INFINITY; + slope = - INFINITY; + argmax_y = -1; + for (i = 0; i < n_lines; i++) { + if (! valid[i]) continue; + tmp_y = points[i].y + points[i].slope * (x - points[i].x); + if (y < tmp_y || (y == tmp_y && slope < points[i].slope)) { + argmax_y = i; + y = tmp_y; + slope = points[i].slope; + } + } + assert(argmax_y != -1); + return argmax_y; +} + +static void change_sign(f) +pwl_t *f; +{ + register pwl_point_t *to; + register pwl_point_t *from; + + if (f->n_points == 0) return; + to = f->points + f->n_points; + for (from = f->points; from < to; from++) { + from->y = - from->y; + from->slope = - from->slope; + } +} + +static pwl_t *compute_pwl_shift(f, shift) +pwl_t *f; +double shift; +{ + pwl_t *result; + pwl_point_t point; + pwl_point_t *ptr = pwl_binary_search(f, shift); + pwl_point_t *to = f->points + f->n_points; + array_t *array_of_points = array_alloc(pwl_point_t, 0); + + point = *ptr; + point.y += point.slope * (shift - point.x); + point.x = 0.0; + array_insert_last(pwl_point_t, array_of_points, point); + for (ptr++; ptr < to; ptr++) { + point = *ptr; + point.x -= shift; + array_insert_last(pwl_point_t, array_of_points, point); + } + result = pwl_extract(array_of_points); + array_free(array_of_points); + return result; +} diff --git a/sis/map/pwl.h b/sis/map/pwl.h new file mode 100644 index 0000000..fcc44e3 --- /dev/null +++ b/sis/map/pwl.h @@ -0,0 +1,77 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/pwl.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)pwl.h 1.7 */ +/* last modified on 7/25/91 at 11:45:54 */ +/* + * $Log: pwl.h,v $ + * Revision 1.1.1.1 2004/02/07 10:14:26 pchong + * imported + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 22:00:59 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:40:53 sis + * Initial revision + * + * Revision 1.1 91/07/02 11:18:35 touati + * Initial revision + * + */ +#ifndef PWL_H +#define PWL_H + +#include "sis.h" + + /* implements piece-wise linear scalar valued functions */ + +typedef struct { + double x; + double y; + double slope; + char *data; +} pwl_point_t; + +typedef struct { + int n_points; + pwl_point_t *points; +} pwl_t; + +#ifndef INFINITY +#define INFINITY 0x7fffffff +#endif + +extern pwl_t *pwl_min(/* pwl_t *f1, pwl_t *f2 */); +extern pwl_t *pwl_max(/* pwl_t *f1, pwl_t *f2 */); +extern pwl_t *pwl_sum(/* pwl_t *f1, pwl_t *f2 */); +extern pwl_t *pwl_shift(/* pwl_t *f, double shift */); +extern pwl_t *pwl_create_linear_max(/* int n_points; pwl_point_t *points; */); +extern pwl_t *pwl_dup(/* pwl_t *f; */); + + /* sort the points if necessary; should be made same interface as create_linear_max */ +extern pwl_t *pwl_create(/* array_t *points; */); + /* does not sort */ +extern pwl_t *pwl_extract(/* array_t *points; */); +extern void pwl_free(/* pwl_t *f; */); +extern void pwl_print(/* FILE *fp; pwl_t *f; VoidFn print_data; */); +extern void pwl_set_data(/* pwl_t *pwl; char *data; */); +extern pwl_point_t *pwl_lookup(/* pwl_t *f; double x; */); +extern double pwl_point_eval(/* pwl_point_t *point, double x */); +extern char *pwl_point_data(/* pwl_point_t *point */); +extern pwl_t *pwl_create_empty(/* */); + +typedef struct { + pwl_t *rise; + pwl_t *fall; +} delay_pwl_t; + +#endif /* PWL_H */ diff --git a/sis/map/pwl_static.h b/sis/map/pwl_static.h new file mode 100644 index 0000000..d1cd7c4 --- /dev/null +++ b/sis/map/pwl_static.h @@ -0,0 +1,24 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/pwl_static.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)pwl_static.h 1.2 */ +/* last modified on 5/1/91 at 15:51:51 */ +static double compute_intersect(); +static double compute_max_slope(); +static int compute_argmax_y(); +static int next_point(); +static int pwl_point_cmp(); +static pwl_point_t *pwl_binary_search(); +static pwl_t *compute_pwl_shift(); +static pwl_t *create_linear_max(); +static pwl_t *pwl_compute_min(); +static pwl_t *pwl_compute_sum(); +static void change_sign(); +static void first_point(); +static void pwl_point_print(); diff --git a/sis/map/replace.c b/sis/map/replace.c new file mode 100644 index 0000000..016bbfb --- /dev/null +++ b/sis/map/replace.c @@ -0,0 +1,241 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/replace.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2005/03/08 03:50:52 $ + * + */ +/* file @(#)replace.c 1.2 */ +/* last modified on 5/1/91 at 15:51:53 */ + +#include "sis.h" + + /* simple optimization */ + /* goes thru the network, and looks at */ + /* all the 2-input OR gate nodes */ + /* for each of them, remember their function in a simple */ + /* structure. Only consider the nodes with fanout == 1 */ + /* Then visit the network from inputs to outputs */ + /* for each of these nodes, put them in a hash table */ + /* using their function as key. If something is already in the hash table */ + /* replace one node by the other. Then both of these nodes are no longer of interest */ + /* (one is of fanout 2, the other one of fanout 0) so remove them. */ + /* continue until no more substitution is possible */ + +static int fncmp(); +static int get_literal(); +static int node_skip(); +static unsigned int fnhash(); +static void extract_node_fn(); +static void replace_node(); +static void smaller_pointer_first(); + +typedef struct { + node_t *fanin[2]; + int phase[2]; +} node_fn_t; + + +void replace_2or(network, verbose) +network_t *network; +int verbose; +{ + int i; + int has_changed; + st_generator *gen; + node_t *node, *replaced_node; + node_fn_t *fn; + array_t *nodevec = network_dfs(network); + st_table *node_table = st_init_table(st_numcmp, st_numhash); + st_table *visited = st_init_table(fncmp, (ST_PFICPI) fnhash); + + /* remove unnecessary buffers that may blur the computation of n_fanouts */ + network_csweep(network); + + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + /* store an easy-to-manipulate fn from the node */ + /* do it only if node is 2-input OR gate */ + /* and the fanout of the node is 1 */ + if (node_skip(node)) continue; + extract_node_fn(node_table, node); + } + do { + has_changed = 0; + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node_skip(node)) continue; + if (! st_lookup(node_table, (char *) node, (char **) &fn)) continue; + if (! st_lookup(visited, (char *) fn, (char **) &replaced_node)) { + st_insert(visited, (char *) fn, (char *) node); + continue; + } + if (node == replaced_node) continue; + if (verbose) (void) fprintf(sisout, "replace node %s by %s\n", replaced_node->name, node->name); + replace_node(node_table, visited, node, replaced_node); + /* the node "replaced_node" has been swept away at this point */ + has_changed = 1; + st_delete(visited, (char **) &fn, NIL(char *)); + st_delete(node_table, (char **) &node, (char **) &fn); + FREE(fn); + st_delete(node_table, (char **) &replaced_node, (char **) &fn); + FREE(fn); + } + } + while(has_changed == 1); + st_foreach_item(node_table, gen, (char **) &node, (char **) &fn) { + FREE(fn); + } + st_free_table(node_table); + st_free_table(visited); + array_free(nodevec); +} + + /* returns 1 iff node is not a 2-input OR gate */ + /* with fanout of 1 */ + +static int node_skip(node) +node_t *node; +{ + if (node_function(node) != NODE_OR) return 1; + if (node_num_fanin(node) != 2) return 1; + if (node_num_fanout(node) != 1) return 1; + return 0; +} + +static void extract_node_fn(table, node) +st_table *table; +node_t *node; +{ + int i, j; + int n_cubes = node_num_cube(node); + int fn_array[2][2]; + node_fn_t *fn; + + assert(n_cubes == 2); + assert(node_num_fanin(node) == 2); + assert(node_function(node) == NODE_OR); + fn = ALLOC(node_fn_t, 1); + fn->fanin[0] = node_get_fanin(node, 0); + fn->fanin[1] = node_get_fanin(node, 1); + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + fn_array[i][j] = get_literal(node, i, j); /* i->cube, j->literal */ + } + } + for (j = 0; j < 2; j++) { + assert(fn_array[0][j] == 2 || fn_array[1][j] == 2); + assert(fn_array[0][j] != 2 || fn_array[1][j] != 2); + fn->phase[j] = (fn_array[0][j] == 2) ? fn_array[1][j] : fn_array[0][j]; + } + smaller_pointer_first(fn); + st_insert(table, (char *) node, (char *) fn); +} + +static int get_literal(node, row, literal) +node_t *node; +int row; +int literal; +{ + node_cube_t cube = node_get_cube(node, row); + switch(node_get_literal(cube, literal)) { + case ZERO: + return 0; + case ONE: + return 1; + default: + return 2; + } +} + +static unsigned int fnhash(obj, modulus) +char *obj; +unsigned int modulus; +{ + node_fn_t *fn = (node_fn_t *) obj; + unsigned int n; + + n = (unsigned int) ((int) fn->fanin[0] + (int) fn->fanin[1] + fn->phase[0] * 2 + fn->phase[1]); + return n % modulus; +} + +static int fncmp(obj1, obj2) +char *obj1; +char *obj2; +{ + node_fn_t *fn1 = (node_fn_t *) obj1; + node_fn_t *fn2 = (node_fn_t *) obj2; + + if (fn1->fanin[0] != fn2->fanin[0]) return 1; + if (fn1->fanin[1] != fn2->fanin[1]) return 1; + if (fn1->phase[0] != fn2->phase[0]) return 1; + if (fn1->phase[1] != fn2->phase[1]) return 1; + return 0; +} + + /* a little bit convoluted */ + /* have to make sure that the node "fanout", in which "replaced" */ + /* is now replaced by "node" is correctly stored in node_table */ + /* and visited table. To do so, need to change its function */ + /* in node_table to make sure it reflects the change. */ + /* if it was visited, we also need to remove that entry in visited */ + /* and rehash it with the new function */ + +static void replace_node(node_table, visited, node, replaced) +st_table *node_table; +st_table *visited; +node_t *node; +node_t *replaced; +{ + node_fn_t *old_fn, *tmp, *new_fn; + node_t *visited_node; + node_t *fanout; + int was_visited; + + assert(node_num_fanout(replaced) == 1); + fanout = node_get_fanout(replaced, 0); + assert(node_substitute(replaced, node, 0)); + if (! st_lookup(node_table, (char *) fanout, (char **) &old_fn)) { + network_sweep_node(fanout); + return; + } + was_visited = 0; + if (st_lookup(visited, (char *) old_fn, (char **) &visited_node)) { + if (fanout == visited_node) { + was_visited = 1; + tmp = old_fn; + st_delete(visited, (char **) &old_fn, NIL(char *)); + assert(tmp == old_fn); + } + } + if (old_fn->fanin[0] == replaced) { + old_fn->fanin[0] = node; + } else { + assert(old_fn->fanin[1] == replaced); + old_fn->fanin[1] = node; + } + smaller_pointer_first(old_fn); + new_fn = old_fn; + if (was_visited) st_insert(visited, (char *) new_fn, (char *) fanout); + network_sweep_node(fanout); +} + + /* makes sure that the smaller node pointer */ + /* is stored first (for commutativity of OR) */ + /* if not, swap */ +static void smaller_pointer_first(fn) +node_fn_t *fn; +{ + node_t *tmp_node; + int tmp_int; + + if ((int) fn->fanin[0] < (int) fn->fanin[1]) return; + tmp_node = fn->fanin[1]; + fn->fanin[1] = fn->fanin[0]; + fn->fanin[0] = tmp_node; + tmp_int = fn->phase[1]; + fn->phase[1] = fn->phase[0]; + fn->phase[0] = tmp_int; +} diff --git a/sis/map/top_down.c b/sis/map/top_down.c new file mode 100644 index 0000000..67277b5 --- /dev/null +++ b/sis/map/top_down.c @@ -0,0 +1,322 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/top_down.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ + +/* + * File that interfaces the algorithm "top_down" to the buffering algorithm + * in the speed package (that can be invoked by the command "buffer_opt") + */ +#include <math.h> +#include "sis.h" +#include "map_int.h" +#include "fanout_int.h" +#include "fanout_delay.h" + +#define BUF_MIN_DELAY(result,t1,t2) \ + ((result).rise=MIN((t1).rise,(t2).rise), \ + (result).fall=MIN((t1).fall,(t2).fall)) + +static int fanout_optimize(); +static void put_tree_in_fanout_tree_order(); + +/* + * No longer needed since the corresponding assertions have been commented out + */ +/* +static node_t *get_fanin_from_link(); +*/ + + + /* EXTERNAL INTERFACE */ + + /* ARGSUSED */ +static int top_down_mode; +void top_down_set_mode(alg, property) +fanout_alg_t *alg; +alg_property_t *property; +{ + top_down_mode = property->value; +} + + /* ARGSUSED */ +static int top_down_debug; +void top_down_set_debug(alg, property) +fanout_alg_t *alg; +alg_property_t *property; +{ + top_down_debug = property->value; +} + + /* ARGSUSED */ +void top_down_init(network, alg) +network_t *network; +fanout_alg_t *alg; +{ + alg->optimize = fanout_optimize; + if (top_down_mode & 1) { + fprintf(sisout, "WARNING: lowest bit of mode for top_down ignored\n"); + top_down_mode--; + } + buf_init_top_down(network, top_down_mode, top_down_debug); +} + + + /* INTERNAL INTERFACE */ +extern delay_time_t map_compute_fanout_tree_req_time(); /* fanout_tree.c */ + +static int +fanout_optimize(fanout_info, tree, cost) +opt_array_t *fanout_info; /* fanout_info[POLAR_X] lists the positive polarity sinks; POLAR_Y negative */ +array_t *tree; /* array in which the result tree is stored: format of fanout_tree.c */ +fanout_cost_t *cost; /* contains information on the result: required times, area */ +{ + lsGen gen; + lib_gate_t *gate; + gate_link_t *link; + st_table *fo_table; + double auto_route, load, def_dr; + network_t *network, *dup_network; + node_t *node, *temp1, *temp, **new_pi, *fo, *inv_node, *new_fo; + node_t *dup_node, *dup_inv_node; + buf_alg_input_t *fanout_data; + delay_pin_t *pin_delay, *inv_pin_delay; + delay_model_t model = buf_get_model(); + delay_time_t t, root_required, inp_req, drive; + int source_index, polarity; + int nin, pin, i, total, num_pos; + + /* + * Setup the data in the required structures + */ + inv_node = fanout_opt_get_root_inv(); + node = fanout_opt_get_root(); + network = node_network(node); + + /* HACK --- Need the appropriate structure of nodes in the network */ + auto_route = buf_get_auto_route(); + + /* + * Create a separate network and add the relevant data to it + */ + gate = lib_gate_of(node); + if (node->type == INTERNAL && gate == NIL(lib_gate_t)){ + /* We always expect to see a mapped gate */ + return 0; + } + + dup_network = network_alloc(); + if (node->type == INTERNAL) { + nin = lib_gate_num_in(gate); + new_pi = ALLOC(node_t *, nin); + for (i = 0; i < nin; i++){ + new_pi[i] = node_alloc(); + network_add_primary_input(dup_network, new_pi[i]); + } + /* + * Create a node with the right number of inputs + * and annotate it with the gate + */ + dup_node = node_constant(1); + for (i = 0; i < nin; i++){ + temp = node_literal(new_pi[i], 1); + temp1 = node_and(temp, dup_node); + node_free(dup_node); + node_free(temp); + dup_node = temp1; + } + network_add_node(dup_network, dup_node); + buf_add_implementation(dup_node, gate); + FREE(new_pi); + } else { + dup_node = node_dup(node); + network_add_primary_input(dup_network, dup_node); + if (!delay_get_pi_drive(dup_node, &drive)){ + def_dr = delay_get_default_parameter(node_network(node), DELAY_DEFAULT_DRIVE_RISE); + if (def_dr == DELAY_NOT_SET) def_dr = 0.0; + delay_set_parameter(dup_node, DELAY_DRIVE_RISE, def_dr); + + def_dr = delay_get_default_parameter(node_network(node), DELAY_DEFAULT_DRIVE_FALL); + if (def_dr == DELAY_NOT_SET) def_dr = 0.0; + delay_set_parameter(dup_node, DELAY_DRIVE_FALL, def_dr); + } + } + + /* If we need an inverter --- create it too */ + if (inv_node != NIL(node_t) && lib_gate_of(inv_node) != NIL(lib_gate_t)){ + dup_inv_node = node_literal(dup_node, 0); + network_add_node(dup_network, dup_inv_node); + } else { + dup_inv_node = NIL(node_t); + } + + source_index = fanout_delay_get_source_index(node); + polarity = fanout_delay_get_source_polarity(source_index); + + fo_table = st_init_table(st_ptrcmp, st_ptrhash); + fanout_data = ALLOC(buf_alg_input_t, 1); + fanout_data->max_ip_load = INFINITY; + total = fanout_info[0].n_elts + fanout_info[1].n_elts; + fanout_data->fanouts = ALLOC(sp_fanout_t, total); + for (i = 0; i < fanout_info[polarity].n_elts; i++){ + link = array_fetch(gate_link_t *, fanout_info[polarity].required, i); + /* + assert((fanin = get_fanin_from_link(link, &fanin_index)) != NIL(node_t)); + */ + new_fo = network_add_primary_output(dup_network, dup_node); + fanout_data->fanouts[i].pin = 0; + fanout_data->fanouts[i].fanout = new_fo; + fanout_data->fanouts[i].load = link->load; + fanout_data->fanouts[i].req = link->required; + fanout_data->fanouts[i].phase = PHASE_NONINVERTING; + (void)st_insert(fo_table, (char *)(new_fo), (char *)link); + delay_set_parameter(new_fo, DELAY_REQUIRED_RISE, link->required.rise); + delay_set_parameter(new_fo, DELAY_REQUIRED_FALL, link->required.fall); + delay_set_parameter(new_fo, DELAY_OUTPUT_LOAD, link->load); + } + num_pos = i; + for (i = 0; i < fanout_info[1-polarity].n_elts; i++){ + link = array_fetch(gate_link_t *, fanout_info[1-polarity].required, i); + /* + assert((fanin = get_fanin_from_link(link, &fanin_index)) != NIL(node_t)); + */ + new_fo = network_add_primary_output(dup_network, dup_inv_node); + fanout_data->fanouts[num_pos+i].pin = 0; + fanout_data->fanouts[num_pos+i].load = link->load; + fanout_data->fanouts[num_pos+i].fanout = new_fo; + fanout_data->fanouts[num_pos+i].req = link->required; + fanout_data->fanouts[num_pos+i].phase = PHASE_INVERTING; + (void)st_insert(fo_table, (char *)(new_fo), (char *)link); + delay_set_parameter(new_fo, DELAY_REQUIRED_RISE, link->required.rise); + delay_set_parameter(new_fo, DELAY_REQUIRED_FALL, link->required.fall); + delay_set_parameter(new_fo, DELAY_OUTPUT_LOAD, link->load); + } + fanout_data->num_pos = num_pos; + fanout_data->num_neg = i; + fanout_data->root = dup_node; + fanout_data->node = dup_node; + fanout_data->inv_node = dup_inv_node; + + + pin_delay = get_pin_delay(dup_node, 0, model); + t.rise = t.fall = 0.0; + buf_set_prev_drive(dup_node, t); + buf_set_prev_phase(dup_node, PHASE_NONINVERTING); + + load = 0; + if (dup_inv_node != NIL(node_t)){ + assert(fanout_data->num_neg > 0); + if ((gate = lib_gate_of(inv_node)) != NIL(lib_gate_t)) { + buf_add_implementation(dup_inv_node, gate); + } + buf_set_prev_drive(dup_inv_node, pin_delay->drive); + buf_set_prev_phase(dup_inv_node, pin_delay->phase); + inv_pin_delay = get_pin_delay(dup_inv_node, 0, model); + load = inv_pin_delay->load + auto_route; + t = *(fanout_info[1-polarity].min_required); + sp_subtract_delay(inv_pin_delay->phase, inv_pin_delay->block, + inv_pin_delay->drive, fanout_info[1-polarity].total_load, &t); + buf_set_required_time_at_input(dup_inv_node, t); + } + + if (num_pos > 0){ + BUF_MIN_DELAY(t, t, *(fanout_info[polarity].min_required)); + } + sp_subtract_delay(pin_delay->phase, pin_delay->block, + pin_delay->drive, (load + fanout_info[polarity].total_load), &t); + buf_set_required_time_at_input(dup_node, t); + + /* Call the recursive algorithm */ + buf_map_interface(dup_network, fanout_data); + + /* Build the tree && evaluate the cost of the fanout structure */ + cost->area = 0; + put_tree_in_fanout_tree_order(network, tree, dup_node, dup_node, + dup_inv_node, source_index, fo_table, &(cost->area)); + cost->slack = map_compute_fanout_tree_req_time(tree); + + network_free(dup_network); + st_free_table(fo_table); + FREE(fanout_data->fanouts); + FREE(fanout_data); + + if (top_down_debug) { + (void) fprintf(sisout,"Done top_down -- Area %f , Slack %f:%f\n", + cost->area, cost->slack.rise, cost->slack.fall); + } + return 1; +} + + +/* + * Creates the data structure for returning to the fanout interface -- + * At the same time it deletes all the nodes that were created + */ +static void +put_tree_in_fanout_tree_order(network, tree, node, root, root_inv, + source_index, fo_table, a) +network_t *network; +array_t *tree; +node_t *node, *root, *root_inv; +int source_index; +st_table *fo_table; +double *a; /* Total area */ +{ + lsGen gen; + lib_gate_t *gate; + gate_link_t *link; + int gate_index; + node_t *fanout; + + if (st_lookup(fo_table, (char *)node, (char **)&link)){ + fanout_tree_insert_sink(tree, link); + } else { + gate = lib_gate_of(node); + if (node == root){ + /* The gate_index is the source index */ + gate_index = source_index; + } else { + /* get the appropriate gate_index from the lib_gate_t */ + gate_index = fanout_delay_get_buffer_index(gate); + *a += lib_gate_area(gate); + } + fanout_tree_insert_gate(tree, gate_index, node_num_fanout(node)); + foreach_fanout(node, gen, fanout) { + put_tree_in_fanout_tree_order(network, tree, fanout, root, root_inv, + source_index, fo_table, a); + } + } +} + +/* +static node_t * +get_fanin_from_link(link, index) +gate_link_t *link; +int *index; +{ + node_t *fanin; + + if (link->node->type == PRIMARY_OUTPUT){ + fanin = node_get_fanin(link->node, 0); + *index = 0; + } else if (link->node->type == INTERNAL){ + if (MAP(link->node)->gate == NIL(lib_gate_t)){ + return NIL(node_t); + } else { + fanin = MAP(link->node)->save_binding[link->pin]; + *index = node_get_fanin_index(link->node, fanin); + assert(*index >= 0); + } + } else { + fanin = NIL(node_t); + } + return fanin; +} +*/ + +#undef BUF_MIN_DELAY diff --git a/sis/map/tree.c b/sis/map/tree.c new file mode 100644 index 0000000..6f82d07 --- /dev/null +++ b/sis/map/tree.c @@ -0,0 +1,121 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/tree.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)tree.c 1.2 */ +/* last modified on 5/1/91 at 15:51:57 */ +#include "sis.h" +#include "map_int.h" + + +static int is_binary_tree(); +static int tree_equal(); +static void mark_isomorphic_nodes(); + + +st_table * +map_find_isomorphisms(network) +network_t *network; +{ + st_table *visited, *isomorphic_sons; + node_t *node; + lsGen gen; + + isomorphic_sons = st_init_table(st_ptrcmp, st_ptrhash); + + if (network_num_po(network) == 1) { + visited = st_init_table(st_ptrcmp, st_ptrhash); + + /* actually, there is only 1 output */ + foreach_primary_output(network, gen, node) { + if (is_binary_tree(node, visited)) { + mark_isomorphic_nodes(node, isomorphic_sons); + } + } + st_free_table(visited); + } + + return isomorphic_sons; +} + + +static int +is_binary_tree(node, visited) +node_t *node; +st_table *visited; +{ + int i; + node_t *fanin; + + if (st_lookup(visited, (char *) node, NIL(char *))) { + return 0; /* is not a tree */ + } else { + (void) st_insert(visited, (char *) node, NIL(char)); + if (node_num_fanin(node) > 2) { + return 0; /* is not unary or binary */ + } + foreach_fanin(node, i, fanin) { + if (! is_binary_tree(fanin, visited)) { + return 0; + } + } + return 1; /* passes as a unary/binary tree */ + } +} + + +static int +tree_equal(node1, node2) +node_t *node1, *node2; +{ + int eql; + + if (node_num_fanin(node1) != node_num_fanin(node2)) { + return 0; + } + + switch(node_num_fanin(node1)) { + case 0: + eql = 1; + break; + case 1: + eql = tree_equal(node_get_fanin(node1, 0), node_get_fanin(node2, 0)); + break; + case 2: + eql = (tree_equal(node_get_fanin(node1, 0), node_get_fanin(node2, 0)) && + tree_equal(node_get_fanin(node1, 1), node_get_fanin(node2, 1))) + || + (tree_equal(node_get_fanin(node1, 0), node_get_fanin(node2, 1)) && + tree_equal(node_get_fanin(node1, 1), node_get_fanin(node2, 0))); + break; + default: + fail("bad node degree in tree_equal"); + /* NOTREACHED */ + } + return eql; +} + + +static void +mark_isomorphic_nodes(node, isomorphic_sons) +node_t *node; +st_table *isomorphic_sons; +{ + int i; + node_t *fanin; + + foreach_fanin(node, i, fanin) { + mark_isomorphic_nodes(fanin, isomorphic_sons); + } + + if (node_num_fanin(node) == 2) { + if (tree_equal(node_get_fanin(node, 0), node_get_fanin(node, 1))) { + (void) st_insert(isomorphic_sons, (char *) node, NIL(char)); + } + } +} diff --git a/sis/map/treemap.c b/sis/map/treemap.c new file mode 100644 index 0000000..8013800 --- /dev/null +++ b/sis/map/treemap.c @@ -0,0 +1,1013 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/treemap.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)treemap.c 1.9 */ +/* last modified on 7/22/91 at 12:36:35 */ +#include "sis.h" +#include <math.h> +#include "map_macros.h" +#include "map_int.h" +#include "lib_int.h" +#include "map_delay.h" +#include "fanout_int.h" + +static int do_tree_match(); +static int find_best_match(); +static void find_match_cost(); +static void match_cost(); +static node_t *build_network_recur(); +static int inverter_optimize(); + +static int global_debug, global_inverter_optz; +static double global_area_mode, global_thresh; +static int g_allow_internal_fanout; +static bin_global_t global; + +/* debugger support ... till we get something better than DBX */ +/* typedef char * STRING; + * static char myname[512]; + * static char *mystr; + * static lib_gate_t *mygate; + * static lsGen mygen; + * static node_t *mynode; + */ + +static double max_arrival_estimate; +static double area_estimate; + +#ifdef SIS +/* sequential support */ +static int is_buffer(); +static char *prim_gate_name(); +static int is_transitive_fanin(); +#if !defined(lint) && !defined(SABER) +static void map_print_network(); +#endif +static void hack_po(); +#endif + +/* + * exported interface ... + */ + +network_t * +map_network(network, library, mode, inv_optz, allow_internal_fanout) +network_t *network; +library_t *library; +double mode; +int inv_optz, allow_internal_fanout; +{ + bin_global_t globals; + int argc; + char **argv; + + argc = 0; + argv = NIL(char *); + (void) map_fill_options(&globals, &argc, &argv); + globals.old_mode = mode; + globals.remove_inverters = 1; + globals.inverter_optz = inv_optz; + globals.allow_internal_fanout = allow_internal_fanout; + globals.library = library; + globals.no_warning = 1; + + return complete_map_interface(network, &globals); +} + +/* + * tree_map -- implement 'network' using the tree-matching algorithm + */ +int +tree_map(network, library, globals) +network_t *network; +library_t *library; +bin_global_t globals; +{ + global = globals; + global.library = library; + global_debug = globals.verbose; /* needed for find_best_match() ! */ + global_area_mode = globals.old_mode; /* needed for find_best_match() ! */ + global_thresh = globals.thresh; + global_inverter_optz = globals.inverter_optz; /* needed for find_best_match() ! */ + g_allow_internal_fanout = globals.allow_internal_fanout; + + area_estimate = 0.0; /* for final heuristics checking */ + max_arrival_estimate = 0.0; /* for final heuristics checking */ + + return do_tree_match(network, library, &globals); +} + +/* + * premap: set each node to be a nand gate or an inverter + * we do this regardless of whether we are using 'nand' gates or 'nor' + * gates in order to time the circuit based on nand gates; note that + * this may change the logic function (if we stopped now); however, + * all pattern matching, etc. is strictly topological based. + */ + +int +do_tree_premap(network, library) +network_t *network; +library_t *library; +{ + lsGen gen; + network_t *libnet; + node_t *pi, *node; + lib_gate_t *gate, *zero, *one, *inv, *nand2; + char **inv_formal, **nand2_formal; + delay_time_t slack; + double real_slack; + int i; + + /* Give each node a 'map' record */ + map_setup_network(network); + + /* find standard gates */ + nand2 = choose_smallest_gate(library, "f=!(a*b);"); + if (nand2 == NIL(lib_gate_t)) { + nand2 = choose_smallest_gate(library, "f=!(a+b);"); + if (nand2 == NIL(lib_gate_t)) { + nand2 = choose_smallest_gate(library, "f=a*b;"); /* hack */ + if (nand2 == NIL(lib_gate_t)) { + nand2 = choose_smallest_gate(library, "f=a+b;"); /* hack */ + if (nand2 == NIL(lib_gate_t)) { + error_append( + "library error: cannot find 2-input nand-gate\n"); + return 0; + } + } + } + } + inv = choose_smallest_gate(library, "f=!a;"); + if (inv == NIL(lib_gate_t)) { + error_append("library error: cannot find inverter\n"); + return 0; + } + zero = choose_smallest_gate(library, "f=0;"); + if (zero == NIL(lib_gate_t)) { + error_append("library error: cannot find constant 0 cell\n"); + return 0; + } + one = choose_smallest_gate(library, "f=1;"); + if (one == NIL(lib_gate_t)) { + error_append("library error: cannot find constant 1 cell\n"); + return 0; + } + + /* create the formal arglist for inv and nand2 */ + inv_formal = ALLOC(char *, 1); + i = 0; + libnet = lib_class_network(lib_gate_class(inv)); + foreach_primary_input(libnet, gen, pi) { + inv_formal[i++] = pi->name; + } + + /* create the formal arglist for inv and nand2 */ + nand2_formal = ALLOC(char *, 2); + i = 0; + libnet = lib_class_network(lib_gate_class(nand2)); + foreach_primary_input(libnet, gen, pi) { + nand2_formal[i++] = pi->name; + } + + /* set the default mapping for each node */ + foreach_node(network, gen, node) { + if (node->type == INTERNAL) { + switch(node_num_fanin(node)) { + case 0: + gate = node_function(node) == NODE_0 ? zero : one; + assert(lib_set_gate(node, gate, NIL(char *), NIL(node_t *), 0)); + break; + case 1: + assert(lib_set_gate(node, inv, inv_formal, node->fanin, 1)); + break; + case 2: + assert(lib_set_gate(node, nand2, nand2_formal, node->fanin, 2)); + break; + default: + fail("bad node degree; should have been caught before here"); + break; + } + } + } + FREE(inv_formal); + FREE(nand2_formal); + + /* perform delay trace using unit-delay model */ + assert(delay_trace(network, DELAY_MODEL_LIBRARY)); + + /* assign the initial area and arrival times for each node */ + foreach_node(network, gen, node) { + if (node->type == PRIMARY_INPUT) { + MAP(node)->map_area = 0; + MAP(node)->map_arrival = delay_arrival_time(node); + } else { + MAP(node)->map_area = -1; + MAP(node)->map_arrival.rise = INFINITY; + MAP(node)->map_arrival.fall = INFINITY; + } + MAP(node)->load = delay_load(node); + slack = delay_slack_time(node); + real_slack = MIN(slack.rise, slack.fall); + MAP(node)->slack_is_critical = real_slack < global_thresh; + } + + return 1; +} + +static int +do_tree_match(network, library, options) +network_t *network; +library_t *library; +bin_global_t *options; +{ + int i, some_output; + node_t *node, *fanout; + prim_t *prim; + array_t *nodevec; + lsGen gen, gen1; + char errmsg[1024]; + int debug = options->verbose; +#ifdef SIS + latch_t *latch; +#endif + + /* clear all bindings for all patterns */ + lsForeachItem(library->patterns, gen, prim) { + prim_clear_binding(prim); + } + + /* Match each node in a depth-first order */ + nodevec = network_dfs(network); + for(i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + +#ifdef SIS + /* sequential support */ + if (node->type == PRIMARY_INPUT) continue; + if (node->type == PRIMARY_OUTPUT && !IS_LATCH_END(node)) continue; +#else + if (node->type != INTERNAL) continue; +#endif + if (node_num_fanin(node) == 0) continue; /* avoid constants */ + +#ifdef SIS + /* set latch type to rising-edge if it is not already set */ + latch = NIL(latch_t); + if (IS_LATCH_END(node)) { + latch = latch_from_node(node); + if (latch == NIL(latch_t)) { + (void) sprintf(errmsg, "latch node '%s' has no latch structure\n", + node_name(node)); + error_append(errmsg); + return 0; + } + } +#endif + + /* Try each primitive rooted at this node */ + MAP(node)->gate = NIL(lib_gate_t); + lsForeachItem(library->patterns, gen, prim) { + gen_all_matches(node, prim, find_best_match, debug > 5, g_allow_internal_fanout, options->fanout_limit); + } + if (MAP(node)->map_area < 0.0 || MAP(node)->gate == 0) { +#ifdef SIS + if (latch == NIL(latch_t) || latch_get_type(latch) == ASYNCH) { +#endif + (void) sprintf(errmsg, + "library error: no gate matches at %s\n", node_name(node)); + error_append(errmsg); + return 0; +#ifdef SIS + } else { + latch_synch_t latch_type; + + /* Synchronous latch - try an opposite polarity latch */ + latch_type = latch_get_type(latch); + switch ((int)latch_type) { + case (int) RISING_EDGE: + latch_set_type(latch, FALLING_EDGE); + break; + case (int) FALLING_EDGE: + latch_set_type(latch, RISING_EDGE); + break; + case (int) ACTIVE_HIGH: + latch_set_type(latch, ACTIVE_LOW); + break; + case (int) ACTIVE_LOW: + latch_set_type(latch, ACTIVE_HIGH); + break; + default: + fail("do_tree_match: bad latch type"); + break; + } + lsForeachItem(library->patterns, gen, prim) { + gen_all_matches(node, prim, find_best_match, debug > 5, g_allow_internal_fanout, options->fanout_limit); + } + if (MAP(node)->map_area < 0.0 || MAP(node)->gate == 0) { + (void) sprintf(errmsg, + "library error: no latch matches at %s\n", node_name(node)); + error_append(errmsg); + return 0; + } else { + node_t *clock, *new_node, *fanin; + lib_gate_t *inv; + + if (! global.no_warning) + (void)fprintf(siserr, + "warning: no %s type latch matches at %s (opposite polarity latch used)\n", + (latch_type==RISING_EDGE)?"RISING_EDGE": + (latch_type==FALLING_EDGE)?"FALLING_EDGE": + (latch_type==ACTIVE_HIGH)?"ACTIVE_HIGH":"ACTIVE_LOW", node_name(node)); + /* Insert a small inverter at the clock */ + inv = choose_smallest_gate(library, "f=!a;"); + clock = latch_get_control(latch); + if (clock != NIL(node_t)) { + assert(node_type(clock) == PRIMARY_OUTPUT); + fanin = node_get_fanin(clock, 0); + new_node = node_alloc(); + node_replace(new_node, node_literal(fanin, 0)); + assert(node_patch_fanin(clock, fanin, new_node)); + network_add_node(network, new_node); + map_alloc(new_node); + MAP(new_node)->gate = inv; + MAP(new_node)->map_area = inv->area; + MAP(new_node)->map_arrival.rise = MAP(fanin)->map_arrival.rise; + MAP(new_node)->map_arrival.fall = MAP(fanin)->map_arrival.fall; + MAP(new_node)->ninputs = 1; + MAP(new_node)->save_binding = ALLOC(node_t *, 1); + MAP(new_node)->save_binding[0] = fanin; + } + } + } +#endif + } + + /* apply inverter optimization at the root of a tree */ + if (global_inverter_optz && is_tree_leaf(node)) { + inverter_optimize(node); + } + + /* compute the area and timing estimates */ + some_output = 0; + foreach_fanout(node, gen1, fanout) { + if (fanout->type == PRIMARY_OUTPUT) { + some_output = 1; + } + } + if (some_output) { + area_estimate += MAP(node)->map_area / node_num_fanout (node); + max_arrival_estimate = MAX (max_arrival_estimate, MAP(node)->map_arrival.rise); + max_arrival_estimate = MAX (max_arrival_estimate, MAP(node)->map_arrival.fall); + } + + if (debug > 0) { + (void) fprintf(sisout, + "Best match at %s is %s area=%5.2f arrival=(%5.2f %5.2f)\n", + node_name(node), MAP(node)->gate->name, MAP(node)->map_area, + MAP(node)->map_arrival.rise, MAP(node)->map_arrival.fall); + } + } + array_free(nodevec); + + /* Derive the optimal cover with a single walk over the network */ +#ifdef SIS + hack_po(network); +#endif + return 1; +} + +/* + * find_best_match: simulate all gates which match a given pattern; + * maintain at the node the best match seen to this point + */ +static int +find_best_match(prim) +prim_t *prim; +{ + lsGen gen; + lib_gate_t *gate; + +#ifdef SIS + /* Make sure that we distinguish between combinational gates and latches. */ + if (seq_filter(prim, global_debug)) { + /* simulate each gate which matches this pattern */ +#endif /* SIS */ + lsForeachItem(prim->gates, gen, gate) { + find_match_cost(prim, gate); + } +#ifdef SIS + } +#endif /* SIS */ + return 1; +} + +/* compare_cost contains the cost function: it returns 1 if THIS is better than + * MATCH. + */ + +int +compare_cost (this_area, this_arrival, match_area, match_arrival, slack_is_critical) + +double match_area, this_area, match_arrival, this_arrival; +int slack_is_critical; + +{ + int optimize_area, optimize_delay; + double this_cost, match_cost; + + /* old cost function for 0.0, 1.0 and 2.0 */ + if (FP_EQUAL (global_area_mode, 2)) { + optimize_area = ! slack_is_critical; + optimize_delay = slack_is_critical; + } + else { + optimize_area = FP_EQUAL (global_area_mode, 0.0); + optimize_delay = FP_EQUAL (global_area_mode, 1.0); + } + + if (optimize_area) { + if (match_area < this_area || + (FP_EQUAL(match_area, this_area) && match_arrival < this_arrival)) { + return 1; + } + } else if (optimize_delay) { + if (match_arrival < this_arrival || + (FP_EQUAL(match_arrival, this_arrival) && match_area < this_area)) { + return 1; + } + } + else { + /* cost = (1 - mode) * area + mode * delay + * use area then delay to break ties + */ + this_cost = (1.0 - global_area_mode) * this_area + global_area_mode * this_arrival; + match_cost = (1.0 - global_area_mode) * match_area + global_area_mode * match_arrival; + if (match_cost < this_cost || + (FP_EQUAL(match_cost, this_cost) && match_area < this_area) || + (FP_EQUAL(match_cost, this_cost) && FP_EQUAL(match_area, this_area) && match_arrival < this_arrival)) { + return 1; + } + } + + return 0; +} + +/* + * find_match_cost: simulate a single gate; keep it if its the best + */ + +static void +find_match_cost(prim, gate) +prim_t *prim; +lib_gate_t *gate; +{ + int i, new_best; + double match_area, this_area, match_arrival, this_arrival; + delay_time_t arrival; + node_t *node; + + /* get the root in the subject network */ + node = map_prim_get_root(prim); + + /* Determine the value of this match */ + match_cost(node, prim, gate, &match_area, &arrival); + match_arrival = MAX(arrival.rise, arrival.fall); + + if (global_debug > 1) { + (void) fprintf(sisout, + " match of %s at %s (area=%5.2f arrival=%5.2f)\n", + gate->name, node_name(node), match_area, match_arrival); + if (global_debug > 2) { + for(i = 0; i < prim->ninputs; i++) { + (void) fprintf(sisout, + " Graph node=%10s <---> (in) prim_node=%10s\n", + prim->inputs[i]->binding->name, prim->inputs[i]->name); + } + for(i = 0; i < prim->noutputs; i++) { + (void) fprintf(sisout, + " Graph node=%10s <---> (out) prim_node=%10s\n", + prim->outputs[i]->binding->name, prim->outputs[i]->name); + } + } + } + + if (MAP(node)->gate == 0) { + /* first match is always the best */ + new_best = 1; + + } else { + this_area = MAP(node)->map_area; + this_arrival = MAX(MAP(node)->map_arrival.rise, + MAP(node)->map_arrival.fall); + new_best = compare_cost (this_area, this_arrival, match_area, match_arrival, + MAP(node)->slack_is_critical); + } + + if (new_best) { + /* save this match as minimum cost for this node */ + MAP(node)->gate = gate; + MAP(node)->map_area = match_area; + MAP(node)->map_arrival.rise = arrival.rise; + MAP(node)->map_arrival.fall = arrival.fall; + + FREE(MAP(node)->save_binding); + MAP(node)->ninputs = prim->ninputs; + MAP(node)->save_binding = ALLOC(node_t *, prim->ninputs); + for(i = 0; i < prim->ninputs; i++) { + MAP(node)->save_binding[i] = prim->inputs[i]->binding; + } + } +} + +static void +match_cost(node, prim, gate, area, arrival) +node_t *node; +prim_t *prim; +lib_gate_t *gate; +double *area; +delay_time_t *arrival; +{ + register int i; + register node_t *fanin; + register delay_time_t **arrival_times; + register prim_node_t **leafs; + + leafs = prim->inputs; + + /* check -- is the match an inverter which is already paid for ? */ + if (global_inverter_optz) { + if (match_is_inverter(node, prim)) { + fanin = leafs[0]->binding; + if (MAP(fanin)->inverter_paid_for) { + *area = 0.0; + *arrival = MAP(fanin)->inverter_arrival; + return; + } + } + } + + + /* + * Compute area cost of this match + */ + *area = gate->area; + for(i = prim->ninputs - 1; i >= 0; i--) { + fanin = leafs[i]->binding; + if (g_allow_internal_fanout & 1) { + if (fanin->type != PRIMARY_INPUT) { + *area += MAP(fanin)->map_area / node_num_fanout(fanin); + } + } else { + if (! is_tree_leaf(fanin)) { + *area += MAP(fanin)->map_area; + } + } + } + + /* + * Compute arrival times (if this match chosen) + */ + if (strcmp(gate->name, "**wire**") == 0) { + *arrival = MAP(prim->inputs[0]->binding)->map_arrival; + + } else { + arrival_times = ALLOC(delay_time_t *, prim->ninputs); + for(i = prim->ninputs - 1; i >= 0; i--) { + fanin = leafs[i]->binding; + arrival_times[i] = &(MAP(fanin)->map_arrival); + } + *arrival = delay_map_simulate(prim->ninputs, arrival_times, + gate->delay_info, MAP(node)->load); + FREE(arrival_times); + } +} + +network_t * +map_build_network(network) +network_t *network; +{ + node_t *node, *new_node, **fanin; + network_t *new_network; + lsGen gen; + + /* clear the 'matching' node for each node in the old network */ + foreach_node(network, gen, node) { + MAP(node)->match_node = NIL(node_t); + } + + /* allocate a new network */ + new_network = network_alloc(); + network_set_name(new_network, network_name(network)); + delay_network_dup(new_network, network); +#ifdef SIS + new_network->astg = astg_dup(network->astg); +#endif /* SIS */ + + /* copy the PI's first */ + foreach_primary_input(network, gen, node) { + delay_time_t drive; + delay_time_t arrival; + + new_node = node_dup(node); + MAP(new_node)->gate = NIL(lib_gate_t); + if (MAP(new_node)->ninputs > 0) { + MAP(new_node)->ninputs = 0; + FREE(MAP(new_node)->save_binding); + } + network_add_primary_input(new_network, new_node); + MAP(node)->match_node = new_node; + if (delay_get_pi_drive(node, &drive)) { + delay_set_parameter(new_node, DELAY_DRIVE_RISE, drive.rise); + delay_set_parameter(new_node, DELAY_DRIVE_FALL, drive.fall); + } + if (delay_get_pi_arrival_time(node, &arrival)) { + delay_set_parameter(new_node, DELAY_ARRIVAL_RISE, arrival.rise); + delay_set_parameter(new_node, DELAY_ARRIVAL_FALL, arrival.fall); + } + } + + /* copy the PO's and recursively from the PO's */ + foreach_primary_output(network, gen, node) { + delay_time_t required; + double load; + + new_node = node_dup(node); + MAP(new_node)->gate = NIL(lib_gate_t); + if (MAP(new_node)->ninputs > 0) { + MAP(new_node)->ninputs = 0; + FREE(MAP(new_node)->save_binding); + } + fanin = ALLOC(node_t *, 1); + fanin[0] = build_network_recur(new_network, map_po_get_fanin(node)); + node_replace_internal(new_node, fanin, 1, NIL(set_family_t)); + network_add_node(new_network, new_node); + MAP(node)->match_node = new_node; + if (delay_get_po_required_time(node, &required)) { + delay_set_parameter(new_node, DELAY_REQUIRED_RISE, required.rise); + delay_set_parameter(new_node, DELAY_REQUIRED_FALL, required.fall); + } + if (delay_get_po_load(node, &load)) { + delay_set_parameter(new_node, DELAY_OUTPUT_LOAD, load); + } + } + return new_network; +} + +static node_t * +build_network_recur(new_network, node) +network_t *new_network; +node_t *node; +{ + int i, nin; + node_t *pi, *new_node, **fanin; + char **formals; + lsGen gen; + + if (MAP(node)->match_node == NIL(node_t)) { + assert(node->type == INTERNAL); + + /* minor hack -- remove 'wires' when building the output graph */ + + assert (MAP(node)->gate != NIL(lib_gate_t)); + if (strcmp(MAP(node)->gate->name, "**wire**") == 0) { + new_node = build_network_recur(new_network, + MAP(node)->save_binding[0]); + MAP(node)->match_node = new_node; + + } else { + new_node = node_alloc(); + new_node->name = util_strsav(node->name); + nin = network_num_pi(MAP(node)->gate->network); + + fanin = ALLOC(node_t *, nin); + for(i = 0; i < nin; i++) { + fanin[i] = build_network_recur(new_network, + MAP(node)->save_binding[i]); + } + formals = ALLOC(char *, nin); + i = 0; + foreach_primary_input(MAP(node)->gate->network, gen, pi) { + formals[i++] = pi->name; + } + + if (!lib_set_gate(new_node, MAP(node)->gate, formals, fanin, nin)) { + fail("lib_set_gate cannot fail"); + } + network_add_node(new_network, new_node); + MAP(node)->match_node = new_node; + FREE(formals); + FREE(fanin); + } + } + return MAP(node)->match_node; +} + +static void +set_leaf_inverter_flag(node) +node_t *node; +{ + int i; + node_t *fanin; + + if (is_tree_leaf(node)) { + /* found leaf -- exit recursion */ + return; + } + + /* see if an inverter matched at the leaf */ + if (best_match_is_inverter(node)) { + fanin = MAP(node)->save_binding[0]; + if (is_tree_leaf(fanin) && ! MAP(fanin)->inverter_paid_for) { + MAP(fanin)->inverter_paid_for = 1; + MAP(fanin)->inverter_arrival = MAP(node)->map_arrival; + } + } + + for(i = MAP(node)->ninputs-1; i >= 0; i--) { + set_leaf_inverter_flag(MAP(node)->save_binding[i]); + } +} + + +static int +inverter_optimize(node) +register node_t *node; +{ + int i; + + /* see if an inverter matched at the root of the tree */ + if (best_match_is_inverter(node)) { + MAP(node)->inverter_paid_for = 1; + MAP(node)->inverter_arrival = MAP(node)->map_arrival; + } + + /* walk back to the leaves, seeing if inverters matched at the inputs */ + for(i = MAP(node)->ninputs-1; i >= 0; i--) { + set_leaf_inverter_flag(MAP(node)->save_binding[i]); + } +} + +/* + * patch the netlist so that all 0,1 cells are driven by a single node + */ + +void +patch_constant_cells(network) +network_t *network; +{ + lsGen gen, gen1; + node_t *node, *fanout, *const0_node, *const1_node; + + const0_node = const1_node = NIL(node_t); + + foreach_node(network, gen, node) { + switch(node_function(node)) { + case NODE_0: + if (const0_node == 0) { + const0_node = node; + } else { + /* patch all other 0 nodes to be driven by the 0-cell */ + foreach_fanout(node, gen1, fanout) { + assert(node_patch_fanin(fanout, node, const0_node)); + } + /* delete this redundant 0-cell */ + network_delete_node_gen(network, gen); + } + break; + + case NODE_1: + if (const1_node == 0) { + const1_node = node; + } else { + /* patch all other 1 nodes to be driven by the 1-cell */ + foreach_fanout(node, gen1, fanout) { + assert(node_patch_fanin(fanout, node, const1_node)); + } + /* delete this redundant 1-cell */ + network_delete_node_gen(network, gen); + } + break; + default: + ; + } + } +} + +#ifdef SIS +/* sequential support */ +/* distinguish between latches and + * combinational gates. + */ +int +seq_filter(prim, debug) +prim_t *prim; +int debug; +{ + prim_node_t *prim_latch_end; + node_t *latch_end, *node; + int i; + latch_t *latch; + + node = map_prim_get_root(prim); + latch_end = network_latch_end(node); + if ( latch_end == NIL(node_t) ) { + /* the subject graph is a combintaional logic */ + if (prim->latch_type != COMBINATIONAL) { + if (debug <= -4) { + (void) fprintf(sisout, "\t--REJECT %s: Need combinational gate at %s\n", + prim_gate_name(prim), node_name(node)); + } + return 0; + } else { + return 1; + } + } else { + /* the subject graph is a latch */ + latch = latch_from_node(node); + if (prim->latch_type != latch_get_type(latch)) { + if (debug <= -4) { + (void) fprintf(sisout, "\t--REJECT %s: Gate type mismatch at %s\n", prim_gate_name(prim), + node_name(node)); + } + return 0; + } else { + /* make sure that the latch outputs match */ + /* first find the latch output node on the pattern graph */ + prim_latch_end = NIL(prim_node_t); + for (i=0; i< prim->ninputs; i++) { + if (prim->inputs[i]->latch_output) { + prim_latch_end = prim->inputs[i]; + break; + } + } + if (prim_latch_end == NIL(prim_node_t)) { + /* no latch output found - must be a d-type latch */ + return 1; + + /* check if both latch output nodes match. + * because of the inverter pairs which are added + * everywhere there may exist a buffer connection + * between the two nodes. + */ + } else if ( prim_latch_end->binding == latch_end || + is_buffer(latch_end, prim_latch_end->binding) ) { + /* make sure that this latch output node is unique */ + for (i=0; i < prim->ninputs; i++) { + if (prim->inputs[i] == prim_latch_end) continue; + if (is_transitive_fanin(prim->inputs[i]->binding, + latch_end)) { + if (debug <= -4) { + (void) fprintf(sisout,"\t--REJECT %s at %s: Latch output is not unique\n", + prim_gate_name(prim), node_name(node)); + (void) fprintf(sisout,"\t\t[[Multiple latch ouputs are %s and %s]]\n", + node_name(prim_latch_end->binding), node_name(prim->inputs[i]->binding)); + } + return 0; + } + } + return 1; + } + if (debug <= -4) { + (void) fprintf(sisout,"\t--REJECT %s at %s: Latch outputs don't match\n", + prim_gate_name(prim), node_name(node)); + (void) fprintf(sisout,"\t\t[[Graph latch output = %s, Prim latch output = %s]]\n", + latch_end->name, prim_latch_end->binding->name); + } + } + } + return 0; +} + +static char * +prim_gate_name(prim) +prim_t *prim; +{ + lsGen gen; + lib_gate_t *gate; + + lsForeachItem(prim->gates, gen, gate) { + LS_ASSERT(lsFinish(gen)); + break; + /* NOTREACHED */ + } + assert(gate != NIL(lib_gate_t)); + return (gate->name); +} + +/* Check if node2 is a buffer of node1 */ +static int +is_buffer(node1, node2) +node_t *node1, *node2; +{ + lsGen gen1, gen2; + node_t *fanout1, *fanout2; + + foreach_fanout(node1, gen1, fanout1) { + if (node_function(fanout1) == NODE_INV) { + foreach_fanout(fanout1, gen2, fanout2) { + if (node_function(fanout2) == NODE_INV && fanout2 == node2) { + LS_ASSERT(lsFinish(gen1)); + LS_ASSERT(lsFinish(gen2)); + return 1; + } + } + } + } + return 0; +} + +/* check if node2 is in the transitive fanin of node1 */ +static int +is_transitive_fanin(node1, node2) +node_t *node1; +register node_t *node2; +{ + node_t *fanin; + int result, i; + + if (node1 == node2) return 1; + if (node1->type == PRIMARY_INPUT) return 0; + result = 0; + foreach_fanin(node1, i, fanin) { + result += is_transitive_fanin(fanin, node2); + if (result > 0) { + break; + } + } + return result; +} + +/* After initial mapping, the function associated with + * latches are temporarily stored at PO/latch-input nodes. + * Now create an extra buffer node to move the func info to. + * Also modify the fanout of the new node + * such that it points to the real PO. + * Before: (internal node) -> real PO (no func) + * -> PO/latch-input (has latch func) + * -> PO/latch-input (has latch func) + * ... + * After: (internal node) -> real PO (no func) + * -> (internal node - has latch func) -> PO/latch-input (no func) + * -> (internal node - has latch func) -> PO/latch-input (no func) + * ... + */ +static void +hack_po(network) +network_t *network; +{ + lsGen gen; + node_t *po, *fanin, *new_node; + int i; + latch_t *latch; + + foreach_latch(network, gen, latch) { + po = latch_get_input(latch); + fanin = node_get_fanin(po, 0); + new_node = node_alloc(); + node_replace(new_node, node_literal(fanin, 1)); + assert(node_patch_fanin(po, fanin, new_node)); + network_add_node(network, new_node); + /* PO derives its output from its fanin node */ + /* Swap names to preserve the IO names*/ + network_swap_names(network, new_node, fanin); + map_alloc(new_node); + MAP(new_node)->gate = MAP(po)->gate; + MAP(new_node)->map_area = MAP(po)->map_area; + MAP(new_node)->map_arrival = MAP(po)->map_arrival; + MAP(new_node)->ninputs = MAP(po)->ninputs; + MAP(new_node)->save_binding = ALLOC(node_t *, MAP(po)->ninputs); + for(i = 0; i < MAP(po)->ninputs; i++) { + MAP(new_node)->save_binding[i] = MAP(po)->save_binding[i]; + } + MAP(po)->gate = NIL(lib_gate_t); + } +} + + +#if !defined(lint) && !defined(SABER) + +/* debug routine */ +static void +map_print_network(network) +network_t *network; +{ + array_t *list; + node_t *node; + int i; + + list = network_dfs(network); + for (i = 0; i < array_n(list); i++) { + node = array_fetch (node_t *, list, i); + node_print(sisout, node); + } + array_free(list); +} +#endif +#endif diff --git a/sis/map/treesize.c b/sis/map/treesize.c new file mode 100644 index 0000000..22051fe --- /dev/null +++ b/sis/map/treesize.c @@ -0,0 +1,139 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/treesize.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)treesize.c 1.2 */ +/* last modified on 5/1/91 at 15:52:02 */ +#include "sis.h" +#include "map_int.h" + + +typedef struct count_struct count_t; +struct count_struct { + int leafs; /* counter */ + int nodes; /* counter */ + int freq; /* frequency of this count */ + node_t *root_node; + count_t *next; +}; + + +static int +compare_count(x, y) +count_t *x, *y; +{ + return y->nodes - x->nodes; +} + + +/* sort_count_list(count_t *list, int compare(count_t *, count_t *)) */ +#define TYPE count_t +#define SORT sort_count_list_helper +#define SORT1 sort_count_list +#include "lsort.h" + + +/* uniq_count_list(count_t *list, int compare(count_t *, count_t *), free) */ +#define TYPE count_t +#define UNIQ uniq_count_list +#define FREQ freq +#include "luniq.h" + + +static void +find_tree_size(node, leaf_table, visited, tree_root) +node_t *node; +st_table *leaf_table; +st_table *visited; +node_t *tree_root; +{ + int i; + count_t *count; + node_t *fanin; + + if (node->type == PRIMARY_INPUT || node_num_fanout(node) > 1) { + /* advance the leaf counter for 'tree_root' */ + if (st_lookup(leaf_table, (char *) tree_root, (char **) &count)) { + count->leafs++; + } else { + count = ALLOC(count_t, 1); + count->nodes = 0; + count->leafs = 1; + count->root_node = tree_root; + (void) st_insert(leaf_table, (char *) tree_root, (char *) count); + } + + tree_root = node; /* start a new tree here */ + } + + if (! st_lookup(visited, (char *) node, NIL(char *))) { + (void) st_insert(visited, (char *) node, NIL(char)); + + /* advance the node counter for 'tree_root' */ + if (st_lookup(leaf_table, (char *) tree_root, (char **) &count)) { + count->nodes++; + } else { + count = ALLOC(count_t, 1); + count->nodes = 1; + count->leafs = 0; + count->root_node = tree_root; + (void) st_insert(leaf_table, (char *) tree_root, (char *) count); + } + + foreach_fanin(node, i, fanin) { + find_tree_size(fanin, leaf_table, visited, tree_root); + } + } +} + + +void +map_print_tree_size(fp, network) +FILE *fp; +network_t *network; +{ +#ifdef _IBMR2 +extern void free(); +#endif + count_t *count, *count_list, *count_next; + node_t *node, *fanin; + st_table *leaf_table, *visited; + st_generator *stgen; + lsGen gen; + + leaf_table = st_init_table(st_ptrcmp, st_ptrhash); + + visited = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_output(network, gen, node) { + fanin = node_get_fanin(node, 0); + find_tree_size(fanin, leaf_table, visited, node); + } + st_free_table(visited); + + count_list = NIL(count_t); + st_foreach_item(leaf_table, stgen, (char **) &node, (char **) &count) { + count->next = count_list; + count_list = count; + /*(void) printf("%-10s : %d\n", node->name, count->nodes);*/ + } + st_free_table(leaf_table); + + count_list = sort_count_list(count_list, compare_count); + count_list = uniq_count_list(count_list, compare_count, free); + + (void) fprintf(fp, "Distribution of Tree Sizes\n"); + (void) fprintf(fp, "--------------------------\n"); + for(count = count_list; count != NIL(count_t); count = count_next) { + count_next = count->next; + (void) fprintf(fp, + " nodes=%3d leaf=%3d freq=%3d (root node = %s)\n", + count->nodes + count->leafs, count->leafs, + count->freq, count->root_node->name); + FREE(count); + } +} diff --git a/sis/map/two_level.c b/sis/map/two_level.c new file mode 100644 index 0000000..56c67b0 --- /dev/null +++ b/sis/map/two_level.c @@ -0,0 +1,482 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/two_level.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* Last modified on Fri Feb 7 21:59:46 1992 by touati */ +/** +** MODIFICATION HISTORY: +** +** 02 7-Feb-1992 touati Fixed the bug introduced by klk's fix. +** Factorized the common code between compute_balanced_required_time() +** and compute_best_fit_required_time(). +** +** 01 10-June-1991 klk Fixed a bug in the functions compute_balanced_required_time() and +** compute_best_fit_required_time(). +**/ + +#include "sis.h" +#include <math.h> +#include "fanout_int.h" +#include "fanout_delay.h" + +static delay_time_t compute_balanced_required_time(); +static delay_time_t compute_best_fit_required_time(); +static delay_time_t from_buffer_assignment_to_required_time(); +static int balanced_optimize(); +static int two_level_optimize(); +static multidim_t *optimize_balanced(); +static multidim_t *optimize_one_source_all_sets_of_sinks(); +static multidim_t *optimize_two_level(); +static void best_one_source(); +static void build_selected_tree(); +static void extract_merge_info(); +static void insert_one_level_tree(); + + + + /* CONTENTS */ + + /* this file contains the routines to compute fanout trees */ + /* of depth 2 with one level of identical buffers */ + /* This file can be used as an independent fanout optimizer */ + /* though it was originally intended to be a subroutine for LT-trees */ + + +static n_gates_t n_gates; +static two_level_t TWO_LEVEL_INIT_VALUE = {-1, -1, {-INFINITY, -INFINITY}}; +static DelayFn two_level_best_fit_fn; + + + /* EXTERNAL INTERFACE */ + + /* ARGSUSED */ +void two_level_init(network, alg) +network_t *network; +fanout_alg_t *alg; +{ + alg->optimize = two_level_optimize; +} + + /* ARGSUSED */ +void balanced_init(network, alg) +network_t *network; +fanout_alg_t *alg; +{ + alg->optimize = balanced_optimize; +} + + + /* INTERNAL INTERFACE */ + +static int two_level_optimize(fanout_info, tree, cost) +opt_array_t *fanout_info; /* fanout_info[POLAR_X] lists the positive polarity sinks; POLAR_Y negative */ +array_t *tree; /* array in which the result tree is stored: format of fanout_tree.c */ +fanout_cost_t *cost; /* contains information on the result: required times, area */ +{ + generic_fanout_optimizer(fanout_info, tree, cost, optimize_two_level, extract_merge_info, build_selected_tree); + return 1; +} + +static int balanced_optimize(fanout_info, tree, cost) +opt_array_t *fanout_info; /* fanout_info[POLAR_X] lists the positive polarity sinks; POLAR_Y negative */ +array_t *tree; /* array in which the result tree is stored: format of fanout_tree.c */ +fanout_cost_t *cost; /* contains information on the result: required times, area */ +{ + generic_fanout_optimizer(fanout_info, tree, cost, optimize_balanced, extract_merge_info, build_selected_tree); + return 1; +} + + + /* this routine computes all table entries for all possible sources */ + /* and all possible intermediate buffers */ + /* but only for one polarity at a time */ + /* which polarity is used is automatically infered from the polarity */ + /* of the source and intermediate buffers */ + /* if the source is an actual source of the fanout problem, only */ + /* one polarity is possible */ + +static multidim_t *optimize_two_level(fanout_info) +opt_array_t *fanout_info; +{ + two_level_best_fit_fn = compute_best_fit_required_time; + return optimize_one_source_all_sets_of_sinks(fanout_info, 0 /* top level only */); +} + +static multidim_t *optimize_balanced(fanout_info) +opt_array_t *fanout_info; +{ + two_level_best_fit_fn = compute_balanced_required_time; + return optimize_one_source_all_sets_of_sinks(fanout_info, 0 /* top level only */); +} + + + /* exported for "lt_trees.c" */ + +multidim_t *two_level_optimize_for_lt_trees(fanout_info) +opt_array_t *fanout_info; +{ + two_level_best_fit_fn = compute_best_fit_required_time; + return optimize_one_source_all_sets_of_sinks(fanout_info, 1 /* all sets */); +} + +static multidim_t *optimize_one_source_all_sets_of_sinks(fanout_info, all_sets_of_sinks) +opt_array_t *fanout_info; +int all_sets_of_sinks; +{ + multidim_t *table; + int indices[4]; + int max_sinks; + int source_index, source_polarity, sink_index, sink_polarity; + two_level_t *entry; + + n_gates = fanout_delay_get_n_gates(); + max_sinks = MAX(fanout_info[POLAR_X].n_elts, fanout_info[POLAR_Y].n_elts); + indices[0] = n_gates.n_gates; /* source index */ + indices[1] = POLAR_MAX; /* polarity at output of source */ + indices[2] = max_sinks; /* max sink index */ + indices[3] = POLAR_MAX; /* sink polarity */ + table = multidim_alloc(two_level_t, 4, indices); + multidim_init(two_level_t, table, TWO_LEVEL_INIT_VALUE); + + foreach_gate(n_gates, source_index) { + foreach_polarity(source_polarity) { + if (is_source(n_gates, source_index) && fanout_delay_get_source_polarity(source_index) != source_polarity) continue; + foreach_polarity(sink_polarity) { + if (fanout_info[sink_polarity].n_elts == 0) continue; + for (sink_index = 0; sink_index < fanout_info[sink_polarity].n_elts; sink_index++) { + if(sink_index > 0 && all_sets_of_sinks == 0) break; + entry = INDEX4P(two_level_t, table, source_index, source_polarity, sink_index, sink_polarity); + best_one_source(&fanout_info[sink_polarity], entry, source_index, sink_index, (source_polarity != sink_polarity)); + } + } + } + } + return table; +} + + + /* computes the best two level tree for a given source, and a given set of sinks */ + /* of the form [sink_index,fanout_info->n_elts[ */ + +static void best_one_source(fanout_info, entry, source_index, sink_index, diff_polarity) +opt_array_t *fanout_info; +two_level_t *entry; +int source_index; +int sink_index; +int diff_polarity; /* 1 iff source and sinks have different polarity */ +{ + int g, k; + int from, to; + int n_sinks; + double load; + delay_time_t required; + + from = (diff_polarity) ? n_gates.n_pos_buffers : 0; + to = (diff_polarity) ? n_gates.n_neg_buffers : n_gates.n_pos_buffers; + n_sinks = fanout_info->n_elts - sink_index; + load = fanout_info->total_load - fanout_info->cumul_load[sink_index] + map_compute_wire_load(n_sinks); + + for (g = from; g < to; g++) { + k = compute_best_number_of_inverters(source_index, g, load, n_sinks); + required = (two_level_best_fit_fn)(fanout_info, source_index, sink_index, g, &k, NIL(int)); + if (GETMIN(entry->required) < GETMIN(required)) { + entry->gate_index = g; + entry->n_gates = k; + entry->required = required; + entry->area = k * fanout_delay_get_area(g) + fanout_delay_get_area(source_index); + } + } +} + + +typedef struct best_fit_struct best_fit_t; +struct best_fit_struct { + delay_time_t required; + double load; + int n_fanouts; +}; + +static best_fit_t BEST_FIT_INIT_VALUE = {{INFINITY, INFINITY}, 0.0, 0}; + + /* greedy algorithm: */ + /* assign the sink to the intermediate node that would provide the largest overall */ + /* required time after the sink is inserted */ + +static delay_time_t compute_best_fit_required_time(fanout_info, source_index, sink_index, buffer_index, n_buffers, sink_to_buffer_map) +opt_array_t *fanout_info; +int source_index; +int sink_index; +int buffer_index; +int *n_buffers; +int *sink_to_buffer_map; /* records mapping sink->buffer; if NIL(int), does nothing */ +{ + best_fit_t *best_fit_info; + delay_time_t required_so_far; + delay_time_t local_required; + double load, local_load; + int sink; /* index on remaining sinks, from sink_index to fanout_info->n_elts */ + int buffer; /* index on intermediate buffers, from 0 to n_buffers */ + int num_assigned_buffers; /* Number of buffers that are actually assigned sinks */ + int n_elts = fanout_info->n_elts; + int n_sinks = n_elts - sink_index; + + best_fit_info = ALLOC(best_fit_t, *n_buffers); + for (buffer = 0; buffer < *n_buffers; buffer++) + best_fit_info[buffer] = BEST_FIT_INIT_VALUE; + + required_so_far = PLUS_INFINITY; + for (sink = sink_index; sink < n_elts; sink++) { + gate_link_t *link; + int best_fit; + delay_time_t best_required; + + link = array_fetch(gate_link_t *, fanout_info->required, sink); + best_fit = -1; + best_required = MINUS_INFINITY; + + for (buffer = 0; buffer < *n_buffers; buffer++) { + SETMIN(local_required, link->required, best_fit_info[buffer].required); + local_load = best_fit_info[buffer].load + link->load; + local_load += map_compute_wire_load(best_fit_info[buffer].n_fanouts + 1); + local_required = fanout_delay_backward_load_dependent(local_required, buffer_index, local_load); + if (GETMIN(best_required) < GETMIN(local_required)) { + best_required = local_required; + best_fit = buffer; + } + } + SETMIN(best_fit_info[best_fit].required, best_fit_info[best_fit].required, link->required); + best_fit_info[best_fit].load += link->load; + best_fit_info[best_fit].n_fanouts++; + if (sink_to_buffer_map != NIL(int)) sink_to_buffer_map[sink] = best_fit; + SETMIN(required_so_far, required_so_far, best_required); + } + return from_buffer_assignment_to_required_time(best_fit_info, n_buffers, required_so_far, source_index, buffer_index, n_sinks); +} + + /* balanced algorithm: ignores the required times to perform the allocation */ + +static delay_time_t compute_balanced_required_time(fanout_info, source_index, sink_index, buffer_index, n_buffers, sink_to_buffer_map) +opt_array_t *fanout_info; +int source_index; +int sink_index; +int buffer_index; +int *n_buffers; +int *sink_to_buffer_map; /* records mapping sink->buffer; if NIL(int), does nothing */ +{ + best_fit_t *best_fit_info; + delay_time_t required_so_far; + delay_time_t local_required; + double load, local_load; + int sink; /* index on remaining sinks, from sink_index to fanout_info->n_elts */ + int buffer; /* index on intermediate buffers, from 0 to n_buffers */ + int n_elts = fanout_info->n_elts; + int n_sinks = n_elts - sink_index; + + best_fit_info = ALLOC(best_fit_t, *n_buffers); + + for (buffer = 0; buffer < *n_buffers; buffer++) + best_fit_info[buffer] = BEST_FIT_INIT_VALUE; + + for (sink = sink_index; sink < n_elts; sink++) { + gate_link_t *link; + int best_fit; + + load = INFINITY; + for (buffer = 0; buffer < *n_buffers; buffer++) { + if (load > best_fit_info[buffer].load) { + load = best_fit_info[buffer].load; + best_fit = buffer; + } + } + link = array_fetch(gate_link_t *, fanout_info->required, sink); + best_fit_info[best_fit].load += link->load; + best_fit_info[best_fit].n_fanouts++; + SETMIN(best_fit_info[best_fit].required, best_fit_info[best_fit].required, link->required); + if (sink_to_buffer_map != NIL(int)) sink_to_buffer_map[sink] = best_fit; + } + required_so_far = PLUS_INFINITY; + for (buffer = 0; buffer < *n_buffers; buffer++) { + local_required = best_fit_info[buffer].required; + local_load = best_fit_info[buffer].load; + local_load += map_compute_wire_load(best_fit_info[buffer].n_fanouts); + local_required = fanout_delay_backward_load_dependent(local_required, buffer_index, local_load); + SETMIN(required_so_far, required_so_far, local_required); + } + return from_buffer_assignment_to_required_time(best_fit_info, n_buffers, required_so_far, source_index, buffer_index, n_sinks); +} + +/* + * takes a buffer assignment computed by either 'compute_balanced_required_time' + * or 'compute_best_fit_required_time', performs some consistency checks + * and returns the required time. + * NOTE: should deallocate 'best_fit_info' + */ + +static delay_time_t from_buffer_assignment_to_required_time(best_fit_info, n_buffers, required_so_far, source_index, buffer_index, n_sinks) +best_fit_t *best_fit_info; +int *n_buffers; +delay_time_t required_so_far; +int source_index; +int buffer_index; +int n_sinks; +{ + int buffer; /* index on intermediate buffers, from 0 to n_buffers */ + int num_assigned_buffers; /* number of buffers that are actually assigned sinks */ + int num_assigned_sinks; /* number of sinks that are actually assigned to a buffer */ + double load; /* load at the main buffer */ + + /* + * Make sure all the buffers are assigned some sink. + * If the number of assigned buffers is not the same as the value of n_buffers, change + * n_buffers to number of actually assigned buffers. + */ + num_assigned_buffers = 0; + num_assigned_sinks = 0; + for (buffer = 0; buffer < *n_buffers; buffer++) { + if (best_fit_info[buffer].n_fanouts > 0) { + num_assigned_sinks += best_fit_info[buffer].n_fanouts; + num_assigned_buffers++; + } + } + FREE(best_fit_info); + assert(num_assigned_sinks == n_sinks); + if(num_assigned_buffers != *n_buffers) { + (void) fprintf(sisout, "balanced: Some buffers in the two-level tree are not assigned sinks\n"); + *n_buffers = num_assigned_buffers; + } + + required_so_far = fanout_delay_backward_intrinsic(required_so_far, buffer_index); + load = fanout_delay_get_buffer_load(buffer_index) * *n_buffers + map_compute_wire_load(*n_buffers); + return fanout_delay_backward_load_dependent(required_so_far, source_index, load); +} + + + /* needs corrective computation if source is root of tree: discard effect of drive at the source */ + +static void extract_merge_info(fanout_info, table, merge_table) +opt_array_t *fanout_info; +multidim_t *table; +multidim_t *merge_table; +{ + int source_index; + delay_time_t origin; + double load; + two_level_t *from; + single_source_t *to; + int source_polarity, sink_polarity; + + foreach_gate(n_gates, source_index) { + foreach_polarity(sink_polarity) { + foreach_polarity(source_polarity) { + from = INDEX4P(two_level_t, table, source_index, source_polarity, 0, sink_polarity); + to = INDEX3P(single_source_t, merge_table, source_index, source_polarity, sink_polarity); + if (fanout_info[sink_polarity].n_elts == 0) { + to->required = PLUS_INFINITY; + } else if (from->gate_index == -1) { + continue; + } else if (is_buffer(n_gates,source_index)) { + to->load = fanout_delay_get_buffer_load(source_index); + to->n_fanouts = 1; + to->required = fanout_delay_backward_intrinsic(from->required, source_index); + to->area = from->area; + } else if (fanout_delay_get_source_polarity(source_index) == source_polarity) { + to->load = fanout_delay_get_buffer_load(from->gate_index) * from->n_gates; + to->n_fanouts = from->n_gates; + load = to->load + map_compute_wire_load(to->n_fanouts); + origin = fanout_delay_backward_load_dependent(ZERO_DELAY, source_index, load); + SETSUB(to->required, from->required, origin); + to->area = from->area; + } + } + } + } +} + +static void build_selected_tree(fanout_info, tree, source, table) +opt_array_t *fanout_info; +array_t *tree; +selected_source_t *source; +multidim_t *table; +{ + int p, q; + int n_fanouts; + int source_polarity, buffer_polarity; + two_level_t *entry_p, *entry_q; + + source_polarity = fanout_delay_get_source_polarity(source->main_source); + p = source->main_source_sink_polarity; + q = POLAR_INV(p); + entry_p = INDEX4P(two_level_t, table, source->main_source, source_polarity, 0, p); + if (fanout_info[p].n_elts == 0) entry_p->n_gates = 0; + + if (fanout_info[q].n_elts > 0) { + if (is_source(n_gates, source->buffer)) { + assert(source->buffer == source->main_source); + entry_q = INDEX4P(two_level_t, table, source->main_source, source_polarity, 0, q); + n_fanouts = entry_p->n_gates + entry_q->n_gates; + fanout_tree_insert_gate(tree, source->main_source, n_fanouts); + insert_two_level_tree(tree, &fanout_info[p], 0, source->main_source, entry_p); + insert_two_level_tree(tree, &fanout_info[q], 0, source->main_source, entry_q); + } else { + n_fanouts = entry_p->n_gates + 1; + fanout_tree_insert_gate(tree, source->main_source, n_fanouts); + insert_two_level_tree(tree, &fanout_info[p], 0, source->main_source, entry_p); + buffer_polarity = (is_inverter(n_gates, source->buffer)) ? POLAR_INV(source_polarity) : source_polarity; + entry_q = INDEX4P(two_level_t, table, source->buffer, buffer_polarity, 0, q); + n_fanouts = entry_q->n_gates; + fanout_tree_insert_gate(tree, source->buffer, n_fanouts); + insert_two_level_tree(tree, &fanout_info[q], 0, source->buffer, entry_q); + } + } else { + fanout_tree_insert_gate(tree, source->main_source, entry_p->n_gates); + insert_two_level_tree(tree, &fanout_info[p], 0, source->main_source, entry_p); + } +} + +void insert_two_level_tree(tree, fanout_info, sink_index, source_index, entry) +array_t *tree; +opt_array_t *fanout_info; +int sink_index; +int source_index; +two_level_t *entry; +{ + int i, j; + int *sink_to_buffer_map; + st_table **fanouts; + + if (entry->n_gates == 0) return; + sink_to_buffer_map = ALLOC(int, fanout_info->n_elts); + fanouts = ALLOC(st_table *, entry->n_gates); + (void) (*two_level_best_fit_fn)(fanout_info, source_index, sink_index, entry->gate_index, &(entry->n_gates), sink_to_buffer_map); + for (i = 0; i < entry->n_gates; i++) + fanouts[i] = st_init_table(st_numcmp, st_numhash); + for (j = sink_index; j < fanout_info->n_elts; j++) + (void) st_insert(fanouts[sink_to_buffer_map[j]], (char *) j, NIL(char)); + for (i = 0; i < entry->n_gates; i++) { + fanout_tree_insert_gate(tree, entry->gate_index, st_count(fanouts[i])); + insert_one_level_tree(tree, fanout_info, fanouts[i]); + } + for (i = 0; i < entry->n_gates; i++) + st_free_table(fanouts[i]); + FREE(fanouts); + FREE(sink_to_buffer_map); +} + +static void insert_one_level_tree(tree, fanout_info, fanout_table) +array_t *tree; +opt_array_t *fanout_info; +st_table *fanout_table; +{ + char *key, *value; + st_generator *gen; + st_foreach_item(fanout_table, gen, &key, &value) { + int sink_index = (int) key; + gate_link_t *link = array_fetch(gate_link_t *, fanout_info->required, sink_index); + fanout_tree_insert_sink(tree, link); + } +} diff --git a/sis/map/virtual_del.c b/sis/map/virtual_del.c new file mode 100644 index 0000000..cc7dc74 --- /dev/null +++ b/sis/map/virtual_del.c @@ -0,0 +1,262 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/virtual_del.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)virtual_del.c 1.7 */ +/* last modified on 7/22/91 at 12:36:39 */ +/* + * $Log: virtual_del.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:26 pchong + * imported + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.3 1992/05/06 18:55:51 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 22:00:59 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:40:59 sis + * Initial revision + * + * Revision 1.3 91/07/02 11:19:23 touati + * corrected a bug: handles default required times properly now. + * + * Revision 1.2 91/06/30 22:19:17 touati + * change MAP(node)->arrival_info from pointers to actual copy of delay info + * + * Revision 1.1 91/06/28 22:51:22 touati + * Initial revision + * + */ +#include "sis.h" +#include "map_int.h" +#include "map_delay.h" +#include "fanout_int.h" +#include "fanout_delay.h" + +static void update_gate_link_loads_rec(); +static void virtual_delay_compute_node_arrival_time(); +static bin_global_t global; + +void virtual_delay_compute_arrival_times(network, globals) +network_t *network; +bin_global_t globals; +{ + lsGen gen; + node_t *pi, *po; + st_table *computed = st_init_table(st_numcmp, st_numhash); + + global = globals; + foreach_primary_input(network, gen, pi) { + update_gate_link_loads_rec(computed, pi); + MAP(pi)->load = gate_link_compute_load(pi); + } + st_free_table(computed); + + computed = st_init_table(st_numcmp, st_numhash); + foreach_primary_output(network, gen, po) { + node_t *node = map_po_get_fanin(po); + virtual_delay_arrival_times_rec(computed, node); + MAP(po)->map_arrival = MAP(node)->map_arrival; + } + st_free_table(computed); +} + + + /* force the required times to be negative to force maximum optimization */ + /* also keep the relative positions of the PO's in terms of criticality */ + +void virtual_delay_set_po_negative_required(network) +network_t *network; +{ + lsGen gen; + node_t *output; + double shift, max_value; + delay_time_t required, max_po_required; + + max_po_required = MINUS_INFINITY; + foreach_primary_output(network, gen, output) { + required = pipo_get_po_required(output); + SETMAX(max_po_required, max_po_required, required); + } + + max_value = GETMAX(max_po_required); + for (shift = 1.0; shift < max_value; shift *= 10.0) ; + + foreach_primary_output(network, gen, output) { + required = pipo_get_po_required(output); + required.rise -= shift; + required.fall -= shift; + MAP(output)->required = required; + virtual_network_update_link_required_times(output, NIL(delay_time_t)); + } +} + +void virtual_delay_set_po_required(network) +network_t *network; +{ + lsGen gen; + node_t *output; + delay_time_t max_po_arrival; + + max_po_arrival = MINUS_INFINITY; + foreach_primary_output(network, gen, output) { + SETMAX(max_po_arrival, max_po_arrival, MAP(output)->map_arrival); + } + pipo_set_default_po_required(max_po_arrival); + foreach_primary_output(network, gen, output) { + MAP(output)->required = pipo_get_po_required(output); + if (IS_EQUAL(MAP(output)->required, MINUS_INFINITY)) + MAP(output)->required = max_po_arrival; + virtual_network_update_link_required_times(output, NIL(delay_time_t)); + } +} + + + /* the required time at a node is the min of the required times in its gate_link */ + /* it does not take into account the delay through the gate at that node */ + /* this routine also computes the required times on the wires ending up at "node" */ + /* those required times take the delay through the gate at "node" into account */ + +void virtual_delay_compute_node_required_time(node) +node_t *node; +{ + double load; + delay_time_t *link_required; + + assert(node->type == PRIMARY_INPUT || MAP(node)->gate != NIL(lib_gate_t)); + MAP(node)->required = gate_link_compute_min_required(node); + if (node->type == PRIMARY_INPUT) return; + load = gate_link_compute_load(node); + link_required = ALLOC(delay_time_t, MAP(node)->ninputs); + delay_map_compute_required_times(MAP(node)->ninputs, MAP(node)->gate->delay_info, MAP(node)->required, load, link_required); + virtual_network_update_link_required_times(node, link_required); + FREE(link_required); +} + + + /* INTERNAL INTERFACE */ + +static void update_gate_link_loads_rec(table, node) +st_table *table; +node_t *node; +{ + int i; + node_t *input; + gate_link_t link; + + if (st_lookup(table, (char *) node, NIL(char *))) return; + if (node->type == PRIMARY_OUTPUT) { + MAP(node)->load = pipo_get_po_load(node); + link.node = node; + link.pin = -1; + input = map_po_get_fanin(node); + assert(gate_link_get(input, &link)); + link.load = MAP(node)->load; + gate_link_put(input, &link); + st_insert(table, (char *) node, NIL(char)); + return; + } + if (gate_link_n_elts(node) == 0) return; + gate_link_first(node, &link); + do { + update_gate_link_loads_rec(table, link.node); + } while (gate_link_next(node, &link)); + MAP(node)->load = gate_link_compute_load(node); + if (node->type == PRIMARY_INPUT) { + st_insert(table, (char *) node, NIL(char)); + return; + } + assert(MAP(node)->gate); + for (i = 0; i < MAP(node)->ninputs; i++) { + link.node = node; + link.pin = i; + input = MAP(node)->save_binding[i]; + assert(gate_link_get(input, &link)); + link.load = delay_get_load(MAP(node)->gate->delay_info[i]); + gate_link_put(input, &link); + } + st_insert(table, (char *) node, NIL(char)); +} + + + /* exported to map_interface.c */ + +void virtual_delay_arrival_times_rec(table, node) + st_table *table; + node_t *node; +{ + int pin; + + if (st_lookup(table, (char *) node, NIL(char *))) return; + if (node->type != PRIMARY_INPUT) { + assert(MAP(node)->gate); + for (pin = 0; pin < MAP(node)->ninputs; pin++) + virtual_delay_arrival_times_rec(table, MAP(node)->save_binding[pin]); + } + virtual_delay_compute_node_arrival_time(node); + st_insert(table, (char *) node, NIL(char)); +} + +static void virtual_delay_compute_node_arrival_time(node) + node_t *node; +{ + int i; + node_t *input; + delay_time_t arrival; + delay_time_t drive; + delay_time_t **arrival_times; + + switch (node_function(node)) { + case NODE_PI: + arrival = pipo_get_pi_arrival(node); + drive = pipo_get_pi_drive(node); + arrival.rise += drive.rise * MAP(node)->load; + arrival.fall += drive.fall * MAP(node)->load; + MAP(node)->map_arrival = arrival; + break; + case NODE_PO: + input = map_po_get_fanin(node); + MAP(node)->map_arrival = MAP(input)->map_arrival; + break; + case NODE_0: + case NODE_1: + if (! global.no_warning) (void) fprintf(siserr, "WARNING: arrival time at constant node is (0.00,0.00) \n"); + MAP(node)->map_arrival = ZERO_DELAY; + break; + case NODE_BUF: + case NODE_INV: + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: + if (strcmp(MAP(node)->gate->name, "**wire**") == 0) { + MAP(node)->map_arrival = MAP(MAP(node)->save_binding[0])->map_arrival; + } else { + arrival_times = ALLOC(delay_time_t *, MAP(node)->ninputs); + for (i = 0; i < MAP(node)->ninputs; i++) { + input = MAP(node)->save_binding[i]; + arrival_times[i] = &(MAP(input)->map_arrival); + } + arrival = delay_map_simulate(MAP(node)->ninputs, arrival_times, MAP(node)->gate->delay_info, MAP(node)->load); + MAP(node)->map_arrival = arrival; + if (MAP(node)->arrival_info) FREE(MAP(node)->arrival_info); + MAP(node)->arrival_info = ALLOC(delay_time_t, MAP(node)->ninputs); + for (i = 0; i < MAP(node)->ninputs; i++) { + MAP(node)->arrival_info[i] = *arrival_times[i]; + } + FREE(arrival_times); + } + break; + case NODE_UNDEFINED: + default: + fail("illegal node type"); + } +} diff --git a/sis/map/virtual_net.c b/sis/map/virtual_net.c new file mode 100644 index 0000000..900845b --- /dev/null +++ b/sis/map/virtual_net.c @@ -0,0 +1,696 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/map/virtual_net.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:26 $ + * + */ +/* file @(#)virtual_net.c 1.7 */ +/* last modified on 7/22/91 at 12:36:42 */ +/* + * $Log: virtual_net.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:26 pchong + * imported + * + * Revision 1.5 1993/08/05 16:14:19 sis + * Added default case to switch statement so gcc version will work. + * + * Revision 1.4 1992/06/05 16:21:19 sis + * bug fix in do_flatten (it skipped POs, resulting in significant + * area overheads) + * + * Revision 1.3 1992/06/01 20:26:28 cmoon + * fixed a bug in do_flatten + * + * Revision 1.2 1992/03/03 00:18:47 cmoon + * do_flatten now handles latches correctly + * + * Revision 1.1 92/01/08 17:40:59 sis + * Initial revision + * + * Revision 1.2 91/07/02 11:22:59 touati + * add a routine to remove all buffers before fanout optimization. + * Before, there was a piece of code that was removing all inverters. + * Since we added support for non-inverting buffers, it was easier + * to remove buffers first, and then remove inverters using the old code + * than to modify the old code. + * + * Revision 1.1 91/06/28 15:47:24 touati + * Initial revision + * + */ + +#include "sis.h" +#include "map_int.h" +#include "lib_int.h" +#include "map_delay.h" +#include "fanout_int.h" + +static void check_fanin(); +static void check_fanout(); +static void concentrate_gate_links_on_source(); +static void remove_buffers(); +static void do_flatten(); +static void do_remove_wires(); +static void extract_local_virtual_network(); +static void extract_local_virtual_network_rec(); +static void make_sources_external(); +static int flatten_is_empty(); +static int flatten_is_source(); +static void remove_intermediate_nodes(); +static void virtual_network_check_node(); +static void virtual_network_setup_node_gate_links(); +static void virtual_setup_inverter(); +static void flatten_check_consistency(); + + /* EXTERNAL INTERFACE */ + + /* set up gate links. Clear up whatever was there before */ + +static bin_global_t global; + +void virtual_network_setup_gate_links(network, options) +network_t *network; +bin_global_t *options; +{ + int i; + node_t *node; + array_t *nodevec; + st_generator *gen; + char *key, *dummy; + st_table *delete_table; + + global = *options; + delete_table = st_init_table(st_numcmp, st_numhash); + nodevec = network_dfs_from_input(network); + for(i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + gate_link_delete_all(node); + } + for(i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + virtual_network_setup_node_gate_links(node, delete_table); + } + st_foreach_item(delete_table, gen, &key, &dummy) { + virtual_network_remove_node((node_t *) key, 1); + } + array_free(nodevec); + st_free_table(delete_table); +} + + + /* remove the wires and update the gate links properly */ + +void virtual_network_remove_wires(network) +network_t *network; +{ + bin_for_all_nodes_outputs_first(network, do_remove_wires); +} + + /* flattens the network: remove all but two sources */ + /* of opposite polarity and update the gate links */ + /* only one source if only one polarity is in use */ + +void virtual_network_flatten(network) +network_t *network; +{ + bin_for_all_nodes_inputs_first(network, remove_buffers); + bin_for_all_nodes_inputs_first(network, do_flatten); +} + + + /* remove a node from a virtual network */ + /* do not check whether the nodes it used to feed are not */ + /* still pointing towards it. This should be taken care of before */ + /* recursively removing all nodes that have it as unique output */ + /* if the flag is on, does it recursively */ + +void virtual_network_remove_node(node, rec_flag) +node_t *node; +int rec_flag; +{ + int pin; + gate_link_t link; + + if (node->type == PRIMARY_INPUT) return; + if (node->type == PRIMARY_OUTPUT) return; + if (MAP(node)->gate == NIL(lib_gate_t)) return; + + for (pin = 0; pin < MAP(node)->ninputs; pin++) { + node_t *input = MAP(node)->save_binding[pin]; + link.node = node; link.pin = pin; + gate_link_remove(input, &link); + if (rec_flag && gate_link_is_empty(input)) + virtual_network_remove_node(input, rec_flag); + } + MAP(node)->load = 0.0; + MAP(node)->required = MINUS_INFINITY; + MAP(node)->gate = NIL(lib_gate_t); + MAP(node)->ninputs = 0; + FREE(MAP(node)->save_binding); + MAP(node)->save_binding = NIL(node_t *); + gate_link_delete_all(node); +} + + + /* makes the node "source" source of the link */ + /* and update the info at the other end */ + /* be careful: if link->node == PRIMARY_OUTPUT, link->pin == -1 */ + +void virtual_network_add_to_gate_link(source, link) +node_t *source; +gate_link_t *link; +{ + if (link->node->type == PRIMARY_OUTPUT) { + if (MAP(link->node)->ninputs == 0) { + MAP(link->node)->ninputs = 1; + MAP(link->node)->save_binding = ALLOC(node_t *, 1); + } + MAP(link->node)->save_binding[0] = source; + } else { + MAP(link->node)->save_binding[link->pin] = source; + } + gate_link_put(source, link); +} + + + /* given new required time at node, update the gate links whose to-node is node */ + +void virtual_network_update_link_required_times(node, required) +node_t *node; +delay_time_t *required; +{ + int i; + node_t *input; + gate_link_t link; + + link.node = node; + switch (node->type) { + case PRIMARY_INPUT: + break; + case PRIMARY_OUTPUT: + if (node_num_fanin(node) == 0) return; + input = map_po_get_fanin(node); + link.pin = -1; + assert(gate_link_get(input, &link)); + link.required = MAP(node)->required; + gate_link_put(input, &link); + break; + case INTERNAL: + assert(MAP(node)->gate != NIL(lib_gate_t)); + for (i = 0; i < MAP(node)->ninputs; i++) { + input = MAP(node)->save_binding[i]; + link.pin = i; + assert(gate_link_get(input, &link)); + link.required = required[i]; + gate_link_put(input, &link); + } + break; + default: + ; + } +} + + + /* INTERNAL INTERFACE */ + + /* the basic convention about gate links */ + /* is that if a node is a primary output */ + /* the gate_link for its unique input is (po,-1) */ + +static void virtual_network_setup_node_gate_links(node, delete_table) +node_t *node; +st_table *delete_table; +{ + int pin; + node_t *input; + gate_link_t link; + + if (node->type == PRIMARY_OUTPUT) { + link.node = node; + link.pin = -1; + link.load = 0.0; + link.required = MINUS_INFINITY; + input = map_po_get_fanin(node); + gate_link_put(input, &link); + return; + } + if (MAP(node)->gate == NIL(lib_gate_t)) return; + if (gate_link_n_elts(node) == 0) { + st_insert(delete_table, (char *) node, NIL(char)); + return; + } + for (pin = 0; pin < MAP(node)->ninputs; pin++) { + link.node = node; + link.pin = pin; + link.load = 0.0; + link.required = MINUS_INFINITY; + input = MAP(node)->save_binding[pin]; + gate_link_put(input, &link); + } +} + + /* remove off the virtual network nodes mapped with wires */ + +static void do_remove_wires(node) +node_t *node; +{ + node_t *input; + gate_link_t link; + if (MAP(node)->gate == NIL(lib_gate_t)) return; + if (strcmp(MAP(node)->gate->name, "**wire**") != 0) return; + assert (! gate_link_is_empty(node)); + input = MAP(node)->save_binding[0]; + gate_link_first(node, &link); + do { + virtual_network_add_to_gate_link(input, &link); + } while (gate_link_next(node, &link)); + virtual_network_remove_node(node, 0); +} + + + /* buffers may be introduced by fanout optimization in some cases */ + /* to make the job of do_flatten easier, we first do one pass on the network */ + /* to remove all the existing buffers and update the underlying and the virtual network accordingly. */ + /* Buffers are already supposed to have been introduced by fanout optimization: */ + /* we check for that implicitly by asserting that all buffers at this stage have been mapped */ + +static void remove_buffers(node) +node_t *node; +{ + int i, n_fanouts; + lsGen gen; + node_t *fanin, *fanout; + gate_link_t link; + node_t **fanouts; + + if (node_function(node) != NODE_BUF) return; +#ifdef SIS + if (lib_gate_type(lib_gate_of(node)) != COMBINATIONAL) return; +#endif /* SIS */ + assert(MAP(node)->gate != NIL(lib_gate_t) && MAP(node)->ninputs == 1); + fanin = node_get_fanin(node, 0); + assert(fanin == MAP(node)->save_binding[0]); + + /* remove gate_link between 'fanin' and 'node' */ + link.node = node; + link.pin = 0; + gate_link_remove(fanin, &link); + + /* move gate_links and save_binding pointers between 'node' and its fanouts to 'fanin' */ + assert(! gate_link_is_empty(node)); + gate_link_first(node, &link); + do { + virtual_network_add_to_gate_link(fanin, &link); + } while (gate_link_next(node, &link)); + + /* update the underlying network */ + i = 0; + n_fanouts = node_num_fanout(node); + fanouts = ALLOC(node_t *, n_fanouts); + foreach_fanout(node, gen, fanout) { + fanouts[i++] = fanout; + } + for (i = 0; i < n_fanouts; i++) { + node_patch_fanin(fanouts[i], node, fanin); + } + FREE(fanouts); + network_delete_node(node_network(node), node); +} + + /* there are two networks: the underlying and the virtual */ + /* the underlying network is whatever is represented by the network_t data structure */ + /* the virtual network is represented by the MAP(node)->save_binding and MAP(node)->gate_link */ + /* the purpose of this routine is to perform some preprocessing to simplify fanout optimization */ + /* The basic idea is simple: for each node in the underlying network that is not an inverter nor a PO */ + /* we look at all the nodes in the virtual network which correspond to the same signal as the */ + /* output of that node (possibly of opposite polarity). If a big gate covers the node in the virtual */ + /* network, this set may be empty. If it is not empty, we put it as the source of all the positive */ + /* polarity signals, and pick up one node as a source for negative polarity signals. */ + /* This node is saved in MAP(node)->node_y and may be 0 if there is no negative polarity sinks. */ + /* All the other nodes mapped to inverters are removed from the virtual network. */ + +static void do_flatten(node) +node_t *node; +{ + int p; + lsGen gen; + node_t *fanout; + node_t *sources[2]; + st_table *nodes[2]; + + switch (node_function(node)) { + case NODE_UNDEFINED: + case NODE_0: + case NODE_1: + case NODE_BUF: + case NODE_PO: + case NODE_INV: + return; + case NODE_PI: + case NODE_AND: + case NODE_OR: + case NODE_COMPLEX: +#ifdef SIS + foreach_fanout(node, gen, fanout) { + switch (lib_gate_type(lib_gate_of(fanout))) { + case COMBINATIONAL: + case UNKNOWN: + break; + default: + LS_ASSERT(lsFinish(gen)); + return; + } + } +#endif /* SIS */ + break; + default: + fail("unexpected node function"); + /* NOTREACHED */ + } + + /* select as sources[POLAR_Y] a mapped fanout if possible */ + /* may have multiple fanout even if fanin > 0 after the first pass of fanout opt */ + sources[POLAR_X] = node; + sources[POLAR_Y] = NIL(node_t); + foreach_fanout(node, gen, fanout) { + if (node_function(fanout) != NODE_INV) continue; + if (sources[POLAR_Y] == NIL(node_t)) { + sources[POLAR_Y] = fanout; + } else if (MAP(sources[POLAR_Y])->gate == NIL(lib_gate_t)) { + sources[POLAR_Y] = fanout; + } else if (MAP(fanout)->gate != NIL(lib_gate_t) && MAP(fanout)->ninputs > 1) { + sources[POLAR_Y] = fanout; + } + } + assert(sources[POLAR_Y] != NIL(node_t)); + MAP(sources[POLAR_X])->node_y = sources[POLAR_Y]; + + /* extract nodes with nonempty gate link */ + /* make sure sources[POLAR_Y] is not left in these tables */ + foreach_polarity(p) { nodes[p] = st_init_table(st_numcmp, st_numhash); } + extract_local_virtual_network(nodes, sources[POLAR_X]); + st_delete(nodes[POLAR_Y], (char **) &sources[POLAR_Y], NIL(char *)); + + foreach_polarity(p) { + concentrate_gate_links_on_source(nodes[p], nodes[POLAR_INV(p)], sources[p]); + } + + /* + * If no logic duplication is allowed, make sure that one of the sources is external the other + * NIL or an inverter to the former. + * If logic duplication is allowed, keep both external sources. + */ + + make_sources_external(sources, nodes); + foreach_polarity(p) { flatten_check_consistency(sources[p]); } + + /* cleanup */ + foreach_polarity(p) { remove_intermediate_nodes(nodes[p]); } + foreach_polarity(p) { st_free_table(nodes[p]); } +} + +static void extract_local_virtual_network(nodes, source) +st_table **nodes; +node_t *source; +{ + lsGen gen; + node_t *fanout; + + foreach_fanout(source, gen, fanout) { + extract_local_virtual_network_rec(nodes, fanout, POLAR_X); + } +} + +static void extract_local_virtual_network_rec(nodes, node, polarity) +st_table **nodes; +node_t *node; +int polarity; +{ + lsGen gen; + node_t *fanout; + int node_polarity; + + if (node_function(node) != NODE_INV) return; + node_polarity = POLAR_INV(polarity); + if (MAP(node)->gate != NIL(lib_gate_t)) + st_insert(nodes[node_polarity], (char *) node, NIL(char)); + foreach_fanout(node, gen, fanout) { + extract_local_virtual_network_rec(nodes, fanout, node_polarity); + } +} + +static void make_sources_external(sources, nodes) +node_t **sources; +st_table **nodes; +{ + int p; + int is_empty[2]; + int is_source[2]; + node_t *source = sources[POLAR_X]; + + foreach_polarity(p) { + is_empty[p] = flatten_is_empty(sources[p], nodes[POLAR_INV(p)]); + is_source[p] = flatten_is_source(sources[p]); + } + + /* + * There is always a sources[POLAR_Y] at this point. + * If sources[POLAR_Y] is not mapped to anything, since it cannot possibly be a PI + * or a constant node, sources[POLAR_X] has to be source (or everything is empty). + * If there is a sink of polarity POLAR_Y, we set up an inverter on sources[POLAR_Y] + * to maintain network consistency (i.e. we could stop after do_flatten and get + * a consistently annotated network). If there is no sink of polarity POLAR_Y, + * we do not need to do anything. + */ + + assert(sources[POLAR_Y] != NIL(node_t)); + if (MAP(sources[POLAR_Y])->gate == NIL(lib_gate_t)) { + assert(is_source[POLAR_X] || (is_empty[POLAR_X] && is_empty[POLAR_Y])); + if (is_empty[POLAR_Y]) return; + virtual_setup_inverter(sources[POLAR_X], sources[POLAR_Y]); + return; + } + + /* + * if sources[POLAR_Y] is mapped to an inverter, keep it + */ + + if (MAP(sources[POLAR_Y])->ninputs == 1) { + assert(! is_empty[POLAR_X] && is_source[POLAR_X]); + assert(MAP(sources[POLAR_Y])->save_binding[0] == source); + return; + } + + /* + * If sources[POLAR_X] is not mapped to anything + * if there are sinks of the same polarity, add a inverter + * rooted at sources[POLAR_Y]. Otherwise, nothing to do. + */ + + if (MAP(source)->gate == NIL(lib_gate_t)) { + if (is_empty[POLAR_X]) return; + virtual_setup_inverter(sources[POLAR_Y], sources[POLAR_X]); + return; + } + + if (global.allow_duplication || global.allow_internal_fanout) { + return; + } else { + assert(! is_source[POLAR_X]); + assert(MAP(source)->ninputs == 1); + assert(! is_empty[POLAR_X]); + assert(MAP(source)->save_binding[0] == sources[POLAR_Y]); + return; + } +} + + /* + * is empty iff (1) or (2): + * (1) there is no sink hooked to it + * (2) the only nodes hooked to it are in table (nodes local to the network of inverters) + * the other source is not in that table, so it counts as non empty if there. + */ + +static int flatten_is_empty(node, table) +node_t *node; +st_table *table; +{ + int is_empty = 1; + gate_link_t link; + + if (node == NIL(node_t)) return 1; + if (gate_link_is_empty(node)) return 1; + gate_link_first(node, &link); + do { + if (! st_lookup(table, (char *) link.node, NIL(char *))) + is_empty = 0; + } while (gate_link_next(node, &link)); + return is_empty; +} + +/* + * a source is anything that can generate a signal. + * Can be a constant node, a PI, or a node mapped with a complex gate. + * NIL node, unmapped nodes, nodes mapped with a buffer or an inverter are out. + */ + +static int flatten_is_source(source) +node_t *source; +{ + node_function_t node_fn; + + if (source == NIL(node_t)) return 0; + if (MAP(source)->ninputs > 1) return 1; + node_fn = node_function(source); + if (node_fn == NODE_PI || node_fn == NODE_0 || node_fn == NODE_1) return 1; + return 0; +} + +static void virtual_setup_inverter(source, dest) +node_t *source; +node_t *dest; +{ + gate_link_t link; + + assert(MAP(dest)->gate == NIL(lib_gate_t)); + MAP(dest)->gate = lib_get_default_inverter(); + MAP(dest)->ninputs = 1; + MAP(dest)->save_binding = ALLOC(node_t *, 1); + MAP(dest)->save_binding[0] = source; + link.node = dest; + link.pin = 0; + link.load = 0.0; + link.required = MINUS_INFINITY; + gate_link_put(source, &link); +} + +static void concentrate_gate_links_on_source(nodes, inv_nodes, source) +st_table *nodes; +st_table *inv_nodes; +node_t *source; +{ + node_t *node; + char *value; + st_generator *gen; + gate_link_t link; + + if (st_count(nodes) == 0) return; + assert(source != NIL(node_t)); + + st_foreach_item(nodes, gen, (char **) &node, &value) { + gate_link_first(node, &link); + do { + if (st_lookup(inv_nodes, (char *) link.node, NIL(char *))) continue; + virtual_network_add_to_gate_link(source, &link); + } while (gate_link_next(node, &link)); + } +} + +static void remove_intermediate_nodes(nodes) +st_table *nodes; +{ + node_t *node; + char *dummy; + st_generator *gen; + + st_foreach_item(nodes, gen, (char **) &node, &dummy) { + virtual_network_remove_node(node, 1); + } +} + + /* case of PRIMARY_INPUT going nowhere: there may be a single inverter attached to it */ + /* that itself goes nowhere. This is due to the trick of adding inverters all over the place */ + +static void flatten_check_consistency(node) +node_t *node; +{ + int alive; + int empty_fanout; + node_t *fanout; + + if (node == NIL(node_t)) return; + + alive = (node->type == PRIMARY_INPUT || MAP(node)->gate != NIL(lib_gate_t)); + empty_fanout = gate_link_is_empty(node); + if ((alive && ! empty_fanout) || (! alive && empty_fanout)) return; + if (global.allow_duplication) return; + + assert(node->type == PRIMARY_INPUT); + assert(node_num_fanout(node) == 1); + fanout = node_get_fanout(node, 0); + assert(node_num_fanout(fanout) == 0); +} + +void virtual_network_check(network) +network_t *network; +{ + lsGen gen; + node_t *node; + + foreach_node(network, gen, node) { + virtual_network_check_node(node); + } +} + +static void virtual_network_check_node(node) +node_t *node; +{ + switch (node->type) { + case INTERNAL: + if (MAP(node)->gate != NIL(lib_gate_t)) { + check_fanin(node); + check_fanout(node); + } + break; + case PRIMARY_INPUT: + check_fanout(node); + break; + case PRIMARY_OUTPUT: + check_fanin(node); + break; + default: + fail("unexpected node type"); + break; + } +} + +static void check_fanout(node) +node_t *node; +{ + gate_link_t link; + assert(! gate_link_is_empty(node)); + gate_link_first(node, &link); + do { + if (link.node->type == PRIMARY_OUTPUT) { + assert (node == map_po_get_fanin(link.node)); + } else { + assert(MAP(link.node)->gate != NIL(lib_gate_t)); + assert(node == MAP(link.node)->save_binding[link.pin]); + } + } while (gate_link_next(node, &link)); +} + +static void check_fanin(node) +node_t *node; +{ + int i; + node_t *fanin; + gate_link_t link; + + if (node->type == PRIMARY_OUTPUT) { + fanin = map_po_get_fanin(node); + link.node = node; + link.pin = -1; + assert(gate_link_get(fanin, &link)); + return; + } + for (i = 0; i < MAP(node)->ninputs; i++) { + fanin = MAP(node)->save_binding[i]; + link.node = node; + link.pin = i; + assert(gate_link_get(fanin, &link)); + } +} diff --git a/sis/maxflow/Makefile.am b/sis/maxflow/Makefile.am new file mode 100644 index 0000000..16ad607 --- /dev/null +++ b/sis/maxflow/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libmaxflow.a +libmaxflow_a_SOURCES = com_max.c cutset.c maxflow.c mf_input.c \ + maxflow_int.h +pkginclude_HEADERS = maxflow.h +dist_doc_DATA = maxflow.doc diff --git a/sis/maxflow/Makefile.in b/sis/maxflow/Makefile.in new file mode 100644 index 0000000..13ea0d4 --- /dev/null +++ b/sis/maxflow/Makefile.in @@ -0,0 +1,421 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libmaxflow_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/maxflow +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libmaxflow_a_AR = $(AR) $(ARFLAGS) +libmaxflow_a_LIBADD = +am_libmaxflow_a_OBJECTS = com_max.$(OBJEXT) cutset.$(OBJEXT) \ + maxflow.$(OBJEXT) mf_input.$(OBJEXT) +libmaxflow_a_OBJECTS = $(am_libmaxflow_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libmaxflow_a_SOURCES) +DIST_SOURCES = $(libmaxflow_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libmaxflow.a +libmaxflow_a_SOURCES = com_max.c cutset.c maxflow.c mf_input.c \ + maxflow_int.h + +pkginclude_HEADERS = maxflow.h +dist_doc_DATA = maxflow.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/maxflow/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/maxflow/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libmaxflow.a: $(libmaxflow_a_OBJECTS) $(libmaxflow_a_DEPENDENCIES) + -rm -f libmaxflow.a + $(libmaxflow_a_AR) libmaxflow.a $(libmaxflow_a_OBJECTS) $(libmaxflow_a_LIBADD) + $(RANLIB) libmaxflow.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/maxflow/com_max.c b/sis/maxflow/com_max.c new file mode 100644 index 0000000..bcbbceb --- /dev/null +++ b/sis/maxflow/com_max.c @@ -0,0 +1,216 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/maxflow/com_max.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +#include "sis.h" +#include "maxflow_int.h" + +#define MAXLINE 200 + +/* ARGSUSED */ +com_maxflow(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + maxflow_debug = 1 - maxflow_debug; +} + +/* ARGSUSED */ +com_test_mf(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i,j; + mf_graph_t *graph; + mf_cutset_t *cutset; + mf_node_t *node; + mf_edge_t *edge; + array_t *from, *to, *flow; + + /* + * Build up a dummy network and print out the + * cutset and the flows + */ + + graph = mf_alloc_graph(); + + /* read in the network */ + + mf_read_node( graph, "mf_source", 1); + mf_read_node( graph, "mf_sink", 2); + mf_read_node( graph, "a", 0); + mf_read_node( graph, "b", 0); + mf_read_node( graph, "c", 0); + mf_read_node( graph, "d", 0); + mf_read_node( graph, "e", 0); + mf_read_node( graph, "f", 0); + mf_read_node( graph, "g", 0); + + /* Now the capacities */ + mf_read_edge( graph, "mf_source","a", 2); + mf_read_edge( graph, "mf_source","b", 2); + mf_read_edge( graph, "a","c", 3); + mf_read_edge( graph, "b","c", 1); + mf_read_edge( graph, "b","d", 2); + mf_read_edge( graph, "c","f", 4); + mf_read_edge( graph, "d","e", 1); + mf_read_edge( graph, "e","mf_sink", 2); + mf_read_edge( graph, "f","e", 2); + mf_read_edge( graph, "f","g", 3); + mf_read_edge( graph, "g","mf_sink", 1); + + mf_display_graph(sisout,graph); + maxflow( graph, 0); + + cutset = mf_get_cutset( graph, &from, &to, &flow); + + (void) fprintf( sisout," From to flow\n"); + for ( i = 0; i < array_n(from); i++){ + (void) fprintf( sisout, " %-10s%-10s %3d\n", + array_fetch( char *, from, i), + array_fetch( char *, to, i), + array_fetch( int , flow, i)); + } + mf_free_cutset( cutset); + + (void)fprintf(sisout,"Cutset has %d arcs\n", mf_sizeof_cutset(graph)); + mf_foreach_node(graph, i, node){ + mf_foreach_fanin(node, j, edge){ + if ( mf_is_edge_on_mincut(edge)){ + (void)fprintf(sisout,"%s -> %s : Cap = %d, flow = %d\n", + mf_node_name(mf_tail_of_edge(edge)), + mf_node_name(mf_head_of_edge(edge)), + mf_get_edge_capacity(edge), + mf_get_edge_flow(edge)); + } + } + } + (void)mf_remove_node( graph, "d"); + (void)mf_reread_edge(graph,"g","mf_sink",3); + mf_change_node_type(graph,mf_get_source_node(graph),0); + mf_change_node_type(graph, mf_get_node(graph,"a"),1); + (void)fprintf(sisout,"After modfication \n"); + mf_display_graph(sisout, graph); + maxflow(graph,0); + mf_foreach_node(graph, i, node){ + mf_foreach_fanin(node, j, edge){ + if ( mf_is_edge_on_mincut(edge)){ + (void)fprintf(sisout,"%s -> %s : Cap = %d, flow = %d\n", + mf_node_name(mf_tail_of_edge(edge)), + mf_node_name(mf_head_of_edge(edge)), + mf_get_edge_capacity(edge), + mf_get_edge_flow(edge)); + } + } + } + + mf_free_graph( graph); + array_free( from); + array_free( to); + array_free( flow); +} + + +/* ARGSUSED */ +com__run_maxflow(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i,j, cap; + FILE *input; + char s[MAXLINE]; + char from[MF_MAXSTR], to[MF_MAXSTR]; + mf_graph_t *graph; + mf_cutset_t *cutset; + array_t *from_array, *to_array, *flow; + + if ( argc < 2 ) goto run_mf_usage; + + graph = mf_alloc_graph(); + input = fopen(argv[1],"r"); + if ( input == NIL(FILE)) return 1; + + j = 0; + while( fgets(s, MAXLINE, input) != NULL){ + if ( strcmp(s,"") == 0) continue; + j++; + if ( j == 1){ + /* get and create the source and sink */ + i = sscanf(s,"Source:%s Sink:%s", from, to); + if ( i != 2){ + error_append("Improper Input format\n"); + goto abort; + } + mf_read_node(graph, from, 1); /* source */ + + mf_read_node(graph, to, 2); /* sink */ + continue; + } else if ( j == 2){ + continue; + } else { + i = sscanf(s,"%s %s %d", from, to, &cap); + if ( i != 3) { + error_append("Improper input format\n"); + goto abort; + } + if ( mf_get_node(graph, from) == NIL(mf_node_t)){ + mf_read_node(graph, from, 0); + } + if ( mf_get_node(graph, to) == NIL(mf_node_t)){ + mf_read_node(graph, to, 0); + } + mf_read_edge(graph, from, to, cap); + } + } + + maxflow( graph, 0); + + cutset = mf_get_cutset( graph, &from_array, &to_array, &flow); + + (void) fprintf( sisout,"Following maxflow/mincut found:\n"); + (void) fprintf( sisout," From to flow\n"); + for ( i = 0; i < array_n(from_array); i++){ + (void) fprintf( sisout, " %-10s%-10s %3d\n", + array_fetch( char *, from_array, i), + array_fetch( char *, to_array, i), + array_fetch( int , flow, i)); + } + mf_free_cutset( cutset); + + (void) fclose(input); + mf_free_graph( graph); + array_free( from_array); + array_free( to_array); + array_free( flow); + + return 0; +run_mf_usage: + (void)fprintf(sisout,"Usage: _run_maxflow input_file \n"); + return 1; +abort: + (void)fprintf(sisout,"%s\n", error_string()); + (void) fclose(input); + mf_free_graph(graph); + return 1; +} + +init_maxflow() +{ + maxflow_debug = FALSE; + + com_add_command("_maxflow", com_maxflow, 0); + com_add_command("_test_mf", com_test_mf, 0); + com_add_command("_run_maxflow", com__run_maxflow, 0); +} + +end_maxflow() +{ +} diff --git a/sis/maxflow/cutset.c b/sis/maxflow/cutset.c new file mode 100644 index 0000000..4f241c0 --- /dev/null +++ b/sis/maxflow/cutset.c @@ -0,0 +1,203 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/maxflow/cutset.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +/*************************************************** +* +* Function: cutset() +* +* Author: Kanwar Jit Singh +* +*****************************************************/ + +#include "sis.h" +#include "maxflow_int.h" + +#define VLARGE (int)1000000 +int maxflow_debug; + + +/* ARGSUSED */ +enum st_retval +speed_add_node_to_graph(node, cap, store) +char *node, **cap; +char *store; +{ + mfgptr graph; + char name[MF_MAXSTR], dup_name[MF_MAXSTR]; + + graph = (mfgptr)store; + + (void) sprintf(name,"%s",node_long_name((node_t *)node)); + (void) sprintf(dup_name,"%s_dup",node_long_name((node_t *)node)); + + mf_read_node(graph, name, 0); + mf_read_node(graph, dup_name, 0); + + return ST_CONTINUE; +} + +array_t * +cutset(network,node_table) +network_t *network; +st_table *node_table; +{ + array_t *cut; + cut = cutset_interface(network, node_table, VLARGE); + return cut; +} + +array_t * +cutset_interface(network, node_table, edge_weight) +network_t *network; +st_table *node_table; +int edge_weight; +{ + st_table *name_node_table; + array_t *array; + mfgptr graph; + st_generator *gene; + char *key, *dummy; + + /* Create the flow network */ + graph = mf_create_flow_network(network, node_table, edge_weight, &name_node_table); + + /* Run the maxflow algorithm on the flow networek */ + maxflow(graph,0); + + /* Get cutset and translate it into nodes of the network */ + array = mf_build_node_cutset(graph, name_node_table); + + /* FREE the memory in the name_node_table and the flow network */ + st_foreach_item(name_node_table, gene, &key, &dummy){ + FREE(key); + } + st_free_table(name_node_table); + mf_free_graph(graph); + + return array; +} + +mf_graph_t * +mf_create_flow_network(network, node_table, edge_weight, p_name_node_table) +network_t *network; +st_table *node_table; +int edge_weight; +st_table **p_name_node_table; +{ + array_t *df_array; + mfgptr graph; + node_t *fi, *fo, *node; + lsGen gen; + char *dummy, temp_name[MF_MAXSTR], name[MF_MAXSTR]; + int j, i, capacity, terminal_flag; + + graph = mf_alloc_graph(); + *p_name_node_table = st_init_table(strcmp,st_strhash); + + /* + * For each node in the network create + * a node and also a duplicate + */ + mf_read_node(graph,"maxflow_source",1); + mf_read_node(graph,"maxflow_sink",2); + st_foreach(node_table, speed_add_node_to_graph, (char *)graph); + + /* + * For each node create an edge to each fanin + * which is in node_table, assign capacity + * to the duplicate. + */ + df_array = network_dfs_from_input(network); + for(i = 0; i < array_n(df_array) ; i++){ + node = array_fetch(node_t *, df_array, i); + if (node->type == INTERNAL){ + if(st_lookup(node_table, (char *)node, &dummy)){ + capacity = (int) dummy; + /* Add the edge between the node and its dup */ + (void) sprintf(name,"%s",node_long_name(node)); + (void) sprintf(temp_name,"%s_dup",node_long_name(node)); + mf_read_edge(graph,name, temp_name,capacity); + + + /* Save the pointer referenced by name */ + (void)st_insert(*p_name_node_table, util_strsav(name), (char *)node); + + /* Add an edge to the source if no fanin is + in the table or if the fanin is a primary i/p */ + terminal_flag = 1; + foreach_fanin(node, j, fi){ + if (st_lookup(node_table,(char *)fi, &dummy)){ + (void) sprintf(temp_name,"%s_dup", node_long_name(fi)); + mf_read_edge(graph, temp_name, name, edge_weight); + terminal_flag = 0; + } + } + if (terminal_flag){ + mf_read_edge(graph, "maxflow_source", name, edge_weight); + } + + /* Add an edge to the sink if no fanout is in table */ + terminal_flag = 1; + foreach_fanout(node, gen, fo){ + if (st_lookup(node_table,(char *)fo, &dummy)){ + terminal_flag = 0; + } + } + if (terminal_flag){ + (void) sprintf(temp_name,"%s_dup", node_long_name(node)); + mf_read_edge(graph, temp_name, "maxflow_sink", edge_weight); + } + } + } + } + array_free(df_array); + + return graph; +} + +array_t * +mf_build_node_cutset(graph, name_node_table) +mf_graph_t *graph; +st_table *name_node_table; +{ + int i; + char *dummy; + node_t *node; + array_t *array; + mfcptr mf_cutset; + + /* Get the cutset from the flow network */ + if (!(mf_cutset = MF_ALLOC(1, mf_cutset_t ))) + mf_error("Memory allocation failure", "cutset"); + mf_cutset->graph = graph; + get_cutset(mf_cutset); + + if (maxflow_debug){ + (void) fprintf(sisout,"Cutset edges:"); + for(i = 0; i < mf_cutset->narcs; i++){ + (void) fprintf(sisout," %s(%d)", (mf_cutset->from_node)[i], (mf_cutset->capacity)[i]); + } + (void) fprintf(sisout,"\n"); + } + + array = array_alloc(node_t *,0); + for(i = 0; i < mf_cutset->narcs; i++){ + if(st_lookup(name_node_table, (mf_cutset->from_node)[i], &dummy)){ + node = (node_t *)dummy; + array_insert_last(node_t *, array, node); + } + else{ + (void) fprintf(sisout,"Unknown node %s encountered \n",(mf_cutset->from_node)[i]); + } + } + + mf_free_cutset(mf_cutset); + + return array; +} diff --git a/sis/maxflow/maxflow.c b/sis/maxflow/maxflow.c new file mode 100644 index 0000000..6a584d6 --- /dev/null +++ b/sis/maxflow/maxflow.c @@ -0,0 +1,591 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/maxflow/maxflow.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +/**********************************************************************/ +/* maximal flow algorithm */ +/* */ +/* Author: Hi-Keung Tony Ma */ +/* last update : 02/26/1988 */ +/* Packaging and garbage collection: Kanwar Jit Singh */ +/**********************************************************************/ + +#include "sis.h" +#include "maxflow_int.h" + +void +maxflow(graph, verify) +mfgptr graph; +int verify; +{ + mfnptr n,ntemp,nscan; + mfeptr e; + int i; + void maxflow_init(), augmentation(), construct_cutset(); + void check(), min_cutset_check(); + + maxflow_init(graph); + graph->source_node->flag |= LABELLED; + graph->source_node->increment_flow = MAX_FLOW; + graph->first_label_element = graph->source_node; + graph->last_label_element = graph->source_node; + nscan = graph->source_node; + + while (nscan) { + for (i = 0; i < nscan->nout; i++) { + e = nscan->out_edge[i]; + if (!(e->onode->flag & LABELLED) && (e->flow < e->capacity)) { + e->onode->flag |= LABELLED; + e->onode->direction = 1; + e->onode->path_node = nscan; + e->onode->path_edge = e; + e->onode->increment_flow = MIN((e->capacity - e->flow),nscan->increment_flow); + if (e->onode != graph->sink_node) { + graph->last_label_element->pnext = e->onode; + graph->last_label_element = e->onode; + } + } + } + for (i = 0; i < nscan->nin; i++) { + e = nscan->in_edge[i]; + if (!(e->inode->flag & LABELLED) && (e->flow > 0)) { + e->inode->flag |= LABELLED; + e->inode->direction = -1; + e->inode->path_node = nscan; + e->inode->path_edge = e; + e->inode->increment_flow = MIN(e->flow,nscan->increment_flow); + if (e->inode != graph->sink_node) { + graph->last_label_element->pnext = e->inode; + graph->last_label_element = e->inode; + } + } + } + nscan = nscan->pnext; + + if (graph->sink_node->flag & LABELLED) { + augmentation(graph); + for (n = graph->first_label_element->pnext; n; n = ntemp) { + ntemp = n->pnext; + n->pnext = NIL(mf_node_t); + n->flag &= ~LABELLED; + } + graph->first_label_element = graph->source_node; + graph->last_label_element = graph->source_node; + graph->source_node->pnext = NIL(mf_node_t ); + nscan = graph->source_node; + } + } + + construct_cutset(graph); + + /*mf_display_flow(sisout, graph);*/ + + check(graph); + if (verify) min_cutset_check(graph); +}/* end of maxflow */ + + +void +augmentation(graph) +mfgptr graph; +{ + mfnptr n; + int increment; + + graph->sink_node->flag &= ~LABELLED; + n = graph->sink_node; + increment = n->increment_flow; + while (n != graph->source_node) { + if (n->direction == 1) n->path_edge->flow += increment; + else n->path_edge->flow -= increment; + n = n->path_node; + } +}/* end of augmentation */ + + +void +construct_cutset(graph) +mfgptr graph; +{ + int i,j; + + for (i = 0; i < graph->num_of_node; i++) { + if (graph->nlist[i]->flag & LABELLED) { + for (j = 0; j < graph->nlist[i]->nout; j++) { + if (!(graph->nlist[i]->out_edge[j]->onode->flag & LABELLED)) { + graph->nlist[i]->out_edge[j]->flag |= CUTSET; + } + } + } + } +}/* end of construct_cutset */ + +void +mf_display_graph(outfile, graph) +FILE *outfile; +mfgptr graph; +{ + int i,j; + mfnptr n; + mfeptr e; + + (void) fprintf(outfile, "Source:%-14s Sink:%-14s\n", + mf_node_name(mf_get_source_node(graph)), + mf_node_name(mf_get_sink_node(graph))); + (void) fprintf(outfile, "%-14s %-14s %-14s\n", "From","To","Capacity"); + mf_foreach_node(graph, i, n){ + mf_foreach_fanout(n, j, e){ + (void) fprintf(outfile, "%-14s %-14s %-14d\n", n->name, e->onode->name, e->capacity); + } + } +}/* end of mf_display_graph */ + +void +mf_display_cutset(outfile, graph) +FILE *outfile; +mfgptr graph; +{ + int i,j; + mf_node_t *node; + mf_edge_t *edge; + + /*(void) fprintf(outfile,"\n");*/ + (void) fprintf(outfile,"Cutset Edges:\n"); + (void) fprintf(outfile,"-------------\n"); + (void) fprintf(outfile,"Input node Output node Flow\n"); + mf_foreach_node(graph, i, node){ + mf_foreach_fanout(node, j, edge){ + if (edge->flag & CUTSET) { + (void) fprintf(outfile,"\n"); + (void) fprintf(outfile,"%-14s %-14s %-14d\n", + mf_node_name(node), mf_node_name(mf_head_of_edge(edge)), + mf_get_edge_capacity(edge)); + } + } + } +}/* end of mf_display_cutset */ + + +void +mf_display_flow(outfile, graph) +FILE *outfile; +mfgptr graph; +{ + int i,j; + + (void) fprintf(outfile,"\n"); + (void) fprintf(outfile,"\n"); + (void) fprintf(outfile,"debugging output flow...\n"); + for (i = 0; i < graph->num_of_node; i++) { + for (j = 0; j < graph->nlist[i]->nout; j++) { + (void) fprintf(outfile,"\n"); + (void) fprintf(outfile,"%-9s %-9s %-9d\n",graph->nlist[i]->name, graph->nlist[i]->out_edge[j]->onode->name,graph->nlist[i]->out_edge[j]->flow); + } + } +}/* end of mf_display_flow */ + +/* this routitne checks + * 1) the conservation of flow; + * 2) flow is smaller than the capacity; + * 3) flow in cutset edge equals to capacity; + * 4) cutset cuts all paths from source to sink + */ +void +check(graph) +mfgptr graph; +{ + int i,j,inflow,outflow; + void unmark_every_node(); + int trace_path(); + + for (i = 0; i < graph->num_of_node; i++) { + inflow = 0; + outflow = 0; + for (j = 0; j < graph->nlist[i]->nin; j++) { + inflow += graph->nlist[i]->in_edge[j]->flow; + } + for (j = 0; j < graph->nlist[i]->nout; j++) { + outflow += graph->nlist[i]->out_edge[j]->flow; + if (graph->nlist[i]->out_edge[j]->flow > graph->nlist[i]->out_edge[j]->capacity) { + (void) fprintf(siserr,"\n"); + (void) fprintf(siserr,"Internal Error: flow is larger than the capacity!\n"); + (void) fprintf(siserr,"edge: input node = %s; output node = %s\n",graph->nlist[i]->name,graph->nlist[i]->out_edge[j]->onode->name); + abort(); + } + if ((graph->nlist[i]->out_edge[j]->flag & CUTSET) && (graph->nlist[i]->out_edge[j]->flow != graph->nlist[i]->out_edge[j]->capacity)) { + (void) fprintf(siserr,"\n"); + (void) fprintf(siserr,"Internal Error: flow in cutset edge is not equal to capacity!\n"); + (void) fprintf(siserr,"edge: input node = %s; output node = %s\n",graph->nlist[i]->name,graph->nlist[i]->out_edge[j]->onode->name); + abort(); + } + } + if ((outflow != inflow) && (graph->nlist[i] != graph->source_node) && (graph->nlist[i] != graph->sink_node)) { + (void) fprintf(siserr,"\n"); + (void) fprintf(siserr,"Internal Error: Violation of conservation of flow!\n"); + (void) fprintf(siserr,"node: %s\n",graph->nlist[i]->name); + abort(); + } + } + + /* check whether the cutset cuts all paths from source to sink */ + unmark_every_node(graph); + if (trace_path(graph, graph->source_node)) { + (void) fprintf(siserr,"\n"); + (void) fprintf(siserr,"Internal Error: Cutset unable to cut all the paths from source to sink!\n"); + abort(); + } +}/* end of check */ + +trace_path(graph, n) +mfgptr graph; +mfnptr n; +{ + int i; + int trace; + + if (n == graph->sink_node) return(TRUE); + else { + trace = FALSE; + if (!(n->flag & MARKED)) { + n->flag |= MARKED; + for (i = 0; i < n->nout; i++) { + if (!(n->out_edge[i]->flag & CUTSET)) { + if (trace_path(graph, n->out_edge[i]->onode)) trace = TRUE; + } + } + } + } + return(trace); +}/* end of trace_path */ + + +void +min_cutset_check(graph) +mfgptr graph; +{ + int i,j; + void unmark_every_node(); + int trace_path(); + + for (i = 0; i < graph->num_of_node; i++) { + for (j = 0; j < graph->nlist[i]->nout; j++) { + if (graph->nlist[i]->out_edge[j]->flag & CUTSET) { + unmark_every_node(graph); + graph->nlist[i]->out_edge[j]->flag &= ~CUTSET; + if (!(trace_path(graph, graph->source_node))) { + (void) fprintf(siserr,"\n"); + (void) fprintf(siserr,"Internal Error: Cutset is not minimum!\n"); + abort(); + } + graph->nlist[i]->out_edge[j]->flag |= CUTSET; + } + } + } +}/* end of min_cutset_check */ + + +void +unmark_every_node(graph) +mfgptr graph; +{ + int i; + + for (i = 0; i < graph->num_of_node; i++) { + graph->nlist[i]->flag &= ~MARKED; + } +}/* end of unmark_every_node */ + + +void +get_cutset(cutset) +mfcptr cutset; +{ + int i, j, k; + + cutset->narcs = 0; + /* count the number of cutset edges */ + for (i = 0; i < cutset->graph->num_of_node; i++) + for (j = 0; j < cutset->graph->nlist[i]->nout; j++) + if (cutset->graph->nlist[i]->out_edge[j]->flag & CUTSET) + (cutset->narcs)++; + + /* allocate memory */ + if (!(cutset->from_node = MF_ALLOC(cutset->narcs,char *)) && + cutset->narcs) + mf_error("Memory allocation failure", "get_cutset"); + if (!(cutset->to_node = MF_ALLOC(cutset->narcs,char *)) && cutset->narcs) + mf_error("Memory allocation failure", "get_cutset"); + if (!(cutset->capacity = MF_ALLOC(cutset->narcs, int)) && cutset->narcs) + mf_error("Memory allocation failure", "get_cutset"); + + /* fill in the cutset edges info */ + for (i = 0, k = 0; i < cutset->graph->num_of_node; i++) { + for (j = 0; j < cutset->graph->nlist[i]->nout; j++) { + if (cutset->graph->nlist[i]->out_edge[j]->flag & CUTSET) { + if (cutset->graph->nlist[i]->flag & FICTITIOUS) + cutset->from_node[k] = + cutset->graph->nlist[i]->fname; + else + cutset->from_node[k] = + cutset->graph->nlist[i]->name; + if (cutset->graph->nlist[i]->out_edge[j]->onode->flag + & FICTITIOUS) + cutset->to_node[k] = cutset->graph->nlist[i]->out_edge[j]->onode->fname; + else + cutset->to_node[k] = + cutset->graph->nlist[i]->out_edge[j]->onode->name; + cutset->capacity[k] = + cutset->graph->nlist[i]->out_edge[j]->flow; + k++; + } + } + } +}/* end of get_cutset */ + +mf_cutset_t * +mf_get_cutset(graph, from_array, to_array, flow_array) +mf_graph_t *graph; +array_t **from_array, **to_array, **flow_array; +{ + mf_cutset_t *cut; + int i; + + /* Allocate the cutset structure */ + if (!(cut = MF_ALLOC(1, mf_cutset_t))) + mf_error("Memory allocation failure", "mf_get_cutset"); + cut->graph = graph; + + *from_array = array_alloc(char *, 0); + *to_array = array_alloc(char *, 0); + *flow_array = array_alloc(int, 0); + + get_cutset(cut); + + for(i = 0; i < cut->narcs; i++){ + array_insert(char *, *from_array, i, (cut->from_node)[i]); + array_insert(char *, *to_array, i, (cut->to_node)[i]); + array_insert(int, *flow_array, i, (cut->capacity)[i]); + } + + return cut; +} + +void +maxflow_init(graph) +mfgptr graph; +{ + int i, j; + mfnptr n; + mfeptr e; + void fix_loop(), unmark_every_node(); + + if (!graph->source_node) + mf_error("Source node unspecified", "maxflow_init"); + if (!graph->sink_node) + mf_error("Sink node unspecified", "maxflow_init"); + fix_loop(graph); + /* + * Make sure fanin pointers are consistent. + * Unmark all the nodes and the edges + */ + mf_foreach_node(graph, i, n){ + n->flag = 0; + if (n->in_edge) FREE(n->in_edge); + if (!(n->in_edge = MF_ALLOC(n->nin, mfeptr)) && n->nin) + mf_error("Memory allocation failure", "maxflow_init"); + n->nin = 0; + n->pnext = NIL(mf_node_t); + } + mf_foreach_node(graph, i, n){ + for (j = 0; j < n->nout; j++) { + e = n->out_edge[j]; + e->flag = 0; + e->flow = 0; + e->onode->in_edge[e->onode->nin] = e; + e->onode->nin++; + } + } +}/* end of maxflow_init */ + + +mfnptr lnode1, lnode2; + +void +fix_loop(graph) +mfgptr graph; +{ + int i, no_loop = FALSE; + void break_loop(); + + while (!no_loop) { + for (i = 0; i < graph->num_of_node; i++) { + graph->nlist[i]->flag &= ~MARKED; + graph->nlist[i]->flag &= ~CUR_TRACE; + } + graph->source_node->flag |= MARKED; + graph->source_node->flag |= CUR_TRACE; + if (check_loop(graph->source_node) == TRUE) { +/* testing check_loop */ +/*(void) fprintf(siserr,"\nnodes %s and %s are involved in a loop!\n", lnode1->name,lnode2->name); + +abort();*/ + break_loop(graph, lnode1, lnode2); + no_loop = FALSE; + } + else { + no_loop = TRUE; + } + if (no_loop) { + for (i = 0; i < graph->num_of_node; i++) { + if (!(graph->nlist[i]->flag & MARKED)) { + graph->nlist[i]->flag |= MARKED; + graph->nlist[i]->flag |= CUR_TRACE; + if (check_loop(graph->nlist[i]) == TRUE) { + break_loop(graph, lnode1, lnode2); + no_loop = FALSE; + break; + } + } + } + } + } +}/* end of fix_loop */ + + +int +check_loop(node) +mfnptr node; +{ + int i; + mfnptr nnode; + + for (i = 0; i < node->nout; i++) { + nnode = node->out_edge[i]->onode; + if (!(nnode->flag & MARKED)) { + nnode->flag |= MARKED; + nnode->flag |= CUR_TRACE; + if (check_loop(nnode) == TRUE) return(TRUE); + } + else if (nnode->flag & CUR_TRACE) { + lnode1 = node; + lnode2 = nnode; + return(TRUE); + } + } + node->flag &= ~CUR_TRACE; + return(FALSE); +}/* end of traverse_node */ + + +void +break_loop(graph, node1, node2) +mfgptr graph; +mfnptr node1, node2; +{ + int index; + char nname1[MF_MAXSTR], nname2[MF_MAXSTR], intstring[5]; + char *dummy; + mfnptr n; + + index = 0; + while (node1->out_edge[index]->onode != node2) index++; + node1->nfict++; + node2->nfict++; + mf_itoa(node1->nfict, intstring); + (void) sprintf(nname1, "%s_fict%s", node1->name, intstring); + mf_read_node(graph, nname1, -1); + if (st_lookup(graph->node_table, nname1, &dummy)){ + n = (mf_node_t *)dummy; + } else mf_error("node not found","break_loop"); + n->fname = node1->name; + mf_itoa(node2->nfict, intstring); + (void) sprintf(nname2, "%s_fict%s", node2->name, intstring); + mf_read_node(graph, nname2, -1); + if (st_lookup(graph->node_table, nname2, &dummy)){ + n = (mf_node_t *)dummy; + } else mf_error("node not found","break_loop"); + n->fname = node2->name; + mf_read_edge(graph, graph->source_node->name, nname1, (int)MAX_FLOW); + mf_read_edge(graph, nname2, graph->sink_node->name, (int)MAX_FLOW); + mf_read_edge(graph, nname1, node2->name, + node1->out_edge[index]->capacity); + if (st_lookup(graph->node_table, node2->name, &dummy)){ + n = (mf_node_t *)dummy; + } else mf_error("node not found","break_loop"); + n->nin--; + if (st_lookup(graph->node_table, nname2, &dummy)){ + n = (mf_node_t *)dummy; + } else mf_error("node not found","break_loop"); + node1->out_edge[index]->onode = n; + n->nin++; +}/* end of break_loop */ + + +/* +* The itoa function +*/ + +mf_reverse(s) /* reverse string s in place */ +char s[]; +{ + int c,i,j; + + for(i = 0, j = strlen(s) - 1; i < j; i++, j--) { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } +} + +mf_itoa(n,s) /* convert n to characters in s */ +int n; +char s[]; +{ + int i,sign; + + if ((sign = n) < 0) /* record sign */ + n = -n; + i = 0; + do { /* generate digits in reverse order */ + s[i++] = n % 10 + '0' ; /* get next digit */ + } while ((n/=10) > 0); /* delete it */ + if (sign < 0) s[i++] = '-'; + s[i] = '\0'; + mf_reverse(s); +} /* end of itoa */ + + +int +mf_sizeof_cutset(graph) +mfgptr graph; +{ + int i, j, num_arcs; + + num_arcs = 0; + /* count the number of cutset edges */ + for (i = 0; i < graph->num_of_node; i++) + for (j = 0; j < graph->nlist[i]->nout; j++) + if (graph->nlist[i]->out_edge[j]->flag & CUTSET) + num_arcs++; + + return num_arcs; +} + +mf_node_t * +mf_get_node(graph, name) +mf_graph_t *graph; +char *name; +{ + char *dummy; + + if (st_lookup(graph->node_table, name, &dummy) ){ + return((mf_node_t *)dummy); + } else { + return(NIL(mf_node_t)); + } +} diff --git a/sis/maxflow/maxflow.doc b/sis/maxflow/maxflow.doc new file mode 100644 index 0000000..db060bb --- /dev/null +++ b/sis/maxflow/maxflow.doc @@ -0,0 +1,356 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/maxflow/maxflow.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +Summary: + cutset(); + mf_create_flow_network(); + mf_build_node_cutset(); + + mf_alloc_graph() + mf_read_node() + mf_read_edge() + mf_reread_edge() + mf_delete_node() + mf_free_graph() + mf_free_cutset() + + maxflow() + mf_get_cutset() + + mf_display_graph() + mf_display_cutset() + mf_display_flow() + + mf_foreach_node() + mf_foreach_fanin() + mf_foreach_fanout() + + mf_get_sink_node() + mf_get_source_node() + mf_get_edge_flow() + mf_get_edge_capacity() + mf_num_nodes() + mf_num_fanin() + mf_num_fanout() + mf_node_name() + mf_get_node() + mf_change_node_type() + mf_tail_of_edge() + mf_head_of_edge() + mf_is_edge_on_mincut() + + ROUTINES TO FIND MINIMUM WEIGHT SEPARATOR SET IN BOOLEAN NETWORKS. +array_t * +cutset(network, weight_table) +network_t *network; +st_table *weight_table; + Takes as input a network and a table of integral weights for + the nodes. Computes the minimum weighted "node_cutset" between + the primary inputs and primary outputs considering only the + nodes passed in the table. Returns an array of nodes that lie + on the cutset. Entries in the array are pointers to node_t. + NOTE: Only internal nodes should be passed in the weight_table + and the node weights should be positive and less than 1000 + (due to the fact that edges between nodes are given a weight + of a million). + NOTE: This routine was written specifically for speed_up, which + calls it on the epsilon-critical network. For this network, if a + node fanin is a PI and some other fanin is epsilon-critical, we + do not want an edge between the node and the source, we only + want an edge between the nodes in the epsilon-critical network. + So the cutset procedure adds edges in this fashion. For the + general case, it is easy enough to construct a flow network and + call maxflow() on that rather than using the cutset() routine. + +array_t * +cutset_interface(network, weight_table, edge_weight) +network_t *network; +st_table *weight_table; +int edge_weight; + Similar to the cutset routine described above. Removes the + restriction that node weights should be less than 1000. By + using this routine nodes can be assigned any positive weights. + IT IS THE USERS RESPONSIBILITY to ensure that the value + given to "edge_weight" is large enough so that the cutset will + comprise only nodes and not edges of the network. + +mf_graph_t * +mf_create_flow_network(network, weight_table, edge_weight, node_name_table) +network_t *network; +st_table *weight_table; +int edge_weight; +st_table **name_node_table; /* Returns correspondence of nodes in network */ + /* and vertices in the mf_graph_t */ + Builds a flow network corresponding to the nodes contained in the + "weight_table". The nodes are duplicated since a node-cutset is + required (weight table has the weight of the node). "edge_weight" + is the weight assigned to edges in the "network" so that they are + not included in the minimum cutset. + + +array_t * +mf_build_node_cutset(graph, name_node_table) +mf_graph_t *graph; +st_table *name_node_table; + On the "graph" you should have run the routine "maxflow()". Then + this routine will return you an array of "node_t *" on the cutset. + These are found by virtue of the name_node_table (this table was + returned by the routine mf_create_flow_network() described above) + + + Primitive operations to build up your own maxflow problem instance. + The nodes in the graph are REFERENCED BY NAME and the edge weights + MUST be positive integers. Note that a "source" and a "sink" node + must be specified (by the routine mf_read_node) for the maxflow + algorithm to work. Routines are provided to traverse the graph that + has been built, to query the nodes and edges and to frre the storage + once it is not required. + +mf_graph_t * +mf_alloc_graph() + Will return a mf_graph_t structure that will be used as the + graph for adding nodes and edges. + +void +mf_read_node( graph, name, type) +mf_graph_t *graph; +char *name; +int type; + Inserts a node in the mf_graph_t structure. The nodes are + distinguished by name and it is a serious error to define a + node more than once. Also there has to be ony one "source" + and only one "sink" node in the graph. The cutset is computed + between these two nodes. The type is as follows -- + 0 for Internal node + 1 for source node + 2 for sink node + +void +mf_read_edge( graph, from, to, capacity) +mf_graph_t *graph; +char *from, *to; +int capacity; + Inserts a directed edge from node "from" to the node "to" of + the specified capacity. Note that the two ends of the edge must + have been already defined as nodes by the "mf_read_node" function. + Also the capacity must be a positive integer. + +int +mf_reread_edge(graph, from, to, capacity) +mf_graph_t *graph; +char *from, *to; +int capacity; + Change the capacity of the edge between "from" and "to" nodes. + If an arc did not exist between the two nodes, a new edge is + created with the desired capacity. When a new edge is created + the routine return 1, otherwise it returns 0. + +int +mf_remove_node( graph, name) +mf_graph_t *graph; +char *name; + Removes the node referenced by "name" from the graph. In addition + to freeing the storage associated with the node, all the edges + incident on and emanating from the node are deleted. Returns 1 if + the graph has been modified, 0 otherwise. + +void +mf_modify_edge_capacity( edge, new_capacity) +mf_edge_t *edge; +int new_capacity; + Modifies the edge capacity on the specified edge. At this stage the + maxflow() routine must be run again to operate on the modified + graph. + +mf_change_node_type(graph, node, new_type) +mf_graph_t *graph; +mf_node_t *node; +int type; + Changes the "type" of a node. Allows repeated use of the same graph + with different source and sinks. It is the users responsibility to + ensure that there is a source and a sink after the modifications. + The node types are the same as defined earlier. + +void +mf_free_graph( graph) +mf_graph_t *graph; + Frees the graph data structure and all the memory that was + used by the maxflow routine. + Should be called once for each call to "mf_alloc_graph" + +void +mf_free_cutset( cutset) +mf_cutset_t *cutset; + Frees the cutset data structures and all the memory that was + used to report the cutset. Should be called once for each call + to "mf_get_cutset". + + +void +maxflow( graph, verify) +mf_graph_t *graph; +int verify; + Runs the maxflow algorithm on the graph and finds the minimum + weighted cutset. The verify flag is used to do a check whether + the cutset is actually the minimum weighted cutset or not. The + edges in the graph have flow assigned to them and can be queried + to see if they lie on the cutset. + +mf_cutset_t * +mf_get_cutset( graph, from_array, to_array, flow_array) +mf_graph_t *graph; +array_t **from_array, **to_array, **flow_array; + After calling the routine "maxflow()" on the graph, this + routine gets the nodes on the cutset. The routine will return + the nodes on the cutset and the flow along the edges on the + cutset by allocating anf filling up the from_array, to_array + and flow_array. The entries in the three arrays are (char *), + (char *) and (int) respectively. The routine also returns a + mf_cutset_t structure that should be freed by the routine + "mf_free_cutset()". + + NOTE: The members of the arrays are not saved explicitly. Hence + the arrays should be used before freeing the cutset. + + + Some routines to allow the user to dump the data structures to a + file. Useful only for debugging. + +void +mf_display_graph( outfile, graph) +FILE *outfile; +mf_graph_t *graph; + Prints the nodes and the edges, alongwith their + capacity, to outfile. + +void +mf_display_cutset( outfile, graph) +FILE *outfile; +mf_graph_t *graph; + After the maxflow() routine, prints the nodes and + the edges lying on either side of the cutset, + alongwith their capacity, to outfile. + +void +mf_display_flow( outfile, graph) +FILE *outfile; +mf_graph_t *graph; + After the maxflow() routine, prints the nodes and + the edges, alongwith their flows, to outfile. + + + The user is provided with various macros as described below + to access the "mf_graph" data structure. These routines return + pointers to existing data structures and so do not free any + of the pointers returned. All the storage will be freed when the + routine "mf_free_graph" is called. In order to generate all edges, + generate all the fanout edges of each node in the graph. Note, that + the traversal via fanout pointers is guaranteed to work, the fanin + pointers may not always be accurate. + +mf_foreach_node( graph, i, node) +mf_graph *graph; +int i; +mf_node_t *node; + Generates all the nodes in the graph, including the "source" + and the "sink" nodes. + +mf_foreach_fanin( node, i, edge) +mf_node *node; +int i; +mf_edge_t *edge; + Generates all the fanin edges of the node. + +mf_foreach_fanout( node, i, edge) +mf_node *node; +int i; +mf_edge_t *edge; + Generates all the fanout edges of the node. + +mf_node_t * +mf_get_node(graph, name) +mf_graph_t *graph; +char *name; + Returns the node corresponding to the name. If no such node + is present a NIL(char) is returned. + + +The following routines are used to query the various entries in +the data structures to retreive information about the vertices +and edges in the graph. + +int +mf_num_nodes(graph) +mf_graph_t *graph; + Returns the number of nodes in the graph. + +int +mf_num_fanin(node) +mf_node_t *node; + Returns the number of fanin edges to a node. + +int +mf_num_fanout(node) +mf_node_t *node; + Returns the number of fanout edges to a node. + +char * +mf_node_name(node) +mf_node_t *node; + Returns the name of the node. This is the key by which the + nodes in the graph are referenced. + +mf_node * +mf_get_sink_node(graph) +mf_graph_t *graph; + Returns the "sink" node of the graph. + +mf_node * +mf_get_source_node(graph) +mf_graph_t *graph; + Returns the "source" node of the graph. + +int +mf_get_edge_flow(edge) +mf_edge *edge; + Returns the flow through the edge after the function maxflow() + has been called. + +int +mf_get_edge_capacity(edge) +mf_edge *edge; + Returns the capacity through the edge. This is the maximum + permissible flow thru the edge. + +mf_node_t * +mf_tail_of_edge(edge) +mf_edge *edge; + Returns the "tail" node of the edge. This is the node where + the edge starts from. + +mf_node_t * +mf_head_of_edge(edge) +mf_edge *edge; + Returns the "head" node of the edge. This is the node where + the edge terminates. + +int +mf_is_edge_on_mincut(edge) +mf_edge *edge; + returns 1 if the edge lies on the minimum weighted cutset, 0 + otherwise. + +int +mf_sizeof_cutset(graph) +mf_graph_t *graph; + This routine is provided for the user who is interested only + in the size of the cutset. This routine must be called after + maxflow(). An alternate way (slower) is to use the routine + mf_get_cutset() and then the size of the returned array can + be used to determine the cutset size. diff --git a/sis/maxflow/maxflow.h b/sis/maxflow/maxflow.h new file mode 100644 index 0000000..4335dcf --- /dev/null +++ b/sis/maxflow/maxflow.h @@ -0,0 +1,163 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/maxflow/maxflow.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +#ifndef MAXFLOW_H +#define MAXFLOW_H + +#define CUTSET 1 + +/* Global variable */ +extern int maxflow_debug; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* + * Define the data structure + */ +typedef struct MF_NODE mf_node_t; +typedef struct MF_EDGE mf_edge_t; +typedef struct MF_GRAPH mf_graph_t; +typedef struct MF_CUTSET mf_cutset_t; +typedef struct MF_NODE *mfnptr; +typedef struct MF_EDGE *mfeptr; +typedef struct MF_GRAPH *mfgptr; +typedef struct MF_CUTSET *mfcptr; + +struct MF_NODE { + char *name; /* asciz name of node */ + mfeptr *in_edge; /* edges incident to this node */ + mfeptr *out_edge; /* edges incident from this node */ + int increment_flow; /* the increment flow */ + mfnptr path_node; /* augmenting path node */ + mfeptr path_edge; /* augmenting path edge */ + mfnptr pnext; /* general usage link */ + short nin; /* number of in_edges */ + short nout; /* number of out_edges */ + short direction; /* direction of the link: 1 = from; -1 = to */ + short flag; /* flag word */ + short max_nout; /* total no. of available out_edge */ + short nfict; /* no. of fictitious nodes using same name */ + char *fname; /* store the fictitious node name pointer */ +}; + +struct MF_EDGE { + mfnptr inode; /* edge incident from this node */ + mfnptr onode; /* edge incident to this node */ + int capacity; /* capacity of the edge */ + int flow; /* flow of the edge */ + int flag; /* flag word */ +} ; + +struct MF_GRAPH { + mfnptr source_node; /* source node */ + mfnptr sink_node; /* sink node */ + mfnptr *nlist; /* node list */ + st_table *node_table; /* hash table of nodes */ + mfnptr first_label_element; /* first element in the scan list */ + mfnptr last_label_element; /* last element in the scan list */ + int num_of_node; /* total no. of nodes in the circuit */ + int max_num_of_nptr; /* total no. of available node pointers */ +}; + +struct MF_CUTSET { + mfgptr graph; + char **from_node; + char **to_node; + int *capacity; + int narcs; +}; + +/* + * Declare the exported routines + */ + +EXTERN int mf_sizeof_cutset ARGS((mf_graph_t *)); +EXTERN int mf_remove_node ARGS((mf_graph_t *, char *)); +EXTERN int mf_reread_edge ARGS((mf_graph_t *, char *, char *, int)); +EXTERN void maxflow ARGS((mf_graph_t *, int)); +EXTERN void mf_read_node ARGS((mf_graph_t *, char *, int)); +EXTERN void mf_read_edge ARGS((mf_graph_t *, char *, char *, int)); +EXTERN void mf_free_cutset ARGS((mf_cutset_t *)); +EXTERN void mf_free_graph ARGS((mf_graph_t *)); +EXTERN void mf_display_graph ARGS((FILE *, mf_graph_t *)); +EXTERN void mf_display_flow ARGS((FILE *, mf_graph_t *)); +EXTERN void mf_display_cutset ARGS((FILE *, mf_graph_t *)); +EXTERN array_t *cutset ARGS((network_t *, st_table *)); +EXTERN array_t *cutset_interface ARGS((network_t *, st_table *, int)); +EXTERN array_t *mf_build_node_cutset ARGS((mf_graph_t *, st_table *)); +EXTERN mf_node_t *mf_get_node ARGS((mf_graph_t *, char *)); +EXTERN mf_graph_t *mf_alloc_graph ARGS((void)); +EXTERN mf_graph_t *mf_create_flow_network ARGS((network_t *, st_table *, int, st_table **)); +EXTERN mf_cutset_t *mf_get_cutset ARGS((mf_graph_t *, array_t **, array_t **, array_t **)); + +/* + * Access macros + */ +#define mf_foreach_node(graph, i, p) \ + for(i = 0; \ + i < (graph)->num_of_node && (p = (graph)->nlist[i]); \ + i++) + +#define mf_foreach_fanout(node, i, e) \ + for(i = 0; \ + i < (node)->nout && (e = (node)->out_edge[i]); \ + i++) + +#define mf_foreach_fanin(node, i, e) \ + for(i = 0; \ + i < (node)->nin && (e = (node)->in_edge[i]); \ + i++) + +/* + * Query macros + */ + +#define mf_node_name(node) \ + ((node)->name) + +#define mf_num_nodes(graph) \ + ((graph)->num_of_node) + +#define mf_num_fanin(node) \ + ((node)->in_edge == NIL(mf_edge_t *) ? 0 : (node)->nin) + +#define mf_num_fanout(node) \ + ((node)->out_edge == NIL(mf_edge_t *) ? 0 : (node)->nout) + +#define mf_get_sink_node(graph) \ + (graph)->sink_node + +#define mf_get_source_node(graph) \ + (graph)->source_node + +#define mf_get_edge_flow(edge) \ + (edge)->flow + +#define mf_get_edge_capacity(edge) \ + (edge)->capacity + +#define mf_modify_edge_capacity(edge, capacity) \ + ((edge)->capacity = capacity) + +#define mf_tail_of_edge(edge) \ + ((edge)->inode) + +#define mf_head_of_edge(edge) \ + ((edge)->onode) + +#define mf_is_edge_on_mincut(edge) \ + ((edge)->flag & CUTSET) + +#endif diff --git a/sis/maxflow/maxflow_int.h b/sis/maxflow/maxflow_int.h new file mode 100644 index 0000000..9cb4321 --- /dev/null +++ b/sis/maxflow/maxflow_int.h @@ -0,0 +1,31 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/maxflow/maxflow_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +/* + * functions that will be used internal to the package + */ +extern void mf_error(); +extern char *MF_calloc(); +extern void get_cutset(); + +#define LABELLED 1 +#define MARKED 2 +#define FICTITIOUS 4 +#define CUR_TRACE 8 + +#define MAX_FLOW 100000000 +#define MF_HASHSIZE 399 +#define MF_MAXSTR 256 + +/* + * miscellaneous marcos + */ +#define MF_ALLOC(num,type) \ + ((type *)MF_calloc((int)(num), sizeof(type))) + diff --git a/sis/maxflow/mf_input.c b/sis/maxflow/mf_input.c new file mode 100644 index 0000000..73d6bb4 --- /dev/null +++ b/sis/maxflow/mf_input.c @@ -0,0 +1,329 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/maxflow/mf_input.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +/**********************************************************************/ +/* This is the input processor for maxflow routines */ +/* */ +/* Author: Hi-Keung Tony Ma */ +/* last update : 03/28/1988 */ +/**********************************************************************/ + +#include "sis.h" +#include "maxflow_int.h" + +mfgptr +mf_alloc_graph() +{ + mfgptr graph; + + if (!(graph = MF_ALLOC(1, mf_graph_t))) + mf_error("Memory allocation failure", "mf_alloc_graph"); + graph->node_table = st_init_table(strcmp, st_strhash); + return(graph); +}/* end of mf_alloc_graph */ + +/* + * read a node structure into the graph + */ +void +mf_read_node(graph, node_name, type) +mfgptr graph; +char *node_name; +int type; /* source = 1, sink = 2, fictitious = -1, others = 0 */ +{ + mfnptr n; + char *name; + void reallocate_graph_node(); + + if (st_is_member(graph->node_table, node_name)) + mf_error("Node defined twice", "mf_read_node"); + + /* allocate new node from free storage */ + if (graph->num_of_node == graph->max_num_of_nptr) { + reallocate_graph_node(graph); + } + if (!(n = MF_ALLOC(1, mf_node_t))) mf_error("Memory allocation failure", "mf_read_node"); + graph->nlist[graph->num_of_node] = n; + graph->num_of_node++; + + /* initialize node entries */ + + n->name = name = util_strsav(node_name); + (void)st_insert(graph->node_table, name ,(char *)n); + n->in_edge = NIL(mfeptr); + + /* check node type */ + if (type == 1) { + if (graph->source_node) + mf_error("Multiple declaration of source node", "mf_read_node"); + else graph->source_node = n; + } + else if (type == 2) { + if (graph->sink_node) + mf_error("Multiple declaration of sink node", "mf_read_node"); + else graph->sink_node = n; + } + else if (type == -1) n->flag |= FICTITIOUS; +}/* end of mf_read_node */ + +int +mf_remove_node(graph, name) +mf_graph_t *graph; +char *name; +{ + int i, j, k; + char *dummy; + mf_node_t *node, *new_node; + mf_edge_t *edge, *new_edge; + + if ((node = mf_get_node(graph, name)) == NIL(mf_node_t)){ + return 0; + } + mf_foreach_fanin(node, i, edge){ + new_node = mf_tail_of_edge(edge); + mf_foreach_fanout(new_node, j, new_edge){ + if(new_edge == edge ) { + --(new_node->nout); + break; + } + } + for (k = j+1; k <= new_node->nout; k++){ + new_node->out_edge[k-1] = new_node->out_edge[k]; + } + FREE(edge); + } + mf_foreach_fanout(node, i, edge){ + new_node = mf_head_of_edge(edge); + mf_foreach_fanin(new_node, j, new_edge){ + if(new_edge == edge ) { + --(new_node->nin); + break; + } + } + for (k = j+1; k <= new_node->nin; k++){ + new_node->in_edge[k-1] = new_node->in_edge[k]; + } + FREE(edge); + } + FREE(node->in_edge); + FREE(node->out_edge); + + (void)st_delete(graph->node_table, &name, &dummy); + mf_foreach_node(graph, i, new_node){ + if (new_node == node ) break; + } + for (k = i+1; k < graph->num_of_node; k++){ + graph->nlist[k-1] = graph->nlist[k]; + } + --(graph->num_of_node); + FREE(node->name); + FREE(node); + + return 1; +} + +mf_change_node_type(graph, node, type) +mf_graph_t *graph; +mf_node_t *node; +int type; /* source = 1, sink = 2, others = 0 */ +{ + if (type == 1){ + graph->source_node = node; + } + if (type == 2){ + graph->sink_node = node; + } + if (type == 0 && mf_get_sink_node(graph) == node ){ + graph->sink_node = NIL(mf_node_t); + } + if (type == 0 && mf_get_source_node(graph) == node ){ + graph->source_node = NIL(mf_node_t); + } +} + +/* read and get edges structures */ +void +mf_read_edge(graph, node1, node2, capacity) +mfgptr graph; +char *node1, *node2; +int capacity; +{ + mfeptr e; + mfnptr n1, n2; + void reallocate_out_edge(); + + if (capacity < 0) mf_error("Negative capacity assigned","mf_read_edge"); + + if ((n1 = mf_get_node(graph, node1)) == NIL(mf_node_t)){ + mf_error("Node undefined", "mf_read_edge"); + } + if (n1->nout == n1->max_nout) reallocate_out_edge(n1); + + if ((n2 = mf_get_node(graph, node2)) == NIL(mf_node_t)){ + mf_error("Node undefined", "mf_read_edge"); + } + + if (n1 == n2) mf_error("Self-Loop is not allowed", "mf_read_edge"); + + if (!(e = MF_ALLOC(1, mf_edge_t))) + mf_error("Memory allocation failure", "mf_read_edge"); + e->inode = n1; + e->onode = n2; + e->capacity = capacity; + n1->out_edge[n1->nout] = e; + n1->nout++; + n2->nin++; +}/* end of mf_read_edge */ + +/* + * reread or create an edge structure + */ +int +mf_reread_edge(graph, node1, node2, capacity) +mfgptr graph; +char *node1, *node2; +int capacity; +{ + int i; + mfeptr e; + mfnptr n1, n2; + void reallocate_out_edge(); + + if (capacity < 0) mf_error("Negative capacity assigned","mf_reread_edge"); + + if ((n1 = mf_get_node(graph, node1)) == NIL(mf_node_t)){ + mf_error("Node undefined", "mf_reread_edge"); + } + if ((n2 = mf_get_node(graph, node2)) == NIL(mf_node_t)){ + mf_error("Node undefined", "mf_reread_edge"); + } + if (n1 == n2) mf_error("Self-Loop is not allowed", "mf_reread_edge"); + mf_foreach_fanout(n1, i, e){ + if (mf_head_of_edge(e) == n2){ + e->capacity = capacity; + return 0; + } + } + + if (n1->nout == n1->max_nout) reallocate_out_edge(n1); + if (!(e = MF_ALLOC(1, mf_edge_t))) + mf_error("Memory allocation failure", "mf_reread_edge"); + e->inode = n1; + e->onode = n2; + e->capacity = capacity; + n1->out_edge[n1->nout] = e; + n1->nout++; + n2->nin++; + return 1; +}/* end of mf_reread_edge */ + +/* +* print mf_error message and die +*/ +void +mf_error(msg1, msg2) +char *msg1, *msg2; +{ + (void) fprintf(siserr,"\n"); + (void) fprintf(siserr,"%s in routine %s\n",msg1, msg2); + abort(); +}/* end of mf_error */ + + +void +reallocate_graph_node(graph) +mfgptr graph; +{ + mfnptr *ntemp; + int i; + + graph->max_num_of_nptr += 50; + if (!(ntemp = MF_ALLOC(graph->max_num_of_nptr, mfnptr)) && + graph->max_num_of_nptr) + mf_error("Memory allocation failure", "reallocate_graph_node"); + for (i = 0; i < graph->num_of_node; i++) { + ntemp[i] = graph->nlist[i]; + } + if (graph->nlist != NIL(mfnptr)) free((char *)graph->nlist); + graph->nlist = ntemp; +}/* end of reallocate_graph_node */ + +void +reallocate_out_edge(node) +mfnptr node; +{ + int i; + mfeptr *etemp; + + node->max_nout += 10; + if (!(etemp = MF_ALLOC(node->max_nout, mfeptr)) && node->max_nout) + mf_error("Memory allocation failure", "reallocate_out_edge"); + for (i = 0; i < node->nout; i++) { + etemp[i] = node->out_edge[i]; + } + if (node->out_edge != NIL(mfeptr)) FREE(node->out_edge); + node->out_edge = etemp; +}/* end of reallocate_out_edge */ + + +char * +MF_calloc(a, b) +int a, b; +{ + int i, size; + char *p; + + size = a * b; + p = ALLOC(char, size); + for(i = 0; i < size; i++){ + *(p+i) = 0; + } + + return p; +} + +void +mf_free_cutset(cutset) +mfcptr cutset; +{ + FREE(cutset->from_node); + FREE(cutset->to_node); + FREE(cutset->capacity); + FREE(cutset); +} + +void +mf_free_node(node) +mfnptr node; +{ + int i; + + for (i = 0; i < node->nout; i++){ + FREE(node->out_edge[i]); + } + FREE(node->in_edge); + FREE(node->out_edge); + FREE(node->name); + + FREE(node); +} + +void +mf_free_graph(graph) +mfgptr graph; +{ + int i; + + for (i = 0; i < graph->num_of_node;i++){ + mf_free_node(graph->nlist[i]); + } + FREE(graph->nlist); + st_free_table(graph->node_table); + FREE(graph); +} diff --git a/sis/mincov/Makefile.am b/sis/mincov/Makefile.am new file mode 100644 index 0000000..157e088 --- /dev/null +++ b/sis/mincov/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libmincov.a +libmincov_a_SOURCES = bin_mincov.c bin_sol.c dominate.c gimpel.c \ + indep.c main.c mincov.c part.c solution.c mincov_int.h +pkginclude_HEADERS = mincov.h +dist_doc_DATA = mincov.doc diff --git a/sis/mincov/Makefile.in b/sis/mincov/Makefile.in new file mode 100644 index 0000000..6a921c8 --- /dev/null +++ b/sis/mincov/Makefile.in @@ -0,0 +1,423 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libmincov_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/mincov +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libmincov_a_AR = $(AR) $(ARFLAGS) +libmincov_a_LIBADD = +am_libmincov_a_OBJECTS = bin_mincov.$(OBJEXT) bin_sol.$(OBJEXT) \ + dominate.$(OBJEXT) gimpel.$(OBJEXT) indep.$(OBJEXT) \ + main.$(OBJEXT) mincov.$(OBJEXT) part.$(OBJEXT) \ + solution.$(OBJEXT) +libmincov_a_OBJECTS = $(am_libmincov_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libmincov_a_SOURCES) +DIST_SOURCES = $(libmincov_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libmincov.a +libmincov_a_SOURCES = bin_mincov.c bin_sol.c dominate.c gimpel.c \ + indep.c main.c mincov.c part.c solution.c mincov_int.h + +pkginclude_HEADERS = mincov.h +dist_doc_DATA = mincov.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/mincov/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/mincov/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libmincov.a: $(libmincov_a_OBJECTS) $(libmincov_a_DEPENDENCIES) + -rm -f libmincov.a + $(libmincov_a_AR) libmincov.a $(libmincov_a_OBJECTS) $(libmincov_a_LIBADD) + $(RANLIB) libmincov.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/mincov/bin_mincov.c b/sis/mincov/bin_mincov.c new file mode 100644 index 0000000..72cc21b --- /dev/null +++ b/sis/mincov/bin_mincov.c @@ -0,0 +1,939 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/bin_mincov.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +#include "sis.h" +#include "mincov_int.h" + +typedef struct _value_t { + sm_element * elem; + double value; +} value_t; + +static int is_unate; +static int (*g_record_fun) (); /* called at the recursion end (if non-nil) */ +static int verify_cover(); + +static sm_matrix *A; /* reordered matrix */ +static int *weights; /* column weights */ + +/* expanded[row_num] points to the element currently expanded; + * it is 0 if rule 3 was applied at the corresponding row level + */ +static sm_element ** expanded; + +/* order[row_num] is an array of pointers to elements; the row should + * be expanded in that order. + */ +static sm_element *** order; + +/* partial prime currently generated, in set form, and its cost */ +static bin_solution_t *sol; +/* best prime up to now, in set form, and its cost */ +static bin_solution_t *best; + +/* stop at first leaf if true */ +static int g_heu; +static int ended; + +/* debugging and statistics variables */ +static int leaves_count, r1, r2, r3, r4, r5; +static int g_debug, g_option, got_best; +static long start_time; +int call_count, cc; + +static int compare (), compare_rev (); +static char * literal_name (); +static sm_matrix * reorder_rows (); +static sm_row * mat_minimum_cover (); + +/* get the index of the complement of the current literal */ +#define GETBAR(v) (((v)&1)?((v)-1):((v)+1)) + +/* flags stored in the user_word of each element */ +#define EXPANDED 1 +#define MARKED 2 + +/* do the binate covering of matrix M with weights w (might be NULL); + * if heuristic != 0, terminate as soon as the first result is obtained; + * g_debug gives the amount of debugging information; + * ubound, if > 0, gives the best possible estimate of the covering cost. + * Any row can be missing from M, but at least one column for each odd-even + * pair should be present. + */ + +sm_row * +sm_mat_bin_minimum_cover (M, weights, heuristic, debug, ubound, option, record_fun) + +sm_matrix *M; +int *weights; +int heuristic, debug, ubound, option; +int (*record_fun) (); + +{ + is_unate = 0; + return mat_minimum_cover (M, weights, heuristic, debug, ubound, + option, record_fun); +} + +sm_row * +sm_mat_minimum_cover (M, weights, heuristic, debug, ubound, option, record_fun) + +sm_matrix *M; +int *weights; +int heuristic, debug, ubound, option; +int (*record_fun) (); + +{ + is_unate = 1; + return mat_minimum_cover (M, weights, heuristic, debug, ubound, + option, record_fun); +} + +static sm_row * +mat_minimum_cover (M, w, heuristic, l_debug, ubound, l_option, record_fun) + +sm_matrix *M; +int *w; +int heuristic, l_debug, ubound, l_option; +int (*record_fun) (); + +{ + int nelem, i, row, col, cost, added, toadd; + double sparsity, *col_value_save; + sm_row *prow, *result; + sm_col *pcol; + sm_matrix *M_save, *temp1, *temp; + sm_element *elem; + value_t * col_value; + pset unate; + + g_debug = l_debug; + g_record_fun = record_fun; + g_option = l_option; + g_heu = heuristic; + weights = w; + ended = 0; + M_save = NIL(sm_matrix); + + if (M->nrows <= 0) { + return sm_row_alloc(); + } + + if (g_debug > 0) { + start_time = util_cpu_time(); + + /* Check the matrix sparsity */ + nelem = 0; + sm_foreach_row(M, prow) { + nelem += prow->length; + } + sparsity = (double) nelem / (double) (M->nrows * M->ncols); + (void) fprintf(misout, "matrix = %d by %d with %d elements (%4.3f%%)\n", + M->nrows, M->ncols, nelem, sparsity * 100.0); + } + if (g_debug > 3) { + (void) fprintf (misout, "Weights:\n"); + for (i = 0; i < M->last_col->col_num + 1; i++) { + (void) fprintf (misout, "%d ", WEIGHT(w, i)); + } + (void) fprintf (misout, "\n"); + (void) fprintf (misout, "Matrix:\n"); + sm_print(misout, M); + (void) fprintf (misout, "\n"); + } + + if (g_option & 2048) { + /* reorder rows such that the tree-like ordering is preserved */ + M_save = M; + M = sm_dup (M_save); + A = sm_alloc (); + + unate = set_clear (set_new (M->last_col->col_num + 1), + M->last_col->col_num + 1); + do { + added = 0; + temp = sm_alloc (); + /* find unate columns */ + sm_foreach_col (M, pcol) { + if (pcol->col_num % 2) { + if (! pcol->prev_col || + pcol->prev_col->col_num != pcol->col_num - 1) { + set_insert (unate, pcol->col_num); + set_insert (unate, (pcol->col_num - 1)); + } + } + else { + if (! pcol->next_col || + pcol->next_col->col_num != pcol->col_num + 1) { + set_insert (unate, pcol->col_num); + set_insert (unate, (pcol->col_num + 1)); + } + } + } + + /* check if all elements are unate */ + for (i = 0; M->nrows && i <= M->last_row->row_num; i++) { + if (! (prow = sm_get_row (M, i))) { + continue; + } + + toadd = 1; + sm_foreach_row_element (prow, elem) { + if (! is_in_set (unate, elem->col_num)) { + toadd = 0; + break; + } + } + if (toadd) { + added = 1; + row = temp->nrows; + sm_foreach_row_element (prow, elem) { + (void) sm_insert (temp, row, elem->col_num); + } + sm_delrow (M, prow->row_num); + i--; + } + } + + /* check if all positive elements are unate */ + for (i = 0; M->nrows && i <= M->last_row->row_num; i++) { + if (! (prow = sm_get_row (M, i))) { + continue; + } + + toadd = 1; + sm_foreach_row_element (prow, elem) { + if (! (elem->col_num % 2) && + ! is_in_set (unate, elem->col_num)) { + toadd = 0; + break; + } + } + if (toadd) { + added = 1; + row = temp->nrows; + sm_foreach_row_element (prow, elem) { + (void) sm_insert (temp, row, elem->col_num); + } + sm_delrow (M, prow->row_num); + i--; + } + } + + temp1 = reorder_rows (temp); + sm_foreach_row (temp1, prow) { + row = A->nrows; + sm_foreach_row_element (prow, elem) { + (void) sm_insert (A, row, elem->col_num); + } + } + sm_free (temp); + sm_free (temp1); + } while (added && M->nrows); + + if (M->nrows) { + (void) fprintf (miserr, + "warning: unate heuristics left %d rows out of %d\n", + M->nrows, A->nrows + M->nrows); + if (g_debug > 2) { + (void) fprintf (misout, "Left-over ratrix:\n"); + sm_print(misout, M); + (void) fprintf (misout, "\n"); + } + temp = sm_alloc (); + sm_foreach_row (M, prow) { + row = temp->nrows; + sm_foreach_row_element (prow, elem) { + (void) sm_insert (temp, row, elem->col_num); + } + } + temp1 = reorder_rows (temp); + sm_foreach_row (temp1, prow) { + row = A->nrows; + sm_foreach_row_element (prow, elem) { + (void) sm_insert (A, row, elem->col_num); + } + } + sm_free (temp); + sm_free (temp1); + } + sm_free (M); + + M = M_save; + set_free (unate); + } + else { + A = reorder_rows (M); + } + + /* reorder cols; at every level the column pair with most elements BELOW + * it is put first; weights might be used also... + */ + col_value = ALLOC (value_t, A->last_col->col_num + 1); + col_value_save = ALLOC (double, A->last_col->col_num + 1); + order = ALLOC (sm_element **, A->nrows); + + for (col = 0; col <= A->last_col->col_num; col++) { + col_value_save[col] = 0.0; + } + + /* run through the rows in reverse order */ + for (row = A->nrows - 1; row >= 0; row--) { + prow = sm_get_row (A, row); + + col = 0; + sm_foreach_row_element (prow, elem) { + if (is_unate) { + col_value_save[elem->col_num]++; + } + else { + if (g_option & 4) { + /* skip odd columns */ + if (! (elem->col_num % 2)) { + col_value_save[elem->col_num / 2]++; + } + } + else { + col_value_save[elem->col_num / 2]++; + } + } + + col_value[col].elem = elem; + + if (is_unate) { + col_value[col].value = col_value_save[elem->col_num]; + } + else { + col_value[col].value = col_value_save[elem->col_num / 2]; + if (g_option & 64) { + if (WEIGHT(weights, elem->col_num) > 0) { + col_value[col].value /= WEIGHT(weights, elem->col_num); + } + else { + col_value[col].value *= 2; + } + } + if (g_option & 32) { + /* leave odd columns first */ + if (elem->col_num % 2) { + col_value[col].value = 1000000.0; + } + } + else if (g_option & 128) { + /* leave odd columns last */ + if (elem->col_num % 2) { + col_value[col].value = 0.0; + } + } + } + + col++; + } + + if (g_option & 8) { + /* do not sort columns */ + } + else { + if (g_option & 16) { + qsort ((char*) col_value, col, sizeof(value_t), compare_rev); + } + else { + qsort ((char*) col_value, col, sizeof(value_t), compare); + } + } + + order[row] = ALLOC (sm_element *, prow->length); + + for (col = 0; col < prow->length; col++) { + order[row][col] = col_value[col].elem; + } + } + + /* statically allocate the stacks */ + expanded = ALLOC (sm_element *, A->nrows); + + if (g_debug > 2) { + (void) fprintf (misout, "Col ordering:\n"); + for (row = 0; row < A->nrows; row++) { + (void) fprintf (misout, "%d: ", row); + prow = sm_get_row (A, row); + for (col = 0; col < prow->length; col++) { + (void) fprintf (misout, "%d ", order[row][col]->col_num); + } + (void) fprintf (misout, "\n"); + } + } + + if (g_debug > 3) { + (void) fprintf (misout, "Reordered matrix:\n"); + sm_print (misout, A); + (void) fprintf (misout, "\n"); + } + + if (g_debug > 1) { + (void) fprintf(misout, "reordering done (time is %s)\n", + util_print_time(util_cpu_time() - start_time)); + } + + /* give an upper bound (for rule 5) if available */ + got_best = 0; + sol = bin_solution_alloc (A->last_col->col_num + 1); + best = bin_solution_alloc (A->last_col->col_num + 1); + if (ubound > 0) { + /* hope we'll succeed... */ + best->cost = ubound; + } + else { + /* not a very good bound... */ + sm_foreach_col (A, pcol) { + best->cost += WEIGHT(weights, pcol->col_num); + } + } + best->cost++; + + /* do the actual work */ + sm_bin_mincov (0); + + if (! g_record_fun) { + /* check out various things */ + if (! got_best) { + (void) fprintf(miserr,"internal error; couldn't improve on bound\n"); + (void) fprintf(miserr,"unsatisfiable binate covering matrix ?\n"); + exit(-1); + } + + /* put back the solution in sparse matrix (reordered) form */ + result = sm_row_alloc(); + for (i = 0; i < A->last_col->col_num + 1; i++) { + if (is_in_set (best->set, i)) { + sm_row_insert (result, i); + } + } + + if (g_debug > 0) { + (void) fprintf (misout, "calls %d leaves %d r1 %d r2 %d r3 %d r4 %d r5 %d\n", + call_count, leaves_count, r1, r2, r3, r4, r5); + + if (g_debug > 1) { + (void) fprintf (misout, "Solution is "); + sm_row_print (misout, result); + (void) fprintf (misout, "\n"); + } + + (void) fprintf(misout, "best solution %d; time %s\n", best->cost, + util_print_time(util_cpu_time() - start_time)); + } + + /* check the cost and the result itself ... */ + cost = 0; + sm_foreach_row_element (result, elem) { + cost += WEIGHT (w, elem->col_num); + } + if (cost != best->cost) { + (void) fprintf (miserr, "Solution cost is corrupted\n"); + exit (-1); + } + if (! verify_cover(M, result)) { + (void) fprintf (misout, "Illegal solution "); + sm_row_print (misout, result); + (void) fprintf (misout, "\nwith cost %d\n", best->cost); + + (void) fprintf (miserr, "internal error -- cover verification failed\n"); + exit (-1); + } + } + + FREE (expanded); + FREE (col_value); + FREE (col_value_save); + bin_solution_free(best); + bin_solution_free(sol); + for (row = A->nrows - 1; row >= 0; row--) { + FREE (order[row]); + } + FREE (order); + sm_free (A); + + return result; +} + +/* reorder the rows of M according to g_option */ +static sm_matrix * +reorder_rows (M) + +sm_matrix *M; + +{ + int i, row, neg_unate, pos_unate; + sm_row *prow; + sm_element *elem; + sm_matrix *result; + value_t * row_value; + + /* reorder rows; longest first */ + /* row_value[i].elem->row_num gives the number of the old row in the i-th + * position of the new matrix; + */ + result = sm_alloc (); + if (M->last_row == NIL(sm_row) || M->last_col == NIL(sm_col)) { + return result; + } + row_value = ALLOC (value_t, M->nrows); + i = 0; + sm_foreach_row (M, prow) { + if (prow->length) { + row_value[i].elem = prow->first_col; + if (g_option & 1) { + /* save original order for ties */ + row_value[i].value = 10000 * prow->length + i; + } + else if (g_option & 256) { + /* define as value the sum of all column values */ + row_value[i].value = 0; + sm_foreach_row_element (prow, elem) { + row_value[i].value += WEIGHT (weights, elem->col_num); + } + } + else { + row_value[i].value = prow->length; + } + + if (g_option & (512 | 1024)) { + /* check if it is 'unate' */ + pos_unate = 1; + neg_unate = 1; + sm_foreach_row_element (prow, elem) { + if (elem->col_num % 2) { + pos_unate = 0; + } + else { + neg_unate = 0; + } + } + + if (pos_unate || neg_unate) { + if (g_option & 512) { + /* 'unate' rows first */ + row_value[i].value += 10000; + } + else { + /* 'unate' rows last */ + row_value[i].value -= 10000; + } + } + } + + i++; + } + } + + if (g_option & 2) { + /* do not sort rows */ + } + else if (g_option & 4096) { + qsort ((char *) row_value, M->nrows, sizeof(value_t), compare_rev); + } + else { + qsort ((char *) row_value, M->nrows, sizeof(value_t), compare); + } + + /* permute the rows of M into A, according to col_value */ + sm_resize(result, M->last_row->row_num, M->last_col->col_num); + for (i = 0; i < M->nrows; i++) { + /* the i-th old column has row_value[i].elem->row_num now !! */ + prow = sm_get_row (M, row_value[i].elem->row_num); + sm_foreach_row_element (prow, elem) { + (void) sm_insert (result, i, elem->col_num); + } + } + + if (g_debug > 2) { + (void) fprintf (misout, "Partial row ordering:\n"); + for (row = 0; row < result->nrows; row++) { + (void) fprintf (misout, "%d ", row_value[row].elem->row_num); + } + (void) fprintf (misout, "\n"); + } + + FREE (row_value); + + return result; +} + +/* Apply Mathony's algorithm to generate all weighted primes of matrix A. + * 1) if we reached the end of the recursion, check if the current solution + * improves the best seen so far, and save it. + * 2) rule 3: if the current solution contains a literal appearing also + * in the current row, ignore the current row. + * 3) for each literal in the current row (sum): + * a) rule 1: if the current solution contains the complement of the + * literal, ignore the current literal; + * b) rule 5: if the current solution plus the cost of the current literal + * would cost more than the best solution, ignore the current literal; + * c) rule 2: if a row at an upper level contains the same literal yet to + * be expanded, ignore the current literal and mark the literal in the + * upper row; + * d) rule 4: if a row at an upper level contains the same literal already + * expanded and if rule 2 was not applied with respect to the literal + * in the upper row in the current expansion (i.e. it is not marked), + * ignore the current literal; + * e) otherwise, add the current literal to the solution and recur for the + * next row. + * 4) remove rule 2 marks from the current rows (if any). + */ + +void +sm_bin_mincov (row_num) + +int row_num; + +{ + sm_row *curr_row; + sm_element *elem, *uplevel_elem; + int literal, literal_bar, col; + + call_count++; +#ifdef DEBUG + /* debugging; dbx is too slow... */ + if (call_count == cc) { + (void) fprintf (miserr, "got it\n"); + } +#endif + + /* check for recursion end, and record the solution if improving */ + if (row_num == A->nrows) { + if (g_record_fun) { + curr_row = sm_row_alloc(); + for (col = 0; col < A->last_col->col_num + 1; col++) { + if (is_in_set (sol->set, col)) { + sm_row_insert (curr_row, col); + } + } + if ((*g_record_fun) (curr_row)) { + ended = 1; + } + sm_row_free (curr_row); + return; + } + else if (sol->cost < best->cost) { + got_best = 1; + bin_solution_free (best); + best = bin_solution_dup (sol, A->last_col->col_num + 1); + + if (g_debug > 0) { + (void) fprintf(misout, " new 'best' solution %d; time %s; calls %d\n", + best->cost, + util_print_time(util_cpu_time() - start_time), + call_count); + (void) fflush (misout); +#ifdef DEBUG + if (g_debug > 5) { + if (g_debug > 9) { + sp (best->set); + } + else { + (void) fprintf (misout, "\n"); + } + } +#endif + } + + } + leaves_count++; + if (g_heu) { + ended = 1; + } + return; + } + + /* initialize the level */ + curr_row = sm_get_row (A, row_num); + expanded[row_num] = NIL(sm_element); /* nothing chosen... */ + +#ifdef DEBUG + if (g_debug > 9) { + print_lev (row_num, "beginning "); + rp (curr_row); + } +#endif + + /* begin R3 */ + /* check if any of the literals in the row appears in the solution already; + * if so ignore the current row + */ + sm_foreach_row_element (curr_row, elem) { + if (is_in_set ((sol->set), elem->col_num)) { +#ifdef DEBUG + if (g_debug > 9) { + print_lev (row_num, "ignoring (R3)\n"); + } +#endif + + r3++; + /* recur for next row */ + sm_bin_mincov (row_num + 1); + return; + } + } + /* end R3 */ + + /* now select each literal in turn */ + for (col = 0; ! ended && col < curr_row->length; col++) { + elem = order[row_num][col]; + + literal = elem->col_num; + if (! is_unate) { + literal_bar = GETBAR (literal); + + /* begin R1 */ + /* check if literal appears complemented in the solution; if so + * ignore the literal + */ + if (is_in_set ((sol->set), literal_bar)) { +#ifdef DEBUG + if (g_debug > 9) { + print_lev (row_num, "pruning (R1) %s\n", + literal_name (literal)); + } +#endif + + r1++; + continue; + } + /* end R1 */ + } + + /* begin R5 */ + /* check if adding the current literal would make the solution worse; + * if so, ignore the literal + */ + if (sol->cost + WEIGHT(weights, literal) >= best->cost) { +#ifdef DEBUG + if (g_debug > 6) { + print_lev (row_num, "pruning (R5) (cost=%d) ", + sol->cost + WEIGHT(weights, literal)); + if (g_debug > 9) { + (void) fprintf (misout, "%s ", literal_name (literal)); + sp (sol->set); + } + else { + (void) fprintf (misout, "\n"); + } + } +#endif + + r5++; + continue; + } + /* end R5 */ + + /* begin R2 and R4 */ + /* prepare for rule 5 and 6 check: + * update the uplevel_elem pointer to be the first element in the + * same column (if any) with row < row_num (i.e. belonging to + * an upper sum) and with expanded[row] != 0. + * If this element was EXPANDED, then the currently expanded element + * at that level must not have been MARKED + */ + for (uplevel_elem = elem->prev_row; uplevel_elem != NIL(sm_element); + uplevel_elem = uplevel_elem->prev_row) { + if (expanded[uplevel_elem->row_num]) { + if ((EXPANDED & (sm_get (int, uplevel_elem)))) { + if (! (MARKED & + (sm_get (int, expanded[uplevel_elem->row_num])))) { + break; + } + } + else { + break; + } + } + } + + /* check if the same literal appears at an upper level */ + if (uplevel_elem != NIL(sm_element)) { + + /* check if it was a yet unexpanded literal; if so, ignore the + * current literal and record this, marking the current literal + * at the upper level (and the row, for a faster reset). + */ + if (! (EXPANDED & (sm_get (int, uplevel_elem)))) { + sm_put (uplevel_elem, ((sm_get (int, uplevel_elem)) | MARKED)); +#ifdef DEBUG + if (g_debug > 9) { + print_lev (row_num, "pruning (R2) %s\n", + literal_name (literal)); + } +#endif + r2++; + continue; + } + else { + /* ignore the current literal (no need to record it...) */ +#ifdef DEBUG + if (g_debug > 9) { + print_lev (row_num, "pruning (R4) %s\n", + literal_name (literal)); + } +#endif + r4++; + continue; + } + } + /* end R2 and R4 */ + + /* add the current literal to the solution and recur */ + expanded[row_num] = elem; + sm_put (elem, ((sm_get (int, elem)) | EXPANDED)); + bin_solution_add (sol, weights, literal); + +#ifdef DEBUG + if (g_debug > 9) { + print_lev (row_num, "choosing %s: ", literal_name (literal)); + sp (sol->set); + } +#endif + + sm_bin_mincov (row_num + 1); + + /* remove the current literal */ + bin_solution_del (sol, weights, literal); + } + + /* end of literal selection loop */ + + /* un-mark the current row */ + sm_foreach_row_element (curr_row, elem) { + sm_put (elem, 0); + } + + expanded[row_num] = NIL(sm_element); + +#ifdef DEBUG + if (g_debug > 9) { + print_lev (row_num, "ending\n"); + } +#endif +} + +/* compare two value records + */ +static int +compare (value1, value2) + +value_t *value1, *value2; + +{ + return value2->value - value1->value; +} + +static int +compare_rev (value1, value2) + +value_t *value1, *value2; + +{ + return value1->value - value2->value; +} + +/* debugging stuff */ +static char * +literal_name (literal) + +int literal; + +{ + static char buf[20]; + + (void) sprintf (buf, "%d", literal); + /* + if (! (literal % 2)) { + (void) sprintf (buf, "%d", literal / 2); + } + else { + (void) sprintf (buf, "%d'", literal / 2); + } */ + return buf; +} + +rp (row) + +sm_row *row; + +{ + sm_element *element; + + sm_foreach_row_element (row, element) { + (void) fprintf (misout, "%s ", literal_name (element->col_num)); + } + (void) fprintf (misout, "\n"); +} + +sp (set) +pset set; + +{ + int i; + + for (i = 0; i < A->last_col->col_num + 1; i++) { + if (is_in_set (set, i)) { + (void) fprintf (misout, "%s ", literal_name (i)); + } + } + (void) fprintf (misout, "\n"); +} + +print_lev (row_num, p1, p2, p3, p4) + +int row_num; +char *p1, *p2, *p3, *p4; + +{ + int i; + + (void) fprintf (misout, "%d\t ", call_count); + for (i = 0; i < row_num; i++) { + putchar (' '); + putchar (' '); + } + (void) fprintf (misout, p1, p2, p3, p4); +} + +ps (set) +pset set; +{ + (void) fprintf (misout, ps1(set)); +} + +pm (mat) +sm_matrix *mat; +{ + sm_print (misout, mat); +} + +wm (mat) +sm_matrix *mat; +{ + sm_write (misout, mat); +} + +static int +verify_cover(A, cover) +sm_matrix *A; +sm_row *cover; +{ + sm_row *prow; + + sm_foreach_row(A, prow) { + if (! sm_row_intersects(prow, cover)) { + return 0; + } + } + return 1; +} diff --git a/sis/mincov/bin_sol.c b/sis/mincov/bin_sol.c new file mode 100644 index 0000000..2e69d89 --- /dev/null +++ b/sis/mincov/bin_sol.c @@ -0,0 +1,69 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/bin_sol.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +#include "sis.h" +#include "mincov_int.h" + +bin_solution_t * +bin_solution_alloc(size) +int size; +{ + bin_solution_t *sol; + + sol = ALLOC(bin_solution_t, 1); + sol->cost = 0; + sol->set = set_new (size); + return sol; +} + + +void +bin_solution_free(sol) +bin_solution_t *sol; +{ + set_free(sol->set); + FREE(sol); +} + + +bin_solution_t * +bin_solution_dup(sol, size) +bin_solution_t *sol; +int size; +{ + bin_solution_t *new_sol; + + new_sol = ALLOC(bin_solution_t, 1); + new_sol->cost = sol->cost; + new_sol->set = set_new (size); + INLINEset_copy (new_sol->set, sol->set); + return new_sol; +} + + +void +bin_solution_del(sol, weight, col) +bin_solution_t *sol; +int *weight; +int col; +{ + set_remove(sol->set, col); + sol->cost -= WEIGHT(weight, col); +} + +void +bin_solution_add(sol, weight, col) +bin_solution_t *sol; +int *weight; +int col; +{ + set_insert(sol->set, col); + sol->cost += WEIGHT(weight, col); +} + diff --git a/sis/mincov/dominate.c b/sis/mincov/dominate.c new file mode 100644 index 0000000..5a9b882 --- /dev/null +++ b/sis/mincov/dominate.c @@ -0,0 +1,98 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/dominate.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +#include "mincov_int.h" + + +int +sm_row_dominance(A) +sm_matrix *A; +{ + register sm_row *prow, *prow1; + register sm_col *pcol, *least_col; + register sm_element *p, *pnext; + int rowcnt; + + rowcnt = A->nrows; + + /* Check each row against all other rows */ + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + + /* Among all columns with a 1 in this row, choose smallest */ + least_col = sm_get_col(A, prow->first_col->col_num); + for(p = prow->first_col->next_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + if (pcol->length < least_col->length) { + least_col = pcol; + } + } + + /* Only check for containment against rows in this column */ + for(p = least_col->first_row; p != 0; p = pnext) { + pnext = p->next_row; + + prow1 = sm_get_row(A, p->row_num); + if ((prow1->length > prow->length) || + (prow1->length == prow->length && + prow1->row_num > prow->row_num)) { + if (sm_row_contains(prow, prow1)) { + sm_delrow(A, prow1->row_num); + } + } + } + } + + return rowcnt - A->nrows; +} + +int +sm_col_dominance(A, weight) +sm_matrix *A; +int *weight; +{ + register sm_row *prow; + register sm_col *pcol, *pcol1; + register sm_element *p; + sm_row *least_row; + sm_col *next_col; + int colcnt; + + colcnt = A->ncols; + + /* Check each column against all other columns */ + for(pcol = A->first_col; pcol != 0; pcol = next_col) { + next_col = pcol->next_col; + + /* Check all rows to find the one with fewest elements */ + least_row = sm_get_row(A, pcol->first_row->row_num); + for(p = pcol->first_row->next_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + if (prow->length < least_row->length) { + least_row = prow; + } + } + + /* Only check for containment against columns in this row */ + for(p = least_row->first_col; p != 0; p = p->next_col) { + pcol1 = sm_get_col(A, p->col_num); + if (weight != 0 && weight[pcol1->col_num] > weight[pcol->col_num]) + continue; + if ((pcol1->length > pcol->length) || + (pcol1->length == pcol->length && + pcol1->col_num > pcol->col_num)) { + if (sm_col_contains(pcol, pcol1)) { + sm_delcol(A, pcol->col_num); + break; + } + } + } + } + + return colcnt - A->ncols; +} diff --git a/sis/mincov/gimpel.c b/sis/mincov/gimpel.c new file mode 100644 index 0000000..9579720 --- /dev/null +++ b/sis/mincov/gimpel.c @@ -0,0 +1,106 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/gimpel.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +#include "mincov_int.h" + + +/* + * check for: + * + * c1 c2 rest + * -- -- --- + * 1 1 0 0 0 0 <-- primary row + * 1 0 S1 <-- secondary row + * 0 1 T1 + * 0 1 T2 + * 0 1 Tn + * 0 0 R + */ + +int +gimpel_reduce(A, select, weight, lb, bound, depth, stats, best) +sm_matrix *A; +solution_t *select; +int *weight; +int lb; +int bound; +int depth; +stats_t *stats; +solution_t **best; +{ + register sm_row *prow, *save_sec; + register sm_col *c1, *c2; + register sm_element *p, *p1; + int c1_col_num, c2_col_num, primary_row_num, secondary_row_num; + int reduce_it; + + reduce_it = 0; + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->length == 2) { + c1 = sm_get_col(A, prow->first_col->col_num); + c2 = sm_get_col(A, prow->last_col->col_num); + if (c1->length == 2) { + reduce_it = 1; + } else if (c2->length == 2) { + c1 = sm_get_col(A, prow->last_col->col_num); + c2 = sm_get_col(A, prow->first_col->col_num); + reduce_it = 1; + } + if (reduce_it) { + primary_row_num = prow->row_num; + secondary_row_num = c1->first_row->row_num; + if (secondary_row_num == primary_row_num) { + secondary_row_num = c1->last_row->row_num; + } + break; + } + } + } + + if (reduce_it) { + c1_col_num = c1->col_num; + c2_col_num = c2->col_num; + save_sec = sm_row_dup(sm_get_row(A, secondary_row_num)); + sm_row_remove(save_sec, c1_col_num); + + for(p = c2->first_row; p != 0; p = p->next_row) { + if (p->row_num != primary_row_num) { + /* merge rows S1 and T */ + for(p1 = save_sec->first_col; p1 != 0; p1 = p1->next_col) { + (void) sm_insert(A, p->row_num, p1->col_num); + } + } + } + + sm_delcol(A, c1_col_num); + sm_delcol(A, c2_col_num); + sm_delrow(A, primary_row_num); + sm_delrow(A, secondary_row_num); + + stats->gimpel_count++; + stats->gimpel++; + *best = sm_mincov(A, select, weight, lb-1, bound-1, depth, stats); + stats->gimpel--; + + if (*best != NIL(solution_t)) { + /* is secondary row covered ? */ + if (sm_row_intersects(save_sec, (*best)->row)) { + /* yes, actually select c2 */ + solution_add(*best, weight, c2_col_num); + } else { + solution_add(*best, weight, c1_col_num); + } + } + + sm_row_free(save_sec); + return 1; + } else { + return 0; + } +} diff --git a/sis/mincov/indep.c b/sis/mincov/indep.c new file mode 100644 index 0000000..d8ba278 --- /dev/null +++ b/sis/mincov/indep.c @@ -0,0 +1,134 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/indep.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +#include "mincov_int.h" + +static sm_matrix *build_intersection_matrix(); + + +#if 0 +/* + * verify that all rows in 'indep' are actually independent ! + */ +static int +verify_indep_set(A, indep) +sm_matrix *A; +sm_row *indep; +{ + register sm_row *prow, *prow1; + register sm_element *p, *p1; + + for(p = indep->first_col; p != 0; p = p->next_col) { + prow = sm_get_row(A, p->col_num); + for(p1 = p->next_col; p1 != 0; p1 = p1->next_col) { + prow1 = sm_get_row(A, p1->col_num); + if (sm_row_intersects(prow, prow1)) { + return 0; + } + } + } + return 1; +} +#endif + +solution_t * +sm_maximal_independent_set(A, weight) +sm_matrix *A; +int *weight; +{ + register sm_row *best_row, *prow; + register sm_element *p; + int least_weight; + sm_row *save; + sm_matrix *B; + solution_t *indep; + + indep = solution_alloc(); + B = build_intersection_matrix(A); + + while (B->nrows > 0) { + /* Find the row which is disjoint from a maximum number of rows */ + best_row = B->first_row; + for(prow = B->first_row->next_row; prow != 0; prow = prow->next_row) { + if (prow->length < best_row->length) { + best_row = prow; + } + } + + /* Find which element in this row has least weight */ + if (weight == NIL(int)) { + least_weight = 1; + } else { + prow = sm_get_row(A, best_row->row_num); + least_weight = weight[prow->first_col->col_num]; + for(p = prow->first_col->next_col; p != 0; p = p->next_col) { + if (weight[p->col_num] < least_weight) { + least_weight = weight[p->col_num]; + } + } + } + indep->cost += least_weight; + (void) sm_row_insert(indep->row, best_row->row_num); + + /* Discard the rows which intersect this row */ + save = sm_row_dup(best_row); + for(p = save->first_col; p != 0; p = p->next_col) { + sm_delrow(B, p->col_num); + sm_delcol(B, p->col_num); + } + sm_row_free(save); + } + + sm_free(B); + +/* + if (! verify_indep_set(A, indep->row)) { + fail("sm_maximal_independent_set: row set is not independent"); + } +*/ + return indep; +} + +static sm_matrix * +build_intersection_matrix(A) +sm_matrix *A; +{ + register sm_row *prow, *prow1; + register sm_element *p, *p1; + register sm_col *pcol; + sm_matrix *B; + + /* Build row-intersection matrix */ + B = sm_alloc(); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + + /* Clear flags on all rows we can reach from row 'prow' */ + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + for(p1 = pcol->first_row; p1 != 0; p1 = p1->next_row) { + prow1 = sm_get_row(A, p1->row_num); + prow1->flag = 0; + } + } + + /* Now record which rows can be reached */ + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + for(p1 = pcol->first_row; p1 != 0; p1 = p1->next_row) { + prow1 = sm_get_row(A, p1->row_num); + if (! prow1->flag) { + prow1->flag = 1; + (void) sm_insert(B, prow->row_num, prow1->row_num); + } + } + } + } + + return B; +} diff --git a/sis/mincov/main.c b/sis/mincov/main.c new file mode 100644 index 0000000..77a4a06 --- /dev/null +++ b/sis/mincov/main.c @@ -0,0 +1,138 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/main.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +#include "util.h" +#include "sparse.h" +#include "mincov.h" + + +/* + * open_file -- open a file, or fail with an error message and exit + * Allows '-' as a synonym for standard input + */ +static FILE * +open_file(filename, mode) +char *filename; +char *mode; +{ + FILE *fp; + + if (strcmp(filename, "-") == 0) { + return mode[0] == 'r' ? stdin : stdout; + } else if ((fp = fopen(filename, mode)) == NULL) { + perror(filename); + exit(1); + } + return fp; +} + + +static void +usage(prog) +char *prog; +{ + (void) fprintf(stderr, "usage: %s [-ch] [-v #]\n", prog); + (void) fprintf(stderr, " -c\t\tread espresso 'compressed' pi table\n"); + (void) fprintf(stderr, " -h\t\theuristic covering\n"); + (void) fprintf(stderr, " -v n\t\tset verbose level to 'n' (e.g., 5)\n"); + exit(2); +} + + +int +main(argc, argv) +int argc; +char **argv; +{ + FILE *fp; + int opt, c, verbose, heuristic, compressed, ok; + char *file; + sm_matrix *A; + sm_row *cover; + +#if defined(vax) || defined(sun) + char *prog; + + prog = util_path_search(argv[0]); + if (prog == NIL(char)) { + (void) fprintf(stderr, "Cannot find current executable\n"); + exit(1); + } + util_restart(prog, "mincov.chkpt", 3600); +#endif + +#if defined(bsd4_2) || defined(sun) + setlinebuf(stdout); +#endif + + opt = 0; + verbose = 0; + compressed = 0; + while ((c = util_getopt(argc, argv, "cho:v:")) != EOF) { + switch(c) { + case 'c': + compressed = 1; + break; + case 'h': + heuristic = 1; + break; + case 'o': + opt = atoi(util_optarg); + break; + case 'v': + verbose = atoi(util_optarg); + break; + default: + usage(argv[0]); + break; + } + } + + if (argc - util_optind == 0) { + file = "-"; + } else if (argc - util_optind == 1) { + file = argv[util_optind]; + } else { + usage(argv[0]); + } + + fp = open_file(file, "r"); + if (compressed) { + ok = sm_read_compressed(fp, &A); + } else { + ok = sm_read(fp, &A); + } + if (! ok) { + (void) fprintf(stderr, "Error reading matrix\n"); + exit(1); + } + + switch (opt) { + case 0: + if (A->nrows < 25) sm_print(fp, A); + cover = sm_minimum_cover(A, NIL(int), heuristic, verbose); + (void) printf("Solution is "); + sm_row_print(stdout, cover); + (void) printf("\n"); + + sm_free(A); + sm_row_free(cover); + break; + + case 1: /* convert old espresso format */ + sm_write(stdout, A); + break; + + default: + usage(argv[0]); + } + + sm_cleanup(); + exit(0); +} diff --git a/sis/mincov/mincov.c b/sis/mincov/mincov.c new file mode 100644 index 0000000..39f5071 --- /dev/null +++ b/sis/mincov/mincov.c @@ -0,0 +1,373 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/mincov.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +#include "mincov_int.h" + +/* + * mincov.c + */ + +#define USE_GIMPEL +#define USE_INDEP_SET + +static int select_column(); +static void select_essential(); +static int verify_cover(); + + + +sm_row * +sm_minimum_cover(A, weight, heuristic, debug_level) +sm_matrix *A; +int *weight; +int heuristic; /* set to 1 for a heuristic covering */ +int debug_level; /* how deep in the recursion to provide info */ +{ + stats_t stats; + solution_t *best, *select; + sm_row *prow, *sol; + sm_col *pcol; + sm_matrix *dup_A; + int nelem, bound; + double sparsity; + + /* Avoid sillyness */ + if (A->nrows <= 0) { + return sm_row_alloc(); /* easy to cover */ + } + + /* Initialize debugging structure */ + stats.start_time = util_cpu_time(); + stats.debug = debug_level > 0; + stats.max_print_depth = debug_level; + stats.max_depth = -1; + stats.nodes = 0; + stats.component = stats.comp_count = 0; + stats.gimpel = stats.gimpel_count = 0; + stats.no_branching = heuristic != 0; + stats.lower_bound = -1; + + /* Check the matrix sparsity */ + nelem = 0; + sm_foreach_row(A, prow) { + nelem += prow->length; + } + sparsity = (double) nelem / (double) (A->nrows * A->ncols); + + /* Determine an upper bound on the solution */ + bound = 1; + sm_foreach_col(A, pcol) { + bound += WEIGHT(weight, pcol->col_num); + } + + /* Perform the covering */ + select = solution_alloc(); + dup_A = sm_dup(A); + best = sm_mincov(dup_A, select, weight, 0, bound, 0, &stats); + sm_free(dup_A); + solution_free(select); + + if (stats.debug) { + if (stats.no_branching) { + (void) printf("**** heuristic covering ...\n"); + (void) printf("lower bound = %d\n", stats.lower_bound); + } + (void) printf("matrix = %d by %d with %d elements (%4.3f%%)\n", + A->nrows, A->ncols, nelem, sparsity * 100.0); + (void) printf("cover size = %d elements\n", best->row->length); + (void) printf("cover cost = %d\n", best->cost); + (void) printf("time = %s\n", + util_print_time(util_cpu_time() - stats.start_time)); + (void) printf("components = %d\n", stats.comp_count); + (void) printf("gimpel = %d\n", stats.gimpel_count); + (void) printf("nodes = %d\n", stats.nodes); + (void) printf("max_depth = %d\n", stats.max_depth); + } + + sol = sm_row_dup(best->row); + if (! verify_cover(A, sol)) { + fail("mincov: internal error -- cover verification failed\n"); + } + solution_free(best); + return sol; +} + +/* + * Find the best cover for 'A' (given that 'select' already selected); + * + * - abort search if a solution cannot be found which beats 'bound' + * + * - if any solution meets 'lower_bound', then it is the optimum solution + * and can be returned without further work. + */ + +solution_t * +sm_mincov(A, select, weight, lb, bound, depth, stats) +sm_matrix *A; +solution_t *select; +int *weight; +int lb; +int bound; +int depth; +stats_t *stats; +{ + sm_matrix *A1, *A2, *L, *R; + sm_element *p; + solution_t *select1, *select2, *best, *best1, *best2, *indep; + int pick, lb_new, debug; + + /* Start out with some debugging information */ + stats->nodes++; + if (depth > stats->max_depth) stats->max_depth = depth; + debug = stats->debug && (depth <= stats->max_print_depth); + + /* Apply row dominance, column dominance, and select essentials */ + select_essential(A, select, weight, bound); + if (select->cost >= bound) { + return NIL(solution_t); + } + + /* See if gimpel's reduction technique applies ... */ +#ifdef USE_GIMPEL + if ( weight == NIL(int)) { /* hack until we fix it */ + if (gimpel_reduce(A, select, weight, lb, bound, depth, stats, &best)) { + return best; + } + } +#endif + +#ifdef USE_INDEP_SET + /* Determine bound from here to final solution using independent-set */ + indep = sm_maximal_independent_set(A, weight); + + /* make sure the lower bound is monotonically increasing */ + lb_new = MAX(select->cost + indep->cost, lb); + pick = select_column(A, weight, indep); + solution_free(indep); +#else + lb_new = select->cost + (A->nrows > 0); + pick = select_column(A, weight, NIL(solution_t)); +#endif + + if (depth == 0) { + stats->lower_bound = lb_new + stats->gimpel; + } + + if (debug) { + (void) printf("ABSMIN[%2d]%s", depth, stats->component ? "*" : " "); + (void) printf(" %3dx%3d sel=%3d bnd=%3d lb=%3d %12s ", + A->nrows, A->ncols, select->cost + stats->gimpel, + bound + stats->gimpel, lb_new + stats->gimpel, + util_print_time(util_cpu_time()-stats->start_time)); + } + + /* Check for bounding based on no better solution possible */ + if (lb_new >= bound) { + if (debug) (void) printf("bounded\n"); + best = NIL(solution_t); + + + /* Check for new best solution */ + } else if (A->nrows == 0) { + best = solution_dup(select); + if (debug) (void) printf("BEST\n"); + if (stats->debug && stats->component == 0) { + (void) printf("new 'best' solution %d at level %d (time is %s)\n", + best->cost + stats->gimpel, depth, + util_print_time(util_cpu_time() - stats->start_time)); + } + + + /* Check for a partition of the problem */ + } else if (sm_block_partition(A, &L, &R)) { + /* Make L the smaller problem */ + if (L->ncols > R->ncols) { + A1 = L; + L = R; + R = A1; + } + if (debug) (void) printf("comp %d %d\n", L->nrows, R->nrows); + stats->comp_count++; + + /* Solve problem for L */ + select1 = solution_alloc(); + stats->component++; + best1 = sm_mincov(L, select1, weight, 0, + bound-select->cost, depth+1, stats); + stats->component--; + solution_free(select1); + sm_free(L); + + /* Add best solution to the selected set */ + if (best1 == NIL(solution_t)) { + best = NIL(solution_t); + } else { + for(p = best1->row->first_col; p != 0; p = p->next_col) { + solution_add(select, weight, p->col_num); + } + solution_free(best1); + + /* recur for the remaining block */ + best = sm_mincov(R, select, weight, lb_new, bound, depth+1, stats); + } + sm_free(R); + + /* We've tried as hard as possible, but now we must split and recur */ + } else { + if (debug) (void) printf("pick=%d\n", pick); + + /* Assume we choose this column to be in the covering set */ + A1 = sm_dup(A); + select1 = solution_dup(select); + solution_accept(select1, A1, weight, pick); + best1 = sm_mincov(A1, select1, weight, lb_new, bound, depth+1, stats); + solution_free(select1); + sm_free(A1); + + /* Update the upper bound if we found a better solution */ + if (best1 != NIL(solution_t) && bound > best1->cost) { + bound = best1->cost; + } + + /* See if this is a heuristic covering (no branching) */ + if (stats->no_branching) { + return best1; + } + + /* Check for reaching lower bound -- if so, don't actually branch */ + if (best1 != NIL(solution_t) && best1->cost == lb_new) { + return best1; + } + + /* Now assume we cannot have that column */ + A2 = sm_dup(A); + select2 = solution_dup(select); + solution_reject(select2, A2, weight, pick); + best2 = sm_mincov(A2, select2, weight, lb_new, bound, depth+1, stats); + solution_free(select2); + sm_free(A2); + + best = solution_choose_best(best1, best2); + } + + return best; +} + +static int +select_column(A, weight, indep) +sm_matrix *A; +int *weight; +solution_t *indep; +{ + register sm_col *pcol; + register sm_row *prow, *indep_cols; + register sm_element *p, *p1; + double w, best; + int best_col; + + indep_cols = sm_row_alloc(); + if (indep != NIL(solution_t)) { + /* Find which columns are in the independent sets */ + for(p = indep->row->first_col; p != 0; p = p->next_col) { + prow = sm_get_row(A, p->col_num); + for(p1 = prow->first_col; p1 != 0; p1 = p1->next_col) { + (void) sm_row_insert(indep_cols, p1->col_num); + } + } + } else { + /* select out of all columns */ + sm_foreach_col(A, pcol) { + (void) sm_row_insert(indep_cols, pcol->col_num); + } + } + + /* Find the best column */ + best_col = -1; + best = -1; + + /* Consider only columns which are in some independent row */ + sm_foreach_row_element(indep_cols, p1) { + pcol = sm_get_col(A, p1->col_num); + + /* Compute the total 'value' of all things covered by the column */ + w = 0.0; + for(p = pcol->first_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + w += 1.0 / ((double) prow->length - 1.0); + } + + /* divide this by the relative cost of choosing this column */ + w = w / (double) WEIGHT(weight, pcol->col_num); + + /* maximize this ratio */ + if (w > best) { + best_col = pcol->col_num; + best = w; + } + } + + sm_row_free(indep_cols); + return best_col; +} + +static void +select_essential(A, select, weight, bound) +sm_matrix *A; +solution_t *select; +int *weight; +int bound; /* must beat this solution */ +{ + register sm_element *p; + register sm_row *prow, *essen; + int delcols, delrows, essen_count; + + do { + /* Check for dominated columns */ + delcols = sm_col_dominance(A, weight); + + /* Find the rows with only 1 element (the essentials) */ + essen = sm_row_alloc(); + sm_foreach_row(A, prow) { + if (prow->length == 1) { + (void) sm_row_insert(essen, prow->first_col->col_num); + } + } + + /* Select all of the elements */ + sm_foreach_row_element(essen, p) { + solution_accept(select, A, weight, p->col_num); + /* Make sure solution still looks good */ + if (select->cost >= bound) { + sm_row_free(essen); + return; + } + } + essen_count = essen->length; + sm_row_free(essen); + + /* Check for dominated rows */ + delrows = sm_row_dominance(A); + + } while (delcols > 0 || delrows > 0 || essen_count > 0); +} + +static int +verify_cover(A, cover) +sm_matrix *A; +sm_row *cover; +{ + sm_row *prow; + + sm_foreach_row(A, prow) { + if (! sm_row_intersects(prow, cover)) { + return 0; + } + } + return 1; +} diff --git a/sis/mincov/mincov.doc b/sis/mincov/mincov.doc new file mode 100644 index 0000000..85677d7 --- /dev/null +++ b/sis/mincov/mincov.doc @@ -0,0 +1,71 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/mincov.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +sm_row * +sm_minimum_cover(M, weights, heuristic, debug) +sm_matrix *M; +int *weights; +int heuristic; +int debug; + + Find a cover for the sparse-matrix M. weights is either NIL(int) + for an unweighted problem (all columns weight equal to 1), or + is an array with as many elements as there are columns in the + matrix. Each entry of the array gives the weight for that column. + The goal is the smallest total weight cover. + + heuristic is a flag which, if set, will visit the first leaf, and + return this as the (approximate) minimum cost cover. + + debug is a flag indicating how far down in the recursion debugging + messages should be printed. 0 gives silent operation. + +sm_row * +sm_mat_bin_minimum_cover (M, weights, heuristic, debug, ubound, option, record_fun) + +sm_matrix *M; +int *weights; +int heuristic, debug, ubound, option; +int (*record_fun) (); + +sm_row * +sm_mat_minimum_cover (M, weights, heuristic, debug, ubound, option, record_fun) + +sm_matrix *M; +int *weights; +int heuristic, debug, ubound, option; +int (*record_fun) (); + + Do the binate or unate covering of matrix M using Mathony's algorithm. + In the binate case each variable is represented with two columns: even for + the positive phase and odd for the negative phase. + + weights is either NIL(int) for an unweighted problem (all weights equal + to 1), or is an array with as many elements as there are columns in + the matrix. Each entry of the array gives the weight for that column. + The goal is the smallest total weight cover. + + A row can be missing from M, but at least one column for each odd-even + pair (a variable in the binate case) should be present. + + if heuristic != 0, terminate as the first leaf is reached. + + debug controls the amount of debugging information. + + ubound, if > 0, gives the best possible estimate of the covering cost. + + option chooses the algorithm to be used; the current best "magic" values + are: + - 6176 for the binate case FOR THE MAPPING MATRIX STRUCTURE (i.e. one + negated variable per row, "diagonal" structure), + - 4096 for the unate case. + + record_fun, if non-nil, is called whenever a leaf is reached, passing to it + as a parameter the current solution; if it returns 1 the solution + generation ends, otherwise it continues. diff --git a/sis/mincov/mincov.h b/sis/mincov/mincov.h new file mode 100644 index 0000000..1fa995b --- /dev/null +++ b/sis/mincov/mincov.h @@ -0,0 +1,15 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/mincov.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:31 $ + * + */ +/* exported */ +EXTERN sm_row *sm_minimum_cover ARGS((sm_matrix *, int *, int, int)); + +EXTERN sm_row *sm_mat_bin_minimum_cover ARGS((sm_matrix *, int *, int, int, int, int, int (*)() +)); +EXTERN sm_row *sm_mat_minimum_cover ARGS((sm_matrix *, int *, int, int, int, int, int (*)())); diff --git a/sis/mincov/mincov_int.h b/sis/mincov/mincov_int.h new file mode 100644 index 0000000..e16e0c3 --- /dev/null +++ b/sis/mincov/mincov_int.h @@ -0,0 +1,60 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/mincov_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "sis.h" + +typedef struct stats_struct stats_t; +struct stats_struct { + int debug; /* 1 if debugging is enabled */ + int max_print_depth; /* dump stats for levels up to this level */ + int max_depth; /* deepest the recursion has gone */ + int nodes; /* total nodes visited */ + int component; /* currently solving a component */ + int comp_count; /* number of components detected */ + int gimpel_count; /* number of times Gimpel reduction applied */ + int gimpel; /* currently inside Gimpel reduction */ + long start_time; /* cpu time when the covering started */ + int no_branching; + int lower_bound; +}; + +typedef struct solution_struct solution_t; +struct solution_struct { + sm_row *row; + int cost; +}; + +extern solution_t *solution_alloc(); +extern void solution_free(); +extern solution_t *solution_dup(); +extern void solution_accept(); +extern void solution_reject(); +extern void solution_add(); +extern solution_t *solution_choose_best(); + +extern solution_t *sm_maximal_independent_set(); +extern solution_t *sm_mincov(); +extern int gimpel_reduce(); + +#define WEIGHT(weight, col) (weight == NIL(int) ? 1 : weight[col]) + +/* for binate covering */ +typedef struct bin_solution_struct bin_solution_t; +struct bin_solution_struct { + pset set; + int cost; +}; + +extern bin_solution_t *bin_solution_alloc(); +extern void bin_solution_free(); +extern bin_solution_t *bin_solution_dup(); +extern void bin_solution_del(); +extern void bin_solution_add(); + +extern void sm_bin_mincov(); diff --git a/sis/mincov/part.c b/sis/mincov/part.c new file mode 100644 index 0000000..2b3cee5 --- /dev/null +++ b/sis/mincov/part.c @@ -0,0 +1,122 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/part.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "mincov_int.h" + +static int visit_col(); + +static void +copy_row(A, prow) +register sm_matrix *A; +register sm_row *prow; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(A, p->row_num, p->col_num); + } +} + + +static int +visit_row(A, prow, rows_visited, cols_visited) +sm_matrix *A; +sm_row *prow; +int *rows_visited; +int *cols_visited; +{ + sm_element *p; + sm_col *pcol; + + if (! prow->flag) { + prow->flag = 1; + (*rows_visited)++; + if (*rows_visited == A->nrows) { + return 1; + } + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + if (! pcol->flag) { + if (visit_col(A, pcol, rows_visited, cols_visited)) { + return 1; + } + } + } + } + return 0; +} + + +static int +visit_col(A, pcol, rows_visited, cols_visited) +sm_matrix *A; +sm_col *pcol; +int *rows_visited; +int *cols_visited; +{ + sm_element *p; + sm_row *prow; + + if (! pcol->flag) { + pcol->flag = 1; + (*cols_visited)++; + if (*cols_visited == A->ncols) { + return 1; + } + for(p = pcol->first_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + if (! prow->flag) { + if (visit_row(A, prow, rows_visited, cols_visited)) { + return 1; + } + } + } + } + return 0; +} + +int +sm_block_partition(A, L, R) +sm_matrix *A; +sm_matrix **L, **R; +{ + int cols_visited, rows_visited; + register sm_row *prow; + register sm_col *pcol; + + /* Avoid the trivial case */ + if (A->nrows == 0) { + return 0; + } + + /* Reset the visited flags for each row and column */ + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + prow->flag = 0; + } + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + pcol->flag = 0; + } + + cols_visited = rows_visited = 0; + if (visit_row(A, A->first_row, &rows_visited, &cols_visited)) { + /* we found all of the rows */ + return 0; + } else { + *L = sm_alloc(); + *R = sm_alloc(); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->flag) { + copy_row(*L, prow); + } else { + copy_row(*R, prow); + } + } + return 1; + } +} diff --git a/sis/mincov/solution.c b/sis/mincov/solution.c new file mode 100644 index 0000000..2871f6b --- /dev/null +++ b/sis/mincov/solution.c @@ -0,0 +1,114 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/mincov/solution.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "mincov_int.h" + + +solution_t * +solution_alloc() +{ + solution_t *sol; + + sol = ALLOC(solution_t, 1); + sol->cost = 0; + sol->row = sm_row_alloc(); + return sol; +} + + +void +solution_free(sol) +solution_t *sol; +{ + sm_row_free(sol->row); + FREE(sol); +} + + +solution_t * +solution_dup(sol) +solution_t *sol; +{ + solution_t *new_sol; + + new_sol = ALLOC(solution_t, 1); + new_sol->cost = sol->cost; + new_sol->row = sm_row_dup(sol->row); + return new_sol; +} + + +void +solution_add(sol, weight, col) +solution_t *sol; +int *weight; +int col; +{ + (void) sm_row_insert(sol->row, col); + sol->cost += WEIGHT(weight, col); +} + + +void +solution_accept(sol, A, weight, col) +solution_t *sol; +sm_matrix *A; +int *weight; +int col; +{ + register sm_element *p, *pnext; + sm_col *pcol; + + solution_add(sol, weight, col); + + /* delete rows covered by this column */ + pcol = sm_get_col(A, col); + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; /* grab it before it disappears */ + sm_delrow(A, p->row_num); + } +} + + +/* ARGSUSED */ +void +solution_reject(sol, A, weight, col) +solution_t *sol; +sm_matrix *A; +int *weight; +int col; +{ + sm_delcol(A, col); +} + + +solution_t * +solution_choose_best(best1, best2) +solution_t *best1, *best2; +{ + if (best1 != NIL(solution_t)) { + if (best2 != NIL(solution_t)) { + if (best1->cost <= best2->cost) { + solution_free(best2); + return best1; + } else { + solution_free(best1); + return best2; + } + } else { + return best1; + } + } else { + if (best2 != NIL(solution_t)) { + return best2; + } else { + return NIL(solution_t); + } + } +} diff --git a/sis/minimize/Makefile.am b/sis/minimize/Makefile.am new file mode 100644 index 0000000..99ca110 --- /dev/null +++ b/sis/minimize/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libminimize.a +libminimize_a_SOURCES = dcsimp.c minimize.c ros.c \ + min_int.h ros.h +pkginclude_HEADERS = minimize.h +dist_doc_DATA = minimize.doc diff --git a/sis/minimize/Makefile.in b/sis/minimize/Makefile.in new file mode 100644 index 0000000..36afc60 --- /dev/null +++ b/sis/minimize/Makefile.in @@ -0,0 +1,421 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libminimize_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/minimize +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libminimize_a_AR = $(AR) $(ARFLAGS) +libminimize_a_LIBADD = +am_libminimize_a_OBJECTS = dcsimp.$(OBJEXT) minimize.$(OBJEXT) \ + ros.$(OBJEXT) +libminimize_a_OBJECTS = $(am_libminimize_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libminimize_a_SOURCES) +DIST_SOURCES = $(libminimize_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libminimize.a +libminimize_a_SOURCES = dcsimp.c minimize.c ros.c \ + min_int.h ros.h + +pkginclude_HEADERS = minimize.h +dist_doc_DATA = minimize.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/minimize/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/minimize/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libminimize.a: $(libminimize_a_OBJECTS) $(libminimize_a_DEPENDENCIES) + -rm -f libminimize.a + $(libminimize_a_AR) libminimize.a $(libminimize_a_OBJECTS) $(libminimize_a_LIBADD) + $(RANLIB) libminimize.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/minimize/dcsimp.c b/sis/minimize/dcsimp.c new file mode 100644 index 0000000..3adf693 --- /dev/null +++ b/sis/minimize/dcsimp.c @@ -0,0 +1,388 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/minimize/dcsimp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include <stdio.h> +#include "espresso.h" + +pcover dcsimp(); +static bool dc_special_cases(); +pcover myexpand(); +int mydescend(); +void dc_simplify(); +bool is_orthagonal(); +pcover expand_to_largest(); +extern void init_ROS(); +extern void close_ROS(); +extern pcover get_ROS(); + +pcover ROS; + +int DC_DEBUG= 1; /* if set to 1, verifies the final cover for correctness*/ + +/* a two-level logic minimizer for multi-level logic synthesis. */ +/* tries to minimize the number of literals in the on-set cover. */ + +pcover dcsimp(F,Old_D) + +pcover F; /* cover for the onset*/ +pcover Old_D; /* cover for the don't care set*/ + +{ + + pcover D; + pcover T; + pcube p; + pcube last; + pcover FF; + pcover E; + int error; + int lit_dis; + cost_t cost; + + FF = sf_save(F); + + D= sf_save(Old_D); + + + /* Initialize data structures for reduced offset */ + init_ROS(FF, D, 1, 3, cube.size); + + +/* check if any of the cubes in the on-set is essential? +* most of the time cubes in the original on-set are primes. therefore, +* it pays off to find essential ones and avoid extra work during reduction +* and expansion. +*/ + + foreach_set(FF,last,p){ + SET(p,RELESSEN); + RESET(p,NONESSEN); + } + EXECUTE(E = essential(&FF, &D), ESSEN_TIME, E, cost); + +/* + if (essen_cube(FF,D,p)){ + E= sf_addset(E,p); + RESET(p, ACTIVE); + FF->active_count-- ; + }else{ + SET(p, ACTIVE); + } + } + FF= sf_inactive(FF); + D= sf_join(D,E); +*/ + +/* reduce cubes in the onset as much as possible. T is the new cover. */ + + dc_simplify(cube1list(FF),cube1list(D),&T); + + + if (T->count > 0){ + ROS = get_ROS(0, T, (pcover) NULL); + + +/* if the number of reduced cubes is large try to minimize the number of +* cubes in the onset in two steps. +*/ + if(T->count > 20) { + lit_dis= (cube.num_binary_vars + 1) /3 ; + + T= myexpand(T,lit_dis); + T= reduce(T,D); + } + lit_dis= cube.num_binary_vars; + + if (T->count > 1) + T= myexpand(T,lit_dis); + T = expand_to_largest(T, ROS); + + } + + + T = sf_append(T,E); + + +/* do a cover verification*/ + if (DC_DEBUG){ + error= verify(T,F,D); + if (error) { + print_solution = FALSE; + sf_free(T); + T = sf_save(F); + } + } + free_cover(F); + sf_free(FF); + sf_free(D); + close_ROS(); + return(T); +} + +pcover myexpand(LKset,lit_dis) +/* a greedy algorithm to reduce the number of cubes in the cover. +* sort all the cubes in the reduced on-set. +* make supercube of every two cube and check if the supercube is in +* F U D. +*/ +pcover LKset; /* reduced on-set cover */ +int lit_dis; /* prameter to decide which supercubes to generate*/ +{ + pcover T3; + pcover T; + pcube p,mp,por; + pcube pp; + pcube last1,last2; + pcube *L; + + T = new_cover(10); +/* sort all the cubes in the reduced onset so that cube with maximum number +* of 2's is on top. +*/ + qsort((char *) (L= sf_list(LKset)), LKset->count, sizeof(pset), mydescend); + T3= sf_unlist(L, LKset->count, LKset->sf_size); + + foreach_set(T3,last1,p){ + SET(p,ACTIVE); + } + + pp= set_save(T3->data); + por = new_cube(); + foreach_active_set(T3,last1,p){ + RESET(p,ACTIVE); + INLINEset_copy(por,p); + INLINEset_copy(pp,p); + + foreach_active_set(T3,last2,mp){ +/* see how many literals need to be raised in order to make the supercube +* if the number of literals is less than limit then do orhagonality test. +*/ + if(literals_to_raise(pp,mp) < lit_dis){ + INLINEset_or(por,por,mp); + if (is_orthagonal(por, ROS)){ + INLINEset_copy(p,por); + RESET(mp,ACTIVE); + }else{ + INLINEset_copy(por,p); + } + } + } + T= sf_addset(T,por); + } + set_free(por); + set_free(pp); + sf_free(LKset); + sf_free(T3); + return(T); +} + + +int literals_to_raise(p,q) +pcube p; +pcube q; + +{ + + int count= 0; + int i; + int lit; + + for(i=0;i< (cube.num_binary_vars);i++){ + if ((lit= GETINPUT(p,i)) != TWO && GETINPUT(q,i)!= lit ) count++ ; + } + return(count); +} + + +int mydescend(a,b) +pset *a, *b; +{ + register pset a1= *a, b1= *b; + if (cube_order(a1) < cube_order(b1)) return 1; + else if (cube_order(a1) > cube_order(b1)) return -1; + else return 0; +} + + +/*split until all the cubes in each leaf are unate then reduce each +* one of the cubes and store all the cubes in one pset-family. +*/ + +void dc_simplify(F,D,LKset) +pcube *F; +pcube *D; +pcover *LKset; +{ + register pcube cl, cr; + register pcube last,p; + register int best; + pcover LKsetr, LKsetl; + + + if (dc_special_cases(F,D,LKset) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(F, cl, cr, COMPL); + + /* Complement the left and right halves */ + dc_simplify(scofactor(F, cl, best), scofactor(D, cl, best),&LKsetl) ; + + dc_simplify(scofactor(F, cr, best), scofactor(D, cr, best),&LKsetr); + + foreach_set(LKsetl,last,p){ + INLINEset_and(p,p,cl); + } + foreach_set(LKsetr,last,p){ + INLINEset_and(p,p,cr); + } + + *LKset= sf_append(LKsetr,LKsetl); + free_cube(cl); + free_cube(cr); + free_cubelist(F); + free_cubelist(D); + } +} + +static bool dc_special_cases(F,D,FD) +pcube *F; +pcube *D; +pcover *FD; +{ + pcover A,B; + + /* Check for no cubes in the cover (function is empty) */ + + if (F[2] == NULL) { + *FD = new_cover(0); + free_cubelist(F); + free_cubelist(D); + return TRUE; + } + + /* Collect column counts, determine unate variables, etc. */ + massive_count(F); + + + /* Check for unate cover */ + if (cdata.vars_unate == cdata.vars_active) { + /* Make the cover minimum by single-cube containment */ + A = cubeunlist(F); + A = sf_contain(A); + if (D[2] != NULL) { + B = cubeunlist(D); + *FD= reduce(A,B); + sf_free(B); + }else{ + *FD= A; + } + free_cubelist(F); + free_cubelist(D); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + + + +/*count the number of 2's in a cube.*/ +int cube_order(p) +pcube p; +{ + int i,j; + for(j=0, i=0;j< (cube.num_binary_vars );j++) + if (GETINPUT(p,j) == TWO) i++; + return(i); + +} + +/* + * Return TRUE if p is orthagonal to each cube in A; otherwise, + * return FALSE. + */ + +bool is_orthagonal(p, A) +pcube p; +pcover A; + +{ + + pcube last, q; + + foreach_set(A, last, q) { + if (cdist0(p, q)) + return(FALSE); + } + + return(TRUE); + +} + +/* + * expand_to_largest -- expand each cube p in F to a larget prime + * containing p. ros should be useful for all the cubes in F. + */ + +pcover +expand_to_largest(F, ros) +pcover F; +pcover ros; + +{ + + pcube RAISE, FREESET; + pcube p, q, last; + int i; + + RAISE = new_cube(); + FREESET = new_cube(); + + /* Find the larget prime of each cube in F */ + foreachi_set(F, i, p) { + + /* Set all cubes in ros active */ + ros->active_count = ros->count; + foreach_set(ros, last, q) { + SET(q, ACTIVE); + } + + /* Initialize the lowering, raising and unassigned sets */ + (void) set_copy(RAISE, p); + (void) set_diff(FREESET, cube.fullset, RAISE); + + /* Remove essentially lowered and essentially raised parts */ + (void) essen_parts(ros, /*CC*/ (pcover) NULL, RAISE, FREESET); + + /* Finally, choose the largest possible prime. We will loop only + if we decide unravelling OFF-set is too expensive */ + while (ros->active_count > 0) { + mincov(ros, RAISE, FREESET); + } + + /* Raise any remaining free coordinates */ + (void) set_or(RAISE, RAISE, FREESET); + + /* Copy RAISE into p */ + (void) set_copy(p, RAISE); + SET(p, PRIME); + RESET(p, COVERED); + + } + + free_cube(RAISE); + free_cube(FREESET); + + return(F); + +} diff --git a/sis/minimize/min_int.h b/sis/minimize/min_int.h new file mode 100644 index 0000000..f0f1f47 --- /dev/null +++ b/sis/minimize/min_int.h @@ -0,0 +1,37 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/minimize/min_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "ros.h" + +/* Functions defined in minimize.c */ + +/* minimize.c */ extern pcover nocomp(); +/* minimize.c */ extern pcover snocomp(); +/* minimize.c */ extern pset_family ncp_unate_compl(); +/* minimize.c */ extern pset_family ncp_unate_complement(); +/* minimize.c */ extern void ncp_compl_special_cases(); +/* minimize.c */ extern pcover nc_super_gasp(); +/* minimize.c */ extern pcover nc_all_primes(); +/* minimize.c */ extern pcover nc_make_sparse(); +/* minimize.c */ extern pcover nc_expand_gasp(); +/* minimize.c */ extern void nc_expand1_gasp(); +/* minimize.c */ extern pcover nc_last_gasp(); +/* minimize.c */ extern pcover nc_reduce_gasp(); +/* minimize.c */ extern pcover nc_reduce(); +/* minimize.c */ extern pcover nc_random_order(); +/* minimize.c */ extern pcover nc_permute(); +/* minimize.c */ extern pcover nc_mini_sort(); +/* minimize.c */ extern pcube nc_reduce_cube(); +/* minimize.c */ extern pcube nc_sccc(); +/* minimize.c */ extern bool nc_sccc_special_cases(); +/* minimize.c */ extern pcover ncp_expand(); +/* minimize.c */ extern void ncp_expand1(); +/* minimize.c */ extern pcover nc_first_expand(); +/* minimize.c */ extern void rem_unnec_r_cubes(); +/* dcsimp.c */ extern pcover dcsimp(); diff --git a/sis/minimize/minimize.c b/sis/minimize/minimize.c new file mode 100644 index 0000000..61b7e90 --- /dev/null +++ b/sis/minimize/minimize.c @@ -0,0 +1,1585 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/minimize/minimize.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +/****************************************************************************** + * This module has been written by Abdul A. Malik * + * Please forward all feedback, comments, bugs etc to: * + * * + * ABDUL A. MALIK * + * malik@ic.berkeley.edu * + * * + * Department of Electrical Engineering and Computer Sciences * + * University of California at Berkeley * + * Berkeley, CA 94704. * + * * + * Telephone: (415) 642-5048 * + ******************************************************************************/ + +/* + * Module: minimize.c + * + * Purpose: To do minimization without evaluating the complement of (FUD). + * This module contains two routines for minimization: nocomp() + * and snocomp(). nocomp() is similar to espresso() except that + * it uses reduced offset rather than the entire offset. snocomp() + * also uses reduced offsets rather than entire offset but it does + * a single pass consisting of essential(), reduce(), expand(), + * and irredundant(). + * + * The subroutine minimize(F, D, single_pass) is written to decide + * whether nocomp() or snocomp() is to be used. If the third + * argument single_pass is TRUE sncomp(F, D) is passed, otherwise + * nocomp(F, D) is called. F and D are the Onset and the Don't Care + * sets. + * + * + * Returns a minimized version of the ON-set of a function + * + * The following global variables affect the operation of nocomp: + * + * MISCELLANEOUS: + * trace + * print trace information as the minimization progresses + * + * remove_essential + * remove essential primes + * + * single_expand + * if true, stop after first expand/irredundant + * + * LAST_GASP or SUPER_GASP strategy: + * use_super_gasp + * uses the super_gasp strategy rather than last_gasp + * + * SETUP strategy: + * recompute_onset + * recompute onset using the complement before starting + * + * unwrap_onset + * unwrap the function output part before first expand + * + * MAKE_SPARSE strategy: + * force_irredundant + * iterates make_sparse to force a minimal solution (used + * indirectly by make_sparse) + * + * skip_make_sparse + * skip the make_sparse step (used by opo only) + * + */ + +#include "sis.h" +#define extern +#include "min_int.h" +#undef extern +#include "minimize.h" + +static pset_family ncp_abs_covered_many(); +static pset_family ncp_abs_covered(); +static int ncp_abs_select_restricted(); + +static bool toggle = TRUE; + +/* + * minimize -- choose between nocomp(), snocomp(), dc_simplify(). + */ + +pcover +minimize(F, D, type) +pcover F; +pcover D; +int type; + +{ + + if (type == SNOCOMP) + return(snocomp(F, D)); + + else if (type == NOCOMP) + return(nocomp(F, D)); + + else if (type == DCSIMPLIFY) + return(dcsimp(F, D)); + + else { + fail("Wrong minimize type"); + exit(-1); + return(F); + } + +} + +/* + * nocomp(): Do minimization whithout computing complement of (F U D). + */ + +pcover +nocomp(F, D1) +pcover F, D1; + +{ + pcover E, D, Fsave, Fold, Fbest_save; + pset last, p; + cost_t cost, best_cost, best_save_cost; + bool skip_gasp = FALSE; + + /* Skip make_sparse if single output binary function */ + if ((cube.size - 2*cube.num_binary_vars) <= 1) { + skip_make_sparse = TRUE; + unwrap_onset = FALSE; + } + + +begin: + Fsave = sf_save(F); /* Save the original cover */ + D = sf_save(D1); /* make a scratch copy of D */ + + /* Initialize variables to collect statistics about ROS */ + init_ROS(F, D, 1, 3, cube.size); + + /* Setup has always been a problem */ + if (recompute_onset) { + EXEC(E = simplify(cube1list(F)), "SIMPLIFY ", E); + free_cover(F); + F = E; + } + cover_cost(F, &cost); + if (unwrap_onset && (cube.part_size[cube.num_vars - 1] > 1) + && (cost.out != cost.cubes*cube.part_size[cube.num_vars-1]) + && (cost.out < 5000)) + EXEC(F = sf_contain(unravel(F, cube.num_vars - 1)), "SETUP ", F); + + /* Initial expand and irredundant */ + foreach_set(F, last, p) { + RESET(p, PRIME); + } + + if (F->count > 6) { + EXECUTE(F = ncp_expand(F, (pcover)NULL, FALSE), EXPAND_TIME, F, cost); + } else { + EXECUTE(F = nc_first_expand(F, FALSE), EXPAND_TIME, F, cost); + } + + EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); + + if (! single_expand) { + if (remove_essential) { + EXECUTE(E = essential(&F, &D), ESSEN_TIME, E, cost); + } else { + E = new_cover(0); + } + + cover_cost(F, &cost); + copy_cost(&cost, &best_save_cost); + Fbest_save = sf_save(F); + do { + + /* Repeat inner loop until solution becomes "stable" */ + do { + copy_cost(&cost, &best_cost); + EXECUTE(F = nc_reduce(F, &Fold, D), REDUCE_TIME, F, cost); + EXECUTE(F = ncp_expand(F, Fold, FALSE), + EXPAND_TIME, F, cost); + + if (F->count == 1) { /* No need iterate any more */ + goto done; + } + + EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); + + /* Save the literal minimum solution */ + if ((best_save_cost.cubes > cost.cubes) || + (best_save_cost.cubes == cost.cubes) && + (best_save_cost.in > cost.in)) { + sf_free(Fbest_save); + Fbest_save = sf_save(F); + } + + } while (cost.cubes < best_cost.cubes); + + if (skip_gasp) /* Skip last_gasp and super_gasp if TRUE */ + goto done; + + /* Perturb solution to see if we can continue to iterate */ + copy_cost(&cost, &best_cost); + if (use_super_gasp) { + F = nc_super_gasp(F, D, &cost); + if (cost.cubes >= best_cost.cubes) + break; + } else { + F = nc_last_gasp(F, D, &cost); + } + + if ((best_save_cost.cubes > cost.cubes) || + (best_save_cost.cubes == cost.cubes) && + (best_save_cost.in > cost.in)) { + sf_free(Fbest_save); + Fbest_save = sf_save(F); + } + + } while (cost.cubes < best_cost.cubes || + (cost.cubes == best_cost.cubes && cost.total < best_cost.total)); + +done: + /* Save the literal minimum solution */ + if ((best_save_cost.cubes > cost.cubes) || + (best_save_cost.cubes == cost.cubes) && + (best_save_cost.in > cost.in)) { + sf_free(Fbest_save); + Fbest_save = sf_save(F); + } + + + /* Append the essential cubes to F */ + sf_free(F); + F = sf_append(Fbest_save, E); + if (trace) size_stamp(F, "ADJUST "); + } + + /* Free the D which we used */ + free_cover(D); + + /* Attempt to make the PLA matrix sparse */ + if (! skip_make_sparse) { + F = nc_make_sparse(F, D1); + } + + /* Close out all stuff about reduced offsets */ + close_ROS(); + + /* + * Check to make sure function is actually smaller !! + * This can only happen because of the initial unravel. If we fail, + * then run the whole thing again without the unravel. + */ + if ((Fsave->count < F->count) && (!unwrap_onset)) { + free_cover(F); + F = Fsave; + unwrap_onset = FALSE; + goto begin; + } else { + free_cover(Fsave); + } + + return F; +} + +/* + * Do a single pass consisting of essential, reduce, expand, irredundant. + * The purpose is to do some reasonable amount of optimization in a short time. + */ + +pcover +snocomp(F, D1) +pcover F, D1; + +{ + pcover E, D, Fold; + cost_t cost; + pcube p, last; + + D = sf_save(D1); + + /* Initialize variables to collect statistics about ROS */ + init_ROS(F, D, 1, 3, cube.size); + + foreach_set(F, last, p) { + SET(p, RELESSEN); + RESET(p, NONESSEN); + } + + EXECUTE(E = essential(&F, &D), ESSEN_TIME, E, cost); + EXECUTE(F = nc_reduce(F, &Fold, D), REDUCE_TIME, F, cost); + + /* Since the initial expand that is done in espresso is not done + here, any cube that could not be reduced by "reduce" is not + necessarily prime. Make sure that no cube has PRIME flag set + before "expand" is called. */ + + foreach_set(F, last, p) { + RESET(p, PRIME); + } + + EXEC(F = ncp_expand(F, Fold, FALSE), "PRIMES ", F); + if (F->count > 1) + EXEC(F = irredundant(F, D), "IRRED_TIME ", F); + + /* Append the essential cubes to F */ + F = sf_append(F, E); + if (trace) size_stamp(F, "ADJUST "); + + /* Free the D which we used */ + free_cover(D); + + /* Close out all stuff about reduced offsets */ + close_ROS(); + + return F; + +} + +/* + * unate_compl + */ + +pset_family +ncp_unate_compl(A, max_lit) +pset_family A; +int max_lit; + +{ + register pset p, last; + + foreach_set(A, last, p) { + PUTSIZE(p, set_ord(p)); + } + + /* Recursively find the complement */ + A = ncp_unate_complement(A, max_lit); + + /* Now, we can guarantee a minimal result by containing the result */ + A = sf_rev_contain(A); + return A; +} + + +/* + * Assume SIZE(p) records the size of each set + */ + +pset_family +ncp_unate_complement(A, max_lit) +pset_family A; /* disposes of A */ +int max_lit; + +{ + pset_family Abar; + register pset p, p1, restrict; + register int i; + int max_i, min_set_ord, j; + + /* Check for no sets in the matrix -- complement is the universe */ + if (A->count == 0) { + sf_free(A); + Abar = sf_new(1, A->sf_size); + (void) set_clear(GETSET(Abar, Abar->count++), A->sf_size); + + /* If the number of literals used so far is larger than or equal to + the number of literals allowed then return */ + }else if (max_lit <= 0) { + Abar = A; + Abar->count = 0; + + /* Check for a single set in the maxtrix -- compute de Morgan complement */ + } else if (A->count == 1) { + p = A->data; + Abar = sf_new(A->sf_size, A->sf_size); + for(i = 0; i < A->sf_size; i++) { + if (is_in_set(p, i)) { + p1 = set_clear(GETSET(Abar, Abar->count++), A->sf_size); + set_insert(p1, i); + } + } + sf_free(A); + + } else { + + /* Select splitting variable as the variable which belongs to a set + * of the smallest size, and which has greatest column count + */ + restrict = set_new(A->sf_size); + min_set_ord = A->sf_size + 1; + foreachi_set(A, i, p) { + if (SIZE(p) < min_set_ord) { + (void) set_copy(restrict, p); + min_set_ord = SIZE(p); + } else if (SIZE(p) == min_set_ord) { + (void) set_or(restrict, restrict, p); + } + } + + /* Check for no data (shouldn't happen ?) */ + if (min_set_ord == 0) { + A->count = 0; + Abar = A; + + /* Check for "essential" columns */ + } else if (min_set_ord == 1) { + i = set_ord(restrict); + if (i > max_lit) { + Abar = A; + Abar->count = 0; + } else { + Abar = ncp_unate_complement(ncp_abs_covered_many(A, restrict), + max_lit-i); + sf_free(A); + foreachi_set(Abar, i, p) { + (void) set_or(p, p, restrict); + } + } + + /* else, recur as usual */ + } else { + max_i = ncp_abs_select_restricted(A, restrict); + + /* Select those rows of A which are not covered by max_i, + * recursively find all minimal covers of these rows, and + * then add back in max_i + */ + Abar = ncp_unate_complement(ncp_abs_covered(A, max_i), max_lit-1); + foreachi_set(Abar, i, p) { + set_insert(p, max_i); + } + + /* Now recur on A with all zero's on column max_i */ + foreachi_set(A, i, p) { + if (is_in_set(p, max_i)) { + set_remove(p, max_i); + j = SIZE(p) - 1; + PUTSIZE(p, j); + } + } + + Abar = sf_append(Abar, ncp_unate_complement(A, max_lit)); + } + set_free(restrict); + } + + return Abar; +} + +/* + * ncp_abs_covered_many -- after selecting many columns for ther selected set, + * create a new matrix which is only those rows which are still uncovered + */ +static pset_family +ncp_abs_covered_many(A, pick_set) +pset_family A; +register pset pick_set; +{ + register pset last, p, pdest; + register pset_family Aprime; + + Aprime = sf_new(A->count, A->sf_size); + pdest = Aprime->data; + foreach_set(A, last, p) + if (setp_disjoint(p, pick_set)) { + INLINEset_copy(pdest, p); + Aprime->count++; + pdest += Aprime->wsize; + } + return Aprime; +} + + +/* + * ncp_abs_select_restricted -- select the column of maximum column count which + * also belongs to the set "restrict"; weight each column of a set as + * 1 / (set_ord(p) - 1). + */ +static int +ncp_abs_select_restricted(A, restrict) +pset_family A; +pset restrict; +{ + register int i, best_var, best_count, *count; + + /* Sum the elements in these columns */ + count = sf_count_restricted(A, restrict); + + /* Find which variable has maximum weight */ + best_var = -1; + best_count = 0; + for(i = 0; i < A->sf_size; i++) { + if (count[i] > best_count) { + best_var = i; + best_count = count[i]; + } + } + FREE(count); + + if (best_var == -1) + fatal("ncp_abs_select_restricted: should not have best_var == -1"); + + return best_var; +} + +/* + * abs_covered -- after selecting a new column for the selected set, + * create a new matrix which is only those rows which are still uncovered + */ +static pset_family +ncp_abs_covered(A, pick) +pset_family A; +register int pick; +{ + register pset last, p, pdest; + register pset_family Aprime; + + Aprime = sf_new(A->count, A->sf_size); + pdest = Aprime->data; + foreach_set(A, last, p) + if (! is_in_set(p, pick)) { + INLINEset_copy(pdest, p); + Aprime->count++; + pdest += Aprime->wsize; + } + return Aprime; +} + +/* + * ncp_compl-special_cases is to be used only to complement unate functions + * when the number of literals in the complement are to be restricted to + * max_lit. + */ +void +ncp_compl_special_cases(T, Tbar, max_lit) +pcube *T; /* will be disposed of */ +pcover *Tbar; /* returned only if answer determined */ +int max_lit; + +{ + register pcube *T1, p, ceil, cof=T[0]; + pcover A, ceil_compl; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tbar = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tbar = nc_compl_cube(set_or(cof, cof, T[2])); + free_cubelist(T); + return; + } + + /* Check for a row of all 1's (implies complement is null) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tbar = new_cover(0); + free_cubelist(T); + return; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + ceil_compl = nc_compl_cube(ceil); + (void) set_or(cof, cof, set_diff(ceil, cube.fullset, ceil)); + set_free(ceil); + ncp_compl_special_cases(T, Tbar, max_lit); + *Tbar = sf_append(*Tbar, ceil_compl); + return; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tbar = new_cover(0); + free_cubelist(T); + return; + + /* The cover is unate since all else failed */ + } else { + A = map_cover_to_unate(T); + free_cubelist(T); + A = ncp_unate_compl(A, max_lit); + *Tbar = map_unate_to_cover(A); + sf_free(A); + return; + } + +} + +/* + * nc_super_gasp + */ + +pcover +nc_super_gasp(F, D, cost) +pcover F, D; +cost_t *cost; +{ + pcover G, G1; + + EXECUTE(G = nc_reduce_gasp(F, D), GREDUCE_TIME, G, *cost); + EXECUTE(G1 = nc_all_primes(G), GEXPAND_TIME, G1, *cost); + free_cover(G); + EXEC(G = sf_dupl(sf_append(F, G1)), "NEWPRIMES", G); + EXECUTE(F = irredundant(G, D), IRRED_TIME, F, *cost); + return F; +} + +/* + * nc_all_primes -- foreach cube in F, generate all of the primes + * which cover the cube. + */ + +pcover +nc_all_primes(F) +pcover F; +{ + register pcube last, p, RAISE = nc_tmp_cube[24], FREESET = nc_tmp_cube[25]; + pcover Fall_primes, B1; + + Fall_primes = new_cover(F->count); + + foreach_set(F, last, p) { + if (TESTP(p, PRIME)) { + Fall_primes = sf_addset(Fall_primes, p); + } else { + + /* Find the blocking matrix */ + get_ROS1(p, cube.fullset, root); + + /* Setup for call to essential parts */ + (void) set_copy(RAISE, p); + (void) set_diff(FREESET, cube.fullset, RAISE); + setup_BB_CC(ROS, /* CC */ (pcover) NULL); + essen_parts(ROS, /* CC */ (pcover) NULL, RAISE, FREESET); + + /* Find all of the primes, and add them to the prime set */ + B1 = find_all_primes(ROS, RAISE, FREESET); + Fall_primes = sf_append(Fall_primes, B1); + + } + } + + return Fall_primes; +} + +/* + * Similar to make_sparse except that the complete off_set is + * not used. + */ + +pcover +nc_make_sparse(F, D) +pcover F, D; +{ + cost_t cost, best_cost; + + cover_cost(F, &best_cost); + + do { + EXECUTE(F = mv_reduce(F, D), MV_REDUCE_TIME, F, cost); + if (cost.total == best_cost.total) + break; + copy_cost(&cost, &best_cost); + + EXECUTE(F = ncp_expand(F, (pcover)NULL, TRUE), RAISE_IN_TIME, F, cost); + if (cost.total == best_cost.total) + break; + copy_cost(&cost, &best_cost); + } while (force_irredundant); + + return F; +} + +/* + * nc_expand_gasp -- similar to expand_gasp except complete + * off set is not used. + * + * expand each nonprime cube of F into a prime implicant + * The gasp strategy differs in that only those cubes which expand to + * cover some other cube are saved; also, all cubes are expanded + * regardless of whether they become covered or not. + */ + +pcover +nc_expand_gasp(F, D, Foriginal) +INOUT pcover F; +IN pcover D; +IN pcover Foriginal; +{ + int c1index; + pcover G; + + /* Try to expand each nonprime and noncovered cube */ + G = new_cover(10); + for(c1index = 0; c1index < F->count; c1index++) { + nc_expand1_gasp(F, D, Foriginal, c1index, &G); + } + G = sf_dupl(G); + G = ncp_expand(G, (pcover)NULL, /*nonsparse*/ FALSE);/* Make them prime ! */ + return G; +} + +/* + * nc_expand1_gasp -- similar to expand1_gasp + * + * Expand a single cube against the OFF-set, using the gasp strategy + */ +void +nc_expand1_gasp(F, D, Foriginal, c1index, G) +pcover F; /* reduced cubes of ON-set */ +pcover D; /* DC-set */ +pcover Foriginal; /* ON-set before reduction (same order as F) */ +int c1index; /* which index of F (or Freduced) to be checked */ +pcover *G; +{ + register int c2index; + register pcube p, last, c2under; + pcube RAISE = nc_tmp_cube[28], + FREESET = nc_tmp_cube[29], + temp = nc_tmp_cube[30]; + pcube *FD, c2essential; + pcube new_lower = nc_tmp_cube[32]; + pcover F1; + + if (debug & EXPAND1) { + (void) printf("\nEXPAND1_GASP: \t%s\n", pc1(GETSET(F, c1index))); + } + + /* Initialize the raising and unassigned sets */ + (void) set_copy(RAISE, GETSET(F, c1index)); + (void) set_diff(FREESET, cube.fullset, RAISE); + + ROS = get_ROS(c1index, F, (pcover) NULL); + + /* Initialize the Blocking Matrix */ + ROS->active_count = ROS->count; + foreach_set(ROS, last, p) { + SET(p, ACTIVE); + } + /* Initialize the reduced ON-set, all nonprime cubes become active */ + F->active_count = F->count; + foreachi_set(F, c2index, c2under) { + if (c1index == c2index || TESTP(c2under, PRIME)) { + F->active_count--; + RESET(c2under, ACTIVE); + } else { + SET(c2under, ACTIVE); + } + } + + /* Determine parts which must be lowered */ + essen_parts(ROS, F, RAISE, FREESET); + + /* Determine parts which can always be raised */ + essen_raising(ROS, RAISE, FREESET); + + /* See which, if any, of the reduced cubes we can cover */ + foreachi_set(F, c2index, c2under) { + if (TESTP(c2under, ACTIVE)) { + /* See if this cube can be covered by an expansion */ + if (setp_implies(c2under, RAISE) || + feasibly_covered(ROS, c2under, RAISE, new_lower)) { + + /* See if c1under can expanded to cover c2 reduced against + * (F - c1) u c1under; if so, c2 can definitely be removed ! + */ + + /* Copy F and replace c1 with c1under */ + F1 = sf_save(Foriginal); + (void) set_copy(GETSET(F1, c1index), GETSET(F, c1index)); + + /* Reduce c2 against ((F - c1) u c1under) */ + FD = cube2list(F1, D); + c2essential = nc_reduce_cube(FD, GETSET(F1, c2index)); + free_cubelist(FD); + sf_free(F1); + + /* See if c2essential is covered by an expansion of c1under */ + if (feasibly_covered(ROS, c2essential, RAISE, new_lower)) { + (void) set_or(temp, RAISE, c2essential); + RESET(temp, PRIME); /* cube not prime */ + *G = sf_addset(*G, temp); + } + set_free(c2essential); + } + } + } + +} + +/* + * nc_last_gasp + */ + +pcover +nc_last_gasp(F, D, cost) +pcover F, D; +cost_t *cost; +{ + pcover G, G1; + + EXECUTE(G = nc_reduce_gasp(F, D), GREDUCE_TIME, G, *cost); + EXECUTE(G1 = nc_expand_gasp(G, D, F), GEXPAND_TIME, G1, *cost); + free_cover(G); + EXECUTE(F = irred_gasp(F, D, G1), GIRRED_TIME, F, *cost); + return F; +} + +/* + * nc_reduce_gasp -- compute the maximal reduction of each cube of F + * + * If a cube does not reduce, it remains prime; otherwise, it is marked + * as nonprime. If the cube is redundant (should NEVER happen here) we + * just crap out ... + * + * A cover with all of the cubes of F is returned. Those that did + * reduce are marked "NONPRIME"; those that reduced are marked "PRIME". + * The cubes are in the same order as in F. + */ +pcover +nc_reduce_gasp(F, D) +pcover F, D; +{ + pcube p, last, cunder, *FD; + pcover G; + + G = new_cover(F->count); + FD = cube2list(F, D); + + /* Reduce cubes of F without replacement */ + foreach_set(F, last, p) { + cunder = nc_reduce_cube(FD, p); + if (setp_empty(cunder)) { + fatal("empty reduction in nc_reduce_gasp, shouldn't happen"); + } else if (setp_equal(cunder, p)) { + SET(cunder, PRIME); /* just to make sure */ + G = sf_addset(G, p); /* it did not reduce ... */ + } else { + RESET(cunder, PRIME); /* it reduced ... */ + G = sf_addset(G, cunder); + } + if (debug & GASP) { + (void) printf("REDUCE_GASP: %s reduced to %s\n", pc1(p), pc2(cunder)); + } + free_cube(cunder); + } + + free_cubelist(FD); + return G; +} + +/* + * This is similar to reduce, except that it returns pre-reduced + * cubes in Fold in the same order that the reduced cubes are returned + * in F. + * + * WARNING: + * variable toggle used in reduce is defined as a global + * variable in reduce.c. The variable is not available here so it + * has been declared as a global variable in this file and set to + * TRUE. So long as toggle here and toggle in reduce.c have the same value, + * The order in which cubes are reduced in the two subroutines will + * be the same. Otherwise, the order will be different. + */ +pcover +nc_reduce(F, Fold, D) +INOUT pcover F; +OUT pcover *Fold; +IN pcover D; +{ + register pcube p, cunder, *FD; + register index; + bool inactive; + + /* Order the cubes */ + if (use_random_order) + F = random_order(F); + else { + F = toggle ? sort_reduce(F) : mini_sort(F, descend); + toggle = ! toggle; + } + + *Fold = sf_save(F); + + inactive = FALSE; + /* Try to reduce each cube */ + FD = cube2list(F, D); + foreachi_set(F, index, p) { + cunder = nc_reduce_cube(FD, p); /* reduce the cube */ + if (setp_equal(cunder, p)) { /* see if it actually did */ + SET(p, ACTIVE); /* cube remains active */ + SET(p, PRIME); /* cube remains prime ? */ + } else { + if (debug & REDUCE) { + (void) printf("REDUCE: %s to %s %s\n", + pc1(p), pc2(cunder), print_time(ptime())); + } + (void) set_copy(p, cunder); /* save reduced version */ + RESET(p, PRIME); /* cube is no longer prime */ + if (setp_empty(cunder)) { + RESET(p, ACTIVE); /* if null, kill the cube */ + inactive = TRUE; + } + else + SET(p, ACTIVE); /* cube is active */ + } + free_cube(cunder); + } + free_cubelist(FD); + + if (inactive) { + + /* Copy the flags from cubes in F to those in Fold */ + foreachi_set(F, index, p) { + if TESTP(p, ACTIVE) + SET(GETSET((*Fold), index), ACTIVE); + else + RESET(GETSET((*Fold), index), ACTIVE); + } + + /* Delete any cubes of F which reduced to the empty cube */ + F = sf_inactive(F); + + /* Also delete old cubes corresponding to the deleted cubes from F */ + *Fold = sf_inactive(*Fold); + + } + + return F; + +} + +/* + * Similar to random_order except that it changes the order of cubes in + * Fold so that the ith cube in Fold is the ith cube in F before reduce. + */ + +pcover +nc_random_order(F, Fold) +register pcover F, Fold; +{ + pset temp; + register int i, k; +#ifdef RANDOM + long random(); +#endif + + temp = set_new(F->sf_size); + for(i = F->count - 1; i > 0; i--) { + /* Choose a random number between 0 and i */ +#ifdef RANDOM + k = random() % i; +#else + /* this is not meant to be really used; just provides an easy + "out" if random() and srandom() aren't around + */ + k = (i*23 + 997) % i; +#endif + /* swap sets i and k in F */ + (void) set_copy(temp, GETSET(F, k)); + (void) set_copy(GETSET(F, k), GETSET(F, i)); + (void) set_copy(GETSET(F, i), temp); + + /* swap sets i and k in Fold */ + (void) set_copy(temp, GETSET(Fold, k)); + (void) set_copy(GETSET(Fold, k), GETSET(Fold, i)); + (void) set_copy(GETSET(Fold, i), temp); + } + set_free(temp); + return F; +} + +/* + * The cubes in F1 are permuted in T1 (e.g the first cube in F1 may + * be in T1[5]). This subroutine returns a cover G that has the cubes + * of F2 permuted in the same way as the cubes of F1 are in T1. + */ + +pcover +nc_permute(F1, T1, F2) +pcover F1; +pcube *T1; +pcover F2; + +{ + + pcover G; + pcube *T; + int count, diff, i; + + count = F1->count; + T = ALLOC(pcube, count+1); + diff = (F2->data) - (F1->data); + + for (i=0; i<count; i++) + T[i] = T1[i] + diff; + T[count] = (pcube) NULL; + + G = sf_unlist(T, count, cube.size); + sf_free(F2); + + return(G); + +} + +/* + * nc_mini_sort -- sort cubes according to the heuristics of mini + * Put cube in G in the same order as the new order for the cubes + * in F. + */ +pcover +nc_mini_sort(F, G, compare) +pcover F; +pcover *G; +int (*compare)(); +{ + register int *count, cnt, n = cube.size, i; + register pcube p, last; + pcover F_sorted; + pcube *F1; + + /* Perform a column sum over the set family */ + count = sf_count(F); + + /* weight is "inner product of the cube and the column sums" */ + foreach_set(F, last, p) { + cnt = 0; + for(i = 0; i < n; i++) + if (is_in_set(p, i)) + cnt += count[i]; + PUTSIZE(p, cnt); + } + FREE(count); + + /* use qsort to sort the array */ + qsort((char *) (F1 = sf_list(F)), F->count, sizeof(pcube), compare); + *G = nc_permute(F, F1, *G); + F_sorted = sf_unlist(F1, F->count, F->sf_size); + free_cover(F); + + return F_sorted; +} + +/* + * nc_reduce_cube -- find the maximal reduction of a cube + */ + +pcube +nc_reduce_cube(FD, p) +IN pcube *FD, p; + +{ + pcube cunder; + + cunder = nc_sccc(cofactor(FD, p), 1); + return set_and(cunder, cunder, p); +} + + +/* nc_sccc -- find Smallest Cube Containing the Complement of a cover */ +pcube +nc_sccc(T, level) +INOUT pcube *T; /* T will be disposed of */ +IN int level; +{ + pcube r, *Tl, *Tr; + register pcube cl, cr; + register int best; + static int sccc_level = 0; + + if (debug & REDUCE1) { + debug_print(T, "SCCC", sccc_level++); + } + + if (nc_sccc_special_cases(T, &r, level) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, REDUCE1); + + Tl = scofactor(T, cl, best); + Tr = scofactor(T, cr, best); + free_cubelist(T); + + r = sccc_merge(nc_sccc(Tl, level+1), nc_sccc(Tr, level+1), cl, cr); + } + + if (debug & REDUCE1) + (void) printf("SCCC[%d]: result is %s\n", --sccc_level, pc1(r)); + return r; +} + +/* + * nc_sccc_special_cases -- check the special cases for sccc + */ + +bool +nc_sccc_special_cases(T, result, level) +INOUT pcube *T; /* will be disposed if answer is determined */ +OUT pcube *result; /* returned only if answer determined */ +IN int level; +{ + register pcube *T1, p, temp = cube.temp[1], ceil, cof = T[0]; + pcube *A, *B; + int size; + + /* empty cover => complement is universe => SCCC is universe */ + if (T[2] == NULL) { + *result = set_save(cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* row of 1's => complement is empty => SCCC is empty */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *result = new_cube(); + free_cubelist(T); + return TRUE; + } + } + + /* Throw away the unnecessary cubes */ + size = CUBELISTSIZE(T); + if ((size > 200) || ((level % N_level == 0) && size > 50)) + rem_unnec_r_cubes(T); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If cover is unate (or single cube), apply simple rules to find SCCCU */ + if (cdata.vars_unate == cdata.vars_active || T[3] == NULL) { + *result = set_save(cube.fullset); + for(T1 = T+2; (p = *T1++) != NULL; ) { + (void) sccc_cube(*result, set_or(temp, p, cof)); + } + free_cubelist(T); + return TRUE; + } + + /* Check for column of 0's (which can be easily factored( */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + *result = sccc_cube(set_save(cube.fullset), ceil); + if (setp_equal(*result, cube.fullset)) { + free_cube(ceil); + } else { + *result = sccc_merge(nc_sccc(cofactor(T,ceil), level+1), + set_save(cube.fullset), ceil, *result); + } + free_cubelist(T); + return TRUE; + } + free_cube(ceil); + + /* Single active column at this point => tautology => SCCC is empty */ + if (cdata.vars_active == 1) { + *result = new_cube(); + free_cubelist(T); + return TRUE; + } + + /* Check for components */ + if (cdata.var_zeros[cdata.best] < CUBELISTSIZE(T)/2) { + if (cubelist_partition(T, &A, &B, debug & REDUCE1) == 0) { + return MAYBE; + } else { + free_cubelist(T); + *result = nc_sccc(A, level+1); + ceil = nc_sccc(B, level+1); + (void) set_and(*result, *result, ceil); + set_free(ceil); + return TRUE; + } + } + + /* Not much we can do about it */ + return MAYBE; +} + +/* + * ncp_expand -- similar to nc_expand but uses ncp_expand1 instead of + * expand1 + */ +pcover +ncp_expand(F, Fold, nonsparse) +INOUT pcover F; +IN pcover Fold; +IN bool nonsparse; /* expand non-sparse variables only */ + +{ + register pcube last, p; + + register pcube + RAISE = nc_tmp_cube[0], + FREESET = nc_tmp_cube[1], + INIT_LOWER = nc_tmp_cube[2], + SUPER_CUBE = nc_tmp_cube[3], + OVEREXPANDED_CUBE = nc_tmp_cube[4]; + + int var, num_covered; + int index; + bool change; + + /* Order the cubes according to "chewing-away from the edges" of mini */ + if (use_random_order) { + if (Fold != (pcover) NULL) + F = nc_random_order(F, Fold); + else + F = random_order(F); + } + else { + if (Fold != (pcover) NULL) + F = nc_mini_sort(F, &Fold, ascend); + else + F = mini_sort(F, ascend); + } + + /* Setup the initial lowering set (differs only for nonsparse) */ + if (nonsparse) + for(var = 0; var < cube.num_vars; var++) + if (cube.sparse[var]) + (void) set_or(INIT_LOWER, INIT_LOWER, cube.var_mask[var]); + + /* Mark all cubes as not covered, and maybe essential */ + foreach_set(F, last, p) { + RESET(p, COVERED); + RESET(p, NONESSEN); + } + + /* Try to expand each nonprime and noncovered cube */ + foreachi_set(F, index, p) { + /* do not expand if PRIME or if covered by previous expansion */ + if (! TESTP(p, PRIME) && ! TESTP(p, COVERED)) { + + /* find the reduced offset for p */ + + ROS = get_ROS(index, F, Fold); + + /* expand the cube p, result is RAISE */ + ncp_expand1(ROS, F, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + INIT_LOWER, &num_covered, p); + + if (debug & EXPAND) + (void) printf("EXPAND: %s (covered %d)\n", pc1(p), num_covered); + + (void) set_copy(p, RAISE); + + SET(p, PRIME); + RESET(p, COVERED); /* not really necessary */ + + /* See if we generated an inessential prime */ + if (num_covered == 0 && ! setp_equal(p, OVEREXPANDED_CUBE)) { + SET(p, NONESSEN); + } + + } + } + + /* Delete any cubes of F which became covered during the expansion */ + F->active_count = 0; + change = FALSE; + foreach_set(F, last, p) { + if (TESTP(p, COVERED)) { + RESET(p, ACTIVE); + change = TRUE; + } else { + SET(p, ACTIVE); + F->active_count++; + } + } + if (change) + F = sf_inactive(F); + + if (Fold != (pcover) NULL) + sf_free(Fold); + + return F; +} + +/* + * ncp_expand1 -- Similar to expand1 except that when there are no + * more feasible cubes, it goes to mincov even if there are some + * yet uncovered cubes left in the cover. + * + */ + +void +ncp_expand1(BB, CC, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + INIT_LOWER, num_covered, c) +pcover BB; /* Blocking matrix (OFF-set) */ +pcover CC; /* Covering matrix (ON-set) */ +pcube RAISE; /* The current parts which have been raised */ +pcube FREESET; /* The current parts which are free */ +pcube OVEREXPANDED_CUBE; /* Overexpanded cube of c */ +pcube SUPER_CUBE; /* Supercube of all cubes of CC we cover */ +pcube INIT_LOWER; /* Parts to initially remove from FREESET */ +int *num_covered; /* Number of cubes of CC which are covered */ +pcube c; /* The cube to be expanded */ + +{ + + if (debug & EXPAND1) + (void) printf("\nEXPAND1: \t%s\n", pc1(c)); + + /* initialize BB and CC */ + SET(c, PRIME); /* don't try to cover ourself */ + setup_BB_CC(BB, CC); + + /* initialize count of # cubes covered, and the supercube of them */ + *num_covered = 0; + (void) set_copy(SUPER_CUBE, c); + + /* Initialize the lowering, raising and unassigned sets */ + (void) set_copy(RAISE, c); + (void) set_diff(FREESET, cube.fullset, RAISE); + + /* If some parts are forced into lowering set, remove them */ + if (! setp_empty(INIT_LOWER)) { + (void) set_diff(FREESET, FREESET, INIT_LOWER); + elim_lowering(BB, CC, RAISE, FREESET); + } + + /* Determine what can be raised, and return the over-expanded cube */ + essen_parts(BB, CC, RAISE, FREESET); + (void) set_or(OVEREXPANDED_CUBE, RAISE, FREESET); + + /* While there are still cubes which can be covered, cover them ! */ + if (CC->active_count > 0) { + select_feasible(BB, CC, RAISE, FREESET, SUPER_CUBE, num_covered); + } + + /* Finally, when all else fails, choose the largest possible prime */ + /* We will loop only if we decide unravelling OFF-set is too expensive */ + while (BB->active_count > 0) { + mincov(BB, RAISE, FREESET); + } + + /* Raise any remaining free coordinates */ + (void) set_or(RAISE, RAISE, FREESET); +} + +/* + * nc_first_expand -- expand each nonprime cube of F into a prime implicant + * + * This subroutine differs from expand in that it is not passed on + * the global off set. For each cube to be expanded, this subroutine + * computes a subset of off set which is sufficient for the expansion + * of the cube. + * + * The subset produced is very small is limited by the number of + * literal in the cube to be expanded. This is an attempt to handle + * functions with very large off sets. + * + * If nonsparse is true, only the non-sparse variables will be expanded; + * this is done by forcing all of the sparse variables out of the free set. + */ + +pcover +nc_first_expand(F, nonsparse) +INOUT pcover F; +IN bool nonsparse; /* expand non-sparse variables only */ + +{ + register pcube last, p; + + register pcube + RAISE = nc_tmp_cube[0], + FREESET = nc_tmp_cube[1], + INIT_LOWER = nc_tmp_cube[2], + SUPER_CUBE = nc_tmp_cube[3], + OVEREXPANDED_CUBE = nc_tmp_cube[4], + overexpanded_cube = nc_tmp_cube[5], + init_lower = nc_tmp_cube[6]; + + pcube q, qlast; + int var, num_covered; + int index; + bool change; + + /* Order the cubes according to "chewing-away from the edges" of mini */ + if (use_random_order) + F = random_order(F); + else + F = mini_sort(F, ascend); + + /* Setup the initial lowering set (differs only for nonsparse) */ + if (nonsparse) + for(var = 0; var < cube.num_vars; var++) + if (cube.sparse[var]) + (void) set_or(INIT_LOWER, INIT_LOWER, cube.var_mask[var]); + + /* Mark all cubes as not covered, and maybe essential */ + foreach_set(F, last, p) { + RESET(p, COVERED); + RESET(p, NONESSEN); + } + + /* Try to expand each nonprime and noncovered cube */ + foreachi_set(F, index, p) { + + if (! TESTP(p, PRIME) && ! TESTP(p, COVERED)) { + + /* find the overexpanded cube of p */ + get_OC(p, overexpanded_cube, (pcube) NULL); + + /* If the overexpanded_cube is the same as p then p cannot + be expanded */ + if (setp_equal(p, overexpanded_cube)) { + foreach_set(F, qlast, q) + if (setp_implies(q, p)) + SET(q, COVERED); + SET(p, PRIME); + RESET(p, COVERED); + + continue; + } + + /* Remove from overexpanded_cube any parts in INIT_LOWER */ + if (nonsparse) { + (void) set_diff(init_lower, INIT_LOWER, p); + (void) set_diff(overexpanded_cube, overexpanded_cube, init_lower); + } + + get_ROS1(p, overexpanded_cube, root); + + /* If the blocking matrix is empty then p can be expanded to + its overexpanded cube */ + if (ROS->count == 0) { + (void) set_copy(p, overexpanded_cube); + foreach_set(F, qlast, q) + if (setp_implies(q, p)) SET(q, COVERED); + SET(p, PRIME); + RESET(p, COVERED); + + continue; + } + + (void) set_diff(init_lower, cube.fullset, overexpanded_cube); + + /* expand the cube p, result is RAISE */ + expand1(ROS, F, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + init_lower, &num_covered, p); + + if (debug & EXPAND) + (void) printf("EXPAND: %s (covered %d)\n", pc1(p), num_covered); + + (void) set_copy(p, RAISE); + + SET(p, PRIME); + RESET(p, COVERED); /* not really necessary */ + + /* See if we generated an inessential prime */ + if (num_covered == 0 && ! setp_equal(p, OVEREXPANDED_CUBE)) { + SET(p, NONESSEN); + } + + } + } + + /* Delete any cubes of F which became covered during the expansion */ + F->active_count = 0; + change = FALSE; + foreach_set(F, last, p) { + if (TESTP(p, COVERED)) { + RESET(p, ACTIVE); + change = TRUE; + } else { + SET(p, ACTIVE); + F->active_count++; + } + } + if (change) + F = sf_inactive(F); + + return F; +} + +/* + * Remove the cubes from T that wont affect the cube p being reduced. + * These are the cubes that have atleast two variables in which T is + * unate. + */ +void +rem_unnec_r_cubes(T) +pcube *T; + +{ + + pcube temp, temp1; + pcube q, *T1; + pcube *Tc, *Topen; + int i; + int temp_int, last; + + /* If the cubelist is empty or has only one cube, don't do anything */ + if ((T[2] == NULL) || (T[3] == NULL)) + return; + + temp = new_cube(); + temp1 = new_cube(); + + (void) set_copy(temp, cube.fullset); + + /* "And" all the cubes together. */ + for (T1=T+2; (q = *T1++) != NULL;) + (void) set_and(temp, temp, q); + + (void) set_or(temp, temp, T[0]); + + /* Find the non-unate and inactive binary variables. Set their values + to all 1s in temp1. Set the unate binary variables to their complements. + Set all mvs to all 1s */ + + last = cube.last_word[cube.num_binary_vars-1]; + for (i=1; i<=last; i++) { + temp_int = (temp[i] & (temp[i] >> 1)) | (~temp[i] & ((~temp[i]) >> 1)); + temp_int &= DISJOINT; + temp1[i] = ~temp[i] | temp_int | (temp_int << 1); + } + (void) set_and(temp1, temp1, cube.fullset); /* Some problem with set_ord if I + don't do this */ + (void) set_or(temp1, temp1, cube.mv_mask); + + /* If temp1 has less than two zeros then no cubes will be removed so + we might as well leave. */ + if (cube.size - set_ord(temp1) < 2) { + free_cube(temp); + free_cube(temp1); + return; + } + + /* Remove each cube q from the cubelist which has more than two + unate variables in it. All such cubes are distance two or more + from temp1 */ + + for (Tc=T+2; (q = *Tc++) != NULL;) { + if (cdist01(temp1, q) >= 2) + break; + } + + /* If there is no such cube in the cube list, return */ + if (q == NULL) { + free_cube(temp); + free_cube(temp1); + return; + } + + Topen = Tc - 1; + + while ((q = *Tc++) != NULL) { + if (cdist01(temp1, q) < 2) + *Topen++ = q; + } + + *Topen++ = (pcube) NULL; + T[1] = (pcube) Topen; + + free_cube(temp); + free_cube(temp1); + +} diff --git a/sis/minimize/minimize.doc b/sis/minimize/minimize.doc new file mode 100644 index 0000000..e127a4d --- /dev/null +++ b/sis/minimize/minimize.doc @@ -0,0 +1,46 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/minimize/minimize.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +Summary: + +#define 0 NOCOMP +#define 1 SNOCOMP +#defin 2 DCSIMPLIFY + +pcover +minimize(F, D, type) +pcover F; +pcover D; +int type; + +F is the Onset. D is the Don't Care set. type is used to choose one +of the three minimization schemes discussed below. It is an error for +type to have a value other than those corresponding to NOCOMP, SNOCOMP +and DCSIMPLIFY. + +NOCOMP: + Similar to espresso() except that it uses the reduced offsets + rather than the entire offset. With this option, minimize() + iterates like espresso(). Global variables "single_expand", + "trace", "remove_essential", "debug" and "use_super_gasp" have + the same effect as in espresso(). The default values for these + variables are the same as for espresso(). These global + variables are defined in espresso.h. + +SNOCOMP: + A special single pass is done that consists of ESPRESSO's + routines essential(), reduce(), expand() and irredundant(). + expand() has been modified to use the reduced offsets rather + than the entire offset. + +DCSIMPLIFY: + This is also a single pass algorithm consisting of the same + basic operations as for SNOCOMP but heuristics in reduce() and + expand() are different from those used in espresso(). This + option also uses reduced offsets. diff --git a/sis/minimize/minimize.h b/sis/minimize/minimize.h new file mode 100644 index 0000000..7729955 --- /dev/null +++ b/sis/minimize/minimize.h @@ -0,0 +1,20 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/minimize/minimize.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#define NOCOMP 0 +#define SNOCOMP 1 +#define DCSIMPLIFY 2 + +#ifndef MINIMIZE_H +#define MINIMIZE_H + +EXTERN pcover minimize ARGS((pcover, pcover, int)); + +#endif + diff --git a/sis/minimize/ros.c b/sis/minimize/ros.c new file mode 100644 index 0000000..c130ca4 --- /dev/null +++ b/sis/minimize/ros.c @@ -0,0 +1,2132 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/minimize/ros.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +/****************************************************************************** + * This module has been written by Abdul A. Malik * + * Please forward all feedback, comments, bugs etc to: * + * * + * ABDUL A. MALIK * + * malik@ic.berkeley.edu * + * * + * Department of Electrical Engineering and Computer Sciences * + * University of California at Berkeley * + * Berkeley, CA 94704. * + * * + * Telephone: (415) 642-5048 * + ******************************************************************************/ + +/* + * This file contains routines to find the overexpanded cube and blocking + * matrix (reduced offset) in the dynamic mode. The dynamic mode is + * characterized by the fact that the unate tree subtree is not stored + * for the cofactor passed to one of these routines. To get to unate cofactors + * of the subtree, all the necessary cofactors will have to be evaluated. + */ + +#include "espresso.h" +#define extern +#include "ros.h" +#undef extern + +static bool is_taut; +static bool d1_active; + +/* + * Get the blocking matrix (Reduced Off Set) for p. + */ + +void +get_ROS1(p, overexpanded_cube, pNode) +pcube p, overexpanded_cube; +pnc_node pNode; + +{ + pcover BB; + long t; + pcube temp; + + if (trace) + t = ptime(); + + temp = new_cube(); + (void) set_or(temp, p, cube.mv_mask); + Num_act_vars = cube.size - set_ord(temp); + Num_act_vars += cube.num_vars - cube.num_binary_vars; + + BB = setupBB(p, overexpanded_cube, pNode, 1); + ROS = sf_contain(BB); + free_cube(temp); + + if (trace) { + Max_ROS_size = MAX(Max_ROS_size, ROS->count); + ROS_count++; + ROS_time += ptime() - t; + } +} + +/* + * Get reduced offset for the ith cube in F, combine it with as many other + * cubes as possible. + */ + +pcover +get_ROS(i, F, Fold) +int i; +pcover F, Fold; + +{ + + int max_ones, last, j; + pcube old_cube, overexpanded_cube; + + if (find_correct_ROS(GETSET(F, i))) { + return (ROS); + } + + ROS_cube = new_cube(); + old_cube = new_cube(); + overexpanded_cube = new_cube(); + + max_ones = cube.size - ROS_zeros; + last = F->count - 1; + + if (Fold == (pcover) NULL) + Fold = F; + + /* Form the ROS_cube by multiplying all the cubes in F beginning with + ith cube until ROS_cube has more ones then max_ones. Form the super- + cube of the corresponding old cubes in old_cube */ + (void) set_copy(ROS_cube, GETSET(F, i)); + (void) set_copy(old_cube, GETSET(Fold, i)); + for(j=i+1; j<=last; j++) { + if (set_ord(ROS_cube) > max_ones) { + (void) set_and(ROS_cube, ROS_cube, GETSET(F, j)); + (void) set_or(old_cube, old_cube, GETSET(Fold, j)); + } else { + break; + } + } + + /* The overexpanded cube of ROS_cube must contain the old_cube; + therefore, if old_cube is fullset so is overexpanded_cube. If + overexpanded_cube equals GETSET(F,i) or GETSET(Fold, i) then + the overexpanded_cube is itself a prime and ROS is simply + complement of overexpanded_cube */ + + if (!setp_equal(old_cube, cube.fullset)) { + get_OC(ROS_cube, overexpanded_cube, old_cube); + if (setp_equal(overexpanded_cube, GETSET(F, i)) + || (setp_equal(overexpanded_cube, GETSET(Fold, i)))) { + ROS = nc_compl_cube(overexpanded_cube); + store_ROS(); + return(ROS); + } + } else { + (void) set_copy(overexpanded_cube, cube.fullset); + } + + get_ROS1(ROS_cube, overexpanded_cube, root); + + if (!setp_equal(overexpanded_cube, cube.fullset)) + ROS = sf_append(ROS, nc_compl_cube(overexpanded_cube)); + + store_ROS(); + + free_cube(old_cube); + free_cube(overexpanded_cube); + + return(ROS); + +} + +/* + * Initialize parameters used by ROS related subroutines. + * Most of these variables are declared in minimize.h + */ + +void +init_ROS(F, D, maxLevel, nLevel, rosZeros) +pcover F; +pcover D; +int maxLevel; +int nLevel; +int rosZeros; + +{ + + pcube *T; + long t; + + ROS = (pcover) NULL;/* Reduced Offset itself */ + ROS_count = 0; /* Number of computations of ROS */ + ROS_time = 0; /* Aggregate time for computation of ROS */ + + ROS_cube = cube.fullset; + /* Cube for which current ROS was computed */ + + Max_ROS_size = 0; /* Maximum size of ROS computed at any time */ + + ROS_zeros = rosZeros; + /* Maximum number of zeros allowed in ROS_cube. + This controls the maximum size of ROS returned. */ + + ROS_max_store = 2 * (F->count); + /* Don't store more than ROS_max_store ROSs */ + + if (F->count != 0) + ROS_max_size_store = (int) (ROS_MEM_SIZE/ROS_max_store); + /* Don't store any ROS that has size more than this */ + + N_ROS = 0; /* Number of ROSs stored so far */ + + /* Allocate memory to ROS_array */ + ROS_array = ALLOC(ros_holder_t, ROS_max_store); + + /* Initialize variables to collect statistics about OC */ + OC_count = 0; + OC_time = 0; + + /* Assigne memory to temporary cubes. */ + nc_setup_tmp_cubes(33); + + /* Generate unate cofactors of T = (F U D) to use latter for computing + reduced off sets */ + Tree_cover = sf_save(F); + Tree_cover = sf_append(Tree_cover, sf_save(D)); + T = cube1list(Tree_cover); + + /* Max_level is the maximum depth of the static cofactoring tree. + N_level is the number of levels after which some special filtering is + done. */ + Max_level = maxLevel; + N_level = nLevel; + + /* Generate the cofactoring tree */ + root = ALLOC(nc_node_t, 1); + if (trace) { + t = ptime(); + } + + nc_generate_cof_tree(root, T, 1); + + if (trace) { + t = ptime() - t; + (void) printf("# COFACTOR TREE\tTime was %s, level=%d\n", + print_time(t), maxLevel); + } + +} + +/* + * find_correct_ROS -- Find a ROS that is usable to expand p. + * If such a ROS is found, set ROS to it and ROS_cube to its cube. + * return TRUE, otherwise return FALSE. + */ + +bool +find_correct_ROS(p) +pcube p; + +{ + + int i; + pros_holder pros_h; + + /* Check to see if the current ROS is usable. If so don't + have to do anything */ + if (setp_implies(ROS_cube, p)) + return(TRUE); + + for (i=0; i<N_ROS; i++) { + pros_h = ROS_array+i; + if (setp_implies(pros_h->ros_cube, p)) { + ROS = pros_h->ros; + ROS_cube = pros_h->ros_cube; + (pros_h->count)++; + return (TRUE); + } + } + + return(FALSE); + +} + +/* + * store_ROS -- store current ROS in ROS_array. + */ + +void +store_ROS() + +{ + + pros_holder pros_h; + int count, min, i; + + /* If the size of ROS is larger than the maximum size allowed for + storage then don't store */ + if (ROS->count > ROS_max_size_store) + return; + + if (N_ROS < ROS_max_store) { + pros_h = ROS_array + N_ROS; + N_ROS++; + } else { /* Find a ros with the least count */ + min = 0; + count = ROS_array[0].count; + for (i=1; i<N_ROS; i++) { + if (ROS_array[i].count < count) { + min = i; + count = ROS_array[i].count; + } + } + pros_h = ROS_array + min; + sf_free(pros_h->ros); + free_cube(pros_h->ros_cube); + } + + pros_h->ros = ROS; + pros_h->ros_cube = ROS_cube; + pros_h->count = 1; + +} + +/* + * Free all the stuff in ROS_array. + */ + +void +close_ROS() + +{ + + int i; + pros_holder pros_h; + + /* Print stat about ROS and OC in this run */ + if (trace) { + (void) printf("# OVEREXPANDED CUBES\tTime was %s, count=%d\n", + print_time(OC_time), OC_count); + (void) printf("# REDUCED OFFSETS\tTime was %s, count=%d, maximum size=%d\n", + print_time(ROS_time), ROS_count, Max_ROS_size); + } + + /* Free the memory used in the unate tree */ + nc_free_unate_tree(root); + sf_free(Tree_cover); + + /* Free temporary cubes */ + nc_free_tmp_cubes(33); + + /* First free all ros and ros_cubes in the array */ + for (i=0; i<N_ROS; i++) { + pros_h = ROS_array + i; + sf_free(pros_h->ros); + free_cube(pros_h->ros_cube); + } + + /* Finally free the array */ + FREE(ROS_array); + +} + +/* + * Find the overexpanded cube of cube p. + * + * This subroutine is used when the entire unate tree is stored + * rather than only the leafs. + */ + +void +find_overexpanded_cube_dyn(p, overexpanded_cube, T, dist_cube, dist, var, level) +pcube p; /* Node to be expanded */ +pcube overexpanded_cube; /* overexpanded cube so far */ +pcube *T; /* The current cubelist */ +pcube dist_cube; /* Node where distance changed from 0 to 1 */ +int dist; /* Distance so far between cofactoring cube and p */ +int var; /* Conflicting variable */ +int level; /* Level in the unate tree */ + +{ + pcube cl, cr; + pcube *Tl, *Tr; + int best; + + if (find_oc_dyn_special_cases(p, overexpanded_cube, T, + dist_cube, dist, var, level)) { + return; + } + else { + + cl = new_cube(); + cr = new_cube(); + + best = binate_split_select(T, cl, cr, COMPL); + + if (best < cube.num_binary_vars) { + nc_bin_cof(T, &Tl, &Tr, cl, cr, best); + } + + else { + Tl = scofactor(T, cl, best); + nc_cof_contain(Tl); + Tr = scofactor(T, cr, best); + nc_cof_contain(Tr); + } + + if (dist == 0) { + + /* Process the left subtree */ + if (cdist0v(cl, p, best)) + find_overexpanded_cube_dyn(p, overexpanded_cube, + Tl, (pcube)NULL, 0, 0, level+1); + else if (cdist0v(cl, overexpanded_cube, best)) { + d1_active = TRUE; + find_overexpanded_cube_dyn(p, overexpanded_cube, + Tl, cr, 1, best, level+1); + } + + /* Process the right subtree */ + if (cdist0v(cr, p, best)) + find_overexpanded_cube_dyn(p, overexpanded_cube, + Tr, (pcube)NULL, 0, 0, level+1); + else if (cdist0v(cr, overexpanded_cube, best)) { + d1_active = TRUE; + find_overexpanded_cube_dyn(p, overexpanded_cube, + Tr, cl, 1, best, level+1); + } + + } + + else { /* dist == 1 */ + + if (var == best) { /* Split is on the conflicting variable */ + find_overexpanded_cube_dyn(p, overexpanded_cube, + Tl, dist_cube, 1, var, level+1); + find_overexpanded_cube_dyn(p, overexpanded_cube, + Tr, dist_cube, 1, var, level+1); + } + + else { + if (cdist0v(cl, p, best)) + find_overexpanded_cube_dyn(p, overexpanded_cube, + Tl, dist_cube, 1, var, level+1); + if (cdist0v(cr, p, best) && (d1_active)) + find_overexpanded_cube_dyn(p, overexpanded_cube, + Tr, dist_cube, 1, var, level+1); + } + } + + /* Free left and right cubelists and partition cubes */ + free_cubelist(Tl); + free_cubelist(Tr); + free_cube(cl); + free_cube(cr); + + } + +} + +/* + * Special cases for finding overexpanded cube. + */ +bool +find_oc_dyn_special_cases(p, overexpanded_cube, T, dist_cube, dist, var, level) +pcube p; /* Node to be expanded */ +pcube overexpanded_cube;/* overexpanded cube so far */ +pcube T[]; /* The current cubelist */ +pcube dist_cube; /* Node where distance changed from 0 to 1 */ +int dist; /* Distance so far between cofactoring cube and p */ +int var; /* Conflicting variable */ +int level; /* Level in the unate tree */ + +{ + pcube temp; + int k, last_word; + pcube mask; + + if (dist == 0) { + + /* If all the variables in T are either already lowered in + the overexpanded cube or not present in p then there is no + point in processing any cofactors of T */ + + temp = set_diff(new_cube(), overexpanded_cube, T[0]); + if (setp_implies(temp, p)) { + free_cube(temp); + return(TRUE); + } + free_cube(temp); + + } + + /* Remove unnecessary cubes from the cofactor. These are the cubes + that don't contain p in their unate variables. */ + + if (!(level % N_level)) { + nc_rem_unnec_cubes(p, T); + } + + /* Avoid massive count if there is no cube or only one cube in the cover */ + if ((T[2] == NULL) || (T[3] == NULL)) + cdata.vars_unate = cdata.vars_active = 1; + + else massive_count(T); + + /* Check for unate cover */ + if (cdata.vars_active == cdata.vars_unate) { /* T is unate */ + + temp = new_cube(); + + if (dist == 0) { + nc_or_unnec(p, T, temp); + (void) set_and(overexpanded_cube, overexpanded_cube, temp); + } + + else { /* dist == 1 */ + + if (var < cube.num_binary_vars) { + /* Conflicting variable is binary variable */ + if (!nc_is_nec(p, T)) { + d1_active = FALSE; + (void) set_and(overexpanded_cube, overexpanded_cube, dist_cube); + } + } + + else { + /* Conflicting variable is an mv. + Lower essential parts in overexpanded cube */ + nc_or_unnec(p, T, temp); + last_word = cube.last_word[var]; + mask = cube.var_mask[var]; + for (k=cube.first_word[var]; k<=last_word; k++) + overexpanded_cube[k] &= temp[k] | ~mask[k]; + } + + } + + free_cube(temp); + + return(TRUE); + + } + + return(FALSE); + +} + +/* + * Generate the blocking matrix for cube p. + * + * This routine is similar to setupBB except that it is + * used when blocking matrix is comupted dynamically for a subtree. + * + */ + +pcover +setupBB_dyn(p, overexpanded_cube, T, level) +pcube p; +pcube overexpanded_cube; +pcube *T; +int level; + +{ + + pcover BBl, BBr; + pcube temp; + pcube cl, cr; + pcube *Tl, *Tr, *Temp; + int best; + bool was_taut; + + + if (BB_dyn_special_cases(&BBl, p, overexpanded_cube, T, level)) { + return(BBl); + } + else { + + cl = new_cube(); + cr = new_cube(); + + best = binate_split_select(T, cl, cr, COMPL); + + if (best < cube.num_binary_vars) { + + nc_bin_cof(T, &Tl, &Tr, cl, cr, best); + free_cubelist(T); + + if (GETINPUT(p, best) == 0) { + BBl = setupBB_dyn(p, overexpanded_cube, Tl, level+1); + + /* Use was_taut to temporarily hold is_taut */ + was_taut = is_taut; + BBr = setupBB_dyn(p, overexpanded_cube, Tr, level+1); + + if (was_taut && is_taut) { + sf_free(BBr); + } else { + nc_sf_multiply(BBl, cl, best); + nc_sf_multiply(BBr, cr, best); + BBl = sf_append(BBl, BBr); + is_taut = FALSE; + } + + free_cube(cl); + free_cube(cr); + is_taut = FALSE; + return(BBl); + + } + + /* Swap left and right sides if cl is not dist0 from p. + Since both left and right cannot be dist1 from p, + cl must be dist0 from p after swapping */ + + if (!cdist0bv(p, cl, best)) { + temp = cl; + cl = cr; + cr = temp; + + Temp = Tl; + Tl = Tr; + Tr = Temp; + } + + BBl = setupBB_dyn(p, overexpanded_cube, Tl, level+1); + free_cube(cl); + + /* If BBl is a tautology, no need to evaluate BBr */ + if (is_taut) { + free_cubelist(Tr); + free_cube(cr); + return(BBl); + } + + BBr = setupBB_dyn(p, overexpanded_cube, Tr, level+1); + + if (cdist0bv(p, cr, best)) { + if (is_taut) { + sf_free(BBl); + free_cube(cr); + return(BBr); + } + else { + BBl = sf_append(BBl, BBr); + free_cube(cr); + return(BBl); + } + } else if (BBr->count == 0) { + sf_free(BBr); + free_cube(cr); + return(BBl); + } else { + is_taut = FALSE; + nc_sf_multiply(BBr, cr, best); + BBl = sf_append(BBl, BBr); + free_cube(cr); + return(BBl); + } + } + + else { /* Splitting variable is multivalued */ + + Tl = scofactor(T, cl, best); + nc_cof_contain(Tl); + Tr = scofactor(T, cr, best); + nc_cof_contain(Tr); + + free_cubelist(T); + + BBl = setupBB_dyn(p, overexpanded_cube, Tl, level+1); + if (cdist0v(p, cl, best)) { + free_cube(cl); + if (is_taut) { + free_cube(cr); + return(BBl); + } + } + else if (BBl->count != 0) { + nc_sf_multiply(BBl, cl, best); + free_cube(cl); + } + + BBr = setupBB_dyn(p, overexpanded_cube, Tr, level+1); + if (cdist0v(p, cr, best)) { + free_cube(cr); + if (is_taut) { + sf_free(BBl); + return(BBr); + } + else { + BBl = sf_append(BBl, BBr); + return(BBl); + } + } else if (BBr->count == 0) { + sf_free(BBr); + free_cube(cr); + return(BBl); + } else { + is_taut = FALSE; + nc_sf_multiply(BBr, cr, best); + free_cube(cr); + BBl = sf_append(BBl, BBr); + return(BBl); + } + } + + } + +} + +/* + * Special cases for setting up blocking matrix (reduced offset) + * This routine uses global variable Num_act_vars declared in + * minimize.h + */ +bool +BB_dyn_special_cases(BB, p, overexpanded_cube, T, level) +pcover *BB; +pcube p; +pcube overexpanded_cube; +pcube *T; +int level; + +{ + + pcube temp; + + if (!(level%N_level)) { + + /* If the cofactoring cube is contained in p, the cofactor + is a tautology. In this case return an empty cover. */ + if (level > Num_act_vars) { + temp = set_diff(new_cube(), cube.fullset, T[0]); + if (setp_implies(temp, p)) { + free_cube(temp); + is_taut = FALSE; + *BB = new_cover(0); + free_cubelist(T); + return(TRUE); + } + + free_cube(temp); + } + + /* Remove unnecessary cubes from the cofactor */ + nc_rem_unnec_cubes(p, T); + } + + /* Avoid massive count if there is no cube or only one cube in the cover */ + if ((T[2] == NULL) || (T[3] == NULL)) + cdata.vars_unate = cdata.vars_active = 1; + else + massive_count(T); + + /* Check for unate cover */ + if (cdata.vars_unate == cdata.vars_active) { /* T is unate */ + + /* Remove those cubes from the cover that don't contain p */ + nc_rem_noncov_cubes(p, T); + + if (T[2] == (pcube) NULL) { /* Empty cubelist. Compl is tautology */ + is_taut = TRUE; + *BB = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return(TRUE); + } + + else { + is_taut = FALSE; + } + + temp = new_cube(); + (void) set_or(T[0], T[0], set_diff(temp, cube.fullset, overexpanded_cube)); + + nc_compl_special_cases(T, BB); + + free_cube(temp); + return(TRUE); + + } + + /* Try to partition T */ + if (level % N_level) + if (partition_ROS(p, overexpanded_cube, level, T, BB)) + return(TRUE); + + return(FALSE); + +} + +/* + * Find the overexpanded cube of cube p. + * + * This subroutine is used when the entire unate tree is stored + * rather than only the leafs. + */ + +void +find_overexpanded_cube(p, overexpanded_cube, pNode, dist_cube, dist, var, level) +pcube p; /* Node to be expanded */ +pcube overexpanded_cube;/* overexpanded cube so far */ +pnc_node pNode; /* The current node */ +pcube dist_cube; /* Node where distance changed from 0 to 1 */ +int dist; /* Distance so far between cofactoring cube and p */ +int var; /* Conflicting variable */ +int level; /* Level from the root of the tree */ + +{ + int k; + + if (find_oc_special_cases(p, overexpanded_cube, pNode, dist_cube, + dist, var, level)) { + return; + } + + else { + + if (dist == 0) { + for (k=0; k<=1; k++) { + + if (cdist0v(pNode->part_cube[k], p, pNode->var)) + find_overexpanded_cube(p, overexpanded_cube, + pNode->child[k], (pcube)NULL, 0, 0, level+1); + + else if (cdist0v(pNode->part_cube[k], overexpanded_cube, + pNode->var)) { + d1_active = TRUE; + find_overexpanded_cube(p, overexpanded_cube, + pNode->child[k], pNode->part_cube[1-k], + 1, pNode->var, level+1); + } + } + } + + else { /* dist == 1 */ + + if (var == pNode->var) { /* Split is on the conflicting variable */ + find_overexpanded_cube(p, overexpanded_cube, + pNode->child[LEFT], dist_cube, 1, var, level+1); + find_overexpanded_cube(p, overexpanded_cube, + pNode->child[RIGHT], dist_cube, 1, var, level+1); + } + else { /* Splitting variable is not the same as conflicting var */ + if (cdist0v(pNode->part_cube[LEFT], p, pNode->var)) + find_overexpanded_cube(p, overexpanded_cube, + pNode->child[LEFT], dist_cube, 1, var, level+1); + + if ((cdist0v(pNode->part_cube[RIGHT], p, pNode->var)) + && (d1_active)) + find_overexpanded_cube(p, overexpanded_cube, + pNode->child[RIGHT], dist_cube, 1, var, level+1); + } + } + } +} + +/* + * Special cases for finding overexpanded cube. + */ +bool +find_oc_special_cases(p, overexpanded_cube, pNode, dist_cube, dist, var, level) +pcube p; /* Node to be expanded */ +pcube overexpanded_cube;/* overexpanded cube so far */ +pnc_node pNode; /* The current node */ +pcube dist_cube; /* Node where distance changed from 0 to 1 */ +int dist; /* Distance so far between cofactoring cube and p */ +int var; /* Conflicting variable */ +int level; /* Level from the root of the tree */ + +{ + + pcube temp; + pcube *T_d; + pcube mask; + int last_word, k; + + /* If all the literals present in p are either in overexpanded cube + already or have been cofactored out, there is no need to continue */ + if (dist == 0) { + temp = set_diff(new_cube(), overexpanded_cube, pNode->cof); + if (setp_implies(temp, p)) { + free_cube(temp); + return(TRUE); + } + free_cube(temp); + } + + if (pNode->cubelist != NULL) { + if (level < Max_level) { /* A unate leaf has been reached */ + + temp = new_cube(); + + if (dist == 0) { + nc_or_unnec(p, pNode->cubelist, temp); + (void) set_and(overexpanded_cube, overexpanded_cube, temp); + } + + else { /* dist == 1 */ + if (var < cube.num_binary_vars) { + /* Conflicting variable is binary */ + + if (!nc_is_nec(p, pNode->cubelist)) { + (void) set_and(overexpanded_cube, + overexpanded_cube, dist_cube); + d1_active = FALSE; + } + } + + else { + /* Conflicting variable is an mv. + Lower essential parts in overexpanded cube */ + + nc_or_unnec(p, pNode->cubelist, temp); + last_word = cube.last_word[var]; + mask = cube.var_mask[var]; + for (k=cube.first_word[var]; k<=last_word; k++) + overexpanded_cube[k] &= temp[k] | ~mask[k]; + + } + + } + + free_cube(temp); + + return(TRUE); + + } + + else { + + /* The leaf is not necessarily unate. Switch to dynamic mode. */ + + /* Copy the cubelist because it will be disposed of by + find_overexpanded_cube_dyn. */ + + temp = set_diff(new_cube(), cube.fullset, pNode->cubelist[0]); + if (setp_implies(temp, overexpanded_cube)) + T_d = nc_copy_cubelist(pNode->cubelist); + else { + T_d = cofactor(pNode->cubelist, overexpanded_cube); + nc_cof_contain(T_d); + } + free_cube(temp); + + if (dist == 0) + find_overexpanded_cube_dyn(p, overexpanded_cube, T_d, + (pcube)NULL, 0, 0, level+1); + else + find_overexpanded_cube_dyn(p, overexpanded_cube, T_d, + dist_cube, 1, var, level+1); + + free_cubelist(T_d); + return(TRUE); + + } + } + + return(FALSE); +} + +/* + * Generate the blocking matrix for cube p. + * + * Compute the Blocking Matrix (reduced offset) recursively. + */ + +pcover +setupBB(p, overexpanded_cube, pNode, level) +pcube p; +pcube overexpanded_cube; +pnc_node pNode; +int level; + +{ + + pset_family BBl, BBr; + pcube cl, cr; + int var; + + if (BB_special_cases(&BBl, p, overexpanded_cube, pNode, level)) { + return(BBl); + } + + else { /* Not quite at a leaf yet */ + + cl = pNode->part_cube[LEFT]; + cr = pNode->part_cube[RIGHT]; + var = pNode->var; + + /* Only those subtrees need to be considered that are not orthogonal + to the overexpanded_cube */ + + if (cdist0v(overexpanded_cube, cl, var)) { + + BBl = setupBB(p, overexpanded_cube, pNode->child[LEFT], level+1); + + if (cdist0v(p, cl, var)) { + if (is_taut) return(BBl); + } + else { + nc_sf_multiply(BBl, cl, var); + } + + if (cdist0v(overexpanded_cube, cr, var)) { + BBr = setupBB(p, overexpanded_cube, pNode->child[RIGHT], level+1); + if (cdist0v(p, cr, var)) { + if (is_taut) { + sf_free(BBl); + return(BBr); + } + else { + if (BBr->count == 0) { + sf_free(BBr); + return(BBl); + } + else { + BBl = sf_append(BBl, BBr); + return(BBl); + } + } + } + else { + if (BBr->count == 0) { + sf_free(BBr); + return(BBl); + } + else { + nc_sf_multiply(BBr, cr, var); + BBl = sf_append(BBl, BBr); + is_taut = FALSE; + return(BBl); + } + } + + } + else { + return(BBl); + } + + } + + /* Left subtree is distance 1 therefore right subtree must be + distance 0 from the overexpanded_cube */ + + else { + BBr = setupBB(p, overexpanded_cube, pNode->child[RIGHT], level+1); + if ((cdist0v(p, cr, var)) || (BBr->count == 0)) return(BBr); + + is_taut = FALSE; + nc_sf_multiply(BBr, cr, var); + return(BBr); + } + + } + +} + +/* + * Special cases for setting up blocking matrix (reduced offset) + * This routine uses global variable Num_act_vars declared in + * minimize.h + */ + +bool +BB_special_cases(BB, p, overexpanded_cube, pNode, level) +pcover *BB; +pcube p; +pcube overexpanded_cube; +pnc_node pNode; +int level; + +{ + + pcube temp; + pcube *T; + + if (!(level%N_level)) { + + /* If the cofactoring cube is contained in p, the cofactor + is a tautology. In this case return an empty cover. */ + if (level > Num_act_vars) { + temp = new_cube(); + (void) set_diff(temp, cube.fullset, pNode->cof); + if (setp_implies(temp, p)) { + free_cube(temp); + is_taut = FALSE; + *BB = new_cover(0); + return(TRUE); + } + + free_cube(temp); + } + + } + + if (pNode->cubelist != NULL) { /* A leaf */ + + /* Remove those cubes from the cover that don't contain p */ + if (level < Max_level) { /* A unate leaf */ + + T = nc_copy_cubelist(pNode->cubelist); + nc_rem_noncov_cubes(p, T); + + if (T[2] == (pcube) NULL) { /* Empty cubelist. Compl is tautology */ + is_taut = TRUE; + *BB = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return(TRUE); + } + + else { + is_taut = FALSE; + } + + temp = new_cube(); + (void) set_or(T[0], T[0], set_diff(temp, cube.fullset, overexpanded_cube)); + + nc_compl_special_cases(T, BB); + + free_cube(temp); + return(TRUE); + + } + else { /* The leaf is not necessarily unate. Switch to dynamic mode */ + + temp = set_diff(new_cube(), cube.fullset, pNode->cubelist[0]); + + /* If all variables in overexpanded_cube have been cofactored out + then cofactoring will not gain anything. The test below is + sufficient because the cofactoring cube is dist 0 from + overexpanded cube. */ + + if (setp_implies(temp, overexpanded_cube)) { + free_cube(temp); + T = nc_copy_cubelist(pNode->cubelist); + *BB = setupBB_dyn(p, overexpanded_cube, T, level+1); + } + else { + free_cube(temp); + T = cofactor(pNode->cubelist, overexpanded_cube); + *BB = setupBB_dyn(p, overexpanded_cube, T, level+1); + } + + return(TRUE); + + } + + } + + return(FALSE); + +} + +/* + * Get the overexpanded cube. + * + * This subroutine uses global variable root. + */ + +void +get_OC(p, overexpanded_cube, old_cube) +pcube p, overexpanded_cube, old_cube; + +{ + + + long t; + + if (trace) { + t = ptime(); + } + + if (old_cube == (pcube) NULL) { + (void) set_copy(overexpanded_cube, cube.fullset); + find_overexpanded_cube(p, overexpanded_cube, root, + (pcube) NULL, 0, 0, 1); + } else { + + /* Temporarily remove all the parts from overexpanded cube + present in the cube before reduce. These parts cannot + be in the overexpanded cube. They are put in the overexpanded + cube to speed up its computation */ + + (void) set_diff(overexpanded_cube, cube.fullset, old_cube); + (void) set_or(overexpanded_cube, overexpanded_cube, p); + + find_overexpanded_cube(p, overexpanded_cube, root, + (pcube) NULL, 0, 0, 1); + + /* Put back the parts into overexpanded cube that were + temporarily removed from it */ + + (void) set_or(overexpanded_cube, overexpanded_cube, old_cube); + + } + + if (trace) { + OC_time = ptime() - t; + OC_count++; + } + +} + +/* + * Partition the cubelist in two parts such that no-nonunate variables are + * shared. If such a partition exist, find reduced offset for each part + * and multiply the two reduced offsets. + */ +bool +partition_ROS(p, overexpanded_cube, level, T, R) +pcube p, overexpanded_cube; +int level; +pcube *T; +pcover *R; + +{ + + pcube temp, temp1, cof; + pcube q, *T1; + pcube *A, *B; + pcover RA, RB; + int i; + int temp_int, last; + + /* If the cubelist is empty or has only one cube, don't do anything */ + if ((T[2] == NULL) || (T[3] == NULL)) + return(FALSE); + + temp = new_cube(); + temp1 = new_cube(); + cof = new_cube(); + + (void) set_copy(temp, cube.fullset); + + /* "And" all the cubes together. */ + for (T1=T+2; (q = *T1++) != NULL;) + (void) set_and(temp, temp, q); + + (void) set_or(temp, temp, T[0]); + + /* Find the non-unate and inactive binary variables. Set their values + to all 0s in temp1. Set all mvs to all 0s */ + + last = cube.last_word[cube.num_binary_vars-1]; + for (i=1; i<=last; i++) { + temp_int = (temp[i] & (temp[i] >> 1)) | (~temp[i] & ((~temp[i]) >> 1)); + temp_int &= DISJOINT; + temp1[i] = temp[i] | temp_int | (temp_int << 1); + } + (void) set_and(temp1, temp1, cube.fullset); /* Some problem with set_ord if I + don't do this */ + (void) set_or(temp1, temp1, cube.mv_mask); + + /* Mask out the unate variables by fixing T[0]. */ + (void) set_copy(cof, T[0]); /* Save T[0] in cof */ + (void) set_or(T[0], T[0], set_diff(temp, cube.fullset, temp1)); + + /* Partition T. */ + if (!nc_cubelist_partition(T, &A, &B, FALSE)) { + (void) set_copy(T[0], cof); + free_cube(temp); + free_cube(temp1); + free_cube(cof); + return(FALSE); + } + + /* Free T */ + free_cubelist(T); + + /* Restore the cofactoring cube */ + (void) set_copy(A[0], cof); + (void) set_copy(B[0], cof); + + /* Find reduced offsets for A and B */ + RA = setupBB_dyn(p, overexpanded_cube, A, level); + + if (RA->count == 0) { /* The product of RA and RB will be Null */ + *R = RA; + free_cubelist(B); + is_taut = FALSE; + } else if (is_taut) { /* No need to multiply RA and RB */ + *R = setupBB_dyn(p, overexpanded_cube, B, level); + sf_free(RA); + } else { + RB = setupBB_dyn(p, overexpanded_cube, B, level); + /* Multiply A and B together */ + *R = multiply2_sf(RA, RB); + is_taut = FALSE; + } + + free_cube(temp); + free_cube(temp1); + free_cube(cof); + return(TRUE); + +} + +/* + * multiply2_sf -- multiply two set families. Return the result. + * Assume that no cube in one set family is orthagonal to any one in + * the other set family. + */ + +pcover +multiply2_sf(A, B) +pcover A, B; /* Disposes of A and B */ + +{ + + pcover C, R; + pcube pA, pB, lastA, lastB; + + /* If either A or B is Null, the product is Null */ + if (A->count == 0) { + sf_free(B); + return(A); + } + + if (B->count == 0) { + sf_free(A); + return(B); + } + + A = sf_contain(A); + B = sf_contain(B); + + /* If B->count is less than A->count, swap A and B */ + if (B->count < A->count) { + C = A; + A = B; + B = C; + } + + if (A->sf_size != B->sf_size) + fatal("multiply2_sf: sf_size mismatch"); + + R = sf_new(A->count * B->count, A->sf_size); + + /* Multiply them together */ + + foreach_set(A, lastA, pA) + foreach_set(B, lastB, pB) + set_and(GETSET(R, R->count++), pB, pA); + R->active_count = A->active_count * B->active_count; + + sf_free(A); + sf_free(B); + + return(R); + +} +/* + * cubelist_partition -- take a cubelist T and see if it has any components; + * if so, return cubelist's of the two partitions A and B; the return value + * is the size of the partition; if not, A and B + * are undefined and the return value is 0 + */ + +int +nc_cubelist_partition(T, A, B, comp_debug) +pcube *T; /* a list of cubes */ +pcube **A, **B; /* cubelist of partition and remainder */ +unsigned int comp_debug; +{ + register pcube *T1, p, seed, cof; + pcube *A1, *B1; + bool change; + int count, numcube; + + numcube = CUBELISTSIZE(T); + + /* Mark all cubes -- covered cubes belong to the partition */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + RESET(p, COVERED); + } + + /* Pick a seed that is not a row of all 1s */ + seed = new_cube(); + for (T1 = T+2; (p = *T1++) != NULL; ) { + (void) set_or(seed, p, T[0]); + if (!setp_equal(seed, cube.fullset)) { + (void) set_copy(seed, p); + SET(p, COVERED); + break; + } + } + + /* + * Extract a partition from the cubelist T; start with the first cube as a + * seed, and then pull in all cubes which share a variable with the seed; + * iterate until no new cubes are brought into the partition. + */ + + cof = T[0]; + count = 1; + + do { + change = FALSE; + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (! TESTP(p, COVERED) && ccommon(p, seed, cof)) { + INLINEset_and(seed, seed, p); + SET(p, COVERED); + change = TRUE; + count++; + } + + } + } while (change); + + set_free(seed); + + if (comp_debug) { + (void) printf("COMPONENT_REDUCTION: split into %d %d\n", + count, numcube - count); + } + + if (count != numcube) { + /* Allocate and setup the cubelist's for the two partitions */ + *A = A1 = ALLOC(pcube, numcube+3); + *B = B1 = ALLOC(pcube, numcube+3); + (*A)[0] = set_save(T[0]); + (*B)[0] = set_save(T[0]); + A1 = *A + 2; + B1 = *B + 2; + + /* Loop over the cubes in T and distribute to A and B */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (TESTP(p, COVERED)) { + *A1++ = p; + } else { + *B1++ = p; + } + } + + /* Stuff needed at the end of the cubelist's */ + *A1++ = NULL; + (*A)[1] = (pcube) A1; + *B1++ = NULL; + (*B)[1] = (pcube) B1; + } + + /* Mark all the cubes non-covered */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + RESET(p, COVERED); + } + + return numcube - count; +} + +/* + * This routine recursively generates unate cofactors of T. + * The cofactors are stored at the leafs. + */ + +void +nc_generate_cof_tree(pNode, T, level) +pnc_node pNode; +pcube *T; +int level; + +{ + + register pcube cl, cr; + register int best; + pcube *Tl, *Tr; + + /* If the level is not less than Max_level, store the cubelist and leave. */ + if (level == Max_level) { + pNode->cubelist = T; + pNode->cof = T[0]; + return; + } + + /* Check for empty cubelist */ + if (T[2] == NULL) { + pNode->cubelist = T; + pNode->cof = T[0]; + return; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + pNode->cubelist = T; + pNode->cof = T[0]; + return; + } + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* Check for unate cover */ + if (cdata.vars_unate == cdata.vars_active) { /* T is unate */ + pNode->cubelist = T; + pNode->cof = T[0]; + return; + } + + /* Store the cofactoring cube */ + pNode->cof = set_copy(new_cube(), T[0]); + + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + + best = binate_split_select(T, cl, cr, COMPL); + + if (best < cube.num_binary_vars) { + nc_bin_cof(T, &Tl, &Tr, cl, cr, best); + } + else { + Tl = scofactor(T, cl, best); + nc_cof_contain(Tl); + Tr = scofactor(T, cr, best); + nc_cof_contain(Tr); + } + + free_cubelist(T); + + /* Save the splitting variable */ + pNode->var = best; + + /* Allocate space for the children of *pNode */ + pNode->child[RIGHT] = ALLOC(nc_node_t, 1); + pNode->child[LEFT] = ALLOC(nc_node_t, 1); + + /* Store the partition cubes */ + pNode->part_cube[LEFT] = cl; + pNode->part_cube[RIGHT] = cr; + + /* Just to be suer that the cubelist pointer is NULL */ + pNode->cubelist = NULL; + + /* Generate cofactoring tree recursively at the children */ + nc_generate_cof_tree(pNode->child[LEFT], Tl, level+1); + nc_generate_cof_tree(pNode->child[RIGHT], Tr, level+1); + + return; + +} + +/* + * nc_compl_cube -- return the complement of a single cube (De Morgan's law) + */ +pcover +nc_compl_cube(p) +register pcube p; +{ + register pcube diff=cube.temp[7], pdest, mask, full=cube.fullset; + int var; + pcover R; + + /* Allocate worst-case size cover (to avoid checking overflow) */ + R = new_cover(cube.num_vars); + + /* Compute bit-wise complement of the cube */ + INLINEset_diff(diff, full, p); + + for(var = 0; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + /* If the bit-wise complement is not empty in var ... */ + if (! setp_disjoint(diff, mask)) { + pdest = GETSET(R, R->count++); + INLINEset_merge(pdest, diff, full, mask); + } + } + return R; +} + +/* + * Free the unate tree. + */ + +void +nc_free_unate_tree(pNode) +pnc_node pNode; + +{ + + if (pNode->cubelist == NULL) { /* Not a leaf */ + + /* Free the left and right subtrees */ + nc_free_unate_tree(pNode->child[LEFT]); + nc_free_unate_tree(pNode->child[RIGHT]); + + /* Free all the partition cubes at this node */ + free_cube(pNode->part_cube[LEFT]); + free_cube(pNode->part_cube[RIGHT]); + free_cube(pNode->cof); + + } + + else { /* A leaf of the tree */ + + /* Free the cubelist */ + free_cubelist(pNode->cubelist); + + } + + /* Free the node itself */ + FREE(pNode); + +} + +/* + * Cofactor the given cubelist T with respect to the binary + * variable var. + * + * The resulting cubelists should be minimum with respect to single + * cube containment assuming that T is minimum w.r.t single cube containment. + */ + +void +nc_bin_cof(T, Tl, Tr, cleft, cright, var) +pcube *T, **Tl, **Tr; +pcube cleft, cright; +int var; + +{ + + pcube *T1, *Tc, *Tlc, *Trc, *Tld, *Trd, *Ttmp; + pcube *Tleft, *Tright; + pcube p, mask, temp; + int size, value; + int left, right; + + mask = new_cube(); + temp = new_cube(); + + /* Set up the mask */ + (void) set_diff(mask, cube.fullset, T[0]); + set_remove(mask, 2*var); + set_remove(mask, 2*var+1); + + /* Setup Tl and Tr */ + size = CUBELISTSIZE(T) + 5; + + Tleft = *Tl = ALLOC(pcube, size); + Tright = *Tr = ALLOC(pcube, size); + + Tleft[0] = set_diff(new_cube(), cube.fullset, cleft); + (void) set_or(Tleft[0], Tleft[0], T[0]); + + Tright[0] = set_diff(new_cube(), cube.fullset, cright); + (void) set_or(Tright[0], Tright[0], T[0]); + + left = GETINPUT(cleft, var); + right = GETINPUT(cright, var); + + /* Set Tc to the location of the first cube that can not be in both lists */ + Tc = T+2; + while (((p = *Tc) != NULL) && (GETINPUT(p, var) == 3)) Tc++; + + /* Make one pass through T to remove cubes which can be in Tleft + or Tright but not in both */ + + Tlc = Tleft+2; + Trc = Tright+2; + + for (T1=Tc; (p = *T1++) != NULL;) { + value = GETINPUT(p, var); + if (value == left) *Tlc++ = p; + else if (value == right) *Trc++ = p; + else *Tc++ = p; + } + + *Tc = NULL; + T[1] = (pcube) (Tc+1); + Tld = Tlc; + Trd = Trc; + + /* Make one more pass through the remaining cubes in T to copy + them into Tleft and Tright provided they are not covered by + any cube that was moved to Tleft or Tright in the first pass */ + + for (T1 = T+2; (p = *T1++) != NULL;) { + + (void) set_and(temp, mask, p); + + for (Ttmp=Tleft+2; Ttmp<Tld; Ttmp++) + if (setp_implies(temp, *Ttmp)) goto skipl; + + *Tlc++ = p; + + skipl: + + for (Ttmp=Tright+2; Ttmp<Trd; Ttmp++) + if (setp_implies(temp, *Ttmp)) goto skipr; + + *Trc++ = p; + + skipr:; + + } + + /* Wrap up and leave */ + *Tlc++ = NULL; + *Trc++ = NULL; + Tleft[1] = (pcube) Tlc; + Tright[1] = (pcube) Trc; + free_cube(mask); + free_cube(temp); + +} + +/* + * Make cofactor T minimum w.r.t single cube containment + */ + +void +nc_cof_contain(T) +INOUT pcube *T; + +{ + + register pcube *Tc, *Topen, *Tp, c, p, temp = nc_tmp_cube[23]; + + for (Tp = T+2; (p = *Tp++) != NULL;) { + + (void) set_or(temp, p, T[0]); + + /* Find the first cube contained in temp other than p */ + for (Tc=T+2; (c = *Tc++) != NULL;) + if (setp_implies(c, temp) && (p != c)) break; + + /* No cube is contained in p so go to the next cube + in the cubelist */ + if (c == NULL) continue; + + Topen = Tc - 1; + while ((c = *Tc++) != NULL) + if ( p == c ) { + Tp = Topen; + *Topen++ = c; + } + else if (!setp_implies(c, temp)) *Topen++ = c; + + *Topen++ = (pcube) NULL; + T[1] = (pcube) Topen; + + } + +} + +/* + * Find if the cube p and q are distance zero away from each other + * in variable var. If so return some non-zero integer, otherwise, + * return zero. + */ + +bool +cdist0v(p, q, var) +pcube p, q; +int var; + +{ + + int k, last_word; + pcube mask; + + if (var < cube.num_binary_vars) + return((GETINPUT(p, var)) & (GETINPUT(q, var))); + + last_word = cube.last_word[var]; + mask = cube.var_mask[var]; + for (k = cube.first_word[var]; k <= last_word; k++) { + if (p[k] & q[k] & mask[k]) + return(TRUE); + } + + return(FALSE); + +} + +/* + * Remove the cubes from T that don't contain the cube p. p is the node + * to be expanded. All cubes in the unate leafs of the cofactors of T + * that are derived from such cubes will not contain p and will be thrown + * away if kept. Therefore, removing such cubes may decrease the paths to + * unate leafs. + */ + +void +nc_rem_unnec_cubes(p, T) +pcube p; +pcube *T; + +{ + + pcube temp, temp1; + pcube q, *T1; + pcube *Tc, *Topen; + int i, j, is_zero; + int temp_int, last; + + /* If the cubelist is empty or has only one cube, don't do anything */ + if ((T[2] == NULL) || (T[3] == NULL)) + return; + + temp = new_cube(); + temp1 = new_cube(); + + (void) set_copy(temp, cube.fullset); + + /* "And" all the cubes together. */ + for (T1=T+2; (q = *T1++) != NULL;) + (void) set_and(temp, temp, q); + + (void) set_or(temp, temp, T[0]); + + /* Find the non-unate and inactive variables. + Set their values to all 0s in temp1 */ + + /* Copy the binary part of p to temp1 */ + (void) set_and(temp1, p, cube.binary_mask); + + last = cube.last_word[cube.num_binary_vars-1]; + for (i=1; i<=last; i++) { + temp_int = (temp[i] & (temp[i] >> 1)) | (~temp[i] & ((~temp[i]) >> 1)); + temp_int &= DISJOINT; + temp1[i] &= ~(temp_int | (temp_int << 1)); + } + + temp1[last] &= cube.binary_mask[last]; + + /* insert unate parts in the unate variables */ + for (i=cube.num_binary_vars; i<cube.num_vars; i++) { + is_zero = 0; + for (j=cube.first_part[i]; j<=cube.last_part[i]; j++) { + if (!is_in_set(temp, j)) { + if (is_zero) goto next_var; + else is_zero = j+1; + } + } + if (is_zero) { + is_zero--; + if (is_in_set(p, is_zero)) + set_insert(temp1, is_zero); + } + next_var:; + } + + /* If temp1 is contained in temp then for each cube q in the cofactor, + q contains temp1. In this case no cubes will be removed */ + if (setp_implies(temp1, temp)) { + free_cube(temp); + free_cube(temp1); + return; + } + + /* Remove each cube q from the cubelist which does not contain temp1 */ + + /* Find the first cube q such that q does not contain temp1 */ + for (Tc=T+2; (q = *Tc++) != NULL;) { + if (!setp_implies(temp1, q)) + break; + } + + /* If there is no such cube in the cube list, return */ + if (q == NULL) { + free_cube(temp); + free_cube(temp1); + return; + } + + Topen = Tc - 1; + while ((q = *Tc++) != NULL) { + if (setp_implies(temp1, q)) *Topen++ = q; + } + + *Topen++ = (pcube) NULL; + T[1] = (pcube) Topen; + + free_cube(temp); + free_cube(temp1); + +} + +/* + * Form or of all the cubes that will not be removed by nc_rem_unnec + * while expanding c. + * If All the cubes in T are such that they will be droped by nc_rem_unnec + * then set orred_cube to fullset. + */ + +void +nc_or_unnec(c, T, orred_cube) +pcube c, *T, orred_cube; + +{ + + register pcube temp = nc_tmp_cube[26]; + register pcube *T1, p; + register bool empty; + + (void) set_copy(orred_cube, T[0]); + + (void) set_diff(temp, cube.fullset, T[0]); + (void) set_and(temp, temp, c); + + /* Loop for each cube in the list. Determine suitability and or */ + + empty = TRUE; + for (T1 = T+2; (p = *T1++) != NULL;) + if (setp_implies(temp, p)) { + (void) set_or(orred_cube, orred_cube, p); + empty = FALSE; + } + + if (empty) + (void) set_copy(orred_cube, cube.fullset); +} + +/* + * Find if there is a cube in T that will not be removed by nc_copy_unnec + * while expanding c. If so, return TRUE, else return FALSE. + */ + +bool +nc_is_nec(c, T) +pcube c, *T; + +{ + + register pcube *T1, p, temp = nc_tmp_cube[27]; + + (void) set_diff(temp, cube.fullset, T[0]); + (void) set_and(temp, temp, c); + + /* Loop for each cube in the list. Return TRUE if the cube qualifies */ + + for (T1 = T+2; (p = *T1++) != NULL;) + if (setp_implies(temp, p)) { + return(TRUE); + } + + return(FALSE); + +} + +/* + * Multiply a set_family by a single variable cube. + */ + +void +nc_sf_multiply(A, c, var) +pset_family A; +pcube c; +int var; + +{ + + pcube p, last, temp; + int fword, lword, i; + + temp = new_cube(); + (void) set_diff(temp, cube.fullset, cube.var_mask[var]); + (void) set_or(temp, temp, c); + + fword = cube.first_word[var]; + lword = cube.last_word[var]; + + foreach_set(A, last, p) + for (i=fword; i<= lword; i++) p[i] &= temp[i]; + + free_cube(temp); + +} + +/* + * Remove all the cubes from T that don't contain p. + */ + +void +nc_rem_noncov_cubes(p, T) +pcube p, *T; + +{ + + pcube temp, q; + pcube *Tc, *Topen; + + temp = new_cube(); + + /* Remove each cube q from the cubelist which does not contain p */ + + /* Knock out variables that have been cofactored out */ + (void) set_diff(temp, p, T[0]); + + /* Find the first cube q such that q does not contain temp */ + for (Tc=T+2; (q = *Tc++) != NULL;) { + if (!setp_implies(temp, q)) + break; + } + + /* If there is no such cube in the cube list, return */ + if (q == NULL) { + free_cube(temp); + return; + } + + /* Go through the rest of the cubelist, saving those cubes + that contain temp */ + Topen = Tc - 1; + while ((q = *Tc++) != NULL) { + if (setp_implies(temp, q)) *Topen++ = q; + } + + *Topen++ = (pcube) NULL; + T[1] = (pcube) Topen; + + free_cube(temp); + +} + +/* + * nc_compl_special_cases is to be called only when the cubelist + * T is known to have only one cube or is known to be unate. + * max_lit is the number of maximum literals allowed in any cube in + * the complement. + */ +void +nc_compl_special_cases(T, Tbar) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tbar; /* returned only if answer determined */ + +{ + register pcube *T1, p, ceil, cof=T[0]; + pcover A, ceil_compl; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tbar = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tbar = nc_compl_cube(set_or(cof, cof, T[2])); + free_cubelist(T); + return; + } + + /* Check for a row of all 1's (implies complement is null) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tbar = new_cover(0); + free_cubelist(T); + return; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + ceil_compl = nc_compl_cube(ceil); + (void) set_or(cof, cof, set_diff(ceil, cube.fullset, ceil)); + set_free(ceil); + nc_compl_special_cases(T, Tbar); + *Tbar = sf_append(*Tbar, ceil_compl); + return; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tbar = new_cover(0); + free_cubelist(T); + return; + + /* The cover is unate since all else failed */ + } else { + A = map_cover_to_unate(T); + free_cubelist(T); + A = unate_compl(A); + *Tbar = map_unate_to_cover(A); + sf_free(A); + return; + } + +} + +/* + * Copy cubelist T. Return the copy. + */ +pcube * +nc_copy_cubelist(T) +pcube *T; + +{ + + pcube *Tc, *Tc_save; + register pcube p, *T1; + int listlen; + + listlen = CUBELISTSIZE(T) + 5; + + /* Allocate a new list of cube pointers (max size is previous size) */ + Tc_save = Tc = ALLOC(pcube, listlen); + + /* pass on which variables have been cofactored against */ + *Tc++ = set_copy(new_cube(), T[0]); + Tc++; + + /* Loop for each cube in the list and save */ + for(T1 = T+2; (p = *T1++) != NULL; ) *Tc++ = p; + + *Tc++ = (pcube) NULL; /* sentinel */ + Tc_save[1] = (pcube) Tc; /* save pointer to last */ + return Tc_save; +} + +/* + * Assign memory to temporary cubes to be used in subroutines in + * this file. + */ + +void +nc_setup_tmp_cubes(num) +int num; + +{ + + int i; + + nc_tmp_cube = ALLOC(pcube, num); + + for (i=0; i<num; i++) + nc_tmp_cube[i] = new_cube(); +} + +/* + * Free memory assigned to the temporary cubes to be used in subroutines + * in this file. + */ + +void +nc_free_tmp_cubes(num) +int num; + +{ + + int i; + + for (i=0; i<num; i++) + free_cube(nc_tmp_cube[i]); + + FREE(nc_tmp_cube); +} diff --git a/sis/minimize/ros.h b/sis/minimize/ros.h new file mode 100644 index 0000000..0dc26cc --- /dev/null +++ b/sis/minimize/ros.h @@ -0,0 +1,123 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/minimize/ros.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +/****************************************************************************** + * This module has been written by Abdul A. Malik * + * Please forward all feedback, comments, bugs etc to: * + * * + * ABDUL A. MALIK * + * malik@ic.berkeley.edu * + * * + * Department of Electrical Engineering and Computer Sciences * + * University of California at Berkeley * + * Berkeley, CA 94704. * + * * + * Telephone: (415) 642-5048 * + ******************************************************************************/ + +#define LEFT 0 +#define RIGHT 1 +#define NONUNATE 0 +#define UNATE 1 +#define cdist0bv(p, q, var) \ +((GETINPUT(p, var)) & (GETINPUT(q, var))) +#define ROS_ZEROS 20 +#define ROS_MEM_SIZE 1000000 + +/* Node to store intermediate nodes of unate tree */ +typedef struct nc_node_struct { + struct nc_node_struct *child[2]; + pset part_cube[2]; + pset *cubelist; + pset cof; + int var; +} nc_node_t, *pnc_node; + +/* ros_holder to hold ROS */ +typedef struct ros_holder_struct { + pset_family ros; + pcube ros_cube; + int count; +} ros_holder_t, *pros_holder; + + +/* Global variables used by routines in ros */ +extern pcube *nc_tmp_cube; /* Temporary cubes to be used in this file */ + +extern pcover Tree_cover; /* F union D used to generate the unate tree */ + +extern int Max_level; /* Controls the depth of the part of unate + tree that is stored */ +extern int N_level; /* Some processing to reduce the size of + cofactors is done every N_level levels */ +extern pnc_node root; /* Root node of the unate tree */ + +extern int Num_act_vars; /* Number of active variables in the cube being + expanded */ + +extern pcover ROS; /* Reduced off set */ + +extern int ROS_count; /* Number of ROS generated */ + +extern long ROS_time; /* Total time for generating ROSs */ + +extern pcube ROS_cube; /* Cube for which ROS was computed */ + +extern int Max_ROS_size; /* Maximum size of off set during the entire + run */ +extern int ROS_zeros; /* Upper bound on the number of zeros in + ROS cube */ +extern int ROS_max_store; /* Number of ROS stored at any time */ + +extern int ROS_max_size_store; /* Upped limit on the size of ROS that can + be stored for future use */ +extern int N_ROS; /* Keeps track of number of ROS stored so far */ + +extern pros_holder ROS_array; /* ROS_array that stores ROS */ + +extern int OC_count; /* Number of overexpanded cubes generated */ + +extern long OC_time; /* Total time for generating overexpanded + cubes */ + +/* Functions used in ros */ + +/* ros.c */ extern void get_ROS1(); +/* ros.c */ extern pcover get_ROS(); +/* ros.c */ extern void init_ROS(); +/* ros.c */ extern bool find_correct_ROS(); +/* ros.c */ extern void store_ROS(); +/* ros.c */ extern void close_ROS(); +/* ros.c */ extern void find_overexpanded_cube_dyn(); +/* ros.c */ extern bool find_oc_dyn_special_cases(); +/* ros.c */ extern pcover setupBB_dyn(); +/* ros.c */ extern bool BB_dyn_special_cases(); +/* ros.c */ extern void find_overexpanded_cube(); +/* ros.c */ extern bool find_oc_special_cases(); +/* ros.c */ extern pcover setupBB(); +/* ros.c */ extern bool BB_special_cases(); +/* ros.c */ extern void get_OC(); +/* ros.c */ extern bool partition_ROS(); +/* ros.c */ extern pcover multiply2_sf(); +/* ros.c */ extern int nc_cubelist_partition(); +/* ros.c */ extern void nc_generate_cof_tree(); +/* ros.c */ extern pcover nc_compl_cube(); +/* ros.c */ extern void nc_free_unate_tree(); +/* ros.c */ extern void nc_bin_cof(); +/* ros.c */ extern void nc_cof_contain(); +/* ros.c */ extern bool cdist0v(); +/* ros.c */ extern void nc_rem_unnec_cubes(); +/* ros.c */ extern void nc_or_unnec(); +/* ros.c */ extern bool nc_is_nec(); +/* ros.c */ extern void nc_sf_multiply(); +/* ros.c */ extern void nc_rem_noncov_cubes(); +/* ros.c */ extern void nc_compl_special_cases(); +/* ros.c */ extern pcube *nc_copy_cubelist(); +/* ros.c */ extern void nc_setup_tmp_cubes(); +/* ros.c */ extern void nc_free_tmp_cubes(); diff --git a/sis/network/Makefile.am b/sis/network/Makefile.am new file mode 100644 index 0000000..af45a95 --- /dev/null +++ b/sis/network/Makefile.am @@ -0,0 +1,9 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libnetwork.a +libnetwork_a_SOURCES = acyclic.c append.c cleanup.c com_network.c \ + dfs.c esp.c net2pla.c net_seq.c net_verify.c netchk.c netclp.c \ + netmake.c network_util.c pla2net.c sweep.c +pkginclude_HEADERS = network.h +dist_doc_DATA = network.doc diff --git a/sis/network/Makefile.in b/sis/network/Makefile.in new file mode 100644 index 0000000..3a7ef93 --- /dev/null +++ b/sis/network/Makefile.in @@ -0,0 +1,426 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libnetwork_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/network +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libnetwork_a_AR = $(AR) $(ARFLAGS) +libnetwork_a_LIBADD = +am_libnetwork_a_OBJECTS = acyclic.$(OBJEXT) append.$(OBJEXT) \ + cleanup.$(OBJEXT) com_network.$(OBJEXT) dfs.$(OBJEXT) \ + esp.$(OBJEXT) net2pla.$(OBJEXT) net_seq.$(OBJEXT) \ + net_verify.$(OBJEXT) netchk.$(OBJEXT) netclp.$(OBJEXT) \ + netmake.$(OBJEXT) network_util.$(OBJEXT) pla2net.$(OBJEXT) \ + sweep.$(OBJEXT) +libnetwork_a_OBJECTS = $(am_libnetwork_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libnetwork_a_SOURCES) +DIST_SOURCES = $(libnetwork_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libnetwork.a +libnetwork_a_SOURCES = acyclic.c append.c cleanup.c com_network.c \ + dfs.c esp.c net2pla.c net_seq.c net_verify.c netchk.c netclp.c \ + netmake.c network_util.c pla2net.c sweep.c + +pkginclude_HEADERS = network.h +dist_doc_DATA = network.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/network/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/network/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libnetwork.a: $(libnetwork_a_OBJECTS) $(libnetwork_a_DEPENDENCIES) + -rm -f libnetwork.a + $(libnetwork_a_AR) libnetwork.a $(libnetwork_a_OBJECTS) $(libnetwork_a_LIBADD) + $(RANLIB) libnetwork.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/network/acyclic.c b/sis/network/acyclic.c new file mode 100644 index 0000000..76ea6db --- /dev/null +++ b/sis/network/acyclic.c @@ -0,0 +1,107 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/acyclic.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "sis.h" + +/* + * network_is_acyclic -- detect whether a network contains a cycle + * + * Calls error_append() with any error messages indicating the nodes + * on a cycle. + */ + +static int do_acyclic_check(); +static void extract_path(); + + +int +network_is_acyclic(network) +network_t *network; +{ + st_table *visited; + node_t *p; + lsGen gen; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + + /* start a DFS from the outputs */ + foreach_primary_output(network, gen, p) { + if (! do_acyclic_check(p->fanin[0], visited)) { + extract_path(visited); + return 0; + } + } + + /* we must now also recur from each node we haven't visited yet */ + foreach_node(network, gen, p) { + if (! st_lookup(visited, (char *) p, NIL(char *))) { + + /* this node was not reached in DFS from the outputs */ + if (! do_acyclic_check(p, visited)) { + extract_path(visited); + return 0; + } + } + } + + st_free_table(visited); + return 1; +} + + +static int +do_acyclic_check(node, visited) +node_t *node; +st_table *visited; +{ + char *value; + int i, status; + node_t *fanin; + + if (st_lookup(visited, (char *) node, &value)) { + return ! (int) value; /* return 0 if already active */ + + } else { + /* add this node to the active path */ + value = (char *) 1; + (void) st_insert(visited, (char *) node, value); + + foreach_fanin(node, i, fanin) { + status = do_acyclic_check(fanin, visited); + if (status == 0) { + return status; + } + } + + /* take this node off of the active path */ + value = (char *) 0; + (void) st_insert(visited, (char *) node, value); + + return 1; + } +} + +static void +extract_path(visited) +st_table *visited; +{ + st_generator *gen; + char *key, *value; + node_t *node; + + error_append("error: network contains a cycle\n"); + st_foreach_item(visited, gen, &key, &value) { + if ((int) value == 1) { + node = (node_t *) key; + error_append("node '"); + error_append(node_name(node)); + error_append("' is on the cycle\n"); + } + } +} diff --git a/sis/network/append.c b/sis/network/append.c new file mode 100644 index 0000000..697246b --- /dev/null +++ b/sis/network/append.c @@ -0,0 +1,168 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/append.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "sis.h" + + +static char *gen_unique_name(); +static node_t *copy_node(); +static int add_node_by_name(); + + + +int +network_append(network1, network2_copy) +network_t *network1; +network_t *network2_copy; +{ + network_t *network2; + node_t *fanin, *node, *node1, *node2; + lsGen gen; + int i, error; + + error = 0; + + /* + * we copy network2 because when we 'copy_node' we corrupt the + * fanout pointer list of network2 + */ + network2 = network_dup(network2_copy); + +#ifdef SIS + /* We don't append STG information, so we invalidate the STG */ + stg_free(network1->stg); +#endif + + /* each node of network1 will be replaced with itself (unless changed) */ + foreach_node(network1, gen, node1) { + node1->copy = node1; + } + + /* copy nodes from network2 */ + foreach_node(network2, gen, node2) { + if (! add_node_by_name(network1, node2)) { + error = 1; + } + } + + /* reset_io */ + foreach_node(network1, gen, node) { + foreach_fanin(node, i, fanin) { + node->fanin[i] = fanin->copy; + } + } + + /* patch any fanin which happens to point to a PO node */ + foreach_node(network1, gen, node1) { + foreach_fanin(node1, i, fanin) { + if (fanin->type == PRIMARY_OUTPUT) { + node1->fanin[i] = fanin->fanin[0]; + } + } + } + + foreach_node(network1, gen, node) { + if (node->type == PRIMARY_INPUT && node->copy != node) { + network_delete_node_gen(network1, gen); + } + } + + /* reset the fanout pointers */ + foreach_node(network1, gen, node1) { + LS_ASSERT(lsDestroy(node1->fanout, free)); + node1->fanout = lsCreate(); + } + foreach_node(network1, gen, node1) { + fanin_add_fanout(node1); + } + +#ifdef SIS + /* Update the latch list and the latch table */ + copy_latch_info(network2->latch, network1->latch, network1->latch_table); +#endif + + /* make sure the resulting network is acyclic */ + if (! network_is_acyclic(network1)) { + error = 1; + } + + network_free(network2); + return ! error; +} + + +static node_t * +copy_node(network1, node2, name_hack) +network_t *network1; +node_t *node2; +int name_hack; +{ + node_t *new_node; + char *new_name; + + new_node = node_dup(node2); /* even duplicates fanin */ + + if (name_hack) { + new_name = gen_unique_name(network1, new_node); + FREE(new_node->name); + new_node->name = new_name; + } + network_add_node(network1, new_node); + node2->copy = new_node; + new_node->copy = new_node; + return new_node; +} + + +static char * +gen_unique_name(network, node) +network_t *network; +node_t *node; +{ + char new_name[1024]; + int count; + + count = 0; + do { + (void) sprintf(new_name, "%s-%d", node->name, count++); + } while (network_find_node(network, new_name) != 0); + + return util_strsav(new_name); +} + +static int +add_node_by_name(network1, node2) +network_t *network1; +node_t *node2; +{ + node_t *temp, *node1; + char errmsg[1024]; + + node1 = network_find_node(network1, node2->name); + if (node1 == 0) { + (void) copy_node(network1, node2, 0); + + } else if (node2->type == PRIMARY_INPUT) { + node2->copy = node1; + + } else { + temp = copy_node(network1, node2, 1); + if (node1->type == PRIMARY_INPUT) { + node1->copy = temp; + network_swap_names(network1, node1, temp); + } else { + (void) sprintf(errmsg, + "network_append: node '%s' already driven\n", node2->name); + error_append(errmsg); + return 0; + } + } + + return 1; +} diff --git a/sis/network/cleanup.c b/sis/network/cleanup.c new file mode 100644 index 0000000..f2c7da8 --- /dev/null +++ b/sis/network/cleanup.c @@ -0,0 +1,122 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/cleanup.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "sis.h" + + +/* + * network_cleanup -- remove internal nodes with no fanout; this is iterated + * until every node has fanout > 0. + */ + + +int +network_cleanup(network) +network_t *network; +{ + int status, latch_removed; + + status = network_cleanup_util(network, 1, &latch_removed); + if ((network->dc_network != NIL(network_t)) && latch_removed) { + network_free(network->dc_network); + network->dc_network = NIL(network_t); + } + return status; +} + + +int network_ccleanup(network) +network_t *network; +{ + return network_cleanup_util(network, 0, NIL(int)); +} + + +int +network_cleanup_util(network, sweep_latch, latch_removed) +network_t *network; +int sweep_latch; +int *latch_removed; +{ + node_t *p; + int some_change, changed; + lsGen gen; +#ifdef SIS + latch_t *l; + int i; + node_t *out; + node_t *in; + node_t *dc_pi, *dc_po, *cnode, *fanout; + lsGen gen2; + node_t **fo_array; +#endif /* SIS */ + + some_change = 0; + if (latch_removed != NIL(int)) { + *latch_removed = 0; + } + do { + changed = 0; + foreach_node(network, gen, p) { + if (p->type == INTERNAL && node_num_fanout(p) == 0) { + network_delete_node_gen(network, gen); + changed = 1; + some_change = 1; + } + } +#ifdef SIS + if (sweep_latch) { + foreach_latch(network, gen, l) { + out = latch_get_output(l); + in = latch_get_input(l); + if (node_num_fanout(out) == 0) { + /* Update the DC network. If no nodes depend on this latch + output, then we can set it to an arbitrary constant in + the DC network. */ + if (network->dc_network != NIL(network_t)) { + dc_pi = network_find_node(network->dc_network, out->name); + if (dc_pi != NIL(node_t)) { + cnode = node_constant(0); + network_add_node(network->dc_network, cnode); + fo_array = ALLOC(node_t *, node_num_fanout(dc_pi)); + i = 0; + foreach_fanout(dc_pi, gen2, fanout) { + fo_array[i++] = fanout; + } + for (i = node_num_fanout(dc_pi); i-- > 0;) { + node_patch_fanin(fo_array[i], dc_pi, cnode); + } + FREE(fo_array); + network_delete_node(network->dc_network, dc_pi); + } + dc_po = network_find_node(network->dc_network, in->name); + if (dc_po != NIL(node_t)) { + network_delete_node(network->dc_network, dc_po); + } + } + network_delete_latch_gen(network, gen); + network_delete_node(network, in); + network_delete_node(network, out); + changed = 1; + some_change = 1; + if (latch_removed != NIL(int)) { + *latch_removed = 1; + } + } + } + } +#endif /* SIS */ + + } while (changed); + if (network->dc_network != NIL(network_t)) { + (void) network_sweep(network->dc_network); + } + + return some_change; +} diff --git a/sis/network/com_network.c b/sis/network/com_network.c new file mode 100644 index 0000000..8b85a1f --- /dev/null +++ b/sis/network/com_network.c @@ -0,0 +1,239 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/com_network.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "sis.h" + + +static int +com_ripup(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + network_t *new_network; + + node_vec = com_get_nodes(*network, argc, argv); + new_network = network_from_nodevec(node_vec); + network_free(*network); + *network = new_network; + return 0; +} + + +static int +com_collapse(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *node1, *node2; + + if (argc == 1) { + (void) network_collapse(*network); + + } else { + node_vec = com_get_nodes(*network, argc, argv); + if (array_n(node_vec) == 1) { + node1 = array_fetch(node_t *, node_vec, 0); + (void) network_collapse_single(node1); + + } else if (array_n(node_vec) == 2) { + node1 = array_fetch(node_t *, node_vec, 0); + node2 = array_fetch(node_t *, node_vec, 1); + (void) node_collapse(node1, node2); + + } else { + (void) fprintf(miserr, "usage: clp [n1] [n2]\n"); + return 1; + } + array_free(node_vec); + } + return 0; +} + +/* ARGSUSED */ +static int +com_sweep(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + if (argc != 1) { + (void) fprintf(miserr, "usage: sweep\n"); + return 1; + } + (void) network_sweep(*network); + return 0; +} + + +/* ARGSUSED */ +static int +com_espresso(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *new_net; + + if (argc != 1) { + (void) fprintf(miserr, "usage: espresso\n"); + return 1; + } + new_net = network_espresso(*network); + if (new_net == 0) { /* well, happens for some weird cases */ + return 0; + } else { + network_free(*network); + *network = new_net; + } + return 0; +} + +static int +com_check(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, verbose, is_okay; + + verbose = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "v")) != EOF) { + switch(c) { + case 'v': + verbose = 1; + break; + default: + goto usage; + } + } + + if (argc != util_optind) goto usage; + + error_init(); + is_okay = network_check(*network) && network_is_acyclic(*network); + if (is_okay) { + if (verbose) { + (void) fprintf(misout, + "check: network passes consistency check\n"); + } + return 0; + } else { + (void) fprintf(miserr, "check: problem detected with network\n"); + (void) fprintf(miserr, "%s", error_string()); + return 1; + } + +usage: + (void) fprintf(miserr, "usage: _check [-v]\n"); + return 1; +} + +/* ARGSUSED */ +static int +com_verify(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, verbose, eql, method; + network_t *network1, *network2; + char cmd[1024]; + + verbose = 0; + +#ifdef SIS + if (network_num_latch(*network) != 0) { + (void) fprintf(siserr, "Use the verify_fsm command to verify sequential circuits.\n"); + return 1; + } +#endif /* SIS */ + + util_getopt_reset(); + method = 0; + while ((c = util_getopt(argc, argv, "m:v")) != EOF) { + switch(c) { + case 'm': + if (strcmp(util_optarg, "clp") == 0) { + method = 0; + } else if (strcmp(util_optarg, "bdd") == 0) { + method = 1; + } else if (strcmp(util_optarg, "par") == 0) { + method = 2; + } else { + goto usage; + } + break; + case 'v': + verbose = 1; + break; + default: + goto usage; + } + } + + if (argc - util_optind == 0) { + network1 = *network; + network2 = (*network)->original; + if (network2 == 0) { + (void) fprintf(miserr, "error -- no original network\n"); + return 1; + } + eql = net_verify_with_dc(network1, network2, method, verbose); + return(eql); + } else if (argc - util_optind == 1) { + network1 = *network; + network2 = network_alloc(); + (void) sprintf(cmd, "read_blif %s", argv[util_optind]); + if (com_execute(&network2, cmd) != 0) return 1; + eql = net_verify_with_dc(network1, network2, method, verbose); + network_free(network2); + return(eql); + + } else if (argc - util_optind == 2) { + network1 = network_alloc(); + (void) sprintf(cmd, "read_blif %s", argv[argc-2]); + if (com_execute(&network1, cmd) != 0) return 1; + network2 = network_alloc(); + (void) sprintf(cmd, "read_blif %s", argv[argc-1]); + if (com_execute(&network2, cmd) != 0) return 1; + eql = net_verify_with_dc(network1, network2, method, verbose); + network_free(network1); + network_free(network2); + return(eql); + + } else { + goto usage; + } + +usage: + (void) fprintf(miserr, "usage: verify [-m] [[net1.blif] [net2.blif]]\n"); + (void) fprintf(miserr, " -m \tclp\tVerifying by collapsing (default)\n"); + (void) fprintf(miserr, " -m \tbdd\tVerifying using bdd\n"); + return 1; +} + +init_network() +{ + com_add_command("_check", com_check, 0); + com_add_command("_ripup", com_ripup, 1); + com_add_command("collapse", com_collapse, 1); + com_add_command("espresso", com_espresso, 1); + com_add_command("sweep", com_sweep, 1); + com_add_command("verify", com_verify, 0); +} + + +end_network() +{ +} diff --git a/sis/network/dfs.c b/sis/network/dfs.c new file mode 100644 index 0000000..7caf5e8 --- /dev/null +++ b/sis/network/dfs.c @@ -0,0 +1,240 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/dfs.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "sis.h" + + +/* + * network_dfs -- order the nodes for a depth-first search from + * the outputs (all fanin's appear in the list before each node) + * + * Crash and burn if a cycle is detected in the network. + */ + +static int network_dfs_recur(); + +array_t * +network_dfs(network) +network_t *network; +{ + int i; + st_table *visited; + array_t *roots; + array_t *node_vec; + node_t *node; + lsGen gen; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + node_vec = array_alloc(node_t *, 0); + roots = array_alloc(node_t *, 0); + + foreach_primary_output(network, gen, node) { + array_insert_last(node_t *, roots, node); + } + /* handle floating nodes */ + foreach_node(network, gen, node) { + if (node_num_fanout(node) == 0 && node->type != PRIMARY_OUTPUT) { + array_insert_last(node_t *, roots, node); + } + } + for (i = 0; i < array_n(roots); i++) { + node = array_fetch(node_t *, roots, i); + if (! network_dfs_recur(node, node_vec, visited, 1, INFINITY)) { + fail("network_dfs: network contains a cycle\n"); + } + } + st_free_table(visited); + array_free(roots); + return node_vec; +} + +#ifdef SIS +/* Make sure that the vector returned has all the control po nodes + BEFORE the latch output nodes. This is so that the arrivals of the + latch outputs can be computed based on the arrival of the clock and + the delay through the latch of the clock. */ + +array_t * +network_special_dfs(network) +network_t *network; +{ + int i; + st_table *visited; + array_t *roots; + array_t *node_vec; + node_t *node; + lsGen gen; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + node_vec = array_alloc(node_t *, 0); + roots = array_alloc(node_t *, 0); + + foreach_primary_output(network, gen, node) { + if (network_is_control(network, node)) { + array_insert_last(node_t *, roots, node); + } + } + foreach_primary_output(network, gen, node) { + if (!network_is_control(network, node)) { + array_insert_last(node_t *, roots, node); + } + } + /* handle floating nodes */ + foreach_node(network, gen, node) { + if (node_num_fanout(node) == 0 && node->type != PRIMARY_OUTPUT) { + array_insert_last(node_t *, roots, node); + } + } + for (i = 0; i < array_n(roots); i++) { + node = array_fetch(node_t *, roots, i); + if (! network_dfs_recur(node, node_vec, visited, 1, INFINITY)) { + fail("network_dfs: network contains a cycle\n"); + } + } + st_free_table(visited); + array_free(roots); + return node_vec; +} +#endif /* SIS */ + + +array_t * +network_dfs_from_input(network) +network_t *network; +{ + int i; + st_table *visited; + array_t *node_vec; + array_t *roots; + node_t *node; + lsGen gen; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + node_vec = array_alloc(node_t *, 0); + roots = array_alloc(node_t *, 0); + + foreach_primary_input(network, gen, node) { + array_insert_last(node_t *, roots, node); + } + /* handle floating nodes */ + foreach_node(network, gen, node) { + if (node_num_fanin(node) == 0 && node->type != PRIMARY_INPUT) { + array_insert_last(node_t *, roots, node); + } + } + for (i = 0; i < array_n(roots); i++) { + node = array_fetch(node_t *, roots, i); + if (! network_dfs_recur(node, node_vec, visited, 0, INFINITY)) { + fail("network_dfs_from_input: network contains a cycle\n"); + } + } + st_free_table(visited); + array_free(roots); + return node_vec; +} + +array_t * +network_tfi(node, level) +node_t *node; +int level; +{ + st_table *visited; + array_t *node_vec; + node_t *fanin; + int i; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + node_vec = array_alloc(node_t *, 0); + + foreach_fanin(node, i, fanin) { + if (! network_dfs_recur(fanin, node_vec, visited, 1, level)) { + fail("network_tfi: network contains a cycle\n"); + } + } + + st_free_table(visited); + return node_vec; +} + + +array_t * +network_tfo(node, level) +node_t *node; +int level; +{ + st_table *visited; + array_t *node_vec; + node_t *fanout; + lsGen gen; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + node_vec = array_alloc(node_t *, 0); + + foreach_fanout(node, gen, fanout) { + if (! network_dfs_recur(fanout, node_vec, visited, 0, level)) { + fail("network_tfo: network contains a cycle\n"); + } + } + + st_free_table(visited); + return node_vec; +} + +static int +network_dfs_recur(node, node_vec, visited, dir, level) +node_t *node; +array_t *node_vec; +st_table *visited; +int dir; /* 1 == visit inputs, 0 == visit outputs */ +int level; +{ + int i; + char *value; + node_t *fanin, *fanout; + lsGen gen; + + if (level > 0) { + + if (st_lookup(visited, (char *) node, &value)) { + return value == 0; /* if value is 1, then a cycle */ + + } else { + /* add this node to the active path */ + value = (char *) 1; + (void) st_insert(visited, (char *) node, value); + + /* avoid recursion if level-1 wouldn't add anything anyways */ + if (level > 1) { + if (dir) { + foreach_fanin(node, i, fanin) { + if (! network_dfs_recur(fanin, node_vec, + visited, dir, level-1)) { + return 0; + } + } + } else { + foreach_fanout(node, gen, fanout) { + if (! network_dfs_recur(fanout, node_vec, + visited, dir, level-1)) { + return 0; + } + } + } + } + + /* take this node off of the active path */ + value = (char *) 0; + (void) st_insert(visited, (char *) node, value); + + /* add node to list */ + array_insert_last(node_t *, node_vec, node); + } + } + return 1; +} diff --git a/sis/network/esp.c b/sis/network/esp.c new file mode 100644 index 0000000..2d94936 --- /dev/null +++ b/sis/network/esp.c @@ -0,0 +1,83 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/esp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "sis.h" + +#ifdef SIS +static void save_latch_info(); +#endif /* SIS */ + +network_t * +network_espresso(network) +network_t *network; +{ + network_t *new_net; + pPLA PLA; + + PLA = network_to_pla(network); + if (PLA == 0) return 0; + + if (PLA->R != 0) sf_free(PLA->R); + if (PLA->D != 0) { + PLA->R = complement(cube2list(PLA->F,PLA->D)); + } else { + PLA->D = new_cover(0); + PLA->R = complement(cube1list(PLA->F)); + } + + PLA->F = espresso(PLA->F, PLA->D, PLA->R); + new_net = pla_to_network(PLA); + network_set_name(new_net, network_name(network)); + delay_network_dup(new_net, network); + new_net->dc_network = network_dup(network->dc_network); +#ifdef SIS + save_latch_info(new_net, network->latch, new_net->latch, new_net->latch_table); + new_net->stg = stg_dup(network->stg); + new_net->astg = astg_dup(network->astg); + network_clock_dup(network, new_net); +#endif /* SIS */ + + discard_pla(PLA); + return new_net; +} + + +#ifdef SIS +static void +save_latch_info(net, list, newlist, newtable) +network_t *net; +lsList list, newlist; +st_table *newtable; +{ + lsGen gen; + latch_t *l1, *l2; + node_t *in, *out; + + lsForeachItem(list, gen, l1) { + l2 = latch_alloc(); + in = network_find_node(net, node_long_name(latch_get_input(l1))); + out = network_find_node(net, node_long_name(latch_get_output(l1))); + latch_set_input(l2, in); + latch_set_output(l2, out); + latch_set_initial_value(l2, latch_get_initial_value(l1)); + + latch_set_current_value(l2, latch_get_current_value(l1)); + latch_set_type(l2, latch_get_type(l1)); + latch_set_gate(l2, latch_get_gate(l1)); + if (latch_get_control(l1) != NIL(node_t)) { + latch_set_control(l2, network_find_node(net, + node_long_name(latch_get_control(l1)))); + } + (void) st_insert(newtable, (char *) in, (char *) l2); + (void) st_insert(newtable, (char *) out, (char *) l2); + LS_ASSERT(lsNewEnd(newlist, (lsGeneric) l2, LS_NH)); + } + return; +} +#endif /* SIS */ diff --git a/sis/network/net2pla.c b/sis/network/net2pla.c new file mode 100644 index 0000000..73de2f5 --- /dev/null +++ b/sis/network/net2pla.c @@ -0,0 +1,170 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/net2pla.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "sis.h" + +extern pset_family node_sf_adjust(); + + +PLA_t * +network_to_pla(network_1) +network_t *network_1; +{ + PLA_t *PLA; + register int i; + register pset last, px, pdest; + pset_family x; + node_t *p, *node, *fanin, **new_fanin; + network_t *network; + int nin, nout, out, hack; + lsGen gen; + network_t *dcnetwork; + node_t *dcnode; + st_table *node_exdc_table; + st_table *node_table; + char *dummy; + + if (network_1 == 0) return 0; + + nin = network_num_pi(network_1); + nout = network_num_po(network_1); + if (nin == 0 || nout == 0) { + return 0; + } + + network = network_dup(network_1); + (void) network_collapse(network); + + /* nin and nout should be reset. The reason is that collapse may have */ + /* deleted latches that fanout nowhere, which changes the number of pi's */ + /* and po's. It is not expect that the number of inputs and outputs will */ + /* go to zero!! */ + + nin = network_num_pi(network); + nout = network_num_po(network); + + dcnetwork = network_dc_network(network); + if (dcnetwork != NIL (network_t)){ + network_collapse(dcnetwork); + node_table = st_init_table(st_ptrcmp, st_ptrhash); + node_exdc_table = attach_dcnetwork_to_network(network); + foreach_primary_output(network, gen, node) { + dcnode = find_ex_dc(node, node_exdc_table); + (void)st_insert(node_table,(char *)node,(char *)dcnode); + } + st_free_table(node_exdc_table); + } + + /* Form a list of the primary inputs */ + new_fanin = ALLOC(node_t *, nin); + i = 0; + foreach_primary_input(network, gen, p) { + new_fanin[i++] = p; + } + + undefine_cube_size(); + cube.num_binary_vars = nin; + cube.num_vars = nin + 1; + cube.part_size = ALLOC(int, cube.num_vars); + cube.part_size[cube.num_vars - 1] = nout; + cube_setup(); + + PLA = new_PLA(); + PLA->label = ALLOC(char *, cube.size); + for(i = 0; i < cube.num_binary_vars; i++) { + node = new_fanin[i]; + PLA->label[cube.first_part[i] + 1] = util_strsav(node->name); + /* map_dcset() requires names on all variables */ + PLA->label[cube.first_part[i]] = ALLOC(char, strlen(node->name) + 6); + (void) sprintf(PLA->label[cube.first_part[i]], "%s.bar", node->name); + } + + out = cube.first_part[cube.output]; + foreach_primary_output(network, gen, p) { + PLA->label[out++] = util_strsav(p->name); + } + + PLA->F = new_cover(100); + if (dcnetwork != NIL (network_t)){ + PLA->D = new_cover(100); + } + out = cube.first_part[cube.output]; + foreach_primary_output(network, gen, node) { + + /* special hack for output == input */ + fanin = node->fanin[0]; + hack = 0; + if (fanin->type == PRIMARY_INPUT) { + fanin = node_literal(fanin, 1); + hack = 1; + } + + x = node_sf_adjust(fanin, new_fanin, nin); + foreach_set(x, last, px) { + pdest = new_cube(); + for(i = 0; i < nin*2; i++) { + if (is_in_set(px, i)) { + set_insert(pdest, i); + } + } + set_insert(pdest, out); + PLA->F = sf_addset(PLA->F, pdest); + set_free(pdest); + } + + /* special hack for output == input */ + if (hack) { + node_free(fanin); + } + sf_free(x); + if (dcnetwork != NIL (network_t)){ + (void)st_lookup(node_table, (char *) node, &dummy); + dcnode= (node_t *) dummy; + if (dcnode->type == PRIMARY_INPUT) { + dcnode = node_literal(dcnode, 1); + } + x = node_sf_adjust(dcnode, new_fanin, nin); + foreach_set(x, last, px) { + pdest = new_cube(); + for(i = 0; i < nin*2; i++) { + if (is_in_set(px, i)) { + set_insert(pdest, i); + } + } + set_insert(pdest, out); + PLA->D = sf_addset(PLA->D, pdest); + set_free(pdest); + } + + /* special hack for output == input */ + node_free(dcnode); + sf_free(x); + } + out++; + } + if (dcnetwork != NIL (network_t)){ + st_free_table(node_table); + } + + FREE(new_fanin); + network_free(network); + return PLA; +} + + +void +discard_pla(PLA) +pPLA PLA; +{ + if (PLA != 0) free_PLA(PLA); + + setdown_cube(); + FREE(cube.part_size); + define_cube_size(20); +} diff --git a/sis/network/net_seq.c b/sis/network/net_seq.c new file mode 100644 index 0000000..f38c83c --- /dev/null +++ b/sis/network/net_seq.c @@ -0,0 +1,733 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/net_seq.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#ifdef SIS + +#include "sis.h" + +node_t * +network_latch_end(node) +node_t *node; +{ + node_type_t type; + network_t *network; + latch_t *latch; + + network = node_network(node); + if (network == NIL(network_t)) { + fail("latch_end: node not part of a network"); + } + + type = node_type(node); + if (type != PRIMARY_INPUT && type != PRIMARY_OUTPUT) { + return NIL(node_t); + } + + if (st_lookup(network->latch_table, (char *) node, (char **) &latch) != 0) { + if (latch == NIL(latch_t)) { + return(NIL(node_t)); + } + if (latch_get_input(latch) == node) { + return latch_get_output(latch); + } + else { + return latch_get_input(latch); + } + } + else { + return(NIL(node_t)); + } +} + + +/* + * The latch order is implicitly stored by network_create_latch(), which will + * add a latch from a po to a pi. Each call to network_create_latch() will + * result in appending another latch at the end of the latch order. + */ +void +network_create_latch(network, l, n1, n2) +network_t *network; +latch_t **l; +node_t *n1, *n2; +{ + lsGen gen; + node_t *fo; + node_t *po_ptr, *pi_ptr; + int found = 0; + st_table *latch_table; + + if ((n1->network != network) || (n2->network != network)) { + fail("network_create_latch: nodes must both belong to the given network"); + } + foreach_fanout(n1, gen, fo) { + if (fo == n2) { + found = 1; + (void) lsFinish(gen); + break; + } + } + if (found) { + network_disconnect(n1, n2, &po_ptr, &pi_ptr); + *l = latch_alloc(); + latch_set_input(*l, po_ptr); + latch_set_output(*l, pi_ptr); + latch_table = network->latch_table; + (void) st_insert(latch_table, (char *) po_ptr, (char *) *l); + (void) st_insert(latch_table, (char *) pi_ptr, (char *) *l); + LS_ASSERT (lsNewEnd(network->latch, (lsGeneric) *l, LS_NH)); + return; + } + if (node_type(n1) == PRIMARY_OUTPUT && node_type(n2) == PRIMARY_INPUT) { + if (network_latch_end(n1) == n2) { + *l = latch_from_node(n1); + return; + } + if (network_latch_end(n1) != NIL(node_t)) { + fail("network_create_latch: input node is already part of a latch"); + } + if (network_latch_end(n2) != NIL(node_t)) { + fail("network_create_latch: output node is already part of a latch"); + } + *l = latch_alloc(); + latch_set_input(*l, n1); + latch_set_output(*l, n2); + latch_table = network->latch_table; + (void) st_insert(latch_table, (char *) n1, (char *) *l); + (void) st_insert(latch_table, (char *) n2, (char *) *l); + LS_ASSERT (lsNewEnd(network->latch, (lsGeneric) *l, LS_NH)); + return; + } else { + fail("network_create_latch: latch cannot be added between those two node types"); + } +} + + +void +network_delete_latch(network, l) +network_t *network; +latch_t *l; +{ + lsGen gen; + char *data = NIL(char); + + if (latch_get_input(l) == NIL(node_t)) { + fail("network_delete_latch: attempt to delete latch with no input"); + } + if (latch_get_input(l)->network != network) { + fail("network_delete_latch: attempt to delete latch not in network"); + } + for (gen = lsStart(network->latch); (latch_t *) data != l; + (void) lsNext(gen, (lsGeneric *) &data, LS_NH)) { + ; + } + assert((latch_t *) data == l); + network_delete_latch_gen(network, gen); + LS_ASSERT(lsFinish(gen)); +} + + +void +network_delete_latch_gen(network, gen) +network_t *network; +lsGen gen; +{ + node_t *input, *output; + latch_t *latch; + + LS_ASSERT(lsDelBefore(gen, (lsGeneric *) &latch)); + input = latch_get_input(latch); + output = latch_get_output(latch); + + if (! st_delete(network->latch_table, (char **) &input, NIL(char *))) { + fail("network_delete_latch_gen: latch input not in the table"); + } + assert(input == latch_get_input(latch)); + + if (! st_delete(network->latch_table, (char **) &output, NIL(char *))) { + fail("network_delete_latch_gen: latch_output not in the table"); + } + assert(output == latch_get_output(latch)); + + latch_free(latch); + return; +} + + +void +network_disconnect(node1, node2, po_ptr, pi_ptr) +node_t *node1, *node2, **po_ptr, **pi_ptr; +{ + if(node1->network != node2->network){ + fail("network_disconnect: node1 and node2 do not belong to the same network"); + } + if(node1->network == NIL(network_t)){ + fail("network_disconnect: node1 and node2 do not belong to a network"); + } + *po_ptr = network_add_fake_primary_output(node1->network, node1); + *pi_ptr = node_alloc(); + network_add_primary_input(node2->network, *pi_ptr); + (void)node_patch_fanin(node2, node1, *pi_ptr); + return; +} + + +void +network_connect(node1, node2) +node_t *node1, *node2; +{ + lsGen gen; + node_t *fanout, *fanin, *n; + int i, num_nodes; + array_t *tfo_array; + network_t *network; + + if(node1->network != node2->network){ + fail("network_connect: node1 and node2 do not belong to the same network"); + } + if(node1->network == NIL(network_t)){ + fail("network_connect: node1 and node2 do not belong to a network"); + } + if(node_function(node1) != NODE_PO){ + fail("network_connect: node1 not a PRIMARY OUTPUT"); + } + if(node_function(node2) != NODE_PI){ + fail("network_connect: node2 not a PRIMARY INPUT"); + } + fanin = node_get_fanin(node1, 0); + network = fanin->network; + num_nodes = network_num_pi(network) + network_num_po(network) + + network_num_internal(network); + foreach_fanout(node2, gen, fanout){ + tfo_array = network_tfo(fanout, num_nodes); + for (i = 0; i < array_n(tfo_array); i++) { + n = array_fetch(node_t *, tfo_array, i); + if (n == fanin) { + (void) array_free(tfo_array); + fail("network_connect: connection would result in combinational cycles"); + } + } + (void) array_free(tfo_array); + } + foreach_fanout(node2, gen, fanout){ + (void) node_patch_fanin(fanout, node2, fanin); + } + network_delete_node(node1->network, node1); + network_delete_node(node2->network, node2); +} + + +graph_t * +network_stg(network) +network_t *network; +{ + if (network == NIL(network_t)) { + fail("network_stg: no network"); + } + return network->stg; +} + + +void +network_set_stg(network, stg) +network_t *network; +graph_t *stg; +{ + if (network == NIL(network_t)) { + fail("network_set_stg: no network"); + } + network->stg = stg; + if (stg != NIL(graph_t)){ + stg_save_names(network, stg, 1); + } + return; +} + +int +network_stg_check(network) +network_t *network; +{ + array_t *po_list, *ar; + bdd_t *f_bdd, *prod_bdd, *new_prod, *bdd_test; + st_table *leaves; + bdd_manager *manager; + char *input, *output; + char *in_state, *out_state; + char *save_in, *save_ps; + lsGen gen, gen2; + edge_t *e; + node_t *pi, *po; + st_generator *sym_table_gen; + int index, max; + + /* if no network exists (just an stg) then return 1 */ + + if (network_num_pi(network) == 0) { + return 1; + } + if (!network_check(network)) { + (void) fprintf(siserr, "network_stg_check: "); + (void) fprintf(siserr, "network failed network_check\n"); + return 0; + } + if (network->stg == NIL(graph_t)) { + return 1; + } + + /* I think this code is not necessary, because if there's an stg, */ + /* it was read in with read_kiss, which calls stg_check. */ + +/* + if (!stg_check(network->stg)) { + (void) fprintf(siserr, "network_stg_check: "); + (void) fprintf(siserr, "STG failed stg_check\n"); + return 0; + } +*/ + + (void) fprintf(sisout, "Checking to see that the STG "); + (void) fprintf(sisout, "covers the network...\n"); + if (network_num_latch(network) != + (int) strlen(stg_get_state_encoding(stg_get_start(network->stg)))) { + (void) fprintf(siserr, "network_stg_check: number of latches "); + (void) fprintf(siserr, "does not match number of encoding bits"); + return 0; + } + + /* + * Create an array for the primary outputs. + */ + po_list = array_alloc(node_t *, 0); + foreach_primary_output (network, gen, po) { + if (network_get_control(network,po) == NIL(node_t)) { + array_insert_last(node_t *, po_list, po); + } + } + + /* + * Create a hash table of the primary inputs, and initialize + * their values ot -1. + */ + leaves = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_input(network, gen, pi) { + if (network_get_control(network,pi) == NIL(node_t)) { + (void) st_insert(leaves, (char *) pi, (char *) -1); + } + } + + /* + * Get an ordering for the leaves. The variable id of each PI node + * will be set as the value in the leaves table. The third argument + * says that the nodes in po_list can be visited in any order. + */ + ar = order_dfs(po_list, leaves, 0); + (void) array_free(ar); + + /* + * We want to elegantly handle the case where a PI does not fanout. + * Thus, first find the max index assigned to an input (which was reached + * from a node in po_list). Then, assign an index to the unassigned PI's. + */ + max = 0; + st_foreach_item_int(leaves, sym_table_gen, (char **) &pi, &index) { + if (index > max) { + max = index; + } + } + max++; + + st_foreach_item_int(leaves, sym_table_gen, (char **) &pi, &index) { + if (index < 0) { + index = max++; + (void) st_insert(leaves, (char *) pi, (char *) index); + } + } + + /* + * Create a manager with number of variables equal to number of primary inputs. + */ + manager = ntbdd_start_manager(st_count(leaves)); + + /* + * Create single variable BDD's for each primary input. We do this explicitly, instead + * of relying on BDD's to be created for the PI's when the BDD's are recursively + * built for the PO's, because some PI's may not fanout. + */ + foreach_primary_input(network, gen, pi) { + if (network_get_control(network,pi) == NIL(node_t)) { + (void) ntbdd_node_to_bdd(pi, manager, leaves); + } + } + + /* + * Create global BDD's for each primary output. These will be automatically + * stored in the BDD slot of the node. This also has the side affect of + * creating BDD's for every node in the transitive fanin of the PO's; the BDD's + * for the primary inputs were built above. Note: return value of + * ntbdd_node_to_bdd not used. + */ + foreach_primary_output(network, gen, po) { + if (network_get_control(network,po) == NIL(node_t)) { + (void) ntbdd_node_to_bdd(po, manager, leaves); + } + } + (void) st_free_table(leaves); + + /* + * Checking that the network performs the behavior specified by the stg. + * Do by simulating each transition in the stg. + */ + stg_foreach_transition(network->stg, gen, e) { + + /* + * Get the input and output vectors for the transition, as well + * as the current state and next state in state-encoded form. + */ + input = stg_edge_input_string(e); + output = stg_edge_output_string(e); + in_state = stg_get_state_encoding(stg_edge_from_state(e)); + if (in_state == NIL(char)) { + (void) fprintf(siserr, "Network_stg_check: \n"); + (void) fprintf(siserr, "State %s is missing its encoding\n", + stg_get_state_name(stg_edge_from_state(e))); + lsFinish(gen); + return 0; + } + save_in = input; /* save pointers to the beginning of these strings */ + save_ps = in_state; /* so that good error messages can be printed */ + out_state = stg_get_state_encoding(stg_edge_to_state(e)); + if (out_state == NIL(char)) { + (void) fprintf(siserr, "Network_stg_check: "); + (void) fprintf(siserr, "State %s is missing its encoding\n", + stg_get_state_name(stg_edge_from_state(e))); + lsFinish(gen); + return 0; + } + + /* + * The product bdd is built incrementally as the product of all the + * input bdds and the from-state bdds. Each bdd is ANDed in + * positive or negative form, depending on the value of that + * particular state bit or input bit. If the bit is 2, the bdd + * is not ANDed into the product. + */ + prod_bdd = bdd_one(manager); + foreach_primary_input(network, gen2, pi) { + if (network_get_control(network,pi) == NIL(node_t)) { + f_bdd = ntbdd_at_node(pi); + if (f_bdd == NIL(bdd_t)) { + /* this PI is unused anyway; can skip */ + continue; + } + if (network_latch_end(pi) == NIL(node_t)) { + if (*input == '0') { + new_prod = bdd_and(prod_bdd, f_bdd, 1, 0); + (void) bdd_free(prod_bdd); + prod_bdd = new_prod; + } else if (*input == '1') { + new_prod = bdd_and(prod_bdd, f_bdd, 1, 1); + (void) bdd_free(prod_bdd); + prod_bdd = new_prod; + } + input++; + } else { + if (*in_state == '0') { + new_prod = bdd_and(prod_bdd, f_bdd, 1, 0); + (void) bdd_free(prod_bdd); + prod_bdd = new_prod; + } else if (*in_state == '1') { + new_prod = bdd_and(prod_bdd, f_bdd, 1, 1); + (void) bdd_free(prod_bdd); + prod_bdd = new_prod; + } + in_state++; + } + } + } /* close: foreach_primary_input(network, gen2, pi) { */ + + /* + * Each output bdd and to-state bdd is cofactored with respect to + * product bdd. The result is checked against the value of that + * output bit on the transition, or the value of the encoded bit + * in the to-state for that transition. + */ + foreach_primary_output(network, gen2, po) { + if (network_get_control(network,po) == NIL(node_t)) { + f_bdd = ntbdd_at_node(po); + bdd_test = bdd_cofactor(f_bdd, prod_bdd); + if (network_latch_end(po) == NIL(node_t)) { + if (*output == '0') { + if (!bdd_is_tautology(bdd_test, 0)) { + (void) fprintf(siserr, "failed on output node "); + (void) fprintf(siserr, "(%s) ", node_name(po)); + (void) fprintf(siserr, "(should have been 0)\n"); + (void) fprintf(siserr, "Present state: %s", save_ps); + (void) fprintf(siserr, " Input: %s\n", save_in); + goto bad_exit; + } + } else if (*output == '1') { + if (!bdd_is_tautology(bdd_test, 1)) { + (void) fprintf(siserr, "failed on output node "); + (void) fprintf(siserr, "(%s) ", node_name(po)); + (void) fprintf(siserr, "(should have been 1)\n"); + (void) fprintf(siserr, "Present state: %s", save_ps); + (void) fprintf(siserr, " Input: %s\n", save_in); + goto bad_exit; + } + } + output++; + } else { + if (*out_state == '0') { + if (!bdd_is_tautology(bdd_test, 0)) { + (void) fprintf(siserr, "failed on latch output node "); + (void) fprintf(siserr, "(%s) ", node_name(po)); + (void) fprintf(siserr, "(should have been 0)\n"); + (void) fprintf(siserr, "Present state: %s", save_ps); + (void) fprintf(siserr, " Input: %s\n", save_in); + goto bad_exit; + } + } else if (*out_state == '1') { + if (!bdd_is_tautology(bdd_test, 1)) { + (void) fprintf(siserr, "failed on latch output node "); + (void) fprintf(siserr, "(%s) ", node_name(po)); + (void) fprintf(siserr, "(should have been 1)\n"); + (void) fprintf(siserr, "Present state: %s", save_ps); + (void) fprintf(siserr, " Input: %s\n", save_in); + goto bad_exit; + } + } + out_state++; + } + (void) bdd_free(bdd_test); + } + } /* close: foreach_primary_output(network, gen2, po) { */ + + (void) bdd_free(prod_bdd); + } /* close: stg_foreach_transition(network->stg, gen, e) { */ + + /* + * Free the manager. This has the side affect of free the bdd_t at every + * node in the network for which a BDD was created. + */ + (void) ntbdd_end_manager(manager); + (void) array_free(po_list); + + return 1; +bad_exit: + read_error("One of the STG edges did not simulate correctly"); + lsFinish(gen); + lsFinish(gen2); + (void) bdd_free(prod_bdd); /* probably superflous since freeing manager next */ + (void) bdd_free(bdd_test); + (void) ntbdd_end_manager(manager); + (void) array_free(po_list); + + return 0; +} + + +/* + * Returns whether node is a real primary input or output of the network. If + * node is not a PI or PO, it can't possibly be in latch_table, returns 0. If + * node is a latch input or latch output, returns 0, sets `latchp' non-nil. + * If node is a control signal, returns 0, sets `latchp' nil. If node is a + * real primary input or output, returns 1. + * + * A member of .clock is considered a real PI. + */ +static int +network_is_real_pio(network, node, latchp) +network_t *network; +node_t *node; +latch_t **latchp; +{ + st_table *latch_table; + network_t *net; + + net = node->network; + + if (net != network) { + abort(); + } + latch_table = net->latch_table; + if (st_lookup(latch_table, (char *) node, (char **) latchp) == 0) { + return(1); + } + return(0); +} + +int +network_is_real_po(network, node) +network_t *network; +node_t *node; +{ + latch_t *latch; + + if (node_type(node) != PRIMARY_OUTPUT) { + return(0); + } + return(network_is_real_pio(network, node, &latch)); +} + +int +network_is_real_pi(network, node) +network_t *network; +node_t *node; +{ + latch_t *latch; + + if (node_type(node) != PRIMARY_INPUT) { + return(0); + } + return(network_is_real_pio(network, node, &latch)); +} + +int +network_is_control(network, node) +network_t *network; +node_t *node; +{ + latch_t *latch; + + if (network_is_real_pio(network, node, &latch) == 0) { + return(latch == NIL(latch_t)); + } + return(0); +} + + +node_t * +network_get_control(network, control) +network_t *network; +node_t *control; +{ + lsGen gen; + node_t *fo; + + if (node_type(control) == PRIMARY_OUTPUT) { + control = node_get_fanin(control, 0); + } + foreach_fanout (control, gen, fo) { + if (node_type(fo) == PRIMARY_OUTPUT) { + if (network_is_control(network, fo) != 0) { + (void) lsFinish(gen); + return(fo); + } + } + } + return(NIL(node_t)); +} + + +/* + * Used for adding primary outputs that will be a latch input or a latch + * control. Should be used in the io package for the network to print out + * correctly. + */ +node_t * +network_add_fake_primary_output(network, node) +network_t *network; +node_t *node; +{ + node_t *out; + + out = network_add_primary_output(network, node); + network_swap_names(network, node, out); + return(out); +} + +/* + * Used only in io package. Problem: when creating the network, need to + * change the name for a fake primary output (a clock or latch) to be " #" + * where # is some number, so it cannot possibly conflict with a user + * specified name to come later. + * + * Postprocess: Change all the fake names that start with the " " to some + * other name. + */ +void +network_replace_io_fake_names(network) +network_t *network; +{ + lsGen gen; + st_table *name_table; + st_table *dc_name_table; + node_t *node; + + name_table = network->name_table; + if (network->dc_network != NIL(network_t)) { + dc_name_table = network->dc_network->name_table; + } else { + dc_name_table = NIL(st_table); + } + foreach_node (network, gen, node) { + if (node->name[0] == ' ') { + (void) st_delete(name_table, &node->name, NIL(char *)); + do { + node_assign_name(node); + } while ((st_is_member(name_table, node->name) != 0) || + (dc_name_table != NIL(st_table) && + st_is_member(dc_name_table, node->name) != 0)); + (void) st_insert(name_table, node->name, (char *) node); + } + } +} + + +/* Visited nodes backwards (towards pi's) */ +/* Jump across latches */ + +static void +snetwork_dfs_recur(node, visited) +node_t *node; +st_table *visited; +{ + char *dummy; + int i; + node_t *fanin; + + if (st_lookup(visited, (char *) node, &dummy)) { + return; + } + (void) st_insert(visited, (char *) node, NIL(char)); + foreach_fanin(node, i, fanin) { + snetwork_dfs_recur(fanin, visited); + } + if ((node_type(node) == PRIMARY_INPUT) && + ((fanin = network_latch_end(node)) != NIL(node_t))) { + snetwork_dfs_recur(fanin, visited); + } + return; +} + + +/* Return a table of all the nodes that have a PO in their transitive + fanout. This is sequential transitive fanout, so latches are traversed */ + +st_table * +snetwork_tfi_po(network) +network_t *network; +{ + st_table *visited; + lsGen gen; + node_t *po; + st_generator *sgen; + node_t *node; + char *dummy; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + + foreach_primary_output(network, gen, po) { + if (!network_is_real_po(network, po)) continue; + snetwork_dfs_recur(po, visited); + } + return visited; +} + +#endif /* SIS */ diff --git a/sis/network/net_verify.c b/sis/network/net_verify.c new file mode 100644 index 0000000..aed2ff6 --- /dev/null +++ b/sis/network/net_verify.c @@ -0,0 +1,184 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/net_verify.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "sis.h" + +int +net_verify_with_dc(network1, network2, method, verbose) +network_t *network1; +network_t *network2; +int method; +int verbose; +{ + network_t *dc1, *dc2; + network_t *net1, *net2; + network_t *or_net_dcnet(); + network_t *network_dc_network(); + int eql; + + /* + * Make sure method has an appropriate value. + */ + if ( (method != 0) && (method != 1) ) { + return 1; + } + + error_init(); + dc1= network_dc_network(network1); + dc2= network_dc_network(network2); + if ((dc1 == NIL (network_t)) && (dc2 == NIL (network_t))){ + eql = network_verify(network1, network2, method); + }else if ((dc1 != NIL (network_t)) && (dc2 != NIL (network_t))){ + eql = network_verify(dc1, dc2, method); + if (!eql){ + (void) fprintf(miserr, "%s", error_string()); + (void)fprintf(miserr,"External don't care networks are not equal.\n"); + return 0; + } + net1= or_net_dcnet(network1); + net2= or_net_dcnet(network2); + eql = network_verify(net1, net2, method); + network_free(net1); + network_free(net2); + }else{ + (void) fprintf(miserr,"External don't care networks are not equal.\n"); + return 0; + } + + /* + * Process the eql flag. Regardless of the value of eql, return 0. Returning 1 + * when the networks are not equal would indicate that we don't want to continue. + * However, we want to continue. + */ + if (eql) { + if (verbose) { + (void) fprintf(misout, "Networks compared equal.\n"); + } + } else { + (void) fprintf(miserr, "%s", error_string()); + (void) fprintf(miserr, "Networks are not equivalent.\n"); + } + return 0; +} + +int +network_verify(network1_t, network2_t, method) +network_t *network1_t; +network_t *network2_t; +int method; /* 0 - collapse, 1 - bdd, others - illegal */ +{ + network_t *network1, *network2; + node_t *po1, *po2, *node1, *node2, *new_node; + lsGen gen; + char errmsg[1024]; + int eql; + + network1 = network_dup(network1_t); + network2 = network_dup(network2_t); + + /* add a buffer if PO is directly connected to a PI */ + foreach_primary_output(network1, gen, po1) { + node1 = node_get_fanin(po1, 0); + if (node1->type == PRIMARY_INPUT) { + new_node = node_literal(node1, 1); + (void) network_add_node(network1, new_node); + assert(node_patch_fanin(po1, node1, new_node)); + } + } + foreach_primary_output(network2, gen, po2) { + node2 = node_get_fanin(po2, 0); + if (node2->type == PRIMARY_INPUT) { + new_node = node_literal(node2, 1); + (void) network_add_node(network2, new_node); + assert(node_patch_fanin(po2, node2, new_node)); + } + } + + /* + * Make sure that there is a 1-1 name correspondance between the primary outputs of + * the two networks. If not, report the differences, and then return. + */ + eql = 1; + foreach_primary_output(network1, gen, po1) { + po2 = network_find_node(network2, po1->name); + if ((po2 == NIL(node_t)) || (po2->type != PRIMARY_OUTPUT)) { + (void) sprintf(errmsg, "output '%s' only in network '%s'\n", + po1->name, network_name(network1)); + error_append(errmsg); + eql = 0; + } + } + foreach_primary_output(network2, gen, po2) { + po1 = network_find_node(network1, po2->name); + if ((po1 == NIL(node_t)) || (po1->type != PRIMARY_OUTPUT)) { + (void) sprintf(errmsg, "output '%s' only in network '%s'\n", + po2->name, network_name(network2)); + error_append(errmsg); + eql= 0; + } + } + if (eql == 0) { + return 0; + } + + /* + * Call the appropriate verification method. + */ + if (method == 0) { + eql = verify_by_collapse(network1, network2); + } else if (method == 1) { + eql = ntbdd_verify_network(network1, network2, DFS_ORDER, ALL_TOGETHER); + } else { + (void) fprintf(miserr, "Error: unknown verification method\n"); + return 0; + } + + network_free(network1); + network_free(network2); + return eql; +} + +int verify_by_collapse(network1, network2) +network_t *network1; +network_t *network2; +{ + node_t *po1, *po2, *node1, *node2; + lsGen gen; + char errmsg[1024]; + + (void) network_collapse(network1); + (void) network_collapse(network2); + + /* + * Assume calling routine has verified a 1-1 name correspondance between the primary outputs + * of the two networks. Quit after finding the first difference. TODO: add command line option + * to generate all output differences. + */ + foreach_primary_output(network1, gen, po1) { + po2 = network_find_node(network2, po1->name); + assert((po2 != NIL(node_t)) && (po2->type == PRIMARY_OUTPUT)); + /* + * Get the nodes driving the primary outputs. + */ + node1 = node_get_fanin(po1, 0); + node2 = node_get_fanin(po2, 0); + + if (! node_equal_by_name(node1, node2)) { + (void) sprintf(errmsg, "Networks differ on (at least) primary output %s\n", node_name(po1)); + error_append(errmsg); + return 0; + } + } + + /* + * All output functions verified successfully. + */ + return 1; +} + diff --git a/sis/network/netchk.c b/sis/network/netchk.c new file mode 100644 index 0000000..f5bb4cf --- /dev/null +++ b/sis/network/netchk.c @@ -0,0 +1,221 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/netchk.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:32 $ + * + */ +#include "sis.h" + + +static void +check_error(s, node) +char *s; +node_t *node; +{ + error_append("network_check: inconsistency detected"); + if (node != 0) { + error_append(" at "); + error_append(node_name(node)); + } + error_append(" -- "); + error_append(s); + error_append("\n"); +} + + +int +network_check(network) +network_t *network; +{ + int i, pin, found_pin, warn; + lsGen gen, gen1; + node_t *p, *p1, *fanin, *fanout, *found_fanout; + st_table *table; + char *key, *value, *data; + + warn = 0; + + /* Make sure each node is correct wrt its flags */ + foreach_node(network, gen, p) { + i = node_check(p); + if (i == 0) return 0; + if (i == 2) warn = 1; + } + + /* check that every node is in the network, and its fanin is as well */ + foreach_node(network, gen, p) { + if (p->network != network) { + check_error("node on network list not in network", p); + return 0; + } + gen1 = lsGenHandle(p->net_handle, &data, LS_BEFORE); + if ((node_t *) data != p) { + check_error("net handle messed up", p); + return 0; + } + LS_ASSERT(lsFinish(gen1)); + foreach_fanin(p, i, fanin) { + if (fanin->network != network) { + check_error("a fanin of a node is not in network", p); + return 0; + } + } + foreach_fanout(p, gen1, fanout) { + if (fanout->network != network) { + check_error("a fanout of a node is not in network", p); + return 0; + } + } + } + + foreach_primary_output(network, gen, p) { + if (p->type != PRIMARY_OUTPUT) { + check_error("node on PO list is not type PO", p); + return 0; + } + if (node_num_fanin(p) != 1) { + check_error("node on PO list has fanin not 1", p); + return 0; + } + if (node_num_fanout(p) != 0) { + check_error("node on PO list has fanout not 0", p); + return 0; + } + } + + foreach_primary_input(network, gen, p) { + if (p->type != PRIMARY_INPUT) { + check_error("node on PI list is not type PI", p); + return 0; + } + if (node_num_fanin(p) != 0) { + check_error("node on PI list has fanin not 0", p); + return 0; + } + } + + foreach_node(network, gen, p) { + switch(p->type) { + case PRIMARY_OUTPUT: + foreach_primary_output(network, gen1, p1) { + if (p == p1) { + LS_ASSERT(lsFinish(gen1)); + break; + } + } + if (p != p1) { + check_error("node has type PO, but is not on PO list", p); + return 0; + } + break; + + case PRIMARY_INPUT: + foreach_primary_input(network, gen1, p1) { + if (p == p1) { + LS_ASSERT(lsFinish(gen1)); + break; + } + } + if (p != p1) { + check_error("node has type PI, but is not on PI list", p); + return 0; + } + break; + + case INTERNAL: + foreach_fanin(p, i, fanin) { + found_fanout = 0; + found_pin = -1; + foreach_fanout_pin(fanin, gen1, p1, pin) { + if (p == p1 && i == pin) { + if (found_fanout != 0) { + check_error("fanout duplicated for some node", p); + return 0; + } + found_fanout = p1; + found_pin = pin; + } + } + if (p != found_fanout) { + check_error("fanout list of some fanin is corrupted", p); + return 0; + } + if (i != found_pin) { + check_error("fanout pin of some fanin is corrupted", p); + return 0; + } + } + + foreach_fanout_pin(p, gen1, fanout, pin) { + found_fanout = 0; + found_pin = -1; + foreach_fanin(fanout, i, p1) { + if (p == p1 && i == pin) { + if (found_fanout != 0) { + check_error("fanout duplicated for some node", p); + return 0; + } + found_fanout = p1; + found_pin = i; + } + } + if (p != found_fanout) { + check_error("fanin list of some fanout is corrupted", p); + return 0; + } + if (pin != found_pin) { + check_error("fanin pin of some fanout is corrupted", p); + return 0; + } + } + break; + + default: + check_error("node type is not PI, PO, or INTERNAL", p); + return 0; + } + } + + + table = st_copy(network->name_table); + foreach_node(network, gen, p) { + key = p->name; + if (! st_delete(table, &key, &value)) { + check_error("node name is not in name_table", p); + return 0; + } + if ((node_t *) value != p) { + check_error("node doesn't match in name_table", p); + return 0; + } + } + if (st_count(table) != 0) { + check_error("name_table contains superfluous entries", NIL(node_t)); + return 0; + } + st_free_table(table); + + table = st_copy(network->short_name_table); + foreach_node(network, gen, p) { + key = p->short_name; + if (! st_delete(table, &key, &value)) { + check_error("node short_name is not in short_name_table", p); + return 0; + } + if ((node_t *) value != p) { + check_error("node doesn't match in short_name_table", p); + return 0; + } + } + if (st_count(table) != 0) { + check_error("short_name_table contains superfluous entries", + NIL(node_t)); + return 0; + } + st_free_table(table); + + return warn ? 0 : 1; +} diff --git a/sis/network/netclp.c b/sis/network/netclp.c new file mode 100644 index 0000000..0e80ce1 --- /dev/null +++ b/sis/network/netclp.c @@ -0,0 +1,71 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/netclp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:33 $ + * + */ +#include "sis.h" + + +/* + * collapse boolean network to two-level functions. + */ + +int +network_collapse(network) +network_t *network; +{ + int i, changed; + node_t *node; + array_t *node_vec; + + /* order the nodes from a depth-first search */ + node_vec = network_dfs(network); + + /* collapse all of the nodes in dfs order */ + changed = 0; + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (node->type == INTERNAL) { + if (network_collapse_single(node)) { + changed = 1; + } + } + } + + /* final cleanup */ + if (network_cleanup(network)) { + changed = 1; + } + + array_free(node_vec); + return changed; +} + + +/* + * collapse a single node until it depends on primary inputs only + */ +int +network_collapse_single(node) +node_t *node; +{ + int j, changed, some_change; + node_t *fanin; + + changed = 0; + do { + some_change = 0; + foreach_fanin(node, j, fanin) { + if (node_collapse(node, fanin)) { + some_change = 1; + changed = 1; + break; + } + } + } while (some_change); + return changed; +} diff --git a/sis/network/netmake.c b/sis/network/netmake.c new file mode 100644 index 0000000..10b2b72 --- /dev/null +++ b/sis/network/netmake.c @@ -0,0 +1,82 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/netmake.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:33 $ + * + */ +#include "sis.h" + +network_t * +network_from_nodevec(nodevec) +array_t *nodevec; +{ + int i, j; + st_table *table; + node_t *node, *node_copy, *fanin, **new_fanin; + char *dummy; + network_t *new_network; + lsGen gen; + + new_network = network_alloc(); + + table = st_init_table(st_ptrcmp, st_ptrhash); + for(i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + (void) st_insert(table, (char *) node, (char *) node_dup(node)); + } + + for(i = 0; i < array_n(nodevec); ++i) { + node = array_fetch(node_t *, nodevec, i); + + new_fanin = ALLOC(node_t *, node_num_fanin(node)); + foreach_fanin(node, j, fanin) { + if (st_lookup(table, (char *) fanin, &dummy)) { + new_fanin[j] = (node_t *) dummy; + } else { + new_fanin[j] = node_alloc(); + new_fanin[j]->name = util_strsav(fanin->name); + network_add_primary_input(new_network, new_fanin[j]); + (void) st_insert(table, (char *) fanin, (char *) new_fanin[j]); + } + } + + (void) st_lookup(table, (char *) node, &dummy); + node_copy = (node_t *) dummy; + if (node->nin > 0) { + node_replace_internal(node_copy, new_fanin, + node->nin, sf_save(node->F)); + } else { + FREE(new_fanin); + } + network_add_node(new_network, node_copy); + } + + foreach_node(new_network, gen, node_copy) { + if (node_function(node_copy) != NODE_PO && + node_num_fanout(node_copy) == 0) { + (void) network_add_primary_output(new_network, node_copy); + } + } + + st_free_table(table); + return new_network; +} + + + +network_t * +network_create_from_node(user_node) +node_t *user_node; +{ + array_t *nodevec; + network_t *network; + + nodevec = array_alloc(node_t *, 10); + array_insert_last(node_t *, nodevec, user_node); + network = network_from_nodevec(nodevec); + array_free(nodevec); + return network; +} diff --git a/sis/network/network.doc b/sis/network/network.doc new file mode 100644 index 0000000..04dae2a --- /dev/null +++ b/sis/network/network.doc @@ -0,0 +1,501 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/network.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:33 $ + * + */ +network_t * +network_alloc() + Allocate and initialize a new network. + + +void +network_free(network) +network_t *network; + Free a network. + + +network_t * +network_dup(network) +network_t *network; + Make a duplicate copy of a network. + + +network_t * +network_create_from_node(node) +node_t *node; + Create a new network with a single internal node with the same logic + function as 'node'. Primary inputs will be created for this + new network with the same names as the fanins of 'node'. + + +char * +network_name(network) +network_t *network; + Returns the name of the network. Do not modify or free the returned + string. + + +void +network_set_name(network, name) +network_t *network; +char *name; + Sets the name of the network. 'name' is copied. + + +int +network_num_pi(network) +network_t *network; + Return the number of primary inputs for the network. + + +int +network_num_po(network) +network_t *network; + Return the number of primary outputs for the network. + + +int +network_num_internal(network) +network_t *network; + Return the number of internal nodes in the network. + + +node_t * +network_get_pi(network, index) +network_t *network; +int index; + Return the index'th primary input of the network. The primary + inputs are numbered starting from 0. Returns NIL(node_t) if + index >= network_num_pi(network). Potentially a very slow way + to access an arbitrary primary input. + + +node_t * +network_get_po(network, index) +network_t *network; +int index; + Return the index'th primary output of the network. The primary + outputs are numbered starting from 0. Returns NIL(node_t) if + index >= network_num_po(network). Potentially a very slow way + to access an arbitrary primary output. + + +int +network_check(network) +network_t *network; + Performs various consistency checks on a network. Used for + debugging the network package. If the network is constructed + using only the routines in this package, it should never fail + this check. Returns 1 if the network is okay, or 0 if the + network contains some internal inconsistency. In the case of + error, error_string() (see error.doc) can be used to retrieve + a description of the error. + +int +network_is_acyclic(network) +network_t *network; + Checks that the network does not contain a cycle. Returns 1 + if there are no cycles, or 0 if there is a cycle. In the case + of a cycle, error_string() (see error.doc) can be used to + retrieve a description of the nodes on the first cycle + encountered. + +/* Generators */ + + + +foreach_node(network, gen, node) +network_t *network; +lsGen gen; +node_t *node; + Generates over the all nodes in a network (that is, including + primary inputs and primary outputs). + + +foreach_primary_input(network, gen, pi) +network_t *network; +lsGen gen; +node_t *pi; + Generates over the primary inputs of a network. + + +foreach_primary_output(network, gen, po) +network_t *network; +lsGen gen; +node_t *po; + Generates over the primary outputs of a network. + + + + The generators are macro's. Typical usage is: + + foreach_node(network, gen, node) { + /* do something with node */ + } + + If the loop is terminated abnormally (i.e., with a break or return), + lsFinish() must be called on the generator. + + In general, the generator operation is not well-defined if any attempt + is made to add a node to the network during the generation loop. + +void +network_add_node(network, node) +network_t *network; +node_t *node; + Adds a node to the network. The node will be assigned + automatically generated names (both long and short) if it is + currently unnamed. It is a serious error if the node has the + same name (or same short_name) as any node already in the + network. + + +void +network_add_primary_input(network, node) +network_t *network; +node_t *node; + Adds a primary input node to the network. The node will be assigned + automatically generated names (both long and short) if it is + currently unnamed. It is a serious error if the node has the + same name (or same short_name) as any node already in the + network. + + +node_t * +network_add_primary_output(network, node) +network_t *network; +node_t *node; + Designate the node 'node' as a primary output node. Creates a + new primary output (of type PRIMARY_OUTPUT) node which is returned. + Node must be a node already in the network. + + +void +network_delete_node(network, node) +network_t *network; +node_t *node; + Deletes a node from the network. The behavior is undefined if + this routine is called from within a generator. It is a + serious error to attempt to delete a node which is not already + in the given network. + + +void +network_delete_node_gen(network, gen) +network_t *network; +lsGen gen; + Deletes the last node generated by the generator gen. Behavior + is well-defined when called from within a generator loop. It + is a serious error to attempt to delete a node which is not + already in the given network. + + +node_t * +network_find_node(network, name) +network_t *network; +char *name; + Find the node in the network with the given name. Note that + the behavior of this routine changes depending on the + name_mode variable (i.e., whether to look at the long names, + or the short names). + + + +void +network_change_node_type(network, node, new_type) +network_t *network; +node_t *node; +node_type_t new_type; /* see node.doc for definition */ + Change the type of a node. In particular, this can be + used to designate certain nodes as either primary inputs + or primary outputs. + + +void +network_change_node_name(network, node, new_name) +network_t *network; +node_t *node; +char *new_name; + Change the name of a node. new_name is taken directly; you may + wish to use strsav() to make a duplicate copy which is passed + to network_change_node_name. + + +int +network_collapse(network) +network_t *network; + Collapse a network into one level of nodes (i.e., two-level). + Returns 1 to indicate if the network changes, 0 otherwise. + + +int +network_sweep(network) +network_t *network; + Propogate (and eliminate) constant-valued nodes in the network. + Also deletes inverter and buffer nodes, and nodes which do not + fanout anywhere. Returns 1 if the network is changed, or + returns 0 if not. + + +int +network_cleanup(network) +network_t *network; + Removes internal nodes which do not fanout anywhere. Returns 1 + if the network is changed, or returns 0 if not. + + +array_t * +network_dfs(network) +network_t *network; + Returns a vector of nodes ordered in a depth-first manner from the + outputs. Includes PRIMARY_INPUT, PRIMARY_OUTPUT and INTERNAL nodes. + (The nodes are ordered such that every node appears somewhere after + all of its transitive fanin nodes.) + + +array_t * +network_dfs_from_input(network) +network_t *network; + Returns a vector of nodes ordered in a depth-first manner from the + inputs. Includes PRIMARY_INPUT, PRIMARY_OUTPUT and INTERNAL nodes. + (The nodes are ordered such that every node appears somewhere after + all of its transitive fanout nodes.) + + + +array_t * +network_tfi(node, level) +node_t *node; +int level; + Returns a vector of nodes ordered in a depth-first search towards + the primary inputs from a given node. Nodes up to a maximum depth + of level are returned. (Level 0 is no nodes, level 1 corresponds + to the immediate fanin nodes, etc.) The list includes PRIMARY_OUTPUT + nodes as appropriate. The list does NOT include the node `node' itself. + + +array_t * +network_tfo(node, level) +node_t *node; +int level; + Returns a vector of nodes ordered in a depth-first search towards + the primary outputs from a given node. Nodes up to a maximum depth + of level are returned. (Level 0 is no nodes, level 1 corresponds + to the immediate fanout nodes, etc.) The list includes PRIMARY_INPUT + nodes as appropriate. The list does NOT include the node `node' itself. + + +pPLA +network_to_pla(network) +network_t *network; + Returns the network as an Espresso PLA structure. A copy + is made of the network, this is collapsed to two-levels, and + then mapped into the Espresso multiple-output PLA format. + The original network is unaffected. The cube_size (that + nasty Espresso global variable) is set to reflect the PLA + that is returned. No other node/network operations may be + performed until discard_pla() is called. + + +pPLA +espresso_read_pla(fp) +FILE *fp; + Uses the espresso PLA read routine to read a PLA from a file. + Returns NIL(PLA_t) if there is any error reading the PLA. + The cube_size (that nasty Espresso global variable) is set + to reflect the PLA that is returned. No other node/network + operations may be performed until discard_pla() is called. + + +void +discard_pla(PLA) +pPLA PLA; + After using network_to_pla(), or espresso_read_pla(), normal + node/network operations CANNOT be performed until the PLA + is discarded using this routine. Free's the PLA, and restores + the `cube' for normal SIS operation. + + +network_t * +pla_to_network(PLA) +pPLA PLA; + Maps a PLA into a network. This creates a two-level structure + of NOR-NOR gates (surrounded by inverters to get the phase + correct). That is, each node in the resulting network will be + either an inverter, or a NOR gate. Assumes the Espresso global + variable `cube' accurately describes the layout of the PLA. + (This will be the case if the PLA is created using + network_to_pla(), or espresso_read_pla().) If the PLA is not a + multiple-output PLA (i.e., if it contains any multiple-valued + variables), then NIL(network_t) is returned. + + + +network_t * +network_espresso(network) +network_t *network; + Runs espresso on a network and returns the optimized network. + Uses pla_to_network() to create a NOR-NOR network. The original + network is unaffected. + + + +void +network_reset_long_name(network) +network_t *network; + Re-create unique names for all nodes which have 'made-up' names. + (i.e., a name of the form [%d]). Also renumbers them starting + from 1. + + +void +network_reset_short_name(network) +network_t *network; + Re-create short names for all nodes. Renumbers the short names + starting with a. Primary inputs and primary outputs are + assigned the lowest valued names, followed by internal nodes. + +The following routines are for supporting sequential extensions: + +node_t * +network_latch_end(node) +node_t *node; + + Returns the other end of the latch associated with the `node'. + If there is no latch associated will return NIL(node_t). + It is a serious error if `node' is not part of a network. + +void +network_create_latch(network, l, n1, n2) +network_t *network; +latch_t **l; +node_t *n1, *n2; + + Insert a latch between nodes n1 and n2. If node n1 is a fanin + of node n2, a latch is inserted between them, and the new latch + structure is returned through the variable l. The fields for the + new latch can be filled in using the latch package routines (e.g. + latch_set_initial_value). The input and output fields should not + be touched. + + If node n1 is a primary output and node n2 is a primary input, and + there is already a latch between them, that latch is returned. + + If node n1 is a primary output and node n2 is a primary input and + neither is already part of a latch, a latch is created between + them and the structure is returned. Warning: the primary output + node that is passed in will no longer be observable as a primary + output, it is now only a latch input. To maintain the observability + property, an extra primary output node must be created by the user. + This function is intended to be used with network_disconnect and + network_connect when passed a primary output and a primary input node. + + If any other combination of nodes is given, the routine prints + a warning message and fails. + +void +network_delete_latch(network, l) +network_t *network; +latch_t *l; + + Delete the latch l from the network. The latch definition is + deleted from the network's list of latches and the latch data + structure is freed. The input and output nodes of the latch + remain unchanged. To reconnect the input and output nodes of + the latch, the routine network_connect must be called. Note + that if a latch is deleted, and its input and output nodes are + reconnected, the don't care network should be updated + accordingly - it may depend on these two nodes. + +void +network_disconnect(node1, node2, po_ptr, pi_ptr) +node_t *node1, *node2, **po_ptr, **pi_ptr; + + Breaks the net between `node1' and `node2'. The broken net now + has a primary output node (returned by *po_ptr) attached to `node1' + and a primary input node (returned by *pi_ptr) that fans into + `node2' instead of `node1'. `node1' and `node2' must belong to + the same network. + +void +network_connect(node1, node2) +node_t *node1, *node2; + + `node1' should be of type primary output and `node2' should be + of type primary input. These two are electrically shorted and + removed from the network. i.e. in each fanout of `node2', `node2' + is replaced by the input of `node1'. + +int +network_num_latch(network) +network_t *network; + + Returns the number of latches currently in the network. + +graph_t * +network_stg(network) +network_t *network; + + Given a network, returns the associated state transition graph, or + NULL if no graph exists. + +void +network_set_stg(network,stg) +network_t *network; +graph_t *stg; + + Sets the stg for `network' to `stg'. + + +int +network_stg_check(network) +network_t *network; + + Returns 1 if the network covers its stg, 0 otherwise. + +int +network_is_real_po(network, node) +network_t *network; +node_t *node; + + Returns 1 if the node is a real primary output of the network, + 0 otherwise. (Some node with type primary output are really + the inputs to latches or the outputs of latch control nodes.) + +int +network_is_real_pi(network, node) +network_t *network; +node_t *node; + + Returns 1 if the node is a real primary output of the network, + 0 otherwise. + +int +network_is_control(network, node) +network_t *network; +node_t *node; + + Returns 1 if the node is a latch control node of the network, + 0 otherwise. + +node_t * +network_get_control(network, control) +network_t *network; +node_t *control; + + If the node 'control' is actually a latch control node or the + latch-control primary output of a control node, the primary-output + latch-control is returned. Otherwise, NIL(node_t) is returned. + +/* Sequential Generators */ + +foreach_latch(network, gen, l) +network_t *network; +lsGen gen; +latch_t *l; + + Generates over all latches in a network. diff --git a/sis/network/network.h b/sis/network/network.h new file mode 100644 index 0000000..c0bc374 --- /dev/null +++ b/sis/network/network.h @@ -0,0 +1,149 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/network.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:33 $ + * + */ +#ifndef NETWORK_H +#define NETWORK_H + + +#define lsForeachItem(list, gen, data) \ + for(gen = lsStart(list); \ + (lsNext(gen, (lsGeneric *) &data, LS_NH) == LS_OK) \ + || ((void) lsFinish(gen), 0); ) + +#define LS_ASSERT(fct) assert((fct) == LS_OK) + + +/*typedef struct network_struct network_t;*/ +struct network_struct { + char *net_name; + st_table *name_table; + st_table *short_name_table; + lsList nodes; /* list of all nodes */ + lsList pi; /* list of just primary inputs */ + lsList po; /* list of just primary outputs */ + network_t *original; /* UNUSED: pointer to original network */ + double area; /* HACK: support area keyword */ + int area_given; /* HACK: support area keyword */ + lsList bdd_list; /* list of bdd managers */ + network_t *dc_network; /* external don't care network */ +#ifdef SIS + st_table *latch_table; /* sequential support */ + lsList latch; /* sequential support */ + graph_t *stg; /* sequential support */ + char *clock; /* sequential support */ +#endif /* SIS */ + char *default_delay; /* Stores default delay info */ +#ifdef SIS + astg_t *astg; /* Asynch. Signal Transition Graph. */ +#endif +}; + + +#define foreach_node(network, gen, p) \ + lsForeachItem((network)->nodes, gen, p) + +#define foreach_primary_input(network, gen, p) \ + lsForeachItem((network)->pi, gen, p) + +#define foreach_primary_output(network, gen, p) \ + lsForeachItem((network)->po, gen, p) + +#ifdef SIS +#define foreach_latch(network, gen, l) \ + lsForeachItem((network)->latch, gen, l) +#endif /* SIS */ + +EXTERN network_t *network_alloc ARGS((void)); +EXTERN void network_free ARGS((network_t *)); +EXTERN network_t *network_dup ARGS((network_t *)); +EXTERN network_t *network_create_from_node ARGS((node_t *)); +EXTERN network_t *network_from_nodevec ARGS((array_t *)); + +EXTERN char *network_name ARGS((network_t *)); +EXTERN void network_set_name ARGS((network_t *, char *)); +EXTERN int network_num_pi ARGS((network_t *)); +EXTERN int network_num_po ARGS((network_t *)); +EXTERN int network_num_internal ARGS((network_t *)); +EXTERN node_t *network_get_pi ARGS((network_t *, int)); +EXTERN node_t *network_get_po ARGS((network_t *, int)); + +EXTERN void network_add_node ARGS((network_t *, node_t *)); +EXTERN void network_add_primary_input ARGS((network_t *, node_t *)); +EXTERN node_t *network_add_primary_output ARGS((network_t *, node_t *)); +EXTERN void network_delete_node ARGS((network_t *, node_t *)); +EXTERN void network_delete_node_gen ARGS((network_t *, lsGen)); +EXTERN node_t *network_find_node ARGS((network_t *, char *)); +EXTERN void network_change_node_type ARGS((network_t *, node_t *, enum node_type_enum)); +EXTERN void network_change_node_name ARGS((network_t *, node_t *, char *)); + +EXTERN int network_check ARGS((network_t *)); +EXTERN int network_is_acyclic ARGS((network_t *)); +EXTERN int network_collapse ARGS((network_t *)); +EXTERN int network_sweep ARGS((network_t *)); +EXTERN int network_csweep ARGS((network_t *)); +EXTERN int network_cleanup ARGS((network_t *)); +EXTERN int network_ccleanup ARGS((network_t *)); +EXTERN network_t *network_espresso ARGS((network_t *)); + +EXTERN array_t *network_dfs ARGS((network_t *)); +#ifdef SIS +EXTERN array_t *network_special_dfs ARGS((network_t *)); +#endif /* SIS */ +EXTERN array_t *network_dfs_from_input ARGS((network_t *)); +EXTERN array_t *network_tfi ARGS((node_t *, int)); +EXTERN array_t *network_tfo ARGS((node_t *, int)); + +EXTERN int network_append ARGS((network_t *, network_t *)); + +EXTERN pPLA espresso_read_pla ARGS((FILE *)); +EXTERN void discard_pla ARGS((pPLA )); +EXTERN pPLA network_to_pla ARGS((network_t *)); +EXTERN network_t *pla_to_network ARGS((pPLA )); +EXTERN network_t *pla_to_network_single ARGS((pPLA )); +EXTERN network_t *pla_to_dcnetwork_single ARGS((pPLA )); + +EXTERN void network_reset_long_name ARGS((network_t *)); +EXTERN void network_reset_short_name ARGS((network_t *)); +EXTERN void network_swap_names ARGS((network_t *, node_t *, node_t *)); + +#ifdef SIS + +EXTERN void copy_latch_info ARGS((lsList, lsList, st_table *)); + /* network_create_latch, network_delete_latch declared in latch.h */ +EXTERN node_t *network_latch_end ARGS((node_t *)); +EXTERN void network_disconnect ARGS((node_t *,node_t *,node_t **,node_t **)); +EXTERN void network_connect ARGS((node_t *,node_t *)); +EXTERN st_table *snetwork_tfi_po ARGS((network_t *)); + +#define network_num_latch(n) \ + lsLength((n)->latch) + +EXTERN graph_t *network_stg ARGS((network_t *)); +EXTERN void network_set_stg ARGS((network_t *,graph_t *)); +EXTERN int network_stg_check ARGS((network_t *)); + +EXTERN int network_is_real_po ARGS((network_t *,node_t *)); +EXTERN int network_is_real_pi ARGS((network_t *,node_t *)); +EXTERN int network_is_control ARGS((network_t *,node_t *)); +EXTERN node_t *network_get_control ARGS((network_t *,node_t *)); +EXTERN node_t *network_add_fake_primary_output ARGS((network_t *,node_t *)); +EXTERN void network_replace_io_fake_names ARGS((network_t *)); + +#endif /* SIS */ + + /* network_bdd_list, network_add_bdd declared in bdd.h */ + +EXTERN int network_verify ARGS((network_t *, network_t *, int)); +EXTERN int net_verify_with_dc ARGS((network_t *, network_t *, int, int)); +EXTERN network_t *network_dc_network ARGS((network_t *)); +EXTERN st_table *attach_dcnetwork_to_network ARGS((network_t *)); +EXTERN node_t *find_ex_dc ARGS((node_t *, st_table *)); +EXTERN network_t *or_net_dcnet ARGS((network_t *)); + +#endif diff --git a/sis/network/network_util.c b/sis/network/network_util.c new file mode 100644 index 0000000..c17002d --- /dev/null +++ b/sis/network/network_util.c @@ -0,0 +1,805 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/network_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:33 $ + * + */ +#include "sis.h" + +typedef struct cpexdc_struct{ + node_t *node; +} cpexdc_type_t; + +#define OBS cspf +#define CPEXDC(node) ((cpexdc_type_t *) (node)->OBS) + +static void duplicate_list(); +static void copy_list(); +static void reset_io(); + +extern void network_rehash_names(); + +static void +cpexdc_alloc(node) +node_t *node; +{ + node->OBS = (char *) ALLOC(cpexdc_type_t, 1); + CPEXDC(node)->node= NIL(node_t); +} + +static void +cpexdc_free(node) +node_t *node; +{ + FREE(node->OBS); +} + + +network_t * +network_alloc() +{ + network_t *net; + + net = ALLOC(network_t, 1); + net->net_name = NIL(char); + net->name_table = st_init_table(strcmp, st_strhash); + net->short_name_table = st_init_table(strcmp, st_strhash); + net->nodes = lsCreate(); + net->pi = lsCreate(); + net->po = lsCreate(); + net->original = NIL(network_t); + net->dc_network = NIL(network_t); + net->area_given = 0; + net->area = 0.0; + net->bdd_list = lsCreate(); + net->default_delay = NIL(char); +#ifdef SIS + net->latch_table = st_init_table(st_ptrcmp, st_ptrhash); + net->latch = lsCreate(); + net->stg = NIL(graph_t); + net->astg = NIL(astg_t); + network_clock_alloc(net); +#endif /* SIS */ + return net; +} + + +void +network_free(net) +network_t *net; +{ + if (net != NIL(network_t)) { + FREE(net->net_name); + st_free_table(net->name_table); + st_free_table(net->short_name_table); + LS_ASSERT(lsDestroy(net->pi, (void (*)()) 0)); + LS_ASSERT(lsDestroy(net->po, (void (*)()) 0)); + LS_ASSERT(lsDestroy(net->nodes, node_free)); + network_free(net->original); + network_free(net->dc_network); + LS_ASSERT(lsDestroy(net->bdd_list, (void (*)()) 0)); + delay_network_free(net); +#ifdef SIS + st_free_table(net->latch_table); + LS_ASSERT(lsDestroy(net->latch, free)); + stg_free(net->stg); + net->stg = NIL(graph_t); + network_clock_free(net); + astg_free (net->astg); +#endif /* SIS */ + FREE(net); + } +} + + +network_t * +network_dup(old) +network_t *old; +{ + network_t *new; + + if (old == NIL(network_t)) { + return(NIL(network_t)); + } + new = network_alloc(); + + if (old->net_name != NIL(char)) { + new->net_name = util_strsav(old->net_name); + } + + duplicate_list(old->nodes, new->nodes, new); + copy_list(old->pi, new->pi); + copy_list(old->po, new->po); + + network_rehash_names(new, /* long */ 1, /* short */ 1); + + /* this makes sure fanout pointers are up-to-date */ + reset_io(new->nodes); + + /* This makes sure that the global delay information is copied */ + delay_network_dup(new, old); + + /* this makes sure that MAP(node)->save_binding pointers are up-to-date */ + map_network_dup(new); + + new->original = network_dup(old->original); + new->dc_network = network_dup(old->dc_network); + new->area_given = old->area_given; + new->area = old->area; +#ifdef SIS + copy_latch_info(old->latch, new->latch, new->latch_table); + new->stg = stg_dup(old->stg); + new->astg = astg_dup(old->astg); + network_clock_dup(old, new); +#endif /* SIS */ + return new; +} + +network_num_pi(network) +network_t *network; +{ + return lsLength(network->pi); +} + + +network_num_po(network) +network_t *network; +{ + return lsLength(network->po); +} + + +network_num_internal(network) +network_t *network; +{ + return lsLength(network->nodes) - + (lsLength(network->pi) + lsLength(network->po)); +} + + +node_t * +network_get_pi(network, index) +network_t *network; +int index; +{ + int i; + lsGen gen; + node_t *node; + + i = 0; + foreach_primary_input(network, gen, node) { + if (i++ == index) { + (void) lsFinish(gen); + return node; + } + } + return 0; +} + + +node_t * +network_get_po(network, index) +network_t *network; +int index; +{ + int i; + lsGen gen; + node_t *node; + + i = 0; + foreach_primary_output(network, gen, node) { + if (i++ == index) { + (void) lsFinish(gen); + return node; + } + } + return 0; +} + +void +network_add_primary_input(network, node) +network_t *network; +node_t *node; +{ + node->type = PRIMARY_INPUT; + node->nin = 0; + FREE(node->fanin); + node->fanin = 0; + network_add_node(network, node); +} + + +node_t * +network_add_primary_output(network, node) +network_t *network; +node_t *node; +{ + node_t *output; + + output = node_alloc(); + output->type = PRIMARY_OUTPUT; + output->nin = 1; + output->fanin = ALLOC(node_t *, 1); + output->fanin[0] = node; + network_add_node(network, output); + network_swap_names(network, node, output); + return output; +} + + +void +network_add_node(network, node) +network_t *network; +node_t *node; +{ + int value; + lsHandle handle; + network_t *dc_net; + + if (node->type == UNASSIGNED) node->type = INTERNAL; + + if (node->name == NIL(char)) node_assign_name(node); + if (node->short_name == NIL(char)) node_assign_short_name(node); + + /* + * force made-up names to be unique when added to network + */ + if (node_is_madeup_name(node->name, &value)) { + + dc_net = network->dc_network; + while (( (dc_net != NIL(network_t) && st_lookup(dc_net->name_table, node->name, NIL(char *)))) + || st_lookup(network->name_table, node->name, NIL(char *))) { + node_assign_name(node); + } + if (network->dc_network != NIL (network_t)){ + while (st_lookup(network->name_table, node->name, NIL(char *))) { + node_assign_name(node); + } + } + } + if (st_insert(network->name_table, node->name, (char *) node)) { + fail("attempt to add node with same name as some existing node"); + } + + + /* + * force short names to be unique when added to network + */ + while (st_lookup(network->short_name_table, node->short_name, NIL(char *))){ + node_assign_short_name(node); + } + if (st_insert(network->short_name_table, node->short_name, (char *) node)) { + fail("attempt to add node with same short_name as some existing node"); + } + + + if (node->type == PRIMARY_INPUT) { + LS_ASSERT(lsNewEnd(network->pi, (lsGeneric) node, LS_NH)); + } + if (node->type == PRIMARY_OUTPUT) { + LS_ASSERT(lsNewEnd(network->po, (lsGeneric) node, LS_NH)); + } + LS_ASSERT(lsNewEnd(network->nodes, (lsGeneric) node, &handle)); + node->network = network; + node->net_handle = handle; + + /* patch the fanout lists for our fanin's */ + fanin_add_fanout(node); +} + +void +network_delete_node(network, node) +network_t *network; +node_t *node; +{ + char *data; + lsGen gen; + + if (node->network != network) { + fail("network_delete_node: attempt to delete node not in network"); + } + + gen = lsGenHandle(node->net_handle, &data, LS_AFTER); + assert((node_t *) data == node); /* Paranoid */ + network_delete_node_gen(network, gen); + LS_ASSERT(lsFinish(gen)); +} + + +void +network_delete_node_gen(network, gen) +network_t *network; +lsGen gen; +{ + char *key; + node_t *node; + + /* Unlink from the node list */ + LS_ASSERT(lsDelBefore(gen, (lsGeneric *) &node)); + + /* force deletion from PI/PO lists */ + network_change_node_type(network, node, INTERNAL); + + key = node->name; + if (! st_delete(network->name_table, &key, NIL(char *))) { + fail("network_delete_node_gen: node name not in name table"); + } + assert(key == node->name); + + key = node->short_name; + if (! st_delete(network->short_name_table, &key, NIL(char *))) { + fail("network_delete_node_gen: node short name not in name table"); + } + assert(key == node->short_name); + + /* patch the fanout lists for our fanins */ + fanin_remove_fanout(node); + + node->network = 0; /* avoid recursion ... */ + node->net_handle = 0; + node_free(node); +} + +node_t * +network_find_node(network, name) +network_t *network; +char *name; +{ + char *dummy; + + if (st_lookup(network->name_table, name, &dummy)) { + return (node_t *) dummy; + } else { + return 0; + } +} + +static int +delete_from_list(list, node) +lsList list; +node_t *node; +{ + lsGen gen; + node_t *data; + + lsForeachItem(list, gen, data) { + if (data == node) { + LS_ASSERT(lsDelBefore(gen, (lsGeneric *) &data)); + LS_ASSERT(lsFinish(gen)); + return 1; + } + } + return 0; +} + + + +void +network_change_node_type(network, node, new_type) +network_t *network; +node_t *node; +node_type_t new_type; +{ + if (node->type == PRIMARY_INPUT) { + if (! delete_from_list(network->pi, node)) { + fail("network_change_node_type: PI node not in PI list"); + } + } else if (node->type == PRIMARY_OUTPUT) { + if (! delete_from_list(network->po, node)) { + fail("network_change_node_type: PO node not in PO list"); + } + } + + node->type = new_type; + if (node->type == PRIMARY_INPUT) { + LS_ASSERT(lsNewEnd(network->pi, (lsGeneric) node, LS_NH)); + } else if (node->type == PRIMARY_OUTPUT) { + LS_ASSERT(lsNewEnd(network->po, (lsGeneric) node, LS_NH)); + } +} + +char * +network_name(network) +network_t *network; +{ + if (network->net_name == NIL(char)) { + return "unknown"; + } else { + return network->net_name; + } +} + + +void +network_set_name(network, name) +network_t *network; +char *name; +{ + FREE(network->net_name); + network->net_name = util_strsav(name); +} + +static void +reset_io(list) +lsList list; +{ + lsGen gen; + node_t *node, *fanin; + int i; + + lsForeachItem(list, gen, node) { + foreach_fanin(node, i, fanin) { + node->fanin[i] = fanin->copy; + } + fanin_add_fanout(node); + } +} + + +static void +copy_list(list, newlist) +lsList list, newlist; +{ + lsGen gen; + node_t *node; + + lsForeachItem(list, gen, node) { + LS_ASSERT(lsNewEnd(newlist, (lsGeneric) node->copy, LS_NH)); + } +} + + +static void +duplicate_list(list, newlist, newnetwork) +lsList list, newlist; +network_t *newnetwork; +{ + lsGen gen; + node_t *node, *newnode; + lsHandle handle; + + lsForeachItem(list, gen, node) { + newnode = node_dup(node); + node->copy = newnode; + LS_ASSERT(lsNewEnd(newlist, (lsGeneric) newnode, &handle)); + newnode->network = newnetwork; + newnode->net_handle = handle; + } +} + + +#ifdef SIS + +void +copy_latch_info(list, newlist, newtable) +lsList list, newlist; +st_table *newtable; +{ + lsGen gen; + latch_t *latch, *l; + node_t *input, *output; + + lsForeachItem(list, gen, latch) { + l = latch_alloc(); + input = (latch_get_input(latch))->copy; + output = (latch_get_output(latch))->copy; + latch_set_input(l, input); + latch_set_output(l, output); + latch_set_initial_value(l, latch_get_initial_value(latch)); + latch_set_current_value(l, latch_get_current_value(latch)); + latch_set_type(l, latch_get_type(latch)); + latch_set_gate(l, latch_get_gate(latch)); + if (latch_get_control(latch) != NIL(node_t)) { + latch_set_control(l, (latch_get_control(latch)->copy)); + } + (void) st_insert(newtable, (char *) input, (char *) l); + (void) st_insert(newtable, (char *) output, (char *) l); + LS_ASSERT(lsNewEnd(newlist, (lsGeneric) l, LS_NH)); + } + return; +} + +#endif /* SIS */ + +void +network_change_node_name(network, node, new_name) +network_t *network; +node_t *node; +char *new_name; +{ + char *key; + + key = node->name; + if (! st_delete(network->name_table, &key, NIL(char *))) { + fail("network_change_name: node not found in name table"); + } + assert(key == node->name); + + FREE(node->name); + node->name = new_name; + if (st_insert(network->name_table, node->name, (char *) node)) { + fail("network_change_name: node with same name already exists"); + } +} + + + +void +network_change_node_short_name(network, node, new_name) +network_t *network; +node_t *node; +char *new_name; +{ + char *key; + + key = node->short_name; + if (! st_delete(network->short_name_table, &key, NIL(char *))) { + fail("change_short_name: node not found in name table"); + } + assert(key == node->short_name); + + node->short_name = new_name; + if (st_insert(network->short_name_table, node->short_name, (char *) node)) { + fail("change_short_name: node with same name already exists"); + } +} + +void +network_swap_names(network, node1, node2) +network_t *network; +node_t *node1; +node_t *node2; +{ + char *key; + + key = node1->name; + assert(st_delete(network->name_table, &key, NIL(char *))); + key = node2->name; + assert(st_delete(network->name_table, &key, NIL(char *))); + key = node1->short_name; + assert(st_delete(network->short_name_table, &key, NIL(char *))); + key = node2->short_name; + assert(st_delete(network->short_name_table, &key, NIL(char *))); + + key = node1->name; + node1->name = node2->name; + node2->name = key; + + key = node1->short_name; + node1->short_name = node2->short_name; + node2->short_name = key; + + assert(! st_insert(network->name_table, node1->name, (char *) node1)); + assert(! st_insert(network->name_table, node2->name, (char *) node2)); + assert(! st_insert(network->short_name_table, node1->short_name, (char *) node1)); + assert(! st_insert(network->short_name_table, node2->short_name, (char *) node2)); +} + +lsList +network_bdd_list(network) +network_t *network; +{ + return(network->bdd_list); +} + +lsHandle +network_add_bdd(network,bdd) +network_t *network; +bdd_manager *bdd; +{ + lsHandle h; + (void) lsNewBegin(network->bdd_list,(lsGeneric) bdd,&h); + return(h); +} + + +network_t * +network_dc_network(network) +network_t *network; +{ + return(network->dc_network); +} + +/* connects primary inputs and primary outputs of the two network through + * a hash table. + */ +st_table * +attach_dcnetwork_to_network(network) +network_t *network; +{ + st_table *node_exdc_table; + node_t *node, *nodedc; + network_t *DC_network; + int i,j; + + if(network == NULL) { + return NIL(st_table); + } + DC_network = network_dc_network(network); + if(DC_network == NULL) { + return NIL(st_table); + } + node_exdc_table = st_init_table(st_ptrcmp, st_ptrhash); + + for(i=0 ; i< network_num_po(network); i++){ + node= network_get_po(network, i); + for(j=0 ; j< network_num_po(DC_network); j++){ + nodedc= network_get_po(DC_network, j); + if (strcmp(nodedc->name, node->name) == 0) + (void)st_insert(node_exdc_table, (char *) node, (char *) nodedc); + } + } + for(i=0 ; i< network_num_pi(network); i++){ + node= network_get_pi(network, i); + for(j=0 ; j< network_num_pi(DC_network); j++){ + nodedc= network_get_pi(DC_network, j); + if (strcmp(nodedc->name, node->name) == 0){ + (void)st_insert(node_exdc_table, (char *) nodedc, (char *) node); + } + } + } + return node_exdc_table; +} + +network_t * +or_net_dcnet(network) +network_t *network; +{ + node_t *node, *dcnode, *dcfanin; + node_t *n1, *n2, *n3, *n4; + node_t *tempnode; + int i,j,k; + pset last, setp; + network_t *DC_network; + array_t *dc_list; + st_table *node_exdc_table; + node_t *po; + network_t *net; + char *dummy; + + net= network_dup(network); + node_exdc_table = attach_dcnetwork_to_network(net); + DC_network = network_dc_network(net); + + dc_list= network_dfs(DC_network); + for(i=0 ; i< array_n(dc_list); i++){ + dcnode = array_fetch(node_t *, dc_list, i); + cpexdc_alloc(dcnode); + if (node_function(dcnode) == NODE_PI){ + assert(st_lookup(node_exdc_table, (char *) dcnode, &dummy)); + node= (node_t *) dummy; + CPEXDC(dcnode)->node = node; + continue; + } + if (node_function(dcnode) == NODE_PO){ + dcfanin= node_get_fanin(dcnode, 0); + CPEXDC(dcnode)->node= CPEXDC(dcfanin)->node; + continue; + } + + n3= node_constant(0); + foreach_set(dcnode->F, last, setp) { + n1= node_constant(1); + for(k=0 ; k< dcnode->nin; k++){ + if ((j= GETINPUT(setp,k))!= TWO){ + if (j== ONE){ + dcfanin= node_get_fanin(dcnode,k); + tempnode= CPEXDC(dcfanin)->node; + n4= node_literal(tempnode,1); + n2= node_and(n1, n4); + node_free(n4); + node_free(n1); + n1= n2; + }else{ + dcfanin= node_get_fanin(dcnode,k); + tempnode= CPEXDC(dcfanin)->node; + n4= node_literal(tempnode,0); + n2= node_and(n1, n4); + node_free(n4); + node_free(n1); + n1= n2; + } + } + } + n2= node_or(n1,n3); + node_free(n1); + node_free(n3); + n3= n2; + } + CPEXDC(dcnode)->node = n3; + network_add_node(net, n3); + } + + for(i=0 ; i< network_num_po(net); i++){ + po= network_get_po(net, i); + assert(st_lookup(node_exdc_table, (char *) po, &dummy)); + node= (node_t *) dummy; + n1= CPEXDC(node)->node; + n2= node_get_fanin(po, 0); + if (node_function(n2) == NODE_PI){ + n4= node_literal(n2, 1); + n3= node_or(n1, n4); + node_free(n4); + }else{ + n3= node_or(n1, n2); + } + network_add_node(net, n3); + node_patch_fanin(po, n2, n3); + } + for(i=0 ; i< array_n(dc_list); i++){ + dcnode = array_fetch(node_t *, dc_list, i); + cpexdc_free(dcnode); + } + st_free_table(node_exdc_table); + array_free(dc_list); + return(net); +} + +/* find the external don't care for each primary output and express it in + * terms of the primary inputs of the care network. + * each primary output or primary input of the don't care network corresponds + * to a primary ouput or primary input of the care network through a hash + * table. + */ +node_t * +find_ex_dc(ponode, node_exdc_table) +node_t *ponode; /*primary output of the care network*/ +st_table *node_exdc_table; + +{ + node_t *dcnodep; + node_t *n1, *n2, *n3, *n4; + node_t *tempnode; + int j,k; + pset last, setp; + char *dummy; + +/* find the corresponding PO in the don't care network from the hash table*/ + if (node_exdc_table == NIL(st_table)) { + return(node_constant(0)); + } + if(!st_lookup(node_exdc_table, (char *) ponode, &dummy)) + return(node_constant(0)); + tempnode= (node_t *) dummy; + dcnodep= node_get_fanin(tempnode,0); + +/* generate external don't care function for PO in the care network*/ + n3= node_constant(0); + if (dcnodep->F == 0) return n3; + foreach_set(dcnodep->F, last, setp) { + n1= node_constant(1); + for(k=0 ; k< dcnodep->nin; k++){ + if ((j= GETINPUT(setp,k))!= TWO){ + if (j== ONE){ + tempnode= node_get_fanin(dcnodep,k); + (void)st_lookup(node_exdc_table, (char *) tempnode, &dummy); + tempnode= (node_t *) dummy; + n4= node_literal(tempnode,1); + n2= node_and(n1, n4); + node_free(n4); + node_free(n1); + n1= n2; + }else{ + tempnode= node_get_fanin(dcnodep,k); + (void)st_lookup(node_exdc_table, (char *) tempnode, &dummy); + tempnode= (node_t *) dummy; + n4= node_literal(tempnode,0); + n2= node_and(n1, n4); + node_free(n4); + node_free(n1); + n1= n2; + } + } + } + n2= node_or(n1,n3); + node_free(n1); + node_free(n3); + n3= n2; + } + return(n3); +} + + diff --git a/sis/network/pla2net.c b/sis/network/pla2net.c new file mode 100644 index 0000000..38b10ac --- /dev/null +++ b/sis/network/pla2net.c @@ -0,0 +1,275 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/pla2net.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:33 $ + * + */ +#include "sis.h" + + +network_t * +pla_to_network(PLA) +pPLA PLA; +{ + network_t *network; + node_t *node, *node1, **inputs, **pterms; + int out, ninputs, npterms; + register pset p, pnew; + register int var, i, k; + + /* we can only handle binary-valued PLAs */ + if (cube.num_binary_vars+1 != cube.num_vars) return 0; + + network = network_alloc(); + + /* Create a node for each primary input */ + ninputs = 0; + inputs = ALLOC(node_t *, cube.num_binary_vars); + for(var = 0; var < cube.num_binary_vars; var++) { + if (network_find_node(network, PLA->label[2*var+1]) != NIL(node_t)) { + (void) fprintf(siserr, "Error reading pla: node %s is already in the network.\n", PLA->label[2*var+1]); + network_free(network); + FREE(inputs); + return NIL(network_t); + } + node = node_alloc(); + node->name = util_strsav(PLA->label[2*var+1]); + inputs[ninputs++] = node; + network_add_primary_input(network, node); + } + + + /* Create a node for each first-level NOR-gate */ + npterms = 0; + pterms = ALLOC(node_t *, PLA->F->count); + foreachi_set(PLA->F, i, p) { + + /* Allocate the node */ + node = node_create(sf_new(1, 2*ninputs), + nodevec_dup(inputs, ninputs), ninputs); + network_add_node(network, node); + pterms[npterms++] = node; + + /* Insert the (inverted inputs) NOR-logic function into the node */ + pnew = GETSET(node->F, node->F->count++); + (void) set_fill(pnew, 2*ninputs); + for(var = ninputs-1; var >= 0; var--) { + switch(GETINPUT(p, var)) { + case ONE: + set_remove(pnew, 2*var); + break; + case ZERO: + set_remove(pnew, 2*var+1); + break; + } + } + node_scc(node); + } + + + /* Create a node (and an output) for each second-level NAND-gate */ + for(out = 0; out < cube.part_size[cube.output]; out++) { + i = cube.first_part[cube.num_vars - 1] + out; + + /* Allocate the node */ + node = node_create(sf_new(1, 2*npterms), + nodevec_dup(pterms, npterms), npterms); + network_add_node(network, node); + + /* Allocate and insert an extra inverter node */ + if (network_find_node(network, PLA->label[i]) != NIL(node_t)) { + (void) fprintf(siserr, "Error reading pla: node %s is already in the network.\n", PLA->label[i]); + network_free(network); + FREE(inputs); + FREE(pterms); + return NIL(network_t); + } + node1 = node_literal(node, 0); + node1->name = util_strsav(PLA->label[i]); + network_add_node(network, node1); + + /* allocate and insert the PO node */ + (void) network_add_primary_output(network, node1); + + /* Insert the NOR-logic function into the node */ + pnew = GETSET(node->F, node->F->count++); + (void) set_fill(pnew, 2*npterms); + foreachi_set(PLA->F, k, p) { + if (is_in_set(p, i)) { + set_remove(pnew, 2*k+1); + } + } + node_scc(node); + } + + FREE(inputs); + FREE(pterms); + + return network; +} + +network_t * +pla_to_network_single(PLA) +pPLA PLA; +{ + network_t *network; + node_t *node, **inputs; + int out, ninputs; + register pset last, p, pnew; + register int var, i; + + /* we can only handle binary-valued PLAs */ + if (cube.num_binary_vars+1 != cube.num_vars) return 0; + + network = network_alloc(); + + /* Create a node for each primary input */ + ninputs = 0; + inputs = ALLOC(node_t *, cube.num_binary_vars); + for(var = 0; var < cube.num_binary_vars; var++) { + if (network_find_node(network, PLA->label[2*var+1]) != NIL(node_t)) { + (void) fprintf(siserr, "Error reading pla: node %s is already in the network.\n", PLA->label[2*var+1]); + network_free(network); + FREE(inputs); + return NIL(network_t); + } + node = node_alloc(); + node->name = util_strsav(PLA->label[2*var+1]); + inputs[ninputs++] = node; + network_add_primary_input(network, node); + } + + + /* Create a node for each function */ + for(out = 0; out < cube.part_size[cube.output]; out++) { + i = cube.first_part[cube.num_vars - 1] + out; + + /* Allocate the node */ + if (network_find_node(network, PLA->label[i]) != NIL(node_t)) { + (void) fprintf(siserr, "Error reading pla: node %s is already in the network.\n", PLA->label[i]); + network_free(network); + FREE(inputs); + return NIL(network_t); + } + node = node_create(sf_new(20, 2*ninputs), + nodevec_dup(inputs, ninputs), ninputs); + node->name = util_strsav(PLA->label[i]); + network_add_node(network, node); + + /* allocate and insert the PO node */ + (void) network_add_primary_output(network, node); + + foreach_set(PLA->F, last, p) { + if (is_in_set(p, i)) { + + /* copy this cube to this node */ + pnew = set_fill(set_new(2*ninputs), 2*ninputs); + for(var = ninputs-1; var >= 0; var--) { + switch(GETINPUT(p, var)) { + case ONE: + set_remove(pnew, 2*var); + break; + case ZERO: + set_remove(pnew, 2*var+1); + break; + } + } + node->F = sf_addset(node->F, pnew); + set_free(pnew); + } + } + node_scc(node); /* make scc and min-base */ + } + + FREE(inputs); + + return network; +} + + +pPLA +espresso_read_pla(fp) +FILE *fp; +{ + pPLA PLA; + + undefine_cube_size(); + if (read_pla(fp, TRUE, FALSE, FD_type, &PLA) <= 0) { + return 0; + } + makeup_labels(PLA); + + return PLA; +} + +network_t * +pla_to_dcnetwork_single(PLA) +pPLA PLA; +{ + network_t *network; + node_t *node, **inputs; + int out, ninputs; + register pset last, p, pnew; + register int var, i; + + /* we can only handle binary-valued PLAs */ + if (cube.num_binary_vars+1 != cube.num_vars) return 0; + if(PLA->D->count == 0){ + return(NIL (network_t)); + } + + network = network_alloc(); + + /* Create a node for each primary input */ + ninputs = 0; + inputs = ALLOC(node_t *, cube.num_binary_vars); + for(var = 0; var < cube.num_binary_vars; var++) { + node = node_alloc(); + node->name = util_strsav(PLA->label[2*var+1]); + inputs[ninputs++] = node; + network_add_primary_input(network, node); + } + + + /* Create a node for each function */ + for(out = 0; out < cube.part_size[cube.output]; out++) { + i = cube.first_part[cube.num_vars - 1] + out; + + /* Allocate the node */ + node = node_create(sf_new(20, 2*ninputs), + nodevec_dup(inputs, ninputs), ninputs); + node->name = util_strsav(PLA->label[i]); + network_add_node(network, node); + + /* allocate and insert the PO node */ + (void) network_add_primary_output(network, node); + + foreach_set(PLA->D, last, p) { + if (is_in_set(p, i)) { + + /* copy this cube to this node */ + pnew = set_fill(set_new(2*ninputs), 2*ninputs); + for(var = ninputs-1; var >= 0; var--) { + switch(GETINPUT(p, var)) { + case ONE: + set_remove(pnew, 2*var); + break; + case ZERO: + set_remove(pnew, 2*var+1); + break; + } + } + node->F = sf_addset(node->F, pnew); + set_free(pnew); + } + } + node_scc(node); /* make scc and min-base */ + } + + FREE(inputs); + + return network; +} diff --git a/sis/network/sweep.c b/sis/network/sweep.c new file mode 100644 index 0000000..665b513 --- /dev/null +++ b/sis/network/sweep.c @@ -0,0 +1,274 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/network/sweep.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:33 $ + * + */ +#include "sis.h" + + +#ifdef SIS +int +network_sweep_latch(latch, reached_table) +latch_t *latch; +st_table *reached_table; +{ + node_t *lin, *lout, *fanin, *fanout, *cnode; + node_function_t func; + node_t **fo_array; + int changed = 0; + int i, init; + lsGen gen; + network_t *network; + + lin = latch_get_input(latch); + lout = latch_get_output(latch); + fanin = node_get_fanin(lin, 0); + func = node_function(fanin); + init = latch_get_initial_value(latch); + network = node_network(lin); + if ((func == NODE_0 && (init == 0 || init == 2)) || + func == NODE_1 && (init == 1 || init == 2)) { + fo_array = ALLOC(node_t *, node_num_fanout(lout)); + i = 0; + foreach_fanout(lout, gen, fanout) { + fo_array[i++] = fanout; + } + for (i = node_num_fanout(lout); i-- > 0;) { + node_patch_fanin(fo_array[i], lout, fanin); + } + FREE(fo_array); + changed = 1; + network_delete_latch(network, latch); + network_delete_node(network, lin); + network_delete_node(network, lout); + return changed; + } + if (!st_lookup(reached_table, (char *) lout, NIL(char *))) { + changed = 1; + cnode = node_constant(0); + network_add_node(network, cnode); + fo_array = ALLOC(node_t *, node_num_fanout(lout)); + i = 0; + foreach_fanout(lout, gen, fanout) { + fo_array[i++] = fanout; + } + for (i = node_num_fanout(lout); i-- > 0;) { + node_patch_fanin(fo_array[i], lout, cnode); + } + FREE(fo_array); + network_delete_latch(network, latch); + network_delete_node(network, lin); + network_delete_node(network, lout); + } + return changed; +} +#endif /* SIS */ + + +int +network_sweep_node(node) +node_t *node; +{ + int i, some_change, changed; + node_t *fanin; + node_function_t func; + + changed = 0; + + if (node->type == PRIMARY_OUTPUT) { + /* For a primary output, only sweep away a buffer node */ + fanin = node_get_fanin(node, 0); + if (node_function(fanin) == NODE_BUF) { + assert(node_patch_fanin(node, fanin, node_get_fanin(fanin, 0))); + changed = 1; + } + } else { + do { + some_change = 0; + foreach_fanin(node, i, fanin) { + func = node_function(fanin); + if (func == NODE_0 || func == NODE_1 || func == NODE_BUF + || func == NODE_INV) { + (void) node_collapse(node, fanin); + some_change = 1; + changed = 1; + break; + } + } + } while (some_change); + } + return changed; +} + + +int +network_sweep(network) +network_t *network; +{ + int status, latch_removed; + + status = network_sweep_util(network, 1, &latch_removed); + if ((network->dc_network != NIL(network_t)) && latch_removed) { + network_free(network->dc_network); + network->dc_network = NIL(network_t); + } + return status; +} + + +/* only sweep combinational logic, not latches */ + +int +network_csweep(network) +network_t *network; +{ + return network_sweep_util(network, 0, NIL(int)); +} + + +int +network_sweep_util(network, sweep_latch, latch_removed) +network_t *network; +int sweep_latch; +int *latch_removed; +{ + int i, j, changed, some_change; + array_t *node_vec; + node_t *node, *pi, *po; +#ifdef SIS + int latch_change = 0; + array_t *latch_array; + latch_t *l, *l2; + node_t *input, *output, *fanin, *fanout; + node_t *dc_pi1, *dc_pi2, *dc_po1, *dc_po2; + int num_fanout; + st_table *lfanin_table, *delete_latch, *reached_table; + st_generator *sgen; + node_t **fo_array; + node_t *latch_patch[3]; + int ival; +#endif /* SIS */ + lsGen gen; + network_t *dc_net; + + changed = 0; + some_change = 1; + + while (some_change) { + some_change = 0; + node_vec = network_dfs(network); + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (network_sweep_node(node)) { + some_change = changed = 1; + } + } + array_free(node_vec); +#ifdef SIS + if (sweep_latch) { + reached_table = snetwork_tfi_po(network); + latch_array = array_alloc(latch_t *, network_num_latch(network)); + foreach_latch(network, gen, l) { + array_insert_last(latch_t *, latch_array, l); + } + for (i = 0; i < array_n(latch_array); i++) { + l = array_fetch(latch_t *, latch_array, i); + if (network_sweep_latch(l, reached_table)) { + some_change = changed = latch_change = 1; + } + } + array_free(latch_array); + st_free_table(reached_table); + } +#endif /* SIS */ + } + if (network->dc_network != NIL(network_t)) { + (void) network_sweep(network->dc_network); + } + +#ifdef SIS + some_change = TRUE; + while(some_change){ + some_change = FALSE; + if (sweep_latch) { + /* delete latches that are redundant */ + + lfanin_table = st_init_table(st_ptrcmp, st_ptrhash); + delete_latch = st_init_table(st_ptrcmp, st_ptrhash); + foreach_latch(network, gen, l) { + fanin = node_get_fanin(latch_get_input(l), 0); + (void) st_insert(lfanin_table, (char *) fanin, NIL(char)); + } + + /* put all redundant latches in the delete_latch table */ + + st_foreach_item(lfanin_table, sgen, (char **) &fanin, NIL(char *)) { + latch_array = array_alloc(latch_t *, node_num_fanout(fanin)); + foreach_fanout(fanin, gen, fanout) { + if ((l = latch_from_node(fanout)) != NIL(latch_t)) { + array_insert_last(latch_t *, latch_array, l); + } + } + /* Compare each latch against all the others for equivalence */ + for (i = 0; i < array_n(latch_array); i++) { + l = array_fetch(latch_t *, latch_array, i); + if (l == NIL(latch_t)) continue; + for (j = i+1; j < array_n(latch_array); j++) { + l2 = array_fetch(latch_t *, latch_array, j); + if (l2 == NIL(latch_t)) continue; + if (latch_equal(l, l2)) { + st_insert(delete_latch, (char *) l2, + (char *) latch_get_output(l)); + array_insert(latch_t *, latch_array, j, NIL(latch_t)); + } + } + } + array_free(latch_array); + } + st_foreach_item(delete_latch, sgen, (char **) &l, (char **) &output) { + node = latch_get_output(l); + input = latch_get_input(l); + fo_array = ALLOC(node_t *, node_num_fanout(node)); + i = 0; + foreach_fanout(node, gen, fanout) { + fo_array[i++] = fanout; + } + for (i = node_num_fanout(node); i-- > 0;) { + node_patch_fanin(fo_array[i], node, output); + } + some_change = TRUE; + changed = latch_change = 1; + + network_delete_latch(network, l); + network_delete_node(network, input); + network_delete_node(network, node); + FREE(fo_array); + } + + st_free_table(lfanin_table); + st_free_table(delete_latch); + } + } + if (latch_removed != NIL(int)) { + *latch_removed = latch_change; + } +#endif /* SIS */ + + /* delete nodes with no fanout */ +#ifdef SIS + if (network_cleanup_util(network, sweep_latch, &latch_change)) { +#else + if (network_cleanup_util(network, sweep_latch, NIL(int))) { +#endif + changed = 1; + } +#ifdef SIS + if (latch_change) *latch_removed = 1; +#endif + return changed; +} + diff --git a/sis/node/Makefile.am b/sis/node/Makefile.am new file mode 100644 index 0000000..8ea40aa --- /dev/null +++ b/sis/node/Makefile.am @@ -0,0 +1,10 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libnode.a +libnode_a_SOURCES = cofct.c collapse.c com_node.c cubehack.c divide.c \ + fan.c invert.c iphase.c libhack.c names.c node.c nodecheck.c \ + nodeindex.c nodemisc.c nodeutil.c print.c sethack.c substitute.c \ + node_int.h +pkginclude_HEADERS = node.h nodeindex.h +dist_doc_DATA = node.doc nodeindex.doc diff --git a/sis/node/Makefile.in b/sis/node/Makefile.in new file mode 100644 index 0000000..297f9ac --- /dev/null +++ b/sis/node/Makefile.in @@ -0,0 +1,428 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libnode_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/node +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libnode_a_AR = $(AR) $(ARFLAGS) +libnode_a_LIBADD = +am_libnode_a_OBJECTS = cofct.$(OBJEXT) collapse.$(OBJEXT) \ + com_node.$(OBJEXT) cubehack.$(OBJEXT) divide.$(OBJEXT) \ + fan.$(OBJEXT) invert.$(OBJEXT) iphase.$(OBJEXT) \ + libhack.$(OBJEXT) names.$(OBJEXT) node.$(OBJEXT) \ + nodecheck.$(OBJEXT) nodeindex.$(OBJEXT) nodemisc.$(OBJEXT) \ + nodeutil.$(OBJEXT) print.$(OBJEXT) sethack.$(OBJEXT) \ + substitute.$(OBJEXT) +libnode_a_OBJECTS = $(am_libnode_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libnode_a_SOURCES) +DIST_SOURCES = $(libnode_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libnode.a +libnode_a_SOURCES = cofct.c collapse.c com_node.c cubehack.c divide.c \ + fan.c invert.c iphase.c libhack.c names.c node.c nodecheck.c \ + nodeindex.c nodemisc.c nodeutil.c print.c sethack.c substitute.c \ + node_int.h + +pkginclude_HEADERS = node.h nodeindex.h +dist_doc_DATA = node.doc nodeindex.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/node/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/node/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libnode.a: $(libnode_a_OBJECTS) $(libnode_a_DEPENDENCIES) + -rm -f libnode.a + $(libnode_a_AR) libnode.a $(libnode_a_OBJECTS) $(libnode_a_LIBADD) + $(RANLIB) libnode.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/node/cofct.c b/sis/node/cofct.c new file mode 100644 index 0000000..2c477fd --- /dev/null +++ b/sis/node/cofct.c @@ -0,0 +1,178 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/cofct.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "node_int.h" + +void +node_algebraic_cofactor(node, fanin, p, q, r) +node_t *node, *fanin; +node_t **p, **q, **r; +{ + register int i; + register pset last, p1, p2; + pset_family p_sf, q_sf, r_sf; + + p_sf = sf_new(node->F->count, node->nin*2); + q_sf = sf_new(node->F->count, node->nin*2); + r_sf = sf_new(node->F->count, node->nin*2); + + i = node_get_fanin_index(node, fanin); + if (i == -1) { + sf_free(r_sf); + r_sf = sf_save(node->F); + } else { + foreach_set(node->F, last, p1) { + switch(GETINPUT(p1, i)) { + case ONE: + p2 = GETSET(p_sf, p_sf->count++); + INLINEset_copy(p2, p1); + set_insert(p2, 2*i); + break; + case ZERO: + p2 = GETSET(q_sf, q_sf->count++); + INLINEset_copy(p2, p1); + set_insert(p2, 2*i+1); + break; + case TWO: + p2 = GETSET(r_sf, r_sf->count++); + INLINEset_copy(p2, p1); + break; + default: + fail("node_algebraic_cofactor: bad cube"); + break; + } + } + } + + *p = node_create(p_sf, nodevec_dup(node->fanin, node->nin), node->nin); + *q = node_create(q_sf, nodevec_dup(node->fanin, node->nin), node->nin); + *r = node_create(r_sf, nodevec_dup(node->fanin, node->nin), node->nin); + (*p)->is_dup_free = node->is_dup_free; + (*q)->is_dup_free = node->is_dup_free; + (*r)->is_dup_free = node->is_dup_free; + + node_minimum_base(*p); + node_minimum_base(*q); + node_minimum_base(*r); +} + +static node_t * +fast_cofactor(node, fanin, phase) +node_t *node, *fanin; +int phase; +{ + register int i; + register pset last, pdest, p; + pset_family func; + node_t *r; + + i = node_get_fanin_index(node, fanin); + if (i == -1) { + func = sf_save(node->F); + + } else { + func = sf_new(node->F->count, node->nin*2); + foreach_set(node->F, last, p) { + switch(GETINPUT(p, i)) { + case ONE: + if (phase == 1) { + pdest = GETSET(func, func->count++); + INLINEset_copy(pdest, p); + set_insert(pdest, 2*i); + } + break; + case ZERO: + if (phase == 0) { + pdest = GETSET(func, func->count++); + INLINEset_copy(pdest, p); + set_insert(pdest, 2*i+1); + } + break; + case TWO: + pdest = GETSET(func, func->count++); + INLINEset_copy(pdest, p); + break; + default: + fail("node_cofactor: bad cube"); + break; + } + } + } + + r = node_create(func, nodevec_dup(node->fanin, node->nin), node->nin); + r->is_dup_free = node->is_dup_free; + node_minimum_base(r); + return r; +} + +node_t * +node_cofactor(node, cube) +node_t *node, *cube; +{ + register pset last, p, g_cube_not, pdest; + pset g_cube, full; + pset_family newf, newg, func; + node_t *r, *fanin, **new_fanin; + int new_nin; + + switch(node_function(cube)) { + case NODE_0: + fail("node_cofactor: not defined for the 0 function"); + break; + + case NODE_1: + r = node_dup(node); + break; + + case NODE_BUF: + fanin = node_get_fanin(cube, 0); + r = fast_cofactor(node, fanin, 1); + break; + + case NODE_INV: + fanin = node_get_fanin(cube, 0); + r = fast_cofactor(node, fanin, 0); + break; + + case NODE_AND: + make_common_base(node, cube, &new_fanin, &new_nin, &newf, &newg); + + define_cube_size(new_nin); + + g_cube = GETSET(newg, 0); + g_cube_not = set_new(new_nin*2); + full = set_fill(set_new(new_nin*2), new_nin*2); + (void) set_diff(g_cube_not, full, g_cube); + set_free(full); + + func = sf_new(newf->count, newf->sf_size); + foreach_set(newf, last, p) { + if (cdist0(p, g_cube)) { + pdest = GETSET(func, func->count++); + INLINEset_or(pdest, p, g_cube_not); + } + } + + set_free(g_cube_not); + sf_free(newf); + sf_free(newg); + + /* allocate a new node */ + r = node_create(func, new_fanin, new_nin); + r->is_dup_free = 1; /* make_common_base assures this */ + node_minimum_base(r); + break; + + default: + fail("node_cofactor: defined for a single cube only"); + } + + return r; +} diff --git a/sis/node/collapse.c b/sis/node/collapse.c new file mode 100644 index 0000000..02ca923 --- /dev/null +++ b/sis/node/collapse.c @@ -0,0 +1,161 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/collapse.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "node_int.h" + + +static void handle_constant(); +/* +static void handle_inverter(); +*/ + + +int +node_collapse(f, g) +node_t *f, *g; +{ + node_t *p, *q, *r, *g_not, *t1, *t2, *t3; + int index; + + if (f->type == PRIMARY_INPUT || g->type == PRIMARY_INPUT) { + return 0; + } + if (f->type == PRIMARY_OUTPUT || g->type == PRIMARY_OUTPUT) { + return 0; + } + + /* make sure f really depends on g */ + index = node_get_fanin_index(f, g); + if (index == -1) { + return 0; + } + + /* there are some special cases -- for speed reasons only ... */ + switch(node_function(g)) { + case NODE_0: + handle_constant(f, index, ONE); + return 1; + + case NODE_1: + handle_constant(f, index, ZERO); + return 1; + + /* these two cases work only when the nodes are in the network */ + /* + case NODE_INV: + handle_inverter(f, g, index, 0); + return 1; + + case NODE_BUF: + handle_inverter(f, g, index, 1); + return 1; + */ + default: break; + } + + /* general case: form cofactors, and re-combine */ + node_algebraic_cofactor(f, g, &p, &q, &r); + t1 = r; + + if (node_function(p) != NODE_0) { + t2 = node_and(p, g); + t3 = node_or(t1, t2); + node_free(t1); + node_free(t2); + t1 = t3; + } + + if (node_function(q) != NODE_0) { + g_not = node_not(g); + t2 = node_and(q, g_not); + t3 = node_or(t1, t2); + node_free(g_not); + node_free(t1); + node_free(t2); + t1 = t3; + } + + node_free(p); + node_free(q); + node_replace(f, t1); + + return 1; +} + +static void +handle_constant(f, index, bad_value) +node_t *f; +register int index; +register int bad_value; +{ + register pset last, p; + register int index2, index2p1; + int delcnt; + + index2 = 2*index; + index2p1 = 2*index + 1; + delcnt = 0; + + foreach_set(f->F, last, p) { + SET(p, ACTIVE); + } + foreach_set(f->F, last, p) { + if (GETINPUT(p, index) == bad_value) { + RESET(p, ACTIVE); /* mark the cube for deletion */ + delcnt++; + } else { + set_insert(p, index2); + set_insert(p, index2p1); + } + } + if (delcnt > 0) { + f->F = sf_inactive(f->F); /* delete cubes which are not active */ + } + node_invalid(f); + node_minimum_base(f); +} + + +/* works only if the node is in the network */ +/* phase = 0 - handle buffer + * 1 - handle inverter + */ +/* +static void +handle_inverter(f, g, index, phase) +node_t *f, *g; +register int index; +int phase; +{ + register pset last, p; + register int index2, index2p1; + + if (phase == 0) { + index2 = 2 * index; + index2p1 = 2 * index + 1; + + foreach_set(f->F, last, p) { + switch (GETINPUT(p, index)) { + case ZERO: + set_insert(p, index2p1); + set_remove(p, index2); + break; + case ONE: + set_insert(p, index2); + set_remove(p, index2p1); + break; + } + } + } + assert(node_patch_fanin(f, g, node_get_fanin(g, 0))); + node_invalid(f); + node_minimum_base(f); +} +*/ diff --git a/sis/node/com_node.c b/sis/node/com_node.c new file mode 100644 index 0000000..78e7896 --- /dev/null +++ b/sis/node/com_node.c @@ -0,0 +1,229 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/com_node.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "node_int.h" + +com_div(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *node1, *node2, *q, *r; + + node_vec = com_get_nodes(*network, argc, argv); + if (array_n(node_vec) != 2) { + (void) fprintf(miserr, "usage: _div n1 n2 -- test division\n"); + return 1; + } + + node1 = array_fetch(node_t *, node_vec, 0); + node2 = array_fetch(node_t *, node_vec, 1); + + q = node_div(node1, node2, &r); + (void) fprintf(misout, "q = "); + node_print_rhs(misout, q); + (void) fprintf(misout, "\nr = "); + node_print_rhs(misout, r); + (void) fprintf(misout, "\n"); + node_free(q); + node_free(r); + + array_free(node_vec); + return 0; +} + +com_sim(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *node; + node_sim_type_t mode; + int c, i; + + mode = NODE_SIM_ESPRESSO; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "m:")) != EOF) { + switch(c) { + case 'm': + if (strcmp(util_optarg, "simpcomp") == 0) { + mode = NODE_SIM_SIMPCOMP; + } else if (strcmp(util_optarg, "espresso") == 0) { + mode = NODE_SIM_ESPRESSO; + } else if (strcmp(util_optarg, "exact") == 0) { + mode = NODE_SIM_EXACT; + } else if (strcmp(util_optarg, "exact-lits") == 0) { + mode = NODE_SIM_EXACT_LITS; + } else { + goto usage; + } + break; + default: + goto usage; + } + } + + node_vec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + switch(node_function(node)) { + case NODE_PI: + case NODE_PO: + break; + default: + (void) node_simplify_replace(node, NIL(node_t), mode); + } + } + array_free(node_vec); + return 0; +usage: + (void) fprintf(miserr, "_sim [node-list] -- test simplification\n"); + (void) fprintf(miserr, " -m simpcomp\t\tselect fast heuristic\n"); + (void) fprintf(miserr, " -m espresso\t\tminimize using espresso\n"); + (void) fprintf(miserr, " -m exact\t\tminimize using exact (cubes)\n"); + (void) fprintf(miserr, " -m exact-lits\tminimize using exact (lits)\n"); + return 1; +} + +com_cof(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *node1, *node2, *r; + + node_vec = com_get_nodes(*network, argc, argv); + if (array_n(node_vec) != 2) { + (void) fprintf(miserr, "usage: _cof n1 n2 -- test cofactor\n"); + return 1; + } + + node1 = array_fetch(node_t *, node_vec, 0); + node2 = array_fetch(node_t *, node_vec, 1); + + r = node_cofactor(node1, node2); + (void) fprintf(misout, "cof = "); + node_print_rhs(misout, r); + (void) fprintf(misout, "\n"); + node_free(r); + + array_free(node_vec); + return 0; +} + +com_wd(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *node1, *node2; + int c, use_complement; + + use_complement = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "c")) != EOF) { + switch(c) { + case 'c': + use_complement = 1; + break; + default: + goto usage; + } + } + + node_vec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + if (array_n(node_vec) != 2) goto usage; + + node1 = array_fetch(node_t *, node_vec, 0); + node2 = array_fetch(node_t *, node_vec, 1); + (void) node_substitute(node1, node2, use_complement); + array_free(node_vec); + return 0; + +usage: + (void) fprintf(miserr, "usage: wd [-c] n1 n2 -- re-express n1 using n2\n"); + (void) fprintf(miserr, " -c\t\talso use the complement of n2\n"); + return 1; +} + +com_scc(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *node; + int i; + + if (argc < 2) goto usage; + + node_vec = com_get_nodes(*network, argc, argv); + if (array_n(node_vec) < 1) goto usage; + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + (void) node_scc(node); + } + array_free(node_vec); + return 0; + +usage: + (void) fprintf(miserr, "usage: scc n1 n2 ...\n"); + return 1; +} + +com_invert(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *node; + int i; + + if (argc < 2) goto usage; + + node_vec = com_get_nodes(*network, argc, argv); + if (array_n(node_vec) < 1) goto usage; + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + (void) node_invert(node); + } + array_free(node_vec); + return 0; + +usage: + (void) fprintf(miserr, "usage: invert n1 n2 ...\n"); + return 1; +} + +init_node() +{ + com_add_command("wd", com_wd, 1); + com_add_command("invert", com_invert, 1); + com_add_command("_scc", com_scc, 1); + com_add_command("_sim", com_sim, 0); + com_add_command("_div", com_div, 0); + com_add_command("_cof", com_cof, 0); + + define_cube_size(20); + set_espresso_flags(); + name_mode = LONG_NAME_MODE; +} + + +end_node() +{ + node_discard_all_daemons(); + undefine_cube_size(); +} diff --git a/sis/node/cubehack.c b/sis/node/cubehack.c new file mode 100644 index 0000000..cfb2685 --- /dev/null +++ b/sis/node/cubehack.c @@ -0,0 +1,135 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/cubehack.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "node_int.h" + +#ifdef lint +struct cube_struct cube; +bool summary; +bool trace; +bool remove_essential; +bool force_irredundant; +bool unwrap_onset; +bool single_expand; +bool pos; +bool recompute_onset; +bool use_super_gasp; +bool use_random_order; +#endif + + +void +cautious_define_cube_size(n) +int n; +{ + if (cube.fullset != 0 && cube.num_binary_vars == n) + return; + if (cube.fullset != 0) { + setdown_cube(); + FREE(cube.part_size); + } + cube.num_binary_vars = cube.num_vars = n; + cube.part_size = ALLOC(int, n); + cube_setup(); +} + + +void +define_cube_size(n) +int n; +{ + register int q, i; + static int called_before = 0; + + /* check if the cube is already just the right size */ + if (cube.fullset != 0 && cube.num_binary_vars == n && cube.num_vars == n) + return; + + /* We can't handle more than 100 inputs */ + if (n > 100) { + cautious_define_cube_size(n); + called_before = 0; + return; + } + + if (cube.fullset == 0 || ! called_before) { + cautious_define_cube_size(100); + called_before = 1; + } + + cube.num_vars = n; + cube.num_binary_vars = n; + cube.num_mv_vars = 0; + cube.output = -1; + cube.size = n * 2; + + /* first_part, last_part, first_word, last_word, part_size OKAY */ + /* cube.sparse is OKAY */ + + /* need to completely re-make cube.fullset and cube.binary_mask */ + (void) set_fill(cube.fullset, n*2); + (void) set_fill(cube.binary_mask, n*2); + + /* need to resize each set in cube.var_mask and cube.temp */ + q = cube.fullset[0]; + for(i = 0; i < cube.num_vars; i++) + cube.var_mask[i][0] = q; + for(i = 0; i < CUBE_TEMP; i++) + cube.temp[i][0] = q; + + /* need to resize cube.emptyset and cube.mv_mask */ + cube.emptyset[0] = q; + cube.mv_mask[0] = q; + + /* need to reset the inword and inmask */ + if (cube.num_binary_vars != 0) { + cube.inword = cube.last_word[cube.num_binary_vars - 1]; + cube.inmask = cube.binary_mask[cube.inword] & DISJOINT; + } else { + cube.inword = -1; + cube.inmask = 0; + } + + /* cdata (entire structure) is OKAY */ +} + + +void +undefine_cube_size() +{ + if (cube.num_binary_vars > 100) { + if (cube.fullset != 0) { + setdown_cube(); + FREE(cube.part_size); + } + } else { + cube.num_vars = cube.num_binary_vars = 100; + if (cube.fullset != 0) { + setdown_cube(); + FREE(cube.part_size); + } + } +} + + +void +set_espresso_flags() +{ + summary = FALSE; + trace = FALSE; + remove_essential = TRUE; + force_irredundant = TRUE; + unwrap_onset = TRUE; + single_expand = FALSE; + pos = FALSE; + recompute_onset = FALSE; + use_super_gasp = FALSE; + use_random_order = FALSE; +} diff --git a/sis/node/divide.c b/sis/node/divide.c new file mode 100644 index 0000000..12902d0 --- /dev/null +++ b/sis/node/divide.c @@ -0,0 +1,437 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/divide.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "node_int.h" + + + +typedef struct div_cube_struct div_cube_t; +struct div_cube_struct { + pset original; + pset cube; + int is_divisor_cube; + div_cube_t *next; +}; + + +#define SORT divide_sort_helper +#define SORT1 divide_sort +#define TYPE div_cube_t +#include "lsort.h" + +#ifdef DIVIDE_DEBUG + +static void +dump_set(fp, setp) +FILE *fp; +pset setp; +{ + int i, n; + + n = (BPI*LOOP(setp)) / 2; + for(i = 0; i < n; i++) { + putc("?01-"[GETINPUT(setp, i)], fp); + } +} + + +static void +dump_list(list) +div_cube_t *list; +{ + div_cube_t *p; + + for(p = list; p != 0; p = p->next) { + (void) fprintf(misout, "original="); + dump_set(misout, p->original); + (void) fprintf(misout, " cube="); + dump_set(misout, p->cube); + (void) fprintf(misout, " is_divisor=%d\n", p->is_divisor_cube); + } +} + + +static void +dump_fanin(fanin, nfanin) +node_t **fanin; +int nfanin; +{ + int i; + + for(i = 0; i < nfanin; i++) { + (void) fprintf(misout, "fanin %d: (%08X) %s\n", + i, fanin[i], node_name(fanin[i])); + } +} + +#endif + +static div_cube_t * +divide_setup_divisor(sf) +pset_family sf; +{ + register pset last, p; + register div_cube_t *div, *head; + + head = 0; + foreach_set(sf, last, p) { + div = ALLOC(div_cube_t, 1); + div->original = p; + div->is_divisor_cube = 1; + div->cube = p; + div->next = head; + head = div; + } + return head; +} + + +static div_cube_t * +divide_setup_dividend(head, sf, divisor_support) +register div_cube_t *head; +pset_family sf; +register pset divisor_support; +{ + register pset last, p; + register div_cube_t *div; + + foreach_set(sf, last, p) { + div = ALLOC(div_cube_t, 1); + div->original = p; + div->is_divisor_cube = 0; + div->cube = set_or(set_save(p), p, divisor_support); + div->next = head; + head = div; + } + return head; +} + +static div_cube_t * +divide_find_classes(list, fullset) +div_cube_t **list; +register pset fullset; +{ + register div_cube_t **prev, *p, *quotient; + pset divisor; + + quotient = 0; + for(prev = list; (p = *prev) != 0; ) { + if (p->is_divisor_cube) { + /* unlink divisor cube from this list, and free it */ + *prev = p->next; + divisor = p->cube; + FREE(p); + + /* now find all cubes 'equal' (under a mask) to this divisor cube */ + while ((p = *prev) != 0 && lex_order(&divisor, &(p->cube)) == 0) { + /* unlink from this list, add to quotient list */ + *prev = p->next; + p->next = quotient; + quotient = p; + + /* divide by this divisor cube */ + INLINEset_ndiff(p->cube, p->original, divisor, fullset); + } + + /* ignore any cubes which are not divisor cubes */ + } else { + prev = &(p->next); + } + } + return quotient; +} + +void +divide_finale(list, quotient, divisor_ncube, q_sf, r_sf) +div_cube_t *list, *quotient; +int divisor_ncube; +pset_family q_sf, r_sf; +{ + register div_cube_t *p, *p1, *p2; + register int run; + register pset pdest; + + for(p = quotient; p != 0; p = p1) { + run = 1; + p1 = p->next; + while (p1 != 0 && lex_order(&(p->cube), &(p1->cube)) == 0) { + p1 = p1->next; + run++; + } + if (run == divisor_ncube) { + /* add single cube to quotient */ + pdest = GETSET(q_sf, q_sf->count++); + INLINEset_copy(pdest, p->cube); + } else { + /* add all of these cubes to remainder */ + if (r_sf != 0) { + for(p2 = p; p2 != p1; p2 = p2->next) { + pdest = GETSET(r_sf, r_sf->count++); + INLINEset_copy(pdest, p2->original); + } + } + } + } + + /* discard the quotient */ + for(p = quotient; p != 0; p = p1) { + p1 = p->next; + set_free(p->cube); + FREE(p); + } + + /* copy the remainder list to the remainder and discard it */ + for(p = list; p != 0; p = p1) { + p1 = p->next; + /* add all of these cubes to remainder */ + if (r_sf != 0) { + pdest = GETSET(r_sf, r_sf->count++); + INLINEset_copy(pdest, p->original); + } + set_free(p->cube); + FREE(p); + } +} + +static int +list_compare(p, q) +div_cube_t *p, *q; +{ + int x; + + x = lex_order(&(p->cube), &(q->cube)); + if (x == 0) { + return q->is_divisor_cube - p->is_divisor_cube; + } else { + return x; + } +} + +/* + * divide f/g giving quotient and (optional) remainder. Assumes that + * g is already known to be a single cube (but not a single literal). + */ + +static node_t * +divide_single_cube(f, g, r_node) +node_t *f, *g; +node_t **r_node; +{ + pset_family newf, newg, q_sf, r_sf; + register pset last, p, fullset, pdest, g_cube; + node_t **new_fanin, *q_node; + int new_nin; + + /* express f and g in a common base */ + make_common_base(f, g, &new_fanin, &new_nin, &newf, &newg); + + /* make a full set of the right size */ + fullset = set_fill(set_new(new_nin * 2), new_nin * 2); + + q_sf = sf_new(newf->count, new_nin * 2); + r_sf = r_node ? sf_new(newf->count, new_nin * 2) : 0; + g_cube = GETSET(newg, 0); + foreach_set(newf, last, p) { + if (setp_implies(p, g_cube)) { + pdest = GETSET(q_sf, q_sf->count++); + *pdest = 0; /* ### crock for saber */ + INLINEset_ndiff(pdest, p, g_cube, fullset); + } else { + if (r_node != 0) { + pdest = GETSET(r_sf, r_sf->count++); + INLINEset_copy(pdest, p); + } + } + } + + if (r_node != 0) { + *r_node = node_create(r_sf, nodevec_dup(new_fanin, new_nin), new_nin); + (*r_node)->is_dup_free = 1; /* make_common_base insures this */ + (*r_node)->is_scc_minimal = f->is_scc_minimal; + node_minimum_base(*r_node); + } + + q_node = node_create(q_sf, new_fanin, new_nin); + q_node->is_dup_free = 1; /* make_common_base insures this */ + q_node->is_scc_minimal = f->is_scc_minimal; + node_minimum_base(q_node); + + sf_free(newf); + sf_free(newg); + set_free(fullset); + return q_node; +} + +/* + * divide f/g giving quotient and (optional) remainder. Assumes that + * g is already known to be a single literal. + */ + +static node_t * +divide_single_literal(f, g, r_node) +node_t *f, *g; +node_t **r_node; +{ + node_t *q_node; + pset_family q_sf, r_sf; + register pset last, p, pdest; + register int index, index1; + int g_lit; + + index = node_get_fanin_index(f, g->fanin[0]); + if (index == -1) { + if (r_node != 0) *r_node = node_dup(f); + return node_constant(0); + } + + q_sf = sf_new(f->F->count, f->nin * 2); + r_sf = r_node ? sf_new(f->F->count, f->nin * 2) : 0; + g_lit = GETINPUT(GETSET(g->F, 0), 0); + assert(g_lit != TWO); /* if so, g is not minimum base */ + index1 = g_lit == ZERO ? 2*index+1 : 2*index; + foreach_set(f->F, last, p) { + if (GETINPUT(p, index) == g_lit) { + pdest = GETSET(q_sf, q_sf->count++); + INLINEset_copy(pdest, p); + set_insert(pdest, index1); + } else { + if (r_node != 0) { + pdest = GETSET(r_sf, r_sf->count++); + INLINEset_copy(pdest, p); + } + } + } + + if (r_node != 0) { + *r_node = node_create(r_sf, nodevec_dup(f->fanin, f->nin), f->nin); + (*r_node)->is_dup_free = 1; /* make_common_base insures this */ + (*r_node)->is_scc_minimal = f->is_scc_minimal; + node_minimum_base(*r_node); + } + + q_node = node_create(q_sf, nodevec_dup(f->fanin, f->nin), f->nin); + q_node->is_dup_free = 1; /* make_common_base insures this */ + q_node->is_scc_minimal = f->is_scc_minimal; + node_minimum_base(q_node); + return q_node; +} + +/* + * node_div -- compute f/g returning quotient in r and remainder in q + * + * This looks complicated, but its really not. + * + * The idea is to find all cubes of f which are equal to a cube of g + * when restricted to the support of g. If we collect the cube + * quotients h(i) = f(i)/g(i) for each of these cases, then a cube + * h(i) belongs to the final quotient iff it appears m times in the + * collection of cubes h(i). (m is the number of cubes of g). + * + * Hence, a single sort (restricted to the support of g) identifies + * all cubes f(i) which are equal to some cube g(i); then, we form the + * cubes h(i) for each of these cases, and sort this list to find the + * duplicity of each h(i). + * + * Some simple filters speed things up: + * 1. support(g) must be contained in the support of f; if not, + * q = 0, r = f + * 2. number of cubes of f must be greater than (or equal) to the + * number of cubes of g; if not, q = 0, r = f. + * 3. divide by a single literal, or divide by a single term is + * much easier (avoid sort, guaranteed o(n)); these are handled + * as special cases + */ + +node_t * +node_div(f, g, r_node) +node_t *f, *g; +node_t **r_node; +{ + pset fullset, f_support, g_support; + pset_family newf, newg, q_sf, r_sf; + node_t **new_fanin, *q_node; + int new_nin; + div_cube_t *list, *quotient; + + if (f->F == 0 || g->F == 0) { + fail("node_div: node does not have a function"); + } + + /* filter 1: trivial answer if f has too few cubes */ + if (f->F->count < g->F->count) { + if (r_node != 0) *r_node = node_dup(f); + return node_constant(0); + } + + /* filter 2: check for a single cube or a single literal */ + if (g->F->count == 1) { + if (g->nin == 1) { + return divide_single_literal(f, g, r_node); + } else { + return divide_single_cube(f, g, r_node); + } + } + + /* express f and g in a common base */ + make_common_base(f, g, &new_fanin, &new_nin, &newf, &newg); + f_support = sf_and(newf); + g_support = sf_and(newg); + + /* filter 3: trivial answer if support(g) not contained in support(f) */ + if (! setp_implies(f_support, g_support)) { + sf_free(newf); + sf_free(newg); + set_free(f_support); + set_free(g_support); + FREE(new_fanin); + if (r_node != 0) *r_node = node_dup(f); + return node_constant(0); + } + + /* make a full set of the right size */ + fullset = set_fill(set_new(new_nin * 2), new_nin * 2); + + /* build the list for the cubes of f and g */ + list = divide_setup_divisor(newg); + list = divide_setup_dividend(list, newf, g_support); + + /* sort the list */ + list = divide_sort(list, list_compare); + + /* form the quotient list */ + quotient = divide_find_classes(&list, fullset); + + /* sort the quotient list */ + quotient = divide_sort(quotient, list_compare); + + /* finally extract the quotient and remainder */ + q_sf = sf_new(newf->count, new_nin * 2); + r_sf = r_node ? sf_new(newf->count, new_nin * 2) : 0; + divide_finale(list, quotient, newg->count, q_sf, r_sf); + + if (r_node != 0) { + *r_node = node_create(r_sf, nodevec_dup(new_fanin, new_nin), new_nin); + (*r_node)->is_dup_free = 1; /* make_common_base insures this */ + (*r_node)->is_scc_minimal = f->is_scc_minimal; + node_minimum_base(*r_node); + } + + q_node = node_create(q_sf, new_fanin, new_nin); + q_node->is_dup_free = 1; /* make_common_base insures this */ + q_node->is_scc_minimal = f->is_scc_minimal; + node_minimum_base(q_node); + + sf_free(newf); + sf_free(newg); + set_free(fullset); + set_free(f_support); + set_free(g_support); + return q_node; +} diff --git a/sis/node/fan.c b/sis/node/fan.c new file mode 100644 index 0000000..972ec6a --- /dev/null +++ b/sis/node/fan.c @@ -0,0 +1,228 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/fan.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "node_int.h" + + +static void +fanin_remove_single_fanout(node, i) +node_t *node; +int i; +{ + char *data; + + LS_ASSERT(lsRemoveItem(node->fanin_fanout[i], &data)); + FREE(data); + /*node->fanin[i]->fanout_changed = 1;*/ +} + + +void +fanin_remove_fanout(node) +node_t *node; +{ + register int i; + char *data; + + for(i = node->nin-1; i >= 0; i--) { + LS_ASSERT(lsRemoveItem(node->fanin_fanout[i], &data)); + FREE(data); +/* node->fanin[i]->fanout_changed = 1;*/ + } +} + +static void +fanin_replace_single_fanout(node, i) +node_t *node; +int i; +{ + lsHandle handle; + register fanout_t *fanout_rec; + node_t *fanin; + + fanin = node->fanin[i]; + fanout_rec = ALLOC(fanout_t, 1); + fanout_rec->fanout = node; + fanout_rec->pin = i; + LS_ASSERT(lsNewEnd(fanin->fanout, (char *) fanout_rec, &handle)); + node->fanin_fanout[i] = handle; +/* fanin->fanout_changed = 1;*/ +} + + +void +fanin_add_fanout(node) +node_t *node; +{ + register int i; + + FREE(node->fanin_fanout); + node->fanin_fanout = ALLOC(lsHandle, node->nin); + for(i = node->nin-1; i >= 0; i--) { + fanin_replace_single_fanout(node, i); + } +} + +lsGen +node_fanout_init_gen(node) +node_t *node; +{ + lsGen gen; + + if (node->network == 0) { + fail("foreach_fanout: node is not in a network, fanout undefined"); + /* NOTREACHED */ + } + gen = lsStart(node->fanout); + assert(gen != 0); + return gen; +} + + +node_t * +node_fanout_gen(gen, pin) +lsGen gen; +int *pin; +{ + char *data; + fanout_t *fanout_rec; + + if (lsNext(gen, &data, LS_NH) != LS_OK) { + (void) lsFinish(gen); + return 0; + } + fanout_rec = (fanout_t *) data; + if (pin != 0) *pin = fanout_rec->pin; + return fanout_rec->fanout; +} + +node_t * +node_get_fanin(node, i) +node_t *node; +int i; +{ + if (i < 0 || i >= node->nin) { + fail("node_get_fanin: bad fanin index"); + } + return node->fanin[i]; +} + + +node_t * +node_get_fanout(node, i) +node_t *node; +int i; +{ + int cnt; + fanout_t *fanout_rec; + lsGen gen; + char *data; + + if (i < 0 || i >= node_num_fanout(node)) { + fail("node_get_fanout: bad fanout index"); + } + + /* painful */ + fanout_rec = 0; + cnt = 0; + lsForeachItem(node->fanout, gen, data) { + if (cnt++ == i) { + fanout_rec = (fanout_t *) data; + LS_ASSERT(lsFinish(gen)); + break; + } + } + return fanout_rec->fanout; +} + + +int +node_get_fanin_index(node, fanin) +register node_t *node, *fanin; +{ + register int i; + + for(i = 0; i < node->nin; i++) { + if (fanin == node->fanin[i]) { + return i; + } + } + return -1; +} + + +int +node_num_fanin(node) +node_t *node; +{ + return node->nin; +} + + +int +node_num_fanout(node) +node_t *node; +{ + if (node->network == 0) { + fail("node_num_fanout: node is not in a network, fanout undefined"); + /* NOTREACHED */ + } + return lsLength(node->fanout); +} + +int +node_patch_fanin(node, fanin, new_fanin) +node_t *node; +node_t *fanin; +node_t *new_fanin; +{ + int i; + + /* Patch fanin list of node, entry 'fanin' to 'new_fanin' */ + for(i = 0; i < node->nin; i++) { + if (node->fanin[i] == fanin) { + fanin_remove_single_fanout(node, i); + node->fanin[i] = new_fanin; + fanin_replace_single_fanout(node, i); + node->is_dup_free = 0; /* don't know ... */ + + return 1; /* success */ + } + } + + return 0; /* failure */ +} + + +/* + * Mimics the functionality of node_patch_fanin() ... However + * uses the index to find the fanin that is going to be replaced by + * "new_fanin" + */ +int +node_patch_fanin_index(node, fanin_index, new_fanin) +node_t *node; +int fanin_index; +node_t *new_fanin; +{ + /* Check if the index is a valid one */ + if (fanin_index < 0 || fanin_index >= node->nin){ + return 0; + } + + /* Patch fanin list of node, entry 'fanin_index' to 'new_fanin' */ + fanin_remove_single_fanout(node, fanin_index); + node->fanin[fanin_index] = new_fanin; + fanin_replace_single_fanout(node, fanin_index); + node->is_dup_free = 0; /* don't know ... */ + + + return 1; /* success */ +} diff --git a/sis/node/invert.c b/sis/node/invert.c new file mode 100644 index 0000000..e9a0d8c --- /dev/null +++ b/sis/node/invert.c @@ -0,0 +1,91 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/invert.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "node_int.h" + + +int +node_invert(node) +node_t *node; +{ + pset_family temp; + lsList po_list; + lsGen gen; + node_t *node1, *fanout; + int pin; + register pset last, p; + register int pin2; + + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) { + return 0; + } + if (node->F == 0) { + fail("node_invert: node does not have a function"); + } + + if (node->R != 0) { + sf_free(node->R); + node->R = 0; + } + node_complement(node); + temp = node->F; + node->F = node->R; + node->R = temp; + node->is_scc_minimal = 1; /* node_complement() assures this */ + node_minimum_base(node); + + po_list = 0; /* record fanouts which are PO's */ + + if (node->network != 0) { + foreach_fanout_pin(node, gen, fanout, pin) { + if (fanout->type == INTERNAL) { + foreach_set(fanout->F, last, p) { + pin2 = 2 * pin; + switch(GETINPUT(p, pin)) { + case ZERO: + set_remove(p, pin2); + set_insert(p, pin2+1); + break; + case ONE: + set_remove(p, pin2+1); + set_insert(p, pin2); + break; + case TWO: + break; + default: + fail("node_invert: bad cube literal"); + } + } + node_invalid(fanout); + + } else if (fanout->type == PRIMARY_OUTPUT) { + /* save this node so we can add an inverter later */ + if (po_list == 0) po_list = lsCreate(); + LS_ASSERT(lsNewEnd(po_list, (char *) fanout, LS_NH)); + + } else { + fail("node_invert: bad node type"); + } + } + + /* Add a single invert (if necessary) to feed the primary outputs */ + if (po_list != 0) { + node1 = node_literal(node, 0); + network_add_node(node->network, node1); + lsForeachItem(po_list, gen, fanout) { + assert(node_patch_fanin(fanout, node, node1)); + } + LS_ASSERT(lsDestroy(po_list, (void (*)()) 0)); + } + } + + factor_invalid(node); + return 1; +} diff --git a/sis/node/iphase.c b/sis/node/iphase.c new file mode 100644 index 0000000..84d11f9 --- /dev/null +++ b/sis/node/iphase.c @@ -0,0 +1,61 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/iphase.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" + + +input_phase_t +node_input_phase(node, fanin) +node_t *node, *fanin; +{ + register int i; + register pset last, p; + register bool pos_used, neg_used; + + if (node_function(node) == NODE_PO) { + fail("node_input_phase: primary output node does not have a function"); + } + + pos_used = neg_used = FALSE; + + i = node_get_fanin_index(node, fanin); + if (i == -1) { + return PHASE_UNKNOWN; + } else { + foreach_set(node->F, last, p) { + switch(GETINPUT(p, i)) { + case ONE: + pos_used = TRUE; + break; + case ZERO: + neg_used = TRUE; + break; + case TWO: + break; + default: + fail("node_input_phase: bad cube"); + break; + } + } + } + + if (pos_used) { + if (neg_used) { + return BINATE; + } else { + return POS_UNATE; + } + } else { + if (neg_used) { + return NEG_UNATE; + } else { + return PHASE_UNKNOWN; + } + } +} diff --git a/sis/node/libhack.c b/sis/node/libhack.c new file mode 100644 index 0000000..be7fa62 --- /dev/null +++ b/sis/node/libhack.c @@ -0,0 +1,55 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/libhack.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "node_int.h" + + +/* + * this is a hack for the library package + * + * 1. collapse network so all nodes are SOP over the primary inputs + * 2. simplify each node so its all primes + * 3. re-adjust the fanin list of each node so that it is defined + * over the full support of all primary inputs; also, order this + * fanin so that it is in the same order as the primary input list + */ + +void +node_lib_process(network) +network_t *network; +{ + node_t *node, *pi, **new_fanin; + int i, new_nin; + pset_family func; + lsGen gen, gen1; + + (void) network_collapse(network); + + foreach_node(network, gen, node) { + if (node->type == INTERNAL) { + (void) node_simplify_replace(node, NIL(node_t), NODE_SIM_ESPRESSO); + } + } + + foreach_node(network, gen, node) { + if (node->type == INTERNAL) { + + i = 0; + new_nin = network_num_pi(network); + new_fanin = ALLOC(node_t *, new_nin); + foreach_primary_input(network, gen1, pi) { + new_fanin[i++] = pi; + } + + func = node_sf_adjust(node, new_fanin, new_nin); + node_replace_internal(node, new_fanin, new_nin, func); + } + } +} diff --git a/sis/node/names.c b/sis/node/names.c new file mode 100644 index 0000000..c3345ff --- /dev/null +++ b/sis/node/names.c @@ -0,0 +1,234 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/names.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" + +#include "node_int.h" + + +/* + * manage the node names + */ + + +name_mode_t name_mode; + +static int long_name_index; +static int short_name_index; +static char *hack_name(); + + +char * +node_name(node) +node_t *node; +{ + if (name_mode == LONG_NAME_MODE) { + if (node->name == NIL(char)) node_assign_name(node); + return hack_name(node, node->name); + } else { + if (node->short_name == NIL(char)) node_assign_short_name(node); + return hack_name(node, node->short_name); + } +} + + +char * +node_long_name(node) +node_t *node; +{ + return node->name; +} + + +void +node_assign_name(node) +node_t *node; +{ + static char buf[80]; + if (node->name != NIL(char)) FREE(node->name); + (void) sprintf(buf, "[%d]", long_name_index); + node->name = ALLOC(char, strlen(buf) + 1); + strcpy (node->name, buf); + long_name_index++; +} + + +void +node_assign_short_name(node) +node_t *node; +{ + int i, c; + + c = "abcdefghijklmnopqrstuvwxyz"[short_name_index % 26]; + i = short_name_index / 26; + + if (node->short_name != NIL(char)) FREE(node->short_name); + node->short_name = ALLOC(char, 10); + if (i == 0) { + (void) sprintf(node->short_name, "%c", c); + } else { + (void) sprintf(node->short_name, "%c%d", c, i-1); + } + short_name_index++; +} + + +static char * +hack_name(node, name) +node_t *node; +char *name; +{ + static char name1[1024]; + char *name2; + int count; + node_t *fanout; + lsGen gen; + node_type_t type; + network_t *net; + + type = node->type; + net = node->network; + if (type == UNASSIGNED || net == NIL(network_t)) { + return(name); + } + if (type == PRIMARY_INPUT) { + return(name); + } + else if (type == PRIMARY_OUTPUT) { +#ifdef SIS + if (network_is_real_po(net, node) == 0) { + count = 0; + foreach_fanout (node->fanin[0], gen, fanout) { + if (fanout->type == PRIMARY_OUTPUT) { + count++; + } + } + if (count == 1) { + node = node->fanin[0]; + name = name_mode == LONG_NAME_MODE ? node->name : node->short_name; + } + } +#endif /* SIS */ + (void) strcpy(name1, "{"); + (void) strcat(name1, name); + (void) strcat(name1, "}"); + return name1; + } + count = 0; + (void) strcpy(name1, "{"); + foreach_fanout (node, gen, fanout) { + +#ifdef SIS + if (network_is_real_po(net, fanout) != 0) { + if (++count > 1) { + (void) strcat(name1, ","); + } + name2 = name_mode == LONG_NAME_MODE ? fanout->name : fanout->short_name; + (void) strcat(name1, name2); + } +#else + if (fanout->type == PRIMARY_OUTPUT) { + if (++count > 1) { + (void) strcat(name1, ","); + } + name2 = name_mode == LONG_NAME_MODE ? + fanout->name : fanout->short_name; + (void) strcat(name1, name2); + } +#endif /* SIS */ + + } + (void) strcat(name1, "}"); + return count == 0 ? name : name1; +} + +int +node_is_madeup_name(name, value) +char *name; +int *value; +{ + if (name[0] == '[' && name[strlen(name)-1] == ']') { + if (sscanf(name, "[%d]", value) == 1) { + return 1; + } + } + return 0; /* not a made-up name */ +} + + +void +network_reset_long_name(network) +network_t *network; +{ + lsGen gen; + node_t *node; + int index; + + long_name_index = 0; + foreach_node(network, gen, node) { + if (node_is_madeup_name(node->name, &index)) { + node_assign_name(node); + } + } + network_rehash_names(network, /* long */ 1, /* short */ 0); +} + + +void +network_reset_short_name(network) +network_t *network; +{ + lsGen gen; + node_t *node; + + short_name_index = 0; + foreach_primary_input(network, gen, node) { + node_assign_short_name(node); + } + foreach_primary_output(network, gen, node) { + node_assign_short_name(node); + } + foreach_node(network, gen, node) { + if (node->type != PRIMARY_INPUT && node->type != PRIMARY_OUTPUT) { + node_assign_short_name(node); + } + } + network_rehash_names(network, /* long */ 0, /* short */ 1); +} + +void +network_rehash_names(network, long_name, short_name) +network_t *network; +register int long_name, short_name; +{ + lsGen gen; + node_t *p; + int found; + + if (long_name) { + st_free_table(network->name_table); + network->name_table = st_init_table(strcmp, st_strhash); + } + if (short_name) { + st_free_table(network->short_name_table); + network->short_name_table = st_init_table(strcmp, st_strhash); + } + + foreach_node(network, gen, p) { + if (long_name) { + found = st_insert(network->name_table, p->name, (char *) p); + assert(! found); + } + if (short_name) { + found = st_insert(network->short_name_table, + p->short_name, (char *) p); + assert(! found); + } + } +} diff --git a/sis/node/node.c b/sis/node/node.c new file mode 100644 index 0000000..b878e33 --- /dev/null +++ b/sis/node/node.c @@ -0,0 +1,712 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/node.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "node_int.h" + +/* + * node_and -- form f * g + */ + +node_t * +node_and(f, g) +node_t *f, *g; +{ + pset_family newf, newg, func; + node_t **new_fanin, *r; + int new_nin; + + if (f->F == 0 || g->F == 0) { + fail("node_and: node does not have a function"); + } + if (f->nin == 0) { + if (f->F->count == 0) { + return node_constant(0); /* f == 0, therefore 0 & g == 0 */ + } else { + r = node_dup(g); + FREE(r->name); + r->name = NIL(char); /* FREE does set it to nil, this is */ + /* for safety */ + FREE(r->short_name); + r->short_name = NIL(char); + return r; /* f == 1, therefore 1 & g == g */ + } + } else if (g->nin == 0) { + if (g->F->count == 0) { /* g == 0, therefore f & 0 == 0 */ + return node_constant(0); + } else { + r = node_dup(f); + FREE(r->name); + r->name = NIL(char); /* FREE does set it to nil, this is */ + /* for safety */ + FREE(r->short_name); + r->short_name = NIL(char); + return r; /* g == 1, therefore f & 1 == f */ + } + } + + /* express f and g in a common base */ + make_common_base(f, g, &new_fanin, &new_nin, &newf, &newg); + + /* define the cube size (needed for intersection) */ + define_cube_size(new_nin); + + /* compute intersection */ + func = cv_intersect(newf, newg); + sf_free(newf); + sf_free(newg); + + /* allocate a new node */ + r = node_create(func, new_fanin, new_nin); + r->is_dup_free = 1; /* make_common_base assures this */ + r->is_scc_minimal = 1; /* cv_intersect() assures this */ + node_minimum_base(r); + return r; +} + +/* + * node_or -- form f + g + */ + +node_t * +node_or(f, g) +node_t *f, *g; +{ + pset_family newf, newg, func; + node_t **new_fanin, *r; + int new_nin; + + if (f->F == 0 || g->F == 0) { + fail("node_or: node does not have a function"); + } + if (f->nin == 0) { + if (f->F->count == 0) { + r = node_dup(g); + FREE(r->name); + r->name = NIL(char); /* FREE does set it to nil, this is */ + /* for safety */ + FREE(r->short_name); + r->short_name = NIL(char); + return r; /* f == 0, therefore 0 | g == g */ + } else { + return node_constant(1); /* f == 1, therefore 1 | g == 1 */ + } + } else if (g->nin == 0) { + if (g->F->count == 0) { /* g == 0, therefore f | 0 == f */ + r = node_dup(f); + FREE(r->name); + r->name = NIL(char); /* FREE does set it to nil, this is */ + /* for safety */ + FREE(r->short_name); + r->short_name = NIL(char); + return r; + } else { + return node_constant(1); /* g == 1, therefore f | 1 == 1 */ + } + } + + /* express f and g in a common base */ + make_common_base(f, g, &new_fanin, &new_nin, &newf, &newg); + + /* compute union */ + func = sf_contain(sf_append(newf, newg)); + + /* allocate a new node */ + r = node_create(func, new_fanin, new_nin); + r->is_dup_free = 1; /* make_common_base assures this */ + r->is_scc_minimal = 1; /* sf_contain() above assures this */ + node_minimum_base(r); + return r; +} + +/* + * node_not -- form NOT f + */ + +node_t * +node_not(f) +node_t *f; +{ + node_t *r; + + if (f->F == 0) { + fail("node_not: node does not have a function"); + } + if (f->nin == 0) { + return node_constant(f->F->count == 0); + } + + node_complement(f); + r = node_create(sf_save(f->R), nodevec_dup(f->fanin, f->nin), f->nin); + r->is_dup_free = f->is_dup_free; /* inherit whatever f was */ + r->is_scc_minimal = 1; /* node_complement() guarantees this */ + node_minimum_base(r); + return r; +} + +/* + * node_xor -- form f <xor> g + */ + +node_t * +node_xor(f, g) +node_t *f, *g; +{ + node_t *fbar, *gbar, *t0, *t1, *r; + + fbar = node_not(f); + gbar = node_not(g); + t0 = node_and(fbar, g); + t1 = node_and(f, gbar); + r = node_or(t0, t1); + node_free(fbar); + node_free(gbar); + node_free(t0); + node_free(t1); + return r; +} + +/* + * node_xnor -- form f <xnor> g (also known as eqv ...) + */ + +node_t * +node_xnor(f, g) +node_t *f, *g; +{ + node_t *fbar, *gbar, *t0, *t1, *r; + + fbar = node_not(f); + gbar = node_not(g); + t0 = node_and(f, g); + t1 = node_and(fbar, gbar); + r = node_or(t0, t1); + node_free(fbar); + node_free(gbar); + node_free(t0); + node_free(t1); + return r; +} + +node_t * +node_literal(f, phase) +node_t *f; +int phase; +{ + node_t *r, **fanin; + pset_family func; + pset pdest; + + fanin = ALLOC(node_t *, 1); + fanin[0] = f; + + func = sf_new(1, 2); + pdest = GETSET(func, func->count++); + (void) set_clear(pdest, 2); + set_insert(pdest, phase); + r = node_create(func, fanin, 1); + r->is_dup_free = 1; /* isn't it obvious ... */ + r->is_scc_minimal =1; /* obviously ... */ + return r; +} + +node_t * +node_constant(phase) +int phase; +{ + node_t *r; + pset_family func; + + func = sf_new(1, 0); + switch(phase) { + case 0: + break; + case 1: + func->count++; + break; + default: + fail("node_constant: phase must be 0 or 1"); + } + r = node_create(func, NIL(node_t *), 0); + r->is_dup_free = 1; /* isn't it obvious ... */ + r->is_scc_minimal = 1; /* obviously ... */ + return r; +} + +node_t * +node_largest_cube_divisor(f) +node_t *f; +{ + pset_family func; + pset supercube; + node_t *r; + + if (f->F == 0) { + fail("node_largest_cube_divisor: node does not have a function"); + } + if (f->nin == 0) { + return node_constant(1); + } + + supercube = sf_or(f->F); + func = sf_new(1, f->nin * 2); + (void) set_copy(GETSET(func, func->count++), supercube); + set_free(supercube); + + r = node_create(func, nodevec_dup(f->fanin, f->nin), f->nin); + r->is_dup_free = f->is_dup_free; /* inherit whatever f was */ + r->is_scc_minimal = 1; /* a single cube is scc-minimal */ + node_minimum_base(r); + return r; +} + +/* + * node_contains -- see if node f contains node g + */ + +int +node_contains(f, g) +node_t *f, *g; +{ + pset last, p, *flist; + pset_family newf, newg; + node_t **new_fanin; + int contains, new_nin; + + if (f->F == 0 || g->F == 0) { + fail("node_contains: node does not have a function"); + } + + /* express f and g in a common base */ + make_common_base(f, g, &new_fanin, &new_nin, &newf, &newg); + + /* define the cube size */ + define_cube_size(new_nin); + + flist = cube1list(newf); + contains = 1; + foreach_set(newg, last, p) { + if (! cube_is_covered(flist, p)) { + contains = 0; + break; + } + } + + FREE(new_fanin); + free_cubelist(flist); + sf_free(newf); + sf_free(newg); + return contains; +} + +/* + * node_equal -- see if node f and node g are Boolean equal + */ + +int +node_equal(f, g) +node_t *f, *g; +{ + return node_contains(f, g) && node_contains(g, f); +} + +/* + * node_equal_by_name -- see if node1 == node2 (boolean sense) + */ + +int +node_equal_by_name(f, g) +node_t *f, *g; +{ + pset last, p, *flist, *glist; + pset_family newf, newg; + node_t **new_fanin; + int eql, new_nin; + + if (f->type == PRIMARY_INPUT || f->type == PRIMARY_OUTPUT) { + return f->type == g->type; + } + if (g->type == PRIMARY_INPUT || g->type == PRIMARY_OUTPUT) { + return f->type == g->type; + } + + if (f->F == 0 || g->F == 0) { + fail("node_equal_by_name: node does not have a function"); + } + + /* express f and g in a common base */ + make_common_base_by_name(f, g, &new_fanin, &new_nin, &newf, &newg); + if (new_nin == 0) { + eql = (newf->count == newg->count); + goto exit_free1; + } + + /* define the cube size */ + define_cube_size(new_nin); + + flist = cube1list(newf); + glist = cube1list(newg); + + foreach_set(newf, last, p) { + if (! cube_is_covered(glist, p)) { + eql = 0; + goto exit_free; + } + } + + foreach_set(newg, last, p) { + if (! cube_is_covered(flist, p)) { + eql = 0; + goto exit_free; + } + } + eql = 1; + +exit_free: + free_cubelist(flist); + free_cubelist(glist); +exit_free1: + FREE(new_fanin); + sf_free(newf); + sf_free(newg); + return eql; +} + +node_t * +node_sort_for_printing(f) +node_t *f; +{ + pset_family newf, newg, func; + node_t **new_fanin, *g, *r; + int new_nin; + + if (f->type == PRIMARY_INPUT || f->type == PRIMARY_OUTPUT) { + return node_dup(f); + } + if (f->F == 0) { + fail("node_sort_for_printing: node does not have a function"); + } + if (f->nin == 0 || f->F->count <= 0) { + return node_dup(f); + } + + g = node_constant(0); + make_common_base_by_name(f, g, &new_fanin, &new_nin, &newf, &newg); + + func = sf_unlist(sf_sort(newf, fancy_lex_order), + newf->count, newf->sf_size); + + /* allocate a new node */ + r = node_create(func, new_fanin, new_nin); + r->is_dup_free = 1; /* make_common_base assures this */ + r->is_scc_minimal = 1; /* pretend like it is */ + sf_free(newf); + sf_free(newg); + node_free(g); + return r; +} + +node_function_t +node_function(node) +node_t *node; +{ + register pset last, p; + + if (node->type == PRIMARY_INPUT) { + return NODE_PI; + + } else if (node->type == PRIMARY_OUTPUT) { + return NODE_PO; + + } else if (node->F == 0) { + return NODE_UNDEFINED; + + } else if (node->F->count == 0) { + if (node->nin != 0) goto failure; + return NODE_0; + + } else if (node->F->count == 1) { + p = GETSET(node->F, 0); + if (node->nin == 0) { + return NODE_1; + } else if (node->nin == 1) { + switch(GETINPUT(p, 0)) { + case ONE: + return NODE_BUF; + case ZERO: + return NODE_INV; + default: + goto failure; + } + } else { + if (node->nin * 2 - set_ord(p) != node->nin) goto failure; + return NODE_AND; + } + + } else { + foreach_set(node->F, last, p) { + if (set_ord(p) != node->nin*2 - 1) { + return NODE_COMPLEX; + } + } + return NODE_OR; + } + +failure: + fail("node_function: function is not minimum-base"); + return NODE_COMPLEX; /* never actually executed */ +} + +node_type_t +node_type(node) +node_t *node; +{ + return(node->type); +} + + +int +node_simplify_replace(F, D, mode) +node_t *F, *D; +node_sim_type_t mode; +{ + node_t *newF; + + newF = node_simplify(F, D, mode); + if (node_num_literal(newF) < node_num_literal(F)) { + node_replace(F, newF); + return 1; + } else { + node_free(newF); + return 0; + } +} + +node_t * +node_simplify(node_F, node_D, mode) +node_t *node_F, *node_D; +node_sim_type_t mode; +{ + int new_nin, dummy; + pset_family newf, newd, newr, temp; + node_t *r, **new_fanin; + + if (node_F->F == 0) { + fail("node_simplify: node does not have a function"); + } + if (node_F->F->count <= 0 || node_F->nin == 0) { + return node_dup(node_F); + } + + /* force a D, even if we just make a constant function */ + dummy = 0; + if (node_D == NIL(node_t)) { + node_D = node_constant(0); + dummy = 1; + } + + /* express F and D in a common base */ + make_common_base(node_F, node_D, &new_fanin, &new_nin, &newf, &newd); + define_cube_size(new_nin); + + if (dummy) { + node_free(node_D); + } + + switch(mode) { + case NODE_SIM_SCC: + newf = sf_contain(newf); + break; + case NODE_SIM_SIMPCOMP: + temp = simplify(cube1list(newf)); + sf_free(newf); + newf = temp; + break; + case NODE_SIM_ESPRESSO: + newr = complement(cube2list(newf, newd)); + newf = espresso(newf, newd, newr); + sf_free(newr); + break; + case NODE_SIM_EXACT: + newf = minimize_exact(newf, newd, NIL(set_family_t), /*exact*/ 1); + break; + case NODE_SIM_EXACT_LITS: + newf = minimize_exact_literals(newf, newd, NIL(set_family_t), /*exact*/ 1); + break; + case NODE_SIM_DCSIMP: + newf = minimize(newf, newd, DCSIMPLIFY); + break; + case NODE_SIM_NOCOMP: + newf = minimize(newf, newd, NOCOMP); + break; + case NODE_SIM_SNOCOMP: + newf = minimize(newf, newd, SNOCOMP); + break; + default: + fail("node_simplify: bad mode\n"); + break; + } + + /* allocate a new node */ + r = node_create(newf, new_fanin, new_nin); + r->is_dup_free = 1; /* make_common_base assures this */ + r->is_scc_minimal = 1; /* minimization assures this */ + node_minimum_base(r); + sf_free(newd); + return r; +} + +void +node_scc(node) +node_t *node; +{ + node->is_scc_minimal = 0; /* be pessimistic */ + node->is_dup_free = 0; /* be pessimistic */ + node_minimum_base(node); +} + +int +node_num_literal(node) +node_t *node; +{ + register int count; + register pset last, p; + + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) { + return 0; + } + if (node->F == 0) { + fail("node_num_literal: node does not have a function"); + } + if (node->F->count <= 0 || node->nin == 0) { + return 0; + } + + count = 0; + foreach_set(node->F, last, p) { + count += node->nin * 2 - set_ord(p); + } + return count; +} + + +int +node_num_cube(node) +node_t *node; +{ + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) { + return 0; + } + if (node->F == 0) { + fail("node_num_cube: node does not have a function"); + } + return node->F->count; +} + +int * +node_literal_count(node) +node_t *node; +{ + register pset last, p, fullset; + register int *count; + pset_family temp; + + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) { + return 0; + } + if (node->F == 0) { + fail("node_literal_count: node does not have a function"); + } + if (node->nin == 0) { + return ALLOC(int, 1); /* no literals in any variables */ + } + + temp = sf_save(node->F); + fullset = set_fill(set_new(node->nin*2), node->nin*2); + foreach_set(temp, last, p) { + (void) set_diff(p, fullset, p); + } + count = sf_count(temp); + set_free(fullset); + sf_free(temp); + + return count; +} + +void +node_complement(node) +node_t *node; +{ + /* if its already there, assume its correct */ + if (node->R != 0) { + return; + } + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) { + return; + } + if (node->F == 0) { + fail("node_complement: node does not have a function"); + } + if (node->nin == 0) { + node->R = sf_new(4, 0); + node->R->count = 1 - (node->F->count > 0); + } else { + define_cube_size(node->nin); + node->R = sf_contain(complement(cube1list(node->F))); + } +} + +/* repeated distance 1 merge */ +void +node_d1merge(f) +node_t *f; +{ + + int nin, i, lit_count; + + nin = node_num_fanin(f); + define_cube_size(nin); + + do { + lit_count = node_num_literal(f); + for (i = 0; i < nin; i ++) { + f->F = d1merge(f->F, i); + } + } while (lit_count > node_num_literal(f)); + + f->is_dup_free = 1; + f->is_scc_minimal = 1; + node_minimum_base(f); +} + +int +node_error(code) +int code; +{ + switch(code) { + case 0: + fail("node_get_cube: node does not have a function"); + /* NOTREACHED */ + case 1: + fail("node_get_cube: cube index out of bounds"); + /* NOTREACHED */ + case 2: + fail("node_get_literal: bad cube"); + /* NOTREACHED */ + case 4: + fail("foreach_fanin: node changed during generation"); + /* NOTREACHED */ + case 5: + fail("foreach_fanout: node changed during generation"); + /* NOTREACHED */ + default: + fail("error code unused"); + } + return 0; +} diff --git a/sis/node/node.doc b/sis/node/node.doc new file mode 100644 index 0000000..6fa34cc --- /dev/null +++ b/sis/node/node.doc @@ -0,0 +1,656 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/node.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +Description: + The node package for SIS. + + +Summary: + node_alloc() + node_free() + node_dup() + + node_name() + node_network() + node_num_literal() + node_num_cube() + node_num_fanin() + node_num_fanout() + node_get_fanin() + node_get_fanout() + node_get_fanin_index() + node_get_fanout_index() + node_get_cube() + node_get_literal() + node_literal_count() + + foreach_fanin() + foreach_fanout() + foreach_fanout_pin() + + node_and() + node_or() + node_not() + node_xor() + node_xnor() + node_div() + node_literal() + node_constant() + node_cofactor() + node_simplify() + node_algebraic_cofactor() + node_largest_cube_divisor() + node_replace() + + node_collapse() + node_substitute() + node_invert() + node_scc() + node_d1merge() + node_function() + node_input_phase() + + node_contains() + node_equal() + node_equal_by_name() + + node_print() + node_print_rhs() + node_print_negative() + + node_register_daemon() + +node_t * +node_alloc() + Allocate a new node. + + +void +node_free(node) +node_t *node; + Free a node. + + +network_t * +node_network(node) +node_t *node; + Returns the network this node belongs to. + + +node_t * +node_dup(node) +node_t *node; + Duplicate a node. + + +int +node_num_literal(node) +node_t *node; + Returns the number of literals in the function. Note that + constant-valued functions have no literals. + + +int +node_num_cube(node) +node_t *node; + Returns the number of cubes in the sum-of-products form for the + function. Note that the 0 function has no cubes, and the 1 + function has 1 cube. + + +int * +node_literal_count(node) +node_t *node; + Returns an array of the literal counts for each variable in the + fanin of a node. The array has twice as many entries as inputs + to the node; entry [2*j] gives the number of positive phase + literals for input 'j', and the entry for [2*j+1] gives the + number of negative phase literals for input 'j'. Typically + this array is accessed from with a fanin generation loop. The + array should be freed when you no longer need it. + +/* Basic node computation routines */ + +The basic operations are supported. The routines all return a new node +as their result, and leave the arguments unchanged. This new node is +not part of a network until it is explicitly added using network_add_node(). + +The implementation guarantees that the result of any operation is +single-cube containment minimal, and is expressed over its minimum +support. (Of course, Boolean redundancy may hide the fact that a +function doesn't really depend on some input.) + + +node_t * +node_and(f, g) +node_t *f, *g; + Computes f * g for two nodes. + + +node_t * +node_or(f, g) +node_t *f, *g; + Computes f + g for two nodes. + + +node_t * +node_not(f) +node_t *f; + Computes the complement of a node f. Potentially very efficient + if the complement of f is already computed and stored. + + +node_t * +node_xor(f, g) +node_t *f, *g; + Computes f <xor> g for two nodes. + + +node_t * +node_xnor(f, g) +node_t *f, *g; + Computes f <xnor> g for two nodes. + + +node_t * +node_div(f, g, r) +node_t *f, *g; +node_t **r; + Computes algebraic quotient f/g for two nodes. f and g are not + changed. If r is not null, then the algebraic remainder is + also returned. + + +node_t * +node_literal(f, phase) +node_t *f; +int phase; + Compute the literal function of f, and allocate a new node for + the result. phase indicates the resulting phase of the literal + (0 for complemented, 1 for uncomplemented). + + +node_t * +node_constant(phase) +int phase; + Returns a constant-valued function, depending on phase. + (phase == 0 is the 0 function, phase == 1 is the 1 function). + + +node_t * +node_simplify(F, D, mode) +node_t *F; +node_t *D; +node_sim_type_t mode; + Minimize the function 'F' using 'D' as a don't-care set. 'D' + may be NIL(node_t) which implies no don't-care set. 'mode' is + one of NODE_SIM_SCC, NODE_SIM_SIMPCOMP, or NODE_SIM_ESPRESSO to + choose the minimization algorithm for simplifying the function + 'F'. Note that NODE_SIM_SCC and NODE_SIM_SIMPCOMP ignore any + don't-care set which is given. + + +node_t * +node_largest_cube_divisor(f) +node_t *f; + Returns the largest single-cube divisor of a node. + + +void +node_replace(r, f) +node_t *r, *f; + Replace node r of a network with f. f is freed. Only the logic + function of `r' is affected, all other information associated + with the node remains intact. (See node_register_daemon() for + more information on how to keep other information up-to-date.) + +node_type_t { + PRIMARY_OUTPUT, PRIMARY_INPUT, INTERNAL +}; + +node_type_t +node_type(n) +node_t *n; + Returns the type of node n. + + +node_function_t { + NODE_PI, NODE_PO, NODE_0, NODE_1, NODE_BUF, NODE_INV, + NODE_AND, NODE_OR, NODE_COMPLEX, NODE_UNDEFINED +}; + + +node_function_t +node_function(f) +node_t *f; + Returns the type of the logic function for f. NODE_PI and + NODE_PO indicate the node is a primary input or a primary + output of a network. NODE_0 and NODE_1 indicate a + constant-valued function. NODE_INV and NODE_BUF indicate a + single literal function (either positive for negative). + NODE_AND indicates a single-product term in the function, and + NODE_OR indicates many product terms, each with a single + literal. NODE_COMPLEX means the logic function is some other + more complex function. Note that NODE_AND or NODE_OR are + returned even if variables are used in their complemented + form. Also, not that NODE_AND or NODE_OR requires 2 or more + inputs (if there is only a single input, the function must be + NODE_0, NODE_1, NODE_INV, or NODE_BUF). NODE_UNDEFINED means + the node has not been given a logic function yet. + + +input_phase_t { + POS_UNATE, NEG_UNATE, BINATE, PHASE_UNKNOWN +}; + +input_phase_t +node_input_phase(f, g) +node_t *f, *g; + Finds out how variable g is used in function f. If g is not + used in f, PHASE_UNKNOWN is returned. If it is used only in + the positive form, POS_UNATE is returned; if it is used only in + the negative form, NEG_UNATE is returned. If used in both + phases, BINATE is returned. + + +/* higher level constructs */ + +These routines are built conceptually on-top of the previous basic +operations. They affect a node in place. They all return a status +code indicating whether the function has actually been changed. +This is 1 if the operation changes the node, or 0 if the nodes is +not changed. These routines gracefully handle boundary conditions +with repsect to being given PRIMARY_INPUT and PRIMARY_OUTPUT nodes. + + +int +node_collapse(f, g) +node_t *f, *g; + Assuming g is an input to f, re-express f without using g. + Changes f in-place, g is unchanged. + + +int +node_substitute(f, g, flag) +node_t *f, *g; +int flag; + Attempts to re-express f in terms of g. `flag' equal to 1 + allows the complement of g to be used as well. Changes f + in-place, g is unchanged. Returns 1 if f is changed (i.e., if + g does actually divide into f), or 0 if f is not changed. If + either f or g is a PRIMARY_INPUT, or a PRIMARY_OUTPUT then f is + not changed. Also, if f equals g (i.e., attempt to substitute + a node into itself), then f is not changed. + + +int +node_invert(node) +node_t *node; + Inverts a node in-place. Replaces the node with its complement, + and then complements the phase of each fanout. That is, if the + node is used in the positive phase of a fanout, this is switched + to negative phase, and vice-versa. Thus, the logic function of + the network is preserved. (Note that this is equivalent to + an in-place node_not() if the node is not in a network.) + + +void +node_scc(node) +node_t *node; + Makes the function single-cube containment (scc) minimal. + (That is, such that no term properly contains another term.) + +void +node_d1merge(node) +node_t *node; + Simplify the function by repeated distance-one merging. + +int +node_contains(f, g) +node_t *f, *g; + Returns 1 if f contains g (in a Boolean sense), or 0 if not. + Returns 0 if either f or g is a PRIMARY_INPUT. + + +int +node_equal(f, g) +node_t *f, *g; + Determines whether two nodes are Boolean equivalent. Returns 1 + if the nodes are equal, or 0 if unequal. Returns 0 if either f + or g is a PRIMARY_INPUT. + + +int +node_equal_by_name(f, g) +node_t *f, *g; + Determines whether two nodes represent the same Boolean logic + function. The inputs of the two nodes are associated by name + (hence, the strange '_by_name' appended to the function name). + What this means is that the two nodes do not necessarily have + to belong to the same network in order to compare them. Returns + 1 if the ndoes are equal, or 0 if unequal. + + +void +node_algebraic_cofactor(f, g, p, q, r) +node_t *f, *g; +node_t **p, **q, **r; + Forms the 'algebraic' cofactor of f with respect to g. p is + the positive phase, q is the negative phase, and r is the + remainder. Each cube of f is assigned to one of the three + functions p, q, or r based on whether it contains a ZERO, ONE, + or TWO in the position corresponding to the input g. + + In particular, f = p * g + q * g' + r. + + + +node_t * +node_cofactor(f, g) +node_t *f, *g; + Forms the Shannon cofactor of f with respect to g. This is + defined only when g is a single cube. + +/* Generators to traverse the graph structure of a network */ + +foreach_fanin(node, i, fanin) +node_t *node; +int i; +node_t *fanin; + Generates all of the inputs to a node. + + +foreach_fanout(node, gen, fanout) +node_t *node; +lsGen gen; +node_t *fanin; + Generates all of the fanouts of a node. + + +foreach_fanout_pin(node, gen, fanout, pin) +node_t *node; +lsGen gen; +node_t *fanin; +int pin; + Generates all of the fanouts of a node, including the input pin + numbers for the fanout gate. + + +These generators are macros. Typical usage is: + + foreach_fanin(node, i, fanin) { + /* do something with fanin */ + } + +It is a serious error to attempt to change a node while you are generating +its fanin. This will cause a run-time error. + +Only a node which is a network (i.e., using network_add_node()) has a +fanout defined. An attempt to generate the fanout of a node which is not +in a network will cause a run-time error. + +/* Looking at the Sum-of-products function stored at a node */ + +node_cube_t +node_get_cube(node, i) +node_t *node; +int i; + Returns the i'th cube of the function for a node. Use + node_num_cube() to find out how many cubes are in the + sum-of-products form for a given node. + + +typedef enum { + ZERO, ONE, TWO +} node_literal_t; + + +node_literal_t +node_get_literal(cube, j) +node_cube_t cube; +int j; + Returns the value of the j'th literal of the given cube. + The value is ONE, ZERO, or TWO. + + +Typical use of these functions: + + for(i = node_num_cube(node)-1; i >= 0; i--) { + cube = node_get_cube(node, i); + foreach_fanin(node, j, fanin) { + literal = node_get_literal(cube, j); + switch(literal) { + case ONE: + /* do something */ + break; + case ZERO: + /* do something else */ + break; + case TWO: + /* do last thing */ + break; + default: + fail("bad literal"); + /* NOTREACHED */ + } + } + } + +/* Looking at the fanin and fanouts for a node */ + + +int +node_num_fanin(node) +node_t *node; + Returns the number of inputs to node. + + +int +node_num_fanout(node) +node_t *node; + Returns the number of fanouts of node. + + +node_t * +node_get_fanin(node, n) +node_t *node; +int n; + Returns the n'th fanin of a node. fanin's are numbered starting + from 0. + + +node_t * +node_get_fanout(node, n) +node_t *node; +int n; + Returns the n'th fanout of a node. fanout's are numbered starting + from 0. + + +int +node_get_fanin_index(node, fanin) +node_t *node; +node_t *fanin; + Return the index of fanin as an input to node, or -1 if fanin + is not an input to node. + +char * +node_name(node) +node_t *node; + Returns the name of a node. Note that the global variable name_mode + affects whether a short name is used, or the user-supplied name. + Also, note that nodes which fanout to primary outputs are given + names of the form {output} using the primary output name. + + +char * +node_long_name(node) +node_t *node; + Returns the real name of a node. node_long_name() should be used + when matching nodes by name between two networks. + + +void +node_print(fp, node) +FILE *fp; +node_t *node; + Prints a node in the form "f = a b c' + d e f". Appends a trailing + newline. Uses node_name(), and hence depends on the current setting + of long names versus short names. + + +void +node_print_rhs(fp, node) +FILE *fp; +node_t *node; + Prints the right-hand-side of a node (that is, in the previous + example, "a b c' + d e f". Does not append a trailing newline. + Uses node_name(), and hence depends on the current setting of + long names versus short names. + + +void +node_print_negative(fp, node) +FILE *fp; +node_t *node; + Prints a node in negative form (i.e., "f = (abc)'" rather than + "f = a' + b' + c'". Appends a trailing newline. Uses node_name(), + and hence depends on the current setting of long names versus + short names. + +/* node daemons */ + +Many routines need to store information along with a node. Currently, +a rudimentary mechanism exists for a package to maintain these +extra data fields. A 'daemon' can be registered with the node package, +and then this daemon will be called when the node is allocated, freed, +duplicated, or changed. + +The goal with using these daemons is to minimize the effect on +other packages (especially the node package) when extra fields +are added to the node structure. + +The current prototype for using this package is the factoring package. +The factoring package will do the following in its startup code: + + node_register_daemon(DAEMON_ALLOC, factor_alloc); + node_register_daemon(DAEMON_FREE, factor_free); + node_register_daemon(DAEMON_DUP, factor_dup); + node_register_daemon(DAEMON_INVALID, factor_invalid); + +A single slot is (can be) reserved in the node structure for each package. +The package can use this pointer to store whatever information it wishes +to associate with the node. A single slot named 'undef1' is also +present, and can be used for development of a new package before the +header file reflects the addition of this new slot to the node structure. + +This slot should be accessed with macros like: + + #define FACTOR_SLOT undef1 + #define FACTOR(node) ((factor_type_t *) (node)->FACTOR_SLOT) + +This allows code like: + + FACTOR(node)->this_thing = 1; + +For development purposes, FACTOR_SLOT is set to the field `undef1'. When +the package is released and installed, the single change of FACTOR_SLOT to +e.g., `factored' (along with a corresponding minor change in the node package) +is all that is needed to allow the factor package to have its own slot +in the node structure. + +Example: + +The routines factor_alloc, factor_free, factor_dup, and factor_invalid +probably look something like: + + + typedef struct factor_struct factor_type_t ; + struct factor_struct { + some_type_t tree; + int this_or_that; + }; + + + #define FACTOR_SLOT factored + #define FACTOR(node) ((factor_type_t *) (node)->FACTOR_SLOT) + + + void factor_alloc(node) + node_t *node; + { + node->FACTOR_SLOT = ALLOC(factor_type_t, 1); + FACTOR(node)->tree = 0; + FACTOR(node)->this_or_that = 0; + } + + + void factor_free(node) + node_t *node; + { + if (FACTOR(node)->tree != 0) do_factored_free(FACTOR(node)->tree); + FREE(node->FACTOR_SLOT); + } + + + void factor_dup(old, new) + node_t *old, *new; + { + /* note that factor_alloc has already been called for new */ + FACTOR(new)->tree = do_factored_dup(FACTOR(old)->tree); + FACTOR(new)->this_or_that = FACTOR(old)->this_or_that; + } + + + void factor_invalid(node) + node_t *node; + { + if (FACTOR(node)->tree != 0) do_factored_free(FACTOR(node)->tree) + FACTOR(node)->tree = 0; + FACTOR(node)->this_or_that = 0; + } + +node_daemon_type_t { + DAEMON_ALLOC, DAEMON_FREE, DAEMON_DUP, DAEMON_INVALID +}; + + +void +node_register_daemon(type, func) +node_daemon_type_t type; +void (*func)(); + + Register a daemon to be called when a node is allocated + (DAEMON_ALLOC), freed (DAEMON_FREE), duplicated (DAEMON_DUP), + or invalidated (DAEMON_INVALID). A node is 'invalidated' when + the logic function stored at the node is changed. Currently, + this is possible only with the node_replace() function. + + The function for allocated, free, and invalidated daemons is called: + + void + allocate_daemon(node) + node_t *node; + + + For the duplicate daemon, the function is called with + both the old and new nodes: + + void + dup_daemon(old, new) + node_t *old, *new; + + Warning: when the daemon for DAEMON_DUP is called, the daemon + for DAEMON_ALLOC (if any) has already been called for the 'new' + node. + + The daemon routine is able to do whatever it wishes with the + node it is passed. Typically, it will play with its own + pointer, and initialize, free, invalidate, or duplicate the + corresponding information. diff --git a/sis/node/node.h b/sis/node/node.h new file mode 100644 index 0000000..0b3d7ec --- /dev/null +++ b/sis/node/node.h @@ -0,0 +1,210 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/node.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#ifndef NODE_H +#define NODE_H + +/* ... belongs in network.h, but node and network reference each other ... */ +typedef struct network_struct network_t; +typedef struct node_struct node_t; + + +typedef enum node_function_enum node_function_t; +enum node_function_enum { + NODE_PI, NODE_PO, NODE_0, NODE_1, NODE_BUF, NODE_INV, + NODE_AND, NODE_OR, NODE_COMPLEX, NODE_UNDEFINED +}; + + +typedef enum name_mode_enum name_mode_t; +enum name_mode_enum { + LONG_NAME_MODE, SHORT_NAME_MODE +}; + + +typedef enum node_type_enum node_type_t; +enum node_type_enum { + PRIMARY_INPUT, PRIMARY_OUTPUT, INTERNAL, UNASSIGNED +}; + + +typedef enum node_daemon_type_enum { + DAEMON_ALLOC=0, DAEMON_FREE=1, DAEMON_INVALID=2, DAEMON_DUP=3 +} node_daemon_type_t; + + +typedef enum input_phase_enum input_phase_t; +enum input_phase_enum { + POS_UNATE, NEG_UNATE, BINATE, PHASE_UNKNOWN +}; + + +typedef struct fanout_struct fanout_t; +struct fanout_struct { + node_t *fanout; + int pin; +}; + + +typedef enum node_sim_enum node_sim_type_t; +enum node_sim_enum { + NODE_SIM_SCC, NODE_SIM_SIMPCOMP, NODE_SIM_ESPRESSO, + NODE_SIM_EXACT, NODE_SIM_EXACT_LITS, NODE_SIM_DCSIMP, + NODE_SIM_NOCOMP, NODE_SIM_SNOCOMP +}; + + +struct node_struct { + char *name; /* name of the output signal */ + char *short_name; /* short name for interactive use */ + node_type_t type; /* type of the node */ + + int sis_id; /* unique id (used to sort fanin) */ + + unsigned fanin_changed:1; /* flag to catch fanin generation errors */ + unsigned fanout_changed:1; /* flag to catch fanout generation errors */ + unsigned is_dup_free:1; /* node has no aliasing of its fanin */ + unsigned is_min_base:1; /* node is minimum base */ + unsigned is_scc_minimal:1; /* node is scc-minimal */ + + int nin; /* number of inputs */ + node_t **fanin; + + lsList fanout; /* list of 'fanout_t' structures */ + lsHandle *fanin_fanout; /* handles of our fanin's fanout_t structure */ + + pset_family F; /* on-set */ + pset_family D; /* dc-set -- currently unused */ + pset_family R; /* off-set */ + + node_t *copy; /* used by network_dup(), network_append() */ + + network_t *network; /* network this node belongs to */ + lsHandle net_handle; /* handle inside of network nodelist */ + + char *simulation; /* reserved for simulation package */ + char *factored; /* reserved for factoring package */ + char *delay; /* reserved for delay package */ + char *map; /* reserved for mapping package */ + char *simplify; /* reserved for simplify package */ + char *bdd; /* reserved for bdd package */ + char *pld; /* reserved for pld package */ + char *ite; /* reserved for pld package */ + char *buf; /* reserved for buffer package */ + char *cspf; /* reserved for cspf (simplify) package */ + char *bin; /* reserved for binning (mapping) package */ + char *atpg; /* reserved for atpg package */ + char *undef1; /* undefined 1 */ +}; + +typedef pset node_cube_t; +typedef int node_literal_t; + +#define foreach_fanin(node, i, p) \ + for(i = 0, node->fanin_changed = 0; \ + node->fanin_changed ? node_error(4) : \ + i < (node)->nin && (p = node->fanin[i]); i++) + +#define foreach_fanout(node, gen, p) \ + for(node->fanout_changed = 0, gen = node_fanout_init_gen(node); \ + node->fanout_changed ? (node_t *) node_error(5) : \ + (p = node_fanout_gen(gen, NIL(int))); ) + +#define foreach_fanout_pin(node, gen, p, pin) \ + for(node->fanout_changed = 0, gen = node_fanout_init_gen(node); \ + node->fanout_changed ? (node_t *) node_error(5) : \ + (p = node_fanout_gen(gen, &pin)); ) + +#define node_get_cube(f_, i_) \ + ((f_)->F ? \ + ((i_) >= 0 && (i_) < (f_)->F->count ? GETSET((f_)->F, (i_)) : \ + (node_cube_t) node_error(0)) \ + : (node_cube_t) node_error(1)) + +#define node_get_literal(c_, j_) \ + ((c_) ? GETINPUT((c_), (j_)) : (node_literal_t) node_error(2)) + + +extern name_mode_t name_mode; + +EXTERN node_t *node_alloc ARGS((void)); +EXTERN void node_free ARGS((node_t *)); +EXTERN node_t *node_dup ARGS((node_t *)); +EXTERN void node_register_daemon ARGS((enum node_daemon_type_enum, void (*)())); +EXTERN network_t *node_network ARGS((node_t *)); + +EXTERN node_t *node_and ARGS((node_t *, node_t *)); +EXTERN node_t *node_or ARGS((node_t *, node_t *)); +EXTERN node_t *node_not ARGS((node_t *)); +EXTERN node_t *node_xor ARGS((node_t *, node_t *)); +EXTERN node_t *node_xnor ARGS((node_t *, node_t *)); +EXTERN node_t *node_div ARGS((node_t *, node_t *, node_t **)); +EXTERN node_t *node_literal ARGS((node_t *, int)); +EXTERN node_t *node_constant ARGS((int)); +EXTERN node_t *node_cofactor ARGS((node_t *, node_t *)); +EXTERN node_t *node_simplify ARGS((node_t *, node_t *, enum node_sim_enum)); +EXTERN node_t *node_largest_cube_divisor ARGS((node_t *)); +EXTERN void node_replace ARGS((node_t *, node_t *)); + +EXTERN int node_contains ARGS((node_t *, node_t *)); +EXTERN int node_equal ARGS((node_t *, node_t *)); +EXTERN int node_equal_by_name ARGS((node_t *, node_t *)); + +EXTERN char *node_name ARGS((node_t *)); +EXTERN char *node_long_name ARGS((node_t *)); +EXTERN int node_num_literal ARGS((node_t *)); +EXTERN int node_num_cube ARGS((node_t *)); +EXTERN int *node_literal_count ARGS((node_t *)); +EXTERN int node_num_fanin ARGS((node_t *)); +EXTERN int node_num_fanout ARGS((node_t *)); +EXTERN node_t *node_get_fanin ARGS((node_t *, int)); +EXTERN node_t *node_get_fanout ARGS((node_t *, int)); +EXTERN int node_get_fanin_index ARGS((node_t *, node_t *)); +/* extern int node_get_fanout_index(); */ + +EXTERN void node_scc ARGS((node_t *)); +EXTERN void node_d1merge ARGS((node_t *)); +EXTERN int node_substitute ARGS((node_t *, node_t *, int)); +EXTERN int node_collapse ARGS((node_t *, node_t *)); +EXTERN void node_algebraic_cofactor ARGS((node_t *,node_t *,node_t **,node_t **,node_t **)); +EXTERN int node_invert ARGS((node_t *)); +EXTERN node_function_t node_function ARGS((node_t *)); +EXTERN node_type_t node_type ARGS((node_t *)); +EXTERN input_phase_t node_input_phase ARGS((node_t *, node_t *)); + +EXTERN void node_print ARGS((FILE *, node_t *)); +EXTERN void node_print_negative ARGS((FILE *, node_t *)); +EXTERN void node_print_rhs ARGS((FILE *, node_t *)); + +EXTERN void node_lib_process ARGS((network_t *)); + +EXTERN void node_minimum_base ARGS((node_t *)); +EXTERN void node_replace_internal ARGS((node_t *, node_t **, int, struct set_family *)); +EXTERN int node_patch_fanin ARGS((node_t *, node_t *, node_t *)); +EXTERN int node_patch_fanin_index ARGS((node_t *, int, node_t *)); +EXTERN int node_compare_id ARGS((char **, char **)); + +EXTERN pset_family node_sf_adjust ARGS((node_t *, node_t **, int)); +EXTERN node_t **nodevec_dup ARGS((node_t **, int)); +EXTERN node_t *node_create ARGS((struct set_family *, node_t **, int)); +EXTERN void cautious_define_cube_size ARGS((int)); +EXTERN void define_cube_size ARGS((int)); +EXTERN void undefine_cube_size ARGS((void)); +EXTERN void node_assign_name ARGS((node_t *)); +EXTERN void node_assign_short_name ARGS((node_t *)); +EXTERN int node_is_madeup_name ARGS((char *, int *)); +EXTERN void fanin_remove_fanout ARGS((node_t *)); +EXTERN void fanin_add_fanout ARGS((node_t *)); + + /* exported for use in macros */ +EXTERN int node_error ARGS((int)); +EXTERN node_t *node_fanout_gen ARGS((lsList, int *)); +EXTERN lsGen node_fanout_init_gen ARGS((node_t *)); + +#endif diff --git a/sis/node/node_int.h b/sis/node/node_int.h new file mode 100644 index 0000000..5223276 --- /dev/null +++ b/sis/node/node_int.h @@ -0,0 +1,31 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/node_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +/* + * daemon's are in a linked list by daemon type + */ + +typedef struct daemon_struct daemon_t; +struct daemon_struct { + void (*func)(); + daemon_t *next; +}; + +#define node_has_function(f) (f->F != 0) + +extern void network_rehash_names(); +extern void node_complement(); +extern void node_invalid(); +extern void make_common_base_by_name(); +extern void make_common_base(); +extern void node_discard_all_daemons(); +extern void set_espresso_flags(); +extern node_t *node_sort_for_printing(); +extern int fancy_lex_order(); +extern void node_remove_dup_fanin(); diff --git a/sis/node/nodecheck.c b/sis/node/nodecheck.c new file mode 100644 index 0000000..6f09672 --- /dev/null +++ b/sis/node/nodecheck.c @@ -0,0 +1,124 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/nodecheck.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#include "sis.h" +#include "node_int.h" + + +static void +chk_err(s, node) +char *s; +node_t *node; +{ + error_append("node_check: inconsistency detected"); + if (node != 0) { + error_append(" at "); + error_append(node_name(node)); + } + error_append(" -- "); + error_append(s); + error_append("\n"); +} + + +int +node_check(node) +node_t *node; +{ + node_literal_t l; + pset support, last, last1, p, p1; + int i, j; + + if (node->type == INTERNAL) { + /* check for existence of a logic function */ + if (node->F == 0) { + chk_err("internal node does not have a logic function", node); + return 0; + } + + /* Check that the node is minimum base */ + if (node->nin > 0) { + support = sf_and(node->F); + for(i = node->nin-1; i >= 0; i--) { + if (GETINPUT(support, i) == TWO) { + chk_err("node is not minimum base", node); + return 0; + } + } + set_free(support); + } + + /* Check that the node is SCC-minimal */ + if (node->nin > 0) { + foreach_set(node->F, last, p) { + foreach_set(node->F, last1, p1) { + if (p != p1 && setp_implies(p, p1)) { + chk_err("node is not SCC-minimal", node); + return 0; + } + } + } + } + + /* Check for any bad literals in F */ + foreach_set(node->F, last, p) { + for(j = node->nin-1; j >= 0; j--) { + l = GETINPUT(p, j); + if (l != ONE && l != TWO && l != ZERO) { + chk_err("node cube has a bad literal", node); + return 0; + } + } + } + + /* Check for any bad literals in R */ + if (node->R != 0) { + foreach_set(node->R, last, p) { + for(j = node->nin-1; j >= 0; j--) { + l = GETINPUT(p, j); + if (l != ONE && l != TWO && l != ZERO) { + chk_err("node offset cube has a bad literal", node); + return 0; + } + } + } + } + + /* Check that F and R are disjoint and F+R=1 */ + if (node->R != 0) { + define_cube_size(node->nin); + foreach_set(node->F, last, p) { + foreach_set(node->R, last1, p1) { + if (cdist0(p, p1)) { + chk_err("node onset and offset are not disjoint", node); + return 0; + } + } + } + if (! tautology(cube2list(node->F, node->R))) { + chk_err("missing minterms from onset union offset", node); + return 0; + } + } + } + +#if 0 + /* Provide a warning if a node has duplicated fanin */ + for(i = 0; i < node->nin; i++) { + for(j = i+1; j < node->nin; j++) { + if (node->fanin[i] == node->fanin[j]) { + chk_err("node with duplicated fanin (warning only)", node); + return 2; + } + } + } +#endif + + return 1; +} diff --git a/sis/node/nodeindex.c b/sis/node/nodeindex.c new file mode 100644 index 0000000..0bd9735 --- /dev/null +++ b/sis/node/nodeindex.c @@ -0,0 +1,78 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/nodeindex.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#include "sis.h" + + +/* + * nodeindex functions -- association table of nodes <-> small ints + */ + + +nodeindex_t * +nodeindex_alloc() +{ + nodeindex_t *table; + + table = ALLOC(nodeindex_t, 1); + table->node_to_int = st_init_table(st_ptrcmp, st_ptrhash); + table->int_to_node = array_alloc(node_t *, 0); + return table; +} + + +void +nodeindex_free(table) +nodeindex_t *table; +{ + st_free_table(table->node_to_int); + array_free(table->int_to_node); + FREE(table); +} + + +nodeindex_insert(table, node) +nodeindex_t *table; +node_t *node; +{ + char *value; + int index; + + if (st_lookup(table->node_to_int, (char *) node, &value)) { + index = (int) value; + } else { + index = st_count(table->node_to_int); + (void) st_insert(table->node_to_int, (char *) node, (char *) index); + array_insert(node_t *, table->int_to_node, index, node); + } + return index; +} + + +nodeindex_indexof(table, node) +nodeindex_t *table; +node_t *node; +{ + char *value; + + if (st_lookup(table->node_to_int, (char *) node, &value)) { + return (int) value; + } else { + return -1; + } +} + + +node_t * +nodeindex_nodeof(table, index) +nodeindex_t *table; +int index; +{ + return array_fetch(node_t *, table->int_to_node, index); +} diff --git a/sis/node/nodeindex.doc b/sis/node/nodeindex.doc new file mode 100644 index 0000000..8c287e1 --- /dev/null +++ b/sis/node/nodeindex.doc @@ -0,0 +1,53 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/nodeindex.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +Description + Builds and maintains an association table to map nodes into small + integers and back. Guaranteed efficient. + +Summary: + nodeindex_alloc() + nodeindex_free(table) + nodeindex_insert(table, node) + nodeindex_indexof(table, node) + nodeindex_nodeof(table, index) + + + +nodeindex_t * +nodeindex_alloc() + Allocate a node to integer association table. + + +void +nodeindex_free(table) +nodeindex_t *table; + Free a node to integer association table. + + +nodeindex_insert(table, node) +nodeindex_t *table; +node_t *node; + If 'node' is not already in the table, give it the next available + index, and add it to the table. Do nothing if 'node' is already + in the table. Returns the index of node. Should be renamed + 'nodeindex_find_or_add' in analogy to st. + + +nodeindex_indexof(table, node) +nodeindex_t *table; +node_t *node; + Given a node, return its index. + + +node_t * +nodeindex_nodeof(table, index) +nodeindex_t *table; +int index; + Given the index of a node, return the node. diff --git a/sis/node/nodeindex.h b/sis/node/nodeindex.h new file mode 100644 index 0000000..25191e6 --- /dev/null +++ b/sis/node/nodeindex.h @@ -0,0 +1,32 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/nodeindex.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#ifndef NODEINDEX_H +#define NODEINDEX_H + + +/* + * a quick way to associate cubes (i.e., sm_row *) to small integers + * and back. Used to build the kernel_cube matrix + */ + +typedef struct nodeindex_struct nodeindex_t; +struct nodeindex_struct { + st_table *node_to_int; + array_t *int_to_node; +}; + + +EXTERN struct nodeindex_struct *nodeindex_alloc ARGS((void)); +EXTERN void nodeindex_free ARGS((struct nodeindex_struct *)); +EXTERN int nodeindex_insert ARGS((struct nodeindex_struct *, node_t *)); +EXTERN int nodeindex_indexof ARGS((struct nodeindex_struct *, node_t *)); +EXTERN node_t *nodeindex_nodeof ARGS((struct nodeindex_struct *, int)); + +#endif diff --git a/sis/node/nodemisc.c b/sis/node/nodemisc.c new file mode 100644 index 0000000..50d6d9c --- /dev/null +++ b/sis/node/nodemisc.c @@ -0,0 +1,509 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/nodemisc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#include "sis.h" +#include "node_int.h" + +static int merge_fanin_list(); +/* static pset_family node_sf_adjust(); -- net2pla.c needs this ... */ +static pset_family node_sf_adjust_by_name(); +static pset_family do_sf_permute(); +static int has_dup_fanin(); + + +int +node_compare_id(p1, p2) +char **p1, **p2; +{ + node_t *q1 = *(node_t **) p1, *q2 = *(node_t **) p2; + + return q1->sis_id - q2->sis_id; +} + + +static int +compare_node_by_name(p1, p2) +char **p1, **p2; +{ + node_t *q1 = *(node_t **) p1, *q2 = *(node_t **) p2; + + if (q1->name == 0) node_assign_name(q1); /* hack */ + if (q2->name == 0) node_assign_name(q2); /* hack */ + return strcmp(q1->name, q2->name); +} + +/* + * take two nodes, and express them over a common base + * - works even if either node has 'duplicate' fanin + */ + +void +make_common_base(f, g, new_fanin, new_nin, newf, newg) +node_t *f, *g; +node_t ***new_fanin; +int *new_nin; +pset_family *newf, *newg; +{ + node_t *func_list[2]; + + func_list[0] = f; + func_list[1] = g; + *new_nin = merge_fanin_list(func_list, 2, new_fanin, node_compare_id); + + *newf = node_sf_adjust(f, *new_fanin, *new_nin); + *newg = node_sf_adjust(g, *new_fanin, *new_nin); +} + +/* + * merge the fanin list from multiple nodes into a single, uniq list + */ + +static int +merge_fanin_list(func_list, nfunc, new_list, compare) +node_t **func_list; +int nfunc; +node_t ***new_list; +int (*compare)(); +{ + register int nlist, i, j, count; + register node_t **list, *func; + + count = 0; + for(i = 0; i < nfunc; i++) { + count += func_list[i]->nin; + } + + list = ALLOC(node_t *, count); + nlist = 0; + for(i = nfunc-1; i >= 0; i--) { + func = func_list[i]; + for(j = func->nin-1; j >= 0; j--) { + list[nlist++] = func->fanin[j]; + } + } + + if (nlist >= 2) { + /* Sort the elements */ + qsort((char *) list, nlist, sizeof(node_t *), compare); + + /* Make the list unique */ + count = 1; + for(i = 1; i < nlist; i++) { + if ((*compare)((char **) &(list[i-1]), (char **) &(list[i])) != 0) { + list[count++] = list[i]; + } + } + nlist = count; + } + + *new_list = list; + return nlist; +} + +/* + * adjust a node to place it over a different base + * - watch carefully for duplicated fanin in the node + */ + +pset_family +node_sf_adjust(node, new_fanin, new_nin) +node_t *node; +register node_t **new_fanin; +int new_nin; +{ + register int i, j, *permute; + register node_t **old_fanin; + int has_dup, old_nin; + pset_family new_sf; + + if (node->is_dup_free) { + has_dup = 0; + } else { + has_dup = has_dup_fanin(node); + node->is_dup_free = ! has_dup; + } + old_nin = node->nin; + old_fanin = node->fanin; + + /* check for 0, or 1 function to be returned ... */ + if (new_nin == 0) { + assert(! has_dup); /* does not make sense */ + new_sf = sf_new(1, 0); + new_sf->count = (node->F->count > 0); + return new_sf; + } + + /* check for identity permutation */ + if (old_nin == new_nin) { + for(i = new_nin-1; i >= 0; i--) { + if (old_fanin[i] != new_fanin[i]) { + break; + } + } + if (i < 0) { + return sf_save(node->F); + } + } + + /* setup permute(old column index) = new column index (or -1) */ + permute = ALLOC(int, old_nin); + for(i = old_nin-1; i >= 0; i--) { + permute[i] = -1; + for(j = new_nin-1; j >= 0; j--) { + if (old_fanin[i] == new_fanin[j]) { + permute[i] = j; + break; + } + } + } + + new_sf = do_sf_permute(node->F, permute, new_nin, has_dup); + FREE(permute); + return new_sf; +} + +static pset_family +do_sf_permute(old_sf, permute, new_nin, has_dup) +pset_family old_sf; +int *permute; +int new_nin; +int has_dup; +{ + pset_family new_sf; + register pset last, p, pdest; + register int i, new_col, t; + int old_nin; + + if (has_dup) { + /* make sure that cdist0 and cube.fullset are defined ! */ + define_cube_size(new_nin); + } + + new_sf = sf_new(old_sf->count, new_nin * 2); + old_nin = old_sf->sf_size / 2; + foreach_set(old_sf, last, p) { + pdest = GETSET(new_sf, new_sf->count++); + (void) set_fill(pdest, new_nin * 2); + + for(i = old_nin-1; i >= 0; i--) { + new_col = permute[i]; + if (new_col != -1) { + switch(GETINPUT(p, i)) { + case ZERO: + t = 2*new_col + 1; + set_remove(pdest, t); + break; + case ONE: + t = 2*new_col; + set_remove(pdest, t); + break; + case TWO: + break; + default: + fail("do_sf_permute: improper set encountered\n"); + } + } + } + + /* don't save the set if it has a 00 coordinate */ + if (has_dup && ! cdist0(pdest, cube.fullset)) { + new_sf->count--; + } + } + return new_sf; +} + +/* + * put 'node' over a minimum base + * - removes duplicated fanin if present + */ + +void +node_minimum_base(node) +node_t *node; +{ + pset floor; + pcover F1; + node_t **new_fanin; + int var, new_nin; + + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) { + return; + } + if (node->F == 0) { + fail("node_minimum_base: node does not have a function"); + } + + /* make sure that no fanin is duplicated */ + if (! node->is_dup_free) { + node_remove_dup_fanin(node); + } + + /* bail out for 0, 1 functions ... */ + if (node->nin == 0) { + node->F->count = (node->F->count > 0); /* make it 0 or 1 */ + return; + } + + /* make sure it is scc-minimal */ + if (! node->is_scc_minimal) { + node->F = sf_contain(node->F); + } + + /* AND together all of the cubes; should form 00 for most positions */ + floor = sf_and(node->F); + + /* see if there are variables we don't depend on */ + for(var = 0; var < node->nin; var++) { + if (GETINPUT(floor, var) == TWO) { + break; + } + } + + if (var != node->nin) { + /* create new fanin list (with minimum number of variables) */ + new_fanin = ALLOC(node_t *, node->nin); + new_nin = 0; + for(var = 0; var < node->nin; var++) { + if (GETINPUT(floor, var) != TWO) { + new_fanin[new_nin++] = node->fanin[var]; + } + } + + F1 = node_sf_adjust(node, new_fanin, new_nin); + node_replace_internal(node, new_fanin, new_nin, F1); + } + set_free(floor); + node->is_dup_free = 1; + node->is_scc_minimal = 1; +} + +/* intended for internal use only ... */ +node_t * +node_create(func, fanin, nin) +pset_family func; +node_t **fanin; +int nin; +{ + node_t *node; + + node = node_alloc(); + node->nin = nin; + node->fanin = fanin; + node->F = func; + return node; +} + + +/* intended for internal use only ... */ +void +node_replace_internal(f, fanin, nin, F) +node_t *f; +node_t **fanin; +int nin; +pset_family F; +{ + /* hack -- allow assignment of a logic function to a PI */ + if (f->type == PRIMARY_INPUT) { + if (f->network != 0) { + network_change_node_type(f->network, f, INTERNAL); + } else { + f->type = UNASSIGNED; /* not in network !?! */ + } + } + + /* patch fanout lists if 'f' is in a network */ + if (f->network != 0) { + fanin_remove_fanout(f); + } + + /* replace the values at the node */ + if (f->fanin != NIL(node_t *)) FREE(f->fanin); + if (f->F != NIL(set_family_t)) sf_free(f->F); + f->nin = nin; + f->fanin = fanin; + f->F = F; + + /* patch fanout list for new fanin list if 'f' is in a network */ + if (f->network != 0) { + fanin_add_fanout(f); + } + + node_invalid(f); + f->fanin_changed = 1; +} + + +void +node_replace(f, r) +node_t *f, *r; +{ + if (r->F == 0) { + fail("node_replace: node does not have a function"); + } + + node_replace_internal(f, r->fanin, r->nin, r->F); + f->is_dup_free = r->is_dup_free; + f->is_scc_minimal = r->is_scc_minimal; + + r->F = 0; + r->fanin = 0; + r->nin = 0; + node_free(r); +} + +int +node_base_contain(f, g) +node_t *f, *g; +{ + register int i, j; + register node_t **listf, **listg; + + if (f->nin < g->nin) { + return 0; /* base of g CANNOT contain base of f */ + } + + /* could avoid sort if already known to be sorted ... */ + + listf = nodevec_dup(f->fanin, f->nin); + qsort((char *) listf, f->nin, sizeof(node_t *), (int (*)()) node_compare_id); + + listg = nodevec_dup(g->fanin, g->nin); + qsort((char *) listg, g->nin, sizeof(node_t *), (int (*)()) node_compare_id); + + /* see if each element of g has a mate in f */ + j = f->nin - 1; + for(i = g->nin - 1; i >= 0; i--) { + while (j >= 0 && listf[j]->sis_id > listg[i]->sis_id) { + j--; + } + if (j < 0 || listf[j]->sis_id < listg[i]->sis_id) { + FREE(listf); + FREE(listg); + return 0; /* no mate for listg[i] */ + } + j--; + } + + FREE(listf); + FREE(listg); + return 1; +} + +static int +has_dup_fanin(node) +node_t *node; +{ + int new_nin; + node_t *func_list[1], **list; + + func_list[0] = node; + new_nin = merge_fanin_list(func_list, 1, &list, node_compare_id); + FREE(list); + + return new_nin != node->nin; +} + + +void +node_remove_dup_fanin(node) +node_t *node; +{ + int new_nin; + node_t *func_list[1], **list; + pset_family newf; + + func_list[0] = node; + new_nin = merge_fanin_list(func_list, 1, &list, node_compare_id); + + /* if some input was duplicated, re-adjust the set family */ + if (new_nin != node->nin) { + newf = node_sf_adjust(node, list, new_nin); + node_replace_internal(node, list, new_nin, newf); + } else { + FREE(list); + } + node->is_dup_free = 1; +} + +/* + * adjust a node to place it over a different base + * - watch carefully for duplicated fanin in the node + */ + +static pset_family +node_sf_adjust_by_name(node, new_fanin, new_nin) +node_t *node; +register node_t **new_fanin; +int new_nin; +{ + register int i, j, *permute; + register node_t **old_fanin; + int has_dup, old_nin; + pset_family new_sf; + char *p1, *p2; + + if (node->is_dup_free) { + has_dup = 0; + } else { + has_dup = has_dup_fanin(node); + node->is_dup_free = ! has_dup; + } + old_nin = node->nin; + old_fanin = node->fanin; + + /* check for identity permutation */ + if (old_nin == new_nin) { + for(i = new_nin-1; i >= 0; i--) { + p1 = (char *) old_fanin[i]; + p2 = (char *) new_fanin[i]; + if (compare_node_by_name(&p1, &p2) != 0) { + break; + } + } + if (i < 0) { + return sf_save(node->F); + } + } + + /* setup permute(old column index) = new column index (or -1) */ + permute = ALLOC(int, old_nin); + for(i = old_nin-1; i >= 0; i--) { + permute[i] = -1; + for(j = new_nin-1; j >= 0; j--) { + p1 = (char *) old_fanin[i]; + p2 = (char *) new_fanin[j]; + if (compare_node_by_name(&p1, &p2) == 0) { + permute[i] = j; + break; + } + } + } + + new_sf = do_sf_permute(node->F, permute, new_nin, has_dup); + FREE(permute); + return new_sf; +} + +void +make_common_base_by_name(f, g, new_fanin, new_nin, newf, newg) +node_t *f, *g; +node_t ***new_fanin; +int *new_nin; +pset_family *newf, *newg; +{ + node_t *func_list[2]; + + func_list[0] = f; + func_list[1] = g; + *new_nin = merge_fanin_list(func_list, 2, new_fanin, compare_node_by_name); + + *newf = node_sf_adjust_by_name(f, *new_fanin, *new_nin); + *newg = node_sf_adjust_by_name(g, *new_fanin, *new_nin); +} diff --git a/sis/node/nodeutil.c b/sis/node/nodeutil.c new file mode 100644 index 0000000..4e8cfc0 --- /dev/null +++ b/sis/node/nodeutil.c @@ -0,0 +1,233 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/nodeutil.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#include "sis.h" +#include "node_int.h" + +static daemon_t *daemon_func[4]; +static global_sis_id = 0; + + +node_t * +node_alloc() +{ + register node_t *node; + register daemon_t *d; + + node = ALLOC(node_t, 1); + + node->name = NIL(char); + node->short_name = NIL(char); + node->type = UNASSIGNED; + node->sis_id = global_sis_id++; + + node->fanin_changed = 0; + node->fanout_changed = 0; + node->is_dup_free = 0; + node->is_min_base = 0; + node->is_scc_minimal = 0; + + node->nin = 0; + node->fanin = NIL(node_t *); + + node->fanout = lsCreate(); + node->fanin_fanout = 0; + + node->F = NIL(set_family_t); + node->D = NIL(set_family_t); + node->R = NIL(set_family_t); + + node->copy = NIL(node_t); + + node->network = NIL(network_t); + node->net_handle = 0; + + node->simulation = 0; + node->factored = 0; + node->delay = 0; + node->map = 0; + node->buf = 0; + node->pld = 0; + node->ite = 0; + node->bin = 0; + node->cspf = 0; + node->atpg = 0; + node->undef1 = 0; + + for(d = daemon_func[(int) DAEMON_ALLOC]; d != 0; d = d->next) { + (*d->func)(node); + } + + return node; +} + +void +node_free(node) +node_t *node; +{ + daemon_t *d; + + if (node == 0) return; + + FREE(node->name); + FREE(node->short_name); + + FREE(node->fanin); + + LS_ASSERT(lsDestroy(node->fanout, free)); + FREE(node->fanin_fanout); + + if (node->F != 0) sf_free(node->F); + if (node->D != 0) sf_free(node->D); + if (node->R != 0) sf_free(node->R); + + for(d = daemon_func[(int) DAEMON_FREE]; d != 0; d = d->next) { + (*d->func)(node); + } + + FREE(node); +} + +node_t * +node_dup(old) +register node_t *old; +{ + register node_t *new; + register daemon_t *d; + + if (old == 0) return 0; + + new = node_alloc(); + + if (old->name != 0) { + new->name = util_strsav(old->name); + } + if (old->short_name != 0) { + new->short_name = util_strsav(old->short_name); + } + + new->type = old->type; + + new->fanin_changed = old->fanin_changed; + new->fanout_changed = old->fanout_changed; + new->is_dup_free = old->is_dup_free; + new->is_min_base = old->is_min_base; + new->is_scc_minimal = old->is_scc_minimal; + + new->nin = old->nin; + if (old->nin != 0) { + new->fanin = nodevec_dup(old->fanin, old->nin); + } + + /* do NOT copy old->fanout ... */ + /* do NOT copy old->fanin_fanout ... */ + + if (old->F != 0) new->F = sf_save(old->F); + if (old->D != 0) new->D = sf_save(old->D); + if (old->R != 0) new->R = sf_save(old->R); + + new->copy = 0; /* ### for saber */ + + /* do NOT copy old->network ... */ + /* do NOT copy old->net_handle ... */ + + for(d = daemon_func[(int) DAEMON_DUP]; d != 0; d = d->next) { + (*d->func)(old, new); + } + return new; +} + +node_t ** +nodevec_dup(fanin, nin) +register node_t **fanin; +int nin; +{ + register int i; + register node_t **new_fanin; + + new_fanin = ALLOC(node_t *, nin); + for(i = nin-1; i >= 0; i--) { + new_fanin[i] = fanin[i]; + } + return new_fanin; +} + + +void +node_invalid(node) +register node_t *node; +{ + register daemon_t *d; + + if (node->D != 0) { + sf_free(node->D); + node->D = 0; + } + if (node->R != 0) { + sf_free(node->R); + node->R = 0; + } + + for(d = daemon_func[(int) DAEMON_INVALID]; d != 0; d = d->next) { + (*d->func)(node); + } + node->is_dup_free = 0; + node->is_min_base = 0; + node->is_scc_minimal = 0; + /* fanin_changed, fanout_changed are updated by fan.c */ +} + + +void +node_register_daemon(type, func) +node_daemon_type_t type; +void (*func)(); +{ + daemon_t *daemon; + + switch (type) { + case DAEMON_ALLOC: + case DAEMON_FREE: + case DAEMON_INVALID: + case DAEMON_DUP: + daemon = ALLOC(daemon_t, 1); + daemon->func = func; + daemon->next = daemon_func[(int) type]; + daemon_func[(int) type] = daemon; + break; + + default: + fail("node_register_daemon: bad daemon type"); + } +} + + +void +node_discard_all_daemons() +{ + node_daemon_type_t type; + daemon_t *d, *dnext; + + for(type = DAEMON_ALLOC; (int) type <= (int) DAEMON_DUP; + type = (node_daemon_type_t) ((int) type + 1)) { + /* ANSI would allow the much simpler type++ */ + for(d = daemon_func[(int) type]; d != 0; d = dnext) { + dnext = d->next; + FREE(d); + } + daemon_func[(int) type] = 0; + } +} + +network_t * +node_network(node) +node_t *node; +{ + return node->network; +} diff --git a/sis/node/print.c b/sis/node/print.c new file mode 100644 index 0000000..d7c282b --- /dev/null +++ b/sis/node/print.c @@ -0,0 +1,171 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/print.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#include "sis.h" +#include "node_int.h" + + +static void node_print_internal(); +static int simple_print(); + + +void +node_print(fp, node) +FILE *fp; +node_t *node; +{ + node_t *node1; + + if (node->type == PRIMARY_INPUT) { + return; + } else if (node->type == PRIMARY_OUTPUT && + node->fanin[0]->type != PRIMARY_INPUT) { + return; + } + + node1 = node_sort_for_printing(node); + (void) fprintf(fp, " %s = ", node_name(node)); + node_print_internal(fp, node1, 1); + (void) fputc('\n', fp); + node_free(node1); +} + + +void +node_print_negative(fp, node) +FILE *fp; +node_t *node; +{ + node_t *node1, *node2; + node_type_t type; + + type = node->type; + if (type == PRIMARY_INPUT) { + return; + } + if (type == PRIMARY_OUTPUT && node->fanin[0]->type != PRIMARY_INPUT) { + return; + } + + node2 = (type == PRIMARY_OUTPUT) ? node : node_not(node); + node1 = node_sort_for_printing(node2); + (void) fprintf(fp, " %s = ", node_name(node)); + node_print_internal(fp, node1, 0); + (void) fputc('\n', fp); + node_free(node1); + if (type != PRIMARY_OUTPUT) { + node_free(node2); + } +} + + +void +node_print_rhs(fp, node) +FILE *fp; +node_t *node; +{ + node_t *node1; + + node1 = node_sort_for_printing(node); + node_print_internal(fp, node1, 1); + node_free(node1); +} + + + +static void +node_print_internal(fp, node, phase) +FILE *fp; +node_t *node; +int phase; +{ + int var, x, first_literal, first_pterm; + pset last, p; + node_t *fanin; + + if (simple_print(fp, node, phase)) return; + + if (! phase) { + (void) fputc('(', fp); + } + + first_pterm = 1; + foreach_set(node->F, last, p) { + if (! first_pterm) { + (void) fputs(" + ", fp); + } + first_pterm = 0; + + first_literal = 1; + foreach_fanin(node, var, fanin) { + switch(x = GETINPUT(p, var)) { + case ZERO: + case ONE: + if (! first_literal) { + (void) fputc(' ', fp); + } + first_literal = 0; + (void) fputs(node_name(fanin), fp); + if (x == ZERO) (void) fputc('\'', fp); + break; + + case TWO: + break; + + default: + fail("node_print: corrupt function"); + } + } + } + if (! phase) { + (void) fputs(")'", fp); + } +} + + +static int +simple_print(fp, node, phase) +FILE *fp; +node_t *node; +int phase; +{ + if (node->type == PRIMARY_INPUT) { + return 1; + + } else if (node->type == PRIMARY_OUTPUT) { + if (node->fanin[0]->type == PRIMARY_INPUT) { + (void) fprintf(fp, "%s", node_name(node->fanin[0])); + } + return 1; + + } else { + switch(node_function(node)) { + case NODE_0: + (void) fprintf(fp, "-%s-", phase ? "0" : "1"); + return 1; + + case NODE_1: + (void) fprintf(fp, "-%s-", phase ? "1" : "0"); + return 1; + + case NODE_BUF: + (void) fprintf(fp, "%s%s", + node_name(node->fanin[0]), phase ? "" : "'"); + return 1; + + case NODE_INV: + (void) fprintf(fp, "%s%s", + node_name(node->fanin[0]), phase ? "'" : ""); + return 1; + + default: + return 0; + } + } +} diff --git a/sis/node/sethack.c b/sis/node/sethack.c new file mode 100644 index 0000000..1b8155f --- /dev/null +++ b/sis/node/sethack.c @@ -0,0 +1,63 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/sethack.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#include "sis.h" + +static unsigned byte_reverse[256] = { + 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, + 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, + 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, +12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, + 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, +10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, + 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, +14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, + 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, + 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, + 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, +13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, + 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, +11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, + 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, +15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 +}; + + +/* bit_reverse -- bitwise reverse the elements of a 32-bit integer */ +static unsigned +bit_reverse(val) +register unsigned val; +{ + return + (byte_reverse[val & 0xFF] << 24) | + (byte_reverse[(val >> 8) & 0xFF] << 16) | + (byte_reverse[(val >> 16) & 0xFF] << 8) | + (byte_reverse[val >> 24]); +} + + +int +fancy_lex_order(a, b) +pset *a, *b; +{ + register int i; + register pset a1 = *a, b1 = *b; + register unsigned temp1, temp2; + + for(i = 1; i <= LOOP(a1); i++) { + temp1 = bit_reverse(~ a1[i]); + temp2 = bit_reverse(~ b1[i]); + if (temp1 > temp2) { + return -1; + } else if (temp1 < temp2) { + return 1; + } + } + return 0; +} diff --git a/sis/node/substitute.c b/sis/node/substitute.c new file mode 100644 index 0000000..4d1f5d3 --- /dev/null +++ b/sis/node/substitute.c @@ -0,0 +1,99 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/node/substitute.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#include "sis.h" +#include "node_int.h" + + +static int divide_one_phase(); + +int +node_substitute(f, g, use_complement) +node_t *f, *g; +int use_complement; +{ + int changed; + node_t *r, *r1; + + if (f->type == PRIMARY_INPUT || g->type == PRIMARY_INPUT) { + return 0; + } + if (f->type == PRIMARY_OUTPUT || g->type == PRIMARY_OUTPUT) { + return 0; + } + if (f == g) { + return 0; + } + if (! node_has_function(f) || ! node_has_function(g)) { + fail("node_substitute: node does not have a function"); + } + + /* check that support of f contains support of g */ + if (! node_base_contain(f, g)) { + return 0; + } + + changed = 0; + + if (divide_one_phase(f, g, &r, 1)) { + changed = 1; + } + if (use_complement) { + if (divide_one_phase(r, g, &r1, 0)) { + changed = 1; + } + node_free(r); + r = r1; + } + + if (changed) { + node_replace(f, r); + } else { + node_free(r); + } + return changed; +} + + +static int +divide_one_phase(f, g, out, phase) +node_t *f, *g; +node_t **out; +int phase; +{ + int changed; + node_t *q, *divisor, *lit, *t0, *t1, *r; + + changed = 0; + + if (phase == 0) { + divisor = node_not(g); + q = node_div(f, divisor, &r); + node_free(divisor); + } else { + q = node_div(f, g, &r); + } + + /* set t1 = (F / G) * g + R */ + if (node_function(q) != NODE_0) { + changed = 1; + lit = node_literal(g, phase); + t0 = node_and(q, lit); + t1 = node_or(t0, r); + node_free(lit); + node_free(t0); + node_free(r); + } else { + t1 = r; + } + node_free(q); + + *out = t1; + return changed; +} diff --git a/sis/ntbdd/Makefile.am b/sis/ntbdd/Makefile.am new file mode 100644 index 0000000..c9688b9 --- /dev/null +++ b/sis/ntbdd/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libntbdd.a +libntbdd_a_SOURCES = bdd_at_node.c bdd_to_ntwk.c com_ntbdd.c manager.c \ + node_to_bdd.c verify_ntwk.c ntbdd_int.h +pkginclude_HEADERS = ntbdd.h +dist_doc_DATA = ntbdd.doc diff --git a/sis/ntbdd/Makefile.in b/sis/ntbdd/Makefile.in new file mode 100644 index 0000000..a2aaf65 --- /dev/null +++ b/sis/ntbdd/Makefile.in @@ -0,0 +1,422 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libntbdd_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/ntbdd +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libntbdd_a_AR = $(AR) $(ARFLAGS) +libntbdd_a_LIBADD = +am_libntbdd_a_OBJECTS = bdd_at_node.$(OBJEXT) bdd_to_ntwk.$(OBJEXT) \ + com_ntbdd.$(OBJEXT) manager.$(OBJEXT) node_to_bdd.$(OBJEXT) \ + verify_ntwk.$(OBJEXT) +libntbdd_a_OBJECTS = $(am_libntbdd_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libntbdd_a_SOURCES) +DIST_SOURCES = $(libntbdd_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libntbdd.a +libntbdd_a_SOURCES = bdd_at_node.c bdd_to_ntwk.c com_ntbdd.c manager.c \ + node_to_bdd.c verify_ntwk.c ntbdd_int.h + +pkginclude_HEADERS = ntbdd.h +dist_doc_DATA = ntbdd.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/ntbdd/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/ntbdd/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libntbdd.a: $(libntbdd_a_OBJECTS) $(libntbdd_a_DEPENDENCIES) + -rm -f libntbdd.a + $(libntbdd_a_AR) libntbdd.a $(libntbdd_a_OBJECTS) $(libntbdd_a_LIBADD) + $(RANLIB) libntbdd.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/ntbdd/bdd_at_node.c b/sis/ntbdd/bdd_at_node.c new file mode 100644 index 0000000..1d43126 --- /dev/null +++ b/sis/ntbdd/bdd_at_node.c @@ -0,0 +1,159 @@ +#include "sis.h" +#include "ntbdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/ntbdd/bdd_at_node.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:27 $ + * $Log: bdd_at_node.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:27 pchong + * imported + * + * Revision 1.6 1993/06/22 17:27:45 sis + * In function ntbdd_set_at_node, added check for NIL bdd_t + * before calling bdd_free. + * + * Revision 1.6 1993/06/07 22:04:17 shiple + * In function ntbdd_set_at_node, added check for NIL bdd_t before calling bdd_free. + * + * Revision 1.5 1993/06/04 15:39:16 shiple + * Removed unnecessary void casts of functions calls. Made changes to adhere to exported BDD interface. + * + * Revision 1.4 1991/11/20 18:25:22 shiple + * Added check for NIL node in bdd_at_node. + * + * Revision 1.3 91/03/31 22:56:47 shiple + * small revisions form Version 3.0 + * + * Revision 1.2 91/03/28 16:01:40 shiple + * explicitly include bdd_int.h + * + * Revision 1.1 91/03/20 14:21:28 shiple + * Initial revision + * + */ + +/* + * This file contains the routines to handle bdd_t * stored at network nodes, + * There is a field (char *) on each node for that to store the bdd_t *'s. + * Standard sis practice is to define a macro to access this field + * that does the type cast. + * + * Also standard sis practice is to have node demon that are automatically + * called whenever a node is created or freed. + */ + +void bdd_alloc_demon(node) +node_t *node; +{ + BDD_SET(node, NIL(bdd_t)); +} + +void bdd_free_demon(node) +node_t *node; +{ + bdd_t *fn; + + fn = ntbdd_at_node(node); + if (fn == NIL(bdd_t)) { + return; + } + + bdd_free(fn); + BDD_SET(node, NIL(bdd_t)); +} + + +/* + * A pair of routines to set and access the BDD field. + * WATCHOUT: the resulting bdd_node may be NIL(bdd_node). + */ + +bdd_t *ntbdd_at_node(node) +node_t *node; +{ + if (node == NIL(node_t)) { + fail ("ntbdd_at_node: NIL node"); + } else { + return BDD(node); + } +} + +/* + * Have to record all the networks where BDD nodes + * of the current manager have been stored. + * The invariant we guarantee is that the BDD(node) + * of a node of any network is put to NIL whenever + * the corresponding BDD manager is deallocated. + * The last_network business is just a 1 slot LRU cache + * for the network_table to avoid too many hash table accesses. + */ +void ntbdd_set_at_node(node, new_fn) +node_t *node; +bdd_t *new_fn; /* may be NIL */ +{ + network_t *network; + bdd_manager *manager; + bdd_t *old_fn; + bdd_external_hooks *hooks; + ntbdd_t *ntbdd_data; + + old_fn = ntbdd_at_node(node); + + /* + * If the fn has already been set at node, just return. Otherwise, free the + * existing BDD (could be NIL) and set the new one. + */ + if (old_fn == new_fn) { + return; + } + + if (old_fn != NIL(bdd_t)) { + bdd_free(old_fn); + } + + BDD_SET(node, new_fn); + + /* + * Get the network of node. If the node does not have a network, return. + */ + network = node_network(node); + if (network == NIL(network_t)) return; + + /* + * Get the ntbdd_data for the manager of the new BDD. If the network was the last + * inserted into the hooks network table, then we don't need to do anything. + * Otherwise, we insert the network into the hooks network table. + */ + manager = bdd_get_manager(new_fn); + hooks = bdd_get_external_hooks(manager); + ntbdd_data = (ntbdd_t *) hooks->network; + + if (ntbdd_data->last_network == network) return; + ntbdd_data->last_network = network; + st_insert(ntbdd_data->network_table, (char *) network, NIL(char)); +} + +/* + * ntbdd_free_at_node - free the bdd associated with this node + * This is the only function that should be called to free + * a bdd which is assigned to a node. Do not call bdd_free + * on such nodes (or make sure that BDD(node) is set to 0). + */ +void ntbdd_free_at_node(node) +node_t *node; +{ + bdd_t *fn; + + fn = ntbdd_at_node(node); + if (fn == NIL(bdd_t)) { + return; + } + bdd_free(fn); + BDD_SET(node, NIL(bdd_t)); +} + + diff --git a/sis/ntbdd/bdd_to_ntwk.c b/sis/ntbdd/bdd_to_ntwk.c new file mode 100644 index 0000000..aeb29a0 --- /dev/null +++ b/sis/ntbdd/bdd_to_ntwk.c @@ -0,0 +1,320 @@ +#include "sis.h" +#include "ntbdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/ntbdd/bdd_to_ntwk.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:27 $ + * $Log: bdd_to_ntwk.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:27 pchong + * imported + * + * Revision 1.8 1993/07/07 16:05:42 shiple + * Added some bdd_frees to ntbdd_bdd_single_to_network. + * + * Revision 1.7 1993/06/04 15:40:19 shiple + * Removed unnecessary void casts of functions calls. Made changes to adhere to exported BDD interface. + * + * Revision 1.6 1993/06/03 15:29:47 shiple + * Changed strsav to util_strsav. + * + * Revision 1.5 1993/01/14 01:30:50 shiple + * Added functions ntbdd_bdd_single_to_network and ntbdd_bdd_array_to_network. Removed + * function ntbdd_bdd_to_network. + * + * Revision 1.4 1992/02/12 21:41:02 shiple + * Modified bdd_do_build_rec to free the pi_literal[i]'s + * allocated with call to node_literal. + * + * Revision 1.3 1991/03/31 23:00:07 shiple + * removed bdd_print_from_leaves and bdd_print_as_eqn; changed name of + * bdd_build to ntbdd_bdd_to_network; rewrote some code to observe BDD + * interface; for Version 3.0 + * + * Revision 1.2 91/03/28 16:02:49 shiple + * explicitly include bdd_int.h + * + * Revision 1.1 91/03/20 14:23:57 shiple + * Initial revision + * + */ + +static void bdd_do_build(); +static node_t *bdd_do_build_rec(); + +/* + * Builds a multi-output network from an array of BDDs. po_names gives the correspondance + * between output function names and BDD functions. var_names gives the correspondance + * between input variable names and variable ids. + */ +network_t *ntbdd_bdd_array_to_network(fn_array, po_names, var_names) +array_t *fn_array; +array_t *po_names; +array_t *var_names; +{ + network_t *network; + bdd_t *fn; + st_table *pi_table; + st_table *bdd_to_node_table; /* acts as a visited table */ + int i; + char *po_name; + + /* + * The number of functions and output names must match. + */ + assert(array_n(fn_array) == array_n(po_names)); + + /* + * Allocate the necessary structures. + */ + network = network_alloc(); + pi_table = st_init_table(st_ptrcmp, st_ptrhash); + bdd_to_node_table = st_init_table(st_ptrcmp, st_ptrhash); + + /* + * For each BDD function, construct the necessary logic. Note that nodes will be shared. + */ + for (i = 0; i < array_n(fn_array); i++) { + fn = array_fetch(bdd_t *, fn_array, i); + if (fn == NIL(bdd_t)) { + continue; + } + po_name = array_fetch(char *, po_names, i); + bdd_do_build(network, fn, po_name, var_names, pi_table, bdd_to_node_table); + } + + /* + * Free the arrays, do a network check, and return. + */ + st_free_table(pi_table); + st_free_table(bdd_to_node_table); + assert(network_check(network)); + return network; +} + +/* + * Convenient interface to ntbdd_bdd_array_to_network. + */ +network_t *ntbdd_bdd_single_to_network(fn, po_name, var_names) +bdd_t *fn; +char *po_name; +array_t *var_names; +{ + network_t *network; + array_t *fn_array; + array_t *po_names; + + /* + * Create the necessary one element arrays for call to ntbdd_bdd_array_to_network. + */ + fn_array = array_alloc(bdd_t *, 1); + array_insert(bdd_t *, fn_array, 0, fn); + po_names = array_alloc(char *, 1); + array_insert(char *, po_names, 0, po_name); + + /* + * Create network. + */ + network = ntbdd_bdd_array_to_network(fn_array, po_names, var_names); + + /* + * Free the arrays, and return the network. + */ + array_free(fn_array); + array_free(po_names); + return network; +} + + + /* INTERNAL INTERFACE */ + +static void bdd_do_build(network, fn, po_name, var_names, pi_table, bdd_to_node_table) +network_t *network; +bdd_t *fn; +char *po_name; +array_t *var_names; +st_table *pi_table; +st_table *bdd_to_node_table; +{ + int phase; + node_t *node, *po; + boolean status_0, status_1; + + + status_0 = bdd_is_tautology(fn, 0); + status_1 = bdd_is_tautology(fn, 1); + + /* + * Handle constants specially. + */ + if (status_0 || status_1) { + phase = (status_1) ? 1 : 0; + node = node_constant(phase); + } else { + node = bdd_do_build_rec(network, fn, pi_table, var_names, bdd_to_node_table); + } + network_add_node(network, node); + po = network_add_primary_output(network, node); + network_change_node_name(network, po, util_strsav(po_name)); +} + +static node_t *bdd_do_build_rec(network, fn, pi_table, var_names, bdd_to_node_table) +network_t *network; +bdd_t *fn; +st_table *pi_table; +array_t *var_names; +st_table *bdd_to_node_table; +{ + int i, active; + bdd_variableId top_var_id; + bdd_node *node_regular; + bdd_t *fn_regular; + bdd_t *sub_fn[2]; + int is_constant[2]; + int phase[2]; + node_t *node, *pi, *and_node[2], *input_node[2]; + node_t *pi_literal[2]; + boolean status_0, status_1; + boolean is_complemented; + + + /* + * The fn should not be zero or one. + */ + status_0 = bdd_is_tautology(fn, 0); + status_1 = bdd_is_tautology(fn, 1); + assert(!status_0 && !status_1); + + /* + * We want to process the regularized version of fn. + */ + node_regular = bdd_get_node(fn, &is_complemented); + if (is_complemented) { + fn_regular = bdd_not(fn); + } else { + fn_regular = bdd_dup(fn); + } + + /* + * Check if this bdd_node has already been visited. If so, return a literal in the proper phase. + */ + if (st_lookup(bdd_to_node_table, (char *) node_regular, (char **) &node)) { + if (is_complemented) { + return node_literal(node, 0); + } else { + return node_literal(node, 1); + } + } + + /* + * If top_var is found in the pi_table (i.e. it has already been visited), then + * simply set pi and continue. Otherwise, make top_var a primary input of the network, + * and add it to the pi_table. + */ + top_var_id = bdd_top_var_id(fn); + if (! st_lookup(pi_table, (char *) top_var_id, (char **) &pi)) { + pi = node_alloc(); + pi->name = util_strsav(array_fetch(char *, var_names, top_var_id)); + network_add_primary_input(network, pi); + st_insert(pi_table, (char *) top_var_id, (char *) pi); + } + + /* + * Set up the branches for special cases of constants. Note that bdd_then and bdd_else take into + * account that fn may be a complemented pointer. The effect of bdd_then and bdd_else is to + * recursively push the negated pointers all the way down to the constants. Thus, the code below + * never has to complement an internal SIS network node. + */ + sub_fn[0] = bdd_else(fn_regular); + sub_fn[1] = bdd_then(fn_regular); + bdd_free(fn_regular); + for (i = 0; i < 2; i++) { + pi_literal[i] = node_literal(pi, i); + is_constant[i] = 0; /* initialize */ + status_0 = bdd_is_tautology(sub_fn[i], 0); + status_1 = bdd_is_tautology(sub_fn[i], 1); + if (status_0 || status_1) { + is_constant[i] = 1; + phase[i] = (status_1) ? 1 : 0; + } + } + + if (is_constant[0] && is_constant[1]) { + /* + * Both then and else functions are constants. fn is a single variable bdd. + * Return pi in the proper phase, and free the other pi_literal. Free the BDDs created. + */ + for (i = 0; i < 2; i++) { + bdd_free(sub_fn[i]); + } + assert(phase[0] != phase[1]); + if ((!is_complemented && phase[1]) || (is_complemented && !phase[1])) { /* logical XOR */ + node_free(pi_literal[0]); + return pi_literal[1]; + } else { + node_free(pi_literal[1]); + return pi_literal[0]; + } + } else if (is_constant[0] || is_constant[1]) { + /* + * One of then and else functions is constant. active denotes which branch function is not a constant. + * If active==1, then the then fn is not a constant. If active==0, then the else fn is not a constant. + * input_node is the node representing the function of the non-constant function. and_node is the function + * of the top variable, with proper phase depending on if active is the then or else function, ANDed with the + * active function. node_or is the and_node ORed with the constant function. + */ + active = is_constant[0] ? 1 : 0; + input_node[active] = bdd_do_build_rec(network, sub_fn[active], pi_table, var_names, bdd_to_node_table); + /* phase[1 - active] gives the value of the constant function */ + if (phase[1 - active]) { + /* + * The constant function is 1. pi_literal[1 - active] gives the literal for top variable corresponding + * to the constant branch. Implicitly making the simplification of the form: xf+x' ==> f+x' + */ + node = node_or(input_node[active], pi_literal[1 - active]); + } else { + /* + * The constant function is 0. AND of 0 and anything is 0, so don't need to OR in anything. + */ + node = node_and(input_node[active], pi_literal[active]); + } + node_free(input_node[active]); + } else { + /* + * Neither branch function is constant. Create the function for each branch function, and AND it with + * the proper phase of the top variable. + */ + for (i = 0; i < 2; i++) { + input_node[i] = bdd_do_build_rec(network, sub_fn[i], pi_table, var_names, bdd_to_node_table); + and_node[i] = node_and(input_node[i], pi_literal[i]); + node_free(input_node[i]); + } + node = node_or(and_node[0], and_node[1]); + node_free(and_node[0]); + node_free(and_node[1]); + } + + /* + * Free the literal nodes associated with the top variable of the BDD fn, and free the BDDs created. + */ + for (i = 0; i < 2; i++) { + node_free(pi_literal[i]); + bdd_free(sub_fn[i]); + } + + /* + * Add to the network the (single) node representing the function positive fn. Add the positive + * version to the visited table. Return the node in the proper phase. + */ + network_add_node(network, node); + assert(!st_insert(bdd_to_node_table, (char *) node_regular, (char *) node)); + if (is_complemented) { + return node_literal(node, 0); + } else { + return node_literal(node, 1); + } +} + diff --git a/sis/ntbdd/com_ntbdd.c b/sis/ntbdd/com_ntbdd.c new file mode 100644 index 0000000..9dc0f47 --- /dev/null +++ b/sis/ntbdd/com_ntbdd.c @@ -0,0 +1,1039 @@ +#include <setjmp.h> +#include <signal.h> +#include "sis.h" +#include "ntbdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/ntbdd/com_ntbdd.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:27 $ + * $Log: com_ntbdd.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:27 pchong + * imported + * + * Revision 1.11 1993/07/27 20:16:41 sis + * Added tests for 5 new functions. Added timeout option to _bdd_create command. + * + * Revision 1.17 1993/07/27 19:29:15 shiple + * Added tests for 5 new functions. Added timeout option to _bdd_create command. + * + * Revision 1.16 1993/07/07 16:05:42 shiple + * Added test of bdd_and_smooth. Added some bdd_frees to com_bdd_test. + * + * Revision 1.15 1993/06/04 15:40:19 shiple + * Removed unnecessary void casts of functions calls. Made changes to adhere to exported BDD interface. + * + * Revision 1.14 1993/06/03 15:30:07 shiple + * Changed getopt, etc., to util_getopt. + * + * Revision 1.13 1993/06/02 21:31:10 shiple + * Removed typos ("\") from two print statements. + * + * Revision 1.12 1993/02/25 02:02:21 shiple + * Added code to exercise bdd_get_support and bdd_count_onset. + * Free some arrays not previously freed. + * + * Revision 1.11 1993/01/14 01:31:22 shiple + * Changed calls to ntbdd_bdd_to_network to ntbdd_bdd_single_to_network. Added a + * test to check that converting a network to a BDD and then back again give the + * original network. + * + * Revision 1.10 1993/01/11 23:38:23 shiple + * Made change to call to st_foreach_item for DEC Alpha compatibility. + * Fixed bug in com_bdd_create; was freeing NIL array returned from order_random. + * + * Revision 1.9 1992/04/01 22:41:30 shiple + * Removed temporary code for garbage collector experiments. + * + * Revision 1.8 1992/02/12 23:47:59 shiple + * Modified code in com_bdd_test to handle empty networks and + * networks with no INTERNAL nodes not feeding POs. + * + * Revision 1.7 1992/02/12 21:47:27 shiple + * In com_bdd_test and com_bdd_create, modified code to free return + * value of variable ordering routine. Added temporary code to + * set garbage collector switches at runtime. + * + * Revision 1.6 91/05/12 16:40:02 shiple + * Fixed bug in com_bdd_smooth. Was not passing an array of smoothing + * variables to bdd_smooth. + * + * Revision 1.5 91/04/29 16:36:04 shiple + * added tests of foreach_bdd_* macros in com_bdd_test + * + * Revision 1.4 91/04/26 17:57:22 shiple + * changed bdd_sharad_order to order_dfs + * + * Revision 1.3 91/03/31 23:01:43 shiple + * fixed numerous bugs in com_bdd_test; eliminated calls to obsolete + * functions; for Version 3.0 + * + * Revision 1.2 91/03/28 16:03:10 shiple + * explicitly include bdd_int.h; change datatype string to char * + * + * Revision 1.1 91/03/20 14:31:19 shiple + * Initial revision + * + */ + +static int com_bdd_stats(); +static int com_bdd_test(); +static int com_bdd_create(); +static int com_bdd_print(); +static int com_bdd_size(); +static int com_bdd_implies(); +static int com_bdd_cofactor(); +static int com_bdd_compose(); +static int com_bdd_verify(); +static int com_bdd_smooth(); + +static jmp_buf timeout_env; +static int timeout_value; +static void timeout_handle(x) +int x; +{ + longjmp(timeout_env, 1); +} + + +/* + * int + * function(network) + * network_t **network; - value/return + */ +static struct { + char *name; + int (*function)(); + boolean changes_network; +} table[] = { + { "_bdd_stats", com_bdd_stats, FALSE }, + { "_bdd_test", com_bdd_test, FALSE }, + { "_bdd_create", com_bdd_create, FALSE }, + { "_bdd_print", com_bdd_print, FALSE }, + { "_bdd_size", com_bdd_size, FALSE }, + { "_bdd_implies", com_bdd_implies, FALSE }, + { "_bdd_cofactor", com_bdd_cofactor, TRUE }, + { "_bdd_compose", com_bdd_compose, FALSE }, + { "_bdd_verify", com_bdd_verify, FALSE }, + { "_bdd_smooth", com_bdd_smooth, FALSE }, +}; + +/* + * init_ntbdd - the ntbdd package initialization + */ +void +init_ntbdd() +{ + int i; + +#if defined(DEBUG) + static string version = "v3.0"; + + (void) fprintf(miserr, "init_ntbdd for version %s of the bdd package\n", version); +#endif + + for (i = 0; i < (sizeof(table) / sizeof(table[0])); i++) { + com_add_command(table[i].name, table[i].function, table[i].changes_network); + } + node_register_daemon(DAEMON_ALLOC, bdd_alloc_demon); + node_register_daemon(DAEMON_FREE, bdd_free_demon); + +#if defined(NEVER) + errProgramName("sis"); +#endif +} + +/* + * end_ntbdd - the ntbdd package uninitialization + */ +void +end_ntbdd() +{} + +/* + * All the functions below here follow the sis-command calling convention + * + * int + * function(network) + * network_t **network; - value/return + * + * Each was registered above via com_add_command + */ + +static int +com_bdd_stats(network) +network_t **network; /* value/return */ +{ + int i; + lsGen gen; + node_t *node; + bdd_t *fn; + bdd_stats stats; + bdd_manager *manager; + st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); + + (void) fprintf(misout, "bdd's for network %s\n", network_name(*network)); + i = 0; + foreach_node(*network, gen, node) { + fn = ntbdd_at_node(node); + if (fn != NIL(bdd_t)) { + /* + * If the manager of the BDD has not been visited yet, then print out its + * stats, and insert it into the visited table. + */ + manager = bdd_get_manager(fn); + if (! st_lookup(visited, (char *) manager, NIL(char *))) { + bdd_get_stats(manager, &stats); + fprintf(misout, "bdd manager #%d ----------\n", i++); + bdd_print_stats(stats, misout); + st_insert(visited, (char *) manager, NIL(char)); + } + } + } + st_free_table(visited); + if (i == 0) { + (void) fprintf(misout, "no bdd manager associated with the network\n"); + } + return 0; +} + +/* + * Convert BDD function to a network and print it. + */ +static void +convert_bdd_to_ntwk_and_print(fn, po_name, var_names) +bdd_t *fn; +char *po_name; +array_t *var_names; +{ + network_t *network; + + /* + * Create network, print it, free it. + */ + network = ntbdd_bdd_single_to_network(fn, po_name, var_names); + com_execute(&network, "print"); + network_free(network); +} + +/* + * Exercise the ntbdd and bdd package. + */ +static int +com_bdd_test(network, argc, argv) +network_t **network; /* value/return */ +int argc; +char **argv; +{ + lsGen gen; + node_t *pi; + node_t *po; + node_t *a_pi, *a_po, *a_node, *node; + bdd_manager *mgr; + bdd_t *node_fn, *pi_fn, *po_fn; + st_table *leaves; + array_t *roots; + array_t *smoothing_vars; + bdd_t *f, *pi_bdd; + bdd_t *fns[8]; + int i, index; + int num_pi; + bdd_t *one, *zero; + array_t *var_names, *var_bdds; + st_generator *sym_table_gen; + bdd_gen *gen_bdd; + bdd_node *node_bdd; + array_t *lit_cube; + bdd_literal literal; + array_t *node_list; + array_t *po_names; + array_t *fn_array; + network_t *bdd_to_ntwk; + int status; + int verbose; + int c; + var_set_t *po_var_set; + double num_onset; + + verbose = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "v")) != EOF) { + switch(c) { + case 'v': + verbose = 1; + break; + default: + goto usage; + } + } + if (argc != util_optind) goto usage; + + /* + * Create a manager. The current network must have at least one primary input to run the + * BDD tests. + */ + num_pi = network_num_pi(*network); + if (num_pi == 0) { + (void) fprintf(miserr, "current network doesn't have any primary inputs\n"); + return 1; + } + mgr = ntbdd_start_manager(num_pi); + + /* + * Test the constants of the manager. + */ + (void) fprintf(misout, "Constants\n"); + one = bdd_one(mgr); + zero = bdd_zero(mgr); + bdd_print(one); + bdd_print(zero); + bdd_free(one); + bdd_free(zero); + + /* + * The leaves of the BDD's will be the PI's of the network. + * The roots for which we want to build BDD's are the PO's of the network. + */ + leaves = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_input(*network, gen, pi) { + st_insert(leaves, (char *) pi, (char *) -1); + } + roots = array_alloc(node_t *, 0); + foreach_primary_output(*network, gen, po) { + array_insert_last(node_t *, roots, po); + } + + /* + * Get an ordering for the leaves. + */ + node_list = order_dfs(roots, leaves, 0); + array_free(node_list); /* node_list not needed */ + + /* + * Create an array of all the names of nodes in leaves for use in + * creating networks from BDD's. Print out each name with its corresponding + * index. Also, create an array of all the single variable BDDs for + * the nodes in leaves. + */ + var_names = array_alloc(char *, st_count(leaves)); + var_bdds = array_alloc(bdd_t *, st_count(leaves)); + st_foreach_item_int(leaves, sym_table_gen, (char **) &node, &index) { + array_insert(char *, var_names, index, node->name); + pi_bdd = bdd_get_variable(mgr, index); + array_insert(bdd_t *, var_bdds, index, pi_bdd); + } + (void) fprintf(misout, "Nodes in leaves table, with variable index: \n"); + for(i = 0; i < array_n(var_names); i++) { + (void) fprintf(misout, " index = %d, name = %s\n", i, array_fetch(char *, var_names, i)); + } + + /* + * Check that the composition of the operations: network to BDD, and BDD to network, is the + * identity operation. + */ + po_names = array_alloc(char *, 0); + fn_array = array_alloc(bdd_t *, 0); + for(i = 0; i < array_n(roots); i++) { + po = array_fetch(node_t *, roots, i); + f = ntbdd_node_to_bdd(po, mgr, leaves); + array_insert(bdd_t *, fn_array, i, f); + array_insert(char *, po_names, i, node_long_name(po)); + } + bdd_to_ntwk = ntbdd_bdd_array_to_network(fn_array, po_names, var_names); + status = network_verify(*network, bdd_to_ntwk, 1); + network_free(bdd_to_ntwk); + if (status == 0) { + (void) fprintf(miserr, "%s", error_string()); + (void) fprintf(miserr, "Networks are not equivalent.\n"); + } else { + (void) fprintf(miserr, "\nComposition of ntwk -> bdd -> ntwk is the identity.\n"); + } + + /* + * Pick up a few nodes to play with, + */ + a_po = network_get_po(*network, 0); + a_po = node_get_fanin(a_po, 0); /* actually, get node which feeds the PO */ + a_pi = network_get_pi(*network, 0); + a_node = NIL(node_t); + foreach_node (*network, gen, node) { + if (node->type == PRIMARY_INPUT) continue; + if (node->type == PRIMARY_OUTPUT) continue; + a_node = node; + } + + if (a_node == NIL(node_t)) { + a_node = a_pi; + } + (void) fprintf(misout, "\nPrimary input: %s\n", node_long_name(a_pi)); + (void) fprintf(misout, "Primary output: %s\n", node_long_name(a_po)); + (void) fprintf(misout, "An internal node: %s\n", node_long_name(a_node)); + + /* + * Test contruction. First get the BDD for a PO. + */ + (void) fprintf(misout, "\nFunction and BDD for node: %s\n", node_long_name(a_po)); + f = ntbdd_node_to_bdd(a_po, mgr, leaves); + po_fn = bdd_dup(f); + convert_bdd_to_ntwk_and_print(po_fn, node_long_name(a_po), var_names); + bdd_print(po_fn); + + /* + * Traverse the BDD node by node. + */ + (void) fprintf(misout, "\nforeach_bdd_node of BDD for node: %s\n", node_long_name(a_po)); + foreach_bdd_node(po_fn, gen_bdd, node_bdd) { + /* note that node_bdd has already been REGULARized */ + (void) fprintf(misout, " address = %#x\n", (int) node_bdd); + } + + /* + * Print out all the cubes of the BDD, found by traversing all the paths from the + * root to the constant 1. + */ + (void) fprintf(misout, "\nforeach_bdd_cube of BDD for node: %s\n", node_long_name(a_po)); + foreach_bdd_cube(po_fn, gen_bdd, lit_cube) { + for(i = 0; i < num_pi; i++) { + literal = array_fetch(bdd_literal, lit_cube, i); + (void) fprintf(misout, "%d", literal); + } + (void) fprintf(misout, "\n"); + } + + /* + * Print out the variable support of po_fn. + */ + po_var_set = bdd_get_support(po_fn); + (void) fprintf(misout, "Variable support for node %s has cardinality %d\n", + node_long_name(a_po), var_set_n_elts(po_var_set)); + var_set_print(misout, po_var_set); + var_set_free(po_var_set); + + /* + * Print out the number of minterms in the onset of po_fn. + */ + num_onset = bdd_count_onset(po_fn, var_bdds); + (void) fprintf(misout, "Number of minterms in onset of node %s = %f\n", node_long_name(a_po), num_onset); + + /* + * Build the BDD for a_node (could be PI, INTERNAL, or INTERNAL driving a PO). + */ + (void) fprintf(misout, "\nFunction and BDD for node: %s\n", node_long_name(a_node)); + f = ntbdd_node_to_bdd(a_node, mgr, leaves); + node_fn = bdd_dup(f); + convert_bdd_to_ntwk_and_print(node_fn, node_long_name(a_node), var_names); + bdd_print(node_fn); + + /* + * Create a new BDD variable. + */ + (void) fprintf(misout, "make a new variable\n"); + f = bdd_create_variable(mgr); + bdd_print(f); + bdd_free(f); + + pi_fn = ntbdd_node_to_bdd(a_pi, mgr, leaves); /* make bdd for pi */ + + /* + * Test cofactor, compose, smooth, and_smooth, minimize, is_cube. + */ + (void) fprintf(misout, "cofactor(%s, %s)\n", node_long_name(a_po), node_long_name(a_pi)); + f = bdd_cofactor(po_fn, pi_fn); + convert_bdd_to_ntwk_and_print(f, "cofactor", var_names); + bdd_print(f); + bdd_free(f); + + (void) fprintf(misout, "compose(%s, %s, %s)\n", node_long_name(a_po), node_long_name(a_pi), node_long_name(a_node)); + f = bdd_compose(po_fn, pi_fn, node_fn); + convert_bdd_to_ntwk_and_print(f, "compose", var_names); + bdd_print(f); + bdd_free(f); + + (void) fprintf(misout, "smooth(%s, %s)\n", node_long_name(a_po), node_long_name(a_pi)); + smoothing_vars = array_alloc(bdd_t *, 0); + array_insert_last(bdd_t *, smoothing_vars, pi_fn); + f = bdd_smooth(po_fn, smoothing_vars); + convert_bdd_to_ntwk_and_print(f, "smooth", var_names); + bdd_print(f); + bdd_free(f); + array_free(smoothing_vars); + + (void) fprintf(misout, "and_smooth(%s, %s)\n", node_long_name(a_po), node_long_name(a_node)); + smoothing_vars = array_alloc(bdd_t *, 0); + foreach_primary_input(*network, gen, pi) { + f = ntbdd_node_to_bdd(pi, mgr, leaves); + array_insert_last(bdd_t *, smoothing_vars, f); + } + f = bdd_and_smooth(po_fn, node_fn, smoothing_vars); /* smoothing out all the variables */ + convert_bdd_to_ntwk_and_print(f, "and_smooth", var_names); + bdd_print(f); + bdd_free(f); + array_free(smoothing_vars); + + (void) fprintf(misout, "minimize(%s, %s)\n", node_long_name(a_po), node_long_name(a_pi)); + f = bdd_minimize_with_params(po_fn, pi_fn, BDD_MIN_OSM, TRUE, FALSE, TRUE); + convert_bdd_to_ntwk_and_print(f, "minimize", var_names); + bdd_print(f); + bdd_free(f); + f = bdd_between(po_fn, node_fn); + bdd_free(f); + + /* This line has been commented out because the Long BDD package doesn't + define bdd_is_cube */ + +/* (void) fprintf(misout, "is_cube(%s) = %s\n", node_long_name(a_po), (bdd_is_cube(po_fn)) ? "TRUE" : "FALSE"); */ + + /* + * Test other BDD functions. + */ + fns[0] = bdd_dup(node_fn); /* a */ + fns[1] = bdd_not(fns[0]); /* a' */ + fns[2] = bdd_dup(po_fn); /* b */ + fns[3] = bdd_not(fns[2]); /* b' */ + fns[4] = bdd_and(fns[0], fns[2], 1, 1); /* a b */ + fns[5] = bdd_or(fns[0], fns[2], 0, 0); /* a' + b' */ + fns[6] = bdd_not(fns[5]); /* (a' + b')' = a b */ + if (! bdd_equal(fns[6], fns[4])) { + (void) fprintf(miserr, "ERROR: De Morgan law violated by BDD package\n"); + } + fns[7] = bdd_or(fns[4], fns[5], 1, 1); /* a b + a' + b' = 1 */ + if (! bdd_is_tautology(fns[7], 1)) { + convert_bdd_to_ntwk_and_print(fns[7], "fn_7", var_names); + (void) fprintf(miserr, "ERROR: fn should have been a tautology\n"); + } + if (! bdd_leq(fns[4], fns[0], 1, 1)) { + convert_bdd_to_ntwk_and_print(fns[4], "fn_4", var_names); + convert_bdd_to_ntwk_and_print(fns[0], "fn_0", var_names); + (void) fprintf(miserr, "ERROR: first fn should have implied the second one\n"); + } + if (verbose) { + for (i = 0; i < 8; i++) { + (void) fprintf(misout, "function %d:\n", i); + convert_bdd_to_ntwk_and_print(fns[i], "bdd_out", var_names); + } + } + + /* + * Free the BDD's created. + */ + for (i = 0; i < 8; i++) { + bdd_free(fns[i]); + } + bdd_free(po_fn); + bdd_free(node_fn); + for (i = 0; i < array_n(var_bdds); i++) { + pi_bdd = array_fetch(bdd_t *, var_bdds, i); + bdd_free(pi_bdd); + } + + /* + * Kill manager. + */ + ntbdd_end_manager(mgr); + + /* + * Free everything else. + */ + array_free(fn_array); + array_free(po_names); + array_free(var_names); + array_free(roots); + array_free(var_bdds); + + return 0; + +usage: + (void) fprintf(miserr, "usage: _bdd_test [-v]\n"); + return 1; +} + +static int +com_bdd_create(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + bdd_manager *manager; + array_t *node_vec; + int i, j, c, count; + ntbdd_type_t locality; + node_t *node, *fanin, *pi; + long time; + array_t *(*ordering)(); + st_table *leaves; + lsGen gen; + bdd_t *fn; + array_t *node_list; + + ordering = order_dfs; + locality = GLOBAL; + timeout_value = 0; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "lot:")) != EOF) { + switch (c) { + case 'l': + locality = LOCAL; + break; + case 'o': + if (strcmp("dfs", util_optarg) == 0) { + ordering = order_dfs; + } else if (strcmp("random", util_optarg) == 0) { + ordering = order_random; + } else { + (void) fprintf(miserr, "unknown ordering method: %s\n", util_optarg); + goto usage; + } + break; + case 't': + timeout_value = atoi(util_optarg); + if (timeout_value < 0 || timeout_value > 3600 * 24 * 365) { + goto usage; + } + break; + default: + goto usage; + } + } + + /* nodes for which to create BDD's */ + node_vec = com_get_nodes(*network, argc - util_optind + 1, argv + util_optind - 1); + if (array_n(node_vec) == 0) goto usage; + + if (timeout_value > 0) { + (void) signal(SIGALRM, timeout_handle); + (void) alarm(timeout_value); + if (setjmp(timeout_env) > 0) { + fprintf(misout, "timeout occurred after %d seconds\n", timeout_value); + return 1; + } + } + + (void) fprintf(misout, "ordering nodes\n"); + leaves = st_init_table(st_ptrcmp, st_ptrhash); + + /* if local, pick up some ordering */ + if (locality == LOCAL) { + count = 0; + for (i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (node->type == PRIMARY_INPUT) { + /* + * If the node is a PI, and it has not been inserted into the table yet, then insert it. + */ + if (! st_is_member(leaves, (char *) node)) { + if (! st_insert(leaves, (char *) node, (char *) count)) count++; + } + } else { + foreach_fanin(node, j, fanin) { /* st_insert returns 0 if no entry was found */ + if (! st_is_member(leaves, (char *) fanin)) { + if (! st_insert(leaves, (char *) fanin, (char *) count)) count++; + } + } + } + } + } else { + foreach_primary_input(*network, gen, pi) { + st_insert(leaves, (char *) pi, (char *) -1); + } + node_list = (*ordering)(node_vec, leaves, 0); + if (node_list != NIL(array_t)) { + array_free(node_list); /* node_list not needed */ + } + } + + (void) fprintf(misout, "constructing BDDs\n"); + time = util_cpu_time(); + manager = ntbdd_start_manager(st_count(leaves)); + if (locality == LOCAL) { + /* + * Create the local BDD for each node in node_vec. Then immediately + * free the BDD. This just makes sure we don't bomb anything; the + * user cannot get to the local BDD he asked to be created. + */ + for (i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + fn = ntbdd_node_to_local_bdd(node, manager, leaves); + bdd_free(fn); + } + } else { /* GLOBAL */ + for (i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + ntbdd_node_to_bdd(node, manager, leaves); + } + } + (void) fprintf(misout, "CPU time used: %g sec\n", (double) (util_cpu_time() - time) / 1000); + + /* we want global BDDs to persist, so don't kill the manager */ + + array_free(node_vec); + st_free_table(leaves); + return (0); + + usage: + (void) fprintf(miserr, "usage: bdd_create [-l] [-o ordering_style] [-t time_limit] node1 node2 ...\n"); + (void) fprintf(miserr, " -l: build the bdd local to the specified nodes; not stored\n"); + (void) fprintf(miserr, " ordering_style is one of the following: dfs, random\n"); + return 1; +} + +static int +com_bdd_print(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + int n, i; + node_t *node; + bdd_t *bdd; + + node_vec = com_get_nodes(*network, argc, argv); + + n = array_n(node_vec); + if (n == 0) { + array_free(node_vec); + (void) fprintf(miserr, "usage: bdd_print n1 n2 ...\n"); + return (1); + } + + for (i=0; i<n; i++) { + node = array_fetch(node_t *, node_vec, i); + bdd = ntbdd_at_node(node); + if ((bdd != NIL(bdd_t)) && (node->type != PRIMARY_OUTPUT)) { + /* Primary outputs will be effectively caught by the fanins of the primary outputs. */ + (void) fprintf(misout, "node: %s\n", node_name(node)); + bdd_print(bdd); + } + } + array_free(node_vec); + return (0); +} + +static int +com_bdd_size(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + int i, n; + node_t *node; + bdd_t *bdd; + + node_vec = com_get_nodes(*network, argc, argv); + + n = array_n(node_vec); + if (n == 0) { + array_free(node_vec); + (void) fprintf(miserr, "usage: bdd_size n1 n2 ...\n"); + return (1); + } + for (i = 0; i < n; i++) { + node = array_fetch(node_t *, node_vec, i); + bdd = ntbdd_at_node(node); + if ((bdd != NIL(bdd_t)) && (node->type != PRIMARY_OUTPUT)) { + /* Primary outputs will be effectively caught by the fanins of the primary outputs. */ + (void) fprintf(misout, "node: %s, size %d\n", node_name(node), bdd_size(bdd)); + } + } + array_free(node_vec); + return (0); +} + +static int +com_bdd_implies(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *n1, *n2; + int p1, p2; + bdd_t *n1_bdd, *n2_bdd; + + if (argc != 5) { + if (argc == 3) { + p1 = 1; + p2 = 1; + } else { +usage: + (void) fprintf(miserr, "usage: bdd_implies n1 n2 [phase1 phase2]\n"); + (void) fprintf(miserr, "\tIf phase1 & phase2 are left out they are assumed both 1\n"); + return (1); + } + } else { + p1 = atoi(argv[3]); + p2 = atoi(argv[4]); + } + if ((p1 != 0 && p1 != 1) || (p2 != 0 && p2 != 1)) { + goto usage; + } + node_vec = com_get_nodes(*network, 3, argv); + if (array_n(node_vec) != 2) { + array_free(node_vec); + goto usage; + } + n1 = array_fetch(node_t *, node_vec, 0); + n2 = array_fetch(node_t *, node_vec, 1); + + array_free(node_vec); + if (n1 == NIL(node_t) || n2 == NIL(node_t)) { + goto usage; + } + n1_bdd = ntbdd_at_node(n1); + n2_bdd = ntbdd_at_node(n2); + (void) fprintf(misout, "%s set to %d %s ", node_name(n1), p1, + ((bdd_leq(n1_bdd, n2_bdd, p1, p2) == 1) ? "forces" : "does not force")); + (void) fprintf(misout, "%s to %d\n", node_name(n2), p2); + return (0); +} + +static int +com_bdd_cofactor(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *n1, *n2, *pi; + bdd_t *bdd, *n1_bdd, *n2_bdd; + int c; + int status = 0; + int print_as_network = 1; + array_t *var_names; + int index; + lsGen gen; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "b")) != EOF) { + switch (c) { + case 'b': + print_as_network = 0; + break; + default: + goto usage; + } + } + node_vec = com_get_nodes(*network, argc - util_optind + 1, argv + util_optind - 1); + if (argc -util_optind + 1 != 3 || array_n(node_vec) != 2) { + status = 1; + } else { + n1 = array_fetch(node_t *, node_vec, 0); + n2 = array_fetch(node_t *, node_vec, 1); + + if (n1 == NIL(node_t) || n2 == NIL(node_t)) { + status = 1; + } else { + n1_bdd = ntbdd_at_node(n1); + n2_bdd = ntbdd_at_node(n2); + if (!((n1_bdd == NIL(bdd_t)) || (n2_bdd == NIL(bdd_t)))) { + bdd = bdd_cofactor(n1_bdd, n2_bdd); + if (print_as_network) { + var_names = array_alloc(char *, network_num_pi(*network)); + foreach_primary_input(*network, gen, pi) { + index = bdd_top_var_id(BDD(pi)); + array_insert(char *, var_names, index, pi->name); + } + convert_bdd_to_ntwk_and_print(bdd, "cofactor", var_names); + } else { + bdd_print(bdd); + } + bdd_free(bdd); + } + } + } + array_free(node_vec); + return status; + + usage: + (void) fprintf(miserr, "\ +_bdd_cofactor [-b] node_fn node_factor\n\ + -b: print as BDD\n"); + return 1; +} + +static int +com_bdd_smooth(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *n1, *node, *pi; + int status = 0; + array_t *smoothing_vars; + bdd_t *bdd, *n1_bdd, *result_bdd; + int c, n, i; + int print_as_network = 1; + array_t *var_names; + int index; + lsGen gen; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "b")) != EOF) { + switch (c) { + case 'b': + print_as_network = 0; + break; + default: + goto usage; + } + } + + node_vec = com_get_nodes(*network, argc - util_optind + 1, argv + util_optind - 1); + n = array_n(node_vec); + if (n < 2) { + (void) array_free(node_vec); + goto usage; + } + + n1 = array_fetch(node_t *, node_vec, 0); + if (n1 == NIL(node_t)) { + (void) fprintf(miserr, "%s: nil node\n", argv[0]); + return (1); + } else { + n1_bdd = ntbdd_at_node(n1); + if (n1_bdd == NIL(bdd_t)) { + (void) fprintf(miserr, "%s: node does not have a BDD\n", argv[0]); + return (1); + } + } + + smoothing_vars = array_alloc(bdd_t *, 0); + for (i = 1; i < n; i++) { + node = array_fetch(node_t *, node_vec, i); + if (n1 == NIL(node_t)) { + (void) fprintf(miserr, "%s: nil node\n", argv[0]); + return (1); + } + bdd = ntbdd_at_node(node); + if (bdd == NIL(bdd_t)) { + (void) fprintf(miserr, "%s: node does not have a BDD\n", argv[0]); + return (1); + } + array_insert_last(bdd_t *, smoothing_vars, bdd); + } + result_bdd = bdd_smooth(n1_bdd, smoothing_vars); + + + if (print_as_network) { + var_names = array_alloc(char *, network_num_pi(*network)); + foreach_primary_input(*network, gen, pi) { + index = bdd_top_var_id(BDD(pi)); + array_insert(char *, var_names, index, pi->name); + } + convert_bdd_to_ntwk_and_print(result_bdd, "smooth", var_names); + } else { + bdd_print(result_bdd); + } + + bdd_free(result_bdd); + array_free(smoothing_vars); + array_free(node_vec); + return (status); + + usage: + (void) fprintf(miserr, "\ +_bdd_smooth [-b] node_fn node_var1 node_var2 ...\n\ + -b: print as BDD\n"); + return 1; + +} + +static int +com_bdd_compose(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *node_vec; + node_t *n1, *n2, *n3; + bdd_t *bdd; + int status; + + node_vec = com_get_nodes(*network, argc, argv); + if (argc != 4 || array_n(node_vec) != 3) { + status = 1; + } else { + n1 = array_fetch(node_t *, node_vec, 0); + n2 = array_fetch(node_t *, node_vec, 1); + n3 = array_fetch(node_t *, node_vec, 2); + + if (n1 == NIL(node_t) || n2 == NIL(node_t) || n3 == NIL(node_t)) { + status = 1; + } else { + bdd = bdd_compose(ntbdd_at_node(n1), ntbdd_at_node(n2), ntbdd_at_node(n3)); + bdd_print(bdd); + bdd_free(bdd); + status = 0; + } + } + array_free(node_vec); + return (status); +} + +static /* boolean */ int readit(); + +static int +com_bdd_verify(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + FILE *f1, *f2; + network_t *net1, *net2; + int status; + int i; + + if (argc != 3) { +usage: + (void) fprintf(miserr, "usage: %s blif_file1 blif_file2\n", argv[0]); + return (1); + } + f1 = com_open_file(argv[1], "r", NIL(char *), 0); + if (f1 == NIL(FILE)) { + goto usage; + } + f2 = com_open_file(argv[2], "r", NIL(char *), 0); + if (f2 == NIL(FILE)) { + (void) fclose(f1); + goto usage; + } + + net1 = net2 = NIL(network_t); + error_init(); + + if (readit(f1, argv[1], &net1) != 1 || readit(f2, argv[2], &net2) != 1) { + (void) fprintf(miserr, "%s: error reading network\n", argv[0]); + if (error_string()[0] != '\0') { + (void) fprintf(miserr, "%s", error_string()); + } + status = 1; + } + else { + i = ntbdd_verify_network(net1, net2, DFS_ORDER, ALL_TOGETHER); + (void) fprintf(misout, "verification %s\n", (i == 0) ? "fails" : "succeeds"); + status = 0; + } + network_free(net1); + network_free(net2); + (void) fclose(f1); + (void) fclose(f2); + return (status); +} + +static /* boolean */ int +readit(file, filename, network) +FILE *file; +char *filename; +network_t **network; /* return */ +{ + error_init(); + read_register_filename(filename); + return (read_blif(file, network)); +} + diff --git a/sis/ntbdd/manager.c b/sis/ntbdd/manager.c new file mode 100644 index 0000000..36a9bc4 --- /dev/null +++ b/sis/ntbdd/manager.c @@ -0,0 +1,114 @@ +#include "sis.h" +#include "ntbdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/ntbdd/manager.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:27 $ + * $Log: manager.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:27 pchong + * imported + * + * Revision 1.6 1993/06/04 19:42:26 sis + * *** empty log message *** + * + * Revision 1.7 1993/06/04 15:39:16 shiple + * Removed unnecessary void casts of functions calls. Made changes to adhere to exported BDD interface. + * + * Revision 1.6 1993/06/02 21:31:48 shiple + * Corrected incorrect cast of (char *) to (char **). + * + * Revision 1.5 1992/04/01 22:42:42 shiple + * Removed temporary code for garbage collector experiments. + * + * Revision 1.4 1992/02/12 23:58:49 shiple + * In ntbdd_end_manager, added call to free NTBDD_HOOK. Added + * temporary code to dump BDD survival rates from ntbdd_end_manager. + * + * Revision 1.3 91/03/31 23:04:40 shiple + * small revisions for Version 3.0 + * + * Revision 1.2 91/03/28 16:03:56 shiple + * explicitly include bdd_int.h + * + * Revision 1.1 91/03/20 14:38:40 shiple + * Initial revision + * + */ + +static void bdd_network_free(); + +/* + * ntbdd_start_manager - Initialize a network bdd manager. + * Set up a data structure to contain references + * to networks when necessary. + * Return the bdd_manager. + */ +bdd_manager *ntbdd_start_manager(num_vars) +int num_vars; +{ + bdd_manager *manager; + ntbdd_t *ntbdd_data; + bdd_external_hooks *hooks; + + manager = bdd_start(num_vars); + ntbdd_data = ALLOC(ntbdd_t, 1); + ntbdd_data->last_network = NIL(network_t); + ntbdd_data->network_table = st_init_table(st_ptrcmp, st_ptrhash); + hooks = bdd_get_external_hooks(manager); + hooks->network = (char *) ntbdd_data; + return manager; +} + +/* + * ntbdd_end_manager - terminate a network bdd manager + * Frees all the BDD's associated to any node in any network + * with that bdd manager. + */ +void ntbdd_end_manager(manager) +bdd_manager *manager; +{ + st_generator *gen; + network_t *network; + st_table *table; + bdd_external_hooks *hooks; + ntbdd_t *ntbdd_data; + + hooks = bdd_get_external_hooks(manager); + ntbdd_data = (ntbdd_t *) hooks->network; + table = ntbdd_data->network_table; + + st_foreach_item(table, gen, (char **) &network, NIL(char *)) { + bdd_network_free(manager, network); + } + st_free_table(table); + FREE(ntbdd_data); + bdd_end(manager); +} + +/* + * Free the BDD's of all the nodes in the network + * with the specified BDD manager. + */ +static void bdd_network_free(manager, network) +bdd_manager *manager; +network_t *network; +{ + lsGen gen; + node_t *node; + bdd_t *fn; + + foreach_node(network, gen, node) { + fn = ntbdd_at_node(node); + if (fn != NIL(bdd_t)) { + if (bdd_get_manager(fn) == manager) { + bdd_free(fn); + /* do not use ntbdd_set_at_node here: problems with manager's hooks->network.network_table */ + BDD_SET(node, NIL(bdd_t)); + } + } + } +} diff --git a/sis/ntbdd/node_to_bdd.c b/sis/ntbdd/node_to_bdd.c new file mode 100644 index 0000000..d1e840c --- /dev/null +++ b/sis/ntbdd/node_to_bdd.c @@ -0,0 +1,380 @@ +#include "sis.h" +#include "ntbdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/ntbdd/node_to_bdd.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:27 $ + * $Log: node_to_bdd.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:27 pchong + * imported + * + * Revision 1.10 1993/06/22 17:27:45 sis + * In function product, added dereference of literal type, outside of a + * switch statement. + * + * Revision 1.9 1993/06/22 00:53:40 shiple + * In function product, added dereference of literal type, outside of a switch statement. + * + * Revision 1.8 1993/06/04 15:40:19 shiple + * Removed unnecessary void casts of functions calls. Made changes to adhere to exported BDD interface. + * + * Revision 1.7 1993/06/02 21:32:16 shiple + * Added proper cast of varid to (int *) in several places. + * + * Revision 1.6 1993/01/11 23:40:27 shiple + * Made change to calls to st_lookup for DEC Alpha compatibility. + * + * Revision 1.5 1992/07/24 01:03:44 shiple + * In function ntbdd_node_to_bdd, changed code so that we do not repeatedly + * allocate and free bdd_t's for nodes in the leaves table. + * + * Revision 1.4 1991/05/10 20:43:39 shiple + * In function product, free unused bdd_t's while building local BDD. + * + * Revision 1.3 91/03/31 23:05:37 shiple + * major revisions for Version 3.0; eliminated several top level routines + * to create global BDD's; using recursion to build global BDD's, instead + * of visiting nodes in topological order; rewrote much code to conform to + * BDD interface + * + * Revision 1.2 91/03/27 14:05:03 shiple + * change include mis.h to sis.h + * + * Revision 1.1 91/03/20 14:25:56 shiple + * Initial revision + * + */ + +static bdd_t *construct_local_bdd(); +static bdd_t *sop(); +static bdd_t *product(); +static bdd_t *get_node_bdd(); + +/* + * Build the logic function at that node in terms of its inputs. + * The ordering of the inputs should be specified in "leaves". + */ +bdd_t *ntbdd_node_to_local_bdd(node, manager, leaves) +node_t *node; +bdd_manager *manager; +st_table *leaves; +{ + int i; + node_t *fanin; + + /* + * Make sure that each fanin is in the leaves table. + */ + foreach_fanin(node, i, fanin) { + assert(st_lookup(leaves, (char *) fanin, NIL(char *))); + } + + return construct_local_bdd(node, manager, leaves); +} + +/* + * ntbdd_node_to_bdd - construct a bdd from a node + * + * The manager is provided by the caller + * The BDD variables are the nodes in leaves. + * The table "leaves" specifies the ordering. + * return the bdd ... + * The BDD is always stored in the node. + * + * If a BDD is already there with the same manager, + * it is considered valid even if it was computed with different leaves. + * If this happens, then the user is not using managers correctly. + * + * If node has a BDD(node) field with same manager, take that. + * Otherwise, build the bdd at the node from the bdd's of its inputs + * the BDD's of the inputs are computed recursively + */ +bdd_t *ntbdd_node_to_bdd(node, manager, leaves) +node_t *node; +bdd_manager *manager; +st_table *leaves; +{ + bdd_variableId varid; + bdd_t *ext_f, *fanin_bdd, *single_var_f; + node_t *fanin_node; + int nliterals; + + + /* + * Handle the cases where node already has a BDD or where node is in the leaves table. + */ + ext_f = ntbdd_at_node(node); + if (ext_f == NIL(bdd_t)) { + /* + * node does not have a BDD. If node is in the leaves table, + * then get the single variable BDD for node, and return it. + * If node is not in the leaves table, drop down for further processing. + */ + if (st_lookup_int(leaves, (char *) node, (int *) &varid)) { + single_var_f = bdd_get_variable(manager, varid); + ntbdd_set_at_node(node, single_var_f); + return single_var_f; + } + + } else { + /* + * The node already has a BDD. + * If node is in the leaves table, then check that ext_f points to the + * single varible BDD representing the node variable. If so, just + * return ext_f; if not, return a pointer to the single variable BDD. + */ + if (st_lookup_int(leaves, (char *) node, (int *) &varid)) { + single_var_f = bdd_get_variable(manager, varid); + if (bdd_equal(ext_f, single_var_f)) { + bdd_free(single_var_f); + return ext_f; + } else { + ntbdd_set_at_node(node, single_var_f); /* automatically frees existing bdd at node */ + return single_var_f; + } + } else { + /* + * node is not in the leaves table. + * If the bdd at this node is already of this bdd manager + * (which presumably means that it has been assigned before) + * then just take that value as the correct value. Otherwise, + * drop down to create a BDD for this node in terms of leaves. + */ + if (bdd_get_manager(ext_f) == manager) { + return ext_f; + } + } + } + + + /* + * Treat constants specially. + */ + nliterals = node_num_fanin(node); + if (nliterals == 0) { + switch (node_function(node)) { + case NODE_0: + ext_f = bdd_zero(manager); + break; + case NODE_1: + ext_f = bdd_one(manager); + break; + default: + fail("variable not listed in the leaves table"); + break; + } + ntbdd_set_at_node(node, ext_f); + return ext_f; + } + + /* + * If there is a fanin and this is a primary output + * (e.g. this is one of those special primary output nodes) + * duplicate the bdd at the fanin of this node and return that. + * Make a new one in any case, in case they + * want to call demons for any changes ... + */ + if (nliterals == 1 && node->type == PRIMARY_OUTPUT) { + fanin_node = node_get_fanin(node, 0); + fanin_bdd = ntbdd_node_to_bdd(fanin_node, manager, leaves); + ext_f = bdd_dup(fanin_bdd); + ntbdd_set_at_node(node, ext_f); + return ext_f; + } + + /* + * General case: get a bdd for the sum of products at this node + */ + ext_f = sop(node, manager, leaves, GLOBAL); + + ntbdd_set_at_node(node, ext_f); + return ext_f; +} + +/* + * Build the node as a function of its direct inputs. + * Assumes all direct inputs are in 'leaves'. + * If node has no fanin, its function is itself. + * In that case, it should be in the 'leaves' table. + */ +static bdd_t *construct_local_bdd(node, manager, leaves) +node_t *node; +bdd_manager *manager; +st_table *leaves; +{ + bdd_variableId varid; + bdd_t *ext_f; + int nliterals; + node_t *fanin; + + /* + * Treat constants specially. + */ + nliterals = node_num_fanin(node); + if (nliterals == 0) { + switch (node_function(node)) { + case NODE_0: + ext_f = bdd_zero(manager); + break; + case NODE_1: + ext_f = bdd_one(manager); + break; + default: + assert(st_lookup_int(leaves, (char *) node, (int *) &varid)); + ext_f = bdd_get_variable(manager, varid); + break; + } + } else if (nliterals == 1 && node->type == PRIMARY_OUTPUT) { + /* + * If there is a fanin and this is a primary output + * (e.g. this is one of those special primary output nodes) + * get the variable associated with the input and return the corresponding BDD. + * Note that we do not return the function of the fanin, but just the + * variable of the fanin. + */ + fanin = node_get_fanin(node, 0); + assert(st_lookup_int(leaves, (char *) fanin, (int *) &varid)); + ext_f = bdd_get_variable(manager, varid); + } else { + /* + * General case: get a bdd for the sum of products at this node + */ + ext_f = sop(node, manager, leaves, LOCAL); + } + + return ext_f; +} + +/* + * sop - get the bdd for a sum of products + * + * The node is made up of a sum of products. Foreach product (cube), + * OR together the cubes in the node to make the final bdd for the node. + * Start by taking the one node as the base-case. + */ +static bdd_t * +sop(node, manager, leaves, bdd_type) +node_t *node; +bdd_manager *manager; +st_table *leaves; +ntbdd_type_t bdd_type; +{ + int ncubes; + int row; + bdd_t *current_bdd, *temp_bdd, *temp2_bdd; + + ncubes = node_num_cube(node); + + /* + * current = or(current, tmp) + */ + current_bdd = bdd_zero(manager); + for (row = 0; row < ncubes; row++) { + temp_bdd = product(node, manager, row, leaves, bdd_type); + temp2_bdd = bdd_or(current_bdd, temp_bdd, 1, 1); + bdd_free(temp_bdd); + bdd_free(current_bdd); + current_bdd = temp2_bdd; + } + + return current_bdd; +} + +/* + * product - take the product of all of the elements in the cube + * return the bdd of the product + */ +static bdd_t * +product(node, manager, row, leaves, bdd_type) +node_t *node; +bdd_manager *manager; +int row; +st_table *leaves; +ntbdd_type_t bdd_type; +{ + int nliterals; + int literal; + node_cube_t cube; + node_t *fanin; + bdd_t *fanin_bdd, *temp_bdd, *temp2_bdd, *current_bdd; + node_literal_t literal_type; + + nliterals = node_num_fanin(node); + cube = node_get_cube(node, row); + + current_bdd = bdd_one(manager); + for (literal = 0; literal < nliterals; literal++) { + literal_type = node_get_literal(cube, literal); + switch (literal_type) { + case ZERO: + fanin = node_get_fanin(node, literal); + fanin_bdd = get_node_bdd(fanin, manager, leaves, bdd_type); + temp_bdd = bdd_not(fanin_bdd); /* take complement */ + if (bdd_type == LOCAL) { + /* + * For the LOCAL case, fanin_bdd is not attached to the fanin node. Thus, + * we must free it so that we don't leave any bdd_t's dangling. In the + * GLOBAL case, the fanin_bdd is attached to the fanin node, and we leave + * it their for future reference. (Same comment applies to case ONE.) + */ + bdd_free(fanin_bdd); + } + break; + case ONE: + fanin = node_get_fanin(node, literal); + fanin_bdd = get_node_bdd(fanin, manager, leaves, bdd_type); + temp_bdd = bdd_dup(fanin_bdd); /* just duplicate, so we have same flow as case ZERO */ + if (bdd_type == LOCAL) { + bdd_free(fanin_bdd); + } + break; + default: + /* do nothing for case TWO (i.e. when variable is a don't care) */ + continue; + } + + /* + * current = and(current, tmp) + */ + temp2_bdd = bdd_and(current_bdd, temp_bdd, 1, 1); + bdd_free(temp_bdd); + bdd_free(current_bdd); + current_bdd = temp2_bdd; + } + + return current_bdd; +} + +/* + * get_node_bdd - If bdd_type is LOCAL, then just call bdd_get_variable. + * If bdd_type is GLOBAL, then call ntbdd_node_to_bdd. The distinction + * is that we don't want to store any BDDs created in making a local BDD. + * On the other hand, in creating a global BDD, we store any BDDs created + * at the respective node. + */ +static bdd_t * +get_node_bdd(node, manager, leaves, bdd_type) +node_t *node; +bdd_manager *manager; +st_table *leaves; +ntbdd_type_t bdd_type; +{ + bdd_t *bdd; + bdd_variableId varid; + + if (bdd_type == LOCAL) { + if (st_lookup_int(leaves, (char *) node, (int *) &varid)) { + bdd = bdd_get_variable(manager, varid); + } + } else if (bdd_type == GLOBAL) { + bdd = ntbdd_node_to_bdd(node, manager, leaves); + } else { + fail ("get_node_bdd: unknown bdd_type"); + } + + return bdd; +} diff --git a/sis/ntbdd/ntbdd.doc b/sis/ntbdd/ntbdd.doc new file mode 100644 index 0000000..5fcffff --- /dev/null +++ b/sis/ntbdd/ntbdd.doc @@ -0,0 +1,277 @@ + +Node to Binary Decision Diagram (NTBDD) Package, Version 3.0 + +Tom Shiple (original contributors: Herve' Touati, Wendell Baker) +University of California, Berkeley, 1991 + + +Introduction ------------------------------------------------------------------ + +The NTBDD package serves as the interface between SIS and the BDD package. It +contains functions for creating, storing, and freeing BDD's for network nodes. +In addition, it provides functions for verifying the equivalence of two +networks using BDD's, and constructing networks from BDD's. + +This package grew out of earlier versions of the BDD package which contained +all the BDD routines, as well as the interface of MIS to the BDD data +structures. Version 3.0 contains just the interface of SIS to the BDD +package. + +Version 3.0 is not strictly compatible with any of the previous versions. The +goal in creating this version was to streamline the interface without +sacrificing any essential functionality. The routines which use now obsolete +BDD data structures have been eliminated. Furthermore, several routines which +can be easily implemented using other exported routines, have been eliminated. +Finally, the names of several routines have been changed to conform to the +prefix "ntbdd", and to make them more lucid. + +The routines used to produce an ordering of the BDD variables have been moved +to the Ordering package. + +The BDD package documentation explains the concepts of BDD manager, BDD +formula (bdd_t), and single variable BDD formula. Also, it contains +documentation for all the BDD Boolean operators, which you may use freely in +conjunction with the NTBDD package. + +An important concept of the NTBDD package is the leaves tables. The leaves +table is a hash table of network nodes (node_t *) to variable ID's (int). The +BDD for a node constructed using a particular leaves table will be in terms of +the node variables in the leaves table. The variable ID's give the variable +ordering for the BDD to be constructed. The following code creates an +ordering of all the primary inputs of a network: + + count = 0; + leaves = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_input(network, gen, pi) { + (void) st_insert(leaves, (char *) pi, (char *) count++); + } + +Of course, you will want to use a more sophisticated ordering, such as one of +those provided by the Ordering package. A BDD constructed using a leaves +table of primary inputs, such as that above, is referred to as a "global BDD". + + +Summary ----------------------------------------------------------------------- + + ntbdd_at_node() + ntbdd_bdd_single_to_network() + ntbdd_bdd_array_to_network() + ntbdd_end_manager() + ntbdd_free_at_node() + ntbdd_node_to_bdd() + ntbdd_node_to_local_bdd() + ntbdd_set_at_node() + ntbdd_start_manager() + ntbdd_verify_network() + + +Description of Functions ------------------------------------------------------ + +bdd_t * +ntbdd_at_node(node) +node_t *node; + + Returns the BDD formula stored at node. + + +network_t * +ntbdd_bdd_array_to_network(fn_array, po_names, var_names) +array_t *fn_array; /* of (bdd_t *) */ +array_t *po_names; /* of (char *) */ +array_t *var_names; /* of (char *) */ + + Builds a multi-output network, where each primary output represents + one of the BDD formulas in `fn_array'. The primary output for the ith + formula in the array `fn_array' is assigned the ith name in the array + `po_names'. The ith name in the array `var_names' is given to the ith + variable in the BDD. The network is built as follows: for each vertex + in the BDD, a SIS node implementing a MUX is added to the network. + Thus, the structure of the BDD is isomorphic to the structure of the + network. + + +network_t * +ntbdd_bdd_single_to_network(fn, po_name, var_names) +bdd_t *fn; +char *po_name; +array_t *var_names; /* of (char *) */ + + Packages each of `fn' and `po_name' into arrays of length one, and then + calls ntbdd_bdd_array_to_network. + + +void +ntbdd_end_manager(manager) +bdd_manager *manager; + + Frees the manager allocated by ntbdd_start_manager. Also frees all + the BDD formulas of that manager stored in any node of any network, + using ntbdd_set_at_node, during the lifetime of the manager. + Furthermore, all BDD formulas stored at any nodes by ntbdd_node_to_bdd + are also freed by ntbdd_end_manager. + + +void +ntbdd_free_at_node(node) +node_t *node; + + Frees the BDD formula for node. Note that when a node is freed using + node_free, the BDD formula for that node is automatically freed using + a node demon. Unlike ntbdd_node_to_bdd, this routine is not called + recursively. + + +bdd_t * +ntbdd_node_to_bdd(node, manager, leaves) +node_t *node; +bdd_manager *manager; +st_table *leaves; + + Builds the BDD for node in terms of the node variables given in the + leaves table. A pointer to the constructed BDD is stored at the node, + and the same pointer is returned by the function. The BDD for node is + built recursively from the BDD's of its immediate fanins. Thus, while + constructing the BDD for node, any node in the intersection of the + transitive fanin of node and the union of the transitive fanouts of the + nodes in leaves, will be visited. If a visited node already has a BDD, + then the BDD will be used if it is in `manager'; if it is not in + `manager', it will be freed and a new BDD will be created. If a visited + node does not have a BDD, then a new BDD will be contructed for the node, + and stored at the node. For a leaf node, a single variable BDD will be + created for the node, and stored at the node, regardless of what BDD is + already present at the node. + + The leaves table is intended to be a cutset of the network. Let us + say we are building the BDD for a particular node x, and the leaves + table contains nodes a, b, c, and d. If there is a path from x to c + through d, then the recursion will stop at d. If there exists at least + one path from x to c which does not pass through another leaf, then c + will be in the BDD. + +bdd_t * +ntbdd_node_to_local_bdd(node, manager, leaves) +node_t *node; +bdd_manager *manager; +st_table *leaves; + + Builds the BDD for node in terms of its immediate fanin. Assumes that + leaves contains the fanins of node. No BDD formula is stored in any + node by this routine; it is the user's responsibility to maintain the + BDD formula returned by this routine. + +void +ntbdd_set_at_node(node, bdd) +bdd_t *bdd; +node_t *node; + + Sets the bdd field of `node' to the BDD formula `bdd'. If there is + already a BDD formula at `node', then the old formula is freed. When + you want to free the new BDD formula, you must do so using + ntbdd_free_at_node. + +bdd_manager * +ntbdd_start_manager(num_vars) +int num_vars; + + Creates a manager and initializes data structures for network + interaction. num_vars is the number of variables allowed in the + manager. It is always possible to increase the number of variables in + this manager by calling bdd_create_variable. + +int +ntbdd_verify_network(network1, network2, order_method, verify_method) +network_t *network1; +network_t *network2; +ntbdd_order_method_t order_method; +ntbdd_verify_method_t verify_method; + + Verifies that two networks are equivalent. Returns TRUE if they are + equivalent, returns FALSE if they are not equivalent. The primary + inputs and primary outputs of the two networks must match name for + name. Creates BDD's for both networks, and then checks, output by + output, if the BDD's are equivalent. A strong canonical form is used + for the BDD's, so once the BDD's are constructed, the test for + equivalence is just a pointer comparison. + + Two different ordering methods can be specified. DFS_ORDER uses an + ordering based on depth first search and the level of a node. See S. + Malik, et. al. "Logic Verification using Binary Decision Diagrams in a + Logic Synthesis Environment," ICCAD, 1988. RANDOM_ORDER uses a random + ordering. + + Two different verifying methods can be specified. ONE_AT_A_TIME may + use a different variable ordering for each primary output. + ALL_TOGETHER uses the same variable ordering for all the primary + outputs. ALL_TOGETHER is usually faster, but ONE_AT_A_TIME can verify + some large networks which ALL_TOGETHER cannot handle. See S. Malik, + et. al. "Logic Verification using Binary Decision Diagrams in a Logic + Synthesis Environment," ICCAD, 1988. + + +Obsolete Functions from Previous Versions ------------------------------------- + +bdd_constant(phase, order_list) + Use the bdd_one and bdd_zero functions from the BDD package. + +bdd_construct(node, order_list, locality) + Use ntbdd_node_to_bdd for global BDD's, and ntbdd_node_to_local_bdd for + local BDD's. + +bdd_do_construct(node, mgr, locality) + Use ntbdd_node_to_bdd for global BDD's, and ntbdd_node_to_local_bdd for + local BDD's. + +bdd_init(network, order_list) + Use ntbdd_start_manager. + +bdd_ordered_create_bdd(node, manager, node_list, leaves) + Use ntbdd_node_to_bdd for global BDD's, and ntbdd_node_to_local_bdd for + local BDD's. + +bdd_order_nodes(roots, leaves, type) + Use an ordering routine from the Ordering package. + +bdd_print_as_eqn(fn, network) + Use ntbdd_bdd_to_network, then print network. + +bdd_print_from_leaves(fn, leaves) + Use ntbdd_bdd_to_network, then print network. + +bdd_quit(mgr) + Use ntbdd_end_manager. + +bdd_verify(net1, net2) + Use ntbdd_verify_network. + +ntbdd_bdd_to_network(fn, var_names) + Use ntbdd_bdd_single_to_network(fn, "bdd_out", var_names). + +order_nodes(node_vec, pi_only) + Use an ordering routine from the Ordering package. + + +Function Name Changes from Previous Versions ---------------------------------- + +bdd_at_node ==> ntbdd_at_node + +bdd_build ==> ntbdd_bdd_to_network + +bdd_create_bdd ==> ntbdd_node_to_bdd + +bdd_create_local_bdd ==> ntbdd_node_to_local_bdd + +bdd_node_free ==> ntbdd_free_at_node + +bdd_set_at_node ==> ntbdd_set_at_node + +node_bdd ==> ntbdd_at_node + +ntbdd_init ==> ntbdd_start_manager + +ntbdd_quit ==> ntbdd_end_manager + +ntbdd_verify ==> ntbdd_verify_network + + + + diff --git a/sis/ntbdd/ntbdd.h b/sis/ntbdd/ntbdd.h new file mode 100644 index 0000000..5d48cbd --- /dev/null +++ b/sis/ntbdd/ntbdd.h @@ -0,0 +1,70 @@ +#ifndef NTBDD_H /* { */ +#define NTBDD_H + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/ntbdd/ntbdd.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * $Log: ntbdd.h,v $ + * Revision 1.1.1.1 2004/02/07 10:14:28 pchong + * imported + * + * Revision 1.6 1993/05/28 23:18:55 sis + * Aesthetic changes to prototypes. + * + * Revision 1.5 1993/02/25 01:05:23 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.5 1993/02/25 01:05:23 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.7 1993/01/14 01:34:01 shiple + * Added EXTERNs for ntbdd_bdd_single_to_network and ntbdd_bdd_array_to_network. + * Removed EXTERN for ntbdd_bdd_to_network. + * + * Revision 1.6 1991/06/27 09:14:12 shiple + * Moved enum declaration before prototype declaration so new gcc + * compiler does not complain. + * + * Revision 1.5 91/05/01 17:44:40 shiple + * convert to new declaration format using EXTERN and ARGS + * + * Revision 1.4 91/04/26 17:57:55 shiple + * removed declaration of ordering routines + * + * Revision 1.3 91/03/31 23:06:50 shiple + * eliminated obsolete functions; renamed remaining functions; for Version 3.0 + * + * Revision 1.2 91/03/28 16:04:37 shiple + * removed extern declaration for bdd_order_nodes, which was placed there + * inadvertently + * + * Revision 1.1 91/03/27 14:12:37 shiple + * Initial revision + * + * + */ + +/* + * Verification methods + */ +typedef enum {ONE_AT_A_TIME, ALL_TOGETHER} ntbdd_verify_method_t; + +/* + * Utilities + */ +EXTERN bdd_t *ntbdd_at_node ARGS((node_t *)); +EXTERN network_t *ntbdd_bdd_single_to_network ARGS((bdd_t *, char *, array_t *)); +EXTERN network_t *ntbdd_bdd_array_to_network ARGS((array_t *, array_t *, array_t *)); +EXTERN void ntbdd_end_manager ARGS((bdd_manager *)); +EXTERN void ntbdd_free_at_node ARGS((node_t *)); +EXTERN bdd_t *ntbdd_node_to_bdd ARGS((node_t *, bdd_manager *, st_table *)); +EXTERN bdd_t *ntbdd_node_to_local_bdd ARGS((node_t *, bdd_manager *, st_table *)); +EXTERN void ntbdd_set_at_node ARGS((node_t *, bdd_t *)); +EXTERN bdd_manager *ntbdd_start_manager ARGS((int)); +EXTERN int ntbdd_verify_network ARGS((network_t *, network_t *, order_method_t, ntbdd_verify_method_t)); + +#endif /* } */ diff --git a/sis/ntbdd/ntbdd_int.h b/sis/ntbdd/ntbdd_int.h new file mode 100644 index 0000000..56d6a30 --- /dev/null +++ b/sis/ntbdd/ntbdd_int.h @@ -0,0 +1,64 @@ +#ifndef NTBDD_INT_H /* { */ +#define NTBDD_INT_H + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/ntbdd/ntbdd_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * $Log: ntbdd_int.h,v $ + * Revision 1.1.1.1 2004/02/07 10:14:28 pchong + * imported + * + * Revision 1.4 1993/06/04 19:42:26 sis + * *** empty log message *** + * + * Revision 1.4 1993/06/04 15:40:19 shiple + * Removed NTBDD and NTBDD_HOOK macros. + * + * Revision 1.3 1991/03/31 23:07:30 shiple + * cleanup for Version 3.0 + * + * Revision 1.2 91/03/28 16:05:34 shiple + * removed include of bdd_int.h because wanted it to be explicit in each + * of the .c files which use it; someday, none of the files should depend + * on bdd_int.h, since this violates the BDD interface + * + * Revision 1.1 91/03/27 14:13:20 shiple + * Initial revision + * + * + */ + +/* + * Stuff hooked on the bdd manager so that everything is + * freed at the appropriate point. + */ +typedef struct { + network_t *last_network; + st_table *network_table; +} ntbdd_t; + +/* + * Macro to access bdd_t's at nodes. + */ +#define BDD(node) ((bdd_t *) (node)->bdd) +#define BDD_SET(node,value) ((node)->bdd = (char *) (value)) + +/* + * Stuff internal to the ntbdd package. + */ +extern void bdd_alloc_demon(/* node_t *node */); +extern void bdd_free_demon(/* node_t *node; */); + +/* + * enum type to denote what type of BDD is being created: LOCAL + * means just in terms of the node's immediate fanin; GLOBAL + * means in terms of the nodes in the leaves table. + */ +typedef enum {LOCAL, GLOBAL} ntbdd_type_t; + +#endif /* } */ + diff --git a/sis/ntbdd/verify_ntwk.c b/sis/ntbdd/verify_ntwk.c new file mode 100644 index 0000000..dfe4e15 --- /dev/null +++ b/sis/ntbdd/verify_ntwk.c @@ -0,0 +1,477 @@ +#include "sis.h" +#include "ntbdd_int.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/ntbdd/verify_ntwk.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:28 $ + * $Log: verify_ntwk.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:28 pchong + * imported + * + * Revision 1.11 1993/07/19 17:39:54 shiple + * Added static declarations for verify_one_at_a_time and verify_all_together. + * + * Revision 1.10 1993/06/04 15:40:19 shiple + * Removed unnecessary void casts of functions calls. + * + * Revision 1.9 1993/01/16 01:18:07 shiple + * Fixed bug in verify_one_at_a_time. Bug caused some outputs to be verified multiple times. + * + * Revision 1.8 1993/01/11 23:41:06 shiple + * Made change to calls to st_lookup for DEC Alpha compatibility. + * + * Revision 1.7 1992/04/01 22:59:09 shiple + * Modified the functions ntbdd_verify_network, verify_all_together, and + * report_error so that logically equivalent networks are not required to + * have identically matching input sets. + * Modified report_error so that when it prints out an error vector, it + * gives the names of the inputs, as well as their values. + * + * Revision 1.6 1992/02/08 00:10:06 shiple + * Modified ntbdd_verify_network to write error messages to error_string, + * instead of to miserr. + * + * Revision 1.5 91/06/16 16:00:20 shiple + * Fixed a memory leak in ntbdd_verify_network and one in verify_all_together. + * Modified verify_all_together and report_error to write error messages to + * error_string, instead of to miserr. + * + * Revision 1.4 91/04/26 17:58:21 shiple + * changed bdd_sharad_order to order_dfs, bdd_random_order to order_random, + * and ntbdd_order_method_t to order_method_t + * + * Revision 1.3 91/03/31 23:07:54 shiple + * small revisions to use Version 3.0 functions + * + * Revision 1.2 91/03/28 17:41:00 shiple + * in function verify_all_together, add a patch to handle case where + * a primary input does not fanout + * + * Revision 1.1 91/03/20 14:29:23 shiple + * Initial revision + * + */ + +static int same_orderp(); +static void report_error(); +static int verify_one_at_a_time(); +static int verify_all_together(); + +/* + * ntbdd_verify_network - verify that the two networks are the same + * + * Convert both networks into a bdd and then see if the + * bdd's for both networks are equivalent; bdd's are a + * canonical form, so this comparison is easy. + * + * return {TRUE, FALSE} on {is, is not}. + */ +int ntbdd_verify_network(net1, net2, order_method, verify_method) +network_t *net1; +network_t *net2; +order_method_t order_method; +ntbdd_verify_method_t verify_method; +{ + int i; + lsGen gen; + int state; + node_t *po, *ipo, *pi; + st_table *leaves1, *leaves2; + array_t *po_list1, *po_list2, *pi_list1, *pi_list2; + char errmsg[128]; + + /* + * If the two networks are exactly the same + * then return TRUE directly. + */ + if (net1 == net2) return (TRUE); + + /* + * Clearly, if one is nil and the other one is + * not, then they are not the same. + */ + if (net1 == NIL(network_t) || net2 == NIL(network_t)) return (FALSE); + + /* + * Create an array for both primary-output + * sets and fill those output sets. + */ + po_list1 = array_alloc(node_t *, 0); + foreach_primary_output(net1, gen, po) { + array_insert_last(node_t *, po_list1, po); + } + + po_list2 = array_alloc(node_t *, 0); + foreach_primary_output(net2, gen, po) { + array_insert_last(node_t *, po_list2, po); + } + + /* + * If they don't have the same output sets in the first place, don't even bother. + */ + if (! same_orderp(po_list1, &po_list2)) { + (void) sprintf(errmsg, "The name/number of outputs of the two networks don't match.\n"); + error_append(errmsg); + array_free(po_list1); + array_free(po_list2); + return (FALSE); + } + + /* + * Take the nodes feeding the PRIMARY_OUTPUTS. + */ + for(i = 0; i < array_n(po_list1); i++) { + po = array_fetch(node_t *, po_list1, i); + ipo = node_get_fanin(po, 0); + array_insert(node_t *, po_list1, i, ipo); + + po = array_fetch(node_t *, po_list2, i); + ipo = node_get_fanin(po, 0); + array_insert(node_t *, po_list2, i, ipo); + } + + pi_list1 = array_alloc(node_t *, 0); + leaves1 = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_input(net1, gen, pi) { + st_insert(leaves1, (char *) pi, (char *) -1); + array_insert_last(node_t *, pi_list1, pi); + } + pi_list2 = array_alloc(node_t *, 0); + leaves2 = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_input(net2, gen, pi) { + st_insert(leaves2, (char *) pi, (char *) -1); + array_insert_last(node_t *, pi_list2, pi); + } + + if (verify_method == ONE_AT_A_TIME) { + state = verify_one_at_a_time(po_list1, pi_list1, leaves1, po_list2, pi_list2, leaves2, order_method); + } else if (verify_method == ALL_TOGETHER) { + state = verify_all_together(po_list1, pi_list1, leaves1, po_list2, pi_list2, leaves2, order_method); + } else { + fail("ntbdd_verify_network: unknown verify method"); + } + + array_free(pi_list1); + array_free(pi_list2); + array_free(po_list1); + array_free(po_list2); + st_free_table(leaves1); + st_free_table(leaves2); + + return (state); +} + +/* + * Does the verification one output at a time, using different orderings each time. + */ +static int verify_one_at_a_time(po_list1, pi_list1, leaves1, po_list2, pi_list2, leaves2, order_method) +array_t *po_list1; +array_t *pi_list1; +st_table *leaves1; +array_t *po_list2; +array_t *pi_list2; +st_table *leaves2; +order_method_t order_method; +{ + int i; + int state; + node_t *po1, *po2; + array_t *single_po1, *single_po2; + + for (i = 0; i < array_n(po_list1); i++) { + single_po1 = array_alloc(node_t *, 0); + single_po2 = array_alloc(node_t *, 0); + po1 = array_fetch(node_t *, po_list1, i); + po2 = array_fetch(node_t *, po_list2, i); + array_insert_last(node_t *, single_po1, po1); + array_insert_last(node_t *, single_po2, po2); + /* + * Note that verify_all_together creates and frees a BDD manager on each call. + */ + state = verify_all_together(single_po1, pi_list1, leaves1, single_po2, pi_list2, leaves2, order_method); + if (state == FALSE) { + array_free(single_po1); + array_free(single_po2); + return FALSE; + } + array_free(single_po1); + array_free(single_po2); + } + return TRUE; +} + +/* + * A node from pi_list1, and a node with the same name in pi_list2, must hash to the same variable ID + * in leaves1 and leaves2, respectively. This is so that BDD's f1 and f2 are built using exactly + * the same BDD variables. + * + * Note: Only the first difference in outputs is found and reported. TODO: report all differences? + */ +static int verify_all_together(po_list1, pi_list1, leaves1, po_list2, pi_list2, leaves2, order_method) +array_t *po_list1; +array_t *pi_list1; +st_table *leaves1; +array_t *po_list2; +array_t *pi_list2; +st_table *leaves2; +order_method_t order_method; +{ + int i, j; + int state; + int index; + bdd_t *f1, *f2; + node_t *n1, *n2; + node_t *pi1, *pi2; + array_t *node_list1; + bdd_manager *manager; + int max_index; + int match_found; + + /* + * Can't order both networks, because if orders differ, we won't be able + * to do anything with the BDDs. Order the first and derive the order for the second. + */ + if (order_method == DFS_ORDER) { + node_list1 = order_dfs(po_list1, leaves1, 0); + array_free(node_list1); /* node_list1 not needed */ + } else if (order_method == RANDOM_ORDER) { + node_list1 = order_random(po_list1, leaves1, 0); + /* order_random always returns NIL(array_t); thus, no need to array_free */ + } else { + fail("verify_all_together: unknown order method"); + } + + /* + * We want to elegantly handle the case where a PI does not fanout. + * Thus, first find the max index assigned to an input. Only those + * inputs which can be reached from po_list1 will be assigned an index + * greater than -1. Note that BDD variable IDs start at 0. + */ + max_index = 0; + for (i = 0; i < array_n(pi_list1); i++) { + pi1 = array_fetch(node_t *, pi_list1, i); + assert(st_lookup_int(leaves1, (char *) pi1, &index)); + if (index > max_index) { + max_index = index; + } + } + max_index++; + + for (i = 0; i < array_n(pi_list1); i++) { + pi1 = array_fetch(node_t *, pi_list1, i); + assert(st_lookup_int(leaves1, (char *) pi1, &index)); + + /* + * Assign an index to those inputs which could not be reached + * from the POs. After assignment, increment max_index. + */ + if (index < 0) { + index = max_index++; + st_insert(leaves1, (char *) pi1, (char *) index); + } + } + + /* + * Based on the variable ordering for nodes in leaves1, assign a variable to the nodes + * in leaves2. Any node in pi_list2 which matches by name a node in pi_list1, is assigned + * the same ordering value. This is so that the BDD package treats the two nodes as if they + * were the same. If a match is not found for a node in pi_list2, then assign the node + * the next index value. + * Note that even if the supports of network1 and network2 are disjoint, the functions + * may still be equal (e.g. if they are the same constant function). + */ + for (i = 0; i < array_n(pi_list2); i++) { + pi2 = array_fetch(node_t *, pi_list2, i); + match_found = FALSE; + for (j = 0; j < array_n(pi_list1); j++) { + pi1 = array_fetch(node_t *, pi_list1, j); + if (strcmp(node_long_name(pi2), node_long_name(pi1)) == 0) { + /* + * A name match is found. Assign pi2 the same index as pi1. + */ + match_found = TRUE; + assert(st_lookup_int(leaves1, (char *) pi1, &index)); + st_insert(leaves2, (char *) pi2, (char *) index); + break; + } + } + + /* + * If no match was found, assign pi2 the next index value. If a match was found, then + * reset the match_found flag. + * TODO: if ability to insert variables into order becomes available, then try to + * interleave variables in network2 not in network1 into variable ordering. Any change + * to the variable ordering here should be reflected in the function report_error. + */ + if (match_found == FALSE) { + index = max_index++; + st_insert(leaves2, (char *) pi2, (char *) index); + } else { + match_found = FALSE; + } + } + + /* + * Both networks will be built in the same manager. The important thing to remember is + * that if 2 leaves have the same name, then they are considered equivalent in the manager, + * because we assigned them the same variable ID. + */ + manager = ntbdd_start_manager(max_index); + state = TRUE; + for (i = 0; i < array_n(po_list1); i++) { + n1 = array_fetch(node_t *, po_list1, i); + n2 = array_fetch(node_t *, po_list2, i); + f1 = ntbdd_node_to_bdd(n1, manager, leaves1); + f2 = ntbdd_node_to_bdd(n2, manager, leaves2); + if (! bdd_equal(f1, f2)) { + report_error(pi_list1, leaves1, pi_list2, leaves2, f1, f2, n1); + state = FALSE; + } + ntbdd_free_at_node(n1); /* frees f1 & f2 */ + ntbdd_free_at_node(n2); + if (state == FALSE) break; + } + ntbdd_end_manager(manager); + return state; +} + + +/* + * Orders the nodes in list2 so that the corresponding nodes in both lists + * have the same names. + */ +static int +same_orderp(list1, list2p) +array_t *list1; +array_t **list2p; /* return */ +{ + int i; + int index; + char *name; + node_t *node; + array_t *new_list; + st_table *name_table; + array_t *list2 = *list2p; + + /* + * Both arrays must have the same number of elements as a necessary condition + * that they are the same. + */ + if (array_n(list1) != array_n(list2)) return FALSE; + + /* + * Hash each node name of list1 into its array position in list1. + */ + name_table = st_init_table(strcmp, st_strhash); + for (i = 0; i < array_n(list1); i++) { + node = array_fetch(node_t *, list1, i); + st_insert(name_table, node_long_name(node), (char *) i); + } + + /* + * If node name from list2 is found in name table, then insert node into + * new_list in the same position that it exists in list1. Assumes that + * 2 nodes in list2 don't have the same name. + */ + new_list = array_alloc(node_t *, 0); + for (i = 0; i < array_n(list2); i++) { + node = array_fetch(node_t *, list2, i); + name = node_long_name(node); + if (st_lookup_int(name_table, name, &index)) { + array_insert(node_t *, new_list, index, node); + } else { + st_free_table(name_table); + array_free(new_list); + return FALSE; + } + } + st_free_table(name_table); + array_free(list2); + *list2p = new_list; + return (TRUE); +} + +static void report_error(pi_list1, leaves1, pi_list2, leaves2, f1, f2, bad_output) +array_t *pi_list1; +st_table *leaves1; +array_t *pi_list2; +st_table *leaves2; +bdd_t *f1; +bdd_t *f2; +node_t *bad_output; +{ + int i; + int index; + int value; + node_t *pi; + bdd_gen *gen; + array_t *cube; + char errmsg[1024]; + int max_index = -1; + + /* + * Find the differences. If there are no differences, then there is a program error. + */ + bdd_t *diff = bdd_xor(f1, f2); + assert(! bdd_is_tautology(diff, 0)); + + gen = bdd_first_cube(diff, &cube); + + (void) sprintf(errmsg, "Networks differ on (at least) primary output %s\n", node_name(bad_output)); + error_append(errmsg); + (void) sprintf(errmsg, "Incorrect input is:\n"); + error_append(errmsg); + + /* + * First extract the variable value from "cube" for each variables in pi_list1. + */ + for (i = 0; i < array_n(pi_list1); i++) { + pi = array_fetch(node_t *, pi_list1, i); + assert(st_lookup_int(leaves1, (char *) pi, &index)); + if (index > max_index) { + max_index = index; + } + value = array_fetch(int, cube, index); + if (value == 2) { + value = 0; + } + (void) sprintf(errmsg, "%d %s\n", value, node_name(pi)); + error_append(errmsg); + } + + /* + * For any node name in pi_list2 that is not in pi_list1, extract the variable value from "cube" for + * that node. Since all such nodes have a higher index value than any nodes in pi_list1, we can easily + * detect such nodes: their index value is higher than the max index value in pi_list1. + */ + for (i = 0; i < array_n(pi_list2); i++) { + pi = array_fetch(node_t *, pi_list2, i); + assert(st_lookup_int(leaves2, (char *) pi, &index)); + /* + * If index is less than or equal to max_index, then this variable was already processed in pi_list1 + * above. + */ + if (index <= max_index) { + continue; + } + value = array_fetch(int, cube, index); + if (value == 2) { + value = 0; + } + (void) sprintf(errmsg, "%d %s\n", value, node_name(pi)); + error_append(errmsg); + } + + /* + * Do not free the generator before the last use of "cube" + * because "cube" points somewhere in the generator. + */ + bdd_gen_free(gen); + (void) sprintf(errmsg, "\n"); + error_append(errmsg); +} + diff --git a/sis/octio/Makefile.am b/sis/octio/Makefile.am new file mode 100644 index 0000000..88dab16 --- /dev/null +++ b/sis/octio/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = farray.h octio.c octio.doc octio.h octread.c octwrite.c diff --git a/sis/octio/Makefile.in b/sis/octio/Makefile.in new file mode 100644 index 0000000..0018973 --- /dev/null +++ b/sis/octio/Makefile.in @@ -0,0 +1,285 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/octio +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +EXTRA_DIST = farray.h octio.c octio.doc octio.h octread.c octwrite.c +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/octio/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/octio/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/octio/farray.h b/sis/octio/farray.h new file mode 100644 index 0000000..684ade2 --- /dev/null +++ b/sis/octio/farray.h @@ -0,0 +1,24 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/octio/farray.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#ifndef F_ARRAY_H +#define F_ARRAY_H + +#define f_array_insert(type, a, i, datum) { \ + int array_i;\ + (array_i = (i), \ + array_i >= (a)->n_size ? array_resize(a, array_i + 1) : 0,\ + array_i >= (a)->num ? (a)->num = array_i + 1 : 0,\ + *((type *) ((a)->space + array_i * sizeof(type))) = datum);\ + } + +#define f_array_insert_last(type, array, datum) \ + f_array_insert(type, array, (array)->num, datum) + +#endif /* F_ARRAY_H */ diff --git a/sis/octio/octio.c b/sis/octio/octio.c new file mode 100644 index 0000000..d4c42ea --- /dev/null +++ b/sis/octio/octio.c @@ -0,0 +1,37 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/octio/octio.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#ifdef OCT +#include "copyright.h" +#endif +#include "sis.h" +#include "octio.h" + +/* + * called when the program starts up + */ +init_octio() +{ +#ifdef OCT + com_add_command("write_oct", external_write_oct, 0); + com_add_command("read_oct", external_read_oct, 1); +#endif +} + +/* + * called just before the program terminates + */ +end_octio() +{ +} + + + + + diff --git a/sis/octio/octio.doc b/sis/octio/octio.doc new file mode 100644 index 0000000..126800f --- /dev/null +++ b/sis/octio/octio.doc @@ -0,0 +1,65 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/octio/octio.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +/* Exported interface --- present in octio.h */ +int +external_read_oct(networkp, argc, argv) +network_t ** networkp; +int argc; +char** argv; + This routine fills in *networkp with the network read in. + This routine packages the interface routine read_oct() described + below. The legal values for argc and argv are --- + + argc argv[0] argv[1] argv[2] internal routine + ---------------------------------------------------------------- + 2 read_oct cell:view ||| read_oct(facet, 0) + 3 read_oct -m cell:view ||| read_oct(facet, 1) + + +int +external_write_oct(networkp, argc, argv) +network_t ** networkp; +int argc; +char** argv; + This routine writes out *networkp into the specified "cell:view" + This routine packages the interface routine write_oct() described + below. The facet "cell:view" should be writeable by the user. + The legal values for argc and argv are --- + + argc argv[0] argv[1] + -------------------------- + 2 write_oct cell:view + + +/* Internal interface --- not present in octio.h */ +int +write_oct(network, facet) +network_t *network; +octObject *facet; + Write a network into an OCT facet. + The routine returns 0 on error and 1 for success. On errors an + appropriate error message will be placed in the error buffer. + +network_t * +read_oct(facet, mappedp) +octObject *facet; +int mappedp; + Read an Oct facet that contains a logic network and + build a network in SIS that represents it. In case mapped is 0, + only instances with CELLTYPE = COMBINATIONAL will be processed. + The logic function for a gate is obtained as follows, first the + library is checked if present, then the instance is checked for + a LOGIC-FUNCTION attached to it (for combinational cells) otherwise + the master is checked for the relevant information. + If a library has been read in and mappedp is 1, this information + will be maintained on read in. On error conditions such as illegal + logic function an appropriate error message will be placed in the + error buffer and NIL(network_t) will be returned. + diff --git a/sis/octio/octio.h b/sis/octio/octio.h new file mode 100644 index 0000000..da2ceb5 --- /dev/null +++ b/sis/octio/octio.h @@ -0,0 +1,19 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/octio/octio.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#ifndef OCTIO_H +#define OCTIO_H + +#define SIS_PKG_NAME "oct/sis" + +EXTERN int external_read_oct ARGS((network_t **,int,char**)); +EXTERN int external_write_oct ARGS((network_t **,int,char**)); + +extern char *optProgName; +#endif diff --git a/sis/octio/octread.c b/sis/octio/octread.c new file mode 100644 index 0000000..e283bf0 --- /dev/null +++ b/sis/octio/octread.c @@ -0,0 +1,1056 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/octio/octread.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#ifdef OCT +#define SEQUENTIAL + +/* + * routine for reading MISII logic networks (mapped and unmapped) from + * Oct facets + * Extended to also read mapped sequential circuits (Andrea Casotto, K.J.Singh) + * NOTE: no facility yet (5/4/91) to read unmapped sequential circuits !!! + */ +#include "copyright.h" +#include "port.h" +#undef assert +#include "sis.h" +#include "st.h" +#undef REALLOC +#undef FREE +#include "errtrap.h" +#include "oct.h" +#include "oh.h" +#include "octio.h" + +#ifdef SIS +extern void read_change_madeup_name(); /* Should be in io.h */ +static void oct_read_set_latch(); +#endif /* SIS */ +extern node_t *read_find_or_create_node(); /* Should be in io.h */ + +#define node_oct_name(node) (node)->name + +#define STREQ(a, b) (strcmp(a, b) == 0) + +#define OCTMISCHECK(fnc) \ + { \ + octStatus octmischeck_status; \ + octmischeck_status = fnc; \ + if (octmischeck_status < OCT_OK) { \ + errRaise(SIS_PKG_NAME, octmischeck_status, octErrorString()); \ + } \ + } + + +static void +uniqNames(container, mask) +octObject *container; +octObjectMask mask; +{ + octObject obj; + octGenerator gen; + octStatus status; + char *name, dummyname[1024]; + st_table *name_table; + int cnt, count; + + name_table = st_init_table(strcmp, st_strhash); + cnt = 0; + + OH_ASSERT(octInitGenContents(container, mask, &gen)); + while ((status = octGenerate(&gen, &obj)) == OCT_OK) { + name = ohGetName(&obj); + if (name == NIL(char)) { + errRaise(SIS_PKG_NAME, OCT_ERROR, "ohGetName returned NIL"); + } + if (name[0] == '\0') { + /* make sure the name is not empty */ + (void) sprintf(dummyname, "%s-%d", ohTypeName(&obj), cnt++); + OH_ASSERT(ohPutName(&obj, dummyname)); + OH_ASSERT(octModify(&obj)); + OH_ASSERT(ohGetById(&obj, obj.objectId)); + name = ohGetName(&obj); + } + if (st_lookup(name_table, name, NIL(char *))) { + /* loop until we can generate a unique name */ + count = 2; + do { + (void) sprintf(dummyname, "%s-{%d}", name, count++); + } while (st_lookup(name_table, dummyname, NIL(char *))); + + /* change the objects name */ + OH_ASSERT(ohPutName(&obj, dummyname)); + OH_ASSERT(octModify(&obj)); + OH_ASSERT(ohGetById(&obj, obj.objectId)); + name = ohGetName(&obj); + } + + (void) st_insert(name_table, name, NIL(char)); + } + OH_ASSERT(status); + (void) st_free_table(name_table); + return; +} + + +static node_t * +build_new_node(node, network, instance) +node_t *node; +network_t *network; +octObject *instance; +{ + node_t *result, *temp, *oldfanin, *newfanin, *nodeliteral, *and, *or; + node_cube_t cube; + node_literal_t literal; + int i, j; + octObject term, net; + octGenerator gen; + st_table *table; + char *netname; + octStatus status; + + /* build up terminal/net table */ + table = st_init_table(strcmp, st_strhash); + OH_ASSERT(octInitGenContents(instance, OCT_TERM_MASK, &gen)); + while (octGenerate(&gen, &term) == OCT_OK) { + status = octGenFirstContainer(&term, OCT_NET_MASK, &net); + if (status == OCT_OK) { + (void) st_insert(table, term.contents.term.name, net.contents.net.name); + } + if (status < OCT_OK) { + errRaise(SIS_PKG_NAME, status, + "oct error (%s)", + octErrorString()); + } + } + + result = node_constant(0); + + for (i = node_num_cube(node) - 1; i >= 0; i--) { + cube = node_get_cube(node, i); + temp = node_constant(1); + foreach_fanin(node, j, oldfanin) { + literal = node_get_literal(cube, j); + + if (literal == TWO) { + continue; + } + + /* get the net attached to the terminal with the name of the oldfanin */ + if (!st_lookup(table, node_oct_name(oldfanin), &netname)) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "FATAL: missing connection to terminal %s on %s\n", + node_oct_name(oldfanin), ohFormatName(instance)); + } + newfanin = read_find_or_create_node(network, netname); + + nodeliteral = node_literal(newfanin, ((literal == ZERO) ? 0 : 1)); + and = node_and(temp, nodeliteral); + node_free(temp); /* garbage collection */ + node_free(nodeliteral); + temp = and; + } + or = node_or(result, temp); + node_free(result); + node_free(temp); + result = or; + } + + st_free_table(table); + return(result); +} + +#ifdef SIS +/* + + OCT structure: + + facet->bag(SIS_CLOCKS)|->prop(CYCLETIME) + |->bag(CLOCK_EVENTS)|->prop(TIME) + | |->bag(EVENT)|->prop(DESCRIPTION) + | | |->prop(MIN) + | | |->prop(MAX) + | | + | |->bag(EVENT)|->prop(DESCRIPTION) + | |->prop(MIN) + | |->prop(MAX) + | + |->bag(CLOCK_EVENTS)|->prop(TIME) + |->bag(EVENT)|->prop(DESCRIPTION) + | |->prop(MIN) + | |->prop(MAX) + | + |->bag(EVENT)|->prop(DESCRIPTION) + |->prop(MIN) + |->prop(MAX) + +*/ + +static void +read_oct_add_clock_event(network, eventBag ) + network_t *network; + octObject *eventBag; +{ + int first = 1; + clock_edge_t first_edge, edge; + octObject bag, prop; + octGenerator gen; + char *name; + + double nominal; + if (ohGetByPropName( eventBag, &prop, "TIME" ) == OCT_OK){ + nominal = prop.contents.prop.value.real; + } else { + nominal = CLOCK_NOT_SET; + } + + octInitGenContents( eventBag, OCT_BAG_MASK, &gen ); + while ( octGenerate( &gen, &bag ) == OCT_OK ) { + char *desc; + double min, max; + + if (ohGetByPropName( &bag, &prop, "DESCRIPTION" ) == OCT_OK){ + desc = prop.contents.prop.value.string; + } else { + errRaise("oct_read", 1, "No specification of description in clock_event"); + } + if (ohGetByPropName( &bag, &prop, "MIN" ) == OCT_OK){ + min = prop.contents.prop.value.real; + } else { + min = CLOCK_NOT_SET; + } + if (ohGetByPropName( &bag, &prop, "MAX" ) == OCT_OK){ + max = prop.contents.prop.value.real; + } else { + max = CLOCK_NOT_SET; + } + + if ( strlen( desc ) < 2 || ( *desc != 'r' && *desc != 'f') ) + errRaise( "oct_read", 1, "Illegal transition description %s", desc ); + + name = desc + 2; + edge.transition = ( *desc=='r') ? RISE_TRANSITION : FALL_TRANSITION; + edge.clock = clock_get_by_name(network, name ); + if ( edge.clock == 0 ) { + errRaise( "oct_read", 1,"clock %s not found in clock_list", name); + } + + (void)clock_set_parameter(edge, CLOCK_NOMINAL_POSITION, nominal); + (void)clock_set_parameter(edge, CLOCK_LOWER_RANGE, min); + (void)clock_set_parameter(edge, CLOCK_UPPER_RANGE, max); + + /* + (void)fprintf(sisout, "Time %lf %s %lf %lf\n", nominal, desc, min, max ); + */ + + if (first) { + first = 0; + first_edge.transition = edge.transition; + first_edge.clock = edge.clock; + } else { + (void) clock_add_dependency(first_edge, edge); + } + } +} + + +/* + * Looks at a net with NETTYPE "CLCOK" and gets the formal terminal name + */ +static char * +read_oct_clock_name(net) +octObject *net; +{ + octGenerator gen; + octObject term; + + OH_ASSERT(octInitGenContents(net, OCT_TERM_MASK, &gen)); + while (octGenerate(&gen, &term) == OCT_OK ) { + if (term.contents.term.instanceId == oct_null_id){ + return util_strsav(term.contents.term.name); + } + } + return NIL(char); +} + +int +read_oct_clock(network,facet) + network_t *network; + octObject *facet; +{ + octObject sisBag, bag, net, term, prop; + octGenerator gen, genNet; + int count = 0; + int i, nlist; + node_t *node; + char *name, *clk_name; + sis_clock_t *clock; + + octInitGenContents( facet, OCT_NET_MASK, &genNet ); + while (octGenerate(&genNet,&net) == OCT_OK ) { + if ( ohGetByPropName(&net,&prop,"NETTYPE") != OCT_OK ) continue; + if ( !STREQ( prop.contents.prop.value.string, "CLOCK" ) ) continue; + count++; + name = net.contents.net.name; + node = read_find_or_create_node(network, name); + if (node_function(node) != NODE_UNDEFINED) { + errRaise( "oct_read", 1, "clock %s is multiply defined", name ); + } + clk_name = read_oct_clock_name(&net); + if (clk_name == NIL(char)){ + errRaise( "oct_read", 1, "Clock %s does not have formal terminal", name); + } + clock = clock_create(clk_name); + if (!clock_add_to_network(network, clock)) { + errRaise("oct_read", 1, "clock %s is already part of the network", + clock_name(clock)); + } + (void) free(clk_name); + } + + if ( count == 0 ) { + /* + (void)fprintf(sisout, "No clocks in the network\n" ); + */ + return 1; + } + + if (ohGetByBagName( facet, &sisBag, "SIS_CLOCKS" )!=OCT_OK ) { + /* + (void)fprintf(sisout, "No SIS_CLOCK bag\n" ); + */ + return 1; + } + + { + double cycle_time; + if (ohGetByPropName( &sisBag, &prop, "CYCLETIME" ) == OCT_OK){ + cycle_time = prop.contents.prop.value.real; + } else { + cycle_time = CLOCK_NOT_SET; + } + clock_set_cycletime(network, cycle_time); + } + + octInitGenContents( &sisBag, OCT_BAG_MASK, &gen ); + while ( octGenerate( &gen, &bag ) == OCT_OK ) { + read_oct_add_clock_event( network, &bag ); /* This is a CLOCK_EVENTS bag */ + } + return 1; +} +#endif /* SIS */ + + +struct termInfo { + char *name; + network_t *logicFunction; +}; + +static st_table *MasterTable = NIL(st_table); +#ifdef SIS +static st_table *TypeTable = NIL(st_table); +static st_table *ClockTable = NIL(st_table); +#endif /* SIS */ + +static void +initialize_master_table() +{ + MasterTable = st_init_table(strcmp, st_strhash); +#ifdef SIS + TypeTable = st_init_table(strcmp, st_strhash); + ClockTable = st_init_table(strcmp, st_strhash); +#endif /* SIS */ + return; +} + +static void +termFree(terminfo) +struct termInfo *terminfo; +{ + (void) free(terminfo->name); + network_free(terminfo->logicFunction); + return; +} + + +static void +clean_master_table() +{ + st_generator *gen; + char *key, *value; + lsList the_list; + + st_foreach_item(MasterTable, gen, &key, &value) { + the_list = (lsList) value; + if (the_list != (lsList) 0) { + (void) lsDestroy(the_list, termFree); + } + } + st_free_table(MasterTable); +#ifdef SIS + st_free_table(TypeTable); + st_free_table(ClockTable); +#endif /* SIS */ + return; +} + +#ifdef SIS + +static lsList +is_a_logic_cell(instance, is_comb_cellp) +octObject *instance; +int *is_comb_cellp; +/* + * determine if an instance has a logic representation + * + * returns: lsList of the logic function(s), 0 if not a logic cell, + * In case the instance is that of a latch, *is_comb_cellp is set to 0 + */ +{ + char *ptr; + octGenerator gen; + octObject term, prop, master; + lsList outputs; + struct termInfo *termInfo; + int termTypeExists, is_comb_cell; + + if (st_lookup(MasterTable, instance->contents.instance.master, &ptr)) { + /* it has been seen before */ + (void)st_lookup_int(TypeTable, instance->contents.instance.master, &is_comb_cell); + *is_comb_cellp = is_comb_cell; + return((lsList) ptr); + } + + if ((ohOpenMaster(&master, instance, "interface", "r") >= OCT_OK) && + (ohGetByPropName(&master, &prop, "CELLTYPE") == OCT_OK)){ + if (STREQ(prop.contents.prop.value.string, "COMBINATIONAL")){ + *is_comb_cellp = TRUE; + } else if (STREQ(prop.contents.prop.value.string, "MEMORY")){ + *is_comb_cellp = FALSE; + } else { + (void) st_insert(MasterTable, instance->contents.instance.master, NIL(char)); + (void) st_insert(TypeTable, instance->contents.instance.master, (char *)1); + return((lsList) 0); + } + } else { + (void) st_insert(MasterTable, instance->contents.instance.master, NIL(char)); + (void) st_insert(TypeTable, instance->contents.instance.master, (char *)1); + return((lsList) 0); + } + + if (octInitGenContents(&master, OCT_TERM_MASK, &gen) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, octErrorString()); + } + + outputs = lsCreate(); + + while (octGenerate(&gen, &term) == OCT_OK) { + termTypeExists = (ohGetByPropName(&term, &prop, "TERMTYPE") == OCT_OK); + /* if no TERMTYPE, defaults to SIGNAL */ + if (termTypeExists && !STREQ(prop.contents.prop.value.string, "SIGNAL")) { + continue; + } + if ((ohGetByPropName(&term, &prop, "DIRECTION") < OCT_OK) || + !STREQ(prop.contents.prop.value.string, "OUTPUT")) { + continue; + } + termInfo = ALLOC(struct termInfo, 1); + termInfo->name = util_strsav(term.contents.term.name); + if (ohGetByPropName(&term, &prop, "LOGICFUNCTION") < OCT_OK) { + termInfo->logicFunction = NIL(network_t); + } else { + if ((termInfo->logicFunction = read_eqn_string(prop.contents.prop.value.string)) == NIL(network_t)) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "bad equation %s (%s)", + prop.contents.prop.value.string, + error_string()); + } + } + (void) lsNewEnd(outputs, (lsGeneric) termInfo, NIL(lsHandle)); + } + + (void) st_insert(MasterTable, instance->contents.instance.master, (char *) outputs); + (void) st_insert(TypeTable, instance->contents.instance.master, (char *)(*is_comb_cellp)); + + if (octCloseFacet(&master) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, octErrorString()); + } + return(outputs); +} + +#else /* for misII the routine has a different structure */ + +static lsList +is_a_logic_cell(instance) +octObject *instance; +/* + * determine if an instance has a logic representation + * + * returns: lsList of the logic function(s), 0 if not a logic cell, + */ +{ + char *ptr; + octGenerator gen; + octObject term, prop, master; + lsList outputs; + struct termInfo *termInfo; + int termTypeExists; + + if (st_lookup(MasterTable, instance->contents.instance.master, &ptr)) { + /* it has been seen before */ + return((lsList) ptr); + } + + if ((ohOpenMaster(&master, instance, "interface", "r") < OCT_OK) || + (ohGetByPropName(&master, &prop, "CELLTYPE") < OCT_OK) || + !STREQ(prop.contents.prop.value.string, "COMBINATIONAL")) { + + (void) st_insert(MasterTable, instance->contents.instance.master, NIL(char)); + return((lsList) 0); + } + + if (octInitGenContents(&master, OCT_TERM_MASK, &gen) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, octErrorString()); + } + + outputs = lsCreate(); + + while (octGenerate(&gen, &term) == OCT_OK) { + termTypeExists = (ohGetByPropName(&term, &prop, "TERMTYPE") == OCT_OK); + /* if no TERMTYPE, defaults to SIGNAL */ + if (termTypeExists && !STREQ(prop.contents.prop.value.string, "SIGNAL")) { + continue; + } + if ((ohGetByPropName(&term, &prop, "DIRECTION") < OCT_OK) || + !STREQ(prop.contents.prop.value.string, "OUTPUT")) { + continue; + } + termInfo = ALLOC(struct termInfo, 1); + termInfo->name = util_strsav(term.contents.term.name); + if (ohGetByPropName(&term, &prop, "LOGICFUNCTION") < OCT_OK) { + termInfo->logicFunction = NIL(network_t); + } else { + if ((termInfo->logicFunction = read_eqn_string(prop.contents.prop.value.string)) == NIL(network_t)) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "bad equation %s (%s)", + prop.contents.prop.value.string, + error_string()); + } + } + (void) lsNewEnd(outputs, (lsGeneric) termInfo, NIL(lsHandle)); + } + + (void) st_insert(MasterTable, instance->contents.instance.master, (char *) outputs); + + if (octCloseFacet(&master) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, octErrorString()); + } + return(outputs); +} +#endif /* SIS */ + +#ifdef SIS /* Routines to deal with latches are required only for sis */ +/* + * Set the type of the latch, initial_value + * TODO, also the control signal + */ +static void oct_read_set_latch(network, latch, instance) +network_t *network; +latch_t *latch; +octObject *instance; +{ + octGenerator gen; + octObject master, term, net, prop; + char *name; + node_t *control_node, *node; + int active_high = -1, edge_triggered = -1, clock_used = 0; + + if (ohOpenMaster(&master, instance, "interface", "r") >= OCT_OK) { + if (ohGetByPropName(&master, &prop, "CELLTYPE") == OCT_OK && + STREQ(prop.contents.prop.value.string, "MEMORY")){ + if (ohGetByPropName(&master, &prop, "SYNCHMODEL") == OCT_OK){ + if (STREQ(prop.contents.prop.value.string, "TRANSPARENT-LATCH")){ + edge_triggered = 0; + } else if (STREQ(prop.contents.prop.value.string, "MASTER-SLAVE-LATCH")){ + edge_triggered = 1; + } + } + + } + if (edge_triggered >= 0){ + OH_ASSERT(octInitGenContents(&master, OCT_TERM_MASK, &gen)); + while (octGenerate(&gen, &term) == OCT_OK) { + if (ohGetByPropName(&term, &prop, "SYNCHTERM") == OCT_OK){ + if (STREQ(prop.contents.prop.value.string, "CONTROL") || + STREQ(prop.contents.prop.value.string, "CONTROLBAR")){ + if (ohGetByPropName(&term, &prop, "ACTIVE_LEVEL") == OCT_OK){ + if (STREQ(prop.contents.prop.value.string, "LOW")){ + active_high = 0; + } else if (STREQ(prop.contents.prop.value.string, "CONTROLBAR")){ + active_high = 1; + } + } + /* + * Also check if this is a clock signal connected to something + * Generate a net from the terminal on the instance + */ + if (ohTerminalNet(&term, &net) == OCT_OK){ + if (clock_used){ + errRaise(SIS_PKG_NAME, OCT_ERROR, + "Multiple clocks used on instance %s", ohFormatName(instance)); + } else { + clock_used = TRUE; + name = net.contents.net.name; + node = read_find_or_create_node(network, name); + control_node = network_get_control(network, node); + if (control_node == NIL(node_t)){ + node = network_add_fake_primary_output(network, control_node); + read_change_madeup_name(network, node); + control_node = node; + } + latch_set_control(latch, control_node); + } + } + } + } + } + } + } + + if (edge_triggered >= 0 && active_high >= 0){ + if (edge_triggered == 0){ + if (active_high == 0){ + latch_set_type(latch, FALLING_EDGE); + } else { + latch_set_type(latch, RISING_EDGE); + } + } else { + if (active_high == 0){ + latch_set_type(latch, ACTIVE_LOW); + } else { + latch_set_type(latch, ACTIVE_HIGH); + } + } + } else { + latch_set_type(latch, UNKNOWN); + } + + if (ohGetByPropName(instance, &prop, "INITIAL_VALUE") == OCT_OK){ + latch_set_initial_value(latch, prop.contents.prop.value.integer); + } else { + latch_set_initial_value(latch, 3); /* UNKNOWN */ + } +} + +#endif /* SIS */ + + +network_t * +read_oct(facet, mappedp) +octObject *facet; +int mappedp; +{ + + network_t *network, *newnetwork; + node_t *output, *fanout, *newnode; +#ifdef SIS + node_t *temp; + latch_t *latch; + int is_comb_cell; +#endif + octObject instance, term, net, prop, bag; + octGenerator gen; + octStatus status; + + lsList outputList; + lsGen outputGen; + lsGeneric ptr; + struct termInfo *termInfo; + int instanceLogicFunction; + + library_t *library; + + node_t *node; + + /* open the facet */ + if (octOpenFacet(facet) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not open the facet %s (%s)", + ohFormatName(facet), + octErrorString()); + } + + /* + * XXX read the required properties to make sure that it + * is a good facet + */ + + /* force the net names to be unique */ + uniqNames(facet, OCT_NET_MASK); + + /* + * make sure formal term names are not the same as net names + * (really only a problem for primary outputs) + */ + + OH_ASSERT(octInitGenContents(facet, OCT_TERM_MASK, &gen)); + while (octGenerate(&gen, &term) == OCT_OK) { + OH_ASSERT(octGenFirstContainer(&term, OCT_NET_MASK, &net)); + if (strcmp(term.contents.term.name, net.contents.net.name) == 0) { + /* build a new name */ + char buffer[1024]; + static int count = 0; + do { + (void) sprintf(buffer, "%s-%d", + term.contents.term.name, count++); + net.contents.net.name = buffer; + } while (octGetByName(facet, &net) == OCT_OK); + + OH_ASSERT(octModify(&net)); + } + } + + network = network_alloc(); + + /* is there a library set? */ + if (mappedp) { + library = lib_get_library(); + } else { + library = NIL(library_t); + } + + if (ohGetByBagName(facet, &bag, "INSTANCES") != OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "Missing INSTANCES bag, facet does not follow policy"); + } + + OH_ASSERT(octInitGenContents(&bag, OCT_INSTANCE_MASK, &gen)); + + initialize_master_table(); + +#ifdef SIS + /* Read in the clocks */ + read_oct_clock(network, facet); +#endif /* SIS */ + + while (octGenerate(&gen, &instance) == OCT_OK) { + + if (library) { + /* see if this is a mapped gate */ + char *lastslash = strrchr(instance.contents.instance.master, '/'); + if (lastslash) { + char gateName[1024]; + lib_gate_t *gate; + + (void) sprintf(gateName, "%s:%s", + lastslash + 1, + instance.contents.instance.view); + if ((gate = lib_get_gate(library, gateName))) { + array_t *formal_array, *actual_array; + char **formal_data; + node_t **actual_data; + node_t *outnode; + int i, size = lib_gate_num_in(gate); + + formal_array = array_alloc(char *, size); + actual_array = array_alloc(node_t *, size); + +#ifdef SIS + is_comb_cell = (lib_gate_type(gate) == COMBINATIONAL); +#endif /* SIS */ + for (i = 0; i < size; i++) { + OH_ASSERT(ohGetByTermName(&instance, &term, lib_gate_pin_name(gate, i, 1))); + OH_ASSERT(octGenFirstContainer(&term, OCT_NET_MASK, &net)); + node = read_find_or_create_node(network, net.contents.net.name); + array_insert_last(char *, formal_array, term.contents.term.name); + array_insert_last(node_t *, actual_array, node); + } + + for (i = 0; i < lib_gate_num_out(gate); i++) { + OH_ASSERT(ohGetByTermName(&instance, &term, lib_gate_pin_name(gate, i, 0))); + OH_ASSERT(octGenFirstContainer(&term, OCT_NET_MASK, &net)); + outnode = read_find_or_create_node(network, net.contents.net.name); + } + formal_data = array_data(char *, formal_array); + actual_data = array_data(node_t *, actual_array); + array_free(formal_array); + array_free(actual_array); + +#ifdef SIS + if (!is_comb_cell){ + if (node_type(outnode) == PRIMARY_INPUT || outnode->F != 0){ + errRaise(SIS_PKG_NAME, -1, "gate `%s' redefined", node_name(outnode)); + } else { + network_change_node_type(network, outnode, PRIMARY_INPUT); + } + } +#endif /* SIS */ + + if (!lib_set_gate(outnode, gate, formal_data, actual_data, size)) { + + errRaise(SIS_PKG_NAME, -1, "error loading gate `%s'", gateName); + } + +#ifdef SIS + /* + * TODO: Should see if the clocks need to be attached + */ +#endif /* SIS */ + + free(formal_data); + free(actual_data); + continue; + } + } + } + +#ifdef SIS + outputList = is_a_logic_cell(&instance, &is_comb_cell); +#else /* misII style call */ + outputList = is_a_logic_cell(&instance); +#endif /* SIS */ + + if (outputList == (lsList) 0) { + continue; + } + + outputGen = lsStart(outputList); + + while (lsNext(outputGen, &ptr, NIL(lsHandle)) == LS_OK) { + + termInfo = (struct termInfo *) ptr; + + /* see if there is a LOGICFUNCTION on the instance */ + if (ohGetByTermName(&instance, &term, termInfo->name) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not get the actual terminal %s of %s (%s)", + termInfo->name, + ohFormatName(&instance), + octErrorString()); + } + + if (ohGetByPropName(&term, &prop, "LOGICFUNCTION") == OCT_OK) { + if ((newnetwork = read_eqn_string(prop.contents.prop.value.string)) == NIL(network_t)) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "bad equation %s (%s)", + prop.contents.prop.value.string, + error_string()); + } + instanceLogicFunction = 1; + } else { + newnetwork = termInfo->logicFunction; + instanceLogicFunction = 0; + if (newnetwork == NIL(network_t)) { + continue; + } + } + + /* get the primary output of the network */ + output = network_get_po(newnetwork, 0); + + status = octGenFirstContainer(&term, OCT_NET_MASK, &net); + if (status == OCT_GEN_DONE) { + if (instanceLogicFunction) { + network_free(newnetwork); + } + continue; + } + if (status < OCT_OK) { + errRaise(SIS_PKG_NAME, status, octErrorString()); + } + + fanout = read_find_or_create_node(network, net.contents.net.name); + + /* build the new node */ + /* get the internal node - should be the only fanin the the primary output */ + newnode = build_new_node(node_get_fanin(output, 0), network, &instance); + +#ifdef SIS + if (is_comb_cell){ + /* put in the new function */ + if (node_function(fanout) == NODE_UNDEFINED) { + node_replace(fanout, newnode); + } else { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "two outputs driving the same node: %s", + node_oct_name(fanout)); + } + } else { + /* TODO: Handle exotic latches (with feedback) */ + /* + * The output of the latch is a PI of the network + */ + if (node_function(fanout) == NODE_UNDEFINED){ + network_change_node_type(network, fanout, PRIMARY_INPUT); + } else { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "latch output driving already driven node: %s", + node_oct_name(fanout)); + } + /* + * Make sure that the node given does not conflict names yet to come + * Add a blank to the name. Have to remove this later. Create latch + */ + temp = node_alloc(); + network_add_node(network, temp); + node_replace(temp, newnode); + read_change_madeup_name(network, temp); + temp = network_add_fake_primary_output(network, temp); + read_change_madeup_name(network, temp); + network_create_latch(network, &latch, temp, fanout); + + oct_read_set_latch(network, latch, &instance); + } +#else /* for misII only comb cells are present */ + /* put in the new function */ + if (node_function(fanout) == NODE_UNDEFINED) { + node_replace(fanout, newnode); + } else { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "two outputs driving the same node: %s", + node_oct_name(fanout)); + } +#endif /* SIS */ + + if (instanceLogicFunction) { + /* garbage collection */ + network_free(newnetwork); + } + } + + (void) lsFinish(outputGen); + } + + /* determine PIs and POs */ + + OH_ASSERT(octInitGenContents(facet, OCT_TERM_MASK, &gen)); + + while (octGenerate(&gen, &term) == OCT_OK) { + node_function_t funct; + + status = octGenFirstContainer(&term, OCT_NET_MASK, &net); + if (status == OCT_GEN_DONE) { + continue; + } + if (status < OCT_OK) { + errRaise(SIS_PKG_NAME, status, "oct error (%s)", octErrorString()); + } + + if ((node = network_find_node(network, net.contents.net.name)) == NIL(node_t)) { + continue; + } + + funct = node_function(node); + + if (funct == NODE_UNDEFINED) { + /* primary input */ + network_change_node_type(network, node, PRIMARY_INPUT); + network_change_node_name(network, node, util_strsav(term.contents.term.name)); + } else { + node_t *new; + char *save; + /* + * network_add_primary_output takes the name of 'node' and + * gives it to 'new'; it then gensyms a name for 'node' + * + * this is okay if 'node' is an internal node, but it 'node' + * is a primary input, this is trouble + * + * thus the name of node must be saved and replaced + */ + save = util_strsav(node_oct_name(node)); + new = network_add_primary_output(network, node); + + /* + * change the name of the output to the name stored in Oct + */ + network_change_node_name(network, new, util_strsav(term.contents.term.name)); + network_change_node_name(network, node, save); + } + } + + /* garbage collect */ + clean_master_table(); + + if (!network_check(network)) { + errRaise(SIS_PKG_NAME, OCT_ERROR, "network check failed (%s)", error_string()); + } + + OH_ASSERT(octCloseFacet(facet)); + +#ifdef SIS + /* Correct the names that had a blank added to avoid conflicts */ + network_replace_io_fake_names(network); +#endif + network_set_name(network, ohFormatName(facet)); + + return(network); +} + + + +static jmp_buf sis_oct_error_buf; + +static void +sis_oct_error_handler(pkgName, code, message) +char *pkgName; +int code; +char *message; +{ + (void) fprintf(stderr, "%s: error (%d)\n\t%s\n", pkgName, code, message); + (void) longjmp(sis_oct_error_buf, -1); + return; +} + + +int +external_read_oct(network, argc, argv) +network_t **network; +int argc; +char **argv; +/* + * read_oct: read a network from an Oct facet + * + */ +{ + octObject facet; + int mappedp = 0; + + if ((argc != 2) && (argc != 3)) { + (void) fprintf(siserr, "usage: read_oct [-m] cell[:view]\n"); + return(1); + } + + octBegin(); + + if (setjmp(sis_oct_error_buf) == 0) { + errPushHandler(sis_oct_error_handler); + + (void) ohUnpackDefaults(&facet, "r", ":logic:contents"); + if (ohUnpackFacetName(&facet, argv[argc - 1]) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, "usage: read_oct cell[:view]"); + } + + error_init(); + if (argc == 3) { + mappedp = 1; + } + *network = read_oct(&facet, mappedp); + errPopHandler(); + } else { + return(1); + } + + octEnd(); + + return(0); +} + +#endif /* OCT */ + diff --git a/sis/octio/octwrite.c b/sis/octio/octwrite.c new file mode 100644 index 0000000..4e67040 --- /dev/null +++ b/sis/octio/octwrite.c @@ -0,0 +1,991 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/octio/octwrite.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#ifdef OCT + +/* + * routine for writing SISII logic networks (mapped and unmapped) into + * Oct facets + */ +#include "copyright.h" +#include "port.h" +#undef assert +#include "sis.h" +#include "farray.h" +#include "st.h" +#undef ALLOC +#undef REALLOC +#undef FREE +#include "errtrap.h" +#include "utility.h" +#include "oct.h" +#include "oh.h" +#include "octio.h" + +#define node_oct_name(node) (node)->name +static char *octCellPath, *octCellView; + +/* name of the program - for errtrap */ +char *optProgName = "sis"; + + + +/* + * special routines to make octGetByName faster (use hash tables) + * + * why: octGetByName does a linear search to find an object, + * as the number of objects increases, the search times becomes + * dominant. The special functions surround octGetByName and + * hash information as it is found/created. + */ + +static st_table *NetTable = NIL(st_table); + +static void +initialize_net_table() +{ + NetTable = st_init_table(strcmp, st_strhash); + return; +} + +static octStatus +specialGetByNetName(facet, net, name) +octObject *facet, *net; +char *name; +{ + char *ptr; + + if (st_lookup(NetTable, name, &ptr)) { + net->objectId = *(octId *) ptr; + OH_ASSERT(octGetById(net)); + return(OCT_OK); + } else { + if (ohGetByNetName(facet, net, name) == OCT_OK) { + octId *id = ALLOC(octId, 1); + *id = net->objectId; + (void) st_insert(NetTable, name, (char *) id); + return(OCT_OK); + } + return(OCT_ERROR); + } +} + +static void +specialCreateNet(facet, net, name) +octObject *facet, *net; +char *name; +{ + octId *id; + + if (st_lookup(NetTable, name, NIL(char *))) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "trying to create a net that already exists: %s", + name); + } + if (ohCreateNet(facet, net, name) != OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not create net %s (%s)", + name, + octErrorString()); + } + id = ALLOC(octId, 1); + *id = net->objectId; + (void) st_insert(NetTable, name, (char *) id); + return; +} + +static void +specialGetOrCreateNet(facet, net, name) +octObject *facet, *net; +char *name; +{ + if (specialGetByNetName(facet, net, name) == OCT_OK) { + return; + } + specialCreateNet(facet, net, name); + return; +} + + + +/* + * routines to attach required SYMBOLIC policy properties + */ + +static void +attachPolicyTermProperties(term, direction, termtype) +octObject *term; +char *direction, *termtype; +{ + octObject prop; + + OH_ASSERT(ohCreatePropStr(term, &prop, "DIRECTION", direction)); + OH_ASSERT(ohCreatePropStr(term, &prop, "TERMTYPE", termtype)); + return; +} + +static void +attachPolicyProperties(facet) + octObject *facet; +{ + char *technology, *editstyle, *viewtype; + octObject prop; + + /* attach POLICY properties */ + if ((technology = com_get_flag("OCT-TECHNOLOGY")) == NIL(char)) { + ohCreateOrModifyPropStr(facet, &prop, "TECHNOLOGY", "scmos"); + } else { + ohCreateOrModifyPropStr(facet, &prop, "TECHNOLOGY", technology); + } + if ((editstyle = com_get_flag("OCT-EDITSTYLE")) == NIL(char)) { + ohCreateOrModifyPropStr(facet, &prop, "EDITSTYLE", "SYMBOLIC"); + } else { + ohCreateOrModifyPropStr(facet, &prop, "EDITSTYLE", editstyle); + } + if ((viewtype = com_get_flag("OCT-VIEWTYPE")) == NIL(char)) { + ohCreateOrModifyPropStr(facet, &prop, "VIEWTYPE", "SYMBOLIC"); + } else { + ohCreateOrModifyPropStr(facet, &prop, "VIEWTYPE", viewtype); + } + return; +} + +static void +createInterface(facet) +octObject *facet; +{ + octObject interface, prop, term, iterm, dummy; + octGenerator tgen; + + interface.type = OCT_FACET; + interface.contents.facet.cell = facet->contents.facet.cell; + interface.contents.facet.view = facet->contents.facet.view; + interface.contents.facet.facet = "interface"; + interface.contents.facet.version = OCT_CURRENT_VERSION; + interface.contents.facet.mode = "w"; + + if (octOpenFacet(&interface) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not open the facet %s (%s)", + ohFormatName(&interface), + octErrorString()); + } + + attachPolicyProperties(&interface); + + OH_ASSERT(octInitGenContents(facet, OCT_TERM_MASK, &tgen)); + while (octGenerate(&tgen, &term) == OCT_OK) { + if (ohGetByTermName(&interface, &iterm, term.contents.term.name) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not get the formal terminal %s on %s (%s)", + term.contents.term.name, + ohFormatName(&interface), + octErrorString()); + } + if (ohGetByPropName(&term, &prop, "DIRECTION") < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not get the DIRECTION property on terminal %s of %s (%s)", + term.contents.term.name, + ohFormatName(&interface), + octErrorString()); + } + OH_ASSERT(ohCreatePropStr(&iterm, &dummy, "DIRECTION", prop.contents.prop.value.string)); + if (ohGetByPropName(&term, &prop, "TERMTYPE") < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not get the TERMTYPE property on terminal %s of %s (%s)", + term.contents.term.name, + ohFormatName(&interface), + octErrorString()); + } + OH_ASSERT(ohCreatePropStr(&iterm, &dummy, "TERMTYPE", prop.contents.prop.value.string)); + } + OH_ASSERT(ohCreatePropStr(&interface, &prop, "CELLCLASS", "MODULE")); + + OH_ASSERT(octCloseFacet(&interface)); + + return; +} + + + +/* + * replacements for the 'library' package functions to handle + * generic instances + */ + +static int IsGeneric = 0; + +static void +createGenericMaster(node, name, view) +node_t *node; +char *name, *view; +/* + * create a generic master + */ +{ + octObject facet, interface, prop, term; + octStatus status; + int i; + char buffer[32]; + + status = ohOpenFacet(&facet, name, view, "contents", "a"); + if ((status == OCT_OLD_FACET) || (status == OCT_ALREADY_OPEN)) { + return; + } else if (status == OCT_NEW_FACET) { + /* new cell */ + attachPolicyProperties(&facet); + OH_ASSERT(ohCreatePropStr(&facet, &prop, "CELLCLASS", "LEAF")); + OH_ASSERT(ohCreatePropStr(&facet, &prop, "CELLTYPE", "COMBINATIONAL")); + /* put some terminals down */ + for (i = 0; i < node_num_fanin(node); i++) { + (void) sprintf(buffer, "in%d", i); + OH_ASSERT(ohCreateTerm(&facet, &term, buffer)); + attachPolicyTermProperties(&term, "INPUT", "SIGNAL"); + } + OH_ASSERT(ohCreateTerm(&facet, &term, "out0")); + attachPolicyTermProperties(&term, "OUTPUT", "SIGNAL"); + OH_ASSERT(octFlushFacet(&facet)); + + /* create the interface facet */ + + OH_ASSERT(ohOpenInterface(&interface, &facet, "w")); + + attachPolicyProperties(&interface); + OH_ASSERT(ohCreatePropStr(&interface, &prop, "CELLCLASS", "LEAF")); + OH_ASSERT(ohCreatePropStr(&interface, &prop, "CELLTYPE", "COMBINATIONAL")); + /* put some terminals down */ + for (i = 0; i < node_num_fanin(node); i++) { + (void) sprintf(buffer, "in%d", i); + if (ohGetByTermName(&interface, &term, buffer) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not get formal terminal %s on %s (%s)", + buffer, + ohFormatName(&interface), + octErrorString()); + } + attachPolicyTermProperties(&term, "INPUT", "SIGNAL"); + } + if (ohGetByTermName(&interface, &term, "out0") < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not get formal terminal %s on %s (%s)", + "out0", + ohFormatName(&interface), + octErrorString()); + } + attachPolicyTermProperties(&term, "OUTPUT", "SIGNAL"); + OH_ASSERT(octFlushFacet(&interface)); + + return; + } + errRaise(SIS_PKG_NAME, status, + "can not open the generic master %s (%s)", + ohFormatName(&facet), + octErrorString()); + return; +} + +/* XXX TOO MUCH STRING SAVING GOING ON HERE */ + +static void +unpackname(name, cell, view, defaultView) +char *name; +char **cell; +char **view; +char *defaultView; +{ + char *ptr; + char buffer[4096]; + + (void) strcpy(buffer, name); + ptr = strchr(buffer, ':'); + if (ptr == NIL(char)) { + *cell = util_strsav(buffer); + *view = util_strsav(defaultView); + } else { + *ptr = '\0'; + *cell = util_strsav(buffer); + *view = util_strsav(ptr + 1); + } + return; +} + +static void +oct_lib_get_gate_cell_and_view(node, facet, cell, view) + node_t *node; + octObject *facet; + char **cell, **view; +{ + static char master[1024]; + char *gateName; + char path[1024]; + int pinCount; + + if ((gateName = lib_get_gate_name(node)) == NIL(char)) { + /* generic node */ + pinCount = node_num_fanin(node); + (void) sprintf(path, "%s/generic-%d", facet->contents.facet.cell, + pinCount); + createGenericMaster(node, path, octCellView); + IsGeneric = 1; + (void) sprintf(master, "generic-%d", pinCount); + *cell = master; + *view = octCellView; + return; + + } else { + IsGeneric = 0; + unpackname(gateName, cell, view, octCellView); + if ((**cell != '/') && (**cell != '~') && (octCellPath != NIL(char))) { + /* prepend octCellPath to cell */ + (void) sprintf(master, "%s/%s", octCellPath, *cell); + *cell = master; + } + return; + } +} + + + +static void +factored_form(network, orig_node, node, fform) +network_t *network; +node_t *orig_node, *node; +array_t *fform; +{ + node_cube_t cube; + node_literal_t literal; + int i, j, cube_count, fanin_count; + char buffer[32]; + + if (node_network(node) == network) { + int size; + + /* the fanin_index stuff should be cached ... */ + (void) sprintf(buffer, "in%d", node_get_fanin_index(orig_node, node)); + size = strlen(buffer); + for (i = 0; i < size; i++) { + f_array_insert_last(char, fform, buffer[i]); + } + return; + } + + cube_count = node_num_cube(node); + if (cube_count == 0) { + return; + } + + if (cube_count > 1) { + f_array_insert_last(char, fform, '('); + f_array_insert_last(char, fform, '+'); + } + + for (i = 0; i < cube_count; i++) { + cube = node_get_cube(node, i); + fanin_count = node_num_fanin(node); + if (fanin_count == 0) { + continue; + } + if (fanin_count > 1) { + if (i > 0) { + f_array_insert_last(char, fform, ' '); + } + f_array_insert_last(char, fform, '('); + f_array_insert_last(char, fform, '*'); + } + + for (j = 0; j < fanin_count; j++) { + literal = node_get_literal(cube, j); + switch (literal) { + case ZERO: + f_array_insert_last(char, fform, ' '); + f_array_insert_last(char, fform, '('); + f_array_insert_last(char, fform, '!'); + f_array_insert_last(char, fform, ' '); + factored_form(network, orig_node, node_get_fanin(node, j), fform); + f_array_insert_last(char, fform, ')'); + break; + case ONE: + f_array_insert_last(char, fform, ' '); + factored_form(network, orig_node, node_get_fanin(node, j), fform); + break; + } + } + if (fanin_count > 1) { + f_array_insert_last(char, fform, ')'); + } + } + + if (cube_count > 1) { + f_array_insert_last(char, fform, ')'); + } + + return; +} + + +static array_t * +oct_lib_get_factored_function(node) +node_t *node; +{ + network_t *network; + array_t *nodes; + int i; + array_t *fform; + + network = node_network(node); + nodes = factor_to_nodes(node); + fform = array_alloc(char, 1024); + factored_form(network, node, array_fetch(node_t *, nodes, 0), fform); + f_array_insert_last(char, fform, '\0'); + for (i = 0; i < array_n(nodes); i++) { + node_free(array_fetch(node_t *, nodes, i)); + } + return fform; +} + + +static char * +oct_lib_get_pin_name(node, index) +node_t *node; +int index; +{ + static char buffer[32]; + + if ( IsGeneric ) { + (void) sprintf(buffer, "in%d", index); + return buffer; + } else { + lib_gate_t *gate = lib_gate_of( node ); + return lib_gate_pin_name(gate, index, 1); + } +} + + +static char * +oct_lib_get_out_pin_name(node, index) +node_t *node; +int index; +{ + static char buffer[32]; + + if (IsGeneric) { + (void) sprintf(buffer, "out%d", index); + return(buffer); + } else { + lib_gate_t *gate = lib_gate_of( node ); + return lib_gate_pin_name(gate, index, 0); + } +} + + +static void +attachLogicFunction(term, node) +octObject *term; +node_t *node; +{ + node_function_t funct; + + octObject prop; + if ( IsGeneric ) { + funct = node_function(node); + switch (funct) { + case NODE_UNDEFINED: + errRaise(SIS_PKG_NAME, OCT_ERROR, + "Function for node %s is undefined.", node_oct_name(node)); + return; + + case NODE_0: + OH_ASSERT(ohCreatePropStr(term, &prop, "LOGICFUNCTION", "(0)")); + break; + + case NODE_1: + OH_ASSERT(ohCreatePropStr(term, &prop, "LOGICFUNCTION", "(1)")); + break; + + default: + { + array_t *fform = oct_lib_get_factored_function(node); + char *data = array_data(char, fform); + + OH_ASSERT(ohCreatePropStr(term, &prop, "LOGICFUNCTION", data)); + array_free(fform); + } + break; + + } + } + return; +} + +create_primary_output( facet, node ) + octObject *facet; + node_t *node; +{ + octObject term, net; + char* nodeName = node_oct_name(node); + + OH_ASSERT(ohCreateTerm(facet, &term, nodeName)); + attachPolicyTermProperties(&term, "OUTPUT", "SIGNAL"); + specialGetOrCreateNet(facet, &net, node_oct_name(node_get_fanin(node, 0))); + OH_ASSERT(octAttach(&net, &term)); +} + +create_primary_input( facet, node ) + octObject *facet; + node_t *node; +{ + octObject term, net, prop; + char* nodeName = node_oct_name(node); + + OH_ASSERT(ohCreateTerm(facet, &term, nodeName)); + specialGetOrCreateNet(facet, &net, nodeName ); +#ifdef SIS + if (network_get_control(node_network(node), node) == NIL(node_t)){ + attachPolicyTermProperties(&term, "INPUT", "SIGNAL"); + } else { + OH_ASSERT(ohCreatePropStr(&net, &prop, "NETTYPE", "CLOCK")); + attachPolicyTermProperties(&term, "INPUT", "CLOCK"); + } +#else + attachPolicyTermProperties(&term, "INPUT", "SIGNAL"); +#endif /* SIS */ + OH_ASSERT(octAttach(&net, &term)); +} + +void oct_connect_instance_term( facet, instance, termName, netName ) + octObject *facet; + octObject *instance; + char *termName; + char *netName; +{ + octObject net,term; + + if (ohGetByTermName(instance, &term, termName) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not get the actual terminal %s of %s (%s)", + termName, + ohFormatName(instance), + octErrorString()); + } + + specialGetOrCreateNet(facet, &net, netName); + + OH_ASSERT( octAttach( &net, &term ) ); +} + +#ifdef SIS /* Support for writing latches */ +void create_latch( facet, node, latch ) + octObject *facet; + node_t *node; + latch_t *latch; +{ + lib_gate_t *gate = NIL(lib_gate_t); + int i; + char* name = 0; + char *cell, *view; + node_t *fanin, *temp, *po; + char *gateName, *netName, *termName; + octObject prop, instance, bag; + + OH_ASSERT(ohGetOrCreateBag(facet, &bag, "INSTANCES")); + + gate = latch_get_gate( latch ); + if ( gate != NIL(lib_gate_t) ) { + po = latch_get_input( latch ); /* Get the input */ + temp = node_get_fanin(po, 0); /* */ + + gateName = lib_gate_name( gate ); + oct_lib_get_gate_cell_and_view(temp, facet, &cell, &view); + /* unpackname( gateName, &cell, &view, octCellView ); */ + /* + (void)fprintf(sisout, "Creating %s of %s:%s in %s\n", gateName, + cell, view, ohFormatName( facet ) ); + */ + OH_ASSERT(ohCreateInst( facet, &instance, gateName, cell, view )); + octAttach( &bag, &instance ); + + + assert(lib_gate_of(temp) == gate); + foreach_fanin(temp, i, fanin){ + if (lib_gate_latch_pin(gate) != i){ + /* Exclude the feedback pin -- if any */ + netName = node_oct_name( fanin ); + termName = lib_gate_pin_name( gate, i, 1 ); + oct_connect_instance_term( facet, &instance, termName, netName ); + } + } + + assert(node == latch_get_output( latch )); + netName = node_oct_name( node ); + termName = lib_gate_pin_name( gate, 0, 0 ); + oct_connect_instance_term( facet, &instance, termName, netName ); + + temp = latch_get_control( latch ); + if (temp != NIL(node_t)){ + assert(temp->type == PRIMARY_OUTPUT); + fanin = node_get_fanin(temp, 0); + netName = node_oct_name( fanin ); + termName = lib_gate_pin_name( gate, 0, 2 ); + oct_connect_instance_term( facet, &instance, termName, netName ); + } + + /* write out the initial value with the INSTANCE */ + OH_ASSERT(ohCreatePropInt(&instance, &prop, "INITIAL_VALUE", + latch_get_initial_value(latch))); + + } else { + errRaise( SIS_PKG_NAME, 1, "Cannot write generic latches into OCT yet." ); + } +} +#endif /* SIS */ + + +#ifdef SIS /* Support for writing clocks */ + +#define DONE_RISE_TRANSITION 1 +#define DONE_FALL_TRANSITION 2 +#define DONE_BOTH_TRANSITION 3 + +/* + * Utility routine that will get the name of the node representing the clock + * This is required since short names may be used during writing. So we + * cannot use the names stored with the sis_clock_t structures + */ +static char * +octio_clock_name(clock, short_flag) +sis_clock_t *clock; +int short_flag; +{ + node_t *node; + extern char *io_name(); /* Should be in io.h */ + + node = network_find_node(clock->network, clock_name(clock)); + assert(node != NIL(node_t)); + return io_name(node, short_flag); +} + +static void +doEdge( edge, clockEventsBag, done_table ) + clock_edge_t *edge; + octObject *clockEventsBag; + st_table *done_table; +{ + char prefix = edge->transition == RISE_TRANSITION ? 'r' : 'f'; + char buffer[256]; + double min, max; + octObject prop, eventBag; + int done; + char *dummy; + + if ( st_lookup_int( done_table, (char *)(edge->clock), &done ) ) { + if ( done == DONE_BOTH_TRANSITION ) return; + if ( done == DONE_RISE_TRANSITION && edge->transition == RISE_TRANSITION ) return; + if ( done == DONE_FALL_TRANSITION && edge->transition == FALL_TRANSITION ) return; + + done = DONE_BOTH_TRANSITION; + } else { + done = (edge->transition == RISE_TRANSITION) ? DONE_RISE_TRANSITION : DONE_FALL_TRANSITION; + } + + (void)sprintf(buffer, "%c'%s", prefix, octio_clock_name(edge->clock, 0 ) ); + max = clock_get_parameter(*edge, CLOCK_UPPER_RANGE); + min = clock_get_parameter(*edge, CLOCK_LOWER_RANGE); + + /* + (void)fprintf (sisout, "%s %lf %lf\n", buffer, min, max ); + */ + + OH_ASSERT(ohCreateBag(clockEventsBag, &eventBag, "EVENT" )); + ohCreatePropStr( &eventBag, &prop, "DESCRIPTION", buffer ); + ohCreatePropReal( &eventBag, &prop, "MAX", max ); + ohCreatePropReal( &eventBag, &prop, "MIN", min ); + + (void) st_insert(done_table, (char *)(edge->clock), (char *)done); +} + +static void +write_gen_event(sisBag, clock, transition, done_table, short_flag) + octObject *sisBag; + sis_clock_t *clock; + int transition; + st_table *done_table; + int short_flag; +{ + octObject clockEventsBag, prop; + clock_edge_t edge, *new_edge; + lsGen gen; + char *dummy; + int done; + char prefix; + + edge.transition = transition; + edge.clock = clock; + + if (clock_get_parameter(edge, CLOCK_NOMINAL_POSITION) == CLOCK_NOT_SET) { + return; + } + + OH_ASSERT(ohCreateBag( sisBag, &clockEventsBag, "CLOCK_EVENTS")); + OH_ASSERT(ohCreatePropReal( &clockEventsBag, &prop, "TIME", + clock_get_parameter(edge, CLOCK_NOMINAL_POSITION))); + + doEdge(&edge, &clockEventsBag, done_table ); + + gen = clock_gen_dependency(edge); + while (lsNext(gen, (char **)&new_edge, LS_NH) == LS_OK) { + doEdge( new_edge, &clockEventsBag, done_table ); + } + lsFinish(gen); +} + +/* + * To write out clock data-str into SIS . Look at oct_read.c for a + * description of the SIS_CLOCKS policy. + */ + +write_oct_clocks(network, facet, short_flag ) + network_t *network; + octObject *facet; + int short_flag; /* whether to use long or short names */ +{ + int first = 1; + lsGen gen; + sis_clock_t *clock; + node_t *node; + double cycle; + st_table *done_table; + octObject sisBag, prop; + int trans; + + ohGetOrCreateBag( facet, &sisBag, "SIS_CLOCKS" ); + ohRecursiveDelete( &sisBag, OCT_BAG_MASK | OCT_PROP_MASK ); + OH_ASSERT(ohGetOrCreateBag( facet, &sisBag, "SIS_CLOCKS")); + + cycle = clock_get_cycletime(network); + if (cycle > 0) { + ohGetOrCreatePropReal( &sisBag, &prop, "CYCLETIME", cycle ); + } + + done_table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_clock (network, gen, clock) { + if (st_lookup_int(done_table, (char *) clock, &trans) != 0) { + + switch (trans) { + case DONE_BOTH_TRANSITION: + break; + case DONE_FALL_TRANSITION: + + write_gen_event(&sisBag, clock, RISE_TRANSITION, done_table, + short_flag); + break; + default: + write_gen_event(&sisBag, clock, FALL_TRANSITION, done_table, + short_flag); + } + } else { + write_gen_event(&sisBag, clock, RISE_TRANSITION, done_table, short_flag); + (void) st_lookup_int(done_table, (char *) clock, &trans); + if (trans != DONE_BOTH_TRANSITION) { + write_gen_event(&sisBag, clock, FALL_TRANSITION, done_table, + short_flag); + } + } + } + st_free_table(done_table); +} +#endif /* SIS */ + + +void +write_oct(network, facet) + network_t **network; + octObject *facet; +/* + * write_oct: write a network out into an Oct facet (procedural interface) + * + */ +{ + octObject instance, net, term, prop, bag; + char *termName, *nodeName, *inTermName, *inNetName; + char *masterCell, *masterView; + int input, i; + array_t *nodes; + node_t *node, *fanin; +#ifdef SIS + int is_mapped; + latch_t *latch; +#endif + node_function_t funct; + + if (octOpenFacet(facet) < OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, + "can not open %s (%s)", + ohFormatName(facet), + octErrorString()); + } + + attachPolicyProperties(facet); + + /* flush the facet (side effect to create directory for GENERIC masters) */ + OH_ASSERT(octFlushFacet(facet)); + + OH_ASSERT(ohCreatePropStr(facet, &prop, "CELLCLASS", "MODULE")); + + /* get a few needed items */ + octCellPath = com_get_flag("OCT-CELL-PATH"); + if ((octCellView = com_get_flag("OCT-CELL-VIEW")) == NIL(char)) { + octCellView = "physical"; + } + + OH_ASSERT(ohGetOrCreateBag(facet, &bag, "INSTANCES")); + + initialize_net_table(); + +#ifdef SIS + /* Write out the clock information */ + write_oct_clocks(*network, facet, 0 /* Use long names */); + is_mapped = lib_network_is_mapped(*network); +#endif /* SIS */ + + /* loop over all nodes in the network from the inputs */ + + nodes = network_dfs(*network); + + for (i = 0; i < array_n(nodes); i++) { + node = array_fetch(node_t *, nodes, i); +#ifdef SIS + /* Skip the internal node corresponding to mapped latches */ + if (is_mapped && node->type == INTERNAL && + lib_gate_type(lib_gate_of(node)) != COMBINATIONAL){ + continue; + } + + if ( (latch = latch_from_node( node )) != NIL(latch_t) ) { + /* Skip the PO corrsponding to the latch input */ + if (node->type == PRIMARY_OUTPUT) continue; + + create_latch(facet, node, latch ); + continue; + } +#endif /* SIS */ + funct = node_function(node); + + switch (funct) { + + case NODE_PO: +#ifdef SIS + if (network_is_real_po(*network, node ) ) { + create_primary_output( facet, node ); + } +#else + create_primary_output( facet, node ); +#endif /* SIS */ + break; + case NODE_PI: +#ifdef SIS + if (network_is_real_pi(*network, node ) ) { + create_primary_input( facet, node ); + } +#else + create_primary_input( facet, node ); +#endif /* SIS */ + break; + default: + + + nodeName = node_oct_name(node); + + oct_lib_get_gate_cell_and_view(node, facet, &masterCell, &masterView); + + /* instantiate the master */ + OH_ASSERT(ohCreateInst(facet, &instance, nodeName, masterCell, masterView)); + OH_ASSERT(octAttach(&bag, &instance)); + + /* connect up the inputs */ + + foreach_fanin(node, input, fanin) { + inTermName = oct_lib_get_pin_name(node, input); + inNetName = node_oct_name(fanin); + oct_connect_instance_term( facet, &instance, inTermName, inNetName ); + } + + termName = oct_lib_get_out_pin_name(node, 0); + oct_connect_instance_term( facet, &instance, termName, nodeName ); + + attachLogicFunction(&term, node); + } + } + + createInterface(facet); + + OH_ASSERT(octCloseFacet(facet)); + + /* free up some space */ + st_free_table(NetTable); + + return; +} + + + +static jmp_buf sis_oct_error_buf; + +static void +sis_oct_error_handler(pkgName, code, message) +char *pkgName; +int code; +char *message; +{ + (void) fprintf(stderr, "%s: error (%d)\n\t%s\n", pkgName, code, message); + (void) longjmp(sis_oct_error_buf, -1); + return; +} + + +int +external_write_oct(network, argc, argv) + network_t **network; + int argc; + char **argv; +/* + * write_oct: write a network out into an Oct facet + * + */ +{ + octObject facet; + + + if (argc != 2) { + (void) fprintf(siserr, "usage: write_oct cell[:view]\n"); + return(1); + } + + octBegin(); + + if (setjmp(sis_oct_error_buf) == 0) { + errPushHandler(sis_oct_error_handler); + + (void) ohUnpackDefaults(&facet, "w", ":logic:contents"); + if (ohUnpackFacetName(&facet, argv[1]) != OCT_OK) { + errRaise(SIS_PKG_NAME, OCT_ERROR, "usage: write_oct cell[:view]"); + } + + error_init(); + write_oct(network, &facet); + errPopHandler(); + } else { + return 1; /* Error detected. */ + } + + octEnd(); + + return 0; /* OK. */ +} + +#endif /* OCT */ diff --git a/sis/order/Makefile.am b/sis/order/Makefile.am new file mode 100644 index 0000000..994b6ca --- /dev/null +++ b/sis/order/Makefile.am @@ -0,0 +1,7 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = liborder.a +liborder_a_SOURCES = dfs_order.c random_order.c +pkginclude_HEADERS = order.h +dist_doc_DATA = order.doc diff --git a/sis/order/Makefile.in b/sis/order/Makefile.in new file mode 100644 index 0000000..d0ef22b --- /dev/null +++ b/sis/order/Makefile.in @@ -0,0 +1,418 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(liborder_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/order +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +liborder_a_AR = $(AR) $(ARFLAGS) +liborder_a_LIBADD = +am_liborder_a_OBJECTS = dfs_order.$(OBJEXT) random_order.$(OBJEXT) +liborder_a_OBJECTS = $(am_liborder_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(liborder_a_SOURCES) +DIST_SOURCES = $(liborder_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = liborder.a +liborder_a_SOURCES = dfs_order.c random_order.c +pkginclude_HEADERS = order.h +dist_doc_DATA = order.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/order/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/order/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +liborder.a: $(liborder_a_OBJECTS) $(liborder_a_DEPENDENCIES) + -rm -f liborder.a + $(liborder_a_AR) liborder.a $(liborder_a_OBJECTS) $(liborder_a_LIBADD) + $(RANLIB) liborder.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/order/dfs_order.c b/sis/order/dfs_order.c new file mode 100644 index 0000000..2c77727 --- /dev/null +++ b/sis/order/dfs_order.c @@ -0,0 +1,406 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/order/dfs_order.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include "sis.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/order/dfs_order.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * $Log: dfs_order.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:51 pchong + * imported + * + * Revision 1.3 1992/05/06 18:58:25 sis + * SIS release 1.1 + * + * Revision 1.3 1992/05/06 18:58:25 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 22:06:10 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:43:56 sis + * Initial revision + * + * Revision 1.1 91/04/01 00:52:30 shiple + * Initial revision + * + * + */ + +/* for order nodes */ +typedef struct { + node_t *node; + int level; + int max_leaf; +} info_t ; + +static int max_leaf_cmp(); +static int propagate_max_leaf_from_fanins(); +static void extract_transitive_fanin(); +static void order_nodes_rec(); +static void propagate_level_thru_factored_form(); +static void propagate_level_to_fanins(); +static void visit_inputs_first(); +static void visit_outputs_first(); + +/* + * order_dfs - Find a good ordering for the nodes. + * The second argument is a hash table. + * Each node that requires ordering is stored in the hash table + * as a key; the value associated to it should be -1. + * The ordering is done by replacing the -1's by variable orders. + * + * Returns an array of nodes in the order of traversal. This used to be used + * to specify in which order the nodes of the transistive fanin should be + * visited when creating the BDD of a root. Simple recursion from the root + * seems to work as well. + * + * Only touches the part of the network that is both in the transitive fanin + * of nodes in roots and in the transitive fanout of nodes in leaves. + * As a consistency condition, it is required that every path from roots to + * a primary input is cut by a node in leaves. Otherwise -> error. + * + * This function was known historically as bdd_sharad_order. + */ +array_t *order_dfs(roots, leaves, fixed_root_order) +array_t *roots; /* root nodes: their transitive fanin has to be ordered */ +st_table *leaves; /* where the dfs search stops: those nodes have to be ordered */ +int fixed_root_order; /* flag: if set, can't change the order of visit of the roots */ +{ + int order_count; + node_t *node; + st_generator *gen; + array_t *tfi_inputs_first, *tfi_outputs_first; + array_t *order_list, *internal_roots; + st_table *info_table, *visited; + info_t *info; + int i; + + if(array_n(roots) == 0) { + assert(st_count(leaves) == 0); + return NIL(array_t); + } + + /* replace PO's by their fanins */ + internal_roots = array_alloc(node_t *, 0); + for(i = 0; i < array_n(roots); i++) { + node = array_fetch(node_t *, roots, i); + if (node->type == PRIMARY_OUTPUT) { + node = node_get_fanin(node, 0); + } + array_insert_last(node_t *, internal_roots, node); + } + + /* form dfs array */ + tfi_inputs_first = array_alloc(node_t *, 0); + tfi_outputs_first = array_alloc(node_t *, 0); + (void) extract_transitive_fanin(internal_roots, leaves, tfi_inputs_first, tfi_outputs_first); + + /* initialize info_table */ + info_table = st_init_table(st_ptrcmp, st_ptrhash); + for(i = 0; i < array_n(tfi_inputs_first); i++) { + node = array_fetch(node_t *, tfi_inputs_first, i); + info = ALLOC(info_t, 1); + info->node = node; + info->level = 0; + info->max_leaf = 0; + (void) st_insert(info_table, (char *) node, (char *) info); + } + + /* compute level information: levelize from outputs to inputs */ + for (i = 0; i < array_n(tfi_outputs_first); i++) { + node = array_fetch(node_t *, tfi_outputs_first, i); + if (st_lookup(leaves, (char *) node, NIL(char *))) + continue; + (void) propagate_level_to_fanins(node, info_table); + } + array_free(tfi_outputs_first); + + /* compute max_leaf fields */ + for (i = 0; i < array_n(tfi_inputs_first); i++) { + node = array_fetch(node_t *, tfi_inputs_first, i); + assert(st_lookup(info_table, (char *) node, (char **) &info)); + if (st_lookup(leaves, (char *) node, NIL(char *))) { + info->max_leaf = info->level; + continue; + } + info->max_leaf = propagate_max_leaf_from_fanins(node, info_table); + } + array_free(tfi_inputs_first); + + /* if fixed root order, take care of that */ + if (fixed_root_order) { + for (i = 0; i < array_n(internal_roots); i++) { + node = array_fetch(node_t *, internal_roots, i); + assert(st_lookup(info_table, (char *) node, (char **) &info)); + info->max_leaf = 0; + info->level = i; + } + } + + /* all the bookkeeping done, go ahead and order */ + order_count = 0; + order_list = array_alloc(node_t *, 0); + visited = st_init_table(st_ptrcmp, st_ptrhash); + (void) order_nodes_rec(internal_roots, info_table, visited, leaves, order_list, &order_count); + assert(order_count <= st_count(leaves)); + + st_foreach_item(info_table, gen, (char **) &node, (char **) &info) { + FREE(info); + } + (void) st_free_table(info_table); + (void) st_free_table(visited); + (void) array_free(internal_roots); + + return order_list; +} + +/* + * Returns an array of the nodes in the transistive fanin of roots, in DFS + * order. Note that the leaves in the TFI are not put into the return array. + * TODO: this function is not currently used anywhere. Historically, it was + * used to provide an alternative to the node ordering returned by Sharad's + * ordering technique. + */ +array_t *bdd_tfi_inputs_first(roots, leaves) +array_t *roots; +st_table *leaves; +{ + int i; + node_t *node; + array_t *tfi_inputs_first = array_alloc(node_t *, 0); + st_table *tfi = st_init_table(st_ptrcmp, st_ptrhash); + + for (i = 0; i < array_n(roots); i++) { + node = array_fetch(node_t *, roots, i); + (void) visit_inputs_first(node, leaves, tfi, tfi_inputs_first); + (void) array_insert_last(node_t *, tfi_inputs_first, node); + (void) st_insert(tfi, (char *) node, NIL(char)); /* tfi table just used for quick searching */ + } + (void) st_free_table(tfi); + return tfi_inputs_first; +} + + +/* + * Extract nodes in transitive fanin of nodes in roots, + * but stop at nodes in table "leaves." + */ +static void extract_transitive_fanin(roots, leaves, tfi_inputs_first, tfi_outputs_first) +array_t *roots; +st_table *leaves; +array_t *tfi_inputs_first; +array_t *tfi_outputs_first; +{ + int i; + node_t *node; + st_generator *gen; + st_table *tfi = st_init_table(st_ptrcmp, st_ptrhash); + st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); + + for (i = 0; i < array_n(roots); i++) { + node = array_fetch(node_t *, roots, i); + (void) visit_inputs_first(node, leaves, tfi, tfi_inputs_first); + } + st_foreach_item(leaves, gen, (char **) &node, NIL(char *)) { + (void) visit_outputs_first(node, visited, tfi, tfi_outputs_first); + } + (void) st_free_table(visited); + (void) st_free_table(tfi); +} + +/* + * The transitive fanin of node limited to the tfi. + * It is an error if find a PRIMARY INPUT not in leaves. + */ +static void visit_inputs_first(node, leaves, tfi, tfi_inputs_first) +node_t *node; +st_table *leaves; +st_table *tfi; +array_t *tfi_inputs_first; +{ + int i; + node_t *fanin; + + /* + * If the node has already been visited, then return. + */ + if (st_lookup(tfi, (char *) node, NIL(char *))) return; + + /* + * Process the node if it's not a leaf. If it's not a constant, then + * it must have fanin. Visit each fanin. + */ + if (! st_lookup(leaves, (char *) node, NIL(char *))) { + if (node_function(node) != NODE_0 && node_function(node) != NODE_1) { + assert(node_num_fanin(node) > 0); + foreach_fanin(node, i, fanin) { + (void) visit_inputs_first(fanin, leaves, tfi, tfi_inputs_first); + } + } + } + (void) array_insert_last(node_t *, tfi_inputs_first, node); + (void) st_insert(tfi, (char *) node, NIL(char)); +} + +static void visit_outputs_first(node, visited, tfi, tfi_outputs_first) +node_t *node; +st_table *visited; +st_table *tfi; +array_t *tfi_outputs_first; +{ + lsGen gen; + node_t *fanout; + + if (! st_lookup(tfi, (char *) node, NIL(char *))) return; + if (st_lookup(visited, (char *) node, NIL(char *))) return; + foreach_fanout(node, gen, fanout) { + (void) visit_outputs_first(fanout, visited, tfi, tfi_outputs_first); + } + (void) array_insert_last(node_t *, tfi_outputs_first, node); + (void) st_insert(visited, (char *) node, NIL(char)); +} + + + /* level propagation through factored nodes */ + +static void propagate_level_to_fanins(node, info_table) +node_t *node; +st_table *info_table; +{ + int i; + info_t *info; + int level; + node_t *factor_node; + array_t *factor_array = factor_to_nodes(node); + st_table *factor_table = st_init_table(st_ptrcmp, st_ptrhash); + + for (i = 0; i < array_n(factor_array); i++) { + factor_node = array_fetch(node_t *, factor_array, i); + (void) st_insert(factor_table, (char *) factor_node, NIL(char)); + } + factor_node = array_fetch(node_t *, factor_array, 0); + assert(st_lookup(info_table, (char *) node, (char **) &info)); + level = info->level; + (void) propagate_level_thru_factored_form(factor_node, level, factor_table, info_table); + for (i = 0; i < array_n(factor_array); i++) { + factor_node = array_fetch(node_t *, factor_array, i); + (void) node_free(factor_node); + } + (void) array_free(factor_array); + (void) st_free_table(factor_table); +} + +static void propagate_level_thru_factored_form(node, level, factor_table, info_table) +node_t *node; +int level; +st_table *factor_table, *info_table; +{ + int i; + node_t *fanin; + info_t *info; + + foreach_fanin(node, i, fanin) { + if (st_lookup(factor_table, (char *) fanin, NIL(char *))) { + (void) propagate_level_thru_factored_form(fanin, level + 1, factor_table, info_table); + continue; + } + assert(st_lookup(info_table, (char *) fanin, (char **) &info)); + info->level = MAX(info->level, level + 1); + } +} + + /* compute max_leaf from inputs to outputs */ + +static int propagate_max_leaf_from_fanins(node, info_table) +node_t *node; +st_table *info_table; +{ + int i; + info_t *info; + node_t *fanin; + int max_leaf = 0; + + foreach_fanin(node, i, fanin) { + assert(st_lookup(info_table, (char *) fanin, (char **) &info)); + max_leaf = MAX(max_leaf, info->max_leaf); + } + return max_leaf; +} + + /* order nodes using dfs. Break ties using max_leaf_cmp */ + +static void order_nodes_rec(roots, info_table, visited, leaves, node_list, order_count) +array_t *roots; +st_table *info_table; +st_table *visited; +st_table *leaves; +array_t *node_list; +int *order_count; +{ + int *slot; + array_t *info_array, *fanin_array; + int i, j; + node_t *node, *fanin; + info_t *info; + + /* sort current list of roots according to their max_leaf entry */ + info_array = array_alloc(info_t *, 0); + for (i = 0; i < array_n(roots); i++) { + node = array_fetch(node_t *, roots, i); + if (st_lookup(visited, (char *) node, NIL(char *))) continue; + assert(st_lookup(info_table, (char *) node, (char **) &info)); + (void) array_insert_last(info_t *, info_array, info); + } + (void) array_sort(info_array, max_leaf_cmp); + + /* continue traversal in dfs mode; stop at leaves ("leaves" nodes) */ + /* need to check for visited here because a node can appear several times */ + /* in info_array */ + for (i = 0; i < array_n(info_array); i++) { + info = array_fetch(info_t *, info_array, i); + node = info->node; + if (st_lookup(visited, (char *) node, NIL(char *))) continue; + if (st_find(leaves, (char *) node, (char ***) &slot)) { + *slot = (*order_count)++; + } else { + fanin_array = array_alloc(node_t *, 0); + foreach_fanin(node, j, fanin) { + (void) array_insert_last(node_t *, fanin_array, fanin); + } + (void) order_nodes_rec(fanin_array, info_table, visited, leaves, node_list, order_count); + (void) array_free(fanin_array); + } + (void) array_insert_last(node_t *, node_list, node); + (void) st_insert(visited, (char *) node, NIL(char)); + } + (void) array_free(info_array); +} + + + /* break ties using first depth, then level */ + /* deeper->higher priority; otherwise lower level->higher priority */ + +static int max_leaf_cmp(key1, key2) +char **key1, **key2; +{ + info_t *info1 = *((info_t **) key1); + info_t *info2 = *((info_t **) key2); + + if (info1->max_leaf == info2->max_leaf) { + return info1->level - info2->level; + } else { + return - (info1->max_leaf - info2->max_leaf); + } +} diff --git a/sis/order/order.doc b/sis/order/order.doc new file mode 100644 index 0000000..ad5b2f9 --- /dev/null +++ b/sis/order/order.doc @@ -0,0 +1,78 @@ + +Order Package, Version 1.0 + +Tom Shiple (original contributors: Herve' Touati, Sharad Malik) +University of California, Berkeley, 1991 + + +Introduction ----------------------------------------------------------------- + +The Order package provides routines to create an ordering of BDD variables, +using the structure of SIS networks. The goal is to find a good ordering +so that the resulting BDD's will be as small as possible. + + +Summary ----------------------------------------------------------------------- + + order_dfs() + order_random() + + +Description of Functions ------------------------------------------------------ + +array_t * +order_dfs(roots, leaves, fixed_root_order) +array_t *roots; +st_table *leaves; +int fixed_root_order; + + Uses an ordering based on depth first search and the level of a node. + See S. Malik, et. al. "Logic Verification using Binary Decision + Diagrams in a Logic Synthesis Environment," ICCAD, 1988. `roots' is + an array of node_t *'s which are the nodes for which you want to + create BDD's. `leaves' is a hash table of node_t *'s to ints. The + nodes in leaves represent the variables of the BDD's to be created. + Each value in the hash table should be initialized by the user to -1. + This function will replace the -1's by integers from 0 to n-1. + + Every path from any root node to any primary input must contain + at least one node in the leaves. Otherwise, an error will result. + + If fixed_root_order is set, the order in which the roots are visited + cannot be altered. + + In addition to setting the values in leaves, this routine returns an + array of node_t *'s. This array contains an ordered list of all the + nodes in the intersection of the transitive fanin of the roots and + the union of the transistive fanouts of the leaves. This provides an + order in which to visit the nodes of the network to create BDD's. + Recent experimentation shows that any topological ordering will + suffice, and subsequently, this array is not used by any functions in + the NTBDD package. Be sure to free this returned array. + + The order_method_t enumerated type of DFS_ORDER is associated with + this routine. + +array_t * +order_random(roots, leaves, dummy) +array_t *roots; +st_table *leaves; +int dummy; + + Uses an random ordering. The seed used for the random number + generator is simply the address of leaves. `leaves' is a hash table of + node_t *'s to ints. The nodes in leaves represent the variables of + the BDD's to be created. Each value in the hash table should be + initialized by the user to -1. This function will replace the -1's by + integers from 0 to n-1. + + This routine is meant to have the same interface as dfs_order. + `roots' and `dummy' are never used by this routine. Furthermore, this + routine returns NIL(array_t). + + The order_method_t enumerated type of RANDOM_ORDER is associated with + this routine. + + + + diff --git a/sis/order/order.h b/sis/order/order.h new file mode 100644 index 0000000..6c14d90 --- /dev/null +++ b/sis/order/order.h @@ -0,0 +1,55 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/order/order.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#ifndef ORDER_H /* { */ +#define ORDER_H + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/order/order.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * $Log: order.h,v $ + * Revision 1.1.1.1 2004/02/07 10:14:52 pchong + * imported + * + * Revision 1.4 1993/05/28 23:19:35 sis + * Aesthetic changes to prototypes. + * + * Revision 1.3 1992/05/06 18:58:25 sis + * SIS release 1.1 + * + * Revision 1.3 1992/05/06 18:58:25 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 22:06:10 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:43:57 sis + * Initial revision + * + * Revision 1.2 91/05/01 17:37:26 shiple + * convert to new declaration format using EXTERN and ARGS + * + * Revision 1.1 91/04/01 00:53:14 shiple + * Initial revision + * + * + */ + +/* + * Variable ordering methods + */ +EXTERN array_t *order_dfs ARGS((array_t *, st_table *, int)); +EXTERN array_t *order_random ARGS((array_t *, st_table *, int)); +typedef enum {DFS_ORDER, RANDOM_ORDER} order_method_t; + +#endif /* } */ diff --git a/sis/order/random_order.c b/sis/order/random_order.c new file mode 100644 index 0000000..289066f --- /dev/null +++ b/sis/order/random_order.c @@ -0,0 +1,94 @@ +#include "sis.h" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/order/random_order.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * $Log: random_order.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:52 pchong + * imported + * + * Revision 1.5 1993/02/25 01:02:46 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.5 1993/02/25 01:02:46 sis + * Shiple updates; 2/24/93. See Shiple's RCS message. + * + * Revision 1.2 1993/01/11 23:28:20 shiple + * Made change to call to st_foreach_item for DEC Alpha compatibility. + * + * Revision 1.1 1991/04/01 00:53:36 shiple + * Initial revision + * + * + */ + +static int *random_permutation(); + +array_t *order_random(roots, leaves, dummy) +array_t *roots; +st_table *leaves; +int dummy; /* to give it the same interface as order_dfs */ +{ + int seed; + int counter; + st_generator *gen; + char *key; + int value; + int *permutation; + + seed = (int) leaves; + permutation = random_permutation(seed, st_count(leaves)); + if (permutation == NIL(int)) return NIL(array_t); + counter = 0; + st_foreach_item_int(leaves, gen, &key, &value) { + if (!st_insert(leaves, (char *)key, (char *)permutation[counter++])){ + fail ("order_random: expecting value to be initialized to -1"); + } + } + FREE(permutation); + return NIL(array_t); +} + +/* + * Computes a random permutation; returned as an array of integers from 0 to n_elts-1. + */ +static int *random_permutation(seed, n_elts) +int seed; +int n_elts; +{ + int i, j; + int *permutation; + int *remaining; + int next_entry; + int next_value; + int n_entries; + /* Declaration for random shouldn't be necessary (pick up from util.h). */ + /* Declaring it here breaks hpux. */ + /* extern long random(); */ + + if (n_elts <= 0) return NIL(int); + + n_entries = n_elts; + permutation = ALLOC(int, n_entries); + remaining = ALLOC(int, n_entries); + for (i = 0; i < n_entries; i++) { + remaining[i] = i; + } + + srandom(seed); + + next_entry = 0; + for (; n_entries > 0; n_entries--) { + next_value = random() % n_entries; + permutation[next_entry++] = remaining[next_value]; + for (j = next_value; j < n_entries - 1; j++) { + remaining[j] = remaining[j + 1]; + } + } + FREE(remaining); + return permutation; +} diff --git a/sis/phase/Makefile.am b/sis/phase/Makefile.am new file mode 100644 index 0000000..9406adb --- /dev/null +++ b/sis/phase/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libphase.a +libphase_a_SOURCES = ai.c com_ph.c greedy.c phase.c phase_lib.c \ + phase_int.h +pkginclude_HEADERS = phase.h +dist_doc_DATA = phase.doc diff --git a/sis/phase/Makefile.in b/sis/phase/Makefile.in new file mode 100644 index 0000000..d9068ed --- /dev/null +++ b/sis/phase/Makefile.in @@ -0,0 +1,421 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libphase_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/phase +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libphase_a_AR = $(AR) $(ARFLAGS) +libphase_a_LIBADD = +am_libphase_a_OBJECTS = ai.$(OBJEXT) com_ph.$(OBJEXT) greedy.$(OBJEXT) \ + phase.$(OBJEXT) phase_lib.$(OBJEXT) +libphase_a_OBJECTS = $(am_libphase_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libphase_a_SOURCES) +DIST_SOURCES = $(libphase_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libphase.a +libphase_a_SOURCES = ai.c com_ph.c greedy.c phase.c phase_lib.c \ + phase_int.h + +pkginclude_HEADERS = phase.h +dist_doc_DATA = phase.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/phase/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/phase/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libphase.a: $(libphase_a_OBJECTS) $(libphase_a_DEPENDENCIES) + -rm -f libphase.a + $(libphase_a_AR) libphase.a $(libphase_a_OBJECTS) $(libphase_a_LIBADD) + $(RANLIB) libphase.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/phase/ai.c b/sis/phase/ai.c new file mode 100644 index 0000000..db68a5e --- /dev/null +++ b/sis/phase/ai.c @@ -0,0 +1,76 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/phase/ai.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#include "sis.h" + + +void +add_inv_network(network) +network_t *network; +{ + int i; + array_t *nodevec; + + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + (void) add_inv_node(network, array_fetch(node_t *, nodevec, i)); + } + array_free(nodevec); +} + + +int +add_inv_node(network, f) +network_t *network; +node_t *f; +{ + node_t *inv, *flit, *fpos, *g, *q, *r, *gnew, *temp; + bool changed; + lsGen gen; + + /* try to find an inverter which is already in our fanout */ + inv = NIL(node_t); + foreach_fanout(f, gen, g) { + if (node_function(g) == NODE_INV) { + inv = g; + (void) lsFinish(gen); + break; + } + } + + changed = FALSE; + flit = node_literal(f, 1); + foreach_fanout(f, gen, g) { + if (g->type != PRIMARY_OUTPUT) { + /* divide by the positive literal of f -- check for nonzero q */ + q = node_div(g, flit, &r); + if (node_function(q) != NODE_0) { + + /* create an inverter if we don't have one so far */ + if (inv == NIL(node_t)) { + inv = node_literal(f, 0); + network_add_node(network, inv); + } + + /* munge the fanout so it depends on the inverter */ + fpos = node_literal(inv, 0); + temp = node_and(q, fpos); + gnew = node_or(temp, r); + node_replace(g, gnew); + node_free(temp); + node_free(fpos); + changed = TRUE; + } + node_free(q); + node_free(r); + } + } + node_free(flit); + return changed; +} diff --git a/sis/phase/com_ph.c b/sis/phase/com_ph.c new file mode 100644 index 0000000..17d14e4 --- /dev/null +++ b/sis/phase/com_ph.c @@ -0,0 +1,134 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/phase/com_ph.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#include "sis.h" +#include "phase.h" +#include "phase_int.h" + +int +com_phase_assign(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, method; + int num; + + method = 0; + util_getopt_reset(); + phase_trace_unset(); + phase_check_unset(); + while ((c = util_getopt(argc, argv, "r:cqgst")) != EOF) { + switch (c) { + case 'c': + phase_check_set(); + break; + case 'q': + method = 0; + break; + case 'g': + method = 1; + break; + case 'r': + method = 3; + num = atoi(util_optarg); + if (num <= 0) { + phase_usage(); + return 1; + } + break; + case 's': + method = 2; + break; + case 't': + phase_trace_set(); + break; + default: + phase_usage(); + return 1; + } + } + + if (argc - util_optind != 0) { + phase_usage(); + return 1; + } + + switch (method) { + case 0: + phase_quick(*network); + break; + case 1: + phase_good(*network); + break; + case 2: + (void) fprintf(misout, "simulated annealing "); + (void) fprintf(misout, "method has not been implemented\n"); + break; + case 3: + phase_random_greedy(*network, num); + break; + default: + fail("com_phase_assign: unknown method"); + } + + return 0; +} + +int +com_add_inv(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *nodevec; + int i, n; + node_t *np; + + if (argc == 1) { + add_inv_network(*network); + return 0; + } + + nodevec = com_get_nodes(*network, argc, argv); + n = array_n(nodevec); + for(i = 0; i < n; i++) { + np = array_fetch(node_t *, nodevec, i); + switch (np->type) { + case PRIMARY_OUTPUT: + break; + default: + (void) add_inv_node(*network, np); + } + } + array_free(nodevec); + return 0; +} + +init_phase() +{ + phase_trace_unset(); + phase_check_unset(); + com_add_command("phase", com_phase_assign, 1); + com_add_command("add_inverter", com_add_inv, 1); +} + +end_phase() +{ +} + +phase_usage() +{ + (void) fprintf(miserr, "usage: phase [-gqst] [-r n]\n"); + (void) fprintf(miserr, " -g Good phase\n"); + (void) fprintf(miserr, " -q Quick phase\n"); + (void) fprintf(miserr, " -s Simulated annealing\n"); + (void) fprintf(miserr, " -t Trace\n"); + (void) fprintf(miserr, " -r n Random greedy (n > 0)\n"); +} diff --git a/sis/phase/greedy.c b/sis/phase/greedy.c new file mode 100644 index 0000000..59379dd --- /dev/null +++ b/sis/phase/greedy.c @@ -0,0 +1,143 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/phase/greedy.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:47 $ + * + */ +#include "sis.h" +#include "phase.h" +#include "phase_int.h" + +static void greedy_down(); +static bool KL_up(); + +void +phase_random_greedy(network, num) +network_t *network; +int num; /* number of random assignment */ +{ + net_phase_t *net_phase, *best_net_phase; + int i; + double cost; + bool trace; + + if (phase_trace) { + trace = TRUE; + phase_trace_unset(); + } else { + trace = FALSE; + } + + net_phase = phase_setup(network); + + best_net_phase = phase_dup(net_phase); + for (i = 0; i < num; i++) { + phase_random_assign(net_phase); + cost = network_cost(net_phase); + greedy_down(net_phase); + + if (trace) { + (void) fprintf(misout, "%3d random assignment: ", i+1); + (void) fprintf(misout, "%6f -> ", cost); + (void) fprintf(misout, "%6f\n", network_cost(net_phase)); + } + + if (network_cost(net_phase) < network_cost(best_net_phase)) { + phase_free(best_net_phase); + best_net_phase = phase_dup(net_phase); + } + } + + phase_record(network, best_net_phase); + phase_free(net_phase); + phase_free(best_net_phase); +} + +void +phase_quick(network) +network_t *network; +{ + net_phase_t *net_phase; + + net_phase = phase_setup(network); + + greedy_down(net_phase); + + phase_record(network, net_phase); + phase_free(net_phase); +} + +void +phase_good(network) +network_t *network; +{ + net_phase_t *net_phase; + bool not_done; + + net_phase = phase_setup(network); + + not_done = TRUE; + while (not_done) { + greedy_down(net_phase); + not_done = KL_up(net_phase); + } + + phase_record(network, net_phase); + phase_free(net_phase); +} + +static void +greedy_down(net_phase) +net_phase_t *net_phase; +{ + node_phase_t *node_phase; + + for (;;) { + node_phase = phase_get_best(net_phase); + if (node_phase != NIL(node_phase_t) && phase_value(node_phase) > 0) { + phase_invert(net_phase, node_phase); + } else { + break; + } + } +} + +/* + * Allow increase in number of inverters, but only flip a node + * once. Return TRUE as soon as a better network is found. + * If all the nodes are inverted and no better network is found, + * return FALSE. + */ +static bool +KL_up(net_phase) +net_phase_t *net_phase; +{ + net_phase_t *net_phase_best; + node_phase_t *node_phase; + + net_phase_best = phase_dup(net_phase); + + for (;;) { + node_phase = phase_get_best(net_phase); + + if (node_phase == NIL(node_phase_t)) { + /* no luck, all nodes are inverted */ + phase_replace(net_phase, net_phase_best); + phase_unmark_all(net_phase); + return FALSE; + } + + phase_invert(net_phase, node_phase); + phase_mark(node_phase); + + if (network_cost(net_phase) < network_cost(net_phase_best)) { + /* good!, a better network is found */ + phase_free(net_phase_best); + phase_unmark_all(net_phase); + return TRUE; + } + } +} diff --git a/sis/phase/phase.c b/sis/phase/phase.c new file mode 100644 index 0000000..4cc7e07 --- /dev/null +++ b/sis/phase/phase.c @@ -0,0 +1,718 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/phase/phase.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#include "sis.h" +#include "phase_int.h" + +#define THRESH 0.00001 + +#define inv_save_output(r) \ + ((r)->pos_used == 0 ? -1 : ((r)->neg_used == 0 ? 1 : 0)) +#define inv_save_input(r, e) \ + ((e)->phase == 0 && (r)->pos_used == 0 ? -1 : \ + ((e)->phase == 1 && (r)->pos_used == 1 ? 1 : 0)) + +static void inv_save_setup(); +static int inv_save_comp(); +static row_data_t *row_data_dup(); +static element_data_t *element_data_dup(); +static void check_phase(); +static void phase_do_invert(); +static bool fanout_to_po(); +static void phase_dec(); +static void phase_inc(); +static void phase_count_comp(); + + +bool phase_trace = FALSE; +bool phase_check = FALSE; + +static void +inv_save_setup(net_phase) +net_phase_t *net_phase; +{ + node_phase_t *node_phase; + row_data_t *rd; + int i; + + for (i = 0; i < array_n(net_phase->rows); i++) { + node_phase = array_fetch(node_phase_t *, net_phase->rows, i); + rd = sm_get(row_data_t *, node_phase->row); + rd->inv_save = inv_save_comp(net_phase, node_phase->row); + } +} + +static int +inv_save_comp(net_phase, row) +net_phase_t *net_phase; +sm_row *row; +{ + register sm_col *col; + register sm_element *element; + register row_data_t *rd, *rd1; + register element_data_t *ed; + register int count; + + rd = sm_get(row_data_t *, sm_get_row(net_phase->matrix, row->row_num)); + count = inv_save_output(rd); + + col = sm_get_col(net_phase->matrix, row->row_num); + if (col != NIL(sm_col)) { + sm_foreach_col_element(col, element) { + ed = sm_get(element_data_t *, element); + row = sm_get_row(net_phase->matrix, element->row_num); + rd1 = sm_get(row_data_t *, row); + count += inv_save_input(rd1, ed); + } + } + + return count; +} + +void +phase_invert(net_phase, node_phase) +net_phase_t *net_phase; +node_phase_t *node_phase; +{ + register sm_row *row, *fanin; + register sm_col *col; + register sm_element *element; + register row_data_t *rd; + double cost_save; + + row = node_phase->row; + col = sm_get_col(net_phase->matrix, row->row_num); + rd = sm_get(row_data_t *, row); + cost_save = net_phase->cost; + + if (!rd->invertible) { + fail("phase_invert: try to invert an non-invertible node"); + } + + net_phase->cost -= phase_value(node_phase); + + /* decrease the inverter savings of each fanout resulting from this node */ + phase_dec(net_phase, row); + + /* increase the inverter savings of each fanout resulting from this node */ + if (col != NIL(sm_col)) { /* warning: node may be a constant (no fanins) */ + sm_foreach_col_element(col, element) { + fanin = sm_get_row(net_phase->matrix, element->row_num); + phase_dec(net_phase, fanin); + } + } + + /* toggle the node and modify the row and col entries */ + phase_do_invert(net_phase, row); + + /* increase the inverter savings of each fanout resulting from this node */ + phase_inc(net_phase, row); + + /* increase the inverter savings of each fanout resulting from this node */ + if (col != NIL(sm_col)) { /* warning: node may be a constant (no fanins) */ + sm_foreach_col_element(col, element) { + fanin = sm_get_row(net_phase->matrix, element->row_num); + phase_inc(net_phase, fanin); + } + } + + if (phase_trace) { + (void) fprintf(misout, "inverting %-10s: ", node_name(rd->node)); + (void) fprintf(misout, "cost: %4.0f", cost_save); + (void) fprintf(misout, " -> %4.0f\n", net_phase->cost); + } + + if (phase_check) { + check_phase(net_phase); + } +} + +static void +phase_do_invert(net_phase, row) +net_phase_t *net_phase; +sm_row *row; +{ + register sm_col *col; + register sm_row *fanin; + register sm_element *element; + register element_data_t *ed; + register row_data_t *rd; + int temp; + + rd = sm_get(row_data_t *, row); + rd->inverted = 1 - rd->inverted; /* toggle the phase */ + temp = rd->neg_used; + rd->neg_used = rd->pos_used; + rd->pos_used = temp; + + sm_foreach_row_element(row, element) { + ed = sm_get(element_data_t *, element); + if (ed->phase != 2) { + ed->phase = 1 - ed->phase; + } + } + + col = sm_get_col(net_phase->matrix, row->row_num); + if (col != NIL(sm_col)) { /* warning: node may be a constant (no fanins) */ + sm_foreach_col_element(col, element) { + fanin = sm_get_row(net_phase->matrix, element->row_num); + rd = sm_get(row_data_t *, fanin); + ed = sm_get(element_data_t *, element); + switch (ed->phase) { + case 0: + ed->phase = 1; + rd->pos_used ++; + rd->neg_used --; + break; + case 1: + ed->phase = 0; + rd->pos_used --; + rd->neg_used ++; + break; + case 2: + break; + default: + fail("phase_do_invert: wrong phase at a element"); + } + } + } +} + +node_phase_t * +phase_get_best(net_phase) +net_phase_t *net_phase; +{ + register node_phase_t *node_phase, *best_phase; + register int i; + register row_data_t *rd; + double best, value; + + best_phase = NIL(node_phase_t); + best = -INFINITY; + for (i = 0; i < array_n(net_phase->rows); i++) { + node_phase = array_fetch(node_phase_t *, net_phase->rows, i); + rd = sm_get(row_data_t *, node_phase->row); + if (rd->invertible && !rd->marked) { + value = phase_value(node_phase); + if (value > best) { + best_phase = node_phase; + best = value; + } + } + } + + return best_phase; +} + +double +network_cost(net_phase) +net_phase_t *net_phase; +{ + return net_phase->cost; +} + +void +phase_unmark_all(net_phase) +net_phase_t *net_phase; +{ + register node_phase_t *node_phase; + register row_data_t *rd; + register int i; + + for (i = 0; i < array_n(net_phase->rows); i++) { + node_phase = array_fetch(node_phase_t *, net_phase->rows, i); + rd = sm_get(row_data_t *, node_phase->row); + rd->marked = FALSE; + } +} + +void +phase_mark(node_phase) +node_phase_t *node_phase; +{ + row_data_t *rd; + + rd = sm_get(row_data_t *, node_phase->row); + rd->marked = TRUE; +} + +net_phase_t * +phase_dup(net_phase) +net_phase_t *net_phase; +{ + register net_phase_t *new; + register sm_row *row, *new_row; + register sm_element *element, *new_element; + node_phase_t *node_phase, *temp; + row_data_t *rd; + element_data_t *ed; + int i; + + new = ALLOC(net_phase_t, 1); + + new->matrix = sm_dup(net_phase->matrix); + sm_foreach_row(new->matrix, new_row) { + row = sm_get_row(net_phase->matrix, new_row->row_num); + rd = sm_get(row_data_t *, row); + sm_put(new_row, row_data_dup(rd)); + sm_foreach_row_element(new_row, new_element) { + element = sm_row_find(row, new_element->col_num); + ed = sm_get(element_data_t *, element); + sm_put(new_element, element_data_dup(ed)); + } + } + + new->rows = array_alloc(node_phase_t *, array_n(net_phase->rows)); + for (i = 0; i < array_n(net_phase->rows); i++) { + temp = array_fetch(node_phase_t *, net_phase->rows, i); + node_phase = ALLOC(node_phase_t, 1); + node_phase->row = sm_get_row(new->matrix, temp->row->row_num); + array_insert_last(node_phase_t *, new->rows, node_phase); + } + + new->cost = net_phase->cost; + return new; +} + +void +phase_replace(old, new) +net_phase_t *old, *new; +{ + sm_matrix *matrix; + array_t *rows; + + matrix = old->matrix; + rows = old->rows; + + old->matrix = new->matrix; + old->rows = new->rows; + old->cost = new->cost; + + new->matrix = matrix; + new->rows = rows; + phase_free(new); +} + +static row_data_t * +row_data_dup(row_data) +row_data_t *row_data; +{ + row_data_t *new; + + new = ALLOC(row_data_t, 1); + new->pos_used = row_data->pos_used; + new->neg_used = row_data->neg_used; + new->inv_save = row_data->inv_save; + new->marked = row_data->marked; + new->invertible = row_data->invertible; + new->inverted = row_data->inverted; + new->po = row_data->po; + new->node = row_data->node; + + return new; +} + +static element_data_t * +element_data_dup(element_data) +element_data_t *element_data; +{ + element_data_t *new; + + new = ALLOC(element_data_t, 1); + new->phase = element_data->phase; + + return new; +} + +void +phase_free(net_phase) +net_phase_t *net_phase; +{ + int i; + node_phase_t *node_phase; + row_data_t *rd; + element_data_t *ed; + sm_row *row; + sm_element *element; + + for (i = 0; i < array_n(net_phase->rows); i++) { + node_phase = array_fetch(node_phase_t *, net_phase->rows, i); + FREE(node_phase); + } + array_free(net_phase->rows); + + sm_foreach_row(net_phase->matrix, row) { + sm_foreach_row_element(row, element) { + ed = sm_get(element_data_t *, element); + FREE(ed); + } + rd = sm_get(row_data_t *, row); + FREE(rd); + } + + sm_free(net_phase->matrix); + FREE(net_phase); +} + +void +phase_print(net_phase) +net_phase_t *net_phase; +{ + sm_row *row, *row1; + row_data_t *rd; + sm_element *element; + element_data_t *ed; + + (void) fprintf(misout, "\n"); + (void) fprintf(misout, "r# name pos,neg,save,"); + (void) fprintf(misout, "inverted,invertible,marked elements\n"); + sm_foreach_row(net_phase->matrix, row) { + (void) fprintf(misout, "%2d", row->row_num); + rd = sm_get(row_data_t *, row); + (void) fprintf(misout, " %5s ", node_name(rd->node)); + (void) fprintf(misout, " %1d", rd->pos_used); + (void) fprintf(misout, ",%1d", rd->neg_used); + (void) fprintf(misout, ",%2d", rd->inv_save); + if (rd->inverted) { + (void) fprintf(misout, ",i"); + } else { + (void) fprintf(misout, ",n"); + } + if (rd->invertible) { + (void) fprintf(misout, ",i"); + } else { + (void) fprintf(misout, ",n"); + } + if (rd->marked) { + (void) fprintf(misout, ",m"); + } else { + (void) fprintf(misout, ",u "); + } + sm_foreach_row_element(row, element) { + ed = sm_get(element_data_t *, element); + row1 = sm_get_row(net_phase->matrix, element->col_num); + if (row1 != NIL(sm_row)) { + rd = sm_get(row_data_t *, row1); +(void) fprintf(misout, " %1d(%s)", ed->phase, node_name(rd->node)); + } + } + (void) fprintf(misout, "\n"); + } + (void) fprintf(misout, "cost = %6.0f\n", net_phase->cost); +} + +void +phase_check_set() +{ + phase_check = TRUE; +} + +void +phase_check_unset() +{ + phase_check = FALSE; +} + +void +phase_trace_set() +{ + phase_trace = TRUE; +} + +void +phase_trace_unset() +{ + phase_trace = FALSE; +} + +static void +check_phase(net_phase) +net_phase_t *net_phase; +{ + sm_row *row; + row_data_t *rd; + int save; + bool pass; + + pass = TRUE; + + if (fabs(net_phase->cost - cost_comp(net_phase)) > (double) THRESH) { + (void) fprintf(miserr, "Error: inverter savings are not correct\n"); + (void) fprintf(miserr, "Computed cost: %f\n", cost_comp(net_phase)); + (void) fprintf(miserr, "Recorded cost: %f\n", net_phase->cost); + pass = FALSE; + } + + sm_foreach_row(net_phase->matrix, row) { + rd = sm_get(row_data_t *, row); + save = inv_save_comp(net_phase, row); + if (rd->invertible && rd->node->type != INTERNAL) { + (void) fprintf(miserr, "Error, %s ", node_name(rd->node)); + (void) fprintf(miserr, "is not INTERNAL, but invertible\n"); + pass = FALSE; + } + if (rd->inv_save != save) { + (void) fprintf(miserr, "inv_save(%-10s) ", node_name(rd->node)); + (void) fprintf(miserr, "recorded: %d, ", rd->inv_save); + (void) fprintf(miserr, "computed: %d\n", save); + pass = FALSE; + } + } + + if (!pass) { + (void) fprintf(miserr, "Did not pass phase consistency check\n"); + exit(-1); + } +} + +/* + * 1. decrease the output inverter saving of row. + * 2. decrease the input inverter saving of row for each fanout of row. + */ +static void +phase_dec(net_phase, row) +net_phase_t *net_phase; +sm_row *row; +{ + sm_row *fanout; + sm_element *element; + row_data_t *rd, *rd1; + element_data_t *ed; + + /* step 1 */ + rd = sm_get(row_data_t *, row); + rd->inv_save -= inv_save_output(rd); + + /* step 2 */ + sm_foreach_row_element(row, element) { + fanout = sm_get_row(net_phase->matrix, element->col_num); + if (fanout != NIL(sm_row)) { + ed = sm_get(element_data_t *, element); + rd1 = sm_get(row_data_t *, fanout); + rd1->inv_save -= inv_save_input(rd, ed); + } + } +} + +/* + * 1. increase the output inverter saving of row. + * 2. increase the input inverter saving of row for each fanout of row. + */ +static void +phase_inc(net_phase, row) +net_phase_t *net_phase; +sm_row *row; +{ + sm_row *fanout; + sm_element *element; + row_data_t *rd, *rd1; + element_data_t *ed; + + /* step 1 */ + rd = sm_get(row_data_t *, row); + rd->inv_save += inv_save_output(rd); + + /* step 2 */ + sm_foreach_row_element(row, element) { + fanout = sm_get_row(net_phase->matrix, element->col_num); + if (fanout != NIL(sm_row)) { + ed = sm_get(element_data_t *, element); + rd1 = sm_get(row_data_t *, fanout); + rd1->inv_save += inv_save_input(rd, ed); + } + } +} + +static bool +fanout_to_po(f) +node_t *f; +{ + node_t *np; + lsGen gen; + node_function_t func; + + foreach_fanout(f, gen, np) { + if (np->type == PRIMARY_OUTPUT) { + (void) lsFinish(gen); + return TRUE; + } + func = node_function(np); + if (func == NODE_INV || func == NODE_BUF) { + if (fanout_to_po(np)) { + (void) lsFinish(gen); + return TRUE; + } + } + } + return FALSE; +} + +void +phase_random_assign(net_phase) +net_phase_t *net_phase; +{ + node_phase_t *node_phase; + row_data_t *rd; + int i; + + for (i = 0; i < array_n(net_phase->rows); i++) { + node_phase = array_fetch(node_phase_t *, net_phase->rows, i); + rd = sm_get(row_data_t *, node_phase->row); + if (rd->invertible) { + if ((rand() % 16384) >= 8192) { + phase_invert(net_phase, node_phase); + } + } + } +} + +net_phase_t * +phase_setup(network) +network_t *network; +{ + node_t *np; + net_phase_t *net_phase; + nodeindex_t *table; + lsGen gen; + + /* initialization */ + net_phase = ALLOC(net_phase_t, 1); + net_phase->matrix = sm_alloc(); + net_phase->rows = array_alloc(node_phase_t *, 0); + table = nodeindex_alloc(); + phase_lib_setup(network); + + /* setup the matrix */ + foreach_node(network, gen, np) { + phase_node_setup(np, table, net_phase); + } + + inv_save_setup(net_phase); + nodeindex_free(table); + net_phase->cost = cost_comp(net_phase); + + if (phase_check) { + check_phase(net_phase); + } + + return net_phase; +} + +phase_node_setup(np, table, net_phase) +node_t *np; +nodeindex_t *table; +net_phase_t *net_phase; +{ + node_function_t func; + node_phase_t *node_phase; + row_data_t *row_data; + int rowi; + + func = node_function(np); + + if (func == NODE_PO || func == NODE_INV || func == NODE_BUF) { + return; + } + + if (func == NODE_PI && node_num_fanout(np) == 0) { + return; + } + + /* setup the matrix entries for this row */ + rowi = nodeindex_insert(table, np); + phase_fanout_setup(rowi, np, table, net_phase, 0); + + /* setup the row_data for this row */ + row_data = ALLOC(row_data_t, 1); + node_phase = ALLOC(node_phase_t, 1); + node_phase->row = sm_get_row(net_phase->matrix, rowi); + sm_put(node_phase->row, row_data); + array_insert_last(node_phase_t *, net_phase->rows, node_phase); + row_data->node = np; + row_data->inverted = FALSE; + row_data->marked = FALSE; + row_data->po = fanout_to_po(np); + phase_invertible_set(row_data); + phase_count_comp(np, table, net_phase); +} + +phase_fanout_setup(rowi, np, table, net_phase, phase) +int rowi; +node_t *np; +nodeindex_t *table; +net_phase_t *net_phase; +int phase; +{ + node_t *fanout; + lsGen gen; + node_function_t func; + sm_element *element; + element_data_t *element_data; + int coli; + + foreach_fanout(np, gen, fanout) { + func = node_function(fanout); + if (func == NODE_INV) { + phase_fanout_setup(rowi, fanout, table, net_phase, 1-phase); + } else if (func == NODE_BUF) { + phase_fanout_setup(rowi, fanout, table, net_phase, phase); + } else { + coli = nodeindex_insert(table, fanout); + element = sm_insert(net_phase->matrix, rowi, coli); + element_data = sm_get(element_data_t *, element); + if (element_data == NIL(element_data_t)) { + element_data = ALLOC(element_data_t, 1); + sm_put(element, element_data); + element_data->phase = -1; + } + if (phase != element_data->phase) { + if (element_data->phase == -1) { + element_data->phase = phase; + } else { + element_data->phase = 2; + } + } + } + } +} + +static void +phase_count_comp(np, table, net_phase) +node_t *np; +nodeindex_t *table; +net_phase_t *net_phase; +{ + sm_row *row; + int rowi; + sm_element *element; + element_data_t *element_data; + row_data_t *row_data; + + rowi = nodeindex_indexof(table, np); + row = sm_get_row(net_phase->matrix, rowi); + row_data = sm_get(row_data_t *, row); + row_data->pos_used = row_data->neg_used = 0; + sm_foreach_row_element(row, element) { + element_data = sm_get(element_data_t *, element); + switch (element_data->phase) { + case 0: + row_data->neg_used ++; + break; + case 1: + row_data->pos_used ++; + break; + case 2: + row_data->pos_used ++; + row_data->neg_used ++; + break; + default: + fail("phase_count_comp: wrong phase at the element"); + } + } +} diff --git a/sis/phase/phase.doc b/sis/phase/phase.doc new file mode 100644 index 0000000..7b4e4bd --- /dev/null +++ b/sis/phase/phase.doc @@ -0,0 +1,95 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/phase/phase.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +Summary: + add_inv_network(); + add_inv_node(); + phase_quick(); + phase_good(); + phase_random_greedy(); + phase_trace_set(); + phase_trace_unset(); + + +void +add_inv_network(network) +network_t *network; + Inserts inverters into the network. Currently, it + assumes inverted logic (e.g. SCMOS). After the + call, all functions, including primary inputs, + are used in their negative forms. It also assumes + that all output phase are correct. + + +int +add_inv_node(network, f) +network_t *network; +node_t *f; + Inserts an inverter in front of f if needed. It + returns 1 if an inverter is inserted, 0 otherwise. + It assumes inverted logic (e.g. SCMOS). After the + call, f is only used in its negative form. The + new inverted is inserted into the network. It also + assumes that all output phase are correct. + + +void +phase_quick(network) +network_t *network; + Determines for each node whether to implement the function + of its complement in order to reduce the total cost of + of the network. If the network is mapped the cost + is the total area and the network is kept mapped, + otherwise the cost is the number of inverters. It uses + quick phase (QP) algorithm. In the resulting network, + if a node is to be implemented using its complement, it + is inverted. All the necessary inverters are added into + the network. See MIS paper for detailed description of + the algorithms. + + +void +phase_good(network) +network_t *network; + Determines for each node whether to implement the function + of its complement in order to reduce the total cost of + of the network. If the network is mapped the cost + is the total area and the network is kepd mapped, + otherwise the cost is the number of inverters. It uses + good phase (GP) algorithm. In the resulting network, + if a node is to be implemented using its complement, it + is inverted. All the necessary inverters are added into + the network. See MIS paper for detailed description of + the algorithms. + + +void +phase_random_greedy(network, num) +network_t *network; +int num; + Determines for each node whether to implement the function + of its complement in order to reduce the total cost of + of the network. If the network is mapped the cost + is the total area and the network is kepd mapped, + otherwise the cost is the number of inverters. + It first randomly assign the phase to each node in the + network. Then, it finds a local minimum in a greedy way. + The process is repeated num times. In the resulting network, + if a node is to be implemented using its complement, it + is inverted. All the necessary inverters are added into + the network. See MIS paper for detailed description of + the algorithms. + + +void +phase_trace_set(); +void +phase_trace_unset(); + Allows (Disallows) the phase assignment program to print out + tracing messages. diff --git a/sis/phase/phase.h b/sis/phase/phase.h new file mode 100644 index 0000000..982c83c --- /dev/null +++ b/sis/phase/phase.h @@ -0,0 +1,21 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/phase/phase.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#ifndef PHASE_H +#define PHASE_H + +EXTERN void add_inv_network ARGS((network_t *)); +EXTERN int add_inv_node ARGS((network_t *, node_t *)); +EXTERN void phase_quick ARGS((network_t *)); +EXTERN void phase_good ARGS((network_t *)); +EXTERN void phase_random_greedy ARGS((network_t *, int)); +EXTERN void phase_trace_set ARGS((void)); +EXTERN void phase_trace_unset ARGS((void)); + +#endif diff --git a/sis/phase/phase_int.h b/sis/phase/phase_int.h new file mode 100644 index 0000000..269a658 --- /dev/null +++ b/sis/phase/phase_int.h @@ -0,0 +1,65 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/phase/phase_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#include "sparse.h" + +typedef struct node_phase_struct node_phase_t; +struct node_phase_struct { + sm_row *row; +}; + +typedef struct net_phase_struct net_phase_t; +struct net_phase_struct { + sm_matrix *matrix; + array_t *rows; + double cost; +}; + + +typedef struct row_data_struct row_data_t; +struct row_data_struct { + int pos_used; /* number of times the positive phase is used */ + int neg_used; /* number of times the positive phase is used */ + int inv_save; /* number of inverters saved when inverting the node */ + bool marked; /* stamp used by good-phase */ + bool invertible; /* whether the node is invertible */ + bool inverted; /* whether the node is inverted */ + bool po; /* whether the node fans out to a PO */ + node_t *node; /* points to the node associate with the row. */ + double area; /* area of the gate */ + double dual_area; /* area of the dual gate */ +}; + + +typedef struct element_data_struct element_data_t; +struct element_data_struct { + int phase; /* 0 - pos. unate, 1 - neg_ungate, 2 - binate */ +}; + +extern net_phase_t *phase_setup(); +extern int invert_saving(); +extern void phase_node_invert(); +extern node_phase_t *phase_get_best(); +extern double network_cost(); +extern void phase_unmark_all(); +extern void phase_mark(); +extern net_phase_t *phase_dup(); +extern void phase_replace(); +extern void phase_free(); +extern void phase_record(); +extern void phase_check_unset(); +extern void phase_check_set(); +extern void phase_random_assign(); +extern void phase_invert(); +extern double phase_value(); +extern double cost_comp(); +extern void phase_invertible_set(); + +extern bool phase_trace; +extern bool phase_check; diff --git a/sis/phase/phase_lib.c b/sis/phase/phase_lib.c new file mode 100644 index 0000000..3e8a07c --- /dev/null +++ b/sis/phase/phase_lib.c @@ -0,0 +1,251 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/phase/phase_lib.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#include "sis.h" +#include "phase.h" +#include "phase_int.h" + +static bool keep_mapped; +static lib_gate_t *inv_gate; +static lib_gate_t *min_area_gate(); + +phase_lib_setup(network) +network_t *network; +{ + lib_class_t *class; + node_t *node; + lsGen gen; + + /* is there a library? */ + if (lib_get_library() == NIL(library_t)) { + keep_mapped = FALSE; + inv_gate = NIL(lib_gate_t); + return; + } + + /* are all the gates mapped? */ + foreach_node(network, gen, node) { + if (node->type == INTERNAL && lib_gate_of(node) == NIL(lib_gate_t)) { + keep_mapped = FALSE; + inv_gate = NIL(lib_gate_t); + (void) lsFinish(gen); + return; + } + } + + /* is there an inverter in the library? */ + network = read_eqn_string("f = a';"); + assert(network != NIL(network_t)); + class = lib_get_class(network, lib_get_library()); + network_free(network); + if (class == NIL(lib_class_t)) { + keep_mapped = FALSE; + inv_gate = NIL(lib_gate_t); + return; + } + + /* Ok, I'll keep the network mapped */ + inv_gate = min_area_gate(class); + keep_mapped = TRUE; +} + +void +phase_invertible_set(row_data) +row_data_t *row_data; +{ + lib_gate_t *gate, *dual_gate; + lib_class_t *dual_class; + + switch (node_function(row_data->node)) { + case NODE_PI: + case NODE_PO: + row_data->invertible = FALSE; + row_data->area = 0.0; + row_data->dual_area = 0.0; + return; + default: + if (!keep_mapped) { + row_data->invertible = TRUE; + row_data->area = 0.0; + row_data->dual_area = 0.0; + return; + } + gate = lib_gate_of(row_data->node); + if (gate == NIL(lib_gate_t)) { + row_data->invertible = TRUE; + row_data->area = 0.0; + row_data->dual_area = 0.0; + return; + } else { + dual_class = lib_class_dual(lib_gate_class(gate)); + if (dual_class == NIL(lib_class_t)) { + row_data->invertible = FALSE; + row_data->area = 0.0; + row_data->dual_area = 0.0; + return; + } else { + dual_gate = min_area_gate(dual_class); + assert(dual_gate != NIL(lib_gate_t)); + row_data->invertible = TRUE; + row_data->area = lib_gate_area(gate); + row_data->dual_area = lib_gate_area(dual_gate); + return; + } + } + } +} + +void +phase_node_invert(np) +node_t *np; +{ + lib_gate_t *gate, *dual_gate; + lib_class_t *dual_class; + char **inv_formals, **formals; + node_t **inv_actuals, **actuals, *node, *fanin; + int i; + + if (keep_mapped) { + gate = lib_gate_of(np); + dual_class = lib_class_dual(lib_gate_class(gate)); + dual_gate = min_area_gate(dual_class); + + inv_formals = ALLOC(char *, 1); + inv_actuals = ALLOC(node_t *, 1); + inv_formals[0] = lib_gate_pin_name(inv_gate, 0, /*input*/ 1); + + formals = ALLOC(char *, node_num_fanin(np)); + actuals = ALLOC(node_t *, node_num_fanin(np)); + + foreach_fanin(np, i, fanin) { + inv_actuals[0] = fanin; + node = node_alloc(); + (void) lib_set_gate(node, inv_gate, inv_formals, inv_actuals, 1); + network_add_node(node_network(np), node); + formals[i] = lib_gate_pin_name(dual_gate, i, 1); + actuals[i] = node; + } + + node = node_alloc(); + (void) lib_set_gate(node, dual_gate, formals, actuals, + node_num_fanin(np)); + network_add_node(node_network(np), node); + inv_actuals[0] = node; + (void) lib_set_gate(np, inv_gate, inv_formals, inv_actuals, 1); + + FREE(formals); + FREE(inv_formals); + FREE(actuals); + FREE(inv_actuals); + + } else { + (void) node_invert(np); + } +} + +static lib_gate_t * +min_area_gate(class) +lib_class_t *class; +{ + lib_gate_t *gate; + lsGen gen; + char *dummy; + + /* find the gate with minimum area */ + gen = lib_gen_gates(class); + if (lsNext(gen, &dummy, LS_NH) != LS_OK) { + fail("Error, dual class is empty\n"); + } + gate = (lib_gate_t *) dummy; + while (lsNext(gen, &dummy, LS_NH) == LS_OK) { + if (lib_gate_area((lib_gate_t *) dummy) < lib_gate_area(gate)) { + gate = (lib_gate_t *) dummy; + } + } + (void) lsFinish(gen); + + return gate; +} + +double +phase_value(node_phase) +node_phase_t *node_phase; +{ + row_data_t *row_data; + lib_gate_t *gate, *dual_gate; + lib_class_t *dual_class; + double value; + + row_data = sm_get(row_data_t *, node_phase->row); + if (!keep_mapped) { + return (double) row_data->inv_save; + } else { + gate = lib_gate_of(row_data->node); + dual_class = lib_class_dual(lib_gate_class(gate)); + dual_gate = min_area_gate(dual_class); + if (row_data->inverted) { + value = lib_gate_area(dual_gate) - lib_gate_area(gate); + } else { + value = lib_gate_area(gate) - lib_gate_area(dual_gate); + } + value += row_data->inv_save * lib_gate_area(inv_gate); + return value; + } +} + +double +cost_comp(net_phase) +net_phase_t *net_phase; +{ + sm_row *row; + row_data_t *rd; + double count; + + count = 0; + sm_foreach_row(net_phase->matrix, row) { + rd = sm_get(row_data_t *, row); + if (rd->inverted) { + count += rd->dual_area; + } else { + count += rd->area; + } + if (rd->pos_used != 0) { + if (keep_mapped) { + count += lib_gate_area(inv_gate); + } else { + count += 1; + } + } + } + + return count; +} + +void +phase_record(network, net_phase) +network_t *network; +net_phase_t *net_phase; +{ + sm_row *row; + row_data_t *rd; + + sm_foreach_row(net_phase->matrix, row) { + rd = sm_get(row_data_t *, row); + if (rd->inverted) { + (void) phase_node_invert(rd->node); + } + } + + if (keep_mapped) { + map_remove_inverter(network, 0); + } else { + (void) network_sweep(network); + add_inv_network(network); + } +} diff --git a/sis/pld/Makefile.am b/sis/pld/Makefile.am new file mode 100644 index 0000000..6ed380f --- /dev/null +++ b/sis/pld/Makefile.am @@ -0,0 +1,17 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libpld.a +libpld_a_SOURCES = act_apply.c act_bdd.c act_bool.c act_collapse.c \ + act_create.c act_delay.c act_dutil.c act_init.c act_ite.c act_ite_new.c \ + act_leaf.c act_map.c act_misc.c act_order.c act_read.c act_reduce.c \ + act_remove.c act_urp.c act_util.c com_ite.c com_pld.c ite_break.c \ + ite_collapse.c ite_factor.c ite_imp.c ite_leaf.c ite_map.c ite_mroot.c \ + ite_mux_net.c ite_new_map.c ite_new_urp.c ite_pld.c ite_urp.c ite_util.c \ + pld_util.c xln_ULM_util.c xln_aodecomp.c xln_aux.c xln_collapse.c \ + xln_cube.c xln_dec_merge.c xln_feasible.c xln_filter.c xln_imp.c \ + xln_k_de_area.c xln_k_decomp.c xln_level.c xln_lindo.c xln_map_par.c \ + xln_merge.c xln_move_d.c xln_new_part.c xln_part_dec.c xln_ufind.c \ + act_bool.h ite_int.h pld_int.h +pkginclude_HEADERS = pld.h +dist_doc_DATA = pld.doc diff --git a/sis/pld/Makefile.in b/sis/pld/Makefile.in new file mode 100644 index 0000000..94a78f8 --- /dev/null +++ b/sis/pld/Makefile.in @@ -0,0 +1,448 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libpld_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/pld +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libpld_a_AR = $(AR) $(ARFLAGS) +libpld_a_LIBADD = +am_libpld_a_OBJECTS = act_apply.$(OBJEXT) act_bdd.$(OBJEXT) \ + act_bool.$(OBJEXT) act_collapse.$(OBJEXT) act_create.$(OBJEXT) \ + act_delay.$(OBJEXT) act_dutil.$(OBJEXT) act_init.$(OBJEXT) \ + act_ite.$(OBJEXT) act_ite_new.$(OBJEXT) act_leaf.$(OBJEXT) \ + act_map.$(OBJEXT) act_misc.$(OBJEXT) act_order.$(OBJEXT) \ + act_read.$(OBJEXT) act_reduce.$(OBJEXT) act_remove.$(OBJEXT) \ + act_urp.$(OBJEXT) act_util.$(OBJEXT) com_ite.$(OBJEXT) \ + com_pld.$(OBJEXT) ite_break.$(OBJEXT) ite_collapse.$(OBJEXT) \ + ite_factor.$(OBJEXT) ite_imp.$(OBJEXT) ite_leaf.$(OBJEXT) \ + ite_map.$(OBJEXT) ite_mroot.$(OBJEXT) ite_mux_net.$(OBJEXT) \ + ite_new_map.$(OBJEXT) ite_new_urp.$(OBJEXT) ite_pld.$(OBJEXT) \ + ite_urp.$(OBJEXT) ite_util.$(OBJEXT) pld_util.$(OBJEXT) \ + xln_ULM_util.$(OBJEXT) xln_aodecomp.$(OBJEXT) \ + xln_aux.$(OBJEXT) xln_collapse.$(OBJEXT) xln_cube.$(OBJEXT) \ + xln_dec_merge.$(OBJEXT) xln_feasible.$(OBJEXT) \ + xln_filter.$(OBJEXT) xln_imp.$(OBJEXT) xln_k_de_area.$(OBJEXT) \ + xln_k_decomp.$(OBJEXT) xln_level.$(OBJEXT) xln_lindo.$(OBJEXT) \ + xln_map_par.$(OBJEXT) xln_merge.$(OBJEXT) xln_move_d.$(OBJEXT) \ + xln_new_part.$(OBJEXT) xln_part_dec.$(OBJEXT) \ + xln_ufind.$(OBJEXT) +libpld_a_OBJECTS = $(am_libpld_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libpld_a_SOURCES) +DIST_SOURCES = $(libpld_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libpld.a +libpld_a_SOURCES = act_apply.c act_bdd.c act_bool.c act_collapse.c \ + act_create.c act_delay.c act_dutil.c act_init.c act_ite.c act_ite_new.c \ + act_leaf.c act_map.c act_misc.c act_order.c act_read.c act_reduce.c \ + act_remove.c act_urp.c act_util.c com_ite.c com_pld.c ite_break.c \ + ite_collapse.c ite_factor.c ite_imp.c ite_leaf.c ite_map.c ite_mroot.c \ + ite_mux_net.c ite_new_map.c ite_new_urp.c ite_pld.c ite_urp.c ite_util.c \ + pld_util.c xln_ULM_util.c xln_aodecomp.c xln_aux.c xln_collapse.c \ + xln_cube.c xln_dec_merge.c xln_feasible.c xln_filter.c xln_imp.c \ + xln_k_de_area.c xln_k_decomp.c xln_level.c xln_lindo.c xln_map_par.c \ + xln_merge.c xln_move_d.c xln_new_part.c xln_part_dec.c xln_ufind.c \ + act_bool.h ite_int.h pld_int.h + +pkginclude_HEADERS = pld.h +dist_doc_DATA = pld.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/pld/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/pld/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libpld.a: $(libpld_a_OBJECTS) $(libpld_a_DEPENDENCIES) + -rm -f libpld.a + $(libpld_a_AR) libpld.a $(libpld_a_OBJECTS) $(libpld_a_LIBADD) + $(RANLIB) libpld.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/pld/act_apply.c b/sis/pld/act_apply.c new file mode 100644 index 0000000..868b928 --- /dev/null +++ b/sis/pld/act_apply.c @@ -0,0 +1,185 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_apply.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/* apply, straight from bryant's paper +*/ + +/* table needed in applyStep */ +st_table *app_table; + +typedef struct two_key_defn{ + int field1; + int field2; +} TWO_KEY, *TWO_KEY_PTR; + +/*extern ACT_VERTEX_PTR applyStep(); +extern int two_cmp(); +extern int two_hash(); +extern enum st_retval applyCleanUp();*/ + +ACT_VERTEX_PTR +apply(v1, v2, op) +ACT_VERTEX_PTR v1, v2; +int op; + +{ ACT_VERTEX_PTR u, actReduce(), applyStep(); + char dummy; + int two_cmp(), two_hash(); + enum st_retval applyCleanUp(); + + app_table = st_init_table(two_cmp, two_hash); + u = applyStep(v1, v2, op); + st_foreach(app_table, applyCleanUp, &dummy); + st_free_table(app_table); + u = actReduce(u); + return(u); +} + +ACT_VERTEX_PTR +applyStep(v1, v2, op) +ACT_VERTEX_PTR v1, v2; +int op; + +{ char *dummy; + ACT_VERTEX_PTR u, vlow1, vhigh1, vlow2, vhigh2; + TWO_KEY_PTR key; + + key = ALLOC(TWO_KEY, 1); + key->field1 = v1->id; + key->field2 = v2->id; + if(st_lookup(app_table, (char *)key, &dummy)){ + u = (ACT_VERTEX_PTR) dummy; + FREE(key); + return(u); + } else { + u = ALLOC(ACT_VERTEX, 1); + u->mark = FALSE; + (void) st_insert(app_table, (char *)key, (char *) u); + if(v1->value == NO_VALUE || v2->value == NO_VALUE){ + u->value = NO_VALUE; + u->id = 0; + u->index_size = v1->index_size; + u->index = min(v1->index, v2->index); + if(v1->index == u->index){ + vlow1 = v1->low; + vhigh1 = v1->high; + } else { + vlow1 = v1; + vhigh1 = v1; + } + if(v2->index == u->index){ + vlow2 = v2->low; + vhigh2 = v2->high; + } else { + vlow2 = v2; + vhigh2 = v2; + } + u->low = applyStep(vlow1, vlow2, op); + u->high = applyStep(vhigh1, vhigh2, op); + } else { + u->index = v1->index_size; + u->low = NIL (act_t); + u->high = NIL (act_t); + u->id = 0; + u->index_size = v1->index_size; + switch(op) { + case(AND + P11): + u->value = v1->value && + v2->value; + break; + case(AND + P10) : + u->value = v1->value && !(v2->value); + break; + case(AND + P01) : + u->value = !(v1->value) && v2->value; + break; + case(AND + P00) : + u->value = !(v1->value) && !(v2->value); + break; + + case(OR + P11): + u->value = v1->value || v2->value; + break; + case(OR + P10) : + u->value = v1->value || !(v2->value); + break; + case(OR + P01) : + u->value = !(v1->value) || v2->value; + break; + case(OR + P00) : + u->value = !(v1->value) || !(v2->value); + break; + case(XOR) : + u->value = (v1->value && !(v2->value)) || + (v2->value && !(v1->value)); + break; + case(XNOR) : + u->value = (v1->value && v2->value) || + (!(v2->value) && !(v1->value)); + break; + default: + break; + } + } + return(u); + } +} + +int +two_cmp(key1, key2) +char *key1, *key2; +{ + TWO_KEY_PTR nkey1, nkey2; + + nkey1 = (TWO_KEY_PTR) key1; + nkey2 = (TWO_KEY_PTR) key2; + + if(nkey1->field1 == nkey2->field1){ + if(nkey1->field2 == nkey2->field2){ + return(0); + } else { + if(nkey1->field2 < nkey2->field2) return(-1); + else return(1); + } + } else { + if(nkey1->field1 < nkey2->field1) return(-1); + else return(1); + } +} + +int +two_hash(key, modulus) +char *key; +int modulus; +{ + TWO_KEY_PTR nkey; + int bucket; + + nkey = (TWO_KEY_PTR) key; + bucket = (1009 * (nkey->field1) + 101 * (nkey->field2)) % modulus; + return(bucket); +} + +/*ARGSUSED*/ +enum st_retval +applyCleanUp(key, value, arg) +char *key; +char *value; +char *arg; + +{ + TWO_KEY_PTR nkey; + nkey = (TWO_KEY_PTR) key; + FREE(nkey); + return(ST_CONTINUE); +} + diff --git a/sis/pld/act_bdd.c b/sis/pld/act_bdd.c new file mode 100644 index 0000000..4fb4415 --- /dev/null +++ b/sis/pld/act_bdd.c @@ -0,0 +1,264 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_bdd.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +static void join(); + +/* Initialize the ACT*/ +act_t * +my_init_act() +{ + act_t *vertex; + + vertex = ALLOC(act_t ,1); + vertex->high = NIL (ACT_VERTEX); + vertex->low = NIL (ACT_VERTEX); + vertex->index = 0; + vertex->value = 0; + vertex->id = 0; + vertex->mark = 0; + vertex->index_size = 0; + vertex->node = NIL (node_t); + vertex->name = NIL (char); + vertex->multiple_fo = 0; + vertex->cost = 0; + vertex->mapped = 0; + /* vertex->parent = NULL; */ + return vertex; +} + + +/* Construct bdd for a cube ie a bdd which is the and of its variables*/ +act_t * +act_F(F) +sm_matrix *F; +{ + act_t *vertex, *t_vertex, *my_init_act(), *my_act_and(); + sm_row *row; + sm_element *p; + int skip= -1, size; + char *name; + +/* Avoid stupidity*/ + if(F->nrows > 1){ + (void)fprintf(sisout, "error in act_f - more than one cube\n"); + return 0; + } + row = F->first_row; + vertex = my_init_act(); +/* vertex->value = 3 is an indication of a dummy vertex*/ + vertex->value = 3; + +/* Preprocess so that variable at end of act is not in negative phase (if + * possible) */ + size = 0; + sm_foreach_row_element(row, p) { + if((p->user_word == (char *)1) && (skip == -1)) { + name = sm_get_col(F, p->col_num)->user_word; + t_vertex = my_act_and(p, vertex, name); + vertex = t_vertex; + skip = p->col_num; + } + if(p->user_word != (char *)2) size++; + } + + sm_foreach_row_element(row, p) { + if((p->user_word != (char *)2) && (p->col_num != skip)) { + name = sm_get_col(F, p->col_num)->user_word; + t_vertex = my_act_and(p, vertex, name); + vertex = t_vertex; + } + } + vertex->index_size = size; + return vertex; +} + +/* And variables in a cube*/ +act_t * +my_act_and(p, vertex, name) +sm_element *p; +act_t *vertex; +char *name; +{ + int is_first = 0; + act_t *p_vertex, *h_vertex, *l_vertex; + char *dummy; +/* Weird initialization for the first vertex, its value is 3*/ + if(vertex->value == 3) { + my_free_act(vertex); + is_first = 1; + } + p_vertex = my_init_act(); + p_vertex->value = 4; + p_vertex->index = p->col_num; + p_vertex->name = name; + (void) st_lookup(end_table, (char *)1, &dummy); + h_vertex = (act_t *)dummy; + (void) st_lookup(end_table, (char *)0, &dummy); + l_vertex = (act_t *)dummy; + + if(is_first) { + p_vertex->index_size = 1; + switch((int )p->user_word) { + case 0: + p_vertex->high = l_vertex; + p_vertex->low = h_vertex; + break; + case 1: + p_vertex->high = h_vertex; + p_vertex->low = l_vertex; + break; + case 2: + (void)fprintf(sisout, "error in my_and_act,\n"); + break; + } + } else { + switch((int )p->user_word) { + case 0: + p_vertex->low = vertex; + p_vertex->high = l_vertex; + p_vertex->index_size = vertex->index_size + 1; + break; + case 1: + p_vertex->high = vertex; + p_vertex->low = l_vertex; + p_vertex->index_size = vertex->index_size +1; + break; + case 2: + (void)fprintf(sisout, "error in my_and act, p->u_w == 2\n"); + break; + + } + } + return p_vertex; +} + +/* Or 2 ACT's*/ +act_t * +my_or_act_F(array_b,cover, array) +array_t *array_b; +array_t *array; +sm_row *cover; +{ + static int compare(); + int i; + act_t *up_vertex, *down_vertex, *vertex; + sm_element *p; + act_t *act; + char *name; + +/* Append the appropriate variables at top of acts*/ + i = 0; + sm_foreach_row_element(cover, p) { + name = sm_get_col(array_fetch(sm_matrix *, array, i), p->col_num) + ->user_word; + vertex = array_fetch(act_t *, array_b, i); + act = my_act_and(p, vertex, name); + array_insert(act_t *, array_b, i, act); + i++; + } +/* Sort the cubes so that the smaller act s are at the top so that less fanout + * problem also we could use the heuristic merging done earlier*/ + array_sort(array_b, compare); + + up_vertex = array_fetch(act_t *, array_b, 0); + act = up_vertex; + for(i = 1; i < array_n(array_b); i++) { + down_vertex = array_fetch(act_t *, array_b, i); + join(up_vertex, up_vertex, down_vertex); + up_vertex = down_vertex; + } + return act; +} + +/* Recursively Join ACT's constructed*/ +static void +join(parent_vertex, vertex, down_vertex) +act_t *vertex, *down_vertex, *parent_vertex; +{ + + + if((vertex->low == NIL (act_t) ) && (vertex->high == NIL (act_t))) { + if(parent_vertex->low->value == 0) { + parent_vertex->low = down_vertex; + } else if(parent_vertex->high->value == 0) { + parent_vertex->high = down_vertex; + } + } + if((vertex->low != NIL (act_t) )&&(vertex->low != down_vertex)) { + join(vertex, vertex->low, down_vertex); + if((vertex->high != NIL (act_t))&&(vertex->high != down_vertex)) { + join(vertex, vertex->high, down_vertex); + } + } +} + + + +/* ACT construction where act_l and act_r are known and we have a binate +varible above the two eg f = a (..) + a'(..)*/ +act_t * +my_and_act(act_l, act_r, b_col, name) +act_t *act_l, *act_r; +int b_col; +char *name; +{ + act_t *act; + + act = my_init_act(); + act->value = 4; + act->index = b_col; + act->name = name; + + + act->index_size = act_l->index_size + act_r->index_size +1; + act->low = act_l; + act->high = act_r; + return act; +} + + +trace_act(vertex) +act_t *vertex; +{ + if((vertex->low != NIL (act_t)) && (vertex->high != NIL (act_t))) { + (void)fprintf(sisout, "current variable - %s\n", vertex->name); + } + + if(vertex->low != NIL (act_t) ) { + trace_act(vertex->low); + if(vertex->high != NIL (act_t) ) { + trace_act(vertex->high); + } + } + + if((vertex->low == NIL (act_t)) && (vertex->high == NIL (act_t) )) { + (void)fprintf(sisout, "END- %d\n", vertex->value); + } +} + +static int +compare(obj1, obj2) +char *obj1, *obj2; +{ + act_t *act1 = *(act_t **)obj1; + act_t *act2 = *(act_t **)obj2; + int value; + + if((act1->index_size == 0 ) || (act2->index_size == 0)) { + (void)fprintf(sisout, "Hey u DOLT act of size \n"); + } + if(act1->index_size == act2->index_size) value = 0; + if(act1->index_size > act2->index_size) value = 1; + if(act1->index_size < act2->index_size) value = -1; + return value; +} + diff --git a/sis/pld/act_bool.c b/sis/pld/act_bool.c new file mode 100644 index 0000000..c0291e6 --- /dev/null +++ b/sis/pld/act_bool.c @@ -0,0 +1,697 @@ +#include "sis.h" +#include "act_bool.h" +extern int ACT_ITE_DEBUG; + +/* +* Jan 29 '93 - added act_is_or_used. +*/ + +static node_t *act_form_G(); + +/*-------------------------------------------------------------------------------- + This includes routines for Boolean matching of a function against actel block. + In the spirit of ENUFOR... Assumes that the nodes are expressed using + minimal support. act_is_or_used is 0 if the OR gate is not used. +---------------------------------------------------------------------------------*/ + +act_bool_map_network(network, map_alg, act_is_or_used, print_flag) + network_t *network; + int map_alg, act_is_or_used, print_flag; +{ + array_t *nodevec; + int i, count_OR = 0, count = 0; + ACT_MATCH *match, *act_is_act_function(); + node_t *node; + node_function_t node_fun_S0, node_fun_S1; + extern char *io_name(); /* to take care of inputs to POs */ + + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + match = act_is_act_function(node, map_alg, act_is_or_used); + if (match) { + node_fun_S0 = node_function(match->S0); + node_fun_S1 = node_function(match->S1); + if (node_fun_S0 != NODE_0 && node_fun_S0 != NODE_1 && + node_fun_S1 != NODE_0 && node_fun_S1 != NODE_1) { + count_OR++; + } + count++; + if (print_flag) { + (void) printf("match found for node %s\n", io_name(node, 0)); + act_print_match(match); + } + act_free_match(match); + } else { + if ((node->type != PRIMARY_INPUT) && (node->type != PRIMARY_OUTPUT)) + if (print_flag) (void) printf("no match found for node %s\n", io_name(node, 0)); + } + } + array_free(nodevec); + (void) printf("out of %d matches, %d use OR gate\n", count, count_OR); +} + +/*--------------------------------------------------------------------------- + Given a function f, finds if f can be implemented by one act block. If so, + returns the first match found in match. Else returns NIL. Assumes f is + expressed in minimum base. Hardwired info about the block. +----------------------------------------------------------------------------*/ +ACT_MATCH * +act_is_act_function(f, map_alg, act_is_or_used) + node_t *f; + int map_alg, act_is_or_used; +{ + int num_fanin; + node_t *fanin, *fanin_lit, *f_fanin_pos, *faninA, *faninB, *faninBc; + node_t *A0, *A1, *SA, *B0, *B1, *SB; + node_t *cof_A, *cof_B, *cof_Ac, *cof_Ac_Bc, *cof_Ac_B, *cof_A_Bc; + st_table *table; + int i, j; + COFC_STRUCT *cofc, *cofcA, *cofcB; + ACT_MATCH *match, *act_alloc_match(); + node_t *fanin_A_pos, *fanin_A_neg, *fanin_B_pos, *fanin_B_neg; + node_t *G, *act_form_G(); + + if (f->type == PRIMARY_INPUT || f->type == PRIMARY_OUTPUT) return NIL (ACT_MATCH); + + if (node_function(f) == NODE_0) return act_alloc_match + (node_constant(0), node_constant(0), + node_constant(0), node_constant(0), + node_constant(0), node_constant(0), + node_constant(0), node_constant(0)); + if (node_function(f) == NODE_1) return act_alloc_match + (node_constant(1), node_constant(1), + node_constant(1), node_constant(1), + node_constant(1), node_constant(1), + node_constant(1), node_constant(1)); + + /* simplify_node(f, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, SIM_FILTER_NONE, + SIM_ACCEPT_SOP_LITS); + */ + num_fanin = node_num_fanin(f); + + if (num_fanin > 8) return NIL (ACT_MATCH); + if ((!act_is_or_used) && num_fanin > 7) return NIL (ACT_MATCH); + + table = st_init_table(st_ptrcmp, st_ptrhash); + + /* find all the fanins which can potentially fanin to OR gate */ + /*---------------------------------------------------------------*/ + foreach_fanin(f, i, fanin) { + fanin_lit = node_literal(fanin, 1); + f_fanin_pos = node_cofactor(f, fanin_lit); + node_free(fanin_lit); + simplify_node(f_fanin_pos, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, SIM_FILTER_NONE, + SIM_ACCEPT_SOP_LITS); + /* changed 4 to 3 - Oct. 19, 1991 - since even if OR gate uses + both the inputs, then f = (a + b) L + a' b' M => cofac f wrt + a is L_a & since L is mux-implementable, L_a has <= 3 inp. */ + /*------------------------------------------------------------*/ + + if (node_num_fanin(f_fanin_pos) > 3) { + node_free(f_fanin_pos); + continue; + } + /* store f_fanin along with the fanin */ + /*------------------------------------*/ + cofc = ALLOC(COFC_STRUCT, 1); + cofc->pos = f_fanin_pos; + cofc->pos_mux = 0; + cofc->B0 = NIL (node_t); + cofc->B1 = NIL (node_t); + cofc->SB = NIL (node_t); + cofc->neg = NIL (node_t); + cofc->node = f; + cofc->fanin = fanin; + assert(!st_insert(table, (char *) fanin, (char *) cofc)); + } + + /* check if some single fanin can be put at the OR gate */ + /*-------------------------------------------------------*/ + foreach_fanin(f, i, fanin) { + if (!st_lookup(table, (char *) fanin, (char **)&cofc)) continue; + if (act_is_mux_function(cofc->pos, &B0, &B1, &SB)) { + cofc->pos_mux = 1; + cofc->B0 = B0; + cofc->B1 = B1; + cofc->SB = SB; + act_bool_set_cof_neg(cofc); + if (act_is_mux_function(cofc->neg, &A0, &A1, &SA)) { + /* set the pointers, free storage and return 1 */ + /*---------------------------------------------*/ + if (ACT_ITE_DEBUG) (void) printf("found a match\n"); + match = act_alloc_match(A0, A1, SA, node_dup(B0), node_dup(B1), + node_dup(SB), node_literal(fanin, 1), + node_constant(0)); + act_bool_free_table(table); + return match; + } + } + } + + if (!act_is_or_used) { + act_bool_free_table(table); + return NIL (ACT_MATCH); + } + + /* check for a pair at the OR gate */ + /*---------------------------------*/ + for (i = 0; i < num_fanin; i++) { + faninA = node_get_fanin(f, i); + if (!st_lookup(table, (char *) faninA, (char **)&cofcA)) continue; + if (cofcA->pos_mux != 1) continue; + cof_A = cofcA->pos; + act_bool_set_cof_neg(cofcA); + for (j = i + 1; j < num_fanin; j++) { + faninB = node_get_fanin(f, j); + if (!st_lookup(table, (char *) faninB, (char **)&cofcB)) continue; + cof_B = cofcB->pos; + act_bool_set_cof_neg(cofcB); + /* using my_node_equal, since node_equal does not take care of 1 */ + /*---------------------------------------------------------------*/ + if (my_node_equal(cof_A, cof_B)) { + /* check if the cof_A' cof_B' is realizable by a mux */ + /*---------------------------------------------------*/ + cof_Ac = cofcA->neg; + faninBc = node_literal(faninB, 0); + cof_Ac_Bc = node_cofactor(cof_Ac, faninBc); + simplify_node(cof_Ac_Bc, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, + SIM_FILTER_NONE, SIM_ACCEPT_SOP_LITS); + if (act_is_mux_function(cof_Ac_Bc, &A0, &A1, &SA)) { + if (ACT_ITE_DEBUG) (void) printf("found a match\n"); + /* free the storage */ + /*------------------*/ + match = act_alloc_match(A0, A1, SA, node_dup(cofcA->B0), + node_dup(cofcA->B1), node_dup(cofcA->SB), + node_literal(faninA, 1), + node_literal(faninB, 1)); + act_bool_free_table(table); + return match; + } + } + } + } + if (map_alg) { + /* do not do general matching */ + /*----------------------------*/ + act_bool_free_table(table); + return NIL (ACT_MATCH); + } + + /* disjoint match not found - try general match */ + /*----------------------------------------------*/ + for (i = 0; i < num_fanin; i++) { + faninA = node_get_fanin(f, i); + if (!st_lookup(table, (char *) faninA, (char **)&cofcA)) continue; + fanin_A_neg = node_literal(faninA, 0); + fanin_A_pos = node_literal(faninA, 1); + act_bool_set_cof_neg(cofcA); + for (j = i + 1; j < num_fanin; j++) { + faninB = node_get_fanin(f, j); + if (!st_lookup(table, (char *) faninB, (char **)&cofcB)) continue; + /* check if the cof_A' cof_B' is realizable by a mux */ + /*---------------------------------------------------*/ + fanin_B_neg = node_literal(faninB, 0); + fanin_B_pos = node_literal(faninB, 1); + act_bool_set_cof_neg(cofcB); + cof_Ac_Bc = node_cofactor(cofcA->neg, fanin_B_neg); + simplify_node(cof_Ac_Bc, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, + SIM_FILTER_NONE, SIM_ACCEPT_SOP_LITS); + if (act_is_mux_function(cof_Ac_Bc, &A0, &A1, &SA)) { + /* form G, H */ + /*-----------*/ + cof_Ac_B = node_cofactor(cofcB->pos, fanin_A_neg); + simplify_node(cof_Ac_B, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, + SIM_FILTER_NONE, SIM_ACCEPT_SOP_LITS); + cof_A_Bc = node_cofactor(cofcA->pos, fanin_B_neg); + simplify_node(cof_A_Bc, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, + SIM_FILTER_NONE, SIM_ACCEPT_SOP_LITS); + + G = act_form_G(cofcA->pos, cof_Ac_B, fanin_A_pos, fanin_B_pos, + fanin_A_neg); + simplify_node(G, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, + SIM_FILTER_NONE, SIM_ACCEPT_SOP_LITS); + assert(node_get_fanin_index(f, faninA) == i); + assert(node_get_fanin_index(f, faninB) == j); + + if (act_find_H(f, G, fanin_A_neg, fanin_B_neg, i, j, cof_Ac_B, + cof_A_Bc, &B0, &B1, &SB)) { + match = act_alloc_match(A0, A1, SA, B0, B1, SB, fanin_A_pos, + fanin_B_pos); + node_free_list(fanin_A_neg, fanin_B_neg, cof_Ac_Bc, G, cof_Ac_B); + node_free(cof_A_Bc); + act_bool_free_table(table); + return match; + } + node_free_list(cof_Ac_B, G, cof_A_Bc, NIL(node_t), NIL(node_t)); + } + node_free_list(cof_Ac_Bc, fanin_B_pos, fanin_B_neg, NIL(node_t), NIL(node_t)); + } + node_free_list(fanin_A_pos, fanin_A_neg, NIL(node_t), NIL(node_t), NIL(node_t)); + } + act_bool_free_table(table); + return NIL (ACT_MATCH); +} + +/*-------------------------------------------------------------------- + Computes cofactor of cofc->node wrt. cofac->fanin'. Sets the neg + pointer. Does this only if neg entry is NIL to begin with. +---------------------------------------------------------------------*/ +act_bool_set_cof_neg(cofc) + COFC_STRUCT *cofc; +{ + node_t *fanin_lit, *neg; + + if (cofc->neg == NIL (node_t)) { + fanin_lit = node_literal(cofc->fanin, 0); + neg = node_cofactor(cofc->node, fanin_lit); + simplify_node(neg, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, SIM_FILTER_NONE, + SIM_ACCEPT_SOP_LITS); + cofc->neg = neg; + + } +} + +act_bool_free_table(table) + st_table *table; +{ + st_generator *stgen; + node_t *fanin; + COFC_STRUCT *cofc; + + st_foreach_item(table, stgen, (char **) &fanin, (char **) &cofc) { + act_bool_free_cofc(cofc); + } + st_free_table(table); +} + +act_bool_free_cofc(cofc) + COFC_STRUCT *cofc; +{ + node_free(cofc->pos); + node_free(cofc->B0); + node_free(cofc->B1); + node_free(cofc->SB); + node_free(cofc->neg); + FREE(cofc); +} + +ACT_MATCH * +act_alloc_match(A0, A1, SA, B0, B1, SB, S0, S1) + node_t *A0, *A1, *SA, *B0, *B1, *SB, *S0, *S1; +{ + ACT_MATCH *match; + + match = ALLOC(ACT_MATCH, 1); + match->A0 = A0; + match->A1 = A1; + match->SA = SA; + match->B0 = B0; + match->B1 = B1; + match->SB = SB; + match->S0 = S0; + match->S1 = S1; + + return match; +} + +/*-------------------------------------------------------------------------------- + Returns 1 if f can be implemented as a mux. If so, it returns the corresponding + select, zero, one fanins. Else returns 0. + NOTE: Assumes that the node has been simplified. +----------------------------------------------------------------------------------*/ +int +act_is_mux_function(f, zero, one, select) + node_t *f, **zero, **one, **select; +{ + int num_fanin, num_cube; + node_function_t node_fn; + input_phase_t phase0, phase1, phase2; + node_t *fanin, *fanin0, *fanin1, *fanin2; + node_cube_t cube0, cube1; + + num_fanin = node_num_fanin(f); + if (num_fanin > 3) return 0; + num_cube = node_num_cube(f); + if (num_cube > 2) return 0; + node_fn = node_function(f); + switch (num_fanin) { + case 0: + if (node_fn == NODE_0) { + *zero = node_constant(0); + *one = node_constant(0); + *select = node_constant(0); + return 1; + } + assert(node_fn == NODE_1); + *zero = node_constant(1); + *one = node_constant(1); + *select = node_constant(1); + return 1; + case 1: + fanin = node_get_fanin(f, 0); + if (node_fn == NODE_BUF) { + *zero = node_constant(0); + *one = node_constant(1); + *select = node_literal(fanin, 1); + return 1; + } + assert(node_fn == NODE_INV); + *zero = node_constant(1); + *one = node_constant(0); + *select = node_literal(fanin, 1); + return 1; + case 2: + fanin0 = node_get_fanin(f, 0); + fanin1 = node_get_fanin(f, 1); + phase0 = node_input_phase(f, fanin0); + phase1 = node_input_phase(f, fanin1); + if ((phase0 != POS_UNATE) && (phase1 != POS_UNATE)) return 0; + /* num cubes = 1 */ + /*---------------*/ + if (num_cube == 1) { + if ((phase0 == POS_UNATE) && (phase1 == NEG_UNATE)) { + *zero = node_literal(fanin0, 1); + *one = node_constant(0); + *select = node_literal(fanin1, 1); + } else { + assert((phase0 != BINATE) && (phase1 == POS_UNATE)); + *select = node_literal(fanin0, 1); + if (phase0 == POS_UNATE) { + *zero = node_constant(0); + *one = node_literal(fanin1, 1); + } else { + *zero = node_literal(fanin1, 1); + *one = node_constant(0); + } + } + return 1; + } + /* num cubes = 2 */ + /*---------------*/ + if (phase0 == POS_UNATE) { + if (phase1 == POS_UNATE) { + *zero = node_literal(fanin1, 1); + *one = node_constant(1); + *select = node_literal(fanin0, 1); + } else { + assert(phase1 == NEG_UNATE); + *zero = node_constant(1); + *one = node_literal(fanin0, 1); + *select = node_literal(fanin1, 1); + } + } else { + assert ((phase0 == NEG_UNATE) && (phase1 == POS_UNATE)); + *zero = node_constant(1); + *one = node_literal(fanin1, 1); + *select = node_literal(fanin0, 1); + } + return 1; + case 3: + if (num_cube != 2) return 0; + cube0 = node_get_cube(f, 0); + cube1 = node_get_cube(f, 1); + if ((pld_num_fanin_cube(cube0, f) != 2) || (pld_num_fanin_cube(cube1, f) != 2)) + return 0; + fanin0 = node_get_fanin(f, 0); + fanin1 = node_get_fanin(f, 1); + fanin2 = node_get_fanin(f, 2); + phase0 = node_input_phase(f, fanin0); + phase1 = node_input_phase(f, fanin1); + phase2 = node_input_phase(f, fanin2); + if ((phase0 == POS_UNATE) && (phase1 == POS_UNATE) && (phase2 == BINATE)) { + if (node_get_literal(cube0, 2) == ONE) { + if (node_get_literal(cube0, 0) == ONE) { + /* f = fanin0 fanin2 + fanin1 fanin2' */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin1, fanin0, fanin2); + } else { + /* f = fanin1 fanin2 + fanin0 fanin2' */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin0, fanin1, fanin2); + } + } else { + if (node_get_literal(cube0, 0) == ONE) { + /* f = fanin0 fanin2' + fanin1 fanin2 */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin0, fanin1, fanin2); + } else { + /* f = fanin1 fanin2' + fanin0 fanin2 */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin1, fanin0, fanin2); + } + } + return 1; + } + if ((phase0 == POS_UNATE) && (phase1 == BINATE) && (phase2 == POS_UNATE)) { + if (node_get_literal(cube0, 1) == ONE) { + if (node_get_literal(cube0, 0) == ONE) { + /* f = fanin0 fanin1 + fanin2 fanin1' */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin2, fanin0, fanin1); + } else { + /* f = fanin2 fanin1 + fanin0 fanin1' */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin0, fanin2, fanin1); + } + } else { + if (node_get_literal(cube0, 0) == ONE) { + /* f = fanin0 fanin1' + fanin2 fanin1 */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin0, fanin2, fanin1); + } else { + /* f = fanin2 fanin1' + fanin0 fanin1 */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin2, fanin0, fanin1); + } + } + return 1; + } + if ((phase0 == BINATE) && (phase1 == POS_UNATE) && (phase2 == POS_UNATE)) { + if (node_get_literal(cube0, 0) == ONE) { + if (node_get_literal(cube0, 1) == ONE) { + /* f = fanin1 fanin0 + fanin2 fanin0' */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin2, fanin1, fanin0); + } else { + /* f = fanin2 fanin0 + fanin1 fanin0' */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin1, fanin2, fanin0); + } + } else { + if (node_get_literal(cube0, 1) == ONE) { + /* f = fanin1 fanin0' + fanin2 fanin0 */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin1, fanin2, fanin0); + } else { + /* f = fanin2 fanin0' + fanin1 fanin0 */ + /*------------------------------------*/ + act_map_mux(zero, one, select, fanin2, fanin1, fanin0); + } + } + return 1; + } + return 0; + } + /*NOTREACHED */ +} + +act_map_mux(zero, one, select, z, o, s) + node_t **zero, **one, **select, *z, *o, *s; +{ + *zero = node_literal(z, 1); + *one = node_literal(o, 1); + *select = node_literal(s, 1); +} + +act_print_match(match) + ACT_MATCH *match; +{ + act_print_match_field(match->A0, "A0"); + act_print_match_field(match->A1, "A1"); + act_print_match_field(match->SA, "SA"); + act_print_match_field(match->B0, "B0"); + act_print_match_field(match->B1, "B1"); + act_print_match_field(match->SB, "SB"); + act_print_match_field(match->S0, "S0"); + act_print_match_field(match->S1, "S1"); +} + +act_print_match_field(node, pin) + node_t *node; + char *pin; +{ + (void) printf("%s = ", pin); + node_print_rhs(stdout, node); + (void) printf("\n"); +} + +act_free_match(match) + ACT_MATCH *match; +{ + if (match == NIL (ACT_MATCH)) return; + + node_free(match->A0); + node_free(match->A1); + node_free(match->SA); + node_free(match->B0); + node_free(match->B1); + node_free(match->SB); + node_free(match->S0); + node_free(match->S1); + FREE(match); +} + +/*--------------------------------------------------------------------- + return A a + Ac_B a_c b. +----------------------------------------------------------------------*/ +static node_t * +act_form_G(A, Ac_B, a, b, a_c) + node_t *A, *Ac_B, *a, *b, *a_c; +{ + node_t *t1, *t2, *t3, *t4; + + t1 = node_and(A, a); + + t2 = node_and(a_c, b); + t3 = node_and(Ac_B, t2); + t4 = node_or(t1, t3); + + node_free(t1); + node_free(t2); + node_free(t3); + + return t4; +} + +int +act_find_H(f, G, Ac, Bc, index_A, index_B, Ac_B, A_Bc, pB0, pB1, pSB) + node_t *f, *G, *Ac, *Bc, *Ac_B, *A_Bc; + int index_A, index_B; + node_t **pB0, **pB1, **pSB; +{ + node_t *ac_bc, *one, *C; + node_t *C_lit_pos, *C_lit_neg; + int i; + + ac_bc = node_and(Ac, Bc); + + /* check H = 0 */ + /*-------------*/ + if (act_is_mux_function(G, pB0, pB1, pSB)) { + node_free(ac_bc); + return 1; + } + + one = node_constant(1); + + /* check H = 1 */ + /*-------------*/ + if (act_find_g_and_match(f, G, one, one, + ac_bc, pB0, pB1, pSB)) { + node_free(ac_bc); + node_free(one); + return 1; + } + foreach_fanin(f, i, C) { + if (i == index_A || i == index_B) continue; + + /* check H = C */ + /*-------------*/ + C_lit_pos = node_literal(C, 1); + if (act_find_g_and_match(f, G, C_lit_pos, one, + ac_bc, pB0, pB1, pSB)) { + node_free_list(C_lit_pos, ac_bc, one, NIL (node_t), NIL(node_t)); + return 1; + } + /* check H = C' */ + /*--------------*/ + C_lit_neg = node_literal(C, 0); + if (act_find_g_and_match(f, G, C_lit_neg, one, + ac_bc, pB0, pB1, pSB)) { + node_free_list(C_lit_pos, ac_bc, one, C_lit_neg, NIL(node_t)); + return 1; + } + node_free(C_lit_neg); + node_free(C_lit_pos); + } + + /* try two input functions H */ + /*---------------------------*/ + if (act_is_two_input_H(Ac_B)) { + if (act_find_g_and_match(f, G, Ac_B, one, ac_bc, pB0, pB1, pSB)) { + node_free(ac_bc); + node_free(one); + return 1; + } + } + + if (act_is_two_input_H(A_Bc)) { + if (act_find_g_and_match(f, G, A_Bc, one, ac_bc, pB0, pB1, pSB)) { + node_free(ac_bc); + node_free(one); + return 1; + } + } + + /* non-disjoint match not found for given A, B*/ + /*--------------------------------------------*/ + node_free(ac_bc); + node_free(one); + return 0; +} + +/*-------------------------------------------------------------- + Construct function g = G + H ac_bc. First you have to construct + H. H is essentially C D. +---------------------------------------------------------------*/ +int +act_find_g_and_match(f, G, C, D, ac_bc, pB0, pB1, pSB) + node_t *f, *G, *C, *D, *ac_bc, **pB0, **pB1, **pSB; +{ + + node_t *H, *g, *t1; + + H = node_and(C, D); + t1 = node_and(H, ac_bc); + g = node_or(G, t1); + node_free(t1); + node_free(H); + simplify_node(g, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, SIM_FILTER_NONE, + SIM_ACCEPT_SOP_LITS); + if (act_is_mux_function(g, pB0, pB1, pSB)) { + node_free(g); + return 1; + } + node_free(g); + return 0; +} + + +node_free_list(n1, n2, n3, n4, n5) + node_t *n1, *n2, *n3, *n4, *n5; +{ + if (n1 != NIL (node_t)) node_free(n1); + if (n2 != NIL (node_t)) node_free(n2); + if (n3 != NIL (node_t)) node_free(n3); + if (n4 != NIL (node_t)) node_free(n4); + if (n5 != NIL (node_t)) node_free(n5); +} + +/*------------------------------------------------------------------------------- + Returns 1 if the node_function if of the type a b, or a' b or a b'. Else + returns 0. +--------------------------------------------------------------------------------*/ +int +act_is_two_input_H(node) + node_t *node; +{ + node_t *a, *b; + + if ((node_num_fanin(node) != 2) || (node_num_cube(node) != 1)) return 0; + a = node_get_fanin(node, 0); + b = node_get_fanin(node, 1); + if ((node_input_phase(node, a) == NEG_UNATE) && + (node_input_phase(node, b) == NEG_UNATE)) return 0; + return 1; +} diff --git a/sis/pld/act_bool.h b/sis/pld/act_bool.h new file mode 100644 index 0000000..4cfff44 --- /dev/null +++ b/sis/pld/act_bool.h @@ -0,0 +1,23 @@ +typedef struct act_match_defn { + node_t *A0; + node_t *A1; + node_t *SA; + node_t *B0; + node_t *B1; + node_t *SB; + node_t *S0; + node_t *S1; +} ACT_MATCH; + +typedef struct cofc_struct_defn { + node_t *pos; + node_t *neg; + int pos_mux; + node_t *B0; + node_t *B1; + node_t *SB; + node_t *node; + node_t *fanin; +} COFC_STRUCT; + +extern ACT_MATCH *act_is_act_function(); diff --git a/sis/pld/act_collapse.c b/sis/pld/act_collapse.c new file mode 100644 index 0000000..2144b9f --- /dev/null +++ b/sis/pld/act_collapse.c @@ -0,0 +1,287 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_collapse.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +/* Aug 21, 1991 - changed the collapse routine for node to take care of + no duplication of the network when a collapse is considered. */ + +#include "sis.h" +#include "pld_int.h" +#include "math.h" + +static node_t *act_partial_collapse_find_max_score(); + +/*---------------------------------------------------------------------------------- + This file has routines for partial collapse of a node without using lindo. +----------------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------------- + As obvious from the name, it does partial collapse on the network when it finds + that lindo is not in the path. Assigns a score to each nodewhich is a measure of + the gain that might be obtained by collapsing the node into each of the fanouts. + This score is just based on the number of fanins, fanouts, cost of node etc. + Updates the score after each successful partial collapse. Tries to collapse + till all nodes get score 0, or have been tried for collapse, but unsuccessfully. +------------------------------------------------------------------------------------*/ +int +act_partial_collapse_without_lindo(network, cost_table, init_param) + network_t *network; + st_table *cost_table; + act_init_param_t *init_param; +{ + st_table *score_table; + int collapsed, gain, total_gain, score; + node_t *node, *act_partial_collapse_find_max_score(); + + score_table = st_init_table(strcmp, st_strhash); + act_partial_collapse_assign_score_network(network, score_table, cost_table, init_param); + + total_gain = 0; + while (1) { + node = act_partial_collapse_find_max_score(network, score_table, &score); + if (score == 0) { + st_free_table(score_table); + if (ACT_DEBUG) + (void) printf("****gain in partial collapse without lindo is %d\n", total_gain); + return total_gain; + } + if (ACT_DEBUG) (void) printf("node from score_table = %s\n", node_long_name(node)); + collapsed = act_partial_collapse_node(network, node, cost_table, init_param, + &gain, score_table); + if (collapsed) { + if (ACT_DEBUG) (void) printf("collapsed node %s\n", node_long_name(node)); + total_gain += gain; + } + } +} + + +/*--------------------------------------------------------------------------------------- + Checks if it is beneficial to collapse node into each of the fanouts. If so, does that + and returns 1 and the gain in pgain. Changes the cost_table entries of these fanouts + and deletes the entry of node. Else returns 0 and pgain is not assigned any values. + Changed Aug 21, 1991 - no duplication of network now... +-----------------------------------------------------------------------------------------*/ + +int +act_partial_collapse_node(network, node, cost_table, init_param, pgain, score_table) + network_t *network; + node_t *node; + st_table *cost_table; + act_init_param_t *init_param; + int *pgain; + st_table *score_table; +{ + int gain, old_cost, score; + char *name, *name1, *dummy; + node_t *fanout, *fanout_simpl, *dup_fanout; + lsGen genfo; + COST_STRUCT *cost_struct; + st_table *fo_table; + array_t *fanout_array, *real_fanout_array; + int i, num_fanout; + + fo_table = st_init_table(strcmp, st_strhash); + name = node_long_name(node); + assert(st_lookup(cost_table, name, &dummy)); + gain = ((COST_STRUCT *) dummy)->cost; + + /* compute the gain if the node is collapsed into each of its + fanouts and is then removed from the network. The cost is stored in the + fo_table for each of the fanouts of the node */ + /*------------------------------------------------------------------------*/ + + /* for each fanout, recompute the cost */ + /*-------------------------------------*/ + real_fanout_array = array_alloc(node_t *, 0); + foreach_fanout(node, genfo, fanout) { + array_insert_last(node_t *, real_fanout_array, fanout); + } + num_fanout = array_n(real_fanout_array); + fanout_array = array_alloc(node_t *, 0); + for (i = 0; i < num_fanout; i++) { + fanout = array_fetch(node_t *, real_fanout_array, i); + dup_fanout = node_dup(fanout); + (void) node_collapse(dup_fanout, node); + fanout_simpl = node_simplify(dup_fanout, NIL(node_t), NODE_SIM_ESPRESSO); + /* + node_free(dup_fanout); + dup_fanout = fanout_simpl; + */ + node_replace(dup_fanout, fanout_simpl); + array_insert_last(node_t *, fanout_array, dup_fanout); + /* a hack to get -h 1 option to work */ + dup_fanout->network = fanout->network; + cost_struct = + act_evaluate_map_cost(dup_fanout, init_param, NIL(network_t), + NIL(array_t), NIL(st_table)); + dup_fanout->network = NIL (network_t); + if (ACT_DEBUG) { + (void) printf("new cost of fanout node %s = %d\n", node_long_name(dup_fanout), + cost_struct->cost); + } + /* put the names in act vertices now */ + /*-----------------------------------*/ + act_partial_collapse_update_act_fields(network, dup_fanout, cost_struct); + name = node_long_name(dup_fanout); + assert(!st_insert(fo_table, name, (char *) cost_struct)); + assert(st_lookup(cost_table, name, &dummy)); + old_cost = ((COST_STRUCT *)dummy)->cost; + gain = gain + old_cost - (cost_struct->cost); + } + if (gain <= 0) { + /* set the score of node to 0, free the storage */ + /*----------------------------------------------*/ + name = node_long_name(node); + assert(st_insert(score_table, name, (char *) 0)); + free_cost_table_without_freeing_key(fo_table); + for (i = 0; i < num_fanout; i++) { + dup_fanout = array_fetch(node_t *, fanout_array, i); + node_free(dup_fanout); + } + array_free(fanout_array); + array_free(real_fanout_array); + return 0; + } + + for (i = 0; i < num_fanout; i++) { + dup_fanout = array_fetch(node_t *, fanout_array, i); + fanout = array_fetch(node_t *, real_fanout_array, i); + /* collapse node into fanout, update the cost_table entry */ + /*--------------------------------------------------------*/ + name1 = node_long_name(fanout); + if (ACT_DEBUG) assert(!strcmp(name1, node_long_name(dup_fanout))); /* checking */ + name = util_strsav(name1); + assert(st_delete(cost_table, &name1, &dummy)); + (void) free_cost_struct((COST_STRUCT *) dummy); + FREE(name1); + assert(node_long_name(fanout) != NIL (char)); + assert(st_lookup(fo_table, name, (char **)&cost_struct)); + assert(!st_insert(cost_table, name, (char *) cost_struct)); + /* updating the score of the fanout */ + /*----------------------------------*/ + (void) act_partial_collapse_assign_score_node(fanout, score_table, cost_table, init_param); + (void) node_replace(fanout, dup_fanout); + } /* for i = 0 */ + array_free(fanout_array); + array_free(real_fanout_array); + st_free_table(fo_table); + /* delete the collapsed node from cost_table, network.*/ + /*----------------------------------------------------*/ + name1 = node_long_name(node); + assert(st_delete(score_table, &name1, (char **) &score)); + assert(st_delete(cost_table, &name1, &dummy)); + (void) free_cost_struct((COST_STRUCT *) dummy); + FREE(name1); + network_delete_node(network, node); + *pgain = gain; + return 1; +} + +int +act_partial_collapse_assign_score_node(node, score_table, cost_table, init_param) + node_t *node; + st_table *score_table; + st_table *cost_table; + act_init_param_t *init_param; +{ + int score, num_fanin, cost, num_fanouts, i; + node_t *fanout; + char *name; + + if (node->type != INTERNAL) return (-1); + name = node_long_name(node); + num_fanin = node_num_fanin(node); + if ((num_fanin > init_param->FANIN_COLLAPSE) || (is_anyfo_PO(node))) { + /* give a score of 0 to this node */ + /*--------------------------------*/ + (void) st_insert(score_table, name, (char *) 0); + return 0; + } + cost = cost_of_node(node, cost_table); + if (cost > 3) { + (void) st_insert(score_table, name, (char *) 0); + return 0; + } + if (cost == 0) cost = 1; + num_fanouts = node_num_fanout(node); + score = 0; + for (i = 0; i < num_fanouts; i++) { + fanout = node_get_fanout(node, i); + score += cost_of_node(fanout, cost_table); + } + score = (int) ceil((double) (score / cost)); + (void) st_insert(score_table, name, (char *) score); + return score; +} + +/*----------------------------------------------------------- + Returns the node with the highest score in the score_table. + The corresponding score is set in pscore. Assumes that all + scores are nonnegative. +-------------------------------------------------------------*/ +static +node_t * +act_partial_collapse_find_max_score(network, score_table, pscore) + network_t *network; + st_table *score_table; + int *pscore; +{ + lsGen gen; + node_t *node, *node_max; + int max_score, score; + + max_score = -1; + node_max = NIL (node_t); + + foreach_node(network, gen, node) { + if (node->type != INTERNAL) continue; + assert(st_lookup_int(score_table, node_long_name(node), &score)); + if (score > max_score) { + max_score = score; + node_max = node; + } + } + *pscore = max_score; + return node_max; +} + +/*-------------------------------------------------------------------------------- + Assigns a score to each internal node. If the cost of the node is > 3, it is 0. + Else it is based on sum of costs of the fanout nodes and the cost of the node. + Stores all the costs in the score_table. +---------------------------------------------------------------------------------*/ +int +act_partial_collapse_assign_score_network(network, score_table, cost_table, init_param) + network_t *network; + st_table *score_table; + st_table *cost_table; + act_init_param_t *init_param; +{ + array_t *nodevec; + int i, num_nodes, score; + node_t *node; + + nodevec = network_dfs(network); + num_nodes = array_n(nodevec); + /* assign score to all the internal nodes */ + /*----------------------------------------*/ + for (i = 0; i < num_nodes; i++) { + node = array_fetch(node_t *, nodevec, i); + score = act_partial_collapse_assign_score_node(node, score_table, cost_table, + init_param); + if (ACT_DEBUG && (score != -1)) + (void) printf("---assigned score of %d to node %s\n", score, node_long_name(node)); + } + array_free(nodevec); +} + + + + + diff --git a/sis/pld/act_create.c b/sis/pld/act_create.c new file mode 100644 index 0000000..463ca3a --- /dev/null +++ b/sis/pld/act_create.c @@ -0,0 +1,630 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_create.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" +extern int MAXOPTIMAL; + + +/* constructing the local and global ACTs +*/ + +/* used in applyCreate */ +typedef struct tree_entry_defn{ + int buf; + ACT_VERTEX_PTR dag; +} tree_t; + +extern void p_applyCreate(); +extern ACT_VERTEX_PTR p_actCreateStep(); +extern ACT_VERTEX_PTR p_optimalDag(); +extern array_t *pld_shuffle(); +extern void p_actCreate4Set(); +extern void p_permute(); +extern enum st_retval p_freeTree(); +extern ACT_VERTEX_PTR p_treeNodeDag(); +extern ACT_VERTEX_PTR p_terminalDag(); +extern array_t *p_alap_order_nodes(); +extern ACT_VERTEX_PTR actPartialReduce(); + +void +p_actCreate4Set(node_vec, node_list, locality, order_style, mode, network, delay_values, cost_table) +array_t *node_vec, *node_list; +int locality, order_style; +float mode; +network_t *network; +array_t *delay_values; +st_table *cost_table; +{ + node_t *current_node; + int i, j, num_fanin, input_size, com_local; + ACT_PTR act; + ACT_VERTEX_PTR p_optimalDag(), p_actCreateStep(), actReduce(); + + input_size = array_n(node_vec); + if(node_list == NIL(array_t)){ + com_local = 1; + } else { + com_local = 0; + } + for(i = 0; i<input_size; i++){ + current_node = array_fetch(node_t *, node_vec, i); + if(node_function(current_node) != NODE_PO){ + if(locality){ + if(com_local){ + node_list = array_alloc(node_t *, 0); + num_fanin = node_num_fanin(current_node); + for(j=0; j<num_fanin; j++){ + array_insert(node_t *, node_list, j, + node_get_fanin(current_node,j)); + } + } + act = ALLOC(ACT, 1); + act->node_name = util_strsav(node_name(current_node)); + + switch(order_style){ + case OPTIMAL: + act->root =p_optimalDag(current_node, node_list, mode, network, delay_values, cost_table); + break; + case RANDOM: + node_list = pld_shuffle(node_list); + act->root = p_actCreateStep(current_node, 0, + node_list, 1); + break; + default: /* Fanin */ + act->root = p_actCreateStep(current_node, 0, + node_list, 1); + break; + } + + act->root = actReduce(act->root); + act->node_list = node_list; + ACT_SET(current_node)->LOCAL_ACT = ALLOC(ACT_ENTRY, 1); + ACT_SET(current_node)->LOCAL_ACT->act = act; + ACT_SET(current_node)->LOCAL_ACT->order_style = + (num_fanin <= MAXOPTIMAL ) ? order_style : FANIN; + } else { + p_applyCreate(current_node, node_list); + ACT_SET(current_node)->GLOBAL_ACT->order_style = order_style; + } + } + } +} + +ACT_VERTEX_PTR +p_actCreateStep(current_node, level, node_list, locality) +node_t *current_node; +int level, locality; +array_t *node_list; + +{ int index_size ; + ACT_VERTEX_PTR u; + node_function_t func; + node_t *p, *q, *r, *low_node, *high_node, *t_node; + + index_size = array_n(node_list); + u = ALLOC(ACT_VERTEX, 1); + u->id = 0; + u->mark = 0; + u->index_size = index_size; + u->node = NIL (node_t); + u->name = NIL (char); + u->multiple_fo = 0; + u->cost = 0; + u->mapped = 0; + func = node_function(current_node); + if(func == NODE_0 || func == NODE_1){ + + u->value = (func == NODE_0) ? 0 : 1; + u->low = NIL (ACT_VERTEX); + u->high = NIL (ACT_VERTEX); + u->index = index_size; + return(u); + } else { + u->value = NO_VALUE; + level--; + do{ + level++; + if(level >= array_n(node_list)){ + u->value = 1; + u->low = NIL (ACT_VERTEX); + u->high = NIL (ACT_VERTEX); + u->index = index_size; + return(u); + } + t_node = array_fetch(node_t *,node_list, level); + if(node_get_fanin_index(current_node, t_node)!= -1){ + node_algebraic_cofactor(current_node, + t_node, &p, &q, &r); + low_node = node_or(q, r); + high_node = node_or(p, r); + simplify_node(low_node, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, + SIM_FILTER_NONE, SIM_ACCEPT_SOP_LITS); + simplify_node(high_node, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, + SIM_FILTER_NONE, SIM_ACCEPT_SOP_LITS); + node_free(p); + node_free(q); + node_free(r); + if(my_node_equal(low_node, high_node)){ + node_free(low_node); + node_free(high_node); + } else break; + } + } while (1); + + u->index = level; + level++; + u->low = p_actCreateStep(low_node, level, node_list, locality); + node_free(low_node); + u->high = p_actCreateStep(high_node, level, node_list, locality); + node_free(high_node); + return(u); } +} + + +/* optimal ACT using brute force, only for local ACT +*/ + + +ACT_VERTEX_PTR +p_optimalDag(current_node, node_list, mode, network, delay_values, cost_table) +node_t *current_node; +array_t *node_list; +float mode; +network_t *network; +array_t *delay_values; +st_table *cost_table; + +{ + int best_cost, n, j; + double best_cost_and_delay; /* best_delay added later- July 5, 90 -- Rajeev*/ + array_t *best_list; + node_t *t_node; + + /* brute force optimal is only done for fanin size <= MAXOPTIMAL + otherwise the fanin ordered ACT is generated */ + + if(array_n(node_list) > MAXOPTIMAL) { + (void) fprintf(sisout, + "Optimal ordering too expensive for node %s, fanin ordering chosen\n", + node_name(current_node)); + return(p_actCreateStep(current_node, 0, node_list, 1)); + } else { + best_cost = HICOST; + best_cost_and_delay = (double) HICOST; + best_list = array_alloc(node_t *, 0); + n = array_n(node_list); + p_permute(current_node, node_list, n, &best_cost, &best_cost_and_delay, + &best_list, mode, network, delay_values, cost_table); + for(j = 0; j<n; j++){ + t_node = array_fetch(node_t *, best_list, j); + array_insert(node_t *, node_list, j, t_node); + } + array_free(best_list); + + /* remove */ + /* Rajeev put the next comment */ + /* (void) fprintf(sisout, " Final Check: "); + for(j = 0; j<n; j++){ + (void) fprintf(sisout, + " %s ", node_name(array_fetch(node_t *, node_list, j))); + (void) fprintf(sisout, "\n"); + } */ + + /* end remove */ + + return(p_actCreateStep(current_node, 0, node_list, 1)); + } +} + +/* permutation routine from kruse +*/ + +void +p_permute(current_node, list, n, best_cost_ptr, best_cost_and_delay_ptr, pbest_list, + mode, network, delay_values, cost_table) +node_t *current_node; +array_t *list, **pbest_list; +int n, *best_cost_ptr; +double *best_cost_and_delay_ptr; +float mode; +network_t *network; +array_t *delay_values; +st_table *cost_table; +{ + int c, cost; + double arrival_time, this_cost_and_delay; + node_t *t, *t1; + ACT_VERTEX_PTR dag; + COST_STRUCT *cost_node; + array_t *best_list; + + best_list = *pbest_list; + c = 1; + if(n>2) { + /* changed - July 5, 90 */ + /*----------------------*/ + /* if (*best_cost_ptr <= 1) ; */ + + if ((mode == AREA) && (*best_cost_ptr <= 1)); + + else + p_permute(current_node, list, n-1, best_cost_ptr, + best_cost_and_delay_ptr, + pbest_list, mode, network, delay_values, cost_table); + } else { + act_print_array(list); + dag = p_actCreateStep(current_node, 0, list, 1); + dag = actReduce(dag); + /* changing the cost function */ + dag->my_type = ORDERED; + WHICH_ACT = ORDERED; + dag->node = current_node; + put_node_names_in_act(dag, list); + if (mode == AREA) { + cost_node = make_tree_and_map(current_node, dag); + } + else { + cost_node = make_tree_and_map_delay(current_node, dag, network, + delay_values, cost_table, mode); + arrival_time = cost_node->arrival_time; + } + cost = cost_node->cost; + + /* cost = dag->id + 1; */ + if (mode == AREA) { + if (cost < *best_cost_ptr) { + *best_cost_ptr = cost; + array_free(best_list); + best_list = array_dup(list); + *pbest_list = best_list; + } + } + else { + this_cost_and_delay = ((double)(1.00 - mode)) * ((double) cost) + ((double) mode) * arrival_time; + if (this_cost_and_delay < *best_cost_and_delay_ptr) { + *best_cost_and_delay_ptr = this_cost_and_delay; + array_free(best_list); + best_list = array_dup(list); + *pbest_list = best_list; + } + } + p_dagDestroy(dag); + /* act_act_free(current_node); */ + FREE(cost_node); + } + + while(c<n){ + if((n%2)==1){ + t = array_fetch(node_t *, list, n-1); + t1 = array_fetch(node_t *, list, 0); + array_insert(node_t *, list, n-1, t1); + array_insert(node_t *, list, 0, t); + } else { + t = array_fetch(node_t *, list, n-1); + t1 = array_fetch(node_t *, list, c-1); + array_insert(node_t *, list, n-1, t1); + array_insert(node_t *, list, c-1, t); + } + c++; + if(n>2){ + /* changed - July 5, 90 */ + /*----------------------*/ + /* if (*best_cost_ptr <= 1) ; */ + + if ((mode == AREA) && (*best_cost_ptr <= 1)) ; + + else { + p_permute(current_node, list, n-1, best_cost_ptr, + best_cost_and_delay_ptr, + pbest_list, mode, network, delay_values, cost_table); + } + } else { + act_print_array(list); + dag = p_actCreateStep(current_node, 0, list, 1); + dag = actReduce(dag); + dag->my_type = ORDERED; + WHICH_ACT = ORDERED; + dag->node = current_node; + put_node_names_in_act(dag, list); + if (mode == AREA) { + cost_node = make_tree_and_map(current_node, dag); + } + else { + cost_node = make_tree_and_map_delay(current_node, dag, + network, delay_values, + cost_table, mode); + arrival_time = cost_node->arrival_time; + } + cost = cost_node->cost; + /* cost = dag->id + 1; */ + if (mode == AREA) { + if (cost < *best_cost_ptr) { + *best_cost_ptr = cost; + array_free(best_list); + best_list = array_dup(list); + *pbest_list = best_list; + } + } + else { + this_cost_and_delay = + ((double)(1.00 - mode)) * ((double) cost) + ((double) mode) * arrival_time; + if (this_cost_and_delay < *best_cost_and_delay_ptr) { + *best_cost_and_delay_ptr = this_cost_and_delay; + array_free(best_list); + best_list = array_dup(list); + *pbest_list = best_list; + } + } + /* act_act_free(current_node); */ + p_dagDestroy(dag); + FREE(cost_node); + + } + } +} + +void +p_applyCreate(node, order_list) +node_t *node; +array_t *order_list; +{ + ACT_VERTEX_PTR term_0, term_1, u, p_terminalDag(), p_rootCopy(); + ACT_VERTEX_PTR p_rootComplement(), p_treeNodeDag(); + enum st_retval p_freeTree(); + int i, tree_size, index_size; + array_t *factor_tree; + st_table *tree_table; + node_t *act_tree_node, *t_node, *fanin_node, *root; + tree_t *tree_entry; + char dummy; + ACT_PTR act; + ACT_ENTRY_PTR act_entry; + + if(ACT_SET(node)->GLOBAL_ACT != NIL (ACT_ENTRY)){ + return; + } + index_size = array_n(order_list); + if(node_num_fanin(node) == 0){ + if(node_function(node) == NODE_0){ + u = p_terminalDag(0, index_size); + } else if(node_function(node) == NODE_1){ + u = p_terminalDag(1, index_size); + } else{ + term_0 = ALLOC(ACT_VERTEX, 1); + term_0->id = 0; + term_0->mark = 0; + term_0->index = index_size; + term_0->index_size = index_size; + term_0->value = 0; + term_0->low = NIL (act_t); + term_0->high = NIL (act_t); + term_0->node = NIL (node_t); + term_0->name = NIL (char); + + term_1 = ALLOC(ACT_VERTEX, 1); + term_1->id = 1; + term_1->mark = 0; + term_1->index = index_size; + term_1->index_size = index_size; + term_1->value = 1; + term_1->low = NIL (act_t); + term_1->high = NIL (act_t); + term_1->node = NIL (node_t); + term_1->name = NIL (char); + + u = ALLOC(ACT_VERTEX, 1); + u->id = 2; + u->mark = 0; + for(i= 0; i<index_size; i++){ + t_node = array_fetch(node_t *, order_list, i); + if(t_node == node){ + u->index = i; + u->node = t_node; + break; + } + } + u->index_size = index_size; + u->value = NO_VALUE; + u->low = term_0; + u->high = term_1; + u->name = NIL (char); + } + } else { + factor_quick(node); + factor_tree = factor_to_nodes(node); + tree_size = array_n(factor_tree); + tree_table = st_init_table(st_ptrcmp, st_ptrhash); + if(tree_size > 1){ + for(i=1; i<tree_size; i++){ + act_tree_node = array_fetch(node_t *, factor_tree, i); + tree_entry = ALLOC(tree_t, 1); + switch(node_function(act_tree_node)){ + case NODE_BUF : + tree_entry->buf = 1; + fanin_node = node_get_fanin(act_tree_node, 0); + if(ACT_SET(fanin_node)->GLOBAL_ACT == NIL (ACT_ENTRY)){ + p_applyCreate(fanin_node, order_list); + } + tree_entry->dag = ACT_SET(fanin_node)->GLOBAL_ACT->act->root; + break; + + case NODE_INV : + tree_entry->buf = 2; + fanin_node = node_get_fanin(act_tree_node, 0); + if(ACT_SET(fanin_node)->GLOBAL_ACT == NIL (ACT_ENTRY)){ + p_applyCreate(fanin_node, order_list); + } + tree_entry->dag = ACT_SET(fanin_node)->GLOBAL_ACT->act->root; + break; + + default: + tree_entry->dag = NIL (act_t); + tree_entry->buf = 0; + break; + } + (void) st_insert(tree_table, (char *) act_tree_node, (char *) tree_entry); + } + } + + root = array_fetch(node_t *, factor_tree, 0); + switch(node_function(root)){ + case NODE_BUF: + fanin_node = node_get_fanin(root, 0); + if(ACT_SET(fanin_node)->GLOBAL_ACT == NIL (ACT_ENTRY)){ + p_applyCreate(fanin_node, order_list); + } + u = p_rootCopy(ACT_SET(fanin_node)->GLOBAL_ACT->act->root); + break; + case NODE_INV: + fanin_node = node_get_fanin(root, 0); + if(ACT_SET(fanin_node)->GLOBAL_ACT == NIL (ACT_ENTRY)){ + p_applyCreate(fanin_node, order_list); + } + u = p_rootComplement(ACT_SET(fanin_node)->GLOBAL_ACT->act->root); + break; + default : + u = p_treeNodeDag(root, tree_table, order_list); + break; + } + (void) st_foreach(tree_table, p_freeTree, &dummy); + array_free(factor_tree); + (void) st_free_table(tree_table); + node_free(root); + } + + act = ALLOC(ACT, 1); + act->root = u; + act->node_list = order_list; + act->node_name = util_strsav(node_name(node)); + + act_entry = ALLOC(ACT_ENTRY, 1); + act_entry->act = act; + act_entry->order_style = HEURISTIC; + + ACT_SET(node)->GLOBAL_ACT = act_entry; + return; +} + +/*ARGSUSED*/ +enum st_retval +p_freeTree(key, value, arg) +char *key, *value, *arg; +{ + tree_t *tree_entry; + node_t *node; + + tree_entry = (tree_t *) value; + if(tree_entry->buf == 0){ + p_dagDestroy(tree_entry->dag); + } + node = (node_t *) key; + node_free(node); + FREE(tree_entry); + return(ST_CONTINUE); +} + +ACT_VERTEX_PTR +p_treeNodeDag(node, tree_table, order_list) +node_t *node; +st_table *tree_table; +array_t *order_list; +{ + node_t *fanin_node; + tree_t *tree_entry; + ACT_VERTEX_PTR fanin_dag, temp_dag, current_dag, apply(); + input_phase_t phase; + char *dummy; + int i, op, num_fanin, index_size, phase_comp, phase_num; + + index_size = array_n(order_list); + switch(node_function(node)){ + case NODE_AND : op = AND; + current_dag = p_terminalDag(1, index_size); + break; + case NODE_OR : op = OR; + current_dag = p_terminalDag(0, index_size); + break; + } + + num_fanin = node_num_fanin(node); + for(i=0; i<num_fanin; i++){ + phase_comp = 0; + fanin_node = node_get_fanin(node,i); + if(st_lookup(tree_table, (char *) fanin_node, &dummy)){ + tree_entry = (tree_t *) dummy; + if(tree_entry->dag == NIL (act_t)){ + tree_entry->dag = p_treeNodeDag(fanin_node, tree_table, order_list); + } + fanin_dag = tree_entry->dag; + if(tree_entry->buf == 2) phase_comp = 1; + } else { + if(ACT_SET(fanin_node)->GLOBAL_ACT == NIL (ACT_ENTRY)){ + p_applyCreate(fanin_node, order_list); + } + fanin_dag = ACT_SET(fanin_node)->GLOBAL_ACT->act->root; + } + + phase = node_input_phase(node, fanin_node); + temp_dag = current_dag; + switch(phase){ + case POS_UNATE: + if(phase_comp){ + phase_num = P10; + } else phase_num = P11; + break; + + case NEG_UNATE: + if(phase_comp){ + phase_num = P11; + } else phase_num = P10; + break; + } + current_dag = apply(current_dag, fanin_dag, op + phase_num); + p_dagDestroy(temp_dag); + } + return(current_dag); +} + +ACT_VERTEX_PTR +p_terminalDag(value, index_size) +int value, index_size; +{ + ACT_VERTEX_PTR u; + + u = ALLOC(ACT_VERTEX, 1); + u->id = 0; + u->mark = 0; + u->index = index_size; + u->index_size = index_size; + u->value = value; + u->low = NIL (act_t); + u->high = NIL (act_t); + u->node = node_constant(value); + u->name = NIL (char); + return(u); +} + +act_print_array(list) + array_t *list; +{ + int i; + node_t *n; + + if (ACT_DEBUG) { + (void) printf("creating bdd for order "); + for (i = 0; i < array_n(list); i++) { + n = array_fetch(node_t *, list, i); + (void) printf("%s", node_long_name(n)); + } + (void) printf("\n"); + } +} + + diff --git a/sis/pld/act_delay.c b/sis/pld/act_delay.c new file mode 100644 index 0000000..2d55a0f --- /dev/null +++ b/sis/pld/act_delay.c @@ -0,0 +1,74 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +array_t * +act_order_for_delay(node, cost_table) + node_t *node; + st_table *cost_table; +{ + array_t *result, *fanin_array; + int nsize, i, j; + char *name, *dummy; + node_t *fanin; + COST_STRUCT *cost_node; + + + switch(node_function(node)) { + case NODE_PI : return NIL (array_t); + case NODE_PO : return NIL (array_t); + case NODE_0 : return NIL (array_t); + case NODE_1 : return NIL (array_t); + default:; + } + + result = array_alloc(node_t *, 0); + fanin_array = array_alloc(COST_STRUCT *, 0); + + foreach_fanin(node, j, fanin) { + name = node_long_name(fanin); + assert(st_lookup(cost_table, name, &dummy)); + cost_node = (COST_STRUCT *) dummy; + array_insert_last(COST_STRUCT *, fanin_array, cost_node); + } + /* sort the fanin_array by the arrival times */ + /*-------------------------------------------*/ + array_sort(fanin_array, arrival_compare_fn); + + /* put the sorted fanins into the result array */ + /*---------------------------------------------*/ + if (ACT_DEBUG) (void) printf("printing delay order_list for node %s\n", node_long_name(node)); + nsize = array_n(fanin_array); + for (i = 0; i < nsize; i++) { + cost_node = array_fetch(COST_STRUCT *, fanin_array, i); + array_insert_last(node_t *, result, cost_node->node); + if (ACT_DEBUG) (void) printf("order_list[%d] = %s\n", i, node_long_name(cost_node->node)); + } + + array_free(fanin_array); + return result; + +} + +int arrival_compare_fn(c1, c2) + COST_STRUCT **c1, **c2; /* check this */ +{ + double arr1, arr2; + + arr1 = (*c1)->arrival_time; + arr2 = (*c2)->arrival_time; + + if (arr1 > arr2) return (-1); + if (arr1 < arr2) return 1; + return 0; +} + + diff --git a/sis/pld/act_dutil.c b/sis/pld/act_dutil.c new file mode 100644 index 0000000..728d0c1 --- /dev/null +++ b/sis/pld/act_dutil.c @@ -0,0 +1,780 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_dutil.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/*-------------------------------------------------------------------------------- + Given a mapped network, in which each node can be mapped onto + one basic block of MB architecture, prints out the value of the + arrival time of each of the outputs. Basically a forward delay trace. + Stores the arrival times in a table. Assumes that the arrival times of + the primary inputs have been set by delay_set command, else assumes them to + be all 0.0 +----------------------------------------------------------------------------------*/ + +void +act_delay_trace_forward(network, cost_table, delay_values) +network_t *network; +st_table *cost_table; +array_t *delay_values; +{ + double delaynum, total_delay, fanin_delay, max_fanin_delay, max_output_arrival_time; + int i, j, nsize, num_fanout; + node_t *node, *fanin, *slowest_po; + array_t *nodevec; + node_function_t node_fun; + COST_STRUCT *cost_node; + + max_output_arrival_time = (double) (-1.0); + slowest_po = NIL(node_t); + + nodevec = network_dfs(network); + nsize = array_n(nodevec); + + for (i = 0; i < nsize; i++) { + node = array_fetch(node_t *, nodevec, i); + node_fun = node_function(node); + + /* set Primary Input arrival time */ + /*--------------------------------*/ + if (node_fun == NODE_PI) { + cost_node = act_set_pi_arrival_time_node(node, cost_table); + if (ACT_DEBUG) (void) printf("---- arrival time of node %s = %f\n", node_long_name(node), cost_node->arrival_time); + continue; + } + + /* Primary Output's arrival time is same as its fanin */ + /*----------------------------------------------------*/ + if (node_fun == NODE_PO) { + fanin = node_get_fanin(node, 0); + fanin_delay = act_get_arrival_time(fanin, cost_table); + cost_node = act_set_arrival_time(node, cost_table, fanin_delay); + if (ACT_DEBUG) (void) printf("---- arrival time of node %s = %f\n", node_long_name(node), cost_node->arrival_time); + if (cost_node->arrival_time > max_output_arrival_time) { + max_output_arrival_time = cost_node->arrival_time; + slowest_po = node; + } + continue; + } + + max_fanin_delay = (double) (0.0); + + foreach_fanin(node, j, fanin) { + fanin_delay = act_get_arrival_time(fanin, cost_table); + if (fanin_delay < max_fanin_delay) continue; + else max_fanin_delay = fanin_delay; + } + num_fanout = node_num_fanout(node); + if (num_fanout == 0) fail("Error: act_delay_trace(): node with 0 fanout found"); + delaynum = act_delay_for_fanout(delay_values, num_fanout); + total_delay = delaynum + max_fanin_delay; + cost_node = act_set_arrival_time(node, cost_table, total_delay); + if (ACT_DEBUG) (void) printf("---- arrival time of node %s = %f\n", node_long_name(node), cost_node->arrival_time); + + } + if ((ACT_DEBUG) || (ACT_STATISTICS)) + (void) printf("---- max arrival time is for node %s = %f\n", node_long_name(slowest_po), max_output_arrival_time); + + array_free(nodevec); +} + +/*-------------------------------------------------------------------------------- + Given a mapped network, in which each node can be mapped onto + one basic block of MB architecture, prints out the value of the + required time of each of the outputs. Basically a delay trace. + Stores the required times in a table. Assumes that the required times of + the primary outputs have been set by delay_set command. Sets the unset + required time of a po to the highest required time. If none of the required + times were set, the required times of all outputs are set to max arrival time + of some output. +----------------------------------------------------------------------------------*/ +void +act_delay_trace_backward(network, cost_table, delay_values) +network_t *network; +st_table *cost_table; +array_t *delay_values; +{ + double delaynum, max_arrival_time; + double max_output_required_time, required_time, min_node_required_time, fanout_required_time; + double node_required_time; + int i, nsize, num_fanout; + node_t *node, *fanout, *po; + array_t *nodevec; + node_function_t node_fun; + COST_STRUCT *cost_node; + st_table *po_table; /* to keep track of all the po's that have their required times set. */ + int flag_all_set, flag_some_not_set; /* indicate if the required times of po's were set in the first pass */ + lsGen gen; + + po_table = st_init_table(strcmp, st_strhash); + + /* set the required times of all the primary_outputs first */ + /*---------------------------------------------------------*/ + flag_all_set = 0; + flag_some_not_set = 0; + max_output_required_time = (double) (-1.0); + + foreach_primary_output(network, gen, po) { + required_time = delay_get_parameter(po, DELAY_REQUIRED_RISE); + if (required_time == DELAY_NOT_SET) flag_some_not_set = 1; + else { + flag_all_set = 1; + if (required_time > max_output_required_time) { + max_output_required_time = required_time; + } + (void) act_set_required_time(po, cost_table, required_time); + } + + } + /* if flag_all_set is 0, this means none of the required times were specified */ + /* find the largest arrival time at some output and set all the + required times to it. */ + /*----------------------------------------------------------------------------*/ + if (flag_all_set == 0) { + max_arrival_time = act_get_max_arrival_time(network, cost_table); + foreach_primary_output(network, gen, po) { + (void) act_set_required_time(po, cost_table, max_arrival_time); + assert(!st_insert(po_table, (char *) node_long_name(po), (char *) node_long_name(po))); + } + } + else if (flag_some_not_set == 0); /* all po's required times have been set */ + else { + /* set required times of not set outputs to the max_output_required_time */ + /*------------------------------------------------------------------------*/ + foreach_primary_output(network, gen, po) { + if (!st_is_member(po_table, (char *) node_long_name(po))) + (void) act_set_required_time(po, cost_table, max_output_required_time); + } + } + st_free_table(po_table); + + nodevec = network_dfs_from_input(network); + nsize = array_n(nodevec); + + for (i = 0; i < nsize; i++) { + node = array_fetch(node_t *, nodevec, i); + node_fun = node_function(node); + if (node_fun == NODE_PO) continue; + + min_node_required_time = (double) (MAXINT); + + foreach_fanout(node, gen, fanout) { + fanout_required_time = act_get_required_time(fanout, cost_table); + + /* if the fanout is a PO, no delay through it basically. */ + /*--------------------------------------------------------*/ + if (fanout->type == PRIMARY_OUTPUT) { + node_required_time = fanout_required_time; + } + else { + num_fanout = node_num_fanout(fanout); + if (num_fanout == 0) fail("Error: act_delay_trace(): node with 0 fanout found"); + delaynum = act_delay_for_fanout(delay_values, num_fanout); + node_required_time = fanout_required_time - delaynum; + } + if (node_required_time >= min_node_required_time) continue; + else min_node_required_time = node_required_time; + } + cost_node = act_set_required_time(node, cost_table, min_node_required_time); + if (ACT_DEBUG) (void) printf("---- arrival time of node %s = %f\n", node_long_name(node), cost_node->required_time); + + } + array_free(nodevec); +} + +double +act_get_arrival_time(node, cost_table) +node_t *node; +st_table *cost_table; +{ + COST_STRUCT *cost_node; + + assert(st_lookup(cost_table, node_long_name(node), (char **) &cost_node)); + return cost_node->arrival_time; +} + +double +act_get_required_time(node, cost_table) +node_t *node; +st_table *cost_table; +{ + COST_STRUCT *cost_node; + + assert(st_lookup(cost_table, node_long_name(node), (char **) &cost_node)); + return cost_node->required_time; +} + +/***************************************************************************** + Sets (updates) the arrival_time of the node in the cost_table to arrival. + Allocates storage for a node if it is not found in the cost_table. +******************************************************************************/ +COST_STRUCT * +act_set_arrival_time(node, cost_table, arrival) +node_t *node; +st_table *cost_table; +double arrival; +{ + COST_STRUCT *cost_node; + char *name; + + if (st_lookup(cost_table, node_long_name(node), (char **) &cost_node)) { + cost_node->arrival_time = arrival; + if (ACT_DEBUG) (void) printf("act_set_arrival_time():node %s found in the cost_table...\n", node_long_name(node)); + if (ACT_DEBUG) (void) printf("setting the arrival time of %s to %f..\n", node_long_name(node), arrival); + return cost_node; + } + /* cost_node not found. Allocate it and set the fields */ + /*-----------------------------------------------------*/ + name = ALLOC(char, strlen (node_long_name(node)) + 1); + (void) strcpy(name, node_long_name(node)); + cost_node = ALLOC(COST_STRUCT, 1); + cost_node->node = node; + cost_node->arrival_time = arrival; + cost_node->required_time = (double) (-1.0); + cost_node->cost_and_arrival_time = (double) (-1.0); + cost_node->cost = 0; + cost_node->act = NIL (ACT_VERTEX); + assert(!st_insert(cost_table, name, (char *) cost_node)); + if (ACT_DEBUG) (void) printf("act_set_arrival_time():node %s not found in the cost_table...\n", node_long_name(node)); + if (ACT_DEBUG) (void) printf("setting the arrival time of %s to %f..\n", node_long_name(node), arrival); + return cost_node; + +} + +/***************************************************************************** + Sets (updates) the required_time of the node in the cost_table to required. + Allocates storage for a node if it is not found in the cost_table. +******************************************************************************/ +COST_STRUCT * +act_set_required_time(node, cost_table, required) +node_t *node; +st_table *cost_table; +double required; +{ + COST_STRUCT *cost_node; + char *name; + + if (st_lookup(cost_table, node_long_name(node), (char **) &cost_node)) { + cost_node->required_time = required; + if (ACT_DEBUG) (void) printf("act_set_required_time():node %s found in the cost_table...\n", node_long_name(node)); + if (ACT_DEBUG) (void) printf("setting the required time of %s to %f..\n", node_long_name(node), required); + return cost_node; + } + /* cost_node not found. Allocate it and set the fields */ + /*-----------------------------------------------------*/ + name = ALLOC(char, strlen (node_long_name(node)) + 1); + (void) strcpy(name, node_long_name(node)); + cost_node = ALLOC(COST_STRUCT, 1); + cost_node->node = node; + cost_node->arrival_time = (double) (-1.0); + cost_node->required_time = required; + cost_node->cost_and_arrival_time = (double) (-1.0); + cost_node->cost = 0; + cost_node->act = NIL (ACT_VERTEX); + assert(!st_insert(cost_table, name, (char *) cost_node)); + if (ACT_DEBUG) (void) printf("act_set_required_time():node %s not found in the cost_table...\n", node_long_name(node)); + if (ACT_DEBUG) (void) printf("setting the required time of %s to %f..\n", node_long_name(node), required); + return cost_node; + +} + +/************************************************************* + Finds the fanout of the vertex in the bdd. Calculates + and returns the propagation delay, taking into account + the fanouts. +*************************************************************/ + +double +act_get_bddfanout_delay(vertex, delay_values, cost_table) +ACT_VERTEX_PTR vertex; +array_t *delay_values; +st_table *cost_table; +{ + int num_fanout; + double delaynum; + + num_fanout = vertex->multiple_fo + 1; + delaynum = act_delay_for_fanout(delay_values, num_fanout); + return delaynum; +} + +/*------------------------------------------------------------ + Finds the fanout of the node. Calculates + the propagation delay delaynum1, taking into account + the actual_numfo's, calculates delaynum2, delay + for assumed_numfo's and returns the difference +--------------------------------------------------------------*/ +double +act_get_node_delay_correction(node, delay_values, assumed_numfo, actual_numfo) +node_t *node; +array_t *delay_values; +int assumed_numfo, actual_numfo; +{ + double delaynum1, delaynum2; + int diff; + + if ((actual_numfo == 0) || (assumed_numfo == 0)) return ((double) 0.0); + + diff = actual_numfo - assumed_numfo; + if (diff == 0) return ((double) 0.0); + + delaynum1 = act_delay_for_fanout(delay_values, actual_numfo); + delaynum2 = act_delay_for_fanout(delay_values, assumed_numfo); + return (delaynum1 - delaynum2); +} + +/*----------------------------------------------------------------- + Gets the delay values set by the user for the primary inputs + of the network, and stores them in the cost_table. +------------------------------------------------------------------*/ +void +act_set_pi_arrival_time_network(network, cost_table) +network_t *network; +st_table *cost_table; +{ + node_t *pi; + lsGen gen; + + + foreach_primary_input(network, gen, pi) { + (void) act_set_pi_arrival_time_node(pi, cost_table); + } +} + +/*----------------------------------------------------------------- + Gets the delay values set by the user for the primary input pi + and stores them in the cost_table. If does not find the entry in + the cost table corresponding to pi, creates one. Returns the + entry cost_node. +------------------------------------------------------------------*/ +COST_STRUCT * +act_set_pi_arrival_time_node(pi, cost_table) +node_t *pi; +st_table *cost_table; +{ + double arrival_time; + + arrival_time = delay_get_parameter(pi, DELAY_ARRIVAL_RISE); + if (arrival_time == DELAY_NOT_SET) arrival_time = (double) 0.0; + return act_set_arrival_time(pi, cost_table, arrival_time); + +} + +void +act_invalidate_cost_and_arrival_time(cost_node) +COST_STRUCT *cost_node; +{ + cost_node->cost_and_arrival_time = (double) (-1.0); +} + +double +act_cost_delay(cost_node, mode) +COST_STRUCT *cost_node; +float mode; +{ + if (cost_node->cost_and_arrival_time < 0.0) return + (double) ( ((double)(1.00 - mode)) * (double) cost_node->cost + ((double) mode) * cost_node->arrival_time + ); + else return cost_node->cost_and_arrival_time; +} + +/*---------------------------------------------------------------------- + Returns the delay-value for a basic block if the number of fanouts + for a signal is num_fanout. The delay_values store the delay-values + upto a certain fanout number. If num_fanout is larger than that, + a simple linear extrapolation is done. +------------------------------------------------------------------------*/ +double +act_delay_for_fanout(delay_values, num_fanout) +array_t *delay_values; +int num_fanout; +{ + int delay_size, delay_size1; + double delaynum, delaynum1, delaynum2; + + delay_size = array_n(delay_values); + delay_size1 = delay_size - 1; + + if (num_fanout > (delay_size - 1)) { + /* linear extrapolation from last two values in delay_values */ + /*-----------------------------------------------------------*/ + delaynum1 = array_fetch(double, delay_values, delay_size1); + delaynum2 = array_fetch(double, delay_values, delay_size - 2); + delaynum = delaynum1 + (delaynum1 - delaynum2) * (double) (num_fanout - delay_size1); + } else { + delaynum = array_fetch(double, delay_values, num_fanout); + } + return delaynum; +} + +void +act_set_slack_network(network, cost_table) +network_t *network; +st_table *cost_table; +{ + lsGen gen; + node_t *node; + + foreach_node(network, gen, node) { + (void) act_set_slack_node(node, cost_table); + } +} + +/*------------------------------------------------------------------------- + Assuming that the cost_node for the node is there in the cost_table, + computes the slack and stores it in the cost_node. +--------------------------------------------------------------------------*/ +COST_STRUCT * +act_set_slack_node(node, cost_table) +node_t *node; +st_table *cost_table; +{ + COST_STRUCT *cost_node; + + assert(st_lookup(cost_table, node_long_name(node), (char **) &cost_node)); + cost_node->slack = cost_node->required_time - cost_node->arrival_time; + return cost_node; +} + +/*------------------------------------------------------------------------- + Assuming that the cost_node for the node is there in the cost_table, + returns the slack. +--------------------------------------------------------------------------*/ +double +act_get_slack_node(node, cost_table) +node_t *node; +st_table *cost_table; +{ + COST_STRUCT *cost_node; + + assert(st_lookup(cost_table, node_long_name(node), (char **) &cost_node)); + return cost_node->slack; +} + + +/*------------------------------------------------------------------------ + Make cost_node's is_critical field YES if the node is critical. + A node is defined critical if its slack is less than or equal to + threshold_slack. Assumes that the slack of the node has been set + already in the cost_node's slack field. +--------------------------------------------------------------------------*/ +void +act_find_critical_nodes(network, cost_table, threshold_slack) +network_t *network; +st_table *cost_table; +double threshold_slack; +{ + node_t *node; + lsGen gen; + COST_STRUCT *cost_node; + int num_critical_nodes; + + num_critical_nodes = 0; + foreach_node(network, gen, node) { + assert(st_lookup(cost_table, node_long_name(node), (char **) &cost_node)); + if (cost_node->slack <= threshold_slack) { + cost_node->is_critical = YES; + num_critical_nodes++; + } + else cost_node->is_critical = NO; + } + if (ACT_DEBUG) (void) printf(" threshold slack = %f, Number of critical nodes = %d\n", + threshold_slack, num_critical_nodes); +} + +array_t * +act_compute_area_delay_weight_network_for_collapse(network, cost_table, mode) +network_t *network; +st_table *cost_table; +float mode; +{ + lsGen gen; + node_t *node; + COST_STRUCT *cost_node; + array_t *c_pair_array, *c_node_pair_array; + + c_pair_array = array_alloc(COLLAPSIBLE_PAIR *, 0); + foreach_node(network, gen, node) { + if (node->type != INTERNAL) continue; /* important probably */ + assert(st_lookup(cost_table, node_long_name(node), (char **) &cost_node)); + cost_node->area_weight = act_compute_area_weight_node_for_collapse(node, cost_node); + c_node_pair_array = act_compute_area_delay_weight_node_for_collapse(node, cost_node, cost_table, mode); + if ((c_node_pair_array == NIL (array_t)) || (array_n(c_node_pair_array) == 0)); + else array_append(c_pair_array, c_node_pair_array); + array_free(c_node_pair_array); /* should I free c_node_pair_array */ + } + return c_pair_array; +} + +/*---------------------------------------------------------------------------- + Given a node, for each of its fanout, it finds out the area_delay weight of + the pair. Returns an array of the collapsible pairs. +-----------------------------------------------------------------------------*/ +array_t * +act_compute_area_delay_weight_node_for_collapse(node, cost_node, cost_table, mode) +node_t *node; +COST_STRUCT *cost_node; +st_table *cost_table; +float mode; +{ + node_t *fanout; + lsGen gen; + COST_STRUCT *cost_fanout; + array_t *c_pair_array; + double small_arrival_at_input_of_fanout, largest_arrival_at_input_of_node, diff; + COLLAPSIBLE_PAIR *c_pair; + + if (cost_node->is_critical == NO) return NIL(array_t); + if (node->type != INTERNAL) return NIL(array_t); + + c_pair_array = array_alloc(COLLAPSIBLE_PAIR *, 0); + foreach_fanout(node, gen, fanout) { + if (fanout->type == PRIMARY_OUTPUT) continue; + assert(st_lookup(cost_table, node_long_name(fanout), (char **) &cost_fanout)); + if (cost_fanout->is_critical == NO) continue; + /* what happens to the next routine if fanout has just 1 input? */ + /*--------------------------------------------------------------*/ + small_arrival_at_input_of_fanout = act_smallest_fanin_arrival_time_at_fanout_except_node(fanout, node, cost_table); + if (small_arrival_at_input_of_fanout >= (double) MAXINT) continue; /* is this OK */ + largest_arrival_at_input_of_node = act_largest_fanin_arrival_time_at_node(node, cost_table); + diff = largest_arrival_at_input_of_node - small_arrival_at_input_of_fanout; + if (diff <= 0.0 ) continue; /* check */ + + /* assign a collapsible_pair to (node, fanout) pair, assign storage for their names */ + /*----------------------------------------------------------------------------------*/ + c_pair = act_allocate_collapsible_pair(); + c_pair->nodename = util_strsav(node_long_name(node)); + c_pair->fanoutname = util_strsav(node_long_name(fanout)); + c_pair->weight = ((double)( cost_node->area_weight * (1.00 - mode))) + diff * (mode); /* is this OK ? */ + array_insert_last(COLLAPSIBLE_PAIR *, c_pair_array, c_pair); + + } + return c_pair_array; +} + +/*----------------------------------------------------------------- + Given a node and its cost_node, returns the area_cost if the node + is to be collapsed into the fanout. +-----------------------------------------------------------------*/ +double +act_compute_area_weight_node_for_collapse(node, cost_node) +node_t *node; +COST_STRUCT *cost_node; +{ + int num_fanout; + + if (node->type != INTERNAL) return ((double) (-1.0)); + num_fanout = node_num_fanout(node); + assert(num_fanout); + if (num_fanout == 1) return (double) 0.0; + return ((double) (cost_node->cost)); +} + +/*----------------------------------------------------------------- + Returns a new COLLAPSIBLE_PAIR, with weight 0.0. +------------------------------------------------------------------*/ +COLLAPSIBLE_PAIR * +act_allocate_collapsible_pair() +{ + COLLAPSIBLE_PAIR *c_pair; + + c_pair = ALLOC(COLLAPSIBLE_PAIR, 1); + c_pair->weight = (double) 0.0; + return c_pair; +} + +double +act_smallest_fanin_arrival_time_at_fanout_except_node(fanout, node, cost_table) +node_t *fanout, *node; +st_table *cost_table; +{ + double act_min; + node_t *fanin; + int i; + COST_STRUCT *cost_fanin; + + act_min = (double) MAXINT; + foreach_fanin(fanout, i, fanin) { + if (fanin == node) continue; + assert(st_lookup(cost_table, node_long_name(fanin), (char **) &cost_fanin)); + if (act_min > cost_fanin->arrival_time) act_min = cost_fanin->arrival_time; + } + return act_min; +} + +double +act_largest_fanin_arrival_time_at_node(node, cost_table) +node_t *node; +st_table *cost_table; +{ + node_t *fanin; + double act_max; + int i; + COST_STRUCT *cost_fanin; + + act_max = (double) (-1.0); + foreach_fanin(node, i, fanin) { + assert(st_lookup(cost_table, node_long_name(fanin), (char **) &cost_fanin)); + if (act_max < cost_fanin->arrival_time) act_max = cost_fanin->arrival_time; + } + return act_max; +} + +/*------------------------------------------------------------------- + Small weight comes towards beginning of the array. +--------------------------------------------------------------------*/ +int c_pair_compare_function(cp1, cp2) +COLLAPSIBLE_PAIR **cp1, **cp2; +{ + + double wt1, wt2; + + wt1 = (*cp1)->weight; + wt2 = (*cp2)->weight; + + if (wt1 > wt2) return 1; + if (wt2 > wt1) return (-1); + return 0; +} + +/*------------------------------------------------------------ + Looks at the primary outputs and find out the maximum + arrival times of these. +------------------------------------------------------------*/ +double act_get_max_arrival_time(network, cost_table) +network_t *network; +st_table *cost_table; +{ + lsGen gen; + node_t *po; + double max_arrival_time, arrival_time; + + max_arrival_time = (double) (-1.0); + foreach_primary_output(network, gen, po) { + arrival_time = act_get_arrival_time(po, cost_table); + if (max_arrival_time < arrival_time) max_arrival_time = arrival_time; + } + return max_arrival_time; +} + +/*----------------------------------------------------------------------- + Returns a hash table, which for every node has its topological index + stored in it. Later free the entries of the hash table. +------------------------------------------------------------------------*/ +st_table * +act_assign_topol_indices_network(network) +network_t *network; +{ + array_t *nodevec; + int size, i; + node_t *node; + st_table *topol_table; + TOPOL_STRUCT *topol_node; + + topol_table = st_init_table(strcmp, st_strhash); + + nodevec = network_dfs(network); + size = array_n(nodevec); + for (i = 0; i < size; i++) { + node = array_fetch(node_t *, nodevec, i); + topol_node = ALLOC (TOPOL_STRUCT, 1); + /* nodename is stored instead of the node because node may have + been replaced (physically) by another node. Hence name + provides a reference, as the new node will have the same name */ + /*---------------------------------------------------------------*/ + topol_node->nodename = util_strsav(node_long_name(node)); + topol_node->index = i; + assert(!st_insert(topol_table, node_long_name(node), (char *) topol_node)); + } + array_free(nodevec); + return topol_table; +} + + +/*---------------------------------------------------------------------- + Given a node, returns in the topol_fanin_array, all the fanins of the + node sorted in a topological order (from inputs). +-----------------------------------------------------------------------*/ +array_t * +act_topol_sort_fanins(node, topol_table, network) +node_t *node; +st_table *topol_table; +network_t *network; +{ + int i, size; + node_t *fanin; + array_t *topol_fanin_array; + array_t *temp_array; + TOPOL_STRUCT *topol_fanin; + int act_topol_compare_function(); + + topol_fanin_array = array_alloc(node_t *, 0); + temp_array = array_alloc(TOPOL_STRUCT *, 0); + + /* get the topol_fanin for all the fanins and sort them */ + /*------------------------------------------------------*/ + foreach_fanin(node, i, fanin) { + assert(st_lookup(topol_table, node_long_name(fanin), (char **) &topol_fanin)); + array_insert_last(TOPOL_STRUCT *, temp_array, topol_fanin); + } + array_sort(temp_array, act_topol_compare_function); + + /* put the sorted fanins in the topol_fanin_array */ + /*------------------------------------------------*/ + size = array_n(temp_array); + for (i = 0; i < size; i++) { + topol_fanin = array_fetch(TOPOL_STRUCT *, temp_array, i); + fanin = network_find_node(network, topol_fanin->nodename); + array_insert_last(node_t *, topol_fanin_array, fanin); + } + array_free(temp_array); + return topol_fanin_array; +} + +/*------------------------------------------------------------------- + Small index comes towards beginning of the array. +--------------------------------------------------------------------*/ +int +act_topol_compare_function(ts1, ts2) +TOPOL_STRUCT **ts1, **ts2; +{ + + int index1, index2; + + index1 = (*ts1)->index; + index2 = (*ts2)->index; + + if (index1 > index2) return 1; + if (index2 > index1) return (-1); + return 0; +} + +void +act_delete_topol_table_entries(topol_table) +st_table *topol_table; +{ + st_foreach(topol_table, act_delete_topol_table_entry, NIL(char)); +} + +enum st_retval +act_delete_topol_table_entry(key, value, arg) +char *key, *value, *arg; +{ + free_topol_struct((TOPOL_STRUCT *) value); + return ST_DELETE; +} + +free_topol_struct(topol_node) +TOPOL_STRUCT *topol_node; +{ + FREE(topol_node->nodename); + FREE(topol_node); +} + diff --git a/sis/pld/act_init.c b/sis/pld/act_init.c new file mode 100644 index 0000000..c3658ae --- /dev/null +++ b/sis/pld/act_init.c @@ -0,0 +1,137 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_init.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/* the init and end routines for the ACT package +*/ + +/*extern void p_transitiveFree();*/ + +end_p_act() +{ + int i; + array_t *list; + for(i=0; i<array_n(global_lists); i++){ + list = array_fetch(array_t *, global_lists, i); + array_free(list); + } + array_free(global_lists); +} + +/* install all the node daemons +*/ + +void +p_actAlloc(node) +node_t *node; +{ + node->PLD_SLOT = (char *) ALLOC(act_type_t, 1); + ACT_SET(node)->LOCAL_ACT = NIL (ACT_ENTRY); + ACT_SET(node)->GLOBAL_ACT = NIL (ACT_ENTRY); +} + +void +local_actFree(node) +node_t *node; +{ + + if (ACT_SET(node) == NIL(act_type_t)) return; + if (ACT_SET(node)->LOCAL_ACT != NIL (ACT_ENTRY)) { + p_actDestroy(&ACT_SET(node)->LOCAL_ACT, 1); + ACT_SET(node)->LOCAL_ACT = NIL (ACT_ENTRY); + } + if (ACT_SET(node)->GLOBAL_ACT != NIL (ACT_ENTRY)) { + p_actDestroy(&ACT_SET(node)->GLOBAL_ACT, 0); + ACT_SET(node)->GLOBAL_ACT = NIL (ACT_ENTRY); + } +} + +void +p_actFree(node) +node_t *node; +{ + act_type_t *a; + + a = (act_type_t *) ACT_GET(node); + FREE(a); +} + +/* ARGSUSED */ +void +p_actDup(old, new) +node_t * old, new; +{ + /* ACTs are NOT copied on duplication */ +} + +p_transitiveFree(node) +node_t *node; +{ + lsGen gen; + node_t *fanout; + + if(ACT_SET(node)->GLOBAL_ACT != NIL (ACT_ENTRY)){ + p_actDestroy(&ACT_SET(node)->GLOBAL_ACT, 0); + ACT_SET(node)->GLOBAL_ACT = NIL (ACT_ENTRY); + if(node_network(node) != NIL(network_t)){ + foreach_fanout(node, gen, fanout){ + p_transitiveFree(fanout); + } + } + } +} + +/* instead of node */ +/*ARGSUSED */ +my_free_act(vertex) +ACT_VERTEX_PTR vertex; +{ + st_table *table; + char *arg; + enum st_retval free_table_entry_improper(); + + if (vertex == NIL (ACT_VERTEX)) return; + table = st_init_table(st_ptrcmp, st_ptrhash); + delete_act(vertex, table); + st_foreach(table, free_table_entry_improper, arg); + st_free_table(table); +} + +/* ARGSUSED */ +enum st_retval +free_table_entry_improper(key, value, arg) + char *key, *value, *arg; +{ + ACT_VERTEX_PTR vertex; + vertex = (ACT_VERTEX_PTR) key; + FREE (vertex); + return ST_DELETE; +} + + +delete_act(vertex, table) +act_t *vertex; +st_table *table; +{ + char *dummy; + + + if (!st_lookup(table, (char *) vertex, &dummy)) { + if (vertex->value == 4) { + delete_act(vertex->low, table); + delete_act(vertex->high, table); + } + (void) st_insert(table, (char *) vertex, NIL(char)); + } +} + + + diff --git a/sis/pld/act_ite.c b/sis/pld/act_ite.c new file mode 100644 index 0000000..a35f2fb --- /dev/null +++ b/sis/pld/act_ite.c @@ -0,0 +1,421 @@ +#include "sis.h" +#include "pld_int.h" /* uncommented Feb 9, 1992 */ +#include "ite_int.h" + +static void my_ite_OR(); +/* +#ifndef +#define ON 1 +#define OFF 0 +#endif +*/ +/* Initialize the ACT*/ +/* +act_t * +my_init_act() +{ + act_t *vertex; + + vertex = ALLOC(act_t ,1); + vertex->high = NULL; + vertex->low = NULL; + vertex->index = 0; + vertex->value = 0; + vertex->id = 0; + vertex->mark = 0; + vertex->index_size = 0; + vertex->node = NULL; + vertex->name = NULL; + vertex->multiple_fo = 0; + vertex->cost = 0; + vertex->mapped = 0; + vertex->parent = NULL; + return vertex; +} + +*/ + +/* Construct ite for a cube ie a ite which is the and of its variables*/ +ite_vertex * +ite_for_cube_F(F, node) +sm_matrix *F; +node_t *node; +{ + ite_vertex *vertex, *my_ite_and(); + sm_row *row; + sm_element *p; + char *name; + node_t *cube_node, *fanin; + array_t *order_list, *single_cube_order(); + st_table *table, *act_make_name_to_element_table(); + int i; + + /* Avoid stupidity */ + /*-----------------*/ + if(F->nrows > 1){ + (void)fprintf(misout, "error in act_f - more than one cube\n"); + exit(1); + } + row = F->first_row; + cube_node = act_make_node_from_row(row, F, node->network); + table = act_make_name_to_element_table(row, F); + order_list = single_cube_order(cube_node); + vertex = NIL (ite_vertex); + /* reverse order, because of the way, my_ite_and works */ + /*-----------------------------------------------------*/ + for (i = array_n(order_list) - 1; i >= 0; i--) { + fanin = array_fetch(node_t *, order_list, i); + assert(st_lookup(table, node_long_name(fanin), (char **) &p)); + name = sm_get_col(F, p->col_num)->user_word; + assert (strcmp(name, node_long_name(fanin)) == 0); + assert(name == node_long_name(fanin)); + vertex = my_ite_and(p, vertex, node_long_name(fanin), fanin); + } + array_free(order_list); + vertex->index_size = node_num_fanin(cube_node); + node_free(cube_node); + st_free_table(table); + return vertex; +} + +/* And variables in a cube*/ +ite_vertex * +my_ite_and(p, vertex, name, fanin) +sm_element *p; +ite_vertex *vertex; +char *name; +node_t *fanin; +{ + ite_vertex *vertex_IF, *p_vertex, *ite_0, *ite_1; + + assert(st_lookup(ite_end_table, (char *)1, (char **) &ite_1)); + assert(st_lookup(ite_end_table, (char *)0, (char **) &ite_0)); + vertex_IF = ite_literal(p->col_num, name, fanin); + + if(vertex == NIL (ite_vertex)) { + switch((int )p->user_word) { + case 0: + p_vertex = my_shannon_ite(vertex_IF, ite_0, ite_1); + break; + case 1: + p_vertex = my_shannon_ite(vertex_IF, ite_1, ite_0); + break; + case 2: + (void)fprintf(misout, "error in my_ite_and,\n"); + exit(1); + } + } else { + switch((int )p->user_word) { + case 0: + p_vertex = my_shannon_ite(vertex_IF, ite_0, vertex); + break; + case 1: + p_vertex = my_shannon_ite(vertex_IF, vertex, ite_0); + break; + case 2: + (void)fprintf(misout, "error in my_and act, p->u_w == 2\n"); + exit(1); + + } + } + return p_vertex; +} + +/* from a set of sub-covers in array, and the corresponding ite_s in array_b, + and the minimum column cover variables in cover, generates an ite for the + original function. */ + +ite_vertex * +my_or_ite_F(array_b, cover, array, network) +array_t *array_b; +array_t *array; +sm_row *cover; +network_t *network; +{ + static int compare(); + int i; + ite_vertex *vertex; + sm_element *p; + ite_vertex *ite; + char *name; + node_t *fanin; + + /* Append the appropriate variables at top of ite's*/ + i = 0; + sm_foreach_row_element(cover, p) { + name = sm_get_col(array_fetch(sm_matrix *, array, i), p->col_num) + ->user_word; + vertex = array_fetch(ite_vertex *, array_b, i); + fanin = network_find_node(network, name); + ite = my_ite_and(p, vertex, name, fanin); + array_insert(ite_vertex *, array_b, i, ite); + i++; + } + /* Sort the cubes so that the smaller ite s are at the top so that less fanout + * problem also we could use the heuristic merging done earlier*/ + + array_sort(array_b, compare); + ite = ite_OR_itevec(array_b); + return ite; +} + +/* Recursively Join ACT's constructed*/ +static void +my_ite_OR(up_vertex, down_vertex) +ite_vertex *up_vertex, *down_vertex; +{ + + st_table *table; + st_generator *stgen; + char *key; + ite_vertex *vertex; + + table = ite_my_traverse_ite(up_vertex); + + /* change all the pointers to 0 terminal vertex to down vertex */ + /*-------------------------------------------------------------*/ + st_foreach_item(table, stgen, &key, (char **) &vertex) { + if (vertex->value != 3) continue; + if (vertex->IF->value == 0) vertex->IF = down_vertex; + if (vertex->THEN->value == 0) vertex->THEN = down_vertex; + if (vertex->ELSE->value == 0) vertex->ELSE = down_vertex; + } + st_free_table(table); +} + +/*------------------------------------------------------------------------------ + Given the column number b_col and the name, makes a vertex for the variable. +-------------------------------------------------------------------------------*/ +ite_vertex * +ite_literal(b_col, name, fanin) + int b_col; + char *name; + node_t *fanin; +{ + ite_vertex *ite; + + ite = ite_alloc(); + ite->value = 2; + ite->phase = 1; + ite->index = b_col; + ite->index_size = 1; + ite->name = name; + ite->fanin = fanin; + return ite; +} + +/* ite construction where ite_IF, ite_THEN, ite_ELSE are known */ +ite_vertex * +my_shannon_ite(ite_IF, ite_THEN, ite_ELSE) +ite_vertex *ite_IF, *ite_THEN, *ite_ELSE; +{ + ite_vertex *ite; + + ite = ite_alloc(); + ite->value = 3; + ite->index_size = ite_ELSE->index_size + ite_THEN->index_size + ite_IF->index_size; + ite->IF = ite_IF; + ite->ELSE = ite_ELSE; + ite->THEN = ite_THEN; + return ite; +} + +static int +compare(obj1, obj2) +char *obj1, *obj2; +{ + ite_vertex *ite1 = *(ite_vertex **)obj1; + ite_vertex *ite2 = *(ite_vertex **)obj2; + int value; + + if((ite1->index_size == 0 ) || (ite2->index_size == 0)) { + (void)fprintf(misout, "Hey u DOLT ite of size \n"); + } + if(ite1->index_size == ite2->index_size) value = 0; + if(ite1->index_size > ite2->index_size) value = 1; + if(ite1->index_size < ite2->index_size) value = -1; + return value; +} + +/*------------------------------------------------------------ + From the row of F, makes a node. This node corresponds to + the cube corresponding to the row. +-------------------------------------------------------------*/ +node_t * +act_make_node_from_row(row, F, network) + sm_row *row; + sm_matrix *F; + network_t *network; +{ + node_t *n, *n1, *f, *fanin; + int phase; + sm_col *col; + sm_element *p; + char *name; + + n = node_constant(1); + sm_foreach_row_element(row, p) { + phase = (int) (p->user_word); + assert(phase >= 0 && phase <= 2); + if (phase != 2) { + col = sm_get_col(F, p->col_num); + name = col->user_word; + fanin = network_find_node(network, name); + f = node_literal(fanin, phase); + n1 = node_and(n, f); + node_free(n); + node_free(f); + n = n1; + } + } + return n; +} + +/*------------------------------------------------------- + From the row, gets each element p, finds its column + and stores p in the table with key = name of the column. +--------------------------------------------------------*/ +st_table * +act_make_name_to_element_table(row, F) + sm_row *row; + sm_matrix *F; +{ + st_table *table; + char *name; + sm_element *p; + sm_col *col; + + table = st_init_table(strcmp, st_strhash); + sm_foreach_row_element(row, p) { + col = sm_get_col(F, p->col_num); + name = col->user_word; + assert(!st_insert(table, name, (char *) p)); + } + return table; +} + +ite_vertex * +ite_OR_itevec(itevec) + array_t *itevec; +{ + int i; + ite_vertex *ite, *up_vertex, *down_vertex; + + up_vertex = array_fetch(ite_vertex *, itevec, 0); + ite = up_vertex; + for(i = 1; i < array_n(itevec); i++) { + down_vertex = array_fetch(ite_vertex *, itevec, i); + my_ite_OR(up_vertex, down_vertex); + up_vertex = down_vertex; + } + return ite; +} + +ite_vertex * +ite_check_for_single_literal_cubes(F, network) + sm_matrix *F; + network_t *network; +{ + int flag, i, phase, num; + node_t *n, *n1, *f, *fanin; + st_table *table; + sm_row *row; + sm_col *col; + sm_element *p; + char *name; + array_t *order_list, *OR_literal_order(); + ite_vertex *ite_0, *ite_1, *ite, *ite_IF; + array_t *ite_vec; + + /* flag is 1 whenever it is detected that some row has more than 1 + non-2 element (that cube is not single literal) */ + + flag = 0; + n = node_constant(0); + table = st_init_table(strcmp, st_strhash); + sm_foreach_row(F, row) { + if (flag) break; + num = 0; + sm_foreach_row_element(row, p) { + phase = (int) p->user_word; + if (phase == 2) continue; + num++; + if (num > 1) { + flag = 1; + break; + } + col = sm_get_col(F, p->col_num); + name = col->user_word; + fanin = network_find_node(network, name); + f = node_literal(fanin, phase); + n1 = node_or(n, f); + node_free(n); + node_free(f); + n = n1; + if (st_insert(table, name, (char *) p)) { + /* a variable occurred twice */ + flag = 1; + break; + } + } + } + if (flag) { + node_free(n); + st_free_table(table); + return NIL (ite_vertex); + } + assert(st_lookup(ite_end_table, (char *)0, (char **) &ite_0)); + assert(st_lookup(ite_end_table, (char *)1, (char **) &ite_1)); + order_list = OR_literal_order(n); + + /* form the ite's for the single literal cubes and store them in ite_vec */ + /*-----------------------------------------------------------------------*/ + ite_vec = array_alloc(ite_vertex *, 0); + for (i = 0; i < array_n(order_list); i++) { + fanin = array_fetch(node_t *, order_list, i); + assert(st_lookup(table, node_long_name(fanin), (char **) &p)); + name = sm_get_col(F, p->col_num)->user_word; + assert (strcmp(name, node_long_name(fanin)) == 0); + assert(name == node_long_name(fanin)); + phase = (int) p->user_word; + assert(phase != 2); + ite_IF = ite_literal(p->col_num, name, fanin); + if (phase) { + ite = my_shannon_ite(ite_IF, ite_1, ite_0); + } else { + ite = my_shannon_ite(ite_IF, ite_0, ite_1); + } + array_insert_last(ite_vertex *, ite_vec, ite); + } + /* OR the ite's together */ + /*-----------------------*/ + ite = ite_OR_itevec(ite_vec); + array_free(ite_vec); + node_free(n); + array_free(order_list); + st_free_table(table); + return ite; +} + +/*---------------------------------------------------------------- + Given an sm_matrix, construct a node with the same function as + the matrix. Matrix is sum of cubes. +-----------------------------------------------------------------*/ +node_t * +act_make_node_from_matrix(F, network) + sm_matrix *F; + network_t *network; +{ + node_t *n, *n1, *f; + sm_row *row; + + n = node_constant(0); + sm_foreach_row(F, row) { + f = act_make_node_from_row(row, F, network); + n1 = node_or(n, f); + node_free(n); + node_free(f); + n = n1; + } + return n; +} diff --git a/sis/pld/act_ite_new.c b/sis/pld/act_ite_new.c new file mode 100644 index 0000000..3a2ae81 --- /dev/null +++ b/sis/pld/act_ite_new.c @@ -0,0 +1,161 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + +static void my_ite_OR(); +static ite_vertex *ite_1, *ite_0; + +ite_vertex * +ite_new_ite_for_cubenode(node) + node_t *node; +{ + array_t *order_list; + int i; + node_t *fanin; + ite_vertex *vertex; + input_phase_t phase; + + order_list = single_cube_order(node); + assert(st_lookup(ite_end_table, (char *)1, (char **) &ite_1)); + assert(st_lookup(ite_end_table, (char *)0, (char **) &ite_0)); + vertex = NIL (ite_vertex); + /* reverse order, because of the way, my_ite_and works */ + /*-----------------------------------------------------*/ + for (i = array_n(order_list) - 1; i >= 0; i--) { + fanin = array_fetch(node_t *, order_list, i); + phase = node_input_phase(node, fanin); + vertex = ite_new_ite_and(vertex, fanin, phase); + } + array_free(order_list); + vertex->index_size = node_num_fanin(node); + return vertex; +} + +ite_vertex * +ite_new_ite_for_single_literal_cubes(node) + node_t *node; +{ + + array_t *order_list; + int i; + input_phase_t phase; + node_t *fanin; + ite_vertex *vertex; + + order_list = OR_literal_order(node); + assert(st_lookup(ite_end_table, (char *)1, (char **) &ite_1)); + assert(st_lookup(ite_end_table, (char *)0, (char **) &ite_0)); + vertex = NIL (ite_vertex); + /* reverse order, because of the way, my_ite_and works */ + /*-----------------------------------------------------*/ + for (i = array_n(order_list) - 1; i >= 0; i--) { + fanin = array_fetch(node_t *, order_list, i); + phase = node_input_phase(node, fanin); + vertex = ite_new_ite_or(vertex, fanin, phase); + } + array_free(order_list); + vertex->index_size = node_num_fanin(node); + return vertex; +} + +/* And variables in a cube*/ +ite_vertex * +ite_new_ite_and(vertex, fanin, phase) +ite_vertex *vertex; +node_t *fanin; +input_phase_t phase; +{ + ite_vertex *vertex_IF, *p_vertex; + + vertex_IF = ite_new_literal(fanin); + + if(vertex == NIL (ite_vertex)) { + switch(phase) { + case POS_UNATE: + p_vertex = my_shannon_ite(vertex_IF, ite_1, ite_0); + break; + case NEG_UNATE: + p_vertex = my_shannon_ite(vertex_IF, ite_0, ite_1); + break; + case BINATE:; + case PHASE_UNKNOWN: + (void)fprintf(misout, "error in new_my_ite_and():phase is binate or unknown\n"); + exit(1); + } + } else { + switch(phase) { + case POS_UNATE: + p_vertex = my_shannon_ite(vertex_IF, vertex, ite_0); + break; + case NEG_UNATE: + p_vertex = my_shannon_ite(vertex_IF, ite_0, vertex); + break; + case BINATE:; + case PHASE_UNKNOWN: + (void)fprintf(misout, "error in new_my_and act, phase is binate or unknown\n"); + exit(1); + } + } + return p_vertex; +} + +/* Or variables */ +ite_vertex * +ite_new_ite_or(vertex, fanin, phase) +ite_vertex *vertex; +node_t *fanin; +input_phase_t phase; +{ + ite_vertex *vertex_IF, *p_vertex; + + vertex_IF = ite_new_literal(fanin); + + if(vertex == NIL (ite_vertex)) { + switch(phase) { + case POS_UNATE: + p_vertex = my_shannon_ite(vertex_IF, ite_1, ite_0); + break; + case NEG_UNATE: + p_vertex = my_shannon_ite(vertex_IF, ite_0, ite_1); + break; + case BINATE:; + case PHASE_UNKNOWN: + (void)fprintf(misout, "error in new_my_ite_or():phase is binate or unknown\n"); + exit(1); + } + } else { + switch(phase) { + case POS_UNATE: + p_vertex = my_shannon_ite(vertex_IF, ite_1, vertex); + break; + case NEG_UNATE: + p_vertex = my_shannon_ite(vertex_IF, vertex, ite_1); + break; + case BINATE:; + case PHASE_UNKNOWN: + (void)fprintf(misout, "error in new_my_or act, phase is binate or unknown\n"); + exit(1); + } + } + return p_vertex; +} + +/*----------------------------------- + Makes an ite vertex for the fanin. +-----------------------------------*/ +ite_vertex * +ite_new_literal(fanin) + node_t *fanin; +{ + ite_vertex *ite; + + ite = ite_alloc(); + ite->value = 2; + ite->phase = 1; + /* ite->index = b_col; */ + ite->index_size = 1; + ite->name = node_long_name(fanin); + ite->fanin = fanin; + return ite; +} + diff --git a/sis/pld/act_leaf.c b/sis/pld/act_leaf.c new file mode 100644 index 0000000..0342f40 --- /dev/null +++ b/sis/pld/act_leaf.c @@ -0,0 +1,157 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_leaf.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +/* Created by Narendra */ +#include "sis.h" +#include "pld_int.h" + +static check_universal(); +static void unate_split_F(); + +/* Here we have obtained a unate leaf and wish to construct its bdd*/ +act_t * +unate_act(F) +sm_matrix *F; +{ + act_t *act, *my_init_act(), *act_F(), *unate_act(), *my_or_act_F(); + int i; + sm_matrix *M; + sm_col *pcol; + sm_row *cover; + sm_element *p; + array_t *array, *array_act; + char *dummy; + int *phase; + + +/* Check whether the matrix has more than one cube and contains + * the universal cube. This helps to prune the tree!*/ + if(check_universal(F)) { + if(st_lookup(end_table, (char *)1, &dummy)) { + act = (act_t *)dummy; + } else { + (void)fprintf(sisout, "error in st_table\n"); + } + } else if (F->nrows == 1){ +/* If matrix has only one leaf construct act so that the and of the + * variables is realised. */ + act = act_F(F); + } else { +/* Construct the M matrix which is used for covering puposes*/ + phase = ALLOC(int, F->ncols); + M = sm_alloc(); + sm_foreach_col(F,pcol) { + sm_foreach_col_element(pcol, p){ + if(p->user_word != (char *)2) { + (void) sm_insert(M, p->row_num, p->col_num); + phase[p->col_num] = (int )p->user_word; + if(ACT_DEBUG) { + (void)fprintf(sisout, "the phase is %d\n", + phase[p->col_num]); + } + } + } + } + +/* solve covering problem for M*/ + cover = sm_minimum_cover(M, NIL(int), 0, 0); + sm_foreach_row_element(cover, p){ + p->user_word = (char *)phase[p->col_num]; + } + sm_free_space(M); + FREE(phase); + array = array_alloc(sm_matrix *, 0); +/* construct sub matrices as a result of the covering solution*/ + unate_split_F(F, cover, array); +/* Recursively solve each of the sub matrices*/ + array_act = array_alloc(act_t *, 0); + for( i = 0; i < array_n(array); i++ ) { + act = unate_act(array_fetch(sm_matrix *, array, i)); + array_insert_last(act_t *, array_act, act); + } + if(array_n(array_act) != cover->length) { + (void)fprintf(sisout, + "error array length (of acts) and minucov solution do not match \n"); + } + act = my_or_act_F(array_act, cover, array); +/* Free up the area alloced for array and the Fi s.*/ + for(i = 0; i< array_n(array); i++ ){ + sm_free_space(array_fetch(sm_matrix *, array, i)); + } + array_free(array); + array_free(array_act); + sm_row_free(cover); + } + return act; +} + + +/* checks for a row of 2's. returns 1 if true else 0*/ +static int +check_universal(F) +sm_matrix *F; +{ + sm_row *row; + sm_element *p; + int var; + + sm_foreach_row(F, row) { + var = 1; + sm_foreach_row_element(row, p){ + if(p->user_word != (char *)2) { + var = 0; + } + } + if (var) return 1; + } + return 0; +} + + + + + + +/* constructs a set of sub matrices from F such that */ +static void +unate_split_F(F, cover, array) +sm_matrix *F; +sm_row *cover; +array_t *array; +{ + sm_element *p, *q; + sm_col *col; + sm_matrix *Fi; + sm_row *row, *F_row, *my_row_dup(); + int col_num; + +/* Initialise row->user_word == NUll to prevent duplication of cubes + * if 2 elements in the cover contain the same cube! Need for optimisation*/ + + sm_foreach_row(F, row) { + row->user_word = (char *)0; + } + sm_foreach_row_element(cover, q) { + col_num = q->col_num; + col = sm_get_col(F, col_num); + Fi = sm_alloc(); + sm_foreach_col_element(col, p) { + F_row = sm_get_row(F, p->row_num); + if((p->user_word != (char *)2)&&(F_row->user_word == (char *)0)) { + my_sm_copy_row(F_row, Fi, col_num, F); + if(ACT_DEBUG) { + my_sm_print(Fi); + } + F_row->user_word = (char *)1; + } + } + array_insert_last(sm_matrix *, array, Fi); + } +} + diff --git a/sis/pld/act_map.c b/sis/pld/act_map.c new file mode 100644 index 0000000..ae08ee2 --- /dev/null +++ b/sis/pld/act_map.c @@ -0,0 +1,3469 @@ +/* April 4, 1991 - added act_is_or_used */ +/* May 7, 1991 - added init_param to make routines look cleaner + - fixed bdnet file generation + - moved some stuff over to act_util.c */ +/* Aug 18, 1991 - fixed another bdnet generation bug - driving a node by + two outputs */ + +#include "sis.h" +#include "pld_int.h" + +static int map_act_delay(); + +array_t *multiple_fo_array; /* holds the nodes that have multiple_fo in the act */ +array_t *num_mux_struct_array; /* holds the cost of each multiple_fo act */ +array_t *my_node_array; +array_t *vertex_node_array; /* for node and its root bdd */ +array_t *vertex_name_array; /* for vertex's association with name of correct node */ +int WHICH_ACT; +ACT_VERTEX * PRESENT_ACT; /* for temporary storage */ +int MARK_VALUE, MARK_COMPLEMENT_VALUE; +int num_or_patterns; /* number of blocks that use the OR_gate */ +static int instance_num; +extern int act_is_or_used; + +network_t * +act_map_network(network, init_param, cost_table) + +network_t *network; +act_init_param_t *init_param; +st_table *cost_table; + +{ + node_t *node; + node_function_t node_fun; + COST_STRUCT *cost_node; + char *name; + int i, size; + int cost_network; + array_t *nodevec; + array_t *delay_values; /* for delay values */ + + if (init_param->DISJOINT_DECOMP) decomp_disj_network(network); + if (init_param->mode != AREA) { + delay_values = act_read_delay(init_param->delayfile); + } + + + nodevec = network_dfs(network); + size = array_n(nodevec); + for (i = 0; i < size; i++) { + node = array_fetch(node_t *, nodevec, i); + node_fun = node_function(node); + if ((node_fun != NODE_PI) && (node_fun != NODE_PO)) { /* node is INTERNAL */ + if ((node_fun == NODE_0) || (node_fun == NODE_1)) { + cost_node = ALLOC(COST_STRUCT, 1); + cost_node->node = node; + cost_node->arrival_time = (double) 0.0; + cost_node->cost_and_arrival_time = (double) (-1.0); + cost_node->cost = 0; + cost_node->act = NIL (ACT_VERTEX); + } else { + if (init_param->mode == AREA) { + cost_node = act_evaluate_map_cost(node, init_param, + NIL(network_t), NIL(array_t), + NIL(st_table)); + } else { + cost_node = act_evaluate_map_cost(node, init_param, + network, delay_values, cost_table); + } + } + name = util_strsav(node_long_name(node)); + assert (!st_insert(cost_table, name, (char *)cost_node)); + } /* if INTERNAL */ + else { + /* set the arrival time of PI's if DELAY mode */ + /*--------------------------------------------*/ + if ((node_fun == NODE_PI) && (init_param->mode != AREA)) + (void) act_set_pi_arrival_time_node(node, cost_table); + } + + } + array_free(nodevec); + + if (init_param->mode == AREA) { + iterative_improvement(network, cost_table, init_param); + if (init_param->LAST_GASP) { + network = act_network_remap(network, cost_table); + } + cost_network = print_network(network, cost_table, -1); + } + if (ACT_STATISTICS) (void) printf(" block count: %d\n", cost_network); + assert(network_check(network)); + if (init_param->BREAK) { + network = act_break_network(network, cost_table); + if ((ACT_STATISTICS) || (ACT_DEBUG)) + (void) printf(" number of blocks using OR gate = %d\n", num_or_patterns); + /* if (ACT_DEBUG) act_final_check_network(network, cost_table); */ + } + if (init_param->mode != AREA) { + if (init_param->BREAK) { + act_delay_iterative_improvement(network, cost_table, delay_values, + init_param); + } + array_free(delay_values); + } + return network; +} + +/******************************************************************************************************************* + improve the network using repeated partial collapse and decomp till NUM_ITER are done, or no further improvement. + then do a quick-phase to determine which nodes should be realized as complemented. +********************************************************************************************************************/ + +static +iterative_improvement(network, cost_table, init_param) + network_t *network; + st_table *cost_table; + act_init_param_t *init_param; +{ + if (init_param->NUM_ITER > 0) improve_network(network, cost_table, init_param); + if (init_param->QUICK_PHASE) act_quick_phase(network, cost_table, init_param); + if (ACT_DEBUG) assert(network_check(network)); +} + +/**************************************************************************** +act_evaluate_map_cost() - summary +It maps the given node onto the actel architecture. Preferably, + the network given could be the one with every node having fanin less than + equal to 6- the maximum limit upto which the act generated for each node is + optimal. Then for the node, the act is generated; + at multiple fanout points in the act, + the act is broken and a set of acts is + constructed. For each small act(a tree), the pattern_match algorithm is + used to compute the cost of the act in terms of the mux structure. +COMMENTS: 1) network, delay_values, cost_table are all NIL if init_param->mode is AREA. + These are needed only if init_param->mode is DELAY. + 2) Returns COST_STRUCT * corresponding to the node, but does + not insert it in the cost_table. +*****************************************************************************/ + +COST_STRUCT * +act_evaluate_map_cost(node, init_param, network, delay_values, cost_table) + node_t *node; + act_init_param_t *init_param; + network_t *network; + array_t *delay_values; + st_table *cost_table; +{ + ACT_VERTEX_PTR act_of_node, act1_of_node, act2_of_node; + COST_STRUCT *cost_node, *cost_node1, *cost_node2; + + if (ACT_DEBUG) node_print(stdout, node); + if((node_num_literal(node) == node_num_cube(node)) || + (node_num_cube(node) == 1)) { + act_of_node = my_create_act(node, init_param->mode, cost_table, + network, delay_values); + act_of_node->my_type = ORDERED; + WHICH_ACT = ORDERED; + act_of_node->node = node; + if (init_param->mode == AREA) cost_node = make_tree_and_map(node, act_of_node); + else cost_node = make_tree_and_map_delay(node, act_of_node, network, delay_values, + cost_table, init_param->mode); + act_act_free(node); + return cost_node; + } + + switch(init_param->HEURISTIC_NUM){ + case 1: + act_of_node = my_create_act(node, init_param->mode, cost_table, network, + delay_values); + WHICH_ACT = act_of_node->my_type = ORDERED; + act_of_node->node = node; + if (init_param->mode == AREA) cost_node = make_tree_and_map(node, act_of_node); + else cost_node = make_tree_and_map_delay(node, act_of_node, network, delay_values, + cost_table, init_param->mode); + act_act_free(node); + return cost_node; + case 2: + make_act(node); + ACT_SET(node)->LOCAL_ACT->act->node_list = NIL(array_t ); + act_of_node = ACT_SET(node)->LOCAL_ACT->act->root; + WHICH_ACT = act_of_node->my_type = UNORDERED; + act_of_node->node = node; + if (init_param->mode == AREA) cost_node = make_tree_and_map(node, act_of_node); + else cost_node = make_tree_and_map_delay(node, act_of_node, network, delay_values, + cost_table, init_param->mode); + act_act_free(node); + return cost_node; + case 3: + if ((node_num_fanin(node) <= MAXOPTIMAL) || + (node_num_literal(node) == node_num_fanin(node))) { + act_of_node = my_create_act(node, init_param->mode, cost_table, network, + delay_values); + WHICH_ACT = act_of_node->my_type = ORDERED; + act_of_node->node = node; + } else { + make_act(node); + ACT_SET(node)->LOCAL_ACT->act->node_list = NIL(array_t ); + act_of_node = ACT_SET(node)->LOCAL_ACT->act->root; + WHICH_ACT = act_of_node->my_type = UNORDERED; + act_of_node->node = node; + } + if (init_param->mode == AREA) cost_node = make_tree_and_map(node, act_of_node); + else cost_node = make_tree_and_map_delay(node, act_of_node, network, delay_values, + cost_table, init_param->mode); + act_act_free(node); + return cost_node; + case 4: + make_act(node); + ACT_SET(node)->LOCAL_ACT->act->node_list = NIL(array_t ); + act2_of_node = ACT_SET(node)->LOCAL_ACT->act->root; + WHICH_ACT = act2_of_node->my_type = UNORDERED; + act2_of_node->node = node; + if (init_param->mode == AREA) cost_node2 = make_tree_and_map(node, act2_of_node); + else cost_node2 = make_tree_and_map_delay(node, act2_of_node, network, delay_values, + cost_table, init_param->mode); + act_act_free(node); + if (cost_node2->cost <= 1) { + return cost_node2; + } + act1_of_node = my_create_act(node, init_param->mode, cost_table, network, + delay_values); + WHICH_ACT = act1_of_node->my_type = ORDERED; + act1_of_node->node = node; + if (init_param->mode == AREA) cost_node1 = make_tree_and_map(node, act1_of_node); + else cost_node1 = make_tree_and_map_delay(node, act1_of_node, network, delay_values, + cost_table, init_param->mode); + act_act_free(node); + if (init_param->mode == AREA) { + if (cost_node1->cost <= cost_node2->cost) { + (void) free_cost_struct(cost_node2); + return cost_node1; + } + (void) free_cost_struct(cost_node1); + return cost_node2; + } else { + if (cost_node1->arrival_time <= cost_node2->arrival_time) { + (void) free_cost_struct(cost_node2); + return cost_node1; + } + (void) free_cost_struct(cost_node1); + return cost_node2; + } + default: + (void) printf("Error: act_map_evaluate(): %d is not a valid heuristic number\n", + init_param->HEURISTIC_NUM); + exit(1); + } + return (NIL (COST_STRUCT)); +} + +/************************************************************************************ + Given a node and its subject_graph (ACT, or OACT), snap at multiple fanout points + and maps each tree using the pattern-set. +*************************************************************************************/ + +COST_STRUCT * +make_tree_and_map(node, act_of_node) + node_t *node; + ACT_VERTEX_PTR act_of_node; + +{ + int num_acts; + int i; + int num_mux_struct; + int TOTAL_MUX_STRUCT; /* cost of the network */ + COST_STRUCT *cost_node; + ACT_VERTEX_PTR act; + + TOTAL_MUX_STRUCT = 0; + cost_node = ALLOC(COST_STRUCT, 1); + + act_init_multiple_fo_array(act_of_node); /* insert the root */ + act_initialize_act_area(act_of_node, multiple_fo_array); + /* initialize the required structures */ + /* if (ACT_DEBUG) my_traverse_act(act_of_node); + if (ACT_DEBUG) print_multiple_fo_array(multiple_fo_array); */ + num_acts = array_n(multiple_fo_array); + /* changed the following traversal , now bottom-up */ + /*--------------------------------------------------*/ + for (i = num_acts - 1; i >= 0; i--) { + act = array_fetch(ACT_VERTEX_PTR, multiple_fo_array, i); + PRESENT_ACT = act; + num_mux_struct = map_act(act); + TOTAL_MUX_STRUCT += num_mux_struct; + } + if (ACT_DEBUG) { + (void) printf("total mux_structures used for the node %s = %d, arrival_time = %f\n", + node_long_name(node), TOTAL_MUX_STRUCT, act_of_node->arrival_time); + } + array_free(multiple_fo_array); + cost_node->cost = TOTAL_MUX_STRUCT; + cost_node->arrival_time = act_of_node->arrival_time; + cost_node->node = node; + cost_node->act = act_of_node; + return cost_node; +} + +/*************************************************************************************** + Creates OACT for a given node. If the node has <= MAXOPTIMAL fanins, optimal act + (with min. number of vertices would be constructed. + COMMENTS: If mode is AREA, cost_table is actually NIL. Not using it then. +****************************************************************************************/ + +ACT_VERTEX_PTR +my_create_act(node, mode, cost_table, network, delay_values) +node_t *node; +float mode; +st_table *cost_table; +network_t *network; +array_t *delay_values; + +{ + array_t *OR_literal_order(); + array_t *single_cube_order(); + array_t *nodevec; + array_t *order_list; + array_t *decomp_array; + node_t *n, *fanin; + node_t *node_of_cube; + node_cube_t cube; + int size; + int num_cube_n, num_literal_n; + int i; + ACT_VERTEX_PTR act; + int act_constructed; /* in case number of cubes = 2 */ + int num_cubes; + int num_literals; + int num_fanins; + array_t *cube_order_list, *order_list_new; + extern ACT_VERTEX * p_act_construct(); + + act_constructed = 0; + + /* if mode is not AREA, arrival times of inputs determine the order_list. */ + /*----------------------------------------------------------------------*/ + if (mode != AREA) { + nodevec = array_alloc(node_t *, 0); + array_insert_last(node_t *, nodevec, node); + if (node_num_fanin(node) <= MAXOPTIMAL) { + p_actCreate4Set(nodevec, NIL(array_t), 1, OPTIMAL, + mode, network, delay_values, cost_table); + act = ACT_SET(node)->LOCAL_ACT->act->root; + if (ACT_SET(node)->LOCAL_ACT->act->node_list == NIL (array_t)) { + (void) printf(" Error: my_create_act(): optimal order list not\ + returned\n"); + exit(1); + } + put_node_names_in_act(ACT_SET(node)->LOCAL_ACT->act->root, + ACT_SET(node)->LOCAL_ACT->act->node_list); + } else { + order_list = act_order_for_delay(node, cost_table); + act = (ACT_VERTEX *) p_act_construct(node, order_list, 1); + put_node_names_in_act(ACT_SET(node)->LOCAL_ACT->act->root, order_list); + array_free(order_list); + ACT_SET(node)->LOCAL_ACT->act->node_list = NIL (array_t); + } + array_free(nodevec); + return act; + } + /* mode = AREA: minimizing the number of basic blocks now. + if the number of cubes is 1, then make sure that the bottom ones are + not inverted. If the number is 2 and the possibility that there + is a factor of type (a+b), then order a,b towards the end(bottom) */ + /*-------------------------------------------------------------------*/ + num_cubes = node_num_cube(node); + if (num_cubes == 0) { + nodevec = array_alloc(node_t *, 0); + array_insert_last(node_t *, nodevec, node); + p_actCreate4Set(nodevec, NIL(array_t), 1, OPTIMAL, (float) 0.0, NIL(network_t), + NIL(array_t), NIL(st_table)); + act = ACT_SET(node)->LOCAL_ACT->act->root; + array_free(nodevec); + return act; + } + num_literals = node_num_literal(node); + num_fanins = node_num_fanin(node); + if (num_cubes == num_literals) { + if (num_fanins == num_literals) { + order_list = OR_literal_order(node); + act = (ACT_VERTEX *) p_act_construct(node, order_list, 1); + put_node_names_in_act(ACT_SET(node)->LOCAL_ACT->act->root, order_list); + array_free(order_list); + ACT_SET(node)->LOCAL_ACT->act->node_list = NIL (array_t); + return act; + } else { + act = my_create_act_general(node); + return act; + } + } + + /* take into account the fact that OR gate is there for single cube*/ + /*-----------------------------------------------------------------*/ + if (num_cubes == 1) { + if (num_fanins == num_literals) { + order_list = single_cube_order(node); + act = p_act_construct(node, order_list, 1); + put_node_names_in_act(ACT_SET(node)->LOCAL_ACT->act->root, order_list); + array_free(order_list); + ACT_SET(node)->LOCAL_ACT->act->node_list = NIL (array_t); + return act; + } else { + act = my_create_act_general(node); + return act; + } + } + + /* if num_literals = num_fanin_node, then it means it is a + disjoint support tree, then the ordering is obtained by + concatenating the optimal ordering of the individual cubes. + ordering of the individual cubes is carried on in the same way as + ordering of the nodes with a single cube. case like f = ab + c' */ + /*-----------------------------------------------------------------*/ + if (num_literals == num_fanins) { + order_list = array_alloc(node_t *, 0); + for (i = num_cubes - 1; i >= 0; i--) { + cube = node_get_cube(node, i); + node_of_cube = pld_make_node_from_cube(node, cube); + cube_order_list = single_cube_order(node_of_cube); + node_free(node_of_cube); + order_list_new = array_join(order_list, cube_order_list); + array_free(order_list); + array_free(cube_order_list); + order_list = array_dup(order_list_new); + array_free(order_list_new); + } + act = p_act_construct(node, order_list, 1); + put_node_names_in_act(ACT_SET(node)->LOCAL_ACT->act->root, order_list); + array_free(order_list); + ACT_SET(node)->LOCAL_ACT->act->node_list = NIL (array_t); + return act; + } + + /* if num_cubes == 2, then check for a special condition - basically a filter */ + /*-----------------------------------------------------------------------------*/ + if (num_cubes == 2) { + decomp_array = decomp_good(node); + size = array_n(decomp_array); + if (size == 2) { + n = array_fetch(node_t *, decomp_array, 1); + num_cube_n = node_num_cube(n); + num_literal_n = node_num_literal(n); + if ((num_cube_n == num_literal_n) && (all_fanins_positive(n))){ + order_list = array_alloc(node_t *, 0); + act_put_nodes(array_fetch(node_t *, decomp_array, 0), n, order_list); + for (i = num_literal_n - 1; i >= 0; i--) { + fanin = node_get_fanin(n, i); + array_insert_last(node_t *, order_list, fanin); + } + act_constructed = 1; + act = p_act_construct(node, order_list, 1); + put_node_names_in_act(ACT_SET(node)->LOCAL_ACT->act->root, order_list); + array_free(order_list); + ACT_SET(node)->LOCAL_ACT->act->node_list = NIL (array_t); + } + } + for (i = 0; i < size; i++) { + node_free(array_fetch(node_t *, decomp_array, i)); + } + array_free(decomp_array); + if (act_constructed) return act; + } /* if num_cubes == 2 */ + + /* create general act */ + /*--------------------*/ + act = my_create_act_general(node); + return act; +} + +static +ACT_VERTEX_PTR +my_create_act_general(node) + node_t *node; +{ + array_t *nodevec; + ACT_VERTEX_PTR act; + array_t *order_list, *order_list1; + array_t *pld_order_nodes(), *act_get_corr_fanin_nodes(); + extern ACT_VERTEX * p_act_construct(); + node_t *po1, *node1; + network_t *network1; + + /* if number of fanins is leq than MAXOPTIMAL, construct an optimal ACT for delay */ + /*--------------------------------------------------------------------------------*/ + if (node_num_fanin(node) <= MAXOPTIMAL) { + nodevec = array_alloc(node_t *, 0); + array_insert_last(node_t *, nodevec, node); + p_actCreate4Set(nodevec, NIL(array_t), 1, OPTIMAL, (float) 0.0, + NIL(network_t), NIL(array_t), NIL(st_table)); + act = ACT_SET(node)->LOCAL_ACT->act->root; + if (ACT_SET(node)->LOCAL_ACT->act->node_list == NIL (array_t)) { + (void) printf(" Error: my_create_act_general(): optimal order list not\ + returned\n"); + exit(1); + } + put_node_names_in_act(ACT_SET(node)->LOCAL_ACT->act->root, + ACT_SET(node)->LOCAL_ACT->act->node_list); + array_free (nodevec); + return act; + } + /* create a network in terms of fanins only */ + + network1 = network_create_from_node(node); + po1 = network_get_po(network1, 0); + node1 = node_get_fanin(po1, 0); + nodevec = array_alloc(node_t *, 0); + array_insert_last(node_t *, nodevec, node1); + order_list1 = pld_order_nodes(nodevec, 1); /* just PI */ + order_list = act_get_corr_fanin_nodes(node, order_list1); + array_free(order_list1); + array_free(nodevec); + network_free(network1); + /* order_list = pld_order_nodes(nodevec, 0); */ /* include internal nodes also */ + + act = p_act_construct(node, order_list, 1); /* local ACT */ + put_node_names_in_act(ACT_SET(node)->LOCAL_ACT->act->root, order_list); + array_free(order_list); + ACT_SET(node)->LOCAL_ACT->act->node_list = NIL (array_t); + return act; +} + +/****************************************************************************** + given a node, checks if all the fanins have a positive phase. + Returns 1 if so, else returns 0. +******************************************************************************/ + +static +int all_fanins_positive(node) + node_t *node; +{ + + int num_fanin; + node_t *fanin; + input_phase_t phase; + int i; + + num_fanin = node_num_fanin(node); + for (i = num_fanin - 1; i >= 0; i--) { + fanin = node_get_fanin(node, i); + phase = node_input_phase(node, fanin); + if (phase != POS_UNATE) return 0; + } + return 1; +} + +/************************************************************* + Initializes the array for the multiple_fo_vertices in the + act for node under consideration. The first entry is the + root itself, although it is not multiple fan_out vertex. +************************************************************/ + +void +act_init_multiple_fo_array(act_of_node) + ACT_VERTEX_PTR act_of_node; +{ + multiple_fo_array = array_alloc(ACT_VERTEX_PTR, 0); + array_insert_last(ACT_VERTEX_PTR, multiple_fo_array, act_of_node); +} + +/*************************************************************************** + Annotates the act vertex with the name of the corresponding index-node. +****************************************************************************/ +void put_node_names_in_act(vertex, list) + ACT_VERTEX_PTR vertex; + array_t *list; +{ + node_t *node; + + if (vertex->mark == 0) vertex->mark = 1; + else vertex->mark = 0; + + if (vertex->value != 4) return; + node = array_fetch(node_t *, list, vertex->index); + vertex->name = node_long_name(node); + if (vertex->mark != vertex->low->mark) /* low child already visited */ + put_node_names_in_act(vertex->low, list); + if (vertex->mark != vertex->high->mark) + put_node_names_in_act(vertex->high, list); +} + +/*********************************************************************** + Returns the cost of mapping a act vertex onto the patterns + The cost of 1 mux structure is 1, hence in all configurations the mux + is equally costly. This results in a very simple method of mapping. + The function looks at the root of the tree_act, looks at two levels below + and calculates the cost of the children there, if any, and adds one + to the cost +***********************************************************************/ +int map_act(vertex) + ACT_VERTEX_PTR vertex; + +{ + + + int TOTAL_PATTERNS = 12; + int pat_num; + int cost[12]; /* for each of the 12 patterns derived from the mux struct */ + int vlow_cost; + int vhigh_cost; + int vlowlow_cost; + int vlowhigh_cost; + int vhighlow_cost; + int vhighhigh_cost; + int best_pat_num; + + /* if cost already computed, don't compute again */ + /*-----------------------------------------------*/ + if (vertex->mapped) return vertex->cost; + + + /* if multiple fanout (but not the root of the present multiple_fo vertex) + return 0, but do not set any value, as this vertex would be/ or was + visited earlier as a root. Basically zero is not its true cost. So do not set + vertex->mapped = 1 also */ + + if ((vertex->multiple_fo != 0) && (vertex != PRESENT_ACT)) { + vertex->cost = 0; + return 0; + } + + vertex->mapped = 1; + + if (vertex->value != 4) { + vertex->cost = 0; + return 0; + } + + /* if a simple input, cost = 0 */ + /*-----------------------------*/ + if ((vertex->low->value == 0) && (vertex->high->value == 1)) { + vertex->cost = 0; + return 0; + } + + + /* if or gate not used, just used first 4 patterns */ + /*-------------------------------------------------*/ + if (!act_is_or_used) TOTAL_PATTERNS = 4; + + /* initialize cost vector to a very high value for all the patterns*/ + /*-----------------------------------------------------------------*/ + for (pat_num = 0; pat_num < TOTAL_PATTERNS; pat_num++) { + cost[pat_num] = MAXINT; + } + + /***********recursively calculate relevant costs *************/ + + if (vertex->low->multiple_fo != 0) vlow_cost = 0; + else vlow_cost = map_act(vertex->low); + + if (vertex->high->multiple_fo != 0) vhigh_cost = 0; + else vhigh_cost = map_act(vertex->high); + + if (vertex->low->value == 4) { + if (vertex->low->multiple_fo != 0) + vlowlow_cost = vlowhigh_cost = MAXINT; + else { + if (vertex->low->low->multiple_fo != 0) vlowlow_cost = 0; + else vlowlow_cost = map_act(vertex->low->low); + if (vertex->low->high->multiple_fo != 0) vlowhigh_cost = 0; + else vlowhigh_cost = map_act(vertex->low->high); + } + } + + if (vertex->high->value == 4) { + if (vertex->high->multiple_fo != 0) + vhighlow_cost = vhighhigh_cost = MAXINT; + else { + if (vertex->high->low->multiple_fo != 0) vhighlow_cost = 0; + else vhighlow_cost = map_act(vertex->high->low); + if (vertex->high->high->multiple_fo != 0) vhighhigh_cost = 0; + else vhighhigh_cost = map_act(vertex->high->high); + } + } + + /**********enumerate possible cases************************/ + + /* l.c. (left child) + r.c.(right child) + 1 */ + /*-------------------------------------------*/ + cost[0] = vlow_cost + vhigh_cost + 1; + + if (vertex->low->value == 4) + cost[1] = vlowlow_cost + vlowhigh_cost + vhigh_cost + 1; + + if (vertex->high->value == 4) + cost[2] = vlow_cost + vhighlow_cost + vhighhigh_cost + 1; + + if ((vertex->low->value == 4) && (vertex->high->value == 4)) + cost[3] = vlowlow_cost + vlowhigh_cost + + vhighlow_cost + vhighhigh_cost + 1; + if (!act_is_or_used) { + /************find minimum cost************************/ + /*---------------------------------------------------*/ + best_pat_num = minimum_cost_index(cost, TOTAL_PATTERNS); + vertex->cost = cost[best_pat_num]; + vertex->pattern_num = best_pat_num; + /* if (ACT_DEBUG) + (void) printf("vertex id = %d, index = %d, cost = %d, name = %s, pattern_num = %d\n", + vertex->id, vertex->index, vertex->cost, vertex->name, vertex->pattern_num);*/ + return vertex->cost; + } + + /* OR patterns - pretty involved -> for more explanation, see doc. */ + /*-----------------------------------------------------------------*/ + + if ((OR_pattern(vertex)) + && (vertex->low->low->multiple_fo == 0) + && (vertex->low->low->value == 4) + ) + cost[4] = map_act(vertex->low->low->low) + + map_act(vertex->low->low->high) + + 1; + + if ((OR_pattern(vertex->high)) && (vertex->high->multiple_fo == 0)) { + if (vertex->low->value == 0) + cost[5] = map_act(vertex->high->high) + map_act(vertex->high->low->low) + + 1; + else { + if ((vertex->low->value == 1) && (vertex->high->high->value == 0) + && (vertex->high->low->low->value == 1)) + cost[6] = 1; + } + } + + if ((OR_pattern(vertex->low)) && (vertex->low->multiple_fo == 0)) { + if (vertex->high->value == 0) + cost[7] = map_act(vertex->low->high) + map_act(vertex->low->low->low) + + 1; + } + + /************find minimum cost************************/ + best_pat_num = minimum_cost_index(cost, TOTAL_PATTERNS); + vertex->cost = cost[best_pat_num]; + vertex->pattern_num = best_pat_num; + /* if (ACT_DEBUG) + (void) printf("vertex id = %d, index = %d, cost = %d, name = %s, pattern_num = %d\n", + vertex->id, vertex->index, vertex->cost, vertex->name, vertex->pattern_num);*/ + return vertex->cost; +} + + +/************************************************************************** + if an OR pattern (or NOR pattern) is rooted at the root, return 1, else + return 0 +***************************************************************************/ +static +int OR_pattern(root) + ACT_VERTEX_PTR root; +{ + if ((root->value == 4) && + (root->low->multiple_fo == 0) && (root->low->value == 4) && + (root->high == root->low->high) + ) + return 1; + + return 0; +} + +/************************************************************************ + returns the index of the pattern which results in the minimum cost + at the present node. +*************************************************************************/ +static +int minimum_cost_index(cost, num_entries) + int cost[]; + int num_entries; +{ + + int i; + int min_index = 0; + + for (i = 1; i < num_entries; i++) { + if (cost[i] < cost[min_index]) min_index = i; + } + return min_index; +} + +static +improve_network(network, cost_table, init_param) + network_t *network; + st_table *cost_table; + act_init_param_t *init_param; + +{ + + int nogain; + network_t *dup_net; + node_t *dup_node; + lsGen genfo; + node_t *node, *fanout; + /* node_t *fanout_simpl; */ + COST_STRUCT ***focost; + int **focost_ind; + char *dummy; + char buf[BUFSIZE]; /* to hold the system command */ + int i, j; + array_t *nodevec; + st_table *node2num_table; + int size_net; + int clust_num; + int numnodes; /*number of internal nodes */ + + int **M; /* coeff. for Integer Programming formulation */ + int *num_ones; /* number of ones in a row of M[][] */ + int *g; /*gain for a cluster*/ + int *collapsed_node; /* for a cluster, stores the id of the + collapsed node */ + + int *variable; /* to hold the value of the variables after IP */ + + int iteration_gain; /* tells the gain at the end of present iteration */ + int gain; /* gain for the node being collapsed */ + int decomp_gain; /* gain for network_decomposition at an iteration */ + int collapse_gain; /*gain from the collapse operation */ + int old_cost; /* old_cost of a fan_out node */ + int cost_network; /* cost of the network in terms of mux_structs*/ + + int num_fo; /* number of fan_outs of a ndoe */ + int clust_num_add1; + + char *lindopathname; + char *name, *name1; + char *infile, *outfile; + node_function_t node_fun; + int num_fanouts; + st_table *fo_table; + int iteration_num; + int sfd; + +nogain = FALSE; +iteration_num = 0; + +while (nogain == FALSE) { + + cost_network = print_network(network, cost_table, iteration_num); + + /* decomposing big nodes in the network if it is profitable*/ + /*---------------------------------------------------------*/ + + decomp_big_nodes(network, cost_table, &decomp_gain, init_param); + + /* check */ + /*-------*/ + assert(network_check(network)); + + if (ACT_DEBUG && (decomp_gain > 0)) + (void) print_network(network, cost_table, iteration_num); + iteration_gain = decomp_gain; + iteration_num++; + if (iteration_num > init_param->NUM_ITER) return; + nogain = TRUE; + clust_num = -1; + + /* check if collapsing is desired. If not, continue if gain sufficient */ + /*---------------------------------------------------------------------*/ + + if (init_param->FANIN_COLLAPSE == 0) { + if (iteration_gain >= (init_param->GAIN_FACTOR * cost_network)) { + nogain = FALSE; + } + continue; + } + + /* search for lindo in the path name. If not found, do not + do collapsing */ + /*--------------------------------------------------------*/ + lindopathname = util_path_search("lindo"); + if (lindopathname == NIL (char)) { + if (ACT_DEBUG) { + (void) printf("YOU DO NOT HAVE LINDO INTEGER PROGRAMMING PACKAGE\n"); + (void) printf("\tIN YOUR PATH.\n"); + (void) printf("CONTINUING WITHOUT LINDO.....\n"); + (void) printf("PLEASE OBTAIN LINDO FROM\n"); + + (void) printf("The Scientific Press, 540 University Ave.\n"); + (void) printf("Palo Alto, CA 94301, USA\n"); + (void) printf("TEL : (415) 322-5221\n"); + } + /* Adding this on Jan. 24, 91 */ + /*----------------------------*/ + collapse_gain = act_partial_collapse_without_lindo(network, + cost_table, init_param); + iteration_gain = collapse_gain + decomp_gain; + + if (iteration_gain >= (init_param->GAIN_FACTOR * cost_network)) { + nogain = FALSE; + } + continue; + } + FREE(lindopathname); + + /*Initialization */ + /*--------------*/ + numnodes = network_num_internal(network) + network_num_po(network) + + network_num_pi(network); + + focost = ALLOC(COST_STRUCT **, numnodes); + focost_ind = ALLOC(int *, numnodes); + M = ALLOC(int *, numnodes); + num_ones = ALLOC(int, numnodes); + g = ALLOC(int, numnodes); + collapsed_node = ALLOC(int, numnodes); + variable = ALLOC(int, numnodes); + + for (i = 0; i < numnodes; i++) { + focost[i] = ALLOC(COST_STRUCT *, numnodes); + M[i] = ALLOC(int, numnodes); + focost_ind[i] = ALLOC(int, numnodes); + for (j = 0; j < numnodes; j++) { + M[i][j] = 0; + focost_ind[i][j] = 0; + } + num_ones[i] = 0; + } + + node2num_table = st_init_table(st_ptrcmp, st_ptrhash); + + nodevec = network_dfs(network); + size_net = array_n(nodevec); + /* establish a link from node to its number */ + /*------------------------------------------*/ + for (i = 0; i <size_net; i++) { + node = array_fetch(node_t *, nodevec, i); + (void) st_insert(node2num_table, node_long_name(node), (char *)i); + } + + for (i = 0; i < size_net; i++) { + node = array_fetch(node_t *, nodevec, i); + node_fun = node_function(node); + if ((node_fun == NODE_PI) || (node_fun == NODE_PO)) continue; + if (node_num_fanin(node) > init_param->FANIN_COLLAPSE) continue; + if (is_anyfo_PO(node)) { + continue; + } + name = node_long_name(node); + dup_net = network_dup(network); + dup_node = network_find_node(dup_net, name); + if (dup_node == NIL (node_t)) { + (void) printf("Error:dup_node not there %s\n", name); + exit(1); + } + name1 = node_long_name(node); + assert(st_lookup(cost_table, name1, &dummy)); + + /* compute the gain if the node "dup_node" is collapsed into each of its + fanouts and is then removed from the network. The cost is stored in the + focost for each of the fanouts of the node "dup_node" */ + /*------------------------------------------------------------------------*/ + gain = ((COST_STRUCT *)dummy)->cost; + num_fo = 0; + clust_num_add1 = clust_num + 1; + + /* for each fanout, recompute the cost */ + /*-------------------------------------*/ + foreach_fanout(dup_node, genfo, fanout) { + (void) node_collapse(fanout, dup_node); + focost[clust_num_add1][num_fo] = + act_evaluate_map_cost(fanout, init_param, NIL(network_t), NIL(array_t), + NIL(st_table)); + /* put the names in act vertices now */ + /*-----------------------------------*/ + act_partial_collapse_update_act_fields(network, fanout, + focost[clust_num_add1][num_fo]); + focost_ind[clust_num_add1][num_fo] = 1; + /* free the act structure of the fanout node, it has been copied into the focost */ + /*-------------------------------------------------------------------------------*/ + assert(st_lookup(cost_table, node_long_name(fanout), &dummy)); + old_cost = ((COST_STRUCT *)dummy)->cost; + gain = gain + old_cost - (focost[clust_num_add1][num_fo]->cost); + num_fo++; + } + + if (gain > 0) { + clust_num++; + + /* assign proper value to g and M for the cluster "clust_num" */ + /*------------------------------------------------------------*/ + collapsed_node[clust_num] = i; + g[clust_num] = gain; + M[i][clust_num] = 1; /* node (ie. with id i) in clust_num */ + num_ones[i]++; + foreach_fanout(node, genfo, fanout) { + assert(st_lookup(node2num_table, node_long_name(fanout), &dummy)); + M[(int) dummy][clust_num] = 1; + num_ones[(int)dummy]++; + } + } /* if (gain > 0) */ + + /* if gain <= 0, free the storage in focost associated with node "dup_node" */ + + else { + for (j = 0; j < num_fo; j++) { + (void) free_cost_struct( focost[clust_num_add1][j]); + focost_ind[clust_num_add1][j] = 0; + } + assert(st_lookup(cost_table, name1, &dummy)); + } + /* free the duplicated node and the network */ + /*-------------------------------------------*/ + network_delete_node(dup_net, dup_node); + network_free(dup_net); + + } /* for i = .. */ + + /* if no cluster (ie with gain > 0) can be formed check here */ + /*-----------------------------------------------------------*/ + if (clust_num < 0) { + if (ACT_DEBUG) + (void) printf("***no improvement in collapse***\n"); + for(i=0; i< numnodes; i++){ + for(j=0; j< numnodes; j++){ + if (focost_ind[i][j] == 1) free_cost_struct( focost[i][j]); + } + FREE( focost[i]); + FREE( focost_ind[i]); + FREE( M[i]); + } + FREE( focost); + FREE( focost_ind); + FREE( variable); + FREE( collapsed_node); + FREE( g); + FREE( num_ones); + FREE(M); + array_free(nodevec); + st_free_table(node2num_table); + if (iteration_gain < (init_param->GAIN_FACTOR * cost_network)) { + if (ACT_DEBUG) { + (void) printf("****no significant improvement in iteration_gain***\n"); + (void) printf("cost_network before iter. = %d, iteration_gain = %d\n", + cost_network, iteration_gain); + } + return; + } + nogain = FALSE; + continue; + } /* if clust_num < 0 */ + + /* else formulate the IP - using LINDO */ + /*---------------------------------*/ + + infile = formulate_IP(nodevec, M, g, num_ones, clust_num, iteration_num); + outfile = ALLOC(char, 100); + (void) sprintf (outfile, "/usr/tmp/actel.lindo.out%d.XXXXXX", iteration_num); + sfd = mkstemp(outfile); + if(sfd != -1) { + close(sfd); + (void) sprintf(buf, "lindo < %s > %s", infile, outfile); + + (void) system(buf); + + /* read the solution and change the network */ + /*-------------------------------------------*/ + read_LINDO_file(outfile, variable, &collapse_gain); + } + + FREE(infile); + FREE(outfile); + iteration_gain = collapse_gain + decomp_gain; + + /* update the cost of affected nodes in the new network */ + /*------------------------------------------------------*/ + for (j = 0; j <= clust_num; j++) { + if (variable[j] == 0) continue; + node = array_fetch(node_t *, nodevec, collapsed_node[j]); + num_fanouts = node_num_fanout(node); + fo_table = st_init_table(strcmp, st_strhash); + foreach_fanout(node, genfo, fanout) { + /* get the correct focost[][] corresponding to fanout */ + /*----------------------------------------------------*/ + for (num_fo = 0; num_fo < num_fanouts; num_fo++) { + if (focost[j][num_fo]->node == fanout) break; + assert(num_fo != (num_fanouts - 1)); + } + assert(!st_insert(fo_table, node_long_name(fanout), (char *) num_fo)); + } + foreach_fanout(node, genfo, fanout) { + (void) node_collapse(fanout, node); + /* fanout_simpl = node_simplify(fanout, NIL (node_t), NODE_SIM_ESPRESSO); + node_replace(fanout, fanout_simpl); */ + name1 = node_long_name(fanout); + name = ALLOC (char, (strlen(name1) + 1) ); /* name needed */ + (void) strcpy(name, name1); + assert(st_delete(cost_table, &name1, &dummy)); + (void) free_cost_struct((COST_STRUCT *) dummy); + FREE(name1); + + /* checking */ + /*----------*/ + if (node_long_name(node) == NIL (char)) { + (void) printf("Error:improve_names---\n"); + exit(1); + } + /* this focost is in the cost_table, unavailable for free. + Therefore set the indicator to 0. */ + /*-------------------------------------------------------*/ + assert(st_lookup_int(fo_table, node_long_name(fanout), &num_fo)); + focost_ind[j][num_fo] = 0; + assert(!st_insert(cost_table, name, (char *) focost[j][num_fo])); + } /* foreach_fanout */ + + st_free_table(fo_table); + /* delete the collapsed node */ + /*---------------------------*/ + name1 = node_long_name(node); + /* delete the act storage from the struct */ + /*----------------------------------------*/ + assert(st_delete(cost_table, &name1, &dummy)); + (void) free_cost_struct((COST_STRUCT *) dummy); + FREE(name1); + + /* checking */ + /*----------*/ + if (node_long_name(node) == NIL (char)) { + (void) printf("Error:improve_names---\n"); + exit(1); + } + + network_delete_node(network, node); + + } /* for j = loop */ + + + /* free storage */ + /*--------------*/ + for (i = 0; i < numnodes; i++) { + for (j = 0; j < numnodes; j++) + if (focost_ind[i][j] == 1) free_cost_struct( focost[i][j]); + FREE( focost[i]); + FREE( focost_ind[i]); + FREE( M[i]); + } + FREE( focost); + FREE( focost_ind); + FREE( M); + FREE( variable); + FREE( collapsed_node); + FREE( g); + FREE( num_ones); + array_free(nodevec); + st_free_table(node2num_table); + if (iteration_gain >= (init_param->GAIN_FACTOR * cost_network)) nogain = FALSE; + if (ACT_DEBUG) + (void) print_network(network, cost_table, iteration_num); + + } /* while (nogain == FALSE) */ + + /* return network; */ +} + +/******************************************************************************** + Generates a file for the program lindo and solves the integer program, + The solution of the integer program generates nodes that should be collapsed. +*********************************************************************************/ +static char * +formulate_IP(nodevec, M, g, num_ones, clust_num, iteration_num) + array_t *nodevec; + int **M; + int g[]; + int num_ones[]; + int clust_num; + int iteration_num; +{ + + int i, j; + int num_constr; + FILE *lindoFile; + int FLAG; + int termsPerLine = 5; + int numTerm; + char *filename; + int net_size; + int fd; + + if (ACT_DEBUG) (void) printf("formulating IP - creating lindo file *****\n"); + filename = ALLOC (char, 100); + (void) sprintf(filename, "/usr/tmp/actel.lindo.in%d.XXXXXX", iteration_num); + fd = mkstemp(filename); + if(fd == -1) { + fprintf(stderr, "failed to open lindo file\n"); + } + lindoFile = fdopen(fd, "w"); + + /* generate objective function : MAX g[0]x0 + .... g[clust_num]xclust_num */ + /*------------------------------------------------------------------------*/ + (void) fprintf(lindoFile, "MAX "); + for (numTerm = 0, i = 0; i <= clust_num; ++numTerm, ++i) { + if (i == 0) (void) fprintf (lindoFile, "%d x0 ", g[0]); + else { + if (numTerm < termsPerLine) + (void) fprintf(lindoFile, "+ %d x%d ", g[i], i); + else { + numTerm = 0; + (void) fprintf(lindoFile, "\n + %d x%d ", g[i], i); + } + } + } + (void) fprintf(lindoFile, "\n"); + + /* Generate constraints for every node in the network, only if at least + two entries for the corresponding row is 1(as told by num_ones. + constraint for a node i is of the form mi,1 x1 + mi,2 x2 + .... <= 1 */ + /*----------------------------------------------------------------------*/ + net_size = array_n(nodevec); + num_constr = 0; + for (i = 0; i < net_size; i++) { + /* if num_ones = 1, obviously constraint would be satisfied - so do + not put the constraint at all */ + /*------------------------------------------------------------------*/ + if (num_ones[i] < 2) continue; + num_constr++; + if (num_constr == 1) (void) fprintf(lindoFile, "ST\n"); + + numTerm = 0; + FLAG = FALSE; + for (j = 0; j <= clust_num; j++) { + if (M[i][j] == 0) continue; + if (FLAG == FALSE) { + FLAG = TRUE; + ++numTerm; + (void) fprintf(lindoFile, "x%d ", j); + continue; + } + if (numTerm < termsPerLine) { + ++numTerm; + (void) fprintf(lindoFile, "+ x%d ", j); + continue; + } + numTerm = 1; + (void) fprintf(lindoFile, "\n + x%d ", j); + } + (void) fprintf(lindoFile, "<= 1\n"); + } /* for i = .. */ + (void) fprintf(lindoFile, "END\n"); + + /* declaration of integrality - integrality would confirm 0-1 IP for lindo */ + /*-------------------------------------------------------------------------*/ + + for ( j = 0; j <= clust_num; j++) + (void) fprintf(lindoFile, "INTEGER x%d\n", j); + + (void) fprintf(lindoFile, "GO\n"); + (void) fprintf(lindoFile, "QUIT\n"); + (void) fclose(lindoFile); + return filename; +} + +/*************************************************************************** + reads the solution generated by the lindo from the file. Sets the + corresponding "variable" values 1. Also reads the gain that resulted + from the collapse operation for the network, stores it in iteration_gain. + -"IP OPTIMUM" means that optimum solution was found. + -"NO FEASIBLE" indicates that no feasible solution exists. + (This normally should not be the case). + -If none of the above two found, then the only other possibility is + "NEW INTEGER", which means optimal answer could not be found, + but some answer was found. So live with that, buddy. For this, + however, the file is scanned again. +****************************************************************************/ +static void +read_LINDO_file(filename, variable, iteration_gain) + char *filename; + int *variable; + int *iteration_gain; + +{ + FILE *lindoFile; + float f_gain; + int variable_id; + float result; + char word[BUFSIZE]; + int FLAG; + + FLAG = 0; + + + + lindoFile = fopen(filename, "r"); + while(TRUE) { + if (fscanf(lindoFile, "%s", word) == EOF) { + if (FLAG == 1) { + FLAG = 2; + break; + } + else { + (void) printf(" sudden end of file lindo.out\n"); + exit(1); + } + } + + if (strcmp(word, "NO") == 0) { + (void) fscanf(lindoFile, "%s", word); + if (strcmp(word, "FEASIBLE") == 0) { + (void) printf(" NO FEASIBLE SOLUTION OBTAINED\n"); + exit(1); + } + (void) printf("Error:NO %s in lindo.out\n", word); + exit(1); + } + if (strcmp(word, "NEW") == 0) { + (void) fscanf(lindoFile, "%s", word); + if (strcmp(word, "INTEGER") == 0) { + FLAG = 1; + } + else { + (void) printf("Error:NEW %s in lindo.out\n", word); + exit(1); + } + continue; + } + /* searching for "IP OPTIMUM" - to get the value of the objective function*/ + /*------------------------------------------------------------------------*/ + if (strcmp(word, "IP") == 0) { + (void) fscanf(lindoFile, "%s", word); + if (strcmp(word, "OPTIMUM") == 0) + break; + else { + (void) printf("Error:unaccounted apperance of IP in lindo file\n"); + exit(1); + } + } + } /* while */ + + /* Optimum solution was not found, but do with the best possible */ + /*---------------------------------------------------------------*/ + if (FLAG == 2) { + (void) fclose(lindoFile); + lindoFile = fopen(filename, "r"); + partial_scan_lindoFile(lindoFile); + } + + /* iteration_gain = value of the objective function */ + /*--------------------------------------------------*/ + while (TRUE) { + (void) fscanf(lindoFile, "%s", word); + if (strcmp(word, "1)") == 0) { + (void) fscanf(lindoFile, "%f", &f_gain); + *iteration_gain = (int) f_gain; + if (ACT_DEBUG) (void) printf("total gain in IP = %d\n", *iteration_gain); + break; + } + } + /* "REDUCED COST" is a precursor of the solution */ + /*-----------------------------------------------*/ + while (TRUE) { + (void) fscanf(lindoFile, "%s", word); + if (strcmp(word, "REDUCED") == 0) { + (void) fscanf(lindoFile, "%s", word); + break; + } + } + + /* now get the result */ + /*--------------------*/ + for(; fscanf(lindoFile, "%s", word) != EOF; ) { + + /* if "ROW" appears solution set section ends */ + /*--------------------------------------------*/ + if (strcmp(word, "ROW") == 0) break; + if (word[0] == 'X') { + (void) sscanf(word, "X%d", &variable_id); + (void) fscanf(lindoFile, "%f", &result); + variable[variable_id] = (int) result; + } + } + (void) fclose(lindoFile); +} + +/*********************************************************************************** + now it is known that the solution is not Optimum; so search for the "NEW INTEGER" + in the file. As soon as it is found(that is, the first instance) return. +*************************************************************************************/ +static void +partial_scan_lindoFile(lindoFile) + FILE *lindoFile; +{ + char word[BUFSIZE]; + + while(TRUE) { + (void) fscanf(lindoFile, "%s", word); + if (strcmp(word, "NEW") == 0) { + (void) fscanf(lindoFile, "%s", word); + if (strcmp(word, "INTEGER") == 0) break; + } + } /* while */ + +} + + + + +/************************************************************************* + return 1 if any fanout of the node is a Primary output. Else return 0. +*************************************************************************/ +int is_anyfo_PO(node) + node_t *node; +{ + lsGen genfo; + node_t *fanout; + node_function_t node_fun; + + foreach_fanout(node, genfo, fanout) { + node_fun = node_function(fanout); + if (node_fun == NODE_PO){ + (void) lsFinish(genfo); + return 1; + } + } + return 0; +} + +print_multiple_fo_array(multiple_fo_array) + array_t *multiple_fo_array; +{ + int nsize; + int i; + ACT_VERTEX_PTR v; + + (void) printf("---- printing multiple_fo_vertices---"); + nsize = array_n(multiple_fo_array); + for (i = 0; i < nsize; i++) { + v = array_fetch(ACT_VERTEX_PTR, multiple_fo_array, i); + (void) printf(" index = %d, id = %d, num_fanouts = %d\n ", v->index, v->id, v->multiple_fo + 1); + } + (void) printf("\n"); +} + +int print_network(network, cost_table, iteration_num) + network_t *network; + st_table *cost_table; + int iteration_num; +{ + lsGen gen; + node_t *node; + char *dummy; + int TOTAL_COST; + char *name; + node_function_t node_fun; + /* int pattern_type; */ /* statistics about how many patterns of what type */ + + /* pattern_type = 0; */ + TOTAL_COST = 0; + + if (ACT_DEBUG) (void) printf("printing network %s\n", network_name(network)); + foreach_node(network, gen, node) { + node_fun = node_function(node); + if ((node_fun == NODE_PI) || (node_fun == NODE_PO)) continue; + if (ACT_DEBUG) node_print(stdout, node); + name = node_long_name(node); + assert(st_lookup(cost_table, name, &dummy)); + if (ACT_DEBUG) (void) printf("cost = %d\n\n", ((COST_STRUCT *)dummy)->cost); + TOTAL_COST += ((COST_STRUCT *) dummy)->cost; + /* pattern_type += ((COST_STRUCT *) dummy)->pattern_type; */ + + } + + if (ACT_DEBUG) { + if (iteration_num < 0) + (void) printf("**** total cost of network after all iterations is %d\n***", + TOTAL_COST); + else + (void) printf("**** total cost of network after iteration %d is %d\n***", + iteration_num, TOTAL_COST); + /* (void) printf("**** usage of OR patterns = %d\n***", + pattern_type); */ + } + + return TOTAL_COST; +} + + +/************************************************************************* + Decompose nodes of the network. If decomposition results in a + lesser cost node, accept the decomposition, and replace the node by + the decomposition. + think about how to decompose the nodes in the network. Should I use the + mux structure and do a resub. this is because it possibly means that the + decomposition would be in terms of a mux structure => Boolean div not + implemented in misII. +**************************************************************************/ + +static +decomp_big_nodes(network, cost_table, gain, init_param) + network_t *network; + st_table *cost_table; + int *gain; + act_init_param_t *init_param; +{ + array_t *nodevec; + int size_net; + int i; + node_t *node; + int num_fanin, num_cube; + node_function_t node_fun; + int FLAG_DECOMP; + + *gain = 0; + FLAG_DECOMP = 1; + + nodevec = network_dfs(network); + size_net = array_n(nodevec); + for (i = 0; i < size_net; i++) { + + node = array_fetch(node_t *, nodevec, i); + node_fun = node_function(node); + if ((node_fun == NODE_PI) || (node_fun == NODE_PO)) continue; + + /* if the num_fanin is less than the limit, continue */ + /*---------------------------------------------------*/ + num_fanin = node_num_fanin(node); + if (num_fanin < init_param->DECOMP_FANIN) continue; + + /* if the node requires upto 2 muxes, do not split it. + Reason being that if split, it would form 2 nodes + (at least) and hence the cost would be >= 2 always */ + /*-----------------------------------------------------*/ + if (cost_of_node(node, cost_table) <= 2) continue; + + /* if constructed optimally, do not decompose */ + /*--------------------------------------------*/ + num_cube = node_num_cube(node); + if ((num_cube == 1) || + (node_num_literal(node) == num_cube) /* earlier it was num_fanin - changed Dec.17, 92 */ + ) continue; + + /* using act_node_remap for decomposition */ + /*----------------------------------------*/ + (*gain) += act_node_remap(network, node, cost_table, FLAG_DECOMP, + init_param->HEURISTIC_NUM); + + } /* for i = loop*/ + + if (ACT_DEBUG) (void) printf("---Gain in decomp_big_nodes = %d\n", *gain); + array_free(nodevec); +/* return network; */ +} + + +/*************************************************************************** + given the node, finds the cost of the node from the cost table. +***************************************************************************/ + + int + cost_of_node(node, cost_table) + node_t *node; + st_table *cost_table; +{ + char *dummy; + + assert(st_lookup(cost_table, node_long_name(node), &dummy)); + return ((COST_STRUCT *) dummy)->cost; + +} + + +/*********************************************************************** + This procedure generates act ordering st. a function which has all the + cubes of single literal, is implemented with minimum no. of mux + structures. First separates the NEG and POS phase fanins. Rest is + complicated!!!! + +*************************************************************************/ + +array_t * +OR_literal_order(node) + node_t *node; + +{ + + array_t *order_list, *order_rev; + array_t *pos_list, *neg_list; + int size_pos, size_neg; + int FLAG_POS, FLAG_NEG; + int pointer_pos, pointer_neg; + int num_fanin; + node_t *fanin, *n; + input_phase_t phase; + int i, j, stage, position; + + num_fanin = node_num_fanin(node); + order_list = array_alloc(node_t *, 0); + order_rev = array_alloc(node_t *, 0); + pos_list = array_alloc(node_t *, 0); + neg_list = array_alloc(node_t *, 0); + + /* separate the fanins with positive phase and negative phase */ + /*------------------------------------------------------------*/ + for (i = num_fanin - 1; i >= 0; i--) { + fanin = node_get_fanin(node, i); + phase = node_input_phase(node, fanin); + if (phase == NEG_UNATE) + array_insert_last(node_t *, neg_list, fanin); + else if (phase == POS_UNATE) + array_insert_last(node_t *, pos_list, fanin); + } + + size_pos = array_n(pos_list); + size_neg = array_n(neg_list); + + /* Get the optimal ordering now for STRUCT module - look at the paper for details*/ + /*-------------------------------------------------------------------------------*/ + + pointer_neg = 0; + pointer_pos = 0; + FLAG_NEG = OFF; + FLAG_POS = OFF; + stage = 0; + + for ( i = 0; i < num_fanin; i++) { + switch (stage) { + case 1 : + if (pointer_neg >= size_neg) { + FLAG_NEG = ON; + break; + } + n = array_fetch(node_t *, neg_list, pointer_neg); + array_insert_last(node_t *, order_rev, n); + pointer_neg++; + break; + case 0:; + case 2:; + case 3: + if (pointer_pos >= size_pos) { + FLAG_POS = ON; + break; + } + n = array_fetch(node_t *, pos_list, pointer_pos); + array_insert_last(node_t *, order_rev, n); + pointer_pos++; + break; + } /* switch */ + + /* if all neg phase fanins finished, put positive now */ + /*----------------------------------------------------*/ + if (FLAG_NEG == ON) { + for (j = i; j < num_fanin; j++) { + if (pointer_pos >= size_pos) { + (void) printf(" Error: pointer_pos = %d??\n", pointer_pos); + exit(1); + } + n = array_fetch(node_t *, pos_list, pointer_pos); + array_insert_last(node_t *, order_rev, n); + pointer_pos++; + } + break; /* from i loop */ + } + + /* if all positive phased fanins finished, put negative now */ + /*-----------------------------------------------------------*/ + if (FLAG_POS == ON) { + for (j = i; j < num_fanin; j++) { + if (pointer_neg >= size_neg) { + (void) printf("Error: pointer_neg = %d??\n", pointer_neg); + exit(1); + } + n = array_fetch(node_t *, neg_list, pointer_neg); + array_insert_last(node_t *, order_rev, n); + pointer_neg++; + } + break; /* from i loop */ + } + + /* for first mux structure, there are 4 inputs that can be assigned, + for the rest, just 3, because the rest of them have as their inputs + the outputs from the previous muxes */ + /*------------------------------------------------------------------*/ + if ((stage % 3) == 0) stage = 1; + else stage = stage + 1; + + } /* for */ + + /* order_rev has everything in reverse order,as it was constructed + bottom_up. Reverse it to get order_list */ + /*------------------------------------------------------------------*/ + for ( i = 0; i < num_fanin; i++) { + position = num_fanin - ( i + 1); + n = array_fetch(node_t *, order_rev, position); + array_insert_last(node_t *, order_list, n); + + } + + /* check */ + /*-------*/ + if (array_n(order_list) != num_fanin) { + (void) printf("single_cube_order():something is binate for node %s\n", + node_long_name(node)); + exit(1); + } + + /* free the lists */ + /*----------------*/ + array_free(order_rev); + array_free(pos_list); + array_free(neg_list); + + return order_list; + +} + +/*********************************************************************** + This procedure generates act ordering st. a function which has a + single cube is implemented with minimum no. of mux + structures. First separates the NEG and POS phase fanins. Rest is + complicated!!!! + +*************************************************************************/ + +array_t * +single_cube_order(node) + node_t *node; + +{ + + array_t *order_list, *order_rev; + array_t *pos_list, *neg_list; + int size_pos, size_neg; + int FLAG_POS, FLAG_NEG; + int pointer_pos, pointer_neg; + int num_fanin; + node_t *fanin, *n; + input_phase_t phase; + int i, j, stage, position; + + num_fanin = node_num_fanin(node); + order_list = array_alloc(node_t *, 0); + order_rev = array_alloc(node_t *, 0); + pos_list = array_alloc(node_t *, 0); + neg_list = array_alloc(node_t *, 0); + + for (i = num_fanin - 1; i >= 0; i--) { + fanin = node_get_fanin(node, i); + phase = node_input_phase(node, fanin); + if (phase == NEG_UNATE) + array_insert_last(node_t *, neg_list, fanin); + else if (phase == POS_UNATE) + array_insert_last(node_t *, pos_list, fanin); + } + + size_pos = array_n(pos_list); + size_neg = array_n(neg_list); + pointer_neg = 0; + pointer_pos = 0; + FLAG_NEG = OFF; + FLAG_POS = OFF; + stage = 0; + + for ( i = 0; i < num_fanin; i++) { + switch (stage) { + case 2 : + case 3 : + if (pointer_neg >= size_neg) { + FLAG_NEG = ON; + break; + } + n = array_fetch(node_t *, neg_list, pointer_neg); + array_insert_last(node_t *, order_rev, n); + pointer_neg++; + break; + case 0:; + case 1: + if (pointer_pos >= size_pos) { + FLAG_POS = ON; + break; + } + n = array_fetch(node_t *, pos_list, pointer_pos); + array_insert_last(node_t *, order_rev, n); + pointer_pos++; + break; + } /* switch */ + + /* if all neg phase fanins finished, put positive now */ + /*----------------------------------------------------*/ + if (FLAG_NEG == ON) { + for (j = i; j < num_fanin; j++) { + if (pointer_pos >= size_pos) { + (void) printf(" pointer_pos = %d??\n", pointer_pos); + exit(1); + } + n = array_fetch(node_t *, pos_list, pointer_pos); + array_insert_last(node_t *, order_rev, n); + pointer_pos++; + } + break; /* from i loop */ + } + + /* if all positive phased fanins finished, put negative now */ + /*-----------------------------------------------------------*/ + if (FLAG_POS == ON) { + for (j = i; j < num_fanin; j++) { + if (pointer_neg >= size_neg) { + (void) printf(" pointer_neg = %d??\n", pointer_neg); + exit(1); + } + n = array_fetch(node_t *, neg_list, pointer_neg); + array_insert_last(node_t *, order_rev, n); + pointer_neg++; + } + break; /* from i loop */ + } + + /* for first mux structure, there are 4 inputs that can be assigned, + for the rest, just 3 */ + /*----------------------------------------------------------------*/ + if ((stage % 3) == 0) stage = 1; + else stage = stage + 1; + + } /* for */ + + /* order_rev has everything in reverse order,as it was constructed + bottom_up. Reverse it to get order_list */ + /*-----------------------------------------------------------------*/ + for ( i = 0; i < num_fanin; i++) { + position = num_fanin - ( i + 1); + n = array_fetch(node_t *, order_rev, position); + array_insert_last(node_t *, order_list, n); + + } + + /* check */ + /*-------*/ + if (array_n(order_list) != num_fanin) { + (void) printf("single_cube_order():something is binate for node %s\n", + node_long_name(node)); + exit(1); + } + + /* free the lists */ + /*----------------*/ + array_free(order_rev); + array_free(pos_list); + array_free(neg_list); + + return order_list; + +} + +/**************************************************************************************** + Checks if it is beneficial to implement the node in negative phase. "Beneficial" is + gotten by recomputing the cost of the node and the fanouts of the node. Greedily selects + the node, if it improves the cost. +******************************************************************************************/ +static +act_quick_phase(network, cost_table, init_param) + network_t *network; + st_table *cost_table; + act_init_param_t *init_param; +{ + + array_t *cost_array, *nodevec; + COST_STRUCT *cost_struc; + int i, j; + int size, TOTAL_GAIN, gain, new_cost, old_cost; + lsGen gen; + node_t *node, *fanout; + char *name, *dummy; + node_function_t node_fun; + + if (ACT_DEBUG) (void) printf("-------entering act_quick_phase--------\n"); + nodevec = network_dfs(network); + size = array_n(nodevec); + + TOTAL_GAIN = 0; + for (i = 0; i < size; i++) { + + node = array_fetch(node_t *, nodevec, i); + if (ACT_DEBUG) node_print(stdout, node); + + /* if node cannot be inverted, get the next node */ + /*-----------------------------------------------*/ + node_fun = node_function(node); + if ((node_fun == NODE_PI) || (node_fun == NODE_PO)) continue; + if (is_anyfo_PO(node)) continue; + + /* invert the node, if possible */ + /*------------------------------*/ + if (!node_invert(node)) { + continue; + } + + /* checking */ + /*----------*/ + assert(st_lookup(cost_table, node_long_name(node), &dummy)); + + /* evaluate the cost of the inverted node, store in cost_array */ + /*-------------------------------------------------------------*/ + gain = 0; + cost_array = array_alloc(COST_STRUCT *, 0); + + old_cost = ((COST_STRUCT *)dummy)->cost; + cost_struc = act_evaluate_map_cost(node, init_param, NIL(network_t), + NIL(array_t), NIL(st_table)); + array_insert_last(COST_STRUCT *, cost_array, cost_struc); + new_cost = cost_struc->cost; + gain = old_cost - new_cost; + + /* evaluate the cost of all the fanouts of the node */ + /*--------------------------------------------------*/ + if (ACT_DEBUG) (void) printf(" num_fo = %d\n", node_num_fanout(node)); + foreach_fanout(node, gen, fanout) { + assert(st_lookup(cost_table, node_long_name(fanout), &dummy)); + old_cost = ((COST_STRUCT *)dummy)->cost; + cost_struc = act_evaluate_map_cost(fanout, init_param, + NIL(network_t), NIL(array_t), NIL(st_table)); + array_insert_last(COST_STRUCT *, cost_array, cost_struc); + new_cost = cost_struc->cost; + gain = gain + old_cost - new_cost; + } + + if (ACT_DEBUG) + (void) printf(" gain from node %s = %d\n", node_long_name(node), gain); + + /* if it is beneficial to invert the node, change the corresponding entries + of the cost_table */ + /*-------------------------------------------------------------------------*/ + if (gain > 0) { + TOTAL_GAIN += gain; + name = node_long_name(node); + assert(st_delete(cost_table, &name, &dummy)); + free_cost_struct((COST_STRUCT *) dummy); + cost_struc = array_fetch(COST_STRUCT *, cost_array, 0); + assert(!st_insert(cost_table, name, (char *)cost_struc)); + j = 1; + foreach_fanout(node, gen, fanout) { + name = node_long_name(fanout); + assert(st_delete(cost_table, &name, &dummy)); + free_cost_struct((COST_STRUCT *) dummy); + cost_struc = array_fetch(COST_STRUCT *, cost_array, j); + j++; + assert(!st_insert(cost_table, name, (char *)cost_struc)); + } + } /* if gain > 0 */ + + /* if it is not beneficial, invert the node back, since earlier + inversion was done in place */ + /*-------------------------------------------------------------*/ + else { + /* if gain <= 0, then do not change the network. Restore it first */ + /*----------------------------------------------------------------*/ + (void) node_invert(node); + + for (j = array_n(cost_array) - 1; j >= 0; j--) { + cost_struc = array_fetch(COST_STRUCT *, cost_array, j); + free_cost_struct((COST_STRUCT *) cost_struc); + } + } /* else */ + + array_free(cost_array); + } /* for i = */ + if (ACT_DEBUG) (void) printf("*******TOTAL_GAIN from act_quick_phase = %d******\n", TOTAL_GAIN); + array_free(nodevec); + /* return network; */ +} + + +void +free_cost_struct(cost_node) + COST_STRUCT *cost_node; +{ + if (cost_node->cost != 0) { + if (ACT_DEBUG) act_check(cost_node->act); + } + my_free_act(cost_node->act); + FREE(cost_node); +} + +/*ARGSUSED*/ +void +free_cost_table(table) + st_table *table; +{ + char *arg; + st_foreach(table, free_table_entry, arg); +} + +/*ARGSUSED */ +static +enum st_retval +free_table_entry(key, value, arg) + char *key, *value, *arg; +{ + (void) free_cost_struct((COST_STRUCT *) value); + FREE(key); + return ST_DELETE; +} + +/*ARGSUSED*/ +void +free_cost_table_without_freeing_key(table) + st_table *table; +{ + char *arg; + st_foreach(table, free_table_entry_without_freeing_key, arg); +} + +/*ARGSUSED */ +enum st_retval +free_table_entry_without_freeing_key(key, value, arg) + char *key, *value, *arg; +{ + (void) free_cost_struct((COST_STRUCT *) value); + return ST_DELETE; +} + + + +/************************************************************************************ + This function returns a node that implements mux function, i.e. + (control' left + control right). +*************************************************************************************/ +node_t * +act_mux_node(control, left, right) + node_t *control, *left, *right; +{ + node_t *not_control, *and1, *and2, *answer, *answer_simpl; + + not_control = node_not(control); + and1 = node_and(not_control, left); + and2 = node_and(control, right); + answer = node_or (and1, and2); + node_free(not_control); + node_free(and1); + node_free(and2); + answer_simpl = node_simplify(answer, NIL (node_t), NODE_SIM_ESPRESSO); + node_free(answer); + return answer_simpl; +} + +/******************************************************************************** + This function returns the function implemented by the Actel basic block. + The naming convention of the inputs is the same as reported in the + Actel paper. +*********************************************************************************/ +static +node_t * +basic_block_node(A0, A1, SA, B0, B1, SB, S0, S1, cost_table) + node_t *A0, *A1, *SA, *B0, *B1, *SB, *S0, *S1; + st_table *cost_table; +{ + node_t *out1, *out2, *or_control, *out, *out_simpl; + + (void) fprintf(BDNET_FILE, "\n INSTANCE \"BASIC_BLOCK\":physical NAME = INST%d;\n", instance_num); + instance_num++; + + print_node_with_string(A0, "A0", cost_table); + print_node_with_string(A1, "A1", cost_table); + print_node_with_string(SA, "SA", cost_table); + print_node_with_string(B0, "B0", cost_table); + print_node_with_string(B1, "B1", cost_table); + print_node_with_string(SB, "SB", cost_table); + print_node_with_string(S0, "S0", cost_table); + print_node_with_string(S1, "S1", cost_table); + + out1 = act_mux_node(SA, A0, A1); + out2 = act_mux_node(SB, B0, B1); + or_control = node_or(S0, S1); + out = act_mux_node(or_control, out1, out2); + node_free(out1); + node_free(out2); + node_free(or_control); + out_simpl = node_simplify(out, NIL (node_t), NODE_SIM_ESPRESSO); + node_free(out); + return out_simpl; +} + +static void +print_output_node_with_string(node, name) + node_t *node; + char *name; + +{ + node_function_t node_fun; + + (void) fprintf(BDNET_FILE, " \"%s\" : \"", name); + node_fun = node_function(node); + switch (node_fun) { + case NODE_0 : (void) fprintf(BDNET_FILE, "GND"); + break; + case NODE_1 : (void) fprintf(BDNET_FILE, "Vdd"); + break; + default : node_print_rhs(BDNET_FILE, node); + } + (void) fprintf(BDNET_FILE, "\";\n"); + + +} + + +static void +print_node_with_string(node, name, cost_table) + node_t *node; + char *name; + st_table *cost_table; + +{ + node_t *fanin; + char *fanin_fn_type; + node_function_t node_fun; + + (void) fprintf(BDNET_FILE, " \"%s\" : \"", name); + + /* hack */ + /*------*/ + node_fun = node_function(node); + switch(node_fun) { + case NODE_0: fanin_fn_type = "GND"; + (void) fprintf(BDNET_FILE, "%s", fanin_fn_type); + break; + case NODE_1: fanin_fn_type = "Vdd"; + (void) fprintf(BDNET_FILE, "%s", fanin_fn_type); + break; + default: + fanin = node_get_fanin(node, 0); + fanin_fn_type = act_get_node_fn_type(fanin, cost_table); + if (fanin_fn_type == NIL (char)) + (void) fprintf(BDNET_FILE, "%s", node_long_name(fanin)); + else (void) fprintf(BDNET_FILE, "%s", fanin_fn_type); + + } + (void) fprintf(BDNET_FILE, "\";\n"); + + +} + +/******************************************************************************** + Given a network and the cost_table, breaks up each node into nodes that can be + realized by one block of STRUCT module. +*********************************************************************************/ +network_t * +act_break_network(network, table) + network_t *network; + st_table *table; +{ + array_t *nodevec; + int size; + int i, i1; + int is_one; /* = 1 if the node has non-zero cost */ + node_t *node; + COST_STRUCT *cost_struct; + char *dummy; + + num_or_patterns = 0; + instance_num = 0; /* keeps track of the instance numbers in the bdnet file */ + nodevec = network_dfs(network); + size = array_n(nodevec); + /* setting up the node_function_info */ + /*-----------------------------------*/ + for (i = 0; i < size; i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + assert(st_lookup(table, node_long_name(node), &dummy)); + cost_struct = (COST_STRUCT *) dummy; + cost_struct->fn_type = act_get_node_fn_type(node, table); + /* fn_type = act_get_node_fn_type(node, table); */ + + /* check - just to be sure */ + /*-------------------------*/ + i1 = (cost_struct->fn_type == NIL (char)); + if (cost_struct->cost != 0) assert (i1); + } + + init_bdnet(network, table); /* print the beginning remarks */ + + for (i = 0; i < size; i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + /* possibly change the node and the bdd (act) there */ + /*--------------------------------------------------*/ + is_one = act_break_node(node, network, table); + if (is_one) { + (void) fprintf(BDNET_FILE, " \"out\" : \"%s\"; \n\n", + node_long_name(node)); + } + } + (void) fprintf(BDNET_FILE, "ENDMODEL;\n"); + + assert(network_check(network)); + array_free(nodevec); + return network; +} +/*--------------------------------------------------------------------------- + Given the node, breaks it up into many nodes, each with cost 1. + Based on the bdd at that node. Network is changed. New nodes may be added + and the functionality of the node may change. Also, breaks the bdd (act) + in the cost_node and puts their appropriate parts in the node. After the + bdd is broken, all the new bdd's are trees (not even leaf dag's). All the + multiple fo points are duplicated. Care has to be taken for all the nodes + so that name at the bdd's are correct. +----------------------------------------------------------------------------*/ +act_break_node(node, network, table) +node_t *node; +network_t *network; +st_table *table; +{ + + int j, size_my_node_array1; + node_t *node1, *node_new, *node_returned; + char *dummy, *node_new_name; + COST_STRUCT *cost_struct, *cost_node; + node_function_t node_fun; + VERTEX_NODE *vertex_name_struct, *vertex_node; + + node_fun = node_function(node); + if ((node_fun == NODE_PI) || (node_fun == NODE_PO)) return 0; + assert(st_lookup(table, node_long_name(node), &dummy)); + cost_struct = (COST_STRUCT *) dummy; + if (cost_struct->cost == 0) return 0; + PRESENT_ACT = cost_struct->act; + /* added Aug 7 '90 */ + /*-----------------*/ + if (ACT_DEBUG) act_check(cost_struct->act); + set_mark_act(PRESENT_ACT); + + my_node_array = array_alloc(node_t *, 0); + vertex_node_array = array_alloc(VERTEX_NODE *, 0); + vertex_name_array = array_alloc(VERTEX_NODE *, 0); + + node_returned = act_get_function(network, node, PRESENT_ACT, table); + node_free(node_returned); + size_my_node_array1 = array_n(my_node_array) - 1; + if (array_n(my_node_array) == 0); + else { + /* add in the network new nodes resulting from breaking the node */ + /*---------------------------------------------------------------*/ + /* with change made Aug 18, 1991, adding the nodes is done earlier.*/ + /*------------------------------------------------------------------*/ + + for (j = 0; j < size_my_node_array1; j++) { + node_new = array_fetch(node_t *, my_node_array, j); + vertex_node = array_fetch(VERTEX_NODE *, vertex_node_array, j); + assert(node_new == vertex_node->node); + /* network_add_node(network, node_new); */ + cost_node = act_allocate_cost_node(node_new, 1, -1.0, -1.0, -1.0, NO, 0.0, 0.0, + vertex_node->vertex); + node_new_name = util_strsav(node_long_name(node_new)); + assert(!st_insert(table, node_new_name, (char *) cost_node)); + /* free the storage associated with the act (bdd) */ + /*------------------------------------------------------*/ + set_mark_act(cost_node->act); + free_nodes_in_act_and_change_multiple_fo(cost_node->act); + + FREE(vertex_node); /* is this the place to free it? */ + } + node1 = array_fetch(node_t *, my_node_array, size_my_node_array1); + node_replace(node, node1); + /* change the cost of node to 1 */ + /*------------------------------*/ + cost_struct->cost = 1; + /* added later */ + /*-------------*/ + vertex_node = array_fetch(VERTEX_NODE *, vertex_node_array, size_my_node_array1); + FREE(vertex_node); + } + /* all the multiple fo vertices had a node in the node field. Free that node */ + /*---------------------------------------------------------------------------*/ + set_mark_act(PRESENT_ACT); + free_nodes_in_act_and_change_multiple_fo(PRESENT_ACT); + + /* associate the vertex with the node - for name: only after all the + corresponding nodes have been inserted into the network */ + /*-----------------------------------------------------------------*/ + for (j = 0; j < array_n(vertex_name_array); j++) { + vertex_name_struct = array_fetch(VERTEX_NODE *, vertex_name_array, j); + vertex_name_struct->vertex->name = node_long_name(vertex_name_struct->node); + FREE(vertex_name_struct); + } + + array_free(my_node_array); + array_free(vertex_name_array); + array_free(vertex_node_array); + return 1; +} + +void +set_mark_act(PRESENT_ACT) + ACT_VERTEX_PTR PRESENT_ACT; +{ + MARK_VALUE = PRESENT_ACT->mark; + if (MARK_VALUE == 1) MARK_COMPLEMENT_VALUE = 0; + else MARK_COMPLEMENT_VALUE = 1; +} + +/************************************************************************************** + Given a node and its corresponding ACT(OACT), breaks the node into nodes, each + new node realizing a function that can be implemented by one basic block. Puts all + these nodes in the network. Original node is changed. +***************************************************************************************/ +static +node_t * +act_get_function(network, node, vertex, table) + network_t *network; + node_t *node; + ACT_VERTEX_PTR vertex; + st_table *table; +{ + + node_t *node1, *node2; + node_t *A0, *A1, *SA, *B0, *B1, *SB, *S0, *S1; + ACT_VERTEX *v_low, *v_high, *v_lowlow, *v_lowhigh, *v_highlow, *v_highhigh; + ACT_VERTEX *v_lowlowlow, *v_lowlowhigh, *v_highlowlow; + VERTEX_NODE *vertex_node; + + /* vertex->node corresponds to the node at the vertex - only for the + multiple_fanout vertex */ + /*-----------------------------------------------------------------*/ + + + if (vertex->value == 0) { + vertex->mark = MARK_COMPLEMENT_VALUE; + return node_constant(0); + } + if (vertex->value == 1) { + vertex->mark = MARK_COMPLEMENT_VALUE; + return node_constant(1); + } + + + if (vertex->mark == MARK_COMPLEMENT_VALUE) { + if (vertex->multiple_fo == 0) { + (void) printf("error: act_get_function()\n"); + exit(1); + } + return vertex->node; + } + + /* added April 4, 1991*/ + /*-------------------*/ + if (!act_is_or_used) { + assert(vertex->pattern_num < 4); + } + + /* even multiple fo vertices will be mapped when they are visited first time */ + /*---------------------------------------------------------------------------*/ + vertex->mark = MARK_COMPLEMENT_VALUE; + + if ((vertex->low->value == 0) && (vertex->high->value == 1)) { + node1 = get_node_literal_of_vertex(vertex, network); + if (vertex->multiple_fo != 0) vertex->node = node1; + return node1; + } + + if (vertex->pattern_num > 3) num_or_patterns++; + + switch(vertex->pattern_num) { + + case 0: + + A0 = node_constant(0); + A1 = act_get_function(network, node, vertex->low, table); + SA = node_constant(1); + + B0 = A0; + B1 = act_get_function(network, node, vertex->high, table); + SB = SA; + + S0 = get_node_literal_of_vertex(vertex, network); + S1 = A0; + + node1 = basic_block_node (A0, A1, SA, B0, B1, SB, S0, S1, table); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + /* need v_low etc because act_change_vertex may change the + pointer of vertex and free_node_if_possible needs + original vertex->low (i.e. v_low) */ + /*-------------------------------------------------------*/ + v_low = vertex->low; + v_high = vertex->high; + act_change_vertex_child(vertex, v_low, LOW, A1); + act_change_vertex_child(vertex, v_high, HIGH, B1); + + free_node_if_possible(A1, v_low); + free_node_if_possible(B1, v_high); + + node_free(A0); + node_free(SA); + node_free(S0); + + node2 = node_literal(node1, 1); + if (vertex != PRESENT_ACT) + print_output_node_with_string(node2, "out"); + if (vertex->multiple_fo != 0) vertex->node = node2; + array_insert_last(node_t *, my_node_array, node1); + + vertex_node = act_allocate_vertex_node_struct(vertex, node1); + array_insert_last(VERTEX_NODE *, vertex_node_array, vertex_node); + + return node2; + + case 1: + + vertex->low->mark = MARK_COMPLEMENT_VALUE; + A0 = act_get_function(network, node, vertex->low->low, table); + A1 = act_get_function(network, node, vertex->low->high, table); + SA = get_node_literal_of_vertex(vertex->low, network); + + B0 = node_constant(0); + B1 = act_get_function(network, node, vertex->high, table); + SB = node_constant(1); + + S0 = get_node_literal_of_vertex(vertex, network); + S1 = B0; + + node1 = basic_block_node (A0, A1, SA, B0, B1, SB, S0, S1, table); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + + v_lowlow = vertex->low->low; + v_lowhigh = vertex->low->high; + v_high = vertex->high; + act_change_vertex_child(vertex->low, v_lowlow, LOW, A0); + act_change_vertex_child(vertex->low, v_lowhigh, HIGH, A1); + act_change_vertex_child(vertex, v_high, HIGH, B1); + + free_node_if_possible(A0, v_lowlow); + free_node_if_possible(A1, v_lowhigh); + free_node_if_possible(B1, v_high); + + node_free(B0); + node_free(SB); + node_free(S0); + node_free(SA); + + node2 = node_literal(node1, 1); + if (vertex != PRESENT_ACT) + print_output_node_with_string(node2, "out"); + if (vertex->multiple_fo != 0) vertex->node = node2; + array_insert_last(node_t *, my_node_array, node1); + + vertex_node = act_allocate_vertex_node_struct(vertex, node1); + array_insert_last(VERTEX_NODE *, vertex_node_array, vertex_node); + + return node2; + + case 2: + vertex->high->mark = MARK_COMPLEMENT_VALUE; + A0 = node_constant(0); + A1 = act_get_function(network, node, vertex->low, table); + SA = node_constant(1); + + B0 = act_get_function(network, node, vertex->high->low, table); + B1 = act_get_function(network, node, vertex->high->high, table); + SB = get_node_literal_of_vertex(vertex->high, network); + + S0 = get_node_literal_of_vertex(vertex, network); + S1 = A0; + + node1 = basic_block_node (A0, A1, SA, B0, B1, SB, S0, S1, table); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + v_highlow = vertex->high->low; + v_highhigh = vertex->high->high; + v_low = vertex->low; + act_change_vertex_child(vertex, v_low, LOW, A1); + act_change_vertex_child(vertex->high, v_highlow, LOW, B0); + act_change_vertex_child(vertex->high, v_highhigh, HIGH, B1); + + + free_node_if_possible(A1, v_low); + free_node_if_possible(B0, v_highlow); + free_node_if_possible(B1, v_highhigh); + + node_free(A0); + node_free(SA); + node_free(S0); + node_free(SB); + + node2 = node_literal(node1, 1); + if (vertex != PRESENT_ACT) + print_output_node_with_string(node2, "out"); + if (vertex->multiple_fo != 0) vertex->node = node2; + array_insert_last(node_t *, my_node_array, node1); + + vertex_node = act_allocate_vertex_node_struct(vertex, node1); + array_insert_last(VERTEX_NODE *, vertex_node_array, vertex_node); + + return node2; + + case 3: + vertex->low->mark = MARK_COMPLEMENT_VALUE; + vertex->high->mark = MARK_COMPLEMENT_VALUE; + + A0 = act_get_function(network, node, vertex->low->low, table); + A1 = act_get_function(network, node, vertex->low->high, table); + SA = get_node_literal_of_vertex(vertex->low, network); + + B0 = act_get_function(network, node, vertex->high->low, table); + B1 = act_get_function(network, node, vertex->high->high, table); + SB = get_node_literal_of_vertex(vertex->high, network); + + S0 = get_node_literal_of_vertex(vertex, network); + S1 = node_constant(0); + + node1 = basic_block_node (A0, A1, SA, B0, B1, SB, S0, S1, table); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + v_lowlow = vertex->low->low; + v_lowhigh = vertex->low->high; + v_highlow = vertex->high->low; + v_highhigh = vertex->high->high; + act_change_vertex_child(vertex->low, v_lowlow, LOW, A0); + act_change_vertex_child(vertex->low, v_lowhigh, HIGH, A1); + act_change_vertex_child(vertex->high, v_highlow, LOW, B0); + act_change_vertex_child(vertex->high, v_highhigh, HIGH, B1); + + + free_node_if_possible(A0, v_lowlow); + free_node_if_possible(A1, v_lowhigh); + free_node_if_possible(B0, v_highlow); + free_node_if_possible(B1, v_highhigh); + + node_free(S1); + node_free(SA); + node_free(SB); + node_free(S0); + + node2 = node_literal(node1, 1); + if (vertex != PRESENT_ACT) + print_output_node_with_string(node2, "out"); + if (vertex->multiple_fo != 0) vertex->node = node2; + array_insert_last(node_t *, my_node_array, node1); + + vertex_node = act_allocate_vertex_node_struct(vertex, node1); + array_insert_last(VERTEX_NODE *, vertex_node_array, vertex_node); + + return node2; + + case 4: + vertex->low->low->mark = MARK_COMPLEMENT_VALUE; + vertex->low->mark = MARK_COMPLEMENT_VALUE; + + A0 = act_get_function(network, node, vertex->low->low->low, table); + A1 = act_get_function(network, node, vertex->low->low->high, table); + SA = get_node_literal_of_vertex(vertex->low->low, network); + + B0 = node_constant(0); + B1 = act_get_function(network, node, vertex->high, table); + SB = node_constant(1); + + S0 = get_node_literal_of_vertex(vertex, network); + S1 = get_node_literal_of_vertex(vertex->low, network); + + node1 = basic_block_node (A0, A1, SA, B0, B1, SB, S0, S1, table); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + v_lowlowlow = vertex->low->low->low; + v_lowlowhigh = vertex->low->low->high; + v_high = vertex->high; + act_change_vertex_child(vertex->low->low, v_lowlowlow, LOW, A0); + act_change_vertex_child(vertex->low->low, v_lowlowhigh, HIGH, A1); + act_change_vertex_child(vertex, v_high, HIGH, B1); + act_change_vertex_child(vertex->low, v_high, HIGH, B1); + + free_node_if_possible(A0, v_lowlowlow); + free_node_if_possible(A1, v_lowlowhigh); + free_node_if_possible(B1, v_high); + + node_free(SA); + node_free(B0); + node_free(SB); + node_free(S0); + node_free(S1); + + node2 = node_literal(node1, 1); + if (vertex != PRESENT_ACT) + print_output_node_with_string(node2, "out"); + if (vertex->multiple_fo != 0) vertex->node = node2; + array_insert_last(node_t *, my_node_array, node1); + + vertex_node = act_allocate_vertex_node_struct(vertex, node1); + array_insert_last(VERTEX_NODE *, vertex_node_array, vertex_node); + + return node2; + + case 5: + vertex->high->mark = MARK_COMPLEMENT_VALUE; + vertex->high->low->mark = MARK_COMPLEMENT_VALUE; + + A0 = node_constant(0); + A1 = act_get_function(network, node, vertex->high->low->low, table); + SA = get_node_literal_of_vertex(vertex, network); + + B0 = A0; + B1 = act_get_function(network, node, vertex->high->high, table); + SB = SA; + + S0 = get_node_literal_of_vertex(vertex->high, network); + S1 = get_node_literal_of_vertex(vertex->high->low, network); + + node1 = basic_block_node (A0, A1, SA, B0, B1, SB, S0, S1, table); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + v_highlowlow = vertex->high->low->low; + v_highhigh = vertex->high->high; + act_change_vertex_child(vertex->high->low, v_highlowlow, LOW, A1); + act_change_vertex_child(vertex->high, v_highhigh, HIGH, B1); + act_change_vertex_child(vertex->high->low, v_highhigh, HIGH, B1); + act_change_vertex_child(vertex, vertex->low, LOW, NIL (node_t)); + + free_node_if_possible(A1, v_highlowlow); + free_node_if_possible(B1, v_highhigh); + + node_free(A0); + node_free(SA); + node_free(S0); + node_free(S1); + + node2 = node_literal(node1, 1); + if (vertex != PRESENT_ACT) + print_output_node_with_string(node2, "out"); + if (vertex->multiple_fo != 0) vertex->node = node2; + array_insert_last(node_t *, my_node_array, node1); + + vertex_node = act_allocate_vertex_node_struct(vertex, node1); + array_insert_last(VERTEX_NODE *, vertex_node_array, vertex_node); + + return node2; + + case 6: + + vertex->high->mark = MARK_COMPLEMENT_VALUE; + vertex->high->low->mark = MARK_COMPLEMENT_VALUE; + + A0 = node_constant(0); + A1 = node_constant(1); + SA = A1; + + B0 = A1; + B1 = A0; + SB = get_node_literal_of_vertex(vertex, network); + + S0 = get_node_literal_of_vertex(vertex->high, network); + S1 = get_node_literal_of_vertex(vertex->high->low, network); + + node1 = basic_block_node (A0, A1, SA, B0, B1, SB, S0, S1, table); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + v_highhigh = vertex->high->high; + act_change_vertex_child(vertex, vertex->low, LOW, NIL(node_t)); + act_change_vertex_child(vertex->high->low, vertex->high->low->low, LOW, NIL(node_t)); + act_change_vertex_child(vertex->high, v_highhigh, HIGH, NIL(node_t)); + act_change_vertex_child(vertex->high->low, v_highhigh, HIGH, NIL(node_t)); + + node_free(A0); + node_free(A1); + node_free(SB); + node_free(S0); + node_free(S1); + + node2 = node_literal(node1, 1); + if (vertex != PRESENT_ACT) + print_output_node_with_string(node2, "out"); + if (vertex->multiple_fo != 0) vertex->node = node2; + array_insert_last(node_t *, my_node_array, node1); + + vertex_node = act_allocate_vertex_node_struct(vertex, node1); + array_insert_last(VERTEX_NODE *, vertex_node_array, vertex_node); + + return node2; + + case 7: + vertex->low->mark = MARK_COMPLEMENT_VALUE; + vertex->low->low->mark = MARK_COMPLEMENT_VALUE; + + A0 = act_get_function(network, node, vertex->low->low->low, table); + A1 = node_constant(0); + SA = get_node_literal_of_vertex(vertex, network); + + B0 = act_get_function(network, node, vertex->low->high, table); + B1 = A1; + SB = SA; + + S0 = get_node_literal_of_vertex(vertex->low, network); + S1 = get_node_literal_of_vertex(vertex->low->low, network); + + node1 = basic_block_node (A0, A1, SA, B0, B1, SB, S0, S1, table); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + v_lowlowlow = vertex->low->low->low; + v_lowhigh = vertex->low->high; + act_change_vertex_child(vertex->low->low, v_lowlowlow, LOW, A0); + act_change_vertex_child(vertex->low->low, v_lowhigh, HIGH, B0); + act_change_vertex_child(vertex->low, v_lowhigh, HIGH, B0); + act_change_vertex_child(vertex, vertex->high, HIGH, NIL(node_t)); + + free_node_if_possible(A0, v_lowlowlow); + free_node_if_possible(B0, v_lowhigh); + + node_free(A1); + node_free(SA); + node_free(S0); + node_free(S1); + + node2 = node_literal(node1, 1); + if (vertex != PRESENT_ACT) + print_output_node_with_string(node2, "out"); + if (vertex->multiple_fo != 0) vertex->node = node2; + array_insert_last(node_t *, my_node_array, node1); + + vertex_node = act_allocate_vertex_node_struct(vertex, node1); + array_insert_last(VERTEX_NODE *, vertex_node_array, vertex_node); + + return node2; + default: + (void) printf(" act_get_function(): unknown pattern_num %d found\n", vertex->pattern_num); + exit(1); + } /* switch */ + return NIL (node_t); +} + +/*------------------------------------------------------------------- + Given a bdd vertex, returns the literal of the node of the network + that corresponds to it. Gets the node by name. + COMMENT: differs from get_node_of_vertex(). +---------------------------------------------------------------------*/ +node_t * +get_node_literal_of_vertex(vertex, network) + ACT_VERTEX_PTR vertex; + network_t *network; +{ + node_t *node; + + node = network_find_node(network, vertex->name); + if (node == NIL (node_t)) { + (void) printf(" get_node_literal_of_network(): node is NULL\n"); + exit(1); + } + return (node_literal(node, 1)); +} + +/*********************************************************************************** + If the vertex is just an input, then the node cannot be freed. If the vertex is + a multiple_fo point, then also it cannot be freed. This is because these nodes + are needed in the network. +************************************************************************************/ +void +free_node_if_possible(node, vertex) + node_t *node; + ACT_VERTEX_PTR vertex; +{ + node_function_t node_fn; + + node_fn = node_function(node); + if ((node_fn == NODE_0) || (node_fn == NODE_1)){ + node_free(node); + return; + } + /* should be after the node_fn check, because 0, 1 vertices + do not store anything */ + /*---------------------------------------------------------*/ + if (vertex->multiple_fo != 0) return; + node_free(node); +} + +void +act_act_free(node) + node_t *node; +{ + void local_actFree(); + + ACT_SET(node)->LOCAL_ACT->act->root = NIL (ACT_VERTEX); + local_actFree(node); + +} + +/*----------------------------------------------------------- + Makes the multiple_fo field of all vertices 0. + Also frees the node associated with the non-terminal + multiple fanout vertices. +-------------------------------------------------------------*/ +static void +free_nodes_in_act_and_change_multiple_fo(vertex) + ACT_VERTEX_PTR vertex; +{ + if (vertex->mark == MARK_COMPLEMENT_VALUE) return; + vertex->mark = MARK_COMPLEMENT_VALUE; + if (vertex->value != 4) { + vertex->multiple_fo = 0; + return; + } + if (vertex->multiple_fo != 0) { + node_free(vertex->node); + vertex->multiple_fo = 0; + } + free_nodes_in_act_and_change_multiple_fo(vertex->low); + free_nodes_in_act_and_change_multiple_fo(vertex->high); + +} + +/********************************************************************* + writes input and output of the network in the bdnet file. +**********************************************************************/ + +static void +init_bdnet(network, table) +network_t *network; +st_table *table; + +{ + + lsGen genpi, genpo; + node_t *pi, *po, *po_fanin; + char *pi_name, *po_name, *po_fanin_fn_type; + + (void) fprintf(BDNET_FILE, "MODEL \"%s\";\n\n", network_name(network)); + + (void) fprintf(BDNET_FILE, "TECHNOLOGY scmos;\n"); + (void) fprintf(BDNET_FILE, "VIEWTYPE SYMBOLIC;\n"); + (void) fprintf(BDNET_FILE, "EDITSTYLE SYMBOLIC;\n\n"); + /* writing inputs */ + /*----------------*/ + foreach_primary_input(network, genpi, pi) { + pi_name = node_long_name(pi); + (void) fprintf(BDNET_FILE, "INPUT \t\"%s\" : \"%s\";\n", + pi_name, pi_name); + } + (void) fprintf(BDNET_FILE, "\n"); + + /* writing outputs */ + /*-----------------*/ + foreach_primary_output(network, genpo, po) { + po_name = node_long_name(po); + po_fanin = node_get_fanin(po, 0); + + /* hack for bdnet */ + /*----------------*/ + /* if po_fanin has 0 cost, then print the transitive input (or Vdd, GND) + that influences it */ + /*---------------------------------------------------------------------*/ + po_fanin_fn_type = act_get_node_fn_type(po_fanin, table); + if (po_fanin_fn_type == NIL (char)) + (void) fprintf(BDNET_FILE, "OUTPUT \t\"%s\" : \"%s\";\n", + po_name, node_long_name(po_fanin) ); + else + (void) fprintf(BDNET_FILE, "OUTPUT \t\"%s\" : \"%s\";\n", + po_name, po_fanin_fn_type); + } + (void) fprintf(BDNET_FILE, "\n"); + +} + + +/*----------------------------------------------------------------- + This is a "hack" for generating bdnet file. If a node has NODE_0 + (NODE_1) function, returns "GND" (Vdd"). If it is a NODE_BUF + (single input), then returns the name of the farthest + transitive fanin node which is either NODE_0, NODE_1, + or NODE_BUF, appropriately. It may happen that the cost of the + node is 0, but it is not of type NODE_0 or NODE_1 (it may be of + the type a + a'), then also GND or Vdd may be returned. Actually + it will never be of type GND. +------------------------------------------------------------------*/ +static char * +act_get_node_fn_type(node, cost_table) +node_t *node; +st_table *cost_table; +{ + node_t *fanin; + char *dummy; + COST_STRUCT *cost_node; + node_function_t node_fun; + ACT_VERTEX_PTR vertex; + + node_fun = node_function(node); + switch(node_fun) { + case NODE_0 : return "GND"; + case NODE_1 : return "Vdd"; + case NODE_BUF: + fanin = node_get_fanin(node, 0); + if (fanin->type == PRIMARY_INPUT) return node_long_name(fanin); + assert(st_lookup(cost_table, node_long_name(fanin), &dummy)); + cost_node = (COST_STRUCT *) dummy; + if (cost_node->fn_type == NIL (char)) return node_long_name(fanin); + else return cost_node->fn_type; + default: + if (node->type != INTERNAL) return NIL (char); /* may not be needed */ + /* change made on Aug. 18, 1991 when pointed out by Andre' */ + /*---------------------------------------------------------*/ + if (!st_lookup(cost_table, node_long_name(node), &dummy)) return NIL (char); + cost_node = (COST_STRUCT *) dummy; + if (cost_node->cost == 0) { + vertex = cost_node->act; + assert(vertex != NIL (ACT_VERTEX)); + assert(vertex->value < 2); + if (vertex->value == 0) return "GND"; + return "Vdd"; + } + return NIL (char); + } +} + + +network_t * +act_network_remap(network, cost_table) + network_t *network; + st_table *cost_table; /* original */ +{ + array_t *nodevec; + node_t *node; + int i, size; + int gain; + int FLAG_DECOMP = 0; + int HEURISTIC_NUM = 0; /* does not matter */ + + gain = 0; + nodevec = network_dfs(network); + size = array_n(nodevec); + for (i = 0; i < size; i++) { + node = array_fetch(node_t *, nodevec, i); + gain += act_node_remap(network, node, cost_table, FLAG_DECOMP, HEURISTIC_NUM); + } + if (ACT_STATISTICS) (void) printf("total gain after remapping = %d\n", gain); + array_free(nodevec); + return network; +} + + +/********************************************************************************************** + Calls the same procedures for a node to obtain a good mapping of the node. + It accepts the solution if it is better than the earlier one. + Can be called either for the DECOMPOSITION or for simply remapping (LAST_GASP). + FLAG_DECOMP is 1 if the routine is called from decomp_big_nodes, is 0 if it is + called from act_network_remap. +**********************************************************************************************/ +int +act_node_remap(network, node, cost_table, FLAG_DECOMP, HEURISTIC_NUM_ORIG) + network_t *network; + node_t *node; + st_table *cost_table; /* original */ + int FLAG_DECOMP, HEURISTIC_NUM_ORIG; +{ + + node_t *dup_node, *node1, *node1_dup; + network_t *network1; + int cost_node_original; + int cost_network1; + st_table *node_cost_table1, *table1; + int num_cubes, gain, num_nodes2, i; + act_init_param_t *init_param; + node_function_t node_fun; + array_t *nodevec1; + char *name, *name1, *dummy; + COST_STRUCT *cost_struct1; + + node_fun = node_function(node); + if ((node_fun == NODE_PI) || (node_fun == NODE_PO)) return 0; + + cost_node_original = cost_of_node (node, cost_table); + if (ACT_DEBUG) + (void) printf("original cost of node %s = %d\n", node_long_name(node), + cost_node_original); + + /* could be made 2, but may be the cost can be made 1 - takes care of f = a + a' */ + /*-------------------------------------------------------------------------------*/ + if (cost_node_original <= 1) return 0; + + /* if the subject-graph for the node is optimal, do not remap */ + /*------------------------------------------------------------*/ + num_cubes = node_num_cube(node); + if ((num_cubes == 1) || + (num_cubes == node_num_literal(node)) + ) return 0; + + dup_node = node_dup(node); + network1 = network_create_from_node(dup_node); + + decomp_good_network(network1); + if ((FLAG_DECOMP == 1) && (network_num_internal(network1) == 1)) { + network_free(network1); + node_free(dup_node); + return 0; + } + if (FLAG_DECOMP == 0) decomp_tech_network(network1, 2, 2); + + init_param = ALLOC(act_init_param_t, 1); + if (FLAG_DECOMP == 0) { + init_param->NUM_ITER = 2; + init_param->GAIN_FACTOR = 0.001; + init_param->FANIN_COLLAPSE = 4; + init_param->DECOMP_FANIN = 4; + init_param->QUICK_PHASE = 1; + init_param->DISJOINT_DECOMP = 0; + init_param->HEURISTIC_NUM = 4; + } + else { + init_param->NUM_ITER = 0; + init_param->GAIN_FACTOR = 0.001; + init_param->FANIN_COLLAPSE = 0; + init_param->DECOMP_FANIN = 0; + init_param->QUICK_PHASE = 0; + init_param->DISJOINT_DECOMP = 0; + init_param->HEURISTIC_NUM = HEURISTIC_NUM_ORIG; + } + init_param->mode = AREA; + init_param->LAST_GASP = 0; + init_param->BREAK = 0; + + node_cost_table1 = st_init_table(strcmp, st_strhash); + network1 = act_map_network(network1, init_param, node_cost_table1); + FREE(init_param); + + cost_network1 = print_network(network1, node_cost_table1, -1); + if (ACT_DEBUG) + (void) printf (" the original cost of node = %d, cost after remapping = %d\n", + cost_node_original, cost_network1); + gain = cost_node_original - cost_network1; + if (gain <= 0) { + free_cost_table(node_cost_table1); + st_free_table(node_cost_table1); + network_free(network1); + node_free(dup_node); + return 0; + } + /* replace the node in the original network by the network1 + better not to call pld_replace_node_by_network, since we + need to re-place the cost_struct also */ + /*----------------------------------------------------------*/ + nodevec1 = network_dfs(network1); + table1 = st_init_table(st_ptrcmp, st_ptrhash); + /* set correspondence between p.i. and ... */ + /*-----------------------------------------*/ + pld_remap_init_corr(table1, network, network1); + num_nodes2 = array_n(nodevec1) - 2; + for (i = 0; i < num_nodes2; i++) { + node1 = array_fetch(node_t *, nodevec1, i); + if (node1->type != INTERNAL) continue; + node1_dup = pld_remap_get_node(node1, table1); + node1_dup->name = NIL (char); /* possibility of leak? */ + node1_dup->short_name = NIL (char); + network_add_node(network, node1_dup); + if (ACT_DEBUG) (void) node_print(sisout, node1_dup); + /* lookup the cost_struct1 for node1 and put it in the + cost_table */ + /*---------------------------------------------------*/ + name1 = util_strsav(node_long_name(node1_dup)); + assert(st_lookup(node_cost_table1, node_long_name(node1), &dummy)); + cost_struct1 = (COST_STRUCT *) dummy; + act_remap_update_act_fields(table1, network1, node1_dup, cost_struct1); + assert(!st_insert(cost_table, name1, (char *) cost_struct1)); + assert(!st_insert(table1, (char *) node1, (char *) node1_dup)); + /* if (ACT_DEBUG) + (void) printf("inserting node %s (%s) in table\n", node_long_name(node1_dup), + node_name(node1_dup)); */ + } + /* the last node in the array in primary output - do not want that */ + /*-----------------------------------------------------------------*/ + node1 = array_fetch(node_t *, nodevec1, num_nodes2); + assert(node1->type == INTERNAL); + node1_dup = pld_remap_get_node(node1, table1); + node_replace(node, node1_dup); + name = node_long_name(node); + name1 = util_strsav(name); + /* delete the entry of the node from the cost_table */ + /*--------------------------------------------------*/ + assert(st_delete(cost_table, &name, &dummy)); + (void) free_cost_struct((COST_STRUCT *)dummy); + FREE(name); + /* look up the cost of node1, put it in the cost_table */ + /*-----------------------------------------------------*/ + assert(st_lookup(node_cost_table1, node_long_name(node1), &dummy)); + cost_struct1 = (COST_STRUCT *) dummy; + act_remap_update_act_fields(table1, network1, node, cost_struct1); + assert(!st_insert(cost_table, name1, (char *) cost_struct1)); + assert(!st_insert(table1, (char *) node1, (char *) node)); + /* if (ACT_DEBUG) { + (void) printf("inserting node %s (%s) in table\n", node_long_name(node), + node_name(node)); + (void) node_print(sisout, node); + } */ + st_free_table(node_cost_table1); + st_free_table(table1); + array_free(nodevec1); + network_free(network1); + node_free(dup_node); + return gain; + +} + + +/************************************************************************************************ + Given a node and its subject_graph (ACT, or OACT), snap at multiple fanout points and maps each + tree using the pattern-set. The mapping is for a combination of delay and area depending upon + value of mode. init_param->mode = 1 (DELAY) means mapping is done only for delay. init_param->mode -> 0 : for AREA. + However this routine is not called for init_param->mode = 0 (AREA) (instead make_tree_and_map() is used.) + REMARK: The arrival time at the output of the node takes into account the fanout of the node. +*************************************************************************************************/ + + +COST_STRUCT * +make_tree_and_map_delay(node, act_of_node, network, delay_values, cost_table, mode) + node_t *node; + ACT_VERTEX_PTR act_of_node; + network_t *network; + array_t *delay_values; + st_table *cost_table; + float mode; + +{ + int num_acts; + int i; + int num_mux_struct; + int TOTAL_MUX_STRUCT; /* cost of the network */ + /* int pattern_type; */ /* how many patterns which use OR gate */ + COST_STRUCT *cost_node; + ACT_VERTEX_PTR act; + double correction; + + /* pattern_type = 0; */ + TOTAL_MUX_STRUCT = 0; + cost_node = ALLOC(COST_STRUCT, 1); + + act_init_multiple_fo_array(act_of_node); /* insert the root */ + act_initialize_act_delay(act_of_node); + make_multiple_fo_array_delay(act_of_node, multiple_fo_array); + /* if (ACT_DEBUG) my_traverse_act(act_of_node); + if (ACT_DEBUG) print_multiple_fo_array(multiple_fo_array); */ + num_acts = array_n(multiple_fo_array); + /* changed the following traversal , now bottom-up */ + /*--------------------------------------------------*/ + for (i = num_acts - 1; i >= 0; i--) { + act = array_fetch(ACT_VERTEX_PTR, multiple_fo_array, i); + PRESENT_ACT = act; + num_mux_struct = map_act_delay(act, network, delay_values, cost_table, mode); + TOTAL_MUX_STRUCT += num_mux_struct; + } + if (ACT_DEBUG) + (void) printf("number of total mux_structures used for the node %s = %d, arrival_time = %f\n", + node_long_name(node), TOTAL_MUX_STRUCT, act_of_node->arrival_time); + + + array_free(multiple_fo_array); + cost_node->cost = TOTAL_MUX_STRUCT; + /* this arrival time was computed with the assumption of one fanout. + Now correct it */ + /*-----------------------------------------------------------------*/ + correction = act_get_node_delay_correction(node, delay_values, 1, node_num_fanout(node)); + cost_node->arrival_time = act_of_node->arrival_time + correction; + act_invalidate_cost_and_arrival_time(cost_node); + cost_node->cost_and_arrival_time = act_cost_delay(cost_node, mode); + cost_node->node = node; + cost_node->act = act_of_node; + /* cost_node->pattern_type = pattern_type; */ + return cost_node; +} + +/*------------------------------------------------------------------- + Given a bdd vertex, maps it in a non-area init_param->mode. +--------------------------------------------------------------------*/ +static +int map_act_delay(vertex, network, delay_values, cost_table, mode) +ACT_VERTEX_PTR vertex; +network_t *network; +array_t *delay_values; +st_table *cost_table; +float mode; + +{ + int TOTAL_PATTERNS = 12; /* right now using just 8 */ + int pat_num; + int cost[12]; /* for each of the 12 patterns, this is the area cost in terms of STRUCT blocks */ + double delay[12]; /* same as cost, but now for delay */ + int vlow_cost, vhigh_cost, vlowlow_cost, vlowhigh_cost, vhighlow_cost, vhighhigh_cost; + double vlow_delay, vhigh_delay, vlowlow_delay, vlowhigh_delay, vhighlow_delay, vhighhigh_delay; + int best_pat_num; + node_t *node; /* corresponding to a vertex of bdd (act), it gives the node */ + node_t *nlow, *nhigh, *nlowlow, *nhighlow; + double prop_delay, max_input_arrival, max_input_int_arrival; + + if (vertex->value != 4) { + vertex->mapped = 1; + vertex->arrival_time = (double) 0.0; + vertex->cost = 0; + return 0; + } + + /* if multiple fanout (but not the root of the present multiple_fo vertex) + return 0, but do not set any value, as this vertex would be/ or was + visited earlier as a root. Basically zero is not its true cost. So do not set + vertex->mapped = 1 also */ + /*--------------------------------------------------------------------------*/ + if ((vertex->multiple_fo != 0) && (vertex != PRESENT_ACT)) + return 0; /* because area not to be counted */ + + /* if cost already computed for a vertex in the tree rooted by "PRESENT_ACT", don't compute again */ + /*------------------------------------------------------------------------------------------------*/ + if (vertex->mapped) + return vertex->cost; + + vertex->mapped = 1; + + /* if a simple input, cost = 0 */ + /*-----------------------------*/ + if ((vertex->low->value == 0) && (vertex->high->value == 1)) { + node = get_node_of_vertex(vertex, network); + vertex->arrival_time = act_get_arrival_time(node, cost_table); + vertex->cost = 0; + return 0; + } + + + /* initialize cost vector to a very high value for all the patterns*/ + /*-----------------------------------------------------------------*/ + for (pat_num = 0; pat_num < TOTAL_PATTERNS; pat_num++) { + cost[pat_num] = MAXINT; + delay[pat_num] = (double) MAXINT; + } + + /***********recursively calculate relevant costs *************/ + + if (vertex->low->multiple_fo != 0) { + vlow_cost = 0; + vlow_delay = vertex->low->arrival_time; + } + else { + (void) map_act_delay(vertex->low, network, delay_values, cost_table, mode); + vlow_cost = vertex->low->cost; + vlow_delay = vertex->low->arrival_time; + } + + if (vertex->high->multiple_fo != 0) { + vhigh_cost = 0; + vhigh_delay = vertex->high->arrival_time; + } + else { + (void) map_act_delay(vertex->high, network, delay_values, cost_table, + mode); + vhigh_cost = vertex->high->cost; + vhigh_delay = vertex->high->arrival_time; + } + + if (vertex->low->value == 4) { + if (vertex->low->multiple_fo != 0) { + vlowlow_cost = vlowhigh_cost = MAXINT; + vlowlow_delay = vlowhigh_delay = (double) MAXINT; /* because do not want to change tree-mapping */ + } + else { + if (vertex->low->low->multiple_fo != 0) vlowlow_cost = 0; + else vlowlow_cost = map_act_delay(vertex->low->low, network, delay_values, + cost_table, mode); + vlowlow_delay = vertex->low->low->arrival_time; /* use the delay value previously set */ + if (vertex->low->high->multiple_fo != 0) vlowhigh_cost = 0; + else vlowhigh_cost = map_act_delay(vertex->low->high, network, delay_values, + cost_table, mode); + vlowhigh_delay = vertex->low->high->arrival_time; + } + } /* if */ + + if (vertex->high->value == 4) { + if (vertex->high->multiple_fo != 0) { + vhighlow_cost = vhighhigh_cost = MAXINT; + vhighlow_delay = vhighhigh_delay = (double) MAXINT; + } + else { + if (vertex->high->low->multiple_fo != 0) vhighlow_cost = 0; + else vhighlow_cost = map_act_delay(vertex->high->low, network, delay_values, + cost_table, mode); + vhighlow_delay = vertex->high->low->arrival_time; + if (vertex->high->high->multiple_fo != 0) vhighhigh_cost = 0; + else vhighhigh_cost = map_act_delay(vertex->high->high, network, delay_values, + cost_table, mode); + vhighhigh_delay = vertex->high->high->arrival_time; + } + } + + node = get_node_of_vertex(vertex, network); + if (vertex->low->value == 4) nlow = get_node_of_vertex(vertex->low, network); + if (vertex->high->value == 4) nhigh = get_node_of_vertex(vertex->high, network); + prop_delay = act_get_bddfanout_delay(vertex, delay_values, cost_table); + + /**********enumerate possible cases************************/ + + + /* l.c. (left child) + r.c.(right child) + 1 */ + /*-------------------------------------------*/ + + cost[0] = vlow_cost + vhigh_cost + 1; + max_input_arrival = my_max(my_max (vlow_delay, vhigh_delay), act_get_arrival_time(node, cost_table)); + delay[0] = max_input_arrival + prop_delay; + + if (vertex->low->value == 4) { + cost[1] = vlowlow_cost + vlowhigh_cost + vhigh_cost + 1; + max_input_int_arrival = my_max (my_max (vlowlow_delay, vlowhigh_delay), vhigh_delay); + max_input_arrival = my_max (my_max (act_get_arrival_time(node, cost_table), act_get_arrival_time(nlow, cost_table)), + max_input_int_arrival); + delay[1] = max_input_arrival + prop_delay; + } + if (vertex->high->value == 4) { + cost[2] = vlow_cost + vhighlow_cost + vhighhigh_cost + 1; + max_input_int_arrival = my_max (my_max (vhighlow_delay, vhighhigh_delay), vlow_delay); + max_input_arrival = my_max (my_max (act_get_arrival_time(node, cost_table), act_get_arrival_time(nhigh, cost_table)), + max_input_int_arrival); + delay[2] = max_input_arrival + prop_delay; + } + + if ((vertex->low->value == 4) && (vertex->high->value == 4)) { + cost[3] = vlowlow_cost + vlowhigh_cost + + vhighlow_cost + vhighhigh_cost + 1; + max_input_int_arrival = my_max (my_max (vlowlow_delay, vlowhigh_delay), + my_max(vhighlow_delay, vhighhigh_delay)); + max_input_arrival = my_max (my_max (act_get_arrival_time(node, cost_table), act_get_arrival_time(nlow, cost_table)), + my_max(act_get_arrival_time(nhigh, cost_table), max_input_int_arrival)); + delay[3] = max_input_arrival + prop_delay; + } + + /* OR patterns - pretty involved -> for more explanation, see doc. */ + /*-----------------------------------------------------------------*/ + + if ((OR_pattern(vertex)) + && (vertex->low->low->multiple_fo == 0) + && (vertex->low->low->value == 4) + ) { + /* important to do this way, otherwise if low->low->low multiple + fo vertex, may get a wrong answer. */ + nlowlow = get_node_of_vertex(vertex->low->low, network); + cost[4] = map_act_delay(vertex->low->low->low, network, delay_values, + cost_table, mode) + + map_act_delay(vertex->low->low->high, network, delay_values, + cost_table, mode) + + 1; /* vertex->high is a multiple-parent vertex */ + max_input_int_arrival = my_max (my_max (vertex->low->low->low->arrival_time, vertex->low->low->high->arrival_time), + vhigh_delay); + max_input_arrival = my_max (my_max (act_get_arrival_time(node, cost_table), act_get_arrival_time(nlow, cost_table)), + my_max(act_get_arrival_time(nlowlow, cost_table), max_input_int_arrival)); + delay[4] = max_input_arrival + prop_delay; + } + + if ((OR_pattern(vertex->high)) && (vertex->high->multiple_fo == 0)) { + if (vertex->low->value == 0) { + nhighlow = get_node_of_vertex(vertex->high->low, network); + cost[5] = map_act_delay(vertex->high->high, network, delay_values, + cost_table, mode) + + map_act_delay(vertex->high->low->low, network, delay_values, cost_table, + mode) + + 1; + max_input_int_arrival = my_max (vertex->high->high->arrival_time, vertex->high->low->low->arrival_time); + max_input_arrival = my_max (my_max (act_get_arrival_time(node, cost_table), act_get_arrival_time(nhigh, cost_table)), + my_max(act_get_arrival_time(nhighlow, cost_table), max_input_int_arrival)); + delay[5] = max_input_arrival + prop_delay; + } + else { + if ((vertex->low->value == 1) && (vertex->high->high->value == 0) + && (vertex->high->low->low->value == 1)) { + nhighlow = get_node_of_vertex(vertex->high->low, network); + cost[6] = 1; + max_input_arrival = my_max (my_max (act_get_arrival_time(node, cost_table), act_get_arrival_time(nhigh, cost_table)), + act_get_arrival_time(nhighlow, cost_table)); + delay[6] = max_input_arrival + prop_delay; + } + } + } + + if ((OR_pattern(vertex->low)) && (vertex->low->multiple_fo == 0)) { + if (vertex->high->value == 0) { + nlowlow = get_node_of_vertex(vertex->low->low, network); + cost[7] = map_act_delay(vertex->low->high, network, delay_values, cost_table, + mode) + + map_act_delay(vertex->low->low->low, network, delay_values, cost_table, mode) + + 1; + max_input_int_arrival = my_max (vertex->low->high->arrival_time, vertex->low->low->low->arrival_time); + max_input_arrival = my_max (my_max (act_get_arrival_time(node, cost_table), act_get_arrival_time(nlow, cost_table)), + my_max(act_get_arrival_time(nlowlow, cost_table), max_input_int_arrival)); + delay[7] = max_input_arrival + prop_delay; + + } + } + + /************find minimum cost************************/ + best_pat_num = minimum_costdelay_index(cost, delay, TOTAL_PATTERNS, mode); + vertex->cost = cost[best_pat_num]; + vertex->arrival_time = delay[best_pat_num]; + vertex->pattern_num = best_pat_num; + /* if (ACT_DEBUG) + (void) printf("vertex id = %d, index = %d, cost = %d, name = %s, arrival_time = %f, pattern_num = %d\n", + vertex->id, vertex->index, vertex->cost, vertex->name, vertex->arrival_time, vertex->pattern_num); */ + return vertex->cost; +} + +static +int minimum_costdelay_index(cost, delay, num_entries, mode) +int cost[]; +double delay[]; +int num_entries; +float mode; +{ + + int i; + int min_index = 0; + double *cost_and_delay; + + /* generate a cost_and_delay array that takes into account cost and delay */ + /*------------------------------------------------------------------------*/ + cost_and_delay = ALLOC(double, num_entries); + for (i = 0; i < num_entries; i++) { + cost_and_delay[i] = ((double)(1.00 - mode)) * (double) cost[i] + + ((double) mode) * delay[i]; + } + + for (i = 1; i < num_entries; i++) { + if (cost_and_delay[i] < cost_and_delay[min_index]) min_index = i; + } + + FREE(cost_and_delay); + return min_index; +} + +/*------------------------------------------------------------------- + Given a bdd vertex, returns the node of the network + that corresponds to it. Gets the node by name. +---------------------------------------------------------------------*/ +static +node_t * +get_node_of_vertex(vertex, network) + ACT_VERTEX_PTR vertex; + network_t *network; +{ + node_t *node; + + node = network_find_node(network, vertex->name); + if (node == NIL (node_t)) { + (void) printf(" get_node_literal_of_network(): node is NULL\n"); + exit(1); + } + return node; +} + + +array_t *act_get_corr_fanin_nodes(node, order_list1) + node_t *node; + array_t *order_list1; +{ + network_t *network; + int i; + array_t *order_list; + node_t *n1, *n; + + network = node->network; + order_list = array_alloc(node_t *, 0); + for (i = 0; i < array_n(order_list1); i++) { + n1 = array_fetch(node_t *, order_list1, i); + assert(n1->type == PRIMARY_INPUT); + n = network_find_node(network, node_long_name(n1)); + assert(n != NIL (node_t)); + array_insert_last(node_t *, order_list, n); + } + assert(array_n(order_list) == node_num_fanin(node)); + return order_list; +} + +/* not implemented yet */ +/*ARGSUSED*/ +act_delay_iterative_improvement(network, cost_table, delay_values, init_param) + network_t *network; + st_table *cost_table; + array_t *delay_values; + act_init_param_t *init_param; +{ +} diff --git a/sis/pld/act_misc.c b/sis/pld/act_misc.c new file mode 100644 index 0000000..d3039d5 --- /dev/null +++ b/sis/pld/act_misc.c @@ -0,0 +1,150 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_misc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +/* changed July 29, 1991 - to make lint happy */ + +#include "sis.h" +#include "pld_int.h" + +/* hash table for partial results*/ +st_table *misc_table; + +/*extern ACT_VERTEX_PTR p_dagCopy(); +extern ACT_VERTEX_PTR p_dagComplement(); +extern void applyCreate(); +extern void actDestroy(); +extern void actCreate4Set();*/ + +void +p_act_node_free(node) +node_t *node; +{ + p_actDestroy(&ACT_SET(node)->GLOBAL_ACT, 0); +} + +ACT_VERTEX_PTR +p_rootCopy(u) +ACT_VERTEX_PTR u; +{ + ACT_VERTEX_PTR v, p_dagCopy(); + + misc_table = st_init_table(st_ptrcmp, st_ptrhash); + v = p_dagCopy(u); + st_free_table(misc_table); + return(v); +} + +ACT_VERTEX_PTR +p_dagCopy(u) +ACT_VERTEX_PTR u; +{ + char *dummy; + ACT_VERTEX_PTR v; + + if(st_lookup(misc_table, (char *)u, &dummy)){ + return((ACT_VERTEX_PTR)dummy); + } + v = ALLOC(ACT_VERTEX, 1); + v->id = u->id; + v->value = u->value; + v->index = u->index; + v->index_size = u->index_size; + v->mark = u->mark; + if(u->value == NO_VALUE){ + v->low = p_dagCopy(u->low); + v->high = p_dagCopy(u->high); + } else { + v->low = NIL (act_t); + v->high = NIL (act_t); + } + + (void) st_insert(misc_table, (char *)u, (char *)v); + return(v); +} + +ACT_VERTEX_PTR +p_rootComplement(u) +ACT_VERTEX_PTR u; +{ + ACT_VERTEX_PTR v, p_dagComplement(); + + misc_table = st_init_table(st_ptrcmp, st_ptrhash); + v = p_dagComplement(u); + st_free_table(misc_table); + return(v); +} + +ACT_VERTEX_PTR +p_dagComplement(u) +ACT_VERTEX_PTR u; +{ + char *dummy; + ACT_VERTEX_PTR v; + + if(st_lookup(misc_table, (char *)u, &dummy)){ + return((ACT_VERTEX_PTR)dummy); + } + v = ALLOC(ACT_VERTEX, 1); + v->id = u->id; + switch (u->value){ + case NO_VALUE : v->value = NO_VALUE; break; + case 1 : v->value = 0; break; + case 0 : v->value = 1; break; + } + v->index = u->index; + v->index_size = u->index_size; + v->mark = u->mark; + if(u->value == NO_VALUE){ + v->low = p_dagComplement(u->low); + v->high = p_dagComplement(u->high); + } else { + v->low = NIL (act_t); + v->high = NIL (act_t); + } + (void) st_insert(misc_table, (char *)u, (char *)v); + return(v); +} + +ACT_VERTEX_PTR +p_act_construct(node, order_list, locality) +node_t *node; +array_t *order_list; +int locality; +{ + array_t *node_vec; + + if(!locality){ + p_applyCreate(node, order_list); + return (ACT_SET(node)->GLOBAL_ACT->act->root); + } else { + node_vec = array_alloc(node_t *, 0); + array_insert_last(node_t *, node_vec, node); + /* changed July 29, 1991 - to make lint happy */ + /* (void)p_actCreate4Set(node_vec, order_list, locality, + FANIN); */ + (void)p_actCreate4Set(node_vec, order_list, locality, + FANIN, (float) 0.0, NIL(network_t), NIL(array_t), NIL(st_table)); + array_free(node_vec); + return (ACT_SET(node)->LOCAL_ACT->act->root); + } +} + + +int +p_act_size(act) +ACT_VERTEX_PTR act; +{ + switch(act->id){ + case 0: + return act->value; + default: + return (act->id + 1); + } +} + diff --git a/sis/pld/act_order.c b/sis/pld/act_order.c new file mode 100644 index 0000000..2cc8d62 --- /dev/null +++ b/sis/pld/act_order.c @@ -0,0 +1,416 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_order.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/* for order_nodes and p_alap_order_nodes */ +typedef struct fanin_record_defn{ + int max_level; + node_t *node; +} fanin_record_t ; + +extern void p_rootAdd(); +extern void p_levelAdd(); +extern int p_maxAdd(); +extern void p_recOrder(); +extern enum st_retval p_cleanFRTable(); +extern enum st_retval p_cleanRTable(); +extern void p_recFree(); +extern int p_fanin_record_sort(); +extern enum st_retval p_addPI(); + +array_t * +p_alap_order_nodes(node_vec) +array_t *node_vec; +{ + node_t *dummy_node, *t_node, *tt_node, *root, *node; + int i; + char *dummy; + st_table *root_table, *level_table; + array_t *order_list, *pi_list; + fanin_record_t *pi_record; + + dummy_node = node_constant(0); + for(i = 0; i<array_n(node_vec); i++){ + node = array_fetch(node_t *, node_vec, i); + if(node_function(node) != NODE_PI){ + if(node_function(node) == NODE_PO){ + node = node_get_fanin(node, 0); + } + t_node = dummy_node; + tt_node = node_literal(node, 1); + dummy_node = node_or(t_node, tt_node); + node_free(t_node); + node_free(tt_node); + } + } + + root_table = st_init_table(st_ptrcmp, st_ptrhash); + p_rootAdd(dummy_node, root_table); + + level_table = st_init_table(st_ptrcmp, st_ptrhash); + (void)st_lookup(root_table, (char *)dummy_node, &dummy); + root = (node_t *)dummy; + (void)st_insert(level_table, (char *)root, (char *) 0); + p_levelAdd(root, level_table, root_table); + + pi_list = array_alloc(fanin_record_t *, 0); + st_foreach(level_table, p_addPI, (char *)pi_list); + + array_sort(pi_list, p_fanin_record_sort); + order_list = array_alloc(node_t *, 0); + for(i=0; i<array_n(pi_list); i++){ + pi_record = array_fetch(fanin_record_t *, pi_list, i); + array_insert_last(node_t *, order_list, pi_record->node); + FREE(pi_record); + } + array_free(pi_list); + st_free_table(level_table); + st_foreach(root_table, p_cleanRTable, (char *)root_table); + st_free_table(root_table); + node_free(dummy_node); + return(order_list); +} + +enum st_retval +p_addPI(key, value, arg) +char *key, *value, *arg; +{ + node_t *node; + int level; + array_t *pi_list; + fanin_record_t *pi_record; + + node = (node_t *)key; + + if((node_num_fanin(node) == 0) && (node_function(node) != NODE_0) && + (node_function(node) != NODE_1)){ + level = (int)value; + pi_record = ALLOC(fanin_record_t, 1); + pi_record->node = node; + pi_record->max_level = level; + pi_list = (array_t *)arg; + array_insert_last(fanin_record_t *, pi_list, pi_record); + } + return ST_CONTINUE; +} + +array_t * +pld_shuffle(list) +array_t *list; + +{ + array_t *newlist, *mark; + int i, list_size, next_index, count, j, index, rand_num; + node_t *new_node; + + mark = array_alloc(int, 0); + newlist = array_alloc(node_t *, 0); + + list_size = array_n(list); + for(i = 0; i < list_size; i++){ + array_insert(int , mark, i, 0); + } + + for(i = 0; i<list_size; i++){ + /*NOSTRICT*/ + rand_num = rand() % 32768; + /* taking random numbers from 0 - 2**15 + this should be portable across most machines */ + next_index = (rand_num / 32768.0)*(list_size - i); + /* normalizing it and multiplying by the range */ + count = -1; + for(j = 0; j<list_size; j++){ + if(array_fetch(int, mark, j) == 0) count++; + if(count == next_index){ + array_insert(int, mark, j, 1); + index = j; + break; + } + } + new_node = array_fetch(node_t *, list, index); + array_insert(node_t *, newlist, i, new_node); + } + array_free(mark); + array_free(list); + return(newlist); +} + + +array_t * +pld_order_nodes(node_vec, pi_only) +array_t *node_vec; +int pi_only; +{ + node_t *dummy_node, *t_node, *tt_node, *root, *node; + int i; + char *dummy; + st_table *root_table, *level_table, *max_table, *fanin_table; + array_t *order_list; + + dummy_node = node_constant(0); + for(i = 0; i<array_n(node_vec); i++){ + node = array_fetch(node_t *, node_vec, i); + t_node = dummy_node; + tt_node = node_literal(node, 1); + dummy_node = node_or(t_node, tt_node); + node_free(t_node); + node_free(tt_node); + } + + root_table = st_init_table(st_ptrcmp, st_ptrhash); + p_rootAdd(dummy_node, root_table); + + level_table = st_init_table(st_ptrcmp, st_ptrhash); + (void)st_lookup(root_table, (char *)dummy_node, &dummy); + root = (node_t *)dummy; + (void)st_insert(level_table, (char *)root, (char *) 0); + p_levelAdd(root, level_table, root_table); + + max_table = st_init_table(st_ptrcmp, st_ptrhash); + (void)p_maxAdd(root, max_table, level_table, root_table); + + order_list = array_alloc(node_t *, 0); + fanin_table = st_init_table(st_ptrcmp, st_ptrhash); + p_recOrder(root, max_table, fanin_table, root_table, order_list, + pi_only); + node_free(dummy_node); + st_free_table(max_table); + st_free_table(level_table); + st_foreach(root_table, p_cleanRTable, (char *)root_table); + st_free_table(root_table); + st_foreach(fanin_table, p_cleanFRTable, dummy); + st_free_table(fanin_table); + return(order_list); +} + +void +p_rootAdd(node, root_table) +node_t *node; +st_table *root_table; +{ + char *dummy; + array_t *factor_array; + node_t *root, *fanin; + int i; + + if(node_num_fanin(node) == 0){ + return; + } + if(!st_lookup(root_table, (char *)node, &dummy)){ + factor_array = factor_to_nodes(node); + root = array_fetch(node_t *, factor_array, 0); + array_free(factor_array); + (void)st_insert(root_table, (char *)node, (char *)root); + foreach_fanin(node, i, fanin){ + p_rootAdd(fanin, root_table); + } + } + return; +} + +void +p_levelAdd(node, level_table, root_table) +node_t *node; +st_table *level_table, *root_table; +{ + char *dummy; + int i, current_level, old_level; + node_t *fanin; + + (void)st_lookup(level_table, (char *)node, &dummy); + current_level = (int)dummy; + foreach_fanin(node, i, fanin){ + if(st_lookup(root_table, (char *)fanin, &dummy)){ + fanin = (node_t *)dummy; + } + if(st_lookup(level_table, (char *)fanin, &dummy)){ + old_level = (int)dummy; + if(old_level <= current_level){ + (void)st_insert(level_table, (char *)fanin, + (char *)(current_level + 1)); + } + } else { + (void)st_insert(level_table, (char *)fanin, + (char *)(current_level + 1)); + } + } + + foreach_fanin(node, i, fanin){ + if(st_lookup(root_table, (char *)fanin, &dummy)){ + fanin = (node_t *)dummy; + } + p_levelAdd(fanin, level_table, root_table); + } +} + +int +p_maxAdd(node, max_table, level_table, root_table) +node_t *node; +st_table *max_table, *level_table, *root_table; +{ + char *dummy; + int i, max, fanin_max; + node_t *fanin; + + (void)st_lookup(level_table, (char *)node, &dummy); + max = (int)dummy; + foreach_fanin(node, i, fanin){ + if(st_lookup(root_table, (char *)fanin, &dummy)){ + fanin = (node_t *)dummy; + } + if(st_lookup(max_table, (char *)fanin, &dummy)){ + fanin_max = (int)dummy; + } else { + fanin_max = p_maxAdd(fanin, max_table, level_table, root_table); + } + max = MAX(max, fanin_max); + } + (void)st_insert(max_table, (char *)node, (char *)max); + return max; +} + +void +p_recOrder(node, max_table, fanin_table, root_table, order_list, pi_only) +node_t *node; +st_table *max_table, *fanin_table, *root_table; +array_t *order_list; +int pi_only; +{ + array_t *fanin_record_list; + int i; + char *dummy; + node_t *fanin; + fanin_record_t *fanin_record; + st_table *iv_table; + + if(node_num_fanin(node) == 0){ + if((node_function(node)!= NODE_0) && + (node_function(node)!= NODE_1)){ + array_insert_last(node_t *, order_list, node); + return; + } + } + + fanin_record_list = array_alloc(fanin_record_t *, 0); + iv_table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_fanin(node, i, fanin){ + if(!pi_only){ + if(st_lookup(root_table, (char *)fanin, &dummy)){ + (void)st_insert(iv_table, dummy, (char *)fanin); + fanin = (node_t *)dummy; + } + } + if(st_lookup(fanin_table, (char *)fanin, &dummy)){ + fanin_record = (fanin_record_t *)dummy; + } else { + fanin_record = ALLOC(fanin_record_t , 1); + (void)st_lookup(max_table, (char *)fanin, &dummy); + fanin_record->max_level = (int)dummy; + fanin_record->node = fanin; + } + array_insert_last(fanin_record_t *, fanin_record_list, fanin_record); + } + + array_sort(fanin_record_list, p_fanin_record_sort); + + for(i = 0; i< array_n(fanin_record_list); i++){ + fanin_record = array_fetch(fanin_record_t *, fanin_record_list, i); + if(!st_lookup(fanin_table, (char *)(fanin_record->node), &dummy)){ + p_recOrder(fanin_record->node, max_table, fanin_table, root_table, + order_list, pi_only); + if(!pi_only){ + if(st_lookup(iv_table, (char *)fanin_record->node, + &dummy)){ + array_insert_last(node_t *, order_list, + (node_t *)dummy); + } + } + (void)st_insert(fanin_table, (char *)(fanin_record->node), + (char *)fanin_record); + } else { + if(fanin_record != (fanin_record_t *)dummy ){ + FREE(fanin_record); + } + } + } + array_free(fanin_record_list); + st_free_table(iv_table); + return; +} + +/*ARGSUSED*/ +enum st_retval +p_cleanRTable(key, value, arg) +char *key, *value, *arg; +{ + st_table *root_table; + node_t *node; + + root_table = (st_table *)arg; + node = (node_t *) value; + p_recFree(node, root_table); + return ST_CONTINUE; +} + +void +p_recFree(node, root_table) +node_t *node; +st_table *root_table; +{ + char *dummy; + node_t *fanin; + int i; + array_t *fanin_list; + + if(st_lookup(root_table, (char *)node, &dummy)){ + return; + } + if(node_num_fanin(node) == 0){ + return; + } + fanin_list = array_alloc(node_t *, 0); + foreach_fanin(node, i, fanin){ + array_insert_last(node_t *, fanin_list, fanin); + } + node_free(node); + for(i = 0; i<array_n(fanin_list); i++){ + node = array_fetch(node_t *, fanin_list, i); + p_recFree(node, root_table); + } + array_free(fanin_list); + return; +} +int +p_fanin_record_sort(key1, key2) +char **key1, **key2; +{ + fanin_record_t *fanin_record1, *fanin_record2; + int level1, level2; + + fanin_record1 = *((fanin_record_t **) key1); + fanin_record2 = *((fanin_record_t **) key2); + level1 = fanin_record1->max_level; + level2 = fanin_record2->max_level; + if(level1<level2) return 1; + else if (level1 > level2) return -1; + else return 0; +} + +/*ARGSUSED*/ +enum st_retval +p_cleanFRTable(key, value, arg) +char *key, *value, *arg; +{ fanin_record_t *fanin_record; + + fanin_record = (fanin_record_t *) value; + FREE(fanin_record); + return(ST_CONTINUE); +} diff --git a/sis/pld/act_read.c b/sis/pld/act_read.c new file mode 100644 index 0000000..34e7a0f --- /dev/null +++ b/sis/pld/act_read.c @@ -0,0 +1,69 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_read.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/************************************************************************* + Assumes that the delay file looks like: + + 4 + 1 2.3 + 2 3.0 + 3 3.9 + 4 5.4 + + This means that total of 4 delay values are specified (first line). + Each subsequent line gives the delay value for number of fanouts. + e.g. delay for fanout of 3 is 3.9 (ns). + + The procedure returns an array of delay values. The first entry in the + array is 0.0 (corr. to fanout of 0). +***************************************************************************/ +array_t * +act_read_delay(filename) +char *filename; +{ + array_t *delay_values; /* stores at location i */ + FILE *delayfile; + int num_spec; /* number of fanout values specified in the file */ + int num_fanout; /* signifies that the word following the current */ + /* word is delay for the num_fanout fanouts */ + double delay_num; /* delay value for some specified fanout */ + + delayfile = fopen(filename, "r"); + fscanf(delayfile, "%d", &num_spec); + if (num_spec < 1) fail("Error(act_read_delay): first word in the file should be > 0"); + delay_values = array_alloc(double, num_spec + 1); + array_insert(double, delay_values, 0, 0.0); + while (fscanf(delayfile, "%d", &num_fanout) != EOF) { + if (num_fanout < 1) fail("Error(act_read_delay): number of fanouts should be > 0"); + (void) fscanf(delayfile, "%f", &delay_num); + if (delay_num < 0.0) fail("Error(act_read_delay): number of fanouts should be > 0"); + array_insert(double, delay_values, num_fanout, delay_num); + } + (void) fclose(delayfile); + if (ACT_DEBUG) print_delay_values(delay_values); + return delay_values; +} + +print_delay_values(delay_values) +array_t *delay_values; +{ + int i, nsize; + double delaynum; + + nsize = array_n(delay_values); + (void) printf("printing actel delay info for number of fanouts...\n"); + for (i = 1; i < nsize; i++) { + delaynum = array_fetch(double, delay_values, i); + (void) printf(" delay[%d] = %f\n", i, delaynum); + } + (void) printf("\n"); +} diff --git a/sis/pld/act_reduce.c b/sis/pld/act_reduce.c new file mode 100644 index 0000000..770c75b --- /dev/null +++ b/sis/pld/act_reduce.c @@ -0,0 +1,162 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_reduce.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/* reduce, strictly follows bryants paper +*/ + +extern int p_compare2key(); + +ACT_VERTEX_PTR +actReduce(fn_graph) +ACT_VERTEX_PTR fn_graph; + +{ + int nextid, i, j, list_size, q_size, num_var; + ACT_VERTEX_PTR u, result; + KEY oldkey, key; + array_t *Q, *current_list, *subgraph; + Q_NODE_PTR q_entry; + + + subgraph = array_alloc(ACT_VERTEX_PTR, 0); + num_var = fn_graph->index_size; + /* create the index_lists */ + index_list_array = array_alloc(array_t *, 0); + for(i=0; i<= num_var; i++ ){ + current_list = array_alloc(ACT_VERTEX_PTR, 0); + array_insert(array_t *, index_list_array, i, current_list); + } + + /* add all the vertices in fn_graph to the lists corresponding + to their indices. + */ + traverse(fn_graph, p_addLists); + + nextid = -1; + for(i=num_var; i>= 0; i--){ + Q = array_alloc(Q_NODE_PTR, 0); + current_list = array_fetch(array_t *, index_list_array, i); + list_size = array_n(current_list); + for(j = 0; j<list_size; j++){ + u = array_fetch(ACT_VERTEX_PTR, current_list, j); + if (i == num_var) { /* add to the Q */ + + q_entry = ALLOC(Q_NODE, 1); + q_entry->key.low = u->value; + q_entry->key.high = u->value; + q_entry->v = u; + array_insert_last(Q_NODE_PTR,Q, q_entry); + } else { + if(u->low->id == u->high->id){ + u->id = u->low->id; + u->mark = DELETE; + } else { + q_entry = ALLOC(Q_NODE, 1); + q_entry->key.low = u->low->id; + q_entry->key.high = u->high->id; + q_entry->v = u; + array_insert_last(Q_NODE_PTR,Q, q_entry); + } + } + } + + array_sort(Q, p_compare2key); + + oldkey.low = -1; + oldkey.high = -1; + + q_size = array_n(Q); + for(j = 0; j<q_size; j++){ + q_entry = array_fetch(Q_NODE_PTR, Q, j); + key = q_entry->key; + u = q_entry -> v; + if((key.low==oldkey.low)&&(key.high==oldkey.high)){ + u->id = nextid; + u->mark = DELETE; + } else { + nextid++; + u->id = nextid; + array_insert(ACT_VERTEX_PTR, subgraph, nextid, u); + if(i != num_var){ + u->low = array_fetch(ACT_VERTEX_PTR, + subgraph, u->low->id); + u->high = array_fetch(ACT_VERTEX_PTR, + subgraph, u->high->id); + } + oldkey.low = key.low; + oldkey.high = key.high; + } + } + + /* Free storage associated with Q */ + for(j = 0; j<q_size; j++){ + q_entry = array_fetch(Q_NODE_PTR, Q, j); + FREE(q_entry); + } + array_free(Q); + } + + result = array_fetch(ACT_VERTEX_PTR, subgraph, fn_graph->id); + array_free(subgraph); + + /* free the storage associated with the unwanted nodes + in the fn_graph and the index lists + */ + + for(i=num_var; i>= 0; i--){ + current_list = array_fetch(array_t *, index_list_array, i); + list_size = array_n(current_list); + for(j = 0; j<list_size; j++){ + u = array_fetch(ACT_VERTEX_PTR, current_list, j); + if(u->mark == DELETE) { + FREE(u); + } + } + array_free(current_list); + } + + array_free(index_list_array); + return(result); +} + +void +p_addLists(v) +ACT_VERTEX_PTR v; +{ int index; + array_t *current_list; + + index = v->index; + current_list = array_fetch(array_t *, index_list_array, index); + array_insert_last(ACT_VERTEX_PTR, current_list, v); +} + +int +p_compare2key(q1, q2) +Q_NODE_PTR *q1, *q2; + +{ + KEY key1, key2; + + key1 = (*q1)->key; + key2 = (*q2)->key; + + if(key1.low < key2.low) + return(-1); + else if(key1.low > key2.low) + return(1); + else if(key1.high < key2.high) + return(-1); + else if(key1.high > key2.high) + return(1); + else return(0); +} + diff --git a/sis/pld/act_remove.c b/sis/pld/act_remove.c new file mode 100644 index 0000000..53b340d --- /dev/null +++ b/sis/pld/act_remove.c @@ -0,0 +1,106 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_remove.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/* free up ACTs +*/ + +int +p_actRemove(network, argc, argv) +network_t **network; +int argc; +char **argv; + +{ + int i, c, locality, input_size; + array_t *node_vec; + node_t *current_node; + + locality = 0; /* default GLOBAL */ + util_getopt_reset(); + while((c = util_getopt(argc, argv, "lg"))!=EOF) { + switch(c) { + case 'l' : locality = 1; break; + case 'g' : locality = 0; break; + default: goto usage; + } + } + node_vec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + input_size = array_n(node_vec); + for(i = 0; i<input_size; i++){ + current_node = array_fetch(node_t *, node_vec, i); + p_actDestroy(&(ACT_SET(current_node)->act_num[locality]), + locality); + ACT_SET(current_node)->act_num[locality] = NIL (ACT_ENTRY); + } + array_free(node_vec); + return(0); /* ok exit */ + + usage: + (void) fprintf(siserr, "usage: act_remove [-l] [-g] nodelist\n -l local\n -g global\n"); + return(1); /* error exit */ +} + +/* ARGSUSED */ +void +p_actDestroy(act_set_entry_ptr, locality) +ACT_ENTRY_PTR *act_set_entry_ptr; +int locality; +{ + ACT_ENTRY_PTR act_set_entry; + + if (*act_set_entry_ptr == NULL) return; + act_set_entry = *act_set_entry_ptr; + if(act_set_entry!=NIL (ACT_ENTRY)){ + + if (act_set_entry->act->root != NIL (ACT_VERTEX)) + p_dagDestroy(act_set_entry->act->root); + if ((act_set_entry->act->node_list != NIL (array_t)) && locality) + array_free(act_set_entry->act->node_list); + FREE(act_set_entry->act->node_name); + FREE(act_set_entry->act); + FREE(act_set_entry); + + } +} + +void +p_dagDestroy(dag) +ACT_VERTEX_PTR dag; +{ + int num_var, i, j, list_size; + array_t *current_list; + ACT_VERTEX_PTR u; + + if(dag != NIL (ACT_VERTEX)){ + index_list_array = array_alloc(array_t *, 0); + num_var = dag->index_size; + for(i = 0; i <= num_var; i++){ + current_list = array_alloc(ACT_VERTEX_PTR, 0); + array_insert(array_t *, index_list_array, i, + current_list); + } + + traverse(dag, p_addLists); + + for(i = num_var; i>=0; i--){ + current_list = array_fetch(array_t *, index_list_array, + i); + list_size = array_n(current_list); + for(j = 0; j<list_size; j++){ + u = array_fetch(ACT_VERTEX_PTR, current_list, j); + FREE(u); + } + array_free(current_list); + } + array_free(index_list_array); + } +} diff --git a/sis/pld/act_urp.c b/sis/pld/act_urp.c new file mode 100644 index 0000000..0b4f24b --- /dev/null +++ b/sis/pld/act_urp.c @@ -0,0 +1,355 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_urp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +/* Created by Narendra */ +#include "sis.h" +#include "pld_int.h" + +st_table *end_table; +static sm_matrix *build_F(); +static act_t* urp_F(); +static int good_bin_var(); +static int find_var(); +static void split_F(); +static void update_F(); + +/* We need this to initialise the 0 and 1 act s and store them + * in a table so they can be easily accessed*/ + +make_act(node) +node_t *node; +{ + sm_matrix *F; + act_t *act, *my_init_act(); + ACT_ENTRY *act_entry; + ACT *act_f; + +/* Init a global lookup table for terminal vertices*/ + end_table = st_init_table(st_ptrcmp, st_ptrhash); + act = my_init_act(); + act->value = 0; + (void) st_insert(end_table, (char *)0, (char *)act); + act = my_init_act(); + act->value = 1; + (void) st_insert(end_table, (char *)1, (char *)act); +/* initialize Matrix for node*/ + F = build_F(node); + if(ACT_DEBUG) my_sm_print(F); +/* construct act for node*/ + act = urp_F(F); +/* Free the st_table now*/ + st_free_table(end_table); + act_entry = ALLOC(ACT_ENTRY , 1); + act_entry->order_style = 0; + ACT_SET(node)->LOCAL_ACT = act_entry; + ACT_SET(node)->GLOBAL_ACT = NIL (ACT_ENTRY); + act_f = ALLOC(ACT , 1); + act_f->root = act; + act_f->node_list = NIL (array_t); + act_f->node_name = util_strsav(node_name(node)); + ACT_SET(node)->LOCAL_ACT->act = act_f; + if(ACT_DEBUG) { + trace_act(act); + } +/* Free up the space*/ + sm_free_space(F); +} + + + +/* Constructs the cover of the node. We use the sm package because we + need to solve a column covering problem at the unate leaf*/ +static +sm_matrix * +build_F(node) +node_t *node; +{ + int i, j; + node_cube_t cube; + node_literal_t literal; + sm_matrix *F; + node_t *fanin; + sm_col *p_col; + + F = sm_alloc(); + + for(i = node_num_cube(node)-1; i >= 0; i--) { + cube = node_get_cube(node, i); + foreach_fanin(node, j, fanin) { + literal = node_get_literal(cube, j); + switch(literal) { + case ONE: + sm_insert(F, i, j)->user_word = (char *)1; + break; + case ZERO: + sm_insert(F, i, j)->user_word = (char *)0; + break; + case TWO: + sm_insert(F, i, j)->user_word = (char *)2; + break; + default: + (void)fprintf(sisout, "error in F construction \n"); + break; + } + } + } +/* STuff the fanin names in the user word for each column*/ + foreach_fanin(node, j, fanin) { + p_col = sm_get_col(F, j); + p_col->user_word = node_long_name(fanin); + } + return F; +} + + + +/* Recurse !! using Unate recursive paradigm(modified)*/ +static +act_t * +urp_F(F) +sm_matrix *F; +{ + int b_col, ex; + act_t *act_l, *act_r, *my_and_act(), *act, *unate_act(); + sm_matrix *Fl, *Fr; + sm_element *p; + char *dummy; + char *b_name; + int value; + + ex = 0; + b_col = good_bin_var(F, &ex); + if(ACT_DEBUG) { + (void)fprintf(sisout, "The most binate col is %d\n", b_col); + } + if(b_col != -1) { + if(!ex) { + b_name = sm_get_col(F, b_col)->user_word; + split_F(F, b_col, &Fl, &Fr); + if(ACT_DEBUG){ + (void)fprintf(sisout, "factored wrt %d'\n", b_col); + my_sm_print(Fl); + } + act_l = urp_F(Fl); + if(ACT_DEBUG){ + (void)fprintf(sisout, "factored wrt %d \n", b_col); + my_sm_print(Fr); + } + act_r = urp_F(Fr); + sm_free_space(Fl); + sm_free_space(Fr); + act = my_and_act(act_l, act_r, b_col,b_name ); + } else { +/* Common variable to all cubes*/ + b_name = sm_get_col(F, b_col)->user_word; + p = sm_find(F, 0, b_col); + value = (int )p->user_word; + if((value != 1) && + (value != 0)) { + (void)fprintf(sisout, "ERROR in Common Variable\n"); + } + if(value == 1){ + (void) st_lookup(end_table, (char *)0, &dummy); + act_l = (act_t *)dummy; + update_F(F, b_col); + if(ACT_DEBUG){ + my_sm_print(F); + } + act_r = urp_F(F); + } + if(value == 0) { + (void) st_lookup(end_table, (char *)0, &dummy); + act_r = (act_t *)dummy; + update_F(F, b_col); + if(ACT_DEBUG){ + my_sm_print(F); + } + act_l = urp_F(F); + } + act = my_and_act(act_l, act_r, b_col, b_name); + } + }else { + act = unate_act(F); + } + return act; + +} + + +/* Choose good variable for co-factoring*/ +static int +good_bin_var(A, ex) +sm_matrix *A; +int *ex; + +{ + int *o, *z, i, var; + sm_col *pcol; + sm_element *p; + + o = ALLOC(int, A->ncols); + z = ALLOC(int, A->ncols); + for( i =0; i< A->ncols; i++) { + o[i] = 0; + z[i] = 0; + } + + i = 0; + + sm_foreach_col(A, pcol){ + sm_foreach_col_element(pcol, p) { + switch((int )p->user_word) { + case 1: + o[i]++; + break; + case 2: + break; + case 0: + z[i]++; + break; + default: + (void)fprintf(sisout, "Err in sm->user_word\n"); + break; + } + } + if(o[i] == A->nrows){ + *ex = 1; + FREE(o); + FREE(z); + return i; + } + if (z[i] == A->nrows){ + *ex = 1; + FREE(o); + FREE(z); + return i; + } + i++; + } + var = find_var(o, z, A->ncols); + FREE(o); + FREE(z); + return var; +} + + + +static int +find_var(o, z, size) +int *o, *z, size; +{ + int i, b_b= 0, b_d= 100, var; + + var = -1; + for(i = 0; i < size; i++) { + if((o[i] > 0) && (z[i] > 0)){ + if(b_b < o[i]+ z[i]){ + b_b = o[i] + z[i]; + b_d = abs(o[i]-z[i]); + var = i; + } else if(b_b == o[i]+ z[i]) { + if(abs(o[i]-z[i]) < b_d) { + b_d = abs(o[i]-z[i]); + var = i; + } + } + } + } + return var; +} + + +/* Divide matrix into the 2 co-factored matrices*/ +static void +split_F(F, b_col, Fl, Fr) +sm_matrix *F, **Fl, **Fr; +int b_col; +{ + sm_matrix *Fhi, *Flo; + sm_row *F_row; + sm_col *pcol; + sm_element *p; + + Fhi = sm_alloc(); + Flo = sm_alloc(); + pcol = sm_get_col(F, b_col); + sm_foreach_col_element(pcol, p) { + F_row = sm_get_row(F, p->row_num); + switch((int )p->user_word) { + case 0: + my_sm_copy_row(F_row, Flo, b_col, F); + break; + case 1: + my_sm_copy_row(F_row, Fhi, b_col, F); + break; + case 2: + my_sm_copy_row(F_row, Flo, b_col, F); + my_sm_copy_row(F_row, Fhi, b_col, F); + break; + default: + (void)fprintf(sisout, "error in duplicating row\n"); + break; + } + } + *Fl = Flo; + *Fr = Fhi; +} + + +my_sm_copy_row(F_row, F, col,Fp) +sm_row *F_row; +sm_matrix *F, *Fp; +int col; +{ + int j; + int row; + + row = F->nrows; + for(j = 0; j< F_row->length; j++){ + if(j != col) { + sm_insert(F, row, j)->user_word = + sm_row_find(F_row, j)->user_word; + } else if(j == col) { + sm_insert(F, row, j)->user_word = (char *)2; + } + sm_get_col(F, j)->user_word = sm_get_col(Fp, j)->user_word; + } +} + +/* For debug*/ +my_sm_print(F) +sm_matrix *F; +{ + sm_row *row; + sm_element *p; + + (void)fprintf(sisout, "Printing F matrix\n"); + sm_foreach_row(F, row) { + sm_foreach_row_element(row, p){ + (void)fprintf(sisout, "%d", (int *)p->user_word); + } + (void)fprintf(sisout, "\n"); + } +} + + +/* Set co-factored variable to 2*/ +static void +update_F(F, b_col) +sm_matrix *F; +int b_col; +{ + sm_col *p_col; + sm_element *p; + + p_col = sm_get_col(F, b_col); + sm_foreach_col_element(p_col, p){ + p->user_word = (char *)2; + } +} diff --git a/sis/pld/act_util.c b/sis/pld/act_util.c new file mode 100644 index 0000000..e28afcf --- /dev/null +++ b/sis/pld/act_util.c @@ -0,0 +1,674 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/act_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/*-------------------------------------------------------------------------- + Returns 1 if node1 is a fanin of node 2. Else returns 0. +---------------------------------------------------------------------------*/ +int +is_fanin_of (node1, node2) +node_t *node1, *node2; +{ + int i, result; + node_t *fanin; + + result = 0; + if (node2->type == PRIMARY_INPUT) return 0; + foreach_fanin(node2, i, fanin) { + if (fanin == node1) { + result = 1; + break; + } + } + return result; +} + +COST_STRUCT * +act_allocate_cost_node(node, cost, arrival_time, required_time, slack, is_critical, area_weight, + cost_and_arrival_time, act) +node_t *node; +int cost, is_critical; +double arrival_time, required_time, slack, area_weight, cost_and_arrival_time; +ACT_VERTEX_PTR act; +{ + COST_STRUCT *cost_node; + + cost_node = ALLOC(COST_STRUCT, 1); + cost_node->node = node; + cost_node->cost = cost; + cost_node->arrival_time = arrival_time; + cost_node->required_time = required_time; + cost_node->slack = slack; + cost_node->is_critical = is_critical; + cost_node->area_weight = area_weight; + cost_node->cost_and_arrival_time = cost_and_arrival_time; + cost_node->act = act; + + return cost_node; +} + + +act_final_check_network(network, cost_table) +network_t *network; +st_table *cost_table; +{ + lsGen gen; + node_t *node; + st_table *table; + enum st_retval act_free_check_table(); + + table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_node(network, gen, node) { + act_final_check_node(node, cost_table, table); + } + st_foreach(table, act_free_check_table, NIL (char)); + st_free_table(table); +} + +act_final_check_node(node, cost_table, table) +node_t *node; +st_table *cost_table, *table; +{ + COST_STRUCT *cost_node; + + if (node->type != INTERNAL) return; + assert(st_lookup(cost_table, node_long_name(node), (char **) &cost_node)); + if (ACT_DEBUG) (void) printf("traversing node %s, cost = %d, pattern_num = %d\n", + node_long_name(node), cost_node->cost, cost_node->act->pattern_num); + my_traverse_act(cost_node->act); + act_check(cost_node->act); + delete_act(cost_node->act, table); + /* act_traverse_not_initialize_act(cost_node->act); + my_traverse_act(cost_node->act); */ +} + +/* ARGSUSED */ +enum st_retval +act_free_check_table(key, value, arg) +char *key, *value, *arg; +{ + return ST_DELETE; + +} + + +ACT_VERTEX_PTR +act_allocate_act_vertex(mark_value) +int mark_value; +{ + ACT_VERTEX_PTR act; + + act = ALLOC(ACT_VERTEX, 1); + act->name = NIL (char); + act->id = 0; + act->mark = mark_value; + act->multiple_fo = 0; +/* act->multiple_fo_for_mapping = 0; */ + act->cost = 0; + act->mapped = 0; + act->low = NIL (ACT_VERTEX); + act->high = NIL (ACT_VERTEX); + return act; +} + + +double my_max(a, b) + double a, b; +{ + if ( a >= b) return a; + return b; +} + +act_check(vertex) +ACT_VERTEX_PTR vertex; + +{ + st_table *table; + enum st_retval act_free_check_table(); + + table = st_init_table(st_ptrcmp, st_ptrhash); + act_check_vertex(vertex, table); + st_foreach(table, act_free_check_table, NIL (char)); + st_free_table(table); +} + +/*------------------------------------------------------------ + Performs a few checks on the vertices of the act (bdd). +-------------------------------------------------------------*/ +act_check_vertex(vertex, table) +ACT_VERTEX_PTR vertex; +st_table *table; +{ + if (st_is_member(table, (char *) vertex)) return; + assert(!st_insert(table, (char *) vertex, (char *) vertex)); + /* if (ACT_DEBUG) + (void) printf (" checking vertex %s, value = %d\n", vertex->name, vertex->value); */ + assert (vertex->value == 0 || vertex->value == 1 || vertex->value == 4); + if ((vertex->value != 4) && (vertex->low != NIL (ACT_VERTEX))) fail(" vertex low not nil"); + if ((vertex->value != 4) && (vertex->high != NIL (ACT_VERTEX))) fail(" vertex high not nil"); + if ((vertex->value == 4) && (vertex->low == NIL (ACT_VERTEX))) fail(" vertex low nil"); + if ((vertex->value == 4) && (vertex->high == NIL (ACT_VERTEX))) fail(" vertex high nil"); + if (vertex->value == 4) { + act_check_vertex(vertex->low, table); + act_check_vertex(vertex->high, table); + } + +} + +/*----------------------------------------------------- + Changes possibly the low or high child (depending on + the flag) of the vertex. Decrements the multiple_fo_ + for_mapping flag if possible. This flag is used to + distinguish originally multiple_fo vertices. + SIDE_EFFECT: May make the newchild and fanin + of the node correspond to each other. newchild + would have to have the same name as the fanin. + Stores the info in the global array + vertex_name_array. +------------------------------------------------------*/ +act_change_vertex_child(vertex, child, flag, node) +ACT_VERTEX_PTR vertex, child; +int flag; +node_t *node; +{ + node_t *fanin; + VERTEX_NODE *vertex_name_struct; + ACT_VERTEX_PTR newchild; + + /* if the child is a 0 or 1 vertex, check if child is a multiple + fo vertex. If it is not, it is OK. Else, decrease the + multiple_fo field of child and then make a new vertex + "newchild", and make it the appropriate child (low or high) + of the vertex. */ + /*------------------------------------------------------------*/ + if (child->value == 0) { + if (node != NIL (node_t)) assert(node_num_fanin(node) == 0); + if (child->multiple_fo_for_mapping == 0) return; + (child->multiple_fo_for_mapping)--; + newchild = act_allocate_act_vertex(MARK_COMPLEMENT_VALUE); + newchild->value = 0; + if (flag == LOW) vertex->low = newchild; + else vertex->high = newchild; + return; + } + if (child->value == 1) { + if (node != NIL (node_t)) assert(node_num_fanin(node) == 0); + if (child->multiple_fo_for_mapping == 0) return; + (child->multiple_fo_for_mapping)--; + newchild = act_allocate_act_vertex(MARK_COMPLEMENT_VALUE); + newchild->value = 1; + if (flag == LOW) vertex->low = newchild; + else vertex->high = newchild; + return; + } + if (child->low->value == 0 && child->high->value == 1) { + /* this part is to handle cases when there may be more + than one such vertices (i.e. like child) and then + there may be more than one parent pointing to the + terminal vertices 0, 1 */ + /*---------------------------------------------------*/ + if (child->multiple_fo_for_mapping == 0) { + if (child->low->multiple_fo_for_mapping != 0) { + (child->low->multiple_fo_for_mapping)--; + newchild = act_allocate_act_vertex(MARK_COMPLEMENT_VALUE); + newchild->value = 0; + child->low = newchild; + } + if (child->high->multiple_fo_for_mapping != 0) { + (child->high->multiple_fo_for_mapping)--; + newchild = act_allocate_act_vertex(MARK_COMPLEMENT_VALUE); + newchild->value = 1; + child->high = newchild; + } + return; + } + (child->multiple_fo_for_mapping)--; + newchild = act_allocate_act_vertex(MARK_COMPLEMENT_VALUE); + newchild->value = 4; + newchild->name = child->name; /* right? */ + if (flag == LOW) vertex->low = newchild; + else vertex->high = newchild; + act_add_terminal_vertices(newchild); + return; + } + /* the child is non-trivial vertex (i.e. root of another tree) + have to create a new vertex for it everytime. */ + /*-------------------------------------------------------------*/ + if (child->multiple_fo_for_mapping != 0) (child->multiple_fo_for_mapping)--; + newchild = act_allocate_act_vertex(MARK_COMPLEMENT_VALUE); + newchild->value = 4; + if (flag == LOW) vertex->low = newchild; + else vertex->high = newchild; + /* make the low and high children of newchild 0 and 1 terminal vertices. */ + /*-----------------------------------------------------------------------*/ + act_add_terminal_vertices(newchild); + + /* newchild corresponds to the fanin of node. Store that info */ + /*------------------------------------------------------------*/ + assert(node_num_fanin(node) == 1); + fanin = node_get_fanin(node, 0); /* node is a node_literal */ + vertex_name_struct = act_allocate_vertex_node_struct(newchild, fanin); + array_insert_last(VERTEX_NODE *, vertex_name_array, vertex_name_struct); +} + + +VERTEX_NODE * +act_allocate_vertex_node_struct(vertex, node) +ACT_VERTEX_PTR vertex; +node_t *node; +{ + VERTEX_NODE *vertex_node_struct; + + vertex_node_struct = ALLOC(VERTEX_NODE, 1); + vertex_node_struct->vertex = vertex; + vertex_node_struct->node = node; + return vertex_node_struct; +} + +/*---------------------------------------------------------- + Creates 0 and 1 terminal vertices and makes them + low and high children of the vertex. +-----------------------------------------------------------*/ +act_add_terminal_vertices(vertex) +ACT_VERTEX_PTR vertex; +{ + ACT_VERTEX_PTR low, high; + + low = act_allocate_act_vertex(MARK_COMPLEMENT_VALUE); + low->value = 0; + high = act_allocate_act_vertex(MARK_COMPLEMENT_VALUE); + high->value = 1; + vertex->low = low; + vertex->high = high; +} + + +/*-------------------------------------------------------------------------------- + Puts the correct node names in the act vertices after partial collapsing of the + node. Also updates fields of the cost_struct. Note that cost_struct corresponds + to the node of the network. +----------------------------------------------------------------------------------*/ +act_partial_collapse_update_act_fields(network, dup_fanout, cost_struct) + network_t *network; + node_t *dup_fanout; + COST_STRUCT *cost_struct; + +{ + node_t *fanout; + + fanout = network_find_node(network, node_long_name(dup_fanout)); + cost_struct->node = fanout; + cost_struct->act->node = fanout; + act_partial_collapse_put_node_names_in_act(cost_struct->act, network); +} + +/*------------------------------------------------------------------------ + Puts correct node names in all the vertices of the act rooted at + vertex. It does this by finding the node in the network with the same + name as vertex->name and pointing the name field at the name of this node. + This is correct since the dup_net has the same node names as original + network. +-------------------------------------------------------------------------*/ +act_partial_collapse_put_node_names_in_act(vertex, network) + ACT_VERTEX_PTR vertex; + network_t *network; +{ + node_t *node; + + if (vertex->mark == 0) vertex->mark = 1; + else vertex->mark = 0; + + if (vertex->value != 4) return; + + node = network_find_node(network, vertex->name); + vertex->name = node_long_name(node); + + if (vertex->mark != vertex->low->mark) + act_partial_collapse_put_node_names_in_act(vertex->low, network); + if (vertex->mark != vertex->high->mark) + act_partial_collapse_put_node_names_in_act(vertex->high, network); +} + + + +/*-------------------------------------------------------------------------------- + Puts the correct node names in the act vertices after the remapping of the node. + Also updates fields of the cost_struct. Note that cost_struct corresponds to the + node of the network. +----------------------------------------------------------------------------------*/ +act_remap_update_act_fields(table1, network1, node, cost_struct) + st_table *table1; + network_t *network1; + node_t *node; + COST_STRUCT *cost_struct; + +{ + cost_struct->node = node; + cost_struct->act->node = node; + act_remap_put_node_names_in_act(cost_struct->act, table1, network1); +} + +/*------------------------------------------------------------------------ + Puts correct node names in all the vertices of the act rooted at + vertex. +-------------------------------------------------------------------------*/ +act_remap_put_node_names_in_act(vertex, table1, network1) + ACT_VERTEX_PTR vertex; + st_table *table1; + network_t *network1; +{ + node_t *node1, *node; + + if (vertex->mark == 0) vertex->mark = 1; + else vertex->mark = 0; + + if (vertex->value != 4) return; + + node1 = network_find_node(network1, vertex->name); + assert(st_lookup(table1, (char *) node1, (char **) &node)); + vertex->name = node_long_name(node); + + if (vertex->mark != vertex->low->mark) + act_remap_put_node_names_in_act(vertex->low, table1, network1); + if (vertex->mark != vertex->high->mark) + act_remap_put_node_names_in_act(vertex->high, table1, network1); +} + +/**************************************************************************** + puts all the fanins of the node "node" in the order_list, + except for the node "n". +*****************************************************************************/ + +void +act_put_nodes(node, n, order_list) + node_t *node; + node_t *n; + array_t *order_list; +{ + int num_fanin; + node_t *fanin; + int i; + int check; /* for debugging */ + + check = 0; + num_fanin = node_num_fanin(node); + for (i = num_fanin -1; i>= 0; i--) { + fanin = node_get_fanin(node, i); + if (fanin == n) { + check = 1; + continue; + } + array_insert_last(node_t *, order_list, fanin); + } + + /* for debugging */ + /*---------------*/ + if (check == 0) { + (void) printf("put_order: node %s does not have the required fanin\n", + node_long_name(node)); + exit(1); + } +} + +/********************************************************************** + recursively initialize the required structure of each act vertex. + also finds out multiple fan out vertices and stores them in the + multiple_fo_array. +************************************************************************/ +void +act_initialize_act_area(vertex, multiple_fo_array) + ACT_VERTEX_PTR vertex; + array_t *multiple_fo_array; +{ + /* to save repetition, mark the vertex as visited */ + /*------------------------------------------------*/ + if (vertex->mark == 0) vertex->mark = 1; + else vertex->mark = 0; + + vertex->pattern_num = -1; + vertex->cost = 0; + vertex->arrival_time = (double) 0.0; + vertex->mapped = 0; + vertex->multiple_fo = 0; + vertex->multiple_fo_for_mapping = 0; + + /* do not care for a terminal vertex- nothing is to be done */ + /*----------------------------------------------------------*/ + if (vertex->value != 4) { + vertex->cost = 0; + vertex->arrival_time = (double) (0.0); + return; + } + + /* if the left(right) son not visited earlier, initialize it, else + mark it as a multiple fo vertex */ + /*---------------------------------------------------------------*/ + + if (vertex->mark != vertex->low->mark) + act_initialize_act_area(vertex->low, multiple_fo_array); + else { + /* important to check that it is a multiple_fo vertex, else you may be + adding a vertex too many times in the multiple_fo array.*/ + /*--------------------------------------------------------------------*/ + if (vertex->low->multiple_fo == 0) { + array_insert_last(ACT_VERTEX_PTR, multiple_fo_array, vertex->low); + } + vertex->low->multiple_fo += 1; + vertex->low->multiple_fo_for_mapping += 1; + } + + if (vertex->mark != vertex->high->mark) + act_initialize_act_area(vertex->high, multiple_fo_array); + else { + if (vertex->high->multiple_fo == 0) { + array_insert_last(ACT_VERTEX_PTR, multiple_fo_array, vertex->high); + } + vertex->high->multiple_fo += 1; + vertex->high->multiple_fo_for_mapping += 1; + + } + +} + + +/* for the purpose of debugging with it first */ + +void +act_initialize_act_delay(vertex) + ACT_VERTEX_PTR vertex; +{ + /* to save repetition, mark the vertex as visited */ + /*------------------------------------------------*/ + if (vertex->mark == 0) vertex->mark = 1; + else vertex->mark = 0; + + vertex->pattern_num = -1; + vertex->cost = 0; + vertex->arrival_time = (double) 0.0; /* so that multiple_fo vertices are taken care of */ + vertex->mapped = 0; + vertex->multiple_fo = 0; + vertex->multiple_fo_for_mapping = 0; + + /* do not care for a terminal vertex- nothing is to be done */ + /*----------------------------------------------------------*/ + if (vertex->value != 4) { + return; + } + /* if the left(right) son not visited earlier, initialize it, else + mark it as a multiple fo vertex */ + /*---------------------------------------------------------------*/ + + if (vertex->mark != vertex->low->mark) act_initialize_act_delay(vertex->low); + else { + vertex->low->multiple_fo += 1; + vertex->low->multiple_fo_for_mapping += 1; + } + + if (vertex->mark != vertex->high->mark) act_initialize_act_delay(vertex->high); + else { + vertex->high->multiple_fo += 1; + vertex->high->multiple_fo_for_mapping += 1; + } + +} + +make_multiple_fo_array_delay(vertex, multiple_fo_array) + ACT_VERTEX_PTR vertex; + array_t *multiple_fo_array; +{ + + /* to save repetition, mark the vertex as visited */ + /*------------------------------------------------*/ + if (vertex->mark == 0) vertex->mark = 1; + else vertex->mark = 0; + + /* do not care for a terminal vertex- nothing is to be done */ + /*----------------------------------------------------------*/ + if (vertex->value != 4) return; + + if (vertex->multiple_fo != 0) my_array_insert_unique(vertex, multiple_fo_array); + if (vertex->mark != vertex->low->mark) make_multiple_fo_array_delay(vertex->low, multiple_fo_array); + if (vertex->mark != vertex->high->mark) make_multiple_fo_array_delay(vertex->high, multiple_fo_array); +} + + +/***************************************************************************** + if vertex is already there in the multiple_fo_array, returns 0. + Else inserts it in the end of the array and returns 1. +******************************************************************************/ +my_array_insert_unique(vertex, multiple_fo_array) + ACT_VERTEX_PTR vertex; + array_t *multiple_fo_array; +{ + int i, nsize; + ACT_VERTEX_PTR v; + + nsize = array_n(multiple_fo_array); + for (i = 0; i < nsize; i++) { + v = array_fetch(ACT_VERTEX_PTR, multiple_fo_array, i); + if (v == vertex) return 0; + } + array_insert_last(ACT_VERTEX_PTR, multiple_fo_array, vertex); + return 1; +} + + +/****************************************************************************************** + Just prints out the BDD (OBDD) starting at the vertex. It first visits the low child and + then the right child. Marks all the nodes that are visited so that in future, it does not + traverse an already traversed (marked) node. +******************************************************************************************/ +void my_traverse_act(vertex) + ACT_VERTEX_PTR vertex; +{ + + if (vertex->mark == 0) vertex->mark = 1; + else vertex->mark = 0; + print_vertex(vertex); + + if (vertex->value != 4) return; + + if (vertex->mark == vertex->low->mark){ + print_vertex(vertex->low); + if (vertex->mark == vertex->high->mark){ + print_vertex(vertex->high); + return; + } + my_traverse_act(vertex->high); + return; + } + my_traverse_act(vertex->low); + if (vertex->mark == vertex->high->mark){ + print_vertex(vertex->high); + return; + } + my_traverse_act(vertex->high); + return; + +} + +static +act_traverse_not_initialize_act(vertex) + ACT_VERTEX_PTR vertex; +{ + /* to save repetition, mark the vertex as visited */ + /*------------------------------------------------*/ + if (vertex->mark == 0) vertex->mark = 1; + else vertex->mark = 0; + + /* do not care for a terminal vertex- nothing is to be done */ + /*----------------------------------------------------------*/ + if (vertex->value != 4) { + return; + } + + /* if the left(right) son not visited earlier, initialize it, else + mark it as a multiple fo vertex */ + /*---------------------------------------------------------------*/ + + if (vertex->mark != vertex->low->mark) act_traverse_not_initialize_act(vertex->low); + else { + /* important to check that it is a multiple_fo vertex, else you may be + adding a vertex too many times in the multiple_fo array.*/ + /*--------------------------------------------------------------------*/ + vertex->low->multiple_fo += 1; + vertex->low->multiple_fo_for_mapping += 1; + } + + if (vertex->mark != vertex->high->mark) act_traverse_not_initialize_act(vertex->high); + else { + vertex->high->multiple_fo += 1; + vertex->high->multiple_fo_for_mapping += 1; + + } + +} + +/***************************************************************************************** + Prints information on a vertex of the ACT (OACT) +*****************************************************************************************/ +void +print_vertex(vertex) +ACT_VERTEX_PTR vertex; +{ + + /* terminal vertex */ + /*-----------------*/ + if (vertex->value != 4) { + (void) printf ("value = %d, id = %d, index = %d, multiple_fo_for_mapping = %d\n", vertex->value, + vertex->id, vertex->index, vertex->multiple_fo_for_mapping); + (void) printf ("value = %d, id = %d, index = %d\n", vertex->value, + vertex->id, vertex->index); + return; + } + + /* nonterminal vertex */ + /*--------------------*/ + if (vertex->name != NIL (char)) + (void) printf ("name = %s, index = %d, num_fanouts = %d, multiple_fo_for_mapping = %d\n", + vertex->name, vertex->index, vertex->multiple_fo + 1, vertex->multiple_fo_for_mapping); + else + (void) printf ("id = %d, index = %d, num_fanouts = %d, multiple_fo_for_mapping = %d\n", + vertex->id, vertex->index, vertex->multiple_fo + 1, vertex->multiple_fo_for_mapping); + + /* (void) printf ("name = %s, index = %d, num_fanouts = %d\n", + vertex->name, vertex->index, vertex->multiple_fo + 1); + else + (void) printf ("id = %d, index = %d, num_fanouts = %d\n", + vertex->id, vertex->index, vertex->multiple_fo + 1); */ + +} + + + + + + diff --git a/sis/pld/com_ite.c b/sis/pld/com_ite.c new file mode 100644 index 0000000..120fd23 --- /dev/null +++ b/sis/pld/com_ite.c @@ -0,0 +1,539 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + + +/* adding these global variables in, so as to + experiment with the variable selection weight + assignment */ + +int ACT_ITE_ALPHA, ACT_ITE_GAMMA; +int UNATE_SELECT; + +int ACT_ITE_DEBUG; +int ACT_ITE_STATISTICS; +int USE_FAC_WHEN_UNATE; + +/* int act_is_or_used; */ /* defined in com_pld.c */ + +com_act_ite_map(network, argc, argv) + network_t **network; + int argc; + char **argv; +{ + int c; + act_init_param_t *init_param; + + init_param = ALLOC(act_init_param_t, 1); + + /* default */ + /*---------*/ + ACT_ITE_DEBUG = 0; + ACT_ITE_STATISTICS = 0; + act_is_or_used = 1; + init_param->HEURISTIC_NUM = 0; + init_param->FANIN_COLLAPSE = 3; + init_param->COLLAPSE_FANINS_OF_FANOUT = 15; + init_param->DECOMP_FANIN = 4; + init_param->NUM_ITER = 0; + init_param->COST_LIMIT = 3; + init_param->LAST_GASP = 0; + init_param->map_alg = 1; + init_param->lit_bound = 200; + init_param->ITE_FANIN_LIMIT_FOR_BDD = 40; + init_param->COLLAPSE_UPDATE = INEXPENSIVE; + init_param->COLLAPSE_METHOD = OLD; + init_param->DECOMP_METHOD = USE_GOOD_DECOMP; + init_param->ALTERNATE_REP = 0; /* do not use it */ + init_param->MAP_METHOD = NEW; + init_param->VAR_SELECTION_LIT = 15; + init_param->BREAK = 0; + + /* the default values are the ones which were used + before these variables were introduced */ + /*------------------------------------------------*/ + ACT_ITE_ALPHA = 2; + ACT_ITE_GAMMA = 1; + USE_FAC_WHEN_UNATE = 1; /* to be used with V > 0 */ + MAXOPTIMAL = 6; + UNATE_SELECT = 0; + + util_getopt_reset(); + while(( c = util_getopt(argc, argv, "A:C:F:G:M:V:b:d:f:h:l:m:n:v:DLNUacorsuw")) != EOF){ + switch(c){ + case 'A': + ACT_ITE_ALPHA = atoi(util_optarg); + break; + case 'C': + init_param->COST_LIMIT = atoi(util_optarg); + break; + case 'D': + init_param->DECOMP_METHOD = USE_FACTOR; + break; + case 'F': + init_param->COLLAPSE_FANINS_OF_FANOUT = atoi(util_optarg); + break; + case 'G': + ACT_ITE_GAMMA = atoi(util_optarg); + break; + case 'L': + init_param->LAST_GASP = 1; + break; + case 'M': + MAXOPTIMAL = atoi(util_optarg); + break; + case 'N': + init_param->COLLAPSE_METHOD = NEW; + break; + case 'U': + init_param->COLLAPSE_UPDATE = EXPENSIVE; + break; + case 'V': + init_param->VAR_SELECTION_LIT = atoi(util_optarg); + break; + case 'a': + init_param->ALTERNATE_REP = 1; + break; + case 'b': + init_param->ITE_FANIN_LIMIT_FOR_BDD = atoi(util_optarg); + break; + case 'c': + init_param->map_alg = 0; + break; + case 'd': + init_param->DECOMP_FANIN = atoi(util_optarg); + break; + case 'f': + init_param->FANIN_COLLAPSE = atoi(util_optarg); + break; + case 'h': + init_param->HEURISTIC_NUM = atoi(util_optarg); + if (init_param->HEURISTIC_NUM != 0) { + (void) printf("only -h 0 supported\n"); + return 1; + } + break; + case 'l': + init_param->lit_bound = atoi(util_optarg); + break; + case 'm': + init_param->MAP_METHOD = atoi(util_optarg); + break; + case 'n': + init_param->NUM_ITER = atoi(util_optarg); + break; + case 'o': + act_is_or_used = 0; + break; + case 'r': + init_param->BREAK = 1; + break; + case 's': + ACT_ITE_STATISTICS = 1; + break; + case 'u': + USE_FAC_WHEN_UNATE = 0; + break; + case 'v': + ACT_ITE_DEBUG = atoi(util_optarg); + break; + case 'w': + UNATE_SELECT = 1; + break; + default: + FREE(init_param); + (void) fprintf(sisout, "usage: ite_map [-o (or_gate_not_used)] [-h HEURISTIC_NUM] [-d DECOMP_FANIN] [-c (complete_matchin)] \n"); + (void) fprintf(sisout, "\t[-f FANIN_COLLAPSE] [F COLLAPSE_FANINS_OF_FANOUT] [-n NUM_ITER] [-s (STATISTICS)] [-L (last_gasp)] [-N (collapse_method NEW)]\n"); + (void) fprintf(sisout, "\t[-a (use bdd as alternate representation)] [-U (make collapse_update expensive)] [-v verbosity level]\n"); + (void) fprintf(sisout, "[-m MAP_METHOD 0:old,1:new,2:with_iter3:with_just_decomp] [-V new var selection method - lit count] HEURISTIC_NUM\t0 => ite, 1 => canonical ite (default 0)\n"); + (void) fprintf(sisout, "\t[-D (DECOMP_METHOD: use factored form)] [-w (unate_select = cover)]\n"); + return 1; + } + } + /* some default values */ + /*---------------------*/ + init_param->mode = 0.0; + init_param->GAIN_FACTOR = 0.01; + + (void) act_ite_map_network_with_iter(*network, init_param); + + FREE(init_param); + return 0; +} + +com_act_ite_create_and_map_mroot_network(network, argc, argv) + network_t **network; + int argc; + char **argv; +{ + int c; + act_init_param_t *init_param; + + init_param = ALLOC(act_init_param_t, 1); + + /* default */ + /*---------*/ + ACT_ITE_DEBUG = 0; + ACT_ITE_STATISTICS = 0; + act_is_or_used = 1; + init_param->HEURISTIC_NUM = 0; + init_param->FANIN_COLLAPSE = 3; + init_param->COLLAPSE_FANINS_OF_FANOUT = 15; + init_param->DECOMP_FANIN = 4; + init_param->NUM_ITER = 0; + init_param->COST_LIMIT = 3; + init_param->LAST_GASP = 0; + init_param->map_alg = 1; + init_param->lit_bound = 200; + init_param->ITE_FANIN_LIMIT_FOR_BDD = 40; + init_param->COLLAPSE_UPDATE = INEXPENSIVE; + init_param->COLLAPSE_METHOD = OLD; + init_param->DECOMP_METHOD = USE_GOOD_DECOMP; + init_param->ALTERNATE_REP = 0; /* do not use it */ + init_param->MAP_METHOD = NEW; + init_param->VAR_SELECTION_LIT = 15; + + /* the default values are the ones which were used + before these variables were introduced */ + /*------------------------------------------------*/ + ACT_ITE_ALPHA = 2; + ACT_ITE_GAMMA = 1; + USE_FAC_WHEN_UNATE = 1; /* to be used with V > 0 */ + MAXOPTIMAL = 6; + + util_getopt_reset(); + while(( c = util_getopt(argc, argv, "A:C:F:G:M:V:b:d:f:h:l:m:n:v:DLNUacorsu")) != EOF){ + switch(c){ + case 'A': + ACT_ITE_ALPHA = atoi(util_optarg); + break; + case 'C': + init_param->COST_LIMIT = atoi(util_optarg); + break; + case 'D': + init_param->DECOMP_METHOD = USE_FACTOR; + break; + case 'F': + init_param->COLLAPSE_FANINS_OF_FANOUT = atoi(util_optarg); + break; + case 'G': + ACT_ITE_GAMMA = atoi(util_optarg); + break; + case 'L': + init_param->LAST_GASP = 1; + break; + case 'M': + MAXOPTIMAL = atoi(util_optarg); + break; + case 'N': + init_param->COLLAPSE_METHOD = NEW; + break; + case 'U': + init_param->COLLAPSE_UPDATE = EXPENSIVE; + break; + case 'V': + init_param->VAR_SELECTION_LIT = atoi(util_optarg); + break; + case 'a': + init_param->ALTERNATE_REP = 1; + break; + case 'b': + init_param->ITE_FANIN_LIMIT_FOR_BDD = atoi(util_optarg); + break; + case 'c': + init_param->map_alg = 0; + break; + case 'd': + init_param->DECOMP_FANIN = atoi(util_optarg); + break; + case 'f': + init_param->FANIN_COLLAPSE = atoi(util_optarg); + break; + case 'h': + init_param->HEURISTIC_NUM = atoi(util_optarg); + if (init_param->HEURISTIC_NUM != 0) { + (void) printf("only -h 0 supported\n"); + return 1; + } + break; + case 'l': + init_param->lit_bound = atoi(util_optarg); + break; + case 'm': + init_param->MAP_METHOD = atoi(util_optarg); + break; + case 'n': + init_param->NUM_ITER = atoi(util_optarg); + break; + case 'o': + act_is_or_used = 0; + break; + case 'r': + init_param->BREAK = 1; + break; + case 's': + ACT_ITE_STATISTICS = 1; + break; + case 'u': + USE_FAC_WHEN_UNATE = 0; + break; + case 'v': + ACT_ITE_DEBUG = atoi(util_optarg); + break; + default: + FREE(init_param); + (void) fprintf(sisout, "usage: ite_map_mroot [-o (or_gate_not_used)] [-h HEURISTIC_NUM] [-d DECOMP_FANIN] [-c (complete_matchin)] \n"); + (void) fprintf(sisout, "\t[-f FANIN_COLLAPSE] [F COLLAPSE_FANINS_OF_FANOUT] [-n NUM_ITER] [-s (STATISTICS)] [-L (last_gasp)] [-N (collapse_method NEW)]\n"); + (void) fprintf(sisout, "\t[-a (use bdd as alternate representation)] [-U (make collapse_update expensive)] [-v verbosity level]\n"); + (void) fprintf(sisout, "[-m MAP_METHOD 0:old,1:new,2:with_iter3:with_just_decomp] [-V new var selection method - lit count] HEURISTIC_NUM\t0 => ite, 1 => canonical ite (default 0)\n"); + (void) fprintf(sisout, "\t[-D (DECOMP_METHOD: use factored form)] \n"); + return 1; + } + } + /* some default values */ + /*---------------------*/ + init_param->mode = 0.0; + init_param->GAIN_FACTOR = 0.01; + + (void) act_ite_create_and_map_mroot_network(*network, init_param); + FREE(init_param); + return 0; +} + +com_act_ite_mux_network(network, argc, argv) + network_t **network; + int argc; + char **argv; +{ + int c; + float FAC_TO_SOP_RATIO; + act_init_param_t *init_param; + + init_param = ALLOC(act_init_param_t, 1); + + /* default */ + /*---------*/ + ACT_ITE_DEBUG = 0; + ACT_ITE_STATISTICS = 0; + act_is_or_used = 1; + init_param->HEURISTIC_NUM = 0; + init_param->FANIN_COLLAPSE = 3; + init_param->COLLAPSE_FANINS_OF_FANOUT = 15; + init_param->DECOMP_FANIN = 4; + init_param->NUM_ITER = 0; + init_param->COST_LIMIT = 3; + init_param->LAST_GASP = 0; + init_param->map_alg = 1; + init_param->lit_bound = 200; + init_param->ITE_FANIN_LIMIT_FOR_BDD = 40; + init_param->COLLAPSE_UPDATE = INEXPENSIVE; + init_param->COLLAPSE_METHOD = OLD; + init_param->DECOMP_METHOD = USE_GOOD_DECOMP; + init_param->ALTERNATE_REP = 0; /* do not use it */ + init_param->MAP_METHOD = NEW; + init_param->VAR_SELECTION_LIT = 15; + init_param->BREAK = 0; + + /* the default values are the ones which were used + before these variables were introduced */ + /*------------------------------------------------*/ + ACT_ITE_ALPHA = 2; + ACT_ITE_GAMMA = 1; + USE_FAC_WHEN_UNATE = 1; /* to be used with V > 0 */ + MAXOPTIMAL = 6; + FAC_TO_SOP_RATIO = 0.7; + + util_getopt_reset(); + while(( c = util_getopt(argc, argv, "A:C:F:G:M:R:V:b:d:f:h:l:m:n:v:DLNUacorsu")) != EOF){ + switch(c){ + case 'A': + ACT_ITE_ALPHA = atoi(util_optarg); + break; + case 'C': + init_param->COST_LIMIT = atoi(util_optarg); + break; + case 'D': + init_param->DECOMP_METHOD = USE_FACTOR; + break; + case 'F': + init_param->COLLAPSE_FANINS_OF_FANOUT = atoi(util_optarg); + break; + case 'G': + ACT_ITE_GAMMA = atoi(util_optarg); + break; + case 'L': + init_param->LAST_GASP = 1; + break; + case 'M': + MAXOPTIMAL = atoi(util_optarg); + break; + case 'N': + init_param->COLLAPSE_METHOD = NEW; + break; + case 'R': + FAC_TO_SOP_RATIO = atof(util_optarg); + break; + case 'U': + init_param->COLLAPSE_UPDATE = EXPENSIVE; + break; + case 'V': + init_param->VAR_SELECTION_LIT = atoi(util_optarg); + break; + case 'a': + init_param->ALTERNATE_REP = 1; + break; + case 'b': + init_param->ITE_FANIN_LIMIT_FOR_BDD = atoi(util_optarg); + break; + case 'c': + init_param->map_alg = 0; + break; + case 'd': + init_param->DECOMP_FANIN = atoi(util_optarg); + break; + case 'f': + init_param->FANIN_COLLAPSE = atoi(util_optarg); + break; + case 'h': + init_param->HEURISTIC_NUM = atoi(util_optarg); + if (init_param->HEURISTIC_NUM != 0) { + (void) printf("only -h 0 supported\n"); + return 1; + } + break; + case 'l': + init_param->lit_bound = atoi(util_optarg); + break; + case 'm': + init_param->MAP_METHOD = atoi(util_optarg); + break; + case 'n': + init_param->NUM_ITER = atoi(util_optarg); + break; + case 'o': + act_is_or_used = 0; + break; + case 'r': + init_param->BREAK = 1; + break; + case 's': + ACT_ITE_STATISTICS = 1; + break; + case 'u': + USE_FAC_WHEN_UNATE = 0; + break; + case 'v': + ACT_ITE_DEBUG = atoi(util_optarg); + break; + default: + FREE(init_param); + (void) fprintf(sisout, "usage: ite_mux [-o (or_gate_not_used)] [-h HEURISTIC_NUM] [-d DECOMP_FANIN] [-c (complete_matchin)] \n"); + (void) fprintf(sisout, "\t[-f FANIN_COLLAPSE] [F COLLAPSE_FANINS_OF_FANOUT] [-n NUM_ITER] [-s (STATISTICS)] [-L (last_gasp)] [-N (collapse_method NEW)]\n"); + (void) fprintf(sisout, "\t[-a (use bdd as alternate representation)] [-U (make collapse_update expensive)] [-v verbosity level]\n"); + (void) fprintf(sisout, "[-m MAP_METHOD 0:old,1:new,2:with_iter3:with_just_decomp] [-V new var selection method - lit count] HEURISTIC_NUM\t0 => ite, 1 => canonical ite (default 0)\n"); + (void) fprintf(sisout, "\t[-D (DECOMP_METHOD: use factored form)] [-R fac_to_sop_ratio]\n"); + return 1; + } + } + /* some default values */ + /*---------------------*/ + init_param->mode = 0.0; + init_param->GAIN_FACTOR = 0.01; + + (void) act_ite_mux_network(*network, init_param, FAC_TO_SOP_RATIO); + FREE(init_param); + return 0; +} + +int +com_act_bool_map_network(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + int map_alg; + int print_flag; + int act_is_or_used; /* though a global variable too - Added Jan 29 '93 */ + + /* default */ + /*---------*/ + map_alg = 1; /* do just algebraic matching */ + print_flag = 1; /* print the matches */ + act_is_or_used = 1; /* or gate is used */ + + util_getopt_reset(); + while(( c = util_getopt(argc, argv, "cop")) != EOF){ + switch(c){ + case 'c': + map_alg = 0; + break; + case 'o': + act_is_or_used = 0; + break; + case 'p': + print_flag = 0; + break; + default: + (void) fprintf(sisout, "usage: act_bool [-c (complete_matching)] [-p (do not print matches)]\n"); + return 1; + } + } + ACT_ITE_DEBUG = print_flag; /* put Jan 11 '93 */ + act_bool_map_network(*network, map_alg, act_is_or_used, print_flag); + return 0; +} + +init_ite() +{ + com_add_command("ite_map", com_act_ite_map, 1); + com_add_command("_ite_mux", com_act_ite_mux_network, 1); + com_add_command("_act_bool", com_act_bool_map_network, 0); + + node_register_daemon(DAEMON_ALLOC, act_ite_alloc); + node_register_daemon(DAEMON_FREE, act_ite_free); + +} + +end_ite() +{ +} + +void +act_ite_alloc(node) + node_t *node; +{ + ACT_ITE_COST_STRUCT *cost_node; + + cost_node = ALLOC(ACT_ITE_COST_STRUCT, 1); + cost_node->node = node; + cost_node->cost = 0; + cost_node->arrival_time = (double) 0.0; + cost_node->required_time = (double) 0.0; + cost_node->slack = (double) 0.0; + cost_node->is_critical = 0; + cost_node->area_weight = (double) 0.0; + cost_node->cost_and_arrival_time = (double) 0.0; + cost_node->ite = NIL(ite_vertex); + /* cost_node->will_ite = (char *) ite_alloc(); */ + cost_node->will_ite = NIL (char); + cost_node->act = NIL(ACT_VERTEX); /* added Feb 8, 1992 */ + cost_node->match = NIL (ACT_MATCH); + cost_node->network = NIL (network_t); + ACT_DEF_ITE_SLOT(node) = (char *) cost_node; +} + +void +act_ite_free(node) + node_t *node; +{ + ACT_ITE_COST_STRUCT *cost_node; + + cost_node = ACT_ITE_SLOT(node); + /* ite_free(cost_node->will_ite); */ + FREE(cost_node); +} + + + + diff --git a/sis/pld/com_pld.c b/sis/pld/com_pld.c new file mode 100644 index 0000000..f7940fc --- /dev/null +++ b/sis/pld/com_pld.c @@ -0,0 +1,1294 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/com_pld.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +static void print_partition_usage(); + +FILE *BDNET_FILE; +int ACT_DEBUG; +int ACT_STATISTICS; +int XLN_DEBUG = 0, XLN_BEST = 0; +int xln_use_best_subkernel; +int act_is_or_used; /* = 1 if the OR gate is to be exploited */ +int MAXOPTIMAL; + +/* traverse a DAG, executing the function manipuilate at each vertex +*/ +void +traverse(v, manipulate) +ACT_VERTEX_PTR v; +void (*manipulate)(); + +{ + v->mark = ( v->mark == 1) ? 0 : 1 ; + (*manipulate)(v); + if((v->index) != v->index_size){ + /* not a terminal vertex */ + if((v->mark)!=v->low->mark) traverse(v->low, manipulate); + if((v->mark)!=v->high->mark) traverse(v->high, manipulate); + } +} + +/* command line interpreter for the ULM_merge command + -Nishizaki*/ +/* command line interpreter for the ULM_merge command + -Nishizaki*/ +int +com_ULM_merge(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int MAX_FANIN, MAX_COMMON_FANIN, MAX_UNION_FANIN, support; + int c; + char filename[BUFSIZE]; + int fileflag, final_collapse_after_merge; + int verbose, use_lindo; + array_t *match1_array, *match2_array; + + /* default parameters */ + /*--------------------*/ + MAX_FANIN = 4; + MAX_COMMON_FANIN = 4; + MAX_UNION_FANIN = 5; + fileflag = 0; + verbose = 0; + use_lindo = 1; + support = 5; + final_collapse_after_merge = 1; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "f:c:n:u:o:Flv")) != EOF) { + switch(c) { + case 'f': + MAX_FANIN = atoi(util_optarg); + if (MAX_FANIN < 0) goto usage; + break; + case 'n': + support = atoi(util_optarg); + if (support < 2) goto usage; + break; + case 'c': + MAX_COMMON_FANIN = atoi(util_optarg); + if (MAX_COMMON_FANIN < 0) goto usage; + break; + case 'u': + MAX_UNION_FANIN = atoi(util_optarg); + if (MAX_UNION_FANIN < 0) goto usage; + break; + case 'o': + (void) strcpy (filename, util_optarg); + fileflag = 1; + break; + case 'l': + use_lindo = 0; + break; + case 'F': + final_collapse_after_merge = 0; + break; + case 'v': + verbose = 1; + break; + default: + goto usage; + } + } + if (argc - util_optind != 0) goto usage; + if (fileflag == 0) goto usage; + + match1_array = array_alloc(node_t *, 0); + match2_array = array_alloc(node_t *, 0); + merge_node(*network, MAX_FANIN, MAX_COMMON_FANIN, MAX_UNION_FANIN, filename, verbose, + use_lindo, match1_array, match2_array); + if (final_collapse_after_merge) { + if (verbose) (void) printf ("checking for collapses after merge...\n"); + st_free_table(xln_collapse_nodes_after_merge(*network, match1_array, match2_array, support, verbose)); + } + array_free(match1_array); + array_free(match2_array); + return 0; + +usage: + (void) fprintf(siserr, + "usage: xl_merge [-f MAX_FANIN] [-c MAX_COMMON_FANIN] [-u MAX_UNION_FANIN] [-n support] [-o filename] [-vlF]\n"); + (void) fprintf(siserr, + " -f \t\tMAX_FANIN is the limit on the fanin of a mergeable node(default = 4)\n"); + (void) fprintf(siserr, + " -c \t\tMAX_COMMON_FANIN is the limit on the common fanins of two mergeable nodes(default = 4)\n"); + (void) fprintf(siserr, + " -u \t\tMAX_UNION_FANIN is the limit on the union of the fanins of two mergeable nodes(default = 5)\n"); + (void)fprintf(siserr, " -n \t\tsupport\tfanin limit of nodes. (default = 5)\n"); + (void) fprintf(siserr, + " -o \t\tfilename is the file in which information about the nodes merged is printed. Must specify.\n"); + (void) fprintf(siserr, + " -l \t\tdo not use lindo, use a heuristic to solve max. card. matching.\n"); + (void) fprintf(siserr, + " -F \t\tdo not do further collapsing after matching pairs of nodes (default: do it).\n"); + (void) fprintf(siserr, + " -v \t\tverbosity option.\n"); + return 1; + + + +} + + + /*command line interpreter for the ULM_merge command */ +int +com_ULM_cover(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int bincov_heuristics; /* if 0, exact binate covering + if 1, Luciano's heuristic + if 2, Rajeev's heuristic - fast + and use for large networks. + if 3, automatically chooses 0 for a + small cover matrix, else chooses 2 */ + int c; + int n; /* added by Rajeev Dec. 27, 1989 - parameter to + partition_network routine -> instead of 5 */ + int cover_node_limit_exact; + int cover_node_limit_heur_upper; + + /* default */ + /*---------*/ + cover_node_limit_exact = 30; + cover_node_limit_heur_upper= 200; + bincov_heuristics = 3; + n = 5; + XLN_DEBUG = 0; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "n:h:e:u:d")) != EOF) { + switch(c) { + case 'n': + n = atoi(util_optarg); + break; + case 'e': + cover_node_limit_exact = atoi(util_optarg); + break; + case 'u': + cover_node_limit_heur_upper = atoi(util_optarg); + break; + case 'h': + bincov_heuristics = atoi(util_optarg); + break; + case 'd': + XLN_DEBUG = 1; + break; + + default: + goto usage; + } + } + if (argc - util_optind != 0) goto usage; + + if (bincov_heuristics == 3) { + if (network_num_internal(*network) <= cover_node_limit_exact) { + partition_network(*network, n, 0); + } else { + if (network_num_internal(*network) <= cover_node_limit_heur_upper) { + partition_network(*network, n, 3); + } + } + } else { + partition_network(*network, n, bincov_heuristics); + } + return 0; + +usage: + (void) fprintf(siserr, + "usage: xl_cover [-n number] [-h heuristic] [-e cover_node_limit_exact] [-u cover_node_limit_heur]\n"); + (void) fprintf(siserr, "-n \t\tlimit on the fanin\n"); + (void) fprintf(siserr, "-h 0,1,2,3 \tuses heuristics for binate covering problem\n"); + (void) fprintf(siserr, " - 0(exact), 1 (Luciano's heuristic), 2 (greedy - for large examples),\n\t 3(default)(automatically switches heuristic number depending on e and u values)\n"); + (void) fprintf(siserr, + "-e \t\tif h = 3, applies exact cover if number of nodes < number (Default 30)\n"); + (void) fprintf(siserr, + "-u \t\tif h = 3, applies heur 2 only if number of nodes < number (Default 200)\n"); + return 1; + + +} + +/* This a routine that helps find the number of nodes with fanins greater + * than the value 'value'. This is used mainly to keep tabs on the fanin + * restriction of the nodes in the network*/ +int +com__node_value(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + lsGen gen; + node_t *node; + int c, count, value; + + util_getopt_reset(); + count = 0; + + value = -1; + while((c = util_getopt(argc, argv,"v:")) != EOF){ + switch(c){ + case 'v': + value = atoi(util_optarg); + break; + default: + (void)fprintf(sisout, "usage: _xl_node_value -v \n"); + (void)fprintf(sisout, "-v should be followed by the fanin limit for the node\n"); + return 1; + } + } + if ( value < 1) return 1; + + + foreach_node(*network, gen, node){ + if ( node_num_fanin(node) >= value){ + count++; + (void)fprintf(sisout,"%s:%d ",node_name(node), + node_num_fanin(node)); + } + } + (void)fprintf(sisout,"\n%d nodes with fanin >= %d\n", count, value); + return 0; +} + +/* command line interpreter for the partition network command + * This is a routine that guarantees that the network will be + * partitioned into nodes with the fanin less than the value + * specified. This may be over kill at times! However this rou- + * tine in very parochial so to speak as it looks only for + * optimal parent child relationships and DOES not look at the + * whole network.*/ +int +com_partition(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int support=5; + int c; + int trivial_collapse_only = 0; /* does just a trivial collapse without creating infeasibilities*/ + int MOVE_FANINS = 0; + int MAX_FANINS = 15; + + util_getopt_reset(); + XLN_DEBUG=0; + while((c = util_getopt(argc, argv, "M:n:v:mt")) != EOF){ + switch(c) { + case 'm': + MOVE_FANINS = 1; + break; + case 'M': + MAX_FANINS = atoi(util_optarg); + if (MAX_FANINS > 31) { + (void) printf("**warning, MAX_FANINS > 31, making it 31\n"); + MAX_FANINS = 31; + } + break; + case 'n': + support = atoi(util_optarg); + break; + case 't': + trivial_collapse_only = 1; + break; + case 'v': + XLN_DEBUG = atoi(util_optarg); + break; + default: + print_partition_usage(); + return 0; + } + } + if(support <= 1){ + (void)fprintf(sisout, "Error, the partition parameter must be > 1\n"); + print_partition_usage(); + return 0; + } + if (trivial_collapse_only) { + (void) xln_do_trivial_collapse_network(*network, support, MOVE_FANINS, + MAX_FANINS); + return 0; + } + imp_part_network(*network, support, MOVE_FANINS, MAX_FANINS); + return 0; +} + +/* This routine is used to count the number of wires in the network. It + * can be used as an indication of the routing complexity of the present + * network. Hope to implement this in a good feedback loop for the system. + * Currently used to keep track of wirability !*/ + +int +com__count_nets(network) +network_t **network; +{ + int net_number; + + util_getopt_reset(); + net_number = estimate_net_no(*network); + (void)fprintf(sisout, "\n the number of nets is %d \n", net_number); + return 0; +} + + +/* This routine is used for an upper bound on the clbs for the current network. + * This does an and or decomposition and then partitions the network. It + * hoped that this estimate is good enough . DOes not change network*/ + +com__estimate_clb(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int upper_bound, value; + if(argc != 2) { + (void)fprintf(sisout, "Error in commamnd\n "); + (void)fprintf(sisout, "usage: _xl_clb n , n = maximum # of inputs to a CLB \n"); + return 1; + } + value = atoi(argv[argc-1]); + upper_bound = estimate_clb_no(*network, value); + (void)fprintf(sisout, "estimate is %d\n", upper_bound); + return 0; + +} + +/* karp decomposer*/ +com_karp_decomp(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + int support; /* cardinality of the bound set */ + node_t *node; + int just_one_node; + xln_init_param_t *init_param; + int MAX_FANINS_K_DECOMP; + int EXHAUSTIVE; + int RECURSIVE; + int DESPERATE; + + /* initialize */ + /*------------*/ + just_one_node = 0; + node = NIL (node_t); + support = 5; + MAX_FANINS_K_DECOMP = 7; + RECURSIVE = 0; + DESPERATE = 1; + EXHAUSTIVE = 0; + XLN_DEBUG = 0; + + util_getopt_reset(); + while(( c = util_getopt(argc, argv, "n:f:p:v:der")) != EOF){ + switch(c){ + case 'n': + support = atoi(util_optarg); + if (support < 2) { + (void)printf("Error: xl_k_decomp: violation*** 2 <=number: exiting \n"); + return 1; + } + break; + case 'p': + node = network_find_node(*network, util_optarg); + if (node == NIL (node_t)) { + (void)printf("Error: xl_k_decomp: node %s not found, try altname of the node\n", + util_optarg); + return 1; + } + if (node->type == PRIMARY_INPUT) { + (void)printf("Error: xl_k_decomp: node %s PI\n", util_optarg); + return 1; + } + if (node->type == PRIMARY_OUTPUT) node = node_get_fanin(node, 0); + just_one_node = 1; + break; + case 'f': + MAX_FANINS_K_DECOMP = atoi(util_optarg); + break; + case 'v': + XLN_DEBUG = atoi(util_optarg); + break; + case 'r': + RECURSIVE = 1; + break; + case 'e': + EXHAUSTIVE = 1; + break; + case 'd': + DESPERATE = 0; + break; + default: + (void) fprintf(sisout, "usage: xl_k_decomp [-n support] [-p nodename] [-v verbosity_level] [-f MAX_FANINS_K_DECOMP] [-der]\n"); + (void)fprintf(sisout, "-n\tsupport\tCardinality of bound set.\n"); + (void) fprintf(sisout, "-p\tnodename Node to decompose.\n"); + (void) fprintf(sisout, "-d\tif k_decomp fails, does not decomp node by cube-packing\n"); + (void) fprintf(sisout, "-r\trecursively decompose the node\n"); + (void) fprintf(sisout, "-e\tdo an exhaustive decomposition of the node\n"); + (void) fprintf(sisout, "-f\tMAX_FANINS_K_DECOMP\t use exhaustive k_decomp if number of fanins\n"); + (void) fprintf(sisout, "\tno more than this (default 7) and -e option was specified.\n"); + return 1; + } + } + assert(!(EXHAUSTIVE && just_one_node)); + init_param = ALLOC(xln_init_param_t, 1); + init_param->support = support; + init_param->MAX_FANINS_K_DECOMP = MAX_FANINS_K_DECOMP; + init_param->RECURSIVE = RECURSIVE; + init_param->DESPERATE = DESPERATE; + if (EXHAUSTIVE) { + xln_exhaustive_k_decomp_network(*network, init_param); + } else { + (void)karp_decomp_network(*network, support, just_one_node, node); + } + FREE(init_param); + return 0; +} + +/* And or map only : takes the network and does the and or decomp and + * partitions the network. A rather crude mapping of the network*/ + +com_and_or_map(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int size; + + if(argc != 2) { + (void)fprintf(sisout, "Error in command\n"); + (void)fprintf(sisout, "usage: _xl_do_clb n , n = # fanin to a CLB\n"); + return 1; + } + size = atoi(argv[argc-1]); + (void)and_or_map(*network, size); + return 0; +} + +/* This routine scans the network for nodes larger than size and splits them*/ +com_divide_network(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int size=5, c; + util_getopt_reset(); + XLN_DEBUG=0; + + while((c = util_getopt(argc, argv, "n:d")) != EOF){ + switch(c) { + case 'n': + size = atoi(util_optarg); + break; + case 'd': + XLN_DEBUG = 1; + break; + default: + (void)fprintf(sisout, "usage: xl_split -n -d \n"); + (void)fprintf(sisout, "\t-n upper limit on number of fanins (Default = 5)\n"); + (void)fprintf(sisout, "\t-d turns debug on\n"); + return 0; + } + } + if(size == 0){ + (void)fprintf(sisout, "Error, split parameter must be greater than zero\n"); + (void)fprintf(sisout, "usage: xl_split -n -d \n"); + (void)fprintf(sisout, "\t-n upper limit on number of fanins (Default = 5)\n"); + (void)fprintf(sisout, "\t-d turns debug on\n"); + return 0; + } + (void)split_network(*network, size); + return 0; +} + +static void +print_partition_usage() +{ + (void) fprintf(siserr, "usage: xl_partition [-n support] [-m (MOVE_FANINS)] [-M MAX_FANINS] [-t]\n"); + (void) fprintf(siserr, "n - #of inputs to each partition\n"); + (void) fprintf(siserr, "m - moves fanins of the node if collapsing is not feasible\n"); + (void) fprintf(siserr, "M - if m option used, moves fanins only if number of fanins at most the number (Default:15)\n"); + (void) fprintf(siserr, "t - collapse a node into all fanouts, if all of them remain feasible, delete node\n"); +} + + +com_act_main(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + st_table *cost_table; + int c; + + int NUM_ITER; /* maximum num of iterations before stopping - default 0*/ + float GAIN_FACTOR; /* go to next iteration only if the + gain > GAIN_FACTOR * network_cost - default 0.01*/ + int FANIN_COLLAPSE;/* only collapse those nodes whose fanin + is <= FANIN_COLLAPSE - default 3*/ + int DECOMP_FANIN; /* decomp nodes with fanin >= this - default 4*/ + int QUICK_PHASE; /* used if number of iterations = 0, and you + do/do not wish to perform QUICK_PHASE. + default= 0 - it will not be performed */ + int LAST_GASP; /* if non-zero, all the nodes in the network will be remapped */ + int BREAK; /* break the network such that each node realized by one basic + block; create a bdnet like file */ + int DISJOINT_DECOMP; /* do a disjoint decomposition of the network */ + int HEURISTIC_NUM; /* chooses the heuristic for building the + ACT. If = 1, constructs optimum ACT for nodes + less than 6 inputs; = 2 constructs "ACT" + using Narendra's heuristic (no longer ACT - + cofactor tree), = 3 a combination of the two, = 4 contructs both + subject graphs for each node, pick the one with lower cost.*/ + float mode; /* = 0.0 for AREA mode, 1.0 for DELAY mode, in between: weighted + sum */ + + char filename[BUFSIZE]; /* bdnet file name */ + int fileflag; + act_init_param_t *init_param; + + util_getopt_reset(); + init_param = ALLOC(act_init_param_t, 1); + /* default settings */ + /*------------------*/ + NUM_ITER = 0; + GAIN_FACTOR = 0.01; + FANIN_COLLAPSE = 3; + DECOMP_FANIN = 4; + QUICK_PHASE = 0; + BREAK = 0; + LAST_GASP = 0; + DISJOINT_DECOMP = 0; + HEURISTIC_NUM = 2; + ACT_STATISTICS = 0; + ACT_DEBUG = 0; + MAXOPTIMAL = 6; + mode = (float) AREA; + fileflag = 0; + act_is_or_used = 1; + + + /* input handler */ + /*---------------*/ + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "M:h:n:f:d:g:r:m:i:oqDlsv")) != EOF) { + switch (c) { + case 'M': + MAXOPTIMAL = atoi(util_optarg); + break; + case 'n': + NUM_ITER = atoi(util_optarg); + if (NUM_ITER < 0) { + (void) printf("num_iteration(%d) should be > 0\n", NUM_ITER); + return 1; + } + break; + case 'h': + HEURISTIC_NUM = atoi(util_optarg); + if ((HEURISTIC_NUM < 1) || (HEURISTIC_NUM > 4)) { + (void) printf("heuristic_num(%d) should be from 1 to 4\n", + HEURISTIC_NUM); + return 1; + } + break; + case 'f': + FANIN_COLLAPSE = atoi(util_optarg); + if (FANIN_COLLAPSE < 0) { + (void) printf("collapse_fanin_limit(%d) should be > 0\n", FANIN_COLLAPSE); + return 1; + } + break; + case 'd': + DECOMP_FANIN = atoi(util_optarg); + if (DECOMP_FANIN < 1) { + (void) printf("decomp_fanin(%d) should be > 0\n", DECOMP_FANIN); + return 1; + } + break; + case 'g': + GAIN_FACTOR = atof(util_optarg); + if ((GAIN_FACTOR < 0) || (GAIN_FACTOR > 1)) { + (void) printf("gain_factor(%f) should be from 0.0 to 1.0\n", GAIN_FACTOR); + return 1; + } + break; + case 'r': + BREAK = 1; + (void) strcpy(filename, util_optarg); + BDNET_FILE = fopen(filename, "w"); + if (BDNET_FILE == NULL) { + (void) printf(" **error** file %s cannot be opened\n", filename); + return 1; + } + break; + case 'm': + mode = atof(util_optarg); + if ( (mode > 1.0) || (mode < 0.0)) { + (void) printf("mode (%f) should be between 0.0 (AREA) and 1.0 (DELAY)\n", mode); + return 1; + } + break; + case 'i': + fileflag = 1; + (void) strcpy(init_param->delayfile, util_optarg); + break; + case 'q': + QUICK_PHASE = 1; + break; + case 'o': + act_is_or_used = 0; + break; + case 'l': + LAST_GASP = 1; + break; + case 'D': + DISJOINT_DECOMP = 1; + break; + case 's': + ACT_STATISTICS = 1; + break; + case 'v': + ACT_DEBUG = 1; + ACT_STATISTICS = 1; /* if ACT_DEBUG is 1, make ACT_STATISTICS also 1 */ + break; + default : + goto usage; + + } /* switch c */ + } /* while */ + + init_param->HEURISTIC_NUM = HEURISTIC_NUM; + init_param->NUM_ITER = NUM_ITER; + init_param->FANIN_COLLAPSE = FANIN_COLLAPSE; + init_param->GAIN_FACTOR = GAIN_FACTOR; + init_param->DECOMP_FANIN = DECOMP_FANIN; + init_param->DISJOINT_DECOMP = DISJOINT_DECOMP; + init_param->QUICK_PHASE = QUICK_PHASE; + init_param->LAST_GASP = LAST_GASP; + init_param->BREAK = BREAK; + init_param->mode = mode; + + if ((fileflag == 0) && (mode != 0.0)) goto usage; + cost_table = st_init_table(strcmp, st_strhash); + + *network = act_map_network(*network, init_param, cost_table); + (void) free_cost_table(cost_table); + st_free_table(cost_table); + if (!network_check(*network)) { + (void) printf("com_act_main():%s\n", error_string()); + exit(1); + } + if (init_param->BREAK) { + (void) fclose(BDNET_FILE); + } + FREE(init_param); + return 0; + +usage: + (void) printf(" usage: act_map [-h heuristic_num] [-m mode] [-n num_iteration] [-f collapse_fanin] [-M MAXOPTIMAL]\n"); + (void) printf(" \t\t[-g gain_factor] [-d decomp_fanin] [-r filename] [-i delayfile] [-qolDsv]\n"); + (void) printf(" -h\theuristic_num\tFor making subject-graphs (default = 2).\n"); + (void) printf(" \t\t\t\t1=>ROBDD, 2 =>BDD (cofactor-tree)\n"); + (void) printf(" \t\t\t\t3=>program decides, 4 => both 1 and 2\n"); + (void) printf(" -m\tmode\tChoose any real number between AREA (0.0) and DELAY (1.0) (default = 0.0).\n"); + (void) printf(" -n\tnum_iteration\tNumber of iterations (default = 0).\n"); + (void) printf(" -f\tcollapse_fanin\tUpper bound on fanin for collapse (default = 3).\n"); + (void) printf(" -M\tMAXOPTIMAL\tall possible orderings tried for ROBDD if number of fanins of the node <= MAXOPTIMAL (default = 6).\n"); + (void) printf(" -d\tdecomp_fanin\tLower bound on fanin for decomposition (default = 4).\n"); + (void) printf(" -g\tgain_factor\tCriterion for going to next iteration (default = 0.01).\n"); + (void) printf(" -r\tfilename\tFinal restructuring to be done and bdnet-like file.\n"); + (void) printf(" \t\t\t filename to be created. \n"); + (void) printf(" -i\tfilename\tdelayfile is the name of the file with info. about delay of\n"); + (void) printf(" \t\t\t a basic block for different fanouts. if mode != 0.0, must specify. \n"); + (void) printf(" -q\t\t\tQuick phase run before exiting.\n"); + (void) printf(" -o\t\t\tignore OR gate in the basic block.\n"); + (void) printf(" -l\t\t\tLast gasp: final shot at improving results.\n"); + (void) printf(" -D\t\t\tDisjoint decomposition done in the beginning.\n"); + (void) printf(" -s\t\t\tStatistics option.\n"); + (void) printf(" -v\t\t\tVerbosity option.\n"); + FREE(init_param); + return 1; +} + +com_xln_ao(network, argc, argv) + network_t **network; + int argc; + char **argv; +{ + int support, c; + + /* default */ + /*---------*/ + support = 5; + XLN_DEBUG = 0; + + util_getopt_reset(); + while(( c = util_getopt(argc, argv, "n:v:")) != EOF){ + switch(c){ + case 'n': + support = atoi(util_optarg); + if (support < 2) { + (void)printf("Error: xl_ao: violation*** 2 <=number: exiting \n"); + return 1; + } + break; + case 'v': + XLN_DEBUG = atoi(util_optarg); + break; + default: + (void) fprintf(sisout, "usage: xl_ao [-n number] [-v verbosity level]\n"); + (void)fprintf(sisout, "-n\tnumber\tfanin limit of nodes.\n"); + (void)fprintf(sisout, "-v\tverbosity level.\n"); + return 1; + } + } + xln_network_ao_map(*network, support); + return 0; +} + +com_xln_improve(network, argc, argv) + network_t **network; + int argc; + char **argv; +{ + int support, cover_node_limit, lit_bound, c; + int flag_decomp_good, good_or_fast, absorb; + int MOVE_FANINS, MAX_FANINS; + int RECURSIVE, DESPERATE, MAX_FANINS_K_DECOMP; + xln_init_param_t *init_param; + + /* default */ + /*---------*/ + support = 5; + cover_node_limit = 25; + lit_bound = 50; + flag_decomp_good = 0; + good_or_fast = GOOD; + absorb = 1; + RECURSIVE = 0; + DESPERATE = 1; + MAX_FANINS_K_DECOMP = 7; + MOVE_FANINS = 0; + MAX_FANINS = 15; + XLN_DEBUG = 0; + XLN_BEST = 0; + + util_getopt_reset(); + while(( c = util_getopt(argc, argv, "M:n:c:f:g:l:v:Aabdmr")) != EOF){ + switch(c){ + case 'n': + support = atoi(util_optarg); + if (support < 2) { + (void)printf("Error: xl_imp: violation*** 2 <=number: exiting \n"); + return 1; + } + break; + case 'm': + MOVE_FANINS = 1; + break; + case 'M': + MAX_FANINS = atoi(util_optarg); + if (MAX_FANINS > 31) { + (void) printf("**warning, MAX_FANINS > 31, making it 31\n"); + MAX_FANINS = 31; + } + break; + case 'a': + good_or_fast = FAST; + break; + case 'A': + absorb = 0; + break; + case 'c': + cover_node_limit = atoi(util_optarg); + break; + case 'l': + lit_bound = atoi(util_optarg); + break; + case 'v': + XLN_DEBUG = atoi(util_optarg); + break; + case 'b': + XLN_BEST = 1; + break; + case 'g': + flag_decomp_good = atoi(util_optarg); + break; + case 'd': + DESPERATE = 0; + break; + case 'r': + RECURSIVE = 1; + break; + case 'f': + MAX_FANINS_K_DECOMP = atoi(util_optarg); + break; + default: + (void) fprintf(sisout, "usage: xl_imp [-n number] [-c cover_node_limit] [-l lit_bound]\n"); + (void) fprintf(sisout, "\t [-g flag_decomp_good][-r (REC)] [-f MAX_FANINS_K_DECOMP]\n"); + (void) fprintf(sisout, "\t [-d(DESP)][-v verbosity level] [-A(don't move fanins after decomp -g)]\n"); + (void) fprintf(sisout, "\t [-a(don't try all decompositions)] [-m (MOVE_FANINS)][-M MAX_FANINS]\n"); + (void)fprintf(sisout, "-n\tnumber\tfanin limit of nodes.\n"); + (void)fprintf(sisout, "-c\tcover_node_limit exact cover of node till these many nodes.\n"); + (void)fprintf(sisout, "-l\tnum_literals > lit_bound => good decompose the node.\n"); + (void) fprintf(siserr, "-m\tmoves fanins of the node if collapsing is not feasible\n"); + (void) fprintf(siserr, "-M\tif m option used, moves fanins only if number of fanins at most the number (Default:15)\n"); + (void)fprintf(sisout, "-v\tverbosity level.\n"); + return 1; + } + } + + init_param = ALLOC(xln_init_param_t, 1); + init_param->support = support; + init_param->cover_node_limit = cover_node_limit; + init_param->lit_bound = lit_bound; + init_param->flag_decomp_good = flag_decomp_good; + init_param->good_or_fast = good_or_fast; + init_param->absorb = absorb; + init_param->DESPERATE = DESPERATE; + init_param->RECURSIVE = RECURSIVE; + init_param->MAX_FANINS_K_DECOMP = MAX_FANINS_K_DECOMP; + init_param->xln_move_struct.MOVE_FANINS = MOVE_FANINS; + init_param->xln_move_struct.MAX_FANINS = MAX_FANINS; + xln_improve_network(*network, init_param); + FREE(init_param); + return 0; +} + +com_xln_reduce_levels(network, argc, argv) + network_t **network; + int argc; + char **argv; +{ + int support, heur, c; + int MAX_FANINS, MOVE_FANINS, bound_alphas; + int collapse_input_limit; + int traversal_method; /* 1 then topological traversal, else levels sorted wrt width */ + xln_init_param_t *init_param; + + /* default */ + /*---------*/ + support = 5; + XLN_DEBUG = 0; + heur = 1; + MAX_FANINS = 15; + MOVE_FANINS = 1; + bound_alphas = 1; + collapse_input_limit = 10; + traversal_method = 1; + + util_getopt_reset(); + while(( c = util_getopt(argc, argv, "c:n:v:h:M:A:mt")) != EOF){ + switch(c){ + case 'n': + support = atoi(util_optarg); + if (support < 2) { + (void)printf("Error: xl_rl: violation*** 2 <=number: exiting \n"); + return 1; + } + break; + case 'v': + XLN_DEBUG = atoi(util_optarg); + break; + case 'h': + heur = atoi(util_optarg); + break; + case 'c': + collapse_input_limit = atoi(util_optarg); + break; + case 'M': + MAX_FANINS = atoi(util_optarg); + break; + case 'A': + bound_alphas = atoi(util_optarg); + break; + case 'm': + MOVE_FANINS = 0; + break; + case 't': + traversal_method = 0; + break; + default: + (void) fprintf(sisout, "usage:xl_rl [-n number] [-v verbosity level]\n"); + (void) fprintf(sisout, "\t[-m (DONT_MOVE_FANINS)] [-M MAX_FANINS] [-h heur]\n"); + (void) fprintf(sisout, "\t[-t (trav_method-levels)] [-c collapse_input_limit]\n"); + (void)fprintf(sisout, "-n\tnumber\tfanin limit of nodes.\n"); + (void)fprintf(sisout, "-h\theur\t1=>collapse into any fanout, 2=> collapse into critical fanouts\n"); + (void)fprintf(sisout, "-c\tnumber\tconsider collapsing of network if PI's less (def = 10).\n"); + (void) fprintf(siserr, "-m\tmoves fanins of the node if collapsing is not feasible\n"); + (void) fprintf(siserr, "-M\tif m option used, moves fanins only if number of fanins at most the number (Default:15\n"); + (void) fprintf(siserr, "-t\ttraverse the network by levels instead of topologically\n"); + (void)fprintf(sisout, "-v\tverbosity level.\n"); + return 1; + } + } + init_param = ALLOC(xln_init_param_t, 1); + init_param->support = support; + init_param->heuristic = heur; /* overuse of heuristic */ + init_param->collapse_input_limit = collapse_input_limit; + init_param->traversal_method = traversal_method; + init_param->xln_move_struct.MOVE_FANINS = MOVE_FANINS; + init_param->xln_move_struct.MAX_FANINS = MAX_FANINS; + init_param->xln_move_struct.bound_alphas = bound_alphas; + assert(bound_alphas == 1); + xln_reduce_levels(network, init_param); + FREE(init_param); + return 0; +} + +com_xln_partial_collapse(network, argc, argv) + network_t **network; + int argc; + char **argv; +{ + int size, c; + int COST_LIMIT, cover_node_limit, lit_bound, flag_decomp_good, good_or_fast; + int MOVE_FANINS, MAX_FANINS; + int absorb; + xln_init_param_t *init_param; + + /* default */ + /*---------*/ + size = 5; + COST_LIMIT = 1; + cover_node_limit = 15; + lit_bound = 50; + flag_decomp_good = 0; + good_or_fast = FAST; + absorb = 0; + MOVE_FANINS = 0; + MAX_FANINS = 15; + XLN_DEBUG = 0; + + util_getopt_reset(); + while(( c = util_getopt(argc, argv, "M:n:C:v:c:g:l:bamA")) != EOF){ + switch(c){ + case 'n': + size = atoi(util_optarg); + if (size < 2) { + (void)printf("Error: xl_part_coll: violation*** 2 <=number: exiting \n"); + return 1; + } + break; + case 'm': + MOVE_FANINS = 1; + break; + case 'M': + MAX_FANINS = atoi(util_optarg); + if (MAX_FANINS > 31) { + (void) printf("**warning, MAX_FANINS > 31, making it 31\n"); + MAX_FANINS = 31; + } + break; + case 'v': + XLN_DEBUG = atoi(util_optarg); + break; + case 'b': + XLN_BEST = 1; + break; + case 'g': + flag_decomp_good = atoi(util_optarg); + break; + case 'a': + good_or_fast = 1; + break; + case 'A': + absorb = 1; + break; + case 'C': + COST_LIMIT = atoi(util_optarg); + break; + case 'c': + cover_node_limit = atoi(util_optarg); + break; + case 'l': + lit_bound = atoi(util_optarg); + break; + default: + (void) fprintf(sisout, "usage: xl_part_coll [-n number] [-C cost_limit] [-b]"); + (void) fprintf(sisout, " [-c cover_node_limit] [-l lit_bound] [-v verbosity level]\n"); + (void) fprintf(sisout, " [-g (flag_decomp_good)] [-a (apply all_decomp_schemes)]\n"); + (void) fprintf(sisout, " [-A (move fanins after decomp -g)] [-m (MOVE_FANINS)] [-M (MAX_FANINS)]\n"); + (void)fprintf(sisout, "-n\tnumber\tfanin limit of nodes.\n"); + (void)fprintf(sisout, "-C\tcost_limit\tnode with higher cost not to be collapsed\n"); + (void) fprintf(siserr, "-m\tmoves fanins of the node if collapsing is not feasible\n"); + (void) fprintf(siserr, "-M\tif m option used, moves fanins only if number of fanins at most the number (Default:15\n"); + (void)fprintf(sisout, "-c\tcover_node_limit exact cover of node till these many nodes.\n"); + (void)fprintf(sisout, "-l\t num_literals > lit_bound => good decompose the node.\n"); + (void)fprintf(sisout, "-v\tverbosity level.\n"); + (void)fprintf(sisout, "-b\ttry best mapping: large node => recursively decomp\n"); + return 1; + } + } + + init_param = ALLOC(xln_init_param_t, 1); + init_param->support = size; + init_param->COST_LIMIT = COST_LIMIT; /* node has higher cost => do not collapse */ + init_param->cover_node_limit = cover_node_limit; + init_param->lit_bound = lit_bound; + init_param->good_or_fast = good_or_fast; + init_param->absorb = absorb; + init_param->flag_decomp_good = flag_decomp_good; + init_param->RECURSIVE = 0; + init_param->DESPERATE= 1; + init_param->MAX_FANINS_K_DECOMP = 7; + init_param->xln_move_struct.MOVE_FANINS = MOVE_FANINS; + init_param->xln_move_struct.MAX_FANINS = MAX_FANINS; + xln_partial_collapse(*network, init_param); + FREE(init_param); + return 0; +} + +int +com_xln_decomp_for_merging_network(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + xln_init_param_t *init_param; + + init_param = ALLOC(xln_init_param_t, 1); + + /* default parameters */ + /*--------------------*/ + init_param->MAX_FANIN = 4; + init_param->MAX_COMMON_FANIN = 4; + init_param->MAX_UNION_FANIN = 5; + init_param->support = 5; + init_param->heuristic = ALL_CUBES; + init_param->common_lower_bound = 2; + init_param->cube_support_lower_bound = 4; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "f:c:n:u:h:l:L:v")) != EOF) { + switch(c) { + case 'f': + init_param->MAX_FANIN = atoi(util_optarg); + if (init_param->MAX_FANIN < 0) goto usage; + break; + case 'c': + init_param->MAX_COMMON_FANIN = atoi(util_optarg); + if (init_param->MAX_COMMON_FANIN < 0) goto usage; + break; + case 'u': + init_param->MAX_UNION_FANIN = atoi(util_optarg); + if (init_param->MAX_UNION_FANIN < 0) goto usage; + break; + case 'n': + init_param->support = atoi(util_optarg); + if (init_param->support < 0) goto usage; + break; + case 'h': + init_param->heuristic = atoi(util_optarg); + if ((init_param->heuristic < 1) || (init_param->heuristic > 2)) + goto usage; + break; + case 'l': + init_param->common_lower_bound = atoi(util_optarg); + break; + case 'L': + init_param->cube_support_lower_bound = atoi(util_optarg); + break; + case 'v': + XLN_DEBUG = 1; + break; + default: + goto usage; + } + } + if (argc - util_optind != 0) goto usage; + + xln_decomp_for_merging_network(*network, init_param); + FREE(init_param); + return 0; + +usage: + (void) fprintf(siserr, + "usage: xl_decomp_two [-f MAX_FANIN] [-c MAX_COMMON_FANIN] [-u MAX_UNION_FANIN]\n"); + (void) fprintf(siserr, + "\t\t\t[-n support] [-h heuristic] [-l lower_common_bound]\n"); + (void) fprintf(siserr, "\t\t\t[-L cube_support_lower_bound] [-v]\n"); + (void) fprintf(siserr, + " -f\t\tMAX_FANIN is the limit on the fanin of a mergeable node(default = 4)\n"); + (void) fprintf(siserr, + " -c\t\tMAX_COMMON_FANIN is the limit on the common fanins of two mergeable nodes(default = 4)\n"); + (void) fprintf(siserr, + " -u\t\tMAX_UNION_FANIN is the limit on the union of the fanins of two mergeable nodes(default = 5)\n"); + (void)fprintf(sisout, "-n\tnumber\tfanin limit of nodes. (default = 5)\n"); + (void)fprintf(sisout, "-h\theuristic\t 1 = ALL_CUBES, 2 = PAIR_NODES. (default = 1)\n"); + (void)fprintf(sisout, "-l\tlower_common_bound\t(default = 2)\n"); + (void)fprintf(sisout, "-L\tcube-support lower bound\t(default = 4)\n"); + (void) fprintf(siserr, "-v\tverbosity option.\n"); + FREE(init_param); + return 1; +} + +int +com_xln_absorb_nodes_in_fanins(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + int support; + int method; + int MAX_FANINS; + + /* default parameters */ + /*--------------------*/ + support = 5; + XLN_DEBUG = 0; + method = 1; /* move_fanin, not absorb */ + MAX_FANINS = 15; /* do not look at a node with higher fanins */ + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "f:m:n:v")) != EOF) { + switch(c) { + case 'f': + MAX_FANINS = atoi(util_optarg); + if (MAX_FANINS > 31) { + (void) printf("**warning--- can't have MAX_FANINS > 31, making it 31\n"); + MAX_FANINS = 31; + } + break; + case 'm': + method = atoi(util_optarg); + if ((method > 1) || (method < 0)) goto usage; + break; + case 'n': + support = atoi(util_optarg); + if (support < 2) goto usage; + break; + case 'v': + XLN_DEBUG = 1; + break; + default: + goto usage; + } + } + if (argc - util_optind != 0) goto usage; + if (method) { + xln_network_reduce_infeasibility_by_moving_fanins(*network, support, MAX_FANINS); + } + else { + xln_absorb_nodes_in_fanins(*network, support); + } + return 0; + +usage: + (void) fprintf(siserr, "xln_absorb \t[-n support] [-m method] [-f MAX_FANINS] [-v]\n"); + (void)fprintf(sisout, "-n\tsupport\tfanin limit of nodes. (default = 5)\n"); + (void)fprintf(sisout, "-f\tMAX_FANINS\t don't consider nodes above these fanins(default = 15)\n"); + (void)fprintf(sisout, "-m\tmethod\t0 => absorb, 1 => move fanins (default = 1)\n"); + (void) fprintf(siserr, "-v \tverbosity option.\n"); + return 1; +} + +int +com_xln_collapse_check_area(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + int support; + int collapse_input_limit; + int roth_karp_flag; + xln_init_param_t *init_param; + + /* default parameters */ + /*--------------------*/ + support = 5; + XLN_DEBUG = 0; + collapse_input_limit = 9; + roth_karp_flag = 1; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "c:n:kv")) != EOF) { + switch(c) { + case 'c': + collapse_input_limit = atoi(util_optarg); + break; + case 'n': + support = atoi(util_optarg); + if (support < 2) goto usage; + break; + case 'v': + XLN_DEBUG = 1; + break; + case 'k': + roth_karp_flag = 0; /* do not do roth-karp */ + break; + default: + goto usage; + } + } + if (argc - util_optind != 0) goto usage; + init_param = ALLOC(xln_init_param_t, 1); + init_param->support = support; + init_param->collapse_input_limit = collapse_input_limit; + xln_collapse_check_area(network, init_param, roth_karp_flag); + FREE(init_param); + return 0; + +usage: + (void) fprintf(siserr, "xl_coll_ck \t[-n support] [-c input_collapse_lim] [-k (don't roth)] [-v]\n"); + (void)fprintf(sisout, "-n\tsupport\tfanin limit of nodes. (default = 5)\n"); + (void)fprintf(sisout, "-c\tcollapse\t use cofactor and roth-karp(default = 9)\n"); + (void) fprintf(siserr, "-v \tverbosity option.\n"); + return 1; +} + +/* init routines*/ +init_pld() +{ + extern int init_ite(), end_ite(); + + com_add_command("act_map", com_act_main, 1); + + node_register_daemon(DAEMON_ALLOC, p_actAlloc); + node_register_daemon(DAEMON_FREE, p_actFree); + node_register_daemon(DAEMON_DUP, p_actDup); + + /* old xilinx commands */ + /*---------------------*/ + com_add_command("xl_partition", com_partition, 1); + com_add_command("xl_merge", com_ULM_merge, 1); + com_add_command("xl_cover", com_ULM_cover, 1); + com_add_command("xl_k_decomp", com_karp_decomp, 1); + com_add_command("xl_split", com_divide_network, 1); + com_add_command("_xl_nodevalue", com__node_value, 0); + com_add_command("_xl_cnets", com__count_nets, 0); + com_add_command("_xl_clb", com__estimate_clb, 0); + com_add_command("_xl_do_clb", com_and_or_map, 1); + + /* new xilinx commands */ + /*---------------------*/ + com_add_command("xl_imp", com_xln_improve, 1); + com_add_command("xl_rl", com_xln_reduce_levels, 1); + com_add_command("xl_ao", com_xln_ao, 1); + com_add_command("xl_decomp_two", com_xln_decomp_for_merging_network, 1); + com_add_command("xl_part_coll", com_xln_partial_collapse, 1); + com_add_command("xl_absorb", com_xln_absorb_nodes_in_fanins, 1); + com_add_command("xl_coll_ck", com_xln_collapse_check_area, 1); + + init_ite(); +} + +end_pld() +{ + end_ite(); +} + diff --git a/sis/pld/ite_break.c b/sis/pld/ite_break.c new file mode 100644 index 0000000..46a1649 --- /dev/null +++ b/sis/pld/ite_break.c @@ -0,0 +1,841 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + +act_ite_break_network(network, init_param) + network_t *network; + act_init_param_t *init_param; +{ + array_t *nodevec; + int i; + /* int is_one; */ /* = 1 if the node has cost > 2 */ + node_t *node; + + num_or_patterns = 0; + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) continue; + /* is_one = act_ite_break_node(node, init_param); */ + (void) act_ite_break_node(node, init_param); + } + if (ACT_ITE_DEBUG > 4) assert(network_check(network)); + array_free(nodevec); +} + +/*--------------------------------------------------------------------------- + Given the node, breaks it up into many nodes, each with cost 1. + Based on the bdd at that node. Network is changed. New nodes may be added + and the functionality of the node may change. Also, breaks the bdd (act) + in the cost_node and puts their appropriate parts in the node. After the + bdd is broken, all the new bdd's are trees (not even leaf dag's). All the + multiple fo points are duplicated. Care has to be taken for all the nodes + so that name at the bdd's are correct. +----------------------------------------------------------------------------*/ +int +act_ite_break_node(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + + network_t *network; + node_t *node1, *node_returned; + ACT_ITE_COST_STRUCT *cost_struct; + node_function_t node_fun; + + network = node_network(node); + node_fun = node_function(node); + if ((node_fun == NODE_PI) || (node_fun == NODE_PO)) return 0; + + if (init_param->MAP_METHOD == MAP_WITH_ITER || init_param->MAP_METHOD == MAP_WITH_JUST_DECOMP) { + if (ACT_ITE_SLOT(node)->network) { + if (ACT_ITE_SLOT(node)->cost != 1) { + pld_replace_node_by_network(node, ACT_ITE_SLOT(node)->network); + } + network_free(ACT_ITE_SLOT(node)->network); + ACT_ITE_SLOT(node)->network = NIL (network_t); + assert(ACT_ITE_SLOT(node)->ite == NIL (ite_vertex)); + return 1; + } + assert(node_fun == NODE_0 || node_fun == NODE_1 || node_fun == NODE_BUF); + return 0; /* cost should be at most 0 */ + } + + cost_struct = ACT_ITE_SLOT(node); + if (cost_struct->cost <= 1) return 0; + if (cost_struct->act) return (act_new_act_break_node(node)); + + PRESENT_ITE = cost_struct->ite; + ite_reset_mark_ite(PRESENT_ITE); + ite_set_MARK_VALUE_ite(PRESENT_ITE); + if (ACT_ITE_DEBUG) ite_check_ite(PRESENT_ITE, node); + + node_returned = act_ite_get_function(network, node, PRESENT_ITE); + node1 = node_get_fanin(node_returned, 0); + node_free(node_returned); + + /* all the multiple fo vertices had a node in the node field. Free that node */ + /*---------------------------------------------------------------------------*/ + ite_set_MARK_VALUE_ite(PRESENT_ITE); + ite_free_nodes_in_multiple_fo_ite(PRESENT_ITE); + /* free the structure of node */ + /*----------------------------*/ + ite_my_free(cost_struct->ite); + cost_struct->ite = NIL (ite_vertex); /* without it, no good */ + node_replace(node, node1); + + return 1; +} + +/************************************************************************************** + Given a node and its corresponding ACT(OACT), breaks the node into nodes, each + new node realizing a function that can be implemented by one basic block. Puts all + these nodes in the network. Original node is changed. +***************************************************************************************/ +node_t * +act_ite_get_function(network, node, vertex) + network_t *network; + node_t *node; + ite_vertex_ptr vertex; +{ + + node_t *node1, *node2, *ELSE_THEN, *ELSE_ELSE, *ELSE_IF, *ELSE_ELSE_IF, *ELSE_ELSE_THEN, *ELSE_ELSE_ELSE; + node_t *IF, *THEN, *ELSE, *IF_THEN, *IF_ELSE, *IF_IF, *THEN_THEN, *THEN_ELSE, *THEN_IF; + + /* vertex->node corresponds to the node at the vertex - only for the + multiple_fanout vertex */ + /*-----------------------------------------------------------------*/ + + if (vertex->value == 0) { + vertex->mark = MARK_COMPLEMENT_VALUE; + return node_constant(0); + } + if (vertex->value == 1) { + vertex->mark = MARK_COMPLEMENT_VALUE; + return node_constant(1); + } + + + if (vertex->mark == MARK_COMPLEMENT_VALUE) { + if (vertex->multiple_fo == 0) { + (void) printf("error: act_ite_get_function()\n"); + exit(1); + } + return vertex->node; + } + + /* added April 4, 1991*/ + /*-------------------*/ + if (!act_is_or_used) { + assert(vertex->pattern_num < 4); + } + + /* even multiple fo vertices will be broken when visited first time */ + /*------------------------------------------------------------------*/ + vertex->mark = MARK_COMPLEMENT_VALUE; + + if (vertex->value == 2 && vertex->phase == 1) { + node1 = ite_get_node_literal_of_vertex(vertex); + if (vertex->multiple_fo != 0) vertex->node = node1; + return node1; + } + /* handle inverter */ + /*-----------------*/ + if (vertex->value == 2 && vertex->phase == 0) { + assert(vertex->pattern_num == 0); + node1 = node_literal(vertex->fanin, 0); + if (vertex->multiple_fo != 0) vertex->node = node1; + return node1; + } + + /* vertex->value = 3 */ + /* if simply an input variable, handle separately */ + /*------------------------------------------------*/ + if ((vertex->IF->value == 2) && (vertex->IF->phase == 1) + && (vertex->THEN->value == 1) && (vertex->ELSE->value == 0)) { + vertex->IF->mark = MARK_COMPLEMENT_VALUE; + vertex->THEN->mark = MARK_COMPLEMENT_VALUE; + vertex->ELSE->mark = MARK_COMPLEMENT_VALUE; + node1 = ite_get_node_literal_of_vertex(vertex->IF); + if (vertex->multiple_fo != 0) vertex->node = node1; + return node1; + } + + if (vertex->pattern_num > 3) num_or_patterns++; + + switch(vertex->pattern_num) { + + case 0: + IF = act_ite_get_function(network, node, vertex->IF); + THEN = act_ite_get_function(network, node, vertex->THEN); + ELSE = act_ite_get_function(network, node, vertex->ELSE); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ITE != vertex) { + network_add_node(network, node1); + } + + ite_free_node_if_possible(IF, vertex->IF); + ite_free_node_if_possible(THEN, vertex->THEN); + ite_free_node_if_possible(ELSE, vertex->ELSE); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 1: + vertex->THEN->mark = MARK_COMPLEMENT_VALUE; + THEN_IF = act_ite_get_function(network, node, vertex->THEN->IF); + THEN_THEN = act_ite_get_function(network, node, vertex->THEN->THEN); + THEN_ELSE = act_ite_get_function(network, node, vertex->THEN->ELSE); + THEN = act_mux_node(THEN_IF, THEN_ELSE, THEN_THEN); + IF = act_ite_get_function(network, node, vertex->IF); + ELSE = act_ite_get_function(network, node, vertex->ELSE); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ITE != vertex) { + network_add_node(network, node1); + } + + ite_free_node_if_possible(IF, vertex->IF); + ite_free_node_if_possible(ELSE, vertex->ELSE); + ite_free_node_if_possible(THEN_IF, vertex->THEN->IF); + ite_free_node_if_possible(THEN_THEN, vertex->THEN->THEN); + ite_free_node_if_possible(THEN_ELSE, vertex->THEN->ELSE); + node_free(THEN); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 2: + vertex->ELSE->mark = MARK_COMPLEMENT_VALUE; + ELSE_IF = act_ite_get_function(network, node, vertex->ELSE->IF); + ELSE_ELSE = act_ite_get_function(network, node, vertex->ELSE->ELSE); + ELSE_THEN = act_ite_get_function(network, node, vertex->ELSE->THEN); + ELSE = act_mux_node(ELSE_IF, ELSE_ELSE, ELSE_THEN); + IF = act_ite_get_function(network, node, vertex->IF); + THEN = act_ite_get_function(network, node, vertex->THEN); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ITE != vertex) { + network_add_node(network, node1); + } + + ite_free_node_if_possible(IF, vertex->IF); + ite_free_node_if_possible(THEN, vertex->THEN); + ite_free_node_if_possible(ELSE_IF, vertex->ELSE->IF); + ite_free_node_if_possible(ELSE_ELSE, vertex->ELSE->ELSE); + ite_free_node_if_possible(ELSE_THEN, vertex->ELSE->THEN); + node_free(ELSE); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 3: + vertex->THEN->mark = MARK_COMPLEMENT_VALUE; + vertex->ELSE->mark = MARK_COMPLEMENT_VALUE; + + THEN_IF = act_ite_get_function(network, node, vertex->THEN->IF); + THEN_THEN = act_ite_get_function(network, node, vertex->THEN->THEN); + THEN_ELSE = act_ite_get_function(network, node, vertex->THEN->ELSE); + THEN = act_mux_node(THEN_IF, THEN_ELSE, THEN_THEN); + + ELSE_IF = act_ite_get_function(network, node, vertex->ELSE->IF); + ELSE_ELSE = act_ite_get_function(network, node, vertex->ELSE->ELSE); + ELSE_THEN = act_ite_get_function(network, node, vertex->ELSE->THEN); + ELSE = act_mux_node(ELSE_IF, ELSE_ELSE, ELSE_THEN); + + IF = act_ite_get_function(network, node, vertex->IF); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ITE != vertex) { + network_add_node(network, node1); + } + + ite_free_node_if_possible(IF, vertex->IF); + ite_free_node_if_possible(THEN_IF, vertex->THEN->IF); + ite_free_node_if_possible(THEN_THEN, vertex->THEN->THEN); + ite_free_node_if_possible(THEN_ELSE, vertex->THEN->ELSE); + ite_free_node_if_possible(ELSE_IF, vertex->ELSE->IF); + ite_free_node_if_possible(ELSE_ELSE, vertex->ELSE->ELSE); + ite_free_node_if_possible(ELSE_THEN, vertex->ELSE->THEN); + node_free(THEN); + node_free(ELSE); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 4: + vertex->IF->mark = MARK_COMPLEMENT_VALUE; + IF_IF = act_ite_get_function(network, node, vertex->IF->IF); + IF_THEN = act_ite_get_function(network, node, vertex->IF->THEN); + IF_ELSE = act_ite_get_function(network, node, vertex->IF->ELSE); + IF = act_mux_node(IF_IF, IF_ELSE, IF_THEN); + THEN = act_ite_get_function(network, node, vertex->THEN); + ELSE = act_ite_get_function(network, node, vertex->ELSE); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ITE != vertex) { + network_add_node(network, node1); + } + + ite_free_node_if_possible(IF_IF, vertex->IF->IF); + ite_free_node_if_possible(IF_THEN, vertex->IF->THEN); + ite_free_node_if_possible(IF_ELSE, vertex->IF->ELSE); + ite_free_node_if_possible(THEN, vertex->THEN); + ite_free_node_if_possible(ELSE, vertex->ELSE); + node_free(IF); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 5: + vertex->IF->mark = MARK_COMPLEMENT_VALUE; + vertex->THEN->mark = MARK_COMPLEMENT_VALUE; + + IF_IF = act_ite_get_function(network, node, vertex->IF->IF); + IF_THEN = act_ite_get_function(network, node, vertex->IF->THEN); + IF_ELSE = act_ite_get_function(network, node, vertex->IF->ELSE); + IF = act_mux_node(IF_IF, IF_ELSE, IF_THEN); + + THEN_IF = act_ite_get_function(network, node, vertex->THEN->IF); + THEN_THEN = act_ite_get_function(network, node, vertex->THEN->THEN); + THEN_ELSE = act_ite_get_function(network, node, vertex->THEN->ELSE); + THEN = act_mux_node(THEN_IF, THEN_ELSE, THEN_THEN); + + ELSE = act_ite_get_function(network, node, vertex->ELSE); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ITE != vertex) { + network_add_node(network, node1); + } + + ite_free_node_if_possible(IF_IF, vertex->IF->IF); + ite_free_node_if_possible(IF_THEN, vertex->IF->THEN); + ite_free_node_if_possible(IF_ELSE, vertex->IF->ELSE); + ite_free_node_if_possible(ELSE, vertex->ELSE); + ite_free_node_if_possible(THEN_IF, vertex->THEN->IF); + ite_free_node_if_possible(THEN_THEN, vertex->THEN->THEN); + ite_free_node_if_possible(THEN_ELSE, vertex->THEN->ELSE); + node_free(IF); + node_free(THEN); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 6: + vertex->IF->mark = MARK_COMPLEMENT_VALUE; + vertex->ELSE->mark = MARK_COMPLEMENT_VALUE; + + IF_IF = act_ite_get_function(network, node, vertex->IF->IF); + IF_THEN = act_ite_get_function(network, node, vertex->IF->THEN); + IF_ELSE = act_ite_get_function(network, node, vertex->IF->ELSE); + IF = act_mux_node(IF_IF, IF_ELSE, IF_THEN); + + ELSE_IF = act_ite_get_function(network, node, vertex->ELSE->IF); + ELSE_ELSE = act_ite_get_function(network, node, vertex->ELSE->ELSE); + ELSE_THEN = act_ite_get_function(network, node, vertex->ELSE->THEN); + ELSE = act_mux_node(ELSE_IF, ELSE_ELSE, ELSE_THEN); + + THEN = act_ite_get_function(network, node, vertex->THEN); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ITE != vertex) { + network_add_node(network, node1); + } + + ite_free_node_if_possible(IF_IF, vertex->IF->IF); + ite_free_node_if_possible(IF_THEN, vertex->IF->THEN); + ite_free_node_if_possible(IF_ELSE, vertex->IF->ELSE); + ite_free_node_if_possible(THEN, vertex->THEN); + ite_free_node_if_possible(ELSE_IF, vertex->ELSE->IF); + ite_free_node_if_possible(ELSE_ELSE, vertex->ELSE->ELSE); + ite_free_node_if_possible(ELSE_THEN, vertex->ELSE->THEN); + node_free(IF); + node_free(ELSE); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 7: + vertex->IF->mark = MARK_COMPLEMENT_VALUE; + vertex->THEN->mark = MARK_COMPLEMENT_VALUE; + vertex->ELSE->mark = MARK_COMPLEMENT_VALUE; + + IF_IF = act_ite_get_function(network, node, vertex->IF->IF); + IF_THEN = act_ite_get_function(network, node, vertex->IF->THEN); + IF_ELSE = act_ite_get_function(network, node, vertex->IF->ELSE); + IF = act_mux_node(IF_IF, IF_ELSE, IF_THEN); + + THEN_IF = act_ite_get_function(network, node, vertex->THEN->IF); + THEN_THEN = act_ite_get_function(network, node, vertex->THEN->THEN); + THEN_ELSE = act_ite_get_function(network, node, vertex->THEN->ELSE); + THEN = act_mux_node(THEN_IF, THEN_ELSE, THEN_THEN); + + ELSE_IF = act_ite_get_function(network, node, vertex->ELSE->IF); + ELSE_ELSE = act_ite_get_function(network, node, vertex->ELSE->ELSE); + ELSE_THEN = act_ite_get_function(network, node, vertex->ELSE->THEN); + ELSE = act_mux_node(ELSE_IF, ELSE_ELSE, ELSE_THEN); + + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ITE != vertex) { + network_add_node(network, node1); + } + + ite_free_node_if_possible(IF_IF, vertex->IF->IF); + ite_free_node_if_possible(IF_THEN, vertex->IF->THEN); + ite_free_node_if_possible(IF_ELSE, vertex->IF->ELSE); + ite_free_node_if_possible(THEN_IF, vertex->THEN->IF); + ite_free_node_if_possible(THEN_THEN, vertex->THEN->THEN); + ite_free_node_if_possible(THEN_ELSE, vertex->THEN->ELSE); + ite_free_node_if_possible(ELSE_IF, vertex->ELSE->IF); + ite_free_node_if_possible(ELSE_ELSE, vertex->ELSE->ELSE); + ite_free_node_if_possible(ELSE_THEN, vertex->ELSE->THEN); + node_free(IF); + node_free(THEN); + node_free(ELSE); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 8: + vertex->ELSE->mark = MARK_COMPLEMENT_VALUE; + + IF = act_ite_get_function(network, node, vertex->IF); + ELSE_THEN = THEN = act_ite_get_function(network, node, vertex->THEN); + + ELSE_ELSE = act_ite_get_function(network, node, vertex->ELSE->ELSE); + ELSE_IF = act_ite_get_function(network, node, vertex->ELSE->IF); + ELSE = act_mux_node(ELSE_IF, ELSE_ELSE, ELSE_THEN); + + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ITE != vertex) { + network_add_node(network, node1); + } + + ite_free_node_if_possible(IF, vertex->IF); + ite_free_node_if_possible(THEN, vertex->THEN); + ite_free_node_if_possible(ELSE_ELSE, vertex->ELSE->ELSE); + ite_free_node_if_possible(ELSE_IF, vertex->ELSE->IF); + node_free(ELSE); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 9: + vertex->ELSE->mark = MARK_COMPLEMENT_VALUE; + vertex->ELSE->ELSE->mark = MARK_COMPLEMENT_VALUE; + + IF = act_ite_get_function(network, node, vertex->IF); + ELSE_THEN = THEN = act_ite_get_function(network, node, vertex->THEN); + + ELSE_ELSE_IF = act_ite_get_function(network, node, vertex->ELSE->ELSE->IF); + ELSE_ELSE_THEN = act_ite_get_function(network, node, vertex->ELSE->ELSE->THEN); + ELSE_ELSE_ELSE = act_ite_get_function(network, node, vertex->ELSE->ELSE->ELSE); + ELSE_ELSE = act_mux_node(ELSE_ELSE_IF, ELSE_ELSE_ELSE, ELSE_ELSE_THEN); + ELSE_IF = act_ite_get_function(network, node, vertex->ELSE->IF); + ELSE = act_mux_node(ELSE_IF, ELSE_ELSE, ELSE_THEN); + + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ITE != vertex) { + network_add_node(network, node1); + } + + ite_free_node_if_possible(IF, vertex->IF); + ite_free_node_if_possible(THEN, vertex->THEN); + ite_free_node_if_possible(ELSE_ELSE_IF, vertex->ELSE->ELSE->IF); + ite_free_node_if_possible(ELSE_ELSE_THEN, vertex->ELSE->ELSE->THEN); + ite_free_node_if_possible(ELSE_ELSE_ELSE, vertex->ELSE->ELSE->ELSE); + ite_free_node_if_possible(ELSE_IF, vertex->ELSE->IF); + node_free(ELSE); + node_free(ELSE_ELSE); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + + default: + (void) printf(" act_ite_get_function(): unknown pattern_num %d found\n", vertex->pattern_num); + exit(1); + } /* switch */ + return NIL (node_t); +} + +ite_set_MARK_VALUE_ite(ite) + ite_vertex *ite; +{ + + MARK_VALUE = ite->mark; + if (MARK_VALUE == 0) MARK_COMPLEMENT_VALUE = 1; + else { + assert (MARK_VALUE == 1); + MARK_COMPLEMENT_VALUE = 0; + } +} + + +/*--------------------------------------------------------------- + Resets the mark field of all ite's in the tree rooted at ite. +---------------------------------------------------------------*/ +ite_reset_mark_ite(ite) + ite_vertex *ite; +{ + st_table *table; + char *key; + st_generator *stgen; + ite_vertex *vertex; + + table = ite_my_traverse_ite(ite); + st_foreach_item(table, stgen, &key, (char **) &vertex) { + vertex->mark = 0; + } + st_free_table(table); +} + +/*********************************************************************************** + If the vertex is just an input, then the node cannot be freed. If the vertex is + a multiple_fo point, then also it cannot be freed. This is because these nodes + are needed in the network. +************************************************************************************/ +ite_free_node_if_possible(node, vertex) + node_t *node; + ite_vertex *vertex; +{ + node_function_t node_fn; + + node_fn = node_function(node); + if ((node_fn == NODE_0) || (node_fn == NODE_1)){ + node_free(node); + return; + } + /* should be after the node_fn check, because 0, 1 vertices + do not store anything */ + /*---------------------------------------------------------*/ + if (vertex->multiple_fo != 0) return; + node_free(node); +} + +int +act_new_act_break_node(node) + node_t *node; +{ + network_t *network; + node_t *node_returned, *node1; + ACT_ITE_COST_STRUCT *cost_struct; + + network = node->network; + cost_struct = ACT_ITE_SLOT(node); + + PRESENT_ACT = cost_struct->act; + set_mark_act(PRESENT_ACT); + if (ACT_ITE_DEBUG) act_check(PRESENT_ACT); + + node_returned = act_new_act_get_function(network, node, PRESENT_ACT); + node1 = node_get_fanin(node_returned, 0); + node_free(node_returned); + + /* all the multiple fo vertices had a node in the node field. Free that node */ + /*---------------------------------------------------------------------------*/ + set_mark_act(PRESENT_ACT); + act_free_nodes_in_multiple_fo_act(PRESENT_ACT); + /* free the structure of node */ + /*----------------------------*/ + my_free_act(cost_struct->act); + cost_struct->act = NIL (ACT_VERTEX); /* without it, no good */ + node_replace(node, node1); + return 1; +} + +/*--------------------------------------------------------------- + Checks a few things about ite of the node. +---------------------------------------------------------------*/ +ite_check_ite(ite, node) + ite_vertex *ite; + node_t *node; +{ + st_table *table; + char *key; + st_generator *stgen; + ite_vertex *vertex; + + table = ite_my_traverse_ite(ite); + st_foreach_item(table, stgen, &key, (char **) &vertex) { + if (vertex->pattern_num < 0) { + if (vertex->cost > 0) { + (void) printf("ite of node %s has wrong pattern num\n", node_long_name(node)); + exit(1); + } + } + } + st_free_table(table); +} + +/************************************************************************************** + Given a node and its corresponding ACT(OACT), breaks the node into nodes, each + new node realizing a function that can be implemented by one basic block. Puts all + these nodes in the network. Original node is changed. +***************************************************************************************/ +node_t * +act_new_act_get_function(network, node, vertex) + network_t *network; + node_t *node; + ACT_VERTEX_PTR vertex; +{ + + node_t *node1, *node2, *ELSE_THEN, *ELSE_ELSE, *ELSE_IF, *ELSE_ELSE_IF, *ELSE_ELSE_THEN, *ELSE_ELSE_ELSE; + node_t *IF, *THEN, *ELSE, *THEN_THEN, *THEN_ELSE, *THEN_IF; + node_t *THEN_ELSE_ELSE, *THEN_ELSE_THEN, *THEN_ELSE_IF; + + /* vertex->node corresponds to the node at the vertex - only for the + multiple_fanout vertex */ + /*-----------------------------------------------------------------*/ + + if (vertex->value == 0) { + vertex->mark = MARK_COMPLEMENT_VALUE; + return node_constant(0); + } + if (vertex->value == 1) { + vertex->mark = MARK_COMPLEMENT_VALUE; + return node_constant(1); + } + + + if (vertex->mark == MARK_COMPLEMENT_VALUE) { + if (vertex->multiple_fo == 0) { + (void) printf("error: act_get_function()\n"); + exit(1); + } + return vertex->node; + } + + /* added April 4, 1991*/ + /*-------------------*/ + if (!act_is_or_used) { + assert(vertex->pattern_num < 4); + } + + /* even multiple fo vertices will be mapped when they are visited first time */ + /*---------------------------------------------------------------------------*/ + vertex->mark = MARK_COMPLEMENT_VALUE; + + if ((vertex->low->value == 0) && (vertex->high->value == 1)) { + node1 = get_node_literal_of_vertex(vertex, network); + if (vertex->multiple_fo != 0) vertex->node = node1; + return node1; + } + + if (vertex->pattern_num > 3) num_or_patterns++; + + switch(vertex->pattern_num) { + + case 0: + + ELSE = act_new_act_get_function(network, node, vertex->low); + THEN = act_new_act_get_function(network, node, vertex->high); + IF = get_node_literal_of_vertex(vertex, network); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + free_node_if_possible(ELSE, vertex->low); + free_node_if_possible(THEN, vertex->high); + node_free(IF); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 1: + + vertex->low->mark = MARK_COMPLEMENT_VALUE; + ELSE_ELSE = act_new_act_get_function(network, node, vertex->low->low); + ELSE_THEN = act_new_act_get_function(network, node, vertex->low->high); + ELSE_IF = get_node_literal_of_vertex(vertex->low, network); + ELSE = act_mux_node(ELSE_IF, ELSE_ELSE, ELSE_THEN); + IF = get_node_literal_of_vertex(vertex, network); + THEN = act_new_act_get_function(network, node, vertex->high); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + free_node_if_possible(THEN, vertex->high); + free_node_if_possible(ELSE_ELSE, vertex->low->low); + free_node_if_possible(ELSE_THEN, vertex->low->high); + node_free(ELSE_IF); + node_free(IF); + node_free(ELSE); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 2: + vertex->high->mark = MARK_COMPLEMENT_VALUE; + + THEN_ELSE = act_new_act_get_function(network, node, vertex->high->low); + THEN_THEN = act_new_act_get_function(network, node, vertex->high->high); + THEN_IF = get_node_literal_of_vertex(vertex->high, network); + THEN = act_mux_node(THEN_IF, THEN_ELSE, THEN_THEN); + IF = get_node_literal_of_vertex(vertex, network); + ELSE = act_new_act_get_function(network, node, vertex->low); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + free_node_if_possible(THEN_ELSE, vertex->high->low); + free_node_if_possible(THEN_THEN, vertex->high->high); + free_node_if_possible(ELSE, vertex->low); + node_free(THEN_IF); + node_free(IF); + node_free(THEN); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + + case 3: + vertex->low->mark = MARK_COMPLEMENT_VALUE; + vertex->high->mark = MARK_COMPLEMENT_VALUE; + + ELSE_ELSE = act_new_act_get_function(network, node, vertex->low->low); + ELSE_THEN = act_new_act_get_function(network, node, vertex->low->high); + ELSE_IF = get_node_literal_of_vertex(vertex->low, network); + ELSE = act_mux_node(ELSE_IF, ELSE_ELSE, ELSE_THEN); + + THEN_ELSE = act_new_act_get_function(network, node, vertex->high->low); + THEN_THEN = act_new_act_get_function(network, node, vertex->high->high); + THEN_IF = get_node_literal_of_vertex(vertex->high, network); + THEN = act_mux_node(THEN_IF, THEN_ELSE, THEN_THEN); + + IF = get_node_literal_of_vertex(vertex, network); + node1 = act_mux_node(IF, ELSE, THEN); + + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + free_node_if_possible(ELSE_ELSE, vertex->low->low); + free_node_if_possible(ELSE_THEN, vertex->low->high); + free_node_if_possible(THEN_ELSE, vertex->high->low); + free_node_if_possible(THEN_THEN, vertex->high->high); + + node_free(ELSE_IF); + node_free(THEN_IF); + node_free(IF); + node_free(THEN); + node_free(ELSE); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 4: + vertex->low->low->mark = MARK_COMPLEMENT_VALUE; + vertex->low->mark = MARK_COMPLEMENT_VALUE; + + ELSE_ELSE_ELSE = act_new_act_get_function(network, node, vertex->low->low->low); + ELSE_ELSE_THEN = act_new_act_get_function(network, node, vertex->low->low->high); + ELSE_ELSE_IF = get_node_literal_of_vertex(vertex->low->low, network); + ELSE_ELSE = act_mux_node(ELSE_ELSE_IF, ELSE_ELSE_ELSE, ELSE_ELSE_THEN); + + ELSE_THEN = THEN = act_new_act_get_function(network, node, vertex->high); + ELSE_IF = get_node_literal_of_vertex(vertex->low, network); + ELSE = act_mux_node(ELSE_IF, ELSE_ELSE, ELSE_THEN); + + IF = get_node_literal_of_vertex(vertex, network); + + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + free_node_if_possible(ELSE_ELSE_ELSE, vertex->low->low->low); + free_node_if_possible(ELSE_ELSE_THEN, vertex->low->low->high); + free_node_if_possible(THEN, vertex->high); + + node_free(ELSE_ELSE_IF); + node_free(ELSE_ELSE); + node_free(ELSE_IF); + node_free(IF); + node_free(ELSE); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 5:; + case 6: + vertex->high->mark = MARK_COMPLEMENT_VALUE; + vertex->high->low->mark = MARK_COMPLEMENT_VALUE; + + THEN_ELSE_ELSE = act_new_act_get_function(network, node, vertex->high->low->low); + THEN_ELSE_THEN = THEN_THEN = act_new_act_get_function(network, node, vertex->high->low->high); + THEN_ELSE_IF = get_node_literal_of_vertex(vertex->high->low, network); + THEN_ELSE = act_mux_node(THEN_ELSE_IF, THEN_ELSE_ELSE, THEN_ELSE_THEN); + + THEN_IF = get_node_literal_of_vertex(vertex->high, network); + THEN = act_mux_node(THEN_IF, THEN_ELSE, THEN_THEN); + ELSE = act_new_act_get_function(network, node, vertex->low); + IF = get_node_literal_of_vertex(vertex, network); + + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + free_node_if_possible(THEN_ELSE_ELSE, vertex->high->low->low); + free_node_if_possible(THEN_ELSE_THEN, vertex->high->low->high); + free_node_if_possible(ELSE, vertex->low); + + node_free(THEN_ELSE_IF); + node_free(THEN_ELSE); + node_free(THEN_IF); + node_free(THEN); + node_free(IF); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + case 7: + vertex->low->mark = MARK_COMPLEMENT_VALUE; + vertex->low->low->mark = MARK_COMPLEMENT_VALUE; + ELSE_ELSE_THEN = ELSE_THEN = act_new_act_get_function(network, node, vertex->low->low->high); + ELSE_ELSE_ELSE = act_new_act_get_function(network, node, vertex->low->low->low); + ELSE_ELSE_IF = get_node_literal_of_vertex(vertex->low->low, network); + ELSE_ELSE = act_mux_node(ELSE_ELSE_IF, ELSE_ELSE_ELSE, ELSE_ELSE_THEN); + ELSE_IF = get_node_literal_of_vertex(vertex->low, network); + ELSE = act_mux_node(ELSE_IF, ELSE_ELSE, ELSE_THEN); + IF = get_node_literal_of_vertex(vertex, network); + THEN = act_new_act_get_function(network, node, vertex->high); + node1 = act_mux_node(IF, ELSE, THEN); + if (PRESENT_ACT != vertex) { + network_add_node(network, node1); + } + + free_node_if_possible(ELSE_ELSE_THEN, vertex->low->low->high); + free_node_if_possible(ELSE_ELSE_ELSE, vertex->low->low->low); + free_node_if_possible(THEN, vertex->high); + node_free(ELSE_ELSE_IF); + node_free(ELSE_ELSE); + node_free(ELSE_IF); + node_free(ELSE); + node_free(IF); + + node2 = node_literal(node1, 1); + if (vertex->multiple_fo != 0) vertex->node = node2; + return node2; + + + default: + (void) printf(" act_get_function(): unknown pattern_num %d found\n", vertex->pattern_num); + exit(1); + } /* switch */ + return NIL (node_t); +} diff --git a/sis/pld/ite_collapse.c b/sis/pld/ite_collapse.c new file mode 100644 index 0000000..a92e464 --- /dev/null +++ b/sis/pld/ite_collapse.c @@ -0,0 +1,547 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" +#include "math.h" + +static node_t * act_ite_partial_collapse_find_max_score(); + +/* Aug 21, 1991 - changed the collapse routine for node to take care of + no duplication of the network when a collapse is considered. */ + +/*----------------------------------------------------------------------------------- + As obvious from the name, it does partial collapse on the network. + Assigns a score to each nodewhich is a measure of + the gain that might be obtained by collapsing the node into each of the fanouts. + This score is just based on the number of fanins, fanouts, cost of node etc. + Updates the score after each successful partial collapse. Tries to collapse + till all nodes get score 0, or have been tried for collapse, but unsuccessfully. +------------------------------------------------------------------------------------*/ +int +act_ite_partial_collapse(network, init_param) + network_t *network; + act_init_param_t *init_param; +{ + st_table *score_table; + int collapsed, gain, total_gain, score; + node_t *node, *act_ite_partial_collapse_find_max_score(); + + if (! init_param->FANIN_COLLAPSE) return 0; + + score_table = st_init_table(strcmp, st_strhash); + act_ite_partial_collapse_assign_score_network(network, score_table, init_param); + + total_gain = 0; + while (1) { + node = act_ite_partial_collapse_find_max_score(network, score_table, &score); + if (score == 0) { + st_free_table(score_table); + if (ACT_ITE_DEBUG) + (void) printf("****gain in partial collapse is %d\n", total_gain); + return total_gain; + } + if (ACT_ITE_DEBUG > 2) (void) printf("node from score_table = %s\n", node_long_name(node)); + if (init_param->COLLAPSE_METHOD == NEW) { + collapsed = act_ite_partial_collapse_node_new(network, node, init_param, + &gain, score_table); + } else { + collapsed = act_ite_partial_collapse_node(network, node, init_param, + &gain, score_table); + } + if (collapsed) { + total_gain += gain; + } + } +} + +/*--------------------------------------------------------------------------------------- + Checks if it is beneficial to collapse node into each of the fanouts. If so, does that + and returns 1 and the gain in pgain. Changes the cost_table entries of these fanouts + and deletes the entry of node. Else returns 0 and pgain is not assigned any values. + Changed Aug 21, 1991 - no duplication of network now... +-----------------------------------------------------------------------------------------*/ + +int +act_ite_partial_collapse_node(network, node, init_param, pgain, score_table) + network_t *network; + node_t *node; + act_init_param_t *init_param; + int *pgain; + st_table *score_table; +{ + int gain; + char *name, *value; + node_t *fanout, /* *fanout_simpl */ *dup_fanout, *fanin; + lsGen genfo; + ACT_ITE_COST_STRUCT *cost_struct, *cost_node; + array_t *fanout_array, *real_fanout_array; + int i, j, num_fanout, num_composite; + st_table *update_nodetable; + st_generator *stgen; + + /* check that number of fanins of each fanout are not too many */ + /*-------------------------------------------------------------*/ + foreach_fanout(node, genfo, fanout) { + num_composite = xln_num_composite_fanin(node, fanout); + if (num_composite <= init_param->COLLAPSE_FANINS_OF_FANOUT) continue; + /* set the score of node to 0, free the storage */ + /*----------------------------------------------*/ + name = node_long_name(node); + assert(st_insert(score_table, name, (char *) 0)); + return 0; + } + cost_node = ACT_ITE_SLOT(node); + gain = cost_node->cost; + foreach_fanout(node, genfo, fanout) { + gain += ACT_ITE_SLOT(fanout)->cost; + } + /* gain now is the max gain possible */ + + /* compute the gain if the node is collapsed into each of its + fanouts and is then removed from the network. The cost is stored in the + fo_table for each of the fanouts of the node */ + /*------------------------------------------------------------------------*/ + + /* for each fanout, recompute the cost */ + /*-------------------------------------*/ + real_fanout_array = array_alloc(node_t *, 0); + foreach_fanout(node, genfo, fanout) { + array_insert_last(node_t *, real_fanout_array, fanout); + } + num_fanout = array_n(real_fanout_array); + fanout_array = array_alloc(node_t *, 0); + for (i = 0; i < num_fanout; i++) { + fanout = array_fetch(node_t *, real_fanout_array, i); + dup_fanout = node_dup(fanout); + (void) node_collapse(dup_fanout, node); + simplify_node(dup_fanout, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, SIM_FILTER_NONE, + SIM_ACCEPT_SOP_LITS); + /* fanout_simpl = node_simplify(dup_fanout, NIL(node_t), NODE_SIM_ESPRESSO); + node_replace(dup_fanout, fanout_simpl); */ + array_insert_last(node_t *, fanout_array, dup_fanout); + /* a hack to get -h 1 option to work */ + dup_fanout->network = fanout->network; + + switch(init_param->MAP_METHOD) { + case MAP_WITH_ITER:; + case MAP_WITH_JUST_DECOMP: + act_ite_map_node_with_iter_imp(dup_fanout, init_param); + break; + case NEW: + (void) act_ite_new_map_node(dup_fanout, init_param); + break; + case OLD: + (void) act_ite_map_node(dup_fanout, init_param); + break; + default: + (void) printf("mapping method %d not known\n", init_param->MAP_METHOD); + exit(1); + } + + cost_struct = ACT_ITE_SLOT(dup_fanout); + dup_fanout->network = NIL (network_t); + if (ACT_ITE_DEBUG > 2) { + (void) printf("new cost of fanout node %s = %d, old_cost = %d\n", node_long_name(dup_fanout), + cost_struct->cost, ACT_ITE_SLOT(fanout)->cost); + } + /* put the names in act vertices now - commented because not breaking yet */ + /*------------------------------------------------------------------------*/ + if (init_param->MAP_METHOD == NEW || init_param->MAP_METHOD == OLD) { + act_ite_partial_collapse_update_ite_fields(network, dup_fanout, cost_struct); + } + gain -= cost_struct->cost; + if (gain <= 0) break; /* now you may not have to go through all the fanouts before + you find out that the collapse is no good */ + } + if (gain <= 0) { + /* set the score of node to 0, free the storage */ + /*----------------------------------------------*/ + name = node_long_name(node); + assert(st_insert(score_table, name, (char *) 0)); + for (j = 0; j <= i; j++) { + dup_fanout = array_fetch(node_t *, fanout_array, j); + act_free_ite_node(dup_fanout); + node_free(dup_fanout); + } + array_free(fanout_array); + array_free(real_fanout_array); + return 0; + } + + for (i = 0; i < num_fanout; i++) { + dup_fanout = array_fetch(node_t *, fanout_array, i); + fanout = array_fetch(node_t *, real_fanout_array, i); + act_free_ite_node(fanout); + act_ite_free(fanout); + ACT_DEF_ITE_SLOT(fanout) = ACT_DEF_ITE_SLOT(dup_fanout); + ACT_DEF_ITE_SLOT(dup_fanout) = NIL (char); + /* updating the score of the fanout */ + /*----------------------------------*/ + act_ite_partial_collapse_assign_score_node(fanout, score_table, init_param); + (void) node_replace(fanout, dup_fanout); + } /* for i = 0 */ + array_free(fanout_array); + + /* change the scores of the fanins of the node, and the fanins of the fanouts + since the fanout information has changed - added Dec. 1, 1992 */ + /*---------------------------------------------------------------------------*/ + if (init_param->COLLAPSE_UPDATE == EXPENSIVE) { + update_nodetable = st_init_table(st_ptrcmp, st_ptrhash); + foreach_fanin(node, i, fanin) { + (void) st_insert(update_nodetable, (char *) fanin, (char *) fanin); + } + } + + /* delete the collapsed node from network.*/ + /*----------------------------------------*/ + if (ACT_ITE_DEBUG > 1) (void) printf("collapsed node %s\n", node_long_name(node)); + act_free_ite_node(node); + network_delete_node(network, node); + + if (init_param->COLLAPSE_UPDATE == EXPENSIVE) { + for (i = 0; i < array_n(real_fanout_array); i++) { + fanout = array_fetch(node_t *, real_fanout_array, i); + foreach_fanin(fanout, j, fanin) { + (void) st_insert(update_nodetable, (char *) fanin, (char *) fanin); + } + } + + st_foreach_item(update_nodetable, stgen, (char **) &fanin, &value) { + act_ite_partial_collapse_assign_score_node(fanin, score_table, init_param); + } + st_free_table(update_nodetable); + } + array_free(real_fanout_array); + *pgain = gain; + return 1; +} + +/*--------------------------------------------------------------------------------------- + Is potentially more powerful than act_ite_partial_collapse_node(), in that, even if + the total collapse is not beneficial, it may happen that collapsing node into some + fanouts (those in good_array) may be benficial. In that case, this is done. + If the overall gain is not positive (because of fanouts whose cost increases as + a result of this collapse - ie in bad_array), node will not be deleted from network. +-----------------------------------------------------------------------------------------*/ + +int +act_ite_partial_collapse_node_new(network, node, init_param, pgain, score_table) + network_t *network; + node_t *node; + act_init_param_t *init_param; + int *pgain; + st_table *score_table; +{ + int gain_good, gain_bad, gain_node; + char *name, *value; + node_t *fanout, /* *fanout_simpl, */ *dup_fanout, *fanin; + lsGen genfo; + ACT_ITE_COST_STRUCT *cost_struct, *cost_node; + array_t *fanout_array, *real_fanout_array, *good_array, *bad_array; + int i, j, num_fanout, num_composite, index; + st_table *update_nodetable; + st_generator *stgen; + + /* check that number of fanins of each fanout are not too many */ + /*-------------------------------------------------------------*/ + foreach_fanout(node, genfo, fanout) { + num_composite = xln_num_composite_fanin(node, fanout); + if (num_composite <= init_param->COLLAPSE_FANINS_OF_FANOUT) continue; + /* set the score of node to 0, free the storage */ + /*----------------------------------------------*/ + name = node_long_name(node); + assert(st_insert(score_table, name, (char *) 0)); + return 0; + } + + cost_node = ACT_ITE_SLOT(node); + gain_bad = cost_node->cost; + gain_good = 0; + + /* compute the gain if the node is collapsed into each of its + fanouts and is then removed from the network. The cost is stored in the + fo_table for each of the fanouts of the node */ + /*------------------------------------------------------------------------*/ + + /* for each fanout, recompute the cost */ + /*-------------------------------------*/ + real_fanout_array = array_alloc(node_t *, 0); + foreach_fanout(node, genfo, fanout) { + array_insert_last(node_t *, real_fanout_array, fanout); + } + + num_fanout = array_n(real_fanout_array); + fanout_array = array_alloc(node_t *, 0); + good_array = array_alloc(int, 0); + bad_array = array_alloc(int, 0); + + for (i = 0; i < num_fanout; i++) { + fanout = array_fetch(node_t *, real_fanout_array, i); + dup_fanout = node_dup(fanout); + (void) node_collapse(dup_fanout, node); + simplify_node(dup_fanout, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, SIM_FILTER_NONE, + SIM_ACCEPT_SOP_LITS); + array_insert_last(node_t *, fanout_array, dup_fanout); + /* a hack to get -h 1 option to work */ + dup_fanout->network = fanout->network; + switch(init_param->MAP_METHOD) { + case MAP_WITH_ITER:; + case MAP_WITH_JUST_DECOMP: + act_ite_map_node_with_iter_imp(dup_fanout, init_param); + break; + case NEW: + (void) act_ite_new_map_node(dup_fanout, init_param); + break; + case OLD: + (void) act_ite_map_node(dup_fanout, init_param); + break; + default: + (void) printf("mapping method %d not known\n", init_param->MAP_METHOD); + exit(1); + } + + cost_struct = ACT_ITE_SLOT(dup_fanout); + dup_fanout->network = NIL (network_t); + if (ACT_ITE_DEBUG > 2) { + (void) printf("new cost of fanout node %s = %d, old_cost = %d\n", node_long_name(dup_fanout), + cost_struct->cost, ACT_ITE_SLOT(fanout)->cost); + } + /* put the names in act vertices now */ + /*-----------------------------------*/ + if (init_param->MAP_METHOD == NEW || init_param->MAP_METHOD == OLD) { + act_ite_partial_collapse_update_ite_fields(network, dup_fanout, cost_struct); + } + gain_node = ACT_ITE_SLOT(fanout)->cost - cost_struct->cost; + if (gain_node > 0) { + gain_good += gain_node; + array_insert_last(int, good_array, i); + } else { + gain_bad += gain_node; + array_insert_last(int, bad_array, i); + } + } + + if (gain_bad <= 0) { + /* set the score of node to 0, free the storage */ + /*----------------------------------------------*/ + name = node_long_name(node); + assert(st_insert(score_table, name, (char *) 0)); + for (j = 0; j < array_n(bad_array); j++) { + index = array_fetch(int, bad_array, j); + dup_fanout = array_fetch(node_t *, fanout_array, index); + act_free_ite_node(dup_fanout); + node_free(dup_fanout); /* act_free_ite() is called from within node_free() */ + } + } else { + for (j = 0; j < array_n(bad_array); j++) { + index = array_fetch(int, bad_array, j); + dup_fanout = array_fetch(node_t *, fanout_array, index); + fanout = array_fetch(node_t *, real_fanout_array, index); + act_free_ite_node(fanout); + act_ite_free(fanout); + ACT_DEF_ITE_SLOT(fanout) = ACT_DEF_ITE_SLOT(dup_fanout); + ACT_DEF_ITE_SLOT(dup_fanout) = NIL (char); + /* updating the score of the fanout */ + /*----------------------------------*/ + act_ite_partial_collapse_assign_score_node(fanout, score_table, init_param); + (void) node_replace(fanout, dup_fanout); + } + } + + for (j = 0; j < array_n(good_array); j++) { + index = array_fetch(int, good_array, j); + dup_fanout = array_fetch(node_t *, fanout_array, index); + fanout = array_fetch(node_t *, real_fanout_array, index); + act_free_ite_node(fanout); + act_ite_free(fanout); + ACT_DEF_ITE_SLOT(fanout) = ACT_DEF_ITE_SLOT(dup_fanout); + ACT_DEF_ITE_SLOT(dup_fanout) = NIL (char); + /* updating the score of the fanout */ + /*----------------------------------*/ + act_ite_partial_collapse_assign_score_node(fanout, score_table, init_param); + (void) node_replace(fanout, dup_fanout); + } + + array_free(fanout_array); + + if (gain_bad > 0) { + /* delete the collapsed node from network - not deleting from + score_table since only nodes in the network are searched + when finding the best node */ + /*---------------------------------------------------------*/ + if (ACT_ITE_DEBUG > 1) (void) printf("collapsed node %s into all the fanouts\n", node_long_name(node)); + act_free_ite_node(node); + network_delete_node(network, node); + } + + if (init_param->COLLAPSE_UPDATE == EXPENSIVE) { + update_nodetable = st_init_table(st_ptrcmp, st_ptrhash); + + /* gain_good > 0 else no member in the array */ + /*--------------------------------------------*/ + for (i = 0; i < array_n(good_array); i++) { + index = array_fetch(int, good_array, i); + fanout = array_fetch(node_t *, real_fanout_array, index); + foreach_fanin(fanout, j, fanin) { + (void) st_insert(update_nodetable, (char *) fanin, (char *) fanin); + } + } + if (gain_bad > 0) { + for (i = 0; i < array_n(bad_array); i++) { + index = array_fetch(int, bad_array, i); + fanout = array_fetch(node_t *, real_fanout_array, index); + foreach_fanin(fanout, j, fanin) { + (void) st_insert(update_nodetable, (char *) fanin, (char *) fanin); + } + } + } + + st_foreach_item(update_nodetable, stgen, (char **) &fanin, &value) { + act_ite_partial_collapse_assign_score_node(fanin, score_table, init_param); + } + st_free_table(update_nodetable); + } + + array_free(real_fanout_array); + array_free(bad_array); + array_free(good_array); + *pgain = gain_good + (gain_bad * (gain_bad > 0)); + return (*pgain); /* not returning 1, *pgain > 0 iff some collapsing took place */ +} + +int +act_ite_partial_collapse_assign_score_node(node, score_table, init_param) + node_t *node; + st_table *score_table; + act_init_param_t *init_param; +{ + int score, num_fanin, cost, num_fanouts, i; + node_t *fanout; + char *name; + + if (node->type != INTERNAL) return (-1); + name = node_long_name(node); + num_fanin = node_num_fanin(node); + if ((num_fanin > init_param->FANIN_COLLAPSE) || (is_anyfo_PO(node))) { + /* give a score of 0 to this node */ + /*--------------------------------*/ + (void) st_insert(score_table, name, (char *) 0); + return 0; + } + cost = ACT_ITE_SLOT(node)->cost; + if (cost > init_param->COST_LIMIT) { + (void) st_insert(score_table, name, (char *) 0); + return 0; + } + if (cost == 0) cost = 1; + num_fanouts = node_num_fanout(node); + score = 0; + for (i = 0; i < num_fanouts; i++) { + fanout = node_get_fanout(node, i); + score += ACT_ITE_SLOT(fanout)->cost; + } + score = (int) ceil((double) (score / cost)); + (void) st_insert(score_table, name, (char *) score); + return score; +} + +/*----------------------------------------------------------- + Returns the node with the highest score in the score_table. + The corresponding score is set in pscore. Assumes that all + scores are nonnegative. +-------------------------------------------------------------*/ +static +node_t * +act_ite_partial_collapse_find_max_score(network, score_table, pscore) + network_t *network; + st_table *score_table; + int *pscore; +{ + lsGen gen; + node_t *node, *node_max; + int max_score, score; + + max_score = -1; + node_max = NIL (node_t); + + foreach_node(network, gen, node) { + if (node->type != INTERNAL) continue; + assert(st_lookup_int(score_table, node_long_name(node), &score)); + if (score > max_score) { + max_score = score; + node_max = node; + } + } + *pscore = max_score; + return node_max; +} + +/*-------------------------------------------------------------------------------- + Assigns a score to each internal node. If the cost of the node is > + init_param->COST_LIMIT, it is 0. + Else it is based on sum of costs of the fanout nodes and the cost of the node. + Stores all the costs in the score_table. +---------------------------------------------------------------------------------*/ +int +act_ite_partial_collapse_assign_score_network(network, score_table, init_param) + network_t *network; + st_table *score_table; + act_init_param_t *init_param; +{ + array_t *nodevec; + int i, num_nodes, score; + node_t *node; + + nodevec = network_dfs(network); + num_nodes = array_n(nodevec); + /* assign score to all the internal nodes */ + /*----------------------------------------*/ + for (i = 0; i < num_nodes; i++) { + node = array_fetch(node_t *, nodevec, i); + score = act_ite_partial_collapse_assign_score_node(node, score_table, + init_param); + if (ACT_ITE_DEBUG > 3 && (score != -1)) + (void) printf("---assigned score of %d to node %s\n", score, node_long_name(node)); + } + array_free(nodevec); +} + +act_ite_partial_collapse_update_ite_fields(network, dup_fanout, cost_struct) + network_t *network; + node_t *dup_fanout; + ACT_ITE_COST_STRUCT *cost_struct; +{ + node_t *fanout; + + fanout = network_find_node(network, node_long_name(dup_fanout)); + cost_struct->node = fanout; + if (cost_struct->match) return; + if (cost_struct->ite) { + cost_struct->ite->node = fanout; + act_ite_partial_collapse_put_node_names_in_ite(cost_struct->ite, network); + assert(cost_struct->act == NIL (ACT_VERTEX)); + } else { + cost_struct->act->node = fanout; + act_partial_collapse_put_node_names_in_act(cost_struct->act, network); + } +} + +act_ite_partial_collapse_put_node_names_in_ite(ite, network) + ite_vertex *ite; + network_t *network; +{ + st_table *table; + char *key; + st_generator *stgen; + ite_vertex *vertex; + + table = ite_my_traverse_ite(ite); + st_foreach_item(table, stgen, &key, (char **) &vertex) { + if (vertex->value != 2) continue; + if (vertex->fanin != network_find_node(network, node_long_name(vertex->fanin))) { + (void) printf("need partial collapse put node names\n"); + } + assert(vertex->fanin = network_find_node(network, node_long_name(vertex->fanin))); + vertex->name = node_long_name(vertex->fanin); + } + st_free_table(table); +} diff --git a/sis/pld/ite_factor.c b/sis/pld/ite_factor.c new file mode 100644 index 0000000..315ca24 --- /dev/null +++ b/sis/pld/ite_factor.c @@ -0,0 +1,186 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + +/*----------------------------------------------------- + Constructs an ite for the factored form of the node. + First contructs a network out of the node, does a + good-decomposition on the node. + Note that the routine constructs ites + of the nodes of the network (corresponding to the node). + To get the ite of the node, the fields in the ite + vertices have to be appropriately set to fanins of the + node. That is done in act_ite_get_ite(). + + NOTE: Hoping to use it only if the function does not + satisfy all the filters. So the cost > 2, it is not + an AND, OR function etc. +-------------------------------------------------------*/ +ite_vertex * +act_ite_create_from_factored_form(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + + network_t *network_node; + int i; + node_t *n, *node1; + array_t *nodevec; + ite_vertex *ite; + + if (node_num_literal(node) == factor_num_literal(node)) return NIL (ite_vertex); + + network_node = network_create_from_node(node); + decomp_good_network(network_node); + /* decomp_tech_network(network_node, 2, 2); */ + + nodevec = network_dfs(network_node); + for (i = 0; i < array_n(nodevec); i++) { + n = array_fetch(node_t *, nodevec, i); + act_ite_intermediate_new_make_ite(n, init_param); + /* change node, value fields in the ites which are either buffers or inverters */ + /*-----------------------------------------------------------------------------*/ + act_ite_mroot_modify_fields_node(n); + } + assert(n->type == PRIMARY_OUTPUT); + node1 = node_get_fanin(n, 0); + ite = ACT_ITE_ite(node1); + /* no need of next statements */ + /* now set all the ite pointers to 0 */ + /*-----------------------------------*/ + /* + for (i = 0; i < array_n(nodevec); i++) { + n = array_fetch(node_t *, nodevec, i); + ACT_ITE_ite(n) = NIL (ite_vertex); + } + */ + + array_free(nodevec); + /* freeing not needed */ + /* + act_free_ite_network(network_node); + */ + + /* the ite vertices pointing to PIs of network_node + are made to point to fanins of node */ + act_ite_correct_PIs(ite, node); + network_free(network_node); + return ite; +} + +/*--------------------------------------------------------- + Given a node, construct an ite from the factored form. + Map this ite, if it is better than the previous ite + (must exist), accept this mapping and free the previous + cost_struct. Returns the resulting gain. + + NOTE: If original cost = 0, may get now a cost of 1. We + do not check for special cases like NODE_0, NODE_BUF etc. +----------------------------------------------------------*/ +int +act_ite_map_factored_form(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + + ACT_ITE_COST_STRUCT *cost_node, *cost_node_original; + int gain; + + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) return 0; + + cost_node_original = ACT_ITE_SLOT(node); + + act_ite_alloc(node); + cost_node = ACT_ITE_SLOT(node); + ACT_ITE_ite(node) = act_ite_create_from_factored_form(node, init_param); + if (ACT_ITE_ite(node) == NIL (ite_vertex)) { + act_ite_free(node); + ACT_DEF_ITE_SLOT(node) = (char *) cost_node_original; + return 0; + } + + cost_node->cost = act_ite_make_tree_and_map(node); + cost_node->arrival_time = ACT_ITE_ite(node)->arrival_time; + cost_node->node = node; + + gain = cost_node_original->cost - cost_node->cost; + if (gain > 0) { + ACT_DEF_ITE_SLOT(node) = (char *) cost_node_original; + act_free_ite_node(node); + act_ite_free(node); + ACT_DEF_ITE_SLOT(node) = (char *) cost_node; + return gain; + } + act_free_ite_node(node); + act_ite_free(node); + ACT_DEF_ITE_SLOT(node) = (char *) cost_node_original; + return 0; +} + +/*-------------------------------------------------------------------- + Change the PI pointers of ite to point to the correct fanins of the + node. They are right now pointing at the primary inputs of + the network that was made out of network_node. +----------------------------------------------------------------------*/ +act_ite_correct_PIs(ite, node) + ite_vertex *ite; + node_t *node; +{ + network_t *network; + ite_vertex *vertex; + int i, j, flag; + node_t *n; + array_t *vertex_vec; + st_table *table; + + network = node->network; + vertex_vec = array_alloc(ite_vertex *, 0); + table = st_init_table(st_ptrcmp, st_ptrhash); + act_ite_get_value_2_vertices(ite, vertex_vec, table); + st_free_table(table); + for (i = 0; i < array_n(vertex_vec); i++) { + vertex = array_fetch(ite_vertex *, vertex_vec, i); + if (network) { + vertex->fanin = network_find_node(network, node_long_name(vertex->fanin)); + assert(vertex->fanin); + vertex->name = node_long_name(vertex->fanin); + } else { + flag = 0; + foreach_fanin(node, j, n) { + if (strcmp(node_long_name(vertex->fanin), node_long_name(n)) == 0) { + flag = 1; + break; + } + } + if (!flag) { + (void) printf("problem in correcting PI routine in ite_factor.c\n"); + exit(1); + } + vertex->fanin = n; + vertex->name = node_long_name(n); + } + } + array_free(vertex_vec); +} + +/*---------------------------------------------------------- + Returns in the vertex_vec all vertices with value 2. + Note: Works only for the case when value = 2 => phase = 1. +-----------------------------------------------------------*/ +act_ite_get_value_2_vertices(ite, vertex_vec, table) + ite_vertex *ite; + array_t *vertex_vec; + st_table *table; +{ + if (st_insert(table, (char *) ite, (char *) ite)) return; + if (ite->value <= 1) return; + if (ite->value == 2) { + assert(ite->phase == 1); + array_insert_last(ite_vertex *, vertex_vec, ite); + return; + } + act_ite_get_value_2_vertices(ite->IF, vertex_vec, table); + act_ite_get_value_2_vertices(ite->THEN, vertex_vec, table); + act_ite_get_value_2_vertices(ite->ELSE, vertex_vec, table); +} + diff --git a/sis/pld/ite_imp.c b/sis/pld/ite_imp.c new file mode 100644 index 0000000..4d5c5a5 --- /dev/null +++ b/sis/pld/ite_imp.c @@ -0,0 +1,476 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + +static void ite_decomp_big_nodes(); + +/* + Log of changes + + Jan 5, 93: decomp_big_nodes accepts a decomposition even if the cost remains the same. + however, after experimenting, it turns out that this move is not good. Even gives worse + results. So was commented out on Jan. 6 '93. + + Jan 11 '93: In act_node_remap(), if DECOMP_FLAG is 1, number of iterations is made 1. + Some other fields are changed as well. Also, the network after decomposition is a + "broken" one, ie, in terms of ACT1 blocks (for almost all practical cases). + + Jan 13 '93: Added DECOMP_METHOD field in act_init_param: USE_GOOD_DECOMP and USE_FACTOR + are two methods now. In principle, they are the same; implementations differ. + USE_GOOD_DECOMP constructs a decomposed network and maps each node separately, whereas + USE_FACTOR contructs an ite for the factored form of the node. +*/ + +/*------------------------------------------------------------------------------------ + Improve the network using repeated partial collapse and decomp till NUM_ITER are + completed, or no further improvement is obtained. + Then quick-phase is entered to determine which nodes should be realized in + negative phase. +--------------------------------------------------------------------------------------*/ + +act_ite_iterative_improvement(network, init_param) + network_t *network; + act_init_param_t *init_param; +{ + if (init_param->NUM_ITER > 0) ite_improve_network(network, init_param); + /* if (init_param->QUICK_PHASE) act_quick_phase(network, init_param); */ + if (init_param->LAST_GASP) act_last_gasp(network, init_param); + if (ACT_ITE_DEBUG >3) assert(network_check(network)); + if (ACT_ITE_STATISTICS) { + (void) printf("block count = %d\n", ite_print_network(network, -1)); + } +} + + +ite_improve_network(network, init_param) + network_t *network; + act_init_param_t *init_param; + +{ + int nogain; + int iteration_num; + int iteration_gain; + int collapse_gain; + int decomp_gain; + + nogain = FALSE; + iteration_num = 0; + while (nogain == FALSE && iteration_num < init_param->NUM_ITER) { + nogain = TRUE; + /* decomposing big nodes in the network if it is profitable*/ + /*---------------------------------------------------------*/ + ite_decomp_big_nodes(network, &decomp_gain, init_param); + if (ACT_ITE_DEBUG > 3) { + assert(network_check(network)); + } + collapse_gain = act_ite_partial_collapse(network, init_param); + iteration_gain = collapse_gain + decomp_gain; + if (iteration_gain > 0) nogain = FALSE; + iteration_num++; + if (ACT_ITE_DEBUG && iteration_gain) { + (void) printf("gain after an iteration = %d\n", iteration_gain); + (void) ite_print_network(network, iteration_num); + } + } +} + +/*-------------------------------------------------------------------------- + Decompose nodes of the network. If decomposition results in a + lesser cost node, accept the decomposition, and replace the node by + the decomposition. + think about how to decompose the nodes in the network. Should I use the + mux structure and do a resub. this is because it possibly means that the + decomposition would be in terms of a mux structure => Boolean div not + implemented in misII. +-----------------------------------------------------------------------------*/ + +static void +ite_decomp_big_nodes(network, gain, init_param) + network_t *network; + int *gain; + act_init_param_t *init_param; +{ + array_t *nodevec; + int i; + node_t *node; + int num_fanin, num_cube; + node_function_t node_fun; + int FLAG_DECOMP; + + *gain = 0; + FLAG_DECOMP = 1; + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + node_fun = node_function(node); + if ((node_fun == NODE_PI) || (node_fun == NODE_PO)) continue; + num_fanin = node_num_fanin(node); + if (num_fanin < init_param->DECOMP_FANIN) continue; + if (ACT_ITE_SLOT(node)->cost <= 2) continue; + + /* if constructed optimally, do not decompose - not implemented yet */ + /*------------------------------------------------------------------*/ + num_cube = node_num_cube(node); + if ((num_cube == 1) || + (node_num_literal(node) == num_cube) + ) continue; + + switch (init_param->DECOMP_METHOD) { + case USE_GOOD_DECOMP: + (*gain) += act_ite_node_remap(network, node, FLAG_DECOMP, init_param); + break; + case USE_FACTOR: + (*gain) += act_ite_map_factored_form(node, init_param); + break; + default: + (void) printf("unexpected DECOMP_METHOD\n"); + exit(1); + } + } + if (ACT_ITE_DEBUG) (void) printf("---Gain in decomp_big_nodes = %d\n", *gain); + array_free(nodevec); +} + +/* this is not being used. Instead using act_last_gasp */ + +network_t * +act_ite_network_remap(network, init_param) + network_t *network; + act_init_param_t *init_param; +{ + array_t *nodevec; + node_t *node; + int i; + int gain; + int FLAG_DECOMP = 0; + /* int HEURISTIC_NUM = 0; */ /* does not matter */ + + gain = 0; + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + gain += act_ite_node_remap(network, node, FLAG_DECOMP, init_param); + } + if (ACT_ITE_STATISTICS) (void) printf("total gain after remapping = %d\n", gain); + array_free(nodevec); + return network; +} + +/*------------------------------------------------------------------------- + A last attempt at improving results. Forms a network out of the node, + decomposes it and then remaps it. +--------------------------------------------------------------------------*/ +act_last_gasp(network, init_param) + network_t *network; + act_init_param_t *init_param; +{ + array_t *nodevec; + int i; + node_t *node; + int DECOMP_FLAG = 0; + int gain; + + gain = 0; + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + gain += act_ite_node_remap(network, node, DECOMP_FLAG, init_param); + } + array_free(nodevec); + + if (ACT_ITE_STATISTICS) (void) printf("total gain in remapping = %d\n", gain); +} + +/*---------------------------------------------------------------------------------- + Calls the same procedures for a node to obtain a good mapping of the node. + It accepts the solution if it is better than the earlier one. + Can be called either for the DECOMPOSITION or for simply remapping (LAST_GASP). + FLAG_DECOMP is 1 if the routine is called from decomp_big_nodes, is 0 if it is + called from act_last_gasp. +------------------------------------------------------------------------------------*/ +int +act_ite_node_remap(network, node, FLAG_DECOMP, init_init_param) + network_t *network; + node_t *node; + int FLAG_DECOMP; + act_init_param_t *init_init_param; +{ + + node_t *dup_node, *node1, *node1_dup; + network_t *network1; + int cost_node_original; + int cost_network1; + st_table *table1; + int num_cubes, gain, alternate_gain, num_nodes2, i, improved, HEURISTIC_NUM_ORIG; + act_init_param_t *init_param; + node_function_t node_fun; + array_t *nodevec1; + + HEURISTIC_NUM_ORIG = init_init_param->HEURISTIC_NUM; + + node_fun = node_function(node); + if ((node_fun == NODE_PI) || (node_fun == NODE_PO)) return 0; + + cost_node_original = ACT_ITE_SLOT(node)->cost; + if (ACT_ITE_DEBUG) { + (void) printf("original cost of node %s = %d\n", node_long_name(node), + cost_node_original); + } + if (cost_node_original <= 2) return 0; + + /* if the subject-graph for the node is optimal, do not remap */ + /*------------------------------------------------------------*/ + num_cubes = node_num_cube(node); + if ((num_cubes == 1) || + (num_cubes == node_num_literal(node)) + ) return 0; + + /* if doing remapping, and constructing ITE only, then also construct + BDD (and vice versa), then check if cost improves. */ + /*-------------------------------------------------------------------*/ + alternate_gain = 0; /* incurred from constructing alternate representation */ + if (FLAG_DECOMP == 0 && init_init_param->ALTERNATE_REP) { + improved = act_ite_use_alternate_rep(node, init_init_param); + if (improved) { + alternate_gain = cost_node_original - ACT_ITE_SLOT(node)->cost; + if (ACT_ITE_SLOT(node)->cost <= 2) return alternate_gain; /* can't improve any more */ + cost_node_original = ACT_ITE_SLOT(node)->cost; + } + } + + dup_node = node_dup(node); + network1 = network_create_from_node(dup_node); + decomp_good_network(network1); + if ((FLAG_DECOMP == 1) && (network_num_internal(network1) == 1)) { + network_free(network1); + node_free(dup_node); + return alternate_gain; + } + if (FLAG_DECOMP == 0) decomp_tech_network(network1, 1000, 1000); /* changed from 2, 2 */ + + init_param = ALLOC(act_init_param_t, 1); + if (FLAG_DECOMP == 0) { + init_param->NUM_ITER = 1; /* changed from 2 */ + init_param->FANIN_COLLAPSE = 8; /* changed from 3 */ + init_param->DECOMP_FANIN = 4; + init_param->QUICK_PHASE = 1; + init_param->HEURISTIC_NUM = 3; + } + else { + init_param->NUM_ITER = 1; /* 0 earlier - Jan 11 93*/ + init_param->FANIN_COLLAPSE = 8; /* 0 earlier */ + init_param->DECOMP_FANIN = 4; /* 0 earlier */ + init_param->QUICK_PHASE = 0; + init_param->HEURISTIC_NUM = HEURISTIC_NUM_ORIG; + } + init_param->DISJOINT_DECOMP = 0; + init_param->GAIN_FACTOR = 0.001; + init_param->map_alg = init_init_param->map_alg; + init_param->mode = 0.0; + init_param->COLLAPSE_FANINS_OF_FANOUT = 15; + init_param->ITE_FANIN_LIMIT_FOR_BDD = 40; + init_param->COST_LIMIT = 3; + init_param->LAST_GASP = 0; + init_param->BREAK = 1; /* 0 earlier */ + init_param->ALTERNATE_REP = 0; + init_param->COLLAPSE_UPDATE = INEXPENSIVE; + init_param->MAP_METHOD = init_init_param->MAP_METHOD; + init_param->VAR_SELECTION_LIT = init_init_param->VAR_SELECTION_LIT; + init_param->COLLAPSE_METHOD = init_init_param->COLLAPSE_METHOD; + init_param->DECOMP_METHOD = init_init_param->DECOMP_METHOD; + + act_ite_map_network_with_iter(network1, init_param); + act_free_ite_network(network1); /* frees the ite, act and match */ + + /* this makes sure that the nodes of network1 do not lose their ite, match or network */ + /*------------------------------------------------------------------------------------*/ + init_param->BREAK = 0; + act_ite_map_network_with_iter(network1, init_param); + + FREE(init_param); + + cost_network1 = ite_print_network(network1, -1); + assert(cost_network1 == network_num_nonzero_cost_nodes(network1)); + + if (ACT_ITE_DEBUG) + (void) printf (" the original cost of node = %d, cost after remapping = %d\n", + cost_node_original, cost_network1); + gain = cost_node_original - cost_network1; + if (gain <= 0) { + act_free_ite_network(network1); + network_free(network1); + node_free(dup_node); + return alternate_gain; + } + + /* replace the node in the original network by the network1 + better not to call pld_replace_node_by_network, since we + need to replace the cost_struct also. */ + /*---------------------------------------------------------*/ + nodevec1 = network_dfs(network1); + table1 = st_init_table(st_ptrcmp, st_ptrhash); + /* set correspondence between p.i. and ... */ + /*-----------------------------------------*/ + pld_remap_init_corr(table1, network, network1); + num_nodes2 = array_n(nodevec1) - 2; + for (i = 0; i < num_nodes2; i++) { + node1 = array_fetch(node_t *, nodevec1, i); + if (node1->type != INTERNAL) continue; + node1_dup = pld_remap_get_node(node1, table1); + node1_dup->name = NIL (char); /* possibility of leak -> no */ + node1_dup->short_name = NIL (char); + network_add_node(network, node1_dup); + if (ACT_ITE_DEBUG) (void) node_print(sisout, node1_dup); + if (init_init_param->MAP_METHOD == MAP_WITH_ITER || init_init_param->MAP_METHOD == MAP_WITH_JUST_DECOMP) { + act_ite_network_update_pi(node1_dup, node1, table1, network1); + } else { + /* get the cost_struct for node1 and put it in the node1_dup */ + /*-----------------------------------------------------------*/ + act_ite_cost_struct_replace(node1_dup, node1, init_init_param->map_alg); + act_ite_remap_update_ite_fields(table1, network1, node1_dup); + } + assert(!st_insert(table1, (char *) node1, (char *) node1_dup)); + } + /* the last node in the array in primary output - do not want that */ + /*-----------------------------------------------------------------*/ + node1 = array_fetch(node_t *, nodevec1, num_nodes2); + assert(node1->type == INTERNAL); + node1_dup = pld_remap_get_node(node1, table1); + node_replace(node, node1_dup); + if (init_init_param->MAP_METHOD == MAP_WITH_ITER || init_init_param->MAP_METHOD == MAP_WITH_JUST_DECOMP) { + act_ite_network_update_pi(node, node1, table1, network1); + } else { + act_ite_cost_struct_replace(node, node1, init_init_param->map_alg); + act_ite_remap_update_ite_fields(table1, network1, node); + } + assert(!st_insert(table1, (char *) node1, (char *) node)); + + st_free_table(table1); + array_free(nodevec1); + network_free(network1); + node_free(dup_node); + return (gain + alternate_gain); +} + +/*------------------------------------------------------------------------------ + Given node1 of the network1 and node1_dup which is a replica of node1, and + an implementation of node1 in terms of network1, change names of the primary + inputs of network1 so that it can be attached to node1_dup. +-------------------------------------------------------------------------------*/ + + +act_ite_network_update_pi(node1_dup, node1, table1, network1) + node_t *node1_dup, *node1; + st_table *table1; + network_t *network1; +{ + network_t *network_node1; + array_t *pivec; + lsGen gen; + int i; + node_t *pi, *pi1, *pi1_dup; + + network_node1 = ACT_ITE_SLOT(node1)->network; + pivec = array_alloc(node_t *, 0); + foreach_primary_input(network_node1, gen, pi) { + array_insert_last(node_t *, pivec, pi); + } + for (i = 0; i < array_n(pivec); i++) { + pi = array_fetch(node_t *, pivec, i); + pi1 = network_find_node(network1, node_long_name(pi)); + assert(pi1); + if (pi1->type == PRIMARY_INPUT) { + assert(st_lookup(table1, (char *) pi1, (char **) &pi1_dup)); + assert(strcmp(node_long_name(pi), node_long_name(pi1_dup)) == 0); + continue; + } + assert(pi1->type == INTERNAL); + assert(st_lookup(table1, (char *) pi1, (char **) &pi1_dup)); + network_change_node_name(network_node1, pi, util_strsav(node_long_name(pi1_dup))); + } + network_free(ACT_ITE_SLOT(node1_dup)->network); + ACT_ITE_SLOT(node1_dup)->network = network_node1; + ACT_ITE_SLOT(node1_dup)->cost = network_num_nonzero_cost_nodes(network_node1); + ACT_ITE_SLOT(node1)->network = NIL(network_t); + array_free(pivec); +} + +int ite_print_network(network, iteration_num) + network_t *network; + int iteration_num; +{ + lsGen gen; + node_t *node; + int TOTAL_COST; + node_function_t node_fun; + + TOTAL_COST = 0; + if (ACT_ITE_DEBUG) (void) printf("printing network %s\n", network_name(network)); + foreach_node(network, gen, node) { + node_fun = node_function(node); + if ((node_fun == NODE_PI) || (node_fun == NODE_PO)) continue; + if (ACT_ITE_DEBUG) { + node_print(stdout, node); + (void) printf("cost = %d\n\n", ACT_ITE_SLOT(node)->cost); + } + TOTAL_COST += ACT_ITE_SLOT(node)->cost; + } + if (ACT_ITE_DEBUG) { + if (iteration_num < 0) + (void) printf("**** total cost of network after all iterations is %d\n***", + TOTAL_COST); + else + (void) printf("**** total cost of network after iteration %d is %d\n***", + iteration_num, TOTAL_COST); + } + return TOTAL_COST; +} + +/*----------------------------------------------------------------------------------- + If using bdd now, use ite and vice versa. If cost improves, accept the alternate + representation. +------------------------------------------------------------------------------------*/ +int +act_ite_use_alternate_rep(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + + ACT_ITE_COST_STRUCT *cost_node; + ACT_VERTEX_PTR act_of_node; + int cost_bdd, cost_ite; + + if ((node->type == PRIMARY_INPUT) || (node->type == PRIMARY_OUTPUT)) return 0; + if (init_param->HEURISTIC_NUM == 3) return 0; + cost_node = ACT_ITE_SLOT(node); + if (cost_node->cost <= 2) return 0; + if (init_param->HEURISTIC_NUM <= 1) { + act_of_node = my_create_act(node, init_param->mode, NIL (st_table), node->network, + NIL (array_t)); /* this sets the pointers in node->pld */ + cost_bdd = act_bdd_make_tree_and_map(node, act_of_node); + if (cost_bdd <= cost_node->cost) { + ite_my_free(cost_node->ite); + cost_node->ite = NIL (ite_vertex); + cost_node->cost = cost_bdd; + cost_node->arrival_time = act_of_node->arrival_time; + cost_node->act = act_of_node; + return 1; + } + my_free_act(act_of_node); + cost_node->act = NIL (ACT_VERTEX); + return 0; + } + assert(init_param->HEURISTIC_NUM == 2); + make_ite(node); + cost_ite = act_ite_make_tree_and_map(node); + if (cost_ite < cost_node->cost) { + my_free_act(cost_node->act); + cost_node->act = NIL (ACT_VERTEX); + cost_node->arrival_time = ACT_ITE_ite(node)->arrival_time; + cost_node->cost = cost_ite; + return 1; + } + ite_my_free(cost_node->ite); + cost_node->ite = NIL (ite_vertex); + return 0; +} diff --git a/sis/pld/ite_int.h b/sis/pld/ite_int.h new file mode 100644 index 0000000..1522729 --- /dev/null +++ b/sis/pld/ite_int.h @@ -0,0 +1,165 @@ +#include "act_bool.h" + +/*----------------------- Will's file starts --------------------------------*/ + +/* commenting the following to make mapping work */ +/* #define ite_slot ite +#define ite_get(node) ((ite_vertex *) (node)->ite_slot) */ + +typedef struct ite_vertex_defn { + struct ite_vertex_defn *IF,*THEN,*ELSE; + struct fo_ite_vertex *fo; + int index; + int value; /* 1 for ONE, 0 for ZERO, 2 for literal,*/ + /*3 for nonterminal node*/ + int id; + int mark; /* for printing use temporarily */ + int print_mark; /* 0 for have been printed */ + int index_size; + node_t *node; + node_t *fanin; + char *name; + int multiple_fo; + int multiple_fo_for_mapping; + int cost; + double arrival_time; + int pattern_num; + int mapped; + struct ite_vertex_defn *parent; + int phase; + } ite_vertex, *ite_vertex_ptr; + +typedef struct fo_ite_vertex { + ite_vertex_ptr *parent_ite_ptr; + struct fo_ite_vertex *next; + } fanout_ite; + +/*-----------------------------my file starts -------------------------------*/ + +#define EXPENSIVE 1 +#define INEXPENSIVE 0 +#define NEW 1 +#define OLD 0 +#define MAP_WITH_ITER 2 +#define MAP_WITH_JUST_DECOMP 3 +#define USE_GOOD_DECOMP 0 +#define USE_FACTOR 1 + +typedef struct act_ite_cost_struct_defn{ + node_t *node; /* pointer to the node of the network */ + int cost; /* number of basic blocks used to realize the node */ + double arrival_time; /* arrival_time at the output of the node */ + double required_time; /* required_time at the output of the node */ + double slack; /* slack = required_time - arrival_time */ + int is_critical; /* is 1 if the slack is <= some threshold */ + double area_weight; /* penalty if node is collapsed */ + double cost_and_arrival_time; + ite_vertex_ptr ite; /* stores the ite for the node */ + ACT_VERTEX_PTR act; /* stores the robdd for the node */ + char *will_ite; + ACT_MATCH *match; /* if the cost is 1, stores the match here */ + network_t *network; /* if MAP_METHOD is MAP_WITH_ITER, this is + the network associated with the node */ +} ACT_ITE_COST_STRUCT; + +#define ACT_DEF_ITE_SLOT(node) node->ite +#define ACT_ITE_SLOT(node) ((ACT_ITE_COST_STRUCT *)node->ite) +#define ACT_ITE_ite(node) (ACT_ITE_SLOT(node)->ite) +#define ACT_ITE_act(node) (ACT_ITE_SLOT(node)->act) +#define ACT_ITE_will_ite(node) (ACT_ITE_SLOT(node)->will_ite) +/* ite_map.c */ +extern int act_is_or_used; +extern int ACT_ITE_DEBUG; +extern ite_vertex_ptr PRESENT_ITE; +extern ACT_VERTEX_PTR PRESENT_ACT; + +/* #ifndef +#define MAXINT 10000000 +#endif +*/ /* Feb 8, 1992 - defined in pld_int.h */ +extern int act_map_ite(); +extern act_ite_map_network_with_iter(); + +/* com_ite.c */ +extern void act_ite_alloc(); +extern void act_ite_free(); +extern int ACT_ITE_DEBUG; +extern int ACT_ITE_STATISTICS; +extern int ACT_BDD_NEW; +extern int USE_FAC_WHEN_UNATE; /* only used when V >= 0, and new mapper */ +extern int ACT_ITE_ALPHA; /* for binateness of the variable */ +extern int ACT_ITE_GAMMA; /* for binateness of the resulting functions */ +extern int UNATE_SELECT; /* if 1, then apply max column cover for unate functions for m = 1 */ + +/* ite_urp.c */ +extern ite_vertex *ite_literal(); +extern ite_vertex *my_shannon_ite(); +extern void ite_split_F(); +extern st_table *ite_end_table; +extern int ACT_ITE_FIND_KERNEL; + +/* act_ite.c */ +extern node_t *act_make_node_from_row(); +extern ite_vertex *ite_OR_itevec(); + +/* ite_leaf.c */ +extern ite_vertex *ite_check_for_single_literal_cubes(); + +/* ite_util.c */ +/* +extern node_t *pld_remap_get_node(); +*/ /* pld_int.h */ +extern node_t *ite_get_node_literal_of_vertex(); +extern st_table *ite_my_traverse_ite(); + +/* ite_break.c */ +extern node_t *act_ite_get_function(); +extern node_t *act_new_act_get_function(); + +/* ite_new_urp.c */ +extern ite_vertex *ite_for_muxnode(); +extern ite_vertex *ite_buffer(); +extern ite_vertex *ite_inv(); +extern ite_vertex *ite_get_vertex(); +extern ite_vertex *ite_new_OR(); +extern ite_vertex *ite_new_OR_with_inv(); +extern ite_vertex *ite_create_ite_for_orthogonal_cubes(); +extern ite_vertex *ite_new_ite_for_unate_cover(); +extern ite_vertex *ite_convert_match_to_ite(); +extern node_t *node_most_binate_variable(); +extern node_t *node_most_binate_variable_new(); +extern node_t *ite_get_minimum_cost_variable(); +extern ite_vertex *ite_new_literal(); + +/* act_ite_new.c */ +extern ite_vertex *ite_new_ite_for_cubenode(); +extern ite_vertex *ite_new_ite_for_single_literal_cubes(); +extern ite_vertex *ite_new_ite_and(); +extern ite_vertex *ite_new_ite_or(); + +/* ite_new_map.c */ +extern act_ite_map_node_with_iter_imp(); + +/* ite_new_bdd.c */ +extern network_t *act_map_using_new_bdd(); + +/* ite_factor.c */ +extern ite_vertex *act_ite_create_from_factored_form(); +extern ite_vertex *act_ite_factored_and(); +extern ite_vertex *act_ite_factored_or(); +extern ite_vertex *act_ite_get_ite(); + +/*---------------------------- my file ends ----------------------------*/ + + +#define ite_slot (ACT_ITE_COST_STRUCT *) ite +#define ite_get(node) ((ite_vertex_ptr) (ACT_ITE_SLOT(node)->will_ite)) + + +extern void ite_clear_dag(); +extern ite_vertex *ite_alloc(); +extern void ite_print_dag(); +extern void ite_print_out(); +extern void ite_assgn_num(); +extern void ite_print(); + diff --git a/sis/pld/ite_leaf.c b/sis/pld/ite_leaf.c new file mode 100644 index 0000000..ab736ab --- /dev/null +++ b/sis/pld/ite_leaf.c @@ -0,0 +1,210 @@ +#include "sis.h" +#include "pld_int.h" /* uncommented Feb 9, 1992 */ +#include "ite_int.h" + +static check_universal(); +static void unate_split_F(); + +/* Here we have obtained a unate leaf and wish to construct its bdd*/ +ite_vertex * +unate_ite(F, node) +sm_matrix *F; +node_t *node; +{ + ite_vertex *ite, *ite_for_cube_F(), *unate_ite(), *my_or_ite_F(); + int i, j; + sm_matrix *M; + sm_col *pcol; + sm_row *cover; + sm_element *p; + array_t *array, *array_ite; + int *phase; + int *weights; /* -ve phase variables get slightly lower weight */ + int is_neg_phase, pos_weight; + int orig_col_num, all_twos; + + /* Check whether the matrix has more than one cube and contains + the universal cube. This helps to prune the tree! */ + /*--------------------------------------------------------------*/ + if(check_universal(F)) { + assert(st_lookup(ite_end_table, (char *)1, (char **) &ite)); + return ite; + } + + /* If matrix has only one row, construct ite so that the AND of the + variables is realised. */ + /*-----------------------------------------------------------------*/ + if (F->nrows == 1){ + ite = ite_for_cube_F(F, node); + return ite; + } + /* if the matrix F corresponds to cubes with single literal each, + construct ite with special attention to variable ordering */ + /*----------------------------------------------------------------*/ + ite = ite_check_for_single_literal_cubes(F, node->network); + if (ite != NIL (ite_vertex)) return ite; + + /* Construct the M matrix which is used for covering purposes + Its number of columns may be different from F's number of + columns, since there may be a column of all 2's in F. Then, + M's columns get shifted to left as compared to F. */ + /*-----------------------------------------------------------*/ + is_neg_phase = 0; /* see if some variable in -ve phase */ + phase = ALLOC(int, F->ncols); + M = sm_alloc(); + j = -1; + sm_foreach_col(F,pcol) { + all_twos = 1; + phase[pcol->col_num] = 2; /* initialize */ + sm_foreach_col_element(pcol, p){ + if(p->user_word != (char *)2) { + if (all_twos != 0) { + all_twos = 0; + j++; + } + (void) sm_insert(M, p->row_num, j); + sm_get_col(M, j)->user_word = (char *) p->col_num; + phase[p->col_num] = (int )p->user_word; + if (phase[p->col_num] == 0) is_neg_phase = 1; + } + } + } + + + /* solve covering problem for M*/ + /* assigning weights - in general, give slightly lower weights to the + -ve phase variables, so that they may occur higher in the order. + "Slight" difference, so that it is not possible to reduce the + weight of the cover by removing one positive guy and putting more + than one negative guys. . We want the + cardinality of the cover to be minimum, with the ties being broken + in favour of -ve wt. variables. + If all variables of positive phase, pass NIL (int). */ + /*--------------------------------------------------------------------*/ + if (is_neg_phase) { + weights = ALLOC(int, M->ncols); + pos_weight = M->ncols + 1; + for (i = 0, j = 0; i < F->ncols; i++) { + switch(phase[i]) { + case 0: + weights[j] = M->ncols; + j++; + break; + case 1: + weights[j] = pos_weight; + j++; + break; + case 2: + break; + } + } + assert(j == M->ncols); + cover = sm_minimum_cover(M, weights, 0, 0); + FREE(weights); + } else { + cover = sm_minimum_cover(M, NIL(int), 0, 0); + } + /* + sm_foreach_row_element(cover, p){ + p->user_word = (char *)phase[p->col_num]; + } + */ + /* change the column and user_word information of the elements of cover + to point to the columns of F (from M). */ + /*---------------------------------------------------------------------*/ + sm_foreach_row_element(cover, p) { + orig_col_num = (int) (sm_get_col(M, p->col_num)->user_word); + p->user_word = (char *) phase[orig_col_num]; /* as earlier */ + p->col_num = orig_col_num; + } + sm_free_space(M); + FREE(phase); + array = array_alloc(sm_matrix *, 0); + /* construct sub matrices as a result of the covering solution*/ + unate_split_F(F, cover, array); + /* Recursively solve each of the sub matrices*/ + array_ite = array_alloc(ite_vertex *, 0); + for( i = 0; i < array_n(array); i++ ) { + ite = unate_ite(array_fetch(sm_matrix *, array, i), node); + array_insert_last(ite_vertex *, array_ite, ite); + } + if(array_n(array_ite) != cover->length) { + (void)fprintf(misout, + "error array length (of ites) and minucov solution do not match \n"); + exit(1); + } + ite = my_or_ite_F(array_ite, cover, array, node->network); + /* Free up the area alloced for array and the Fi s.*/ + for(i = 0; i< array_n(array); i++ ){ + sm_free_space(array_fetch(sm_matrix *, array, i)); + } + array_free(array); + array_free(array_ite); + sm_row_free(cover); + return ite; +} + + +/* checks for a row of 2's. returns 1 if true else 0*/ +static int +check_universal(F) +sm_matrix *F; +{ + sm_row *row; + sm_element *p; + int var; + + sm_foreach_row(F, row) { + var = 1; + sm_foreach_row_element(row, p){ + if(p->user_word != (char *)2) { + var = 0; + } + } + if (var) return 1; + } + return 0; +} + + + + + + +/* constructs a set of sub matrices from F such that */ +static void +unate_split_F(F, cover, array) +sm_matrix *F; +sm_row *cover; +array_t *array; +{ + sm_element *p, *q; + sm_col *col; + sm_matrix *Fi; + sm_row *row, *F_row, *my_row_dup(); + int col_num; + +/* Initialise row->user_word == NUll to prevent duplication of cubes + * if 2 elements in the cover contain the same cube! Need for optimisation*/ + + sm_foreach_row(F, row) { + row->user_word = (char *)0; + } + sm_foreach_row_element(cover, q) { + col_num = q->col_num; + col = sm_get_col(F, col_num); + Fi = sm_alloc(); + sm_foreach_col_element(col, p) { + F_row = sm_get_row(F, p->row_num); + if((p->user_word != (char *)2)&&(F_row->user_word == (char *)0)) { + my_sm_copy_row(F_row, Fi, col_num, F); + if(ACT_ITE_DEBUG > 2) { + my_sm_print(Fi); + } + F_row->user_word = (char *)1; + } + } + array_insert_last(sm_matrix *, array, Fi); + } +} + diff --git a/sis/pld/ite_map.c b/sis/pld/ite_map.c new file mode 100644 index 0000000..3e44f87 --- /dev/null +++ b/sis/pld/ite_map.c @@ -0,0 +1,682 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + +static void act_initialize_ite_area(); + +ite_vertex_ptr PRESENT_ITE; +extern int WHICH_ACT; + +act_ite_map_network_with_iter(network, init_param) + network_t *network; + act_init_param_t *init_param; +{ + /* act_ite_preprocess(network, init_param); */ /* done with a separate command */ + act_ite_map_network(network, init_param); + act_ite_iterative_improvement(network, init_param); + if (init_param->BREAK) act_ite_break_network(network, init_param); +} + +act_ite_preprocess(network, init_param) + network_t *network; + act_init_param_t *init_param; +{ + array_t *nodevec; + int i; + node_t *node; + + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) continue; + if (node_num_literal(node) > init_param->lit_bound) decomp_quick_node(network, node); + } + array_free(nodevec); +} + +/*---------------------------------------------------------------- + For each intermediate node of the network, builds up the ite + and then maps it to the basic blocks of the ACTEL architecture. + NOTE: it does not free the ite at each node. +------------------------------------------------------------------*/ +act_ite_map_network(network, init_param) + network_t *network; + act_init_param_t *init_param; +{ + array_t *nodevec; + int i; + node_t *node; + int total_cost = 0; + + nodevec = network_dfs(network); + + switch(init_param->MAP_METHOD) { + case MAP_WITH_ITER:; + case MAP_WITH_JUST_DECOMP: + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + total_cost += act_ite_map_node_with_iter_imp(node, init_param); + } + break; + case NEW: + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + total_cost += act_ite_new_map_node(node, init_param); + } + break; + case OLD: + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + total_cost += act_ite_map_node(node, init_param); + } + break; + default: + (void) printf("mapping method %d not known\n", init_param->MAP_METHOD); + exit(1); + } + if (ACT_ITE_DEBUG || ACT_ITE_STATISTICS) { + (void) printf("number of basic blocks = %d\n", total_cost); + } + array_free(nodevec); +} + +int +act_ite_map_node(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + node_t **order_list, **act_ite_order_fanins(); + ACT_MATCH *match; + ACT_ITE_COST_STRUCT *cost_node; + ACT_VERTEX_PTR act_of_node; + int cost_bdd; + node_function_t node_fun; + + if ((node->type == PRIMARY_INPUT) || (node->type == PRIMARY_OUTPUT)) return 0; + cost_node = ACT_ITE_SLOT(node); + /* note: not handling constants separately, because either remove them by sweep + before, or if needed, act_is_act_function will detect and use a block */ + /* check if the node is realizable by one block */ + /*----------------------------------------------*/ + match = act_is_act_function(node, init_param->map_alg, act_is_or_used); + if (match) { + cost_node->match = match; + node_fun = node_function(node); + if (node_fun == NODE_0 || node_fun == NODE_1 || node_fun == NODE_BUF) { + cost_node->cost = 0; /* added Nov. 18, 92 - earlier wrong cost assignment */ + } else { + cost_node->cost = 1; + } + return cost_node->cost; + } + + switch (init_param->HEURISTIC_NUM) { + case 0: + /* make heuristic ite */ + /*--------------------*/ + make_ite(node); + cost_node->cost = act_ite_make_tree_and_map(node); + cost_node->arrival_time = ACT_ITE_ite(node)->arrival_time; + cost_node->node = node; + /* cost_node->ite = ACT_ITE_ite(node); */ /* make_ite sets this */ + break; + case 1: + /* construct canonical ite */ + /*-------------------------*/ + order_list = act_ite_order_fanins(node); + /* ite_pld(node, order_list); */ /* commented Jul 21, 1992 */ + /* just for the time being */ + ACT_ITE_ite(node) = ite_get(node); + FREE(order_list); + cost_node->cost = act_ite_make_tree_and_map(node); + cost_node->arrival_time = ACT_ITE_ite(node)->arrival_time; + cost_node->node = node; + /* cost_node->ite = ACT_ITE_ite(node); */ + break; + case 2: + /* make ROBDD */ + /*------------*/ + act_of_node = my_create_act(node, init_param->mode, NIL (st_table), node->network, + NIL (array_t)); /* this sets the pointers in node->pld */ + cost_node->cost = act_bdd_make_tree_and_map(node, act_of_node); + cost_node->arrival_time = act_of_node->arrival_time; + cost_node->node = node; + cost_node->act = act_of_node; + break; + case 3: + /* make both heuristic ite and ROBDD - select the one with lower cost */ + /*--------------------------------------------------------------------*/ + make_ite(node); + cost_node->cost = act_ite_make_tree_and_map(node); + cost_node->arrival_time = ACT_ITE_ite(node)->arrival_time; + cost_node->node = node; + if (cost_node->cost <= 2) break; + if (node_num_fanin(node) <= init_param->ITE_FANIN_LIMIT_FOR_BDD) { + act_of_node = my_create_act(node, init_param->mode, NIL (st_table), node->network, + NIL (array_t)); + cost_bdd = act_bdd_make_tree_and_map(node, act_of_node); + /* made it <= rather than <, since ite_map -n 1 later may be + better for a BDD rather than an ITE */ + if (cost_bdd <= cost_node->cost) { + ite_my_free(cost_node->ite); + cost_node->ite = NIL (ite_vertex); + cost_node->cost = cost_bdd; + cost_node->arrival_time = act_of_node->arrival_time; + cost_node->act = act_of_node; + } else { + my_free_act(act_of_node); + cost_node->act = NIL (ACT_VERTEX); + } + } + break; + default: + fail("heuristic number out of range"); + break; + } + return cost_node->cost; +} + + +/*------------------------------------------------------------------- + Assumes that ite of the node has been created. Breaks the ite into + trees and maps each tree using the pattern graphs. +--------------------------------------------------------------------*/ +int +act_ite_make_tree_and_map(node) + node_t *node; + +{ + ite_vertex_ptr ite_of_node; + int num_ite; + int i; + int num_mux_struct; + int TOTAL_MUX_STRUCT; /* cost of the node */ + ite_vertex_ptr ite; + array_t *multiple_fo_array; + + ite_of_node = ACT_ITE_ite(node); /* check this */ + TOTAL_MUX_STRUCT = 0; + + /* initialize the required structures */ + /*------------------------------------*/ + multiple_fo_array = array_alloc(ite_vertex_ptr, 0); + array_insert_last(ite_vertex_ptr, multiple_fo_array, ite_of_node); + act_initialize_ite_area(ite_of_node, multiple_fo_array); + + + if (ACT_ITE_DEBUG > 3) { + ite_print_dag(ite_of_node); + /* print_multiple_fo_array(multiple_fo_array); */ + } + + /* traverse the ite of node bottom up and map each tree ite */ + /*----------------------------------------------------------*/ + num_ite = array_n(multiple_fo_array); + for (i = num_ite - 1; i >= 0; i--) { + ite = array_fetch(ite_vertex_ptr, multiple_fo_array, i); + PRESENT_ITE = ite; + num_mux_struct = act_map_ite(ite); + TOTAL_MUX_STRUCT += num_mux_struct; + } + if (ACT_ITE_DEBUG) + (void) printf("number of total mux_structures used for the node %s = %d, arrival_time = %f\n", + node_long_name(node), TOTAL_MUX_STRUCT, ite_of_node->arrival_time); + array_free(multiple_fo_array); + ite_clear_dag(ite_of_node); /* to make all mark fields 0 */ + if (ACT_ITE_DEBUG > 1) { + node_print(stdout, node); + ite_print_dag(ite_of_node); + } + return TOTAL_MUX_STRUCT; +} + + +/*----------------------------------------------------------------------------- + Maps a given vertex of ite-dag into pattern graphs for ACTEL architecture. + If the vertex has multiple fanouts, does not map until PRESENT_ITE = vertex. + The detection of OR-gate is easy in this case. + Note: need to change the OR-gate detection: there are additional cases that + could be detected: + IF X THEN Z1 ELSE (IF Y THEN Z1 ELSE Z2) + <=> IF (X + Y) THEN Z1 ELSE Z2. + Here X, Y, Z1, Z2 are any functions. + This can, however, never occur in canonical ite. +------------------------------------------------------------------------------*/ + +int +act_map_ite(vertex) + ite_vertex_ptr vertex; +{ + + int TOTAL_PATTERNS = 10; + int pat_num, best_pat_num; + int cost[10]; /* for each of the 10 patterns derived from the mux struct */ + int vif_cost, vthen_cost, velse_cost; + int vifif_cost, vifelse_cost; + int vthenif_cost, vthenthen_cost, vthenelse_cost; + int velseif_cost, velsethen_cost, velseelse_cost; + int velseelseif_cost, velseelsethen_cost, velseelseelse_cost; + int temp_if_cost, temp_then_cost, temp_else_cost, temp_elseelse_cost; + int OR_pattern1, OR_pattern2; + int compl_then, compl_else, compl_elseelse; + int cond_then, cond_else, cond_elseelse; + + /* if vertex has multiple fanouts (but is not the root of the present + multiple_fo vertex) return 0, as this vertex would be/ or was + visited earlier as a root. Basically zero is not its true cost. + So do not set vertex->mapped = 1 also. + NOTE: order of this statement and the next statement (vertex->mapped + == 1) is opposite in mapping using bdd's. This order makes + code of v_thenif, etc. very easy. */ + /*------------------------------------------------------------------*/ + + if ((vertex->multiple_fo) && (vertex != PRESENT_ITE)) { + return 0; + } + + /* if cost already computed, don't compute again */ + /*-----------------------------------------------*/ + if (vertex->mapped) return vertex->cost; + + vertex->mapped = 1; + + if ((vertex->value == 0) || (vertex->value == 1)) { + vertex->cost = 0; + return 0; + } + + if (vertex->value == 2) { + assert(vertex->phase == 0 || vertex->phase == 1); + if (vertex->phase == 1) { + vertex->cost = 0; + return 0; + } + vertex->cost = 1; + vertex->pattern_num = 0; + return vertex->cost; + } + /* vertex->value = 3 */ + /*-------------------*/ + + /* if simply an input variable, return 0 */ + /*---------------------------------------*/ + if ((vertex->IF->value == 2) && (vertex->IF->phase == 1) + && (vertex->THEN->value == 1) && (vertex->ELSE->value == 0)) { + vertex->cost = 0; + return 0; + } + /* if or gate not used, just used first 4 patterns */ + /*-------------------------------------------------*/ + if (!act_is_or_used) TOTAL_PATTERNS = 4; + + /* initialize cost vector to a very high value for all the patterns*/ + /*-----------------------------------------------------------------*/ + for (pat_num = 0; pat_num < TOTAL_PATTERNS; pat_num++) { + cost[pat_num] = MAXINT; + } + + /* recursively calculate relevant costs */ + /*--------------------------------------*/ + + vif_cost = act_map_ite(vertex->IF); + vthen_cost = act_map_ite(vertex->THEN); + velse_cost = act_map_ite(vertex->ELSE); + + OR_pattern1 = 0; + if ((vertex->IF->value == 3) && (vertex->IF->THEN->value == 1)) { + OR_pattern1 = 1; + if (vertex->IF->multiple_fo == 0) { + vifif_cost = act_map_ite(vertex->IF->IF); + vifelse_cost = act_map_ite(vertex->IF->ELSE); + temp_if_cost = vifif_cost + vifelse_cost; + } + } + + /* changed Dec. 10, 1992 - to handle the fact that now terminal 1 and 0 + vertices may be replicated all over the place - added value conditions */ + /*------------------------------------------------------------------------*/ + OR_pattern2 = 0; + if ((vertex->ELSE->value == 3) && (vertex->ELSE->multiple_fo == 0) + && ((vertex->THEN == vertex->ELSE->THEN) || + (vertex->THEN->value == 0 && vertex->ELSE->THEN->value == 0) || + (vertex->THEN->value == 1 && vertex->ELSE->THEN->value == 1) + ) + ) { + OR_pattern2 = 1; + cond_elseelse = 0; + if (vertex->ELSE->ELSE->multiple_fo == 0) { + compl_elseelse = act_vertex_ite_complemented(vertex->ELSE->ELSE); + cond_elseelse = ((vertex->ELSE->ELSE->value == 3) || compl_elseelse); + if (compl_elseelse) temp_elseelse_cost = 0; + if (vertex->ELSE->ELSE->value == 3) { + velseelseif_cost = act_map_ite(vertex->ELSE->ELSE->IF); + velseelsethen_cost = act_map_ite(vertex->ELSE->ELSE->THEN); + velseelseelse_cost = act_map_ite(vertex->ELSE->ELSE->ELSE); + temp_elseelse_cost = velseelseif_cost + velseelsethen_cost + + velseelseelse_cost; + } + } + } + + /* conditions to be used multiple times later */ + /*--------------------------------------------*/ + compl_then = act_vertex_ite_complemented(vertex->THEN); + compl_else = act_vertex_ite_complemented(vertex->ELSE); + cond_then = ((vertex->THEN->value == 3) || (compl_then)); + cond_else = ((vertex->ELSE->value == 3) || (compl_else)); + + /* if complemented phase, can realize it with the input mux, so cost = 0 */ + /*-----------------------------------------------------------------------*/ + if (compl_then) { + temp_then_cost = 0; + } + if (vertex->THEN->value == 3) { + if (vertex->THEN->multiple_fo) { + vthenif_cost = vthenthen_cost = vthenelse_cost = MAXINT; + } + else { + vthenif_cost = act_map_ite(vertex->THEN->IF); + vthenthen_cost = act_map_ite(vertex->THEN->THEN); + vthenelse_cost = act_map_ite(vertex->THEN->ELSE); + } + temp_then_cost = vthenif_cost + vthenthen_cost + vthenelse_cost; + } + + if (compl_else) { + temp_else_cost = 0; + } + if (vertex->ELSE->value == 3) { + if (vertex->ELSE->multiple_fo) { + velseif_cost = velsethen_cost = velseelse_cost = MAXINT; + } + else { + velseif_cost = act_map_ite(vertex->ELSE->IF); + velsethen_cost = act_map_ite(vertex->ELSE->THEN); + velseelse_cost = act_map_ite(vertex->ELSE->ELSE); + } + temp_else_cost = velseif_cost + velsethen_cost + velseelse_cost; + } + + /* enumerate possible cases */ + /*--------------------------*/ + + /* if_cost + then_cost + else_cost + 1 */ + /*-------------------------------------*/ + cost[0] = vif_cost + vthen_cost + velse_cost + 1; + + if (cond_then) { + cost[1] = vif_cost + temp_then_cost + velse_cost + 1; + } + + if (cond_else) { + cost[2] = vif_cost + vthen_cost + temp_else_cost + 1; + } + + if (cond_then && cond_else) { + cost[3] = vif_cost + temp_then_cost + temp_else_cost + 1; + } + + if (!act_is_or_used) { + /* find minimum cost */ + /*-------------------*/ + best_pat_num = minimum_cost_index(cost, TOTAL_PATTERNS); + vertex->cost = cost[best_pat_num]; + vertex->pattern_num = best_pat_num; + if (ACT_ITE_DEBUG > 3) + (void) printf("vertex id = %d, index = %d, cost = %d, name = %s, pattern_num = %d\n", + vertex->id, vertex->index, vertex->cost, vertex->name, vertex->pattern_num); + return vertex->cost; + } + + /* OR patterns - recognized easily here - if vertex->IF->THEN is constant + 1, then the OR pattern is there. */ + /*-----------------------------------------------------------------------*/ + + if ((OR_pattern1 == 1) && (vertex->IF->multiple_fo == 0)) { + cost[4] = temp_if_cost + vthen_cost + velse_cost + 1; + + if (cond_then) { + cost[5] = temp_if_cost + temp_then_cost + velse_cost + 1; + } + + if (cond_else) { + cost[6] = temp_if_cost + vthen_cost + temp_else_cost + 1; + } + + if (cond_then && cond_else) { + cost[7] = temp_if_cost + temp_then_cost + temp_else_cost + 1; + } + } + + if (OR_pattern2 == 1) { + cost[8] = vif_cost + temp_else_cost + 1; + + if (cond_elseelse) { + cost[9] = vif_cost + vthen_cost + velseif_cost + temp_elseelse_cost + 1; + assert(vthen_cost == 0); + } + } + /* find minimum cost */ + /*-------------------*/ + best_pat_num = minimum_cost_index(cost, TOTAL_PATTERNS); + vertex->cost = cost[best_pat_num]; + vertex->pattern_num = best_pat_num; + if (ACT_ITE_DEBUG > 3) + (void) printf("vertex id = %d, index = %d, cost = %d, name = %s, pattern_num = %d\n", + vertex->id, vertex->index, vertex->cost, vertex->name, vertex->pattern_num); + return vertex->cost; +} + +/*-------------------------------------------------------------------- + returns the index of the pattern which results in the minimum cost + at the present node. +---------------------------------------------------------------------*/ +static +int minimum_cost_index(cost, num_entries) + int cost[]; + int num_entries; +{ + + int i; + int min_index = 0; + + for (i = 1; i < num_entries; i++) { + if (cost[i] < cost[min_index]) min_index = i; + } + return min_index; +} + +/*------------------------------------------------------------------ + If the vertex is just realizing an inverter, return 1. Else 0. +-------------------------------------------------------------------*/ +int +act_vertex_ite_complemented(vertex) + ite_vertex_ptr vertex; +{ + return ((vertex->value == 2) && (vertex->phase == 0)); +} + +/*---------------------------------------------------------------------- + recursively initialize the required structure of each act vertex. + also finds out multiple fan out vertices and stores them in the + multiple_fo_array. +------------------------------------------------------------------------*/ + +static void +act_initialize_ite_area(vertex, multiple_fo_array) + ite_vertex_ptr vertex; + array_t *multiple_fo_array; +{ + /* to save repetition, mark the vertex as visited */ + /*------------------------------------------------*/ + if (vertex->mark == 0) vertex->mark = 1; + else vertex->mark = 0; + + vertex->pattern_num = -1; + vertex->cost = 0; + vertex->arrival_time = (double) 0.0; + vertex->mapped = 0; + vertex->multiple_fo = 0; + vertex->multiple_fo_for_mapping = 0; + + /* do not care for a terminal vertex- nothing is to be done */ + /*----------------------------------------------------------*/ + if (vertex->value != 3) { + vertex->cost = 0; + vertex->arrival_time = (double) (0.0); + return; + } + + /* if the IF (THEN, ELSE) not visited earlier, initialize it, else + mark it as a multiple fo vertex */ + /*---------------------------------------------------------------*/ + + if (vertex->mark != vertex->IF->mark) { + act_initialize_ite_area(vertex->IF, multiple_fo_array); + } + else { + /* important to check that it is a multiple_fo vertex, else you may be + adding a vertex too many times in the multiple_fo array. */ + /*--------------------------------------------------------------------*/ + if (vertex->IF->multiple_fo == 0) { + array_insert_last(ite_vertex_ptr, multiple_fo_array, vertex->IF); + } + vertex->IF->multiple_fo += 1; + vertex->IF->multiple_fo_for_mapping += 1; + } + + if (vertex->mark != vertex->THEN->mark) { + act_initialize_ite_area(vertex->THEN, multiple_fo_array); + } + else { + if (vertex->THEN->multiple_fo == 0) { + array_insert_last(ite_vertex_ptr, multiple_fo_array, vertex->THEN); + } + vertex->THEN->multiple_fo += 1; + vertex->THEN->multiple_fo_for_mapping += 1; + } + if (vertex->mark != vertex->ELSE->mark) { + act_initialize_ite_area(vertex->ELSE, multiple_fo_array); + } + else { + if (vertex->ELSE->multiple_fo == 0) { + array_insert_last(ite_vertex_ptr, multiple_fo_array, vertex->ELSE); + } + vertex->ELSE->multiple_fo += 1; + vertex->ELSE->multiple_fo_for_mapping += 1; + } +} + +/*------------------------------------------------------------------ + Given a node, returns the fanins of the node in the order_list. + The order is just the order used in misII numbering of the fanins. +--------------------------------------------------------------------*/ +node_t ** +act_ite_order_fanins(node) + node_t *node; +{ + node_t **order_list, *fanin; + int i; + + order_list = ALLOC(node_t *, node_num_fanin(node)); + foreach_fanin(node, i, fanin) { + order_list[i] = fanin; + } + return order_list; +} + +/* +static +print_multiple_fo_array(multiple_fo_array) + array_t *multiple_fo_array; +{ + int nsize; + int i; + ite_vertex_ptr v; + + (void) printf("---- printing multiple_fo_vertices---"); + nsize = array_n(multiple_fo_array); + for (i = 0; i < nsize; i++) { + v = array_fetch(ite_vertex_ptr, multiple_fo_array, i); + (void) printf(" index = %d, id = %d, num_fanouts = %d\n ", + v->index, v->id, v->multiple_fo + 1); + } + (void) printf("\n"); +} +*/ + +/* +int +act_ite_decomp_big_nodes(network, DECOMP_FANIN) + network_t *network; + int DECOMP_FANIN; +{ + + array_t *nodevec; + int size_net, i, gain; + node_t *node; + + nodevec = network_dfs(network); + size_net = array_n(nodevec); + for (i = 0; i < size_net; i++) { + node = array_fetch(node_t *, nodevec, i); + act_ite_decomp_big_node(node, &gain, DECOMP_FANIN); + if gain > + } + array_free(nodevec); +} +*/ + +ite_free_cost_struct(cost_struct) + ACT_ITE_COST_STRUCT *cost_struct; +{ + if (cost_struct == NIL (ACT_ITE_COST_STRUCT)) return; + FREE(cost_struct); +} + + +/*----------------------------------------------------------------------- + Used to make the bdd work along with the ite's. +------------------------------------------------------------------------*/ +int +act_bdd_make_tree_and_map(node, act_of_node) + node_t *node; + ACT_VERTEX_PTR act_of_node; + +{ + int num_acts; + int i; + int num_mux_struct; + int TOTAL_MUX_STRUCT; /* cost of the network */ + ACT_VERTEX_PTR act; + + ACT_SET(node)->LOCAL_ACT->act->node_list = NIL(array_t ); + act_of_node = ACT_SET(node)->LOCAL_ACT->act->root; + WHICH_ACT = act_of_node->my_type = ORDERED; + act_of_node->node = node; + + TOTAL_MUX_STRUCT = 0; + + act_init_multiple_fo_array(act_of_node); /* insert the root */ + act_initialize_act_area(act_of_node, multiple_fo_array); + /* initialize the required structures */ + /* if (ACT_DEBUG) my_traverse_act(act_of_node); + if (ACT_DEBUG) print_multiple_fo_array(multiple_fo_array); */ + num_acts = array_n(multiple_fo_array); + /* changed the following traversal , now bottom-up */ + /*--------------------------------------------------*/ + for (i = num_acts - 1; i >= 0; i--) { + act = array_fetch(ACT_VERTEX_PTR, multiple_fo_array, i); + PRESENT_ACT = act; + num_mux_struct = map_act(act); + TOTAL_MUX_STRUCT += num_mux_struct; + } + if (ACT_DEBUG) { + (void) printf("total mux_structures used for the node %s = %d, arrival_time = %f\n", + node_long_name(node), TOTAL_MUX_STRUCT, act_of_node->arrival_time); + } + array_free(multiple_fo_array); + act_act_free(node); + return TOTAL_MUX_STRUCT; +} + diff --git a/sis/pld/ite_mroot.c b/sis/pld/ite_mroot.c new file mode 100644 index 0000000..7827d43 --- /dev/null +++ b/sis/pld/ite_mroot.c @@ -0,0 +1,381 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + +extern ite_vertex *PRESENT_ITE; + +/* +* This file contains routines to construct a multiple-root ite for the +* entire network. Then it is mapped. First we +* use the existing code to construct the ite for each node, then change the +* information in the ite: like appropriately changing the pointers. Then a +* mapping is performed. +*/ + +act_ite_create_and_map_mroot_network(network, init_param) + network_t *network; + act_init_param_t *init_param; +{ + act_ite_create_mroot_ite_network(network, init_param); + (void) act_ite_mroot_make_tree_and_map(network); + /* if (init_param->BREAK) act_ite_mroot_break_network(network); */ + act_ite_mroot_traverse_and_free(network); +} + +act_ite_create_mroot_ite_network(network, init_param) + network_t *network; + act_init_param_t *init_param; +{ + + node_t *node; + array_t *nodevec; + int i; + + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + act_ite_intermediate_new_make_ite(node, init_param); /* to skirt the problem of ite_1, ite_0 */ + /* change node, value fields in the ites which are either buffers or inverters */ + /*-----------------------------------------------------------------------------*/ + act_ite_mroot_modify_fields_node(node); + } + array_free(nodevec); +} + + +act_ite_mroot_modify_fields_node(node) + node_t *node; +{ + ite_vertex *ite, *vertex; + st_table *table, *table_free; + st_generator *stgen; + char *key, *value; + node_t *fanin; + + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) return; + + ite = ACT_ITE_ite(node); + + /* ite is buffer, replace it by the fanin ite, free the old one + assuming here that vertex 1 and 0 in the ite are not shared */ + /*--------------------------------------------------------------*/ + if (ite_is_buffer(ite)) { + fanin = ite->IF->fanin; + if (fanin->type != PRIMARY_INPUT) { + ACT_ITE_ite(node) = ACT_ITE_ite(fanin); + ite_my_free(ite); + } + } else { + table = st_init_table(st_ptrcmp, st_ptrhash); /* for traversing ite */ + table_free = st_init_table(st_ptrcmp, st_ptrhash); /* for storing the potential vertices + to be freed */ + act_ite_mroot_modify_fields_ite(ite, table, table_free); + /* free only those vertices of table_free + that are not found in the table */ + /*--------------------------------------*/ + st_foreach_item(table_free, stgen, &key, &value) { + if (st_lookup(table, key, &value)) continue; + vertex = (ite_vertex *) key; + ite_my_free_vertex(vertex); + } + st_free_table(table); + st_free_table(table_free); + } +} + +/*------------------------------------------------------------------- + Given an ite, checks if there is a child which has value 2: then + replaces it by ite of the appropriate fanin node. + + Notes: 1) Most likely, will not work for canonical ite because I am + not taking care of cases like phase = 0. + 2). Also may not work with the ite constructed with -m 0. + Try it and see. May work too because changing the fields + after constructing the ite. + 3) Assuming that ite_1, ite_0 (may be multiple for one node) + not being pointed at by any other node. +--------------------------------------------------------------------*/ +act_ite_mroot_modify_fields_ite(ite, table, table_free) + ite_vertex *ite; + st_table *table, *table_free; +{ + ite_vertex *ite_if, *ite_then, *ite_else; + node_t *fanin; + + if (st_insert(table, (char *) ite, (char *) ite)) return; + if (ite->value <= 1) return; + assert(ite->value == 3); + + ite_if = ite->IF; + if (ite_if->value == 2) { + assert(ite_if->phase == 1); + fanin = ite_if->fanin; + if (fanin->type != PRIMARY_INPUT) { + ite->IF = ACT_ITE_ite(fanin); + (void) st_insert(table_free, (char *) ite_if, (char *) ite_if); + } else { + (void) st_insert(table, (char *) ite_if, (char *) ite_if); + } + } else { + if (ite_is_buffer(ite_if)) { + act_ite_mroot_modify_part(ite, ite_if, 'I', table, table_free); + } else { + act_ite_mroot_modify_fields_ite(ite_if, table, table_free); + } + } + + ite_then = ite->THEN; + if (ite_is_buffer(ite_then)) { + act_ite_mroot_modify_part(ite, ite_then, 'T', table, table_free); + } else { + act_ite_mroot_modify_fields_ite(ite_then, table, table_free); + } + + ite_else = ite->ELSE; + if (ite_is_buffer(ite_else)) { + act_ite_mroot_modify_part(ite, ite_else, 'E', table, table_free); + } else { + act_ite_mroot_modify_fields_ite(ite_else, table, table_free); + } +} + +int +ite_is_buffer(ite) + ite_vertex *ite; +{ + return (ite->value == 3 && ite->IF->value == 2 && ite->IF->phase == 1 && ite->THEN->value == 1 + && ite->ELSE->value == 0); +} + +/*----------------------------------------------------------------------- + Parent's "c" (could be 'I', 'T', 'E') child is a buffer. +------------------------------------------------------------------------*/ +act_ite_mroot_modify_part(parent, child, c, table, table_free) + ite_vertex *parent, *child; + char c; + st_table *table, *table_free; +{ + node_t *fanin; + + fanin = child->IF->fanin; + if (fanin->type != PRIMARY_INPUT) { + (void) st_insert(table_free, (char *) child->THEN, (char *) child->THEN); + (void) st_insert(table_free, (char *) child->ELSE, (char *) child->ELSE); + (void) st_insert(table_free, (char *) child->IF, (char *) child->IF); + (void) st_insert(table_free, (char *) child, (char *) child); + switch(c) { + case 'I': + parent->IF = ACT_ITE_ite(fanin); + break; + case 'T': + parent->THEN = ACT_ITE_ite(fanin); + break; + case 'E': + parent->ELSE = ACT_ITE_ite(fanin); + break; + } + assert(ACT_ITE_ite(fanin)); + } else { + (void) st_insert(table, (char *) child, (char *) child); + (void) st_insert(table, (char *) child->IF, (char *) child->IF); + (void) st_insert(table, (char *) child->THEN, (char *) child->THEN); + (void) st_insert(table, (char *) child->ELSE, (char *) child->ELSE); + } +} + + +act_ite_create_mroot_ite_node(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) return; + /* + if (factor_num_literal(node) > FAC_TO_SOP_RATIO_BOUND * node_num_literal(node)) { + act_ite_new_make_ite(node, init_param); + } else { + ACT_ITE_ite(node) = act_ite_create_from_factored_form(node, init_param); + } + */ /* this is for the time being */ + act_ite_new_make_ite(node, init_param); +} + + + + +/*------------------------------------------------------------------- + Assumes that ite of the node has been created. Breaks the ite into + trees and maps each tree using the pattern graphs. +--------------------------------------------------------------------*/ +int +act_ite_mroot_make_tree_and_map(network) + network_t *network; + +{ + int num_ite; + int i; + int num_mux_struct; + int TOTAL_MUX_STRUCT; /* cost of the node */ + ite_vertex_ptr ite; + array_t *multiple_fo_array; + node_t *po, *po_fanin; + lsGen gen; + + TOTAL_MUX_STRUCT = 0; + multiple_fo_array = array_alloc(ite_vertex_ptr, 0); + foreach_primary_output(network, gen, po) { + po_fanin = node_get_fanin(po, 0); + if (po_fanin->type != PRIMARY_INPUT) { + array_insert_last(ite_vertex_ptr, multiple_fo_array, ACT_ITE_ite(po_fanin)); + } + } + + act_ite_mroot_initialize_ite_area_network(multiple_fo_array); + + /* + if (ACT_ITE_DEBUG > 3) { + ite_print_dag(ite_of_node); + print_multiple_fo_array(multiple_fo_array); + } + */ + + /* traverse the ite of node bottom up and map each tree ite */ + /*----------------------------------------------------------*/ + num_ite = array_n(multiple_fo_array); + for (i = num_ite - 1; i >= 0; i--) { + ite = array_fetch(ite_vertex_ptr, multiple_fo_array, i); + PRESENT_ITE = ite; + num_mux_struct = act_map_ite(ite); + TOTAL_MUX_STRUCT += num_mux_struct; + } + (void) printf("number of total mux_structures used for the network = %d\n", + TOTAL_MUX_STRUCT); + array_free(multiple_fo_array); + /* ite_clear_dag(ite_of_node); */ /* to make all mark fields 0 */ + /* + if (ACT_ITE_DEBUG > 1) { + node_print(stdout, node); + ite_print_dag(ite_of_node); + } + */ + return TOTAL_MUX_STRUCT; +} + + +act_ite_mroot_initialize_ite_area_network(multiple_fo_array) + array_t *multiple_fo_array; +{ + int init_num, i; + st_table *table; + ite_vertex *ite; + + init_num = array_n(multiple_fo_array); + table = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 0; i < init_num; i++) { + ite = array_fetch(ite_vertex *, multiple_fo_array, i); + (void) st_insert(table, (char *) ite, (char *) ite); + ite->multiple_fo = 1; /* to fool the mapper */ + ite->pattern_num = -1; + ite->cost = 0; + ite->arrival_time = (double) 0.0; + ite->mapped = 0; + ite->multiple_fo_for_mapping = 0; + ite->mark = 0; + } + for (i = 0; i < init_num; i++) { + ite = array_fetch(ite_vertex *, multiple_fo_array, i); + if (ite->value == 3) { + act_ite_mroot_initialize_area_ite(ite->IF, multiple_fo_array, table); + act_ite_mroot_initialize_area_ite(ite->THEN, multiple_fo_array, table); + act_ite_mroot_initialize_area_ite(ite->ELSE, multiple_fo_array, table); + } + } + st_free_table(table); +} + +act_ite_mroot_initialize_area_ite(vertex, multiple_fo_array, table) + ite_vertex *vertex; + array_t *multiple_fo_array; + st_table *table; +{ + char *value; + + if (st_lookup(table, (char *) vertex, (char **) &value)) { + if (vertex->multiple_fo == 0) { + array_insert_last(ite_vertex *, multiple_fo_array, vertex); + } + vertex->multiple_fo += 1; + vertex->multiple_fo_for_mapping += 1; + return; + } + assert(!st_insert(table, (char *) vertex, (char *) vertex)); + vertex->pattern_num = -1; + vertex->cost = 0; + vertex->arrival_time = (double) 0.0; + vertex->mapped = 0; + vertex->multiple_fo = 0; + vertex->multiple_fo_for_mapping = 0; + vertex->mark = 0; + + if (vertex->value != 3) return; + act_ite_mroot_initialize_area_ite(vertex->IF, multiple_fo_array, table); + act_ite_mroot_initialize_area_ite(vertex->THEN, multiple_fo_array, table); + act_ite_mroot_initialize_area_ite(vertex->ELSE, multiple_fo_array, table); + +} + +act_ite_mroot_traverse_and_free(network) + network_t *network; +{ + lsGen gen; + node_t *po, *po_fanin; + char *key; + st_generator *stgen; + ite_vertex *vertex; + st_table *table; + + table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_output(network, gen, po) { + po_fanin = node_get_fanin(po, 0); + if (po_fanin->type == PRIMARY_INPUT) continue; + vertex = ACT_ITE_ite(po_fanin); + if (!st_is_member(table, (char *) vertex)) { + assert(!st_insert(table, (char *) vertex, (char *) vertex)); + ite_mroot_traverse_ite(vertex, table); + } + } + st_foreach_item(table, stgen, &key, (char **) &vertex) { + ite_my_free_vertex(vertex); + } + st_free_table(table); +} + +ite_mroot_traverse_ite(vertex, table) + ite_vertex *vertex; + st_table *table; +{ + if (vertex->value != 3) return; + + if (!st_is_member(table, (char *) vertex->IF)) { + assert(!st_insert(table, (char *) vertex->IF, (char *) vertex->IF)); + ite_mroot_traverse_ite(vertex->IF, table); + } + if (!st_is_member(table, (char *) vertex->THEN)) { + assert(!st_insert(table, (char *) vertex->THEN, (char *) vertex->THEN)); + ite_mroot_traverse_ite(vertex->THEN, table); + } + if (!st_is_member(table, (char *) vertex->ELSE)) { + assert(!st_insert(table, (char *) vertex->ELSE, (char *) vertex->ELSE)); + ite_mroot_traverse_ite(vertex->ELSE, table); + } +} + +/* +act_ite_mroot_break_network(network) + network_t *network; +{ + foreach_primary_output(network, gen, po) { + po_fanin = node_get_fanin(po, 0); + act_ite_mroot_break_node(po, +} +*/ diff --git a/sis/pld/ite_mux_net.c b/sis/pld/ite_mux_net.c new file mode 100644 index 0000000..567978b --- /dev/null +++ b/sis/pld/ite_mux_net.c @@ -0,0 +1,76 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + +act_ite_mux_network(network, init_param, FAC_TO_SOP_RATIO) + network_t *network; + act_init_param_t *init_param; + float FAC_TO_SOP_RATIO; +{ + array_t *nodevec; + int i, num_lit; + node_t *node; + node_function_t node_fun; + + nodevec = network_dfs(network); + + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + num_lit = node_num_literal(node); + if ((num_lit > 4) && (factor_num_literal(node) < FAC_TO_SOP_RATIO * num_lit)) { + ACT_ITE_ite(node) = act_ite_create_from_factored_form(node, init_param); + } else { + act_ite_intermediate_new_make_ite(node, init_param); + } + act_ite_initialize_ite_area_pattern0(ACT_ITE_ite(node)); + /* next line checks if it is a buffer node, 0, 1 node, do nothing - Sept 10, 93 */ + /*------------------------------------------------------------------------------*/ + node_fun = node_function(node); + if (node_fun != NODE_0 && node_fun != NODE_1 && node_fun != NODE_BUF) { + ACT_ITE_SLOT(node)->cost = 2; /* to fool act_ite_break_node */ + act_ite_break_node(node, init_param); + } + } + array_free(nodevec); + act_free_ite_network(network); +} + +/*----------------------------------------------------------------- + Initialize each vertex of the ite so that its mapped field is 1 + and pattern_num = 0 (just a mux.). Set the multiple_fo vertex + correctly because it will be needed while breaking the node. +------------------------------------------------------------------*/ +act_ite_initialize_ite_area_pattern0(ite) + ite_vertex *ite; +{ + st_table *table; + + table = st_init_table(st_ptrcmp, st_ptrhash); + act_ite_insert_table_area_pattern0(ite, table); + st_free_table(table); +} + +act_ite_insert_table_area_pattern0(ite, table) + ite_vertex *ite; + st_table *table; +{ + if (st_insert(table, (char *) ite, (char *) ite)) { + (ite->multiple_fo)++; + return; + } + + ite->pattern_num = 0; + ite->cost = 0; + ite->mark = 0; + ite->mapped = 1; + ite->arrival_time = (double) 0.0; + ite->multiple_fo = 0; + ite->multiple_fo_for_mapping = 0; + + if (ite->value < 3) return; + act_ite_insert_table_area_pattern0(ite->IF, table); + act_ite_insert_table_area_pattern0(ite->THEN, table); + act_ite_insert_table_area_pattern0(ite->ELSE, table); +} + diff --git a/sis/pld/ite_new_map.c b/sis/pld/ite_new_map.c new file mode 100644 index 0000000..e410426 --- /dev/null +++ b/sis/pld/ite_new_map.c @@ -0,0 +1,110 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + +/*-------------------------------------------------------------------------- + This is another mapping method which takes a node, makes a network out + of it and then uses MAP_METHOD = NEW to map the network, uses iterative + improvement on this network to get a good representation. If + init_param->MAP_METHOD requires just decomp, then FANIN_COLLAPSE field + is set to 0. Else it is left untouched. +---------------------------------------------------------------------------*/ +act_ite_map_node_with_iter_imp(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + node_function_t node_fun; + network_t *network1; + /* network_t *new_network; */ /* commented because using new bdd package - not using */ + int save_iter, save_break, save_last_gasp; + /* int act_bdd_new_sav; */ + /* int new_cost */ /* commented because using new bdd package - not using */ + int save_map_method, save_fanin_collapse; + + node_fun = node_function(node); + if (node_fun == NODE_PI || node_fun == NODE_PO) return 0; + if (node_fun == NODE_0 || node_fun == NODE_1 || node_fun == NODE_BUF) { + ACT_ITE_SLOT(node)->network = NIL (network_t); + ACT_ITE_SLOT(node)->cost = 0; + } else { + network1 = network_create_from_node(node); + + save_iter = init_param->NUM_ITER; + save_break = init_param->BREAK; + save_last_gasp = init_param->LAST_GASP; + save_map_method = init_param->MAP_METHOD; + save_fanin_collapse = init_param->FANIN_COLLAPSE; + + if (init_param->MAP_METHOD == MAP_WITH_JUST_DECOMP) { + init_param->FANIN_COLLAPSE = 0; + } + init_param->NUM_ITER = 1; + /* change init_param->MAP_METHOD to NEW */ + init_param->MAP_METHOD = NEW; + init_param->BREAK = 1; + init_param->LAST_GASP = 0; + /* + act_bdd_new_sav = ACT_BDD_NEW; + ACT_BDD_NEW = 0; + */ + + act_ite_map_network_with_iter(network1, init_param); /* with at most one iteration */ + act_free_ite_network(network1); /* frees the ite, act and match */ + ACT_ITE_SLOT(node)->cost = network_num_nonzero_cost_nodes(network1); + + /* this takes care of single literal cubes, single cubes and optimum mapping */ + /*---------------------------------------------------------------------------*/ + if (ACT_ITE_SLOT(node)->cost > 2 && (node_fun != NODE_AND) && (node_fun != NODE_OR) && + save_map_method == MAP_WITH_ITER) { + act_ite_map_network_with_iter(network1, init_param); + act_free_ite_network(network1); /* frees the ite, act and match */ + ACT_ITE_SLOT(node)->cost = network_num_nonzero_cost_nodes(network1); + } + ACT_ITE_SLOT(node)->network = network1; + + /* commented Mar 3 94 for official release - Long bdd package!*/ + /* + if (ACT_ITE_SLOT(node)->cost > 3 && act_bdd_new_sav && (node_fun != NODE_AND) && (node_fun != NODE_OR)) { + new_network = act_map_using_new_bdd(network1, init_param); + act_free_ite_network(new_network); + new_cost = network_num_nonzero_cost_nodes(new_network); + if (new_cost < ACT_ITE_SLOT(node)->cost) { + network_free(ACT_ITE_SLOT(node)->network); + ACT_ITE_SLOT(node)->network = new_network; + ACT_ITE_SLOT(node)->cost = new_cost; + } else { + network_free(new_network); + } + } + */ + init_param->FANIN_COLLAPSE = save_fanin_collapse; + init_param->MAP_METHOD = save_map_method; + init_param->NUM_ITER = save_iter; + init_param->LAST_GASP = save_last_gasp; + init_param->BREAK = save_break; + /* ACT_BDD_NEW = act_bdd_new_sav; */ + + } + return ACT_ITE_SLOT(node)->cost; +} + +int +network_num_nonzero_cost_nodes(network) + network_t *network; +{ + int count; + node_t *node; + node_function_t node_fun; + lsGen gen; + + count = 0; + foreach_node(network, gen, node) { + if (node->type != INTERNAL) continue; + node_fun = node_function(node); + if (node_fun == NODE_0 || node_fun == NODE_1 || node_fun == NODE_BUF) continue; + count++; + } + return count; +} + + diff --git a/sis/pld/ite_new_urp.c b/sis/pld/ite_new_urp.c new file mode 100644 index 0000000..0377b2b --- /dev/null +++ b/sis/pld/ite_new_urp.c @@ -0,0 +1,1216 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" +#include "math.h" + +extern st_table *ite_end_table; +static ite_vertex *ite_1, *ite_0; +static sm_matrix *build_F(); +static ite_vertex* urp_F(); +static int good_bin_var(); +static int find_var(); +static void update_F(); +extern my_sm_copy_row(), my_sm_print(); + +int +act_ite_new_map_node(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + ACT_ITE_COST_STRUCT *cost_node; + + if ((node->type == PRIMARY_INPUT) || (node->type == PRIMARY_OUTPUT)) return 0; + act_ite_intermediate_new_make_ite(node, init_param); + cost_node = ACT_ITE_SLOT(node); + cost_node->cost = act_ite_make_tree_and_map(node); + cost_node->arrival_time = ACT_ITE_ite(node)->arrival_time; + cost_node->node = node; + return cost_node->cost; +} + +act_ite_intermediate_new_make_ite(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + ite_vertex *ite; + node_function_t node_fun; + + if ((node->type == PRIMARY_INPUT) || (node->type == PRIMARY_OUTPUT)) return; + node_fun = node_function(node); + switch(node_fun) { + case NODE_0: + ite = ite_alloc(); + ite->value = 0; + ACT_ITE_ite(node) = ite; + break; + case NODE_1: + ite = ite_alloc(); + ite->value = 1; + ACT_ITE_ite(node) = ite; + break; + default: + ite_end_table = st_init_table(st_ptrcmp, st_ptrhash); + ite_0 = ite_alloc(); + ite_0->value = 0; + (void) st_insert(ite_end_table, (char *)0, (char *)ite_0); + ite_1 = ite_alloc(); + ite_1->value = 1; + (void) st_insert(ite_end_table, (char *)1, (char *)ite_1); + act_ite_new_make_ite(node, init_param); + st_free_table(ite_end_table); + break; + } +} + +/* We need this to initialise the 0 and 1 ite's and store them + * in a table so they can be easily accessed + Note: node must be in the network (the only use of network is to get the fanin nodes + from the fanin names: so the restriction can be removed in future, if needed)*/ + +act_ite_new_make_ite(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + ite_vertex *ite_lit, *ite_if, *ite_else, *ite_else_if, *ite_else_then, *ite_else_else, + *ite_a, *ite_b, *ite_1_sav, *ite_0_sav, *ite_unate; + node_function_t node_fun, node_fun_if; + node_t *node_if, *node_else_then, *node_else_else, *fanin_a, *fanin_b, *variable, *fanin; + int num_cube, num_lit, num_cube_if, flag; + ACT_ITE_COST_STRUCT *cost_node; + ACT_MATCH *match; + st_table *ite_end_table_sav; + + /* handle trivial cases */ + /*----------------------*/ + node_fun = node_function(node); + switch(node_fun) { + case NODE_PI:; + case NODE_PO: + return; + case NODE_0: + ACT_ITE_ite(node) = ite_0; + return; + case NODE_1: + ACT_ITE_ite(node) = ite_1; + return; + case NODE_BUF: + fanin = node_get_fanin(node, 0); + ite_lit = ite_new_literal(fanin); + ACT_ITE_ite(node) = my_shannon_ite(ite_lit, ite_1, ite_0); + return; + } + + /* check if node is a single cube */ + /*--------------------------------*/ + num_cube = node_num_cube(node); + if (num_cube == 1) { + ACT_ITE_ite(node) = ite_new_ite_for_cubenode(node); + return; + } + + /* check if node is composed of single-literal cubes */ + /*---------------------------------------------------*/ + num_lit = node_num_literal(node); + if (num_lit == num_cube) { + ACT_ITE_ite(node) = ite_new_ite_for_single_literal_cubes(node); + return; + } + + /* check if the node is realizable by one block */ + /*----------------------------------------------*/ + cost_node = ACT_ITE_SLOT(node); + match = act_is_act_function(node, init_param->map_alg, act_is_or_used); + if (match) { + /* cost_node->match = match; */ + ACT_ITE_ite(node) = ite_convert_match_to_ite(node, match); + act_free_match(cost_node->match); + assert(!(cost_node->match)); /* just a check */ + return; + } + + /* if the node is a function of cubes of disjoint support */ + /*--------------------------------------------------------*/ + if (num_lit == node_num_fanin(node)) { + ACT_ITE_ite(node) = ite_create_ite_for_orthogonal_cubes(node); + return; + } + + if (UNATE_SELECT) { + if (node_is_unate(node)) { + ACT_ITE_ite(node) = ite_new_ite_for_unate_cover(node, init_param); + return; + } + } + + switch (init_param->VAR_SELECTION_LIT) { + case 0: + variable = node_most_binate_variable(node); + break; + case (-1): + /* first save these global variables since the next routine is + going to change them */ + /*--------------------------------------------------------------*/ + ite_1_sav = ite_1; + ite_0_sav = ite_0; + ite_end_table_sav = ite_end_table; + + variable = ite_get_minimum_cost_variable(node, init_param); + + ite_1 = ite_1_sav; + ite_0 = ite_0_sav; + ite_end_table = ite_end_table_sav; + break; + default: + ite_1_sav = ite_1; + ite_0_sav = ite_0; + ite_end_table_sav = ite_end_table; + + /* this may call indirectly act_ite_intermediate_new_make_ite() */ + variable = node_most_binate_variable_new(node, init_param, &ite_unate); + + + ite_1 = ite_1_sav; + ite_0 = ite_0_sav; + ite_end_table = ite_end_table_sav; + break; + } + if (init_param->VAR_SELECTION_LIT > 0 && !variable) { + assert(ite_unate); + ACT_ITE_ite(node) = ite_unate; + return; + } + assert(variable); + node_algebraic_cofactor(node, variable, &node_else_then, &node_else_else, &node_if); + + /* at least one of node_else_then and node_else_then is not a constant, since + we checked if num_occur > 1 in this case */ + /*----------------------------------------------------------------------------*/ + act_ite_new_make_ite(node_else_then, init_param); + act_ite_new_make_ite(node_else_else, init_param); + ite_else_if = ite_new_literal(variable); + ite_else_then = ACT_ITE_ite(node_else_then); + ite_else_else = ACT_ITE_ite(node_else_else); + ite_else = my_shannon_ite(ite_else_if, ite_else_then, ite_else_else); + + /* check if node_if satisfies some simple conditions, under which OR gate + may not be used or may be used effectively */ + /*-----------------------------------------------------------------------*/ + node_fun_if = node_function(node_if); + switch(node_fun_if) { + case NODE_0: + ACT_ITE_ite(node) = ite_else; + break; + case NODE_BUF: + fanin = node_get_fanin(node_if, 0); + ite_if = ite_new_literal(fanin); + ACT_ITE_ite(node) = my_shannon_ite(ite_if, ite_1, ite_else); + break; + case NODE_INV: + fanin = node_get_fanin(node_if, 0); + ite_if = ite_new_literal(fanin); + ACT_ITE_ite(node) = my_shannon_ite(ite_if, ite_else, ite_1); + break; + default: + /* node_if is of the form a' b' */ + /*------------------------------*/ + flag = 0; + num_cube_if = node_num_cube(node_if); + if (num_cube_if == 1 && node_num_fanin(node_if) == 2) { + fanin_a = node_get_fanin(node_if, 0); + if (node_input_phase(node_if, fanin_a) == NEG_UNATE) { + fanin_b = node_get_fanin(node_if, 1); + if (node_input_phase(node_if, fanin_b) == NEG_UNATE) { + ite_a = ite_buffer(fanin_a); + ite_b = ite_buffer(fanin_b); + ite_if = ite_new_OR(ite_a, ite_b); + ACT_ITE_ite(node) = my_shannon_ite(ite_if, ite_else, ite_1); + flag = 1; + } + } + } + if (!flag) { + act_ite_new_make_ite(node_if, init_param); + ite_if = ACT_ITE_ite(node_if); + ACT_ITE_ite(node) = my_shannon_ite(ite_if, ite_1, ite_else); + } + } + node_free(node_if); + node_free(node_else_then); + node_free(node_else_else); +} + +/*----------------------------------------------------------- + Return the fanin of the node that occurs most often in the + SOP. Priority is given to a fanin that occurs in all the + cubes in the same phase. Then, the ties are broken by + selecting the fanin that has minimum difference between the + positive and the negative occurrences. In pnum_occur, return + the total number of occurrences of the variable being + returned. +-------------------------------------------------------------*/ +node_t * +node_most_binate_variable(node) + node_t *node; +{ + + int *lit_count_array, j, j2, j2p1, num_cube, max_count, diff_count, index, j_count, j_diff_count; + node_t *variable; + + if (node_num_fanin(node) == 0) return NIL(node_t); + + num_cube = node_num_cube(node); + lit_count_array = node_literal_count(node); + max_count = -1; + diff_count = -1; + index = -1; + for (j = 0; j < node_num_fanin(node); j++) { + j2 = 2 * j; + j2p1 = j2 + 1; + j_count = lit_count_array[j2] + lit_count_array[j2p1]; + j_diff_count = abs(lit_count_array[j2] - lit_count_array[j2p1]); + if (j_count > max_count) { + index = j; + max_count = j_count; + diff_count = j_diff_count; + continue; + } + if (j_count == max_count) { + /* if jth variable occurs in all the cubes in the same phase, or + it occurs nearly the same number of times in the +ve & -ve phases + (and the best guy so far does not occur in all the cubes in the + same phase) select it */ + /*------------------------------------------------------------------*/ + if ((j_diff_count == num_cube) || + ((diff_count != num_cube) && (j_diff_count < diff_count))) { + diff_count = j_diff_count; + index = j; + max_count = j_count; + } + } + } + FREE(lit_count_array); + variable = node_get_fanin(node, index); + return variable; +} + +node_t * +node_most_binate_variable_new(node, init_param, pite) + node_t *node; + act_init_param_t *init_param; + ite_vertex **pite; +{ + + int *lit_count_array, j, j2, j2p1, num_cube, max_count, wt, max_weight; + int unate, diff_count, index, j_count, j_diff_count; + node_t *variable, *fanin; + + if (node_num_fanin(node) == 0) return NIL(node_t); + + num_cube = node_num_cube(node); + lit_count_array = node_literal_count(node); + + /* check if the SOP is unate */ + /*---------------------------*/ + unate = 1; + j2 = -2; + for (j = 0; j < node_num_fanin(node); j++) { + j2 += 2; + if (lit_count_array[j2] && lit_count_array[j2 + 1]) { + unate = 0; + break; + } + } + if (unate) { + if (USE_FAC_WHEN_UNATE) { + *pite = act_ite_create_from_factored_form(node, init_param); + FREE(lit_count_array); + return NIL (node_t); + } + + /* select variable that occurs most often, break the + ties by selecting a negative unate variable */ + /*--------------------------------------------------*/ + max_count = -1; index = -1; + j2 = -2; + for (j = 0; j < node_num_fanin(node); j++) { + j2 += 2; + j2p1 = j2 + 1; + j_count = lit_count_array[j2] + lit_count_array[j2p1]; + if ((j_count > max_count) || + (j_count == max_count && lit_count_array[j2] == 0) + ) { + max_count = j_count; + index = j; + } + + } + FREE(lit_count_array); + variable = node_get_fanin(node, index); + return variable; + } + + if (node_num_literal(node) >= init_param->VAR_SELECTION_LIT) { + /* assign weight to each fanin node, + select the fanin with the max wt */ + /*----------------------------------*/ + max_weight = -1; + for (j = 0; j < node_num_fanin(node); j++) { + fanin = node_get_fanin(node, j); + wt = ite_assign_var_weight(node, fanin, j, lit_count_array); + if (wt > max_weight) { + max_weight = wt; + variable = fanin; + } + } + return variable; + } + + max_count = -1; + diff_count = -1; + index = -1; + j2 = -2; j2p1 = -1; + for (j = 0; j < node_num_fanin(node); j++) { + j2 += 2; + j2p1 += 2; + j_count = lit_count_array[j2] + lit_count_array[j2p1]; + j_diff_count = abs(lit_count_array[j2] - lit_count_array[j2p1]); + if (j_count > max_count) { + index = j; + max_count = j_count; + diff_count = j_diff_count; + continue; + } + if (j_count == max_count) { + /* if jth variable occurs in all the cubes in the same phase, or + it occurs nearly the same number of times in the +ve & -ve phases + (and the best guy so far does not occur in all the cubes in the + same phase) select it */ + /*------------------------------------------------------------------*/ + if ((j_diff_count == num_cube) || + ((diff_count != num_cube) && (j_diff_count < diff_count))) { + diff_count = j_diff_count; + index = j; + max_count = j_count; + } + } + } + FREE(lit_count_array); + variable = node_get_fanin(node, index); + return variable; +} + +/*--------------------------------------------------------------------- + Compute a fast cost estimate of the algebraic cofactors of the node + function with respect to each fanin and returns the variable that + results in minimum cost. +-----------------------------------------------------------------------*/ +node_t * +ite_get_minimum_cost_variable(node, init_param) + node_t *node; + act_init_param_t *init_param; + +{ + int min_cost, j, cost; + node_t *fanin, *variable; + int break_sav, num_iter_sav, map_method_sav, var_selection_lit_sav, last_gasp_save; + /* int bdd_new_sav; */ + + /* change some of the init_param fields to make a faster mapping */ + /*---------------------------------------------------------------*/ + break_sav = init_param->BREAK; + num_iter_sav = init_param->NUM_ITER; + map_method_sav = init_param->MAP_METHOD; + var_selection_lit_sav = init_param->VAR_SELECTION_LIT; + last_gasp_save = init_param->LAST_GASP; + /* bdd_new_sav = ACT_BDD_NEW; */ + + init_param->BREAK = 0; + init_param->NUM_ITER = 0; + init_param->MAP_METHOD = NEW; + init_param->VAR_SELECTION_LIT = 0; + init_param->LAST_GASP = 0; + /* ACT_BDD_NEW = 0; */ + + min_cost = MAXINT; + for (j = 0; j < node_num_fanin(node); j++) { + fanin = node_get_fanin(node, j); + cost = ite_assign_var_cost(node, fanin, init_param, min_cost); + if (cost < min_cost) { + min_cost = cost; + variable = fanin; + } + } + /* restore the init_param fields */ + /*-------------------------------*/ + init_param->BREAK = break_sav; + init_param->NUM_ITER = num_iter_sav; + init_param->MAP_METHOD = map_method_sav; + init_param->VAR_SELECTION_LIT = var_selection_lit_sav; + init_param->LAST_GASP = last_gasp_save; + /* ACT_BDD_NEW = bdd_new_sav; */ + + return variable; +} + +/*--------------------------------------------------------------------- + Converting a match to an ITE. Remember that inputs to a match are + either 0, 1 or node_literal(fanin, 1) where fanin was an input + of node. +----------------------------------------------------------------------*/ +ite_vertex * +ite_convert_match_to_ite(node, match) + node_t *node; + ACT_MATCH *match; +{ + + node_function_t node_fun, node_fun_S1, node_fun_S0; + ite_vertex *ite, *ite_IF, *ite_THEN, *ite_ELSE, *ite_lit, *ite_IF_1, *ite_IF_2; + node_t *fanin; + + node_fun = node_function(node); + switch(node_fun) { + case NODE_0: + return ite_0; + case NODE_1: + return ite_1; + case NODE_BUF: + fanin = node_get_fanin(node, 0); + ite_lit = ite_new_literal(fanin); + ite = my_shannon_ite(ite_lit, ite_1, ite_0); + return ite; + case NODE_INV: + fanin = node_get_fanin(node, 0); + ite_lit = ite_new_literal(fanin); + ite = my_shannon_ite(ite_lit, ite_0, ite_1); + return ite; + } + + node_fun_S0 = node_function(match->S0); + node_fun_S1 = node_function(match->S1); + ite_THEN = ite_for_muxnode(match->SB, match->B0, match->B1); + ite_ELSE = ite_for_muxnode(match->SA, match->A0, match->A1); + if (node_fun_S0 == NODE_1 || node_fun_S1 == NODE_1) { + ite_IF = ite_1; + } else { + if (node_fun_S0 == NODE_0) { + ite_IF = ite_get_vertex(match->S1); + } else { + if (node_fun_S1 == NODE_0) { + ite_IF = ite_get_vertex(match->S0); + } else { + ite_IF_1 = ite_get_vertex(match->S0); + ite_IF_2 = ite_get_vertex(match->S1); + ite_IF = my_shannon_ite(ite_IF_1, ite_1, ite_IF_2); + } + } + } + ite = my_shannon_ite(ite_IF, ite_THEN, ite_ELSE); + return ite; +} + +ite_vertex * +ite_for_muxnode(control, zero, one) + node_t *control, *zero, *one; +{ + + node_function_t node_fun; + node_t *mux_node, *fanin; + ite_vertex *ite, *ite_IF, *ite_THEN, *ite_ELSE; + + mux_node = act_mux_node(control, zero, one); + node_fun = node_function(mux_node); + switch(node_fun) { + case NODE_0: + ite = ite_0; + break; + case NODE_1: + ite = ite_1; + break; + case NODE_BUF: + fanin = node_get_fanin(mux_node, 0); + ite = ite_buffer(fanin); + break; + case NODE_INV: + fanin = node_get_fanin(mux_node, 0); + ite = ite_inv(fanin); + break; + default: + ite_IF = ite_get_vertex(control); + ite_THEN = ite_get_vertex(one); + ite_ELSE = ite_get_vertex(zero); + ite = my_shannon_ite(ite_IF, ite_THEN, ite_ELSE); + break; + } + node_free(mux_node); + return ite; +} + +ite_vertex * +ite_buffer(node) + node_t *node; +{ + + ite_vertex *ite, *ite_IF; + + ite_IF = ite_new_literal(node); + ite = my_shannon_ite(ite_IF, ite_1, ite_0); + return ite; +} + +ite_vertex * +ite_inv(node) + node_t *node; +{ + + ite_vertex *ite, *ite_IF; + + ite_IF = ite_new_literal(node); + ite = my_shannon_ite(ite_IF, ite_0, ite_1); + return ite; +} + +ite_vertex * +ite_get_vertex(node) + node_t *node; +{ + node_function_t node_fun; + ite_vertex *ite; + node_t *fanin; + + node_fun = node_function(node); + + if (node_fun == NODE_0) { + return ite_0; + } + if (node_fun == NODE_1) { + return ite_1; + } + fanin = node_get_fanin(node, 0); + ite = ite_buffer(fanin); + return ite; +} + +/*---------------------------------------------------------------------- + Get ite for each cubenode and then OR these ites. +-----------------------------------------------------------------------*/ +ite_vertex * +ite_create_ite_for_orthogonal_cubes(node) + node_t *node; +{ + array_t *full_ite_vec, *muxfree_ite_vec, *cubevec; + node_t *cubenode; + int i, is_mux_free, p, q; + ite_vertex *ite; + + full_ite_vec = array_alloc(ite_vertex *, 0); + muxfree_ite_vec = array_alloc(ite_vertex *, 0); + + cubevec = pld_nodes_from_cubes(node); + for (i = 0; i < array_n(cubevec); i++) { + cubenode = array_fetch(node_t *, cubevec, i); + ite = ite_new_ite_for_cubenode(cubenode); + pld_find_pos_neg_litcount_in_cube(cubenode, &p, &q); /* p +ve, q -ve */ + is_mux_free = ite_find_mux_remaining(p, q, 0); + if (is_mux_free) { + array_insert_last(ite_vertex *, muxfree_ite_vec, ite); + } else { + array_insert_last(ite_vertex *, full_ite_vec, ite); + } + } + ite_interleave_muxfree_and_full(muxfree_ite_vec, full_ite_vec, 0, 0); + ite = array_fetch(ite_vertex *, full_ite_vec, array_n(full_ite_vec) - 1); + + array_free(muxfree_ite_vec); + array_free(full_ite_vec); + for (i = 0; i < array_n(cubevec); i++) { + cubenode = array_fetch(node_t *, cubevec, i); + node_free(cubenode); + } + array_free(cubevec); + + return ite; +} + +/*---------------------------------------------------------------------- + Given p = number of +ve literals, and q = number of -ve literals in a + cube, return 1 if the top mux of the ACT1 architecture will be + unutilized, else return 0. +-----------------------------------------------------------------------*/ +int +ite_find_mux_remaining(p, q, count) + int p, q, count; +{ + int q_3; + + if (p == 0 && q == 0) return 0; + if (count == 0) { + /* if the cube is just eg f = a, then treat it as full */ + /*-----------------------------------------------------*/ + if (p == 1 && q == 0) return 0; + if (q == 0) { + if (p == 2) return 1; + return ((p - 3) % 2); + } + if (p == 0) { + q_3 = q % 3; + if (q_3 == 0 || q_3 == 2) return 0; + return 1; + } + if (q == 1) { + if (p == 1) return 1; + return ((p - 2) % 2); + } + if (p == 1) { + q_3 = q % 3; + if (q_3 == 0 || q_3 == 2) return 0; + return 1; + } + return ite_find_mux_remaining(p - 2, q - 2, 1); + } + /* count = 1 */ + if (q == 0) return (p % 2); + if (p == 0) { + q_3 = q % 3; + if (q_3 == 0 || q_3 == 2) return 0; + return 1; + } + if (q == 1) return ((p - 1) %2); + return ite_find_mux_remaining(q - 2, p -1 , 1); +} + +/*----------------------------------------------------------------------- + Given a cubenode, return in p number of variables in the positive phase + and in q, the ones in negative phase. +------------------------------------------------------------------------*/ +pld_find_pos_neg_litcount_in_cube(cubenode, p, q) + node_t *cubenode; + int *p, *q; +{ + int i; + node_t *fanin; + input_phase_t phase; + + *p = *q = 0; + assert(node_num_cube(cubenode) == 1); + for (i = 0; i < node_num_fanin(cubenode); i++) { + fanin = node_get_fanin(cubenode, i); + phase = node_input_phase(cubenode, fanin); + switch(phase) { + case POS_UNATE: + (*p)++; + break; + case NEG_UNATE: + (*q)++; + break; + default: + (void) printf("pld_find_pos_neg_litcount_in_cube(): variable type binate?"); + exit(1); + } + } +} + +/*------------------------------------------------------------------- + Pick one element from muxfree_ite_vec and two from full_ite_vec, + OR them in an appropriate way such that the unused mux of the muxfree + ite gets utilized. Boundary cases are handled explicitly causing the + code to become longish. +---------------------------------------------------------------------*/ +ite_interleave_muxfree_and_full(muxfree_ite_vec, full_ite_vec, m, f) + array_t *muxfree_ite_vec, *full_ite_vec; + int m, f; /* pointers to current ites in muxfree and full - ite_vecs */ +{ + ite_vertex *ite, *ite_a, *ite_b, *ite_c, *ite_d, *ite_c1, *ite_c2, *ite_bc, *ite_cd, *ite_ab, *temp; + int diff, diff_f, a_inv, b_inv, c_inv, temp_inv; + + /* when m and f point to the last elements, we are done */ + /*------------------------------------------------------*/ + if ((m == array_n(muxfree_ite_vec)) && (f >= (array_n(full_ite_vec) - 1))) return; + + /* muxfree ites are over, try to combine at most 4 of the full ites */ + /*------------------------------------------------------------------*/ + if (m == array_n(muxfree_ite_vec)) { + while ((diff = array_n(full_ite_vec) - f) >= 2) { + if (diff == 2) { + ite_a = array_fetch(ite_vertex *, full_ite_vec, f++); + ite_b = array_fetch(ite_vertex *, full_ite_vec, f++); + ite = ite_new_OR(ite_a, ite_b); + array_insert_last(ite_vertex *, full_ite_vec, ite); + } else { + if (diff == 3) { + ite_a = array_fetch(ite_vertex *, full_ite_vec, f++); + ite_b = array_fetch(ite_vertex *, full_ite_vec, f++); + ite_c = array_fetch(ite_vertex *, full_ite_vec, f++); + ite_ab = ite_new_OR(ite_a, ite_b); + ite = ite_new_OR(ite_c, ite_ab); + array_insert_last(ite_vertex *, full_ite_vec, ite); + } else { + ite_a = array_fetch(ite_vertex *, full_ite_vec, f++); + ite_b = array_fetch(ite_vertex *, full_ite_vec, f++); + ite_c = array_fetch(ite_vertex *, full_ite_vec, f++); + ite_d = array_fetch(ite_vertex *, full_ite_vec, f++); + ite_ab = ite_new_OR(ite_a, ite_b); + ite_cd = ite_new_OR(ite_c, ite_d); + ite = ite_new_OR(ite_cd, ite_ab); + array_insert_last(ite_vertex *, full_ite_vec, ite); + } + } + } + return; + } + + /* if full ites are over (can happen when there were none to start with), + combine at most 3 mux ites. */ + /*----------------------------------------------------------------------*/ + if (f == array_n(full_ite_vec)) { + diff = array_n(muxfree_ite_vec) - m; + if (diff == 1) { + ite = array_fetch(ite_vertex *, muxfree_ite_vec, m++); + array_insert_last(ite_vertex *, full_ite_vec, ite); + return; + } else { + if (diff == 2) { + ite_a = array_fetch(ite_vertex *, muxfree_ite_vec, m++); + ite_b = array_fetch(ite_vertex *, muxfree_ite_vec, m++); + if (ite_is_inv(ite_a)) { + ite = ite_new_OR_with_inv(ite_a, ite_b); /* saving a mux (an inverter) */ + } else { + if (ite_is_inv(ite_b)) { + ite = ite_new_OR_with_inv(ite_b, ite_a); + } else { + ite = ite_new_OR(ite_b, ite_a); + } + } + array_insert_last(ite_vertex *, full_ite_vec, ite); + return; + } else { + ite_a = array_fetch(ite_vertex *, muxfree_ite_vec, m++); + ite_b = array_fetch(ite_vertex *, muxfree_ite_vec, m++); + ite_c = array_fetch(ite_vertex *, muxfree_ite_vec, m++); + + /* get an inverter (if present) to the "place of c" */ + /*--------------------------------------------------*/ + a_inv = ite_is_inv(ite_a); + b_inv = ite_is_inv(ite_b); + c_inv = ite_is_inv(ite_c); + if (c_inv) { + } else { + if (a_inv) { + temp = ite_a; + ite_a = ite_c; + ite_c = temp; + temp_inv = a_inv; + a_inv = c_inv; + c_inv = temp_inv; + } else { + if (b_inv) { + temp = ite_b; + ite_b = ite_c; + ite_c = temp; + temp_inv = b_inv; + b_inv = c_inv; + c_inv = temp_inv; + } + } + } + /* get an inverter if possible on a */ + /*----------------------------------*/ + if (b_inv && !a_inv) { + temp = ite_a; + ite_a = ite_b; + ite_b = temp; + temp_inv = a_inv; + a_inv = b_inv; + b_inv = temp_inv; + } + if (c_inv) { + ite_bc = ite_new_OR_with_inv(ite_c, ite_b); + } else { + ite_bc = ite_new_OR(ite_b, ite_c); + } + if (a_inv) { + ite = ite_new_OR_with_inv(ite_a, ite_bc); + } else { + ite = ite_new_OR(ite_bc, ite_a); + } + array_insert_last(ite_vertex *, full_ite_vec, ite); + ite_interleave_muxfree_and_full(muxfree_ite_vec, full_ite_vec, m, f); + return; + } + } + } + + /* combination of muxfree and full ites to be combined - at least one of each present*/ + /*-----------------------------------------------------------------------------------*/ + diff_f = array_n(full_ite_vec) - f; + if (diff_f == 1) { + ite_c = array_fetch(ite_vertex *, full_ite_vec, f++); + } else { + ite_c1 = array_fetch(ite_vertex *, full_ite_vec, f++); + ite_c2 = array_fetch(ite_vertex *, full_ite_vec, f++); + ite_c = ite_new_OR(ite_c1, ite_c2); + } + ite_a = array_fetch(ite_vertex *, muxfree_ite_vec, m++); + if (ite_is_inv(ite_a)) { + ite = ite_new_OR_with_inv(ite_a, ite_c); + } else { + ite = ite_new_OR(ite_c, ite_a); + } + array_insert_last(ite_vertex *, full_ite_vec, ite); + ite_interleave_muxfree_and_full(muxfree_ite_vec, full_ite_vec, m, f); +} + +ite_vertex * +ite_new_OR(ite_a, ite_b) + ite_vertex *ite_a, *ite_b; +{ + ite_vertex *ite; + + ite = my_shannon_ite(ite_a, ite_1, ite_b); + return ite; +} + +/*-------------------------------------------------------------------- + Returns ite_a + ite_b, knowing that ite_a is an inverter. So first + makes ite_a' (a positive literal) and then does OR by interchanging + the otherwise THEN and ELSE children of the root node. +----------------------------------------------------------------------*/ +ite_vertex * +ite_new_OR_with_inv(ite_a, ite_b) + ite_vertex *ite_a, *ite_b; +{ + ite_vertex *temp, *ite; + + if (ite_a->value == 2) { + assert (ite_a->phase == 0); + ite_a->phase = 1; + } else { + temp = ite_a->THEN; + ite_a->THEN = ite_a->ELSE; + ite_a->ELSE = temp; + } + ite = my_shannon_ite(ite_a, ite_b, ite_1); + return ite; +} + +int +ite_is_inv(ite) + ite_vertex *ite; +{ + if (ite->value == 2 && ite->phase == 0) return 1; /* this should happen only in a canonical ite */ + if (ite->value == 3 && ite->IF->value == 2 && ite->IF->phase == 1 && ite->THEN->value == 0 && + ite->ELSE->value == 1) return 1; + return 0; +} + +/*------------------------------------------------------- + Returns the number of binate variables in a node. +-------------------------------------------------------*/ +int +node_num_binate_variables(node) + node_t *node; +{ + int i, num_binate = 0; + node_t *fanin; + + for (i = 0; i < node_num_fanin(node); i++) { + fanin = node_get_fanin(node, i); + if (node_input_phase(node, fanin) == BINATE) num_binate++; + } + return num_binate; +} + +/*------------------------------------------------------------ + Assigns weight to the fanin. The weight takes into account + 1) number of occurrences of the fanin, + 2) binateness of the fanin, + 3) binateness of the functions resulting on cofactoring + node wrt fanin. +-------------------------------------------------------------*/ + +int +ite_assign_var_weight(node, fanin, j, lit_count_array) + node_t *node, *fanin; + int j, *lit_count_array; +{ + int j2, j2p1, weight1, weight2, weight; + int binateness_if, binateness_then, binateness_else, total_binateness, + node_compute_binateness(); + node_t *node_if, *node_else_else, *node_else_then; + + j2 = 2 * j; + j2p1 = j2 + 1; + + weight1 = lit_count_array[j2] + lit_count_array[j2p1]; + weight2 = lit_count_array[j2] && lit_count_array[j2p1]; + + node_algebraic_cofactor(node, fanin, &node_else_then, &node_else_else, &node_if); + binateness_if = node_compute_binateness(node_if); + binateness_then = node_compute_binateness(node_else_then); + binateness_else = node_compute_binateness(node_else_else); + total_binateness = binateness_if + binateness_then + binateness_else; + + /* + if (total_binateness > 0.6) { + weight3 = 2; + } else { + if (total_binateness > 0.3) { + weight3 = 1; + } else { + weight3 = 0; + } + } + */ + weight = weight1 + ACT_ITE_ALPHA * weight2 + ACT_ITE_GAMMA * total_binateness; + node_free(node_else_then); + node_free(node_else_else); + node_free(node_if); + return weight; +} + +int +node_compute_binateness(node) + node_t *node; +{ + int num_fanin, num_bin; + + num_fanin = node_num_fanin(node); + if (num_fanin == 0) return 0; + + if (node_function(node) == NODE_BUF) return 0; + + num_bin = node_num_binate_variables(node); + return num_bin; + /* return (((float) num_bin)/num_fanin); */ +} + +/*------------------------------------------------------------------------------ + Maps each of three algebraic cofactors and computes the cost. If the cost + turns out to be more than the minimum seen so far, abandons further mapping. + In this case, the cost returned is not the right estimate, but that is fine + since a lower cost is known. +-------------------------------------------------------------------------------*/ +int +ite_assign_var_cost(node, fanin, init_param, min_cost_so_far) + node_t *node, *fanin; + act_init_param_t *init_param; + int min_cost_so_far; +{ + node_t *node_if, *node_else_else, *node_else_then; + int total_cost; + + node_algebraic_cofactor(node, fanin, &node_else_then, &node_else_else, &node_if); + + total_cost = act_ite_new_map_node(node_if, init_param); + if (total_cost < min_cost_so_far) { + total_cost += act_ite_new_map_node(node_else_then, init_param); + if (total_cost < min_cost_so_far) { + total_cost += act_ite_new_map_node(node_else_else, init_param); + } + } + + act_free_ite_node(node_if); + act_free_ite_node(node_else_then); + act_free_ite_node(node_else_else); + + node_free(node_if); + node_free(node_else_then); + node_free(node_else_else); + + return total_cost; +} + + +int node_is_unate(node) + node_t *node; +{ + int i; + node_t *fanin; + input_phase_t input_phase; + + foreach_fanin(node, i, fanin) { + input_phase = node_input_phase(node, fanin); + assert(input_phase != PHASE_UNKNOWN); + if (input_phase == BINATE) return 0; + } + return 1; +} + + +/* Constructs the cover of the node. We use the sm package because we + need to solve a column covering problem at the unate leaf*/ +/* no changes needed */ +static +sm_matrix * +build_F(node) +node_t *node; +{ + int i, j; + node_cube_t cube; + node_literal_t literal; + sm_matrix *F; + node_t *fanin; + sm_col *p_col; + + F = sm_alloc(); + + for(i = node_num_cube(node)-1; i >= 0; i--) { + cube = node_get_cube(node, i); + foreach_fanin(node, j, fanin) { + literal = node_get_literal(cube, j); + switch(literal) { + case ONE: + sm_insert(F, i, j)->user_word = (char *)1; + break; + case ZERO: + sm_insert(F, i, j)->user_word = (char *)0; + break; + case TWO: + sm_insert(F, i, j)->user_word = (char *)2; + break; + default: + (void)fprintf(misout, "error in F construction \n"); + break; + } + } + } +/* STuff the fanin names in the user word for each column*/ + foreach_fanin(node, j, fanin) { + p_col = sm_get_col(F, j); + p_col->user_word = node_long_name(fanin); + } + return F; +} + + +ite_vertex * +ite_new_ite_for_unate_cover(node, init_param) + node_t *node; + act_init_param_t *init_param; +{ + sm_matrix *F, *M, *build_F(); + sm_col *pcol, *col; + sm_row *row, *F_row, *cover; + sm_element *p, *q; + int *phase, i, j, is_neg_phase, *weights, pos_weight, col_num; + ite_vertex *ite_so_far, *ite_sub_node_1, *ite_and, *vertex_if; + node_t *variable, *variable_lit, *sub_node, *sub_node_1, *node_cube, *temp_node; + input_phase_t inp_phase; + node_cube_t cube; + + F = build_F(node); + +/* Construct the M matrix which is used for covering puposes*/ + is_neg_phase = 0; /* see if some variable in -ve phase */ + phase = ALLOC(int, F->ncols); + M = sm_alloc(); + sm_foreach_col(F, pcol) { + sm_foreach_col_element(pcol, p){ + if(p->user_word != (char *)2) { + (void) sm_insert(M, p->row_num, p->col_num); + phase[p->col_num] = (int )p->user_word; + if (phase[p->col_num] == 0) is_neg_phase = 1; + } + } + } + + /* solve covering problem for M*/ + /* assigning weights - in general, give slightly lower weights to the + -ve phase variables, so that they may occur higher in the order. + "Slight" difference, so that it is not possible to reduce the + weight of the cover by removing one positive guy and putting more + than one negative guys. . We want the + cardinality of the cover to be minimum, with the ties being broken + in favour of -ve wt. variables. + If all variables of positive phase, pass NIL (int). */ + /*--------------------------------------------------------------------*/ + if (is_neg_phase) { + weights = ALLOC(int, M->ncols); + pos_weight = M->ncols + 1; + for (i = 0, j = 0; i < F->ncols; i++) { + switch(phase[i]) { + case 0: + weights[j] = M->ncols; + j++; + break; + case 1: + weights[j] = pos_weight; + j++; + break; + case 2: + break; + } + } + assert(j == M->ncols); + cover = sm_minimum_cover(M, weights, 0, 0); + FREE(weights); + } else { + cover = sm_minimum_cover(M, NIL(int), 0, 0); + } + + sm_foreach_row_element(cover, p){ + p->user_word = (char *) phase[p->col_num]; + } + sm_free_space(M); + + /* constructs nodes that go with selected fanins */ + /*-----------------------------------------------*/ + + sm_foreach_row(F, row) { + row->user_word = (char *)0; + } + ite_so_far = NIL (ite_vertex); + sm_foreach_row_element(cover, q) { + col_num = q->col_num; + variable = node_get_fanin(node, col_num); + assert(variable); + sub_node = node_constant(0); + col = sm_get_col(F, col_num); + sm_foreach_col_element(col, p) { + F_row = sm_get_row(F, p->row_num); + if((p->user_word != (char *)2) && (F_row->user_word == (char *)0)) { + cube = node_get_cube(node, p->row_num); + node_cube = pld_make_node_from_cube(node, cube); + temp_node = node_or(sub_node, node_cube); + node_free(sub_node); + node_free(node_cube); + sub_node = temp_node; + F_row->user_word = (char *)1; + } + } + /* do something with the sub-node */ + /*--------------------------------*/ + if (phase[col_num]) { + variable_lit = node_literal(variable, 1); + inp_phase = POS_UNATE; + } else { + variable_lit = node_literal(variable, 0); + inp_phase = NEG_UNATE; + } + sub_node_1 = node_cofactor(sub_node, variable_lit); + node_free(sub_node); + node_free(variable_lit); + act_ite_new_make_ite(sub_node_1, init_param); + ite_sub_node_1 = ACT_ITE_ite(sub_node_1); + ACT_ITE_ite(sub_node_1) = NIL (ite_vertex); + act_free_ite_node(sub_node_1); /* ?? */ + node_free(sub_node_1); + /* ANDing being done this way, because ite_0 is static in ite_new_urp.c */ + /*----------------------------------------------------------------------*/ + vertex_if = ite_new_literal(variable); + if (inp_phase == POS_UNATE) { + ite_and = my_shannon_ite(vertex_if, ite_sub_node_1, ite_0); + } else { + ite_and = my_shannon_ite(vertex_if, ite_0, ite_sub_node_1); + } + if (ite_so_far == NIL (ite_vertex)) { + ite_so_far = ite_and; + } else { + ite_so_far = ite_new_OR(ite_so_far, ite_and); + } + } + sm_row_free(cover); + sm_free_space(F); + FREE(phase); + return ite_so_far; + +} diff --git a/sis/pld/ite_pld.c b/sis/pld/ite_pld.c new file mode 100644 index 0000000..a20fe16 --- /dev/null +++ b/sis/pld/ite_pld.c @@ -0,0 +1,190 @@ +#include "sis.h" +#include "pld_int.h" /* added Feb 9 1992 */ +#include "ite_int.h" +#include <stdio.h> + + +static struct ite_terminal { + node_t *fanin; + int node_num; + ite_vertex *ite_node; + } ite_inode[100]; + + + +ite_vertex *ite_alloc() +{ +ite_vertex *temp; + +temp=ALLOC(ite_vertex,1); +temp->IF=NULL; +temp->THEN=NULL; +temp->ELSE=NULL; +temp->multiple_fo=0; +temp->mark=0; +temp->index_size = 0; +temp->print_mark=0; +temp->fo=ALLOC(fanout_ite,1); +temp->fo->parent_ite_ptr=NULL; +temp->fo->next=NULL; +return(temp); +} + +/* Rajeev commented it */ +/* +void alloc_ite_node(node) +node_t *node; +{ +ite_vertex *ite; +(node)->ite_slot=(char *) ite_alloc(); +ite_connect(&(node->ite_slot),node->ite_slot); +ite=ite_get(node); +} +*/ + +void +ite_assgn_num(ite, n_ptr,addr_max_stored) +ite_vertex *ite; +int *n_ptr; +int *addr_max_stored; +{ + +if(ite->mark != 0) + return; +if(ite->value==2) + { + + /*store fanin*/ + if(ite->phase==1) + { + ite_inode[*addr_max_stored].fanin=(ite->fanin); + ite_inode[*addr_max_stored].node_num= *n_ptr; + (*addr_max_stored)++; + } + (ite->mark)=(*n_ptr); + (*n_ptr)++; + } +else { + (ite->mark)= (*n_ptr); + (*n_ptr)++; + if(ite->IF!=NULL) + { + ite_assgn_num(ite->IF,n_ptr,addr_max_stored); + ite_assgn_num(ite->THEN,n_ptr,addr_max_stored); + ite_assgn_num(ite->ELSE,n_ptr,addr_max_stored); + } + } +} + + +/* print out a numbered ITE */ +void +ite_print(ite,addr_max_stored) +int *addr_max_stored; +ite_vertex *ite; +{ +int found,i; +if((ite->print_mark)==1) + return; +if(0<=ite->value&&ite->value<=2) + { + if(ite->value==2) + { + if(ite->phase==0) + { + found=0; + for(i=0;i<*addr_max_stored;i++) + { + if(ite->fanin==ite_inode[i].fanin) + { + /*printf("[%d]=[%d]'\n",ite->mark,ite_inode[i].node_num);*/ + printf("[%d]=%s'\n",ite->mark,node_long_name(ite_inode[i].fanin)); + (ite->print_mark)=1; + found=1; + break; + } + } + if(found==0) + { + /*printf("[%d]'\n",ite->mark);*/ + printf("[%d]'=%s'\n",ite->mark,node_long_name(ite->fanin)); + (ite->print_mark)=1; + } + } + else { + /*printf("[%d]\n",ite->mark);*/ + printf("[%d]=%s\n",ite->mark,node_long_name(ite->fanin)); + /* printf("[%d]=%s\n",ite->mark,ite->name); */ /* Rajeev */ + (ite->print_mark)=1; + } + } + else if(ite->value==1) + { + printf("[%d]=1\n",ite->mark); + (ite->print_mark)=1; + } + else + { + printf("[%d]=0\n",ite->mark); + (ite->print_mark)=1; + } + return; + } +else { + printf("[%d]=[%d, %d, %d], cost = %d, pattern_num = %d\n", + ite->mark, ite->IF->mark, ite->THEN->mark, ite->ELSE->mark, + ite->cost, ite->pattern_num); + (ite->print_mark)=1; + ite_print(ite->IF,addr_max_stored); + ite_print(ite->THEN,addr_max_stored); + ite_print(ite->ELSE,addr_max_stored); + } +} + + +/* print ite */ + +void +ite_print_dag(ite) +ite_vertex *ite; +{ +int node_num, max_stored; + +max_stored=0; +node_num=1; +ite_assgn_num(ite, &node_num, &max_stored); +ite_print(ite, &max_stored); +ite_clear_dag(ite); +} + +void ite_clear_dag(ite) +ite_vertex *ite; +{ +if(ite->mark==0) + return; +ite->mark=0; +ite->print_mark=0; +if(ite->IF!=NULL){ + ite_clear_dag(ite->IF); + ite_clear_dag(ite->THEN); + ite_clear_dag(ite->ELSE); +} +} +void +ite_print_out(ite) +ite_vertex *ite; +{ +int node_num, max_stored; + +max_stored=0; +node_num=1; +ite_assgn_num(ite, &node_num,&max_stored); +ite_print(ite,&max_stored); +ite_clear_dag(ite); +} +/* commented Jul 21, 1992 to see if Will's files can be ignored */ +/* +#include "ite_scite" +#include "ite_share" +#include "ite_canonical" +*/ diff --git a/sis/pld/ite_urp.c b/sis/pld/ite_urp.c new file mode 100644 index 0000000..cfcf61e --- /dev/null +++ b/sis/pld/ite_urp.c @@ -0,0 +1,513 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + +/* int ACT_ITE_FIND_KERNEL; */ +st_table *ite_end_table; +static sm_matrix *build_F(); +static ite_vertex* urp_F(); +static int good_bin_var(); +static int find_var(); +static void update_F(); +extern my_sm_copy_row(), my_sm_print(); + +/* We need this to initialise the 0 and 1 ite's and store them + * in a table so they can be easily accessed + Note: node must be in the network (the only use of network is to get the fanin nodes + from the fanin names: so the restriction can be removed in future, if needed)*/ + +make_ite(node) +node_t *node; +{ + sm_matrix *F; + ite_vertex *ite, *vertex; + node_function_t node_fun; + + assert(node->type != PRIMARY_INPUT && node->type != PRIMARY_OUTPUT); + /* handle trivial cases */ + /*----------------------*/ + node_fun = node_function(node); + switch(node_fun) { + case NODE_0: + ite = ite_alloc(); + ite->value = 0; + ACT_ITE_ite(node) = ite; + return; + case NODE_1: + ite = ite_alloc(); + ite->value = 1; + ACT_ITE_ite(node) = ite; + return; + } + + /* ACT_ITE_FIND_KERNEL = 1; */ + /* Init a global lookup table for terminal vertices*/ + ite_end_table = st_init_table(st_ptrcmp, st_ptrhash); + vertex = ite_alloc(); + vertex->value = 0; + (void) st_insert(ite_end_table, (char *)0, (char *)vertex); + vertex = ite_alloc(); + vertex->value = 1; + (void) st_insert(ite_end_table, (char *)1, (char *)vertex); +/* initialize Matrix for node*/ + F = build_F(node); + if(ACT_ITE_DEBUG > 2) my_sm_print(F); +/* construct act for node*/ + /* ite = act_ite_build(F, node); */ + ite = urp_F(F, node); +/* Free the st_table now*/ + st_free_table(ite_end_table); + ACT_ITE_ite(node) = ite; + if(ACT_ITE_DEBUG > 2) { + ite_print_dag(ite); + } +/* Free up the space*/ + sm_free_space(F); +} + + + +/* Constructs the cover of the node. We use the sm package because we + need to solve a column covering problem at the unate leaf*/ +/* no changes needed */ +static +sm_matrix * +build_F(node) +node_t *node; +{ + int i, j; + node_cube_t cube; + node_literal_t literal; + sm_matrix *F; + node_t *fanin; + sm_col *p_col; + + F = sm_alloc(); + + for(i = node_num_cube(node)-1; i >= 0; i--) { + cube = node_get_cube(node, i); + foreach_fanin(node, j, fanin) { + literal = node_get_literal(cube, j); + switch(literal) { + case ONE: + sm_insert(F, i, j)->user_word = (char *)1; + break; + case ZERO: + sm_insert(F, i, j)->user_word = (char *)0; + break; + case TWO: + sm_insert(F, i, j)->user_word = (char *)2; + break; + default: + (void)fprintf(misout, "error in F construction \n"); + break; + } + } + } +/* STuff the fanin names in the user word for each column*/ + foreach_fanin(node, j, fanin) { + p_col = sm_get_col(F, j); + p_col->user_word = node_long_name(fanin); + } + return F; +} + + + +/* Recurse !! using Unate recursive paradigm(modified)*/ +static +ite_vertex * +urp_F(F, node) +sm_matrix *F; +node_t *node; +{ + int b_col, ex, a_col_special, b_col_special; + ite_vertex *ite_THEN, *ite_ELSE, *ite_IF; + ite_vertex *ite_ELSE_IF, *ite_ELSE_THEN, *ite_ELSE_ELSE; + ite_vertex *my_shannon_ite(), *ite, *unate_ite(), *ite_1, *ite_0; + sm_matrix *F_IF, *F_ELSE_THEN, *F_ELSE_ELSE, *F_new_IF, *act_sm_complement_special_case(); + sm_element *p; + char *b_name; + int value, special_case; + node_t *fanin; + + /* if there are no cubes in the matrix F, return 0 */ + /*-------------------------------------------------*/ + if (F->nrows == 0) { + assert(st_lookup(ite_end_table, (char *)0, (char **) &ite_0)); + return ite_0; + } + + + ex = 0; + b_col = good_bin_var(F, &ex); + if(ACT_ITE_DEBUG > 2) { + (void)fprintf(misout, "The most binate col is %d\n", b_col); + } + if(b_col != -1) { + b_name = sm_get_col(F, b_col)->user_word; + fanin = network_find_node(node->network, b_name); + assert(fanin != NIL (node_t)); + if(!ex) { + ite_split_F(F, b_col, &F_IF, &F_ELSE_THEN, &F_ELSE_ELSE); + if(ACT_ITE_DEBUG > 2){ + (void)fprintf(misout, "factored wrt %d'\n", b_col); + my_sm_print(F_IF); + } + /* check if F_IF is of the form a' or a' b'. If so, put a + b (a) as the IF child, + and swap the THEN and ELSE children (done slightly later) */ + /*-------------------------------------------------------------------------------*/ + if (special_case = act_mux_inputs_special_case(F_IF, &a_col_special, &b_col_special)) { + F_new_IF = act_sm_complement_special_case(F_IF, special_case, a_col_special, b_col_special); + sm_free_space(F_IF); + F_IF = F_new_IF; + } + ite_IF = urp_F(F_IF, node); + if(ACT_ITE_DEBUG > 2){ + (void)fprintf(misout, "factored wrt %d \n", b_col); + my_sm_print(F_ELSE_THEN); + } + ite_ELSE_THEN = urp_F(F_ELSE_THEN, node); + if(ACT_ITE_DEBUG > 2){ + (void)fprintf(misout, "factored wrt %d'\n", b_col); + my_sm_print(F_ELSE_ELSE); + } + ite_ELSE_ELSE = urp_F(F_ELSE_ELSE, node); + ite_ELSE_IF = ite_literal(b_col, b_name, fanin); + ite_ELSE = my_shannon_ite(ite_ELSE_IF, ite_ELSE_THEN, ite_ELSE_ELSE); + + /* if there are no rows in the IF part, can remove extra vertices */ + /*----------------------------------------------------------------*/ + if (F_IF->nrows == 0) { + ite = ite_ELSE; + } else { + assert(st_lookup(ite_end_table, (char *) 1, (char **) &ite_1)); + if (special_case) { + ite = my_shannon_ite(ite_IF, ite_ELSE, ite_1); + } else { + ite = my_shannon_ite(ite_IF, ite_1, ite_ELSE); + } + } + sm_free_space(F_IF); + sm_free_space(F_ELSE_THEN); + sm_free_space(F_ELSE_ELSE); + + } else { + + /* Common variable to all cubes */ + /*------------------------------*/ + p = sm_find(F, 0, b_col); + value = (int )p->user_word; + if((value != 1) && (value != 0)) { + (void)fprintf(misout, "ERROR in Common Variable\n"); + exit(1); + } + assert(st_lookup(ite_end_table, (char *)0, (char **) &ite_0)); + update_F(F, b_col); + if(ACT_ITE_DEBUG > 2){ + my_sm_print(F); + } + ite_IF = ite_literal(b_col, b_name, fanin); + if(value == 1){ + ite_THEN = urp_F(F, node); + ite = my_shannon_ite(ite_IF, ite_THEN, ite_0); + } + if(value == 0) { + ite_ELSE = urp_F(F, node); + ite = my_shannon_ite(ite_IF, ite_0, ite_ELSE); /* saving an inverter */ + } + } + } + else + /* unate cover */ + /*-------------*/ + { + ite = unate_ite(F, node); + } + return ite; + +} + + +/* Choose good variable for co-factoring*/ +static int +good_bin_var(A, ex) +sm_matrix *A; +int *ex; + +{ + int *o, *z, i, var; + sm_col *pcol; + sm_element *p; + int unate; + + o = ALLOC(int, A->ncols); + z = ALLOC(int, A->ncols); + for( i =0; i< A->ncols; i++) { + o[i] = 0; + z[i] = 0; + } + + /* find number of times each variable appears in + uncomplemented (o[]) and complemented (z[]) phase */ + /*---------------------------------------------------*/ + + i = 0; + sm_foreach_col(A, pcol){ + sm_foreach_col_element(pcol, p) { + switch((int )p->user_word) { + case 1: + o[i]++; + break; + case 2: + break; + case 0: + z[i]++; + break; + default: + (void)fprintf(misout, "Err in sm->user_word\n"); + break; + } + } + i++; + } + + /* check if a unate cover */ + /*------------------------*/ + unate = 1; + for (i = 0; i < A->ncols; i++) { + if (o[i] == 0 || z[i] == 0) continue; + unate = 0; + break; + } + if (unate) { + FREE(o); + FREE(z); + return (-1); + } + + /* look for a common variable in same phase in all the cubes */ + /*-----------------------------------------------------------*/ + for (i = 0; i < A->ncols; i++) { + if(o[i] == A->nrows){ + *ex = 1; + FREE(o); + FREE(z); + return i; + } + if (z[i] == A->nrows){ + *ex = 1; + FREE(o); + FREE(z); + return i; + } + } + /* find the most binate variable */ + /*-------------------------------*/ + var = find_var(o, z, A->ncols); + FREE(o); + FREE(z); + return var; +} + + + +static int +find_var(o, z, size) +int *o, *z, size; +{ + int i, b_b= 0, b_d= MAXINT, var; + + var = -1; + for(i = 0; i < size; i++) { + if((o[i] > 0) && (z[i] > 0)){ + if(b_b < o[i]+ z[i]){ + b_b = o[i] + z[i]; + b_d = abs(o[i]-z[i]); + var = i; + } else if(b_b == o[i]+ z[i]) { + if(abs(o[i]-z[i]) < b_d) { + b_d = abs(o[i]-z[i]); + var = i; + } + } + } + } + return var; +} + + +/* Divide matrix into 3 co-factored matrices - THENELSE is the matrix + with cubes that have 2 in the b_col, THEN cubes have 1, ELSE have 0 */ +void +ite_split_F(F, b_col, F_THENELSE, F_THEN, F_ELSE) +sm_matrix *F, **F_THENELSE, **F_THEN, **F_ELSE; +int b_col; +{ + sm_matrix *Fthenelse, *Fthen, *Felse; + sm_row *F_row; + sm_col *pcol; + sm_element *p; + + Fthen = sm_alloc(); + Felse = sm_alloc(); + Fthenelse = sm_alloc(); + pcol = sm_get_col(F, b_col); + sm_foreach_col_element(pcol, p) { + F_row = sm_get_row(F, p->row_num); + switch((int )p->user_word) { + case 0: + my_sm_copy_row(F_row, Felse, b_col, F); + break; + case 1: + my_sm_copy_row(F_row, Fthen, b_col, F); + break; + case 2: + my_sm_copy_row(F_row, Fthenelse, b_col, F); + break; + default: + (void)fprintf(misout, "error in duplicating row\n"); + break; + } + } + *F_THENELSE = Fthenelse; + *F_ELSE = Felse; + *F_THEN = Fthen; +} + +/* +my_sm_copy_row(F_row, F, col,Fp) +sm_row *F_row; +sm_matrix *F, *Fp; +int col; +{ + int j; + int row; + + row = F->nrows; + for(j = 0; j< F_row->length; j++){ + if(j != col) { + sm_insert(F, row, j)->user_word = + sm_row_find(F_row, j)->user_word; + } else if(j == col) { + sm_insert(F, row, j)->user_word = (char *)2; + } + sm_get_col(F, j)->user_word = sm_get_col(Fp, j)->user_word; + } +} + +*/ + +/* For debug */ +/* +my_sm_print(F) +sm_matrix *F; +{ + sm_row *row; + sm_element *p; + + (void)fprintf(misout, "Printing F matrix\n"); + sm_foreach_row(F, row) { + sm_foreach_row_element(row, p){ + (void)fprintf(misout, "%d", (int *)p->user_word); + } + (void)fprintf(misout, "\n"); + } +} + +*/ + +/* Set co-factored variable to 2*/ +static void +update_F(F, b_col) +sm_matrix *F; +int b_col; +{ + sm_col *p_col; + sm_element *p; + + p_col = sm_get_col(F, b_col); + sm_foreach_col_element(p_col, p){ + p->user_word = (char *)2; + } +} + +/*------------------------------------------------------------------------------- + Given F, checks if F implements function of the form a'b' or a'. Returns 2 if + former, 1 if latter, 0 otherwise. Returns column numbers of a and b + (whichever applicable) in a_col and b_col. +--------------------------------------------------------------------------------*/ +int +act_mux_inputs_special_case(F, a_col, b_col) + sm_matrix *F; + int *a_col, *b_col; +{ + + sm_element *p; + int count_neg; + + if (F->nrows != 1) return 0; + + count_neg = 0; + sm_foreach_row_element(F->first_row, p) { + switch ((int) p->user_word) { + case 0: + count_neg++; + if (count_neg > 2) return 0; + if (count_neg == 1) *a_col = p->col_num; + else *b_col = p->col_num; + break; + case 1: + return 0; + case 2: + break; + default: + (void)fprintf(misout, "error in row\n"); + break; + } + } + return count_neg; +} + +/*---------------------------------------------------------------------------- + If F = a' b', obtain the matrix for a + b. If F = a', obtain matrix for a. +------------------------------------------------------------------------------*/ +sm_matrix * +act_sm_complement_special_case(F, special_case, a_col, b_col) + sm_matrix *F; + int special_case, a_col, b_col; +{ + sm_matrix *not_F; + sm_row *r; + sm_element *not_p; + int row, j; + + not_F = sm_alloc(); + row = not_F->nrows; + r = F->first_row; + for (j = 0; j< r->length; j++){ + not_p = sm_insert(not_F, row, j); + if (j != a_col) { + not_p->user_word = (char *) 2; + } else { + not_p->user_word = (char *) 1; + } + sm_get_col(not_F, j)->user_word = sm_get_col(F, j)->user_word; + } + if (special_case == 1) return not_F; + + /* special case = 2, insert one more row */ + /*---------------------------------------*/ + row = not_F->nrows; + for (j = 0; j< r->length; j++){ + not_p = sm_insert(not_F, row, j); + if (j != b_col) { + not_p->user_word = (char *) 2; + } else { + not_p->user_word = (char *) 1; + } + } + return not_F; +} + + diff --git a/sis/pld/ite_util.c b/sis/pld/ite_util.c new file mode 100644 index 0000000..10decdb --- /dev/null +++ b/sis/pld/ite_util.c @@ -0,0 +1,239 @@ +#include "sis.h" +#include "pld_int.h" +#include "ite_int.h" + +/* Log of changes +* Jan 16 '93: In my_traverse_ite(), ite vertices were visited +* despite having been visited earlier. Fixed it. - Rajeev Murgai +*/ + +/*-------------------------------------------------------- + Frees the cost struct of n1, replaces it with that of + n2. If match is non-nil, rebuilds the + match, frees the old one and generates the new one. + Frees the ite and match of cost_struct of n1 also. + Makes the ACT_ITE_SLOT of n2 NIL. +---------------------------------------------------------*/ +act_ite_cost_struct_replace(n1, n2, map_alg) + node_t *n1, *n2; + int map_alg; +{ + ACT_ITE_COST_STRUCT *cost_struct1, *cost_struct2; + ACT_MATCH *match; + + cost_struct1 = ACT_ITE_SLOT(n1); + if (cost_struct1) { + ite_my_free(cost_struct1->ite); + my_free_act(cost_struct1->act); + act_free_match(cost_struct1->match); + FREE(cost_struct1); + } + ACT_DEF_ITE_SLOT(n1) = ACT_DEF_ITE_SLOT(n2); + cost_struct2 = ACT_ITE_SLOT(n2); + if (cost_struct2 != NIL (ACT_ITE_COST_STRUCT)) { + if (cost_struct2->match) { + act_free_match(cost_struct2->match); + match = act_is_act_function(n1, map_alg, act_is_or_used); + assert(match != NIL (ACT_MATCH)); + cost_struct2->match = match; + } + } + ACT_DEF_ITE_SLOT(n2) = NIL (char); +} + +ite_my_free(ite) + ite_vertex *ite; +{ + st_table *table; + char *key; + st_generator *stgen; + ite_vertex *vertex; + + if (ite == NIL (ite_vertex)) return; + table = ite_my_traverse_ite(ite); + st_foreach_item(table, stgen, &key, (char **) &vertex) { + ite_my_free_vertex(vertex); + } + st_free_table(table); + ite = NIL (ite_vertex); +} + +ite_my_free_vertex(vertex) + ite_vertex *vertex; +{ + if (vertex->fo != NULL) { + if (vertex->fo->next != NULL) { + (void) printf("the next is not NIL\n"); + } + FREE(vertex->fo); + } + FREE(vertex); +} + +/*---------------------------------------------------------------------- + Frees the ite and match fields of the undef1 field of all the + internal nodes. +-----------------------------------------------------------------------*/ +act_free_ite_network(network) + network_t *network; +{ + lsGen gen; + node_t *node; + + foreach_node(network, gen, node) { + act_free_ite_node(node); + } +} + +act_free_ite_node(node) + node_t *node; +{ + /* + if (node->type != PRIMARY_INPUT || node->type != PRIMARY_OUTPUT) return; + */ + if (ACT_ITE_SLOT(node)) { + network_free(ACT_ITE_SLOT(node)->network); + ACT_ITE_SLOT(node)->network = NIL (network_t); + + act_free_match(ACT_ITE_SLOT(node)->match); + ACT_ITE_SLOT(node)->match = NIL (ACT_MATCH); + + ite_my_free(ACT_ITE_ite(node)); + ACT_ITE_ite(node) = NIL (ite_vertex); + + my_free_act(ACT_ITE_act(node)); + ACT_ITE_act(node) = NIL (ACT_VERTEX); + } +} + + +act_ite_remap_update_ite_fields(table1, network1, node) + st_table *table1; + network_t *network1; + node_t *node; +{ + ACT_ITE_COST_STRUCT *cost_struct; + + cost_struct = ACT_ITE_SLOT(node); + cost_struct->node = node; + if (cost_struct->match) return; + if (cost_struct->ite) { + cost_struct->ite->node = node; + act_ite_remap_put_node_names_in_ite(cost_struct->ite, table1, network1); + assert(cost_struct->act == NIL (ACT_VERTEX)); + } else { + cost_struct->act->node = node; + act_remap_put_node_names_in_act(cost_struct->act, table1, network1); + } +} + +act_ite_remap_put_node_names_in_ite(ite, table1, network1) + ite_vertex *ite; + st_table *table1; + network_t *network1; +{ + st_table *table; + char *key; + st_generator *stgen; + ite_vertex *vertex; + node_t *node1, *node; + + table = ite_my_traverse_ite(ite); + st_foreach_item(table, stgen, &key, (char **) &vertex) { + if (vertex->value != 2) continue; + node1 = network_find_node(network1, node_long_name(vertex->fanin)); + assert(st_lookup(table1, (char *) node1, (char **) &node)); + vertex->name = node_long_name(node); + vertex->fanin = node; + } + st_free_table(table); +} + +my_traverse_ite(vertex, table) + ite_vertex *vertex; + st_table *table; +{ + if (vertex->value != 3) return; + + if (!st_is_member(table, (char *) vertex->IF)) { + assert(!st_insert(table, (char *) vertex->IF, (char *) vertex->IF)); + my_traverse_ite(vertex->IF, table); + } + if (!st_is_member(table, (char *) vertex->THEN)) { + assert(!st_insert(table, (char *) vertex->THEN, (char *) vertex->THEN)); + my_traverse_ite(vertex->THEN, table); + } + if (!st_is_member(table, (char *) vertex->ELSE)) { + assert(!st_insert(table, (char *) vertex->ELSE, (char *) vertex->ELSE)); + my_traverse_ite(vertex->ELSE, table); + } +} + +/*----------------------------------------------------------------- + Puts all the ite vertices in the tree rooted at ite in the table. +------------------------------------------------------------------*/ +st_table * +ite_my_traverse_ite(ite) +ite_vertex *ite; +{ + st_table *table; + table = st_init_table(st_ptrcmp, st_ptrhash); + assert(!st_insert(table, (char *) ite, (char *) ite)); + my_traverse_ite(ite, table); + return table; +} + +/*------------------------------------------------------------------- + Given an ite vertex that has value 2, returns the literal of + node of the network that corresponds to it. Gets the node by + vertex->fanin. +---------------------------------------------------------------------*/ +node_t * +ite_get_node_literal_of_vertex(vertex) + ite_vertex *vertex; +{ + node_t *node; + + assert(vertex->value == 2); + node = vertex->fanin; + return (node_literal(node, 1)); +} + +/*----------------------------------------------------------- + Also frees the node associated with the non-terminal + multiple fanout vertices. +-------------------------------------------------------------*/ +ite_free_nodes_in_multiple_fo_ite(vertex) + ite_vertex_ptr vertex; +{ + if (vertex->mark == MARK_COMPLEMENT_VALUE) return; + vertex->mark = MARK_COMPLEMENT_VALUE; + if (vertex->value <= 1) return; + if (vertex->multiple_fo != 0) { + node_free(vertex->node); + } + if (vertex->value == 3) { + ite_free_nodes_in_multiple_fo_ite(vertex->IF); + ite_free_nodes_in_multiple_fo_ite(vertex->THEN); + ite_free_nodes_in_multiple_fo_ite(vertex->ELSE); + } +} + +/*----------------------------------------------------------- + Frees the node associated with the non-terminal + multiple fanout vertices. +-------------------------------------------------------------*/ +act_free_nodes_in_multiple_fo_act(vertex) + ACT_VERTEX_PTR vertex; +{ + if (vertex->mark == MARK_COMPLEMENT_VALUE) return; + vertex->mark = MARK_COMPLEMENT_VALUE; + if (vertex->value <= 1) return; + if (vertex->multiple_fo != 0) { + node_free(vertex->node); + } + act_free_nodes_in_multiple_fo_act(vertex->low); + act_free_nodes_in_multiple_fo_act(vertex->high); +} + + diff --git a/sis/pld/pld.doc b/sis/pld/pld.doc new file mode 100644 index 0000000..95b3389 --- /dev/null +++ b/sis/pld/pld.doc @@ -0,0 +1,521 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/pld/pld.doc,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:56 $ +.\" * +.\" +This package manipulates the network for mapping onto the programmable gate arrays. +Two kinds of architectures are targeted: Xilinx-like (table look up) and Actel. +The optimization is targeted towards minimizing 1) the number of blocks, and 2) delay +through the circuit. + + +XILINX + +A node if feasible if it has at most `support' number of inputs. A network +is feasible if all nodes of the network are feasible. + +The following structures are used frequently in the routines. To use these routines, +the xln_init_param_t structure must be allocated and all the necessary fields be set +to proper values. The information on the fields to be set for a particular routine is +given after the description of the routine. The fields are as follows: + + typedef struct xln_init_param_defn { + int support; /* fanin-restriction for a node. For xilinx, support = 5 */ + int MAX_FANIN; /* for two-output blocks - see merge_node()*/ + int MAX_COMMON_FANIN; /* for two-output blocks - see merge_node()*/ + int MAX_UNION_FANIN; /* for two-output blocks - see merge_node()*/ + int heuristic; /* overloaded right now - being used for + xln_decomp_for_merging_network() as well as + xln_reduce_levels() + for xln_decomp_for_merging_network() - + ALL_CUBES: consider cubes of all infeasible nodes. + PAIR_NODES: consider cubes of pair of nodes. + (suggested value = ALL_CUBES) + for xln_reduce_levelS() - + 1: collapse a node into all fanouts. + 2: collapse only into critical fanouts. + (suggested value = 1) */ + int common_lower_bound; /* for xln_decomp_for_merging_network() - do not + consider a cube-pair for extraction if their + number of common inputs is less than + lower_common_bound (suggested value = 2 for Xilinx)*/ + int cube_support_lower_bound; /* for xln_decomp_for_merging_network() - do + not consider a cube if it has + less than cube_support_lower_bound inputs + (suggested value = 4 for Xilinx)*/ + int lit_bound; /* if the infeasible node has greater than lit_bound + literals, do a good decomposition of the node + (i.e. decomp -g) */ + int cover_node_limit; /* apply exact partition_network() if number of nodes in some + subnetwork (or network) is at most this + (suggested value = 30)*/ + int flag_decomp_good; /* could be 0 (do not apply decomp -g), 1 (apply + decomp -g), 2 (pick the better of the previous two) */ + int good_or_fast; /* if = FAST, just apply cube-packing, else (= GOOD) + all decomposition techniques */ + int absorb; /* if 1, use Roth-Karp to move fanins */ + int DESPERATE; /* if Roth-Karp decomposition fails to get a disjoint + decomposition and DESPERATE = 1, call + xl_node_ao_map() */ + int RECURSIVE; /* if 1, recursively apply Roth-Karp decomposition + on the root node */ + int MAX_FANINS_K_DECOMP; /* node considered for Roth-Karp decomposition if has + at most these many fanins (should be at most 32) + (suggested value = 15) */ + int COST_LIMIT; /* nodes with at most this cost to be collapsed in + partial_collapse routine (suggested value = 1) */ + XLN_MOVE_STRUCT xln_move_struct; + int collapse_input_limit; /* consider total collapse of the network if number + of primary inputs is no more than this + (suggested value = 10) */ + int traversal_method; /* 1 then topological traversal, else levels sorted + on the number of nodes at a level (suggested value = 1)*/ + } xln_init_param_t; + + + typedef struct xln_move_struct_defn { + int MOVE_FANINS; /* if 1, then moving of fanins is invoked. */ + int MAX_FANINS; /* limit on number of fanins of node whose + fanins are to be moved (at most 32)*/ + int bound_alphas; /* for delay: this controls the number of functions + created (set it to 1 for now) */ + } XLN_MOVE_STRUCT; + + + +decomposition +-------------- + +void +karp_decomp_network(network, support, one_node, user_node) +network_t *network; +int support; +int one_node; +node_t *user_node; + Uses Karp_Roth disjoint decomposition to decompose recursively + nodes of the network having fanin greater than + "support". If "one_node" is 1, it just decomposes the + "user_node", else it decomposes all the nodes of the + network whose fanin is greater than "support". + In the present implementation, the + first decomposition found is selected and no attempt + is made to have the best decomposition. + +network_t * +xln_exhaustive_k_decomp_node(node, support, MAX_FANINS) +node_t *node; +int support; +int MAX_FANINS; + Call Roth Karp decomp on a node of the network. Try all possible + input partitions for the node if the number of fanins of the node + is no more than MAX_FANINS (if higher, + return NIL). The original node changes as a result of the + decomposition. If it is infeasible, does an xl_ao on the node. + Finds the number of feasible nodes for each partition. + Returns the best subnetwork (corresponding to the decomposition with + minimum number of feasible nodes). + + If the node is feasible, or is not an internal node of a network, + NIL is returned. + + + +int +split_network(network, support) +network_t *network; +int support; + Does a decomposition of the network so that all nodes have a fanin + less than the value of support. Uses kernel extraction and AND-OR + decomposition. Returns one on success. + + + +xln_network_reduce_infeasibility_by_moving_fanins(network, support, MAX_FANINS) +network_t *network; +int support, MAX_FANINS; + Given an infeasible network, tries to make nodes of the network + feasible by moving fanins around, i.e., by moving a fanin of an + infeasible node to some other feasible node that can accommodate one + more input. Uses Roth-Karp decomposition. + Fanins of only those nodes are moved which have at most + MAX_FANINS fanins. The resulting network may not be feasible. + +xln_network_ao_map(network, support) +network_t *network; +int support; + Given an infeasible network, apply cube-packing heurisitc to do an + AND-OR decomposition. Generates a feasible network. + + +xln_node_ao_map(node, support) +node_t *node; +int support; + For node belonging to a network, first maps cubes with number of literals + greater than support to a CLB and after that does a best fit decreasing + packing of the cubes. Replaces the node in the network by this set of new + nodes. If node has less than `support' inputs, nothing is done. + + +xln_improve_network(network, init_param) +network_t *network; +xln_init_param_t *init_param; + Given an infeasible network, generates a feasible network. Depending + on the options in the init_param, tries different decomposition + schemes: like Roth-Karp, cofactoring, xl_ao_map, split etc. + + Must set the following fields of init_param: support, + cover_node_limit, lit_bound, flag_decomp_good, good_or_fast, absorb, + DESPERATE, RECURSIVE, MAX_FANINS_K_DECOMP, + xln_move_struct.MOVE_FANINS, xln_move_struct.MAX_FANINS. + + +xln_improve_node(node, init_param) +node_t *node; +xln_init_param_t *init_param; + Given an infeasible node of a network, replaces it by a feasible set + of nodes. Depending on the options in the init_param, tries different + decomposition schemes. + + Must set the following fields of init_param: support, + cover_node_limit, lit_bound, flag_decomp_good, good_or_fast, absorb, + DESPERATE, RECURSIVE, MAX_FANINS_K_DECOMP, + xln_move_struct.MOVE_FANINS, xln_move_struct.MAX_FANINS. + + +xln_partial_collapse(network, init_param) +network_t *network; +xln_init_param_t *init_param; + Given an infeasible network, first maps each node + of the network. Then collapses each node into its fanouts, remaps the + fanouts. If the number of blocks decreases, accepts the collapse. + Repeats the process until no more gain. Finally, generates a feasible network. + + Must set the following fields of init_param: support, + COST_LIMIT, cover_node_limit, lit_bound, flag_decomp_good, good_or_fast, absorb, + DESPERATE, RECURSIVE, MAX_FANINS_K_DECOMP, + xln_move_struct.MOVE_FANINS, xln_move_struct.MAX_FANINS. + + +xln_cofactor_decomp_network(network, support, mode) +network_t *network; +int support; +float mode; + Cofactors each infeasible node of the network. The mode is + either AREA or DELAY - it determines the cofactoring variable + selecetion. Assumes initially that a delay trace using + DELAY_MODEL_UNIT has been done (if mode is DELAY). + If support is 2, this operation will not return a feasible + network. (to be fixed in future). + + +xln_cofactor_decomp_node(node, support, mode) +node_t *node; +int support; +float mode; + Given a node belonging to a network, cofactors it recursively, till it becomes + feasible (determined by support). Selection of the cofactoring variable + is based on mode. If mode = AREA, then a variable + that occurs in all the cubes in the same phase (pos. or neg) is + selected first. If mode = DELAY, the most critical fanin is selected first. + For DELAY mode, assumes that a delay-trace has been done on the + network. Replaces the node in the network by the cofactored tree. + If support is 2, this operation will not return a feasible set of nodes. + (to be fixed in future). + + +xln_decomp_for_merging_network(network, init_param) +network_t *network; +xln_init_param_t *init_param; + Given an infeasible network, decomposes nodes keeping in mind that a + Xilinx CLB can realize two mergeable functions as well. The resulting + network may not be feasible and appropriate decomposition routines + may be needed later. + + Must set the following fields of init_param: support, + MAX_FANIN, MAX_COMMON_FANIN, MAX_UNION_FANIN, heuristic, + common_lower_bound, cube_support_lower_bound. See merge_node() + for details on MAX_FANIN, MAX_COMMON_FANIN, MAX_UNION_FANIN. + + + + +block count minimization +------------------------- + +int +xln_do_trivial_collapse_network(network, support, MOVE_FANINS, MAX_FANINS) +network_t *network; +int support; +int MOVE_FANINS; +int MAX_FANINS; + Traverses the nodes of the network topologically. + First tries to reduce the number of fanins of the node by moving + some of fanins of the node to some other node. + This is done only if MOVE_FANINS flag is 1, and the + number of fanins of the node is at most MAX_FANINS. + Then collapses the node into all its fanouts if none of the fanouts + become infeasible (as determined by support). If it can be collapsed, + it is deleted from the network. Repeats the process until no more + nodes can be collapsed. Can be applied on a potentially infeasible network. + Returns the number of collapsed nodes. + + +int +xln_do_trivial_collapse_node_without_moving(node, support) +node_t *node; +int support; + Returns 1 if the node can be collapsed into all the fanouts, + without making them infeasible. Does not delete the node from + the network. Otherwise (i.e., if either the node is + not INTERNAL, or some fanout is primary output, or if some fanout + becomes infeasible) returns 0. Then the network remains the same. + Can be applied on an infeasible node. + + +int +imp_part_network(network, support, MOVE_FANINS, MAX_FANINS) +network_t *network; +int support; +int MOVE_FANINS; +int MAX_FANINS; + First calls xln_do_trivial_collapse_network( + network, support, MOVE_FANINS, MAX_FANINS). + Then finds out all + the (node, fanout) pairs such that node can be collapsed into fanout + without making the fanout infeasible. Associates a cost with each such + pair. This cost reflects the number of new edges created by the + collapse. Then at each step, picks the pair with minimum cost. + + Repeats the whole process until no more collapsing can be done. Can be + applied on an infeasible network also. + + +void +partition_network(network, support, bincov_heuristics) +network_t *network; +int support; +int bincov_heuristics; + The `network' should have all intermediate + nodes with fanin less than or equal to `support'. + Uses Mathony's binate covering algorithm to + minimize the number of nodes in the network. + Uses different heuristics to solve the covering + problem- `bincov_heuristics' ( 0, 1, 2 or 3) is + a flag that specifies which heuristic should be + employed, as described below: + + - 0 (exact), + - 1 (Luciano's heuristic), + - 2 (For large examples), + - 3 (automatically switches between 0 and 2) + + +void +merge_node(network, MAX_FANIN, MAX_COMMON_FANIN, MAX_UNION_FANIN) +network_t *network; +int MAX_FANIN, MAX_COMMON_FANIN, MAX_UNION_FANIN; + Exploits the fact that a Xilinx CLB can realize two functions also, + provided the two functions satisfy the constraints as listed below: + Each of the two functions should not have fanin more than MAX_FANIN, + they should not have more than MAX_COMMON_FANIN many common fanins, + and the union of their fanins should not exceed MAX_UNION_FANIN. + For xilinx XC3090 the numbers are MAX_FANIN = 4, MAX_COMMON_FANIN = 4 + and MAX_UNION_FANIN = 5. + + Although the problem is a maximum cardinality matching problem + (solvable in polynomial time), it is formulated as an integer program, + and solved using package Lindo. If Lindo package is not found in the + path, the program exits. If found, the routine lists the pairs of + nodes that were merged. Does not change the network. + + + +network_t * +xln_check_network_for_collapsing_area(network, init_param, roth_karp_flag) +network_t *network; +xln_init_param_t *init_param; +int roth_karp_flag; + Collapses a feasible network if the number of primary inputs of the network + is at most init_param->collapse_input_limit. Applies Roth-Karp + decomposition and cofactoring to the collapsed network. If the number + of nodes of either decomposition is less than the original network, + accepts the better decomposition and returns the new network. + Else, returns NIL. Roth-Karp decomposition is applied only if + roth_karp_flag is 1. + + Must specify support, collapse_input_limit. If support = 2, nothing is + done. + + +delay optimization +------------------- + +xln_reduce_levels(network, init_param) +network_t *network; +xln_init_param_t *init_param; + Given a feasible network (preferably in terms of 2-input gates - + obtained say by speed-up), reduces the number of levels, maintaining + the feasibility of the network. + + Must set the following fields of init_param: support, + heuristic, collapse_input_limit, traversal_method, + xln_move_struct.MOVE_FANINS, xln_move_struct.MAX_FANINS, + xln_move_struct.bound_alphas. + + +network_t * +xln_check_network_for_collapsing_delay(network, init_param) +network_t *network; +xln_init_param_t *init_param; + Collapses a feasible network if the number of primary inputs of the network + is at most init_param->collapse_input_limit. Applies Roth-Karp + decomposition and cofactoring techniques on the network and evaluates + them. Returns the network with lower number of levels. Returns NIL if collapsing + could not be done. Does nothing if init_param->support = 2. + + Must set the following fields of init_param: support, collapse_input_limit. + `network' changes if collapsing is done. + + + + +ACTEL + +Mapping onto ACT1 architecture: minimizing the number of blocks used. + +/* init_param structure to put all the options for actel mapping */ + typedef struct act_init_param_defn{ + int HEURISTIC_NUM; /* what BDD (ordered or unordered) to construct */ + int NUM_ITER; /* number of iterations in iter. improvement */ + int FANIN_COLLAPSE; /* upper limit on fanins of a node to collapse */ + float GAIN_FACTOR; /* go from one iteration to other only if gain increases + by this ratio (suggested value = 0.001) */ + int DECOMP_FANIN; /* lower limit on fanins of node to decompose */ + int DISJOINT_DECOMP;/* do disjoint decomposition before mapping */ + int QUICK_PHASE; /* do phase-assignment */ + int LAST_GASP; /* make network out of node and do iterations on it */ + int BREAK ; /* make the final network in terms of basic blocks */ + float mode; /* 0 for area and 1 for delay mode, in between, a + weighted sum */ + char delayfile[500];/* name of the file with delay numbers for basic block + as a function of number of fanouts - needed only if + mode is non-zero */ + } act_init_param_t; + + +network_t * +act_map_network(network, init_param, cost_table) +network_t *network; +act_init_param_t *init_param; +st_table *cost_table; + +This procedure synthesizes the given circuit onto actel +architecture. The original network "network" is lost. + +It uses tree-mapping approach to +cover the subject graph with the pattern-graphs. +The pattern graphs are hardwired into the code +and so no library is to be read in. + +Subject graph and pattern-graphs are in terms of +2-1 muxes. Subject graph is constructed for each intermediate +node of the network. Either an OBDD (Ordered reduced BDD) +and/or a BDD (Binary Decision Diagram) is constructed for each +such node. After entire network is mapped, an iterative_improvement +phase may be entered. + +The following fields of init_param must be set: HEURISTIC_NUM, +NUM_ITER, FANIN_COLLAPSE, DECOMP_FANIN, DISJOINT_DECOMP, +QUICK_PHASE, GAIN_FACTOR, LAST_GASP, BREAK, mode. + +HEURISTIC_NUM (1, 2, 3, 4) specifies which one of the two +subject_graphs would be constructed: +HEURISTIC_NUM = 1 => OBDD +HEURISTIC_NUM = 2 => BDD +HEURISTIC_NUM = 3 => program decides which one to construct.(default). +HEURISTIC_NUM = 4 => both are constructed and the one with + lower mapped cost is selected. Gives the best + result, but typically takes more time. + +NUM_ITER equals the maximum number of iterations +to be performed in the iterative_improvement phase. Each such +iteration involves a good_decomposition followed by a partial_collapse +routine. + +If the iterative_improvement phase is entered, in the partial_collapse +routine, only those nodes are considered as candidates +for partial_collapse which have fanin no more than FANIN_COLLAPSE. + +The good_decomposition routine is called only for those nodes +which have fanin greater than or equal to DECOMP_FANIN. + +The program enters the next iteration only if gain in the present +iteration is at least (present_cost * GAIN_FACTOR). +The cost and gain are measured in terms of the number of basic blocks +used for the network. + +If DISJOINT_DECOMP is non-zero, disjoint_decomposition routine +is invoked on the network at the very start. This may help in +getting big gains in partial_collapse routine later. Also, big +nodes are decomposed, potentially reducing the final cost. + +If QUICK_PHASE is non-zero, the program, before exiting, +enters an act_quick_phase routine, which greedily +finds out if it is beneficial to implement the node in +negative phase. + +if BREAK = 1, each node in the final network will be implementable by +one ACT1 block. A bdnet file is also generated. There is a global +variable FILE *BDNET_FILE which must be fopen-ed by the user +before calling the routine with BREAK = 1. Then it is his +responsibility to fclose it. + +mode must be set to AREA for the time being. +mode = DELAY is not yet supported. + +A global variable `act_is_or_used' should be set before calling this routine. +It should be set to 1 if the OR gate in ACT1 is to be used, else set to 0. + +The cost_table should be initialized by +st_init_table() before calling this routine. After the routine, it has +a subject graph for each node. Call free_cost_table() to free all the +associated storage. Also it is a serious error to call act_map_network() +with negative flags. + +void +free_cost_table(cost_table) +st_table *cost_table; + Frees the associated storage associated with the + cost_table. This space was allocated by the act_map_network() + routine. + + + +Some utility routines +--------------------- + +int +xln_is_network_feasible(network, support) +network_t *network; +int support; + Returns 1 if the network is feasible, as determined by support. + Else returns 0. (For xilinx) + + +pld_replace_node_by_network(node, network) +node_t *node; +network_t *network; + Replaces node by network. Node should be in some network. + + +node_t * +pld_make_node_from_cube(node, cube) +node_t *node; +node_cube_t cube; + Returns a node which has the same function as `cube', which belongs to + the `node'. + diff --git a/sis/pld/pld.h b/sis/pld/pld.h new file mode 100644 index 0000000..3cdaa5a --- /dev/null +++ b/sis/pld/pld.h @@ -0,0 +1,18 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/pld.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +extern void merge_node(); /* xln_merge.c */ +extern void partition_network(); /* xln_map_par.c */ +extern int part_network(); /* xln_part.c */ +extern int split_network(); /* xln_part_dec.c */ +extern void karp_decomp_network(); /* xln_k_decomp.c */ + +extern network_t *act_map_network(); /* act_map.c */ +extern void free_cost_table(); /* act_map.c */ + diff --git a/sis/pld/pld_int.h b/sis/pld/pld_int.h new file mode 100644 index 0000000..4c6efd7 --- /dev/null +++ b/sis/pld/pld_int.h @@ -0,0 +1,549 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/pld_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "pld.h" +/* definitions for actel */ +#define LOW 0 +#define HIGH 1 +#define AREA 0.0 +#define DELAY 1.0 +#define UNORDERED 0 +#define ORDERED 1 +#ifndef NULL +#define NULL 0 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#define HICOST 100000 +#define DELETE 3 +#define NO_VALUE 4 +#define FANIN 0 +#define RANDOM 1 +#define OPTIMAL 2 +#define COMPOSE 0 +#define ALAP 3 +#define HEURISTIC 4 +#define MAXSTYLES 6 +#define MAXTYPES 5 +/* #define MAXOPTIMAL 6 changed from 7 to 6 */ +#define AND 0 +#define OR 4 +#define P11 0 +#define P10 1 +#define P01 2 +#define P00 3 +#define XOR 8 +#define XNOR 9 +#define min(A,B) ( (A) < (B) ? (A) : (B) ) +#undef equal + +#define PLD_SLOT pld +#define ACT_SET(node) ((act_type_t *) (node)->PLD_SLOT) +#define ACT_GET(node) ((node)->PLD_SLOT) +#define GLOBAL_ACT act_num[0] +#define LOCAL_ACT act_num[1] + +#define A_F 1.0; +#define S_F 0.0; +#define ACT_MAP_NAME actel_map +/* DAG vertex */ +typedef struct act_vertex_defn { + struct act_vertex_defn *low, *high; + int index; + int value; + int id; + int mark; + int index_size; + node_t *node; + char *name; + int multiple_fo; + int cost; + int pattern_num; /* for the pattern_matched at a node */ + int mapped; + struct act_vertex_defn *parent; /* delete later*/ + char *fn_type; /* delete later */ + int my_type ; /* ORDERED or UNORDERED */ + double arrival_time; + int multiple_fo_for_mapping; /* for mapping */ +} ACT_VERTEX, *ACT_VERTEX_PTR; + +#define act_t ACT_VERTEX + +typedef struct cost_struct_defn{ + int cost; /* number of basic blocks used to realize the node */ + char *fn_type; /* a "hacked" field to get bdnet file right */ + ACT_VERTEX_PTR act; /* stores the bdd (act) for the function at the node */ + node_t *node; /* pointer to the node of the network */ + double arrival_time; /* arrival_time at the output of the node */ + double required_time; /* required_time at the output of the node */ + double slack; /* slack = required_time - arrival_time */ + int is_critical; /* is the slack <= some threshold */ + double area_weight; /* penalty if node is collapsed */ + double cost_and_arrival_time; + } COST_STRUCT; + +/* ACT with root, name, and order_list */ + typedef struct act_defn { + ACT_VERTEX_PTR root; + array_t *node_list; + node_t *node; + char *node_name; + } ACT, *ACT_PTR; + +/* ACT and order style */ + typedef struct act_entry_defn{ + ACT_PTR act; + int order_style; + } ACT_ENTRY, *ACT_ENTRY_PTR; + +/* local and global ACTs */ + typedef struct act_slot_defn{ +/* COST_STRUCT *cost_node;*/ /* added Aug 9 for delay */ + ACT_ENTRY_PTR act_num[2]; + } act_type_t; + +/* used in act2ntwk and reduce */ + typedef struct key_defn{ + int low, high; + int low_sign, high_sign; + } KEY; + + typedef struct queue_node_defn{ + KEY key; + ACT_VERTEX_PTR v; + } Q_NODE, *Q_NODE_PTR; + +/* init_param structure to put all the options */ + typedef struct act_init_param_defn{ + int HEURISTIC_NUM; /* which act to construct */ + int NUM_ITER; /* number of iterations in iter. improvement */ + int FANIN_COLLAPSE; /* upper limit on fanins of a node to collapse */ + float GAIN_FACTOR; /* go from one iteration to other only if gain increases + by this ratio */ + int DECOMP_FANIN; /* lower limit on fanins of node to decompose */ + int DISJOINT_DECOMP;/* do disjoint decomposition before mapping */ + int QUICK_PHASE; /* do phase-assignment */ + int LAST_GASP; /* make network out of node and do iterations on it */ + int BREAK ; /* make the final network in terms of basic blocks */ + char delayfile[500]; /* name of the file with delay numbers for basic block + as a function of number of fanouts */ + float mode; /* 0 for area and 1 for delay mode, in between, a + weighted sum */ + /* the following used in ite routines */ + int COLLAPSE_FANINS_OF_FANOUT; /* u.l. on fanins of a fanout node after collapse */ + int map_alg; /* 1 if just algebraic matching used in act_bool.c */ + int lit_bound; /* decompose the node if it has more than these literals */ + int ITE_FANIN_LIMIT_FOR_BDD; /* construct an robdd (along with ite) if the node has + at most these many fanins */ + int COST_LIMIT; /* collapse a node into its fanout only if the cost of the node + is at most this much */ + int COLLAPSE_UPDATE; /* if set to EXPENSIVE, when a node is accepted for collapse, + include the fanins of the node, and the fanins of the fanouts for + the potential candidates for collapse along with the fanouts of the + node, else (INEXPENSIVE) just include the fanouts of the node */ + int COLLAPSE_METHOD; /* if OLD, then accept a collapse only if the sum of the costs of the + new fanouts is less than the cost of the node plus the sum of the + old costs of the fanouts. If NEW, if the cost of a single fanout + goes down, the collapse is accepted. Node remains in the network + unless the criterion in the OLD is satisfied too */ + int DECOMP_METHOD; /* if USE_GOOD_DECOMP, then use good decomp, get a network, map each + node of the network independently and then enter iterative + improvement. If USE_FACTOR, then an ite is constructed for the + factored form of the node. This factored form is arrived at by + decomp -g and tech_decomp -a 2 -o 2. */ + int ALTERNATE_REP; /* used right now only with ite_map - if 1, use robdd and see if the + cost improves. */ + int MAP_METHOD; /* if NEW, use the new mapping ite method (Dec. 92) else use + old method*/ + int VAR_SELECTION_LIT; /* if 0, use the old method of selecting the selection variable + at each step of ITE construction. If -1, then at each step, actual + mapping of the algebraic cofactors is done to get a better + estimate of the cost. Else it calls the new + method. If number of literals in a function is greater than + this number, weight assignment to each input is based on + three criterion: see ite_new_urp.c */ + + } act_init_param_t; + +/* just to store the fanout and arrival time info before and after a transformation */ +typedef struct temp_struct_defn{ + double old_arrival_time; + int old_num_fanouts; + int new_num_fanouts; + node_t *node; +} TEMP_STRUCT; + +/* stores info about the node and its fanout that we have to collapse into. + names are stored because on collapsing, fanout node is deleted and is replaced + by a new node of the same name. */ +typedef struct collapsible_pair_defn{ + char *nodename; + char *fanoutname; + double weight; /* reflects the total gain out of collapsing */ +} COLLAPSIBLE_PAIR; + +/* for freeing collapsed node from the network and cost_table */ +typedef struct argument_defn{ + st_table *cost_table; + network_t *network; +} ARGUMENT; + +/* update the arrival time info for collapsing only in topol. + order of fanins. This structure associates an index with a + nodename and hence allows sorting. */ +typedef struct topol_defn{ + char *nodename; + int index; +} TOPOL_STRUCT; + +/* to associate a vertex of the bdd with the node */ +typedef struct vertex_node_defn{ + ACT_VERTEX_PTR vertex; + node_t *node; +} VERTEX_NODE; + +/* global */ + + array_t *index_list_array; + array_t *index_list_array2; + array_t *global_lists; + + extern void p_actAlloc(); /* act_init.c */ + extern void p_actFree(); /* act_init.c */ + extern void p_actfree(); /* act_init.c */ + extern void p_actDup(); /* act_init.c */ + extern int p_actRemove(); /* act_remove.c */ + extern void p_actDestroy(); /* act_remove.c */ + extern void p_dagDestroy(); /* act_remove.c */ + extern void p_actCreate4Set(); + extern void p_addLists(); + extern void p_applyCreate(); + extern void traverse(); /* act_trav.c*/ + extern ACT_VERTEX_PTR actReduce(); /*act_reduce.c*/ + +/* act_map_delay.c (act_map.c) */ +extern COST_STRUCT *act_evaluate_map_cost(); +static decomp_big_nodes(); +static improve_network(); +static act_quick_phase(); +static iterative_improvement(); + +extern node_t *act_mux_node(); +static node_t *basic_block_node(); +static node_t *act_get_function(); +node_t *get_node_literal_of_vertex(); +static node_t *get_node_of_vertex(); +void free_node_if_possible(); +extern void put_node_names_in_act(); +extern void print_vertex(); +static int OR_pattern(); +extern array_t *OR_literal_order(); +extern array_t *single_cube_order(); +static int minimum_cost_index(); +static int minimum_costdelay_index(); +static char *formulate_IP(); +static void read_LINDO_file(); +static void partial_scan_lindoFile(); +extern int is_anyfo_PO(); +static int compute_cost_array(); +extern int cost_of_node(); +static void print_node_with_string(); +void set_mark_act(); +static void free_nodes_in_act_and_change_multiple_fo(); +static void init_bdnet(); +static char *act_get_node_fn_type(); +static enum st_retval free_table_entry(); +extern enum st_retval free_table_entry_without_freeing_key(); +extern void free_cost_table_without_freeing_key(); +extern ACT_VERTEX_PTR my_create_act(); +static ACT_VERTEX_PTR my_create_act_general(); +static int all_fanins_positive(); +extern int MARK_VALUE, MARK_COMPLEMENT_VALUE; +extern array_t *act_order_for_delay(); +extern int arrival_compare_fn(); +extern array_t *act_read_delay(); /*act_read.c */ +extern array_t *vertex_name_array; + +/* act_collapse.c */ +extern int act_partial_collapse_assign_score_network(); +extern int act_partial_collapse_assign_score_node(); +extern int act_partial_collapse_node(); +extern int act_partial_collapse_without_lindo(); +extern network_t *xln_check_network_for_collapsing_area(); + +/* act_util.c */ +extern int is_fanin_of(); +extern double my_max(); +extern COST_STRUCT *act_allocate_cost_node(); +extern ACT_VERTEX_PTR act_allocate_act_vertex(); +extern void act_initialize_act_area(); +extern void act_initialize_act_delay(); +extern VERTEX_NODE *act_allocate_vertex_node_struct(); +extern void act_put_nodes(); +extern void my_traverse_act(); + +/*act_dutil.c */ +extern void act_delay_trace_forward(); +extern void act_delay_trace_backward(); +extern double act_get_arrival_time(); +extern double act_get_required_time(); +extern COST_STRUCT *act_set_arrival_time(); +extern COST_STRUCT *act_set_required_time(); +extern double act_get_bddfanout_delay(); +extern double act_get_node_delay_correction(); +extern void act_set_pi_arrival_time_network(); +extern COST_STRUCT *act_set_pi_arrival_time_node(); +extern void act_invalidate_cost_and_arrival_time(); +extern double act_cost_delay(); +extern double act_delay_for_fanout(); +extern void act_set_slack_network(); +extern COST_STRUCT *act_set_slack_node(); +extern double act_get_slack_node(); +extern void act_find_critical_nodes(); +extern array_t *act_compute_area_delay_weight_network_for_collapse(); +extern array_t *act_compute_area_delay_weight_node_for_collapse(); +extern double act_compute_area_weight_node_for_collapse(); +extern COLLAPSIBLE_PAIR *act_allocate_collapsible_pair(); +extern double act_smallest_fanin_arrival_time_at_fanout_except_node(); +extern double act_largest_fanin_arrival_time_at_node(); +extern int c_pair_compare_function(); +extern double act_get_max_arrival_time(); +extern st_table *act_assign_topol_indices_network(); +extern array_t *act_topol_sort_fanins(); +extern void act_delete_topol_table_entries(); +extern enum st_retval act_delete_topol_table_entry(); + +/* act_map_delay.c (act_map.c) */ +extern void act_init_multiple_fo_array( /* VERTEX_PTR act_of_node */ ); +extern int map_act( /* VERTEX_PTR vertex */ ); +extern st_table *end_table; /* needed in make_bdd() urp_bdd.c*/ +extern network_t *act_map_network(); /* act_map.c */ +extern network_t *act_break_network(); /*act_map.c */ +extern network_t *act_network_remap(); /* act_map.c */ +extern void act_act_free(); +extern void free_cost_struct(); +extern COST_STRUCT *make_tree_and_map(); +extern COST_STRUCT *make_tree_and_map_delay(); + +extern int WHICH_ACT; /* act_map.c */ +extern int print_network(); +extern FILE *BDNET_FILE; /* com_pld.c */ +extern int ACT_DEBUG; /* com_pld.c */ +extern int ACT_STATISTICS; /* com_pld.c */ + +extern int MAXOPTIMAL; +extern array_t *multiple_fo_array; /* holds the nodes that have multiple_fo in the act */ +extern int WHICH_ACT; +extern ACT_VERTEX * PRESENT_ACT; /* for temporary storage */ +extern int num_or_patterns; + +/* act_delay.c */ +extern array_t *act_order_for_delay(); + +/* Definitions for Xilinx*/ + +/* xln_merge and xln_map_par*/ +#define MAX_MATCHING 1000 +#define BUFSIZE 500 + +#define SOURCE_NAME "source" +#define SINK_NAME "sink" + +#define FAST 0 +#define GOOD 1 +#define ON 1 +#define OFF 0 +#define YES 1 +#define NO 0 +#define OK 1 +#define UNKNOWN -1 +extern void ULM_decompose_func(); +extern void ULM_eval_func(); +extern void ULM_create_partition_matrix(); +extern void merge_node(); +extern void partition_network(); +extern void change_edge_capacity(); +extern int get_maxflow(); +extern char *formulate_Lindo(); +extern mf_edge_t *get_maxflow_edge(); +extern node_t *graph2network_node(); +extern void print_fanin(); +extern int comp_ptr(); +extern void count_intsec_union(); +extern enum st_retval print_table_entry(); +extern void print_array(); +/* added March 30, 1992 */ +/*----------------------*/ +extern sm_row *sm_shortest_row(); +extern st_table *xln_collapse_nodes_after_merge(); +extern sm_row *sm_mat_bin_minimum_cover_my(); +extern sm_row *sm_mat_bin_minimum_cover_greedy(); + +/**********/ +/* macros */ +/**********/ + +/* Macro procedure that swaps two entities. */ +/*------------------------------------------*/ +#define SWAP(type, a, b) {type swapx; swapx = a; a = b; b = swapx;} + + +/* Macro to copy a string: it returns the pointer to the string */ +/*--------------------------------------------------------------*/ +#define SAVE(ptostring) strcpy(CALLOC(char,strlen(ptostring)+1),ptostring) + +/* Macro for random number generation */ +/*------------------------------------*/ +#define RAND(a) ( a = ( a * 1103515245 + 12345 ) & MAX_INT )) +#define NORM(n) ( (double) n / (double) MAX_INT ) +#define NRAND(a) ( (double) ( a = ( a * 1103515245 + 12345 ) & MAX_INT ) / (double) MAX_INT ) + +#define EXP(d,t) ( (t) == 0. ? 0. : exp( -(double) (d) / (t) ) ) +#define LOG_B(base,x) ( log(x)/log(base) ) + +#define RINT(a) ( (int) floor( (double) a + 0.5 ) ) + +/* xln_part.c */ +typedef struct a_node_struct { + float value; + char *name; + char *fanout; +} a_node, *a_node_ptr; + + +typedef struct a_divisor { + node_t *divisor; + int kernelsize; +} divisor_t; + +typedef struct a_kern_node{ + node_t *node; + array_t *cost_array; + int size; /* added later */ +} kern_node; + +/* xln_k_decomp.c and xln_ufind.c*/ + +typedef struct tree_node{ + int index; + struct tree_node *parent; + int num_child; + int class_num; + } tree_node; + + + extern void binary(); /* (value, string) */ /* xln_aux.c */ + extern void reverse_string(); /* (answer, givenstring) */ /* xln_aux.c */ + extern void xl_binary1(); /*xln_aux.c */ + extern int *xln_array_to_indices(); /* xln_aux.c */ + extern tree_node *find_tree(); /*xln_ufind.c */ + extern int unionop(); /* xln_ufind.c */ + +/* xln_feasible.c */ + extern array_t *xln_get_bound_set(); + extern int xln_node_move_fanin(); + + extern node_t *dec_node_cube(); /* xln_aodecomp.c */ + extern int pld_decomp_and_or(); /* xln_part_dec.c */ + + extern int XLN_DEBUG; + extern int XLN_BEST; + extern int use_complement; + extern xln_kernel_extract(); + +/* xln_imp.c */ + extern network_t *xln_best_script(); + extern network_t *xln_cofactor_decomp(); + extern node_t *xln_select_fanin_for_cofactor_area(); + extern node_t *xln_select_fanin_for_cofactor_delay(); + + extern array_t *xln_k_decomp_node_with_array(); + extern network_t *xln_k_decomp_node_with_network(); + +/* xln_level.c */ + extern network_t *xln_check_network_for_collapsing_delay(); + extern array_t *xln_array_of_levels(); + extern array_t *xln_array_of_critical_nodes_at_levels(); + +/* xln_k_decomp_area.c */ + extern network_t *xln_exhaustive_k_decomp_node(); + +/* xln_cube.c */ + extern int xln_ao_compare(); + +/* pld_util.c */ + extern pld_replace_node_by_network(); + extern pld_remap_init_corr(); + extern node_t *pld_remap_get_node(); + extern node_t *pld_make_node_from_cube(); + extern array_t *pld_nodes_from_cubes(); + extern array_t *pld_cubes_of_node(); + extern array_t *pld_get_non_common_fanins(); + extern int pld_is_node_in_array(); + extern int pld_is_fanin_subset(); + extern array_t *pld_get_array_of_fanins(); + extern st_table *pld_insert_intermediate_nodes_in_table(); + extern array_t *sm_get_rows_covered_by_col(); + extern array_t *sm_get_cols_covered_by_row(); + +/* xln_dec_merge.c */ +#define ALL_CUBES 1 +#define PAIR_NODES 2 + + extern int pld_affinity_compare_function(); + extern array_t *xln_node_find_common_inputs(); + extern node_t *xln_extract_supercube_from_cube(); + extern array_t *xln_fill_tables(); + extern array_t *xln_infeasible_nodes(); + + /* for storing the pairs of nodes and their affinity */ + typedef struct xln_affinity_struct_defn { + node_t *node1; /* first node of the pair */ + node_t *node2; /* second node of the pair*/ + array_t *common; /* array of common fanins of node1 & node2 */ + } AFFINITY_STRUCT; + + typedef struct xln_move_struct_defn { + int MOVE_FANINS; + int MAX_FANINS; + int bound_alphas; /* for delay: this controls the number of functions created */ + } XLN_MOVE_STRUCT; + + typedef struct xln_init_param_defn { + int support; /* for xilinx, support = 5 */ + int MAX_FANIN; /* for two-output blocks - condition for merging*/ + int MAX_COMMON_FANIN; /* for two-output blocks - condition for merging*/ + int MAX_UNION_FANIN; /* for two-output blocks - condition for merging*/ + int heuristic; + int common_lower_bound; /* for dec_merge */ + int cube_support_lower_bound; /* for dec_merge */ + int lit_bound; + int cover_node_limit; /* apply exact xl_cover if number of nodes in some + subnetwork (or network) is at most this */ + int flag_decomp_good; /* could be 0 (no decomp -g), 1 (decomp -g), 2 + (pick the better of the previous two) */ + int good_or_fast; /* just apply cube-packing or all decomp techniques */ + int absorb; /* use Roth-Karp to move fanins */ + int num_iter_partition; /* xl_reduce will call xl_partition these many times */ + int num_iter_cover; /* xl_reduce will call xl_cover these many times */ + int DESPERATE; + int RECURSIVE; + int MAX_FANINS_K_DECOMP; /* node considered for Roth-Karp decomp if has at most + these many fanins */ + int COST_LIMIT; /* nodes with at most this cost to be collapsed in + partial_collapse routine */ + XLN_MOVE_STRUCT xln_move_struct; + int collapse_input_limit; /* consider total collapse of the network if number + of PI's no more than this */ + int traversal_method; /* 1 then topological traversal, else levels sorted + wrt width */ + } xln_init_param_t; + + diff --git a/sis/pld/pld_util.c b/sis/pld/pld_util.c new file mode 100644 index 0000000..03c677b --- /dev/null +++ b/sis/pld/pld_util.c @@ -0,0 +1,469 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/pld_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/*----------------------------------------------------------------------- + Replaces node by network1. Node should be in some network. Postscript + 1 always refers to the network for node or any node therein. +------------------------------------------------------------------------*/ +pld_replace_node_by_network(node, network1) + node_t *node; + network_t *network1; +{ + node_t *node1, *node1_dup; + array_t *nodevec1; + int i, num_nodes2; + st_table *table1; + network_t *network; + + network = node->network; + nodevec1 = network_dfs(network1); + table1 = st_init_table(st_ptrcmp, st_ptrhash); + /* set correspondence between p.i. and ... */ + /*-----------------------------------------*/ + pld_remap_init_corr(table1, network, network1); + num_nodes2 = array_n(nodevec1) - 2; + for (i = 0; i < num_nodes2; i++) { + node1 = array_fetch(node_t *, nodevec1, i); + if (node1->type != INTERNAL) continue; + node1_dup = pld_remap_get_node(node1, table1); + FREE(node1_dup->name); + FREE(node1_dup->short_name); + network_add_node(network, node1_dup); + assert(!st_insert(table1, (char *) node1, (char *) node1_dup)); + /* if (XLN_DEBUG > 3) (void) printf("****corr. between %s and %s\n", + node_long_name(node1), node_long_name(node1_dup)); + */ + } + /* the last node in the array in primary output - do not want that */ + /*-----------------------------------------------------------------*/ + node1 = array_fetch(node_t *, nodevec1, num_nodes2); + assert(node1->type == INTERNAL); + node1_dup = pld_remap_get_node(node1, table1); + /* if (XLN_DEBUG > 3) (void) printf("****corr. finally between %s and %s\n", + node_long_name(node1), node_long_name(node1_dup)); */ + node_replace(node, node1_dup); + + st_free_table(table1); + array_free(nodevec1); +} + +/*----------------------------------------------------------------- + Returns a node for the original network which has same logic + function as node1 of network1. +------------------------------------------------------------------*/ +node_t * +pld_remap_get_node(node1, table1) + node_t *node1; + st_table *table1; +{ + node_t *node, *n2, *cube, *cube2, *fanin, *fanin1, *fanin_lit; + node_cube_t cube1; + node_literal_t literal1; + int i, j; + + node = node_constant(0); + for (i = node_num_cube(node1) - 1; i >= 0; i--) { + cube = node_constant(1); + cube1 = node_get_cube(node1, i); + foreach_fanin(node1, j, fanin1) { + assert(st_lookup(table1, (char *) fanin1, (char **) &fanin)); + literal1 = node_get_literal(cube1, j); + switch(literal1) { + case ONE: /* +ve phase */ + fanin_lit = node_literal(fanin, 1); + cube2 = node_and(cube, fanin_lit); + node_free(fanin_lit); + node_free(cube); + cube = cube2; + break; + case ZERO: + fanin_lit = node_literal(fanin, 0); + cube2 = node_and(cube, fanin_lit); + node_free(fanin_lit); + node_free(cube); + cube = cube2; + break; + case TWO: + break; + default: + (void) printf("error in the cube\n"); + exit(1); + } + } + n2 = node_or(cube, node); + node_free(cube); + node_free(node); + node = n2; + } + return node; +} + +/*------------------------------------------------------------------ + Sets up correspondence between primary inputs of network1 and + the corresponding nodes of network. +--------------------------------------------------------------------*/ +pld_remap_init_corr(table1, network, network1) + st_table *table1; + network_t *network, *network1; +{ + lsGen gen; + node_t *pi1, *node; + + foreach_primary_input(network1, gen, pi1) { + node = network_find_node(network, node_long_name(pi1)); + assert(!st_insert(table1, (char *) pi1, (char *) node)); + /* if (ACT_DEBUG) + (void) printf("inserting node %s (%s) in table\n", node_long_name(node), + node_name(node)); */ + } +} + +/*--------------------------------------------------------------------------- + For each cube of the node, forms a node. Returns an array of these nodes. +----------------------------------------------------------------------------*/ +array_t * +pld_nodes_from_cubes(node) + node_t *node; +{ + array_t *nodevec; + int i; + node_cube_t cube; + node_t *node_cube; + + nodevec = array_alloc(node_t *, 0); + for (i = node_num_cube(node) - 1; i >= 0; i--) { + cube = node_get_cube(node, i); + node_cube = pld_make_node_from_cube(node, cube); + array_insert_last(node_t *, nodevec, node_cube); + } + return nodevec; +} + +/*----------------------------------------------------------------- + Returns a node from the cube. +------------------------------------------------------------------*/ +node_t * +pld_make_node_from_cube(node, cube) + node_t *node; + node_cube_t cube; +{ + node_t *n, *n1, *n2, *fanin; + int j; + node_literal_t literal; + + n = node_constant(1); + foreach_fanin(node, j, fanin) { + literal = node_get_literal(cube, j); + switch(literal) { + case ONE: + n1 = node_literal(fanin, 1); + n2 = node_and(n, n1); + node_free(n); + node_free(n1); + n = n2; + break; + case ZERO: + n1 = node_literal(fanin, 0); + n2 = node_and(n, n1); + node_free(n); + node_free(n1); + n = n2; + break; + case TWO: + break; + } + } + return n; +} + +/*----------------------------------------------------------------- + Given a node, returns an array of cubes of the nodes. +------------------------------------------------------------------*/ +array_t * +pld_cubes_of_node(node) + node_t *node; +{ + array_t *cubevec; + int i; + node_cube_t cube; + + cubevec = array_alloc(node_cube_t, 0); + for (i = node_num_cube(node) - 1; i >= 0; i--) { + cube = node_get_cube(node, i); + array_insert_last(node_cube_t, cubevec, cube); + } + return cubevec; +} + +/*------------------------------------------------------------------------- + Given a node, returns an array of fanins of the node not present in the + array common. +--------------------------------------------------------------------------*/ +array_t * +pld_get_non_common_fanins(node, common) + node_t *node; + array_t *common; +{ + array_t *nc; + node_t *fanin; + int i; + + nc = array_alloc(node_t *, 0); + foreach_fanin(node, i, fanin) { + if (pld_is_node_in_array(fanin, common)) continue; + array_insert_last(node_t *, nc, fanin); + } + return nc; +} + +int +pld_is_node_in_array(node, vec) + node_t *node; + array_t *vec; +{ + int i; + node_t *n; + + for(i = 0; i < array_n(vec); i++) { + n = array_fetch(node_t *, vec, i); + if (n == node) return 1; + } + return 0; +} + +int +pld_num_fanin_cube(cube, node) + node_cube_t cube; + node_t *node; +{ + int i; + int num_fanin; + int count; + node_literal_t literal; + + count = 0; + num_fanin = node_num_fanin(node); + for (i = 0; i < num_fanin; i++) { + literal = node_get_literal(cube, i); + if ((literal == ONE) || (literal == ZERO)) count++; + } + return count; +} + +/*-------------------------------------------------------------- + Returns 1 if the fanin-set of n1 is a subset of fanin-set of + n2. Else 0. +---------------------------------------------------------------*/ +int +pld_is_fanin_subset(n1, n2) + node_t *n1, *n2; +{ + int j; + node_t *fanin; + + foreach_fanin(n1, j, fanin) { + if (node_get_fanin_index(n2, fanin) >= 0) continue; + return 0; + } + return 1; +} + +array_t * +pld_get_array_of_fanins(node) + node_t *node; +{ + int i; + node_t *fanin; + array_t *faninvec; + + if (node->type == PRIMARY_INPUT) return NIL (array_t); + faninvec = array_alloc(node_t *, 0); + foreach_fanin(node, i, fanin) { + array_insert_last(node_t *, faninvec, fanin); + } + return faninvec; +} + +pld_replace_node_with_array(node, nodevec) + node_t *node; + array_t *nodevec; +{ + node_t *n; + int i; + + for (i = 1; i < array_n(nodevec); i++) { + n = array_fetch(node_t *, nodevec, i); + network_add_node(node->network, n); + } + n = array_fetch(node_t *, nodevec, 0); + node_replace(node, n); +} + +pld_simplify_network_without_dc(network) + network_t *network; +{ + lsGen gen; + node_t *node; + + foreach_node(network, gen, node) { + if (node->type != INTERNAL) continue; + simplify_node(node, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, SIM_FILTER_NONE, + SIM_ACCEPT_SOP_LITS); + } +} + +int +xln_is_network_feasible(network, support) + network_t *network; + int support; +{ + lsGen gen; + node_t *node; + + foreach_node(network, gen, node) { + if (node->type != INTERNAL) continue; + if (node_num_fanin(node) > support) return 0; + } + return 1; +} + +int +my_node_equal(node1, node2) + node_t *node1, *node2; +{ + node_function_t fn1, fn2; + + fn1 = node_function(node1); + fn2 = node_function(node2); + if ((fn1 == NODE_0) && (fn2 == NODE_0)) return 1; + if ((fn1 == NODE_1) && (fn2 == NODE_1)) return 1; + return node_equal(node1, node2); +} + +st_table* +pld_insert_intermediate_nodes_in_table(network) + network_t *network; +{ + st_table *table; + node_t *node; + lsGen gen; + + table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_node(network, gen, node) { + if (node->type == INTERNAL) { + (void) st_insert(table, (char *) node, (char *) node); + } + } + return table; +} + +/*----------------------------------------- + Delete nodes of array from table. +------------------------------------------*/ +pld_delete_array_nodes_from_table(table, array) + st_table *table; + array_t *array; +{ + int i; + node_t *node; + char *dummy; + + for (i = 0; i < array_n(array); i++) { + node = array_fetch(node_t *, array, i); + assert(st_delete(table, (char **) &node, &dummy)); + } +} + +sm_delete_rows_covered_by_col(matrix, col) + sm_matrix *matrix; + sm_col *col; +{ + array_t *row_array; + + row_array = sm_get_rows_covered_by_col(matrix, col); + sm_delete_rows_in_array(matrix, row_array); + array_free(row_array); +} + +sm_delete_rows_in_array(matrix, row_array) + sm_matrix *matrix; + array_t *row_array; +{ + int i; + sm_row *row; + + for (i = 0; i < array_n(row_array); i++) { + row = array_fetch(sm_row *, row_array, i); + sm_delrow(matrix, row->row_num); + } + +} + +sm_delete_cols_covered_by_row(matrix, row) + sm_matrix *matrix; + sm_row *row; +{ + array_t *col_array; + + col_array = sm_get_cols_covered_by_row(matrix, row); + sm_delete_cols_in_array(matrix, col_array); + array_free(col_array); +} + +sm_delete_cols_in_array(matrix, col_array) + sm_matrix *matrix; + array_t *col_array; +{ + int i; + sm_col *col; + + for (i = 0; i < array_n(col_array); i++) { + col = array_fetch(sm_col *, col_array, i); + sm_delcol(matrix, col->col_num); + } + +} + +array_t * +sm_get_rows_covered_by_col(matrix, col) + sm_matrix *matrix; + sm_col *col; +{ + array_t *row_array; + sm_element *p; + sm_row *row; + + row_array = array_alloc(sm_row *, 0); + sm_foreach_col_element(col, p) { + assert(row = sm_get_row(matrix, p->row_num)); + array_insert_last(sm_row *, row_array, row); + } + return row_array; +} + +array_t * +sm_get_cols_covered_by_row(matrix, row) + sm_matrix *matrix; + sm_row *row; +{ + array_t *col_array; + sm_element *p; + sm_col *col; + + col_array = array_alloc(sm_col *, 0); + sm_foreach_row_element(row, p) { + assert(col = sm_get_col(matrix, p->col_num)); + array_insert_last(sm_col *, col_array, col); + } + return col_array; +} + diff --git a/sis/pld/xln_ULM_util.c b/sis/pld/xln_ULM_util.c new file mode 100644 index 0000000..02430bf --- /dev/null +++ b/sis/pld/xln_ULM_util.c @@ -0,0 +1,316 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_ULM_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +/* + * util.c + * ****** + * functions contained in this file: + * change_edge_capacity() + * get_maxflow() + * get_maxflow_edge() + * graph2network_node() + * print_fanin() + * comp_ptr() + * count_intsec_union() + * print_table() + * print_array() + * Import descriptions: + * sis.h : macros for misII + * ULM_int.h : macros for universal logic module package + */ + +#include "sis.h" +#include "pld_int.h" +/* + * change_edge_capacity() + * Change the capacity of an edge in the flow network + * Assumes this edge is from bottom node to top node both of which + * corresponds to the given node in the network + */ + +void +change_edge_capacity(graph, node, capacity) + +mf_graph_t *graph; +node_t *node; +int capacity; + +{ + char name1[BUFSIZE]; + char name2[BUFSIZE]; + + (void) sprintf(name1, "%s_top", node_long_name(node)); + (void) sprintf(name2, "%s_bottom", node_long_name(node)); + (void) mf_reread_edge(graph, name2, name1, capacity); +} + + + +/* + * get_maxflow() + * Get the value of maxflow for the given flow network + */ + + +int +get_maxflow(graph) + +mf_graph_t *graph; /* pointer to graph */ + +{ + int i; + int flow; + int save_flow; + mf_edge_t *edge; + mf_node_t *source; + + /* Print the input graph */ + + maxflow(graph, OFF); + + /* Get the value of maxflow */ + flow = 0; + source = mf_get_source_node(graph); + mf_foreach_fanout(source, i, edge) { + save_flow = flow; + flow += mf_get_edge_flow(edge); + + /* Check if the overflow has occured */ + if (flow < save_flow) { + flow = MAXINT; + break; + } + } + + return(flow); +} + + + + +/* + * get_maxflow_edge() + * Get the maxflow network edge from the graph nodes + * RETURNS + * edge : pointer to the network edge + */ + + +mf_edge_t * +get_maxflow_edge(graph, name1, name2) + +mf_graph_t *graph; /* pointer to graph */ +char *name1; /* name of the source node of an edge */ +char *name2; /* name of the sink node of an edge */ + +{ + + + int i; + mf_edge_t *edge; + mf_node_t *node1; + mf_node_t *node2; + + + node1 = mf_get_node(graph, name1); + node2 = mf_get_node(graph, name2); + mf_foreach_fanout(node1, i, edge) { + if (node2 == mf_head_of_edge(edge)) { + return(edge); + } + } + return(NULL); + + +} + + + + + +/* + * graph2network_node() + * Get the network node from the graph node + * + * RETURN + * node : pointer to the network node + * Possible errors + * --------------- + * Assumes that the name of each graph_node has a modifier such as _top, + * _bottom, _left, or _right in the end. + * + */ + + +node_t * +graph2network_node(network, graph_node) +network_t *network; /* pointer to network */ +mf_node_t *graph_node; /* pointer to a node in the graph */ +{ + char buf[BUFSIZE], *ptr; + + (void) strcpy(buf, mf_node_name(graph_node)); + ptr = strrchr(buf, '_'); + if (ptr) + *ptr = '\0'; + return(network_find_node(network, buf)); +} + +/* + * print_fanin() + * Print the names of the fanin nodes of a given node + * Arguments: + * --------- + * node : node whose fanins are to be printed + * + */ + +void print_fanin(node) + +node_t *node; + +{ + + node_t *fanin; + int i; + + (void) printf("Fanins of node %s = ", node_long_name(node)); + foreach_fanin(node, i, fanin) { + (void) printf("%s ", node_long_name(fanin)); + } + (void) printf("\n"); + +} + + + +/* + * comp_ptr() + * Compare function for array_sort + * + * RETURNS + * ------- + * -1,0,1 : if obj1 <,=,> obj2 + */ + +int comp_ptr(obj1, obj2) + +char *obj1; +char *obj2; + +{ + + int value; + + value = (int)obj1 - (int)obj2; + if (value < 0) { + return(-1); + } else if (value > 0) { + return(1); + } else { + return(0); + } +} + + + + +/* + * count_intsec_union() + * Count the cardinality of the intersection and union of two sets given + * that are stored in array_t. + * + * Assume that the arrays are sorted in advance + */ + + +void +count_intsec_union(array1, array2, num_intsec, num_union) + +array_t *array1, *array2; +int *num_intsec, *num_union; + +{ + + int i, j; + char *element1, *element2; + + + *num_intsec = *num_union = 0; + + for(i = 0, j = 0; ;) { + if (i > array_n(array1) - 1) { + *num_union += array_n(array2) - j; + break; + } + if (j > array_n(array2) - 1) { + *num_union += array_n(array1) - i; + break; + } + element1 = array_fetch(char *, array1, i); + element2 = array_fetch(char *, array2, j); + if (element1 < element2) { + ++i; + } else if (element1 > element2) { + ++j; + } else { + ++(*num_intsec); + ++i; ++j; + } + ++(*num_union); + } + +} + + + + +/* + * Print an entry in the table (debug use) + * + */ + +enum st_retval +print_table_entry(key, value, arg) + +char *key; +char *value; +char *arg; + +{ + + (void) printf("key = %s, value = %x arg = %s\n", key, value, arg); + return(ST_CONTINUE); + +} + + + +void print_table(table) +st_table *table; +{ + st_foreach(table, print_table_entry, (char *)NULL); +} + + +void print_array(array, hash_table) +array_t *array; +nodeindex_t *hash_table; +{ + int i; + node_t *node; + + for(i = 0; i < array_n(array); i++) { + node = array_fetch(node_t *, array, i); + (void) printf("%s(%d) ", node_long_name(node), + nodeindex_indexof(hash_table, node)); + } + (void) printf("\n"); +} + diff --git a/sis/pld/xln_aodecomp.c b/sis/pld/xln_aodecomp.c new file mode 100644 index 0000000..11752f9 --- /dev/null +++ b/sis/pld/xln_aodecomp.c @@ -0,0 +1,222 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_aodecomp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +static void decomp_and(); +static void decomp_or(); + +int +pld_decomp_and_or(network, f, size) +network_t *network; +node_t *f; +int size; +{ + node_t *g, *t, *clit, *c; + int i; + if(XLN_DEBUG){ + node_print(sisout, f); + } + if( node_function(f) == NODE_AND) { + decomp_and(network, f , size); + } + if ( node_function(f) == NODE_OR) { + decomp_or(network, f , size); + } + if(node_function(f) == NODE_COMPLEX) { + g = node_constant(0); + for (i = node_num_cube(f)-1; i>= 0; i--) { + c = dec_node_cube(f, i); + network_add_node(network, c); + /* node_print(sisout, c);*/ + if(node_num_fanin(c) > size ) { + decomp_and(network, c, size); + } + clit = node_literal(c, 1); + t = node_or(g, clit); + node_free(clit); + node_free(g); + g = t; + } + node_replace(f, g); + if(node_num_fanin(f) > size) { + decomp_or(network, f, size); + } + } + return(1); +} + +static void +decomp_and(network, f, and_limit) +network_t *network; +node_t *f; +int and_limit; +{ + array_t *nodes, *leaves; + node_t *root, *leaf, *fanin, *node; + int i; + + if (and_limit <= 0) { + fail("Error: wrong fanin limit for AND gate"); + } + + if (node_function(f) != NODE_AND) { + fail("Error: function type is not AND in decomp_and"); + } + (void)node_d1merge(f); + if((node_function(f) == NODE_0) || (node_function(f) == NODE_1)) { + (void)fprintf(sisout, "redundancy in logic, advise u to \n minimise logic and proceed\n"); + (void)node_print(sisout, f); + return ; + } +balanced_tree(node_num_fanin(f), and_limit, node_and, &root, &nodes, &leaves); + + /* connect the leaves */ + for (i = array_n(leaves)-1; i >= 0; i--) { + leaf = array_fetch(node_t *, leaves, i); + fanin = node_get_fanin(f, i); + switch (node_input_phase(f, node_get_fanin(f, i))) { + case POS_UNATE: + node_replace(leaf, node_literal(fanin, 1)); + break; + case NEG_UNATE: + node_replace(leaf, node_literal(fanin, 0)); + break; + default: + fail("Error: wrong phase of a input in decomp_and"); + } + } + + /* replace f */ + for (i = array_n(nodes)-1; i >= 0; i--) { + node = array_fetch(node_t *, nodes, i); + if (node == root) { + node_replace(f, node); + } else { + network_add_node(network, node); + } + } + + array_free(nodes); + array_free(leaves); +} + + +static void +decomp_or(network, f, or_limit) +network_t *network; +node_t *f; +int or_limit; +{ + array_t *nodes, *leaves; + node_t *root, *leaf, *fanin, *node; + int i; + + if (or_limit <= 0) { + fail("Error: wrong fanin limit for OR gate"); + } + + if (node_function(f) != NODE_OR) { + fail("Error: function type is not OR in decomp_or"); + } + (void)node_d1merge(f); + if((node_function(f) == NODE_0) || (node_function(f) == NODE_1)) { + (void)fprintf(sisout, "redundancy in logic, advise u to \n minimise logic and proceed\n"); + (void)node_print(sisout, f); + return; + } + +balanced_tree(node_num_fanin(f), or_limit, node_or, &root, &nodes, &leaves); + + /* connect the leaves */ + for (i = array_n(leaves)-1; i >= 0; i--) { + leaf = array_fetch(node_t *, leaves, i); + fanin = node_get_fanin(f, i); + switch (node_input_phase(f, node_get_fanin(f, i))) { + case POS_UNATE: + node_replace(leaf, node_literal(fanin, 1)); + break; + case NEG_UNATE: + node_replace(leaf, node_literal(fanin, 0)); + break; + case BINATE: + (void)fprintf(sisout,"BINATE \n"); + node_print(sisout, leaf); + node_print(sisout, fanin); + break; + default: + fail("Error: wrong phase of a input in decomp_or"); + (void)node_print(sisout, leaf); + (void)node_print(sisout, fanin); + break; + } + } + + /* replace f */ + for (i = array_n(nodes)-1; i >= 0; i--) { + node = array_fetch(node_t *, nodes, i); + if (node == root) { + node_replace(f, node); + } else { + network_add_node(network, node); + } + } + + array_free(nodes); + array_free(leaves); +} + + +balanced_tree(n, m, node_func, root, nodes, leaves) +int n; /* number of leaves */ +int m; /* branching factor */ +node_t *(*node_func)(); /* function at a node */ +node_t **root; /* points to the root of the tree */ +array_t **nodes; /* points to all nodes */ +array_t **leaves; /* points to the leaves */ +{ + node_t *np, *rt; + array_t *ns, *lv; + int d, s; + bool first; + + if (n == 1) { + *root = node_alloc(); + *nodes = array_alloc(node_t *, 0); + array_insert_last(node_t *, *nodes, *root); + *leaves = array_alloc(node_t *, 0); + array_insert_last(node_t *, *leaves, *root); + } else { + first = TRUE; + d = (n + m - 1) / m; + while (n > 0) { + s = MIN(d, n); + n = n - d; + balanced_tree(s, m, node_func, &rt, &ns, &lv); + if (first) { + *root = node_literal(rt, 1); + *nodes = array_alloc(node_t *, 0); + array_insert_last(node_t *, *nodes, *root); + array_append((*nodes), ns); + array_free(ns); + *leaves = lv; + first = FALSE; + } else { + np = node_literal(rt, 1); + node_replace(*root, (*node_func)(*root, np)); + node_free(np); + array_append((*nodes), ns); + array_append((*leaves), lv); + array_free(ns); + array_free(lv); + } + } + } +} diff --git a/sis/pld/xln_aux.c b/sis/pld/xln_aux.c new file mode 100644 index 0000000..1b74e11 --- /dev/null +++ b/sis/pld/xln_aux.c @@ -0,0 +1,85 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_aux.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" +#include <math.h> + +/* Return the ceiling of log2(n). Use the fact that the floor of the binary +log of n is the highest-order bit of the integer representation */ +int +intlog2(n) +int n; +{ + int i, j, ans; + + if(n <= 0) { + (void) fprintf(stderr, "Error: can't take the log of %d\n", n); + fail(""); + } + + /* Through the loop, ans is = floor(log2(n)), i = 2^ans */ + for(ans = 0, i = 1, j = n; (j = j >> 1) != 0; ++ans, (i = i<<1)); + + /* if n = i, n = 2^ans, i.e., floor(log2(n)) = ceil(log2(n)). Otherwise + bump up ans to make it the ceil */ + if(n > i) ++ans; + return ans; +} + + +void xl_binary1(value, length, string) + int value; + int length; + char *string; +{ + int Position = 0; + int remainder; + int i; + char string1[BUFSIZE]; + + for ( i= 0; i < BUFSIZE; i++) string1[i] = '0'; + while (value != 0) { + remainder = value % 2; + value = (value - remainder) /2; + if (remainder == 0) string1[Position++] = '0'; + else string1[Position++] = '1'; + }; + if (Position > length) { + (void) printf(" The length of string of value '%d' greater than %d\n",value,length); + exit(1); + } + for (i = 0; i < length; i++) + string[i] = string1[length - 1 - i]; + + string[length] = '\0'; + +}; +/*-------------------------------------------------------------- + Given some subset of fanins of node in array Y, return an + int array corresponding to the indices of the fanins. +---------------------------------------------------------------*/ +int * +xln_array_to_indices(Y, node) + array_t *Y; + node_t *node; +{ + int *lambda_indices; + int j, index; + node_t *fanin; + + lambda_indices = ALLOC(int, array_n(Y)); + for (j = 0; j < array_n(Y); j++) { + fanin = array_fetch(node_t *, Y, j); + index = node_get_fanin_index(node, fanin); + lambda_indices[j] = index; + } + return lambda_indices; +} + diff --git a/sis/pld/xln_collapse.c b/sis/pld/xln_collapse.c new file mode 100644 index 0000000..3233f4b --- /dev/null +++ b/sis/pld/xln_collapse.c @@ -0,0 +1,431 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_collapse.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" + + +/*-------------------------------------------------------------------------- + This file includes a routine similar to the one used in Actel - cost for + each node is known. (The node is not decomposed into feasible nodes, but + remains as such). Then a score is given to each node which reflects the + possible gain that might be achieved if this node is collapsed into all + the fanouts. Node with maximum score is picked and tried for collapsing. + If it helps, it is accepted and the score of each fanout is updated. + Repeat the process and in the end, replace each node by the network + associated with it. +-----------------------------------------------------------------------------*/ + +xln_partial_collapse(network, init_param) + network_t *network; + xln_init_param_t *init_param; +{ + array_t *nodevec, *fanoutvec; + int i, j, k, num; + node_t *node, *fanin, *fanout; + st_table *cost_table; /* storing a feasible network for each internal node */ + network_t *network_node; /* feasible network for a node */ + int gain, total_gain, collapsed; + int cost_node; + int num_collapsed, trivial_collapsed; + int total_cost; /* of the network in terms of tlu's*/ + /* int changed; */ + st_table *table_affected_nodes; + st_generator *stgen; + lsGen genfo; + char *dummy, *key, *name; + + /* do a trivial collapse first */ + /*------------------------------*/ + num_collapsed = 0; + trivial_collapsed = 1; + while (trivial_collapsed) { + trivial_collapsed = + xln_do_trivial_collapse_network(network, init_param->support, + init_param->xln_move_struct.MOVE_FANINS, + init_param->xln_move_struct.MAX_FANINS); + /* added March 15, 1991 */ + num_collapsed += trivial_collapsed; + } + + if (XLN_DEBUG) { + (void) printf("---collapsed %d nodes in trivial collapse\n", num_collapsed); + } + + nodevec = network_dfs(network); + num = array_n(nodevec); + + /* compute the cost of each node and store the resulting feasible network */ + /*------------------------------------------------------------------------*/ + cost_table = st_init_table(strcmp, st_strhash); /* stores the network here */ + total_cost = 0; + for (i = 0; i < num; i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + + /* Added Aug 26 93 to avoid the problem encountered when the node + is not expressed in minimum support - see xln_imp.c */ + /*--------------------------------------------------------------*/ + simplify_node(node, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, SIM_FILTER_NONE, + SIM_ACCEPT_SOP_LITS); + network_node = xln_best_script(node, init_param); + total_cost += network_num_internal(network_node); + assert(!st_insert(cost_table, node_long_name(node), (char *) network_node)); + } + array_free(nodevec); + if (XLN_DEBUG) + (void) printf("****total cost after initial mapping is %d\n", total_cost); + + /* alternate collapsing - hopefully faster */ + /*-----------------------------------------*/ + total_gain = 0; + nodevec = network_dfs(network); + num = array_n(nodevec); + while (num) { + /* for next iteration, store affected nodes in this table */ + /*--------------------------------------------------------*/ + table_affected_nodes = st_init_table(strcmp, st_strhash); + for (i = 0; i < num; i++) { + node = array_fetch(node_t *, nodevec, i); + + /* if the node was to be considered in next iteration, delete it + from table, as it is being considered now */ + /*--------------------------------------------------------------*/ + name = node_long_name(node); + (void) st_delete(table_affected_nodes, &name, &dummy); + if (node->type != INTERNAL) continue; + if (is_anyfo_PO(node)) continue; + cost_node = xln_cost_of_node(node, cost_table); + if (cost_node > init_param->COST_LIMIT) continue; + + /* save fanouts, as we may lose them in collapse routine */ + /*-------------------------------------------------------*/ + fanoutvec = array_alloc(node_t *, 0); + foreach_fanout(node, genfo, fanout) { + array_insert_last(node_t *, fanoutvec, fanout); + } + /* see if collapse is good */ + /*-------------------------*/ + collapsed = xln_partial_collapse_node(network, node, cost_table, + init_param, &gain); + if (collapsed) { + + /* if node is collapsed, all the fanouts (& their fanins) + and fanins should be considered in the next iteration. */ + /*----------------------------------------------------------*/ + for (j = 0; j < array_n(fanoutvec); j++) { + fanout = array_fetch(node_t *, fanoutvec, j); + (void) st_insert(table_affected_nodes, node_long_name(fanout), + (char *) fanout); + foreach_fanin(fanout, k, fanin) { + if (fanin == node) continue; + (void) st_insert(table_affected_nodes, node_long_name(fanin), + (char *) fanin); + } + + } + foreach_fanin(node, j, fanin) { + (void) st_insert(table_affected_nodes, node_long_name(fanin), + (char *) fanin); + } + network_delete_node(network, node); + total_gain += gain; + } + array_free(fanoutvec); + } + array_free(nodevec); + + /* form an array of nodes to be tried for collapsing in the next iteration */ + /*-------------------------------------------------------------------------*/ + nodevec = array_alloc(node_t *, 0); + st_foreach_item(table_affected_nodes, stgen, &key, (char **) &node) { + if (node->type != INTERNAL) continue; + array_insert_last(node_t *, nodevec, node); + } + st_free_table(table_affected_nodes); + num = array_n(nodevec); + } /* while num */ + array_free(nodevec); + + if (XLN_DEBUG) + (void) printf("****gain in partial collapse is %d\n", total_gain); + + /* finally replace each node by its network */ + /*------------------------------------------*/ + assert(network_check(network)); + nodevec = network_dfs(network); + num = array_n(nodevec); + for (i = 0; i < num; i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + assert(st_lookup(cost_table, node_long_name(node), (char **) &network_node)); + assert(network_check(network_node)); + if (node_num_fanin(node) <= init_param->support) { + network_free(network_node); + continue; + } + /* trying to improve results by trying other decomposition options*/ + /*----------------------------------------------------------------*/ + xln_collapse_remap(node, &network_node, init_param); + pld_replace_node_by_network(node, network_node); + network_free(network_node); + } + /* free */ + /*------*/ + st_free_table(cost_table); + array_free(nodevec); +} + + +int +xln_cost_of_node(node, cost_table) + node_t *node; + st_table *cost_table; +{ + network_t *network_node; + + assert(st_lookup(cost_table, node_long_name(node), (char **) &network_node)); + if (network_node == NIL(network_t)) return 0; + return network_num_internal(network_node); +} + +/*----------------------------------------------------------------------------------------- + Checks if it is beneficial to collapse node into each of the fanouts. If so, does that + and returns 1 and the gain in pgain. Changes the cost_table entries of these fanouts + and deletes the entry of node. Else returns 0 and pgain is not assigned any values. +--------------------------------------------------------------------------------------------*/ +int +xln_partial_collapse_node(network, node, cost_table, init_param, pgain) + network_t *network; + node_t *node; + st_table *cost_table; + xln_init_param_t *init_param; + int *pgain; +{ + int gain, old_cost; + char *name, *name1, *dummy, *key; + network_t *network_fanout; + node_t *fanout, *fanout_simpl, *dup_fanout; + lsGen genfo; + st_generator *stgen; + st_table *fo_table; + array_t *fanout_array, *real_fanout_array; + int i, num_fanout, cost_node; + + fo_table = st_init_table(strcmp, st_strhash); + name = node_long_name(node); + assert(st_lookup(cost_table, name, &dummy)); + cost_node = network_num_internal((network_t *)dummy); + gain = cost_node; + + /* compute the gain if the node is collapsed into each of its + fanouts and is then removed from the network. The cost is stored in the + fo_table for each of the fanouts of the node */ + /*------------------------------------------------------------------------*/ + + /* for each fanout, recompute the cost */ + /*-------------------------------------*/ + real_fanout_array = array_alloc(node_t *, 0); + foreach_fanout(node, genfo, fanout) { + array_insert_last(node_t *, real_fanout_array, fanout); + } + num_fanout = array_n(real_fanout_array); + fanout_array = array_alloc(node_t *, 0); + for (i = 0; i < num_fanout; i++) { + fanout = array_fetch(node_t *, real_fanout_array, i); + dup_fanout = node_dup(fanout); + (void) node_collapse(dup_fanout, node); + fanout_simpl = node_simplify(dup_fanout, NIL(node_t), NODE_SIM_ESPRESSO); + /* + node_free(dup_fanout); + dup_fanout = fanout_simpl; + */ + node_replace(dup_fanout, fanout_simpl); + array_insert_last(node_t *, fanout_array, dup_fanout); + network_fanout = xln_best_script(dup_fanout, init_param); + if (XLN_DEBUG > 3) { + (void) printf("number of nodes of network for node %s = %d\n", node_long_name(fanout), + network_num_internal(network_fanout)); + } + name = node_long_name(dup_fanout); + assert(!st_insert(fo_table, name, (char *) network_fanout)); + assert(st_lookup(cost_table, name, &dummy)); + old_cost = network_num_internal((network_t *)dummy); + gain = gain + old_cost - network_num_internal(network_fanout); + } + if (gain <= 0) { + if (XLN_DEBUG > 3) { + (void) printf("could not collapse node, gain = %d", gain); + node_print(stdout, node); + (void) printf("num_fanin = %d, num_fanout = %d, cost = %d\n", + node_num_fanin(node), node_num_fanout(node), cost_node); + } + name = node_long_name(node); + xln_free_fo_table_without_freeing_key(fo_table); + for (i = 0; i < num_fanout; i++) { + dup_fanout = array_fetch(node_t *, fanout_array, i); + node_free(dup_fanout); + } + array_free(fanout_array); + array_free(real_fanout_array); + return 0; + } + if (XLN_DEBUG) { + (void) printf("------collapsed node, gain = %d ", gain); + node_print(stdout, node); + (void) printf("num_fanin = %d, num_fanout = %d, cost = %d\n", + node_num_fanin(node), node_num_fanout(node), cost_node); + st_foreach_item(fo_table, stgen, &key, (char **) &network_fanout) { + (void) printf("\t cost of fanout %s is %d\n", key, + network_num_internal(network_fanout)); + } + } + + for (i = 0; i < num_fanout; i++) { + dup_fanout = array_fetch(node_t *, fanout_array, i); + fanout = array_fetch(node_t *, real_fanout_array, i); + /* collapse node into fanout, update the cost_table entry */ + /*--------------------------------------------------------*/ + name1 = node_long_name(dup_fanout); + assert(st_delete(cost_table, &name1, &dummy)); + network_free((network_t *) dummy); + assert(st_lookup(fo_table, name1, (char **)&network_fanout)); + assert(!st_insert(cost_table, name1, (char *) network_fanout)); + (void) node_replace(fanout, dup_fanout); + if (XLN_DEBUG > 3) { + (void) printf("number of nodes of network for node %s = %d\n", name1, + network_num_internal(network_fanout)); + } + } /* foreach_fanout */ + array_free(fanout_array); + array_free(real_fanout_array); + st_free_table(fo_table); + /* delete the collapsed node from cost_table, network.*/ + /*----------------------------------------------------*/ + name1 = node_long_name(node); + assert(st_delete(cost_table, &name1, &dummy)); + network_free((network_t *) dummy); + *pgain = gain; + return 1; +} + +xln_free_fo_table_without_freeing_key(fo_table) + st_table *fo_table; +{ + st_generator *gen; + char *key; + network_t *network_node; + + st_foreach_item(fo_table, gen, &key, (char **) &network_node) { + network_free(network_node); + } + st_free_table(fo_table); +} + + +xln_collapse_remap(node, pnetwork, init_param) + node_t *node; + network_t **pnetwork; + xln_init_param_t *init_param; +{ + network_t *network2; + int flag_decomp_save; + + /* if this flag is GOOD, then all the mapping options have been tried */ + /*--------------------------------------------------------------------*/ + if (init_param->good_or_fast == GOOD) return; + + /* if the decomp flag was 2 (used both with and without good_decomp), + call xln_try_other_options. */ + /*-------------------------------------------------------------------*/ + if (init_param->flag_decomp_good == 2) { + xln_try_other_mapping_options(node, pnetwork, init_param); + return; + } + + flag_decomp_save = init_param->flag_decomp_good; + if (flag_decomp_save) { + init_param->flag_decomp_good = 0; + } else { + init_param->flag_decomp_good = 1; + } + network2 = xln_best_script(node, init_param); + if (network_num_internal(network2) < network_num_internal(*pnetwork)) { + network_free(*pnetwork); + *pnetwork = network2; + } else { + network_free(network2); + } + init_param->flag_decomp_good = flag_decomp_save; +} + +/*------------------------------------------------------------------ + Assumes that the pnetwork is feasible to begin with. +--------------------------------------------------------------------*/ +xln_collapse_check_area(pnetwork, init_param, roth_karp_flag) + network_t **pnetwork; + xln_init_param_t *init_param; + int roth_karp_flag; +{ + network_t *network1; + + network1 = xln_check_network_for_collapsing_area(*pnetwork, init_param, roth_karp_flag); + if (network1 == NIL(network_t)) return; + if (network_num_internal(*pnetwork) > network_num_internal(network1)) { + network_free(*pnetwork); + *pnetwork = network1; + } else { + network_free(network1); + } +} + + +/*--------------------------------------------------------------------------------- + If the network has small number of inputs, collapses the network. Then applies + Roth-Karp decomposition and cofactoring techniques on the network and evaluates + them. Returns the network with fewer nodes. Returns NIL if collapsing + could not be done. If roth_karp flag is 0, roth_karp decomposition is not done. +-----------------------------------------------------------------------------------*/ +network_t * +xln_check_network_for_collapsing_area(network, init_param, roth_karp_flag) + network_t *network; + xln_init_param_t *init_param; + int roth_karp_flag; +{ + network_t *network1, *network2; + + /* if support = 2, do not do anything */ + /*------------------------------------*/ + if (init_param->support == 2) return NIL (network_t); + + if (network_num_pi(network) > init_param->collapse_input_limit) return NIL (network_t); + + network1 = network_dup(network); + (void) network_collapse(network1); + if (roth_karp_flag) network2 = network_dup(network1); + + pld_simplify_network_without_dc(network1); + xln_cofactor_decomp_network(network1, init_param->support, AREA); + + /* karp_decomp_network simplifies each node */ + /*------------------------------------------*/ + if (roth_karp_flag) { + karp_decomp_network(network2, init_param->support, 0, NIL (node_t)); + assert(xln_is_network_feasible(network2, init_param->support)); + + if (network_num_internal(network1) < network_num_internal(network2)) { + network_free(network2); + return network1; + } + network_free(network1); + return network2; + } + return network1; +} + diff --git a/sis/pld/xln_cube.c b/sis/pld/xln_cube.c new file mode 100644 index 0000000..d1d3790 --- /dev/null +++ b/sis/pld/xln_cube.c @@ -0,0 +1,383 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_cube.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +node_t *xln_make_big_and(); +extern int XLN_DEBUG; + +/*---------------------------------------------------------------------- + Employs a bin-packing Best Fit Decreasing algorithm to decompose all + the nodes of the network to nodes with number of fanins at most size. +------------------------------------------------------------------------*/ +xln_network_ao_map(network, size) + network_t *network; + int size; +{ + array_t *nodevec; + int num, i; + node_t *node; + + nodevec = network_dfs(network); + num = array_n(nodevec); + for (i = 0; i < num; i++) { + node = array_fetch(node_t *, nodevec, i); + xln_node_ao_map(node, size); + } + array_free(nodevec); +} + +/*------------------------------------------------------------------------ + First maps cubes of the node with number of literals + greater than size to a CLB and after that does an BFD packing of the + cubes. Hopefully a similar algorithm would work for minimizing levels + also. +-------------------------------------------------------------------------*/ +xln_node_ao_map(node, size) + node_t *node; + int size; +{ + int num_cube, i, node_changed, cube_changed; + node_cube_t cube; + network_t *network; + + if (node->type != INTERNAL) return; + if (node_num_fanin(node) <= size) return; + + network = node->network; + node_changed = 1; + while (node_changed) { + node_changed = 0; + num_cube = node_num_cube(node); + for (i = 0; i < num_cube; i++) { + cube = node_get_cube(node, i); + cube_changed = xln_extract_big_ands_from_cube(network, node, cube, size); + node_changed = node_changed || cube_changed; + } + } + xln_ao_replace_node_with_tlus(network, node, size); +} + +/*------------------------------------------------------------------------ + Given a node and a cube in the node, extracts supercubes that have + at least size number of literals. This is done one supercube at a time. + The supercube is extracted, made a node in the network and also + substituted in the node. +-------------------------------------------------------------------------*/ +xln_extract_big_ands_from_cube(network, node, cube, size) + network_t *network; + node_t *node; + node_cube_t cube; + int size; +{ + array_t *one_array, *zero_array, *andvec; + int count, count1, count0, num_and, j, k; + node_t *fanin, *node_and; + node_literal_t literal; + + /* do not extract anything if the number of literals in the + cube is not higher than size. */ + /*---------------------------------------------------------*/ + if (pld_num_fanin_cube(cube, node) <= size) return 0; + + one_array = array_alloc(node_t *, 0); + zero_array = array_alloc(node_t *, 0); + andvec = array_alloc(node_t *, 0); + + count = 0; + count1 = 0; + count0 = 0; + foreach_fanin(node, j, fanin) { + literal = node_get_literal(cube, j); + switch(literal) { + case ONE: + array_insert(node_t *, one_array, count1, fanin); + count1++; + count++; + break; + case ZERO: + array_insert(node_t *, zero_array, count0, fanin); + count++; + count0++; + break; + case TWO: + break; + } + if (count == size) { + /* found a BIG AND */ + /*-----------------*/ + node_and = xln_make_big_and(one_array, zero_array, count1, count0); + array_insert_last(node_t *, andvec, node_and); + count = 0; + count1 = 0; + count0 = 0; + } + } + num_and = array_n(andvec); + if (num_and != 0) { + for (k = 0; k < num_and; k++) { + node_and = array_fetch(node_t *, andvec, k); + network_add_node(network, node_and); + node_substitute(node, node_and, 0); + } + array_free(one_array); + array_free(zero_array); + array_free(andvec); + /* xln_extract_big_ands_from_cube(network, node, pcube, size); */ + return 1; + } + else { + array_free(one_array); + array_free(zero_array); + array_free(andvec); + return 0; + /*NOTREACHED */ + } +} + +/*------------------------------------------------------------------------ + Given two arrays and the number of elements in them, returns a node + that is AND of the nodes in the two arrays. The phases of literals + is determined by which array the literal belongs to. one_array stores + uncomplemented literals. + ------------------------------------------------------------------------*/ +node_t * +xln_make_big_and(one_array, zero_array, num_one, num_zero) + array_t *one_array, *zero_array; + int num_one, num_zero; +{ + int i; + node_t *n, *n1, *n2, *fanin; + + n = node_constant(1); + for (i = 0; i < num_one; i++) { + fanin = array_fetch(node_t *, one_array, i); + n1 = node_literal(fanin, 1); + n2 = node_and(n, n1); + node_free(n1); + node_free(n); + n = n2; + } + for (i = 0; i < num_zero; i++) { + fanin = array_fetch(node_t *, zero_array, i); + n1 = node_literal(fanin, 0); + n2 = node_and(n, n1); + node_free(n1); + node_free(n); + n = n2; + } + return n; +} + + +/*--------------------------------------------------------------------- + Given a node, if the number of fanins is greater than size, replaces + it by table look up (tlu) blocks. +-----------------------------------------------------------------------*/ +xln_ao_replace_node_with_tlus(network, node, size) + network_t *network; + node_t *node; + int size; +{ + int xln_ao_compare(), num_cube, i, num_tlu, num_tlu1; + array_t *cubevec, *tluvec; + node_cube_t cube; + node_t *cube_node, *tlu, *tlu1, *prev_tlu; + + if (node_num_fanin(node) <= size) return; + + /* form nodes from all the cubes and store in cubevec */ + /*----------------------------------------------------*/ + num_cube = node_num_cube(node); + cubevec = array_alloc(node_t *, 0); + for (i = 0; i < num_cube; i++) { + cube = node_get_cube(node, i); + cube_node = pld_make_node_from_cube(node, cube); + array_insert_last(node_t *, cubevec, cube_node); + } + + /* making lookup tables (tlu's) now */ + /*----------------------------------*/ + tluvec = array_alloc(node_t *, 0); + while (array_n(cubevec) != 0) { + array_sort(cubevec, xln_ao_compare); + if (XLN_DEBUG > 3) { + (void) printf("---printing cube nodes for %s\n", node_long_name(node)); + num_cube = array_n(cubevec); + for (i = 0; i < num_cube; i++) { + cube_node = array_fetch(node_t *, cubevec, i); + (void) node_print_rhs(sisout, cube_node); + (void) printf("(fanins = %d) ", node_num_fanin(cube_node)); + } + (void) printf("\n\n"); + } + /* this makes tlu's and puts them in tluvec. Each tlu generates + a new single-literal cube which is put in cubevec */ + /*------------------------------------------------------------*/ + xln_make_tlus(network, node, &cubevec, &tluvec, size); + } + array_free(cubevec); + + /* now just make the first guy in tluvec a node, add it in the + network and continue propagating towards the end of tluvec */ + /*------------------------------------------------------------*/ + num_tlu = array_n(tluvec); + num_tlu1 = num_tlu - 1; + prev_tlu = node_constant(0); + for (i = 0; i < num_tlu; i++) { + tlu = array_fetch(node_t *, tluvec, i); + tlu1 = node_or(prev_tlu, tlu); + node_free(prev_tlu); + node_free(tlu); + if (i != num_tlu1) { + network_add_node(network, tlu1); + prev_tlu = node_literal(tlu1, 1); + } + else node_replace(node, tlu1); + } + array_free(tluvec); + +} + +/*----------------------------------------------------------------------- + Given some nodes as tlu's in tluvec (possibly empty), and nodes in + pcubevec which are to be realized as tlu's, pack the cubes. This is + a complicated implementation, consisting of two phases: + + 1) Each cube in pcubevec is checked to see if it can be implemented + by some tlu in ptluvec. If so, change + the function of that tlu appropriately (OR with the cube). Else, + generate a new tlu, put it in ptluvec. + + 2) After all cubes in pcubevec have been thus processed, the tlu's + in ptluvec are checked to see if some tlu has number of inputs + = size. If so, that tlu is added as a node in the network, it + generates a cube with single literal, which is then put in the + pcubevec. Such a tlu is deleted from the ptluvec, as it cannot + accomodate any more cubes (all the new sinle-literal cubes have + different fanin). +-------------------------------------------------------------------------*/ +int +xln_make_tlus(network, node, pcubevec, ptluvec, size) + network_t *network; + node_t *node; + array_t **pcubevec, **ptluvec; + int size; +{ + int num_tlu, num_cubevec, i, tlu_num, j; + array_t *cubevec, *tluvec, *newtluvec; + node_t *cube_node, *tlu, *tlu1; + + cubevec = *pcubevec; + tluvec = *ptluvec; + num_tlu = array_n(tluvec); + num_cubevec = array_n(cubevec); + + /* absorb cube_node either into already existing tlu's or make a new tlu */ + /*-----------------------------------------------------------------------*/ + for (i= 0; i < num_cubevec; i++) { + cube_node = array_fetch(node_t *, cubevec, i); + tlu_num = xln_is_cube_absorbed(cube_node, tluvec, size); + if (tlu_num < 0) { + array_insert_last(node_t *, tluvec, node_dup(cube_node)); + num_tlu++; + } + node_free(cube_node); + } + array_free(cubevec); + + /* now have a second pass over tlu's to absorb all "size"-input tlu's */ + /*--------------------------------------------------------------------*/ + array_sort(tluvec, xln_ao_compare); + cubevec = array_alloc(node_t *, 0); + if (num_tlu == 1) { + tlu = array_fetch(node_t *, tluvec, 0); + node_replace(node, tlu); + array_free(tluvec); + newtluvec = array_alloc(node_t *, 0); + *ptluvec = newtluvec; + } + else { + for (i = 0; i < num_tlu; i++) { + tlu = array_fetch(node_t *, tluvec, i); + if (node_num_fanin(tlu) < size) break; + network_add_node(network, tlu); + tlu1 = node_literal(tlu, 1); + array_insert_last(node_t *, cubevec, tlu1); + } + /* update the tlu list - no size input tlu's remain */ + /*--------------------------------------------------*/ + if (i != 0) { + newtluvec = array_alloc(node_t *, 0); + for ( j = i; j < num_tlu; j++) { + tlu = array_fetch(node_t *, tluvec, j); + array_insert_last(node_t *, newtluvec, tlu); + } + array_free(tluvec); + *ptluvec = newtluvec; + } + } + *pcubevec = cubevec; +} + +int +xln_ao_compare(pn1, pn2) + node_t **pn1, **pn2; +{ + int num1, num2; + + num1 = node_num_fanin(*pn1); + num2 = node_num_fanin(*pn2); + if (num1 > num2) return -1; + if (num1 == num2) return 0; + return 1; +} + +/*--------------------------------------------------------------------- + If the cube_node is mergeable with previous tlu's, do so and return + the array location of tlu with which it was absorbed. Find the best + fit (that is the tlu in which the num_composite_fanin is minimum). + Else return -1. tluvec has all the tlu's generated so far. +-----------------------------------------------------------------------*/ +int +xln_is_cube_absorbed(cube_node, tluvec, size) + node_t *cube_node; + array_t *tluvec; + int size; +{ + int num, j, tlu_num, num_composite_fanin, best_num_composite_fanin; + node_t *tlu, *new_tlu; + + tlu_num = -1; + best_num_composite_fanin = MAXINT; + + /* get the best tlu that can absorb cube_node */ + /*--------------------------------------------*/ + num = array_n(tluvec); + for (j = 0; j < num; j++) { + tlu = array_fetch(node_t *, tluvec, j); + num_composite_fanin = xln_num_composite_fanin(cube_node, tlu); + if (num_composite_fanin <= size) { + if (num_composite_fanin < best_num_composite_fanin) { + best_num_composite_fanin = num_composite_fanin; + tlu_num = j; + } + } + } + if (tlu_num < 0) return tlu_num; + /* found a good tlu: merge the cube_node with it */ + /*-----------------------------------------------*/ + tlu = array_fetch(node_t *, tluvec, tlu_num); + new_tlu = node_or(cube_node, tlu); + node_free(tlu); + array_insert(node_t *, tluvec, tlu_num, new_tlu); + return tlu_num; +} + diff --git a/sis/pld/xln_dec_merge.c b/sis/pld/xln_dec_merge.c new file mode 100644 index 0000000..91c1968 --- /dev/null +++ b/sis/pld/xln_dec_merge.c @@ -0,0 +1,662 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_dec_merge.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/*--------------------------------------------------------------------- + Find pairs of nodes for extracting mergeable nodes. This is done as + follows: first infeasible nodes are collected. Then, for each of + the pairs of nodes, finds the affinity between the nodes. Greedily + selects the best pairs and generates mergeable functions. +-----------------------------------------------------------------------*/ +xln_decomp_for_merging_network(network, init_param) + network_t *network; + xln_init_param_t *init_param; +{ + array_t *nodevec; + + /* make an array of internal infeasible nodes */ + /*--------------------------------------------*/ + nodevec = xln_infeasible_nodes(network, init_param->support); + + /* depending on the heuristic, decide if you wish to do an + all-cube approach or a pair of node approach. */ + /*--------------------------------------------------------*/ + if (init_param->heuristic == ALL_CUBES) { + xln_decomp_for_merging_ALL_CUBES(nodevec, init_param); + } else { + xln_decomp_for_merging_PAIR_NODES(nodevec, init_param); + } + (void) network_sweep(network); + array_free(nodevec); +} + +xln_decomp_for_merging_ALL_CUBES(nodevec, init_param) + array_t *nodevec; + xln_init_param_t *init_param; +{ + array_t *cube_node_vec; + st_table *cubenode2node_table; + st_table *node2cubenode_table; + + /* table stores for a cube_node, the node from which it was extracted */ + /*--------------------------------------------------------------------*/ + cubenode2node_table = st_init_table(st_ptrcmp, st_ptrhash); + node2cubenode_table = st_init_table(st_ptrcmp, st_ptrhash); + + cube_node_vec = xln_fill_tables(cubenode2node_table, node2cubenode_table, + nodevec, init_param); + xln_decomp_for_merge_cube_nodes(cube_node_vec, cubenode2node_table, + node2cubenode_table, init_param); + + xln_free_cube_nodes(cube_node_vec); + array_free(cube_node_vec); + xln_free_node2cubenode_table(node2cubenode_table); + st_free_table(cubenode2node_table); +} + + +xln_decomp_for_merging_PAIR_NODES(nodevec, init_param) + array_t *nodevec; + xln_init_param_t *init_param; +{ + array_t *affinity_vec; + array_t *matched_vec; + st_table *table1, *table2; + int i, j; + node_t *node1, *node2; + AFFINITY_STRUCT *affinity_struct; + + /* find affinity (number of common inputs) for each pair of + nodes in nodevec */ + /*---------------------------------------------------------------*/ + affinity_vec = array_alloc(AFFINITY_STRUCT *, 0); + for (i = 0; i < array_n(nodevec); i++) { + node1 = array_fetch(node_t *, nodevec, i); + for (j = i + 1; j < array_n(nodevec); j++) { + node2 = array_fetch(node_t *, nodevec, j); + affinity_struct = ALLOC(AFFINITY_STRUCT, 1); + affinity_struct->node1 = node1; + affinity_struct->node2 = node2; + affinity_struct->common = xln_node_find_common_inputs(node1, node2); + array_insert_last(AFFINITY_STRUCT *, affinity_vec, affinity_struct); + } + } + array_sort(affinity_vec, pld_affinity_compare_function); + + /* store the matched-cubes in matched_vec, table1, table2 */ + /*--------------------------------------------------------*/ + matched_vec = array_alloc(AFFINITY_STRUCT *, 0); + table1 = st_init_table(st_ptrcmp, st_ptrhash); + table2 = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 0; i < array_n(affinity_vec); i++) { + affinity_struct = array_fetch(AFFINITY_STRUCT *, affinity_vec, i); + node1 = affinity_struct->node1; + node2 = affinity_struct->node2; + + /* check for already matched up cube either from node1 or node2*/ + /*-------------------------------------------------------------*/ + if ((st_is_member(table1, (char *) node1)) || + (st_is_member(table2, (char *) node2))) { + xln_free_AFFINITY_STRUCT(affinity_struct); + continue; + } + assert(!st_insert(table1, (char *) node1, (char *) node1)); + assert(!st_insert(table2, (char *) node2, (char *) node2)); + array_insert_last(AFFINITY_STRUCT *, matched_vec, affinity_struct); + } + array_free(affinity_vec); + st_free_table(table1); + st_free_table(table2); + + /* for each of the pairs, find mergeable functions, extract + them. Change the nodes. */ + /*----------------------------------------------------------*/ + for (i = 0; i < array_n(matched_vec); i++) { + affinity_struct = array_fetch(AFFINITY_STRUCT *, matched_vec, i); + /* assert(network_check(network)); */ + xln_decomp_for_merge_pair_of_nodes(affinity_struct->node1, + affinity_struct->node2, init_param); + xln_free_AFFINITY_STRUCT(affinity_struct); + } + /* assert(network_check(network)); */ + array_free(matched_vec); +} + +/*----------------------------------------------------------------------------- + Given two infeasible nodes n1 & n2, pair up cubes which have good chances of + generating good mergeable functions. This is done by simply finding the + number of common inputs to the two cubes. Then for these pairs, generate + mergeable functions. Make these the nodes of the network. The + cover-merge or merge routine will hopefully merge these nodes. +------------------------------------------------------------------------------*/ +xln_decomp_for_merge_pair_of_nodes(n1, n2, init_param) + node_t *n1, *n2; + xln_init_param_t *init_param; +{ + array_t *cube_node_vec; + array_t *nodevec; + st_table *cubenode2node_table; + st_table *node2cubenode_table; + + /* table stores for a cube_node, the node from which it was extracted */ + /*--------------------------------------------------------------------*/ + cubenode2node_table = st_init_table(st_ptrcmp, st_ptrhash); + node2cubenode_table = st_init_table(st_ptrcmp, st_ptrhash); + + nodevec = array_alloc(node_t *, 0); + array_insert_last(node_t *, nodevec, n1); + array_insert_last(node_t *, nodevec, n2); + + cube_node_vec = xln_fill_tables(cubenode2node_table, node2cubenode_table, nodevec, + init_param); + xln_decomp_for_merge_cube_nodes(cube_node_vec, cubenode2node_table, + node2cubenode_table, init_param); + + xln_free_cube_nodes(cube_node_vec); + array_free(cube_node_vec); + array_free(nodevec); + xln_free_node2cubenode_table(node2cubenode_table); + st_free_table(cubenode2node_table); +} + +/*------------------------------------------------------------------------------- + Given an array of cube_nodes (cube_node_vec) and the nodes of the network to + which they belong (in the table cubenode2node_table), pair up the cube_nodes + and extract mergeable functions. +--------------------------------------------------------------------------------*/ + +xln_decomp_for_merge_cube_nodes(cube_node_vec, cubenode2node_table, + node2cubenode_table, init_param) + array_t *cube_node_vec; + st_table *cubenode2node_table, *node2cubenode_table; + xln_init_param_t *init_param; +{ + array_t *affinity_vec; + int i, j; + node_t *cube_node1, *cube_node2; + node_t *n1, *n2; /* nodes of the network to which cube_node1 + and cube_node2 belong */ + AFFINITY_STRUCT *affinity_struct; + st_table *table; + array_t *common; + + /* set up the affinity between all pairs of cube_nodes */ + /*-----------------------------------------------------*/ + affinity_vec = array_alloc(AFFINITY_STRUCT *, 0); + for (i = 0; i < array_n(cube_node_vec); i++) { + cube_node1 = array_fetch(node_t *, cube_node_vec, i); + for (j = i + 1; j < array_n(cube_node_vec); j++) { + cube_node2 = array_fetch(node_t *, cube_node_vec, j); + + /* if the two cubes belong to the same node and have number of + total inputs <= init_param->support, do not pair them together. + They can anyway be realized in one CLB (by bin-packing) */ + /*---------------------------------------------------------------*/ + assert(st_lookup(cubenode2node_table, (char *) cube_node1, (char **) &n1)); + assert(st_lookup(cubenode2node_table, (char *) cube_node2, (char **) &n2)); + if ((n1 == n2) && + (xln_num_composite_fanin(cube_node1, cube_node2) <= init_param->support) + ) continue; + + /* find the set of inputs common to two sub_cubes. If the number is + lower than a limit, ignore the pair */ + /*---------------------------------------------------------------*/ + common = xln_node_find_common_inputs(cube_node1, cube_node2); + if (array_n(common) < init_param->common_lower_bound) { + array_free(common); + continue; + } + affinity_struct = ALLOC(AFFINITY_STRUCT, 1); + affinity_struct->node1 = cube_node1; + affinity_struct->node2 = cube_node2; + affinity_struct->common = common; + array_insert_last(AFFINITY_STRUCT *, affinity_vec, affinity_struct); + } + } + /* pair up the cubes to maximize the total affinity. This is done by greedily + selecting the cube-pairs with maximum affinity. Care is taken not to + repeat the cubes already matched up earlier in the process. */ + /*--------------------------------------------------------------------------*/ + array_sort(affinity_vec, pld_affinity_compare_function); + + /* store the matched-cubes in table */ + /*----------------------------------*/ + + table = st_init_table(st_ptrcmp, st_ptrhash); + + for (i = 0; i < array_n(affinity_vec); i++) { + affinity_struct = array_fetch(AFFINITY_STRUCT *, affinity_vec, i); + cube_node1 = affinity_struct->node1; + cube_node2 = affinity_struct->node2; + + /* check for already matched up cube either from node1 or node2*/ + /*-------------------------------------------------------------*/ + if ((st_is_member(table, (char *) cube_node1)) || + (st_is_member(table, (char *) cube_node2))) { + xln_free_AFFINITY_STRUCT(affinity_struct); + continue; + } + assert(st_lookup(cubenode2node_table, (char *) cube_node1, (char **) &n1)); + assert(st_lookup(cubenode2node_table, (char *) cube_node2, (char **) &n2)); + assert(network_check(n1->network)); + assert(!st_insert(table, (char *) cube_node1, (char *) cube_node1)); + assert(!st_insert(table, (char *) cube_node2, (char *) cube_node2)); + + /* extract mergeable functions from the nodes n1 & n2 with + cubes in affinity_struct. May consume other cubes also. */ + /*---------------------------------------------------------*/ + xln_extract_mergeable_fns_from_cubes(n1, n2, affinity_struct, table, + node2cubenode_table, init_param); + xln_free_AFFINITY_STRUCT(affinity_struct); + } + array_free(affinity_vec); + st_free_table(table); +} + +array_t * +xln_node_find_common_inputs(node1, node2) + node_t *node1, *node2; +{ + array_t *common_fanins; + int j; + node_t *fanin; + + common_fanins = array_alloc(node_t *, 0); + foreach_fanin(node1, j, fanin) { + if (node_get_fanin_index(node2, fanin) >= 0) { + array_insert_last(node_t *, common_fanins, fanin); + } + } + return common_fanins; +} + +/*--------------------------------------------------------------------------- + Given two cubes (in the form of node1 & node2 in affinity_struct), extract + more nodes out of them based on the mergeability cost function. + The information about common inputs is present in affinity_struct. + At each step, a subset of common inputs is selected that is the largest + possible (limited by init_param->common_inputs). Corresponding literals + are extracted from the nodes as new nodes and substituted in n1 (or n2). + Some other literals may be put in the new nodes subject to the max inputs + and union information along with these new nodes. +----------------------------------------------------------------------------*/ +xln_extract_mergeable_fns_from_cubes(n1, n2, affinity_struct, table, + node2cubenode_table, init_param) + node_t *n1, *n2; + AFFINITY_STRUCT *affinity_struct; + st_table *table, *node2cubenode_table; + xln_init_param_t *init_param; +{ + int common_ptr; /* points to the array location from where the next + common fanin will be chosen */ + node_t *node1; /* affinity_struct->node1 */ + node_t *node2; /* affinity_struct->node2 */ + array_t *common; /* common fanins of node1 and node2 */ + array_t *subset_common; + /* subset of common */ + array_t *nc1; /* array storing the fanins of node1 not in common*/ + array_t *nc2; /* array storing the fanins of node2 not in common*/ + int nc1_ptr; /* points to that nc1 entry from where a fanin + may be selected to be put in the extracted node */ + int nc2_ptr; /* points to that nc2 entry from where a fanin + may be selected to be put in the extracted node */ + int j, num_subset_common, temp, temp1, temp2; + int fanin_bound_more1, fanin_bound_more2, bound_union_more, lower, remember; + node_t *fanin, *sub_node1, *sub_node2; + + node1 = affinity_struct->node1; + node2 = affinity_struct->node2; + common = affinity_struct->common; + + /* get the non-common fanins of node1 and node2 */ + /*----------------------------------------------*/ + nc1 = pld_get_non_common_fanins(node1, common); + nc2 = pld_get_non_common_fanins(node2, common); + nc1_ptr = nc2_ptr = 0; + + common_ptr = 0; + while (common_ptr < array_n(common)) { + + /* get as many common fanins as allowed by MAX_COMMON_FANIN and common array */ + /*---------------------------------------------------------------------------*/ + subset_common = array_alloc(node_t *, 0); + for (j = 0; (j < init_param->MAX_COMMON_FANIN && common_ptr < array_n(common)); + j++, common_ptr++) { + fanin = array_fetch(node_t *, common, common_ptr); + array_insert_last(node_t *, subset_common, fanin); + } + + /* extract node corresponding to the subset_common */ + /*-------------------------------------------------*/ + sub_node1 = xln_extract_supercube_from_cube(node1, subset_common); + sub_node2 = xln_extract_supercube_from_cube(node2, subset_common); + num_subset_common = array_n(subset_common); + + /* find bounds on "number of more fanins permissible" because + of the MAX_FANIN constraint. */ + /*-----------------------------------------------------------*/ + temp = init_param->MAX_FANIN - num_subset_common; + if (temp > 0) { + fanin_bound_more1 = fanin_bound_more2 = temp; + } else { + fanin_bound_more1 = fanin_bound_more2 = 0; + } + + /* make these bounds tighter based on the number of REMAINING fanins + not in the common fanins */ + /*------------------------------------------------------------------*/ + temp1 = array_n(nc1) - nc1_ptr; + temp2 = array_n(nc2) - nc2_ptr; + + /* checks */ + /*--------*/ + assert(temp1 >= 0); + assert(temp2 >= 0); + + fanin_bound_more1 = min(fanin_bound_more1, temp1); + fanin_bound_more2 = min(fanin_bound_more2, temp2); + + /* find bound based on the MAX_UNION_FANIN constraint */ + /*----------------------------------------------------*/ + bound_union_more = init_param->MAX_UNION_FANIN - num_subset_common; + + /* compare the bounds and make them tight appropriately */ + /*------------------------------------------------------*/ + if (bound_union_more < fanin_bound_more1 + fanin_bound_more2) { + if (fanin_bound_more1 < fanin_bound_more2) { + lower = fanin_bound_more1; + remember = 1; + } else { + lower = fanin_bound_more2; + remember = 2; + } + if (lower >= bound_union_more) { + fanin_bound_more1 = bound_union_more / 2; + fanin_bound_more2 = bound_union_more - fanin_bound_more1; + } else { + if (remember == 1) { + fanin_bound_more2 = + min(bound_union_more - fanin_bound_more1, fanin_bound_more2); + } else { + fanin_bound_more1 = + min(bound_union_more - fanin_bound_more2, fanin_bound_more1); + } + } + } + + /* change the sub_node1 and sub_node2 (add more literals) */ + /*--------------------------------------------------------*/ + xln_add_more_literals(&sub_node1, node1, fanin_bound_more1, nc1, nc1_ptr); + xln_add_more_literals(&sub_node2, node2, fanin_bound_more2, nc2, nc2_ptr); + nc1_ptr += fanin_bound_more1; + nc2_ptr += fanin_bound_more2; + + /* try to cover other cubes from the function into sub_node1 */ + /*-----------------------------------------------------------*/ + xln_add_more_cubes(&sub_node1, node1, n1, node2cubenode_table, table); + xln_add_more_cubes(&sub_node2, node2, n2, node2cubenode_table, table); + + /* put the new nodes in the network */ + /*----------------------------------*/ + network_add_node(n1->network, sub_node1); + network_add_node(n1->network, sub_node2); + if (XLN_DEBUG) { + (void) printf("---added the following pair---\n"); + node_print(stdout, sub_node1); + node_print(stdout, sub_node2); + } + assert(network_check(n1->network)); + + /* returns void since it may happen that some earlier sub_node + that contained all the literals of sub_node1 (sub_node2) got + substituted in n1 (n2). */ + /*-------------------------------------------------------------*/ + (void) node_substitute(n1, sub_node1, 0); + (void) node_substitute(n2, sub_node2, 0); + array_free(subset_common); + } + array_free(nc2); + array_free(nc1); +} + +/*-------------------------------------------------------------------------- + Given a node having just 1 cube, and a subset of its fanins, smooths + away all the inputs not present in the subset and returns the resulting + node. Node does not change. +---------------------------------------------------------------------------*/ +node_t * +xln_extract_supercube_from_cube(node, subset_common) + node_t *node; + array_t *subset_common; +{ + node_t *n, *n1, *n2, *fanin; + int i; + input_phase_t phase; + + n = node_constant(1); + for (i = 0; i < array_n(subset_common); i++) { + fanin = array_fetch(node_t *, subset_common, i); + phase = node_input_phase(node, fanin); + switch (phase) { + case POS_UNATE: + n1 = node_literal(fanin, 1); + break; + case NEG_UNATE: + n1 = node_literal(fanin, 0); + break; + default: + assert(0); + } + n2 = node_and(n, n1); + node_free(n); + node_free(n1); + n = n2; + } + return n; +} + +/*-------------------------------------------------------------------------- + Adds more literals to the node psub_node. These literals are from the + node n. The literals to be added correspond to the fanins at nc[*pnc_ptr] + to nc[*pnc_ptr + fanin_bound_more - 1]. The phases of these literals are + the phases in the node. +---------------------------------------------------------------------------*/ +xln_add_more_literals(psub_node, node, fanin_bound_more, nc, nc_ptr) + node_t **psub_node, *node; + int fanin_bound_more; + array_t *nc; + int nc_ptr; +{ + int final, i; + node_t *fanin, *n1, *n2; + input_phase_t phase; + + final = nc_ptr + fanin_bound_more; + for (i = nc_ptr; i < final; i++) { + fanin = array_fetch(node_t *, nc, i); + phase = node_input_phase(node, fanin); + switch (phase) { + case POS_UNATE: + n1 = node_literal(fanin, 1); + break; + case NEG_UNATE: + n1 = node_literal(fanin, 0); + break; + default: + assert(0); + } + n2 = node_and(n1, *psub_node); + node_free(n1); + node_free(*psub_node); + *psub_node = n2; + } +} + +xln_free_AFFINITY_STRUCT(affinity_struct) + AFFINITY_STRUCT *affinity_struct; +{ + array_free(affinity_struct->common); + FREE(affinity_struct); +} + +/*---------------------------------------------------------- + Sorting in decreasing order of common fanins. +-----------------------------------------------------------*/ +int +pld_affinity_compare_function(p1, p2) + AFFINITY_STRUCT **p1, **p2; +{ + int num1, num2; + + num1 = array_n((*p1)->common); + num2 = array_n((*p2)->common); + if (num1 > num2) return (-1); + if (num1 < num2) return 1; + return 0; +} + +/*---------------------------------------------------------------- + Given a network, returns an array of infeasible internal nodes, + i.e., the ones with fanin higher than support. +-----------------------------------------------------------------*/ +array_t * +xln_infeasible_nodes(network, support) + network_t *network; + int support; +{ + array_t *nodevec; + lsGen gen; + node_t *node; + + /* make an array of internal infeasible nodes */ + /*--------------------------------------------*/ + nodevec = array_alloc(node_t *, 0); + foreach_node(network, gen, node) { + if (node->type != INTERNAL) continue; + if (node_num_fanin(node) <= support) continue; + array_insert_last(node_t *, nodevec, node); + } + return nodevec; +} + +/*----------------------------------------------------------------------- + Given a set of nodes in the nodevec (from the network). For each node + in nodevec, generate all cubes, and for each cube, make a node from + it (the node has the same function as the cube) and store it in the + cube_node_vec (if the number of inputs of the node is larger than + init_param->cube_support_lower_limit, and establish a correspondence + from it to the node in the cubenode2node_table. Returns cube_node_vec. +------------------------------------------------------------------------*/ +array_t * +xln_fill_tables(cubenode2node_table, node2cubenode_table, nodevec, init_param) + st_table *cubenode2node_table, *node2cubenode_table; + array_t *nodevec; + xln_init_param_t *init_param; +{ + array_t *cube_node_vec; + array_t *cubevec; + node_t *node, *cube_node; + node_cube_t cube; + int i, j; + + cube_node_vec = array_alloc(node_t *, 0); + + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + cubevec = array_alloc(node_t *, 0); + for (j = node_num_cube(node) - 1; j >= 0; j--) { + cube = node_get_cube(node, j); + cube_node = pld_make_node_from_cube(node, cube); + array_insert_last(node_t *, cubevec, cube_node); + if (node_num_fanin(cube_node) < init_param->cube_support_lower_bound) + continue; + array_insert_last(node_t *, cube_node_vec, cube_node); + assert(!st_insert(cubenode2node_table, (char *) cube_node, (char *) node)); + } + assert(!st_insert(node2cubenode_table, (char *) node, (char *) cubevec)); + } + return cube_node_vec; +} + + +xln_free_cube_nodes(cube_node_vec) + array_t *cube_node_vec; +{ + int i; + node_t *cube_node; + + for (i = 0; i < array_n(cube_node_vec); i++) { + cube_node = array_fetch(node_t *, cube_node_vec, i); + /* just checking */ + /*---------------*/ + assert(cube_node->network == NIL (network_t)); + node_free(cube_node); + } +} + +/*------------------------------------------------------------------------- + Given a sub_cube (psub_node) of the cube_node (which is a cube of the + node n), see if psub_node can "consume" other cubes of the "original" + node n: this just means that if there is a cube in the original cover + of the node whose set of inputs is a subset of the inputs of this node, + OR the function of the psub_node with that cube. + A condition to be satisfied is that the cube should be the same as cube + cube_node: i.e., psubnode has the same function as the cube_node. +---------------------------------------------------------------------------*/ +xln_add_more_cubes(psub_node, cube_node, n, + node2cubenode_table, table) + node_t **psub_node, *cube_node, *n; + st_table *node2cubenode_table, *table; +{ + node_t *sub_node, *sub_node1, *cube; + int nin_sub_node, nin_cube_node, i; + array_t *cubenode_vec; + int is_fanin_subset; + + sub_node = *psub_node; + nin_sub_node = node_num_fanin(sub_node); + nin_cube_node = node_num_fanin(cube_node); + if (nin_sub_node < nin_cube_node) return; + + assert(nin_sub_node == nin_cube_node); + assert(st_lookup(node2cubenode_table, (char *) n, (char **) &cubenode_vec)); + for (i = 0; i < array_n(cubenode_vec); i++) { + cube = array_fetch(node_t *, cubenode_vec, i); + + /* the next check takes care of the cube_node and the other + cube_node with which it is being matched. */ + /*---------------------------------------------------------*/ + if (st_is_member(table, (char *) cube)) continue; + is_fanin_subset = pld_is_fanin_subset(cube, sub_node); + if (is_fanin_subset) { + sub_node1 = node_or(sub_node, cube); + node_free(sub_node); + sub_node = sub_node1; + assert(!st_insert(table, (char *) cube, (char *) cube)); + } + } + *psub_node = sub_node; +} + + +xln_free_node2cubenode_table(node2cubenode_table) + st_table *node2cubenode_table; +{ + char *key; + st_generator *stgen; + array_t *cubevec; + + st_foreach_item(node2cubenode_table, stgen, &key, (char **) &cubevec) { + array_free(cubevec); + } + st_free_table(node2cubenode_table); +} diff --git a/sis/pld/xln_feasible.c b/sis/pld/xln_feasible.c new file mode 100644 index 0000000..be6c75f --- /dev/null +++ b/sis/pld/xln_feasible.c @@ -0,0 +1,265 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_feasible.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ + +#include "sis.h" +#include "pld_int.h" + +/*--------------------------------------------------------------------------- + This file carries routines that could make a non-feasible node feasible + without increasing the number of nodes in the network. This is done by + looking at a non-feasible node n, then trying to remove one of the fanins f + of the node, by making f a fanin of node g (that is a fanin of node n) + that is feasible and has some vacancy in it. This is done by collapsing g + into n, then look for a decomposition (roth-karp) with bound set that includes + {fanins of g different from the ones of n} U {f}. If number of equivalence + classes is 2, you can do it!!! + Hopefully, this routine will be useful for "critical" nodes, i.e., + with m + 1 inputs for CLB of m inputs. In this file, it is done for each + infeasible node till it becomes feasible, or we run out of its fanins. + + Notes: + + 1) Difference with Fujita's work: Here, we are changing the function of + some other node of the network (g) too apart from n. Fujita just re-expresses + n in terms of some other transitive fanins. The two methods are essentially + non-overlapping and hence there should be cases covered in one, not covered by + the other. + + 2) Partial collapse does similar stuff but this is a special case, and + cube-packing may not be able to detect such a case. + + 3) We are restricting ourselves by looking at only disjoint decomposition. + + 4) Of course, we are ignoring the possibility of collapsing some other node + into g later. Difficult to take into account. +-------------------------------------------------------------------------------*/ + +xln_network_reduce_infeasibility_by_moving_fanins(network, support, MAX_FANINS) + network_t *network; + int support; + int MAX_FANINS; /* do not move fanins if number of fanins of node exceeds this */ +{ + array_t *nodevec; + int i; + node_t *node; + + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + (void) + xln_node_move_fanins(node, support, MAX_FANINS, 0); /* 0 => make it feasible */ + } + array_free(nodevec); +} + +int +xln_node_move_fanins(node, support, MAX_FANINS, diff) + node_t *node; + int support, MAX_FANINS; + int diff; /* if 0, then from infeasible to feasible, else just moving fanins as + much as diff wants */ +{ + int infeasibility; + int improvement; + int i, j, num_fanin; + node_t *fanin, *f; + array_t *faninvec; + int bound_alphas; + + bound_alphas = 1; /* for area */ + + if (node->type != INTERNAL) return 0; + num_fanin = node_num_fanin(node); + + if (num_fanin > MAX_FANINS) return 0; + if (diff == 0) { + infeasibility = num_fanin - support; + if (infeasibility <= 0) return 0; + } else { + infeasibility = diff; + } + + /* make an array of fanin nodes */ + /*------------------------------*/ + faninvec = array_alloc(node_t *, 0); + foreach_fanin(node, j, fanin) { + array_insert_last(node_t *, faninvec, fanin); + } + /* try each f in faninvec for decreasing infeasibility */ + /*-----------------------------------------------------*/ + improvement = 0; + for (i = 0; i < array_n(faninvec); i++) { + f = array_fetch(node_t *, faninvec, i); + improvement += xln_node_move_fanin(node, f, support, bound_alphas, AREA); + if (improvement == infeasibility) break; + } + array_free(faninvec); + return improvement; +} + +/*------------------------------------------------------------------- + Returns 1 if the fanin f of an infeasible node can be removed to + one of the other fanins g. This decreases "infeasibility of the + node by 1. Moves the f fanin. Right now, bound alphas can only + be 1. Also, if DELAY mode, then do not select a critical node as g. +--------------------------------------------------------------------*/ +int +xln_node_move_fanin(node, f, support, bound_alphas, mode) + node_t *node, *f; + int support; + int bound_alphas; + float mode; +{ + array_t *faninvec; + node_t *g; + int j, i; + node_t *dup_node, *n, *node_simpl; + array_t *Y; + int *lambda_indices; + array_t *nodevec; + + assert(bound_alphas == 1); + /* get feasible internal fanins of node with vacant spot */ + /*-------------------------------------------------------*/ + faninvec = array_alloc(node_t *, 0); + foreach_fanin(node, j, g) { + if (g == f) continue; + if (g->type == PRIMARY_INPUT) continue; + if ((node_num_fanout(g) == 1) && (node_num_fanin(g) < support)) { + /* in DELAY mode, do not want a critical g */ + /*-----------------------------------------*/ + if (mode == DELAY) { + if (xln_is_node_critical(g, (double) 0)) continue; + } + array_insert_last(node_t *, faninvec, g); + } + } + + /* try collapsing each of the faninvec nodes g into node and + redecomposing. */ + /*----------------------------------------------------------*/ + for (i = 0; i < array_n(faninvec); i++) { + dup_node = node_dup(node); + FREE(dup_node->name); + FREE(dup_node->short_name); + network_add_node(node->network, dup_node); /* to make roth-karp decomp work */ + g = array_fetch(node_t *, faninvec, i); + assert(node_collapse(dup_node, g)); + node_simpl = node_simplify(dup_node, (node_t *) NULL, NODE_SIM_ESPRESSO); /* Added Jul 1, 93 */ + node_replace(dup_node, node_simpl); + if (XLN_DEBUG) { + (void) printf("----------------------------------------\n"); + (void) printf("dup_node after collapse = "); + node_print(sisout, dup_node); + (void) printf("\n"); + } + + /* passing dup_node to xln_get_bound_Set, since it may happen that a + node that was a fanin to g is not a fanin to dup_node. Now make sure + that only those fanins of g are inserted in Y that are actually fanins + of dup_node also -- April 23 1992 */ + /*---------------------------------------------------------------------*/ + Y = xln_get_bound_set(node, f, g, dup_node); /* node, not dup_node */ + if (array_n(Y) <= 1) { + array_free(Y); + network_delete_node(dup_node->network, dup_node); + continue; + } + lambda_indices = xln_array_to_indices(Y, dup_node); + /* try out this partition for decomposition */ + /*------------------------------------------*/ + nodevec = xln_k_decomp_node_with_array(dup_node, lambda_indices, + array_n(Y), bound_alphas); + FREE(lambda_indices); + array_free(Y); + network_delete_node(dup_node->network, dup_node); + if (nodevec == NIL (array_t)) { + continue; + } + assert(array_n(nodevec) <= (bound_alphas + 1)); + if (XLN_DEBUG) { + (void) printf("node = "); + node_print(sisout, node); + (void) printf("\n"); + (void) printf("f = "); + node_print(sisout, f); + (void) printf("\n"); + (void) printf("g = "); + node_print(sisout, g); + (void) printf("\n"); + (void) printf("--------\n"); + } + n = array_fetch(node_t *, nodevec, 0); + if (XLN_DEBUG) { + (void) printf("root node after decomp = "); + node_print_rhs(sisout, n); + (void) printf("\n"); + } + node_replace(node, n); + if (XLN_DEBUG) { + (void) printf("root node after replace = "); + node_print(sisout, node); + (void) printf("\n"); + } + n = array_fetch(node_t *, nodevec, 1); + if (XLN_DEBUG) { + (void) printf("g node after decomp = "); + node_print_rhs(sisout, n); + (void) printf("\n"); + } + node_patch_fanin(node, n, g); + node_replace(g, n); + if (XLN_DEBUG) { + (void) printf("g node after replace = "); + node_print(sisout, g); + (void) printf("\n"); + } + array_free(nodevec); + array_free(faninvec); + return 1; + } + array_free(faninvec); + return 0; +} + +/*----------------------------------------------------------------- + Add all those fanins of g into Y that aren't fanins of + the node, but should be fanins of dup_node. + Do add f in Y. Here, Y is the bound set to be used in + roth-karp decomposition. +-------------------------------------------------------------------*/ +array_t * +xln_get_bound_set(node, f, g, dup_node) + node_t *node, *f, *g, *dup_node; +{ + array_t *Y; + int j; + node_t *fanin; + + Y = array_alloc(node_t *, 0); + array_insert_last(node_t *, Y, f); + foreach_fanin(g, j , fanin) { + if (node_get_fanin_index(node, fanin) < 0) { + if (node_get_fanin_index(dup_node, fanin) >= 0) { + array_insert_last(node_t *, Y, fanin); + } else { + if (XLN_DEBUG) { + (void) printf("a fanin of g does not fanout to dup_node\n"); + } + } + } else { + if (XLN_DEBUG) { + (void) printf("there is a common fanin\n"); + } + } + } + return Y; +} + diff --git a/sis/pld/xln_filter.c b/sis/pld/xln_filter.c new file mode 100644 index 0000000..670b681 --- /dev/null +++ b/sis/pld/xln_filter.c @@ -0,0 +1,349 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_filter.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" +#include "math.h" + +/*--------------------------------------------------------------------------- + This file contains routines which detect filter condition under which + a node can be essentially absorbed in its fanins. +----------------------------------------------------------------------------*/ + +xln_absorb_nodes_in_fanins(network, support) + network_t *network; + int support; +{ + array_t *Y, *Z; + array_t *nodevec; + array_t *decomp_vec; + int i, j, k; + node_t *node, *n, *fanin; + array_t *xln_can_node_be_absorbed_in_fanins(); + + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + decomp_vec = xln_can_node_be_absorbed_in_fanins(node, support, &Y, &Z); + if (decomp_vec == NIL (array_t)) continue; + + /* found a decomposition */ + /*-----------------------*/ + if (XLN_DEBUG) { + (void) printf("----found a valid decomposition\n"); + } + for (j = 1; j < array_n(decomp_vec); j++) { + n = array_fetch(node_t *, decomp_vec, j); + network_add_node(network, n); + for (k = 0; k < array_n(Y); k++) { + fanin = array_fetch(node_t *, Y, k); + (void) node_collapse(n, fanin); + } + } + n = array_fetch(node_t *, decomp_vec, 0); + node_replace(node, n); + for (k = 0; k < array_n(Z); k++) { + fanin = array_fetch(node_t *, Z, k); + (void) node_collapse(node, fanin); + } + array_free(Y); + array_free(Z); + array_free(decomp_vec); + + } + array_free(nodevec); + (void) network_sweep(network); + +} + +/*------------------------------------------------------------------------------- + Given a "feasible" node (for the time being), returns two arrays pY and pZ + (which form a partition of the fanin-set of node), such that it is possible + to absorb the node in the CLB's for fanins Y and Z. It returns the array of + nodes which will replace the node in nodevec. +--------------------------------------------------------------------------------*/ +array_t * +xln_can_node_be_absorbed_in_fanins(node, support, pY, pZ) + node_t *node; + int support; + array_t **pY, **pZ; +{ + + array_t *nodevec; /* returned array: stores possible decomposition of node */ + array_t *Y, *Z; /* for bound-set and free-set respectively */ + int num_fanin; /* number of fanins of node */ + int num_comb; /* 2 ** num_fanin */ + node_t *fanin; + int i, k; + int num_union_fanin_Y, num_union_fanin_Z; + int bound1, bound2; + int num_internal_Y, num_internal_Z, sum_internal; + int bound_alphas; + int *lambda_indices; + array_t *faninvec; + int support_x_2; + int flag; + + /* return NIL if the support of the node is high */ + /*---------------------------------------------*/ + num_fanin = node_num_fanin(node); + support_x_2 = 2 * support; + + if (num_fanin >= support_x_2) return NIL (array_t); + + /* return NIL if some fanin that is an + intermediate node has multiple fanouts + or if all the fanins are primary inputs */ + /*---------------------------------------------*/ + flag = 0; + foreach_fanin(node, k, fanin) { + if (fanin->type == INTERNAL) { + if (node_num_fanout(fanin) > 1) return NIL(array_t); + flag = 1; + } + } + if (!flag) return NIL(array_t); + + /* return NIL if the union of fanins of fanins is >= 2 * support */ + /*---------------------------------------------------------------*/ + faninvec = pld_get_array_of_fanins(node); + if (xln_num_union_of_fanins(faninvec) > support_x_2) { + array_free(faninvec); + return NIL (array_t); + } + array_free(faninvec); + + /* try all possible partitions of the fanin-space one by one */ + /*-----------------------------------------------------------*/ + /* num_comb = (int) (pow ((double) 2, (double) num_fanin)); */ + /* added for robustness */ + /*----------------------*/ + if (num_fanin > 31) return NIL (array_t); + num_comb = 1 << num_fanin; + for (i = 0; i < num_comb; i++) { + Y = array_alloc(node_t *, 0); + Z = array_alloc(node_t *, 0); + xln_generate_fanin_combination(node, i, Y, Z); + if (XLN_DEBUG) { + xln_print_absorb_node(node, Y, Z); + } + /* check if the partition is non-trivial */ + /*---------------------------------------*/ + if ((array_n(Y) <= 1) || (array_n(Z) == 0)) { + array_free(Y); + array_free(Z); + continue; + } + + /* if the union_fanin_support high, ignore the partition */ + /*-------------------------------------------------------*/ + num_union_fanin_Y = xln_num_union_of_fanins(Y); /* Y - bound set */ + num_union_fanin_Z = xln_num_union_of_fanins(Z); /* Z - free set */ + if ((num_union_fanin_Y > support) || (num_union_fanin_Z > support)) { + array_free(Y); + array_free(Z); + continue; + } + /* calculate bounds on number of alphas (new nodes after decomposition */ + /* bound1 is based on the fact that the resulting node after decomposition + should be feasible (for the time being - else do a cost estimation. */ + /*---------------------------------------------------------------------*/ + bound1 = support - num_union_fanin_Z; /* upper bounds num. of alphas */ + + /* bound2 is calculated based on the observation that the saving is + in fact, internal_Y + internal_Z - num_alphas. This should be >0*/ + /*----------------------------------------------------------------*/ + + num_internal_Y = xln_num_internal_nodes(Y); + num_internal_Z = xln_num_internal_nodes(Z); + sum_internal = num_internal_Y + num_internal_Z; + bound2 = sum_internal - 1; + bound_alphas = min (bound1, bound2); + if (XLN_DEBUG) { + (void) printf("---num_union_fanin_Y = %d, num_union_fanin_Z = %d\n", + num_union_fanin_Y, num_union_fanin_Z); + } + /* try out this partition for decomposition */ + /*------------------------------------------*/ + lambda_indices = xln_array_to_indices(Y, node); + nodevec = xln_k_decomp_node_with_array(node, lambda_indices, + array_n(Y), bound_alphas); + FREE(lambda_indices); + if (nodevec == NIL (array_t)) { + array_free(Y); + array_free(Z); + continue; + } + /* found the required partition */ + /*------------------------------*/ + *pY = Y; + *pZ = Z; + return nodevec; + } + return NIL (array_t); + +} + +/*--------------------------------------------------------------------- + Given a set of nodes (nodevec), returns the total number of fanins + of the set. There may be primary inputs in the set. +----------------------------------------------------------------------*/ +int +xln_num_union_of_fanins(nodevec) + array_t *nodevec; +{ + st_table *table; + int i, j; + int num; /* total number of fanins of all the nodes in nodevec */ + node_t *node, *fanin; + + table = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + /* check this */ + /*------------*/ + if (node->type == PRIMARY_INPUT) { + (void) st_insert(table, (char *) node, (char *) node); + continue; + } + foreach_fanin(node, j, fanin) { + (void) st_insert(table, (char *) fanin, (char *) fanin); + } + } + num = st_count(table); + if (XLN_DEBUG) { + (void) printf("union of the fanins of nodes = %d\n", num); + } + st_free_table(table); + return num; +} + +/*----------------------------------------------------------------------------- + This routine systematically generates ALL partitions (disjoint) of + fanins of the node in the arrays pY and pZ. There are (2 ** num_fanin) + possible combinations. The ith entries Y and Z in + the two arrays form a partition of the fanins of node. The way used to + generate these partitions is that first a binary representation is generated + for the number "i" in num_fanin bits. If there is a 0 at a bit position, the + corresponding fanin is put in the array Y, else in the array Z. +-------------------------------------------------------------------------------*/ + +xln_generate_all_fanin_combinations(node, pY, pZ) + node_t *node; + array_t *pY, *pZ; + +{ + int num_fanin; + int num_comb; + char *encoded_char; + int i, l; + node_t *fanin; + array_t *Y, *Z; /* the two arrays storing the partition + of the fanins of the node */ + + assert(node->type == INTERNAL); + + num_fanin = node_num_fanin(node); + encoded_char = ALLOC(char, num_fanin + 1); + /* num_comb = (int) (pow ((double) 2, (double) num_fanin)); */ + assert(num_fanin <= 31); + num_comb = 1 << num_fanin; + for (i = 0; i < num_comb; i++) { + Y = array_alloc(node_t *, 0); + Z = array_alloc(node_t *, 0); + xl_binary1(i, num_fanin, encoded_char); + for (l = 0; l < num_fanin; l++) { + fanin = node_get_fanin(node, l); + if (encoded_char[l] == '0') { + array_insert_last(node_t *, Y, fanin); + } else { + assert(encoded_char[l] == '1'); + array_insert_last(node_t *, Z, fanin); + } + } + array_insert_last(array_t *, pY, Y); + array_insert_last(array_t *, pZ, Z); + } + FREE(encoded_char); +} + +/*---------------------------------------------------------------------- + Generates a fanin combination corresponding to i. Returns in arrays + Y and Z the partition of fanins corresponding to binary encoding of + i. +-----------------------------------------------------------------------*/ +xln_generate_fanin_combination(node, i, Y, Z) + node_t *node; + int i; + array_t *Y, *Z; /* the two arrays storing the partition + of the fanins of the node */ + +{ + int num_fanin; + char *encoded_char; + int l; + node_t *fanin; + + num_fanin = node_num_fanin(node); + encoded_char = ALLOC(char, num_fanin + 1); + xl_binary1(i, num_fanin, encoded_char); + for (l = 0; l < num_fanin; l++) { + fanin = node_get_fanin(node, l); + if (encoded_char[l] == '0') { + array_insert_last(node_t *, Y, fanin); + } else { + assert(encoded_char[l] == '1'); + array_insert_last(node_t *, Z, fanin); + } + } + FREE(encoded_char); +} + +xln_print_absorb_node(node, Y, Z) + node_t *node; + array_t *Y; + array_t *Z; +{ + int i; + node_t *fanin; + + (void) printf("candidate node for absorption => %s\n", node_long_name(node)); + (void) printf("---total number of fanins = %d\n", node_num_fanin(node)); + + (void) printf("bound set: number of nodes = %d\n", array_n(Y)); + for (i = 0; i < array_n(Y); i++) { + fanin = array_fetch(node_t *, Y, i); + (void) printf(" %s, ", node_long_name(fanin)); + } + (void) printf("\n"); + + (void) printf("free set: number of nodes = %d\n", array_n(Z)); + for (i = 0; i < array_n(Z); i++) { + fanin = array_fetch(node_t *, Z, i); + (void) printf(" %s, ", node_long_name(fanin)); + } + (void) printf("\n"); +} + +int +xln_num_internal_nodes(nodevec) + array_t *nodevec; +{ + int sum; + int i; + node_t *node; + + sum = 0; + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type == INTERNAL) sum++; + } + return sum; +} diff --git a/sis/pld/xln_imp.c b/sis/pld/xln_imp.c new file mode 100644 index 0000000..459a7ec --- /dev/null +++ b/sis/pld/xln_imp.c @@ -0,0 +1,504 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_imp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" +#include "math.h" + +extern node_t *pld_remap_get_node(); +extern network_t *xln_best_script(); + +/*-------------------------------------------------------------------------- + If the network is small (number of literals in SOP less than lit_limit), + does not do anything. Else, looks at each node and its sop and fac forms, + and if num_fac_literals < alpha * num_sop_literals, decomposes the node in + place. alpha is typically less than 1. +----------------------------------------------------------------------------*/ +xln_selective_good_decomp(network, lit_limit, alpha) + network_t *network; + int lit_limit; + float alpha; +{ + int num_lit_sop, num_lit_fac, lit_sop_total; + int i, num; + lsGen gen; + array_t *nodevec; + node_t *node; + + nodevec = network_dfs(network); + num = array_n(nodevec); + lit_sop_total = 0; + foreach_node(network, gen, node) { + lit_sop_total += node_num_literal(node); + } + if (lit_sop_total < lit_limit) return; /* small network */ + for (i = 0; i < num; i++) { + node = array_fetch(node_t *, nodevec, i); + num_lit_sop = node_num_literal(node); + num_lit_fac = factor_num_literal(node); + if (num_lit_fac < num_lit_sop * alpha) decomp_good_node(network, node); + } + array_free(nodevec); +} + +xln_improve_network(network, init_param) + network_t *network; + xln_init_param_t *init_param; + +{ + array_t *nodevec; + int i, num; + node_t *node; + + nodevec = network_dfs(network); + num = array_n(nodevec); + for (i = 0; i < num; i++) { + node = array_fetch(node_t *, nodevec, i); + (void) xln_improve_node(node, init_param); + } + array_free(nodevec); +} + +/*--------------------------------------------------------- + If the node is infeasible, then it replaces the node by + network. Then it applies the best script on the node, and + gets a good representation of that. Replaces the node by + the new network. +----------------------------------------------------------*/ +xln_improve_node(node, init_param) + node_t *node; + xln_init_param_t *init_param; +{ + node_t *dup_node; + network_t *network1; + + if (node->type != INTERNAL) return 0; + if (node_num_fanin(node) <= init_param->support) return 0; + + /* added Aug 24 93 - for nodes which may not be on minimum support - then + node_replace_by_network() can die */ + /*-----------------------------------------------------------------------*/ + + simplify_node(node, SIM_METHOD_SNOCOMP, SIM_DCTYPE_NONE, SIM_FILTER_NONE, + SIM_ACCEPT_SOP_LITS); + + dup_node = node_dup(node); + if (XLN_DEBUG > 0) { + (void) printf("node %s[%s]\n", node_long_name(node), node_name(node)); + node_print(siserr, node); + } + + /* run best script on network from node */ + /*--------------------------------------*/ + network1 = xln_best_script(dup_node, init_param); + + if (XLN_DEBUG) + (void) printf("\t---replacing node %s by %d feasible nodes\n\n", + node_long_name(node), network_num_internal(network1)); + + /* replace the node in the original network by the network1 */ + /*----------------------------------------------------------*/ + pld_replace_node_by_network(node, network1); + network_free(network1); + node_free(dup_node); + return 1; +} + +/*--------------------------------------------------------------------------- + Take in a node, make a network out of it and return a good feasible network + out of it. cover_node_limit is needed for deciding what options to use + while generating the network. +-----------------------------------------------------------------------------*/ +network_t * +xln_best_script(node, init_param) + node_t *node; + xln_init_param_t *init_param; +{ + network_t *network1, *network2; + int num_fanin; + int num_lit; + int diff1; + double upper_bound; + + num_fanin = node_num_fanin(node); + if (num_fanin <= init_param->support) { + network1 = network_create_from_node(node); + return network1; + } + num_lit = node_num_literal(node); + /* good ao decomposition from feasibility point of view */ + /*------------------------------------------------------*/ + network1 = network_create_from_node(node); + + if (num_lit == num_fanin) { + xln_network_ao_map(network1, init_param->support); + if (XLN_DEBUG > 1) (void) printf("the best possible??\n"); + return network1; + } + + if (init_param->flag_decomp_good == 1) { + decomp_good_network(network1); /* added later with return network1 */ + if (init_param->absorb) { + xln_network_reduce_infeasibility_by_moving_fanins(network1, + init_param->support, 15); + } + } + xln_network_ao_map(network1, init_param->support); + if (XLN_DEBUG > 2) (void) printf("\tafter ao map %d nodes, ", + network_num_internal(network1)); + if (network_num_internal(network1) == 2) { + if (XLN_DEBUG > 1) (void) printf("the best possible??\n"); + return network1; /* not seen any counterexamples so far */ + } + xln_cover_or_partition(network1, init_param); + if (init_param->flag_decomp_good == 2) { + network2 = network_create_from_node(node); + decomp_good_network(network2); + if (network_num_internal(network2) == 1) { + network_free(network2); + } else { + if (init_param->absorb) { + xln_network_reduce_infeasibility_by_moving_fanins(network2, + init_param->support, 15); + } + xln_network_ao_map(network2, init_param->support); + if (XLN_DEBUG > 2) (void) printf("\tafter good decomp & ao map %d nodes, ", + network_num_internal(network2)); + xln_cover_or_partition(network2, init_param); + if (network_num_internal(network2) < network_num_internal(network1)) { + network_free(network1); + network1 = network2; + } else { + network_free(network2); + } + } + } + + /* make a check based on cofactor decomposition (extend it for support + from 6 to 10) */ + /*--------------------------------------------------------------------*/ + if ((init_param->support > 2) && (init_param->support <= 5)) { + diff1 = num_fanin - init_param->support + 1; + /* make it more efficient */ + /*------------------------*/ + if (diff1 <= 31) { + upper_bound = (double) ((1 << diff1) - 1); + } else { + upper_bound = (pow ((double) 2, (double) diff1)) - 1.0; + } + if (network_num_internal(network1) > upper_bound) { + network_free(network1); + network1 = xln_cofactor_decomp(node, init_param->support, AREA); /* for AREA */ + if (XLN_DEBUG > 2) (void) printf("\tafter cofactor %d nodes, ", + network_num_internal(network1)); + } + } + + if (init_param->good_or_fast == FAST) return network1; + xln_try_other_mapping_options(node, &network1, init_param); + return network1; +} + +/*----------------------------------------------------------- + If number of nodes in network not large, then do an exact + cover. Else, use partition command. +-------------------------------------------------------------*/ +xln_cover_or_partition(network, init_param) + network_t *network; + xln_init_param_t *init_param; +{ + (void) xln_do_trivial_collapse_network(network, init_param->support, + init_param->xln_move_struct.MOVE_FANINS, + init_param->xln_move_struct.MAX_FANINS); + /* use exact xl_cover routine */ + /*----------------------------*/ + if (network_num_internal(network) <= init_param->cover_node_limit) { + partition_network(network, init_param->support, 0); + if (XLN_DEBUG > 2) { + (void) printf("using trivial collapse & xl_cover exact "); + (void) printf("=> %d feasible nodes\n", + network_num_internal(network)); + } + + } + if (XLN_DEBUG > 3) xln_network_print(network); +} + + +xln_network_print(network) + network_t *network; +{ + int i, num; + node_t *node; + array_t *nodevec; + + nodevec = network_dfs(network); + num = array_n(nodevec); + for (i = 0; i < num; i++) { + node = array_fetch(node_t *, nodevec, i); + node_print(siserr, node); + } + array_free(nodevec); +} + +/*----------------------------------------------------------------------- + Tries other decomposition methods: disjoint decomposition, roth-karp + decomp, tech. decomposition. Replaces pnetwork with the lower cost one. +-------------------------------------------------------------------------*/ +xln_try_other_mapping_options(node, pnetwork, init_param) + + node_t *node; + network_t **pnetwork; + xln_init_param_t *init_param; +{ + network_t *network1, *network2, *network3, *network4 /* , *network5 */; + int num1, num2, num3, num4 /* , num5 */; + int num_lit, flag; + + network1 = *pnetwork; + num_lit = node_num_literal(node); + + /* in second case, we already have probably the best network */ + /*-----------------------------------------------------------*/ + num1 = network_num_internal(network1); + if ((num1 <= 2) || (node_num_fanin(node) == num_lit)) return; + + /* splitting and covering */ + /*------------------------*/ + flag = 0; + network4 = network_create_from_node(node); + if (num_lit > init_param->lit_bound || init_param->flag_decomp_good) + decomp_good_network(network4); + if (num_lit > init_param->lit_bound) { + num4 = network_num_internal(network4); + if (num4 > 1) { + flag = 1; + if (XLN_BEST) + xln_improve_network(network4, init_param); + } + if (XLN_DEBUG > 2) (void) printf("\tdone good decomp, num nodes = %d\n", + network_num_internal(network4)); + } + split_network(network4, init_param->support); + if (XLN_DEBUG > 2) (void) printf("\tafter splitting %d nodes, ", + network_num_internal(network4)); + xln_cover_or_partition(network4, init_param); + + num4 = network_num_internal(network4); + if (num4 == 2) { + network_free(network1); + *pnetwork = network4; + return; + } + + if (num4 < num1) { + network_free(network1); + network1 = network4; + num1 = num4; + } + else { + network_free(network4); + } + + network3 = network_create_from_node(node); + if (init_param->flag_decomp_good) decomp_good_network(network3); + decomp_disj_network(network3); + num3 = network_num_internal(network3); + if (XLN_DEBUG > 2) (void) printf("\tafter disj decomp %d nodes, ", num3); + + /* accept disj decomp only if good decomp was done or num nodes > 1*/ + /*-----------------------------------------------------------------*/ + if (flag || (num3 != 1)) { + split_network(network3, init_param->support); + if (XLN_DEBUG > 2) (void) printf("\tafter splitting %d nodes, ", + network_num_internal(network3)); + xln_cover_or_partition(network3, init_param); + num3 = network_num_internal(network3); + if (num1 < num3) { + network_free(network3); + } + else { + network_free(network1); + network1 = network3; + num1 = num3; + } + } + else { + network_free(network3); + } + + /* if number of literals is large, do splitting followed by reduction */ + /*--------------------------------------------------------------------*/ + /* if ((num_lit > init_param->cover_node_limit + 1) || (num1 == 2)) { */ + if (num1 == 2) { + *pnetwork = network1; + return; + } + + /* try tech-decomposing and reduction */ + /*------------------------------------*/ + + network2 = network_create_from_node(node); + if (init_param->flag_decomp_good) decomp_good_network(network2); + decomp_tech_network(network2, 2, 2); + if (XLN_DEBUG > 2) (void) printf("\tafter tech decomp %d nodes, ", + network_num_internal(network2)); + xln_cover_or_partition(network2, init_param); + + num2 = network_num_internal(network2); + if (num1 < num2) { + network_free(network2); + } + else { + network_free(network1); + network1 = network2; + num1 = num2; + } + + /* try roth-karp and cover next */ + /*------------------------------*/ + /* + network5 = network_create_from_node(node); + xln_exhaustive_k_decomp_network(network5, init_param); + num5 = network_num_internal(network5); + if (num1 < num5) { + network_free(network5); + } else { + network_free(network1); + network1 = network5; + num1 = num5; + } + */ + + *pnetwork = network1; +} + +network_t * +xln_cofactor_decomp(node, support, mode) + node_t *node; + int support; + float mode; +{ + network_t *network; + node_t *po, *node1; + + network = network_create_from_node(node); + po = network_get_po(network, 0); + node1 = node_get_fanin(po, 0); + (void) xln_cofactor_decomp_node(node1, support, mode); + (void) network_sweep(network); + return network; +} + +/*----------------------------------------------------------------------- + Given a node of the network, cofactors it recursively, till the nodes + added nodes become feasible. The selection of the cofactoring variable + is done based on the fact whether there is a variable that occurs in + all the cubes in the same phase (pos. or neg). +------------------------------------------------------------------------*/ +int +xln_cofactor_decomp_node(node, support, mode) + node_t *node; + int support; + float mode; +{ + node_t *fanin, *fanin0, *fanin1; + node_t *pos, *neg, *rem; + node_t *p, *q; + node_t *p1, *q1, *temp1, *temp2; + node_t *new_node; + + if ((node->type == PRIMARY_INPUT) || (node->type == PRIMARY_OUTPUT)) return 0; + if (node_num_fanin(node) <= support) return 0; + if (mode == AREA) { + fanin = xln_select_fanin_for_cofactor_area(node); + } else { + fanin = xln_select_fanin_for_cofactor_delay(node); + } + node_algebraic_cofactor(node, fanin, &pos, &neg, &rem); + p = node_or(pos, rem); + q = node_or(neg, rem); + fanin0 = node_literal (fanin, 0); /* complemented */ + fanin1 = node_literal (fanin, 1); /* uncomplemented */ + p1 = node_literal(p, 1); + q1 = node_literal(q, 1); + temp1 = node_and(p1, fanin1); + temp2 = node_and(q1, fanin0); + new_node = node_or(temp1, temp2); + node_free(fanin0); + node_free(fanin1); + node_free(pos); + node_free(neg); + node_free(rem); + node_free(p1); + node_free(q1); + node_free(temp1); + node_free(temp2); + network_add_node(node->network, p); + network_add_node(node->network, q); + node_replace(node, new_node); + (void) xln_cofactor_decomp_node(p, support, mode); + (void) xln_cofactor_decomp_node(q, support, mode); + return 1; +} + +/*----------------------------------------------------------------- + If there is a fanin that is in positive (or negative) phase in + all the cubes, returns that fanin. Else returns the last fanin + (does not actually matter). +------------------------------------------------------------------*/ +node_t * +xln_select_fanin_for_cofactor_area(node) + node_t *node; +{ + int num_cube; + int *lit_count_arr; + int j, jx2; + node_t *fanin; + + num_cube = node_num_cube(node); + lit_count_arr = node_literal_count(node); + foreach_fanin(node, j, fanin) { + jx2 = 2 * j; + if ((lit_count_arr[jx2] == num_cube) || lit_count_arr[jx2 + 1] == num_cube) { + FREE(lit_count_arr); + return fanin; + } + } + FREE(lit_count_arr); + return fanin; +} + +/*----------------------------------------------------------------- + Returns the most critical fanin (with least slack). + Assumes that a delay trace has been done on the network. +------------------------------------------------------------------*/ +node_t * +xln_select_fanin_for_cofactor_delay(node) + node_t *node; +{ + node_t *fanin, *min_fanin; + delay_time_t slack_fanin; + double slack; + int j; + + slack = (double) MAXINT; + min_fanin = NIL (node_t); + assert(node->type != PRIMARY_INPUT); + foreach_fanin(node, j, fanin) { + slack_fanin = delay_slack_time(fanin); + if (slack > slack_fanin.rise) { + slack = slack_fanin.rise; + min_fanin = fanin; + } + } + assert(min_fanin != NIL(node_t)); + return min_fanin; +} + diff --git a/sis/pld/xln_k_de_area.c b/sis/pld/xln_k_de_area.c new file mode 100644 index 0000000..17c134d --- /dev/null +++ b/sis/pld/xln_k_de_area.c @@ -0,0 +1,143 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_k_de_area.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/*------------------------------------------------------------------------ + For each node of the network, tries to decompose it using Roth-Karp + decomp. Uses all possible combinations if number of fanins of the node + is <= MAX_FANINS. Then decomposes the resulting root node recursively + if the RECURSIVE is non-zero. + If the Roth-Karp decomposition fails (a disjoint decomp not possible), + and DESPERATE is non-zero, then use xl_ao map to decompose the node. +--------------------------------------------------------------------------*/ +xln_exhaustive_k_decomp_network(network, init_param) + network_t *network; + xln_init_param_t *init_param; +{ + array_t *nodevec; + int i; + node_t *node; + int done; + network_t *net_decomp; + + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + + done = 0; + while (!done) { + net_decomp = xln_exhaustive_k_decomp_node(node, init_param->support, + init_param->MAX_FANINS_K_DECOMP); + if (net_decomp == NIL (network_t)) { + done = 1; + continue; + } + pld_replace_node_by_network(node, net_decomp); + network_free(net_decomp); + if (!init_param->RECURSIVE) done = 1; + } + /* final resort */ + /*--------------*/ + if ((node_num_fanin(node) > init_param->support)) { + xln_node_ao_map(node, init_param->support); + } + } + array_free(nodevec); +} + + +/*------------------------------------------------------------------ + Call Roth Karp decomp on a node of the network. Try all possible + input partitions for the node if the number of fanins of the node + is not too high: i.e., no more than MAX_FANINS. If higher, + generate just one partition. Returns an array of nodes as the + decomposition. The selection of the best node is found by a + decomposition of the new root node by xl_ao (a fast estimate). + This decomposes just once, but it can be called recursively, if + wanted from the calling routine. +-------------------------------------------------------------------*/ + +network_t * +xln_exhaustive_k_decomp_node(node, support, MAX_FANINS) + node_t *node; + int support; + int MAX_FANINS; +{ + int best_cost; + int cost; + int num_fanin; + int *lambda_indices; + int num_comb, i; + node_t *po, *node_root; + network_t *net_new, *net_best; + array_t *Y, *Z; + + if (node->type != INTERNAL) return NIL(network_t); + num_fanin = node_num_fanin(node); + if (num_fanin <= support) return NIL(network_t); + /* somehow generate a good combination */ + /*-------------------------------------*/ + if (num_fanin > MAX_FANINS) { + return NIL (network_t); /* for the time being */ + } + + /* generate all the partitions, one by one, and ask for a decomposition */ + /*----------------------------------------------------------------------*/ + best_cost = HICOST; + net_best = NIL (network_t); + /* num_comb = (int) (pow ((double) 2, (double) num_fanin)); */ + num_comb = 1 << num_fanin; + for (i = 0; i < num_comb; i++) { + /* can I ignore this partition from the bound info. calculated earlier */ + /*---------------------------------------------------------------------*/ + if ((i == 1) && (num_fanin > MAX_FANINS)) break; + Y = array_alloc(node_t *, 0); + Z = array_alloc(node_t *, 0); + xln_generate_fanin_combination(node, i, Y, Z); + + /* check if the partition is non-trivial and also for feasibility of Y */ + /*---------------------------------------------------------------------*/ + if ((array_n(Y) <= 1) || (array_n(Y) > support) || (array_n(Z) == 0)) { + array_free(Y); + array_free(Z); + continue; + } + lambda_indices = xln_array_to_indices(Y, node); + net_new = xln_k_decomp_node_with_network(node, lambda_indices, array_n(Y)); + FREE(lambda_indices); + if (net_new == NIL (network_t)) { + array_free(Y); + array_free(Z); + continue; + } + /* calculate the cost of this decomposition - root node's cost + estimated by xl_node_ao_map */ + /*------------------------------------------------------------*/ + po = network_get_po(net_new, 0); + node_root = node_get_fanin(po, 0); + xln_node_ao_map(node_root, support); + cost = network_num_internal(net_new); + if (cost < best_cost) { + best_cost = cost; + /* free the best_nodevec, along with all the nodes */ + /*-------------------------------------------------*/ + if (net_best != NIL(network_t)) { + network_free(net_best); + } + net_best = net_new; + } + array_free(Y); + array_free(Z); + } + return net_best; +} + diff --git a/sis/pld/xln_k_decomp.c b/sis/pld/xln_k_decomp.c new file mode 100644 index 0000000..82574bd --- /dev/null +++ b/sis/pld/xln_k_decomp.c @@ -0,0 +1,1252 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_k_decomp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +/* changed Feb 20, 1991 - - to accomodate delay routine, made these changes. + had to change some other stuff, like init_intersection was written,... */ + +#include "sis.h" +#include "pld_int.h" +#include <math.h> + +struct my_cube { + int *variable; /* maximum cardinality of LAMBDA-set */ + }; + +static node_t **ALPHA; /* for storing ALPHA functions */ +static node_t *G_node; /* used for finding G_node */ + +static array_t *karp_decomp_internal(); /* added Feb 25, 1991 */ +network_t *xln_k_decomp_node_with_network(); /* added Feb 25, 1991 */ +array_t *xln_k_decomp_node_with_array(); /* added Feb 25, 1991 */ +extern int split_node(); /* Narendra's routine added Feb 25, 1991 */ + +static void karp_decomp_node_internal(); +static void form_incompatibility_graph(); +static void form_u_intersection(); +static void get_lambda_cube(); +static int val_literal(); +static int** init_incompatible(); +static int** init_intersection(); +static void alloc_my_cube(); +static void end_incompatible(); +static void end_intersection(); +static void free_my_cube(); +static void make_incompatible(); +static void generate_all_minterms(); +static void generate_minterm_with_index(); +static void tree_init(); +static void form_compatibility_classes(); +static void mark_roots_of_trees(); +static void get_combination(); +static void mark_all_inputs(); +static int is_fanin_in_lambda(); +static int marked(); +static int find_alphas_and_G(); /* returns number of alpha nodes */ +static node_t *product_node_for_minterm(); +static node_t *find_G(); +static void free_tree(); +static enum st_retval k_decomp_free_table_entry(); +static void replace_node_decomposed(); + +void +karp_decomp_network(network, SUPPORT, one_node, user_node) + network_t *network; + int SUPPORT; + int one_node; + node_t *user_node; +{ + + node_t *node, *node_simpl; + array_t *nodevec; + int i; + int num_nodes; + int **intersection; + int *lambda_indices; + int NUM_NODES; + + /* NUM_NODES = (int)(pow((double)2, (double)SUPPORT)); */ + NUM_NODES = 1 << SUPPORT; + intersection = init_intersection(); + lambda_indices = ALLOC(int, SUPPORT); + if (one_node) { + nodevec = array_alloc(node_t *, 0); + array_insert_last(node_t *, nodevec, user_node); + } + else { + nodevec = network_dfs_from_input(network); + } + num_nodes = array_n(nodevec); + /* simplify so that while taking complement, the support remains same for + complemented node */ + /*---------------------------------------------------------------------*/ + for (i = 0; i < num_nodes; i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + node_simpl = node_simplify(node, (node_t *) NULL, NODE_SIM_ESPRESSO); + node_replace(node, node_simpl); + } + for (i = 0; i < num_nodes; i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + karp_decomp_node_internal(node, intersection, lambda_indices, NUM_NODES, SUPPORT); + } + (void) network_sweep(network); + + /* freeing */ + /*---------*/ + array_free(nodevec); + end_intersection(intersection); + FREE(lambda_indices); +} + +/*---------------------------------------------------------------------------------------- + For the node, generates a lambda set, and then calls the karp_decomp_internal routine. + If the node cannot be decomposed, calls the split routine. Recursively decomposes till + feasible node generated. +------------------------------------------------------------------------------------------*/ +static void +karp_decomp_node_internal(node, intersection, lambda_indices, NUM_NODES, SUPPORT) + node_t *node; + int **intersection; + int *lambda_indices; + int NUM_NODES, SUPPORT; +{ + int j, num; + node_t *new_node; + array_t *newvec; + + while (1) { + /* if feasible, return - note this can't be put outside "while" */ + /*--------------------------------------------------------------*/ + if (node_num_fanin (node) <= SUPPORT) return; + + /* decompose node using lambda indices as bound set */ + /*--------------------------------------------------*/ + get_combination(node, 0, lambda_indices, SUPPORT); + newvec = karp_decomp_internal(node, intersection, lambda_indices, + NUM_NODES, SUPPORT); + /* checking if decomposition possible */ + /*------------------------------------*/ + if (newvec != NIL(array_t)) { + num = array_n(newvec); + for (j = 1; j < num; j++) { + new_node = array_fetch(node_t *, newvec, j); + network_add_node(node->network, new_node); + } + new_node = array_fetch(node_t *, newvec, 0); + node_replace(node, new_node); + array_free(newvec); + } + /* decomposition not possible, split the node */ + /*--------------------------------------------*/ + else { + (void) split_node(node->network, node, SUPPORT); + return; + } + } +} + +/************************************************************** + decomposes a node in the network such that the bound set + LAMBDA has a cardinality of SUPPORT. Based on karp's method of + decomposition. However, to speed up things, presently we do + not go for the best decomposition. We just go for "a" + decomposition. +**************************************************************/ +static array_t * +karp_decomp_internal(node, intersection, lambda_indices, NUM_NODES, SUPPORT) +node_t *node; +int **intersection; +int *lambda_indices; +int NUM_NODES, SUPPORT; + +{ + + node_t *node_inv; + int i; + st_table *root_table; + st_table *lambda_table; + tree_node **treenode; + int **incompatible; /* stores whether minterms i & j are incompatible */ + int CLASS_NUM, NUM_ALPHAS; + array_t *nodevec; + + incompatible = init_incompatible(NUM_NODES); + + /* to store the info. about the root of the trees. CLASS_NUM tells the + class_num of each tree (but is valid only at the end of mark_root */ + + root_table = st_init_table(st_ptrcmp, st_ptrhash); + lambda_table = st_init_table(st_ptrcmp, st_ptrhash); + CLASS_NUM = 0; + treenode = ALLOC (tree_node *, NUM_NODES); + tree_init(treenode, NUM_NODES); + + node_inv = node_not(node); + + form_incompatibility_graph(node, node_inv, intersection, incompatible, + lambda_table, lambda_indices, NUM_NODES, SUPPORT); + form_compatibility_classes(treenode, incompatible, NUM_NODES); + mark_roots_of_trees(treenode, root_table, NUM_NODES, &CLASS_NUM); + NUM_ALPHAS = intlog2(CLASS_NUM); + /* check when the node cannot be decomposed */ + /*------------------------------------------*/ + if (NUM_ALPHAS == SUPPORT) { + node_free(node_inv); + free_tree(treenode, root_table, lambda_table, NUM_NODES); + end_incompatible(incompatible, NUM_NODES); + return NIL (array_t); + } + find_alphas_and_G(node, lambda_table, treenode, lambda_indices, + NUM_NODES, SUPPORT, CLASS_NUM, NUM_ALPHAS); + nodevec = array_alloc(node_t *, 0); + array_insert_last(node_t *, nodevec, G_node); + for (i = 0; i < NUM_ALPHAS; i++) { + array_insert_last(node_t *, nodevec, ALPHA[i]); + } + node_free(node_inv); + FREE(ALPHA); + /* frees the root_table, lambda table also */ + /*-----------------------------------------*/ + free_tree(treenode, root_table, lambda_table, NUM_NODES); + end_incompatible(incompatible, NUM_NODES); + return nodevec; +} + +static void +form_incompatibility_graph(node, node_inv, intersection, incompatible, lambda_table, lambda_indices, NUM_NODES, SUPPORT) +node_t *node; +node_t *node_inv; +int **intersection, **incompatible; +st_table *lambda_table; +int *lambda_indices; +int NUM_NODES, SUPPORT; + +{ + int node_numcubes; + int i; + node_cube_t cube_n; + + /* if the input in is in lambda part, mark it 1, else mark it 0 */ + /* assume static (global) storage for the marking arrays */ + /*---------------------------------------------------------------*/ + mark_all_inputs(node, lambda_table, lambda_indices, SUPPORT); + node_numcubes = node_num_cube(node); + for (i = node_numcubes - 1; i >= 0; i--) { + cube_n = node_get_cube(node, i); + form_u_intersection(node, cube_n, node_inv, intersection, incompatible, + lambda_table, lambda_indices, NUM_NODES, SUPPORT); + } + } + +/******************************************************************** + for a cube of the node, form its u-intersection with every + cube of node_inv. +*********************************************************************/ + +static void +form_u_intersection(node, cube, node_inv, intersection, incompatible, + lambda_table, lambda_indices, NUM_NODES, SUPPORT) +node_t *node; +node_cube_t cube; +node_t *node_inv; +int **intersection; +int **incompatible; +st_table *lambda_table; +int *lambda_indices; +int NUM_NODES, SUPPORT; +{ + int NULL_INT; + int node_inv_numcubes; + int i; + int j; + node_t *fanin; + node_t *fanin_inv; + node_literal_t literal; + int lit_val; + node_literal_t literal_inv; + int lit_inv_val; + struct my_cube lambda_cube; + struct my_cube lambda_cube_inv; + node_cube_t cube_inv; + + node_inv_numcubes = node_num_cube(node_inv); + + for (i = node_inv_numcubes -1; i >= 0; i--) { + cube_inv = node_get_cube(node_inv, i); /* m_lambda, m_u */ + NULL_INT = FALSE; + foreach_fanin(node, j, fanin) { + if (marked(fanin, lambda_table)) continue; /* ignore lambda fanins */ + literal = node_get_literal(cube, j); + lit_val = val_literal(literal); + + fanin_inv = node_get_fanin(node_inv, j); + if (marked(fanin_inv, lambda_table)) { + (void) fprintf(sisout, "Fatal error: cube ordering erros\n"); + exit(1); + } + literal_inv = node_get_literal(cube_inv, j); + lit_inv_val = val_literal(literal_inv); + if (intersection[lit_val][lit_inv_val] == -1) { + NULL_INT = TRUE; + break; + } + } + if (NULL_INT) continue; + /* found a non-empty intersection of cube with cube_inv */ + /* form the incompatibity matrix from the lambda parts */ + /*-----------------------------------------------------*/ + alloc_my_cube(&lambda_cube, SUPPORT); + alloc_my_cube(&lambda_cube_inv, SUPPORT); + get_lambda_cube(cube, &lambda_cube, lambda_indices, SUPPORT); + get_lambda_cube(cube_inv, &lambda_cube_inv, lambda_indices, SUPPORT); + make_incompatible(lambda_cube, lambda_cube_inv, incompatible, NUM_NODES, SUPPORT); + free_my_cube(&lambda_cube); + free_my_cube(&lambda_cube_inv); + } +} + +/*------------------------------------------------------------------ + Get the literals of the cube corresponding to the lambda_indices. + Return it in lambda_cube. The order of literals is important. So, + the 0th literal (variable[0]) is the one corresponding to fanin with + index lambda_indices[0], and so on... +--------------------------------------------------------------------*/ +static void +get_lambda_cube(cube, lambda_cube, lambda_indices, SUPPORT) + node_cube_t cube; + struct my_cube *lambda_cube; + int *lambda_indices; + int SUPPORT; +{ + int j; + node_literal_t literal; + + for (j = 0; j < SUPPORT; j++) { + literal = node_get_literal(cube, lambda_indices[j]); + lambda_cube->variable[j] = val_literal(literal); + } +} + +/*----------------------------------------------------------------- + If complemented => return 0, uncomplemented => return 1, else 2. +------------------------------------------------------------------*/ + +static +int val_literal(literal) + node_literal_t literal; +{ + int value; + + switch(literal) { + case ZERO : /* complemented */ + value = 0; + break; + case ONE : /* uncomplemented */ + value = 1; + break; + case TWO : /* does not appear */ + value = 2; + break; + } + return value; +} + + +static int** +init_incompatible(NUM_NODES) +int NUM_NODES; +{ + int i; + int j; + int **incompatible; + + incompatible = ALLOC(int *, NUM_NODES); + for (i = 0; i < NUM_NODES; i++) { + incompatible[i] = ALLOC(int, NUM_NODES); + } + + for (i =0 ; i < NUM_NODES; i++) { + for (j = 0; j < NUM_NODES; j++) { + incompatible[i][j] = FALSE; + } + } + return incompatible; +} + +static void +end_incompatible(incompatible, NUM_NODES) +int **incompatible; +int NUM_NODES; +{ + int i; + + for (i = 0; i < NUM_NODES; i++) { + FREE(incompatible[i]); + } + FREE(incompatible); +} + +/*--------------------------------------------------------------------- + Generate all the minterms in a and b my_cubes, and make them + incompatible. +----------------------------------------------------------------------*/ +static void +make_incompatible(a, b, incompatible, NUM_NODES, SUPPORT) +struct my_cube a, b; +int **incompatible; +int NUM_NODES, SUPPORT; +{ + + int i; + int j; + int *min_a; + int *min_b; + int num_min_a = 0; + int num_min_b = 0; + + min_a = ALLOC(int, NUM_NODES); + min_b = ALLOC(int, NUM_NODES); + + generate_all_minterms(min_a, &num_min_a, a, SUPPORT); + generate_all_minterms(min_b, &num_min_b, b, SUPPORT); + for (i = 0; i < num_min_a; i++) { + for (j = 0; j < num_min_b; j++) { + incompatible[min_a[i]][min_b[j]] = incompatible[min_b[j]][min_a[i]] + = TRUE; + + } + } + FREE(min_a); + FREE(min_b); +} + +/*-------------------------------------------------------------------------- + returns in min_arr all the minterms in the cube cube. Returns the number + of these minterms in num_min. +----------------------------------------------------------------------------*/ +static +void +generate_all_minterms(min_arr, num_min, cube, support) + int min_arr[]; + int *num_min; + struct my_cube cube; + int support; +{ + + generate_minterm_with_index(min_arr, num_min, cube, support, 0, 0); +} + +static +void +generate_minterm_with_index(min_arr, num_min, cube, support, value, i) + int min_arr[]; + int *num_min; + struct my_cube cube; + int support; + int value; + int i; +{ + if (i == support - 1) { + switch (cube.variable[i]) { + case 0: + min_arr[*num_min] = 2*value; *num_min = *num_min + 1; + return; + case 1: + + min_arr[*num_min] = 2*value + 1; *num_min = *num_min + 1; + return; + case 2: + + min_arr[*num_min] = 2*value; *num_min = *num_min + 1; + min_arr[*num_min] = 2*value + 1;*num_min = *num_min + 1; + return; + }; + } + switch (cube.variable[i]) { + case 0 : generate_minterm_with_index(min_arr, num_min, cube, support, 2*value, i+1); + return; + case 1 : generate_minterm_with_index(min_arr, num_min, cube, support, 2*value + 1, i+1); + return; + case 2 : generate_minterm_with_index(min_arr, num_min, cube, support, 2*value, i+1); + generate_minterm_with_index(min_arr, num_min, cube, support, 2*value + 1, i+1); + return; + } + +} + +/*------------------------------------------------------------------ + Each treenode[i] corresponds to a minterm. +-------------------------------------------------------------------*/ +static void +tree_init(treenode, NUM_NODES) +tree_node **treenode; +int NUM_NODES; +{ + + int i; + + for (i = 0; i < NUM_NODES; i++) { + treenode[i] = ALLOC(tree_node, 1); + treenode[i]->parent = treenode[i]; + treenode[i]->index = i; + treenode[i]->num_child = 0; + treenode[i]->class_num = -1; + + } + + +} + +/*--------------------------------------------------------------------- + Put all the minterms that are compatible in one equivalence class. + The data structure for equivalence class is a tree. Initially, all + minterms are a tree each. Then, we merge the trees corresponding to + the two compatible minterms: the tree with more children becomes the + parent tree. +-----------------------------------------------------------------------*/ +static void +form_compatibility_classes(treenode, incompatible, NUM_NODES) +tree_node **treenode; +int **incompatible; +int NUM_NODES; +{ + + int i; + int j; + struct tree_node *root1; + struct tree_node *root2; + + for (i = 0; i< NUM_NODES; i++) { + for (j = i+1; j < NUM_NODES; j++) { + if (incompatible[i][j] == FALSE ) /* i and j are compatible */ + { + root1 = find_tree(treenode[i]); + root2 = find_tree(treenode[j]); + if (root1->index == root2->index) continue; + /* merge the trees corresponding to the minterms */ + /*-----------------------------------------------*/ + unionop(root1, root2); + + } + } + } +} + +/*---------------------------------------------------------------- + Stores the root of all the compatibility classes in root_table. + Counts the number of equivalence (compatibility) classes. + The final value is stored in CLASS_NUM (initially 0). Also + assigns class number to each minterm. +-----------------------------------------------------------------*/ +static void +mark_roots_of_trees(treenode, root_table, NUM_NODES, CLASS_NUM) +tree_node **treenode; +st_table *root_table; +int NUM_NODES, *CLASS_NUM; + +{ + + int i; + tree_node *root; + char *dummy; + int value; + + for (i = 0; i < NUM_NODES; i++) { + root = find_tree(treenode[i]); + treenode[i]->parent = root; + if (st_is_member(root_table, (char *)root->index)) { + (void) st_lookup(root_table, (char *)root->index, &dummy); + value = (int) dummy; + treenode[i]->class_num = value; + } + else { + (void) st_insert(root_table, (char*)root->index, (char *)(*CLASS_NUM)); + treenode[i]->class_num = (*CLASS_NUM); + *CLASS_NUM = (*CLASS_NUM) + 1; + + } + + } +} + +static void +get_combination(node, comb_num, lambda_indices, SUPPORT) +node_t *node; +int comb_num; +int *lambda_indices; +int SUPPORT; + +{ + int num_fanin; + /* adhoc routine - can only return a few combinations*/ + int i; + num_fanin = node_num_fanin(node); + for (i = 0; i < SUPPORT; i++) + lambda_indices[i] = (comb_num + i) % num_fanin; + +} + +/* marks all the inputs of the node as 1 if it corresponds to lambda part, + else 0 */ + +static +void +mark_all_inputs(node, lambda_table, lambda_indices, SUPPORT) +node_t *node; +st_table *lambda_table; +int *lambda_indices, SUPPORT; +{ + + int islambda_fanin; + int j; + node_t *fanin; + + foreach_fanin(node, j, fanin) { + islambda_fanin = is_fanin_in_lambda(node, fanin, lambda_indices, SUPPORT); + (void) st_insert(lambda_table, (char *)fanin, (char *)islambda_fanin); + } +} + +/*--------------------------------------------------------------- + Returns 1 if the fanin is in lambda_part. Else returns 0. +----------------------------------------------------------------*/ +static +int is_fanin_in_lambda(node, fanin, lambda_indices, SUPPORT) +node_t *fanin ; +node_t *node; +int *lambda_indices, SUPPORT; +{ + + int i; + node_t *fanin_my; + + for (i = 0; i < SUPPORT; i++) { + fanin_my = node_get_fanin(node, lambda_indices[i]); + if (fanin_my == fanin) return 1; + } + return 0; +} + +/*--------------------------------------------------------------- + Returns 1 if the fanin is in lambda_table (i.e., it is in + lambda_set. +-----------------------------------------------------------------*/ +static +int marked(fanin, lambda_table) +node_t *fanin; +st_table *lambda_table; +{ + char *dummy; + int found; + + + found = st_lookup(lambda_table, (char *)fanin, &dummy); + if (!found) { + (void) fprintf(sisout, " Fatal error: marked(fanin) : error in finding node\n", + node_name(fanin)); + exit(1); + } + return (int)dummy; +} + +/*----------------------------------------------------------------------- + f = g(alpha1, alpha2, ...., alphat, ....); + Number of ALPHA functions is log2 of number of compatibility classes. + fn_array stores for a minterm binary value of classnum that minterm + belongs to. + From fn_array, the ALPHA functions are constructed by ORing the + minterms that result in 1 for that function. +-------------------------------------------------------------------------*/ + +static int +find_alphas_and_G(node_to_decomp, lambda_table, treenode, lambda_indices, + NUM_NODES, SUPPORT, CLASS_NUM, NUM_ALPHAS) +node_t *node_to_decomp; +st_table *lambda_table; +tree_node **treenode; +int *lambda_indices; +int NUM_NODES, SUPPORT, CLASS_NUM, NUM_ALPHAS; +{ + + char **fn_array; + node_t *fn, *fn_simplified; + node_t *fn_node1; + node_t *node_for_minterm; + int minterm; + int fn_num; + int FLAG; + + fn_array = ALLOC(char *, NUM_NODES); + + if (CLASS_NUM == 0) { + (void) fprintf(sisout, "Fatal error: no class?\n"); + exit(1); + } + if (CLASS_NUM == 1) { + (void) fprintf(sisout, "Fatal error: strange!!\n"); + exit(1); + } + + ALPHA = ALLOC(node_t *, NUM_ALPHAS); + /* for each minterm (in lambda_space), fn_array stores the binary. rep. + of the class number */ + for (minterm = 0; minterm < NUM_NODES; minterm++) { + fn_array[minterm] = ALLOC(char, NUM_ALPHAS + 1); + xl_binary1(treenode[minterm]->class_num, NUM_ALPHAS, fn_array[minterm]); + } + /* (void) printf( "NUM_ALPHAS = %d\n", NUM_ALPHAS); */ + + for (fn_num = 0; fn_num < NUM_ALPHAS; fn_num++) { + fn = node_constant(0); + FLAG = 0; + for (minterm =0; minterm < NUM_NODES; minterm++) { + if (fn_array[minterm][fn_num] == '0') continue; + FLAG = 1; + node_for_minterm = product_node_for_minterm(minterm, node_to_decomp, + lambda_indices, SUPPORT); + fn_node1 = node_or(node_for_minterm, fn); + node_free(fn); + node_free(node_for_minterm); + fn = fn_node1; + }; + if (FLAG) { + if (XLN_DEBUG > 1) { + (void) printf("fn before simplify = "); + node_print_rhs(sisout, fn); + } + fn_simplified = node_simplify(fn, (node_t *) NULL, NODE_SIM_ESPRESSO); + ALPHA[fn_num] = fn_simplified; + node_free(fn); + } + else ALPHA[fn_num] = fn; + } + G_node = find_G(node_to_decomp, lambda_table, lambda_indices, + treenode, NUM_NODES, SUPPORT, NUM_ALPHAS); + + if (XLN_DEBUG > 1) { + (void) printf("G_node = "); + node_print_rhs(sisout, G_node); + } + for (minterm = 0; minterm < NUM_NODES; minterm++) { + FREE(fn_array[minterm]); + } + FREE(fn_array); +} + +/*----------------------------------------------------------------------------- + Form a node that corresponds to the minterm of the node (the minterm is in + lambda_space). +------------------------------------------------------------------------------*/ +static +node_t * +product_node_for_minterm(minterm, node_to_decomp, lambda_indices, SUPPORT) +int minterm; +node_t *node_to_decomp; +int *lambda_indices, SUPPORT; +{ + + node_t *node; + node_t *fn; + node_t *fn1, *literal_fn, *fanin; + char char_minterm[BUFSIZE]; + int length, i; + int phase; + + /* get a binary representation of minterm */ + fn = node_constant(1); + xl_binary1(minterm, SUPPORT, char_minterm); + length = strlen (char_minterm); + if (length != SUPPORT) { + (void) fprintf(sisout, "Fatal error: product_node_for_minterm(): length not SUPPORT\n"); + exit(1); + } + for (i = 0; i < length; i++) { + fanin = node_get_fanin(node_to_decomp, lambda_indices[i]); + if (char_minterm[i] == '0') phase = 0; + else phase = 1; + literal_fn = node_literal(fanin, phase); + fn1 = node_and (literal_fn, fn); + node_free(fn); + node_free(literal_fn); + fn = fn1; + } + node = fn; + return node; +} + +/*------------------------------------------------------------------------ + Find the corresponding function G of the initial node to be decomposed. +--------------------------------------------------------------------------*/ +static +node_t * +find_G( node_to_decomp, lambda_table, lambda_indices, treenode, NUM_NODES, + SUPPORT, NUM_ALPHAS) +node_t *node_to_decomp; +st_table *lambda_table; +int *lambda_indices; +tree_node **treenode; +int NUM_NODES, SUPPORT, NUM_ALPHAS; + +{ + char encoded_char[BUFSIZE]; + node_t *Gnode; /* to be returned */ + node_t *fanin; + node_t *product_fn, *product_fn1, *literal_fn; + node_t *nodeG, *nodeG1, *nodeG2; + node_t *u_fn, *u_fn1, *cube_fn, *cube_fn1; + int i, j, k, l; + int num_min; + int *min_arr, minterm; + int lit_val, phase; + node_cube_t cube; + struct my_cube lambda_cube; + node_literal_t literal; + + min_arr = ALLOC(int, NUM_NODES); + nodeG = node_constant(0); + i = node_num_cube(node_to_decomp); + if (i == 0) { + (void) fprintf(sisout, "Fatal error: node %s has no cubes??\n", + node_name(node_to_decomp)); + exit(1); + } + for (i = node_num_cube(node_to_decomp) - 1 ; i>= 0; i--) { + cube = node_get_cube(node_to_decomp, i); + alloc_my_cube(&lambda_cube, SUPPORT); + get_lambda_cube(cube, &lambda_cube, lambda_indices, SUPPORT); + num_min = 0; + generate_all_minterms(min_arr, &num_min, lambda_cube, SUPPORT); + + /* compute fn. corresponding to the u_part only once for the + cube */ + /*---------------------------------------------------------*/ + u_fn = node_constant(1); + foreach_fanin(node_to_decomp, j, fanin) { + if (marked(fanin, lambda_table)) continue; + literal = node_get_literal(cube, j); + lit_val = val_literal(literal); + if (lit_val != 2) { + literal_fn = node_literal(fanin, lit_val); + u_fn1 = node_and(literal_fn, u_fn); + node_free(literal_fn); + node_free(u_fn); + u_fn = u_fn1; + } + } + + /* for each minterm in the lambda_space, compute the + alpha_functions; OR them together, then AND with u_fn */ + /*-----------------------------------------------------*/ + + cube_fn = node_constant(0); + + for (k = 0; k < num_min; k++) { + product_fn = node_constant(1); + minterm = min_arr[k]; + xl_binary1(treenode[minterm]->class_num, NUM_ALPHAS, + encoded_char); + for (l = 0; l < NUM_ALPHAS; l++) { + if (encoded_char[l] == '0') phase = 0; + else phase = 1; + literal_fn = node_literal(ALPHA[l], phase); + product_fn1 = node_and (literal_fn, product_fn); + node_free(literal_fn); + node_free(product_fn); + product_fn = product_fn1; + } + cube_fn1 = node_or(cube_fn, product_fn); + node_free(cube_fn); + node_free(product_fn); + cube_fn = cube_fn1; + } + + nodeG1 = node_and(cube_fn, u_fn); + node_free(cube_fn); + node_free(u_fn); + + nodeG2 = node_or(nodeG1, nodeG); + node_free(nodeG1); + node_free(nodeG); + nodeG = nodeG2; + free_my_cube(&lambda_cube); + } /* for i */ + + Gnode = node_simplify(nodeG, (node_t *) NULL, NODE_SIM_ESPRESSO); + node_free(nodeG); + FREE(min_arr); + return Gnode; +} + +/* frees the storage allocated for the nodes treenode[] after a node of the + network has been decomposed */ + +/*ARGSUSED*/ +static void +free_tree(treenode, root_table, lambda_table, NUM_NODES) +tree_node **treenode; +st_table *root_table, *lambda_table; +int NUM_NODES; +{ + + int i; + char *arg; + + for (i = 0; i < NUM_NODES; i++) { + FREE(treenode[i]); + } + FREE(treenode); + st_foreach(root_table, k_decomp_free_table_entry, arg); + st_free_table(root_table); + st_foreach(lambda_table, k_decomp_free_table_entry, arg); + st_free_table(lambda_table); + +} + +/*ARGSUSED*/ +static +enum st_retval +k_decomp_free_table_entry(key, value, arg) + char *key, *value, *arg; +{ + return ST_DELETE; +} + +/*------------------------------------------------------------------- + The decomposed node is replaced by the set of ALPHA nodes and + G node. The network changes as a result. +--------------------------------------------------------------------*/ +static void +replace_node_decomposed(network, node_to_replace, NUM_ALPHAS) +network_t *network; +node_t *node_to_replace; +int NUM_ALPHAS; +{ + + int i; + + /* add nodes corresponding to all ALPHA nodes and G node */ + /*-------------------------------------------------------*/ + for (i = 0; i < NUM_ALPHAS; i++) { + network_add_node(network, ALPHA[i]); + }; + FREE(ALPHA); + node_replace(node_to_replace, G_node); + +} + +static void +alloc_my_cube(cube, support) + struct my_cube *cube; + int support; +{ + cube->variable = ALLOC(int, support); +} + +static void +free_my_cube(cube) + struct my_cube *cube; + +{ + FREE(cube->variable); +} + +static int** +init_intersection() +{ + int **intersection; + int i; + + /* initializing intersection function */ + /*------------------------------------*/ + intersection = ALLOC(int *, 3); + for (i = 0; i < 3; i++) { + intersection[i] = ALLOC(int, 3); + } + intersection[0][1] = -1; + intersection[1][0] = -1; + intersection[0][0] = intersection[0][2] = intersection[2][0] = 0; + intersection[1][1] = intersection[1][2] = intersection[2][1] = 1; + intersection[2][2] = 2; + return intersection; +} + +static void +end_intersection(intersection) + int **intersection; +{ + int i; + for (i = 0; i < 3; i++){ + FREE(intersection[i]); + } + FREE(intersection); +} + +/*------------------------------------------------------------------------- + Given lambda indices as the bound set and SUPPORT being the + support of lambda indices, decompose the user_node. + Not recursive. Just does it once. Returns a network with the + decomposition. user_node is not changed if it does not belong to + a network, else it may be simplified. +--------------------------------------------------------------------------*/ +network_t * +xln_k_decomp_node_with_network(user_node, lambda_indices, SUPPORT) + node_t *user_node; + int *lambda_indices, SUPPORT; +{ + network_t *network; /* created out of user_node */ + node_t *node, *node_inv, *node_simpl; + lsGen gen; + int NUM_NODES, CLASS_NUM, NUM_ALPHAS; + int **intersection, **incompatible; + tree_node **treenode; + st_table *root_table, *lambda_table; + int new_support; + + node_simpl = node_simplify(user_node, (node_t *) NULL, NODE_SIM_ESPRESSO); + + /* Added July 1 '93 */ + new_support = xln_modify_lambda_indices(user_node, node_simpl, lambda_indices, SUPPORT); + if (new_support <= 1) { + node_free(node_simpl); + return NIL (network_t); + } + SUPPORT = new_support; + + network = network_create_from_node(node_simpl); + if (node_network(user_node) != NIL (network_t)) { + node_replace(user_node, node_simpl); + } else { + node_free(node_simpl); + } + /* NUM_NODES = (int)(pow((double)2, (double)SUPPORT)); */ + NUM_NODES = 1 << SUPPORT; + intersection = init_intersection(); + incompatible = init_incompatible(NUM_NODES); + + /* to store the info. about the root of the trees. CLASS_NUM tells the + class_num of each tree (but is valid only at the end of mark_root */ + + root_table = st_init_table(st_ptrcmp, st_ptrhash); + lambda_table = st_init_table(st_ptrcmp, st_ptrhash); + CLASS_NUM = 0; + treenode = ALLOC (tree_node *, NUM_NODES); + tree_init(treenode, NUM_NODES); + + /* get the internal node of the network- this would be decomposed */ + /*----------------------------------------------------------------*/ + foreach_node(network, gen, node) { + if (node->type == INTERNAL) break; + } + node_inv = node_not(node); + + form_incompatibility_graph(node, node_inv, intersection, incompatible, + lambda_table, lambda_indices, NUM_NODES, SUPPORT); + form_compatibility_classes(treenode, incompatible, NUM_NODES); + mark_roots_of_trees(treenode, root_table, NUM_NODES, &CLASS_NUM); + NUM_ALPHAS = intlog2(CLASS_NUM); + if (NUM_ALPHAS == SUPPORT) { + node_free(node_inv); + free_tree(treenode, root_table, lambda_table, NUM_NODES); + end_incompatible(incompatible, NUM_NODES); + return NIL (network_t); + } + find_alphas_and_G(node, lambda_table, treenode, lambda_indices, + NUM_NODES, SUPPORT, CLASS_NUM, NUM_ALPHAS); + + /* node is changed, ALPHA freed */ + /*------------------------------*/ + replace_node_decomposed(network, node, NUM_ALPHAS); + node_free(node_inv); + /* frees the root_table, lambda table also */ + /*-----------------------------------------*/ + free_tree(treenode, root_table, lambda_table, NUM_NODES); + end_incompatible(incompatible, NUM_NODES); + end_intersection(intersection); + (void) network_sweep(network); /* node simplify may be simplifying some nodes */ + return network; +} + +/*-------------------------------------------------------------------- + Same as above, except that it takes in a node of the network and + returns its decomposition in this array of nodes. Original node and + network remain unchanged. Slightly different from + karp_decomp_internal. If NUM_ALPHAS( number of alpha functions) is + greater than bound_alphas, return NIL. If a valid decomposition is + found, the first node in the array corresponds to the original node. +----------------------------------------------------------------------*/ +array_t * +xln_k_decomp_node_with_array(node, lambda_indices, SUPPORT, bound_alphas) + node_t *node; + int *lambda_indices, SUPPORT, bound_alphas; +{ + node_t *node_inv, *node_simpl; + int NUM_NODES, CLASS_NUM, NUM_ALPHAS; + int **intersection, **incompatible; + tree_node **treenode; + st_table *root_table, *lambda_table; + int i; + array_t *nodevec; + array_t *check_vec, *xln_checking_lambda_indices_create(); + int new_support; + + node_simpl = node_simplify(node, (node_t *) NULL, NODE_SIM_ESPRESSO); + if (node_num_fanin(node) != node_num_fanin(node_simpl)) { + (void) printf("warning---- node was not expressed on minimal support\n"); + (void) printf("warning---- changing node %s\n", node_long_name(node)); + } + new_support = xln_modify_lambda_indices(node, node_simpl, lambda_indices, SUPPORT); + if (new_support != SUPPORT) { + (void) printf("warning---- a fanin of the node deleted after simplifying\n"); + (void) printf("warning---- new lambda set is of cardinality %d (not %d),\n", + new_support, SUPPORT); + (void) printf("old node = "); + node_print(stdout, node); + (void) printf("\n, simplified node = "); + node_print(stdout, node_simpl); + (void) printf("\n"); + if (new_support <= 1) { + (void) printf("the lambda set is no good\n"); + node_free(node_simpl); + return (NIL (array_t)); + } + SUPPORT = new_support; + } + node_replace(node, node_simpl); + check_vec = xln_checking_lambda_indices_create(node, lambda_indices, SUPPORT); + + node_inv = node_not(node); + xln_checking_lambda_indices(node_inv, lambda_indices, check_vec); + array_free(check_vec); + + /* NUM_NODES = (int)(pow((double)2, (double)SUPPORT)); */ + NUM_NODES = 1 << SUPPORT; + intersection = init_intersection(); + incompatible = init_incompatible(NUM_NODES); + + /* to store the info. about the root of the trees. CLASS_NUM tells the + class_num of each tree (but is valid only at the end of mark_root */ + + root_table = st_init_table(st_ptrcmp, st_ptrhash); + lambda_table = st_init_table(st_ptrcmp, st_ptrhash); + CLASS_NUM = 0; + treenode = ALLOC (tree_node *, NUM_NODES); + tree_init(treenode, NUM_NODES); + + form_incompatibility_graph(node, node_inv, intersection, incompatible, + lambda_table, lambda_indices, NUM_NODES, SUPPORT); + form_compatibility_classes(treenode, incompatible, NUM_NODES); + /* printing */ + if (XLN_DEBUG > 2) { + xln_print_incompatible_matrix(incompatible, NUM_NODES); + } + + mark_roots_of_trees(treenode, root_table, NUM_NODES, &CLASS_NUM); + NUM_ALPHAS = intlog2(CLASS_NUM); + if (XLN_DEBUG) { + (void) printf("number of equivalence classes = %d\n", CLASS_NUM); + } + + /* added May 29, 91 for generating functions + only if this condition is met + check when the node cannot be decomposed */ + /*------------------------------------------*/ + if ((NUM_ALPHAS > bound_alphas) || (NUM_ALPHAS == SUPPORT)) { + node_free(node_inv); + free_tree(treenode, root_table, lambda_table, NUM_NODES); + end_incompatible(incompatible, NUM_NODES); + return NIL (array_t); + } + find_alphas_and_G(node, lambda_table, treenode, lambda_indices, + NUM_NODES, SUPPORT, CLASS_NUM, NUM_ALPHAS); + + nodevec = array_alloc(node_t *, 0); + array_insert_last(node_t *, nodevec, G_node); + for (i = 0; i < NUM_ALPHAS; i++) { + array_insert_last(node_t *, nodevec, ALPHA[i]); + + } + node_free(node_inv); + FREE(ALPHA); + /* frees the root_table, lambda table also */ + /*-----------------------------------------*/ + free_tree(treenode, root_table, lambda_table, NUM_NODES); + end_incompatible(incompatible, NUM_NODES); + end_intersection(intersection); + return nodevec; +} + +array_t * +xln_checking_lambda_indices_create(node, lambda_indices, SUPPORT) + node_t *node; + int *lambda_indices; + int SUPPORT; +{ + array_t *check_vec; + int i; + node_t *fanin; + + check_vec = array_alloc(node_t *, 0); + for (i = 0; i < SUPPORT; i++) { + fanin = node_get_fanin(node, lambda_indices[i]); + array_insert_last(node_t *, check_vec, fanin); + } + return check_vec; +} + +xln_checking_lambda_indices(node, lambda_indices, check_vec) + node_t *node; + int *lambda_indices; + array_t *check_vec; +{ + int i; + node_t *fanin; + + for (i = 0; i < array_n(check_vec); i++) { + fanin = array_fetch(node_t *, check_vec, i); + assert(lambda_indices[i] == node_get_fanin_index(node, fanin)); + } +} + +/*-------------------------------------------------------------------- + Given a node and a simplified node, generates new lambda_indices + to take care of any fanins that have been deleted and were there in + lambda_indices. +---------------------------------------------------------------------*/ +int +xln_modify_lambda_indices(node, node_simpl, lambda_indices, SUPPORT) + node_t *node, *node_simpl; + int *lambda_indices, SUPPORT; +{ + int i, j; + node_t *fanin; + + for (i = 0, j =0; i < SUPPORT; i++) { + fanin = node_get_fanin(node, lambda_indices[i]); + if (node_get_fanin_index(node_simpl, fanin) >= 0) { + lambda_indices[j++] = lambda_indices[i]; + } + } + return j; +} + + +xln_print_incompatible_matrix(incompatible, NUM_NODES) + int **incompatible; + int NUM_NODES; +{ + int i, j; + + for (i = 0; i< NUM_NODES; i++) { + for (j = i+1; j < NUM_NODES; j++) { + (void) printf("%d ", incompatible[i][j]); + } + (void) printf("\n"); + } +} diff --git a/sis/pld/xln_level.c b/sis/pld/xln_level.c new file mode 100644 index 0000000..93eed87 --- /dev/null +++ b/sis/pld/xln_level.c @@ -0,0 +1,668 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_level.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/*--------------------------------------------------------------------------- + Does a delay trace on the network. Then finds a node critical node + which can be collapsed into some of its critical fanouts. This constitutes + one pass. This process is repeated till no such collapsing is possible. + + xln_reduce_level_one_pass() collapses a critical node into critical fanouts + even if it can't be collapsed in all the critical fanouts. + xln_find_critical_collapsible_node() collapses a node only if it can be + collapsed in all the critical fanouts. Also, right now, + xln_reduce_level_one_pass() also does first a collapse of a node into a + fanout that may be "slightly" infeasible right now, but which has a fanin + that has a lower level (arrival time) and hence can be cofactored wrt that + fanin. In future, xln_find_critical_collapsible_node() should also have this + capability. + + Also needed is a way to move fanins that are not critical, so that the node + may be collapsed into the fanout nodes. +----------------------------------------------------------------------------*/ +xln_reduce_levels(net, init_param) + network_t **net; + xln_init_param_t *init_param; +{ + network_t *network, *network1; + int changed_network; + double max_level, max_level1; + node_t *node; + + network = *net; + + changed_network = 1; + assert(delay_trace(network, DELAY_MODEL_UNIT)); + while (changed_network) { + if (XLN_DEBUG) { + node= delay_latest_output(network, &max_level); + (void) printf("latest output %s (%s) -> level %f\n", + node_long_name(node), node_name(node), + max_level); + } + if (init_param->traversal_method == 0) { + changed_network = xln_one_pass_by_levels(network, (double) 0, init_param); + } else { + changed_network = xln_one_pass_topol(network, (double) 0, init_param); + } + /* try to make the fanins of critical nodes as few as possible + 0 for not doing an initial delay trace. Note that moving is + done only if MOVE_FANINS is non-zero in init_param. */ + /*-------------------------------------------------------------*/ + if (changed_network) { + xln_network_move_fanins_for_delay(network, init_param, 0); + } + } + /* try a cofactor based approach - new network is good if number of levels less + or levels same, but nodes less */ + /*---------------------------------------------------------------------------*/ + network1 = xln_check_network_for_collapsing_delay(network, init_param); + if (network1 == NIL (network_t)) return; + (void) delay_latest_output(network, &max_level); + (void) delay_latest_output(network1, &max_level1); + if ((max_level1 < max_level) || + ((max_level1 == max_level) && + (network_num_internal(network1) < network_num_internal(network)))) { + network_free(network); + network = network1; + } else { + network_free(network1); + } + *net = network; +} + +/*--------------------------------------------------------------------------- + Tries to reduce levels by collapsing a critical node into its fanouts. + Returns 1 if any change was done in the network. + Disadvantage: a new node may become critical after an operation: not taken + into account... Always dealing with the old info... +-----------------------------------------------------------------------------*/ +int +xln_one_pass_by_levels(network, threshold, init_param) + network_t *network; + double threshold; + xln_init_param_t *init_param; +{ + int changed; + node_t *node; + array_t *levelsvec, *levelvec; + int i, j, xln_level_width_compare_function(); + + if (XLN_DEBUG) (void) printf("----------------------------------\n"); + changed = 0; + /* nodevec = network_dfs(network); */ + /* first process level with minimum number of nodes */ + /*--------------------------------------------------*/ + levelsvec = xln_array_of_critical_nodes_at_levels(network, threshold); + array_sort(levelsvec, xln_level_width_compare_function); + for (i = 0; i < array_n(levelsvec); i++) { + levelvec = array_fetch(array_t *, levelsvec, i); + if (XLN_DEBUG) (void) printf("number of nodes = %d\n", array_n(levelvec)); + for (j = 0; j < array_n(levelvec); j++) { + node = array_fetch(node_t *, levelvec, j); + if (xln_node_collapse_if_critical(node, threshold, init_param)) { + changed = 1; + if (node_num_fanout(node) == 0) network_delete_node(network, node); + /* (void) network_cleanup(network); */ /* to delete the node too */ + assert(delay_trace(network, DELAY_MODEL_UNIT)); + } + } + array_free(levelvec); + } + array_free(levelsvec); + return changed; +} + +int +xln_one_pass_topol(network, threshold, init_param) + network_t *network; + double threshold; + xln_init_param_t *init_param; +{ + int changed; + node_t *node; + array_t *nodevec; + int i; + + changed = 0; + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (xln_node_collapse_if_critical(node, threshold, init_param)) { + changed = 1; + if (node_num_fanout(node) == 0) network_delete_node(network, node); + assert(delay_trace(network, DELAY_MODEL_UNIT)); + } + } + array_free(nodevec); + return changed; +} + +/*--------------------------------------------------------------------------- + If it is a critical node, tries to collapse it into fanouts that are + critical "because of this node" (i.e. with arrival time 1 greater than + node). + heuristic = 2 collapses the node only if it can be collapsed into all + critical fanouts. heuristic = 1 collapses the node into whatever fanouts + it can. It also does cofactoring if the fanout is infeasible... May move + fanins too. + 1 is returned if any collapses or fanin-moves were done, else returns 0. + Note: init_param->heuristic = 1 or 2 are the only ones supported. + Node is not deleted from the network. +----------------------------------------------------------------------------*/ +int +xln_node_collapse_if_critical(node, threshold, init_param) + node_t *node; + double threshold; + xln_init_param_t *init_param; +{ + node_t *fanout, *fanin; + int flag, flag1, j, num_comp_fanin, diff; + array_t *fanoutvec, *fanoutvec1, *comp_fanin, *xln_composite_fanin(); + lsGen gen; + delay_time_t arrival_node; + st_table *table; + int changed_node; + int size; + network_t *network; + + /* if node not INTERNAL, or not critical, return */ + /*-----------------------------------------------*/ + if (node->type != INTERNAL) return 0; + if (!xln_is_node_critical(node, threshold)) return 0; + + assert(init_param->heuristic == 1 || init_param->heuristic == 2); + network = node->network; + size = init_param->support; + arrival_node = delay_arrival_time(node); + fanoutvec = array_alloc(node_t *, 0); + /* table to store for infeasible fanouts(after collapse), the critical fanin */ + /*---------------------------------------------------------------------------*/ + if (init_param->heuristic == 1) { + table = st_init_table(st_ptrcmp, st_ptrhash); + fanoutvec1 = array_alloc(node_t *, 0); + diff = 0; + } + foreach_fanout(node, gen, fanout) { + if (fanout->type == PRIMARY_OUTPUT) continue; + /* if (!xln_is_node_critical(fanout, threshold)) continue; */ /*commented July 30 */ + + /* if fanout critical because of node and composite fanins + <= size, select the pair for collapsing */ + /*--------------------------------------------------------*/ + if (delay_arrival_time(fanout).rise == arrival_node.rise + 1) { + if (init_param->heuristic == 2) { + if (xln_num_composite_fanin(node, fanout) <= size) { + array_insert_last(node_t *, fanoutvec, fanout); + } else { + array_free(fanoutvec); + return 0; + } + } else { + comp_fanin = xln_composite_fanin(node, fanout); + num_comp_fanin = array_n(comp_fanin); + flag1 = 0; + if ((num_comp_fanin <= size) || + ((num_comp_fanin == size + 1) && (size != 2) && + (flag1 = xln_is_just_one_fanin_critical(fanout, comp_fanin, + size, &fanin))) + ) { + array_insert_last(node_t *, fanoutvec, fanout); + if (flag1) { + assert(!st_insert(table, (char *) fanout, (char *) fanin)); + } + } else { + diff = MAX(diff, num_comp_fanin - size); + array_insert_last(node_t *, fanoutvec1, fanout); + } + array_free(comp_fanin); + } + } + } + + /* collapse node into selected fanouts */ + /*-------------------------------------*/ + flag = 0; + for (j = 0; j < array_n(fanoutvec); j++) { + fanout = array_fetch(node_t *, fanoutvec, j); + node_collapse(fanout, node); + if (XLN_DEBUG) (void) printf("--collapsing %s into %s\n", + node_long_name(node), node_long_name(fanout)); + flag = 1; + } + + /* flag is 1 whenever collapsing was done */ + /*----------------------------------------*/ + + if (init_param->heuristic == 2) return flag; + + if (flag) { + xln_mux_decomp(fanoutvec, network, table, size); + } + st_free_table(table); + array_free(fanoutvec); + changed_node = 0; + if (init_param->xln_move_struct.MOVE_FANINS) { + if (xln_node_move_fanins_for_delay(node, init_param->support, + init_param->xln_move_struct.MAX_FANINS, + diff, + init_param->xln_move_struct.bound_alphas)) { + changed_node = xln_try_collapsing_node(node, fanoutvec1, init_param); + } + } + array_free(fanoutvec1); + return (flag || changed_node); +} + +/*---------------------------------------------------------------------------- + If there is at most one node in comp_fanin that has level level_fanout - 2 + and none with level_fanout - 1, then return 1, else return 0. +-----------------------------------------------------------------------------*/ +xln_is_just_one_fanin_critical(fanout, comp_fanin, size, fanin) + node_t *fanout; + array_t *comp_fanin; + int size; + node_t **fanin; +{ + int i, num, num_level_fanout_minus_2; + double level_fanout, level_fanout_minus_2, level_fanout_minus_1, level_node; + delay_time_t arrival_fanout, arrival_node; + node_t *node; + + *fanin = NIL(node_t); + arrival_fanout = delay_arrival_time(fanout); + level_fanout = arrival_fanout.rise; + level_fanout_minus_2 = level_fanout - 2.00000; + level_fanout_minus_1 = level_fanout - 1.00000; + num_level_fanout_minus_2 = 0; + num = array_n(comp_fanin); + for (i = 0; i < num; i++) { + node = array_fetch(node_t *, comp_fanin, i); + arrival_node = delay_arrival_time(node); + level_node = arrival_node.rise; + if (level_node == level_fanout_minus_2) { + num_level_fanout_minus_2++; + *fanin = node; + if (num_level_fanout_minus_2 > 1) return 0; + } else { + if (level_node == level_fanout_minus_1) return 0; + } + } + return 1; +} +/*------------------------------------------------------ + Using the data structure of delay package, tell if the + node is critical. +-------------------------------------------------------*/ +xln_is_node_critical(node, threshold) + node_t *node; + double threshold; +{ + + delay_time_t slack; + slack = delay_slack_time(node); + assert(slack.rise == slack.fall); + if (slack.rise <= threshold) return 1; + return 0; +} + +/*----------------------------------------------------- + Using sophisticated delay model, tells if node is + critical. +------------------------------------------------------*/ +/* commented because pld_get_node_slack not defined here */ +/* +xln_is_node_critical_sophis(node, threshold) + node_t *node; + double threshold; +{ + extern double pld_get_node_slack(); + + if (pld_get_node_slack(node) <= threshold) return 1; + return 0; +} +*/ + +xln_num_composite_fanin(n1, n2) + node_t *n1, *n2; +{ + int is_n2_fanin_of_n1, is_n1_fanin_of_n2, i; + int num_composite_fanin; + node_t *fanin; + + /* assert(n1->type == INTERNAL); + assert(n2->type == INTERNAL); */ + is_n2_fanin_of_n1 = node_get_fanin_index(n1, n2); + is_n1_fanin_of_n2 = node_get_fanin_index(n2, n1); + + num_composite_fanin = node_num_fanin(n1); + foreach_fanin(n2, i, fanin) { + if (node_get_fanin_index(n1, fanin) == (-1)) num_composite_fanin++; + } + if ((is_n2_fanin_of_n1 >= 0) || (is_n1_fanin_of_n2 >= 0)) num_composite_fanin--; + return num_composite_fanin; +} + +array_t * +xln_composite_fanin(n1, n2) + node_t *n1, *n2; +{ + array_t *faninvec; + node_t *fanin; + int i; + + assert(n1->type == INTERNAL); + assert(n2->type == INTERNAL); + + faninvec = array_alloc(node_t *, 0); + foreach_fanin(n1, i, fanin) { + if (fanin != n2) array_insert_last(node_t *, faninvec, fanin); + } + foreach_fanin(n2, i, fanin) { + if ((node_get_fanin_index(n1, fanin) == (-1)) && (fanin != n1)) + array_insert_last(node_t *, faninvec, fanin); + } + return faninvec; +} + +xln_mux_decomp(fanoutvec, network, table, size) + array_t *fanoutvec; + network_t *network; + st_table *table; + int size; +{ + int num, num_fanin, i; + node_t *fanout, *crit_fanin, *crit_fanin0, *crit_fanin1; + node_t *pos, *neg, *rem, *p, *q, *p1, *q1, *temp1, *temp2, *new_fanout; + + num = array_n(fanoutvec); + for (i = 0; i < num; i++) { + fanout = array_fetch(node_t *, fanoutvec, i); + num_fanin = node_num_fanin(fanout); + if (num_fanin <= size) continue; + /* fanout has size + 1 inputs, decompose it using + the mux decomposition */ + /*----------------------------------------------*/ + assert(num_fanin == size + 1); + assert(st_lookup(table, (char *) fanout, (char **) &crit_fanin)); + node_algebraic_cofactor(fanout, crit_fanin, &pos, &neg, &rem); + p = node_or(pos, rem); + q = node_or(neg, rem); + crit_fanin0 = node_literal(crit_fanin, 0); /* complemented */ + crit_fanin1 = node_literal(crit_fanin, 1); /* uncomplemented */ + /* orig fanout = crit_fanin1 p + crit_fanin0 q */ + /*---------------------------------------------*/ + p1 = node_literal(p, 1); + q1 = node_literal(q, 1); + temp1 = node_and(p1, crit_fanin1); + temp2 = node_and(q1, crit_fanin0); + new_fanout = node_or(temp1, temp2); + node_free(crit_fanin0); + node_free(crit_fanin1); + node_free(pos); + node_free(neg); + node_free(rem); + node_free(p1); + node_free(q1); + node_free(temp1); + node_free(temp2); + network_add_node(network, p); + network_add_node(network, q); + node_replace(fanout, new_fanout); + if (XLN_DEBUG) { + (void) printf("mux decomposing %s ", node_long_name(fanout)); + (void) printf("critical fanin %s\n", node_long_name(crit_fanin)); + node_print(sisout, p); + node_print(sisout, q); + node_print(sisout, fanout); + } + + } +} + +/*---------------------------------------------------------------------------- + Tries to collapse node into the fanouts in fanoutvec if they are feasible + after collapsing. If the collapse cannot be done, tries to move the + non-critical fanins of the fanout to get some benefit. + Returns 1 if any collapse took place. Else returns 0. +-----------------------------------------------------------------------------*/ +int +xln_try_collapsing_node(node, fanoutvec, init_param) + node_t *node; + array_t *fanoutvec; + xln_init_param_t *init_param; +{ + int changed; + int i; + node_t *fanout; + int num_comp, diff; + + changed = 0; + for (i = 0; i < array_n(fanoutvec); i++) { + fanout = array_fetch(node_t *, fanoutvec, i); + num_comp = xln_num_composite_fanin(node, fanout); + diff = num_comp - init_param->support; + if (diff <= 0) { + changed = 1; + node_collapse(node, fanout); + } else { + /* try to move fanins of fanout */ + /*------------------------------*/ + if (init_param->xln_move_struct.MOVE_FANINS) { + if (diff == + xln_node_move_fanins_for_delay(fanout, init_param->support, + init_param->xln_move_struct.MAX_FANINS, + diff, + init_param->xln_move_struct.bound_alphas) + ) { + changed = 1; + node_collapse(node, fanout); + + } + } + } + } + return changed; +} + +/*--------------------------------------------------------------------------------- + If the network has small number of inputs, collapses the network. Then applies + Roth-Karp decomposition and cofactoring techniques on the network and evaluates + them. Returns the network with lower number of levels. Returns NIL if collapsing + could not be done. +-----------------------------------------------------------------------------------*/ +network_t * +xln_check_network_for_collapsing_delay(network, init_param) + network_t *network; + xln_init_param_t *init_param; +{ + network_t *network1, *network2; + double max_level1, max_level2; + + if (network_num_pi(network) > init_param->collapse_input_limit) return NIL (network_t); + + /* for the time being, do not handle support = 2 case */ + /*----------------------------------------------------*/ + if (init_param->support == 2) return NIL (network_t); + + network1 = network_dup(network); + (void) network_collapse(network1); + network2 = network_dup(network1); + + pld_simplify_network_without_dc(network1); + (void) network_sweep(network1); + assert(delay_trace(network1, DELAY_MODEL_UNIT)); + xln_cofactor_decomp_network(network1, init_param->support, DELAY); + assert(delay_trace(network1, DELAY_MODEL_UNIT)); + + karp_decomp_network(network2, init_param->support, 0, NIL (node_t)); + assert(xln_is_network_feasible(network2, init_param->support)); + assert(delay_trace(network2, DELAY_MODEL_UNIT)); + + (void) delay_latest_output(network1, &max_level1); + (void) delay_latest_output(network2, &max_level2); + if (max_level1 < max_level2) { + network_free(network2); + return network1; + } + if (max_level1 == max_level2) { + if (network_num_internal(network1) < network_num_internal(network2)) { + network_free(network2); + return network1; + } + } + network_free(network1); + return network2; +} + +/*------------------------------------------------------------ + Cofactors each infeasible node of the network. The mode is + either AREA or DELAY. DELAY mode made faster by levelling + the network and treating each level at one step. Only + after the whole level is processed, a delay trace is done + if needed. Assumes initially that a delay trace using + DELAY_MODEL_UNIT has been done (if mode == DELAY). +--------------------------------------------------------------*/ +xln_cofactor_decomp_network(network, support, mode) + network_t *network; + int support; + float mode; +{ + array_t *levelsvec, *levelvec; + array_t *nodevec; + int i, j; + int changed; /* set to 1 for a level if a node at that level was decomposed */ + node_t *node; + + if (mode == AREA) { + changed = 0; + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (xln_cofactor_decomp_node(node, support, AREA)) { + changed = 1; + } + } + array_free(nodevec); + if (changed) (void) network_sweep(network); + return; + } + + /* mode == DELAY */ + /*---------------*/ + levelsvec = xln_array_of_levels(network); + for (i = 0; i < array_n(levelsvec); i++) { + levelvec = array_fetch(array_t *, levelsvec, i); + changed = 0; + for (j = 0; j < array_n(levelvec); j++) { + node = array_fetch(node_t *, levelvec, j); + if (xln_cofactor_decomp_node(node, support, DELAY)) { + changed = 1; + } + } + array_free(levelvec); + if (changed) { + (void) network_sweep(network); + assert(delay_trace(network, DELAY_MODEL_UNIT)); + } + } + array_free(levelsvec); +} + +/*--------------------------------------------------------------------- + Arranges nodes of the network in an array of levels. Assumes that + delay trace has been done on the network. +----------------------------------------------------------------------*/ +array_t * +xln_array_of_levels(network) + network_t *network; +{ + double max_level; + int imax_level; + array_t *levelsvec, *levelvec; + node_t *node; + delay_time_t arrival_node; + int level; + lsGen gen; + int i; + + (void) delay_latest_output(network, &max_level); + imax_level = (int) max_level; + if (imax_level < 0) imax_level = 0; + levelsvec = array_alloc(array_t *, 0); + for (i = 0; i <= imax_level; i++) { + levelvec = array_alloc(node_t *, 0); + array_insert_last(array_t *, levelsvec, levelvec); + } + foreach_node(network, gen, node) { + arrival_node = delay_arrival_time(node); + level = (int) arrival_node.rise; + assert(level <= imax_level); + /* for nodes with no inputs - Added July 5 '93 */ + /*---------------------------------------------*/ + if (level < 0) level = 0; + levelvec = array_fetch(array_t *, levelsvec, level); + array_insert_last(node_t *, levelvec, node); + } + return levelsvec; +} + +/*----------------------------------------------------------------------- + Given a network, create an array of levels having critical nodes. +------------------------------------------------------------------------*/ +array_t * +xln_array_of_critical_nodes_at_levels(network, threshold) + network_t *network; + double threshold; +{ + double max_level; + int imax_level; + array_t *levelsvec, *levelvec; + node_t *node; + delay_time_t arrival_node; + int level; + lsGen gen; + int i; + + (void) delay_latest_output(network, &max_level); + imax_level = (int) max_level; + if (imax_level < 0) imax_level = 0; + levelsvec = array_alloc(array_t *, 0); + for (i = 0; i <= imax_level; i++) { + levelvec = array_alloc(node_t *, 0); + array_insert_last(array_t *, levelsvec, levelvec); + } + foreach_node(network, gen, node) { + if (xln_is_node_critical(node, threshold)) { + arrival_node = delay_arrival_time(node); + level = (int) arrival_node.rise; + assert(level <= imax_level); + /* for nodes with no inputs - Added July 5 '93 */ + /*---------------------------------------------*/ + if (level < 0) level = 0; + levelvec = array_fetch(array_t *, levelsvec, level); + array_insert_last(node_t *, levelvec, node); + } + } + return levelsvec; +} + +xln_level_width_compare_function(obj1, obj2) + array_t **obj1, **obj2; +{ + return (array_n(*obj1) - array_n(*obj2)); +} + + +/*---------------------------------------------------------------------- + Given a level of nodes, finds all fanouts critical because of some of + them. Makes copies of all these nodes, +------------------------------------------------------------------------*/ diff --git a/sis/pld/xln_lindo.c b/sis/pld/xln_lindo.c new file mode 100644 index 0000000..53a5276 --- /dev/null +++ b/sis/pld/xln_lindo.c @@ -0,0 +1,246 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_lindo.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2005/03/08 05:31:12 $ + * + */ +/* + * This file contains routines for formulating a network node merging + * problem by interger programming + * functions contained in this file: + * formulate_Lindo() + * get_Lindo_result() + * + * Import descriptions: + * + */ + +#include "sis.h" +#include "pld_int.h" +#include <math.h> + +/* + * formulate_Lindo() + * Formulate an integer programming in LINDO format + * Arguments: + * --------- + * coeff<input> : coefficient sparse matrix representing which matching + * (column) includes which nodes (rows) + * Local variables: + * --------------- + * numTerm : counter for the number of terms per line for lindo + * termsPerLine : maximum number of terms per line for lindo + */ + +char * +formulate_Lindo(coeff) + +sm_matrix *coeff; + + +{ + + +int i; +int numTerm; +int termsPerLine = 5; +int flag; +FILE *lindoFile; +sm_row *row; +sm_element *elem; +char *lindo_in; +int sfd; + + + +lindo_in = ALLOC(char, 1000); +(void)sprintf(lindo_in, "/usr/tmp/merge.lindo_in.XXXXXX"); +sfd = mkstemp(lindo_in); +if(sfd == -1) { + (void) fprintf(siserr, "cannot create temp lindo file\n"); + exit(1); +} +lindoFile = fdopen(sfd,"w"); +if(lindoFile == NULL) { + (void) fprintf(siserr, "No space on disk for ILP formulation\n"); + exit(1); +} + +/* Generate objective function : MAX x1 + x2 + ..... + xn */ +/*--------------------------------------------------------*/ +(void) fprintf(lindoFile,"MAX "); +for (numTerm = 0, i = 0; i < coeff->ncols; ++numTerm, ++i) { + + if (i == 0) { + (void) fprintf(lindoFile,"x0 "); + } else { + if (numTerm < termsPerLine) { + (void) fprintf(lindoFile,"+ x%d ", i); + } else { + numTerm = 0; + (void) fprintf(lindoFile,"\n + x%d ", i); + } + } +} +(void) fprintf(lindoFile,"\n"); + +/* Generate constraints : xi1 + xi2 + ..... + xim <= 1 */ +/*-----------------------------------------------------*/ +(void) fprintf(lindoFile,"ST\n"); + +sm_foreach_row(coeff, row) { + + flag = OFF; + numTerm = 0; + sm_foreach_row_element(row, elem) { + + if (flag == OFF) { + flag = ON; + ++numTerm; + (void) fprintf(lindoFile,"x%d ", elem->col_num); + continue; + } + if (numTerm < termsPerLine) { + ++numTerm; + (void) fprintf(lindoFile,"+ x%d ", elem->col_num); + } else { + numTerm = 1; + (void) fprintf(lindoFile,"\n + x%d ", elem->col_num); + } + + } + (void) fprintf(lindoFile,"<= 1\n"); +} +(void) fprintf(lindoFile,"END\n"); + + +/* Declaration of integrality */ +/*----------------------------*/ +for (i = 0; i < coeff->ncols; ++i) { + (void) fprintf(lindoFile,"INTEGER x%d\n",i); +} + +(void) fprintf(lindoFile,"GO\n"); +(void) fprintf(lindoFile,"QUIT\n"); +(void) fclose(lindoFile); + +return lindo_in; +} + + + + + +/* + * get_Lindo_result() + * Get lindo results from file and write them to arrays + */ + + +int +get_Lindo_result(cand_node_array, coeff, match1_array, match2_array, lindo_out, outputFile) + +array_t *cand_node_array; /* nodes in matching problem */ +sm_matrix *coeff; /* incidence matrix: row=node, col=matching */ +array_t *match1_array; /* nodes on one end of matching edge */ +array_t *match2_array; /* nodes on other end of matching edge */ +char *lindo_out; +FILE *outputFile; /* details of the merge results go here */ +{ + +int i; +int endFlg; /* flag, if ON, EOF encountered */ +int infeasibleFlg; /* flag, if ON, no feasible solution obtained */ +char word[50]; /* storage of string from lindo output file */ +int *LPresult; /* answer of max matching problem */ +int match_id; /* sequence number for matching candidate */ +float result; /* result value from LINDO file */ +int num_match; /* cardinality of max matching */ +sm_col *col; /* column of coeff */ +node_t *node; /* node in the network */ +FILE *lindoFile; /* output file from Lindo */ + +/* Initialization */ +/*----------------*/ +LPresult = ALLOC(int, coeff->ncols); +lindoFile = fopen(lindo_out,"r"); + +/* Scan each set of solution in the report + * "REDUCED COST" is the keyword appearing just before the solution set + * "NO FEASIBLE" is the keyword indicating no feasible solution obtained + *----------------------------------------------------------------------*/ +for (endFlg = infeasibleFlg = OFF;;) { + for (;;) { + if (fscanf(lindoFile,"%s",word) == EOF) { + endFlg = ON; + break; + } + if (strcmp(word,"NO") == 0) { + (void) fscanf(lindoFile,"%s",word); + if (strcmp(word,"FEASIBLE") == 0) { + endFlg = ON; + infeasibleFlg = ON; + break; + } + } + if (strcmp(word,"REDUCED") == 0) { + (void) fscanf(lindoFile,"%s",word); + break; + } + } + if (endFlg == ON) { + break; + } + +/* Now seek the result + * Note that variable names are changed to upper case letters in the result + * ex) x5 (lindo.in) --> X5 (lindo.out) + *-----------------------------------------------------------------------*/ + for (; fscanf(lindoFile,"%s",word) != EOF; ) { + +/* If "ROW" appears, solution set section ends */ +/*---------------------------------------------*/ + if (strcmp(word,"ROW") == 0) { + break; + } + if (word[0] == 'X') { + (void) sscanf(word,"X%d",&match_id); + (void) fscanf(lindoFile,"%f",&result); + LPresult[match_id] = RINT(result); + } else { + continue; + } + } +} +(void) fclose(lindoFile); + +/* If no feasible solution, exit */ +/*-------------------------------*/ +if (infeasibleFlg == ON) { + (void) (void) printf("NO FEASIBLE SOLUTION OBTAINED\n"); + exit(8); +} + +for (num_match = 0, i = 0; i < coeff->ncols; ++i) { + if (LPresult[i] == 1) { + ++num_match; + col = sm_get_col(coeff, i); + node = array_fetch(node_t *, cand_node_array, col->first_row->row_num); + array_insert_last(node_t *, match1_array, node); + node = array_fetch(node_t *, cand_node_array, col->last_row->row_num); + array_insert_last(node_t *, match2_array, node); + } +} + +(void) fprintf(outputFile,"Total number of matching = %d\n\n", num_match); + +/* Termination */ +/*-------------*/ +FREE(LPresult); + +return(num_match); + +} diff --git a/sis/pld/xln_map_par.c b/sis/pld/xln_map_par.c new file mode 100644 index 0000000..58378fa --- /dev/null +++ b/sis/pld/xln_map_par.c @@ -0,0 +1,1334 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_map_par.c,v $ + * $Author: pchong $ + * $Revision: 1.3 $ + * $Date: 2005/03/08 01:07:23 $ + * + */ + +/* March 30, 1992 - changed weight to be int * in partition_network() */ + +/* This file contains routines for partitioning cells into unit blocks. + * This corresponds to a technology mapping in the conventional LSI. + * functions contained in this file: + * merge() + * Import descriptions: + * sis.h : macros for misII + * ULM_int.h : macros for universal logic module package + */ + +#include "sis.h" +#include "pld_int.h" + +extern sm_row *sm_mat_bin_minimum_cover(); +extern sm_row *sm_mat_minimum_cover(); + +mf_graph_t *pld_nishiza_graph; /* a graph (flow network) */ +network_t *pld_nishiza_network; /* network we are working on */ +nodeindex_t *pld_nishiza_hash_table; /* hash table for node <--> index */ +int pld_nishiza_g_flag; /* if ON, found a new matching */ + +/* added by Rajeev Dec. 27, 1989 */ +int ULM_INPUT_SIZE; +array_t *solution_array; /* matrix with the selected columns */ + + + + +void +print_suppressed_node() + +{ + lsGen gen; /* generators */ + node_t *node; /* a node in the network */ + char name1[BUFSIZE]; /* name buffer */ + char name2[BUFSIZE]; /* name buffer */ + + (void) printf("\tSuppressed nodes : "); + foreach_node(pld_nishiza_network, gen, node) { + if (node->type == PRIMARY_OUTPUT) { + continue; + } + /* Watch for the Vdd and GND node */ + if (node->type == INTERNAL && node_num_fanin(node) == 0) { + continue; + } + (void) sprintf(name1, "%s_top", node_long_name(node)); + (void) sprintf(name2, "%s_bottom", node_long_name(node)); + if (get_maxflow_edge(pld_nishiza_graph, name2, name1)->capacity == (int) MAXINT) { + (void) printf("%s ", node_long_name(node)); + } + } + (void) printf("\n"); + +} + + + +/* + * construct_maxflow_network() + * Construct a network for maxflow problem to get s-t connectivity + */ + + +void +construct_maxflow_network() + +{ + + lsGen gen, gen2; /* generators */ + node_t *node; /* a node in the network */ + node_t *fanout; /* a fanout node of a node in the network */ + char name1[BUFSIZE]; /* name buffer */ + char name2[BUFSIZE]; /* name buffer */ + + + /* Create a dummy node for a source */ + /*----------------------------------*/ + mf_read_node(pld_nishiza_graph, SOURCE_NAME, 1); + + foreach_node(pld_nishiza_network, gen, node) { + + if (node->type == PRIMARY_OUTPUT) { + continue; + } + /* Watch for the Vdd and GND node */ + if (node->type == INTERNAL && node_num_fanin(node) == 0) { + continue; + } + + /* Create both top and bottom nodes and add an edge between them */ + /*---------------------------------------------------------------*/ + (void) sprintf(name1, "%s_top", node_long_name(node)); + mf_read_node(pld_nishiza_graph, name1, 0); + (void) sprintf(name2, "%s_bottom", node_long_name(node)); + mf_read_node(pld_nishiza_graph, name2, 0); + + mf_read_edge(pld_nishiza_graph, name2, name1, 1); + + /* If this is PI, add an edge from source to the bottom node */ + /*-----------------------------------------------------------*/ + if (node->type == PRIMARY_INPUT) { + mf_read_edge(pld_nishiza_graph, SOURCE_NAME, name2, (int) MAXINT); + } + } + + /* Add edges between intermediate nodes */ + /*--------------------------------------*/ + foreach_node(pld_nishiza_network, gen, node) { + if (node->type == PRIMARY_OUTPUT) { + continue; + } + /* Watch for the Vdd and GND node */ + if (node->type == INTERNAL && node_num_fanin(node) == 0) { + continue; + } + (void) sprintf(name1, "%s_top", node_long_name(node)); + foreach_fanout(node, gen2, fanout) { + if (fanout->type == PRIMARY_OUTPUT) { + continue; + } + (void) sprintf(name2, "%s_bottom", node_long_name(fanout)); + mf_read_edge(pld_nishiza_graph, name1, name2, (int) MAXINT); + } + } + + +} + + + + + +/* + * form_suppress_matrix() + * Form a sparse matrix which represents a relationship between separating + * sets and their covering nodes. + * Each row corresponds to a separating set and each column a node. + */ + +void +form_suppress_matrix(matrix, sepset_array) + +sm_matrix *matrix; +array_t *sepset_array; + +{ + int i, j; + array_t *sepset_node_array; + int idx; + node_t *node; + + + for (i = 0; i < array_n(sepset_array); ++i) { + sepset_node_array = array_fetch(array_t *, sepset_array, i); + for (j = 0; j < array_n(sepset_node_array); ++j) { + node = array_fetch(node_t *, sepset_node_array, j); + idx = nodeindex_indexof(pld_nishiza_hash_table, node); + (void) sm_insert(matrix, i, idx); + } + } +} + + + + +/* + * squeeze_matching() + * Generate one matching which has the sink node as an output + * by changing the combination of suppressed node. + * Used when the generation of matching in generate_matching fails. + */ + +int +squeeze_matching(row) + +sm_row *row; + +{ + sm_element *element; + node_t *node; + int maxflow; + + + /* Suppress the nodes corresponding to the column cover */ + for (element = row->first_col; + element != NULL; element = element->next_col) { + node = nodeindex_nodeof(pld_nishiza_hash_table, element->col_num); + change_edge_capacity(pld_nishiza_graph, node, (int) MAXINT); + } + if(XLN_DEBUG){ + print_suppressed_node(); + } + maxflow = get_maxflow(pld_nishiza_graph); + + /* If found a separating set, mark the flag and return */ + if (maxflow <= ULM_INPUT_SIZE) { + pld_nishiza_g_flag = ON; + return(1); + } + + /* Release the nodes corresponding to the column cover and try next */ + for (element = row->first_col; + element != NULL; element = element->next_col) { + node = nodeindex_nodeof(pld_nishiza_hash_table, element->col_num); + change_edge_capacity(pld_nishiza_graph, node, 1); + } + return(0); + +} + + + + +/* + * initialize_edge_capacity() + * Initialize the capacity of edges + */ + +void +initialize_edge_capacity() + +{ + node_t *node; + lsGen gen; + + foreach_node(pld_nishiza_network, gen, node) { + if (node->type == PRIMARY_OUTPUT) { + continue; + } + /* Watch for the Vdd and GND node */ + if (node->type == INTERNAL && node_num_fanin(node) == 0) { + continue; + } + change_edge_capacity(pld_nishiza_graph, node, 1); + } +} + + + +/* + * generate_matching() + * Generate (all) matching(s) which has the sink node as an output + */ + + +void +generate_matching(sink_array, sepset_array, count) + +array_t *sink_array; /* array of sink nodes for this matching, + * simply copying the current sink node of the + * network */ +array_t *sepset_array; /* array of pointers to arrays of separating + * sets for the matchings obtained */ +int count; + +{ + + int i; + node_t *node; + mf_cutset_t *cutset; /* cutset of the network */ + array_t *sepset_node_array; + /* array of pointers to arrays of separating + * sets for the matchings obtained */ + array_t *from_array; /* array of graph nodes (from) in the cutset */ + array_t *to_array; /* array of graph nodes (to) in the cutset */ + array_t *flow_array; /* array of flows for edges in the cutset */ + int maxflow; + sm_matrix *suppress_matrix; + char sup_file[1000]; + FILE *supFile; + int sfd; + + +for (;;) { + if(XLN_DEBUG){ + print_suppressed_node(); + } + maxflow = get_maxflow(pld_nishiza_graph); + + /* If a finite maxflow was not obtained, try a squeeze operation */ + /*---------------------------------------------------------------*/ + if (maxflow > ULM_INPUT_SIZE) { + if(XLN_DEBUG){ + (void) printf("Squeezing operation ...\n"); + } + initialize_edge_capacity(); + suppress_matrix = sm_alloc(); + form_suppress_matrix(suppress_matrix, sepset_array); + if (XLN_DEBUG) { + (void)sprintf(sup_file, "/usr/tmp/xln.merge.sup_matrix.XXXXXX"); + sfd = mkstemp(sup_file); + if(sfd != -1) { + supFile = fdopen(sfd, "w"); + if (supFile != NULL) { + sm_print(supFile, suppress_matrix); + (void) fclose(supFile); + } + close(sfd); + } + } + pld_nishiza_g_flag = OFF; + (void) sm_mat_minimum_cover(suppress_matrix, NULL, 0, 0, 0, 4096, + squeeze_matching); + sm_free(suppress_matrix); + if (pld_nishiza_g_flag == OFF) { + if(XLN_DEBUG){ + (void) printf("No more finite maxflows\n\n"); + } + return; + } + } + + /* Record the current sink */ + /*-------------------------*/ + node = graph2network_node(pld_nishiza_network, mf_get_sink_node(pld_nishiza_graph)); + array_insert_last(node_t *, sink_array, node); + + /* Record the current separating set */ + /*-----------------------------------*/ + sepset_node_array = array_alloc(node_t *, 0); + array_insert_last(array_t *, sepset_array, sepset_node_array); + cutset = mf_get_cutset(pld_nishiza_graph, &from_array, &to_array, &flow_array); + if(XLN_DEBUG){ + (void) printf("Found a separating set (%d) : ", count); + } + count++; + for(i = 0; i < array_n(flow_array); i++) { + if (array_fetch(int, flow_array, i) == 1) { + node = graph2network_node(pld_nishiza_network, + mf_get_node(pld_nishiza_graph, array_fetch(char *, from_array, i))); + array_insert_last(node_t *, sepset_node_array, node); + if(XLN_DEBUG){ + (void) printf("%s ", node_long_name(node)); + } + } + } + if(XLN_DEBUG){ + (void) printf("\n"); + } + array_free(from_array); + array_free(to_array); + array_free(flow_array); + mf_free_cutset(cutset); + + /* Suppress the mincut found just now */ + /*------------------------------------*/ + node = array_fetch(node_t *, sepset_node_array, 0); + change_edge_capacity(pld_nishiza_graph, node, (int) MAXINT); +} + + +} + + + +/* + * DFS_covered_node() + * DFS to get all the intermediate nodes covered by the matching + */ + + +void +DFS_covered_node(node, node_array, flag) + +node_t *node; /* current node */ +array_t *node_array; /* array of nodes covered by this matching */ +int *flag; /* array of flags, if ON, threaded by DFS */ + +{ + + + node_t *fanin; + int i; + int idx; /* index of node */ + + + /* Set the flag at ON and store the node in the array */ + /*----------------------------------------------------*/ + idx = nodeindex_indexof(pld_nishiza_hash_table, node); + flag[idx] = ON; + array_insert_last(node_t *, node_array, node); + + foreach_fanin(node, i, fanin) { + idx = nodeindex_indexof(pld_nishiza_hash_table, fanin); + if (flag[idx] == OFF) { + DFS_covered_node(fanin, node_array, flag); + } + } + + +} + + + + +/* + * form_binate_matrix() + * Form a sparse matrix for binate covering problem + */ + + +void +form_binate_matrix(network, matrix, weight, sink_array, sepset_array, pbasic_num_rows) + +network_t *network; +sm_matrix *matrix; /* sparse matrix for binate covering problem */ +int *weight; /* array of weight of each column of matrix */ +array_t *sink_array; /* array of sink nodes for all the matchings */ +array_t *sepset_array; /* array of pointers to arrays of separating + * set for all matchings */ +int *pbasic_num_rows; + +{ + + + node_t *node; /* a node */ + node_t *sink; /* a sink */ + node_t *sink_scan, *po; + array_t *sepset_node_array; + /* array of nodes in separating set */ + array_t *node_array; /* array of nodes covered in the matching */ + int row_index; /* row index of a sparse matrix */ + int i, j, k; + int num_node; /* # of PI's and internal nodes */ + int idx; /* index of a node */ + int *flag; /* flags for DFS, if ON, threaded by DFS */ + lsGen gen; + + + /* Initialization */ + /*----------------*/ + num_node = network_num_pi(pld_nishiza_network) + network_num_internal(pld_nishiza_network); + flag = ALLOC(int, num_node); + row_index = num_node - 1; + + /* a node that fans out to a PO must be output of a match */ + /*--------------------------------------------------------*/ + foreach_primary_output(network, gen, po) { + /* If this node fans out to PO, should be implemented by some cover */ + /*------------------------------------------------------------------*/ + sink = node_get_fanin(po, 0); + if ((sink->type == INTERNAL) && (node_num_fanin(sink) == 0)) continue; + ++row_index; + for(k = 0; k < array_n(sink_array); k++) { + sink_scan = array_fetch(node_t *, sink_array, k); + if (sink_scan == sink) { + (void) sm_insert(matrix, row_index, 2 * k); + } + } + } + + *pbasic_num_rows = row_index + 1; + for(i = 0; i < array_n(sink_array); i++) { + + sink = array_fetch(node_t *, sink_array, i); + sepset_node_array = array_fetch(array_t *, sepset_array, i); + + /* Initialize DFS flag */ + /*---------------------*/ + for (j = 0; j < num_node; ++j) { + flag[j] = OFF; + } + for(j = 0; j < array_n(sepset_node_array); j++) { + node = array_fetch(node_t *, sepset_node_array, j); + idx = nodeindex_indexof(pld_nishiza_hash_table, node); + flag[idx] = ON; + } + + /* DFS to get all the intermediate nodes covered by current matching */ + /*-------------------------------------------------------------------*/ + node_array = array_alloc(node_t *, 0); + DFS_covered_node(sink, node_array, flag); + if(XLN_DEBUG){ + (void) printf("Cover(%d) = %s(%d) | ", i, node_long_name(sink), + nodeindex_indexof(pld_nishiza_hash_table, sink)); + print_array(node_array, pld_nishiza_hash_table); + } + + /* Insert an element for each node covered by this matching */ + /*----------------------------------------------------------*/ + for(j = 0; j < array_n(node_array); j++) { + node = array_fetch(node_t *, node_array, j); + idx = nodeindex_indexof(pld_nishiza_hash_table, node); + + /* Watch for the Vdd and GND node */ + if (node->type == INTERNAL && node_num_fanin(node) == 0) { + continue; + } + + (void) sm_insert(matrix, idx, 2 * i); + } + array_free(node_array); + + /* Each input of this matching should be an output of some other */ + /*---------------------------------------------------------------*/ + for(j = 0; j < array_n(sepset_node_array); j++) { + node = array_fetch(node_t *, sepset_node_array, j); + if (node->type == PRIMARY_INPUT) { + continue; + } + ++row_index; + + for(k = 0; k < array_n(sink_array); k++) { + sink_scan = array_fetch(node_t *, sink_array, k); + if (sink_scan == node) { + (void) sm_insert(matrix, row_index, 2 * k); + } + } + + /* If we do not pick up this matching, no problem */ + /*------------------------------------------------*/ + (void) sm_insert(matrix, row_index, 2 * i + 1); + } + + /* Set weight */ + /*------------*/ + weight[2 * i] = 1; + weight[2 * i + 1] = 0; + } + + /* Termination */ + /*-------------*/ + FREE(flag); + + +} + + + +/* + * partial_collapse_node() + * Collapse the given node until it reaches the separating set + */ + + +node_t * +partial_collapse_node(sink, sepset_node_array) + +node_t *sink; /* node to be collapsed */ +array_t *sepset_node_array; + /* array of nodes in separating set */ + +{ + + + int i, j; + int flag1; /* if ON, found a node which needs collapse */ + int flag2; /* if ON, this fanin is in separating set */ + node_t *sink_save; + node_t *node; + node_t *fanin; + + + /* Collapse the nodes */ + /*--------------------*/ + for(;;) { + sink_save = node_dup(sink); + flag1 = OFF; + if(XLN_DEBUG){ + (void) printf("( "); + } + foreach_fanin(sink_save, i, fanin) { + if(XLN_DEBUG){ + (void) printf("%s ", node_long_name(fanin)); + } + /* Check if this fanin node is in separating set */ + /*-----------------------------------------------*/ + for(flag2 = OFF, j = 0; j < array_n(sepset_node_array); j++) { + node = array_fetch(node_t *, sepset_node_array, j); + if (strcmp(node_long_name(fanin), node_long_name(node)) == 0) { + flag2 = ON; + break; + } + } + if (flag2 == OFF) { + flag1 = ON; + (void) node_collapse(sink, fanin); + } + } + if(XLN_DEBUG){ + (void) printf(") --> "); + } + node_free(sink_save); + if (flag1 == OFF) { + break; + } + } + if(XLN_DEBUG){ + (void) printf("end"); + } + return(sink); + +} + + + + +/* + * partial_collapse() + * Collapse some of the network and reorganize it according to the result + * of the technology mapping + */ + +network_t * +partial_collapse(sink_array, sepset_array) + +array_t *sink_array; /* array of sink nodes for all the matchings + * in the solution */ +array_t *sepset_array; /* array of pointers to arrays of separating + * sets for all the matchings in the solution */ + +{ + + + array_t *sepset_node_array; + /* array of nodes in the separating set */ + array_t *collapsed_node_array; + /* array of collapsed nodes */ + array_t *del_node_array;/* array of nodes to be deleted */ + /* array_t *dfs_array; */ /* array of sorted nodes */ + int i; + /* int j; */ + /* int flag; */ + node_t *sink; + node_t *col_node; /* collapsed node */ + + + /* Initialization */ + /*----------------*/ + collapsed_node_array = array_alloc(node_t *, 0); + del_node_array = array_alloc(node_t *, 0); + + /* For each sink node in the solution, collapse the node */ + /*-------------------------------------------------------*/ + for(i = 0; i < array_n(sink_array); i++) { + sink = array_fetch(node_t *, sink_array, i); + if(XLN_DEBUG){ + (void) printf("Node %s : ", node_long_name(sink)); + } + sepset_node_array = array_fetch(array_t *, sepset_array, i); + + col_node = partial_collapse_node(node_dup(sink), sepset_node_array); + if(XLN_DEBUG){ + (void) printf("\n"); + } + array_insert_last(node_t *, collapsed_node_array, col_node); + } + + /* Replace the sink nodes with the collapsed nodes */ + /*-------------------------------------------------*/ + for(i = 0; i < array_n(sink_array); i++) { + sink = array_fetch(node_t *, sink_array, i); + col_node = array_fetch(node_t *, collapsed_node_array, i); + node_replace(sink, col_node); + } + + /* Remove the nodes that are not sinks of the matching */ + /*-----------------------------------------------------*/ + /* + dfs_array = network_dfs_from_input(pld_nishiza_network); + for (i = 0; i < array_n(dfs_array); ++i) { + + node = array_fetch(node_t *, dfs_array, i); + if (node->type != INTERNAL) { + continue; + } + for(flag = OFF, j = 0; j < array_n(sink_array); j++) { + sink = array_fetch(node_t *, sink_array, j); + if (sink == node) { + flag = ON; + break; + } + } + if (flag == OFF) { + array_insert_last(node_t *, del_node_array, node); + } + } + for (i = 0; i < array_n(del_node_array); ++i) { + node = array_fetch(node_t *, del_node_array, i); + network_delete_node(pld_nishiza_network, node); + } + */ + /* Termination */ + /*-------------*/ + array_free(collapsed_node_array); + /* + array_free(dfs_array); + */ + array_free(del_node_array); + +} + + + + + + +/* + extern void partition_network(); + * partition_network() + * Partition the given network into universal logic modules + */ + + +void +partition_network(network_in, n, bincov_heuristics) + +network_t *network_in; +int n; +int bincov_heuristics; + +{ + + + lsGen gen, gen2; /* generator */ + node_t *node; + node_t *fanout; + array_t *match_sink_array; + /* array of sink nodes for all the matchings + * obtained so far */ + array_t *match_sepset_array; + /* array of pointers to arrays of separating + * sets for all the matchings obtained so far */ + array_t *sink_array; /* array of sink nodes for the matching + * for the current sink */ + array_t *sepset_array; /* array of pointers to arrays of separating + * sets for matchings for the current sink */ + array_t *sol_sink_array; + /* array of sink nodes for all the matchings + * in the solution */ + array_t *sol_sepset_array; + /* array of pointers to arrays of separating + * sets for all the matchings in the solution */ + char buf[BUFSIZE]; + sm_row *solution; /* solution of the binate covering problem */ + sm_element *element; /* element of sparse matrix */ + sm_matrix *matrix; /* sparse matrix for binate covering */ + int idx2; + int j; + int *weight; /* weight array for binate covering problem */ + int basic_num_rows; + node_t *sink, *pre_sink; + array_t *fetched_sepset; + FILE *binFile; + char bin_file[100]; + sm_row *sm_mat_bin_minimum_cover_my(); + int sfd; + + + ULM_INPUT_SIZE = n; + + foreach_node(network_in, gen, node) { + if (node_num_fanin(node) > ULM_INPUT_SIZE) { + (void) printf("Error: The network has a node with > %d fanins\n", ULM_INPUT_SIZE); + (void) printf("Run xl_imp (xl_ao) -n %d to decompose these nodes\n", ULM_INPUT_SIZE); + (void) lsFinish(gen); + return; + } + } + + /* Initialization */ + /*----------------*/ + pld_nishiza_network = network_in; + + match_sink_array = array_alloc(node_t *, 0); + match_sepset_array = array_alloc(array_t *, 0); + sol_sink_array = array_alloc(node_t *, 0); + sol_sepset_array = array_alloc(array_t *, 0); + pld_nishiza_graph = mf_alloc_graph(); + pld_nishiza_hash_table = nodeindex_alloc(); + matrix = sm_alloc(); + + /* Form a hash table from a node pointer to a row index */ + /*------------------------------------------------------*/ + foreach_node(pld_nishiza_network, gen, node) { + if (node->type == PRIMARY_OUTPUT) { + continue; + } + (void) nodeindex_insert(pld_nishiza_hash_table, node); + } + + construct_maxflow_network(); + + /* Obtain matchings for each intermediate nodes */ + /*----------------------------------------------*/ + foreach_node(pld_nishiza_network, gen, node) { + if (node->type != INTERNAL) { + continue; + } + /* Watch for the Vdd and GND node */ + if (node_num_fanin(node) == 0) { + (void) printf("%s has 0 fanin. Skipping.\n\n", node_long_name(node)); + continue; + } + sink_array = array_alloc(node_t *, 0); + sepset_array = array_alloc(array_t *, 0); + (void) sprintf(buf, "%s_bottom", node_long_name(node)); + mf_change_node_type(pld_nishiza_graph, mf_get_node(pld_nishiza_graph, buf), 2); + if(XLN_DEBUG){ + (void) printf("Generate matching for %s", node_long_name(node)); + } + foreach_fanout(node, gen2, fanout) { + if (fanout->type == PRIMARY_OUTPUT) { + if(XLN_DEBUG){ + (void) printf(" (PO: %s)", node_long_name(fanout)); + } + (void)lsFinish(gen2); + break; + } + } + if(XLN_DEBUG){ + (void) printf("\n"); + } + generate_matching(sink_array, sepset_array, array_n(match_sink_array)); + initialize_edge_capacity(); + + mf_change_node_type(pld_nishiza_graph, mf_get_node(pld_nishiza_graph, buf), 0); + array_append(match_sink_array, sink_array); + array_append(match_sepset_array, sepset_array); + + array_free(sink_array); + array_free(sepset_array); + } + + weight = ALLOC (int, 2 * array_n(match_sink_array)); + form_binate_matrix(network_in, matrix, weight, match_sink_array, match_sepset_array, &basic_num_rows); + if (XLN_DEBUG) { + (void)sprintf(bin_file, "/usr/tmp/xln_merge.bin_matrix.XXXXXX"); + sfd = mkstemp(bin_file); + if(sfd != -1) { + binFile = fdopen(sfd, "w"); + if (binFile != NULL) { + sm_print(binFile, matrix); + (void) fclose(binFile); + } + close(sfd); + } + } + if (bincov_heuristics != 4) { + solution = + sm_mat_bin_minimum_cover_greedy(matrix, weight, bincov_heuristics); + } else { + solution = sm_mat_bin_minimum_cover_my(matrix, weight, bincov_heuristics, basic_num_rows); + } + FREE(weight); + /* Extract the matchings and separating sets belonging to the solution */ + /*---------------------------------------------------------------------*/ + if(XLN_DEBUG){ + (void) printf("\nCover solution\n"); + } + for (pre_sink = NULL, element = solution->first_col; + element != NULL; element = element->next_col) { + if (element->col_num % 2 == 1) { + if(XLN_DEBUG){ + (void) printf("Cover(%d)'\n", (element->col_num - 1) / 2); + } + continue; + } + idx2 = element->col_num / 2; + sink = array_fetch(node_t *, match_sink_array, idx2); + + /* If this matching implements the same node again, discard it */ + /*-------------------------------------------------------------*/ + if (pre_sink == sink) { + continue; + } + fetched_sepset = array_fetch(array_t *, match_sepset_array, idx2); + if(XLN_DEBUG){ + (void) printf("Cover(%d) = %s(%d) | ", idx2, node_long_name(sink), + nodeindex_indexof(pld_nishiza_hash_table, sink)); + print_array(fetched_sepset, pld_nishiza_hash_table); + } + + array_insert_last(node_t *, sol_sink_array, sink); + array_insert_last(array_t *, sol_sepset_array, fetched_sepset); + pre_sink = sink; + } + if(XLN_DEBUG){ + (void) printf("\nCollapsing the nodes ...\n"); + } + partial_collapse(sol_sink_array, sol_sepset_array); + + /* Termination */ + /*-------------*/ + array_free(match_sink_array); + array_free(sol_sink_array); + for(j=array_n(match_sepset_array)-1; j>=0; j--){ + array_free(array_fetch(array_t*, match_sepset_array, j)); + } + array_free(match_sepset_array); + array_free(sol_sepset_array); + mf_free_graph(pld_nishiza_graph); + nodeindex_free(pld_nishiza_hash_table); + sm_free(matrix); + sm_row_free(solution); + + /* to delete those nodes that do not fanout anywhere */ + /*---------------------------------------------------*/ + (void) network_sweep(pld_nishiza_network); + if (network_check(pld_nishiza_network)); + else (void) printf(" %s\n", error_string()); +} + + + +sm_row * +sm_mat_bin_minimum_cover_greedy(matrix, weight, bincov_heuristics) +sm_matrix *matrix; +int *weight; +int bincov_heuristics; + +{ + sm_row *solution; + sm_row *sm_generate_row(); + sm_matrix *matrix_dup; + + + if (bincov_heuristics <= 1) + return sm_mat_bin_minimum_cover(matrix, weight, + bincov_heuristics, 0, 0, 6176, NULL); + + /* if bincov_heuristic is 3 (default) => if num_cols <= 40 => go for the exact solution. + else apply greedy heuristic.(-h 2) */ + /*------------------------------------------------------------------------------------*/ + if ((bincov_heuristics == 3) && (matrix->ncols <= 40)) + return sm_mat_bin_minimum_cover(matrix, weight, + 0, 0, 0, 6176, NULL); + + /* Else apply a simple heuristic for the cover. + Find the column that covers the maximum number of rows, + select it in the cover, change the matrix,ie, + delete the rows that are covered by this column, + delete the column corresponding to the matchbar. */ + /*--------------------------------------------------*/ + + solution_array = array_alloc(int, 0); + matrix_dup = sm_dup(matrix); + + /* select columns; selected column nums returned in solution_array*/ + /* ---------------------------------------------------------------*/ + select_column_and_update_matrix(matrix_dup); + solution = sm_generate_row(solution_array); + + sm_free(matrix_dup); + array_free(solution_array); + + return solution; +} + +/**************************************************************************** + Get the column with the maximum number of elements in the matrix. +******************************************************************************/ + +sm_col * +get_column_with_max_elements(matrix) +sm_matrix *matrix; +{ + sm_col *pcol; + sm_col *best_col; + int MAX_ELEMENTS; + int colnum; + int COLUMNS_REMAIN; /* for the condition when only match bar columns remain */ + + MAX_ELEMENTS = 0; + COLUMNS_REMAIN = 0; + + for (pcol = matrix->first_col; pcol != 0; pcol = pcol->next_col) { + colnum = pcol->col_num; + if (colnum % 2 == 1) continue; + COLUMNS_REMAIN = 1; + if (pcol->length < MAX_ELEMENTS) continue; + best_col = pcol; + MAX_ELEMENTS = pcol->length; + } + if (COLUMNS_REMAIN == 0) { + (void) printf("get_column_with_max_elements(): no valid columns remain ->error\n"); + exit(1); + } + + if (XLN_DEBUG) + (void) printf("max_elements in %d (%d)\n", best_col->col_num, best_col->length); + return best_col; + +} + +/************************************************************************************ + It selects one column at a time, deletes the covered rows and then recursively + calls itself. Finally a covre of the matrix is obtained. The matrix changes + everytime. Final answer is in the array solution_array. Contains the column numbers + of all the selected columns in the cover. +************************************************************************************/ +select_column_and_update_matrix(matrix) + sm_matrix *matrix; +{ + + array_t *row_array; /* matrix for the rows every time */ + sm_col *best_col, *next_best_col; + sm_col *get_column_with_max_elements(); + sm_row *prow; + int best_colnum; + int i; + int num_covered_rows; + int DELETE_FLAG; /* flag for checking if the best_col's complement needs deletion*/ + + if (XLN_DEBUG) + (void) printf("select_col_and_up.. num_rows = %d, num_columns = %d\n", matrix->nrows, matrix->ncols); + + if (matrix->ncols == 0 || matrix->nrows == 0) return; + + DELETE_FLAG = 0; + row_array = array_alloc(sm_row *, 0); + + best_col = get_column_with_max_elements(matrix); + best_colnum = best_col->col_num; + + /* the complement of the best_col, if present */ + /*--------------------------------------------*/ + next_best_col = best_col->next_col; + if (next_best_col == 0); + else { + if (next_best_col->col_num == best_colnum + 1) DELETE_FLAG = 1; + } + + if (XLN_DEBUG) (void) printf("best column = %d\n", best_colnum); + + /* remember the column number of the best column */ + /*-----------------------------------------------*/ + array_insert(int, solution_array, array_n(solution_array), best_colnum); + + /* find the rows covered by the best_col */ + /*---------------------------------------*/ + for (prow = matrix->first_row; prow != 0; prow = prow->next_row) { + if (sm_find(matrix, prow->row_num, best_col->col_num) == 0) continue; + array_insert(sm_row *, row_array, array_n(row_array), prow); + if (XLN_DEBUG) + (void) printf("inserting row %d in row_array\n", prow->row_num); + } + num_covered_rows = array_n(row_array); + + /* delete the column and its complement, if there in the matrix */ + /* actually no need to delete the column but still deleting. */ + /*--------------------------------------------------------------*/ + sm_delcol(matrix, best_colnum); + if (DELETE_FLAG) sm_delcol(matrix, next_best_col->col_num); + + + /* delete the covered rows from the matrix. */ + /*------------------------------------------*/ + for (i = 0; i < num_covered_rows; i++) { + prow = array_fetch(sm_row *, row_array, i); + sm_delrow(matrix, prow->row_num); + } + array_free(row_array); + + if (XLN_DEBUG) sm_print(stdout, matrix); + + select_column_and_update_matrix(matrix); +} + +/********************************************************************************** + From the solution array, generate the sm_row which has an entry for each match + in the binate cover. +***********************************************************************************/ +sm_row * +sm_generate_row(solution_array) + array_t *solution_array; +{ + sm_row *solution; /* answer to the binate covering problem */ + int i, colnum; + int num_solution; /* number of matches found by the heuristic */ + + solution = sm_row_alloc(); + + num_solution = array_n(solution_array); + for (i = 0; i < num_solution; i++){ + colnum = array_fetch(int, solution_array, i); + (void) sm_row_insert(solution, colnum); + } + return solution; +} + +/*--------------------------------------------------------------------------- + Form a matrix (matrix_basic) that is all matches + the first rows upto the + basic_num_rows. Solve a unate covering problem on this matrix. All the + columns selected are deleted, so are their complements. All the rows of + matrix (original one) that are covered by these columns are also deleted. + What to do on this small matrix? +----------------------------------------------------------------------------*/ +sm_row * +sm_mat_bin_minimum_cover_my(matrix, weight, bincov_heuristic, + basic_num_rows) + sm_matrix *matrix; + int *weight, bincov_heuristic, basic_num_rows; + +{ + sm_matrix *matrix_basic, *matrix_nonbasic; + sm_row *row, *row_solution_basic, *row_solution_nonbasic; + sm_col *col, *odd_col; + sm_element *p; + array_t *col_array, *row_array; + st_table *table; + int i; + + /* + if (bincov_heuristic != 4) { + row = sm_mat_bin_minimum_cover_greedy(matrix, weight, bincov_heuristic); + return row; + } + */ /* commented because want to try right now my heuristic */ + /* forming matrix_basic */ + /*----------------------*/ + matrix_basic = sm_alloc(); + matrix_nonbasic = sm_alloc(); + + /* first add basic rows */ + /*----------------------*/ + for (row = matrix->first_row; row != 0; row = row->next_row) { + if (row->row_num < basic_num_rows) { + sm_copy_row(matrix_basic, row->row_num, row); + } else { + sm_copy_row(matrix_nonbasic, row->row_num, row); + } + } + /* now delete odd columns */ + /*------------------------*/ + col_array = array_alloc(sm_col *, 0); + for (col = matrix_basic->first_col; col != 0; col = col->next_col) { + if (col->col_num % 2 == 1) { + array_insert_last(sm_col *, col_array, col); + } + } + for (i = 0; i < array_n(col_array); i++) { + col = array_fetch(sm_col *, col_array, i); + sm_delcol(matrix_basic, col->col_num); + } + array_free(col_array); + + /* solve a unate covering problem on matrix_basic - use a different flag here */ + /*----------------------------------------------------------------------------*/ + row_solution_basic = sm_minimum_cover(matrix_basic, NIL (int), bincov_heuristic, XLN_DEBUG); + + /* check that the elements are from even columns of matrix */ + /*---------------------------------------------------------*/ + assert(xln_seq_check_row_elements_even(row_solution_basic)); + + /* form matrix for the rest of the operations */ + /*--------------------------------------------*/ + row_array = array_alloc(sm_row *, 0); + for (row = matrix_nonbasic->first_row; row != 0; row = row->next_row) { + if (sm_row_intersects(row, row_solution_basic)) { + array_insert_last(sm_row *, row_array, row); + } + } + for (i = 0; i < array_n(row_array); i++) { + row = array_fetch(sm_row *, row_array, i); + sm_delrow(matrix_nonbasic, row->row_num); + } + array_free(row_array); + + /* now delete columns that are in row_solution_basic and their complements */ + /*-------------------------------------------------------------------------*/ + col_array = array_alloc(sm_col *, 0); + sm_foreach_row_element(row_solution_basic, p) { + assert(col = sm_get_col(matrix, p->col_num)); + assert(col->col_num % 2 == 0); + array_insert_last(sm_col *, col_array, col); + odd_col = col->next_col; + if (odd_col && (odd_col->col_num == col->col_num + 1)) { + array_insert_last(sm_col *, col_array, col->next_col); + } + } + sm_delete_cols_in_array(matrix_nonbasic, col_array); + array_free(col_array); + + /* select greedily the columns from matrix_nonbasic */ + /*--------------------------------------------------*/ + table = st_init_table(st_numcmp, st_numhash); + row_solution_nonbasic = sm_row_alloc(); + xln_seq_table_of_rows_covered_by_odd_columns(matrix_nonbasic, table); + sm_mat_bin_minimum_cover_nonbasic(matrix_nonbasic, row_solution_nonbasic, table); + st_free_table(table); + + /* combine the basic solution with the nonbasic solution */ + /*-------------------------------------------------------*/ + sm_foreach_row_element(row_solution_nonbasic, p) { + sm_row_insert(row_solution_basic, p->col_num); + } + + sm_row_free(row_solution_nonbasic); + sm_free(matrix_basic); + sm_free(matrix_nonbasic); + + return row_solution_basic; +} + +/*------------------------------------------------------------------ + Returns 1 if all the elements of row have even column numbers. +-------------------------------------------------------------------*/ +int +xln_seq_check_row_elements_even(row) + sm_row *row; +{ + sm_element *p; + + sm_foreach_row_element(row, p) { + if (p->col_num % 2 == 1) return 0; + } + return 1; +} + +/*-------------------------------------------------------------------- + If all the rows of the matrix can be covered by odd columns of the + matrix, insert all the odd columns in the solution. Else + find greedily an even column (with max score), add it to the current + solution, delete the rows it covers and delete it too, along + with its odd column. Recursively calls itself. +---------------------------------------------------------------------*/ +sm_mat_bin_minimum_cover_nonbasic(matrix, row_solution, table) + sm_matrix *matrix; + sm_row *row_solution; + st_table *table; /* initially stores the rows that have not been covered - + assumes that even columns presented in matrix are + not selected */ +{ + sm_col *best_col, *sm_get_even_column_with_max_score(), *col, *odd_col; + sm_element *p; + char *value; + + /* check if all the rows of matrix can be covered by odd columns */ + /*---------------------------------------------------------------*/ + if (matrix->nrows == st_count(table)) { + /* insert all the odd-column entries in the solution */ + /*---------------------------------------------------*/ + sm_foreach_col(matrix, col) { + if (col->col_num %2 == 1) { + sm_row_insert(row_solution, col->col_num); + } + } + return; + } + + best_col = sm_get_even_column_with_max_score(matrix); + if (!best_col) return; + sm_row_insert(row_solution, best_col->col_num); + odd_col = best_col->next_col; + if (odd_col && (odd_col->col_num == best_col->col_num + 1)) { + /* delete the rows from the table that were covered by odd_column */ + /*----------------------------------------------------------------*/ + sm_foreach_col_element(odd_col, p) { + assert(st_delete_int(table, &(p->row_num), &value)); + } + } + /* delete the rows that this column covers */ + /*-----------------------------------------*/ + sm_delete_rows_covered_by_col(matrix, best_col); + + sm_delcol(matrix, best_col->col_num); + if (odd_col && (odd_col->col_num == best_col->col_num + 1)) { + sm_delcol(matrix, odd_col->col_num); + } + sm_mat_bin_minimum_cover_nonbasic(matrix, row_solution, table); +} + + +/*----------------------------------------------------------------------- + Score of each even column is num_elements - num_elements of the next + column. Return the column with max score. +-----------------------------------------------------------------------*/ +sm_col * +sm_get_even_column_with_max_score(matrix) +sm_matrix *matrix; +{ + sm_col *pcol, *next_col, *best_col; + int max_score, score; + int colnum; + + best_col = NIL (sm_col); + max_score = - MAXINT; + + for (pcol = matrix->first_col; pcol != 0; pcol = pcol->next_col) { + colnum = pcol->col_num; + if (colnum % 2 == 1) continue; + /* next_col may not be the next_col of the original matrix */ + /*---------------------------------------------------------*/ + next_col = pcol->next_col; + if (next_col && (next_col->col_num == colnum + 1)) { + score = pcol->length - next_col->length; + } else { + score = pcol->length; + } + if (score < max_score) continue; + best_col = pcol; + max_score = score; + } + if (XLN_DEBUG) { + (void) printf("max score of %d (%d)\n", best_col->col_num, max_score); + } + return best_col; +} + +/*------------------------------------------------------------- + Fills table with row numbers of all the rows covered by the + odd numbered columns of matrix. +---------------------------------------------------------------*/ +xln_seq_table_of_rows_covered_by_odd_columns(matrix, table) + sm_matrix *matrix; + st_table *table; +{ + sm_col *col; + sm_element *p; + + sm_foreach_col(matrix, col) { + if (col->col_num %2 == 1) { + sm_foreach_col_element(col, p) { + assert(!st_insert(table, (char *) p->row_num, (char *) p->row_num)); + } + } + } +} + + + diff --git a/sis/pld/xln_merge.c b/sis/pld/xln_merge.c new file mode 100644 index 0000000..075e6c5 --- /dev/null +++ b/sis/pld/xln_merge.c @@ -0,0 +1,429 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_merge.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2005/03/08 05:31:12 $ + * + */ + +/* March 30, 1992 - Added a heuristic to run merge without lindo. + - Added a routine that collapses nodes after merging is done. + This was to exploit the case when the network is 4-feasible. +*/ + +/* + * merge.c + * ******* + * + * Copyright (C) 1989 Yoshihito Nishizaki + * University of California, Berkeley + * + * Author: Advising professor: + * Yoshihito Nishizaki Alberto Sangiovanni-Vincentelli + * + * -------------------------------------------------------------------------- + * + * This file contains routines for merging cells into one unit block + * by max cardinality matching method. + * + * functions contained in this file: + * merge_node() + * + * + * Import descriptions: + * sis.h : macros for misII + * ULM_int.h : macros for universal logic module package + * + */ + +#include "sis.h" +#include "pld_int.h" + + + + +/* + * merge_node() + * + * DESCRIPTION + * ----------- + * Merge two (or more) intermediate nodes in the graph into one ULM node. + * Formulate the problem as an integer programming problem + * and solve it by Lindo linear programming package. + * + * This problem should be formulated as a max cardinality matching of a + * general graph, if the # nodes to be merged is 2. + * But for the generality of the routine, we use integer programming. + * This does not depend on the number of nodes to be merged. + * + * RETURNS + * ------- + * None + * + * Arguments: + * --------- + * network : pointer to a network + * + * Local variables: + * --------------- + * gen : generator + * cand_node_array : array of candidate node for merging + * fanin_array : array of pointers to an array of fanin nodes a node + * fanin_nodes : pointer to an array of fanin nodes + * fanin1 : pointer to an array of fanin nodes + * fanin2 : pointer to an array of fanin nodes + * node : pointer to a node in the network + * fanin : pointer to a fanin node of a node in the network + * node1 : pointer to a node in the network + * node2 : pointer to a node in the network + * intsec : size of intersection of two sets + * union : size of union of two sets + * match1_array : array of pointers to left side nodes in the mathing + * match2_array : array of pointers to right side nodes in the mathing + * + * Possible errors: + * --------------- + * + * SIDE-EFFECTS + * ------------ + * None + * + * GLOBAL VARIABLES + * ---------------- + * None + * + */ + + +extern void merge_node(); +void +merge_node(network, MAX_FANIN, MAX_COMMON_FANIN, MAX_UNION_FANIN, filename, verbose, use_lindo, + match1_array, match2_array) + +network_t *network; +int MAX_FANIN, MAX_COMMON_FANIN, MAX_UNION_FANIN; +char *filename; +int verbose, use_lindo; +array_t *match1_array, *match2_array; +{ + + lsGen gen; + array_t *cand_node_array; + array_t *fanin_array; + array_t *fanin_nodes; + array_t *fanin1, *fanin2; + node_t *node, *fo; + node_t *fanin; + node_t *node1, *node2; + int i, j; + int num_intsec; + int num_union; + sm_matrix *coeff; + int col; + int num_match; + char *merge_file; + char *buf; + FILE *mergeFile, *outputFile; + char *lindopathname, *lindo_in, *lindo_out; + int sfd; + + + /* search for lindo in the path name. If not found, return */ + /*---------------------------------------------------------*/ + if (use_lindo) { + lindopathname = util_path_search("lindo"); + if (lindopathname == NULL) { + (void) printf("YOU DO NOT HAVE LINDO INTEGER PROGRAMMING PACKAGE\n"); + (void) printf("\tIN YOUR PATH.\n\n"); + (void) printf("PLEASE OBTAIN LINDO FROM\n\n"); + (void) printf("\tThe Scientific Press, 540 University Ave.\n"); + (void) printf("\tPalo Alto, CA 94301, USA\n"); + (void) printf("\tTEL : (415) 322-5221\n"); + (void) printf("USING A HEURISTIC INSTEAD.....\n"); + use_lindo = 0; + } else { + FREE(lindopathname); + } + } + /* Initialization */ + /*----------------*/ + cand_node_array = array_alloc(node_t *, 0); + fanin_array = array_alloc(array_t *, 0); + coeff = sm_alloc(); + + /* Extract the intermediate nodes with fanins <= MAX_FANIN */ + /*---------------------------------------------------------*/ + foreach_node(network, gen, node) { + if (node->type != INTERNAL) { + continue; + } + if (node_num_fanin(node) > MAX_FANIN) { + continue; + } + array_insert_last(node_t *, cand_node_array, node); + fanin_nodes = array_alloc(char *, 0); + array_insert_last(array_t *, fanin_array, fanin_nodes); + + /* Save each fanin of this node and sort them */ + /*--------------------------------------------*/ + foreach_fanin(node, i, fanin) { + array_insert_last(char *, fanin_nodes, (char *)fanin); + } + array_sort(fanin_nodes, comp_ptr); + } + + /* Check every mergeable combination of intermediate nodes */ + /*---------------------------------------------------------*/ + for(i = 0, col = 0; i < array_n(cand_node_array); i++) { + node1 = array_fetch(node_t *, cand_node_array, i); + fanin1 = array_fetch(array_t *, fanin_array, i); + + for(j = i + 1; j < array_n(cand_node_array); j++) { + node2 = array_fetch(node_t *, cand_node_array, j); + fanin2 = array_fetch(array_t *, fanin_array, j); + + count_intsec_union(fanin1, fanin2, &num_intsec, &num_union); + if (num_intsec <= MAX_COMMON_FANIN && + num_union <= MAX_UNION_FANIN) { + (void) sm_insert(coeff, i, col); + (void) sm_insert(coeff, j, col); + ++col; + + /* + print_fanin(node1); + print_fanin(node2); + (void) printf("Node %s and node %s are mergeable\n", + node_long_name(node1), node_long_name(node2)); + */ + } + } + } + if(XLN_DEBUG){ + merge_file = ALLOC(char, 100); + (void)sprintf(merge_file, "/usr/tmp/xln.merge.merge_matrix.XXXXXX"); + sfd = mkstemp(merge_file); + FREE(merge_file); + if(sfd == -1) { + (void) fprintf(siserr, "cannot open temp file\n"); + } + else { + mergeFile = fdopen(sfd, "w"); + if(mergeFile != NULL) { + sm_print(mergeFile, coeff); + (void) fclose(mergeFile); + } else { + (void) fprintf(siserr, "No space for mergeFile to be written \n"); + } + } + } + + outputFile = fopen(filename, "w"); + + /* either lindo not available or user did not choose lindo option - use a heuristic to solve + maximum cardinality matching problem */ + /*------------------------------------------------------------------------------------------*/ + if (!use_lindo) { + xln_merge_nodes_without_lindo(coeff, cand_node_array, match1_array, match2_array); + num_match = array_n(match1_array); + + } else { + + /* Solve max cardinality matching problem by lindo to get the best merge */ + /*-----------------------------------------------------------------------*/ + lindo_in = formulate_Lindo(coeff); + lindo_out = ALLOC(char, 1000); + buf = ALLOC(char, 500); + (void) sprintf(lindo_out, "/usr/tmp/merge.lindo.out.XXXXXX"); + sfd = mkstemp(lindo_out); + if(sfd != -1) { + close(sfd); + (void) sprintf(buf, "lindo < %s > %s", lindo_in, lindo_out); + (void) system(buf); + + /* Print the results */ + /*-------------------*/ + num_match = get_Lindo_result(cand_node_array, coeff, + match1_array, match2_array, lindo_out, outputFile); + } + FREE(lindo_in); + FREE(buf); + FREE(lindo_out); + } + if (verbose) (void) printf("Total number of matchings = %d\n\n", num_match); + + (void) fprintf(outputFile, "Merging two CLB's into one CLB\n"); + if (verbose) (void) printf("Merging two CLB's into one CLB\n"); + for(i = 0; i < array_n(match1_array); i++) { + node1 = array_fetch(node_t *, match1_array, i); + node2 = array_fetch(node_t *, match2_array, i); + if (io_po_fanout_count(node1, &fo) == 1) { + node1 = fo; + } + if (io_po_fanout_count(node2, &fo) == 1) { + node2 = fo; + } + (void) fprintf(outputFile, "Merge node %s and %s\n", + node_long_name(node1), node_long_name(node2)); + if (verbose) (void) printf("Merge node %s and %s\n", + node_long_name(node1), node_long_name(node2)); + } + (void) fprintf(outputFile, "\n# of CLB's = %d\n", network_num_internal(network) - num_match); + if (verbose) (void) printf("\n# of CLB's = %d\n", network_num_internal(network) - num_match); + (void) fclose (outputFile); + + /* Termination */ + /*-------------*/ + array_free(cand_node_array); + for(j=array_n(fanin_array)-1; j>=0; j--){ + array_free(array_fetch(array_t *, fanin_array, j)); + } + array_free(fanin_array); + sm_free(coeff); + +} + + +/*---------------------------------------------------------------------------------------------------- + An alternate to lindo option. Uses greedy merging. A node with minimum mergeable nodes is picked + first. It is combined with a neighbor node that has minimum number of neighbors. The pairs of + matches are stored in corresponding entries of match1_array and match2_array. +-----------------------------------------------------------------------------------------------------*/ +xln_merge_nodes_without_lindo(coeff, cand_node_array, match1_array, match2_array) + sm_matrix *coeff; + array_t *cand_node_array, *match1_array, *match2_array; +{ + node_t *n1, *n2; + sm_row *row1, *row2; + static sm_row *xln_merge_find_neighbor_of_row1_with_minimum_neighbors(); + + while (TRUE) { + row1 = sm_shortest_row(coeff); + if (row1 == NIL (sm_row)) return; + n1 = array_fetch(node_t *, cand_node_array, row1->row_num); + row2 = xln_merge_find_neighbor_of_row1_with_minimum_neighbors(row1, coeff); + n2 = array_fetch(node_t *, cand_node_array, row2->row_num); + array_insert_last(node_t *, match1_array, n1); + array_insert_last(node_t *, match2_array, n2); + xln_merge_update_neighbor_info(coeff, row1, row2); + } +} + +sm_row * +sm_shortest_row(A) + sm_matrix *A; +{ + register sm_row *short_row, *prow; + register int min_length; + + min_length = MAXINT; + short_row = NIL(sm_row); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->length < min_length) { + min_length = prow->length; + short_row = prow; + } + } + return short_row; +} + +static sm_row * +xln_merge_find_neighbor_of_row1_with_minimum_neighbors(row1, coeff) + sm_row *row1; + sm_matrix *coeff; +{ + sm_row *row, *row2; + sm_element *p; + int min_neighbr; + + min_neighbr = MAXINT; + row2 = NIL (sm_row); + + /* each column has two elements */ + /*------------------------------*/ + sm_foreach_row_element(row1, p) { + if (p->prev_row == NIL (sm_element)) { + row = sm_get_row(coeff, (p->next_row)->row_num); + } else { + row = sm_get_row(coeff, (p->prev_row)->row_num); + } + if (row->length < min_neighbr) { + min_neighbr = row->length; + row2 = row; + } + } + assert (row2); + return row2; +} + +xln_merge_update_neighbor_info(coeff, row1, row2) + sm_matrix *coeff; + sm_row *row1, *row2; +{ + sm_delete_cols_covered_by_row(coeff, row1); + sm_delete_cols_covered_by_row(coeff, row2); + sm_delrow(coeff, row1->row_num); + sm_delrow(coeff, row2->row_num); +} + +/*------------------------------------------------------------------------------------- + There may be cases where after merge, a node can be collapsed into its fanouts without + destroying the feasibility of the network. Returns the rest of the nodes of the network + that are not present in match1_array or match2_array. +---------------------------------------------------------------------------------------*/ +st_table * +xln_collapse_nodes_after_merge(network, match1_array, match2_array, support, verbose) + network_t *network; + array_t *match1_array, *match2_array; + int support, verbose; +{ + st_table *table; + array_t *nodevec; /* stores the nodes that are collapsed, so that they can be deleted later */ + int i, OK_to_collapse, is_collapsed; + node_t *node; + st_generator *stgen; + char *dummy, *dummy1; + + table = pld_insert_intermediate_nodes_in_table(network); + pld_delete_array_nodes_from_table(table, match1_array); + pld_delete_array_nodes_from_table(table, match2_array); + nodevec = array_alloc(node_t *, 0); + st_foreach_item(table, stgen, (char **)&node, &dummy) { + OK_to_collapse = xln_merge_are_fanouts_in_table(table, node); + if (OK_to_collapse) { + is_collapsed = xln_do_trivial_collapse_node_without_moving(node, support); + if (is_collapsed > 0) { + array_insert_last(node_t *, nodevec, node); + } + } + } + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + assert(st_delete(table, (char **) &node, &dummy1)); + network_delete_node(network, node); + } + if (verbose) { + (void) printf("deleted %d nodes in the final collapse, final CLBs = %d\n", array_n(nodevec), + network_num_internal(network) - array_n(match1_array)); + } + array_free(nodevec); + return(table); +} + +int +xln_merge_are_fanouts_in_table(table, node) + st_table *table; + node_t *node; +{ + lsGen gen; + node_t *fanout; + + if (node->type == PRIMARY_INPUT || node->type == PRIMARY_OUTPUT) return 0; + foreach_fanout(node, gen, fanout) { + if (!st_is_member(table, (char *) fanout)) return 0; + } + return 1; +} + + diff --git a/sis/pld/xln_move_d.c b/sis/pld/xln_move_d.c new file mode 100644 index 0000000..fa475a8 --- /dev/null +++ b/sis/pld/xln_move_d.c @@ -0,0 +1,114 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_move_d.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:56 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +/*--------------------------------------------------------------------------- + This file carries routines that move fanins f around of a node n + that are not critical. f is made a fanin of g (a fanin of n) that + is feasible and has some vacancy in it. This is done by collapsing g + into n, then look for a decomposition (roth-karp) with bound set that includes + {fanins of g different from the ones of n} U {f}. If number of equivalence + classes is 2, you can do it!!! g has to be a single fanout node, not a PI. + + Notes: + 1) Assumes that a delay trace has been done on the network. + + 2) We are restricting ourselves by looking at only disjoint decomposition. + + 3) Of course, we are ignoring the possibility of collapsing some other node + into g later. Difficult to take into account. +-------------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------------- + Moves fanins of the critical nodes as much as possible, ie, tries to have + as few fanins there as possible. If init_delay_trace is 1, does a delay trace + first. +---------------------------------------------------------------------------------*/ +xln_network_move_fanins_for_delay(network, init_param, init_delay_trace) + network_t *network; + xln_init_param_t *init_param; + int init_delay_trace; +{ + array_t *nodevec; + int i; + node_t *node; + int support; + int MAX_FANINS; /* do not move fanins if number of fanins of node exceeds this */ + int bound_alphas; + + if (init_param->xln_move_struct.MOVE_FANINS == 0) return; + + support = init_param->support; + MAX_FANINS = init_param->xln_move_struct.MAX_FANINS; + bound_alphas = init_param->xln_move_struct.bound_alphas; + + nodevec = network_dfs(network); + if (init_delay_trace) assert(delay_trace(network, DELAY_MODEL_UNIT)); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (!xln_is_node_critical(node, (double) 0)) continue; + /* move as much as possible - takes care that a non-critical fanin does not + become over-critical */ + /*----------------------------------------------------------------------------*/ + (void) xln_node_move_fanins_for_delay(node, support, MAX_FANINS, + MAXINT, bound_alphas); + } + array_free(nodevec); +} + +int +xln_node_move_fanins_for_delay(node, support, MAX_FANINS, diff, bound_alphas) + node_t *node; + int support, MAX_FANINS; + int diff; /* if 0, then from infeasible to feasible, else just moving fanins as + much as diff wants */ + int bound_alphas; +{ + int infeasibility; + int improvement; + int i, num_fanin; + node_t *f; + array_t *faninvec; + int moved; + + if (node->type != INTERNAL) return 0; + num_fanin = node_num_fanin(node); + + if (num_fanin > MAX_FANINS) return 0; + if (diff == 0) { + infeasibility = num_fanin - support; + if (infeasibility <= 0) return 0; + } else { + infeasibility = diff; + } + + faninvec = pld_get_array_of_fanins(node); + + /* try each f in faninvec for moving */ + /*-----------------------------------*/ + improvement = 0; + for (i = 0; i < array_n(faninvec); i++) { + f = array_fetch(node_t *, faninvec, i); + if (xln_is_node_critical(f, (double) 0)) continue; + moved = xln_node_move_fanin(node, f, support, bound_alphas, DELAY); + if (moved) { + /* need this, since a non-critical node may become critical */ + /*----------------------------------------------------------*/ + assert(delay_trace(node->network, DELAY_MODEL_UNIT)); + improvement++; + } + if (improvement == infeasibility) break; + } + array_free(faninvec); + return improvement; +} + + diff --git a/sis/pld/xln_new_part.c b/sis/pld/xln_new_part.c new file mode 100644 index 0000000..44221d7 --- /dev/null +++ b/sis/pld/xln_new_part.c @@ -0,0 +1,367 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_new_part.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:57 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +extern int XLN_DEBUG; + +struct sol_struct { + int value; + node_t *in, *out; +}; +typedef struct sol_struct sol_t; + +static int cost_fanin(); +static int composite_fanin(); + +/* new improved routine: hopefully better, faster and smoother */ +imp_part_network(network, size, MOVE_FANINS, MAX_FANINS) +network_t *network; +int size; +int MOVE_FANINS; +int MAX_FANINS; +{ + int no_nodes; + int i, xln_comp(), l; + node_t *node, *fi, *fo; + sol_t *sol; + lsGen gen, gen1; + st_table *table; + array_t *cover, *array_disjoint(); + array_t *values; + int changed; + + changed = 1; + while(changed){ + changed = 0; + if (xln_do_trivial_collapse_network(network, size, MOVE_FANINS, MAX_FANINS)) + changed = 1; + no_nodes = network_num_internal(network); + table = st_init_table(st_ptrcmp, st_ptrhash); + l = 0; + values = array_alloc(sol_t *, 0); + foreach_node(network, gen, node){ + if((node_function(node) == NODE_PI)||(node_function(node) == NODE_PO)) continue; + st_insert(table, (char *)node, (char *)l); + l++; + foreach_fanin(node, i, fi){ + if(node_function(fi) == NODE_PI) continue; + if(composite_fanin(node, fi) <= size){ + sol = ALLOC(sol_t, 1); + sol->in = fi; + sol->out = node; + sol->value = 0; + foreach_fanout(fi, gen1, fo){ + sol->value += cost_fanin(fo, fi); + } + (void)array_insert_last(sol_t *, values, sol); + } + } + } + + if(array_n(values) == 0) { + array_free(values); + continue; + } + array_sort(values, xln_comp); + cover = array_disjoint(values, no_nodes, table); + changed = 1; + if(array_n(cover) == 0){ + (void)error_init(); + (void)error_append("array values was not zero, disjoint array is\n"); + assert(0); + } + for(i = 0; i < array_n(cover); i++){ + sol = array_fetch(sol_t *, cover, i); + fi = sol->in; + node = sol->out; + if(composite_fanin(node, fi) <= size){ + if(node_collapse(node, fi)){ + if(XLN_DEBUG > 1){ + (void)fprintf(sisout, "collapsed %s into %s\n", + node_long_name(fi), node_long_name(node)); + } + } + else { + (void) printf("could not collapse %s into %s\n", + node_long_name(fi), node_long_name(node)); + exit(1); + } + } + else { + (void) printf("composite fanin of (%s, %s) > %d\n", + node_long_name(fi), node_long_name(node), size); + exit(1); + } + } + st_free_table(table); + for(i = 0; i < array_n(cover); i++){ + sol = array_fetch(sol_t *, cover, i); + FREE(sol); + } + array_free(cover); + array_free(values); + network_sweep(network); + } +} + + +array_t * +array_disjoint(a, s, t) +array_t *a; +int s; +st_table *t; +{ + int i, *n_out; + int j, k; + array_t *new_a; + sol_t *sol; + char *dummy; + + n_out = ALLOC(int, s); + for( i = 0; i < s; i++){ + n_out[i] = 0; + } + + new_a = array_alloc(sol_t *, 0); + for(i = 0; i < array_n(a); i++){ + sol = array_fetch(sol_t *, a, i); + if(st_lookup(t, (char *)sol->in, &dummy)){ + (void)error_init(); + (void)error_append("Hello node number not found\n"); + } + j = (int )dummy; + if(st_lookup(t, (char *)sol->out, &dummy)){ + (void)error_init(); + (void)error_append("Hello node number not found\n"); + } + k = (int )dummy; + (void)error_init(); + (void)error_append("index size out of array\n"); + assert(j < s); + assert(k < s); + if((n_out[j] == 0)&&(n_out[k] == 0)){ + array_insert_last(sol_t *, new_a, sol); + n_out[k] = 1; + }else{ + FREE(sol); + } + } + FREE(n_out); + return new_a; +} + + + + +int +xln_comp(o1, o2) +sol_t **o1, **o2; +{ + sol_t *sol1, *sol2; + sol1 = *o1; + sol2 = *o2; + + if(sol1->value == sol2->value) return 0; + if(sol1->value > sol2->value) return 1; + return -1; +} + +/*------------------------------------------------------------------------------ + Collapsing nodes which can be collapsed into all their fanouts without + getting any infeasibilities. The nodes collapsed are deleted from the network. + Returns the number of collapsed nodes. +-------------------------------------------------------------------------------*/ +int +xln_do_trivial_collapse_network(network, size, MOVE_FANINS, MAX_FANINS) +network_t *network; +int size; +int MOVE_FANINS; /* if want to move fanins */ +int MAX_FANINS; +{ + int num_collapsed; + int changed; + int num_collapsed_iter; + + num_collapsed = 0; + changed = 1; + while (changed) { + num_collapsed_iter = + xln_do_trivial_collapse_network_one_iter(network, size, + MOVE_FANINS, MAX_FANINS); + num_collapsed += num_collapsed_iter; + changed = num_collapsed_iter; + } + if (XLN_DEBUG > 1) { + (void) printf("---collapsed %d nodes in trivial collapse\n", num_collapsed); + } + return num_collapsed; +} + +int +xln_do_trivial_collapse_network_one_iter(network, size, MOVE_FANINS, MAX_FANINS) +network_t *network; +int size; +int MOVE_FANINS; /* if want to move fanins */ +int MAX_FANINS; +{ + int num_collapsed; + int is_collapsed; + int i; + array_t *nodevec; + node_t *node; + + num_collapsed = 0; + nodevec = network_dfs(network); + + for(i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + is_collapsed = xln_do_trivial_collapse_node(node, size, MOVE_FANINS, MAX_FANINS); + if (is_collapsed == 1) { /* can collapse */ + network_delete_node(network, node); + num_collapsed++; + } + } + array_free(nodevec); + if (XLN_DEBUG > 1) { + (void) printf("---collapsed %d nodes in trivial collapse one iter\n", + num_collapsed); + } + return num_collapsed; +} + +/*---------------------------------------------------------------------------- + If the node can be collapsed into its fanouts, maintaining feasibility, + returns 1. If node is not INTERNAL, or has a fanout that is PO, returns 0. + If MOVE_FANINS = 1, then it tries to move fanins of the node around, so that + feasibility may be achieved. If some fanins are moved (using Roth-Karp + decomp.), then it tries to do collapse this node again into its fanouts. + If it succeeds, it is fine (return 1), else return 0. + Note: If collapse is possible, the fanout nodes are changed. +-------------------------------------------------------------------------------*/ +int +xln_do_trivial_collapse_node(node, size, MOVE_FANINS, MAX_FANINS) + node_t *node; + int size; + int MOVE_FANINS, MAX_FANINS; +{ + int is_collapsed; + + if (MOVE_FANINS) { + /* returns a flag telling if it moved some fanins. */ + /*-------------------------------------------------*/ + (void) xln_node_move_fanins(node, size, MAX_FANINS, MAXINT); + } + is_collapsed = xln_do_trivial_collapse_node_without_moving(node, size); + if (is_collapsed <= 0) return 0; /* either not INTERNAL, or some fo PO, or not + collapsible */ + return 1; /* can collapse */ +} + +/*-------------------------------------------------------------------------- + Returns 1 if the node can be collapsed into all the fanouts, + maintaining feasibility of the fanout nodes. It collapses the node into + all the fanouts, so the functions of fanout nodes change. However, does + not delete the node from the network. Otherwise returns + 0: either the node is not INTERNAL, or some fanout is PO. + -ve number diff: diff tells by how much was the feasibility missed. + In last two cases, there is no change in the network. +---------------------------------------------------------------------------*/ +int +xln_do_trivial_collapse_node_without_moving(node, size) + node_t *node; + int size; +{ + int j; + array_t *fo_array; + node_t *fo, *fo_simpl; + lsGen gen; + int diff, diff_fo; + int flag; + + if(node->type != INTERNAL) return 0; + fo_array = array_alloc(node_t*, 0); + flag = 1; + diff = MAXINT; + foreach_fanout(node, gen, fo){ + if(fo->type == PRIMARY_OUTPUT) { + lsFinish(gen); + array_free(fo_array); + return 0; + } + diff_fo = size - composite_fanin(fo, node); + if (diff_fo < 0) { + diff = min(diff_fo, diff); + flag = 0; + } else { + array_insert_last(node_t *, fo_array, fo); + } + } + /* flag = 0 means the node cannot be collapsed because of infeasibility */ + /*----------------------------------------------------------------------*/ + if (flag == 0) { + array_free(fo_array); + return diff; + } + /* number of fanouts = 0 */ + /*-----------------------*/ + if (array_n(fo_array) == 0) { + if (XLN_DEBUG) { + (void) printf("warning-- node %s does not fanout anywhere\n", + node_long_name(node)); + } + array_free(fo_array); + return 0; + } + assert(array_n(fo_array) > 0); + for(j = 0; j < array_n(fo_array); j++){ + fo = array_fetch(node_t *, fo_array, j); + node_collapse(fo, node); + fo_simpl = node_simplify(fo, NIL (node_t), NODE_SIM_ESPRESSO); + node_replace(fo, fo_simpl); + } + array_free(fo_array); + return 1; +} + + +/* Finds number of distinct fanins of fanin- fanin is a fanin to po + * ie should fanin be merged into po then the number of wires that + * would have to be routed to po in addition to the fanins of po*/ + +static int +cost_fanin(po, fanin) +node_t *po, *fanin; +{ + node_t *fi; + int j, cost; + + cost = node_num_fanin(fanin); + foreach_fanin(po, j, fi) { + if(node_get_fanin_index(fanin, fi) >= 0) cost--; + } + return(cost); +} + + +static int +composite_fanin(node1, node2) +node_t *node1, *node2 ; +{ +node_t *fi; +int inp, j; + +inp = node_num_fanin(node1)-1; + foreach_fanin(node2, j, fi) { + if(node_get_fanin_index(node1, fi) < 0) inp++; + } +return(inp); +} + diff --git a/sis/pld/xln_part_dec.c b/sis/pld/xln_part_dec.c new file mode 100644 index 0000000..1c856bd --- /dev/null +++ b/sis/pld/xln_part_dec.c @@ -0,0 +1,249 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_part_dec.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:57 $ + * + */ + +/* fixed the bug which resulted because of the way kernel, + cokernel and remainder were substituted in the node. + They were substituted in the negative phase too earlier. + June 21, 93. */ + +/* changes made on cost function and the way split works: + now it finds nonfeasible kernels also. Feb 13, 91 ---- Rajeev +*/ +#include "sis.h" +#include "pld_int.h" + +int split_node(); +static void find_best_div(); + +split_network(network, size) +network_t *network; +int size; +{ + array_t *order; + node_t *node; + int i ; + char *err; + + order = network_dfs(network); + for(i=0 ; i < array_n(order); i++) { + node = array_fetch(node_t *, order, i); + if(node_num_fanin(node) > size) { + (void) split_node(network, node, size); + error_init(); + if(!network_check(network)) { + err = error_string(); + (void)fprintf(sisout, "%s", err); + } + } + } + array_free(order); + (void) network_sweep(network); +} + + + +int +split_node(network, node, size) +network_t *network; +node_t *node; +int size; +{ + static int kernel_value(); + int i, value = 1; + kern_node *sorted; + divisor_t *div, *best_div; + node_t *best, *co_best, *rem, *t_node; + node_t *p, *q, *r, *pq, *new_node; + + if (node_num_fanin(node) <= size) return 0; + + /* First try finding kernels */ + if((t_node = ex_find_divisor_quick(node)) != NIL(node_t)) { + sorted = ALLOC(kern_node, 1); + sorted->node = node; + sorted->cost_array = array_alloc(divisor_t *, 0); + sorted->size = size; + ex_kernel_gen(node, kernel_value, (char *)sorted); + ex_subkernel_gen(node, kernel_value, 0, (char *)sorted); + best_div = ALLOC( divisor_t, 1); + best_div->divisor = NIL(node_t); + best_div->kernelsize = HICOST; + + for( i=0; i< array_n(sorted->cost_array); i++){ + div = array_fetch(divisor_t *, sorted->cost_array, i); + (void)find_best_div(div, best_div, size); + } + /* (void) printf("\n\n"); */ + + array_free(sorted->cost_array); + FREE(sorted); + + if(best_div->divisor != NIL(node_t)) { + best = best_div->divisor; + FREE(best_div); + if(XLN_DEBUG){ + (void)fprintf(sisout,"Node %s has been added to the network\n", + node_name(best)); + (void)node_print(sisout, best); + } + co_best = node_div(node, best, &rem); + if(XLN_DEBUG){ + (void)fprintf(sisout, "cokernel"); + node_print(sisout, co_best); + (void)fprintf(sisout, "remainder"); + node_print(sisout, rem); + } + network_add_node(network, best); + network_add_node(network, co_best); + network_add_node(network, rem); + p = node_literal(best, 1); + q = node_literal(co_best, 1); + r = node_literal(rem, 1); + pq = node_and(p, q); + new_node = node_or(pq, r); + node_free(p); + node_free(q); + node_free(pq); + node_free(r); + node_replace(node, new_node); + (void)split_node(network, rem, size); + (void) split_node(network, co_best, size); + (void) split_node(network, best, size); + (void) split_node(network, node, size); + + if(XLN_DEBUG) { + node_print(sisout, node); + } + } else { + node_free(best_div->divisor); + FREE(best_div); + value = pld_decomp_and_or(network, node, size); + } + } else { + if( !pld_decomp_and_or(network, node, size)){ + (void)fprintf(sisout,"No and_or decomposition possible\n"); + value = 0; + } + } + node_free(t_node); + return (value); +} + + + +static int +kernel_value(kernel, cokernel, state) +node_t *kernel; +node_t *cokernel; +char *state; +{ + divisor_t *k_data, *c_data; + kern_node *store; + node_t *rem , *new_cokernel; + int size; + int num_nc, num_k, num_node, num_rem, cost; + /* int infeasible_nc, infeasible_k, infeasible_rem, total_infeasibility; */ + + store = (kern_node *)state; + size = store->size; + new_cokernel = node_div(store->node, kernel, &rem); + + num_node = node_num_fanin(store->node); + num_nc = node_num_fanin(new_cokernel); + num_k = node_num_fanin(kernel); + num_rem = node_num_fanin(rem); + cost = num_nc + num_k + num_rem; + + /* do infeasibility study */ + /*------------------------*/ + /* infeasible_nc = xln_infeasibility_measure(new_cokernel, size); + infeasible_k = xln_infeasibility_measure(kernel, size); + infeasible_rem = xln_infeasibility_measure(rem, size); */ + + /* change the cost by feasibility number */ + /*---------------------------------------*/ + /* total_infeasibility = infeasible_nc + infeasible_k + infeasible_rem; */ + + /* if all three nodes feasible, accept it definitely */ + /*---------------------------------------------------*/ + if ((num_nc == size) && (num_k == size) && (num_rem == size)) cost = -HICOST; + /* else cost += total_infeasibility; */ + + /* if((node_num_fanin(new_cokernel) <= size)&&(node_num_fanin(new_cokernel) > 1)){ */ + if((num_nc > 1) && (num_nc < num_node)) { + c_data = ALLOC(divisor_t, 1); + c_data->divisor = new_cokernel; + /* c_data->kernelsize = 2 * composite_fanin(rem, kernel) + + node_num_fanin(new_cokernel); */ + c_data->kernelsize = cost; + array_insert_last(divisor_t *, store->cost_array, c_data); + } + + /* if((node_num_fanin(kernel) <= size)&&(node_num_fanin(kernel) > 1)){ */ + if((num_k > 1) && (num_k < num_node)) { + k_data = ALLOC(divisor_t, 1); + k_data->divisor = kernel; + /* k_data->kernelsize = 2 * composite_fanin(rem ,new_cokernel) + + node_num_fanin(kernel); */ + k_data->kernelsize = cost; + array_insert_last(divisor_t *, store->cost_array, k_data); + } + + node_free(rem); + node_free(cokernel); +} + + +static void +find_best_div(div, best_div, size) +divisor_t *div, *best_div; +int size; +{ + /* (void) printf("%d ", div->kernelsize); */ + if(div->kernelsize < best_div->kernelsize) { + if(best_div->divisor != NIL(node_t )){ + node_free(best_div->divisor); + } + best_div->divisor = node_dup(div->divisor); + best_div->kernelsize = div->kernelsize; + } + node_free(div->divisor); + FREE(div); +} + + +xln_infeasibility_measure(node, size) + node_t *node; + int size; +{ + int num_lit, num_fanin, diff; + + + num_fanin = node_num_fanin(node); + if (num_fanin <= size) return 0; /* node feasible */ + /* return a feasibility number reflecting diff. between num_fanin and size + and also the number of literals */ + /*------------------------------------------------------------------------*/ + num_lit = node_num_literal(node); + diff = num_fanin - size; + if (diff == 1) return 1; + if (diff <= 4) { + if (num_lit <= 25) return 2; + if (num_lit <= 50) return 3; + if (num_lit <= 100) return 5; + } + return 6; +} + + + + + + diff --git a/sis/pld/xln_ufind.c b/sis/pld/xln_ufind.c new file mode 100644 index 0000000..70a8a84 --- /dev/null +++ b/sis/pld/xln_ufind.c @@ -0,0 +1,112 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/pld/xln_ufind.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:57 $ + * + */ +#include "sis.h" +#include "pld_int.h" + +unionop(node1, node2) + struct tree_node *node1; + struct tree_node *node2; +{ + + if (node1->parent != node1) { + (void) printf(" Node %d has a parent\n", node1->index); + exit(8); + } + if (node2->parent != node2) { + (void) printf( " Node %d has a parent\n", node2->index); + exit(8); + } + + if (node1->num_child < node2->num_child) + make_son(node1, node2); + else make_son (node2, node1); + +} + +/* make node1 the son of node2 */ + +make_son(node1, node2) + struct tree_node *node1, *node2; +{ + node1->parent = node2; + node2->num_child = node2->num_child + node1->num_child; +} + +/* try changing the parent fields of all the nodes on the + path done*/ + +struct tree_node * +find_tree(node) + struct tree_node *node; +{ + struct tree_node *dummy_node; + struct tree_node *node_on_path; + + node_on_path = node; + dummy_node = node; + while (dummy_node->parent != dummy_node) + dummy_node = dummy_node->parent; + while (node_on_path != dummy_node) { + node_on_path = node_on_path->parent = dummy_node; + } + return dummy_node; + +} + +int +estimate_clb_no(network, size) +network_t *network; +int size; +{ + int upper_bound; + network_t *dup_network; + + dup_network = network_dup(network); + (void)decomp_tech_network(dup_network, 2, 2); + imp_part_network(dup_network, size, 0, 0); /* for not moving fanins */ + upper_bound = network_num_internal(dup_network); + network_free(dup_network); + (void)fprintf(sisout, "The upper bound on CLBs is %d\n", upper_bound); + return upper_bound; +} + +and_or_map(network, size) +network_t *network; +int size; +{ + (void)decomp_tech_network(network, 2, 2); + imp_part_network(network, size, 0, 0); /* for not moving fanins */ + return 0; +} + + +int +estimate_net_no(network) +network_t *network; +{ + node_t *node; + int value=0, i; + array_t *order; + + order = network_dfs(network); + for( i = 0; i < array_n(order) ; i++) { + node = array_fetch(node_t *, order, i); + if((node_function(node) != NODE_PI) && + (node_function(node) != NODE_PO)) { + value += node_num_fanin(node); + } + } + array_free(order); + return value; +} + + + + diff --git a/sis/power/Makefile.am b/sis/power/Makefile.am new file mode 100644 index 0000000..3d47a82 --- /dev/null +++ b/sis/power/Makefile.am @@ -0,0 +1,10 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libpower.a +libpower_a_SOURCES = com_power.c power_comb.c power_comp.c \ + power_dynamic.c power_main.c power_pipe.c power_psAppr.c \ + power_psExact.c power_sample.c power_seq.c power_sim.c power_util.c \ + power_int.h +pkginclude_HEADERS = power.h +dist_doc_DATA = power.doc diff --git a/sis/power/Makefile.in b/sis/power/Makefile.in new file mode 100644 index 0000000..02b1553 --- /dev/null +++ b/sis/power/Makefile.in @@ -0,0 +1,427 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libpower_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/power +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libpower_a_AR = $(AR) $(ARFLAGS) +libpower_a_LIBADD = +am_libpower_a_OBJECTS = com_power.$(OBJEXT) power_comb.$(OBJEXT) \ + power_comp.$(OBJEXT) power_dynamic.$(OBJEXT) \ + power_main.$(OBJEXT) power_pipe.$(OBJEXT) \ + power_psAppr.$(OBJEXT) power_psExact.$(OBJEXT) \ + power_sample.$(OBJEXT) power_seq.$(OBJEXT) power_sim.$(OBJEXT) \ + power_util.$(OBJEXT) +libpower_a_OBJECTS = $(am_libpower_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libpower_a_SOURCES) +DIST_SOURCES = $(libpower_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libpower.a +libpower_a_SOURCES = com_power.c power_comb.c power_comp.c \ + power_dynamic.c power_main.c power_pipe.c power_psAppr.c \ + power_psExact.c power_sample.c power_seq.c power_sim.c power_util.c \ + power_int.h + +pkginclude_HEADERS = power.h +dist_doc_DATA = power.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/power/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/power/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libpower.a: $(libpower_a_OBJECTS) $(libpower_a_DEPENDENCIES) + -rm -f libpower.a + $(libpower_a_AR) libpower.a $(libpower_a_OBJECTS) $(libpower_a_LIBADD) + $(RANLIB) libpower.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/power/com_power.c b/sis/power/com_power.c new file mode 100644 index 0000000..60fdfb5 --- /dev/null +++ b/sis/power/com_power.c @@ -0,0 +1,104 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/com_power.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:05 $ + * + */ +/*--------------------------------------------------------------------------- +| Interface routines between SIS and the probabilistic power estimation +| package: +| +| init_sis() +| end_sis() +| +| Copyright (c) 1991 - Abhijit Ghosh +| University of California at Berkeley +| +| Jose' Monteiro, MIT, Jan/93 jcm@rle-vlsi.mit.edu ++--------------------------------------------------------------------------*/ + +#include "sis.h" +#include "power_int.h" + +static int com_power_main(); +static int free_power_info(); +static int print_power_info(); + +static struct{ + char *name; + int (*function)(); + boolean changes_network; +} table[] = { + { "power_estimate", com_power_main, TRUE /* Adds prob info */}, + { "power_free_info", free_power_info, TRUE /* Frees prob info */}, + { "power_print", print_power_info, FALSE /* Doesn't change network */} +}; + +int init_power() +{ + int i; + + for(i = 0; i < sizeof_el(table); i++){ + com_add_command(table[i].name, table[i].function, + table[i].changes_network); + } +} + +end_power() +{ +} + + +/* Main driver for deriving the power of a network */ +static int com_power_main(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int status; + + status = power_command_line_interface(*network, argc, argv); + + return status; +} + + +static int free_power_info(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int status; + + if(argc != 1){ + fprintf(siserr, "Too many arguments. Usage: power_free_info\n"); + return 1; + } + + status = power_free_info(); + + return status; +} + + +static int print_power_info(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int status; + + if(argc != 1){ + fprintf(siserr, "Too many arguments. Usage: power_print\n"); + return 1; + } + + status = power_print_info(*network); + + return status; +} + + diff --git a/sis/power/power.doc b/sis/power/power.doc new file mode 100644 index 0000000..ab19ea0 --- /dev/null +++ b/sis/power/power.doc @@ -0,0 +1,133 @@ +/*--------------------------------------------------------------------------- +| +| Documentation for global routines/structures. +| +| Jose' Monteiro, MIT, Mar/94 jcm@rle-vlsi.mit.edu ++--------------------------------------------------------------------------*/ + +Description: + The power package for SIS. + + +Summary: + power_estimate(); + power_main_driver(); + power_sample_estimate(); + power_simulation_estimate(); + power_free_info(); + power_print(); + + SWITCH_PROB(); + CAP_FACTOR(); + +int +power_estimate(network, type, delay, total_power) +network_t *network; +int type; /* {COMBINATIONAL; SEQUENTIAL; PIPELINE; DYNAMIC} */ +int delay; /* {0 - zerod delay; 1 - unit delay; 2 - general delay} */ +double *total_power; /* Returned value */ + + Calls power_main_driver with default values: + + psProbOption = APPROXIMATION_PS; + info_file = NIL(FILE); + sop_or_fact = FACTORED_FORM; + input_sizing = DEFAULT_MAX_INPUT_SIZING (4); + + power_setSize = 1; + power_delta = DEFAULT_PS_MAX_ALLOWED_ERROR (0.01); + power_verbose = 0; + power_cap_in = CAP_IN_LATCH (4); + power_cap_out = CAP_OUT_LATCH (20); + + +int +power_main_driver(network, type, delay, psProbOption, info_file, + sop_or_fact, input_sizing, total_power) +network_t *network; +int type; /* {COMBINATIONAL; SEQUENTIAL; PIPELINE; DYNAMIC} */ +int delay; /* {0 - zerod delay; 1 - unit delay; 2 - general delay} */ +int psProbOption; /* {APPROXIMATION_PS; EXACT_PS; UNIFORM_PS} */ +FILE *info_file; /* File with primary input probabilities */ +int sop_or_fact; /* {FACTORED_FORM; SUM_OF_PRODUCTS} */ +int input_sizing; /* Maximum number of inputs of node for sizing */ +double *total_power; /* Returned value */ + +NOTE: Besides these arguments, the calling routine must set global variables: + power_setSize, power_delta, power_verbose, power_cap_[in/out]. + + Estimates the capacitive load and expected number of transitions of each + node in the network. These values are stored in a global table and can + be retrieved using the macros SWITCH_PROB and CAP_FACTOR. The estimated + total power dissipated by the network is returned in "total_power". This + value is computed by adding SWITCH_PROB * CAP_FACTOR * CAPACITANCE * 250.0 + over all the nodes (250.0 = 0.5 * 5V^2 * 20MHz and CAPACITANCE = 0.01). + The routine returns 0 if all went well, 1 if something went wrong. + + +int +power_sample_estimate(network, type, delay, num_samples, total_power) +network_t *network; +int type; /* {COMBINATIONAL; SEQUENTIAL; PIPELINE; DYNAMIC} */ +int delay; /* {0 - zerod delay; 1 - unit delay; 2 - general delay} */ +int num_samples; /* Number of sets of 32 input vectors to simulate */ +double *total_power; /* Returned value */ + + Calls power_simulation_estimate with default values: + + psProbOption = APPROXIMATION_PS; + info_file = NIL(FILE); + sop_or_fact = FACTORED_FORM; + input_sizing = DEFAULT_MAX_INPUT_SIZING (4); + + power_setSize = 1; + power_delta = DEFAULT_PS_MAX_ALLOWED_ERROR (0.01); + power_verbose = 0; + power_cap_in = CAP_IN_LATCH (4); + power_cap_out = CAP_OUT_LATCH (20); + +int +power_simulation_estimate(network, type, delay, psProbOption, num_samples, + sample_gap, info_file, sop_or_fact, input_sizing, + total_power) +network_t *network; +int type; /* {COMBINATIONAL; SEQUENTIAL; PIPELINE; DYNAMIC} */ +int delay; /* {0 - zerod delay; 1 - unit delay; 2 - general delay} */ +int psProbOption; /* {APPROXIMATION_PS; EXACT_PS; UNIFORM_PS} */ +int num_samples; /* Number of sets of 32 input vectors to simulate */ +int sample_gap; /* Sample interval to print current power estimate */ +FILE *info_file; /* File with primary input probabilities */ +int sop_or_fact; /* {FACTORED_FORM; SUM_OF_PRODUCTS} */ +int input_sizing; /* Maximum number of inputs of node for sizing */ +double *total_power; /* Returned value */ + + Same as power_estimate, but uses logic simulation instead of calculating + signal probabilities through BDD's (can be less accurate and slower, + but can be used with larger circuits for which BDD's are too large). + + +int +power_free_info(network) +network_t *network; + + Frees power information stored in global table 'power_info_table'. + Always returns 0. + +int +power_print(network) +network_t *network; + + Goes through all nodes of the network and prints their switching + probability and capacitance. + + +double +SWITCH_PROB(node) +node_t *node; + Returns the expected number of transitions this node makes + per clock cycle. + +int +CAP_FACTOR(node); +node_t *node; + Returns the capacitive load the node is driving. diff --git a/sis/power/power.h b/sis/power/power.h new file mode 100644 index 0000000..f9740f1 --- /dev/null +++ b/sis/power/power.h @@ -0,0 +1,58 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:05 $ + * + */ +/*-------------------------------------------------------------------------- +| Constants and structures needed to use the power package routines. +| +| Copyright (c) 1993 - Jose' Monteiro +| Massachusetts Institute of Technology ++-------------------------------------------------------------------------*/ + +#ifndef POWER_H +#define POWER_H + +/* Some constant definitions */ +#define POWER_ZERO_D 0 +#define POWER_UNIT_D 1 +#define POWER_GENERAL_D 2 +#define COMBINATIONAL 10 +#define SEQUENTIAL 11 +#define PIPELINE 12 +#define DYNAMIC 13 +#define APPROXIMATION_PS 20 +#define EXACT_PS 21 +#define STATELINE_PS 22 +#define UNIFORM_PS 23 +#define FACTORED_FORM 30 +#define SUM_OF_PRODUCTS 31 + +#define CAPACITANCE 0.01 /* In pico farads per fanout */ + +typedef struct{ + int cap_factor; /* The load of the gate */ + double switching_prob; /* Expected number of transistions in one cycle */ +} power_info_t; + + +/* Table with switching, capacitance and delay info */ +extern st_table *power_info_table; + +extern int power_free_info(); /* power_util.c */ +extern int power_print_info(); /* power_util.c */ + +extern int power_estimate(); /* power_main.c */ +extern int power_main_driver(); /* power_main.c */ + +extern char *power_dummy; /* For use in the following macros */ + +#define SWITCH_PROB(node) (st_lookup(power_info_table, (char *) (node), &power_dummy) ? (((power_info_t *) power_dummy)->switching_prob) : (fprintf(siserr, "Error in SWITCH_PROB, no power info for node %s\n", node->name), abort(), 0 /* make compiler happy */)) +#define CAP_FACTOR(node) (st_lookup(power_info_table, (char *) (node), &power_dummy) ? (((power_info_t *) power_dummy)->cap_factor) : (fprintf(siserr, "Error in SWITCH_PROB, no power info for node %s\n", node->name), abort(), 0 /* make compiler happy */)) + +#endif + diff --git a/sis/power/power_comb.c b/sis/power/power_comb.c new file mode 100644 index 0000000..e91a62d --- /dev/null +++ b/sis/power/power_comb.c @@ -0,0 +1,203 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_comb.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:05 $ + * + */ +/*--------------------------------------------------------------------------- +| This file contains routines for power estimation of combinational +| circuits. +| +| power_comb_static_zero() +| power_comb_static_unit() +| power_comb_static_arbit() +| +| Copyright (c) 1991 - Abhijit Ghosh. University of California, Berkeley +| +| Jose' Monteiro, MIT, Jan/93 jcm@rle-vlsi.mit.edu +| - Modified to be included in SIS (instead of Flames) +| - Added power information for each node ++--------------------------------------------------------------------------*/ + +#include "sis.h" +#include "power_int.h" + + +/* This routine is for finding the power dissipation in combinational circuits +* implemented using static logic, assuming zero delay +*/ +int power_comb_static_zero(network, info_table, total_power) +network_t *network; +st_table *info_table; +double *total_power; +{ + st_table *leaves = st_init_table(st_ptrcmp, st_ptrhash); + bdd_manager *manager; + bdd_t *bdd; + power_info_t *power_info; + node_info_t *node_info; + power_pi_t *PIInfo; + array_t *poArray, + *piOrder; + node_t *po, + *pi, + *node; + double prob_node_one; + int i; + lsGen gen; + + poArray = array_alloc(node_t *, 0); + + foreach_primary_output(network, gen, po){ + array_insert_last(node_t *, poArray, po); + } + piOrder = order_nodes(poArray, /* PI's only */ 1); + if(piOrder == NIL(array_t)) + piOrder = array_alloc(node_t *, 0); + array_free(poArray); + + manager = ntbdd_start_manager(3 * network_num_pi(network)); + + PIInfo = ALLOC(power_pi_t, network_num_pi(network)); + for(i = 0; i < array_n(piOrder); i++){ + pi = array_fetch(node_t *, piOrder, i); + st_insert(leaves, (char *) pi, (char *) i); + assert(st_lookup(info_table, (char *) pi, (char **) &node_info)); + PIInfo[i].probOne = node_info->prob_one; + } + array_free(piOrder); + + /* Create a BDD for each PO will create a BDD at each node */ + foreach_primary_output(network, gen, po){ + bdd = ntbdd_node_to_bdd(po, manager, leaves); + } + + /* Have to calculate the probability of a function being one given the + probabilities in the one and the zero array */ + *total_power = 0.0; + foreach_node(network, gen, node){ + if(node_function(node) == NODE_PO) + continue; + assert(st_lookup(power_info_table, (char*) node, (char**) &power_info)); + + if(node_function(node) == NODE_PI){ + assert(st_lookup(info_table, (char *) node, (char **) &node_info)); + prob_node_one = node_info->prob_one; + } + else{ + bdd = ntbdd_at_node(node); + prob_node_one = power_calc_func_prob(bdd, PIInfo); + } + prob_node_one = 2 * prob_node_one * (1.0 - prob_node_one); + if(power_verbose > 50) + fprintf(sisout, "Node %s Probability %f\n", + node_name(node), prob_node_one); + + *total_power += power_info->cap_factor * prob_node_one * CAPACITANCE; + power_info->switching_prob += prob_node_one; + } + *total_power *= 250.0; /* The 0.5 Vdd ^2 factor for a 5V Vdd */ + + ntbdd_end_manager(manager); + st_free_table(leaves); + FREE(PIInfo); + + return 0; +} + + +/* This is the core routine for doing power computation for static circuits, +* using any kind of delay +*/ +int power_comb_static_arbit(network, info_table, total_power) +network_t *network; +st_table *info_table; +double *total_power; +{ + st_table *leaves = st_init_table(st_ptrcmp, st_ptrhash); + array_t *poArray, + *piOrder; + bdd_manager *manager; + bdd_t *bdd; + network_t *symbolic; + power_info_t *power_info; + node_info_t *node_info; + power_pi_t *PIInfo; + node_t *node, + *po, + *pi, + *orig_node; + double prob_node_one; + int i; + lsGen gen; + + /* First simulate the circuit symbolically */ + symbolic = power_symbolic_simulate(network, info_table); + +#ifdef DEBUG + write_blif(sisout, symbolic, 0, 0); + fflush(sisout); + power_network_print(symbolic); +#endif + + /* Remove all PI's that don't go anywhere. Such PIs might exist */ + poArray = array_alloc(node_t *, 0); + foreach_primary_input(symbolic, gen, pi){ + if(node_num_fanout(pi) == 0) + array_insert_last(node_t *, poArray, pi); + } + for(i = 0; i < array_n(poArray); i++){ + node = array_fetch(node_t *, poArray, i); + network_delete_node(symbolic, node); + } + array_free(poArray); + + /* We have the symbolic network, so now just get the probability of inputs + and calculate the probability of function */ + + poArray = array_alloc(node_t *, 0); + foreach_primary_output(symbolic, gen, po){ + array_insert_last(node_t *, poArray, po); + } + piOrder = order_nodes(poArray, /* PI's only */ 1); + if(piOrder == NIL(array_t)) /* So it doesn't crash without network */ + piOrder = array_alloc(node_t *, 0); + array_free(poArray); + + manager = ntbdd_start_manager(3 * network_num_pi(symbolic)); + + PIInfo = ALLOC(power_pi_t, network_num_pi(symbolic)); + for(i = 0; i < array_n(piOrder); i++){ + pi = array_fetch(node_t *, piOrder, i); + st_insert(leaves, (char *) pi, (char *) i); + orig_node = pi->copy; /* Link to the original network */ + assert(st_lookup(info_table, (char *) orig_node, (char **) &node_info)); + PIInfo[i].probOne = node_info->prob_one; + } + array_free(piOrder); + + *total_power = 0.0; + foreach_primary_output(symbolic, gen, po){ + node = po->fanin[0]; /* The actual node we are looking at */ + bdd = ntbdd_node_to_bdd(node, manager, leaves); + prob_node_one = power_calc_func_prob(bdd, PIInfo); + orig_node = node->copy; /* Link to the original network */ + assert(st_lookup(power_info_table,(char*)orig_node,(char**)&power_info)); + *total_power += power_info->cap_factor * prob_node_one * CAPACITANCE; + power_info->switching_prob += prob_node_one; + if(power_verbose > 50) + fprintf(sisout, "Node %s Probability %f\n", + node_name(node), prob_node_one); + } + *total_power *= 250.0; /* The 0.5 Vdd ^2 factor for a 5V Vdd */ + + ntbdd_end_manager(manager); + st_free_table(leaves); + FREE(PIInfo); + network_free(symbolic); + + return 0; +} diff --git a/sis/power/power_comp.c b/sis/power/power_comp.c new file mode 100644 index 0000000..68baa9d --- /dev/null +++ b/sis/power/power_comp.c @@ -0,0 +1,370 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_comp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:05 $ + * + */ +/*--------------------------------------------------------------------------- +| This file contains the "SCAN" operation on the BDD whereby all the +| probabilities are easily obtained using static probabilities of inputs. +| +| power_calc_func_prob() +| power_calc_func_prob_w_stateProb() +| power_calc_func_prob_w_sets() +| +| Copyright (c) 1991 - Abhijit Ghosh. University of California, Berkeley +| +| Jose' Monteiro, MIT, Aug/93 jcm@rle-vlsi.mit.edu +| - New function that takes into account probabilities of sets of lines ++--------------------------------------------------------------------------*/ + +#include "sis.h" +#include "power_int.h" + +static double power_count_prob(); +#ifdef SIS +static double power_count_prob_w_stateProb(); +static void evaluate_included_state_prob(); +static double power_count_f_prob_w_sets(); +static void multiply_PS_prob(); +#endif /* SIS */ + + +static st_table *visited; +static power_pi_t *PIInfo; + + +/* The following routine calculates the probability of function a (given with +* bdd) being one, given the static input zero and one probabilities of its +* inputs in the zero and one array +*/ +double power_calc_func_prob(f_bdd, infoPIs) +bdd_t *f_bdd; +power_pi_t *infoPIs; +{ + double result; + char *value, *key; + st_generator *gen; + + assert(f_bdd != NIL(bdd_t)); + + visited = st_init_table(st_ptrcmp, st_ptrhash); + PIInfo = infoPIs; + + result = power_count_prob(f_bdd); + + st_foreach_item(visited, gen, &key, &value){ + FREE(value); + } + st_free_table(visited); + + return result; +} + +/* Basically counts the probability of going down each path in the bdd and +* sums it up to give the total probability of function being one +*/ +static double power_count_prob(f) +bdd_t *f; +{ + bdd_t *child; + double result, + *stored; + long topf; + + if(st_lookup(visited, (char *) f->node, (char **) &stored)) + return *stored; + + if(f->node == cmu_bdd_zero(f->mgr)) + return 0.0; + if(f->node == cmu_bdd_one(f->mgr)) + return 1.0; + + topf = cmu_bdd_if_index(f->mgr, f->node); + + child = bdd_else(f); + result = (1.0 - PIInfo[topf].probOne) * power_count_prob(child); + FREE(child); + + child = bdd_then(f); + result += PIInfo[topf].probOne * power_count_prob(child); + FREE(child); + + stored = ALLOC(double, 1); + *stored = result; + st_insert(visited, (char *) f->node, (char *) stored); + + return result; +} + +#ifdef SIS +/* The following routine calculates the probability of a function (given with +* bdd) being one, given the static input zero and one probabilities of its +* primary inputs in the zero and one array and the probability of the FSM +* being in each state +*/ +double power_calc_func_prob_w_stateProb(f_bdd, infoPIs, stateProb, stateIndex, + nStateLines) +bdd_t *f_bdd; +power_pi_t *infoPIs; +double *stateProb; +st_table *stateIndex; +int nStateLines; +{ + double result; + char *value, + *key, + *encoding; + int i; + st_generator *gen; + + assert(f_bdd != NIL(bdd_t)); + + visited = st_init_table(st_ptrcmp, st_ptrhash); + PIInfo = infoPIs; + + encoding = ALLOC(char, nStateLines + 1); + for(i = 0; i < nStateLines; i++) + encoding[i] = '-'; + encoding[nStateLines] = '\0'; + + result = power_count_prob_w_stateProb(f_bdd, stateProb,stateIndex,encoding); + + st_foreach_item(visited, gen, &key, &value){ + FREE(value); + } + st_free_table(visited); + + return result; +} + +/* Goes down the BDD until a PI is found, thus we have which states are +* included in this BDD path (state lines are all before PI lines). At +* this point 'power_count_prob' is called and the result returned +* multiplied by the sum of the state probabilities. +*/ +static double power_count_prob_w_stateProb(f, stateProb, stateIndex, encoding) +bdd_t *f; +double *stateProb; +st_table *stateIndex; +char *encoding; +{ + bdd_t *child; + double result; + long topf; + + if(f->node == cmu_bdd_zero(f->mgr)){ + FREE(encoding); + return 0.0; + } + if(f->node == cmu_bdd_one(f->mgr)){ + result = 0.0; + evaluate_included_state_prob(encoding, stateProb, stateIndex,0,&result); + return result; + } + + topf = cmu_bdd_if_index(f->mgr, f->node); + + if(PIInfo[topf].PSLineIndex == -1){ /* This is a PI */ + result = 0.0; + evaluate_included_state_prob(encoding, stateProb, stateIndex,0,&result); + result *= power_count_prob(f); + return result; + } + + encoding[PIInfo[topf].PSLineIndex] = '0'; + child = bdd_else(f); + result = power_count_prob_w_stateProb(child, stateProb, stateIndex, + util_strsav(encoding)); + FREE(child); + + encoding[PIInfo[topf].PSLineIndex] = '1'; + child = bdd_then(f); + result += power_count_prob_w_stateProb(child,stateProb,stateIndex,encoding); + FREE(child); + + return result; +} + + +static void evaluate_included_state_prob(encoding, stateProb, stateIndexTable, + lineIndex, result) +char *encoding; +double *stateProb; +st_table *stateIndexTable; +int lineIndex; +double *result; +{ + int stateIndex; + + switch(encoding[lineIndex]){ + case '\0': + if(st_lookup(stateIndexTable, encoding, (char **) &stateIndex)) + *result += stateProb[stateIndex]; + FREE(encoding); + return; + case '0': + case '1': + evaluate_included_state_prob(encoding, stateProb, stateIndexTable, + lineIndex+1, result); + return; + case '-': + encoding[lineIndex] = '0'; + evaluate_included_state_prob(util_strsav(encoding), stateProb, + stateIndexTable, lineIndex+1, result); + encoding[lineIndex] = '1'; + evaluate_included_state_prob(encoding, stateProb, stateIndexTable, + lineIndex+1, result); + return; + default: + fail("Bad encoding string!"); + } +} + + + +/* The following routine calculates the probability of a function (given with +* bdd) being one, given the static input zero and one probabilities of its +* primary inputs in the zero and one array and the probability of the sets +* of PS lines +*/ +double power_calc_func_prob_w_sets(f_bdd, infoPIs, psProb, nPSLines) +bdd_t *f_bdd; +power_pi_t *infoPIs; +double *psProb; +int nPSLines; +{ + pset sets; + double result; + char *value, + *key; + st_generator *gen; + + assert(f_bdd != NIL(bdd_t)); + + visited = st_init_table(st_ptrcmp, st_ptrhash); + PIInfo = infoPIs; + + sets = set_full(2 * power_setSize); + + result = power_count_f_prob_w_sets(f_bdd, psProb, nPSLines, -1, sets); + + st_foreach_item(visited, gen, &key, &value){ + FREE(value); + } + st_free_table(visited); + + return result; +} + + +/* Goes down the BDD until a PI is found, from which point 'power_count_prob' +* is called (state lines are all before PI lines). Each time we enter a new +* set (which can be determined by power_setSize) we multiply the current +* result by the sum of the probabilities of the combinations included +* in the previous set. +*/ +static double power_count_f_prob_w_sets(f, psProb, nPSLines, prevInd, sets) +bdd_t *f; +double *psProb; +int nPSLines; +long prevInd; +pset sets; +{ + bdd_t *child; + pset keepSets, + otherSet; + double result, + *stored; + long topf; + int newSet; + + if(f->node == cmu_bdd_zero(f->mgr)){ + set_free(sets); + return 0.0; + } + if(f->node == cmu_bdd_one(f->mgr)){ + result = 1.0; + multiply_PS_prob(&result, prevInd, psProb, sets); + set_free(sets); + return result; + } + + if(st_lookup(visited, (char *) f->node, (char **) &stored)){ + result = *stored; + multiply_PS_prob(&result, prevInd, psProb, sets); + set_free(sets); + return result; + } + + topf = cmu_bdd_if_index(f->mgr, f->node); + + if(topf >= nPSLines){ /* First PI found, all PIs from now on */ + result = power_count_prob(f); + multiply_PS_prob(&result, prevInd, psProb, sets); + set_free(sets); + return result; + } + + newSet = (prevInd >= 0) && + ((topf / power_setSize) != (prevInd / power_setSize)); + + if(newSet){ + keepSets = sets; + sets = set_full(2 * power_setSize); + } + + otherSet = set_save(sets); + set_remove(otherSet, 2 * (topf % power_setSize) + 1); + child = bdd_else(f); + result = power_count_f_prob_w_sets(child, psProb, nPSLines, topf, otherSet); + FREE(child); + + set_remove(sets, 2 * (topf % power_setSize)); + child = bdd_then(f); + result += power_count_f_prob_w_sets(child, psProb, nPSLines, topf, sets); + FREE(child); + + if(!(topf % power_setSize)){ /* First element in a set, can store result */ + stored = ALLOC(double, 1); + *stored = result; + st_insert(visited, (char *) f->node, (char *) stored); + } + + if(newSet){ + multiply_PS_prob(&result, prevInd, psProb, keepSets); + set_free(keepSets); + } + + return result; +} + +static void multiply_PS_prob(result, index, psProb, sets) +double *result; +long index; +double *psProb; +pset sets; +{ + pset inclSets; + double probSum; + long setN; + int i, + setSize; + + setN = index / power_setSize; + setSize = 1 << power_setSize; + inclSets = power_lines_in_set(sets, setSize); + probSum = 0.0; + for(i = 0; i < setSize; i++) + if(is_in_set(inclSets, i)) + probSum += psProb[setN*setSize + i]; + + *result *= probSum; + + set_free(inclSets); +} + +#endif /* SIS */ diff --git a/sis/power/power_dynamic.c b/sis/power/power_dynamic.c new file mode 100644 index 0000000..8a8306d --- /dev/null +++ b/sis/power/power_dynamic.c @@ -0,0 +1,119 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_dynamic.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:05 $ + * + */ +/*--------------------------------------------------------------------------- +| This file contains routines for power estimation of dynamic domino +| circuits. +| +| power_dynamic() +| +| Copyright (c) 1991 - Abhijit Ghosh. University of California, Berkeley +| +| Jose' Monteiro, MIT, Jan/93 jcm@rle-vlsi.mit.edu +| - Modified to be included in SIS (instead of Flames) +| - Fixed estimation for dynamic sequential circuits ++--------------------------------------------------------------------------*/ + +#include "sis.h" +#include "power_int.h" + + +/* This routine is for finding the power dissipation in combinational circuits +* implemented using dynamic logic +*/ +int power_dynamic(network, info_table, total_power) +network_t *network; +st_table *info_table; +double *total_power; +{ + st_table *leaves = st_init_table(st_ptrcmp, st_ptrhash); + array_t *poArray, + *piOrder, + *psOrder; + bdd_manager *manager; + bdd_t *bdd; + power_info_t *power_info; + node_info_t *node_info; + power_pi_t *PIInfo; + node_t *po, + *pi, + *node; + double prob_node_one, + *psLineProb; + int i; + lsGen gen; + + /* Check if this is a sequential circuit. If so, calculate ps lines prob. + For now, hardcode approximation method */ +#ifdef SIS + if(network_num_latch(network)){ + power_setSize = 1; + psLineProb = power_direct_PS_lines_prob(network, info_table, &psOrder, + NIL(network_t)); + FREE(psLineProb); /* PS prob. have been updated inside */ + array_free(psOrder); + } +#endif /* SIS */ + + poArray = array_alloc(node_t *, 0); + + foreach_primary_output(network, gen, po){ + array_insert_last(node_t *, poArray, po); + } + piOrder = order_nodes(poArray, /* PI's only */ 1); + if(piOrder == NIL(array_t)) + piOrder = array_alloc(node_t *, 0); + array_free(poArray); + + manager = ntbdd_start_manager(3 * network_num_pi(network)); + + PIInfo = ALLOC(power_pi_t, network_num_pi(network)); + for(i = 0; i < array_n(piOrder); i++){ + pi = array_fetch(node_t *, piOrder, i); + st_insert(leaves, (char *) pi, (char *) i); + assert(st_lookup(info_table, (char *) pi, (char **) &node_info)); + PIInfo[i].probOne = node_info->prob_one; + } + array_free(piOrder); + + /* Create a BDD for each PO will create BDD at each node */ + foreach_primary_output(network, gen, po){ + bdd = ntbdd_node_to_bdd(po, manager, leaves); + } + + /* Have to calculate the probability of a function being one given the + probabilities in the one and the zero array */ + *total_power = 0.0; + foreach_node(network, gen, node){ + if(node_function(node) == NODE_PI) + continue; + if(node_function(node) == NODE_PO) + continue; + bdd = ntbdd_at_node(node); + prob_node_one = power_calc_func_prob(bdd, PIInfo); + assert(st_lookup(power_info_table, (char*) node, (char**) &power_info)); + *total_power += power_info->cap_factor * prob_node_one * CAPACITANCE; + power_info->switching_prob += prob_node_one; + if(power_verbose > 50) + fprintf(sisout, "Node %s Probability %f\n", + node_name(node), prob_node_one); + } + *total_power *= 250.0; /* The 0.5 Vdd ^2 factor for a 5V Vdd */ + + ntbdd_end_manager(manager); + st_free_table(leaves); + FREE(PIInfo); + + return 0; +} + + + + + diff --git a/sis/power/power_int.h b/sis/power/power_int.h new file mode 100644 index 0000000..f40730f --- /dev/null +++ b/sis/power/power_int.h @@ -0,0 +1,108 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:05 $ + * + */ +/*--------------------------------------------------------------------------- +| This is an internal header file for the power estimation package. +| +| Copyright (c) 1991 - Abhijit Ghosh. University of California, Berkeley +| +| Jose' Monteiro, MIT, Jan/93 jcm@rle-vlsi.mit.edu ++--------------------------------------------------------------------------*/ + +#include "power.h" + +#define sizeof_el(thing) (sizeof (thing)/sizeof (thing[0])) + +#define BDD_MODE 100 +#define SAMPLE_MODE 101 + +#define DEFAULT_MAX_INPUT_SIZING 4 /* Transistor sizing is assumed only for */ + /* gates with 4 or less inputs. */ +#define DEFAULT_PS_MAX_ALLOWED_ERROR 0.01 /* For ps lines probabilities */ +#define CAP_IN_LATCH 4 /* inv+2or */ +#define CAP_OUT_LATCH 20 /* 2(nand+or)/2 + 2(2(or+nand)) (internal) */ + /* Register from pag 217 Weste-Eshragian */ + +typedef struct{ + int delay; /* The delay of the gate */ + double prob_one; /* Probability of gate being logical one */ +} node_info_t; + + +typedef struct{ /* Used in power_sim.c */ + array_t *before_switching; + array_t *after_switching; + array_t *switching_times; +} delay_info_t; + + +typedef struct{ /* JCM: information for state probability */ + double probOne; + int PSLineIndex; +} power_pi_t; + + +#ifdef MAIN /* Global variables */ +/* Table with switching and capacitance info */ +st_table *power_info_table; + +short power_verbose; +int power_cap_in_latch; +int power_cap_out_latch; +double power_delta; /* Max allowed error for PS lines probabilities */ +int power_setSize; /* # of PS lines correlated in the direct method */ +char *power_dummy; /* Used in the SWITCH_PROB and CAP_FACTOR macros */ + +st_table *power_get_node_info(); /* power_main.c */ +#else +extern short power_verbose; +extern int power_cap_in_latch; +extern int power_cap_out_latch; +extern double power_delta; +extern int power_setSize; + +extern int power_command_line_interface(); /* power_main.c */ +extern st_table *power_get_node_info(); /* power_main.c */ +extern int power_get_mapped_delay(); /* power_main.c */ + +extern int power_comb_static_zero(); /* power_comb.c */ +extern int power_comb_static_arbit(); /* power_comb.c */ + +extern int power_dynamic(); /* power_dynamic.c */ + +#ifdef SIS +extern int power_pipe_static_arbit(); /* power_pipe.c */ +extern int power_add_pipeline_logic(); /* power_pipe.c */ + +extern int power_seq_static_arbit(); /* power_seq.c */ +extern int power_add_fsm_state_logic(); /* power_seq.c */ + +extern void power_PS_lines_from_state(); /* power_PSprob_exact.c */ +extern double *power_exact_state_prob(); /* power_PSprob_exact.c */ + +extern double *power_direct_PS_lines_prob(); /* power_PSprob_direct.c*/ +extern void power_place_PIs_last(); /* power_PSprob_direct.c*/ + +extern double power_calc_func_prob_w_stateProb(); /* power_comp.c */ +extern double power_calc_func_prob_w_sets(); /* power_comp.c */ +#endif /* SIS */ +extern double power_calc_func_prob(); /* power_comp.c */ + +extern network_t *power_symbolic_simulate(); /* power_sim.c */ + +extern array_t *power_network_dfs(); /* power_util.c */ +extern void power_network_print(); /* power_util.c */ +extern pset power_lines_in_set(); /* power_util.c */ + +extern bdd_node *cmu_bdd_zero(); /* Taken directly from the CMU package */ +extern bdd_node *cmu_bdd_one(); +extern long cmu_bdd_if_index(); + +#endif + diff --git a/sis/power/power_main.c b/sis/power/power_main.c new file mode 100644 index 0000000..7ef2af7 --- /dev/null +++ b/sis/power/power_main.c @@ -0,0 +1,772 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_main.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/16 19:11:05 $ + * + */ +/*--------------------------------------------------------------------------- +| The main routines for power estimation are stored here: +| +| power_main_driver() +| power_estimate() +| +| power_command_line_interface() +| power_get_node_info() +| power_get_mapped_delay() +| +| The remaining are auxiliary routines to determine delay and capacitance +| at each node in the network and define switching at the primary inputs. +| +| Copyright (c) 1991 - Abhijit Ghosh. University of California, Berkeley +| +| Jose' Monteiro, MIT, Jan/93 jcm@rle-vlsi.mit.edu +| - Modified to be included in SIS (instead of Flames) +| - Added power for primary inputs +| - Added power_estimate routine +| - Added pipelines +| - Added state probabilities +| - New interface ++--------------------------------------------------------------------------*/ + +#include "sis.h" +#define MAIN +#include "power_int.h" +#undef MAIN + +static void power_fill_info_table_from_file(); +static int load_sum_of_products(); +static int load_factored_form(); +static void power_usage(); + + +int power_command_line_interface(network, argc, argv) +network_t *network; +int argc; +char **argv; +{ + FILE *info_file; + int i, + status, + mode, + delay, + type, + psProbOption, + sop_or_fact, + input_sizing, + num_samples, + sample_gap; + double total_power; + + /* Default values */ + mode = BDD_MODE; + delay = 0; /* Default is zero delay model */ + type = COMBINATIONAL; + psProbOption = APPROXIMATION_PS; + power_setSize = 1; + power_delta = DEFAULT_PS_MAX_ALLOWED_ERROR; + num_samples = 100; + info_file = NIL(FILE); + + sop_or_fact = FACTORED_FORM; + input_sizing = DEFAULT_MAX_INPUT_SIZING; + sample_gap = INFINITY; /* Don't show intermediate value in sampling */ + power_verbose = 0; + power_cap_in_latch = CAP_IN_LATCH; /* Default I/O latch capacitances */ + power_cap_out_latch = CAP_OUT_LATCH; + + /* Check arguments */ + for(i = 1; i != argc; ) + switch(argv[i++][1]){ + case 'm': + switch(argv[i][0]){ + case 'b': + case 'B': + mode = BDD_MODE; + break; + case 's': + case 'S': + mode = SAMPLE_MODE; + break; + default: + fprintf(siserr, + "Invalid mode: %s. Only BDD or SAMPLE.\n", + argv[i]); + return 1; + } + i++; + continue; + case 'd': + switch(argv[i][0]){ + case 'z': + case 'Z': + delay = 0; + break; + case 'u': + case 'U': + delay = 1; + break; + case 'g': + case 'G': + delay = 2; + break; + default: + fprintf(siserr, + "Invalid delay: %s. One of ZERO, UNIT or GENERAL.\n", + argv[i]); + return 1; + } + i++; + continue; + case 't': + switch(argv[i][0]){ + case 'c': + case 'C': + type = COMBINATIONAL; + break; +#ifdef SIS + case 's': + case 'S': + if(network_num_latch(network)) + type = SEQUENTIAL; + else + fprintf(siserr, "Warning, non sequential network. Combinational power will be reported.\n"); + break; + case 'p': + case 'P': + if(network_num_latch(network)) + type = PIPELINE; + else + fprintf(siserr, "Warning, non sequential network. Combinational power will be reported.\n"); + break; +#endif + case 'd': + case 'D': + type = DYNAMIC; + break; + default: + fprintf(siserr, "Invalid type: %s. One of COMBINATIONAL", + argv[i]); +#ifdef SIS + fprintf(siserr, ", SEQUENTIAL, PIPELINE"); +#endif + fprintf(siserr, " or DYNAMIC.\n"); + return 1; + } + i++; + continue; +#ifdef SIS + case 's': /* Only used for sequential type circuits */ + switch(argv[i][0]){ + case 'a': + case 'A': + psProbOption = APPROXIMATION_PS; + break; + case 'e': + case 'E': + if(network_num_latch(network) > 16){ + fprintf(siserr, "Too many states! Maximum number of latches for exact method is 16.\n"); + return 1; + } + psProbOption = EXACT_PS; + break; +/* case 'l': * Not very interesting - remove + case 'L': + if(network_num_latch(network) > 16){ + fprintf(siserr, "Too many states! Maximum number of latches for exact method is 16.\n"); + return 1; + } + psProbOption = STATELINE_PS; + break; +*/ case 'u': + case 'U': + psProbOption = UNIFORM_PS; + break; + default: + fprintf(siserr, + "Invalid PS prob calculation: %s. One of APPROXIMATION, EXACT or UNIFORM.\n", + argv[i]); + return 1; + } + i++; + continue; + case 'a': /* Only for APPROXIMATION_PS, correlation between PS lines*/ + power_setSize = atoi(argv[i]); + if((power_setSize < 1) || (power_setSize > 16)){ + fprintf(siserr, "Invalid PS lines set size: %d. Limits are 1 to 16.\n", power_setSize); + return 1; + } + i++; + continue; + case 'e': /* Only for APPROX_PS, error allowed for PS lines prob */ + power_delta = atof(argv[i]); + if(power_delta <= 0){ + fprintf(siserr, "Invalid error: %f. Must be a positive value.\n", power_delta); + return 1; + } + i++; + continue; +#endif + case 'n': /* Only used for sampling mode */ + num_samples = atoi(argv[i]); + i++; + continue; + case 'f': + info_file = fopen(argv[i], "r"); + if(info_file == NIL(FILE)){ + fprintf(siserr, "Cannot open information file: %s\n", argv[i]); + return 1; + } + i++; + continue; + case 'h': + power_usage(); + return 0; +/* Undocumented options: might be useful for someone else, so leave them here */ +#ifdef SIS + case 'R': /* Sets latch capacitances to 0, only comb power reported */ + power_cap_in_latch = power_cap_out_latch = 0; + continue; +#endif + case 'M': /* Until how many inputs we assume transistor resizing */ + input_sizing = atoi(argv[i]); + i++; + continue; + case 'S': + sop_or_fact = SUM_OF_PRODUCTS; + continue; + case 'N': + sample_gap = atoi(argv[i]); + i++; + continue; + case 'V': + power_verbose = atoi(argv[i]); + i++; + continue; + default: /* Came here => Bad option */ + fprintf(siserr, "Option %s not understood\n", argv[i-1]); + power_usage(); + return 1; + } + + if(mode == BDD_MODE) + status = power_main_driver(network, type, delay, psProbOption, + info_file, sop_or_fact, input_sizing, + &total_power); + else + status = power_simulation_estimate(network, type, delay, psProbOption, + num_samples, sample_gap, info_file, + sop_or_fact, input_sizing, + &total_power); + if(status) + return 1; + + /* Print result */ + switch(type){ + case COMBINATIONAL: + fprintf(sisout, "Combinational power estimation, "); + break; +#ifdef SIS + case SEQUENTIAL: + fprintf(sisout, "Sequential power estimation"); + switch(psProbOption){ + case APPROXIMATION_PS: + if(power_setSize != 1){ + fprintf(sisout, " (setsize = %d", power_setSize); + if(power_delta != DEFAULT_PS_MAX_ALLOWED_ERROR) + fprintf(sisout, ", maxerror = %f),\n", power_delta); + else + fprintf(sisout, "), "); + } + else + if(power_delta != DEFAULT_PS_MAX_ALLOWED_ERROR) + fprintf(sisout, " (maxerror = %f), ", power_delta); + else + fprintf(sisout, ", "); + break; + case EXACT_PS: + fprintf(sisout, " (Exact method), "); + break; + case UNIFORM_PS: + fprintf(sisout, " (Uniform method), "); + } + break; + case PIPELINE: + fprintf(sisout, "Pipeline power estimation, "); + break; +#endif + case DYNAMIC: + fprintf(sisout, "Dynamic power estimation.\n"); + } + if(type != DYNAMIC) + switch(delay){ + case 0: + fprintf(sisout, "with Zero delay model.\n"); + break; + case 1: + fprintf(sisout, "with Unit delay model.\n"); + break; + default: + fprintf(sisout, "with General delay model.\n"); + } + if(mode == SAMPLE_MODE) + fprintf(sisout, "Using Sampling, #vectors = %d\n", + num_samples * sizeof(long) * 8); + + fprintf(sisout, "Network: %s, Power = %.1f uW assuming 20 MHz clock and Vdd = 5V\n", + network_name(network), total_power); + + return 0; +} + + +/* Simple interface (Note: corresponding sample routine is in power_sample.c) */ +int power_estimate(network, type, delay, total_power) +network_t *network; +int type; +int delay; +double *total_power; +{ + int status; + + if(network == NIL(network_t)){ + fprintf(siserr, "Power estimation routine called with NULL network.\n"); + return 1; + } + + /* Default values for global variables */ + power_setSize = 1; + power_delta = DEFAULT_PS_MAX_ALLOWED_ERROR; + power_verbose = 0; + power_cap_in_latch = CAP_IN_LATCH; /* Default I/O latch capacitances */ + power_cap_out_latch = CAP_OUT_LATCH; + + status = power_main_driver(network, type, delay, APPROXIMATION_PS, + NIL(FILE), FACTORED_FORM, + DEFAULT_MAX_INPUT_SIZING, total_power); + return status; +} + + +/* Interface with all options - calling routine must define GLOBAL variables: + power_setSize, power_delta, power_verbose, power_cap_in/out_latch */ +int power_main_driver(network, type, delay, psProbOption, info_file, + sop_or_fact, input_sizing, total_power) +network_t *network; +int type; +int psProbOption; +FILE *info_file; +int sop_or_fact; +int input_sizing; +double *total_power; +{ + st_table *info_table; + node_t *node; + node_info_t *info; + int status; + st_generator *gen; + + /* Calculate node capacitances */ + info_table = power_get_node_info(network, info_file, sop_or_fact, + input_sizing); + if (info_file) { + fclose(info_file); + } + + /* Calculate node delays */ + switch(delay){ + case 0: + st_foreach_item(info_table, gen, (char **) &node, (char **) &info){ + if(info->delay == -1) /* Otherwise already specified */ + info->delay = 0; + } + break; + case 1: + st_foreach_item(info_table, gen, (char **) &node, (char **) &info){ + if(info->delay == -1) /* Otherwise already specified */ + info->delay = 1; + } + break; + default: + status = delay_trace(network, DELAY_MODEL_MAPPED); + if(!status){ + fprintf(siserr, "Something's wrong! No library loaded?!...\n"); + return 1; + } + st_foreach_item(info_table, gen, (char **) &node, (char **) &info){ + if(info->delay == -1) /* Otherwise already specified */ + info->delay = power_get_mapped_delay(node); + } + } + + /* Now we have info needed, call the appropriate routine */ + switch(type){ + case COMBINATIONAL: + switch(delay){ + case 0: + status = power_comb_static_zero(network, info_table, total_power); + break; + default: + status = power_comb_static_arbit(network, info_table, total_power); + } + break; +#ifdef SIS + case SEQUENTIAL: + status = power_seq_static_arbit(network, info_table, psProbOption, + total_power); + break; + case PIPELINE: + status = power_pipe_arbit(network, info_table, total_power); + break; +#endif + case DYNAMIC: + status = power_dynamic(network, info_table, total_power); + break; + default: + fprintf(siserr, "Internal error!!! Unknown mode in power_main_driver!\n"); + return 1; + } + + st_foreach_item(info_table, gen, (char **) &node, (char **) &info){ + FREE(info); + } + st_free_table(info_table); + + return status; +} + + +st_table *power_get_node_info(network, file, sop_or_fact, input_sizing) +network_t *network; +FILE *file; +int sop_or_fact; +int input_sizing; +{ + st_table *info_table; + node_t *node; + power_info_t *power_info; + node_info_t *node_info; + lsGen gen; + + if(power_info_table != NIL(st_table)) + power_free_info(); + + power_info_table = st_init_table(st_ptrcmp, st_ptrhash); + + info_table = st_init_table(st_ptrcmp, st_ptrhash); + + power_fill_info_table_from_file(info_table, network, file, sop_or_fact, + input_sizing); + + foreach_node(network, gen, node){ + + if(st_lookup(power_info_table, (char *) node, (char **) &power_info)) + continue; /* Info already specified from the file */ + + power_info = ALLOC(power_info_t, 1); + node_info = ALLOC(node_info_t, 1); + + if(node_function(node) == NODE_PI){ + if(network_is_real_pi(network, node)) + power_info->cap_factor = 0; + else /* Latch output */ + power_info->cap_factor = power_cap_out_latch; + if(sop_or_fact == SUM_OF_PRODUCTS) + power_info->cap_factor += + load_sum_of_products(network, node, input_sizing); + else + power_info->cap_factor += + load_factored_form(network, node, input_sizing); + node_info->delay = -1; /* Mark it not initialized */ + node_info->prob_one = 0.5; + } + else if(node_function(node) == NODE_PO){ /* These won't be used */ + power_info->cap_factor = 0; + node_info->delay = -1; /* Mark it not initialized */ + node_info->prob_one = 0.0; + } + else{ /* This is an internal node */ + if(sop_or_fact == SUM_OF_PRODUCTS) + power_info->cap_factor = /* Output load + Internal dissipation*/ + load_sum_of_products(network, node, input_sizing) + + node_num_literal(node) / 2; + else + power_info->cap_factor = + load_factored_form(network, node, input_sizing) + + factor_num_literal(node) / 2; + node_info->delay = -1; /* Mark it not initialized */ + node_info->prob_one = 0.0; /* Won't be used */ + } + power_info->switching_prob = 0.0; + st_insert(power_info_table, (char *) node, (char *) power_info); + st_insert(info_table, (char *) node, (char *) node_info); + } + + return info_table; +} + + +static void power_fill_info_table_from_file(info_table, network, file, + sop_or_fact, input_sizing) +st_table *info_table; +network_t *network; +FILE *file; +int sop_or_fact; +int input_sizing; +{ + char buffer[100]; + power_info_t *power_info; + node_info_t *node_info; + node_t *node; + + if(file == NIL(FILE)) /* Nothing to read */ + return; + + while(1){ + if(fscanf(file, "%s", buffer) != EOF){ + TOP: + if(!strcmp(buffer, "name")){ /* New gate record beginning */ + power_info = ALLOC(power_info_t, 1); + node_info = ALLOC(node_info_t, 1); + /* Put in the default values in the info structure */ + if(fscanf(file, "%s", buffer) == EOF){ + fprintf(siserr, "Sudden end of file in input\n"); + FREE(power_info); + FREE(node_info); + return; + } + node = network_find_node(network, buffer); + if(node == NIL(node_t)){ + fprintf(siserr, "Cannot find node %s in network\n", buffer); + /* Scan in but ignore rest of this record */ + while(fscanf(file, "%s", buffer) != EOF){ + if(!strcmp(buffer, "name")) + break; /* Got to a new record */ + } + if(!strcmp(buffer, "name")) + goto TOP; + else + goto BRKPT; + } + power_info->switching_prob = 0.0; + st_insert(power_info_table, (char *) node, (char *) power_info); + st_insert(info_table, (char *) node, (char *) node_info); + if(node_function(node) == NODE_PI){ + if(network_is_real_pi(network, node)) + power_info->cap_factor = 0; + else /* Latch output */ + power_info->cap_factor = power_cap_out_latch; + if(sop_or_fact == SUM_OF_PRODUCTS) + power_info->cap_factor += + load_sum_of_products(network, node, input_sizing); + else + power_info->cap_factor += + load_factored_form(network, node, input_sizing); + node_info->delay = -1; /* Mark it not initialized */ + node_info->prob_one = 0.0; + } + else if(node_function(node) == NODE_PO){ /* Won't be used */ + power_info->cap_factor = 0; + node_info->delay = 0; + node_info->prob_one = 0.0; + } + else{ /* This is an internal node */ + if(sop_or_fact == SUM_OF_PRODUCTS) + power_info->cap_factor = + load_sum_of_products(network, node, input_sizing) + + node_num_literal(node) / 2; + else + power_info->cap_factor = + load_factored_form(network, node, input_sizing) + + factor_num_literal(node) / 2; + node_info->delay = -1; /* Mark not it initialized */ + node_info->prob_one = 0.0; /* Won't be used */ + } + } /* End if(!strcmp(buffer, "name")) */ + + /* Now we have the default values in there. Should read in + non-default values, provided in file */ + + if(!strcmp(buffer, "cap_factor")){ + if(fscanf(file, "%s", buffer) == EOF){ + fprintf(siserr, "Sudden end in information file\n"); + return; + } + power_info->cap_factor = atoi(buffer); + continue; + } + if(!strcmp(buffer, "delay")){ + if(fscanf(file, "%s", buffer) == EOF){ + fprintf(siserr, "Sudden end in information file\n"); + return; + } + node_info->delay = atoi(buffer); + continue; + } + if(!strcmp(buffer, "p0")){ + if(fscanf(file, "%s", buffer) == EOF){ + fprintf(siserr, "Sudden end in information file\n"); + return; + } + node_info->prob_one = 1.0 - atof(buffer); + continue; + } + if(!strcmp(buffer, "p1")){ + if(fscanf(file, "%s", buffer) == EOF){ + fprintf(siserr, "Sudden end in information file\n"); + return; + } + node_info->prob_one = atof(buffer); + continue; + } + } /* Ends fscanf main loop */ + else{ + BRKPT: + break; /* Get out of the loop */ + } + } /* End while(1) */ +} + + +/* +* Assume that a delay trace has been performed. +* Obtain the delay values of the nodes. +* Multiply by 5 to return an integer value. +*/ +int power_get_mapped_delay(node) +node_t *node; +{ + node_t *fanin; + delay_time_t delay; + double max, + act_delay; + int i, + int_delay; + + max = -1.0; + foreach_fanin(node, i, fanin){ + delay = delay_arrival_time(fanin); + if(delay.rise >= delay.fall) + if(delay.rise > max) + max = delay.rise; + else + if(delay.fall > max) + max = delay.fall; + } + + delay = delay_arrival_time(node); + if(delay.rise >= delay.fall) + act_delay = delay.rise - max; + else + act_delay = delay.fall - max; + + int_delay = (int)((act_delay + 0.1) / 0.2); + + return int_delay; +} + + +static int load_sum_of_products(network, node, input_sizing) +network_t *network; +node_t *node; +int input_sizing; +{ + node_t *fanout, + *fanin; + power_info_t *power_info; + int i, + total = 0, + num_fanin, + *literal_count; + lsGen gen; + + foreach_fanout(node, gen, fanout){ + if(node_function(fanout) == NODE_PO){ + if(network_is_real_po(network, fanout)){ + if(st_lookup(power_info_table, (char *) fanout, + (char **) &power_info)) + /* Yes the information for this output has been specified */ + total += power_info->cap_factor; + } + else /* It is a latch input */ + total += power_cap_in_latch; + } + else{ + literal_count = node_literal_count(fanout); + + num_fanin = node_num_fanin(fanout); + if(num_fanin > input_sizing) + num_fanin = input_sizing; + + foreach_fanin(fanout, i, fanin){ + if(fanin == node) + break; + } + total += num_fanin * (literal_count[2*i] + literal_count[2*i + 1]); + FREE(literal_count); + }/*Number of inputs to the node determines the size of the transistors*/ + } /* times the number of times this input is used (+ and - phase) */ + + return total; +} + + +static int load_factored_form(network, node, input_sizing) +network_t *network; +node_t *node; +int input_sizing; +{ + node_t *fanout; + power_info_t *power_info; + int total = 0, + num_fanin; + lsGen gen; + + foreach_fanout(node, gen, fanout){ + if(node_function(fanout) == NODE_PO){ + if(network_is_real_po(network, fanout)){ + if(st_lookup(power_info_table, (char *) fanout, + (char **) &power_info)) + /* Yes the information for this output has been specified */ + total += power_info->cap_factor; + } + else /* It is a latch input */ + total += power_cap_in_latch; + } + else{ + num_fanin = node_num_fanin(fanout); + if(num_fanin > input_sizing) + num_fanin = input_sizing; + + total += num_fanin * factor_num_used(fanout, node); + + }/*Number of inputs to the node determines the size of the transistors*/ + } /* times the number of times this input is used (+ and - phase) */ + + return total; +} + + +static void power_usage() +{ + fprintf(siserr, "Power estimation program for CMOS Circuits\n"); +#ifdef SIS + fprintf(siserr, "Usage: power_estimate [-m c] [-d c] [-t c] [-s c] [-a n] [-e f] [-n n] [-f file]\n"); +#else + fprintf(siserr, "Usage: power_estimate [-m c] [-d n] [-t c] [-n n] [-f file]\n"); +#endif + fprintf(siserr, "-m c: estimation mode, c either SAMPLING or BDD (default).\n"); + fprintf(siserr, "-d c: delay model, c one of ZERO (default), UNIT or GENERAL (from library).\n"); +#ifdef SIS + fprintf(siserr, "-t c: estimation type, c one of COMBINATIONAL (default), SEQUENTIAL,\n PIPELINE or DYNAMIC (for dynamic domino circuits).\n"); + fprintf(siserr, "-s c: PS lines probability calculation method, c one of APPROXIMATION (default),\n EXACT or UNIFORM (0.5 is used). Only used for SEQUENTIAL type.\n"); + fprintf(siserr, "-a n: number of PS lines to be correlated (default 1). Only used for\n the APPROXIMATION method.\n"); + fprintf(siserr, "-e f: maximum error allowed for PS lines probabilities (default 0.01). Only\n used for the APPROXIMATION method.\n"); +#else + fprintf(siserr, "-t c: estimation type, c one of COMBINATIONAL (default) or DYNAMIC.\n"); +#endif + fprintf(siserr, "-n n: number of sets of %d input vectors to be simulated (default 100). Only\n used for SAMPLING mode.\n", sizeof(long) * 8); + fprintf(siserr, "-f file: specify file with input probabilities, node capacitance and delay.\n"); +} diff --git a/sis/power/power_pipe.c b/sis/power/power_pipe.c new file mode 100644 index 0000000..362edbe --- /dev/null +++ b/sis/power/power_pipe.c @@ -0,0 +1,278 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_pipe.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:06 $ + * + */ +/*--------------------------------------------------------------------------- +| This file contains routines that evaluate the power dissipation +| in various types of static pipelined circuits. +| +| power_pipe_static_zero() +| power_pipe_static_unit() +| power_pipe_static_arbit() +| power_add_pipeline_logic(); +| +| Jose' Monteiro, MIT, Feb/93 jcm@rle-vlsi.mit.edu ++--------------------------------------------------------------------------*/ + +#ifdef SIS + +#include "sis.h" +#include "power_int.h" + + +static void power_pipe_network_concatenate(); + + +int power_pipe_arbit(network, info_table, total_power) +network_t *network; +st_table *info_table; +double *total_power; +{ + st_table *leaves = st_init_table(st_ptrcmp, st_ptrhash); + array_t *poArray, + *piOrder; + bdd_manager *manager; + bdd_t *bdd; + network_t *symbolic; + node_t *node, + *pi, + *po; + power_info_t *power_info; + node_info_t *node_info; + power_pi_t *PIInfo; + double prob_node_one; + int i; + lsGen gen; + + /* First thing to do is to get the symbolic network */ + symbolic = power_symbolic_simulate(network, info_table); + + /* Add 0-delay logic to simulate outputs of registers */ + if(power_add_pipeline_logic(network, symbolic)) + return 1; + + /* Now the probability calculation for the circuit */ + poArray = array_alloc(node_t *, 0); + foreach_primary_output(symbolic, gen, po){ + array_insert_last(node_t *, poArray, po); + } + piOrder = order_nodes(poArray, /* PI's only */ 1); + if(piOrder == NIL(array_t)) + piOrder = array_alloc(node_t *, 0); + array_free(poArray); + + manager = ntbdd_start_manager(3 * network_num_pi(symbolic)); + + PIInfo = ALLOC(power_pi_t, network_num_pi(symbolic)); + for(i = 0; i < array_n(piOrder); i++){ + pi = array_fetch(node_t *, piOrder, i); + st_insert(leaves, (char *) pi, (char *) i); + node = pi->copy; /* Node in the original network */ + assert(st_lookup(info_table, (char *) node, (char **) &node_info)); + PIInfo[i].probOne = node_info->prob_one; + } + array_free(piOrder); + + *total_power = 0; + foreach_primary_output(symbolic, gen, po){ + node = po->fanin[0]; /* The actual node we are looking at */ + bdd = ntbdd_node_to_bdd(node, manager, leaves); + prob_node_one = power_calc_func_prob(bdd, PIInfo); + node = node->copy; /* Link to the original network */ + assert(st_lookup(power_info_table, (char*) node, (char**) &power_info)); + *total_power += power_info->cap_factor * prob_node_one * CAPACITANCE; + power_info->switching_prob += prob_node_one; + if(power_verbose > 50) + fprintf(sisout, "Node %s Probability %f\n", + node_name(node), prob_node_one); + } + *total_power *= 250.0; /* The 0.5 Vdd ^2 factor for a 5V Vdd */ + + ntbdd_end_manager(manager); + st_free_table(leaves); + FREE(PIInfo); + network_free(symbolic); + + return 0; +} + + +int power_add_pipeline_logic(network, symbolic) +network_t *network; +network_t *symbolic; +{ + array_t *latchArray, + *nodeArray; + network_t *zero_delay_net; + latch_t *latch; + node_t *node, + *po, + *inLatch, + *outLatch; + int i; + lsGen gen; + + /* Get the network corresponding to the whole combinational network */ + zero_delay_net = network_dup(network); + + /* Now delete the real PO gates */ + nodeArray = array_alloc(node_t *, 0); + foreach_primary_output(zero_delay_net, gen, po){ + if(network_is_real_po(zero_delay_net, po)) + array_insert_last(node_t *, nodeArray, po); + } + for(i = 0; i < array_n(nodeArray); i++){ + node = array_fetch(node_t *, nodeArray, i); + network_delete_node(zero_delay_net, node); + } + array_free(nodeArray); + + /* Short-circuit latches, also creating PO's at those nodes */ + latchArray = array_alloc(latch_t *, 0); + foreach_latch(zero_delay_net, gen, latch){ + array_insert_last(latch_t *, latchArray, latch); + } + for(i = 0; i < array_n(latchArray); i++){ + latch = array_fetch(latch_t *, latchArray, i); + inLatch = latch_get_input(latch); + outLatch = latch_get_output(latch); + network_add_primary_output(zero_delay_net, outLatch); + network_delete_latch(zero_delay_net, latch); + network_connect(inLatch, outLatch); + } + array_free(latchArray); + + /* Doesn't do any good, network_connect will crash before this test! + if(!network_is_acyclic(zero_delay_net)){ + fprintf(siserr, "Network is not acyclic! Quit!\n"); + return 1; + } */ + + /* Delete all the nodes that don't go anywhere */ + network_sweep(zero_delay_net); + + /* Now have to concatenate the networks: one instant 0 and other for t */ + power_pipe_network_concatenate(symbolic, zero_delay_net, "000"); + power_pipe_network_concatenate(symbolic, zero_delay_net, "ttt"); + + network_free(zero_delay_net); + + /* Delete all the PI's that don't go anywhere */ + nodeArray = array_alloc(node_t *, 0); + foreach_primary_input(symbolic, gen, node){ + if(node_num_fanout(node) == 0) + array_insert_last(node_t *, nodeArray, node); + } + for(i = 0; i < array_n(nodeArray); i++){ + node = array_fetch(node_t *, nodeArray, i); + network_delete_node(symbolic, node); + } + array_free(nodeArray); + + return 0; +} + + +static void power_pipe_network_concatenate(symbolic, zero_delay_net, instant) +network_t *symbolic; +network_t *zero_delay_net; +char *instant; +{ + st_table *correspondance = st_init_table(st_ptrcmp, st_ptrhash); + array_t *nodeArray, + *inArray, + *outArray; + node_t *node, + *new_node, + *fanin, + *fanout; + int i, j; + char buffer[1000]; + lsGen gen; + + inArray = array_alloc(node_t *, 0); + outArray = array_alloc(node_t *, 0); + + nodeArray = network_dfs(zero_delay_net); + for(i = 0; i < array_n(nodeArray); i++){ + + node = array_fetch(node_t *, nodeArray, i); + + new_node = node_dup(node); + st_insert(correspondance, (char *) node, (char *) new_node); + network_add_node(symbolic, new_node); + + /* There is no guarantee that the names in each net are unique. + Add the prefix n0_ or nT_ to each name in the zero_delay_net */ + sprintf(buffer, "n%c_%s", instant[0] == '0' ? '0' : 'T', node->name); + network_change_node_name(symbolic, new_node, util_strsav(buffer)); + + if(node_function(node) == NODE_PI){ + array_insert_last(node_t *, inArray, new_node); + continue; + } + + if(node_function(node) == NODE_PO){ + array_insert_last(node_t *, outArray, new_node); + + /* Patch the fanin right */ + fanin = node->fanin[0]; + assert(st_lookup(correspondance, (char *) fanin, (char **) &node)); + node_patch_fanin(new_node, fanin, node); + continue; + } + + /* Came here => internal node */ + /*Patch its fanins */ + foreach_fanin(new_node, j, fanin){ + assert(st_lookup(correspondance, (char *) fanin, (char **) &node)); + node_patch_fanin(new_node, fanin, node); + } + } + array_free(nodeArray); + st_free_table(correspondance); + + /* Now we have copied the zero_delay network into the symbolic network. + The next thing to do is to link them up. */ + + /* Substitute PIs of zero_delay_net by the PIs of symbolic network */ + for(i = 0; i < array_n(inArray); i++){ + new_node = array_fetch(node_t *, inArray, i); + + sprintf(buffer, "%s_%s", &(new_node->name[3]), instant); + node = network_find_node(symbolic, buffer); + + foreach_fanout(new_node, gen, fanout){ + node_patch_fanin(fanout, new_node, node); + } + network_delete_node(symbolic, new_node); + } + array_free(inArray); + + /* Connect the POs of zero_delay_net to the respective PIs of symbolic + network */ + for(i = 0; i < array_n(outArray); i++){ + new_node = array_fetch(node_t *, outArray, i); + + sprintf(buffer, "%s_%s", &(new_node->name[3]), instant); + node = network_find_node(symbolic, buffer); + fanin = new_node->fanin[0]; + + foreach_fanout(node, gen, fanout){ + node_patch_fanin(fanout, node, fanin); + } + network_delete_node(symbolic, new_node); + network_delete_node(symbolic, node); + } + array_free(outArray); + + /* Check to make sure that network thing is valid */ + assert(network_check(symbolic)); +} + +#endif /* SIS */ diff --git a/sis/power/power_psAppr.c b/sis/power/power_psAppr.c new file mode 100644 index 0000000..1075189 --- /dev/null +++ b/sis/power/power_psAppr.c @@ -0,0 +1,801 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_psAppr.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:06 $ + * + */ +/*--------------------------------------------------------------------------- +| Calculate PS lines probabilities of a FSM directly (without +| enumerating the states of the FSM). +| +| power_direct_PS_lines_prob() +| power_place_PIs_last() +| +| Jose' Monteiro, MIT, Oct/93 jcm@rle-vlsi.mit.edu ++--------------------------------------------------------------------------*/ + +#ifdef SIS + +#include "sis.h" +#include "power_int.h" + +#define TINY 1.0e-20; + +static array_t *orderPSLines(); +static array_t *addOutputLogic(); +static node_t **addNewNSSet(); +static void update_PSLines_prob(); + +static double *calculate_line_prob(); +static double *power_calc_func_cofact_prob(); +static double *power_count_f_cof_probPS(); +static double *power_count_f_cof_probPI(); +static void multiply_PS_prob(); +static void calculate_next_iteration(); + +static void ludcmp(); +static void lubksb(); + +static double *save_vector(); + +static st_table *visited; +static power_pi_t *PIInfo; + + +double *power_direct_PS_lines_prob(network, info_table, symbPSOrder, symbolic) +network_t *network; +st_table *info_table; +array_t **symbPSOrder; +network_t *symbolic; +{ + network_t *nsLogic; + array_t *psOrder, + *poArray, + *newNSs; + node_t *node; + double *lineProb; + char name[1000]; + int i; + lsGen gen; + + /* Get the network corresponding to the NS logic */ + nsLogic = network_dup(network); + + /* Now delete the real PO nodes */ + poArray = array_alloc(node_t *, 0); + foreach_primary_output(nsLogic, gen, node){ + array_insert_last(node_t *, poArray, node); + } + for(i = 0; i < array_n(poArray); i++){ + node = array_fetch(node_t *, poArray, i); + if(network_latch_end(node) == NIL(node_t)) + /* This is a pure PO */ + network_delete_node(nsLogic, node); + } + array_free(poArray); + + /* Delete all the nodes that don't go anywhere */ + network_csweep(nsLogic); + + if(power_setSize != 1){ + /* Generate sets of PS lines */ + psOrder = orderPSLines(nsLogic); + /* Generate output logic for next state */ + newNSs = addOutputLogic(nsLogic, psOrder); + } + else{ + newNSs = array_alloc(node_t *, 0); + psOrder = array_alloc(node_t *, 0); + foreach_primary_output(nsLogic, gen, node){ + array_insert_last(node_t *, newNSs, node); + array_insert_last(node_t *, psOrder, network_latch_end(node)); + } + } + + lineProb = calculate_line_prob(nsLogic, network, info_table,psOrder,newNSs); + + if(power_setSize == 1){ + update_PSLines_prob(network, info_table, lineProb, psOrder); + *symbPSOrder = psOrder; /* Return something, won't be used */ + } + else{ + *symbPSOrder = array_alloc(node_t *, 0); + for(i = 0; i < array_n(psOrder); i++){ + node = array_fetch(node_t *, psOrder, i); + sprintf(name, "%s_nsl", node->name); + node = network_find_node(symbolic, name); + array_insert_last(node_t *, *symbPSOrder, node); + } + array_free(psOrder); + } + + array_free(newNSs); + network_free(nsLogic); + + return lineProb; +} + + +static double *calculate_line_prob(nsLogic, network, info_table, psOrder,newNSs) +network_t *nsLogic; +network_t *network; +st_table *info_table; +array_t *psOrder; +array_t *newNSs; +{ + st_table *leaves = st_init_table(st_ptrcmp, st_ptrhash); + array_t *poArray, + *piOrder; + bdd_manager *manager; + bdd_t *bdd; + node_info_t *info; + node_t *pi, + *po, + *node; + double *allpsLinesProb, /* To be returned */ + *psLinesProb, /* Without the redundant value per set */ + *Y_J_values, + *Y, + *J; + int i, j, + remain, + nSets, + psPerSet, + nNSLines, + n_iter = 0, + converged; + lsGen gen; + + /* Initialize bdd manager for next state logic */ + poArray = array_alloc(node_t *, 0); + foreach_primary_output(nsLogic, gen, po){ + array_insert_last(node_t *, poArray, po); + } + piOrder = order_nodes(poArray, /* PI's only */ 1); + if(piOrder == NIL(array_t)) + piOrder = array_alloc(node_t *, 0); + array_free(poArray); + + power_place_PIs_last(&piOrder, psOrder);/* Also works for power_setSize=1*/ + + manager = ntbdd_start_manager(3 * network_num_pi(nsLogic)); + + PIInfo = ALLOC(power_pi_t, array_n(piOrder)); + for(i = 0; i < array_n(piOrder); i++){ + pi = array_fetch(node_t *, piOrder, i); + st_insert(leaves, (char *) pi, (char *) i); + if(i < array_n(psOrder)) /* Then it's a PS line */ + continue; + node = network_find_node(network, pi->name); + assert(st_lookup(info_table, (char *) node, (char **) &info)); + PIInfo[i].probOne = info->prob_one; + } + array_free(piOrder); + + /* Alloc vector of solutions */ + nNSLines = array_n(newNSs); + psPerSet = 1 << power_setSize; + nSets = array_n(psOrder) / power_setSize; + remain = nNSLines - nSets * (psPerSet - 1); + if(remain){ + remain++; /* ++ to include the all ones lines */ + allpsLinesProb = ALLOC(double, (nSets + 1) * psPerSet); + for(i = nSets * psPerSet + remain; i < (nSets + 1) * psPerSet; i++) + allpsLinesProb[i] = 0.0; /* Won't be used, make things generic */ + } + else + allpsLinesProb = ALLOC(double, nSets * psPerSet); + + /* Initial solution */ + for(i = 0; i < nSets * psPerSet; i++) /* Some waste for setSize = 1 */ + allpsLinesProb[i] = 1.0 / psPerSet; + for(i = nSets * psPerSet; i < nSets * psPerSet + remain; i++) + allpsLinesProb[i] = 1.0 / remain; + psLinesProb = ALLOC(double, nNSLines); + for(i = 0; i < nSets * (psPerSet - 1); i++) + psLinesProb[i] = 1.0 / psPerSet; + for(i = nSets * (psPerSet - 1); i < nNSLines; i++) + psLinesProb[i] = 1.0 / remain; + + /* Alloc Y vector and J jacobian matrix */ + Y = ALLOC(double, nNSLines); + J = ALLOC(double, nNSLines * nNSLines); + + /* Format of the Y_J_values array: + + f__ | f |... nNSLines times | y | + psi psi i + */ + do{ /* Iteration loop */ + for(i = 0; i < nNSLines; i++){ /* Build matrices */ + po = array_fetch(node_t *, newNSs, i); + bdd = ntbdd_node_to_bdd(po, manager, leaves); + Y_J_values = power_calc_func_cofact_prob(bdd, allpsLinesProb, + nNSLines,array_n(psOrder)); + for(j = 0; j < nNSLines; j ++) + J[i*nNSLines + j] = + Y_J_values[2*j] - Y_J_values[2*j + 1] + (i == j); + Y[i] = psLinesProb[i] - Y_J_values[2*nNSLines]; + FREE(Y_J_values); + } + + converged = TRUE; /* Test for convergence */ + for(i = 0; i < nNSLines; i++) + if(ABS(Y[i]) > power_delta){ + converged = FALSE; + break; + } + + calculate_next_iteration(allpsLinesProb, &psLinesProb, &Y, J, nNSLines); + + for(i = 0; i < nNSLines; i++){ /* To avoid round-off errors */ + if(psLinesProb[i] < 0.0) + psLinesProb[i] = 0.0; + if(psLinesProb[i] > 1.0) + psLinesProb[i] = 1.0; + } + + n_iter++; + } while(!converged); + + if(power_verbose > 25){ + fprintf(sisout, "Number of Iterations: %d\nLine probabilities:\n", + n_iter); + for(i = 0; i < nNSLines; i++) + fprintf(sisout, "Index: %d\t\tProb: %.3f\n", i, psLinesProb[i]); + } + + FREE(Y); + FREE(J); + FREE(PIInfo); + FREE(psLinesProb); + st_free_table(leaves); + ntbdd_end_manager(manager); + + return allpsLinesProb; +} + + +void power_place_PIs_last(piOrder, psOrder) +array_t **piOrder; +array_t *psOrder; +{ + st_table *psTable = st_init_table(st_ptrcmp, st_ptrhash); + array_t *newPIOrder = array_alloc(node_t *, 0); + node_t *node; + int i; + char *dummy = NIL(char); + + for(i = 0; i < array_n(psOrder); i++){ + node = array_fetch(node_t *, psOrder, i); + array_insert_last(node_t *, newPIOrder, node); + st_insert(psTable, (char *) node, dummy); + } + for(i = 0; i < array_n(*piOrder); i++){ + node = array_fetch(node_t *, *piOrder, i); + if(!st_lookup(psTable, (char *) node, &dummy)) + array_insert_last(node_t *, newPIOrder, node); + } + st_free_table(psTable); + array_free(*piOrder); + *piOrder = newPIOrder; +} + + +static double *power_calc_func_cofact_prob(f_bdd, psProb, nNSLines, nPSLines) +bdd_t *f_bdd; +double *psProb; +int nNSLines; +int nPSLines; +{ + double *result; + int i; + pset sets; + char *value, + *key; + st_generator *gen; + + assert(f_bdd != NIL(bdd_t)); + + visited = st_init_table(st_ptrcmp, st_ptrhash); + + sets = set_full(2 * power_setSize); + + result = power_count_f_cof_probPS(f_bdd, psProb, nNSLines,nPSLines,-1,sets); + + if(result == NIL(double)){ /* Weird case... */ + result = ALLOC(double, 2*nNSLines + 1); + for(i = 0; i < 2*nNSLines + 1; i++) + result[i] = 0.0; + } + + st_foreach_item(visited, gen, &key, &value){ + FREE(value); + } + st_free_table(visited); + + return result; +} + + +static double *power_count_f_cof_probPS(f,psProb,nNSLines,nPSLines,prevInd,sets) +bdd_t *f; +double *psProb; +int nNSLines; +int nPSLines; +long prevInd; +pset sets; +{ + bdd_t *child; + double *result, + *result1; + pset keepSets, + otherSet; + long topf; + int i, + newSet; + + if(f->node == cmu_bdd_zero(f->mgr)){ + set_free(sets); + return NIL(double); + } + if(f->node == cmu_bdd_one(f->mgr)){ + result = ALLOC(double, 2*nNSLines + 1); + for(i = 0; i < 2*nNSLines + 1; i++) + result[i] = 1.0; + multiply_PS_prob(result, prevInd, psProb, sets, nNSLines); + set_free(sets); + return result; + } + + if(st_lookup(visited, (char *) f->node, (char **) &result)){ + result1 = save_vector(result, 2*nNSLines+1); + multiply_PS_prob(result1, prevInd, psProb, sets, nNSLines); + set_free(sets); + return result1; + } + + topf = cmu_bdd_if_index(f->mgr, f->node); + + if(topf >= nPSLines){ /* First PI found, all PIs from now on */ + result = power_count_f_cof_probPI(f, nNSLines); + if((result != NIL(double)) && (prevInd >= 0)) + multiply_PS_prob(result, prevInd, psProb, sets, nNSLines); + set_free(sets); + return result; + } + + newSet = (prevInd != -1) && + ((topf / power_setSize) != (prevInd / power_setSize)); + + if(newSet){ + keepSets = sets; + sets = set_full(2 * power_setSize); + } + + otherSet = set_save(sets); + set_remove(otherSet, 2 * (topf % power_setSize) + 1); + child = bdd_else(f); + result = power_count_f_cof_probPS(child, psProb, nNSLines, nPSLines, topf, + otherSet); + FREE(child); + + set_remove(sets, 2 * (topf % power_setSize)); + child = bdd_then(f); + result1 = power_count_f_cof_probPS(child, psProb, nNSLines, nPSLines, topf, + sets); + if(result1 != NIL(double)){ + if(result == NIL(double)) + result = result1; + else{ + for(i = 0; i < 2*nNSLines + 1; i++) + result[i] += result1[i]; + FREE(result1); + } + } + FREE(child); + + if(!(topf % power_setSize)) /* First element in a set, can store result */ + st_insert(visited, (char *) f->node, + (char *) save_vector(result,2*nNSLines+1)); + + if(newSet){ + multiply_PS_prob(result, prevInd, psProb, keepSets, nNSLines); + set_free(keepSets); + } + + return result; +} + +static double *power_count_f_cof_probPI(f, nNSLines) +bdd_t *f; +int nNSLines; +{ + bdd_t *child; + double *result, + *result1; + int i, + topf; + + if(st_lookup(visited, (char *) f->node, (char **) &result)){ + result1 = save_vector(result, 2*nNSLines+1); + return result1; + } + if(f->node == cmu_bdd_zero(f->mgr)) + return NIL(double); + if(f->node == cmu_bdd_one(f->mgr)){ + result = ALLOC(double, 2*nNSLines + 1); + for(i = 0; i < 2*nNSLines + 1; i++) + result[i] = 1.0; + return result; + } + + topf = cmu_bdd_if_index(f->mgr, f->node); + + child = bdd_else(f); + result = power_count_f_cof_probPI(child, nNSLines); + if(result != NIL(double)) + for(i = 0; i < 2*nNSLines + 1; i++) + result[i] *= (1.0 - PIInfo[topf].probOne); + FREE(child); + + child = bdd_then(f); + result1 = power_count_f_cof_probPI(child, nNSLines); + if(result1 != NIL(double)){ + for(i = 0; i < 2*nNSLines + 1; i++) + result1[i] *= PIInfo[topf].probOne; + + if(result == NIL(double)) + result = result1; + else{ + for(i = 0; i < 2*nNSLines + 1; i++) + result[i] += result1[i]; + FREE(result1); + } + } + FREE(child); + + st_insert(visited, (char *) f->node, + (char *) save_vector(result, 2*nNSLines + 1)); + + return result; +} + +static void multiply_PS_prob(result, index, psProb, sets, nNSLines) +double *result; +long index; +double *psProb; +pset sets; +int nNSLines; +{ + pset inclSets; + double sumProb; + long setN; + int i, + thisSet, + setSize; + + if(power_setSize == 1){ /* This if is not need, but is much simpler */ + if(is_in_set(sets, 1)) + sumProb = psProb[index]; + else + sumProb = 1 - psProb[index]; + for(i = 0; i < 2*nNSLines + 1; i++) + if(i == 2*index) + if(is_in_set(sets, 1)) + result[i++] = 0.0; + else + result[++i] = 0.0; + else + result[i] *= sumProb; + } + else{ + setN = index / power_setSize; + setSize = (1 << power_setSize) - 1; + if((thisSet = setSize + 1) > (nNSLines+1-setN*setSize)) + thisSet = nNSLines + 1 - setN*setSize; + inclSets = power_lines_in_set(sets, thisSet); + + sumProb = 0.0; + for(i = 0; i < thisSet; i++) + if(is_in_set(inclSets, i)) + sumProb += psProb[setN*(setSize+1) + i]; + + for(i = 0; i < 2*nNSLines; i++) + if(i/(2*setSize) != setN) + result[i] *= sumProb; + result[i] *= sumProb; + + for(i = 0; i < (thisSet-1); i++) + if(!is_in_set(inclSets, i)) + result[2*(setN*setSize + i) + 1] = 0.0; + if(!is_in_set(inclSets, thisSet-1)) + for(i = 0; i < (thisSet-1); i++) + result[2*(setN*setSize + i)] = 0.0; + set_free(inclSets); + } +} + +static void calculate_next_iteration(allpsLinesProb, psLinesProb, Y, J,nNSLines) +double *allpsLinesProb; +double **psLinesProb; +double **Y; +double *J; +int nNSLines; +{ + int i, j, + *indx; + double sum, + *tmp; + + for(i = 0; i < nNSLines; i++){ + sum = 0.0; + for(j = 0; j < nNSLines; j++) + sum += J[i * nNSLines + j] * (*psLinesProb)[j]; + (*Y)[i] = sum - (*Y)[i]; + } + + indx = ALLOC(int, nNSLines); + ludcmp(J, nNSLines, indx); + lubksb(J, nNSLines, indx, *Y); + FREE(indx); + + tmp = *Y; + *Y = *psLinesProb; + *psLinesProb = tmp; + + /* Compute probability for remaining element in each set */ + if(power_setSize == 1) + for(i = 0; i < nNSLines; i++) + allpsLinesProb[i] = (*psLinesProb)[i]; + else{ + sum = 0.0; + for(i = 0, j = 0; i < nNSLines; i++, j++){ + allpsLinesProb[j] = (*psLinesProb)[i]; + sum += (*psLinesProb)[i]; + if(!((i+1) % ((1 << power_setSize) - 1)) || ((i+1) == nNSLines)){ + allpsLinesProb[++j] = 1.0 - sum; /* Last NS in set: 1-P */ + sum = 0.0; + } + } + if(sum != 0.0) /* Case of incomplete last set */ + allpsLinesProb[nNSLines] = 1.0 - sum; + } +} + + +/* Routines from "Numerical Recipes in C" */ +static void ludcmp(a, n, indx) +double *a; +int n; +int *indx; +{ + int i, + imax, + j, + k; + double big, + dum, + sum, + temp, + *vv; + + vv = ALLOC(double, n); + for(i = 0; i < n; i++){ + big = 0.0; + for(j = 0; j < n; j++) + if((temp = fabs(a[i*n + j])) > big) + big = temp; + if(big == 0.0) + fail("Singular matrix in routine LUDCMP"); + vv[i] = 1.0 / big; + } + for(j = 0; j < n; j++){ + for(i = 0; i < j; i++){ + sum = a[i*n + j]; + for(k = 0; k < i; k++) + sum -= a[i*n + k] * a[k*n + j]; + a[i*n + j] = sum; + } + big = 0.0; + for(i = j; i < n; i++){ + sum = a[i*n + j]; + for(k = 0; k < j; k++) + sum -= a[i*n + k] * a[k*n + j]; + a[i*n + j] = sum; + if((dum = vv[i] * fabs(sum)) >= big){ + big = dum; + imax = i; + } + } + if(j != imax){ + for(k = 0; k < n; k++){ + dum = a[imax*n + k]; + a[imax*n + k] = a[j*n + k]; + a[j*n + k] = dum; + } + vv[imax] = vv[j]; + } + indx[j] = imax; + if(a[j*n + j] == 0.0) + a[j*n + j] = TINY; + if(j != n - 1){ + dum = 1.0 / a[j*n + j]; + for(i = j+1; i < n; i++) + a[i*n + j] *= dum; + } + } + FREE(vv); +} + +static void lubksb(a, n, indx, b) +double *a; +int n; +int *indx; +double b[]; +{ + int i, + ii = -1, + ip, + j; + double sum; + + for(i = 0; i < n; i++){ + ip = indx[i]; + sum = b[ip]; + b[ip] = b[i]; + if(ii != -1) + for(j = ii; j < i; j++) + sum -= a[i*n + j] * b[j]; + else + if(sum) + ii = i; + b[i] = sum; + } + for(i = n - 1; i >= 0; i--){ + sum = b[i]; + for(j = i+1; j < n; j++) + sum -= a[i*n + j] * b[j]; + b[i] = sum / a[i*n + i]; + } +} + + +static double *save_vector(vector, n) +double *vector; +int n; +{ + double *newVector; + int i; + + newVector = ALLOC(double, n); + for(i = 0; i < n; i++) + newVector[i] = vector[i]; + + return newVector; +} + + +static array_t *orderPSLines(nsLogic) +network_t *nsLogic; +{ + array_t *psOrder; + node_t *po; + lsGen gen; + + /* For now, just list the PIs. Think of a way to get a better ordering */ + psOrder = array_alloc(node_t *, 0); + foreach_primary_output(nsLogic, gen, po){ + array_insert_last(node_t *, psOrder, network_latch_end(po)); + } + + return psOrder; +} + + +static array_t *addOutputLogic(network, oldPSOrder) +network_t *network; +array_t *oldPSOrder; +{ + array_t *newNSs; + node_t **nsSet; + int nSets, + nNewNSs, + remain, + i, j; + + newNSs = array_alloc(node_t *, 0); + nSets = array_n(oldPSOrder) / power_setSize; + nNewNSs = (1 << power_setSize) - 1; /* Last element of set is (1-P) */ + + for(i = 0; i < nSets; i++){ + nsSet= addNewNSSet(network, power_setSize, nNewNSs, oldPSOrder, i); + for(j = 0; j < nNewNSs; j++) + array_insert_last(node_t *, newNSs, nsSet[j]); + FREE(nsSet); + } + remain = array_n(oldPSOrder) - power_setSize * nSets; + if(remain != 0){ + nsSet = addNewNSSet(network, remain, (1 << remain) - 1, oldPSOrder, i); + for(j = 0; j < (1 << remain) - 1; j++) + array_insert_last(node_t *, newNSs, nsSet[j]); + FREE(nsSet); + } + + return newNSs; +} + + +static node_t **addNewNSSet(network, setSize, nNewNSs, oldPSOrder, i) +network_t *network; +int setSize; +int nNewNSs; +array_t *oldPSOrder; +int i; +{ + node_t *node, + **newNSSet, + **toOldNSs; + pset implic; + pset_family cover; + int j, k, + mask; + + newNSSet = ALLOC(node_t *, nNewNSs); + toOldNSs = ALLOC(node_t *, setSize); + + for(j = 0; j < setSize; j++){ + node = node_alloc(); + network_add_primary_input(network, node); + toOldNSs[j] = node; + } + for(j = 0; j < nNewNSs; j++){ + node = node_alloc(); + network_add_node(network, node); + cover = sf_new(1, setSize * 2); + implic = set_new(setSize * 2); + mask = 1; + for(k = 0; k < setSize; k++, mask <<= 1){ + if(j & mask) + set_insert(implic, 2*k + 1); + else + set_insert(implic, 2*k); + } + cover = sf_addset(cover, implic); + set_free(implic); + node_replace_internal(node,nodevec_dup(toOldNSs,setSize),setSize,cover); + node_scc(node); /* make it scc-minimal, dup_free, etc. */ + newNSSet[j] = network_add_primary_output(network, node); + } + for(j = 0; j < setSize; j++){ + node = array_fetch(node_t *, oldPSOrder, i*power_setSize + j); + network_connect(network_latch_end(node), toOldNSs[j]); + } + FREE(toOldNSs); + + return newNSSet; +} + + +static void update_PSLines_prob(network, info_table, psLineProb, psOrder) +network_t *network; +st_table *info_table; +double *psLineProb; +array_t *psOrder; +{ + node_t *ps; + node_info_t *info; + int i; + + for(i = 0; i < array_n(psOrder); i++){ + ps = array_fetch(node_t *, psOrder, i); + ps = network_find_node(network, ps->name); + assert(st_lookup(info_table, (char *) ps, (char **) &info)); + info->prob_one = psLineProb[i]; + } +} + +#endif /* SIS */ diff --git a/sis/power/power_psExact.c b/sis/power/power_psExact.c new file mode 100644 index 0000000..ccd9034 --- /dev/null +++ b/sis/power/power_psExact.c @@ -0,0 +1,268 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_psExact.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:06 $ + * + */ +/*--------------------------------------------------------------------------- +| Calculates state probabilities of a FSM. Also calculates PS lines +| probabilities from state probabilities. +| +| power_PS_lines_from_state() +| power_exact_state_prob() +| +| Jose' Monteiro, MIT, Oct/93 jcm@rle-vlsi.mit.edu ++--------------------------------------------------------------------------*/ + +#ifdef SIS + +#include "sis.h" +#include "power_int.h" +#include "spMatrix.h" + +static double *power_state_prob(); +static st_table *generatePSLIndexTable(); +static void update_PSLines_prob(); + + +void power_PS_lines_from_state(network, info_table) +network_t *network; +st_table *info_table; +{ + st_table *stateIndex, + *stateLineIndex; + graph_t *stg; + vertex_t *state; + double *stateProb, + *psLinesProb; + int i, j, + nPSLines ; + char *encoding, + *key, *value; + st_generator *sgen; + lsGen gen; + + stg = stg_extract(network, 0 /* Use initial state */); + if(stg == NIL(graph_t)) + return; + + stateProb = power_state_prob(network, stg, info_table, &stateIndex); + st_foreach_item(stateIndex, sgen, &key, &value){ + FREE(key); + } + st_free_table(stateIndex); + + /* Get number of present state lines */ + nPSLines = network_num_latch(network); + psLinesProb = ALLOC(double, nPSLines); + for(i = 0; i < nPSLines; i++) + psLinesProb[i] = 0.0; + + i = 0; + stg_foreach_state(stg, gen, state){ + encoding = stg_get_state_encoding(state); + for(j = 0; j < nPSLines; j++) + if(encoding[j] == '1') + psLinesProb[j] += stateProb[i]; + else + assert(encoding[j] == '0'); + i++; + } + + if(power_verbose > 40) + for(i = 0; i < nPSLines; i++) + fprintf(sisout, "Index = %d\tProb = %f\n", i, psLinesProb[i]); + + stateLineIndex = generatePSLIndexTable(network); /* Need latch order */ + update_PSLines_prob(network, info_table, psLinesProb, stateLineIndex); + + FREE(stateProb); + FREE(psLinesProb); + st_free_table(stateLineIndex); + stg_free(stg); + network_set_stg(network, NIL(graph_t)); +} + + +double *power_exact_state_prob(network, info_table, stateIndex, stateLineIndex) +network_t *network; +st_table *info_table; +st_table **stateIndex; +st_table **stateLineIndex; +{ + graph_t *stg; + double *stateProb; + + stg = stg_extract(network, 0 /* Use initial state */); + if(stg == NIL(graph_t)) + return NIL(double); + + stateProb = power_state_prob(network, stg, info_table, stateIndex); + + stg_free(stg); + network_set_stg(network, NIL(graph_t)); + + *stateLineIndex = generatePSLIndexTable(network); /* Need latch order */ + + return stateProb; +} + + +static double *power_state_prob(network, stg, info_table, stateIndex) +network_t *network; +graph_t *stg; +st_table *info_table; +st_table **stateIndex; +{ + vertex_t *state, + *fromState; + node_t *pi; + edge_t *transition; + node_info_t *info; + char *matrix, + *transitionInput; + int i, + row, + column, + matrixSize, + spError; + double *PIProb, + transitionProb, + *matrixEntry, + *rhs, + *solution; + lsGen genPI, + genState, + genTransition; + + PIProb = ALLOC(double, network_num_pi(network)); + i = 0; + foreach_primary_input(network, genPI, pi){ + assert(st_lookup(info_table, (char *) pi, (char **) &info)); + PIProb[i] = info->prob_one; + i++; + } + + *stateIndex = st_init_table(strcmp, st_strhash); + i = 0; + stg_foreach_state(stg, genState, state){ + st_insert(*stateIndex, util_strsav(stg_get_state_encoding(state)), + (char*)i++); + } + + matrixSize = i; + matrix = spCreate(matrixSize, 0 /* Real */, &spError); + assert(spError == spOKAY); + + row = 1; + stg_foreach_state(stg, genState, state){ + if(row == matrixSize) /* Don't fill last row */ + break; + + foreach_state_inedge(state, genTransition, transition){ + + transitionInput = stg_edge_input_string(transition); + transitionProb = 1.0; + for(i = 0; transitionInput[i] != '\0'; i++) + switch(transitionInput[i]){ + case '0': + transitionProb *= (1 - PIProb[i]); + continue; + case '1': + transitionProb *= PIProb[i]; + } + + fromState = stg_edge_from_state(transition); + assert(st_lookup(*stateIndex, stg_get_state_encoding(fromState), (char **) &column)); + + matrixEntry = spGetElement(matrix, row, column+1); + spADD_REAL_ELEMENT(matrixEntry, transitionProb); + } + row++; + } + + /* Subtract 1 from elements of the diagonal, except last row */ + for(i = 1; i < matrixSize; i++){ + matrixEntry = spGetElement(matrix, i, i); + spADD_REAL_ELEMENT(matrixEntry, -1.0); + } + + /* Last line in the matrix is sum of all probabilities */ + for(i = 1; i <= matrixSize; i++){ + matrixEntry = spGetElement(matrix, matrixSize, i); + spADD_REAL_ELEMENT(matrixEntry, 1.0); + } + + /* Build right hand side (rhs) */ + rhs = ALLOC(double, matrixSize); + for(i = 0; i < (matrixSize - 1); i++) + rhs[i] = 0.0; + rhs[matrixSize - 1] = 1.0; + + spError = spOrderAndFactor(matrix, rhs, + 0.01 /*pivot selection*/, + 0.0 /*smaller than any element in the diagonal*/, + 0 /*don't restrict to diagonal pivoting*/); + assert(spError == spOKAY); +/* +spPrint(matrix, 0, 1, 1); +printf("spCondition = %f\n", spCondition(matrix, spNorm(matrix), &spError)); +assert(spError == spOKAY); +*/ + + solution = ALLOC(double, matrixSize); + spSolve(matrix, rhs, solution); + + if(power_verbose > 40) + for(i = 0; i < matrixSize; i++) + fprintf(sisout, "i = %d\t\tsolution = %f\n", i, solution[i]); + + FREE(PIProb); + FREE(rhs); + spDestroy(matrix); + + return solution; +} + + +static st_table *generatePSLIndexTable(network) +network_t *network; +{ + st_table *indexTable; + latch_t *latch; + int i = 0; + lsGen gen; + + indexTable = st_init_table(st_ptrcmp, st_ptrhash); + foreach_latch(network, gen, latch){ + st_insert(indexTable, (char*) latch_get_output(latch), (char*) i++); + } + + return indexTable; +} + + +static void update_PSLines_prob(network, info_table, psLineProb, psIndex) +network_t *network; +st_table *info_table; +double *psLineProb; +st_table *psIndex; +{ + node_t *pi; + node_info_t *info; + int index; + lsGen gen; + + foreach_primary_input(network, gen, pi){ + if(network_is_real_pi(network, pi)) + continue; + assert(st_lookup(info_table, (char *) pi, (char **) &info)); + assert(st_lookup(psIndex, (char *) pi, (char **) &index)); + info->prob_one = psLineProb[index]; + } +} + +#endif /* SIS */ diff --git a/sis/power/power_sample.c b/sis/power/power_sample.c new file mode 100644 index 0000000..2e239fc --- /dev/null +++ b/sis/power/power_sample.c @@ -0,0 +1,390 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_sample.c,v $ + * $Author: pchong $ + * $Revision: 1.3 $ + * $Date: 2004/03/16 19:11:05 $ + * + */ +/*--------------------------------------------------------------------------- +| The routines for power estimation using simulation are stored here: +| +| power_sample_estimate() +| power_simulation_estimate() +| +| Copyright (c) 1991 - Abhijit Ghosh. University of California, Berkeley +| +| Jose' Monteiro, MIT, Jun/93 jcm@rle-vlsi.mit.edu ++--------------------------------------------------------------------------*/ + +#include "sis.h" +#include "power_int.h" + +#define RAND_RANGE 0x7fffffff + + +static double *power_get_PIs_prob(); +static double power_sample_do_estimate(); +static double calculate_power(); +/* These routines were copied from ../sim/interpret.c, also static there */ +static void gen_random_pattern(); +static void simulate_network_word(); +static long simulate_network_word_rec(); +static long simulate_node_word(); + + +/* Simple interface for power estimate using sampling */ +int power_sample_estimate(network, type, delay, num_samples, total_power) +network_t *network; +int type; +int delay; +int num_samples; +double *total_power; +{ + int status; + + if(network == NIL(network_t)){ + fprintf(siserr, "Power estimation routine called with NIL network.\n"); + return 1; + } + + /* Default values for global variables */ + power_setSize = 1; + power_delta = DEFAULT_PS_MAX_ALLOWED_ERROR; + power_verbose = 0; + power_cap_in_latch = CAP_IN_LATCH; /* Default I/O latch capacitances */ + power_cap_out_latch = CAP_OUT_LATCH; + + status = power_simulation_estimate(network, type, delay, APPROXIMATION_PS, + num_samples, num_samples+1, NIL(FILE), + FACTORED_FORM, DEFAULT_MAX_INPUT_SIZING, + total_power); + return status; +} + + +/* Interface with all options - calling routine must define GLOBAL variables: + power_setSize, power_delta, power_verbose, power_cap_in/out_latch */ +int power_simulation_estimate(network, type, delay, psProbOption, num_samples, + sample_gap, info_file, sop_or_fact, input_sizing, + total_power) +network_t *network; +int type; +int delay; +int psProbOption; +int num_samples; +int sample_gap; +FILE *info_file; +int sop_or_fact; +int input_sizing; +double *total_power; +{ + st_table *info_table; + array_t *psOrder; + network_t *symbolic; + node_info_t *info; + node_t *node; + double *probPI, + *psLineProb; + int status; + st_generator *gen; + + /* Calculate node capacitances */ + info_table = power_get_node_info(network, info_file, sop_or_fact, + input_sizing); + if (info_file) { + fclose(info_file); + } + + /* Calculate node delays */ + switch(delay){ + case 0: + st_foreach_item(info_table, gen, (char **) &node, (char **) &info){ + if(info->delay == -1) /* Otherwise already specified */ + info->delay = 0; + } + break; + case 1: + st_foreach_item(info_table, gen, (char **) &node, (char **) &info){ + if(info->delay == -1) /* Otherwise already specified */ + info->delay = 1; + } + break; + default: + status = delay_trace(network, DELAY_MODEL_MAPPED); + if(!status){ + fprintf(siserr, "Something's wrong! No library loaded?!...\n"); + return 1; + } + st_foreach_item(info_table, gen, (char **) &node, (char **) &info){ + if(info->delay == -1) /* Otherwise already specified */ + info->delay = power_get_mapped_delay(node); + } + } + + /* First create the symbolic network */ + symbolic = power_symbolic_simulate(network, info_table); + + switch(type){ + case COMBINATIONAL: + break; /* Nothing to be done */ +#ifdef SIS + case PIPELINE: + if(power_add_pipeline_logic(network, symbolic)) + return 1; + break; + case SEQUENTIAL: /* For sampling, only PSlines probability */ + if(power_add_fsm_state_logic(network, symbolic)) + return 1; + switch(psProbOption){ + case EXACT_PS: + case STATELINE_PS: + fprintf(siserr, "Warning, this version doesn't support exact state probabilities in sample mode.\nThe approximate method will be used.\n"); + case APPROXIMATION_PS: /* Line prob. will be changed inside */ + if(power_setSize != 1){ + fprintf(siserr, "Warning, this version doesn't support correlation between PS lines in sample\nmode. The approximate method will be used with set size 1.\n"); + power_setSize = 1; + } + psLineProb = power_direct_PS_lines_prob(network, info_table, + &psOrder, symbolic); + FREE(psLineProb); + array_free(psOrder); + break; + case UNIFORM_PS: + break; + default: + fprintf(siserr, "Internal error!!! Unknown option in power_simulation_estimate!\n"); + return 1; + } + break; +#endif /* SIS */ + case DYNAMIC: + fprintf(siserr, "Error! Sorry, this version does not support dynamic circuits in sample mode.\n"); + return 1; + default: + fprintf(siserr, "Internal error!!! Unknown type in power_simulation_estimate!\n"); + return 1; + } + + probPI = power_get_PIs_prob(symbolic, info_table); + + /* Now simulate network to estimate power */ + *total_power = power_sample_do_estimate(symbolic, num_samples, sample_gap, + probPI); + + FREE(probPI); + st_foreach_item(info_table, gen, (char **) &node, (char **) &info){ + FREE(info); + } + st_free_table(info_table); + + network_free(symbolic); + + return 0; +} + + +static double power_sample_do_estimate(network, num_iter, num_gap, probPI) +network_t *network; +int num_iter, num_gap; +double *probPI; +{ + double total_power; + long mask, + *pi_values, + *po_values; + int i, j, k, + n_pi, + n_po, + seed, + *n_ones, + num_since_last = 0; + + n_pi = network_num_pi(network); + n_po = network_num_po(network); + pi_values = ALLOC(long, n_pi); + po_values = ALLOC(long, n_po); + n_ones = ALLOC(int, n_po); + for(i = 0; i < n_po; i++) + n_ones[i] = 0; + + for(i = 0; i < num_iter; i++, num_since_last++){ + seed = (int)time(0); + gen_random_pattern(n_pi, pi_values, seed, probPI); + simulate_network_word(network, pi_values, po_values); + + for(j = 0; j < n_po; j++){ + mask = 1; + for(k = 0; k < sizeof(long) * 8; k++){ + n_ones[j] += ((po_values[j] & mask) != 0); + mask <<= 1; + } + } + + if(num_since_last == num_gap){ + num_since_last = 0; + fprintf(sisout, "Iteration %d :: Power %f\n", + (i+1) * sizeof(long) * 8, + calculate_power(network, n_ones, i+1)); + } + } + + total_power = calculate_power(network, n_ones, i); + FREE(pi_values); + FREE(po_values); + FREE(n_ones); + + return total_power; +} + +static double calculate_power(network, n_ones, i) +network_t *network; +int *n_ones; +int i; +{ + node_t *po; + power_info_t *power_info; + int i_po; + double power = 0.0; + lsGen gen; + + i *= sizeof(long) * 8; + i_po = 0; + + foreach_primary_output(network, gen, po){ + po = po->fanin[0]->copy; /* Link to the original network */ + assert(st_lookup(power_info_table, (char*) po, (char**) &power_info)); + power_info->switching_prob = ((double) n_ones[i_po]) / i; + power += ((((double) n_ones[i_po]) / i) * power_info->cap_factor); + i_po++; + } + + return power * CAPACITANCE * 250.0; +} + + +static double *power_get_PIs_prob(symbolic, info_table) +network_t *symbolic; +st_table *info_table; +{ + node_t *pi; + node_info_t *info; + double *probPI; + int i; + lsGen gen; + + probPI = ALLOC(double, network_num_pi(symbolic)); + + i = 0; + foreach_primary_input(symbolic, gen, pi){ + pi = pi->copy; /* Link to the original network */ + assert(st_lookup(info_table, (char *) pi, (char **) &info)); + probPI[i++] = info->prob_one; + } + + return probPI; +} + + +static void gen_random_pattern(n, pattern, seed, probPI) +int n; +long *pattern; +int seed; +double *probPI; +{ + int i, j; + + srandom(seed); + for(i = 0; i < n; i++){ + pattern[i] = 0; + for(j = 0; j < sizeof(long) * 8; j++) + if(random() < ((int) (probPI[i] * RAND_RANGE))) + pattern[i] |= 1 << j; + } +} + +static void simulate_network_word(network, pi_values, po_values) +network_t *network; +long *pi_values; +long *po_values; +{ + st_table *table = st_init_table(st_ptrcmp, st_ptrhash); + lsGen gen; + node_t *pi, + *po, + *input; + int i; + + i = 0; + foreach_primary_input(network, gen, pi){ + st_insert(table, (char *) pi, (char *) pi_values[i]); + i++; + } + i = 0; + foreach_primary_output(network, gen, po){ + input = node_get_fanin(po, 0); + po_values[i] = simulate_network_word_rec(network, table, input); + i++; + } + st_free_table(table); +} + +static long simulate_network_word_rec(network, table, node) +network_t *network; +st_table *table; +node_t *node; +{ + node_t *input; + long result, + **inputs; + int i, + n_inputs = node_num_fanin(node); + char *value; + + if(st_lookup(table, (char *) node, &value)) + return (long) value; + + assert(node->type != PRIMARY_INPUT); + inputs = ALLOC(long *, 4); + for(i = 0; i < 4; i++) + inputs[i] = ALLOC(long, n_inputs); + for(i = 0; i < n_inputs; i++){ + input = node_get_fanin(node, i); + inputs[ONE][i] = simulate_network_word_rec(network, table, input); + inputs[ZERO][i] = ~ inputs[ONE][i]; + inputs[TWO][i] = ~ 0l; + } + result = simulate_node_word(node, inputs); + st_insert(table, (char *) node, (char *) result); + for(i = 0; i < 4; i++) + FREE(inputs[i]); + FREE(inputs); + + return result; +} + +static long simulate_node_word(node, inputs) +node_t *node; +long **inputs; +{ + register int i, j; + node_t *fanin; + node_cube_t cube; + long result = 0, + and_result; + int num_cubes = node_num_cube(node), + literal; + + for(i = 0; i < num_cubes; i++){ + and_result = ~ 0l; + cube = node_get_cube(node, i); + foreach_fanin(node, j, fanin){ + literal = node_get_literal(cube, j); + and_result &= inputs[literal][j]; + } + result |= and_result; + } + + return result; +} diff --git a/sis/power/power_seq.c b/sis/power/power_seq.c new file mode 100644 index 0000000..1b30926 --- /dev/null +++ b/sis/power/power_seq.c @@ -0,0 +1,431 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_seq.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:06 $ + * + */ +/*--------------------------------------------------------------------------- +| This file contains routines that evaluate the power dissipation +| in various types of static sequential circuits. +| +| power_seq_static_zero() +| power_seq_static_unit() +| power_seq_static_arbit() +| power_add_fsm_state_logic() +| +| Copyright (c) 1991 - Abhijit Ghosh. University of California, Berkeley +| +| Jose' Monteiro, MIT, Jan/93 jcm@rle-vlsi.mit.edu +| - Modified to be included in SIS (instead of Flames) +| - Added exact and approximate methods, calculating respectively +| state probabilities and PS lines probabilities ++--------------------------------------------------------------------------*/ + +#ifdef SIS + +#include "sis.h" +#include "power_int.h" + + +static void power_place_PS_lines_first(); +static int power_network_concatenate(); + + +/* This is the main routine for the evaluation of power in sequential circuits +*/ +int power_seq_static_arbit(network, info_table, pslOption, total_power) +network_t *network; +st_table *info_table; +int pslOption; +double *total_power; +{ + st_table *leaves = st_init_table(st_ptrcmp, st_ptrhash), + *stateIndex, + *stateLineIndex; + array_t *piOrder, + *psOrder, + *poArray; + bdd_manager *manager; + bdd_t *bdd; + network_t *symbolic; + node_t *po, + *pi, + *node, + *orig_node; + power_info_t *power_info; + node_info_t *node_info; + power_pi_t *PIInfo; + int i, + index; + double prob_node_one, + *stateProb, + *psLineProb; + char *key, *value; + st_generator *sgen; + lsGen gen; + + /* First thing to do is to get the symbolic network */ + symbolic = power_symbolic_simulate(network, info_table); + + /* Generate PI_ttt through next state logic */ + if(power_add_fsm_state_logic(network, symbolic)) + return 1; + + /* Calculate state/PSlines probability */ + switch(pslOption){ + case EXACT_PS: + stateProb = power_exact_state_prob(network, info_table, &stateIndex, + &stateLineIndex); + break; + case STATELINE_PS: /* Line prob. are changed inside */ + power_PS_lines_from_state(network, info_table); + break; + case APPROXIMATION_PS: /* Line prob. are changed inside if set size = 1 */ + psLineProb = power_direct_PS_lines_prob(network, info_table, &psOrder, + symbolic); + break; + case UNIFORM_PS: + break; + /* Do nothing: default value! */ + } + + /* Now the probability calculation for the symbolic circuit */ + poArray = array_alloc(node_t *, 0); + foreach_primary_output(symbolic, gen, po){ + array_insert_last(node_t *, poArray, po); + } + piOrder = order_nodes(poArray, /* PI's only */ 1); + if(piOrder == NIL(array_t)) + piOrder = array_alloc(node_t *, 0); + array_free(poArray); + + switch(pslOption){ + case EXACT_PS: + power_place_PS_lines_first(&piOrder, stateLineIndex); + break; + case APPROXIMATION_PS: + if(power_setSize != 1) + power_place_PIs_last(&piOrder, psOrder); + } + + manager = ntbdd_start_manager(3 * network_num_pi(symbolic)); + + PIInfo = ALLOC(power_pi_t, network_num_pi(symbolic)); + for(i = 0; i < array_n(piOrder); i++){ + pi = array_fetch(node_t *, piOrder, i); + st_insert(leaves, (char *) pi, (char *) i); + orig_node = pi->copy; /* Link to the original network */ + assert(st_lookup(info_table, (char *) orig_node, (char **) &node_info)); + PIInfo[i].probOne = node_info->prob_one; + if(pslOption == EXACT_PS) + if(st_lookup(stateLineIndex, (char *) pi->copy, (char **) &index)) + PIInfo[i].PSLineIndex = index; + else + PIInfo[i].PSLineIndex = -1; + } + array_free(piOrder); + + *total_power = 0; + foreach_primary_output(symbolic, gen, po){ + node = po->fanin[0]; /* The actual node we are looking at */ + bdd = ntbdd_node_to_bdd(node, manager, leaves); + switch(pslOption){ + case EXACT_PS: + prob_node_one = power_calc_func_prob_w_stateProb(bdd, PIInfo, + stateProb, stateIndex, st_count(stateLineIndex)); + break; + case APPROXIMATION_PS: + if(power_setSize == 1) + prob_node_one = power_calc_func_prob(bdd, PIInfo); + else + prob_node_one = power_calc_func_prob_w_sets(bdd, PIInfo, + psLineProb, array_n(psOrder)); + break; + default: + prob_node_one = power_calc_func_prob(bdd, PIInfo); + } + orig_node = node->copy; /* Correspondence to the orig. network */ + assert(st_lookup(power_info_table,(char*)orig_node,(char**)&power_info)); + *total_power += power_info->cap_factor * prob_node_one * CAPACITANCE; + power_info->switching_prob += prob_node_one; + if(power_verbose > 50) + fprintf(sisout, "Node %s Probability %f\n", + node_name(node), prob_node_one); + } + *total_power *= 250.0; /* The 0.5 Vdd ^2 factor for a 5V Vdd */ + + ntbdd_end_manager(manager); + st_free_table(leaves); + FREE(PIInfo); + network_free(symbolic); + switch(pslOption){ + case EXACT_PS: + FREE(stateProb); + st_foreach_item(stateIndex, sgen, &key, &value){ + FREE(key); + } + st_free_table(stateIndex); + st_free_table(stateLineIndex); + break; + case APPROXIMATION_PS: + FREE(psLineProb); + array_free(psOrder); + } + + return 0; +} + + +int power_add_fsm_state_logic(network, symbolic) +network_t *network; +network_t *symbolic; +{ + st_table *po_table, + *pi_table, + *ps_table; + array_t *poArray; + network_t *ns_logic; + node_t *node, + *pi, + *po; + int i; + char buffer[100]; + lsGen gen; + + /* Get the network corresponding to the NS logic */ + ns_logic = network_dup(network); + + /* Now delete the real PO gates */ + poArray = array_alloc(node_t *, 0); + foreach_primary_output(ns_logic, gen, po){ + array_insert_last(node_t *, poArray, po); + } + for(i = 0; i < array_n(poArray); i++){ + node = array_fetch(node_t *, poArray, i); + if(network_latch_end(node) == NIL(node_t)){ + /* This is a pure PO */ + network_delete_node(ns_logic, node); + } + } + array_free(poArray); + + /* Delete all the nodes that don't go anywhere */ + network_csweep(ns_logic); + + /* Now have to concatenate the networks */ + /* However, we need to fill up the tables first */ + po_table = st_init_table(st_ptrcmp, st_ptrhash); + pi_table = st_init_table(st_ptrcmp, st_ptrhash); + ps_table = st_init_table(st_ptrcmp, st_ptrhash); + + foreach_primary_output(ns_logic, gen, po){ + node = network_latch_end(po); + sprintf(buffer, "%s_ttt", node->name); + pi = network_find_node(symbolic, buffer); + st_insert(po_table, (char *) po, (char *) pi); + sprintf(buffer, "%s_000", node->name); + pi = network_find_node(symbolic, buffer); + st_insert(ps_table, (char *) node, (char *) pi); + } + foreach_primary_input(ns_logic, gen, pi){ + if(network_latch_end(pi) == NIL(node_t)){ + /* It is definitely a PI */ + sprintf(buffer, "%s_000", pi->name); + node = network_find_node(symbolic, buffer); + if(node != NIL(node_t)) + st_insert(pi_table, (char *) pi, (char *) node); + } + } + + power_network_concatenate(symbolic, ns_logic, po_table, ps_table, pi_table); + + st_free_table(po_table); + st_free_table(pi_table); + st_free_table(ps_table); + network_free(ns_logic); + + /* Delete all the PI's that don't go anywhere */ + poArray = array_alloc(node_t *, 0); + foreach_primary_input(symbolic, gen, pi){ + if(node_num_fanout(pi) == 0){ + array_insert_last(node_t *, poArray, pi); + } + } + for(i = 0; i < array_n(poArray); i++){ + node = array_fetch(node_t *, poArray, i); + network_delete_node(symbolic, node); + } + array_free(poArray); + + return 0; +} + + +static void power_place_PS_lines_first(piOrder, stateLineIndex) +array_t **piOrder; +st_table *stateLineIndex; +{ + array_t *PSlines, + *PIlines; + node_t *node; + int i; + char *dummy; + + PSlines = array_alloc(node_t *, 0); + PIlines = array_alloc(node_t *, 0); + + for(i = 0; i < array_n(*piOrder); i++){ + node = array_fetch(node_t *, *piOrder, i); + if(st_lookup(stateLineIndex, (char *) node->copy, &dummy)) + array_insert_last(node_t *, PSlines, node); + else + array_insert_last(node_t *, PIlines, node); + } + array_append(PSlines, PIlines); + + array_free(PIlines); + array_free(*piOrder); + *piOrder = PSlines; +} + + +static int power_network_concatenate(symbolic_net, ns_logic, po_link_table, + ps_link_table, pi_link_table) +network_t *symbolic_net; /* Will be changed */ +network_t *ns_logic; /* Will not be freed */ +st_table *po_link_table; /* Will not be freed */ +st_table *ps_link_table; /* Will not be freed */ +st_table *pi_link_table; /* Will not be freed */ +{ + st_table *correspondance = st_init_table(st_ptrcmp, st_ptrhash); + array_t *nodeArray; + node_t *fanin, + *node, + *node2, + *new_node, + *fanout; + int i, j; + char *value, *key, *buffer; + st_generator *sgen; + lsGen gen; + + /* There is no guarantee that the names in each net are unique. Therefore + add the prefix ns_ to each name in the ns_logic network */ + nodeArray = power_network_dfs(ns_logic); + for(i = 0; i < array_n(nodeArray); i++){ + + node = array_fetch(node_t *, nodeArray, i); + + /* First change the name of the node */ + buffer = ALLOC(char, (int) strlen(node->name)+5); + sprintf(buffer, "%s_nsl", node->name); + network_change_node_name(ns_logic, node, buffer); + + new_node = node_dup(node); + network_add_node(symbolic_net, new_node); + st_insert(correspondance, (char *) node, (char *) new_node); + + if(node_function(node) == NODE_PI) + continue; + + if(node_function(node) == NODE_PO){ + /* Patch the fanin right */ + fanin = node->fanin[0]; + st_lookup(correspondance, (char *) fanin, (char **) &node); + node_patch_fanin(new_node, fanin, node); + continue; + } + + /* Came here => internal node */ + /*Patch its fanins */ + foreach_fanin(new_node, j, fanin){ + st_lookup(correspondance, (char *) fanin, (char **) &node); + node_patch_fanin(new_node, fanin, node); + } + } + array_free(nodeArray); + + /* Now we have copied the NS logic network into the symbolic network */ + /* The next thing to do is to link them up right using the link tables */ + + if(po_link_table != NIL(st_table)){ + /* In the link table, the key is a PO node in the ns_logic net and + the value is a PI node in the symbolic net */ + /* Link the PO nodes of NS Logic with some inputs of the symbolic net */ + st_foreach_item(po_link_table, sgen, (char **) &key, (char **) &value){ + node = (node_t *) key; /* PO node in NS logic */ + new_node = (node_t *) value; /* PI node in symbolic */ + st_lookup(correspondance, (char *) node, &value); + node = (node_t *) value; + if((node_function(new_node) != NODE_PI) || + (node_function(node) != NODE_PO)){ + fprintf(siserr, "error in performing linkup of PO node's \n"); + return 1; + } + node2 = node->fanin[0]; + foreach_fanout(new_node, gen, fanout){ + node_patch_fanin(fanout, new_node, node2); + } + network_delete_node(symbolic_net, new_node); + network_delete_node(symbolic_net, node); + } + } + + if(ps_link_table != NIL(st_table)){ + /* In the link table, the key is a PI in the ns_logic net, and the + value is a PI in the symbolic net */ + /* Link the PS nodes of NS Logic with some PS nodes of Symbolic net. */ + st_foreach_item(ps_link_table, sgen, (char **) &key, (char **) &value){ + node = (node_t *) key; /* PI node in NS logic */ + new_node = (node_t *) value; /* PI node in symbolic net */ + st_lookup(correspondance, (char *) node, &value); + node = (node_t *) value; + if((node_function(new_node) != NODE_PI) || + (node_function(node) != NODE_PI)){ + fprintf(siserr, "error in performing linkup of PS node's \n"); + return 1; + } + node2 = node; + foreach_fanout(new_node, gen, fanout){ + node_patch_fanin(fanout, new_node, node2); + } + node->copy = new_node->copy; /* Keep link to original network */ + network_delete_node(symbolic_net, new_node); + } + } + + if(pi_link_table != NIL(st_table)){ + /* In the link table, the key is a PI in the ns_logic net, and the + value is a PI in the symbolic net */ + /* Link the PS nodes of NS Logic with some PS nodes of Symbolic net. */ + st_foreach_item(pi_link_table, sgen, (char **) &key, (char **) &value){ + node = (node_t *) key; /* PI node in NS Logic */ + new_node = (node_t *) value; /* PI node in symbolic net */ + st_lookup(correspondance, (char *) node, &value); + node = (node_t *) value; + if((node_function(new_node) != NODE_PI) || + (node_function(node) != NODE_PI)){ + fprintf(siserr, "error in performing linkup of PI node's \n"); + return 1; + } + node2 = node; + foreach_fanout(new_node, gen, fanout){ + node_patch_fanin(fanout, new_node, node2); + } + node->copy = new_node->copy; /* Keep link to original network */ + network_delete_node(symbolic_net, new_node); + } + } + + /* Check to make sure that network thing is valid */ + assert(network_check(symbolic_net)); + + st_free_table(correspondance); + + return 0; +} + +#endif /* SIS */ diff --git a/sis/power/power_sim.c b/sis/power/power_sim.c new file mode 100644 index 0000000..7e4c6a8 --- /dev/null +++ b/sis/power/power_sim.c @@ -0,0 +1,322 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_sim.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:06 $ + * + */ +/*--------------------------------------------------------------------------- +| This file contains the symbolic simulation routine that is +| necessary for power estimation in static circuits, both combinational +| and sequential. +| +| power_symbolic_simulate() +| +| Copyright (c) 1991 - Abhijit Ghosh. U.C. Berkeley +| +| Jose' Monteiro, MIT, Jan/93 jcm@rle-vlsi.mit.edu +| - Modified to be included in SIS (instead of Flames) +| - Added power also for primary inputs ++--------------------------------------------------------------------------*/ + +#include "sis.h" +#include "power_int.h" + + +/* This is the one and only routine for symbolic simulation */ +network_t *power_symbolic_simulate(network, info_table) +network_t *network; +st_table *info_table; +{ + st_table *internal = st_init_table(st_ptrcmp, st_ptrhash); + array_t *gates, + *local_array, + *array1, + *array3, + *array4, + *before_switching, + *after_switching, + *switching_times; + network_t *symbolic_network; + node_t *actual_gate, + *a, *b, *xor, + *fanin, + *fanin1, + **old_to_gate, + **new_to_gate, + *pi1, + *pi2; + node_info_t *node_info; + delay_info_t *delay_info; + int i, j, k, l, + *array2, + next, + first, + last, + *switched, + frame, + gate_delay, + max, + min, + max_num_tr, + transition; + char buffer[1000], + *key; + st_generator *sgen; + + symbolic_network = network_alloc(); + strcpy(buffer, network_name(network)); + strcat(buffer, "_symbolic"); + network_set_name(symbolic_network, buffer); + + gates = power_network_dfs(network); + + max_num_tr = -INFINITY; + + for(i = 0; i < array_n(gates); i++){ + actual_gate = array_fetch(node_t *, gates, i); + + if(node_function(actual_gate) == NODE_PI){ + /* This is a PI gate, we have to do something special about it */ + /* All the PI and PS lines are assumed to switch at the same time */ + pi1 = node_dup(actual_gate); + pi2 = node_dup(actual_gate); + + network_add_node(symbolic_network, pi1); + sprintf(buffer, "%s_000", actual_gate->name); + network_change_node_name(symbolic_network, pi1,util_strsav(buffer)); + pi1->copy = actual_gate; /* Link to the original PI */ + + network_add_node(symbolic_network, pi2); + sprintf(buffer, "%s_ttt", actual_gate->name); + network_change_node_name(symbolic_network, pi2,util_strsav(buffer)); + pi2->copy = actual_gate; /* Link to the original PI */ + + switching_times = array_alloc(int, 1); + array_insert_last(int, switching_times, 0); + before_switching = array_alloc(node_t *, 1); + array_insert_last(node_t *, before_switching, pi1); + after_switching = array_alloc(node_t *, 1); + array_insert_last(node_t *, after_switching, pi2); + + delay_info = ALLOC(delay_info_t, 1); + delay_info->before_switching = before_switching; + delay_info->after_switching = after_switching; + delay_info->switching_times = switching_times; + st_insert(internal, (char *) actual_gate, (char *) delay_info); + + /* JCM - also calculate power for PIs */ + a = node_literal(pi1, 1); + b = node_literal(pi2, 1); + xor = node_xor(a, b); + node_free(a); + node_free(b); + network_add_node(symbolic_network, xor); + sprintf(buffer, "%s_xor_0", node_long_name(actual_gate)); + network_change_node_name(symbolic_network, xor,util_strsav(buffer)); + xor->copy = actual_gate; /* Link symbolic->original */ + network_add_primary_output(symbolic_network, xor); + + continue; + } + + if(node_function(actual_gate) == NODE_PO) + /* There is nothing to do as it is a dummy node */ + continue; + + /* Came here => node is an internal node */ + /* This part of the routine is complicated */ + /* Allocate some stuff we will need */ + switching_times = array_alloc(int, 0); + before_switching = array_alloc(node_t *, 0); + after_switching = array_alloc(node_t *, 0); + delay_info = ALLOC(delay_info_t, 1); + delay_info->before_switching = before_switching; + delay_info->after_switching = after_switching; + delay_info->switching_times = switching_times; + st_insert(internal, (char *) actual_gate, (char *) delay_info); + + if(node_num_fanin(actual_gate) == 0){ /* i.e., constant nodes */ + pi1 = node_dup(actual_gate); + network_add_node(symbolic_network, pi1); + array_insert_last(int, switching_times, 0); + array_insert_last(node_t *, delay_info->before_switching, pi1); + array_insert_last(node_t *, delay_info->after_switching, pi1); + continue; + } + + /* Get the delay of the node first */ + assert(st_lookup(info_table, (char *) actual_gate, (char**)&node_info)); + gate_delay = node_info->delay; /* Just the transport delay */ + + /* Get earliest transition arriving at gate */ + max = -INFINITY; + min = INFINITY; + foreach_fanin(actual_gate, j, fanin){ + assert(st_lookup(internal, (char *) fanin, (char **) &delay_info)); + array1 = delay_info->switching_times; + first = array_fetch(int, array1, 0); + last = array_fetch(int, array1, (array_n(array1) - 1)); + if(first < min) + min = first; + if(last > max) + max = last; + } + if((max + gate_delay) > max_num_tr) + max_num_tr = max + gate_delay; + + /* Now see what transitions are possible at the output of the gate */ + local_array = array_alloc(int *, 0); + for(j = 0; j < (max-min+1); j++){ + switched = ALLOC(int, node_num_fanin(actual_gate)); + for(k = 0; k < node_num_fanin(actual_gate); k++) + switched[k] = -1; + array_insert_last(int *, local_array, switched); + } + + foreach_fanin(actual_gate, j, fanin){ + assert(st_lookup(internal, (char *) fanin, (char **) &delay_info)); + array1 = delay_info->switching_times; + for(k = 0; k<array_n(array1); k++){ + first = array_fetch(int, array1, k) - min; + array2 = array_fetch(int *, local_array, first); + array2[j] = 1; + } + } + + /* Fix the old and new inputs array from which new gate will be made */ + old_to_gate = ALLOC(node_t *, node_num_fanin(actual_gate)); + new_to_gate = ALLOC(node_t *, node_num_fanin(actual_gate)); + foreach_fanin(actual_gate, j, fanin){ + assert(st_lookup(internal, (char *) fanin, (char **) &delay_info)); + array1 = delay_info->before_switching; + array3 = delay_info->after_switching; + array4 = delay_info->switching_times; + old_to_gate[j] = array_fetch(node_t *, array1, 0); + first = array_fetch(int, array4, 0); + if(first == min) + new_to_gate[j] = array_fetch(node_t *, array3, 0); + else + new_to_gate[j] = old_to_gate[j]; + } + + for(j = 0; j < (max-min+1); j++){ + /* Check if there is a transition at current j */ + transition = 0; + array2 = array_fetch(int *, local_array, j); + for(l = 0; l < node_num_fanin(actual_gate); l++) + if(array2[l] == 1){ + transition = 1; + break; + } + if(transition){ + next = j + 1; + + pi1 = node_dup(actual_gate); + pi2 = node_dup(actual_gate); + + network_add_node(symbolic_network, pi1); + sprintf(buffer, "%s_1_%d", actual_gate->name, j); + network_change_node_name(symbolic_network, pi1, + util_strsav(buffer)); + + network_add_node(symbolic_network, pi2); + sprintf(buffer, "%s_2_%d", actual_gate->name, j); + network_change_node_name(symbolic_network, pi2, + util_strsav(buffer)); + + array_insert_last(node_t *, before_switching, pi1); + array_insert_last(node_t *, after_switching, pi2); + array_insert_last(int, switching_times, j+min+gate_delay); + + for(k = 0; k < node_num_fanin(actual_gate); k++){ + fanin1 = node_get_fanin(actual_gate, k); /* Patch fanins */ + node_patch_fanin(pi1, fanin1, old_to_gate[k]); + node_patch_fanin(pi2, fanin1, new_to_gate[k]); + } + + a = node_literal(pi1, 1); + b = node_literal(pi2, 1); + xor = node_xor(a, b); + node_free(a); + node_free(b); + network_add_node(symbolic_network, xor); + sprintf(buffer, "%s_xor_%d", node_long_name(actual_gate), + j+min+gate_delay); + network_change_node_name(symbolic_network, xor, + util_strsav(buffer)); + xor->copy = actual_gate; /* Link symbolic->original */ + network_add_primary_output(symbolic_network, xor); + + /* Now update the new and the old to gate arrays */ + /* Note that old_to_gate changes here */ + for(k = 0; k < node_num_fanin(actual_gate); k++) + old_to_gate[k] = new_to_gate[k]; + + if(next > (max-min)) /* We are done, go out */ + break; + array2 = array_fetch(int *, local_array, next); + for(k = 0; k < node_num_fanin(actual_gate); k++){ + if(array2[k] == 1){ + fanin = node_get_fanin(actual_gate, k); + assert(st_lookup(internal, (char *) fanin, (char **) &delay_info)); + array3 = delay_info->after_switching; + array4 = delay_info->switching_times; + for(l = 0; l < array_n(array4); l++){ + frame = array_fetch(int, array4, l); + if(next+min == frame) + new_to_gate[k] = array_fetch(node_t *,array3,l); + } + } + } + } /* end if(transition) */ + else{ + /* Just make the new and old to gate arrays consistent */ + /* old_to_gate does not change in this case */ + array2 = array_fetch(int *, local_array, j+1); + for(k = 0; k < node_num_fanin(actual_gate); k++){ + if(array2[k] == 1){ + fanin = node_get_fanin(actual_gate, k); + assert(st_lookup(internal, (char *) fanin, (char **) &delay_info)); + array3 = delay_info->after_switching; + array4 = delay_info->switching_times; + for(l = 0; l < array_n(array4); l++){ + frame = array_fetch(int, array4, l); + if(j+1+min == frame) + new_to_gate[k] = array_fetch(node_t *,array3,l); + } + } + } + } /* end else above */ + } /* end for loop of variable j */ + FREE(old_to_gate); + FREE(new_to_gate); + for(j = 0; j < array_n(local_array); j++){ + array2 = array_fetch(int *, local_array, j); + FREE(array2); + } + array_free(local_array); + + } /* end outermost for loop for variable i (over all gates in network) */ + + st_foreach_item(internal, sgen, &key, (char **) &delay_info){ + array_free(delay_info->switching_times); + array_free(delay_info->after_switching); + array_free(delay_info->before_switching); + FREE(delay_info); + } + st_free_table(internal); + array_free(gates); + + assert(network_check(symbolic_network)); + + if(power_verbose){ + fprintf(sisout,"Static Timing Analysis : Normalized Delay = %d units\n", + (max_num_tr == -INFINITY) ? 0 : max_num_tr); + fflush(sisout); + } + + return symbolic_network; +} diff --git a/sis/power/power_util.c b/sis/power/power_util.c new file mode 100644 index 0000000..2f6a7e5 --- /dev/null +++ b/sis/power/power_util.c @@ -0,0 +1,177 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/power/power_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:06 $ + * + */ +/*-------------------------------------------------------------------------- +| Auxiliary routines for the power estimate package: +| +| power_free_info() +| power_print_info() +| +| power_network_dfs() +| power_network_print() +| power_lines_in_set() +| +| Copyright (c) Mar 94 - Jose' Monteiro jcm@rle-vlsi.mit.edu +| Massachusetts Institute of Technology ++-------------------------------------------------------------------------*/ + +#include "sis.h" +#include "power_int.h" + +int power_free_info() +{ + node_t *node; + power_info_t *info; + st_generator *gen; + + if(power_info_table == NIL(st_table)) + return 0; + + st_foreach_item(power_info_table, gen, (char **) &node, (char **) &info){ + FREE(info); + } + st_free_table(power_info_table); + power_info_table = NIL(st_table); + + return 0; +} + + +int power_print_info(network) +network_t *network; +{ + node_t *node; + power_info_t *info; + double PIs_power, + total_power; + lsGen gen; + + if(power_info_table == NIL(st_table)){ + fprintf(siserr, "Power for this network not estimated yet!\n"); + return 1; + } + + total_power = PIs_power = 0.0; + foreach_node(network, gen, node){ + if(node_function(node) == NODE_PO) + continue; + + if(!st_lookup(power_info_table, (char *) node, (char **) &info)){ + power_free_info(); + fprintf(siserr, "Power for this network not estimated yet!\n"); + return 1; + } + + fprintf(sisout, + "Node %-5s\tCap. = %d\tSwitch Prob. = %.2f\tPower = %.1f\n", + node->name, info->cap_factor, info->switching_prob, + 250.0 * info->cap_factor * info->switching_prob * CAPACITANCE); + total_power += 250.0 * info->cap_factor * info->switching_prob * + CAPACITANCE; + if(node_function(node) == NODE_PI) + PIs_power += 250.0 * info->cap_factor * info->switching_prob * + CAPACITANCE; + } + fprintf(sisout, "Total Power:\t%f\nPIs Power:\t%f\n", + total_power, PIs_power); + + return 0; +} + + +array_t *power_network_dfs(net) +network_t *net; +{ + st_table *input, + *output; + array_t *result, + *temp; + node_t *node, + *pi, + *po; + int i; + char *value; + lsGen gen; + + input = st_init_table(st_ptrcmp, st_ptrhash); + output = st_init_table(st_ptrcmp, st_ptrhash); + result = array_alloc(node_t *, 0); + + /* Put the PI nodes in the array first */ + foreach_primary_input(net, gen, pi){ + array_insert_last(node_t *, result, pi); + st_insert(input, (char *) pi, (char *) 0); + } + foreach_primary_output(net, gen, po){ + st_insert(output, (char *) po, (char *) 0); + } + + temp = network_dfs(net); + + /* Now put the intermediate nodes */ + for(i = 0; i < array_n(temp); i++){ + node = array_fetch(node_t *, temp, i); + if(!st_lookup(input, (char *) node, &value) && + !st_lookup(output, (char *) node, &value)) + array_insert_last(node_t *, result, node); + } + + /* Now put the PO nodes */ + foreach_primary_output(net, gen, po){ + array_insert_last(node_t *, result, po); + } + + array_free(temp); + st_free_table(input); + st_free_table(output); + + return result; +} + + +void power_network_print(net) +network_t *net; +{ + array_t *node_vec; + node_t *node; + int i; + + node_vec = power_network_dfs(net); + for(i = 0; i < array_n(node_vec); i++){ + node = array_fetch(node_t *, node_vec, i); + node_print(sisout, node); + } + array_free(node_vec); +} + + +pset power_lines_in_set(set, setSize) +pset set; +int setSize; +{ + pset inclSets = set_full(setSize); + int i, j, + mask; + + for(i = 0; i < setSize; i++) + for(j = 0, mask = 1; j < power_setSize; j++, mask <<= 1) + if(mask & i){ + if(!is_in_set(set, 2*j + 1)){ + set_remove(inclSets, i); + break; + } + } + else + if(!is_in_set(set, 2*j)){ + set_remove(inclSets, i); + break; + } + + return inclSets; +} diff --git a/sis/resub/Makefile.am b/sis/resub/Makefile.am new file mode 100644 index 0000000..f277a04 --- /dev/null +++ b/sis/resub/Makefile.am @@ -0,0 +1,7 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libresub.a +libresub_a_SOURCES = aresub.c bresub.c com_resub.c resub_int.h +pkginclude_HEADERS = resub.h +dist_doc_DATA = resub.doc diff --git a/sis/resub/Makefile.in b/sis/resub/Makefile.in new file mode 100644 index 0000000..6a1bdc2 --- /dev/null +++ b/sis/resub/Makefile.in @@ -0,0 +1,419 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libresub_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/resub +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libresub_a_AR = $(AR) $(ARFLAGS) +libresub_a_LIBADD = +am_libresub_a_OBJECTS = aresub.$(OBJEXT) bresub.$(OBJEXT) \ + com_resub.$(OBJEXT) +libresub_a_OBJECTS = $(am_libresub_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libresub_a_SOURCES) +DIST_SOURCES = $(libresub_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libresub.a +libresub_a_SOURCES = aresub.c bresub.c com_resub.c resub_int.h +pkginclude_HEADERS = resub.h +dist_doc_DATA = resub.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/resub/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/resub/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libresub.a: $(libresub_a_OBJECTS) $(libresub_a_DEPENDENCIES) + -rm -f libresub.a + $(libresub_a_AR) libresub.a $(libresub_a_OBJECTS) $(libresub_a_LIBADD) + $(RANLIB) libresub.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/resub/aresub.c b/sis/resub/aresub.c new file mode 100644 index 0000000..b8626ea --- /dev/null +++ b/sis/resub/aresub.c @@ -0,0 +1,84 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/resub/aresub.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +/* + * aresub: algebraic re-sutstitution. + * routines provided: + * resub_alge_node(); + * resub_alge_network(); + */ + +#include "sis.h" +#include "resub.h" +#include "resub_int.h" + +/* + * Substitute one function (nodep) into all other + * functions using algebraic division of the function + * default is to use complement + * if use_complement =0 then don't use it + */ +int +resub_alge_node(f,use_complement) +node_t *f; +int use_complement; +{ + array_t *target, *tl1; + node_t *np; + int i, status; + + status = 0; + if (f->type == PRIMARY_INPUT || f->type == PRIMARY_OUTPUT) { + return status; + } + + target = array_alloc(node_t *, 0); + foreach_fanin(f, i, np) { + tl1 = network_tfo(np, 1); + array_append(target, tl1); + array_free(tl1); + } + array_sort(target, node_compare_id); + array_uniq(target, node_compare_id, (void (*)()) 0); + + for(i = 0; i < array_n(target); i++) { + np = array_fetch(node_t *, target, i); + if (node_substitute(f, np, use_complement)) { + status = 1; + } + } + array_free(target); + + return status; +} + +/* + * Substitute each function in the network into all other + * functions using algebraic division of the function and + * its complement. + */ +void +resub_alge_network(network,use_complement) +network_t *network; +int use_complement; +{ + lsGen gen; + node_t *np; + bool not_done; + + not_done = TRUE; + while (not_done) { + not_done = FALSE; + foreach_node(network, gen, np) { + if (resub_alge_node(np,use_complement)) { + not_done = TRUE; + } + } + } +} diff --git a/sis/resub/bresub.c b/sis/resub/bresub.c new file mode 100644 index 0000000..4dc221b --- /dev/null +++ b/sis/resub/bresub.c @@ -0,0 +1,30 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/resub/bresub.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#include "sis.h" +#include "resub.h" +#include "resub_int.h" + +void +resub_bool_node(f) +node_t *f; +{ + (void) fprintf(miserr, "Warning!: Boolean resub has not been "); + (void) fprintf(miserr, "implemented, algebraic resub is used.\n"); + (void) resub_alge_node(f, 1); +} + +void +resub_bool_network(network) +network_t *network; +{ + (void) fprintf(miserr, "Warning!: Boolean resub has not been "); + (void) fprintf(miserr, "implemented, algebraic resub is used.\n"); + resub_alge_network(network, 1); +} diff --git a/sis/resub/com_resub.c b/sis/resub/com_resub.c new file mode 100644 index 0000000..e88f1c4 --- /dev/null +++ b/sis/resub/com_resub.c @@ -0,0 +1,90 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/resub/com_resub.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#include "sis.h" +#include "resub.h" +#include "resub_int.h" + +static void resub_usage(); + +int +com_resub(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i, c, method, use_complement; + array_t *nodevec; + + use_complement = 1; + method = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "abd")) != EOF) { + switch (c) { + case 'a': + method = 0; + break; + case 'b': + method = 1; + break; + case 'd': + use_complement = 0; + break; + default: + resub_usage(); + return 1; + } + } + + /* Note!, "resub" is different from "resub *" */ + /* "resub" iterates until no more improvement can be made. */ + if (argc - util_optind == 0) { + switch (method) { + case 1: + resub_bool_network(*network); + break; + case 0: + resub_alge_network(*network,use_complement); + break; + } + return 0; + } + + nodevec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + for(i = 0; i < array_n(nodevec); i++) { + switch (method) { + case 1: + resub_bool_node(array_fetch(node_t *, nodevec, i)); + break; + case 0: + (void) resub_alge_node(array_fetch(node_t *, nodevec, i),use_complement); + break; + } + } + array_free(nodevec); + return 0; +} + +init_resub() +{ + (void) com_add_command("resub", com_resub, 1); +} + +end_resub() +{ +} + +static void +resub_usage() +{ + (void) fprintf(miserr, "usage: resub [-abd] [node-list]\n"); + (void) fprintf(miserr, " -a\t\tAlgebraic resubstitution (default).\n"); + (void) fprintf(miserr, " -b\t\tBoolean resubstitution.\n"); + (void) fprintf(miserr, " -d\t\tDon't use complement (in algebraic resubstitution).\n"); +} diff --git a/sis/resub/resub.doc b/sis/resub/resub.doc new file mode 100644 index 0000000..357cd3a --- /dev/null +++ b/sis/resub/resub.doc @@ -0,0 +1,33 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/resub/resub.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +Summary: + resub_alge_node(); + resub_alge_network(); + + +int +resub_alge_node(f, use_complement) +node_t *f; +int use_complement; + Algebraic re-substitution of f into all other nodes in the network. + It returns 1 if f is substituted into some other notes, 0 otherwise. + If use_complement is 1, the substitution uses both f and its complement. + Because it uses algebraic division, only the immediate fanouts of the + immediate fanins of f can possibly be simplified. No action is taken + if f is a primary input, a primary output, or a + constant function. + + +void +resub_alge_network(network, use_complement) +network_t *network; +int use_complement; + Does resub_alge_node on each function in the network until no more + improvement can be made. diff --git a/sis/resub/resub.h b/sis/resub/resub.h new file mode 100644 index 0000000..c8022c2 --- /dev/null +++ b/sis/resub/resub.h @@ -0,0 +1,18 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/resub/resub.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#ifndef RESUB_H +#define RESUB_H + +EXTERN int resub_alge_node ARGS((node_t *, int)); +EXTERN void resub_alge_network ARGS((network_t *, int)); +EXTERN void resub_bool_node ARGS((node_t *)); +EXTERN void resub_bool_network ARGS((network_t *)); + +#endif diff --git a/sis/resub/resub_int.h b/sis/resub/resub_int.h new file mode 100644 index 0000000..d2472dd --- /dev/null +++ b/sis/resub/resub_int.h @@ -0,0 +1,10 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/resub/resub_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ + diff --git a/sis/retime/Makefile.am b/sis/retime/Makefile.am new file mode 100644 index 0000000..2efc461 --- /dev/null +++ b/sis/retime/Makefile.am @@ -0,0 +1,9 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libretime.a +libretime_a_SOURCES = com_retime.c re_computeWD.c re_delay.c re_export.c \ + re_graph.c re_initial.c re_milp.c re_minreg.c re_nanni.c re_net.c \ + re_simplx.c re_util.c retime_util.c retime_int.h +pkginclude_HEADERS = retime.h +dist_doc_DATA = retime.doc diff --git a/sis/retime/Makefile.in b/sis/retime/Makefile.in new file mode 100644 index 0000000..0bf7f22 --- /dev/null +++ b/sis/retime/Makefile.in @@ -0,0 +1,425 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libretime_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/retime +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libretime_a_AR = $(AR) $(ARFLAGS) +libretime_a_LIBADD = +am_libretime_a_OBJECTS = com_retime.$(OBJEXT) re_computeWD.$(OBJEXT) \ + re_delay.$(OBJEXT) re_export.$(OBJEXT) re_graph.$(OBJEXT) \ + re_initial.$(OBJEXT) re_milp.$(OBJEXT) re_minreg.$(OBJEXT) \ + re_nanni.$(OBJEXT) re_net.$(OBJEXT) re_simplx.$(OBJEXT) \ + re_util.$(OBJEXT) retime_util.$(OBJEXT) +libretime_a_OBJECTS = $(am_libretime_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libretime_a_SOURCES) +DIST_SOURCES = $(libretime_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libretime.a +libretime_a_SOURCES = com_retime.c re_computeWD.c re_delay.c re_export.c \ + re_graph.c re_initial.c re_milp.c re_minreg.c re_nanni.c re_net.c \ + re_simplx.c re_util.c retime_util.c retime_int.h + +pkginclude_HEADERS = retime.h +dist_doc_DATA = retime.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/retime/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/retime/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libretime.a: $(libretime_a_OBJECTS) $(libretime_a_DEPENDENCIES) + -rm -f libretime.a + $(libretime_a_AR) libretime.a $(libretime_a_OBJECTS) $(libretime_a_LIBADD) + $(RANLIB) libretime.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/retime/com_retime.c b/sis/retime/com_retime.c new file mode 100644 index 0000000..6084c6a --- /dev/null +++ b/sis/retime/com_retime.c @@ -0,0 +1,471 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/com_retime.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +int retime_debug; +static void retime_print_stg_data(); + +int +com_retime(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + re_graph *graph; + delay_model_t model; + network_t *new_network; + latch_synch_t old_type; + clock_setting_t setting; + int num_latch = network_num_latch(*network); + int found_unknown_type, use_mapped, minimize_reg; + int c, flag, success, milp_flag; + int can_initialize, should_initialize; + double spec_c, new_c, desired_c, init_c; + double retime_tol, area_r, delay_r; + + milp_flag = FALSE; /* To use milp formulation of Saxe's routine */ + minimize_reg = FALSE; /* To minimize registers or not */ + should_initialize = 1; /* Initialize if required */ + model = DELAY_MODEL_MAPPED; + area_r = RETIME_DEFAULT_REG_AREA; + delay_r = RETIME_DEFAULT_REG_DELAY; + use_mapped = TRUE; + + desired_c = RETIME_NOT_SET; + retime_debug = FALSE; + retime_tol = RETIME_DEF_TOL; + + error_init(); + util_getopt_reset(); + + while ((c = util_getopt(argc, argv, "fimnv:c:d:a:t:")) != EOF) { + switch (c) { + case 'n': + use_mapped = FALSE; + model = DELAY_MODEL_UNIT_FANOUT; + break; + case 'i': + should_initialize = 0; /* Do not initialize latches */ + break; + case 'm': + minimize_reg = TRUE; + break; + case 'f': + milp_flag = TRUE; + break; + case 't': + retime_tol = atof(util_optarg ); + break; + case 'd': + delay_r = atof(util_optarg ); + break; + case 'a': + area_r = atof(util_optarg ); + break; + case 'c': + desired_c = atof(util_optarg ); + break; + case 'v': + retime_debug = atoi(util_optarg); + break; + default: + goto retime_usage; + } + } + + /* + * First check if there are any latches at all + */ + if (re_empty_network(*network) || num_latch == 0){ + return 0; + } + + if (use_mapped){ + if (!lib_network_is_mapped(*network)){ + (void) fprintf(siserr,"Network is not mapped (use -n option for unmapped networks)\n"); + return 0; + } + if (lib_get_library() == NIL(library_t)){ + (void) fprintf(siserr,"Need to define a library (use -n option for unmapped networks)\n"); + return 0; + } + } + + if (!use_mapped){ + network_sweep(*network); + } + + if (!delay_trace(*network, model)){ + (void)fprintf(siserr,"%s", error_string()); + return 1; + } + + /* + * Check to see if (single phase), edge triggered system + */ + if (retime_get_clock_data(*network, use_mapped, &found_unknown_type, + &should_initialize, &old_type, &delay_r, &area_r)){ + (void)fprintf(siserr,"%s", error_string()); + return 1; + } + + if (found_unknown_type && old_type != UNKNOWN){ + (void)fprintf(sisout,"Latches with unknown synchronization type assumed %s triggered\n", + (old_type == RISING_EDGE ? "rising edge" : "falling_edge")); + } + + if (retime_debug > 20){ + (void)fprintf(sisout,"Latch-delay %5.3f, Area %6.2f\n", delay_r, area_r); + } + + if (desired_c == RETIME_NOT_SET){ + if ((spec_c = clock_get_cycletime(*network)) > 0){ + (void)fprintf(sisout,"Retiming will try to meet the cycle time of the specification\n"); + desired_c = spec_c; + } + } + if (desired_c > 0 && desired_c < delay_r){ + (void)fprintf(sisout,"Delay through register exceeds desired cycletime\n"); + return 0; + } + + /* + * Convert it into a retime graph + */ + graph = retime_network_to_graph(*network, 1, use_mapped); + if (graph == NIL(re_graph)){ + (void)fprintf(siserr,"%s", error_string()); + return 1; + } + + /* Just for checking */ + if (retime_debug > 60) { + if (!retime_check_graph(graph)){ + (void)fprintf(siserr,"%s", error_string()); + } + error_init(); + retime_dump_graph(sisout, graph); + } + + if (desired_c == RETIME_NOT_SET){ + /* Not specified in the blif file or command line */ + desired_c = delay_r + retime_cycle_lower_bound(graph); + (void)fprintf(sisout,"Lower bound on the cycle time = %5.2f\n", + desired_c); + (void)fprintf(sisout,"Retiming will minimize the cycle time \n"); + } + + init_c = re_cycle_delay(graph, delay_r); + (void)fprintf(sisout,"RETIME: Initial clk = %-5.2f, Desired clk = %-5.2f\n", + init_c, desired_c); + + if (!minimize_reg && init_c <= desired_c){ + (void)fprintf(sisout,"Circuit meets specification\n"); + re_delete_temp_nodes(*network); + re_graph_free(graph); + return 0; + } + + /* + * Retime graph returns -1 if there is an error and 0 if retiming does + * not change the network + */ + flag = retime_graph(*network, graph, area_r, delay_r, retime_tol, + desired_c, &new_c, milp_flag, minimize_reg, should_initialize, + &can_initialize); + + if (flag <= 0){ + /* + * Return the original network --- no changes made + */ + if (should_initialize && !can_initialize){ + (void)fprintf(sisout,"RETIMING DOES NOT PRESERVE INITIAL STATES --- NETWORK NOT CHANGED\n"); + (void)fprintf(sisout,"(use -i option to suppress initial-state computation)\n"); + } else { + (void)fprintf(sisout,"No latches were moved by retiming\n"); + } + re_delete_temp_nodes(*network); + re_graph_free(graph); + return 0; + } + + /* + * We call the retiming a success only if cycle time improved and we can + * get a correct set of initial states for the circuit + */ + success = FALSE; + if (minimize_reg || (new_c <= init_c)) { + success = TRUE; + } + + success = (success && can_initialize); + + if (success){ + new_network = retime_graph_to_network(graph, use_mapped); + if (new_network == NIL(network_t)){ + (void)fprintf(siserr,"Unable to reconstruct network: %s", error_string()); + re_delete_temp_nodes(*network); + return 1; + } + network_set_name(new_network, network_name(*network)); + network_clock_dup(*network, new_network); /* To recover the clocks */ + delay_network_dup(new_network, *network); /* To copy global defaults */ + network_free(*network); + *network = new_network; + + num_latch = network_num_latch(*network); + (void)fprintf(sisout,"\nfinal cycle delay = %-5.2f\n", new_c); + (void)fprintf(sisout,"final number of registers = %-d\n", num_latch); + (void)fprintf(sisout,"final logic cost = %-5.2f\n", + re_sum_node_area(graph)); + (void)fprintf(sisout,"final register cost = %-5.2f\n\n", + num_latch * area_r); + + } + + /* + * also set the value of the working cycle time to be the one achieved + */ + setting = clock_get_current_setting(*network); + clock_set_current_setting(*network, WORKING); + clock_set_cycletime(*network, new_c); + clock_set_current_setting(*network, setting); + + re_delete_temp_nodes(*network); /* Delete any temporary nodes */ + re_graph_free(graph); + + (void) fprintf(sisout,"RETIME: Final cycle time %s achieved = %-5.2f\n", + (can_initialize ? "": "that can be"), new_c); + + return 0; + +retime_usage: + (void)fprintf(sisout,"retime [-fimn] [-c #.#] [-t #.#] [-d #.#] [-a #.#] [-v #]\n"); + (void)fprintf(sisout,"-i\t\t: Do not recompute the initial states\n"); + (void)fprintf(sisout,"-n\t\t: Use delay/area of unmapped network\n"); + (void)fprintf(sisout,"-m\t\t: Minimize registers subject to given cycle time (-c option)"); + (void)fprintf(sisout,"\t\t: May be very slow for large circuits\n"); + (void)fprintf(sisout,"-f\t\t: Use MILP formulation (default is Saxe's relaxation alg)\n"); + (void)fprintf(sisout,"-c\t#.#\t: Set the desired clock period\n"); + (void)fprintf(sisout,"-t\t#.#\t: Set tolerance for binary search (default = 0.1)\n"); + (void)fprintf(sisout,"-d\t#.#\t: Set the delay thru register (with -n option only)\n"); + (void)fprintf(sisout,"-a\t#.#\t: Set the area of a register (with -n option only)\n"); + (void)fprintf(sisout,"-v\t#\t: Set the verbosity level (0-100)\n"); + return 1; +} + +/* ARGSUSED */ +int +com__print_stats(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + re_graph *graph; + double init_c; + latch_synch_t old_type; + double delay_r, area_r; + int use_mapped, num_latch, flag, to_init; + + retime_debug = FALSE; + to_init = FALSE; + area_r = RETIME_DEFAULT_REG_AREA; + delay_r = RETIME_DEFAULT_REG_DELAY; + use_mapped = TRUE; + + error_init(); + util_getopt_reset(); + + while ((c = util_getopt(argc, argv, "d:a:")) != EOF) { + switch (c) { + case 'a': + area_r = atof(util_optarg ); + break; + case 'd': + delay_r = atof(util_optarg ); + break; + default: + (void)fprintf(sisout,"Unknown option\n"); + return 1; + /* NOTREACHED */ + break; + } + } + + if (re_empty_network(*network)){ + retime_print_stg_data(network_stg(*network)); + return 0; + } + if (use_mapped && (lib_get_library() == NIL(library_t)) ){ + (void) fprintf(sisout,"Using the \"unit-fanout\" delay model\n"); + use_mapped = FALSE; + } + if (use_mapped && (!lib_network_is_mapped(*network)) ){ + (void) fprintf(sisout,"Using the \"unit-fanout\" delay model\n"); + use_mapped = FALSE; + } + + graph = retime_network_to_graph(*network, 1, use_mapped); + re_delete_temp_nodes(*network); + if (graph == NIL(re_graph)){ + (void)fprintf(siserr,"%s", error_string()); + return 1; + } + if (retime_get_clock_data(*network, use_mapped, &flag, + &to_init, &old_type, &delay_r, &area_r)){ + (void)fprintf(siserr,"%s", error_string()); + return 1; + } + (void)fprintf(sisout,"Latch-delay %5.3f, Area %6.2f\n", delay_r, area_r); + + init_c = re_cycle_delay(graph, delay_r); + + num_latch = network_num_latch(*network); + + (void)fprintf(sisout,"Cycle delay = %-5.2f\n", init_c); + (void)fprintf(sisout,"Number of registers = %-d\n", num_latch); + (void)fprintf(sisout,"Register area = %-5.2f\n", area_r * num_latch); + (void)fprintf(sisout,"Combinational area = %-5.2f\n\n", re_sum_node_area(graph)); + + retime_print_stg_data(network_stg(*network)); + re_delete_temp_nodes(*network); + + return 0; +} + +static void +retime_print_stg_data(stg) +graph_t *stg; +{ + if (stg == NIL(graph_t)) return; + + (void)fprintf(sisout, + "STG data: %d inputs, %d outputs, %d states, %d edges\n", + stg_get_num_inputs(stg), stg_get_num_outputs(stg), + stg_get_num_states(stg), stg_get_num_products(stg)); +} + +int +com__check_tr(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + lsGen gen; + latch_t *latch; + re_graph *graph; + network_t *newnet; + latch_synch_t old_type; + int c, to_init, use_mapped, found_unknown_type; + double delay_r, area_r; + + use_mapped = TRUE; + to_init = FALSE; + retime_debug = 100; + area_r = RETIME_DEFAULT_REG_AREA; + delay_r = RETIME_DEFAULT_REG_DELAY; + error_init(); + util_getopt_reset(); + + while ((c = util_getopt(argc, argv, "n")) != EOF) { + switch (c) { + case 'n': + use_mapped = FALSE; + break; + default: + (void)fprintf(sisout,"Unknown option \n"); + return 1; + /* NOTREACHED */ + break; + } + } + + if (re_empty_network(*network)){ + return 0; + } + + (void)fprintf(sisout,"Latches have true inputs\n"); + foreach_latch(*network, gen, latch){ + (void)fprintf(sisout, "%s \n", + node_name(node_get_fanin(latch_get_input(latch), 0))); + + } + (void)fprintf(sisout,"\n\n \t Initial Network \n\n"); + (void)com_execute(network, "p"); + (void)com_execute(network, "pio"); + (void)com_execute(network, "print_latch"); + if (use_mapped && !lib_network_is_mapped(*network)){ + use_mapped = FALSE; + } + graph = retime_network_to_graph(*network, 1, use_mapped); + + if (graph == NIL(re_graph)){ + (void)fprintf(siserr,"%s", error_string()); + return 1; + } + (void)fprintf(sisout,"\n\n \t Corresponding retiming graph \n\n"); + retime_dump_graph(sisout, graph); + (void)retime_check_graph(graph); + + if (retime_get_clock_data(*network, use_mapped, &found_unknown_type, + &to_init, &old_type, &delay_r, &area_r)){ + (void)fprintf(siserr,"%s", error_string()); + return 1; + } + if (found_unknown_type && old_type != UNKNOWN){ + (void)fprintf(sisout,"Latches with unknown synchronization type assumed %s triggered\n", + (old_type == RISING_EDGE ? "rising edge" : "falling_edge")); + } + + (void)fprintf(sisout,"Latch-delay %5.3f, Area %6.2f\n", delay_r, area_r); + + newnet = retime_graph_to_network(graph, use_mapped); + if (newnet == NIL(network_t)){ + (void)fprintf(siserr,"Unable to reconstruct network: %s", error_string()); + return 1; + } + + (void)fprintf(sisout,"\n\n \t Final Network \n\n"); + (void)com_execute(&newnet, "p"); + (void)com_execute(&newnet, "pio"); + (void)com_execute(&newnet, "print_latch"); + + if (use_mapped && (!lib_network_is_mapped(newnet)) ){ + (void)fprintf(sisout, "Network after translation is not mapped\n"); + return 1; + } + + network_clock_dup(*network, newnet); /* To recover the clocks */ + delay_network_dup(newnet, *network); /* To copy global defaults */ + network_free(*network); + *network = newnet; + re_delete_temp_nodes(*network); + re_graph_free(graph); + + return 0; +} + +init_retime() +{ + (void) com_add_command("retime", com_retime, 1); + (void) com_add_command("_check_tr", com__check_tr, 1); + (void) com_add_command("_print_stats", com__print_stats, 0); +} + +end_retime() +{ +} +#endif /* SIS */ + + + diff --git a/sis/retime/re_computeWD.c b/sis/retime/re_computeWD.c new file mode 100644 index 0000000..d98dd1c --- /dev/null +++ b/sis/retime/re_computeWD.c @@ -0,0 +1,137 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_computeWD.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +static int greater(); +static void sum(); + +#define IS_POS_LARGE 5000 + +void +re_computeWD(graph, N, table, pWD) +re_graph *graph; /* Graph under consideration */ +int N; /* Number of rows and cols -- also index of host node */ +st_table *table; /* The correspondence between the variables and nodes */ +wd_t ***pWD; /* Returned array of W and D */ +{ + double t; + wd_t **WD; + re_edge *edge; + re_node *sink; + int i, j, k, index, delay, offset; + + WD = ALLOC(wd_t *, N); + for (i = N; i-- > 0; ){ + WD[i] = ALLOC(wd_t, N); + } + + for (i = N; i-- > 0; ){ + for (j = N; j-- > 0; ){ + WD[i][j].w = POS_LARGE; + WD[i][j].d = 0; + } + } + + re_foreach_edge(graph, index, edge){ + i = edge->source->lp_index; + j = edge->sink->lp_index; + /* + * The weight corresponds to the largest weight between the nodes + */ + if (WD[i][j].w != POS_LARGE){ + WD[i][j].w = MIN(WD[i][j].w, edge->weight); + } else { + WD[i][j].w = edge->weight; + } + /* Check to see if the input has a user specified arrival time */ + offset = 0; + if (edge->source->type == RE_PRIMARY_INPUT && + edge->source->user_time > RETIME_TEST_NOT_SET){ + WD[i][j].d = MIN(WD[i][j].d, + offset = edge->source->scaled_user_time); + } + delay = 0 - (edge->source->scaled_delay + offset); + WD[i][j].d = MIN(WD[i][j].d, delay); + } + + for (k = N; k-- > 0; ){ + for (i = N; i-- > 0; ){ + for (j = N; j-- > 0; ){ + if (greater(WD[i][j], WD[i][k], WD[k][j])) + sum(&(WD[i][j]), WD[i][k], WD[k][j]); + } + } + } + + for (i = N; i-- > 0; ){ + for (j = N; j-- > 0; ){ + if (j >= N-2){ /* Host vertex */ + t = 0; + } else { + assert(st_lookup(table, (char *)j, (char **)&sink)); + t = sink->scaled_delay; + } + WD[i][j].d = t - WD[i][j].d; + } + } + + if (retime_debug > 40){ + (void)fprintf(sisout,"Correspondence between lp_index & nodes\n"); + for (i = N-2; i-- > 0; ){ + assert(st_lookup(table, (char *)i, (char **)&sink)); + if (sink->type == RE_IGNORE){ + (void)fprintf(sisout,"Index %d is REG_SHAR_NODE\n", i); + } else { + (void)fprintf(sisout,"Index %d is node %s\n", i, sink->node->name); + } + } + if (retime_debug > 60){ + (void)fprintf(sisout,"Index %d is HOST_NODE_SOURCE\n", N-2); + (void)fprintf(sisout,"Index %d is HOST_NODE_SINK\n", N-1); + (void)fprintf(sisout,"Data on the WD values\n"); + for (i = N; i-- > 0; ){ + (void)fprintf(sisout,"%d::",i); + for (j = N; j-- > 0; ){ + if (WD[i][j].w > IS_POS_LARGE ){ + (void)fprintf(sisout," INFIN"); + } else { + (void)fprintf(sisout," %d-%4d", WD[i][j].w, WD[i][j].d); + } + } + (void)fprintf(sisout,"\n"); + } + } + } + + *pWD = WD; +} + +static int +greater(WD1, WD2, WD3) +wd_t WD1, WD2, WD3; +{ + if(WD1.w > (WD2.w + WD3.w)) return 1; + + if(WD1.w == (WD2.w + WD3.w)) + if(WD1.d > (WD2.d + WD3.d)) return 1; + + return 0; +} + +static void +sum(pWD1, WD2, WD3) +wd_t *pWD1, WD2, WD3; +{ + pWD1->w = WD2.w + WD3.w; + pWD1->d = WD2.d + WD3.d; +} +#endif /* SIS */ diff --git a/sis/retime/re_delay.c b/sis/retime/re_delay.c new file mode 100644 index 0000000..d38a637 --- /dev/null +++ b/sis/retime/re_delay.c @@ -0,0 +1,132 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + + +/* + * Compute the cycle time for the retime graph ---- + * Account for the user specified constraints and delay throught latches + */ +double +re_cycle_delay(graph, delay_r) +re_graph *graph; +double delay_r; +{ + re_node *node; + bool *valid_table; + int i, n = re_num_nodes(graph); + double crit, d, offset, *delay_table; + + valid_table = ALLOC(bool, n); + delay_table = ALLOC(double, n); + + for (i = n; i-- > 0; ){ + valid_table[i] = FALSE; + delay_table[i] = 0.0; + } + + /* primary input and primary output nodes need not be evaluated */ + re_foreach_node(graph, i, node){ + if (re_num_fanins(node) == 0) { + valid_table[i] = TRUE; + if (node->user_time > RETIME_TEST_NOT_SET){ + delay_table[i] = node->user_time; + } + } + } + + /* compute delays */ + for (i = n; i-- > 0; ){ + if (!valid_table[i]) { + node = array_fetch(re_node *, graph->nodes, i); + re_evaluate_delay(node, valid_table, delay_table); + } + } + + /* find critical delay */ + crit = 0.0; + for (i = n; i-- > 0; ){ + d = delay_table[i]; + node = array_fetch(re_node *, graph->nodes, i); + + if (node->type == RE_PRIMARY_OUTPUT && + node->user_time > RETIME_TEST_NOT_SET){ + /* The po signal is required early */ + offset = 0.0 - (node->user_time); + } else if (re_max_fanout_weight(node) > 0) { + /* Add the delay delay thru the latch that follows */ + offset = delay_r; + } else { + offset = 0.0; + } + + crit = MAX(crit, d+offset); + } + FREE(valid_table); + FREE(delay_table); + + return crit; +} + +/* + * For the specified "node" compute the arrival time at its output + * The entries in the delay_table and the valid table are updated + * after recording the delay at the output of the node + */ +void +re_evaluate_delay(node, valid_table, delay_table) +re_node *node; +bool *valid_table; +double *delay_table; +{ + int i; + double m; + re_edge *edge; + + re_foreach_fanin(node, i, edge){ + if ((edge->weight == 0) && (!valid_table[edge->source->id])) { + /* recursively evaluate the fanins */ + re_evaluate_delay(edge->source, valid_table, delay_table); + } + } + + m = 0.0; + re_foreach_fanin(node, i, edge){ + if (edge->weight == 0) { + m = MAX(m, delay_table[edge->source->id]); + } + } + valid_table[node->id] = TRUE; + delay_table[node->id] = m + node->final_delay; +} +/* + * Find a lower bound on the cycle time. + * THis is actually MAX(cycle delay/ cycle weight)... + * However for now we will just take the largest delay of a gate + */ +double +retime_cycle_lower_bound(graph) +re_graph *graph; +{ + int i; + re_node *node; + double bound; + + bound = -1.0; + re_foreach_node(graph, i, node){ + if (node->type == RE_INTERNAL){ + bound = MAX(bound, node->final_delay); + } + } + return bound; +} +#endif /* SIS */ diff --git a/sis/retime/re_export.c b/sis/retime/re_export.c new file mode 100644 index 0000000..e93d374 --- /dev/null +++ b/sis/retime/re_export.c @@ -0,0 +1,174 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_export.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +int +re_min_fanin_weight(node) +re_node *node; +{ + int m, i; + re_edge *edge; + + m = POS_LARGE; + re_foreach_fanin(node, i, edge){ + if (re_ignore_edge(edge)) continue; + m = MIN(m, edge->weight); + } + return m; +} + +int +re_min_fanout_weight(node) +re_node *node; +{ + int m, i; + re_edge *edge; + + m = POS_LARGE; + re_foreach_fanout(node, i, edge){ + if (re_ignore_edge(edge)) continue; + m = MIN(m, edge->weight); + } + return m; +} + +int +re_max_fanin_weight(node) +re_node *node; +{ + int m, i; + re_edge *edge; + + m = 0; + re_foreach_fanin(node, i, edge){ + if (re_ignore_edge(edge)) continue; + m = MAX(m, edge->weight); + } + return m; +} + +int +re_max_fanout_weight(node) +re_node *node; +{ + int m, i; + re_edge *edge; + + m = 0; + re_foreach_fanout(node, i, edge){ + if (re_ignore_edge(edge)) continue; + m = MAX(m, edge->weight); + } + return m; +} + +int +re_sum_of_edge_weight(graph) +re_graph *graph; +{ + int i; + int c; + re_edge *edge; + + c = 0; + re_foreach_edge(graph, i, edge){ + if (re_ignore_edge(edge)) continue; + c += edge->weight; + } + + /* return */ + return c; + +} + +int +re_effective_sum_edge_weight(graph) +re_graph *graph; +{ + int i, m, c; + re_node *node; + + c = 0; + re_foreach_node(graph, i, node){ + if (node->type == RE_IGNORE) continue; + m = re_max_fanout_weight(node); + c += m; + } + + /* return */ + return c; +} + +double +re_sum_node_area(graph) +re_graph *graph; +{ + int i; + double c; + re_node *node; + + c = 0.0; + for (i = re_num_nodes(graph); i-- > 0; ) { + node = array_fetch(re_node *, graph->nodes, i); + c += node->final_area; + } + + /* return */ + return c; +} + +double +re_total_area(graph, area_r) +re_graph *graph; +double area_r; +{ + double n; + n = re_sum_node_area(graph) + /* Area of nodes */ + area_r * re_effective_sum_edge_weight(graph); /* Register area */ + + return n; +} + +bool +re_node_retimable(node) +re_node *node; +{ + if (node->type != RE_INTERNAL) return FALSE; + + if (re_min_fanin_weight(node) == 0 && re_min_fanout_weight(node) == 0) + return FALSE; + + return TRUE; +} + +bool +re_node_forward_retimable(node) +re_node *node; +{ + if (node->type != RE_INTERNAL) return FALSE; + + if (re_min_fanin_weight(node) == 0) return FALSE; + + return TRUE; +} + +bool +re_node_backward_retimable(node) +re_node *node; +{ + if (node->type != RE_INTERNAL) return FALSE; + + if (re_min_fanout_weight(node) == 0) return FALSE; + + return TRUE; +} +#endif /* SIS */ diff --git a/sis/retime/re_graph.c b/sis/retime/re_graph.c new file mode 100644 index 0000000..f9b62de --- /dev/null +++ b/sis/retime/re_graph.c @@ -0,0 +1,270 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_graph.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +#define EPS 1.0e-9 +#define FUDGE 1.0 + +/* + * Routine that encapsulates the retiming procedures for the user + * that wants to use the retiming algorithm on a graph + */ + +int +retime_graph_interface(graph, area_r, delay_r, retime_tol, d_clk, new_c) +re_graph *graph; +double area_r, delay_r; +double retime_tol, d_clk, *new_c; +{ + int flag, can_init; + + flag = retime_graph(NIL(network_t), graph, area_r, delay_r, retime_tol, + d_clk, new_c, 1, 0, 0, &can_init); + return flag; +} + +/* + * Uses a binary search to determine the clock cycle that is feasible. + * Will use either nanni's algorithm (default) or lieserson's algorithm + * If the min_reg parameter == 1: minimize the register count as well + * + * The respective algorithms get a copy of the graph and the clock period to + * attempt and they return a status (feasible or not) and the value of the + * retiming vector. This is used to compute the initial states. The initial + * states are computed only if ---- + * should_init == 1 && number of latches <= MAX_LATCH_TO_INITIALIZE + * OR if + * should_init == 2 (can be set by the -I option) + */ +int +retime_graph(network, graph, area_r, delay_r, retime_tol, + d_clk, new_c, lp_flag, min_reg, should_init, can_initialize) +network_t *network; +re_graph *graph; +double area_r, delay_r, retime_tol, d_clk, *new_c; +int lp_flag; /* == 1 => use the lieserson, otherwise nanni */ +int min_reg; /* == 1 => minimize number of registers */ +int should_init;/* == 1 => compute initial states, == 2 => at all cost */ +int *can_initialize;/* RETURN: can the network be initialized */ +{ + int i, j, status, n; + int no_err_flag, changed; + int make_legal_check, make_legal; + int *sol, *best_sol; /* The solution to the retiming problem */ + double current_c, max_fail_c, best_c, initial_c, c, attempting_c; + re_node *node; + re_edge *edge; + re_graph *new_graph; + + best_c = re_cycle_delay(graph, delay_r); + sol = ALLOC(int, re_num_nodes(graph)*2); /* Big enuff vector */ + /* + * First of all make the edge weights positive --- We could have started + * with a graph with -ve weights due to R&R procedures + */ + make_legal = FALSE; + re_foreach_edge(graph, i, edge){ + if (edge->weight < 0) make_legal = TRUE; + } + if (make_legal){ + if (retime_debug > 40){ + (void)fprintf(sisout,"Making the circuit legal\n"); + } + status = retime_lies_routine(graph, best_c + FUDGE, sol); + if (status == 0){ + /* + * Infeasible solution --- should never happen if the negative + * weigths were obtained by a proper procedure + */ + error_append("Cannot get rid of the negative latches\n"); + return -1; + } + make_legal_check = FALSE; + re_foreach_edge(graph, i, edge){ + if (edge->weight < 0) make_legal_check = TRUE; + } + /* Final check --- just in case something got overlooked */ + assert(make_legal_check == FALSE); + } + + /* Now we have a legal retiming graph -- try to optimize the delay */ + best_c = re_cycle_delay(graph, delay_r); + initial_c = best_c; + if (!min_reg && best_c <= d_clk) { + /* Current network meets the constraints */ + *new_c = best_c; + (void)fprintf(sisout,"Current network meets cycle time constraint\n"); + return TRUE; + } + + max_fail_c = d_clk; + best_sol = NIL(int); + n = network_num_latch(network); + + /* + * Now work to improve the graph by retiming + */ + (void)fprintf(sisout,"initial cycle delay = %-5.2f\n", best_c); + (void)fprintf(sisout,"initial number of registers = %-d\n", n); + (void)fprintf(sisout,"initial logic cost = %-5.2f\n", + re_sum_node_area(graph)); + (void)fprintf(sisout,"initial register cost = %-5.2f\n\n", n * area_r); + + attempting_c = d_clk; + +loop: new_graph = re_graph_dup(graph); + c = attempting_c - delay_r; + if (min_reg){ + status = retime_min_register(new_graph, c, sol); + } else if (lp_flag) { + status = retime_lies_routine(new_graph, c, sol); + } else { + status = retime_nanni_routine(new_graph, c, sol); + } + + if (status == 0) { + /* + * The value of attempting_clk is infeasible + */ + if ((best_c - attempting_c) > retime_tol) { + max_fail_c = attempting_c; + (void)fprintf(sisout,"Failed at %-5.2f",attempting_c); + attempting_c = 0.5 *(best_c + attempting_c); + (void)fprintf(sisout," : Now attempting %-5.2f\n", attempting_c); + re_graph_free(new_graph); + goto loop; + } else { + /* There is no feasible soln better than "best_c - TOL" */ + (void)fprintf(sisout,"Quitting binary search at %-5.2f\n", attempting_c); + goto exit_after_init; + } + } + + /* + * Success has been achieved -- accept the current soln + */ + + if (!retime_check_graph(new_graph)){ + re_graph_free(new_graph); + FREE(sol); + return 0; + } + + current_c = re_cycle_delay(new_graph, delay_r); + (void)fprintf(sisout,"Success at %-5.2f, Delay is %-5.2f\n", + attempting_c, current_c); + + /* + * Just a check to make sure that retiming computations were OK + */ + if (current_c > (attempting_c + EPS)){ /* Floating point comaparison */ + (void)fprintf(sisout,"SERIOUS INTERNAL ERROR: The cycle after retiming %4.1f exceeds initial %4.1f\n", current_c, attempting_c); + re_graph_free(new_graph); + *new_c = best_c; + FREE(sol); + return 0; + } + + /* Store the best values of the retiming and the cycle time */ + best_c = current_c; + if (best_sol == NIL(int)){ + best_sol = ALLOC(int, re_num_nodes(graph)); + } + for (i = re_num_nodes(graph); i-- > 0; ){ + best_sol[i] = sol[i]; + } + + /* + * Even thought we succedded -- are we close enuff to the desired clock + */ + if (current_c > (d_clk + retime_tol)) { + if (current_c > (max_fail_c + retime_tol)){ + attempting_c = 0.5 *(max_fail_c + current_c); + (void)fprintf(sisout,"Success: Now attempting %-5.2f\n", attempting_c); + re_graph_free(new_graph); + goto loop; + } + } + + /* + * We have achieved the constraint specified or no + * further improvement is in sight ---- + */ + +exit_after_init: + /* + * If there was a feasible retiming (best_sol != NIL(int) then + * call the routine to update the initial values on the edges + */ + *new_c = best_c; + *can_initialize = TRUE; + no_err_flag = TRUE; changed = FALSE; + (void)fprintf(sisout, "\n"); + if ( best_sol != NIL(int)){ + if (should_init){ + if (!min_reg) { + /* Timing should have improved */ + assert(best_c < initial_c); + } + no_err_flag = retime_update_init_states(network, graph, best_sol, + should_init, can_initialize); + } + if (should_init == 0 || no_err_flag == 2) { + /* + * Either initial state computation was suppresed (-i option) + * or the number of latches was too many .... + * Just move the latches and set initial states to 3 (UNKNOWN) + */ + no_err_flag = TRUE; *can_initialize = TRUE; + (void)fprintf(sisout, + "NEW INITIAL STATE FOR ALL LATCHES IS 3 (UNKNOWN)\n"); + re_foreach_node(graph, i, node){ + if (re_ignore_node(node)) continue; + if (node->type == RE_INTERNAL){ + retime_single_node(node, best_sol[i]); + } else { + assert(best_sol[i] == 0); + } + } + re_foreach_edge(graph, i, edge){ + if (re_ignore_edge(edge)) continue; + if (edge->weight > 0){ + if (edge->num_val_alloc > 0) FREE(edge->initial_values); + edge->initial_values = ALLOC(int, edge->weight); + edge->num_val_alloc = edge->weight; + for (j = edge->weight; j-- > 0; ){ + edge->initial_values[j] = 3 /* UNKNOWN */; + } + } + } + } + for (i = re_num_nodes(graph); i-- > 0; ){ + if (best_sol[i] != 0){ + changed = TRUE; + break; + } + } + FREE(best_sol); + } + + FREE(sol); + re_graph_free(new_graph); + + if (!no_err_flag) return -1; + if (!changed && !make_legal) { + return FALSE; + } + return TRUE; +} + +#undef EPS +#endif /* SIS */ diff --git a/sis/retime/re_initial.c b/sis/retime/re_initial.c new file mode 100644 index 0000000..ec63f6f --- /dev/null +++ b/sis/retime/re_initial.c @@ -0,0 +1,664 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_initial.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +/* + * $Log: re_initial.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:48 pchong + * imported + * + * Revision 1.5 1993/05/06 01:25:21 sis + * *** empty log message *** + * + * Revision 1.4 22/.0/.1 .0:.5:.3 sis + * Updates for the Alpha port. + * + * Revision 1.3 1992/05/06 19:00:16 sis + * SIS release 1.1 + * + * Revision 1.2 1992/04/17 22:13:47 sis + * *** empty log message *** + * + * Revision 1.1 92/01/08 17:45:43 sis + * Initial revision + * + */ + +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +/* + * UPDATING INITIAL STATE AFTER RETIMING + * + * Use algorithm by Touati & Brayton TRANSCAD January 93 + * + * May fail if the initial state is not reachable from itself. + * In that case, use "add_reset" before retiming and "remove_reset" after retiming. + * + * "*can_init" = 1 if update was possible, edges annotated with new reset state + * "*can_init" = 0 if update not possible (graph is not modified) + * + * need to extract a sequence ending into the reset state of sufficient length + * need to be able to simulate a node forward + * need to be able to extract inputs vectors + */ + +typedef struct { + re_node **current; /* top of stack pointer */ + re_node **top; /* max value for top of stack pointer */ + re_node **bottom; /* stack of ready nodes implemented as an array */ + int *in_stack; /* flag: if 1, the node is already in the stack */ +} re_stack_t; + + +static int make_retiming_negative(); +static int min_n_input_latch(); +static int re_stack_is_empty(); +static int simulate_node_function(); +static re_node *re_stack_pop(); +static re_stack_t *re_stack_init(); +static void re_stack_free(); +static void re_stack_push(); +static void realloc_initial_values(); +static void retime_get_input_order(); +static void retime_node_forward(); +static void retime_primary_input_forward(); +static void retime_primary_output_forward(); +static void set_initial_state(); +static void simulate_forward(); +static st_table *retime_get_latch_corresp(); +static st_table *retime_swap_latches(); + + + /* ARGSUSED */ + +int retime_update_init_states(network, graph, r_vec, should_init, can_init) +network_t *network; /* Network to get STG from */ +re_graph *graph; /* graph representation of network for retiming */ +int *r_vec; /* solution vector: r_vec[i] corresponds to node = array_fetch(re_node *, graph->nodes, i) */ +int should_init; /* currently unused: always try */ +int *can_init; /* Flag to specify if all went OK */ +{ + int j, i, n_shift; /* = max(r(v)-r(host)) */ + int *retiming; /* Saved vector of retiming values */ + st_table *reset_ancestor; /* maps latch to its value in ancestor state */ + st_table *orig_reset_ancestor; + st_table *latch_table; /* mapes latches in orig and dup networks */ + array_t *input_seq; /* sequence of (PI inputs) in reverse temporal order */ + st_table *input_order; /* maps external PI in 'network' to small integers: their order of occurrence in 'graph' */ + st_generator *stgen; + latch_t *latch; + char *input; + int value; + network_t *dup_network; + + *can_init = TRUE; + if (network == NIL(network_t)) { + *can_init = FALSE; + return 2; /* Set initial states to Dont Cares */ + } + + retiming = ALLOC(int, re_num_nodes(graph)); + for ( i = re_num_nodes(graph); i-- > 0; ){ + retiming[i] = r_vec[i]; + } + dup_network = network_dup(network); + n_shift = make_retiming_negative(graph, retiming); + assert(n_shift >= 0); + input_order = st_init_table(st_ptrcmp, st_ptrhash); + retime_get_input_order(dup_network, graph, input_order, /* node_t's */ 0); + reset_ancestor = st_init_table(st_ptrcmp, st_ptrhash); + latch_table = retime_get_latch_corresp(network, dup_network); + input_seq = array_alloc(char *, 0); + + if (seqbdd_extract_input_sequence(dup_network, n_shift, input_order, input_seq, reset_ancestor)) { + *can_init = FALSE; + } else { + if (retime_debug) { + (void)fprintf(sisout, "RESET ANCESTOR CHANGES \n"); + st_foreach_item_int(reset_ancestor, stgen, (char **)&latch, &value){ + (void)fprintf(sisout, "%s %d -> %d\n", + node_name(latch_get_output(latch)), value, + latch_get_initial_value(latch)); + } + } + orig_reset_ancestor = retime_swap_latches(reset_ancestor, latch_table); + set_initial_state(graph, orig_reset_ancestor); + if (retime_debug){ + (void)fprintf(sisout, "ON INPUTS\n"); + for ( i = array_n(input_seq); i--> 0; ){ + input = array_fetch(char *, input_seq, i); + for (j = 0; j < st_count(input_order); j++){ + (void)fprintf(sisout, "%d", (int)input[j]); + } + (void)fprintf(sisout, "\n"); + } + } + simulate_forward(graph, retiming, input_seq); + st_free_table(orig_reset_ancestor); + } + + /* cleanup */ + st_free_table(input_order); + st_free_table(latch_table); + st_free_table(reset_ancestor); + for (i = 0; i < array_n(input_seq); i++) { + input = array_fetch(char *, input_seq, i); + FREE(input); + } + FREE(retiming); + array_free(input_seq); + network_free(dup_network); + + return (*can_init); +} + + + /* INTERNAL INTERFACE */ + + +/* + * Expects that initially the PIPO nodes have a retiming value of 0. This is checked. + * computes n_shift = MAX_i(retiming[i]) and subtract this value to all entries in 'retiming'. + */ + +static int +make_retiming_negative(graph, retiming) +re_graph *graph; /* graph representation of network for retiming */ +int *retiming; /* solution vector */ +{ + int i; + int n_shift; /* = max(r(v)-r(host)) */ + int n_nodes = re_num_nodes(graph); + int max_value; + re_node *pi, *po; + + re_foreach_primary_input(graph, i, pi) { + assert(retiming[pi->id] == 0); + } + re_foreach_primary_output(graph, i, po) { + assert(retiming[po->id] == 0); + } + max_value = 0; + for (i = n_nodes; i-- > 0; ) { + if (max_value < retiming[i]) max_value = retiming[i]; + } + n_shift = max_value; + for (i = n_nodes; i-- > 0; ) + retiming[i] -= n_shift; + + return n_shift; +} + + +/* + * stores in 'input_order' a map between external PI of 'network' + * and the ordering of primary inputs in graph. + * If 'use_re_nodes_flag' is set, stores the correspondance between + * the external PI in 'graph' rather than external PI in 'network'. + * Just to make sure the two are consistent. + */ + +static void +retime_get_input_order(network, graph, input_order, use_re_node_flag) +network_t *network; +re_graph *graph; +st_table *input_order; +int use_re_node_flag; /* if 1, map re_node to integers; if 0, map node_t to integers */ +{ + int i; + re_node *node; + node_t *old_pi, *pi; + + re_foreach_primary_input(graph, i, node) { + if (use_re_node_flag) { + (void) st_insert(input_order, (char *) node, (char *) i); + } else { + old_pi = node->node; + pi = network_find_node(network, node_long_name(old_pi)); + assert(pi != NIL(node_t)); + assert(pi->type == PRIMARY_INPUT && network_is_real_pi(network, pi)); + (void) st_insert(input_order, (char *) pi, (char *) i); + } + } +} + + +/* + * Copies the initial values from the latches into the initial_states field. + * It is an error if the value is not specified. + * NOTE: It frees the latch entries associated with the edges. + */ + +static void +set_initial_state(graph, latch_values) +re_graph *graph; /* graph representation of network for retiming */ +st_table *latch_values; +{ + re_edge *edge; + latch_t *latch; + int edge_index, i, init_val; + + re_foreach_edge(graph, edge_index, edge) { + if (re_ignore_edge(edge)) continue; + if (edge->weight == 0) continue; + assert(edge->weight > 0); + if (edge->num_val_alloc > 0) FREE(edge->initial_values); + edge->initial_values = ALLOC(int, edge->weight); + edge->num_val_alloc = edge->weight; + for (i = 0; i < edge->weight; i++) { + latch = edge->latches[i]; + assert(st_lookup_int(latch_values, (char *) latch, &init_val)); + edge->initial_values[i] = init_val; + } + FREE(edge->latches); + edge->latches = NIL(latch_t *); /* For garbage collection routines */ + } +} + + +/* + * The heart of the algorithm. + * Uses a stack. Pushes on the stack all the nodes that are ready to be retimed. + * A node is ready to be retimed if it still needs to be retimed and it has latches on all its inputs. + * A node still needs to be retimed if retiming[node_id] < 0. + * We need to be careful not to put the same node twice on the stack, or we will get stack overflow. + * For that,we use the special array 'on_stack' that checks for this condition. + * After a node has fired, it may enable its outputs: we check to see if any output needs to be + * put on the stack. + * The algorithm completes when the stack is empty. For consistency, we check that the retiming + * is complete then (all entries of 'retiming' are 0). + */ + +static void +simulate_forward(graph, retiming, input_seq) +re_graph *graph; /* graph representation of network for retiming */ +int *retiming; /* solution vector (integer version) */ +array_t *input_seq; /* array of char* pointing to input sequences from ancestor to reset */ +{ + int i, input_position, local_shift; + re_node *node, *output; + re_edge *outedge; + int n_nodes; + re_stack_t *stack; + st_table *pi_order; /* correspondance between 'graph' PI and indices in 'input_seq' */ + + pi_order = st_init_table(st_numcmp, st_numhash); + retime_get_input_order(NIL(network_t), graph, pi_order, /* re_node */ 1); + stack = re_stack_init(graph); + + n_nodes = re_num_nodes(graph); + for (i = 0; i < n_nodes; i++) { + node = array_fetch(re_node *, graph->nodes, i); + assert(node->id == i); + if (retiming[i] < 0) re_stack_push(stack, node); + } + + + while (! re_stack_is_empty(stack)) { + /* retime the node at the top of the stack */ + node = re_stack_pop(stack); + local_shift = MIN(min_n_input_latch(node), - retiming[node->id]); + assert(local_shift > 0); + switch (node->type) { + case RE_PRIMARY_INPUT: + assert(array_n(input_seq) == local_shift); + assert(st_lookup_int(pi_order, (char *) node, &input_position)); + retime_primary_input_forward(node, input_position, input_seq); + break; + case RE_PRIMARY_OUTPUT: + retime_primary_output_forward(node, local_shift); + break; + case RE_INTERNAL: + retime_node_forward(node, local_shift); + break; + default: + fail("node of type RE_IGNORE encountered"); + } + retiming[node->id] += local_shift; + + /* + * propagate readiness to node outputs + */ + re_foreach_fanout(node, i, outedge) { + if (re_ignore_edge(outedge)) continue; + output = outedge->sink; + if (retiming[output->id] < 0) re_stack_push(stack, output); + } + } + + /* check that the work has been done and cleanup */ + for (i = 0; i < n_nodes; i++) { + assert(retiming[i] == 0); + } + re_stack_free(stack); + st_free_table(pi_order); +} + + +/* + * Stack manipulation routines for retiming + */ + +static re_stack_t * +re_stack_init(graph) +re_graph *graph; +{ + int i; + int n_nodes; + re_stack_t *stack; + + stack = ALLOC(re_stack_t, 1); + n_nodes = re_num_nodes(graph); + stack->bottom = ALLOC(re_node *, n_nodes); + stack->top = stack->bottom + n_nodes; + stack->current = stack->bottom; + stack->in_stack = ALLOC(int, n_nodes); + for (i = 0; i < n_nodes; i++) { + stack->in_stack[i] = 0; + } + return stack; +} + +static void +re_stack_free(stack) +re_stack_t *stack; +{ + FREE(stack->bottom); + FREE(stack->in_stack); + FREE(stack); +} + +/* + * Does not always push. Checks whether the node needs to be pushed on the stack or not. + * Supposes that the node needs retiming. This should be checked by the caller. + */ + +static void +re_stack_push(stack, node) +re_stack_t *stack; +re_node *node; +{ + int n_input_latches; + + if (stack->in_stack[node->id]) return; + n_input_latches = min_n_input_latch(node); + if (n_input_latches <= 0) return; + assert(stack->current < stack->top); + *(stack->current++) = node; + stack->in_stack[node->id] = 1; +} + +static re_node * +re_stack_pop(stack) +re_stack_t *stack; +{ + re_node *node; + + assert(stack->current > stack->bottom); + node = *(--stack->current); + stack->in_stack[node->id] = 0; + return node; +} + +static int +re_stack_is_empty(stack) +re_stack_t *stack; +{ + return (stack->current == stack->bottom); +} + + + /* yes iff currently a latch is present on each fanin edge */ + +static int +min_n_input_latch(node) +re_node *node; +{ + int i; + re_edge *backedge; + int min_weight = (int) INFINITY; + + re_foreach_fanin(node, i, backedge) { + if (re_ignore_edge(backedge)) continue; + if (min_weight > backedge->weight) + min_weight = backedge->weight; + } + return min_weight; +} + + +/* + * array_t *input_seq + * char *one_seq = array_fetch(char *, input_seq, i) + * EXPECTS "one_seq" TO BE ORDERED IN THE SAME ORDER AS + * PRIMARY INPUTS OF GRAPH (guaranteed by 'retime_get_input_order') + */ + +static void +retime_primary_input_forward(node, input_index, input_seq) +re_node *node; /* node being retimed */ +int input_index; +array_t *input_seq; +{ + int i, j; + re_edge *edge; + int n_shift = array_n(input_seq); + + if (n_shift == 0) return; + re_foreach_fanout(node, i, edge) { + if (re_ignore_edge(edge)) continue; + realloc_initial_values(edge, n_shift); + } + re_foreach_fanout(node, j, edge) { + if (re_ignore_edge(edge)) continue; + for (i = 0; i < n_shift; i++) { + char *input = array_fetch(char *, input_seq, i); + edge->initial_values[i] = (int)(input[input_index]); + } + } +} + +/* + * ASSERTION: the body of the loops are not called when new_size == 0. + */ + +static void +realloc_initial_values(edge, size_incr) +re_edge *edge; +int size_incr; +{ + int i; + int old_size, new_size; + int *new_init_values; + + if (size_incr == 0) return; + old_size = edge->weight; + new_size = edge->weight + size_incr; + + assert(old_size >= 0 && new_size >= 0); + new_init_values = (new_size > 0) ? ALLOC(int, new_size) : NIL(int); + if (size_incr > 0) { + for (i = 0; i < edge->weight; i++) { + new_init_values[i + size_incr] = edge->initial_values[i]; + } + } else { /* size_incr < 0 */ + for (i = 0; i < edge->weight + size_incr; i++) { + new_init_values[i] = edge->initial_values[i]; + } + } + if (old_size > 0) FREE(edge->initial_values); + edge->initial_values = new_init_values; + edge->weight = edge->num_val_alloc = new_size; +} + + +static void +retime_primary_output_forward(node, n_shift) +re_node *node; /* node being retimed */ +int n_shift; +{ + int i; + re_edge *edge; + + re_foreach_fanin(node, i, edge) { + if (re_ignore_edge(edge)) continue; + realloc_initial_values(edge, 0 - n_shift); + } +} + + +static void +retime_node_forward(node, n_shift) +re_node *node; /* node being retimed */ +int n_shift; +{ + int i, j; + re_edge *edge; + int n_inputs = array_n(node->fanins); + int **input_values = ALLOC(int *, n_shift); + int *output_values = ALLOC(int, n_shift); + + for (i = 0; i < n_shift; i++) { + input_values[i] = ALLOC(int, n_inputs); + } + + for (i = 0; i < n_shift; i++) { + re_foreach_fanin(node, j, edge) { + if (re_ignore_edge(edge)) continue; + input_values[i][edge->sink_fanin_id] = edge->initial_values[i + edge->weight - n_shift]; + } + } + re_foreach_fanin(node, j, edge) { + if (re_ignore_edge(edge)) continue; + realloc_initial_values(edge, 0 - n_shift); + } + re_foreach_fanout(node, j, edge) { + if (re_ignore_edge(edge)) continue; + realloc_initial_values(edge, 0 + n_shift); + } + + for (i = 0; i < n_shift; i++) { + output_values[i] = simulate_node_function(node->node, input_values[i]); + } + + for (i = 0; i < n_shift; i++) { + re_foreach_fanout(node, j, edge) { + if (re_ignore_edge(edge)) continue; + edge->initial_values[i] = output_values[i]; + } + } + + for (i = 0; i < n_shift; i++) { + FREE(input_values[i]); + } + FREE(input_values); + FREE(output_values); +} + +static int and_table[3][2] = { + {0, 0}, /* first arg is 0 */ + {0, 1}, /* first arg is 1 */ + {0, 1}, /* first arg is 2 */ +}; + +static int or_table[3][2] = { + {0, 1}, /* first arg is 0 */ + {1, 1}, /* first arg is 1 */ + {0, 1}, /* first arg is 2 */ +}; + + +static int +simulate_node_function(node, in_values) +node_t *node; +int *in_values; +{ + int i, j, num_in; + node_cube_t cube; + int num_cubes = node_num_cube(node); + int out_value = 2; + node_function_t node_fn = node_function(node); + + if (node_fn == NODE_0) return 0; + if (node_fn == NODE_1) return 1; + num_in = node_num_fanin(node); + for (i = 0; i < num_cubes; i++) { + int local_out_value = 2; + cube = node_get_cube(node, i); + for (j = 0; j < num_in; j++) { + int literal = node_get_literal(cube, j); + switch (literal) { + case ZERO: + local_out_value = and_table[local_out_value][1 - in_values[j]]; + break; + case ONE: + local_out_value = and_table[local_out_value][in_values[j]]; + break; + case TWO: + break; + default: + fail("bad literal"); + /* NOTREACHED */ + } + if (local_out_value == 0) break; + } + assert(local_out_value != 2); + out_value = or_table[out_value][local_out_value]; + if (out_value == 1) break; + } + return out_value; +} +/* + * Store corresponding latches in the two networks + */ +static st_table * +retime_get_latch_corresp(net1, net2) +network_t *net1, *net2; +{ + lsGen gen; + node_t *po1, *po2; + latch_t *l1, *l2; + st_table *latch_table; + + latch_table = st_init_table(st_ptrcmp, st_ptrhash); + + foreach_latch(net1, gen, l1){ + po1 = latch_get_input(l1); + assert((po2 = network_find_node(net2, node_long_name(po1))) != NIL(node_t)); + assert((l2 = latch_from_node(po2)) != NIL(latch_t)); + (void)st_insert(latch_table, (char *)l1, (char *)l2); + } + foreach_latch(net2, gen, l2){ + po2 = latch_get_input(l2); + assert((po1 = network_find_node(net1, node_long_name(po2))) != NIL(node_t)); + assert((l1 = latch_from_node(po1)) != NIL(latch_t)); + (void)st_insert(latch_table, (char *)l2, (char *)l1); + } + + return latch_table; +} + +static st_table * +retime_swap_latches(ancestor, latch_table) +st_table *ancestor, *latch_table; +{ + int value; + st_generator *stgen; + latch_t *l1, *l2; + st_table *orig_ancestor; + + orig_ancestor = st_init_table(st_ptrcmp, st_ptrhash); + st_foreach_item_int(ancestor, stgen, (char **)&l1, &value){ + assert(st_lookup(latch_table, (char *)l1, (char **)&l2)); + st_insert(orig_ancestor, (char *)l2, (char *)value); + } + return orig_ancestor; +} +#endif /* SIS */ diff --git a/sis/retime/re_milp.c b/sis/retime/re_milp.c new file mode 100644 index 0000000..ad1fd36 --- /dev/null +++ b/sis/retime/re_milp.c @@ -0,0 +1,514 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_milp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +#define REAL 1 +#define INT 2 + +#define D_MIN(a,b) ((double)a < (double)b ? (double)a : (double)b) + +#define SCALE 10000 +#define ALLOC_EDGES 20 + +struct a_graph{ + struct a_node **nodes; + struct a_edge **edges; + int num_edges; + int num_edges_alloc; + int num_int; + int num_total; + }; + +struct a_node{ + struct a_edge *fanin; + double r; + double y; + double x; + }; + +struct a_edge{ + int from; + int to; + double weight_a; + double weight_b; + int type; + struct a_edge *next; + }; + +static void re_free_lies_graph(); +static void re_add_usertime_constraints(); +static void re_add_vertex_constraints(); +static void re_add_edge_constraint(); +static void re_node_to_index(); + +/* + * Compute the retiming to meet the specified time "c" by solving the + * MILP (Mixed Integer Linear Program) formulation of the problem + */ + +/* ARGSUSED */ +int +retime_lies_routine(graph, c, retiming) +re_graph *graph; +double c; +int *retiming; /* Array of adequate length to hold the solution */ +{ + struct a_graph *milp_graph; + int i, j, k, count, num_int, num_total; + double arrival; + char *key, *value; + re_node *re_no; + re_edge *re_ed; + struct a_edge *edge; + struct a_node **nodes; + avl_tree *tree; + avl_generator *gen; + st_table *table; + int to, from, lag; + + milp_graph = ALLOC(struct a_graph, 1); + count = 0; + milp_graph->num_edges = 0; + milp_graph->num_edges_alloc = ALLOC_EDGES; + num_int = milp_graph->num_int = re_num_internals(graph)+1; + num_total = milp_graph->num_total = 2*num_int; + milp_graph->nodes = ALLOC(struct a_node *, num_total); + for(i = 0; i < num_total; i++){ + milp_graph->nodes[i] = ALLOC(struct a_node,1); + (milp_graph->nodes[i])->r = 0.0; + (milp_graph->nodes[i])->y = 0.0; + (milp_graph->nodes[i])->fanin = NIL(struct a_edge); + } + milp_graph->edges = ALLOC(struct a_edge *, milp_graph->num_edges_alloc); + for(i = milp_graph->num_edges_alloc; i-- > 0; ){ + milp_graph->edges[i] = ALLOC(struct a_edge,1); + } + /* + * Insert the constraints corresponding to the retime graph + * by creating the required edges between the a_node entries + * Keep the correspondence between the re_no and the index of + * the node in the milp_graph->nodes + */ + table = st_init_table(st_ptrcmp, st_ptrhash); + re_foreach_node(graph, i, re_no){ + if (re_no->type == RE_INTERNAL){ + count++; + (void) st_insert(table,(char *)(re_no),(char *)count); + } + } + assert(count == (num_int-1)); + + /* + * Vertex constraints for the host vertex + */ + re_add_vertex_constraints(milp_graph, NIL(re_node), 0, c); + re_foreach_node(graph, i, re_no){ + if (re_no->type == RE_PRIMARY_OUTPUT){ + /* + * Add the edges between the host vertex and the immediate fanin + */ + to = 0; + re_foreach_fanin(re_no, j, re_ed){ + re_node_to_index(table, re_ed->source, &from); + re_add_edge_constraint(milp_graph, from, to, re_ed, c); + } + } else if (re_no->type == RE_INTERNAL){ + re_node_to_index(table, re_no, &to); + /* + * Add the two edges corresponding to the vertex constraints + */ + re_add_vertex_constraints(milp_graph, re_no, to, c); + + /* + * Add the two edges corresponding to the edge constraints + */ + re_foreach_fanin(re_no, j, re_ed){ + re_node_to_index(table, re_ed->source, &from); + re_add_edge_constraint(milp_graph, from, to, re_ed, c); + } + } + + /* + * Now add the constraints that might result from the user specifying + * arrival and required times at the host vertices + */ + re_add_usertime_constraints(milp_graph, table, re_no, c); + } + nodes = milp_graph->nodes; + + /* Now carry out the MILP solution -- ala the Lieserson paper */ + /* T1-T4 */ + for (i = num_int; i < num_total; i++){ + for (j = num_int; j < num_total; j++){ + for(edge = nodes[j]->fanin; edge != NIL(struct a_edge); + edge = edge->next){ + (nodes[j])->r = D_MIN((nodes[j])->r, + (nodes[edge->from])->r + edge->weight_a); + } + } + } + /* T5-T6 */ + for (j = num_int; j < num_total; j++){ + for(edge = nodes[j]->fanin; edge != NIL(struct a_edge); + edge = edge->next){ + if (nodes[j]->r > nodes[edge->from]->r + edge->weight_a){ + if (retime_debug > 40){ + (void)fprintf(sisout,"\tMILP_FAIL1 :%d to %d, %5.2f > %5.2f + %5.2f \n", + edge->from,edge->to, nodes[j]->r, nodes[edge->from]->r , edge->weight_a); + } + st_free_table(table); + re_free_lies_graph(milp_graph); + return 0; + } + } + } + /* T7-T8 */ + for (i = milp_graph->num_edges; i-- > 0; ){ + edge = (milp_graph->edges)[i]; + edge->weight_b = edge->weight_a + nodes[edge->from]->r - nodes[edge->to]->r; + if (edge->type == REAL) assert(edge->weight_b >= 0); + } + /* T10-T22 */ + for (k = 0; k < num_int; k++){ + tree = avl_init_table(avl_numcmp); + for(i = 0; i < num_int; i++){ + for(edge = nodes[i]->fanin; edge != NIL(struct a_edge); + edge = edge->next){ + nodes[edge->to]->y = D_MIN(nodes[edge->to]->y, + floor(nodes[edge->from]->y + edge->weight_b)); + } + } + /* T15-T21 */ + for (i = 0; i < num_total; i++){ + (void)avl_insert(tree, (char *)((int)floor(SCALE * nodes[i]->y)),(char *)i); + } + gen = avl_init_gen(tree, AVL_FORWARD); + while (avl_gen(gen, &key, &value) ){ + i = (int)value; + /* T19-T21 */ + for (j = num_int; j < num_total; j++){ + for(edge = nodes[j]->fanin; edge != NIL(struct a_edge); + edge = edge->next){ + if (edge->from == i){ + nodes[edge->to]->y = D_MIN(nodes[edge->to]->y, + nodes[i]->y + edge->weight_b); + } + } + } + } + avl_free_gen(gen); + avl_free_table(tree, (void(*)())0, (void(*)())0); + } + /* T23-T26 */ + for(i = 0; i < num_int; i++){ + for(edge = nodes[i]->fanin; edge != NIL(struct a_edge); + edge = edge->next){ + if (nodes[edge->to]->y > (nodes[edge->from]->y + edge->weight_b)) { + if (retime_debug > 40){ + (void)fprintf(sisout,"\tMILP_FAIL2: %d to %d, %5.2f > %5.2f + %5.2f \n", + edge->from,edge->to, nodes[edge->to]->y, nodes[edge->from]->y , edge->weight_b); + } + st_free_table(table); + re_free_lies_graph(milp_graph); + return 0; + } + } + } + /* + * Scale everything so that the host has a integral variable == 0 + */ + if (retime_debug > 20) (void)fprintf(sisout,"\n\tInteger part(lags) \n\t"); + nodes[0]->x = nodes[0]->y + nodes[0]->r; + for(i = 1; i < num_int; i++){ + nodes[i]->x = nodes[i]->y + nodes[i]->r - nodes[0]->x; + if (retime_debug > 20){ + (void)fprintf(sisout,"%5d ",(int)(nodes[i]->x)); + } + } + if (retime_debug > 20) (void)fprintf(sisout,"\n\tReal part(arrival times)\n\t"); + nodes[num_int]->x = nodes[num_int]->y + nodes[num_int]->r - nodes[0]->x; + for(i = num_int+1; i < num_total; i++){ + nodes[i]->x = nodes[i]->y + nodes[i]->r - nodes[0]->x; + if (retime_debug > 20){ + arrival = c * (nodes[i]->x - nodes[i-num_int]->x); + (void)fprintf(sisout,"%5.2f ", arrival); + } + } + if (retime_debug > 20) (void)fprintf(sisout,"\n"); + + /* Build up the soultion vector */ + if (retime_debug) (void)fprintf(sisout,"\tRetiming following nodes\n\t"); + re_foreach_node(graph, i, re_no){ + retiming[i] = 0; + if (re_no->type == RE_INTERNAL){ + re_node_to_index(table, re_no, &from); + lag = (int)(nodes[from]->x); + if(retime_debug && lag != 0){ + (void)fprintf(sisout,"%s by %d ",re_no->node->name, + (int)(nodes[from]->x)); + } + retiming[i] = lag; + retime_single_node(re_no, lag); + } + } + if (retime_debug) (void)fprintf(sisout,"\n"); + + st_free_table(table); + re_free_lies_graph(milp_graph); + return 1; +} + +static void +re_free_lies_graph(milp_graph) +struct a_graph *milp_graph; +{ + int i; + struct a_node **nodes; + + nodes = milp_graph->nodes; + for (i = milp_graph->num_edges_alloc; i-- > 0; ){ + FREE((milp_graph->edges)[i]); + } + for (i = milp_graph->num_total; i-- > 0; ){ + FREE(nodes[i]); + } + FREE(milp_graph->nodes); + FREE(milp_graph->edges); + FREE(milp_graph); +} + +/* + * from(u) is a fanin of to(v) in the orig re_graph + */ +static void +re_add_edge_constraint(graph, from, to, edge, c) +struct a_graph *graph; +int from, to; +re_edge *edge; +double c; +{ + int count; + double node_delay; + struct a_edge **edge_array; + struct a_node *u_no; + + node_delay = (to == 0 ? -c : edge->sink->final_delay); + + count = graph->num_edges; + re_add_edges_to_graph(graph, 2); /* Need two more edges */ + + edge_array = graph->edges; + + /* The r(u)-r(v) <= w(e) : from(u) is a fanin to to(v) in the re_graph*/ + u_no = (graph->nodes)[from]; + edge_array[count]->from = to; + edge_array[count]->to = from; + edge_array[count]->weight_a = (double)(edge->weight); + edge_array[count]->type = INT; + edge_array[count]->next = u_no->fanin; + u_no->fanin = edge_array[count]; +#ifdef RE_DEBUG + if (retime_debug > 40){ + (void)fprintf(sisout,"constraint3: %d to %d = %5.2f\n", + edge_array[count]->from, edge_array[count]->to, + edge_array[count]->weight_a); + } +#endif + count++; + /* The R(u)-R(v) <= w(e) - d(v)/c */ + u_no = (graph->nodes)[from+graph->num_int]; + edge_array[count]->from = to+graph->num_int; + edge_array[count]->to = from+graph->num_int; + edge_array[count]->weight_a = (double)(edge->weight) - (node_delay)/c; + edge_array[count]->type = REAL; + edge_array[count]->next = u_no->fanin; + u_no->fanin = edge_array[count]; +#ifdef RE_DEBUG + if (retime_debug > 40){ + (void)fprintf(sisout,"constraint4: %d to %d = %5.2f\n", + edge_array[count]->from, edge_array[count]->to, + edge_array[count]->weight_a); + } +#endif + count++; + + graph->num_edges = count; +} + +static void +re_add_vertex_constraints(graph, re_no, to, c) +struct a_graph *graph; +re_node *re_no; +int to; +double c; +{ + int count, num_int; + double node_delay; + struct a_edge **edge_array; + struct a_node *i_no, *r_no; + + node_delay = (to == 0 ? -c : re_no->final_delay); + num_int = graph->num_int; + count = graph->num_edges; + i_no = (graph->nodes)[to]; + r_no = (graph->nodes)[to+num_int]; + re_add_edges_to_graph(graph, 2); + + edge_array = graph->edges; + + /* The r(v)-R(v) <= -d(v)/c ; edge incident on the integer node*/ + edge_array[count]->from = to+num_int; + edge_array[count]->to = to; + edge_array[count]->weight_a = -(node_delay/c); + edge_array[count]->type = INT; + edge_array[count]->next = i_no->fanin; + i_no->fanin = edge_array[count]; +#ifdef RE_DEBUG + if (retime_debug > 40){ + (void)fprintf(sisout,"\tconstraint1: %d to %d = %5.2f\n", + edge_array[count]->from, edge_array[count]->to, + edge_array[count]->weight_a); + } +#endif + count++; + + /* The R(v)-r(v) <= c; edge is incident on the real node */ + edge_array[count]->to = to+num_int; + edge_array[count]->from = to; + edge_array[count]->weight_a = 1; /* Maybe RHS should be 1 */ + edge_array[count]->type = REAL; + edge_array[count]->next = r_no->fanin; + r_no->fanin = edge_array[count]; +#ifdef RE_DEBUG + if (retime_debug > 40){ + (void)fprintf(sisout,"\tconstraint2: %d to %d = %5.2f\n", + edge_array[count]->from, edge_array[count]->to, + edge_array[count]->weight_a); + } +#endif + count++; + + graph->num_edges = count; +} + +static void +re_add_usertime_constraints(graph, table, re_no, c) +struct a_graph *graph; +st_table *table; /* Stores the index corresponding to the node */ +re_node *re_no; +double c; +{ + re_edge *re_ed; + double node_delay, user_time; + struct a_edge **edge_array; + int i, count, num_int, from, to, index; + + if ((re_no->type == RE_INTERNAL) + || (re_no->user_time < RETIME_TEST_NOT_SET)) + return; + + count = graph->num_edges; + num_int = graph->num_int; + edge_array = graph->edges; + + if (re_no->type == RE_PRIMARY_INPUT){ + /* Allocte the edges in the milp graph structure */ + re_add_edges_to_graph(graph, re_num_fanouts(re_no)); + + /* + * Constraints of the form r(h) - R(v) <= w(e) - d(v)/c - t/c + * where "t" is the time AFTER the edge that the data is available + * The constraint edge is incident on the integer node r(h) ... + */ + re_foreach_fanout(re_no, i, re_ed){ + re_node_to_index(table, re_ed->sink, &index); + node_delay = re_ed->sink->final_delay; + user_time = re_no->user_time; + from = index+num_int; + to = 0; + + edge_array[count]->from = from; + edge_array[count]->to = to; + edge_array[count]->weight_a = + re_ed->weight - (user_time + node_delay)/c; + edge_array[count]->type = INT; + edge_array[count]->next = ((graph->nodes)[to])->fanin; + ((graph->nodes)[to])->fanin = edge_array[count]; + count++; + } + } else { + /* Allocte the edges in the milp graph structure */ + re_add_edges_to_graph(graph, re_num_fanins(re_no)); + + /* + * Constraint of the form R(v) - r(h) <= t/c + w(e) + * where "t" is the time AFTER the clock edge that the data is + * required to be present at the output... The edge is incident on the + * REAL node + */ + re_foreach_fanin(re_no, i, re_ed){ + re_node_to_index(table, re_ed->source, &index); + /* User time is referenced to the start of the clock */ + user_time = (c + re_no->user_time); + from = 0; + to = index+num_int; + + edge_array[count]->from = from; + edge_array[count]->to = to; + edge_array[count]->weight_a = re_ed->weight + user_time/c; + edge_array[count]->type = REAL; + edge_array[count]->next = ((graph->nodes)[to])->fanin; + ((graph->nodes)[to])->fanin = edge_array[count]; + count++; + } + } + graph->num_edges = count; +} + +re_add_edges_to_graph(graph, num) +struct a_graph *graph; +int num; +{ + int i, count, alloc_count; + struct a_edge **edge_array; + + count = graph->num_edges; + alloc_count = graph->num_edges_alloc; + edge_array = graph->edges; + + if (count+num >= graph->num_edges_alloc){ + alloc_count += ALLOC_EDGES; + edge_array = REALLOC(struct a_edge *, edge_array, alloc_count); + for (i = ALLOC_EDGES; i > 0; i--){ + edge_array[alloc_count-i] = ALLOC(struct a_edge,1); + } + } + graph->num_edges_alloc = alloc_count; + graph->edges = edge_array; +} + +static void +re_node_to_index(table, node, index) +st_table *table; +re_node *node; +int *index; +{ + if (node->type == RE_INTERNAL){ + if(!st_lookup(table, (char *)node, (char **)index)){ + fail("Hey, howcome node not assigned an index"); + } + } else { + *index = 0; + } +} + +#endif /* SIS */ diff --git a/sis/retime/re_minreg.c b/sis/retime/re_minreg.c new file mode 100644 index 0000000..8efe5db --- /dev/null +++ b/sis/retime/re_minreg.c @@ -0,0 +1,419 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_minreg.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +#define SCALE 1000 + +static void re_setup_lp_tableau(); +static void re_adjust_user_delays(); +static void re_add_register_sharing_node(); + +/* + * Minimize the number of registers while trying to achieve the + * cycle time of "c"... returns 1 if there is a feasible solution + * The graph is modified according to the feasible retiming + * + * Since the delay values need not be integral.. We will scale the + * values of delay by a factor SCALE and then floor the delay values + */ + +int +retime_min_register(graph, c, retiming) +re_graph *graph; +double c; +int *retiming; +{ + wd_t **WD; + double **a; + re_node *re_no, *new_node; + st_table *table; + int r_host; /* Retiming at the host vertex */ + int *iposv, *izrov; + int i, N, m, m1, m2, m3; + int status, flag, scaled_c, index, lag; + + /* Add the dummy node to the retime graph to model register sharing */ + re_add_register_sharing_node(graph); + + /* + * Create a table of correspondence between nodes and variables in lp + * The index "N-1" represents the host(source) vertex and the index + * "N" represents the host (sink) vertex. + */ + N = 0; + table = st_init_table(st_numcmp, st_numhash); + re_foreach_node(graph, i, re_no){ + if (re_no->type == RE_INTERNAL || re_no->type == RE_IGNORE){ + (void)st_insert(table, (char *)N, (char *)re_no); + re_no->lp_index = N; + N++; + } else if (re_no->user_time > RETIME_TEST_NOT_SET) { + re_no->scaled_user_time = (int)ceil(re_no->user_time * SCALE); + } + /* Scale the delay values */ + re_no->scaled_delay = (int)ceil(re_no->final_delay * SCALE); + } + + re_foreach_node(graph, i, re_no){ + if (re_no->type == RE_PRIMARY_INPUT){ + re_no->lp_index = N; + } else if (re_no->type == RE_PRIMARY_OUTPUT){ + re_no->lp_index = N+1; + } + } + N += 2; /* For the two host vertices */ + + /* adjust the delays according to the user specified delays */ + re_adjust_user_delays(graph); + + /* Setup the W and D matrices */ + re_computeWD(graph, N, table, &WD); + + /* Generate the tableau for the linear programming */ + scaled_c = (int)ceil(SCALE * c); + re_setup_lp_tableau(graph, N, WD, scaled_c, &a, &m, &m1, &m2, &m3, &r_host); + + for (i = N; i-- > 0; ) FREE(WD[i]); + FREE(WD); + + /* Solve the linear program */ + iposv = ALLOC(int, m+1); + izrov = ALLOC(int, N+1); + if (re_simplx(a, m, N, m1, m2, m3, &flag, izrov, iposv)){ + fail(error_string()); + } + + if (!flag){ + status = 1; + if (retime_debug > 20){ + (void)fprintf(sisout,"SIMPLEX -- optimum value = %f\n", a[1][1]); + } + + for (i = re_num_nodes(graph); i-- > 0; ) + retiming[i] = 0; + for (i = 1; i <= m; i++){ + if (retime_debug > 60){ + (void)fprintf(sisout,"%-4d: iposv(%d) = %6.3f -- %8s \n", + i, iposv[i], a[i+1][1], (iposv[i] > N ? "SLACK" : "VARIABLE")); + } + /* + * The indices are numbered 0 to (N-1) -- not 1 to N + * We are interested only in the variables (not slack data) + * and the variable indices N,N-1 are actually host. Since those + * have a retiming equal to 0 and do not have an entry in the + * symbol_table ignore it. + */ + if (iposv[i] < N-1){ + index = iposv[i] - 1; + assert(st_lookup(table, (char *)index, (char **)&new_node)); + retiming[new_node->id] = (int)ceil((double)(a[i+1][1]))-r_host; + } + } + + if (retime_debug) + (void)fprintf(sisout,"\tRetiming following nodes\n\t"); + re_foreach_node(graph, i, re_no){ + if (re_no->type == RE_INTERNAL){ + lag = retiming[re_no->id]; + if(retime_debug && lag != 0){ + (void)fprintf(sisout,"%s by %d ", re_no->node->name, lag); + } + retime_single_node(re_no, lag); + } + } + if (retime_debug) (void)fprintf(sisout,"\n"); + } else { + status = 0; + if (retime_debug){ + (void)fprintf(sisout,"LP HAS %s\n", (flag == -1 ? + "NO FEASIBLE SOLUTION": "UNBOUNDED SOLUTION")); + } + } + + /* Garbage collection */ + for (i = m+3; i-- > 0; ) FREE(a[i]); + FREE(a); + FREE(iposv); + FREE(izrov); + st_free_table(table); + + return status; +} + +/* + * add nodes to appropriately model sharing of registers --- + * Do this for multi-fanout nodes -- includeing primary inputs + * This is tricky since the source (PI vertex) is actually a + * bunch of vertices.... + */ +static void +re_add_register_sharing_node(graph) +re_graph *graph; +{ + array_t *array; + re_edge *re_ed, *edge; + re_node *re_no, *new_node; + int i, j, max_weight, num_fan; + + /* + * For each node with multiple fanout -- + * Add a dummy node for the correct modelling of register sharing + */ + array = array_alloc(re_node *, 0); + re_foreach_node(graph, i, re_no){ + if (re_num_fanouts(re_no) > 1){ + array_insert_last(re_node *, array, re_no); + } + } + + if (retime_debug > 40){ + (void)fprintf(sisout, "%d nodes added to model register cost\n", + array_n(array)); + } + + /* + * Now look over all the multi-fanout nodes and modify the breadth + * as well as add edges from its fanouts to the dummy node + */ + + for (i = array_n(array); i-- > 0; ){ + re_no = array_fetch(re_node *, array, i); + new_node = retime_alloc_node(); + new_node->node = NIL(node_t); + new_node->id = re_num_nodes(graph); + new_node->type = RE_IGNORE; + new_node->final_area = new_node->final_delay = 0.0; + + /* First figure out the true fanout and maximum weight */ + max_weight = NEG_LARGE; + num_fan = 0; + re_foreach_fanout(re_no, j, re_ed){ + if (re_ignore_edge(re_ed)) continue; + num_fan++; + max_weight = MAX(max_weight, re_ed->weight); + re_ed->temp_breadth = re_ed->breadth; + } + + re_foreach_fanout(re_no, j, re_ed){ + if (re_ignore_edge(re_ed)) continue; + + /* Modify the breadth of the edge */ + re_ed->temp_breadth = re_ed->breadth / num_fan; + + /* Add an edge from the curent node to the dummy node */ + edge = re_create_edge(graph, re_ed->sink, new_node, + re_num_fanins(new_node), max_weight-re_ed->weight, 1.0); + edge->temp_breadth = edge->breadth / num_fan; + } + /* Add the new_node as part of the graph */ + array_insert_last(re_node *, graph->nodes, new_node); + } + array_free(array); +} + +/* + * First figure the number of constraints + * 2 equality constraint (r(host) = CONST) -- for appropraite scaling + * num_edge constraints of the type r(u) - r(v) <= w(e) for edges u->v + * ??? of type r(u) - r(v) <= W(u,v)-1 whenever D(u,v) > c + * Since the rhs of simplex is always positive, we need see if + * W(u,v)-1 is negative and if so, then the corresponding constraint has + * to be multiplied by -1 + */ +static void +re_setup_lp_tableau(graph, N, WD, c, ap, mp, m1p, m2p, m3p, trans) +re_graph *graph; +int N; +wd_t **WD; +int c; +double ***ap; +int *mp, *m1p, *m2p, *m3p; +int *trans; +{ + int i, j, k, t; + int m, m1, m2, m3; + int num_edges, cur_m1, cur_m2; + re_edge *re_ed; + re_node *re_no; + double **a; + + num_edges = re_num_edges(graph); + m1 = num_edges; /* <= constraints */ + m2 = 0; /* >= constraints */ + m3 = 2; /* == constraints -- retiming at host */ + + for ( i = 0; i < N; i++){ + for (j = 0; j < N; j++){ + if (WD[i][j].w == POS_LARGE) /* No path fron i to j */ continue; + if (WD[i][j].d > c){ /* Need to add aconstraint */ + if (WD[i][j].w < 1) m2++; + else m1++; + } + } + } + m = m1+m2+m3; + *trans = num_edges * re_sum_of_edge_weight(graph); + + /* Now allocate the a matrix --- for the tableau */ + a = ALLOC(double *, m+3); + for (i = m+3; i-- > 0; ){ + a[i] = ALLOC(double, N+2); + for (j = N+2; j-- > 0; ){ + a[i][j] = 0.0; + } + } + /* Now fillin the entries of the tableau */ + cur_m1 = 2; + cur_m2 = m1+2; + re_foreach_edge(graph, k, re_ed){ + /* edge (i,j) */ + i = re_ed->source->lp_index; + j = re_ed->sink->lp_index; + /* Add the constraint r(i) - r(j) <= w(e) */ + a[cur_m1][i+2] -= 1.0; a[cur_m1][j+2] += 1.0; + a[cur_m1][1] = re_ed->weight; + cur_m1++; + } + for ( i = 0; i < N; i++){ + for (j = 0; j < N; j++){ + if (WD[i][j].w == POS_LARGE) continue; /* No path from i to j */ + /* + * The constraint: 0 <= (W(i,j)-1) - r(i) + r(j), if D(i,j) > c + */ + if (WD[i][j].d > c){ + t = WD[i][j].w - 1; + if (t < 0) { + a[cur_m2][i+2] += 1.0; a[cur_m2][j+2] -= 1.0; + a[cur_m2][1] -= (double)t; + cur_m2++; + } else { + a[cur_m1][i+2] -= 1.0; a[cur_m1][j+2] += 1.0; + a[cur_m1][1] += (double)t; + cur_m1++; + } + } + } + } + + /* Retiming at the host (index N and N-1) is set to 0 */ + a[m][1] = *trans; a[m][N] = -1.0; /* Source HOST */ + a[m+1][1] = *trans; a[m+1][N+1] = -1.0; /* Sink HOST */ + + /* + * Now we need to setup the cost function. For the ith node the + * weight is sum_over_(i->?)(b(e)) - sum_over_(?->i)(b(e)). + * Note: since the simplex solves a max problem we have inverted the + * coefficient of the ith variable + */ + re_foreach_node(graph, k, re_no){ + i = re_no->lp_index; + re_foreach_fanout(re_no, j, re_ed){ + a[1][i+2] += re_ed->temp_breadth; + } + re_foreach_fanin(re_no, j, re_ed){ + a[1][i+2] -= re_ed->temp_breadth; + } + } + + if (retime_debug > 40){ + (void)fprintf(sisout,"Graph data :: %d internal nodes, %d edges\n", + re_num_internals(graph), num_edges); + (void)fprintf(sisout,"Simplex data:: %d variable, %d=%d+%d+%d constraints\n", + N, m, m1, m2, m3); + (void)fprintf(sisout,"Translation of the retiming = %d\n", *trans); + (void)fprintf(sisout,"Objective function \n"); + for (i = 2; i <= N+1; i++){ + (void)fprintf(sisout,"%s%5.3f r%d ", + (a[1][i] >= 0 ?"+":"-"), ABS(a[1][i]), i-2); + } + (void)fprintf(sisout,"\n"); + /* + for ( i = 0; i < m; i++){ + if (i == num_edges) + (void)fprintf(sisout,"End of edge constraints\n"); + (void)fprintf(sisout,"Eqn %-5d is: ", i); + sign = (i < m1 ? "<=" : (i >= (m1+m2) ? "=" : ">=")); + for (j = 0; j < N; j++){ + if (a[i+2][j+2] != 0) (void)fprintf(sisout,"%s%2.0f r%d ", + (a[i+2][j+2] >= 0 ? "+":"-"), ABS(a[i+2][j+2]), j); + } + (void)fprintf(sisout," %s %6.2f\n", sign, a[i+2][1]); + } + */ + } + + *ap = a; + *mp = m; + *m1p = m1; + *m2p = m2; + *m3p = m3; + + return; +} + +/* + * If the PI/PO nodes haver user specified delays, then we modify + * the delays of immidiate fanouts/fanins to account for the + * user-specified delays... In effect the delay of the node is the + * composite if the node's delay and the delay through a fictitious + * node whose delay equals the user specified delay at PI/PO + */ +static void +re_adjust_user_delays(graph) +re_graph *graph; +{ + int i, j; + re_edge *re_ed; + re_node *re_no; + + /* Do the PRIMARY INPUTS */ + /* Right now we account for PI arrival times in the WD computation */ + /* + pipo_array = array_alloc(re_node *, 0); + pipo_table = st_init_table(st_ptrcmp, st_ptrhash); + re_foreach_primary_input(graph, i, re_no){ + if (re_no->user_time > RETIME_TEST_NOT_SET){ + re_foreach_fanout(re_no, j, re_ed){ + if (re_ed->sink->type == RE_INTERNAL && + !st_insert(pipo_table, (char *)(re_ed->sink), NIL(char))){ + array_insert_last(re_node *, pipo_array, re_ed->sink); + } + } + } + } + for (i = array_n(pipo_array); i-- > 0; ){ + time = RETIME_USER_NOT_SET; + re_no = array_fetch(re_node *, pipo_array, i); + re_foreach_fanin(re_no, j, re_ed){ + if (re_ed->source->type == RE_PRIMARY_INPUT && + re_ed->source->user_time > RETIME_USER_NOT_SET){ + time = MAX(time, re_ed->source->scaled_user_time); + } + } + assert(time > RETIME_TEST_NOT_SET); + re_no->scaled_delay += time; + } + array_free(pipo_array); + st_free_table(pipo_table); + */ + + /* Now do the PRIMARY OUTPUTS --- these have a single fanin */ + re_foreach_primary_output(graph, i, re_no){ + if (re_no->user_time > RETIME_TEST_NOT_SET){ + re_foreach_fanin(re_no, j, re_ed){ + re_ed->source->scaled_delay -= re_no->scaled_user_time; + } + } + } +} + +#endif /* SIS */ diff --git a/sis/retime/re_nanni.c b/sis/retime/re_nanni.c new file mode 100644 index 0000000..77fa2bc --- /dev/null +++ b/sis/retime/re_nanni.c @@ -0,0 +1,295 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_nanni.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:48 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +static int retime_set_outputs(); +static st_table *retime_get_po_from_array(); +static array_t *retime_get_slow_nodes(); +static int re_translate_retiming_vector(); +static array_t *retime_get_input_reachable(); + +/* + * Use static arrays to cut down the allocation and freeing of the arrays + * used to store information during the delay tracing + */ +static bool *static_valid_table; +static double *static_delay_table; + +static void +retime_allocate_delay_data(n) +int n; +{ + static_valid_table = ALLOC(bool, n); + static_delay_table = ALLOC(double, n); +} + +static void +retime_free_delay_data() +{ + FREE(static_valid_table); + FREE(static_delay_table); +} + +/* + * Carry out the retiming procedure outlined in nanni's paper.... + * return 1 if success is achieved -- + */ + +int +retime_nanni_routine(graph, d_clk, retiming) +re_graph *graph; +double d_clk; +int *retiming; /* Array storing the retiming vector */ +{ + int i, j, n; + re_node *re_no; + array_t *M; + + /* Initialization */ + n = re_num_nodes(graph); + for ( i = n; i-- > 0; ){ + retiming[i] = 0; + } + retime_allocate_delay_data(n); + + /* Iteration according to Nanni's paper (and Saxe's thesis) */ + for (i = n; i-- > 0; ){ + M = retime_get_slow_nodes(graph, d_clk); + if ( array_n(M) == 0){ + array_free(M); + re_translate_retiming_vector(graph, retiming); + retime_free_delay_data(); + return TRUE; + } + + for( j = array_n(M); j-- > 0; ){ + re_no = array_fetch( re_node *, M, j); + retime_single_node(re_no, 1); + retiming[re_no->id] += 1; + } + if (retime_set_outputs(graph, M, retiming) == FALSE){ + array_free(M); + retime_free_delay_data(); + return FALSE; + } + array_free(M); + } + /* No feasible retiming exists for d_clk */ + retime_free_delay_data(); + return FALSE; +} +/* + * Delays all outputs and speedup all inputs -- + * returns FALSE if this is not possible without violating + * path weights + */ + +static int +retime_set_outputs(graph, M, retiming) +re_graph *graph; +array_t *M; +int *retiming; +{ + int i; + array_t *S; + re_node *node; + st_table *table; + + if ( (table = retime_get_po_from_array(M)) != NIL(st_table)){ + /* + * Retime all the o/p not in M, i.e. those o/p which have not + * been retimed. This is required since at this stage at least + * one o/p has been retimed + */ + re_foreach_primary_output( graph, i, node){ + if ( !st_is_member(table, (char *)node) ){ + retime_single_node(node, 1); + retiming[node->id] += 1; + } + } + + /* + * Now to find the vertices,v, such that a zero weight + * path exists from i/p to v. These are in the array S + */ + S = retime_get_input_reachable(graph); + for ( i = array_n(S); i-- > 0; ){ + node = array_fetch( re_node *, S, i); + if ( (node->type == RE_PRIMARY_OUTPUT) && + (st_is_member(table, (char *)node))){ + array_free(S); + st_free_table(table); + return FALSE; + } + /* Retime the node */ + retime_single_node( node, 1); + retiming[node->id] += 1; + } + array_free(S); + (void)st_free_table(table); + } + return TRUE; +} + +/* + * Just gets the primary outputs from the array + */ +static st_table * +retime_get_po_from_array(M) +array_t *M; +{ + int i; + re_node *node; + st_table *table; + + table = NIL(st_table); + for (i = array_n(M); i-- > 0; ){ + node = array_fetch( re_node *, M, i); + if ( node->type == RE_PRIMARY_OUTPUT) { + if ( table == NIL(st_table)){ + table = st_init_table( st_ptrcmp, st_ptrhash); + } + (void)st_insert(table, (char *)node, ""); + } + } + + return table; +} + +/* + * Gets the nodes in re_graph that are "slow" w.r.t. the given clock "clk" + * + * Uses the arrival time data for the primary input and the required times + * for the outputs while doing this computation ... + */ +static array_t * +retime_get_slow_nodes(graph, clk) +re_graph *graph; +double clk; +{ + int i, n = re_num_nodes(graph); + array_t *M; + re_node *node; + double offset; + + for (i = n ; i-- > 0; ) { + static_valid_table[i] = FALSE; + static_delay_table[i] = 0.0; + } + + /* primary input nodes need not be evaluated */ + re_foreach_node(graph, i, node){ + if (re_num_fanins(node) == 0){ + static_valid_table[i] = TRUE; + if (node->user_time > RETIME_TEST_NOT_SET) { + static_delay_table[i] = node->user_time; + } + } + } + + /* compute delays */ + for (i = n; i-- > 0; ) { + if (!static_valid_table[i]) { + node = array_fetch(re_node *, graph->nodes, i); + re_evaluate_delay(node, static_valid_table, static_delay_table); + } + } + + /* find the nodes with arrival time > clk */ + M = array_alloc(re_node *,0); + for (i = n; i-- > 0; ) { + offset = 0.0; + node = array_fetch(re_node *, graph->nodes, i); + if (node->type == RE_PRIMARY_OUTPUT && + node->user_time > RETIME_TEST_NOT_SET){ + offset = node->user_time; + } + if ((static_delay_table[i] - offset) > clk) { + array_insert_last(re_node *, M, node); + } + } + + /* return */ + return(M); +} + +/* + * Get the nodes reachable from pi with 0 weight paths + */ + +static array_t * +retime_get_input_reachable(graph) +re_graph *graph; +{ + array_t *S; + re_edge *edge; + re_node *node; + st_table *table; + int i, j, first, last, more_to_come; + + /* + * Perform bfs to get these nodes + */ + S = array_alloc( re_node *, 0); + table = st_init_table( st_ptrcmp, st_ptrhash); + re_foreach_primary_input( graph, i, node){ + (void)st_insert(table, (char *)node, ""); + array_insert_last( re_node *, S, node); + } + + first = 0; + more_to_come = TRUE; + while ( more_to_come){ + last = array_n(S); + more_to_come = FALSE; + for( i = first; i < array_n(S); i++){ + node = array_fetch( re_node *, S, i); + re_foreach_fanout( node, j, edge){ + if (re_ignore_edge(edge)) continue; + if ( (edge->weight == 0) && + (!st_is_member(table,(char *)(edge->sink)))){ + (void)st_insert(table, (char *)(edge->sink), ""); + array_insert_last( re_node *, S, edge->sink); + more_to_come = TRUE; + } + } + } + first = last; + } + st_free_table(table); + + return(S); +} + +static int +re_translate_retiming_vector(graph, r) +re_graph *graph; +int *r; +{ + re_node *re_no; + int i, max_po = 0, max_pi = 0, n = re_num_nodes(graph); + + re_foreach_node(graph, i, re_no){ + if (re_no->type == RE_PRIMARY_INPUT){ + max_pi = MAX(max_pi, r[i]); + } else if (re_no->type == RE_PRIMARY_OUTPUT){ + max_po = MAX(max_po, r[i]); + } + } + assert(max_pi == max_po); + for (i = n; i-- > 0; ){ + re_no = array_fetch(re_node *, graph->nodes, i); + r[i] -= max_pi; + retime_single_node(re_no, -max_pi); + } +} +#endif /* SIS */ diff --git a/sis/retime/re_net.c b/sis/retime/re_net.c new file mode 100644 index 0000000..376773f --- /dev/null +++ b/sis/retime/re_net.c @@ -0,0 +1,1111 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_net.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +typedef struct retime_fanout_struct{ + node_t *fanout; + int fanin_id; + int weight; + } re_fanout_t; + +typedef struct retime_array_struct{ + array_t *bfs; + st_table *visited; + } re_data_t; + +static void retime_set_gate(); +static void retime_add_latches(); +static void retime_share_latches(); +static void retime_add_latches_to_network(); +static void retime_assure_init_values(); +static node_t *retime_get_latch_input(); +static array_t *retime_gen_weights(); +static latch_t **re_gen_latches(); +static void retime_add_bfs_nodes(); +static void re_patch_fanouts(); + +enum st_retval re_table_to_array(); + +#define is_feedback_latch(g) \ + (lib_gate_latch_pin((g)) != -1) + +/* ARGSUSED */ +/* + * We assume the following --- + * + * The user has made sure that the network is one that is retimable i.e. + * the routine "retime_is_network_retimable()" should return 1 + * + * if (not_mapped) then no buffers between PI and PO are used.. use the value + * delay_r to specify the i/p o/p delay thru the latch + * if (mapped) then annotate the node in the retime graph with the delay thru + * the latch (ignore the delay_r parameter).. + * + * REMEMBER::: In cases where cycles consisting of only latches are found + * some nodes are added to the network, Remember to delete these + * using the routine "re_delete_temp_nodes()" !!!! + */ +re_graph * +retime_network_to_graph(network, size, use_mapped) +network_t *network; +int use_mapped; +int size; +{ + lsGen gen; + re_graph *graph; + st_table *l_table; /* Table of all the latches that must be traversed */ + st_table *node_to_id_table; /* Stores correp between nodes and id */ + st_generator *stgen; + char *dummy, name[128]; + latch_synch_t type, s_type; + latch_t *latch; + lib_gate_t *d_latch = NIL(lib_gate_t); + int i, n, index; + re_node *re_no; + node_t *node, *temp, **fo_array, *cntrl, *control = NIL(node_t); + re_data_t latch_end_data; + array_t *nodevec, *temp_array; + + /* Allocation & initializations */ + s_type = UNKNOWN; + graph = re_graph_alloc(); + node_to_id_table = st_init_table(st_ptrcmp, st_ptrhash); + + nodevec = array_alloc(node_t *, 0); + foreach_primary_input(network, gen, node ){ + if (network_latch_end(node) != NIL(node_t)){ + /* Keep the synchronization type around */ + latch = latch_from_node(node); + if ((type = latch_get_type(latch)) != UNKNOWN){ + s_type = type; + } + if ((cntrl = latch_get_control(latch)) != NIL(node_t)){ + control = cntrl; + } + } + } + graph->s_type = s_type; /* For use in converting the re_graph to netw */ + if (control != NIL(node_t)){ + /* The name of the signal stored is that of the fanin */ + graph->control_name = util_strsav(node_long_name(node_get_fanin(control,0))); + } + + /* + * check if an appropriate d-latch is present: This is essential since + * we require the generic latch so that we can move latches + */ + if (use_mapped){ + d_latch = lib_choose_smallest_latch(lib_get_library(), "f=a;", s_type); + if (d_latch == NIL(lib_gate_t)){ + (void)fprintf(siserr, "%s D-FlipFlop not present in library\n", + (s_type == RISING_EDGE ? "rising edge" : "falling_edge")); + return NIL(re_graph); + } + } + + foreach_node(network, gen, node ){ + /* + * Do not add PI/PO nodes corresponding to latches or nodes that + * correspond to the logic of the D-FlipFlops, or to control nodes of + * latches, or internal nodes that are part of mapped D-latches + */ + if (network_latch_end(node) != NIL(node_t) || + network_is_control(network, node) || + (node->type == INTERNAL && use_mapped && + lib_gate_of(node) == d_latch) ) continue; + re_graph_add_node(graph, node, use_mapped, d_latch, node_to_id_table); + } + + + /* + * Starting from the inputs start adding edges in a breadth + * first manner. Take care when wrapping around due to latches + * Keep a table of latches and delete the latches that are traversed. + * Then we can find out if all lathes are traversed or not.... + */ + foreach_node(network, gen, node ){ + if (network_latch_end(node) == NIL(node_t) + && node_num_fanin(node) == 0){ + array_insert_last(node_t *, nodevec, node); + } + } + l_table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_latch(network, gen, latch){ + (void)st_insert(l_table, (char *)latch, NIL(char)); + } + + /* Add the edges encountered starting from the inputs */ + retime_add_bfs_nodes(graph, nodevec, l_table, node_to_id_table, d_latch); + array_free(nodevec); + + /* + * In pathological case there may be sections of the circuit left out--- + * those that have no inputs. These + * we traverse starting from the nodes that are outputs of latches + */ + if (st_count(l_table) > 0){ + latch_end_data.bfs = array_alloc(node_t *, 0); + latch_end_data.visited = st_init_table(st_ptrcmp, st_ptrhash); + st_foreach(l_table, re_table_to_array, (char *)&latch_end_data); + retime_add_bfs_nodes(graph, latch_end_data.bfs, l_table, + node_to_id_table, d_latch); + array_free(latch_end_data.bfs); + st_free_table(latch_end_data.visited); + } + /* At this stage in really pathological cases in which cycles of + * latches exist without any logic there are latches left unvisited. + * Since the retime graph has no representation for such cycles + * (vertices have to exist for weighted edges to exist between them) + */ + if (st_count(l_table) > 0){ + /* + * !!!! CYCLE WITH NO COMBINATIONAL GATES EXISTS !!!! + * Add gates temporarily to the network so that vertices in + * the retime graph can be defined. These vertices are special + */ + temp_array = array_alloc(node_t *, 0); + + st_foreach_item(l_table, stgen, (char **)&latch, (char **)&dummy){ + node = latch_get_output(latch); + if ((n = node_num_fanout(node)) > 1){ + /* Record the current fanouts of node */ + i = 0; fo_array = ALLOC(node_t *,n); + foreach_fanout(node, gen, temp){ + fo_array[i++] = temp; + } + /* Add buffer; Put a ' ' in name to recognize it later */ + temp = node_literal(node, 0); + network_add_node(network, temp); + sprintf(name, "%s temp", temp->name); + network_change_node_name(network, temp, util_strsav(name)); + /* Patch the fanouts of latch output to the buffer */ + for (i = n; i-- > 0; ){ + node_patch_fanin(fo_array[i], node, temp); + } + FREE(fo_array); + + array_insert_last(node_t *, temp_array, temp); + re_graph_add_node(graph, temp, use_mapped, d_latch, + node_to_id_table); + /* Set the area and delay of the buffer to be 0.0 */ + assert(st_lookup_int(node_to_id_table, (char *)temp, &index)); + re_no = re_get_node(graph, index); + re_no->final_delay = 0.0; + re_no->final_area = 0.0; + } + } + + retime_add_bfs_nodes(graph, temp_array, l_table, + node_to_id_table, d_latch); + + array_free(temp_array); + } + + assert(st_count(l_table) == 0); + + st_free_table(l_table); + st_free_table(node_to_id_table); + return(graph); +} + +/* + * Routine called to generate the fanouts of the latches so as to + * be able to carry on the traversal of components that dont have + * inputs + */ + +/* ARGSUSED */ +enum st_retval +re_table_to_array(key, value, arg) +char *key, *value, *arg; +{ + lsGen gen; + node_t *node, *fo; + latch_t *latch = (latch_t *)key; + re_data_t *data = (re_data_t *)arg; + + node = latch_get_output(latch); + foreach_fanout(node, gen, fo){ + if (fo->type == INTERNAL && + !st_insert(data->visited, (char *)fo, NIL(char))){ + array_insert_last(node_t *, data->bfs, fo); + } + } + + return ST_CONTINUE; +} + +/* + * This routine takes the nodes in "nodevec" and then will do a + * breadth_first_traversal and add the nodes it encounters + */ +static void +retime_add_bfs_nodes(graph, nodevec, l_table, node_to_id_table, d_latch) +re_graph *graph; +array_t *nodevec; +st_table *l_table; +st_table *node_to_id_table; +lib_gate_t *d_latch; +{ + + array_t *fan; + node_t *node; + re_edge *re_ed; + st_table *add_table; /* Stores tempory data during traversal */ + re_fanout_t *fanout; + int i, j, first, last; + + /* The actual breadth first traversal */ + first = 0; + add_table = st_init_table(st_ptrcmp, st_ptrhash); + do { + last = array_n(nodevec); + for (i = first; i < last ; i++){ + node = array_fetch(node_t *, nodevec, i); + if (! st_is_member(add_table, (char *)node) ){ + /* Generate the fanouts and the weights if not visited */ + fan = retime_gen_weights(node, d_latch); + + for (j = array_n(fan); j-- > 0; ){ + fanout = array_fetch(re_fanout_t *, fan, j); + if (!st_is_member(add_table, (char *)(fanout->fanout)) ){ + array_insert_last(node_t *, nodevec, fanout->fanout); + } + /* + * Now generate the latches from the fanout to node + */ + re_ed = re_graph_add_edge(graph, node, fanout->fanout, + fanout->weight, 1.0/*breadth=1*/, fanout->fanin_id, + node_to_id_table); + re_ed->latches = re_gen_latches(fanout->fanout, + fanout->fanin_id, fanout->weight, l_table, d_latch); + + /* + * To check the translation etc. I want to put the initial + * values in the initial_values filed at this stage + */ + + /* + if (re_ed->weight > re_ed->num_val_alloc){ + re_ed->num_val_alloc = re_ed->weight; + re_ed->initial_values = REALLOC(int, + re_ed->initial_values, re_ed->num_val_alloc); + } + for (k = re_ed->weight; k-- > 0; ) { + re_ed->initial_values[k] = + latch_get_initial_value(re_ed->latches[k]); + } + */ + FREE(fanout); + } + (void) st_insert(add_table, (char *)node, NIL(char)); + array_free(fan); + } + } + first = last; + } while (first < array_n(nodevec) ); + st_free_table(add_table ); +} + +/* + * Generate the number of registers between the node + * and its fanouts. Take care since primary outputs of the + * network may be true po or inputs to latches. Also insert the + * initial values of the latches in the fanout structure. + */ +static array_t * +retime_gen_weights(node, d_latch) +node_t *node; +lib_gate_t *d_latch; /* If NIL(lib_gate_t) then unmapped netw */ +{ + lsGen gen; + char *dummy; + st_table *table; + re_fanout_t *new_fan; + node_t *fo, *end, *np; + array_t *fan, *nodevec; + int i, pin, first, last, depth, more_to_come; + + fan = array_alloc(re_fanout_t *, 0); + + if (node->type == PRIMARY_OUTPUT && + (network_latch_end(node) != NIL(node_t))) return(fan); + if (node->type == PRIMARY_INPUT && + (network_latch_end(node) != NIL(node_t))) return(fan); + + table = st_init_table(st_ptrcmp, st_ptrhash); + nodevec = array_alloc(node_t *, 0); + (void)st_insert(table, (char *)node, (char *)0); + array_insert_last(node_t *, nodevec, node); + + more_to_come = TRUE; + first = 0; + while (more_to_come ){ + more_to_come = FALSE; + last = array_n(nodevec); + for (i = first; i < last; i++){ + np = array_fetch(node_t *, nodevec, i); + if (st_lookup(table, (char *)np, &dummy) ){ + depth = (int) dummy; + } else { + (void) fprintf(sisout,"Hey !! node not in table \n"); + continue; + } + + if (np->type == PRIMARY_OUTPUT){ + /* + * A primary o/p at this stage is a latch end + * or a true PO which has no fanouts anyway in which + * case no work needs to be done + */ + if ((end = network_latch_end(np)) != NIL(node_t)){ + if (st_lookup(table, (char *)np, &dummy) ){ + depth = (int)dummy; + if (!st_is_member(table, (char *)end)){ + more_to_come = TRUE; + array_insert_last(node_t *, nodevec, end); + (void)st_insert(table, (char *)end, (char *)(depth+1)); + } + } else { + (void) fprintf(sisout,"Hey !! po not in table \n"); + } + } + } else { + foreach_fanout_pin(np, gen, fo, pin) { + end = retime_network_latch_end(fo, d_latch); + if (end == NIL(node_t)){ + /* Check if it is a dummy PO for control of latches */ + if (network_is_control(node_network(node), fo)) + continue; + /* This is a fanout of the node */ + new_fan = ALLOC(re_fanout_t , 1); + new_fan->fanout = fo; + new_fan->fanin_id = pin; + new_fan->weight = depth; + array_insert_last(re_fanout_t *, fan, new_fan); + } else { + /* latch i/p -- Add to list being processed */ + more_to_come = TRUE; + array_insert_last(node_t *, nodevec, fo); + (void)st_insert(table, (char *)fo, (char *)depth); + } + } + } + } + first = last; + } + array_free(nodevec); + st_free_table(table); + return (fan); +} + +/* Utility routine + * If node is the input of a latch, it will generate its o/p else NIL + */ +node_t * +retime_network_latch_end(node, d_latch) +node_t *node; +lib_gate_t *d_latch; +{ + node_t *po, *end; + + if ((end = network_latch_end(node)) == NIL(node_t) && + d_latch != NIL(lib_gate_t) && node->type == INTERNAL && + lib_gate_of(node) == d_latch){ + po = node_get_fanout(node, 0); + end = network_latch_end(po); + assert(end != NIL(node_t) && po->type == PRIMARY_OUTPUT); + } + return end; +} + + /* + * Utility: Move the fanouts of "from" to be fanouts of the "to" node + */ +static void +re_patch_fanouts(from, to) +node_t *from, *to; +{ + int j=0, n; + lsGen gen; + node_t **fo_array, *fanout; + + n = node_num_fanout(from); + fo_array = ALLOC(node_t *,n); + foreach_fanout(from, gen, fanout){ + fo_array[j++] = fanout; + } + for (j = n; j-- > 0; ){ + node_patch_fanin(fo_array[j], from, to); + } + FREE(fo_array); +} + /* + * Routine to delete the temoporary nodes added to make sure that a + * retime graph can be generated from the network in case cycles with + * only latches are encountered in the circuit... + */ +void +re_delete_temp_nodes(network) +network_t *network; +{ + lsGen gen; + node_t *node, *temp; + + foreach_node(network, gen, node){ + if (node->type != INTERNAL) continue; + if (index(node->name, ' ') == NULL) continue; + temp = node_get_fanin(node, 0); + re_patch_fanouts(node, temp); /* move fanouts from node to temp */ + network_delete_node_gen(network, gen); + } +} + +/* + * If use_mapped is set... then we need to get the appropriate dff from the + * library and inset them. Furthermore for the original mapped latches + * in the network, we need to ensure that the latches are captured correctly + */ +network_t * +retime_graph_to_network(graph, use_mapped) +re_graph *graph; +int use_mapped; +{ + char *name; + int i, j, k; + lsGen gen, gen2; + latch_t *latch; + re_edge *edge; + re_node *re_no; + st_table *node_to_id_table; /* Need to maintain correspondence */ + st_table *gate_table; + extern void delay_dup(); /* Should actually be in delay.h */ + array_t *fo_array, *nodes, *orig_po_array, *fanin_array; + network_t *netw, *netw1, *network; + lib_gate_t *gate, *d_latch; + node_t *temp, *new_buffer, *node, *dup_node, *po, *pi, *control; + node_t *root_node, *fanin, *fanin_node, *fo, *old_fanin; + + extern void map_invalid(); /* belongs to map_int.h */ + extern array_t *network_and_node_to_array(); /* belongs to speed_int.h */ + + + if (use_mapped){ + /* Get the latch from the library so as to annotate the latches */ + d_latch = lib_choose_smallest_latch(lib_get_library(), "f=a;", graph->s_type); + if (d_latch == NIL(lib_gate_t)) { + error_append("No D flip-flop present in library\n"); + return NIL(network_t); + } + } else { + d_latch = NIL(lib_gate_t); + } + network = network_alloc(); + node_to_id_table = st_init_table(st_ptrcmp, st_ptrhash); + + re_foreach_node(graph, i, re_no){ + if (re_no->type != RE_PRIMARY_OUTPUT && re_no->type != RE_IGNORE){ + dup_node = node_dup(re_no->node); + if (!use_mapped) map_invalid(dup_node); + re_no->node->copy = dup_node; + (void)st_insert(node_to_id_table, (char *)dup_node, (char *)(re_no->id)); + + if (re_no->type == RE_PRIMARY_INPUT){ + network_add_primary_input(network, dup_node); + } else{ + /* + * Next need to set the implementation as the one desired + * The duplicate node is the key to the retime node in the + * cache + */ + network_add_node(network, dup_node); + if (use_mapped) retime_set_gate(dup_node, graph, node_to_id_table); + } + + /* Retain correspondence of primary o/p nodes */ + re_foreach_fanout(re_no, j, edge){ + if (re_ignore_edge(edge)) continue; + if (edge->sink->type == RE_PRIMARY_OUTPUT){ + if (graph->control_name != NIL(char) && + !strcmp(node_long_name(dup_node), graph->control_name)) + continue; + po = network_add_primary_output(network, dup_node); + /* JCM - don't change name of primary inputs!!! */ + if(re_no->type == RE_PRIMARY_INPUT) + network_swap_names(network, dup_node, po); + network_change_node_name(network, po, + util_strsav(node_long_name(edge->sink->node))); + if (edge->weight > 0){ + fanin_remove_fanout(po); + retime_assure_init_values(edge); + retime_add_latches_to_network(network, dup_node, po, + 0, edge->weight, d_latch, edge->initial_values); + fanin_add_fanout(po); + } + } + } + } + } + + /* + * For the +ve weight edges add appropriate latches . Also + * patch the pointers. + */ + re_foreach_node(graph, i, re_no) { + if (re_no->type == RE_INTERNAL) { + fanin_remove_fanout(re_no->node->copy); + re_foreach_fanin(re_no, j, edge) { + if (re_ignore_edge(edge)) continue; + if (edge->weight == 0){ + /* + * Check to make sure that the fanin ptrs are fine, + * Required since the graph can contain cycles + */ + dup_node = re_no->node->copy; + k = edge->sink_fanin_id; + old_fanin = node_get_fanin(dup_node, k); + fanin = edge->source->node->copy; + if (old_fanin != fanin){ + dup_node->fanin[k] = fanin; + } + } else { + retime_add_latches(network, edge, d_latch); + } + } + fanin_add_fanout(re_no->node->copy); + } + } + st_free_table(node_to_id_table); + + if (use_mapped){ + /* + * Remove extra gates that might be left behind from old DFF's + */ + foreach_node(network, gen, node){ + if (node->type == INTERNAL) { + if (node_function(node) == NODE_BUF){ + gate = lib_gate_of(node); + if (lib_gate_type(gate) != COMBINATIONAL){ /* D-FF */ + fanin_node = node_get_fanin(node, 0); + if (node_num_fanout(node) == 1){ + fo = node_get_fanout(node, 0); + if (fo->type != PRIMARY_OUTPUT || + network_is_real_po(network, fo)){ + /* node is a leftover from previous mapping */ + (void)node_patch_fanin(fo, node, fanin_node); + network_delete_node_gen(network, gen); + } + } else { + fo_array = array_alloc(node_t *, 0); + foreach_fanout(node, gen2, fo){ + array_insert_last(node_t *, fo_array, fo); + } + for (i = array_n(fo_array); i-- > 0; ){ + fo = array_fetch(node_t *, fo_array, i); + (void)node_patch_fanin(fo, node, fanin_node); + } + network_delete_node_gen(network, gen); + array_free(fo_array); + } + } + } else { + gate = lib_gate_of(node); + if (lib_gate_type(gate) != COMBINATIONAL) { + fo = node_get_fanout(node, 0); + if (network_latch_end(fo) == NIL(node_t)) { + + /* This is combinational logic left over from retiming + latches with combinational logic but with no + feedback. This needs to be remapped. */ + + (void)fprintf(sisout, "WARNING: complex latch %s at %s had to be remapped\n", + lib_gate_name(gate), node_name(node)); + /* + * Decompose the logic gate and replace it by mapped ones + */ + netw1 = network_create_from_node(node); + netw = map_network(netw1, lib_get_library(), 0.0, 1, 0); + if (netw == NIL(network_t)){ + error_append("Unable to remap complex latch\n"); + return NIL(network_t); + } + network_free(netw1); + gate_table = st_init_table(st_ptrcmp, st_ptrhash); + nodes = network_and_node_to_array(netw, node, + gate_table); + root_node = array_fetch(node_t *, nodes, 1); + for (i = array_n(nodes)-1; i > 1; i--) { + temp = array_fetch(node_t *, nodes, i); + if (node_function(temp) != NODE_PI){ + network_add_node(network, temp); + /* + * Also need to annotate the node with corresp gate + */ + (void)st_lookup(gate_table, (char *)temp, + (char **)&gate); + buf_add_implementation(temp, gate); + } else { + node_free(temp); + } + } + (void)st_lookup(gate_table,(char *)root_node, + (char **)&gate); + node_replace(node, root_node); + buf_add_implementation(node, gate); + array_free(nodes); + network_free(netw); + st_free_table(gate_table); + } + } + } + } + } + } + if (use_mapped){ + foreach_latch(network, gen, latch){ + po = latch_get_input(latch); + pi = latch_get_output(latch); + fanin_node = node_get_fanin(po, 0); + if (node_num_fanout(fanin_node) > 1){ + (void)fprintf(sisout, "WARNING: complex latch %s at %s had to be remapped\n", + lib_gate_name(latch_get_gate(latch)), io_name(pi, 0)); + /* + * Decompose the logic gate and replace it by mapped ones + */ + netw1 = network_create_from_node(fanin_node); + netw = map_network(netw1, lib_get_library(), 0.0, 1, 0); + if (netw == NIL(network_t)){ + error_append("Unable to remap complex latch\n"); + return NIL(network_t); + } + network_free(netw1); + gate_table = st_init_table(st_ptrcmp, st_ptrhash); + nodes = network_and_node_to_array(netw, fanin_node, gate_table); + root_node = array_fetch(node_t *, nodes, 1); + for (i = array_n(nodes)-1; i > 1; i--) { + temp = array_fetch(node_t *, nodes, i); + if (node_function(temp) != NODE_PI){ + network_add_node(network, temp); + /* Also need to annotate the node with corresp gate */ + (void)st_lookup(gate_table, (char *)temp, (char **)&gate); + buf_add_implementation(temp, gate); + } else { + node_free(temp); + } + } + (void)st_lookup(gate_table,(char *)root_node, (char **)&gate); + node_replace(fanin_node, root_node); + buf_add_implementation(fanin_node, gate); + array_free(nodes); + network_free(netw); + st_free_table(gate_table); + /* + * Set the latch type for the latch to be a simple DFF + */ + new_buffer = node_literal(fanin_node, 1); + network_add_node(network, new_buffer); + node_patch_fanin(po, fanin_node, new_buffer); + retime_lib_set_gate(new_buffer, d_latch, 0); + latch_set_gate(latch, d_latch); + } + } + } + + /* + * Just for ease of the user we will keep the primary outputs in the same + * order as the original network. Also copy over any delay data that may + * be stored with the PO nodes .... + */ + orig_po_array = array_alloc(node_t *, 0); + fanin_array = array_alloc(node_t *, 0); + re_foreach_primary_output(graph, i, re_no){ + name = re_no->node->name; + po = network_find_node(network, name); + if (po != NIL(node_t)){ + array_insert_last(node_t *, fanin_array, node_get_fanin(po, 0)); + array_insert_last(node_t *, orig_po_array, re_no->node); + network_delete_node(network, po); + } else { + (void)fprintf(sisout, "E: PO %s not found in new network\n", name); + } + } + for (i = 0; i < array_n(fanin_array); i++){ + fanin_node = array_fetch(node_t *, fanin_array, i); + po = network_add_primary_output(network, fanin_node); + temp = array_fetch(node_t *, orig_po_array, i); + network_change_node_name(network, po, util_strsav(node_long_name(temp))); + delay_dup(temp, po); + } + array_free(orig_po_array); + array_free(fanin_array); + + if (!network_check(network)){ + (void)fprintf(siserr,"%s", error_string()); + } + if (use_mapped && (!lib_network_is_mapped(network)) ){ + error_append("Network is not mapped after conversion\n"); + } + + /* Now annotate each latch with the appropriate control signal */ + control = NIL(node_t); + if (graph->control_name != NIL(char)){ + control = network_find_node(network, graph->control_name); + if (control == NIL(node_t)){ + (void)fprintf(siserr,"Cannot recover control signal for latches\n"); + } + control = network_add_fake_primary_output(network, control); + } + foreach_latch(network, gen, latch){ + latch_set_control(latch, control); + latch_set_type(latch, graph->s_type); + } + + return(network); +} + + +/* + * Assures that the initial values are present on the edge. + * If the initial values are presnt, no problem. Else the + * latches should be present on the edge. Get the values + * from the latches. Failing this assume don't care values. + */ +static void +retime_assure_init_values(edge) +re_edge *edge; +{ + int k; + + if (edge->weight == 0) return; + + if (edge->initial_values == NIL(int)){ + edge->initial_values = ALLOC(int, edge->weight); + edge->num_val_alloc = edge->weight; + if (edge->latches != NIL(latch_t *)){ + for(k = edge->weight; k-- > 0; ){ + edge->initial_values[k] = + latch_get_initial_value(edge->latches[k]); + } + } else { + for(k = edge->weight; k-- > 0; ){ + edge->initial_values[k] = 2; + } + } + } +} +/* + * Adds the appropriate latches -- + * Note that the source and sink fields hold the entries to + * nodes in the old network. The copy field of these nodes + * has the info in the current network. + */ +static void +retime_add_latches(network, edge, d_latch) +network_t *network; +re_edge *edge; +lib_gate_t *d_latch; +{ + latch_t *latch; + + if (edge->weight <= 0) return; + + retime_assure_init_values(edge); + if (d_latch != NIL(lib_gate_t) && + is_feedback_latch(lib_gate_of(edge->source->node)) && + edge->weight == 1 && edge->source == edge->sink){ + /* + * The latch has been added when the gate was set at the source + * Make sure that the initial value is correctly put in + */ + latch = latch_from_node(node_get_fanout(edge->source->node->copy,0)); + assert(latch != NIL(latch_t)); + latch_set_initial_value(latch, edge->initial_values[0]); + latch_set_current_value(latch, edge->initial_values[0]); + return; + } + + retime_add_latches_to_network(network, edge->source->node->copy, + edge->sink->node->copy, edge->sink_fanin_id, edge->weight, + d_latch, edge->initial_values); +} + +/* + * Add "weight" latches between "from" and the "index" fanin of "to" + */ +static void +retime_add_latches_to_network(network, from_node, to, index, weight, d_latch, init_val) +network_t *network; +node_t *from_node, *to; +int index, weight; +lib_gate_t *d_latch; +int *init_val; /* Hold the initial value to be inserted for latches */ +{ + int i, num_latches; + latch_t *latch; + node_t *l_in, *l_out, *from, *node; + /* + * see if there are already some latches that can be shared + */ + + num_latches = 0; + from = from_node; + /* + * Find the number of latches yet to be added + */ + retime_share_latches(&from, weight, d_latch, init_val, &num_latches); + + if (num_latches > 0){ + node = from; + + /* + * For all but last latch add a pair of po and pi nodes and connect + * them via the latch entry. Also put in the correct initial value + */ + for (i = 0; i < num_latches-1; i++){ + if (d_latch != NIL(lib_gate_t)){ + l_in = node_literal(node, 1); + network_add_node(network, l_in); + retime_lib_set_gate(l_in, d_latch, 0); /* Annotate the gate */ + node = l_in; + } + l_in = network_add_fake_primary_output(network, node); + l_out = node_alloc(); + network_add_primary_input(network, l_out); + network_create_latch(network, &latch, l_in, l_out); + latch_set_initial_value(latch, init_val[weight-num_latches+i]); + latch_set_current_value(latch, init_val[weight-num_latches+i]); + latch_set_gate(latch, d_latch); + node = l_out; + } + /* + * Add the last latch and connect to the "index" fanin of "to" + */ + if (d_latch != NIL(lib_gate_t)){ + l_in = node_literal(node, 1); + network_add_node(network, l_in); + retime_lib_set_gate(l_in, d_latch, 0); /* Annotate the latch */ + node = l_in; + } + l_in = network_add_fake_primary_output(network, node); + node = node_alloc(); + network_add_primary_input(network, node); + network_create_latch(network, &latch, l_in, node); + latch_set_initial_value(latch, init_val[weight-1]); + latch_set_current_value(latch, init_val[weight-1]); + latch_set_gate(latch, d_latch); + to->fanin[index] = node; + } else { + to->fanin[index] = from; + } +} + +/* + * Check to see if we can share latches already present. Make sure + * that the latches present have the same initial value as ours + */ +static void +retime_share_latches(node, req, d_latch, init_val, deficit) +node_t **node; /* RETURN: The new starting point for adding latches */ +int req, *init_val; /* Number latches required and their initial values */ +lib_gate_t *d_latch; +int *deficit; /* RETURN: Number of latches to be added */ +{ + int i; + node_t *np, *l_out, *l_in; + + for (np = *node, *deficit = req, i = 0; + ((l_out = retime_get_latch_input(np, d_latch, init_val[i])) != NIL(node_t)) + && (*deficit > 0);i++){ + l_in = network_latch_end(l_out); + + np = *node = l_in; + (*deficit)--; + } +} + +/* + * Check if latch with the same initial value is present or not + */ +static node_t * +retime_get_latch_input(node, d_latch, value) +node_t *node; +lib_gate_t *d_latch; +int value; +{ + lsGen gen; + node_t *np, *l_out; + + foreach_fanout(node, gen, np) { + if (d_latch != NIL(lib_gate_t)){ + /* Traverse a possible buffer -- added nodes are already mapped */ + if (np->type == INTERNAL && lib_gate_of(np) == d_latch){ + assert(node_num_fanout(np) == 1); + np = node_get_fanout(np, 0); + return np; + } + } + if ((l_out = network_latch_end(np)) != NIL(node_t)){ + /* Make sure the new latch has the desired initial value */ + if (latch_get_initial_value(latch_from_node(l_out)) == value){ + (void)lsFinish(gen); + return np; + } + } + } + return NIL(node_t); +} + +/* + * Set the gate implementation of node.. node is part of a network + */ +static void +retime_set_gate(node, graph, node_to_id_table) +node_t *node; +re_graph *graph; +st_table *node_to_id_table; +{ + re_edge *edge; + re_node *re_no; + int j, k, index; + lib_gate_t *gate; + node_t *orig_node; + + assert(st_lookup_int(node_to_id_table, (char *)node, &index)); + re_no = re_get_node(graph, index); + orig_node = re_no->node; + + gate = lib_gate_of(orig_node); + k = -1; + if (is_feedback_latch(gate)){ + /* Look for the index of the feedback arc for the complex latch */ + re_foreach_fanout(re_no, j, edge){ + if (re_ignore_edge(edge)) continue; + if (edge->weight == 1 && edge->sink == re_no){ + k = edge->sink_fanin_id; + } + } + assert(k != -1); + } + retime_lib_set_gate(node, gate, k); +} + +retime_lib_set_gate(node, gate, index) +node_t *node; +lib_gate_t *gate; +int index; /* index == -1 if there is no feedback pin on complex latch */ +{ + int i, n; + char **formals; + latch_t *latch; + network_t *network; + node_t *po_node, *pi_node, *np, **actuals; + + /* HERE */ + network = node_network(node); + if (is_feedback_latch(gate)){ + /* + * Special casing for the Complex flip flops + * Add the PI/PO and the latch construct right here + */ + pi_node = node_alloc(); + network_add_primary_input(network, pi_node); + po_node = network_add_primary_output(network, node); + + n = node_num_fanin(node); + actuals = ALLOC(node_t *, n); + foreach_fanin(node, i, np) { + if (i != index) + actuals[i] = np; + else + actuals[i] = pi_node; + } + formals = ALLOC(char *,n); + for (i=0; i < n; i++){ + formals[i] = lib_gate_pin_name(gate, i, 1); + } + if (!lib_set_gate(node, gate, formals, actuals, n)){ + (void)fprintf(siserr,"%s", error_string()); + } + network_create_latch(network, &latch, po_node, pi_node); + latch_set_gate(latch, gate); + } else { + /* + * Either a DFF or a combinational gate in the old network + * For now add only the internal gate corresp to the old_gate + */ + + n = node_num_fanin(node); + actuals = ALLOC(node_t *, n); + foreach_fanin(node, i, np) { + actuals[i] = np; + } + formals = ALLOC(char *,n); + for (i=0; i < n; i++){ + formals[i] = lib_gate_pin_name(gate, i, 1); + } + if (!lib_set_gate(node, gate, formals, actuals, n)){ + (void)fprintf(siserr,"%s", error_string()); + } + } + FREE(actuals); + FREE(formals); +} + + +/* + * Generates an array of latches between "to" and "from" modes. The + * number of such latches is "num" and the latches are arranged in + * the array as they appear in going from "from" to the "to" node + */ +static latch_t ** +re_gen_latches(to, index, num, l_table, d_latch) +node_t *to; +int index, num; +st_table *l_table; /* reference table of latches */ +lib_gate_t *d_latch; +{ + int i; + char *dummy; + latch_t **latches; + node_t *temp, *po, *pi, *end, *actual_to; + + if (num == 0) return NIL(latch_t *); + + actual_to = node_get_fanin(to, index); + end = network_latch_end(actual_to); + + assert(actual_to->type == PRIMARY_INPUT && end != NIL(node_t)); + + latches = ALLOC(latch_t *, num); + for (i = num, pi = actual_to ; i-- > 0; ){ + latches[i] = latch_from_node(pi); + /* + * This latch has been traversed -- + * delete it from the set of latches that we need to traverse + */ + (void)st_delete(l_table, (char **)(latches+i), &dummy); + + po = network_latch_end(pi); + if (d_latch != NIL(lib_gate_t)){ + /* A buffer exists -- traverse it as well */ + temp = node_get_fanin(po, 0); + pi = node_get_fanin(temp, 0); + } else { + pi = node_get_fanin(po ,0); + } + } + return latches; +} + +#undef is_feedback_latch + +#endif /* SIS */ diff --git a/sis/retime/re_simplx.c b/sis/retime/re_simplx.c new file mode 100644 index 0000000..35f5eb4 --- /dev/null +++ b/sis/retime/re_simplx.c @@ -0,0 +1,248 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_simplx.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#ifdef SIS +#include "sis.h" + +/* + * This file contains all the routines to carry out the simplex + * procedure described in "Numerical Recipes in C"... + * pages 329-343 + * The relevant files -- simp1.c, simp2.c, simp3.c and simplx.c -- + * have been merged in this file.... The routines simp[123] have + * been made static and simplx has been renamed to re_simplx to + * avoid possible conflicts. Also re_simplx returns a status + * (1 if error and the error_string() is appended to) + * + * Also added the utility routines ivector and free_ivector. + * The routine nrerror has been replaced by a sis interface + * The routine nrerror has been replaced by a sis interface + */ + +static int * +ivector(nl, nh) +int nl, nh; +{ + int *v; + v = ALLOC(int, nh-nl+1); + return v-nl; +} + +/* ARGSUSED */ +static void +free_ivector(v, nl, nh) +int *v, nl, nh; +{ + free ((char *) (v+nl)); +} + +static void +simp1(a,mm,ll,nll,iabf,kp,bmax) +double **a,*bmax; +int mm,ll[],nll,iabf,*kp; +{ + int k; + double test; + + *kp=ll[1]; + *bmax=a[mm+1][*kp+1]; + for (k=2;k<=nll;k++) { + if (iabf == 0) + test=a[mm+1][ll[k]+1]-(*bmax); + else + test=fabs(a[mm+1][ll[k]+1])-fabs(*bmax); + if (test > 0.0) { + *bmax=a[mm+1][ll[k]+1]; + *kp=ll[k]; + } + } +} + +#define EPS 1.0e-6 + +static void +simp2(a,n,l2,nl2,ip,kp,q1) +int n,l2[],nl2,*ip,kp; +double **a,*q1; +{ + int k,ii,i; + double qp,q0,q; + + *ip=0; + for (i=1;i<=nl2;i++) { + if (a[l2[i]+1][kp+1] < -EPS) { + *q1 = -a[l2[i]+1][1]/a[l2[i]+1][kp+1]; + *ip=l2[i]; + for (i=i+1;i<=nl2;i++) { + ii=l2[i]; + if (a[ii+1][kp+1] < -EPS) { + q = -a[ii+1][1]/a[ii+1][kp+1]; + if (q < *q1) { + *ip=ii; + *q1=q; + } else if (q == *q1) { + for (k=1;k<=n;k++) { + qp = -a[*ip+1][k+1]/a[*ip+1][kp+1]; + q0 = -a[ii+1][k+1]/a[ii+1][kp+1]; + if (q0 != qp) break; + } + if (q0 < qp) *ip=ii; + } + } + } + } + } +} + +static void +simp3(a,i1,k1,ip,kp) +int i1,k1,ip,kp; +double **a; +{ + int kk,ii; + double piv; + + piv=1.0/a[ip+1][kp+1]; + for (ii=1;ii<=i1+1;ii++) + if (ii-1 != ip) { + a[ii][kp+1] *= piv; + for (kk=1;kk<=k1+1;kk++) + if (kk-1 != kp) + a[ii][kk] -= a[ip+1][kk]*a[ii][kp+1]; + } + for (kk=1;kk<=k1+1;kk++) + if (kk-1 != kp) a[ip+1][kk] *= -piv; + a[ip+1][kp+1]=piv; +} + + +#define FREEALL free_ivector(l3,1,m);free_ivector(l2,1,m);\ + free_ivector(l1,1,n+1); + +/* + * The call to re_simplx solves the following + * + * MAX z = a[0][1].x1 + a[0][2].x2+ ... + a[0][N].xN + * s.t + * x1 >= 0, ...., xN >= 0 + * and also M = m1+m2+m3 constraints of the type + * + */ +int +re_simplx(a,m,n,m1,m2,m3,icase,izrov,iposv) +int m,n,m1,m2,m3,*icase,izrov[],iposv[]; +double **a; +{ + int i,ip,ir,is,k,kh,kp,m12,nl1,nl2; + int *l1,*l2,*l3; + double q1,bmax; + + if (m != (m1+m2+m3)) { + error_append("Bad input constraint counts in SIMPLX\n"); + return 1; + } + l1=ivector(1,n+1); + l2=ivector(1,m); + l3=ivector(1,m); + nl1=n; + for (k=1;k<=n;k++) l1[k]=izrov[k]=k; + nl2=m; + for (i=1;i<=m;i++) { + if (a[i+1][1] < 0.0) { + error_append("Bad input tableau in SIMPLX\n"); + return 1; + } + l2[i]=i; + iposv[i]=n+i; + } + for (i=1;i<=m2;i++) l3[i]=1; + ir=0; + if (m2+m3) { + ir=1; + for (k=1;k<=(n+1);k++) { + q1=0.0; + for (i=m1+1;i<=m;i++) q1 += a[i+1][k]; + a[m+2][k] = -q1; + } + do { + simp1(a,m+1,l1,nl1,0,&kp,&bmax); + if (bmax <= EPS && a[m+2][1] < -EPS) { + *icase = -1; + FREEALL return 0; + } else if (bmax <= EPS && a[m+2][1] <= EPS) { + m12=m1+m2+1; + if (m12 <= m) { + for (ip=m12;ip<=m;ip++) { + if (iposv[ip] == (ip+n)) { + simp1(a,ip,l1, + nl1,1,&kp,&bmax); + if (bmax > 0.0) + goto one; + } + } + } + ir=0; + --m12; + if (m1+1 <= m12) + for (i=m1+1;i<=m12;i++) + if (l3[i-m1] == 1) + for (k=1;k<=n+1;k++) + a[i+1][k] = -a[i+1][k]; + break; + } + simp2(a,n,l2,nl2,&ip,kp,&q1); + if (ip == 0) { + *icase = -1; + FREEALL return 0; + } +one: simp3(a,m+1,n,ip,kp); + if (iposv[ip] >= (n+m1+m2+1)) { + for (k=1;k<=nl1;k++) + if (l1[k] == kp) break; + --nl1; + for (is=k;is<=nl1;is++) l1[is]=l1[is+1]; + a[m+2][kp+1] += 1.0; + for (i=1;i<=m+2;i++) a[i][kp+1] = -a[i][kp+1]; + } else { + if (iposv[ip] >= (n+m1+1)) { + kh=iposv[ip]-m1-n; + if (l3[kh]) { + l3[kh]=0; + a[m+2][kp+1] += 1.0; + for (i=1;i<=m+2;i++) + a[i][kp+1] = -a[i][kp+1]; + } + } + } + is=izrov[kp]; + izrov[kp]=iposv[ip]; + iposv[ip]=is; + } while (ir); + } + for (;;) { + simp1(a,0,l1,nl1,0,&kp,&bmax); + if (bmax <= 0.0) { + *icase=0; + FREEALL return 0; + } + simp2(a,n,l2,nl2,&ip,kp,&q1); + if (ip == 0) { + *icase=1; + FREEALL return 0; + } + simp3(a,m,n,ip,kp); + is=izrov[kp]; + izrov[kp]=iposv[ip]; + iposv[ip]=is; + } +} + +#undef EPS +#undef FREEALL +#endif /* SIS */ diff --git a/sis/retime/re_util.c b/sis/retime/re_util.c new file mode 100644 index 0000000..8b00440 --- /dev/null +++ b/sis/retime/re_util.c @@ -0,0 +1,623 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/re_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +static int re_graph_dfs_recur(); +static int retime_node_num_fanout(); +static double retime_get_gate_load(); +static double retime_get_user_constraint(); + +/* + * For the node in the network, add a node in the retime graph... + * Inherit the delay data as well as the default arrival times at the + * primary inputs and req times at p/o + */ +void +re_graph_add_node(graph, node, use_mapped, d_latch, node_to_id_table) +re_graph *graph; +node_t *node; +int use_mapped; +lib_gate_t *d_latch; +st_table *node_to_id_table; +{ + double load; + int node_id; + re_node *re_no; + lib_gate_t *gate; + + /* Allocation & initialization */ + re_no = retime_alloc_node(); + re_no->node = node; + node_id = re_num_nodes(graph); + array_insert_last(re_node *, graph->nodes, re_no); + re_no->id = node_id; + + (void)st_insert(node_to_id_table, (char *)node, (char *)node_id); + + /* HERE --- add the user-time data from the p/i and p/o nodes */ + if (node->type == PRIMARY_INPUT){ + re_no->type = RE_PRIMARY_INPUT; + re_no->user_time = retime_get_user_constraint(node); + re_no->final_area = re_no->final_delay = 0.0; + array_insert_last(re_node *, graph->primary_inputs, re_no); + return; + } else if (node->type == PRIMARY_OUTPUT){ + re_no->type = RE_PRIMARY_OUTPUT; + re_no->user_time = retime_get_user_constraint(node); + re_no->final_area = re_no->final_delay = 0.0; + array_insert_last(re_node *, graph->primary_outputs, re_no); + return; + } + + re_no->type = RE_INTERNAL; + re_no->user_time = RETIME_USER_NOT_SET; + + /* Special casing for constant nodes */ + if (node_num_fanin(node) == 0){ + re_no->final_area = 0.0; + re_no->final_delay = 0.0; + } + + if (use_mapped){ + /* + * Get the gate from the node + * Fill in the field for the node + */ + gate = lib_gate_of(node); + + re_no->final_area = lib_gate_area(gate); + load = retime_get_gate_load(node, d_latch); + re_no->final_delay = retime_simulate_gate(gate, load); + + } else { + /* + * Put the area as the number of literals, + * delay according to the unit fanout model + */ + re_no->final_area = node_num_literal(node); + re_no->final_delay = 1.0 + 0.2 * retime_node_num_fanout(node); + } + +} + +/* + * gets the load driven by the node.. we only consider the actual nodes + * being driven since the latches may be replaced or moved by retiming + */ +static double +retime_get_gate_load(node, d_latch) +node_t *node; +lib_gate_t *d_latch; +{ + int pin; + lsGen gen; + node_t *fo, *end; + double load, po_load; + delay_pin_t *pin_delay; + + load = 0.0; + foreach_fanout_pin(node, gen, fo, pin){ + end = retime_network_latch_end(fo, d_latch); + if (end == NIL(node_t)){ + if (node_type(fo) == INTERNAL){ + assert(lib_gate_of(fo) != NIL(lib_gate_t)); + pin_delay = (delay_pin_t *)lib_get_pin_delay(fo, pin); + load += pin_delay->load; + } else { + /* Primary output node -- add its load if specified */ + if (delay_get_po_load(fo, &po_load)) load += po_load; + } + } else { + /* the fanout is a latch --- Recursively compute its load */ + load += retime_get_gate_load(end, d_latch); + } + } + return load; +} + +/* + * Recursively computes the number of fanouts of a node. + * Traverses latches to find the true number of fanouts + */ +static int +retime_node_num_fanout(node) +node_t *node; +{ + int count; + lsGen gen; + node_t *fo, *end; + + count = 0; + foreach_fanout(node, gen, fo){ + if ((end = retime_network_latch_end(fo, NIL(lib_gate_t))) == NIL(node_t)){ + /* the fanout is not the input of a latch */ + count++; + } else { + /* Recursively use the end of the latch to compute fanouts */ + count += retime_node_num_fanout(end); + } + } + return count; +} + + +int +retime_get_dff_info(network, area_r, delay_r, type) +network_t *network; +double *area_r, *delay_r; +latch_synch_t type; +{ + double d; + lib_gate_t *d_latch; + delay_pin_t *pin_delay; + + if (lib_network_is_mapped(network)){ + d_latch = lib_choose_smallest_latch(lib_get_library(), "f=a;", type); + if (d_latch == NIL(lib_gate_t)){ + error_append("Appropriate D-FF not in the library\n"); + return 1; + } + *area_r = lib_gate_area(d_latch); + pin_delay = (delay_pin_t *)(d_latch->delay_info[0]); + d = retime_simulate_gate(d_latch, pin_delay->load); + if (d > 0) *delay_r = d; + } + return 0; +} + +double +retime_simulate_gate(gate, load) +lib_gate_t *gate; +double load; +{ + int i, j, n; + delay_time_t t, **a_t; + double max_time, delay; + + n = lib_gate_num_in(gate); + a_t = ALLOC(delay_time_t *, n); + for (i = 0; i < n; i++){ + a_t[i] = ALLOC(delay_time_t, 1); + } + + delay = NEG_LARGE; + + for (i = 0; i < n; i++){ + for (j = 0; j < n; j++){ + a_t[j]->rise = a_t[j]->fall = NEG_LARGE; + } + a_t[i]->rise = a_t[i]->fall = 0.0; + + t = delay_map_simulate(n, a_t, gate->delay_info, load); + max_time = MAX(t.rise , t.fall); + delay = MAX(max_time, delay); + } + for (i = 0; i < n; i++){ + FREE(a_t[i]); + } + FREE(a_t); + + return delay; +} + + +/* + * In some cases the edges may be generated twice. So, take care to see if an + * edge with the same properties exists. If so, then do nothing... + */ +re_edge * +re_graph_add_edge(graph, from, to, weight, breadth, index, node_to_id_table) +re_graph *graph; +node_t *from, *to; +int weight; +double breadth; +int index; +st_table *node_to_id_table; +{ + re_edge *edge; + re_node *from_node, *to_node; + int i, from_index, to_index; + + assert(st_lookup_int(node_to_id_table, (char *)from, &from_index)); + assert(st_lookup_int(node_to_id_table, (char *)to, &to_index)); + from_node = re_get_node(graph, from_index); + to_node = re_get_node(graph, to_index); + + re_foreach_fanout(from_node, i, edge){ + if (edge->sink == to_node && edge->weight == weight && + edge->sink_fanin_id == index){ + /* Edge with specified characteristics present --- do nothing */ + return edge; + } + } + /* No edge present with same characteristics --- go on and create one */ + edge = re_create_edge(graph, from_node, to_node, index, weight, breadth); + + return edge; +} + +array_t * +re_graph_dfs(graph) +re_graph *graph; +{ + int i; + re_node *p; + st_table *visited; + array_t *node_vec; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + node_vec = array_alloc(re_node *, 0); + + re_foreach_primary_output(graph, i, p) { + if (! re_graph_dfs_recur(p, node_vec, visited, 1, INFINITY, 0)) { + fail("re_graph_dfs_recur: graph contains a zero weight cycle\n"); + } + } + + st_free_table(visited); + return node_vec; +} + +array_t * +re_graph_dfs_from_input(graph) +re_graph *graph; +{ + int i; + re_node *p; + st_table *visited; + array_t *node_vec; + + visited = st_init_table(st_ptrcmp, st_ptrhash); + node_vec = array_alloc(re_node *, 0); + + re_foreach_primary_input(graph, i, p) { + if (! re_graph_dfs_recur(p, node_vec, visited, 0, INFINITY, 0)) { + fail("re_graph_dfs_recur: graph contains a 0 weight cycle\n"); + } + } + + st_free_table(visited); + return node_vec; +} + +static int +re_graph_dfs_recur(node, node_vec, visited, dir, level, weight) +re_node *node; +array_t *node_vec; +st_table *visited; +int dir; /* 1 == visit inputs, 0 == visit outputs */ +int level; +int weight; /* Number of latches on current path */ +{ + int i, j; + char *value; + re_node *re_no; + re_edge *fanin, *fanout; + + if (level > 0) { + + if (st_lookup(visited, (char *) node, &value)) { + /* if value of the node i== weight, then a + zero weight cycle */ + return (int)value != weight; + + } else { + /* add this node to the active path */ + value = (char *) weight; + (void) st_insert(visited, (char *) node, value); + + /* avoid recursion if level-1 wouldn't add anything anyways */ + if (level > 1) { + if (dir) { + re_foreach_fanin(node, i, fanin) { + if (re_ignore_edge(fanin)) continue; + re_no = fanin->source; + if (! re_graph_dfs_recur(re_no, node_vec, + visited, dir, level-1, weight+fanin->weight)) { + return 0; + } + } + } else { + re_foreach_fanout(node, j, fanout) { + if (re_ignore_edge(fanout)) continue; + re_no = fanout->sink; + if (! re_graph_dfs_recur(re_no, node_vec, + visited, dir, level-1, weight+fanout->weight)) { + return 0; + } + } + } + } + + /* take this node off of the active path */ + value = (char *) (-1); + (void) st_insert(visited, (char *) node, value); + + /* add node to list */ + array_insert_last(re_node *, node_vec, node); + } + } + return 1; +} + + +re_node * +retime_alloc_node() +{ + re_node *re_no; + + re_no = ALLOC(re_node, 1); + re_no->fanins = array_alloc(re_edge *, 0); + re_no->fanouts = array_alloc(re_edge *, 0); + re_no->scaled_delay = RETIME_NOT_SET; + re_no->scaled_user_time = 0; + + return (re_no); +} + + +int +re_retime_node(node, r) +re_node *node; +int r; +{ + int i; + re_edge *edge; + + if (node->type == RE_INTERNAL){ + re_foreach_fanin(node, i, edge){ + if (!re_ignore_edge(edge)){ + edge->weight += r; + } + } + re_foreach_fanout(node, i, edge){ + if (!re_ignore_edge(edge)){ + edge->weight -= r; + } + } + return 0; + } else{ + return 1; + } +} + +int +retime_check_graph(graph) +re_graph *graph; +{ + int i, j; + re_node *node; + re_edge *edge; + + re_foreach_node(graph, i, node){ + if (node->type == RE_PRIMARY_INPUT){ + if (re_num_fanins(node) != 0){ + error_append("E: PI with non-zero fanins detected\n"); + return 0; + } + } + if (node->type == RE_PRIMARY_OUTPUT){ + if (re_num_fanouts(node) != 0){ + /* Added edges may be added to model register sharing */ + re_foreach_fanout(node, j, edge){ + if (re_ignore_edge(edge)) continue; + error_append("E: PO with non-zero fanouts detected\n"); + return 0; + } + } + } + } + + re_foreach_edge(graph, i, edge){ + if (re_ignore_edge(edge)) continue; + if (edge->weight < 0){ + error_append("E: edge with negative weights encountered\n"); + return 0; + } + } + return 1; +} + +/* + * Retimes a single node by an amount "lag" + */ +void +retime_single_node(node, lag) +re_node *node; +int lag; +{ + int i; + re_edge *edge; + + if (lag == 0) return; + re_foreach_fanout(node, i, edge){ + if (re_ignore_edge(edge)) continue; + edge->weight -= lag; + if (edge->latches != NIL(latch_t *)){ + FREE(edge->latches); + edge->latches = NIL(latch_t *); + } + } + re_foreach_fanin(node, i, edge){ + if (re_ignore_edge(edge)) continue; + edge->weight += lag; + if (edge->latches != NIL(latch_t *)){ + FREE(edge->latches); + edge->latches = NIL(latch_t *); + } + } +} + +void +retime_dump_graph(fp, graph) +FILE *fp; +re_graph *graph; +{ + int i, j; + re_node *re_no; + re_edge *re_ed; + + (void)fprintf(fp,"Inputs --\n\t"); + re_foreach_primary_input(graph, i, re_no){ + (void) fprintf(fp, "%s ", node_name(re_no->node)); + } + (void)fprintf(fp,"\nOutputs --\n\t"); + re_foreach_primary_output(graph, i, re_no){ + (void) fprintf(fp, "%s ", node_name(re_no->node)); + } + (void)fprintf(fp,"\n\nFanin(weight) --> Node -->Fanouts(weight)\n\n"); + re_foreach_node(graph, i, re_no){ + if (re_no->type != RE_PRIMARY_INPUT){ + re_foreach_fanin(re_no, j, re_ed){ + (void)fprintf(fp, "%s(%d) ",node_name(re_ed->source->node), + re_ed->weight); + } + (void) fprintf(fp," --> %s --> ", node_name(re_no->node)); + re_foreach_fanout(re_no, j, re_ed){ + (void)fprintf(fp, "%s(%d) ",node_name(re_ed->sink->node), + re_ed->weight); + } + (void)fprintf(sisout,"\n\t Delay: %-5.2f , Area: %-5.0f\n", + re_no->final_delay, re_no->final_area); + } + } +} +/* + * Get the user specified constraint for the PI/PO node + */ +static double +retime_get_user_constraint(node) +node_t *node; +{ + int flag; + delay_time_t t; + clock_edge_t edge; + double constraint = RETIME_USER_NOT_SET; + + if (node->type == INTERNAL) return constraint; + + if (delay_get_synch_edge(node, &edge, &flag)){ + if(node->type == PRIMARY_INPUT && delay_get_pi_arrival_time(node, &t)){ + /* Take the latest arrival time */ + if (flag == BEFORE_CLOCK_EDGE){ + constraint = -1.0 * MIN(t.rise, t.fall); + } else { + constraint = MAX(t.rise, t.fall); + } + } else if (node->type == PRIMARY_OUTPUT && + delay_get_po_required_time(node, &t)){ + /* Take the earliest required time */ + if (flag == BEFORE_CLOCK_EDGE){ + constraint = -1.0 * MAX(t.rise, t.fall); + } else { + constraint = MIN(t.rise, t.fall); + } + } else { + /* Normally should not happen -- consider it unsynchronized */ + } + } else { + /* Not synchronized --- Assume no constraint on the signal */ + } + + return constraint; +} + +/* + * Determine if the network is fit to be retimed -- If so get the type and the + * control information + */ +int +retime_get_clock_data(network, use_mapped, found_unknown_type, + should_init, old_type, delay_r, area_r) +network_t *network; +int use_mapped; +int *found_unknown_type; +int *should_init; /* Should initialize or not */ +latch_synch_t *old_type; +double *delay_r, *area_r; +{ + lsGen gen; + latch_t *latch; + node_t *control, *prev_control; + latch_synch_t type; + int is_first = TRUE; + int all_twos; + + *found_unknown_type = FALSE; + prev_control = NIL(node_t); + *old_type = UNKNOWN; + all_twos = TRUE; /* All latches have init_val (2)DONT_CARE or (3)UNSET */ + foreach_latch(network, gen, latch){ + type = latch_get_type(latch); + if (type == RISING_EDGE || type == FALLING_EDGE || type == UNKNOWN){ + if (type != UNKNOWN){ + if (is_first){ + *old_type = type; + is_first = FALSE; + } else if (type != *old_type) { + error_append("ERROR: Synchronization types of clocked latches differ\n"); + (void)lsFinish(gen); + return 1; + } + control = latch_get_control(latch); + if (prev_control == NIL(node_t)){ + prev_control = control; + } else if (prev_control != control) { + error_append("ERROR: Latches not clocked by same signal\n"); + (void)lsFinish(gen); + return 1; + } + } else { + *found_unknown_type = TRUE; + } + all_twos = (all_twos && (latch_get_initial_value(latch) >= 2)); + } else { + error_append("Retiming not supported for TRANSPARENT latches\n"); + (void)lsFinish(gen); + return 1; + } + } + /* If all the latch values are twos do not compute initial states */ + if (all_twos) *should_init = 0; + + /* + * Now that we know that the structure is OK -- also find the area + * and delay thru a latch if it a mapped network + */ + if (use_mapped){ + /* get the area and delay corresponding to the D-FlopFlop */ + return (retime_get_dff_info(network, area_r, delay_r, *old_type)); + } else { + return 0; + } +} + +/* + * For convenience a single routine is provided to check if the + * retiming is possible or not + */ +int +retime_is_network_retimable(network) +network_t *network; +{ + int flag; + int a, b; /* Dummy variable for storing initialization data */ + latch_synch_t type; /* Dummy variable for storing latch type */ + double d, e; /* Dummy variable for storing latch data */ + + flag = retime_get_clock_data(network, lib_network_is_mapped(network), + &a, &b, &type, &d, &e); + + return (1-flag); +} + +#endif /* SIS */ diff --git a/sis/retime/retime.doc b/sis/retime/retime.doc new file mode 100644 index 0000000..fb86815 --- /dev/null +++ b/sis/retime/retime.doc @@ -0,0 +1,356 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/retime.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +int +retime_is_network_retimable(network) +network_t *network; + This routine performs some checks on the network and returns a value + of 1 if the network satisfies the constraints of a retimable circuit + (single-phase, edge-triggered circuit). The exported routines and + data-structured make strict assumptions about the network structure + (single-phase, edge-triggered) and so before calling the other routines + the user should call this routine and check the return value.... + +re_graph * +retime_network_to_graph(network, size, use_mapped) +network *network; +int size; +int use_mapped; + Build the retiming graph from the network. The nodes of the + retiming graph correspond to the nodes in the network and the + weights on the edges are the number of latches between the nodes. + The parameter "size" is provided for clustreing but this is not + yet used. If the flag "use_mapped" is used the routine will + generate some additional information to allow it to reconstruct + the mapped network after retiming (see the routine + retime_graph_to_network() below) + + +int +retime_graph_interface(graph, area_r, delay_r, retime_tol, d_clk, new_c) +re_graph *graph; +double area_r, delay_r; +double retime_tol, d_clk, *new_c; + Routine that encapsulates the retiming procedures for the user + that wants to use the retiming algorithm on a graph. This routine + is able to handle graphs with negative weights and uses the + Lieserson's MILP procedure for retiming. No initial states are + computed. This is due to the fact that negative edge weights are + allowed. + + +int +retime_graph(network, graph, area_r, delay_r, retime_tol, + d_clk, new_c, lp_flag, min_reg, should_init, can_init) +network_t *network; /* The network that corrsponds to this graph */ +re_graph *graph; /* graph to be retimed */ +double area_r; /* default area cost for a standard register */ +double delay_r; /* default delay cost for a standard register */ +double retime_tol; /* Tolerance for the binary search */ +double d_clk; /* Desired clock cycle */ +double *new_c; /* The clock cycle after retiming */ +int lp_flag; /* == 1 => Use MILP otherwise Saxe's relaxation */ +int min_reg; /* == 1 => minimize num registers, overrides lp_flag */ +int should_init; /* == 1 => compute_initial_ state + == 2 => compute initial states at all costs */ +int *can_int; /* RETURN: == 1 => could do the initialization */ + + Retime the sequential network specified by `graph' . Returns a value + 1 if latches were moved and 0 if there is no retiming possible. + In the retimed graph, the weight values of the edges w(e) will be + modified to reflect the retimed network. + + If the "network" paprameter is not NIL(network_t) and the parameter + "should_init == 1" then the new initial states will be computed for + the retimed graph. If such a computation is feasible then the + flag "can_nit" is set to 1, otherwise it is set to 0. If the flag + "should_init" is set then the user must provide the network, nodes + for which correspond to the retime graph. + + The `area_r' parameter specifies the area of each register. + The `delay_r' parameter specifies the delay cost of each register. + Delay cost for a register can be thought of as an estimate for its + setup and hold times. + + The "retime_tol" is the tolerance for the binary search and the "d_clk" + specifies the cycle time that the user wants to achieve. The retuned + calue "new_c" refers to the best cycle-time that can be achieved. + This may or may not meet the user desired cycle-time "d_clk". + + The user has the option of specifying one of three methods for + retiming. These are governed by the flags lp_flag and min_reg + min_reg lp_flag Algorithm used + -------------------------------------- + 1 anything MInimize number of registers (uses Simplex) + 0 1 UseLieserson's MILP formulation + 0 0 Use Saxe's relaxation algorithm + + +network_t +retime_graph_to_network(graph, use_mapped) +re_graph *graph; +int use_mapped; + This routine will generate a Boolean network from the specified + graph. The flag "use_mapped" when set to 1 will result in the + routine accessing the nodes in the original network so as to + preserve the mapping of the circuit. + + +/* Memory management functions */ + +re_graph * +re_graph_alloc() + Allocate a new graph. Initialize the array fields to zero + elements. + +void +re_graph_free(graph) +re_graph *graph; + Free a graph. + +re_graph * +re_graph_dup(graph) +re_graph *graph; + Make a duplicate copy of a graph. + +re_edge * +re_create_edge(graph, source, sink, index, weight, breadth) +re_graph *graph; +re_node *source; +re_node *sink; +int index; +int weight; +double breadth; + Allocate a new edge. The source and sink nodes are assumed + to have been created. The new edge is created and inserted + into the graph data structure, the list of fanins of the sink + node, and the list of fanouts of the source node. THe connection + is mode to the "index" fanin of if the sink node. The id fields + of the edge structure are properly assigned. The weight + field is assigned the value `weight'. The breadth of the edge is + the cost of putting a latch on it (may exceed 1 if it represents + a bus). + + +/* Counting functions */ + +int +re_num_nodes(graph) +re_graph *graph; + Return the number of nodes in the graph. + +int +re_num_edges(graph) +re_graph *graph; + Return the number of edges in the graph. + +int +re_num_primary_inputs(graph) +re_graph *graph; + Return the number of primary input nodes in the graph. + +int +re_num_primary_outputs(graph) +re_graph *graph; + Return the number of primary output nodes in the graph. + +int +re_num_internals(graph) +re_graph *graph; + Return the number of internal nodes in the graph. + Number of internal nodes is equal to the total number + of nodes in the graph minus the primary input nodes + and the primary output nodes. + +int +re_num_fanins(node) +re_node *node; + Return the number of fanin edges to node. + +int +re_num_fanouts(node) +re_node *node; + Return the number of fanout edges from node. + + +/* Random access functions */ + +re_node * +re_get_node(graph, index) +re_graph *graph; +int index; + Return the index'th node of the graph. The nodes are numbered + starting from 0. Returns NIL(re_node) if index >= re_num_nodes(graph). + Access should be very quick. + +re_edge * +re_get_edge(graph, index) +re_graph *graph; +int index; + Return the index'th edge of the graph. The edges are numbered + starting from 0. Returns NIL(re_edge) if index >= re_num_edges(graph). + Access should be very quick. + +re_node * +re_get_primary_input(graph, index) +re_graph *graph; +int index; + Return the index'th primary input of the graph. The primary + inputs are numbered starting from 0. Returns NIL(re_node) + if index >= re_num_primary_inputs(graph). + Access should be very quick. + +re_node * +re_get_primary_output(graph, index) +re_graph *graph; +int index; + Return the index'th primary output of the graph. The primary + outputs are numbered starting from 0. Returns NIL(re_node) + if index >= re_num_primary_outputs(graph). + +re_edge * +re_get_fanin(node, index) +re_node *node; +int index; + Return the index'th fanin edge of the node. The fanin + edges are numbered starting from 0. Returns NIL(re_edge) + if index >= re_num_fanins(node). + +re_edge * +re_get_fanout(node, index) +re_node *node; +int index; + Return the index'th fanout edge of the node. The fanout + edges are numbered starting from 0. Returns NIL(re_edge) + if index >= re_num_fanouts(node). + + +/* Generators */ + +re_foreach_node(graph, index, node) +re_graph *graph; +int index; +re_node *node; + Generate over all nodes in the graph (that is, including + primary inputs and primary outputs). + +re_foreach_edge(graph, index, edge) +re_graph *graph; +int index; +re_edge *edge; + Generate over all edges in the graph. + +re_foreach_primary_input(graph, index, node) +re_graph *graph; +int index; +re_node *node; + Generate over all primary inputs of a graph. + +re_foreach_primary_output(graph, index, node) +re_graph *graph; +int index; +re_node *node; + Generate over all primary outputs of a graph. + +re_foreach_fanin(node, index, edge) +re_node *node +int index; +re_edge *edge; + Generate over all the fanin edges to node. + +re_foreach_fanout(node, index, edge) +re_node *node +int index; +re_edge *edge; + Generate over all the fanout edges from node. + + + + The generators are macro's. Typical usage is: + + re_foreach_node(graph, index, node) { + /* do something with node */ + } + + The generator is implemented using the array package. + +int +re_ignore_edge(edge) +re_edge *edge; + If the edge is marked as being deleted it is not removed from + the graph but just marked as deleted. This routine can be + used to query for such edges. During traversal these edges + should not be followed. + +int +re_ignore_node(node) +re_node *node; + If the node is marked as being deleted (of type RE_IGNORE) + this routine can be used to query for such nodes. During + traversal these nodes should not be visited since some fields + may be out of date. + + +/* Exportable retiming functions */ + +int +re_min_fanin_weight(node) +re_node *node; + Return the minimum weight from the fanin edges. + +int +re_min_fanout_weight(node) +re_node *node; + Return the minimum weight from the fanout edges. + +int +re_max_fanin_weight(node) +re_node *node; + Return the maximum weight from the fanin edges. + +int +re_max_fanout_weight(node) +re_node *node; + Return the maximum weight from the fanout edges. + +int +re_sum_of_edge_weight(graph) +re_graph *graph; + Return the sum of weights from the edges in the graph. + +int +re_effective_sum_edge_weight(graph) +re_graph *graph; + Return the effective sum of weights from the edges in the graph. + Effective meaning that only the `maximum' weight from the + fanout edges of the given node will be counted in the total + weight. This is useful to model `register sharing'. + +double +re_sum_node_area(graph) +re_graph *graph; + Return the sum of area of the nodes. + +double +re_total_area(graph, area_r) +re_graph *graph; +double area_r; + Return the sum of area including both area contributed by the + nodes and area contributed by the registers. This area calculation + uses the register sharing model. The parameter `area_r' specifies + the area cost of a standard register. + +double +re_cycle_delay(graph, delay_r) +re_graph *graph; +double delay_r; + Return the critical delay of the graph. The parameter `delay_r' + specifies the delay cost of a standard register. Delay cost is + usually an estimated sum of the setup and hold time. + diff --git a/sis/retime/retime.h b/sis/retime/retime.h new file mode 100644 index 0000000..2d4a5d9 --- /dev/null +++ b/sis/retime/retime.h @@ -0,0 +1,164 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/retime.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#ifndef RETIME_H +#define RETIME_H + +/* + * retime.h - retiming package header file + */ + +typedef enum re_node_type re_node_type; +enum re_node_type { + RE_PRIMARY_INPUT, RE_PRIMARY_OUTPUT, RE_INTERNAL, RE_IGNORE + }; + +typedef struct re_graph re_graph; +struct re_graph { + array_t *nodes; /* nodes in network (typed re_node *) */ + array_t *edges; /* edges in network (typed re_edge *) */ + array_t *primary_inputs; /* primary inputs (typed re_node *) */ + array_t *primary_outputs; /* primary outputs (typed re_node *) */ + enum latch_synch_enum s_type; /* Synchronization type of design */ + char *control_name; /* Name of the controlling signal */ + }; + +typedef struct re_node re_node; +struct re_node { + int id; /* reference id for direct access */ + re_node_type type; /* type of node */ + int lp_index; /* Index of variable in lp formulation */ + node_t *node; /* pointer to the corresponding mis node */ + array_t *fanins; /* fanin edges of node (typed re_edge *) */ + array_t *fanouts; /* fanout edges of node (typed re_edge *) */ + int scaled_delay; /* integral value of delay -- scaled */ + double final_area; /* area target for final implementation */ + double final_delay; /* delay target for final implementation */ + double user_time; /* Constraint on inputs and outputs wrt clock */ + int scaled_user_time; /* Integral value of specification -- scaled */ + }; + +typedef struct re_edge re_edge; +struct re_edge { + int id; /* reference id for direct access */ + struct re_node *source; /* source node (typed re_node *) */ + struct re_node *sink; /* sink node (typed re_node *) */ + int sink_fanin_id; /* the fanin id of the sink node */ + int weight; /* edge weight w(e) ie. number of registers */ + double breadth; /* Cost of adding a register along the edge */ + double temp_breadth; /* Modified breadth to account for reg shar */ + struct latch_struct **latches; /* Initial correspondence wrt latches */ + int num_val_alloc; /* Number of value entries allocated */ + int *initial_values; /* Initial values on the latches */ + }; + +/* To associate the latches in the network with the retime graph --- + * The latch_id gives the edge and position (on that edge) of a latch + */ +typedef struct re_latch_id re_latch_id_t; +struct re_latch_t { + struct latch_struct *latch; /* Reference to the latch in the network */ + int value; /* initial value generated by the init_states */ + }; + +/* graph traversal macros' */ +#define re_num_nodes(graph) array_n(graph->nodes) +#define re_num_edges(graph) array_n(graph->edges) +#define re_num_primary_inputs(graph) array_n(graph->primary_inputs) +#define re_num_primary_outputs(graph) array_n(graph->primary_outputs) +#define re_num_fanins(node) array_n(node->fanins) +#define re_num_fanouts(node) array_n(node->fanouts) + +#define re_host_vertex(node) \ + ((node)->type == RE_PRIMARY_INPUT || (node)->type == RE_PRIMARY_OUTPUT) +#define re_ignore_node(node) (node->type == RE_IGNORE) +#define re_ignore_edge(edge) \ + ((edge)->source->type == RE_IGNORE || (edge)->sink->type == RE_IGNORE) + +#define re_num_internals(graph) \ + (array_n(graph->nodes) - \ + (array_n(graph->primary_inputs) + array_n(graph->primary_outputs))) + +#define re_foreach_node(graph, index, p) \ + for (index=0; \ + index<array_n(graph->nodes) && \ + ((p=array_fetch(re_node *, graph->nodes, index)) || !p); \ + index++) + +#define re_foreach_edge(graph, index, p) \ + for (index=0; \ + index<array_n(graph->edges) && \ + ((p=array_fetch(re_edge *, graph->edges, index)) || !p); \ + index++) + +#define re_foreach_primary_input(graph, index, p) \ + for (index=0; \ + index<array_n(graph->primary_inputs) && \ + ((p=array_fetch(re_node *, graph->primary_inputs, index)) || \ + !p); \ + index++) + +#define re_foreach_primary_output(graph, index, p) \ + for (index=0; \ + index<array_n(graph->primary_outputs) && \ + ((p=array_fetch(re_node *, graph->primary_outputs, index)) || \ + !p); \ + index++) + +#define re_foreach_fanin(node, index, p) \ + for (index=0; \ + index<array_n(node->fanins) && \ + ((p=array_fetch(re_edge *, node->fanins, index)) || !p); \ + index++) + +#define re_foreach_fanout(node, index, p) \ + for (index=0; \ + index<array_n(node->fanouts) && \ + ((p=array_fetch(re_edge *, node->fanouts, index)) || !p); \ + index++) + +/* export functions */ +EXTERN int retime_is_network_retimable ARGS((network_t *)); +EXTERN re_graph *retime_network_to_graph ARGS((network_t *, int, int)); +EXTERN int retime_graph + ARGS((network_t *, re_graph *, double, double, double, double, double *, + int, int, int, int *)); +EXTERN int retime_graph_interface + ARGS((re_graph *, double, double, double, double, double *)); +EXTERN network_t *retime_graph_to_network ARGS((re_graph *, int)); + +EXTERN void re_graph_free ARGS((re_graph *)); +EXTERN re_graph *re_graph_dup ARGS((re_graph *)); +EXTERN re_graph *re_graph_alloc ARGS((void)); + +EXTERN re_node *re_get_node ARGS((re_graph *, int)); +EXTERN re_edge *re_get_edge ARGS((re_graph *, int)); +EXTERN re_node *re_get_primary_input ARGS((re_graph *, int)); +EXTERN re_node *re_get_primary_output ARGS((re_graph *, int)); +EXTERN re_edge *re_get_fanin ARGS((re_node *, int)); +EXTERN re_edge *re_get_fanout ARGS((re_node *, int)); + +EXTERN re_edge *re_create_edge + ARGS((re_graph *, re_node *, re_node *, int, int, double)); + +EXTERN int re_min_fanin_weight ARGS((re_node *)); +EXTERN int re_min_fanout_weight ARGS((re_node *)); +EXTERN int re_max_fanin_weight ARGS((re_node *)); +EXTERN int re_max_fanout_weight ARGS((re_node *)); +EXTERN int re_sum_of_edge_weight ARGS((re_graph *)); +EXTERN int re_effective_sum_edge_weight ARGS((re_graph *)); +EXTERN double re_sum_node_area ARGS((re_graph *)); +EXTERN double re_total_area ARGS((re_graph *, double)); +EXTERN double re_cycle_delay ARGS((re_graph *, double)); + +EXTERN int re_node_retimable ARGS((re_node *)); +EXTERN int re_node_forward_retimable ARGS((re_node *)); +EXTERN int re_node_backward_retimable ARGS((re_node *)); + +#endif diff --git a/sis/retime/retime_int.h b/sis/retime/retime_int.h new file mode 100644 index 0000000..3e3b295 --- /dev/null +++ b/sis/retime/retime_int.h @@ -0,0 +1,65 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/retime_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#include "retime.h" + +#define RETIME_SLOT undef1 +#define RETIME(node) ((int) node->RETIME_SLOT) + +#define re_empty_network(n) ((network_num_po(n)+network_num_pi(n)) == 0) + +typedef struct class_data re_class_t; +struct class_data{ + array_t *gates; /* Array of type (lib_gate_t *) */ + array_t *delay; /* Array of type double */ + }; + +typedef struct wd_struct wd_t; +struct wd_struct{ + int w; + int d; +}; + +/* Global variables */ +extern int retime_debug; + +/* Extern function declarations */ +extern void re_computeWD(); +extern void retime_dump_graph(); +extern void retime_single_node(); +extern void re_graph_add_node(); +extern void re_evaluate_delay(); +extern int re_simplx(); +extern int retime_check_graph(); +extern int retime_min_register(); /* re_minreg.c */ +extern int retime_nanni_routine(); /* re_nanni.c */ +extern int retime_lies_routine(); /* re_milp.c */ +extern int retime_update_init_states(); +extern int retime_get_dff_info(); +extern int retime_get_clock_data(); +extern node_t *retime_network_latch_end(); /* utility */ +extern double retime_simulate_gate(); +extern double retime_cycle_lower_bound(); +extern array_t *re_graph_dfs(); +extern array_t *re_graph_dfs_from_input(); +extern re_node *retime_alloc_node(); +extern re_edge *re_graph_add_edge(); + +#define RETIME_DEFAULT_REG_AREA 1.0 /* Area of a latch */ +#define RETIME_DEFAULT_REG_DELAY 0.0 /* Delay through a latch */ +#define MAX_LATCH_TO_INITIALIZE 16 /* No of latches acceptable to extract STG */ + +#define RETIME_NOT_SET -1 +#define RETIME_USER_NOT_SET -100000.0 +#define RETIME_TEST_NOT_SET -50000.0 /* Half of the USER_NOT_SET value */ + +#define RETIME_DEF_TOL 0.1 /* Tolerence of the binary search */ + +#define POS_LARGE 10000 +#define NEG_LARGE -10000 diff --git a/sis/retime/retime_util.c b/sis/retime/retime_util.c new file mode 100644 index 0000000..61abb3a --- /dev/null +++ b/sis/retime/retime_util.c @@ -0,0 +1,291 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/retime/retime_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "retime_int.h" + +re_node *re_node_dup(); +re_edge *re_edge_dup(); + +re_graph * +re_graph_alloc() +{ + re_graph *new_graph; + + new_graph = ALLOC(re_graph, 1); + new_graph->nodes = array_alloc(re_node *, 0); + new_graph->edges = array_alloc(re_edge *, 0); + new_graph->primary_inputs = array_alloc(re_node *, 0); + new_graph->primary_outputs = array_alloc(re_node *, 0); + new_graph->control_name = NIL(char); + new_graph->s_type = UNKNOWN; + + return new_graph; +} + +void +re_graph_free(graph) +re_graph *graph; +{ + int i; + re_node *node; + re_edge *edge; + + for (i = re_num_edges(graph); i-- > 0; ) { + edge = array_fetch(re_edge *, graph->edges, i); + FREE(edge->latches); + FREE(edge->initial_values); + FREE(edge); + } + + for (i = re_num_nodes(graph); i-- > 0; ) { + node = array_fetch(re_node *, graph->nodes, i); + (void) array_free(node->fanins); + (void) array_free(node->fanouts); + FREE(node); + } + + (void) array_free(graph->nodes); + (void) array_free(graph->edges); + (void) array_free(graph->primary_inputs); + (void) array_free(graph->primary_outputs); + if (graph->control_name != NIL(char)) FREE(graph->control_name); + + FREE(graph); +} + +re_graph * +re_graph_dup(graph) +re_graph *graph; +{ + int i, j; + re_graph *new_graph; + re_node *node, *new_node; + re_edge *edge, *new_edge; + st_table *edge_ref_table, *node_ref_table; + + new_graph = re_graph_alloc(); + edge_ref_table = st_init_table(st_numcmp, st_numhash); + node_ref_table = st_init_table(st_numcmp, st_numhash); + + /* copy nodes */ + re_foreach_node(graph, i, node){ + if (re_ignore_node(node)) continue; + + new_node = re_node_dup(node); + new_node->id = re_num_nodes(new_graph); + + if (new_node->type == RE_PRIMARY_INPUT) + (void)array_insert_last(re_node *, new_graph->primary_inputs, + new_node); + else if (new_node->type == RE_PRIMARY_OUTPUT) + (void)array_insert_last(re_node *, new_graph->primary_outputs, + new_node); + + (void) array_insert_last(re_node *, new_graph->nodes, new_node); + (void)st_insert(node_ref_table, (char *)node->id, (char *)new_node); + } + + /* copy edges */ + re_foreach_edge(graph, i, edge){ + /* Ignore this edge if it connects to a RE_IGNORE node */ + if (re_ignore_edge(edge)) continue; + new_edge = re_edge_dup(edge); + new_edge->id = re_num_edges(new_graph); + (void) array_insert(re_edge *, new_graph->edges, i, new_edge); + (void)st_insert(edge_ref_table, (char *)edge->id, (char *)new_edge); + } + + /* cross link fanins and fanouts */ + re_foreach_node(graph, i, node){ + if (re_ignore_node(node)) continue; + assert(st_lookup(node_ref_table, (char *)node->id, (char **)&new_node)); + re_foreach_fanin(node, j, edge){ + if (re_ignore_edge(edge)) continue; + assert(st_lookup(edge_ref_table, (char *)edge->id, (char **)&new_edge)); + (void) array_insert_last(re_edge *, new_node->fanins, new_edge); + } + + re_foreach_fanout(node, j, edge){ + if (re_ignore_edge(edge)) continue; + assert(st_lookup(edge_ref_table, (char *)edge->id, (char **)&new_edge)); + (void) array_insert_last(re_edge *, new_node->fanouts, new_edge); + } + } + + /* cross link sink and source */ + re_foreach_edge(graph, i, edge){ + /* Ignore this edge if it connects to a RE_IGNORE node */ + if (re_ignore_edge(edge)) continue; + assert(st_lookup(edge_ref_table, (char *)edge->id, (char **)&new_edge)); + + assert(st_lookup(node_ref_table, (char *)edge->sink->id, (char **)&new_node)); + new_edge->sink = new_node; + + assert(st_lookup(node_ref_table, (char *)edge->source->id, (char **)&new_node)); + new_edge->source = new_node; + } + + new_graph->s_type = graph->s_type; + if (graph->control_name != NIL(char)){ + new_graph->control_name = util_strsav(graph->control_name); + } + st_free_table(edge_ref_table); + st_free_table(node_ref_table); + return new_graph; +} + +re_node * +re_get_node(graph, index) +re_graph *graph; +int index; +{ + if (index >= re_num_nodes(graph)) + return NIL(re_node); + + return array_fetch(re_node *, graph->nodes, index); +} + +re_edge * +re_get_edge(graph, index) +re_graph *graph; +int index; +{ + if (index >= re_num_edges(graph)) + return NIL(re_edge); + + return array_fetch(re_edge *, graph->edges, index); +} + +re_node * +re_get_primary_input(graph, index) +re_graph *graph; +int index; +{ + if (index >= re_num_primary_inputs(graph)) + return NIL(re_node); + + return array_fetch(re_node *, graph->primary_inputs, index); +} + +re_node * +re_get_primary_output(graph, index) +re_graph *graph; +int index; +{ + if (index >= re_num_primary_outputs(graph)) + return NIL(re_node); + + return array_fetch(re_node *, graph->primary_outputs, index); +} + +re_edge * +re_get_fanin(node, index) +re_node *node; +int index; +{ + if (index >= re_num_fanins(node)) + return NIL(re_edge); + + return array_fetch(re_edge *, node->fanins, index); +} + +re_edge * +re_get_fanout(node, index) +re_node *node; +int index; +{ + if (index >= re_num_fanouts(node)) + return NIL(re_edge); + + return array_fetch(re_edge *, node->fanouts, index); +} + +re_edge * +re_create_edge(graph, source, sink, index, weight, breadth) +re_graph *graph; +re_node *source, *sink; +int index; /* The fanin index of the "sink" node */ +int weight; +double breadth; +{ + re_edge *new_edge; + + /* create the edge next */ + new_edge = ALLOC(re_edge, 1); + new_edge->id = re_num_edges(graph); + new_edge->weight = weight; + new_edge->breadth = breadth; + new_edge->temp_breadth = breadth; + new_edge->source = source; + new_edge->sink = sink; + new_edge->sink_fanin_id = index; + new_edge->num_val_alloc = 0; + new_edge->initial_values = NIL(int); + new_edge->latches = NIL(latch_t *); + (void) array_insert_last(re_edge *, graph->edges, new_edge); + (void) array_insert_last(re_edge *, source->fanouts, new_edge); + (void) array_insert_last(re_edge *, sink->fanins, new_edge); + + return new_edge; +} + +re_edge * +re_edge_dup(edge) +re_edge *edge; +{ + int i; + re_edge *new_edge; + + new_edge = ALLOC(re_edge, 1); + new_edge->sink_fanin_id = edge->sink_fanin_id; + new_edge->weight = edge->weight; + new_edge->breadth = edge->breadth; + new_edge->temp_breadth = edge->breadth; + + new_edge->num_val_alloc = edge->num_val_alloc; + if (edge->num_val_alloc > 0 && edge->initial_values != NIL(int)){ + new_edge->initial_values = ALLOC(int, new_edge->num_val_alloc); + for (i = edge->weight; i-- > 0; ){ + (new_edge->initial_values)[i] = (edge->initial_values)[i]; + } + } else { + new_edge->initial_values = NIL(int); + } + if (edge->latches != NIL(latch_t *)){ + new_edge->latches = ALLOC(latch_t *, new_edge->weight); + for (i = edge->weight; i-- > 0; ){ + (new_edge->latches)[i] = (edge->latches)[i]; + } + } else new_edge->latches = NIL(latch_t *); + + return new_edge; +} + +re_node * +re_node_dup(node) +re_node *node; +{ + re_node *new_node; + + new_node = ALLOC(re_node, 1); + new_node->node = node->node; + new_node->fanins = array_alloc(re_edge *, 0); + new_node->fanouts = array_alloc(re_edge *, 0); + new_node->type = node->type; + new_node->final_area = node->final_area; + new_node->final_delay = node->final_delay; + new_node->user_time = node->user_time; + new_node->scaled_delay = RETIME_NOT_SET; + new_node->scaled_user_time = 0; + + return new_node; +} +#endif /* SIS */ diff --git a/sis/seqbdd/Makefile.am b/sis/seqbdd/Makefile.am new file mode 100644 index 0000000..fead405 --- /dev/null +++ b/sis/seqbdd/Makefile.am @@ -0,0 +1,9 @@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libseqbdd.a +libseqbdd_a_SOURCES = bull.c bull_util.c com_verify.c consistency.c \ + manual_order.c network_info.c ordering.c prioqueue.c prioqueue.h \ + prl_dep.c prl_equiv.c prl_extract.c prl_ordering.c prl_product.c \ + prl_remlatch.c prl_seqbdd.h prl_seqinfo.c prl_util.c prl_util.h \ + product.c seqbdd_cycle.c verif_util.c +pkginclude_HEADERS = seqbdd.h diff --git a/sis/seqbdd/Makefile.in b/sis/seqbdd/Makefile.in new file mode 100644 index 0000000..d2cf76e --- /dev/null +++ b/sis/seqbdd/Makefile.in @@ -0,0 +1,407 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +SOURCES = $(libseqbdd_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/seqbdd +DIST_COMMON = $(pkginclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libseqbdd_a_AR = $(AR) $(ARFLAGS) +libseqbdd_a_LIBADD = +am_libseqbdd_a_OBJECTS = bull.$(OBJEXT) bull_util.$(OBJEXT) \ + com_verify.$(OBJEXT) consistency.$(OBJEXT) \ + manual_order.$(OBJEXT) network_info.$(OBJEXT) \ + ordering.$(OBJEXT) prioqueue.$(OBJEXT) prl_dep.$(OBJEXT) \ + prl_equiv.$(OBJEXT) prl_extract.$(OBJEXT) \ + prl_ordering.$(OBJEXT) prl_product.$(OBJEXT) \ + prl_remlatch.$(OBJEXT) prl_seqinfo.$(OBJEXT) \ + prl_util.$(OBJEXT) product.$(OBJEXT) seqbdd_cycle.$(OBJEXT) \ + verif_util.$(OBJEXT) +libseqbdd_a_OBJECTS = $(am_libseqbdd_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libseqbdd_a_SOURCES) +DIST_SOURCES = $(libseqbdd_a_SOURCES) +am__installdirs = "$(DESTDIR)$(pkgincludedir)" +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libseqbdd.a +libseqbdd_a_SOURCES = bull.c bull_util.c com_verify.c consistency.c \ + manual_order.c network_info.c ordering.c prioqueue.c prioqueue.h \ + prl_dep.c prl_equiv.c prl_extract.c prl_ordering.c prl_product.c \ + prl_remlatch.c prl_seqbdd.h prl_seqinfo.c prl_util.c prl_util.h \ + product.c seqbdd_cycle.c verif_util.c + +pkginclude_HEADERS = seqbdd.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/seqbdd/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/seqbdd/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libseqbdd.a: $(libseqbdd_a_OBJECTS) $(libseqbdd_a_DEPENDENCIES) + -rm -f libseqbdd.a + $(libseqbdd_a_AR) libseqbdd.a $(libseqbdd_a_OBJECTS) $(libseqbdd_a_LIBADD) + $(RANLIB) libseqbdd.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-pkgincludeHEADERS \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/seqbdd/bull.c b/sis/seqbdd/bull.c new file mode 100644 index 0000000..ff43d6c --- /dev/null +++ b/sis/seqbdd/bull.c @@ -0,0 +1,550 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/bull.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ +#ifdef SIS +#include "sis.h" + +static bdd_t *bull_cache_lookup(); +static int bull_key_cmp(); +static int bull_manual_cmp(); +static st_table *bull_cache_create(); +static int bull_key_hash(); +static void bull_cache_free(); +static void bull_cache_insert(); + + +st_table *gcache; + +range_data_t *bull_alloc_range_data(network, options) +network_t *network; +verif_options_t *options; +{ + bdd_t *bdd; + array_t *pi_list; + array_t *po_ordering; + node_t *n1, *n2; + int i, id, count; + char *dummy; + lsGen gen; + array_t *remaining_po; + output_info_t *info = options->output_info; + range_data_t *data = ALLOC(range_data_t, 1); + + data->type = BULL_METHOD; + gcache = bull_cache_create(); + + po_ordering = info->po_ordering; + info->pi_ordering = st_init_table(st_ptrcmp, st_ptrhash); + pi_list = order_nodes(po_ordering, 2); + count= array_n(pi_list); + info->pi_ordering= from_array_to_table(pi_list); + array_free(pi_list); + + remaining_po = get_remaining_po(network, po_ordering); + pi_list = order_nodes(remaining_po, 1); + array_free(remaining_po); + for (i = 0; i< array_n(pi_list); i++){ + n1 = array_fetch(node_t *, pi_list, i); + if(!st_is_member(info->pi_ordering, (char *) n1)){ + st_insert(info->pi_ordering, (char *) n1, (char *) count); + count++; + } + } + array_free(pi_list); + + + foreach_primary_input(network, gen, n1) { + if(!st_is_member(info->pi_ordering, (char *) n1)){ + st_insert(info->pi_ordering, (char *) n1, (char *) count); + count++; + } + } + + data->manager = ntbdd_start_manager(st_count(info->pi_ordering)); + + for (i = array_n(po_ordering) - 1; i >= 0; i--) { + n1 = array_fetch(node_t *, po_ordering, i); + (void) ntbdd_node_to_bdd(n1, data->manager, info->pi_ordering); + } + + /* create BDD for external output_fns and init_state_fn */ + /* in case of simple range computation, output_node may be NIL(node_t) */ + data->init_state_fn = ntbdd_node_to_bdd(info->init_node, data->manager, info->pi_ordering); + if (options->does_verification) { + data->external_outputs= array_alloc(bdd_t *, 0); + for (i = 0; i < array_n(info->xnor_nodes); i++) { + n1 = array_fetch(node_t *, info->xnor_nodes, i); + bdd = ntbdd_node_to_bdd(n1, data->manager, info->pi_ordering); + array_insert_last(bdd_t *, data->external_outputs, bdd); + } + }else{ + data->external_outputs= NIL (array_t); + } + + data->pi_inputs = array_alloc(bdd_t *, array_n(po_ordering)); + for (i =0 ; i< array_n(po_ordering) ; i++) { + n1 = array_fetch(node_t *,po_ordering,i); + n2= network_latch_end(n1); + assert(n2 != NIL(node_t)); + assert(st_lookup(info->pi_ordering, (char *)n2, (char **) &dummy)); + id= (int) dummy; + bdd = bdd_get_variable(data->manager, id); + array_insert_last(bdd_t *, data->pi_inputs , bdd); + } + if (options->verbose >= 3) print_node_table(info->pi_ordering); + + return data; +} + +void bull_free_range_data(data, options) +range_data_t *data; +verif_options_t *options; +{ + output_info_t *info = options->output_info; + + ntbdd_free_at_node(info->init_node); + st_free_table(info->pi_ordering); + /* Set the pi_ordering st_table to NIL so that output_info_free + doesn't core dump */ + info->pi_ordering = NIL(st_table); + bull_cache_free(gcache); + ntbdd_end_manager(data->manager); + array_free(data->pi_inputs); + FREE(data); +} + + +bdd_t *bull_compute_next_states(current_set, data, options) +bdd_t *current_set; +range_data_t *data; +verif_options_t *options; +{ + int i; + array_t *bdd_list; + node_t *n1; + bdd_t *f1, *fc; + bdd_t *new_current_set; + array_t *pi_list; + bdd_t *total_set; + st_table *cache; + output_info_t *info = options->output_info; + + bdd_list = array_alloc(bdd_t *,0); + for (i =0 ; i< array_n(info->po_ordering) ; i++) { + n1 = array_fetch(node_t *, info->po_ordering, i); + f1 = ntbdd_at_node(n1); + fc = bdd_cofactor(f1, current_set); + array_insert_last(bdd_t *,bdd_list,fc); + } + pi_list = array_alloc(bdd_t *,0); + for (i =0 ; i< array_n(data->pi_inputs) ; i++) { + f1 = array_fetch(bdd_t *, data->pi_inputs, i); + array_insert_last(bdd_t *, pi_list, f1); + } + if (options->does_verification) + total_set= NIL(bdd_t); + else + total_set= bdd_dup(data->total_set); + cache= gcache; + new_current_set= bull_cofactor(bdd_list, pi_list, data->manager, total_set, cache, info->pi_ordering, options); + return(new_current_set); +} + +bdd_t *bull_compute_reverse_image(next_set, data, options) +bdd_t *next_set; +range_data_t *data; +verif_options_t *options; +{ + return NIL(bdd_t); +} + + /* returns 1 iff everything is OK */ +int bull_check_output(current_set, data, output_index, options) +bdd_t *current_set; +range_data_t *data; +int *output_index; +verif_options_t *options; +{ + int i; + bdd_t *bdd; + + for (i = 0; i < array_n(data->external_outputs); i++) { + bdd = array_fetch(bdd_t *, data->external_outputs, i); + if (! bdd_leq(current_set, bdd, 1, 1)) { + report_inconsistency(current_set, bdd, options->output_info->pi_ordering); + if (output_index != NIL(int)) { + *output_index = i; + } + return 0; + } + } + return 1; +} + +void bull_bdd_sizes(data, fn_size, output_size) +range_data_t *data; +int *fn_size; +int *output_size; +{ + int i; + bdd_t *fn; + node_t *node; + bdd_t *output; + + if (fn_size) { + *fn_size = 0; + for (i = 0; i < array_n(data->output_fns); i++) { + node = array_fetch(node_t *, data->output_fns, i); + fn = ntbdd_at_node(node); + *fn_size += bdd_size(fn); + } + } + if (output_size) { + *output_size = 0; + if (data->external_outputs == NIL (array_t)) + return; + for (i = 0; i < array_n(data->external_outputs); i++) { + output = array_fetch(bdd_t *, data->external_outputs, i); + *output_size += bdd_size(output); + } + } +} + +bdd_t *bull_cofactor(bdd_list, pi_list, mg, total_set, cache, leaves, options) +array_t *bdd_list; +array_t *pi_list; +bdd_manager *mg; +bdd_t *total_set; +st_table *cache; +st_table *leaves; +verif_options_t *options; +{ + bdd_t *bdd; + bdd_t *c, *cbar, *left_bdd, *right_bdd; + bdd_t *new_bdd, *f1; + array_t *sup_list; + array_t *left_list, *right_list; + array_t *left_pi, *right_pi; + int flag, active; + array_t *f_list; + var_set_t *set; + var_set_t *andset, *nset; + bdd_t *tmpbdd; + int i, j, l, count, andcount; + bdd_t *rtotal_set, *ltotal_set; + array_t *oldlist; + + count= 0; + active = 0; + flag = -1; + + if (!options->does_verification) { + if (bdd_is_tautology(total_set,1)){ + bdd_free(total_set); + bdd = array_fetch(bdd_t *,bdd_list,0); + f1 = array_fetch(bdd_t *,pi_list,0); + if (bdd_is_tautology(bdd, 1)){ + tmpbdd= bdd_dup(f1); + }else{ + tmpbdd= bdd_not(f1); + } + for (i= 0 ; i< array_n(bdd_list); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + if (bdd != NIL(bdd_t)) + bdd_free(bdd); + } + array_free(bdd_list); + array_free(pi_list); + return(tmpbdd); + } + } + new_bdd= bdd_one(mg); + oldlist = array_alloc(bdd_t *, array_n(bdd_list)); + if ((array_n(bdd_list) > 3) ){ + if ((bdd = bull_cache_lookup(cache, bdd_list, pi_list, mg ,leaves)) != NIL (bdd_t)) { + return bdd; + } + } + for (i= 0 ; i< array_n(bdd_list); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + array_insert(bdd_t *, oldlist, i, bdd); + if (bdd == NIL(bdd_t)) + continue; + if (bdd_is_tautology(bdd, 1)){ + array_insert(bdd_t *, bdd_list, i, NIL (bdd_t)); + f1= array_fetch(bdd_t *, pi_list, i); + c= bdd_and(f1, new_bdd, 1, 1); + bdd_free(new_bdd); + new_bdd= c; + continue; + } + if (bdd_is_tautology(bdd, 0)){ + array_insert(bdd_t *, bdd_list, i, NIL (bdd_t)); + f1= array_fetch(bdd_t *, pi_list, i); + c= bdd_and(f1, new_bdd, 0, 1); + bdd_free(new_bdd); + new_bdd= c; + continue; + } + count++; + } + if (count <= 1){ + for (i= 0 ; i< array_n(oldlist); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + if (bdd != NIL(bdd_t)) + bdd_free(bdd); + } + array_free(bdd_list); + array_free(oldlist); + array_free(pi_list); + if (!options->does_verification) + bdd_free(total_set); + return(new_bdd); + } + sup_list = array_alloc(var_set_t *, count); + andset = var_set_new(bdd_num_vars(mg)); + andset = var_set_not(andset, andset); + for (i= 0 ; i< array_n(bdd_list); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + if (bdd == NIL(bdd_t)) + continue; + set= bdd_get_support(bdd); + nset= var_set_copy(set); + nset= var_set_and(nset, set, andset); + var_set_free(andset); + andset=nset; + array_insert_last(var_set_t *, sup_list, set); + } + f_list= disjoint_support_functions(sup_list); + for (i= 0 ; i< array_n(sup_list); i++){ + set = array_fetch(var_set_t *,sup_list,i); + var_set_free(set); + } + array_free(sup_list); + andcount= var_set_n_elts(andset); + + if ((andcount) && (andcount < (count/4)) ){ + j= 0; + tmpbdd = input_cofactor(bdd_list, pi_list, mg, total_set, cache, leaves, options, andset, j); + }else{ + tmpbdd= bdd_one(mg); + for (i= 0 ; i< array_n(f_list); i++){ + set = array_fetch(var_set_t *,f_list,i); + if ((active= var_set_n_elts(set)) == 1) + continue; + if(active==2){ + bdd= range_2_compute(set, bdd_list, pi_list); + f1 = bdd_and(bdd, tmpbdd, 1, 1); + bdd_free(bdd); + bdd_free(tmpbdd); + tmpbdd= f1; + continue; + } + flag = -1; + right_list = array_alloc(bdd_t *, 0); + left_list = array_alloc(bdd_t *, 0); + right_pi = array_alloc(bdd_t *, 0); + left_pi = array_alloc(bdd_t *, 0); + for (j= 0, l=0; j< array_n(bdd_list) ; j++){ + bdd = array_fetch(bdd_t *,bdd_list,j); + if (bdd == NIL(bdd_t)){ + continue; + } + if(var_set_get_elt(set,l)){ + f1= array_fetch(bdd_t *, pi_list, j); + array_insert_last(bdd_t *, right_pi, f1); + array_insert_last(bdd_t *, left_pi, f1); + if(flag == -1){ + flag = j; + c = bdd; + cbar= bdd_not(c); + array_insert_last(bdd_t *, right_list, bdd_one(mg)); + array_insert_last(bdd_t *, left_list, bdd_zero(mg)); + if (!options->does_verification){ + rtotal_set= bdd_cofactor(total_set, f1); + ltotal_set= bdd_cofactor(total_set, bdd_not(f1)); + } + }else{ + array_insert_last(bdd_t *, right_list, bdd_cofactor(bdd,c)); + array_insert_last(bdd_t *, left_list, bdd_cofactor(bdd,cbar)); + } + } + l++; + } + bdd_free(cbar); + right_bdd= bull_cofactor(right_list, right_pi, mg, rtotal_set, cache, leaves,options); + left_bdd= bull_cofactor(left_list, left_pi, mg, ltotal_set, cache,leaves,options); + + bdd = bdd_or(right_bdd, left_bdd, 1, 1); + bdd_free(right_bdd); + bdd_free(left_bdd); + f1 = bdd_and(bdd, tmpbdd, 1, 1); + bdd_free(bdd); + bdd_free(tmpbdd); + tmpbdd= f1; + } + } + + for (i= 0 ; i< array_n(f_list); i++){ + set = array_fetch(var_set_t *,f_list,i); + var_set_free(set); + } + array_free(f_list); + + c= bdd_and(new_bdd, tmpbdd, 1, 1); + bdd_free(new_bdd); + bdd_free(tmpbdd); + if ((array_n(oldlist) > 3) ){ + bull_cache_insert(cache, oldlist, c, pi_list); + }else{ + for (i= 0 ; i< array_n(oldlist); i++){ + bdd = array_fetch(bdd_t *,oldlist,i); + if (bdd != NIL(bdd_t)) + bdd_free(bdd); + } + array_free(pi_list); + array_free(oldlist); + } + var_set_free(andset); + array_free(bdd_list); + if (!options->does_verification) + bdd_free(total_set); + return(c); +} + +static bdd_t *bull_cache_lookup(cache, bdd_list, pi_list, manager , leaves) +st_table *cache; +array_t *bdd_list; +array_t *pi_list; +bdd_manager *manager; +st_table *leaves; +{ + int i; + bull_key_t key; + bull_value_t *value; + bdd_t *result, *new_result; + bdd_t *f0, *f1, *inv; + bdd_t *var_bar; + bdd_t *c1; + + key.fns = bdd_list; + if (! st_lookup(cache, (char *) &key, (char **) &value)) return NIL(bdd_t); + result = bdd_substitute(value->range, value->ins, pi_list); + for (i=0 ; i < array_n(bdd_list) ; i++){ + f0 = array_fetch(bdd_t *, value->fns, i); + f1 = array_fetch(bdd_t *, bdd_list, i); + c1 = array_fetch(bdd_t *, pi_list, i); + if (bdd_equal(f0, f1)) + continue; + inv = bdd_not(f1); + bdd_free(inv); + var_bar = bdd_not(c1); + new_result= bdd_compose(result, c1, var_bar); + bdd_free(result); + result= new_result; + bdd_free(var_bar); + } + return result; +} + +/* duplicate everything so that can free everything upon exit without trouble */ + /* I wish we had a C garbage collector!!! */ +static void bull_cache_insert(cache, bdd_list, range, pi_list) +st_table *cache; +array_t *bdd_list; +bdd_t *range; +array_t *pi_list; +{ + bull_key_t *key = ALLOC(bull_key_t, 1); + bull_value_t *value = ALLOC(bull_value_t, 1); + + value->ins = pi_list; + key->fns = bdd_list; + value->fns = key->fns; + value->range = bdd_dup(range); + st_insert(cache, (char *) key, (char *) value); +} + +static st_table *bull_cache_create() +{ + st_table *cache = st_init_table(bull_key_cmp, bull_key_hash); + return cache; +} + + /* do not free value->fns: it is a pointer to key->fns */ +static void bull_cache_free(cache) +st_table *cache; +{ + int i; + bdd_t *f; + st_generator *gen; + bull_key_t *key; + bull_value_t *value; + + st_foreach_item(cache, gen, (char **) &key, (char **) &value) { + for (i = 0; i < array_n(key->fns); i++) { + f = array_fetch(bdd_t *, key->fns, i); + if (f != NIL(bdd_t)) + bdd_free(f); + } + array_free(key->fns); + array_free(value->ins); + FREE(key); + bdd_free(value->range); + FREE(value); + } + st_free_table(cache); +} + + /* should be 0 if match */ +static int bull_key_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + int i; + bdd_t *f1, *f2, *inv; + array_t *array1 = ((bull_key_t *) obj1)->fns; + array_t *array2 = ((bull_key_t *) obj2)->fns; + + if (array_n(array1) != array_n(array2)) + return 1; + for (i = 0; i < array_n(array1); i++) { + f1 = array_fetch(bdd_t *, array1, i); + f2 = array_fetch(bdd_t *, array2, i); + if (f1 == f2) continue; + if (! bdd_equal(f1, f2)) { + inv = bdd_not(f1); + if (! bdd_equal(inv, f2)) { + bdd_free(inv); + return 1; + } + bdd_free(inv); + } + } + return 0; +} + +static int bull_key_hash(obj, modulus) +char *obj; +int modulus; +{ + int i; + bdd_t *fn; + array_t *array = ((bull_key_t *) obj)->fns; + register unsigned int result = 0; + + for (i = 0; i < array_n(array); i++) { + fn = array_fetch(bdd_t *, array, i); + if (fn == NIL(bdd_t)) continue; + result <<= 1; + result += (int) bdd_top_var_id(fn); + } + return result % modulus; +} +#endif /* SIS */ diff --git a/sis/seqbdd/bull_util.c b/sis/seqbdd/bull_util.c new file mode 100644 index 0000000..99bc340 --- /dev/null +++ b/sis/seqbdd/bull_util.c @@ -0,0 +1,189 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/bull_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + /* file bull1.c release 1.1 */ + /* last modified: 8/21/90 at 17:02:17 */ +#ifdef SIS +#include "sis.h" + +bdd_t *input_cofactor(bdd_list,pi_list,mg,total_set,cache,leaves,options,andset,pt) +array_t *bdd_list; +array_t *pi_list; +bdd_manager *mg; +bdd_t *total_set; +st_table *cache; +st_table *leaves; +verif_options_t *options; +var_set_t *andset; +int pt; +{ + array_t *right_list, *left_list, *right_pi, *left_pi; + int i,j; + bdd_t *c, *cbar, *f1, *rtotal_set, *ltotal_set; + bdd_t *bdd, *left_bdd, *right_bdd; + bdd_t *tmpbdd; + + for (j= pt ; j< andset->n_elts; j++){ + if (var_set_get_elt(andset,j)){ + c= bdd_get_variable(mg,j); + right_list = array_alloc(bdd_t *, 0); + left_list = array_alloc(bdd_t *, 0); + right_pi = array_alloc(bdd_t *, 0); + left_pi = array_alloc(bdd_t *, 0); + cbar= bdd_not(c); + for (i= 0 ; i< array_n(bdd_list); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + if (bdd == NIL(bdd_t)) + continue; + array_insert_last(bdd_t *, right_list, bdd_cofactor(bdd,c)); + array_insert_last(bdd_t *, left_list, bdd_cofactor(bdd,cbar)); + f1= array_fetch(bdd_t *, pi_list, i); + array_insert_last(bdd_t *, right_pi,f1); + array_insert_last(bdd_t *, left_pi,f1); + } + bdd_free(cbar); + bdd_free(c); + if (!options->does_verification){ + rtotal_set= bdd_dup(total_set); + ltotal_set= bdd_dup(total_set); + } + right_bdd= input_cofactor(right_list, right_pi, mg, rtotal_set, cache,leaves,options,andset,j+1); + left_bdd= input_cofactor(left_list, left_pi, mg, ltotal_set, cache,leaves,options,andset,j+1); + tmpbdd= bdd_or(right_bdd, left_bdd, 1, 1); + bdd_free(right_bdd); + bdd_free(left_bdd); + if (pt > 0){ + for (i= 0 ; i< array_n(bdd_list); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + if (bdd != NIL(bdd_t)) + bdd_free(bdd); + } + array_free(bdd_list); + array_free(pi_list); + if (!options->does_verification) + bdd_free(total_set); + } + return(tmpbdd); + } + } + return(bull_cofactor(bdd_list,pi_list,mg,total_set,cache,leaves,options)); +} + +array_t *disjoint_support_functions(list) +array_t *list; +{ + int row,column; + int i,j; + int flag; + array_t *tmp; + var_set_t *set, *fset, *nset; + array_t *prtn_list; + + row= array_n(list); + tmp= array_alloc(var_set_t *, row); + for(i=0; i< row; i++){ + set= array_fetch(var_set_t *, list, i); + nset= var_set_copy(set); + array_insert(var_set_t *, tmp, i, nset); + } + set= array_fetch(var_set_t *, list, 0); + column= set->n_elts; + + for(i=0; i< column; i++){ + flag=1; + for(j=0; j< row; j++){ + set= array_fetch(var_set_t *, tmp, j); + if (set != NIL(var_set_t) ){ + if (flag){ + if (var_set_get_elt(set, i)){ + fset= set; + flag= 0; + continue; + } + } + if (var_set_get_elt(set, i)){ + fset= var_set_or(fset, fset, set); + var_set_free(set); + array_insert(var_set_t *, tmp, j, NIL(var_set_t )); + } + } + } + } + + prtn_list = array_alloc(var_set_t *, 0); + for(j=0; j< row; j++){ + set= array_fetch(var_set_t *, tmp, j); + if (set != NIL(var_set_t) ){ + nset= var_set_new(row); + for(i=0; i< row; i++){ + fset= array_fetch(var_set_t *, list, i); + if (var_set_intersect(set, fset)) + var_set_set_elt(nset, i); + } + var_set_free(set); + array_insert(var_set_t *, tmp, j, NIL(var_set_t )); + array_insert_last(var_set_t *, prtn_list, nset); + } + } + array_free(tmp); + return(prtn_list); +} + +bdd_t *range_2_compute(set, bdd_list, pi_list) +var_set_t *set; +array_t *bdd_list; +array_t *pi_list; +{ + int i,j; + int k1,k2; + bdd_t *bdd, *n1, *n2, *f1, *f2, *g, *out1, *out2, *f1_bar; + bdd_t *c1, *c2; + + k1= -1; + for(i=0,j=0; i< array_n(bdd_list); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + if(bdd == NIL(bdd_t)) + continue; + if(!var_set_get_elt(set, j++)) + continue; + if(k1 == -1){ + k1=i; + f1= bdd; + }else{ + k2=i; + f2= bdd; + break; + } + } + n1= array_fetch(bdd_t *, pi_list, k1); + n2= array_fetch(bdd_t *, pi_list, k2); + f1_bar= bdd_not(f1); + out1= bdd_cofactor(f2, f1); + out2= bdd_cofactor(f2, f1_bar); + bdd_free(f1_bar); + if (bdd_is_tautology(out1, 1)) + c1= bdd_and(n1,n2,1,1); + else if (bdd_is_tautology(out1, 0)) + c1= bdd_and(n1,n2,1,0); + else + c1= bdd_dup(n1); + if (bdd_is_tautology(out2, 1)) + c2= bdd_and(n1,n2,0,1); + else if (bdd_is_tautology(out2, 0)) + c2= bdd_and(n1,n2,0,0); + else + c2= bdd_not(n1); + g= bdd_or(c1, c2, 1, 1); + bdd_free(c1); + bdd_free(c2); + bdd_free(out1); + bdd_free(out2); + return(g); +} +#endif /* SIS */ diff --git a/sis/seqbdd/com_verify.c b/sis/seqbdd/com_verify.c new file mode 100644 index 0000000..e1e24ee --- /dev/null +++ b/sis/seqbdd/com_verify.c @@ -0,0 +1,801 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/com_verify.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + /* file %M% release %I% */ + /* last modified: %G% at %U% */ +#ifdef SIS +#include <setjmp.h> +#include <signal.h> +#include "sis.h" +#include "prl_seqbdd.h" + +static int com_extract_seq_dc(); +static int com_extract_env_seq_dc(); +static int com_verify_fsm(); +static int com_env_verify_fsm(); +static int com_remove_latches(); +static int com_latch_output(); +static int com_equiv_nets(); +static int com_remove_dependencies(); +static int com_free_dc(); + +static void seqbdd_print_usage(); +static network_t *read_optional_network(); + +static jmp_buf timeout_env; + + /* ARGSUSED */ +static void timeout_handle(x) +int x; +{ + longjmp(timeout_env, 1); +} + +/* + * int + * function(network) + * network_t **network; - value/return + */ + +static struct { + char *name; + int (*function)(); + int changes_network; +} table[] = { + { "verify_fsm", com_verify_fsm, TRUE }, + { "extract_seq_dc", com_extract_seq_dc, TRUE }, + { "env_seq_dc", com_extract_env_seq_dc, TRUE }, + { "env_verify_fsm", com_env_verify_fsm, FALSE }, + { "remove_latches", com_remove_latches, TRUE }, + { "latch_output", com_latch_output, TRUE }, + { "equiv_nets", com_equiv_nets, TRUE }, + { "remove_dep", com_remove_dependencies, TRUE }, + { "free_dc", com_free_dc, TRUE }, +}; + +/* + * init_bdd - the mis-defined bdd-package initialization + * + * return nothing (why does it return an int then?) + */ +int +init_seqbdd() +{ + int i; + int size; + + size = sizeof(table)/sizeof(table[0]); + for (i = 0; i < size; i++) { + com_add_command(table[i].name, table[i].function, table[i].changes_network); + } +#ifdef old_code + for (i=0; i< sizeof_el(table); i++) { + com_add_command(table[i].name, table[i].function, table[i].changes_network); + } +#endif +} + +end_seqbdd() +{ +} + +/* verifies the equivalence of two finite state machine using implicit + * state enumeration techniques. First the product machine is built. + * It finds all the reachable states starting from the initial state + * in the product machine and checks if the output in the product + * machine always produces 1 for any reachable state of the product + * machine. + */ + +static int +com_verify_fsm(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int status; + network_t *network1, *network2; + verif_options_t options; + + network1 = *network; + if (network1 == NIL(network_t)) { + return 1; + } + options.does_verification = 1; + if (bdd_range_fill_options(&options, &argc, &argv)) goto usage; + if (options.alloc_range_data == 0) goto usage; + if (argc - util_optind != 1) goto usage; + + argv = &argv[util_optind]; + network2 = read_optional_network("read_blif", argv[0]); + if (network2 == NIL(network_t)) { + return 1; + } + + + if (options.timeout > 0) { + (void) signal(SIGALRM, timeout_handle); + (void) alarm((unsigned int) options.timeout); + if (setjmp(timeout_env) > 0) { + fprintf(misout, "timeout occurred after %d seconds\n", options.timeout); + return 1; + } + } + status = seq_verify_interface(network1, network2, &options); + if (options.timeout > 0) (void) alarm(options.timeout); + network_free(network2); + return (options.stop_if_verify) ? (!status) : (status); + usage: + seqbdd_print_usage("verify_fsm", "network2.blif"); + return 1; +} + + +/* Starting from initial states, finds all the reachable states. + * Any state that is not reachable is a don't care because it + * is not a valid input. An external don't care network is built + * representing all the unreachable states. These are don't cares + * for every primary output in the circuit which could be a real + * primary output or output of a latch. + */ + +static void store_as_dc_network(); +static int com_extract_seq_dc(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *new_network ; + network_t *dup_net; + verif_options_t options; + + if (bdd_range_fill_options(&options, &argc, &argv)) goto usage; + if (argc - util_optind != 0) goto usage; + options.keep_old_network = 0; + options.n_iter = INFINITY; + + if ((*network) == NIL(network_t)) + return 0; + if (network_num_internal(*network) == 0) + return 0; + if (network_num_latch(*network) == 0) + return 0; + + if (options.timeout > 0) { + (void) signal(SIGALRM, timeout_handle); + (void) alarm(options.timeout); + if (setjmp(timeout_env) > 0) { + fprintf(misout, "timeout occurred after %d seconds\n", options.timeout); + return 1; + } + } + dup_net = network_dup(*network); + new_network = range_computation_interface(dup_net, &options); + /* dup_net, the "old network" used to be freed in breadth_first_traversal, + because it is no longer needed after that routine. However, the manager + was freed in options->free_range_data, which tries to access the + network. So the network is now freed here, AFTER the manager has been + freed. */ + network_free(dup_net); + if (new_network == 0) { + (void) fprintf(siserr, "%s", error_string()); + return 1; + } + Prl_StoreAsSingleOutputDcNetwork(*network, new_network); + return 0; + + usage: + seqbdd_print_usage("extract_seq_dc", ""); + return 1; +} + + +/* Generic routines to fill the option parameters + */ + +static +int bdd_range_fill_method(options, method_name) +verif_options_t *options; +char *method_name; +{ + /* Set function pointers in options depending on the method name. */ + + if (strcmp (method_name, "consistency") == 0) { + options->type = CONSISTENCY_METHOD; + options->alloc_range_data = consistency_alloc_range_data; + options->compute_next_states = consistency_compute_next_states; + options->compute_reverse_image = consistency_compute_reverse_image; + options->free_range_data = consistency_free_range_data; + options->check_output = consistency_check_output; + options->bdd_sizes = consistency_bdd_sizes; + } + else if (strcmp (method_name, "bull") == 0) { + options->type = BULL_METHOD; + options->alloc_range_data = bull_alloc_range_data; + options->compute_next_states = bull_compute_next_states; + options->compute_reverse_image = bull_compute_reverse_image; + options->free_range_data = bull_free_range_data; + options->check_output = bull_check_output; + options->bdd_sizes = bull_bdd_sizes; + } + else if (strcmp (method_name, "product") == 0) { + options->type = PRODUCT_METHOD; + options->alloc_range_data = product_alloc_range_data; + options->compute_next_states = product_compute_next_states; + options->compute_reverse_image = product_compute_reverse_image; + options->free_range_data = product_free_range_data; + options->check_output = product_check_output; + options->bdd_sizes = product_bdd_sizes; + } + else { + return 0; /* unrecognized method */ + } + return 1; +} + +int bdd_range_fill_options(options, argc_addr, argv_addr) +verif_options_t *options; +int *argc_addr; +char ***argv_addr; +{ + int c; + int argc = *argc_addr; + char **argv = *argv_addr; + char *s; + + options->timeout = 0; + options->keep_old_network = 1; + options->n_iter = 1; + options->verbose = 0; + options->use_manual_order = 0; + options->order_network = NIL(network_t); + options->last_time = util_cpu_time(); + options->total_time = 0; + options->ordering_depth = 2; + options->sim_file = NIL(char); + options->stop_if_verify = 0; + s = "product"; + bdd_range_fill_method (options,s); + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "i:m:o:O:t:v:s:V")) != EOF) { + switch(c) { + case 'i': + options->n_iter = atoi(util_optarg); + if (options->n_iter < 0 || options->n_iter > INFINITY) return 1; + break; + case 'm': + if (bdd_range_fill_method (options,util_optarg) == 0) return 1; + break; + case 'o': + options->ordering_depth = atoi(util_optarg); + break; + case 'O': + options->use_manual_order = 1; + options->order_network_name = util_strsav(util_optarg); + break; + case 't': + options->timeout = atoi(util_optarg); + if (options->timeout < 0 || options->timeout > 3600 * 24 * 365) return 1; + break; + case 'v': + options->verbose = atoi(util_optarg); + break; + case 's': + options->sim_file = util_strsav(util_optarg); + break; + case 'V': + options->stop_if_verify = 1; + break; + default: + return 1; + } + } + /* because util_optarg use global variables, + * we can't call read_optional_network within the loop + */ + if (options->use_manual_order) { + options->order_network = read_optional_network("read_eqn", options->order_network_name); + FREE(options->order_network_name); + options->order_network_name = NIL(char); + if (options->order_network == NIL(network_t)) { + return 1; + } + } + *argc_addr = argc; + *argv_addr = argv; + return 0; +} + +static void seqbdd_print_usage(name, uniq_options) +char *name; +char *uniq_options; +{ + (void) fprintf(siserr, "usage: %s [-o d] [-t s] [-v n] [-V] -m method %s\n", name, uniq_options); + (void) fprintf(siserr, " [-o d]: depth of search for good variable ordering; d == 0 greedy\n"); + (void) fprintf(siserr, " [-t s]: time out after s seconds of cpu time\n"); + (void) fprintf(siserr, " [-v n]: verbosity level\n"); + (void) fprintf(siserr, " [-V]: returns an error status if verification succeeds\n"); + (void) fprintf(siserr, " [-s filename]: save a distinguishing input vector to filename\n"); + (void) fprintf(siserr, " method is one of: "); +#define use(NAME,STRING,UPPERCASE)\ + (void) fprintf(siserr, "%s ", STRING); +use(consistency,"consistency",CONSISTENCY) +use(bull,"bull",BULL) +use(product,"product",PRODUCT) +#undef use + (void) fprintf(siserr, "\n"); +} + +static network_t *read_optional_network(command, filename) +char *command; +char *filename; +{ + int status; + char *buffer; + network_t *result; + int save_optind = util_optind; + char *save_optarg = util_optarg; + + buffer = ALLOC(char, 20 + strlen(command) + strlen(filename)); + (void) sprintf(buffer, "%s %s", command, filename); + result = network_alloc(); + status = com_execute(&result, buffer); + FREE(buffer); + if (status) { + network_free(result); + result = NIL(network_t); + } + util_optind = save_optind; + util_optarg = save_optarg; + return result; +} + + + +/* FROM NOW ON: INTERFACE CODE FOR THE PRL FILES + * IMPLEMENTS THE FOLLOWING NEW COMMANDS: + * env_seq_dc,remove_latches,latch_output,equiv_nets + */ + +static void Prl_PrintUsage ARGS((char *, char *)); +static int Prl_FillOptions ARGS((prl_options_t *, int *, char ***)); + + +/* Given another network, passed as an argument to the command, do: + * (1) connect the current network to that other network + * (2) enumerate all the states of the product networks + * (3) use the complement of resulting set of reachable states + * as external don't cares. + * This command extracts the reachability don't care set under + * an environment constraint. It is strictly more more powerful + * than 'extract_seq_dc'. + * The two networks are connected by names. An external PI (resp. PO) + * of the current network is connected to a matching external PO + * (resp. PI) of the network passed as argument. + */ + +static int com_extract_env_seq_dc(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int status; + prl_options_t options; + network_t *fsm_network, *env_network; + + if (Prl_FillOptions(&options, &argc, &argv)) goto usage; + + fsm_network = *network; + if (fsm_network == NIL(network_t)) return 0; + if (network_num_internal(fsm_network) == 0) return 0; + if (network_num_latch(fsm_network) == 0) return 0; + + if (argc - util_optind == 0) { + (void) fprintf(siserr, "Warning: no network specified as argument\n"); + env_network = NIL(network_t); + } else if (argc - util_optind == 1) { + env_network = read_optional_network("read_blif", argv[util_optind]); + if (env_network == NIL(network_t)) { + (void) fprintf(siserr, "Warning: can't read network \"%s\";", argv[util_optind]); + } + } else { + goto usage; + } + + if (env_network == NIL(network_t)) { + (void) fprintf(siserr, "\"extract_seq_dc\" is being called instead\n"); + return com_execute(network, "extract_seq_dc"); + } + + if (options.timeout > 0) { + (void) signal(SIGALRM, timeout_handle); + (void) alarm(options.timeout); + if (setjmp(timeout_env) > 0) { + fprintf(sisout, "timeout occurred after %d seconds\n", options.timeout); + return 1; + } + } + status = Prl_ExtractEnvDc(fsm_network, env_network, &options); + return status; + usage: + Prl_PrintUsage("env_seq_dc", "<network>"); + return 1; +} + + +/* + *---------------------------------------------------------------------- + * + * com_env_verify_fsm -- INTERNAL ROUTINE + * + * Verifies two FSMs under a given environment. + * If the environment is not specified, defaults to 'com_verify_fsm'. + * + *---------------------------------------------------------------------- + */ + +static int com_env_verify_fsm(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int status; + prl_options_t options; + network_t *fsm_network, *check_network, *env_network; + + if (Prl_FillOptions(&options, &argc, &argv)) goto usage; + fsm_network = *network; + if (fsm_network == NIL(network_t)) return 0; + + if (argc - util_optind != 2) goto usage; + + env_network = read_optional_network("read_blif", argv[util_optind+1]); + if (env_network == NIL(network_t)) { + (void) fprintf(siserr, "Warning: can't read network \"%s\";", argv[util_optind+1]); + (void) fprintf(siserr, " verify_fsm is being called instead\n"); + return com_verify_fsm(network, argc - 1, argv); + } + + check_network = read_optional_network("read_blif", argv[util_optind]); + if (check_network == NIL(network_t)) { + (void) fprintf(siserr, "can't read network %s\n", argv[util_optind]); + return 1; + } + + if (options.timeout > 0) { + (void) signal(SIGALRM, timeout_handle); + (void) alarm(options.timeout); + if (setjmp(timeout_env) > 0) { + fprintf(sisout, "timeout occurred after %d seconds\n", options.timeout); + return 1; + } + } + status = Prl_VerifyEnvFsm(fsm_network, check_network, env_network, &options); + network_free(check_network); + network_free(env_network); + return (options.stop_if_verify) ? (! status) : (status); + usage: + Prl_PrintUsage("env_verify_fsm", "<check network> <env network>"); + return 1; +} + + + /* 'equiv_nets' performs the following optimization: + * 1. for each net in the network, computes the BDD representing + * the Boolean function of that net in terms of PIs. + * 2. use the external don't care (e.g. reachability) + * and cofactor the BDD at each net by the EXDC. + * 3. group the nets by equivalence class, were n1 and n2 + * are equivalent iff they are always equal or always + * the negation of each other in the don't care set. + * 4. for each equivalence class, select a net of smallest depth + * and move the fanouts of all the other nets of that class + * to that net, inserting inverters whenever necessary. + * 5. sweeps the network to remove the dead logic. + */ + +static int com_equiv_nets(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + prl_options_t options; + + if (Prl_FillOptions(&options, &argc, &argv)) goto usage; + if (argc - util_optind != 0) goto usage; + + if (*network == NIL(network_t)) { + (void) fprintf(siserr, "no network specified\n"); + return 1; + } + Prl_EquivNets(*network, &options); + network_sweep(*network); + return 0; + usage: + Prl_PrintUsage("remove_latches", ""); + return 1; +} + + +/* 1. Remove latches that are functionally deducible from the others. + * Latches whose equivalent combinational logic has too many inputs + * (exceeding some threshold specified as a command line parameter) + * are not removed. + * 2. In addition, performs some local retiming by moving latches + * forward if that reduces the total latch count. + * 3. Finally, tries to remove boot latches (i.e. latches fed by a constant + * but initialized by a different constant) by looking for a state + * equivalent to the initial state in which the initial value of the latch + * is equal to the value of its constant input. + * + * The network is modified in place. + */ + +static int com_remove_latches(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + prl_options_t options; + + if (Prl_FillOptions(&options, &argc, &argv)) goto usage; + if (argc - util_optind != 0) goto usage; + + if (options.timeout > 0) { + (void) signal(SIGALRM, timeout_handle); + (void) alarm(options.timeout); + if (setjmp(timeout_env) > 0) { + fprintf(sisout, "timeout occurred after %d seconds\n", options.timeout); + return 1; + } + } + + if (*network == NIL(network_t)) { + (void) fprintf(siserr, "no network specified\n"); + return 1; + } + if (network_num_latch(*network) == 0) { + /* nothing to do */ + return 0; + } + Prl_RemoveLatches(*network, &options); + return 0; + + usage: + Prl_PrintUsage("equiv_nets", ""); + return 1; +} + + +/* 'latch_output' forces the listed external POs to be fed by a latch + * by forward retiming of latches in the transitive fanin of the PO. + * If one of the POs depends combinationally on one of the external PIs + * the routine reports an error status code. + * This function is useful out there in the real world; i.e. + * if we want to control a memory chip, 'latch_output' is a simple way to make sure + * that the write_enable signal does not glitch. + */ + +static int com_latch_output(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + array_t *node_vec; + int status = 0; + int verbosity = 0; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "v:")) != EOF) { + switch(c) { + case 'v': + verbosity = atoi(util_optarg); + break; + default: + goto usage; + } + } + node_vec = com_get_true_nodes(*network, argc-util_optind+1, argv+util_optind-1); + status = Prl_LatchOutput(*network, node_vec, verbosity); + array_free(node_vec); + return status; + usage: + (void) fprintf(siserr, "latch_output [-v verbosity_level] <node_list>\n"); + return 1; +} + +/* 'remove_dep' forces the listed external POs not to depend on the given PI. + * It is assumed that the dependency is structural, not logical. + * This fact is checked with the -p option. + */ + +static int com_remove_dependencies(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + array_t *node_vec; + prl_removedep_t options; + int status = 0; + + options.verbosity = 0; + options.perform_check = 0; + options.insert_a_one = 0; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "opv:")) != EOF) { + switch(c) { + case 'o': + options.insert_a_one = 1; + break; + case 'p': + options.perform_check = 1; + break; + case 'v': + options.verbosity = atoi(util_optarg); + break; + default: + goto usage; + } + } + node_vec = com_get_true_nodes(*network, argc-util_optind+1, argv+util_optind-1); + status = Prl_RemoveDependencies(*network, node_vec, &options); + array_free(node_vec); + return status; + usage: + (void) fprintf(siserr, "remove_dep [-o] [-v verbosity_level] <input> <output list>\n"); +/* (void) fprintf(siserr, "\t[-p] perform dependency check (not implemented)\n"); */ + (void) fprintf(siserr, "\t[-o] inserts a one instead of a zero\n"); + return 1; +} + + +/* + *---------------------------------------------------------------------- + * + * com_free_dc -- INTERNAL ROUTINE + * + * Frees the don't care network, if any. + * + *---------------------------------------------------------------------- + */ + +static int com_free_dc(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + Prl_RemoveDcNetwork(*network); + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * Prl_FillOptions -- + * + *---------------------------------------------------------------------- + */ + +static int Prl_FillOptions(options, argc_addr, argv_addr) +prl_options_t *options; +int *argc_addr; +char ***argv_addr; +{ + int c; + int argc = *argc_addr; + char **argv = *argv_addr; + char *method_name = NIL(char); + char *red_latch_method_name = NIL(char); + + /* global options */ + options->verbose = 0; + + /* ordering heuristic: branch & bound depth */ + options->ordering_depth = 1; + + /* timing control */ + options->timeout = 0; + options->last_time = util_cpu_time(); + options->total_time = 0; + + /* for env_verify_fsm */ + options->stop_if_verify = 0; + + /* for removing latches */ + options->remlatch.max_cost = INFINITY; + options->remlatch.max_level = INFINITY; + options->remlatch.local_retiming = 1; + options->remlatch.remove_boot = 1; + + error_init(); + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "o:p:f:t:v:l:riV")) != EOF) { + switch(c) { + case 'o': + options->ordering_depth = atoi(util_optarg); + break; + case 't': + options->timeout = atoi(util_optarg); + if (options->timeout < 0 || options->timeout > 3600 * 24 * 365) return 1; + break; + case 'v': + options->verbose = atoi(util_optarg); + break; + /* the rest is for "remove_latches" */ + case 'l': + options->remlatch.max_level = atoi(util_optarg); + if (options->remlatch.max_level <= 1) return 1; + break; + case 'f': + options->remlatch.max_cost = atoi(util_optarg); + if (options->remlatch.max_cost < 1) return 1; + break; + case 'r': + options->remlatch.local_retiming = 0; + break; + case 'i': + options->remlatch.remove_boot = 0; + break; + case 'V': + options->stop_if_verify = 1; + break; + default: + return 1; + } + } + + /* select a method: only one supported here */ + method_name = "product"; + options->type = PRODUCT_METHOD; + options->method_name = "product"; + options->bdd_order = Prl_ProductBddOrder; + options->init_seq_info = Prl_ProductInitSeqInfo; + options->free_seq_info = Prl_ProductFreeSeqInfo; + options->compute_next_states = Prl_ProductComputeNextStates; + options->compute_reverse_image = Prl_ProductReverseImage; + options->extract_network_input_names = Prl_ProductExtractNetworkInputNames; + + *argc_addr = argc; + *argv_addr = argv; + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * Prl_PrintUsage -- + * + *---------------------------------------------------------------------- + */ + +static void Prl_PrintUsage(name, msg) +char* name; +char* msg; +{ + (void) fprintf(siserr, "usage: %s [-o d] [-t s] [-v n] [-l m] [-f n] [-r] [-b] [-V] %s\n", name, msg); + (void) fprintf(siserr, "---- options for: env_seq_dc, remove_latches, equiv_nets, env_verify_fsm ----\n"); + (void) fprintf(siserr, " [-o d]: depth of search for good variable ordering;"); + (void) fprintf(siserr, " d == 0 means greedy; default is d = 1\n"); + (void) fprintf(siserr, " [-t s]: time out after s seconds of cpu time\n"); + (void) fprintf(siserr, " [-v n]: verbosity level\n"); + (void) fprintf(siserr, "---- options specific to remove_latches ----\n"); + (void) fprintf(siserr, " [-f n]: remove a latch only if fanin of its recoding fn is <= n\n"); + (void) fprintf(siserr, " [-l n]: remove a latch only if its recoding fn has a depth <= n\n"); + (void) fprintf(siserr, " [-r]: do not perform local retiming before remove latches\n"); + (void) fprintf(siserr, " [-i]: do not attempt to remove boot latches\n"); + (void) fprintf(siserr, "---- options specific to env_verify_fsm ----\n"); + (void) fprintf(siserr, " [-V]: returns an error status if verification succeeds\n"); +} + +#endif /* SIS */ diff --git a/sis/seqbdd/consistency.c b/sis/seqbdd/consistency.c new file mode 100644 index 0000000..8858a6c --- /dev/null +++ b/sis/seqbdd/consistency.c @@ -0,0 +1,230 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/consistency.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + /* file %M% release %I% */ + /* last modified: %G% at %U% */ +#ifdef SIS +#include "sis.h" + + + /* EXTERNAL INTERFACE */ + + /* ARGSUSED */ +range_data_t *consistency_alloc_range_data(network, options) +network_t *network; +verif_options_t *options; +{ + st_table *input_to_output_table; + output_info_t *info = options->output_info; + range_data_t *data = ALLOC(range_data_t, 1); + + data->type = CONSISTENCY_METHOD; + + /* create a BDD manager */ + if (options->verbose >= 3) print_node_table(info->pi_ordering); + data->manager = ntbdd_start_manager(st_count(info->pi_ordering)); + + /* create BDD for external output_fn and init_state_fn */ + data->init_state_fn = ntbdd_node_to_bdd(info->init_node, data->manager, info->pi_ordering); + if (options->does_verification) { + data->output_fn = ntbdd_node_to_bdd(info->output_node, data->manager, info->pi_ordering); + } else { + data->output_fn = NIL(bdd_t); + } + + /* consistency fn and the like */ + data->consistency_fn = ntbdd_node_to_bdd(info->main_node, data->manager, info->pi_ordering); + data->smoothing_inputs = bdd_extract_var_array(data->manager, info->org_pi, info->pi_ordering); + + + /* create and save two arrays of bdd variables in order: yi's and their corresponding xi's */ + input_to_output_table = extract_input_to_output_table(info->org_pi, info->new_pi, info->po_ordering, network); + data->input_vars = extract_state_input_vars(data->manager, info->pi_ordering, input_to_output_table); + data->output_vars = extract_state_output_vars(data->manager, info->pi_ordering, input_to_output_table); + + /* only present state variables: used for counting the onset of reached set */ + data->pi_inputs = data->input_vars; + + /* free space allocated here */ + st_free_table(input_to_output_table); + + return data; +} + +void consistency_free_range_data(data, options) +range_data_t *data; +verif_options_t *options; +{ + output_info_t *info = options->output_info; + + /* do not free data->pi_inputs (== data->input_vars) */ + array_free(data->input_vars); + array_free(data->output_vars); + array_free(data->smoothing_inputs); + if (options->does_verification) { + ntbdd_free_at_node(info->output_node); + } + ntbdd_free_at_node(info->init_node); + ntbdd_free_at_node(info->main_node); + ntbdd_end_manager(data->manager); +} + + /* ARGSUSED */ +bdd_t *consistency_compute_next_states(current_set, data, options) +bdd_t *current_set; +range_data_t *data; +verif_options_t *options; +{ + bdd_t *result_as_output; + bdd_t *new_current_set; + + result_as_output = bdd_and_smooth(data->consistency_fn, current_set, data->smoothing_inputs); + new_current_set = bdd_substitute(result_as_output, data->output_vars, data->input_vars); + bdd_free(result_as_output); + return new_current_set; +} + /* ARGSUSED */ +bdd_t *consistency_compute_reverse_image(next_set, data, options) +bdd_t *next_set; +range_data_t *data; +verif_options_t *options; +{ + bdd_t *next_set_as_next_state_vars; + bdd_t *result; + + next_set_as_next_state_vars = bdd_substitute(next_set, data->input_vars, data->output_vars); + result = bdd_and_smooth(data->consistency_fn, next_set_as_next_state_vars, data->output_vars); + bdd_free(next_set_as_next_state_vars); + return result; +} + + /* returns 1 iff everything is OK */ +int consistency_check_output(current_set, data, index, options) +bdd_t *current_set; +range_data_t *data; +int *index; +verif_options_t *options; +{ + if (bdd_leq(current_set, data->output_fn, 1, 1)) return 1; + report_inconsistency(current_set, data->output_fn, options->output_info->pi_ordering); + return 0; +} + +void consistency_bdd_sizes(data, fn_size, output_size) +range_data_t *data; +int *fn_size; +int *output_size; +{ + if (fn_size) { + *fn_size = bdd_size(data->consistency_fn); + } + if (output_size) { + if (data->output_fn == NIL(bdd_t)) { + *output_size = 0; + } else { + *output_size = bdd_size(data->output_fn); + } + } +} + + + /* EXPORTED UTILITIES */ + + /* returns a table that takes a state input node as key, and returns the new primary input */ + /* associated with the state output node which matches the key */ + /* nodes in org_pi, new_pi and po_ordering belong to the main network */ + /* they have to be matched by name */ + +st_table *extract_input_to_output_table(org_pi, new_pi, po_ordering, network) +array_t *org_pi; +array_t *new_pi; +array_t *po_ordering; +network_t *network; +{ + int i, index; + lsGen gen; + latch_t *l; + node_t *input, *output; + st_table *name_table = st_init_table(strcmp,st_strhash); + st_table *index_table = st_init_table(strcmp,st_strhash); + st_table *result = st_init_table(st_ptrcmp, st_ptrhash); + + /* index_table: state PO name --> index in po_ordering */ + /* (orderings in po_ordering and new_pi are the same) */ + for (i = 0; i < array_n(po_ordering); i++) { + output = array_fetch(node_t *, po_ordering, i); + st_insert(index_table, output->name, (char *) i); + } + + /* name_table: state PI name --> index of matching state PO */ + foreach_latch(network, gen, l){ +/* output is a primary output of the network and input to latch*/ + output = latch_get_input(l); +/*input is a primary input of the circuit and output of latch*/ + input = latch_get_output(l); + assert(input->type == PRIMARY_INPUT); + assert(st_lookup_int(index_table, output->name, &index)); + st_insert(name_table, input->name, (char *) index); + } + + for (i = 0; i < array_n(org_pi); i++) { + node_t *ps_node = array_fetch(node_t *, org_pi, i); + if (! st_lookup_int(name_table, ps_node->name, &index)) continue; + input = array_fetch(node_t *, new_pi, index); + st_insert(result, (char *) ps_node, (char *) input); + } + st_free_table(name_table); + st_free_table(index_table); + return result; +} + + + /* the order of appearance in pi_ordering */ +array_t *extract_state_input_vars(manager, pi_ordering, ito_table) +bdd_manager *manager; +st_table *pi_ordering; +st_table *ito_table; +{ + int index; + st_generator *gen; + node_t *ps_node, *ns_node; + array_t *tmp = array_alloc(node_t *, 0); + array_t *result; + + st_foreach_item_int(pi_ordering, gen, (char **) &ps_node, &index) { + if (! st_lookup(ito_table, (char *) ps_node, (char **) &ns_node)) ps_node = NIL(node_t); + array_insert(node_t *, tmp, index, ps_node); + } + result = bdd_extract_var_array(manager, tmp, pi_ordering); + array_free(tmp); + return result; +} + + /* the order of appearance in pi_ordering */ +array_t *extract_state_output_vars(manager, pi_ordering, ito_table) +bdd_manager *manager; +st_table *pi_ordering; +st_table *ito_table; +{ + int index; + st_generator *gen; + node_t *ps_node, *ns_node; + array_t *tmp = array_alloc(node_t *, 0); + array_t *result; + + st_foreach_item_int(pi_ordering, gen, (char **) &ps_node, &index) { + if (! st_lookup(ito_table, (char *) ps_node, (char **) &ns_node)) ns_node = NIL(node_t); + array_insert(node_t *, tmp, index, ns_node); + } + result = bdd_extract_var_array(manager, tmp, pi_ordering); + array_free(tmp); + return result; +} +#endif /* SIS */ + diff --git a/sis/seqbdd/manual_order.c b/sis/seqbdd/manual_order.c new file mode 100644 index 0000000..399d3d6 --- /dev/null +++ b/sis/seqbdd/manual_order.c @@ -0,0 +1,132 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/manual_order.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + /* file %M% release %I% */ + /* last modified: %G% at %U% */ +#ifdef SIS +#include "sis.h" + +static int get_node_order(); +static st_table *extract_order_info(); +static void order_table(); +static int extract_trailing_y(); +static void replace_character(); + + /* puts the order in the table: node (key) -> index (value) */ + +void get_manual_order(order, options) +st_table *order; +verif_options_t *options; +{ + int n_elts; + st_table *name_table; + + assert(options->use_manual_order); + assert(options->order_network); + name_table = extract_order_info(options->order_network); + n_elts = st_count(order); + order_table(order, name_table); + assert(n_elts == st_count(order)); + st_free_table(name_table); +} + + /* take the network, extract the PI names in that order */ + /* and put them in a hash table, with the order as value */ +static st_table *extract_order_info(network) +network_t *network; +{ + int count = 0; + node_t *pi; + lsGen gen; + st_table *name_table = st_init_table(strcmp, st_strhash); + + foreach_primary_input(network, gen, pi) { + st_insert(name_table, pi->name, (char *) count); + count++; + } + return name_table; +} + +static void order_table(node_table, name_table) +st_table *node_table; +st_table *name_table; +{ + int i; + int index; + int count; + node_t *node; + st_generator *gen; + node_t **nodes; + + count = 0; + nodes = ALLOC(node_t *, st_count(node_table)); + st_foreach_item(node_table, gen, (char **) &node, NIL(char *)) { + nodes[count++] = node; + } + for (i = 0; i < count; i++) { + index = get_node_order(nodes[i]->name, name_table); + st_insert(node_table, (char *) nodes[i], (char *) index); + } + FREE(nodes); +} + + + /* take the name; remove the ":y%d if something like that at the end */ + /* lookup the matching thing in the table and return the number */ +static int get_node_order(name, name_table) +char *name; +st_table *name_table; +{ + int rank; + char *new_name; + + if (! extract_trailing_y(name, &new_name)) { + new_name = util_strsav(name); + } + replace_character(new_name, ':', '_'); + if (! st_lookup_int(name_table, new_name, &rank)) { + fprintf(miserr, "can't find ordering information in file\n"); + rank = 0; + } + FREE(new_name); + return rank; +} + + /* returns 0 if nothing changed; 1 otherwise */ + /* takes a name, and strips anything of the form :y%d at the end */ + +static int extract_trailing_y(name, new_name) +char *name; +char **new_name; +{ + char *result; + char *last = (char *) rindex(name, ':'); + + *new_name = 0; + if (last == 0) return 0; + if (last[1] != 'y') return 0; + result = (char *) malloc(last - name + 1); + strncpy(result, name, last - name); + result[last - name] = '\0'; + *new_name = result; + return 1; +} + +static void replace_character(name, old, new) +char *name; +char old; +char new; +{ + char *p; + + for (p = name; *p != '\0'; p++) { + if (*p == old) *p = new; + } +} +#endif /* SIS */ diff --git a/sis/seqbdd/network_info.c b/sis/seqbdd/network_info.c new file mode 100644 index 0000000..22f613d --- /dev/null +++ b/sis/seqbdd/network_info.c @@ -0,0 +1,556 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/network_info.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ +#ifdef SIS +#include "sis.h" + +static array_t *network_extract_extern_pi(); +static void allocate_and_rename_primary_inputs(); +static void extract_local_pipo(); +static void extract_product_pi_info(); +static void merge_io_outputs(); +static void remember_primary_output_names(); +static void rename_internal_nodes(); +static void hack_rename_internal_nodes(); +static void rename_primary_outputs(); + + + /* network: is the FSM transition + output fn network */ + /* if range computation, just that; if verification, product machine */ + /* constraints: a simple network with only PI and PO; specifies */ + /* the initial state, the list of PS and NS variables, and the correspondance */ + /* between PS (present state) and NS (next state). The NS are PO fed by */ + /* the corresponding PS, which is represented as a PI. */ + +void extract_network_info(network, options) +network_t *network; +verif_options_t *options; +{ + char *name; + node_t *node; + array_t *next_state_po; + output_info_t *output_info = options->output_info; + + if (options->verbose >= 1) report_elapsed_time(options, "extract network info"); + output_info->org_pi = network_extract_pi(network); + output_info->extern_pi = network_extract_extern_pi(network); + output_info->init_node = copy_init_state_constraint(network); + next_state_po = network_extract_next_state_po(network); + switch (options->type) { + case BULL_METHOD: + output_info->po_ordering = get_po_ordering(network, next_state_po, options); + array_free(next_state_po); + break; + case CONSISTENCY_METHOD: + output_info->po_ordering = get_po_ordering(network, next_state_po, options); + array_free(next_state_po); + name = util_strsav("consistency:output"); + output_info->new_pi = create_new_pi(network, output_info->po_ordering); + if (output_info->is_product_network) { /* verification */ + extract_product_pi_info(network, output_info, name); + } else { /* range computation */ + node = build_equivalence_node(network, output_info->new_pi, output_info->po_ordering, name, NIL(array_t)); + output_info->main_node = network_add_primary_output(network, node); + } + output_info->pi_ordering = get_pi_ordering(network, output_info->po_ordering, output_info->new_pi); + if (options->use_manual_order) get_manual_order(output_info->pi_ordering, options); + break; + case PRODUCT_METHOD: /* keep the transition relation as independent products; no special case here */ + output_info->po_ordering = get_po_ordering(network, next_state_po, options); + array_free(next_state_po); + output_info->new_pi = create_new_pi(network, output_info->po_ordering); + output_info->transition_nodes = array_alloc(node_t *, 0); + node = build_equivalence_node(network, output_info->new_pi, output_info->po_ordering, NIL(char), output_info->transition_nodes); + network_delete_node(network, node); + output_info->main_node = NIL(node_t); + output_info->pi_ordering = get_pi_ordering(network, output_info->po_ordering, output_info->new_pi); + if (options->use_manual_order) get_manual_order(output_info->pi_ordering, options); + break; + default: + fail("unregistered range computation method"); + } +} + +void extract_product_network_info(network1, network2, options) +network_t *network1; +network_t *network2; +verif_options_t *options; +{ + if (options->verbose >= 1) report_elapsed_time(options, "compute product network"); + compute_product_network(network1, network2, options->output_info); + extract_network_info(network2, options); +} + + /* put the product and the product constraints on network2/constraint2 */ + /* return the output created by merging IO_OUTPUTS together and AND and XNOR's */ + /* all tables work by name; good both for networki and constraintsi */ + /* fill the "xnor_nodes" array of external outputs */ + /* as well as the "output_node" */ + +void compute_product_network(network1, network2, output_info) +network_t *network1; +network_t *network2; +output_info_t *output_info; +{ + lsGen gen; + st_generator *sgen; + char *name; + node_t *output, *n1, *n2; + latch_t *l1, *l2; + int value; + st_table *node_table = st_init_table(st_ptrcmp, st_ptrhash); + st_table *input_table = st_init_table(strcmp,st_strhash); + st_table *output_table = st_init_table(strcmp,st_strhash); + + allocate_and_rename_primary_inputs(network1, network2, input_table, ":0"); + rename_primary_outputs(network2, output_table, ":0"); + rename_internal_nodes(network2, ":0"); + hack_rename_internal_nodes(network1, network2, ":0"); + remember_primary_output_names(network1, output_info, 0); + remember_primary_output_names(network2, output_info, 1); + + foreach_primary_output(network1, gen, output) { + (void) network_copy_subnetwork(network2, output, input_table, node_table); + } + merge_io_outputs(network1, network2, output_table, output_info); + st_free_table(input_table); + st_foreach_item(output_table, sgen, &name, NIL(char *)) { + FREE(name); + } + st_free_table(output_table); + st_free_table(node_table); + /* copy latches from network1 to network2*/ + foreach_latch(network1, gen, l1){ + n1 = latch_get_input(l1); + n2 = latch_get_output(l1); + n1 = network_find_node(network2, n1->name); + n2 = network_find_node(network2, n2->name); + network_create_latch(network2, &l2, n1, n2); + value = latch_get_initial_value(l1); + latch_set_initial_value(l2, value); + } +} + + /* for each PI of network1 that does not appear as output of a latch*/ + /* find the corresponding PI in network2 and store (name, net2_pi) in input_table */ + /* for each PI of network1 that appears as a PI in constraints1 */ + /* rename the corresponding PI in network2 if any and add a new PI in network2 */ + /* again, store the correspondance in input_table */ + /* renaming is done by appending the string ":0" to the PI name */ + +static void allocate_and_rename_primary_inputs(network1, network2, input_table, postfix) +network_t *network1; +network_t *network2; +st_table *input_table; +char *postfix; +{ + lsGen gen; + int postfix_length = (int) strlen(postfix) + 1; + node_t *input, *new_input; + + foreach_primary_input(network1, gen, input) { + if (latch_from_node(input) == NIL (latch_t)){ + assert(new_input = network_find_node(network2, input->name)); + }else{ + if (new_input = network_find_node(network2, input->name)) { + char *new_name = ALLOC(char, (int) strlen(input->name) + postfix_length); + (void) sprintf(new_name, "%s%s", input->name, postfix); + network_change_node_name(network2, new_input, new_name); + /* + * Also ensure that if needed the reference in the dc_network is + * also changed. This is required to allow the subsequent addition + * of new_input to retain the name input->name in case the latter is + * a madeup_name. The routine network_add_node() checks to see if the + * name being assigned is absent from both the care and dc networks !!! + */ + if ((network2->dc_network != NIL(network_t)) && + (new_input = network_find_node(network2->dc_network, input->name))) + { + network_change_node_name(network2->dc_network, new_input, + util_strsav(new_name)); + } + } + new_input = node_alloc(); + new_input->name = util_strsav(input->name); + network_add_primary_input(network2, new_input); + } + st_insert(input_table, input->name, (char *) new_input); + } +} + + /* rename each PO of "network" by appending a ":0" at the end */ + /* this is to avoid conflicts with other network */ + /* keeps the correspondance between old name and nodes in "output_table" */ + +static void rename_primary_outputs(network, output_table, postfix) +network_t *network; +st_table *output_table; +char *postfix; +{ + lsGen gen; + node_t *output; + int postfix_length = (int) strlen(postfix) + 1; + + foreach_primary_output(network, gen, output) { + char *old_name = util_strsav(output->name); + char *new_name = ALLOC(char, (int) strlen(old_name) + postfix_length); + (void) sprintf(new_name, "%s%s", old_name, postfix); + network_change_node_name(network, output, new_name); + st_insert(output_table, old_name, (char *) output); + } +} + +static void rename_internal_nodes(network, postfix) +network_t *network; +char *postfix; +{ + char *new_name; + lsGen gen; + node_t *node; + int postfix_length = (int) strlen(postfix) + 1; + + foreach_node(network, gen, node) { + if (node->type != INTERNAL) continue; + new_name = ALLOC(char, strlen(node->name) + postfix_length); + (void) sprintf(new_name, "%s%s", node->name, postfix); + network_change_node_name(network, node, new_name); + } +} + + +/* This is a hack. There is a special case in which verify_fsm + core dumps. If n1 has an internal node with the same name as + a pi in n2 that is a latch output, a core dump occurs. This fixes + that problem. */ + +static void hack_rename_internal_nodes(n1, n2, postfix) +network_t *n1, *n2; +char *postfix; +{ + char *new_name; + lsGen gen; + node_t *node, *node2; + int postfix_length = (int) strlen(postfix) + 1; + + foreach_node(n1, gen, node) { + if (node->type != INTERNAL) continue; + if ((node2 = network_find_node(n2, node->name)) != NIL(node_t)) { + new_name = ALLOC(char, strlen(node->name) + postfix_length); + (void) sprintf(new_name, "%s%s", node->name, postfix); + network_change_node_name(n1, node, new_name); + } + } +} + + + /* only those outputs that do not figure in constraints1 */ + /* fill the "xnor_nodes" array of external outputs */ + /* as well as the "output_node" */ + +static void merge_io_outputs(network1, network2, output_table, output_info) +network_t *network1; +network_t *network2; +st_table *output_table; +output_info_t *output_info; +{ + int i; + lsGen gen; + char *name = EXTERNAL_OUTPUT_NAME; + node_t *output, *new_output, *matching_output; + array_t *io_outputs1 = array_alloc(node_t *, 0); + array_t *io_outputs2 = array_alloc(node_t *, 0); + array_t *io_fanin1 = array_alloc(node_t *, 0); + array_t *io_fanin2 = array_alloc(node_t *, 0); + + foreach_primary_output(network1, gen, output) { + if (!network_is_real_po(network1, output)) continue; + assert(new_output = network_find_node(network2, output->name)); + assert(new_output->type == PRIMARY_OUTPUT); + array_insert_last(node_t *, io_outputs1, new_output); + new_output = node_get_fanin(new_output, 0); + assert(st_lookup(output_table, output->name, (char **) &matching_output)); + assert(matching_output->type == PRIMARY_OUTPUT); + array_insert_last(node_t *, io_outputs2, matching_output); + matching_output = node_get_fanin(matching_output, 0); + array_insert_last(node_t *, io_fanin1, new_output); + array_insert_last(node_t *, io_fanin2, matching_output); + } + if (array_n(io_outputs1) == 0) return; + output_info->xnor_nodes = array_alloc(node_t *, 0); + output = build_equivalence_node(network2, io_fanin1, io_fanin2, name, output_info->xnor_nodes); + if (output_info->generate_global_output) { + output_info->output_node = network_add_primary_output(network2, output); + } else { + network_delete_node(network2, output); + output_info->output_node = NIL(node_t); + for (i = 0; i < array_n(output_info->xnor_nodes); i++) { + output = array_fetch(node_t *, output_info->xnor_nodes, i); + (void) network_add_primary_output(network2, output); + } + } + for (i = 0; i < array_n(io_outputs1); i++) { + output = array_fetch(node_t *, io_outputs1, i); + network_delete_node(network2, output); + output = array_fetch(node_t *, io_outputs2, i); + network_delete_node(network2, output); + } + array_free(io_outputs1); + array_free(io_outputs2); + array_free(io_fanin1); + array_free(io_fanin2); +} + + /* convention: all PO of "network" that have the same name as PO of "input" */ + /* except for the PO of "input" called INIT_STATE_OUTPUT_NAME are next_state PO */ + +array_t *network_extract_next_state_po(network) +network_t *network; +{ + lsGen gen; + node_t *n1; + latch_t *l; + array_t *result; + + result = array_alloc(node_t *, 0); + + foreach_latch(network, gen, l){ + n1 = latch_get_input(l); + array_insert_last(node_t *, result, n1); + } + return result; +} + + + /* simply puts the PI of a network in an array */ + +array_t *network_extract_pi(network) +network_t *network; +{ + lsGen gen; + node_t *input; + array_t *result = array_alloc(node_t *, 0); + + foreach_primary_input(network, gen, input) { + array_insert_last(node_t *, result, input); + } + return result; +} + + /* is extern_pi iff pi and name does not appear in constraint */ + +static array_t *network_extract_extern_pi(network) +network_t *network; +{ + lsGen gen; + node_t *input; + array_t *result = array_alloc(node_t *, 0); + + foreach_primary_input(network, gen, input) { + if(network_is_real_pi(network, input)) + array_insert_last(node_t *, result, input); + } + return result; +} + + /* copy the init state output and its inputs in network */ + /* match the PI's by name */ + +node_t *copy_init_state_constraint(network) +network_t *network; +{ + lsGen gen; + node_t *init_state; + node_t *n1, *n2, *n3; + latch_t *l; + int value; + + init_state = node_constant(1); + foreach_latch(network, gen, l){ + value = latch_get_initial_value(l); + switch (value) { + case 0: + case 1: + n1 = latch_get_output(l); + n2 = node_literal(n1, value); + n3 = node_and(init_state, n2); + node_free(n2); + node_free(init_state); + init_state = n3; + break; + case 2: + break; + default: + (void) fprintf(sisout, "Latch with input: %s and output: %s is not properly initialized. \n", + node_name(latch_get_input(l)), + node_name(latch_get_output(l))); + node_free(init_state); + return(NIL (node_t)); + } + } + network_add_node(network, init_state); + network_change_node_name(network, init_state, util_strsav(INIT_STATE_OUTPUT_NAME)); + return network_add_primary_output(network, init_state); +} + + /* create one new PI per node in outputs */ + +array_t *create_new_pi(network, outputs) +network_t *network; +array_t *outputs; +{ + int i; + int n_new_pi = array_n(outputs); + array_t *new_pi = array_alloc(node_t *, 0); + + for (i = 0; i < n_new_pi; i++) { + node_t *node = node_alloc(); + node_t *output = array_fetch(node_t *, outputs, i); + char *buffer = ALLOC(char, (int) strlen(output->name) + 10); + + (void) sprintf(buffer, "%s:y%d", output->name, i); + node->name = util_strsav(buffer); + network_add_primary_input(network, node); + array_insert_last(node_t *, new_pi, node); + FREE(buffer); + } + return new_pi; +} + + + /* takes the two lists of nodes of "network", merge them together into XNOR gates */ + /* connect the results of those XNOR gates into a AND gate, and return the resulting node */ + /* the name of the resulting node is given by the output_name argument if non NIL */ + /* if xnor_array is non NIL, the intermediate XNOR nodes are saved there */ + /* if any node is a PO, it is replaced by its unique fanin */ + +node_t *build_equivalence_node(network, nodes1, nodes2, output_name, xnor_array) +network_t *network; +array_t *nodes1; +array_t *nodes2; +char *output_name; +array_t *xnor_array; +{ + int i; + int n_nodes = array_n(nodes1); + node_t *a, *b, *and_node, *new_and_node; + node_t **xnor_nodes = ALLOC(node_t *, n_nodes); + + assert(array_n(nodes1) == array_n(nodes2)); + for (i = 0; i < n_nodes; i++) { + a = array_fetch(node_t *, nodes1, i); + b = array_fetch(node_t *, nodes2, i); + if (a->type == PRIMARY_OUTPUT) a = node_get_fanin(a, 0); + if (b->type == PRIMARY_OUTPUT) b = node_get_fanin(b, 0); + a = node_literal(a, 1); + b = node_literal(b, 1); + xnor_nodes[i] = node_xnor(a, b); + node_free(a); + node_free(b); + network_add_node(network, xnor_nodes[i]); + } + if (n_nodes == 0) { + and_node = node_constant(1); + } else if (n_nodes == 1) { + and_node = node_literal(xnor_nodes[0], 1); + if (xnor_array) array_insert_last(node_t *, xnor_array, xnor_nodes[0]); + } else { + for (i = 0; i < n_nodes; i++) { + xnor_nodes[i] = node_literal(xnor_nodes[i], 1); + } + and_node = node_and(xnor_nodes[0], xnor_nodes[1]); + for (i = 2; i < n_nodes; i++) { + new_and_node = node_and(and_node, xnor_nodes[i]); + node_free(and_node); + and_node = new_and_node; + } + for (i = 0; i < n_nodes; i++) { + if (xnor_array != NIL(array_t)) { + network_add_node(network, xnor_nodes[i]); + array_insert_last(node_t *, xnor_array, xnor_nodes[i]); + } else { + node_free(xnor_nodes[i]); + } + } + } + network_add_node(network, and_node); + if (output_name) { + network_change_node_name(network, and_node, util_strsav(output_name)); + } + FREE(xnor_nodes); + return and_node; +} + + /* build the consistency output for each of the two networks separately */ + /* record the result in output_info, as well as their "AND" */ + /* the problem is that we need to extract info on the networks from their product ("network") */ + +static void extract_product_pi_info(network, output_info, name) +network_t *network; +output_info_t *output_info; +char *name; +{ + int i; + node_t *node; + array_t *local_pi, *local_po; + + for (i = 0; i < 2; i++) { + local_pi = array_alloc(node_t *, 0); + local_po = array_alloc(node_t *, 0); + extract_local_pipo(output_info, local_pi, local_po, i); + output_info->main_nodes[i] = build_equivalence_node(network, local_pi, local_po, NIL(char), NIL(array_t)); + array_free(local_pi); + array_free(local_po); + } + node = node_and(output_info->main_nodes[0], output_info->main_nodes[1]); + network_add_node(network, node); + network_change_node_name(network, node, name); + output_info->main_node = network_add_primary_output(network, node); +} + +static void remember_primary_output_names(network, info, value) +network_t *network; +output_info_t *info; +int value; +{ + lsGen gen; + node_t *output; + + if (info->name_table == NIL(st_table)) { + info->name_table = st_init_table(strcmp, st_strhash); + } + foreach_primary_output(network, gen, output) { + st_insert(info->name_table, output->name, (char *) value); + } +} + + /* given info->po_ordering: i.e. PO of product network in some order */ + /* and info->new_pi: matching PI (newly allocated) in same order */ + /* and info->name_table: table of (char *) for PO mapping to the netid of their original net */ + /* extract in local_pi/local_po those PI-PO pairs for a given netid */ +static void extract_local_pipo(info, local_pi, local_po, netid) +output_info_t *info; +array_t *local_pi; +array_t *local_po; +int netid; +{ + int i; + int id; + node_t *pi, *po; + + for (i = 0; i < array_n(info->po_ordering); i++) { + po = array_fetch(node_t *, info->po_ordering, i); + assert(st_lookup_int(info->name_table, po->name, &id)); + if (id != netid) continue; + array_insert_last(node_t *, local_po, po); + pi = array_fetch(node_t *, info->new_pi, i); + array_insert_last(node_t *, local_pi, pi); + } +} +#endif /* SIS */ + diff --git a/sis/seqbdd/ordering.c b/sis/seqbdd/ordering.c new file mode 100644 index 0000000..3e0045b --- /dev/null +++ b/sis/seqbdd/ordering.c @@ -0,0 +1,506 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/ordering.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + /* file %M% release %I% */ + /* last modified: %G% at %U% */ +#ifdef SIS +#include "sis.h" + + /* this file implements an exact solution to the following problem */ + /* given A1,...,An n subsets of some finite set S */ + /* find an ordering of {1,...,n} such that */ + /* if s_i = |\cup{1\leq j\leq i} A_i | */ + /* \sum_{1\leq i \leq n} s_i is minimized */ + /* This is used for ordering output fns in BDD range computation heuristics */ + + /* the algorithm is exponential in the worst-case */ + /* it uses a branch and bound heuristic */ + /* as well as the fact that if A_i included in A_j */ + /* we can always suppose that A_i appears before A_j */ + /* In fact, more strongly that that: if A_i is included in A_j */ + /* except for elements that only appear in A_i and in no other set */ + /* then A_i always appear before A_j if #singletons(A_i) \leq #singletons(A_j) */ + + /* key into the cache: should use var_set_t compare */ + /* describes as a bit string the sets scheduled so far */ +typedef struct { + var_set_t *placed_so_far; +} set_key_t; + + /* value stored in the cache */ + /* the best next set index, and the cost at that point */ +typedef struct { + int index; + int cost; +} set_value_t; + + /* should not overflow too easily but should be large enough */ +#define LARGE_NUMBER ((int) 0x1fffffff) + + /* information associated with dominators used in branch & bound */ + /* a dominator is a set that does not contain any other */ + /* (not exactly true; for exact definition, see compare routine) */ + /* the size of the dominator is the number of elts it contains */ + /* that are not in the union of the sets visited so far */ +typedef struct { + int index; /* index of the set (if A5, index is 5) */ + int bound; /* lower bound of the cost of choosing this index */ + int cost; /* real cost, after recursive computation */ + int size; /* size of the index, minus all variables already there */ +} dominator_t; + + +static array_t *extract_dominators(); +static int arg_min_remaining_size(); +static int dominator_cmp(); +static int do_find_best_set_order(); +static int set_is_less_than(); +static int set_key_cmp(); +static int set_key_hash(); +static var_set_t *extract_uncovered_variables(); +static void compute_bounds(); +static void extract_best_order_from_cache(); +static void print_int_array(); +static void print_set_info(); +static void set_cache_free(); +static int compute_order_cost(); + + /* EXTERNAL INTERFACE */ + + /* returns an array of size n_sets representing the optimal ordering of the sets */ + +static int global_verbose; + +array_t *find_best_set_order(info, options) +set_info_t *info; +verif_options_t *options; +{ + int cost; + set_key_t *key = ALLOC(set_key_t, 1); + array_t *result = array_alloc(int, 0); + st_table *cache = st_init_table(set_key_cmp, set_key_hash); + + global_verbose = options->verbose; + if (options->verbose >= 4) print_set_info(info); + key->placed_so_far = var_set_new(info->n_sets); /* automatically initialized to 0 */ + if (options->ordering_depth >= 0) { + cost = do_find_best_set_order(info, key, cache, options->ordering_depth, LARGE_NUMBER); + extract_best_order_from_cache(info, cache, key, result); + assert(cost == compute_order_cost(info, result)); + } else { + array_free(result); + result = find_greedy_set_order(info); + cost = compute_order_cost(info, result); + } + /* TODO: compute the cost again; check with evaluated cost above */ + if (options->verbose >= 2) { + printf("ordering cost is: %d\n", cost); + if (options->verbose >= 3) print_int_array(result); + } + set_cache_free(cache); + return result; +} + + + /* INTERNAL INTERFACE */ + + /* returns the cost of the solution so far */ + /* the resulting order can be derived from the cache */ + /* The key is newly allocated when it comes in */ + /* it is either kept in the cache or freed by this routine */ + /* info is read-only */ + +static int do_find_best_set_order(info, key, cache, depth, allocated) +set_info_t *info; +set_key_t *key; +st_table *cache; +int depth; +int allocated; /* for bounding the search: if allocated < 0, can kill this subtree */ +{ + int i; + int local_cost; + set_key_t *new_key; + set_value_t *value; + var_set_t *remaining_vars, *dead_vars; + array_t *dominators; + dominator_t d; + dominator_t *dom; + int n_remaining_sets; + var_set_t *tmp = NIL(var_set_t); + + n_remaining_sets = info->n_sets - var_set_n_elts(key->placed_so_far); + if (n_remaining_sets == 0) { + var_set_free(key->placed_so_far); + FREE(key); + return 0; + } + if (allocated < 0) { + var_set_free(key->placed_so_far); + FREE(key); + return LARGE_NUMBER; + } + if (st_lookup(cache, (char *) key, (char **) &value)) { + var_set_free(key->placed_so_far); + FREE(key); + return value->cost; + } + /* variables still active (i.e. complement of union of sets in key) */ + remaining_vars = extract_uncovered_variables(info, key); + dead_vars = var_set_copy(remaining_vars); + (void) var_set_not(dead_vars, dead_vars); + + if (depth <= 0) { + dominators = array_alloc(dominator_t, 0); + /* get the first remaining set of minimum size relative to remaining vars */ + d.bound = 0; + d.cost = LARGE_NUMBER; + d.index = arg_min_remaining_size(info, key->placed_so_far, dead_vars, &(d.size)); + array_insert_last(dominator_t, dominators, d); + } else { + dominators = extract_dominators(info, key->placed_so_far, remaining_vars); + if (array_n(dominators) > 1) { + array_sort(dominators, dominator_cmp); + compute_bounds(info, key->placed_so_far, remaining_vars, dominators); + } + } + assert(array_n(dominators) > 0); + /* compute the best solution among all alternatives */ + tmp = var_set_new(info->n_vars); + value = ALLOC(set_value_t, 1); + value->index = -1; + value->cost = LARGE_NUMBER; + for (i = 0; i < array_n(dominators); i++) { + dom = array_fetch_p(dominator_t, dominators, i); + if (dom->bound >= value->cost) continue; + + /* to compute the cost at this level: number of 1's here */ + /* times how many times they are going to appear: # remaining_sets */ + (void) var_set_and(tmp, info->sets[dom->index], remaining_vars); + local_cost = var_set_n_elts(tmp) * n_remaining_sets; + + allocated = value->cost - local_cost; + new_key = ALLOC(set_key_t, 1); + new_key->placed_so_far = var_set_copy(key->placed_so_far); + var_set_set_elt(new_key->placed_so_far, dom->index); + dom->cost = local_cost + do_find_best_set_order(info, new_key, cache, depth - 1, allocated); + if (value->cost > dom->cost) { + value->cost = dom->cost; + value->index = dom->index; + } + } + assert(value->index != -1); + assert(! var_set_get_elt(key->placed_so_far, value->index)); + st_insert(cache, (char *) key, (char *) value); + array_free(dominators); + var_set_free(remaining_vars); + var_set_free(dead_vars); + if (tmp) var_set_free(tmp); + return value->cost; +} + +static int dominator_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + dominator_t *dom1 = (dominator_t *) obj1; + dominator_t *dom2 = (dominator_t *) obj2; + + return dom1->size - dom2->size; +} + + +static int set_key_hash(k, modulus) +char *k; +int modulus; +{ + register set_key_t *key = (set_key_t *) k; + register unsigned int hash = var_set_hash(key->placed_so_far); + return hash % modulus; +} + + /* returns 0 iff equal */ +static int set_key_cmp(k1, k2) +char *k1; +char *k2; +{ + register set_key_t *key1 = (set_key_t *) k1; + register set_key_t *key2 = (set_key_t *) k2; + + return (! var_set_equal(key1->placed_so_far, key2->placed_so_far)); +} + + /* frees keys and values */ + +static void set_cache_free(cache) +st_table *cache; +{ + st_generator *gen; + set_key_t *key; + set_value_t *value; + + st_foreach_item(cache, gen, (char **) &key, (char **) &value) { + var_set_free(key->placed_so_far); + FREE(key); + FREE(value); + } + st_free_table(cache); +} + + /* check that we generate a permutation of 0->n_sets-1 */ + /* if not in hash table: means all remaining ones are equivalent */ + +static void extract_best_order_from_cache(info, cache, first_key, result) +set_info_t *info; +st_table *cache; +set_key_t *first_key; +array_t *result; +{ + int i, j; + set_key_t key; + set_value_t *value; + + key.placed_so_far = var_set_copy(first_key->placed_so_far); + assert(var_set_is_empty(key.placed_so_far)); + for (i = 0; i < info->n_sets; i++) { + if (! st_lookup(cache, (char *) &key, (char **) &value)) break; + assert(value->index >= 0 && value->index < info->n_sets); + assert(! var_set_get_elt(key.placed_so_far, value->index)); + array_insert(int, result, i, value->index); + var_set_set_elt(key.placed_so_far, value->index); + } + if (i < info->n_sets) { + for (j = 0; j < info->n_sets; j++) { + if (var_set_get_elt(key.placed_so_far, j)) continue; + array_insert(int, result, i, j); + i++; + } + } + var_set_free(key.placed_so_far); +} + + /* try to compute a good lower bound of cost of solution */ + /* that would try with each separate dominator */ + /* mask: union of variables still to be covered */ +static void compute_bounds(info, placed_so_far, mask, dominators) +set_info_t *info; +var_set_t *placed_so_far; +var_set_t *mask; +array_t *dominators; +{ + int i, j; + dominator_t *dom; + var_set_t *set = var_set_new(info->n_vars); + var_set_t *tmp = var_set_new(info->n_vars); + int n_remaining = info->n_sets - var_set_n_elts(placed_so_far); + + for (i = 0; i < array_n(dominators); i++) { + dom = array_fetch_p(dominator_t, dominators, i); + dom->bound = dom->size * n_remaining; + var_set_clear(set); + for (j = 0; j < info->n_sets; j++) { + if (j == dom->index) continue; + if (var_set_get_elt(placed_so_far, j)) continue; + (void) var_set_or(set, set, info->sets[j]); + } + (void) var_set_and(set, set, mask); + (void) var_set_not(tmp, info->sets[dom->index]); + (void) var_set_and(set, set, tmp); + dom->bound += var_set_n_elts(set); + } + var_set_free(set); + var_set_free(tmp); +} + + /* put in an dominator_t array_t info about the dominator sets */ + /* after we have eliminated the placed_so_far */ + /* (mask is complement of union of placed_so_far) */ + /* a dominator is a set that does not contain any other */ + /* we also need the size of each dominator (not counting the elts in mask) */ + /* If there is no dominator, it means that all sets are equivalent (all equal) */ + /* with respect to mask: in that case, can conclude immediately */ +static array_t *extract_dominators(info, placed_so_far, mask) +set_info_t *info; +var_set_t *placed_so_far; +var_set_t *mask; +{ + int i, j; + int is_dominator; + dominator_t dom; + array_t *result = array_alloc(dominator_t, 0); + var_set_t *dominators = var_set_new(info->n_sets); + var_set_t *tmp; + + for (i = 0; i < info->n_sets; i++) { + if (var_set_get_elt(placed_so_far, i)) continue; + is_dominator = 1; + for (j = 0; j < info->n_sets; j++) { + if (j == i) continue; + if (var_set_get_elt(placed_so_far, j)) continue; + if (set_is_less_than(info->sets[j], info->sets[i], mask, j - i)) { + is_dominator = 0; + break; + } + } + if (is_dominator) var_set_set_elt(dominators, i); + } + tmp = var_set_new(info->n_vars); + for (i = 0; i < info->n_sets; i++) { + if (! var_set_get_elt(dominators, i)) continue; + (void) var_set_and(tmp, mask, info->sets[i]); + dom.index = i; + dom.size = var_set_n_elts(tmp); + dom.cost = LARGE_NUMBER; + dom.bound = 0; + array_insert_last(dominator_t, result, dom); + } + var_set_free(dominators); + var_set_free(tmp); + return result; +} + + + /* check whether set1 inter set2 is equal to set1 (modulo mask) */ + /* should be strictly less than, thus check for equality */ + /* if equal, use diff to make the difference */ +static int set_is_less_than(set1, set2, mask, diff) +var_set_t *set1; +var_set_t *set2; +var_set_t *mask; +int diff; +{ + int result; + var_set_t *tmp1 = var_set_copy(set1); + var_set_t *tmp2 = var_set_copy(set2); + + (void) var_set_and(tmp1, tmp1, mask); + (void) var_set_and(tmp2, tmp2, mask); + if (var_set_equal(tmp1, tmp2)) { + result = (diff < 0) ? 1 : 0; + } else { + (void) var_set_and(tmp2, tmp1, tmp2); + result = var_set_equal(tmp1, tmp2); + } + var_set_free(tmp1); + var_set_free(tmp2); + return result; +} + + /* extract variables still active (i.e. complement of union of sets in key) */ +static var_set_t *extract_uncovered_variables(info, key) +set_info_t *info; +set_key_t *key; +{ + int i; + var_set_t *result = var_set_new(info->n_vars); + + for (i = 0; i < info->n_sets; i++) { + if (! var_set_get_elt(key->placed_so_far, i)) continue; + (void) var_set_or(result, result, info->sets[i]); + } + (void) var_set_not(result, result); + return result; +} + + /* for debugging */ + + + /* simple greedy heuristic */ + +array_t *find_greedy_set_order(info) +set_info_t *info; +{ + int i; + int size; + int best_next_index; + array_t *result = array_alloc(int, 0); + var_set_t *placed_so_far = var_set_new(info->n_sets); + var_set_t *mask = var_set_new(info->n_vars); + + for (i = 0; i < info->n_sets; i++) { + best_next_index = arg_min_remaining_size(info, placed_so_far, mask, &size); + array_insert_last(int, result, best_next_index); + var_set_set_elt(placed_so_far, best_next_index); + (void) var_set_or(mask, mask, info->sets[best_next_index]); + } + var_set_free(placed_so_far); + var_set_free(mask); + return result; +} + + + /* get the first remaining set of minimum size relative to remaining vars */ + /* also returns its size relative to remaining vars (vars not in mask) */ + +static int arg_min_remaining_size(info, placed_so_far, mask, min_size) +set_info_t *info; +var_set_t *placed_so_far; +var_set_t *mask; /* all those already there: do not discriminate any more */ +int *min_size; +{ + int i, size; + int best_index = -1; + int best_size = LARGE_NUMBER; + var_set_t *tmp = var_set_new(info->n_vars); + + for (i = 0; i < info->n_sets; i++) { + if (var_set_get_elt(placed_so_far, i)) continue; + size = var_set_n_elts(var_set_or(tmp, mask, info->sets[i])); + if (size < best_size) { + best_size = size; + best_index = i; + } + } + var_set_free(tmp); + *min_size = best_size - var_set_n_elts(mask); + return best_index; +} + +static void print_set_info(info) +set_info_t *info; +{ + int i, j, value; + for (i = 0; i < info->n_sets; i++) { + assert(info->sets[i]->n_elts == info->n_vars); + for (j = 0; j < info->n_vars; j++) { + value = var_set_get_elt(info->sets[i], j); + printf("%d%s", value, (j == info->n_vars - 1) ? "" : " "); + } + printf("\n"); + } +} + +static void print_int_array(data) +array_t *data; +{ + int i; + + for (i = 0; i < array_n(data); i++) { + printf("%d ", array_fetch(int, data, i)); + } + printf("\n"); +} + +static int compute_order_cost(info, order) +set_info_t *info; +array_t *order; +{ + int i; + int index; + int result = 0; + var_set_t *union_so_far = var_set_new(info->n_vars); + + for (i = 0; i < array_n(order); i++) { + index = array_fetch(int, order, i); + (void) var_set_or(union_so_far, union_so_far, info->sets[index]); + result += var_set_n_elts(union_so_far); + } + var_set_free(union_so_far); + return result; +} +#endif /* SIS */ diff --git a/sis/seqbdd/prioqueue.c b/sis/seqbdd/prioqueue.c new file mode 100644 index 0000000..c39c47f --- /dev/null +++ b/sis/seqbdd/prioqueue.c @@ -0,0 +1,366 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prioqueue.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + /* file %M% release %I% */ + /* last modified: %G% at %U% */ +/* + * Code File : prio.c + * Original Author : Antony P-C Ng + * Created : 11 Apr, 1990 + * + * Modified by : Herve' Touati + * : June, 1990 + * + ************************************************ + * >> XPSim << * + * * + * Antony P-C Ng * + * Robert K. Brayton * + * * + * Computer Science Dept, * + * 573 Evans Hall, * + * U.C. Berkeley, * + * Berkeley, CA 94720. * + * * + ************************************************ + * + * Priority queue operations. + * + * A priority queue of all active vertex-instances is maintained. + * The ordering is user-specified, thru a callback boolean function, QueueCmp. + * + * Creates a queue and returns a pointer to it. + * Should give the max_size and a comparison function + * standard UNIX comparision function (e.g. as in qsort). + * It returns an integer that is negative if V1 < V2, + * positive if V1 > V2, and 0 iff V1 == V2 in the ordering. + * The print_fn is used to print entries. NIL is OK there (nothing will be printed) + * + * + * queue_t *init_queue(max_size, cmp, print_fn) + * int max_size; + * int (*cmp)(); + * void (*print_fn)(); + * + * free the storage associated with a queue. + * + * void free_queue(queue) + * queue_t *queue; + * + * inserts an pointer to an object into the priority queue. + * (char *) is understood as generic pointer. The actual type + * of the object should be the one expected by the cmp function. + * + * void put_queue(queue, ptr) + * queue_t *queue; + * char *ptr; + * + * gets a pointer to the object at the top of the queue + * and pops it from the queue. + * + * char *get_queue(queue) + * queue_t *queue; + * + * gets a pointer to the object at the top of the queue + * but does not pop it from the queue. + * + * char *top_queue(queue) + * queue_t *queue; + * + * adjusts the ordering of an object already in the queue. + * makes no assumption about the direction of the adjustment. + * + * void adj_queue(queue, ptr) + * queue_t *queue; + * char *ptr; + * + * adjusts the ordering of an object already in the queue. + * expects the priority of the object not to have decreased. + * + * void adj_up_queue(queue, ptr) + * queue_t *queue; + * char *ptr; + * + * adjusts the ordering of an object already in the queue. + * expects the priority of the object not to have increased. + * + * void adj_up_queue(queue, ptr) + * queue_t *queue; + * char *ptr; + * + * returns the number of elements in the queue. + * + * int queue_size(queue) + * queue_t *queue; + * + */ +#ifdef SIS +#include "sis.h" +#include "prioqueue.h" + +static void SiftUp(); +static void SiftDown(); + +/* + * Allocate the heap-array. Note that the queue-pointer is decremented. This is + * because Heap accesses start at 1. + */ + +queue_t *init_queue(max_size, cmp_fn, print_fn) +int max_size; +IntFn cmp_fn; +VoidFn print_fn; +{ + int i; + queue_t *result = ALLOC(queue_t, 1); + + result->Queue = ALLOC(queue_entry_t *, max_size); + for (i = 0; i < max_size; i++) { + result->Queue[i] = NIL(queue_entry_t); + } + result->Queue--; + result->MaxQSize = max_size; + result->QueueCmp = cmp_fn; + result->print_entry = print_fn; + result->table = st_init_table(st_ptrcmp, st_ptrhash); + result->NumInQueue = 0; + return result; +} + + /* have to restore the Queue pointer to the ALLOC'ed address */ + +void free_queue(queue) +queue_t *queue; +{ + st_free_table(queue->table); + queue->Queue++; + FREE(queue->Queue); + FREE(queue); +} + +/* + * Standard heap sifting routines. + */ + +static void SiftUp(queue, SiftIndx ) +queue_t *queue; +int SiftIndx; +{ + queue_entry_t *entry; + int NextIndx; + + entry = queue->Queue[SiftIndx]; + while( SiftIndx > 1 ) { + NextIndx = SiftIndx / 2; + if((*(queue->QueueCmp))(entry->VPtr , queue->Queue[NextIndx]->VPtr) >= 0 ) break; + queue->Queue[SiftIndx] = queue->Queue[NextIndx]; + queue->Queue[SiftIndx]->QPosn = SiftIndx; + SiftIndx = NextIndx; + } + queue->Queue[SiftIndx] = entry; + queue->Queue[SiftIndx]->QPosn = SiftIndx; +} + +static void SiftDown(queue, SiftIndx) +queue_t *queue; +int SiftIndx; +{ + queue_entry_t *entry; + int NextIndx; + + entry = queue->Queue[SiftIndx]; + while(( NextIndx = SiftIndx * 2 ) <= queue->NumInQueue ) { + if(NextIndx < queue->NumInQueue && + (*(queue->QueueCmp))(queue->Queue[NextIndx+1]->VPtr, queue->Queue[NextIndx]->VPtr) < 0) { + NextIndx++; + } + if((*(queue->QueueCmp))(entry->VPtr, queue->Queue[NextIndx]->VPtr) <= 0) break; + queue->Queue[SiftIndx] = queue->Queue[NextIndx]; + queue->Queue[SiftIndx]->QPosn = SiftIndx; + SiftIndx = NextIndx; + } + queue->Queue[SiftIndx] = entry; + queue->Queue[SiftIndx]->QPosn = SiftIndx; +} + + +void put_queue(queue, VPtr) +queue_t *queue; +char *VPtr; +{ + queue_entry_t *new_entry; + + assert(queue->NumInQueue < queue->MaxQSize); + queue->NumInQueue++; + new_entry = ALLOC(queue_entry_t, 1); + queue->Queue[queue->NumInQueue] = new_entry; + new_entry->VPtr = VPtr; + new_entry->QPosn = queue->NumInQueue; + st_insert(queue->table, VPtr, (char *) new_entry); + SiftUp(queue, queue->NumInQueue); +} + +char *get_queue(queue) +queue_t *queue; +{ + char *VPtr; + queue_entry_t *entry; + + if (queue->NumInQueue == 0) return NIL(char); + VPtr = queue->Queue[1]->VPtr; + (void) st_delete(queue->table, (char **) &VPtr, (char **) &entry); + assert(entry == queue->Queue[1]); + FREE(entry); + queue->Queue[1] = queue->Queue[queue->NumInQueue]; + queue->NumInQueue--; + if (queue->NumInQueue > 0) { + queue->Queue[1]->QPosn = 1; + SiftDown(queue, 1); + } + return VPtr; +} + +char *top_queue(queue) +queue_t *queue; +{ + if (queue->NumInQueue == 0) return NIL(char); + return queue->Queue[1]->VPtr; +} + +void adj_queue(queue, VPtr) +queue_t *queue; +char *VPtr; +{ + queue_entry_t *entry; + + assert(st_lookup(queue->table, VPtr, (char **) &entry)); + SiftUp(queue, entry->QPosn); + SiftDown(queue, entry->QPosn); +} + +void adj_up_queue(queue, VPtr) +queue_t *queue; +char *VPtr; +{ + queue_entry_t *entry; + + assert(st_lookup(queue->table, VPtr, (char **) &entry)); + SiftUp(queue, entry->QPosn); +} + +void adj_down_queue(queue, VPtr) +queue_t *queue; +char *VPtr; +{ + queue_entry_t *entry; + + assert(st_lookup(queue->table, VPtr, (char **) &entry)); + SiftDown(queue, entry->QPosn); +} + +int queue_size(queue) +queue_t *queue; +{ + return queue->NumInQueue; +} + +/* ------------------------------------------------------------------------- */ + +/* + * Consistency Check on queues. + */ + +/* + * Display the queue. + */ + +void print_queue(queue) +queue_t *queue; +{ + int Indx , Stop; + + fprintf(misout, "priority queue\n\t"); + Stop = 2; + for( Indx = 1 ; Indx <= queue->NumInQueue ; ++ Indx ) { + if( Indx == Stop ) { + fprintf(misout, "\n\t"); + Stop *= 2; + } + (*(queue->print_entry))(queue->Queue[Indx]->VPtr); + fprintf(misout, " "); + } + fprintf(misout, "\n"); +} + +/* + * Check queue for consistency. Returns 0 if everything is OK. + */ + +int CheckQueue(queue) +queue_t *queue; +{ + int Indx; + int CheckFailed; + st_generator *gen; + char *VPtr; + queue_entry_t *entry; + + CheckFailed = 0; + + /* + * Check that Queue positions are correct + */ + + for( Indx = 1 ; Indx <= queue->NumInQueue ; ++ Indx ) { + if( Indx != queue->Queue[Indx]->QPosn ) { + fprintf(miserr, "\nQueue Position, Computed=%d, Stored=%d.", Indx , queue->Queue[Indx]->QPosn); + CheckFailed = 1; + } + } + + /* + * Check that the ordering relations are correct + */ + + for( Indx = 2 ; Indx <= queue->NumInQueue ; ++ Indx ) { + if((*(queue->QueueCmp))(queue->Queue[Indx/2]->VPtr, queue->Queue[Indx]->VPtr) > 0) { + (void) fprintf(misout, "\nQueue Ordering Mixup:" ); + (void) fprintf(misout, "\n\tPosn %3d, Entry ", Indx/2); + (*(queue->print_entry))(queue->Queue[Indx/2]->VPtr); + (void) fprintf(misout, "\n\tPosn %3d, Entry ", Indx); + (*(queue->print_entry))(queue->Queue[Indx]->VPtr); + (void) fprintf(misout, "\n"); + CheckFailed = 1; + } + } + + /* check that the entries have all the right index */ + if (st_count(queue->table) != queue->NumInQueue) { + (void) fprintf(misout, "\nQueue Accounting Mixup: queue->%d, table->%d\n", queue->NumInQueue, st_count(queue->table)); + CheckFailed = 1; + } + st_foreach_item(queue->table, gen, &VPtr, (char **) &entry) { + if (entry->VPtr != VPtr) { + (void) fprintf(misout, "\nEntry Mixup: entry->0x%x, ptr->0x%x\n", entry->VPtr, VPtr); + CheckFailed = 1; + } + if (entry->QPosn < 1 || entry->QPosn > queue->NumInQueue) { + (void) fprintf(misout, "\nEntry Mixup: out of range: 1 <= %d <= %d\n", entry->QPosn, queue->NumInQueue); + CheckFailed = 1; + } + if (queue->Queue[entry->QPosn] != entry) { + (void) fprintf(misout, "\nEntry Mixup: entry->0x%x, actual->0x%x\n", entry, queue->Queue[entry->QPosn]); + CheckFailed = 1; + } + } + + return(! CheckFailed); +} +#endif /* SIS */ + diff --git a/sis/seqbdd/prioqueue.h b/sis/seqbdd/prioqueue.h new file mode 100644 index 0000000..d3942e6 --- /dev/null +++ b/sis/seqbdd/prioqueue.h @@ -0,0 +1,36 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prioqueue.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + /* file %M% release %I% */ + /* last modified: %G% at %U% */ +typedef struct { + char *VPtr; + int QPosn; /* there for historical reasons. Updated but not used anywhere */ +} queue_entry_t; + +typedef struct { + int MaxQSize; + int NumInQueue; + IntFn QueueCmp; + VoidFn print_entry; + queue_entry_t **Queue; + st_table *table; /* maps the external VPtr's to the corresponding queue_entry_t * in Queue */ +} queue_t; + +extern queue_t *init_queue(/* int max_size; int (*cmp)(); void (*print_fn)() */); +extern void free_queue(/* queue_t *queue */); +extern void put_queue(/* queue_t *queue; char *ptr */); +extern char *get_queue(/* queue_t *queue */); +extern char *top_queue(/* queue_t *queue */); +extern void adj_queue(/* queue_t *queue; char *ptr */); +extern void adj_up_queue(/* queue_t *queue; char *ptr */); +extern void adj_down_queue(/* queue_t *queue; char *ptr */); +extern int queue_size(/* queue_t *queue */); +extern void print_queue(/* queue_t *queue */); +extern void check_queue(/* queue_t *queue */); diff --git a/sis/seqbdd/prl_dep.c b/sis/seqbdd/prl_dep.c new file mode 100644 index 0000000..d298cf5 --- /dev/null +++ b/sis/seqbdd/prl_dep.c @@ -0,0 +1,361 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prl_dep.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + +#ifdef SIS +#include "sis.h" +#include "prl_seqbdd.h" + +static int CheckInput ARGS((network_t *, array_t *)); +static array_t *ExtractPiTfo ARGS((network_t *, node_t *)); +static void BlowAwayDependencies ARGS((array_t *, st_table *)); + +/* + *---------------------------------------------------------------------- + * + * Prl_RemoveDependencies -- EXPORTED ROUTINE + * + * Given an external PI and a list of external PO + * remove the structural dependencies between the POs and the PI. + * When the 'perform_check' flag is on, check that the dependencies + * to be removed are structural but not logical. + * + * Results: + * 1 iff the check fails. + * + * Side effects: + * The network is modified in place. + * + *---------------------------------------------------------------------- + */ + +static prl_removedep_t prl_dep_options; + +int Prl_RemoveDependencies(network, nodevec, options) +network_t *network; +array_t *nodevec; +prl_removedep_t *options; +{ + int i; + node_t *pi, *po; + array_t *pi_tfo; + st_table *po_tfi; + + if (CheckInput(network, nodevec)) return 1; /* wrong input */ + if (array_n(nodevec) == 1) return 0; /* nothing to do */ + prl_dep_options = *options; + + /* + * Allocate: + * 1. an array of nodes containing the TFI of 'pi' + * 2. a hash table, that will eventually contain the TFO of the 'po'. + * + */ + + pi = array_fetch(node_t *, nodevec, 0); + pi_tfo = ExtractPiTfo(network, pi); + po_tfi = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 1; i < array_n(nodevec); i++) { + po = array_fetch(node_t *, nodevec, i); + st_insert(po_tfi, (char *) po, NIL(char)); + if (prl_dep_options.verbosity) { + (void) fprintf(sisout, "PO \"%s\" is a root\n", io_name(po, 0)); + } + } + BlowAwayDependencies(pi_tfo, po_tfi); + st_free_table(po_tfi); + array_free(pi_tfo); + + /* + * Finally, sweep the network + */ + + network_sweep(network); + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * CheckInput -- INTERNAL ROUTINE + * + * Given a list of nodes, make sure that the first node is an external PI + * and the remaining nodes are external POs. + * + * Results: + * 1 iff the check fails. + * + *---------------------------------------------------------------------- + */ + + +static int CheckInput(network, nodevec) +network_t *network; +array_t *nodevec; +{ + int i; + node_t *pi, *po; + + if (array_n(nodevec) == 0) return 1; + pi = array_fetch(node_t *, nodevec, 0); + if (! network_is_real_pi(network, pi)) return 1; + for (i = 1; i < array_n(nodevec); i++) { + po = array_fetch(node_t *, nodevec, i); + if (! network_is_real_po(network, po)) return 1; + } + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * ExtractPiTfo -- INTERNAL ROUTINE + * + * Given a primary input, returns an array of nodes containing + * exactly those nodes in the transitive fanout of the PI. + * The nodes are sorted in topological order. + * + * Results: + * An array of nodes. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static array_t *ExtractPiTfo(network, pi) +network_t *network; +node_t *pi; +{ + int i, j; + node_t *node, *fanin; + st_table *roots = st_init_table(st_ptrcmp, st_ptrhash); + array_t *pi_tfo = array_alloc(node_t *, 0); + array_t *nodevec = network_dfs(network); + + st_insert(roots, (char *) pi, NIL(char)); + array_insert_last(node_t *, pi_tfo, pi); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + foreach_fanin(node, j, fanin) { + if (! st_lookup(roots, (char *) fanin, NIL(char*))) continue; + st_insert(roots, (char *) node, NIL(char)); + array_insert_last(node_t *, pi_tfo, node); + break; + } + } + st_free_table(roots); + array_free(nodevec); + return pi_tfo; +} + + +static array_t *GetRootFanouts ARGS((node_t *, st_table *)); +static node_t *ProcessInternalNode ARGS((node_t *, array_t *)); +static void ProcessPrimaryInput ARGS((node_t *, array_t *)); + +/* + *---------------------------------------------------------------------- + * + * BlowAwayDependencies -- INTERNAL ROUTINE + * + * Given an array of nodes in topological order, + * and a set of roots at their outputs, + * apply the following algorithm: + * 1. visit the nodes from outputs to inputs (reverse order) + * 1.a if the node is a primary output, skip it + * 1.b examine the fanouts of the node. + * 1.c If none of the fanouts belong to the set 'root', skip the node. + * 1.d If some of the fanouts belong to the set 'root', add the node + * to the set root. + * 1.e If all the fanouts belong to the set 'root', skip the node. + * 1.f If some but not all of the fanouts belong to the set 'root', + * and the node is not a primary input, + * make a copy of the node. + * Move the fanouts of the node that do not belong to the set 'root' + * to the newly created node. + * 1.g If some but not all of the fanouts belong to the set 'root', + * and the node is a primary input, create a constant node, + * move the fanouts of the node that belong to the set 'root' + * to the newly created node. + * 2. sweep the network. + * + * Results: + * None. + * + * Side effects: + * The network is modified in place.a + * + *---------------------------------------------------------------------- + */ + +static void BlowAwayDependencies(nodes, roots) +array_t *nodes; +st_table *roots; +{ + int i; + int all_roots; + int none_roots; + node_t *node; + node_t *root; + array_t *root_fanouts; + + for (i = array_n(nodes) - 1; i >= 0; i--) { + node = array_fetch(node_t *, nodes, i); + if (prl_dep_options.verbosity) { + (void) fprintf(sisout, "process node \"%s\"\n", node->name); + } + if (node->type == PRIMARY_OUTPUT) continue; + root_fanouts = GetRootFanouts(node, roots); + if (node->type == INTERNAL) { + root = ProcessInternalNode(node, root_fanouts); + st_insert(roots, (char *) root, NIL(char)); + if (prl_dep_options.verbosity) { + (void) fprintf(sisout, "node \"%s\" is a new root\n", node->name); + } + } else if (node->type == PRIMARY_INPUT) { + ProcessPrimaryInput(node, root_fanouts); + } + array_free(root_fanouts); + } +} + + +/* + *---------------------------------------------------------------------- + * + * GetRootFanouts -- INTERNAL ROUTINE + * + * Results: + * An array of the non root fanouts of 'node'. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static array_t *GetRootFanouts(node, roots) +node_t *node; +st_table *roots; +{ + lsGen gen; + node_t *fanout; + array_t *root_fanouts = array_alloc(node_t *, 0); + + foreach_fanout(node, gen, fanout) { + if (st_lookup(roots, (char *) fanout, NIL(char *))) { + array_insert_last(node_t *, root_fanouts, fanout); + } + } + return root_fanouts; +} + + +static void PatchFanin ARGS((array_t *, node_t *, node_t *)); + +/* + *---------------------------------------------------------------------- + * + * ProcessInternalNode -- INTERNAL ROUTINE + * + * Results: + * The node that supports the nodes in 'root_fanouts', if any. + * + * Side effects: + * The node may be duplicated. + * + *---------------------------------------------------------------------- + */ + +static node_t *ProcessInternalNode(node, root_fanouts) +node_t *node; +array_t *root_fanouts; +{ + node_t *copy; + + if (array_n(root_fanouts) == 0) return NIL(node_t); + if (array_n(root_fanouts) == node_num_fanout(node)) return node; + copy = node_dup(node); + if (copy->name != NIL(char)) { + FREE(copy->name); + copy->name = NIL(char); + } + network_add_node(node->network, copy); + PatchFanin(root_fanouts, node, copy); + return copy; +} + + +/* + *---------------------------------------------------------------------- + * + * ProcessPrimaryInput -- INTERNAL ROUTINE + * + * Results: + * None. + * + * Side effects: + * A constant is inserted to feed the nodes in 'root_fanouts'. + * + *---------------------------------------------------------------------- + */ + +static void ProcessPrimaryInput(node, root_fanouts) +node_t *node; +array_t *root_fanouts; +{ + node_t *copy; + + if (array_n(root_fanouts) == 0) return; + copy = node_constant(prl_dep_options.insert_a_one); + network_add_node(node->network, copy); + PatchFanin(root_fanouts, node, copy); +} + +/* + *---------------------------------------------------------------------- + * + * PatchFanin -- INTERNAL ROUTINE + * + * Results: + * None. + * + * Side effects: + * Replaces 'old' by 'new' as an input for all nodes in 'nodevec'. + * + *---------------------------------------------------------------------- + */ + +static void PatchFanin(nodevec, old, new) +array_t *nodevec; +node_t *old; +node_t *new; +{ + int i; + node_t *node; + + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + (void) node_patch_fanin(node, old, new); + node_scc(node); + if (prl_dep_options.verbosity) { + (void) fprintf(sisout, + "move input of \"%s\" from \"%s\" to \"%s\"\n", + node->name, + old->name, + new->name); + } + } +} + +#endif /* SIS */ diff --git a/sis/seqbdd/prl_equiv.c b/sis/seqbdd/prl_equiv.c new file mode 100644 index 0000000..51b9879 --- /dev/null +++ b/sis/seqbdd/prl_equiv.c @@ -0,0 +1,384 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prl_equiv.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + +#ifdef SIS +#include "sis.h" +#include "prl_util.h" + + /* EXTERNAL INTERFACE */ + + /* 'equiv_nets' performs the following optimization: + * 1. for each net in the network, computes the BDD representing + * the Boolean function of that net in terms of PIs. + * 2. use the external don't care (e.g. reachability) + * and cofactor the BDD at each net by the EXDC. + * 3. group the nets by equivalence class, were n1 and n2 + * are equivalent iff they are always equal or always + * the negation of each other in the don't care set. + * 4. for each equivalence class, select a net of smallest depth + * and move the fanouts of all the other nets of that class + * to that net, inserting inverters whenever necessary. + * 5. sweeps the network to remove the dead logic. + * + * We take the Boolean and of all output don't cares. + * + * Since it may remove latches on which the dc_network may depend + * this routine removes the dc_network when it is done. + */ + +static void equiv_nets ARGS((network_t *, seq_info_t *, bdd_t *, prl_options_t *)); + +void Prl_EquivNets(network, options) +network_t *network; +prl_options_t *options; +{ + seq_info_t *seq_info; + bdd_t *reachable_states, *seq_dc; + + seq_info = Prl_SeqInitNetwork(network, options); + seq_dc = Prl_GetSimpleDc(seq_info); + if (network->dc_network != NIL(network_t) && bdd_is_tautology(seq_dc, 0)) { + (void) fprintf(siserr, "no reachability information found in don't care network\n"); + } + equiv_nets(network, seq_info, seq_dc, options); + bdd_free(seq_dc); + Prl_SeqInfoFree(seq_info, options); + Prl_RemoveDcNetwork(network); +} + + + /* INTERNAL INTERFACE */ + +typedef struct net_info_struct net_info_t; + +struct net_info_struct { + node_t *node; /* source of the net */ + int index; /* index of the net in the array of nets */ + int root_index; /* smallest index of an equivalent net */ + array_t *equiv_array; /* array of nets equivalent to this one; empty if index > root_index */ + net_info_t *best_member; /* best node to be taken as source among all nodes in equiv_array */ + long depth; /* depth of source of this node */ + long cost; /* cost of using this node as source for all equiv nets */ + bdd_t *fn; /* value of the net; after cofactoring */ + bdd_t *inv_fn; /* not(value) of the net; after cofactoring */ +}; + +static void initialize_net_entry ARGS((seq_info_t *, net_info_t *, node_t *, int, bdd_t *)); +static void compute_equivalence_classes ARGS((int, net_info_t *)); +static void report_equivalence_classes ARGS((int, net_info_t *)); +static int skip_this_net ARGS((net_info_t *)); +static void collapse_equiv_nets ARGS((net_info_t *, prl_options_t *)); + +static void equiv_nets(network, seq_info, dc, options) +network_t *network; +seq_info_t *seq_info; +bdd_t *dc; +prl_options_t *options; +{ + int i; + lsGen gen; + int node_count; + int n_nets; + node_t *node; + net_info_t *net_info; + bdd_t *care_set; + + n_nets = network_num_internal(network) + network_num_pi(network); + net_info = ALLOC(net_info_t, n_nets); + node_count = 0; + care_set = bdd_not(dc); + + if (options->verbose > 0) { + (void) fprintf(sisout, "build BDDs for equivalence computation ... \n"); + } + foreach_node(network, gen, node) { + if (node->type == PRIMARY_OUTPUT) continue; + initialize_net_entry(seq_info, &(net_info[node_count]), node, node_count, care_set); + node_count++; + } + assert(node_count == n_nets); + if (options->verbose > 0) { + (void) fprintf(sisout, "compute equivalence classes ... \n"); + } + compute_equivalence_classes(n_nets, net_info); + if (options->verbose > 0) { + report_equivalence_classes(n_nets, net_info); + } + if (options->verbose > 0) { + (void) fprintf(sisout, "collapse equivalent nets ... \n"); + } + for (i = 0; i < n_nets; i++) { + if (skip_this_net(&(net_info[i]))) continue; + collapse_equiv_nets(&(net_info[i]), options); + } + + bdd_free(care_set); + for (i = 0; i < n_nets; i++) { + array_free(net_info[i].equiv_array); + } + FREE(net_info); +} + + /* skip all entries that either are not equivalence classes */ + /* or are equivalence classes with only one element */ + +static int skip_this_net(net_info) +net_info_t *net_info; +{ + if (net_info->root_index < net_info->index) return 1; + if (array_n(net_info->equiv_array) <= 1) return 1; + return 0; +} + +static void initialize_net_entry(seq_info, net_info, node, index, care_set) +seq_info_t *seq_info; +net_info_t *net_info; +node_t *node; +int index; +bdd_t *care_set; +{ + bdd_t *fn; + + net_info->node = node; + net_info->index = index; + net_info->root_index = index; + net_info->cost = INFINITY; + net_info->best_member = NIL(net_info_t); + net_info->equiv_array = array_alloc(net_info_t *, 0); + array_insert_last(net_info_t *, net_info->equiv_array, net_info); + fn = ntbdd_node_to_bdd(node, seq_info->manager, seq_info->leaves); + assert(fn != NIL(bdd_t)); + if (bdd_is_tautology(care_set, 0)) { + net_info->fn = bdd_dup(care_set); + net_info->inv_fn = bdd_not(care_set); + } else { + net_info->fn = bdd_cofactor(fn, care_set); + net_info->inv_fn = bdd_not(net_info->fn); + } +} + + /* + * we use a couple of invariants: + * (1) root_index < index iff visited net belongs to an equiv class + * with at least one member with smaller index. The smallest index + * among all members of this class is root_index. + */ + +static void compute_equivalence_classes(n_nets, net_info) +int n_nets; +net_info_t *net_info; +{ + int i, j; + + for (i = 0; i < n_nets; i++) { + assert(net_info[i].index == i); + if (net_info[i].root_index < net_info[i].index) continue; + for (j = i + 1; j < n_nets; j++) { + if (net_info[j].root_index < net_info[j].index) continue; + if (bdd_equal(net_info[i].fn, net_info[j].fn)) { + array_insert_last(net_info_t *, net_info[i].equiv_array, &(net_info[j])); + net_info[j].root_index = i; + } else if (bdd_equal(net_info[i].inv_fn, net_info[j].fn)) { + array_insert_last(net_info_t *, net_info[i].equiv_array, &(net_info[j])); + net_info[j].root_index = i; + } + } + } +} + +/* + * Prints the equivalence classes on stdout. + */ + +static void report_equivalence_classes(n_nets, net_info) +int n_nets; +net_info_t *net_info; +{ + int i; + int max_size; + int *stats; + int n_classes; + + max_size = 1; + for (i = 0; i < n_nets; i++) { + max_size = MAX(max_size, array_n(net_info[i].equiv_array)); + } + + n_classes = 0; + stats = ALLOC(int, max_size + 1); + for (i = 0; i <= max_size; i++) { + stats[i] = 0; + } + for (i = 0; i < n_nets; i++) { + if (net_info[i].root_index < net_info[i].index) continue; + stats[array_n(net_info[i].equiv_array)]++; + n_classes++; + } + (void) fprintf(sisout, "Report on net equivalence classes:\n"); + (void) fprintf(sisout, "Total Number of Classes: %d\n", n_classes); + if (n_classes > 0) { + for (i = 1; i <= max_size; i++) { + (void) fprintf(sisout, "classes of size %d: %d %2.2f%%\n", + i, + stats[i], + 100 * (double) stats[i] / n_classes); + } + } + FREE(stats); +} + +/* + * Work on an equivalence class basis. + * First: compute the costs: based on depth, then on amount of logic that can be removed. + * depth is important: guarantees that we are not creating cycles. + * + * For each equivalence class containing more than one element + * move the fanouts of all members to the best_member of the class. + * 'best_member' has been computing earlier, as the best choice within the class. + */ + +static void compute_node_cost_rec ARGS((node_t *, st_table *, st_table *)); +static void MoveFanout ARGS((node_t *, node_t *)); + +static void collapse_equiv_nets(net_info, options) +net_info_t *net_info; +prl_options_t *options; +{ + int i; + int is_inverted; + int best_cost, best_depth; + node_t *inv_node, *source_node; + net_info_t *net; + st_table *cost_table, *depth_table; + + /* compute the best node to be used as root for all of the equiv nets */ + + cost_table = st_init_table(st_ptrcmp, st_ptrhash); + depth_table = st_init_table(st_ptrcmp, st_ptrhash); + best_cost = INFINITY; + best_depth = INFINITY; + + for (i = 0; i < array_n(net_info->equiv_array); i++) { + net = array_fetch(net_info_t *, net_info->equiv_array, i); + compute_node_cost_rec(net->node, cost_table, depth_table); + assert(st_lookup(cost_table, (char *) net->node, (char **) &(net->cost))); /* long cost */ + assert(st_lookup(depth_table, (char *) net->node, (char **) &(net->depth))); /* long depth */ + if (options->verbose > 0) { + (void) fprintf(sisout, "source %s depth=%d cost=%d\n", net->node->name, net->depth, net->cost); + } + if (net->depth < best_depth || (net->depth == best_depth && net->cost < best_cost)) { + best_depth = net->depth; + best_cost = net->cost; + net_info->best_member = net; + } + } + st_free_table(cost_table); + st_free_table(depth_table); + + + /* perform the collapsing */ + + source_node = net_info->best_member->node; + inv_node = node_literal(source_node, 0); + network_add_node(node_network(source_node), inv_node); + + for (i = 0; i < array_n(net_info->equiv_array); i++) { + net = array_fetch(net_info_t *, net_info->equiv_array, i); + if (bdd_equal(net->fn, net_info->best_member->fn)) { + MoveFanout(net->node, source_node); + } else { + assert(bdd_equal(net->fn, net_info->best_member->inv_fn)); + MoveFanout(net->node, inv_node); + } + if (options->verbose > 0) { + (void) fprintf(sisout, "move fanout of node %s to node %s ", net->node->name, source_node->name); + if (bdd_equal(net->fn, net_info->best_member->inv_fn)) { + (void) fprintf(sisout, "(inverted -> %s)", inv_node->name); + } + (void) fprintf(sisout, "\n"); + } + } +} + +static void compute_node_cost_rec(node, cost_table, depth_table) +node_t *node; +st_table *cost_table; +st_table *depth_table; +{ + int i; + long fanin_cost, fanin_depth; + long cost, depth; + node_t *fanin; + + if (st_lookup(cost_table, (char *) node, NIL(char *))) return; + cost = (node_num_fanout(node) == 1) ? node_num_literal(node) : 0; + depth = 0; + foreach_fanin(node, i, fanin) { + compute_node_cost_rec(fanin, cost_table, depth_table); + assert(st_lookup(cost_table, (char *) fanin, (char **) &fanin_cost)); /* long fanin_cost */ + assert(st_lookup(depth_table, (char *) fanin, (char **) &fanin_depth)); /* long fanin_depth */ + cost += fanin_cost; + depth = MAX(depth, 1 + fanin_depth); + } + st_insert(cost_table, (char *) node, (char *) cost); + st_insert(depth_table, (char *) node, (char *) depth); +} + + +/* + *---------------------------------------------------------------------- + * + * MoveFanout -- INTERNAL ROUTINE + * + * Takes the fanout of 'from' and move it to 'to'. + * The copying of the fanouts into an array is necessary: + * not a good idea to iterate on a list while each iteration + * removes an element of the list. Safer this way. + * The call to 'node_scc' is necessary to make sure that + * there is no duplicated fanin after the optimization. + * + * Results: + * None. + * + * Side effects: + * 1. all the fanouts of 'from' are moved to 'to'. + * 2. all fanout nodes are minimized using 'node_scc'. + * + *---------------------------------------------------------------------- + */ + +static void MoveFanout(from, to) +node_t *from; +node_t *to; +{ + int i; + lsGen gen; + int n_fanouts; + node_t *fanout; + node_t **fanouts; + + if (from == to) return; + n_fanouts = node_num_fanout(from); + fanouts = ALLOC(node_t *, n_fanouts); + i = 0; + + foreach_fanout(from, gen, fanout) { + fanouts[i++] = fanout; + } + + for (i = 0; i < n_fanouts; i++) { + (void) node_patch_fanin(fanouts[i], from, to); + node_scc(fanouts[i]); + } + + FREE(fanouts); +} +#endif /* SIS */ + diff --git a/sis/seqbdd/prl_extract.c b/sis/seqbdd/prl_extract.c new file mode 100644 index 0000000..e81a7bb --- /dev/null +++ b/sis/seqbdd/prl_extract.c @@ -0,0 +1,1182 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prl_extract.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + + /* this file provides the basic functions of the sequential BDD package */ + +#include "sis.h" +#include "prl_seqbdd.h" +#include "prl_util.h" + +static void ExtractBddVars ARGS((seq_info_t *, network_t *, array_t *, array_t *)); +static int AddEnvFsm ARGS((network_t *, network_t *, array_t *)); +static bdd_t *MakeFsmInputRelation ARGS((seq_info_t *, array_t *)); +static void FreeConnectionArray ARGS((array_t *)); + +typedef struct { + char *input_name; /* a copy of the name of an external PI in fsm */ + + node_t *copy_output; /* the node to which 'pi' is attached after performing (env x fsm) */ + /* if the PI is still around, this is NIL */ + + node_t *pi; /* the original PI if it is still in (env x fsm) */ + /* nil otherwise (mutually exclusive with 'copy_output') */ +} Connection; + +/* + *---------------------------------------------------------------------- + * + * Prl_ExtractEnvDc -- EXPORTED ROUTINE + * + * Enumerates all the reachable states of the product (env x fsm) + * and put as combinational logic don't care network + * the set of possible (fsm states x fsm inputs) given the env constraint. + * + * Results: + * None. + * + * Side effects: + * The old DC network of 'fsm_network' is lost. + * A new DC network is computed as the set of possible + * (input x state) patterns that can occur during operation + * of the system (fsm_network x env_network) and is stored + * as 'fsm_network->dc_network'. + * + *---------------------------------------------------------------------- + */ + +int Prl_ExtractEnvDc(fsm_network, env_network, options) +network_t *fsm_network; +network_t *env_network; +prl_options_t *options; +{ + network_t *product_network; + network_t *dc_network; + seq_info_t *seq_info; + bdd_t *reachable_states; + array_t *env_vars; /* input vars as well as state vars of the env_network */ + array_t *fsm_state_vars; + bdd_t *fsm_reachable_transitions; + bdd_t *fsm_input_relation; + bdd_t *fsm_reachable_states; + bdd_t *seq_dc; + array_t *controlled_fsm_inputs; + array_t *input_names; + int status = 0; + + Prl_RemoveDcNetwork(fsm_network); + + /* enumerate product machine */ + controlled_fsm_inputs = array_alloc(Connection, 0); + + product_network = network_dup(fsm_network); + if (AddEnvFsm(product_network, env_network, controlled_fsm_inputs)) { + status = 1; + } else { + seq_info = Prl_SeqInitNetwork(product_network, options); + reachable_states = Prl_ExtractReachableStates(seq_info, options); + env_vars = array_alloc(bdd_t *, 0); + fsm_state_vars = array_alloc(bdd_t *, 0); + ExtractBddVars(seq_info, env_network, env_vars, fsm_state_vars); + + /* make the input BDDs */ + fsm_input_relation = MakeFsmInputRelation(seq_info, controlled_fsm_inputs); + + /* smooth away the free inputs and state vars of env network */ + fsm_reachable_transitions = bdd_and_smooth(reachable_states, fsm_input_relation, env_vars); + + /* extract fsm seq dc */ + bdd_free(reachable_states); + array_free(env_vars); + array_free(fsm_state_vars); + seq_dc = bdd_not(fsm_reachable_transitions); + bdd_free(fsm_reachable_transitions); + + /* build dc network */ + if (bdd_is_tautology(seq_dc, 0)) { + Prl_RemoveDcNetwork(fsm_network); + } else { + input_names = (*options->extract_network_input_names)(seq_info, options); + dc_network = ntbdd_bdd_single_to_network(seq_dc, "foo", input_names); + Prl_StoreAsSingleOutputDcNetwork(fsm_network, dc_network); + Prl_CleanupDcNetwork(fsm_network); + array_free(input_names); + } + bdd_free(seq_dc); + Prl_SeqInfoFree(seq_info, options); + } + + network_free(product_network); + FreeConnectionArray(controlled_fsm_inputs); + return status; +} + + +EXTERN char *io_name ARGS((node_t *, int)); +static int CopyRealPo ARGS((network_t *, node_t *, char *)); +static void CopyLatchPo ARGS((network_t *, node_t *, char *, node_t *)); + +/* + *---------------------------------------------------------------------- + * + * AddEnvFsm -- INTERNAL ROUTINE + * + * Makes the product of two networks. + * They can be arbitrary; when the input name of one + * matches the output name of the other, a connection is created. + * The resulting connections are returned in the Connect array. + * Also makes sure that each PI is pointing towards the corresponding PI + * in the original network. + * Also, returns an array of pointers, in the result network, to nodes + * that correspond to primary inputs in to_network and have been realized + * by logic copied from env_network. + * + * Results: + * Returns 0 iff everything went all right. + * + * Side effects: + * 1. Appends to the array 'connections' records of the form: + * (pi,po,copy) where 'pi' belongs to 'to_network', 'po' belongs to 'env_network', + * and 'copy' belongs to the new network. 'copy' is the copy in + * the new network of 'po'. 'pi' is an external PI + * in 'to_network'. 'pi' and 'po' have the same external name. + * 2. The 'copy' fields of the nodes in 'env_network' are modified. + * 3. 'to_network' is modified in place. + * + *---------------------------------------------------------------------- + */ + +static int AddEnvFsm(to_network, env_network, connections) +network_t *to_network; +network_t *env_network; +array_t *connections; /* PI of to_network connected to PO of env_network */ +{ + int i; + char* pi_name; + lsGen gen; + node_t *pi; + node_t* fanout; + node_t *env_fanin, *env_output; + node_t *copy_output; + char* output_name; + Connection connection; + + /* + * 'Prl_SetupCopyFields' guarantees that inputs of 'env_network' + * that are fed by outputs of 'to_network' + * are directly connected to the outputs of 'to_network'. + */ + + Prl_SetupCopyFields(to_network, env_network); + + foreach_primary_input(to_network, gen, pi) { + if (! network_is_real_pi(to_network, pi)) continue; + connection.pi = pi; + connection.input_name = util_strsav(pi->name); + connection.copy_output = NIL(node_t); + array_insert_last(Connection, connections, connection); + } + + foreach_primary_output(env_network, gen, env_output) { + env_fanin = node_get_fanin(env_output, 0); + copy_output = Prl_CopySubnetwork(to_network, env_fanin); + output_name = io_name(env_output, 0); + if (! network_is_real_po(env_network, env_output)) { + CopyLatchPo(to_network, copy_output, output_name, env_output); + } else { + pi = network_find_node(to_network, output_name); + if (pi == NIL(node_t) || ! network_is_real_pi(to_network, pi)) { + if (CopyRealPo(to_network, copy_output, output_name)) return 1; + } else { + for (i = 0; i < array_n(connections); i++) { + connection = array_fetch(Connection, connections, i); + if (connection.pi == pi) { + connection.copy_output = copy_output; + array_insert(Connection, connections, i, connection); + break; + } + } + } + } + } + + /* + * We need to make sure that inputs of 'to_network' that are fed by outputs of 'env_network' + * are directly connected to the outputs of 'to_network'. + * for that, we need to move the fanout of 'pi' onto 'copy_output'. + */ + + for (i = 0; i < array_n(connections); i++) { + connection = array_fetch(Connection, connections, i); + if (connection.copy_output == NIL(node_t)) continue; + foreach_fanout(connection.pi, gen, fanout) { + (void) node_patch_fanin(fanout, connection.pi, connection.copy_output); + node_scc(fanout); + } + network_delete_node(to_network, connection.pi); + connection.pi = NIL(node_t); + array_insert(Connection, connections, i, connection); + } + return 0; +} + + +static node_t *AddPrimaryOutput ARGS((network_t *, node_t *, char *)); + +/* + *---------------------------------------------------------------------- + * CopyRealPo -- INTERNAL ROUTINE + * + * 'node' is already a node of 'network'. + * We need to add a node named 'name' and make that node a PO fed by 'node'. + * If there is already one with that name, it is a fatal error. + * + * Results: + * 0 iff everything went OK. + * + * Side Effects: + * Creates a new external PO of 'network'. + * + *---------------------------------------------------------------------- + */ + +static int CopyRealPo(network, node, name) +network_t *network; +node_t *node; +char *name; +{ + node_t *product_output; + node_t *matching_output, *matching_fanin; + node_t *tmp[2]; + + if (network_find_node(network, name)) { + (void) fprintf(siserr, "Error: network \"%s\" already has a PO named \"%s\"; abort\n", + network->net_name, + name); + return 1; + } + (void) AddPrimaryOutput(network, node, util_strsav(name)); + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * CopyLatchPo -- INTERNAL ROUTINE + * + * Given 'node' which belongs to 'network', makes 'node' the input of + * a freshly created latch. + * + * Results: + * None. + * + * Side effects: + * Change the name of 'node' to a disambiguated version if + * 'name' conflicts with existing node names in 'network'. + * A new latch is created in 'network'. + * + *---------------------------------------------------------------------- + */ + +static void CopyLatchPo(network, node, name, original_po) +network_t *network; +node_t *node; +char *name; +node_t *original_po; +{ + node_t *product_output; + node_t *product_po; + node_t *matching_input; + latch_t *latch, *product_latch; + + name = Prl_DisambiguateName(network, name, NIL(node_t)); + product_po = AddPrimaryOutput(network, node, name); + network_swap_names(network, node, product_po); + matching_input = network_latch_end(original_po); + network_create_latch(network, &product_latch, product_po, matching_input->copy); + latch = latch_from_node(original_po); + latch_set_initial_value(product_latch, latch_get_initial_value(latch)); +} + +/* + *---------------------------------------------------------------------- + * + * AddPrimaryOutput -- INTERNAL ROUTINE + * + * The library routine 'network_add_primary_input' + * does not do the job properly. + * It swaps the names of the 'fanin' and the newly created node. + * This is incorrect if the 'fanin' is a PI. Here we insert + * a buffer when the 'fanin' is a PI to avoid this problem. + * Here we make sure that the resulting PO is named 'name'. + * + * Hack due to the fact that sis does not have an explicit notion of nets + * and assign names to nodes instead. That creates havoc in cases such as: + * .latch a b 0 + * .latch b c 0 + * Here 'b' is used both as a name for a PI and a PO. + * The rule is that PIs keep their names in any circumstance. + * + * Results: + * The freshly created PO. + * + * Side Effects: + * (to be specified). + * + *---------------------------------------------------------------------- + */ + +static node_t *AddPrimaryOutput(network, fanin, name) +network_t *network; +node_t * fanin; +char* name; +{ + node_t *result; + + if (fanin->type == PRIMARY_INPUT) { + fanin = node_literal(fanin, 1); + network_add_node(network, fanin); + } + if (strcmp(fanin->name, name) != 0) { /* i.e. if not equal */ + network_change_node_name(network, fanin, name); + } + result = network_add_primary_output(network, fanin); + return result; +} + + + +/* + * env_vars are all smoothed away. + * fsm_state_vars are only needed to count reachable states. + */ + +static void ExtractBddVars(seq_info, env_network, env_vars, fsm_state_vars) +seq_info_t *seq_info; +network_t *env_network; +array_t *env_vars; +array_t *fsm_state_vars; +{ + int i; + lsGen gen; + bdd_t* var; + node_t *input; + + foreach_primary_input(env_network, gen, input) { + input->copy->copy = input; + } + for (i = 0; i < array_n(seq_info->input_nodes); i++) { + node_t *input = array_fetch(node_t *, seq_info->input_nodes, i); + var = array_fetch(bdd_t *, seq_info->input_vars, i); + if (input->copy != NIL(node_t) && node_network(input->copy) == env_network) { + array_insert_last(bdd_t *, env_vars, var); + } else if (! network_is_real_pi(node_network(input), input)) { + array_insert_last(bdd_t *, fsm_state_vars, var); + } + } + foreach_primary_input(env_network, gen, input) { + input->copy->copy = NIL(node_t); + } +} + + /* + *---------------------------------------------------------------------- + * + * MakeFsmInputRelation -- INTERNAL ROUTINE + * + * Builds the AND of expressions of the form: (x[i] XNOR fn[i](input,state)) + * for each input of the FSM that is bound to an output of the environment. + * + * Side Effects: + * For each input of the FSM that is bound to an output of the environment + * we introduce a new primary input that is added to seq_info->network. + * That primary input is given a BDD variable (inserted in seq_info->input_vars) + * and seq_info->input_nodes and seq_info->var_names are updated accordingly. + * + * NOTES: + * The index in seq_info->var_names should always be equal to the + * BDD variable associated with the corresponding input. This is checked + * by an assertion. + * + *---------------------------------------------------------------------- + */ + +static bdd_t *MakeFsmInputRelation(seq_info, controlled_fsm_inputs) +seq_info_t *seq_info; +array_t *controlled_fsm_inputs; +{ + int i; + bdd_t *result; + bdd_t *fn, *var, *tmp, *new_result; + node_t *pi; + Connection connection; + /* inputs of fsm, outputs of env */ + array_t *new_input_vars = array_alloc(bdd_t *, 0); + + /* Add new variables for the controlled fsm inputs. */ + for (i = 0; i < array_n(controlled_fsm_inputs); i++) { + connection = array_fetch(Connection, controlled_fsm_inputs, i); + if (connection.copy_output != NIL(node_t)) { + bdd_t *var = bdd_create_variable(seq_info->manager); + array_insert_last(bdd_t *, new_input_vars, var); + } + else { + /* Unused entries. Should be BDDs for Prl_FreeBddArray. */ + array_insert_last(bdd_t *, new_input_vars, bdd_one(seq_info->manager)); + } + } + + /* Add corresponding variables to seq_info and primary inputs to the network. */ + for (i = 0; i < array_n(controlled_fsm_inputs); i++) { + connection = array_fetch(Connection, controlled_fsm_inputs, i); + if (connection.copy_output != NIL(node_t)) { + var = array_fetch(bdd_t *, new_input_vars, i); + var = bdd_dup(var); + array_insert_last(bdd_t *, seq_info->input_vars, var); + pi = node_alloc(); + pi->name = util_strsav(connection.input_name); + network_add_primary_input(seq_info->network, pi); + array_insert_last(node_t *, seq_info->input_nodes, pi); + array_insert_last(char *, seq_info->var_names, util_strsav(pi->name)); + assert(bdd_top_var_id(var) == array_n(seq_info->var_names) - 1); + } + } + + /* Build the resulting bdd. */ + result = bdd_one(seq_info->manager); + for (i = 0; i < array_n(controlled_fsm_inputs); i++) { + connection = array_fetch(Connection, controlled_fsm_inputs, i); + if (connection.copy_output != NIL(node_t)) { + fn = ntbdd_node_to_bdd(connection.copy_output, seq_info->manager, seq_info->leaves); + var = array_fetch(bdd_t *, new_input_vars, i); + tmp = bdd_xnor(var, fn); + new_result = bdd_and(tmp, result, 1, 1); + bdd_free(tmp); + bdd_free(result); + result = new_result; + } + } + Prl_FreeBddArray(new_input_vars); + return result; +} + + + +typedef int (*CheckFn) ARGS((bdd_t *, bdd_t *, seq_info_t *, prl_options_t *, void *)); +static int CheckCurrentStateTautology ARGS((bdd_t *, bdd_t *, seq_info_t *, prl_options_t *, void *)); + +static int BreadthFirstTraversal ARGS((seq_info_t *, prl_options_t *, CheckFn, void *)); +static int MakeProductFsm ARGS((network_t *, network_t *, array_t *, array_t *)); +static void ReportEnvErrorTrace ARGS((network_t *, array_t *, seq_info_t *, prl_options_t *)); +static void RemoveUnusedPos ARGS((network_t *, array_t *, prl_options_t *)); + +/* + *---------------------------------------------------------------------- + * + * Prl_VerifyEnvFsm -- EXPORTED ROUTINE + * + * Verifies that two FSMs are equivalent under a given environment FSM. + * 1. Builds the product network of 'fsm_network' and 'check_network'. + * The result is placed in 'check_network'. + * The inputs are connected together, and the outputs are duplicated. + * The outputs of 'check_network' are kept as is. The copied outputs + * of 'fsm_network' are XNORed with their corresponding outputs + * in 'check_network' and become new POs. Those two categories of POs + * are kept in two different lists. + * 2. The 'env_network' is added. If it has a PI that matches an output + * of 'check_network', the PI/PO pair is connected. + * We can tolerate free inputs to 'check_network' + * but free outputs of 'env_network' do not make any sense, so we report a warning + * and ignore these outputs (done in 3). + * 3. Any remaining PO of 'check_network' that is not an XNOR is removed. + * 4. States of the product machine are enumerated. At each step, we check + * that all POs are always equal to 1 for any input combination. + * 5. If all states are enumerated without error, we are done. + * 6. In case of a verification error, we first compute a sequence of + * input minterms that generate the error. By simulation through 'fsm_network' + * and 'env_network', we deduce a sequence of input minterms to 'fsm_network' + * that activates the problem. + * + * Results: + * Returns 0 iff everything went all right. + * + * Side effects: + * 'fsm_network' is unmodified. + * 'env_network' is unmodified. + * 'check_network' is modified in place. + * The caller should take care of deallocating the networks. + * In case of verification error, prints on siserr an input sequence + * that can be generated by the environment and differentiates the two FSMs. + * + *---------------------------------------------------------------------- + */ + +int Prl_VerifyEnvFsm(fsm_network, check_network, env_network, options) +network_t *fsm_network; +network_t *check_network; +network_t *env_network; +prl_options_t *options; +{ + seq_info_t *seq_info; + array_t *xnor_outputs; + array_t *other_outputs; + array_t *controlled_fsm_inputs; + int status = 0; + + /* 'fsm_network' is not modified */ + xnor_outputs = array_alloc(node_t *, 0); + other_outputs = array_alloc(node_t *, 0); + controlled_fsm_inputs = array_alloc(Connection, 0); + if (MakeProductFsm(check_network, fsm_network, xnor_outputs, other_outputs) + || AddEnvFsm(check_network, env_network, controlled_fsm_inputs)) { + status = 1; + } else { + RemoveUnusedPos(check_network, xnor_outputs, options); + seq_info = Prl_SeqInitNetwork(check_network, options); + status = BreadthFirstTraversal(seq_info, options, CheckCurrentStateTautology, NIL(void)); + if (status) { + ReportEnvErrorTrace(check_network, controlled_fsm_inputs, seq_info, options); + } else { + (void) fprintf(misout, "FSM's are equivalent under given environment\n"); + } + Prl_SeqInfoFree(seq_info, options); + } + array_free(xnor_outputs); + array_free(other_outputs); + FreeConnectionArray(controlled_fsm_inputs); + return status; +} + +/* + *---------------------------------------------------------------------- + * + * BreadthFirstTraversal -- INTERNAL ROUTINE + * + * Traverses a machine until all states are reached or a predicate fails. + * The predicate may have side effects. + * + *---------------------------------------------------------------------- + */ + +static int BreadthFirstTraversal(seq_info, options, checkFn, closure) +seq_info_t *seq_info; +prl_options_t *options; +CheckFn checkFn; +void *closure; +{ + bdd_t *current_set; + bdd_t *total_set; + bdd_t *new_current_set; + bdd_t *new_states; + bdd_t *care_set; + bdd_t *new_total_set; + + int status = 0; + + Prl_ReportElapsedTime(options, "begin STG traversal"); + + current_set = bdd_dup(seq_info->init_state_fn); + total_set = bdd_dup(current_set); + + for (;;) { + if ((*checkFn)(current_set, total_set, seq_info, options, closure)) { + status = 1; + break; + } + new_current_set = (*options->compute_next_states)(current_set, seq_info, options); + if (options->verbose >= 1) { + double total_onset, new_onset; + total_onset = bdd_count_onset(total_set, seq_info->present_state_vars); + new_states = bdd_and(new_current_set, total_set, 1, 0); + new_onset = bdd_count_onset(new_states, seq_info->present_state_vars); + bdd_free(new_states); + (void) fprintf(sisout, "add %2.0f states to %2.0f states\n", new_onset, total_onset); + } + if (bdd_leq(new_current_set, total_set, 1, 1)) { + bdd_free(new_current_set); + status = 0; + break; + } + care_set = bdd_not(total_set); + current_set = bdd_cofactor(new_current_set, care_set); + bdd_free(care_set); + new_total_set = bdd_or(new_current_set, total_set, 1, 1); + bdd_free(new_current_set); + bdd_free(total_set); + total_set = new_total_set; + } + + bdd_free(current_set); + bdd_free(total_set); + Prl_ReportElapsedTime(options, "end STG traversal"); + return status; +} + +/* + *---------------------------------------------------------------------- + * + * CheckCurrentStateTautology -- INTERNAL ROUTINE + * + * Results: + * returns 0 iff all outputs are at 1 in all states of 'current_set'. + * + * Side effects: + * Prints an error message if the check fails. + * If 'output_index' is not nil and the check fails, + * sets 'output_index' to the index of an output + * which fails the test. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ + +static int CheckCurrentStateTautology(current_set, total_set, seq_info, options, closure) +bdd_t *current_set; +bdd_t *total_set; +seq_info_t *seq_info; +prl_options_t *options; +void *closure; +{ + int i; + bdd_t *fn; + + for (i = 0; i < array_n(seq_info->external_output_fns); i++) { + fn = array_fetch(bdd_t *, seq_info->external_output_fns, i); + if (! bdd_leq(current_set, fn, 1, 1)) { + (void) fprintf(siserr, "does not pass verification\n"); + return 1; + } + } + return 0; +} + + + +static int CheckAndRecordStates ARGS((bdd_t *, bdd_t *, seq_info_t *, prl_options_t *, void *)); +static void PrintEnvErrorTrace ARGS((array_t *, network_t *, array_t *, seq_info_t *, prl_options_t *)); + +typedef struct ClosureStruct { + array_t *total_sets; + int output_index; +} Closure; + + /* + *---------------------------------------------------------------------- + * + * ReportEnvErrorTrace -- INTERNAL ROUTINE + * + * Enumerates states until an error is found. + * At each iteration, keeps around a copy of 'total_set'. + * Then go backwards and generates an input sequence + * justifying the error. This algorithm guarantees + * the shortest possible error trace. + * + * Once the error trace is obtained for the entire network, + * we simulate it through the 'env_network' and 'fsm_network' + * to get an error trace for the 'env_network'. + * + * 'connections' contain the connections between the env POs + * and the PIs of the fsm. + * + *---------------------------------------------------------------------- + */ + +static void ReportEnvErrorTrace(product_network, connections, seq_info, options) +network_t *product_network; +array_t *connections; +seq_info_t *seq_info; +prl_options_t *options; +{ + Closure closure; + int iter_count; + bdd_t *tmp; + bdd_t *output_fn; + bdd_t *total_set; + bdd_t *incorrect_domain; + bdd_t *incorrect_state, *incorrect_input; + array_t *input_trace; + + /* + * Generates an array of total_sets, one per iteration, until failure. + */ + + closure.total_sets = array_alloc(bdd_t *, 0); + assert(BreadthFirstTraversal(seq_info, options, CheckAndRecordStates, (void *) &closure)); + + /* + * Traverses the machine backwards to generate a trace. + */ + + output_fn = array_fetch(bdd_t *, seq_info->external_output_fns, closure.output_index); + iter_count = array_n(closure.total_sets) - 1; + total_set = array_fetch(bdd_t *, closure.total_sets, iter_count); + incorrect_domain = bdd_and(total_set, output_fn, 1, 0); + input_trace = array_alloc(bdd_t *, 0); + + for (;;) { + Prl_GetOneEdge(incorrect_domain, seq_info, &incorrect_state, &incorrect_input); + bdd_free(incorrect_domain); + array_insert(bdd_t *, input_trace, iter_count, incorrect_input); + if (iter_count == 0) break; + iter_count--; + tmp = (*options->compute_reverse_image)(incorrect_state, seq_info, options); + total_set = array_fetch(bdd_t *, closure.total_sets, iter_count); + incorrect_domain = bdd_and(tmp, total_set, 1, 1); + bdd_free(tmp); + } + + /* + * Cleanup and print the error trace. + */ + + PrintEnvErrorTrace(input_trace, product_network, connections, seq_info, options); + + Prl_FreeBddArray(closure.total_sets); + Prl_FreeBddArray(input_trace); +} + +/* + *---------------------------------------------------------------------- + * + * CheckAndRecordStates -- INTERNAL ROUTINE + * + * Results: + * returns 0 iff all outputs are at 1 in all states of 'current_set'. + * + * Side effects: + * Accumulates in 'closure' an array of bdds + * containing the total sets seen at each iteration. + * + *---------------------------------------------------------------------- + */ + +static int CheckAndRecordStates(current_set, total_set, seq_info, options, closure) +bdd_t *current_set; +bdd_t *total_set; +seq_info_t *seq_info; +prl_options_t *options; +void *closure; +{ + int i; + bdd_t *fn; + Closure *data = (Closure *) closure; + + array_insert_last(bdd_t *, data->total_sets, bdd_dup(total_set)); + for (i = 0; i < array_n(seq_info->external_output_fns); i++) { + fn = array_fetch(bdd_t *, seq_info->external_output_fns, i); + if (! bdd_leq(current_set, fn, 1, 1)) { + data->output_index = i; + return 1; + } + } + return 0; +} + +typedef struct PrintClosureStruct { + network_t *network; /* the product network: fsm x check x env */ + array_t *input_vars; /* a bdd_t* per PI of 'network'; only external PI used */ + /* should match ordering of 'foreach_primary_input(network)' */ + array_t *node_vec; /* the result of 'network_dfs(network)' */ + array_t *input_values; /* an array of int; match order of 'input_vars' */ + array_t *fsm_inputs; /* an array of node_t *; copies of 'fsm_network' ext. PIs */ +} PrintClosure; + + +static PrintClosure *PrintClosureInit ARGS((network_t *, array_t *, seq_info_t *)); +static array_t *PrintClosureSimulateNetwork ARGS((bdd_t *, PrintClosure *)); +static void PrintClosureFree ARGS((PrintClosure *)); + + + /* + *---------------------------------------------------------------------- + * + * PrintEnvErrorTrace -- INTERNAL ROUTINE + * + * Given an input trace in terms of the 'env_network', + * generates an input trace in terms of the 'fsm_network' + * and prints it. This is achieved by simulating the data in 'input_trace' + * on the 'product_network', and printing the simulation values + * of the nodes in 'product_network' that corresponds to the inputs of + * 'fsm_network' and are stored in the array 'connections'. + * + *---------------------------------------------------------------------- + */ + +static void PrintEnvErrorTrace(input_trace, product_network, connections, seq_info, options) +array_t *input_trace; +network_t *product_network; +array_t *connections; +seq_info_t *seq_info; +prl_options_t *options; +{ + int i; + PrintClosure *closure; + + /* Then: Initialize the network for simulation */ + + closure = PrintClosureInit(product_network, connections, seq_info); + + /* Run the simulation and cleanup */ + + for (i = 0; i < array_n(input_trace); i++) { + bdd_t *input = array_fetch(bdd_t *, input_trace, i); + PrintClosureSimulateNetwork(input, closure); + } + + PrintClosureFree(closure); +} + +static array_t *ExtractFsmInputs ARGS((network_t *, array_t *)); + + + /* + *---------------------------------------------------------------------- + * + * PrintClosureInit -- INTERNAL ROUTINE + * + * Results: + * A correctly initialized copy of a 'PrintClosure' object. + * + * Side effects: + * 'product_network' is reset to its initial state. + * + *---------------------------------------------------------------------- + */ + +static PrintClosure *PrintClosureInit(product_network, connections, seq_info) +network_t *product_network; +array_t *connections; +seq_info_t *seq_info; +{ + lsGen gen; + node_t *pi; + latch_t *latch; + int init_value; + st_table *pi_to_var_table; + PrintClosure *closure = ALLOC(PrintClosure, 1); + + pi_to_var_table = Prl_GetPiToVarTable(seq_info); + closure->network = product_network; + closure->input_vars = array_alloc(bdd_t *, 0); + foreach_primary_input(closure->network, gen, pi) { + bdd_t *var; + if (network_is_real_pi(closure->network, pi)) { + assert(st_lookup(pi_to_var_table, (char *) pi, (char **) &var)); + } else { + var = NIL(bdd_t); + } + array_insert_last(bdd_t *, closure->input_vars, var); + } + st_free_table(pi_to_var_table); + + foreach_latch(closure->network, gen, latch) { + init_value = latch_get_initial_value(latch); + latch_set_current_value(latch, init_value); + } + + closure->node_vec = network_dfs(closure->network); + closure->input_values = array_alloc(int, network_num_pi(closure->network)); + closure->fsm_inputs = ExtractFsmInputs(closure->network, connections); + + return closure; +} + +/* + *---------------------------------------------------------------------- + * + * ExtractFsmInputs -- INTERNAL ROUTINE + * + * Results: + * an array of node_t *'s representing the external PIs + * of 'product_network' before the merging with the 'env_network'. + * + *---------------------------------------------------------------------- + */ + +static array_t *ExtractFsmInputs(network, connections) +network_t *network; +array_t *connections; +{ + int i; + lsGen gen; + node_t *node; + array_t *fsm_inputs; + Connection connection; + + for (i = 0; i < array_n(connections); i++) { + connection = array_fetch(Connection, connections, i); + (void) fprintf(sisout, "%s ", connection.input_name); + } + (void) fprintf(sisout, "\n"); + + fsm_inputs = array_alloc(node_t *, 0); + for (i = 0; i < array_n(connections); i++) { + connection = array_fetch(Connection, connections, i); + if (connection.pi == NIL(node_t)) { + node = connection.copy_output; + } else { + node = connection.pi; + } + assert(node != NIL(node_t)); + array_insert_last(node_t *, fsm_inputs, node); + } + return fsm_inputs; +} + + /* + *---------------------------------------------------------------------- + * + * PrintClosureSimulateNetwork -- INTERNAL ROUTINE + * + *---------------------------------------------------------------------- + */ + +static array_t *PrintClosureSimulateNetwork(input, closure) +bdd_t *input; +PrintClosure *closure; +{ + int i; + int value; + lsGen gen; + latch_t *latch; + node_t *pi, *po; + bdd_t *var; + array_t *output_values; + + i = 0; + foreach_primary_input(closure->network, gen, pi) { + if ((latch = latch_from_node(pi)) != NIL(latch_t)) { + value = latch_get_current_value(latch); + } else { + assert((var = array_fetch(bdd_t *, closure->input_vars, i)) != NIL(bdd_t)); + value = (bdd_leq(input, var, 1, 1)) ? 1 : 0; + } + array_insert(int, closure->input_values, i, value); + i++; + } + + output_values = simulate_network(closure->network, closure->node_vec, closure->input_values); + + i = 0; + foreach_primary_output(closure->network, gen, po) { + if ((latch = latch_from_node(po)) != NIL(latch_t)) { + value = array_fetch(int, output_values, i); + latch_set_current_value(latch, value); + } + i++; + } + array_free(output_values); + + (void) fprintf(sisout, "simulate "); + for (i = 0; i < array_n(closure->fsm_inputs); i++) { + node_t *node = array_fetch(node_t *, closure->fsm_inputs, i); + value = GET_VALUE(node); + (void) fprintf(sisout, "%d ", value); + } + (void) fprintf(sisout, "\n"); +} + + + /* + *---------------------------------------------------------------------- + * + * PrintClosureFree -- INTERNAL ROUTINE + * + *---------------------------------------------------------------------- + */ + +static void PrintClosureFree(closure) +PrintClosure *closure; +{ + array_free(closure->input_vars); + array_free(closure->node_vec); + array_free(closure->input_values); + array_free(closure->fsm_inputs); + FREE(closure); +} + +static node_t *AddXnorPo ARGS((network_t *, node_t *, node_t *)); + +/* + *---------------------------------------------------------------------- + * + * MakeProductFsm -- INTERNAL ROUTINE + * + * Builds the product network of 'from_network' and 'to_network'. + * + * The inputs are connected together, and the outputs are duplicated. + * The outputs of 'to_network' are kept as is. The copied outputs + * of 'from_network' are XNORed with their corresponding outputs + * in 'to_network' and become new POs. Those two categories of POs + * are kept in two different arrays: 'xnor_outputs' and 'other_outputs'. + * + * It is the responsability of the caller to allocate/deallocate + * the 'xnor_outputs' and 'other_outputs' arrays. + * + * Results: + * returns 1 iff 'from_network' contains external POs + * that do not match by name with external POs in 'to_network'. + * + * Side effects: + * The resulting product is placed in 'to_network'. + * 'from_network' is unchanged. + * + *---------------------------------------------------------------------- + */ + +static int MakeProductFsm(to_network, from_network, xnor_outputs, other_outputs) +network_t *to_network; +network_t *from_network; +array_t *xnor_outputs; +array_t *other_outputs; +{ + lsGen gen; + node_t *from_output; + node_t *from_fanin; + node_t *to_output; + node_t *copy_output; + char *output_name; + + /* + * 'Prl_SetupCopyFields' guarantees that extenal PIs of 'from_network' + * that have homonymous PIs in 'to_network' are used + * instead of the 'from_network' PIs. + */ + + Prl_SetupCopyFields(to_network, from_network); + + foreach_primary_output(from_network, gen, from_output) { + output_name = io_name(from_output, 0); + to_output = network_find_node(to_network, output_name); + from_fanin = node_get_fanin(from_output, 0); + copy_output = Prl_CopySubnetwork(to_network, from_fanin); + if (! network_is_real_po(from_network, from_output)) { + CopyLatchPo(to_network, copy_output, output_name, from_output); + } else if (to_output == NIL(node_t) || ! network_is_real_po(to_network, to_output)) { + return 1; + } else { + node_t *xnor_node = AddXnorPo(to_network, to_output, copy_output); + array_insert_last(node_t *, xnor_outputs, xnor_node); + array_insert_last(node_t *, other_outputs, to_output); + } + } + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * AddXnorPo -- INTERNAL ROUTINE + * + * Given two nodes in a network, one being an external PO, + * adds another external PO which is the XNOR of the first external PO + * with the other node. + * + * Results: + * The new external PO. + * + *---------------------------------------------------------------------- + */ + +static node_t *AddXnorPo(network, po, node) +network_t *network; +node_t *po; +node_t *node; +{ + char* name; + node_t *tmp0, *tmp1; + node_t *xnor_node; + + tmp0 = node_literal(node_get_fanin(po, 0), 1); + tmp1 = node_literal(node, 1); + xnor_node = node_xnor(tmp0, tmp1); + node_free(tmp0); + node_free(tmp1); + name = io_name(po, 0); + xnor_node->name = Prl_DisambiguateName(network, name, NIL(node_t)); + network_add_node(network, xnor_node); + return network_add_primary_output(network, xnor_node); +} + +/* + *---------------------------------------------------------------------- + * + * RemoveUnusedPos -- INTERNAL ROUTINE + * + * Look for any external PO not in 'used_outputs'. + * When one is found, mark it and remove it later. + * Generates a warning when one is removed. + * + * Side effects: + * 1. Use the 'copy' field of the PO nodes to indicate + * whether a node is used or not. + * 2. Unused POs are discarded. + * + *---------------------------------------------------------------------- + */ + +static void RemoveUnusedPos(network, used_outputs, options) +network_t *network; +array_t *used_outputs; +prl_options_t *options; +{ + int i; + lsGen gen; + node_t *po; + array_t *to_be_removed = array_alloc(node_t *, 0); + + foreach_primary_output(network, gen, po) { + po->copy = NIL(node_t); + } + for (i = 0; i < array_n(used_outputs); i++) { + po = array_fetch(node_t *, used_outputs, i); + po->copy = po; + } + foreach_primary_output(network, gen, po) { + if (! network_is_real_po(network, po)) continue; + if (po->copy == po) continue; + array_insert_last(node_t *, to_be_removed, po); + } + for (i = 0; i < array_n(to_be_removed); i++) { + po = array_fetch(node_t *, to_be_removed, i); + if (options->verbose > 0) { + (void) fprintf(siserr, "Warning: PO \"%s\" is skipped\n", io_name(po, 0)); + } + network_delete_node(network, po); + } + array_free(to_be_removed); +} + +/* + *---------------------------------------------------------------------- + * + * FreeConnectionArray -- INTERNAL PROCEDURE + * + * simple utility to free strings allocated in 'AddEnvFsm' + * in Connection records. + * + *---------------------------------------------------------------------- + */ + +static void FreeConnectionArray(connections) +array_t *connections; +{ + int i; + Connection connection; + + for (i = 0; i < array_n(connections); i++) { + connection = array_fetch(Connection, connections, i); + FREE(connection.input_name); + } + array_free(connections); +} + + diff --git a/sis/seqbdd/prl_ordering.c b/sis/seqbdd/prl_ordering.c new file mode 100644 index 0000000..8920a63 --- /dev/null +++ b/sis/seqbdd/prl_ordering.c @@ -0,0 +1,527 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prl_ordering.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + +#ifdef SIS +#include "sis.h" +#include "prl_util.h" + + /* key into the cache: should use var_set_t compare */ + /* describes as a bit string the sets scheduled so far */ + +typedef struct { + var_set_t *placed_so_far; +} set_key_t; + + /* value stored in the cache */ + /* the best next set index, and the cost at that point */ +typedef struct { + int index; + int cost; +} set_value_t; + + /* should not overflow too easily but should be large enough */ +#define LARGE_NUMBER ((int) 0x1fffffff) + + /* information associated with dominators used in branch & bound */ + /* a dominator is a set that does not contain any other */ + /* (not exactly true; for exact definition, see compare routine) */ + /* the size of the dominator is the number of elts it contains */ + /* that are not in the union of the sets visited so far */ + +typedef struct { + int index; /* index of the set (if A5, index is 5) */ + int bound; /* lower bound of the cost of choosing this index */ + int cost; /* real cost, after recursive computation */ + int size; /* size of the index, minus all variables already there */ +} dominator_t; + + +static int set_key_hash ARGS((char*, int)); +static int set_key_cmp ARGS((char*, char*)); +static void set_cache_free ARGS((st_table *)); +static int do_find_best_set_order ARGS((set_info_t *, set_key_t *, st_table *, int, int)); +static void extract_best_order_from_cache ARGS((set_info_t *, st_table *, set_key_t *, array_t *)); +static int compute_order_cost ARGS((set_info_t *, array_t *)); +static void print_int_array ARGS((array_t *)); +static void print_set_info ARGS((set_info_t *)); + + +/* + *---------------------------------------------------------------------- + * + * Prl_OrderSetHeuristic -- EXTERNAL ROUTINE + * + * Computes an heuristic solution to the following problem: + * + * INPUT: A1,...,An n subsets of some finite set S + * OUTPUT: an ordering of {1,...,n} such that + * if s_i = |\cup{1\leq j\leq i} A_i | + * cost = (\sum_{1\leq i \leq n} s_i) is minimized. + * + * This routine is used for ordering output fns in BDD range computation heuristics. + + * The algorithm is exponential in the worst-case. + * It uses a branch and bound heuristic + * as well as the fact that if A_i is included into A_j + * we can always suppose that A_i appears before A_j. + * In fact if A_i is included in A_j + * except for elements that only appear in A_i and in no other set + * then A_i always appear before A_j if #singletons(A_i) \leq #singletons(A_j). + * + * Results: + * an array of size n_sets representing the optimal ordering of the sets. + * + * Side Effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int global_verbose; + +array_t *Prl_OrderSetHeuristic(info, verbosity, level) +set_info_t *info; +int verbosity; +int level; +{ + int cost; + set_key_t *key = ALLOC(set_key_t, 1); + array_t *result = array_alloc(int, 0); + st_table *cache = st_init_table(set_key_cmp, set_key_hash); + + global_verbose = verbosity; + if (verbosity >= 4) print_set_info(info); + key->placed_so_far = var_set_new(info->n_sets); /* automatically initialized to 0 */ + cost = do_find_best_set_order(info, key, cache, level, LARGE_NUMBER); + extract_best_order_from_cache(info, cache, key, result); + assert(cost == compute_order_cost(info, result)); + + /* TODO: compute the cost again; check with evaluated cost above */ + if (verbosity >= 2) { + printf("ordering cost is: %d\n", cost); + if (verbosity >= 3) print_int_array(result); + } + set_cache_free(cache); + return result; +} + + + /* INTERNAL INTERFACE */ + +static int dominator_cmp ARGS((char *, char*)); +static void compute_bounds ARGS((set_info_t *, var_set_t *, var_set_t *, array_t *)); +static array_t * extract_dominators ARGS((set_info_t *, var_set_t *, var_set_t *)); +static var_set_t *extract_uncovered_variables ARGS((set_info_t *, set_key_t *)); +static int arg_min_remaining_size ARGS((set_info_t *, var_set_t *, var_set_t *, int *)); + + + /* returns the cost of the solution so far */ + /* the resulting order can be derived from the cache */ + /* The key is newly allocated when it comes in */ + /* it is either kept in the cache or freed by this routine */ + /* info is read-only */ + +static int do_find_best_set_order(info, key, cache, depth, allocated) +set_info_t *info; +set_key_t *key; +st_table *cache; +int depth; +int allocated; /* for bounding the search: if allocated < 0, can kill this subtree */ +{ + int i; + int local_cost; + set_key_t *new_key; + set_value_t *value; + var_set_t *remaining_vars, *dead_vars; + array_t *dominators; + dominator_t d; + dominator_t *dom; + int n_remaining_sets; + var_set_t *tmp = NIL(var_set_t); + + n_remaining_sets = info->n_sets - var_set_n_elts(key->placed_so_far); + if (n_remaining_sets == 0) { + var_set_free(key->placed_so_far); + FREE(key); + return 0; + } + if (allocated < 0) { + var_set_free(key->placed_so_far); + FREE(key); + return LARGE_NUMBER; + } + if (st_lookup(cache, (char *) key, (char **) &value)) { + var_set_free(key->placed_so_far); + FREE(key); + return value->cost; + } + /* variables still active (i.e. complement of union of sets in key) */ + remaining_vars = extract_uncovered_variables(info, key); + dead_vars = var_set_copy(remaining_vars); + (void) var_set_not(dead_vars, dead_vars); + + if (depth <= 0) { + dominators = array_alloc(dominator_t, 0); + /* get the first remaining set of minimum size relative to remaining vars */ + d.bound = 0; + d.cost = LARGE_NUMBER; + d.index = arg_min_remaining_size(info, key->placed_so_far, dead_vars, &(d.size)); + array_insert_last(dominator_t, dominators, d); + } else { + dominators = extract_dominators(info, key->placed_so_far, remaining_vars); + if (array_n(dominators) > 1) { + array_sort(dominators, dominator_cmp); + compute_bounds(info, key->placed_so_far, remaining_vars, dominators); + } + } + assert(array_n(dominators) > 0); + /* compute the best solution among all alternatives */ + tmp = var_set_new(info->n_vars); + value = ALLOC(set_value_t, 1); + value->index = -1; + value->cost = LARGE_NUMBER; + for (i = 0; i < array_n(dominators); i++) { + dom = array_fetch_p(dominator_t, dominators, i); + if (dom->bound >= value->cost) continue; + + /* to compute the cost at this level: number of 1's here */ + /* times how many times they are going to appear: # remaining_sets */ + (void) var_set_and(tmp, info->sets[dom->index], remaining_vars); + local_cost = var_set_n_elts(tmp) * n_remaining_sets; + + allocated = value->cost - local_cost; + new_key = ALLOC(set_key_t, 1); + new_key->placed_so_far = var_set_copy(key->placed_so_far); + var_set_set_elt(new_key->placed_so_far, dom->index); + dom->cost = local_cost + do_find_best_set_order(info, new_key, cache, depth - 1, allocated); + if (value->cost > dom->cost) { + value->cost = dom->cost; + value->index = dom->index; + } + } + assert(value->index != -1); + assert(! var_set_get_elt(key->placed_so_far, value->index)); + st_insert(cache, (char *) key, (char *) value); + array_free(dominators); + var_set_free(remaining_vars); + var_set_free(dead_vars); + if (tmp) var_set_free(tmp); + return value->cost; +} + +static int dominator_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + dominator_t *dom1 = (dominator_t *) obj1; + dominator_t *dom2 = (dominator_t *) obj2; + + return dom1->size - dom2->size; +} + + +static int set_key_hash(k, modulus) +char *k; +int modulus; +{ + register set_key_t *key = (set_key_t *) k; + register unsigned int hash = var_set_hash(key->placed_so_far); + return hash % modulus; +} + + /* returns 0 iff equal */ +static int set_key_cmp(k1, k2) +char *k1; +char *k2; +{ + register set_key_t *key1 = (set_key_t *) k1; + register set_key_t *key2 = (set_key_t *) k2; + + return (! var_set_equal(key1->placed_so_far, key2->placed_so_far)); +} + + /* frees keys and values */ + +static void set_cache_free(cache) +st_table *cache; +{ + st_generator *gen; + set_key_t *key; + set_value_t *value; + + st_foreach_item(cache, gen, (char **) &key, (char **) &value) { + var_set_free(key->placed_so_far); + FREE(key); + FREE(value); + } + st_free_table(cache); +} + + /* check that we generate a permutation of 0->n_sets-1 */ + /* if not in hash table: means all remaining ones are equivalent */ + +static void extract_best_order_from_cache(info, cache, first_key, result) +set_info_t *info; +st_table *cache; +set_key_t *first_key; +array_t *result; +{ + int i, j; + set_key_t key; + set_value_t *value; + + key.placed_so_far = var_set_copy(first_key->placed_so_far); + assert(var_set_is_empty(key.placed_so_far)); + for (i = 0; i < info->n_sets; i++) { + if (! st_lookup(cache, (char *) &key, (char **) &value)) break; + assert(value->index >= 0 && value->index < info->n_sets); + assert(! var_set_get_elt(key.placed_so_far, value->index)); + array_insert(int, result, i, value->index); + var_set_set_elt(key.placed_so_far, value->index); + } + if (i < info->n_sets) { + for (j = 0; j < info->n_sets; j++) { + if (var_set_get_elt(key.placed_so_far, j)) continue; + array_insert(int, result, i, j); + i++; + } + } + var_set_free(key.placed_so_far); +} + + /* try to compute a good lower bound of cost of solution */ + /* that would try with each separate dominator */ + /* mask: union of variables still to be covered */ +static void compute_bounds(info, placed_so_far, mask, dominators) +set_info_t *info; +var_set_t *placed_so_far; +var_set_t *mask; +array_t *dominators; +{ + int i, j; + dominator_t *dom; + var_set_t *set = var_set_new(info->n_vars); + var_set_t *tmp = var_set_new(info->n_vars); + int n_remaining = info->n_sets - var_set_n_elts(placed_so_far); + + for (i = 0; i < array_n(dominators); i++) { + dom = array_fetch_p(dominator_t, dominators, i); + dom->bound = dom->size * n_remaining; + var_set_clear(set); + for (j = 0; j < info->n_sets; j++) { + if (j == dom->index) continue; + if (var_set_get_elt(placed_so_far, j)) continue; + (void) var_set_or(set, set, info->sets[j]); + } + (void) var_set_and(set, set, mask); + (void) var_set_not(tmp, info->sets[dom->index]); + (void) var_set_and(set, set, tmp); + dom->bound += var_set_n_elts(set); + } + var_set_free(set); + var_set_free(tmp); +} + +static int set_is_less_than ARGS((var_set_t *, var_set_t *, var_set_t *, int)); + + /* put in an dominator_t array_t info about the dominator sets */ + /* after we have eliminated the placed_so_far */ + /* (mask is complement of union of placed_so_far) */ + /* a dominator is a set that does not contain any other */ + /* we also need the size of each dominator (not counting the elts in mask) */ + /* If there is no dominator, it means that all sets are equivalent (all equal) */ + /* with respect to mask: in that case, can conclude immediately */ + +static array_t *extract_dominators(info, placed_so_far, mask) +set_info_t *info; +var_set_t *placed_so_far; +var_set_t *mask; +{ + int i, j; + int is_dominator; + dominator_t dom; + array_t *result = array_alloc(dominator_t, 0); + var_set_t *dominators = var_set_new(info->n_sets); + var_set_t *tmp; + + for (i = 0; i < info->n_sets; i++) { + if (var_set_get_elt(placed_so_far, i)) continue; + is_dominator = 1; + for (j = 0; j < info->n_sets; j++) { + if (j == i) continue; + if (var_set_get_elt(placed_so_far, j)) continue; + if (set_is_less_than(info->sets[j], info->sets[i], mask, j - i)) { + is_dominator = 0; + break; + } + } + if (is_dominator) var_set_set_elt(dominators, i); + } + tmp = var_set_new(info->n_vars); + for (i = 0; i < info->n_sets; i++) { + if (! var_set_get_elt(dominators, i)) continue; + (void) var_set_and(tmp, mask, info->sets[i]); + dom.index = i; + dom.size = var_set_n_elts(tmp); + dom.cost = LARGE_NUMBER; + dom.bound = 0; + array_insert_last(dominator_t, result, dom); + } + var_set_free(dominators); + var_set_free(tmp); + return result; +} + + + /* check whether set1 inter set2 is equal to set1 (modulo mask) */ + /* should be strictly less than, thus check for equality */ + /* if equal, use diff to make the difference */ + +static int set_is_less_than(set1, set2, mask, diff) +var_set_t *set1; +var_set_t *set2; +var_set_t *mask; +int diff; +{ + int result; + var_set_t *tmp1 = var_set_copy(set1); + var_set_t *tmp2 = var_set_copy(set2); + + (void) var_set_and(tmp1, tmp1, mask); + (void) var_set_and(tmp2, tmp2, mask); + if (var_set_equal(tmp1, tmp2)) { + result = (diff < 0) ? 1 : 0; + } else { + (void) var_set_and(tmp2, tmp1, tmp2); + result = var_set_equal(tmp1, tmp2); + } + var_set_free(tmp1); + var_set_free(tmp2); + return result; +} + + /* extract variables still active (i.e. complement of union of sets in key) */ + +static var_set_t *extract_uncovered_variables(info, key) +set_info_t *info; +set_key_t *key; +{ + int i; + var_set_t *result = var_set_new(info->n_vars); + + for (i = 0; i < info->n_sets; i++) { + if (! var_set_get_elt(key->placed_so_far, i)) continue; + (void) var_set_or(result, result, info->sets[i]); + } + (void) var_set_not(result, result); + return result; +} + + /* get the first remaining set of minimum size relative to remaining vars */ + /* also returns its size relative to remaining vars (vars not in mask) */ + +static int arg_min_remaining_size(info, placed_so_far, mask, min_size) +set_info_t *info; +var_set_t *placed_so_far; +var_set_t *mask; /* all those already there: do not discriminate any more */ +int *min_size; +{ + int i, size; + int best_index = -1; + int best_size = LARGE_NUMBER; + var_set_t *tmp = var_set_new(info->n_vars); + + for (i = 0; i < info->n_sets; i++) { + if (var_set_get_elt(placed_so_far, i)) continue; + size = var_set_n_elts(var_set_or(tmp, mask, info->sets[i])); + if (size < best_size) { + best_size = size; + best_index = i; + } + } + var_set_free(tmp); + *min_size = best_size - var_set_n_elts(mask); + return best_index; +} + +static int compute_order_cost(info, order) +set_info_t *info; +array_t *order; +{ + int i; + int index; + int result = 0; + var_set_t *union_so_far = var_set_new(info->n_vars); + + for (i = 0; i < array_n(order); i++) { + index = array_fetch(int, order, i); + (void) var_set_or(union_so_far, union_so_far, info->sets[index]); + result += var_set_n_elts(union_so_far); + } + var_set_free(union_so_far); + return result; +} + + + /* for debugging */ + + /*NOTUSED*/ + +static void check_cache(cache, key, value) +st_table *cache; +set_key_t *key; +set_value_t *value; +{ + st_generator *gen; + set_key_t *k; + set_value_t *v; + + if (key != NIL(set_key_t) && value != NIL(set_value_t)) { + fprintf(siserr, "insert %d, %d (%x) --> ", value->index, value->cost, value); + fprintf(siserr, "(%d) ", var_set_hash(key->placed_so_far)); + var_set_print(siserr, key->placed_so_far); + } + st_foreach_item(cache, gen, (char **) &k, (char **) &v) { + fprintf(siserr, "found %d, %d (%x) --> ", v->index, v->cost, v); + fprintf(siserr, "(%d) ", var_set_hash(k->placed_so_far)); + var_set_print(siserr, k->placed_so_far); + if (value != NIL(set_value_t)) { + st_lookup(cache, (char *) k, (char **) &value); + assert(v == value); + } + } +} + +static void print_int_array(data) +array_t *data; +{ + int i; + + for (i = 0; i < array_n(data); i++) { + printf("%d ", array_fetch(int, data, i)); + } + printf("\n"); +} + +static void print_set_info(info) +set_info_t *info; +{ + int i, j, value; + for (i = 0; i < info->n_sets; i++) { + assert(info->sets[i]->n_elts == info->n_vars); + for (j = 0; j < info->n_vars; j++) { + value = var_set_get_elt(info->sets[i], j); + printf("%d%s", value, (j == info->n_vars - 1) ? "" : " "); + } + printf("\n"); + } +} + +#endif /* SIS */ diff --git a/sis/seqbdd/prl_product.c b/sis/seqbdd/prl_product.c new file mode 100644 index 0000000..ebafb75 --- /dev/null +++ b/sis/seqbdd/prl_product.c @@ -0,0 +1,1202 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prl_product.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + +#ifdef SIS +#include "sis.h" +#include "prl_util.h" +#include "prioqueue.h" + + + +static void compute_po_ordering ARGS((seq_info_t *, prl_options_t *)); +static void compute_pi_ordering ARGS((seq_info_t *, prl_options_t *)); + +/* + *---------------------------------------------------------------------- + * + * Prl_ProductBddOrder -- EXPORTED ROUTINE + * + * Produce the variable ordering required for product / consistency method. + * + * Results: + * None. + * + * Side effects: + * 'seq_info' is updated with the variable ordering information. + * + *---------------------------------------------------------------------- + */ + +void Prl_ProductBddOrder(seq_info, options) +seq_info_t *seq_info; +prl_options_t *options; +{ + compute_po_ordering(seq_info, options); + compute_pi_ordering(seq_info, options); +} + +/* + *---------------------------------------------------------------------- + * + * Routines to implement Prl_SeqInitNetwork + * + *---------------------------------------------------------------------- + */ + + /* puts the result in seq_info->output_nodes */ + /* add the external outputs at the end */ + +static var_set_t **extract_support_info ARGS((network_t *, array_t *)); + +static void compute_po_ordering(seq_info, options) +seq_info_t *seq_info; +prl_options_t *options; +{ + int i, index; + lsGen gen; + node_t *output; + array_t *next_state_po; + var_set_t **support_info; + set_info_t set_info; + array_t *ordering; + network_t *network = seq_info->network; + + /* extract the next_state PO's */ + next_state_po = array_alloc(node_t *, 0); + foreach_primary_output(network, gen, output) { + if (network_is_real_po(network, output)) continue; + array_insert_last(node_t *, next_state_po, output); + } + + /* fits the information in the right format */ + /* compute the support for all nodes at the same time: much faster O(n) instead of O(n^2) */ + support_info = extract_support_info(seq_info->network, next_state_po); + set_info.n_vars = network_num_pi(network); + set_info.n_sets = array_n(next_state_po); + set_info.sets = support_info; + + /* orders and recasts the ordering information */ + ordering = Prl_OrderSetHeuristic(&set_info, options->verbose, options->ordering_depth); + assert(array_n(ordering) == array_n(next_state_po)); + seq_info->output_nodes = array_alloc(node_t *, network_num_po(network)); + for (i = 0; i < array_n(ordering); i++) { + index = array_fetch(int, ordering, i); + output = array_fetch(node_t *, next_state_po, index); + array_insert_last(node_t *, seq_info->output_nodes, output); + } + + /* append the external outputs */ + foreach_primary_output(network, gen, output) { + if (! network_is_real_po(network, output)) continue; + array_insert_last(node_t *, seq_info->output_nodes, output); + } + + /* cleanup */ + for (i = 0; i < array_n(next_state_po); i++) { + var_set_free(support_info[i]); + } + FREE(support_info); + array_free(ordering); + array_free(next_state_po); +} + +static array_t *order_dfs_from_count ARGS((node_t *, st_table *, int, int*, int)); +static void add_new_inputs ARGS((seq_info_t *, array_t *)); +static void add_next_state_vars ARGS((seq_info_t *, st_table *)); +static void ResetVariableOrder ARGS((st_table *, node_t *)); +static void SetVariableOrder ARGS((st_table *, node_t *, int, int)); + +/* + *---------------------------------------------------------------------- + * + * compute_pi_ordering -- INTERNAL ROUTINE + * + *---------------------------------------------------------------------- + */ + +static void compute_pi_ordering(seq_info, options) +seq_info_t *seq_info; +prl_options_t *options; +{ + char buffer[10]; + char *value; + int i, index; + int n_vars; + lsGen gen; + bdd_t *var; + node_t *input; + node_t *output; + array_t *input_order; + int next_index; + int n_next_state_po; + st_generator *table_gen; + network_t *network = seq_info->network; + st_table *leaves = st_init_table(st_ptrcmp, st_ptrhash); + st_table *next_state_table = st_init_table(st_ptrcmp, st_ptrhash); + + /* bdd manager + leaves init: make all PI's leaves */ + foreach_primary_input(network, gen, input) { + ResetVariableOrder(leaves, input); + } + seq_info->leaves = leaves; + + /* we add one variable per latch for consistency method: -> next_state_vars */ + n_vars = st_count(leaves) + network_num_latch(seq_info->network); + seq_info->manager = ntbdd_start_manager(n_vars); + + /* initialize a bunch of arrays */ + seq_info->present_state_vars = array_alloc(bdd_t *, 0); + seq_info->transition.transition_vars = array_alloc(bdd_t *, 0); + seq_info->transition.next_state_vars = array_alloc(bdd_t *, 0); + seq_info->external_input_vars = array_alloc(bdd_t *, 0); + seq_info->input_vars = array_alloc(bdd_t *, 0); + seq_info->input_nodes = array_alloc(node_t *, 0); + seq_info->var_names = array_alloc(char *, 0); + + /* generate the order */ + next_index = 0; + + /* first treat the next state outputs */ + n_next_state_po = network_num_latch(seq_info->network); + for (i = 0; i < n_next_state_po; i++) { + output = array_fetch(node_t *, seq_info->output_nodes, i); + input_order = order_dfs_from_count(output, leaves, DFS_ORDER, &next_index, options->verbose); + add_new_inputs(seq_info, input_order); + + sprintf(buffer, "y:%d", i); + array_insert_last(char *, seq_info->var_names, util_strsav(buffer)); + st_insert(next_state_table, (char *) output, (char *) next_index); + var = bdd_get_variable(seq_info->manager, next_index); + array_insert_last(bdd_t *, seq_info->transition.transition_vars, var); + + next_index++; + array_free(input_order); + } + + /* then treat the external outputs */ + for (i = n_next_state_po; i < array_n(seq_info->output_nodes); i++) { + output = array_fetch(node_t *, seq_info->output_nodes, i); + input_order = order_dfs_from_count(output, leaves, DFS_ORDER, &next_index, options->verbose); + add_new_inputs(seq_info, input_order); + array_free(input_order); + } + + /* then add all the input variables that have not been handled so far */ + input_order = array_alloc(node_t *, 0); + table_gen = st_init_gen(leaves); + while (st_gen_int(table_gen, (char**) &input, &index)) { + if (index == -1) { + array_insert_last(node_t *, input_order, input); + } + } + st_free_gen(table_gen); + for (i = 0; i < array_n(input_order); i++) { + input = array_fetch(node_t *, input_order, i); + SetVariableOrder(leaves, input, i + next_index, options->verbose); + } + add_new_inputs(seq_info, input_order); + array_free(input_order); + + /* finally treat the next_state_vars: should be in the same order as present_state_vars */ + add_next_state_vars(seq_info, next_state_table); + + /* clean up and consistency check */ + st_free_table(next_state_table); + assert(array_n(seq_info->input_vars) == network_num_pi(seq_info->network)); + + /* debug information */ + if (options->verbose >= 1) { + (void) fprintf(sisout, "Variable ordering selected for product method:\n"); + for (i = 0; i < array_n(seq_info->var_names); i++) { + (void) fprintf(sisout, "%s<id=%d> ", array_fetch(char *, seq_info->var_names, i), i); + if (i % 8 == 7) (void) fprintf(sisout, "\n"); + } + if (i % 8 != 7) (void) fprintf(sisout, "\n"); + } + if (options->verbose >= 2) { + int discrepancy_found = 0; + (void) fprintf(sisout, "Checking the indices of input variables ... \n"); + for (i = 0; i < array_n(seq_info->input_nodes); i++) { + input = array_fetch(node_t *, seq_info->input_nodes, i); + assert(st_lookup_int(seq_info->leaves, (char *) input, &index)); + (void) fprintf(sisout, "%s<id=%d> ", input->name, index); + if (i % 8 == 7) (void) fprintf(sisout, "\n"); + discrepancy_found |= strcmp(input->name, array_fetch(char *, seq_info->var_names, index)); + } + if (i % 8 != 7) (void) fprintf(sisout, "\n"); + assert(discrepancy_found == 0); + (void) fprintf(sisout, "Check passed. \n"); + } +} + +/* + *---------------------------------------------------------------------- + * + * add_new_inputs -- INTERNAL ROUTINE + * + * For each node found in 'node_list' that is a PI, add: + * 1. to 'seq_info->var_names', the name of that PI + * 2. to 'seq_info->input_nodes', a pointer to that PI + * 3. either to 'seq_info->external_input_vars' + * or to 'seq_info->present_state_vars' a bdd_t* + * representing that PI as a BDD variable. + * + *---------------------------------------------------------------------- + */ + +static void add_new_inputs(seq_info, node_list) +seq_info_t *seq_info; +array_t *node_list; +{ + int i; + int index; + node_t *input; + bdd_t *var; + + for (i = 0; i < array_n(node_list); i++) { + input = array_fetch(node_t *, node_list, i); + if (input->type != PRIMARY_INPUT) continue; + array_insert_last(char *, seq_info->var_names, util_strsav(input->name)); + array_insert_last(node_t *, seq_info->input_nodes, input); + assert(st_lookup_int(seq_info->leaves, (char *) input, &index)); + assert(index >= 0); + var = bdd_get_variable(seq_info->manager, index); + array_insert_last(bdd_t *, seq_info->input_vars, var); + var = bdd_dup(var); + if (network_is_real_pi(seq_info->network, input)) { + array_insert_last(bdd_t *, seq_info->external_input_vars, var); + } else { + array_insert_last(bdd_t *, seq_info->present_state_vars, var); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * add_next_state_vars -- INTERNAL ROUTINE + * + * The next_state_vars should be inserted in the same order + * as they appear in 'present_state_vars'. + * + *---------------------------------------------------------------------- + */ + +static void add_next_state_vars(seq_info, next_state_table) +seq_info_t *seq_info; +st_table *next_state_table; +{ + int i; + int index; + bdd_t *var; + node_t *input; + node_t *output; + network_t *network = seq_info->network; + + for (i = 0; i < array_n(seq_info->input_nodes); i++) { + input = array_fetch(node_t *, seq_info->input_nodes, i); + if (network_is_real_pi(network, input)) continue; + output = network_latch_end(input); + assert(st_lookup_int(next_state_table, (char *) output, &index)); + var = bdd_get_variable(seq_info->manager, index); + array_insert_last(bdd_t *, seq_info->transition.next_state_vars, var); + } +} + +static void extract_support_info_rec ARGS((node_t *, st_table *, st_table *, var_set_t *)); + +/* + *---------------------------------------------------------------------- + * + * extract_support_info -- INTERNAL ROUTINE + * + * Results: + * returns a var_set_t containing + * in bitmap the info: which PI is in the support of the node. + * Skips over those nodes that are not PI's. + * + *---------------------------------------------------------------------- + */ + +static var_set_t **extract_support_info(network, node_list) +network_t *network; +array_t *node_list; +{ + int i, uid; + lsGen gen; + node_t *input, *output; + int n_pi = network_num_pi(network); + int n_po = array_n(node_list); + st_table *pi_table = st_init_table(st_ptrcmp, st_ptrhash); + var_set_t **support_info = ALLOC(var_set_t *, n_po); + + for (i = 0; i < n_po; i++) { + support_info[i] = var_set_new(n_pi); + } + uid = 0; + foreach_primary_input(network, gen, input) { + st_insert(pi_table, (char *) input, (char *) uid); + uid++; + } + for (i = 0; i < array_n(node_list); i++) { + st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); + output = array_fetch(node_t *, node_list, i); + extract_support_info_rec(output, pi_table, visited, support_info[i]); + st_free_table(visited); + } + st_free_table(pi_table); + return support_info; +} + +static void extract_support_info_rec(node, pi_table, visited, set) +node_t *node; +st_table *pi_table; +st_table *visited; +var_set_t *set; +{ + int i; + node_t *fanin; + int uid; + + if (st_lookup(visited, (char *) node, NIL(char *))) return; + st_insert(visited, (char *) node, NIL(char)); + if (node->type == PRIMARY_INPUT) { + assert(st_lookup_int(pi_table, (char *) node, &uid)); + var_set_set_elt(set, uid); + } else { + foreach_fanin(node, i, fanin) { + extract_support_info_rec(fanin, pi_table, visited, set); + } + } +} + + +/* + *---------------------------------------------------------------------- + * + * order_dfs_from_count -- INTERNAL ROUTINE + * + * A hack: order PIs reached from 'node' starting at 'order_count'. + * The hack is necessary due to the fact that the library routine + * 'order_dfs' is not general enough to start allocating variable indices + * from another value than 0. We call 'order_dfs' and shift the resulting + * ordering using '*order_count' as an offset. We check that PIs + * have not been allocated an index previously by looking in 'leaves'. + * + * Results: + * returns an array of PIs for which a variable ordering has been found. + * + * Side effects: + * 1. stores that variable ordering in 'leaves'. + * 2. increments '*order_count' by the number of PIs returned. + * + *---------------------------------------------------------------------- + */ + +static array_t *order_dfs_from_count(node, leaves, fixed_root_order, order_count, verbosity) +node_t *node; /* root node: its transitive fanin has to be ordered */ +st_table *leaves; /* where the dfs search stops: those nodes have to be ordered */ +int fixed_root_order; /* flag: if set, can't change the order of visit of the roots */ +int *order_count; /* start the var indices from '*order_count' */ +int verbosity; +{ + st_generator *gen; + char *key; + char* value; + int i, index; + int previous_index; + array_t *roots; + array_t *nodes; + array_t *result; + + st_table *local_leaves = st_init_table(st_ptrcmp, st_ptrhash); + st_foreach_item(leaves, gen, &key, &value) { + ResetVariableOrder(local_leaves, (node_t *) key); + } + roots = array_alloc(node_t *, 0); + array_insert_last(node_t *, roots, node); + nodes = order_dfs(roots, local_leaves, DFS_ORDER); + array_free(roots); + + /* + * If the node already has an index (i.e. >= 0) + * we skip it (i.e. we keep the index it has). + * Otherwise we look into 'local_leaves'. + * If the node does not have either an index in 'local_leaves' + * either, we skip it. Otherwise, we store it into the array 'result'. + * 'previous_index' is here just as a consistency check. + */ + + result = array_alloc(node_t *, 0); + previous_index = -1; + for (i = 0; i < array_n(nodes); i++) { + node = array_fetch(node_t *, nodes, i); + if (node->type != PRIMARY_INPUT) continue; + assert(st_lookup_int(leaves, (char *) node, &index)); + if (index >= 0) continue; + assert(st_lookup_int(local_leaves, (char *) node, &index)); + if (index == -1) continue; + assert(previous_index < index); + previous_index = index; + array_insert_last(node_t *, result, node); + } + array_free(nodes); + st_free_table(local_leaves); + + /* + * For each node in 'result', we store a varid in 'leaves'. + * That varid is the index of the node in 'result' + * offset by '*order_count'. + */ + + for (i = 0; i < array_n(result); i++) { + node = array_fetch(node_t *, result, i); + SetVariableOrder(leaves, node, i + *order_count, verbosity); + } + + *order_count += array_n(result); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * ResetVariableOrder -- INTERNAL ROUTINE + * + *---------------------------------------------------------------------- + */ + +static void ResetVariableOrder(leaves, node) +st_table *leaves; +node_t *node; +{ + int index; + + assert(! st_lookup_int(leaves, (char *) node, &index)); + st_insert(leaves, (char *) node, (char *) -1); +} + +/* + *---------------------------------------------------------------------- + * + * SetVariableOrder -- INTERNAL ROUTINE + * + *---------------------------------------------------------------------- + */ + +static void SetVariableOrder(leaves, node, varid, verbosity) +st_table *leaves; +node_t *node; +int varid; +int verbosity; +{ + int index; + + if (verbosity >= 2) { + (void) fprintf(sisout, "set var id: %s <id=%d>\n", node->name, varid); + assert(st_lookup_int(leaves, (char *) node, &index)); + assert(index == -1); + } + st_insert(leaves, (char *) node, (char *) varid); +} + + + +/* + *---------------------------------------------------------------------- + * + * Prl_ProductInitSeqInfo -- EXPORTED ROUTINE + * + * Side effects: + * Allocates the transition relation part of the 'seq_info' records. + * + *---------------------------------------------------------------------- + */ + +void Prl_ProductInitSeqInfo(seq_info, options) +seq_info_t *seq_info; +prl_options_t *options; +{ + int i; + bdd_t *fn; + bdd_t *var; + int n_elts; + array_t *xnor_array; + + n_elts = array_n(seq_info->next_state_fns); + xnor_array = array_alloc(bdd_t *, n_elts); + for (i = 0; i < n_elts; i++) { + fn = array_fetch(bdd_t *, seq_info->next_state_fns, i); + var = array_fetch(bdd_t *, seq_info->transition.transition_vars, i); + fn = bdd_xnor(fn, var); + array_insert_last(bdd_t *, xnor_array, fn); + } + seq_info->transition.product.transition_fns = xnor_array; +} + +/* + *---------------------------------------------------------------------- + * + * Prl_ProductFreeSeqInfo -- EXPORTED ROUTINE + * + * Side effects: + * Frees the transition relation part of the 'seq_info' records. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ + +void Prl_ProductFreeSeqInfo(seq_info, options) +seq_info_t *seq_info; +prl_options_t *options; +{ + Prl_FreeBddArray(seq_info->transition.transition_vars); + Prl_FreeBddArray(seq_info->transition.next_state_vars); + Prl_FreeBddArray(seq_info->transition.product.transition_fns); +} + + +/* + *---------------------------------------------------------------------- + * + * Prl_ProductExtractNextworkInputNames -- EXPORTED ROUTINE + * + * Results: + * Returns an array of char*, where the name of each PI + * is stored in order, except for the PIs that have been + * inserted for the product / consistency methods. + * Those PIs get a NULL pointer instead. + * + *---------------------------------------------------------------------- + */ + +array_t *Prl_ProductExtractNetworkInputNames(seq_info, options) +seq_info_t *seq_info; +prl_options_t *options; +{ + int i; + array_t *result; + char *name; + + result = array_alloc(char *, 0); + for (i = 0; i < array_n(seq_info->var_names); i++) { + name = array_fetch(char *, seq_info->var_names, i); + if (name[0] == 'y' && name[1] == ':') name = NIL(char); + array_insert_last(char *, result, name); + } + return result; +} + + + +static bdd_t *BddIncrAndSmooth ARGS((seq_info_t *, bdd_t *, array_t *, prl_options_t *)); + +/* + *---------------------------------------------------------------------- + * + * Prl_ProductComputeNextStates -- EXTERNAL ROUTINE + * + * Results: + * the states reachable in one step from the states in 'current_set'. + * + * Side effects: + * Does not free 'current_set'. + * + *---------------------------------------------------------------------- + */ + +bdd_t *Prl_ProductComputeNextStates(current_set, seq_info, options) +bdd_t *current_set; +seq_info_t *seq_info; +prl_options_t *options; +{ + bdd_t *result_as_next_state_vars; + bdd_t *new_current_set; + + if (bdd_is_tautology(current_set, 0)) { + result_as_next_state_vars = bdd_dup(current_set); + } else { + result_as_next_state_vars = BddIncrAndSmooth(seq_info, + current_set, + seq_info->transition.next_state_vars, + options); + } + new_current_set = bdd_substitute(result_as_next_state_vars, + seq_info->transition.next_state_vars, + seq_info->present_state_vars); + + if (options->verbose >= 3) { + (void) fprintf(sisout, + "(%d->%d)]", + bdd_size(result_as_next_state_vars), + bdd_size(new_current_set)); + + (void) fflush(sisout); + } + + bdd_free(result_as_next_state_vars); + return new_current_set; +} + +/* + *---------------------------------------------------------------------- + * + * Prl_ProductReverseImage -- EXTERNAL ROUTINE + * + * Traverses a sequential circuit backwards. + * + *---------------------------------------------------------------------- + */ + +bdd_t *Prl_ProductReverseImage(next_set, seq_info, options) +bdd_t *next_set; +seq_info_t *seq_info; +prl_options_t *options; +{ + bdd_t *next_set_as_next_state_vars; + bdd_t *result; + + next_set_as_next_state_vars = bdd_substitute(next_set, + seq_info->present_state_vars, + seq_info->transition.next_state_vars); + + result = BddIncrAndSmooth(seq_info, + next_set_as_next_state_vars, + seq_info->input_vars, + options); + + bdd_free(next_set_as_next_state_vars); + return result; +} + + + + + /* INTERNAL INTERFACE */ + + /* types used in PRODUCT for smoothing as soon as possible */ + +typedef struct { + int varid; + bdd_t *var; /* result of bdd_get_variable(mgr, varid) */ + st_table *fn_table; /* list of indices of fns depending on that variable in fns[] */ + int last_index; /* the most recent fn index depending on this var */ +} var_info_t; + +typedef struct { + int fnid; /* small integer; unique identifier for the function */ + bdd_t *fn; /* accumulation of AND's of functions */ + int cost; /* simply an index for static merging; */ + /* size of bdd for dynamic merging */ + var_set_t *support; /* support of that function */ + int partition; /* to which partition the fn belongs */ +} fn_info_t; + + + /* should avoid smoothing out next_state_vars ... */ + +typedef struct { + int n_fns; + fn_info_t **fns; + int n_vars; + var_info_t **vars; + queue_t *queue; /* priority queue where to store the functions by size */ + bdd_manager *manager; + int n_partitions; + int *partition_count; /* number of fns alive in each partition */ + int *next_partition; /* map to tell in which partition to go when current one is empty */ +} support_info_t; + + /* result < 0 means obj1 higher priority than obj2 (obj1 comes first) */ + +static int fn_info_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + int diff; + fn_info_t *info1 = (fn_info_t *) obj1; + fn_info_t *info2 = (fn_info_t *) obj2; + diff = info1->partition - info2->partition; + if (diff == 0) diff = info1->cost - info2->cost; + return diff; +} + +static void fn_info_print(obj) +char *obj; +{ + fn_info_t *info = (fn_info_t *) obj; + (void) fprintf(misout, "fn %d", info->fnid); +} + + +static support_info_t *support_info_extract ARGS((seq_info_t *, bdd_t **, int, array_t *, prl_options_t *)); +static void support_info_free ARGS((support_info_t *)); +static bdd_t * do_fn_merging ARGS((support_info_t *, prl_options_t *)); + +/* + *---------------------------------------------------------------------- + * + * BddIncrAndSmooth -- INTERNAL ROUTINE + * + * Performs the bdd_and and the existential quantifier in one step. + * The existential quantifier is applied as early as possible. + * + *---------------------------------------------------------------------- + */ + +static bdd_t *BddIncrAndSmooth(seq_info, current_set, keep_vars, options) +seq_info_t *seq_info; +bdd_t *current_set; +array_t *keep_vars; +prl_options_t *options; +{ + int i; + int n_fns; + bdd_t *tmp; + bdd_t **fns; + bdd_t *resulting_product; + support_info_t *support_info; + array_t *transition_outputs; + + if (options->verbose >= 3) { + (void) fprintf(misout, "["); (void) fflush(misout); + } + + transition_outputs = seq_info->transition.product.transition_fns; + n_fns = array_n(transition_outputs); + fns = ALLOC(bdd_t *, n_fns); + for (i = 0; i < n_fns; i++) { + tmp = array_fetch(bdd_t *, transition_outputs, i); + fns[i] = bdd_cofactor(tmp, current_set); + if (options->verbose >= 3) { + (void) fprintf(misout, "(#%d->%d),", i, bdd_size(tmp)); + (void) fprintf(misout, "(#%d->%d),", i, bdd_size(fns[i])); + (void) fflush(misout); + } + } + + support_info = support_info_extract(seq_info, fns, n_fns, keep_vars, options); + FREE(fns); + resulting_product = do_fn_merging(support_info, options); + support_info_free(support_info); + return resulting_product; +} + + +static void extract_var_info ARGS((support_info_t *, st_table *)); +static void smooth_lonely_variables ARGS((support_info_t *, prl_options_t *)); +static void initialize_partition_info ARGS((support_info_t *)); +static st_table *get_varids_in_table ARGS((array_t *)); +static void extract_fn_info ARGS((support_info_t *, bdd_t **, prl_options_t *)); + +/* + *---------------------------------------------------------------------- + * + * support_info_extract -- INTERNAL ROUTINE + * + *---------------------------------------------------------------------- + */ + +static support_info_t *support_info_extract(seq_info, fns, n_fns, keep_vars, options) +seq_info_t *seq_info; +bdd_t **fns; +int n_fns; +array_t *keep_vars; +prl_options_t *options; +{ + int i; + st_table *skip_varids; + support_info_t *support_info = ALLOC(support_info_t, 1); + + support_info->n_fns = n_fns; + + /* allocate a priority queue for storing the functions */ + support_info->queue = init_queue(support_info->n_fns, fn_info_cmp, fn_info_print); + + /* compute the info related to each fn */ + support_info->fns = ALLOC(fn_info_t *, support_info->n_fns); + extract_fn_info(support_info, fns, options); + + /* get a hash table containing the varids of all the next state variables */ + skip_varids = get_varids_in_table(keep_vars); + + /* compute the info related to each variable; skip over next_state_vars */ + support_info->manager = seq_info->manager; + support_info->n_vars = array_n(seq_info->var_names); + support_info->vars = ALLOC(var_info_t *, support_info->n_vars); + extract_var_info(support_info, skip_varids); + + /* simple static binary tree */ + support_info->n_partitions = support_info->n_fns; + for (i = 0; i < support_info->n_fns; i++) { + support_info->fns[i]->partition = i; + } + initialize_partition_info(support_info); + + /* smooth now all variables that appear only once */ + smooth_lonely_variables(support_info, options); + + /* deallocate what is no longer needed */ + st_free_table(skip_varids); + + return support_info; +} + + /* ARGSUSED */ +static void extract_fn_info(support_info, fns, options) +support_info_t *support_info; +bdd_t **fns; +prl_options_t *options; +{ + int i; + fn_info_t *info; + + for (i = 0; i < support_info->n_fns; i++) { + info = ALLOC(fn_info_t, 1); + info->fnid = i; + info->partition = 0; + info->fn = fns[i]; + info->support = bdd_get_support(fns[i]); + info->cost = i; + put_queue(support_info->queue, (char *) info); + support_info->fns[i] = info; + } +} + + + /* extract varids from array of bdd_t *'s and put in a hash table */ +static st_table *get_varids_in_table(bdd_array) +array_t *bdd_array; +{ + int i; + int varid; + st_table *result = st_init_table(st_numcmp, st_numhash); + array_t *var_array = bdd_get_varids(bdd_array); + + for (i = 0; i < array_n(var_array); i++) { + varid = array_fetch(int, var_array, i); + st_insert(result, (char *) varid, NIL(char)); + } + array_free(var_array); + return result; +} + + + /* valid for all methods */ + /* compute n such that n = 2^p <= n_partitions < 2^{p+1} */ + /* compute x such that x + n = n_partitions */ + /* x is guaranteed to be such that 2 * x < n_partitions */ + +static void initialize_partition_info(support_info) +support_info_t *support_info; +{ + int n_partitions; + int partition; + int i, n, x; + int count; + int n_entries; + int *partition_map; + st_table *table = st_init_table(st_numcmp, st_numhash); + + if (support_info->n_fns == 0) { + support_info->partition_count = ALLOC(int, 0); + support_info->next_partition = ALLOC(int, 0); + return; + } + + /* first make the partition identifiers consecutive integers from 0 to n_entries - 1 */ + n_partitions = 0; + for (i = 0; i < support_info->n_fns; i++) { + if (st_lookup_int(table, (char *) support_info->fns[i]->partition, &partition)) { + support_info->fns[i]->partition = partition; + } else { + st_insert(table, (char *) support_info->fns[i]->partition, (char *) n_partitions); + support_info->fns[i]->partition = n_partitions++; + } + } + st_free_table(table); + + /* just a consistency check */ + assert(n_partitions == support_info->n_partitions); + + /* compute n=2^p such that 2^p <= n_partitions < 2^{p+1} */ + /* and compute x = n_partitions - 2^p */ + for (n = 1; n <= n_partitions; n <<= 1) ; + if (n > n_partitions) n >>= 1; + assert(n <= n_partitions && 2 * n > n_partitions); + x = n_partitions - n; + + /* make the map from small integers to partition identifiers */ + partition_map = ALLOC(int, n_partitions); + for (i = 0; i < 2 * x; i++) { + partition_map[i] = i; + } + for (i = 2 * x; i < n_partitions; i++) { + partition_map[i] = i + x; + } + + /* make the map from one node in the binary tree of AND's to the next higher one */ + n_entries = n_partitions * 2 - 1; + support_info->next_partition = ALLOC(int, n_entries); + for (i = 0; i < 2 * x; i++) { + support_info->next_partition[i] = 2 * x + i / 2; + } + for (count = n_entries - 1, i = n_entries - 3; i >= 2 * x; i -= 2, count--) { + support_info->next_partition[i] = count; + support_info->next_partition[i + 1] = count; + } + support_info->next_partition[n_entries - 1] = n_entries - 1; + + /* the hard part is done; simple bookkeeping now */ + support_info->partition_count = ALLOC(int, n_entries); + for (i = 0; i < n_entries; i++) { + support_info->partition_count[i] = 0; + } + for (i = 0; i < support_info->n_fns; i++) { + support_info->fns[i]->partition = partition_map[support_info->fns[i]->partition]; + support_info->partition_count[support_info->fns[i]->partition]++; + adj_queue(support_info->queue, (char *) support_info->fns[i]); + } + FREE(partition_map); +} + + +static var_info_t *var_info_free ARGS((var_info_t *)); + +/* + *---------------------------------------------------------------------- + * + * smooth_lonely_variables -- EXPORTED ROUTINE + * + * smooth (existentially quantify) all variables that appear only once. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ + +static void smooth_lonely_variables(support_info, options) +support_info_t *support_info; +prl_options_t *options; +{ + int varid; + int index; + bdd_t *tmp; + int remaining; + array_t *var_array; + + var_array = array_alloc(bdd_t *, 1); + for (varid = 0; varid < support_info->n_vars; varid++) { + if (support_info->vars[varid] == NIL(var_info_t)) continue; + remaining = st_count(support_info->vars[varid]->fn_table); + if (remaining == 1) { + array_insert(bdd_t *, var_array, 0, support_info->vars[varid]->var); + index = support_info->vars[varid]->last_index; + tmp = bdd_smooth(support_info->fns[index]->fn, var_array); + bdd_free(support_info->fns[index]->fn); + support_info->fns[index]->fn = tmp; + } + if (remaining == 0 || remaining == 1) { + var_info_free(support_info->vars[varid]); + support_info->vars[varid] = NIL(var_info_t); + } + } + array_free(var_array); +} + + +static void fn_info_free ARGS((fn_info_t *)); +static array_t *smooth_vars_extract ARGS((support_info_t *, fn_info_t *, fn_info_t *)); + +/* + *---------------------------------------------------------------------- + * + * do_fn_merging -- INTERNAL ROUTINE + * + * AND all functions together and return the result. + * + *---------------------------------------------------------------------- + */ + + +static bdd_t *do_fn_merging(support_info, options) +support_info_t *support_info; +prl_options_t *options; +{ + int i; + bdd_t *tmp; + fn_info_t *fn0, *fn1; + array_t *smooth_vars; + + if (support_info->n_fns == 0) return bdd_one(support_info->manager); + + /* fn1 disappears after being anded to fn0 */ + for (;;) { + fn0 = (fn_info_t *) get_queue(support_info->queue); + assert(fn0 != NIL(fn_info_t)); + fn1 = (fn_info_t *) get_queue(support_info->queue); + if (fn1 == NIL(fn_info_t)) break; + smooth_vars = smooth_vars_extract(support_info, fn0, fn1); + if (array_n(smooth_vars) == 0) { + tmp = bdd_and(fn0->fn, fn1->fn, 1, 1); + } else { + tmp = bdd_and_smooth(fn0->fn, fn1->fn, smooth_vars); + } + bdd_free(fn0->fn); + fn0->fn = tmp; + + /* if fn0 is the last of its partition, promote it in a higher partition */ + support_info->partition_count[fn1->partition]--; + if (support_info->partition_count[fn0->partition] == 1) { + support_info->partition_count[fn0->partition]--; + fn0->partition = support_info->next_partition[fn0->partition]; + support_info->partition_count[fn0->partition]++; + } + /* adjust the costs */ + fn0->cost += support_info->n_fns; + put_queue(support_info->queue, (char *) fn0); + + if (options->verbose >= 3) { + if (array_n(smooth_vars) > 0) { + (void) fprintf(misout, "(s%d/#%d->#%d,%d),", array_n(smooth_vars), fn1->fnid, fn0->fnid, bdd_size(fn0->fn)); + } else { + (void) fprintf(misout, "(#%d->#%d,%d),", fn1->fnid, fn0->fnid, bdd_size(fn0->fn)); + } + (void) fflush(misout); + } + support_info->fns[fn1->fnid] = NIL(fn_info_t); + fn_info_free(fn1); + for (i = 0; i < array_n(smooth_vars); i++) { + tmp = array_fetch(bdd_t *, smooth_vars, i); + bdd_free(tmp); + } + array_free(smooth_vars); + } + tmp = bdd_dup(fn0->fn); + support_info->fns[fn0->fnid] = NIL(fn_info_t); + fn_info_free(fn0); + return tmp; +} + + + /* a variable still active here appears in at least two functions */ + /* thus the assertion. If the two functions are fns[index0] and fns[index1] */ + /* we can smooth that variable out now */ + /* can only disappear if it is in both; some bookkeeping if it is in index1 and not in index0 */ + +static array_t *smooth_vars_extract(support_info, fn0, fn1) +support_info_t *support_info; +fn_info_t *fn0; +fn_info_t *fn1; +{ + int i; + char *key; + int remaining; + array_t *result; + int is_in_index0; + int is_in_index1; + var_info_t *var_info; + + result = array_alloc(bdd_t *, 0); + for (i = 0; i < support_info->n_vars; i++) { + var_info = support_info->vars[i]; + if (var_info == NIL(var_info_t)) continue; + remaining = st_count(var_info->fn_table); + assert(remaining > 1); + is_in_index1 = var_set_get_elt(fn1->support, i); + if (! is_in_index1) continue; + is_in_index0 = var_set_get_elt(fn0->support, i); + if (! is_in_index0) { /* move var i to fn0 */ + var_set_set_elt(fn0->support, i); + key = (char *) fn1->fnid; /* for 64 bit support */ + st_delete(var_info->fn_table, &key, NIL(char *)); + st_insert(var_info->fn_table, (char *) fn0->fnid, NIL(char)); + } else if (remaining == 2) { /* is in both fns only: can be smoothed out */ + array_insert_last(bdd_t *, result, bdd_dup(var_info->var)); + var_info_free(var_info); + support_info->vars[i] = NIL(var_info_t); + } else { /* is in both but somewhere else as well: remove fn1 occurrence */ + key = (char *) fn1->fnid; + st_delete(var_info->fn_table, &key, NIL(char *)); + } + } + return result; +} + +static void support_info_free(support_info) +support_info_t *support_info; +{ + int i; + + free_queue(support_info->queue); + for (i = 0; i < support_info->n_vars; i++) { + assert(support_info->vars[i] == NIL(var_info_t)); + } + FREE(support_info->vars); + for (i = 0; i < support_info->n_fns; i++) { + assert(support_info->fns[i] == NIL(fn_info_t)); + } + FREE(support_info->fns); + FREE(support_info->partition_count); + FREE(support_info->next_partition); + FREE(support_info); +} + +static void fn_info_free(info) +fn_info_t *info; +{ + var_set_free(info->support); + bdd_free(info->fn); + FREE(info); +} + + + /* creates an object with a varid, the corresponding BDD and a hash table */ + /* containing the indices of the fns having the varid in their support */ + +static void extract_var_info(support_info, skip_varids) +support_info_t *support_info; +st_table *skip_varids; +{ + int i; + int varid; + var_info_t *info; + + for (varid = 0; varid < support_info->n_vars; varid++) { + if (st_lookup(skip_varids, (char *) varid, NIL(char *))) { + support_info->vars[varid] = NIL(var_info_t); + continue; + } + info = ALLOC(var_info_t, 1); + info->varid = varid; + info->var = bdd_get_variable(support_info->manager, varid); + info->last_index = -1; + info->fn_table = st_init_table(st_numcmp, st_numhash); + for (i = 0; i < support_info->n_fns; i++) { + if (var_set_get_elt(support_info->fns[i]->support, varid)) { + assert(i == support_info->fns[i]->fnid); + st_insert(info->fn_table, (char *) i, NIL(char)); + info->last_index = i; + } + } + support_info->vars[varid] = info; + } +} + +static var_info_t *var_info_free(info) +var_info_t *info; +{ + bdd_free(info->var); + st_free_table(info->fn_table); + FREE(info); +} + +#endif /* SIS */ diff --git a/sis/seqbdd/prl_remlatch.c b/sis/seqbdd/prl_remlatch.c new file mode 100644 index 0000000..2a463ab --- /dev/null +++ b/sis/seqbdd/prl_remlatch.c @@ -0,0 +1,1222 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prl_remlatch.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + +#ifdef SIS +#include "sis.h" +#include "prl_util.h" + + +static void PerformLocalRetiming ARGS((network_t *, int)); +static void FirstFitLatchRemoval ARGS((network_t *, seq_info_t *, bdd_t *, prl_options_t *)); +static void RemoveOneBootLatch ARGS((network_t *, prl_options_t *)); +static bdd_t *GetReachableStatesFromDc ARGS((seq_info_t *, prl_options_t *)); + + +/* + *---------------------------------------------------------------------- + * + * Prl_RemoveLatches -- EXPORTED ROUTINE + * + * 1. Remove latches that are functionally deducible from the others. + * Latches whose equivalent combinational logic has too many inputs + * (exceeding some threshold specified as a command line parameter) + * are not removed. + * 2. In addition, performs some local retiming by moving latches + * forward if that reduces the total latch count. + * 3. Finally, tries to remove boot latches (i.e. latches fed by a constant + * but initialized by a different constant) by looking for a state + * equivalent to the initial state in which the initial value of the latch + * is equal to the value of its constant input. + * + * Results: + * None. + * + * Side effects: + * The network is modified in place. + * To avoid problems with don't care networks (may depend on PI variables + * that do not exist any more after latch removal), we destroy the dc_network + * if there is one. + * + *---------------------------------------------------------------------- + */ + +void Prl_RemoveLatches(network, options) +network_t *network; +prl_options_t *options; +{ + seq_info_t *seq_info; + bdd_t *reachable_states; + network_t *new_network; + int n_latches, new_n_latches; + + /* remove logically redundant latches */ + new_network = network_dup(network); + seq_info = Prl_SeqInitNetwork(new_network, options); + reachable_states = GetReachableStatesFromDc(seq_info, options); + if (network->dc_network != NIL(network_t) && bdd_is_tautology(reachable_states, 1)) { + (void) fprintf(siserr, "no reachability information found in don't care network\n"); + } + FirstFitLatchRemoval(network, seq_info, reachable_states, options); + bdd_free(reachable_states); + Prl_SeqInfoFree(seq_info, options); + network_free(new_network); + + /* remove the DC network */ + Prl_RemoveDcNetwork(network); + + /* remove the boot latches */ + if (options->remlatch.remove_boot) { + do { + n_latches = network_num_latch(network); + RemoveOneBootLatch(network, options); + network_sweep(network); + new_n_latches = network_num_latch(network); + } while (new_n_latches < n_latches); + } + + /* push latches forward across logic if it decreases latch count */ + if (options->remlatch.local_retiming) { + PerformLocalRetiming(network, options->verbose); + } +} + + +/* + *---------------------------------------------------------------------- + * + * GetReachableStatesFromDc -- INTERNAL ROUTINE + * + * Results: + * Computes the bdd_and of all external don't cares. + * Complements it. + * Existentially quantify the external inputs. + * + * Side Effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static bdd_t *GetReachableStatesFromDc(seq_info, options) +seq_info_t *seq_info; +prl_options_t *options; +{ + bdd_t *reachable_states; + bdd_t *tmp = Prl_GetSimpleDc(seq_info); + bdd_t *all_inputs = bdd_not(tmp); + bdd_free(tmp); + reachable_states = bdd_smooth(all_inputs, seq_info->external_input_vars); + bdd_free(all_inputs); + return reachable_states; +} + + + + /* INTERNAL INTERFACE */ + +/* Structure used by 'latch_removal'. */ + +typedef struct { + bdd_t *var; /* the PI (latch output) identifying a latch */ + bdd_t *recoding_fn; /* the combinational logic fn that can be substituted to the latch */ + bdd_t *recoding_fn_dc; /* the don't care of that function (unreachable states) */ + bdd_t *new_set; /* the set of reachable states after this var is removed (if red.) */ + int support_size; /* the size of the support of the recoding_fn */ + int output_distance; /* the depth of the output of 'recoding_fn' */ +} var_info_t; + +/* It seems that only 'old_vars' is ever used */ + +typedef struct { + bdd_manager *manager; + array_t *old_vars; /* of bdd_t*; present state variables */ + array_t *new_vars; /* of bdd_t*; as many as 'old_vars'; fresh variables */ + array_t *support_vars; /* of bdd_t*; as many as 'old_vars'; fresh variables */ + st_table *new_to_support_map; /* int-->int; maps new_vars->id --> support_vars->id */ +} extra_vars_t; + +static extra_vars_t *extra_vars_alloc(); +static int get_output_distance(); +static int get_output_distance_rec(); +static int save_enough_latches(); +static st_table *compute_from_var_to_pi_table(); +static void extra_vars_free(); +static void extract_var_info(); +static void get_good_support_fn(); +static void get_minimum_support_fn(); +static void move_latches_forward(); +static void red_latch_remove_latches(); +static void RemoveOneLatch(); +static void RemoveRedundantLatches(); +static void remove_unused_pis(); +static void replace_latch_by_node(); + + +/* Where the real work is done. + * We do the modifications directly on 'network'. + * WARNING: seq_info->network is a COPY of 'network', not the same network. + */ + +static void FirstFitLatchRemoval(network, seq_info, valid_states, options) +network_t *network; +seq_info_t *seq_info; +bdd_t *valid_states; +prl_options_t *options; +{ + int i; + bdd_t *set; + bdd_t *var; + node_t *pi; + array_t *var_array; + var_info_t var_info; + array_t *state_vars; + extra_vars_t *extra_vars; + array_t *input_names; + st_table *from_var_to_pi; + + input_names = (*options->extract_network_input_names)(seq_info, options); + from_var_to_pi = compute_from_var_to_pi_table(network, seq_info, input_names); + + extra_vars = extra_vars_alloc(seq_info); + state_vars = seq_info->present_state_vars; + var_array = array_alloc(var_info_t, 0); + set = bdd_dup(valid_states); + for (i = 0; i < array_n(state_vars); i++) { + var = array_fetch(bdd_t *, state_vars, i); + extract_var_info(extra_vars, var, set, &var_info); + if (var_info.var == NIL(bdd_t)) continue; + if (var_info.support_size > options->remlatch.max_cost) { + if (options->verbose > 0) { + (void) fprintf(siserr, "latch support %d too large\n", var_info.support_size); + } + bdd_free(var_info.new_set); + bdd_free(var_info.recoding_fn); + bdd_free(var_info.recoding_fn_dc); + continue; + } + if (options->verbose > 0) { + assert(st_lookup(from_var_to_pi, (char *) var_info.var, (char **) &pi)); + (void) fprintf(siserr, "remove latch [%s] of support %d\n", + io_name(pi, 0), + var_info.support_size); + } + array_insert_last(var_info_t, var_array, var_info); + bdd_free(set); + set = bdd_dup(var_info.new_set); + } + extra_vars_free(extra_vars); + st_free_table(from_var_to_pi); + array_free(input_names); + + RemoveRedundantLatches(network, seq_info, var_array, options); + + for (i = 0; i < array_n(var_array); i++) { + var_info = array_fetch(var_info_t, var_array, i); + bdd_free(var_info.new_set); + bdd_free(var_info.recoding_fn); + bdd_free(var_info.recoding_fn_dc); + } + array_free(var_array); +} + +/* + * a variable can be removed iff all the minterms in 'set' + * can still be distinguished in the variable is removed. + * This is equivalent to saying that the universal quantifier + * applied to 'set' on the candidate variable yields the empty set. + * For all such variables, we compute the size of its minimum support. + * We remove the variables of smaller support first. + */ + +static void extract_var_info(extra_vars, var, set, var_info) +extra_vars_t *extra_vars; +bdd_t *var; +bdd_t *set; +var_info_t *var_info; +{ + int var_is_redundant; + bdd_t *independence_check; + bdd_t *fn, *dc; + bdd_t *new_fn, *new_dc; + int support_size; + array_t *var_array; + + var_array = array_alloc(bdd_t *, 0); + array_insert_last(bdd_t *, var_array, var); + independence_check = bdd_consensus(set, var_array); + var_is_redundant = bdd_is_tautology(independence_check, 0); + bdd_free(independence_check); + if (var_is_redundant) { + var_info->var = var; + var_info->new_set = bdd_smooth(set, var_array); + fn = bdd_cofactor(set, var); + dc = bdd_not(var_info->new_set); + get_good_support_fn(extra_vars, fn, dc, &support_size, &new_fn, &new_dc); + var_info->recoding_fn = new_fn; + var_info->recoding_fn_dc = new_dc; + var_info->support_size = support_size; + bdd_free(fn); + bdd_free(dc); + } else { + var_info->support_size = INFINITY; + var_info->var = NIL(bdd_t); + } + array_free(var_array); +} + +/* + *---------------------------------------------------------------------- + * + * RemoveRedundantLatches -- INTERNAL ROUTINE + * + * Since 'network' is updated possibly several times, to avoid + * dangling pointers from 'seq_info', 'seq_info' is constructed + * from a copy of 'network'. + * + * 'input_names' is an array_t * of char*; one per PI of 'network'. + * The index in 'input_names' correspond to the BDD varid of the PI. + * If the product method is used, some entries of 'input_names' are set to NIL. + * Those entries correspond to the extra PI corresponding to the next state POs. + * + * 'from_var_to_pi' is a st_table mapping bdd_t * vars (corresponding to PIs of 'network') + * onto the corresponding PIs in 'network'. + * + * Results: + * None. + * + * Side effects: + * 'network' is modified. The latches in 'removed_vars' are replaced + * by logically equivalent combinational logic. + * + *---------------------------------------------------------------------- + */ + +static void RemoveRedundantLatches(network, seq_info, removed_vars, options) +network_t *network; +seq_info_t *seq_info; +array_t *removed_vars; +prl_options_t *options; +{ + int i; + node_t *pi; + var_info_t var_info; + array_t *input_names; + st_table *from_var_to_pi; + + input_names = (*options->extract_network_input_names)(seq_info, options); + from_var_to_pi = compute_from_var_to_pi_table(network, seq_info, input_names); + + for (i = 0; i < array_n(removed_vars); i++) { + var_info = array_fetch(var_info_t, removed_vars, i); + var_info.output_distance = get_output_distance(from_var_to_pi, var_info.var); + if (var_info.output_distance + 1 > options->remlatch.max_level) { + assert(st_lookup(from_var_to_pi, (char *) var_info.var, (char **) &pi)); + if (options->verbose > 0) { + (void) fprintf(siserr, "latch [%s,%d] too far: kept\n", + io_name(pi, 0), + var_info.output_distance); + } + continue; + } + RemoveOneLatch(network, input_names, from_var_to_pi, &var_info); + } + st_free_table(from_var_to_pi); + array_free(input_names); +} + +/* + *---------------------------------------------------------------------- + * + * compute_from_var_to_pi_table -- INTERNAL ROUTINE + * + * Maps var's under the form of bdd_t *'s to PI's in 'network'. + * + * NOTE: 'seq_info->network' != 'network' but the former is a copy of the latter. + * + *---------------------------------------------------------------------- + */ + +static st_table *compute_from_var_to_pi_table(network, seq_info, input_names) +network_t *network; +seq_info_t *seq_info; +array_t *input_names; +{ + int i, var_id; + bdd_t *var; + node_t *pi; + char *input_name; + st_table *var_to_pi_table; + + var_to_pi_table = st_init_table(st_numcmp, st_numhash); + for (i = 0; i < array_n(seq_info->present_state_vars); i++) { + var = array_fetch(bdd_t *, seq_info->present_state_vars, i); + var_id = (int) bdd_top_var_id(var); + input_name = array_fetch(char *, input_names, var_id); + if (input_name == NIL(char)) continue; + assert((pi = network_find_node(network, input_name)) != NIL(node_t)); + st_insert(var_to_pi_table, (char *) var, (char *) pi); + } + return var_to_pi_table; +} + + +/* + *---------------------------------------------------------------------- + * + * RemoveOneLatch -- INTERNAL ROUTINE + * + * Replaces one latch by a piece of combinational logic. + * + * Results: + * None. + * + * Side effects: + * 'network' is modified. The latch described in 'var_info' is replaced + * by logically equivalent combinational logic. + * + *---------------------------------------------------------------------- + */ + +static void RemoveOneLatch(network, input_names, from_var_to_pi, var_info) +network_t *network; +array_t *input_names; +st_table *from_var_to_pi; +var_info_t *var_info; +{ + node_t *output, *recoding_output, *pi; + network_t *recoding_network; + network_t *dc_recoding_network; + latch_t *latch; + + /* get latch corresponding to var */ + assert(st_lookup(from_var_to_pi, (char *) var_info->var, (char **) &pi)); + assert((latch = latch_from_node(pi)) != NIL(latch_t)); + + /* build a network with a single output for the recoding function */ + recoding_network = ntbdd_bdd_single_to_network(var_info->recoding_fn, "dummy_name!", input_names); + dc_recoding_network = ntbdd_bdd_single_to_network(var_info->recoding_fn_dc, "dummy_name!", input_names); + recoding_network->dc_network = dc_recoding_network; + com_execute(&recoding_network, "collapse; full_simplify"); + remove_unused_pis(recoding_network); + + /* copy the single output function in 'network' */ + assert(network_num_po(recoding_network) == 1); + recoding_output = network_get_po(recoding_network, 0); + recoding_output = node_get_fanin(recoding_output, 0); + Prl_SetupCopyFields(network, recoding_network); + output = Prl_CopySubnetwork(network, recoding_output); + network_free(recoding_network); + + /* remove the latch and move its fanouts to node 'output' */ + replace_latch_by_node(network, latch, output); +} + +static void remove_unused_pis(network) +network_t *network; +{ + int i; + lsGen gen; + int n_nodes; + node_t *node; + node_t **nodes; + + n_nodes = 0; + nodes = ALLOC(node_t *, network_num_pi(network)); + foreach_primary_input(network, gen, node) { + if (node_num_fanout(node) == 0) { + nodes[n_nodes++] = node; + } + } + for (i = 0; i < n_nodes; i++) { + network_delete_node(network, nodes[i]); + } + FREE(nodes); +} + +static void replace_latch_by_node(network, latch, node) +network_t *network; +latch_t *latch; +node_t *node; +{ + lsGen gen; + node_t *pi, *po, *fanin; + + pi = latch_get_output(latch); + po = latch_get_input(latch); + network_delete_latch(network, latch); + fanin = node_get_fanin(po, 0); + assert(node_patch_fanin(po, fanin, node)); + node_scc(po); + network_connect(po, pi); +} + +/* + * given a function 'fn' and its don't care set 'dc' + * computes a function in the interval (fn, dc) + * with small support. Heuristic. + */ + +static void get_good_support_fn(extra_vars, fn, dc, support_size, new_fn, new_dc) +extra_vars_t *extra_vars; +bdd_t *fn; +bdd_t *dc; +int *support_size; +bdd_t **new_fn; +bdd_t **new_dc; +{ + int i; + bdd_t *var; + bdd_t *derived_fn; + bdd_t *g, *h; + bdd_t *bigger_g, *smaller_h; + array_t *var_array; + var_set_t *support; + + g = bdd_and(fn, dc, 1, 0); + h = bdd_or(fn, dc, 1, 1); + var_array = array_alloc(bdd_t *, 1); + for (i = 0; i < array_n(extra_vars->old_vars); i++) { + var = array_fetch(bdd_t *, extra_vars->old_vars, i); + array_insert(bdd_t *, var_array, 0, var); + bigger_g = bdd_smooth(g, var_array); + smaller_h = bdd_consensus(h, var_array); + if (bdd_leq(bigger_g, smaller_h, 1, 1)) { + bdd_free(g); + g = bigger_g; + bdd_free(h); + h = smaller_h; + } else { + bdd_free(bigger_g); + bdd_free(smaller_h); + } + } + array_free(var_array); + *new_fn = g; + *new_dc = bdd_xor(g, h); + bdd_free(h); + support = bdd_get_support(*new_fn); + *support_size = var_set_n_elts(support); + var_set_free(support); +} + +/* + * Allocates an 'extra_var_t' structure. + */ + +static extra_vars_t *extra_vars_alloc(seq_info) +seq_info_t *seq_info; +{ + int i; + extra_vars_t *result; + bdd_t *new_var, *support_var; + + result = ALLOC(extra_vars_t, 1); + result->manager = seq_info->manager; + result->old_vars = seq_info->present_state_vars; + result->new_vars = array_alloc(bdd_t *, 0); + result->support_vars = array_alloc(bdd_t *, 0); + result->new_to_support_map = st_init_table(st_numcmp, st_numhash); + for (i = 0; i < array_n(result->old_vars); i++) { + support_var = bdd_create_variable(seq_info->manager); + array_insert_last(bdd_t *, result->support_vars, support_var); + new_var = bdd_create_variable(seq_info->manager); + array_insert_last(bdd_t *, result->new_vars, new_var); + st_insert(result->new_to_support_map, + (char *) bdd_top_var_id(new_var), + (char *) bdd_top_var_id(support_var)); + } + return result; +} + +static void extra_vars_free(extra_vars) +extra_vars_t *extra_vars; +{ + Prl_FreeBddArray(extra_vars->new_vars); + Prl_FreeBddArray(extra_vars->support_vars); + st_free_table(extra_vars->new_to_support_map); + FREE(extra_vars); +} + + +/* + * To compute output distances. + */ + +static int get_output_distance(from_var_to_pi, var) +st_table *from_var_to_pi; +bdd_t *var; +{ + node_t *pi; + int distance; + st_table *output_distances = st_init_table(st_numcmp, st_numhash); + + assert(st_lookup(from_var_to_pi, (char *) var, (char **) &pi)); + distance = get_output_distance_rec(output_distances, pi); + st_free_table(output_distances); + return distance; +} + +static int get_output_distance_rec(table, node) +st_table *table; +node_t *node; +{ + node_t *pi; + lsGen gen; + node_t *fanout; + latch_t *latch; + int distance, fanout_distance; + + if (st_lookup(table, (char *) node, NIL(char *))) return; + distance = 0; + foreach_fanout(node, gen, fanout) { + fanout_distance = get_output_distance_rec(table, fanout); + distance = MAX(distance, fanout_distance); + } + if (node->type != PRIMARY_INPUT) distance++; + st_insert(table, (char *) node, (char *) distance); + return distance; +} + + /* + * Checks for gates that are fed only by latches + * and move the latches forward. + * Be careful to compute the initial state properly. + */ + +static void PerformLocalRetiming(network, verbosity) +network_t *network; +int verbosity; +{ + int done; + int i; + node_t *node; + array_t *nodes; + + network_sweep(network); + do { + done = 1; + nodes = network_dfs(network); + for (i = 0; i < array_n(nodes); i++) { + node = array_fetch(node_t *, nodes, i); + if (save_enough_latches(network, node)) { + move_latches_forward(network, node, verbosity); + network_sweep(network); + done = 0; + break; + } + } + array_free(nodes); + } while (done == 0); +} + +/* + * we need to add a latch at the output + */ + +static int save_enough_latches(network, node) +network_t *network; +node_t *node; +{ + int i; + int n_latches_saved; + node_t *fanin; + + if (node->type == PRIMARY_INPUT) return 0; + if (node->type == PRIMARY_OUTPUT) return 0; + n_latches_saved = -1; + foreach_fanin(node, i, fanin) { + if (fanin->type != PRIMARY_INPUT) return 0; + if (network_is_real_pi(network, fanin)) return 0; + if (node_num_fanout(fanin) == 1) n_latches_saved++; + } + return (n_latches_saved < 0) ? 0 : n_latches_saved; +} + +/* + * "node" has only latches at its inputs + * these latches are moved forward + */ + +static void move_latches_forward(network, node, verbosity) +network_t *network; +node_t *node; +int verbosity; +{ + int i; + node_t *po, *pi; + lsGen gen; + node_t *fanout; + node_t *buffer; + node_t *fanin, *input; + int init_value; + latch_t *latch; + st_table *latches; + + if (verbosity > 0) { + (void) fprintf(sisout, "latches moved forward node %s\n", node->name); + } + + + /* + * First add the new latch at the output of 'node' + */ + + foreach_fanin(node, i, fanin) { + assert((latch = latch_from_node(fanin)) != NIL(latch_t)); + SET_VALUE(fanin, latch_get_initial_value(latch)); + if (verbosity > 1) { + (void) fprintf(sisout, "fanin %s\n", fanin->name); + } + } + simulate_node(node); + init_value = GET_VALUE(node); + buffer = node_literal(node, 1); + network_add_node(network, buffer); + foreach_fanout(node, gen, fanout) { + if (fanout == buffer) continue; + assert(node_patch_fanin(fanout, node, buffer)); + node_scc(fanout); + } + network_disconnect(node, buffer, &po, &pi); + network_create_latch(network, &latch, po, pi); + latch_set_initial_value(latch, init_value); + latch_set_current_value(latch, init_value); + + /* + * Then remove the latches at the input of 'node' + */ + + latches = st_init_table(st_ptrcmp, st_ptrhash); + foreach_fanin(node, i, fanin) { + assert((latch = latch_from_node(fanin)) != NIL(latch_t)); + st_insert(latches, (char *) latch, NIL(char)); + } + red_latch_remove_latches(network, node, latches); + st_free_table(latches); +} + +/* + * "table" contains a list of latches to be removed + * presumably the latches at the inputs of node "node". + * replace, in the fanin of "node", the output of each latch + * by the input of that latch. If the latch has no more outputs, + * it is removed. + */ + +static void red_latch_remove_latches(network, node, table) +network_t *network; +node_t *node; +st_table *table; +{ + st_generator *gen; + latch_t *latch; + node_t *input, *output, *fanin; + + st_foreach_item(table, gen, (char **) &latch, NIL(char *)) { + input = latch_get_input(latch); + output = latch_get_output(latch); + if (node_num_fanout(output) == 1) { + assert(node_get_fanout(output, 0) == node); + network_delete_latch(network, latch); + network_connect(input, output); + } else { + fanin = node_get_fanin(input, 0); + assert(node_patch_fanin(node, output, fanin)); + node_scc(node); + } + } +} + + + /* EXTERNAL INTERACE */ + +/* + *---------------------------------------------------------------------- + * Prl_LatchOutput -- INTERNAL INTERFACE + * + * Forces the listed external POs to be fed by a latch + * by forward retiming of latches in the transitive fanin of the PO. + * If one of the POs depends combinationally on one of the external PIs + * the routine reports an error status code. + * This function is useful out there in the real world; i.e. + * if we want to control a memory chip, 'latch_output' is a simple way to make sure + * that the write_enable signal does not glitch. + * + * Results: + * Returns 0 iff the listed POs are all fed by a latch or a constant. + * + * Side effects: + * 'network' is modified in place. + * + *---------------------------------------------------------------------- + */ + +static int force_latched_output ARGS((network_t *, node_t *, int)); + +int Prl_LatchOutput(network, node_vec, verbosity) +network_t *network; +array_t *node_vec; +int verbosity; +{ + int i; + int status; + node_t *node; + + for (i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (! network_is_real_po(network, node)) { + (void) fprintf(siserr, "cannot apply latch_output to node %s\n", node->name); + return 1; + } + status = force_latched_output(network, node, verbosity); + if (status == 1) { + (void) fprintf(siserr, "Combinational logic dependency detected for node \"%s\":", node->name); + (void) fprintf(siserr, "latches cannot be moved forward\n"); + return 1; + } else if (status == 2) { + (void) fprintf(siserr, "Warning: node \"%s\" is fed by a constant\n", node->name); + } + } + return 0; +} + + +/* + *---------------------------------------------------------------------- + * + * force_latched_output -- INTERNAL ROUTINE + * + * Moves latches forward until a primary output is reached. + * Looks through the transitive fanin of the PO until it finds + * a node only fed by latches. Across such a node, called 'candidate' here, + * we push latches. This process continues until the fanin of the PO is + * a latch or until we do not find any more candidates. + * + * WARNING: if the PO is fed by a constant node, the algorithm outlined + * above enters an infinite loop ('candidate' will always be equal to 'fanin') + * To avoid problems with constant nodes, we perform a 'network_sweep' + * before entering the loop, and add a special test. + * + * Results: + * 0 if PO is set to be the output of a latch. + * 1 if PO depends combinationally on some external PIs. + * 2 if PO is fed by a constant. + * + * Side effects: + * 'network' is modified in place. Some latches may be moved forward + * across logic. + * + *---------------------------------------------------------------------- + */ + +static node_t *get_candidate_node ARGS((node_t *)); + +static int force_latched_output(network, po, verbosity) +network_t *network; +node_t *po; +int verbosity; +{ + node_t *fanin, *candidate; + + network_sweep(network); + for (;;) { + fanin = node_get_fanin(po, 0); + if (fanin->type == PRIMARY_INPUT && latch_from_node(fanin) != NIL(latch_t)) return 0; + if (node_num_fanin(fanin) == 0) return 2; + candidate = get_candidate_node(fanin); + if (candidate == NIL(node_t)) return 1; + move_latches_forward(network, candidate, verbosity); + network_sweep(network); + } +} + +/* + * returns a node in the transitive fanin of "node" whose fanins are all latches. + * returns NIL(node_t) if it cannot find any. + */ + +static node_t *get_candidate_node_rec ARGS((node_t *, st_table *)); + +static node_t *get_candidate_node(node) +node_t *node; +{ + node_t *candidate; + st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); + + candidate = get_candidate_node_rec(node, visited); + st_free_table(visited); + return candidate; +} + +static int node_only_fed_by_latches ARGS((node_t *)); + +static node_t *get_candidate_node_rec(node, visited) +node_t *node; +st_table *visited; +{ + int i; + node_t *fanin; + node_t *candidate; + + if (st_lookup(visited, (char *) node, NIL(char *))) return NIL(node_t); + if (node_only_fed_by_latches(node)) return node; + foreach_fanin(node, i, fanin) { + if ((candidate = get_candidate_node_rec(fanin, visited)) != NIL(node_t)) return candidate; + } + st_insert(visited, (char *) node, NIL(char)); + return NIL(node_t); +} + +static int node_only_fed_by_latches(node) +node_t *node; +{ + int i; + node_t *fanin; + network_t *network; + + if (node->type == PRIMARY_INPUT) return 0; + if (node->type == PRIMARY_OUTPUT) return 0; + foreach_fanin(node, i, fanin) { + if (fanin->type != PRIMARY_INPUT) return 0; + if (latch_from_node(fanin) == NIL(latch_t)) return 0; + } + return 1; +} + +/* + * For debugging + */ + +static void prl_print_bdd(fn, var_names) +bdd_t *fn; +array_t *var_names; +{ + network_t *network; + + network = ntbdd_bdd_single_to_network(fn, "foo", var_names); + com_execute(&network, "collapse; simplify; print"); + network_free(network); +} + + + +static int CanFlipInitialBit ARGS((network_t *, seq_info_t *, latch_t *)); + +/* + *---------------------------------------------------------------------- + * + * RemoveOneBootLatch -- INTERNAL ROUTINE + * + * a 'boot_latch' is a latch fed by a constant different from its initial value. + * This routine looks for a boot latch such that there is a state + * equivalent to the initial state for which the initial value of the latch + * becomes equal to the constant that feeds it. + * We remove only one latch at a time to avoid the additional complexity + * of updating 'seq_info' records and other related data structures. + * + * Results: + * None. + * + * Side effects: + * If possible, the initial state is changed to an equivalent state + * and one boot latch is removed. + * + *---------------------------------------------------------------------- + */ + +static void RemoveOneBootLatch(network, options) +network_t *network; +prl_options_t *options; +{ + lsGen gen; + latch_t *latch; + node_t *po, *fanin; + node_t *constant_node; + int input_value; + seq_info_t *seq_info; + + seq_info = Prl_SeqInitNetwork(network, options); + foreach_latch(network, gen, latch) { + po = latch_get_input(latch); + fanin = node_get_fanin(po, 0); + switch (node_function(fanin)) { + case NODE_0: + input_value = 0; + break; + case NODE_1: + input_value = 1; + break; + default: + continue; + } + if (input_value == latch_get_initial_value(latch)) continue; + if (! CanFlipInitialBit(network, seq_info, latch)) continue; + + /* replace the latch by a constant and exit the loop */ + constant_node = node_constant(latch_get_initial_value(latch)); + network_add_node(network, constant_node); + replace_latch_by_node(network, latch, constant_node); + break; + } + Prl_SeqInfoFree(seq_info, options); +} + + +static bdd_t *ComputeFlippedLiteral ARGS((network_t *, seq_info_t *, latch_t *)); +static bdd_t *BddFindAlternateInit ARGS((bdd_t *, bdd_t *, seq_info_t *)); +static bdd_t *BddAndPositive ARGS((bdd_t *, bdd_t *)); +static bdd_t *BinaryMergeBdds ARGS((bdd_t **, int, BddFn, bdd_t *)); +static void ForceNewInitState ARGS((network_t *, seq_info_t *, bdd_t *)); + +/* + *---------------------------------------------------------------------- + * + * CanFlipInitialBit -- INTERNAL ROUTINE + * + * Try to flip the initial bit of latch 'latch' by selecting a state + * equivalent to the initial state. + * + * Results: + * returns 1 if such an initial state with found. + * returns 0 otherwise. + * + * Side effects: + * if such an initial state is found, 'seq_info->init_state_fn' + * is modified to correspond to that new state + * and the latch initial values and current values are updated + * to correspond to the new initial state. + * + *---------------------------------------------------------------------- + */ + +static int CanFlipInitialBit(network, seq_info, latch) +network_t *network; +seq_info_t *seq_info; +latch_t *latch; +{ + int i, n_latches, n_elts; + bdd_t *fn; + bdd_t **fn_array; + bdd_t *literal; + bdd_t *result; + bdd_t *one; + bdd_t *new_init_state; + + literal = ComputeFlippedLiteral(network, seq_info, latch); + n_latches = array_n(seq_info->next_state_fns); + n_elts = n_latches + array_n(seq_info->external_output_fns); + fn_array = ALLOC(bdd_t *, n_elts); + for (i = 0; i < n_latches; i++) { + fn = array_fetch(bdd_t *, seq_info->next_state_fns, i); + fn_array[i] = BddFindAlternateInit(fn, literal, seq_info); + } + for (i = 0; i < array_n(seq_info->external_output_fns); i++) { + fn = array_fetch(bdd_t *, seq_info->external_output_fns, i); + fn_array[n_latches + i] = BddFindAlternateInit(fn, literal, seq_info); + } + bdd_free(literal); + one = bdd_one(seq_info->manager); + result = BinaryMergeBdds(fn_array, n_elts, BddAndPositive, one); + FREE(fn_array); + if (bdd_is_tautology(result, 0)) { + bdd_free(result); + return 0; + } + Prl_GetOneEdge(result, seq_info, &new_init_state, NIL(bdd_t *)); + bdd_free(seq_info->init_state_fn); + seq_info->init_state_fn = new_init_state; + ForceNewInitState(network, seq_info, new_init_state); + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * BddFindAlternateInit -- INTERNAL ROUTINE + * + * Computes all the states x such that the output 'fn'(x,i) + * is equal to 'fn'(init_state,i) for all input values i. + * + * Results: + * A bdd_t* corresponding to the set of such states. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static bdd_t *BddFindAlternateInit(fn, literal, seq_info) +bdd_t *fn; +bdd_t *literal; +seq_info_t *seq_info; +{ + bdd_t *tmp1, *tmp2; + + tmp1 = bdd_and_smooth(fn, seq_info->init_state_fn, seq_info->present_state_vars); + tmp2 = bdd_xnor(tmp1, fn); + bdd_free(tmp1); + tmp1 = bdd_consensus(tmp2, seq_info->external_input_vars); + bdd_free(tmp2); + tmp2 = bdd_and(tmp1, literal, 1, 1); + bdd_free(tmp1); + return tmp2; +} + +/* + *---------------------------------------------------------------------- + * + * ComputeFlippedLiteral -- INTERNAL ROUTINE + * + * let Xi be the input var corresponding to the output of 'latch'. Then: + * if init value of latch is 0 returns Xi + * if init value of latch is 1 returns not(Xi) + * + * Results: + * A literal, in BDD form. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static bdd_t *ComputeFlippedLiteral(network, seq_info, latch) +network_t *network; +seq_info_t *seq_info; +latch_t *latch; +{ + int i; + node_t *pi; + bdd_t *var, *literal; + + pi = latch_get_output(latch); + for (i = 0; i < array_n(seq_info->input_nodes); i++) { + if (pi == array_fetch(node_t *, seq_info->input_nodes, i)) break; + } + var = array_fetch(bdd_t *, seq_info->input_vars, i); + literal = (latch_get_initial_value(latch)) ? bdd_not(var) : bdd_dup(var); + return literal; +} + +/* + *---------------------------------------------------------------------- + * + * ForceNewInitState -- INTERNAL ROUTINE + * + * Given a new initial state expressed as a BDD, + * visit all the latches and assert the new value + * + * Results: + * None. + * + * Side effects: + * The initial state of 'network' is modified. + * + *---------------------------------------------------------------------- + */ + +static void ForceNewInitState(network, seq_info, new_init_state) +network_t *network; +seq_info_t *seq_info; +bdd_t *new_init_state; +{ + int i; + latch_t *latch; + node_t *pi, *po; + bdd_t *var; + int init_value; + int index; + st_table *pi_to_var_table; + + pi_to_var_table = Prl_GetPiToVarTable(seq_info); + for (i = 0; i < array_n(seq_info->next_state_fns); i++) { + po = array_fetch(node_t *, seq_info->output_nodes, i); + assert((latch = latch_from_node(po)) != NIL(latch_t)); + pi = latch_get_output(latch); + assert(st_lookup(pi_to_var_table, (char *) pi, (char **) &var)); + init_value = (bdd_leq(new_init_state, var, 1, 1)) ? 1 : 0; + latch_set_initial_value(latch, init_value); + latch_set_current_value(latch, init_value); + } + st_free_table(pi_to_var_table); +} + + + +/* + *---------------------------------------------------------------------- + * + * BinaryMergeBdds -- INTERNAL ROUTINE + * + * Applies 'bdd_fn', which takes two bdd_t*s as arguments and returns one, + * on all elements in 'bdd_array' and returns the result. + * 'neutral_elt' is used as start of the merging. + * + * Results: + * A bdd_t*, the result of the application of 'bdd_fn' on the array. + * + * Side effects: + * 'neutral_elt' is freed. + * + *---------------------------------------------------------------------- + */ + + +static bdd_t *BinaryMergeBdds(bdd_array, n_elts, bdd_fn, neutral_elt) +bdd_t **bdd_array; +int n_elts; +BddFn bdd_fn; +bdd_t *neutral_elt; +{ + bdd_t **arg1, **arg2, **result, **top; + bdd_t *fn; + + if (n_elts == 0) return neutral_elt; + bdd_free(neutral_elt); + for (;;) { + if (n_elts == 1) return bdd_array[0]; + arg1 = &bdd_array[0]; + arg2 = &bdd_array[1]; + result = &bdd_array[0]; + top = &bdd_array[n_elts]; + while (arg2 < top) { + fn = (*bdd_fn)(*arg1, *arg2); + bdd_free(*arg1); + bdd_free(*arg2); + *result++ = fn; + arg1 += 2; + arg2 += 2; + } + if (arg1 < top) { + *result++ = *arg1; + } + n_elts = result - bdd_array; + } +} + +/* + *---------------------------------------------------------------------- + * + * BddAndPositive -- + * + * Returns the 'and' of two BDDs. + * + *---------------------------------------------------------------------- + */ + +static bdd_t *BddAndPositive(fn1, fn2) +bdd_t *fn1; +bdd_t *fn2; +{ + return bdd_and(fn1, fn2, 1, 1); +} + +#endif /* SIS */ diff --git a/sis/seqbdd/prl_seqbdd.h b/sis/seqbdd/prl_seqbdd.h new file mode 100644 index 0000000..e080cac --- /dev/null +++ b/sis/seqbdd/prl_seqbdd.h @@ -0,0 +1,90 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prl_seqbdd.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ + +#ifndef PRL_SEQBDD_H +#define PRL_SEQBDD_H + +#include "var_set.h" + +/* referenced via a pointer only */ + +typedef struct seq_info_t seq_info_t; +typedef struct prl_options_t prl_options_t; + + /* routines that are method dependent; currently we only support product method */ + +EXTERN void Prl_ProductBddOrder ARGS((seq_info_t *, prl_options_t *)); +EXTERN void Prl_ProductInitSeqInfo ARGS((seq_info_t *, prl_options_t *)); +EXTERN void Prl_ProductFreeSeqInfo ARGS((seq_info_t *, prl_options_t *)); +EXTERN bdd_t *Prl_ProductComputeNextStates ARGS((bdd_t *, seq_info_t *, prl_options_t *)); +EXTERN bdd_t *Prl_ProductReverseImage ARGS((bdd_t *, seq_info_t *, prl_options_t *)); +EXTERN array_t *Prl_ProductExtractNetworkInputNames ARGS((seq_info_t *, prl_options_t *)); + + /* the corresponding function types */ + +typedef void (*Prl_SeqInfoFn) ARGS((seq_info_t *, prl_options_t *)); +typedef bdd_t * (*Prl_NextStateFn) ARGS((bdd_t *, seq_info_t *, prl_options_t *)); +typedef array_t * (*Prl_NameExtractFn) ARGS((seq_info_t *, prl_options_t *)); + + +struct prl_options_t { + /* global options */ + int verbose; + + /* ordering heuristic: branch & bound depth */ + int ordering_depth; + + /* timing control */ + int timeout; + long last_time; + long total_time; + + /* method dependent generic info */ + char * method_name; + range_method_t type; + Prl_SeqInfoFn bdd_order; + Prl_SeqInfoFn init_seq_info; + Prl_SeqInfoFn free_seq_info; + Prl_NextStateFn compute_next_states; + Prl_NextStateFn compute_reverse_image; + Prl_NameExtractFn extract_network_input_names; + + /* Option for env_verify_fsm */ + int stop_if_verify; + + /* Options to Prl_RemoveLatches */ + struct { + int local_retiming; /* when on, perform local retiming before removing redundant latches */ + int max_cost; /* max support size; when exceeded, latch is not removed */ + int max_level; /* max depth for substitute logic; when exceeded, latch not removed */ + int remove_boot; /* if set, tries to remove boot latches (latches fed by a constant) */ + } remlatch; +}; + +typedef struct prl_removedep_struct prl_removedep_t; + +struct prl_removedep_struct { + int perform_check; /* checks whether the dependencies are not logical */ + int verbosity; /* */ + int insert_a_one; /* if set, inserts a constant one instead of a constant zero */ +}; + +EXTERN int Prl_ExtractEnvDc ARGS((network_t *, network_t *, prl_options_t *)); +EXTERN void Prl_EquivNets ARGS((network_t *, prl_options_t *)); +EXTERN void Prl_RemoveLatches ARGS((network_t *, prl_options_t *)); +EXTERN int Prl_LatchOutput ARGS((network_t *, array_t *, int)); +EXTERN int Prl_RemoveDependencies ARGS((network_t *, array_t *, prl_removedep_t *)); +EXTERN int Prl_VerifyEnvFsm ARGS((network_t *, network_t *, network_t *, prl_options_t *)); + + + /* exported from "com_verify.c" */ +EXTERN void Prl_StoreAsSingleOutputDcNetwork ARGS((network_t *, network_t *)); + +#endif /* PRL_SEQBDD_H */ diff --git a/sis/seqbdd/prl_seqinfo.c b/sis/seqbdd/prl_seqinfo.c new file mode 100644 index 0000000..303157f --- /dev/null +++ b/sis/seqbdd/prl_seqinfo.c @@ -0,0 +1,330 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prl_seqinfo.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + +#ifdef SIS +#include "sis.h" +#include "prl_util.h" + +static void seq_compute_init_state ARGS((seq_info_t *)); +static void seq_build_dc_bdds ARGS((seq_info_t *)); +static void seq_build_output_bdds ARGS((seq_info_t *)); + +/* + *---------------------------------------------------------------------- + * + * Prl_SeqInitNetwork -- EXPORTED ROUTINE + * + * Allocates and initializes a 'seq_info' structure. + * That structure contains all the information required to perform + * traversal of a sequential circuits using BDDs. Even if there is + * no 'dc_network' attached to 'network', we allocate a 'dc_map' table. + * A 'dc_map' maps: + * 1. 'network' PO to 'dc_network' PO + * 2. 'dc_network' PI to 'network' PI + * + * Results: + * the 'seq_info' structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +seq_info_t *Prl_SeqInitNetwork(network, options) +network_t *network; +prl_options_t *options; +{ + seq_info_t *seq_info = ALLOC(seq_info_t, 1); + + seq_info->network = network; + seq_info->dc_map = attach_dcnetwork_to_network(network); + if (seq_info->dc_map == NIL(st_table)) { + seq_info->dc_map = st_init_table(st_ptrcmp, st_ptrhash); + } + + (*options->bdd_order)(seq_info, options); + + seq_build_output_bdds(seq_info); + seq_build_dc_bdds(seq_info); + seq_compute_init_state(seq_info); + + /* command specific initialization (whatever remains to be done) */ + (*options->init_seq_info)(seq_info, options); + + /* a few consistency checks */ + assert(array_n(seq_info->next_state_fns) == network_num_latch(seq_info->network)); + assert(array_n(seq_info->next_state_fns) == array_n(seq_info->present_state_vars)); + assert(array_n(seq_info->output_nodes) == network_num_po(seq_info->network)); + assert(array_n(seq_info->output_nodes) == array_n(seq_info->next_state_fns) + array_n(seq_info->external_output_fns)); + assert(array_n(seq_info->present_state_vars) == array_n(seq_info->next_state_fns)); + assert(array_n(seq_info->input_vars) == network_num_pi(seq_info->network)); + assert(array_n(seq_info->input_nodes) == array_n(seq_info->input_vars)); + + return seq_info; +} + + +/* + *---------------------------------------------------------------------- + * + * seq_build_output_bdds -- INTERNAL ROUTINE + * + *---------------------------------------------------------------------- + */ + +static void seq_build_output_bdds(seq_info) +seq_info_t *seq_info; +{ + int i; + bdd_t *fn; + node_t *output; + + seq_info->external_output_fns = array_alloc(bdd_t *, 0); + seq_info->next_state_fns = array_alloc(bdd_t *, 0); + + for (i = 0; i < array_n(seq_info->output_nodes); i++) { + output = array_fetch(node_t *, seq_info->output_nodes, i); + fn = ntbdd_node_to_bdd(output, seq_info->manager, seq_info->leaves); + if (network_is_real_po(seq_info->network, output)) { + array_insert_last(bdd_t *, seq_info->external_output_fns, fn); + } else { + array_insert_last(bdd_t *, seq_info->next_state_fns, fn); + } + } +} + + +static void seq_register_pis_as_bdd_inputs ARGS((seq_info_t *, network_t *)); + +/* + *---------------------------------------------------------------------- + * + * seq_build_dc_bdds -- INTERNAL ROUTINE + * + *---------------------------------------------------------------------- + */ + +static void seq_build_dc_bdds(seq_info) +seq_info_t *seq_info; +{ + int i; + lsGen gen; + char *output_name; + node_t *input; + node_t *dc_output, *output; + network_t *dc_network; + bdd_t *dc_fn; + + seq_info->next_state_dc = array_alloc(bdd_t *, 0); + seq_info->external_output_dc = array_alloc(bdd_t *, 0); + + dc_network = seq_info->network->dc_network; + seq_register_pis_as_bdd_inputs(seq_info, dc_network); + + for (i = 0; i < array_n(seq_info->output_nodes); i++) { + output = array_fetch(node_t *, seq_info->output_nodes, i); + /* if no don't care for that node, put a 0 BDD */ + if (st_lookup(seq_info->dc_map, (char *) output, (char **) &dc_output)) { + dc_fn = ntbdd_node_to_bdd(dc_output, seq_info->manager, seq_info->leaves); + } else { + dc_fn = bdd_zero(seq_info->manager); + } + /* store BDDs in the same order as for the main network */ + if (network_is_real_po(seq_info->network, output)) { + array_insert_last(bdd_t *, seq_info->external_output_dc, dc_fn); + } else { + array_insert_last(bdd_t *, seq_info->next_state_dc, dc_fn); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * seq_register_pis_as_bdd_inputs -- INTERNAL ROUTINE + * + * Goes through the PIs of the dc_network. + * The PIs should appear in seq_info->dc_map and be mapped + * to PIs of the original network. + * Store a mapping between the dc_network PIs and the bdd_t *vars + * so that seq_info->leaves can be used to build BDD's over the dc_networks. + * + *---------------------------------------------------------------------- + */ + +static void seq_register_pis_as_bdd_inputs(seq_info, dc_network) +seq_info_t *seq_info; +network_t *dc_network; +{ + int var_index; + lsGen gen; + node_t *dc_input; + node_t *input; + + if (dc_network == NIL(network_t)) return; + foreach_primary_input(dc_network, gen, dc_input) { + assert(st_lookup(seq_info->dc_map, (char *) dc_input, (char **) &input)); + assert(st_lookup_int(seq_info->leaves, (char *) input, &var_index)); + st_insert(seq_info->leaves, (char *) dc_input, (char *) var_index); + } +} + + +/* + *---------------------------------------------------------------------- + * + * seq_compute_initial_state -- INTERNAL ROUTINE + * + *---------------------------------------------------------------------- + */ + +static void seq_compute_init_state(seq_info) +seq_info_t *seq_info; +{ + lsGen gen; + latch_t *latch; + node_t *pi; + int var_index; + int init_value; + bdd_t *tmp, *var; + int warning_done = 0; + bdd_t *result = bdd_one(seq_info->manager); + network_t *network = seq_info->network; + + foreach_latch(network, gen, latch) { + /* + * first, compute the initial value. If 2, specifying it: -> get a cube, not a minterm + */ + init_value = latch_get_initial_value(latch); + assert(init_value >= 0 && init_value <= 3); + if (init_value == 2) continue; + if (init_value == 3) { + init_value = 0; + if (! warning_done) { + warning_done = 1; + pi = latch_get_input(latch); + (void) fprintf(siserr, "WARNING: unspecified init value of node %s set to 0\n", node_long_name(pi)); + } + } + + /* + * then compute the literal to AND with the current result + */ + pi = latch_get_output(latch); + assert(st_lookup_int(seq_info->leaves, (char *) pi, &var_index)); + var = bdd_get_variable(seq_info->manager, var_index); + + tmp = bdd_and(result, var, 1, init_value); + bdd_free(var); + bdd_free(result); + result = tmp; + } + + seq_info->init_state_fn = result; +} + + +/* + *---------------------------------------------------------------------- + * + * Prl_SeqInfoFree -- EXPORTED ROUTINE + * + * Side effects: + * Frees the 'seq_info' record. + * + *---------------------------------------------------------------------- + */ + +void Prl_SeqInfoFree(seq_info, options) +seq_info_t *seq_info; +prl_options_t *options; +{ + int i; + char *name; + + /* don't free those BDD's: stored at nodes: will be done by ntbdd_end_manager */ + array_free(seq_info->next_state_fns); + array_free(seq_info->external_output_fns); + array_free(seq_info->output_nodes); + + Prl_FreeBddArray(seq_info->present_state_vars); + Prl_FreeBddArray(seq_info->external_input_vars); + Prl_FreeBddArray(seq_info->input_vars); + array_free(seq_info->input_nodes); + for (i = 0; i < array_n(seq_info->var_names); i++) { + name = array_fetch(char *, seq_info->var_names, i); + FREE(name); + } + array_free(seq_info->var_names); + + array_free(seq_info->next_state_dc); + array_free(seq_info->external_output_dc); + + (*options->free_seq_info)(seq_info, options); + + st_free_table(seq_info->leaves); + ntbdd_end_manager(seq_info->manager); + + st_free_table(seq_info->dc_map); + + FREE(seq_info); +} + + +/* + *---------------------------------------------------------------------- + * + * Prl_ExtractReachableStates -- EXPORTED ROUTINE + * + *---------------------------------------------------------------------- + */ + +bdd_t *Prl_ExtractReachableStates(seq_info, options) +seq_info_t *seq_info; +prl_options_t *options; +{ + bdd_t *new_current_set; + bdd_t *new_total_set; + bdd_t *current_set; + bdd_t *total_set; + bdd_t *care_set; + bdd_t *new_states; + double total_onset, new_onset; + + Prl_ReportElapsedTime(options, "build BDDs"); + current_set = bdd_dup(seq_info->init_state_fn); + total_set = bdd_dup(current_set); + Prl_ReportElapsedTime(options, "begin STG traversal"); + for (;;) { + new_current_set = (*options->compute_next_states)(current_set, seq_info, options); + bdd_free(current_set); + if (options->verbose >= 1) { + total_onset = bdd_count_onset(total_set, seq_info->present_state_vars); + new_states = bdd_and(new_current_set, total_set, 1, 0); + new_onset = bdd_count_onset(new_states, seq_info->present_state_vars); + bdd_free(new_states); + (void) fprintf(sisout, "add %2.0f states to %2.0f states\n", new_onset, total_onset); + } + if (bdd_leq(new_current_set, total_set, 1, 1)) break; + care_set = bdd_not(total_set); + current_set = bdd_cofactor(new_current_set, care_set); + bdd_free(care_set); + new_total_set = bdd_or(new_current_set, total_set, 1, 1); + bdd_free(new_current_set); + bdd_free(total_set); + total_set = new_total_set; + } + bdd_free(new_current_set); + Prl_ReportElapsedTime(options, "end STG traversal"); + return total_set; +} + +#endif /* SIS */ diff --git a/sis/seqbdd/prl_util.c b/sis/seqbdd/prl_util.c new file mode 100644 index 0000000..2a7d6d7 --- /dev/null +++ b/sis/seqbdd/prl_util.c @@ -0,0 +1,649 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prl_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ + +#ifdef SIS +#include "sis.h" +#include "prl_util.h" + +/* + *---------------------------------------------------------------------- + * + * Prl_RemoveDcNetwork -- EXPORTED ROUTINE + * + * Removes the dc network associated to 'network'. + * + * Results: + * None. + * + * Side effects: + * 'network->dc_network' is nil. + * + *---------------------------------------------------------------------- + */ + +void Prl_RemoveDcNetwork(network) +network_t *network; +{ + if (network->dc_network != NIL(network_t)) { + network_free(network->dc_network); + network->dc_network = NIL(network_t); + } +} + + +/* + *---------------------------------------------------------------------- + * + * Prl_SetupCopyFields -- EXPORTED ROUTINE + * + * 1. Initializes the 'copy' field of all the nodes in 'network_from' to NIL. + * 2. Initializes the 'copy' field of the PIs in 'network_from' to point to + * a node in 'network_from; that has the same name, if there is any. + * In case that node is a PO of 'network_from', its fanin is used instead. + * In case there are no homonyms, a dummy PI in 'network_to' is created. + * + * WARNING: + * Do not change the test of 'to_input->type == PRIMARY_INPUT' + * to 'network_is_real_pi(to_network, to_input)' below. + * Otherwise 'remove_latches' will break. 'remove_latches' + * relies on the fact that 'from_network' has real PIs with + * the same name as the latch PIs of 'to_network'. It is used + * to replace a latch with an equivalent combinational logic circuit. + * + * Results: + * None. + * + * Side Effects: + * The 'copy' fields of nodes in 'from_network' are modified. + * Some PIs may have been added to 'to_network'. + * + *---------------------------------------------------------------------- + */ + + +void Prl_SetupCopyFields(to_network, from_network) +network_t *to_network; +network_t *from_network; +{ + lsGen gen; + node_t *from_node; + node_t *from_input, *to_input; + + foreach_node(from_network, gen, from_node) { + from_node->copy = NIL(node_t); + } + + /* visit the PIs of 'source' */ + foreach_primary_input(from_network, gen, from_input) { + + /* find the homonym in 'target' */ + to_input = network_find_node(to_network, from_input->name); + + /* if names are meaningful and there is a matching node, just use it */ + if (network_is_real_pi(from_network, from_input) && to_input != NIL(node_t)) { + if (network_is_real_po(to_network, to_input)) { + from_input->copy = node_get_fanin(to_input, 0); + } else if (to_input->type == PRIMARY_INPUT) { + from_input->copy = to_input; + } + } + + /* otherwise make one PI up */ + if (from_input->copy == NIL(node_t)) { + from_input->copy = node_alloc(); + from_input->copy->name = Prl_DisambiguateName(to_network, from_input->name, NIL(node_t)); + network_add_primary_input(to_network, from_input->copy); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * Prl_DisambiguateName -- EXTERNAL ROUTINE + * + * From a string 'name', generates a string + * that is not used as a node name in 'network' + * by appending some suffix. If anywhere during the search + * the node 'node' is found as a match, a copy of its name + * is returned. If 'node' is NIL, a name is generated that is + * guaranteed not to be used in 'network'. + * + * Results: + * Either a copy of the name of 'node', or a new name + * not used by any node in 'network'. + * + * Side effects; + * The result is a freshly allocated string. + * + *---------------------------------------------------------------------- + */ + +char* Prl_DisambiguateName(network, name, node) +network_t *network; +char* name; +node_t *node; +{ + char *buffer; + node_t *matching_node; + + name = util_strsav(name); + while ((matching_node = network_find_node(network, name))) { + if (matching_node == node) return name; + buffer = ALLOC(char, strlen(name) + 5); + (void) sprintf(buffer, "%s:dup", name); + FREE(name); + name = buffer; + } + return name; +} + + +/* + *---------------------------------------------------------------------- + * + * Prl_CopySubNetwork -- EXPORTED ROUTINE + * + * 'network' is the network to be augmented. + * 'node' is a node from some other network whose tfi is to be copied in 'network'. + * The 'copy' fields of the nodes in 'node'->network are used to keep track + * of what has been already copied. The 'copy' fields of the PIs of 'node'->network + * must have been initialized properly already (i.e.: 'CopySubnetwork' + * should only be called after 'Prl_SetupCopyFields'). + * + * Results: + * A logically equivalent copy of 'node' in 'network'. + * + * Side Effects: + * 'network' is modified; the transitive fanin of 'node' + * is copied over into 'network'. + * The 'copy' fields of nodes in 'node->network' are modified + * to point to their copies in 'network'. + * + *---------------------------------------------------------------------- + */ + +node_t *Prl_CopySubnetwork(network, node) +network_t *network; +node_t *node; +{ + int i; + char* name; + node_t *fanin; + + if (node->copy == NIL(node_t)) { + assert(node->type != PRIMARY_INPUT); + node->copy = node_dup(node); + foreach_fanin(node, i, fanin) { + fanin->copy = Prl_CopySubnetwork(network, fanin); + node->copy->fanin[i] = fanin->copy; + } + name = node->copy->name; + if (name != NIL(char) && network_find_node(network, name) != NIL(node_t)) { + node->copy->name = Prl_DisambiguateName(network, name, NIL(node_t)); + FREE(name); + } + network_add_node(network, node->copy); + } + return node->copy; +} + + +/* + *---------------------------------------------------------------------- + * + * Prl_StoreAsSingleOutputDcNetwork -- EXPORTED ROUTINE + * + * 'dc_network' has a single PO, expressing a global dc condition + * valid for all POs of 'network'. The PIs of 'dc_network' + * match by name the PIs of 'network'. This routine modifies + * 'dc_network' to be an acceptable dc_network of 'network', + * by inserting in 'dc_network' one PO per PO in 'network'. + * The old 'network->dc_network', if any, is discarded. + * + * WARNING: + * 'attach_dcnetwork_to_network' matches POs by node->name. + * For POs that correspond to latch inputs, that does not always work + * properly. Those internal POs may borrow their name from their inputs. + * The correct way of doing things would be: + * 1. to modify 'attach_dcnetwork_to_network' to use 'io_name' + * 2. to modify 'Prl_StoreAsSingleOutputDcNetwork' to use 'io_name' + * (be careful to guarantee unicity of PO names in the 'dc_network'). + * + * Results: + * None. + * + * Side effects: + * 'network->dc_network' is generated. + * + * Note: + * 'dc_network' will be freed when 'network' is. + * + *---------------------------------------------------------------------- + */ + +void Prl_StoreAsSingleOutputDcNetwork(network, dc_network) +network_t *network; +network_t *dc_network; +{ + lsGen gen; + node_t *node, *po, *oldpo, *fanin; + node_t *pi; + char *name; + int i; + + if (dc_network == NIL(network_t)) return; + assert(network_num_po(dc_network) == 1); + Prl_RemoveDcNetwork(network); + + oldpo = network_get_po(dc_network, 0); + fanin = node_get_fanin(oldpo, 0); + + foreach_primary_output(network, gen, po){ + node = node_literal(fanin, 1); + node->name = util_strsav(po->name); + network_add_node(dc_network, node); + (void) network_add_primary_output(dc_network, node); + } + network_delete_node(dc_network, oldpo); + network_sweep(dc_network); + name = ALLOC(char, (int) (strlen(network_name(network)) + strlen(".dc") + 1)); + (void) sprintf(name, "%s%s", network_name(network), ".dc"); + network_set_name(dc_network, name); + FREE(name); + network->dc_network = dc_network; +} + + +/* + *---------------------------------------------------------------------- + * + * Prl_FreeBddArray -- EXPORTED ROUTINE + * + * Given an 'array_t *' of 'bdd_t *', frees all the bdds in the array + * and then free the array itself. + * + * Results: + * None. + * + * Side effects: + * 'bdd_array' and all its elements are freed. + * + *---------------------------------------------------------------------- + */ + +void Prl_FreeBddArray(bdd_array) +array_t *bdd_array; +{ + int i; + bdd_t *fn; + + for (i = 0; i < array_n(bdd_array); i++) { + fn = array_fetch(bdd_t *, bdd_array, i); + bdd_free(fn); + } + array_free(bdd_array); +} + + + /* + *---------------------------------------------------------------------- + * + * Prl_CleanupDcNetwork -- + * + * Removes any PI that does not fanout anywhere. + * + * WARNING: + * Should guarantee compatibility with 'attach_dcnetwork_to_network', + * which attach 'network' PO to 'dc_network' PO based on node->name only. + * + * Results: + * None. + * + * Side effects: + * dc_network is modified in place. + * + *---------------------------------------------------------------------- + */ + +void Prl_CleanupDcNetwork(network) +network_t *network; +{ + int i; + lsGen gen; + node_t *pi; + array_t *nodes_to_be_removed; + + if (network->dc_network == NIL(network_t)) return; + nodes_to_be_removed = array_alloc(node_t *, 0); + foreach_primary_input(network->dc_network, gen, pi) { + if (node_num_fanout(pi) == 0) { + array_insert_last(node_t *, nodes_to_be_removed, pi); + } + } + for (i = 0; i < array_n(nodes_to_be_removed); i++) { + pi = array_fetch(node_t *, nodes_to_be_removed, i); + network_delete_node(network->dc_network, pi); + } + array_free(nodes_to_be_removed); + network_sweep(network->dc_network); +} + + /* + *---------------------------------------------------------------------- + * + * Prl_ReportElapsedTime -- EXTERNAL ROUTINE + * + *---------------------------------------------------------------------- + */ + +void Prl_ReportElapsedTime(options, comment) +prl_options_t *options; +char *comment; +{ + int last_time = options->last_time; + int new_time = util_cpu_time(); + double elapsed; + double total; + + if (options->verbose == 0) return; + (void) fprintf(misout, "use method %s\n", options->method_name); + options->last_time = new_time; + options->total_time += (new_time - last_time); + elapsed = (double) (new_time - last_time) / 1000; + total = (double) (options->total_time) / 1000; + (void) fprintf(misout, "*** [elapsed(%2.1f),total(%2.1f)] ***\n", elapsed, total); + if (comment != NIL(char)) (void) fprintf(misout, "%s...\n", comment); +} + + +static bdd_t *array_bdd_and ARGS((bdd_manager *, array_t *)); + +/* + *---------------------------------------------------------------------- + * + * Prl_GetSimpleDc -- EXTERNAL ROUTINE + * + * Results: + * Returns the bdd_and of all the don't care bdds. + * + *---------------------------------------------------------------------- + */ + +bdd_t *Prl_GetSimpleDc(seq_info) +seq_info_t *seq_info; +{ + bdd_t *tmp1 = array_bdd_and(seq_info->manager, seq_info->next_state_dc); + bdd_t *tmp2 = array_bdd_and(seq_info->manager, seq_info->external_output_dc); + bdd_t *result = bdd_and(tmp1, tmp2, 1, 1); + bdd_free(tmp1); + bdd_free(tmp2); + return result; +} + + +/* + *---------------------------------------------------------------------- + * + * array_bdd_and -- INTERNAL ROUTINE + * + * Results: + * Returns the bdd_and of an array of BDDs. + * + *---------------------------------------------------------------------- + */ + +static bdd_t *array_bdd_and(manager, array) +bdd_manager* manager; +array_t *array; +{ + int i; + bdd_t *tmp; + bdd_t *result = bdd_one(manager); + + for (i = 0; i < array_n(array); i++) { + tmp = bdd_and(result, array_fetch(bdd_t *, array, i), 1, 1); + bdd_free(result); + result = tmp; + } + return result; +} + + + +static bdd_t *GetOneMinterm ARGS((bdd_manager *, bdd_t *, st_table *)); +static void StoreVarIdsInTable ARGS((array_t *, st_table *)); + +/* + *---------------------------------------------------------------------- + * + * Prl_GetOneEdge -- EXTERNAL ROUTINE + * + * Get one edge contained in the transition condition 'from'. + * An edge is given as a 'state' and an 'input' bdd_t*. + * Both are returned as a minterm wrt their own variable set. + * In case a cube would work, the zero branch is arbitrarily selected. + * + * Results: + * 'state' and 'input' are modified to point towards a valid edge. + * + * Side effects: + * Assertion failure if 'from' is equal to 0. + * + *---------------------------------------------------------------------- + */ + + +void Prl_GetOneEdge(from, seq_info, state, input) +bdd_t *from; +seq_info_t *seq_info; +bdd_t **state; +bdd_t **input; +{ + bdd_t *minterm; + st_table *var_table; + + assert(! bdd_is_tautology(from, 0)); + + /* precompute the vars to be used */ + var_table = st_init_table(st_numcmp, st_numhash); + StoreVarIdsInTable(seq_info->present_state_vars, var_table); + StoreVarIdsInTable(seq_info->external_input_vars, var_table); + minterm = GetOneMinterm(seq_info->manager, from, var_table); + st_free_table(var_table); + + if (state != NIL(bdd_t *)) *state = bdd_smooth(minterm, seq_info->external_input_vars); + if (input != NIL(bdd_t *)) *input = bdd_smooth(minterm, seq_info->present_state_vars); +} + + +/* + *---------------------------------------------------------------------- + * + * GetOneMinterm -- INTERNAL ROUTINE + * + * Returns a minterm from 'fn'. + * 'fn' should only depend on variables contain in 'vars'. + * 'vars' is a table of variable_id (small ints), not of bdd_t*'s. + * WARNING: Relies on the fact that the ith bdd_literal in cube + * corresponds to the variable of variable_id == i. + * + * Results: + * a bdd_t*, a minterm from 'fn' wrt to 'vars'. + * + * Side effects: + * Assertion failure if 'fn' is equal to 0. + * + *---------------------------------------------------------------------- + */ + +static bdd_t *GetOneMinterm(manager, fn, vars) +bdd_manager *manager; +bdd_t *fn; +st_table *vars; +{ + int i; + bdd_t *tmp; + bdd_t *bdd_lit; + bdd_t *minterm; + bdd_gen *gen; + int n_lits; + bdd_literal *lits; + array_t *cube; + + assert(! bdd_is_tautology(fn, 0)); + + /* + * WARNING: need to free the bdd_gen immediately + * otherwise problems with the BDD garbage collector. + */ + + minterm = bdd_one(manager); + gen = bdd_first_cube(fn, &cube); + n_lits = array_n(cube); + lits = ALLOC(bdd_literal, n_lits); + for (i = 0; i < n_lits; i++) { + lits[i] = array_fetch(bdd_literal, cube, i); + } + (void) bdd_gen_free(gen); + + for (i = 0; i < n_lits; i++) { + if (! st_lookup(vars, (char *) i, NIL(char *))) { + assert(lits[i] == 2); + continue; + } + switch (lits[i]) { + case 0: + case 2: + tmp = bdd_get_variable(manager, i); + bdd_lit = bdd_not(tmp); + bdd_free(tmp); + break; + case 1: + bdd_lit = bdd_get_variable(manager, i); + break; + default: + fail("unexpected literal in GetOneMinterm"); + break; + } + tmp = bdd_and(minterm, bdd_lit, 1, 1); + bdd_free(minterm); + bdd_free(bdd_lit); + minterm = tmp; + } + return minterm; +} + + +/* + *---------------------------------------------------------------------- + * + * AddVaridsToTable -- INTERNAL ROUTINE + * + * Given 'vars', an array of bdd_t*'s representing variables + * extract from each its variable identifier and store it + * in the hash table 'table' as key. The associated values + * are always 0, i.e. 'table' is used as a set. + * + * Results: + * None. + * + * Side effects: + * 'table' is augmented with the varids of the variables in 'vars'. + * + *---------------------------------------------------------------------- + */ + + +static void AddVaridsToTable(vars, table) +array_t *vars; +st_table *table; +{ + int i; + bdd_t *var; + int varid; + + for (i = 0; i < array_n(vars); i++) { + var = array_fetch(bdd_t *, vars, i); + varid = bdd_top_var_id(var); + st_insert(table, (char *) varid, NIL(char)); + } +} + + + /* + *---------------------------------------------------------------------- + * + * Prl_GetPiToVarTable -- EXTERNAL ROUTINE + * + * a simple utility: computes a map between PIs and bdd_t *vars + * corresponding to the PIs. + * + * Results: + * a hash table mapping node_t*'s to bdd_t*'s. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +st_table *Prl_GetPiToVarTable(seq_info) +seq_info_t *seq_info; +{ + int i; + node_t *pi; + bdd_t *var; + st_table *pi_to_var_table; + + pi_to_var_table = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 0; i < array_n(seq_info->input_nodes); i++) { + pi = array_fetch(node_t *, seq_info->input_nodes, i); + var = array_fetch(bdd_t *, seq_info->input_vars, i); + st_insert(pi_to_var_table, (char *) pi, (char *) var); + } + return pi_to_var_table; +} + + + /* + *---------------------------------------------------------------------- + * + * StoreVarIdsInTable -- INTERNAL ROUTINE + * + * a simple utility: extract the varids from the bdd_t*s + * stored in array 'vars' and store them in 'table'. + * 'table' is used as a set. + * + * Results: + * None. + * + * Side effects: + * 'table' is augmented with the top varid of the bdds in 'vars'. + * + *---------------------------------------------------------------------- + */ + +static void StoreVarIdsInTable(vars, table) +array_t *vars; +st_table *table; +{ + int i; + bdd_t *var; + int varid; + + for (i = 0; i < array_n(vars); i++) { + var = array_fetch(bdd_t *, vars, i); + varid = bdd_top_var_id(var); + st_insert(table, (char *) varid, NIL(char)); + } +} + +#endif /* SIS */ diff --git a/sis/seqbdd/prl_util.h b/sis/seqbdd/prl_util.h new file mode 100644 index 0000000..7def31b --- /dev/null +++ b/sis/seqbdd/prl_util.h @@ -0,0 +1,123 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/prl_util.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:55 $ + * + */ + +#ifndef PRL_INT_H +#define PRL_INT_H + +#include "prl_seqbdd.h" + +/* + * "typedef struct seq_info_t seq_info_t;" is already in "seqbdd.h" + */ + +struct seq_info_t { + /* + * OUTPUTS + */ + array_t *next_state_fns; /* of bdd_t *'s */ + array_t *external_output_fns; /* of bdd_t *'s */ + array_t *output_nodes; /* of node_t *'s: the corresponding PO in order: NS first */ + + /* + * INPUTS + */ + array_t *present_state_vars; /* of bdd_t *'s; only present state PI's */ + array_t *external_input_vars; /* of bdd_t *'s; only the external PI's */ + array_t *input_vars; /* all input variables in BDD order */ + array_t *input_nodes; /* of node_t *'s: 1-1 correspondance with input_vars */ + + bdd_t *init_state_fn; /* the initial state (may be a set) */ + + st_table *dc_map; /* the map between PI's and PO's of network and + * network->dc.network (both ways) + */ + + /* + * The BDD's for the DC network: + * 1-1 correspondance with previous BDD's + */ + array_t *next_state_dc; /* of bdd_t *'s */ + array_t *external_output_dc; /* of bdd_t *'s */ + + /* + * BDD Manager and related information + */ + bdd_manager *manager; + st_table *leaves; /* specify the BDD variable ordering: map PI's to indices */ + array_t *var_names; /* of char *'s: input_names[i] is name of BDD var of id=i */ + /* size of this array is input_vars+transition_vars */ + + /* + * Other info of global interest + */ + network_t *network; + + /* + * Method specific info + */ + struct { + array_t *transition_vars; /* of bdd_t *'s; next_state_vars, + * same order as next_state_fns + */ + array_t *next_state_vars; /* of bdd_t *'s; next_state_vars, + * same order as present_state_vars + */ + struct { + array_t *transition_fns; /* array of bdd_t *'s; y_j==f_j(x,i) */ + } product; + } transition; +}; + +/* + * Procedures used to manipulate 'seq_info_t' records + */ + +EXTERN seq_info_t *Prl_SeqInitNetwork ARGS((network_t *, prl_options_t *)); +EXTERN bdd_t *Prl_ExtractReachableStates ARGS((seq_info_t *, prl_options_t *)); +EXTERN void Prl_SeqInfoFree ARGS((seq_info_t *, prl_options_t *)); + +/* utilities for dc_networks */ + +EXTERN void Prl_RemoveDcNetwork ARGS((network_t *)); +EXTERN void Prl_CleanupDcNetwork ARGS((network_t *)); +EXTERN bdd_t * Prl_GetSimpleDc ARGS((seq_info_t *)); + + + /* utilities for networks */ + +EXTERN void Prl_StoreAsSingleOutputDcNetwork ARGS((network_t *, network_t *)); +EXTERN void Prl_CleanupDcNetwork ARGS((network_t *)); +EXTERN void Prl_SetupCopyFields ARGS((network_t *, network_t *)); +EXTERN node_t *Prl_CopySubnetwork ARGS((network_t *, node_t *)); +EXTERN char *Prl_DisambiguateName ARGS((network_t *, char *, node_t *)); +EXTERN void Prl_CleanupDcNetwork ARGS((network_t *)); + + + /* BDD utilities */ + +EXTERN void Prl_FreeBddArray ARGS((array_t *)); +EXTERN array_t *Prl_OrderSetHeuristic ARGS((set_info_t *, int, int)); +EXTERN void Prl_GetOneEdge ARGS((bdd_t *, seq_info_t *, bdd_t **, bdd_t **)); +EXTERN st_table *Prl_GetPiToVarTable ARGS((seq_info_t *)); + + + /* Misc. utilities */ + +EXTERN void Prl_ReportElapsedTime ARGS((prl_options_t *, char *)); + + + /* utilities from other directories */ + +#define SIM_SLOT simulation +#define GET_VALUE(node) ((int) node->SIM_SLOT) +#define SET_VALUE(node, value) (node->SIM_SLOT = (char *) value) +EXTERN array_t *simulate_network ARGS((network_t *, array_t *, array_t *)); + +#endif /* PRL_INT_H */ diff --git a/sis/seqbdd/product.c b/sis/seqbdd/product.c new file mode 100644 index 0000000..f7ec606 --- /dev/null +++ b/sis/seqbdd/product.c @@ -0,0 +1,667 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/product.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ + /* file %M% release %I% */ + /* last modified: %G% at %U% */ +#ifdef SIS +#include "sis.h" +#include "prioqueue.h" + + + /* types used in PRODUCT for smoothing as soon as possible */ + +typedef struct { + int varid; + bdd_t *var; /* result of bdd_get_variable(mgr, varid) */ + st_table *fn_table; /* list of indices of fns depending on that variable in fns[] */ + int last_index; /* the most recent fn index depending on this var */ +} var_info_t; + +typedef struct { + int fnid; /* small integer; unique identifier for the function */ + bdd_t *fn; /* accumulation of AND's of functions */ + int cost; /* simply an index for static merging; */ + /* size of bdd for dynamic merging */ + var_set_t *support; /* support of that function */ + int partition; /* to which partition the fn belongs */ +} fn_info_t; + + + /* should avoid smoothing out next_state_vars ... */ + +typedef struct { + int n_fns; + fn_info_t **fns; + int n_vars; + var_info_t **vars; + queue_t *queue; /* priority queue where to store the functions by size */ + bdd_manager *manager; + int n_partitions; + int *partition_count; /* number of fns alive in each partition */ + int *next_partition; /* map to tell in which partition to go when current one is empty */ +} support_info_t; + + + /* result < 0 means obj1 higher priority than obj2 (obj1 comes first) */ +static int fn_info_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + int diff; + fn_info_t *info1 = (fn_info_t *) obj1; + fn_info_t *info2 = (fn_info_t *) obj2; + diff = info1->partition - info2->partition; + if (diff == 0) diff = info1->cost - info2->cost; + return diff; +} + +static void fn_info_print(obj) +char *obj; +{ + fn_info_t *info = (fn_info_t *) obj; + (void) fprintf(misout, "fn %d", info->fnid); +} + +static array_t *smooth_vars_extract(); +static bdd_t *do_fn_merging(); +static int fn_info_cmp(); +static st_table *get_varids_in_table(); +static support_info_t *support_info_extract(); +static void *var_info_free(); +static void extract_fn_info(); +static void extract_var_info(); +static void fn_info_free(); +static void fn_info_print(); +static void initialize_partition_info(); +static void smooth_lonely_variables(); +static void support_info_free(); + + + + /* EXTERNAL INTERFACE */ + + /* keep everything separate: transition relation and the output fn in case of verif */ + + /* ARGSUSED */ +range_data_t *product_alloc_range_data(network, options) +network_t *network; +verif_options_t *options; +{ + int i; + node_t *node; + bdd_t *output; + st_table *input_to_output_table; + output_info_t *info = options->output_info; + range_data_t *data = ALLOC(range_data_t, 1); + + data->type = PRODUCT_METHOD; + + /* create a BDD manager */ + if (options->verbose >= 3) print_node_table(info->pi_ordering); + data->manager = ntbdd_start_manager(st_count(info->pi_ordering)); + + /* create BDD for external output_fn and init_state_fn */ + data->init_state_fn = ntbdd_node_to_bdd(info->init_node, data->manager, info->pi_ordering); + data->external_outputs = array_alloc(bdd_t *, 0); + if (options->does_verification) { + for (i = 0; i < array_n(info->xnor_nodes); i++) { + node = array_fetch(node_t *, info->xnor_nodes, i); + output = ntbdd_node_to_bdd(node, data->manager, info->pi_ordering); + array_insert_last(bdd_t *, data->external_outputs, output); + } + } + + /* consistency fn and the like */ + data->consistency_fn = 0; + data->transition_outputs = array_alloc(bdd_t *, 0); + for (i = 0; i < array_n(info->transition_nodes); i++) { + node = array_fetch(node_t *, info->transition_nodes, i); + output = ntbdd_node_to_bdd(node, data->manager, info->pi_ordering); + array_insert_last(bdd_t *, data->transition_outputs, output); + } + data->smoothing_inputs = bdd_extract_var_array(data->manager, info->org_pi, info->pi_ordering); + + /* create and save two arrays of bdd variables in order: yi's and their corresponding xi's */ + input_to_output_table = extract_input_to_output_table(info->org_pi, info->new_pi, info->po_ordering, network); + data->input_vars = extract_state_input_vars(data->manager, info->pi_ordering, input_to_output_table); + data->output_vars = extract_state_output_vars(data->manager, info->pi_ordering, input_to_output_table); + + /* only present state variables: used for counting the onset of reached set */ + data->pi_inputs = data->input_vars; + + /* free space allocated here */ + st_free_table(input_to_output_table); + + return data; +} + +void product_free_range_data(data, options) +range_data_t *data; +verif_options_t *options; +{ + int i; + node_t *node; + output_info_t *info = options->output_info; + + /* do not free data->pi_inputs (== data->input_vars) */ + array_free(data->input_vars); + array_free(data->output_vars); + array_free(data->smoothing_inputs); + if (options->does_verification) { + for (i = 0; i < array_n(info->xnor_nodes); i++) { + node = array_fetch(node_t *, info->xnor_nodes, i); + ntbdd_free_at_node(node); + } + } + array_free(data->external_outputs); + ntbdd_free_at_node(info->init_node); + for (i = 0; i < array_n(info->transition_nodes); i++) { + node = array_fetch(node_t *, info->transition_nodes, i); + ntbdd_free_at_node(node); + } + array_free(data->transition_outputs); + ntbdd_end_manager(data->manager); + FREE(data); +} + + /* first cofactor all the transition outputs with the current set */ + /* */ + /* do the AND by building a binary trees of those */ + /* keep track of variables that can be removed immediately */ + + +bdd_t *product_compute_next_states(current_set, data, options) +bdd_t *current_set; +range_data_t *data; +verif_options_t *options; +{ + bdd_t *result_as_output = bdd_incr_and_smooth(data->transition_outputs, current_set, data->output_vars, options); + bdd_t *new_current_set = bdd_substitute(result_as_output, data->output_vars, data->input_vars); + + if (options->verbose >= 3) { + (void) fprintf(misout, "(%d->%d)", bdd_size(result_as_output), bdd_size(new_current_set)); + (void) fprintf(sisout, "\n"); + (void) fflush(misout); + } + bdd_free(result_as_output); + return new_current_set; +} + +bdd_t *product_compute_reverse_image(next_set, data, options) +bdd_t *next_set; +range_data_t *data; +verif_options_t *options; +{ + int i; + node_t *node; + array_t *ps_and_pi_array; + bdd_t *result; + bdd_t *next_set_as_next_state_vars; + + next_set_as_next_state_vars = + bdd_substitute(next_set, data->input_vars, data->output_vars); + + ps_and_pi_array = array_alloc(bdd_t *, 0); + for (i = array_n(options->output_info->org_pi); i-- > 0; ){ + node = array_fetch(node_t *, options->output_info->org_pi, i); + array_insert_last(bdd_t *, ps_and_pi_array, ntbdd_at_node(node)); + } + + result = bdd_incr_and_smooth(data->transition_outputs, next_set_as_next_state_vars, ps_and_pi_array, options); + + bdd_free(next_set_as_next_state_vars); + array_free(ps_and_pi_array); + return result; +} + + + /* use this function as a general interface for this operator */ + +bdd_t *bdd_incr_and_smooth(transition_outputs, current_set, keep_vars, options) +array_t *transition_outputs; +bdd_t *current_set; +array_t *keep_vars; +verif_options_t *options; +{ + int i; + int n_fns; + bdd_t *tmp; + bdd_t **fns; + bdd_t *resulting_product; + support_info_t *support_info; + + if (options->verbose >= 3) { + (void) fprintf(misout, "["); (void) fflush(misout); + } + n_fns = array_n(transition_outputs); + fns = ALLOC(bdd_t *, n_fns); + for (i = 0; i < n_fns; i++) { + tmp = array_fetch(bdd_t *, transition_outputs, i); + fns[i] = bdd_cofactor(tmp, current_set); + if (options->verbose >= 3) { + (void) fprintf(misout, "(#%d->%d),", i, bdd_size(tmp)); + (void) fprintf(misout, "(#%d->%d),", i, bdd_size(fns[i])); + (void) fflush(misout); + } + } + if (options->verbose >= 3) { + (void) fprintf(sisout, "]\n"); + } + support_info = support_info_extract(keep_vars, n_fns, fns, options); + FREE(fns); + resulting_product = do_fn_merging(support_info, options); + support_info_free(support_info); + return resulting_product; +} + +int product_check_output(current_set, data, output_index, options) +bdd_t *current_set; +range_data_t *data; +int *output_index; +verif_options_t *options; +{ + int i; + bdd_t *output; + + for (i = 0; i < array_n(data->external_outputs); i++) { + output = array_fetch(bdd_t *, data->external_outputs, i); + if (! bdd_leq(current_set, output, 1, 1)) { + report_inconsistency(current_set, output, options->output_info->pi_ordering); + if (output_index != NIL(int)) { + *output_index = i; + } + return 0; + } + } + return 1; +} + +void product_bdd_sizes(data, fn_size, output_size) +range_data_t *data; +int *fn_size; +int *output_size; +{ + int i; + bdd_t *output; + + if (fn_size) { + *fn_size = 0; + for (i = 0; i < array_n(data->transition_outputs); i++) { + output = array_fetch(bdd_t *, data->transition_outputs, i); + *fn_size += bdd_size(output); + } + } + if (output_size) { + *output_size = 0; + for (i = 0; i < array_n(data->external_outputs); i++) { + output = array_fetch(bdd_t *, data->external_outputs, i); + *output_size += bdd_size(output); + } + } +} + + + /* INTERNAL INTERFACE */ + +static support_info_t *support_info_extract(keep_vars, n_fns, fns, options) +array_t *keep_vars; +int n_fns; +bdd_t **fns; +verif_options_t *options; +{ + int i; + st_table *skip_varids; + support_info_t *support_info = ALLOC(support_info_t, 1); + + support_info->n_fns = n_fns; + if (n_fns == 0) return support_info; + + /* allocate a priority queue for storing the functions */ + support_info->queue = init_queue(support_info->n_fns, fn_info_cmp, fn_info_print); + + /* compute the info related to each fn */ + support_info->fns = ALLOC(fn_info_t *, support_info->n_fns); + extract_fn_info(support_info, fns, options); + + /* get a hash table containing the varids of all the next state variables */ + skip_varids = get_varids_in_table(keep_vars); + + /* compute the info related to each variable; skip over next_state_vars */ + support_info->manager = bdd_get_manager(fns[0]); + support_info->n_vars = bdd_num_vars(support_info->manager); + support_info->vars = ALLOC(var_info_t *, support_info->n_vars); + extract_var_info(support_info, skip_varids); + + support_info->n_partitions = support_info->n_fns; + for (i = 0; i < support_info->n_fns; i++) { + support_info->fns[i]->partition = i; + } + initialize_partition_info(support_info); + + /* smooth now all variables that appear only once */ + smooth_lonely_variables(support_info, options); + + /* deallocate what is no longer needed */ + st_free_table(skip_varids); + + return support_info; +} + +static void support_info_free(support_info) +support_info_t *support_info; +{ + int i; + + free_queue(support_info->queue); + for (i = 0; i < support_info->n_vars; i++) { + assert(support_info->vars[i] == NIL(var_info_t)); + } + FREE(support_info->vars); + for (i = 0; i < support_info->n_fns; i++) { + assert(support_info->fns[i] == NIL(fn_info_t)); + } + FREE(support_info->fns); + FREE(support_info->partition_count); + FREE(support_info->next_partition); + FREE(support_info); +} + +static void extract_fn_info(support_info, fns, options) +support_info_t *support_info; +bdd_t **fns; +verif_options_t *options; +{ + int i; + fn_info_t *info; + + for (i = 0; i < support_info->n_fns; i++) { + info = ALLOC(fn_info_t, 1); + info->fnid = i; + info->partition = 0; + info->fn = fns[i]; + info->support = bdd_get_support(fns[i]); + info->cost = i; + put_queue(support_info->queue, (char *) info); + support_info->fns[i] = info; + } +} + +static void fn_info_free(info) +fn_info_t *info; +{ + var_set_free(info->support); + bdd_free(info->fn); + FREE(info); +} + + /* creates an object with a varid, the corresponding BDD and a hash table */ + /* containing the indices of the fns having the varid in their support */ + +static void extract_var_info(support_info, skip_varids) +support_info_t *support_info; +st_table *skip_varids; +{ + int i; + int varid; + var_info_t *info; + + for (varid = 0; varid < support_info->n_vars; varid++) { + if (st_lookup(skip_varids, (char *) varid, NIL(char *))) { + support_info->vars[varid] = NIL(var_info_t); + continue; + } + info = ALLOC(var_info_t, 1); + info->varid = varid; + info->var = bdd_get_variable(support_info->manager, varid); + info->last_index = -1; + info->fn_table = st_init_table(st_numcmp, st_numhash); + for (i = 0; i < support_info->n_fns; i++) { + if (var_set_get_elt(support_info->fns[i]->support, varid)) { + assert(i == support_info->fns[i]->fnid); + st_insert(info->fn_table, (char *) i, NIL(char)); + info->last_index = i; + } + } + support_info->vars[varid] = info; + } +} + +static void *var_info_free(info) +var_info_t *info; +{ + bdd_free(info->var); + st_free_table(info->fn_table); + FREE(info); +} + + + /* smooth all variables that appear only once */ + +static void smooth_lonely_variables(support_info, options) +support_info_t *support_info; +verif_options_t *options; +{ + int varid; + int index; + bdd_t *tmp; + int remaining; + array_t *var_array; + + var_array = array_alloc(bdd_t *, 1); + for (varid = 0; varid < support_info->n_vars; varid++) { + if (support_info->vars[varid] == NIL(var_info_t)) continue; + remaining = st_count(support_info->vars[varid]->fn_table); + if (remaining == 1) { + array_insert(bdd_t *, var_array, 0, support_info->vars[varid]->var); + index = support_info->vars[varid]->last_index; + tmp = bdd_smooth(support_info->fns[index]->fn, var_array); + bdd_free(support_info->fns[index]->fn); + support_info->fns[index]->fn = tmp; + } + if (remaining == 0 || remaining == 1) { + var_info_free(support_info->vars[varid]); + support_info->vars[varid] = NIL(var_info_t); + } + } + array_free(var_array); +} + + /* AND all functions together and return the result */ + +static bdd_t *do_fn_merging(support_info, options) +support_info_t *support_info; +verif_options_t *options; +{ + int i; + bdd_t *tmp; + fn_info_t *fn0, *fn1; + array_t *smooth_vars; + + /* fn1 disappears after being anded to fn0 */ + for (;;) { + fn0 = (fn_info_t *) get_queue(support_info->queue); + assert(fn0 != NIL(fn_info_t)); + fn1 = (fn_info_t *) get_queue(support_info->queue); + if (fn1 == NIL(fn_info_t)) break; + smooth_vars = smooth_vars_extract(support_info, fn0, fn1); + if (array_n(smooth_vars) == 0) { + tmp = bdd_and(fn0->fn, fn1->fn, 1, 1); + } else { + tmp = bdd_and_smooth(fn0->fn, fn1->fn, smooth_vars); + } + bdd_free(fn0->fn); + fn0->fn = tmp; + + /* if fn0 is the last of its partition, promote it in a higher partition */ + support_info->partition_count[fn1->partition]--; + if (support_info->partition_count[fn0->partition] == 1) { + support_info->partition_count[fn0->partition]--; + fn0->partition = support_info->next_partition[fn0->partition]; + support_info->partition_count[fn0->partition]++; + } + /* adjust the costs */ + fn0->cost += support_info->n_fns; + put_queue(support_info->queue, (char *) fn0); + + if (options->verbose >= 3) { + if (array_n(smooth_vars) > 0) { + (void) fprintf(misout, "(s%d/#%d->#%d,%d),", array_n(smooth_vars), fn1->fnid, fn0->fnid, bdd_size(fn0->fn)); + } else { + (void) fprintf(misout, "(#%d->#%d,%d),", fn1->fnid, fn0->fnid, bdd_size(fn0->fn)); + } + (void) fflush(misout); + } + support_info->fns[fn1->fnid] = NIL(fn_info_t); + fn_info_free(fn1); + for (i = 0; i < array_n(smooth_vars); i++) { + tmp = array_fetch(bdd_t *, smooth_vars, i); + bdd_free(tmp); + } + array_free(smooth_vars); + } + if (options->verbose >= 3) { + (void) fprintf(sisout, "\n"); + } + tmp = bdd_dup(fn0->fn); + support_info->fns[fn0->fnid] = NIL(fn_info_t); + fn_info_free(fn0); + return tmp; +} + + + /* a variable still active here appears in at least two functions */ + /* thus the assertion. If the two functions are fns[index0] and fns[index1] */ + /* we can smooth that variable out now */ + /* can only disappear if it is in both; some bookkeeping if it is in index1 and not in index0 */ + +static array_t *smooth_vars_extract(support_info, fn0, fn1) +support_info_t *support_info; +fn_info_t *fn0; +fn_info_t *fn1; +{ + int i; + int remaining; + array_t *result; + int is_in_index0; + int is_in_index1; + var_info_t *var_info; + + result = array_alloc(bdd_t *, 0); + for (i = 0; i < support_info->n_vars; i++) { + var_info = support_info->vars[i]; + if (var_info == NIL(var_info_t)) continue; + remaining = st_count(var_info->fn_table); + assert(remaining > 1); + is_in_index1 = var_set_get_elt(fn1->support, i); + if (! is_in_index1) continue; + is_in_index0 = var_set_get_elt(fn0->support, i); + if (! is_in_index0) { /* move var i to fn0 */ + var_set_set_elt(fn0->support, i); + st_delete_int(var_info->fn_table, &fn1->fnid, NIL(char *)); + st_insert(var_info->fn_table, (char *) fn0->fnid, NIL(char)); + } else if (remaining == 2) { /* is in both fns only: can be smoothed out */ + array_insert_last(bdd_t *, result, bdd_dup(var_info->var)); + var_info_free(var_info); + support_info->vars[i] = NIL(var_info_t); + } else { /* is in both but somewhere else as well: remove fn1 occurrence */ + st_delete_int(var_info->fn_table, &fn1->fnid, NIL(char *)); + } + } + return result; +} + + /* extract varids from array of bdd_t *'s and put in a hash table */ +static st_table *get_varids_in_table(bdd_array) +array_t *bdd_array; +{ + int i; + int varid; + st_table *result = st_init_table(st_numcmp, st_numhash); + array_t *var_array = bdd_get_varids(bdd_array); + + for (i = 0; i < array_n(var_array); i++) { + varid = array_fetch(int, var_array, i); + st_insert(result, (char *) varid, NIL(char)); + } + array_free(var_array); + return result; +} + + /* valid for all methods */ + /* compute n such that n = 2^p <= n_partitions < 2^{p+1} */ + /* compute x such that x + n = n_partitions */ + /* x is guaranteed to be such that 2 * x < n_partitions */ + +static void initialize_partition_info(support_info) +support_info_t *support_info; +{ + int n_partitions; + int partition; + int i, n, x; + int count; + int n_entries; + int *partition_map; + st_table *table = st_init_table(st_numcmp, st_numhash); + + /* first make the partition identifiers consecutive integers from 0 to n_entries - 1 */ + n_partitions = 0; + for (i = 0; i < support_info->n_fns; i++) { + if (st_lookup(table, (char *) support_info->fns[i]->partition, (char **) &partition)) { + support_info->fns[i]->partition = partition; + } else { + st_insert(table, (char *) support_info->fns[i]->partition, (char *) n_partitions); + support_info->fns[i]->partition = n_partitions++; + } + } + st_free_table(table); + + /* just a consistency check */ + assert(n_partitions == support_info->n_partitions); + + /* compute n=2^p such that 2^p <= n_partitions < 2^{p+1} */ + /* and compute x = n_partitions - 2^p */ + for (n = 1; n <= n_partitions; n <<= 1) ; + if (n > n_partitions) n >>= 1; + assert(n <= n_partitions && 2 * n > n_partitions); + x = n_partitions - n; + + /* make the map from small integers to partition identifiers */ + partition_map = ALLOC(int, n_partitions); + for (i = 0; i < 2 * x; i++) { + partition_map[i] = i; + } + for (i = 2 * x; i < n_partitions; i++) { + partition_map[i] = i + x; + } + + /* make the map from one node in the binary tree of AND's to the next higher one */ + n_entries = n_partitions * 2 - 1; + support_info->next_partition = ALLOC(int, n_entries); + for (i = 0; i < 2 * x; i++) { + support_info->next_partition[i] = 2 * x + i / 2; + } + for (count = n_entries - 1, i = n_entries - 3; i >= 2 * x; i -= 2, count--) { + support_info->next_partition[i] = count; + support_info->next_partition[i + 1] = count; + } + support_info->next_partition[n_entries - 1] = n_entries - 1; + + /* the hard part is done; simple bookkeeping now */ + support_info->partition_count = ALLOC(int, n_entries); + for (i = 0; i < n_entries; i++) { + support_info->partition_count[i] = 0; + } + for (i = 0; i < support_info->n_fns; i++) { + support_info->fns[i]->partition = partition_map[support_info->fns[i]->partition]; + support_info->partition_count[support_info->fns[i]->partition]++; + adj_queue(support_info->queue, (char *) support_info->fns[i]); + } + FREE(partition_map); +} +#endif /* SIS */ diff --git a/sis/seqbdd/seqbdd.h b/sis/seqbdd/seqbdd.h new file mode 100644 index 0000000..e68ff05 --- /dev/null +++ b/sis/seqbdd/seqbdd.h @@ -0,0 +1,204 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/seqbdd.h,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/02/07 11:03:22 $ + * + */ + /* file %M% release %I% */ + /* last modified: %G% at %U% */ + +#ifndef VERIF_INT_H +#define VERIF_INT_H + +typedef enum { + CONSISTENCY_METHOD, + BULL_METHOD, + PRODUCT_METHOD +} range_method_t; + +typedef struct { + int is_product_network; /* 0/1 */ + int generate_global_output; /* 0/1 */ + node_t *main_node; /* main consistency output node: AND of the two net_nodes */ + node_t *output_node; /* the main output node: AND of the xnor_nodes */ + node_t *init_node; /* initial state */ + array_t *new_pi; + array_t *org_pi; /* the PI's before we introduce the consistency PI's */ + array_t *extern_pi; /* the external PI's (not present states) */ + st_table *pi_ordering; /* some good order of the PI's */ + array_t *po_ordering; /* next_state_po, in some good order */ + /* the remaining is (so far) only used by "decoupled.c" */ + node_t *main_nodes[2]; /* net nodes: consistency output for each net (for verification only) */ + array_t *xnor_nodes; /* array of all xnor_nodes (xnor of external outputs) */ + st_table *name_table; /* PIPO name is mapped to 0 or 1 (network 0 or network 1) */ + array_t *transition_nodes; /* nodes corresponding to (y_i == f_i(x)) for each i; product is trans relation */ +} output_info_t; + +typedef struct { + bdd_t *total_set; /* should be computed by general stg traversal routine (read-only) */ + range_method_t type; /* should always be computed */ + bdd_manager *manager; /* should always be computed */ + bdd_t *output_fn; /* should always be computed */ + bdd_t *init_state_fn; /* should always be computed */ + array_t *pi_inputs; /* should always be computed: array of BDD's for PI current state */ + bdd_t *consistency_fn; /* for CONSISTENCY_METHOD */ + array_t *smoothing_inputs; /* for CONSISTENCY_METHOD */ + array_t *output_fns; /* for BULL_METHOD */ + array_t *input_vars; /* for CONSISTENCY2_METHOD (should be merged with pi_inputs) */ + array_t *output_vars; /* for CONSISTENCY2_METHOD */ + array_t *external_outputs; + array_t *transition_outputs; /* for CONSISTENCY2 (one bdd_t per (y_i==f_i(x))) */ +} range_data_t; + +typedef struct verif_options_t verif_options_t; + + /* Each method is implemented using 5 functions of these types. */ + /* The typedefs use _f suffix to remind they are for functions. */ + +typedef range_data_t *seqbdd_range_f ARGS((network_t *, verif_options_t *)); +typedef bdd_t *seqbdd_next_f ARGS((bdd_t *, range_data_t *, verif_options_t *)); +typedef bdd_t *seqbdd_reverse_f ARGS((bdd_t *, range_data_t *, verif_options_t *)); +typedef void seqbdd_free_f ARGS((range_data_t *, verif_options_t *)); +typedef int seqbdd_check_f ARGS((bdd_t *, range_data_t *, int *, verif_options_t *)); +typedef void seqbdd_sizes_f ARGS((range_data_t *, int *, int *)); + +typedef int (*IntFn)(); +typedef bdd_t *(*BddFn)(); + + +#define INIT_STATE_OUTPUT_NAME "initial_state" +#define EXTERNAL_OUTPUT_NAME "equiv:output" + +struct verif_options_t { + /* interface options */ + int timeout; + int keep_old_network; /* 0/1 */ + output_info_t *output_info; + /* algorithm options */ + int does_verification; /* 0/1 */ + int n_iter; /* used for range_computation */ + int stop_if_verify; /* if set, flip the return status of verify_fsm */ + range_method_t type; + seqbdd_range_f *alloc_range_data; + seqbdd_next_f *compute_next_states; + seqbdd_reverse_f *compute_reverse_image; + seqbdd_free_f *free_range_data; + seqbdd_check_f *check_output; + seqbdd_sizes_f *bdd_sizes; + int verbose; + char *sim_file; /* file to save the simulation vectors in */ + /* for machines that do not verify */ + int ordering_depth; /* use to limit the search in good ordering heuristic */ + /* depth of 0 means greedy algorithm */ + int use_manual_order; /* 0/1 */ + char *order_network_name; + network_t *order_network; /* network that specifies the order of PIPO to be used */ + int last_time; /* last time the time was asked for */ + int total_time; /* total time since beginning of command */ + int n_partitions; +}; + + + /* Three sets of functions to implement 3 different methods. */ + /* Because of bug in DECstation cc, can't use typedefs above. */ + +extern range_data_t *consistency_alloc_range_data(); +extern bdd_t *consistency_compute_next_states(); +extern bdd_t *consistency_compute_reverse_image(); +extern void consistency_free_range_data(); +extern int consistency_check_output(); +extern void consistency_bdd_sizes(); + +extern range_data_t *bull_alloc_range_data(); +extern bdd_t *bull_compute_next_states(); +extern bdd_t *bull_compute_reverse_image(); +extern void bull_free_range_data(); +extern int bull_check_output(); +extern void bull_bdd_sizes(); + +extern range_data_t *product_alloc_range_data(); +extern bdd_t *product_compute_next_states(); +extern bdd_t *product_compute_reverse_image(); +extern void product_free_range_data(); +extern int product_check_output(); +extern void product_bdd_sizes(); + + +extern int seqbdd_extract_input_sequence(); +extern int bdd_range_fill_options(); +extern int input_network_check_pi(/* net1, net2 */); +extern int check_input_networks(/* net1, constraints1, net2, constraints2 */); +extern void bdd_print_any_minterm(/* bdd_t *fn */); +extern int seq_verify_interface(); +extern network_t *range_computation_interface(); +extern node_t *copy_init_state_constraint(); +extern node_t *build_equivalence_node(); + + /* from verif_util.c */ +extern array_t *order_nodes(); +extern array_t *create_new_pi(); +extern array_t *get_po_ordering(); +extern st_table *get_pi_ordering(); +extern array_t *get_remaining_po(); +extern array_t *network_extract_next_state_po(/* network_t *network, network_t *constraints */); +extern array_t *network_extract_pi(/* network_t *network */); +extern void print_node_array(/* array_t *array */); +extern void print_node_table(/* st_table *table */); +extern node_t *network_copy_subnetwork(); +extern void report_inconsistency(); +extern st_table *from_array_to_table(/* array_t *array */); +extern void output_info_free(); + + /* from ordering.c */ +typedef struct { + int n_vars; + int n_sets; + var_set_t **sets; +} set_info_t; + +extern array_t *find_best_set_order(/* set_info_t *info, int verbose */); +extern array_t *find_greedy_set_order(/* set_info_t *info, int verbose */); + + /* from verif_util.c */ +extern array_t *bdd_extract_var_array(/* array_t *node_list */); + + /* bdd_tovar.c */ +extern array_t *bdd_get_varids(/* array_t *var_array */); +extern array_t *bdd_get_sorted_varids(/* array_t *var_array */); +extern int bdd_varid_cmp(/* char *obj1, char *obj2 */); + +extern array_t *extract_state_input_vars(/* st_table *pi_ordering, st_table *ito_table */); +extern array_t *extract_state_output_vars(/* st_table *pi_ordering, st_table *ito_table */); +extern st_table *extract_input_to_output_table(/* array_t *org_pi, *new_pi, *po_ordering, network_t *network */); + +extern void report_elapsed_time(/* verif_options_t *options, char *string */); + +extern void compute_product_network(); +extern void output_info_init(); + +typedef struct { + array_t *fns; +} bull_key_t; + +typedef struct { + array_t *fns; + array_t *ins; + bdd_t *range; +} bull_value_t; + +extern bdd_t *input_cofactor(); +extern array_t *disjoint_support_functions(); +extern bdd_t *range_2_compute(); +extern bdd_t *bull_cofactor(); + +extern void get_manual_order(/* st_table *order, verif_options_t *options */); + +extern int breadth_first_stg_traversal(/* network_t **network, network_t *constraints, */ + /* verif_options_t *options */); + + /* from product.c */ +extern bdd_t *bdd_incr_and_smooth(); +#endif /* VERIF_INT_H */ diff --git a/sis/seqbdd/seqbdd_cycle.c b/sis/seqbdd/seqbdd_cycle.c new file mode 100644 index 0000000..dbffe11 --- /dev/null +++ b/sis/seqbdd/seqbdd_cycle.c @@ -0,0 +1,352 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/seqbdd_cycle.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ +#ifdef SIS +#include "sis.h" + +static char *convert_input_minterm_to_char_string(); +static void free_bdd_array(); +static void seqbdd_get_one_edge(); +static bdd_t *seqbdd_get_one_minterm(); +static void bdd_add_varids_to_table(); +static void store_ancestor_state_info(); + +/* + * For computing the initial state after retiming. + * + * 'network': sis network on which the retiming will be applied + + * 'n_shift': the number of clock ticks of simulation the initial state computation will do. + * 'n_shift' is also the number of entries in 'input_seq' that this routine should compute. + + * 'input_order': hash table which maps external PI's from network to small integers, + * from 0 to st_count(input_order)-1. + + * 'input_seq': an array of char strings of length 'n_inputs'. Each correspond to a vector of inputs. + * input = array_fetch(char *, input_seq, i) is interpreted as follows: + * entry input[j] is the value of the external PI mapped to j by 'input_order' at simulation time i. + * input[j] can take one of two possible small integer values: 0, 1. + * BEWARE: simulation time i: input_seq[0] corresponds to the last input transition + * input_seq[n_shift-1] corresponds to the transition leaving the ancestor state + * + * 'reset_ancestor': maps latches to their initial values. If a latch is missing from the table, + * it keeps its previous value. Values can be 0 or 1, as above. + + * returns 0 iff succeeds (1 if the initial state was not reachable from itself). + */ + +int +seqbdd_extract_input_sequence(network, n_shift, input_order, input_seq, reset_ancestor_table) +network_t *network; +int n_shift; +st_table *input_order; +array_t *input_seq; +st_table *reset_ancestor_table; +{ + int i; + int argc; + lsGen gen; + char **argv; + node_t *node; + output_info_t output_info; + verif_options_t local_options, *options; + range_data_t *range_data; + int cycle_found; + bdd_t *edges, *constrained_edges; + bdd_t *ancestor_state; + int ancestor_index; + int cycle_length; + int edge_index; + array_t *total_sets; + bdd_t *current_set, *new_current_set; + bdd_t *var, *care_set; + bdd_t *total_set, *new_total_set; + bdd_t *current_state; + int iter_count; + array_t *cycle_states, *cycle_inputs; + array_t *present_state_array, *true_pi_array; + bdd_t *current_input; + char *input; + + argc = 0; + assert(! bdd_range_fill_options(&local_options, &argc, &argv)); + options = &(local_options); + options->does_verification = 0; + output_info_init(&output_info); + options->output_info = &output_info; + output_info.is_product_network = 0; + extract_network_info(network, options); + if (output_info.init_node == NIL (node_t)) + return 0; + range_data = (*options->alloc_range_data)(network, options); + + present_state_array = array_alloc(bdd_t *, 0); + true_pi_array = array_alloc(bdd_t *, 0); + foreach_primary_input(network, gen, node){ + var = ntbdd_at_node(node); + if (network_latch_end(node) != NIL(node_t)){ + array_insert_last(bdd_t *, present_state_array, var); + } else { + array_insert_last(bdd_t *, true_pi_array, var); + } + } + + total_sets = array_alloc(bdd_t *, 0); + current_set = bdd_dup(range_data->init_state_fn); + total_set = bdd_dup(current_set); + iter_count = 0; + cycle_found = 0; + for (;;) { + array_insert(bdd_t *, total_sets, iter_count, bdd_dup(total_set)); + iter_count++; + new_current_set = (*options->compute_next_states)(current_set, range_data, options); + bdd_free(current_set); + if (bdd_leq(range_data->init_state_fn, new_current_set, 1, 1)) { + cycle_found = 1; + break; + } + if (bdd_leq(new_current_set, total_set, 1, 1)) { + free_bdd_array(total_sets); + (*options->free_range_data)(range_data, options); + return 1; + } + care_set = bdd_not(total_set); + current_set = bdd_cofactor(new_current_set, care_set); + bdd_free(care_set); + new_total_set = bdd_or(new_current_set, total_set, 1, 1); + bdd_free(new_current_set); + bdd_free(total_set); + total_set = new_total_set; + } + + /* need to find the input sequence now */ + assert(cycle_found); + current_state = bdd_dup(range_data->init_state_fn); + cycle_states = array_alloc(bdd_t *, iter_count); + cycle_inputs = array_alloc(bdd_t *, iter_count); + do { + iter_count--; + edges = (*options->compute_reverse_image)(current_state, range_data, options); + bdd_free(current_state); + total_set = array_fetch(bdd_t *, total_sets, iter_count); + constrained_edges = bdd_and(edges, total_set, 1, 1); + bdd_free(edges); + seqbdd_get_one_edge(constrained_edges, range_data, present_state_array, + true_pi_array, ¤t_state, ¤t_input); + bdd_free(constrained_edges); + array_insert(bdd_t *, cycle_states, iter_count, bdd_dup(current_state)); + array_insert(bdd_t *, cycle_inputs, iter_count, bdd_dup(current_input)); + bdd_free(current_input); + } while (iter_count > 0); + bdd_free(current_state); + free_bdd_array(total_sets); + array_free(true_pi_array); + array_free(present_state_array); + + /* consistency check */ + current_state = array_fetch(bdd_t *, cycle_states, 0); + assert(bdd_equal(current_state, range_data->init_state_fn)); + + /* generate the ancestor state and input sequence */ + cycle_length = array_n(cycle_states); + if (n_shift == 0 || cycle_length == 1) { + ancestor_index = 0; + } else { + ancestor_index = (- n_shift) % cycle_length; + if (ancestor_index < 0) { + ancestor_index += cycle_length; + } + } + ancestor_state = array_fetch(bdd_t *, cycle_states, ancestor_index); + store_ancestor_state_info(network, range_data, reset_ancestor_table, ancestor_state); + free_bdd_array(cycle_states); + + edge_index = ancestor_index; + for (i = n_shift - 1; i >= 0; i--, edge_index++) { + current_input = array_fetch(bdd_t *, cycle_inputs, (edge_index % cycle_length)); + input = convert_input_minterm_to_char_string(network, range_data, input_order, current_input); + array_insert(char *, input_seq, i, input); + } + free_bdd_array(cycle_inputs); + (*options->free_range_data)(range_data, options); + output_info_free(&output_info); + return 0; +} + + + /* INTERNAL INTERFACE */ + + +static void +store_ancestor_state_info(network, seq_info, reset_ancestor_table, ancestor_state) +network_t *network; +range_data_t *seq_info; +st_table *reset_ancestor_table; +bdd_t *ancestor_state; +{ + lsGen gen; + node_t *pi; + latch_t *latch; + bdd_t *var; + int value; + + foreach_primary_input(network, gen, pi){ + if (network_is_real_pi(network, pi)) continue; + assert((latch = latch_from_node(pi)) != NIL(latch_t)); + var = ntbdd_at_node(pi); + value = (bdd_leq(ancestor_state, var, 1, 1)) ? 1 : 0; + st_insert(reset_ancestor_table, (char *) latch, (char *) value); + } +} + +static char * +convert_input_minterm_to_char_string(network, seq_info, input_order, input_minterm) +network_t *network; +range_data_t *seq_info; +st_table *input_order; +bdd_t *input_minterm; +{ + st_generator *stgen; + node_t *pi; + bdd_t *var, *bdd_var; + int value; + char *input; + int index; + + input = ALLOC(char, st_count(input_order)); + + + st_foreach_item_int(input_order, stgen, (char **)&pi, &index){ + var = ntbdd_at_node(pi); + value = (bdd_leq(input_minterm, var, 1, 1)) ? 1 : 0; + input[index] = value; + } + return input; +} + +static void +free_bdd_array(bdd_array) +array_t *bdd_array; +{ + int i; + bdd_t *fn; + + for (i = 0; i < array_n(bdd_array); i++) { + fn = array_fetch(bdd_t *, bdd_array, i); + bdd_free(fn); + } + array_free(bdd_array); +} + +static void +seqbdd_get_one_edge(from, seq_info, ps_array, pi_array, state, input) +bdd_t *from; +range_data_t *seq_info; +array_t *ps_array, *pi_array; +bdd_t **state; +bdd_t **input; +{ + bdd_t *minterm; + st_table *var_table; + + assert(! bdd_is_tautology(from, 0)); + + /* precompute the vars to be used */ + var_table = st_init_table(st_numcmp, st_numhash); + bdd_add_varids_to_table(ps_array, var_table); + bdd_add_varids_to_table(pi_array, var_table); + + minterm = seqbdd_get_one_minterm(seq_info->manager, from, var_table); + + st_free_table(var_table); + + if (state != NIL(bdd_t *)) *state = bdd_smooth(minterm, pi_array); + if (input != NIL(bdd_t *)) *input = bdd_smooth(minterm, ps_array); +} + + +/* + * returns a minterm from fn + * Function should only depend on variables contain in 'vars'. + * 'vars' is a table of variable_id, not of bdd_t *'s. + * WARNING: Relies on the fact that the ith bdd_literal in cube + * corresponds to the variable of variable_id == i. + */ + +static bdd_t * +seqbdd_get_one_minterm(manager, fn, vars) +bdd_manager *manager; +bdd_t *fn; +st_table *vars; +{ + int i; + bdd_t *tmp; + bdd_t *bdd_lit; + bdd_t *minterm; + bdd_gen *gen; + int n_lits; + bdd_literal *lits; + array_t *cube; + + assert(! bdd_is_tautology(fn, 0)); + + /* need to free the bdd_gen immediately, otherwise problems with the BDD GC */ + minterm = bdd_one(manager); + gen = bdd_first_cube(fn, &cube); + n_lits = array_n(cube); + lits = ALLOC(bdd_literal, n_lits); + for (i = 0; i < n_lits; i++) { + lits[i] = array_fetch(bdd_literal, cube, i); + } + (void) bdd_gen_free(gen); + + for (i = 0; i < n_lits; i++) { + if (! st_lookup(vars, (char *) i, NIL(char *))) { + assert(lits[i] == 2); + continue; + } + switch (lits[i]) { + case 0: + case 2: + tmp = bdd_get_variable(manager, i); + bdd_lit = bdd_not(tmp); + bdd_free(tmp); + break; + case 1: + bdd_lit = bdd_get_variable(manager, i); + break; + default: + fail("unexpected literal in get_one_minterm"); + break; + } + tmp = bdd_and(minterm, bdd_lit, 1, 1); + bdd_free(minterm); + bdd_free(bdd_lit); + minterm = tmp; + } + return minterm; +} + +static void +bdd_add_varids_to_table(vars, table) +array_t *vars; +st_table *table; +{ + int i; + int varid; + array_t *id_array; + + id_array = bdd_get_varids(vars); + for (i = 0; i < array_n(id_array); i++) { + varid = array_fetch(int, id_array, i); + st_insert(table, (char *) varid, NIL(char)); + } + array_free(id_array); +} +#endif /* SIS */ diff --git a/sis/seqbdd/verif_util.c b/sis/seqbdd/verif_util.c new file mode 100644 index 0000000..833574f --- /dev/null +++ b/sis/seqbdd/verif_util.c @@ -0,0 +1,1081 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/seqbdd/verif_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:54 $ + * + */ +#ifdef SIS +#include "sis.h" + +static int report_error_trace(); +static bdd_t *find_good_constraint(); +static int node_table_entry_cmp(); +static var_set_t **extract_support_info(); +static void bdd_cube_print(); +static void extract_support_info_rec(); +static void node_table_entry_print(); +extern void output_info_free(); +static void use_cofactored_set(); +static void seqbdd_get_one_edge(); +static bdd_t *seqbdd_get_one_minterm(); +static void bdd_add_varids_to_table(); +static void free_bdd_array(); +static void print_error_trace(); +static st_table *get_pi_to_var_table(); +static void print_error_input(); + + + + + /* top level routine for the sequential verifier */ + /* returns 0 iff OK, 1 if verification failed */ + +int seq_verify_interface(network1, network2, options) +network_t *network1; +network_t *network2; +verif_options_t *options; +{ + int result; + output_info_t output_info; + range_data_t *data; + int count1, count2; + node_t *input, *output; + latch_t *latch; + int value; + lsGen gen; + + options->does_verification = 1; + output_info_init(&output_info); + options->output_info = &output_info; + output_info.is_product_network = 1; + count1 = 0; + count2 = 0; + foreach_primary_input(network1, gen, input) { + if ((latch = latch_from_node(input)) == NIL (latch_t)){ + if (!network_find_node(network2, input->name)){ + fprintf(siserr, "input %s appears in network1 but not network2.\n", input->name); + fprintf(siserr, "Finite state machines are not equal.\n"); + return 1; + } + count1++; + } else { + value = latch_get_initial_value(latch); + if ((value != 0) && (value != 1) && (value != 2)) { + fprintf(siserr, "Latch with input %s and output %s is not properly initialized.\n", + node_name(latch_get_input(latch)), + node_name(latch_get_output(latch))); + fprintf(siserr, "Its value should be 0, 1, or 2.\n"); + return 1; + } + } + } + foreach_primary_input(network2, gen, input) { + if ((latch = latch_from_node(input)) == NIL (latch_t)){ + count2++; + } else { + value = latch_get_initial_value(latch); + if (value == 3) { + fprintf(siserr, "Latch with input %s and output %s is not properly initialized.\n", + node_name(latch_get_input(latch)), + node_name(latch_get_output(latch))); + fprintf(siserr, "Its value should be 0, 1, or 2 (don't care).\n"); + return 1; + } + } + } + if (count1 != count2){ + fprintf(siserr, "The number of inputs in the networks are not equal.\n"); + fprintf(siserr, "Finite state machines are not equal.\n"); + return 1; + } + count1 = 0; + count2 = 0; + foreach_primary_output(network1, gen, output) { + if (network_is_real_po(network1, output)){ + if (!network_find_node(network2, output->name)){ + fprintf(siserr, "output %s appears in network1 but not network2.\n", output->name); + fprintf(siserr, "Finite state machines are not equal.\n"); + return 1; + } + count1++; + } + } + foreach_primary_output(network2, gen, output) { + if (network_is_real_po(network2, output)){ + count2++; + } + } + if (count1 != count2){ + fprintf(siserr, "The number of outputs in the networks are not equal.\n"); + fprintf(siserr, "Finite state machines are not equal.\n"); + return 1; + } + if (count1 == 0) { + fprintf(siserr, "Verification not performed: no outputs in the network.\n"); + return 1; + } + switch (options->type) { + case PRODUCT_METHOD: + case BULL_METHOD: + output_info.generate_global_output = 0; + break; + case CONSISTENCY_METHOD: + output_info.generate_global_output = 1; + break; + default: + fail("unregistered range computation method"); + } + extract_product_network_info(network1, network2, options); + result = breadth_first_stg_traversal(&network2, &data, options); +/* if (output_info.init_node == NIL (node_t)) { + return 1; + }*/ + if (result == 0){ + fprintf(siserr, "The finite state machines have the same sequential behavior.\n"); + } else { + if (options->type != PRODUCT_METHOD) { + (void) fprintf(sisout, "error trace only reported for product method\n"); + } else { + report_error_trace(data, options); + } + } + (*options->free_range_data)(data, options); + output_info_free(&output_info); + return result; +} + +static int report_error_trace(range_data, options) +range_data_t *range_data; +verif_options_t *options; +{ + int output_index; + bdd_t *current_set; + bdd_t *new_current_set; + bdd_t *total_set; + bdd_t *new_total_set; + bdd_t *output_fn; + bdd_t *incorrect_support; + bdd_t *incorrect_state; + bdd_t *incorrect_input; + bdd_t *tmp; + array_t *total_sets; + array_t *input_trace; + int iter_count = 0; + int error_found = 0; + + total_sets = array_alloc(bdd_t *, 0); + current_set = bdd_dup(range_data->init_state_fn); + total_set = bdd_zero(range_data->manager); + + for (;;) { + if (options->does_verification) { + if (! (*options->check_output)(current_set, range_data, &output_index, options) +) { + error_found = 1; + break; + } + } + if (! options->does_verification && iter_count >= options->n_iter) break; + use_cofactored_set(¤t_set, &total_set, bdd_cofactor); + array_insert(bdd_t *, total_sets, iter_count, bdd_dup(total_set)); + if (options->does_verification && bdd_is_tautology(total_set, 1)) break; + range_data->total_set = total_set; + new_current_set = (*options->compute_next_states)(current_set, + range_data, options); + bdd_free(current_set); + current_set = new_current_set; + iter_count++; + } + assert(error_found); + output_fn = array_fetch(bdd_t *, range_data->external_outputs, output_index); + incorrect_support = bdd_and(current_set, output_fn, 1, 0); + input_trace = array_alloc(bdd_t *, 0); + for (;;) { + seqbdd_get_one_edge(incorrect_support, range_data, &incorrect_state, + &incorrect_input, options); + bdd_free(incorrect_support); + array_insert(bdd_t *, input_trace, iter_count, incorrect_input); + if (iter_count == 0) break; + iter_count--; + tmp = (*options->compute_reverse_image)(incorrect_state, range_data, options); + total_set = array_fetch(bdd_t *, total_sets, iter_count); + incorrect_support = bdd_and(tmp, total_set, 1, 1); + bdd_free(tmp); + } + free_bdd_array(total_sets); + print_error_trace(input_trace, range_data, options); + free_bdd_array(input_trace); + report_elapsed_time(options, "end error trace generation"); + bdd_free(current_set); + return; +} + +network_t *range_computation_interface(network, options) +network_t *network; +verif_options_t *options; +{ + output_info_t output_info; + range_data_t *data; + + options->does_verification = 0; + output_info_init(&output_info); + options->output_info = &output_info; + output_info.is_product_network = 0; + extract_network_info(network, options); + if (output_info.init_node == NIL (node_t)) + return 0; + (void) breadth_first_stg_traversal(&network, &data, options); + (*options->free_range_data)(data, options); + output_info_free(&output_info); + return network; +} + + + /* INTERNAL INTERFACE */ + + /* returns 0 if it verifies, 1 otherwise */ + + /* WARNING: the output_fn is recomputed by some algorithms */ + /* please do not replace its occurrences by an initialized local variable */ + /* ultimately this should be changed to have a more coherent computation of output_fn */ + /* in particular, here the extraction of error pattern is wrong in case output_fn */ + /* is recomputed at each iteration */ + +int breadth_first_stg_traversal(network, data, options) +network_t **network; +range_data_t **data; +verif_options_t *options; +{ + int i = 0; + int result = 0; + int fn_size, output_size; + bdd_t *new_current_set; + bdd_t *unreached_states; + range_data_t *range_data; + bdd_t *current_set; + bdd_t *total_set; + int index; + node_t *node; + st_generator *gen; + lsGen listgen; + array_t *var_names; + st_table *leaves; + network_t *new_network; + array_t *nodes_array; + char *exdc_prefix; + int prefix_lenght; + char *name; + + range_data = (*options->alloc_range_data)(*network, options); + current_set = bdd_dup(range_data->init_state_fn); + total_set = bdd_zero(range_data->manager); + leaves = options->output_info->pi_ordering; + + for (;;) { + if (options->does_verification) { + if (! (*options->check_output)(current_set, range_data, NIL(int), options)) { + result = 1; + break; + } + } + if (bdd_leq(current_set, total_set, 1, 1)) break; + if (! options->does_verification && i >= options->n_iter) break; + use_cofactored_set(¤t_set, &total_set, bdd_cofactor); + if (options->does_verification && bdd_is_tautology(total_set, 1)) break; + range_data->total_set = total_set; + new_current_set = (*options->compute_next_states)(current_set, range_data, options); + bdd_free(current_set); + current_set = new_current_set; + i++; + } + if (! options->does_verification){ + fprintf(sisout, "\n"); + fprintf(sisout, "number of latches = %d depth = %d states visited = %2.0f\n", + network_num_latch(*network), i, bdd_count_onset(total_set, range_data->pi_inputs)); + } + if (! options->does_verification && ! options->keep_old_network) { + var_names = array_alloc(char *, st_count(leaves)); + st_foreach_item_int(leaves, gen, (char **) &node, &index) { + array_insert(char *, var_names, index, node->name); + } + unreached_states = bdd_not(total_set); + new_network = ntbdd_bdd_single_to_network(unreached_states, "foo", var_names); + nodes_array = network_dfs(new_network); + exdc_prefix = "dc"; + prefix_lenght = strlen(exdc_prefix) + 1; + for(i= 0; i < array_n(nodes_array); i++){ + node = array_fetch(node_t *, nodes_array, i); + if (node_function(node) == NODE_PI) + continue; + if (node_function(node) == NODE_PO) + continue; + name = ALLOC(char , (int) (strlen(node->name) + prefix_lenght)); + (void) sprintf(name, "%s%s", exdc_prefix, node->name); + network_change_node_name(new_network, node, name); + } + foreach_node(new_network, listgen, node){ + node->bdd = (char *) NIL (bdd_t); + } + bdd_free(unreached_states); + array_free(var_names); + array_free(nodes_array); + + eliminate(new_network, 0, 10000); + /* The old network is not freed here. It is the responsibility of + any routine calling breadth_first_traversal and asking NOT to keep + the old network to free that network itself. The reason is that + a later call to ntbdd_end_manager will core dump if this network + is freed now */ + /* network_free(*network); */ + *network = new_network; + } + bdd_free(current_set); + *data = range_data; + return result; +} + +static bdd_t * +find_good_constraint(current_set, total_set, cofactor_fn) +bdd_t *current_set; +bdd_t *total_set; +BddFn cofactor_fn; +{ + bdd_t *care_set = bdd_not(total_set); + bdd_t *result = (*cofactor_fn)(current_set, care_set); + bdd_free(care_set); + return result; +} + + /* leaves: mapping of PI nodes to small integers -> BDD varid's */ + +void report_inconsistency(current_set, output_fn, leaves) +bdd_t *current_set; +bdd_t *output_fn; +st_table *leaves; +{ + bdd_gen *gen; + array_t *cube; + bdd_t *wrong_set = bdd_and(current_set, output_fn, 1, 0); + + assert(! bdd_is_tautology(wrong_set, 0)); + gen = bdd_first_cube(wrong_set, &cube); + (void) fprintf(misout, "\nWARNING: verification failed\nfailing minterm ->\n"); + bdd_cube_print(cube, leaves); + bdd_gen_free(gen); +} + +static void +use_cofactored_set(current_set, total_set, cofactor_fn) +bdd_t **current_set; +bdd_t **total_set; +BddFn cofactor_fn; +{ + bdd_t *new_total_set, *new_current_set; + + new_current_set = find_good_constraint(*current_set, *total_set, cofactor_fn); + new_total_set = bdd_or(*current_set, *total_set, 1, 1); + bdd_free(*current_set); + bdd_free(*total_set); + *total_set = new_total_set; + *current_set = new_current_set; +} + + + /* "network" is the network to be augmented */ + /* "node" is node from some other network */ + /* "pi_table" maps PI names to nodes in "network" */ + /* "node_table" table of nodes already copied and their corresponding node in "network" */ + +node_t *network_copy_subnetwork(network, node, pi_table, node_table) +network_t *network; +node_t *node; +st_table *pi_table; +st_table *node_table; +{ + int i; + node_t *fanin; + node_t *new_node; + + if (st_lookup(node_table, (char *) node, (char **) &new_node)) return new_node; + if (node->type == PRIMARY_INPUT) { + node_t *pi; + assert(st_lookup(pi_table, node->name, (char **) &pi)); + st_insert(node_table, (char *) node, (char *) pi); + return pi; + } + if (node->type == PRIMARY_OUTPUT) { + new_node = network_copy_subnetwork(network, node_get_fanin(node, 0), pi_table, node_table); + if (new_node->type == PRIMARY_INPUT) { + new_node = node_literal(new_node, 1); + network_add_node(network, new_node); + network_change_node_name(network, new_node, util_strsav(node->name)); + } else { + network_change_node_name(network, new_node, util_strsav(node->name)); + } + return network_add_primary_output(network, new_node); + } + new_node = node_dup(node); + foreach_fanin(node, i, fanin) { + node_t *new_fanin = network_copy_subnetwork(network, fanin, pi_table, node_table); + new_node->fanin[i] = new_fanin; + } + network_add_node(network, new_node); + st_insert(node_table, (char *) node, (char *) new_node); + return new_node; +} + +void print_node_array(array) +array_t *array; +{ + int i; + for (i = 0; i < array_n(array); i++) { + node_t *node = array_fetch(node_t *, array, i); + (void) fprintf(misout, "%s ", (node == NIL(node_t)) ? "---" : node->name); + } + (void) fprintf(misout, "\n"); +} + +typedef struct { + node_t *node; + int value; +} node_table_entry_t; + +static int +node_table_entry_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + int diff; + node_table_entry_t *a = (node_table_entry_t *) obj1; + node_table_entry_t *b = (node_table_entry_t *) obj2; + + diff = a->value - b->value; + if (diff == 0) { + diff = strcmp(a->node->name, b->node->name); + } + return diff; +} + +static void +node_table_entry_print(entry) +node_table_entry_t *entry; +{ + (void) fprintf(misout, "%s=>%d ", entry->node->name, entry->value); +} + +void print_node_table(table) +st_table *table; +{ + int i; + node_t *node; + st_generator *gen; + node_table_entry_t entry; + array_t *array = array_alloc(node_table_entry_t, 0); + + st_foreach_item_int(table, gen, (char **) &node, &i) { + entry.node = node; + entry.value = i; + array_insert_last(node_table_entry_t, array, entry); + } + array_sort(array, node_table_entry_cmp); + for (i = 0; i < array_n(array); i++) { + entry = array_fetch(node_table_entry_t, array, i); + node_table_entry_print(&entry); + } + (void) fprintf(misout, "\n"); + array_free(array); +} + + /* skip over the NIL(node_t) entries */ + /* if node does not have a BDD associated with it, should be registered in leaves */ + /* make one for it */ + +array_t *bdd_extract_var_array(manager, node_list, leaves) +bdd_manager *manager; +array_t *node_list; +st_table *leaves; +{ + int i; + int index; + bdd_t *var; + node_t *node; + array_t *result = array_alloc(bdd_t *, array_n(node_list)); + + for (i = 0; i < array_n(node_list); i++) { + node = array_fetch(node_t *, node_list, i); + if (node == NIL(node_t)) continue; + var = ntbdd_at_node(node); + if (var == NIL(bdd_t)) { + assert(st_lookup_int(leaves, (char *) node, &index)); + var = bdd_get_variable(manager, index); + ntbdd_set_at_node(node, var); + } + array_insert_last(bdd_t *, result, var); + } + return result; +} + + + /* heuristic: order the po by minimum increase in total support size so far */ + /* first: minimum support size; second, the one that increases the previous */ + /* support by a minimum amount and so on... */ + /* if use_good_heuristic is on, uses the heuristic in file ordering.c */ + +array_t *get_po_ordering(network, next_state_po, options) +network_t *network; +array_t *next_state_po; +verif_options_t *options; +{ + node_t *node; + int i, index; + set_info_t info; + int n_pi = network_num_pi(network); + int n_po = array_n(next_state_po); + array_t *index_ordering; + array_t *ordering = array_alloc(node_t *, 0); + var_set_t **support_info = extract_support_info(network, next_state_po); + + info.n_vars = n_pi; + info.n_sets = n_po; + info.sets = support_info; + index_ordering = find_best_set_order(&info, options); + assert(array_n(index_ordering) == n_po); + for (i = 0; i < array_n(index_ordering); i++) { + index = array_fetch(int, index_ordering, i); + node = array_fetch(node_t *, next_state_po, index); + array_insert_last(node_t *, ordering, node); + } + array_free(index_ordering); + for (i = 0; i < n_po; i++) { + var_set_free(support_info[i]); + } + FREE(support_info); + return ordering; +} + + /* returns an array of n_po var_set_t containing */ +/* in bitmap the info on which PI is in the support of which PO */ + +static var_set_t ** +extract_support_info(network, node_list) +network_t *network; +array_t *node_list; +{ + int i, uid; + lsGen gen; + node_t *input, *output; + int n_pi = network_num_pi(network); + int n_po = array_n(node_list); + st_table *pi_table = st_init_table(st_ptrcmp, st_ptrhash); + var_set_t **support_info = ALLOC(var_set_t *, n_po); + + for (i = 0; i < n_po; i++) { + support_info[i] = var_set_new(n_pi); + } + uid = 0; + foreach_primary_input(network, gen, input) { + st_insert(pi_table, (char *) input, (char *) uid); + uid++; + } + for (i = 0; i < array_n(node_list); i++) { + st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); + output = array_fetch(node_t *, node_list, i); + extract_support_info_rec(output, pi_table, visited, support_info[i]); + st_free_table(visited); + } + st_free_table(pi_table); + return support_info; +} + +static void +extract_support_info_rec(node, pi_table, visited, set) +node_t *node; +st_table *pi_table; +st_table *visited; +var_set_t *set; +{ + int i; + node_t *fanin; + int uid; + + if (st_lookup(visited, (char *) node, NIL(char *))) return; + st_insert(visited, (char *) node, NIL(char)); + if (node->type == PRIMARY_INPUT) { + assert(st_lookup_int(pi_table, (char *) node, &uid)); + var_set_set_elt(set, uid); + } else { + foreach_fanin(node, i, fanin) { + extract_support_info_rec(fanin, pi_table, visited, set); + } + } +} + + /* starting with po_ordering, get new input variables needed for each po */ + /* and after each po is done, add up the corresponding new_pi */ + +st_table *get_pi_ordering(network, po_ordering, new_pi) +network_t *network; +array_t *po_ordering; +array_t *new_pi; +{ + lsGen gen; + int i, node_index, node_id; + node_t *new_input, *node, *pi; + var_set_t *support; + char *key, *value; + st_generator *table_gen; + array_t *old_pi; + st_table *result; + array_t *remaining_po, *other_pi; + array_t *pi_order = array_alloc(node_t *, 0); + st_table *pi_table = st_init_table(st_ptrcmp, st_ptrhash); + var_set_t **support_info = extract_support_info(network, po_ordering); + var_set_t *so_far = var_set_new(network_num_pi(network)); + + /* extract basic order of PI's out of the network */ + node_id = 0; + foreach_primary_input(network, gen, node) { + st_insert(pi_table, (char *) node, (char *) node_id); + node_id++; + } + + /* extract a good PI order, respecting the po_ordering */ + old_pi = order_nodes(po_ordering, 2); + + + /* order the PI's wrt to the remaining PO's */ + remaining_po = get_remaining_po(network, po_ordering); + other_pi = order_nodes(remaining_po, 1); + array_free(remaining_po); + + /* add the new_inputs and check for consistency */ + node_index = 0; + for (i = 0; i < array_n(po_ordering); i++) { + new_input = array_fetch(node_t *, new_pi, i); + support = support_info[i]; + for (;;) { + if (node_index >= array_n(old_pi)) break; + node = array_fetch(node_t *, old_pi, node_index); + assert(st_lookup_int(pi_table, (char *) node, &node_id)); + if (! var_set_get_elt(support, node_id)) break; + assert(! var_set_get_elt(so_far, node_id)); + array_insert_last(node_t *, pi_order, node); + st_delete(pi_table, (char **) &node, NIL(char *)); + node_index++; + } + array_insert_last(node_t *, pi_order, new_input); + st_delete(pi_table, (char **) &new_input, NIL(char *)); + (void) var_set_or(so_far, so_far, support); + } + + /* put the PI's only dependent on external PO's */ + for (i = 0; i < array_n(other_pi); i++) { + node = array_fetch(node_t *, other_pi, i); + if (st_delete(pi_table, (char **) &node, NIL(char *))) { + array_insert_last(node_t *, pi_order, node); + } + } + + /* put at the end those PI's left over if any */ + st_foreach_item(pi_table, table_gen, &key, &value) { + array_insert_last(node_t *, pi_order, (node_t *) key); + } + assert(network_num_pi(network) == array_n(pi_order)); + + /* free stuff */ + array_free(other_pi); + st_free_table(pi_table); + var_set_free(so_far); + if (old_pi != NIL (array_t)) + array_free(old_pi); + for (i = 0; i < array_n(po_ordering); i++) { + var_set_free(support_info[i]); + } + FREE(support_info); + + result = from_array_to_table(pi_order); + array_free(pi_order); + return result; +} + +array_t *get_remaining_po(network, po_array) +network_t *network; +array_t *po_array; +{ + int i; + lsGen gen; + node_t *po; + array_t *remaining_po = array_alloc(node_t *, 0); + st_table *po_table = st_init_table(st_ptrcmp, st_ptrhash); + + for (i = 0; i < array_n(po_array); i++) { + po = array_fetch(node_t *, po_array, i); + st_insert(po_table, (char *) po, NIL(char)); + } + foreach_primary_output(network, gen, po) { + if (st_lookup(po_table, (char *) po, NIL(char *))) continue; + array_insert_last(node_t *, remaining_po, po); + } + st_free_table(po_table); + return remaining_po; +} + + + +static output_info_t DEFAULT_OUTPUT_INFO = {0,0,0,0,0,0,0,0,0,0, {0,0},0,0,0}; + +void output_info_init(info) +output_info_t *info; +{ + *info = DEFAULT_OUTPUT_INFO; +} + +void +output_info_free(info) +output_info_t *info; +{ + if (info->org_pi) array_free(info->org_pi); + if (info->extern_pi) array_free(info->extern_pi); + if (info->pi_ordering) st_free_table(info->pi_ordering); + if (info->po_ordering) array_free(info->po_ordering); + if (info->new_pi) array_free(info->new_pi); + if (info->xnor_nodes) array_free(info->xnor_nodes); + if (info->name_table) st_free_table(info->name_table); + if (info->transition_nodes) array_free(info->transition_nodes); +} + +void report_elapsed_time(options, comment) +verif_options_t *options; +char *comment; +{ + int last_time = options->last_time; + int new_time = util_cpu_time(); + double elapsed; + double total; + + options->last_time = new_time; + options->total_time += (new_time - last_time); + elapsed = (double) (new_time - last_time) / 1000; + total = (double) (options->total_time) / 1000; + (void) fprintf(misout, "*** [elapsed(%2.1f),total(%2.1f)] ***\n", elapsed, total); + if (comment != NIL(char)) { + (void) fprintf(misout, "%s...\n", comment); + } +} + +st_table *from_array_to_table(array) +array_t *array; +{ + int i; + node_t *node; + st_table *table = st_init_table(st_ptrcmp, st_ptrhash); + + for (i = 0; i < array_n(array); i++) { + node = array_fetch(node_t *, array, i); + st_insert(table, (char *) node, (char *) i); + } + return table; +} + +static void +bdd_cube_print(cube, leaves) +array_t *cube; +st_table *leaves; +{ + int i; + int phase; + int index; + node_t *node; + array_t *names; + st_generator *gen; + char *name; + static char cube_symbols[] = "01-"; + + names = array_alloc(char *, 0); + st_foreach_item_int(leaves, gen, (char **) &node, &index) { + array_insert(char *, names, index, node_long_name(node)); + } + assert(array_n(names) == array_n(cube)); + for (i = 0; i < array_n(cube); i++) { + name = array_fetch(char *, names, i); + (void) fprintf(misout, "%s ", name); + } + (void) fprintf(misout, "\n"); + array_free(names); + for (i = 0; i < array_n(cube); i++) { + phase = array_fetch(int, cube, i); + (void) fprintf(misout, "%c", cube_symbols[phase]); + } + (void) fprintf(misout, "\n"); +} + +array_t *order_nodes(node_vec, pi_only) +array_t *node_vec; +int pi_only; +{ + int index; + lsGen gen; + st_generator *stgen; + node_t *node, *pi; + network_t *network; + st_table *leaves; + array_t *result; + + if (array_n(node_vec) == 0) return NIL(array_t); + node = array_fetch(node_t *, node_vec, 0); + network = node_network(node); + leaves = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_input(network, gen, pi) { + (void) st_insert(leaves, (char *) pi, (char *) -1); + } + result = order_dfs(node_vec, leaves, (pi_only == 2) ? 1 : 0); + if (pi_only) { + array_free(result); + result = array_alloc(node_t *, st_count(leaves)); + st_foreach_item_int(leaves, stgen, (char **) &node, &index) { + if (index != -1) { + array_insert(node_t *, result, index, node); + } + } + } + st_free_table(leaves); + return result; +} + +static void +seqbdd_get_one_edge(from, data, state, input, options) +bdd_t *from; +range_data_t *data; +bdd_t **state; +bdd_t **input; +verif_options_t *options; +{ + output_info_t *info = options->output_info; + bdd_t *minterm; + st_table *var_table; + array_t *external_input_vars; + + assert(! bdd_is_tautology(from, 0)); + + external_input_vars = bdd_extract_var_array(data->manager, info->extern_pi, info->pi_ordering); + /* precompute the vars to be used */ + var_table = st_init_table(st_numcmp, st_numhash); + bdd_add_varids_to_table(data->input_vars, var_table); + bdd_add_varids_to_table(external_input_vars, var_table); + minterm = seqbdd_get_one_minterm(data->manager, from, var_table); + st_free_table(var_table); + + if (state != NIL(bdd_t *)) *state = bdd_smooth(minterm, external_input_vars); + if (input != NIL(bdd_t *)) *input = bdd_smooth(minterm, data->input_vars); + bdd_free(minterm); + array_free(external_input_vars); +} + + +/* + * returns a minterm from fn + * Function should only depend on variables contain in 'vars'. + * 'vars' is a table of variable_id, not of bdd_t *'s. + * WARNING: Relies on the fact that the ith bdd_literal in cube + * corresponds to the variable of variable_id == i. + */ + +static bdd_t * +seqbdd_get_one_minterm(manager, fn, vars) +bdd_manager *manager; +bdd_t *fn; +st_table *vars; +{ + int i; + bdd_t *tmp; + bdd_t *bdd_lit; + bdd_t *minterm; + bdd_gen *gen; + int n_lits; + bdd_literal *lits; + array_t *cube; + + assert(! bdd_is_tautology(fn, 0)); + + /* need to free the bdd_gen immediately, otherwise problems with the BDD GC +*/ + minterm = bdd_one(manager); + gen = bdd_first_cube(fn, &cube); + n_lits = array_n(cube); + + lits = ALLOC(bdd_literal, n_lits); + for (i = 0; i < n_lits; i++) { + lits[i] = array_fetch(bdd_literal, cube, i); + } + (void) bdd_gen_free(gen); + + for (i = 0; i < n_lits; i++) { + if (! st_lookup(vars, (char *) i, NIL(char *))) { + assert(lits[i] == 2); + continue; + } + switch (lits[i]) { + case 0: + case 2: + tmp = bdd_get_variable(manager, i); + bdd_lit = bdd_not(tmp); + bdd_free(tmp); + break; + case 1: + bdd_lit = bdd_get_variable(manager, i); + break; + default: + fail("unexpected literal in get_one_minterm"); + break; + } + tmp = bdd_and(minterm, bdd_lit, 1, 1); + bdd_free(minterm); + bdd_free(bdd_lit); + minterm = tmp; + } + FREE(lits); + return minterm; +} + +static void +bdd_add_varids_to_table(vars, table) +array_t *vars; +st_table *table; +{ + int i; + int varid; + array_t *ids; + + ids = bdd_get_varids(vars); + for (i = 0; i < array_n(vars); i++) { + varid = array_fetch(int, ids, i); + st_insert(table, (char *) varid, NIL(char)); + } + array_free(ids); +} + + + /* given an array of BDD's corresponding to external inputs */ + /* prints out 0's and 1's in a format directly usable by simulate */ + /* input_vars: in simulation order */ + + + /* ARGSUSED */ +static void +print_error_trace(input_trace, data, options) +array_t *input_trace; +range_data_t *data; +verif_options_t *options; +{ + int i; + lsGen gen; + node_t *pi; + bdd_t *input; + bdd_t *var; + array_t *input_vars; + st_table *pi_to_var_table; + output_info_t *info = options->output_info; + char *realf; + FILE *fp = NULL; + + fp = stdout; + (void) fprintf(sisout, "\n"); + if (options->sim_file != NIL(char)) { + fp = com_open_file(options->sim_file, "w", &realf, 0); + if (fp != NULL) { + (void) fprintf(sisout, "Simulation vectors saved in file %s\n", + realf); + } else { + fp = stdout; + } + } + /* first, compute an array: input_vars: external PI index -> BDD var */ + pi_to_var_table = get_pi_to_var_table(data->manager, info, data); + input_vars = array_alloc(bdd_t *, 0); + (void) fprintf(fp, "Input nodes: "); + for(i = 0; i < array_n(info->extern_pi); i++) { + pi = array_fetch(node_t *, info->extern_pi, i); + assert(st_lookup(pi_to_var_table, (char *) pi, (char **) &var)); + array_insert_last(bdd_t *, input_vars, var); + (void) fprintf(fp, "%s ", node_name(pi)); + } + (void) fprintf(fp, "\n"); + st_free_table(pi_to_var_table); + + /* then print minterm by minterm: 2->0 */ + for (i = 0; i < array_n(input_trace); i++) { + input = array_fetch(bdd_t *, input_trace, i); + (void) fprintf(fp, "sim "); + print_error_input(fp, input, input_vars); + (void) fprintf(fp, "\n"); + } + array_free(input_vars); +} + + + /* vars in input_vars are already put in correct I/O order */ + +static void +print_error_input(fp, input, input_vars) +FILE *fp; +bdd_t *input; +array_t *input_vars; +{ + int i; + int value; + bdd_t *var; + + for (i = 0; i < array_n(input_vars); i++) { + var = array_fetch(bdd_t *, input_vars, i); + value = (bdd_leq(input, var, 1, 1)) ? 1 : 0; + (void) fprintf(fp, "%d ", value); + } +} + + /* + * simple utility: report the map between PRIMARY_INPUTS and bdd_t *var's corre +sponding to them + */ + + +static st_table * +get_pi_to_var_table(manager, info, data) +bdd_manager *manager; +output_info_t *info; +range_data_t *data; +{ + int index; + node_t *pi; + bdd_t *var; + st_table *pi_to_var_table; + st_table *po_ordering; + st_generator *gen; + + pi_to_var_table = st_init_table(st_ptrcmp, st_ptrhash); + st_foreach_item_int(info->pi_ordering, gen, (char **) &pi, &index) { + var = ntbdd_node_to_bdd(pi, manager, info->pi_ordering); + st_insert(pi_to_var_table, (char *) pi, (char *) var); + } + return pi_to_var_table; +} + + +static void +free_bdd_array(bdd_array) +array_t *bdd_array; +{ + int i; + bdd_t *fn; + + for (i = 0; i < array_n(bdd_array); i++) { + fn = array_fetch(bdd_t *, bdd_array, i); + bdd_free(fn); + } + array_free(bdd_array); +} + + +#endif /* SIS */ diff --git a/sis/sim/Makefile.am b/sis/sim/Makefile.am new file mode 100644 index 0000000..c69d076 --- /dev/null +++ b/sis/sim/Makefile.am @@ -0,0 +1,4 @@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libsim.a +libsim_a_SOURCES = codegen.c com_sim.c interpret.c sim_int.h diff --git a/sis/sim/Makefile.in b/sis/sim/Makefile.in new file mode 100644 index 0000000..077b953 --- /dev/null +++ b/sis/sim/Makefile.in @@ -0,0 +1,368 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(libsim_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/sim +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libsim_a_AR = $(AR) $(ARFLAGS) +libsim_a_LIBADD = +am_libsim_a_OBJECTS = codegen.$(OBJEXT) com_sim.$(OBJEXT) \ + interpret.$(OBJEXT) +libsim_a_OBJECTS = $(am_libsim_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libsim_a_SOURCES) +DIST_SOURCES = $(libsim_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libsim.a +libsim_a_SOURCES = codegen.c com_sim.c interpret.c sim_int.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/sim/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/sim/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libsim.a: $(libsim_a_OBJECTS) $(libsim_a_DEPENDENCIES) + -rm -f libsim.a + $(libsim_a_AR) libsim.a $(libsim_a_OBJECTS) $(libsim_a_LIBADD) + $(RANLIB) libsim.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/sim/codegen.c b/sis/sim/codegen.c new file mode 100644 index 0000000..6048df6 --- /dev/null +++ b/sis/sim/codegen.c @@ -0,0 +1,220 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/sim/codegen.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:45 $ + * + */ +#include "sis.h" +#include "sim_int.h" + +static void sim_gen_code(); + + +sim_verify_codegen(network1, network2, num, root) +network_t *network1; +network_t *network2; +int num; +char *root; +{ + FILE *fp, *fpread; + int i, j, c, nin, nout, nodes1, nodes2, *inmap, *outmap; + node_t *node1, *node2; + lsGen gen1, gen2; + char buffer[1024]; + + if (network_num_pi(network1) != network_num_pi(network2)) { + (void) fprintf(miserr, "Number of inputs do not agree\n"); + return 0; + } + + if (network_num_po(network1) != network_num_po(network2)) { + (void) fprintf(miserr, "Number of outputs do not agree\n"); + return 0; + } + + /* generate the input mapping table */ + inmap = ALLOC(int, network_num_pi(network1)); + i = 0; + foreach_primary_input(network1, gen1, node1) { + j = 0; + foreach_primary_input(network2, gen2, node2) { + if (strcmp(node1->name, node2->name) == 0) { + inmap[i] = j; + break; + } + j++; + } + if (j == network_num_pi(network2)) { + (void) fprintf(miserr, + "No match for input '%s' in network2\n", node_name(node1)); + return 0; + } + i++; + } + + /* generate the output mapping table */ + outmap = ALLOC(int, network_num_po(network1)); + i = 0; + foreach_primary_output(network1, gen1, node1) { + j = 0; + foreach_primary_output(network2, gen2, node2) { + if (strcmp(node1->name, node2->name) == 0) { + outmap[i] = j; + break; + } + j++; + } + if (j == network_num_po(network2)) { + (void) fprintf(miserr, + "No match for output '%s' in network2\n", node_name(node1)); + return 0; + } + i++; + } + + /* open the C source file */ + (void) sprintf(buffer, "%s.c", root); + fp = com_open_file(buffer, "w", NIL(char *), /* silent */ 0); + if (fp == 0) return 0; + + /* generate constants */ + nin = network_num_pi(network1); + nout = network_num_po(network2); + nodes1 = network_num_internal(network1) + nin + nout + 10; + nodes2 = network_num_internal(network2) + nin + nout + 10; + (void) fprintf(fp, "#define nin %d\n", nin); + (void) fprintf(fp, "#define nout %d\n", nout); + (void) fprintf(fp, "#define nodes1 %d\n", nodes1); + (void) fprintf(fp, "#define nodes2 %d\n", nodes2); + + /* generate code for the two networks */ + sim_gen_code(fp, network1, "func1"); + sim_gen_code(fp, network2, "func2"); + + /* generate the name for outputs */ + (void) fprintf(fp, "char *output_names[%d] = {\n", nout); + foreach_primary_output(network1, gen1, node1) { + (void) fprintf(fp, " \"%s\",\n", node1->name); + } + (void) fprintf(fp, "};\n"); + + /* print the input mapping table */ + (void) fprintf(fp, "int input_map[%d] = {\n", nin); + for(i = 0; i < nin; i++) { + (void) fprintf(fp, " %d,\n", inmap[i]); + } + (void) fprintf(fp, "};\n"); + + /* print the output mapping table */ + (void) fprintf(fp, "int output_map[%d] = {\n", nout); + for(i = 0; i < nout; i++) { + (void) fprintf(fp, " %d,\n", outmap[i]); + } + (void) fprintf(fp, "};\n"); + + /* copy the standard driver source */ + fpread = com_open_file("driver.c", "r", NIL(char *), /* silent */ 0); + if (fpread == 0) return 0; + while ((c = getc(fpread)) != EOF) { + putc(c, fp); + } + (void) fclose(fpread); + + (void) fclose(fp); + + (void) sprintf(buffer, "cc -o %s %s.c", root, root); + (void) system(buffer); + + (void) sprintf(buffer, "%s %d", root, num / 32 + 1); + (void) system(buffer); + + FREE(inmap); + FREE(outmap); + return 1; +} + +static void +sim_gen_code(fp, network, func_name) +FILE *fp; +network_t *network; +char *func_name; +{ + int i, j, k, first_literal, first_cube; + nodeindex_t *table; + node_cube_t cube; + node_literal_t literal; + node_t *node, *fanin; + array_t *nodevec; + lsGen gen; + + table = nodeindex_alloc(); + foreach_primary_input(network, gen, node) { + (void) nodeindex_insert(table, node); + } + foreach_primary_output(network, gen, node) { + (void) nodeindex_insert(table, node); + } + foreach_node(network, gen, node) { + if (node->type == INTERNAL) { + (void) nodeindex_insert(table, node); + } + } + + (void) fprintf(fp, "void %s(a)\nregister unsigned *a;\n{\n", func_name); + nodevec = network_dfs(network); + + for(i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type == INTERNAL) { + (void) fprintf(fp, " a[%d] = ", nodeindex_indexof(table, node)); + + if (node_function(node) == NODE_0) { + (void) fprintf(fp, "0"); + + } else if (node_function(node) == NODE_1) { + (void) fprintf(fp, "(unsigned) -1"); + + } else { + first_cube = 1; + + for(j = node_num_cube(node)-1; j >= 0; j--) { + cube = node_get_cube(node, j); + if (! first_cube) (void) fprintf(fp, "|"); + first_literal = 1; + + foreach_fanin(node, k, fanin) { + literal = node_get_literal(cube, k); + switch(literal) { + case ONE: + if (! first_literal) (void) fprintf(fp, "&"); + (void) fprintf(fp, "a[%d]", + nodeindex_indexof(table, fanin)); + first_literal = 0; + break; + case ZERO: + if (! first_literal) (void) fprintf(fp, "&"); + (void) fprintf(fp, "~a[%d]", + nodeindex_indexof(table, fanin)); + first_literal = 0; + break; + } + } + first_cube = 0; + } + } + (void) fprintf(fp, ";\n"); + + } else if (node->type == PRIMARY_OUTPUT) { + fanin = node_get_fanin(node, 0); + (void) fprintf(fp, " a[%d] = a[%d];\n", + nodeindex_indexof(table, node), + nodeindex_indexof(table, fanin)); + } + } + array_free(nodevec); + nodeindex_free(table); + (void) fprintf(fp, "}\n"); +} diff --git a/sis/sim/com_sim.c b/sis/sim/com_sim.c new file mode 100644 index 0000000..1315a9e --- /dev/null +++ b/sis/sim/com_sim.c @@ -0,0 +1,502 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/sim/com_sim.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "sim_int.h" + + +#ifdef SIS + +static void +dump_outputs(fp, n, vec) +FILE *fp; +network_t *n; +array_t *vec; +{ + int i; + latch_t *l; + lsGen gen; + node_t *po; + + (void) fprintf(fp, "\nNetwork simulation:\n"); + (void) fprintf(fp, "Outputs:"); + i = 0; + foreach_primary_output(n, gen, po) { + if (network_is_real_po(n, po)) { + (void) fprintf(fp, " %d", array_fetch(int, vec, i)); + } + i++; + } + (void) fprintf(fp, "\n"); + (void) fprintf(fp, "Next state: "); + i = 0; + foreach_primary_output(n, gen, po) { + if ((l = latch_from_node(po)) != NIL(latch_t)) { + (void) fprintf(fp, "%d", latch_get_current_value(l)); + } + i++; + } + (void) fprintf(fp, "\n"); + return; +} + + +static int +com_simulate(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i, j; + int c; + int do_logic = 1; + int do_stg = 1; + array_t *in_value, *out_value, *node_vec, *out_char; + st_table *control_table; + int value, control_value; + node_t *pi, *po, *control; + latch_t *l; + lsGen gen; + graph_t *stg; + vertex_t *state; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "is")) != EOF) { + switch(c) { + case 'i': + do_stg = 0; + break; + case 's': + do_logic = 0; + break; + default: + goto usage; + } + } + if (!do_stg && !do_logic) { + do_stg = do_logic = 1; + } + if (do_logic) { + if (network_num_pi(*network) != 0) { + if (argc-util_optind != (network_num_pi(*network) - + network_num_latch(*network))) { + (void) fprintf(miserr, + "simulate network: network has %d inputs; %d values were supplied.\n", + network_num_pi(*network) - + network_num_latch(*network), argc - 1); + goto usage; + } + in_value = array_alloc(int, network_num_pi(*network)); + i = util_optind; + foreach_primary_input(*network, gen, pi) { + if ((l = latch_from_node(pi)) != NIL(latch_t)) { + value = latch_get_current_value(l); + if ((value != 0) && (value != 1)) { + (void) fprintf(siserr, "Some latch has the value 'don't care' or 'undefined'.\n"); + (void) fprintf(siserr, "Use set_state to put the network in a valid state.\n"); + array_free(in_value); + lsFinish(gen); + return 1; + } + array_insert_last(int, in_value, value); + } else { + if (strcmp(argv[i], "0") == 0) { + array_insert_last(int, in_value, 0); + } else if (strcmp(argv[i], "1") == 0) { + array_insert_last(int, in_value, 1); + } else { + (void) fprintf(miserr, + "simulate network: bad value '%s' -- should be 0 or 1\n", argv[i]); + array_free(in_value); + lsFinish(gen); + goto usage; + } + i++; + } + } + node_vec = network_dfs(*network); + out_value = simulate_network(*network, node_vec, in_value); + j = 0; + control_table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_output(*network, gen, po) { + value = array_fetch(int, out_value, j); + (void) st_insert(control_table, (char *) po, (char *) value); + j++; + } + j = 0; + foreach_primary_output(*network, gen, po) { + if ((l = latch_from_node(po)) != NIL(latch_t)) { + value = array_fetch(int, out_value, j); + control = latch_get_control(l); + if (control == NIL(node_t)) { + /* If no control node is specified, clock the latch. */ + latch_set_current_value(l, value); + } else { + (void) st_lookup_int(control_table, (char *) control, + &control_value); + if (control_value) { + latch_set_current_value(l, value); + } + } + } + j++; + } + st_free_table(control_table); + array_free(node_vec); + dump_outputs(misout, *network, out_value); + array_free(in_value); + array_free(out_value); + } + } + if (do_stg) { + if ((stg = network_stg(*network)) != NIL(graph_t)) { + if (argc-util_optind != stg_get_num_inputs(stg)) { + (void) fprintf(miserr, "simulate stg: stg has %d inputs; %d values were supplied.\n", stg_get_num_inputs(stg), argc-1); + goto usage; + } + in_value = array_alloc(int, stg_get_num_inputs(stg)); + for (i = util_optind; i < stg_get_num_inputs(stg)+util_optind; i++) { + if (strcmp(argv[i], "0") == 0) { + array_insert_last(int, in_value, 0); + } else if (strcmp(argv[i], "1") == 0) { + array_insert_last(int, in_value, 1); + } else { + (void) fprintf(miserr, "simulate stg: bad value '%s' -- should be 0 or 1\n", argv[i]); + array_free(in_value); + goto usage; + } + } + out_char = simulate_stg(stg, in_value, &state); + (void) fprintf(misout, "\nSTG simulation:\n"); + if (state == NIL(vertex_t)) { + (void) fprintf(misout, "Next state cannot be determined\n"); + array_free(out_char); + array_free(in_value); + return 0; + } + (void) fprintf(misout, "Outputs:"); + for (i = 0; i < stg_get_num_outputs(stg); i++) { + (void) fprintf(misout, " %c", array_fetch(char, out_char, i)); + } + (void) fprintf(misout, "\nNext state: %s (%s)\n\n", + stg_get_state_name(state), + stg_get_state_encoding(state)); + array_free(in_value); + array_free(out_char); + } + } + return 0; + +usage: + (void) fprintf(miserr, "usage: simulate [-s] [-i] in1 in2 in3 ...\n"); + return 1; +} + + + +static int +com_set_state(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int do_stg = 1; + int do_logic = 1; + char *state_name; + char *temp; + lsGen gen; + latch_t *l; + int encoding; + int c; + graph_t *stg; + int i; + vertex_t *v; + + if ((network_num_pi(*network) == 0) && + (network_stg(*network) == NIL(graph_t))) { + return 0; + } + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "is")) != EOF) { + switch(c) { + case 'i': + do_stg = 0; + break; + case 's': + do_logic = 0; + break; + default: + goto usage; + } + } + if (!do_stg && !do_logic) { + do_stg = do_logic = 1; + } + if (do_logic && (network_num_pi(*network) != 0)) { + encoding = 1; + } else { + encoding = 0; + } + if (argc-util_optind == 0) { + foreach_latch(*network, gen, l) { + latch_set_current_value(l, latch_get_initial_value(l)); + } + if ((stg = network_stg(*network)) != NIL(graph_t)) { + stg_reset(stg); + } + return 0; + } + if (argc-util_optind != 1) { + (void) fprintf(miserr, "set_state: one state must be given\n"); + goto usage; + } + state_name = argv[util_optind]; + if (do_logic) { + if (network_num_latch(*network) != 0) { + if (strlen(state_name) != network_num_latch(*network)) { + (void) fprintf(miserr, "set_state: network had %d latches; %d values were supplied.\n", network_num_latch(*network), strlen(state_name)); + goto usage; + } + for (i = 0; i < strlen(state_name); i++) { + if ((state_name[i] != '0') && (state_name[i] != '1')) { + (void) fprintf(miserr, "set_state: bad value '%c' -- should be 0 or 1\n", c); + goto usage; + } + } + temp = state_name; + foreach_latch(*network, gen, l) { + c = *state_name++; + if (c == '0') { + latch_set_current_value(l, 0); + } else if (c == '1') { + latch_set_current_value(l, 1); + } + } + state_name = temp; + } + } + if (do_stg) { + if ((stg = network_stg(*network)) != NIL(graph_t)) { + if (encoding) { + if ((v = stg_get_state_by_encoding(stg, state_name)) + != NIL(vertex_t)) { + stg_set_current(stg, v); + } else { + (void) fprintf(miserr, "set_state: state with encoding name %s not found in stg\n", state_name); + goto usage; + } + } else { + if ((v = stg_get_state_by_name(stg, state_name)) + != NIL(vertex_t)) { + stg_set_current(stg, v); + } else { + (void) fprintf(miserr, "set_state: state with symbolic name %s not found in stg\n", state_name); + goto usage; + } + } + } + } + return 0; + +usage: + (void) fprintf(miserr, "usage: set_state [-s] [-i] [state_name]\n"); + return 1; +} + + +/*ARGSUSED*/ +static int +com_print_state(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + lsGen gen; + latch_t *l; + graph_t *stg; + vertex_t *v; + + if (argc != 1) { + goto usage; + } + (void) fprintf(misout, "\n"); + if (network_num_pi(*network) != 0) { + (void) fprintf(misout, "Network state: "); + foreach_latch(*network, gen, l) { + (void) fprintf(misout, "%d", latch_get_current_value(l)); + } + (void) fprintf(misout, "\n\n"); + } + if ((stg = network_stg(*network)) != NIL(graph_t)) { + (void) fprintf(misout, "STG state: "); + v = stg_get_current(stg); + (void) fprintf(misout, "%s (%s)\n\n", stg_get_state_name(v), + stg_get_state_encoding(v)); + } + return 0; +usage: + (void) fprintf(miserr, "usage: print_state\n"); + return 1; +} + +#else + +static int +dump_vector(fp, vec) +FILE *fp; +array_t *vec; +{ + int i; + + for(i = 0; i < array_n(vec); i++) { + (void) fprintf(fp, " %d", array_fetch(int, vec, i)); + } + (void) fprintf(fp, "\n"); +} + + + +static int +com_simulate(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i; + array_t *in_value, *out_value, *node_vec; + + if (argc - 1 != network_num_pi(*network)) { + (void) fprintf(miserr, + "simulate: network has %d inputs; %d values were supplied.\n", + network_num_pi(*network), argc - 1); + goto usage; + } + + in_value = array_alloc(int, 10); + for(i = 1; i < argc; i++) { + if (strcmp(argv[i], "0") == 0) { + array_insert_last(int, in_value, 0); + } else if (strcmp(argv[i], "1") == 0) { + array_insert_last(int, in_value, 1); + } else { + (void) fprintf(miserr, + "simulate: bad value '%s' -- should be 0 or 1\n", argv[i]); + array_free(in_value); + goto usage; + } + } + +#if 1 + node_vec = network_dfs(*network); + out_value = simulate_network(*network, node_vec, in_value); + array_free(node_vec); +#else + { + int i, j; + network_t *net1; + node_t *node; + lsGen gen; + + net1 = network_dup(*network); + + i = 0; + foreach_primary_input(net1, gen, node) { + j = array_fetch(int, in_value, i++); + node_replace(node, j ? node_constant(1) : node_constant(0)); + } + (void) network_collapse(net1); + out_value = array_alloc(int, 0); + foreach_primary_output(net1, gen, node) { + j = node_function(node_get_fanin(node, 0)) == NODE_1; + array_insert_last(int, out_value, j); + } + network_free(net1); + } +#endif + + dump_vector(misout, out_value); + + array_free(in_value); + array_free(out_value); + return 0; + +usage: + (void) fprintf(miserr, "usage: simulate in1 in2 in3 ...\n"); + return 1; +} + +#endif + + +static int +com_sim_verify(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + int n_patterns = 1024; + network_t *network1; + char buffer[1024]; + int status; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "n:")) != EOF) { + switch (c) { + case 'n': + n_patterns = atoi(util_optarg); + if (n_patterns < 1) goto usage; + if (n_patterns % 32 != 0) + n_patterns += (32 - (n_patterns % 32)); + break; + default: + goto usage; + } + } + if (argc - util_optind != 1) goto usage; + (void) sprintf(buffer, "read_blif %s", argv[util_optind]); + network1 = network_alloc(); + if (com_execute(&network1, buffer) != 0) { + network_free(network1); + return 1; + } + if (network_num_pi(network1) != network_num_pi(*network)) { + (void) fprintf(miserr, "Number of inputs do not agree\n"); + network_free(network1); + return 1; + } + if (network_num_po(network1) != network_num_po(*network)) { + (void) fprintf(miserr, "Number of outputs do not agree\n"); + network_free(network1); + return 1; + } + + status = sim_verify(*network, network1, n_patterns); + network_free(network1); + return status; + + usage: + (void) fprintf(miserr, "usage: sim_verify [-n n_patterns] network2.blif\n"); + return 1; +} + +init_sim() +{ + com_add_command("simulate", com_simulate, 0); +#ifdef SIS + com_add_command("set_state", com_set_state, 1); + com_add_command("print_state", com_print_state, 0); +#endif + com_add_command("sim_verify", com_sim_verify, 0); +} + + +end_sim() +{ +} diff --git a/sis/sim/interpret.c b/sis/sim/interpret.c new file mode 100644 index 0000000..bfa45a0 --- /dev/null +++ b/sis/sim/interpret.c @@ -0,0 +1,382 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/sim/interpret.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include "sis.h" +#include "sim_int.h" + +/* + * simulate a node + * assumes the values are already stored for the fanin's + * sets the new value at the node + */ + +void +simulate_node(node) +node_t *node; +{ + int i, value; + node_t *fanin, *func, *func1, *lit; + + func = node_dup(node); + foreach_fanin(node, i, fanin) { + value = GET_VALUE(fanin); + + lit = node_literal(fanin, value); + func1 = node_cofactor(func, lit); + node_free(func); + node_free(lit); + func = func1; + + if (node_function(func) == NODE_0) { + break; + } + } + + if (node_function(func) == NODE_0) { + SET_VALUE(node, 0); + } else { + SET_VALUE(node, 1); + } + + node_free(func); +} + +/* + * simulate a network + */ + +array_t * +simulate_network(network, node_vec, in_value) +network_t *network; +array_t *node_vec; /* dfs order for nodes */ +array_t *in_value; /* values for Primary Inputs */ +{ + int i, value; + node_t *node, *pi, *po; + array_t *po_value; + lsGen gen; + + if (array_n(in_value) != network_num_pi(network)) { + fail("network_simulate: too few input values supplied"); + } + + /* set the values on the primary inputs */ + i = 0; + foreach_primary_input(network, gen, pi) { + value = array_fetch(int, in_value, i); + SET_VALUE(pi, value); + i++; + } + + /* simulate the values through the network */ + for(i = 0; i < array_n(node_vec); i++) { + node = array_fetch(node_t *, node_vec, i); + if (node->type == INTERNAL) { + simulate_node(node); + } + } + + /* retrieve the values on the outputs (from their driving nodes) */ + po_value = array_alloc(int, 10); + foreach_primary_output(network, gen, po) { + value = GET_VALUE(node_get_fanin(po, 0)); + array_insert_last(int, po_value, value); + } + + return po_value; +} + + +#ifdef SIS + +static int +equivtrans(x, y) +char *x, *y; +{ + char c; + + while (c = *x++) { + if (c != '-' && *y != '-' && c != *y) { + return(FALSE); + } + y++; + } + return(TRUE); +} + + +array_t * +simulate_stg(stg, in_value, state) +graph_t *stg; +array_t *in_value; +vertex_t **state; +{ + vertex_t *current, *temp; + edge_t *edge; + lsGen gen; + int value; + char *input, *output; + char *buf; + int i; + array_t *out_char; + + buf = ALLOC(char, array_n(in_value) + 1); + for (i = 0; i < array_n(in_value); i++) { + value = array_fetch(int, in_value, i); + if (value == 0) { + buf[i] = '0'; + } else if (value == 1) { + buf[i] = '1'; + } else { + fail("simulate_stg: bad value in simulation\n"); + } + } + buf[array_n(in_value)] = '\0'; + current = stg_get_current(stg); + *state = NIL(vertex_t); + out_char = array_alloc(char, stg_get_num_outputs(stg)); + foreach_state_outedge(current, gen, edge) { + input = stg_edge_input_string(edge); + if (equivtrans(input, buf)) { + output = stg_edge_output_string(edge); + *state = stg_edge_to_state(edge); + stg_set_current(stg, *state); + for (i = 0; i < stg_get_num_outputs(stg); i++) { + array_insert_last(char, out_char, *output++); + } + } + } + if (*state == NIL(vertex_t)) { + if ((current = stg_get_state_by_name(stg, "ANY")) != NIL(vertex_t) || + (temp = stg_get_state_by_name(stg, "*")) != NIL(vertex_t)) { + current = (current != NIL(vertex_t)) ? current : temp; + foreach_state_outedge(current, gen, edge) { + input = stg_edge_input_string(edge); + if (equivtrans(input, buf)) { + output = stg_edge_output_string(edge); + *state = stg_edge_to_state(edge); + stg_set_current(stg, *state); + for (i = 0; i < stg_get_num_outputs(stg); i++) { + array_insert_last(char, out_char, *output++); + } + } + } + } + } + + FREE(buf); + return out_char; +} + +#endif + + /* routines to do simulation 32 bits at a time */ + /* implements sim_verify */ + +static int simulate_network_32_rec(); +static int simulate_node_32(); +static void gen_random_pattern(); +static void print_pattern(); +static void report_error(); +static void simulate_network_32(); + + /* EXTERNAL INTERFACE */ + +int sim_verify(network0, network1, n_patterns) +network_t *network0; +network_t *network1; +int n_patterns; +{ + int i, j, k; + int n_pi = network_num_pi(network0); + int n_po = network_num_po(network0); + int *pi_values = ALLOC(int, n_pi); + int **po_values = ALLOC(int *, 2); + network_t **networks = ALLOC(network_t *, 2); + + n_patterns >>= 5; + networks[0] = network0; + networks[1] = network1; + + for (j = 0; j < 2; j++) { + po_values[j] = ALLOC(int, n_po); + } + + for (i = 0; i < n_patterns; i++) { + int seed = (int) network0 + (int) network1 + (int) pi_values; + gen_random_pattern(n_pi, pi_values, seed); + for (j = 0; j < 2; j++) { + simulate_network_32(networks[j], pi_values, po_values[j]); + } + for (k = 0; k < n_po; k++) { + if (po_values[0][k] != po_values[1][k]) { + report_error(pi_values, po_values, networks, k); + FREE(pi_values); + for (i = 0; i < 2; i++) + FREE(po_values[i]); + FREE(po_values); + return 1; + } + } + } + FREE(pi_values); + for (i = 0; i < 2; i++) + FREE(po_values[i]); + FREE(po_values); + (void) fprintf(misout, "Passed verification with %d random input vectors\n", n_patterns << 5); + return 0; +} + +static void report_error(pi_values, po_values, networks, faulty_po) +int *pi_values; +int **po_values; +network_t **networks; +int faulty_po; +{ + int i; + int diff; + int n_pi = network_num_pi(networks[0]); + int n_po = network_num_po(networks[1]); + int mask; + + diff = po_values[0][faulty_po] ^ po_values[1][faulty_po]; + assert(diff); + i = 0; + while (diff % 2 == 0) { + diff >>= 1; + i++; + } + mask = 1 << i; + (void) fprintf(misout, "verification failed on input value: "); + print_pattern(n_pi, pi_values, mask); + (void) fprintf(misout, "\n"); + (void) fprintf(misout, "internal network outputs: "); + print_pattern(n_po, po_values[0], mask); + (void) fprintf(misout, "\n"); + (void) fprintf(misout, "read-in network outputs: "); + print_pattern(n_po, po_values[1], mask); + (void) fprintf(misout, "\n"); + (void) fprintf(misout, "Note that the inputs and outputs are matched up by order, not by name\n"); +} + +static void print_pattern(n, pattern, mask) +int n; +int *pattern; +int mask; +{ + int i; + for (i = 0; i < n; i++) + fprintf(misout, "%d ", (pattern[i] & mask) != 0); +} + + + /* minor hack: random generates numbers from 0 to 2^31 only */ + +static void gen_random_pattern(n, pattern, seed) +int n; +int *pattern; +int seed; +{ + int i; + srandom(seed); + for (i = 0; i < n; i++) { + pattern[i] = (random() << 16) | (random() & 0xffff); + } +} + +static void simulate_network_32(network, pi_values, po_values) +network_t *network; +int *pi_values; +int *po_values; +{ + int i; + lsGen gen; + node_t *pi, *po; + st_table *table = st_init_table(st_ptrcmp, st_ptrhash); + + i = 0; + foreach_primary_input(network, gen, pi) { + st_insert(table, (char *) pi, (char *) pi_values[i]); + i++; + } + i = 0; + foreach_primary_output(network, gen, po) { + node_t *input = node_get_fanin(po, 0); + po_values[i] = simulate_network_32_rec(network, table, input); + i++; + } +} + +static int simulate_network_32_rec(network, table, node) +network_t *network; +st_table *table; +node_t *node; +{ + int i; + char *value; + int result; + int n_inputs = node_num_fanin(node); + int **inputs; + + if (st_lookup(table, (char *) node, &value)) return (int) value; + assert(node->type != PRIMARY_INPUT); + inputs = ALLOC(int *, 4); + for (i = 0; i < 4; i++) { + inputs[i] = ALLOC(int, n_inputs); + } + for (i = 0; i < n_inputs; i++) { + node_t *input = node_get_fanin(node, i); + inputs[ONE][i] = simulate_network_32_rec(network, table, input); + inputs[ZERO][i] = ~ inputs[ONE][i]; + inputs[TWO][i] = 0xffffffff; + } + result = simulate_node_32(node, inputs); + st_insert(table, (char *) node, (char *) result); + for (i = 0; i < 3; i++) + FREE(inputs[i]); + FREE(inputs); + return result; +} + +static int simulate_node_32(node, inputs) +node_t *node; +int **inputs; +{ + register int i, j; + node_t *fanin; + node_cube_t cube; + int num_cubes = node_num_cube(node); + int and_result; + int result = 0; + + for (i = 0; i < num_cubes; i++) { + and_result = 0xffffffff; + cube = node_get_cube(node, i); + foreach_fanin(node, j, fanin) { + int literal = node_get_literal(cube, j); + and_result &= inputs[literal][j]; + /* + switch (literal) { + case ZERO: + and_result &= inputs[1][j]; + break; + case ONE: + and_result &= inputs[0][j]; + break; + case TWO: + break; + default: + fail("bad literal"); + } + */ + } + result |= and_result; + } + return result; +} diff --git a/sis/sim/sim_int.h b/sis/sim/sim_int.h new file mode 100644 index 0000000..1ef4e1f --- /dev/null +++ b/sis/sim/sim_int.h @@ -0,0 +1,18 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/sim/sim_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#define SIM_SLOT simulation +#define GET_VALUE(node) ((int) node->SIM_SLOT) +#define SET_VALUE(node, value) (node->SIM_SLOT = (char *) value) + +extern void simulate_node(); +extern array_t *simulate_network(); +extern array_t *simulate_stg(); + +extern int sim_verify_codegen(); diff --git a/sis/simplify/Makefile.am b/sis/simplify/Makefile.am new file mode 100644 index 0000000..eef9975 --- /dev/null +++ b/sis/simplify/Makefile.am @@ -0,0 +1,9 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libsimplify.a +libsimplify_a_SOURCES = com_simp.c compute_dc.c dc_filter.c filter_util.c \ + simp.c simp_daemon.c simp_dc.c simp_image.c simp_sm.c simp_util.c \ + simp_int.h +pkginclude_HEADERS = simplify.h +dist_doc_DATA = simplify.doc diff --git a/sis/simplify/Makefile.in b/sis/simplify/Makefile.in new file mode 100644 index 0000000..3fcb15d --- /dev/null +++ b/sis/simplify/Makefile.in @@ -0,0 +1,424 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libsimplify_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/simplify +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libsimplify_a_AR = $(AR) $(ARFLAGS) +libsimplify_a_LIBADD = +am_libsimplify_a_OBJECTS = com_simp.$(OBJEXT) compute_dc.$(OBJEXT) \ + dc_filter.$(OBJEXT) filter_util.$(OBJEXT) simp.$(OBJEXT) \ + simp_daemon.$(OBJEXT) simp_dc.$(OBJEXT) simp_image.$(OBJEXT) \ + simp_sm.$(OBJEXT) simp_util.$(OBJEXT) +libsimplify_a_OBJECTS = $(am_libsimplify_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libsimplify_a_SOURCES) +DIST_SOURCES = $(libsimplify_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libsimplify.a +libsimplify_a_SOURCES = com_simp.c compute_dc.c dc_filter.c filter_util.c \ + simp.c simp_daemon.c simp_dc.c simp_image.c simp_sm.c simp_util.c \ + simp_int.h + +pkginclude_HEADERS = simplify.h +dist_doc_DATA = simplify.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/simplify/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/simplify/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libsimplify.a: $(libsimplify_a_OBJECTS) $(libsimplify_a_DEPENDENCIES) + -rm -f libsimplify.a + $(libsimplify_a_AR) libsimplify.a $(libsimplify_a_OBJECTS) $(libsimplify_a_LIBADD) + $(RANLIB) libsimplify.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/simplify/com_simp.c b/sis/simplify/com_simp.c new file mode 100644 index 0000000..83514e3 --- /dev/null +++ b/sis/simplify/com_simp.c @@ -0,0 +1,708 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/com_simp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#include <setjmp.h> +#include <signal.h> +#include "sis.h" +#include "simp_int.h" + +#define BDD_NODE_LIMIT 480000 +#define BDD_NODE_LOW 50000 + +int com_simplify(); +int com_simp(); +int com_full_simplify(); +st_table *find_node_level(); +static bool get_cone_levels(); +static void full_simplify_usage(); +static void simp_node_to_bdd(); +bool hsimp_debug; + +static jmp_buf timeout_env; +static void timeout_handle() +{ + longjmp(timeout_env, 1); +} + +init_simplify() +{ + simp_trace = FALSE; + simp_debug = FALSE; + + node_register_daemon(DAEMON_FREE, simp_free); + node_register_daemon(DAEMON_ALLOC, simp_alloc); + node_register_daemon(DAEMON_DUP, simp_dup); + node_register_daemon(DAEMON_INVALID, simp_invalid); + + com_add_command("simplify", com_simplify, 1); + com_add_command("_simp", com_simp, 1); + com_add_command("full_simplify", com_full_simplify, 0); +} + +end_simplify() +{ +} + +static void full_simplify_usage(command) +char *command; +{ + (void) fprintf(siserr, "usage: %s [-d]", command); + (void) fprintf(siserr, "[-o ordering] [-m method] [-l] "); + (void) fprintf(siserr, "[-t time] [-v]\n"); + (void) fprintf(siserr, " -o 0 \tordering type (uses depths: default) \n"); + (void) fprintf(siserr, " -o 1 \tordering type (uses levels) \n"); + (void) fprintf(siserr, " -d \tNo observability don't care set \n"); + (void) fprintf(siserr, " -l \trestricted don't care to preserve the level"); + (void) fprintf(siserr, "(default is a subset of fanin don't cares)\n"); + (void) fprintf(siserr, " -m snocomp\tSingle pass minimizer (default)\n"); + (void) fprintf(siserr, " -m nocomp\tMultiple pass minimizer\n"); + (void) fprintf(siserr, " -m dcsimp\tAnother single pass minimizer\n"); + (void) fprintf(siserr, " -v \tverbose (for debugging)\n"); +/* + (void) fprintf(siserr, " -t <num> \ttimeout mechanism \n"); +*/ +} + +static void simp_usage(command) +char *command; +{ + (void) fprintf(siserr, "usage: %s [-d]", command); + (void) fprintf(siserr, "[-i <num>[:<num>]] [-m method] [-f filter] "); + (void) fprintf(siserr, "[node-list]\n"); + (void) fprintf(siserr, " -d\tNo don't care set "); + (void) fprintf(siserr, " -l restricted don't care to preserve the level"); + (void) fprintf(siserr, "(default is a subset of the fanin don't cares)\n"); + (void) fprintf(siserr, " -i <num>[:<num>]\tGenerate fanin don't-care"); + (void) fprintf(siserr, " for nodes specified in cone\n"); + (void) fprintf(siserr, " -m snocomp\tSingle pass minimizer (default)\n"); + (void) fprintf(siserr, " -m nocomp\tMultiple pass minimizer\n"); + (void) fprintf(siserr, " -m dcsimp\tAnother single pass minimizer\n"); + (void) fprintf(siserr, " -f exact\tExact filter (default)\n"); + (void) fprintf(siserr, " -f disj_sup\tDisjoint support filter\n"); +} + +int +com_simplify(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, i; + array_t *nodevec; + node_t *np; + sim_accept_t accept; + sim_method_t method; + sim_dctype_t dctype; + sim_filter_t filter; + st_table *level_table; + extern int level_node_cmp2(); + + dctype = SIM_DCTYPE_SUB_FANIN; + accept = SIM_ACCEPT_FCT_LITS; + method = SIM_METHOD_SNOCOMP; + filter = SIM_FILTER_EXACT; + util_getopt_reset(); + simp_debug = FALSE; + simp_trace = FALSE; + simp_fanin_level = 1; + simp_fanin_fanout_level = 0; + while ((c = util_getopt(argc, argv, "m:i:f:tdl")) != EOF) { + switch (c) { + case 'l': + dctype = SIM_DCTYPE_LEVEL; + break; + case 'd': + dctype = SIM_DCTYPE_NONE; + break; + case 'm': + if (strcmp(util_optarg, "nocomp") == 0) { + method = SIM_METHOD_NOCOMP; + } else if (strcmp(util_optarg, "snocomp") == 0) { + method = SIM_METHOD_SNOCOMP; + } else if (strcmp(util_optarg, "dcsimp") == 0) { + method = SIM_METHOD_DCSIMP; + } else { + simp_usage(argv[0]); + return 1; + } + break; + case 'f': + if (strcmp(util_optarg, "exact") == 0) { + filter = SIM_FILTER_EXACT; + } else if (strcmp(util_optarg, "disj_sup") == 0) { + filter = SIM_FILTER_DISJ_SUPPORT; + } else { + simp_usage(argv[0]); + return 1; + } + break; + case 'i': + dctype = SIM_DCTYPE_FANIN; + if (!get_cone_levels(util_optarg, &simp_fanin_level, + &simp_fanin_fanout_level)) { + simp_usage(argv[0]); + return 1; + } + break; + case 't': + simp_trace = TRUE; + break; + default: + simp_usage(argv[0]); + return 1; + } + } + if(dctype == SIM_DCTYPE_LEVEL){ + level_table= find_node_level(*network); + } + + nodevec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + nodevec = simp_order(nodevec); + for(i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + if (np->type == INTERNAL) { + simplify_node(np, method, dctype, accept, filter, level_table); + } + } + if(dctype == SIM_DCTYPE_LEVEL){ + st_free_table(level_table); + } + array_free(nodevec); + return 0; +} + +int +com_simp(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, i; + array_t *nodevec; + node_t *np; + sim_method_t method; + sim_accept_t accept; + sim_dctype_t dctype; + sim_filter_t filter; + st_table *level_table; + level_table= NIL (st_table); + dctype = SIM_DCTYPE_FANIN; + accept = SIM_ACCEPT_FCT_LITS; + method = SIM_METHOD_SNOCOMP; + filter = SIM_FILTER_EXACT; + util_getopt_reset(); + simp_debug = FALSE; + simp_trace = FALSE; + simp_fanin_level = 1; + simp_fanin_fanout_level = 0; + while ((c = util_getopt(argc, argv, "a:d:m:i:o:f:Dt")) != EOF) { + switch (c) { + case 'a': + if (strcmp(util_optarg, "fct_lits") == 0) { + accept = SIM_ACCEPT_FCT_LITS; + } else if (strcmp(util_optarg, "sop_lits") == 0) { + accept = SIM_ACCEPT_SOP_LITS; + } else if (strcmp(util_optarg, "cubes") == 0) { + accept = SIM_ACCEPT_CUBES; + } else if (strcmp(util_optarg, "always") == 0) { + accept = SIM_ACCEPT_ALWAYS; + } else { + simp_usage(argv[0]); + return 1; + } + break; + case 'd': + if (strcmp(util_optarg, "none") == 0) { + dctype = SIM_DCTYPE_NONE; + } else if (strcmp(util_optarg, "fanin") == 0) { + dctype = SIM_DCTYPE_FANIN; + } else if (strcmp(util_optarg, "fanout") == 0) { + dctype = SIM_DCTYPE_FANOUT; + } else if (strcmp(util_optarg, "inout") == 0) { + dctype = SIM_DCTYPE_INOUT; + } else if (strcmp(util_optarg, "support") == 0) { + dctype = SIM_DCTYPE_SUB_FANIN; + } else if (strcmp(util_optarg, "all") == 0) { + dctype = SIM_DCTYPE_ALL; + } else { + simp_usage(argv[0]); + return 1; + } + break; + case 'm': + if (strcmp(util_optarg, "simpcomp") == 0) { + method = SIM_METHOD_SIMPCOMP; + } else if (strcmp(util_optarg, "espresso") == 0) { + method = SIM_METHOD_ESPRESSO; + } else if (strcmp(util_optarg, "exact") == 0) { + method = SIM_METHOD_EXACT; + } else if (strcmp(util_optarg, "min_lit") == 0) { + method = SIM_METHOD_EXACT_LITS; + } else if (strcmp(util_optarg, "dcsimp") == 0) { + method = SIM_METHOD_DCSIMP; + } else if (strcmp(util_optarg, "nocomp") == 0) { + method = SIM_METHOD_NOCOMP; + } else if (strcmp(util_optarg, "snocomp") == 0) { + method = SIM_METHOD_SNOCOMP; + } else { + simp_usage(argv[0]); + return 1; + } + break; + case 'f': + if (strcmp(util_optarg, "exact") == 0) { + filter = SIM_FILTER_EXACT; + } else if (strcmp(util_optarg, "disj_sup") == 0) { + filter = SIM_FILTER_DISJ_SUPPORT; + } else if (strcmp(util_optarg, "size") == 0) { + filter = SIM_FILTER_SIZE; + } else if (strcmp(util_optarg, "fdist") == 0) { + filter = SIM_FILTER_FDIST; + } else if (strcmp(util_optarg, "sdist") == 0) { + filter = SIM_FILTER_SDIST; + } else if (strcmp(util_optarg, "none") == 0) { + filter = SIM_FILTER_NONE; + } else if (strcmp(util_optarg, "all") == 0) { + filter = SIM_FILTER_ALL; + } else { + simp_usage(argv[0]); + return 1; + } + break; + case 'i': + simp_fanin_level = atoi(util_optarg); + switch (dctype) { + case SIM_DCTYPE_FANOUT: + dctype = SIM_DCTYPE_INOUT; + break; + case SIM_DCTYPE_INOUT: + case SIM_DCTYPE_ALL: + break; + default: + dctype = SIM_DCTYPE_FANIN; + } + break; + case 'o': + simp_fanin_fanout_level = atoi(util_optarg); + switch (dctype) { + case SIM_DCTYPE_FANOUT: + dctype = SIM_DCTYPE_INOUT; + break; + case SIM_DCTYPE_INOUT: + case SIM_DCTYPE_ALL: + break; + default: + dctype = SIM_DCTYPE_FANIN; + } + break; + case 't': + simp_trace = TRUE; + break; + case 'D': + simp_debug = TRUE; + break; + default: + simp_usage(argv[0]); + return 1; + } + } + + nodevec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + for(i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + if (np->type == INTERNAL) { + simplify_node(np, method, dctype, accept, filter, level_table); + } + } + array_free(nodevec); + return 0; +} + +static bool +get_cone_levels(name, par1, par2) +char *name; +int *par1, *par2; +{ + char *s, *str, *str1 = NIL(char), *str2 = NIL(char); + + /* Check for silly input */ + if (name == NIL(char) || strcmp(name, "") == 0) + return FALSE; + if (strchr(name, ' ') != NIL(char)) + return FALSE; + + /* Copy the input string (because we will tear it apart) */ + str = ALLOC(char, strlen(name)+1); + s = strcpy(str, name); + + if (s[0] != ':') str1 = s; + if ((s = strchr(s, ':')) != NIL(char)) { + *s++ = '\0'; + str2 = s; + } + + if (str1 != NIL(char)) + *par1 = atoi(str1); + if (str2 != NIL(char)) + *par2 = atoi(str2); + FREE(str); + return TRUE; +} + +st_table *find_node_level(network) +network_t *network; +{ + st_table *node_level_table; + array_t *nodevec; + int i,j; + node_t *np, *fanin; + int level,tmp; + char *dummy; + + node_level_table = st_init_table(st_ptrcmp, st_ptrhash); + nodevec= network_dfs(network); + for(i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + if (node_function(np) == NODE_PI) + continue; + level = 0; + foreach_fanin(np, j, fanin){ + if(st_lookup(node_level_table, (char *) fanin, &dummy)) + tmp= (int) dummy; + else + tmp= 0; + if (level < tmp) + level=tmp; + } + level++; + st_insert(node_level_table, (char *) np, (char *) level); + } + array_free(nodevec); + return(node_level_table); +} + + +int +com_full_simplify(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + st_table *leaves; + st_table *node_exdc_table; + array_t *po_list; + array_t *newlist; + array_t *odc_order_list, *network_node_list; + node_t *pi, *po, *node; + bdd_t *bdd, *temp_bdd; + lsGen gen; + bdd_manager *manager; + int x_ordering = 0; + int array_size; + extern int level_node_cmp2(); + int c,i,j; + sim_accept_t accept; + sim_method_t method; + sim_dctype_t dctype; + sim_filter_t filter; + st_table *level_table; + extern st_table *attach_dcnetwork_to_network(); + int timeout = 0; + st_generator *tablegen; + int max, index; + bdd_stats stats; + + dctype = SIM_DCTYPE_ALL; + accept = SIM_ACCEPT_FCT_LITS; + method = SIM_METHOD_SNOCOMP; + filter = SIM_FILTER_EXACT; + util_getopt_reset(); + hsimp_debug = FALSE; + simp_debug = FALSE; + simp_trace = FALSE; + simp_fanin_level = 1; + simp_fanin_fanout_level = 0; + while ((c = util_getopt(argc, argv, "f:o:m:t:vdl")) != EOF) { + switch (c) { + case 'o': + x_ordering = atoi(util_optarg); + break; + case 't': + timeout= atoi(util_optarg); + break; + case 'l': + filter = SIM_FILTER_LEVEL; + break; + case 'f': + if (strcmp(util_optarg, "level") == 0) { + filter = SIM_FILTER_LEVEL; + } else if (strcmp(util_optarg, "all") == 0) { + filter = SIM_FILTER_ALL; + } else { + full_simplify_usage(argv[0]); + return 1; + } + break; + case 'd': + dctype = SIM_DCTYPE_FANIN; + break; + case 'm': + if (strcmp(util_optarg, "nocomp") == 0) { + method = SIM_METHOD_NOCOMP; + } else if (strcmp(util_optarg, "snocomp") == 0) { + method = SIM_METHOD_SNOCOMP; + } else if (strcmp(util_optarg, "dcsimp") == 0) { + method = SIM_METHOD_DCSIMP; + } else { + return 1; + } + break; + case 'v': + hsimp_debug= TRUE; + break; + default: + full_simplify_usage(argv[0]); + return 1; + } + } + if (*network == NIL (network_t)) + return 0; + + if (timeout > 0) { + (void) signal(SIGALRM, timeout_handle); + (void) alarm((unsigned int) timeout); + if (setjmp(timeout_env) > 0) { + fprintf(sisout, "timeout occurred after %d seconds\n", timeout); + return 0; + } + } + + + if(filter == SIM_FILTER_LEVEL){ + level_table= find_node_level(*network); + } + po_list = array_alloc(node_t *, 0); + foreach_primary_output (*network, gen, po) { + array_insert_last(node_t *, po_list, po); + } + copy_dcnetwork(*network); + + node_exdc_table = attach_dcnetwork_to_network(*network); + foreach_primary_output (*network, gen, po) { + node = find_node_exdc(po, node_exdc_table); + array_insert_last(node_t *, po_list, node); + } + + + + newlist = NIL (array_t); + leaves = st_init_table(st_ptrcmp, st_ptrhash); + if (x_ordering){ + network_node_list= network_dfs_from_input(*network); + array_size= array_n(network_node_list); + odc_order_list= array_alloc(node_t *, 0); + for(i= 0; i< array_size; i++){ + node= array_fetch(node_t *, network_node_list, i); + odc_alloc(node); + ODC(node)->value= odc_value(node); + ODC(node)->order= i; + if (node_function(node) == NODE_PO) + continue; + array_insert_last(node_t *, odc_order_list, node); + } + (void) find_odc_level(*network); + array_sort(odc_order_list, level_node_cmp2); + for(i= 0, j = 0 ; i < array_n(odc_order_list) ; i++){ + node= array_fetch(node_t *, odc_order_list, i); + if (node_function(node) == NODE_PI){ + (void) st_insert(leaves, (char *) node, (char *) j++); + } + } + for(i= 0 ; i < array_n(network_node_list) ; i++){ + node= array_fetch(node_t *, network_node_list, i); + odc_free(node); + } + array_free(odc_order_list); + array_free(network_node_list); + }else{ + foreach_primary_input(*network, gen, pi) { + (void) st_insert(leaves, (char *) pi, (char *) -1); + } + newlist= order_dfs(po_list, leaves, 0); + array_free(newlist); + } + +/* Order all the PI's that cannot be reached from PO's*/ + max = 0; + st_foreach_item_int(leaves, tablegen, (char **) &pi, &index) { + if (index > max) { + max = index; + } + } + max++; + st_foreach_item_int(leaves, tablegen, (char **) &pi, &index) { + if (index < 0){ + index = max++; + (void) st_insert(leaves, (char *) pi, (char *) index); + } + } + + manager = ntbdd_start_manager(network_num_pi(*network)); + for(i= 0 ; i < array_n(po_list) ; i++){ + node= array_fetch(node_t *, po_list, i); + if (node_function(node) != NODE_PO) + node_free(node); + } + array_free(po_list); + +/*allocate space for CSPFs; Get the external don't cares for Primary Outputs*/ + newlist = network_dfs(*network); + + foreach_node(*network, gen,node){ + if (node_function(node) == NODE_PI) + continue; + cspf_alloc(node); + } + + bdd_get_stats(manager, &stats); + for(i = 0; i < array_n(newlist) ; i++){ + node = array_fetch(node_t *, newlist, i); + if (node_function(node) == NODE_PI) + continue; + if (stats.nodes.total > BDD_NODE_LOW){ + (void) simp_node_to_bdd(node, manager, leaves); + } else{ + (void) ntbdd_node_to_bdd(node, manager, leaves); + } + bdd_get_stats(manager, &stats); + if (stats.nodes.total > BDD_NODE_LIMIT){ + ntbdd_end_manager(manager); + fprintf(sisout, "The BDD's for this circuit have more than %d nodes.\n", BDD_NODE_LIMIT); + fprintf(sisout, "full_simplify is not performed. \n"); + return(0); + } + if (node_function(node) == NODE_PO){ + CSPF(node)->node= find_node_exdc(node, node_exdc_table); + temp_bdd = ntbdd_node_to_bdd(CSPF(node)->node, manager, leaves); + CSPF(node)->bdd = bdd_dup(temp_bdd); + continue; + } + } + array_free(newlist); + if (hsimp_debug) { + bdd_get_stats(manager, &stats); + fprintf(sisout, "total BDD nodes= %d \n", stats.nodes.total); + fprintf(sisout, "used BDD nodes= %d \n", stats.nodes.used); + foreach_primary_output(*network, gen, node){ + fprintf(sisout, "used BDD nodes for outputs = %d \n", bdd_size(ntbdd_at_node(node))); + } + } + foreach_node(*network, gen,node){ + if (node_function(node) == NODE_PI) + continue; + if (node_function(node) == NODE_PO) + continue; + if (node_num_fanout(node) == 0) + continue; + bdd = ntbdd_node_to_bdd(node, manager, leaves); + CSPF(node)->set= bdd_get_support(bdd); + } + + if (hsimp_debug) { + fprintf(sisout, "done"); + fflush(sisout); + } + + + if(dctype == SIM_DCTYPE_FANIN) { + simplify_without_odc(*network,accept,method,dctype,filter,level_table,manager,leaves); + }else{ + simplify_with_odc(*network,accept,method,dctype,filter,level_table,manager,leaves); + } + foreach_node(*network, gen,node){ + ntbdd_free_at_node(node); + if (node_function(node)!= NODE_PI){ + bdd_free(CSPF(node)->bdd); + if (CSPF(node)->list != NIL (array_t)) + array_free(CSPF(node)->list); + if (CSPF(node)->node != NIL (node_t)) + node_free(CSPF(node)->node); + if (CSPF(node)->set != NIL (var_set_t)) + var_set_free(CSPF(node)->set); + cspf_free(node); + } + } + + free_dcnetwork_copy(*network); + + ntbdd_end_manager(manager); + st_free_table(leaves); + if (node_exdc_table != NIL(st_table)) { + st_free_table(node_exdc_table); + } + if(filter == SIM_FILTER_LEVEL){ + st_free_table(level_table); + } + if (hsimp_debug) { + fprintf(sisout, "\n"); + } + if (timeout > 0) { + (void) alarm((unsigned int) INFINITY); + } + return 0; +} + +static void simp_node_to_bdd(node, manager, leaves) +node_t *node; +bdd_manager *manager; +st_table *leaves; +{ + bdd_t *bdd, *newbdd, *tmpbdd, *cube_bdd; + node_t *fanin; + int i,j,k; + pset last, setp; + bdd_stats stats; + + bdd = bdd_zero(manager); + + if (node_function(node) == NODE_PO){ + (void) ntbdd_node_to_bdd(node, manager, leaves); + return; + } + + foreach_set(node->F, last, setp) { + cube_bdd = bdd_one(manager); + for(k=0 ; k< node->nin; k++){ + if ((j= GETINPUT(setp,k)) == TWO) + continue; + if (j== ONE){ + fanin= node_get_fanin(node,k); + tmpbdd = ntbdd_node_to_bdd(fanin, manager, leaves); + newbdd = bdd_and(cube_bdd, tmpbdd, 1, 1); + }else{ + fanin= node_get_fanin(node,k); + tmpbdd = ntbdd_node_to_bdd(fanin, manager, leaves); + newbdd = bdd_and(cube_bdd, tmpbdd, 1, 0); + } + bdd_free(cube_bdd); + cube_bdd = newbdd; + bdd_get_stats(manager, &stats); + if (stats.nodes.total > BDD_NODE_LIMIT) + return; + } + newbdd = bdd_or(bdd, cube_bdd, 1, 1); + bdd_get_stats(manager, &stats); + if (stats.nodes.total > BDD_NODE_LIMIT) + return; + bdd_free(bdd); + bdd_free(cube_bdd); + bdd = newbdd; + } + ntbdd_set_at_node(node, bdd); +} diff --git a/sis/simplify/compute_dc.c b/sis/simplify/compute_dc.c new file mode 100644 index 0000000..3bee6b0 --- /dev/null +++ b/sis/simplify/compute_dc.c @@ -0,0 +1,752 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/compute_dc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#include "sis.h" +#include "simp_int.h" + +static double_node_t *compute_mspf(); +static node_t *compute_cspf(); +static st_table *cspf_inout_table(); +static node_t *cube_to_node(); +void simplify_without_odc(); +void simplify_with_odc(); +void cspf_alloc(); +void cspf_free(); +bdd_t *cspf_bdd_dc(); +static void update_cspf_of_fanins(); +void odc_alloc(); +void odc_free(); +int level_node_cmp1(); +int level_node_cmp2(); +int level_node_cmp3(); +void find_odc_level(); +int odc_value(); + +/* + * simplifies each node using the local don't cares and a subset of satisfiability don't cares + * generated for the nodes that have the same support as node being simplified. No observability + * don't care is computed, therefore, the local don't care is incomplete. + */ +void simplify_without_odc(network, accept, method, dctype, filter, level_table, mg, leaves) +network_t *network; +sim_accept_t accept; +sim_method_t method; +sim_dctype_t dctype; +sim_filter_t filter; +st_table *level_table; +bdd_manager *mg; +st_table *leaves; /*cutset of nodes in the network, used for BDD construction*/ +{ + array_t *network_node_list;/*an array of the nodes in the network*/ + int array_size; + int i, j; + array_t *fanout_list; + node_t *node, *fanout; + bdd_t *bdd, *newbdd; + + network_node_list= network_dfs_from_input(network); + array_size= array_n(network_node_list); + + for(i= 0; i< array_size; i++){ + node= array_fetch(node_t *, network_node_list, i); + if (node_function(node) == NODE_PI) + continue; + if (node_function(node) == NODE_PO) + continue; + if (node_num_fanin(node) == 0){ + CSPF(node)->bdd= bdd_zero(mg); + continue; + } + fanout_list= network_tfo(node, 1); + newbdd = bdd_one(mg); + for(j= 0; j < array_n(fanout_list) ; j++){ + fanout= array_fetch(node_t *, fanout_list, j); + bdd= bdd_and(CSPF(fanout)->bdd, newbdd, 1, 1); + bdd_free(newbdd); + newbdd= bdd; + } + array_free(fanout_list); + CSPF(node)->bdd = newbdd; + if (node->type== INTERNAL){ + simplify_cspf_node(node, method,dctype,accept,filter,level_table,mg,leaves); + } + } + array_free(network_node_list); +} +/* + * Computes compatible observability don't cares for each node. This is used later + * to find the local don't cares (don't cares in terms of fanins of each node). + * Also the satisfiability don't cares for a subset of nodes that can be + * substituted in the current node is generated. The don't cares are + * used to simplify the node using a two-level minimizer. + */ + +void simplify_with_odc(network, accept, method, dctype, filter, level_table, mg, leaves) +network_t *network; +sim_accept_t accept; +sim_method_t method; +sim_dctype_t dctype; +sim_filter_t filter; +st_table *level_table; +bdd_manager *mg; +st_table *leaves; /*cutset of nodes in the network, used for BDD construction*/ +{ + array_t *network_node_list;/*an array of the nodes in the network*/ + array_t *fanin_list, *fanout_list; + array_t *node_list, *dc_list; + int numin, array_size; + int i,j,k,m; + int index; + node_t *p, *q, *node, *fanout; + node_t *pfanin, *nd; + node_t *dcnode; + node_t *fanin; + node_t *pi; + double_node_t *mspf_node; + bdd_t *bdd, *dcbdd, *FDC; + node_t *ANDpi; /* ANDing of all the primary inputs*/ + st_table *tfotfi_table, *fis_table; + st_table *fofis_table; + lsGen gen; + + network_node_list= network_dfs_from_input(network); + array_size= array_n(network_node_list); + +/*create a new node by ANDing all the PIs. This is used for filtering*/ + ANDpi= node_constant(1); + foreach_primary_input(network, gen, pi){ + p= node_literal(pi, 1); + q= node_and(p, ANDpi); + node_free(p); + node_free(ANDpi); + ANDpi= q; + } +/*compute CSPF and simplify each node*/ + for(i= 0; i< array_size; i++){ + node= array_fetch(node_t *, network_node_list, i); + if (node_function(node) == NODE_PI) + continue; + if (node_function(node) == NODE_PO) + continue; + if (node_num_fanin(node) == 0){ + CSPF(node)->bdd= bdd_zero(mg); + continue; + } + fanout_list= network_tfo(node, 1); + + tfotfi_table= cspf_inout_table(node, INFINITY, 1); + node_list= network_tfi(node, 1); + fis_table = st_init_table(st_ptrcmp, st_ptrhash); + for(m= 0; m < array_n(node_list) ; m++){ + nd= array_fetch(node_t *, node_list, m); + (void) st_insert(fis_table, (char *)nd, NIL(char)); + } + + FDC= NIL (bdd_t); + +/* compute CSPF for each of the fanout edges; intersect them to + * find the CSPF for the node. + */ + for(j= 0; j < array_n(fanout_list) ; j++){ + fanout= array_fetch(node_t *, fanout_list, j); + if(node_function(fanout) == NODE_PO){ + dcnode= node_constant(0); + }else{ + index = node_get_fanin_index(fanout, node); + dc_list= CSPF(fanout)->list; + mspf_node = array_fetch(double_node_t *, dc_list, index); + dcnode= node_dup(mspf_node->pos); + dcnode= simp_obsdc_filter(dcnode, tfotfi_table, 0, ANDpi); + } + + if((node_function(fanout) != NODE_PO) || (node_num_fanout(fanout) > 0)){ + fanin_list= network_tfi(fanout, 1); + +/* make the mspf compatible with the cspf computed for previous edges. */ + fofis_table = st_init_table(st_ptrcmp, st_ptrhash); + for(m= 0; m < array_n(fanin_list) ; m++){ + nd= array_fetch(node_t *, fanin_list, m); + (void) st_insert(fofis_table, (char *)nd, NIL(char)); + } + for(k= 0 ; k < array_n(fanin_list); k++){ + pfanin= array_fetch(node_t *, fanin_list, k); + index = node_get_fanin_index(fanout, pfanin); + dc_list= CSPF(fanout)->list; + mspf_node = array_fetch(double_node_t *, dc_list, index); + if (node_function(pfanin) != NODE_PI) + dcnode= compute_cspf(dcnode, pfanin, mspf_node->neg, fis_table, + ANDpi, fofis_table); + } + st_free_table(fofis_table); + array_free(fanin_list); + } + +/* OR the computed CSPF with the CSPF of the fanout node.*/ + dcbdd= bdd_dup(ntbdd_node_to_bdd(dcnode, mg, leaves)); + if (CSPF(fanout)->bdd != NIL (bdd_t)){ + bdd = CSPF(fanout)->bdd; + bdd = bdd_or(bdd, dcbdd, 1, 1); + bdd_free(dcbdd); + dcbdd= bdd; + } + ntbdd_free_at_node(dcnode); + node_free(dcnode); + +/* Filter the CSPF and collapse all the nodes that are not transitive + * fanins of the node being simplified. + */ + +/* Do the intersection to find the CSPF of the node */ + if (FDC == NIL (bdd_t)) { + FDC= dcbdd; + }else{ + bdd= bdd_and(FDC, dcbdd, 1, 1); + bdd_free(dcbdd); + bdd_free(FDC); + FDC= bdd; + } + } + +/* store the CSPF */ + if (FDC != NIL (bdd_t)) { + CSPF(node)->bdd= FDC; + }else{ + CSPF(node)->bdd= bdd_zero(mg); + } + + st_free_table(tfotfi_table); + st_free_table(fis_table); + array_free(node_list); + array_free(fanout_list); + +/* simplify the node */ + if (node->type== INTERNAL){ + simplify_cspf_node(node, method,dctype,accept,filter,level_table,mg,leaves); + numin= node_num_fanin(node); + CSPF(node)->list= array_alloc(node_t *, 0); + dc_list = CSPF(node)->list ; + for(k=0 ; k < numin ; k++){ + fanin= node_get_fanin(node, k); + if ((node_function(fanin) == NODE_PI) || + ((numin > 15) && (numin * node_num_cube(node) >= 300))){ + mspf_node = ALLOC(double_node_t, 1); + mspf_node->pos = node_constant(0); + mspf_node->neg = node_constant(1); + }else{ + mspf_node = compute_mspf(node, fanin); + } + array_insert_last(double_node_t *, dc_list, mspf_node); + } + update_cspf_of_fanins(node, ANDpi, mg, leaves); + } + } + foreach_node(network, gen,node){ + if ((node->type== INTERNAL) && (node_num_fanin(node) != 0)){ + dc_list= CSPF(node)->list; + for(i=0 ; i < array_n(dc_list) ; i++){ + mspf_node = array_fetch(double_node_t *, dc_list, i); + node_free(mspf_node->pos); + node_free(mspf_node->neg); + FREE(mspf_node); + } + } + } + + +/* free the space allocated for CSPFs*/ + node_free(ANDpi); + array_free(network_node_list); +} + +/* + * Because of the use of subset support filter it is possible to add new fanins to a node. + * If the ODC for such fanins has been already computed, it is necessary to update that + * ODC. This updating is done here. + */ +static void update_cspf_of_fanins(node, ANDpi, mg, leaves) +node_t *node; +node_t *ANDpi; +bdd_manager *mg; +st_table *leaves; +{ + int numin, k, j, m; + node_t *fanin, *nd, *tmpnode; + double_node_t *mspf_node; + node_t *dcnode, *pfanin; + bdd_t *bdd, *dcbdd; + array_t *fanin_list, *node_list, *dc_list; + st_table *fofis_table, *fis_table; + + + numin= node_num_fanin(node); + dc_list = CSPF(node)->list ; + node_list= network_tfi(node, 1); + +/* make the mspf compatible with the cspf computed for previous edges. */ + fofis_table = st_init_table(st_ptrcmp, st_ptrhash); + for(m= 0; m < array_n(node_list) ; m++){ + nd= array_fetch(node_t *, node_list, m); + (void) st_insert(fofis_table, (char *)nd, NIL(char)); + } + array_free(node_list); + for(k = 0 ; k < numin ; k++){ + fanin= node_get_fanin(node, k); + if (node_function(fanin) == NODE_PI) + continue; + if ((CSPF(fanin)->bdd) == NIL (bdd_t)) + continue; + fanin_list= network_tfi(fanin, 1); + fis_table = st_init_table(st_ptrcmp, st_ptrhash); + for(m= 0; m < array_n(fanin_list) ; m++){ + tmpnode= array_fetch(node_t *, fanin_list, m); + (void) st_insert(fis_table, (char *)tmpnode, NIL(char)); + } + array_free(fanin_list); + mspf_node = array_fetch(double_node_t *, dc_list, k); + dcnode = node_dup(mspf_node->pos); + for(j= 0 ; j < k ; j++){ + pfanin= node_get_fanin(node, j); + mspf_node = array_fetch(double_node_t *, dc_list, j); + if (node_function(pfanin) != NODE_PI){ + dcnode= compute_cspf(dcnode, pfanin, mspf_node->neg, fis_table, + ANDpi, fofis_table); + } + } + dcbdd= bdd_dup(ntbdd_node_to_bdd(dcnode, mg, leaves)); + if (CSPF(node)->bdd != NIL (bdd_t)){ + bdd = CSPF(node)->bdd; + bdd = bdd_or(bdd, dcbdd, 1, 1); + bdd_free(dcbdd); + dcbdd= bdd; + } + ntbdd_free_at_node(dcnode); + node_free(dcnode); + bdd= bdd_and(CSPF(fanin)->bdd, dcbdd, 1, 1); + bdd_free(dcbdd); + bdd_free(CSPF(fanin)->bdd); + CSPF(fanin)->bdd= bdd; + st_free_table(fis_table); + } + st_free_table(fofis_table); +} + +/* + * allocate space for CSPFs. + */ +void +cspf_alloc(node) +node_t *node; +{ + node->OBS = (char *) ALLOC(cspf_type_t, 1); + CSPF(node)->level= 0; + CSPF(node)->node= NIL (node_t); + CSPF(node)->list= NIL (array_t); + CSPF(node)->bdd= NIL (bdd_t); + CSPF(node)->set= NIL (var_set_t); +} + + +/* free space allocated for CSPFs. + * + */ +void +cspf_free(node) +node_t *node; +{ + FREE(node->OBS); +} + + +/* compute maximum set of permissible functions for an edge. + * + */ +static double_node_t * +compute_mspf(node, fanin) +node_t *node; +node_t *fanin; +{ + node_t *f_x, *f_xbar, *h, *hbar; + node_t *p, *pnot, *node_cube, *tmpnode; + double_node_t *mspf_node; + int index; + pset last, setp; + + mspf_node = ALLOC(double_node_t, 1); + if ((node_function(node) == NODE_PO) || (node_function(fanin) == NODE_PI)){ + mspf_node->pos = node_constant(0); + mspf_node->neg = node_constant(1); + return(mspf_node); + } + f_x = node_constant(0); + f_xbar = node_constant(0); + h = node_constant(0); + index = node_get_fanin_index(node, fanin); + foreach_set(node->F, last, setp) { + node_cube = cube_to_node(node, setp, index); + if (GETINPUT(setp, index) == TWO){ + tmpnode = node_or(node_cube, h); + node_free(h); + node_free(node_cube); + h = tmpnode; + continue; + } + if (GETINPUT(setp, index) == ONE){ + tmpnode = node_or(node_cube, f_x); + node_free(f_x); + node_free(node_cube); + f_x = tmpnode; + continue; + } + assert(GETINPUT(setp, index) == ZERO); + tmpnode = node_or(node_cube, f_xbar); + node_free(f_xbar); + node_free(node_cube); + f_xbar = tmpnode; + } + p = node_xnor(f_x, f_xbar); + pnot = node_not(p); + mspf_node->pos = node_or(p, h); + hbar = node_not(h); + mspf_node->neg = node_and(pnot, hbar); + node_free(f_x); + node_free(f_xbar); + node_free(h); + node_free(hbar); + node_free(p); + node_free(pnot); + return(mspf_node); +} + +/* + * Generate a node representing the cube which is a part of f. + * If index is positive, also smooth that particular variable from + * the cube. +*/ +static node_t *cube_to_node(node, setp, index) +node_t *node; +pset setp; +int index; +{ + node_t *n1, *n2, *n3; + node_t *fanin; + int k, j; + + n1= node_constant(1); + for(k=0 ; k< node->nin; k++){ + if (k == index) + continue; + if ((j= GETINPUT(setp,k)) == TWO) + continue; + if (j== ONE){ + fanin= node_get_fanin(node,k); + n2= node_literal(fanin, 1); + n3= node_and(n1, n2); + node_free(n2); + node_free(n1); + n1 = n3; + continue; + } + assert(j== ZERO); + fanin= node_get_fanin(node,k); + n2= node_literal(fanin, 0); + n3= node_and(n1, n2); + node_free(n2); + node_free(n1); + n1 = n3; + } + return(n1); +} + + + + + + + + + + +/* Makes the don't care computed for an edge compatible with a previous + * edge. If the obs. don't care for current edge is D and for the previous + * edge DP, and the Boolean variable at the node that previous edge + * originates from is x, then we find Dx . Dx' + D . DP'. + */ +static node_t * +compute_cspf(DC, pfanin, bool_diff, fis_table, ANDpi, fofis_table) +node_t *DC; +node_t *pfanin; +node_t *bool_diff; +st_table *fis_table; /* used for filtering. */ +node_t *ANDpi; /* ANDing of the PIs used for filtering. */ +st_table *fofis_table; /* used for collapsing. */ +{ + node_t *q, *n0, *n1, *f0, *f1, *ndc; + bdd_t *bdd; + int l,numin; + node_t *dcfanin; + char *dummy; + + + if ((bdd= CSPF(pfanin)->bdd) == NIL(bdd_t)){ + return(DC); + } + + if (bdd_is_tautology(bdd, 0)){ + return(DC); + } + +/*finds Dx . Dx', given x is the previous fanin*/ + f0= node_literal(pfanin, 0); + f1= node_literal(pfanin, 1); + n0= node_cofactor(DC, f0); + n1= node_cofactor(DC, f1); + q= node_and(n0, n1); + + + node_free(n0); + node_free(n1); + node_free(f0); + node_free(f1); + + n0 = node_dup(bool_diff); + +/* filter DP before computing DP' . D. */ + if (node_num_fanin(n0) > 0){ + n0= simp_obsdc_filter(n0, fis_table, 3,ANDpi); + numin = node_num_fanin(n0); + for(l=0; l< numin; l++){ + dcfanin= node_get_fanin(n0, l); + if (!st_lookup(fis_table,(char *)dcfanin,&dummy)){ + if (node_function(dcfanin) != NODE_PI){ + if (st_lookup(fofis_table,(char *)dcfanin,&dummy)){ + (void)node_collapse(n0, dcfanin); + l--; + numin = node_num_fanin(n0); + } + } + } + } + } + n1= node_and(DC, n0); + node_free(n0); + + ndc= node_or(q, n1); + node_free(q); + node_free(n1); + node_free(DC); + return(ndc); +} + +/* Returns the CSPF for a node if it exists. + * + */ +bdd_t *cspf_bdd_dc(f, mg) +node_t *f; +bdd_manager *mg; +{ + bdd_t *p; + + if ((p= CSPF(f)->bdd) != NIL(bdd_t)){ + return(bdd_dup(p)); + }else{ + (void) fprintf(siserr, "cspf does not exist\n"); + return(bdd_zero(mg)); + } +} + + + + + +/* A table of transitive fanouts of transitive fanins of a node. + * + */ +static st_table * +cspf_inout_table(f, il, ol) +node_t *f; +int il, ol; +{ + st_table *finout_table; + array_t *fanin_list, *fanout_list; + node_t *fanin, *np; + int i, j; + + finout_table= st_init_table(st_ptrcmp, st_ptrhash); + fanin_list = network_tfi(f, il); + for (i = 0; i < array_n(fanin_list); i++) { + fanin = array_fetch(node_t *, fanin_list, i); + (void) st_insert(finout_table, (char *) fanin, NIL(char)); + fanout_list = network_tfo(fanin, ol); + for (j = 0; j < array_n(fanout_list); j++) { + np = array_fetch(node_t *, fanout_list, j); + (void) st_insert(finout_table, (char *) np, NIL(char)); + } + array_free(fanout_list); + } + array_free(fanin_list); + return(finout_table); +} + + +/* + * + */ +void odc_alloc(node) +node_t *node; +{ + node->OBS = (char *) ALLOC(odc_type_t, 1); + ODC(node)->order= 0; + ODC(node)->level= 0; + ODC(node)->value= 0; + ODC(node)->f= NIL (bdd_t); + ODC(node)->var= NIL (bdd_t); + ODC(node)->vodc = NIL (array_t); +} + + +/* + * + */ +void +odc_free(node) +node_t *node; +{ + FREE(node->OBS); +} + +void find_odc_level(network) +network_t *network; +{ + array_t *nodevec; + int i,j; + node_t *np, *fanin; + int level,tmp; + + nodevec= network_dfs(network); + for(i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + if (node_function(np) == NODE_PI){ + ODC(np)->level= 0; + continue; + } + level = 0; + foreach_fanin(np, j, fanin){ + tmp= ODC(fanin)->level; + if (level < tmp) + level=tmp; + } + level++; + ODC(np)->level = level ; + } + array_free(nodevec); +} + +int level_node_cmp1(obj1, obj2) +char **obj1; +char **obj2; +{ + node_t *node1, *node2; + + node1= *((node_t **)obj1); + node2= *((node_t **)obj2); + if (ODC(node1)->level > ODC(node2)->level) + return(-1); + if (ODC(node1)->level < ODC(node2)->level) + return(1); + + if (ODC(node1)->value > ODC(node2)->value) + return(-1); + if (ODC(node1)->value < ODC(node2)->value) + return(1); + + if (ODC(node1)->order > ODC(node2)->order) + return(-1); + if (ODC(node1)->order < ODC(node2)->order) + return(1); + return(0); +} + +int level_node_cmp2(obj1, obj2) +char **obj1; +char **obj2; +{ + node_t *node1, *node2; + + node1= *((node_t **)obj1); + node2= *((node_t **)obj2); + if (ODC(node1)->level > ODC(node2)->level) + return(-1); + if (ODC(node1)->level < ODC(node2)->level) + return(1); + + if (ODC(node1)->order > ODC(node2)->order) + return(-1); + if (ODC(node1)->order < ODC(node2)->order) + return(1); + return(0); +} +int level_node_cmp3(obj1, obj2) +char **obj1; +char **obj2; +{ + node_t *node1, *node2; + + node1= *((node_t **)obj1); + node2= *((node_t **)obj2); + if (ODC(node1)->level < ODC(node2)->level) + return(-1); + if (ODC(node1)->level > ODC(node2)->level) + return(1); + if (node_num_cube(node1) < node_num_cube(node2)) + return(-1); + if (node_num_cube(node1) > node_num_cube(node2)) + return(1); + + return(0); +} + +/* + * + */ +int odc_value(nodep) +node_t *nodep; +{ + node_t *np; + int value; + lsGen gen; + st_generator *sgen; + st_table *table; + + /* if all outputs of this nodes are primary output, its value is oo */ + value = INFINITY; + if (nodep->type == PRIMARY_OUTPUT) { + return value; + } + foreach_fanout(nodep, gen, np) { + if (np->type != PRIMARY_OUTPUT) { + value = 0; + } + } + if (value != 0) { + return value; + } + + /* compute the number of times the function is used */ + table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_fanout(nodep, gen, np) { + st_insert(table, (char *) np, NIL(char)); + } + st_foreach_item(table, sgen, (char **) &np, NIL(char *)) { + if (np->type != PRIMARY_OUTPUT) { + value += factor_num_used(np, nodep); + } + } + st_free_table(table); + return(value); +} diff --git a/sis/simplify/dc_filter.c b/sis/simplify/dc_filter.c new file mode 100644 index 0000000..3356ec4 --- /dev/null +++ b/sis/simplify/dc_filter.c @@ -0,0 +1,315 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/dc_filter.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#include "sis.h" +#include "simp_int.h" + +static void fobsdc_sm_bp_1(); +void node_d2merge(); +static void filter_exact(); +static void filter_disj_support(); +static void filter_size(); +static void filter_fdist(); +static void filter_sdist(); + +/* filter the dont care set according to the filter type indicated + */ +node_t * +simp_dc_filter(f, dc, filter) +node_t *f,*dc; +sim_filter_t filter; +{ + + sm_matrix *Mfdc; + node_t *new_dc; + + /* constant functions ignored for filtering */ + if (node_num_fanin(dc) == 0) { + return(dc); + } + + (void) node_d1merge(dc); + + /* create sparse matrix for function and its dont care */ + Mfdc = simp_node_to_sm(f, dc); + + if (simp_debug) { + simp_sm_print(Mfdc); + } + + switch (filter) { + case SIM_FILTER_EXACT : + (void) filter_exact(Mfdc); + break; + case SIM_FILTER_DISJ_SUPPORT : + (void) filter_exact(Mfdc); + (void) filter_disj_support(Mfdc); + break; + case SIM_FILTER_SIZE : + (void) filter_exact(Mfdc); + (void) filter_size(Mfdc); + break; + case SIM_FILTER_FDIST : + (void) filter_exact(Mfdc); + (void) filter_fdist(Mfdc, DIST_BOUND); + break; + case SIM_FILTER_SDIST : + (void) filter_exact(Mfdc); + (void) filter_sdist(Mfdc, DIST_BOUND); + break; + case SIM_FILTER_ALL : + (void) filter_exact(Mfdc); + (void) filter_disj_support(Mfdc); + (void) filter_size(Mfdc); + break; + case SIM_FILTER_NONE: + break; + default: + fail("Wrong filter type"); + exit(-1); + } + + if (simp_debug) { + simp_sm_print(Mfdc); + } + + new_dc = simp_sm_to_node(Mfdc); + node_free(dc); + sm_free(Mfdc); + + return(new_dc); +} + +/* attempt to find a partition (iteratively) of the form : + * + * xy- + * -yz + * + * where y is a single variable. + */ +static void +filter_exact(Mfdc) +sm_matrix *Mfdc; +{ + array_t *chosen; + sm_col *col; + + chosen = sm_col_count_init(sm_ncols(Mfdc)); + while ((col = sm_get_long_col(Mfdc, chosen)) != NULL) { + (void) fdc_sm_bp_1(Mfdc, col); + } +} + +static void +filter_disj_support(Mfdc) +sm_matrix *Mfdc; +{ + (void) fdc_sm_bp_2(Mfdc); +} + +static void +filter_size(Mfdc) +sm_matrix *Mfdc; +{ + (void) fdc_sm_bp_4(Mfdc); +} + +static void +filter_fdist(Mfdc, distance) +sm_matrix *Mfdc; +int distance; +{ + (void) fdc_sm_bp_6(Mfdc, distance); +} + +static void +filter_sdist(Mfdc, distance) +sm_matrix *Mfdc; +int distance; +{ + (void) fdc_sm_bp_7(Mfdc, distance); +} + +/* removes the cubes in the observability don't care set that are unlikely + * to be used for simplification. + */ +node_t * +simp_obsdc_filter(dc, node_table, var, nodepi) +node_t *dc; +st_table *node_table; /* a list of variables allowed in each cube. */ +int var; /* indicates how many variables that are not in the + * table are allowed in each cube. */ +node_t *nodepi; +{ + + sm_matrix *Mfdc; + node_t *new_dc; + node_t *n1, *n2, *n3; + st_generator *gen; + char *dummy; + node_t *np; + + /* if nothing to filter. */ + if (node_num_fanin(dc) == 0) { + return(dc); + } + + /* AND all the nodes in the table and all Primary Inputs. */ + n1= node_constant(1); + st_foreach_item(node_table, gen, &dummy, NIL(char *)) { + np = (node_t *) dummy; + n3= node_literal(np,1); + n2= node_and(n3, n1); + node_free(n1); + node_free(n3); + n1= n2; + } + n3= node_literal(nodepi,1); + n2= node_and(n3, n1); + node_free(n1); + node_free(n3); + n1= n2; + + + node_d2merge(dc); + if (node_num_fanin(dc) == 0) { + return(dc); + } + + + /* create sparse matrix for the AND function and its dont care */ + Mfdc = simp_node_to_sm(n1, dc); + + fobsdc_sm_bp_1(Mfdc, var); + + new_dc = simp_sm_to_node(Mfdc); + + node_free(dc); + node_free(n1); + sm_free(Mfdc); + return(new_dc); +} + + +/* remove any cube from observability don't care set that has more than + * "var" literals that are not in any cubes of the onset function. + */ +static void +fobsdc_sm_bp_1(M, var) +sm_matrix *M; +int var; +{ + sm_row *prow; + sm_col *pcol; + sm_element *p; + int i, init_rows; + + if (M->nrows == 0) + return; + + /* mark every row and column as unvisited */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) + prow->flag = 0; + for (pcol = M->first_col; pcol != NULL; pcol = pcol->next_col) + pcol->flag = 0; + + /* for each row in the on set mark the columns in them as visited */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) { + if (((int) prow->user_word) == F_SET) { + prow->flag = 1; + for (p = prow->first_col; p != NULL; p = p->next_col) { + pcol = sm_get_col(M, p->col_num); + pcol->flag = 1; + } + } + } + + for (prow = M->first_row; prow != NULL; prow = prow->next_row) { + if (!(((int) prow->user_word) == F_SET)) { + for (p = prow->first_col; p != NULL; p = p->next_col) { + pcol = sm_get_col(M, p->col_num); + if (!pcol->flag) + prow->flag++; + } + } + } + + + /* any unmarked rows can now be deleted => inessential dont cares */ + init_rows = M->rows_size; + if (simp_debug) + (void) fprintf(sisout, "rows deleted : "); + for (i = 0; i < init_rows; i ++) { + prow = sm_get_row(M, i); + if (prow != NULL){ + if (!(((int) prow->user_word) == F_SET)) { + if ( prow->flag > var) { + sm_delrow(M, i); + } + } + } + } +} + +node_t * +simp_obssatdc_filter(dc, f, var) +node_t *dc; /*obs. don't care to be filtered. */ +node_t *f; +int var; +{ + sm_matrix *Mfdc; + node_t *new_dc; + + /* if nothing to filter. */ + if (node_num_fanin(dc) == 0) { + return(dc); + } + + + /* create sparse matrix for the AND function and its dont care */ + Mfdc = simp_node_to_sm(f, dc); + + fobsdc_sm_bp_1(Mfdc, var); + + new_dc = simp_sm_to_node(Mfdc); + + node_free(dc); + sm_free(Mfdc); + return(new_dc); +} + + +/* repeated distance 1 merge + * + */ +void node_d2merge(f) +node_t *f; +{ + + int nin, i, lit_count; + int old_litcount; + + nin = node_num_fanin(f); + define_cube_size(nin); + + old_litcount = node_num_literal(f); + do { + lit_count = node_num_literal(f); + for (i=0; i< nin; i++){ + f->F = d1merge(f->F, i); + } + } while (lit_count > node_num_literal(f)); + + if (old_litcount > node_num_literal(f)) + node_scc(f); + + f->is_dup_free = 1; + f->is_scc_minimal = 1; + node_minimum_base(f); +} diff --git a/sis/simplify/filter_util.c b/sis/simplify/filter_util.c new file mode 100644 index 0000000..aa115ce --- /dev/null +++ b/sis/simplify/filter_util.c @@ -0,0 +1,471 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/filter_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#include "sis.h" +#include "simp_int.h" + +static void bd_comp_exact(); + +/* Three flags are used to mark rows and columns + * 0 - indicates not visited + * 1 - indicates visited and to be considered + * 2 - indicates visited but not to be considered + */ + +/* + * find a block decomposition of a sparse matrix - suitable only for + * dont care filtering (type 1). second parameter indicates which column to + * ignore in the decoposition - use NULL to supress. + */ +void +fdc_sm_bp_1(M, ex_col) +sm_matrix *M; +sm_col *ex_col; +{ + sm_row *prow; + sm_col *pcol; + int i, init_rows; + + if (M->nrows == 0) + return; + + /* mark dc set rows and all columns as unvisited */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) + if (((int) prow->user_word) == F_SET) + prow->flag = 1; + else + prow->flag = 0; + for (pcol = M->first_col; pcol != NULL; pcol = pcol->next_col) + pcol->flag = 0; + + /* call block decomposition recursively */ + (void) bd_comp_exact(M, ex_col); + + /* any unmarked rows can now be deleted => inessential dont cares */ + init_rows = M->rows_size; + if (simp_debug) { + (void) fprintf(sisout, "excluded column is %d\n", ex_col->col_num); + (void) fprintf(sisout, "rows deleted : "); + } + for (i = 0; i < init_rows; i ++) { + prow = sm_get_row(M, i); + if ((prow != NULL) && (prow->flag == 0)) { + if (simp_debug) { + (void) fprintf(sisout, "%d ", prow->row_num); + } + sm_delrow(M, i); + } + } + if (simp_debug) + (void) fprintf(sisout, "\n"); +} + +/* attempt to partition the sparse matrix for the exact filter recursively */ +static void +bd_comp_exact(M, ex_col) +sm_matrix *M; +sm_col *ex_col; +{ + + sm_row *prow; + sm_col *pcol; + sm_element *p; + bool new_found; + + new_found = FALSE; + + /* for all marked rows mark columns as visited */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) { + if (prow->flag == 1) { + prow->flag = 2; + for (p = prow->first_col; p != NULL; p = p->next_col) { + pcol = sm_get_col(M, p->col_num); + if ((pcol != ex_col) && (pcol->flag == 0)) { + new_found = TRUE; + pcol->flag = 1; + } + } + } + } + + if (!new_found) + return; /* no more to do */ + + new_found = FALSE; + + /* for each column marked as visited mark the rows in them as visited */ + for (pcol = M->first_col; pcol != NULL; pcol = pcol->next_col) { + if ((pcol != ex_col) && (pcol->flag == 1)) { + pcol->flag = 2; + for (p = pcol->first_row; p != NULL; p = p->next_row) { + prow = sm_get_row(M, p->row_num); + if (prow->flag == 0) { + new_found = TRUE; + prow->flag = 1; + } + } + } + } + + if (!new_found) + return; /* no more to do */ + else + (void) bd_comp_exact(M, ex_col); /* recurse */ +} + +/* + * heuristic filter - remove the dont care cubes that do not share any + * variables with the on set. this is an approximation and may delete + * dont cares that are useful in simplification. + */ +void +fdc_sm_bp_2(M) +sm_matrix *M; +{ + sm_row *prow; + sm_col *pcol; + sm_element *p; + int i, init_rows; + + if (M->nrows == 0) + return; + + /* mark every row and column as unvisited */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) + prow->flag = 0; + for (pcol = M->first_col; pcol != NULL; pcol = pcol->next_col) + pcol->flag = 0; + + /* for each row in the on set mark the columns in them as visited */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) { + if (((int) prow->user_word) == F_SET) { + prow->flag = 1; + for (p = prow->first_col; p != NULL; p = p->next_col) { + pcol = sm_get_col(M, p->col_num); + pcol->flag = 1; + } + } + } + + /* for each column visited mark the rows in them as visited */ + for (pcol = M->first_col; pcol != NULL; pcol = pcol->next_col) { + if (pcol->flag) { + for (p = pcol->first_row; p != NULL; p = p->next_row) { + prow = sm_get_row(M, p->row_num); + prow->flag = 1; + } + } + } + + /* any unmarked rows can now be deleted => inessential dont cares */ + init_rows = M->rows_size; + if (simp_debug) + (void) fprintf(sisout, "rows deleted : "); + for (i = 0; i < init_rows; i ++) { + prow = sm_get_row(M, i); + if ((prow != NULL) && (! prow->flag)) { + if (simp_debug) + (void) fprintf(sisout, "%d ", i); + sm_delrow(M, i); + } + } + if (simp_debug) + (void) fprintf(sisout, "\n"); +} + +/* + * heuristic filter - remove the smaller dont care cubes that have some part + * of their support outside the on set. this is an approximation and may delete + * dont cares that are useful in simplification. + */ +void +fdc_sm_bp_4(M) +sm_matrix *M; +{ + sm_row *prow; + sm_col *pcol; + sm_element *p; + int i, init_rows; + + if (M->nrows == 0) + return; + + /* mark every row and column as unvisited */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) + prow->flag = 0; + for (pcol = M->first_col; pcol != NULL; pcol = pcol->next_col) + pcol->flag = 0; + + /* for each row in the on set mark the columns in them as visited */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) { + if (((int) prow->user_word) == F_SET) { + for (p = prow->first_col; p != NULL; p = p->next_col) { + pcol = sm_get_col(M, p->col_num); + pcol->flag = 1; + } + } + } + + /* for each column unvisited, mark the rows in them as visited */ + for (pcol = M->first_col; pcol != NULL; pcol = pcol->next_col) { + if (!pcol->flag) { + for (p = pcol->first_row; p != NULL; p = p->next_row) { + prow = sm_get_row(M, p->row_num); + prow->flag = 1; + } + } + } + + /* unmark any rows with large dont care cubes */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) + if (prow->length <= SIZE_BOUND) + prow->flag = 0; + + /* any marked rows can now be deleted => inessential dont cares */ + init_rows = M->rows_size; + if (simp_debug) + (void) fprintf(sisout, "rows deleted : "); + for (i = 0; i < init_rows; i ++) { + prow = sm_get_row(M, i); + if ((prow != NULL) && (prow->flag)) { + if (simp_debug) + (void) fprintf(sisout, "%d ", i); + sm_delrow(M, i); + } + } + if (simp_debug) + (void) fprintf(sisout, "\n"); +} + +/* + * heuristic filter - remove the dont care cubes that have more than + * a certain distance from any cube in the on set + * this is an approximation and may delete dont cares that are useful + * in simplification. + */ +void +fdc_sm_bp_6(M, distance) +sm_matrix *M; +int distance; +{ + sm_row *prow; + sm_element *p; + sm_col *pcol; + int i, init_rows, cdist; + + if (M->nrows == 0) + return; + + /* mark every row of dc-set as unvisited. + * mark on set columns, unmark others */ + for (pcol = M->first_col; pcol != NULL; pcol = pcol->next_col) + pcol->flag = 0; + for (prow = M->first_row; prow != NULL; prow = prow->next_row) { + if ((int) (prow->user_word) == F_SET) { + prow->flag = 1; + for (p = prow->first_col; p != NULL; p = p->next_col) { + pcol = sm_get_col(M, p->col_num); + pcol->flag = 1; + } + } + else { + prow->flag = 0; + } + } + + /* for each dc set cube, mark as visited those cubes less than certain + * distance (only support outside on set is considered */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) { + if (((int) prow->user_word) == DC_SET) { + cdist = 0; + for (p = prow->first_col; p != NULL; p = p->next_col) { + pcol = sm_get_col(M, p->col_num); + if ((!pcol->flag) && (sm_get(int, p) != 2)) + cdist ++; + if (cdist > distance) + break; + } + if (cdist <= distance) + prow->flag = 1; /* less than distance bound */ + } + } + + /* any unmarked rows can now be deleted => inessential dont cares */ + init_rows = M->rows_size; + for (i = 0; i < init_rows; i ++) { + prow = sm_get_row(M, i); + if ((prow != NULL) && (!prow->flag)) { + sm_delrow(M, i); + } + } +} + +/* + * heuristic filter - remove the dont care cubes that have more than + * a certain distance from any cube in the on set + * this is an approximation and may delete dont cares that are useful + * in simplification. + */ +void +fdc_sm_bp_7(M, distance) +sm_matrix *M; +int distance; +{ + sm_row *prow, *pr; + sm_element *p; + sm_col *pcol; + int i, init_rows; + + if (M->nrows == 0) + return; + + /* mark every row of dc-set as unvisited. + mark on set columns, unmark others */ + for (pcol = M->first_col; pcol != NULL; pcol = pcol->next_col) + pcol->flag = 0; + for (prow = M->first_row; prow != NULL; prow = prow->next_row) { + if ((int) (prow->user_word) == F_SET) { + prow->flag = 1; + for (p = prow->first_col; p != NULL; p = p->next_col) { + pcol = sm_get_col(M, p->col_num); + pcol->flag = 1; + } + } + else { + prow->flag = 0; + } + } + + /* for each on set cube mark all dont care cubes less than max_distance + * as visited */ + for (prow = M->first_row; prow != NULL; prow = prow->next_row) { + if (((int) prow->user_word) == F_SET) { + for (pr= M->first_row; pr!= NULL; pr= pr->next_row) { + if (pr->flag) + continue; + if (((int) pr->user_word) != F_SET) { + if (dist_check(M, prow, pr, distance)) + pr->flag = 1; + } + } + } + } + + /* any unmarked rows can now be deleted => inessential dont cares */ + init_rows = M->rows_size; + for (i = 0; i < init_rows; i ++) { + prow = sm_get_row(M, i); + if ((prow != NULL) && (!prow->flag)) { + sm_delrow(M, i); + } + } +} + +array_t * +sm_col_count_init(size) +int size; +{ + + array_t *chosen; + int i; + + chosen = array_alloc(bool, size); + for (i = 0; i < size; i ++) + (void) array_insert(bool, chosen, i, FALSE); + return(chosen); +} + +sm_col * +sm_get_long_col(M, chosen) +sm_matrix *M; +array_t *chosen; +{ + + sm_col *col, *max; + + /* find the longest column not already chosen */ + max = NULL; + sm_foreach_col(M, col) { + if (array_fetch(bool, chosen, col->col_num) == TRUE) + continue; + else { + if ((max == NULL) || (col->length > max->length)) + max = col; + } + } + + if (max == NULL) { + array_free(chosen); + return(NULL); + } + else { + array_insert(bool, chosen, max->col_num, TRUE); + return(max); + } +} + +/* return true if distance between "p" and "r" is not greater than "distance" + * distance is measured a little differently than the standard definition + * (see espresso book for example). for the on set support distance is the + * same as the usual definition. for the variables outside the on set + * support, if the on set has a 2 and the dc set cube does not then + * distance is 1. of course if the on set cube has a 0 (1) and the dc set + * cube has a 1 (0) the distance is 1. + * "p" is an on set cube + * "r" is a dc set cube */ +bool +dist_check(M, p, r, distance) +sm_matrix *M; +sm_row *p, *r; +int distance; +{ + + sm_element *pele, *rele; + sm_col *pcol; + int cdist = 0; + int pval, rval; + + pele = p->first_col; + rele = r->first_col; + while ((pele != NULL) && (rele != NULL)) { + if (pele->col_num < rele->col_num) + pele = pele->next_col; + else if (pele->col_num > rele->col_num) { + pcol = sm_get_col(M, rele->col_num); + if (!pcol->flag && (sm_get(int, rele) != 2)) + cdist ++; + rele = rele->next_col; + } + else if (pele->col_num == rele->col_num) { + pcol = sm_get_col(M, pele->col_num); + pval = sm_get(int, pele); + rval = sm_get(int, rele); + if (pcol->flag == 1) { + if ((pval != 2) && (rval != 2) && (pval != rval)) + cdist ++; + } + else if ((rval != 2) && (pval != rval)) + cdist ++; + pele = pele->next_col; + rele = rele->next_col; + } + if (cdist > distance) + return(FALSE); + } + + /* distance for variables outside support of on set cube */ + while (rele != NULL) { + cdist ++; + if (cdist > distance) + return(FALSE); + rele = rele->next_col; + } + + return(TRUE); +} diff --git a/sis/simplify/simp.c b/sis/simplify/simp.c new file mode 100644 index 0000000..fbdd4a9 --- /dev/null +++ b/sis/simplify/simp.c @@ -0,0 +1,360 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/simp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#include "sis.h" +#include "simp_int.h" + +static void simp_accept(); +static node_t *local_dc(); +void simplify_cspf_node(); + +void +simplify_node(f, method, dctype, accept, filter, level_table) +node_t *f; +sim_method_t method; +sim_dctype_t dctype; +sim_accept_t accept; +sim_filter_t filter; +st_table *level_table; +{ + node_t *DC, *newf; + node_sim_type_t node_sim_type; + char buffer[80]; + + if (simp_trace) { + (void) fprintf(sisout, "%-6s ", node_name(f)); + (void) fprintf(sisout, "(%3d): ", factor_num_literal(f)); + (void) fflush(sisout); + } + + /* generate the don't care set */ + switch (dctype) { + case SIM_DCTYPE_NONE: + DC = node_constant(0); + break; + case SIM_DCTYPE_FANIN: + DC = simp_tfanin_dc(f, simp_fanin_level, simp_fanin_fanout_level); + break; + case SIM_DCTYPE_FANOUT: + DC = simp_fanout_dc(f); + break; + case SIM_DCTYPE_INOUT: + DC = simp_inout_dc(f, simp_fanin_level, simp_fanin_fanout_level); + break; + case SIM_DCTYPE_SUB_FANIN: + DC = simp_sub_fanin_dc(f); + break; + case SIM_DCTYPE_ALL: + DC = simp_all_dc(f); + break; + case SIM_DCTYPE_LEVEL: + DC = simp_level_dc(f,level_table); + break; + case SIM_DCTYPE_UNKNOWN: + default: + fail("Error: unknown dctype"); + /* NOTREACHED */ + } + + if (simp_trace) { + (void) sprintf(buffer, "DCb=(%d,%d,%d)", + node_num_fanin(DC), node_num_cube(DC), node_num_literal(DC)); + (void) fprintf(sisout, "%-24s", buffer); + (void) fflush(sisout); + } + if (simp_debug) { + (void) fprintf(sisout, "DC(%s) = ", node_name(f)); + node_print_rhs(sisout, DC); + (void) fprintf(sisout, "\n"); + (void) fflush(sisout); + } + + /* trim the don't-care set */ + DC = simp_dc_filter(f, DC, filter); + + if (simp_trace) { + (void) sprintf(buffer, "DCa=(%d,%d,%d)", + node_num_fanin(DC), node_num_cube(DC), node_num_literal(DC)); + (void) fprintf(sisout, "%-24s", buffer); + (void) fflush(sisout); + } + if (simp_debug) { + (void) fprintf(sisout, "simp_dc_filtered(%s) = ", node_name(f)); + node_print_rhs(sisout, DC); + (void) fprintf(sisout, "\n"); + (void) fflush(sisout); + } + + + /* minimize f */ + switch (method) { + case SIM_METHOD_SIMPCOMP: + node_sim_type = NODE_SIM_SIMPCOMP; + break; + case SIM_METHOD_ESPRESSO: + node_sim_type = NODE_SIM_ESPRESSO; + break; + case SIM_METHOD_EXACT: + node_sim_type = NODE_SIM_EXACT; + break; + case SIM_METHOD_EXACT_LITS: + node_sim_type = NODE_SIM_EXACT_LITS; + break; + case SIM_METHOD_DCSIMP: + node_sim_type = NODE_SIM_DCSIMP; + break; + case SIM_METHOD_NOCOMP: + node_sim_type = NODE_SIM_NOCOMP; + break; + case SIM_METHOD_SNOCOMP: + node_sim_type = NODE_SIM_SNOCOMP; + break; + case SIM_METHOD_UNKNOWN: + default: + fail("Error: unknown simplication method"); + /* NOTREACHED */ + } + + newf = node_simplify(f, DC, node_sim_type); + node_free(DC); + + /* accept ? */ + simp_accept(f, newf, accept); + + /* save update the sim_flag */ + SIM_FLAG(f)->method = method; + SIM_FLAG(f)->accept = accept; + SIM_FLAG(f)->dctype = dctype; +} + +static void +simp_accept(f, newf, accept) +node_t *f, *newf; +sim_accept_t accept; +{ + bool do_accept; + int old, new; + + do_accept = FALSE; + + switch (accept) { + case SIM_ACCEPT_FCT_LITS: + old = factor_num_literal(f); + new = factor_num_literal(newf); + break; + case SIM_ACCEPT_SOP_LITS: + old = node_num_literal(f); + new = node_num_literal(newf); + break; + case SIM_ACCEPT_CUBES: + old = node_num_cube(f); + new = node_num_cube(newf); + break; + case SIM_ACCEPT_ALWAYS: + old = factor_num_literal(f); + new = factor_num_literal(newf); + do_accept = TRUE; + break; + case SIM_ACCEPT_UNKNOWN: + default: + fail("Error: unknown acceptance criteria."); + exit(-1); + /* NOTREACHED */ + } + + if ((new == old) && (accept == SIM_ACCEPT_FCT_LITS)) { + old = node_num_literal(f); + new = node_num_literal(newf); + } + if (do_accept || new < old) { + if (simp_trace) { + (void) fprintf(sisout, "simplified ", node_name(f)); + (void) fprintf(sisout, "(%d)\n", new); + (void) fflush(sisout); + } + (void) node_replace(f, newf); + } else { + if (simp_trace) { + (void) fprintf(sisout, "not simplified\n", node_name(f)); + (void) fflush(sisout); + } + node_free(newf); + } +} + +void +simplify_cspf_node(f, method, dctype, accept, filter, level_table, mg, leaves) +node_t *f; +sim_method_t method; +sim_dctype_t dctype; +sim_accept_t accept; +sim_filter_t filter; +st_table *level_table; +bdd_manager *mg; +st_table *leaves; +{ + node_t *DC, *newf; + node_sim_type_t node_sim_type; + char buffer[80]; + + if (simp_trace) { + (void) fprintf(sisout, "%-6s ", node_name(f)); + (void) fprintf(sisout, "(%3d): ", factor_num_literal(f)); + (void) fflush(sisout); + } + DC = local_dc(f, mg, leaves, filter, level_table); + + if (simp_trace) { + (void) sprintf(buffer, "DCb=(%d,%d,%d)", + node_num_fanin(DC), node_num_cube(DC), node_num_literal(DC)); + (void) fprintf(sisout, "%-24s", buffer); + (void) fflush(sisout); + } + + if (filter != SIM_FILTER_NONE){ + DC = simp_obssatdc_filter(DC, f, 2); + if ((node_num_cube(DC) > 100) && (node_num_fanin(DC)> 20)) + DC = simp_obssatdc_filter(DC, f, 1); + if ((node_num_cube(DC) > 100) && (node_num_fanin(DC)> 20)) + DC = simp_obssatdc_filter(DC, f, 0); + } + + if (simp_trace) { + (void) sprintf(buffer, "DCa=(%d,%d,%d)", + node_num_fanin(DC), node_num_cube(DC), node_num_literal(DC)); + (void) fprintf(sisout, "%-24s", buffer); + (void) fflush(sisout); + } + + /* minimize f */ + switch (method) { + case SIM_METHOD_SIMPCOMP: + node_sim_type = NODE_SIM_SIMPCOMP; + break; + case SIM_METHOD_ESPRESSO: + node_sim_type = NODE_SIM_ESPRESSO; + break; + case SIM_METHOD_EXACT: + node_sim_type = NODE_SIM_EXACT; + break; + case SIM_METHOD_EXACT_LITS: + node_sim_type = NODE_SIM_EXACT_LITS; + break; + case SIM_METHOD_DCSIMP: + node_sim_type = NODE_SIM_DCSIMP; + break; + case SIM_METHOD_NOCOMP: + node_sim_type = NODE_SIM_NOCOMP; + break; + case SIM_METHOD_SNOCOMP: + node_sim_type = NODE_SIM_SNOCOMP; + break; + case SIM_METHOD_UNKNOWN: + default: + fail("Error: unknown simplication method"); + /* NOTREACHED */ + } + + newf = node_simplify(f, DC, node_sim_type); + if(hsimp_debug){ + fprintf(sisout, "."); + fflush(sisout); + } + + node_free(DC); + + /* accept ? */ + simp_accept(f, newf, accept); + + /* save update the sim_flag */ + SIM_FLAG(f)->method = method; + SIM_FLAG(f)->accept = accept; + SIM_FLAG(f)->dctype = dctype; +} + +static node_t *local_dc(f, mg, leaves, filter, level_table) +node_t *f; +bdd_manager *mg; +st_table *leaves; +sim_filter_t filter; +st_table *level_table; +{ + node_t *dc1, *careset, *node; + bdd_t *bdd; + array_t *bdd_list, *node_list; + int num_in, i; + node_t *DC; + node_t *ldc; + bdd_t *newbdd, *c, *cnot, *outbdd; + array_t *tfo_list; + int set_size_sort(); + + num_in= node_num_fanin(f); + if (filter == SIM_FILTER_LEVEL){ + dc1= simp_level_dc(f, level_table); + }else{ + dc1= simp_sub_fanin_dc(f); + } + + node_list= array_alloc(node_t *,0); + bdd_list= array_alloc(bdd_t *,0); + + + tfo_list= network_tfo(f, INFINITY); + newbdd= bdd_one(mg); + for(i=0 ; i< array_n(tfo_list); i++){ + node= array_fetch(node_t *, tfo_list, i); + if(node_function(node)== NODE_PO){ + outbdd= ntbdd_at_node(CSPF(node)->node) ; + bdd= bdd_and(newbdd, outbdd, 1, 1); + bdd_free(newbdd); + newbdd= bdd; + } + } + bdd = cspf_bdd_dc(f, mg); + c= bdd_or(bdd, newbdd, 1, 1); + bdd_free(bdd); + bdd_free(newbdd); + cnot = bdd_not(c); + bdd_free(c); + + for(i=0 ; i< num_in ; i++){ + node= node_get_fanin(f, i); + array_insert_last(node_t *, node_list, node); + } + array_sort(node_list, set_size_sort); + if( !bdd_is_tautology(cnot, 0)){ + for(i=0 ; i< num_in ; i++){ + node= array_fetch(node_t *, node_list, i); + bdd= ntbdd_at_node(node); + array_insert_last(bdd_t *, bdd_list, bdd_cofactor(bdd, cnot)); + } + + careset = simp_bull_cofactor(bdd_list, node_list, mg, leaves); + }else{ + careset= node_constant(0); + } + bdd_free(cnot); + array_free(tfo_list); + + if(hsimp_debug){ + fprintf(sisout, "1"); + fflush(sisout); + } + ldc = node_not(careset); + if(hsimp_debug){ + fprintf(sisout, "2"); + fflush(sisout); + } + node_free(careset); + DC= node_or(dc1, ldc); + node_free(dc1); + node_free(ldc); + return DC; +} diff --git a/sis/simplify/simp_daemon.c b/sis/simplify/simp_daemon.c new file mode 100644 index 0000000..7b5138d --- /dev/null +++ b/sis/simplify/simp_daemon.c @@ -0,0 +1,49 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/simp_daemon.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#include "sis.h" +#include "simp_int.h" + + +void +simp_free(f) +node_t *f; +{ + FREE(f->SIM_SLOT); +} + +void +simp_alloc(f) +node_t *f; +{ + f->SIM_SLOT = (char *) ALLOC(sim_flag_t, 1); + SIM_FLAG(f)->method = SIM_METHOD_UNKNOWN; + SIM_FLAG(f)->accept = SIM_ACCEPT_UNKNOWN; + SIM_FLAG(f)->dctype = SIM_DCTYPE_UNKNOWN; +} + + +void +simp_invalid(f) +node_t *f; +{ + SIM_FLAG(f)->method = SIM_METHOD_UNKNOWN; + SIM_FLAG(f)->accept = SIM_ACCEPT_UNKNOWN; + SIM_FLAG(f)->dctype = SIM_DCTYPE_UNKNOWN; +} + + +void +simp_dup(old, new) +node_t *old, *new; +{ + SIM_FLAG(new)->method = SIM_FLAG(old)->method; + SIM_FLAG(new)->accept = SIM_FLAG(old)->accept; + SIM_FLAG(new)->dctype = SIM_FLAG(old)->dctype; +} diff --git a/sis/simplify/simp_dc.c b/sis/simplify/simp_dc.c new file mode 100644 index 0000000..1ef21c3 --- /dev/null +++ b/sis/simplify/simp_dc.c @@ -0,0 +1,443 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/simp_dc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#include "sis.h" +#include "simp_int.h" + +int simp_fanin_level; +int simp_fanin_fanout_level; +bool simp_debug = FALSE; +bool simp_trace = FALSE; + +static st_table *simp_table(); +static array_t *simp_nodefanout_vec(); +static void nodefanout_print(); +static void fanout_table_print(); +static array_t *get_sub_list(); + + +typedef struct nodefanout_struct { + node_t *node; + node_t *fanout; +} nodefanout_t; + +node_t * +simp_DI(f) +node_t *f; +{ + node_t *DC, *flit; + + flit = node_literal(f, 1); + DC = node_xor(f, flit); + node_free(flit); + return DC; +} + +node_t * +unused_simp_fanin_dc(f) +node_t *f; +{ + st_table *table; + node_t *x, *DC, *x_xor_xlit, *DC_temp; + st_generator *gen; + char *dummy; + + /* build a table of "useful" nodes for generating the don't-care set */ + table = simp_table(f); + + /* for each node in the table, generate the don't care set */ + DC = node_constant(0); + st_foreach_item(table, gen, &dummy, NIL(char *)) { + x = (node_t *) dummy; + if (x != f) { + x_xor_xlit = simp_DI(x); + DC_temp = node_or(DC, x_xor_xlit); + node_free(DC); + node_free(x_xor_xlit); + DC = DC_temp; + } + } + + st_free_table(table); + return DC; +} + +static st_table * +simp_table(f) +node_t *f; +{ + array_t *nodefanout_vec, *temp; + node_t *fanin; + nodefanout_t curr, next; + st_table *table; + int i; + + /* put fanins of f and their fanins in the node-fanout array */ + nodefanout_vec = simp_nodefanout_vec(f); + foreach_fanin(f, i, fanin) { + temp = simp_nodefanout_vec(fanin); + array_append(nodefanout_vec, temp); + array_free(temp); + } + + /* sort the node-fanout array */ + array_sort(nodefanout_vec, node_compare_id); + if (simp_debug) { + nodefanout_print(nodefanout_vec); + } + + /* for each duplicated entry, put the fanout into a hash table */ + table = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 0; i < array_n(nodefanout_vec)-1; i++) { + curr = array_fetch(nodefanout_t, nodefanout_vec, i); + next = array_fetch(nodefanout_t, nodefanout_vec, i+1); + if (curr.node == next.node) { + (void) st_insert(table, (char *) curr.fanout, NIL(char)); + (void) st_insert(table, (char *) next.fanout, NIL(char)); + } + } + array_free(nodefanout_vec); + + if (simp_debug) { + fanout_table_print(table); + } + + return table; +} + +static array_t * +simp_nodefanout_vec(f) +node_t *f; +{ + nodefanout_t nodefanout; + array_t *nodefanout_vec; + node_t *fanin; + int i; + + nodefanout_vec = array_alloc(nodefanout_t, 0); + + foreach_fanin(f, i, fanin) { + nodefanout.node = fanin; + nodefanout.fanout = f; + array_insert_last(nodefanout_t, nodefanout_vec, nodefanout); + } + + return nodefanout_vec; +} + +static void +nodefanout_print(vec) +array_t *vec; +{ + int i; + nodefanout_t nf; + + (void) fprintf(sisout, "nodefanout_vec:\n"); + for (i = 0; i < array_n(vec); i++) { + nf = array_fetch(nodefanout_t, vec, i); + (void) fprintf(sisout, " %s->", node_name(nf.node)); + (void) fprintf(sisout, "%s", node_name(nf.fanout)); + } + (void) fprintf(sisout, "\n"); +} + +static +void +fanout_table_print(table) +st_table *table; +{ + char *dummy; + st_generator *gen; + node_t *x; + + (void) fprintf(sisout, "fanout_table:\n"); + st_foreach_item(table, gen, &dummy, NIL(char *)) { + x = (node_t *) dummy; + (void) fprintf(sisout, " %s", node_name(x)); + } + (void) fprintf(sisout, "\n\n"); +} + +node_t * +simp_fanout_dc(f) +node_t *f; +{ + lsGen gen; + node_t *DC, *fanout, *f0, *f1, *p, *q, *t1, *t2; + + DC = node_constant(1); + f1 = node_literal(f, 1); + f0 = node_literal(f, 0); + foreach_fanout(f, gen, fanout) { + + if (node_function(fanout) == NODE_PO) { + node_free(DC); + DC = node_constant(0); + (void) lsFinish(gen); + break; + } + + p = node_cofactor(fanout, f1); + q = node_cofactor(fanout, f0); + t1 = node_xnor(p, q); + t2 = node_and(DC, t1); + node_free(p); + node_free(q); + node_free(t1); + node_free(DC); + DC = t2; + + if (node_function(DC) == NODE_0) { + (void) lsFinish(gen); + break; + } + } + + node_free(f1); + node_free(f0); + + return DC; +} + +node_t * +simp_inout_dc(f, il, iol) +node_t *f; +int il, iol; +{ + node_t *DC, *faninDC, *fanoutDC; + + faninDC = simp_tfanin_dc(f, il, iol); + fanoutDC = simp_fanout_dc(f); + DC = node_or(faninDC, fanoutDC); + node_free(faninDC); + node_free(fanoutDC); + return DC; +} + +node_t * +simp_tfanin_dc(f, il, ol) +node_t *f; +int il, ol; +{ + st_table *f_fanout_table, *dc_table; + st_generator *gen; + array_t *f_fanout, *n_fanout, *f_fanin; + node_t *DC, *DC1, *DC_temp, *fanout, *fanin, *np; + int i, j; + char *dummy; + + /* build the transitive-fanout-cone table */ + f_fanout_table = st_init_table(st_ptrcmp, st_ptrhash); + f_fanout = network_tfo(f, INFINITY); + for (i = 0; i < array_n(f_fanout); i++) { + fanout = array_fetch(node_t *, f_fanout, i); + (void) st_insert(f_fanout_table, (char *) fanout, NIL(char)); + } + (void) st_insert(f_fanout_table, (char *) f, NIL(char)); + array_free(f_fanout); + + /* build transitive-fanin_cone table */ + dc_table = st_init_table(st_ptrcmp, st_ptrhash); + f_fanin = network_tfi(f, il); + for (i = 0; i < array_n(f_fanin); i++) { + fanin = array_fetch(node_t *, f_fanin, i); + (void) st_insert(dc_table, (char *) fanin, NIL(char)); + n_fanout = network_tfo(fanin, ol); + for (j = 0; j < array_n(n_fanout); j++) { + np = array_fetch(node_t *, n_fanout, j); + if (!st_lookup(f_fanout_table, (char *) np, &dummy)) { + (void) st_insert(dc_table, (char *) np, NIL(char)); + } + } + array_free(n_fanout); + } + array_free(f_fanin); + st_free_table(f_fanout_table); + + /* build the don't-care set for each node in the dc_table */ + DC = node_constant(0); + st_foreach_item(dc_table, gen, &dummy, NIL(char *)) { + np = (node_t *) dummy; + if (np->type == INTERNAL) { + DC1 = simp_DI(np); + DC_temp = node_or(DC, DC1); + node_free(DC1); + node_free(DC); + DC = DC_temp; + } + } + st_free_table(dc_table); + + return DC; +} + + +node_t * +simp_all_dc(f) +node_t *f; +{ + node_t *fanin_dc, *fanout_dc, *DC; + + fanin_dc = simp_tfanin_dc(f, INFINITY, INFINITY); + fanout_dc = simp_fanout_dc(f); + DC = node_or(fanin_dc, fanout_dc); + node_free(fanin_dc); + node_free(fanout_dc); + + return DC; +} + +node_t * +simp_sub_fanin_dc(f) +node_t *f; +{ + node_t *np, *DC, *DC1, *DC_temp; + array_t *dc_list; + int i,j; + int num_cube_cmp(); + + dc_list = get_sub_list(f); + + /* build the don't-care set for each node in the dc_table */ + DC = node_constant(0); + array_sort(dc_list, num_cube_cmp); + for (i = 0, j=0; i < array_n(dc_list); i ++) { + np = array_fetch(node_t *, dc_list, i); + if (node_num_literal(np) == 1) + continue; + if (node_num_cube(np) > 100) + continue; + if (node_num_cube(np) > 2 * node_num_cube(f)) + continue; + if ((node_num_fanin(f)> 15) && ((j * node_num_fanin(f))> 6000)){ + break; + } + if ((node_num_fanin(f)>= 50) && ((j * node_num_fanin(f))> 3000)){ + break; + } + if (np->type == INTERNAL) { + DC1 = simp_DI(np); + DC_temp = node_or(DC, DC1); + node_free(DC1); + node_free(DC); + DC = DC_temp; + j= node_num_literal(DC); + } + } + array_free(dc_list); + return DC; +} + +static array_t * +get_sub_list(f) +node_t *f; +{ + st_table *f_table, *sup_table; + array_t *f_fanin, *f_fanout, *nlist, *sup_list; + node_t *fanin, *fanout, *np; + bool same_sup; + int i, j; + char *dummy; + + /* get a list of the immediate fanin */ + f_table = st_init_table(st_ptrcmp, st_ptrhash); + f_fanin = network_tfi(f, 1); + nlist = array_alloc(node_t *, 0); + for (i = 0; i < array_n(f_fanin); i ++) { + fanin = array_fetch(node_t *, f_fanin, i); + if (!st_lookup(f_table, (char *) fanin, &dummy)) { + (void) array_insert_last(node_t *, nlist, fanin); + (void) st_insert(f_table, (char *) fanin, NIL(char)); + } + f_fanout = network_tfo(fanin, INFINITY); + for (j = 0; j < array_n(f_fanout); j ++) { + fanout = array_fetch(node_t *, f_fanout, j); + if (fanout->type != INTERNAL) + continue; + if (!st_lookup(f_table, (char *) fanout, &dummy)) { + (void) array_insert_last(node_t *, nlist, fanout); + (void) st_insert(f_table, (char *) fanout, NIL(char)); + } + } + array_free(f_fanout); + } + array_free(f_fanin); + st_free_table(f_table); + + /* retain all nodes with the same or subset support of f + * assumes minimum base for the network nodes + */ + sup_table = st_init_table(st_ptrcmp, st_ptrhash); + sup_list = array_alloc(node_t *, 0); + foreach_fanin(f, i, fanin) + (void) st_insert(sup_table, (char *) fanin, NIL(char)); + for (i = 0; i < array_n(nlist); i ++) { + np = array_fetch(node_t *, nlist, i); + if (np == f) + continue; + same_sup = TRUE; + foreach_fanin(np, j, fanin) { + if (!st_lookup(sup_table, (char *) fanin, &dummy)) { + same_sup = FALSE; + } + } + if (same_sup) { + (void) st_insert(sup_table, (char *) np, NIL(char)); + (void) array_insert_last(node_t *, sup_list, np); + } + } + st_free_table(sup_table); + array_free(nlist); + return(sup_list); +} + +node_t * +simp_level_dc(f, level_table) +node_t *f; +st_table *level_table; +{ + node_t *np, *DC, *DC1, *DC_temp; + array_t *dc_list; + int i,j; + int dlevel, flevel; + char *dummy; + + dc_list = get_sub_list(f); + if(st_lookup(level_table, (char *) f, &dummy)) + flevel= (int) dummy; + + /* build the don't-care set for each node in the dc_table */ + DC = node_constant(0); + for (i = 0, j=0; i < array_n(dc_list); i ++) { + np = array_fetch(node_t *, dc_list, i); + if (node_num_literal(np) == 1) + continue; + if (node_num_cube(np) > 100) + continue; + if (node_num_cube(np) > 2 * node_num_cube(f)) + continue; + if ((node_num_fanin(f)> 15) && ((j * node_num_fanin(f))> 6000)){ + break; + } + if (np->type == INTERNAL) { + if(st_lookup(level_table, (char *) np, &dummy)) + dlevel= (int) dummy; + if(dlevel < flevel){ + DC1 = simp_DI(np); + DC_temp = node_or(DC, DC1); + node_free(DC1); + node_free(DC); + DC = DC_temp; + j= node_num_literal(DC); + } + } + } + array_free(dc_list); + return DC; +} diff --git a/sis/simplify/simp_image.c b/sis/simplify/simp_image.c new file mode 100644 index 0000000..5885c00 --- /dev/null +++ b/sis/simplify/simp_image.c @@ -0,0 +1,404 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/simp_image.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#include "sis.h" +#include "simp_int.h" + +node_t *simp_bull_cofactor(); +static array_t *simp_disjoint_support_functions(); +static node_t *simp_range_2_compute(); +int set_size_sort(); + + +static void +simp_free_bddlist(bdd_list, node_list) +array_t *bdd_list; /* list of functions whose image to be computed */ +array_t *node_list; /* variables associated with each function */ +{ + int j; + bdd_t *bdd; + + for (j= 0 ; j< array_n(bdd_list); j++){ + bdd = array_fetch(bdd_t *,bdd_list,j); + if (bdd != NIL(bdd_t)) { + bdd_free(bdd); + } + } + array_free(bdd_list); + array_free(node_list); +} + + + + + +/* + * It finds the image of a set of Boolean functions and returns the + * image in sum-of-products form (node_t). + */ +node_t *simp_bull_cofactor(bdd_list, node_list, mg, leaves) +array_t *bdd_list; /* list of functions whose image to be computed */ +array_t *node_list; /* variables associated with each function */ +bdd_manager *mg; +st_table *leaves; /* not used here, for debugging purposes */ +{ + int i; + bdd_t *bdd; + bdd_t *c, *cbar; + node_t *image_node, *tmpnode; + array_t *sup_list; + array_t *left_list, *right_list; + array_t *left_node, *right_node; + node_t *node; + node_t *n1, *n2, *n3; + int flag, active; + array_t *f_list; + var_set_t *set; + int l, j, count; + unsigned list_not_free; + + count= 0; + active = 0; + flag = -1; + + /*The image is represented by image_node */ + image_node= node_constant(1); + +/* + * Check if a function is constant. Constant functions are removed from the list. + * AND an appropriate variable with image_node. + */ + for (i= 0 ; i< array_n(bdd_list); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + if (bdd == NIL(bdd_t)) + continue; + if (bdd_is_tautology(bdd, 1)){ + bdd_free(bdd); + array_insert(bdd_t *, bdd_list, i, NIL (bdd_t)); + n1= array_fetch(node_t *, node_list, i); + n2= node_literal(n1, 1); + n3= node_and(n2, image_node); + node_free(image_node); + node_free(n2); + image_node= n3; + continue; + } + if (bdd_is_tautology(bdd, 0)){ + bdd_free(bdd); + array_insert(bdd_t *, bdd_list, i, NIL (bdd_t)); + n1= array_fetch(node_t *, node_list, i); + n2= node_literal(n1, 0); + n3= node_and(n2, image_node); + node_free(image_node); + node_free(n2); + image_node= n3; + continue; + } + count++; + } + +/* If only one function left in the list return. */ + if (count <= 1){ + for (i= 0 ; i< array_n(bdd_list); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + if (bdd != NIL(bdd_t)) { + bdd_free(bdd); + break; /* because there is at most one */ + } + } + array_free(bdd_list); + array_free(node_list); + return(image_node); + } + + +/* Patition the functions into sets with disjoint support. */ + sup_list = array_alloc(var_set_t *, count); + flag= 1; + for (i= 0 ; i< array_n(bdd_list); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + if (bdd == NIL(bdd_t)) + continue; + set= bdd_get_support(bdd); + array_insert_last(var_set_t *, sup_list, set); + } + f_list= simp_disjoint_support_functions(sup_list); + + for (i= 0 ; i< array_n(sup_list); i++){ + set = array_fetch(var_set_t *,sup_list,i); + var_set_free(set); + } + array_free(sup_list); + +/* + * process each partition separately. If there is only function in a partition, then + * both phases of that function are reachable. If there are two functions, call + * a special routine for computing the range of two functions. Else, do output + * cofactoring with respect to the first function in the partition and call + * this routine again. + */ + + list_not_free = 1; + assert(array_n(f_list) >= 1); /* for loop should be executed at least once */ + tmpnode= node_constant(1); + for (i= 0 ; i< array_n(f_list); i++){ + set = array_fetch(var_set_t *,f_list,i); + active= var_set_n_elts(set); + if(active==1) + continue; + if(active==2){ + node= simp_range_2_compute(set, bdd_list, node_list); + n1 = node_and(tmpnode, node); + node_free(node); + node_free(tmpnode); + tmpnode= n1; + continue; + } + flag= -1; + right_list = array_alloc(bdd_t *, 0); + left_list = array_alloc(bdd_t *, 0); + right_node = array_alloc(node_t *, 0); + left_node = array_alloc(node_t *, 0); + for (j= 0,l=0;j< array_n(bdd_list);j++){ + bdd = array_fetch(bdd_t *,bdd_list,j); + if (bdd == NIL(bdd_t)) + continue; + if(var_set_get_elt(set,l)){ + n1= array_fetch(node_t *, node_list, j); + array_insert_last(node_t *, right_node, n1); + array_insert_last(node_t *, left_node, n1); + if(flag == -1){ + c = bdd; + flag= j; + cbar= bdd_not(c); + array_insert_last(bdd_t *, right_list, bdd_one(mg)); + array_insert_last(bdd_t *, left_list, bdd_zero(mg)); + }else{ + array_insert_last(bdd_t *, right_list, bdd_cofactor(bdd,c)); + array_insert_last(bdd_t *, left_list, bdd_cofactor(bdd,cbar)); + } + } + l++; + } + + if (flag != -1) { + bdd_free(cbar); + } + + if (i == (array_n(f_list) - 1)) { + /* won't be going through for loop again, so free BDDs now to save memory */ + simp_free_bddlist(bdd_list, node_list); + list_not_free = 0; + } + + n1= simp_bull_cofactor(right_list, right_node, mg, leaves); + n2= simp_bull_cofactor(left_list, left_node, mg, leaves); + + node= node_or(n1, n2); + node_free(n1); + node_free(n2); + n1= node_and(node, tmpnode); + node_free(node); + node_free(tmpnode); + tmpnode= n1; + } + + node= node_and(image_node, tmpnode); + node_free(image_node); + node_free(tmpnode); + + if (list_not_free){ + simp_free_bddlist(bdd_list, node_list); + } + + for (j= 0 ; j< array_n(f_list); j++){ + set = array_fetch(var_set_t *,f_list,j); + var_set_free(set); + } + array_free(f_list); + + + return(node); +} + + + +/* + * Finds groups of functions whose support is completely disjoint from the + * rest of the functions. + */ + +static array_t *simp_disjoint_support_functions(list) +array_t *list; +{ + int row,column; + int i,j; + int flag; + array_t *tmp; + var_set_t *set, *fset, *nset; + array_t *prtn_list; + + row= array_n(list); + tmp= array_alloc(var_set_t *, row); + for(i=0; i< row; i++){ + set= array_fetch(var_set_t *, list, i); + nset= var_set_copy(set); + array_insert(var_set_t *, tmp, i, nset); + } + set= array_fetch(var_set_t *, list, 0); + column= set->n_elts; + + for(i=0; i< column; i++){ + flag=1; + for(j=0; j< row; j++){ + set= array_fetch(var_set_t *, tmp, j); + if (set != NIL(var_set_t) ){ + if (flag){ + if (var_set_get_elt(set, i)){ + fset= set; + flag= 0; + continue; + } + } + if (var_set_get_elt(set, i)){ + fset= var_set_or(fset, fset, set); + var_set_free(set); + array_insert(var_set_t *, tmp, j, NIL(var_set_t )); + continue; + } + } + } + } + + prtn_list = array_alloc(var_set_t *, 0); + for(j=0; j< row; j++){ + set= array_fetch(var_set_t *, tmp, j); + if (set != NIL(var_set_t) ){ + nset= var_set_new(row); + for(i=0; i< row; i++){ + fset= array_fetch(var_set_t *, list, i); + if (var_set_intersect(set, fset)) + var_set_set_elt(nset, i); + } + var_set_free(set); + array_insert(var_set_t *, tmp, j, NIL(var_set_t )); + array_insert_last(var_set_t *, prtn_list, nset); + } + } + array_free(tmp); + return(prtn_list); +} + + + +/* special case of range computation for only two functions */ + +static node_t *simp_range_2_compute(set, bdd_list, node_list) +var_set_t *set; +array_t *bdd_list; +array_t *node_list; +{ + int i,j; + int k1,k2; + bdd_t *bdd, *f1, *f2, *out1, *out2, *f1_bar; + node_t *c1, *c2, *g; + node_t *n1, *n2; + node_t *n3, *n4; + + k1= -1; + for(i=0,j=0; i< array_n(bdd_list); i++){ + bdd = array_fetch(bdd_t *,bdd_list,i); + if(bdd == NIL(bdd_t)) + continue; + if(!var_set_get_elt(set, j++)) + continue; + if(k1 == -1){ + k1=i; + f1= bdd; + }else{ + k2=i; + f2= bdd; + break; + } + } + n1= array_fetch(node_t *, node_list, k1); + n2= array_fetch(node_t *, node_list, k2); + f1_bar= bdd_not(f1); + out1= bdd_cofactor(f2, f1); + out2= bdd_cofactor(f2, f1_bar); + bdd_free(f1_bar); + if (bdd_is_tautology(out1, 1)){ + n3= node_literal(n1, 1); + n4= node_literal(n2, 1); + c1= node_and(n3,n4); + node_free(n3); + node_free(n4); + }else if (bdd_is_tautology(out1, 0)){ + n3= node_literal(n1, 1); + n4= node_literal(n2, 0); + c1= node_and(n3,n4); + node_free(n3); + node_free(n4); + }else + c1= node_literal(n1, 1); + + if (bdd_is_tautology(out2, 1)){ + n3= node_literal(n1, 0); + n4= node_literal(n2, 1); + c2= node_and(n3,n4); + node_free(n3); + node_free(n4); + }else if (bdd_is_tautology(out2, 0)){ + n3= node_literal(n1, 0); + n4= node_literal(n2, 0); + c2= node_and(n3,n4); + node_free(n3); + node_free(n4); + }else{ + c2= node_literal(n1, 0); + } + + g= node_or(c1, c2); + node_free(c1); + node_free(c2); + bdd_free(out1); + bdd_free(out2); + return(g); +} + + +/* sort sets based on the number of bits that are set to 1. */ + +int set_size_sort(obj1, obj2) +char **obj1; +char **obj2; +{ + node_t *node1, *node2; + int el1, el2; + + node1= *((node_t **)obj1); + node2= *((node_t **)obj2); + +/* The following two lines were added to make this function correctly on VMS */ + if (node_function(node1) == NODE_PI && node_function(node2) == NODE_PI) + return 0; + + if (node_function(node1) == NODE_PI) + return(-1); + if (node_function(node2) == NODE_PI) + return(1); + el1= var_set_n_elts(CSPF(node1)->set); + el2= var_set_n_elts(CSPF(node2)->set); + if (el1 < el2) + return(-1); + if (el1 > el2) + return(1); + return(0); +} + diff --git a/sis/simplify/simp_int.h b/sis/simplify/simp_int.h new file mode 100644 index 0000000..8355cc9 --- /dev/null +++ b/sis/simplify/simp_int.h @@ -0,0 +1,126 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/simp_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +typedef struct sim_flag_struct { + sim_method_t method; + sim_accept_t accept; + sim_dctype_t dctype; +} sim_flag_t; + +#define SIM_SLOT simplify +#define SIM_FLAG(node) ((sim_flag_t *) ((node)->SIM_SLOT)) + +typedef struct cspf_struct{ + node_t *node; + int level; + int order; + array_t *list; + bdd_t *bdd; + var_set_t *set; +} cspf_type_t; + +typedef struct odc_struct{ + bdd_t *f; + bdd_t *var; + array_t *vodc; + int order; + int level; + int value; + int po; +} odc_type_t; + +typedef struct double_node_struct{ + node_t *pos; + node_t *neg; +} double_node_t; + +#define OBS cspf +#define CSPF(node) ((cspf_type_t *) (node)->OBS) +#define ODC(node) ((odc_type_t *) (node)->OBS) + +/* constants for filtering */ +#define F_SET 1 +#define DC_SET 2 +#define SIZE_BOUND 3 +#define DIST_BOUND 2 +#define sm_ncols(M) M->ncols + +/* simp_dc.c */ +extern int simp_fanin_level; +extern int simp_fanin_fanout_level; +extern bool simp_debug; +extern bool simp_trace; +extern bool hsimp_debug; + +/* simp_dc.c */ +extern node_t *simp_all_dc(); +extern node_t *simp_tfanin_dc(); +extern node_t *simp_fanout_dc(); +extern node_t *simp_inout_dc(); +extern node_t *simp_sub_fanin_dc(); +extern node_t *simp_sub_x(); +extern node_t *simp_level_dc(); + +/* filter.c */ +extern node_t *simp_dc_filter(); + +/* simp_daemon.c */ +extern void simp_alloc(); +extern void simp_free(); +extern void simp_invalid(); +extern void simp_dup(); + +/* filter_util.c */ +extern void fdc_sm_bp_1(); +extern void fdc_sm_bp_2(); +extern void fdc_sm_bp_4(); +extern void fdc_sm_bp_6(); +extern void fdc_sm_bp_7(); +extern array_t *sm_col_count_init(); +extern sm_col *sm_get_long_col(); + +/* simp_sm.c */ +extern sm_matrix *simp_node_to_sm(); +extern node_t *simp_sm_to_node(); +extern void simp_sm_print(); + +/* simp_order.c */ +extern array_t *simp_order(); + +/* compute_dc.c */ +extern void simplify_with_odc(); +extern void simplify_without_odc(); +extern bdd_t *cspf_bdd_dc(); +extern int odc_value(); +extern void find_odc_level(); +extern void cspf_alloc(); +extern void cspf_free(); +extern void odc_alloc(); +extern void odc_free(); +extern int level_node_cmp1(); +extern int level_node_cmp2(); +extern int level_node_cmp3(); + +/* simp_util.c */ +extern void copy_dcnetwork(); +extern node_t *find_node_exdc(); +extern void free_dcnetwork_copy(); +extern array_t *order_nodes_elim(); +extern int num_cube_cmp(); +extern int fsize_cmp(); + +/* simp_image.c */ +extern node_t *simp_bull_cofactor(); +extern int set_size_sort(); + +/* simp.c */ +extern void simplify_cspf_node(); + +/* com_simp.c */ +extern st_table *find_node_level(); diff --git a/sis/simplify/simp_sm.c b/sis/simplify/simp_sm.c new file mode 100644 index 0000000..01caee4 --- /dev/null +++ b/sis/simplify/simp_sm.c @@ -0,0 +1,231 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/simp_sm.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +/* + * routines to convert node to/from sm + * exports: simp_node_to_sm(); + * simp_sm_to_node(); + */ + +#include "sis.h" +#include "simp_int.h" + +static int get_fcol_sm(); + +/* + * create a single sparse matrix for the on set and dont care set. + * note that all fanin of f occur in columns before variables not + * used by f in the matrix created. + */ +sm_matrix * +simp_node_to_sm(f, dc) +node_t *f, *dc; +{ + sm_matrix *M; + st_table *table; + sm_element *element; + sm_row *row; + sm_col *column; + node_cube_t cube; + node_literal_t literal; + node_t *fanin; + int i, j, col_num; + int f_numrows, dc_numrows; + + M = sm_alloc(); + table = st_init_table(st_ptrcmp, st_ptrhash); + + /* create elements first for the on set f */ + f_numrows = node_num_cube(f); + for(i = 0; i < f_numrows; i++) { + cube = node_get_cube(f, i); + foreach_fanin(f, j, fanin) { + literal = node_get_literal(cube, j); + switch (literal) { + case ZERO: + case ONE: + (void) st_insert(table, (char *) fanin, (char *) j); + element = sm_insert(M, i, j); + if (literal == ZERO) + sm_put(element, 0); + else + sm_put(element, 1); + column = sm_get_col(M, j); + sm_put(column, fanin); + break; + case TWO: + break; + default: + fail("bad literal"); + } + } + row = sm_get_row(M, i); + sm_put(row, F_SET); + } + + /* create elements for the dont care set dc. variables common to the + * on set must be inserted in the same column as their occurrence in the + * on set */ + dc_numrows = node_num_cube(dc); + for(i = 0; i < dc_numrows; i++) { + cube = node_get_cube(dc, i); + foreach_fanin(dc, j, fanin) { + literal = node_get_literal(cube, j); + switch (literal) { + case ZERO: + case ONE: + col_num = get_fcol_sm(table, M, fanin); + element = sm_insert(M, (i + f_numrows), col_num); + column = sm_get_col(M, col_num); + if (literal == ZERO) + sm_put(element, 0); + else + sm_put(element, 1); + sm_put(column, fanin); + break; + case TWO: + break; + default: + fail("bad literal"); + /* NOTREACHED */ + } + } + row = sm_get_row(M, (i + f_numrows)); + sm_put(row, DC_SET); + } + (void) st_free_table(table); + return M; +} + +/* return the column number where a variable occurs in the matrix. return the + * next unused column number if the variable is absent */ +static int +get_fcol_sm(table, M, np) +st_table *table; +sm_matrix *M; +node_t *np; +{ + char *dummy; + + if (st_lookup(table, (char *) np, &dummy)) { + return((int) dummy); + } + else { + (void) st_insert(table, (char *) np, (char *) sm_ncols(M)); + return(sm_ncols(M)); + } +} + +void +simp_sm_print(M) +sm_matrix *M; +{ + sm_row *row; + sm_col *col; + sm_element *element; + int i, j; + + (void) fprintf(sisout, "\n "); + sm_foreach_col(M, col) { + (void) fprintf(sisout, "%3s", node_name(sm_get(node_t *, col))); + } + (void) fprintf(sisout, "\n"); + + for (i = 0; i < M->rows_size; i++) { + row = sm_get_row(M, i); + if (row == NULL) + continue; + (void) fprintf(sisout," %c ",(sm_get(int, row) == F_SET)?'f':'d'); + for (j = 0; j < M->cols_size; j++) { + if (sm_get_col(M, j) == NULL) + continue; + element = sm_find(M, i, j); + if (element == NIL(sm_element)) { + (void) fprintf(sisout, " ."); + } + else { + switch (sm_get(int, element)) { + case 0: + (void) fprintf(sisout, " 0"); + break; + case 1: + (void) fprintf(sisout, " 1"); + break; + default: + fail("bad sm_element_data"); + } + } + } + (void) fprintf(sisout, "\n"); + } +} + +/* + * map the dont care part of a sparse-matrix representation of a Mtion + * and its dont care back into a dont care node + */ +node_t * +simp_sm_to_node(M) +sm_matrix *M; +{ + int i, nin, init_rows, val; + node_t *node, *fanin_node, **fanin; + pset setp; + pset_family F; + sm_col *pcol; + sm_row *prow; + sm_element *p; + + /* delete all rows of the on set from the matrix */ + init_rows = M->rows_size; + for (i = 0; i < init_rows; i ++) { + prow = sm_get_row(M, i); + if ((prow != NULL) && (sm_get(int, prow) == F_SET)) + sm_delrow(M, i); + } + + /* + * Determine the fanin points; + * set pcol->flag to be the column number in the set family + */ + node = node_alloc(); + nin = 0; + fanin = ALLOC(node_t *, 2*M->ncols); /* worst case */ + sm_foreach_col(M, pcol) { + if (pcol->length == 0) + continue; + fanin_node = sm_get(node_t *, pcol); + pcol->flag = nin; + fanin[nin++] = fanin_node; + } + + /* Create the set family */ + F = sf_new(M->nrows, nin * 2); + sm_foreach_row(M, prow) { + setp = GETSET(F, F->count++); + (void) set_fill(setp, nin * 2); + sm_foreach_row_element(prow, p) { + i = sm_get_col(M, p->col_num)->flag; + val = sm_get(int, p); + switch (val) { + case 0 : + PUTINPUT(setp, i, ZERO); + break; + case 1 : + PUTINPUT(setp, i, ONE); + break; + default : + fail("bad sm_element_data"); + } + } + } + + node_replace_internal(node, fanin, nin, F); + return(node); +} diff --git a/sis/simplify/simp_util.c b/sis/simplify/simp_util.c new file mode 100644 index 0000000..9ccd45c --- /dev/null +++ b/sis/simplify/simp_util.c @@ -0,0 +1,259 @@ +#include "sis.h" +#include "simp_int.h" + +void copy_dcnetwork(); +node_t *find_node_exdc(); +void free_dcnetwork_copy(); +array_t *order_nodes_elim(); +int num_cube_cmp(); +static int level_elim_cmp(); +int fsize_cmp(); + +typedef struct node_fsize_t_defn { + node_t *node; + int fsize; +} node_fsize_t; + + +void copy_dcnetwork(network) +network_t *network; +{ + node_t *node, *dcnode, *dcfanin; + node_t *n1, *n2, *n3, *n4; + node_t *tempnode; + int i,j,k; + pset last, setp; + network_t *DC_network; + array_t *dc_list; + + if(network == NULL) { + return; + } + DC_network = network_dc_network(network); + if(DC_network == NULL) { + return; + } + dc_list= network_dfs(DC_network); + for(i=0 ; i< array_n(dc_list); i++){ + dcnode = array_fetch(node_t *, dc_list, i); + (void) cspf_alloc(dcnode); + if (node_function(dcnode) == NODE_PI){ + for(j=0 ; j< network_num_pi(network); j++){ + node= network_get_pi(network, j); + if (strcmp(dcnode->name, node->name) == 0){ + CSPF(dcnode)->node = node; + break; + } + } + continue; + } + if (node_function(dcnode) == NODE_PO){ + dcfanin= node_get_fanin(dcnode, 0); + CSPF(dcnode)->node= CSPF(dcfanin)->node; + continue; + } + + n3= node_constant(0); + foreach_set(dcnode->F, last, setp) { + n1= node_constant(1); + for(k=0 ; k< dcnode->nin; k++){ + if ((j= GETINPUT(setp,k))!= TWO){ + if (j== ONE){ + dcfanin= node_get_fanin(dcnode,k); + tempnode= CSPF(dcfanin)->node; + n4= node_literal(tempnode,1); + n2= node_and(n1, n4); + node_free(n4); + node_free(n1); + n1= n2; + }else{ + dcfanin= node_get_fanin(dcnode,k); + tempnode= CSPF(dcfanin)->node; + n4= node_literal(tempnode,0); + n2= node_and(n1, n4); + node_free(n4); + node_free(n1); + n1= n2; + } + } + } + n2= node_or(n1,n3); + node_free(n1); + node_free(n3); + n3= n2; + } + CSPF(dcnode)->node = n3; + } + array_free(dc_list); + return; +} + +node_t *find_node_exdc(ponode, node_exdc_table) +node_t *ponode; /*primary output of the care network*/ +st_table *node_exdc_table; + +{ + node_t *dcponode; + char *dummy; + +/* find the corresponding PO in the don't care network from the hash table*/ + if (node_exdc_table == NIL(st_table)) { + return(node_constant(0)); + } + if(!st_lookup(node_exdc_table, (char *) ponode, &dummy)) + return(node_constant(0)); + dcponode= (node_t *) dummy; + if (node_function(CSPF(dcponode)->node) == NODE_PI){ + return(node_literal(CSPF(dcponode)->node, 1)); + } + return(node_dup(CSPF(dcponode)->node)); +} + +void free_dcnetwork_copy(network) +network_t *network; +{ + node_t *dcnode; + int i; + network_t *DC_network; + array_t *dc_list; + + if(network == NULL) { + return; + } + DC_network = network_dc_network(network); + if(DC_network == NULL) { + return; + } + + dc_list= network_dfs(DC_network); + for(i=0 ; i< array_n(dc_list); i++){ + dcnode = array_fetch(node_t *, dc_list, i); + if (node_function(dcnode) == NODE_PO){ + (void) cspf_free(dcnode); + continue; + } + if (node_function(dcnode) == NODE_PI){ + cspf_free(dcnode); + continue; + } + ntbdd_free_at_node(CSPF(dcnode)->node); + node_free(CSPF(dcnode)->node); + cspf_free(dcnode); + } + array_free(dc_list); +} + +array_t *order_nodes_elim(network) +network_t *network; +{ + array_t *odc_order_list, *network_node_list; + node_t *node; + int array_size; + int i; + + network_node_list= network_dfs_from_input(network); + array_size= array_n(network_node_list); + odc_order_list= array_alloc(node_t *, 0); + for(i= 0; i< array_size; i++){ + node= array_fetch(node_t *, network_node_list, i); + odc_alloc(node); + ODC(node)->value= odc_value(node); + ODC(node)->order= i; + if (node_function(node) == NODE_PO) + continue; + array_insert_last(node_t *, odc_order_list, node); + } + (void) find_odc_level(network); + array_sort(odc_order_list, level_elim_cmp); + for(i= 0 ; i < array_n(network_node_list) ; i++){ + node= array_fetch(node_t *, network_node_list, i); + odc_free(node); + } + array_free(network_node_list); + return(odc_order_list); +} + +static int level_elim_cmp(obj1, obj2) +char **obj1; +char **obj2; +{ + node_t *node1, *node2; + + node1= *((node_t **)obj1); + node2= *((node_t **)obj2); + + if (ODC(node1)->level < ODC(node2)->level) + return(-1); + if (ODC(node1)->level > ODC(node2)->level) + return(1); + + if (ODC(node1)->order > ODC(node2)->order) + return(-1); + if (ODC(node1)->order < ODC(node2)->order) + return(1); + return(0); +} + + +int num_cube_cmp(obj1, obj2) +char **obj1; +char **obj2; +{ + node_t *node1, *node2; + + node1= *((node_t **)obj1); + node2= *((node_t **)obj2); + + if (node_num_cube(node1) < node_num_cube(node2)) + return(-1); + if (node_num_cube(node1) > node_num_cube(node2)) + return(1); + return(0); +} + +array_t * +simp_order(nodevec) +array_t *nodevec; +{ + node_t *cn; + node_fsize_t *new_entry, *this_entry; + array_t *list; + int i, fac_size; + + list = array_alloc(node_fsize_t *, 0); + for (i = 0; i < array_n(nodevec); i ++) { + cn = array_fetch(node_t *, nodevec, i); + fac_size = factor_num_literal(cn); + new_entry = ALLOC(node_fsize_t, 1); + new_entry->node = cn; + new_entry->fsize = fac_size; + array_insert(node_fsize_t *, list, i, new_entry); + } + + array_sort(list, fsize_cmp); + for (i = 0; i < array_n(list); i ++) { + this_entry = array_fetch(node_fsize_t *, list, i); + array_insert(node_t *, nodevec, i, this_entry->node); + FREE(this_entry); + } + + array_free(list); + return(nodevec); +} + +int fsize_cmp(obj1, obj2) +char **obj1; +char **obj2; +{ + node_fsize_t *fsize_struct1, *fsize_struct2; + + fsize_struct1 = *((node_fsize_t **) obj1); + fsize_struct2 = *((node_fsize_t **) obj2); + + if (fsize_struct1->fsize < fsize_struct2->fsize) + return(1); + else if (fsize_struct1->fsize > fsize_struct2->fsize) + return(-1); + else + return(0); +} diff --git a/sis/simplify/simplify.doc b/sis/simplify/simplify.doc new file mode 100644 index 0000000..40516cd --- /dev/null +++ b/sis/simplify/simplify.doc @@ -0,0 +1,231 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/simplify.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +Summary: + void simplify_node(); + node_t *simp_dc_filter(); + + +typedef enum sim_method_enum sim_method_t; +enum sim_method_enum { + SIM_METHOD_DCSIMP, SIM_METHOD_NOCOMP, SIM_METHOD_SNOCOMP +}; + +typedef enum sim_dctype_enum sim_dctype_t; +enum sim_dctype_enum { + SIM_DCTYPE_NONE, SIM_DCTYPE_FANIN, SIM_DCTYPE_FANOUT, + SIM_DCTYPE_INOUT, SIM_DCTYPE_ALL, SIM_DCTYPE_SUB_FANIN, + SIM_DCTYPE_LEVEL, SIM_DCTYPE_UNKNOWN +}; + +typedef enum sim_filter_enum sim_filter_t; +enum sim_filter_enum { + SIM_FILTER_NONE, SIM_FILTER_EXACT, SIM_FILTER_DISJ_SUPPORT, + SIM_FILTER_SIZE, SIM_FILTER_FDIST, SIM_FILTER_SDIST, + SIM_FILTER_ALL +}; + +void +simplify_node(f, method, dctype, accept, filter) +node_t *f; +sim_method_t method; +sim_dctype_t dctype; +sim_accept_t accept; +sim_filter_t filter; + + Simplify f using "method", with "dctype" don't-care set + filtered using "filter", and accept the result using + "accept" criteria. + + "method" is used to specify what algorithm is to be used + to simplify f. + SIM_METHOD_SNOCOMP is a single pass of NOCOMP (See next option). + SIM_METHOD_NOCOMP uses ESPRESSO with EXPAND being replaced + with a new algorithm. See Abdul Malik's paper on ICCAD-88. + SIM_METHOD_DCSIMP uses reduced offset based ESPRESSO. + This is advantangous over regular espresso when the + off-set is too large. + + "dctype" is used to specify what type of don't-care set is + to be generated. + SIM_DCTYPE_NONE generates no don't-care set. + SIM_DCTYPE_FANIN generates fanin don't-care sets. + SIM_DCTYPE_FANOUT generates one-level fanout don't-care set. + SIM_DCTYPE_INOUT combines SIM_DCTYPE_FANIN and SIM_DCTYPE_FANOUT. + SIM_DCTYPE_ALL generates all the don't-care set that we are + be able to generate currently. This should be used + with caution for the don't-care set may be too large. + SIM_DCTYPE_SUB_FANIN generates fanin don't cares only for nodes + with the same or subset support as the node being + minimized. This is very effective for fast simplification + when the don't care sets are very large. + SIM_DCTYPE_LEVEL generates fanin don't cares only for nodes + with the same or subset support as the node being minimized + which have level less than the node being minimized. The level + is the largest number of nodes on the longest path from the node to + a primary input. + SIM_DCTYPE_NONE should not be used. + + "filter" is used to trim the don't-care set to speed up the + minimization process. + SIM_FILTER_NONE doesn't trim the don't-care set at all. + SIM_FILTER_EXACT only trims out the absolutely un-necessary + part of the don't-care set. + SIM_FILTER_DISJ_SUPPORT removes all the cubes in the don't-care + set which have disjoint support from the support of the + on-set. + SIM_FILTER_SIZE removes all the cubes in the don't-care + set which are have more than a fixed number of literals (3). + SIM_FILTER_FDIST removes all the cubes in the don't-care + set which are more than a fixed number of literals outside + the support of the node being simplified (2). + SIM_FILTER_SDIST removes all the cubes in the don't-care + set which are more than a fixed distance from all the cubes + of the node being simplified (2). + + "accept" is used to specify the acceptance criteria. + SIM_ACCEPT_FCT_LITS accepts the result if the number + of literals in the factored form decreases. + SIM_ACCEPT_SOP_LITS accepts the result if the number + of literals in the sum-of-product form decreases. + SIM_ACCEPT_CUBES accepts the result if the number of + cubes decreases. + SIM_ACCEPT_ALWAYS forces the acceptance. + +void +simplify_without_odc(network, accept, method, dctype, filter, level_table, mg, leaves) +network_t *network; +sim_accept_t accept; +sim_method_t method; +sim_dctype_t dctype; +sim_filter_t filter; +st_table *level_table; +bdd_manager *mg; +st_table *leaves; + + Simplify each node in the network using "method", + and accept the result using "accept" criteria. + The don't care sets are created and filtered internally. + Don't cares in terms of fanins of a node being simplified + are generated (also called local don't cares) using image computation + techniques. No observability don't cares are computed here. Therefore + the don't cares are the unreachable minterms of the local space. + + "method" is used to specify what algorithm is to be used + to simplify f. + SIM_METHOD_SNOCOMP is a single pass of NOCOMP (See next option). + SIM_METHOD_NOCOMP uses ESPRESSO with EXPAND being replaced + with a new algorithm. See Abdul Malik's paper on ICCAD-88. + SIM_METHOD_DCSIMP uses reduced offset based ESPRESSO. + This is advantangous over regular espresso when the + off-set is too large. + + "dctype" is used to specify what type of don't-care set is + to be generated. + SIM_DCTYPE_SUB_FANIN generates fanin don't cares only for nodes + with the same or subset support as the node being + minimized. This is very effective for fast simplification + when the don't care sets are very large. + SIM_DCTYPE_LEVEL generates fanin don't cares only for nodes + with the same or subset support as the node being minimized + which have level less than the node being minimized. The level + is the largest number of nodes on the longest path from the node to + a primary input. + + "filter" Most of the filtering is done internally. + + SIM_FILTER_LEVEL generates fanin don't cares only for nodes + with the same or subset support as the node being minimized + which have level less than the node being minimized. The level + is the largest number of nodes on the longest path from the node to + a primary input. + + "accept" is used to specify the acceptance criteria. + SIM_ACCEPT_FCT_LITS accepts the result if the number + of literals in the factored form decreases. + SIM_ACCEPT_SOP_LITS accepts the result if the number + of literals in the sum-of-product form decreases. + SIM_ACCEPT_CUBES accepts the result if the number of + cubes decreases. + SIM_ACCEPT_ALWAYS forces the acceptance. + + "level_table" contains the level associated to each node. + + "leaves" a cut set of nodes in the network which are used for building + BDD's. Currently, these are only the primary inputs. + +void +simplify_with_odc(network, accept, method, dctype, filter, level_table, mg, leaves) +network_t *network; +sim_accept_t accept; +sim_method_t method; +sim_dctype_t dctype; +sim_filter_t filter; +st_table *level_table; +bdd_manager *mg; +st_table *leaves; + + Simplify each node in the network using "method", + and accept the result using "accept" criteria. + The don't care sets are created and filtered internally. + Don't cares in terms of fanins of a node being simplified + are generated (also called local don't cares) using image computation + techniques. Observability plus external don't cares are + computed for each node in the network. + The computation is done originally in terms of primary inputs. Then + the image computation techniques are used to map the don't cares + into the local space of the node being simplified. The computed + observability don't cares are compatible. This algorithm does not + guarantee 100% testability but it removes most redundancies. + + "method" is used to specify what algorithm is to be used + to simplify f. + SIM_METHOD_SNOCOMP is a single pass of NOCOMP (See next option). + SIM_METHOD_NOCOMP uses ESPRESSO with EXPAND being replaced + with a new algorithm. See Abdul Malik's paper on ICCAD-88. + SIM_METHOD_DCSIMP uses reduced offset based ESPRESSO. + This is advantangous over regular espresso when the + off-set is too large. + + "dctype" is used to specify what type of don't-care set is + to be generated. + SIM_DCTYPE_SUB_FANIN generates fanin don't cares only for nodes + with the same or subset support as the node being + minimized. This is very effective for fast simplification + when the don't care sets are very large. + SIM_DCTYPE_LEVEL generates fanin don't cares only for nodes + with the same or subset support as the node being minimized + which have level less than the node being minimized. The level + is the largest number of nodes on the longest path from the node to + a primary input. + + "filter" Most of the filtering is done internally. + + SIM_FILTER_LEVEL generates fanin don't cares only for nodes + with the same or subset support as the node being minimized + which have level less than the node being minimized. The level + is the largest number of nodes on the longest path from the node to + a primary input. + + "accept" is used to specify the acceptance criteria. + SIM_ACCEPT_FCT_LITS accepts the result if the number + + "level_table" contains the level associated to each node. + + "leaves" a cut set of nodes in the network which are used for building + BDD's. Currently, these are only the primary inputs. + +node_t * +simp_dc_filter(f, dc, filter); +node_t *f; +node_t *dc; +sim_filter_t filter; + + Returns the don't-care set after applying the "filter". + "f" is the on-set, and "dc" is the don't-care set. diff --git a/sis/simplify/simplify.h b/sis/simplify/simplify.h new file mode 100644 index 0000000..3c2f880 --- /dev/null +++ b/sis/simplify/simplify.h @@ -0,0 +1,49 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/simplify/simplify.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:49 $ + * + */ +#ifndef SIMPLIFY_H +#define SIMPLIFY_H + +typedef enum sim_method_enum sim_method_t; +enum sim_method_enum { + SIM_METHOD_SIMPCOMP, SIM_METHOD_ESPRESSO, SIM_METHOD_EXACT, + SIM_METHOD_EXACT_LITS, SIM_METHOD_DCSIMP, SIM_METHOD_NOCOMP, + SIM_METHOD_SNOCOMP, SIM_METHOD_UNKNOWN +}; + +typedef enum sim_accept_enum sim_accept_t; +enum sim_accept_enum { + SIM_ACCEPT_FCT_LITS, SIM_ACCEPT_CUBES, SIM_ACCEPT_SOP_LITS, + SIM_ACCEPT_ALWAYS, SIM_ACCEPT_UNKNOWN +}; + +typedef enum sim_dctype_enum sim_dctype_t; +enum sim_dctype_enum { + SIM_DCTYPE_NONE, SIM_DCTYPE_FANIN, SIM_DCTYPE_FANOUT, + SIM_DCTYPE_INOUT, SIM_DCTYPE_ALL, SIM_DCTYPE_SUB_FANIN, + SIM_DCTYPE_LEVEL, SIM_DCTYPE_UNKNOWN, + SIM_DCTYPE_X +}; + +typedef enum sim_filter_enum sim_filter_t; +enum sim_filter_enum { + SIM_FILTER_NONE, SIM_FILTER_EXACT, SIM_FILTER_DISJ_SUPPORT, + SIM_FILTER_SIZE, SIM_FILTER_FDIST, SIM_FILTER_SDIST, SIM_FILTER_LEVEL, + SIM_FILTER_ALL +}; + +extern void simplify_node(); +extern void simplify_all(); +extern node_t *simp_dc_filter(); + +extern void comp_perm_fn(); +extern node_t *cspf_dc(); +extern node_t *simp_obsdc_filter(); +extern node_t *simp_obssatdc_filter(); +#endif diff --git a/sis/sis_lib/.misrc b/sis/sis_lib/.misrc new file mode 100644 index 0000000..5d7eee6 --- /dev/null +++ b/sis/sis_lib/.misrc @@ -0,0 +1,59 @@ +alias ai add_inverter +alias alt print_altname +alias asb resub -a +alias c chng_name +alias clp collapse +alias crit -m unit-fanout -a -p 2 +alias el eliminate +alias exit quit +alias fs full_simplify +alias gd decomp -g +alias gf factor -g +alias gp phase -g +alias inv invert +alias man help +alias nts print_stats +alias p print +alias pat print_delay -a +alias pd print_delay +alias pf print_factor +alias pg print_gate +alias pgc print_gate -s +alias pio print_io +alias pk print_kernel +alias plt print_delay -l +alias plv print_level +alias pn p -n +alias prt print_delay -r +alias ps print_stats -f +alias psf print_stats +alias pst print_delay -s +alias pv print_value +alias q quit +alias qd decomp -q +alias qf factor -q +alias qp phase -q +alias rd reduce_depth +alias re read_eqn +alias rl read_blif +alias rlib read_library +alias ro read_oct +alias rp read_pla +alias rr red_removal +alias rsn reset_name +alias sim simulate +alias sim0 simplify -m snocomp -d +alias sim1 simplify -m nocomp -d +alias sim2 simplify +alias sim3 simplify -m nocomp +alias so source +alias sr source +alias sp speed_up +alias sw sweep +alias td tech_decomp +alias u undo +alias wb write_bdnet +alias we write_eqn +alias wl write_blif +alias wp write_pla +alias wo write_oct diff --git a/sis/sis_lib/.sisrc b/sis/sis_lib/.sisrc new file mode 100644 index 0000000..57c86c3 --- /dev/null +++ b/sis/sis_lib/.sisrc @@ -0,0 +1,15 @@ +alias 1h state_assign nova -e h +alias oh one_hot +alias pc print_clock +alias pl print_latch +alias ra read_astg +alias rk read_kiss +alias rs read_slif +alias sa state_assign +alias se stg_extract +alias sm state_minimize +alias v verify_fsm +alias wa write_astg +alias wk write_kiss +alias ws write_slif +alias xdc extract_seq_dc diff --git a/sis/sis_lib/22-1.genlib b/sis/sis_lib/22-1.genlib new file mode 100644 index 0000000..c4f0934 --- /dev/null +++ b/sis/sis_lib/22-1.genlib @@ -0,0 +1,8 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE "!a" 2 O=!a; +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab)'" 3 O=!(a*b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b)'" 3 O=!(a+b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/22-2.genlib b/sis/sis_lib/22-2.genlib new file mode 100644 index 0000000..ae8593e --- /dev/null +++ b/sis/sis_lib/22-2.genlib @@ -0,0 +1,16 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE "!a" 2 O=!a; +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab)'" 3 O=!(a*b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c))'" 4 O=!(a*(b+c)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d))'" 5 O=!((a+b)*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b)'" 3 O=!(a+b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc)'" 4 O=!(a+b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd)'" 5 O=!(a*b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/33-1.genlib b/sis/sis_lib/33-1.genlib new file mode 100644 index 0000000..2207edb --- /dev/null +++ b/sis/sis_lib/33-1.genlib @@ -0,0 +1,12 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE "!a" 2 O=!a; +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab)'" 3 O=!(a*b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc)'" 4 O=!(a*b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b)'" 3 O=!(a+b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c)'" 4 O=!(a+b+c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/33-2.genlib b/sis/sis_lib/33-2.genlib new file mode 100644 index 0000000..c718dc8 --- /dev/null +++ b/sis/sis_lib/33-2.genlib @@ -0,0 +1,68 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE "!a" 2 O=!a; +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab)'" 3 O=!(a*b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c))'" 4 O=!(a*(b+c)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d))'" 5 O=!(a*(b+c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d))'" 5 O=!((a+b)*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e))'" 6 O=!((a+b)*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f))'" 7 O=!((a+b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc)'" 4 O=!(a*b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d))'" 5 O=!(a*b*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e))'" 6 O=!(a*b*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e))'" 6 O=!(a*(b+c)*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f))'" 7 O=!(a*(b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g))'" 8 O=!(a*(b+c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f))'" 7 O=!((a+b)*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g))'" 8 O=!((a+b)*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h))'" 9 O=!((a+b)*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i))'" 10 O=!((a+b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b)'" 3 O=!(a+b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc)'" 4 O=!(a+b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd)'" 5 O=!(a+b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd)'" 5 O=!(a*b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde)'" 6 O=!(a*b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def)'" 7 O=!(a*b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c)'" 4 O=!(a+b+c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd)'" 5 O=!(a+b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde)'" 6 O=!(a+b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de)'" 6 O=!(a+b*c+d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def)'" 7 O=!(a+b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg)'" 8 O=!(a+b*c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef)'" 7 O=!(a*b+c*d+e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg)'" 8 O=!(a*b+c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh)'" 9 O=!(a*b+c*d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi)'" 10 O=!(a*b*c+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/33-4.genlib b/sis/sis_lib/33-4.genlib new file mode 100644 index 0000000..f6d43e6 --- /dev/null +++ b/sis/sis_lib/33-4.genlib @@ -0,0 +1,176 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE "!a" 2 O=!a; +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab)'" 3 O=!(a*b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c))'" 4 O=!(a*(b+c)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd))'" 5 O=!(a*(b+c*d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e)))'" 6 O=!(a*(b+c*(d+e))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f)))'" 7 O=!(a*(b+(c+d)*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de))'" 6 O=!(a*(b*c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f)))'" 7 O=!(a*(b*c+d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g)))'" 8 O=!(a*(b*c+(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d))'" 5 O=!(a*(b+c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de))'" 6 O=!(a*(b+c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef))'" 7 O=!(a*(b+c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg))'" 8 O=!(a*(b*c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d))'" 5 O=!((a+b)*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de))'" 6 O=!((a+b)*(c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f)))'" 7 O=!((a+b)*(c+d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g)))'" 8 O=!((a+b)*(c+(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef))'" 7 O=!((a+b)*(c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g)))'" 8 O=!((a+b)*(c*d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h)))'" 9 O=!((a+b)*(c*d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e))'" 6 O=!((a+b)*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef))'" 7 O=!((a+b)*(c+d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg))'" 8 O=!((a+b)*(c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh))'" 9 O=!((a+b)*(c*d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f))'" 7 O=!((a+b*c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g))'" 8 O=!((a+b*(c+d))*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h))'" 9 O=!((a+(b+c)*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g))'" 8 O=!((a*b+c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h))'" 9 O=!((a*b+c*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i))'" 10 O=!((a*b+(c+d)*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f))'" 7 O=!((a+b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg))'" 8 O=!((a+b+c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh))'" 9 O=!((a+b+c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi))'" 10 O=!((a+b+c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc)'" 4 O=!(a*b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d))'" 5 O=!(a*b*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e))'" 6 O=!(a*b*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e))'" 6 O=!(a*(b+c)*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f))'" 7 O=!(a*(b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g))'" 8 O=!(a*(b+c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f))'" 7 O=!((a+b)*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g))'" 8 O=!((a+b)*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h))'" 9 O=!((a+b)*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i))'" 10 O=!((a+b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b)'" 3 O=!(a+b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc)'" 4 O=!(a+b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d))'" 5 O=!(a+b*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+de))'" 6 O=!(a+b*(c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+ef))'" 7 O=!(a+b*(c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e))'" 6 O=!(a+(b+c)*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+ef))'" 7 O=!(a+(b+c)*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fg))'" 8 O=!(a+(b+c)*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd)'" 5 O=!(a+b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e))'" 6 O=!(a+b*c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f))'" 7 O=!(a+b*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g))'" 8 O=!(a+(b+c)*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd)'" 5 O=!(a*b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e))'" 6 O=!(a*b+c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+ef))'" 7 O=!(a*b+c*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fg))'" 8 O=!(a*b+c*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f))'" 7 O=!(a*b+(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fg))'" 8 O=!(a*b+(c+d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+gh))'" 9 O=!(a*b+(c+d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde)'" 6 O=!(a*b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f))'" 7 O=!(a*b+c*d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g))'" 8 O=!(a*b+c*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h))'" 9 O=!(a*b+(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+def)'" 7 O=!(a*(b+c)+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+efg)'" 8 O=!(a*(b+c*d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fgh)'" 9 O=!(a*(b*c+d*e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efg)'" 8 O=!((a+b)*(c+d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fgh)'" 9 O=!((a+b)*(c+d*e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+ghi)'" 10 O=!((a+b)*(c*d+e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def)'" 7 O=!(a*b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g))'" 8 O=!(a*b*c+d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h))'" 9 O=!(a*b*c+d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i))'" 10 O=!(a*b*c+(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c)'" 4 O=!(a+b+c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd)'" 5 O=!(a+b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde)'" 6 O=!(a+b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de)'" 6 O=!(a+b*c+d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def)'" 7 O=!(a+b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg)'" 8 O=!(a+b*c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef)'" 7 O=!(a*b+c*d+e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg)'" 8 O=!(a*b+c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh)'" 9 O=!(a*b+c*d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi)'" 10 O=!(a*b*c+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/43-5.genlib b/sis/sis_lib/43-5.genlib new file mode 100644 index 0000000..d596480 --- /dev/null +++ b/sis/sis_lib/43-5.genlib @@ -0,0 +1,794 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE "!a" 2 O=!a; +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab)'" 3 O=!(a*b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c))'" 4 O=!(a*(b+c)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd))'" 5 O=!(a*(b+c*d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e)))'" 6 O=!(a*(b+c*(d+e))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+ef)))'" 7 O=!(a*(b+c*(d+e*f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(de+fg)))'" 8 O=!(a*(b+c*(d*e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f)))'" 7 O=!(a*(b+(c+d)*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+fg)))'" 8 O=!(a*(b+(c+d)*(e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(ef+gh)))'" 9 O=!(a*(b+(c+d)*(e*f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde))'" 6 O=!(a*(b+c*d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd(e+f)))'" 7 O=!(a*(b+c*d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e)(f+g)))'" 8 O=!(a*(b+c*(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f)(g+h)))'" 9 O=!(a*(b+(c+d)*(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de))'" 6 O=!(a*(b*c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f)))'" 7 O=!(a*(b*c+d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+fg)))'" 8 O=!(a*(b*c+d*(e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(ef+gh)))'" 9 O=!(a*(b*c+d*(e*f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g)))'" 8 O=!(a*(b*c+(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+gh)))'" 9 O=!(a*(b*c+(d+e)*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(fg+hi)))'" 10 O=!(a*(b*c+(d+e)*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def))'" 7 O=!(a*(b*c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de(f+g)))'" 8 O=!(a*(b*c+d*e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f)(g+h)))'" 9 O=!(a*(b*c+d*(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g)(h+i)))'" 10 O=!(a*(b*c+(d+e)*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+efg))'" 8 O=!(a*(b*(c+d)+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+fgh))'" 9 O=!(a*(b*(c+d*e)+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+ghi))'" 10 O=!(a*(b*(c*d+e*f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+fgh))'" 9 O=!(a*((b+c)*(d+e)+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef)+ghi))'" 10 O=!(a*((b+c)*(d+e*f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+fg)+hij))'" 11 O=!(a*((b+c)*(d*e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg))'" 8 O=!(a*(b*c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+ef(g+h)))'" 9 O=!(a*(b*c*d+e*f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+e(f+g)(h+i)))'" 10 O=!(a*(b*c*d+e*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+(e+f)(g+h)(i+j)))'" 11 O=!(a*(b*c*d+(e+f)*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d))'" 5 O=!(a*(b+c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de))'" 6 O=!(a*(b+c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+def))'" 7 O=!(a*(b+c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef))'" 7 O=!(a*(b+c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+efg))'" 8 O=!(a*(b+c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde+fgh))'" 9 O=!(a*(b+c*d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg))'" 8 O=!(a*(b*c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fgh))'" 9 O=!(a*(b*c+d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def+ghi))'" 10 O=!(a*(b*c+d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg+hij))'" 11 O=!(a*(b*c*d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d))'" 5 O=!((a+b)*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de))'" 6 O=!((a+b)*(c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f)))'" 7 O=!((a+b)*(c+d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+fg)))'" 8 O=!((a+b)*(c+d*(e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(ef+gh)))'" 9 O=!((a+b)*(c+d*(e*f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g)))'" 8 O=!((a+b)*(c+(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+gh)))'" 9 O=!((a+b)*(c+(d+e)*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(fg+hi)))'" 10 O=!((a+b)*(c+(d+e)*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def))'" 7 O=!((a+b)*(c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de(f+g)))'" 8 O=!((a+b)*(c+d*e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f)(g+h)))'" 9 O=!((a+b)*(c+d*(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g)(h+i)))'" 10 O=!((a+b)*(c+(d+e)*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef))'" 7 O=!((a+b)*(c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g)))'" 8 O=!((a+b)*(c*d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+gh)))'" 9 O=!((a+b)*(c*d+e*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(fg+hi)))'" 10 O=!((a+b)*(c*d+e*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h)))'" 9 O=!((a+b)*(c*d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+hi)))'" 10 O=!((a+b)*(c*d+(e+f)*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(gh+ij)))'" 11 O=!((a+b)*(c*d+(e+f)*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg))'" 8 O=!((a+b)*(c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef(g+h)))'" 9 O=!((a+b)*(c*d+e*f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g)(h+i)))'" 10 O=!((a+b)*(c*d+e*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h)(i+j)))'" 11 O=!((a+b)*(c*d+(e+f)*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+fgh))'" 9 O=!((a+b)*(c*(d+e)+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+ghi))'" 10 O=!((a+b)*(c*(d+e*f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+hij))'" 11 O=!((a+b)*(c*(d*e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+ghi))'" 10 O=!((a+b)*((c+d)*(e+f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg)+hij))'" 11 O=!((a+b)*((c+d)*(e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+gh)+ijk))'" 12 O=!((a+b)*((c+d)*(e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh))'" 9 O=!((a+b)*(c*d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fg(h+i)))'" 10 O=!((a+b)*(c*d*e+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+f(g+h)(i+j)))'" 11 O=!((a+b)*(c*d*e+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+(f+g)(h+i)(j+k)))'" 12 O=!((a+b)*(c*d*e+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e))'" 6 O=!((a+b)*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef))'" 7 O=!((a+b)*(c+d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+efg))'" 8 O=!((a+b)*(c+d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg))'" 8 O=!((a+b)*(c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fgh))'" 9 O=!((a+b)*(c+d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def+ghi))'" 10 O=!((a+b)*(c+d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh))'" 9 O=!((a+b)*(c*d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+ghi))'" 10 O=!((a+b)*(c*d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg+hij))'" 11 O=!((a+b)*(c*d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh+ijk))'" 12 O=!((a+b)*(c*d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef))'" 7 O=!((a+b*c)*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e(f+g)))'" 8 O=!((a+b*c)*(d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+(e+f)(g+h)))'" 9 O=!((a+b*c)*(d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg))'" 8 O=!((a+b*c)*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+f(g+h)))'" 9 O=!((a+b*c)*(d*e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+(f+g)(h+i)))'" 10 O=!((a+b*c)*(d*e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f))'" 7 O=!((a+b*c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+fg))'" 8 O=!((a+b*c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef+gh))'" 9 O=!((a+b*c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg+hi))'" 10 O=!((a+b*c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f(g+h)))'" 9 O=!((a+b*(c+d))*(e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+(f+g)(h+i)))'" 10 O=!((a+b*(c+d))*(e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh))'" 9 O=!((a+b*(c+d))*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+g(h+i)))'" 10 O=!((a+b*(c+d))*(e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+(g+h)(i+j)))'" 11 O=!((a+b*(c+d))*(e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g))'" 8 O=!((a+b*(c+d))*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+gh))'" 9 O=!((a+b*(c+d))*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+fg+hi))'" 10 O=!((a+b*(c+d))*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh+ij))'" 11 O=!((a+b*(c+d))*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+de))(f+g+h))'" 9 O=!((a+b*(c+d*e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+ef))(g+h+i))'" 10 O=!((a+b*(c*d+e*f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+(g+h)(i+j)))'" 11 O=!((a+(b+c)*(d+e))*(f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi))'" 10 O=!((a+(b+c)*(d+e))*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+h(i+j)))'" 11 O=!((a+(b+c)*(d+e))*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+(h+i)(j+k)))'" 12 O=!((a+(b+c)*(d+e))*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h))'" 9 O=!((a+(b+c)*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+hi))'" 10 O=!((a+(b+c)*(d+e))*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+gh+ij))'" 11 O=!((a+(b+c)*(d+e))*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi+jk))'" 12 O=!((a+(b+c)*(d+e))*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+ef))(g+h+i))'" 10 O=!((a+(b+c)*(d+e*f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+fg))(h+i+j))'" 11 O=!((a+(b+c)*(d*e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd)(e+f+g))'" 8 O=!((a+b*c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc(d+e))(f+g+h))'" 9 O=!((a+b*c*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d)(e+f))(g+h+i))'" 10 O=!((a+b*(c+d)*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e)(f+g))(h+i+j))'" 11 O=!((a+(b+c)*(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh))'" 9 O=!((a*b+c*d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+g(h+i)))'" 10 O=!((a*b+c*d)*(e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+(g+h)(i+j)))'" 11 O=!((a*b+c*d)*(e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g))'" 8 O=!((a*b+c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+gh))'" 9 O=!((a*b+c*d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+fg+hi))'" 10 O=!((a*b+c*d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh+ij))'" 11 O=!((a*b+c*d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+h(i+j)))'" 11 O=!((a*b+c*(d+e))*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+(h+i)(j+k)))'" 12 O=!((a*b+c*(d+e))*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h))'" 9 O=!((a*b+c*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+hi))'" 10 O=!((a*b+c*(d+e))*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+gh+ij))'" 11 O=!((a*b+c*(d+e))*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+hi+jk))'" 12 O=!((a*b+c*(d+e))*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+ef))(g+h+i))'" 10 O=!((a*b+c*(d+e*f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+fg))(h+i+j))'" 11 O=!((a*b+c*(d*e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+(i+j)(k+l)))'" 13 O=!((a*b+(c+d)*(e+f))*(g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i))'" 10 O=!((a*b+(c+d)*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+ij))'" 11 O=!((a*b+(c+d)*(e+f))*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+hi+jk))'" 12 O=!((a*b+(c+d)*(e+f))*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+ij+kl))'" 13 O=!((a*b+(c+d)*(e+f))*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+fg))(h+i+j))'" 11 O=!((a*b+(c+d)*(e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+gh))(i+j+k))'" 12 O=!((a*b+(c+d)*(e*f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde)(f+g+h))'" 9 O=!((a*b+c*d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd(e+f))(g+h+i))'" 10 O=!((a*b+c*d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e)(f+g))(h+i+j))'" 11 O=!((a*b+c*(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f)(g+h))(i+j+k))'" 12 O=!((a*b+(c+d)*(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+def)(g+h+i))'" 10 O=!((a*(b+c)+d*e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+efg)(h+i+j))'" 11 O=!((a*(b+c*d)+e*f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+fgh)(i+j+k))'" 12 O=!((a*(b*c+d*e)+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+efg)(h+i+j))'" 11 O=!(((a+b)*(c+d)+e*f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+fgh)(i+j+k))'" 12 O=!(((a+b)*(c+d*e)+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+ghi)(j+k+l))'" 13 O=!(((a+b)*(c*d+e*f)+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def)(g+h+i))'" 10 O=!((a*b*c+d*e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+de(f+g))(h+i+j))'" 11 O=!((a*b*c+d*e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+d(e+f)(g+h))(i+j+k))'" 12 O=!((a*b*c+d*(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e)(f+g)(h+i))(j+k+l))'" 13 O=!((a*b*c+(d+e)*(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f))'" 7 O=!((a+b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg))'" 8 O=!((a+b+c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fgh))'" 9 O=!((a+b+c)*(d+e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh))'" 9 O=!((a+b+c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+ghi))'" 10 O=!((a+b+c)*(d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+efg+hij))'" 11 O=!((a+b+c)*(d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi))'" 10 O=!((a+b+c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hij))'" 11 O=!((a+b+c)*(d*e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fgh+ijk))'" 12 O=!((a+b+c)*(d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(def+ghi+jkl))'" 13 O=!((a+b+c)*(d*e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+gh))'" 9 O=!((a+b+c*d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+fg+hi))'" 10 O=!((a+b+c*d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(ef+gh+ij))'" 11 O=!((a+b+c*d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+gh+ij))'" 11 O=!((a+b*c+d*e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(fg+hi+jk))'" 12 O=!((a+b*c+d*e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(gh+ij+kl))'" 13 O=!((a*b+c*d+e*f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc)'" 4 O=!(a*b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d))'" 5 O=!(a*b*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de))'" 6 O=!(a*b*(c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d(e+f)))'" 7 O=!(a*b*(c+d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+(d+e)(f+g)))'" 8 O=!(a*b*(c+(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef))'" 7 O=!(a*b*(c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+e(f+g)))'" 8 O=!(a*b*(c*d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+(e+f)(g+h)))'" 9 O=!(a*b*(c*d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e))'" 6 O=!(a*b*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+ef))'" 7 O=!(a*b*(c+d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de+fg))'" 8 O=!(a*b*(c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef+gh))'" 9 O=!(a*b*(c*d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e))'" 6 O=!(a*(b+c)*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef))'" 7 O=!(a*(b+c)*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e(f+g)))'" 8 O=!(a*(b+c)*(d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+(e+f)(g+h)))'" 9 O=!(a*(b+c)*(d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg))'" 8 O=!(a*(b+c)*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+f(g+h)))'" 9 O=!(a*(b+c)*(d*e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+(f+g)(h+i)))'" 10 O=!(a*(b+c)*(d*e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f))'" 7 O=!(a*(b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+fg))'" 8 O=!(a*(b+c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef+gh))'" 9 O=!(a*(b+c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg+hi))'" 10 O=!(a*(b+c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)(e+f+g))'" 8 O=!(a*(b+c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e))(f+g+h))'" 9 O=!(a*(b+c*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f))(g+h+i))'" 10 O=!(a*(b+(c+d)*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)(f+g+h))'" 9 O=!(a*(b*c+d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f))(g+h+i))'" 10 O=!(a*(b*c+d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g))(h+i+j))'" 11 O=!(a*(b*c+(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g))'" 8 O=!(a*(b+c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+gh))'" 9 O=!(a*(b+c+d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+fg+hi))'" 10 O=!(a*(b+c+d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(ef+gh+ij))'" 11 O=!(a*(b+c+d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f))'" 7 O=!((a+b)*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg))'" 8 O=!((a+b)*(c+d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f(g+h)))'" 9 O=!((a+b)*(c+d)*(e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+(f+g)(h+i)))'" 10 O=!((a+b)*(c+d)*(e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh))'" 9 O=!((a+b)*(c+d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+g(h+i)))'" 10 O=!((a+b)*(c+d)*(e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+(g+h)(i+j)))'" 11 O=!((a+b)*(c+d)*(e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g))'" 8 O=!((a+b)*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+gh))'" 9 O=!((a+b)*(c+d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg+hi))'" 10 O=!((a+b)*(c+d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh+ij))'" 11 O=!((a+b)*(c+d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)(f+g+h))'" 9 O=!((a+b)*(c+d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f))(g+h+i))'" 10 O=!((a+b)*(c+d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g))(h+i+j))'" 11 O=!((a+b)*(c+(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)(g+h+i))'" 10 O=!((a+b)*(c*d+e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g))(h+i+j))'" 11 O=!((a+b)*(c*d+e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h))(i+j+k))'" 12 O=!((a+b)*(c*d+(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h))'" 9 O=!((a+b)*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+hi))'" 10 O=!((a+b)*(c+d+e)*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+gh+ij))'" 11 O=!((a+b)*(c+d+e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(fg+hi+jk))'" 12 O=!((a+b)*(c+d+e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f)(g+h+i))'" 10 O=!((a+b*c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g)(h+i+j))'" 11 O=!((a+b*(c+d))*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h)(i+j+k))'" 12 O=!((a+(b+c)*(d+e))*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g)(h+i+j))'" 11 O=!((a*b+c*d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h)(i+j+k))'" 12 O=!((a*b+c*(d+e))*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i)(j+k+l))'" 13 O=!((a*b+(c+d)*(e+f))*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i))'" 10 O=!((a+b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+ij))'" 11 O=!((a+b+c)*(d+e+f)*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+hi+jk))'" 12 O=!((a+b+c)*(d+e+f)*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(gh+ij+kl))'" 13 O=!((a+b+c)*(d+e+f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd)'" 5 O=!(a*b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e))'" 6 O=!(a*b*c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e+f))'" 7 O=!(a*b*c*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f))'" 7 O=!(a*b*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f+g))'" 8 O=!(a*b*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e)(f+g+h))'" 9 O=!(a*b*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g))'" 8 O=!(a*(b+c)*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g+h))'" 9 O=!(a*(b+c)*(d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f)(g+h+i))'" 10 O=!(a*(b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g)(h+i+j))'" 11 O=!(a*(b+c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h))'" 9 O=!((a+b)*(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h+i))'" 10 O=!((a+b)*(c+d)*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g)(h+i+j))'" 11 O=!((a+b)*(c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h)(i+j+k))'" 12 O=!((a+b)*(c+d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i)(j+k+l))'" 13 O=!((a+b+c)*(d+e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b)'" 3 O=!(a+b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc)'" 4 O=!(a+b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d))'" 5 O=!(a+b*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+de))'" 6 O=!(a+b*(c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+def))'" 7 O=!(a+b*(c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+ef))'" 7 O=!(a+b*(c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+efg))'" 8 O=!(a+b*(c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cde+fgh))'" 9 O=!(a+b*(c*d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e))'" 6 O=!(a+(b+c)*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+ef))'" 7 O=!(a+(b+c)*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+efg))'" 8 O=!(a+(b+c)*(d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fg))'" 8 O=!(a+(b+c)*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fgh))'" 9 O=!(a+(b+c)*(d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(def+ghi))'" 10 O=!(a+(b+c)*(d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(e+fg))'" 8 O=!(a+(b+c*d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(ef+gh))'" 9 O=!(a+(b+c*d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(fg+hi))'" 10 O=!(a+(b*c+d*e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd)'" 5 O=!(a+b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e))'" 6 O=!(a+b*c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+ef))'" 7 O=!(a+b*c*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(de+fg))'" 8 O=!(a+b*c*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f))'" 7 O=!(a+b*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+fg))'" 8 O=!(a+b*(c+d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(ef+gh))'" 9 O=!(a+b*(c+d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g))'" 8 O=!(a+(b+c)*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+gh))'" 9 O=!(a+(b+c)*(d+e)*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(fg+hi))'" 10 O=!(a+(b+c)*(d+e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde)'" 6 O=!(a+b*c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd(e+f))'" 7 O=!(a+b*c*d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e)(f+g))'" 8 O=!(a+b*c*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f)(g+h))'" 9 O=!(a+b*(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g)(h+i))'" 10 O=!(a+(b+c)*(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd)'" 5 O=!(a*b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e))'" 6 O=!(a*b+c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+ef))'" 7 O=!(a*b+c*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+efg))'" 8 O=!(a*b+c*(d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fg))'" 8 O=!(a*b+c*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fgh))'" 9 O=!(a*b+c*(d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(def+ghi))'" 10 O=!(a*b+c*(d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f))'" 7 O=!(a*b+(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fg))'" 8 O=!(a*b+(c+d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fgh))'" 9 O=!(a*b+(c+d)*(e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+gh))'" 9 O=!(a*b+(c+d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+ghi))'" 10 O=!(a*b+(c+d)*(e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(efg+hij))'" 11 O=!(a*b+(c+d)*(e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(f+gh))'" 9 O=!(a*b+(c+d*e)*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(fg+hi))'" 10 O=!(a*b+(c+d*e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(gh+ij))'" 11 O=!(a*b+(c*d+e*f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde)'" 6 O=!(a*b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f))'" 7 O=!(a*b+c*d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+fg))'" 8 O=!(a*b+c*d*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(ef+gh))'" 9 O=!(a*b+c*d*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g))'" 8 O=!(a*b+c*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+gh))'" 9 O=!(a*b+c*(d+e)*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(fg+hi))'" 10 O=!(a*b+c*(d+e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h))'" 9 O=!(a*b+(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+hi))'" 10 O=!(a*b+(c+d)*(e+f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(gh+ij))'" 11 O=!(a*b+(c+d)*(e+f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef)'" 7 O=!(a*b+c*d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde(f+g))'" 8 O=!(a*b+c*d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f)(g+h))'" 9 O=!(a*b+c*d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g)(h+i))'" 10 O=!(a*b+c*(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h)(i+j))'" 11 O=!(a*b+(c+d)*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+def)'" 7 O=!(a*(b+c)+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+defg)'" 8 O=!(a*(b+c)+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+efg)'" 8 O=!(a*(b+c*d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+efgh)'" 9 O=!(a*(b+c*d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fgh)'" 9 O=!(a*(b+c*d*e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fghi)'" 10 O=!(a*(b+c*d*e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fgh)'" 9 O=!(a*(b*c+d*e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fghi)'" 10 O=!(a*(b*c+d*e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+ghi)'" 10 O=!(a*(b*c+d*e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+ghij)'" 11 O=!(a*(b*c+d*e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hij)'" 11 O=!(a*(b*c*d+e*f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hijk)'" 12 O=!(a*(b*c*d+e*f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efg)'" 8 O=!((a+b)*(c+d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efgh)'" 9 O=!((a+b)*(c+d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fgh)'" 9 O=!((a+b)*(c+d*e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fghi)'" 10 O=!((a+b)*(c+d*e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+ghi)'" 10 O=!((a+b)*(c+d*e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+ghij)'" 11 O=!((a+b)*(c+d*e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+ghi)'" 10 O=!((a+b)*(c*d+e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+ghij)'" 11 O=!((a+b)*(c*d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hij)'" 11 O=!((a+b)*(c*d+e*f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hijk)'" 12 O=!((a+b)*(c*d+e*f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ijk)'" 12 O=!((a+b)*(c*d*e+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ijkl)'" 13 O=!((a+b)*(c*d*e+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+ghi)'" 10 O=!((a+b*c)*(d+e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+ghij)'" 11 O=!((a+b*c)*(d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hij)'" 11 O=!((a+b*c)*(d*e+f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hijk)'" 12 O=!((a+b*c)*(d*e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ijk)'" 12 O=!((a*b+c*d)*(e*f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ijkl)'" 13 O=!((a*b+c*d)*(e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def)'" 7 O=!(a*b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g))'" 8 O=!(a*b*c+d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+gh))'" 9 O=!(a*b*c+d*e*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(fg+hi))'" 10 O=!(a*b*c+d*e*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h))'" 9 O=!(a*b*c+d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+hi))'" 10 O=!(a*b*c+d*(e+f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(gh+ij))'" 11 O=!(a*b*c+d*(e+f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i))'" 10 O=!(a*b*c+(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+ij))'" 11 O=!(a*b*c+(d+e)*(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(hi+jk))'" 12 O=!(a*b*c+(d+e)*(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg)'" 8 O=!(a*b*c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def(g+h))'" 9 O=!(a*b*c+d*e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g)(h+i))'" 10 O=!(a*b*c+d*e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h)(i+j))'" 11 O=!(a*b*c+d*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i)(j+k))'" 12 O=!(a*b*c+(d+e)*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+efgh)'" 9 O=!(a*b*(c+d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+fghi)'" 10 O=!(a*b*(c+d*e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+ghij)'" 11 O=!(a*b*(c*d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+fghi)'" 10 O=!(a*(b+c)*(d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+ghij)'" 11 O=!(a*(b+c)*(d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+hijk)'" 12 O=!(a*(b+c)*(d*e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+ghij)'" 11 O=!((a+b)*(c+d)*(e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg)+hijk)'" 12 O=!((a+b)*(c+d)*(e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh)+ijkl)'" 13 O=!((a+b)*(c+d)*(e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh)'" 9 O=!(a*b*c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efg(h+i))'" 10 O=!(a*b*c*d+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+ef(g+h)(i+j))'" 11 O=!(a*b*c*d+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+e(f+g)(h+i)(j+k))'" 12 O=!(a*b*c*d+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f)(g+h)(i+j)(k+l))'" 13 O=!(a*b*c*d+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c)'" 4 O=!(a+b+c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd)'" 5 O=!(a+b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde)'" 6 O=!(a+b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cdef)'" 7 O=!(a+b+c*d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de)'" 6 O=!(a+b*c+d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def)'" 7 O=!(a+b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+defg)'" 8 O=!(a+b*c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg)'" 8 O=!(a+b*c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efgh)'" 9 O=!(a+b*c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fghi)'" 10 O=!(a+b*c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef)'" 7 O=!(a*b+c*d+e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg)'" 8 O=!(a*b+c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efgh)'" 9 O=!(a*b+c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh)'" 9 O=!(a*b+c*d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fghi)'" 10 O=!(a*b+c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+ghij)'" 11 O=!(a*b+c*d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi)'" 10 O=!(a*b*c+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghij)'" 11 O=!(a*b*c+d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hijk)'" 12 O=!(a*b*c+d*e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ijkl)'" 13 O=!(a*b*c*d+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/44-1.genlib b/sis/sis_lib/44-1.genlib new file mode 100644 index 0000000..4d2256d --- /dev/null +++ b/sis/sis_lib/44-1.genlib @@ -0,0 +1,16 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE "!a" 2 O=!a; +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab)'" 3 O=!(a*b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc)'" 4 O=!(a*b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd)'" 5 O=!(a*b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b)'" 3 O=!(a+b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c)'" 4 O=!(a+b+c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+d)'" 5 O=!(a+b+c+d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/44-2.genlib b/sis/sis_lib/44-2.genlib new file mode 100644 index 0000000..9c67b07 --- /dev/null +++ b/sis/sis_lib/44-2.genlib @@ -0,0 +1,264 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE "!a" 2 O=!a; +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab)'" 3 O=!(a*b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c))'" 4 O=!(a*(b+c)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d))'" 5 O=!(a*(b+c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e))'" 6 O=!(a*(b+c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d))'" 5 O=!((a+b)*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e))'" 6 O=!((a+b)*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f))'" 7 O=!((a+b)*(c+d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f))'" 7 O=!((a+b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g))'" 8 O=!((a+b+c)*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h))'" 9 O=!((a+b+c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc)'" 4 O=!(a*b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d))'" 5 O=!(a*b*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e))'" 6 O=!(a*b*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e+f))'" 7 O=!(a*b*(c+d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e))'" 6 O=!(a*(b+c)*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f))'" 7 O=!(a*(b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f+g))'" 8 O=!(a*(b+c)*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g))'" 8 O=!(a*(b+c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g+h))'" 9 O=!(a*(b+c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+g+h+i))'" 10 O=!(a*(b+c+d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f))'" 7 O=!((a+b)*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g))'" 8 O=!((a+b)*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g+h))'" 9 O=!((a+b)*(c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h))'" 9 O=!((a+b)*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h+i))'" 10 O=!((a+b)*(c+d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+h+i+j))'" 11 O=!((a+b)*(c+d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i))'" 10 O=!((a+b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i+j))'" 11 O=!((a+b+c)*(d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+i+j+k))'" 12 O=!((a+b+c)*(d+e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+j+k+l))'" 13 O=!((a+b+c+d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd)'" 5 O=!(a*b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e))'" 6 O=!(a*b*c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e+f))'" 7 O=!(a*b*c*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e+f+g))'" 8 O=!(a*b*c*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f))'" 7 O=!(a*b*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f+g))'" 8 O=!(a*b*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f+g+h))'" 9 O=!(a*b*(c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e)(f+g+h))'" 9 O=!(a*b*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e)(f+g+h+i))'" 10 O=!(a*b*(c+d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e+f)(g+h+i+j))'" 11 O=!(a*b*(c+d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g))'" 8 O=!(a*(b+c)*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g+h))'" 9 O=!(a*(b+c)*(d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g+h+i))'" 10 O=!(a*(b+c)*(d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f)(g+h+i))'" 10 O=!(a*(b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f)(g+h+i+j))'" 11 O=!(a*(b+c)*(d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f+g)(h+i+j+k))'" 12 O=!(a*(b+c)*(d+e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g)(h+i+j))'" 11 O=!(a*(b+c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g)(h+i+j+k))'" 12 O=!(a*(b+c+d)*(e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g+h)(i+j+k+l))'" 13 O=!(a*(b+c+d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+g+h+i)(j+k+l+m))'" 14 O=!(a*(b+c+d+e)*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h))'" 9 O=!((a+b)*(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h+i))'" 10 O=!((a+b)*(c+d)*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h+i+j))'" 11 O=!((a+b)*(c+d)*(e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g)(h+i+j))'" 11 O=!((a+b)*(c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g)(h+i+j+k))'" 12 O=!((a+b)*(c+d)*(e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g+h)(i+j+k+l))'" 13 O=!((a+b)*(c+d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h)(i+j+k))'" 12 O=!((a+b)*(c+d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h)(i+j+k+l))'" 13 O=!((a+b)*(c+d+e)*(f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h+i)(j+k+l+m))'" 14 O=!((a+b)*(c+d+e)*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+h+i+j)(k+l+m+n))'" 15 O=!((a+b)*(c+d+e+f)*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i)(j+k+l))'" 13 O=!((a+b+c)*(d+e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i)(j+k+l+m))'" 14 O=!((a+b+c)*(d+e+f)*(g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i+j)(k+l+m+n))'" 15 O=!((a+b+c)*(d+e+f)*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+i+j+k)(l+m+n+o))'" 16 O=!((a+b+c)*(d+e+f+g)*(h+i+j+k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+j+k+l)(m+n+o+p))'" 17 O=!((a+b+c+d)*(e+f+g+h)*(i+j+k+l)*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b)'" 3 O=!(a+b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc)'" 4 O=!(a+b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd)'" 5 O=!(a+b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde)'" 6 O=!(a+b*c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd)'" 5 O=!(a*b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde)'" 6 O=!(a*b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef)'" 7 O=!(a*b+c*d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def)'" 7 O=!(a*b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg)'" 8 O=!(a*b*c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh)'" 9 O=!(a*b*c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c)'" 4 O=!(a+b+c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd)'" 5 O=!(a+b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde)'" 6 O=!(a+b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cdef)'" 7 O=!(a+b+c*d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de)'" 6 O=!(a+b*c+d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def)'" 7 O=!(a+b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+defg)'" 8 O=!(a+b*c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg)'" 8 O=!(a+b*c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efgh)'" 9 O=!(a+b*c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fghi)'" 10 O=!(a+b*c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef)'" 7 O=!(a*b+c*d+e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg)'" 8 O=!(a*b+c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efgh)'" 9 O=!(a*b+c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh)'" 9 O=!(a*b+c*d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fghi)'" 10 O=!(a*b+c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+ghij)'" 11 O=!(a*b+c*d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi)'" 10 O=!(a*b*c+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghij)'" 11 O=!(a*b*c+d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hijk)'" 12 O=!(a*b*c+d*e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ijkl)'" 13 O=!(a*b*c*d+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+d)'" 5 O=!(a+b+c+d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+de)'" 6 O=!(a+b+c+d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+def)'" 7 O=!(a+b+c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+defg)'" 8 O=!(a+b+c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd+ef)'" 7 O=!(a+b+c*d+e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd+efg)'" 8 O=!(a+b+c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd+efgh)'" 9 O=!(a+b+c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde+fgh)'" 9 O=!(a+b+c*d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde+fghi)'" 10 O=!(a+b+c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cdef+ghij)'" 11 O=!(a+b+c*d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de+fg)'" 8 O=!(a+b*c+d*e+f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de+fgh)'" 9 O=!(a+b*c+d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de+fghi)'" 10 O=!(a+b*c+d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def+ghi)'" 10 O=!(a+b*c+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def+ghij)'" 11 O=!(a+b*c+d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+defg+hijk)'" 12 O=!(a+b*c+d*e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg+hij)'" 11 O=!(a+b*c*d+e*f*g+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg+hijk)'" 12 O=!(a+b*c*d+e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efgh+ijkl)'" 13 O=!(a+b*c*d+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fghi+jklm)'" 14 O=!(a+b*c*d*e+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef+gh)'" 9 O=!(a*b+c*d+e*f+g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef+ghi)'" 10 O=!(a*b+c*d+e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef+ghij)'" 11 O=!(a*b+c*d+e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg+hij)'" 11 O=!(a*b+c*d+e*f*g+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg+hijk)'" 12 O=!(a*b+c*d+e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efgh+ijkl)'" 13 O=!(a*b+c*d+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh+ijk)'" 12 O=!(a*b+c*d*e+f*g*h+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh+ijkl)'" 13 O=!(a*b+c*d*e+f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fghi+jklm)'" 14 O=!(a*b+c*d*e+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+ghij+klmn)'" 15 O=!(a*b+c*d*e*f+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi+jkl)'" 13 O=!(a*b*c+d*e*f+g*h*i+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi+jklm)'" 14 O=!(a*b*c+d*e*f+g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghij+klmn)'" 15 O=!(a*b*c+d*e*f+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hijk+lmno)'" 16 O=!(a*b*c+d*e*f*g+h*i*j*k+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ijkl+mnop)'" 17 O=!(a*b*c*d+e*f*g*h+i*j*k*l+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/44-3.genlib b/sis/sis_lib/44-3.genlib new file mode 100644 index 0000000..41eefb7 --- /dev/null +++ b/sis/sis_lib/44-3.genlib @@ -0,0 +1,1252 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE "!a" 2 O=!a; +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab)'" 3 O=!(a*b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c))'" 4 O=!(a*(b+c)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd))'" 5 O=!(a*(b+c*d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde))'" 6 O=!(a*(b+c*d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de))'" 6 O=!(a*(b*c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def))'" 7 O=!(a*(b*c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg))'" 8 O=!(a*(b*c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d))'" 5 O=!(a*(b+c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de))'" 6 O=!(a*(b+c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+def))'" 7 O=!(a*(b+c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef))'" 7 O=!(a*(b+c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+efg))'" 8 O=!(a*(b+c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde+fgh))'" 9 O=!(a*(b+c*d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg))'" 8 O=!(a*(b*c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fgh))'" 9 O=!(a*(b*c+d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def+ghi))'" 10 O=!(a*(b*c+d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg+hij))'" 11 O=!(a*(b*c*d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e))'" 6 O=!(a*(b+c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+ef))'" 7 O=!(a*(b+c+d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+efg))'" 8 O=!(a*(b+c+d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de+fg))'" 8 O=!(a*(b+c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de+fgh))'" 9 O=!(a*(b+c+d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+def+ghi))'" 10 O=!(a*(b+c+d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef+gh))'" 9 O=!(a*(b+c*d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef+ghi))'" 10 O=!(a*(b+c*d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+efg+hij))'" 11 O=!(a*(b+c*d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde+fgh+ijk))'" 12 O=!(a*(b+c*d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg+hi))'" 10 O=!(a*(b*c+d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg+hij))'" 11 O=!(a*(b*c+d*e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fgh+ijk))'" 12 O=!(a*(b*c+d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def+ghi+jkl))'" 13 O=!(a*(b*c+d*e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg+hij+klm))'" 14 O=!(a*(b*c*d+e*f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d))'" 5 O=!((a+b)*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de))'" 6 O=!((a+b)*(c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def))'" 7 O=!((a+b)*(c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef))'" 7 O=!((a+b)*(c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg))'" 8 O=!((a+b)*(c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh))'" 9 O=!((a+b)*(c*d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e))'" 6 O=!((a+b)*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef))'" 7 O=!((a+b)*(c+d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+efg))'" 8 O=!((a+b)*(c+d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg))'" 8 O=!((a+b)*(c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fgh))'" 9 O=!((a+b)*(c+d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def+ghi))'" 10 O=!((a+b)*(c+d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh))'" 9 O=!((a+b)*(c*d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+ghi))'" 10 O=!((a+b)*(c*d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg+hij))'" 11 O=!((a+b)*(c*d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh+ijk))'" 12 O=!((a+b)*(c*d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f))'" 7 O=!((a+b)*(c+d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+fg))'" 8 O=!((a+b)*(c+d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+fgh))'" 9 O=!((a+b)*(c+d+e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef+gh))'" 9 O=!((a+b)*(c+d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef+ghi))'" 10 O=!((a+b)*(c+d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+efg+hij))'" 11 O=!((a+b)*(c+d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg+hi))'" 10 O=!((a+b)*(c+d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg+hij))'" 11 O=!((a+b)*(c+d*e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fgh+ijk))'" 12 O=!((a+b)*(c+d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def+ghi+jkl))'" 13 O=!((a+b)*(c+d*e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh+ij))'" 11 O=!((a+b)*(c*d+e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh+ijk))'" 12 O=!((a+b)*(c*d+e*f+g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+ghi+jkl))'" 13 O=!((a+b)*(c*d+e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg+hij+klm))'" 14 O=!((a+b)*(c*d+e*f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh+ijk+lmn))'" 15 O=!((a+b)*(c*d*e+f*g*h+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef))'" 7 O=!((a+b*c)*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg))'" 8 O=!((a+b*c)*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f))'" 7 O=!((a+b*c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+fg))'" 8 O=!((a+b*c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef+gh))'" 9 O=!((a+b*c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg+hi))'" 10 O=!((a+b*c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f+g))'" 8 O=!((a+b*c)*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f+gh))'" 9 O=!((a+b*c)*(d+e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+fg+hi))'" 10 O=!((a+b*c)*(d+e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef+gh+ij))'" 11 O=!((a+b*c)*(d+e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg+hi+jk))'" 12 O=!((a+b*c)*(d*e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd)(e+f+g))'" 8 O=!((a+b*c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd)(e+f+g+h))'" 9 O=!((a+b*c*d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh))'" 9 O=!((a*b+c*d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g))'" 8 O=!((a*b+c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+gh))'" 9 O=!((a*b+c*d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+fg+hi))'" 10 O=!((a*b+c*d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh+ij))'" 11 O=!((a*b+c*d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g+h))'" 9 O=!((a*b+c*d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g+hi))'" 10 O=!((a*b+c*d)*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+gh+ij))'" 11 O=!((a*b+c*d)*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+fg+hi+jk))'" 12 O=!((a*b+c*d)*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh+ij+kl))'" 13 O=!((a*b+c*d)*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde)(f+g+h))'" 9 O=!((a*b+c*d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde)(f+g+h+i))'" 10 O=!((a*b+c*d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def)(g+h+i))'" 10 O=!((a*b*c+d*e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def)(g+h+i+j))'" 11 O=!((a*b*c+d*e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f))'" 7 O=!((a+b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg))'" 8 O=!((a+b+c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fgh))'" 9 O=!((a+b+c)*(d+e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh))'" 9 O=!((a+b+c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+ghi))'" 10 O=!((a+b+c)*(d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+efg+hij))'" 11 O=!((a+b+c)*(d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi))'" 10 O=!((a+b+c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hij))'" 11 O=!((a+b+c)*(d*e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fgh+ijk))'" 12 O=!((a+b+c)*(d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(def+ghi+jkl))'" 13 O=!((a+b+c)*(d*e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g))'" 8 O=!((a+b+c)*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+gh))'" 9 O=!((a+b+c)*(d+e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+ghi))'" 10 O=!((a+b+c)*(d+e+f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg+hi))'" 10 O=!((a+b+c)*(d+e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg+hij))'" 11 O=!((a+b+c)*(d+e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fgh+ijk))'" 12 O=!((a+b+c)*(d+e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh+ij))'" 11 O=!((a+b+c)*(d+e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh+ijk))'" 12 O=!((a+b+c)*(d+e*f+g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+ghi+jkl))'" 13 O=!((a+b+c)*(d+e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+efg+hij+klm))'" 14 O=!((a+b+c)*(d+e*f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi+jk))'" 12 O=!((a+b+c)*(d*e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi+jkl))'" 13 O=!((a+b+c)*(d*e+f*g+h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hij+klm))'" 14 O=!((a+b+c)*(d*e+f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fgh+ijk+lmn))'" 15 O=!((a+b+c)*(d*e+f*g*h+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(def+ghi+jkl+mno))'" 16 O=!((a+b+c)*(d*e*f+g*h*i+j*k*l+m*n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+gh))'" 9 O=!((a+b+c*d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+fg+hi))'" 10 O=!((a+b+c*d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(ef+gh+ij))'" 11 O=!((a+b+c*d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+g+h))'" 9 O=!((a+b+c*d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+g+hi))'" 10 O=!((a+b+c*d)*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+gh+ij))'" 11 O=!((a+b+c*d)*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+fg+hi+jk))'" 12 O=!((a+b+c*d)*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(ef+gh+ij+kl))'" 13 O=!((a+b+c*d)*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cde)(f+g+h+i))'" 10 O=!((a+b+c*d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+gh+ij))'" 11 O=!((a+b*c+d*e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(fg+hi+jk))'" 12 O=!((a+b*c+d*e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+g+h+i))'" 10 O=!((a+b*c+d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+g+h+ij))'" 11 O=!((a+b*c+d*e)*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+g+hi+jk))'" 12 O=!((a+b*c+d*e)*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+gh+ij+kl))'" 13 O=!((a+b*c+d*e)*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(fg+hi+jk+lm))'" 14 O=!((a+b*c+d*e)*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+def)(g+h+i+j))'" 11 O=!((a+b*c+d*e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd+efg)(h+i+j+k))'" 12 O=!((a+b*c*d+e*f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(gh+ij+kl))'" 13 O=!((a*b+c*d+e*f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(g+h+i+j))'" 11 O=!((a*b+c*d+e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(g+h+i+jk))'" 12 O=!((a*b+c*d+e*f)*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(g+h+ij+kl))'" 13 O=!((a*b+c*d+e*f)*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(g+hi+jk+lm))'" 14 O=!((a*b+c*d+e*f)*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(gh+ij+kl+mn))'" 15 O=!((a*b+c*d+e*f)*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+efg)(h+i+j+k))'" 12 O=!((a*b+c*d+e*f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde+fgh)(i+j+k+l))'" 13 O=!((a*b+c*d*e+f*g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def+ghi)(j+k+l+m))'" 14 O=!((a*b*c+d*e*f+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h))'" 9 O=!((a+b+c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+hi))'" 10 O=!((a+b+c+d)*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+hij))'" 11 O=!((a+b+c+d)*(e+f+g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+gh+ij))'" 11 O=!((a+b+c+d)*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+gh+ijk))'" 12 O=!((a+b+c+d)*(e+f+g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+ghi+jkl))'" 13 O=!((a+b+c+d)*(e+f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+fg+hi+jk))'" 12 O=!((a+b+c+d)*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+fg+hi+jkl))'" 13 O=!((a+b+c+d)*(e+f*g+h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+fg+hij+klm))'" 14 O=!((a+b+c+d)*(e+f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+fgh+ijk+lmn))'" 15 O=!((a+b+c+d)*(e+f*g*h+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(ef+gh+ij+kl))'" 13 O=!((a+b+c+d)*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(ef+gh+ij+klm))'" 14 O=!((a+b+c+d)*(e*f+g*h+i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(ef+gh+ijk+lmn))'" 15 O=!((a+b+c+d)*(e*f+g*h+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(ef+ghi+jkl+mno))'" 16 O=!((a+b+c+d)*(e*f+g*h*i+j*k*l+m*n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(efg+hij+klm+nop))'" 17 O=!((a+b+c+d)*(e*f*g+h*i*j+k*l*m+n*o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+de)(f+g+h+ij))'" 11 O=!((a+b+c+d*e)*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+de)(f+g+hi+jk))'" 12 O=!((a+b+c+d*e)*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+de)(f+gh+ij+kl))'" 13 O=!((a+b+c+d*e)*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+de)(fg+hi+jk+lm))'" 14 O=!((a+b+c+d*e)*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd+ef)(g+h+ij+kl))'" 13 O=!((a+b+c*d+e*f)*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd+ef)(g+hi+jk+lm))'" 14 O=!((a+b+c*d+e*f)*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd+ef)(gh+ij+kl+mn))'" 15 O=!((a+b+c*d+e*f)*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de+fg)(h+ij+kl+mn))'" 15 O=!((a+b*c+d*e+f*g)*(h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de+fg)(hi+jk+lm+no))'" 16 O=!((a+b*c+d*e+f*g)*(h*i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef+gh)(ij+kl+mn+op))'" 17 O=!((a*b+c*d+e*f+g*h)*(i*j+k*l+m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc)'" 4 O=!(a*b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d))'" 5 O=!(a*b*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de))'" 6 O=!(a*b*(c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef))'" 7 O=!(a*b*(c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e))'" 6 O=!(a*b*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+ef))'" 7 O=!(a*b*(c+d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de+fg))'" 8 O=!(a*b*(c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef+gh))'" 9 O=!(a*b*(c*d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e+f))'" 7 O=!(a*b*(c+d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e+fg))'" 8 O=!(a*b*(c+d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+ef+gh))'" 9 O=!(a*b*(c+d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de+fg+hi))'" 10 O=!(a*b*(c+d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef+gh+ij))'" 11 O=!(a*b*(c*d+e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e))'" 6 O=!(a*(b+c)*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef))'" 7 O=!(a*(b+c)*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg))'" 8 O=!(a*(b+c)*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f))'" 7 O=!(a*(b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+fg))'" 8 O=!(a*(b+c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef+gh))'" 9 O=!(a*(b+c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg+hi))'" 10 O=!(a*(b+c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f+g))'" 8 O=!(a*(b+c)*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f+gh))'" 9 O=!(a*(b+c)*(d+e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+fg+hi))'" 10 O=!(a*(b+c)*(d+e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef+gh+ij))'" 11 O=!(a*(b+c)*(d+e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg+hi+jk))'" 12 O=!(a*(b+c)*(d*e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)(e+f+g))'" 8 O=!(a*(b+c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)(e+f+g+h))'" 9 O=!(a*(b+c*d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)(f+g+h))'" 9 O=!(a*(b*c+d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)(f+g+h+i))'" 10 O=!(a*(b*c+d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g))'" 8 O=!(a*(b+c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+gh))'" 9 O=!(a*(b+c+d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+fg+hi))'" 10 O=!(a*(b+c+d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(ef+gh+ij))'" 11 O=!(a*(b+c+d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g+h))'" 9 O=!(a*(b+c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g+hi))'" 10 O=!(a*(b+c+d)*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+gh+ij))'" 11 O=!(a*(b+c+d)*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+fg+hi+jk))'" 12 O=!(a*(b+c+d)*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(ef+gh+ij+kl))'" 13 O=!(a*(b+c+d)*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de)(f+g+h+i))'" 10 O=!(a*(b+c+d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef)(g+h+i+j))'" 11 O=!(a*(b+c*d+e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg)(h+i+j+k))'" 12 O=!(a*(b*c+d*e+f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+g+h+i))'" 10 O=!(a*(b+c+d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+g+h+ij))'" 11 O=!(a*(b+c+d+e)*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+g+hi+jk))'" 12 O=!(a*(b+c+d+e)*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+gh+ij+kl))'" 13 O=!(a*(b+c+d+e)*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(fg+hi+jk+lm))'" 14 O=!(a*(b+c+d+e)*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f))'" 7 O=!((a+b)*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg))'" 8 O=!((a+b)*(c+d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh))'" 9 O=!((a+b)*(c+d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g))'" 8 O=!((a+b)*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+gh))'" 9 O=!((a+b)*(c+d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg+hi))'" 10 O=!((a+b)*(c+d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh+ij))'" 11 O=!((a+b)*(c+d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g+h))'" 9 O=!((a+b)*(c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g+hi))'" 10 O=!((a+b)*(c+d)*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+gh+ij))'" 11 O=!((a+b)*(c+d)*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg+hi+jk))'" 12 O=!((a+b)*(c+d)*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh+ij+kl))'" 13 O=!((a+b)*(c+d)*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)(f+g+h))'" 9 O=!((a+b)*(c+d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)(f+g+h+i))'" 10 O=!((a+b)*(c+d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)(g+h+i))'" 10 O=!((a+b)*(c*d+e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)(g+h+i+j))'" 11 O=!((a+b)*(c*d+e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h))'" 9 O=!((a+b)*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+hi))'" 10 O=!((a+b)*(c+d+e)*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+gh+ij))'" 11 O=!((a+b)*(c+d+e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(fg+hi+jk))'" 12 O=!((a+b)*(c+d+e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h+i))'" 10 O=!((a+b)*(c+d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h+ij))'" 11 O=!((a+b)*(c+d+e)*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+hi+jk))'" 12 O=!((a+b)*(c+d+e)*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+gh+ij+kl))'" 13 O=!((a+b)*(c+d+e)*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(fg+hi+jk+lm))'" 14 O=!((a+b)*(c+d+e)*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef)(g+h+i+j))'" 11 O=!((a+b)*(c+d+e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg)(h+i+j+k))'" 12 O=!((a+b)*(c+d*e+f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh)(i+j+k+l))'" 13 O=!((a+b)*(c*d+e*f+g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+h+i+j))'" 11 O=!((a+b)*(c+d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+h+i+jk))'" 12 O=!((a+b)*(c+d+e+f)*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+h+ij+kl))'" 13 O=!((a+b)*(c+d+e+f)*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+hi+jk+lm))'" 14 O=!((a+b)*(c+d+e+f)*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(gh+ij+kl+mn))'" 15 O=!((a+b)*(c+d+e+f)*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f)(g+h+i))'" 10 O=!((a+b*c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f)(g+h+i+j))'" 11 O=!((a+b*c)*(d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f+g)(h+i+j+k))'" 12 O=!((a+b*c)*(d+e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g)(h+i+j))'" 11 O=!((a*b+c*d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g)(h+i+j+k))'" 12 O=!((a*b+c*d)*(e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g+h)(i+j+k+l))'" 13 O=!((a*b+c*d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i))'" 10 O=!((a+b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+ij))'" 11 O=!((a+b+c)*(d+e+f)*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+hi+jk))'" 12 O=!((a+b+c)*(d+e+f)*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(gh+ij+kl))'" 13 O=!((a+b+c)*(d+e+f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i+j))'" 11 O=!((a+b+c)*(d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i+jk))'" 12 O=!((a+b+c)*(d+e+f)*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+ij+kl))'" 13 O=!((a+b+c)*(d+e+f)*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+hi+jk+lm))'" 14 O=!((a+b+c)*(d+e+f)*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(gh+ij+kl+mn))'" 15 O=!((a+b+c)*(d+e+f)*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg)(h+i+j+k))'" 12 O=!((a+b+c)*(d+e+f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh)(i+j+k+l))'" 13 O=!((a+b+c)*(d+e*f+g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi)(j+k+l+m))'" 14 O=!((a+b+c)*(d*e+f*g+h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+i+j+k))'" 12 O=!((a+b+c)*(d+e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+i+j+kl))'" 13 O=!((a+b+c)*(d+e+f+g)*(h+i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+i+jk+lm))'" 14 O=!((a+b+c)*(d+e+f+g)*(h+i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+ij+kl+mn))'" 15 O=!((a+b+c)*(d+e+f+g)*(h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(hi+jk+lm+no))'" 16 O=!((a+b+c)*(d+e+f+g)*(h*i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+g+h)(i+j+k+l))'" 13 O=!((a+b+c*d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+g+h+i)(j+k+l+m))'" 14 O=!((a+b*c+d*e)*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(g+h+i+j)(k+l+m+n))'" 15 O=!((a*b+c*d+e*f)*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+j+k+l))'" 13 O=!((a+b+c+d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+j+k+lm))'" 14 O=!((a+b+c+d)*(e+f+g+h)*(i+j+k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+j+kl+mn))'" 15 O=!((a+b+c+d)*(e+f+g+h)*(i+j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+jk+lm+no))'" 16 O=!((a+b+c+d)*(e+f+g+h)*(i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(ij+kl+mn+op))'" 17 O=!((a+b+c+d)*(e+f+g+h)*(i*j+k*l+m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd)'" 5 O=!(a*b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e))'" 6 O=!(a*b*c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e+f))'" 7 O=!(a*b*c*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e+f+g))'" 8 O=!(a*b*c*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f))'" 7 O=!(a*b*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f+g))'" 8 O=!(a*b*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f+g+h))'" 9 O=!(a*b*(c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e)(f+g+h))'" 9 O=!(a*b*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e)(f+g+h+i))'" 10 O=!(a*b*(c+d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e+f)(g+h+i+j))'" 11 O=!(a*b*(c+d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g))'" 8 O=!(a*(b+c)*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g+h))'" 9 O=!(a*(b+c)*(d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g+h+i))'" 10 O=!(a*(b+c)*(d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f)(g+h+i))'" 10 O=!(a*(b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f)(g+h+i+j))'" 11 O=!(a*(b+c)*(d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f+g)(h+i+j+k))'" 12 O=!(a*(b+c)*(d+e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g)(h+i+j))'" 11 O=!(a*(b+c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g)(h+i+j+k))'" 12 O=!(a*(b+c+d)*(e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g+h)(i+j+k+l))'" 13 O=!(a*(b+c+d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+g+h+i)(j+k+l+m))'" 14 O=!(a*(b+c+d+e)*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h))'" 9 O=!((a+b)*(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h+i))'" 10 O=!((a+b)*(c+d)*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h+i+j))'" 11 O=!((a+b)*(c+d)*(e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g)(h+i+j))'" 11 O=!((a+b)*(c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g)(h+i+j+k))'" 12 O=!((a+b)*(c+d)*(e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g+h)(i+j+k+l))'" 13 O=!((a+b)*(c+d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h)(i+j+k))'" 12 O=!((a+b)*(c+d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h)(i+j+k+l))'" 13 O=!((a+b)*(c+d+e)*(f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h+i)(j+k+l+m))'" 14 O=!((a+b)*(c+d+e)*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+h+i+j)(k+l+m+n))'" 15 O=!((a+b)*(c+d+e+f)*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i)(j+k+l))'" 13 O=!((a+b+c)*(d+e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i)(j+k+l+m))'" 14 O=!((a+b+c)*(d+e+f)*(g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i+j)(k+l+m+n))'" 15 O=!((a+b+c)*(d+e+f)*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+i+j+k)(l+m+n+o))'" 16 O=!((a+b+c)*(d+e+f+g)*(h+i+j+k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+j+k+l)(m+n+o+p))'" 17 O=!((a+b+c+d)*(e+f+g+h)*(i+j+k+l)*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b)'" 3 O=!(a+b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc)'" 4 O=!(a+b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d))'" 5 O=!(a+b*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+e))'" 6 O=!(a+b*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e))'" 6 O=!(a+(b+c)*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+f))'" 7 O=!(a+(b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+g))'" 8 O=!(a+(b+c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd)'" 5 O=!(a+b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e))'" 6 O=!(a+b*c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e+f))'" 7 O=!(a+b*c*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f))'" 7 O=!(a+b*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f+g))'" 8 O=!(a+b*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+e)(f+g+h))'" 9 O=!(a+b*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g))'" 8 O=!(a+(b+c)*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g+h))'" 9 O=!(a+(b+c)*(d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+f)(g+h+i))'" 10 O=!(a+(b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+g)(h+i+j))'" 11 O=!(a+(b+c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde)'" 6 O=!(a+b*c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd(e+f))'" 7 O=!(a+b*c*d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd(e+f+g))'" 8 O=!(a+b*c*d*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e)(f+g))'" 8 O=!(a+b*c*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e)(f+g+h))'" 9 O=!(a+b*c*(d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e+f)(g+h+i))'" 10 O=!(a+b*c*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f)(g+h))'" 9 O=!(a+b*(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f)(g+h+i))'" 10 O=!(a+b*(c+d)*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f+g)(h+i+j))'" 11 O=!(a+b*(c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+e)(f+g+h)(i+j+k))'" 12 O=!(a+b*(c+d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g)(h+i))'" 10 O=!(a+(b+c)*(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g)(h+i+j))'" 11 O=!(a+(b+c)*(d+e)*(f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g+h)(i+j+k))'" 12 O=!(a+(b+c)*(d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+f)(g+h+i)(j+k+l))'" 13 O=!(a+(b+c)*(d+e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+g)(h+i+j)(k+l+m))'" 14 O=!(a+(b+c+d)*(e+f+g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd)'" 5 O=!(a*b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e))'" 6 O=!(a*b+c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+f))'" 7 O=!(a*b+c*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f))'" 7 O=!(a*b+(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+g))'" 8 O=!(a*b+(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+h))'" 9 O=!(a*b+(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde)'" 6 O=!(a*b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f))'" 7 O=!(a*b+c*d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f+g))'" 8 O=!(a*b+c*d*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g))'" 8 O=!(a*b+c*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g+h))'" 9 O=!(a*b+c*(d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+f)(g+h+i))'" 10 O=!(a*b+c*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h))'" 9 O=!(a*b+(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h+i))'" 10 O=!(a*b+(c+d)*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+g)(h+i+j))'" 11 O=!(a*b+(c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+h)(i+j+k))'" 12 O=!(a*b+(c+d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef)'" 7 O=!(a*b+c*d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde(f+g))'" 8 O=!(a*b+c*d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde(f+g+h))'" 9 O=!(a*b+c*d*e*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f)(g+h))'" 9 O=!(a*b+c*d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f)(g+h+i))'" 10 O=!(a*b+c*d*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f+g)(h+i+j))'" 11 O=!(a*b+c*d*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g)(h+i))'" 10 O=!(a*b+c*(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g)(h+i+j))'" 11 O=!(a*b+c*(d+e)*(f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g+h)(i+j+k))'" 12 O=!(a*b+c*(d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+f)(g+h+i)(j+k+l))'" 13 O=!(a*b+c*(d+e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h)(i+j))'" 11 O=!(a*b+(c+d)*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h)(i+j+k))'" 12 O=!(a*b+(c+d)*(e+f)*(g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h+i)(j+k+l))'" 13 O=!(a*b+(c+d)*(e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+g)(h+i+j)(k+l+m))'" 14 O=!(a*b+(c+d)*(e+f+g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+h)(i+j+k)(l+m+n))'" 15 O=!(a*b+(c+d+e)*(f+g+h)*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(e+f))'" 7 O=!(a*(b+c)+d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(f+g))'" 8 O=!(a*(b+c)+(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+def)'" 7 O=!(a*(b+c)+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+de(f+g))'" 8 O=!(a*(b+c)+d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(e+f)(g+h))'" 9 O=!(a*(b+c)+d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(f+g)(h+i))'" 10 O=!(a*(b+c)+(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+defg)'" 8 O=!(a*(b+c)+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+def(g+h))'" 9 O=!(a*(b+c)+d*e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+de(f+g)(h+i))'" 10 O=!(a*(b+c)+d*e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(e+f)(g+h)(i+j))'" 11 O=!(a*(b+c)+d*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(f+g)(h+i)(j+k))'" 12 O=!(a*(b+c)+(d+e)*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)+efg)'" 8 O=!(a*(b+c+d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)+efgh)'" 9 O=!(a*(b+c+d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(g+h))'" 9 O=!((a+b)*(c+d)+(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efg)'" 8 O=!((a+b)*(c+d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+ef(g+h))'" 9 O=!((a+b)*(c+d)+e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+e(f+g)(h+i))'" 10 O=!((a+b)*(c+d)+e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(g+h)(i+j))'" 11 O=!((a+b)*(c+d)+(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efgh)'" 9 O=!((a+b)*(c+d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efg(h+i))'" 10 O=!((a+b)*(c+d)+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+ef(g+h)(i+j))'" 11 O=!((a+b)*(c+d)+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+e(f+g)(h+i)(j+k))'" 12 O=!((a+b)*(c+d)+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(g+h)(i+j)(k+l))'" 13 O=!((a+b)*(c+d)+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)+fgh)'" 9 O=!((a+b)*(c+d+e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)+fghi)'" 10 O=!((a+b)*(c+d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)+ghi)'" 10 O=!((a+b+c)*(d+e+f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)+ghij)'" 11 O=!((a+b+c)*(d+e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def)'" 7 O=!(a*b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g))'" 8 O=!(a*b*c+d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g+h))'" 9 O=!(a*b*c+d*e*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h))'" 9 O=!(a*b*c+d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h+i))'" 10 O=!(a*b*c+d*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f+g)(h+i+j))'" 11 O=!(a*b*c+d*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i))'" 10 O=!(a*b*c+(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i+j))'" 11 O=!(a*b*c+(d+e)*(f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g+h)(i+j+k))'" 12 O=!(a*b*c+(d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e+f)(g+h+i)(j+k+l))'" 13 O=!(a*b*c+(d+e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg)'" 8 O=!(a*b*c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def(g+h))'" 9 O=!(a*b*c+d*e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def(g+h+i))'" 10 O=!(a*b*c+d*e*f*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g)(h+i))'" 10 O=!(a*b*c+d*e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g)(h+i+j))'" 11 O=!(a*b*c+d*e*(f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g+h)(i+j+k))'" 12 O=!(a*b*c+d*e*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h)(i+j))'" 11 O=!(a*b*c+d*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h)(i+j+k))'" 12 O=!(a*b*c+d*(e+f)*(g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h+i)(j+k+l))'" 13 O=!(a*b*c+d*(e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f+g)(h+i+j)(k+l+m))'" 14 O=!(a*b*c+d*(e+f+g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i)(j+k))'" 12 O=!(a*b*c+(d+e)*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i)(j+k+l))'" 13 O=!(a*b*c+(d+e)*(f+g)*(h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i+j)(k+l+m))'" 14 O=!(a*b*c+(d+e)*(f+g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g+h)(i+j+k)(l+m+n))'" 15 O=!(a*b*c+(d+e)*(f+g+h)*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e+f)(g+h+i)(j+k+l)(m+n+o))'" 16 O=!(a*b*c+(d+e+f)*(g+h+i)*(j+k+l)*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+ef(g+h))'" 9 O=!(a*b*(c+d)+e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+e(f+g)(h+i))'" 10 O=!(a*b*(c+d)+e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+(e+f)(g+h)(i+j))'" 11 O=!(a*b*(c+d)+(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+efgh)'" 9 O=!(a*b*(c+d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+efg(h+i))'" 10 O=!(a*b*(c+d)+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+ef(g+h)(i+j))'" 11 O=!(a*b*(c+d)+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+e(f+g)(h+i)(j+k))'" 12 O=!(a*b*(c+d)+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+(e+f)(g+h)(i+j)(k+l))'" 13 O=!(a*b*(c+d)+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e)+fghi)'" 10 O=!(a*b*(c+d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+f(g+h)(i+j))'" 11 O=!(a*(b+c)*(d+e)+f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+(f+g)(h+i)(j+k))'" 12 O=!(a*(b+c)*(d+e)+(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+fghi)'" 10 O=!(a*(b+c)*(d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+fgh(i+j))'" 11 O=!(a*(b+c)*(d+e)+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+fg(h+i)(j+k))'" 12 O=!(a*(b+c)*(d+e)+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+f(g+h)(i+j)(k+l))'" 13 O=!(a*(b+c)*(d+e)+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a*(b+c)*(d+e)+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f)+ghij)'" 11 O=!(a*(b+c)*(d+e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g)+hijk)'" 12 O=!(a*(b+c+d)*(e+f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+(g+h)(i+j)(k+l))'" 13 O=!((a+b)*(c+d)*(e+f)+(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+ghij)'" 11 O=!((a+b)*(c+d)*(e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+ghi(j+k))'" 12 O=!((a+b)*(c+d)*(e+f)+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+gh(i+j)(k+l))'" 13 O=!((a+b)*(c+d)*(e+f)+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+g(h+i)(j+k)(l+m))'" 14 O=!((a+b)*(c+d)*(e+f)+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+(g+h)(i+j)(k+l)(m+n))'" 15 O=!((a+b)*(c+d)*(e+f)+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g)+hijk)'" 12 O=!((a+b)*(c+d)*(e+f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h)+ijkl)'" 13 O=!((a+b)*(c+d+e)*(f+g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i)+jklm)'" 14 O=!((a+b+c)*(d+e+f)*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh)'" 9 O=!(a*b*c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efg(h+i))'" 10 O=!(a*b*c*d+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efg(h+i+j))'" 11 O=!(a*b*c*d+e*f*g*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+ef(g+h)(i+j))'" 11 O=!(a*b*c*d+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+ef(g+h)(i+j+k))'" 12 O=!(a*b*c*d+e*f*(g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+ef(g+h+i)(j+k+l))'" 13 O=!(a*b*c*d+e*f*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+e(f+g)(h+i)(j+k))'" 12 O=!(a*b*c*d+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+e(f+g)(h+i)(j+k+l))'" 13 O=!(a*b*c*d+e*(f+g)*(h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+e(f+g)(h+i+j)(k+l+m))'" 14 O=!(a*b*c*d+e*(f+g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+e(f+g+h)(i+j+k)(l+m+n))'" 15 O=!(a*b*c*d+e*(f+g+h)*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f)(g+h)(i+j)(k+l))'" 13 O=!(a*b*c*d+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f)(g+h)(i+j)(k+l+m))'" 14 O=!(a*b*c*d+(e+f)*(g+h)*(i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f)(g+h)(i+j+k)(l+m+n))'" 15 O=!(a*b*c*d+(e+f)*(g+h)*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f)(g+h+i)(j+k+l)(m+n+o))'" 16 O=!(a*b*c*d+(e+f)*(g+h+i)*(j+k+l)*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f+g)(h+i+j)(k+l+m)(n+o+p))'" 17 O=!(a*b*c*d+(e+f+g)*(h+i+j)*(k+l+m)*(n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e)+fgh(i+j))'" 11 O=!(a*b*c*(d+e)+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e)+fg(h+i)(j+k))'" 12 O=!(a*b*c*(d+e)+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e)+f(g+h)(i+j)(k+l))'" 13 O=!(a*b*c*(d+e)+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e)+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a*b*c*(d+e)+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f)+gh(i+j)(k+l))'" 13 O=!(a*b*(c+d)*(e+f)+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f)+g(h+i)(j+k)(l+m))'" 14 O=!(a*b*(c+d)*(e+f)+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f)+(g+h)(i+j)(k+l)(m+n))'" 15 O=!(a*b*(c+d)*(e+f)+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g)+h(i+j)(k+l)(m+n))'" 15 O=!(a*(b+c)*(d+e)*(f+g)+h*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g)+(h+i)(j+k)(l+m)(n+o))'" 16 O=!(a*(b+c)*(d+e)*(f+g)+(h+i)*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h)+(i+j)(k+l)(m+n)(o+p))'" 17 O=!((a+b)*(c+d)*(e+f)*(g+h)+(i+j)*(k+l)*(m+n)*(o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c)'" 4 O=!(a+b+c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd)'" 5 O=!(a+b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(d+e))'" 6 O=!(a+b+c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(e+f))'" 7 O=!(a+b+(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde)'" 6 O=!(a+b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd(e+f))'" 7 O=!(a+b+c*d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(d+e)(f+g))'" 8 O=!(a+b+c*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(e+f)(g+h))'" 9 O=!(a+b+(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cdef)'" 7 O=!(a+b+c*d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde(f+g))'" 8 O=!(a+b+c*d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd(e+f)(g+h))'" 9 O=!(a+b+c*d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(d+e)(f+g)(h+i))'" 10 O=!(a+b+c*(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(e+f)(g+h)(i+j))'" 11 O=!(a+b+(c+d)*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de)'" 6 O=!(a+b*c+d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(e+f))'" 7 O=!(a+b*c+d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(f+g))'" 8 O=!(a+b*c+(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def)'" 7 O=!(a+b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de(f+g))'" 8 O=!(a+b*c+d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(e+f)(g+h))'" 9 O=!(a+b*c+d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(f+g)(h+i))'" 10 O=!(a+b*c+(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+defg)'" 8 O=!(a+b*c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def(g+h))'" 9 O=!(a+b*c+d*e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de(f+g)(h+i))'" 10 O=!(a+b*c+d*e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(e+f)(g+h)(i+j))'" 11 O=!(a+b*c+d*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(f+g)(h+i)(j+k))'" 12 O=!(a+b*c+(d+e)*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)+efg)'" 8 O=!(a+b*(c+d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)+efgh)'" 9 O=!(a+b*(c+d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)+fgh)'" 9 O=!(a+(b+c)*(d+e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)+fghi)'" 10 O=!(a+(b+c)*(d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg)'" 8 O=!(a+b*c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+ef(g+h))'" 9 O=!(a+b*c*d+e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+e(f+g)(h+i))'" 10 O=!(a+b*c*d+e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+(e+f)(g+h)(i+j))'" 11 O=!(a+b*c*d+(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efgh)'" 9 O=!(a+b*c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg(h+i))'" 10 O=!(a+b*c*d+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+ef(g+h)(i+j))'" 11 O=!(a+b*c*d+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+e(f+g)(h+i)(j+k))'" 12 O=!(a+b*c*d+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+(e+f)(g+h)(i+j)(k+l))'" 13 O=!(a+b*c*d+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e)+fghi)'" 10 O=!(a+b*c*(d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f)+ghij)'" 11 O=!(a+b*(c+d)*(e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g)+hijk)'" 12 O=!(a+(b+c)*(d+e)*(f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fghi)'" 10 O=!(a+b*c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fgh(i+j))'" 11 O=!(a+b*c*d*e+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fg(h+i)(j+k))'" 12 O=!(a+b*c*d*e+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+f(g+h)(i+j)(k+l))'" 13 O=!(a+b*c*d*e+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a+b*c*d*e+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef)'" 7 O=!(a*b+c*d+e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(f+g))'" 8 O=!(a*b+c*d+e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(g+h))'" 9 O=!(a*b+c*d+(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg)'" 8 O=!(a*b+c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef(g+h))'" 9 O=!(a*b+c*d+e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(f+g)(h+i))'" 10 O=!(a*b+c*d+e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(g+h)(i+j))'" 11 O=!(a*b+c*d+(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efgh)'" 9 O=!(a*b+c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg(h+i))'" 10 O=!(a*b+c*d+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef(g+h)(i+j))'" 11 O=!(a*b+c*d+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(f+g)(h+i)(j+k))'" 12 O=!(a*b+c*d+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(g+h)(i+j)(k+l))'" 13 O=!(a*b+c*d+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)+fgh)'" 9 O=!(a*b+c*(d+e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)+fghi)'" 10 O=!(a*b+c*(d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)+ghi)'" 10 O=!(a*b+(c+d)*(e+f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)+ghij)'" 11 O=!(a*b+(c+d)*(e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh)'" 9 O=!(a*b+c*d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fg(h+i))'" 10 O=!(a*b+c*d*e+f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+f(g+h)(i+j))'" 11 O=!(a*b+c*d*e+f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+(f+g)(h+i)(j+k))'" 12 O=!(a*b+c*d*e+(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fghi)'" 10 O=!(a*b+c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh(i+j))'" 11 O=!(a*b+c*d*e+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fg(h+i)(j+k))'" 12 O=!(a*b+c*d*e+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+f(g+h)(i+j)(k+l))'" 13 O=!(a*b+c*d*e+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a*b+c*d*e+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f)+ghij)'" 11 O=!(a*b+c*d*(e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g)+hijk)'" 12 O=!(a*b+c*(d+e)*(f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h)+ijkl)'" 13 O=!(a*b+(c+d)*(e+f)*(g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+ghij)'" 11 O=!(a*b+c*d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+ghi(j+k))'" 12 O=!(a*b+c*d*e*f+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+gh(i+j)(k+l))'" 13 O=!(a*b+c*d*e*f+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+g(h+i)(j+k)(l+m))'" 14 O=!(a*b+c*d*e*f+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+(g+h)(i+j)(k+l)(m+n))'" 15 O=!(a*b+c*d*e*f+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+def+ghi)'" 10 O=!(a*(b+c)+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+def+ghij)'" 11 O=!(a*(b+c)+d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+defg+hijk)'" 12 O=!(a*(b+c)+d*e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efg+hij)'" 11 O=!((a+b)*(c+d)+e*f*g+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efg+hijk)'" 12 O=!((a+b)*(c+d)+e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efgh+ijkl)'" 13 O=!((a+b)*(c+d)+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi)'" 10 O=!(a*b*c+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+gh(i+j))'" 11 O=!(a*b*c+d*e*f+g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+g(h+i)(j+k))'" 12 O=!(a*b*c+d*e*f+g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+(g+h)(i+j)(k+l))'" 13 O=!(a*b*c+d*e*f+(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghij)'" 11 O=!(a*b*c+d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi(j+k))'" 12 O=!(a*b*c+d*e*f+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+gh(i+j)(k+l))'" 13 O=!(a*b*c+d*e*f+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+g(h+i)(j+k)(l+m))'" 14 O=!(a*b*c+d*e*f+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+(g+h)(i+j)(k+l)(m+n))'" 15 O=!(a*b*c+d*e*f+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g)+hijk)'" 12 O=!(a*b*c+d*e*(f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h)+ijkl)'" 13 O=!(a*b*c+d*(e+f)*(g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i)+jklm)'" 14 O=!(a*b*c+(d+e)*(f+g)*(h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hijk)'" 12 O=!(a*b*c+d*e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hij(k+l))'" 13 O=!(a*b*c+d*e*f*g+h*i*j*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hi(j+k)(l+m))'" 14 O=!(a*b*c+d*e*f*g+h*i*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+h(i+j)(k+l)(m+n))'" 15 O=!(a*b*c+d*e*f*g+h*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+(h+i)(j+k)(l+m)(n+o))'" 16 O=!(a*b*c+d*e*f*g+(h+i)*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+efgh+ijkl)'" 13 O=!(a*b*(c+d)+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+fghi+jklm)'" 14 O=!(a*(b+c)*(d+e)+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+ghij+klmn)'" 15 O=!((a+b)*(c+d)*(e+f)+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ijkl)'" 13 O=!(a*b*c*d+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ijk(l+m))'" 14 O=!(a*b*c*d+e*f*g*h+i*j*k*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ij(k+l)(m+n))'" 15 O=!(a*b*c*d+e*f*g*h+i*j*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+i(j+k)(l+m)(n+o))'" 16 O=!(a*b*c*d+e*f*g*h+i*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+(i+j)(k+l)(m+n)(o+p))'" 17 O=!(a*b*c*d+e*f*g*h+(i+j)*(k+l)*(m+n)*(o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+d)'" 5 O=!(a+b+c+d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+de)'" 6 O=!(a+b+c+d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+def)'" 7 O=!(a+b+c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+defg)'" 8 O=!(a+b+c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd+ef)'" 7 O=!(a+b+c*d+e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd+efg)'" 8 O=!(a+b+c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd+efgh)'" 9 O=!(a+b+c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde+fgh)'" 9 O=!(a+b+c*d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde+fghi)'" 10 O=!(a+b+c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cdef+ghij)'" 11 O=!(a+b+c*d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de+fg)'" 8 O=!(a+b*c+d*e+f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de+fgh)'" 9 O=!(a+b*c+d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de+fghi)'" 10 O=!(a+b*c+d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def+ghi)'" 10 O=!(a+b*c+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def+ghij)'" 11 O=!(a+b*c+d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+defg+hijk)'" 12 O=!(a+b*c+d*e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg+hij)'" 11 O=!(a+b*c*d+e*f*g+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg+hijk)'" 12 O=!(a+b*c*d+e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efgh+ijkl)'" 13 O=!(a+b*c*d+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fghi+jklm)'" 14 O=!(a+b*c*d*e+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef+gh)'" 9 O=!(a*b+c*d+e*f+g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef+ghi)'" 10 O=!(a*b+c*d+e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef+ghij)'" 11 O=!(a*b+c*d+e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg+hij)'" 11 O=!(a*b+c*d+e*f*g+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg+hijk)'" 12 O=!(a*b+c*d+e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efgh+ijkl)'" 13 O=!(a*b+c*d+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh+ijk)'" 12 O=!(a*b+c*d*e+f*g*h+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh+ijkl)'" 13 O=!(a*b+c*d*e+f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fghi+jklm)'" 14 O=!(a*b+c*d*e+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+ghij+klmn)'" 15 O=!(a*b+c*d*e*f+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi+jkl)'" 13 O=!(a*b*c+d*e*f+g*h*i+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi+jklm)'" 14 O=!(a*b*c+d*e*f+g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghij+klmn)'" 15 O=!(a*b*c+d*e*f+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hijk+lmno)'" 16 O=!(a*b*c+d*e*f*g+h*i*j*k+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ijkl+mnop)'" 17 O=!(a*b*c*d+e*f*g*h+i*j*k*l+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/44-6.genlib b/sis/sis_lib/44-6.genlib new file mode 100644 index 0000000..8ad9bac --- /dev/null +++ b/sis/sis_lib/44-6.genlib @@ -0,0 +1,7008 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE "!a" 2 O=!a; +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab)'" 3 O=!(a*b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c))'" 4 O=!(a*(b+c)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd))'" 5 O=!(a*(b+c*d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e)))'" 6 O=!(a*(b+c*(d+e))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+ef)))'" 7 O=!(a*(b+c*(d+e*f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e(f+g))))'" 8 O=!(a*(b+c*(d+e*(f+g)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+(e+f)(g+h))))'" 9 O=!(a*(b+c*(d+(e+f)*(g+h)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(de+fg)))'" 8 O=!(a*(b+c*(d*e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(de+f(g+h))))'" 9 O=!(a*(b+c*(d*e+f*(g+h)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(de+(f+g)(h+i))))'" 10 O=!(a*(b+c*(d*e+(f+g)*(h+i)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e+f)))'" 7 O=!(a*(b+c*(d+e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e+fg)))'" 8 O=!(a*(b+c*(d+e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+ef+gh)))'" 9 O=!(a*(b+c*(d+e*f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(de+fg+hi)))'" 10 O=!(a*(b+c*(d*e+f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f)))'" 7 O=!(a*(b+(c+d)*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+fg)))'" 8 O=!(a*(b+(c+d)*(e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f(g+h))))'" 9 O=!(a*(b+(c+d)*(e+f*(g+h)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+(f+g)(h+i))))'" 10 O=!(a*(b+(c+d)*(e+(f+g)*(h+i)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(ef+gh)))'" 9 O=!(a*(b+(c+d)*(e*f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(ef+g(h+i))))'" 10 O=!(a*(b+(c+d)*(e*f+g*(h+i)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(ef+(g+h)(i+j))))'" 11 O=!(a*(b+(c+d)*(e*f+(g+h)*(i+j)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f+g)))'" 8 O=!(a*(b+(c+d)*(e+f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f+gh)))'" 9 O=!(a*(b+(c+d)*(e+f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+fg+hi)))'" 10 O=!(a*(b+(c+d)*(e+f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(ef+gh+ij)))'" 11 O=!(a*(b+(c+d)*(e*f+g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+de)(f+g+h)))'" 9 O=!(a*(b+(c+d*e)*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d(e+f))(g+h+i)))'" 10 O=!(a*(b+(c+d*(e+f))*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+(d+e)(f+g))(h+i+j)))'" 11 O=!(a*(b+(c+(d+e)*(f+g))*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(cd+ef)(g+h+i)))'" 10 O=!(a*(b+(c*d+e*f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(cd+e(f+g))(h+i+j)))'" 11 O=!(a*(b+(c*d+e*(f+g))*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(cd+(e+f)(g+h))(i+j+k)))'" 12 O=!(a*(b+(c*d+(e+f)*(g+h))*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d+e)(f+g+h)))'" 9 O=!(a*(b+(c+d+e)*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d+e)(f+g+hi)))'" 10 O=!(a*(b+(c+d+e)*(f+g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d+e)(f+gh+ij)))'" 11 O=!(a*(b+(c+d+e)*(f+g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d+e)(fg+hi+jk)))'" 12 O=!(a*(b+(c+d+e)*(f*g+h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde))'" 6 O=!(a*(b+c*d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd(e+f)))'" 7 O=!(a*(b+c*d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd(e+f+g)))'" 8 O=!(a*(b+c*d*(e+f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e)(f+g)))'" 8 O=!(a*(b+c*(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e)(f+g+h)))'" 9 O=!(a*(b+c*(d+e)*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e+f)(g+h+i)))'" 10 O=!(a*(b+c*(d+e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f)(g+h)))'" 9 O=!(a*(b+(c+d)*(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f)(g+h+i)))'" 10 O=!(a*(b+(c+d)*(e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f+g)(h+i+j)))'" 11 O=!(a*(b+(c+d)*(e+f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d+e)(f+g+h)(i+j+k)))'" 12 O=!(a*(b+(c+d+e)*(f+g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de))'" 6 O=!(a*(b*c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f)))'" 7 O=!(a*(b*c+d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+fg)))'" 8 O=!(a*(b*c+d*(e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f(g+h))))'" 9 O=!(a*(b*c+d*(e+f*(g+h)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+(f+g)(h+i))))'" 10 O=!(a*(b*c+d*(e+(f+g)*(h+i)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(ef+gh)))'" 9 O=!(a*(b*c+d*(e*f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(ef+g(h+i))))'" 10 O=!(a*(b*c+d*(e*f+g*(h+i)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(ef+(g+h)(i+j))))'" 11 O=!(a*(b*c+d*(e*f+(g+h)*(i+j)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f+g)))'" 8 O=!(a*(b*c+d*(e+f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f+gh)))'" 9 O=!(a*(b*c+d*(e+f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+fg+hi)))'" 10 O=!(a*(b*c+d*(e+f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(ef+gh+ij)))'" 11 O=!(a*(b*c+d*(e*f+g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g)))'" 8 O=!(a*(b*c+(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+gh)))'" 9 O=!(a*(b*c+(d+e)*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g(h+i))))'" 10 O=!(a*(b*c+(d+e)*(f+g*(h+i)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+(g+h)(i+j))))'" 11 O=!(a*(b*c+(d+e)*(f+(g+h)*(i+j)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(fg+hi)))'" 10 O=!(a*(b*c+(d+e)*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(fg+h(i+j))))'" 11 O=!(a*(b*c+(d+e)*(f*g+h*(i+j)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(fg+(h+i)(j+k))))'" 12 O=!(a*(b*c+(d+e)*(f*g+(h+i)*(j+k)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g+h)))'" 9 O=!(a*(b*c+(d+e)*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g+hi)))'" 10 O=!(a*(b*c+(d+e)*(f+g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+gh+ij)))'" 11 O=!(a*(b*c+(d+e)*(f+g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(fg+hi+jk)))'" 12 O=!(a*(b*c+(d+e)*(f*g+h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+ef)(g+h+i)))'" 10 O=!(a*(b*c+(d+e*f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e(f+g))(h+i+j)))'" 11 O=!(a*(b*c+(d+e*(f+g))*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+(e+f)(g+h))(i+j+k)))'" 12 O=!(a*(b*c+(d+(e+f)*(g+h))*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(de+fg)(h+i+j)))'" 11 O=!(a*(b*c+(d*e+f*g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(de+f(g+h))(i+j+k)))'" 12 O=!(a*(b*c+(d*e+f*(g+h))*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(de+(f+g)(h+i))(j+k+l)))'" 13 O=!(a*(b*c+(d*e+(f+g)*(h+i))*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e+f)(g+h+i)))'" 10 O=!(a*(b*c+(d+e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e+f)(g+h+ij)))'" 11 O=!(a*(b*c+(d+e+f)*(g+h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e+f)(g+hi+jk)))'" 12 O=!(a*(b*c+(d+e+f)*(g+h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e+f)(gh+ij+kl)))'" 13 O=!(a*(b*c+(d+e+f)*(g*h+i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def))'" 7 O=!(a*(b*c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de(f+g)))'" 8 O=!(a*(b*c+d*e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de(f+g+h)))'" 9 O=!(a*(b*c+d*e*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f)(g+h)))'" 9 O=!(a*(b*c+d*(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f)(g+h+i)))'" 10 O=!(a*(b*c+d*(e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f+g)(h+i+j)))'" 11 O=!(a*(b*c+d*(e+f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g)(h+i)))'" 10 O=!(a*(b*c+(d+e)*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g)(h+i+j)))'" 11 O=!(a*(b*c+(d+e)*(f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g+h)(i+j+k)))'" 12 O=!(a*(b*c+(d+e)*(f+g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e+f)(g+h+i)(j+k+l)))'" 13 O=!(a*(b*c+(d+e+f)*(g+h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+e(f+g)))'" 8 O=!(a*(b*(c+d)+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+e(f+gh)))'" 9 O=!(a*(b*(c+d)+e*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+e(fg+hi)))'" 10 O=!(a*(b*(c+d)+e*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+(e+f)(g+h)))'" 9 O=!(a*(b*(c+d)+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+(e+f)(g+hi)))'" 10 O=!(a*(b*(c+d)+(e+f)*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+(e+f)(gh+ij)))'" 11 O=!(a*(b*(c+d)+(e+f)*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+efg))'" 8 O=!(a*(b*(c+d)+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+ef(g+h)))'" 9 O=!(a*(b*(c+d)+e*f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+e(f+g)(h+i)))'" 10 O=!(a*(b*(c+d)+e*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+(e+f)(g+h)(i+j)))'" 11 O=!(a*(b*(c+d)+(e+f)*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+f(g+hi)))'" 10 O=!(a*(b*(c+d*e)+f*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+f(gh+ij)))'" 11 O=!(a*(b*(c+d*e)+f*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+(f+g)(h+i)))'" 10 O=!(a*(b*(c+d*e)+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+(f+g)(h+ij)))'" 11 O=!(a*(b*(c+d*e)+(f+g)*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+(f+g)(hi+jk)))'" 12 O=!(a*(b*(c+d*e)+(f+g)*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+fgh))'" 9 O=!(a*(b*(c+d*e)+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+fg(h+i)))'" 10 O=!(a*(b*(c+d*e)+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+f(g+h)(i+j)))'" 11 O=!(a*(b*(c+d*e)+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+(f+g)(h+i)(j+k)))'" 12 O=!(a*(b*(c+d*e)+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d(e+f))+ghi))'" 10 O=!(a*(b*(c+d*(e+f))+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+(d+e)(f+g))+hij))'" 11 O=!(a*(b*(c+(d+e)*(f+g))+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+g(hi+jk)))'" 12 O=!(a*(b*(c*d+e*f)+g*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+(g+h)(i+j)))'" 11 O=!(a*(b*(c*d+e*f)+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+(g+h)(i+jk)))'" 12 O=!(a*(b*(c*d+e*f)+(g+h)*(i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+(g+h)(ij+kl)))'" 13 O=!(a*(b*(c*d+e*f)+(g+h)*(i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+ghi))'" 10 O=!(a*(b*(c*d+e*f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+gh(i+j)))'" 11 O=!(a*(b*(c*d+e*f)+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+g(h+i)(j+k)))'" 12 O=!(a*(b*(c*d+e*f)+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+(g+h)(i+j)(k+l)))'" 13 O=!(a*(b*(c*d+e*f)+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+e(f+g))+hij))'" 11 O=!(a*(b*(c*d+e*(f+g))+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+(e+f)(g+h))+ijk))'" 12 O=!(a*(b*(c*d+(e+f)*(g+h))+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d+e)+fgh))'" 9 O=!(a*(b*(c+d+e)+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d+ef)+ghi))'" 10 O=!(a*(b*(c+d+e*f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de+fg)+hij))'" 11 O=!(a*(b*(c+d*e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef+gh)+ijk))'" 12 O=!(a*(b*(c*d+e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+(f+g)(h+i)))'" 10 O=!(a*((b+c)*(d+e)+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+(f+g)(h+ij)))'" 11 O=!(a*((b+c)*(d+e)+(f+g)*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+(f+g)(hi+jk)))'" 12 O=!(a*((b+c)*(d+e)+(f+g)*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+fgh))'" 9 O=!(a*((b+c)*(d+e)+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+fg(h+i)))'" 10 O=!(a*((b+c)*(d+e)+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+f(g+h)(i+j)))'" 11 O=!(a*((b+c)*(d+e)+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+(f+g)(h+i)(j+k)))'" 12 O=!(a*((b+c)*(d+e)+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef)+(g+h)(i+jk)))'" 12 O=!(a*((b+c)*(d+e*f)+(g+h)*(i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef)+(g+h)(ij+kl)))'" 13 O=!(a*((b+c)*(d+e*f)+(g+h)*(i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef)+ghi))'" 10 O=!(a*((b+c)*(d+e*f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef)+gh(i+j)))'" 11 O=!(a*((b+c)*(d+e*f)+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef)+g(h+i)(j+k)))'" 12 O=!(a*((b+c)*(d+e*f)+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef)+(g+h)(i+j)(k+l)))'" 13 O=!(a*((b+c)*(d+e*f)+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e(f+g))+hij))'" 11 O=!(a*((b+c)*(d+e*(f+g))+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+(e+f)(g+h))+ijk))'" 12 O=!(a*((b+c)*(d+(e+f)*(g+h))+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+fg)+(h+i)(jk+lm)))'" 14 O=!(a*((b+c)*(d*e+f*g)+(h+i)*(j*k+l*m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+fg)+hij))'" 11 O=!(a*((b+c)*(d*e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+fg)+hi(j+k)))'" 12 O=!(a*((b+c)*(d*e+f*g)+h*i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+fg)+h(i+j)(k+l)))'" 13 O=!(a*((b+c)*(d*e+f*g)+h*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+fg)+(h+i)(j+k)(l+m)))'" 14 O=!(a*((b+c)*(d*e+f*g)+(h+i)*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+f(g+h))+ijk))'" 12 O=!(a*((b+c)*(d*e+f*(g+h))+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+(f+g)(h+i))+jkl))'" 13 O=!(a*((b+c)*(d*e+(f+g)*(h+i))+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e+f)+ghi))'" 10 O=!(a*((b+c)*(d+e+f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e+fg)+hij))'" 11 O=!(a*((b+c)*(d+e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef+gh)+ijk))'" 12 O=!(a*((b+c)*(d+e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+fg+hi)+jkl))'" 13 O=!(a*((b+c)*(d*e+f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+cd)(e+f+g)+hij))'" 11 O=!(a*((b+c*d)*(e+f+g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c(d+e))(f+g+h)+ijk))'" 12 O=!(a*((b+c*(d+e))*(f+g+h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+(c+d)(e+f))(g+h+i)+jkl))'" 13 O=!(a*((b+(c+d)*(e+f))*(g+h+i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((bc+de)(f+g+h)+ijk))'" 12 O=!(a*((b*c+d*e)*(f+g+h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((bc+d(e+f))(g+h+i)+jkl))'" 13 O=!(a*((b*c+d*(e+f))*(g+h+i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((bc+(d+e)(f+g))(h+i+j)+klm))'" 14 O=!(a*((b*c+(d+e)*(f+g))*(h+i+j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c+d)(e+f+g)+hij))'" 11 O=!(a*((b+c+d)*(e+f+g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c+d)(e+f+gh)+ijk))'" 12 O=!(a*((b+c+d)*(e+f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c+d)(e+fg+hi)+jkl))'" 13 O=!(a*((b+c+d)*(e+f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c+d)(ef+gh+ij)+klm))'" 14 O=!(a*((b+c+d)*(e*f+g*h+i*j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg))'" 8 O=!(a*(b*c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+ef(g+h)))'" 9 O=!(a*(b*c*d+e*f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+ef(g+h+i)))'" 10 O=!(a*(b*c*d+e*f*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+e(f+g)(h+i)))'" 10 O=!(a*(b*c*d+e*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+e(f+g)(h+i+j)))'" 11 O=!(a*(b*c*d+e*(f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+e(f+g+h)(i+j+k)))'" 12 O=!(a*(b*c*d+e*(f+g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+(e+f)(g+h)(i+j)))'" 11 O=!(a*(b*c*d+(e+f)*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+(e+f)(g+h)(i+j+k)))'" 12 O=!(a*(b*c*d+(e+f)*(g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+(e+f)(g+h+i)(j+k+l)))'" 13 O=!(a*(b*c*d+(e+f)*(g+h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+(e+f+g)(h+i+j)(k+l+m)))'" 14 O=!(a*(b*c*d+(e+f+g)*(h+i+j)*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc(d+e)+fg(h+i)))'" 10 O=!(a*(b*c*(d+e)+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc(d+e)+f(g+h)(i+j)))'" 11 O=!(a*(b*c*(d+e)+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc(d+e)+(f+g)(h+i)(j+k)))'" 12 O=!(a*(b*c*(d+e)+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)(e+f)+g(h+i)(j+k)))'" 12 O=!(a*(b*(c+d)*(e+f)+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)(e+f)+(g+h)(i+j)(k+l)))'" 13 O=!(a*(b*(c+d)*(e+f)+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)(f+g)+(h+i)(j+k)(l+m)))'" 14 O=!(a*((b+c)*(d+e)*(f+g)+(h+i)*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d))'" 5 O=!(a*(b+c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de))'" 6 O=!(a*(b+c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d(e+f)))'" 7 O=!(a*(b+c+d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d(e+fg)))'" 8 O=!(a*(b+c+d*(e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d(ef+gh)))'" 9 O=!(a*(b+c+d*(e*f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+(d+e)(f+g)))'" 8 O=!(a*(b+c+(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+(d+e)(f+gh)))'" 9 O=!(a*(b+c+(d+e)*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+(d+e)(fg+hi)))'" 10 O=!(a*(b+c+(d+e)*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+def))'" 7 O=!(a*(b+c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de(f+g)))'" 8 O=!(a*(b+c+d*e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d(e+f)(g+h)))'" 9 O=!(a*(b+c+d*(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+(d+e)(f+g)(h+i)))'" 10 O=!(a*(b+c+(d+e)*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef))'" 7 O=!(a*(b+c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+e(f+g)))'" 8 O=!(a*(b+c*d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+e(f+gh)))'" 9 O=!(a*(b+c*d+e*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+e(fg+hi)))'" 10 O=!(a*(b+c*d+e*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+(e+f)(g+h)))'" 9 O=!(a*(b+c*d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+(e+f)(g+hi)))'" 10 O=!(a*(b+c*d+(e+f)*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+(e+f)(gh+ij)))'" 11 O=!(a*(b+c*d+(e+f)*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+efg))'" 8 O=!(a*(b+c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef(g+h)))'" 9 O=!(a*(b+c*d+e*f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+e(f+g)(h+i)))'" 10 O=!(a*(b+c*d+e*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+(e+f)(g+h)(i+j)))'" 11 O=!(a*(b+c*d+(e+f)*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e)+fgh))'" 9 O=!(a*(b+c*(d+e)+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+ef)+ghi))'" 10 O=!(a*(b+c*(d+e*f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(de+fg)+hij))'" 11 O=!(a*(b+c*(d*e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f)+ghi))'" 10 O=!(a*(b+(c+d)*(e+f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+fg)+hij))'" 11 O=!(a*(b+(c+d)*(e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(ef+gh)+ijk))'" 12 O=!(a*(b+(c+d)*(e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde+fgh))'" 9 O=!(a*(b+c*d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde+fg(h+i)))'" 10 O=!(a*(b+c*d*e+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde+f(g+h)(i+j)))'" 11 O=!(a*(b+c*d*e+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde+(f+g)(h+i)(j+k)))'" 12 O=!(a*(b+c*d*e+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg))'" 8 O=!(a*(b*c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+f(g+h)))'" 9 O=!(a*(b*c+d*e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+f(g+hi)))'" 10 O=!(a*(b*c+d*e+f*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+f(gh+ij)))'" 11 O=!(a*(b*c+d*e+f*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+(f+g)(h+i)))'" 10 O=!(a*(b*c+d*e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+(f+g)(h+ij)))'" 11 O=!(a*(b*c+d*e+(f+g)*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+(f+g)(hi+jk)))'" 12 O=!(a*(b*c+d*e+(f+g)*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fgh))'" 9 O=!(a*(b*c+d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg(h+i)))'" 10 O=!(a*(b*c+d*e+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+f(g+h)(i+j)))'" 11 O=!(a*(b*c+d*e+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+(f+g)(h+i)(j+k)))'" 12 O=!(a*(b*c+d*e+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f)+ghi))'" 10 O=!(a*(b*c+d*(e+f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+fg)+hij))'" 11 O=!(a*(b*c+d*(e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(ef+gh)+ijk))'" 12 O=!(a*(b*c+d*(e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g)+hij))'" 11 O=!(a*(b*c+(d+e)*(f+g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+gh)+ijk))'" 12 O=!(a*(b*c+(d+e)*(f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(fg+hi)+jkl))'" 13 O=!(a*(b*c+(d+e)*(f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def+ghi))'" 10 O=!(a*(b*c+d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def+gh(i+j)))'" 11 O=!(a*(b*c+d*e*f+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def+g(h+i)(j+k)))'" 12 O=!(a*(b*c+d*e*f+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def+(g+h)(i+j)(k+l)))'" 13 O=!(a*(b*c+d*e*f+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+efg+hij))'" 11 O=!(a*(b*(c+d)+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+fgh+ijk))'" 12 O=!(a*(b*(c+d*e)+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+ghi+jkl))'" 13 O=!(a*(b*(c*d+e*f)+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+fgh+ijk))'" 12 O=!(a*((b+c)*(d+e)+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef)+ghi+jkl))'" 13 O=!(a*((b+c)*(d+e*f)+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+fg)+hij+klm))'" 14 O=!(a*((b+c)*(d*e+f*g)+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg+hij))'" 11 O=!(a*(b*c*d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg+hi(j+k)))'" 12 O=!(a*(b*c*d+e*f*g+h*i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg+h(i+j)(k+l)))'" 13 O=!(a*(b*c*d+e*f*g+h*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg+(h+i)(j+k)(l+m)))'" 14 O=!(a*(b*c*d+e*f*g+(h+i)*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e))'" 6 O=!(a*(b+c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+ef))'" 7 O=!(a*(b+c+d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+efg))'" 8 O=!(a*(b+c+d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de+fg))'" 8 O=!(a*(b+c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de+fgh))'" 9 O=!(a*(b+c+d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+def+ghi))'" 10 O=!(a*(b+c+d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef+gh))'" 9 O=!(a*(b+c*d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef+ghi))'" 10 O=!(a*(b+c*d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+efg+hij))'" 11 O=!(a*(b+c*d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde+fgh+ijk))'" 12 O=!(a*(b+c*d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg+hi))'" 10 O=!(a*(b*c+d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg+hij))'" 11 O=!(a*(b*c+d*e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fgh+ijk))'" 12 O=!(a*(b*c+d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def+ghi+jkl))'" 13 O=!(a*(b*c+d*e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg+hij+klm))'" 14 O=!(a*(b*c*d+e*f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d))'" 5 O=!((a+b)*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de))'" 6 O=!((a+b)*(c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f)))'" 7 O=!((a+b)*(c+d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+fg)))'" 8 O=!((a+b)*(c+d*(e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f(g+h))))'" 9 O=!((a+b)*(c+d*(e+f*(g+h)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+(f+g)(h+i))))'" 10 O=!((a+b)*(c+d*(e+(f+g)*(h+i)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(ef+gh)))'" 9 O=!((a+b)*(c+d*(e*f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(ef+g(h+i))))'" 10 O=!((a+b)*(c+d*(e*f+g*(h+i)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(ef+(g+h)(i+j))))'" 11 O=!((a+b)*(c+d*(e*f+(g+h)*(i+j)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f+g)))'" 8 O=!((a+b)*(c+d*(e+f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f+gh)))'" 9 O=!((a+b)*(c+d*(e+f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+fg+hi)))'" 10 O=!((a+b)*(c+d*(e+f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(ef+gh+ij)))'" 11 O=!((a+b)*(c+d*(e*f+g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g)))'" 8 O=!((a+b)*(c+(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+gh)))'" 9 O=!((a+b)*(c+(d+e)*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g(h+i))))'" 10 O=!((a+b)*(c+(d+e)*(f+g*(h+i)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+(g+h)(i+j))))'" 11 O=!((a+b)*(c+(d+e)*(f+(g+h)*(i+j)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(fg+hi)))'" 10 O=!((a+b)*(c+(d+e)*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(fg+h(i+j))))'" 11 O=!((a+b)*(c+(d+e)*(f*g+h*(i+j)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(fg+(h+i)(j+k))))'" 12 O=!((a+b)*(c+(d+e)*(f*g+(h+i)*(j+k)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g+h)))'" 9 O=!((a+b)*(c+(d+e)*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g+hi)))'" 10 O=!((a+b)*(c+(d+e)*(f+g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+gh+ij)))'" 11 O=!((a+b)*(c+(d+e)*(f+g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(fg+hi+jk)))'" 12 O=!((a+b)*(c+(d+e)*(f*g+h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+ef)(g+h+i)))'" 10 O=!((a+b)*(c+(d+e*f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e(f+g))(h+i+j)))'" 11 O=!((a+b)*(c+(d+e*(f+g))*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+(e+f)(g+h))(i+j+k)))'" 12 O=!((a+b)*(c+(d+(e+f)*(g+h))*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(de+fg)(h+i+j)))'" 11 O=!((a+b)*(c+(d*e+f*g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(de+f(g+h))(i+j+k)))'" 12 O=!((a+b)*(c+(d*e+f*(g+h))*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(de+(f+g)(h+i))(j+k+l)))'" 13 O=!((a+b)*(c+(d*e+(f+g)*(h+i))*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e+f)(g+h+i)))'" 10 O=!((a+b)*(c+(d+e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e+f)(g+h+ij)))'" 11 O=!((a+b)*(c+(d+e+f)*(g+h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e+f)(g+hi+jk)))'" 12 O=!((a+b)*(c+(d+e+f)*(g+h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e+f)(gh+ij+kl)))'" 13 O=!((a+b)*(c+(d+e+f)*(g*h+i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def))'" 7 O=!((a+b)*(c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de(f+g)))'" 8 O=!((a+b)*(c+d*e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de(f+g+h)))'" 9 O=!((a+b)*(c+d*e*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f)(g+h)))'" 9 O=!((a+b)*(c+d*(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f)(g+h+i)))'" 10 O=!((a+b)*(c+d*(e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f+g)(h+i+j)))'" 11 O=!((a+b)*(c+d*(e+f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g)(h+i)))'" 10 O=!((a+b)*(c+(d+e)*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g)(h+i+j)))'" 11 O=!((a+b)*(c+(d+e)*(f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g+h)(i+j+k)))'" 12 O=!((a+b)*(c+(d+e)*(f+g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e+f)(g+h+i)(j+k+l)))'" 13 O=!((a+b)*(c+(d+e+f)*(g+h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef))'" 7 O=!((a+b)*(c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g)))'" 8 O=!((a+b)*(c*d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+gh)))'" 9 O=!((a+b)*(c*d+e*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g(h+i))))'" 10 O=!((a+b)*(c*d+e*(f+g*(h+i)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+(g+h)(i+j))))'" 11 O=!((a+b)*(c*d+e*(f+(g+h)*(i+j)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(fg+hi)))'" 10 O=!((a+b)*(c*d+e*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(fg+h(i+j))))'" 11 O=!((a+b)*(c*d+e*(f*g+h*(i+j)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(fg+(h+i)(j+k))))'" 12 O=!((a+b)*(c*d+e*(f*g+(h+i)*(j+k)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g+h)))'" 9 O=!((a+b)*(c*d+e*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g+hi)))'" 10 O=!((a+b)*(c*d+e*(f+g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+gh+ij)))'" 11 O=!((a+b)*(c*d+e*(f+g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(fg+hi+jk)))'" 12 O=!((a+b)*(c*d+e*(f*g+h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h)))'" 9 O=!((a+b)*(c*d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+hi)))'" 10 O=!((a+b)*(c*d+(e+f)*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h(i+j))))'" 11 O=!((a+b)*(c*d+(e+f)*(g+h*(i+j)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+(h+i)(j+k))))'" 12 O=!((a+b)*(c*d+(e+f)*(g+(h+i)*(j+k)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(gh+ij)))'" 11 O=!((a+b)*(c*d+(e+f)*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(gh+i(j+k))))'" 12 O=!((a+b)*(c*d+(e+f)*(g*h+i*(j+k)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(gh+(i+j)(k+l))))'" 13 O=!((a+b)*(c*d+(e+f)*(g*h+(i+j)*(k+l)))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h+i)))'" 10 O=!((a+b)*(c*d+(e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h+ij)))'" 11 O=!((a+b)*(c*d+(e+f)*(g+h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+hi+jk)))'" 12 O=!((a+b)*(c*d+(e+f)*(g+h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(gh+ij+kl)))'" 13 O=!((a+b)*(c*d+(e+f)*(g*h+i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+fg)(h+i+j)))'" 11 O=!((a+b)*(c*d+(e+f*g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f(g+h))(i+j+k)))'" 12 O=!((a+b)*(c*d+(e+f*(g+h))*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+(f+g)(h+i))(j+k+l)))'" 13 O=!((a+b)*(c*d+(e+(f+g)*(h+i))*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(ef+gh)(i+j+k)))'" 12 O=!((a+b)*(c*d+(e*f+g*h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(ef+g(h+i))(j+k+l)))'" 13 O=!((a+b)*(c*d+(e*f+g*(h+i))*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(ef+(g+h)(i+j))(k+l+m)))'" 14 O=!((a+b)*(c*d+(e*f+(g+h)*(i+j))*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f+g)(h+i+j)))'" 11 O=!((a+b)*(c*d+(e+f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f+g)(h+i+jk)))'" 12 O=!((a+b)*(c*d+(e+f+g)*(h+i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f+g)(h+ij+kl)))'" 13 O=!((a+b)*(c*d+(e+f+g)*(h+i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f+g)(hi+jk+lm)))'" 14 O=!((a+b)*(c*d+(e+f+g)*(h*i+j*k+l*m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg))'" 8 O=!((a+b)*(c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef(g+h)))'" 9 O=!((a+b)*(c*d+e*f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef(g+h+i)))'" 10 O=!((a+b)*(c*d+e*f*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g)(h+i)))'" 10 O=!((a+b)*(c*d+e*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g)(h+i+j)))'" 11 O=!((a+b)*(c*d+e*(f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g+h)(i+j+k)))'" 12 O=!((a+b)*(c*d+e*(f+g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h)(i+j)))'" 11 O=!((a+b)*(c*d+(e+f)*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h)(i+j+k)))'" 12 O=!((a+b)*(c*d+(e+f)*(g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h+i)(j+k+l)))'" 13 O=!((a+b)*(c*d+(e+f)*(g+h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f+g)(h+i+j)(k+l+m)))'" 14 O=!((a+b)*(c*d+(e+f+g)*(h+i+j)*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+f(g+h)))'" 9 O=!((a+b)*(c*(d+e)+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+f(g+hi)))'" 10 O=!((a+b)*(c*(d+e)+f*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+f(gh+ij)))'" 11 O=!((a+b)*(c*(d+e)+f*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+(f+g)(h+i)))'" 10 O=!((a+b)*(c*(d+e)+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+(f+g)(h+ij)))'" 11 O=!((a+b)*(c*(d+e)+(f+g)*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+(f+g)(hi+jk)))'" 12 O=!((a+b)*(c*(d+e)+(f+g)*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+fgh))'" 9 O=!((a+b)*(c*(d+e)+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+fg(h+i)))'" 10 O=!((a+b)*(c*(d+e)+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+f(g+h)(i+j)))'" 11 O=!((a+b)*(c*(d+e)+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+(f+g)(h+i)(j+k)))'" 12 O=!((a+b)*(c*(d+e)+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+g(h+ij)))'" 11 O=!((a+b)*(c*(d+e*f)+g*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+g(hi+jk)))'" 12 O=!((a+b)*(c*(d+e*f)+g*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+(g+h)(i+j)))'" 11 O=!((a+b)*(c*(d+e*f)+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+(g+h)(i+jk)))'" 12 O=!((a+b)*(c*(d+e*f)+(g+h)*(i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+(g+h)(ij+kl)))'" 13 O=!((a+b)*(c*(d+e*f)+(g+h)*(i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+ghi))'" 10 O=!((a+b)*(c*(d+e*f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+gh(i+j)))'" 11 O=!((a+b)*(c*(d+e*f)+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+g(h+i)(j+k)))'" 12 O=!((a+b)*(c*(d+e*f)+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+(g+h)(i+j)(k+l)))'" 13 O=!((a+b)*(c*(d+e*f)+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e(f+g))+hij))'" 11 O=!((a+b)*(c*(d+e*(f+g))+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+(e+f)(g+h))+ijk))'" 12 O=!((a+b)*(c*(d+(e+f)*(g+h))+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+h(ij+kl)))'" 13 O=!((a+b)*(c*(d*e+f*g)+h*(i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+(h+i)(j+k)))'" 12 O=!((a+b)*(c*(d*e+f*g)+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+(h+i)(j+kl)))'" 13 O=!((a+b)*(c*(d*e+f*g)+(h+i)*(j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+(h+i)(jk+lm)))'" 14 O=!((a+b)*(c*(d*e+f*g)+(h+i)*(j*k+l*m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+hij))'" 11 O=!((a+b)*(c*(d*e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+hi(j+k)))'" 12 O=!((a+b)*(c*(d*e+f*g)+h*i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+h(i+j)(k+l)))'" 13 O=!((a+b)*(c*(d*e+f*g)+h*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+(h+i)(j+k)(l+m)))'" 14 O=!((a+b)*(c*(d*e+f*g)+(h+i)*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+f(g+h))+ijk))'" 12 O=!((a+b)*(c*(d*e+f*(g+h))+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+(f+g)(h+i))+jkl))'" 13 O=!((a+b)*(c*(d*e+(f+g)*(h+i))+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e+f)+ghi))'" 10 O=!((a+b)*(c*(d+e+f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e+fg)+hij))'" 11 O=!((a+b)*(c*(d+e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef+gh)+ijk))'" 12 O=!((a+b)*(c*(d+e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg+hi)+jkl))'" 13 O=!((a+b)*(c*(d*e+f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+(g+h)(i+j)))'" 11 O=!((a+b)*((c+d)*(e+f)+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+(g+h)(i+jk)))'" 12 O=!((a+b)*((c+d)*(e+f)+(g+h)*(i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+(g+h)(ij+kl)))'" 13 O=!((a+b)*((c+d)*(e+f)+(g+h)*(i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+ghi))'" 10 O=!((a+b)*((c+d)*(e+f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+gh(i+j)))'" 11 O=!((a+b)*((c+d)*(e+f)+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+g(h+i)(j+k)))'" 12 O=!((a+b)*((c+d)*(e+f)+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+(g+h)(i+j)(k+l)))'" 13 O=!((a+b)*((c+d)*(e+f)+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg)+(h+i)(j+kl)))'" 13 O=!((a+b)*((c+d)*(e+f*g)+(h+i)*(j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg)+(h+i)(jk+lm)))'" 14 O=!((a+b)*((c+d)*(e+f*g)+(h+i)*(j*k+l*m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg)+hij))'" 11 O=!((a+b)*((c+d)*(e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg)+hi(j+k)))'" 12 O=!((a+b)*((c+d)*(e+f*g)+h*i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg)+h(i+j)(k+l)))'" 13 O=!((a+b)*((c+d)*(e+f*g)+h*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg)+(h+i)(j+k)(l+m)))'" 14 O=!((a+b)*((c+d)*(e+f*g)+(h+i)*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f(g+h))+ijk))'" 12 O=!((a+b)*((c+d)*(e+f*(g+h))+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+(f+g)(h+i))+jkl))'" 13 O=!((a+b)*((c+d)*(e+(f+g)*(h+i))+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+gh)+(i+j)(kl+mn)))'" 15 O=!((a+b)*((c+d)*(e*f+g*h)+(i+j)*(k*l+m*n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+gh)+ijk))'" 12 O=!((a+b)*((c+d)*(e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+gh)+ij(k+l)))'" 13 O=!((a+b)*((c+d)*(e*f+g*h)+i*j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+gh)+i(j+k)(l+m)))'" 14 O=!((a+b)*((c+d)*(e*f+g*h)+i*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+gh)+(i+j)(k+l)(m+n)))'" 15 O=!((a+b)*((c+d)*(e*f+g*h)+(i+j)*(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+g(h+i))+jkl))'" 13 O=!((a+b)*((c+d)*(e*f+g*(h+i))+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+(g+h)(i+j))+klm))'" 14 O=!((a+b)*((c+d)*(e*f+(g+h)*(i+j))+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f+g)+hij))'" 11 O=!((a+b)*((c+d)*(e+f+g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f+gh)+ijk))'" 12 O=!((a+b)*((c+d)*(e+f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg+hi)+jkl))'" 13 O=!((a+b)*((c+d)*(e+f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+gh+ij)+klm))'" 14 O=!((a+b)*((c+d)*(e*f+g*h+i*j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+de)(f+g+h)+ijk))'" 12 O=!((a+b)*((c+d*e)*(f+g+h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d(e+f))(g+h+i)+jkl))'" 13 O=!((a+b)*((c+d*(e+f))*(g+h+i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+(d+e)(f+g))(h+i+j)+klm))'" 14 O=!((a+b)*((c+(d+e)*(f+g))*(h+i+j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((cd+ef)(g+h+i)+jkl))'" 13 O=!((a+b)*((c*d+e*f)*(g+h+i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((cd+e(f+g))(h+i+j)+klm))'" 14 O=!((a+b)*((c*d+e*(f+g))*(h+i+j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((cd+(e+f)(g+h))(i+j+k)+lmn))'" 15 O=!((a+b)*((c*d+(e+f)*(g+h))*(i+j+k)+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d+e)(f+g+h)+ijk))'" 12 O=!((a+b)*((c+d+e)*(f+g+h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d+e)(f+g+hi)+jkl))'" 13 O=!((a+b)*((c+d+e)*(f+g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d+e)(f+gh+ij)+klm))'" 14 O=!((a+b)*((c+d+e)*(f+g*h+i*j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d+e)(fg+hi+jk)+lmn))'" 15 O=!((a+b)*((c+d+e)*(f*g+h*i+j*k)+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh))'" 9 O=!((a+b)*(c*d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fg(h+i)))'" 10 O=!((a+b)*(c*d*e+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fg(h+i+j)))'" 11 O=!((a+b)*(c*d*e+f*g*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+f(g+h)(i+j)))'" 11 O=!((a+b)*(c*d*e+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+f(g+h)(i+j+k)))'" 12 O=!((a+b)*(c*d*e+f*(g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+f(g+h+i)(j+k+l)))'" 13 O=!((a+b)*(c*d*e+f*(g+h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+(f+g)(h+i)(j+k)))'" 12 O=!((a+b)*(c*d*e+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+(f+g)(h+i)(j+k+l)))'" 13 O=!((a+b)*(c*d*e+(f+g)*(h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+(f+g)(h+i+j)(k+l+m)))'" 14 O=!((a+b)*(c*d*e+(f+g)*(h+i+j)*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+(f+g+h)(i+j+k)(l+m+n)))'" 15 O=!((a+b)*(c*d*e+(f+g+h)*(i+j+k)*(l+m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd(e+f)+gh(i+j)))'" 11 O=!((a+b)*(c*d*(e+f)+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd(e+f)+g(h+i)(j+k)))'" 12 O=!((a+b)*(c*d*(e+f)+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd(e+f)+(g+h)(i+j)(k+l)))'" 13 O=!((a+b)*(c*d*(e+f)+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)(f+g)+h(i+j)(k+l)))'" 13 O=!((a+b)*(c*(d+e)*(f+g)+h*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)(f+g)+(h+i)(j+k)(l+m)))'" 14 O=!((a+b)*(c*(d+e)*(f+g)+(h+i)*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)(g+h)+(i+j)(k+l)(m+n)))'" 15 O=!((a+b)*((c+d)*(e+f)*(g+h)+(i+j)*(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e))'" 6 O=!((a+b)*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef))'" 7 O=!((a+b)*(c+d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e(f+g)))'" 8 O=!((a+b)*(c+d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e(f+gh)))'" 9 O=!((a+b)*(c+d+e*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e(fg+hi)))'" 10 O=!((a+b)*(c+d+e*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+(e+f)(g+h)))'" 9 O=!((a+b)*(c+d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+(e+f)(g+hi)))'" 10 O=!((a+b)*(c+d+(e+f)*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+(e+f)(gh+ij)))'" 11 O=!((a+b)*(c+d+(e+f)*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+efg))'" 8 O=!((a+b)*(c+d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef(g+h)))'" 9 O=!((a+b)*(c+d+e*f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e(f+g)(h+i)))'" 10 O=!((a+b)*(c+d+e*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+(e+f)(g+h)(i+j)))'" 11 O=!((a+b)*(c+d+(e+f)*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg))'" 8 O=!((a+b)*(c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+f(g+h)))'" 9 O=!((a+b)*(c+d*e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+f(g+hi)))'" 10 O=!((a+b)*(c+d*e+f*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+f(gh+ij)))'" 11 O=!((a+b)*(c+d*e+f*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+(f+g)(h+i)))'" 10 O=!((a+b)*(c+d*e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+(f+g)(h+ij)))'" 11 O=!((a+b)*(c+d*e+(f+g)*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+(f+g)(hi+jk)))'" 12 O=!((a+b)*(c+d*e+(f+g)*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fgh))'" 9 O=!((a+b)*(c+d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg(h+i)))'" 10 O=!((a+b)*(c+d*e+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+f(g+h)(i+j)))'" 11 O=!((a+b)*(c+d*e+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+(f+g)(h+i)(j+k)))'" 12 O=!((a+b)*(c+d*e+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f)+ghi))'" 10 O=!((a+b)*(c+d*(e+f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+fg)+hij))'" 11 O=!((a+b)*(c+d*(e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(ef+gh)+ijk))'" 12 O=!((a+b)*(c+d*(e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g)+hij))'" 11 O=!((a+b)*(c+(d+e)*(f+g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+gh)+ijk))'" 12 O=!((a+b)*(c+(d+e)*(f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(fg+hi)+jkl))'" 13 O=!((a+b)*(c+(d+e)*(f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def+ghi))'" 10 O=!((a+b)*(c+d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def+gh(i+j)))'" 11 O=!((a+b)*(c+d*e*f+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def+g(h+i)(j+k)))'" 12 O=!((a+b)*(c+d*e*f+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def+(g+h)(i+j)(k+l)))'" 13 O=!((a+b)*(c+d*e*f+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh))'" 9 O=!((a+b)*(c*d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+g(h+i)))'" 10 O=!((a+b)*(c*d+e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+g(h+ij)))'" 11 O=!((a+b)*(c*d+e*f+g*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+g(hi+jk)))'" 12 O=!((a+b)*(c*d+e*f+g*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+(g+h)(i+j)))'" 11 O=!((a+b)*(c*d+e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+(g+h)(i+jk)))'" 12 O=!((a+b)*(c*d+e*f+(g+h)*(i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+(g+h)(ij+kl)))'" 13 O=!((a+b)*(c*d+e*f+(g+h)*(i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+ghi))'" 10 O=!((a+b)*(c*d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh(i+j)))'" 11 O=!((a+b)*(c*d+e*f+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+g(h+i)(j+k)))'" 12 O=!((a+b)*(c*d+e*f+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+(g+h)(i+j)(k+l)))'" 13 O=!((a+b)*(c*d+e*f+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g)+hij))'" 11 O=!((a+b)*(c*d+e*(f+g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+gh)+ijk))'" 12 O=!((a+b)*(c*d+e*(f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(fg+hi)+jkl))'" 13 O=!((a+b)*(c*d+e*(f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h)+ijk))'" 12 O=!((a+b)*(c*d+(e+f)*(g+h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+hi)+jkl))'" 13 O=!((a+b)*(c*d+(e+f)*(g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(gh+ij)+klm))'" 14 O=!((a+b)*(c*d+(e+f)*(g*h+i*j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg+hij))'" 11 O=!((a+b)*(c*d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg+hi(j+k)))'" 12 O=!((a+b)*(c*d+e*f*g+h*i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg+h(i+j)(k+l)))'" 13 O=!((a+b)*(c*d+e*f*g+h*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg+(h+i)(j+k)(l+m)))'" 14 O=!((a+b)*(c*d+e*f*g+(h+i)*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+fgh+ijk))'" 12 O=!((a+b)*(c*(d+e)+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+ghi+jkl))'" 13 O=!((a+b)*(c*(d+e*f)+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+hij+klm))'" 14 O=!((a+b)*(c*(d*e+f*g)+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+ghi+jkl))'" 13 O=!((a+b)*((c+d)*(e+f)+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg)+hij+klm))'" 14 O=!((a+b)*((c+d)*(e+f*g)+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+gh)+ijk+lmn))'" 15 O=!((a+b)*((c+d)*(e*f+g*h)+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh+ijk))'" 12 O=!((a+b)*(c*d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh+ij(k+l)))'" 13 O=!((a+b)*(c*d*e+f*g*h+i*j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh+i(j+k)(l+m)))'" 14 O=!((a+b)*(c*d*e+f*g*h+i*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh+(i+j)(k+l)(m+n)))'" 15 O=!((a+b)*(c*d*e+f*g*h+(i+j)*(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f))'" 7 O=!((a+b)*(c+d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+fg))'" 8 O=!((a+b)*(c+d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+fgh))'" 9 O=!((a+b)*(c+d+e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef+gh))'" 9 O=!((a+b)*(c+d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef+ghi))'" 10 O=!((a+b)*(c+d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+efg+hij))'" 11 O=!((a+b)*(c+d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg+hi))'" 10 O=!((a+b)*(c+d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg+hij))'" 11 O=!((a+b)*(c+d*e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fgh+ijk))'" 12 O=!((a+b)*(c+d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def+ghi+jkl))'" 13 O=!((a+b)*(c+d*e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh+ij))'" 11 O=!((a+b)*(c*d+e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh+ijk))'" 12 O=!((a+b)*(c*d+e*f+g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+ghi+jkl))'" 13 O=!((a+b)*(c*d+e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg+hij+klm))'" 14 O=!((a+b)*(c*d+e*f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh+ijk+lmn))'" 15 O=!((a+b)*(c*d*e+f*g*h+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef))'" 7 O=!((a+b*c)*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e(f+g)))'" 8 O=!((a+b*c)*(d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e(f+g+h)))'" 9 O=!((a+b*c)*(d+e*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+(e+f)(g+h)))'" 9 O=!((a+b*c)*(d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+(e+f)(g+h+i)))'" 10 O=!((a+b*c)*(d+(e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+(e+f+g)(h+i+j)))'" 11 O=!((a+b*c)*(d+(e+f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg))'" 8 O=!((a+b*c)*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+f(g+h)))'" 9 O=!((a+b*c)*(d*e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+f(g+h+i)))'" 10 O=!((a+b*c)*(d*e+f*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+(f+g)(h+i)))'" 10 O=!((a+b*c)*(d*e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+(f+g)(h+i+j)))'" 11 O=!((a+b*c)*(d*e+(f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+(f+g+h)(i+j+k)))'" 12 O=!((a+b*c)*(d*e+(f+g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d(e+f)+g(h+i)))'" 10 O=!((a+b*c)*(d*(e+f)+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d(e+f)+(g+h)(i+j)))'" 11 O=!((a+b*c)*(d*(e+f)+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)((d+e)(f+g)+(h+i)(j+k)))'" 12 O=!((a+b*c)*((d+e)*(f+g)+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f))'" 7 O=!((a+b*c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+fg))'" 8 O=!((a+b*c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f(g+h)))'" 9 O=!((a+b*c)*(d+e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+(f+g)(h+i)))'" 10 O=!((a+b*c)*(d+e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef+gh))'" 9 O=!((a+b*c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef+g(h+i)))'" 10 O=!((a+b*c)*(d+e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef+(g+h)(i+j)))'" 11 O=!((a+b*c)*(d+e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg+hi))'" 10 O=!((a+b*c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg+h(i+j)))'" 11 O=!((a+b*c)*(d*e+f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg+(h+i)(j+k)))'" 12 O=!((a+b*c)*(d*e+f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f+g))'" 8 O=!((a+b*c)*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f+gh))'" 9 O=!((a+b*c)*(d+e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+fg+hi))'" 10 O=!((a+b*c)*(d+e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef+gh+ij))'" 11 O=!((a+b*c)*(d+e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg+hi+jk))'" 12 O=!((a+b*c)*(d*e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f(g+h)))'" 9 O=!((a+b*(c+d))*(e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f(g+h+i)))'" 10 O=!((a+b*(c+d))*(e+f*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+(f+g)(h+i)))'" 10 O=!((a+b*(c+d))*(e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+(f+g)(h+i+j)))'" 11 O=!((a+b*(c+d))*(e+(f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+(f+g+h)(i+j+k)))'" 12 O=!((a+b*(c+d))*(e+(f+g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh))'" 9 O=!((a+b*(c+d))*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+g(h+i)))'" 10 O=!((a+b*(c+d))*(e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+g(h+i+j)))'" 11 O=!((a+b*(c+d))*(e*f+g*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+(g+h)(i+j)))'" 11 O=!((a+b*(c+d))*(e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+(g+h)(i+j+k)))'" 12 O=!((a+b*(c+d))*(e*f+(g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+(g+h+i)(j+k+l)))'" 13 O=!((a+b*(c+d))*(e*f+(g+h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e(f+g)+h(i+j)))'" 11 O=!((a+b*(c+d))*(e*(f+g)+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e(f+g)+(h+i)(j+k)))'" 12 O=!((a+b*(c+d))*(e*(f+g)+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))((e+f)(g+h)+(i+j)(k+l)))'" 13 O=!((a+b*(c+d))*((e+f)*(g+h)+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g))'" 8 O=!((a+b*(c+d))*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+gh))'" 9 O=!((a+b*(c+d))*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g(h+i)))'" 10 O=!((a+b*(c+d))*(e+f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+(g+h)(i+j)))'" 11 O=!((a+b*(c+d))*(e+f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+fg+hi))'" 10 O=!((a+b*(c+d))*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+fg+h(i+j)))'" 11 O=!((a+b*(c+d))*(e+f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+fg+(h+i)(j+k)))'" 12 O=!((a+b*(c+d))*(e+f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh+ij))'" 11 O=!((a+b*(c+d))*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh+i(j+k)))'" 12 O=!((a+b*(c+d))*(e*f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh+(i+j)(k+l)))'" 13 O=!((a+b*(c+d))*(e*f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g+h))'" 9 O=!((a+b*(c+d))*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g+hi))'" 10 O=!((a+b*(c+d))*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+gh+ij))'" 11 O=!((a+b*(c+d))*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+fg+hi+jk))'" 12 O=!((a+b*(c+d))*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh+ij+kl))'" 13 O=!((a+b*(c+d))*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+de))(f+g+h))'" 9 O=!((a+b*(c+d*e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+de))(f+g+h+i))'" 10 O=!((a+b*(c+d*e))*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d(e+f)))(g+h+i))'" 10 O=!((a+b*(c+d*(e+f)))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d(e+f)))(g+h+i+j))'" 11 O=!((a+b*(c+d*(e+f)))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+(d+e)(f+g)))(h+i+j))'" 11 O=!((a+b*(c+(d+e)*(f+g)))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+(d+e)(f+g)))(h+i+j+k))'" 12 O=!((a+b*(c+(d+e)*(f+g)))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+ef))(g+h+i))'" 10 O=!((a+b*(c*d+e*f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+ef))(g+h+i+j))'" 11 O=!((a+b*(c*d+e*f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+e(f+g)))(h+i+j))'" 11 O=!((a+b*(c*d+e*(f+g)))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+e(f+g)))(h+i+j+k))'" 12 O=!((a+b*(c*d+e*(f+g)))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+(e+f)(g+h)))(i+j+k))'" 12 O=!((a+b*(c*d+(e+f)*(g+h)))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+(e+f)(g+h)))(i+j+k+l))'" 13 O=!((a+b*(c*d+(e+f)*(g+h)))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g(h+i+j)))'" 11 O=!((a+b*(c+d+e))*(f+g*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+(g+h)(i+j)))'" 11 O=!((a+b*(c+d+e))*(f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+(g+h)(i+j+k)))'" 12 O=!((a+b*(c+d+e))*(f+(g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+(g+h+i)(j+k+l)))'" 13 O=!((a+b*(c+d+e))*(f+(g+h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(fg+hi))'" 10 O=!((a+b*(c+d+e))*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(fg+h(i+j)))'" 11 O=!((a+b*(c+d+e))*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(fg+h(i+j+k)))'" 12 O=!((a+b*(c+d+e))*(f*g+h*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(fg+(h+i)(j+k)))'" 12 O=!((a+b*(c+d+e))*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(fg+(h+i)(j+k+l)))'" 13 O=!((a+b*(c+d+e))*(f*g+(h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(fg+(h+i+j)(k+l+m)))'" 14 O=!((a+b*(c+d+e))*(f*g+(h+i+j)*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f(g+h)+i(j+k)))'" 12 O=!((a+b*(c+d+e))*(f*(g+h)+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f(g+h)+(i+j)(k+l)))'" 13 O=!((a+b*(c+d+e))*(f*(g+h)+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))((f+g)(h+i)+(j+k)(l+m)))'" 14 O=!((a+b*(c+d+e))*((f+g)*(h+i)+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g+h))'" 9 O=!((a+b*(c+d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g+hi))'" 10 O=!((a+b*(c+d+e))*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g+h(i+j)))'" 11 O=!((a+b*(c+d+e))*(f+g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g+(h+i)(j+k)))'" 12 O=!((a+b*(c+d+e))*(f+g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+gh+ij))'" 11 O=!((a+b*(c+d+e))*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+gh+i(j+k)))'" 12 O=!((a+b*(c+d+e))*(f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+gh+(i+j)(k+l)))'" 13 O=!((a+b*(c+d+e))*(f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(fg+hi+jk))'" 12 O=!((a+b*(c+d+e))*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(fg+hi+j(k+l)))'" 13 O=!((a+b*(c+d+e))*(f*g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(fg+hi+(j+k)(l+m)))'" 14 O=!((a+b*(c+d+e))*(f*g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g+h+i))'" 10 O=!((a+b*(c+d+e))*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g+h+ij))'" 11 O=!((a+b*(c+d+e))*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g+hi+jk))'" 12 O=!((a+b*(c+d+e))*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+gh+ij+kl))'" 13 O=!((a+b*(c+d+e))*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(fg+hi+jk+lm))'" 14 O=!((a+b*(c+d+e))*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+ef))(g+h+i))'" 10 O=!((a+b*(c+d+e*f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+ef))(g+h+i+j))'" 11 O=!((a+b*(c+d+e*f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+de+fg))(h+i+j))'" 11 O=!((a+b*(c+d*e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+de+fg))(h+i+j+k))'" 12 O=!((a+b*(c+d*e+f*g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+ef+gh))(i+j+k))'" 12 O=!((a+b*(c*d+e*f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+ef+gh))(i+j+k+l))'" 13 O=!((a+b*(c*d+e*f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+(g+h)(i+j)))'" 11 O=!((a+(b+c)*(d+e))*(f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+(g+h)(i+j+k)))'" 12 O=!((a+(b+c)*(d+e))*(f+(g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+(g+h+i)(j+k+l)))'" 13 O=!((a+(b+c)*(d+e))*(f+(g+h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi))'" 10 O=!((a+(b+c)*(d+e))*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+h(i+j)))'" 11 O=!((a+(b+c)*(d+e))*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+h(i+j+k)))'" 12 O=!((a+(b+c)*(d+e))*(f*g+h*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+(h+i)(j+k)))'" 12 O=!((a+(b+c)*(d+e))*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+(h+i)(j+k+l)))'" 13 O=!((a+(b+c)*(d+e))*(f*g+(h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+(h+i+j)(k+l+m)))'" 14 O=!((a+(b+c)*(d+e))*(f*g+(h+i+j)*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f(g+h)+i(j+k)))'" 12 O=!((a+(b+c)*(d+e))*(f*(g+h)+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f(g+h)+(i+j)(k+l)))'" 13 O=!((a+(b+c)*(d+e))*(f*(g+h)+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))((f+g)(h+i)+(j+k)(l+m)))'" 14 O=!((a+(b+c)*(d+e))*((f+g)*(h+i)+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h))'" 9 O=!((a+(b+c)*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+hi))'" 10 O=!((a+(b+c)*(d+e))*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h(i+j)))'" 11 O=!((a+(b+c)*(d+e))*(f+g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+(h+i)(j+k)))'" 12 O=!((a+(b+c)*(d+e))*(f+g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+gh+ij))'" 11 O=!((a+(b+c)*(d+e))*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+gh+i(j+k)))'" 12 O=!((a+(b+c)*(d+e))*(f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+gh+(i+j)(k+l)))'" 13 O=!((a+(b+c)*(d+e))*(f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi+jk))'" 12 O=!((a+(b+c)*(d+e))*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi+j(k+l)))'" 13 O=!((a+(b+c)*(d+e))*(f*g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi+(j+k)(l+m)))'" 14 O=!((a+(b+c)*(d+e))*(f*g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h+i))'" 10 O=!((a+(b+c)*(d+e))*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h+ij))'" 11 O=!((a+(b+c)*(d+e))*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+hi+jk))'" 12 O=!((a+(b+c)*(d+e))*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+gh+ij+kl))'" 13 O=!((a+(b+c)*(d+e))*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi+jk+lm))'" 14 O=!((a+(b+c)*(d+e))*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+ef))(g+h+i))'" 10 O=!((a+(b+c)*(d+e*f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+ef))(g+h+i+j))'" 11 O=!((a+(b+c)*(d+e*f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e(f+g)))(h+i+j))'" 11 O=!((a+(b+c)*(d+e*(f+g)))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e(f+g)))(h+i+j+k))'" 12 O=!((a+(b+c)*(d+e*(f+g)))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+(e+f)(g+h)))(i+j+k))'" 12 O=!((a+(b+c)*(d+(e+f)*(g+h)))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+(e+f)(g+h)))(i+j+k+l))'" 13 O=!((a+(b+c)*(d+(e+f)*(g+h)))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+fg))(h+i+j))'" 11 O=!((a+(b+c)*(d*e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+fg))(h+i+j+k))'" 12 O=!((a+(b+c)*(d*e+f*g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+f(g+h)))(i+j+k))'" 12 O=!((a+(b+c)*(d*e+f*(g+h)))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+f(g+h)))(i+j+k+l))'" 13 O=!((a+(b+c)*(d*e+f*(g+h)))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+(f+g)(h+i)))(j+k+l))'" 13 O=!((a+(b+c)*(d*e+(f+g)*(h+i)))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+(f+g)(h+i)))(j+k+l+m))'" 14 O=!((a+(b+c)*(d*e+(f+g)*(h+i)))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+(h+i)(j+k+l)))'" 13 O=!((a+(b+c)*(d+e+f))*(g+(h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+(h+i+j)(k+l+m)))'" 14 O=!((a+(b+c)*(d+e+f))*(g+(h+i+j)*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(gh+ij))'" 11 O=!((a+(b+c)*(d+e+f))*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(gh+i(j+k)))'" 12 O=!((a+(b+c)*(d+e+f))*(g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(gh+i(j+k+l)))'" 13 O=!((a+(b+c)*(d+e+f))*(g*h+i*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(gh+(i+j)(k+l)))'" 13 O=!((a+(b+c)*(d+e+f))*(g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(gh+(i+j)(k+l+m)))'" 14 O=!((a+(b+c)*(d+e+f))*(g*h+(i+j)*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(gh+(i+j+k)(l+m+n)))'" 15 O=!((a+(b+c)*(d+e+f))*(g*h+(i+j+k)*(l+m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g(h+i)+j(k+l)))'" 13 O=!((a+(b+c)*(d+e+f))*(g*(h+i)+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g(h+i)+(j+k)(l+m)))'" 14 O=!((a+(b+c)*(d+e+f))*(g*(h+i)+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))((g+h)(i+j)+(k+l)(m+n)))'" 15 O=!((a+(b+c)*(d+e+f))*((g+h)*(i+j)+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+h+i))'" 10 O=!((a+(b+c)*(d+e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+h+ij))'" 11 O=!((a+(b+c)*(d+e+f))*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+h+i(j+k)))'" 12 O=!((a+(b+c)*(d+e+f))*(g+h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+h+(i+j)(k+l)))'" 13 O=!((a+(b+c)*(d+e+f))*(g+h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+hi+jk))'" 12 O=!((a+(b+c)*(d+e+f))*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+hi+j(k+l)))'" 13 O=!((a+(b+c)*(d+e+f))*(g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+hi+(j+k)(l+m)))'" 14 O=!((a+(b+c)*(d+e+f))*(g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(gh+ij+kl))'" 13 O=!((a+(b+c)*(d+e+f))*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(gh+ij+k(l+m)))'" 14 O=!((a+(b+c)*(d+e+f))*(g*h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(gh+ij+(k+l)(m+n)))'" 15 O=!((a+(b+c)*(d+e+f))*(g*h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+h+i+j))'" 11 O=!((a+(b+c)*(d+e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+h+i+jk))'" 12 O=!((a+(b+c)*(d+e+f))*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+h+ij+kl))'" 13 O=!((a+(b+c)*(d+e+f))*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+hi+jk+lm))'" 14 O=!((a+(b+c)*(d+e+f))*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(gh+ij+kl+mn))'" 15 O=!((a+(b+c)*(d+e+f))*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+fg))(h+i+j))'" 11 O=!((a+(b+c)*(d+e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+fg))(h+i+j+k))'" 12 O=!((a+(b+c)*(d+e+f*g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+ef+gh))(i+j+k))'" 12 O=!((a+(b+c)*(d+e*f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+ef+gh))(i+j+k+l))'" 13 O=!((a+(b+c)*(d+e*f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+fg+hi))(j+k+l))'" 13 O=!((a+(b+c)*(d*e+f*g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+fg+hi))(j+k+l+m))'" 14 O=!((a+(b+c)*(d*e+f*g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+cd)(e+f+g))(h+i+j))'" 11 O=!((a+(b+c*d)*(e+f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+cd)(e+f+g))(h+i+j+k))'" 12 O=!((a+(b+c*d)*(e+f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c(d+e))(f+g+h))(i+j+k))'" 12 O=!((a+(b+c*(d+e))*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c(d+e))(f+g+h))(i+j+k+l))'" 13 O=!((a+(b+c*(d+e))*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+(c+d)(e+f))(g+h+i))(j+k+l))'" 13 O=!((a+(b+(c+d)*(e+f))*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+(c+d)(e+f))(g+h+i))(j+k+l+m))'" 14 O=!((a+(b+(c+d)*(e+f))*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(bc+de)(f+g+h))(i+j+k))'" 12 O=!((a+(b*c+d*e)*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(bc+de)(f+g+h))(i+j+k+l))'" 13 O=!((a+(b*c+d*e)*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(bc+d(e+f))(g+h+i))(j+k+l))'" 13 O=!((a+(b*c+d*(e+f))*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(bc+d(e+f))(g+h+i))(j+k+l+m))'" 14 O=!((a+(b*c+d*(e+f))*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(bc+(d+e)(f+g))(h+i+j))(k+l+m))'" 14 O=!((a+(b*c+(d+e)*(f+g))*(h+i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(bc+(d+e)(f+g))(h+i+j))(k+l+m+n))'" 15 O=!((a+(b*c+(d+e)*(f+g))*(h+i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+(i+j+k)(l+m+n)))'" 15 O=!((a+(b+c+d)*(e+f+g))*(h+(i+j+k)*(l+m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(hi+jk))'" 12 O=!((a+(b+c+d)*(e+f+g))*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(hi+j(k+l)))'" 13 O=!((a+(b+c+d)*(e+f+g))*(h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(hi+j(k+l+m)))'" 14 O=!((a+(b+c+d)*(e+f+g))*(h*i+j*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(hi+(j+k)(l+m)))'" 14 O=!((a+(b+c+d)*(e+f+g))*(h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(hi+(j+k)(l+m+n)))'" 15 O=!((a+(b+c+d)*(e+f+g))*(h*i+(j+k)*(l+m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(hi+(j+k+l)(m+n+o)))'" 16 O=!((a+(b+c+d)*(e+f+g))*(h*i+(j+k+l)*(m+n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h(i+j)+k(l+m)))'" 14 O=!((a+(b+c+d)*(e+f+g))*(h*(i+j)+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h(i+j)+(k+l)(m+n)))'" 15 O=!((a+(b+c+d)*(e+f+g))*(h*(i+j)+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))((h+i)(j+k)+(l+m)(n+o)))'" 16 O=!((a+(b+c+d)*(e+f+g))*((h+i)*(j+k)+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+i+j))'" 11 O=!((a+(b+c+d)*(e+f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+i+jk))'" 12 O=!((a+(b+c+d)*(e+f+g))*(h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+i+j(k+l)))'" 13 O=!((a+(b+c+d)*(e+f+g))*(h+i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+i+(j+k)(l+m)))'" 14 O=!((a+(b+c+d)*(e+f+g))*(h+i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+ij+kl))'" 13 O=!((a+(b+c+d)*(e+f+g))*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+ij+k(l+m)))'" 14 O=!((a+(b+c+d)*(e+f+g))*(h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+ij+(k+l)(m+n)))'" 15 O=!((a+(b+c+d)*(e+f+g))*(h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(hi+jk+lm))'" 14 O=!((a+(b+c+d)*(e+f+g))*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(hi+jk+l(m+n)))'" 15 O=!((a+(b+c+d)*(e+f+g))*(h*i+j*k+l*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(hi+jk+(l+m)(n+o)))'" 16 O=!((a+(b+c+d)*(e+f+g))*(h*i+j*k+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+i+j+k))'" 12 O=!((a+(b+c+d)*(e+f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+i+j+kl))'" 13 O=!((a+(b+c+d)*(e+f+g))*(h+i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+i+jk+lm))'" 14 O=!((a+(b+c+d)*(e+f+g))*(h+i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+ij+kl+mn))'" 15 O=!((a+(b+c+d)*(e+f+g))*(h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(hi+jk+lm+no))'" 16 O=!((a+(b+c+d)*(e+f+g))*(h*i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+gh))(i+j+k))'" 12 O=!((a+(b+c+d)*(e+f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+gh))(i+j+k+l))'" 13 O=!((a+(b+c+d)*(e+f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+fg+hi))(j+k+l))'" 13 O=!((a+(b+c+d)*(e+f*g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+fg+hi))(j+k+l+m))'" 14 O=!((a+(b+c+d)*(e+f*g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(ef+gh+ij))(k+l+m))'" 14 O=!((a+(b+c+d)*(e*f+g*h+i*j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(ef+gh+ij))(k+l+m+n))'" 15 O=!((a+(b+c+d)*(e*f+g*h+i*j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd)(e+f+g))'" 8 O=!((a+b*c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd)(e+f+g+h))'" 9 O=!((a+b*c*d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc(d+e))(f+g+h))'" 9 O=!((a+b*c*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc(d+e))(f+g+h+i))'" 10 O=!((a+b*c*(d+e))*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc(d+e+f))(g+h+i))'" 10 O=!((a+b*c*(d+e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc(d+e+f))(g+h+i+j))'" 11 O=!((a+b*c*(d+e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d)(e+f))(g+h+i))'" 10 O=!((a+b*(c+d)*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d)(e+f))(g+h+i+j))'" 11 O=!((a+b*(c+d)*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d)(e+f+g))(h+i+j))'" 11 O=!((a+b*(c+d)*(e+f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d)(e+f+g))(h+i+j+k))'" 12 O=!((a+b*(c+d)*(e+f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e)(f+g+h))(i+j+k))'" 12 O=!((a+b*(c+d+e)*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e)(f+g+h))(i+j+k+l))'" 13 O=!((a+b*(c+d+e)*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e)(f+g))(h+i+j))'" 11 O=!((a+(b+c)*(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e)(f+g))(h+i+j+k))'" 12 O=!((a+(b+c)*(d+e)*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e)(f+g+h))(i+j+k))'" 12 O=!((a+(b+c)*(d+e)*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e)(f+g+h))(i+j+k+l))'" 13 O=!((a+(b+c)*(d+e)*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f)(g+h+i))(j+k+l))'" 13 O=!((a+(b+c)*(d+e+f)*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f)(g+h+i))(j+k+l+m))'" 14 O=!((a+(b+c)*(d+e+f)*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g)(h+i+j))(k+l+m))'" 14 O=!((a+(b+c+d)*(e+f+g)*(h+i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g)(h+i+j))(k+l+m+n))'" 15 O=!((a+(b+c+d)*(e+f+g)*(h+i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh))'" 9 O=!((a*b+c*d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+g(h+i)))'" 10 O=!((a*b+c*d)*(e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+g(h+i+j)))'" 11 O=!((a*b+c*d)*(e*f+g*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+(g+h)(i+j)))'" 11 O=!((a*b+c*d)*(e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+(g+h)(i+j+k)))'" 12 O=!((a*b+c*d)*(e*f+(g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+(g+h+i)(j+k+l)))'" 13 O=!((a*b+c*d)*(e*f+(g+h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e(f+g)+h(i+j)))'" 11 O=!((a*b+c*d)*(e*(f+g)+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e(f+g)+(h+i)(j+k)))'" 12 O=!((a*b+c*d)*(e*(f+g)+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)((e+f)(g+h)+(i+j)(k+l)))'" 13 O=!((a*b+c*d)*((e+f)*(g+h)+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g))'" 8 O=!((a*b+c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+gh))'" 9 O=!((a*b+c*d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g(h+i)))'" 10 O=!((a*b+c*d)*(e+f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+(g+h)(i+j)))'" 11 O=!((a*b+c*d)*(e+f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+fg+hi))'" 10 O=!((a*b+c*d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+fg+h(i+j)))'" 11 O=!((a*b+c*d)*(e+f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+fg+(h+i)(j+k)))'" 12 O=!((a*b+c*d)*(e+f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh+ij))'" 11 O=!((a*b+c*d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh+i(j+k)))'" 12 O=!((a*b+c*d)*(e*f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh+(i+j)(k+l)))'" 13 O=!((a*b+c*d)*(e*f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g+h))'" 9 O=!((a*b+c*d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g+hi))'" 10 O=!((a*b+c*d)*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+gh+ij))'" 11 O=!((a*b+c*d)*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+fg+hi+jk))'" 12 O=!((a*b+c*d)*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh+ij+kl))'" 13 O=!((a*b+c*d)*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+h(i+j)))'" 11 O=!((a*b+c*(d+e))*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+h(i+j+k)))'" 12 O=!((a*b+c*(d+e))*(f*g+h*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+(h+i)(j+k)))'" 12 O=!((a*b+c*(d+e))*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+(h+i)(j+k+l)))'" 13 O=!((a*b+c*(d+e))*(f*g+(h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+(h+i+j)(k+l+m)))'" 14 O=!((a*b+c*(d+e))*(f*g+(h+i+j)*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f(g+h)+i(j+k)))'" 12 O=!((a*b+c*(d+e))*(f*(g+h)+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f(g+h)+(i+j)(k+l)))'" 13 O=!((a*b+c*(d+e))*(f*(g+h)+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))((f+g)(h+i)+(j+k)(l+m)))'" 14 O=!((a*b+c*(d+e))*((f+g)*(h+i)+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h))'" 9 O=!((a*b+c*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+hi))'" 10 O=!((a*b+c*(d+e))*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h(i+j)))'" 11 O=!((a*b+c*(d+e))*(f+g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+(h+i)(j+k)))'" 12 O=!((a*b+c*(d+e))*(f+g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+gh+ij))'" 11 O=!((a*b+c*(d+e))*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+gh+i(j+k)))'" 12 O=!((a*b+c*(d+e))*(f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+gh+(i+j)(k+l)))'" 13 O=!((a*b+c*(d+e))*(f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+hi+jk))'" 12 O=!((a*b+c*(d+e))*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+hi+j(k+l)))'" 13 O=!((a*b+c*(d+e))*(f*g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+hi+(j+k)(l+m)))'" 14 O=!((a*b+c*(d+e))*(f*g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h+i))'" 10 O=!((a*b+c*(d+e))*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h+ij))'" 11 O=!((a*b+c*(d+e))*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+hi+jk))'" 12 O=!((a*b+c*(d+e))*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+gh+ij+kl))'" 13 O=!((a*b+c*(d+e))*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+hi+jk+lm))'" 14 O=!((a*b+c*(d+e))*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+ef))(g+h+i))'" 10 O=!((a*b+c*(d+e*f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+ef))(g+h+i+j))'" 11 O=!((a*b+c*(d+e*f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e(f+g)))(h+i+j))'" 11 O=!((a*b+c*(d+e*(f+g)))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e(f+g)))(h+i+j+k))'" 12 O=!((a*b+c*(d+e*(f+g)))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+(e+f)(g+h)))(i+j+k))'" 12 O=!((a*b+c*(d+(e+f)*(g+h)))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+(e+f)(g+h)))(i+j+k+l))'" 13 O=!((a*b+c*(d+(e+f)*(g+h)))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+fg))(h+i+j))'" 11 O=!((a*b+c*(d*e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+fg))(h+i+j+k))'" 12 O=!((a*b+c*(d*e+f*g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+f(g+h)))(i+j+k))'" 12 O=!((a*b+c*(d*e+f*(g+h)))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+f(g+h)))(i+j+k+l))'" 13 O=!((a*b+c*(d*e+f*(g+h)))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+(f+g)(h+i)))(j+k+l))'" 13 O=!((a*b+c*(d*e+(f+g)*(h+i)))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+(f+g)(h+i)))(j+k+l+m))'" 14 O=!((a*b+c*(d*e+(f+g)*(h+i)))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(gh+i(j+k+l)))'" 13 O=!((a*b+c*(d+e+f))*(g*h+i*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(gh+(i+j)(k+l)))'" 13 O=!((a*b+c*(d+e+f))*(g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(gh+(i+j)(k+l+m)))'" 14 O=!((a*b+c*(d+e+f))*(g*h+(i+j)*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(gh+(i+j+k)(l+m+n)))'" 15 O=!((a*b+c*(d+e+f))*(g*h+(i+j+k)*(l+m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g(h+i)+j(k+l)))'" 13 O=!((a*b+c*(d+e+f))*(g*(h+i)+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g(h+i)+(j+k)(l+m)))'" 14 O=!((a*b+c*(d+e+f))*(g*(h+i)+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))((g+h)(i+j)+(k+l)(m+n)))'" 15 O=!((a*b+c*(d+e+f))*((g+h)*(i+j)+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+h+i))'" 10 O=!((a*b+c*(d+e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+h+ij))'" 11 O=!((a*b+c*(d+e+f))*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+h+i(j+k)))'" 12 O=!((a*b+c*(d+e+f))*(g+h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+h+(i+j)(k+l)))'" 13 O=!((a*b+c*(d+e+f))*(g+h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+hi+jk))'" 12 O=!((a*b+c*(d+e+f))*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+hi+j(k+l)))'" 13 O=!((a*b+c*(d+e+f))*(g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+hi+(j+k)(l+m)))'" 14 O=!((a*b+c*(d+e+f))*(g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(gh+ij+kl))'" 13 O=!((a*b+c*(d+e+f))*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(gh+ij+k(l+m)))'" 14 O=!((a*b+c*(d+e+f))*(g*h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(gh+ij+(k+l)(m+n)))'" 15 O=!((a*b+c*(d+e+f))*(g*h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+h+i+j))'" 11 O=!((a*b+c*(d+e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+h+i+jk))'" 12 O=!((a*b+c*(d+e+f))*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+h+ij+kl))'" 13 O=!((a*b+c*(d+e+f))*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+hi+jk+lm))'" 14 O=!((a*b+c*(d+e+f))*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(gh+ij+kl+mn))'" 15 O=!((a*b+c*(d+e+f))*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+fg))(h+i+j))'" 11 O=!((a*b+c*(d+e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+fg))(h+i+j+k))'" 12 O=!((a*b+c*(d+e+f*g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+ef+gh))(i+j+k))'" 12 O=!((a*b+c*(d+e*f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+ef+gh))(i+j+k+l))'" 13 O=!((a*b+c*(d+e*f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+fg+hi))(j+k+l))'" 13 O=!((a*b+c*(d*e+f*g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+fg+hi))(j+k+l+m))'" 14 O=!((a*b+c*(d*e+f*g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+(i+j)(k+l)))'" 13 O=!((a*b+(c+d)*(e+f))*(g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+(i+j)(k+l+m)))'" 14 O=!((a*b+(c+d)*(e+f))*(g*h+(i+j)*(k+l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+(i+j+k)(l+m+n)))'" 15 O=!((a*b+(c+d)*(e+f))*(g*h+(i+j+k)*(l+m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g(h+i)+j(k+l)))'" 13 O=!((a*b+(c+d)*(e+f))*(g*(h+i)+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g(h+i)+(j+k)(l+m)))'" 14 O=!((a*b+(c+d)*(e+f))*(g*(h+i)+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))((g+h)(i+j)+(k+l)(m+n)))'" 15 O=!((a*b+(c+d)*(e+f))*((g+h)*(i+j)+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i))'" 10 O=!((a*b+(c+d)*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+ij))'" 11 O=!((a*b+(c+d)*(e+f))*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i(j+k)))'" 12 O=!((a*b+(c+d)*(e+f))*(g+h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+(i+j)(k+l)))'" 13 O=!((a*b+(c+d)*(e+f))*(g+h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+hi+jk))'" 12 O=!((a*b+(c+d)*(e+f))*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+hi+j(k+l)))'" 13 O=!((a*b+(c+d)*(e+f))*(g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+hi+(j+k)(l+m)))'" 14 O=!((a*b+(c+d)*(e+f))*(g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+ij+kl))'" 13 O=!((a*b+(c+d)*(e+f))*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+ij+k(l+m)))'" 14 O=!((a*b+(c+d)*(e+f))*(g*h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+ij+(k+l)(m+n)))'" 15 O=!((a*b+(c+d)*(e+f))*(g*h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i+j))'" 11 O=!((a*b+(c+d)*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i+jk))'" 12 O=!((a*b+(c+d)*(e+f))*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+ij+kl))'" 13 O=!((a*b+(c+d)*(e+f))*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+hi+jk+lm))'" 14 O=!((a*b+(c+d)*(e+f))*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+ij+kl+mn))'" 15 O=!((a*b+(c+d)*(e+f))*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+fg))(h+i+j))'" 11 O=!((a*b+(c+d)*(e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+fg))(h+i+j+k))'" 12 O=!((a*b+(c+d)*(e+f*g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f(g+h)))(i+j+k))'" 12 O=!((a*b+(c+d)*(e+f*(g+h)))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f(g+h)))(i+j+k+l))'" 13 O=!((a*b+(c+d)*(e+f*(g+h)))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+(f+g)(h+i)))(j+k+l))'" 13 O=!((a*b+(c+d)*(e+(f+g)*(h+i)))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+(f+g)(h+i)))(j+k+l+m))'" 14 O=!((a*b+(c+d)*(e+(f+g)*(h+i)))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+gh))(i+j+k))'" 12 O=!((a*b+(c+d)*(e*f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+gh))(i+j+k+l))'" 13 O=!((a*b+(c+d)*(e*f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+g(h+i)))(j+k+l))'" 13 O=!((a*b+(c+d)*(e*f+g*(h+i)))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+g(h+i)))(j+k+l+m))'" 14 O=!((a*b+(c+d)*(e*f+g*(h+i)))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+(g+h)(i+j)))(k+l+m))'" 14 O=!((a*b+(c+d)*(e*f+(g+h)*(i+j)))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+(g+h)(i+j)))(k+l+m+n))'" 15 O=!((a*b+(c+d)*(e*f+(g+h)*(i+j)))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(hi+(j+k)(l+m+n)))'" 15 O=!((a*b+(c+d)*(e+f+g))*(h*i+(j+k)*(l+m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(hi+(j+k+l)(m+n+o)))'" 16 O=!((a*b+(c+d)*(e+f+g))*(h*i+(j+k+l)*(m+n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h(i+j)+k(l+m)))'" 14 O=!((a*b+(c+d)*(e+f+g))*(h*(i+j)+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h(i+j)+(k+l)(m+n)))'" 15 O=!((a*b+(c+d)*(e+f+g))*(h*(i+j)+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))((h+i)(j+k)+(l+m)(n+o)))'" 16 O=!((a*b+(c+d)*(e+f+g))*((h+i)*(j+k)+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+i+j))'" 11 O=!((a*b+(c+d)*(e+f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+i+jk))'" 12 O=!((a*b+(c+d)*(e+f+g))*(h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+i+j(k+l)))'" 13 O=!((a*b+(c+d)*(e+f+g))*(h+i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+i+(j+k)(l+m)))'" 14 O=!((a*b+(c+d)*(e+f+g))*(h+i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+ij+kl))'" 13 O=!((a*b+(c+d)*(e+f+g))*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+ij+k(l+m)))'" 14 O=!((a*b+(c+d)*(e+f+g))*(h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+ij+(k+l)(m+n)))'" 15 O=!((a*b+(c+d)*(e+f+g))*(h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(hi+jk+lm))'" 14 O=!((a*b+(c+d)*(e+f+g))*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(hi+jk+l(m+n)))'" 15 O=!((a*b+(c+d)*(e+f+g))*(h*i+j*k+l*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(hi+jk+(l+m)(n+o)))'" 16 O=!((a*b+(c+d)*(e+f+g))*(h*i+j*k+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+i+j+k))'" 12 O=!((a*b+(c+d)*(e+f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+i+j+kl))'" 13 O=!((a*b+(c+d)*(e+f+g))*(h+i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+i+jk+lm))'" 14 O=!((a*b+(c+d)*(e+f+g))*(h+i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+ij+kl+mn))'" 15 O=!((a*b+(c+d)*(e+f+g))*(h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(hi+jk+lm+no))'" 16 O=!((a*b+(c+d)*(e+f+g))*(h*i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+gh))(i+j+k))'" 12 O=!((a*b+(c+d)*(e+f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+gh))(i+j+k+l))'" 13 O=!((a*b+(c+d)*(e+f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+fg+hi))(j+k+l))'" 13 O=!((a*b+(c+d)*(e+f*g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+fg+hi))(j+k+l+m))'" 14 O=!((a*b+(c+d)*(e+f*g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+gh+ij))(k+l+m))'" 14 O=!((a*b+(c+d)*(e*f+g*h+i*j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+gh+ij))(k+l+m+n))'" 15 O=!((a*b+(c+d)*(e*f+g*h+i*j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+de)(f+g+h))(i+j+k))'" 12 O=!((a*b+(c+d*e)*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+de)(f+g+h))(i+j+k+l))'" 13 O=!((a*b+(c+d*e)*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d(e+f))(g+h+i))(j+k+l))'" 13 O=!((a*b+(c+d*(e+f))*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d(e+f))(g+h+i))(j+k+l+m))'" 14 O=!((a*b+(c+d*(e+f))*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+(d+e)(f+g))(h+i+j))(k+l+m))'" 14 O=!((a*b+(c+(d+e)*(f+g))*(h+i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+(d+e)(f+g))(h+i+j))(k+l+m+n))'" 15 O=!((a*b+(c+(d+e)*(f+g))*(h+i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(cd+ef)(g+h+i))(j+k+l))'" 13 O=!((a*b+(c*d+e*f)*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(cd+ef)(g+h+i))(j+k+l+m))'" 14 O=!((a*b+(c*d+e*f)*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(cd+e(f+g))(h+i+j))(k+l+m))'" 14 O=!((a*b+(c*d+e*(f+g))*(h+i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(cd+e(f+g))(h+i+j))(k+l+m+n))'" 15 O=!((a*b+(c*d+e*(f+g))*(h+i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(cd+(e+f)(g+h))(i+j+k))(l+m+n))'" 15 O=!((a*b+(c*d+(e+f)*(g+h))*(i+j+k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(cd+(e+f)(g+h))(i+j+k))(l+m+n+o))'" 16 O=!((a*b+(c*d+(e+f)*(g+h))*(i+j+k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(ij+(k+l+m)(n+o+p)))'" 17 O=!((a*b+(c+d+e)*(f+g+h))*(i*j+(k+l+m)*(n+o+p))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i(j+k)+l(m+n)))'" 15 O=!((a*b+(c+d+e)*(f+g+h))*(i*(j+k)+l*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i(j+k)+(l+m)(n+o)))'" 16 O=!((a*b+(c+d+e)*(f+g+h))*(i*(j+k)+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))((i+j)(k+l)+(m+n)(o+p)))'" 17 O=!((a*b+(c+d+e)*(f+g+h))*((i+j)*(k+l)+(m+n)*(o+p))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+j+k))'" 12 O=!((a*b+(c+d+e)*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+j+kl))'" 13 O=!((a*b+(c+d+e)*(f+g+h))*(i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+j+k(l+m)))'" 14 O=!((a*b+(c+d+e)*(f+g+h))*(i+j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+j+(k+l)(m+n)))'" 15 O=!((a*b+(c+d+e)*(f+g+h))*(i+j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+jk+lm))'" 14 O=!((a*b+(c+d+e)*(f+g+h))*(i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+jk+l(m+n)))'" 15 O=!((a*b+(c+d+e)*(f+g+h))*(i+j*k+l*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+jk+(l+m)(n+o)))'" 16 O=!((a*b+(c+d+e)*(f+g+h))*(i+j*k+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(ij+kl+mn))'" 15 O=!((a*b+(c+d+e)*(f+g+h))*(i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(ij+kl+m(n+o)))'" 16 O=!((a*b+(c+d+e)*(f+g+h))*(i*j+k*l+m*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(ij+kl+(m+n)(o+p)))'" 17 O=!((a*b+(c+d+e)*(f+g+h))*(i*j+k*l+(m+n)*(o+p))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+j+k+l))'" 13 O=!((a*b+(c+d+e)*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+j+k+lm))'" 14 O=!((a*b+(c+d+e)*(f+g+h))*(i+j+k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+j+kl+mn))'" 15 O=!((a*b+(c+d+e)*(f+g+h))*(i+j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+jk+lm+no))'" 16 O=!((a*b+(c+d+e)*(f+g+h))*(i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(ij+kl+mn+op))'" 17 O=!((a*b+(c+d+e)*(f+g+h))*(i*j+k*l+m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+hi))(j+k+l))'" 13 O=!((a*b+(c+d+e)*(f+g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+hi))(j+k+l+m))'" 14 O=!((a*b+(c+d+e)*(f+g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+gh+ij))(k+l+m))'" 14 O=!((a*b+(c+d+e)*(f+g*h+i*j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+gh+ij))(k+l+m+n))'" 15 O=!((a*b+(c+d+e)*(f+g*h+i*j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(fg+hi+jk))(l+m+n))'" 15 O=!((a*b+(c+d+e)*(f*g+h*i+j*k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(fg+hi+jk))(l+m+n+o))'" 16 O=!((a*b+(c+d+e)*(f*g+h*i+j*k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde)(f+g+h))'" 9 O=!((a*b+c*d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde)(f+g+h+i))'" 10 O=!((a*b+c*d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd(e+f))(g+h+i))'" 10 O=!((a*b+c*d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd(e+f))(g+h+i+j))'" 11 O=!((a*b+c*d*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd(e+f+g))(h+i+j))'" 11 O=!((a*b+c*d*(e+f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd(e+f+g))(h+i+j+k))'" 12 O=!((a*b+c*d*(e+f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e)(f+g))(h+i+j))'" 11 O=!((a*b+c*(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e)(f+g))(h+i+j+k))'" 12 O=!((a*b+c*(d+e)*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e)(f+g+h))(i+j+k))'" 12 O=!((a*b+c*(d+e)*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e)(f+g+h))(i+j+k+l))'" 13 O=!((a*b+c*(d+e)*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f)(g+h+i))(j+k+l))'" 13 O=!((a*b+c*(d+e+f)*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f)(g+h+i))(j+k+l+m))'" 14 O=!((a*b+c*(d+e+f)*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f)(g+h))(i+j+k))'" 12 O=!((a*b+(c+d)*(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f)(g+h))(i+j+k+l))'" 13 O=!((a*b+(c+d)*(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f)(g+h+i))(j+k+l))'" 13 O=!((a*b+(c+d)*(e+f)*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f)(g+h+i))(j+k+l+m))'" 14 O=!((a*b+(c+d)*(e+f)*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g)(h+i+j))(k+l+m))'" 14 O=!((a*b+(c+d)*(e+f+g)*(h+i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g)(h+i+j))(k+l+m+n))'" 15 O=!((a*b+(c+d)*(e+f+g)*(h+i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h)(i+j+k))(l+m+n))'" 15 O=!((a*b+(c+d+e)*(f+g+h)*(i+j+k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h)(i+j+k))(l+m+n+o))'" 16 O=!((a*b+(c+d+e)*(f+g+h)*(i+j+k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g(h+i)+j(k+l)))'" 13 O=!((a*(b+c)+d*(e+f))*(g*(h+i)+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g(h+i)+(j+k)(l+m)))'" 14 O=!((a*(b+c)+d*(e+f))*(g*(h+i)+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))((g+h)(i+j)+(k+l)(m+n)))'" 15 O=!((a*(b+c)+d*(e+f))*((g+h)*(i+j)+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+h+i))'" 10 O=!((a*(b+c)+d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+h+ij))'" 11 O=!((a*(b+c)+d*(e+f))*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+h+i(j+k)))'" 12 O=!((a*(b+c)+d*(e+f))*(g+h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+h+(i+j)(k+l)))'" 13 O=!((a*(b+c)+d*(e+f))*(g+h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+hi+jk))'" 12 O=!((a*(b+c)+d*(e+f))*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+hi+j(k+l)))'" 13 O=!((a*(b+c)+d*(e+f))*(g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+hi+(j+k)(l+m)))'" 14 O=!((a*(b+c)+d*(e+f))*(g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(gh+ij+kl))'" 13 O=!((a*(b+c)+d*(e+f))*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(gh+ij+k(l+m)))'" 14 O=!((a*(b+c)+d*(e+f))*(g*h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(gh+ij+(k+l)(m+n)))'" 15 O=!((a*(b+c)+d*(e+f))*(g*h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+h+i+j))'" 11 O=!((a*(b+c)+d*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+h+i+jk))'" 12 O=!((a*(b+c)+d*(e+f))*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+h+ij+kl))'" 13 O=!((a*(b+c)+d*(e+f))*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+hi+jk+lm))'" 14 O=!((a*(b+c)+d*(e+f))*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(gh+ij+kl+mn))'" 15 O=!((a*(b+c)+d*(e+f))*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+fg))(h+i+j))'" 11 O=!((a*(b+c)+d*(e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+fg))(h+i+j+k))'" 12 O=!((a*(b+c)+d*(e+f*g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(ef+gh))(i+j+k))'" 12 O=!((a*(b+c)+d*(e*f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(ef+gh))(i+j+k+l))'" 13 O=!((a*(b+c)+d*(e*f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h(i+j)+(k+l)(m+n)))'" 15 O=!((a*(b+c)+(d+e)*(f+g))*(h*(i+j)+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))((h+i)(j+k)+(l+m)(n+o)))'" 16 O=!((a*(b+c)+(d+e)*(f+g))*((h+i)*(j+k)+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+i+j))'" 11 O=!((a*(b+c)+(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+i+jk))'" 12 O=!((a*(b+c)+(d+e)*(f+g))*(h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+i+j(k+l)))'" 13 O=!((a*(b+c)+(d+e)*(f+g))*(h+i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+i+(j+k)(l+m)))'" 14 O=!((a*(b+c)+(d+e)*(f+g))*(h+i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+ij+kl))'" 13 O=!((a*(b+c)+(d+e)*(f+g))*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+ij+k(l+m)))'" 14 O=!((a*(b+c)+(d+e)*(f+g))*(h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+ij+(k+l)(m+n)))'" 15 O=!((a*(b+c)+(d+e)*(f+g))*(h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(hi+jk+lm))'" 14 O=!((a*(b+c)+(d+e)*(f+g))*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(hi+jk+l(m+n)))'" 15 O=!((a*(b+c)+(d+e)*(f+g))*(h*i+j*k+l*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(hi+jk+(l+m)(n+o)))'" 16 O=!((a*(b+c)+(d+e)*(f+g))*(h*i+j*k+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+i+j+k))'" 12 O=!((a*(b+c)+(d+e)*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+i+j+kl))'" 13 O=!((a*(b+c)+(d+e)*(f+g))*(h+i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+i+jk+lm))'" 14 O=!((a*(b+c)+(d+e)*(f+g))*(h+i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+ij+kl+mn))'" 15 O=!((a*(b+c)+(d+e)*(f+g))*(h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(hi+jk+lm+no))'" 16 O=!((a*(b+c)+(d+e)*(f+g))*(h*i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+gh))(i+j+k))'" 12 O=!((a*(b+c)+(d+e)*(f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+gh))(i+j+k+l))'" 13 O=!((a*(b+c)+(d+e)*(f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(fg+hi))(j+k+l))'" 13 O=!((a*(b+c)+(d+e)*(f*g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(fg+hi))(j+k+l+m))'" 14 O=!((a*(b+c)+(d+e)*(f*g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+def)(g+h+i))'" 10 O=!((a*(b+c)+d*e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+def)(g+h+i+j))'" 11 O=!((a*(b+c)+d*e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+de(f+g))(h+i+j))'" 11 O=!((a*(b+c)+d*e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+de(f+g))(h+i+j+k))'" 12 O=!((a*(b+c)+d*e*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f)(g+h))(i+j+k))'" 12 O=!((a*(b+c)+d*(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f)(g+h))(i+j+k+l))'" 13 O=!((a*(b+c)+d*(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g)(h+i))(j+k+l))'" 13 O=!((a*(b+c)+(d+e)*(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g)(h+i))(j+k+l+m))'" 14 O=!((a*(b+c)+(d+e)*(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+e(f+gh))(i+j+k))'" 12 O=!((a*(b+c*d)+e*(f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+e(f+gh))(i+j+k+l))'" 13 O=!((a*(b+c*d)+e*(f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+e(fg+hi))(j+k+l))'" 13 O=!((a*(b+c*d)+e*(f*g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+e(fg+hi))(j+k+l+m))'" 14 O=!((a*(b+c*d)+e*(f*g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+(e+f)(g+h))(i+j+k))'" 12 O=!((a*(b+c*d)+(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+(e+f)(g+h))(i+j+k+l))'" 13 O=!((a*(b+c*d)+(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+(e+f)(g+hi))(j+k+l))'" 13 O=!((a*(b+c*d)+(e+f)*(g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+(e+f)(g+hi))(j+k+l+m))'" 14 O=!((a*(b+c*d)+(e+f)*(g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+(e+f)(gh+ij))(k+l+m))'" 14 O=!((a*(b+c*d)+(e+f)*(g*h+i*j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+(e+f)(gh+ij))(k+l+m+n))'" 15 O=!((a*(b+c*d)+(e+f)*(g*h+i*j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+efg)(h+i+j))'" 11 O=!((a*(b+c*d)+e*f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+efg)(h+i+j+k))'" 12 O=!((a*(b+c*d)+e*f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+ef(g+h))(i+j+k))'" 12 O=!((a*(b+c*d)+e*f*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+ef(g+h))(i+j+k+l))'" 13 O=!((a*(b+c*d)+e*f*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+e(f+g)(h+i))(j+k+l))'" 13 O=!((a*(b+c*d)+e*(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+e(f+g)(h+i))(j+k+l+m))'" 14 O=!((a*(b+c*d)+e*(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+(e+f)(g+h)(i+j))(k+l+m))'" 14 O=!((a*(b+c*d)+(e+f)*(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+(e+f)(g+h)(i+j))(k+l+m+n))'" 15 O=!((a*(b+c*d)+(e+f)*(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c(d+e))+fgh)(i+j+k))'" 12 O=!((a*(b+c*(d+e))+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c(d+e))+fgh)(i+j+k+l))'" 13 O=!((a*(b+c*(d+e))+f*g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+(c+d)(e+f))+ghi)(j+k+l))'" 13 O=!((a*(b+(c+d)*(e+f))+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+(c+d)(e+f))+ghi)(j+k+l+m))'" 14 O=!((a*(b+(c+d)*(e+f))+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+f(gh+ij))(k+l+m))'" 14 O=!((a*(b*c+d*e)+f*(g*h+i*j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+f(gh+ij))(k+l+m+n))'" 15 O=!((a*(b*c+d*e)+f*(g*h+i*j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+(f+g)(h+i))(j+k+l))'" 13 O=!((a*(b*c+d*e)+(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+(f+g)(h+i))(j+k+l+m))'" 14 O=!((a*(b*c+d*e)+(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+(f+g)(h+ij))(k+l+m))'" 14 O=!((a*(b*c+d*e)+(f+g)*(h+i*j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+(f+g)(h+ij))(k+l+m+n))'" 15 O=!((a*(b*c+d*e)+(f+g)*(h+i*j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+(f+g)(hi+jk))(l+m+n))'" 15 O=!((a*(b*c+d*e)+(f+g)*(h*i+j*k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+(f+g)(hi+jk))(l+m+n+o))'" 16 O=!((a*(b*c+d*e)+(f+g)*(h*i+j*k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+fgh)(i+j+k))'" 12 O=!((a*(b*c+d*e)+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+fgh)(i+j+k+l))'" 13 O=!((a*(b*c+d*e)+f*g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+fg(h+i))(j+k+l))'" 13 O=!((a*(b*c+d*e)+f*g*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+fg(h+i))(j+k+l+m))'" 14 O=!((a*(b*c+d*e)+f*g*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+f(g+h)(i+j))(k+l+m))'" 14 O=!((a*(b*c+d*e)+f*(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+f(g+h)(i+j))(k+l+m+n))'" 15 O=!((a*(b*c+d*e)+f*(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+(f+g)(h+i)(j+k))(l+m+n))'" 15 O=!((a*(b*c+d*e)+(f+g)*(h+i)*(j+k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+(f+g)(h+i)(j+k))(l+m+n+o))'" 16 O=!((a*(b*c+d*e)+(f+g)*(h+i)*(j+k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+d(e+f))+ghi)(j+k+l))'" 13 O=!((a*(b*c+d*(e+f))+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+d(e+f))+ghi)(j+k+l+m))'" 14 O=!((a*(b*c+d*(e+f))+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+(d+e)(f+g))+hij)(k+l+m))'" 14 O=!((a*(b*c+(d+e)*(f+g))+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+(d+e)(f+g))+hij)(k+l+m+n))'" 15 O=!((a*(b*c+(d+e)*(f+g))+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c+d)+efg)(h+i+j))'" 11 O=!((a*(b+c+d)+e*f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c+d)+efg)(h+i+j+k))'" 12 O=!((a*(b+c+d)+e*f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c+de)+fgh)(i+j+k))'" 12 O=!((a*(b+c+d*e)+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c+de)+fgh)(i+j+k+l))'" 13 O=!((a*(b+c+d*e)+f*g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd+ef)+ghi)(j+k+l))'" 13 O=!((a*(b+c*d+e*f)+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd+ef)+ghi)(j+k+l+m))'" 14 O=!((a*(b+c*d+e*f)+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de+fg)+hij)(k+l+m))'" 14 O=!((a*(b*c+d*e+f*g)+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de+fg)+hij)(k+l+m+n))'" 15 O=!((a*(b*c+d*e+f*g)+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))((i+j)(k+l)+(m+n)(o+p)))'" 17 O=!(((a+b)*(c+d)+(e+f)*(g+h))*((i+j)*(k+l)+(m+n)*(o+p))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+j+k))'" 12 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+j+kl))'" 13 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+j+k(l+m)))'" 14 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+j+(k+l)(m+n)))'" 15 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+jk+lm))'" 14 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+jk+l(m+n)))'" 15 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j*k+l*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+jk+(l+m)(n+o)))'" 16 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j*k+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(ij+kl+mn))'" 15 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(ij+kl+m(n+o)))'" 16 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i*j+k*l+m*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(ij+kl+(m+n)(o+p)))'" 17 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i*j+k*l+(m+n)*(o+p))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+j+k+l))'" 13 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+j+k+lm))'" 14 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j+k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+j+kl+mn))'" 15 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+jk+lm+no))'" 16 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(ij+kl+mn+op))'" 17 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i*j+k*l+m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+hi))(j+k+l))'" 13 O=!(((a+b)*(c+d)+(e+f)*(g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+hi))(j+k+l+m))'" 14 O=!(((a+b)*(c+d)+(e+f)*(g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(gh+ij))(k+l+m))'" 14 O=!(((a+b)*(c+d)+(e+f)*(g*h+i*j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(gh+ij))(k+l+m+n))'" 15 O=!(((a+b)*(c+d)+(e+f)*(g*h+i*j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+efg)(h+i+j))'" 11 O=!(((a+b)*(c+d)+e*f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+efg)(h+i+j+k))'" 12 O=!(((a+b)*(c+d)+e*f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+ef(g+h))(i+j+k))'" 12 O=!(((a+b)*(c+d)+e*f*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+ef(g+h))(i+j+k+l))'" 13 O=!(((a+b)*(c+d)+e*f*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+e(f+g)(h+i))(j+k+l))'" 13 O=!(((a+b)*(c+d)+e*(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+e(f+g)(h+i))(j+k+l+m))'" 14 O=!(((a+b)*(c+d)+e*(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h)(i+j))(k+l+m))'" 14 O=!(((a+b)*(c+d)+(e+f)*(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h)(i+j))(k+l+m+n))'" 15 O=!(((a+b)*(c+d)+(e+f)*(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+(f+g)(h+ij))(k+l+m))'" 14 O=!(((a+b)*(c+d*e)+(f+g)*(h+i*j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+(f+g)(h+ij))(k+l+m+n))'" 15 O=!(((a+b)*(c+d*e)+(f+g)*(h+i*j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+(f+g)(hi+jk))(l+m+n))'" 15 O=!(((a+b)*(c+d*e)+(f+g)*(h*i+j*k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+(f+g)(hi+jk))(l+m+n+o))'" 16 O=!(((a+b)*(c+d*e)+(f+g)*(h*i+j*k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+fgh)(i+j+k))'" 12 O=!(((a+b)*(c+d*e)+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+fgh)(i+j+k+l))'" 13 O=!(((a+b)*(c+d*e)+f*g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+fg(h+i))(j+k+l))'" 13 O=!(((a+b)*(c+d*e)+f*g*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+fg(h+i))(j+k+l+m))'" 14 O=!(((a+b)*(c+d*e)+f*g*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+f(g+h)(i+j))(k+l+m))'" 14 O=!(((a+b)*(c+d*e)+f*(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+f(g+h)(i+j))(k+l+m+n))'" 15 O=!(((a+b)*(c+d*e)+f*(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+(f+g)(h+i)(j+k))(l+m+n))'" 15 O=!(((a+b)*(c+d*e)+(f+g)*(h+i)*(j+k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+(f+g)(h+i)(j+k))(l+m+n+o))'" 16 O=!(((a+b)*(c+d*e)+(f+g)*(h+i)*(j+k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d(e+f))+ghi)(j+k+l))'" 13 O=!(((a+b)*(c+d*(e+f))+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d(e+f))+ghi)(j+k+l+m))'" 14 O=!(((a+b)*(c+d*(e+f))+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+(d+e)(f+g))+hij)(k+l+m))'" 14 O=!(((a+b)*(c+(d+e)*(f+g))+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+(d+e)(f+g))+hij)(k+l+m+n))'" 15 O=!(((a+b)*(c+(d+e)*(f+g))+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+(g+h)(ij+kl))(m+n+o))'" 16 O=!(((a+b)*(c*d+e*f)+(g+h)*(i*j+k*l))*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+(g+h)(ij+kl))(m+n+o+p))'" 17 O=!(((a+b)*(c*d+e*f)+(g+h)*(i*j+k*l))*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+ghi)(j+k+l))'" 13 O=!(((a+b)*(c*d+e*f)+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+ghi)(j+k+l+m))'" 14 O=!(((a+b)*(c*d+e*f)+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+gh(i+j))(k+l+m))'" 14 O=!(((a+b)*(c*d+e*f)+g*h*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+gh(i+j))(k+l+m+n))'" 15 O=!(((a+b)*(c*d+e*f)+g*h*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+g(h+i)(j+k))(l+m+n))'" 15 O=!(((a+b)*(c*d+e*f)+g*(h+i)*(j+k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+g(h+i)(j+k))(l+m+n+o))'" 16 O=!(((a+b)*(c*d+e*f)+g*(h+i)*(j+k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+(g+h)(i+j)(k+l))(m+n+o))'" 16 O=!(((a+b)*(c*d+e*f)+(g+h)*(i+j)*(k+l))*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+(g+h)(i+j)(k+l))(m+n+o+p))'" 17 O=!(((a+b)*(c*d+e*f)+(g+h)*(i+j)*(k+l))*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+e(f+g))+hij)(k+l+m))'" 14 O=!(((a+b)*(c*d+e*(f+g))+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+e(f+g))+hij)(k+l+m+n))'" 15 O=!(((a+b)*(c*d+e*(f+g))+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+(e+f)(g+h))+ijk)(l+m+n))'" 15 O=!(((a+b)*(c*d+(e+f)*(g+h))+i*j*k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+(e+f)(g+h))+ijk)(l+m+n+o))'" 16 O=!(((a+b)*(c*d+(e+f)*(g+h))+i*j*k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d+e)+fgh)(i+j+k))'" 12 O=!(((a+b)*(c+d+e)+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d+e)+fgh)(i+j+k+l))'" 13 O=!(((a+b)*(c+d+e)+f*g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d+ef)+ghi)(j+k+l))'" 13 O=!(((a+b)*(c+d+e*f)+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d+ef)+ghi)(j+k+l+m))'" 14 O=!(((a+b)*(c+d+e*f)+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de+fg)+hij)(k+l+m))'" 14 O=!(((a+b)*(c+d*e+f*g)+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de+fg)+hij)(k+l+m+n))'" 15 O=!(((a+b)*(c+d*e+f*g)+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef+gh)+ijk)(l+m+n))'" 15 O=!(((a+b)*(c*d+e*f+g*h)+i*j*k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef+gh)+ijk)(l+m+n+o))'" 16 O=!(((a+b)*(c*d+e*f+g*h)+i*j*k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+bc)(d+e+f)+ghi)(j+k+l))'" 13 O=!(((a+b*c)*(d+e+f)+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+bc)(d+e+f)+ghi)(j+k+l+m))'" 14 O=!(((a+b*c)*(d+e+f)+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b(c+d))(e+f+g)+hij)(k+l+m))'" 14 O=!(((a+b*(c+d))*(e+f+g)+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b(c+d))(e+f+g)+hij)(k+l+m+n))'" 15 O=!(((a+b*(c+d))*(e+f+g)+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+(b+c)(d+e))(f+g+h)+ijk)(l+m+n))'" 15 O=!(((a+(b+c)*(d+e))*(f+g+h)+i*j*k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+(b+c)(d+e))(f+g+h)+ijk)(l+m+n+o))'" 16 O=!(((a+(b+c)*(d+e))*(f+g+h)+i*j*k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((ab+cd)(e+f+g)+hij)(k+l+m))'" 14 O=!(((a*b+c*d)*(e+f+g)+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((ab+cd)(e+f+g)+hij)(k+l+m+n))'" 15 O=!(((a*b+c*d)*(e+f+g)+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((ab+c(d+e))(f+g+h)+ijk)(l+m+n))'" 15 O=!(((a*b+c*(d+e))*(f+g+h)+i*j*k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((ab+c(d+e))(f+g+h)+ijk)(l+m+n+o))'" 16 O=!(((a*b+c*(d+e))*(f+g+h)+i*j*k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((ab+(c+d)(e+f))(g+h+i)+jkl)(m+n+o))'" 16 O=!(((a*b+(c+d)*(e+f))*(g+h+i)+j*k*l)*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((ab+(c+d)(e+f))(g+h+i)+jkl)(m+n+o+p))'" 17 O=!(((a*b+(c+d)*(e+f))*(g+h+i)+j*k*l)*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b+c)(d+e+f)+ghi)(j+k+l))'" 13 O=!(((a+b+c)*(d+e+f)+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b+c)(d+e+f)+ghi)(j+k+l+m))'" 14 O=!(((a+b+c)*(d+e+f)+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b+c)(d+e+fg)+hij)(k+l+m))'" 14 O=!(((a+b+c)*(d+e+f*g)+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b+c)(d+e+fg)+hij)(k+l+m+n))'" 15 O=!(((a+b+c)*(d+e+f*g)+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b+c)(d+ef+gh)+ijk)(l+m+n))'" 15 O=!(((a+b+c)*(d+e*f+g*h)+i*j*k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b+c)(d+ef+gh)+ijk)(l+m+n+o))'" 16 O=!(((a+b+c)*(d+e*f+g*h)+i*j*k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b+c)(de+fg+hi)+jkl)(m+n+o))'" 16 O=!(((a+b+c)*(d*e+f*g+h*i)+j*k*l)*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b+c)(de+fg+hi)+jkl)(m+n+o+p))'" 17 O=!(((a+b+c)*(d*e+f*g+h*i)+j*k*l)*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def)(g+h+i))'" 10 O=!((a*b*c+d*e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def)(g+h+i+j))'" 11 O=!((a*b*c+d*e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+de(f+g))(h+i+j))'" 11 O=!((a*b*c+d*e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+de(f+g))(h+i+j+k))'" 12 O=!((a*b*c+d*e*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+de(f+g+h))(i+j+k))'" 12 O=!((a*b*c+d*e*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+de(f+g+h))(i+j+k+l))'" 13 O=!((a*b*c+d*e*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+d(e+f)(g+h))(i+j+k))'" 12 O=!((a*b*c+d*(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+d(e+f)(g+h))(i+j+k+l))'" 13 O=!((a*b*c+d*(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+d(e+f)(g+h+i))(j+k+l))'" 13 O=!((a*b*c+d*(e+f)*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+d(e+f)(g+h+i))(j+k+l+m))'" 14 O=!((a*b*c+d*(e+f)*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+d(e+f+g)(h+i+j))(k+l+m))'" 14 O=!((a*b*c+d*(e+f+g)*(h+i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+d(e+f+g)(h+i+j))(k+l+m+n))'" 15 O=!((a*b*c+d*(e+f+g)*(h+i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e)(f+g)(h+i))(j+k+l))'" 13 O=!((a*b*c+(d+e)*(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e)(f+g)(h+i))(j+k+l+m))'" 14 O=!((a*b*c+(d+e)*(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e)(f+g)(h+i+j))(k+l+m))'" 14 O=!((a*b*c+(d+e)*(f+g)*(h+i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e)(f+g)(h+i+j))(k+l+m+n))'" 15 O=!((a*b*c+(d+e)*(f+g)*(h+i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e)(f+g+h)(i+j+k))(l+m+n))'" 15 O=!((a*b*c+(d+e)*(f+g+h)*(i+j+k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e)(f+g+h)(i+j+k))(l+m+n+o))'" 16 O=!((a*b*c+(d+e)*(f+g+h)*(i+j+k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e+f)(g+h+i)(j+k+l))(m+n+o))'" 16 O=!((a*b*c+(d+e+f)*(g+h+i)*(j+k+l))*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e+f)(g+h+i)(j+k+l))(m+n+o+p))'" 17 O=!((a*b*c+(d+e+f)*(g+h+i)*(j+k+l))*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab(c+d)+ef(g+h))(i+j+k))'" 12 O=!((a*b*(c+d)+e*f*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab(c+d)+ef(g+h))(i+j+k+l))'" 13 O=!((a*b*(c+d)+e*f*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab(c+d)+e(f+g)(h+i))(j+k+l))'" 13 O=!((a*b*(c+d)+e*(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab(c+d)+e(f+g)(h+i))(j+k+l+m))'" 14 O=!((a*b*(c+d)+e*(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab(c+d)+(e+f)(g+h)(i+j))(k+l+m))'" 14 O=!((a*b*(c+d)+(e+f)*(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab(c+d)+(e+f)(g+h)(i+j))(k+l+m+n))'" 15 O=!((a*b*(c+d)+(e+f)*(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)(d+e)+f(g+h)(i+j))(k+l+m))'" 14 O=!((a*(b+c)*(d+e)+f*(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)(d+e)+f(g+h)(i+j))(k+l+m+n))'" 15 O=!((a*(b+c)*(d+e)+f*(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)(d+e)+(f+g)(h+i)(j+k))(l+m+n))'" 15 O=!((a*(b+c)*(d+e)+(f+g)*(h+i)*(j+k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)(d+e)+(f+g)(h+i)(j+k))(l+m+n+o))'" 16 O=!((a*(b+c)*(d+e)+(f+g)*(h+i)*(j+k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)(e+f)+(g+h)(i+j)(k+l))(m+n+o))'" 16 O=!(((a+b)*(c+d)*(e+f)+(g+h)*(i+j)*(k+l))*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)(e+f)+(g+h)(i+j)(k+l))(m+n+o+p))'" 17 O=!(((a+b)*(c+d)*(e+f)+(g+h)*(i+j)*(k+l))*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f))'" 7 O=!((a+b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg))'" 8 O=!((a+b+c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f(g+h)))'" 9 O=!((a+b+c)*(d+e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f(g+hi)))'" 10 O=!((a+b+c)*(d+e+f*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f(gh+ij)))'" 11 O=!((a+b+c)*(d+e+f*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+(f+g)(h+i)))'" 10 O=!((a+b+c)*(d+e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+(f+g)(h+ij)))'" 11 O=!((a+b+c)*(d+e+(f+g)*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+(f+g)(hi+jk)))'" 12 O=!((a+b+c)*(d+e+(f+g)*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fgh))'" 9 O=!((a+b+c)*(d+e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg(h+i)))'" 10 O=!((a+b+c)*(d+e+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f(g+h)(i+j)))'" 11 O=!((a+b+c)*(d+e+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+(f+g)(h+i)(j+k)))'" 12 O=!((a+b+c)*(d+e+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh))'" 9 O=!((a+b+c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+g(h+i)))'" 10 O=!((a+b+c)*(d+e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+g(h+ij)))'" 11 O=!((a+b+c)*(d+e*f+g*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+g(hi+jk)))'" 12 O=!((a+b+c)*(d+e*f+g*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+(g+h)(i+j)))'" 11 O=!((a+b+c)*(d+e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+(g+h)(i+jk)))'" 12 O=!((a+b+c)*(d+e*f+(g+h)*(i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+(g+h)(ij+kl)))'" 13 O=!((a+b+c)*(d+e*f+(g+h)*(i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+ghi))'" 10 O=!((a+b+c)*(d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh(i+j)))'" 11 O=!((a+b+c)*(d+e*f+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+g(h+i)(j+k)))'" 12 O=!((a+b+c)*(d+e*f+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+(g+h)(i+j)(k+l)))'" 13 O=!((a+b+c)*(d+e*f+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e(f+g)+hij))'" 11 O=!((a+b+c)*(d+e*(f+g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e(f+gh)+ijk))'" 12 O=!((a+b+c)*(d+e*(f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e(fg+hi)+jkl))'" 13 O=!((a+b+c)*(d+e*(f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+(e+f)(g+h)+ijk))'" 12 O=!((a+b+c)*(d+(e+f)*(g+h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+(e+f)(g+hi)+jkl))'" 13 O=!((a+b+c)*(d+(e+f)*(g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+(e+f)(gh+ij)+klm))'" 14 O=!((a+b+c)*(d+(e+f)*(g*h+i*j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+efg+hij))'" 11 O=!((a+b+c)*(d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+efg+hi(j+k)))'" 12 O=!((a+b+c)*(d+e*f*g+h*i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+efg+h(i+j)(k+l)))'" 13 O=!((a+b+c)*(d+e*f*g+h*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+efg+(h+i)(j+k)(l+m)))'" 14 O=!((a+b+c)*(d+e*f*g+(h+i)*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi))'" 10 O=!((a+b+c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+h(i+j)))'" 11 O=!((a+b+c)*(d*e+f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+h(i+jk)))'" 12 O=!((a+b+c)*(d*e+f*g+h*(i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+h(ij+kl)))'" 13 O=!((a+b+c)*(d*e+f*g+h*(i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+(h+i)(j+k)))'" 12 O=!((a+b+c)*(d*e+f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+(h+i)(j+kl)))'" 13 O=!((a+b+c)*(d*e+f*g+(h+i)*(j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+(h+i)(jk+lm)))'" 14 O=!((a+b+c)*(d*e+f*g+(h+i)*(j*k+l*m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hij))'" 11 O=!((a+b+c)*(d*e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi(j+k)))'" 12 O=!((a+b+c)*(d*e+f*g+h*i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+h(i+j)(k+l)))'" 13 O=!((a+b+c)*(d*e+f*g+h*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+(h+i)(j+k)(l+m)))'" 14 O=!((a+b+c)*(d*e+f*g+(h+i)*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+f(g+h)+ijk))'" 12 O=!((a+b+c)*(d*e+f*(g+h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+f(g+hi)+jkl))'" 13 O=!((a+b+c)*(d*e+f*(g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+f(gh+ij)+klm))'" 14 O=!((a+b+c)*(d*e+f*(g*h+i*j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+(f+g)(h+i)+jkl))'" 13 O=!((a+b+c)*(d*e+(f+g)*(h+i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+(f+g)(h+ij)+klm))'" 14 O=!((a+b+c)*(d*e+(f+g)*(h+i*j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+(f+g)(hi+jk)+lmn))'" 15 O=!((a+b+c)*(d*e+(f+g)*(h*i+j*k)+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fgh+ijk))'" 12 O=!((a+b+c)*(d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fgh+ij(k+l)))'" 13 O=!((a+b+c)*(d*e+f*g*h+i*j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fgh+i(j+k)(l+m)))'" 14 O=!((a+b+c)*(d*e+f*g*h+i*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fgh+(i+j)(k+l)(m+n)))'" 15 O=!((a+b+c)*(d*e+f*g*h+(i+j)*(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d(e+f)+ghi+jkl))'" 13 O=!((a+b+c)*(d*(e+f)+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d(e+fg)+hij+klm))'" 14 O=!((a+b+c)*(d*(e+f*g)+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d(ef+gh)+ijk+lmn))'" 15 O=!((a+b+c)*(d*(e*f+g*h)+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)((d+e)(f+g)+hij+klm))'" 14 O=!((a+b+c)*((d+e)*(f+g)+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)((d+e)(f+gh)+ijk+lmn))'" 15 O=!((a+b+c)*((d+e)*(f+g*h)+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)((d+e)(fg+hi)+jkl+mno))'" 16 O=!((a+b+c)*((d+e)*(f*g+h*i)+j*k*l+m*n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(def+ghi+jkl))'" 13 O=!((a+b+c)*(d*e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(def+ghi+jk(l+m)))'" 14 O=!((a+b+c)*(d*e*f+g*h*i+j*k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(def+ghi+j(k+l)(m+n)))'" 15 O=!((a+b+c)*(d*e*f+g*h*i+j*(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(def+ghi+(j+k)(l+m)(n+o)))'" 16 O=!((a+b+c)*(d*e*f+g*h*i+(j+k)*(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g))'" 8 O=!((a+b+c)*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+gh))'" 9 O=!((a+b+c)*(d+e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+ghi))'" 10 O=!((a+b+c)*(d+e+f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg+hi))'" 10 O=!((a+b+c)*(d+e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg+hij))'" 11 O=!((a+b+c)*(d+e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fgh+ijk))'" 12 O=!((a+b+c)*(d+e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh+ij))'" 11 O=!((a+b+c)*(d+e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh+ijk))'" 12 O=!((a+b+c)*(d+e*f+g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+ghi+jkl))'" 13 O=!((a+b+c)*(d+e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+efg+hij+klm))'" 14 O=!((a+b+c)*(d+e*f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi+jk))'" 12 O=!((a+b+c)*(d*e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi+jkl))'" 13 O=!((a+b+c)*(d*e+f*g+h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hij+klm))'" 14 O=!((a+b+c)*(d*e+f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fgh+ijk+lmn))'" 15 O=!((a+b+c)*(d*e+f*g*h+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(def+ghi+jkl+mno))'" 16 O=!((a+b+c)*(d*e*f+g*h*i+j*k*l+m*n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+gh))'" 9 O=!((a+b+c*d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+g(h+i)))'" 10 O=!((a+b+c*d)*(e+f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+(g+h)(i+j)))'" 11 O=!((a+b+c*d)*(e+f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+fg+hi))'" 10 O=!((a+b+c*d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+fg+h(i+j)))'" 11 O=!((a+b+c*d)*(e+f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+fg+(h+i)(j+k)))'" 12 O=!((a+b+c*d)*(e+f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(ef+gh+ij))'" 11 O=!((a+b+c*d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(ef+gh+i(j+k)))'" 12 O=!((a+b+c*d)*(e*f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(ef+gh+(i+j)(k+l)))'" 13 O=!((a+b+c*d)*(e*f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+g+h))'" 9 O=!((a+b+c*d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+g+hi))'" 10 O=!((a+b+c*d)*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+gh+ij))'" 11 O=!((a+b+c*d)*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+fg+hi+jk))'" 12 O=!((a+b+c*d)*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(ef+gh+ij+kl))'" 13 O=!((a+b+c*d)*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(f+g+h(i+j)))'" 11 O=!((a+b+c*(d+e))*(f+g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(f+g+(h+i)(j+k)))'" 12 O=!((a+b+c*(d+e))*(f+g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(f+gh+ij))'" 11 O=!((a+b+c*(d+e))*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(f+gh+i(j+k)))'" 12 O=!((a+b+c*(d+e))*(f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(f+gh+(i+j)(k+l)))'" 13 O=!((a+b+c*(d+e))*(f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(fg+hi+jk))'" 12 O=!((a+b+c*(d+e))*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(fg+hi+j(k+l)))'" 13 O=!((a+b+c*(d+e))*(f*g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(fg+hi+(j+k)(l+m)))'" 14 O=!((a+b+c*(d+e))*(f*g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(f+g+h+i))'" 10 O=!((a+b+c*(d+e))*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(f+g+h+ij))'" 11 O=!((a+b+c*(d+e))*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(f+g+hi+jk))'" 12 O=!((a+b+c*(d+e))*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(f+gh+ij+kl))'" 13 O=!((a+b+c*(d+e))*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(fg+hi+jk+lm))'" 14 O=!((a+b+c*(d+e))*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+ef))(g+h+i+j))'" 11 O=!((a+b+c*(d+e*f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(de+fg))(h+i+j+k))'" 12 O=!((a+b+c*(d*e+f*g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(g+h+(i+j)(k+l)))'" 13 O=!((a+b+(c+d)*(e+f))*(g+h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(g+hi+jk))'" 12 O=!((a+b+(c+d)*(e+f))*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(g+hi+j(k+l)))'" 13 O=!((a+b+(c+d)*(e+f))*(g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(g+hi+(j+k)(l+m)))'" 14 O=!((a+b+(c+d)*(e+f))*(g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(gh+ij+kl))'" 13 O=!((a+b+(c+d)*(e+f))*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(gh+ij+k(l+m)))'" 14 O=!((a+b+(c+d)*(e+f))*(g*h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(gh+ij+(k+l)(m+n)))'" 15 O=!((a+b+(c+d)*(e+f))*(g*h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(g+h+i+j))'" 11 O=!((a+b+(c+d)*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(g+h+i+jk))'" 12 O=!((a+b+(c+d)*(e+f))*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(g+h+ij+kl))'" 13 O=!((a+b+(c+d)*(e+f))*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(g+hi+jk+lm))'" 14 O=!((a+b+(c+d)*(e+f))*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(gh+ij+kl+mn))'" 15 O=!((a+b+(c+d)*(e+f))*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+fg))(h+i+j+k))'" 12 O=!((a+b+(c+d)*(e+f*g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(ef+gh))(i+j+k+l))'" 13 O=!((a+b+(c+d)*(e*f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cde)(f+g+h+i))'" 10 O=!((a+b+c*d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd(e+f))(g+h+i+j))'" 11 O=!((a+b+c*d*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e)(f+g))(h+i+j+k))'" 12 O=!((a+b+c*(d+e)*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f)(g+h))(i+j+k+l))'" 13 O=!((a+b+(c+d)*(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+gh+ij))'" 11 O=!((a+b*c+d*e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+gh+i(j+k)))'" 12 O=!((a+b*c+d*e)*(f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+gh+(i+j)(k+l)))'" 13 O=!((a+b*c+d*e)*(f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(fg+hi+jk))'" 12 O=!((a+b*c+d*e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(fg+hi+j(k+l)))'" 13 O=!((a+b*c+d*e)*(f*g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(fg+hi+(j+k)(l+m)))'" 14 O=!((a+b*c+d*e)*(f*g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+g+h+i))'" 10 O=!((a+b*c+d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+g+h+ij))'" 11 O=!((a+b*c+d*e)*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+g+hi+jk))'" 12 O=!((a+b*c+d*e)*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+gh+ij+kl))'" 13 O=!((a+b*c+d*e)*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(fg+hi+jk+lm))'" 14 O=!((a+b*c+d*e)*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(g+hi+j(k+l)))'" 13 O=!((a+b*c+d*(e+f))*(g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(g+hi+(j+k)(l+m)))'" 14 O=!((a+b*c+d*(e+f))*(g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(gh+ij+kl))'" 13 O=!((a+b*c+d*(e+f))*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(gh+ij+k(l+m)))'" 14 O=!((a+b*c+d*(e+f))*(g*h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(gh+ij+(k+l)(m+n)))'" 15 O=!((a+b*c+d*(e+f))*(g*h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(g+h+i+j))'" 11 O=!((a+b*c+d*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(g+h+i+jk))'" 12 O=!((a+b*c+d*(e+f))*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(g+h+ij+kl))'" 13 O=!((a+b*c+d*(e+f))*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(g+hi+jk+lm))'" 14 O=!((a+b*c+d*(e+f))*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(gh+ij+kl+mn))'" 15 O=!((a+b*c+d*(e+f))*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+fg))(h+i+j+k))'" 12 O=!((a+b*c+d*(e+f*g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(ef+gh))(i+j+k+l))'" 13 O=!((a+b*c+d*(e*f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g))(h+ij+(k+l)(m+n)))'" 15 O=!((a+b*c+(d+e)*(f+g))*(h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g))(hi+jk+lm))'" 14 O=!((a+b*c+(d+e)*(f+g))*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g))(hi+jk+l(m+n)))'" 15 O=!((a+b*c+(d+e)*(f+g))*(h*i+j*k+l*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g))(hi+jk+(l+m)(n+o)))'" 16 O=!((a+b*c+(d+e)*(f+g))*(h*i+j*k+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g))(h+i+j+k))'" 12 O=!((a+b*c+(d+e)*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g))(h+i+j+kl))'" 13 O=!((a+b*c+(d+e)*(f+g))*(h+i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g))(h+i+jk+lm))'" 14 O=!((a+b*c+(d+e)*(f+g))*(h+i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g))(h+ij+kl+mn))'" 15 O=!((a+b*c+(d+e)*(f+g))*(h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g))(hi+jk+lm+no))'" 16 O=!((a+b*c+(d+e)*(f+g))*(h*i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+gh))(i+j+k+l))'" 13 O=!((a+b*c+(d+e)*(f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(fg+hi))(j+k+l+m))'" 14 O=!((a+b*c+(d+e)*(f*g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+def)(g+h+i+j))'" 11 O=!((a+b*c+d*e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de(f+g))(h+i+j+k))'" 12 O=!((a+b*c+d*e*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f)(g+h))(i+j+k+l))'" 13 O=!((a+b*c+d*(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g)(h+i))(j+k+l+m))'" 14 O=!((a+b*c+(d+e)*(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d)+efg)(h+i+j+k))'" 12 O=!((a+b*(c+d)+e*f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+de)+fgh)(i+j+k+l))'" 13 O=!((a+b*(c+d*e)+f*g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+ef)+ghi)(j+k+l+m))'" 14 O=!((a+b*(c*d+e*f)+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e)+fgh)(i+j+k+l))'" 13 O=!((a+(b+c)*(d+e)+f*g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+ef)+ghi)(j+k+l+m))'" 14 O=!((a+(b+c)*(d+e*f)+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+fg)+hij)(k+l+m+n))'" 15 O=!((a+(b+c)*(d*e+f*g)+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd+efg)(h+i+j+k))'" 12 O=!((a+b*c*d+e*f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd+ef(g+h))(i+j+k+l))'" 13 O=!((a+b*c*d+e*f*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd+e(f+g)(h+i))(j+k+l+m))'" 14 O=!((a+b*c*d+e*(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd+(e+f)(g+h)(i+j))(k+l+m+n))'" 15 O=!((a+b*c*d+(e+f)*(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(gh+ij+kl))'" 13 O=!((a*b+c*d+e*f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(gh+ij+k(l+m)))'" 14 O=!((a*b+c*d+e*f)*(g*h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(gh+ij+(k+l)(m+n)))'" 15 O=!((a*b+c*d+e*f)*(g*h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(g+h+i+j))'" 11 O=!((a*b+c*d+e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(g+h+i+jk))'" 12 O=!((a*b+c*d+e*f)*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(g+h+ij+kl))'" 13 O=!((a*b+c*d+e*f)*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(g+hi+jk+lm))'" 14 O=!((a*b+c*d+e*f)*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(gh+ij+kl+mn))'" 15 O=!((a*b+c*d+e*f)*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(f+g))(hi+jk+l(m+n)))'" 15 O=!((a*b+c*d+e*(f+g))*(h*i+j*k+l*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(f+g))(hi+jk+(l+m)(n+o)))'" 16 O=!((a*b+c*d+e*(f+g))*(h*i+j*k+(l+m)*(n+o))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(f+g))(h+i+j+k))'" 12 O=!((a*b+c*d+e*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(f+g))(h+i+j+kl))'" 13 O=!((a*b+c*d+e*(f+g))*(h+i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(f+g))(h+i+jk+lm))'" 14 O=!((a*b+c*d+e*(f+g))*(h+i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(f+g))(h+ij+kl+mn))'" 15 O=!((a*b+c*d+e*(f+g))*(h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(f+g))(hi+jk+lm+no))'" 16 O=!((a*b+c*d+e*(f+g))*(h*i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(f+gh))(i+j+k+l))'" 13 O=!((a*b+c*d+e*(f+g*h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(fg+hi))(j+k+l+m))'" 14 O=!((a*b+c*d+e*(f*g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+(e+f)(g+h))(ij+kl+(m+n)(o+p)))'" 17 O=!((a*b+c*d+(e+f)*(g+h))*(i*j+k*l+(m+n)*(o+p))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+(e+f)(g+h))(i+j+k+l))'" 13 O=!((a*b+c*d+(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+(e+f)(g+h))(i+j+k+lm))'" 14 O=!((a*b+c*d+(e+f)*(g+h))*(i+j+k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+(e+f)(g+h))(i+j+kl+mn))'" 15 O=!((a*b+c*d+(e+f)*(g+h))*(i+j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+(e+f)(g+h))(i+jk+lm+no))'" 16 O=!((a*b+c*d+(e+f)*(g+h))*(i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+(e+f)(g+h))(ij+kl+mn+op))'" 17 O=!((a*b+c*d+(e+f)*(g+h))*(i*j+k*l+m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+(e+f)(g+hi))(j+k+l+m))'" 14 O=!((a*b+c*d+(e+f)*(g+h*i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+(e+f)(gh+ij))(k+l+m+n))'" 15 O=!((a*b+c*d+(e+f)*(g*h+i*j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+efg)(h+i+j+k))'" 12 O=!((a*b+c*d+e*f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef(g+h))(i+j+k+l))'" 13 O=!((a*b+c*d+e*f*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(f+g)(h+i))(j+k+l+m))'" 14 O=!((a*b+c*d+e*(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+(e+f)(g+h)(i+j))(k+l+m+n))'" 15 O=!((a*b+c*d+(e+f)*(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e)+fgh)(i+j+k+l))'" 13 O=!((a*b+c*(d+e)+f*g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+ef)+ghi)(j+k+l+m))'" 14 O=!((a*b+c*(d+e*f)+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+fg)+hij)(k+l+m+n))'" 15 O=!((a*b+c*(d*e+f*g)+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f)+ghi)(j+k+l+m))'" 14 O=!((a*b+(c+d)*(e+f)+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+fg)+hij)(k+l+m+n))'" 15 O=!((a*b+(c+d)*(e+f*g)+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+gh)+ijk)(l+m+n+o))'" 16 O=!((a*b+(c+d)*(e*f+g*h)+i*j*k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde+fgh)(i+j+k+l))'" 13 O=!((a*b+c*d*e+f*g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde+fg(h+i))(j+k+l+m))'" 14 O=!((a*b+c*d*e+f*g*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde+f(g+h)(i+j))(k+l+m+n))'" 15 O=!((a*b+c*d*e+f*(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde+(f+g)(h+i)(j+k))(l+m+n+o))'" 16 O=!((a*b+c*d*e+(f+g)*(h+i)*(j+k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+def+ghi)(j+k+l+m))'" 14 O=!((a*(b+c)+d*e*f+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+efg+hij)(k+l+m+n))'" 15 O=!((a*(b+c*d)+e*f*g+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+fgh+ijk)(l+m+n+o))'" 16 O=!((a*(b*c+d*e)+f*g*h+i*j*k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+efg+hij)(k+l+m+n))'" 15 O=!(((a+b)*(c+d)+e*f*g+h*i*j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+fgh+ijk)(l+m+n+o))'" 16 O=!(((a+b)*(c+d*e)+f*g*h+i*j*k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+ghi+jkl)(m+n+o+p))'" 17 O=!(((a+b)*(c*d+e*f)+g*h*i+j*k*l)*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def+ghi)(j+k+l+m))'" 14 O=!((a*b*c+d*e*f+g*h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def+gh(i+j))(k+l+m+n))'" 15 O=!((a*b*c+d*e*f+g*h*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def+g(h+i)(j+k))(l+m+n+o))'" 16 O=!((a*b*c+d*e*f+g*(h+i)*(j+k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def+(g+h)(i+j)(k+l))(m+n+o+p))'" 17 O=!((a*b*c+d*e*f+(g+h)*(i+j)*(k+l))*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h))'" 9 O=!((a+b+c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+hi))'" 10 O=!((a+b+c+d)*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+hij))'" 11 O=!((a+b+c+d)*(e+f+g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+gh+ij))'" 11 O=!((a+b+c+d)*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+gh+ijk))'" 12 O=!((a+b+c+d)*(e+f+g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+ghi+jkl))'" 13 O=!((a+b+c+d)*(e+f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+fg+hi+jk))'" 12 O=!((a+b+c+d)*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+fg+hi+jkl))'" 13 O=!((a+b+c+d)*(e+f*g+h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+fg+hij+klm))'" 14 O=!((a+b+c+d)*(e+f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+fgh+ijk+lmn))'" 15 O=!((a+b+c+d)*(e+f*g*h+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(ef+gh+ij+kl))'" 13 O=!((a+b+c+d)*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(ef+gh+ij+klm))'" 14 O=!((a+b+c+d)*(e*f+g*h+i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(ef+gh+ijk+lmn))'" 15 O=!((a+b+c+d)*(e*f+g*h+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(ef+ghi+jkl+mno))'" 16 O=!((a+b+c+d)*(e*f+g*h*i+j*k*l+m*n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(efg+hij+klm+nop))'" 17 O=!((a+b+c+d)*(e*f*g+h*i*j+k*l*m+n*o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+de)(f+g+h+ij))'" 11 O=!((a+b+c+d*e)*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+de)(f+g+hi+jk))'" 12 O=!((a+b+c+d*e)*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+de)(f+gh+ij+kl))'" 13 O=!((a+b+c+d*e)*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+de)(fg+hi+jk+lm))'" 14 O=!((a+b+c+d*e)*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd+ef)(g+h+ij+kl))'" 13 O=!((a+b+c*d+e*f)*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd+ef)(g+hi+jk+lm))'" 14 O=!((a+b+c*d+e*f)*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd+ef)(gh+ij+kl+mn))'" 15 O=!((a+b+c*d+e*f)*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de+fg)(h+ij+kl+mn))'" 15 O=!((a+b*c+d*e+f*g)*(h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de+fg)(hi+jk+lm+no))'" 16 O=!((a+b*c+d*e+f*g)*(h*i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef+gh)(ij+kl+mn+op))'" 17 O=!((a*b+c*d+e*f+g*h)*(i*j+k*l+m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc)'" 4 O=!(a*b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d))'" 5 O=!(a*b*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de))'" 6 O=!(a*b*(c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d(e+f)))'" 7 O=!(a*b*(c+d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d(e+f+g)))'" 8 O=!(a*b*(c+d*(e+f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+(d+e)(f+g)))'" 8 O=!(a*b*(c+(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+(d+e)(f+g+h)))'" 9 O=!(a*b*(c+(d+e)*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+(d+e+f)(g+h+i)))'" 10 O=!(a*b*(c+(d+e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef))'" 7 O=!(a*b*(c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+e(f+g)))'" 8 O=!(a*b*(c*d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+e(f+g+h)))'" 9 O=!(a*b*(c*d+e*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+(e+f)(g+h)))'" 9 O=!(a*b*(c*d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+(e+f)(g+h+i)))'" 10 O=!(a*b*(c*d+(e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+(e+f+g)(h+i+j)))'" 11 O=!(a*b*(c*d+(e+f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c(d+e)+f(g+h)))'" 9 O=!(a*b*(c*(d+e)+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c(d+e)+(f+g)(h+i)))'" 10 O=!(a*b*(c*(d+e)+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab((c+d)(e+f)+(g+h)(i+j)))'" 11 O=!(a*b*((c+d)*(e+f)+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e))'" 6 O=!(a*b*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+ef))'" 7 O=!(a*b*(c+d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e(f+g)))'" 8 O=!(a*b*(c+d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+(e+f)(g+h)))'" 9 O=!(a*b*(c+d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de+fg))'" 8 O=!(a*b*(c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de+f(g+h)))'" 9 O=!(a*b*(c+d*e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de+(f+g)(h+i)))'" 10 O=!(a*b*(c+d*e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef+gh))'" 9 O=!(a*b*(c*d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef+g(h+i)))'" 10 O=!(a*b*(c*d+e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef+(g+h)(i+j)))'" 11 O=!(a*b*(c*d+e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e+f))'" 7 O=!(a*b*(c+d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e+fg))'" 8 O=!(a*b*(c+d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+ef+gh))'" 9 O=!(a*b*(c+d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de+fg+hi))'" 10 O=!(a*b*(c+d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef+gh+ij))'" 11 O=!(a*b*(c*d+e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e))'" 6 O=!(a*(b+c)*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef))'" 7 O=!(a*(b+c)*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e(f+g)))'" 8 O=!(a*(b+c)*(d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e(f+g+h)))'" 9 O=!(a*(b+c)*(d+e*(f+g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+(e+f)(g+h)))'" 9 O=!(a*(b+c)*(d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+(e+f)(g+h+i)))'" 10 O=!(a*(b+c)*(d+(e+f)*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+(e+f+g)(h+i+j)))'" 11 O=!(a*(b+c)*(d+(e+f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg))'" 8 O=!(a*(b+c)*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+f(g+h)))'" 9 O=!(a*(b+c)*(d*e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+f(g+h+i)))'" 10 O=!(a*(b+c)*(d*e+f*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+(f+g)(h+i)))'" 10 O=!(a*(b+c)*(d*e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+(f+g)(h+i+j)))'" 11 O=!(a*(b+c)*(d*e+(f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+(f+g+h)(i+j+k)))'" 12 O=!(a*(b+c)*(d*e+(f+g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d(e+f)+g(h+i)))'" 10 O=!(a*(b+c)*(d*(e+f)+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d(e+f)+(g+h)(i+j)))'" 11 O=!(a*(b+c)*(d*(e+f)+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)((d+e)(f+g)+(h+i)(j+k)))'" 12 O=!(a*(b+c)*((d+e)*(f+g)+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f))'" 7 O=!(a*(b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+fg))'" 8 O=!(a*(b+c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f(g+h)))'" 9 O=!(a*(b+c)*(d+e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+(f+g)(h+i)))'" 10 O=!(a*(b+c)*(d+e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef+gh))'" 9 O=!(a*(b+c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef+g(h+i)))'" 10 O=!(a*(b+c)*(d+e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef+(g+h)(i+j)))'" 11 O=!(a*(b+c)*(d+e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg+hi))'" 10 O=!(a*(b+c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg+h(i+j)))'" 11 O=!(a*(b+c)*(d*e+f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg+(h+i)(j+k)))'" 12 O=!(a*(b+c)*(d*e+f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f+g))'" 8 O=!(a*(b+c)*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f+gh))'" 9 O=!(a*(b+c)*(d+e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+fg+hi))'" 10 O=!(a*(b+c)*(d+e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef+gh+ij))'" 11 O=!(a*(b+c)*(d+e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg+hi+jk))'" 12 O=!(a*(b+c)*(d*e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)(e+f+g))'" 8 O=!(a*(b+c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)(e+f+g+h))'" 9 O=!(a*(b+c*d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e))(f+g+h))'" 9 O=!(a*(b+c*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e))(f+g+h+i))'" 10 O=!(a*(b+c*(d+e))*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e+f))(g+h+i))'" 10 O=!(a*(b+c*(d+e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e+f))(g+h+i+j))'" 11 O=!(a*(b+c*(d+e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f))(g+h+i))'" 10 O=!(a*(b+(c+d)*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f))(g+h+i+j))'" 11 O=!(a*(b+(c+d)*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f+g))(h+i+j))'" 11 O=!(a*(b+(c+d)*(e+f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f+g))(h+i+j+k))'" 12 O=!(a*(b+(c+d)*(e+f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d+e)(f+g+h))(i+j+k))'" 12 O=!(a*(b+(c+d+e)*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d+e)(f+g+h))(i+j+k+l))'" 13 O=!(a*(b+(c+d+e)*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)(f+g+h))'" 9 O=!(a*(b*c+d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)(f+g+h+i))'" 10 O=!(a*(b*c+d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f))(g+h+i))'" 10 O=!(a*(b*c+d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f))(g+h+i+j))'" 11 O=!(a*(b*c+d*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f+g))(h+i+j))'" 11 O=!(a*(b*c+d*(e+f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f+g))(h+i+j+k))'" 12 O=!(a*(b*c+d*(e+f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g))(h+i+j))'" 11 O=!(a*(b*c+(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g))(h+i+j+k))'" 12 O=!(a*(b*c+(d+e)*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g+h))(i+j+k))'" 12 O=!(a*(b*c+(d+e)*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g+h))(i+j+k+l))'" 13 O=!(a*(b*c+(d+e)*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e+f)(g+h+i))(j+k+l))'" 13 O=!(a*(b*c+(d+e+f)*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e+f)(g+h+i))(j+k+l+m))'" 14 O=!(a*(b*c+(d+e+f)*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+e(f+g))(h+i+j))'" 11 O=!(a*(b*(c+d)+e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+e(f+g))(h+i+j+k))'" 12 O=!(a*(b*(c+d)+e*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+(e+f)(g+h))(i+j+k))'" 12 O=!(a*(b*(c+d)+(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+(e+f)(g+h))(i+j+k+l))'" 13 O=!(a*(b*(c+d)+(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+(f+g)(h+i))(j+k+l))'" 13 O=!(a*((b+c)*(d+e)+(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+(f+g)(h+i))(j+k+l+m))'" 14 O=!(a*((b+c)*(d+e)+(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g))'" 8 O=!(a*(b+c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+gh))'" 9 O=!(a*(b+c+d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g(h+i)))'" 10 O=!(a*(b+c+d)*(e+f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+(g+h)(i+j)))'" 11 O=!(a*(b+c+d)*(e+f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+fg+hi))'" 10 O=!(a*(b+c+d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+fg+h(i+j)))'" 11 O=!(a*(b+c+d)*(e+f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+fg+(h+i)(j+k)))'" 12 O=!(a*(b+c+d)*(e+f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(ef+gh+ij))'" 11 O=!(a*(b+c+d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(ef+gh+i(j+k)))'" 12 O=!(a*(b+c+d)*(e*f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(ef+gh+(i+j)(k+l)))'" 13 O=!(a*(b+c+d)*(e*f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g+h))'" 9 O=!(a*(b+c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g+hi))'" 10 O=!(a*(b+c+d)*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+gh+ij))'" 11 O=!(a*(b+c+d)*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+fg+hi+jk))'" 12 O=!(a*(b+c+d)*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(ef+gh+ij+kl))'" 13 O=!(a*(b+c+d)*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de)(f+g+h+i))'" 10 O=!(a*(b+c+d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d(e+f))(g+h+i+j))'" 11 O=!(a*(b+c+d*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+(d+e)(f+g))(h+i+j+k))'" 12 O=!(a*(b+c+(d+e)*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef)(g+h+i+j))'" 11 O=!(a*(b+c*d+e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+e(f+g))(h+i+j+k))'" 12 O=!(a*(b+c*d+e*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+(e+f)(g+h))(i+j+k+l))'" 13 O=!(a*(b+c*d+(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg)(h+i+j+k))'" 12 O=!(a*(b*c+d*e+f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+f(g+h))(i+j+k+l))'" 13 O=!(a*(b*c+d*e+f*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+(f+g)(h+i))(j+k+l+m))'" 14 O=!(a*(b*c+d*e+(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+g+h+i))'" 10 O=!(a*(b+c+d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+g+h+ij))'" 11 O=!(a*(b+c+d+e)*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+g+hi+jk))'" 12 O=!(a*(b+c+d+e)*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+gh+ij+kl))'" 13 O=!(a*(b+c+d+e)*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(fg+hi+jk+lm))'" 14 O=!(a*(b+c+d+e)*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f))'" 7 O=!((a+b)*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg))'" 8 O=!((a+b)*(c+d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f(g+h)))'" 9 O=!((a+b)*(c+d)*(e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f(g+h+i)))'" 10 O=!((a+b)*(c+d)*(e+f*(g+h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+(f+g)(h+i)))'" 10 O=!((a+b)*(c+d)*(e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+(f+g)(h+i+j)))'" 11 O=!((a+b)*(c+d)*(e+(f+g)*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+(f+g+h)(i+j+k)))'" 12 O=!((a+b)*(c+d)*(e+(f+g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh))'" 9 O=!((a+b)*(c+d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+g(h+i)))'" 10 O=!((a+b)*(c+d)*(e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+g(h+i+j)))'" 11 O=!((a+b)*(c+d)*(e*f+g*(h+i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+(g+h)(i+j)))'" 11 O=!((a+b)*(c+d)*(e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+(g+h)(i+j+k)))'" 12 O=!((a+b)*(c+d)*(e*f+(g+h)*(i+j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+(g+h+i)(j+k+l)))'" 13 O=!((a+b)*(c+d)*(e*f+(g+h+i)*(j+k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e(f+g)+h(i+j)))'" 11 O=!((a+b)*(c+d)*(e*(f+g)+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e(f+g)+(h+i)(j+k)))'" 12 O=!((a+b)*(c+d)*(e*(f+g)+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)((e+f)(g+h)+(i+j)(k+l)))'" 13 O=!((a+b)*(c+d)*((e+f)*(g+h)+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g))'" 8 O=!((a+b)*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+gh))'" 9 O=!((a+b)*(c+d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g(h+i)))'" 10 O=!((a+b)*(c+d)*(e+f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+(g+h)(i+j)))'" 11 O=!((a+b)*(c+d)*(e+f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg+hi))'" 10 O=!((a+b)*(c+d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg+h(i+j)))'" 11 O=!((a+b)*(c+d)*(e+f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg+(h+i)(j+k)))'" 12 O=!((a+b)*(c+d)*(e+f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh+ij))'" 11 O=!((a+b)*(c+d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh+i(j+k)))'" 12 O=!((a+b)*(c+d)*(e*f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh+(i+j)(k+l)))'" 13 O=!((a+b)*(c+d)*(e*f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g+h))'" 9 O=!((a+b)*(c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g+hi))'" 10 O=!((a+b)*(c+d)*(e+f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+gh+ij))'" 11 O=!((a+b)*(c+d)*(e+f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg+hi+jk))'" 12 O=!((a+b)*(c+d)*(e+f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh+ij+kl))'" 13 O=!((a+b)*(c+d)*(e*f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)(f+g+h))'" 9 O=!((a+b)*(c+d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)(f+g+h+i))'" 10 O=!((a+b)*(c+d*e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f))(g+h+i))'" 10 O=!((a+b)*(c+d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f))(g+h+i+j))'" 11 O=!((a+b)*(c+d*(e+f))*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f+g))(h+i+j))'" 11 O=!((a+b)*(c+d*(e+f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f+g))(h+i+j+k))'" 12 O=!((a+b)*(c+d*(e+f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g))(h+i+j))'" 11 O=!((a+b)*(c+(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g))(h+i+j+k))'" 12 O=!((a+b)*(c+(d+e)*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g+h))(i+j+k))'" 12 O=!((a+b)*(c+(d+e)*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g+h))(i+j+k+l))'" 13 O=!((a+b)*(c+(d+e)*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e+f)(g+h+i))(j+k+l))'" 13 O=!((a+b)*(c+(d+e+f)*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e+f)(g+h+i))(j+k+l+m))'" 14 O=!((a+b)*(c+(d+e+f)*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)(g+h+i))'" 10 O=!((a+b)*(c*d+e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)(g+h+i+j))'" 11 O=!((a+b)*(c*d+e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g))(h+i+j))'" 11 O=!((a+b)*(c*d+e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g))(h+i+j+k))'" 12 O=!((a+b)*(c*d+e*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g+h))(i+j+k))'" 12 O=!((a+b)*(c*d+e*(f+g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g+h))(i+j+k+l))'" 13 O=!((a+b)*(c*d+e*(f+g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h))(i+j+k))'" 12 O=!((a+b)*(c*d+(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h))(i+j+k+l))'" 13 O=!((a+b)*(c*d+(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h+i))(j+k+l))'" 13 O=!((a+b)*(c*d+(e+f)*(g+h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h+i))(j+k+l+m))'" 14 O=!((a+b)*(c*d+(e+f)*(g+h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f+g)(h+i+j))(k+l+m))'" 14 O=!((a+b)*(c*d+(e+f+g)*(h+i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f+g)(h+i+j))(k+l+m+n))'" 15 O=!((a+b)*(c*d+(e+f+g)*(h+i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+f(g+h))(i+j+k))'" 12 O=!((a+b)*(c*(d+e)+f*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+f(g+h))(i+j+k+l))'" 13 O=!((a+b)*(c*(d+e)+f*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+(f+g)(h+i))(j+k+l))'" 13 O=!((a+b)*(c*(d+e)+(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+(f+g)(h+i))(j+k+l+m))'" 14 O=!((a+b)*(c*(d+e)+(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+(g+h)(i+j))(k+l+m))'" 14 O=!((a+b)*((c+d)*(e+f)+(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+(g+h)(i+j))(k+l+m+n))'" 15 O=!((a+b)*((c+d)*(e+f)+(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h))'" 9 O=!((a+b)*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+hi))'" 10 O=!((a+b)*(c+d+e)*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h(i+j)))'" 11 O=!((a+b)*(c+d+e)*(f+g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+(h+i)(j+k)))'" 12 O=!((a+b)*(c+d+e)*(f+g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+gh+ij))'" 11 O=!((a+b)*(c+d+e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+gh+i(j+k)))'" 12 O=!((a+b)*(c+d+e)*(f+g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+gh+(i+j)(k+l)))'" 13 O=!((a+b)*(c+d+e)*(f+g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(fg+hi+jk))'" 12 O=!((a+b)*(c+d+e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(fg+hi+j(k+l)))'" 13 O=!((a+b)*(c+d+e)*(f*g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(fg+hi+(j+k)(l+m)))'" 14 O=!((a+b)*(c+d+e)*(f*g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h+i))'" 10 O=!((a+b)*(c+d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h+ij))'" 11 O=!((a+b)*(c+d+e)*(f+g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+hi+jk))'" 12 O=!((a+b)*(c+d+e)*(f+g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+gh+ij+kl))'" 13 O=!((a+b)*(c+d+e)*(f+g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(fg+hi+jk+lm))'" 14 O=!((a+b)*(c+d+e)*(f*g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef)(g+h+i+j))'" 11 O=!((a+b)*(c+d+e*f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e(f+g))(h+i+j+k))'" 12 O=!((a+b)*(c+d+e*(f+g))*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+(e+f)(g+h))(i+j+k+l))'" 13 O=!((a+b)*(c+d+(e+f)*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg)(h+i+j+k))'" 12 O=!((a+b)*(c+d*e+f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+f(g+h))(i+j+k+l))'" 13 O=!((a+b)*(c+d*e+f*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+(f+g)(h+i))(j+k+l+m))'" 14 O=!((a+b)*(c+d*e+(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh)(i+j+k+l))'" 13 O=!((a+b)*(c*d+e*f+g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+g(h+i))(j+k+l+m))'" 14 O=!((a+b)*(c*d+e*f+g*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+(g+h)(i+j))(k+l+m+n))'" 15 O=!((a+b)*(c*d+e*f+(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+h+i+j))'" 11 O=!((a+b)*(c+d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+h+i+jk))'" 12 O=!((a+b)*(c+d+e+f)*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+h+ij+kl))'" 13 O=!((a+b)*(c+d+e+f)*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+hi+jk+lm))'" 14 O=!((a+b)*(c+d+e+f)*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(gh+ij+kl+mn))'" 15 O=!((a+b)*(c+d+e+f)*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f)(g+h+i))'" 10 O=!((a+b*c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f)(g+h+i+j))'" 11 O=!((a+b*c)*(d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f+g)(h+i+j+k))'" 12 O=!((a+b*c)*(d+e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g)(h+i+j))'" 11 O=!((a+b*(c+d))*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g)(h+i+j+k))'" 12 O=!((a+b*(c+d))*(e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g+h)(i+j+k+l))'" 13 O=!((a+b*(c+d))*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g+h)(i+j+k))'" 12 O=!((a+b*(c+d+e))*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g+h)(i+j+k+l))'" 13 O=!((a+b*(c+d+e))*(f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d+e))(f+g+h+i)(j+k+l+m))'" 14 O=!((a+b*(c+d+e))*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h)(i+j+k))'" 12 O=!((a+(b+c)*(d+e))*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h)(i+j+k+l))'" 13 O=!((a+(b+c)*(d+e))*(f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h+i)(j+k+l+m))'" 14 O=!((a+(b+c)*(d+e))*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+h+i)(j+k+l))'" 13 O=!((a+(b+c)*(d+e+f))*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+h+i)(j+k+l+m))'" 14 O=!((a+(b+c)*(d+e+f))*(g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e+f))(g+h+i+j)(k+l+m+n))'" 15 O=!((a+(b+c)*(d+e+f))*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+i+j)(k+l+m))'" 14 O=!((a+(b+c+d)*(e+f+g))*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+i+j)(k+l+m+n))'" 15 O=!((a+(b+c+d)*(e+f+g))*(h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c+d)(e+f+g))(h+i+j+k)(l+m+n+o))'" 16 O=!((a+(b+c+d)*(e+f+g))*(h+i+j+k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g)(h+i+j))'" 11 O=!((a*b+c*d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g)(h+i+j+k))'" 12 O=!((a*b+c*d)*(e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g+h)(i+j+k+l))'" 13 O=!((a*b+c*d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h)(i+j+k))'" 12 O=!((a*b+c*(d+e))*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h)(i+j+k+l))'" 13 O=!((a*b+c*(d+e))*(f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h+i)(j+k+l+m))'" 14 O=!((a*b+c*(d+e))*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+h+i)(j+k+l))'" 13 O=!((a*b+c*(d+e+f))*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+h+i)(j+k+l+m))'" 14 O=!((a*b+c*(d+e+f))*(g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e+f))(g+h+i+j)(k+l+m+n))'" 15 O=!((a*b+c*(d+e+f))*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i)(j+k+l))'" 13 O=!((a*b+(c+d)*(e+f))*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i)(j+k+l+m))'" 14 O=!((a*b+(c+d)*(e+f))*(g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i+j)(k+l+m+n))'" 15 O=!((a*b+(c+d)*(e+f))*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+i+j)(k+l+m))'" 14 O=!((a*b+(c+d)*(e+f+g))*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+i+j)(k+l+m+n))'" 15 O=!((a*b+(c+d)*(e+f+g))*(h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f+g))(h+i+j+k)(l+m+n+o))'" 16 O=!((a*b+(c+d)*(e+f+g))*(h+i+j+k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+j+k)(l+m+n))'" 15 O=!((a*b+(c+d+e)*(f+g+h))*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+j+k)(l+m+n+o))'" 16 O=!((a*b+(c+d+e)*(f+g+h))*(i+j+k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d+e)(f+g+h))(i+j+k+l)(m+n+o+p))'" 17 O=!((a*b+(c+d+e)*(f+g+h))*(i+j+k+l)*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+h+i)(j+k+l))'" 13 O=!((a*(b+c)+d*(e+f))*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+h+i)(j+k+l+m))'" 14 O=!((a*(b+c)+d*(e+f))*(g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+d(e+f))(g+h+i+j)(k+l+m+n))'" 15 O=!((a*(b+c)+d*(e+f))*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+i+j)(k+l+m))'" 14 O=!((a*(b+c)+(d+e)*(f+g))*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+i+j)(k+l+m+n))'" 15 O=!((a*(b+c)+(d+e)*(f+g))*(h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+(d+e)(f+g))(h+i+j+k)(l+m+n+o))'" 16 O=!((a*(b+c)+(d+e)*(f+g))*(h+i+j+k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+j+k)(l+m+n))'" 15 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+j+k)(l+m+n+o))'" 16 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j+k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+(e+f)(g+h))(i+j+k+l)(m+n+o+p))'" 17 O=!(((a+b)*(c+d)+(e+f)*(g+h))*(i+j+k+l)*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i))'" 10 O=!((a+b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+ij))'" 11 O=!((a+b+c)*(d+e+f)*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i(j+k)))'" 12 O=!((a+b+c)*(d+e+f)*(g+h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+(i+j)(k+l)))'" 13 O=!((a+b+c)*(d+e+f)*(g+h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+hi+jk))'" 12 O=!((a+b+c)*(d+e+f)*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+hi+j(k+l)))'" 13 O=!((a+b+c)*(d+e+f)*(g+h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+hi+(j+k)(l+m)))'" 14 O=!((a+b+c)*(d+e+f)*(g+h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(gh+ij+kl))'" 13 O=!((a+b+c)*(d+e+f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(gh+ij+k(l+m)))'" 14 O=!((a+b+c)*(d+e+f)*(g*h+i*j+k*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(gh+ij+(k+l)(m+n)))'" 15 O=!((a+b+c)*(d+e+f)*(g*h+i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i+j))'" 11 O=!((a+b+c)*(d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i+jk))'" 12 O=!((a+b+c)*(d+e+f)*(g+h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+ij+kl))'" 13 O=!((a+b+c)*(d+e+f)*(g+h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+hi+jk+lm))'" 14 O=!((a+b+c)*(d+e+f)*(g+h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(gh+ij+kl+mn))'" 15 O=!((a+b+c)*(d+e+f)*(g*h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg)(h+i+j+k))'" 12 O=!((a+b+c)*(d+e+f*g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f(g+h))(i+j+k+l))'" 13 O=!((a+b+c)*(d+e+f*(g+h))*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+(f+g)(h+i))(j+k+l+m))'" 14 O=!((a+b+c)*(d+e+(f+g)*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh)(i+j+k+l))'" 13 O=!((a+b+c)*(d+e*f+g*h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+g(h+i))(j+k+l+m))'" 14 O=!((a+b+c)*(d+e*f+g*(h+i))*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+(g+h)(i+j))(k+l+m+n))'" 15 O=!((a+b+c)*(d+e*f+(g+h)*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi)(j+k+l+m))'" 14 O=!((a+b+c)*(d*e+f*g+h*i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+h(i+j))(k+l+m+n))'" 15 O=!((a+b+c)*(d*e+f*g+h*(i+j))*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+(h+i)(j+k))(l+m+n+o))'" 16 O=!((a+b+c)*(d*e+f*g+(h+i)*(j+k))*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+i+j+k))'" 12 O=!((a+b+c)*(d+e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+i+j+kl))'" 13 O=!((a+b+c)*(d+e+f+g)*(h+i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+i+jk+lm))'" 14 O=!((a+b+c)*(d+e+f+g)*(h+i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+ij+kl+mn))'" 15 O=!((a+b+c)*(d+e+f+g)*(h+i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(hi+jk+lm+no))'" 16 O=!((a+b+c)*(d+e+f+g)*(h*i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+g+h)(i+j+k+l))'" 13 O=!((a+b+c*d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c(d+e))(f+g+h+i)(j+k+l+m))'" 14 O=!((a+b+c*(d+e))*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+(c+d)(e+f))(g+h+i+j)(k+l+m+n))'" 15 O=!((a+b+(c+d)*(e+f))*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+g+h+i)(j+k+l+m))'" 14 O=!((a+b*c+d*e)*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+d(e+f))(g+h+i+j)(k+l+m+n))'" 15 O=!((a+b*c+d*(e+f))*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+(d+e)(f+g))(h+i+j+k)(l+m+n+o))'" 16 O=!((a+b*c+(d+e)*(f+g))*(h+i+j+k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(g+h+i+j)(k+l+m+n))'" 15 O=!((a*b+c*d+e*f)*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+e(f+g))(h+i+j+k)(l+m+n+o))'" 16 O=!((a*b+c*d+e*(f+g))*(h+i+j+k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+(e+f)(g+h))(i+j+k+l)(m+n+o+p))'" 17 O=!((a*b+c*d+(e+f)*(g+h))*(i+j+k+l)*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+j+k+l))'" 13 O=!((a+b+c+d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+j+k+lm))'" 14 O=!((a+b+c+d)*(e+f+g+h)*(i+j+k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+j+kl+mn))'" 15 O=!((a+b+c+d)*(e+f+g+h)*(i+j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+jk+lm+no))'" 16 O=!((a+b+c+d)*(e+f+g+h)*(i+j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(ij+kl+mn+op))'" 17 O=!((a+b+c+d)*(e+f+g+h)*(i*j+k*l+m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd)'" 5 O=!(a*b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e))'" 6 O=!(a*b*c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e+f))'" 7 O=!(a*b*c*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e+f+g))'" 8 O=!(a*b*c*(d+e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f))'" 7 O=!(a*b*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f+g))'" 8 O=!(a*b*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f+g+h))'" 9 O=!(a*b*(c+d)*(e+f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e)(f+g+h))'" 9 O=!(a*b*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e)(f+g+h+i))'" 10 O=!(a*b*(c+d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e+f)(g+h+i+j))'" 11 O=!(a*b*(c+d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g))'" 8 O=!(a*(b+c)*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g+h))'" 9 O=!(a*(b+c)*(d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g+h+i))'" 10 O=!(a*(b+c)*(d+e)*(f+g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f)(g+h+i))'" 10 O=!(a*(b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f)(g+h+i+j))'" 11 O=!(a*(b+c)*(d+e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f+g)(h+i+j+k))'" 12 O=!(a*(b+c)*(d+e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g)(h+i+j))'" 11 O=!(a*(b+c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g)(h+i+j+k))'" 12 O=!(a*(b+c+d)*(e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g+h)(i+j+k+l))'" 13 O=!(a*(b+c+d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d+e)(f+g+h+i)(j+k+l+m))'" 14 O=!(a*(b+c+d+e)*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h))'" 9 O=!((a+b)*(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h+i))'" 10 O=!((a+b)*(c+d)*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h+i+j))'" 11 O=!((a+b)*(c+d)*(e+f)*(g+h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g)(h+i+j))'" 11 O=!((a+b)*(c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g)(h+i+j+k))'" 12 O=!((a+b)*(c+d)*(e+f+g)*(h+i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g+h)(i+j+k+l))'" 13 O=!((a+b)*(c+d)*(e+f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h)(i+j+k))'" 12 O=!((a+b)*(c+d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h)(i+j+k+l))'" 13 O=!((a+b)*(c+d+e)*(f+g+h)*(i+j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h+i)(j+k+l+m))'" 14 O=!((a+b)*(c+d+e)*(f+g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e+f)(g+h+i+j)(k+l+m+n))'" 15 O=!((a+b)*(c+d+e+f)*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i)(j+k+l))'" 13 O=!((a+b+c)*(d+e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i)(j+k+l+m))'" 14 O=!((a+b+c)*(d+e+f)*(g+h+i)*(j+k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i+j)(k+l+m+n))'" 15 O=!((a+b+c)*(d+e+f)*(g+h+i+j)*(k+l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f+g)(h+i+j+k)(l+m+n+o))'" 16 O=!((a+b+c)*(d+e+f+g)*(h+i+j+k)*(l+m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c+d)(e+f+g+h)(i+j+k+l)(m+n+o+p))'" 17 O=!((a+b+c+d)*(e+f+g+h)*(i+j+k+l)*(m+n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b)'" 3 O=!(a+b); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc)'" 4 O=!(a+b*c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d))'" 5 O=!(a+b*(c+d)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+de))'" 6 O=!(a+b*(c+d*e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d(e+f)))'" 7 O=!(a+b*(c+d*(e+f))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d(e+fg)))'" 8 O=!(a+b*(c+d*(e+f*g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d(ef+gh)))'" 9 O=!(a+b*(c+d*(e*f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+(d+e)(f+g)))'" 8 O=!(a+b*(c+(d+e)*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+(d+e)(f+gh)))'" 9 O=!(a+b*(c+(d+e)*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+(d+e)(fg+hi)))'" 10 O=!(a+b*(c+(d+e)*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+def))'" 7 O=!(a+b*(c+d*e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+de(f+g)))'" 8 O=!(a+b*(c+d*e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d(e+f)(g+h)))'" 9 O=!(a+b*(c+d*(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+(d+e)(f+g)(h+i)))'" 10 O=!(a+b*(c+(d+e)*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+ef))'" 7 O=!(a+b*(c*d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+e(f+g)))'" 8 O=!(a+b*(c*d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+e(f+gh)))'" 9 O=!(a+b*(c*d+e*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+e(fg+hi)))'" 10 O=!(a+b*(c*d+e*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+(e+f)(g+h)))'" 9 O=!(a+b*(c*d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+(e+f)(g+hi)))'" 10 O=!(a+b*(c*d+(e+f)*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+(e+f)(gh+ij)))'" 11 O=!(a+b*(c*d+(e+f)*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+efg))'" 8 O=!(a+b*(c*d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+ef(g+h)))'" 9 O=!(a+b*(c*d+e*f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+e(f+g)(h+i)))'" 10 O=!(a+b*(c*d+e*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+(e+f)(g+h)(i+j)))'" 11 O=!(a+b*(c*d+(e+f)*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c(d+e)+fgh))'" 9 O=!(a+b*(c*(d+e)+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c(d+ef)+ghi))'" 10 O=!(a+b*(c*(d+e*f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c(de+fg)+hij))'" 11 O=!(a+b*(c*(d*e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b((c+d)(e+f)+ghi))'" 10 O=!(a+b*((c+d)*(e+f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b((c+d)(e+fg)+hij))'" 11 O=!(a+b*((c+d)*(e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b((c+d)(ef+gh)+ijk))'" 12 O=!(a+b*((c+d)*(e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cde+fgh))'" 9 O=!(a+b*(c*d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cde+fg(h+i)))'" 10 O=!(a+b*(c*d*e+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cde+f(g+h)(i+j)))'" 11 O=!(a+b*(c*d*e+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cde+(f+g)(h+i)(j+k)))'" 12 O=!(a+b*(c*d*e+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+e))'" 6 O=!(a+b*(c+d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+ef))'" 7 O=!(a+b*(c+d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+efg))'" 8 O=!(a+b*(c+d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+de+fg))'" 8 O=!(a+b*(c+d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+de+fgh))'" 9 O=!(a+b*(c+d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+def+ghi))'" 10 O=!(a+b*(c+d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+ef+gh))'" 9 O=!(a+b*(c*d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+ef+ghi))'" 10 O=!(a+b*(c*d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+efg+hij))'" 11 O=!(a+b*(c*d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cde+fgh+ijk))'" 12 O=!(a+b*(c*d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e))'" 6 O=!(a+(b+c)*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+ef))'" 7 O=!(a+(b+c)*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e(f+g)))'" 8 O=!(a+(b+c)*(d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e(f+gh)))'" 9 O=!(a+(b+c)*(d+e*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e(fg+hi)))'" 10 O=!(a+(b+c)*(d+e*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+(e+f)(g+h)))'" 9 O=!(a+(b+c)*(d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+(e+f)(g+hi)))'" 10 O=!(a+(b+c)*(d+(e+f)*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+(e+f)(gh+ij)))'" 11 O=!(a+(b+c)*(d+(e+f)*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+efg))'" 8 O=!(a+(b+c)*(d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+ef(g+h)))'" 9 O=!(a+(b+c)*(d+e*f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e(f+g)(h+i)))'" 10 O=!(a+(b+c)*(d+e*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+(e+f)(g+h)(i+j)))'" 11 O=!(a+(b+c)*(d+(e+f)*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fg))'" 8 O=!(a+(b+c)*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+f(g+h)))'" 9 O=!(a+(b+c)*(d*e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+f(g+hi)))'" 10 O=!(a+(b+c)*(d*e+f*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+f(gh+ij)))'" 11 O=!(a+(b+c)*(d*e+f*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+(f+g)(h+i)))'" 10 O=!(a+(b+c)*(d*e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+(f+g)(h+ij)))'" 11 O=!(a+(b+c)*(d*e+(f+g)*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+(f+g)(hi+jk)))'" 12 O=!(a+(b+c)*(d*e+(f+g)*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fgh))'" 9 O=!(a+(b+c)*(d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fg(h+i)))'" 10 O=!(a+(b+c)*(d*e+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+f(g+h)(i+j)))'" 11 O=!(a+(b+c)*(d*e+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+(f+g)(h+i)(j+k)))'" 12 O=!(a+(b+c)*(d*e+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d(e+f)+ghi))'" 10 O=!(a+(b+c)*(d*(e+f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d(e+fg)+hij))'" 11 O=!(a+(b+c)*(d*(e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d(ef+gh)+ijk))'" 12 O=!(a+(b+c)*(d*(e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)((d+e)(f+g)+hij))'" 11 O=!(a+(b+c)*((d+e)*(f+g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)((d+e)(f+gh)+ijk))'" 12 O=!(a+(b+c)*((d+e)*(f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)((d+e)(fg+hi)+jkl))'" 13 O=!(a+(b+c)*((d+e)*(f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(def+ghi))'" 10 O=!(a+(b+c)*(d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(def+gh(i+j)))'" 11 O=!(a+(b+c)*(d*e*f+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(def+g(h+i)(j+k)))'" 12 O=!(a+(b+c)*(d*e*f+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(def+(g+h)(i+j)(k+l)))'" 13 O=!(a+(b+c)*(d*e*f+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+f))'" 7 O=!(a+(b+c)*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+fg))'" 8 O=!(a+(b+c)*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+fgh))'" 9 O=!(a+(b+c)*(d+e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+ef+gh))'" 9 O=!(a+(b+c)*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+ef+ghi))'" 10 O=!(a+(b+c)*(d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+efg+hij))'" 11 O=!(a+(b+c)*(d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fg+hi))'" 10 O=!(a+(b+c)*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fg+hij))'" 11 O=!(a+(b+c)*(d*e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fgh+ijk))'" 12 O=!(a+(b+c)*(d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(def+ghi+jkl))'" 13 O=!(a+(b+c)*(d*e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(e+fg))'" 8 O=!(a+(b+c*d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(e+f(g+h)))'" 9 O=!(a+(b+c*d)*(e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(e+(f+g)(h+i)))'" 10 O=!(a+(b+c*d)*(e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(ef+gh))'" 9 O=!(a+(b+c*d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(ef+g(h+i)))'" 10 O=!(a+(b+c*d)*(e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(ef+(g+h)(i+j)))'" 11 O=!(a+(b+c*d)*(e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(e+f+g))'" 8 O=!(a+(b+c*d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(e+f+gh))'" 9 O=!(a+(b+c*d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(e+fg+hi))'" 10 O=!(a+(b+c*d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(ef+gh+ij))'" 11 O=!(a+(b+c*d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e))(f+g(h+i)))'" 10 O=!(a+(b+c*(d+e))*(f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e))(f+(g+h)(i+j)))'" 11 O=!(a+(b+c*(d+e))*(f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e))(fg+hi))'" 10 O=!(a+(b+c*(d+e))*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e))(fg+h(i+j)))'" 11 O=!(a+(b+c*(d+e))*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e))(fg+(h+i)(j+k)))'" 12 O=!(a+(b+c*(d+e))*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e))(f+g+h))'" 9 O=!(a+(b+c*(d+e))*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e))(f+g+hi))'" 10 O=!(a+(b+c*(d+e))*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e))(f+gh+ij))'" 11 O=!(a+(b+c*(d+e))*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e))(fg+hi+jk))'" 12 O=!(a+(b+c*(d+e))*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+ef))(g+h+i))'" 10 O=!(a+(b+c*(d+e*f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(de+fg))(h+i+j))'" 11 O=!(a+(b+c*(d*e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+f))(g+(h+i)(j+k)))'" 12 O=!(a+(b+(c+d)*(e+f))*(g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+f))(gh+ij))'" 11 O=!(a+(b+(c+d)*(e+f))*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+f))(gh+i(j+k)))'" 12 O=!(a+(b+(c+d)*(e+f))*(g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+f))(gh+(i+j)(k+l)))'" 13 O=!(a+(b+(c+d)*(e+f))*(g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+f))(g+h+i))'" 10 O=!(a+(b+(c+d)*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+f))(g+h+ij))'" 11 O=!(a+(b+(c+d)*(e+f))*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+f))(g+hi+jk))'" 12 O=!(a+(b+(c+d)*(e+f))*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+f))(gh+ij+kl))'" 13 O=!(a+(b+(c+d)*(e+f))*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+fg))(h+i+j))'" 11 O=!(a+(b+(c+d)*(e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(ef+gh))(i+j+k))'" 12 O=!(a+(b+(c+d)*(e*f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cde)(f+g+h))'" 9 O=!(a+(b+c*d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd(e+f))(g+h+i))'" 10 O=!(a+(b+c*d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e)(f+g))(h+i+j))'" 11 O=!(a+(b+c*(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+f)(g+h))(i+j+k))'" 12 O=!(a+(b+(c+d)*(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(fg+hi))'" 10 O=!(a+(b*c+d*e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(fg+h(i+j)))'" 11 O=!(a+(b*c+d*e)*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(fg+(h+i)(j+k)))'" 12 O=!(a+(b*c+d*e)*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(f+g+h))'" 9 O=!(a+(b*c+d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(f+g+hi))'" 10 O=!(a+(b*c+d*e)*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(f+gh+ij))'" 11 O=!(a+(b*c+d*e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(fg+hi+jk))'" 12 O=!(a+(b*c+d*e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+d(e+f))(gh+i(j+k)))'" 12 O=!(a+(b*c+d*(e+f))*(g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+d(e+f))(gh+(i+j)(k+l)))'" 13 O=!(a+(b*c+d*(e+f))*(g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+d(e+f))(g+h+i))'" 10 O=!(a+(b*c+d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+d(e+f))(g+h+ij))'" 11 O=!(a+(b*c+d*(e+f))*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+d(e+f))(g+hi+jk))'" 12 O=!(a+(b*c+d*(e+f))*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+d(e+f))(gh+ij+kl))'" 13 O=!(a+(b*c+d*(e+f))*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+d(e+fg))(h+i+j))'" 11 O=!(a+(b*c+d*(e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+d(ef+gh))(i+j+k))'" 12 O=!(a+(b*c+d*(e*f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+(d+e)(f+g))(hi+(j+k)(l+m)))'" 14 O=!(a+(b*c+(d+e)*(f+g))*(h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+(d+e)(f+g))(h+i+j))'" 11 O=!(a+(b*c+(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+(d+e)(f+g))(h+i+jk))'" 12 O=!(a+(b*c+(d+e)*(f+g))*(h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+(d+e)(f+g))(h+ij+kl))'" 13 O=!(a+(b*c+(d+e)*(f+g))*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+(d+e)(f+g))(hi+jk+lm))'" 14 O=!(a+(b*c+(d+e)*(f+g))*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+(d+e)(f+gh))(i+j+k))'" 12 O=!(a+(b*c+(d+e)*(f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+(d+e)(fg+hi))(j+k+l))'" 13 O=!(a+(b*c+(d+e)*(f*g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+def)(g+h+i))'" 10 O=!(a+(b*c+d*e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de(f+g))(h+i+j))'" 11 O=!(a+(b*c+d*e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+d(e+f)(g+h))(i+j+k))'" 12 O=!(a+(b*c+d*(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+(d+e)(f+g)(h+i))(j+k+l))'" 13 O=!(a+(b*c+(d+e)*(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b(c+d)+efg)(h+i+j))'" 11 O=!(a+(b*(c+d)+e*f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b(c+de)+fgh)(i+j+k))'" 12 O=!(a+(b*(c+d*e)+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b(cd+ef)+ghi)(j+k+l))'" 13 O=!(a+(b*(c*d+e*f)+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+((b+c)(d+e)+fgh)(i+j+k))'" 12 O=!(a+((b+c)*(d+e)+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+((b+c)(d+ef)+ghi)(j+k+l))'" 13 O=!(a+((b+c)*(d+e*f)+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+((b+c)(de+fg)+hij)(k+l+m))'" 14 O=!(a+((b+c)*(d*e+f*g)+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bcd+efg)(h+i+j))'" 11 O=!(a+(b*c*d+e*f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bcd+ef(g+h))(i+j+k))'" 12 O=!(a+(b*c*d+e*f*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bcd+e(f+g)(h+i))(j+k+l))'" 13 O=!(a+(b*c*d+e*(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bcd+(e+f)(g+h)(i+j))(k+l+m))'" 14 O=!(a+(b*c*d+(e+f)*(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+g))'" 8 O=!(a+(b+c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+gh))'" 9 O=!(a+(b+c+d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+ghi))'" 10 O=!(a+(b+c+d)*(e+f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+fg+hi))'" 10 O=!(a+(b+c+d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+fg+hij))'" 11 O=!(a+(b+c+d)*(e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+fgh+ijk))'" 12 O=!(a+(b+c+d)*(e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(ef+gh+ij))'" 11 O=!(a+(b+c+d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(ef+gh+ijk))'" 12 O=!(a+(b+c+d)*(e*f+g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(ef+ghi+jkl))'" 13 O=!(a+(b+c+d)*(e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(efg+hij+klm))'" 14 O=!(a+(b+c+d)*(e*f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+de)(f+g+hi))'" 10 O=!(a+(b+c+d*e)*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+de)(f+gh+ij))'" 11 O=!(a+(b+c+d*e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+de)(fg+hi+jk))'" 12 O=!(a+(b+c+d*e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd+ef)(g+hi+jk))'" 12 O=!(a+(b+c*d+e*f)*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd+ef)(gh+ij+kl))'" 13 O=!(a+(b+c*d+e*f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de+fg)(hi+jk+lm))'" 14 O=!(a+(b*c+d*e+f*g)*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd)'" 5 O=!(a+b*c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e))'" 6 O=!(a+b*c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+ef))'" 7 O=!(a+b*c*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e(f+g)))'" 8 O=!(a+b*c*(d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+(e+f)(g+h)))'" 9 O=!(a+b*c*(d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(de+fg))'" 8 O=!(a+b*c*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(de+f(g+h)))'" 9 O=!(a+b*c*(d*e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(de+(f+g)(h+i)))'" 10 O=!(a+b*c*(d*e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e+f))'" 7 O=!(a+b*c*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e+fg))'" 8 O=!(a+b*c*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+ef+gh))'" 9 O=!(a+b*c*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(de+fg+hi))'" 10 O=!(a+b*c*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f))'" 7 O=!(a+b*(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+fg))'" 8 O=!(a+b*(c+d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f(g+h)))'" 9 O=!(a+b*(c+d)*(e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+(f+g)(h+i)))'" 10 O=!(a+b*(c+d)*(e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(ef+gh))'" 9 O=!(a+b*(c+d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(ef+g(h+i)))'" 10 O=!(a+b*(c+d)*(e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(ef+(g+h)(i+j)))'" 11 O=!(a+b*(c+d)*(e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f+g))'" 8 O=!(a+b*(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f+gh))'" 9 O=!(a+b*(c+d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+fg+hi))'" 10 O=!(a+b*(c+d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(ef+gh+ij))'" 11 O=!(a+b*(c+d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+de)(f+g+h))'" 9 O=!(a+b*(c+d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d(e+f))(g+h+i))'" 10 O=!(a+b*(c+d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+(d+e)(f+g))(h+i+j))'" 11 O=!(a+b*(c+(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+ef)(g+h+i))'" 10 O=!(a+b*(c*d+e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+e(f+g))(h+i+j))'" 11 O=!(a+b*(c*d+e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+(e+f)(g+h))(i+j+k))'" 12 O=!(a+b*(c*d+(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+e)(f+g+h))'" 9 O=!(a+b*(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+e)(f+g+hi))'" 10 O=!(a+b*(c+d+e)*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+e)(f+gh+ij))'" 11 O=!(a+b*(c+d+e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+e)(fg+hi+jk))'" 12 O=!(a+b*(c+d+e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g))'" 8 O=!(a+(b+c)*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+gh))'" 9 O=!(a+(b+c)*(d+e)*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g(h+i)))'" 10 O=!(a+(b+c)*(d+e)*(f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+(g+h)(i+j)))'" 11 O=!(a+(b+c)*(d+e)*(f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(fg+hi))'" 10 O=!(a+(b+c)*(d+e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(fg+h(i+j)))'" 11 O=!(a+(b+c)*(d+e)*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(fg+(h+i)(j+k)))'" 12 O=!(a+(b+c)*(d+e)*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g+h))'" 9 O=!(a+(b+c)*(d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g+hi))'" 10 O=!(a+(b+c)*(d+e)*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+gh+ij))'" 11 O=!(a+(b+c)*(d+e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(fg+hi+jk))'" 12 O=!(a+(b+c)*(d+e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+ef)(g+h+i))'" 10 O=!(a+(b+c)*(d+e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e(f+g))(h+i+j))'" 11 O=!(a+(b+c)*(d+e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+(e+f)(g+h))(i+j+k))'" 12 O=!(a+(b+c)*(d+(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fg)(h+i+j))'" 11 O=!(a+(b+c)*(d*e+f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+f(g+h))(i+j+k))'" 12 O=!(a+(b+c)*(d*e+f*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+(f+g)(h+i))(j+k+l))'" 13 O=!(a+(b+c)*(d*e+(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+f)(g+h+i))'" 10 O=!(a+(b+c)*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+f)(g+h+ij))'" 11 O=!(a+(b+c)*(d+e+f)*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+f)(g+hi+jk))'" 12 O=!(a+(b+c)*(d+e+f)*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+f)(gh+ij+kl))'" 13 O=!(a+(b+c)*(d+e+f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(e+f+g)(h+i+j))'" 11 O=!(a+(b+c*d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c(d+e))(f+g+h)(i+j+k))'" 12 O=!(a+(b+c*(d+e))*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+(c+d)(e+f))(g+h+i)(j+k+l))'" 13 O=!(a+(b+(c+d)*(e+f))*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(f+g+h)(i+j+k))'" 12 O=!(a+(b*c+d*e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+d(e+f))(g+h+i)(j+k+l))'" 13 O=!(a+(b*c+d*(e+f))*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+(d+e)(f+g))(h+i+j)(k+l+m))'" 14 O=!(a+(b*c+(d+e)*(f+g))*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+g)(h+i+j))'" 11 O=!(a+(b+c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+g)(h+i+jk))'" 12 O=!(a+(b+c+d)*(e+f+g)*(h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+g)(h+ij+kl))'" 13 O=!(a+(b+c+d)*(e+f+g)*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+g)(hi+jk+lm))'" 14 O=!(a+(b+c+d)*(e+f+g)*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde)'" 6 O=!(a+b*c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd(e+f))'" 7 O=!(a+b*c*d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd(e+f+g))'" 8 O=!(a+b*c*d*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e)(f+g))'" 8 O=!(a+b*c*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e)(f+g+h))'" 9 O=!(a+b*c*(d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e+f)(g+h+i))'" 10 O=!(a+b*c*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f)(g+h))'" 9 O=!(a+b*(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f)(g+h+i))'" 10 O=!(a+b*(c+d)*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f+g)(h+i+j))'" 11 O=!(a+b*(c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d+e)(f+g+h)(i+j+k))'" 12 O=!(a+b*(c+d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g)(h+i))'" 10 O=!(a+(b+c)*(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g)(h+i+j))'" 11 O=!(a+(b+c)*(d+e)*(f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g+h)(i+j+k))'" 12 O=!(a+(b+c)*(d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e+f)(g+h+i)(j+k+l))'" 13 O=!(a+(b+c)*(d+e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c+d)(e+f+g)(h+i+j)(k+l+m))'" 14 O=!(a+(b+c+d)*(e+f+g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd)'" 5 O=!(a*b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e))'" 6 O=!(a*b+c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+ef))'" 7 O=!(a*b+c*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e(f+g)))'" 8 O=!(a*b+c*(d+e*(f+g))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e(f+gh)))'" 9 O=!(a*b+c*(d+e*(f+g*h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e(fg+hi)))'" 10 O=!(a*b+c*(d+e*(f*g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+(e+f)(g+h)))'" 9 O=!(a*b+c*(d+(e+f)*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+(e+f)(g+hi)))'" 10 O=!(a*b+c*(d+(e+f)*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+(e+f)(gh+ij)))'" 11 O=!(a*b+c*(d+(e+f)*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+efg))'" 8 O=!(a*b+c*(d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+ef(g+h)))'" 9 O=!(a*b+c*(d+e*f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e(f+g)(h+i)))'" 10 O=!(a*b+c*(d+e*(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+(e+f)(g+h)(i+j)))'" 11 O=!(a*b+c*(d+(e+f)*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fg))'" 8 O=!(a*b+c*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+f(g+h)))'" 9 O=!(a*b+c*(d*e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+f(g+hi)))'" 10 O=!(a*b+c*(d*e+f*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+f(gh+ij)))'" 11 O=!(a*b+c*(d*e+f*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+(f+g)(h+i)))'" 10 O=!(a*b+c*(d*e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+(f+g)(h+ij)))'" 11 O=!(a*b+c*(d*e+(f+g)*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+(f+g)(hi+jk)))'" 12 O=!(a*b+c*(d*e+(f+g)*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fgh))'" 9 O=!(a*b+c*(d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fg(h+i)))'" 10 O=!(a*b+c*(d*e+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+f(g+h)(i+j)))'" 11 O=!(a*b+c*(d*e+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+(f+g)(h+i)(j+k)))'" 12 O=!(a*b+c*(d*e+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d(e+f)+ghi))'" 10 O=!(a*b+c*(d*(e+f)+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d(e+fg)+hij))'" 11 O=!(a*b+c*(d*(e+f*g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d(ef+gh)+ijk))'" 12 O=!(a*b+c*(d*(e*f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c((d+e)(f+g)+hij))'" 11 O=!(a*b+c*((d+e)*(f+g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c((d+e)(f+gh)+ijk))'" 12 O=!(a*b+c*((d+e)*(f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c((d+e)(fg+hi)+jkl))'" 13 O=!(a*b+c*((d+e)*(f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(def+ghi))'" 10 O=!(a*b+c*(d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(def+gh(i+j)))'" 11 O=!(a*b+c*(d*e*f+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(def+g(h+i)(j+k)))'" 12 O=!(a*b+c*(d*e*f+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(def+(g+h)(i+j)(k+l)))'" 13 O=!(a*b+c*(d*e*f+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+f))'" 7 O=!(a*b+c*(d+e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+fg))'" 8 O=!(a*b+c*(d+e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+fgh))'" 9 O=!(a*b+c*(d+e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+ef+gh))'" 9 O=!(a*b+c*(d+e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+ef+ghi))'" 10 O=!(a*b+c*(d+e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+efg+hij))'" 11 O=!(a*b+c*(d+e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fg+hi))'" 10 O=!(a*b+c*(d*e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fg+hij))'" 11 O=!(a*b+c*(d*e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fgh+ijk))'" 12 O=!(a*b+c*(d*e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(def+ghi+jkl))'" 13 O=!(a*b+c*(d*e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f))'" 7 O=!(a*b+(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fg))'" 8 O=!(a*b+(c+d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f(g+h)))'" 9 O=!(a*b+(c+d)*(e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f(g+hi)))'" 10 O=!(a*b+(c+d)*(e+f*(g+h*i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f(gh+ij)))'" 11 O=!(a*b+(c+d)*(e+f*(g*h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+(f+g)(h+i)))'" 10 O=!(a*b+(c+d)*(e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+(f+g)(h+ij)))'" 11 O=!(a*b+(c+d)*(e+(f+g)*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+(f+g)(hi+jk)))'" 12 O=!(a*b+(c+d)*(e+(f+g)*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fgh))'" 9 O=!(a*b+(c+d)*(e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fg(h+i)))'" 10 O=!(a*b+(c+d)*(e+f*g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f(g+h)(i+j)))'" 11 O=!(a*b+(c+d)*(e+f*(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+(f+g)(h+i)(j+k)))'" 12 O=!(a*b+(c+d)*(e+(f+g)*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+gh))'" 9 O=!(a*b+(c+d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+g(h+i)))'" 10 O=!(a*b+(c+d)*(e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+g(h+ij)))'" 11 O=!(a*b+(c+d)*(e*f+g*(h+i*j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+g(hi+jk)))'" 12 O=!(a*b+(c+d)*(e*f+g*(h*i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+(g+h)(i+j)))'" 11 O=!(a*b+(c+d)*(e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+(g+h)(i+jk)))'" 12 O=!(a*b+(c+d)*(e*f+(g+h)*(i+j*k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+(g+h)(ij+kl)))'" 13 O=!(a*b+(c+d)*(e*f+(g+h)*(i*j+k*l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+ghi))'" 10 O=!(a*b+(c+d)*(e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+gh(i+j)))'" 11 O=!(a*b+(c+d)*(e*f+g*h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+g(h+i)(j+k)))'" 12 O=!(a*b+(c+d)*(e*f+g*(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+(g+h)(i+j)(k+l)))'" 13 O=!(a*b+(c+d)*(e*f+(g+h)*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e(f+g)+hij))'" 11 O=!(a*b+(c+d)*(e*(f+g)+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e(f+gh)+ijk))'" 12 O=!(a*b+(c+d)*(e*(f+g*h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e(fg+hi)+jkl))'" 13 O=!(a*b+(c+d)*(e*(f*g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)((e+f)(g+h)+ijk))'" 12 O=!(a*b+(c+d)*((e+f)*(g+h)+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)((e+f)(g+hi)+jkl))'" 13 O=!(a*b+(c+d)*((e+f)*(g+h*i)+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)((e+f)(gh+ij)+klm))'" 14 O=!(a*b+(c+d)*((e+f)*(g*h+i*j)+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(efg+hij))'" 11 O=!(a*b+(c+d)*(e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(efg+hi(j+k)))'" 12 O=!(a*b+(c+d)*(e*f*g+h*i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(efg+h(i+j)(k+l)))'" 13 O=!(a*b+(c+d)*(e*f*g+h*(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(efg+(h+i)(j+k)(l+m)))'" 14 O=!(a*b+(c+d)*(e*f*g+(h+i)*(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+g))'" 8 O=!(a*b+(c+d)*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+gh))'" 9 O=!(a*b+(c+d)*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+ghi))'" 10 O=!(a*b+(c+d)*(e+f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fg+hi))'" 10 O=!(a*b+(c+d)*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fg+hij))'" 11 O=!(a*b+(c+d)*(e+f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fgh+ijk))'" 12 O=!(a*b+(c+d)*(e+f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+gh+ij))'" 11 O=!(a*b+(c+d)*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+gh+ijk))'" 12 O=!(a*b+(c+d)*(e*f+g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+ghi+jkl))'" 13 O=!(a*b+(c+d)*(e*f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(efg+hij+klm))'" 14 O=!(a*b+(c+d)*(e*f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(f+gh))'" 9 O=!(a*b+(c+d*e)*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(f+g(h+i)))'" 10 O=!(a*b+(c+d*e)*(f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(f+(g+h)(i+j)))'" 11 O=!(a*b+(c+d*e)*(f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(fg+hi))'" 10 O=!(a*b+(c+d*e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(fg+h(i+j)))'" 11 O=!(a*b+(c+d*e)*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(fg+(h+i)(j+k)))'" 12 O=!(a*b+(c+d*e)*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(f+g+h))'" 9 O=!(a*b+(c+d*e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(f+g+hi))'" 10 O=!(a*b+(c+d*e)*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(f+gh+ij))'" 11 O=!(a*b+(c+d*e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(fg+hi+jk))'" 12 O=!(a*b+(c+d*e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f))(g+h(i+j)))'" 11 O=!(a*b+(c+d*(e+f))*(g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f))(g+(h+i)(j+k)))'" 12 O=!(a*b+(c+d*(e+f))*(g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f))(gh+ij))'" 11 O=!(a*b+(c+d*(e+f))*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f))(gh+i(j+k)))'" 12 O=!(a*b+(c+d*(e+f))*(g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f))(gh+(i+j)(k+l)))'" 13 O=!(a*b+(c+d*(e+f))*(g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f))(g+h+i))'" 10 O=!(a*b+(c+d*(e+f))*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f))(g+h+ij))'" 11 O=!(a*b+(c+d*(e+f))*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f))(g+hi+jk))'" 12 O=!(a*b+(c+d*(e+f))*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f))(gh+ij+kl))'" 13 O=!(a*b+(c+d*(e+f))*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+fg))(h+i+j))'" 11 O=!(a*b+(c+d*(e+f*g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(ef+gh))(i+j+k))'" 12 O=!(a*b+(c+d*(e*f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+g))(h+(i+j)(k+l)))'" 13 O=!(a*b+(c+(d+e)*(f+g))*(h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+g))(hi+jk))'" 12 O=!(a*b+(c+(d+e)*(f+g))*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+g))(hi+j(k+l)))'" 13 O=!(a*b+(c+(d+e)*(f+g))*(h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+g))(hi+(j+k)(l+m)))'" 14 O=!(a*b+(c+(d+e)*(f+g))*(h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+g))(h+i+j))'" 11 O=!(a*b+(c+(d+e)*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+g))(h+i+jk))'" 12 O=!(a*b+(c+(d+e)*(f+g))*(h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+g))(h+ij+kl))'" 13 O=!(a*b+(c+(d+e)*(f+g))*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+g))(hi+jk+lm))'" 14 O=!(a*b+(c+(d+e)*(f+g))*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+gh))(i+j+k))'" 12 O=!(a*b+(c+(d+e)*(f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(fg+hi))(j+k+l))'" 13 O=!(a*b+(c+(d+e)*(f*g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+def)(g+h+i))'" 10 O=!(a*b+(c+d*e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de(f+g))(h+i+j))'" 11 O=!(a*b+(c+d*e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f)(g+h))(i+j+k))'" 12 O=!(a*b+(c+d*(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+g)(h+i))(j+k+l))'" 13 O=!(a*b+(c+(d+e)*(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(gh+ij))'" 11 O=!(a*b+(c*d+e*f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(gh+i(j+k)))'" 12 O=!(a*b+(c*d+e*f)*(g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(gh+(i+j)(k+l)))'" 13 O=!(a*b+(c*d+e*f)*(g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(g+h+i))'" 10 O=!(a*b+(c*d+e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(g+h+ij))'" 11 O=!(a*b+(c*d+e*f)*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(g+hi+jk))'" 12 O=!(a*b+(c*d+e*f)*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(gh+ij+kl))'" 13 O=!(a*b+(c*d+e*f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+e(f+g))(hi+j(k+l)))'" 13 O=!(a*b+(c*d+e*(f+g))*(h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+e(f+g))(hi+(j+k)(l+m)))'" 14 O=!(a*b+(c*d+e*(f+g))*(h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+e(f+g))(h+i+j))'" 11 O=!(a*b+(c*d+e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+e(f+g))(h+i+jk))'" 12 O=!(a*b+(c*d+e*(f+g))*(h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+e(f+g))(h+ij+kl))'" 13 O=!(a*b+(c*d+e*(f+g))*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+e(f+g))(hi+jk+lm))'" 14 O=!(a*b+(c*d+e*(f+g))*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+e(f+gh))(i+j+k))'" 12 O=!(a*b+(c*d+e*(f+g*h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+e(fg+hi))(j+k+l))'" 13 O=!(a*b+(c*d+e*(f*g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+(e+f)(g+h))(ij+(k+l)(m+n)))'" 15 O=!(a*b+(c*d+(e+f)*(g+h))*(i*j+(k+l)*(m+n))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+(e+f)(g+h))(i+j+k))'" 12 O=!(a*b+(c*d+(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+(e+f)(g+h))(i+j+kl))'" 13 O=!(a*b+(c*d+(e+f)*(g+h))*(i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+(e+f)(g+h))(i+jk+lm))'" 14 O=!(a*b+(c*d+(e+f)*(g+h))*(i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+(e+f)(g+h))(ij+kl+mn))'" 15 O=!(a*b+(c*d+(e+f)*(g+h))*(i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+(e+f)(g+hi))(j+k+l))'" 13 O=!(a*b+(c*d+(e+f)*(g+h*i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+(e+f)(gh+ij))(k+l+m))'" 14 O=!(a*b+(c*d+(e+f)*(g*h+i*j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+efg)(h+i+j))'" 11 O=!(a*b+(c*d+e*f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef(g+h))(i+j+k))'" 12 O=!(a*b+(c*d+e*f*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+e(f+g)(h+i))(j+k+l))'" 13 O=!(a*b+(c*d+e*(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+(e+f)(g+h)(i+j))(k+l+m))'" 14 O=!(a*b+(c*d+(e+f)*(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c(d+e)+fgh)(i+j+k))'" 12 O=!(a*b+(c*(d+e)+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c(d+ef)+ghi)(j+k+l))'" 13 O=!(a*b+(c*(d+e*f)+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c(de+fg)+hij)(k+l+m))'" 14 O=!(a*b+(c*(d*e+f*g)+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+((c+d)(e+f)+ghi)(j+k+l))'" 13 O=!(a*b+((c+d)*(e+f)+g*h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+((c+d)(e+fg)+hij)(k+l+m))'" 14 O=!(a*b+((c+d)*(e+f*g)+h*i*j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+((c+d)(ef+gh)+ijk)(l+m+n))'" 15 O=!(a*b+((c+d)*(e*f+g*h)+i*j*k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cde+fgh)(i+j+k))'" 12 O=!(a*b+(c*d*e+f*g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cde+fg(h+i))(j+k+l))'" 13 O=!(a*b+(c*d*e+f*g*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cde+f(g+h)(i+j))(k+l+m))'" 14 O=!(a*b+(c*d*e+f*(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cde+(f+g)(h+i)(j+k))(l+m+n))'" 15 O=!(a*b+(c*d*e+(f+g)*(h+i)*(j+k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+h))'" 9 O=!(a*b+(c+d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+hi))'" 10 O=!(a*b+(c+d+e)*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+hij))'" 11 O=!(a*b+(c+d+e)*(f+g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+gh+ij))'" 11 O=!(a*b+(c+d+e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+gh+ijk))'" 12 O=!(a*b+(c+d+e)*(f+g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+ghi+jkl))'" 13 O=!(a*b+(c+d+e)*(f+g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(fg+hi+jk))'" 12 O=!(a*b+(c+d+e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(fg+hi+jkl))'" 13 O=!(a*b+(c+d+e)*(f*g+h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(fg+hij+klm))'" 14 O=!(a*b+(c+d+e)*(f*g+h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(fgh+ijk+lmn))'" 15 O=!(a*b+(c+d+e)*(f*g*h+i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+ef)(g+h+ij))'" 11 O=!(a*b+(c+d+e*f)*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+ef)(g+hi+jk))'" 12 O=!(a*b+(c+d+e*f)*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+ef)(gh+ij+kl))'" 13 O=!(a*b+(c+d+e*f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de+fg)(h+ij+kl))'" 13 O=!(a*b+(c+d*e+f*g)*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de+fg)(hi+jk+lm))'" 14 O=!(a*b+(c+d*e+f*g)*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef+gh)(ij+kl+mn))'" 15 O=!(a*b+(c*d+e*f+g*h)*(i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde)'" 6 O=!(a*b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f))'" 7 O=!(a*b+c*d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+fg))'" 8 O=!(a*b+c*d*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f(g+h)))'" 9 O=!(a*b+c*d*(e+f*(g+h))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+(f+g)(h+i)))'" 10 O=!(a*b+c*d*(e+(f+g)*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(ef+gh))'" 9 O=!(a*b+c*d*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(ef+g(h+i)))'" 10 O=!(a*b+c*d*(e*f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(ef+(g+h)(i+j)))'" 11 O=!(a*b+c*d*(e*f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f+g))'" 8 O=!(a*b+c*d*(e+f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f+gh))'" 9 O=!(a*b+c*d*(e+f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+fg+hi))'" 10 O=!(a*b+c*d*(e+f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(ef+gh+ij))'" 11 O=!(a*b+c*d*(e*f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g))'" 8 O=!(a*b+c*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+gh))'" 9 O=!(a*b+c*(d+e)*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g(h+i)))'" 10 O=!(a*b+c*(d+e)*(f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+(g+h)(i+j)))'" 11 O=!(a*b+c*(d+e)*(f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(fg+hi))'" 10 O=!(a*b+c*(d+e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(fg+h(i+j)))'" 11 O=!(a*b+c*(d+e)*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(fg+(h+i)(j+k)))'" 12 O=!(a*b+c*(d+e)*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g+h))'" 9 O=!(a*b+c*(d+e)*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g+hi))'" 10 O=!(a*b+c*(d+e)*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+gh+ij))'" 11 O=!(a*b+c*(d+e)*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(fg+hi+jk))'" 12 O=!(a*b+c*(d+e)*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+ef)(g+h+i))'" 10 O=!(a*b+c*(d+e*f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e(f+g))(h+i+j))'" 11 O=!(a*b+c*(d+e*(f+g))*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+(e+f)(g+h))(i+j+k))'" 12 O=!(a*b+c*(d+(e+f)*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fg)(h+i+j))'" 11 O=!(a*b+c*(d*e+f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+f(g+h))(i+j+k))'" 12 O=!(a*b+c*(d*e+f*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+(f+g)(h+i))(j+k+l))'" 13 O=!(a*b+c*(d*e+(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+f)(g+h+i))'" 10 O=!(a*b+c*(d+e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+f)(g+h+ij))'" 11 O=!(a*b+c*(d+e+f)*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+f)(g+hi+jk))'" 12 O=!(a*b+c*(d+e+f)*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+f)(gh+ij+kl))'" 13 O=!(a*b+c*(d+e+f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h))'" 9 O=!(a*b+(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+hi))'" 10 O=!(a*b+(c+d)*(e+f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h(i+j)))'" 11 O=!(a*b+(c+d)*(e+f)*(g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+(h+i)(j+k)))'" 12 O=!(a*b+(c+d)*(e+f)*(g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(gh+ij))'" 11 O=!(a*b+(c+d)*(e+f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(gh+i(j+k)))'" 12 O=!(a*b+(c+d)*(e+f)*(g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(gh+(i+j)(k+l)))'" 13 O=!(a*b+(c+d)*(e+f)*(g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h+i))'" 10 O=!(a*b+(c+d)*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h+ij))'" 11 O=!(a*b+(c+d)*(e+f)*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+hi+jk))'" 12 O=!(a*b+(c+d)*(e+f)*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(gh+ij+kl))'" 13 O=!(a*b+(c+d)*(e+f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fg)(h+i+j))'" 11 O=!(a*b+(c+d)*(e+f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f(g+h))(i+j+k))'" 12 O=!(a*b+(c+d)*(e+f*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+(f+g)(h+i))(j+k+l))'" 13 O=!(a*b+(c+d)*(e+(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+gh)(i+j+k))'" 12 O=!(a*b+(c+d)*(e*f+g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+g(h+i))(j+k+l))'" 13 O=!(a*b+(c+d)*(e*f+g*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+(g+h)(i+j))(k+l+m))'" 14 O=!(a*b+(c+d)*(e*f+(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+g)(h+i+j))'" 11 O=!(a*b+(c+d)*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+g)(h+i+jk))'" 12 O=!(a*b+(c+d)*(e+f+g)*(h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+g)(h+ij+kl))'" 13 O=!(a*b+(c+d)*(e+f+g)*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+g)(hi+jk+lm))'" 14 O=!(a*b+(c+d)*(e+f+g)*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(f+g+h)(i+j+k))'" 12 O=!(a*b+(c+d*e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d(e+f))(g+h+i)(j+k+l))'" 13 O=!(a*b+(c+d*(e+f))*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+(d+e)(f+g))(h+i+j)(k+l+m))'" 14 O=!(a*b+(c+(d+e)*(f+g))*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(g+h+i)(j+k+l))'" 13 O=!(a*b+(c*d+e*f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+e(f+g))(h+i+j)(k+l+m))'" 14 O=!(a*b+(c*d+e*(f+g))*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+(e+f)(g+h))(i+j+k)(l+m+n))'" 15 O=!(a*b+(c*d+(e+f)*(g+h))*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+h)(i+j+k))'" 12 O=!(a*b+(c+d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+h)(i+j+kl))'" 13 O=!(a*b+(c+d+e)*(f+g+h)*(i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+h)(i+jk+lm))'" 14 O=!(a*b+(c+d+e)*(f+g+h)*(i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+h)(ij+kl+mn))'" 15 O=!(a*b+(c+d+e)*(f+g+h)*(i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef)'" 7 O=!(a*b+c*d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde(f+g))'" 8 O=!(a*b+c*d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde(f+g+h))'" 9 O=!(a*b+c*d*e*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f)(g+h))'" 9 O=!(a*b+c*d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f)(g+h+i))'" 10 O=!(a*b+c*d*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f+g)(h+i+j))'" 11 O=!(a*b+c*d*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g)(h+i))'" 10 O=!(a*b+c*(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g)(h+i+j))'" 11 O=!(a*b+c*(d+e)*(f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g+h)(i+j+k))'" 12 O=!(a*b+c*(d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e+f)(g+h+i)(j+k+l))'" 13 O=!(a*b+c*(d+e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h)(i+j))'" 11 O=!(a*b+(c+d)*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h)(i+j+k))'" 12 O=!(a*b+(c+d)*(e+f)*(g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h+i)(j+k+l))'" 13 O=!(a*b+(c+d)*(e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f+g)(h+i+j)(k+l+m))'" 14 O=!(a*b+(c+d)*(e+f+g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d+e)(f+g+h)(i+j+k)(l+m+n))'" 15 O=!(a*b+(c+d+e)*(f+g+h)*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(e+f))'" 7 O=!(a*(b+c)+d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(e+fg))'" 8 O=!(a*(b+c)+d*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(e+fgh))'" 9 O=!(a*(b+c)+d*(e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(ef+gh))'" 9 O=!(a*(b+c)+d*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(ef+ghi))'" 10 O=!(a*(b+c)+d*(e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(efg+hij))'" 11 O=!(a*(b+c)+d*(e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(f+g))'" 8 O=!(a*(b+c)+(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(f+gh))'" 9 O=!(a*(b+c)+(d+e)*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(f+ghi))'" 10 O=!(a*(b+c)+(d+e)*(f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(fg+hi))'" 10 O=!(a*(b+c)+(d+e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(fg+hij))'" 11 O=!(a*(b+c)+(d+e)*(f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(fgh+ijk))'" 12 O=!(a*(b+c)+(d+e)*(f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+ef)(g+hi))'" 10 O=!(a*(b+c)+(d+e*f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+ef)(gh+ij))'" 11 O=!(a*(b+c)+(d+e*f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(de+fg)(hi+jk))'" 12 O=!(a*(b+c)+(d*e+f*g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+def)'" 7 O=!(a*(b+c)+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+de(f+g))'" 8 O=!(a*(b+c)+d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+de(f+gh))'" 9 O=!(a*(b+c)+d*e*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+de(fg+hi))'" 10 O=!(a*(b+c)+d*e*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(e+f)(g+h))'" 9 O=!(a*(b+c)+d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(e+f)(g+hi))'" 10 O=!(a*(b+c)+d*(e+f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(e+f)(gh+ij))'" 11 O=!(a*(b+c)+d*(e+f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(f+g)(h+i))'" 10 O=!(a*(b+c)+(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(f+g)(h+ij))'" 11 O=!(a*(b+c)+(d+e)*(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(f+g)(hi+jk))'" 12 O=!(a*(b+c)+(d+e)*(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+defg)'" 8 O=!(a*(b+c)+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+def(g+h))'" 9 O=!(a*(b+c)+d*e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+de(f+g)(h+i))'" 10 O=!(a*(b+c)+d*e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+d(e+f)(g+h)(i+j))'" 11 O=!(a*(b+c)+d*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+(d+e)(f+g)(h+i)(j+k))'" 12 O=!(a*(b+c)+(d+e)*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+e(f+gh))'" 9 O=!(a*(b+c*d)+e*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+e(f+ghi))'" 10 O=!(a*(b+c*d)+e*(f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+e(fg+hi))'" 10 O=!(a*(b+c*d)+e*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+e(fg+hij))'" 11 O=!(a*(b+c*d)+e*(f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+e(fgh+ijk))'" 12 O=!(a*(b+c*d)+e*(f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+f)(g+h))'" 9 O=!(a*(b+c*d)+(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+f)(g+hi))'" 10 O=!(a*(b+c*d)+(e+f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+f)(g+hij))'" 11 O=!(a*(b+c*d)+(e+f)*(g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+f)(gh+ij))'" 11 O=!(a*(b+c*d)+(e+f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+f)(gh+ijk))'" 12 O=!(a*(b+c*d)+(e+f)*(g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+f)(ghi+jkl))'" 13 O=!(a*(b+c*d)+(e+f)*(g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+fg)(h+ij))'" 11 O=!(a*(b+c*d)+(e+f*g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+fg)(hi+jk))'" 12 O=!(a*(b+c*d)+(e+f*g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(ef+gh)(ij+kl))'" 13 O=!(a*(b+c*d)+(e*f+g*h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+efg)'" 8 O=!(a*(b+c*d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+ef(g+h))'" 9 O=!(a*(b+c*d)+e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+ef(g+hi))'" 10 O=!(a*(b+c*d)+e*f*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+ef(gh+ij))'" 11 O=!(a*(b+c*d)+e*f*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+e(f+g)(h+i))'" 10 O=!(a*(b+c*d)+e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+e(f+g)(h+ij))'" 11 O=!(a*(b+c*d)+e*(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+e(f+g)(hi+jk))'" 12 O=!(a*(b+c*d)+e*(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+f)(g+h)(i+j))'" 11 O=!(a*(b+c*d)+(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+f)(g+h)(i+jk))'" 12 O=!(a*(b+c*d)+(e+f)*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+f)(g+h)(ij+kl))'" 13 O=!(a*(b+c*d)+(e+f)*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+efgh)'" 9 O=!(a*(b+c*d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+efg(h+i))'" 10 O=!(a*(b+c*d)+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+ef(g+h)(i+j))'" 11 O=!(a*(b+c*d)+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+e(f+g)(h+i)(j+k))'" 12 O=!(a*(b+c*d)+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+(e+f)(g+h)(i+j)(k+l))'" 13 O=!(a*(b+c*d)+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e))+fgh)'" 9 O=!(a*(b+c*(d+e))+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e))+fghi)'" 10 O=!(a*(b+c*(d+e))+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+ef))+ghi)'" 10 O=!(a*(b+c*(d+e*f))+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+ef))+ghij)'" 11 O=!(a*(b+c*(d+e*f))+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(de+fg))+hij)'" 11 O=!(a*(b+c*(d*e+f*g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(de+fg))+hijk)'" 12 O=!(a*(b+c*(d*e+f*g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f))+ghi)'" 10 O=!(a*(b+(c+d)*(e+f))+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f))+ghij)'" 11 O=!(a*(b+(c+d)*(e+f))+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+fg))+hij)'" 11 O=!(a*(b+(c+d)*(e+f*g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+fg))+hijk)'" 12 O=!(a*(b+(c+d)*(e+f*g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(ef+gh))+ijk)'" 12 O=!(a*(b+(c+d)*(e*f+g*h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(ef+gh))+ijkl)'" 13 O=!(a*(b+(c+d)*(e*f+g*h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+f(g+hij))'" 11 O=!(a*(b+c*d*e)+f*(g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+f(gh+ij))'" 11 O=!(a*(b+c*d*e)+f*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+f(gh+ijk))'" 12 O=!(a*(b+c*d*e)+f*(g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+f(ghi+jkl))'" 13 O=!(a*(b+c*d*e)+f*(g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+g)(h+i))'" 10 O=!(a*(b+c*d*e)+(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+g)(h+ij))'" 11 O=!(a*(b+c*d*e)+(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+g)(h+ijk))'" 12 O=!(a*(b+c*d*e)+(f+g)*(h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+g)(hi+jk))'" 12 O=!(a*(b+c*d*e)+(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+g)(hi+jkl))'" 13 O=!(a*(b+c*d*e)+(f+g)*(h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+g)(hij+klm))'" 14 O=!(a*(b+c*d*e)+(f+g)*(h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+gh)(i+jk))'" 12 O=!(a*(b+c*d*e)+(f+g*h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+gh)(ij+kl))'" 13 O=!(a*(b+c*d*e)+(f+g*h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(fg+hi)(jk+lm))'" 14 O=!(a*(b+c*d*e)+(f*g+h*i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fgh)'" 9 O=!(a*(b+c*d*e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fg(h+i))'" 10 O=!(a*(b+c*d*e)+f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fg(h+ij))'" 11 O=!(a*(b+c*d*e)+f*g*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fg(hi+jk))'" 12 O=!(a*(b+c*d*e)+f*g*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+f(g+h)(i+j))'" 11 O=!(a*(b+c*d*e)+f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+f(g+h)(i+jk))'" 12 O=!(a*(b+c*d*e)+f*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+f(g+h)(ij+kl))'" 13 O=!(a*(b+c*d*e)+f*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+g)(h+i)(j+k))'" 12 O=!(a*(b+c*d*e)+(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+g)(h+i)(j+kl))'" 13 O=!(a*(b+c*d*e)+(f+g)*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+g)(h+i)(jk+lm))'" 14 O=!(a*(b+c*d*e)+(f+g)*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fghi)'" 10 O=!(a*(b+c*d*e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fgh(i+j))'" 11 O=!(a*(b+c*d*e)+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fg(h+i)(j+k))'" 12 O=!(a*(b+c*d*e)+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+f(g+h)(i+j)(k+l))'" 13 O=!(a*(b+c*d*e)+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a*(b+c*d*e)+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd(e+f))+ghi)'" 10 O=!(a*(b+c*d*(e+f))+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd(e+f))+ghij)'" 11 O=!(a*(b+c*d*(e+f))+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e)(f+g))+hij)'" 11 O=!(a*(b+c*(d+e)*(f+g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e)(f+g))+hijk)'" 12 O=!(a*(b+c*(d+e)*(f+g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f)(g+h))+ijk)'" 12 O=!(a*(b+(c+d)*(e+f)*(g+h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f)(g+h))+ijkl)'" 13 O=!(a*(b+(c+d)*(e+f)*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+f(gh+ij))'" 11 O=!(a*(b*c+d*e)+f*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+f(gh+ijk))'" 12 O=!(a*(b*c+d*e)+f*(g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+f(ghi+jkl))'" 13 O=!(a*(b*c+d*e)+f*(g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+g)(h+i))'" 10 O=!(a*(b*c+d*e)+(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+g)(h+ij))'" 11 O=!(a*(b*c+d*e)+(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+g)(h+ijk))'" 12 O=!(a*(b*c+d*e)+(f+g)*(h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+g)(hi+jk))'" 12 O=!(a*(b*c+d*e)+(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+g)(hi+jkl))'" 13 O=!(a*(b*c+d*e)+(f+g)*(h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+g)(hij+klm))'" 14 O=!(a*(b*c+d*e)+(f+g)*(h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+gh)(i+jk))'" 12 O=!(a*(b*c+d*e)+(f+g*h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+gh)(ij+kl))'" 13 O=!(a*(b*c+d*e)+(f+g*h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(fg+hi)(jk+lm))'" 14 O=!(a*(b*c+d*e)+(f*g+h*i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fgh)'" 9 O=!(a*(b*c+d*e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fg(h+i))'" 10 O=!(a*(b*c+d*e)+f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fg(h+ij))'" 11 O=!(a*(b*c+d*e)+f*g*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fg(hi+jk))'" 12 O=!(a*(b*c+d*e)+f*g*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+f(g+h)(i+j))'" 11 O=!(a*(b*c+d*e)+f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+f(g+h)(i+jk))'" 12 O=!(a*(b*c+d*e)+f*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+f(g+h)(ij+kl))'" 13 O=!(a*(b*c+d*e)+f*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+g)(h+i)(j+k))'" 12 O=!(a*(b*c+d*e)+(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+g)(h+i)(j+kl))'" 13 O=!(a*(b*c+d*e)+(f+g)*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+g)(h+i)(jk+lm))'" 14 O=!(a*(b*c+d*e)+(f+g)*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fghi)'" 10 O=!(a*(b*c+d*e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fgh(i+j))'" 11 O=!(a*(b*c+d*e)+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fg(h+i)(j+k))'" 12 O=!(a*(b*c+d*e)+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+f(g+h)(i+j)(k+l))'" 13 O=!(a*(b*c+d*e)+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a*(b*c+d*e)+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f))+ghi)'" 10 O=!(a*(b*c+d*(e+f))+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f))+ghij)'" 11 O=!(a*(b*c+d*(e+f))+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+fg))+hij)'" 11 O=!(a*(b*c+d*(e+f*g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+fg))+hijk)'" 12 O=!(a*(b*c+d*(e+f*g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(ef+gh))+ijk)'" 12 O=!(a*(b*c+d*(e*f+g*h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(ef+gh))+ijkl)'" 13 O=!(a*(b*c+d*(e*f+g*h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g))+hij)'" 11 O=!(a*(b*c+(d+e)*(f+g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g))+hijk)'" 12 O=!(a*(b*c+(d+e)*(f+g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+gh))+ijk)'" 12 O=!(a*(b*c+(d+e)*(f+g*h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+gh))+ijkl)'" 13 O=!(a*(b*c+(d+e)*(f+g*h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(fg+hi))+jkl)'" 13 O=!(a*(b*c+(d+e)*(f*g+h*i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(fg+hi))+jklm)'" 14 O=!(a*(b*c+(d+e)*(f*g+h*i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+g(hi+jkl))'" 13 O=!(a*(b*c+d*e*f)+g*(h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+g(hij+klm))'" 14 O=!(a*(b*c+d*e*f)+g*(h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+h)(i+j))'" 11 O=!(a*(b*c+d*e*f)+(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+h)(i+jk))'" 12 O=!(a*(b*c+d*e*f)+(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+h)(i+jkl))'" 13 O=!(a*(b*c+d*e*f)+(g+h)*(i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+h)(ij+kl))'" 13 O=!(a*(b*c+d*e*f)+(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+h)(ij+klm))'" 14 O=!(a*(b*c+d*e*f)+(g+h)*(i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+h)(ijk+lmn))'" 15 O=!(a*(b*c+d*e*f)+(g+h)*(i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+hi)(j+kl))'" 13 O=!(a*(b*c+d*e*f)+(g+h*i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+hi)(jk+lm))'" 14 O=!(a*(b*c+d*e*f)+(g+h*i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(gh+ij)(kl+mn))'" 15 O=!(a*(b*c+d*e*f)+(g*h+i*j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+ghi)'" 10 O=!(a*(b*c+d*e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+gh(i+j))'" 11 O=!(a*(b*c+d*e*f)+g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+gh(i+jk))'" 12 O=!(a*(b*c+d*e*f)+g*h*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+gh(ij+kl))'" 13 O=!(a*(b*c+d*e*f)+g*h*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+g(h+i)(j+k))'" 12 O=!(a*(b*c+d*e*f)+g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+g(h+i)(j+kl))'" 13 O=!(a*(b*c+d*e*f)+g*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+g(h+i)(jk+lm))'" 14 O=!(a*(b*c+d*e*f)+g*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+h)(i+j)(k+l))'" 13 O=!(a*(b*c+d*e*f)+(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+h)(i+j)(k+lm))'" 14 O=!(a*(b*c+d*e*f)+(g+h)*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+h)(i+j)(kl+mn))'" 15 O=!(a*(b*c+d*e*f)+(g+h)*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+ghij)'" 11 O=!(a*(b*c+d*e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+ghi(j+k))'" 12 O=!(a*(b*c+d*e*f)+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+gh(i+j)(k+l))'" 13 O=!(a*(b*c+d*e*f)+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+g(h+i)(j+k)(l+m))'" 14 O=!(a*(b*c+d*e*f)+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+(g+h)(i+j)(k+l)(m+n))'" 15 O=!(a*(b*c+d*e*f)+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de(f+g))+hij)'" 11 O=!(a*(b*c+d*e*(f+g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de(f+g))+hijk)'" 12 O=!(a*(b*c+d*e*(f+g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f)(g+h))+ijk)'" 12 O=!(a*(b*c+d*(e+f)*(g+h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f)(g+h))+ijkl)'" 13 O=!(a*(b*c+d*(e+f)*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g)(h+i))+jkl)'" 13 O=!(a*(b*c+(d+e)*(f+g)*(h+i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g)(h+i))+jklm)'" 14 O=!(a*(b*c+(d+e)*(f+g)*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+efg)+hij)'" 11 O=!(a*(b*(c+d)+e*f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+d)+efg)+hijk)'" 12 O=!(a*(b*(c+d)+e*f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+fgh)+ijk)'" 12 O=!(a*(b*(c+d*e)+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(c+de)+fgh)+ijkl)'" 13 O=!(a*(b*(c+d*e)+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+ghi)+jkl)'" 13 O=!(a*(b*(c*d+e*f)+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b(cd+ef)+ghi)+jklm)'" 14 O=!(a*(b*(c*d+e*f)+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+fgh)+ijk)'" 12 O=!(a*((b+c)*(d+e)+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+e)+fgh)+ijkl)'" 13 O=!(a*((b+c)*(d+e)+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef)+ghi)+jkl)'" 13 O=!(a*((b+c)*(d+e*f)+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(d+ef)+ghi)+jklm)'" 14 O=!(a*((b+c)*(d+e*f)+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+fg)+hij)+klm)'" 14 O=!(a*((b+c)*(d*e+f*g)+h*i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a((b+c)(de+fg)+hij)+klmn)'" 15 O=!(a*((b+c)*(d*e+f*g)+h*i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+h(ijk+lmn))'" 15 O=!(a*(b*c*d+e*f*g)+h*(i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+i)(j+k))'" 12 O=!(a*(b*c*d+e*f*g)+(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+i)(j+kl))'" 13 O=!(a*(b*c*d+e*f*g)+(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+i)(j+klm))'" 14 O=!(a*(b*c*d+e*f*g)+(h+i)*(j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+i)(jk+lm))'" 14 O=!(a*(b*c*d+e*f*g)+(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+i)(jk+lmn))'" 15 O=!(a*(b*c*d+e*f*g)+(h+i)*(j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+i)(jkl+mno))'" 16 O=!(a*(b*c*d+e*f*g)+(h+i)*(j*k*l+m*n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+ij)(k+lm))'" 14 O=!(a*(b*c*d+e*f*g)+(h+i*j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+ij)(kl+mn))'" 15 O=!(a*(b*c*d+e*f*g)+(h+i*j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(hi+jk)(lm+no))'" 16 O=!(a*(b*c*d+e*f*g)+(h*i+j*k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hij)'" 11 O=!(a*(b*c*d+e*f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hi(j+k))'" 12 O=!(a*(b*c*d+e*f*g)+h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hi(j+kl))'" 13 O=!(a*(b*c*d+e*f*g)+h*i*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hi(jk+lm))'" 14 O=!(a*(b*c*d+e*f*g)+h*i*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+h(i+j)(k+l))'" 13 O=!(a*(b*c*d+e*f*g)+h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+h(i+j)(k+lm))'" 14 O=!(a*(b*c*d+e*f*g)+h*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+h(i+j)(kl+mn))'" 15 O=!(a*(b*c*d+e*f*g)+h*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+i)(j+k)(l+m))'" 14 O=!(a*(b*c*d+e*f*g)+(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+i)(j+k)(l+mn))'" 15 O=!(a*(b*c*d+e*f*g)+(h+i)*(j+k)*(l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+i)(j+k)(lm+no))'" 16 O=!(a*(b*c*d+e*f*g)+(h+i)*(j+k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hijk)'" 12 O=!(a*(b*c*d+e*f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hij(k+l))'" 13 O=!(a*(b*c*d+e*f*g)+h*i*j*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hi(j+k)(l+m))'" 14 O=!(a*(b*c*d+e*f*g)+h*i*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+h(i+j)(k+l)(m+n))'" 15 O=!(a*(b*c*d+e*f*g)+h*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+(h+i)(j+k)(l+m)(n+o))'" 16 O=!(a*(b*c*d+e*f*g)+(h+i)*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+ef(g+h))+ijk)'" 12 O=!(a*(b*c*d+e*f*(g+h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+ef(g+h))+ijkl)'" 13 O=!(a*(b*c*d+e*f*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+e(f+g)(h+i))+jkl)'" 13 O=!(a*(b*c*d+e*(f+g)*(h+i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+e(f+g)(h+i))+jklm)'" 14 O=!(a*(b*c*d+e*(f+g)*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+(e+f)(g+h)(i+j))+klm)'" 14 O=!(a*(b*c*d+(e+f)*(g+h)*(i+j))+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+(e+f)(g+h)(i+j))+klmn)'" 15 O=!(a*(b*c*d+(e+f)*(g+h)*(i+j))+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)+efg)'" 8 O=!(a*(b+c+d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)+efgh)'" 9 O=!(a*(b+c+d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de)+fgh)'" 9 O=!(a*(b+c+d*e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+de)+fghi)'" 10 O=!(a*(b+c+d*e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+def)+ghi)'" 10 O=!(a*(b+c+d*e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+def)+ghij)'" 11 O=!(a*(b+c+d*e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef)+ghi)'" 10 O=!(a*(b+c*d+e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+ef)+ghij)'" 11 O=!(a*(b+c*d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+efg)+hij)'" 11 O=!(a*(b+c*d+e*f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd+efg)+hijk)'" 12 O=!(a*(b+c*d+e*f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde+fgh)+ijk)'" 12 O=!(a*(b+c*d*e+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde+fgh)+ijkl)'" 13 O=!(a*(b+c*d*e+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg)+hij)'" 11 O=!(a*(b*c+d*e+f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fg)+hijk)'" 12 O=!(a*(b*c+d*e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fgh)+ijk)'" 12 O=!(a*(b*c+d*e+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de+fgh)+ijkl)'" 13 O=!(a*(b*c+d*e+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def+ghi)+jkl)'" 13 O=!(a*(b*c+d*e*f+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def+ghi)+jklm)'" 14 O=!(a*(b*c+d*e*f+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg+hij)+klm)'" 14 O=!(a*(b*c*d+e*f*g+h*i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg+hij)+klmn)'" 15 O=!(a*(b*c*d+e*f*g+h*i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(g+h))'" 9 O=!((a+b)*(c+d)+(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(g+hi))'" 10 O=!((a+b)*(c+d)+(e+f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(g+hij))'" 11 O=!((a+b)*(c+d)+(e+f)*(g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(gh+ij))'" 11 O=!((a+b)*(c+d)+(e+f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(gh+ijk))'" 12 O=!((a+b)*(c+d)+(e+f)*(g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(ghi+jkl))'" 13 O=!((a+b)*(c+d)+(e+f)*(g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+fg)(h+ij))'" 11 O=!((a+b)*(c+d)+(e+f*g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+fg)(hi+jk))'" 12 O=!((a+b)*(c+d)+(e+f*g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(ef+gh)(ij+kl))'" 13 O=!((a+b)*(c+d)+(e*f+g*h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efg)'" 8 O=!((a+b)*(c+d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+ef(g+h))'" 9 O=!((a+b)*(c+d)+e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+ef(g+hi))'" 10 O=!((a+b)*(c+d)+e*f*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+ef(gh+ij))'" 11 O=!((a+b)*(c+d)+e*f*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+e(f+g)(h+i))'" 10 O=!((a+b)*(c+d)+e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+e(f+g)(h+ij))'" 11 O=!((a+b)*(c+d)+e*(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+e(f+g)(hi+jk))'" 12 O=!((a+b)*(c+d)+e*(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(g+h)(i+j))'" 11 O=!((a+b)*(c+d)+(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(g+h)(i+jk))'" 12 O=!((a+b)*(c+d)+(e+f)*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(g+h)(ij+kl))'" 13 O=!((a+b)*(c+d)+(e+f)*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efgh)'" 9 O=!((a+b)*(c+d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efg(h+i))'" 10 O=!((a+b)*(c+d)+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+ef(g+h)(i+j))'" 11 O=!((a+b)*(c+d)+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+e(f+g)(h+i)(j+k))'" 12 O=!((a+b)*(c+d)+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+(e+f)(g+h)(i+j)(k+l))'" 13 O=!((a+b)*(c+d)+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+g)(h+ij))'" 11 O=!((a+b)*(c+d*e)+(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+g)(h+ijk))'" 12 O=!((a+b)*(c+d*e)+(f+g)*(h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+g)(hi+jk))'" 12 O=!((a+b)*(c+d*e)+(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+g)(hi+jkl))'" 13 O=!((a+b)*(c+d*e)+(f+g)*(h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+g)(hij+klm))'" 14 O=!((a+b)*(c+d*e)+(f+g)*(h*i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+gh)(i+jk))'" 12 O=!((a+b)*(c+d*e)+(f+g*h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+gh)(ij+kl))'" 13 O=!((a+b)*(c+d*e)+(f+g*h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(fg+hi)(jk+lm))'" 14 O=!((a+b)*(c+d*e)+(f*g+h*i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fgh)'" 9 O=!((a+b)*(c+d*e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fg(h+i))'" 10 O=!((a+b)*(c+d*e)+f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fg(h+ij))'" 11 O=!((a+b)*(c+d*e)+f*g*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fg(hi+jk))'" 12 O=!((a+b)*(c+d*e)+f*g*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+f(g+h)(i+j))'" 11 O=!((a+b)*(c+d*e)+f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+f(g+h)(i+jk))'" 12 O=!((a+b)*(c+d*e)+f*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+f(g+h)(ij+kl))'" 13 O=!((a+b)*(c+d*e)+f*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+g)(h+i)(j+k))'" 12 O=!((a+b)*(c+d*e)+(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+g)(h+i)(j+kl))'" 13 O=!((a+b)*(c+d*e)+(f+g)*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+g)(h+i)(jk+lm))'" 14 O=!((a+b)*(c+d*e)+(f+g)*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fghi)'" 10 O=!((a+b)*(c+d*e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fgh(i+j))'" 11 O=!((a+b)*(c+d*e)+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fg(h+i)(j+k))'" 12 O=!((a+b)*(c+d*e)+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+f(g+h)(i+j)(k+l))'" 13 O=!((a+b)*(c+d*e)+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+(f+g)(h+i)(j+k)(l+m))'" 14 O=!((a+b)*(c+d*e)+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f))+ghi)'" 10 O=!((a+b)*(c+d*(e+f))+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f))+ghij)'" 11 O=!((a+b)*(c+d*(e+f))+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+fg))+hij)'" 11 O=!((a+b)*(c+d*(e+f*g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+fg))+hijk)'" 12 O=!((a+b)*(c+d*(e+f*g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(ef+gh))+ijk)'" 12 O=!((a+b)*(c+d*(e*f+g*h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(ef+gh))+ijkl)'" 13 O=!((a+b)*(c+d*(e*f+g*h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g))+hij)'" 11 O=!((a+b)*(c+(d+e)*(f+g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g))+hijk)'" 12 O=!((a+b)*(c+(d+e)*(f+g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+gh))+ijk)'" 12 O=!((a+b)*(c+(d+e)*(f+g*h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+gh))+ijkl)'" 13 O=!((a+b)*(c+(d+e)*(f+g*h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(fg+hi))+jkl)'" 13 O=!((a+b)*(c+(d+e)*(f*g+h*i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(fg+hi))+jklm)'" 14 O=!((a+b)*(c+(d+e)*(f*g+h*i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(g+h)(i+jkl))'" 13 O=!((a+b)*(c+d*e*f)+(g+h)*(i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(g+h)(ij+kl))'" 13 O=!((a+b)*(c+d*e*f)+(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(g+h)(ij+klm))'" 14 O=!((a+b)*(c+d*e*f)+(g+h)*(i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(g+h)(ijk+lmn))'" 15 O=!((a+b)*(c+d*e*f)+(g+h)*(i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(g+hi)(j+kl))'" 13 O=!((a+b)*(c+d*e*f)+(g+h*i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(g+hi)(jk+lm))'" 14 O=!((a+b)*(c+d*e*f)+(g+h*i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(gh+ij)(kl+mn))'" 15 O=!((a+b)*(c+d*e*f)+(g*h+i*j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+ghi)'" 10 O=!((a+b)*(c+d*e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+gh(i+j))'" 11 O=!((a+b)*(c+d*e*f)+g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+gh(i+jk))'" 12 O=!((a+b)*(c+d*e*f)+g*h*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+gh(ij+kl))'" 13 O=!((a+b)*(c+d*e*f)+g*h*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+g(h+i)(j+k))'" 12 O=!((a+b)*(c+d*e*f)+g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+g(h+i)(j+kl))'" 13 O=!((a+b)*(c+d*e*f)+g*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+g(h+i)(jk+lm))'" 14 O=!((a+b)*(c+d*e*f)+g*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(g+h)(i+j)(k+l))'" 13 O=!((a+b)*(c+d*e*f)+(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(g+h)(i+j)(k+lm))'" 14 O=!((a+b)*(c+d*e*f)+(g+h)*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(g+h)(i+j)(kl+mn))'" 15 O=!((a+b)*(c+d*e*f)+(g+h)*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+ghij)'" 11 O=!((a+b)*(c+d*e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+ghi(j+k))'" 12 O=!((a+b)*(c+d*e*f)+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+gh(i+j)(k+l))'" 13 O=!((a+b)*(c+d*e*f)+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+g(h+i)(j+k)(l+m))'" 14 O=!((a+b)*(c+d*e*f)+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+(g+h)(i+j)(k+l)(m+n))'" 15 O=!((a+b)*(c+d*e*f)+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de(f+g))+hij)'" 11 O=!((a+b)*(c+d*e*(f+g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de(f+g))+hijk)'" 12 O=!((a+b)*(c+d*e*(f+g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f)(g+h))+ijk)'" 12 O=!((a+b)*(c+d*(e+f)*(g+h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f)(g+h))+ijkl)'" 13 O=!((a+b)*(c+d*(e+f)*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g)(h+i))+jkl)'" 13 O=!((a+b)*(c+(d+e)*(f+g)*(h+i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g)(h+i))+jklm)'" 14 O=!((a+b)*(c+(d+e)*(f+g)*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+(g+h)(ij+kl))'" 13 O=!((a+b)*(c*d+e*f)+(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+(g+h)(ij+klm))'" 14 O=!((a+b)*(c*d+e*f)+(g+h)*(i*j+k*l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+(g+h)(ijk+lmn))'" 15 O=!((a+b)*(c*d+e*f)+(g+h)*(i*j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+(g+hi)(j+kl))'" 13 O=!((a+b)*(c*d+e*f)+(g+h*i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+(g+hi)(jk+lm))'" 14 O=!((a+b)*(c*d+e*f)+(g+h*i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+(gh+ij)(kl+mn))'" 15 O=!((a+b)*(c*d+e*f)+(g*h+i*j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+ghi)'" 10 O=!((a+b)*(c*d+e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+gh(i+j))'" 11 O=!((a+b)*(c*d+e*f)+g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+gh(i+jk))'" 12 O=!((a+b)*(c*d+e*f)+g*h*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+gh(ij+kl))'" 13 O=!((a+b)*(c*d+e*f)+g*h*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+g(h+i)(j+k))'" 12 O=!((a+b)*(c*d+e*f)+g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+g(h+i)(j+kl))'" 13 O=!((a+b)*(c*d+e*f)+g*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+g(h+i)(jk+lm))'" 14 O=!((a+b)*(c*d+e*f)+g*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+(g+h)(i+j)(k+l))'" 13 O=!((a+b)*(c*d+e*f)+(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+(g+h)(i+j)(k+lm))'" 14 O=!((a+b)*(c*d+e*f)+(g+h)*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+(g+h)(i+j)(kl+mn))'" 15 O=!((a+b)*(c*d+e*f)+(g+h)*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+ghij)'" 11 O=!((a+b)*(c*d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+ghi(j+k))'" 12 O=!((a+b)*(c*d+e*f)+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+gh(i+j)(k+l))'" 13 O=!((a+b)*(c*d+e*f)+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+g(h+i)(j+k)(l+m))'" 14 O=!((a+b)*(c*d+e*f)+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+(g+h)(i+j)(k+l)(m+n))'" 15 O=!((a+b)*(c*d+e*f)+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g))+hij)'" 11 O=!((a+b)*(c*d+e*(f+g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g))+hijk)'" 12 O=!((a+b)*(c*d+e*(f+g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+gh))+ijk)'" 12 O=!((a+b)*(c*d+e*(f+g*h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+gh))+ijkl)'" 13 O=!((a+b)*(c*d+e*(f+g*h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(fg+hi))+jkl)'" 13 O=!((a+b)*(c*d+e*(f*g+h*i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(fg+hi))+jklm)'" 14 O=!((a+b)*(c*d+e*(f*g+h*i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h))+ijk)'" 12 O=!((a+b)*(c*d+(e+f)*(g+h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h))+ijkl)'" 13 O=!((a+b)*(c*d+(e+f)*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+hi))+jkl)'" 13 O=!((a+b)*(c*d+(e+f)*(g+h*i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+hi))+jklm)'" 14 O=!((a+b)*(c*d+(e+f)*(g+h*i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(gh+ij))+klm)'" 14 O=!((a+b)*(c*d+(e+f)*(g*h+i*j))+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(gh+ij))+klmn)'" 15 O=!((a+b)*(c*d+(e+f)*(g*h+i*j))+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+(h+i)(jk+lmn))'" 15 O=!((a+b)*(c*d+e*f*g)+(h+i)*(j*k+l*m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+(h+i)(jkl+mno))'" 16 O=!((a+b)*(c*d+e*f*g)+(h+i)*(j*k*l+m*n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+(h+ij)(k+lm))'" 14 O=!((a+b)*(c*d+e*f*g)+(h+i*j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+(h+ij)(kl+mn))'" 15 O=!((a+b)*(c*d+e*f*g)+(h+i*j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+(hi+jk)(lm+no))'" 16 O=!((a+b)*(c*d+e*f*g)+(h*i+j*k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hij)'" 11 O=!((a+b)*(c*d+e*f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hi(j+k))'" 12 O=!((a+b)*(c*d+e*f*g)+h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hi(j+kl))'" 13 O=!((a+b)*(c*d+e*f*g)+h*i*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hi(jk+lm))'" 14 O=!((a+b)*(c*d+e*f*g)+h*i*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+h(i+j)(k+l))'" 13 O=!((a+b)*(c*d+e*f*g)+h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+h(i+j)(k+lm))'" 14 O=!((a+b)*(c*d+e*f*g)+h*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+h(i+j)(kl+mn))'" 15 O=!((a+b)*(c*d+e*f*g)+h*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+(h+i)(j+k)(l+m))'" 14 O=!((a+b)*(c*d+e*f*g)+(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+(h+i)(j+k)(l+mn))'" 15 O=!((a+b)*(c*d+e*f*g)+(h+i)*(j+k)*(l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+(h+i)(j+k)(lm+no))'" 16 O=!((a+b)*(c*d+e*f*g)+(h+i)*(j+k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hijk)'" 12 O=!((a+b)*(c*d+e*f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hij(k+l))'" 13 O=!((a+b)*(c*d+e*f*g)+h*i*j*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hi(j+k)(l+m))'" 14 O=!((a+b)*(c*d+e*f*g)+h*i*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+h(i+j)(k+l)(m+n))'" 15 O=!((a+b)*(c*d+e*f*g)+h*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+(h+i)(j+k)(l+m)(n+o))'" 16 O=!((a+b)*(c*d+e*f*g)+(h+i)*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef(g+h))+ijk)'" 12 O=!((a+b)*(c*d+e*f*(g+h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef(g+h))+ijkl)'" 13 O=!((a+b)*(c*d+e*f*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g)(h+i))+jkl)'" 13 O=!((a+b)*(c*d+e*(f+g)*(h+i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g)(h+i))+jklm)'" 14 O=!((a+b)*(c*d+e*(f+g)*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h)(i+j))+klm)'" 14 O=!((a+b)*(c*d+(e+f)*(g+h)*(i+j))+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h)(i+j))+klmn)'" 15 O=!((a+b)*(c*d+(e+f)*(g+h)*(i+j))+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+fgh)+ijk)'" 12 O=!((a+b)*(c*(d+e)+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+e)+fgh)+ijkl)'" 13 O=!((a+b)*(c*(d+e)+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+ghi)+jkl)'" 13 O=!((a+b)*(c*(d+e*f)+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(d+ef)+ghi)+jklm)'" 14 O=!((a+b)*(c*(d+e*f)+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+hij)+klm)'" 14 O=!((a+b)*(c*(d*e+f*g)+h*i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c(de+fg)+hij)+klmn)'" 15 O=!((a+b)*(c*(d*e+f*g)+h*i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+ghi)+jkl)'" 13 O=!((a+b)*((c+d)*(e+f)+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+f)+ghi)+jklm)'" 14 O=!((a+b)*((c+d)*(e+f)+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg)+hij)+klm)'" 14 O=!((a+b)*((c+d)*(e+f*g)+h*i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(e+fg)+hij)+klmn)'" 15 O=!((a+b)*((c+d)*(e+f*g)+h*i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+gh)+ijk)+lmn)'" 15 O=!((a+b)*((c+d)*(e*f+g*h)+i*j*k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)((c+d)(ef+gh)+ijk)+lmno)'" 16 O=!((a+b)*((c+d)*(e*f+g*h)+i*j*k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+(i+j)(klm+nop))'" 17 O=!((a+b)*(c*d*e+f*g*h)+(i+j)*(k*l*m+n*o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+(i+jk)(l+mn))'" 15 O=!((a+b)*(c*d*e+f*g*h)+(i+j*k)*(l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+(i+jk)(lm+no))'" 16 O=!((a+b)*(c*d*e+f*g*h)+(i+j*k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+(ij+kl)(mn+op))'" 17 O=!((a+b)*(c*d*e+f*g*h)+(i*j+k*l)*(m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ijk)'" 12 O=!((a+b)*(c*d*e+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ij(k+l))'" 13 O=!((a+b)*(c*d*e+f*g*h)+i*j*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ij(k+lm))'" 14 O=!((a+b)*(c*d*e+f*g*h)+i*j*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ij(kl+mn))'" 15 O=!((a+b)*(c*d*e+f*g*h)+i*j*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+i(j+k)(l+m))'" 14 O=!((a+b)*(c*d*e+f*g*h)+i*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+i(j+k)(l+mn))'" 15 O=!((a+b)*(c*d*e+f*g*h)+i*(j+k)*(l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+i(j+k)(lm+no))'" 16 O=!((a+b)*(c*d*e+f*g*h)+i*(j+k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+(i+j)(k+l)(m+n))'" 15 O=!((a+b)*(c*d*e+f*g*h)+(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+(i+j)(k+l)(m+no))'" 16 O=!((a+b)*(c*d*e+f*g*h)+(i+j)*(k+l)*(m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+(i+j)(k+l)(mn+op))'" 17 O=!((a+b)*(c*d*e+f*g*h)+(i+j)*(k+l)*(m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ijkl)'" 13 O=!((a+b)*(c*d*e+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ijk(l+m))'" 14 O=!((a+b)*(c*d*e+f*g*h)+i*j*k*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ij(k+l)(m+n))'" 15 O=!((a+b)*(c*d*e+f*g*h)+i*j*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+i(j+k)(l+m)(n+o))'" 16 O=!((a+b)*(c*d*e+f*g*h)+i*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+(i+j)(k+l)(m+n)(o+p))'" 17 O=!((a+b)*(c*d*e+f*g*h)+(i+j)*(k+l)*(m+n)*(o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fg(h+i))+jkl)'" 13 O=!((a+b)*(c*d*e+f*g*(h+i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fg(h+i))+jklm)'" 14 O=!((a+b)*(c*d*e+f*g*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+f(g+h)(i+j))+klm)'" 14 O=!((a+b)*(c*d*e+f*(g+h)*(i+j))+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+f(g+h)(i+j))+klmn)'" 15 O=!((a+b)*(c*d*e+f*(g+h)*(i+j))+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+(f+g)(h+i)(j+k))+lmn)'" 15 O=!((a+b)*(c*d*e+(f+g)*(h+i)*(j+k))+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+(f+g)(h+i)(j+k))+lmno)'" 16 O=!((a+b)*(c*d*e+(f+g)*(h+i)*(j+k))+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)+fgh)'" 9 O=!((a+b)*(c+d+e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)+fghi)'" 10 O=!((a+b)*(c+d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef)+ghi)'" 10 O=!((a+b)*(c+d+e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+ef)+ghij)'" 11 O=!((a+b)*(c+d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+efg)+hij)'" 11 O=!((a+b)*(c+d+e*f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+efg)+hijk)'" 12 O=!((a+b)*(c+d+e*f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg)+hij)'" 11 O=!((a+b)*(c+d*e+f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fg)+hijk)'" 12 O=!((a+b)*(c+d*e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fgh)+ijk)'" 12 O=!((a+b)*(c+d*e+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de+fgh)+ijkl)'" 13 O=!((a+b)*(c+d*e+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def+ghi)+jkl)'" 13 O=!((a+b)*(c+d*e*f+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def+ghi)+jklm)'" 14 O=!((a+b)*(c+d*e*f+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh)+ijk)'" 12 O=!((a+b)*(c*d+e*f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+gh)+ijkl)'" 13 O=!((a+b)*(c*d+e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+ghi)+jkl)'" 13 O=!((a+b)*(c*d+e*f+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef+ghi)+jklm)'" 14 O=!((a+b)*(c*d+e*f+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg+hij)+klm)'" 14 O=!((a+b)*(c*d+e*f*g+h*i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg+hij)+klmn)'" 15 O=!((a+b)*(c*d+e*f*g+h*i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh+ijk)+lmn)'" 15 O=!((a+b)*(c*d*e+f*g*h+i*j*k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh+ijk)+lmno)'" 16 O=!((a+b)*(c*d*e+f*g*h+i*j*k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+(g+hi)(j+kl))'" 13 O=!((a+b*c)*(d+e*f)+(g+h*i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+(g+hi)(jk+lm))'" 14 O=!((a+b*c)*(d+e*f)+(g+h*i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+(gh+ij)(kl+mn))'" 15 O=!((a+b*c)*(d+e*f)+(g*h+i*j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+ghi)'" 10 O=!((a+b*c)*(d+e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+gh(i+j))'" 11 O=!((a+b*c)*(d+e*f)+g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+gh(i+jk))'" 12 O=!((a+b*c)*(d+e*f)+g*h*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+gh(ij+kl))'" 13 O=!((a+b*c)*(d+e*f)+g*h*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+g(h+i)(j+k))'" 12 O=!((a+b*c)*(d+e*f)+g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+g(h+i)(j+kl))'" 13 O=!((a+b*c)*(d+e*f)+g*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+g(h+i)(jk+lm))'" 14 O=!((a+b*c)*(d+e*f)+g*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+(g+h)(i+j)(k+l))'" 13 O=!((a+b*c)*(d+e*f)+(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+(g+h)(i+j)(k+lm))'" 14 O=!((a+b*c)*(d+e*f)+(g+h)*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+(g+h)(i+j)(kl+mn))'" 15 O=!((a+b*c)*(d+e*f)+(g+h)*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+ghij)'" 11 O=!((a+b*c)*(d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+ghi(j+k))'" 12 O=!((a+b*c)*(d+e*f)+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+gh(i+j)(k+l))'" 13 O=!((a+b*c)*(d+e*f)+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+g(h+i)(j+k)(l+m))'" 14 O=!((a+b*c)*(d+e*f)+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+(g+h)(i+j)(k+l)(m+n))'" 15 O=!((a+b*c)*(d+e*f)+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e(f+g))+hij)'" 11 O=!((a+b*c)*(d+e*(f+g))+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e(f+g))+hijk)'" 12 O=!((a+b*c)*(d+e*(f+g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+(e+f)(g+h))+ijk)'" 12 O=!((a+b*c)*(d+(e+f)*(g+h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+(e+f)(g+h))+ijkl)'" 13 O=!((a+b*c)*(d+(e+f)*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+(h+ij)(kl+mn))'" 15 O=!((a+b*c)*(d*e+f*g)+(h+i*j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+(hi+jk)(lm+no))'" 16 O=!((a+b*c)*(d*e+f*g)+(h*i+j*k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hij)'" 11 O=!((a+b*c)*(d*e+f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hi(j+k))'" 12 O=!((a+b*c)*(d*e+f*g)+h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hi(j+kl))'" 13 O=!((a+b*c)*(d*e+f*g)+h*i*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hi(jk+lm))'" 14 O=!((a+b*c)*(d*e+f*g)+h*i*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+h(i+j)(k+l))'" 13 O=!((a+b*c)*(d*e+f*g)+h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+h(i+j)(k+lm))'" 14 O=!((a+b*c)*(d*e+f*g)+h*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+h(i+j)(kl+mn))'" 15 O=!((a+b*c)*(d*e+f*g)+h*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+(h+i)(j+k)(l+m))'" 14 O=!((a+b*c)*(d*e+f*g)+(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+(h+i)(j+k)(l+mn))'" 15 O=!((a+b*c)*(d*e+f*g)+(h+i)*(j+k)*(l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+(h+i)(j+k)(lm+no))'" 16 O=!((a+b*c)*(d*e+f*g)+(h+i)*(j+k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hijk)'" 12 O=!((a+b*c)*(d*e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hij(k+l))'" 13 O=!((a+b*c)*(d*e+f*g)+h*i*j*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hi(j+k)(l+m))'" 14 O=!((a+b*c)*(d*e+f*g)+h*i*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+h(i+j)(k+l)(m+n))'" 15 O=!((a+b*c)*(d*e+f*g)+h*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+(h+i)(j+k)(l+m)(n+o))'" 16 O=!((a+b*c)*(d*e+f*g)+(h+i)*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+f(g+h))+ijk)'" 12 O=!((a+b*c)*(d*e+f*(g+h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+f(g+h))+ijkl)'" 13 O=!((a+b*c)*(d*e+f*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+(f+g)(h+i))+jkl)'" 13 O=!((a+b*c)*(d*e+(f+g)*(h+i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+(f+g)(h+i))+jklm)'" 14 O=!((a+b*c)*(d*e+(f+g)*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f)+ghi)'" 10 O=!((a+b*c)*(d+e+f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f)+ghij)'" 11 O=!((a+b*c)*(d+e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+fg)+hij)'" 11 O=!((a+b*c)*(d+e+f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+fg)+hijk)'" 12 O=!((a+b*c)*(d+e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef+gh)+ijk)'" 12 O=!((a+b*c)*(d+e*f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef+gh)+ijkl)'" 13 O=!((a+b*c)*(d+e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg+hi)+jkl)'" 13 O=!((a+b*c)*(d*e+f*g+h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg+hi)+jklm)'" 14 O=!((a+b*c)*(d*e+f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f(g+h))+ijk)'" 12 O=!((a+b*(c+d))*(e+f*(g+h))+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f(g+h))+ijkl)'" 13 O=!((a+b*(c+d))*(e+f*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+(f+g)(h+i))+jkl)'" 13 O=!((a+b*(c+d))*(e+(f+g)*(h+i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+(f+g)(h+i))+jklm)'" 14 O=!((a+b*(c+d))*(e+(f+g)*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh)+ijk)'" 12 O=!((a+b*(c+d))*(e*f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh)+ijkl)'" 13 O=!((a+b*(c+d))*(e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+g(h+i))+jkl)'" 13 O=!((a+b*(c+d))*(e*f+g*(h+i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+g(h+i))+jklm)'" 14 O=!((a+b*(c+d))*(e*f+g*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+(g+h)(i+j))+klm)'" 14 O=!((a+b*(c+d))*(e*f+(g+h)*(i+j))+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+(g+h)(i+j))+klmn)'" 15 O=!((a+b*(c+d))*(e*f+(g+h)*(i+j))+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g)+hij)'" 11 O=!((a+b*(c+d))*(e+f+g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g)+hijk)'" 12 O=!((a+b*(c+d))*(e+f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+gh)+ijk)'" 12 O=!((a+b*(c+d))*(e+f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+gh)+ijkl)'" 13 O=!((a+b*(c+d))*(e+f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+fg+hi)+jkl)'" 13 O=!((a+b*(c+d))*(e+f*g+h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+fg+hi)+jklm)'" 14 O=!((a+b*(c+d))*(e+f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh+ij)+klm)'" 14 O=!((a+b*(c+d))*(e*f+g*h+i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(ef+gh+ij)+klmn)'" 15 O=!((a+b*(c+d))*(e*f+g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+de))(f+g+h)+ijk)'" 12 O=!((a+b*(c+d*e))*(f+g+h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+de))(f+g+h)+ijkl)'" 13 O=!((a+b*(c+d*e))*(f+g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+ef))(g+h+i)+jkl)'" 13 O=!((a+b*(c*d+e*f))*(g+h+i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(cd+ef))(g+h+i)+jklm)'" 14 O=!((a+b*(c*d+e*f))*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+(g+h)(i+j))+klm)'" 14 O=!((a+(b+c)*(d+e))*(f+(g+h)*(i+j))+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+(g+h)(i+j))+klmn)'" 15 O=!((a+(b+c)*(d+e))*(f+(g+h)*(i+j))+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi)+jkl)'" 13 O=!((a+(b+c)*(d+e))*(f*g+h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi)+jklm)'" 14 O=!((a+(b+c)*(d+e))*(f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+h(i+j))+klm)'" 14 O=!((a+(b+c)*(d+e))*(f*g+h*(i+j))+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+h(i+j))+klmn)'" 15 O=!((a+(b+c)*(d+e))*(f*g+h*(i+j))+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+(h+i)(j+k))+lmn)'" 15 O=!((a+(b+c)*(d+e))*(f*g+(h+i)*(j+k))+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+(h+i)(j+k))+lmno)'" 16 O=!((a+(b+c)*(d+e))*(f*g+(h+i)*(j+k))+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h)+ijk)'" 12 O=!((a+(b+c)*(d+e))*(f+g+h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h)+ijkl)'" 13 O=!((a+(b+c)*(d+e))*(f+g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+hi)+jkl)'" 13 O=!((a+(b+c)*(d+e))*(f+g+h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+hi)+jklm)'" 14 O=!((a+(b+c)*(d+e))*(f+g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+gh+ij)+klm)'" 14 O=!((a+(b+c)*(d+e))*(f+g*h+i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+gh+ij)+klmn)'" 15 O=!((a+(b+c)*(d+e))*(f+g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi+jk)+lmn)'" 15 O=!((a+(b+c)*(d+e))*(f*g+h*i+j*k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(fg+hi+jk)+lmno)'" 16 O=!((a+(b+c)*(d+e))*(f*g+h*i+j*k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+ef))(g+h+i)+jkl)'" 13 O=!((a+(b+c)*(d+e*f))*(g+h+i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+ef))(g+h+i)+jklm)'" 14 O=!((a+(b+c)*(d+e*f))*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+fg))(h+i+j)+klm)'" 14 O=!((a+(b+c)*(d*e+f*g))*(h+i+j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(de+fg))(h+i+j)+klmn)'" 15 O=!((a+(b+c)*(d*e+f*g))*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd)(e+f+g)+hij)'" 11 O=!((a+b*c*d)*(e+f+g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bcd)(e+f+g)+hijk)'" 12 O=!((a+b*c*d)*(e+f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc(d+e))(f+g+h)+ijk)'" 12 O=!((a+b*c*(d+e))*(f+g+h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc(d+e))(f+g+h)+ijkl)'" 13 O=!((a+b*c*(d+e))*(f+g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d)(e+f))(g+h+i)+jkl)'" 13 O=!((a+b*(c+d)*(e+f))*(g+h+i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d)(e+f))(g+h+i)+jklm)'" 14 O=!((a+b*(c+d)*(e+f))*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e)(f+g))(h+i+j)+klm)'" 14 O=!((a+(b+c)*(d+e)*(f+g))*(h+i+j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e)(f+g))(h+i+j)+klmn)'" 15 O=!((a+(b+c)*(d+e)*(f+g))*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+(ij+kl)(mn+op))'" 17 O=!((a*b+c*d)*(e*f+g*h)+(i*j+k*l)*(m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ijk)'" 12 O=!((a*b+c*d)*(e*f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ij(k+l))'" 13 O=!((a*b+c*d)*(e*f+g*h)+i*j*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ij(k+lm))'" 14 O=!((a*b+c*d)*(e*f+g*h)+i*j*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ij(kl+mn))'" 15 O=!((a*b+c*d)*(e*f+g*h)+i*j*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+i(j+k)(l+m))'" 14 O=!((a*b+c*d)*(e*f+g*h)+i*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+i(j+k)(l+mn))'" 15 O=!((a*b+c*d)*(e*f+g*h)+i*(j+k)*(l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+i(j+k)(lm+no))'" 16 O=!((a*b+c*d)*(e*f+g*h)+i*(j+k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+(i+j)(k+l)(m+n))'" 15 O=!((a*b+c*d)*(e*f+g*h)+(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+(i+j)(k+l)(m+no))'" 16 O=!((a*b+c*d)*(e*f+g*h)+(i+j)*(k+l)*(m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+(i+j)(k+l)(mn+op))'" 17 O=!((a*b+c*d)*(e*f+g*h)+(i+j)*(k+l)*(m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ijkl)'" 13 O=!((a*b+c*d)*(e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ijk(l+m))'" 14 O=!((a*b+c*d)*(e*f+g*h)+i*j*k*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ij(k+l)(m+n))'" 15 O=!((a*b+c*d)*(e*f+g*h)+i*j*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+i(j+k)(l+m)(n+o))'" 16 O=!((a*b+c*d)*(e*f+g*h)+i*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+(i+j)(k+l)(m+n)(o+p))'" 17 O=!((a*b+c*d)*(e*f+g*h)+(i+j)*(k+l)*(m+n)*(o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+g(h+i))+jkl)'" 13 O=!((a*b+c*d)*(e*f+g*(h+i))+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+g(h+i))+jklm)'" 14 O=!((a*b+c*d)*(e*f+g*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+(g+h)(i+j))+klm)'" 14 O=!((a*b+c*d)*(e*f+(g+h)*(i+j))+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+(g+h)(i+j))+klmn)'" 15 O=!((a*b+c*d)*(e*f+(g+h)*(i+j))+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g)+hij)'" 11 O=!((a*b+c*d)*(e+f+g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g)+hijk)'" 12 O=!((a*b+c*d)*(e+f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+gh)+ijk)'" 12 O=!((a*b+c*d)*(e+f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+gh)+ijkl)'" 13 O=!((a*b+c*d)*(e+f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+fg+hi)+jkl)'" 13 O=!((a*b+c*d)*(e+f*g+h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+fg+hi)+jklm)'" 14 O=!((a*b+c*d)*(e+f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh+ij)+klm)'" 14 O=!((a*b+c*d)*(e*f+g*h+i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh+ij)+klmn)'" 15 O=!((a*b+c*d)*(e*f+g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+h(i+j))+klm)'" 14 O=!((a*b+c*(d+e))*(f*g+h*(i+j))+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+h(i+j))+klmn)'" 15 O=!((a*b+c*(d+e))*(f*g+h*(i+j))+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+(h+i)(j+k))+lmn)'" 15 O=!((a*b+c*(d+e))*(f*g+(h+i)*(j+k))+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+(h+i)(j+k))+lmno)'" 16 O=!((a*b+c*(d+e))*(f*g+(h+i)*(j+k))+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h)+ijk)'" 12 O=!((a*b+c*(d+e))*(f+g+h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h)+ijkl)'" 13 O=!((a*b+c*(d+e))*(f+g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+hi)+jkl)'" 13 O=!((a*b+c*(d+e))*(f+g+h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+hi)+jklm)'" 14 O=!((a*b+c*(d+e))*(f+g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+gh+ij)+klm)'" 14 O=!((a*b+c*(d+e))*(f+g*h+i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+gh+ij)+klmn)'" 15 O=!((a*b+c*(d+e))*(f+g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+hi+jk)+lmn)'" 15 O=!((a*b+c*(d+e))*(f*g+h*i+j*k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(fg+hi+jk)+lmno)'" 16 O=!((a*b+c*(d+e))*(f*g+h*i+j*k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+ef))(g+h+i)+jkl)'" 13 O=!((a*b+c*(d+e*f))*(g+h+i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+ef))(g+h+i)+jklm)'" 14 O=!((a*b+c*(d+e*f))*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+fg))(h+i+j)+klm)'" 14 O=!((a*b+c*(d*e+f*g))*(h+i+j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(de+fg))(h+i+j)+klmn)'" 15 O=!((a*b+c*(d*e+f*g))*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+(i+j)(k+l))+mno)'" 16 O=!((a*b+(c+d)*(e+f))*(g*h+(i+j)*(k+l))+m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+(i+j)(k+l))+mnop)'" 17 O=!((a*b+(c+d)*(e+f))*(g*h+(i+j)*(k+l))+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i)+jkl)'" 13 O=!((a*b+(c+d)*(e+f))*(g+h+i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i)+jklm)'" 14 O=!((a*b+(c+d)*(e+f))*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+ij)+klm)'" 14 O=!((a*b+(c+d)*(e+f))*(g+h+i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+ij)+klmn)'" 15 O=!((a*b+(c+d)*(e+f))*(g+h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+hi+jk)+lmn)'" 15 O=!((a*b+(c+d)*(e+f))*(g+h*i+j*k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+hi+jk)+lmno)'" 16 O=!((a*b+(c+d)*(e+f))*(g+h*i+j*k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+ij+kl)+mno)'" 16 O=!((a*b+(c+d)*(e+f))*(g*h+i*j+k*l)+m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(gh+ij+kl)+mnop)'" 17 O=!((a*b+(c+d)*(e+f))*(g*h+i*j+k*l)+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+fg))(h+i+j)+klm)'" 14 O=!((a*b+(c+d)*(e+f*g))*(h+i+j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+fg))(h+i+j)+klmn)'" 15 O=!((a*b+(c+d)*(e+f*g))*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+gh))(i+j+k)+lmn)'" 15 O=!((a*b+(c+d)*(e*f+g*h))*(i+j+k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(ef+gh))(i+j+k)+lmno)'" 16 O=!((a*b+(c+d)*(e*f+g*h))*(i+j+k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde)(f+g+h)+ijk)'" 12 O=!((a*b+c*d*e)*(f+g+h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cde)(f+g+h)+ijkl)'" 13 O=!((a*b+c*d*e)*(f+g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd(e+f))(g+h+i)+jkl)'" 13 O=!((a*b+c*d*(e+f))*(g+h+i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd(e+f))(g+h+i)+jklm)'" 14 O=!((a*b+c*d*(e+f))*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e)(f+g))(h+i+j)+klm)'" 14 O=!((a*b+c*(d+e)*(f+g))*(h+i+j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e)(f+g))(h+i+j)+klmn)'" 15 O=!((a*b+c*(d+e)*(f+g))*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f)(g+h))(i+j+k)+lmn)'" 15 O=!((a*b+(c+d)*(e+f)*(g+h))*(i+j+k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f)(g+h))(i+j+k)+lmno)'" 16 O=!((a*b+(c+d)*(e+f)*(g+h))*(i+j+k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+def)(g+h+i)+jkl)'" 13 O=!((a*(b+c)+d*e*f)*(g+h+i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+c)+def)(g+h+i)+jklm)'" 14 O=!((a*(b+c)+d*e*f)*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+efg)(h+i+j)+klm)'" 14 O=!((a*(b+c*d)+e*f*g)*(h+i+j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(b+cd)+efg)(h+i+j)+klmn)'" 15 O=!((a*(b+c*d)+e*f*g)*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+fgh)(i+j+k)+lmn)'" 15 O=!((a*(b*c+d*e)+f*g*h)*(i+j+k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a(bc+de)+fgh)(i+j+k)+lmno)'" 16 O=!((a*(b*c+d*e)+f*g*h)*(i+j+k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+efg)(h+i+j)+klm)'" 14 O=!(((a+b)*(c+d)+e*f*g)*(h+i+j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+d)+efg)(h+i+j)+klmn)'" 15 O=!(((a+b)*(c+d)+e*f*g)*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+fgh)(i+j+k)+lmn)'" 15 O=!(((a+b)*(c+d*e)+f*g*h)*(i+j+k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(c+de)+fgh)(i+j+k)+lmno)'" 16 O=!(((a+b)*(c+d*e)+f*g*h)*(i+j+k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+ghi)(j+k+l)+mno)'" 16 O=!(((a+b)*(c*d+e*f)+g*h*i)*(j+k+l)+m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(((a+b)(cd+ef)+ghi)(j+k+l)+mnop)'" 17 O=!(((a+b)*(c*d+e*f)+g*h*i)*(j+k+l)+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def)(g+h+i)+jkl)'" 13 O=!((a*b*c+d*e*f)*(g+h+i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+def)(g+h+i)+jklm)'" 14 O=!((a*b*c+d*e*f)*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+de(f+g))(h+i+j)+klm)'" 14 O=!((a*b*c+d*e*(f+g))*(h+i+j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+de(f+g))(h+i+j)+klmn)'" 15 O=!((a*b*c+d*e*(f+g))*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+d(e+f)(g+h))(i+j+k)+lmn)'" 15 O=!((a*b*c+d*(e+f)*(g+h))*(i+j+k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+d(e+f)(g+h))(i+j+k)+lmno)'" 16 O=!((a*b*c+d*(e+f)*(g+h))*(i+j+k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e)(f+g)(h+i))(j+k+l)+mno)'" 16 O=!((a*b*c+(d+e)*(f+g)*(h+i))*(j+k+l)+m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((abc+(d+e)(f+g)(h+i))(j+k+l)+mnop)'" 17 O=!((a*b*c+(d+e)*(f+g)*(h+i))*(j+k+l)+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)+ghi)'" 10 O=!((a+b+c)*(d+e+f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)+ghij)'" 11 O=!((a+b+c)*(d+e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg)+hij)'" 11 O=!((a+b+c)*(d+e+f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fg)+hijk)'" 12 O=!((a+b+c)*(d+e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fgh)+ijk)'" 12 O=!((a+b+c)*(d+e+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+fgh)+ijkl)'" 13 O=!((a+b+c)*(d+e+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh)+ijk)'" 12 O=!((a+b+c)*(d+e*f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+gh)+ijkl)'" 13 O=!((a+b+c)*(d+e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+ghi)+jkl)'" 13 O=!((a+b+c)*(d+e*f+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+ef+ghi)+jklm)'" 14 O=!((a+b+c)*(d+e*f+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+efg+hij)+klm)'" 14 O=!((a+b+c)*(d+e*f*g+h*i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+efg+hij)+klmn)'" 15 O=!((a+b+c)*(d+e*f*g+h*i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi)+jkl)'" 13 O=!((a+b+c)*(d*e+f*g+h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hi)+jklm)'" 14 O=!((a+b+c)*(d*e+f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hij)+klm)'" 14 O=!((a+b+c)*(d*e+f*g+h*i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fg+hij)+klmn)'" 15 O=!((a+b+c)*(d*e+f*g+h*i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fgh+ijk)+lmn)'" 15 O=!((a+b+c)*(d*e+f*g*h+i*j*k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(de+fgh+ijk)+lmno)'" 16 O=!((a+b+c)*(d*e+f*g*h+i*j*k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(def+ghi+jkl)+mno)'" 16 O=!((a+b+c)*(d*e*f+g*h*i+j*k*l)+m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(def+ghi+jkl)+mnop)'" 17 O=!((a+b+c)*(d*e*f+g*h*i+j*k*l)+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+gh)+ijk)'" 12 O=!((a+b+c*d)*(e+f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+f+gh)+ijkl)'" 13 O=!((a+b+c*d)*(e+f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+fg+hi)+jkl)'" 13 O=!((a+b+c*d)*(e+f*g+h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(e+fg+hi)+jklm)'" 14 O=!((a+b+c*d)*(e+f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(ef+gh+ij)+klm)'" 14 O=!((a+b+c*d)*(e*f+g*h+i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+cd)(ef+gh+ij)+klmn)'" 15 O=!((a+b+c*d)*(e*f+g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+gh+ij)+klm)'" 14 O=!((a+b*c+d*e)*(f+g*h+i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(f+gh+ij)+klmn)'" 15 O=!((a+b*c+d*e)*(f+g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(fg+hi+jk)+lmn)'" 15 O=!((a+b*c+d*e)*(f*g+h*i+j*k)+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc+de)(fg+hi+jk)+lmno)'" 16 O=!((a+b*c+d*e)*(f*g+h*i+j*k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(gh+ij+kl)+mno)'" 16 O=!((a*b+c*d+e*f)*(g*h+i*j+k*l)+m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd+ef)(gh+ij+kl)+mnop)'" 17 O=!((a*b+c*d+e*f)*(g*h+i*j+k*l)+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def)'" 7 O=!(a*b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g))'" 8 O=!(a*b*c+d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+gh))'" 9 O=!(a*b*c+d*e*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g(h+i)))'" 10 O=!(a*b*c+d*e*(f+g*(h+i))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+(g+h)(i+j)))'" 11 O=!(a*b*c+d*e*(f+(g+h)*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(fg+hi))'" 10 O=!(a*b*c+d*e*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(fg+h(i+j)))'" 11 O=!(a*b*c+d*e*(f*g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(fg+(h+i)(j+k)))'" 12 O=!(a*b*c+d*e*(f*g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g+h))'" 9 O=!(a*b*c+d*e*(f+g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g+hi))'" 10 O=!(a*b*c+d*e*(f+g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+gh+ij))'" 11 O=!(a*b*c+d*e*(f+g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(fg+hi+jk))'" 12 O=!(a*b*c+d*e*(f*g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h))'" 9 O=!(a*b*c+d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+hi))'" 10 O=!(a*b*c+d*(e+f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h(i+j)))'" 11 O=!(a*b*c+d*(e+f)*(g+h*(i+j))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+(h+i)(j+k)))'" 12 O=!(a*b*c+d*(e+f)*(g+(h+i)*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(gh+ij))'" 11 O=!(a*b*c+d*(e+f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(gh+i(j+k)))'" 12 O=!(a*b*c+d*(e+f)*(g*h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(gh+(i+j)(k+l)))'" 13 O=!(a*b*c+d*(e+f)*(g*h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h+i))'" 10 O=!(a*b*c+d*(e+f)*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h+ij))'" 11 O=!(a*b*c+d*(e+f)*(g+h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+hi+jk))'" 12 O=!(a*b*c+d*(e+f)*(g+h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(gh+ij+kl))'" 13 O=!(a*b*c+d*(e+f)*(g*h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+fg)(h+i+j))'" 11 O=!(a*b*c+d*(e+f*g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f(g+h))(i+j+k))'" 12 O=!(a*b*c+d*(e+f*(g+h))*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+(f+g)(h+i))(j+k+l))'" 13 O=!(a*b*c+d*(e+(f+g)*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(ef+gh)(i+j+k))'" 12 O=!(a*b*c+d*(e*f+g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(ef+g(h+i))(j+k+l))'" 13 O=!(a*b*c+d*(e*f+g*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(ef+(g+h)(i+j))(k+l+m))'" 14 O=!(a*b*c+d*(e*f+(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f+g)(h+i+j))'" 11 O=!(a*b*c+d*(e+f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f+g)(h+i+jk))'" 12 O=!(a*b*c+d*(e+f+g)*(h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f+g)(h+ij+kl))'" 13 O=!(a*b*c+d*(e+f+g)*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f+g)(hi+jk+lm))'" 14 O=!(a*b*c+d*(e+f+g)*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i))'" 10 O=!(a*b*c+(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+ij))'" 11 O=!(a*b*c+(d+e)*(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i(j+k)))'" 12 O=!(a*b*c+(d+e)*(f+g)*(h+i*(j+k))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+(i+j)(k+l)))'" 13 O=!(a*b*c+(d+e)*(f+g)*(h+(i+j)*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(hi+jk))'" 12 O=!(a*b*c+(d+e)*(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(hi+j(k+l)))'" 13 O=!(a*b*c+(d+e)*(f+g)*(h*i+j*(k+l))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(hi+(j+k)(l+m)))'" 14 O=!(a*b*c+(d+e)*(f+g)*(h*i+(j+k)*(l+m))); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i+j))'" 11 O=!(a*b*c+(d+e)*(f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i+jk))'" 12 O=!(a*b*c+(d+e)*(f+g)*(h+i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+ij+kl))'" 13 O=!(a*b*c+(d+e)*(f+g)*(h+i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(hi+jk+lm))'" 14 O=!(a*b*c+(d+e)*(f+g)*(h*i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+gh)(i+j+k))'" 12 O=!(a*b*c+(d+e)*(f+g*h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g(h+i))(j+k+l))'" 13 O=!(a*b*c+(d+e)*(f+g*(h+i))*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+(g+h)(i+j))(k+l+m))'" 14 O=!(a*b*c+(d+e)*(f+(g+h)*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(fg+hi)(j+k+l))'" 13 O=!(a*b*c+(d+e)*(f*g+h*i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(fg+h(i+j))(k+l+m))'" 14 O=!(a*b*c+(d+e)*(f*g+h*(i+j))*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(fg+(h+i)(j+k))(l+m+n))'" 15 O=!(a*b*c+(d+e)*(f*g+(h+i)*(j+k))*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g+h)(i+j+k))'" 12 O=!(a*b*c+(d+e)*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g+h)(i+j+kl))'" 13 O=!(a*b*c+(d+e)*(f+g+h)*(i+j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g+h)(i+jk+lm))'" 14 O=!(a*b*c+(d+e)*(f+g+h)*(i+j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g+h)(ij+kl+mn))'" 15 O=!(a*b*c+(d+e)*(f+g+h)*(i*j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+ef)(g+h+i)(j+k+l))'" 13 O=!(a*b*c+(d+e*f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e(f+g))(h+i+j)(k+l+m))'" 14 O=!(a*b*c+(d+e*(f+g))*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+(e+f)(g+h))(i+j+k)(l+m+n))'" 15 O=!(a*b*c+(d+(e+f)*(g+h))*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(de+fg)(h+i+j)(k+l+m))'" 14 O=!(a*b*c+(d*e+f*g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(de+f(g+h))(i+j+k)(l+m+n))'" 15 O=!(a*b*c+(d*e+f*(g+h))*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(de+(f+g)(h+i))(j+k+l)(m+n+o))'" 16 O=!(a*b*c+(d*e+(f+g)*(h+i))*(j+k+l)*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e+f)(g+h+i)(j+k+l))'" 13 O=!(a*b*c+(d+e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e+f)(g+h+i)(j+k+lm))'" 14 O=!(a*b*c+(d+e+f)*(g+h+i)*(j+k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e+f)(g+h+i)(j+kl+mn))'" 15 O=!(a*b*c+(d+e+f)*(g+h+i)*(j+k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e+f)(g+h+i)(jk+lm+no))'" 16 O=!(a*b*c+(d+e+f)*(g+h+i)*(j*k+l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg)'" 8 O=!(a*b*c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def(g+h))'" 9 O=!(a*b*c+d*e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def(g+h+i))'" 10 O=!(a*b*c+d*e*f*(g+h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g)(h+i))'" 10 O=!(a*b*c+d*e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g)(h+i+j))'" 11 O=!(a*b*c+d*e*(f+g)*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g+h)(i+j+k))'" 12 O=!(a*b*c+d*e*(f+g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h)(i+j))'" 11 O=!(a*b*c+d*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h)(i+j+k))'" 12 O=!(a*b*c+d*(e+f)*(g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h+i)(j+k+l))'" 13 O=!(a*b*c+d*(e+f)*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f+g)(h+i+j)(k+l+m))'" 14 O=!(a*b*c+d*(e+f+g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i)(j+k))'" 12 O=!(a*b*c+(d+e)*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i)(j+k+l))'" 13 O=!(a*b*c+(d+e)*(f+g)*(h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i+j)(k+l+m))'" 14 O=!(a*b*c+(d+e)*(f+g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g+h)(i+j+k)(l+m+n))'" 15 O=!(a*b*c+(d+e)*(f+g+h)*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e+f)(g+h+i)(j+k+l)(m+n+o))'" 16 O=!(a*b*c+(d+e+f)*(g+h+i)*(j+k+l)*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+ef(g+h))'" 9 O=!(a*b*(c+d)+e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+ef(g+hi))'" 10 O=!(a*b*(c+d)+e*f*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+ef(gh+ij))'" 11 O=!(a*b*(c+d)+e*f*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+e(f+g)(h+i))'" 10 O=!(a*b*(c+d)+e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+e(f+g)(h+ij))'" 11 O=!(a*b*(c+d)+e*(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+e(f+g)(hi+jk))'" 12 O=!(a*b*(c+d)+e*(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+(e+f)(g+h)(i+j))'" 11 O=!(a*b*(c+d)+(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+(e+f)(g+h)(i+jk))'" 12 O=!(a*b*(c+d)+(e+f)*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+(e+f)(g+h)(ij+kl))'" 13 O=!(a*b*(c+d)+(e+f)*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+efgh)'" 9 O=!(a*b*(c+d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+efg(h+i))'" 10 O=!(a*b*(c+d)+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+ef(g+h)(i+j))'" 11 O=!(a*b*(c+d)+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+e(f+g)(h+i)(j+k))'" 12 O=!(a*b*(c+d)+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+(e+f)(g+h)(i+j)(k+l))'" 13 O=!(a*b*(c+d)+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+fg(h+ij))'" 11 O=!(a*b*(c+d*e)+f*g*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+fg(hi+jk))'" 12 O=!(a*b*(c+d*e)+f*g*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+f(g+h)(i+j))'" 11 O=!(a*b*(c+d*e)+f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+f(g+h)(i+jk))'" 12 O=!(a*b*(c+d*e)+f*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+f(g+h)(ij+kl))'" 13 O=!(a*b*(c+d*e)+f*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+(f+g)(h+i)(j+k))'" 12 O=!(a*b*(c+d*e)+(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+(f+g)(h+i)(j+kl))'" 13 O=!(a*b*(c+d*e)+(f+g)*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+(f+g)(h+i)(jk+lm))'" 14 O=!(a*b*(c+d*e)+(f+g)*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+fghi)'" 10 O=!(a*b*(c+d*e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+fgh(i+j))'" 11 O=!(a*b*(c+d*e)+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+fg(h+i)(j+k))'" 12 O=!(a*b*(c+d*e)+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+f(g+h)(i+j)(k+l))'" 13 O=!(a*b*(c+d*e)+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a*b*(c+d*e)+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d(e+f))+ghij)'" 11 O=!(a*b*(c+d*(e+f))+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+(d+e)(f+g))+hijk)'" 12 O=!(a*b*(c+(d+e)*(f+g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+gh(ij+kl))'" 13 O=!(a*b*(c*d+e*f)+g*h*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+g(h+i)(j+k))'" 12 O=!(a*b*(c*d+e*f)+g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+g(h+i)(j+kl))'" 13 O=!(a*b*(c*d+e*f)+g*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+g(h+i)(jk+lm))'" 14 O=!(a*b*(c*d+e*f)+g*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+(g+h)(i+j)(k+l))'" 13 O=!(a*b*(c*d+e*f)+(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+(g+h)(i+j)(k+lm))'" 14 O=!(a*b*(c*d+e*f)+(g+h)*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+(g+h)(i+j)(kl+mn))'" 15 O=!(a*b*(c*d+e*f)+(g+h)*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+ghij)'" 11 O=!(a*b*(c*d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+ghi(j+k))'" 12 O=!(a*b*(c*d+e*f)+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+gh(i+j)(k+l))'" 13 O=!(a*b*(c*d+e*f)+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+g(h+i)(j+k)(l+m))'" 14 O=!(a*b*(c*d+e*f)+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+(g+h)(i+j)(k+l)(m+n))'" 15 O=!(a*b*(c*d+e*f)+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+e(f+g))+hijk)'" 12 O=!(a*b*(c*d+e*(f+g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+(e+f)(g+h))+ijkl)'" 13 O=!(a*b*(c*d+(e+f)*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+e)+fghi)'" 10 O=!(a*b*(c+d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d+ef)+ghij)'" 11 O=!(a*b*(c+d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de+fg)+hijk)'" 12 O=!(a*b*(c+d*e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef+gh)+ijkl)'" 13 O=!(a*b*(c*d+e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+f(g+h)(i+j))'" 11 O=!(a*(b+c)*(d+e)+f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+f(g+h)(i+jk))'" 12 O=!(a*(b+c)*(d+e)+f*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+f(g+h)(ij+kl))'" 13 O=!(a*(b+c)*(d+e)+f*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+(f+g)(h+i)(j+k))'" 12 O=!(a*(b+c)*(d+e)+(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+(f+g)(h+i)(j+kl))'" 13 O=!(a*(b+c)*(d+e)+(f+g)*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+(f+g)(h+i)(jk+lm))'" 14 O=!(a*(b+c)*(d+e)+(f+g)*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+fghi)'" 10 O=!(a*(b+c)*(d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+fgh(i+j))'" 11 O=!(a*(b+c)*(d+e)+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+fg(h+i)(j+k))'" 12 O=!(a*(b+c)*(d+e)+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+f(g+h)(i+j)(k+l))'" 13 O=!(a*(b+c)*(d+e)+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a*(b+c)*(d+e)+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+g(h+i)(j+kl))'" 13 O=!(a*(b+c)*(d+e*f)+g*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+g(h+i)(jk+lm))'" 14 O=!(a*(b+c)*(d+e*f)+g*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+(g+h)(i+j)(k+l))'" 13 O=!(a*(b+c)*(d+e*f)+(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+(g+h)(i+j)(k+lm))'" 14 O=!(a*(b+c)*(d+e*f)+(g+h)*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+(g+h)(i+j)(kl+mn))'" 15 O=!(a*(b+c)*(d+e*f)+(g+h)*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+ghij)'" 11 O=!(a*(b+c)*(d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+ghi(j+k))'" 12 O=!(a*(b+c)*(d+e*f)+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+gh(i+j)(k+l))'" 13 O=!(a*(b+c)*(d+e*f)+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+g(h+i)(j+k)(l+m))'" 14 O=!(a*(b+c)*(d+e*f)+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+(g+h)(i+j)(k+l)(m+n))'" 15 O=!(a*(b+c)*(d+e*f)+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e(f+g))+hijk)'" 12 O=!(a*(b+c)*(d+e*(f+g))+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+(e+f)(g+h))+ijkl)'" 13 O=!(a*(b+c)*(d+(e+f)*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+h(i+j)(kl+mn))'" 15 O=!(a*(b+c)*(d*e+f*g)+h*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+(h+i)(j+k)(l+m))'" 14 O=!(a*(b+c)*(d*e+f*g)+(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+(h+i)(j+k)(l+mn))'" 15 O=!(a*(b+c)*(d*e+f*g)+(h+i)*(j+k)*(l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+(h+i)(j+k)(lm+no))'" 16 O=!(a*(b+c)*(d*e+f*g)+(h+i)*(j+k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+hijk)'" 12 O=!(a*(b+c)*(d*e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+hij(k+l))'" 13 O=!(a*(b+c)*(d*e+f*g)+h*i*j*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+hi(j+k)(l+m))'" 14 O=!(a*(b+c)*(d*e+f*g)+h*i*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+h(i+j)(k+l)(m+n))'" 15 O=!(a*(b+c)*(d*e+f*g)+h*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+(h+i)(j+k)(l+m)(n+o))'" 16 O=!(a*(b+c)*(d*e+f*g)+(h+i)*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+f(g+h))+ijkl)'" 13 O=!(a*(b+c)*(d*e+f*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+(f+g)(h+i))+jklm)'" 14 O=!(a*(b+c)*(d*e+(f+g)*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+f)+ghij)'" 11 O=!(a*(b+c)*(d+e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e+fg)+hijk)'" 12 O=!(a*(b+c)*(d+e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef+gh)+ijkl)'" 13 O=!(a*(b+c)*(d+e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg+hi)+jklm)'" 14 O=!(a*(b+c)*(d*e+f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)(e+f+g)+hijk)'" 12 O=!(a*(b+c*d)*(e+f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c(d+e))(f+g+h)+ijkl)'" 13 O=!(a*(b+c*(d+e))*(f+g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+(c+d)(e+f))(g+h+i)+jklm)'" 14 O=!(a*(b+(c+d)*(e+f))*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)(f+g+h)+ijkl)'" 13 O=!(a*(b*c+d*e)*(f+g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+d(e+f))(g+h+i)+jklm)'" 14 O=!(a*(b*c+d*(e+f))*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+(d+e)(f+g))(h+i+j)+klmn)'" 15 O=!(a*(b*c+(d+e)*(f+g))*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+g)+hijk)'" 12 O=!(a*(b+c+d)*(e+f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+f+gh)+ijkl)'" 13 O=!(a*(b+c+d)*(e+f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(e+fg+hi)+jklm)'" 14 O=!(a*(b+c+d)*(e+f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c+d)(ef+gh+ij)+klmn)'" 15 O=!(a*(b+c+d)*(e*f+g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+(g+h)(i+j)(k+l))'" 13 O=!((a+b)*(c+d)*(e+f)+(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+(g+h)(i+j)(k+lm))'" 14 O=!((a+b)*(c+d)*(e+f)+(g+h)*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+(g+h)(i+j)(kl+mn))'" 15 O=!((a+b)*(c+d)*(e+f)+(g+h)*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+ghij)'" 11 O=!((a+b)*(c+d)*(e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+ghi(j+k))'" 12 O=!((a+b)*(c+d)*(e+f)+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+gh(i+j)(k+l))'" 13 O=!((a+b)*(c+d)*(e+f)+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+g(h+i)(j+k)(l+m))'" 14 O=!((a+b)*(c+d)*(e+f)+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+(g+h)(i+j)(k+l)(m+n))'" 15 O=!((a+b)*(c+d)*(e+f)+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg)+(h+i)(j+k)(l+mn))'" 15 O=!((a+b)*(c+d)*(e+f*g)+(h+i)*(j+k)*(l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg)+(h+i)(j+k)(lm+no))'" 16 O=!((a+b)*(c+d)*(e+f*g)+(h+i)*(j+k)*(l*m+n*o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg)+hijk)'" 12 O=!((a+b)*(c+d)*(e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg)+hij(k+l))'" 13 O=!((a+b)*(c+d)*(e+f*g)+h*i*j*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg)+hi(j+k)(l+m))'" 14 O=!((a+b)*(c+d)*(e+f*g)+h*i*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg)+h(i+j)(k+l)(m+n))'" 15 O=!((a+b)*(c+d)*(e+f*g)+h*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg)+(h+i)(j+k)(l+m)(n+o))'" 16 O=!((a+b)*(c+d)*(e+f*g)+(h+i)*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f(g+h))+ijkl)'" 13 O=!((a+b)*(c+d)*(e+f*(g+h))+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+(f+g)(h+i))+jklm)'" 14 O=!((a+b)*(c+d)*(e+(f+g)*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh)+(i+j)(k+l)(mn+op))'" 17 O=!((a+b)*(c+d)*(e*f+g*h)+(i+j)*(k+l)*(m*n+o*p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh)+ijkl)'" 13 O=!((a+b)*(c+d)*(e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh)+ijk(l+m))'" 14 O=!((a+b)*(c+d)*(e*f+g*h)+i*j*k*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh)+ij(k+l)(m+n))'" 15 O=!((a+b)*(c+d)*(e*f+g*h)+i*j*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh)+i(j+k)(l+m)(n+o))'" 16 O=!((a+b)*(c+d)*(e*f+g*h)+i*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh)+(i+j)(k+l)(m+n)(o+p))'" 17 O=!((a+b)*(c+d)*(e*f+g*h)+(i+j)*(k+l)*(m+n)*(o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+g(h+i))+jklm)'" 14 O=!((a+b)*(c+d)*(e*f+g*(h+i))+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+(g+h)(i+j))+klmn)'" 15 O=!((a+b)*(c+d)*(e*f+(g+h)*(i+j))+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+g)+hijk)'" 12 O=!((a+b)*(c+d)*(e+f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f+gh)+ijkl)'" 13 O=!((a+b)*(c+d)*(e+f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg+hi)+jklm)'" 14 O=!((a+b)*(c+d)*(e+f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh+ij)+klmn)'" 15 O=!((a+b)*(c+d)*(e*f+g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)(f+g+h)+ijkl)'" 13 O=!((a+b)*(c+d*e)*(f+g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d(e+f))(g+h+i)+jklm)'" 14 O=!((a+b)*(c+d*(e+f))*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+(d+e)(f+g))(h+i+j)+klmn)'" 15 O=!((a+b)*(c+(d+e)*(f+g))*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)(g+h+i)+jklm)'" 14 O=!((a+b)*(c*d+e*f)*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+e(f+g))(h+i+j)+klmn)'" 15 O=!((a+b)*(c*d+e*(f+g))*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+(e+f)(g+h))(i+j+k)+lmno)'" 16 O=!((a+b)*(c*d+(e+f)*(g+h))*(i+j+k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+h)+ijkl)'" 13 O=!((a+b)*(c+d+e)*(f+g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+g+hi)+jklm)'" 14 O=!((a+b)*(c+d+e)*(f+g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(f+gh+ij)+klmn)'" 15 O=!((a+b)*(c+d+e)*(f+g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d+e)(fg+hi+jk)+lmno)'" 16 O=!((a+b)*(c+d+e)*(f*g+h*i+j*k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+e+f)(g+h+i)+jklm)'" 14 O=!((a+b*c)*(d+e+f)*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b(c+d))(e+f+g)(h+i+j)+klmn)'" 15 O=!((a+b*(c+d))*(e+f+g)*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+(b+c)(d+e))(f+g+h)(i+j+k)+lmno)'" 16 O=!((a+(b+c)*(d+e))*(f+g+h)*(i+j+k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(e+f+g)(h+i+j)+klmn)'" 15 O=!((a*b+c*d)*(e+f+g)*(h+i+j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+c(d+e))(f+g+h)(i+j+k)+lmno)'" 16 O=!((a*b+c*(d+e))*(f+g+h)*(i+j+k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+(c+d)(e+f))(g+h+i)(j+k+l)+mnop)'" 17 O=!((a*b+(c+d)*(e+f))*(g+h+i)*(j+k+l)+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+i)+jklm)'" 14 O=!((a+b+c)*(d+e+f)*(g+h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+h+ij)+klmn)'" 15 O=!((a+b+c)*(d+e+f)*(g+h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(g+hi+jk)+lmno)'" 16 O=!((a+b+c)*(d+e+f)*(g+h*i+j*k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b+c)(d+e+f)(gh+ij+kl)+mnop)'" 17 O=!((a+b+c)*(d+e+f)*(g*h+i*j+k*l)+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh)'" 9 O=!(a*b*c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efg(h+i))'" 10 O=!(a*b*c*d+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efg(h+i+j))'" 11 O=!(a*b*c*d+e*f*g*(h+i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+ef(g+h)(i+j))'" 11 O=!(a*b*c*d+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+ef(g+h)(i+j+k))'" 12 O=!(a*b*c*d+e*f*(g+h)*(i+j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+ef(g+h+i)(j+k+l))'" 13 O=!(a*b*c*d+e*f*(g+h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+e(f+g)(h+i)(j+k))'" 12 O=!(a*b*c*d+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+e(f+g)(h+i)(j+k+l))'" 13 O=!(a*b*c*d+e*(f+g)*(h+i)*(j+k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+e(f+g)(h+i+j)(k+l+m))'" 14 O=!(a*b*c*d+e*(f+g)*(h+i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+e(f+g+h)(i+j+k)(l+m+n))'" 15 O=!(a*b*c*d+e*(f+g+h)*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f)(g+h)(i+j)(k+l))'" 13 O=!(a*b*c*d+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f)(g+h)(i+j)(k+l+m))'" 14 O=!(a*b*c*d+(e+f)*(g+h)*(i+j)*(k+l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f)(g+h)(i+j+k)(l+m+n))'" 15 O=!(a*b*c*d+(e+f)*(g+h)*(i+j+k)*(l+m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f)(g+h+i)(j+k+l)(m+n+o))'" 16 O=!(a*b*c*d+(e+f)*(g+h+i)*(j+k+l)*(m+n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+(e+f+g)(h+i+j)(k+l+m)(n+o+p))'" 17 O=!(a*b*c*d+(e+f+g)*(h+i+j)*(k+l+m)*(n+o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e)+fgh(i+j))'" 11 O=!(a*b*c*(d+e)+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e)+fg(h+i)(j+k))'" 12 O=!(a*b*c*(d+e)+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e)+f(g+h)(i+j)(k+l))'" 13 O=!(a*b*c*(d+e)+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc(d+e)+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a*b*c*(d+e)+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f)+gh(i+j)(k+l))'" 13 O=!(a*b*(c+d)*(e+f)+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f)+g(h+i)(j+k)(l+m))'" 14 O=!(a*b*(c+d)*(e+f)+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)(e+f)+(g+h)(i+j)(k+l)(m+n))'" 15 O=!(a*b*(c+d)*(e+f)+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g)+h(i+j)(k+l)(m+n))'" 15 O=!(a*(b+c)*(d+e)*(f+g)+h*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)(f+g)+(h+i)(j+k)(l+m)(n+o))'" 16 O=!(a*(b+c)*(d+e)*(f+g)+(h+i)*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)(g+h)+(i+j)(k+l)(m+n)(o+p))'" 17 O=!((a+b)*(c+d)*(e+f)*(g+h)+(i+j)*(k+l)*(m+n)*(o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c)'" 4 O=!(a+b+c); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd)'" 5 O=!(a+b+c*d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(d+e))'" 6 O=!(a+b+c*(d+e)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(d+ef))'" 7 O=!(a+b+c*(d+e*f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(d+efg))'" 8 O=!(a+b+c*(d+e*f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(de+fg))'" 8 O=!(a+b+c*(d*e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(de+fgh))'" 9 O=!(a+b+c*(d*e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(def+ghi))'" 10 O=!(a+b+c*(d*e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(e+f))'" 7 O=!(a+b+(c+d)*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(e+fg))'" 8 O=!(a+b+(c+d)*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(e+fgh))'" 9 O=!(a+b+(c+d)*(e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(ef+gh))'" 9 O=!(a+b+(c+d)*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(ef+ghi))'" 10 O=!(a+b+(c+d)*(e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(efg+hij))'" 11 O=!(a+b+(c+d)*(e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+de)(f+gh))'" 9 O=!(a+b+(c+d*e)*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+de)(fg+hi))'" 10 O=!(a+b+(c+d*e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(cd+ef)(gh+ij))'" 11 O=!(a+b+(c*d+e*f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde)'" 6 O=!(a+b+c*d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd(e+f))'" 7 O=!(a+b+c*d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd(e+fg))'" 8 O=!(a+b+c*d*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd(ef+gh))'" 9 O=!(a+b+c*d*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(d+e)(f+g))'" 8 O=!(a+b+c*(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(d+e)(f+gh))'" 9 O=!(a+b+c*(d+e)*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(d+e)(fg+hi))'" 10 O=!(a+b+c*(d+e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(e+f)(g+h))'" 9 O=!(a+b+(c+d)*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(e+f)(g+hi))'" 10 O=!(a+b+(c+d)*(e+f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(e+f)(gh+ij))'" 11 O=!(a+b+(c+d)*(e+f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cdef)'" 7 O=!(a+b+c*d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde(f+g))'" 8 O=!(a+b+c*d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd(e+f)(g+h))'" 9 O=!(a+b+c*d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c(d+e)(f+g)(h+i))'" 10 O=!(a+b+c*(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+(c+d)(e+f)(g+h)(i+j))'" 11 O=!(a+b+(c+d)*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de)'" 6 O=!(a+b*c+d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(e+f))'" 7 O=!(a+b*c+d*(e+f)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(e+fg))'" 8 O=!(a+b*c+d*(e+f*g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(e+fgh))'" 9 O=!(a+b*c+d*(e+f*g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(ef+gh))'" 9 O=!(a+b*c+d*(e*f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(ef+ghi))'" 10 O=!(a+b*c+d*(e*f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(efg+hij))'" 11 O=!(a+b*c+d*(e*f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(f+g))'" 8 O=!(a+b*c+(d+e)*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(f+gh))'" 9 O=!(a+b*c+(d+e)*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(f+ghi))'" 10 O=!(a+b*c+(d+e)*(f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(fg+hi))'" 10 O=!(a+b*c+(d+e)*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(fg+hij))'" 11 O=!(a+b*c+(d+e)*(f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(fgh+ijk))'" 12 O=!(a+b*c+(d+e)*(f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+ef)(g+hi))'" 10 O=!(a+b*c+(d+e*f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+ef)(gh+ij))'" 11 O=!(a+b*c+(d+e*f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(de+fg)(hi+jk))'" 12 O=!(a+b*c+(d*e+f*g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def)'" 7 O=!(a+b*c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de(f+g))'" 8 O=!(a+b*c+d*e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de(f+gh))'" 9 O=!(a+b*c+d*e*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de(fg+hi))'" 10 O=!(a+b*c+d*e*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(e+f)(g+h))'" 9 O=!(a+b*c+d*(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(e+f)(g+hi))'" 10 O=!(a+b*c+d*(e+f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(e+f)(gh+ij))'" 11 O=!(a+b*c+d*(e+f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(f+g)(h+i))'" 10 O=!(a+b*c+(d+e)*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(f+g)(h+ij))'" 11 O=!(a+b*c+(d+e)*(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(f+g)(hi+jk))'" 12 O=!(a+b*c+(d+e)*(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+defg)'" 8 O=!(a+b*c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def(g+h))'" 9 O=!(a+b*c+d*e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de(f+g)(h+i))'" 10 O=!(a+b*c+d*e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+d(e+f)(g+h)(i+j))'" 11 O=!(a+b*c+d*(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+(d+e)(f+g)(h+i)(j+k))'" 12 O=!(a+b*c+(d+e)*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)+efg)'" 8 O=!(a+b*(c+d)+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)+efgh)'" 9 O=!(a+b*(c+d)+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+de)+fgh)'" 9 O=!(a+b*(c+d*e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+de)+fghi)'" 10 O=!(a+b*(c+d*e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+def)+ghi)'" 10 O=!(a+b*(c+d*e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+def)+ghij)'" 11 O=!(a+b*(c+d*e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+ef)+ghi)'" 10 O=!(a+b*(c*d+e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+ef)+ghij)'" 11 O=!(a+b*(c*d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+efg)+hij)'" 11 O=!(a+b*(c*d+e*f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cd+efg)+hijk)'" 12 O=!(a+b*(c*d+e*f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cde+fgh)+ijk)'" 12 O=!(a+b*(c*d*e+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(cde+fgh)+ijkl)'" 13 O=!(a+b*(c*d*e+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)+fgh)'" 9 O=!(a+(b+c)*(d+e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)+fghi)'" 10 O=!(a+(b+c)*(d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+ef)+ghi)'" 10 O=!(a+(b+c)*(d+e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+ef)+ghij)'" 11 O=!(a+(b+c)*(d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+efg)+hij)'" 11 O=!(a+(b+c)*(d+e*f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+efg)+hijk)'" 12 O=!(a+(b+c)*(d+e*f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fg)+hij)'" 11 O=!(a+(b+c)*(d*e+f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fg)+hijk)'" 12 O=!(a+(b+c)*(d*e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fgh)+ijk)'" 12 O=!(a+(b+c)*(d*e+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(de+fgh)+ijkl)'" 13 O=!(a+(b+c)*(d*e+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(def+ghi)+jkl)'" 13 O=!(a+(b+c)*(d*e*f+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(def+ghi)+jklm)'" 14 O=!(a+(b+c)*(d*e*f+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(e+fg)+hij)'" 11 O=!(a+(b+c*d)*(e+f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(e+fg)+hijk)'" 12 O=!(a+(b+c*d)*(e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(ef+gh)+ijk)'" 12 O=!(a+(b+c*d)*(e*f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+cd)(ef+gh)+ijkl)'" 13 O=!(a+(b+c*d)*(e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(fg+hi)+jkl)'" 13 O=!(a+(b*c+d*e)*(f*g+h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(bc+de)(fg+hi)+jklm)'" 14 O=!(a+(b*c+d*e)*(f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg)'" 8 O=!(a+b*c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+ef(g+h))'" 9 O=!(a+b*c*d+e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+ef(g+hi))'" 10 O=!(a+b*c*d+e*f*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+ef(gh+ij))'" 11 O=!(a+b*c*d+e*f*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+e(f+g)(h+i))'" 10 O=!(a+b*c*d+e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+e(f+g)(h+ij))'" 11 O=!(a+b*c*d+e*(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+e(f+g)(hi+jk))'" 12 O=!(a+b*c*d+e*(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+(e+f)(g+h)(i+j))'" 11 O=!(a+b*c*d+(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+(e+f)(g+h)(i+jk))'" 12 O=!(a+b*c*d+(e+f)*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+(e+f)(g+h)(ij+kl))'" 13 O=!(a+b*c*d+(e+f)*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efgh)'" 9 O=!(a+b*c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg(h+i))'" 10 O=!(a+b*c*d+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+ef(g+h)(i+j))'" 11 O=!(a+b*c*d+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+e(f+g)(h+i)(j+k))'" 12 O=!(a+b*c*d+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+(e+f)(g+h)(i+j)(k+l))'" 13 O=!(a+b*c*d+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+e)+fghi)'" 10 O=!(a+b*c*(d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(d+ef)+ghij)'" 11 O=!(a+b*c*(d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc(de+fg)+hijk)'" 12 O=!(a+b*c*(d*e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+f)+ghij)'" 11 O=!(a+b*(c+d)*(e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(e+fg)+hijk)'" 12 O=!(a+b*(c+d)*(e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b(c+d)(ef+gh)+ijkl)'" 13 O=!(a+b*(c+d)*(e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+g)+hijk)'" 12 O=!(a+(b+c)*(d+e)*(f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(f+gh)+ijkl)'" 13 O=!(a+(b+c)*(d+e)*(f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+(b+c)(d+e)(fg+hi)+jklm)'" 14 O=!(a+(b+c)*(d+e)*(f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fghi)'" 10 O=!(a+b*c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fgh(i+j))'" 11 O=!(a+b*c*d*e+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fg(h+i)(j+k))'" 12 O=!(a+b*c*d*e+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+f(g+h)(i+j)(k+l))'" 13 O=!(a+b*c*d*e+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a+b*c*d*e+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef)'" 7 O=!(a*b+c*d+e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(f+g))'" 8 O=!(a*b+c*d+e*(f+g)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(f+gh))'" 9 O=!(a*b+c*d+e*(f+g*h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(f+ghi))'" 10 O=!(a*b+c*d+e*(f+g*h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(fg+hi))'" 10 O=!(a*b+c*d+e*(f*g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(fg+hij))'" 11 O=!(a*b+c*d+e*(f*g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(fgh+ijk))'" 12 O=!(a*b+c*d+e*(f*g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(g+h))'" 9 O=!(a*b+c*d+(e+f)*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(g+hi))'" 10 O=!(a*b+c*d+(e+f)*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(g+hij))'" 11 O=!(a*b+c*d+(e+f)*(g+h*i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(gh+ij))'" 11 O=!(a*b+c*d+(e+f)*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(gh+ijk))'" 12 O=!(a*b+c*d+(e+f)*(g*h+i*j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(ghi+jkl))'" 13 O=!(a*b+c*d+(e+f)*(g*h*i+j*k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+fg)(h+ij))'" 11 O=!(a*b+c*d+(e+f*g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+fg)(hi+jk))'" 12 O=!(a*b+c*d+(e+f*g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(ef+gh)(ij+kl))'" 13 O=!(a*b+c*d+(e*f+g*h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg)'" 8 O=!(a*b+c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef(g+h))'" 9 O=!(a*b+c*d+e*f*(g+h)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef(g+hi))'" 10 O=!(a*b+c*d+e*f*(g+h*i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef(gh+ij))'" 11 O=!(a*b+c*d+e*f*(g*h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(f+g)(h+i))'" 10 O=!(a*b+c*d+e*(f+g)*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(f+g)(h+ij))'" 11 O=!(a*b+c*d+e*(f+g)*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(f+g)(hi+jk))'" 12 O=!(a*b+c*d+e*(f+g)*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(g+h)(i+j))'" 11 O=!(a*b+c*d+(e+f)*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(g+h)(i+jk))'" 12 O=!(a*b+c*d+(e+f)*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(g+h)(ij+kl))'" 13 O=!(a*b+c*d+(e+f)*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efgh)'" 9 O=!(a*b+c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg(h+i))'" 10 O=!(a*b+c*d+e*f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef(g+h)(i+j))'" 11 O=!(a*b+c*d+e*f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+e(f+g)(h+i)(j+k))'" 12 O=!(a*b+c*d+e*(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+(e+f)(g+h)(i+j)(k+l))'" 13 O=!(a*b+c*d+(e+f)*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)+fgh)'" 9 O=!(a*b+c*(d+e)+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)+fghi)'" 10 O=!(a*b+c*(d+e)+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+ef)+ghi)'" 10 O=!(a*b+c*(d+e*f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+ef)+ghij)'" 11 O=!(a*b+c*(d+e*f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+efg)+hij)'" 11 O=!(a*b+c*(d+e*f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+efg)+hijk)'" 12 O=!(a*b+c*(d+e*f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fg)+hij)'" 11 O=!(a*b+c*(d*e+f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fg)+hijk)'" 12 O=!(a*b+c*(d*e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fgh)+ijk)'" 12 O=!(a*b+c*(d*e+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(de+fgh)+ijkl)'" 13 O=!(a*b+c*(d*e+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(def+ghi)+jkl)'" 13 O=!(a*b+c*(d*e*f+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(def+ghi)+jklm)'" 14 O=!(a*b+c*(d*e*f+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)+ghi)'" 10 O=!(a*b+(c+d)*(e+f)+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)+ghij)'" 11 O=!(a*b+(c+d)*(e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fg)+hij)'" 11 O=!(a*b+(c+d)*(e+f*g)+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fg)+hijk)'" 12 O=!(a*b+(c+d)*(e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fgh)+ijk)'" 12 O=!(a*b+(c+d)*(e+f*g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+fgh)+ijkl)'" 13 O=!(a*b+(c+d)*(e+f*g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+gh)+ijk)'" 12 O=!(a*b+(c+d)*(e*f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+gh)+ijkl)'" 13 O=!(a*b+(c+d)*(e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+ghi)+jkl)'" 13 O=!(a*b+(c+d)*(e*f+g*h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(ef+ghi)+jklm)'" 14 O=!(a*b+(c+d)*(e*f+g*h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(efg+hij)+klm)'" 14 O=!(a*b+(c+d)*(e*f*g+h*i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(efg+hij)+klmn)'" 15 O=!(a*b+(c+d)*(e*f*g+h*i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(f+gh)+ijk)'" 12 O=!(a*b+(c+d*e)*(f+g*h)+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(f+gh)+ijkl)'" 13 O=!(a*b+(c+d*e)*(f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(fg+hi)+jkl)'" 13 O=!(a*b+(c+d*e)*(f*g+h*i)+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+de)(fg+hi)+jklm)'" 14 O=!(a*b+(c+d*e)*(f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(gh+ij)+klm)'" 14 O=!(a*b+(c*d+e*f)*(g*h+i*j)+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(cd+ef)(gh+ij)+klmn)'" 15 O=!(a*b+(c*d+e*f)*(g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh)'" 9 O=!(a*b+c*d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fg(h+i))'" 10 O=!(a*b+c*d*e+f*g*(h+i)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fg(h+ij))'" 11 O=!(a*b+c*d*e+f*g*(h+i*j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fg(hi+jk))'" 12 O=!(a*b+c*d*e+f*g*(h*i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+f(g+h)(i+j))'" 11 O=!(a*b+c*d*e+f*(g+h)*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+f(g+h)(i+jk))'" 12 O=!(a*b+c*d*e+f*(g+h)*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+f(g+h)(ij+kl))'" 13 O=!(a*b+c*d*e+f*(g+h)*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+(f+g)(h+i)(j+k))'" 12 O=!(a*b+c*d*e+(f+g)*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+(f+g)(h+i)(j+kl))'" 13 O=!(a*b+c*d*e+(f+g)*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+(f+g)(h+i)(jk+lm))'" 14 O=!(a*b+c*d*e+(f+g)*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fghi)'" 10 O=!(a*b+c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh(i+j))'" 11 O=!(a*b+c*d*e+f*g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fg(h+i)(j+k))'" 12 O=!(a*b+c*d*e+f*g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+f(g+h)(i+j)(k+l))'" 13 O=!(a*b+c*d*e+f*(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+(f+g)(h+i)(j+k)(l+m))'" 14 O=!(a*b+c*d*e+(f+g)*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+f)+ghij)'" 11 O=!(a*b+c*d*(e+f)+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(e+fg)+hijk)'" 12 O=!(a*b+c*d*(e+f*g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd(ef+gh)+ijkl)'" 13 O=!(a*b+c*d*(e*f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+g)+hijk)'" 12 O=!(a*b+c*(d+e)*(f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(f+gh)+ijkl)'" 13 O=!(a*b+c*(d+e)*(f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+c(d+e)(fg+hi)+jklm)'" 14 O=!(a*b+c*(d+e)*(f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+h)+ijkl)'" 13 O=!(a*b+(c+d)*(e+f)*(g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(g+hi)+jklm)'" 14 O=!(a*b+(c+d)*(e+f)*(g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+(c+d)(e+f)(gh+ij)+klmn)'" 15 O=!(a*b+(c+d)*(e+f)*(g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+ghij)'" 11 O=!(a*b+c*d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+ghi(j+k))'" 12 O=!(a*b+c*d*e*f+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+gh(i+j)(k+l))'" 13 O=!(a*b+c*d*e*f+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+g(h+i)(j+k)(l+m))'" 14 O=!(a*b+c*d*e*f+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+(g+h)(i+j)(k+l)(m+n))'" 15 O=!(a*b+c*d*e*f+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+def+ghi)'" 10 O=!(a*(b+c)+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+def+ghij)'" 11 O=!(a*(b+c)+d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)+defg+hijk)'" 12 O=!(a*(b+c)+d*e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+efg+hij)'" 11 O=!(a*(b+c*d)+e*f*g+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+efg+hijk)'" 12 O=!(a*(b+c*d)+e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cd)+efgh+ijkl)'" 13 O=!(a*(b+c*d)+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fgh+ijk)'" 12 O=!(a*(b+c*d*e)+f*g*h+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fgh+ijkl)'" 13 O=!(a*(b+c*d*e)+f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+cde)+fghi+jklm)'" 14 O=!(a*(b+c*d*e)+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fgh+ijk)'" 12 O=!(a*(b*c+d*e)+f*g*h+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fgh+ijkl)'" 13 O=!(a*(b*c+d*e)+f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+de)+fghi+jklm)'" 14 O=!(a*(b*c+d*e)+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+ghi+jkl)'" 13 O=!(a*(b*c+d*e*f)+g*h*i+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+ghi+jklm)'" 14 O=!(a*(b*c+d*e*f)+g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bc+def)+ghij+klmn)'" 15 O=!(a*(b*c+d*e*f)+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hij+klm)'" 14 O=!(a*(b*c*d+e*f*g)+h*i*j+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hij+klmn)'" 15 O=!(a*(b*c*d+e*f*g)+h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(bcd+efg)+hijk+lmno)'" 16 O=!(a*(b*c*d+e*f*g)+h*i*j*k+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efg+hij)'" 11 O=!((a+b)*(c+d)+e*f*g+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efg+hijk)'" 12 O=!((a+b)*(c+d)+e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)+efgh+ijkl)'" 13 O=!((a+b)*(c+d)+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fgh+ijk)'" 12 O=!((a+b)*(c+d*e)+f*g*h+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fgh+ijkl)'" 13 O=!((a+b)*(c+d*e)+f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+de)+fghi+jklm)'" 14 O=!((a+b)*(c+d*e)+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+ghi+jkl)'" 13 O=!((a+b)*(c+d*e*f)+g*h*i+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+ghi+jklm)'" 14 O=!((a+b)*(c+d*e*f)+g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+def)+ghij+klmn)'" 15 O=!((a+b)*(c+d*e*f)+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+ghi+jkl)'" 13 O=!((a+b)*(c*d+e*f)+g*h*i+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+ghi+jklm)'" 14 O=!((a+b)*(c*d+e*f)+g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+ef)+ghij+klmn)'" 15 O=!((a+b)*(c*d+e*f)+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hij+klm)'" 14 O=!((a+b)*(c*d+e*f*g)+h*i*j+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hij+klmn)'" 15 O=!((a+b)*(c*d+e*f*g)+h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cd+efg)+hijk+lmno)'" 16 O=!((a+b)*(c*d+e*f*g)+h*i*j*k+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ijk+lmn)'" 15 O=!((a+b)*(c*d*e+f*g*h)+i*j*k+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ijk+lmno)'" 16 O=!((a+b)*(c*d*e+f*g*h)+i*j*k+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(cde+fgh)+ijkl+mnop)'" 17 O=!((a+b)*(c*d*e+f*g*h)+i*j*k*l+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+ghi+jkl)'" 13 O=!((a+b*c)*(d+e*f)+g*h*i+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+ghi+jklm)'" 14 O=!((a+b*c)*(d+e*f)+g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(d+ef)+ghij+klmn)'" 15 O=!((a+b*c)*(d+e*f)+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hij+klm)'" 14 O=!((a+b*c)*(d*e+f*g)+h*i*j+k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hij+klmn)'" 15 O=!((a+b*c)*(d*e+f*g)+h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+bc)(de+fg)+hijk+lmno)'" 16 O=!((a+b*c)*(d*e+f*g)+h*i*j*k+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ijk+lmn)'" 15 O=!((a*b+c*d)*(e*f+g*h)+i*j*k+l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ijk+lmno)'" 16 O=!((a*b+c*d)*(e*f+g*h)+i*j*k+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((ab+cd)(ef+gh)+ijkl+mnop)'" 17 O=!((a*b+c*d)*(e*f+g*h)+i*j*k*l+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi)'" 10 O=!(a*b*c+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+gh(i+j))'" 11 O=!(a*b*c+d*e*f+g*h*(i+j)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+gh(i+jk))'" 12 O=!(a*b*c+d*e*f+g*h*(i+j*k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+gh(ij+kl))'" 13 O=!(a*b*c+d*e*f+g*h*(i*j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+g(h+i)(j+k))'" 12 O=!(a*b*c+d*e*f+g*(h+i)*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+g(h+i)(j+kl))'" 13 O=!(a*b*c+d*e*f+g*(h+i)*(j+k*l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+g(h+i)(jk+lm))'" 14 O=!(a*b*c+d*e*f+g*(h+i)*(j*k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+(g+h)(i+j)(k+l))'" 13 O=!(a*b*c+d*e*f+(g+h)*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+(g+h)(i+j)(k+lm))'" 14 O=!(a*b*c+d*e*f+(g+h)*(i+j)*(k+l*m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+(g+h)(i+j)(kl+mn))'" 15 O=!(a*b*c+d*e*f+(g+h)*(i+j)*(k*l+m*n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghij)'" 11 O=!(a*b*c+d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi(j+k))'" 12 O=!(a*b*c+d*e*f+g*h*i*(j+k)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+gh(i+j)(k+l))'" 13 O=!(a*b*c+d*e*f+g*h*(i+j)*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+g(h+i)(j+k)(l+m))'" 14 O=!(a*b*c+d*e*f+g*(h+i)*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+(g+h)(i+j)(k+l)(m+n))'" 15 O=!(a*b*c+d*e*f+(g+h)*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+g)+hijk)'" 12 O=!(a*b*c+d*e*(f+g)+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(f+gh)+ijkl)'" 13 O=!(a*b*c+d*e*(f+g*h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+de(fg+hi)+jklm)'" 14 O=!(a*b*c+d*e*(f*g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+h)+ijkl)'" 13 O=!(a*b*c+d*(e+f)*(g+h)+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(g+hi)+jklm)'" 14 O=!(a*b*c+d*(e+f)*(g+h*i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+d(e+f)(gh+ij)+klmn)'" 15 O=!(a*b*c+d*(e+f)*(g*h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+i)+jklm)'" 14 O=!(a*b*c+(d+e)*(f+g)*(h+i)+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(h+ij)+klmn)'" 15 O=!(a*b*c+(d+e)*(f+g)*(h+i*j)+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+(d+e)(f+g)(hi+jk)+lmno)'" 16 O=!(a*b*c+(d+e)*(f+g)*(h*i+j*k)+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hijk)'" 12 O=!(a*b*c+d*e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hij(k+l))'" 13 O=!(a*b*c+d*e*f*g+h*i*j*(k+l)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hi(j+k)(l+m))'" 14 O=!(a*b*c+d*e*f*g+h*i*(j+k)*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+h(i+j)(k+l)(m+n))'" 15 O=!(a*b*c+d*e*f*g+h*(i+j)*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+(h+i)(j+k)(l+m)(n+o))'" 16 O=!(a*b*c+d*e*f*g+(h+i)*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+d)+efgh+ijkl)'" 13 O=!(a*b*(c+d)+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(c+de)+fghi+jklm)'" 14 O=!(a*b*(c+d*e)+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab(cd+ef)+ghij+klmn)'" 15 O=!(a*b*(c*d+e*f)+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+e)+fghi+jklm)'" 14 O=!(a*(b+c)*(d+e)+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(d+ef)+ghij+klmn)'" 15 O=!(a*(b+c)*(d+e*f)+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a(b+c)(de+fg)+hijk+lmno)'" 16 O=!(a*(b+c)*(d*e+f*g)+h*i*j*k+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+f)+ghij+klmn)'" 15 O=!((a+b)*(c+d)*(e+f)+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(e+fg)+hijk+lmno)'" 16 O=!((a+b)*(c+d)*(e+f*g)+h*i*j*k+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "((a+b)(c+d)(ef+gh)+ijkl+mnop)'" 17 O=!((a+b)*(c+d)*(e*f+g*h)+i*j*k*l+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ijkl)'" 13 O=!(a*b*c*d+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ijk(l+m))'" 14 O=!(a*b*c*d+e*f*g*h+i*j*k*(l+m)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ij(k+l)(m+n))'" 15 O=!(a*b*c*d+e*f*g*h+i*j*(k+l)*(m+n)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+i(j+k)(l+m)(n+o))'" 16 O=!(a*b*c*d+e*f*g*h+i*(j+k)*(l+m)*(n+o)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+(i+j)(k+l)(m+n)(o+p))'" 17 O=!(a*b*c*d+e*f*g*h+(i+j)*(k+l)*(m+n)*(o+p)); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+d)'" 5 O=!(a+b+c+d); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+de)'" 6 O=!(a+b+c+d*e); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+def)'" 7 O=!(a+b+c+d*e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+c+defg)'" 8 O=!(a+b+c+d*e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd+ef)'" 7 O=!(a+b+c*d+e*f); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd+efg)'" 8 O=!(a+b+c*d+e*f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cd+efgh)'" 9 O=!(a+b+c*d+e*f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde+fgh)'" 9 O=!(a+b+c*d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cde+fghi)'" 10 O=!(a+b+c*d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+b+cdef+ghij)'" 11 O=!(a+b+c*d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de+fg)'" 8 O=!(a+b*c+d*e+f*g); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de+fgh)'" 9 O=!(a+b*c+d*e+f*g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+de+fghi)'" 10 O=!(a+b*c+d*e+f*g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def+ghi)'" 10 O=!(a+b*c+d*e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+def+ghij)'" 11 O=!(a+b*c+d*e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bc+defg+hijk)'" 12 O=!(a+b*c+d*e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg+hij)'" 11 O=!(a+b*c*d+e*f*g+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efg+hijk)'" 12 O=!(a+b*c*d+e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcd+efgh+ijkl)'" 13 O=!(a+b*c*d+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(a+bcde+fghi+jklm)'" 14 O=!(a+b*c*d*e+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef+gh)'" 9 O=!(a*b+c*d+e*f+g*h); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef+ghi)'" 10 O=!(a*b+c*d+e*f+g*h*i); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+ef+ghij)'" 11 O=!(a*b+c*d+e*f+g*h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg+hij)'" 11 O=!(a*b+c*d+e*f*g+h*i*j); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efg+hijk)'" 12 O=!(a*b+c*d+e*f*g+h*i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cd+efgh+ijkl)'" 13 O=!(a*b+c*d+e*f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh+ijk)'" 12 O=!(a*b+c*d*e+f*g*h+i*j*k); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fgh+ijkl)'" 13 O=!(a*b+c*d*e+f*g*h+i*j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cde+fghi+jklm)'" 14 O=!(a*b+c*d*e+f*g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(ab+cdef+ghij+klmn)'" 15 O=!(a*b+c*d*e*f+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi+jkl)'" 13 O=!(a*b*c+d*e*f+g*h*i+j*k*l); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghi+jklm)'" 14 O=!(a*b*c+d*e*f+g*h*i+j*k*l*m); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+def+ghij+klmn)'" 15 O=!(a*b*c+d*e*f+g*h*i*j+k*l*m*n); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abc+defg+hijk+lmno)'" 16 O=!(a*b*c+d*e*f*g+h*i*j*k+l*m*n*o); +PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE "(abcd+efgh+ijkl+mnop)'" 17 O=!(a*b*c*d+e*f*g*h+i*j*k*l+m*n*o*p); +PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/Makefile.am b/sis/sis_lib/Makefile.am new file mode 100644 index 0000000..9739bb5 --- /dev/null +++ b/sis/sis_lib/Makefile.am @@ -0,0 +1,11 @@ +sislibdir = @SIS_SISLIBDIR@ + +SUBDIRS = help +dist_sislib_DATA = 22-1.genlib 22-2.genlib 33-1.genlib 33-2.genlib \ + 33-4.genlib 43-5.genlib 44-1.genlib 44-2.genlib 44-3.genlib 44-6.genlib \ + asynch.genlib const.genlib example.genlib lib2.genlib lib2_latch.genlib \ + mcnc-subset.genlib mcnc.genlib mcnc_latch.genlib minimal.genlib \ + msu.genlib msu_latch.genlib nand-nor.genlib script script.algebraic \ + script.boolean script.delay script.espresso script.mcnc script.msu \ + script.oct script.rugged script.rugged.notes stdcell2_2.genlib \ + synch.genlib weird.genlib weird.lib .misrc .sisrc diff --git a/sis/sis_lib/Makefile.in b/sis/sis_lib/Makefile.in new file mode 100644 index 0000000..f6f92d7 --- /dev/null +++ b/sis/sis_lib/Makefile.in @@ -0,0 +1,460 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/sis_lib +DIST_COMMON = $(dist_sislib_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +am__installdirs = "$(DESTDIR)$(sislibdir)" +dist_sislibDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_sislib_DATA) +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +sislibdir = @SIS_SISLIBDIR@ +SUBDIRS = help +dist_sislib_DATA = 22-1.genlib 22-2.genlib 33-1.genlib 33-2.genlib \ + 33-4.genlib 43-5.genlib 44-1.genlib 44-2.genlib 44-3.genlib 44-6.genlib \ + asynch.genlib const.genlib example.genlib lib2.genlib lib2_latch.genlib \ + mcnc-subset.genlib mcnc.genlib mcnc_latch.genlib minimal.genlib \ + msu.genlib msu_latch.genlib nand-nor.genlib script script.algebraic \ + script.boolean script.delay script.espresso script.mcnc script.msu \ + script.oct script.rugged script.rugged.notes stdcell2_2.genlib \ + synch.genlib weird.genlib weird.lib .misrc .sisrc + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/sis_lib/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/sis_lib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +install-dist_sislibDATA: $(dist_sislib_DATA) + @$(NORMAL_INSTALL) + test -z "$(sislibdir)" || $(mkdir_p) "$(DESTDIR)$(sislibdir)" + @list='$(dist_sislib_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_sislibDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(sislibdir)/$$f'"; \ + $(dist_sislibDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(sislibdir)/$$f"; \ + done + +uninstall-dist_sislibDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_sislib_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(sislibdir)/$$f'"; \ + rm -f "$(DESTDIR)$(sislibdir)/$$f"; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || mkdir "$(distdir)/$$subdir" \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="../$(top_distdir)" \ + distdir="../$(distdir)/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(sislibdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-dist_sislibDATA + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-dist_sislibDATA uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-generic clean-recursive ctags ctags-recursive \ + distclean distclean-generic distclean-recursive distclean-tags \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am \ + install-dist_sislibDATA install-exec install-exec-am \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-generic \ + mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-dist_sislibDATA \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/sis_lib/asynch.genlib b/sis/sis_lib/asynch.genlib new file mode 100644 index 0000000..868d464 --- /dev/null +++ b/sis/sis_lib/asynch.genlib @@ -0,0 +1,239 @@ +# --- COMBINATIONAL GATES + +GATE "inv:combinational" 16 O=!1A; +PIN * INV 1 999 1 .2 1 .2 + +GATE "nor2:combinational" 24 O=!(1A+1B); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nor3:combinational" 32 O=!(1A+1B+1C); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nor4:combinational" 40 O=!(1A+1B+1C+1D); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nand2:combinational" 24 O=!(1A*1B); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nand3:combinational" 32 O=!(1A*1B*1C); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nand4:combinational" 40 O=!(1A*1B*1C*1D); +PIN * INV 1 999 1 .2 1 .2 + +GATE "and2:combinational" 32 O2=1A*1B; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "and3:combinational" 40 O2=1A*1B*1C; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "and4:combinational" 48 O2=1A*1B*1C*1D; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "or2:combinational" 32 O1=1A+1B; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "or3:combinational" 40 O1=1A+1B+1C; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "or4:combinational" 48 O=1A+1B+1C+1D; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "aoi22:combinational" 40 O=!(1A*1B+2C*2D); +PIN * INV 1 999 1 .2 1 .2 + +GATE "aoi12:combinational" 32 O=!(1A+2B*2C); +PIN * INV 1 999 1 .2 1 .2 + +GATE "oai22:combinational" 40 O=!((1A+1B)*(2C+2D)); +PIN * INV 1 999 1 .2 1 .2 + +GATE "oai12:combinational" 32 O=!(1A*(2B+2C)); +PIN * INV 1 999 1 .2 1 .2 + +GATE "ao22:combinational" 56 O=1A*1B+2C*2D; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "ao222:combinational" 72 O=1A*1B+2C*2D+3E*3F; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "ao2222:combinational" 96 O=1A*1B+2C*2D+3E*3F+4G*4H; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "ao33:combinational" 64 O=1A*1B*1C+2D*2E*2F; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "xor:combinational" 40 O=1A*!1B+!1A*1B; +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "xor:combinational" 40 O=!(1A*1B+!1A*!1B); +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "xorbar:combinational" 48 O=1A*1B+!1A*!1B; +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "xorbar:combinational" 48 O=!(1A*!1B+!1A*1B); +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "invand:combinational" 32 O=!1A*2B; +PIN 1A INV 1 999 1 .2 1 .2 +PIN 2B NONINV 1 999 1 .2 1 .2 + +GATE "invor:combinational" 32 O=1A+!2B; +PIN 1A NONINV 1 999 1 .2 1 .2 +PIN 2B INV 1 999 1 .2 1 .2 + +GATE "mux2:combinational" 48 O=1D1*3SEL+2D2*!3SEL; +PIN 1D1 NONINV 1 999 1 .2 1 .2 +PIN 2D2 NONINV 1 999 1 .2 1 .2 +PIN 3SEL UNKNOWN 1 999 1 .2 1 .2 + +GATE "const1:combinational" 8 O=CONST1; +GATE "const0:combinational" 8 O=CONST0; + +# --- TRANSPARENT LATCHES + +# Clocked Latch - active_high +LATCH "dff:active_high" 80 Q=D; +PIN D NONINV 1 999 1 .2 1 .2 +SEQ Q ANY ACTIVE_HIGH +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# Clocked Latch - active_low +LATCH "dff:active_low" 80 Q=D; +PIN D NONINV 1 999 1 .2 1 .2 +SEQ Q ANY ACTIVE_LOW +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# --- EDGE_TRIGGERED FLIP FLOPS + +# D-FF +LATCH "dff:rising_edge" 88 Q=D; +PIN D NONINV 1 999 1 .2 1 .2 +SEQ Q ANY RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# D-FF with ENABLE +LATCH "dff_enable:rising_edge" 100 Q=D*E+Q_NEXT*!E; +PIN D NONINV 1 999 1 .2 1 .2 +PIN E UNKNOWN 1 999 1 .2 1 .2 +SEQ Q Q_NEXT RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# D-FF with synchronous reset +LATCH "dff_reset:rising_edge" 104 Q=D*!R; +PIN D NONINV 1 999 1 .2 1 .2 +PIN R INV 1 999 1 .2 1 .2 +SEQ Q D RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# D-FF with synchronous set/reset +LATCH "dff_set_reset:rising_edge" 136 Q=(D+S)*!R; +PIN D NONINV 1 999 1 .2 1 .2 +PIN S NONINV 1 999 1 .2 1 .2 +PIN R INV 1 999 1 .2 1 .2 +SEQ Q D RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# JK-FF +LATCH "jk_ff:rising_edge" 100 Q=(J*!Q_NEXT)+(!K*Q_NEXT); +PIN J NONINV 1 999 1 .2 1 .2 +PIN K INV 1 999 1 .2 1 .2 +SEQ Q Q_NEXT RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# D-FF +LATCH "dff:falling_edge" 88 Q=D; +PIN D NONINV 1 999 1 .2 1 .2 +SEQ Q ANY RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# D-FF with ENABLE +LATCH "dff_enable:falling_edge" 100 Q=D*E+Q_NEXT*!E; +PIN D NONINV 1 999 1 .2 1 .2 +PIN E UNKNOWN 1 999 1 .2 1 .2 +SEQ Q Q_NEXT RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# D-FF with synchronous reset +LATCH "dff_reset:falling_edge" 104 Q=D*!R; +PIN D NONINV 1 999 1 .2 1 .2 +PIN R INV 1 999 1 .2 1 .2 +SEQ Q D RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# D-FF with synchronous set/reset +LATCH "dff_set_reset:falling_edge" 136 Q=(D+S)*!R; +PIN D NONINV 1 999 1 .2 1 .2 +PIN S NONINV 1 999 1 .2 1 .2 +PIN R INV 1 999 1 .2 1 .2 +SEQ Q D RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# JK-FF +LATCH "jk_ff:falling_edge" 100 Q=(J*!Q_NEXT)+(!K*Q_NEXT); +PIN J NONINV 1 999 1 .2 1 .2 +PIN K INV 1 999 1 .2 1 .2 +SEQ Q Q_NEXT RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# --- ASYNCH LATCHES + +# Pure delay +LATCH "delay:asynch" 10000 Q=D; +PIN D NONINV 1 999 0.00001 0.00001 0.00001 0.00001 +SEQ Q ANY ASYNCH + +# Cross-coupled NAND (SR latch) +LATCH "sr_nand:asynch" 40 Q=!S+R*Q_NEXT; +PIN S INV 1 999 1 .2 1 .2 +PIN R NONINV 1 999 1 .2 1 .2 +SEQ Q Q_NEXT ASYNCH + +# Cross-coupled NOR (SR latch) +LATCH "sr_nor:asynch" 40 Q=S+!R*Q_NEXT; +PIN S NONINV 1 999 1 .2 1 .2 +PIN R INV 1 999 1 .2 1 .2 +SEQ Q Q_NEXT ASYNCH + +# 1 of 2 C-element +LATCH "c_element1:asynch" 50 C = A*B+A*C_NEXT+B*C_NEXT; +PIN A NONINV 1 999 1 .2 1 .2 +PIN B NONINV 1 999 1 .2 1 .2 +SEQ C C_NEXT ASYNCH + +# 2 of 2 C-element +LATCH "c_element2:asynch" 50 C = A*B+(A+B)*C_NEXT; +PIN A NONINV 1 999 1 .2 1 .2 +PIN B NONINV 1 999 1 .2 1 .2 +SEQ C C_NEXT ASYNCH + +# 3 of 3 C-element +LATCH "c_element2:asynch" 50 C = A*(B+C_NEXT)+B*C_NEXT; +PIN A NONINV 1 999 1 .2 1 .2 +PIN B NONINV 1 999 1 .2 1 .2 +SEQ C C_NEXT ASYNCH + +# 1 of 2 Gated Latch +LATCH "gated_latch1:asynch" 40 Q=D*G+Q_NEXT*(!G+D); +PIN D NONINV 1 999 1 .2 1 .2 +PIN G UNKNOWN 1 999 1 .2 1 .2 +SEQ Q Q_NEXT ASYNCH + +# 2 of 2 Gated Latch +LATCH "gated_latch2:asynch" 40 Q=D*G+Q_NEXT*!G+Q_NEXT*D; +PIN D NONINV 1 999 1 .2 1 .2 +PIN G UNKNOWN 1 999 1 .2 1 .2 +SEQ Q Q_NEXT ASYNCH diff --git a/sis/sis_lib/const.genlib b/sis/sis_lib/const.genlib new file mode 100644 index 0000000..d22afe2 --- /dev/null +++ b/sis/sis_lib/const.genlib @@ -0,0 +1,2 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; diff --git a/sis/sis_lib/example.genlib b/sis/sis_lib/example.genlib new file mode 100644 index 0000000..681dc19 --- /dev/null +++ b/sis/sis_lib/example.genlib @@ -0,0 +1,26 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE inv1 2 O=!a; PIN * INV 1 999 0.9 0.3 0.9 0.3 +GATE nand2 3 O=!(a*b); PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE nand3 4 O=!(a*b*c); PIN * INV 1 999 1.1 0.3 1.1 0.3 +GATE nand4 5 O=!(a*b*c*d); PIN * INV 1 999 1.4 0.4 1.4 0.4 +GATE nor2 3 O=!(a+b); PIN * INV 1 999 1.4 0.5 1.4 0.5 +GATE nor3 4 O=!(a+b+c); PIN * INV 1 999 2.4 0.7 2.4 0.7 +GATE nor4 5 O=!(a+b+c+d); PIN * INV 1 999 3.8 1.0 3.8 1.0 +GATE aoi21 4 O=!(a*b+c); PIN * INV 1 999 1.6 0.4 1.6 0.4 +GATE aoi22 5 O=!(a*b+c*d); PIN * INV 1 999 2.0 0.4 2.0 0.4 +GATE oai21 4 O=!((a+b)*c); PIN * INV 1 999 1.6 0.4 1.6 0.4 +GATE oai22 5 O=!((a+b)*(c+d));PIN * INV 1 999 2.0 0.4 2.0 0.4 +# note: the duplicate forms for xor, xnor, and mux21 are necessary ... +GATE xor 5 O=a*!b+!a*b; PIN * UNKNOWN 2 999 1.9 0.5 1.9 0.5 +GATE xor 5 O=!(a*b+!a*!b); PIN * UNKNOWN 2 999 1.9 0.5 1.9 0.5 +GATE xnor 5 O=a*b+!a*!b; PIN * UNKNOWN 2 999 2.1 0.5 2.1 0.5 +GATE xnor 5 O=!(!a*b+a*!b); PIN * UNKNOWN 2 999 2.1 0.5 2.1 0.5 +GATE mux21 4 O=a*s+b*!s; + PIN a NONINV 1 999 1.6 0.4 1.6 0.4 + PIN b NONINV 1 999 1.6 0.4 1.6 0.4 + PIN s UNKNOWN 2 999 2.0 0.4 1.6 0.4 +GATE mux21 4 O=!(!a*s+!b*!s); + PIN a NONINV 1 999 1.6 0.4 1.6 0.4 + PIN b NONINV 1 999 1.6 0.4 1.6 0.4 + PIN s UNKNOWN 2 999 2.0 0.4 1.6 0.4 diff --git a/sis/sis_lib/help/Makefile.am b/sis/sis_lib/help/Makefile.am new file mode 100644 index 0000000..a06e8e4 --- /dev/null +++ b/sis/sis_lib/help/Makefile.am @@ -0,0 +1,65 @@ +helpdir = @SIS_SISLIBDIR@/help + +dist_help_DATA = act_map.fmt add_inverter.fmt alias.fmt \ + astg_add_state.fmt astg_contract.fmt astg_current.fmt astg_cycle.fmt \ + astg_encode.fmt astg_flow.fmt astg_hfrpdft.fmt astg_irred.fmt \ + astg_lockgraph.fmt astg_marking.fmt astg_mgc.fmt astg_persist.fmt \ + astg_print_sg.fmt astg_print_stat.fmt astg_slow.fmt astg_smc.fmt \ + astg_state_min.fmt astg_stg_scr.fmt astg_syn.fmt astg_to_f.fmt \ + astg_to_stg.fmt atpg.fmt bdsyn.fmt buffer_opt.fmt c_check.fmt \ + c_opt.fmt chng_clock.fmt chng_name.fmt collapse.fmt constraints.fmt \ + decomp.fmt echo.fmt eliminate.fmt env_seq_dc.fmt env_verify_fsm.fmt \ + equiv_nets.fmt espresso.fmt extract_seq_dc.fmt factor.fmt fanout_alg.fmt \ + fanout_param.fmt force_init_0.fmt free_dc.fmt full_simplify.fmt fx.fmt \ + gcx.fmt gkx.fmt help.fmt history.fmt invert.fmt invert_io.fmt \ + ite_map.fmt latch_output.fmt map.fmt one_hot.fmt phase.fmt \ + plot_blif.fmt power_estimate.fmt power_free_info.fmt power_print.fmt \ + print.fmt print_altname.fmt print_clock.fmt print_delay.fmt \ + print_factor.fmt print_gate.fmt print_io.fmt print_kernel.fmt \ + print_latch.fmt print_level.fmt print_library.fmt print_map_stats.fmt \ + print_state.fmt print_stats.fmt print_value.fmt quit.fmt read_astg.fmt \ + read_blif.fmt read_eqn.fmt read_kiss.fmt read_library.fmt read_oct.fmt \ + read_pla.fmt read_slif.fmt red_removal.fmt reduce_depth.fmt \ + remove_dep.fmt remove_latches.fmt replace.fmt reset_name.fmt resub.fmt \ + retime.fmt save.fmt set.fmt set_delay.fmt set_state.fmt short_tests.fmt \ + sim_verify.fmt simplify.fmt simulate.fmt source.fmt speed_up.fmt \ + speedup_alg.fmt state_assign.fmt state_minimize.fmt stg_cover.fmt \ + stg_extract.fmt stg_to_astg.fmt stg_to_network.fmt sweep.fmt \ + tech_decomp.fmt time.fmt timeout.fmt unalias.fmt undo.fmt unset.fmt \ + usage.fmt verify.fmt verify_fsm.fmt wd.fmt write_astg.fmt write_bdnet.fmt \ + write_blif.fmt write_eqn.fmt write_kiss.fmt write_oct.fmt write_pds.fmt \ + write_pla.fmt write_slif.fmt xilinx.fmt xl_absorb.fmt xl_ao.fmt \ + xl_coll_ck.fmt xl_cover.fmt xl_decomp_two.fmt xl_imp.fmt xl_k_decomp.fmt \ + xl_merge.fmt xl_part_coll.fmt xl_partition.fmt xl_rl.fmt xl_split.fmt +dist_man1_MANS = sis.1 + +EXTRA_DIST = _astg_cycle.1 _astg_flow.1 _astg_hfrpdft.1 _astg_irred.1 \ + _astg_mgc.1 _astg_smc.1 act_map.1 add_inverter.1 alias.1 astg_add_state.1 \ + astg_contract.1 astg_current.1 astg_encode.1 astg_lockgraph.1 \ + astg_marking.1 astg_persist.1 astg_print_sg.1 astg_print_stat.1 \ + astg_slow.1 astg_state_min.1 astg_stg_scr.1 astg_syn.1 astg_to_f.1 \ + astg_to_stg.1 atpg.1 bdsyn.1 buffer_opt.1 c_check.1 c_opt.1 chng_clock.1 \ + chng_name.1 collapse.1 constraints.1 decomp.1 echo.1 eliminate.1 \ + env_seq_dc.1 env_verify_fsm.1 equiv_nets.1 espresso.1 extract_seq_dc.1 \ + factor.1 fanout_alg.1 fanout_param.1 force_init_0.1 free_dc.1 \ + full_simplify.1 fx.1 gcx.1 gkx.1 help.1 history.1 invert.1 \ + invert_io.1 ite_map.1 latch_output.1 map.1 one_hot.1 phase.1 \ + plot_blif.1 power_estimate.1 power_free_info.1 power_print.1 \ + print.1 print_altname.1 print_clock.1 print_delay.1 print_factor.1 \ + print_gate.1 print_io.1 print_kernel.1 print_latch.1 print_level.1 \ + print_library.1 print_map_stats.1 print_state.1 print_stats.1 \ + print_value.1 quit.1 read_astg.1 read_blif.1 read_eqn.1 read_kiss.1 \ + read_library.1 read_oct.1 read_pla.1 read_slif.1 red_removal.1 \ + reduce_depth.1 remove_dep.1 remove_latches.1 replace.1 reset_name.1 \ + resub.1 retime.1 save.1 set.1 set_delay.1 set_state.1 short_tests.1 \ + sim_verify.1 simplify.1 simulate.1 source.1 speed_up.1 speedup_alg.1 \ + state_assign.1 state_minimize.1 stg_cover.1 stg_extract.1 \ + stg_to_astg.1 stg_to_network.1 sweep.1 tech_decomp.1 time.1 timeout.1 \ + unalias.1 undo.1 usage.1 verify.1 verify_fsm.1 wd.1 write_astg.1 \ + write_bdnet.1 write_blif.1 write_eqn.1 write_kiss.1 write_oct.1 \ + write_pds.1 write_pla.1 write_slif.1 xilinx.1 xl_absorb.1 xl_ao.1 \ + xl_coll_ck.1 xl_cover.1 xl_decomp_two.1 xl_imp.1 xl_k_decomp.1 \ + xl_merge.1 xl_part_coll.1 xl_partition.1 xl_rl.1 xl_split.1 \ + _astg_cycle.fmt _astg_flow.fmt _astg_hfrpdft.fmt _astg_irred.fmt \ + _astg_mgc.fmt _astg_smc.fmt \ + sis.man format header.me make.awk trail diff --git a/sis/sis_lib/help/Makefile.in b/sis/sis_lib/help/Makefile.in new file mode 100644 index 0000000..9fd609e --- /dev/null +++ b/sis/sis_lib/help/Makefile.in @@ -0,0 +1,426 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/sis_lib/help +DIST_COMMON = $(dist_help_DATA) $(dist_man1_MANS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +man1dir = $(mandir)/man1 +am__installdirs = "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(helpdir)" +NROFF = nroff +MANS = $(dist_man1_MANS) +dist_helpDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_help_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +helpdir = @SIS_SISLIBDIR@/help +dist_help_DATA = act_map.fmt add_inverter.fmt alias.fmt \ + astg_add_state.fmt astg_contract.fmt astg_current.fmt astg_cycle.fmt \ + astg_encode.fmt astg_flow.fmt astg_hfrpdft.fmt astg_irred.fmt \ + astg_lockgraph.fmt astg_marking.fmt astg_mgc.fmt astg_persist.fmt \ + astg_print_sg.fmt astg_print_stat.fmt astg_slow.fmt astg_smc.fmt \ + astg_state_min.fmt astg_stg_scr.fmt astg_syn.fmt astg_to_f.fmt \ + astg_to_stg.fmt atpg.fmt bdsyn.fmt buffer_opt.fmt c_check.fmt \ + c_opt.fmt chng_clock.fmt chng_name.fmt collapse.fmt constraints.fmt \ + decomp.fmt echo.fmt eliminate.fmt env_seq_dc.fmt env_verify_fsm.fmt \ + equiv_nets.fmt espresso.fmt extract_seq_dc.fmt factor.fmt fanout_alg.fmt \ + fanout_param.fmt force_init_0.fmt free_dc.fmt full_simplify.fmt fx.fmt \ + gcx.fmt gkx.fmt help.fmt history.fmt invert.fmt invert_io.fmt \ + ite_map.fmt latch_output.fmt map.fmt one_hot.fmt phase.fmt \ + plot_blif.fmt power_estimate.fmt power_free_info.fmt power_print.fmt \ + print.fmt print_altname.fmt print_clock.fmt print_delay.fmt \ + print_factor.fmt print_gate.fmt print_io.fmt print_kernel.fmt \ + print_latch.fmt print_level.fmt print_library.fmt print_map_stats.fmt \ + print_state.fmt print_stats.fmt print_value.fmt quit.fmt read_astg.fmt \ + read_blif.fmt read_eqn.fmt read_kiss.fmt read_library.fmt read_oct.fmt \ + read_pla.fmt read_slif.fmt red_removal.fmt reduce_depth.fmt \ + remove_dep.fmt remove_latches.fmt replace.fmt reset_name.fmt resub.fmt \ + retime.fmt save.fmt set.fmt set_delay.fmt set_state.fmt short_tests.fmt \ + sim_verify.fmt simplify.fmt simulate.fmt source.fmt speed_up.fmt \ + speedup_alg.fmt state_assign.fmt state_minimize.fmt stg_cover.fmt \ + stg_extract.fmt stg_to_astg.fmt stg_to_network.fmt sweep.fmt \ + tech_decomp.fmt time.fmt timeout.fmt unalias.fmt undo.fmt unset.fmt \ + usage.fmt verify.fmt verify_fsm.fmt wd.fmt write_astg.fmt write_bdnet.fmt \ + write_blif.fmt write_eqn.fmt write_kiss.fmt write_oct.fmt write_pds.fmt \ + write_pla.fmt write_slif.fmt xilinx.fmt xl_absorb.fmt xl_ao.fmt \ + xl_coll_ck.fmt xl_cover.fmt xl_decomp_two.fmt xl_imp.fmt xl_k_decomp.fmt \ + xl_merge.fmt xl_part_coll.fmt xl_partition.fmt xl_rl.fmt xl_split.fmt + +dist_man1_MANS = sis.1 +EXTRA_DIST = _astg_cycle.1 _astg_flow.1 _astg_hfrpdft.1 _astg_irred.1 \ + _astg_mgc.1 _astg_smc.1 act_map.1 add_inverter.1 alias.1 astg_add_state.1 \ + astg_contract.1 astg_current.1 astg_encode.1 astg_lockgraph.1 \ + astg_marking.1 astg_persist.1 astg_print_sg.1 astg_print_stat.1 \ + astg_slow.1 astg_state_min.1 astg_stg_scr.1 astg_syn.1 astg_to_f.1 \ + astg_to_stg.1 atpg.1 bdsyn.1 buffer_opt.1 c_check.1 c_opt.1 chng_clock.1 \ + chng_name.1 collapse.1 constraints.1 decomp.1 echo.1 eliminate.1 \ + env_seq_dc.1 env_verify_fsm.1 equiv_nets.1 espresso.1 extract_seq_dc.1 \ + factor.1 fanout_alg.1 fanout_param.1 force_init_0.1 free_dc.1 \ + full_simplify.1 fx.1 gcx.1 gkx.1 help.1 history.1 invert.1 \ + invert_io.1 ite_map.1 latch_output.1 map.1 one_hot.1 phase.1 \ + plot_blif.1 power_estimate.1 power_free_info.1 power_print.1 \ + print.1 print_altname.1 print_clock.1 print_delay.1 print_factor.1 \ + print_gate.1 print_io.1 print_kernel.1 print_latch.1 print_level.1 \ + print_library.1 print_map_stats.1 print_state.1 print_stats.1 \ + print_value.1 quit.1 read_astg.1 read_blif.1 read_eqn.1 read_kiss.1 \ + read_library.1 read_oct.1 read_pla.1 read_slif.1 red_removal.1 \ + reduce_depth.1 remove_dep.1 remove_latches.1 replace.1 reset_name.1 \ + resub.1 retime.1 save.1 set.1 set_delay.1 set_state.1 short_tests.1 \ + sim_verify.1 simplify.1 simulate.1 source.1 speed_up.1 speedup_alg.1 \ + state_assign.1 state_minimize.1 stg_cover.1 stg_extract.1 \ + stg_to_astg.1 stg_to_network.1 sweep.1 tech_decomp.1 time.1 timeout.1 \ + unalias.1 undo.1 usage.1 verify.1 verify_fsm.1 wd.1 write_astg.1 \ + write_bdnet.1 write_blif.1 write_eqn.1 write_kiss.1 write_oct.1 \ + write_pds.1 write_pla.1 write_slif.1 xilinx.1 xl_absorb.1 xl_ao.1 \ + xl_coll_ck.1 xl_cover.1 xl_decomp_two.1 xl_imp.1 xl_k_decomp.1 \ + xl_merge.1 xl_part_coll.1 xl_partition.1 xl_rl.1 xl_split.1 \ + _astg_cycle.fmt _astg_flow.fmt _astg_hfrpdft.fmt _astg_irred.fmt \ + _astg_mgc.fmt _astg_smc.fmt \ + sis.man format header.me make.awk trail + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/sis_lib/help/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/sis_lib/help/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done +install-dist_helpDATA: $(dist_help_DATA) + @$(NORMAL_INSTALL) + test -z "$(helpdir)" || $(mkdir_p) "$(DESTDIR)$(helpdir)" + @list='$(dist_help_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_helpDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(helpdir)/$$f'"; \ + $(dist_helpDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(helpdir)/$$f"; \ + done + +uninstall-dist_helpDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_help_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(helpdir)/$$f'"; \ + rm -f "$(DESTDIR)$(helpdir)/$$f"; \ + done +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(MANS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(helpdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_helpDATA install-man + +install-exec-am: + +install-info: install-info-am + +install-man: install-man1 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_helpDATA uninstall-info-am uninstall-man + +uninstall-man: uninstall-man1 + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-dist_helpDATA install-exec install-exec-am \ + install-info install-info-am install-man install-man1 \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-dist_helpDATA uninstall-info-am uninstall-man \ + uninstall-man1 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/sis_lib/help/_astg_cycle.1 b/sis/sis_lib/help/_astg_cycle.1 new file mode 100644 index 0000000..28408f5 --- /dev/null +++ b/sis/sis_lib/help/_astg_cycle.1 @@ -0,0 +1,14 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/_astg_cycle.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_cycle [<cycle-index>] +.PP +Print the simple cycles of the ASTG, or optionally print +only the cycle with the given index. diff --git a/sis/sis_lib/help/_astg_cycle.fmt b/sis/sis_lib/help/_astg_cycle.fmt new file mode 100644 index 0000000..6ea6574 --- /dev/null +++ b/sis/sis_lib/help/_astg_cycle.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + astg_cycle [<cycle-index>] + + Print the simple cycles of the ASTG, or optionally print only the cycle + with the given index. + + 1 diff --git a/sis/sis_lib/help/_astg_flow.1 b/sis/sis_lib/help/_astg_flow.1 new file mode 100644 index 0000000..7fab37c --- /dev/null +++ b/sis/sis_lib/help/_astg_flow.1 @@ -0,0 +1,41 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/_astg_flow.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_flow [-x] [-l <latch-type>] [-o <out-file>] +.PP +Do exhaustive token flow on an ASTG, forming a state graph +using the ASTG signals to define the state codes. +A next-state logic function is extracted from the state +graph in two-level form. +Then the next state logic is converted into a network +which can be manipulated using the standard \fISIS\fP +network commands. +.PP +The generated network has PI and PO names which match the +signal names specified in the ASTG. +The network has one special structural requirement: for any +signal which is used for feedback, the real PO is attached +to the output of the feedback latch (i.e. connected to the +fake PI for the latch). +This is necessary for other ASTG commands to work properly. +.PP +The -l option specifies the type of latches to insert for +feedback signals. +The default is type "as" (asynchronous). +.PP +The -o option writes the BLIF description of the network +to a file but does not change the current SIS network. +.PP +Normally astg_flow does a structural net check to make sure +the marking is live-safe, using the one-token state machine +condition proposed by T.A. Chu. +This can be extremely time consuming, so the -x option +bypasses this check and does the token flow using the +existing initial marking. diff --git a/sis/sis_lib/help/_astg_flow.fmt b/sis/sis_lib/help/_astg_flow.fmt new file mode 100644 index 0000000..79c0a69 --- /dev/null +++ b/sis/sis_lib/help/_astg_flow.fmt @@ -0,0 +1,30 @@ + + July 1, 1994 SIS(1) + + astg_flow [-x] [-l <latch-type>] [-o <out-file>] + + Do exhaustive token flow on an ASTG, forming a state graph using the + ASTG signals to define the state codes. A next-state logic function is + extracted from the state graph in two-level form. Then the next state + logic is converted into a network which can be manipulated using the + standard _S_I_S network commands. + + The generated network has PI and PO names which match the signal names + specified in the ASTG. The network has one special structural require- + ment: for any signal which is used for feedback, the real PO is attached + to the output of the feedback latch (i.e. connected to the fake PI for + the latch). This is necessary for other ASTG commands to work properly. + + The -l option specifies the type of latches to insert for feedback sig- + nals. The default is type "as" (asynchronous). + + The -o option writes the BLIF description of the network to a file but + does not change the current SIS network. + + Normally astg_flow does a structural net check to make sure the marking + is live-safe, using the one-token state machine condition proposed by + T.A. Chu. This can be extremely time consuming, so the -x option + bypasses this check and does the token flow using the existing initial + marking. + + 1 diff --git a/sis/sis_lib/help/_astg_hfrpdft.1 b/sis/sis_lib/help/_astg_hfrpdft.1 new file mode 100644 index 0000000..f28993d --- /dev/null +++ b/sis/sis_lib/help/_astg_hfrpdft.1 @@ -0,0 +1,11 @@ +.XX +astg_hfrpdft [-v debug_level] +.PP +Make each node in the network hazard-free robustly path-delay fault testable. +Test inputs may be added as a side effect of this command. +.PP +It should be called immediately after \fBastg_to_f\fR, on the initial two-level +cover (see \fBastg_to_f\fR for a recommended script file). +Remember that hazard-free robust path-delay fault +testability is maintained only by \fIalgebraic\fR +optimization. diff --git a/sis/sis_lib/help/_astg_hfrpdft.fmt b/sis/sis_lib/help/_astg_hfrpdft.fmt new file mode 100644 index 0000000..04951ad --- /dev/null +++ b/sis/sis_lib/help/_astg_hfrpdft.fmt @@ -0,0 +1,14 @@ + + July 1, 1994 SIS(1) + + astg_hfrpdft [-v debug_level] + + Make each node in the network hazard-free robustly path-delay fault + testable. Test inputs may be added as a side effect of this command. + + It should be called immediately after astg_to_f, on the initial two- + level cover (see astg_to_f for a recommended script file). Remember + that hazard-free robust path-delay fault testability is maintained only + by _a_l_g_e_b_r_a_i_c optimization. + + 1 diff --git a/sis/sis_lib/help/_astg_irred.1 b/sis/sis_lib/help/_astg_irred.1 new file mode 100644 index 0000000..c3e833b --- /dev/null +++ b/sis/sis_lib/help/_astg_irred.1 @@ -0,0 +1,23 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/_astg_irred.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_irred [-p] +.PP +Delete or print structurally redundant constraints in the ASTG. +A redundant constraint is essentially a constraint from +some transition x* to transition z* when there is also +a constraint from x* to y* to z* (there are additional global +conditions in which the constraint x* to z* is not redundant, +see Chu's dissertation). +In this case z* is already constrained to follow x* and so the +explicit constraint is redundant. +.PP +The -p option just prints constraints which have been identified +as redundant without modifying the ASTG. diff --git a/sis/sis_lib/help/_astg_irred.fmt b/sis/sis_lib/help/_astg_irred.fmt new file mode 100644 index 0000000..718ccdb --- /dev/null +++ b/sis/sis_lib/help/_astg_irred.fmt @@ -0,0 +1,16 @@ + + July 1, 1994 SIS(1) + + astg_irred [-p] + + Delete or print structurally redundant constraints in the ASTG. A + redundant constraint is essentially a constraint from some transition x* + to transition z* when there is also a constraint from x* to y* to z* + (there are additional global conditions in which the constraint x* to z* + is not redundant, see Chu's dissertation). In this case z* is already + constrained to follow x* and so the explicit constraint is redundant. + + The -p option just prints constraints which have been identified as + redundant without modifying the ASTG. + + 1 diff --git a/sis/sis_lib/help/_astg_mgc.1 b/sis/sis_lib/help/_astg_mgc.1 new file mode 100644 index 0000000..01a4821 --- /dev/null +++ b/sis/sis_lib/help/_astg_mgc.1 @@ -0,0 +1,18 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/_astg_mgc.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_mgc [<component-index>] +.PP +Generate all the marked graph (MG) components of the ASTG. +If an optional index is given, then also print the specified +component number. +.PP +For example, if an ASTG has 3 MG components, then \fBastg_mgc 2\fP +will print the vertices in the second component. diff --git a/sis/sis_lib/help/_astg_mgc.fmt b/sis/sis_lib/help/_astg_mgc.fmt new file mode 100644 index 0000000..b2d53ce --- /dev/null +++ b/sis/sis_lib/help/_astg_mgc.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + astg_mgc [<component-index>] + + Generate all the marked graph (MG) components of the ASTG. If an + optional index is given, then also print the specified component number. + + For example, if an ASTG has 3 MG components, then astg_mgc 2 will print + the vertices in the second component. + + 1 diff --git a/sis/sis_lib/help/_astg_smc.1 b/sis/sis_lib/help/_astg_smc.1 new file mode 100644 index 0000000..d10121a --- /dev/null +++ b/sis/sis_lib/help/_astg_smc.1 @@ -0,0 +1,18 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/_astg_smc.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_smc [<component-index>] +.PP +Generate all the state machine (SM) components of the ASTG. +If an optional index is given, then also print the specified +component number. +.PP +For example, if an ASTG has 3 SM components, then \fBastg_smc 2\fP +will print the vertices in the second component. diff --git a/sis/sis_lib/help/_astg_smc.fmt b/sis/sis_lib/help/_astg_smc.fmt new file mode 100644 index 0000000..9692acf --- /dev/null +++ b/sis/sis_lib/help/_astg_smc.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + astg_smc [<component-index>] + + Generate all the state machine (SM) components of the ASTG. If an + optional index is given, then also print the specified component number. + + For example, if an ASTG has 3 SM components, then astg_smc 2 will print + the vertices in the second component. + + 1 diff --git a/sis/sis_lib/help/act_map.1 b/sis/sis_lib/help/act_map.1 new file mode 100644 index 0000000..b69b0c2 --- /dev/null +++ b/sis/sis_lib/help/act_map.1 @@ -0,0 +1,113 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/act_map.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +act_map [-h heuristic_num] [-n num_iteration] [-f collapse_fanin] + [-g gain_factor] [-d decomp_fanin] [-r filename] + [-M MAXOPTIMAL] [-qolDsv] +.PP +Routine to find an optimal mapping to the Actel architecture. +The input is the Boolean network and the output +is a netlist and the block count +(reference: An Architecture for Electrically Configurable Gate Arrays, +Gamal et. al., IEEE J. of Solid State Circuits, April 1989, pp. 394-398). +.PP +\fBact_map\fP synthesizes the given circuit onto Actel +architecture. +It uses a tree-mapping approach to +cover the subject graph with the pattern graphs. +The pattern graphs are hard-wired into the code +and so no library is to be read in. +Subject graph and pattern-graphs are in terms of +2-1 muxes. Subject graph is constructed for each intermediate +node of the network. +Either an OBDD (Ordered BDD) +and/or a BDD is constructed for each such node. +After the entire +network is mapped, an iterative_improvement phase may be entered. + +Following options are supported: + +.PP +\fB-h heuristic_number\fP specifies which one of the two +subject_graphs would be constructed. +.br +.PP +heuristic num = 1 => OBDD +.br +.PP +heuristic num = 2 => BDD (default) +.br +.PP +heuristic num = 3 => program decides which one to construct. +.br +.PP +heuristic num = 4 => both are constructed and the one with +lower mapped cost is selected. Gives the best +result, but typically takes more time. +.br +.PP +\fB-M MAXOPTIMAL\fP constructs an optimal OBDD for a node if number of fanins is +at most MAXOPTIMAL. +.br +.PP +\fB-n num_iteration\fP specifies the maximum number of iterations +to be performed in the iterative_improvement phase. Each such +iteration involves a good_decomposition followed by a partial_collapse +routine. Partial_collapse tries to collapse each node into +its fanouts. Default is -n 0. +.br +.PP +\fB-f collapse_fanin\fP considers only those nodes +for partial_collapse which have fanin no more than collapse_fanin. +(Default: -f 3). +.br +.PP +\fB-g gain_factor\fP makes the program enter the next iteration +only if gain in the present iteration is at least +(present_cost * gain_factor). (Default: -g 0.01) +.br +.PP +\fB-d decomp_fanin\fP considers only those nodes for good_decomposition +which have fanin greater than or equal to decomp_fanin. (Default -d 4). +.br +.PP +\fB-r filename\fP is the final mapping option. +After mapping, a mapped network would be created, in +which each intermediate node corresponds to one basic block +of Actel architecture. +A file \fBfilename\fP having the netlist description +in a BDNET-like format is also formed. +The pin names of the basic block are the same +as those given in a Figure in the paper on Actel +architecture (reference: An Architecture for Electrically +Configurable Gate Arrays, Gamal et al., IEEE J. Solid State +Circuits, April 1989, pp. 394-398). +.br +.PP +\fB-q\fP makes the program enter a quick_phase +routine (after iterative_improvement phase), which greedily +finds out if it is beneficial to implement the node in +negative phase. +.br +.PP +\fB-D\fP causes a disjoint decomposition routine +to be invoked on the network before mapping starts. +.br +.PP +\fB-o\fP causes the OR gate in the basic block to be ignored. So mapping is done onto a +three-mux structure. +.br +.PP +\fB-v\fP turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. +.br +.PP +\fB-s\fP gives the statistics, regarding the block count +of the circuit. diff --git a/sis/sis_lib/help/act_map.fmt b/sis/sis_lib/help/act_map.fmt new file mode 100644 index 0000000..cec0929 --- /dev/null +++ b/sis/sis_lib/help/act_map.fmt @@ -0,0 +1,84 @@ + + July 1, 1994 SIS(1) + + act_map [-h heuristic_num] [-n num_iteration] [-f collapse_fanin] + [-g gain_factor] [-d decomp_fanin] [-r filename] + [-M MAXOPTIMAL] [-qolDsv] + + Routine to find an optimal mapping to the Actel architecture. The input + is the Boolean network and the output is a netlist and the block count + (reference: An Architecture for Electrically Configurable Gate Arrays, + Gamal et. al., IEEE J. of Solid State Circuits, April 1989, pp. 394- + 398). + + act_map synthesizes the given circuit onto Actel architecture. It uses + a tree-mapping approach to cover the subject graph with the pattern + graphs. The pattern graphs are hard-wired into the code and so no + library is to be read in. Subject graph and pattern-graphs are in terms + of 2-1 muxes. Subject graph is constructed for each intermediate node of + the network. Either an OBDD (Ordered BDD) and/or a BDD is constructed + for each such node. After the entire network is mapped, an + iterative_improvement phase may be entered. + + Following options are supported: + + -h heuristic_number specifies which one of the two subject_graphs would + be constructed. + + heuristic num = 1 => OBDD + + heuristic num = 2 => BDD (default) + + heuristic num = 3 => program decides which one to construct. + + heuristic num = 4 => both are constructed and the one with lower mapped + cost is selected. Gives the best result, but typically takes more time. + + -M MAXOPTIMAL constructs an optimal OBDD for a node if number of fanins + is at most MAXOPTIMAL. + + -n num_iteration specifies the maximum number of iterations to be per- + formed in the iterative_improvement phase. Each such iteration involves + a good_decomposition followed by a partial_collapse routine. + Partial_collapse tries to collapse each node into its fanouts. Default + is -n 0. + + -f collapse_fanin considers only those nodes for partial_collapse which + have fanin no more than collapse_fanin. (Default: -f 3). + + -g gain_factor makes the program enter the next iteration only if gain + in the present iteration is at least (present_cost * gain_factor). + (Default: -g 0.01) + + -d decomp_fanin considers only those nodes for good_decomposition which + have fanin greater than or equal to decomp_fanin. (Default -d 4). + + 1 + + SIS(1) July 1, 1994 + + -r filename is the final mapping option. After mapping, a mapped net- + work would be created, in which each intermediate node corresponds to + one basic block of Actel architecture. A file filename having the net- + list description in a BDNET-like format is also formed. The pin names + of the basic block are the same as those given in a Figure in the paper + on Actel architecture (reference: An Architecture for Electrically Con- + figurable Gate Arrays, Gamal et al., IEEE J. Solid State Circuits, April + 1989, pp. 394-398). + + -q makes the program enter a quick_phase routine (after + iterative_improvement phase), which greedily finds out if it is benefi- + cial to implement the node in negative phase. + + -D causes a disjoint decomposition routine to be invoked on the network + before mapping starts. + + -o causes the OR gate in the basic block to be ignored. So mapping is + done onto a three-mux structure. + + -v turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + + -s gives the statistics, regarding the block count of the circuit. + + 2 diff --git a/sis/sis_lib/help/add_inverter.1 b/sis/sis_lib/help/add_inverter.1 new file mode 100644 index 0000000..3e9aac8 --- /dev/null +++ b/sis/sis_lib/help/add_inverter.1 @@ -0,0 +1,16 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/add_inverter.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +add_inverter +.PP +Add inverters into the network wherever needed to make each +signal (including the primary inputs) used only in its negative form. +After this command, every literal in a node is in the negative form. +This is the appropriate starting point for the technology mapping step. diff --git a/sis/sis_lib/help/add_inverter.fmt b/sis/sis_lib/help/add_inverter.fmt new file mode 100644 index 0000000..e687b00 --- /dev/null +++ b/sis/sis_lib/help/add_inverter.fmt @@ -0,0 +1,11 @@ + + July 1, 1994 SIS(1) + + add_inverter + + Add inverters into the network wherever needed to make each signal + (including the primary inputs) used only in its negative form. After + this command, every literal in a node is in the negative form. This is + the appropriate starting point for the technology mapping step. + + 1 diff --git a/sis/sis_lib/help/alias.1 b/sis/sis_lib/help/alias.1 new file mode 100644 index 0000000..35e5a4c --- /dev/null +++ b/sis/sis_lib/help/alias.1 @@ -0,0 +1,60 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/alias.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +alias [name [string]] +.X1 +unalias name ... +.PP +The \fBalias\fR command, if given no arguments, will print the +definition of all current aliases. Given a single argument, it +will print the definition of that alias (if any). Given two +arguments, the keyword \fBname\fP becomes an alias for +the command string \fBstring\fP, replacing any other alias with the +same name. +The \fBunalias\fR command removes the definition of an alias. +.PP +It is possible to create aliases that take arguments by using the history +substitution mechanism. To protect the history substitution character `%' +from immediate expansion, it must be preceded by a `\\' when entering the +alias. For example: +.IP +.nf +sis> alias read read_\\%:1 \\%:2.\\%:1 +sis> alias write write_\\%:1 \\%:2.\\%:1 +sis> read blif lion +sis> write eqn tiger +.fi +.PP +will create the two aliases `read' and `write', execute "read_blif +lion.blif", and then execute "write_eqn tiger.eqn". And... +.fi +.IP +.nf +sis> alias echo2 "echo Hi ; echo \\%* !" +sis> echo2 happy birthday +.fi +.PP +would print: +.IP +.nf +Hi +happy birthday ! +.fi +.PP +\fBCAVEAT:\fR Currently there is no check to see if there is a circular +dependency in the alias definition. e.g. +.IP +.nf +sis> alias foo "print_stats -f; print_level -l; foo" +.fi +.PP +creates an alias which refers to itself. Executing the command "foo" will +result an infinite loop during which the commands "print_stats -f" and +"print_level -l" will be executed. diff --git a/sis/sis_lib/help/alias.fmt b/sis/sis_lib/help/alias.fmt new file mode 100644 index 0000000..1911f20 --- /dev/null +++ b/sis/sis_lib/help/alias.fmt @@ -0,0 +1,44 @@ + + July 1, 1994 SIS(1) + + alias [name [string]] + unalias name ... + + The alias command, if given no arguments, will print the definition of + all current aliases. Given a single argument, it will print the defini- + tion of that alias (if any). Given two arguments, the keyword name + becomes an alias for the command string string, replacing any other + alias with the same name. The unalias command removes the definition of + an alias. + + It is possible to create aliases that take arguments by using the his- + tory substitution mechanism. To protect the history substitution char- + acter `%' from immediate expansion, it must be preceded by a `\' when + entering the alias. For example: + + sis> alias read read_\%:1 \%:2.\%:1 + sis> alias write write_\%:1 \%:2.\%:1 + sis> read blif lion + sis> write eqn tiger + + will create the two aliases `read' and `write', execute "read_blif + lion.blif", and then execute "write_eqn tiger.eqn". And... + + sis> alias echo2 "echo Hi ; echo \%* !" + sis> echo2 happy birthday + + would print: + + Hi + happy birthday ! + + CAVEAT: Currently there is no check to see if there is a circular depen- + dency in the alias definition. e.g. + + sis> alias foo "print_stats -f; print_level -l; foo" + + creates an alias which refers to itself. Executing the command "foo" + will result an infinite loop during which the commands "print_stats -f" + and "print_level -l" will be executed. + + 1 diff --git a/sis/sis_lib/help/astg_add_state.1 b/sis/sis_lib/help/astg_add_state.1 new file mode 100644 index 0000000..7d03d70 --- /dev/null +++ b/sis/sis_lib/help/astg_add_state.1 @@ -0,0 +1,17 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_add_state.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:45 $ +.\" * +.\" +.XX +astg_add_state [-v debug_level] [-m] +.PP +Adds state signal transitions to the Signal Transition Graph to guarantee +implementability (see \fBastg_state_min\fR for a recommended script file). +.PP +The \fB-m\fR option does not preserve the original ASTG marking, and forces its +re-computation (may be slow; dubious usefulness). diff --git a/sis/sis_lib/help/astg_add_state.fmt b/sis/sis_lib/help/astg_add_state.fmt new file mode 100644 index 0000000..044a020 --- /dev/null +++ b/sis/sis_lib/help/astg_add_state.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + astg_add_state [-v debug_level] [-m] + + Adds state signal transitions to the Signal Transition Graph to guaran- + tee implementability (see astg_state_min for a recommended script file). + + The -m option does not preserve the original ASTG marking, and forces + its re-computation (may be slow; dubious usefulness). + + 1 diff --git a/sis/sis_lib/help/astg_contract.1 b/sis/sis_lib/help/astg_contract.1 new file mode 100644 index 0000000..464be4e --- /dev/null +++ b/sis/sis_lib/help/astg_contract.1 @@ -0,0 +1,19 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_contract.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_contract [-f] <signal-name> +.PP +Generate the contracted net for the specified signal of the ASTG. +.PP +The -f option adds the restriction that the contracted net +must also be free-choice. +Chu has conjectured that this restriction may not be necessary, +so it is optional at this time until we have answered this +question. diff --git a/sis/sis_lib/help/astg_contract.fmt b/sis/sis_lib/help/astg_contract.fmt new file mode 100644 index 0000000..9dc2771 --- /dev/null +++ b/sis/sis_lib/help/astg_contract.fmt @@ -0,0 +1,13 @@ + + July 1, 1994 SIS(1) + + astg_contract [-f] <signal-name> + + Generate the contracted net for the specified signal of the ASTG. + + The -f option adds the restriction that the contracted net must also be + free-choice. Chu has conjectured that this restriction may not be + necessary, so it is optional at this time until we have answered this + question. + + 1 diff --git a/sis/sis_lib/help/astg_current.1 b/sis/sis_lib/help/astg_current.1 new file mode 100644 index 0000000..4b41793 --- /dev/null +++ b/sis/sis_lib/help/astg_current.1 @@ -0,0 +1,19 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_current.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_current +.PP +Display information about the current ASTG: +its name, +whether it is a free-choice net, +state machine, or marked graph, +and the number of state machine (SM) and marked +graph (MG) components if astg_smc or astg_mgc have +been run on the ASTG. diff --git a/sis/sis_lib/help/astg_current.fmt b/sis/sis_lib/help/astg_current.fmt new file mode 100644 index 0000000..6d68d9f --- /dev/null +++ b/sis/sis_lib/help/astg_current.fmt @@ -0,0 +1,11 @@ + + July 1, 1994 SIS(1) + + astg_current + + Display information about the current ASTG: its name, whether it is a + free-choice net, state machine, or marked graph, and the number of state + machine (SM) and marked graph (MG) components if astg_smc or astg_mgc + have been run on the ASTG. + + 1 diff --git a/sis/sis_lib/help/astg_cycle.fmt b/sis/sis_lib/help/astg_cycle.fmt new file mode 100644 index 0000000..2d5abe3 --- /dev/null +++ b/sis/sis_lib/help/astg_cycle.fmt @@ -0,0 +1,9 @@ + + May 4, 1992 SIS(1) + + astg_cycle [<cycle-index>] + + Print the simple cycles of the ASTG, or optionally print only the cycle + with the given index. + + 1 diff --git a/sis/sis_lib/help/astg_encode.1 b/sis/sis_lib/help/astg_encode.1 new file mode 100644 index 0000000..9885813 --- /dev/null +++ b/sis/sis_lib/help/astg_encode.1 @@ -0,0 +1,23 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_encode.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:45 $ +.\" * +.\" +.XX +astg_encode [-v debug_level] [-h] [-s] [-u] +.PP +Encodes the states of the current State Transition Graph using Tracey's +critical race-free encoding algorithm. Used to perform state encoding for +asynchronous circuits (see \fBastg_state_min\fR for a recommended script file). +.PP +The \fB-h\fR option selects a faster heuristic (that may result in more state +variables). +.PP +The \fB-s\fR option prints out a brief summary of the encoding algorithm +results. +.PP +The \fB-u\fR option allows to enter user-defined codes (for debugging purposes). diff --git a/sis/sis_lib/help/astg_encode.fmt b/sis/sis_lib/help/astg_encode.fmt new file mode 100644 index 0000000..f9a6475 --- /dev/null +++ b/sis/sis_lib/help/astg_encode.fmt @@ -0,0 +1,20 @@ + + July 1, 1994 SIS(1) + + astg_encode [-v debug_level] [-h] [-s] [-u] + + Encodes the states of the current State Transition Graph using Tracey's + critical race-free encoding algorithm. Used to perform state encoding + for asynchronous circuits (see astg_state_min for a recommended script + file). + + The -h option selects a faster heuristic (that may result in more state + variables). + + The -s option prints out a brief summary of the encoding algorithm + results. + + The -u option allows to enter user-defined codes (for debugging pur- + poses). + + 1 diff --git a/sis/sis_lib/help/astg_flow.fmt b/sis/sis_lib/help/astg_flow.fmt new file mode 100644 index 0000000..9e550e8 --- /dev/null +++ b/sis/sis_lib/help/astg_flow.fmt @@ -0,0 +1,30 @@ + + May 4, 1992 SIS(1) + + astg_flow [-x] [-l <latch-type>] [-o <out-file>] + + Do exhaustive token flow on an ASTG, forming a state graph using the + ASTG signals to define the state codes. A next-state logic function is + extracted from the state graph in two-level form. Then the next state + logic is converted into a network which can be manipulated using the + standard _S_I_S network commands. + + The generated network has PI and PO names which match the signal names + specified in the ASTG. The network has one special structural require- + ment: for any signal which is used for feedback, the real PO is attached + to the output of the feedback latch (i.e. connected to the fake PI for + the latch). This is necessary for other ASTG commands to work properly. + + The -l option specifies the type of latches to insert for feedback sig- + nals. The default is type "as" (asynchronous). + + The -o option writes the BLIF description of the network to a file but + does not change the current SIS network. + + Normally astg_flow does a structural net check to make sure the marking + is live-safe, using the one-token state machine condition proposed by + T.A. Chu. This can be extremely time consuming, so the -x option + bypasses this check and does the token flow using the existing initial + marking. + + 1 diff --git a/sis/sis_lib/help/astg_hfrpdft.fmt b/sis/sis_lib/help/astg_hfrpdft.fmt new file mode 100644 index 0000000..2ad1be6 --- /dev/null +++ b/sis/sis_lib/help/astg_hfrpdft.fmt @@ -0,0 +1,14 @@ + + May 4, 1992 SIS(1) + + astg_hfrpdft [-v debug_level] + + Make each node in the network hazard-free robustly path-delay fault + testable. Test inputs may be added as a side effect of this command. + + It should be called immediately after astg_to_f, on the initial two- + level cover (see astg_to_f for a recommended script file). Remember + that hazard-free robust path-delay fault testability is maintained only + by _a_l_g_e_b_r_a_i_c optimization. + + 1 diff --git a/sis/sis_lib/help/astg_irred.fmt b/sis/sis_lib/help/astg_irred.fmt new file mode 100644 index 0000000..68243f4 --- /dev/null +++ b/sis/sis_lib/help/astg_irred.fmt @@ -0,0 +1,16 @@ + + May 4, 1992 SIS(1) + + astg_irred [-p] + + Delete or print structurally redundant constraints in the ASTG. A + redundant constraint is essentially a constraint from some transition x* + to transition z* when there is also a constraint from x* to y* to z* + (there are additional global conditions in which the constraint x* to z* + is not redundant, see Chu's dissertation). In this case z* is already + constrained to follow x* and so the explicit constraint is redundant. + + The -p option just prints constraints which have been identified as + redundant without modifying the ASTG. + + 1 diff --git a/sis/sis_lib/help/astg_lockgraph.1 b/sis/sis_lib/help/astg_lockgraph.1 new file mode 100644 index 0000000..51e7824 --- /dev/null +++ b/sis/sis_lib/help/astg_lockgraph.1 @@ -0,0 +1,27 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_lockgraph.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:43 $ +.\" * +.\" +.XX +astg_lockgraph [-l] +.PP +Build the lock graph for the current ASTG. +.PP +With the -l option, edges are added to +the ASTG to ensure that the lock graph +is connected, and thus that the ASTG has the Complete State +Coding property. +.PP +If an ASTG has the CSC property, the state of the circuit can +be represented completely by the collection of input, output +and internal signals specified in the ASTG. +This simplifies many synthesis algorithms. +.PP +The algorithm works only for ASTGs that are marked graphs (no choice). +See \fBastg_state_min\fR for a set of commands that +ensure Complete State Coding for more general ASTGs. diff --git a/sis/sis_lib/help/astg_lockgraph.fmt b/sis/sis_lib/help/astg_lockgraph.fmt new file mode 100644 index 0000000..30eb468 --- /dev/null +++ b/sis/sis_lib/help/astg_lockgraph.fmt @@ -0,0 +1,21 @@ + + July 1, 1994 SIS(1) + + astg_lockgraph [-l] + + Build the lock graph for the current ASTG. + + With the -l option, edges are added to the ASTG to ensure that the lock + graph is connected, and thus that the ASTG has the Complete State Coding + property. + + If an ASTG has the CSC property, the state of the circuit can be + represented completely by the collection of input, output and internal + signals specified in the ASTG. This simplifies many synthesis algo- + rithms. + + The algorithm works only for ASTGs that are marked graphs (no choice). + See astg_state_min for a set of commands that ensure Complete State Cod- + ing for more general ASTGs. + + 1 diff --git a/sis/sis_lib/help/astg_marking.1 b/sis/sis_lib/help/astg_marking.1 new file mode 100644 index 0000000..fa6da10 --- /dev/null +++ b/sis/sis_lib/help/astg_marking.1 @@ -0,0 +1,24 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_marking.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_marking [-s] [<marking>] +.PP +Display or set the initial marking of the ASTG. +If no marking is given, the current initial marking is +displayed. +The default format for the marking is the same as for the +\fB.marking\fP command of read_astg. +.PP +The -s option uses a state code format for the marking. +This is a list of signal name and value pairs. +For example, to set an initial state with signal A at +value 0 and B at value 1, use the command: +.br +astg_marking -s A 0 B 1 diff --git a/sis/sis_lib/help/astg_marking.fmt b/sis/sis_lib/help/astg_marking.fmt new file mode 100644 index 0000000..a072e04 --- /dev/null +++ b/sis/sis_lib/help/astg_marking.fmt @@ -0,0 +1,15 @@ + + July 1, 1994 SIS(1) + + astg_marking [-s] [<marking>] + + Display or set the initial marking of the ASTG. If no marking is given, + the current initial marking is displayed. The default format for the + marking is the same as for the + + The -s option uses a state code format for the marking. This is a list + of signal name and value pairs. For example, to set an initial state + with signal A at value 0 and B at value 1, use the command: + astg_marking -s A 0 B 1 + + 1 diff --git a/sis/sis_lib/help/astg_mgc.fmt b/sis/sis_lib/help/astg_mgc.fmt new file mode 100644 index 0000000..654337a --- /dev/null +++ b/sis/sis_lib/help/astg_mgc.fmt @@ -0,0 +1,12 @@ + + May 4, 1992 SIS(1) + + astg_mgc [<component-index>] + + Generate all the marked graph (MG) components of the ASTG. If an + optional index is given, then also print the specified component number. + + For example, if an ASTG has 3 MG components, then astg_mgc 2 will print + the vertices in the second component. + + 1 diff --git a/sis/sis_lib/help/astg_persist.1 b/sis/sis_lib/help/astg_persist.1 new file mode 100644 index 0000000..0eada86 --- /dev/null +++ b/sis/sis_lib/help/astg_persist.1 @@ -0,0 +1,23 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_persist.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_persist [-p] +.PP +Add constraints to make an ASTG persistent. +With the -p option, non-persistent transitions are printed +but the ASTG is not modified. +.PP +For small ASTGs with very high concurrency, enforcing the +ASTG persistency property will partially and sometimes completely +enforce the Complete State Coding property (CSC). +If an ASTG has the CSC property, the state of the circuit can +be represented completely by the collection of input, output +and internal signals specified in the ASTG. +This simplifies many synthesis algorithms. diff --git a/sis/sis_lib/help/astg_persist.fmt b/sis/sis_lib/help/astg_persist.fmt new file mode 100644 index 0000000..fe3948f --- /dev/null +++ b/sis/sis_lib/help/astg_persist.fmt @@ -0,0 +1,16 @@ + + May 4, 1992 SIS(1) + + astg_persist [-p] + + Add constraints to make an ASTG persistent. With the -p option, nonper- + sistent transitions are printed but the ASTG is not modified. + + For small ASTGs with very high concurrency, enforcing the ASTG per- + sistency property will partially and sometimes completely enforce the + Complete State Coding property (CSC). If an ASTG has the CSC property, + the state of the circuit can be represented completely by the collection + of input, output and internal signals specified in the ASTG. This sim- + plifies many synthesis algorithms. + + 1 diff --git a/sis/sis_lib/help/astg_print_sg.1 b/sis/sis_lib/help/astg_print_sg.1 new file mode 100644 index 0000000..dcc6e8f --- /dev/null +++ b/sis/sis_lib/help/astg_print_sg.1 @@ -0,0 +1,15 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_print_sg.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_print_sg +.PP +Print the state graph of the current ASTG. If no state graph is +present, this will create one by token flow. + diff --git a/sis/sis_lib/help/astg_print_sg.fmt b/sis/sis_lib/help/astg_print_sg.fmt new file mode 100644 index 0000000..a19cd89 --- /dev/null +++ b/sis/sis_lib/help/astg_print_sg.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + astg_print_sg + + Print the state graph of the current ASTG. If no state graph is + present, this will create one by token flow. + + 1 diff --git a/sis/sis_lib/help/astg_print_stat.1 b/sis/sis_lib/help/astg_print_stat.1 new file mode 100644 index 0000000..b22aa26 --- /dev/null +++ b/sis/sis_lib/help/astg_print_stat.1 @@ -0,0 +1,15 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_print_stat.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +astg_print_stat +.PP +Print the statistics of the current ASTG: name of the ASTG file, initial +marking, total number of states in the state graph and the total +number of I/O signals. diff --git a/sis/sis_lib/help/astg_print_stat.fmt b/sis/sis_lib/help/astg_print_stat.fmt new file mode 100644 index 0000000..edf05e5 --- /dev/null +++ b/sis/sis_lib/help/astg_print_stat.fmt @@ -0,0 +1,10 @@ + + July 1, 1994 SIS(1) + + astg_print_stat + + Print the statistics of the current ASTG: name of the ASTG file, initial + marking, total number of states in the state graph and the total number + of I/O signals. + + 1 diff --git a/sis/sis_lib/help/astg_slow.1 b/sis/sis_lib/help/astg_slow.1 new file mode 100644 index 0000000..cf543b0 --- /dev/null +++ b/sis/sis_lib/help/astg_slow.1 @@ -0,0 +1,64 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_slow.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_slow [-v debug_level] [-t tolerance] [-s] [-u] +[[-f|-F] external_delay_file] [-d default_external_delay] [-m min_delay_factor] +.PP +Remove hazards from the ASTG implementation, inserting delay buffers after some +ASTG signals. Delays are inserted so that no gate within the circuit +implementation can react as though the ASTG specified ordering of signals is +reversed in time. +.PP +It must be invoked after technology mapping (see \fBastg_to_f\fR for a +recommended script file). +.PP +The \fB-m\fR option specifies the amount by which all MINIMUM delays are +MULTIPLIED (this until the delay computation will understand min/max delays). +Of course 0.0 < min_delay_factor <= 1.0. Default value: 1.0. +.PP +The \fB-t\fR option specifies the tolerance to be used during the hazard check +procedure (the larger the specified value, the more conservative is the +algorithm). Default value: 0.0. +.PP +The \fB-s\fR option specifies not to use the shortest-path algorithm when +computing the delays in the network. This might result in being overly +pessimistic (this option is only experimental). +.PP +The \fB-f\fR option specifies a file name to search for the minimum +delays between output signals and input signals of the ASTG (i.e. for those +signals that are not being synthesized). This can be useful if some information +about these signals is known either from the specification or from the +synthesis of another sub-component of the total asynchronous system. +.PP +The file can also be +updated with the minimum delays between each input signal and each output +signal if the \fB-F\fR option is used in place of \fB-f\fR. +This allows for separate synthesis of various sub-components of an +asynchronous system. In this case iteration might be necessary to obtain +optimal results, and a warning message is issued when the stored information +is changed, and a new iteration is required. +.PP +The \fB-u\fR option specifies not to remove hazards, but only to update the +external elay file (if appropriate). This can be used to remove hazards from a +set of Signal Transition Graphs that are synthesized separately (e.g. by +contraction). In this case, a first round of synthesis can be performed +on each Signal Transition Graph, followed by \fBastg_slow\fR +with the \fB-F\fR and the \fB-u\fR options, to store the information on the +delay of the function implementing each signal. Then \fBastg_slow\fR can be +iterated among the Signal Transition Graphs with the \fB-F\fR option only until +convergence is obtained. The results should be comparable with synthesis and +hazard removal from a single Signal Transition Graph, but can be considerably +faster for large specifications. +.PP +The \fB-d\fR option specifies the default minimum delay between output signals +and input signals of the ASTG (if no information can be obtained from the above +described file). The default value is 0.0 (i.e. the environment responds +instantaneously), but this can be overly pessimistic, and result in an +unnecessary slow and large implementation. diff --git a/sis/sis_lib/help/astg_slow.fmt b/sis/sis_lib/help/astg_slow.fmt new file mode 100644 index 0000000..472900c --- /dev/null +++ b/sis/sis_lib/help/astg_slow.fmt @@ -0,0 +1,64 @@ + + July 1, 1994 SIS(1) + + astg_slow [-v debug_level] [-t tolerance] [-s] [-u] [[-f|-F] + external_delay_file] [-d default_external_delay] [-m min_delay_factor] + + Remove hazards from the ASTG implementation, inserting delay buffers + after some ASTG signals. Delays are inserted so that no gate within the + circuit implementation can react as though the ASTG specified ordering + of signals is reversed in time. + + It must be invoked after technology mapping (see astg_to_f for a recom- + mended script file). + + The -m option specifies the amount by which all MINIMUM delays are MUL- + TIPLIED (this until the delay computation will understand min/max + delays). Of course 0.0 < min_delay_factor <= 1.0. Default value: 1.0. + + The -t option specifies the tolerance to be used during the hazard check + procedure (the larger the specified value, the more conservative is the + algorithm). Default value: 0.0. + + The -s option specifies not to use the shortest-path algorithm when com- + puting the delays in the network. This might result in being overly pes- + simistic (this option is only experimental). + + The -f option specifies a file name to search for the minimum delays + between output signals and input signals of the ASTG (i.e. for those + signals that are not being synthesized). This can be useful if some + information about these signals is known either from the specification + or from the synthesis of another sub-component of the total asynchronous + system. + + The file can also be updated with the minimum delays between each input + signal and each output signal if the -F option is used in place of -f. + This allows for separate synthesis of various sub-components of an asyn- + chronous system. In this case iteration might be necessary to obtain + optimal results, and a warning message is issued when the stored infor- + mation is changed, and a new iteration is required. + + The -u option specifies not to remove hazards, but only to update the + external elay file (if appropriate). This can be used to remove hazards + from a set of Signal Transition Graphs that are synthesized separately + (e.g. by contraction). In this case, a first round of synthesis can be + performed on each Signal Transition Graph, followed by astg_slow with + the -F and the -u options, to store the information on the delay of the + function implementing each signal. Then astg_slow can be iterated among + the Signal Transition Graphs with the -F option only until convergence + is obtained. The results should be comparable with synthesis and hazard + removal from a single Signal Transition Graph, but can be considerably + faster for large specifications. + + The -d option specifies the default minimum delay between output signals + and input signals of the ASTG (if no information can be obtained from + the above described file). The default value is 0.0 (i.e. the environ- + ment responds instantaneously), but this can be overly pessimistic, and + + 1 + + SIS(1) July 1, 1994 + + result in an unnecessary slow and large implementation. + + 2 diff --git a/sis/sis_lib/help/astg_smc.fmt b/sis/sis_lib/help/astg_smc.fmt new file mode 100644 index 0000000..f576513 --- /dev/null +++ b/sis/sis_lib/help/astg_smc.fmt @@ -0,0 +1,12 @@ + + May 4, 1992 SIS(1) + + astg_smc [<component-index>] + + Generate all the state machine (SM) components of the ASTG. If an + optional index is given, then also print the specified component number. + + For example, if an ASTG has 3 SM components, then astg_smc 2 will print + the vertices in the second component. + + 1 diff --git a/sis/sis_lib/help/astg_state_min.1 b/sis/sis_lib/help/astg_state_min.1 new file mode 100644 index 0000000..8497005 --- /dev/null +++ b/sis/sis_lib/help/astg_state_min.1 @@ -0,0 +1,98 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_state_min.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:44 $ +.\" * +.\" +.XX +astg_state_min [-v debug_level] [-p minimized_file] [-c "command"] +[-b|-B] [-g|-G] [-u] [-m|-M] [-o #] [-f signal_cost_file] +.PP +Minimizes the current State Transition Graph and derives the information +required to encode the associated Signal Transition Graph. +The complete sequence of actions to implement a Signal Transition Graph that +does not have Complete State Coding is as follows: +.br + +.br +astg_to_stg -m +.br +astg_state_min +.br +astg_encode +.br +astg_add_state +.br + +.br +astg_to_f +.br + ... +.PP +The \fB-f\fR option selects a signal cost file. +This file should contain one line of the form +.br +<signal name> <cost> +.br +(e.g. "bus_ack 10") for each signal in the ASTG. The encoding algorithm +minimizes the sum of the weights of signals that follow state transitions. +Hence this file can be used to strongly favor or disfavor changing the +predecessors of the transitions of a signal. +.PP +By default, output signals have a cost of one and input signals have a +cost equal to the number of output signals plus one. In this way, no input +signal is constrained, if possible. +.PP +The command may emit a series of diagnostic messages of the form: +.br +warning: the STG may not be live (multiple exit point): may need constraint +<signal 1> -> <signal 2> +.br +These messages may or may not cause a failure (diagnosed as internal error) +later on during \fBastg_add_state\fR. In case of failure, \fBone\fR of the +required constraints (ideally the constraint that least decreases the circuit +performance due to the reduction in concurrency) should be added to the ASTG. +The procedure should be repeated until no more such messages occur. +.PP +The options listed below are not generally useful except for debugging purposes +or to obtain faster (but potentially less optimal) +results for large Signal Transition Graphs. +All algorithm speed indications reflect average case analysis. +.PP +The \fB-B\fR and \fB-b\fR options select Binary Decision Diagrams +as internal data structure to find the encoding information (both are generally +slower than the default selection, but \fB-b\fR is generally +faster than \fB-B\fR). +.PP +The \fB-M\fR and \fB-m\fR options select Sparse Matrices +as internal data structure to find the encoding information (both are generally +slower than the default selection, but \fB-m\fR is generally +faster than \fB-M\fR). If \fB-M\fR is selected, then \fB-o\fR can be used to +define some further internal options (this is strongly discouraged). +.PP +The \fB-G\fR and \fB-g\fR options select a greedy (\fB-g\fR) or very greedy +(\fB-G\fR) heuristic +to find the encoding information (both faster and looser than the default +selection). +.PP +The \fB-u\fR option selects a generally slower +heuristic to find the encoding information. +.PP +The \fB-c\fR option allows to use a different minimizer from the default +choice. The minimizer must be able to read and write .kiss format and to write +equivalence class information in the output file, in the following format: +.br +#begin_classes <number of classes> +.br +# <state name> <class number> +.br + ... +.br +#end_classes +.PP +The \fB-p\fR option avoids calling the minimizer altogether, just reading in +the specified minimized file (in .kiss format with equivalence class +information). diff --git a/sis/sis_lib/help/astg_state_min.fmt b/sis/sis_lib/help/astg_state_min.fmt new file mode 100644 index 0000000..d9f2e17 --- /dev/null +++ b/sis/sis_lib/help/astg_state_min.fmt @@ -0,0 +1,81 @@ + + July 1, 1994 SIS(1) + + astg_state_min [-v debug_level] [-p minimized_file] [-c "command"] [-b|-B] + [-g|-G] [-u] [-m|-M] [-o #] [-f signal_cost_file] + + Minimizes the current State Transition Graph and derives the information + required to encode the associated Signal Transition Graph. The complete + sequence of actions to implement a Signal Transition Graph that does not + have Complete State Coding is as follows: + + astg_to_stg -m + astg_state_min + astg_encode + astg_add_state + + astg_to_f + ... + + The -f option selects a signal cost file. This file should contain one + line of the form + <signal name> <cost> + (e.g. "bus_ack 10") for each signal in the ASTG. The encoding algorithm + minimizes the sum of the weights of signals that follow state transi- + tions. Hence this file can be used to strongly favor or disfavor chang- + ing the predecessors of the transitions of a signal. + + By default, output signals have a cost of one and input signals have a + cost equal to the number of output signals plus one. In this way, no + input signal is constrained, if possible. + + The command may emit a series of diagnostic messages of the form: + warning: the STG may not be live (multiple exit point): may need con- + straint <signal 1> -> <signal 2> + These messages may or may not cause a failure (diagnosed as internal + error) later on during astg_add_state. In case of failure, one of the + required constraints (ideally the constraint that least decreases the + circuit performance due to the reduction in concurrency) should be added + to the ASTG. The procedure should be repeated until no more such mes- + sages occur. + + The options listed below are not generally useful except for debugging + purposes or to obtain faster (but potentially less optimal) results for + large Signal Transition Graphs. All algorithm speed indications reflect + average case analysis. + + The -B and -b options select Binary Decision Diagrams as internal data + structure to find the encoding information (both are generally slower + than the default selection, but -b is generally faster than -B). + + The -M and -m options select Sparse Matrices as internal data structure + to find the encoding information (both are generally slower than the + default selection, but -m is generally faster than -M). If -M is + selected, then -o can be used to define some further internal options + (this is strongly discouraged). + + 1 + + SIS(1) July 1, 1994 + + The -G and -g options select a greedy (-g) or very greedy (-G) heuristic + to find the encoding information (both faster and looser than the + default selection). + + The -u option selects a generally slower heuristic to find the encoding + information. + + The -c option allows to use a different minimizer from the default + choice. The minimizer must be able to read and write .kiss format and to + write equivalence class information in the output file, in the following + format: + #begin_classes <number of classes> + # <state name> <class number> + ... + #end_classes + + The -p option avoids calling the minimizer altogether, just reading in + the specified minimized file (in .kiss format with equivalence class + information). + + 2 diff --git a/sis/sis_lib/help/astg_stg_scr.1 b/sis/sis_lib/help/astg_stg_scr.1 new file mode 100644 index 0000000..967eaea --- /dev/null +++ b/sis/sis_lib/help/astg_stg_scr.1 @@ -0,0 +1,19 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_stg_scr.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:45 $ +.\" * +.\" +.XX +astg_stg_scr [-v debug_level] +.PP +Transforms the current State Transition Graph into one that satisfies the +Single Cube Restriction. +.PP +The Single Cube Restriction means that each state has exactly one associated +value of input signals under which it is entered. The result is accomplished by +state duplication, but the result may be non-minimal. +This command is required (and useful) before \fBstg_to_astg\fR. diff --git a/sis/sis_lib/help/astg_stg_scr.fmt b/sis/sis_lib/help/astg_stg_scr.fmt new file mode 100644 index 0000000..e581bc2 --- /dev/null +++ b/sis/sis_lib/help/astg_stg_scr.fmt @@ -0,0 +1,14 @@ + + July 1, 1994 SIS(1) + + astg_stg_scr [-v debug_level] + + Transforms the current State Transition Graph into one that satisfies + the Single Cube Restriction. + + The Single Cube Restriction means that each state has exactly one asso- + ciated value of input signals under which it is entered. The result is + accomplished by state duplication, but the result may be non-minimal. + This command is required (and useful) before stg_to_astg. + + 1 diff --git a/sis/sis_lib/help/astg_syn.1 b/sis/sis_lib/help/astg_syn.1 new file mode 100644 index 0000000..c3f6421 --- /dev/null +++ b/sis/sis_lib/help/astg_syn.1 @@ -0,0 +1,45 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_syn.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_syn [-m] [-r] [-v debug_level] [-x] +.PP +Synthesize from the current signal transition graph a two-level implementation +which is hazard-free under the unbounded gate delay model (i.e., gates have +unbounded delays, wires have zero delays). +.PP +The synthesis is performed in two steps. The first step derives a +state graph from the ASTG by performing a reachability analysis. If no +initial marking is given, then \fBastg_syn\fR will try to find a live, +safe initial marking. The second step uses the state graph generated +in step one to perform hazard analysis and synthesis. All static +hazards and critical races are removed. \fBastg_syn\fR tries to +remove all dynamic hazards arising from multiple input or output +changes. When it cannot remove such hazards, it will print the terms +which can potentially produce hazards and the conditions under which +hazards can be produced. From this user can remove the dynamic +hazards by removing some concurrency. +The resulting implementation may be neither prime nor irredundant. +.PP +The following options are not intended for general use. +.PP +The \fB-m\fR does not perform cube reduction and always returns a +prime cover implementation free of static hazards. As a consequence, +dynamic hazards due to multiple input/output changes may not be +removed. +.PP +The \fB-r\fR option runs ESPRESSO in single-output mode. +The implementation will be prime and irredundant, but may have static hazards +and dynamic hazards. +.PP +The \fB-v\fR option specifies the debug level. +.PP +The \fB-x\fR assumes that a state graph has already been derived, and +perform synthesis directly from the given state graph. State graph can be +derived by using \fB_astg_flow\fR. diff --git a/sis/sis_lib/help/astg_syn.fmt b/sis/sis_lib/help/astg_syn.fmt new file mode 100644 index 0000000..35bf8c0 --- /dev/null +++ b/sis/sis_lib/help/astg_syn.fmt @@ -0,0 +1,39 @@ + + July 1, 1994 SIS(1) + + astg_syn [-m] [-r] [-v debug_level] [-x] + + Synthesize from the current signal transition graph a two-level imple- + mentation which is hazard-free under the unbounded gate delay model + (i.e., gates have unbounded delays, wires have zero delays). + + The synthesis is performed in two steps. The first step derives a state + graph from the ASTG by performing a reachability analysis. If no ini- + tial marking is given, then astg_syn will try to find a live, safe ini- + tial marking. The second step uses the state graph generated in step + one to perform hazard analysis and synthesis. All static hazards and + critical races are removed. astg_syn tries to remove all dynamic + hazards arising from multiple input or output changes. When it cannot + remove such hazards, it will print the terms which can potentially pro- + duce hazards and the conditions under which hazards can be produced. + From this user can remove the dynamic hazards by removing some con- + currency. The resulting implementation may be neither prime nor + irredundant. + + The following options are not intended for general use. + + The -m does not perform cube reduction and always returns a prime cover + implementation free of static hazards. As a consequence, dynamic + hazards due to multiple input/output changes may not be removed. + + The -r option runs ESPRESSO in single-output mode. The implementation + will be prime and irredundant, but may have static hazards and dynamic + hazards. + + The -v option specifies the debug level. + + The -x assumes that a state graph has already been derived, and perform + synthesis directly from the given state graph. State graph can be + derived by using _astg_flow. + + 1 diff --git a/sis/sis_lib/help/astg_to_f.1 b/sis/sis_lib/help/astg_to_f.1 new file mode 100644 index 0000000..f030c0c --- /dev/null +++ b/sis/sis_lib/help/astg_to_f.1 @@ -0,0 +1,72 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_to_f.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_to_f [-v debug_level] [-r] [-s signal_name] [-d] +.PP +Generate an initial two-level implementation of each output signal specified by +the current Signal Transition Graph. +.PP +If the initial marking is not defined, then a valid marking is searched for. +The list of potential hazards, used by \fBastg_slow\fR, is also produced. +.PP +One primary input is generated for each signal (both input and output) +specified by the ASTG, with the same name as the signal (and "_" appended if the +signal is an output). +.PP +One primary output is generated for each output signal +specified by the ASTG, with the same name as the signal. +The primary output is driven directly by the primary input. +.PP +One asynchronous latch is generated for each output signal specified by the +ASTG, connecting the combinational logic function implementing the signal (a +"fake" primary output with the same name as the signal and "_next" appended) and +the corresponding primary input. +.PP +If some signal is not used inside the combinational logic, then the +corresponding primary input and latch is not created (unless the option +\fB-r\fR is specified). +.PP +The \fB-s\fR option adds a set of fake primary outputs that ensure that the +named signal is implemented as a Set-Reset flip-flop. If, in addition, +the \fB-d\fR option is specified, the functions for the Set and Reset input are +made disjoint. This may increase the implementation cost, but reduces its +sensitivity to dynamic hazards. +.PP +An error message results if either no valid marking is found (in which case it +might be advisable to define it in the ASTG specification file) or the ASTG does +not have the Compatible State Coding property (i.e. if two markings with +different sets of enabled output signals have the same binary label). +See \fBastg_state_min\fR for a recommended action in the latter case. +.PP +A typical ASTG synthesis and optimization script should look like: +.br +astg_to_f +.br + +.br +gkx -ab +.br +resub -ad; sweep +.br +gcx -b +.br +resub -ad; sweep +.br +eliminate 0 +.br +decomp -g * +.br +eliminate -1 +.br + +.br +map +.br +astg_slow diff --git a/sis/sis_lib/help/astg_to_f.fmt b/sis/sis_lib/help/astg_to_f.fmt new file mode 100644 index 0000000..5f3e114 --- /dev/null +++ b/sis/sis_lib/help/astg_to_f.fmt @@ -0,0 +1,57 @@ + + July 1, 1994 SIS(1) + + astg_to_f [-v debug_level] [-r] [-s signal_name] [-d] + + Generate an initial two-level implementation of each output signal + specified by the current Signal Transition Graph. + + If the initial marking is not defined, then a valid marking is searched + for. The list of potential hazards, used by astg_slow, is also pro- + duced. + + One primary input is generated for each signal (both input and output) + specified by the ASTG, with the same name as the signal (and "_" + appended if the signal is an output). + + One primary output is generated for each output signal specified by the + ASTG, with the same name as the signal. The primary output is driven + directly by the primary input. + + One asynchronous latch is generated for each output signal specified by + the ASTG, connecting the combinational logic function implementing the + signal (a "fake" primary output with the same name as the signal and + "_next" appended) and the corresponding primary input. + + If some signal is not used inside the combinational logic, then the + corresponding primary input and latch is not created (unless the option + -r is specified). + + The -s option adds a set of fake primary outputs that ensure that the + named signal is implemented as a Set-Reset flip-flop. If, in addition, + the -d option is specified, the functions for the Set and Reset input + are made disjoint. This may increase the implementation cost, but + reduces its sensitivity to dynamic hazards. + + An error message results if either no valid marking is found (in which + case it might be advisable to define it in the ASTG specification file) + or the ASTG does not have the Compatible State Coding property (i.e. if + two markings with different sets of enabled output signals have the same + binary label). See astg_state_min for a recommended action in the + latter case. + + A typical ASTG synthesis and optimization script should look like: + astg_to_f + + gkx -ab + resub -ad; sweep + gcx -b + resub -ad; sweep + eliminate 0 + decomp -g * + eliminate -1 + + map + astg_slow + + 1 diff --git a/sis/sis_lib/help/astg_to_stg.1 b/sis/sis_lib/help/astg_to_stg.1 new file mode 100644 index 0000000..c5ddf67 --- /dev/null +++ b/sis/sis_lib/help/astg_to_stg.1 @@ -0,0 +1,26 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/astg_to_stg.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +astg_to_stg [-v debug_level] [-m] +.PP +Generate a State Transition Graph +from the current Signal Transition Graph. +The State Transition Graph has one input signal for each signal in the Signal +Transition Graph (both input and output), and one output signal for each output +signal in the Signal Transition Graph. +.PP +If the initial marking is not defined, then a valid marking is searched for. +.PP +An error message results if no valid marking is found (in which case it +might be advisable to define it in the ASTG specification file). +.PP +The \fB-m\fR option additionally performs a pre-minimization step that produces +a State Transition Graph suitable for subsequent state encoding commands (such +as, e.g., \fBastg_state_min\fR). diff --git a/sis/sis_lib/help/astg_to_stg.fmt b/sis/sis_lib/help/astg_to_stg.fmt new file mode 100644 index 0000000..9ea5c6a --- /dev/null +++ b/sis/sis_lib/help/astg_to_stg.fmt @@ -0,0 +1,21 @@ + + July 1, 1994 SIS(1) + + astg_to_stg [-v debug_level] [-m] + + Generate a State Transition Graph from the current Signal Transition + Graph. The State Transition Graph has one input signal for each signal + in the Signal Transition Graph (both input and output), and one output + signal for each output signal in the Signal Transition Graph. + + If the initial marking is not defined, then a valid marking is searched + for. + + An error message results if no valid marking is found (in which case it + might be advisable to define it in the ASTG specification file). + + The -m option additionally performs a pre-minimization step that pro- + duces a State Transition Graph suitable for subsequent state encoding + commands (such as, e.g., astg_state_min). + + 1 diff --git a/sis/sis_lib/help/atpg.1 b/sis/sis_lib/help/atpg.1 new file mode 100644 index 0000000..f14ff53 --- /dev/null +++ b/sis/sis_lib/help/atpg.1 @@ -0,0 +1,69 @@ +.XX +atpg [-fFhrRpt] [-d RTG_depth] [-n n_fault_sim] [-v verbosity_level] + [-y random_prop_depth] file +.PP +Perform test generation for both combinational and sequential circuits using +random test generation, deterministic test generation, and fault simulation. Deterministic test generation is accomplished by one of two methods. The +first method is a three-step test generation algorithm consisting of +combinational test generation (assuming that latch outputs are controllable, +and that latch inputs are observable), followed by state justification and propagation, when necessary. The combinational test generation is +accomplished using Boolean satisfiability. Justification and propagation are +performed using implicit state transition graph traversal techniques. If the +three-step method does not generate a test for a fault, then the product of +the good and faulty circuit is built and traversed, as in sequential circuit +verification. If this traversal proves the circuits equivalent, then the +fault is redundant; otherwise any differentiating sequence is a test for the +fault. +.PP +Fault collapsing is performed before test generation, across only simple +gates. Both fault equivalence and fault dominance are used to reduce the +fault list. +.PP +For combinational circuits, external don't cares are automatically taken +into account when the don't care network is attached to the care network. The PI's and PO's of the external don't care network (when it is not NIL) must match exactly with the care network. That is, the don't care network cannot specify only a subset of the PI's or PO's of the care network. If this condition is not met, +then the atpg package automatically adds dummy primary inputs and outputs to the +external don't care network. +.PP +Reverse fault simulation is performed as a post-processing step to reduce +test set size. +.PP +The \fB-f\fP option causes the atpg not to perform fault simulation of +deterministically-generated tests on untested faults. +.PP +The \fB-F\fP option causes the atpg not to use reverse fault simulation. +.PP +The \fB-h\fP option restricts the boolean satisfiability algorithm to not use +non-local implications. Four greedy ordering heuristics are tried in this case +instead of the default of eight. Hard-to-test faults that can only be tested +with non-local implication information are aborted by this option. +.PP +The \fB-r\fP option causes the atpg not to perform random test pattern +generation. +.PP +The \fB-R\fP option causes the atpg not to perform random propagation. +(Deterministic propagation is still attempted). +.PP +The \fB-p\fP option causes the atpg not to build any product machines. Thus, +neither deterministic propagation nor good/faulty product machine traversal +will be performed. +.PP +The \fB-t\fP option first converts the network to arbitrary fanin AND and +OR gates. The decomposed network is returned. +.PP +The \fB-d\fP option allows the specification of the length of the random +sequences applied during random test generation. The default length is +the depth of the circuit's state transition graph. +.PP +The \fB-n\fP option allows the specification of the number of sequences +to fault simulate at one time during fault simulation. The default is the +system word length. +.PP +The \fB-v\fP allows the specification of the verbosity level of the output. +.PP +The \fB-y\fP option allows the specification of the length of the random +sequences applied during random propagation. The default length is 20. +.PP +If \fBfile\fP is specified, test patterns are written out to the given file. +.PP +Note: in order to use this command with sequential circuits, the circuit +reset state must be specified in the circuit input file. diff --git a/sis/sis_lib/help/atpg.fmt b/sis/sis_lib/help/atpg.fmt new file mode 100644 index 0000000..a95b39d --- /dev/null +++ b/sis/sis_lib/help/atpg.fmt @@ -0,0 +1,85 @@ + + July 1, 1994 SIS(1) + + atpg [-fFhrRpt] [-d RTG_depth] [-n n_fault_sim] [-v verbosity_level] + [-y random_prop_depth] file + + Perform test generation for both combinational and sequential circuits + using random test generation, deterministic test generation, and fault + simulation. Deterministic test generation is accomplished by one of two + methods. The first method is a three-step test generation algorithm con- + sisting of combinational test generation (assuming that latch outputs + are controllable, and that latch inputs are observable), followed by + state justification and propagation, when necessary. The combinational + test generation is accomplished using Boolean satisfiability. Justifica- + tion and propagation are performed using implicit state transition graph + traversal techniques. If the three-step method does not generate a test + for a fault, then the product of the good and faulty circuit is built + and traversed, as in sequential circuit verification. If this traversal + proves the circuits equivalent, then the fault is redundant; otherwise + any differentiating sequence is a test for the fault. + + Fault collapsing is performed before test generation, across only simple + gates. Both fault equivalence and fault dominance are used to reduce the + fault list. + + For combinational circuits, external don't cares are automatically taken + into account when the don't care network is attached to the care net- + work. The PI's and PO's of the external don't care network (when it is + not NIL) must match exactly with the care network. That is, the don't + care network cannot specify only a subset of the PI's or PO's of the + care network. If this condition is not met, then the atpg package + automatically adds dummy primary inputs and outputs to the external + don't care network. + + Reverse fault simulation is performed as a post-processing step to + reduce test set size. + + The -f option causes the atpg not to perform fault simulation of + deterministically-generated tests on untested faults. + + The -F option causes the atpg not to use reverse fault simulation. + + The -h option restricts the boolean satisfiability algorithm to not use + non-local implications. Four greedy ordering heuristics are tried in + this case instead of the default of eight. Hard-to-test faults that can + only be tested with non-local implication information are aborted by + this option. + + The -r option causes the atpg not to perform random test pattern genera- + tion. + + The -R option causes the atpg not to perform random propagation. (Deter- + ministic propagation is still attempted). + + The -p option causes the atpg not to build any product machines. Thus, + neither deterministic propagation nor good/faulty product machine + + 1 + + SIS(1) July 1, 1994 + + traversal will be performed. + + The -t option first converts the network to arbitrary fanin AND and OR + gates. The decomposed network is returned. + + The -d option allows the specification of the length of the random + sequences applied during random test generation. The default length is + the depth of the circuit's state transition graph. + + The -n option allows the specification of the number of sequences to + fault simulate at one time during fault simulation. The default is the + system word length. + + The -v allows the specification of the verbosity level of the output. + + The -y option allows the specification of the length of the random + sequences applied during random propagation. The default length is 20. + + If file is specified, test patterns are written out to the given file. + + Note: in order to use this command with sequential circuits, the circuit + reset state must be specified in the circuit input file. + + 2 diff --git a/sis/sis_lib/help/bdsyn.1 b/sis/sis_lib/help/bdsyn.1 new file mode 100644 index 0000000..f9f02e2 --- /dev/null +++ b/sis/sis_lib/help/bdsyn.1 @@ -0,0 +1,13 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/bdsyn.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +bdsyn +.PP +A special command exported for use by bdsyn(1). Not for general use. diff --git a/sis/sis_lib/help/bdsyn.fmt b/sis/sis_lib/help/bdsyn.fmt new file mode 100644 index 0000000..6cc02e4 --- /dev/null +++ b/sis/sis_lib/help/bdsyn.fmt @@ -0,0 +1,8 @@ + + July 1, 1994 SIS(1) + + bdsyn + + A special command exported for use by bdsyn(1). Not for general use. + + 1 diff --git a/sis/sis_lib/help/buffer_opt.1 b/sis/sis_lib/help/buffer_opt.1 new file mode 100644 index 0000000..f8bbf4d --- /dev/null +++ b/sis/sis_lib/help/buffer_opt.1 @@ -0,0 +1,50 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/buffer_opt.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +buffer_opt [-l #] [-f #] [-c] [-d] [-T] [-L] [-v #] [-D] node-list +.PP +Builds fanout trees for the nodes in the \fBnode-list\fR. +If no nodes are specified selects the nodes to be buffered +in order to improve performance of the entire network. The +network is assumed to be mapped. +.PP +The \fB-l #\fR option specifies the number of fanouts which +a node can have so as to be eligible for buffering. The +default is 2, hence any multi-fanout node is a candidate for +buffering. +.PP +The \fB-f #\fR option specifies the transformations to use. Set the +three least significant bits indicate the use (value == 1) of +the transformations. xx1 to use the \fIrepower\fR transformation, +x1x to use an \fIunbalanced\fR transformation and 1xx to use the +\fIbalanced\fR distribution of signals. More than one transformation +can be set active. Thus to allow the algorithm full flexibility use +the value = 7 (111 in binary notation) which is also the default. +.PP +The \fB-c\fR option specifies that one pass be carried out. +The default is to iterate till no improvement is achieved. +.PP +The \fB-d\fR option allows the complex gates to be decomposed +into smaller ones so as to increase drive capability. By default +the complex gates are retained. +.PP +The \fB-L\fR option traverses the network from outputs to +inputs ensuring that for every node, the gate that implements it +does not drive a load greater than the \fImax_load\fR limit +specified for that gate. \fBTHIS OPTION IS NOT YET IMPLEMENTED\fR. +.PP +The \fB-T\fR option displays the circuit performance as the +iterations progress. If the required times at the outputs are +not specified the circuit delay is shown, else the minimum +slack value is displayed. +.PP +The \fB-v #,-D\fR option are for debugging. The \fB-v #\fR option +is the most verbose and the amount of verbosity can be increased +by letting the argument for \fB-v\fR range from 1 to 100. diff --git a/sis/sis_lib/help/buffer_opt.fmt b/sis/sis_lib/help/buffer_opt.fmt new file mode 100644 index 0000000..4fb1af6 --- /dev/null +++ b/sis/sis_lib/help/buffer_opt.fmt @@ -0,0 +1,42 @@ + + July 1, 1994 SIS(1) + + buffer_opt [-l #] [-f #] [-c] [-d] [-T] [-L] [-v #] [-D] node-list + + Builds fanout trees for the nodes in the node-list. If no nodes are + specified selects the nodes to be buffered in order to improve perfor- + mance of the entire network. The network is assumed to be mapped. + + The -l # option specifies the number of fanouts which a node can have so + as to be eligible for buffering. The default is 2, hence any multi- + fanout node is a candidate for buffering. + + The -f # option specifies the transformations to use. Set the three + least significant bits indicate the use (value == 1) of the transforma- + tions. xx1 to use the _r_e_p_o_w_e_r transformation, x1x to use an _u_n_b_a_l_a_n_c_e_d + transformation and 1xx to use the _b_a_l_a_n_c_e_d distribution of signals. More + than one transformation can be set active. Thus to allow the algorithm + full flexibility use the value = 7 (111 in binary notation) which is + also the default. + + The -c option specifies that one pass be carried out. The default is to + iterate till no improvement is achieved. + + The -d option allows the complex gates to be decomposed into smaller + ones so as to increase drive capability. By default the complex gates + are retained. + + The -L option traverses the network from outputs to inputs ensuring that + for every node, the gate that implements it does not drive a load + greater than the _m_a_x__l_o_a_d limit specified for that gate. THIS OPTION IS + NOT YET IMPLEMENTED. + + The -T option displays the circuit performance as the iterations pro- + gress. If the required times at the outputs are not specified the cir- + cuit delay is shown, else the minimum slack value is displayed. + + The -v #,-D option are for debugging. The -v # option is the most ver- + bose and the amount of verbosity can be increased by letting the argu- + ment for -v range from 1 to 100. + + 1 diff --git a/sis/sis_lib/help/c_check.1 b/sis/sis_lib/help/c_check.1 new file mode 100644 index 0000000..d6b4816 --- /dev/null +++ b/sis/sis_lib/help/c_check.1 @@ -0,0 +1,14 @@ +.XX +c_check -[nd] -[SH]#.# +.PP +Verifies that the given circuit satisfies the constraints for correct +clocking. By default the circuit is assumed to be mapped to a library. +Use the \fB-n\fR option to use the \fIunit-fanout\fR delay model. +.PP +The user can give global set-up (and hold) times for all memory +elements using the \fB-S\fR (\fB-H\fR) option. By default it computes +the set-up and hold times from the library. \fIIf the optimal clocking +scheme was found using the c_opt command\fR make sure you use the same +delay model! +.PP +The \fB-d value\fR selects the debug level. The range is 1-5. diff --git a/sis/sis_lib/help/c_check.fmt b/sis/sis_lib/help/c_check.fmt new file mode 100644 index 0000000..b1205de --- /dev/null +++ b/sis/sis_lib/help/c_check.fmt @@ -0,0 +1,17 @@ + + July 1, 1994 SIS(1) + + c_check -[nd] -[SH]#.# + + Verifies that the given circuit satisfies the constraints for correct + clocking. By default the circuit is assumed to be mapped to a library. + Use the -n option to use the _u_n_i_t-_f_a_n_o_u_t delay model. + + The user can give global set-up (and hold) times for all memory elements + using the -S (-H) option. By default it computes the set-up and hold + times from the library. _I_f _t_h_e _o_p_t_i_m_a_l _c_l_o_c_k_i_n_g _s_c_h_e_m_e _w_a_s _f_o_u_n_d _u_s_i_n_g + _t_h_e _c__o_p_t _c_o_m_m_a_n_d make sure you use the same delay model! + + The -d value selects the debug level. The range is 1-5. + + 1 diff --git a/sis/sis_lib/help/c_opt.1 b/sis/sis_lib/help/c_opt.1 new file mode 100644 index 0000000..8297819 --- /dev/null +++ b/sis/sis_lib/help/c_opt.1 @@ -0,0 +1,39 @@ +.XX +c_opt -[nGI] -[dSHmM]#.# +.PP +Computes the optimal clock for a given clocking scheme. +Finds rise and fall times for the clock events. A single clock +multi-phase clocking scheme is assumed. +.PP +The algorithm works on mapped and unmapped networks (default is +mapped). Note that to ensure every node is mapped, you should read in +the blif file, read in the library, map the circuit and then run the +optimal clocking algorithm. \fIIt is a known fact that reading in a +mapped netlist often causes some nodes to remain un-mapped\fR. The +command will abort in such a case. The \fB-n\fR option is used for the +\fIunit-fanout\fR delay model. +.PP +By default the algorithm uses a special Linear program solver based on the +Floyd-Warshall algorithm. An alternate formulation using binary search +is available (\fB-B\fR) as long as \fIno minimum duty cycle constraints +are imposed\fR. +.PP +The \fB-I\fR option is used for \fI2 phase inverted clocking schemes only\fR. +.PP +The user can give global set-up (and hold) times for all memory +elements using the \fB-S\fR (\fB-H\fR) option. By default it computes +the set-up and hold times from the library. +.PP +The \fB-m\fR option permits the user to specify a minimum phase +separation as a fraction of the clock cycle. Similarly the \fB-M\fR +option sets the maximum phase separation as a fraction of the clock +cycle. +.PP +The \fB-d value\fR selects the debug level (range 0-4). + +This routine runs faster (upto 2X) when compiled with the priority +queue library from octtools (use flag -DOCT when compiling this +directory). + + + diff --git a/sis/sis_lib/help/c_opt.fmt b/sis/sis_lib/help/c_opt.fmt new file mode 100644 index 0000000..24dba8c --- /dev/null +++ b/sis/sis_lib/help/c_opt.fmt @@ -0,0 +1,37 @@ + + July 1, 1994 SIS(1) + + c_opt -[nGI] -[dSHmM]#.# + + Computes the optimal clock for a given clocking scheme. Finds rise and + fall times for the clock events. A single clock multi-phase clocking + scheme is assumed. + + The algorithm works on mapped and unmapped networks (default is mapped). + Note that to ensure every node is mapped, you should read in the blif + file, read in the library, map the circuit and then run the optimal + clocking algorithm. _I_t _i_s _a _k_n_o_w_n _f_a_c_t _t_h_a_t _r_e_a_d_i_n_g _i_n _a _m_a_p_p_e_d _n_e_t_l_i_s_t + _o_f_t_e_n _c_a_u_s_e_s _s_o_m_e _n_o_d_e_s _t_o _r_e_m_a_i_n _u_n-_m_a_p_p_e_d. The command will abort in + such a case. The -n option is used for the _u_n_i_t-_f_a_n_o_u_t delay model. + + By default the algorithm uses a special Linear program solver based on + the Floyd-Warshall algorithm. An alternate formulation using binary + search is available (-B) as long as _n_o _m_i_n_i_m_u_m _d_u_t_y _c_y_c_l_e _c_o_n_s_t_r_a_i_n_t_s + _a_r_e _i_m_p_o_s_e_d. + + The -I option is used for _2 _p_h_a_s_e _i_n_v_e_r_t_e_d _c_l_o_c_k_i_n_g _s_c_h_e_m_e_s _o_n_l_y. + + The user can give global set-up (and hold) times for all memory elements + using the -S (-H) option. By default it computes the set-up and hold + times from the library. + + The -m option permits the user to specify a minimum phase separation as + a fraction of the clock cycle. Similarly the -M option sets the maximum + phase separation as a fraction of the clock cycle. + + The -d value selects the debug level (range 0-4). + + This routine runs faster (upto 2X) when compiled with the priority queue + library from octtools (use flag -DOCT when compiling this directory). + + 1 diff --git a/sis/sis_lib/help/chng_clock.1 b/sis/sis_lib/help/chng_clock.1 new file mode 100644 index 0000000..55bc765 --- /dev/null +++ b/sis/sis_lib/help/chng_clock.1 @@ -0,0 +1,22 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/chng_clock.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +chng_clock +.PP +Toggles the setting of the clock between the user-specified +clock settings (specified in the blif file) and the working +values (generated by algorithms inside \fBSIS\fR). +.PP +All algorithms use the current setting as input. If the +algorithms modify the clocking scheme or the cycle-time they +write the modified clocking scheme into the working fields. +Thus, to write out the blif file containing the clock scheme +generated by algorithms inside \fBSIS\fR, the setting must first be +set to the working one and then \fBwrite_blif\fR must be invoked. diff --git a/sis/sis_lib/help/chng_clock.fmt b/sis/sis_lib/help/chng_clock.fmt new file mode 100644 index 0000000..535d716 --- /dev/null +++ b/sis/sis_lib/help/chng_clock.fmt @@ -0,0 +1,17 @@ + + July 1, 1994 SIS(1) + + chng_clock + + Toggles the setting of the clock between the user-specified clock set- + tings (specified in the blif file) and the working values (generated by + algorithms inside SIS). + + All algorithms use the current setting as input. If the algorithms + modify the clocking scheme or the cycle-time they write the modified + clocking scheme into the working fields. Thus, to write out the blif + file containing the clock scheme generated by algorithms inside SIS, the + setting must first be set to the working one and then write_blif must be + invoked. + + 1 diff --git a/sis/sis_lib/help/chng_name.1 b/sis/sis_lib/help/chng_name.1 new file mode 100644 index 0000000..1a8637f --- /dev/null +++ b/sis/sis_lib/help/chng_name.1 @@ -0,0 +1,15 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/chng_name.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +chng_name +.PP +Toggles the network between +long-name mode (user supplied names) and short-name mode +(automatically generated single-character names). diff --git a/sis/sis_lib/help/chng_name.fmt b/sis/sis_lib/help/chng_name.fmt new file mode 100644 index 0000000..b589fa9 --- /dev/null +++ b/sis/sis_lib/help/chng_name.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + chng_name + + Toggles the network between long-name mode (user supplied names) and + short-name mode (automatically generated single-character names). + + 1 diff --git a/sis/sis_lib/help/collapse.1 b/sis/sis_lib/help/collapse.1 new file mode 100644 index 0000000..c83ff2d --- /dev/null +++ b/sis/sis_lib/help/collapse.1 @@ -0,0 +1,31 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/collapse.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +collapse [n1] [n2] +.PP +Collapse nodes in the network. With no arguments, the entire network is +collapsed into a single-level of functions (i.e., two-level form). +Each output will be expressed in terms of the primary inputs. +.PP +Given a single node, +that function is collapsed until it is represented entirely in terms of +primary inputs. +.PP +Given two arguments, it is assumed that the second node +is a fanin of the first node. In this case, this dependency is removed +(the first node is expressed without the second node as a fanin). +.PP +Please note that this command negates any mapping that may have been done +at an earlier time. +.PP +Caution should be taken when collapsing network to two levels because +the two level representation may be too large. +The alternative is to use \fBeliminate\fR (selective collapse). +Refer to \fBeliminate\fR for the details. diff --git a/sis/sis_lib/help/collapse.fmt b/sis/sis_lib/help/collapse.fmt new file mode 100644 index 0000000..b8a3852 --- /dev/null +++ b/sis/sis_lib/help/collapse.fmt @@ -0,0 +1,24 @@ + + July 1, 1994 SIS(1) + + collapse [n1] [n2] + + Collapse nodes in the network. With no arguments, the entire network is + collapsed into a single-level of functions (i.e., two-level form). Each + output will be expressed in terms of the primary inputs. + + Given a single node, that function is collapsed until it is represented + entirely in terms of primary inputs. + + Given two arguments, it is assumed that the second node is a fanin of + the first node. In this case, this dependency is removed (the first + node is expressed without the second node as a fanin). + + Please note that this command negates any mapping that may have been + done at an earlier time. + + Caution should be taken when collapsing network to two levels because + the two level representation may be too large. The alternative is to + use eliminate (selective collapse). Refer to eliminate for the details. + + 1 diff --git a/sis/sis_lib/help/constraints.1 b/sis/sis_lib/help/constraints.1 new file mode 100644 index 0000000..dce24d2 --- /dev/null +++ b/sis/sis_lib/help/constraints.1 @@ -0,0 +1,16 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/constraints.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:35 $ +.\" * +.\" +.XX +constraints [node_1....node_n] +.PP +Print the values of the various delay constraints for the nodes in the +argument list, which must be either inputs or outputs. Also prints +the default values of the default delay parameters for the network. +Used to check the values set by \fBset_delay\fR. diff --git a/sis/sis_lib/help/constraints.fmt b/sis/sis_lib/help/constraints.fmt new file mode 100644 index 0000000..35581c0 --- /dev/null +++ b/sis/sis_lib/help/constraints.fmt @@ -0,0 +1,11 @@ + + July 1, 1994 SIS(1) + + constraints [node_1....node_n] + + Print the values of the various delay constraints for the nodes in the + argument list, which must be either inputs or outputs. Also prints the + default values of the default delay parameters for the network. Used to + check the values set by set_delay. + + 1 diff --git a/sis/sis_lib/help/decomp.1 b/sis/sis_lib/help/decomp.1 new file mode 100644 index 0000000..174bb61 --- /dev/null +++ b/sis/sis_lib/help/decomp.1 @@ -0,0 +1,44 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/decomp.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +decomp [-gqd] [node-list] +.PP +Decompose all the nodes in the \fBnode-list\fR. If the \fBnode-list\fR +is not specified, all the nodes in the current network will be +decomposed. Decompostion will factor nodes and make the divisor a new +node within the network, re-expressing other nodes in terms of this +newly introduced node. It is one of the transforms used to break +down large functions into smaller pieces, usually at the cost of +introducing a few more literals. +.PP +If the \fB-q\fR option (the default) is specified, the \fIquick decomp\fR +algorithm is used which +extracts out an \fIarbitrary\fR kernel successively. Because +of the fast algorithm for generating an arbitrary kernel, +\fBdecomp -q\fR is very fast compared with the \fBdecomp -g\fR. +In most cases, the result is very close. +This command is recommended at the early phase of the optimization. +.PP +If the \fB-g\fR option is specified, the \fIgood decomp\fR +algorithm is used which +successively extracts out the \fIbest kernel\fR until the function is +factor free, and applies the same algorithm to all the kernels just extracted. +This operation will give the best \fIalgebraic\fR decomposition for the nodes. +But, since it generates all the kernels at each step, it takes more +CPU time. In general, \fBdecomp -q\fR should be used in the early +stage of the optimization. Only at the end of the optimization, should +\fBdecomp -g\fR be used. +.PP +If the \fB-d\fR option is specified, the disjoint decomposition +is performed. Currently, the disjoint decomposition is limited +to the following simple algorithm: It partitions the cubes +into sets of cubes having disjoint variable support, creates +one node for each partition, and a node (the root of the +decomposition) which is the OR of all the partitions. diff --git a/sis/sis_lib/help/decomp.fmt b/sis/sis_lib/help/decomp.fmt new file mode 100644 index 0000000..fd9d859 --- /dev/null +++ b/sis/sis_lib/help/decomp.fmt @@ -0,0 +1,36 @@ + + July 1, 1994 SIS(1) + + decomp [-gqd] [node-list] + + Decompose all the nodes in the node-list. If the node-list is not + specified, all the nodes in the current network will be decomposed. + Decompostion will factor nodes and make the divisor a new node within + the network, re-expressing other nodes in terms of this newly introduced + node. It is one of the transforms used to break down large functions + into smaller pieces, usually at the cost of introducing a few more + literals. + + If the -q option (the default) is specified, the _q_u_i_c_k _d_e_c_o_m_p algorithm + is used which extracts out an _a_r_b_i_t_r_a_r_y kernel successively. Because of + the fast algorithm for generating an arbitrary kernel, decomp -q is very + fast compared with the decomp -g. In most cases, the result is very + close. This command is recommended at the early phase of the optimiza- + tion. + + If the -g option is specified, the _g_o_o_d _d_e_c_o_m_p algorithm is used which + successively extracts out the _b_e_s_t _k_e_r_n_e_l until the function is factor + free, and applies the same algorithm to all the kernels just extracted. + This operation will give the best _a_l_g_e_b_r_a_i_c decomposition for the nodes. + But, since it generates all the kernels at each step, it takes more CPU + time. In general, decomp -q should be used in the early stage of the + optimization. Only at the end of the optimization, should decomp -g be + used. + + If the -d option is specified, the disjoint decomposition is performed. + Currently, the disjoint decomposition is limited to the following simple + algorithm: It partitions the cubes into sets of cubes having disjoint + variable support, creates one node for each partition, and a node (the + root of the decomposition) which is the OR of all the partitions. + + 1 diff --git a/sis/sis_lib/help/echo.1 b/sis/sis_lib/help/echo.1 new file mode 100644 index 0000000..883c00c --- /dev/null +++ b/sis/sis_lib/help/echo.1 @@ -0,0 +1,13 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/echo.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +echo args ... +.PP +Echoes the arguments to standard output. diff --git a/sis/sis_lib/help/echo.fmt b/sis/sis_lib/help/echo.fmt new file mode 100644 index 0000000..2235083 --- /dev/null +++ b/sis/sis_lib/help/echo.fmt @@ -0,0 +1,8 @@ + + July 1, 1994 SIS(1) + + echo args ... + + Echoes the arguments to standard output. + + 1 diff --git a/sis/sis_lib/help/eliminate.1 b/sis/sis_lib/help/eliminate.1 new file mode 100644 index 0000000..f4fbd35 --- /dev/null +++ b/sis/sis_lib/help/eliminate.1 @@ -0,0 +1,31 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/eliminate.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +eliminate [-l limit] thresh +.PP +Eliminate all the nodes in the network whose +value is less than or equal to \fBthresh\fR. +The value of a node represents the number of literals saved +in the literal count for the network by leaving the +node in the network. +If the value is less than (or equal to) the threshold, the node +will be eliminated by collapsing the node into each of its fanouts. +A primary input or a primary output will not be eliminated. +.PP +The value of the node is approximated based on +the number of times the node is used +in the factored form for each of its fanouts. +Note that if a node is used only once, its value is always -1. +.PP +\fBlimit\fR is used to control the maximum number of cubes +in any node. The default is 1000. Using a very large \fBlimit\fR +may result in collapsing the network to two levels. In general, +if the circuit is collapsible, the command \fBcollapse\fR is +more efficient. diff --git a/sis/sis_lib/help/eliminate.fmt b/sis/sis_lib/help/eliminate.fmt new file mode 100644 index 0000000..1be5810 --- /dev/null +++ b/sis/sis_lib/help/eliminate.fmt @@ -0,0 +1,22 @@ + + July 1, 1994 SIS(1) + + eliminate [-l limit] thresh + + Eliminate all the nodes in the network whose value is less than or equal + to thresh. The value of a node represents the number of literals saved + in the literal count for the network by leaving the node in the network. + If the value is less than (or equal to) the threshold, the node will be + eliminated by collapsing the node into each of its fanouts. A primary + input or a primary output will not be eliminated. + + The value of the node is approximated based on the number of times the + node is used in the factored form for each of its fanouts. Note that if + a node is used only once, its value is always -1. + + limit is used to control the maximum number of cubes in any node. The + default is 1000. Using a very large limit may result in collapsing the + network to two levels. In general, if the circuit is collapsible, the + command collapse is more efficient. + + 1 diff --git a/sis/sis_lib/help/env_seq_dc.1 b/sis/sis_lib/help/env_seq_dc.1 new file mode 100644 index 0000000..ab4794a --- /dev/null +++ b/sis/sis_lib/help/env_seq_dc.1 @@ -0,0 +1,32 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/env_seq_dc.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:43 $ +.\" * +.\" +.XX +env_seq_dc [-v n] filename.blif +.PP +This command extracts sequential don't cares based on unreachable +states. It builds the product of the current network with the network +passed as argument, computes the set of reachable states of the +product, extracts from that the set of reachable states of the +original network, and uses its complement to build a don't care +network for the current network. Any previous don't care network is +discarded. +.PP +\fBfull_simplify\fR or \fBequiv_nets\fR should be run afterwards to +exploit these don't cares. +.PP +External inputs of the current network are connected to matching +external outputs of the network passed as argument and vice-versa. +Nodes match if and only if they have the same name. +.PP +\fB-v\fR allows the specification of the verbosity level of the output. +The default value is 0. +.PP +The method used to compute the set of reachable states is the +\fBproduct\fR method. See \fBextract_seq_dc\fR for details. diff --git a/sis/sis_lib/help/env_seq_dc.fmt b/sis/sis_lib/help/env_seq_dc.fmt new file mode 100644 index 0000000..fa5e88d --- /dev/null +++ b/sis/sis_lib/help/env_seq_dc.fmt @@ -0,0 +1,26 @@ + + July 1, 1994 SIS(1) + + env_seq_dc [-v n] filename.blif + + This command extracts sequential don't cares based on unreachable + states. It builds the product of the current network with the network + passed as argument, computes the set of reachable states of the product, + extracts from that the set of reachable states of the original network, + and uses its complement to build a don't care network for the current + network. Any previous don't care network is discarded. + + full_simplify or equiv_nets should be run afterwards to exploit these + don't cares. + + External inputs of the current network are connected to matching exter- + nal outputs of the network passed as argument and vice-versa. Nodes + match if and only if they have the same name. + + -v allows the specification of the verbosity level of the output. The + default value is 0. + + The method used to compute the set of reachable states is the product + method. See extract_seq_dc for details. + + 1 diff --git a/sis/sis_lib/help/env_verify_fsm.1 b/sis/sis_lib/help/env_verify_fsm.1 new file mode 100644 index 0000000..b395221 --- /dev/null +++ b/sis/sis_lib/help/env_verify_fsm.1 @@ -0,0 +1,33 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/env_verify_fsm.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:44 $ +.\" * +.\" +.XX +env_verify_fsm [-v n] [-V] fsm.blif env.blif +.PP +Verify the equivalence of two synchronous networks in a given environment. +The current network is compared with \fBfsm.blif\fR under the +environment defined by the \fBenv.blif\fR network. +The environment is a sequential circuit that generates the inputs of +the circuits under verification, and possibly takes some inputs from +them. What is verified is that the current network and the +\fBfsm.blif\fR network are substituable for one another when used in +the context of the \fBenv.blif\fR network. +.PP +The input and output variables from the three networks are +matched by names. It is assumed that all the latches in both designs +are clocked by a single, global clock. +The verification is done by implicitly enumerating all the +states in the product machine, and checking that the outputs +are equivalent for all reachable state pairs starting +from the initial state of the product machine. +.PP +\fB-v\fR allows specification of the verbosity level of the output. +.PP +By default, the command returns an error status if the verification fails. +When option \fB-V\fR is used, it returns an error status if the verification succeeds. diff --git a/sis/sis_lib/help/env_verify_fsm.fmt b/sis/sis_lib/help/env_verify_fsm.fmt new file mode 100644 index 0000000..1ab77d7 --- /dev/null +++ b/sis/sis_lib/help/env_verify_fsm.fmt @@ -0,0 +1,27 @@ + + July 1, 1994 SIS(1) + + env_verify_fsm [-v n] [-V] fsm.blif env.blif + + Verify the equivalence of two synchronous networks in a given environ- + ment. The current network is compared with fsm.blif under the environ- + ment defined by the env.blif network. The environment is a sequential + circuit that generates the inputs of the circuits under verification, + and possibly takes some inputs from them. What is verified is that the + current network and the fsm.blif network are substituable for one + another when used in the context of the env.blif network. + + The input and output variables from the three networks are matched by + names. It is assumed that all the latches in both designs are clocked by + a single, global clock. The verification is done by implicitly + enumerating all the states in the product machine, and checking that the + outputs are equivalent for all reachable state pairs starting from the + initial state of the product machine. + + -v allows specification of the verbosity level of the output. + + By default, the command returns an error status if the verification + fails. When option -V is used, it returns an error status if the verif- + ication succeeds. + + 1 diff --git a/sis/sis_lib/help/equiv_nets.1 b/sis/sis_lib/help/equiv_nets.1 new file mode 100644 index 0000000..6c2b98a --- /dev/null +++ b/sis/sis_lib/help/equiv_nets.1 @@ -0,0 +1,29 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/equiv_nets.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:44 $ +.\" * +.\" +.XX +equiv_nets [-v n] +.PP +This command simplifies the network using net equivalence. +With \fBfull_simplify\fR, it is one of the two routines able to take +advantage of network don't cares. +.PP +\fBequiv_nets\fR groups all nets of the network by equivalence classes. +Two nets are equivalent if and only if they always compute the same +function with respect to the external care set. It only uses input +don't cares, not observabiilty don't cares. +.PP +For each equivalence class, \fBequiv_nets\fR selects a lowest cost +net, and moves the fanout of all the other nets of the equivalence +class onto the lowest cost net. +.PP +Finally, it calls the command \fBsweep\fR. +.PP +\fB-v\fR allows the specification of the verbosity level of the output. +The default value is 0. diff --git a/sis/sis_lib/help/equiv_nets.fmt b/sis/sis_lib/help/equiv_nets.fmt new file mode 100644 index 0000000..1328962 --- /dev/null +++ b/sis/sis_lib/help/equiv_nets.fmt @@ -0,0 +1,24 @@ + + July 1, 1994 SIS(1) + + equiv_nets [-v n] + + This command simplifies the network using net equivalence. With + full_simplify, it is one of the two routines able to take advantage of + network don't cares. + + equiv_nets groups all nets of the network by equivalence classes. Two + nets are equivalent if and only if they always compute the same function + with respect to the external care set. It only uses input don't cares, + not observabiilty don't cares. + + For each equivalence class, equiv_nets selects a lowest cost net, and + moves the fanout of all the other nets of the equivalence class onto the + lowest cost net. + + Finally, it calls the command sweep. + + -v allows the specification of the verbosity level of the output. The + default value is 0. + + 1 diff --git a/sis/sis_lib/help/espresso.1 b/sis/sis_lib/help/espresso.1 new file mode 100644 index 0000000..544fc96 --- /dev/null +++ b/sis/sis_lib/help/espresso.1 @@ -0,0 +1,14 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/espresso.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +espresso +.PP +Collapse the network into a PLA, minimize it using \fIespresso\fR, +and put the result back into the multiple-level \fInor-nor\fR form. diff --git a/sis/sis_lib/help/espresso.fmt b/sis/sis_lib/help/espresso.fmt new file mode 100644 index 0000000..b4d1d8e --- /dev/null +++ b/sis/sis_lib/help/espresso.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + espresso + + Collapse the network into a PLA, minimize it using _e_s_p_r_e_s_s_o, and put the + result back into the multiple-level _n_o_r-_n_o_r form. + + 1 diff --git a/sis/sis_lib/help/extract_seq_dc.1 b/sis/sis_lib/help/extract_seq_dc.1 new file mode 100644 index 0000000..8da6778 --- /dev/null +++ b/sis/sis_lib/help/extract_seq_dc.1 @@ -0,0 +1,40 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/extract_seq_dc.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +extract_seq_dc [-o depth] [-v n] [-m method] +.PP +Extract sequential don't cares based on unreachable states. +The unreachable states are computed by +implicitly enumerating the set of +reachable states in the circuit starting from an initial state +and then computing the inverse of that set. +\fBfull_simplify\fR or \fBequiv_nets\fR should be run afterwards to +exploit these don't cares. +.PP +\fB-o depth\fR allows the specification of the depth of search for good +variable ordering. +A larger value for depth will require more CPU time but determine +a better ordering. +The default value is 2. +.PP +\fB-v\fR allows specification of the verbosity level of the output. +.PP +The \fB-m\fR option specifies \fBmethod\fR for determining +the reachable states. +\fBconsistency\fR builds the entire transition relation +and uses it to determine the reached states. +\fBbull\fR does output cofactoring to find the reachable +states. +The \fBproduct\fR method is similar to the \fBconsistency\fR method but +input variables are smoothed as soon as possible as the characteristic +function is being built. +This makes the size of the resulting BDD representing the +characteristic function of the transition relation smaller. +The default method is \fBproduct\fR. diff --git a/sis/sis_lib/help/extract_seq_dc.fmt b/sis/sis_lib/help/extract_seq_dc.fmt new file mode 100644 index 0000000..4deb590 --- /dev/null +++ b/sis/sis_lib/help/extract_seq_dc.fmt @@ -0,0 +1,27 @@ + + July 1, 1994 SIS(1) + + extract_seq_dc [-o depth] [-v n] [-m method] + + Extract sequential don't cares based on unreachable states. The + unreachable states are computed by implicitly enumerating the set of + reachable states in the circuit starting from an initial state and then + computing the inverse of that set. full_simplify or equiv_nets should + be run afterwards to exploit these don't cares. + + -o depth allows the specification of the depth of search for good vari- + able ordering. A larger value for depth will require more CPU time but + determine a better ordering. The default value is 2. + + -v allows specification of the verbosity level of the output. + + The -m option specifies method for determining the reachable states. + consistency builds the entire transition relation and uses it to deter- + mine the reached states. bull does output cofactoring to find the + reachable states. The product method is similar to the consistency + method but input variables are smoothed as soon as possible as the + characteristic function is being built. This makes the size of the + resulting BDD representing the characteristic function of the transition + relation smaller. The default method is product. + + 1 diff --git a/sis/sis_lib/help/factor.1 b/sis/sis_lib/help/factor.1 new file mode 100644 index 0000000..c394adf --- /dev/null +++ b/sis/sis_lib/help/factor.1 @@ -0,0 +1,18 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/factor.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +factor [-gq] node-list +.PP +Throw away the old factored forms and factor each node in the +\fBnode-list\fR, and store the factored forms with the nodes. +If the \fB-q\fR option is specified, the \fIquick factor\fR algorithm +is used to factor the node. +If the \fB-g\fR option is specified, the \fIgood factor\fR +algorithm is used to factor the node. diff --git a/sis/sis_lib/help/factor.fmt b/sis/sis_lib/help/factor.fmt new file mode 100644 index 0000000..18d8d80 --- /dev/null +++ b/sis/sis_lib/help/factor.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + factor [-gq] node-list + + Throw away the old factored forms and factor each node in the node-list, + and store the factored forms with the nodes. If the -q option is speci- + fied, the _q_u_i_c_k _f_a_c_t_o_r algorithm is used to factor the node. If the -g + option is specified, the _g_o_o_d _f_a_c_t_o_r algorithm is used to factor the + node. + + 1 diff --git a/sis/sis_lib/help/fanout_alg.1 b/sis/sis_lib/help/fanout_alg.1 new file mode 100644 index 0000000..bd19ea6 --- /dev/null +++ b/sis/sis_lib/help/fanout_alg.1 @@ -0,0 +1,22 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/fanout_alg.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +fanout_alg [-v] alg_list +.PP +Activates selectively one or more fanout algorithms. For a list of +fanout algorithms known to the system, use the \fB-v\fR option. +The algorithms activated are the ones specified in the list. +One algorithm, \fInoalg\fR, is always active. +\fItwo_level\fR +is a fast, area efficient algorithm. The best results are +obtained with \fItwo_level\fR, \fIbottom_up\fR, \fIlt_trees\fR, +and \fImixed_lt_trees\fR. +.PP +Fanout optimization itself is performed using the \fBmap\fR command. diff --git a/sis/sis_lib/help/fanout_alg.fmt b/sis/sis_lib/help/fanout_alg.fmt new file mode 100644 index 0000000..2d2930b --- /dev/null +++ b/sis/sis_lib/help/fanout_alg.fmt @@ -0,0 +1,15 @@ + + July 1, 1994 SIS(1) + + fanout_alg [-v] alg_list + + Activates selectively one or more fanout algorithms. For a list of + fanout algorithms known to the system, use the -v option. The algo- + rithms activated are the ones specified in the list. One algorithm, + _n_o_a_l_g, is always active. _t_w_o__l_e_v_e_l is a fast, area efficient algorithm. + The best results are obtained with _t_w_o__l_e_v_e_l, _b_o_t_t_o_m__u_p, _l_t__t_r_e_e_s, and + _m_i_x_e_d__l_t__t_r_e_e_s. + + Fanout optimization itself is performed using the map command. + + 1 diff --git a/sis/sis_lib/help/fanout_param.1 b/sis/sis_lib/help/fanout_param.1 new file mode 100644 index 0000000..32249f5 --- /dev/null +++ b/sis/sis_lib/help/fanout_param.1 @@ -0,0 +1,15 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/fanout_param.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +fanout_param [-v] fanout_alg [property value] +.PP +Changes the default parameter values associated with specific +fanout algorithms. For a list of these parameters and their values, +use the \fB-v\fP option with a fanout algorithm. diff --git a/sis/sis_lib/help/fanout_param.fmt b/sis/sis_lib/help/fanout_param.fmt new file mode 100644 index 0000000..75ccb0c --- /dev/null +++ b/sis/sis_lib/help/fanout_param.fmt @@ -0,0 +1,10 @@ + + July 1, 1994 SIS(1) + + fanout_param [-v] fanout_alg [property value] + + Changes the default parameter values associated with specific fanout + algorithms. For a list of these parameters and their values, use the -v + option with a fanout algorithm. + + 1 diff --git a/sis/sis_lib/help/force_init_0.1 b/sis/sis_lib/help/force_init_0.1 new file mode 100644 index 0000000..d9026ff --- /dev/null +++ b/sis/sis_lib/help/force_init_0.1 @@ -0,0 +1,18 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/force_init_0.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:44 $ +.\" * +.\" +.XX +force_init_0 +.PP +This command replaces all latches initialized to 1 by latches +initialized to 0. It inserts an inverter before and after the latch +to maintain circuit behavior. +.PP +This command is useful for certain types of FPGA architectures +which do not support the initialization of latches to 1. diff --git a/sis/sis_lib/help/force_init_0.fmt b/sis/sis_lib/help/force_init_0.fmt new file mode 100644 index 0000000..0389b06 --- /dev/null +++ b/sis/sis_lib/help/force_init_0.fmt @@ -0,0 +1,13 @@ + + July 1, 1994 SIS(1) + + force_init_0 + + This command replaces all latches initialized to 1 by latches initial- + ized to 0. It inserts an inverter before and after the latch to maintain + circuit behavior. + + This command is useful for certain types of FPGA architectures which do + not support the initialization of latches to 1. + + 1 diff --git a/sis/sis_lib/help/format b/sis/sis_lib/help/format new file mode 100755 index 0000000..5cfa1e6 --- /dev/null +++ b/sis/sis_lib/help/format @@ -0,0 +1 @@ +tbl header.me $* | nroff -man | col | trail diff --git a/sis/sis_lib/help/free_dc.1 b/sis/sis_lib/help/free_dc.1 new file mode 100644 index 0000000..db1990e --- /dev/null +++ b/sis/sis_lib/help/free_dc.1 @@ -0,0 +1,14 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/free_dc.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:44 $ +.\" * +.\" +.XX +free_dc +.PP +Frees the don't care network associated with a network. +This command is used for debugging and experimental purposes. diff --git a/sis/sis_lib/help/free_dc.fmt b/sis/sis_lib/help/free_dc.fmt new file mode 100644 index 0000000..e68e334 --- /dev/null +++ b/sis/sis_lib/help/free_dc.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + free_dc + + Frees the don't care network associated with a network. This command is + used for debugging and experimental purposes. + + 1 diff --git a/sis/sis_lib/help/full_simplify.1 b/sis/sis_lib/help/full_simplify.1 new file mode 100644 index 0000000..288a4f4 --- /dev/null +++ b/sis/sis_lib/help/full_simplify.1 @@ -0,0 +1,63 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/full_simplify.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +full_simplify [-d][-o ordering] [-m method] [-l] [-v verbose] +.PP +Simplify each node in the network using the local don't cares +generated in terms of fanins of each node. +First compatible +observability plus external don't cares are generated for +each node in terms of primary inputs. +Then the image +computation techniques are used to map these don't cares +to the local space of each node. +This technique removes +most redundancies in the network. +The satisfiability don't cares +for a subset of the nodes in the network which have the same +support as the node being simplified is also generated. +An ordering is given to the nodes of the network +and local don't cares for the nodes are computed according +to that ordering. +Each node is simplified using its local don't cares and an +appropriate satisfiability don't care subset. + +.PP +\fB-d\fR If this option is used no observability don't cares are computed. +In this case the local don't cares are only the unreachable points +in the local space of each node (a subset of the satisfiability +don't care set). + +.PP +\fB-o\fR Used for BDD ordering. If 0 (default) is used, variables +are ordered based on their depth. If 1 is used, the level of +a node is used for its ordering. + +.PP +\fBmethod\fR specifies the algorithm used to minimize the nodes. +\fIsnocomp\fR (default) invokes a single pass minimization procedure that does +not compute the complete offset. +\fInocomp\fR invokes the full minimization procedure (ala ESPRESSO) but does +not compute the complete offset. +\fIdcsimp\fR invokes single pass tautology-based minimizer. + +.PP +\fB-l\fR generates fanin don't cares only for nodes +with the same or subset support as the node being minimized +which have level less than the node being minimized. The level +is the largest number of nodes on the longest path from the node to +a primary input. + +.PP +\fB-v\fR prints out extra info for debugging the code. + + +SIS(1) UNIX Programmer's Manual SIS(1) + diff --git a/sis/sis_lib/help/full_simplify.fmt b/sis/sis_lib/help/full_simplify.fmt new file mode 100644 index 0000000..98e3762 --- /dev/null +++ b/sis/sis_lib/help/full_simplify.fmt @@ -0,0 +1,42 @@ + + July 1, 1994 SIS(1) + + full_simplify [-d][-o ordering] [-m method] [-l] [-v verbose] + + Simplify each node in the network using the local don't cares generated + in terms of fanins of each node. First compatible observability plus + external don't cares are generated for each node in terms of primary + inputs. Then the image computation techniques are used to map these + don't cares to the local space of each node. This technique removes + most redundancies in the network. The satisfiability don't cares for a + subset of the nodes in the network which have the same support as the + node being simplified is also generated. An ordering is given to the + nodes of the network and local don't cares for the nodes are computed + according to that ordering. Each node is simplified using its local + don't cares and an appropriate satisfiability don't care subset. + + -d If this option is used no observability don't cares are computed. In + this case the local don't cares are only the unreachable points in the + local space of each node (a subset of the satisfiability don't care + set). + + -o Used for BDD ordering. If 0 (default) is used, variables are ordered + based on their depth. If 1 is used, the level of a node is used for its + ordering. + + method specifies the algorithm used to minimize the nodes. _s_n_o_c_o_m_p + (default) invokes a single pass minimization procedure that does not + compute the complete offset. _n_o_c_o_m_p invokes the full minimization pro- + cedure (ala ESPRESSO) but does not compute the complete offset. _d_c_s_i_m_p + invokes single pass tautology-based minimizer. + + -l generates fanin don't cares only for nodes with the same or subset + support as the node being minimized which have level less than the node + being minimized. The level is the largest number of nodes on the longest + path from the node to a primary input. + + -v prints out extra info for debugging the code. + + SIS(1) UNIX Programmer's Manual SIS(1) + + 1 diff --git a/sis/sis_lib/help/fx.1 b/sis/sis_lib/help/fx.1 new file mode 100644 index 0000000..09b0cb4 --- /dev/null +++ b/sis/sis_lib/help/fx.1 @@ -0,0 +1,32 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/fx.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +fx [-o] [-b limit] [-l] [-z] +.PP +Greedy concurrent algorithm for finding the best double cube divisors and +single cube divisors. +Finds all the double cube and single cube divisors +of the nodes in the network. +It associates a cost function to each node, +and extracts the node with the best cost function greedily. +.PP +The \fB-o\fP option only looks for 0-level two-cube divisors. +.PP +The \fB-b\fP option reads an upper bound for the number of divisors +generated. The default value is 50000. This is because the +number of divisors in some cases can grow very large. +.PP +The \fB-l\fP option changes the level of each node in the network as allowed +by the slack between the required time and arrival time at that node. +.PP +The \fB-z\fP option uses zero-weight divisors (in addition to divisors with +a larger weight). This means that divisors that contribute zero gain to +the overall decomposition are extracted. This may result in an overall +better decomposition, but take an exhorbitant amount of time. diff --git a/sis/sis_lib/help/fx.fmt b/sis/sis_lib/help/fx.fmt new file mode 100644 index 0000000..0666bee --- /dev/null +++ b/sis/sis_lib/help/fx.fmt @@ -0,0 +1,25 @@ + + July 1, 1994 SIS(1) + + fx [-o] [-b limit] [-l] [-z] + + Greedy concurrent algorithm for finding the best double cube divisors + and single cube divisors. Finds all the double cube and single cube + divisors of the nodes in the network. It associates a cost function to + each node, and extracts the node with the best cost function greedily. + + The -o option only looks for 0-level two-cube divisors. + + The -b option reads an upper bound for the number of divisors generated. + The default value is 50000. This is because the number of divisors in + some cases can grow very large. + + The -l option changes the level of each node in the network as allowed + by the slack between the required time and arrival time at that node. + + The -z option uses zero-weight divisors (in addition to divisors with a + larger weight). This means that divisors that contribute zero gain to + the overall decomposition are extracted. This may result in an overall + better decomposition, but take an exhorbitant amount of time. + + 1 diff --git a/sis/sis_lib/help/gcx.1 b/sis/sis_lib/help/gcx.1 new file mode 100644 index 0000000..f99934c --- /dev/null +++ b/sis/sis_lib/help/gcx.1 @@ -0,0 +1,34 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/gcx.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +gcx [-bcdf] [-t threshold] +.PP +Extract common cubes from a network, re-express the network +in terms of these cubes, and in the process cut down on the +number of literals needed in the network. +.PP +The \fB-b\fP option chooses the best cube at each step when examining +possible cubes to be extracted; otherwise, the more efficient \fIping-pong\fP +algorithm is used to find a good (but not necessarily the best) cube +at each step. +.PP +The \fB-c\fP option uses the complement of each cube as well as the cube +when dividing the new cube into the network. +.PP +The \fB-f\fP option uses the number +of literals in the factored form for the +network as a cost function for determining the best cube to be extracted. +.PP +The \fB-t\fP option sets a threshold such that only a cube with a value +greater than the threshold will be extracted. By default, the threshold is +0, so that all possible cube divisors are extracted. +.PP +The \fB-d\fP option enables a debugging mode which traces the execution +of gcx. diff --git a/sis/sis_lib/help/gcx.fmt b/sis/sis_lib/help/gcx.fmt new file mode 100644 index 0000000..b764739 --- /dev/null +++ b/sis/sis_lib/help/gcx.fmt @@ -0,0 +1,28 @@ + + July 1, 1994 SIS(1) + + gcx [-bcdf] [-t threshold] + + Extract common cubes from a network, re-express the network in terms of + these cubes, and in the process cut down on the number of literals + needed in the network. + + The -b option chooses the best cube at each step when examining possible + cubes to be extracted; otherwise, the more efficient _p_i_n_g-_p_o_n_g algorithm + is used to find a good (but not necessarily the best) cube at each step. + + The -c option uses the complement of each cube as well as the cube when + dividing the new cube into the network. + + The -f option uses the number of literals in the factored form for the + network as a cost function for determining the best cube to be + extracted. + + The -t option sets a threshold such that only a cube with a value + greater than the threshold will be extracted. By default, the threshold + is 0, so that all possible cube divisors are extracted. + + The -d option enables a debugging mode which traces the execution of + gcx. + + 1 diff --git a/sis/sis_lib/help/gkx.1 b/sis/sis_lib/help/gkx.1 new file mode 100644 index 0000000..5efa309 --- /dev/null +++ b/sis/sis_lib/help/gkx.1 @@ -0,0 +1,44 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/gkx.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +gkx [-1abcdfo] [-t threshold] +.PP +Extract multiple-cube common divisors from the network. +.PP +The \fB-a\fP option generates all kernels of all function in the network +when building the kernel-intersection table. By default, only level-0 +kernels are used. +.PP +The \fB-b\fP option chooses the best kernel intersection as the new +factor at each step of the algorithm; this is done by enumerating and +considering each possible kernel intersection, and choosing the best. +By default, the more efficient \fIping-pong\fP algorithm is used to +find a good (but not necessarily the best) kernel intersection. +.PP +The \fB-c\fP option uses the new factor and its complement when attempting +to introduce the new factor into the network. +.PP +The \fB-d\fP option enables debugging information which traces the execution +of the kernel extract algorithm. +.PP +The \fB-f\fP option uses the number of literals in the factored form for +the network as the cost function when determining the value of a +kernel intersection; by default, the number of literals in the sum-of-products +form for the network is used. +.PP +The \fB-o\fP option allows for overlapping factors. +.PP +The \fB-t\fP option sets a threshold such that divisors are extracted +only while their value exceeds the threshold. By default, the threshold is 0 +so that all possible multiple-cube divisors are extracted from the network. +.PP +The \fB-1\fP option performs only a single pass over the network. By default, +the kernel extract algorithm is iterated while there are still divisors whose +value exceeds the given threshold. diff --git a/sis/sis_lib/help/gkx.fmt b/sis/sis_lib/help/gkx.fmt new file mode 100644 index 0000000..4df26a6 --- /dev/null +++ b/sis/sis_lib/help/gkx.fmt @@ -0,0 +1,40 @@ + + July 1, 1994 SIS(1) + + gkx [-1abcdfo] [-t threshold] + + Extract multiple-cube common divisors from the network. + + The -a option generates all kernels of all function in the network when + building the kernel-intersection table. By default, only level-0 ker- + nels are used. + + The -b option chooses the best kernel intersection as the new factor at + each step of the algorithm; this is done by enumerating and considering + each possible kernel intersection, and choosing the best. By default, + the more efficient _p_i_n_g-_p_o_n_g algorithm is used to find a good (but not + necessarily the best) kernel intersection. + + The -c option uses the new factor and its complement when attempting to + introduce the new factor into the network. + + The -d option enables debugging information which traces the execution + of the kernel extract algorithm. + + The -f option uses the number of literals in the factored form for the + network as the cost function when determining the value of a kernel + intersection; by default, the number of literals in the sum-of-products + form for the network is used. + + The -o option allows for overlapping factors. + + The -t option sets a threshold such that divisors are extracted only + while their value exceeds the threshold. By default, the threshold is 0 + so that all possible multiple-cube divisors are extracted from the net- + work. + + The -1 option performs only a single pass over the network. By default, + the kernel extract algorithm is iterated while there are still divisors + whose value exceeds the given threshold. + + 1 diff --git a/sis/sis_lib/help/header.me b/sis/sis_lib/help/header.me new file mode 100644 index 0000000..0d445de --- /dev/null +++ b/sis/sis_lib/help/header.me @@ -0,0 +1,12 @@ +.TH SIS 1 "July 1, 1994" +.UC 1 +.de XX +.LP +.ti -5 +.B +.. +.de X1 +.br +.ti -5 +.B +.. diff --git a/sis/sis_lib/help/help.1 b/sis/sis_lib/help/help.1 new file mode 100644 index 0000000..85dcda7 --- /dev/null +++ b/sis/sis_lib/help/help.1 @@ -0,0 +1,18 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/help.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +help [-a] [command] +.PP +Given no arguments, help prints a list of all commands known to the +command interpreter. The \fB-a\fP option provides a list of all +debugging commands, which by convention begin with an underscore. +If a command name is given, +detailed information for that command will be provided. + diff --git a/sis/sis_lib/help/help.fmt b/sis/sis_lib/help/help.fmt new file mode 100644 index 0000000..dd82af0 --- /dev/null +++ b/sis/sis_lib/help/help.fmt @@ -0,0 +1,11 @@ + + July 1, 1994 SIS(1) + + help [-a] [command] + + Given no arguments, help prints a list of all commands known to the com- + mand interpreter. The -a option provides a list of all debugging com- + mands, which by convention begin with an underscore. If a command name + is given, detailed information for that command will be provided. + + 1 diff --git a/sis/sis_lib/help/history.1 b/sis/sis_lib/help/history.1 new file mode 100644 index 0000000..ed9329a --- /dev/null +++ b/sis/sis_lib/help/history.1 @@ -0,0 +1,56 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/history.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:43 $ +.\" * +.\" +.XX +history [-h] [num] +.PP +Lists previous commands and their event numbers. +The \fB-h\fP option suppresses printing the event number. +If \fBnum\fP is specified, lists the last \fBnum\fP events. Lists the last +30 events if \fBnum\fP is not specified. +.PP +History Substitution: +.PP +The history substitution mechanism is a simpler version of the csh history +substitution mechanism. It enables you to reuse words from previously typed +commands. +.PP +The default history substitution character is the `%' (`!' is default for shell +escapes, and `#' marks the beginning of a comment). This can be changed using +the "set" command. In this description '%' is used as the history_char. +The `%' can appear +anywhere in a line. A line containing a history substitution is echoed to +the screen after the substitution takes place. `%' can be preceded by a +`\\' in order to escape the substitution, for example, to enter a `%' into +an alias or to set the prompt. +.PP +Each valid line typed at the prompt is saved. If the \fBhistory\fP variable +is set (see help page for \fBset\fP), each line is also echoed to the history +file. You can use the "history" command to list the previously typed +commands. +.PP +Substitutions: at any point in a line these history substitutions are +available +.ta .5i 1.5i +.PP +.nf + %:0 Initial word of last command. + %:n n'th argument of last command. + %$ Last argument of last command. + %* All but initial word of last command. + + %% Last command. + %stuf Last command beginning with "stuf". + %n Repeat the n'th command. + %-n Repeat the n'th previous command. + ^old^new Replace "old" w/ "new" in previous command. + + Trailing spaces are significant during substitution. + Initial spaces are not significant. +.fi diff --git a/sis/sis_lib/help/history.fmt b/sis/sis_lib/help/history.fmt new file mode 100644 index 0000000..aebb3e0 --- /dev/null +++ b/sis/sis_lib/help/history.fmt @@ -0,0 +1,47 @@ + + July 1, 1994 SIS(1) + + history [-h] [num] + + Lists previous commands and their event numbers. The -h option + suppresses printing the event number. If num is specified, lists the + last num events. Lists the last 30 events if num is not specified. + + History Substitution: + + The history substitution mechanism is a simpler version of the csh his- + tory substitution mechanism. It enables you to reuse words from previ- + ously typed commands. + + The default history substitution character is the `%' (`!' is default + for shell escapes, and `#' marks the beginning of a comment). This can + be changed using the "set" command. In this description '%' is used as + the history_char. The `%' can appear anywhere in a line. A line con- + taining a history substitution is echoed to the screen after the substi- + tution takes place. `%' can be preceded by a `\' in order to escape the + substitution, for example, to enter a `%' into an alias or to set the + prompt. + + Each valid line typed at the prompt is saved. If the history variable + is set (see help page for set), each line is also echoed to the history + file. You can use the "history" command to list the previously typed + commands. + + Substitutions: at any point in a line these history substitutions are + available + + %:0 Initial word of last command. + %:n n'th argument of last command. + %$ Last argument of last command. + %* All but initial word of last command. + + %% Last command. + %stuf Last command beginning with "stuf". + %n Repeat the n'th command. + %-n Repeat the n'th previous command. + ^old^new Replace "old" w/ "new" in previous command. + + Trailing spaces are significant during substitution. + Initial spaces are not significant. + + 1 diff --git a/sis/sis_lib/help/invert.1 b/sis/sis_lib/help/invert.1 new file mode 100644 index 0000000..79aecfa --- /dev/null +++ b/sis/sis_lib/help/invert.1 @@ -0,0 +1,16 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/invert.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +invert node-list +.PP +Invert each node in the \fBnode-list\fR. It is used when +the complement of a node is to be implemented. Note that +it does not change the logic function of the current Boolean +network, but will have an effect on the structure of the network. diff --git a/sis/sis_lib/help/invert.fmt b/sis/sis_lib/help/invert.fmt new file mode 100644 index 0000000..42ab556 --- /dev/null +++ b/sis/sis_lib/help/invert.fmt @@ -0,0 +1,11 @@ + + July 1, 1994 SIS(1) + + invert node-list + + Invert each node in the node-list. It is used when the complement of a + node is to be implemented. Note that it does not change the logic func- + tion of the current Boolean network, but will have an effect on the + structure of the network. + + 1 diff --git a/sis/sis_lib/help/invert_io.1 b/sis/sis_lib/help/invert_io.1 new file mode 100644 index 0000000..1f9bc84 --- /dev/null +++ b/sis/sis_lib/help/invert_io.1 @@ -0,0 +1,17 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/invert_io.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:44 $ +.\" * +.\" +.XX +invert_io node-list +.PP +This command reverses the polarity of the specified nodes. +The nodes have to be external primary inputs or external primary outputs. +.PP +The polarity inversion is done by adding an inverter before a primary output or +after a primary input. diff --git a/sis/sis_lib/help/invert_io.fmt b/sis/sis_lib/help/invert_io.fmt new file mode 100644 index 0000000..1bd0749 --- /dev/null +++ b/sis/sis_lib/help/invert_io.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + invert_io node-list + + This command reverses the polarity of the specified nodes. The nodes + have to be external primary inputs or external primary outputs. + + The polarity inversion is done by adding an inverter before a primary + output or after a primary input. + + 1 diff --git a/sis/sis_lib/help/ite_map.1 b/sis/sis_lib/help/ite_map.1 new file mode 100644 index 0000000..b82f4a7 --- /dev/null +++ b/sis/sis_lib/help/ite_map.1 @@ -0,0 +1,98 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/ite_map.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:44 $ +.\" * +.\" +.XX +ite_map [-n num_iter] [-C cost_limit] [-f collapse_fanin] + [-m map_method] [-d decomp_fanin] [-M MAXOPTIMAL] [-clorsvD] +.PP +Routine to find an optimal mapping to Actel's ACT1 architecture. +The input is the Boolean network and the output +is a netlist and the block count +(reference: An Architecture for Electrically Configurable Gate Arrays, +Gamal et. al., IEEE J. of Solid State Circuits, April 1989, pp. 394-398). +.PP +\fBite_map\fP synthesizes the given circuit onto Actel ACT1 +architecture. +The pattern graphs are hard-wired into the code +and so no library is to be read in. Each intermediate +node of the network is checked to see if it matches onto one ACT1 +module. This check is done using a Boolean matching algorithm. +If not, then a subject graph is constructed for the node function. +The subject graph (as well as the pattern-graphs) is in terms of +2-1 muxes: it uses ITEs (if-then-else DAGs) and ROBDDs (Reduced +Ordered BDDs) for the mapping. After an initial mapping of the +network, an iterative_improvement phase may be entered. Local collapse and +decomposition operations are performed for better quality. + +Following options are supported: + +.PP +\fB-m map_method\fP specifies which one of the two +subject_graphs would be constructed. +.br +.PP +map_method = 1 => Standard mapping for each node. +.br +.PP +map_method = 2 => construct a sub-network from each node. Map the +sub-network using iterative improvement and finally replace the node +with the mapped sub-network. +.br +.PP +\fB-n num_iteration\fP specifies the maximum number of iterations +to be performed in the iterative_improvement phase. Default is -n 0. +.br +.PP +\fB-F collapse_fanins_of_fanout\fP used in partial collapse. Collapses +a node into fanouts only if after collapsing, each fanout has at most +collapse_fanins_of_fanout fanins (Default: -F 15). +.br +.PP +\fB-C cost_limit\fP in partial collapse, collapse a node only if its +cost is at most cost_limit (Default: -C 3). +.br +.PP +\fB-f collapse_fanin\fP considers only those nodes for partial +collapse which have at most collapse_fanin fanins (Default: -f 3). +.br +.PP +\fB-d decomp_fanin\fP considers only those nodes for decomposition in +iterative improvement which have fanin greater than or equal to +decomp_fanin. (Default -d 4). +.br +.PP +\fB-M MAXOPTIMAL\fP constructs an optimal ROBDD (if the ROBDD option +is selected) for a node if number of fanins is at most MAXOPTIMAL. +.br +.PP +\fB-r\fP is the final mapping option. After initial mapping and +possible iterative improvement, a mapped network is created in +which each intermediate node corresponds to one ACT1 module. If not +specified, the network may not have a one-to-one correspondence with +the ACT1 module. +.br +.PP +\fB-D\fP selects the decomposition method. If specified, computes a +factored form of the node and then constructs ITE for each factor. +.br +.PP +\fB-c\fP causes the matching algorithm to be exact. If not +specified, matching is approximate. +.br +.PP +\fB-o\fP causes the OR gate in ACT1 to be ignored. So mapping is done onto a +three-mux structure. +.br +.PP +\fB-v\fP turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. +.br +.PP +\fB-s\fP gives the statistics, regarding the block count +of the circuit. diff --git a/sis/sis_lib/help/ite_map.fmt b/sis/sis_lib/help/ite_map.fmt new file mode 100644 index 0000000..f409b2e --- /dev/null +++ b/sis/sis_lib/help/ite_map.fmt @@ -0,0 +1,78 @@ + + July 1, 1994 SIS(1) + + ite_map [-n num_iter] [-C cost_limit] [-f collapse_fanin] + [-m map_method] [-d decomp_fanin] [-M MAXOPTIMAL] [-clorsvD] + + Routine to find an optimal mapping to Actel's ACT1 architecture. The + input is the Boolean network and the output is a netlist and the block + count (reference: An Architecture for Electrically Configurable Gate + Arrays, Gamal et. al., IEEE J. of Solid State Circuits, April 1989, pp. + 394-398). + + ite_map synthesizes the given circuit onto Actel ACT1 architecture. The + pattern graphs are hard-wired into the code and so no library is to be + read in. Each intermediate node of the network is checked to see if it + matches onto one ACT1 module. This check is done using a Boolean match- + ing algorithm. If not, then a subject graph is constructed for the node + function. The subject graph (as well as the pattern-graphs) is in terms + of 2-1 muxes: it uses ITEs (if-then-else DAGs) and ROBDDs (Reduced + Ordered BDDs) for the mapping. After an initial mapping of the network, + an iterative_improvement phase may be entered. Local collapse and decom- + position operations are performed for better quality. + + Following options are supported: + + -m map_method specifies which one of the two subject_graphs would be + constructed. + + map_method = 1 => Standard mapping for each node. + + map_method = 2 => construct a sub-network from each node. Map the sub- + network using iterative improvement and finally replace the node with + the mapped sub-network. + + -n num_iteration specifies the maximum number of iterations to be per- + formed in the iterative_improvement phase. Default is -n 0. + + -F collapse_fanins_of_fanout used in partial collapse. Collapses a node + into fanouts only if after collapsing, each fanout has at most + collapse_fanins_of_fanout fanins (Default: -F 15). + + -C cost_limit in partial collapse, collapse a node only if its cost is + at most cost_limit (Default: -C 3). + + -f collapse_fanin considers only those nodes for partial collapse which + have at most collapse_fanin fanins (Default: -f 3). + + -d decomp_fanin considers only those nodes for decomposition in itera- + tive improvement which have fanin greater than or equal to decomp_fanin. + (Default -d 4). + + -M MAXOPTIMAL constructs an optimal ROBDD (if the ROBDD option is + selected) for a node if number of fanins is at most MAXOPTIMAL. + + 1 + + SIS(1) July 1, 1994 + + -r is the final mapping option. After initial mapping and possible + iterative improvement, a mapped network is created in which each inter- + mediate node corresponds to one ACT1 module. If not specified, the net- + work may not have a one-to-one correspondence with the ACT1 module. + + -D selects the decomposition method. If specified, computes a factored + form of the node and then constructs ITE for each factor. + + -c causes the matching algorithm to be exact. If not specified, matching + is approximate. + + -o causes the OR gate in ACT1 to be ignored. So mapping is done onto a + three-mux structure. + + -v turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + + -s gives the statistics, regarding the block count of the circuit. + + 2 diff --git a/sis/sis_lib/help/latch_output.1 b/sis/sis_lib/help/latch_output.1 new file mode 100644 index 0000000..54e8f5f --- /dev/null +++ b/sis/sis_lib/help/latch_output.1 @@ -0,0 +1,25 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/latch_output.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:44 $ +.\" * +.\" +.XX +latch_output [-v n] node-list +.PP +The nodes passed as argument should be external primary outputs. +This command forces the listed external primary outputs to be fed by a +latch. This is accomplished by moving latches forward by retiming. +.PP +The command fails if there is a combinational dependency between an +external primary input and one of the specified primary outputs. +.PP +This function is useful to guarantee that certain outputs will not +glitch. It is handy if that output is to control an external device +such as the write enable signal of a memory chip. +.PP +\fB-v\fR allows the specification of the verbosity level of the output. +The default value is 0. diff --git a/sis/sis_lib/help/latch_output.fmt b/sis/sis_lib/help/latch_output.fmt new file mode 100644 index 0000000..c373a81 --- /dev/null +++ b/sis/sis_lib/help/latch_output.fmt @@ -0,0 +1,20 @@ + + July 1, 1994 SIS(1) + + latch_output [-v n] node-list + + The nodes passed as argument should be external primary outputs. This + command forces the listed external primary outputs to be fed by a latch. + This is accomplished by moving latches forward by retiming. + + The command fails if there is a combinational dependency between an + external primary input and one of the specified primary outputs. + + This function is useful to guarantee that certain outputs will not + glitch. It is handy if that output is to control an external device such + as the write enable signal of a memory chip. + + -v allows the specification of the verbosity level of the output. The + default value is 0. + + 1 diff --git a/sis/sis_lib/help/make.awk b/sis/sis_lib/help/make.awk new file mode 100644 index 0000000..829ffb6 --- /dev/null +++ b/sis/sis_lib/help/make.awk @@ -0,0 +1,37 @@ +BEGIN { + printf ".SUFFIXES: .1 .fmt\n"; + printf ".1.fmt:\n"; + printf "\tformat $*.1 >$*.fmt\n"; +} +{ + file[nfile++] = $1; +} +END { + len = 8; + printf "make_fmt: "; + for(j = 0; j < nfile; j++) { + if (len + length(file[j])+5 > 75) { + printf " \\\n\t"; + len = 8; + } + len += length(file[j]) + 5; + printf "%s.fmt ", file[j]; + } + printf "\n"; + + for(j = 0; j < nfile; j++) { + printf "%s.fmt: %s.1 header.me\n", file[j], file[j];\ + } + + len = 14; + printf "sis.1: sis.man "; + for(j = 0; j < nfile; j++) { + if (len + length(file[j])+3 > 75) { + printf " \\\n\t"; + len = 8; + } + len += length(file[j]) + 3; + printf "%s.1 ", file[j]; + } + printf "\n"; +} diff --git a/sis/sis_lib/help/map.1 b/sis/sis_lib/help/map.1 new file mode 100644 index 0000000..7c58cb5 --- /dev/null +++ b/sis/sis_lib/help/map.1 @@ -0,0 +1,115 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/map.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +map [-b #][-f #][-i][-m #][-n #][-r][-s][-p][-v #] [-A][-B #][-F][-G][-W] +.PP +Perform a technology mapping on the current network. A library must be read +using the \fBread_library\fR command before mapping can be performed. +The result +of the mapping may become invalidated if a command such as \fBplot\fR or +\fBprint_stats -f\fR is executed which computes a factored form +representation of +every node. +.PP +To produce a minimum area circuit with no consideration for load limits, the +recommended option is \fBmap -m 0\fR. +.PP +To produce a minimum area circuit that respects load limits, the recommended +option is \fBmap -m 0 -AF\fR. Use \fB_check_load_limit\fR +command to check for +load limit violations. +.PP +To produce a minimum delay circuit that respects load limits, the recommended +option is \fBmap -n 1 -AFG\fR. +To specify required times in order to allow the +mapper to trade off delay and area, use the \fBset_delay\fR command. +.PP +Details about the meanings of the various options follow. +.PP +The \fB-b n\fP sets the number by which the load value +should be multiplied in case of a load limit violation during fanout optimization. +.PP +The \fB-f n\fP option controls the internal fanout handling. A value +of '0' disables it completely (i.e. the mapping is strictly +tree-based). +A value of '1' enables an heuristics approximating the +cost of the previous tree at fanout branches. +A value of '2' enables +the usage of cells with internal fanout (such as EXOR and +MULTIPLEXER). A value of '3' (default) enables both. None of these +values is guaranteed to give the best solution in all cases, but '3' +usually does. A warning is issued if the current value can give bad +results with the current network (use \fBundo\fR before mapping +again). +.PP +The \fB-i\fP option disables the \fIinverter-at-branch-point\fR heuristic. +It is intended for experimentation with different mapping heuristics. +.PP +The \fB-m\fP option controls the cost function used for a simple version of the +tree covering algorithm. A mode of '0' (the default) minimizes the area of the +resulting circuit. A mode of '1' minimizes the delay of the resulting circuit +(without regard to the total area). An intermediate value uses as cost +function a linear combination of the two, and can be used to explore the +area-delay tradeoff. A value of '2' minimizes the delay on an estimate of the +critical path obtained from a trivial 2-input NAND mapping, and the area +elsewhere. +.PP +The \fB-n\fP option allows the access to a better tree covering algorithm. It +can only be used in delay mode, i.e. with an argument of 1: \fB-n 1\fP. This +algorithm gives better performance than \fB-m 1\fP but is noticeably slower. It uses a +finer dynamic programming algorithm that takes output load values into account, +while \fB-m 1\fP option supposes all loads to be the same. As a consequence, +the \fB-n 1\fP option performs better than \fB-m 1\fP especially with rich +libraries of gates. Both algorithms use heuristics to guess the load value at +multiple fanout points. Both options should always be used with fanout +optimization turned on. +.PP +If \fB-r\fP is given (\fIraw mode\fP), the network must already be either 1- +and 2-input NAND gates, or 1- and 2-input NOR gates form, depending on whether +a NAND-library, or a NOR-library was specified when the library was originally +read (see \fBread_library\fR). +If \fB-r\fP is not given, appropriate commands are +inserted to transform the network into the correct format. +.PP +The \fB-s\fP option prints brief statistics on the mapping results. +.PP +The \fB-p\fP option forces the mapper to ignore the delay information provided +by the user at primary inputs and primary outputs (arrival times, required +times, loads, drive capability). It is intended for experimental use. This +option forces the arrival times and required times to be all 0, the loads and +drive capabilities to be all equal to the load and drive capability of the second +smallest inverter in the library. If there is only one inverter, the data are +taken from that inverter. +.PP +The \fB-v n\fP options is for development use, and provides debugging +information of varying degrees of verbosity as the mapping proceeds. +.PP +The \fB-A\fP option recovers area after fanout optimization +at little or no delay cost by resizing buffers and inverters. +.PP +The \fB-B n\fP option controls the enforcement of load limits during fanout +optimization. A value of 0 ignores the load limits. A value of 1 takes +load limits into account. The default is set to 1. +This option is effective only in conjunction with fanout optimization. It is +implemented by artificially increasing the load at a gate output by a +multiplicative factor whenever the load exceeds the limit specified in the +library. The default multiplicative factor is 1000. This value can be changed +with the \fB-b n\fP option. There is a priori no reason to change this value. +.PP +The \fB-F\fP option performs fanout optimization. This disables the internal +fanout handling (i.e. forces \fB-f 0\fP). In order to recover area +after fanout optimization use the \fB-A\fP option. There are several fanout +optimization algorithms implemented in \fBSIS\fR. For details, type +\fBhelp fanout_alg\fR and \fBhelp fanout_params\fR. +.PP +The \fB-G\fP option recovers area after fanout optimization +at no cost in delay by resizing all gates in the network. +.PP +The \fB-W\fP option suppresses the warning messages. diff --git a/sis/sis_lib/help/map.fmt b/sis/sis_lib/help/map.fmt new file mode 100644 index 0000000..e816195 --- /dev/null +++ b/sis/sis_lib/help/map.fmt @@ -0,0 +1,108 @@ + + July 1, 1994 SIS(1) + + map [-b #][-f #][-i][-m #][-n #][-r][-s][-p][-v #] [-A][-B #][-F][-G][-W] + + Perform a technology mapping on the current network. A library must be + read using the read_library command before mapping can be performed. + The result of the mapping may become invalidated if a command such as + plot or print_stats -f is executed which computes a factored form + representation of every node. + + To produce a minimum area circuit with no consideration for load limits, + the recommended option is map -m 0. + + To produce a minimum area circuit that respects load limits, the recom- + mended option is map -m 0 -AF. Use _check_load_limit command to check + for load limit violations. + + To produce a minimum delay circuit that respects load limits, the recom- + mended option is map -n 1 -AFG. To specify required times in order to + allow the mapper to trade off delay and area, use the set_delay command. + + Details about the meanings of the various options follow. + + The -b n sets the number by which the load value should be multiplied in + case of a load limit violation during fanout optimization. + + The -f n option controls the internal fanout handling. A value of '0' + disables it completely (i.e. the mapping is strictly tree-based). A + value of '1' enables an heuristics approximating the cost of the previ- + ous tree at fanout branches. A value of '2' enables the usage of cells + with internal fanout (such as EXOR and MULTIPLEXER). A value of '3' + (default) enables both. None of these values is guaranteed to give the + best solution in all cases, but '3' usually does. A warning is issued if + the current value can give bad results with the current network (use + undo before mapping again). + + The -i option disables the _i_n_v_e_r_t_e_r-_a_t-_b_r_a_n_c_h-_p_o_i_n_t heuristic. It is + intended for experimentation with different mapping heuristics. + + The -m option controls the cost function used for a simple version of + the tree covering algorithm. A mode of '0' (the default) minimizes the + area of the resulting circuit. A mode of '1' minimizes the delay of the + resulting circuit (without regard to the total area). An intermediate + value uses as cost function a linear combination of the two, and can be + used to explore the area-delay tradeoff. A value of '2' minimizes the + delay on an estimate of the critical path obtained from a trivial 2- + input NAND mapping, and the area elsewhere. + + The -n option allows the access to a better tree covering algorithm. It + can only be used in delay mode, i.e. with an argument of 1: -n 1. This + algorithm gives better performance than -m 1 but is noticeably slower. + It uses a finer dynamic programming algorithm that takes output load + values into account, while -m 1 option supposes all loads to be the + same. As a consequence, the -n 1 option performs better than -m 1 espe- + cially with rich libraries of gates. Both algorithms use heuristics to + + 1 + + SIS(1) July 1, 1994 + + guess the load value at multiple fanout points. Both options should + always be used with fanout optimization turned on. + + If -r is given (_r_a_w _m_o_d_e), the network must already be either 1- and 2- + input NAND gates, or 1- and 2-input NOR gates form, depending on whether + a NAND-library, or a NOR-library was specified when the library was ori- + ginally read (see read_library). If -r is not given, appropriate com- + mands are inserted to transform the network into the correct format. + + The -s option prints brief statistics on the mapping results. + + The -p option forces the mapper to ignore the delay information provided + by the user at primary inputs and primary outputs (arrival times, + required times, loads, drive capability). It is intended for experimen- + tal use. This option forces the arrival times and required times to be + all 0, the loads and drive capabilities to be all equal to the load and + drive capability of the second smallest inverter in the library. If + there is only one inverter, the data are taken from that inverter. + + The -v n options is for development use, and provides debugging informa- + tion of varying degrees of verbosity as the mapping proceeds. + + The -A option recovers area after fanout optimization at little or no + delay cost by resizing buffers and inverters. + + The -B n option controls the enforcement of load limits during fanout + optimization. A value of 0 ignores the load limits. A value of 1 + takes load limits into account. The default is set to 1. This option + is effective only in conjunction with fanout optimization. It is imple- + mented by artificially increasing the load at a gate output by a multi- + plicative factor whenever the load exceeds the limit specified in the + library. The default multiplicative factor is 1000. This value can be + changed with the -b n option. There is a priori no reason to change this + value. + + The -F option performs fanout optimization. This disables the internal + fanout handling (i.e. forces -f 0). In order to recover area after + fanout optimization use the -A option. There are several fanout optimi- + zation algorithms implemented in SIS. For details, type help fanout_alg + and help fanout_params. + + The -G option recovers area after fanout optimization at no cost in + delay by resizing all gates in the network. + + The -W option suppresses the warning messages. + + 2 diff --git a/sis/sis_lib/help/one_hot.1 b/sis/sis_lib/help/one_hot.1 new file mode 100644 index 0000000..d73a7c6 --- /dev/null +++ b/sis/sis_lib/help/one_hot.1 @@ -0,0 +1,15 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/one_hot.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +one_hot +.PP +Does a quick one-hot encoding of the current STG. +It assigns one-hot codes, minimizes the resulting PLA +using espresso, and returns the network to SIS. diff --git a/sis/sis_lib/help/one_hot.fmt b/sis/sis_lib/help/one_hot.fmt new file mode 100644 index 0000000..5590254 --- /dev/null +++ b/sis/sis_lib/help/one_hot.fmt @@ -0,0 +1,10 @@ + + July 1, 1994 SIS(1) + + one_hot + + Does a quick one-hot encoding of the current STG. It assigns one-hot + codes, minimizes the resulting PLA using espresso, and returns the net- + work to SIS. + + 1 diff --git a/sis/sis_lib/help/phase.1 b/sis/sis_lib/help/phase.1 new file mode 100644 index 0000000..5978e0c --- /dev/null +++ b/sis/sis_lib/help/phase.1 @@ -0,0 +1,28 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/phase.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +phase [-qgst] [-r n] +.PP +Decide for each node whether to implement the node or its complement +in order to reduce the total cost of the network. If the network is +mapped, the cost is the total area and the network will be kept mapped, +otherwise, the cost is the total number of inverters in the network +assuming all the inverters are already in the network. +At the end, all the necessary inverters are inserted into the network +and all the extra inverters are removed from the network. +.PP +The default algorithm, which can also be specified by \fB-q\fR option, is +a greedy algorithm called \fIquick phase\fR. The \fB-g\fR option uses +the Kernighan-Lin type algorithm called \fIgood phase\fR. The +\fB-s\fR option chooses the Simulated Annealing algorithm. The \fB-r n\fR +option chooses a random-greedy algorithm which does a random assignment first, +uses a greedy approach to get to a local minimum, and iterates +\fIn\fR times. If the \fB-t\fR option is specified, some tracing +information is printed as the assignment proceeds. diff --git a/sis/sis_lib/help/phase.fmt b/sis/sis_lib/help/phase.fmt new file mode 100644 index 0000000..99c0bf7 --- /dev/null +++ b/sis/sis_lib/help/phase.fmt @@ -0,0 +1,23 @@ + + July 1, 1994 SIS(1) + + phase [-qgst] [-r n] + + Decide for each node whether to implement the node or its complement in + order to reduce the total cost of the network. If the network is + mapped, the cost is the total area and the network will be kept mapped, + otherwise, the cost is the total number of inverters in the network + assuming all the inverters are already in the network. At the end, all + the necessary inverters are inserted into the network and all the extra + inverters are removed from the network. + + The default algorithm, which can also be specified by -q option, is a + greedy algorithm called _q_u_i_c_k _p_h_a_s_e. The -g option uses the Kernighan- + Lin type algorithm called _g_o_o_d _p_h_a_s_e. The -s option chooses the Simu- + lated Annealing algorithm. The -r n option chooses a random-greedy + algorithm which does a random assignment first, uses a greedy approach + to get to a local minimum, and iterates _n times. If the -t option is + specified, some tracing information is printed as the assignment + proceeds. + + 1 diff --git a/sis/sis_lib/help/plot_blif.1 b/sis/sis_lib/help/plot_blif.1 new file mode 100644 index 0000000..c555b80 --- /dev/null +++ b/sis/sis_lib/help/plot_blif.1 @@ -0,0 +1,43 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/plot_blif.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +plot_blif [-k] [-r] [-i] [-g WxH+X+Y] [-n name] +.PP +The \fBplot_blif\fR command +creates a window with an abstract representation of the +network, at its current level of optimization, labeling all nodes, including +primary inputs and outputs. +Vectors are used to show relationships between the various nodes. +Latches are not printed explicitly. +The network is drawn as an acyclic combinational circuit. +Labelled arrows indicate the locations of the latches. +.PP +The \fB-k\fR option "kills" (closes) the most recent plot window with +the current network name. +.PP +The \fB-r\fR option replaces the contents of an existing plot window +with the current network structure. +This is useful if the network has been modified since it was last +plotted. +If no plot window is open with the current network name, the command +has no effect. +.PP +The \fB-i\fR option forces a plot of the internal network structure +used by \fISIS\fP. +The default is to plot the structure corresponding to the write_blif +command. +The primary difference in the internal structure is in how primary +outputs are handled. +.PP +The \fB-g\fR option allows an initial geometry to be specified +for the plot window. +.PP +The \fB-n\fR option allows "name" to be used for the plot window name +instead of the network name. diff --git a/sis/sis_lib/help/plot_blif.fmt b/sis/sis_lib/help/plot_blif.fmt new file mode 100644 index 0000000..97660c6 --- /dev/null +++ b/sis/sis_lib/help/plot_blif.fmt @@ -0,0 +1,32 @@ + + July 1, 1994 SIS(1) + + plot_blif [-k] [-r] [-i] [-g WxH+X+Y] [-n name] + + The plot_blif command creates a window with an abstract representation + of the network, at its current level of optimization, labeling all + nodes, including primary inputs and outputs. Vectors are used to show + relationships between the various nodes. Latches are not printed expli- + citly. The network is drawn as an acyclic combinational circuit. + Labelled arrows indicate the locations of the latches. + + The -k option "kills" (closes) the most recent plot window with the + current network name. + + The -r option replaces the contents of an existing plot window with the + current network structure. This is useful if the network has been modi- + fied since it was last plotted. If no plot window is open with the + current network name, the command has no effect. + + The -i option forces a plot of the internal network structure used by + _S_I_S. The default is to plot the structure corresponding to the + write_blif command. The primary difference in the internal structure is + in how primary outputs are handled. + + The -g option allows an initial geometry to be specified for the plot + window. + + The -n option allows "name" to be used for the plot window name instead + of the network name. + + 1 diff --git a/sis/sis_lib/help/power_estimate.1 b/sis/sis_lib/help/power_estimate.1 new file mode 100644 index 0000000..395ce5b --- /dev/null +++ b/sis/sis_lib/help/power_estimate.1 @@ -0,0 +1,103 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/power_estimate.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:45 $ +.\" * +.\" +.XX +power_estimate [-m c] [-d c] [-t c] [-s c] [-a n] [-e f] [-n n] + [-f file] [-S] [-M n] [-N n] [-R] [-h] [-v] + +.PP +Estimates the power dissipated in a circuit due to switching activity: +.nf + P = 0.5 x Vdd^2 x sum(p x C ) / f + i i i +where + + Vdd = 5V + f = 20MHz + p = expected number of transitions of node i in one clock cycle + i + C = capacitive load of node i + i +.fi + +The expected number of transitions of each node per clock cycle is +calculated through symbolic simulation, based on the static +probabilities of the primary inputs (by default prob_one = prob_zero = +0.5). The capacitive load of a node is obtained by summing the gate +capacitances of its fanout nodes and adding some internal drain +capacitance. Gate capacitances are multiple of a minimum sized +transistor (0.01pF), admitting transistor sizing based on the number +of inputs to the node (up to a value max_input_sizing, default +4). Drain capacitances are calculated from the number of transistors +this node has (multiple of 0.005pF) and this number can be obtained +either from a factored form or sum of products. + +.PP +\fB-m c\fR Estimation mode, c either SAMPLING or BDD (default). + +.PP +\fB-d c\fR Delay model, c one of ZERO (default), UNIT or GENERAL (from +library). + +.PP +\fB-t c\fR Estimation type, c one of COMBINATIONAL (default), +SEQUENTIAL, PIPELINE or DYNAMIC (for dynamic domino circuits). + +.PP +\fB-s c\fR PS lines probability calculation method, c one of APPROXIMATE +(default), EXACT or UNIFORM (0.5 is used). Only used for SEQUENTIAL +type. + +.PP +\fB-a n\fR Number of PS lines to be correlated (default 1). Only used +for the APPROXIMATION method. + +.PP +\fB-e f\fR Maximum error allowed for PS lines probabilities (default +0.01). Only used for the APPROXIMATION method. + +.PP +\fB-n n\fR Number of sets of 32 input vectors to be simulated (default +100). Only used for SAMPLING mode. + +.PP +\fB-f filename\fR Allows the specification of input probabilities, node +capacitances and node delays in the format: + +.nf + name "nodename" p0 "value" + name "nodename" p1 "value" + name "nodename" cap_factor "value" + name "nodename" delay "value" +.fi + +.PP +\fB-S\fR Assumes complex gates in sum of products form (default is factored +form). + +.PP +\fB-M n\fR Maximum number of inputs of a node considered for transistor +sizing (default 4). + +.PP +\fB-N n\fR Interval of input vectors for which the current value of +power estimation is printed. Only used for SAMPLING mode. + +.PP +\fB-R\fR Sets latch capacitances to 0, only comb power reported. + +.PP +\fB-h\fR Prints power_estimate usage. + +.PP +\fB-V n\fR Verbose run time information. + +Note: currently a memory fault occurs on the RS6000 when the exact calculation +is used for present state probabilities. This is probably due to the use +of stg_extract. diff --git a/sis/sis_lib/help/power_estimate.fmt b/sis/sis_lib/help/power_estimate.fmt new file mode 100644 index 0000000..7cf8439 --- /dev/null +++ b/sis/sis_lib/help/power_estimate.fmt @@ -0,0 +1,83 @@ + + July 1, 1994 SIS(1) + + power_estimate [-m c] [-d c] [-t c] [-s c] [-a n] [-e f] [-n n] + [-f file] [-S] [-M n] [-N n] [-R] [-h] [-v] + + Estimates the power dissipated in a circuit due to switching activity: + P = 0.5 x Vdd^2 x sum(p x C ) / f + i i i + where + + Vdd = 5V + f = 20MHz + p = expected number of transitions of node i in one clock cycle + i + C = capacitive load of node i + i + + The expected number of transitions of each node per clock cycle is cal- + culated through symbolic simulation, based on the static probabilities + of the primary inputs (by default prob_one = prob_zero = 0.5). The capa- + citive load of a node is obtained by summing the gate capacitances of + its fanout nodes and adding some internal drain capacitance. Gate capa- + citances are multiple of a minimum sized transistor (0.01pF), admitting + transistor sizing based on the number of inputs to the node (up to a + value max_input_sizing, default 4). Drain capacitances are calculated + from the number of transistors this node has (multiple of 0.005pF) and + this number can be obtained either from a factored form or sum of pro- + ducts. + + -m c Estimation mode, c either SAMPLING or BDD (default). + + -d c Delay model, c one of ZERO (default), UNIT or GENERAL (from + library). + + -t c Estimation type, c one of COMBINATIONAL (default), SEQUENTIAL, + PIPELINE or DYNAMIC (for dynamic domino circuits). + + -s c PS lines probability calculation method, c one of APPROXIMATE + (default), EXACT or UNIFORM (0.5 is used). Only used for SEQUENTIAL + type. + + -a n Number of PS lines to be correlated (default 1). Only used for the + APPROXIMATION method. + + -e f Maximum error allowed for PS lines probabilities (default 0.01). + Only used for the APPROXIMATION method. + + 1 + + SIS(1) July 1, 1994 + + -n n Number of sets of 32 input vectors to be simulated (default 100). + Only used for SAMPLING mode. + + -f filename Allows the specification of input probabilities, node capa- + citances and node delays in the format: + + name "nodename" p0 "value" + name "nodename" p1 "value" + name "nodename" cap_factor "value" + name "nodename" delay "value" + + -S Assumes complex gates in sum of products form (default is factored + form). + + -M n Maximum number of inputs of a node considered for transistor sizing + (default 4). + + -N n Interval of input vectors for which the current value of power + estimation is printed. Only used for SAMPLING mode. + + -R Sets latch capacitances to 0, only comb power reported. + + -h Prints power_estimate usage. + + -V n Verbose run time information. + + Note: currently a memory fault occurs on the RS6000 when the exact cal- + culation is used for present state probabilities. This is probably due + to the use of stg_extract. + + 2 diff --git a/sis/sis_lib/help/power_free_info.1 b/sis/sis_lib/help/power_free_info.1 new file mode 100644 index 0000000..7ee4781 --- /dev/null +++ b/sis/sis_lib/help/power_free_info.1 @@ -0,0 +1,16 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/power_free_info.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:45 $ +.\" * +.\" +.XX +power_free_info + +.PP +Frees data structures storing capacitance and switching of every node in +the network. + diff --git a/sis/sis_lib/help/power_free_info.fmt b/sis/sis_lib/help/power_free_info.fmt new file mode 100644 index 0000000..4d0d888 --- /dev/null +++ b/sis/sis_lib/help/power_free_info.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + power_free_info + + Frees data structures storing capacitance and switching of every node in + the network. + + 1 diff --git a/sis/sis_lib/help/power_print.1 b/sis/sis_lib/help/power_print.1 new file mode 100644 index 0000000..7e7191e --- /dev/null +++ b/sis/sis_lib/help/power_print.1 @@ -0,0 +1,17 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/power_print.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:45 $ +.\" * +.\" +.XX +power_print + +.PP +Prints the switching probability and capacitance for each node in the +network. Only valid after a power estimation has been performed. + + diff --git a/sis/sis_lib/help/power_print.fmt b/sis/sis_lib/help/power_print.fmt new file mode 100644 index 0000000..6196d3d --- /dev/null +++ b/sis/sis_lib/help/power_print.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + power_print + + Prints the switching probability and capacitance for each node in the + network. Only valid after a power estimation has been performed. + + 1 diff --git a/sis/sis_lib/help/print.1 b/sis/sis_lib/help/print.1 new file mode 100644 index 0000000..8bd34f5 --- /dev/null +++ b/sis/sis_lib/help/print.1 @@ -0,0 +1,19 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +print [-n] [-d] node-list +.PP +Print all the nodes in the \fBnode-list\fR in sum-of-product form. +.PP +If \fB-n\fR option is specified, the nodes are printed in +the negative form. (i.e. a' + b' will be printed as (a b)'). +.PP +If \fB-d\fR option is specified, the nodes in the external +don't care network are printed. diff --git a/sis/sis_lib/help/print.fmt b/sis/sis_lib/help/print.fmt new file mode 100644 index 0000000..d66611d --- /dev/null +++ b/sis/sis_lib/help/print.fmt @@ -0,0 +1,14 @@ + + July 1, 1994 SIS(1) + + print [-n] [-d] node-list + + Print all the nodes in the node-list in sum-of-product form. + + If -n option is specified, the nodes are printed in the negative form. + (i.e. a' + b' will be printed as (a b)'). + + If -d option is specified, the nodes in the external don't care network + are printed. + + 1 diff --git a/sis/sis_lib/help/print_altname.1 b/sis/sis_lib/help/print_altname.1 new file mode 100644 index 0000000..66e123c --- /dev/null +++ b/sis/sis_lib/help/print_altname.1 @@ -0,0 +1,16 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_altname.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +print_altname node-list +.PP +Print the alternate name of all the nodes in the +\fBnode-list\fR. If the current name mode is \fIshort\fR (\fBSIS\fR +internal name), the alternate name will be the \fIlong\fR name +(user-specified name) and vice-versa. diff --git a/sis/sis_lib/help/print_altname.fmt b/sis/sis_lib/help/print_altname.fmt new file mode 100644 index 0000000..f5617c7 --- /dev/null +++ b/sis/sis_lib/help/print_altname.fmt @@ -0,0 +1,10 @@ + + July 1, 1994 SIS(1) + + print_altname node-list + + Print the alternate name of all the nodes in the node-list. If the + current name mode is _s_h_o_r_t (SIS internal name), the alternate name will + be the _l_o_n_g name (user-specified name) and vice-versa. + + 1 diff --git a/sis/sis_lib/help/print_clock.1 b/sis/sis_lib/help/print_clock.1 new file mode 100644 index 0000000..5bc44e9 --- /dev/null +++ b/sis/sis_lib/help/print_clock.1 @@ -0,0 +1,15 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_clock.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +print_clock +.PP +Prints the clocking scheme associated with the current network. +The clocking scheme printed depends on the current setting +of the clock data structure (see \fB chng_clock\fR). diff --git a/sis/sis_lib/help/print_clock.fmt b/sis/sis_lib/help/print_clock.fmt new file mode 100644 index 0000000..b654930 --- /dev/null +++ b/sis/sis_lib/help/print_clock.fmt @@ -0,0 +1,10 @@ + + July 1, 1994 SIS(1) + + print_clock + + Prints the clocking scheme associated with the current network. The + clocking scheme printed depends on the current setting of the clock data + structure (see chng_clock). + + 1 diff --git a/sis/sis_lib/help/print_delay.1 b/sis/sis_lib/help/print_delay.1 new file mode 100644 index 0000000..3c76b54 --- /dev/null +++ b/sis/sis_lib/help/print_delay.1 @@ -0,0 +1,52 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_delay.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +print_delay [-alrs] [-m model] [-p n] [-f file-name] [node-list] +.PP +Do a delay trace (static timing analysis) +on the network depending on the specified \fBmodel\fR +and print the delay data. +Without any arguments the routine will +use the \fIlibrary\fR model which assumes that the network is mapped and +will print the arrival times, required times and the slack for all the +nodes in the network. +.PP +Specifying an optional \fBnode-list\fR will print the delay data +only for the specified nodes. +.PP +The user can selectively have portions of the delay data printed. +The option \fB-a\fP will cause the arrival times to be printed. +The option \fB-r\fP will cause the required times to be printed. +The option \fB-s\fP will cause the slacks at nodes to be reported. +The option \fB-l\fP will cause the load driven by the node to be printed. +.PP +The option \fB-p n\fP when specified with one of the options \fB-[alrs]\fP +will print out the delay data so that the first \fBn\fP nodes with the +most critical values are printed. The critical portion of the delay data +is determined by the first of the options \fB-[alrs]\fP specified. +Thus specifying \fB-p n -[al]\fP prints the \fBn\fP nodes with the greatest +arrival-time/load. For the \fB-[rs]\fP option the nodes with the smallest +required-time/slack are printed. +.PP +The delay model can be specified by the \fB-m\fP option followed by one +of the following keywords --- \fIunit\fR, \fIunit-fanout\fR, +\fIlibrary\fR, \fImapped\fR or \fItdc\fR. +Specifying \fIunit\fR results in delay being computed as 1 unit per node in +the network. +\fIunit-fanout\fR adds an additional delay of 0.2 per fanout. +If a library has been read in using the \fBread_library\fP command one +can use more accurate models, \fImapped\fR and \fIlibrary\fR, by using data +stored in the library. Using the model \fIlibrary\fR assumes that the network +has been mapped. The \fImapped\fR model does not make this assumption and will +do a mapping of the nodes on an individual basis to compute a +delay model for use during the delay trace. +The \fItdc\fR model is an attempt to predict the delay of a node based on the +distribution of arrival times. The parameters used in this model prediction +are optionally specified using the \fB-f\fR option. diff --git a/sis/sis_lib/help/print_delay.fmt b/sis/sis_lib/help/print_delay.fmt new file mode 100644 index 0000000..01ceaed --- /dev/null +++ b/sis/sis_lib/help/print_delay.fmt @@ -0,0 +1,43 @@ + + July 1, 1994 SIS(1) + + print_delay [-alrs] [-m model] [-p n] [-f file-name] [node-list] + + Do a delay trace (static timing analysis) on the network depending on + the specified model and print the delay data. Without any arguments the + routine will use the _l_i_b_r_a_r_y model which assumes that the network is + mapped and will print the arrival times, required times and the slack + for all the nodes in the network. + + Specifying an optional node-list will print the delay data only for the + specified nodes. + + The user can selectively have portions of the delay data printed. The + option -a will cause the arrival times to be printed. The option -r will + cause the required times to be printed. The option -s will cause the + slacks at nodes to be reported. The option -l will cause the load + driven by the node to be printed. + + The option -p n when specified with one of the options -[alrs] will + print out the delay data so that the first n nodes with the most criti- + cal values are printed. The critical portion of the delay data is deter- + mined by the first of the options -[alrs] specified. Thus specifying -p + n -[al] prints the n nodes with the greatest arrival-time/load. For the + -[rs] option the nodes with the smallest required-time/slack are + printed. + + The delay model can be specified by the -m option followed by one of the + following keywords --- _u_n_i_t, _u_n_i_t-_f_a_n_o_u_t, _l_i_b_r_a_r_y, _m_a_p_p_e_d or _t_d_c. + Specifying _u_n_i_t results in delay being computed as 1 unit per node in + the network. _u_n_i_t-_f_a_n_o_u_t adds an additional delay of 0.2 per fanout. + If a library has been read in using the read_library command one can use + more accurate models, _m_a_p_p_e_d and _l_i_b_r_a_r_y, by using data stored in the + library. Using the model _l_i_b_r_a_r_y assumes that the network has been + mapped. The _m_a_p_p_e_d model does not make this assumption and will do a + mapping of the nodes on an individual basis to compute a delay model for + use during the delay trace. The _t_d_c model is an attempt to predict the + delay of a node based on the distribution of arrival times. The parame- + ters used in this model prediction are optionally specified using the -f + option. + + 1 diff --git a/sis/sis_lib/help/print_factor.1 b/sis/sis_lib/help/print_factor.1 new file mode 100644 index 0000000..884b500 --- /dev/null +++ b/sis/sis_lib/help/print_factor.1 @@ -0,0 +1,15 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_factor.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +print_factor node-list +.PP +Print all the nodes in the \fBnode-list\fR in the \fIfactored\fR form. +If a node has not beed factored, \fIfactor -q\fR will be used to +factor the node. diff --git a/sis/sis_lib/help/print_factor.fmt b/sis/sis_lib/help/print_factor.fmt new file mode 100644 index 0000000..95675e3 --- /dev/null +++ b/sis/sis_lib/help/print_factor.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + print_factor node-list + + Print all the nodes in the node-list in the _f_a_c_t_o_r_e_d form. If a node + has not beed factored, _f_a_c_t_o_r -_q will be used to factor the node. + + 1 diff --git a/sis/sis_lib/help/print_gate.1 b/sis/sis_lib/help/print_gate.1 new file mode 100644 index 0000000..253d09c --- /dev/null +++ b/sis/sis_lib/help/print_gate.1 @@ -0,0 +1,18 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_gate.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +print_gate [-ps] node-list +.PP +Prints the information provided in the library for the list of mapped +gates. +.PP +The \fB-p\fR option prints the pin information of the gates. +.PP +The \fB-s\fR option prints summary of the gates and their area. diff --git a/sis/sis_lib/help/print_gate.fmt b/sis/sis_lib/help/print_gate.fmt new file mode 100644 index 0000000..2a59a6c --- /dev/null +++ b/sis/sis_lib/help/print_gate.fmt @@ -0,0 +1,13 @@ + + July 1, 1994 SIS(1) + + print_gate [-ps] node-list + + Prints the information provided in the library for the list of mapped + gates. + + The -p option prints the pin information of the gates. + + The -s option prints summary of the gates and their area. + + 1 diff --git a/sis/sis_lib/help/print_io.1 b/sis/sis_lib/help/print_io.1 new file mode 100644 index 0000000..fe5fb67 --- /dev/null +++ b/sis/sis_lib/help/print_io.1 @@ -0,0 +1,17 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_io.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +print_io [-d] [node-list] +.PP +Print both fanin and fanout list for each node in the \fBnode-list\fR. +Absence of \fBnode-list\fR implies all the nodes in the current network. +.PP +If the \fB-d\fR option is specified, the nodes in the external don't care +network are considered. diff --git a/sis/sis_lib/help/print_io.fmt b/sis/sis_lib/help/print_io.fmt new file mode 100644 index 0000000..12bb646 --- /dev/null +++ b/sis/sis_lib/help/print_io.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + print_io [-d] [node-list] + + Print both fanin and fanout list for each node in the node-list. + Absence of node-list implies all the nodes in the current network. + + If the -d option is specified, the nodes in the external don't care net- + work are considered. + + 1 diff --git a/sis/sis_lib/help/print_kernel.1 b/sis/sis_lib/help/print_kernel.1 new file mode 100644 index 0000000..0cebaa0 --- /dev/null +++ b/sis/sis_lib/help/print_kernel.1 @@ -0,0 +1,17 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_kernel.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +print_kernel [-as] node-list +.PP +Print kernels and corresponding co-kernels of all the nodes in +the \fBnode-list\fR. If \fB-a\fR option (default) is specified, +all kernels, including the function itself if it is a kernel, are +printed. If \fB-s\fR option is specified, only +the sub-kernels are printed. diff --git a/sis/sis_lib/help/print_kernel.fmt b/sis/sis_lib/help/print_kernel.fmt new file mode 100644 index 0000000..ed797e2 --- /dev/null +++ b/sis/sis_lib/help/print_kernel.fmt @@ -0,0 +1,11 @@ + + July 1, 1994 SIS(1) + + print_kernel [-as] node-list + + Print kernels and corresponding co-kernels of all the nodes in the + node-list. If -a option (default) is specified, all kernels, including + the function itself if it is a kernel, are printed. If -s option is + specified, only the sub-kernels are printed. + + 1 diff --git a/sis/sis_lib/help/print_latch.1 b/sis/sis_lib/help/print_latch.1 new file mode 100644 index 0000000..8de2cb3 --- /dev/null +++ b/sis/sis_lib/help/print_latch.1 @@ -0,0 +1,22 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_latch.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +print_latch [-s] [node-list] +.PP +With no arguments, \fBprint_latch\fR prints out information for +all the latches in the network. +The information printed for each latch is the latch input, latch output, +initial value, current value, synchronization type, and controlling node. +The latch values can be 0, 1, 2 (don't care), and 3 (undefined). + +If the \fB-s\fR option is specified, only the latch input, output, initial +and current values are given. +If a \fBnode-list\fR is given, only the latches associated with those +nodes are printed (each node should be a latch input or output). diff --git a/sis/sis_lib/help/print_latch.fmt b/sis/sis_lib/help/print_latch.fmt new file mode 100644 index 0000000..070fb5a --- /dev/null +++ b/sis/sis_lib/help/print_latch.fmt @@ -0,0 +1,17 @@ + + July 1, 1994 SIS(1) + + print_latch [-s] [node-list] + + With no arguments, print_latch prints out information for all the + latches in the network. The information printed for each latch is the + latch input, latch output, initial value, current value, synchronization + type, and controlling node. The latch values can be 0, 1, 2 (don't + care), and 3 (undefined). + + If the -s option is specified, only the latch input, output, initial and + current values are given. If a node-list is given, only the latches + associated with those nodes are printed (each node should be a latch + input or output). + + 1 diff --git a/sis/sis_lib/help/print_level.1 b/sis/sis_lib/help/print_level.1 new file mode 100644 index 0000000..8890c93 --- /dev/null +++ b/sis/sis_lib/help/print_level.1 @@ -0,0 +1,26 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_level.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +print_level [-l] [-c] [-m model] [-t value] [node-list] +.PP +Prints the nodes of the network according to their level. +When called with a \fBnode-list\fR, only the nodes in the +transitve fanin of the specified nodes are printed. +The primary inputs are assigned level 0, and the level of +a node is the length of the longest path from it to a +primary input. The \fB -l\fR options prints only the +number of levels in the network. +.PP +If the \fB-c\fR option is specified, only critical nodes are +printed according to their level. The delay trace is done +according to the \fB-m model\fR option (default is the +unit-fanout model) and all the nodes with a slack within a +\fB-t value\fR of the smallest slack are considered to be +critical. diff --git a/sis/sis_lib/help/print_level.fmt b/sis/sis_lib/help/print_level.fmt new file mode 100644 index 0000000..1771bbd --- /dev/null +++ b/sis/sis_lib/help/print_level.fmt @@ -0,0 +1,17 @@ + + July 1, 1994 SIS(1) + + print_level [-l] [-c] [-m model] [-t value] [node-list] + + Prints the nodes of the network according to their level. When called + with a node-list, only the nodes in the transitve fanin of the specified + nodes are printed. The primary inputs are assigned level 0, and the + level of a node is the length of the longest path from it to a primary + input. The -l options prints only the number of levels in the network. + + If the -c option is specified, only critical nodes are printed according + to their level. The delay trace is done according to the -m model option + (default is the unit-fanout model) and all the nodes with a slack within + a -t value of the smallest slack are considered to be critical. + + 1 diff --git a/sis/sis_lib/help/print_library.1 b/sis/sis_lib/help/print_library.1 new file mode 100644 index 0000000..fd37b97 --- /dev/null +++ b/sis/sis_lib/help/print_library.1 @@ -0,0 +1,33 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_library.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +print_library [-a][-f][-h][-l][-r] [function-string] +.PP +Print the contents of the current library. If the optional string is +given, only the combinational gates with the same logic function as the string +will be printed. \fIfunction-string\fP is in the format of +read_eqn. For example +.in +1i +.nf +print_library "f=!(a*b);" +.in -1i +.fi +will print all combinational gates with a NAND2 logic function. +.PP +The \fB-a\fP option prints asynchronous type latches matching the 'function-string'. +.PP +The \fB-f\fP option prints falling edge triggered flip-flops matching the 'function-string'. +.PP +The \fB-h\fP option prints active high transparent latches matching the 'function-string'. +.PP +The \fB-l\fP option prints active low transparent latches matching the 'function-string'. +.PP +The \fB-r\fP option prints rising edge triggered flip-flops matching the 'function-string'. + diff --git a/sis/sis_lib/help/print_library.fmt b/sis/sis_lib/help/print_library.fmt new file mode 100644 index 0000000..9070df0 --- /dev/null +++ b/sis/sis_lib/help/print_library.fmt @@ -0,0 +1,28 @@ + + July 1, 1994 SIS(1) + + print_library [-a][-f][-h][-l][-r] [function-string] + + Print the contents of the current library. If the optional string is + given, only the combinational gates with the same logic function as the + string will be printed. _f_u_n_c_t_i_o_n-_s_t_r_i_n_g is in the format of read_eqn. + For example + print_library "f=!(a*b);" + will print all combinational gates with a NAND2 logic function. + + The -a option prints asynchronous type latches matching the 'function- + string'. + + The -f option prints falling edge triggered flip-flops matching the + 'function-string'. + + The -h option prints active high transparent latches matching the + 'function-string'. + + The -l option prints active low transparent latches matching the + 'function-string'. + + The -r option prints rising edge triggered flip-flops matching the + 'function-string'. + + 1 diff --git a/sis/sis_lib/help/print_map_stats.1 b/sis/sis_lib/help/print_map_stats.1 new file mode 100644 index 0000000..3f7777b --- /dev/null +++ b/sis/sis_lib/help/print_map_stats.1 @@ -0,0 +1,13 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_map_stats.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +print_map_stats +.PP +Prints delay and area information of the network. The network should be mapped. diff --git a/sis/sis_lib/help/print_map_stats.fmt b/sis/sis_lib/help/print_map_stats.fmt new file mode 100644 index 0000000..8c30ff4 --- /dev/null +++ b/sis/sis_lib/help/print_map_stats.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + print_map_stats + + Prints delay and area information of the network. The network should be + mapped. + + 1 diff --git a/sis/sis_lib/help/print_state.1 b/sis/sis_lib/help/print_state.1 new file mode 100644 index 0000000..59a1c24 --- /dev/null +++ b/sis/sis_lib/help/print_state.1 @@ -0,0 +1,19 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_state.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +print_state +.PP +Prints out the current state of the machine for both the STG +and the logic implementation. +For the logic implementation, the current state is printed as +a string of integers representing the values on the latches: +0, 1, 2 (don't care), and 3 (undefined). +For the STG, the current state is printed with its symbolic +and encoded names. diff --git a/sis/sis_lib/help/print_state.fmt b/sis/sis_lib/help/print_state.fmt new file mode 100644 index 0000000..cd42655 --- /dev/null +++ b/sis/sis_lib/help/print_state.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + print_state + + Prints out the current state of the machine for both the STG and the + logic implementation. For the logic implementation, the current state + is printed as a string of integers representing the values on the + latches: 0, 1, 2 (don't care), and 3 (undefined). For the STG, the + current state is printed with its symbolic and encoded names. + + 1 diff --git a/sis/sis_lib/help/print_stats.1 b/sis/sis_lib/help/print_stats.1 new file mode 100644 index 0000000..d49b15a --- /dev/null +++ b/sis/sis_lib/help/print_stats.1 @@ -0,0 +1,26 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_stats.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +print_stats [-f] [-d] +.PP +Print the current network status, which includes the network name, +number of primary inputs (pi), number of primary outputs (po), +number of nodes (nodes), the number of latches (latches), +the number of literals in the sum-of-product +form (lits(sop)), and the number of states in the STG +(#states(STG)). +.PP +If \fB-f\fR option is specified, the number of literals in +the factored form (lits(fac)) is computed. +This could be slow when +the factored form for some network takes too long to generate. +.PP +If \fB-d\fR option is specified, the statistics of the external don't care +network is printed. diff --git a/sis/sis_lib/help/print_stats.fmt b/sis/sis_lib/help/print_stats.fmt new file mode 100644 index 0000000..7e0b133 --- /dev/null +++ b/sis/sis_lib/help/print_stats.fmt @@ -0,0 +1,19 @@ + + July 1, 1994 SIS(1) + + print_stats [-f] [-d] + + Print the current network status, which includes the network name, + number of primary inputs (pi), number of primary outputs (po), number of + nodes (nodes), the number of latches (latches), the number of literals + in the sum-of-product form (lits(sop)), and the number of states in the + STG (#states(STG)). + + If -f option is specified, the number of literals in the factored form + (lits(fac)) is computed. This could be slow when the factored form for + some network takes too long to generate. + + If -d option is specified, the statistics of the external don't care + network is printed. + + 1 diff --git a/sis/sis_lib/help/print_value.1 b/sis/sis_lib/help/print_value.1 new file mode 100644 index 0000000..79de10b --- /dev/null +++ b/sis/sis_lib/help/print_value.1 @@ -0,0 +1,25 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/print_value.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +print_value [-a] [-d] [-p n] node-list +.PP +Print the value of all the nodes in the \fBnode-list\fR. The value +is currently defined as the number of literals increased if the node +were eliminated from the network. Since the value of a node depends +on the particular factored form of the node and its fanouts, all the +nodes which don't have factored forms will be factored using +\fIfactor -q\fR. +.PP +The \fB-a\fR option prints the values in ascending order. +.PP +The \fB-d\fR option prints the values in descending order. +.PP +The \fB-p\fR takes an argument \fBn\fR, and directs print_value to only +print the top n values. diff --git a/sis/sis_lib/help/print_value.fmt b/sis/sis_lib/help/print_value.fmt new file mode 100644 index 0000000..807ee4c --- /dev/null +++ b/sis/sis_lib/help/print_value.fmt @@ -0,0 +1,19 @@ + + July 1, 1994 SIS(1) + + print_value [-a] [-d] [-p n] node-list + + Print the value of all the nodes in the node-list. The value is + currently defined as the number of literals increased if the node were + eliminated from the network. Since the value of a node depends on the + particular factored form of the node and its fanouts, all the nodes + which don't have factored forms will be factored using _f_a_c_t_o_r -_q. + + The -a option prints the values in ascending order. + + The -d option prints the values in descending order. + + The -p takes an argument n, and directs print_value to only print the + top n values. + + 1 diff --git a/sis/sis_lib/help/quit.1 b/sis/sis_lib/help/quit.1 new file mode 100644 index 0000000..a9e2eb2 --- /dev/null +++ b/sis/sis_lib/help/quit.1 @@ -0,0 +1,16 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/quit.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +quit [-s] +.PP +Stop the program. Does not save the current network before exiting. +\fB-s\fP frees all the memory before quitting. This is slower, and +is used for finding core leaks or when \fIsis\fR is called from +another program. diff --git a/sis/sis_lib/help/quit.fmt b/sis/sis_lib/help/quit.fmt new file mode 100644 index 0000000..c5ec5f4 --- /dev/null +++ b/sis/sis_lib/help/quit.fmt @@ -0,0 +1,10 @@ + + July 1, 1994 SIS(1) + + quit [-s] + + Stop the program. Does not save the current network before exiting. -s + frees all the memory before quitting. This is slower, and is used for + finding core leaks or when _s_i_s is called from another program. + + 1 diff --git a/sis/sis_lib/help/read_astg.1 b/sis/sis_lib/help/read_astg.1 new file mode 100644 index 0000000..9234647 --- /dev/null +++ b/sis/sis_lib/help/read_astg.1 @@ -0,0 +1,74 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/read_astg.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +read_astg [<file-name>] +.PP +Read a text description of an Asynchronous Signal Transition Graph (ASTG). +The overall format follows the style of BLIF, and uses +an adjacency list to describe the net interconnection +structure. +If no filename is specified, the description is read from stdin. +.PP +All names in the ASTG description must start with a letter, +consist of letters, digits and underscores, and are case-sensitive. +A signal transition is represented with a suffix: "+" means a low +to high transition, "-" means high to low, "~" means toggles (changes +to the opposite value. +.PP + .model <model-name> +.br +This gives an arbitrary name to the ASTG, and it +must be the first line of the model description. +.PP + .inputs <signal-list> +.br +Specifies a list of names of ASTG input signals. +Signals from multiple .inputs are concatenated. +.PP + .outputs <signal-list> +.br +Specifies a list of names of ASTG output signals. +Signals from multiple .inputs are concatenated. +.PP + .internal <signal-list> +.br +Specifies a list of names of ASTG internal signals, i.e. +signals which are only used to maintain state information. +.PP + .dummy <name-list> +.br +Specifies a list of names which are accepted as dummy or null +transitions. +Null transitions are necessary to specify some behaviors using +the ASTG syntax. +By convention, the name "e" is used as a dummy signal (to +represent epsilon transitions). + .graph +.br +Indicates the lines which follow describe the ASTG net structure +using an adjacency list format. +This must follow all signal declarations (.inputs, etc.). +Net places are optional for simple constraints between two transitions; +in this case an intervening place is generated automatically. +Multiple instances of a transition are distinguished by following +them with a slash and a copy number. +For example, a second instance of transition "t+" can be +specified by "t+/2". +Copy numbers do not have to be consecutive. +.PP + .marking {<place-list>} +An initial marking can optionally be specified after the net structure +has been given. +Implied places (see .graph) between two transitions x* and y* can +be specified using the syntax <x*,y*>. + .end +This required line indicates the end of the ASTG description. +.PP +Error messages are printed for any unrecognized input sequences. diff --git a/sis/sis_lib/help/read_astg.fmt b/sis/sis_lib/help/read_astg.fmt new file mode 100644 index 0000000..2a0947a --- /dev/null +++ b/sis/sis_lib/help/read_astg.fmt @@ -0,0 +1,55 @@ + + July 1, 1994 SIS(1) + + read_astg [<file-name>] + + Read a text description of an Asynchronous Signal Transition Graph + (ASTG). The overall format follows the style of BLIF, and uses an adja- + cency list to describe the net interconnection structure. If no + filename is specified, the description is read from stdin. + + All names in the ASTG description must start with a letter, consist of + letters, digits and underscores, and are case-sensitive. A signal tran- + sition is represented with a suffix: "+" means a low to high transition, + "-" means high to low, "~" means toggles (changes to the opposite value. + + .model <model-name> + This gives an arbitrary name to the ASTG, and it must be the first line + of the model description. + + .inputs <signal-list> + Specifies a list of names of ASTG input signals. Signals from multiple + .inputs are concatenated. + + .outputs <signal-list> + Specifies a list of names of ASTG output signals. Signals from multiple + .inputs are concatenated. + + .internal <signal-list> + Specifies a list of names of ASTG internal signals, i.e. signals which + are only used to maintain state information. + + .dummy <name-list> + Specifies a list of names which are accepted as dummy or null transi- + tions. Null transitions are necessary to specify some behaviors using + the ASTG syntax. By convention, the name "e" is used as a dummy signal + (to represent epsilon transitions). + .graph + Indicates the lines which follow describe the ASTG net structure using + an adjacency list format. This must follow all signal declarations + (.inputs, etc.). Net places are optional for simple constraints between + two transitions; in this case an intervening place is generated automat- + ically. Multiple instances of a transition are distinguished by follow- + ing them with a slash and a copy number. For example, a second instance + of transition "t+" can be specified by "t+/2". Copy numbers do not have + to be consecutive. + + .marking {<place-list>} An initial marking can optionally be specified + after the net structure has been given. Implied places (see .graph) + between two transitions x* and y* can be specified using the syntax + <x*,y*>. + .end This required line indicates the end of the ASTG description. + + Error messages are printed for any unrecognized input sequences. + + 1 diff --git a/sis/sis_lib/help/read_blif.1 b/sis/sis_lib/help/read_blif.1 new file mode 100644 index 0000000..e1ec049 --- /dev/null +++ b/sis/sis_lib/help/read_blif.1 @@ -0,0 +1,45 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/read_blif.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +read_blif [-a] filename +.PP +Read in a network from the file \fBfilename\fP which is assumed +to be in \fIblif\fP format. +The network name is given +by the \fI.model\fP statement in the file. If a \fI.model\fP +is not given, the network name is the filename with any trailing +extension removed. +See the blif.tex document for a complete description +of the \fIblif\fP format. +.PP +The user can also specify an external don't care network. This +network must be placed after the care network in the same +file. The statement \fI.exdc\fP must precede the description +of the external don't care network. The names of primary outputs and +primary inputs of the external don't care network +must be exactly the same as the names of primary outputs +and primary inputs of the care network. +.PP +Usual filename conventions apply: \fB-\fP (or no +filename) stands for standard input, and tilde-expansion is performed +on the filename. +.PP +Normal operation is to replace the current network with a new network. +If no external don't care network is specified, the external don't +care network is set to NIL (nonexistent). Otherwise the external +don't care network is replaced by the new external don't care network. +The -a option specifies that the new network should be appended to the +current network. Functions are associated between the two networks +using the long names of each network. Name conflicts (where two +functions attempt to define the same name) generate warning messages +and are resolved by renaming the signal from the new network. +.PP +The \fB-s\fR option, though accepted, has no effect on \fBread_blif\fR, and is +instead reserved for the \fBread_pla\fR command. diff --git a/sis/sis_lib/help/read_blif.fmt b/sis/sis_lib/help/read_blif.fmt new file mode 100644 index 0000000..5d11178 --- /dev/null +++ b/sis/sis_lib/help/read_blif.fmt @@ -0,0 +1,35 @@ + + July 1, 1994 SIS(1) + + read_blif [-a] filename + + Read in a network from the file filename which is assumed to be in _b_l_i_f + format. The network name is given by the ._m_o_d_e_l statement in the file. + If a ._m_o_d_e_l is not given, the network name is the filename with any + trailing extension removed. See the blif.tex document for a complete + description of the _b_l_i_f format. + + The user can also specify an external don't care network. This network + must be placed after the care network in the same file. The statement + ._e_x_d_c must precede the description of the external don't care network. + The names of primary outputs and primary inputs of the external don't + care network must be exactly the same as the names of primary outputs + and primary inputs of the care network. + + Usual filename conventions apply: - (or no filename) stands for standard + input, and tilde-expansion is performed on the filename. + + Normal operation is to replace the current network with a new network. + If no external don't care network is specified, the external don't care + network is set to NIL (nonexistent). Otherwise the external don't care + network is replaced by the new external don't care network. The -a + option specifies that the new network should be appended to the current + network. Functions are associated between the two networks using the + long names of each network. Name conflicts (where two functions attempt + to define the same name) generate warning messages and are resolved by + renaming the signal from the new network. + + The -s option, though accepted, has no effect on read_blif, and is + instead reserved for the read_pla command. + + 1 diff --git a/sis/sis_lib/help/read_eqn.1 b/sis/sis_lib/help/read_eqn.1 new file mode 100644 index 0000000..564fad0 --- /dev/null +++ b/sis/sis_lib/help/read_eqn.1 @@ -0,0 +1,68 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/read_eqn.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +read_eqn [-a] [filename] +.PP +Read a set of logic equations in the format expected by eqntott(1). +Each equation becomes a node in the logic network. +.PP +INORDER and OUTORDER can be used to specify the primary inputs and +primary outputs for the network. If neither is given, then primary +inputs are inferred from signals which are not driven, and +primary outputs are inferred from signals which do not have any +fanout. +.PP +The equations are of the form "<signal> = <expr> ;". +For reference, the equation format uses the operators: +.LP +.TS +center box; +l l. +() grouping +!= (or ^) exclusive-or +== exclusive-nor +! complement +& (or *) boolean-and +| (or +) boolean-or +.TE +As a simple extension to eqntott, juxtaposition of two operands stands +for boolean-and, and ' used as a post-fix operator stands for complement. +Hence, +.nf + F = a*!b + c*!d ; +.fi +and +.nf + F = a b' + c d' ; +.fi +represent the same equation. +.PP +Note that eqntott and \fBread_eqn\fR treat the intermediate nodes of a network +slightly differently. +\fBread_eqn\fR will not make an intermediate node +a primary output unless it also appears in the OUTORDER list. +Also, the resulting network is a multiple-level network with all +of the intermediate signals preserved. +Finally, eqntott is order-dependent in that it requires signals to +be defined before they can be used again; \fBread_eqn\fR relaxes this +condition. +.PP +The \fB-a\fR option specifies that the new network should be appended to the +current network. Functions are associated between the two networks +using the long names of each network. Name conflicts (where two +functions attempt to define the same name) generate warning messages +and are resolved by renaming the signal from the new network. +.PP +The \fB-s\fR option, though accepted, has no effect on \fBread_eqn\fR +and is instead +reserved for the \fBread_pla\fR command. +.pp +Note that since the characters '(' and ')' are used for grouping, +they cannot be part of a signal name. diff --git a/sis/sis_lib/help/read_eqn.fmt b/sis/sis_lib/help/read_eqn.fmt new file mode 100644 index 0000000..8740862 --- /dev/null +++ b/sis/sis_lib/help/read_eqn.fmt @@ -0,0 +1,50 @@ + + July 1, 1994 SIS(1) + + read_eqn [-a] [filename] + + Read a set of logic equations in the format expected by eqntott(1). + Each equation becomes a node in the logic network. + + INORDER and OUTORDER can be used to specify the primary inputs and pri- + mary outputs for the network. If neither is given, then primary inputs + are inferred from signals which are not driven, and primary outputs are + inferred from signals which do not have any fanout. + + The equations are of the form "<signal> = <expr> ;". For reference, the + equation format uses the operators: + + ___________________________ + | () grouping | + | != (or ^) exclusive-or | + | == exclusive-nor| + | ! complement | + | & (or *) boolean-and | + ||_|__(_o_r__+_)_____b_o_o_l_e_a_n_-_o_r_____|| + As a simple extension to eqntott, juxtaposition of two operands stands + for boolean-and, and ' used as a post-fix operator stands for comple- + ment. Hence, + F = a*!b + c*!d ; + and + F = a b' + c d' ; + represent the same equation. + + Note that eqntott and read_eqn treat the intermediate nodes of a network + slightly differently. read_eqn will not make an intermediate node a + primary output unless it also appears in the OUTORDER list. Also, the + resulting network is a multiple-level network with all of the intermedi- + ate signals preserved. Finally, eqntott is order-dependent in that it + requires signals to be defined before they can be used again; read_eqn + relaxes this condition. + + The -a option specifies that the new network should be appended to the + current network. Functions are associated between the two networks + using the long names of each network. Name conflicts (where two func- + tions attempt to define the same name) generate warning messages and are + resolved by renaming the signal from the new network. + + The -s option, though accepted, has no effect on read_eqn and is instead + reserved for the read_pla command. Note that since the characters '(' + and ')' are used for grouping, they cannot be part of a signal name. + + 1 diff --git a/sis/sis_lib/help/read_kiss.1 b/sis/sis_lib/help/read_kiss.1 new file mode 100644 index 0000000..69c9464 --- /dev/null +++ b/sis/sis_lib/help/read_kiss.1 @@ -0,0 +1,27 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/read_kiss.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +read_kiss [filename] +.PP +Reads a \fIkiss2\fP format file into a state transition graph. The state +names may be symbolic or strings of "0" and "1". Inputs and outputs should be +strings of "0", "1", and "-"; inputs should not be symbolic. +The \fIkiss2\fP format is described in doc/blif.tex. +Note that there is no mechanism for specifying the names of the +I/O pins in \fIkiss2\fP. +Naming can be done in \fBSIS\fP by specifying a \fIblif\fP +file containing the \fI.inputs\fP and \fI.outputs\fP lines +(which give I/O names) followed by the embedded \fIkiss2\fP +file. +See also \fBstg_to_network\fR, \fBread_kiss_net\fR. +.PP +Note that \fIread_kiss\fP followed by \fIwrite_kiss\fP alters the ordering of +the product terms. This could make a difference in the \fInova\fP +output. diff --git a/sis/sis_lib/help/read_kiss.fmt b/sis/sis_lib/help/read_kiss.fmt new file mode 100644 index 0000000..b6cc8cd --- /dev/null +++ b/sis/sis_lib/help/read_kiss.fmt @@ -0,0 +1,18 @@ + + July 1, 1994 SIS(1) + + read_kiss [filename] + + Reads a _k_i_s_s_2 format file into a state transition graph. The state + names may be symbolic or strings of "0" and "1". Inputs and outputs + should be strings of "0", "1", and "-"; inputs should not be symbolic. + The _k_i_s_s_2 format is described in doc/blif.tex. Note that there is no + mechanism for specifying the names of the I/O pins in _k_i_s_s_2. Naming can + be done in SIS by specifying a _b_l_i_f file containing the ._i_n_p_u_t_s and + ._o_u_t_p_u_t_s lines (which give I/O names) followed by the embedded _k_i_s_s_2 + file. See also stg_to_network, read_kiss_net. + + Note that _r_e_a_d__k_i_s_s followed by _w_r_i_t_e__k_i_s_s alters the ordering of the + product terms. This could make a difference in the _n_o_v_a output. + + 1 diff --git a/sis/sis_lib/help/read_library.1 b/sis/sis_lib/help/read_library.1 new file mode 100644 index 0000000..188406f --- /dev/null +++ b/sis/sis_lib/help/read_library.1 @@ -0,0 +1,21 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/read_library.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +read_library [-ainr] filename +.PP +Read a \fBSIS\fR-format library for future technology mapping. +The \fB-a\fP option appends the library to the current library; +otherwise, any previous library is discarded. +The \fB-i\fP flag suppresses adding extra inverters to all of the +primitives. This is intended for debugging only. +The \fB-n\fP flag requests that a library, if it is generated, be +made using NAND gates rather than NOR gates. +The \fB-r\fP flag reads a raw library format (given in BLIF) +rather than the normal genlib format. diff --git a/sis/sis_lib/help/read_library.fmt b/sis/sis_lib/help/read_library.fmt new file mode 100644 index 0000000..f5e614c --- /dev/null +++ b/sis/sis_lib/help/read_library.fmt @@ -0,0 +1,14 @@ + + July 1, 1994 SIS(1) + + read_library [-ainr] filename + + Read a SIS-format library for future technology mapping. The -a option + appends the library to the current library; otherwise, any previous + library is discarded. The -i flag suppresses adding extra inverters to + all of the primitives. This is intended for debugging only. The -n + flag requests that a library, if it is generated, be made using NAND + gates rather than NOR gates. The -r flag reads a raw library format + (given in BLIF) rather than the normal genlib format. + + 1 diff --git a/sis/sis_lib/help/read_oct.1 b/sis/sis_lib/help/read_oct.1 new file mode 100644 index 0000000..9d8b9bc --- /dev/null +++ b/sis/sis_lib/help/read_oct.1 @@ -0,0 +1,20 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/read_oct.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +read_oct cell[:view] +.PP +Read in a network from the Oct facet `cell:view:contents'. +If `view' is not specified, it defaults to `logic'. +The network name is set to `cell:view'. +Oct nets without names are given machine-generated unique names. +All primary inputs and outputs are named the same as the equivalent +Oct formal terminals of the facet. +.PP +This operation replaces the current network with the new network. diff --git a/sis/sis_lib/help/read_oct.fmt b/sis/sis_lib/help/read_oct.fmt new file mode 100644 index 0000000..59e1ba0 --- /dev/null +++ b/sis/sis_lib/help/read_oct.fmt @@ -0,0 +1,14 @@ + + July 1, 1994 SIS(1) + + read_oct cell[:view] + + Read in a network from the Oct facet `cell:view:contents'. If `view' is + not specified, it defaults to `logic'. The network name is set to + `cell:view'. Oct nets without names are given machine-generated unique + names. All primary inputs and outputs are named the same as the + equivalent Oct formal terminals of the facet. + + This operation replaces the current network with the new network. + + 1 diff --git a/sis/sis_lib/help/read_pla.1 b/sis/sis_lib/help/read_pla.1 new file mode 100644 index 0000000..32d74de --- /dev/null +++ b/sis/sis_lib/help/read_pla.1 @@ -0,0 +1,46 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/read_pla.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +read_pla [-a] [-s] [-c] filename +.PP +Read in an espresso-format PLA from the +file \fBfilename\fP (see espresso(5) for more +information). The network name is derived +from the filename with any trailing extension removed. +.PP +Usual filename conventions apply: \fB-\fP (or no +filename) stands for standard input, and tilde-expansion is performed +on the filename. +.PP +Normal operation is to replace the current network with a single-level +network of complex gates with the same logic functions as the PLA outputs. +This makes each PLA output a separate single-output function and is +a good starting point for the standard scripts. +If don't care conditions exist, the external +don't care network is also replaced with a single-level network +which implements the don't care conditions of the PLA. +Otherwise, the external don't care network is set to NIL (nonexistent). +.PP +The \fB-c\fP option replaces the current network with +a two-level network of NOR-gates (and inverters) +which implements the PLA. +This preserves the multiple-output nature of the PLA. +The external don't care network is manipulated exactly the same as above. +This used to be the default, while the \fB-s\fP option +replaced the network with a single-level network as described above. +The \fB-s\fP option has been retained for compatibility. +.PP +The \fB-a\fR option specifies that the new network should be appended to the +current network. +Functions are associated between the two networks +using the long names of each network. +Name conflicts (two +functions attempt to define the same name) generate warning messages +and are resolved by renaming the signal from the new network. diff --git a/sis/sis_lib/help/read_pla.fmt b/sis/sis_lib/help/read_pla.fmt new file mode 100644 index 0000000..fca32cc --- /dev/null +++ b/sis/sis_lib/help/read_pla.fmt @@ -0,0 +1,35 @@ + + July 1, 1994 SIS(1) + + read_pla [-a] [-s] [-c] filename + + Read in an espresso-format PLA from the file filename (see espresso(5) + for more information). The network name is derived from the filename + with any trailing extension removed. + + Usual filename conventions apply: - (or no filename) stands for standard + input, and tilde-expansion is performed on the filename. + + Normal operation is to replace the current network with a single-level + network of complex gates with the same logic functions as the PLA out- + puts. This makes each PLA output a separate single-output function and + is a good starting point for the standard scripts. If don't care condi- + tions exist, the external don't care network is also replaced with a + single-level network which implements the don't care conditions of the + PLA. Otherwise, the external don't care network is set to NIL (nonex- + istent). + + The -c option replaces the current network with a two-level network of + NOR-gates (and inverters) which implements the PLA. This preserves the + multiple-output nature of the PLA. The external don't care network is + manipulated exactly the same as above. This used to be the default, + while the -s option replaced the network with a single-level network as + described above. The -s option has been retained for compatibility. + + The -a option specifies that the new network should be appended to the + current network. Functions are associated between the two networks + using the long names of each network. Name conflicts (two functions + attempt to define the same name) generate warning messages and are + resolved by renaming the signal from the new network. + + 1 diff --git a/sis/sis_lib/help/read_slif.1 b/sis/sis_lib/help/read_slif.1 new file mode 100644 index 0000000..75735a7 --- /dev/null +++ b/sis/sis_lib/help/read_slif.1 @@ -0,0 +1,17 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/read_slif.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +read_slif filename +.PP +Read in a network from the file \fBfilename\fP which is in \fIslif\fP +format. \fISLIF\fP is a hierarchical circuit description language and the +root network, the one returned to the caller, is defined to be the first +network encountered in the file \fBfilename\fP. + diff --git a/sis/sis_lib/help/read_slif.fmt b/sis/sis_lib/help/read_slif.fmt new file mode 100644 index 0000000..77a8645 --- /dev/null +++ b/sis/sis_lib/help/read_slif.fmt @@ -0,0 +1,11 @@ + + July 1, 1994 SIS(1) + + read_slif filename + + Read in a network from the file filename which is in _s_l_i_f format. _S_L_I_F + is a hierarchical circuit description language and the root network, the + one returned to the caller, is defined to be the first network encoun- + tered in the file filename. + + 1 diff --git a/sis/sis_lib/help/red_removal.1 b/sis/sis_lib/help/red_removal.1 new file mode 100644 index 0000000..d41d4af --- /dev/null +++ b/sis/sis_lib/help/red_removal.1 @@ -0,0 +1,69 @@ +.XX +red_removal [-hqrRpt] [-d RTG_depth] [-n n_fault_sim] [-v verbosity_level] + [-y random_prop_depth] +.PP +Perform sequential redundancy removal using random test generation, +deterministic test generation, and fault simulation. Deterministic test +generation is accomplished by one of two methods. The first method is a +three-step test generation algorithm consisting of combinational test +generation (assuming that latch outputs are controllable, and that latch +inputs are observable), followed by state justification and propagation, +when necessary. The combinational test generation is accomplished using +Boolean satisfiability. Justification and propagation are performed using +implicit state transition graph traversal techniques. If the three-step +method does not generate a test for a fault, then the product of the good +and faulty circuit is built and traversed, as in sequential circuit +verification. If this traversal proves the circuits equivalent, then the +fault is redundant; otherwise any differentiating sequence is a test for +the fault. +.PP +Each time a redundant fault is encountered during deterministic test +generation, the redundant line is replaced by a constant 1 or 0, and +deterministic test generation begins again. At the end of the redundancy +removal procedure, the network is 100% testable for single stuck faults +unless the test generator aborts on some faults. +.PP +For combinational circuits, external don't cares are automatically taken +into account when the don't care network is attached to the care network. The PI's and PO's of the external don't care network (when it is not NIL) must match exactly with the care network. That is, the don't care network cannot specify only a subset of the PI's or PO's of the care network. If this +condition is not met, then the atpg package automatically adds dummy primary +inputs and outputs to the external don't care network. +.PP +The \fB-h\fP option restricts the boolean satisfiability algorithm to not +use non-local implications. Four greedy ordering heuristics are tried in +this case instead of the default of eight. Hard-to-test faults that can only +be tested with non-local implication information are aborted by this option. +.PP +The \fB-q\fP specifies "quick redundancy removal." With this option, the +deterministic test generation algorithm identifies only those redundant faults +that cannot be excited from any reachable state. In practice, quick redundancy +removal usually gives the same results as regular redundancy removal, in much +less time. +.PP +The \fB-r\fP option causes the test generator not to perform random test pattern +generation. +.PP +The \fB-R\fP option causes the test generator not to perform random propagation. +(Deterministic propagation is still attempted). +.PP +The \fB-p\fP option causes the test generator not to build any product +machines. Thus, neither deterministic propagation nor good/faulty product +machine traversal will be performed. +.PP +The \fB-t\fP option first converts the network to arbitrary fanin AND and +OR gates. The decomposed network is returned. +.PP +The \fB-d\fP option allows the specification of the length of the random +sequences applied during random test generation. The default length is +the depth of the circuit's state transition graph. +.PP +The \fB-n\fP option allows the specification of the number of sequences +to fault simulate at one time during fault simulation. The default is the +system word length. +.PP +The \fB-v\fP allows the specification of the verbosity level of the output. +.PP +The \fB-y\fP option allows the specification of the length of the random +sequences applied during random propagation. The default length is 20. +.PP +Note: in order to use this command with sequential circuits, the circuit +reset state must be specified in the circuit input file. diff --git a/sis/sis_lib/help/red_removal.fmt b/sis/sis_lib/help/red_removal.fmt new file mode 100644 index 0000000..8283c6c --- /dev/null +++ b/sis/sis_lib/help/red_removal.fmt @@ -0,0 +1,83 @@ + + July 1, 1994 SIS(1) + + red_removal [-hqrRpt] [-d RTG_depth] [-n n_fault_sim] [-v verbosity_level] + [-y random_prop_depth] + + Perform sequential redundancy removal using random test generation, + deterministic test generation, and fault simulation. Deterministic test + generation is accomplished by one of two methods. The first method is a + three-step test generation algorithm consisting of combinational test + generation (assuming that latch outputs are controllable, and that latch + inputs are observable), followed by state justification and propagation, + when necessary. The combinational test generation is accomplished using + Boolean satisfiability. Justification and propagation are performed + using implicit state transition graph traversal techniques. If the + three-step method does not generate a test for a fault, then the product + of the good and faulty circuit is built and traversed, as in sequential + circuit verification. If this traversal proves the circuits equivalent, + then the fault is redundant; otherwise any differentiating sequence is a + test for the fault. + + Each time a redundant fault is encountered during deterministic test + generation, the redundant line is replaced by a constant 1 or 0, and + deterministic test generation begins again. At the end of the redundancy + removal procedure, the network is 100% testable for single stuck faults + unless the test generator aborts on some faults. + + For combinational circuits, external don't cares are automatically taken + into account when the don't care network is attached to the care net- + work. The PI's and PO's of the external don't care network (when it is + not NIL) must match exactly with the care network. That is, the don't + care network cannot specify only a subset of the PI's or PO's of the + care network. If this condition is not met, then the atpg package + automatically adds dummy primary inputs and outputs to the external + don't care network. + + The -h option restricts the boolean satisfiability algorithm to not use + non-local implications. Four greedy ordering heuristics are tried in + this case instead of the default of eight. Hard-to-test faults that can + only be tested with non-local implication information are aborted by + this option. + + The -q specifies "quick redundancy removal." With this option, the + deterministic test generation algorithm identifies only those redundant + faults that cannot be excited from any reachable state. In practice, + quick redundancy removal usually gives the same results as regular + redundancy removal, in much less time. + + The -r option causes the test generator not to perform random test pat- + tern generation. + + The -R option causes the test generator not to perform random propaga- + tion. (Deterministic propagation is still attempted). + + The -p option causes the test generator not to build any product + machines. Thus, neither deterministic propagation nor good/faulty + + 1 + + SIS(1) July 1, 1994 + + product machine traversal will be performed. + + The -t option first converts the network to arbitrary fanin AND and OR + gates. The decomposed network is returned. + + The -d option allows the specification of the length of the random + sequences applied during random test generation. The default length is + the depth of the circuit's state transition graph. + + The -n option allows the specification of the number of sequences to + fault simulate at one time during fault simulation. The default is the + system word length. + + The -v allows the specification of the verbosity level of the output. + + The -y option allows the specification of the length of the random + sequences applied during random propagation. The default length is 20. + + Note: in order to use this command with sequential circuits, the circuit + reset state must be specified in the circuit input file. + + 2 diff --git a/sis/sis_lib/help/reduce_depth.1 b/sis/sis_lib/help/reduce_depth.1 new file mode 100644 index 0000000..a6292b2 --- /dev/null +++ b/sis/sis_lib/help/reduce_depth.1 @@ -0,0 +1,54 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/reduce_depth.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +reduce_depth [-b] [-d #] [-g] [-r] [-s #] [-v #] [-R #.#] [-S #] [-f #] +.PP +This command is to be used to improve the speed of a network before +technology mapping. It performs a partial collapse of the network by +first clustering nodes according to some criteria and collapsing each +cluster into a single node. The clusters are formed as follows: a +maximum cluster size is first computed, and the algorithm finds a +clustering that respects this size limit and minimizes the number of +levels in the network after the collapsing of the clusters. The size +limit is a limit on the number of nodes covered by the cluster, and +does not take into account the complexity of the nodes. Therefore this +command should only be used on networks decomposed into simple gates. +The cluster size limit can be provided in a variety of ways, +depending on which option is used. +.PP +The \fB-b\fP option performs the clustering under the duplication ratio +constraint specified by \fB-R\fP option. +.PP +The \fB-d #\fP option specifies the desired depth of the network after +clustering. The depth counts the number of nodes. Since each node +is expressed as a sum-of-products, specifying depth of 1 corresponds +to collapsing the network to two levels of logic. The algorithm +computes the minimum cluster size limit that yields a depth of \fBn\fR. +.PP +The \fB-g\fP option prints out statistics based on cluster sizes. No +clustering is done. +.PP +The \fB-r\fP option specifies a modification of the clustering +algorithm that produces the same number of logic levels but with less +duplication of logic. +.PP +The \fB-s #\fP option specifies the desired cluster size limit. +.PP +The \fB-v #\fP option specifies a verbosity level. It is used mainly for +debugging. +.PP +The \fB-R #.#\fP option specifies the maximum duplication ratio. The default is 2.0. +.PP +The \fB-S #\fP option specifies the smallest cluster size limit that +produces the same depth as a cluster size limit of \fBn\fR. +.PP +The \fB-f #\fP option specifies a cluster size limit in terms +of the number of fanins of the cluster. Its intended use is +for table-lookup FPGAs. It is a poor man's version of FlowMap. diff --git a/sis/sis_lib/help/reduce_depth.fmt b/sis/sis_lib/help/reduce_depth.fmt new file mode 100644 index 0000000..7a5b1b8 --- /dev/null +++ b/sis/sis_lib/help/reduce_depth.fmt @@ -0,0 +1,50 @@ + + July 1, 1994 SIS(1) + + reduce_depth [-b] [-d #] [-g] [-r] [-s #] [-v #] [-R #.#] [-S #] [-f #] + + This command is to be used to improve the speed of a network before + technology mapping. It performs a partial collapse of the network by + first clustering nodes according to some criteria and collapsing each + cluster into a single node. The clusters are formed as follows: a max- + imum cluster size is first computed, and the algorithm finds a cluster- + ing that respects this size limit and minimizes the number of levels in + the network after the collapsing of the clusters. The size limit is a + limit on the number of nodes covered by the cluster, and does not take + into account the complexity of the nodes. Therefore this command should + only be used on networks decomposed into simple gates. The cluster size + limit can be provided in a variety of ways, depending on which option is + used. + + The -b option performs the clustering under the duplication ratio con- + straint specified by -R option. + + The -d # option specifies the desired depth of the network after clus- + tering. The depth counts the number of nodes. Since each node is + expressed as a sum-of-products, specifying depth of 1 corresponds to + collapsing the network to two levels of logic. The algorithm computes + the minimum cluster size limit that yields a depth of n. + + The -g option prints out statistics based on cluster sizes. No cluster- + ing is done. + + The -r option specifies a modification of the clustering algorithm that + produces the same number of logic levels but with less duplication of + logic. + + The -s # option specifies the desired cluster size limit. + + The -v # option specifies a verbosity level. It is used mainly for + debugging. + + The -R #.# option specifies the maximum duplication ratio. The default + is 2.0. + + The -S # option specifies the smallest cluster size limit that produces + the same depth as a cluster size limit of n. + + The -f # option specifies a cluster size limit in terms of the number of + fanins of the cluster. Its intended use is for table-lookup FPGAs. It is + a poor man's version of FlowMap. + + 1 diff --git a/sis/sis_lib/help/remove_dep.1 b/sis/sis_lib/help/remove_dep.1 new file mode 100644 index 0000000..ec7b50e --- /dev/null +++ b/sis/sis_lib/help/remove_dep.1 @@ -0,0 +1,31 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/remove_dep.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:44 $ +.\" * +.\" +.XX +remove_dep [-o] [-v n] input output-list +.PP +The first node passed as argument should be an external primary input. +The remaining nodes passed as arguments should be external primary outputs. +This command assumes that the dependency between the given input +and the given outputs is structural but not logical, and it removes +these structural dependencies by forcing the input at 0 in the cone +of logic going from the input to the listed outputs. +.PP +The logic that depends on the given input and is shared with outputs +not passed as arguments is duplicated. +.PP +This function is useful when performing hierarchical optimization, +to guarantee that sis does not introduce dependencies that will create +combinational logic loops when the hierarchy is reassembled. +.PP +\fB-v\fR allows the specification of the verbosity level of the output. +The default value is 0. +.PP +With option \fB-o\fR the constant 1 is used instead of the constant 0 +to replace the input. diff --git a/sis/sis_lib/help/remove_dep.fmt b/sis/sis_lib/help/remove_dep.fmt new file mode 100644 index 0000000..789f6e7 --- /dev/null +++ b/sis/sis_lib/help/remove_dep.fmt @@ -0,0 +1,26 @@ + + July 1, 1994 SIS(1) + + remove_dep [-o] [-v n] input output-list + + The first node passed as argument should be an external primary input. + The remaining nodes passed as arguments should be external primary out- + puts. This command assumes that the dependency between the given input + and the given outputs is structural but not logical, and it removes + these structural dependencies by forcing the input at 0 in the cone of + logic going from the input to the listed outputs. + + The logic that depends on the given input and is shared with outputs not + passed as arguments is duplicated. + + This function is useful when performing hierarchical optimization, to + guarantee that sis does not introduce dependencies that will create com- + binational logic loops when the hierarchy is reassembled. + + -v allows the specification of the verbosity level of the output. The + default value is 0. + + With option -o the constant 1 is used instead of the constant 0 to + replace the input. + + 1 diff --git a/sis/sis_lib/help/remove_latches.1 b/sis/sis_lib/help/remove_latches.1 new file mode 100644 index 0000000..d60db05 --- /dev/null +++ b/sis/sis_lib/help/remove_latches.1 @@ -0,0 +1,34 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/remove_latches.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:44 $ +.\" * +.\" +.XX +remove_latches [-v n] [-f n] [-r] [-b] +.PP +This command removes redundant latches, using three different techniques. +.PP +First, it performs some local retiming, by moving forward latches +across combinational logic if that decreases the latch count. This +optimization can be disabled by specifying the option \fB-r\fR. +.PP +Second, it looks for boot latches, that is latches fed by a constant +but initialized at the opposite value. If there are such latches, it +looks for a state equivalent to the initial state in which the initial +value of the latch is equal to the value of its constant input. When +this optimization applies, the latch can be removed, and constant +folding propagates the constant across the logic. This optimization +can be disabled by specifying the option \fB-b\fR. +.PP +Third, it computes the set of reachable states, and checks whether +some latches cannot be deduced combinationally from other latches. +If that is the case, and if the fanin limit specified by the \fB-f\fR +option is not exceeded, the latch is removed and replaced by +combinational logic. +.PP +\fB-v\fR allows the specification of the verbosity level of the output. +The default value is 0. diff --git a/sis/sis_lib/help/remove_latches.fmt b/sis/sis_lib/help/remove_latches.fmt new file mode 100644 index 0000000..64c724f --- /dev/null +++ b/sis/sis_lib/help/remove_latches.fmt @@ -0,0 +1,29 @@ + + July 1, 1994 SIS(1) + + remove_latches [-v n] [-f n] [-r] [-b] + + This command removes redundant latches, using three different tech- + niques. + + First, it performs some local retiming, by moving forward latches across + combinational logic if that decreases the latch count. This optimization + can be disabled by specifying the option -r. + + Second, it looks for boot latches, that is latches fed by a constant but + initialized at the opposite value. If there are such latches, it looks + for a state equivalent to the initial state in which the initial value + of the latch is equal to the value of its constant input. When this + optimization applies, the latch can be removed, and constant folding + propagates the constant across the logic. This optimization can be dis- + abled by specifying the option -b. + + Third, it computes the set of reachable states, and checks whether some + latches cannot be deduced combinationally from other latches. If that + is the case, and if the fanin limit specified by the -f option is not + exceeded, the latch is removed and replaced by combinational logic. + + -v allows the specification of the verbosity level of the output. The + default value is 0. + + 1 diff --git a/sis/sis_lib/help/replace.1 b/sis/sis_lib/help/replace.1 new file mode 100644 index 0000000..c35088e --- /dev/null +++ b/sis/sis_lib/help/replace.1 @@ -0,0 +1,18 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/replace.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +replace [-t n] [-v n] +.PP +This is a simple routine that performs the same function as +\fBresub -a -d\fR on a network decomposed in 2-input NAND gates +using \fBtech_decomp -o 2\fR. It is just much faster. +.PP +The \fB-v n\fP specifies the verbosity level. +It is only used for debugging. diff --git a/sis/sis_lib/help/replace.fmt b/sis/sis_lib/help/replace.fmt new file mode 100644 index 0000000..bf0c8c2 --- /dev/null +++ b/sis/sis_lib/help/replace.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + replace [-t n] [-v n] + + This is a simple routine that performs the same function as resub -a -d + on a network decomposed in 2-input NAND gates using tech_decomp -o 2. It + is just much faster. + + The -v n specifies the verbosity level. It is only used for debugging. + + 1 diff --git a/sis/sis_lib/help/reset_name.1 b/sis/sis_lib/help/reset_name.1 new file mode 100644 index 0000000..31f963c --- /dev/null +++ b/sis/sis_lib/help/reset_name.1 @@ -0,0 +1,15 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/reset_name.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +reset_name [-ls] +.PP +Resets either the short names (starting again from the single letter a) +with the \fB-l\fP option, or the \fBSIS\fR-generated +long-names (starting again from [0]) with the \fB-s\fP option. diff --git a/sis/sis_lib/help/reset_name.fmt b/sis/sis_lib/help/reset_name.fmt new file mode 100644 index 0000000..c87d5cf --- /dev/null +++ b/sis/sis_lib/help/reset_name.fmt @@ -0,0 +1,10 @@ + + July 1, 1994 SIS(1) + + reset_name [-ls] + + Resets either the short names (starting again from the single letter a) + with the -l option, or the SIS-generated long-names (starting again from + [0]) with the -s option. + + 1 diff --git a/sis/sis_lib/help/resub.1 b/sis/sis_lib/help/resub.1 new file mode 100644 index 0000000..73eba90 --- /dev/null +++ b/sis/sis_lib/help/resub.1 @@ -0,0 +1,31 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/resub.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +resub [-a] [-b] [-d] [node-list] +.PP +Resubstitute each node in the \fBnode-list\fR into all the nodes in the network. +The resubstitution will try to use both the \fIpositive\fR and \fInegative\fR +phase of the node. If \fBnode-list\fR is not specified, the resubstitution +will be done for every node in the network and this operation will keep +looping until no more changes of the network can be made. Note +the difference between \fBresub *\fR and \fBresub\fR. The +former will apply the resubstitution to each node only once. +.PP +The \fB-a\fR (default) option uses algebraic division when +substituting one node into another. +The division is +performed on both the divisor and its complement. +.PP +The \fB-b\fR option uses Boolean division when substituting one +node into another. +NOTE: Boolean resubstitution has not yet been implemented. +.PP +The \fB-d\fR option directs \fBresub\fR not to use the complement of a given +node in algebraic resubstitutions. diff --git a/sis/sis_lib/help/resub.fmt b/sis/sis_lib/help/resub.fmt new file mode 100644 index 0000000..e16122b --- /dev/null +++ b/sis/sis_lib/help/resub.fmt @@ -0,0 +1,24 @@ + + July 1, 1994 SIS(1) + + resub [-a] [-b] [-d] [node-list] + + Resubstitute each node in the node-list into all the nodes in the net- + work. The resubstitution will try to use both the _p_o_s_i_t_i_v_e and _n_e_g_a_t_i_v_e + phase of the node. If node-list is not specified, the resubstitution + will be done for every node in the network and this operation will keep + looping until no more changes of the network can be made. Note the + difference between resub * and resub. The former will apply the resub- + stitution to each node only once. + + The -a (default) option uses algebraic division when substituting one + node into another. The division is performed on both the divisor and + its complement. + + The -b option uses Boolean division when substituting one node into + another. NOTE: Boolean resubstitution has not yet been implemented. + + The -d option directs resub not to use the complement of a given node in + algebraic resubstitutions. + + 1 diff --git a/sis/sis_lib/help/retime.1 b/sis/sis_lib/help/retime.1 new file mode 100644 index 0000000..d140788 --- /dev/null +++ b/sis/sis_lib/help/retime.1 @@ -0,0 +1,68 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/retime.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:37 $ +.\" * +.\" +.XX +retime [-nfim] [-c #.#] [-t #.#] [-d #.#] [-a #.#] [-v #] +.PP +Applies the retiming transformation on the circuit in an +effort to reduce the cycle time. The retiming operation is +supported only for single phase, edge-triggered designs. Both +mapped and unmapped networks can be retimed. +The algorithm attempts to maintain the initial state information. +.PP +The algorithm expects to work on mapped networks so that accurate +delays on the gates can be used. +However, an unmapped network can be retimed by using +the \fB-n\fR option. +In that case the delay through +each node is computed according to the \fIunit-fanout\fR delay model. +\fIThe user should be aware of the fact that when retiming circuits +containing complex registers (JK, D-flip flops with enables/presets), +the complex registers may have to be decomposed into simpler gates.\fR +.PP +By default the algorithm uses a relaxation based approach which +is very fast. An alternate formulation uses a mathematical +programming formulation and can be selected using the \fB-f\fR option. +After profiling on a number of circuits only one will be retained. +.PP +The \fB-m\fR option can be used to minimize the number of registers +under cycle time constraints. If the cycle time is not specified +using the \fB-c\fR option then this command will try to minimize the +cycle time. Thus to obtain the absolute minimum number of registers +for a circuit the user should specify a very loose cycle time constraint +(very large value for the \fB-c\fR option). +.PP +The retiming algorithm will try to compute the new initial states +of the latches. +In case no feasible initial state exists the retiming is aborted and +the network is not modified. To suppress the initialization routine +use the \fB-i\fR option. In that case the initial values for all the +latches after retiming is set to value of 2 (DONT_CARE). +.PP +The desired clock period can be specified with the \fB-c value\fR +option. When this option is not used the algorithm first checks to see +if there is a cycle_time specification with the current network (the +value depends on the current setting of the clock_flag in the network) +and tries to meet this. If no cycle_time is specified with the design +the retiming operation tries to minimize the cycle time. For this it +uses a binary search for testing feasible clock values. The tolerance of +the binary search can be specified with the \fB-t value\fR option (the +default is 0.1). +.PP +Latches in the network can be assigned a propogation delay and an +area. These are helpful in the realistic modelling of the circuit +delay and area. Use the \fB-d value\fR option to specify the delay +through a latch (to approximate the setup and propogation delay of +the latch) and the \fB-a value\fR option to specify the area +of a latch. In case of mapped networks, these values are automatically +determined from the library of gates. +.PP +The \fB-v value\fR selects the verbosity level. The range is 1-100 +(100 will literally swamp you with a lot of unneeded data). Use +the value 1 to see the progress of the algorithm. diff --git a/sis/sis_lib/help/retime.fmt b/sis/sis_lib/help/retime.fmt new file mode 100644 index 0000000..ae0a826 --- /dev/null +++ b/sis/sis_lib/help/retime.fmt @@ -0,0 +1,58 @@ + + July 1, 1994 SIS(1) + + retime [-nfim] [-c #.#] [-t #.#] [-d #.#] [-a #.#] [-v #] + + Applies the retiming transformation on the circuit in an effort to + reduce the cycle time. The retiming operation is supported only for sin- + gle phase, edge-triggered designs. Both mapped and unmapped networks can + be retimed. The algorithm attempts to maintain the initial state infor- + mation. + + The algorithm expects to work on mapped networks so that accurate delays + on the gates can be used. However, an unmapped network can be retimed + by using the -n option. In that case the delay through each node is + computed according to the _u_n_i_t-_f_a_n_o_u_t delay model. _T_h_e _u_s_e_r _s_h_o_u_l_d _b_e + _a_w_a_r_e _o_f _t_h_e _f_a_c_t _t_h_a_t _w_h_e_n _r_e_t_i_m_i_n_g _c_i_r_c_u_i_t_s _c_o_n_t_a_i_n_i_n_g _c_o_m_p_l_e_x _r_e_g_i_s_- + _t_e_r_s (_J_K, _D-_f_l_i_p _f_l_o_p_s _w_i_t_h _e_n_a_b_l_e_s/_p_r_e_s_e_t_s), _t_h_e _c_o_m_p_l_e_x _r_e_g_i_s_t_e_r_s _m_a_y + _h_a_v_e _t_o _b_e _d_e_c_o_m_p_o_s_e_d _i_n_t_o _s_i_m_p_l_e_r _g_a_t_e_s. + + By default the algorithm uses a relaxation based approach which is very + fast. An alternate formulation uses a mathematical programming formula- + tion and can be selected using the -f option. After profiling on a + number of circuits only one will be retained. + + The -m option can be used to minimize the number of registers under + cycle time constraints. If the cycle time is not specified using the -c + option then this command will try to minimize the cycle time. Thus to + obtain the absolute minimum number of registers for a circuit the user + should specify a very loose cycle time constraint (very large value for + the -c option). + + The retiming algorithm will try to compute the new initial states of the + latches. In case no feasible initial state exists the retiming is + aborted and the network is not modified. To suppress the initialization + routine use the -i option. In that case the initial values for all the + latches after retiming is set to value of 2 (DONT_CARE). + + The desired clock period can be specified with the -c value option. When + this option is not used the algorithm first checks to see if there is a + cycle_time specification with the current network (the value depends on + the current setting of the clock_flag in the network) and tries to meet + this. If no cycle_time is specified with the design the retiming opera- + tion tries to minimize the cycle time. For this it uses a binary search + for testing feasible clock values. The tolerance of the binary search + can be specified with the -t value option (the default is 0.1). + + Latches in the network can be assigned a propogation delay and an area. + These are helpful in the realistic modelling of the circuit delay and + area. Use the -d value option to specify the delay through a latch (to + approximate the setup and propogation delay of the latch) and the -a + value option to specify the area of a latch. In case of mapped networks, + these values are automatically determined from the library of gates. + + The -v value selects the verbosity level. The range is 1-100 (100 will + literally swamp you with a lot of unneeded data). Use the value 1 to see + the progress of the algorithm. + + 1 diff --git a/sis/sis_lib/help/save.1 b/sis/sis_lib/help/save.1 new file mode 100644 index 0000000..eab36b3 --- /dev/null +++ b/sis/sis_lib/help/save.1 @@ -0,0 +1,21 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/save.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +save filename +.PP +Save a copy of the current executable to a file which can be restarted. +This can be used to freeze the current network or the current library +for later optimization. When the executable \fBfilename\fR is executed, +execution returns to the top-level of the command interpreter. +.PP +NOTE: The \fBsave\fR command is very operating-system dependent and may not +be implemented on your system. +If this is the case then the \fBsave\fR +command is unusable on your system. diff --git a/sis/sis_lib/help/save.fmt b/sis/sis_lib/help/save.fmt new file mode 100644 index 0000000..4893255 --- /dev/null +++ b/sis/sis_lib/help/save.fmt @@ -0,0 +1,15 @@ + + July 1, 1994 SIS(1) + + save filename + + Save a copy of the current executable to a file which can be restarted. + This can be used to freeze the current network or the current library + for later optimization. When the executable filename is executed, exe- + cution returns to the top-level of the command interpreter. + + NOTE: The save command is very operating-system dependent and may not be + implemented on your system. If this is the case then the save command + is unusable on your system. + + 1 diff --git a/sis/sis_lib/help/set.1 b/sis/sis_lib/help/set.1 new file mode 100644 index 0000000..747f41a --- /dev/null +++ b/sis/sis_lib/help/set.1 @@ -0,0 +1,72 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/set.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +set [name] [value] +.X1 +unset name ... +.PP +A variable environment is maintained by the command interpreter. +The \fBset\fR command sets a variable to a particular value, and the +\fBunset\fR command removes the definition of a variable. +If \fBset\fR is given no arguments, it prints the definition of all variables. +.PP +Different commands use environment information for different purposes. +The command interpreter makes use of the following: +.TP 8 +.B autoexec +Defines a command string to be automatically executed after every command +processed by the command interpreter. +This is useful for things like timing +commands, or tracing the progress of optimization. +.TP 8 +.B sisout +Standard output (normally stdout) can be re-directed to a file +by setting the variable sisout. +.TP 8 +.B siserr +Standard error (normally stderr) can be re-directed to a file +by setting the variable siserr. +.TP 8 +.B history +Each valid command entered at the prompt can be echoed to a file +by setting the variable history. +.TP 8 +.B history_char +By default the character `%' is used to do the history substitution +inside sis. This can be changed by setting the variable \fBhistory_char\fR. +.TP 8 +.B shell_char +By default the character `!' is used to do invoke shell commands from +inside sis. This can be changed by setting the variable \fBshell_char\fR. +\fI In order to switch the interpretation of shell_char and history_char it is +neccessary to first set history_char and then the shell_char. Alternately, +you may escape the current history char by preceeding it with +a `\' while setting the shell_char. In addition none of them can be set +to a `#' which is reserved for comments.\fR +.TP 8 +.B filec +Setting this variable enables the user to use "file-completion" like in +the C-shell. An ESC causes the current line to be extended to its unique +completion. A CTRL-d generates a list of the possible extensions. +.TP 8 +.B open_path +\fBopen_path\fR (in analogy to the shell-variable PATH) is a list of +colon-separated strings giving directories to be searched whenever +a file is opened for read. Typically the current directory (.) is +first in this list. The standard system +library (typically $SIS/sis_lib) is always implicitly appended +to the current path. +This provides a convenient short-hand +mechanism for reaching standard library files. +.TP 8 +.B prompt +defines the prompt string. If the prompt string contains a `%'(or whatever +the history_char has been set to using the set command), the `%' +will be replaced whenever the prompt is printed by the current event number. diff --git a/sis/sis_lib/help/set.fmt b/sis/sis_lib/help/set.fmt new file mode 100644 index 0000000..1857b23 --- /dev/null +++ b/sis/sis_lib/help/set.fmt @@ -0,0 +1,70 @@ + + July 1, 1994 SIS(1) + + set [name] [value] + unset name ... + + A variable environment is maintained by the command interpreter. The + set command sets a variable to a particular value, and the unset command + removes the definition of a variable. If set is given no arguments, it + prints the definition of all variables. + + Different commands use environment information for different purposes. + The command interpreter makes use of the following: + + autoexec + Defines a command string to be automatically executed after + every command processed by the command interpreter. This is + useful for things like timing commands, or tracing the progress + of optimization. + + sisout Standard output (normally stdout) can be re-directed to a file + by setting the variable sisout. + + siserr Standard error (normally stderr) can be re-directed to a file by + setting the variable siserr. + + history Each valid command entered at the prompt can be echoed to a file + by setting the variable history. + + history_char + By default the character `%' is used to do the history substitu- + tion inside sis. This can be changed by setting the variable + history_char. + + shell_char + By default the character `!' is used to do invoke shell commands + from inside sis. This can be changed by setting the variable + shell_char. + _I_n _o_r_d_e_r _t_o _s_w_i_t_c_h _t_h_e _i_n_t_e_r_p_r_e_t_a_t_i_o_n _o_f _s_h_e_l_l__c_h_a_r _a_n_d + _h_i_s_t_o_r_y__c_h_a_r _i_t _i_s _n_e_c_c_e_s_s_a_r_y _t_o _f_i_r_s_t _s_e_t _h_i_s_t_o_r_y__c_h_a_r _a_n_d _t_h_e_n + _t_h_e _s_h_e_l_l__c_h_a_r. _A_l_t_e_r_n_a_t_e_l_y, _y_o_u _m_a_y _e_s_c_a_p_e _t_h_e _c_u_r_r_e_n_t _h_i_s_t_o_r_y + _c_h_a_r _b_y _p_r_e_c_e_e_d_i_n_g _i_t _w_i_t_h _a `' _w_h_i_l_e _s_e_t_t_i_n_g _t_h_e _s_h_e_l_l__c_h_a_r. _I_n + _a_d_d_i_t_i_o_n _n_o_n_e _o_f _t_h_e_m _c_a_n _b_e _s_e_t _t_o _a `#' _w_h_i_c_h _i_s _r_e_s_e_r_v_e_d _f_o_r + _c_o_m_m_e_n_t_s. + + filec Setting this variable enables the user to use "file-completion" + like in the C-shell. An ESC causes the current line to be + extended to its unique completion. A CTRL-d generates a list of + the possible extensions. + + open_path + open_path (in analogy to the shell-variable PATH) is a list of + colon-separated strings giving directories to be searched when- + ever a file is opened for read. Typically the current directory + (.) is first in this list. The standard system library (typi- + cally $SIS/sis_lib) is always implicitly appended to the current + + 1 + + SIS(1) July 1, 1994 + + path. This provides a convenient short-hand mechanism for + reaching standard library files. + + prompt defines the prompt string. If the prompt string contains a + `%'(or whatever the history_char has been set to using the set + command), the `%' will be replaced whenever the prompt is + printed by the current event number. + + 2 diff --git a/sis/sis_lib/help/set_delay.1 b/sis/sis_lib/help/set_delay.1 new file mode 100644 index 0000000..27275d0 --- /dev/null +++ b/sis/sis_lib/help/set_delay.1 @@ -0,0 +1,54 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/set_delay.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +set_delay [-a|d|i|l|r f] [-A f] [-D f] [-I f] [-L f] [-R f] [-S f] [-W f][o1 o2 ... | i1 i2 ...] +.PP +Set various delay parameters for the inputs and outputs of a network. +These timing constraints are used by the \fBprint_delay\fP command in +addition to commands like \fBspeed_up\fR, \fBbuffer_opt\fR, and \fBmap\fR +that perform +delay optimizations. The values for these constraints are numbers and it +is the user's responsibility to ensure that these values are meaningful +when a particular delay model is used during the optimizations. +Capitalized options set defaults, lower-case options set the +parameters for the nodes in nodelist, which is either a list of output +nodes or a list of input nodes. +.PP +The option \fB-A\fP sets the default arrival time for primary inputs +to the real value \fBf\fR. +The option \fB-R\fP sets the default required time for primary +outputs to \fBf\fR. +The \fB-D\fP option sets the default drive on a primary +input to \fBf\fR, and the \fB-L\fP option sets the default load on primary +outputs to \fBf\fR. +The \fB-I\fR option specifies the default value for the +maximum load that can be present at a primary input. The \fB-S\fP option +sets the wire load per fanout to \fBf\fR. +The wire loads for a given number of fanouts can be specified +with the \fB-W\fP option. With the \fIi\fPth use +of the \fB-W\fP option, the load for a gate driving \fIi\fP outputs is set +to the value \fBf\fR. +.PP +The settings can be undone by using a negative number for the value. +This will result in the parameter to be "unspecified" and the +individual commands will use appropriate defaults if neccessary. +.PP +The \fB-a, -r, -d, -i\fP, and \fB-l\fR options can be used to specify the +delay constraints on specific nodes (as opposed to the uppercase options +which specify a default value for ALL terminals). These terminal-specific +values will supersede the defaults specified with the uppercase options. +The \fB-a (-r)\fP option sets the arrival (required) time to \fBf\fR for the +specified nodes if the node list +given is a list of primary inputs (outputs). +The \fB-d (-i)\fP option sets the drive (maximum load limit) for each node in +the list to \fBf\fR; +if there is a non-primary input in the list this is an error. +The \fB-l\fP option sets the load on each node in the list to \fBf\fR; if there +is a non-primary output in the list this is an error. diff --git a/sis/sis_lib/help/set_delay.fmt b/sis/sis_lib/help/set_delay.fmt new file mode 100644 index 0000000..f6563b9 --- /dev/null +++ b/sis/sis_lib/help/set_delay.fmt @@ -0,0 +1,42 @@ + + July 1, 1994 SIS(1) + + set_delay [-a|d|i|l|r f] [-A f] [-D f] [-I f] [-L f] [-R f] [-S f] [-W + f][o1 o2 ... | i1 i2 ...] + + Set various delay parameters for the inputs and outputs of a network. + These timing constraints are used by the print_delay command in addition + to commands like speed_up, buffer_opt, and map that perform delay optim- + izations. The values for these constraints are numbers and it is the + user's responsibility to ensure that these values are meaningful when a + particular delay model is used during the optimizations. Capitalized + options set defaults, lower-case options set the parameters for the + nodes in nodelist, which is either a list of output nodes or a list of + input nodes. + + The option -A sets the default arrival time for primary inputs to the + real value f. The option -R sets the default required time for primary + outputs to f. The -D option sets the default drive on a primary input + to f, and the -L option sets the default load on primary outputs to f. + The -I option specifies the default value for the maximum load that can + be present at a primary input. The -S option sets the wire load per + fanout to f. The wire loads for a given number of fanouts can be speci- + fied with the -W option. With the _ith use of the -W option, the load for + a gate driving _i outputs is set to the value f. + + The settings can be undone by using a negative number for the value. + This will result in the parameter to be "unspecified" and the individual + commands will use appropriate defaults if neccessary. + + The -a, -r, -d, -i, and -l options can be used to specify the delay con- + straints on specific nodes (as opposed to the uppercase options which + specify a default value for ALL terminals). These terminal-specific + values will supersede the defaults specified with the uppercase options. + The -a (-r) option sets the arrival (required) time to f for the speci- + fied nodes if the node list given is a list of primary inputs (outputs). + The -d (-i) option sets the drive (maximum load limit) for each node in + the list to f; if there is a non-primary input in the list this is an + error. The -l option sets the load on each node in the list to f; if + there is a non-primary output in the list this is an error. + + 1 diff --git a/sis/sis_lib/help/set_state.1 b/sis/sis_lib/help/set_state.1 new file mode 100644 index 0000000..18e4287 --- /dev/null +++ b/sis/sis_lib/help/set_state.1 @@ -0,0 +1,21 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/set_state.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +set_state [-s] [-i] [name] +.PP +Sets the current state in the machine to the given state. +If no +state is given, it sets the current state to the initial state (resets +the machine). +If the \fB-s\fR option is given, only the state of the +STG is changed; if the \fB-i\fR option is specified, only the state of the +logic implementation is changed. If no logic implementation exists, +or if only the state of the STG is to be changed, then the state name +should be symbolic; otherwise it should be the encoded name of the state. diff --git a/sis/sis_lib/help/set_state.fmt b/sis/sis_lib/help/set_state.fmt new file mode 100644 index 0000000..eb2b2ab --- /dev/null +++ b/sis/sis_lib/help/set_state.fmt @@ -0,0 +1,14 @@ + + July 1, 1994 SIS(1) + + set_state [-s] [-i] [name] + + Sets the current state in the machine to the given state. If no state + is given, it sets the current state to the initial state (resets the + machine). If the -s option is given, only the state of the STG is + changed; if the -i option is specified, only the state of the logic + implementation is changed. If no logic implementation exists, or if + only the state of the STG is to be changed, then the state name should + be symbolic; otherwise it should be the encoded name of the state. + + 1 diff --git a/sis/sis_lib/help/short_tests.1 b/sis/sis_lib/help/short_tests.1 new file mode 100644 index 0000000..759a8a5 --- /dev/null +++ b/sis/sis_lib/help/short_tests.1 @@ -0,0 +1,61 @@ +.XX +short_tests [-fFhirtV] [-v verbosity_level] file +.PP +Perform test generation for sequential circuits with the goal of +producing small test sets. Random test generation is not used unless +its use is specified by the user. Deterministic test generation is +accomplished by one of two methods. The first method is a three-step test +generation algorithm consisting of combinational test generation (assuming +that latch outputs are controllable, and that latch inputs are observable), +followed by state justification and propagation, when necessary. The +combinational test generation is accomplished using Boolean satisfiability. +Justification and propagation are performed using implicit state transition +graph traversal techniques. If the three-step method does not generate a +test for a fault, then the product of the good and faulty circuit is built +and traversed, as in sequential circuit verification. If this traversal +proves the circuits equivalent, then the fault is redundant; otherwise any +differentiating sequence is a test for the fault. Fault simulation is +performed after each deterministic test generation. +.PP +Fault collapsing is performed before test generation, across only simple +gates. Both fault equivalence and fault dominance are used to reduce the +fault list. +.PP +Deterministically-generated tests may start from the circuit reset state +or a state reached by the application of another test. In the latter case, +the new test is appended onto the end of the old test. +.PP +Reverse fault simulation is performed as a post-processing step to reduce +test set size. +.PP +The \fB-f\fP option causes the test generator not to perform fault simulation +of deterministically-generated tests on untested faults. +.PP +The \fB-F\fP option causes the test generator not to use reverse fault +simulation. +.PP +The \fB-h\fP option restricts the boolean satisfiability algorithm to not use +non-local implications. Four greedy ordering heuristics are tried in this case +instead of the default of eight. Hard-to-test faults that can only be tested +with non-local implication information are aborted by this option. +.PP +The \fB-i\fP option causes the test generator not to append new tests onto +the end of old tests. +.PP +The \fB-r\fP option causes the test generator to perform random test pattern +generation and random propagation. +.PP +The \fB-t\fP option first converts the network to arbitrary fanin AND and +OR gates. The decomposed network is returned. +.PP +The \fB-v\fP allows the specification of the verbosity level of the output. +.PP +The \fB-V\fP causes the test generator to not use the three-step algorithm +to generate tests. Instead, only good/faulty product machine verification +is used to generate tests, thus guaranteeing that each individual test +generated is the shortest possible. +.PP +If \fBfile\fP is specified, test patterns are written out to the given file. +.PP +Note: in order to use this command with sequential circuits, the circuit +reset state must be specified in the circuit input file. diff --git a/sis/sis_lib/help/short_tests.fmt b/sis/sis_lib/help/short_tests.fmt new file mode 100644 index 0000000..82902e3 --- /dev/null +++ b/sis/sis_lib/help/short_tests.fmt @@ -0,0 +1,71 @@ + + July 1, 1994 SIS(1) + + short_tests [-fFhirtV] [-v verbosity_level] file + + Perform test generation for sequential circuits with the goal of produc- + ing small test sets. Random test generation is not used unless its use + is specified by the user. Deterministic test generation is accomplished + by one of two methods. The first method is a three-step test generation + algorithm consisting of combinational test generation (assuming that + latch outputs are controllable, and that latch inputs are observable), + followed by state justification and propagation, when necessary. The + combinational test generation is accomplished using Boolean satisfiabil- + ity. Justification and propagation are performed using implicit state + transition graph traversal techniques. If the three-step method does not + generate a test for a fault, then the product of the good and faulty + circuit is built and traversed, as in sequential circuit verification. + If this traversal proves the circuits equivalent, then the fault is + redundant; otherwise any differentiating sequence is a test for the + fault. Fault simulation is performed after each deterministic test gen- + eration. + + Fault collapsing is performed before test generation, across only simple + gates. Both fault equivalence and fault dominance are used to reduce the + fault list. + + Deterministically-generated tests may start from the circuit reset state + or a state reached by the application of another test. In the latter + case, the new test is appended onto the end of the old test. + + Reverse fault simulation is performed as a post-processing step to + reduce test set size. + + The -f option causes the test generator not to perform fault simulation + of deterministically-generated tests on untested faults. + + The -F option causes the test generator not to use reverse fault simula- + tion. + + The -h option restricts the boolean satisfiability algorithm to not use + non-local implications. Four greedy ordering heuristics are tried in + this case instead of the default of eight. Hard-to-test faults that can + only be tested with non-local implication information are aborted by + this option. + + The -i option causes the test generator not to append new tests onto the + end of old tests. + + The -r option causes the test generator to perform random test pattern + generation and random propagation. + + The -t option first converts the network to arbitrary fanin AND and OR + gates. The decomposed network is returned. + + The -v allows the specification of the verbosity level of the output. + + 1 + + SIS(1) July 1, 1994 + + The -V causes the test generator to not use the three-step algorithm to + generate tests. Instead, only good/faulty product machine verification + is used to generate tests, thus guaranteeing that each individual test + generated is the shortest possible. + + If file is specified, test patterns are written out to the given file. + + Note: in order to use this command with sequential circuits, the circuit + reset state must be specified in the circuit input file. + + 2 diff --git a/sis/sis_lib/help/sim_verify.1 b/sis/sis_lib/help/sim_verify.1 new file mode 100644 index 0000000..ec0c318 --- /dev/null +++ b/sis/sis_lib/help/sim_verify.1 @@ -0,0 +1,24 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sim_verify.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +sim_verify [-n # pats] filename.blif +.PP +Verify that two networks are equivalent using random-pattern +simulation. That is, generate a random input vector, simulate the +logic network, and check that the outputs between the two networks +agree. The first network is the current network, and a second +network is read from the file \fBfilename.blif\fR: +it must be a \fIblif\fR format file. +(This restriction will be fixed when the command interpreter is +expanded to handle multiple networks.) +.PP +\fB-n\fP gives the number of random patterns to simulate. +.PP +NOTE: this command only works for combinational networks. diff --git a/sis/sis_lib/help/sim_verify.fmt b/sis/sis_lib/help/sim_verify.fmt new file mode 100644 index 0000000..73abff8 --- /dev/null +++ b/sis/sis_lib/help/sim_verify.fmt @@ -0,0 +1,18 @@ + + July 1, 1994 SIS(1) + + sim_verify [-n # pats] filename.blif + + Verify that two networks are equivalent using random-pattern simulation. + That is, generate a random input vector, simulate the logic network, and + check that the outputs between the two networks agree. The first net- + work is the current network, and a second network is read from the file + filename.blif: it must be a _b_l_i_f format file. (This restriction will be + fixed when the command interpreter is expanded to handle multiple net- + works.) + + -n gives the number of random patterns to simulate. + + NOTE: this command only works for combinational networks. + + 1 diff --git a/sis/sis_lib/help/simplify.1 b/sis/sis_lib/help/simplify.1 new file mode 100644 index 0000000..bbdc0d5 --- /dev/null +++ b/sis/sis_lib/help/simplify.1 @@ -0,0 +1,38 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/simplify.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +simplify [-d][-i <num>[:<num>]] [-m method] [-f filter] [node-list] +.PP +Simplify each node in the \fBnode-list\fR using +\fImethod\fR with the don't-care set generated according to +\fIdctype\fR. +.PP +\fImethod\fR specifies the algorithm used to minimize the nodes. +\fIsnocomp\fR (default) invokes a single pass minimization procedure that does +not compute the complete offset. +\fInocomp\fR invokes the full minimization procedure (ala ESPRESSO) but does +not compute the complete offset. +\fIdcsimp\fR invokes single pass tautology-based minimizer. +.PP +\fIdctype\fR specifies how the don't-care set is generated. +The default don't care set generated is a subset of the fanin don't care set. +\fB-d\fR option specifies that no don't care set is used. +\fB-i m:n\fR specifies that the fanin don't cares of nodes within +\fBm\fR levels of transitive fanin and \fBn\fR levels of transitive fanout +of these transitive fanin are to be generated. +.PP +\fIfilter\fR specifies how the don't-care set is filtered. +\fIexact\fR (default) uses the exact filter. +\fIdisj_sup\fR uses the disjoint support filter. +.PP +Note that a node function is replaced with the simplified version +if the new function has fewer literals in factored form. +In the case of a tie, the node function is replaced if the new function +has fewer literals in sum-of-products form. diff --git a/sis/sis_lib/help/simplify.fmt b/sis/sis_lib/help/simplify.fmt new file mode 100644 index 0000000..5bb3231 --- /dev/null +++ b/sis/sis_lib/help/simplify.fmt @@ -0,0 +1,30 @@ + + July 1, 1994 SIS(1) + + simplify [-d][-i <num>[:<num>]] [-m method] [-f filter] [node-list] + + Simplify each node in the node-list using _m_e_t_h_o_d with the don't-care set + generated according to _d_c_t_y_p_e. + + _m_e_t_h_o_d specifies the algorithm used to minimize the nodes. _s_n_o_c_o_m_p + (default) invokes a single pass minimization procedure that does not + compute the complete offset. _n_o_c_o_m_p invokes the full minimization pro- + cedure (ala ESPRESSO) but does not compute the complete offset. _d_c_s_i_m_p + invokes single pass tautology-based minimizer. + + _d_c_t_y_p_e specifies how the don't-care set is generated. The default don't + care set generated is a subset of the fanin don't care set. -d option + specifies that no don't care set is used. -i m:n specifies that the + fanin don't cares of nodes within m levels of transitive fanin and n + levels of transitive fanout of these transitive fanin are to be gen- + erated. + + _f_i_l_t_e_r specifies how the don't-care set is filtered. _e_x_a_c_t (default) + uses the exact filter. _d_i_s_j__s_u_p uses the disjoint support filter. + + Note that a node function is replaced with the simplified version if the + new function has fewer literals in factored form. In the case of a tie, + the node function is replaced if the new function has fewer literals in + sum-of-products form. + + 1 diff --git a/sis/sis_lib/help/simulate.1 b/sis/sis_lib/help/simulate.1 new file mode 100644 index 0000000..d9a0f2f --- /dev/null +++ b/sis/sis_lib/help/simulate.1 @@ -0,0 +1,37 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/simulate.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +simulate in1 in2 in3 ... +.PP +For the current implementation of the network, given a value ('0' or '1') +for each of the primary inputs of the network, simulate prints the value +produced at each of the primary outputs. The correspondence of the +input values and the primary inputs can be determined by the order in +which the primary inputs and outputs are printed using the \fBwrite_eqn\fR +command. +.PP +For example, for a three-input AND gate, the command + +\fB simulate 1 1 0\fR + +will produce a + + 0 +.PP +NOTE: For sequential circuits, this command essentially assumes that all +latches are clocked simultaneously by a single clock. +Simulation will take the current values on the latches (which can be +displayed by using \fBprint_latch\fR) and the user-supplied primary +input values +and simulate the network, placing the new latch values in the +current state of the latches. +The values of the outputs and the new state are printed. +If a more sophisticated simulation method is needed, timing simulation +should be used; this is not currently implemented in SIS. diff --git a/sis/sis_lib/help/simulate.fmt b/sis/sis_lib/help/simulate.fmt new file mode 100644 index 0000000..d4e70cb --- /dev/null +++ b/sis/sis_lib/help/simulate.fmt @@ -0,0 +1,30 @@ + + July 1, 1994 SIS(1) + + simulate in1 in2 in3 ... + + For the current implementation of the network, given a value ('0' or + '1') for each of the primary inputs of the network, simulate prints the + value produced at each of the primary outputs. The correspondence of + the input values and the primary inputs can be determined by the order + in which the primary inputs and outputs are printed using the write_eqn + command. + + For example, for a three-input AND gate, the command + + simulate 1 1 0 + + will produce a + + 0 + + NOTE: For sequential circuits, this command essentially assumes that + all latches are clocked simultaneously by a single clock. Simulation + will take the current values on the latches (which can be displayed by + using print_latch) and the user-supplied primary input values and simu- + late the network, placing the new latch values in the current state of + the latches. The values of the outputs and the new state are printed. + If a more sophisticated simulation method is needed, timing simulation + should be used; this is not currently implemented in SIS. + + 1 diff --git a/sis/sis_lib/help/sis.1 b/sis/sis_lib/help/sis.1 new file mode 100644 index 0000000..a0082d2 --- /dev/null +++ b/sis/sis_lib/help/sis.1 @@ -0,0 +1,8320 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.TH SIS 1CAD "1 July 1994" +.SH NAME +sis \- Sequential Interactive System +.SH SYNOPSIS +.B sis +[options] [file] +.SH DESCRIPTION +\fBSIS\fR is an algorithmic sequential circuit optimization +program. \fBSIS\fR starts from a description +of a sequential logic macro-cell and produces +an optimized set of logic equations plus latches which preserves +the input-output behavior of the macro-cell. +The sequential circuit can be stored as a finite +state machine or as an implementation consisting of logic +gates and memory elements. +The program +includes algorithms for minimizing the area required to +implement the logic equations, algorithms for minimizing delay, +and a technology +mapping step to map a network into a user-specified cell library. +It includes all of the optimization techniques available in +\fBMIS\fR, and replaces \fBMIS\fR completely. +.PP +\fBSIS\fR can be run in interactive mode accepting commands +from the user, or in batch mode reading commands +from a file or from the command line. +If no options are given on the command line, \fBSIS\fP will +enter interactive mode. +Otherwise, \fBSIS\fP will enter batch mode. +When running in batch mode, \fBSIS\fP reads its +input from the file given on the command line, or from standard input +if no filename is given; +output is directed to standard output, unless \fB-o\fP is used to +specify an output filename. +.PP +When \fBSIS\fP starts-up, it performs an initial source of the +files $SIS/sis_lib/.misrc and $SIS/sis_lib/.sisrc. +Typically this defines a standard +set of aliases for various commands. +Following that the files ~/.misrc, ~/.sisrc, ./misrc, and ./sisrc +are sourced for user-defined aliases at startup. +.SH OPTIONS +.TP 8 +.B -c cmdline +Run \fBSIS\fR in batch mode, and execute \fBcmdline\fR. +Multiple commands are separated with semicolons. +.TP 8 +.B -f script +Run \fBSIS\fR in the batch mode, and execute commands from the +file \fBscript\fR. +.TP 8 +.B -t type +Specifies the type of the input when running in batch mode. +The legal input types are: +Berkeley Logic Interchange Format (\fB-t blif\fP), +eqntott(1CAD)-format equation input (\fB-t eqn\fP), +\fIKISS2 format\fR (\fB-t kiss\fP), +\fIOct Logic View\fR (\fB-t oct\fP), +Berkeley PLA Format (\fB-t pla\fP), +\fISLIF format\fR (\fB-t slif\fP), +and suppress input (\fB-t none\fP). +The default input type is \fIblif\fR. +.TP 8 +.B -T type +Specifies the type of the output when running in batch mode. +The legal output types are: +bdnet(1CAD)-format net-list (\fB-T bdnet\fP), +Berkeley Logic Interchange Format (\fB-T blif\fP), +eqntott(1CAD)-format equation input (\fB-T eqn\fP), +\fIKISS2 format\fR (\fB-T kiss\fP), +\fIOct logic view\fR (\fB-T oct\fP), +Berkeley PLA Format (\fB-T pla\fP), +\fISLIF format\fR (\fB-T slif\fP), +and suppress output (\fB-T none\fP). +The default output type is \fIblif\fR. +.TP 8 +.B -o file +Specifies the output file when running in batch mode. +For \fIOct\fP output, this is a string of the +form \fIcell\fP:\fIview\fP. +The default for the output is the standard output. +.TP 8 +.B -s +Suppress sourcing the commands from the standard +startup script ($SIS/sis_lib/.misrc and $SIS/sis_lib/.sisrc). +.TP 8 +.B -x +For batch mode operation, suppress reading an initial network, and +suppress writing an output network. +Equivalent to \fB-t none -T none\fP. +.de XX +.sp 1 +.LP +.ti -5 +.B +.. +.de X1 +.br +.ti -5 +.B +.. +.PP +.SH COMMAND SUMMARY +All commands are summarized below according +to their function : network manipulation (operations +on the logic-level implementation), +ASTG manipulation (operations on the asynchronous +signal transition graph), STG manipulation (operations +on the synchronous state transition graph), +input-output, network status, command interpreter, +and miscellaneous. +The last two tables summarize the newest commands that +operate on ASTG's and sequential circuits, respectively. +.sp 2 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \wact_map +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wadd_inverter +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_slow +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_syn +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_to_f +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_to_stg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wbuffer_opt +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wchng_clock +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wcollapse +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wdecomp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \weliminate +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wenv_seq_dc +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wequiv_nets +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wespresso +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wextract_seq_dc +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wfactor +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wfanout_alg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wfanout_param +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wfree_dc +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wforce_init_0 +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wfull_simplify +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wfx +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wgcx +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wgkx +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \winvert +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wlatch_output +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wmap +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wone_hot +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wphase +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wred_removal +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wreduce_depth +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wremove_dep +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wremove_latches +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wreplace +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wresub +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wretime +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsimplify +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wspeed_up +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wspeed_up_alg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstate_assign +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstg_extract +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstg_to_network +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsweep +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wtech_decomp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwd +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wtechnology mapping to Actel architecture +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wadd inverters to the network to make all gates negative +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wremove hazards from the ASTG implementation +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \w(uses bounded wire delay model) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsynthesize a two-level implementation from the ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \w(uses unbounded wire delay model) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wgenerate a two-level implementation of each output of the ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \w(uses bounded wire delay model) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wgenerate an STG from the ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \winserts buffering trees for high fanout gates +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtoggles clock setting between user-specification and generated values +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcollapse a network or a set of nodes +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wdecompose a node into a set of nodes +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \weliminates nodes whose value falls below a threshold +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wextract sequential don't cares based on the environment +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wgroup and merge nets by equivalence classes +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcollapse network and minimize with a two-level minimizer +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wextract sequential don't cares +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wdetermine a factored form for a node +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wselect a fanout optimization algorithm (to be used by map) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wset some parameters for fanout algorithm (to be used by map) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wfrees the external don't care network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wmodify so all latches to have a 0 initial state +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsimplify the nodes using local compatible don't cares +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wdo fast extraction of the best double cube and single cube divisors +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wextract common cubes from the network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wextract common multiple-cube divisors from the network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \winvert a node, and toggle the phase of all of its fanouts +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wforces some outputs to be fed directly by latches +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtechnology mapping to find an implementation for the network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wquick one-hot encoding +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wphase assignment to minimize number of inverters +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wperform redundancy removal via atpg +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wincrease the speed before mapping by reducing the depth +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wremoves some structural (but not logical) dependencies +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wremoves redundant latches +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wquick algebraic decomposition on 2-input NANDs +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wperform resubstitution of a node into other nodes in the network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wmove the latches in the circuit to minimize cycle time/# latches +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtwo-level minimization of each node +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wrestructure critical paths to reduce delay +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wseveral algorithms for performance enhancement +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcreate the logic from the STG using state assignment +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wextract an STG from the logic +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wconverts a state-encoded STG to a logic network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wremove all inverters, buffers, and unnecessary latches from the network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wdecompose a network for technology mapping +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wre-express a node using another node using weak division +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBNetwork Manipulation Commands\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 178 file Input is too wide - \n(TW units +.ne 49v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBNetwork Manipulation Commands\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'act_map\h'|\n(41u'technology mapping to Actel architecture +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'add_inverter\h'|\n(41u'add inverters to the network to make all gates negative +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_slow\h'|\n(41u'remove hazards from the ASTG implementation +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\h'|\n(41u'(uses bounded wire delay model) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_syn\h'|\n(41u'synthesize a two-level implementation from the ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\h'|\n(41u'(uses unbounded wire delay model) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_to_f\h'|\n(41u'generate a two-level implementation of each output of the ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\h'|\n(41u'(uses bounded wire delay model) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_to_stg\h'|\n(41u'generate an STG from the ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'buffer_opt\h'|\n(41u'inserts buffering trees for high fanout gates +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'chng_clock\h'|\n(41u'toggles clock setting between user-specification and generated values +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'collapse\h'|\n(41u'collapse a network or a set of nodes +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'decomp\h'|\n(41u'decompose a node into a set of nodes +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'eliminate\h'|\n(41u'eliminates nodes whose value falls below a threshold +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'env_seq_dc\h'|\n(41u'extract sequential don't cares based on the environment +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'equiv_nets\h'|\n(41u'group and merge nets by equivalence classes +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'espresso\h'|\n(41u'collapse network and minimize with a two-level minimizer +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'extract_seq_dc\h'|\n(41u'extract sequential don't cares +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'factor\h'|\n(41u'determine a factored form for a node +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'fanout_alg\h'|\n(41u'select a fanout optimization algorithm (to be used by map) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'fanout_param\h'|\n(41u'set some parameters for fanout algorithm (to be used by map) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'free_dc\h'|\n(41u'frees the external don't care network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'force_init_0\h'|\n(41u'modify so all latches to have a 0 initial state +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'full_simplify\h'|\n(41u'simplify the nodes using local compatible don't cares +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'fx\h'|\n(41u'do fast extraction of the best double cube and single cube divisors +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'gcx\h'|\n(41u'extract common cubes from the network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'gkx\h'|\n(41u'extract common multiple-cube divisors from the network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'invert\h'|\n(41u'invert a node, and toggle the phase of all of its fanouts +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'latch_output\h'|\n(41u'forces some outputs to be fed directly by latches +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'map\h'|\n(41u'technology mapping to find an implementation for the network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'one_hot\h'|\n(41u'quick one-hot encoding +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'phase\h'|\n(41u'phase assignment to minimize number of inverters +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'red_removal\h'|\n(41u'perform redundancy removal via atpg +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'reduce_depth\h'|\n(41u'increase the speed before mapping by reducing the depth +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'remove_dep\h'|\n(41u'removes some structural (but not logical) dependencies +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'remove_latches\h'|\n(41u'removes redundant latches +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'replace\h'|\n(41u'quick algebraic decomposition on 2-input NANDs +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'resub\h'|\n(41u'perform resubstitution of a node into other nodes in the network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'retime\h'|\n(41u'move the latches in the circuit to minimize cycle time/# latches +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'simplify\h'|\n(41u'two-level minimization of each node +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'speed_up\h'|\n(41u'restructure critical paths to reduce delay +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'speed_up_alg\h'|\n(41u'several algorithms for performance enhancement +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'state_assign\h'|\n(41u'create the logic from the STG using state assignment +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'stg_extract\h'|\n(41u'extract an STG from the logic +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'stg_to_network\h'|\n(41u'converts a state-encoded STG to a logic network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sweep\h'|\n(41u'remove all inverters, buffers, and unnecessary latches from the network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'tech_decomp\h'|\n(41u'decompose a network for technology mapping +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'wd\h'|\n(41u're-express a node using another node using weak division +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-54 +.sp 2 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \wxl_absorb +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_ao +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_coll_ck +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_cover +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_decomp_two +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_imp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_k_decomp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_merge +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_part_coll +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_partition +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_rl +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxl_split +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wdecreases number of fanins to make nodes feasible +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wAND-OR decomposition of an infeasible network to a feasible one +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcollapse and apply Roth-Karp decomposition and cofactoring +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wglobal cover of nodes by "xilinx" blocks of pld gates +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wdecomposition into two compatible "xilinx" functions +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wgenerates a feasible network using various decomposition schemes +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wKarp-Roth decomposition for mapping into "xilinx" gates +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wmerge "xilinx" blocks +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wpartial collapse +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wlocal cover of nodes by "xilinx" blocks of pld gates +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtiming optimization for table look up architectures +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wdecompose a network (using routing complexity as cost) +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBNetwork Manipulation Commands (cont.)\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 198 file Input is too wide - \n(TW units +.ne 13v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBNetwork Manipulation Commands (cont.)\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_absorb\h'|\n(41u'decreases number of fanins to make nodes feasible +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_ao\h'|\n(41u'AND-OR decomposition of an infeasible network to a feasible one +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_coll_ck\h'|\n(41u'collapse and apply Roth-Karp decomposition and cofactoring +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_cover\h'|\n(41u'global cover of nodes by "xilinx" blocks of pld gates +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_decomp_two\h'|\n(41u'decomposition into two compatible "xilinx" functions +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_imp\h'|\n(41u'generates a feasible network using various decomposition schemes +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_k_decomp\h'|\n(41u'Karp-Roth decomposition for mapping into "xilinx" gates +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_merge\h'|\n(41u'merge "xilinx" blocks +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_part_coll\h'|\n(41u'partial collapse +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_partition\h'|\n(41u'local cover of nodes by "xilinx" blocks of pld gates +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_rl\h'|\n(41u'timing optimization for table look up architectures +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xl_split\h'|\n(41u'decompose a network (using routing complexity as cost) +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-18 +.sp 2 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \wastg_add_state +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_contract +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_encode +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_lockgraph +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_marking +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_persist +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_state_min +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_stg_scr +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstg_to_astg +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wadds states to the ASTG to guarantee implementability +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wgenerate the contracted net for a signal of the ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcritical race-free STG encoding +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wbuild the lock graph for the current ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wset or display the initial marking of the ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wmake the ASTG persistent +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wminimizes the current STG and derives encoding +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \winformation for the associated ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtransforms the STG to one that satisfies SCR property +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtransforms the STG (with the SCR property) to an ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBASTG Manipulation Commands\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 216 file Input is too wide - \n(TW units +.ne 11v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBASTG Manipulation Commands\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_add_state\h'|\n(41u'adds states to the ASTG to guarantee implementability +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_contract\h'|\n(41u'generate the contracted net for a signal of the ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_encode\h'|\n(41u'critical race-free STG encoding +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_lockgraph\h'|\n(41u'build the lock graph for the current ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_marking\h'|\n(41u'set or display the initial marking of the ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_persist\h'|\n(41u'make the ASTG persistent +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_state_min\h'|\n(41u'minimizes the current STG and derives encoding +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\h'|\n(41u'information for the associated ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_stg_scr\h'|\n(41u'transforms the STG to one that satisfies SCR property +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'stg_to_astg\h'|\n(41u'transforms the STG (with the SCR property) to an ASTG +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-16 +.sp 2 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \wstate_assign +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstate_minimize +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstg_to_astg +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wassign binary codes to the states in the STG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wminimize the number of states in the STG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtransforms the STG (with the SCR property) to an ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBSTG Manipulation Commands\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 227 file Input is too wide - \n(TW units +.ne 4v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBSTG Manipulation Commands\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'state_assign\h'|\n(41u'assign binary codes to the states in the STG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'state_minimize\h'|\n(41u'minimize the number of states in the STG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'stg_to_astg\h'|\n(41u'transforms the STG (with the SCR property) to an ASTG +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-9 +.sp 2 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \wc_check +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wc_opt +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wverifies satisfaction of clocking constraints +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcomputes the optimal clock for a given clocking scheme +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBTiming Commands\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 237 file Input is too wide - \n(TW units +.ne 3v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBTiming Commands\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'c_check\h'|\n(41u'verifies satisfaction of clocking constraints +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'c_opt\h'|\n(41u'computes the optimal clock for a given clocking scheme +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-8 +.sp 2 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \wread_astg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wread_blif +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wread_eqn +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wread_kiss +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wread_library +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wread_oct +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wread_pla +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wread_slif +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wset_delay +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wset_state +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_astg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_bdnet +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_blif +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_eqn +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_kiss +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_oct +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_pla +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_pds +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_slif +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wread a signal transition graph in ASTG format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread a network in BLIF format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread a network in eqntott(1CAD) format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread an STG in KISS2 format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread a library description file +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread a network from an Oct Logic view +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread a network in PLA format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread a network in Stanford Logic Interchange Format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wset delay parameters for primary inputs and outputs  +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wset the current state in a sequential circuit to the given state +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the current signal transition graph in ASTG format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the current (mapped) network in bdnet(1CAD) format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the current network in BLIF format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the current network in eqntott(1CAD) equation format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the STG in KISS2 format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the current network into an Oct Logic view +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the current network in PLA(5CAD) format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the current network in PDS format for Xilinx +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the current network in SLIF format +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBInput-Output Commands\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 264 file Input is too wide - \n(TW units +.ne 20v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBInput-Output Commands\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_astg\h'|\n(41u'read a signal transition graph in ASTG format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_blif\h'|\n(41u'read a network in BLIF format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_eqn\h'|\n(41u'read a network in eqntott(1CAD) format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_kiss\h'|\n(41u'read an STG in KISS2 format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_library\h'|\n(41u'read a library description file +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_oct\h'|\n(41u'read a network from an Oct Logic view +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_pla\h'|\n(41u'read a network in PLA format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_slif\h'|\n(41u'read a network in Stanford Logic Interchange Format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'set_delay\h'|\n(41u'set delay parameters for primary inputs and outputs  +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'set_state\h'|\n(41u'set the current state in a sequential circuit to the given state +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_astg\h'|\n(41u'write the current signal transition graph in ASTG format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_bdnet\h'|\n(41u'write the current (mapped) network in bdnet(1CAD) format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_blif\h'|\n(41u'write the current network in BLIF format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_eqn\h'|\n(41u'write the current network in eqntott(1CAD) equation format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_kiss\h'|\n(41u'write the STG in KISS2 format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_oct\h'|\n(41u'write the current network into an Oct Logic view +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_pla\h'|\n(41u'write the current network in PLA(5CAD) format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_pds\h'|\n(41u'write the current network in PDS format for Xilinx +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_slif\h'|\n(41u'write the current network in SLIF format +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-25 +.sp 1 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \wastg_current +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_print_sg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_print_stat +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wconstraints +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wplot_blif +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpower_estimate +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpower_free_info +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpower_print +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_altname +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_clock +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_delay +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_factor +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_gate +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_io +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_kernel +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_latch +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_level +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_library +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_map_stats +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_state +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_stats +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_value +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wdisplay information about the current ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the state graph of the current ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the statistics of the current ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the delay constraints for a set of nodes +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wplot the network in a graphics window (only available in \fBxsis\fR) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \westimate dissipated power based on switching activity +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wfrees memory associated with power calculations +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint switcing probabilities and capacitances +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint logic function associated with a node +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the short (and long) names for a node +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint out information about the clocks in the network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtiming simulate a network and print results +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the factored form associated with a node +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint information about the gates used in the mapped network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the fanin and fanout of a node (or the network) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the kernels (and subkernels) of a set of functions +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint out information about all the latches in the circuit +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the levels of a set of nodes +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wlist the gates in the current library +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint delay and area information for a mapped network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the current state of a sequential circuit +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint statistics on a set of nodes +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the value of a set of nodes +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBNetwork Status Commands\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 295 file Input is too wide - \n(TW units +.ne 24v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBNetwork Status Commands\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_current\h'|\n(41u'display information about the current ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_print_sg\h'|\n(41u'print the state graph of the current ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_print_stat\h'|\n(41u'print the statistics of the current ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'constraints\h'|\n(41u'print the delay constraints for a set of nodes +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'plot_blif\h'|\n(41u'plot the network in a graphics window (only available in \fBxsis\fR) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'power_estimate\h'|\n(41u'estimate dissipated power based on switching activity +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'power_free_info\h'|\n(41u'frees memory associated with power calculations +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'power_print\h'|\n(41u'print switcing probabilities and capacitances +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print\h'|\n(41u'print logic function associated with a node +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_altname\h'|\n(41u'print the short (and long) names for a node +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_clock\h'|\n(41u'print out information about the clocks in the network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_delay\h'|\n(41u'timing simulate a network and print results +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_factor\h'|\n(41u'print the factored form associated with a node +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_gate\h'|\n(41u'print information about the gates used in the mapped network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_io\h'|\n(41u'print the fanin and fanout of a node (or the network) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_kernel\h'|\n(41u'print the kernels (and subkernels) of a set of functions +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_latch\h'|\n(41u'print out information about all the latches in the circuit +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_level\h'|\n(41u'print the levels of a set of nodes +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_library\h'|\n(41u'list the gates in the current library +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_map_stats\h'|\n(41u'print delay and area information for a mapped network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_state\h'|\n(41u'print the current state of a sequential circuit +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_stats\h'|\n(41u'print statistics on a set of nodes +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_value\h'|\n(41u'print the value of a set of nodes +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-29 +.sp 1 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \walias +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wchng_name +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wecho +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \whelp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \whistory +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wquit +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wreset_name +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsave +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wset +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsource +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wtime +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wtimeout +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wunalias +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wundo +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wunset +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wusage +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wprovide an alias for a command +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wswitch between short and long forms for node names +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wmerely echo the arguments +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprovide on-line information on commands +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wa UNIX-like history mechanism inside the \fBSIS\fP shell +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wexit \fBSIS\fP +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wrename all of the short names in the network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsave a copy of the current executable +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wset an environment variable +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wexecute commands from a file +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprovide a simple elapsed time value +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsends an interrupt to the \fBSIS\fR process +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wremove the definition of an alias +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wundo the result of the last command which changed the network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wunset an environment variable +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprovide a dump of process statistics +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBCommand Interpreter\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 319 file Input is too wide - \n(TW units +.ne 17v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBCommand Interpreter\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'alias\h'|\n(41u'provide an alias for a command +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'chng_name\h'|\n(41u'switch between short and long forms for node names +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'echo\h'|\n(41u'merely echo the arguments +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'help\h'|\n(41u'provide on-line information on commands +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'history\h'|\n(41u'a UNIX-like history mechanism inside the \fBSIS\fP shell +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'quit\h'|\n(41u'exit \fBSIS\fP +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'reset_name\h'|\n(41u'rename all of the short names in the network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'save\h'|\n(41u'save a copy of the current executable +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'set\h'|\n(41u'set an environment variable +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'source\h'|\n(41u'execute commands from a file +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'time\h'|\n(41u'provide a simple elapsed time value +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'timeout\h'|\n(41u'sends an interrupt to the \fBSIS\fR process +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'unalias\h'|\n(41u'remove the definition of an alias +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'undo\h'|\n(41u'undo the result of the last command which changed the network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'unset\h'|\n(41u'unset an environment variable +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'usage\h'|\n(41u'provide a dump of process statistics +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-22 +.sp 1 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \watpg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wbdsyn +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wenv_verify_fsm +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wshort_tests +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsim_verify +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsimulate +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstg_cover +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wverify +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wverify_fsm +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wperform combinational atpg using SAT approach +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wspecial command used by bdsyn(1CAD) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wverify equivalence of two networks in an environment +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wgenerate small sequential test sets +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wverify networks equivalent via simulation +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wlogic simulation of the current network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcheck that the STG behavior covers the logic implementation +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wverify equivalence of two combinational networks +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wverify equivalence of two combinational or sequential networks +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBMiscellaneous\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 336 file Input is too wide - \n(TW units +.ne 10v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBMiscellaneous\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'atpg\h'|\n(41u'perform combinational atpg using SAT approach +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'bdsyn\h'|\n(41u'special command used by bdsyn(1CAD) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'env_verify_fsm\h'|\n(41u'verify equivalence of two networks in an environment +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'short_tests\h'|\n(41u'generate small sequential test sets +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sim_verify\h'|\n(41u'verify networks equivalent via simulation +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'simulate\h'|\n(41u'logic simulation of the current network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'stg_cover\h'|\n(41u'check that the STG behavior covers the logic implementation +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'verify\h'|\n(41u'verify equivalence of two combinational networks +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'verify_fsm\h'|\n(41u'verify equivalence of two combinational or sequential networks +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-15 +.sp 1 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \wastg_add_state +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_contract +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_current +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_encode +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_lockgraph +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_marking +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_persist +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_print_sg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_print_stat +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_slow +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_state_min +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_stg_scr +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_syn +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_to_f +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wastg_to_stg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wread_astg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_astg +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wadds states to the ASTG to guarantee implementability +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wgenerate the contracted net for a signal of the ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wdisplay information about the current ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcritical race-free STG encoding +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wbuild the lock graph for the current ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wset or display the initial marking of the ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wmake the ASTG persistent +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the state graph of the current ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint the statistics of the current ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wremove hazards from the ASTG (uses bounded wire delay model) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wminimizes the current STG and derives encoding +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \winformation for the associated ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtransforms the STG to one that satisfies SCR property +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsynthesize a two-level implementation from the ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \w(uses unbounded wire delay model) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wgenerate a two-level implementation of each output of the ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \w(uses bounded wire delay model) +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wgenerate an STG from the ASTG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread a signal transition graph in ASTG format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the current signal transition graph in ASTG format +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBAsynchronous Synthesis Commands\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 364 file Input is too wide - \n(TW units +.ne 21v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBAsynchronous Synthesis Commands\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_add_state\h'|\n(41u'adds states to the ASTG to guarantee implementability +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_contract\h'|\n(41u'generate the contracted net for a signal of the ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_current\h'|\n(41u'display information about the current ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_encode\h'|\n(41u'critical race-free STG encoding +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_lockgraph\h'|\n(41u'build the lock graph for the current ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_marking\h'|\n(41u'set or display the initial marking of the ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_persist\h'|\n(41u'make the ASTG persistent +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_print_sg\h'|\n(41u'print the state graph of the current ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_print_stat\h'|\n(41u'print the statistics of the current ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_slow\h'|\n(41u'remove hazards from the ASTG (uses bounded wire delay model) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_state_min\h'|\n(41u'minimizes the current STG and derives encoding +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\h'|\n(41u'information for the associated ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_stg_scr\h'|\n(41u'transforms the STG to one that satisfies SCR property +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_syn\h'|\n(41u'synthesize a two-level implementation from the ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\h'|\n(41u'(uses unbounded wire delay model) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_to_f\h'|\n(41u'generate a two-level implementation of each output of the ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\h'|\n(41u'(uses bounded wire delay model) +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'astg_to_stg\h'|\n(41u'generate an STG from the ASTG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_astg\h'|\n(41u'read a signal transition graph in ASTG format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_astg\h'|\n(41u'write the current signal transition graph in ASTG format +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-26 +.sp 1 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \wc_check +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wc_opt +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wchng_clock +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wenv_seq_dc +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wenv_verify_fsm +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wextract_seq_dc +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wforce_init_0 +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wlatch_output +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wone_hot +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpower_estimate +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpower_free_info +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpower_print +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_clock +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprint_latch +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wread_kiss +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wread_slif +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wremove_latches +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wretime +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wset_delay +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wset_state +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wshort_tests +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstate_assign +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstate_minimize +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstg_cover +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstg_extract +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wstg_to_network +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wverify_fsm +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_kiss +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwrite_slif +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wverifies satisfaction of clocking constraints +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcomputes the optimal clock for a given clocking scheme +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtoggles clock setting between user-specification and generated values +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wextract sequential don't cares based on the environment +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wverify equivalence of two networks in an environment +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wextract sequential don't cares +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wmodify so all latches to have a 0 initial state +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wforces some outputs to be fed directly by latches +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wquick one-hot encoding +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \westimate dissipated power based on switching activity +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wfrees memory associated with power calculations +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint switcing probabilities and capacitances +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint out information about the clocks in the network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint out information about all the latches in the circuit +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread an STG in KISS2 format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread a network in Stanford Logic Interchange Format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wremoves redundant latches +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wmove the latches in the circuit to minimize cycle time/# latches +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wset delay parameters for primary inputs and outputs  +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wset the current state in a sequential circuit to the given state +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wgenerate small sequential test sets +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcreate the logic from the STG using state assignment +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wminimize the number of states in the STG +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcheck that the STG behavior covers the logic implementation +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wextract an STG from the logic +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wconverts a state-encoded STG to a logic network +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wverify equivalence of two combinational or sequential networks +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the STG in KISS2 format +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite the current network in SLIF format +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 \w\fBSequential Synthesis Commands\fP-\n(80-3n-\n(81 +.if \n(38>0 .nr 38 \n(38/1 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 401 file Input is too wide - \n(TW units +.ne 30v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBSequential Synthesis Commands\fP +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'c_check\h'|\n(41u'verifies satisfaction of clocking constraints +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'c_opt\h'|\n(41u'computes the optimal clock for a given clocking scheme +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'chng_clock\h'|\n(41u'toggles clock setting between user-specification and generated values +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'env_seq_dc\h'|\n(41u'extract sequential don't cares based on the environment +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'env_verify_fsm\h'|\n(41u'verify equivalence of two networks in an environment +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'extract_seq_dc\h'|\n(41u'extract sequential don't cares +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'force_init_0\h'|\n(41u'modify so all latches to have a 0 initial state +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'latch_output\h'|\n(41u'forces some outputs to be fed directly by latches +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'one_hot\h'|\n(41u'quick one-hot encoding +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'power_estimate\h'|\n(41u'estimate dissipated power based on switching activity +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'power_free_info\h'|\n(41u'frees memory associated with power calculations +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'power_print\h'|\n(41u'print switcing probabilities and capacitances +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_clock\h'|\n(41u'print out information about the clocks in the network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'print_latch\h'|\n(41u'print out information about all the latches in the circuit +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_kiss\h'|\n(41u'read an STG in KISS2 format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'read_slif\h'|\n(41u'read a network in Stanford Logic Interchange Format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'remove_latches\h'|\n(41u'removes redundant latches +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'retime\h'|\n(41u'move the latches in the circuit to minimize cycle time/# latches +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'set_delay\h'|\n(41u'set delay parameters for primary inputs and outputs  +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'set_state\h'|\n(41u'set the current state in a sequential circuit to the given state +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'short_tests\h'|\n(41u'generate small sequential test sets +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'state_assign\h'|\n(41u'create the logic from the STG using state assignment +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'state_minimize\h'|\n(41u'minimize the number of states in the STG +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'stg_cover\h'|\n(41u'check that the STG behavior covers the logic implementation +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'stg_extract\h'|\n(41u'extract an STG from the logic +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'stg_to_network\h'|\n(41u'converts a state-encoded STG to a logic network +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'verify_fsm\h'|\n(41u'verify equivalence of two combinational or sequential networks +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_kiss\h'|\n(41u'write the STG in KISS2 format +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'write_slif\h'|\n(41u'write the current network in SLIF format +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-35 +.sp .5i +.SH NODELIST ARGUMENTS +Most commands which take a node also take a list of nodes as an +argument. This is referred to as a \fBnode-list\fP in the +documentation below. +This list of nodes includes \fB*\fP to specify +all nodes in the network, \fBi()\fP to specify the primary +inputs of the network, \fBo()\fP to specify the primary +outputs of the network, \fBi(node)\fP to specify the +direct fanin of \fInode\fP, and \fBo(node)\fP to specify the +direct fanout of \fInode\fP. +.sp .5i +.SH STANDARD ALIASES +When \fBSIS\fP starts, it executes commands from a system startup file +(usually $(SIS)/sis_lib/.misrc and $(SIS)/sis_lib/.sisrc). +This defines a standard set of +aliases, and then sources the files ~/.misrc, ~/.sisrc, ./misrc, +and ./sisrc to allow +users to define their own set of aliases. The default alias set includes +the following aliases which have proven useful. Note that many of the aliases +are intended for compatibility with \fBSIS\fP Version #1.0. +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 82 +.nr 80 0 +.nr 38 \walias +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \w1h +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wai +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \walt +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wasb +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wc +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wclp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wcrit +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wel +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wexit +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wfs +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wgd +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wgf +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wgp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \winv +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \woh +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wman +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wnts +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpat +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpc +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpd +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpf +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpg +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpgc +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpio +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpk +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpl +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wplt +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wplv +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpn +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wprt +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wps +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpsf +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpst +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wpv +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wq +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wqd +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wqf +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wqp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wra +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wrd +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wre +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wrk +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wrl +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wrlib +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wro +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wrp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wrr +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wrs +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wcommand +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsa nova -e h +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wadd_inverter +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_altname +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wresub -a +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wchng_name +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcollapse +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wpd -a -p 2 +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \weliminate +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wquit +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wfull_simplify +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wdecomp -g +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wfactor -g +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wphase -g +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \winvert +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wone_hot +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \whelp +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_stats +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_delay -a +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_clock +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_delay +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_factor +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_gate +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_gate -s +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_io +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_kernel +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_latch +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_delay -l +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_level +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wp -n +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_delay -r +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_stats -f +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_stats +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_delay -s +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wprint_value +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wquit +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wdecomp -q +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wfactor -g +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wphase -q +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread_astg +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wreduce_depth +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread_eqn +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread_kiss +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread_blif +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread_library +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread_oct +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread_pla +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wred_removal +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wread_slif +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 82 0 +.nr 38 \wdescription +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wdo 1-hot state encoding using nova +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wadd inverters to a network to correct the phases +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint both long and short names for a node +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \walgebraic resubstitution +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wtoggle between long and short names +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wcollapse network +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint out the 2 most critical paths +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \weliminate nodes below a threshold +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wterminate program +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wsimplify each node function +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wgood decomposition (i.e., best kernel decomposition) +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wgood factoring (i.e., best kernel factoring) +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wgood phase assignment (i.e., more expensive) +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \winvert a node keeping network function consistent +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wdo quick one-hot encoding +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint out command information +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint network status (including factored form) +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint sum-of-products form of a node +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint node arrival times +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint information about clocks in the network +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint delay +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint factored form of a node +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint gate information for a node +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wsummarize gate information for the network +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint inputs and outputs of a node or the network +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint kernels of a node +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint latch information +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint output loading for each node +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint the level of each node +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint nodes in 'negative' form +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint node required times +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint network status (including factored form) +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint network status +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint node slack times +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wprint node values +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wterminate program +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wquick decomposition (i.e., any kernel decomposition) +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wquick factoring (i.e., any kernel factoring) +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wquick phase (i.e., simple greedy algorithm) +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wread a signal transition graph in ASTG format +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wincrease speed before mapping by reducing the depth +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wread equations from a file +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wread an STG in KISS2 format +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wread a blif network from a file +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wread a library +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wread a network from an Oct view +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wread a PLA in espresso format +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wremove combinationally redundant signals +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wread a network in SLIF fornat +.if \n(82<\n(38 .nr 82 \n(38 +.82 +.rm 82 +.nr 38 \w\fBStandard Aliases\fP-\n(80-3n-\n(81-3n-\n(82 +.if \n(38>0 .nr 38 \n(38/2 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 82 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr 42 \n(81+(3*\n(38) +.nr 82 +\n(42 +.nr TW \n(82 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 480 file Input is too wide - \n(TW units +.ne 51v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBStandard Aliases\fP +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'alias\h'|\n(41u'command\h'|\n(42u'description +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'1h\h'|\n(41u'sa nova -e h\h'|\n(42u'do 1-hot state encoding using nova +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'ai\h'|\n(41u'add_inverter\h'|\n(42u'add inverters to a network to correct the phases +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'alt\h'|\n(41u'print_altname\h'|\n(42u'print both long and short names for a node +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'asb\h'|\n(41u'resub -a\h'|\n(42u'algebraic resubstitution +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'c\h'|\n(41u'chng_name\h'|\n(42u'toggle between long and short names +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'clp\h'|\n(41u'collapse\h'|\n(42u'collapse network +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'crit\h'|\n(41u'pd -a -p 2\h'|\n(42u'print out the 2 most critical paths +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'el\h'|\n(41u'eliminate\h'|\n(42u'eliminate nodes below a threshold +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'exit\h'|\n(41u'quit\h'|\n(42u'terminate program +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'fs\h'|\n(41u'full_simplify\h'|\n(42u'simplify each node function +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'gd\h'|\n(41u'decomp -g\h'|\n(42u'good decomposition (i.e., best kernel decomposition) +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'gf\h'|\n(41u'factor -g\h'|\n(42u'good factoring (i.e., best kernel factoring) +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'gp\h'|\n(41u'phase -g\h'|\n(42u'good phase assignment (i.e., more expensive) +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'inv\h'|\n(41u'invert\h'|\n(42u'invert a node keeping network function consistent +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'oh\h'|\n(41u'one_hot\h'|\n(42u'do quick one-hot encoding +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'man\h'|\n(41u'help\h'|\n(42u'print out command information +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'nts\h'|\n(41u'print_stats\h'|\n(42u'print network status (including factored form) +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'p\h'|\n(41u'print\h'|\n(42u'print sum-of-products form of a node +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pat\h'|\n(41u'print_delay -a\h'|\n(42u'print node arrival times +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pc\h'|\n(41u'print_clock\h'|\n(42u'print information about clocks in the network +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pd\h'|\n(41u'print_delay\h'|\n(42u'print delay +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pf\h'|\n(41u'print_factor\h'|\n(42u'print factored form of a node +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pg\h'|\n(41u'print_gate\h'|\n(42u'print gate information for a node +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pgc\h'|\n(41u'print_gate -s\h'|\n(42u'summarize gate information for the network +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pio\h'|\n(41u'print_io\h'|\n(42u'print inputs and outputs of a node or the network +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pk\h'|\n(41u'print_kernel\h'|\n(42u'print kernels of a node +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pl\h'|\n(41u'print_latch\h'|\n(42u'print latch information +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'plt\h'|\n(41u'print_delay -l\h'|\n(42u'print output loading for each node +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'plv\h'|\n(41u'print_level\h'|\n(42u'print the level of each node +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pn\h'|\n(41u'p -n\h'|\n(42u'print nodes in 'negative' form +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'prt\h'|\n(41u'print_delay -r\h'|\n(42u'print node required times +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'ps\h'|\n(41u'print_stats -f\h'|\n(42u'print network status (including factored form) +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'psf\h'|\n(41u'print_stats\h'|\n(42u'print network status +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pst\h'|\n(41u'print_delay -s\h'|\n(42u'print node slack times +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'pv\h'|\n(41u'print_value\h'|\n(42u'print node values +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'q\h'|\n(41u'quit\h'|\n(42u'terminate program +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'qd\h'|\n(41u'decomp -q\h'|\n(42u'quick decomposition (i.e., any kernel decomposition) +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'qf\h'|\n(41u'factor -g\h'|\n(42u'quick factoring (i.e., any kernel factoring) +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'qp\h'|\n(41u'phase -q\h'|\n(42u'quick phase (i.e., simple greedy algorithm) +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'ra\h'|\n(41u'read_astg\h'|\n(42u'read a signal transition graph in ASTG format +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'rd\h'|\n(41u'reduce_depth\h'|\n(42u'increase speed before mapping by reducing the depth +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u're\h'|\n(41u'read_eqn\h'|\n(42u'read equations from a file +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'rk\h'|\n(41u'read_kiss\h'|\n(42u'read an STG in KISS2 format +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'rl\h'|\n(41u'read_blif\h'|\n(42u'read a blif network from a file +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'rlib\h'|\n(41u'read_library\h'|\n(42u'read a library +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'ro\h'|\n(41u'read_oct\h'|\n(42u'read a network from an Oct view +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'rp\h'|\n(41u'read_pla\h'|\n(42u'read a PLA in espresso format +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'rr\h'|\n(41u'red_removal\h'|\n(42u'remove combinationally redundant signals +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'rs\h'|\n(41u'read_slif\h'|\n(42u'read a network in SLIF fornat +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-57 +.sp 1 +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 82 +.nr 80 0 +.nr 38 \walias +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wrsn +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wrt +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsa +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wse +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsim +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsim0 +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsim1 +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsim2 +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsim3 +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsm +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wso  +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wsw +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wtd +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wu +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wv +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwa +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwb +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwe +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwk +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwl +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwp +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wwo +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wws +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \wxdc +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wcommand +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wreset_name +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wretime -n +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wstate_assign +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wstg_extract +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsimulate +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsimplify -d +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsimplify -m nocomp -d +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsimplify +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsimplify -m nocomp +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wstate_minimize +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsource +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wspeed_up +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wsweep +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wtech_decomp +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wundo +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wverify_fsm +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite_astg +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite_bdnet +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite_eqn +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite_kiss +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite_blif +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite_pla +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite_oct +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wwrite_slif +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wextract_seq_dc +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 82 0 +.nr 38 \wdescription +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wreset all short names starting from 'a' +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wretime an unmapped network +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wcreate the logic from the STG using state assignment +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wextract an STG from the logic +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wlogic simulation on a network +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wquick minimization of a node (no don't cares) +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wcomplete minimization of a node (no don't cares) +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wsingle pass minimization with fanin DC-set +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wcomplete minimization with fanin DC-set +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wminimize the number of states in the STG +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wsource a script file +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wcritical path restructuring to reduce delay +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wremove buffers, inverters from a network +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wdecompose network into AND/OR gates +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wundo last command which changed network +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wverify the equivalence of two sequential networks +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wwrite the current signal transition graph in ASTG format +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wwrite mapped network in BDNET format +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wwrite network in EQN format +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wwrite the STG in KISS2 format +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wwrite network in blif format +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wwrite network in Espresso PLA format +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wwrite network as an Oct view +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wwrite network in SLIF format +.if \n(82<\n(38 .nr 82 \n(38 +.nr 38 \wextract sequential don't cares (unreachable states) +.if \n(82<\n(38 .nr 82 \n(38 +.82 +.rm 82 +.nr 38 \w\fBStandard Aliases (cont.)\fP-\n(80-3n-\n(81-3n-\n(82 +.if \n(38>0 .nr 38 \n(38/2 +.if \n(38<0 .nr 38 0 +.nr 81 +\n(38 +.nr 82 +\n(38 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr 42 \n(81+(3*\n(38) +.nr 82 +\n(42 +.nr TW \n(82 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 515 file Input is too wide - \n(TW units +.ne 27v+2p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'\fBStandard Aliases (cont.)\fP +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'alias\h'|\n(41u'command\h'|\n(42u'description +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'rsn\h'|\n(41u'reset_name\h'|\n(42u'reset all short names starting from 'a' +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'rt\h'|\n(41u'retime -n\h'|\n(42u'retime an unmapped network +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sa\h'|\n(41u'state_assign\h'|\n(42u'create the logic from the STG using state assignment +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'se\h'|\n(41u'stg_extract\h'|\n(42u'extract an STG from the logic +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sim\h'|\n(41u'simulate\h'|\n(42u'logic simulation on a network +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sim0\h'|\n(41u'simplify -d\h'|\n(42u'quick minimization of a node (no don't cares) +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sim1\h'|\n(41u'simplify -m nocomp -d\h'|\n(42u'complete minimization of a node (no don't cares) +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sim2\h'|\n(41u'simplify\h'|\n(42u'single pass minimization with fanin DC-set +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sim3\h'|\n(41u'simplify -m nocomp\h'|\n(42u'complete minimization with fanin DC-set +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sm\h'|\n(41u'state_minimize\h'|\n(42u'minimize the number of states in the STG +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'so \h'|\n(41u'source\h'|\n(42u'source a script file +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sp\h'|\n(41u'speed_up\h'|\n(42u'critical path restructuring to reduce delay +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'sw\h'|\n(41u'sweep\h'|\n(42u'remove buffers, inverters from a network +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'td\h'|\n(41u'tech_decomp\h'|\n(42u'decompose network into AND/OR gates +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'u\h'|\n(41u'undo\h'|\n(42u'undo last command which changed network +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'v\h'|\n(41u'verify_fsm\h'|\n(42u'verify the equivalence of two sequential networks +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'wa\h'|\n(41u'write_astg\h'|\n(42u'write the current signal transition graph in ASTG format +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'wb\h'|\n(41u'write_bdnet\h'|\n(42u'write mapped network in BDNET format +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'we\h'|\n(41u'write_eqn\h'|\n(42u'write network in EQN format +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'wk\h'|\n(41u'write_kiss\h'|\n(42u'write the STG in KISS2 format +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'wl\h'|\n(41u'write_blif\h'|\n(42u'write network in blif format +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'wp\h'|\n(41u'write_pla\h'|\n(42u'write network in Espresso PLA format +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'wo\h'|\n(41u'write_oct\h'|\n(42u'write network as an Oct view +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'ws\h'|\n(41u'write_slif\h'|\n(42u'write network in SLIF format +.ta \n(80u \n(81u \n(82u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'xdc\h'|\n(41u'extract_seq_dc\h'|\n(42u'extract sequential don't cares (unreachable states) +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-33 +.bp +.SH DETAILED COMMAND DESCRIPTIONS +.PP +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +act_map [-h heuristic_num] [-n num_iteration] [-f collapse_fanin] + [-g gain_factor] [-d decomp_fanin] [-r filename] + [-M MAXOPTIMAL] [-qolDsv] +.PP +Routine to find an optimal mapping to the Actel architecture. +The input is the Boolean network and the output +is a netlist and the block count +(reference: An Architecture for Electrically Configurable Gate Arrays, +Gamal et. al., IEEE J. of Solid State Circuits, April 1989, pp. 394-398). +.PP +\fBact_map\fP synthesizes the given circuit onto Actel +architecture. +It uses a tree-mapping approach to +cover the subject graph with the pattern graphs. +The pattern graphs are hard-wired into the code +and so no library is to be read in. +Subject graph and pattern-graphs are in terms of +2-1 muxes. Subject graph is constructed for each intermediate +node of the network. +Either an OBDD (Ordered BDD) +and/or a BDD is constructed for each such node. +After the entire +network is mapped, an iterative_improvement phase may be entered. + +Following options are supported: + +.PP +\fB-h heuristic_number\fP specifies which one of the two +subject_graphs would be constructed. +.br +.PP +heuristic num = 1 => OBDD +.br +.PP +heuristic num = 2 => BDD (default) +.br +.PP +heuristic num = 3 => program decides which one to construct. +.br +.PP +heuristic num = 4 => both are constructed and the one with +lower mapped cost is selected. Gives the best +result, but typically takes more time. +.br +.PP +\fB-M MAXOPTIMAL\fP constructs an optimal OBDD for a node if number of fanins is +at most MAXOPTIMAL. +.br +.PP +\fB-n num_iteration\fP specifies the maximum number of iterations +to be performed in the iterative_improvement phase. Each such +iteration involves a good_decomposition followed by a partial_collapse +routine. Partial_collapse tries to collapse each node into +its fanouts. Default is -n 0. +.br +.PP +\fB-f collapse_fanin\fP considers only those nodes +for partial_collapse which have fanin no more than collapse_fanin. +(Default: -f 3). +.br +.PP +\fB-g gain_factor\fP makes the program enter the next iteration +only if gain in the present iteration is at least +(present_cost * gain_factor). (Default: -g 0.01) +.br +.PP +\fB-d decomp_fanin\fP considers only those nodes for good_decomposition +which have fanin greater than or equal to decomp_fanin. (Default -d 4). +.br +.PP +\fB-r filename\fP is the final mapping option. +After mapping, a mapped network would be created, in +which each intermediate node corresponds to one basic block +of Actel architecture. +A file \fBfilename\fP having the netlist description +in a BDNET-like format is also formed. +The pin names of the basic block are the same +as those given in a Figure in the paper on Actel +architecture (reference: An Architecture for Electrically +Configurable Gate Arrays, Gamal et al., IEEE J. Solid State +Circuits, April 1989, pp. 394-398). +.br +.PP +\fB-q\fP makes the program enter a quick_phase +routine (after iterative_improvement phase), which greedily +finds out if it is beneficial to implement the node in +negative phase. +.br +.PP +\fB-D\fP causes a disjoint decomposition routine +to be invoked on the network before mapping starts. +.br +.PP +\fB-o\fP causes the OR gate in the basic block to be ignored. So mapping is done onto a +three-mux structure. +.br +.PP +\fB-v\fP turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. +.br +.PP +\fB-s\fP gives the statistics, regarding the block count +of the circuit. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +add_inverter +.PP +Add inverters into the network wherever needed to make each +signal (including the primary inputs) used only in its negative form. +After this command, every literal in a node is in the negative form. +This is the appropriate starting point for the technology mapping step. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +alias [name [string]] +.X1 +unalias name ... +.PP +The \fBalias\fR command, if given no arguments, will print the +definition of all current aliases. Given a single argument, it +will print the definition of that alias (if any). Given two +arguments, the keyword \fBname\fP becomes an alias for +the command string \fBstring\fP, replacing any other alias with the +same name. +The \fBunalias\fR command removes the definition of an alias. +.PP +It is possible to create aliases that take arguments by using the history +substitution mechanism. To protect the history substitution character `%' +from immediate expansion, it must be preceded by a `\\' when entering the +alias. For example: +.IP +.nf +sis> alias read read_\\%:1 \\%:2.\\%:1 +sis> alias write write_\\%:1 \\%:2.\\%:1 +sis> read blif lion +sis> write eqn tiger +.fi +.PP +will create the two aliases `read' and `write', execute "read_blif +lion.blif", and then execute "write_eqn tiger.eqn". And... +.fi +.IP +.nf +sis> alias echo2 "echo Hi ; echo \\%* !" +sis> echo2 happy birthday +.fi +.PP +would print: +.IP +.nf +Hi +happy birthday ! +.fi +.PP +\fBCAVEAT:\fR Currently there is no check to see if there is a circular +dependency in the alias definition. e.g. +.IP +.nf +sis> alias foo "print_stats -f; print_level -l; foo" +.fi +.PP +creates an alias which refers to itself. Executing the command "foo" will +result an infinite loop during which the commands "print_stats -f" and +"print_level -l" will be executed. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_add_state [-v debug_level] [-m] +.PP +Adds state signal transitions to the Signal Transition Graph to guarantee +implementability (see \fBastg_state_min\fR for a recommended script file). +.PP +The \fB-m\fR option does not preserve the original ASTG marking, and forces its +re-computation (may be slow; dubious usefulness). +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_contract [-f] <signal-name> +.PP +Generate the contracted net for the specified signal of the ASTG. +.PP +The -f option adds the restriction that the contracted net +must also be free-choice. +Chu has conjectured that this restriction may not be necessary, +so it is optional at this time until we have answered this +question. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_current +.PP +Display information about the current ASTG: +its name, +whether it is a free-choice net, +state machine, or marked graph, +and the number of state machine (SM) and marked +graph (MG) components if astg_smc or astg_mgc have +been run on the ASTG. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_encode [-v debug_level] [-h] [-s] [-u] +.PP +Encodes the states of the current State Transition Graph using Tracey's +critical race-free encoding algorithm. Used to perform state encoding for +asynchronous circuits (see \fBastg_state_min\fR for a recommended script file). +.PP +The \fB-h\fR option selects a faster heuristic (that may result in more state +variables). +.PP +The \fB-s\fR option prints out a brief summary of the encoding algorithm +results. +.PP +The \fB-u\fR option allows to enter user-defined codes (for debugging purposes). +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_lockgraph [-l] +.PP +Build the lock graph for the current ASTG. +.PP +With the -l option, edges are added to +the ASTG to ensure that the lock graph +is connected, and thus that the ASTG has the Complete State +Coding property. +.PP +If an ASTG has the CSC property, the state of the circuit can +be represented completely by the collection of input, output +and internal signals specified in the ASTG. +This simplifies many synthesis algorithms. +.PP +The algorithm works only for ASTGs that are marked graphs (no choice). +See \fBastg_state_min\fR for a set of commands that +ensure Complete State Coding for more general ASTGs. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_marking [-s] [<marking>] +.PP +Display or set the initial marking of the ASTG. +If no marking is given, the current initial marking is +displayed. +The default format for the marking is the same as for the +\fB.marking\fP command of read_astg. +.PP +The -s option uses a state code format for the marking. +This is a list of signal name and value pairs. +For example, to set an initial state with signal A at +value 0 and B at value 1, use the command: +.br +astg_marking -s A 0 B 1 +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_persist [-p] +.PP +Add constraints to make an ASTG persistent. +With the -p option, non-persistent transitions are printed +but the ASTG is not modified. +.PP +For small ASTGs with very high concurrency, enforcing the +ASTG persistency property will partially and sometimes completely +enforce the Complete State Coding property (CSC). +If an ASTG has the CSC property, the state of the circuit can +be represented completely by the collection of input, output +and internal signals specified in the ASTG. +This simplifies many synthesis algorithms. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_print_sg +.PP +Print the state graph of the current ASTG. If no state graph is +present, this will create one by token flow. + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_print_stat +.PP +Print the statistics of the current ASTG: name of the ASTG file, initial +marking, total number of states in the state graph and the total +number of I/O signals. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_slow [-v debug_level] [-t tolerance] [-s] [-u] +[[-f|-F] external_delay_file] [-d default_external_delay] [-m min_delay_factor] +.PP +Remove hazards from the ASTG implementation, inserting delay buffers after some +ASTG signals. Delays are inserted so that no gate within the circuit +implementation can react as though the ASTG specified ordering of signals is +reversed in time. +.PP +It must be invoked after technology mapping (see \fBastg_to_f\fR for a +recommended script file). +.PP +The \fB-m\fR option specifies the amount by which all MINIMUM delays are +MULTIPLIED (this until the delay computation will understand min/max delays). +Of course 0.0 < min_delay_factor <= 1.0. Default value: 1.0. +.PP +The \fB-t\fR option specifies the tolerance to be used during the hazard check +procedure (the larger the specified value, the more conservative is the +algorithm). Default value: 0.0. +.PP +The \fB-s\fR option specifies not to use the shortest-path algorithm when +computing the delays in the network. This might result in being overly +pessimistic (this option is only experimental). +.PP +The \fB-f\fR option specifies a file name to search for the minimum +delays between output signals and input signals of the ASTG (i.e. for those +signals that are not being synthesized). This can be useful if some information +about these signals is known either from the specification or from the +synthesis of another sub-component of the total asynchronous system. +.PP +The file can also be +updated with the minimum delays between each input signal and each output +signal if the \fB-F\fR option is used in place of \fB-f\fR. +This allows for separate synthesis of various sub-components of an +asynchronous system. In this case iteration might be necessary to obtain +optimal results, and a warning message is issued when the stored information +is changed, and a new iteration is required. +.PP +The \fB-u\fR option specifies not to remove hazards, but only to update the +external elay file (if appropriate). This can be used to remove hazards from a +set of Signal Transition Graphs that are synthesized separately (e.g. by +contraction). In this case, a first round of synthesis can be performed +on each Signal Transition Graph, followed by \fBastg_slow\fR +with the \fB-F\fR and the \fB-u\fR options, to store the information on the +delay of the function implementing each signal. Then \fBastg_slow\fR can be +iterated among the Signal Transition Graphs with the \fB-F\fR option only until +convergence is obtained. The results should be comparable with synthesis and +hazard removal from a single Signal Transition Graph, but can be considerably +faster for large specifications. +.PP +The \fB-d\fR option specifies the default minimum delay between output signals +and input signals of the ASTG (if no information can be obtained from the above +described file). The default value is 0.0 (i.e. the environment responds +instantaneously), but this can be overly pessimistic, and result in an +unnecessary slow and large implementation. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_state_min [-v debug_level] [-p minimized_file] [-c "command"] +[-b|-B] [-g|-G] [-u] [-m|-M] [-o #] [-f signal_cost_file] +.PP +Minimizes the current State Transition Graph and derives the information +required to encode the associated Signal Transition Graph. +The complete sequence of actions to implement a Signal Transition Graph that +does not have Complete State Coding is as follows: +.br + +.br +astg_to_stg -m +.br +astg_state_min +.br +astg_encode +.br +astg_add_state +.br + +.br +astg_to_f +.br + ... +.PP +The \fB-f\fR option selects a signal cost file. +This file should contain one line of the form +.br +<signal name> <cost> +.br +(e.g. "bus_ack 10") for each signal in the ASTG. The encoding algorithm +minimizes the sum of the weights of signals that follow state transitions. +Hence this file can be used to strongly favor or disfavor changing the +predecessors of the transitions of a signal. +.PP +By default, output signals have a cost of one and input signals have a +cost equal to the number of output signals plus one. In this way, no input +signal is constrained, if possible. +.PP +The command may emit a series of diagnostic messages of the form: +.br +warning: the STG may not be live (multiple exit point): may need constraint +<signal 1> -> <signal 2> +.br +These messages may or may not cause a failure (diagnosed as internal error) +later on during \fBastg_add_state\fR. In case of failure, \fBone\fR of the +required constraints (ideally the constraint that least decreases the circuit +performance due to the reduction in concurrency) should be added to the ASTG. +The procedure should be repeated until no more such messages occur. +.PP +The options listed below are not generally useful except for debugging purposes +or to obtain faster (but potentially less optimal) +results for large Signal Transition Graphs. +All algorithm speed indications reflect average case analysis. +.PP +The \fB-B\fR and \fB-b\fR options select Binary Decision Diagrams +as internal data structure to find the encoding information (both are generally +slower than the default selection, but \fB-b\fR is generally +faster than \fB-B\fR). +.PP +The \fB-M\fR and \fB-m\fR options select Sparse Matrices +as internal data structure to find the encoding information (both are generally +slower than the default selection, but \fB-m\fR is generally +faster than \fB-M\fR). If \fB-M\fR is selected, then \fB-o\fR can be used to +define some further internal options (this is strongly discouraged). +.PP +The \fB-G\fR and \fB-g\fR options select a greedy (\fB-g\fR) or very greedy +(\fB-G\fR) heuristic +to find the encoding information (both faster and looser than the default +selection). +.PP +The \fB-u\fR option selects a generally slower +heuristic to find the encoding information. +.PP +The \fB-c\fR option allows to use a different minimizer from the default +choice. The minimizer must be able to read and write .kiss format and to write +equivalence class information in the output file, in the following format: +.br +#begin_classes <number of classes> +.br +# <state name> <class number> +.br + ... +.br +#end_classes +.PP +The \fB-p\fR option avoids calling the minimizer altogether, just reading in +the specified minimized file (in .kiss format with equivalence class +information). +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_stg_scr [-v debug_level] +.PP +Transforms the current State Transition Graph into one that satisfies the +Single Cube Restriction. +.PP +The Single Cube Restriction means that each state has exactly one associated +value of input signals under which it is entered. The result is accomplished by +state duplication, but the result may be non-minimal. +This command is required (and useful) before \fBstg_to_astg\fR. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_syn [-m] [-r] [-v debug_level] [-x] +.PP +Synthesize from the current signal transition graph a two-level implementation +which is hazard-free under the unbounded gate delay model (i.e., gates have +unbounded delays, wires have zero delays). +.PP +The synthesis is performed in two steps. The first step derives a +state graph from the ASTG by performing a reachability analysis. If no +initial marking is given, then \fBastg_syn\fR will try to find a live, +safe initial marking. The second step uses the state graph generated +in step one to perform hazard analysis and synthesis. All static +hazards and critical races are removed. \fBastg_syn\fR tries to +remove all dynamic hazards arising from multiple input or output +changes. When it cannot remove such hazards, it will print the terms +which can potentially produce hazards and the conditions under which +hazards can be produced. From this user can remove the dynamic +hazards by removing some concurrency. +The resulting implementation may be neither prime nor irredundant. +.PP +The following options are not intended for general use. +.PP +The \fB-m\fR does not perform cube reduction and always returns a +prime cover implementation free of static hazards. As a consequence, +dynamic hazards due to multiple input/output changes may not be +removed. +.PP +The \fB-r\fR option runs ESPRESSO in single-output mode. +The implementation will be prime and irredundant, but may have static hazards +and dynamic hazards. +.PP +The \fB-v\fR option specifies the debug level. +.PP +The \fB-x\fR assumes that a state graph has already been derived, and +perform synthesis directly from the given state graph. State graph can be +derived by using \fB_astg_flow\fR. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_to_f [-v debug_level] [-r] [-s signal_name] [-d] +.PP +Generate an initial two-level implementation of each output signal specified by +the current Signal Transition Graph. +.PP +If the initial marking is not defined, then a valid marking is searched for. +The list of potential hazards, used by \fBastg_slow\fR, is also produced. +.PP +One primary input is generated for each signal (both input and output) +specified by the ASTG, with the same name as the signal (and "_" appended if the +signal is an output). +.PP +One primary output is generated for each output signal +specified by the ASTG, with the same name as the signal. +The primary output is driven directly by the primary input. +.PP +One asynchronous latch is generated for each output signal specified by the +ASTG, connecting the combinational logic function implementing the signal (a +"fake" primary output with the same name as the signal and "_next" appended) and +the corresponding primary input. +.PP +If some signal is not used inside the combinational logic, then the +corresponding primary input and latch is not created (unless the option +\fB-r\fR is specified). +.PP +The \fB-s\fR option adds a set of fake primary outputs that ensure that the +named signal is implemented as a Set-Reset flip-flop. If, in addition, +the \fB-d\fR option is specified, the functions for the Set and Reset input are +made disjoint. This may increase the implementation cost, but reduces its +sensitivity to dynamic hazards. +.PP +An error message results if either no valid marking is found (in which case it +might be advisable to define it in the ASTG specification file) or the ASTG does +not have the Compatible State Coding property (i.e. if two markings with +different sets of enabled output signals have the same binary label). +See \fBastg_state_min\fR for a recommended action in the latter case. +.PP +A typical ASTG synthesis and optimization script should look like: +.br +astg_to_f +.br + +.br +gkx -ab +.br +resub -ad; sweep +.br +gcx -b +.br +resub -ad; sweep +.br +eliminate 0 +.br +decomp -g * +.br +eliminate -1 +.br + +.br +map +.br +astg_slow +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +astg_to_stg [-v debug_level] [-m] +.PP +Generate a State Transition Graph +from the current Signal Transition Graph. +The State Transition Graph has one input signal for each signal in the Signal +Transition Graph (both input and output), and one output signal for each output +signal in the Signal Transition Graph. +.PP +If the initial marking is not defined, then a valid marking is searched for. +.PP +An error message results if no valid marking is found (in which case it +might be advisable to define it in the ASTG specification file). +.PP +The \fB-m\fR option additionally performs a pre-minimization step that produces +a State Transition Graph suitable for subsequent state encoding commands (such +as, e.g., \fBastg_state_min\fR). +.XX +atpg [-fFhrRpt] [-d RTG_depth] [-n n_fault_sim] [-v verbosity_level] + [-y random_prop_depth] file +.PP +Perform test generation for both combinational and sequential circuits using +random test generation, deterministic test generation, and fault simulation. Deterministic test generation is accomplished by one of two methods. The +first method is a three-step test generation algorithm consisting of +combinational test generation (assuming that latch outputs are controllable, +and that latch inputs are observable), followed by state justification and propagation, when necessary. The combinational test generation is +accomplished using Boolean satisfiability. Justification and propagation are +performed using implicit state transition graph traversal techniques. If the +three-step method does not generate a test for a fault, then the product of +the good and faulty circuit is built and traversed, as in sequential circuit +verification. If this traversal proves the circuits equivalent, then the +fault is redundant; otherwise any differentiating sequence is a test for the +fault. +.PP +Fault collapsing is performed before test generation, across only simple +gates. Both fault equivalence and fault dominance are used to reduce the +fault list. +.PP +For combinational circuits, external don't cares are automatically taken +into account when the don't care network is attached to the care network. The PI's and PO's of the external don't care network (when it is not NIL) must match exactly with the care network. That is, the don't care network cannot specify only a subset of the PI's or PO's of the care network. If this condition is not met, +then the atpg package automatically adds dummy primary inputs and outputs to the +external don't care network. +.PP +Reverse fault simulation is performed as a post-processing step to reduce +test set size. +.PP +The \fB-f\fP option causes the atpg not to perform fault simulation of +deterministically-generated tests on untested faults. +.PP +The \fB-F\fP option causes the atpg not to use reverse fault simulation. +.PP +The \fB-h\fP option restricts the boolean satisfiability algorithm to not use +non-local implications. Four greedy ordering heuristics are tried in this case +instead of the default of eight. Hard-to-test faults that can only be tested +with non-local implication information are aborted by this option. +.PP +The \fB-r\fP option causes the atpg not to perform random test pattern +generation. +.PP +The \fB-R\fP option causes the atpg not to perform random propagation. +(Deterministic propagation is still attempted). +.PP +The \fB-p\fP option causes the atpg not to build any product machines. Thus, +neither deterministic propagation nor good/faulty product machine traversal +will be performed. +.PP +The \fB-t\fP option first converts the network to arbitrary fanin AND and +OR gates. The decomposed network is returned. +.PP +The \fB-d\fP option allows the specification of the length of the random +sequences applied during random test generation. The default length is +the depth of the circuit's state transition graph. +.PP +The \fB-n\fP option allows the specification of the number of sequences +to fault simulate at one time during fault simulation. The default is the +system word length. +.PP +The \fB-v\fP allows the specification of the verbosity level of the output. +.PP +The \fB-y\fP option allows the specification of the length of the random +sequences applied during random propagation. The default length is 20. +.PP +If \fBfile\fP is specified, test patterns are written out to the given file. +.PP +Note: in order to use this command with sequential circuits, the circuit +reset state must be specified in the circuit input file. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +bdsyn +.PP +A special command exported for use by bdsyn(1). Not for general use. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +buffer_opt [-l #] [-f #] [-c] [-d] [-T] [-L] [-v #] [-D] node-list +.PP +Builds fanout trees for the nodes in the \fBnode-list\fR. +If no nodes are specified selects the nodes to be buffered +in order to improve performance of the entire network. The +network is assumed to be mapped. +.PP +The \fB-l #\fR option specifies the number of fanouts which +a node can have so as to be eligible for buffering. The +default is 2, hence any multi-fanout node is a candidate for +buffering. +.PP +The \fB-f #\fR option specifies the transformations to use. Set the +three least significant bits indicate the use (value == 1) of +the transformations. xx1 to use the \fIrepower\fR transformation, +x1x to use an \fIunbalanced\fR transformation and 1xx to use the +\fIbalanced\fR distribution of signals. More than one transformation +can be set active. Thus to allow the algorithm full flexibility use +the value = 7 (111 in binary notation) which is also the default. +.PP +The \fB-c\fR option specifies that one pass be carried out. +The default is to iterate till no improvement is achieved. +.PP +The \fB-d\fR option allows the complex gates to be decomposed +into smaller ones so as to increase drive capability. By default +the complex gates are retained. +.PP +The \fB-L\fR option traverses the network from outputs to +inputs ensuring that for every node, the gate that implements it +does not drive a load greater than the \fImax_load\fR limit +specified for that gate. \fBTHIS OPTION IS NOT YET IMPLEMENTED\fR. +.PP +The \fB-T\fR option displays the circuit performance as the +iterations progress. If the required times at the outputs are +not specified the circuit delay is shown, else the minimum +slack value is displayed. +.PP +The \fB-v #,-D\fR option are for debugging. The \fB-v #\fR option +is the most verbose and the amount of verbosity can be increased +by letting the argument for \fB-v\fR range from 1 to 100. +.XX +c_check -[nd] -[SH]#.# +.PP +Verifies that the given circuit satisfies the constraints for correct +clocking. By default the circuit is assumed to be mapped to a library. +Use the \fB-n\fR option to use the \fIunit-fanout\fR delay model. +.PP +The user can give global set-up (and hold) times for all memory +elements using the \fB-S\fR (\fB-H\fR) option. By default it computes +the set-up and hold times from the library. \fIIf the optimal clocking +scheme was found using the c_opt command\fR make sure you use the same +delay model! +.PP +The \fB-d value\fR selects the debug level. The range is 1-5. +.XX +c_opt -[nGI] -[dSHmM]#.# +.PP +Computes the optimal clock for a given clocking scheme. +Finds rise and fall times for the clock events. A single clock +multi-phase clocking scheme is assumed. +.PP +The algorithm works on mapped and unmapped networks (default is +mapped). Note that to ensure every node is mapped, you should read in +the blif file, read in the library, map the circuit and then run the +optimal clocking algorithm. \fIIt is a known fact that reading in a +mapped netlist often causes some nodes to remain un-mapped\fR. The +command will abort in such a case. The \fB-n\fR option is used for the +\fIunit-fanout\fR delay model. +.PP +By default the algorithm uses a special Linear program solver based on the +Floyd-Warshall algorithm. An alternate formulation using binary search +is available (\fB-B\fR) as long as \fIno minimum duty cycle constraints +are imposed\fR. +.PP +The \fB-I\fR option is used for \fI2 phase inverted clocking schemes only\fR. +.PP +The user can give global set-up (and hold) times for all memory +elements using the \fB-S\fR (\fB-H\fR) option. By default it computes +the set-up and hold times from the library. +.PP +The \fB-m\fR option permits the user to specify a minimum phase +separation as a fraction of the clock cycle. Similarly the \fB-M\fR +option sets the maximum phase separation as a fraction of the clock +cycle. +.PP +The \fB-d value\fR selects the debug level (range 0-4). + +This routine runs faster (upto 2X) when compiled with the priority +queue library from octtools (use flag -DOCT when compiling this +directory). + + + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +chng_clock +.PP +Toggles the setting of the clock between the user-specified +clock settings (specified in the blif file) and the working +values (generated by algorithms inside \fBSIS\fR). +.PP +All algorithms use the current setting as input. If the +algorithms modify the clocking scheme or the cycle-time they +write the modified clocking scheme into the working fields. +Thus, to write out the blif file containing the clock scheme +generated by algorithms inside \fBSIS\fR, the setting must first be +set to the working one and then \fBwrite_blif\fR must be invoked. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +chng_name +.PP +Toggles the network between +long-name mode (user supplied names) and short-name mode +(automatically generated single-character names). +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +collapse [n1] [n2] +.PP +Collapse nodes in the network. With no arguments, the entire network is +collapsed into a single-level of functions (i.e., two-level form). +Each output will be expressed in terms of the primary inputs. +.PP +Given a single node, +that function is collapsed until it is represented entirely in terms of +primary inputs. +.PP +Given two arguments, it is assumed that the second node +is a fanin of the first node. In this case, this dependency is removed +(the first node is expressed without the second node as a fanin). +.PP +Please note that this command negates any mapping that may have been done +at an earlier time. +.PP +Caution should be taken when collapsing network to two levels because +the two level representation may be too large. +The alternative is to use \fBeliminate\fR (selective collapse). +Refer to \fBeliminate\fR for the details. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +constraints [node_1....node_n] +.PP +Print the values of the various delay constraints for the nodes in the +argument list, which must be either inputs or outputs. Also prints +the default values of the default delay parameters for the network. +Used to check the values set by \fBset_delay\fR. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +decomp [-gqd] [node-list] +.PP +Decompose all the nodes in the \fBnode-list\fR. If the \fBnode-list\fR +is not specified, all the nodes in the current network will be +decomposed. Decompostion will factor nodes and make the divisor a new +node within the network, re-expressing other nodes in terms of this +newly introduced node. It is one of the transforms used to break +down large functions into smaller pieces, usually at the cost of +introducing a few more literals. +.PP +If the \fB-q\fR option (the default) is specified, the \fIquick decomp\fR +algorithm is used which +extracts out an \fIarbitrary\fR kernel successively. Because +of the fast algorithm for generating an arbitrary kernel, +\fBdecomp -q\fR is very fast compared with the \fBdecomp -g\fR. +In most cases, the result is very close. +This command is recommended at the early phase of the optimization. +.PP +If the \fB-g\fR option is specified, the \fIgood decomp\fR +algorithm is used which +successively extracts out the \fIbest kernel\fR until the function is +factor free, and applies the same algorithm to all the kernels just extracted. +This operation will give the best \fIalgebraic\fR decomposition for the nodes. +But, since it generates all the kernels at each step, it takes more +CPU time. In general, \fBdecomp -q\fR should be used in the early +stage of the optimization. Only at the end of the optimization, should +\fBdecomp -g\fR be used. +.PP +If the \fB-d\fR option is specified, the disjoint decomposition +is performed. Currently, the disjoint decomposition is limited +to the following simple algorithm: It partitions the cubes +into sets of cubes having disjoint variable support, creates +one node for each partition, and a node (the root of the +decomposition) which is the OR of all the partitions. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +echo args ... +.PP +Echoes the arguments to standard output. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +eliminate [-l limit] thresh +.PP +Eliminate all the nodes in the network whose +value is less than or equal to \fBthresh\fR. +The value of a node represents the number of literals saved +in the literal count for the network by leaving the +node in the network. +If the value is less than (or equal to) the threshold, the node +will be eliminated by collapsing the node into each of its fanouts. +A primary input or a primary output will not be eliminated. +.PP +The value of the node is approximated based on +the number of times the node is used +in the factored form for each of its fanouts. +Note that if a node is used only once, its value is always -1. +.PP +\fBlimit\fR is used to control the maximum number of cubes +in any node. The default is 1000. Using a very large \fBlimit\fR +may result in collapsing the network to two levels. In general, +if the circuit is collapsible, the command \fBcollapse\fR is +more efficient. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +env_seq_dc [-v n] filename.blif +.PP +This command extracts sequential don't cares based on unreachable +states. It builds the product of the current network with the network +passed as argument, computes the set of reachable states of the +product, extracts from that the set of reachable states of the +original network, and uses its complement to build a don't care +network for the current network. Any previous don't care network is +discarded. +.PP +\fBfull_simplify\fR or \fBequiv_nets\fR should be run afterwards to +exploit these don't cares. +.PP +External inputs of the current network are connected to matching +external outputs of the network passed as argument and vice-versa. +Nodes match if and only if they have the same name. +.PP +\fB-v\fR allows the specification of the verbosity level of the output. +The default value is 0. +.PP +The method used to compute the set of reachable states is the +\fBproduct\fR method. See \fBextract_seq_dc\fR for details. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +env_verify_fsm [-v n] [-V] fsm.blif env.blif +.PP +Verify the equivalence of two synchronous networks in a given environment. +The current network is compared with \fBfsm.blif\fR under the +environment defined by the \fBenv.blif\fR network. +The environment is a sequential circuit that generates the inputs of +the circuits under verification, and possibly takes some inputs from +them. What is verified is that the current network and the +\fBfsm.blif\fR network are substituable for one another when used in +the context of the \fBenv.blif\fR network. +.PP +The input and output variables from the three networks are +matched by names. It is assumed that all the latches in both designs +are clocked by a single, global clock. +The verification is done by implicitly enumerating all the +states in the product machine, and checking that the outputs +are equivalent for all reachable state pairs starting +from the initial state of the product machine. +.PP +\fB-v\fR allows specification of the verbosity level of the output. +.PP +By default, the command returns an error status if the verification fails. +When option \fB-V\fR is used, it returns an error status if the verification succeeds. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +equiv_nets [-v n] +.PP +This command simplifies the network using net equivalence. +With \fBfull_simplify\fR, it is one of the two routines able to take +advantage of network don't cares. +.PP +\fBequiv_nets\fR groups all nets of the network by equivalence classes. +Two nets are equivalent if and only if they always compute the same +function with respect to the external care set. It only uses input +don't cares, not observabiilty don't cares. +.PP +For each equivalence class, \fBequiv_nets\fR selects a lowest cost +net, and moves the fanout of all the other nets of the equivalence +class onto the lowest cost net. +.PP +Finally, it calls the command \fBsweep\fR. +.PP +\fB-v\fR allows the specification of the verbosity level of the output. +The default value is 0. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +espresso +.PP +Collapse the network into a PLA, minimize it using \fIespresso\fR, +and put the result back into the multiple-level \fInor-nor\fR form. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +extract_seq_dc [-o depth] [-v n] [-m method] +.PP +Extract sequential don't cares based on unreachable states. +The unreachable states are computed by +implicitly enumerating the set of +reachable states in the circuit starting from an initial state +and then computing the inverse of that set. +\fBfull_simplify\fR or \fBequiv_nets\fR should be run afterwards to +exploit these don't cares. +.PP +\fB-o depth\fR allows the specification of the depth of search for good +variable ordering. +A larger value for depth will require more CPU time but determine +a better ordering. +The default value is 2. +.PP +\fB-v\fR allows specification of the verbosity level of the output. +.PP +The \fB-m\fR option specifies \fBmethod\fR for determining +the reachable states. +\fBconsistency\fR builds the entire transition relation +and uses it to determine the reached states. +\fBbull\fR does output cofactoring to find the reachable +states. +The \fBproduct\fR method is similar to the \fBconsistency\fR method but +input variables are smoothed as soon as possible as the characteristic +function is being built. +This makes the size of the resulting BDD representing the +characteristic function of the transition relation smaller. +The default method is \fBproduct\fR. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +factor [-gq] node-list +.PP +Throw away the old factored forms and factor each node in the +\fBnode-list\fR, and store the factored forms with the nodes. +If the \fB-q\fR option is specified, the \fIquick factor\fR algorithm +is used to factor the node. +If the \fB-g\fR option is specified, the \fIgood factor\fR +algorithm is used to factor the node. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +fanout_alg [-v] alg_list +.PP +Activates selectively one or more fanout algorithms. For a list of +fanout algorithms known to the system, use the \fB-v\fR option. +The algorithms activated are the ones specified in the list. +One algorithm, \fInoalg\fR, is always active. +\fItwo_level\fR +is a fast, area efficient algorithm. The best results are +obtained with \fItwo_level\fR, \fIbottom_up\fR, \fIlt_trees\fR, +and \fImixed_lt_trees\fR. +.PP +Fanout optimization itself is performed using the \fBmap\fR command. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +fanout_param [-v] fanout_alg [property value] +.PP +Changes the default parameter values associated with specific +fanout algorithms. For a list of these parameters and their values, +use the \fB-v\fP option with a fanout algorithm. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +force_init_0 +.PP +This command replaces all latches initialized to 1 by latches +initialized to 0. It inserts an inverter before and after the latch +to maintain circuit behavior. +.PP +This command is useful for certain types of FPGA architectures +which do not support the initialization of latches to 1. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +free_dc +.PP +Frees the don't care network associated with a network. +This command is used for debugging and experimental purposes. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +full_simplify [-d][-o ordering] [-m method] [-l] [-v verbose] +.PP +Simplify each node in the network using the local don't cares +generated in terms of fanins of each node. +First compatible +observability plus external don't cares are generated for +each node in terms of primary inputs. +Then the image +computation techniques are used to map these don't cares +to the local space of each node. +This technique removes +most redundancies in the network. +The satisfiability don't cares +for a subset of the nodes in the network which have the same +support as the node being simplified is also generated. +An ordering is given to the nodes of the network +and local don't cares for the nodes are computed according +to that ordering. +Each node is simplified using its local don't cares and an +appropriate satisfiability don't care subset. + +.PP +\fB-d\fR If this option is used no observability don't cares are computed. +In this case the local don't cares are only the unreachable points +in the local space of each node (a subset of the satisfiability +don't care set). + +.PP +\fB-o\fR Used for BDD ordering. If 0 (default) is used, variables +are ordered based on their depth. If 1 is used, the level of +a node is used for its ordering. + +.PP +\fBmethod\fR specifies the algorithm used to minimize the nodes. +\fIsnocomp\fR (default) invokes a single pass minimization procedure that does +not compute the complete offset. +\fInocomp\fR invokes the full minimization procedure (ala ESPRESSO) but does +not compute the complete offset. +\fIdcsimp\fR invokes single pass tautology-based minimizer. + +.PP +\fB-l\fR generates fanin don't cares only for nodes +with the same or subset support as the node being minimized +which have level less than the node being minimized. The level +is the largest number of nodes on the longest path from the node to +a primary input. + +.PP +\fB-v\fR prints out extra info for debugging the code. + + +SIS(1) UNIX Programmer's Manual SIS(1) + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +fx [-o] [-b limit] [-l] [-z] +.PP +Greedy concurrent algorithm for finding the best double cube divisors and +single cube divisors. +Finds all the double cube and single cube divisors +of the nodes in the network. +It associates a cost function to each node, +and extracts the node with the best cost function greedily. +.PP +The \fB-o\fP option only looks for 0-level two-cube divisors. +.PP +The \fB-b\fP option reads an upper bound for the number of divisors +generated. The default value is 50000. This is because the +number of divisors in some cases can grow very large. +.PP +The \fB-l\fP option changes the level of each node in the network as allowed +by the slack between the required time and arrival time at that node. +.PP +The \fB-z\fP option uses zero-weight divisors (in addition to divisors with +a larger weight). This means that divisors that contribute zero gain to +the overall decomposition are extracted. This may result in an overall +better decomposition, but take an exhorbitant amount of time. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +gcx [-bcdf] [-t threshold] +.PP +Extract common cubes from a network, re-express the network +in terms of these cubes, and in the process cut down on the +number of literals needed in the network. +.PP +The \fB-b\fP option chooses the best cube at each step when examining +possible cubes to be extracted; otherwise, the more efficient \fIping-pong\fP +algorithm is used to find a good (but not necessarily the best) cube +at each step. +.PP +The \fB-c\fP option uses the complement of each cube as well as the cube +when dividing the new cube into the network. +.PP +The \fB-f\fP option uses the number +of literals in the factored form for the +network as a cost function for determining the best cube to be extracted. +.PP +The \fB-t\fP option sets a threshold such that only a cube with a value +greater than the threshold will be extracted. By default, the threshold is +0, so that all possible cube divisors are extracted. +.PP +The \fB-d\fP option enables a debugging mode which traces the execution +of gcx. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +gkx [-1abcdfo] [-t threshold] +.PP +Extract multiple-cube common divisors from the network. +.PP +The \fB-a\fP option generates all kernels of all function in the network +when building the kernel-intersection table. By default, only level-0 +kernels are used. +.PP +The \fB-b\fP option chooses the best kernel intersection as the new +factor at each step of the algorithm; this is done by enumerating and +considering each possible kernel intersection, and choosing the best. +By default, the more efficient \fIping-pong\fP algorithm is used to +find a good (but not necessarily the best) kernel intersection. +.PP +The \fB-c\fP option uses the new factor and its complement when attempting +to introduce the new factor into the network. +.PP +The \fB-d\fP option enables debugging information which traces the execution +of the kernel extract algorithm. +.PP +The \fB-f\fP option uses the number of literals in the factored form for +the network as the cost function when determining the value of a +kernel intersection; by default, the number of literals in the sum-of-products +form for the network is used. +.PP +The \fB-o\fP option allows for overlapping factors. +.PP +The \fB-t\fP option sets a threshold such that divisors are extracted +only while their value exceeds the threshold. By default, the threshold is 0 +so that all possible multiple-cube divisors are extracted from the network. +.PP +The \fB-1\fP option performs only a single pass over the network. By default, +the kernel extract algorithm is iterated while there are still divisors whose +value exceeds the given threshold. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +help [-a] [command] +.PP +Given no arguments, help prints a list of all commands known to the +command interpreter. The \fB-a\fP option provides a list of all +debugging commands, which by convention begin with an underscore. +If a command name is given, +detailed information for that command will be provided. + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +history [-h] [num] +.PP +Lists previous commands and their event numbers. +The \fB-h\fP option suppresses printing the event number. +If \fBnum\fP is specified, lists the last \fBnum\fP events. Lists the last +30 events if \fBnum\fP is not specified. +.PP +History Substitution: +.PP +The history substitution mechanism is a simpler version of the csh history +substitution mechanism. It enables you to reuse words from previously typed +commands. +.PP +The default history substitution character is the `%' (`!' is default for shell +escapes, and `#' marks the beginning of a comment). This can be changed using +the "set" command. In this description '%' is used as the history_char. +The `%' can appear +anywhere in a line. A line containing a history substitution is echoed to +the screen after the substitution takes place. `%' can be preceded by a +`\\' in order to escape the substitution, for example, to enter a `%' into +an alias or to set the prompt. +.PP +Each valid line typed at the prompt is saved. If the \fBhistory\fP variable +is set (see help page for \fBset\fP), each line is also echoed to the history +file. You can use the "history" command to list the previously typed +commands. +.PP +Substitutions: at any point in a line these history substitutions are +available +.ta .5i 1.5i +.PP +.nf + %:0 Initial word of last command. + %:n n'th argument of last command. + %$ Last argument of last command. + %* All but initial word of last command. + + %% Last command. + %stuf Last command beginning with "stuf". + %n Repeat the n'th command. + %-n Repeat the n'th previous command. + ^old^new Replace "old" w/ "new" in previous command. + + Trailing spaces are significant during substitution. + Initial spaces are not significant. +.fi +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +invert node-list +.PP +Invert each node in the \fBnode-list\fR. It is used when +the complement of a node is to be implemented. Note that +it does not change the logic function of the current Boolean +network, but will have an effect on the structure of the network. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +invert_io node-list +.PP +This command reverses the polarity of the specified nodes. +The nodes have to be external primary inputs or external primary outputs. +.PP +The polarity inversion is done by adding an inverter before a primary output or +after a primary input. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +ite_map [-n num_iter] [-C cost_limit] [-f collapse_fanin] + [-m map_method] [-d decomp_fanin] [-M MAXOPTIMAL] [-clorsvD] +.PP +Routine to find an optimal mapping to Actel's ACT1 architecture. +The input is the Boolean network and the output +is a netlist and the block count +(reference: An Architecture for Electrically Configurable Gate Arrays, +Gamal et. al., IEEE J. of Solid State Circuits, April 1989, pp. 394-398). +.PP +\fBite_map\fP synthesizes the given circuit onto Actel ACT1 +architecture. +The pattern graphs are hard-wired into the code +and so no library is to be read in. Each intermediate +node of the network is checked to see if it matches onto one ACT1 +module. This check is done using a Boolean matching algorithm. +If not, then a subject graph is constructed for the node function. +The subject graph (as well as the pattern-graphs) is in terms of +2-1 muxes: it uses ITEs (if-then-else DAGs) and ROBDDs (Reduced +Ordered BDDs) for the mapping. After an initial mapping of the +network, an iterative_improvement phase may be entered. Local collapse and +decomposition operations are performed for better quality. + +Following options are supported: + +.PP +\fB-m map_method\fP specifies which one of the two +subject_graphs would be constructed. +.br +.PP +map_method = 1 => Standard mapping for each node. +.br +.PP +map_method = 2 => construct a sub-network from each node. Map the +sub-network using iterative improvement and finally replace the node +with the mapped sub-network. +.br +.PP +\fB-n num_iteration\fP specifies the maximum number of iterations +to be performed in the iterative_improvement phase. Default is -n 0. +.br +.PP +\fB-F collapse_fanins_of_fanout\fP used in partial collapse. Collapses +a node into fanouts only if after collapsing, each fanout has at most +collapse_fanins_of_fanout fanins (Default: -F 15). +.br +.PP +\fB-C cost_limit\fP in partial collapse, collapse a node only if its +cost is at most cost_limit (Default: -C 3). +.br +.PP +\fB-f collapse_fanin\fP considers only those nodes for partial +collapse which have at most collapse_fanin fanins (Default: -f 3). +.br +.PP +\fB-d decomp_fanin\fP considers only those nodes for decomposition in +iterative improvement which have fanin greater than or equal to +decomp_fanin. (Default -d 4). +.br +.PP +\fB-M MAXOPTIMAL\fP constructs an optimal ROBDD (if the ROBDD option +is selected) for a node if number of fanins is at most MAXOPTIMAL. +.br +.PP +\fB-r\fP is the final mapping option. After initial mapping and +possible iterative improvement, a mapped network is created in +which each intermediate node corresponds to one ACT1 module. If not +specified, the network may not have a one-to-one correspondence with +the ACT1 module. +.br +.PP +\fB-D\fP selects the decomposition method. If specified, computes a +factored form of the node and then constructs ITE for each factor. +.br +.PP +\fB-c\fP causes the matching algorithm to be exact. If not +specified, matching is approximate. +.br +.PP +\fB-o\fP causes the OR gate in ACT1 to be ignored. So mapping is done onto a +three-mux structure. +.br +.PP +\fB-v\fP turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. +.br +.PP +\fB-s\fP gives the statistics, regarding the block count +of the circuit. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +latch_output [-v n] node-list +.PP +The nodes passed as argument should be external primary outputs. +This command forces the listed external primary outputs to be fed by a +latch. This is accomplished by moving latches forward by retiming. +.PP +The command fails if there is a combinational dependency between an +external primary input and one of the specified primary outputs. +.PP +This function is useful to guarantee that certain outputs will not +glitch. It is handy if that output is to control an external device +such as the write enable signal of a memory chip. +.PP +\fB-v\fR allows the specification of the verbosity level of the output. +The default value is 0. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +map [-b #][-f #][-i][-m #][-n #][-r][-s][-p][-v #] [-A][-B #][-F][-G][-W] +.PP +Perform a technology mapping on the current network. A library must be read +using the \fBread_library\fR command before mapping can be performed. +The result +of the mapping may become invalidated if a command such as \fBplot\fR or +\fBprint_stats -f\fR is executed which computes a factored form +representation of +every node. +.PP +To produce a minimum area circuit with no consideration for load limits, the +recommended option is \fBmap -m 0\fR. +.PP +To produce a minimum area circuit that respects load limits, the recommended +option is \fBmap -m 0 -AF\fR. Use \fB_check_load_limit\fR +command to check for +load limit violations. +.PP +To produce a minimum delay circuit that respects load limits, the recommended +option is \fBmap -n 1 -AFG\fR. +To specify required times in order to allow the +mapper to trade off delay and area, use the \fBset_delay\fR command. +.PP +Details about the meanings of the various options follow. +.PP +The \fB-b n\fP sets the number by which the load value +should be multiplied in case of a load limit violation during fanout optimization. +.PP +The \fB-f n\fP option controls the internal fanout handling. A value +of '0' disables it completely (i.e. the mapping is strictly +tree-based). +A value of '1' enables an heuristics approximating the +cost of the previous tree at fanout branches. +A value of '2' enables +the usage of cells with internal fanout (such as EXOR and +MULTIPLEXER). A value of '3' (default) enables both. None of these +values is guaranteed to give the best solution in all cases, but '3' +usually does. A warning is issued if the current value can give bad +results with the current network (use \fBundo\fR before mapping +again). +.PP +The \fB-i\fP option disables the \fIinverter-at-branch-point\fR heuristic. +It is intended for experimentation with different mapping heuristics. +.PP +The \fB-m\fP option controls the cost function used for a simple version of the +tree covering algorithm. A mode of '0' (the default) minimizes the area of the +resulting circuit. A mode of '1' minimizes the delay of the resulting circuit +(without regard to the total area). An intermediate value uses as cost +function a linear combination of the two, and can be used to explore the +area-delay tradeoff. A value of '2' minimizes the delay on an estimate of the +critical path obtained from a trivial 2-input NAND mapping, and the area +elsewhere. +.PP +The \fB-n\fP option allows the access to a better tree covering algorithm. It +can only be used in delay mode, i.e. with an argument of 1: \fB-n 1\fP. This +algorithm gives better performance than \fB-m 1\fP but is noticeably slower. It uses a +finer dynamic programming algorithm that takes output load values into account, +while \fB-m 1\fP option supposes all loads to be the same. As a consequence, +the \fB-n 1\fP option performs better than \fB-m 1\fP especially with rich +libraries of gates. Both algorithms use heuristics to guess the load value at +multiple fanout points. Both options should always be used with fanout +optimization turned on. +.PP +If \fB-r\fP is given (\fIraw mode\fP), the network must already be either 1- +and 2-input NAND gates, or 1- and 2-input NOR gates form, depending on whether +a NAND-library, or a NOR-library was specified when the library was originally +read (see \fBread_library\fR). +If \fB-r\fP is not given, appropriate commands are +inserted to transform the network into the correct format. +.PP +The \fB-s\fP option prints brief statistics on the mapping results. +.PP +The \fB-p\fP option forces the mapper to ignore the delay information provided +by the user at primary inputs and primary outputs (arrival times, required +times, loads, drive capability). It is intended for experimental use. This +option forces the arrival times and required times to be all 0, the loads and +drive capabilities to be all equal to the load and drive capability of the second +smallest inverter in the library. If there is only one inverter, the data are +taken from that inverter. +.PP +The \fB-v n\fP options is for development use, and provides debugging +information of varying degrees of verbosity as the mapping proceeds. +.PP +The \fB-A\fP option recovers area after fanout optimization +at little or no delay cost by resizing buffers and inverters. +.PP +The \fB-B n\fP option controls the enforcement of load limits during fanout +optimization. A value of 0 ignores the load limits. A value of 1 takes +load limits into account. The default is set to 1. +This option is effective only in conjunction with fanout optimization. It is +implemented by artificially increasing the load at a gate output by a +multiplicative factor whenever the load exceeds the limit specified in the +library. The default multiplicative factor is 1000. This value can be changed +with the \fB-b n\fP option. There is a priori no reason to change this value. +.PP +The \fB-F\fP option performs fanout optimization. This disables the internal +fanout handling (i.e. forces \fB-f 0\fP). In order to recover area +after fanout optimization use the \fB-A\fP option. There are several fanout +optimization algorithms implemented in \fBSIS\fR. For details, type +\fBhelp fanout_alg\fR and \fBhelp fanout_params\fR. +.PP +The \fB-G\fP option recovers area after fanout optimization +at no cost in delay by resizing all gates in the network. +.PP +The \fB-W\fP option suppresses the warning messages. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +one_hot +.PP +Does a quick one-hot encoding of the current STG. +It assigns one-hot codes, minimizes the resulting PLA +using espresso, and returns the network to SIS. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +phase [-qgst] [-r n] +.PP +Decide for each node whether to implement the node or its complement +in order to reduce the total cost of the network. If the network is +mapped, the cost is the total area and the network will be kept mapped, +otherwise, the cost is the total number of inverters in the network +assuming all the inverters are already in the network. +At the end, all the necessary inverters are inserted into the network +and all the extra inverters are removed from the network. +.PP +The default algorithm, which can also be specified by \fB-q\fR option, is +a greedy algorithm called \fIquick phase\fR. The \fB-g\fR option uses +the Kernighan-Lin type algorithm called \fIgood phase\fR. The +\fB-s\fR option chooses the Simulated Annealing algorithm. The \fB-r n\fR +option chooses a random-greedy algorithm which does a random assignment first, +uses a greedy approach to get to a local minimum, and iterates +\fIn\fR times. If the \fB-t\fR option is specified, some tracing +information is printed as the assignment proceeds. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +plot_blif [-k] [-r] [-i] [-g WxH+X+Y] [-n name] +.PP +The \fBplot_blif\fR command +creates a window with an abstract representation of the +network, at its current level of optimization, labeling all nodes, including +primary inputs and outputs. +Vectors are used to show relationships between the various nodes. +Latches are not printed explicitly. +The network is drawn as an acyclic combinational circuit. +Labelled arrows indicate the locations of the latches. +.PP +The \fB-k\fR option "kills" (closes) the most recent plot window with +the current network name. +.PP +The \fB-r\fR option replaces the contents of an existing plot window +with the current network structure. +This is useful if the network has been modified since it was last +plotted. +If no plot window is open with the current network name, the command +has no effect. +.PP +The \fB-i\fR option forces a plot of the internal network structure +used by \fISIS\fP. +The default is to plot the structure corresponding to the write_blif +command. +The primary difference in the internal structure is in how primary +outputs are handled. +.PP +The \fB-g\fR option allows an initial geometry to be specified +for the plot window. +.PP +The \fB-n\fR option allows "name" to be used for the plot window name +instead of the network name. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +power_estimate [-m c] [-d c] [-t c] [-s c] [-a n] [-e f] [-n n] + [-f file] [-S] [-M n] [-N n] [-R] [-h] [-v] + +.PP +Estimates the power dissipated in a circuit due to switching activity: +.nf + P = 0.5 x Vdd^2 x sum(p x C ) / f + i i i +where + + Vdd = 5V + f = 20MHz + p = expected number of transitions of node i in one clock cycle + i + C = capacitive load of node i + i +.fi + +The expected number of transitions of each node per clock cycle is +calculated through symbolic simulation, based on the static +probabilities of the primary inputs (by default prob_one = prob_zero = +0.5). The capacitive load of a node is obtained by summing the gate +capacitances of its fanout nodes and adding some internal drain +capacitance. Gate capacitances are multiple of a minimum sized +transistor (0.01pF), admitting transistor sizing based on the number +of inputs to the node (up to a value max_input_sizing, default +4). Drain capacitances are calculated from the number of transistors +this node has (multiple of 0.005pF) and this number can be obtained +either from a factored form or sum of products. + +.PP +\fB-m c\fR Estimation mode, c either SAMPLING or BDD (default). + +.PP +\fB-d c\fR Delay model, c one of ZERO (default), UNIT or GENERAL (from +library). + +.PP +\fB-t c\fR Estimation type, c one of COMBINATIONAL (default), +SEQUENTIAL, PIPELINE or DYNAMIC (for dynamic domino circuits). + +.PP +\fB-s c\fR PS lines probability calculation method, c one of APPROXIMATE +(default), EXACT or UNIFORM (0.5 is used). Only used for SEQUENTIAL +type. + +.PP +\fB-a n\fR Number of PS lines to be correlated (default 1). Only used +for the APPROXIMATION method. + +.PP +\fB-e f\fR Maximum error allowed for PS lines probabilities (default +0.01). Only used for the APPROXIMATION method. + +.PP +\fB-n n\fR Number of sets of 32 input vectors to be simulated (default +100). Only used for SAMPLING mode. + +.PP +\fB-f filename\fR Allows the specification of input probabilities, node +capacitances and node delays in the format: + +.nf + name "nodename" p0 "value" + name "nodename" p1 "value" + name "nodename" cap_factor "value" + name "nodename" delay "value" +.fi + +.PP +\fB-S\fR Assumes complex gates in sum of products form (default is factored +form). + +.PP +\fB-M n\fR Maximum number of inputs of a node considered for transistor +sizing (default 4). + +.PP +\fB-N n\fR Interval of input vectors for which the current value of +power estimation is printed. Only used for SAMPLING mode. + +.PP +\fB-R\fR Sets latch capacitances to 0, only comb power reported. + +.PP +\fB-h\fR Prints power_estimate usage. + +.PP +\fB-V n\fR Verbose run time information. + +Note: currently a memory fault occurs on the RS6000 when the exact calculation +is used for present state probabilities. This is probably due to the use +of stg_extract. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +power_free_info + +.PP +Frees data structures storing capacitance and switching of every node in +the network. + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +power_print + +.PP +Prints the switching probability and capacitance for each node in the +network. Only valid after a power estimation has been performed. + + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print [-n] [-d] node-list +.PP +Print all the nodes in the \fBnode-list\fR in sum-of-product form. +.PP +If \fB-n\fR option is specified, the nodes are printed in +the negative form. (i.e. a' + b' will be printed as (a b)'). +.PP +If \fB-d\fR option is specified, the nodes in the external +don't care network are printed. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_altname node-list +.PP +Print the alternate name of all the nodes in the +\fBnode-list\fR. If the current name mode is \fIshort\fR (\fBSIS\fR +internal name), the alternate name will be the \fIlong\fR name +(user-specified name) and vice-versa. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_clock +.PP +Prints the clocking scheme associated with the current network. +The clocking scheme printed depends on the current setting +of the clock data structure (see \fB chng_clock\fR). +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_delay [-alrs] [-m model] [-p n] [-f file-name] [node-list] +.PP +Do a delay trace (static timing analysis) +on the network depending on the specified \fBmodel\fR +and print the delay data. +Without any arguments the routine will +use the \fIlibrary\fR model which assumes that the network is mapped and +will print the arrival times, required times and the slack for all the +nodes in the network. +.PP +Specifying an optional \fBnode-list\fR will print the delay data +only for the specified nodes. +.PP +The user can selectively have portions of the delay data printed. +The option \fB-a\fP will cause the arrival times to be printed. +The option \fB-r\fP will cause the required times to be printed. +The option \fB-s\fP will cause the slacks at nodes to be reported. +The option \fB-l\fP will cause the load driven by the node to be printed. +.PP +The option \fB-p n\fP when specified with one of the options \fB-[alrs]\fP +will print out the delay data so that the first \fBn\fP nodes with the +most critical values are printed. The critical portion of the delay data +is determined by the first of the options \fB-[alrs]\fP specified. +Thus specifying \fB-p n -[al]\fP prints the \fBn\fP nodes with the greatest +arrival-time/load. For the \fB-[rs]\fP option the nodes with the smallest +required-time/slack are printed. +.PP +The delay model can be specified by the \fB-m\fP option followed by one +of the following keywords --- \fIunit\fR, \fIunit-fanout\fR, +\fIlibrary\fR, \fImapped\fR or \fItdc\fR. +Specifying \fIunit\fR results in delay being computed as 1 unit per node in +the network. +\fIunit-fanout\fR adds an additional delay of 0.2 per fanout. +If a library has been read in using the \fBread_library\fP command one +can use more accurate models, \fImapped\fR and \fIlibrary\fR, by using data +stored in the library. Using the model \fIlibrary\fR assumes that the network +has been mapped. The \fImapped\fR model does not make this assumption and will +do a mapping of the nodes on an individual basis to compute a +delay model for use during the delay trace. +The \fItdc\fR model is an attempt to predict the delay of a node based on the +distribution of arrival times. The parameters used in this model prediction +are optionally specified using the \fB-f\fR option. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_factor node-list +.PP +Print all the nodes in the \fBnode-list\fR in the \fIfactored\fR form. +If a node has not beed factored, \fIfactor -q\fR will be used to +factor the node. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_gate [-ps] node-list +.PP +Prints the information provided in the library for the list of mapped +gates. +.PP +The \fB-p\fR option prints the pin information of the gates. +.PP +The \fB-s\fR option prints summary of the gates and their area. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_io [-d] [node-list] +.PP +Print both fanin and fanout list for each node in the \fBnode-list\fR. +Absence of \fBnode-list\fR implies all the nodes in the current network. +.PP +If the \fB-d\fR option is specified, the nodes in the external don't care +network are considered. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_kernel [-as] node-list +.PP +Print kernels and corresponding co-kernels of all the nodes in +the \fBnode-list\fR. If \fB-a\fR option (default) is specified, +all kernels, including the function itself if it is a kernel, are +printed. If \fB-s\fR option is specified, only +the sub-kernels are printed. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_latch [-s] [node-list] +.PP +With no arguments, \fBprint_latch\fR prints out information for +all the latches in the network. +The information printed for each latch is the latch input, latch output, +initial value, current value, synchronization type, and controlling node. +The latch values can be 0, 1, 2 (don't care), and 3 (undefined). + +If the \fB-s\fR option is specified, only the latch input, output, initial +and current values are given. +If a \fBnode-list\fR is given, only the latches associated with those +nodes are printed (each node should be a latch input or output). +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_level [-l] [-c] [-m model] [-t value] [node-list] +.PP +Prints the nodes of the network according to their level. +When called with a \fBnode-list\fR, only the nodes in the +transitve fanin of the specified nodes are printed. +The primary inputs are assigned level 0, and the level of +a node is the length of the longest path from it to a +primary input. The \fB -l\fR options prints only the +number of levels in the network. +.PP +If the \fB-c\fR option is specified, only critical nodes are +printed according to their level. The delay trace is done +according to the \fB-m model\fR option (default is the +unit-fanout model) and all the nodes with a slack within a +\fB-t value\fR of the smallest slack are considered to be +critical. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_library [-a][-f][-h][-l][-r] [function-string] +.PP +Print the contents of the current library. If the optional string is +given, only the combinational gates with the same logic function as the string +will be printed. \fIfunction-string\fP is in the format of +read_eqn. For example +.in +1i +.nf +print_library "f=!(a*b);" +.in -1i +.fi +will print all combinational gates with a NAND2 logic function. +.PP +The \fB-a\fP option prints asynchronous type latches matching the 'function-string'. +.PP +The \fB-f\fP option prints falling edge triggered flip-flops matching the 'function-string'. +.PP +The \fB-h\fP option prints active high transparent latches matching the 'function-string'. +.PP +The \fB-l\fP option prints active low transparent latches matching the 'function-string'. +.PP +The \fB-r\fP option prints rising edge triggered flip-flops matching the 'function-string'. + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_map_stats +.PP +Prints delay and area information of the network. The network should be mapped. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_state +.PP +Prints out the current state of the machine for both the STG +and the logic implementation. +For the logic implementation, the current state is printed as +a string of integers representing the values on the latches: +0, 1, 2 (don't care), and 3 (undefined). +For the STG, the current state is printed with its symbolic +and encoded names. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_stats [-f] [-d] +.PP +Print the current network status, which includes the network name, +number of primary inputs (pi), number of primary outputs (po), +number of nodes (nodes), the number of latches (latches), +the number of literals in the sum-of-product +form (lits(sop)), and the number of states in the STG +(#states(STG)). +.PP +If \fB-f\fR option is specified, the number of literals in +the factored form (lits(fac)) is computed. +This could be slow when +the factored form for some network takes too long to generate. +.PP +If \fB-d\fR option is specified, the statistics of the external don't care +network is printed. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +print_value [-a] [-d] [-p n] node-list +.PP +Print the value of all the nodes in the \fBnode-list\fR. The value +is currently defined as the number of literals increased if the node +were eliminated from the network. Since the value of a node depends +on the particular factored form of the node and its fanouts, all the +nodes which don't have factored forms will be factored using +\fIfactor -q\fR. +.PP +The \fB-a\fR option prints the values in ascending order. +.PP +The \fB-d\fR option prints the values in descending order. +.PP +The \fB-p\fR takes an argument \fBn\fR, and directs print_value to only +print the top n values. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +quit [-s] +.PP +Stop the program. Does not save the current network before exiting. +\fB-s\fP frees all the memory before quitting. This is slower, and +is used for finding core leaks or when \fIsis\fR is called from +another program. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +read_astg [<file-name>] +.PP +Read a text description of an Asynchronous Signal Transition Graph (ASTG). +The overall format follows the style of BLIF, and uses +an adjacency list to describe the net interconnection +structure. +If no filename is specified, the description is read from stdin. +.PP +All names in the ASTG description must start with a letter, +consist of letters, digits and underscores, and are case-sensitive. +A signal transition is represented with a suffix: "+" means a low +to high transition, "-" means high to low, "~" means toggles (changes +to the opposite value. +.PP + .model <model-name> +.br +This gives an arbitrary name to the ASTG, and it +must be the first line of the model description. +.PP + .inputs <signal-list> +.br +Specifies a list of names of ASTG input signals. +Signals from multiple .inputs are concatenated. +.PP + .outputs <signal-list> +.br +Specifies a list of names of ASTG output signals. +Signals from multiple .inputs are concatenated. +.PP + .internal <signal-list> +.br +Specifies a list of names of ASTG internal signals, i.e. +signals which are only used to maintain state information. +.PP + .dummy <name-list> +.br +Specifies a list of names which are accepted as dummy or null +transitions. +Null transitions are necessary to specify some behaviors using +the ASTG syntax. +By convention, the name "e" is used as a dummy signal (to +represent epsilon transitions). + .graph +.br +Indicates the lines which follow describe the ASTG net structure +using an adjacency list format. +This must follow all signal declarations (.inputs, etc.). +Net places are optional for simple constraints between two transitions; +in this case an intervening place is generated automatically. +Multiple instances of a transition are distinguished by following +them with a slash and a copy number. +For example, a second instance of transition "t+" can be +specified by "t+/2". +Copy numbers do not have to be consecutive. +.PP + .marking {<place-list>} +An initial marking can optionally be specified after the net structure +has been given. +Implied places (see .graph) between two transitions x* and y* can +be specified using the syntax <x*,y*>. + .end +This required line indicates the end of the ASTG description. +.PP +Error messages are printed for any unrecognized input sequences. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +read_blif [-a] filename +.PP +Read in a network from the file \fBfilename\fP which is assumed +to be in \fIblif\fP format. +The network name is given +by the \fI.model\fP statement in the file. If a \fI.model\fP +is not given, the network name is the filename with any trailing +extension removed. +See the blif.tex document for a complete description +of the \fIblif\fP format. +.PP +The user can also specify an external don't care network. This +network must be placed after the care network in the same +file. The statement \fI.exdc\fP must precede the description +of the external don't care network. The names of primary outputs and +primary inputs of the external don't care network +must be exactly the same as the names of primary outputs +and primary inputs of the care network. +.PP +Usual filename conventions apply: \fB-\fP (or no +filename) stands for standard input, and tilde-expansion is performed +on the filename. +.PP +Normal operation is to replace the current network with a new network. +If no external don't care network is specified, the external don't +care network is set to NIL (nonexistent). Otherwise the external +don't care network is replaced by the new external don't care network. +The -a option specifies that the new network should be appended to the +current network. Functions are associated between the two networks +using the long names of each network. Name conflicts (where two +functions attempt to define the same name) generate warning messages +and are resolved by renaming the signal from the new network. +.PP +The \fB-s\fR option, though accepted, has no effect on \fBread_blif\fR, and is +instead reserved for the \fBread_pla\fR command. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +read_eqn [-a] [filename] +.PP +Read a set of logic equations in the format expected by eqntott(1). +Each equation becomes a node in the logic network. +.PP +INORDER and OUTORDER can be used to specify the primary inputs and +primary outputs for the network. If neither is given, then primary +inputs are inferred from signals which are not driven, and +primary outputs are inferred from signals which do not have any +fanout. +.PP +The equations are of the form "<signal> = <expr> ;". +For reference, the equation format uses the operators: +.LP +.TS +.if \n+(b.=1 .nr d. \n(.c-\n(c.-1 +.de 35 +.ps \n(.s +.vs \n(.vu +.in \n(.iu +.if \n(.u .fi +.if \n(.j .ad +.if \n(.j=0 .na +.. +.nf +.nr #~ 0 +.if n .nr #~ 0.6n +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.fc +.nr 33 \n(.s +.rm 80 81 +.nr 80 0 +.nr 38 \w() +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \w!= (or ^) +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \w== +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \w!  +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \w& (or *) +.if \n(80<\n(38 .nr 80 \n(38 +.nr 38 \w| (or +) +.if \n(80<\n(38 .nr 80 \n(38 +.80 +.rm 80 +.nr 81 0 +.nr 38 \wgrouping +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wexclusive-or  +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wexclusive-nor +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wcomplement +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wboolean-and +.if \n(81<\n(38 .nr 81 \n(38 +.nr 38 \wboolean-or +.if \n(81<\n(38 .nr 81 \n(38 +.81 +.rm 81 +.nr 38 1n +.nr 79 0 +.nr 40 \n(79+(1*\n(38) +.nr 80 +\n(40 +.nr 41 \n(80+(3*\n(38) +.nr 81 +\n(41 +.nr TW \n(81 +.nr TW +1*\n(38 +.if t .if \n(TW>\n(.li .tm Table at line 3047 file Input is too wide - \n(TW units +.ne 6v+0p +.nr #I \n(.i +.in +(\n(.lu-\n(TWu-\n(.iu)/2u +.fc   +.nr #T 0-1 +.nr #a 0-1 +.nr #a 0-1 +.eo +.de T# +.ds #d .d +.if \(ts\n(.z\(ts\(ts .ds #d nl +.mk ## +.nr ## -1v +.ls 1 +.if \n(#T>=0 .nr #a \n(#T +.if \n(T. .vs \n(.vu-\n(.sp +.if \n(T. \h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.if \n(T. .vs +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|0'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v'\h'|\n(TWu' +.if \n(#a>=0 .sp -1 +.if \n(#a>=0 \h'|\n(TWu'\s\n(33\h'-\n(#~u'\L'|\n(#au-1v'\s0\v'\n(\*(#du-\n(#au+1v' +.ls +.. +.ec +.nr 36 \n(.v +.vs \n(.vu-\n(.sp +\h'|0'\s\n(33\l'|\n(TWu\(ul'\s0 +.vs \n(36u +.mk #a +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'()\h'|\n(41u'grouping +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'!= (or ^)\h'|\n(41u'exclusive-or  +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'==\h'|\n(41u'exclusive-nor +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'! \h'|\n(41u'complement +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'& (or *)\h'|\n(41u'boolean-and +.ta \n(80u \n(81u +.nr 31 \n(.f +.nr 35 1m +\&\h'|\n(40u'| (or +)\h'|\n(41u'boolean-or +.fc +.nr T. 1 +.T# 1 +.in \n(#Iu +.35 +.nr #a 0 +.TE +.if \n-(b.=0 .nr c. \n(.c-\n(d.-9 +As a simple extension to eqntott, juxtaposition of two operands stands +for boolean-and, and ' used as a post-fix operator stands for complement. +Hence, +.nf + F = a*!b + c*!d ; +.fi +and +.nf + F = a b' + c d' ; +.fi +represent the same equation. +.PP +Note that eqntott and \fBread_eqn\fR treat the intermediate nodes of a network +slightly differently. +\fBread_eqn\fR will not make an intermediate node +a primary output unless it also appears in the OUTORDER list. +Also, the resulting network is a multiple-level network with all +of the intermediate signals preserved. +Finally, eqntott is order-dependent in that it requires signals to +be defined before they can be used again; \fBread_eqn\fR relaxes this +condition. +.PP +The \fB-a\fR option specifies that the new network should be appended to the +current network. Functions are associated between the two networks +using the long names of each network. Name conflicts (where two +functions attempt to define the same name) generate warning messages +and are resolved by renaming the signal from the new network. +.PP +The \fB-s\fR option, though accepted, has no effect on \fBread_eqn\fR +and is instead +reserved for the \fBread_pla\fR command. +.pp +Note that since the characters '(' and ')' are used for grouping, +they cannot be part of a signal name. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +read_kiss [filename] +.PP +Reads a \fIkiss2\fP format file into a state transition graph. The state +names may be symbolic or strings of "0" and "1". Inputs and outputs should be +strings of "0", "1", and "-"; inputs should not be symbolic. +The \fIkiss2\fP format is described in doc/blif.tex. +Note that there is no mechanism for specifying the names of the +I/O pins in \fIkiss2\fP. +Naming can be done in \fBSIS\fP by specifying a \fIblif\fP +file containing the \fI.inputs\fP and \fI.outputs\fP lines +(which give I/O names) followed by the embedded \fIkiss2\fP +file. +See also \fBstg_to_network\fR, \fBread_kiss_net\fR. +.PP +Note that \fIread_kiss\fP followed by \fIwrite_kiss\fP alters the ordering of +the product terms. This could make a difference in the \fInova\fP +output. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +read_library [-ainr] filename +.PP +Read a \fBSIS\fR-format library for future technology mapping. +The \fB-a\fP option appends the library to the current library; +otherwise, any previous library is discarded. +The \fB-i\fP flag suppresses adding extra inverters to all of the +primitives. This is intended for debugging only. +The \fB-n\fP flag requests that a library, if it is generated, be +made using NAND gates rather than NOR gates. +The \fB-r\fP flag reads a raw library format (given in BLIF) +rather than the normal genlib format. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +read_oct cell[:view] +.PP +Read in a network from the Oct facet `cell:view:contents'. +If `view' is not specified, it defaults to `logic'. +The network name is set to `cell:view'. +Oct nets without names are given machine-generated unique names. +All primary inputs and outputs are named the same as the equivalent +Oct formal terminals of the facet. +.PP +This operation replaces the current network with the new network. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +read_pla [-a] [-s] [-c] filename +.PP +Read in an espresso-format PLA from the +file \fBfilename\fP (see espresso(5) for more +information). The network name is derived +from the filename with any trailing extension removed. +.PP +Usual filename conventions apply: \fB-\fP (or no +filename) stands for standard input, and tilde-expansion is performed +on the filename. +.PP +Normal operation is to replace the current network with a single-level +network of complex gates with the same logic functions as the PLA outputs. +This makes each PLA output a separate single-output function and is +a good starting point for the standard scripts. +If don't care conditions exist, the external +don't care network is also replaced with a single-level network +which implements the don't care conditions of the PLA. +Otherwise, the external don't care network is set to NIL (nonexistent). +.PP +The \fB-c\fP option replaces the current network with +a two-level network of NOR-gates (and inverters) +which implements the PLA. +This preserves the multiple-output nature of the PLA. +The external don't care network is manipulated exactly the same as above. +This used to be the default, while the \fB-s\fP option +replaced the network with a single-level network as described above. +The \fB-s\fP option has been retained for compatibility. +.PP +The \fB-a\fR option specifies that the new network should be appended to the +current network. +Functions are associated between the two networks +using the long names of each network. +Name conflicts (two +functions attempt to define the same name) generate warning messages +and are resolved by renaming the signal from the new network. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +read_slif filename +.PP +Read in a network from the file \fBfilename\fP which is in \fIslif\fP +format. \fISLIF\fP is a hierarchical circuit description language and the +root network, the one returned to the caller, is defined to be the first +network encountered in the file \fBfilename\fP. + +.XX +red_removal [-hqrRpt] [-d RTG_depth] [-n n_fault_sim] [-v verbosity_level] + [-y random_prop_depth] +.PP +Perform sequential redundancy removal using random test generation, +deterministic test generation, and fault simulation. Deterministic test +generation is accomplished by one of two methods. The first method is a +three-step test generation algorithm consisting of combinational test +generation (assuming that latch outputs are controllable, and that latch +inputs are observable), followed by state justification and propagation, +when necessary. The combinational test generation is accomplished using +Boolean satisfiability. Justification and propagation are performed using +implicit state transition graph traversal techniques. If the three-step +method does not generate a test for a fault, then the product of the good +and faulty circuit is built and traversed, as in sequential circuit +verification. If this traversal proves the circuits equivalent, then the +fault is redundant; otherwise any differentiating sequence is a test for +the fault. +.PP +Each time a redundant fault is encountered during deterministic test +generation, the redundant line is replaced by a constant 1 or 0, and +deterministic test generation begins again. At the end of the redundancy +removal procedure, the network is 100% testable for single stuck faults +unless the test generator aborts on some faults. +.PP +For combinational circuits, external don't cares are automatically taken +into account when the don't care network is attached to the care network. The PI's and PO's of the external don't care network (when it is not NIL) must match exactly with the care network. That is, the don't care network cannot specify only a subset of the PI's or PO's of the care network. If this +condition is not met, then the atpg package automatically adds dummy primary +inputs and outputs to the external don't care network. +.PP +The \fB-h\fP option restricts the boolean satisfiability algorithm to not +use non-local implications. Four greedy ordering heuristics are tried in +this case instead of the default of eight. Hard-to-test faults that can only +be tested with non-local implication information are aborted by this option. +.PP +The \fB-q\fP specifies "quick redundancy removal." With this option, the +deterministic test generation algorithm identifies only those redundant faults +that cannot be excited from any reachable state. In practice, quick redundancy +removal usually gives the same results as regular redundancy removal, in much +less time. +.PP +The \fB-r\fP option causes the test generator not to perform random test pattern +generation. +.PP +The \fB-R\fP option causes the test generator not to perform random propagation. +(Deterministic propagation is still attempted). +.PP +The \fB-p\fP option causes the test generator not to build any product +machines. Thus, neither deterministic propagation nor good/faulty product +machine traversal will be performed. +.PP +The \fB-t\fP option first converts the network to arbitrary fanin AND and +OR gates. The decomposed network is returned. +.PP +The \fB-d\fP option allows the specification of the length of the random +sequences applied during random test generation. The default length is +the depth of the circuit's state transition graph. +.PP +The \fB-n\fP option allows the specification of the number of sequences +to fault simulate at one time during fault simulation. The default is the +system word length. +.PP +The \fB-v\fP allows the specification of the verbosity level of the output. +.PP +The \fB-y\fP option allows the specification of the length of the random +sequences applied during random propagation. The default length is 20. +.PP +Note: in order to use this command with sequential circuits, the circuit +reset state must be specified in the circuit input file. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +reduce_depth [-b] [-d #] [-g] [-r] [-s #] [-v #] [-R #.#] [-S #] [-f #] +.PP +This command is to be used to improve the speed of a network before +technology mapping. It performs a partial collapse of the network by +first clustering nodes according to some criteria and collapsing each +cluster into a single node. The clusters are formed as follows: a +maximum cluster size is first computed, and the algorithm finds a +clustering that respects this size limit and minimizes the number of +levels in the network after the collapsing of the clusters. The size +limit is a limit on the number of nodes covered by the cluster, and +does not take into account the complexity of the nodes. Therefore this +command should only be used on networks decomposed into simple gates. +The cluster size limit can be provided in a variety of ways, +depending on which option is used. +.PP +The \fB-b\fP option performs the clustering under the duplication ratio +constraint specified by \fB-R\fP option. +.PP +The \fB-d #\fP option specifies the desired depth of the network after +clustering. The depth counts the number of nodes. Since each node +is expressed as a sum-of-products, specifying depth of 1 corresponds +to collapsing the network to two levels of logic. The algorithm +computes the minimum cluster size limit that yields a depth of \fBn\fR. +.PP +The \fB-g\fP option prints out statistics based on cluster sizes. No +clustering is done. +.PP +The \fB-r\fP option specifies a modification of the clustering +algorithm that produces the same number of logic levels but with less +duplication of logic. +.PP +The \fB-s #\fP option specifies the desired cluster size limit. +.PP +The \fB-v #\fP option specifies a verbosity level. It is used mainly for +debugging. +.PP +The \fB-R #.#\fP option specifies the maximum duplication ratio. The default is 2.0. +.PP +The \fB-S #\fP option specifies the smallest cluster size limit that +produces the same depth as a cluster size limit of \fBn\fR. +.PP +The \fB-f #\fP option specifies a cluster size limit in terms +of the number of fanins of the cluster. Its intended use is +for table-lookup FPGAs. It is a poor man's version of FlowMap. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +remove_dep [-o] [-v n] input output-list +.PP +The first node passed as argument should be an external primary input. +The remaining nodes passed as arguments should be external primary outputs. +This command assumes that the dependency between the given input +and the given outputs is structural but not logical, and it removes +these structural dependencies by forcing the input at 0 in the cone +of logic going from the input to the listed outputs. +.PP +The logic that depends on the given input and is shared with outputs +not passed as arguments is duplicated. +.PP +This function is useful when performing hierarchical optimization, +to guarantee that sis does not introduce dependencies that will create +combinational logic loops when the hierarchy is reassembled. +.PP +\fB-v\fR allows the specification of the verbosity level of the output. +The default value is 0. +.PP +With option \fB-o\fR the constant 1 is used instead of the constant 0 +to replace the input. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +remove_latches [-v n] [-f n] [-r] [-b] +.PP +This command removes redundant latches, using three different techniques. +.PP +First, it performs some local retiming, by moving forward latches +across combinational logic if that decreases the latch count. This +optimization can be disabled by specifying the option \fB-r\fR. +.PP +Second, it looks for boot latches, that is latches fed by a constant +but initialized at the opposite value. If there are such latches, it +looks for a state equivalent to the initial state in which the initial +value of the latch is equal to the value of its constant input. When +this optimization applies, the latch can be removed, and constant +folding propagates the constant across the logic. This optimization +can be disabled by specifying the option \fB-b\fR. +.PP +Third, it computes the set of reachable states, and checks whether +some latches cannot be deduced combinationally from other latches. +If that is the case, and if the fanin limit specified by the \fB-f\fR +option is not exceeded, the latch is removed and replaced by +combinational logic. +.PP +\fB-v\fR allows the specification of the verbosity level of the output. +The default value is 0. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +replace [-t n] [-v n] +.PP +This is a simple routine that performs the same function as +\fBresub -a -d\fR on a network decomposed in 2-input NAND gates +using \fBtech_decomp -o 2\fR. It is just much faster. +.PP +The \fB-v n\fP specifies the verbosity level. +It is only used for debugging. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +reset_name [-ls] +.PP +Resets either the short names (starting again from the single letter a) +with the \fB-l\fP option, or the \fBSIS\fR-generated +long-names (starting again from [0]) with the \fB-s\fP option. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +resub [-a] [-b] [-d] [node-list] +.PP +Resubstitute each node in the \fBnode-list\fR into all the nodes in the network. +The resubstitution will try to use both the \fIpositive\fR and \fInegative\fR +phase of the node. If \fBnode-list\fR is not specified, the resubstitution +will be done for every node in the network and this operation will keep +looping until no more changes of the network can be made. Note +the difference between \fBresub *\fR and \fBresub\fR. The +former will apply the resubstitution to each node only once. +.PP +The \fB-a\fR (default) option uses algebraic division when +substituting one node into another. +The division is +performed on both the divisor and its complement. +.PP +The \fB-b\fR option uses Boolean division when substituting one +node into another. +NOTE: Boolean resubstitution has not yet been implemented. +.PP +The \fB-d\fR option directs \fBresub\fR not to use the complement of a given +node in algebraic resubstitutions. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +retime [-nfim] [-c #.#] [-t #.#] [-d #.#] [-a #.#] [-v #] +.PP +Applies the retiming transformation on the circuit in an +effort to reduce the cycle time. The retiming operation is +supported only for single phase, edge-triggered designs. Both +mapped and unmapped networks can be retimed. +The algorithm attempts to maintain the initial state information. +.PP +The algorithm expects to work on mapped networks so that accurate +delays on the gates can be used. +However, an unmapped network can be retimed by using +the \fB-n\fR option. +In that case the delay through +each node is computed according to the \fIunit-fanout\fR delay model. +\fIThe user should be aware of the fact that when retiming circuits +containing complex registers (JK, D-flip flops with enables/presets), +the complex registers may have to be decomposed into simpler gates.\fR +.PP +By default the algorithm uses a relaxation based approach which +is very fast. An alternate formulation uses a mathematical +programming formulation and can be selected using the \fB-f\fR option. +After profiling on a number of circuits only one will be retained. +.PP +The \fB-m\fR option can be used to minimize the number of registers +under cycle time constraints. If the cycle time is not specified +using the \fB-c\fR option then this command will try to minimize the +cycle time. Thus to obtain the absolute minimum number of registers +for a circuit the user should specify a very loose cycle time constraint +(very large value for the \fB-c\fR option). +.PP +The retiming algorithm will try to compute the new initial states +of the latches. +In case no feasible initial state exists the retiming is aborted and +the network is not modified. To suppress the initialization routine +use the \fB-i\fR option. In that case the initial values for all the +latches after retiming is set to value of 2 (DONT_CARE). +.PP +The desired clock period can be specified with the \fB-c value\fR +option. When this option is not used the algorithm first checks to see +if there is a cycle_time specification with the current network (the +value depends on the current setting of the clock_flag in the network) +and tries to meet this. If no cycle_time is specified with the design +the retiming operation tries to minimize the cycle time. For this it +uses a binary search for testing feasible clock values. The tolerance of +the binary search can be specified with the \fB-t value\fR option (the +default is 0.1). +.PP +Latches in the network can be assigned a propogation delay and an +area. These are helpful in the realistic modelling of the circuit +delay and area. Use the \fB-d value\fR option to specify the delay +through a latch (to approximate the setup and propogation delay of +the latch) and the \fB-a value\fR option to specify the area +of a latch. In case of mapped networks, these values are automatically +determined from the library of gates. +.PP +The \fB-v value\fR selects the verbosity level. The range is 1-100 +(100 will literally swamp you with a lot of unneeded data). Use +the value 1 to see the progress of the algorithm. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +save filename +.PP +Save a copy of the current executable to a file which can be restarted. +This can be used to freeze the current network or the current library +for later optimization. When the executable \fBfilename\fR is executed, +execution returns to the top-level of the command interpreter. +.PP +NOTE: The \fBsave\fR command is very operating-system dependent and may not +be implemented on your system. +If this is the case then the \fBsave\fR +command is unusable on your system. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +set [name] [value] +.X1 +unset name ... +.PP +A variable environment is maintained by the command interpreter. +The \fBset\fR command sets a variable to a particular value, and the +\fBunset\fR command removes the definition of a variable. +If \fBset\fR is given no arguments, it prints the definition of all variables. +.PP +Different commands use environment information for different purposes. +The command interpreter makes use of the following: +.TP 8 +.B autoexec +Defines a command string to be automatically executed after every command +processed by the command interpreter. +This is useful for things like timing +commands, or tracing the progress of optimization. +.TP 8 +.B sisout +Standard output (normally stdout) can be re-directed to a file +by setting the variable sisout. +.TP 8 +.B siserr +Standard error (normally stderr) can be re-directed to a file +by setting the variable siserr. +.TP 8 +.B history +Each valid command entered at the prompt can be echoed to a file +by setting the variable history. +.TP 8 +.B history_char +By default the character `%' is used to do the history substitution +inside sis. This can be changed by setting the variable \fBhistory_char\fR. +.TP 8 +.B shell_char +By default the character `!' is used to do invoke shell commands from +inside sis. This can be changed by setting the variable \fBshell_char\fR. +\fI In order to switch the interpretation of shell_char and history_char it is +neccessary to first set history_char and then the shell_char. Alternately, +you may escape the current history char by preceeding it with +a `\' while setting the shell_char. In addition none of them can be set +to a `#' which is reserved for comments.\fR +.TP 8 +.B filec +Setting this variable enables the user to use "file-completion" like in +the C-shell. An ESC causes the current line to be extended to its unique +completion. A CTRL-d generates a list of the possible extensions. +.TP 8 +.B open_path +\fBopen_path\fR (in analogy to the shell-variable PATH) is a list of +colon-separated strings giving directories to be searched whenever +a file is opened for read. Typically the current directory (.) is +first in this list. The standard system +library (typically $SIS/sis_lib) is always implicitly appended +to the current path. +This provides a convenient short-hand +mechanism for reaching standard library files. +.TP 8 +.B prompt +defines the prompt string. If the prompt string contains a `%'(or whatever +the history_char has been set to using the set command), the `%' +will be replaced whenever the prompt is printed by the current event number. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +set_delay [-a|d|i|l|r f] [-A f] [-D f] [-I f] [-L f] [-R f] [-S f] [-W f][o1 o2 ... | i1 i2 ...] +.PP +Set various delay parameters for the inputs and outputs of a network. +These timing constraints are used by the \fBprint_delay\fP command in +addition to commands like \fBspeed_up\fR, \fBbuffer_opt\fR, and \fBmap\fR +that perform +delay optimizations. The values for these constraints are numbers and it +is the user's responsibility to ensure that these values are meaningful +when a particular delay model is used during the optimizations. +Capitalized options set defaults, lower-case options set the +parameters for the nodes in nodelist, which is either a list of output +nodes or a list of input nodes. +.PP +The option \fB-A\fP sets the default arrival time for primary inputs +to the real value \fBf\fR. +The option \fB-R\fP sets the default required time for primary +outputs to \fBf\fR. +The \fB-D\fP option sets the default drive on a primary +input to \fBf\fR, and the \fB-L\fP option sets the default load on primary +outputs to \fBf\fR. +The \fB-I\fR option specifies the default value for the +maximum load that can be present at a primary input. The \fB-S\fP option +sets the wire load per fanout to \fBf\fR. +The wire loads for a given number of fanouts can be specified +with the \fB-W\fP option. With the \fIi\fPth use +of the \fB-W\fP option, the load for a gate driving \fIi\fP outputs is set +to the value \fBf\fR. +.PP +The settings can be undone by using a negative number for the value. +This will result in the parameter to be "unspecified" and the +individual commands will use appropriate defaults if neccessary. +.PP +The \fB-a, -r, -d, -i\fP, and \fB-l\fR options can be used to specify the +delay constraints on specific nodes (as opposed to the uppercase options +which specify a default value for ALL terminals). These terminal-specific +values will supersede the defaults specified with the uppercase options. +The \fB-a (-r)\fP option sets the arrival (required) time to \fBf\fR for the +specified nodes if the node list +given is a list of primary inputs (outputs). +The \fB-d (-i)\fP option sets the drive (maximum load limit) for each node in +the list to \fBf\fR; +if there is a non-primary input in the list this is an error. +The \fB-l\fP option sets the load on each node in the list to \fBf\fR; if there +is a non-primary output in the list this is an error. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +set_state [-s] [-i] [name] +.PP +Sets the current state in the machine to the given state. +If no +state is given, it sets the current state to the initial state (resets +the machine). +If the \fB-s\fR option is given, only the state of the +STG is changed; if the \fB-i\fR option is specified, only the state of the +logic implementation is changed. If no logic implementation exists, +or if only the state of the STG is to be changed, then the state name +should be symbolic; otherwise it should be the encoded name of the state. +.XX +short_tests [-fFhirtV] [-v verbosity_level] file +.PP +Perform test generation for sequential circuits with the goal of +producing small test sets. Random test generation is not used unless +its use is specified by the user. Deterministic test generation is +accomplished by one of two methods. The first method is a three-step test +generation algorithm consisting of combinational test generation (assuming +that latch outputs are controllable, and that latch inputs are observable), +followed by state justification and propagation, when necessary. The +combinational test generation is accomplished using Boolean satisfiability. +Justification and propagation are performed using implicit state transition +graph traversal techniques. If the three-step method does not generate a +test for a fault, then the product of the good and faulty circuit is built +and traversed, as in sequential circuit verification. If this traversal +proves the circuits equivalent, then the fault is redundant; otherwise any +differentiating sequence is a test for the fault. Fault simulation is +performed after each deterministic test generation. +.PP +Fault collapsing is performed before test generation, across only simple +gates. Both fault equivalence and fault dominance are used to reduce the +fault list. +.PP +Deterministically-generated tests may start from the circuit reset state +or a state reached by the application of another test. In the latter case, +the new test is appended onto the end of the old test. +.PP +Reverse fault simulation is performed as a post-processing step to reduce +test set size. +.PP +The \fB-f\fP option causes the test generator not to perform fault simulation +of deterministically-generated tests on untested faults. +.PP +The \fB-F\fP option causes the test generator not to use reverse fault +simulation. +.PP +The \fB-h\fP option restricts the boolean satisfiability algorithm to not use +non-local implications. Four greedy ordering heuristics are tried in this case +instead of the default of eight. Hard-to-test faults that can only be tested +with non-local implication information are aborted by this option. +.PP +The \fB-i\fP option causes the test generator not to append new tests onto +the end of old tests. +.PP +The \fB-r\fP option causes the test generator to perform random test pattern +generation and random propagation. +.PP +The \fB-t\fP option first converts the network to arbitrary fanin AND and +OR gates. The decomposed network is returned. +.PP +The \fB-v\fP allows the specification of the verbosity level of the output. +.PP +The \fB-V\fP causes the test generator to not use the three-step algorithm +to generate tests. Instead, only good/faulty product machine verification +is used to generate tests, thus guaranteeing that each individual test +generated is the shortest possible. +.PP +If \fBfile\fP is specified, test patterns are written out to the given file. +.PP +Note: in order to use this command with sequential circuits, the circuit +reset state must be specified in the circuit input file. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +sim_verify [-n # pats] filename.blif +.PP +Verify that two networks are equivalent using random-pattern +simulation. That is, generate a random input vector, simulate the +logic network, and check that the outputs between the two networks +agree. The first network is the current network, and a second +network is read from the file \fBfilename.blif\fR: +it must be a \fIblif\fR format file. +(This restriction will be fixed when the command interpreter is +expanded to handle multiple networks.) +.PP +\fB-n\fP gives the number of random patterns to simulate. +.PP +NOTE: this command only works for combinational networks. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +simplify [-d][-i <num>[:<num>]] [-m method] [-f filter] [node-list] +.PP +Simplify each node in the \fBnode-list\fR using +\fImethod\fR with the don't-care set generated according to +\fIdctype\fR. +.PP +\fImethod\fR specifies the algorithm used to minimize the nodes. +\fIsnocomp\fR (default) invokes a single pass minimization procedure that does +not compute the complete offset. +\fInocomp\fR invokes the full minimization procedure (ala ESPRESSO) but does +not compute the complete offset. +\fIdcsimp\fR invokes single pass tautology-based minimizer. +.PP +\fIdctype\fR specifies how the don't-care set is generated. +The default don't care set generated is a subset of the fanin don't care set. +\fB-d\fR option specifies that no don't care set is used. +\fB-i m:n\fR specifies that the fanin don't cares of nodes within +\fBm\fR levels of transitive fanin and \fBn\fR levels of transitive fanout +of these transitive fanin are to be generated. +.PP +\fIfilter\fR specifies how the don't-care set is filtered. +\fIexact\fR (default) uses the exact filter. +\fIdisj_sup\fR uses the disjoint support filter. +.PP +Note that a node function is replaced with the simplified version +if the new function has fewer literals in factored form. +In the case of a tie, the node function is replaced if the new function +has fewer literals in sum-of-products form. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +simulate in1 in2 in3 ... +.PP +For the current implementation of the network, given a value ('0' or '1') +for each of the primary inputs of the network, simulate prints the value +produced at each of the primary outputs. The correspondence of the +input values and the primary inputs can be determined by the order in +which the primary inputs and outputs are printed using the \fBwrite_eqn\fR +command. +.PP +For example, for a three-input AND gate, the command + +\fB simulate 1 1 0\fR + +will produce a + + 0 +.PP +NOTE: For sequential circuits, this command essentially assumes that all +latches are clocked simultaneously by a single clock. +Simulation will take the current values on the latches (which can be +displayed by using \fBprint_latch\fR) and the user-supplied primary +input values +and simulate the network, placing the new latch values in the +current state of the latches. +The values of the outputs and the new state are printed. +If a more sophisticated simulation method is needed, timing simulation +should be used; this is not currently implemented in SIS. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +source [-psx] filename +.PP +Read commands from a file. The \fB-p\fP option prints a prompt before +reading each command, and the \fB-x\fP option echoes each command before +it is executed. The \fB-s\fP option silently ignores an attempt to execute +commands from a nonexistent file. +.PP +Arguments on the command line after the filename are remembered but not +evaluated. Commands in the script file can then refer to these arguments +using the history substitution mechanism. +.PP +EXAMPLE: +.IP +Contents of test.scr: +.IP +.nf + read_blif %:2 + collapse + write_eqn %:2.eqn +.fi +.IP +Typing "source test.scr lion.blif" on the command line will execute the +sequence +.IP +.nf + read_blif lion.blif + collapse + write_eqn lion.blif.eqn +.fi +.IP +If you type "alias st source test.scr" and then type "st lion.blif bozo", you +will execute +.IP +.nf + read_blif bozo + collapse + write_eqn bozo.eqn +.fi +.IP +because "bozo" was the second argument on the last command line typed. In +other words, command substitution in a script file depends on how the script +file was invoked. +.PP +Some standard script files are provided. \fIscript\fR (executed by typing +\fBsource script\fP is a script that works well on most examples. +\fIscript.boolean\fR uses a larger part of the don't care set during two-level +minimization, requiring more time and producing better results. +\fIscript.algebraic\fR uses a smaller part of the don't care set. +\fIscript.rugged\fR uses the newest BDD-based techniques, +and \fIscript.delay\fR synthesizes a circuit for a final +implementation that is optimal with respect to speed. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +speed_up [-m model] [-d #] [-w #] [-t #.#] [-i] [-c] [-T] [-a #] [-vD] node-list +.PP +Speed-up the nodes in the \fBnode-list\fR. If no nodes are +specified, it selects the nodes to be speeded-up in order to +speed-up the entire network. The best decomposition seen +so far is accepted (except with the \fB-c\fR flag). The network +after running speed_up is composed of 2-input AND gates and inverters. +.PP +The \fB-m model\fR option selects the delay model according to +which the delay data is computed. The values allowed for +\fBmodel\fR are \fIunit\fR, \fIunit-fanout\fR and \fImapped\fR. +The \fIunit\fR +delay model counts the level of the circuit as its delay. +The \fIunit-fanout\fR model is intended to capture +a technology-independent model and it assigns a delay of 1 unit to each +gate and 0.2 units to each fanout stem. The \fImapped\fR delay +model uses the delay data in the library to compute delay. +.PP +The \fB-d #\fR option selects the distance up to which the +critical fanins are collapsed in order to do the speed-up. +A fast value is 3, a good one is 6. +.PP +The \fB-t #.#\fR option determines which nodes are considered +critical. The critical nodes are those with a slack within +#.# of the most negative slack. +.PP +The \fB-w #\fR option selects between the area mode and the +pure timing mode. A value of 0 selects pure-timing mode +while a value of 1 will conserve as much area as possible. +.PP +The \fB-i\fR option specifies that only the initial 2-input +NAND decomposition be carried out. +.PP +The \fB-c\fR option specifies that one pass be carried out. +The new decomposition is always accepted, even if it results +in a slower circuit. +.PP +The \fB-T\fR option displays the delay as the iterations progress. +.PP +The \fB-a #\fR option tries to do the specified number of attempts +when restructuring a node. By default the algorithm tries only +one attempt at the restructuring. This option is for experimental +use at this stage. +.PP +The \fB-v\fR and \fB-D\fR options display debugging information. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: +.\" * $Author: +.\" * $Revision: +.\" * $Date: +.\" * +.\" +.XX +speedup_alg [-v] alg_list +.PP +Activates selectively one or more performance enhancing algorithms. For a +list of local optimizations known to the system, use the \fB-v\fR option. +The algorithms activated are the ones specified in the list. +For mapped circuits the algorithms perform the optimization and remap +the sub-network that was optimized. \fInoalg\fR performs no +optimization, it only remaps the region. \fIfanout\fR builds a +fanout-tree while \fIrepower\fR simply uses a gate of greater drive +Of the others \fIdivisor\fR and \fI2c_kernel\fR +perform restructuring by extracting kernels and 2-cube divisors. When +applied to the complement of the function these are called +\fIcomp_div\fR and \fIcomp_2c\fR respectively. Techniques based on the +existing structure are \fIcofactor\fR which performs +timing-driven-cofactoring and \fIbypass\fR applies the +generalized-bypass transformation. +.PP +Performance optimization itself is performed using the \fBspeed_up\fR +command without the \fB-f\fR option. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +state_assign progname options +.PP +Perform state assignment on the current STG. +The program used for state assignment is \fBprogname\fP +and it is given the options \fBoptions\fP. +The program \fBprogname\fP must exist somewhere in the user's +path. +.PP +The state assignment program is given the current STG, and +returns a logic implementation. After execution of the \fBstate_assign\fP +command, both the STG and the logic implementation are available +for optimization. +.PP +The state assignment program called must conform to the +specification (see doc/SPEC). +Currently, the programs that are compatible with this specification +and are shipped with SIS are nova and jedi. +To get help information for a specific program, use the -h option +(i.e. \fBstate_assign nova -h\fP would produce help information for +the nova state assignment program). +.PP +A one-hot encoding can be obtained by using \fBstate_assign progname -e h\fP. +Note that nova and jedi produce different results for one-hot encoding. +jedi produces typical one-hot codes (1000) while nova produces one-hot +codes with don't care conditions (1---). +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +state_minimize progname options +.PP +Perform state minimization on the current STG. +The program used for state minimization is \fBprogname\fP +and it is given the options \fBoptions\fP. +The program \fBprogname\fP must exist somewhere in the user's +path. +.PP +The state minimization program is given the current STG, and +returns a new STG. After execution of the \fBstate_minimize\fP +command, only the STG is available for optimization (any existing +logic implementation is removed, since there is no guarantee that +it implements the new STG). +.PP +The state minimization program called must conform to the +specification (see doc/SPEC). +Currently, the program that is compatible with this specification +and is shipped with \fBSIS\fR is \fBstamina\fR (from the University of Colorado, +Boulder, rho@boulder.colorado.edu). +To get help information for a specific program, use the \fB-h\fR option +(i.e. \fBstate_minimize stamina -h\fP would produce help information for +the \fBstamina\fR state minimization program). +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +stg_cover +.PP +Check to see that the behavior of the STG covers +that of the logic implementation. +This operation is provided for the user to check that +two descriptions of the same machine are consistent. +Each edge in the STG is symbolically simulated in the +logic implementation to ensure that the logic implementation +behaves as specified by the STG. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +stg_extract [-a] [-e] [-c] +.PP +Takes the current network and extracts the state transition graph from it. +.PP +If the \fB-a\fP option is not specified, the values on the latches are taken +to be the start state, and every state reachable from the +start state is explored. This is the normal method of execution. +.PP +If the \fB-a\fP option is specified, the state transition graph is extracted +for all possible start states, provided the number of latches does not +exceed 16. This limitation cannot be overridden (there are too many +states to store). +.PP +Extraction of the STG could take an enormous amount of time. +If there are more than 16 latches in the network, \fBstg_extract\fR won't +attempt to extract the STG. +This can be overridden with the \fB-e\fP option. +.PP +At the end of \fBstg_extract\fR, a check is done to ensure that +the behavior of the STG is consistent with that of the logic implementation. +This is done with symbolic simulation using BDDs, and could be expensive. +\fBstg_extract\fR will not do this check for networks with more than +16 latches or more than 500 transitions unless the \fB-c\fR option is given. +.PP +Note: a \fBsweep\fI is done on the network before the STG is extracted. +This removes latches that do not fanout, so the sweep makes the extraction +more efficient. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +stg_to_astg [-v debug_level] +.PP +Transforms the current State Transition Graph (that must satisfy the +Single Cube Restriction, see \fBastg_stg_scr\fR) into a Signal Transition +Graph. +.PP +Can be used to transform a burst-mode +Flow Table specification (written in .kiss format +and read using \fBread_kiss\fR) of an asynchronous circuit into a Signal +Transition Graph for subsequent encoding and synthesis (see +\fBastg_state_min\fR, \fBastg_to_f\fR and \fBastg_syn\fR). +.PP +Burst mode means that the circuit specified by the Flow Table may change state +only after all signals in a specified set (a "burst") have changed value. Many +bursts can occur from a given state, but no burst can be a subset of another +burst from the same state (or else meta-stability can occur). +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +stg_to_network [-e option] +.PP +Takes the current state-encoded state transition graph and generates +an optimized two-level logic network. The initial mapping is optimized +using a two-level Boolean minimizer (i.e. \fBespresso\fR) +along with the invalid +state codes as don't cares. +\fB-e\fR allows the user to specify how +the two-level logic-encoded network should be processed using \fBespresso\fR. +The option can be +either 0, 1, or 2. +The \fB-e 0\fR option simply runs espresso and executes \fBread_pla\fR. +The \fB-e 1\fR option runs \fBespresso\fR, but does a +\fBread_pla -s\fR instead. +This reads in the PLA in single-level form (fully collapsed) rather than +two-level form. +This often produces better results. +The \fB-e 2\fR option +runs \fBespresso -Dso\fR, which does a single-output minimization. +Again, \fBread_pla -s\fR is used. +This option also produces better results for some +cases, but typically takes more time. +The default is the \fB-e 1\fR option. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +sweep +.PP +Successively eliminate all the single-input nodes and constant nodes +(0 or 1) from the current network. +.PP +NOTE: Successfully invoking a sweep command on a mapped network can +possibly "unmap" the network. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +tech_decomp [-a and-limit] [-o or-limit] +.PP +Decompose all the nodes in the current network into AND gates +or OR gates or both depending on whether \fB-a\fR, +\fB-o\fR, or both flags are specified. +The fanins of AND gates +will be no more than \fBand-limit\fR and that of the OR gates +will be no more than \fBor-limit\fR. \fBand-limit\fR and +\fBor-limit\fR, if specified, must be at least 2. +The default option is \fB-a 2\fR. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +time +.PP +Prints the processor time used since the last time command, and the total +processor time used since \fBSIS\fR was started. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +timeout [-t n] [-k] +.PP +Sends an interrupt to the \fBSIS\fR process. With no argument, this +routine inactivates any previous calls. +.PP +The \fB-t n\fP specifies the timeout limit, in seconds. +.PP +The \fB-k\fP option specifies that a kill signal is to be sent to +\fBSIS\fR rather than a interrupt signal. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +alias [name [string]] +.X1 +unalias name ... +.PP +The \fBalias\fR command, if given no arguments, will print the +definition of all current aliases. +Given a single argument, it +will print the definition of that alias (if any). +Given two +arguments, the keyword \fBname\fP becomes an alias for +the command string \fBstring\fP, replacing any other alias with the +same name. +The \fBunalias\fR command removes the definition of an alias. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +undo +.PP +A simple 1-level undo is supported. +It reverts the network to its state +before the last command which changed the network. +Note that interrupting +a command (with ^C) which changes the network +uses up the one level of undo. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +set [name] [value] +.X1 +unset name ... +.PP +A variable environment is maintained by the command interpreter. +The \fBset\fR command sets a variable to a particular value, and the +\fBunset\fR command removes the definition of a variable. +If \fBset\fR is given no arguments, it prints the definition of all variables. +.PP +Different commands use environment information for different purposes. +The command interpreter makes use of the following: +.TP 8 +.B autoexec +Defines a command string to be automatically executed after every command +processed by the command interpreter. +This is useful for things like timing +commands, or tracing the progress of optimization. +.TP 8 +.B sisout +Standard output (normally stdout) can be re-directed to a file +by setting the variable sisout. +.TP 8 +.B siserr +Standard error (normally stderr) can be re-directed to a file +by setting the variable siserr. +.TP 8 +.B history +Each valid command entered at the prompt can be echoed to a file +by setting the variable history. +.TP 8 +.B history_char +By default the character `%' is used to do the history substitution +inside sis. This can be changed by setting the variable \fBhistory_char\fR. +.TP 8 +.B shell_char +By default the character `!' is used to do invoke shell commands from +inside sis. This can be changed by setting the variable \fBshell_char\fR. +\fI In order to switch the interpretation of shell_char and history_char it is +neccessary to first set history_char and then the shell_char. Alternately, +you may escape the current history char by preceeding it with +a `\' while setting the shell_char. In addition none of them can be set +to a `#' which is reserved for comments.\fR +.TP 8 +.B filec +Setting this variable enables the user to use "file-completion" like in +the C-shell. An ESC causes the current line to be extended to its unique +completion. A CTRL-d generates a list of the possible extensions. +.TP 8 +.B open_path +\fBopen_path\fR (in analogy to the shell-variable PATH) is a list of +colon-separated strings giving directories to be searched whenever +a file is opened for read. Typically the current directory (.) is +first in this list. The standard system +library (typically $SIS/sis_lib) is always implicitly appended +to the current path. +This provides a convenient short-hand +mechanism for reaching standard library files. +.TP 8 +.B prompt +defines the prompt string. If the prompt string contains a `%'(or whatever +the history_char has been set to using the set command), the `%' +will be replaced whenever the prompt is printed by the current event number. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +usage +.PP +Prints a formatted dump of processor-specific usage statistics. +For Berkeley Unix, this includes all of the information in the +\fIgetrusage()\fR structure. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +verify [-m method] [-v] file1 [file2] +.PP +Verify the Boolean equivalence of two networks. \fBfile1\fR +is compared with the current network when \fBfile2\fR is not +specified, otherwise, \fBfile1\fR is compared with \fBfile2\fR. +The input and output variables from two networks are associated +by their names. +.PP +The \fB-m\fR option specifies the verification method. +If \fBmethod\fR is \fIclp\fR (default), two networks are collapsed and +compared as PLA's. +If \fBmethod\fR is \fIbdd\fR, the BDD's are constructed for both networks and +compared. +.PP +The \fB-v\fR option engages the "verbose" mode of verify. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +verify_fsm [-o depth] [-v n] [-m method] filename.blif +.PP +Verify the equivalence of two synchronous networks. +The current network is compared with \fBfilename.blif\fR. +The input and output variables from the two networks are +associated by their names. +It is assumed that all the latches in both designs are clocked +by a single, global clock. +The verification is done by implicitly enumerating all the +states in the product machine, and checking that the outputs +are equivalent for all reachable state pairs starting +from the initial state of the product machine. +.PP +\fB-o depth\fR allows the specification of the depth of search for a good +variable ordering. +A larger value for depth will require more CPU time but determine +a better ordering. +The default value is 2. +.PP +\fB-v\fR allows specification of the verbosity level of the output. +.PP +The \fB-m\fR option specifies \fBmethod\fR for determining +the reachable states. +\fBconsistency\fR builds the entire transition relation +and uses it to determine the reached states. +\fBbull\fR does output cofactoring to find the reachable +states. +The \fBproduct\fR method is similar to the \fBconsistency\fR method but +input variables are smoothed as soon as possible as the characteristic +function is being built. +This makes the size of the resulting BDD representing the +characteristic function of the transition relation smaller. +The default method is \fBproduct\fR. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +wd [-c] node1 node2 +.PP +The \fBwd\fR command (which stands for "weak division") is very similiar +to resubstitution (\fBresub\fR command), except that instead of operating +on the entire network, \fBwd\fR simply re-expresses \fBnode1\fR +in terms of \fBnode2\fR. +.PP +The \fB-c\fR option allows re-substitution of the +complement of \fBnode2\fR. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +write_astg [-p] [<file-name>] +.PP +Write a text description of an ASTG to a file, or stdout if no filename +is given. +See read_astg for a description of the format. +.PP +The -p option forces implied places to be written explicitly in the +description. +Normally a place with exactly one fanin and one fanout transition +is suppressed by specifying the fanout transition +as adjacent to the fanin transition. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +write_bdnet [filename] +.PP +Write the current network to file \fBfilename\fP in the format +for a net-list defined by bdnet(1). +This is allowed only after the network has been mapped into a final +implementation technology. +.PP +The environment variable OCT-CELL-PATH defines where the cell library +is located. If a cell does not have a leading '~' or '/' in its name, +then OCT-CELL-PATH is prepended to the filename. +.PP +The variable OCT-CELL-VIEW defines the viewname to be used if the cell +does not have a ':' in its name to separate the cell name from the view +name. +.PP +The variables OCT-TECHNOLOGY, OCT-VIEWTYPE, and OCT-EDITSTYLE define +the technology, view-type, and edit-style properties for the Oct cell. + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +write_blif [-s] [-n] [filename] +.PP +Write the current network to file \fBfilename\fP in the Berkeley +Logic Interchange Format (\fIblif\fP). +.PP +The \fB-s\fP option uses the network short names rather than the +network long names for the \fIblif\fP file. +This can be used to encrypt the names of a net-list. +.PP +The \fB-n\fP option uses the net-list format of \fIblif\fP when +a node has a gate implementation in the library. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +write_eqn [-s] [filename] +.PP +The \fBwrite_eqn\fR command prints out the equations from the current +network according to format specifications laid out in the +documentation for \fBread_eqn\fR. +Both primary inputs and outputs are indicated. +.PP +The \fB-s\fR option uses the network short names rather than the +network long names for the output. +.PP +If \fBfilename\fR is not specified the equations will be written to +standard out, otherwise they will be written into the given file and +may be read by \fBread_blif\fR at a later time. +.PP +Note that since the eqn format uses the '(' and ')' characters +for grouping, they cannot appear in any of the signal names. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +write_kiss [filename] +.PP +The current state transition graph is saved in \fIkiss2\fP format to the +file \fBfilename\fP or printed to the screen if no filename is given. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +write_oct [-m] cell[:view] +.PP +Write the current network to the Oct facet \fBcell:view:contents\fR. +If \fBview\fR is not specified, it will default to `logic'. +.PP +If the \fB-m\fR flag is specified, the network is merged into an existing +network. +All of the logic elements and internal nets are ripped up and replaced +with the new network. +Oct net names are used to determine how to merge in the network, so +if the net names at the interface of the logic are not defined the +merge will fail. +.PP +The environment variable OCT-CELL-PATH defines where the cell library +is located. If a cell does not have a leading '~' or '/' in its name, +then OCT-CELL-PATH is prepended to the filename. +.PP +The variable OCT-CELL-VIEW defines the viewname to be used if the cell +does not have a ':' in its name to separate the cell name from the view +name. +.PP +The variables OCT-TECHNOLOGY, OCT-VIEWTYPE, and OCT-EDITSTYLE define +the technology, view-type, and edit-style properties for the Oct facet. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +write_pds [-c] [-d] [-s] [filename] +.PP +Write the current network to file \fBfilename\fP in the \fIpds\fP +format suitable for Xilinx. +The \fIpds\fP descriptions are generated for single output CLBs +(LUTs) only. +.PP +The \fB-c\fP option indicates that only the combinational portion +of the network should be written out. +.PP +The \fB-d\fP option will cause debugging information to be printed. +.PP +The \fB-s\fP option uses the network short names rather than the +network long names for the \fIpds\fP file. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +write_pla [filename] +.PP +Write the current network to file \fBfilename\fP in the Berkeley +PLA Format. No optimization is done on the PLA. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +write_slif [-s] [-n] [-d] [filename] +.PP +Write the current network to the file \fBfilename\fP in the Stanford Logic +Interchange Format (\fISLIF\fP). +.PP +The \fB-s\fP option uses the network short names rather than the network +long names for the \fISLIF\fP file. This can be used to encrypt the names of a +net-list. +.PP +The \fB-n\fP option uses the net-list format of \fISLIF\fP when a node has a +gate implementation in the library. +.PP +The \fB-d\fP option makes the \fISLIF\fR writer print out any delay information +known about the current network. This is not the default because a standard +for printing delay information has not been established for the +\fISLIF\fP format. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +XILINX +.br +Description +.br +.PP +This is a package to optimize the Boolean network and map it onto +the Xilinx Programmable Gate Array architecture +(reference: Xilinx, the Programmable Gate Array Data Book, +Xilinx Corporation). +All the routines except \fBxl_merge\fR can be used to map the design +onto an architecture with a CLB (Configurable Logic Block) realizing an +arbitrary function of up to n inputs, where n >= 2. +The package contains the following commands available to the user +for experimentation. +.br +.PP +Suggested script +.br +.PP +time +.br +.PP +sweep +.br +.PP +simplify +.br +.PP +sweep +.br +.PP +simplify +.br +.PP +xl_split -n 5 +.br +.PP +sweep +.br +.PP +simplify +.br +.PP +xl_split -n 5 +.br +.PP +sweep +.br +.PP +xl_partition -n 5 +.br +.PP +sweep +.br +.PP +simplify +.br +.PP +xl_partition -n 5 +.br +.PP +sweep +.br +.PP +xl_k_decomp -n 5 +.br +.PP +sweep +.br +.PP +xl_cover -n 5 -h 3 +.br +.PP +xl_merge +.br +.PP +time +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_absorb [-n support] [-f MAX_FANINS] [-v] +.PP +Given a possibly infeasible network, moves fanins of the nodes so as +to decrease their number of fanins. Some infeasible +nodes may become feasible and decomposition may not be applied on +them. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.br +.PP +\fB-f\fP: Does not move fanins of a node if it has more than MAX_FANINS +(default 15). +.br +.PP +\fB-v\fP: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_ao [-n support] +.PP +Uses a cube-packing heuristic to do an AND-OR decomposition of an infeasible network. +This is fast and the result is a feasible network. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_coll_ck [-n support] [-c collapse_input_limit] [-kv] +.PP +Assumes a feasible network. +If the number of inputs to the network is at most +\fBcollapse_input_limit\fP (default 9), collapse the network, +apply Roth-Karp decomposition and cofactoring schemes. +Pick the best result and compare with the original network +(before collapsing). If the number of nodes is smaller, accept the +better decomposition. Does nothing if n = 2. +.PP +\fB-k\fP: does not apply Roth-Karp decomposition, just use cofactoring. +.br +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.br +.PP +\fB-v\fP: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_cover [-n number] [-h heuristic number] +.br +.PP +For mapping onto Xilinx architecture. +The initial network +should have all intermediate nodes with fanin less than +or equal to \fBnumber\fP (default is 5). +Mathony's binate covering algorithm is used to +minimize the number of nodes in the network. +Different heuristics are used to solve the covering +problem. The heuristic number can be specified +by \fB-h\fP option. Heuristic number can be 0, 1, 2 or 3: +.br +.PP +- 0 (exact), +.PP +- 1 (Mathony's method - stop when first leaf is reached), +.PP +- 2 (For large examples), +.PP +- 3 (default: automatically decides between 0 and 2) +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_decomp_two [-n support] [-l lower_common_bound] + [-L cube_support_lower_bound] [-f MAX_FANIN] + [-c MAX_COMMON_FANIN] [-u MAX_UNION_FANIN] [-v] +.PP +Given an infeasible network, does decomposition +knowing that each Xilinx3090 CLB can have two functions if they have +no more than MAX_FANIN (default = 4) fanins each, their union has at +most MAX_UNION_FANINS (default = 5) fanins and they have at most +MAX_COMMON_FANINS (default = 4) common fanins. It does so by +considering certain cubes of all the infeasible nodes of the network, and +associating an affinity value with each cube-pair. Extracts +cube-pairs with high affinity. Need to do a decomposition later to +make the network feasible. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.br +.PP +\fB-l\fP: do not consider a cube-pair for extraction if their number of +common inputs is less than lower_common_bound (default = 2). +.br +.PP +\fB-L\fP: do not consider a cube if it has less than +cube_support_lower_bound inputs. +.br +.PP +\fB-v\fP: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_imp [-n support] [-c cover_node_limit] [-l lit_bound] [-Aabm] + [-g good_decomp] [-M MAX_FANINS] + [-v verbosity level] +.PP +Given an infeasible network, replaces each internal infeasible node +by a set of feasible nodes. These nodes are derived by trying +different decomposition strategies (like xl_ao, xl_split, +cofactoring, decomp -d and tech_decomp -a 2 -o 2), each followed +by a partition/cover phase. In the end, picks the best result (the +one with minimum number of feasible nodes). The result is a feasible network. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.br +.PP +\fB-A\fP do not move fanins around after decomp -g. +.br +.PP +\fB-a\fP: do not apply all decomposition methods. Only cube-packing on +sum-of-product (SOP), cube-packing on factored-form (if g flag +!= 0) and cofactoring. If this option is not specified, also apply +Roth-Karp, tech_decomp, decomp -d, and xl_split. +.br +.PP +\fB-b\fP: for best results, use this option. +Effective on a node only if its number of +literals is greater than lit_bound. In that case, after the good decomposition, +recursively call the command for each of the nodes in +decomposition. Time consuming. +.br +.PP +\fB-c\fP: sets the limit for the cover algorithm used after each +decomposition. If the number of feasible nodes for an infeasible node +is no more than cover_node_limit, then exact cover is used, else +heuristic (-h 3) option is used. (default = 25). +.br +.PP +\fB-g\fP: if 0 (default), do not use decomp -g for cube-packing, just +SOP. If 1, use only decomp -g, not SOP. If 2, use both decomp -g and SOP for +cube-packing, and pick the best result. +.br +.PP +\fB-l\fP: if the infeasible node has greater than lit_bound literals, +does a good decomposition of the node (i.e. decomp -g) (default: 50) +.br +.PP +\fB-m\fP: While doing partition, move fanins around for a node with at +most MAX_FANINS (default 15). +.br +.PP +\fB-v\fP: this sets the verbosity level (amount of information printed +as the algorithm proceeds) to \fBverbosity_level\fP. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_k_decomp [-n support] [-p node_name] [-v verbosity_level] [-f MAX_FANINS_K_DECOMP] [-de] +.PP +Uses Karp_Roth disjoint decomposition to recursively decompose +nodes of the network having fanin greater than +\fBsupport\fP to obtain nodes each having +fanin of at most \fBsupport\fP. +If \fB-p node_name\fP is specified, only the node with the name +\fBnode_name\fP is decomposed. +Otherwise, all the nodes +that have fanin greater than \fBsupport\fP are +decomposed. +If \fB-d\fP option is specified, then if k_decomp fails to find a disjoint decomposition on a node, +the node is not decomposd by cube-packing. Option \fB-e\fP allows an exhaustive search over all +possible partitions to pick the best decomposition of a node. Then the option \fB-f MAX_FANINS_K_DECOMP\fP +sets the limit on maximum number of fanins of a node for exhaustive decomposition. If the number of fanins +is higher, only the first input partition is considered. + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_merge [-f MAX_FANIN] [-c MAX_COMMON_FANIN] [-u MAX_UNION_FANIN] + [-n support] [-o filename] [-vlF] +.PP +Used for mapping onto Xilinx architecture. +It selects pairs of nodes of the network that can be merged +so as to minimize the number of nodes. +and solves an integer program using the package Lindo. +In the end it lists the pairs of nodes that were merged. +The command does not change the network. +.PP +\fB-f\fP: MAX_FANIN is the limit on the fanin of a mergeable node (default = 4). +.br +.PP +\fB-c\fP: MAX_COMMON_FANIN is the limit on the common fanins of two +mergeable nodes (default = 4). +.br +.PP +\fB-u\fP: MAX_UNION_FANIN is the limit on the union of the fanins of two +mergeable nodes (default = 5). +.br +.PP +\fB-n\fP: support is the limit on the number of fanins of a single function that +can be put on a CLB (default = 5). +.br +.PP +\fB-o\fP: filename is the file in which information about the nodes merged is +printed. Must specify. +.br +.PP +\fB-l\fP: Do not use lindo, an integer-linear programming package used to solve +the matching problem. Instead use a heuristic. If not specified, the program first +searches for lindo in the path. If found, lindo is invoked, else the program +automatically calls the heuristic. +.br +.PP +\fB-F\fP: If the input network is say a 4-feasible network and the support = 5, it +may be possible to reduce the number of nodes after matching. If this option is not +used,\fBxl_partition\fP is called after matching step on the subnetwork composed of +unmatched nodes. Otherwise, only matching is done and the network remains unchanged. +.br +.PP +\fB-v\fP: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_part_coll [-n support] [-C cost_limit] [-c cover_node_limit] + [-l lit_bound] [-Aabm] [-g decomp_good] + [-M MAX_FANINS] [-v verbosity_level] +.PP +This is a partial collapse routine. On an infeasible network, +first runs trivial partition routine. Then for each node, +finds the cost of the node using a routine similar to \fBxl_imp\fP. +Collapses each node into fanouts and computes the cost of the +fanouts likewise. If the new cost of the fanouts is less, accepts +the collapse. Deletes the collapsed node from the network. +It does this until no more collapses can be beneficially carried out. +The nodes are visited topologically. +The result is a feasible network. +.PP +\fB-C\fP: tries only those nodes for collapsing whose cost is less +than or equal to cost_limit. +Our experience has been that it is beneficial to collapse +only feasible nodes. So the default is 1. +.br +.PP +Other options are the same as in \fBxl_imp\fP except -c has default of +10 and -A means move fanins around. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_partition [-n support] [-M MAX_FANINS] [-v verbosity_level] [-tm] +.PP +Tries to reduce the number of nodes by collapsing nodes into their +fanouts. Also takes into account extra nets created. Collapses a +node into its fanout only if the resulting fanout is feasible. +Associates a cost with each (node, fanout) pair which reflects the +extra nets created if node is collapsed into the fanout. It then selects +pairs with lowest costs and collapses them. +The starting network need not be feasible, in which case +the resulting network also may not be. But if the starting network is, +so is the resulting network. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.br +.PP +\fB-t\fP: Our experience was that if one is just interested in +minimization of number of nodes, then those nodes which can +be collapsed into all their fanouts are the main reduction-contributors. +This option removes a node from the network if it +can be collapsed into all its fanouts. Very fast. +.br +.PP +\fB-m\fP: move fanins around to increase collapsing possibilities. Do so for a node +only if after collapsing, it has at most MAX_FANINS (default = 15)(as specified by \fB-M\fP option). +.br +.PP +\fB-v\fP: this sets the verbosity level (amount of information printed +as the algorithm proceeds) to \fBverbosity_level\fP. +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_rl [-n support] [-m] [-M MAX_FANINS] + [-t (trav_method-levels)] [-c collapse_input_limit] + [-v verbosity_level] +.PP +Used for timing optimization for table look up architectures (phase 1). +Given a feasible network (obtained say by using speed_up), reduces number of +levels for table look up with "support" inputs. If \fB-m\fP is not given, +it tries to move fanins for each node also, provided the number of +fanins of the node does not exceed MAX_FANINS (default 15). As a +final step, tries collapsing the network if number of inputs to the +network is at most collapse_input_limit (default = 10). Then applies +Roth-Karp decomposition and cofactoring (support > 2). If number of +levels decreases, accepts the better decomposition. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:34 $ +.\" * +.\" +.XX +xl_split [-n value] [-d] +.PP +Ensures that every node in the network has number of fanins less than or +equal to \fBvalue\fP. +This is accomplished by using kernel extraction and AND-OR decomposition. +\fB-d\fP turns on debugging facilities. +.SH FILES +$SIS/ex +.br +$SIS/sis_lib/.misrc +.br +$SIS/sis_lib/.sisrc +.br +$SIS/sis_lib/script +.br +$SIS/sis_lib/* +.SH "SEE ALSO" +espresso(1CAD), espresso(5CAD), eqntott(1CAD), nova(1CAD), +stamina(UC Boulder), jedi(1CAD), doc/blif.tex, doc/SPEC. +.SH AUTHORS +Ellen Sentovich +.br +Kanwar Jit Singh +.SH OTHER CONTRIBUTORS +Bill Lin, Luciano Lavagno, Sharad Malik, Cho Moon, Rajeev Murgai, +Alex Saldanha, Hamid Savoj, Narendra Shenoy, Tom Shiple, Paul Stephan, +Colin Stevens, Herve Touati, Tiziano Villa, and Carol Wawrukiewicz. +Jose Monteiro (MIT) contributed the power estimation package. +David Long (AT&T Bell Laboratories) contribued the BDD package. +June Rho (CU Boulder) contributed the stamina program. +Roberto Rambaldi (D.E.I.S. Universita' di Bologna) contributed +the vst2blif program. +Richard Rudell and Albert Wang wrote the program MISII, upon which +SIS is built. +.SH BUGS +If a state machine has only one state, calling state assignment using +nova causes a fatal error. This is due to the fact that if a PLA has +outputs that are all 0, espresso returns no PLA (when the type requested +is the ON-set). nova tries to read the pla using SIS and fails. + +The simulate command does not work as it should for sequential circuits. +Gated clocks are not simulated correctly, and incorrect results are obtained +when the network has a clock and the STG does not. + +.SH COMMENTS +Mapping information is lost during factoring. Once a circuit is mapped, +it is not expected that any further operations on the logic will +be performed, hence, if they are, the mapping is lost. + +Many of the new routines (e.g. extract_seq_dc, full_simplify, verify_fsm) +use BDDs and can be very time- and memory-consuming. +Work is underway on this problem. diff --git a/sis/sis_lib/help/sis.man b/sis/sis_lib/help/sis.man new file mode 100644 index 0000000..1001aa7 --- /dev/null +++ b/sis/sis_lib/help/sis.man @@ -0,0 +1,703 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sis.man,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.TH SIS 1CAD "1 July 1994" +.SH NAME +sis \- Sequential Interactive System +.SH SYNOPSIS +.B sis +[options] [file] +.SH DESCRIPTION +\fBSIS\fR is an algorithmic sequential circuit optimization +program. \fBSIS\fR starts from a description +of a sequential logic macro-cell and produces +an optimized set of logic equations plus latches which preserves +the input-output behavior of the macro-cell. +The sequential circuit can be stored as a finite +state machine or as an implementation consisting of logic +gates and memory elements. +The program +includes algorithms for minimizing the area required to +implement the logic equations, algorithms for minimizing delay, +and a technology +mapping step to map a network into a user-specified cell library. +It includes all of the optimization techniques available in +\fBMIS\fR, and replaces \fBMIS\fR completely. +.PP +\fBSIS\fR can be run in interactive mode accepting commands +from the user, or in batch mode reading commands +from a file or from the command line. +If no options are given on the command line, \fBSIS\fP will +enter interactive mode. +Otherwise, \fBSIS\fP will enter batch mode. +When running in batch mode, \fBSIS\fP reads its +input from the file given on the command line, or from standard input +if no filename is given; +output is directed to standard output, unless \fB-o\fP is used to +specify an output filename. +.PP +When \fBSIS\fP starts-up, it performs an initial source of the +files $SIS/sis_lib/.misrc and $SIS/sis_lib/.sisrc. +Typically this defines a standard +set of aliases for various commands. +Following that the files ~/.misrc, ~/.sisrc, ./misrc, and ./sisrc +are sourced for user-defined aliases at startup. +.SH OPTIONS +.TP 8 +.B -c cmdline +Run \fBSIS\fR in batch mode, and execute \fBcmdline\fR. +Multiple commands are separated with semicolons. +.TP 8 +.B -f script +Run \fBSIS\fR in the batch mode, and execute commands from the +file \fBscript\fR. +.TP 8 +.B -t type +Specifies the type of the input when running in batch mode. +The legal input types are: +Berkeley Logic Interchange Format (\fB-t blif\fP), +eqntott(1CAD)-format equation input (\fB-t eqn\fP), +\fIKISS2 format\fR (\fB-t kiss\fP), +\fIOct Logic View\fR (\fB-t oct\fP), +Berkeley PLA Format (\fB-t pla\fP), +\fISLIF format\fR (\fB-t slif\fP), +and suppress input (\fB-t none\fP). +The default input type is \fIblif\fR. +.TP 8 +.B -T type +Specifies the type of the output when running in batch mode. +The legal output types are: +bdnet(1CAD)-format net-list (\fB-T bdnet\fP), +Berkeley Logic Interchange Format (\fB-T blif\fP), +eqntott(1CAD)-format equation input (\fB-T eqn\fP), +\fIKISS2 format\fR (\fB-T kiss\fP), +\fIOct logic view\fR (\fB-T oct\fP), +Berkeley PLA Format (\fB-T pla\fP), +\fISLIF format\fR (\fB-T slif\fP), +and suppress output (\fB-T none\fP). +The default output type is \fIblif\fR. +.TP 8 +.B -o file +Specifies the output file when running in batch mode. +For \fIOct\fP output, this is a string of the +form \fIcell\fP:\fIview\fP. +The default for the output is the standard output. +.TP 8 +.B -s +Suppress sourcing the commands from the standard +startup script ($SIS/sis_lib/.misrc and $SIS/sis_lib/.sisrc). +.TP 8 +.B -x +For batch mode operation, suppress reading an initial network, and +suppress writing an output network. +Equivalent to \fB-t none -T none\fP. +.de XX +.sp 1 +.LP +.ti -5 +.B +.. +.de X1 +.br +.ti -5 +.B +.. +.PP +.SH COMMAND SUMMARY +All commands are summarized below according +to their function : network manipulation (operations +on the logic-level implementation), +ASTG manipulation (operations on the asynchronous +signal transition graph), STG manipulation (operations +on the synchronous state transition graph), +input-output, network status, command interpreter, +and miscellaneous. +The last two tables summarize the newest commands that +operate on ASTG's and sequential circuits, respectively. +.sp 2 +.TS +center box; +c s +l l. +\fBNetwork Manipulation Commands\fP +_ +act_map technology mapping to Actel architecture +add_inverter add inverters to the network to make all gates negative +astg_slow remove hazards from the ASTG implementation + (uses bounded wire delay model) +astg_syn synthesize a two-level implementation from the ASTG + (uses unbounded wire delay model) +astg_to_f generate a two-level implementation of each output of the ASTG + (uses bounded wire delay model) +astg_to_stg generate an STG from the ASTG +buffer_opt inserts buffering trees for high fanout gates +chng_clock toggles clock setting between user-specification and generated values +collapse collapse a network or a set of nodes +decomp decompose a node into a set of nodes +eliminate eliminates nodes whose value falls below a threshold +env_seq_dc extract sequential don't cares based on the environment +equiv_nets group and merge nets by equivalence classes +espresso collapse network and minimize with a two-level minimizer +extract_seq_dc extract sequential don't cares +factor determine a factored form for a node +fanout_alg select a fanout optimization algorithm (to be used by map) +fanout_param set some parameters for fanout algorithm (to be used by map) +free_dc frees the external don't care network +force_init_0 modify so all latches to have a 0 initial state +full_simplify simplify the nodes using local compatible don't cares +fx do fast extraction of the best double cube and single cube divisors +gcx extract common cubes from the network +gkx extract common multiple-cube divisors from the network +invert invert a node, and toggle the phase of all of its fanouts +latch_output forces some outputs to be fed directly by latches +map technology mapping to find an implementation for the network +one_hot quick one-hot encoding +phase phase assignment to minimize number of inverters +red_removal perform redundancy removal via atpg +reduce_depth increase the speed before mapping by reducing the depth +remove_dep removes some structural (but not logical) dependencies +remove_latches removes redundant latches +replace quick algebraic decomposition on 2-input NANDs +resub perform resubstitution of a node into other nodes in the network +retime move the latches in the circuit to minimize cycle time/# latches +simplify two-level minimization of each node +speed_up restructure critical paths to reduce delay +speed_up_alg several algorithms for performance enhancement +state_assign create the logic from the STG using state assignment +stg_extract extract an STG from the logic +stg_to_network converts a state-encoded STG to a logic network +sweep remove all inverters, buffers, and unnecessary latches from the network +tech_decomp decompose a network for technology mapping +wd re-express a node using another node using weak division +.TE +.sp 2 +.TS +center box; +c s +l l. +\fBNetwork Manipulation Commands (cont.)\fP +_ +xl_absorb decreases number of fanins to make nodes feasible +xl_ao AND-OR decomposition of an infeasible network to a feasible one +xl_coll_ck collapse and apply Roth-Karp decomposition and cofactoring +xl_cover global cover of nodes by "xilinx" blocks of pld gates +xl_decomp_two decomposition into two compatible "xilinx" functions +xl_imp generates a feasible network using various decomposition schemes +xl_k_decomp Karp-Roth decomposition for mapping into "xilinx" gates +xl_merge merge "xilinx" blocks +xl_part_coll partial collapse +xl_partition local cover of nodes by "xilinx" blocks of pld gates +xl_rl timing optimization for table look up architectures +xl_split decompose a network (using routing complexity as cost) +.TE +.sp 2 +.TS +center box; +c s +l l. +\fBASTG Manipulation Commands\fP +_ +astg_add_state adds states to the ASTG to guarantee implementability +astg_contract generate the contracted net for a signal of the ASTG +astg_encode critical race-free STG encoding +astg_lockgraph build the lock graph for the current ASTG +astg_marking set or display the initial marking of the ASTG +astg_persist make the ASTG persistent +astg_state_min minimizes the current STG and derives encoding + information for the associated ASTG +astg_stg_scr transforms the STG to one that satisfies SCR property +stg_to_astg transforms the STG (with the SCR property) to an ASTG +.TE +.sp 2 +.TS +center box; +c s +l l. +\fBSTG Manipulation Commands\fP +_ +state_assign assign binary codes to the states in the STG +state_minimize minimize the number of states in the STG +stg_to_astg transforms the STG (with the SCR property) to an ASTG +.TE +.sp 2 +.TS +center box; +c s +l l. +\fBTiming Commands\fP +_ +c_check verifies satisfaction of clocking constraints +c_opt computes the optimal clock for a given clocking scheme +.TE +.sp 2 +.TS +center box; +c s +l l. +\fBInput-Output Commands\fP +_ +read_astg read a signal transition graph in ASTG format +read_blif read a network in BLIF format +read_eqn read a network in eqntott(1CAD) format +read_kiss read an STG in KISS2 format +read_library read a library description file +read_oct read a network from an Oct Logic view +read_pla read a network in PLA format +read_slif read a network in Stanford Logic Interchange Format +set_delay set delay parameters for primary inputs and outputs +set_state set the current state in a sequential circuit to the given state +write_astg write the current signal transition graph in ASTG format +write_bdnet write the current (mapped) network in bdnet(1CAD) format +write_blif write the current network in BLIF format +write_eqn write the current network in eqntott(1CAD) equation format +write_kiss write the STG in KISS2 format +write_oct write the current network into an Oct Logic view +write_pla write the current network in PLA(5CAD) format +write_pds write the current network in PDS format for Xilinx +write_slif write the current network in SLIF format +.TE +.sp 1 +.TS +center box; +c s +l l. +\fBNetwork Status Commands\fP +_ +astg_current display information about the current ASTG +astg_print_sg print the state graph of the current ASTG +astg_print_stat print the statistics of the current ASTG +constraints print the delay constraints for a set of nodes +plot_blif plot the network in a graphics window (only available in \fBxsis\fR) +power_estimate estimate dissipated power based on switching activity +power_free_info frees memory associated with power calculations +power_print print switcing probabilities and capacitances +print print logic function associated with a node +print_altname print the short (and long) names for a node +print_clock print out information about the clocks in the network +print_delay timing simulate a network and print results +print_factor print the factored form associated with a node +print_gate print information about the gates used in the mapped network +print_io print the fanin and fanout of a node (or the network) +print_kernel print the kernels (and subkernels) of a set of functions +print_latch print out information about all the latches in the circuit +print_level print the levels of a set of nodes +print_library list the gates in the current library +print_map_stats print delay and area information for a mapped network +print_state print the current state of a sequential circuit +print_stats print statistics on a set of nodes +print_value print the value of a set of nodes +.TE +.sp 1 +.TS +center box; +c s +l l. +\fBCommand Interpreter\fP +_ +alias provide an alias for a command +chng_name switch between short and long forms for node names +echo merely echo the arguments +help provide on-line information on commands +history a UNIX-like history mechanism inside the \fBSIS\fP shell +quit exit \fBSIS\fP +reset_name rename all of the short names in the network +save save a copy of the current executable +set set an environment variable +source execute commands from a file +time provide a simple elapsed time value +timeout sends an interrupt to the \fBSIS\fR process +unalias remove the definition of an alias +undo undo the result of the last command which changed the network +unset unset an environment variable +usage provide a dump of process statistics +.TE +.sp 1 +.TS +center box; +c s +l l. +\fBMiscellaneous\fP +_ +atpg perform combinational atpg using SAT approach +bdsyn special command used by bdsyn(1CAD) +env_verify_fsm verify equivalence of two networks in an environment +short_tests generate small sequential test sets +sim_verify verify networks equivalent via simulation +simulate logic simulation of the current network +stg_cover check that the STG behavior covers the logic implementation +verify verify equivalence of two combinational networks +verify_fsm verify equivalence of two combinational or sequential networks +.TE +.sp 1 +.TS +center box; +c s +l l. +\fBAsynchronous Synthesis Commands\fP +_ +astg_add_state adds states to the ASTG to guarantee implementability +astg_contract generate the contracted net for a signal of the ASTG +astg_current display information about the current ASTG +astg_encode critical race-free STG encoding +astg_lockgraph build the lock graph for the current ASTG +astg_marking set or display the initial marking of the ASTG +astg_persist make the ASTG persistent +astg_print_sg print the state graph of the current ASTG +astg_print_stat print the statistics of the current ASTG +astg_slow remove hazards from the ASTG (uses bounded wire delay model) +astg_state_min minimizes the current STG and derives encoding + information for the associated ASTG +astg_stg_scr transforms the STG to one that satisfies SCR property +astg_syn synthesize a two-level implementation from the ASTG + (uses unbounded wire delay model) +astg_to_f generate a two-level implementation of each output of the ASTG + (uses bounded wire delay model) +astg_to_stg generate an STG from the ASTG +read_astg read a signal transition graph in ASTG format +write_astg write the current signal transition graph in ASTG format +.TE +.sp 1 +.TS +center box; +c s +l l. +\fBSequential Synthesis Commands\fP +_ +c_check verifies satisfaction of clocking constraints +c_opt computes the optimal clock for a given clocking scheme +chng_clock toggles clock setting between user-specification and generated values +env_seq_dc extract sequential don't cares based on the environment +env_verify_fsm verify equivalence of two networks in an environment +extract_seq_dc extract sequential don't cares +force_init_0 modify so all latches to have a 0 initial state +latch_output forces some outputs to be fed directly by latches +one_hot quick one-hot encoding +power_estimate estimate dissipated power based on switching activity +power_free_info frees memory associated with power calculations +power_print print switcing probabilities and capacitances +print_clock print out information about the clocks in the network +print_latch print out information about all the latches in the circuit +read_kiss read an STG in KISS2 format +read_slif read a network in Stanford Logic Interchange Format +remove_latches removes redundant latches +retime move the latches in the circuit to minimize cycle time/# latches +set_delay set delay parameters for primary inputs and outputs +set_state set the current state in a sequential circuit to the given state +short_tests generate small sequential test sets +state_assign create the logic from the STG using state assignment +state_minimize minimize the number of states in the STG +stg_cover check that the STG behavior covers the logic implementation +stg_extract extract an STG from the logic +stg_to_network converts a state-encoded STG to a logic network +verify_fsm verify equivalence of two combinational or sequential networks +write_kiss write the STG in KISS2 format +write_slif write the current network in SLIF format +.TE +.sp .5i +.SH NODELIST ARGUMENTS +Most commands which take a node also take a list of nodes as an +argument. This is referred to as a \fBnode-list\fP in the +documentation below. +This list of nodes includes \fB*\fP to specify +all nodes in the network, \fBi()\fP to specify the primary +inputs of the network, \fBo()\fP to specify the primary +outputs of the network, \fBi(node)\fP to specify the +direct fanin of \fInode\fP, and \fBo(node)\fP to specify the +direct fanout of \fInode\fP. +.sp .5i +.SH STANDARD ALIASES +When \fBSIS\fP starts, it executes commands from a system startup file +(usually $(SIS)/sis_lib/.misrc and $(SIS)/sis_lib/.sisrc). +This defines a standard set of +aliases, and then sources the files ~/.misrc, ~/.sisrc, ./misrc, +and ./sisrc to allow +users to define their own set of aliases. The default alias set includes +the following aliases which have proven useful. Note that many of the aliases +are intended for compatibility with \fBSIS\fP Version #1.0. +.TS +center box; +c s s +c c c +l l l. +\fBStandard Aliases\fP +alias command description +_ +1h sa nova -e h do 1-hot state encoding using nova +ai add_inverter add inverters to a network to correct the phases +alt print_altname print both long and short names for a node +asb resub -a algebraic resubstitution +c chng_name toggle between long and short names +clp collapse collapse network +crit pd -a -p 2 print out the 2 most critical paths +el eliminate eliminate nodes below a threshold +exit quit terminate program +fs full_simplify simplify each node function +gd decomp -g good decomposition (i.e., best kernel decomposition) +gf factor -g good factoring (i.e., best kernel factoring) +gp phase -g good phase assignment (i.e., more expensive) +inv invert invert a node keeping network function consistent +oh one_hot do quick one-hot encoding +man help print out command information +nts print_stats print network status (including factored form) +p print print sum-of-products form of a node +pat print_delay -a print node arrival times +pc print_clock print information about clocks in the network +pd print_delay print delay +pf print_factor print factored form of a node +pg print_gate print gate information for a node +pgc print_gate -s summarize gate information for the network +pio print_io print inputs and outputs of a node or the network +pk print_kernel print kernels of a node +pl print_latch print latch information +plt print_delay -l print output loading for each node +plv print_level print the level of each node +pn p -n print nodes in 'negative' form +prt print_delay -r print node required times +ps print_stats -f print network status (including factored form) +psf print_stats print network status +pst print_delay -s print node slack times +pv print_value print node values +q quit terminate program +qd decomp -q quick decomposition (i.e., any kernel decomposition) +qf factor -g quick factoring (i.e., any kernel factoring) +qp phase -q quick phase (i.e., simple greedy algorithm) +ra read_astg read a signal transition graph in ASTG format +rd reduce_depth increase speed before mapping by reducing the depth +re read_eqn read equations from a file +rk read_kiss read an STG in KISS2 format +rl read_blif read a blif network from a file +rlib read_library read a library +ro read_oct read a network from an Oct view +rp read_pla read a PLA in espresso format +rr red_removal remove combinationally redundant signals +rs read_slif read a network in SLIF fornat +.TE +.sp 1 +.TS +center box; +c s s +c c c +l l l. +\fBStandard Aliases (cont.)\fP +alias command description +_ +rsn reset_name reset all short names starting from 'a' +rt retime -n retime an unmapped network +sa state_assign create the logic from the STG using state assignment +se stg_extract extract an STG from the logic +sim simulate logic simulation on a network +sim0 simplify -d quick minimization of a node (no don't cares) +sim1 simplify -m nocomp -d complete minimization of a node (no don't cares) +sim2 simplify single pass minimization with fanin DC-set +sim3 simplify -m nocomp complete minimization with fanin DC-set +sm state_minimize minimize the number of states in the STG +so source source a script file +sp speed_up critical path restructuring to reduce delay +sw sweep remove buffers, inverters from a network +td tech_decomp decompose network into AND/OR gates +u undo undo last command which changed network +v verify_fsm verify the equivalence of two sequential networks +wa write_astg write the current signal transition graph in ASTG format +wb write_bdnet write mapped network in BDNET format +we write_eqn write network in EQN format +wk write_kiss write the STG in KISS2 format +wl write_blif write network in blif format +wp write_pla write network in Espresso PLA format +wo write_oct write network as an Oct view +ws write_slif write network in SLIF format +xdc extract_seq_dc extract sequential don't cares (unreachable states) +.TE +.bp +.SH DETAILED COMMAND DESCRIPTIONS +.PP +.so act_map.1 +.so add_inverter.1 +.so alias.1 +.so astg_add_state.1 +.so astg_contract.1 +.so astg_current.1 +.so astg_encode.1 +.so astg_lockgraph.1 +.so astg_marking.1 +.so astg_persist.1 +.so astg_print_sg.1 +.so astg_print_stat.1 +.so astg_slow.1 +.so astg_state_min.1 +.so astg_stg_scr.1 +.so astg_syn.1 +.so astg_to_f.1 +.so astg_to_stg.1 +.so atpg.1 +.so bdsyn.1 +.so buffer_opt.1 +.so c_check.1 +.so c_opt.1 +.so chng_clock.1 +.so chng_name.1 +.so collapse.1 +.so constraints.1 +.so decomp.1 +.so echo.1 +.so eliminate.1 +.so env_seq_dc.1 +.so env_verify_fsm.1 +.so equiv_nets.1 +.so espresso.1 +.so extract_seq_dc.1 +.so factor.1 +.so fanout_alg.1 +.so fanout_param.1 +.so force_init_0.1 +.so free_dc.1 +.so full_simplify.1 +.so fx.1 +.so gcx.1 +.so gkx.1 +.so help.1 +.so history.1 +.so invert.1 +.so invert_io.1 +.so ite_map.1 +.so latch_output.1 +.so map.1 +.so one_hot.1 +.so phase.1 +.so plot_blif.1 +.so power_estimate.1 +.so power_free_info.1 +.so power_print.1 +.so print.1 +.so print_altname.1 +.so print_clock.1 +.so print_delay.1 +.so print_factor.1 +.so print_gate.1 +.so print_io.1 +.so print_kernel.1 +.so print_latch.1 +.so print_level.1 +.so print_library.1 +.so print_map_stats.1 +.so print_state.1 +.so print_stats.1 +.so print_value.1 +.so quit.1 +.so read_astg.1 +.so read_blif.1 +.so read_eqn.1 +.so read_kiss.1 +.so read_library.1 +.so read_oct.1 +.so read_pla.1 +.so read_slif.1 +.so red_removal.1 +.so reduce_depth.1 +.so remove_dep.1 +.so remove_latches.1 +.so replace.1 +.so reset_name.1 +.so resub.1 +.so retime.1 +.so save.1 +.so set.1 +.so set_delay.1 +.so set_state.1 +.so short_tests.1 +.so sim_verify.1 +.so simplify.1 +.so simulate.1 +.so source.1 +.so speed_up.1 +.so speedup_alg.1 +.so state_assign.1 +.so state_minimize.1 +.so stg_cover.1 +.so stg_extract.1 +.so stg_to_astg.1 +.so stg_to_network.1 +.so sweep.1 +.so tech_decomp.1 +.so time.1 +.so timeout.1 +.so unalias.1 +.so undo.1 +.so unset.1 +.so usage.1 +.so verify.1 +.so verify_fsm.1 +.so wd.1 +.so write_astg.1 +.so write_bdnet.1 +.so write_blif.1 +.so write_eqn.1 +.so write_kiss.1 +.so write_oct.1 +.so write_pds.1 +.so write_pla.1 +.so write_slif.1 +.so xilinx.1 +.so xl_absorb.1 +.so xl_ao.1 +.so xl_coll_ck.1 +.so xl_cover.1 +.so xl_decomp_two.1 +.so xl_imp.1 +.so xl_k_decomp.1 +.so xl_merge.1 +.so xl_part_coll.1 +.so xl_partition.1 +.so xl_rl.1 +.so xl_split.1 +.SH FILES +$SIS/ex +.br +$SIS/sis_lib/.misrc +.br +$SIS/sis_lib/.sisrc +.br +$SIS/sis_lib/script +.br +$SIS/sis_lib/* +.SH "SEE ALSO" +espresso(1CAD), espresso(5CAD), eqntott(1CAD), nova(1CAD), +stamina(UC Boulder), jedi(1CAD), doc/blif.tex, doc/SPEC. +.SH AUTHORS +Ellen Sentovich +.br +Kanwar Jit Singh +.SH OTHER CONTRIBUTORS +Bill Lin, Luciano Lavagno, Sharad Malik, Cho Moon, Rajeev Murgai, +Alex Saldanha, Hamid Savoj, Narendra Shenoy, Tom Shiple, Paul Stephan, +Colin Stevens, Herve Touati, Tiziano Villa, and Carol Wawrukiewicz. +Jose Monteiro (MIT) contributed the power estimation package. +David Long (AT&T Bell Laboratories) contribued the BDD package. +June Rho (CU Boulder) contributed the stamina program. +Roberto Rambaldi (D.E.I.S. Universita' di Bologna) contributed +the vst2blif program. +Richard Rudell and Albert Wang wrote the program MISII, upon which +SIS is built. +.SH BUGS +If a state machine has only one state, calling state assignment using +nova causes a fatal error. This is due to the fact that if a PLA has +outputs that are all 0, espresso returns no PLA (when the type requested +is the ON-set). nova tries to read the pla using SIS and fails. + +The simulate command does not work as it should for sequential circuits. +Gated clocks are not simulated correctly, and incorrect results are obtained +when the network has a clock and the STG does not. + +.SH COMMENTS +Mapping information is lost during factoring. Once a circuit is mapped, +it is not expected that any further operations on the logic will +be performed, hence, if they are, the mapping is lost. + +Many of the new routines (e.g. extract_seq_dc, full_simplify, verify_fsm) +use BDDs and can be very time- and memory-consuming. +Work is underway on this problem. diff --git a/sis/sis_lib/help/source.1 b/sis/sis_lib/help/source.1 new file mode 100644 index 0000000..1997b9a --- /dev/null +++ b/sis/sis_lib/help/source.1 @@ -0,0 +1,61 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/source.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +source [-psx] filename +.PP +Read commands from a file. The \fB-p\fP option prints a prompt before +reading each command, and the \fB-x\fP option echoes each command before +it is executed. The \fB-s\fP option silently ignores an attempt to execute +commands from a nonexistent file. +.PP +Arguments on the command line after the filename are remembered but not +evaluated. Commands in the script file can then refer to these arguments +using the history substitution mechanism. +.PP +EXAMPLE: +.IP +Contents of test.scr: +.IP +.nf + read_blif %:2 + collapse + write_eqn %:2.eqn +.fi +.IP +Typing "source test.scr lion.blif" on the command line will execute the +sequence +.IP +.nf + read_blif lion.blif + collapse + write_eqn lion.blif.eqn +.fi +.IP +If you type "alias st source test.scr" and then type "st lion.blif bozo", you +will execute +.IP +.nf + read_blif bozo + collapse + write_eqn bozo.eqn +.fi +.IP +because "bozo" was the second argument on the last command line typed. In +other words, command substitution in a script file depends on how the script +file was invoked. +.PP +Some standard script files are provided. \fIscript\fR (executed by typing +\fBsource script\fP is a script that works well on most examples. +\fIscript.boolean\fR uses a larger part of the don't care set during two-level +minimization, requiring more time and producing better results. +\fIscript.algebraic\fR uses a smaller part of the don't care set. +\fIscript.rugged\fR uses the newest BDD-based techniques, +and \fIscript.delay\fR synthesizes a circuit for a final +implementation that is optimal with respect to speed. diff --git a/sis/sis_lib/help/source.fmt b/sis/sis_lib/help/source.fmt new file mode 100644 index 0000000..8d7f289 --- /dev/null +++ b/sis/sis_lib/help/source.fmt @@ -0,0 +1,50 @@ + + July 1, 1994 SIS(1) + + source [-psx] filename + + Read commands from a file. The -p option prints a prompt before reading + each command, and the -x option echoes each command before it is exe- + cuted. The -s option silently ignores an attempt to execute commands + from a nonexistent file. + + Arguments on the command line after the filename are remembered but not + evaluated. Commands in the script file can then refer to these argu- + ments using the history substitution mechanism. + + EXAMPLE: + + Contents of test.scr: + + read_blif %:2 + collapse + write_eqn %:2.eqn + + Typing "source test.scr lion.blif" on the command line will execute + the sequence + + read_blif lion.blif + collapse + write_eqn lion.blif.eqn + + If you type "alias st source test.scr" and then type "st lion.blif + bozo", you will execute + + read_blif bozo + collapse + write_eqn bozo.eqn + + because "bozo" was the second argument on the last command line + typed. In other words, command substitution in a script file + depends on how the script file was invoked. + + Some standard script files are provided. _s_c_r_i_p_t (executed by typing + source script is a script that works well on most examples. + _s_c_r_i_p_t._b_o_o_l_e_a_n uses a larger part of the don't care set during two-level + minimization, requiring more time and producing better results. + _s_c_r_i_p_t._a_l_g_e_b_r_a_i_c uses a smaller part of the don't care set. + _s_c_r_i_p_t._r_u_g_g_e_d uses the newest BDD-based techniques, and _s_c_r_i_p_t._d_e_l_a_y + synthesizes a circuit for a final implementation that is optimal with + respect to speed. + + 1 diff --git a/sis/sis_lib/help/speed_up.1 b/sis/sis_lib/help/speed_up.1 new file mode 100644 index 0000000..8918fc7 --- /dev/null +++ b/sis/sis_lib/help/speed_up.1 @@ -0,0 +1,55 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/speed_up.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +speed_up [-m model] [-d #] [-w #] [-t #.#] [-i] [-c] [-T] [-a #] [-vD] node-list +.PP +Speed-up the nodes in the \fBnode-list\fR. If no nodes are +specified, it selects the nodes to be speeded-up in order to +speed-up the entire network. The best decomposition seen +so far is accepted (except with the \fB-c\fR flag). The network +after running speed_up is composed of 2-input AND gates and inverters. +.PP +The \fB-m model\fR option selects the delay model according to +which the delay data is computed. The values allowed for +\fBmodel\fR are \fIunit\fR, \fIunit-fanout\fR and \fImapped\fR. +The \fIunit\fR +delay model counts the level of the circuit as its delay. +The \fIunit-fanout\fR model is intended to capture +a technology-independent model and it assigns a delay of 1 unit to each +gate and 0.2 units to each fanout stem. The \fImapped\fR delay +model uses the delay data in the library to compute delay. +.PP +The \fB-d #\fR option selects the distance up to which the +critical fanins are collapsed in order to do the speed-up. +A fast value is 3, a good one is 6. +.PP +The \fB-t #.#\fR option determines which nodes are considered +critical. The critical nodes are those with a slack within +#.# of the most negative slack. +.PP +The \fB-w #\fR option selects between the area mode and the +pure timing mode. A value of 0 selects pure-timing mode +while a value of 1 will conserve as much area as possible. +.PP +The \fB-i\fR option specifies that only the initial 2-input +NAND decomposition be carried out. +.PP +The \fB-c\fR option specifies that one pass be carried out. +The new decomposition is always accepted, even if it results +in a slower circuit. +.PP +The \fB-T\fR option displays the delay as the iterations progress. +.PP +The \fB-a #\fR option tries to do the specified number of attempts +when restructuring a node. By default the algorithm tries only +one attempt at the restructuring. This option is for experimental +use at this stage. +.PP +The \fB-v\fR and \fB-D\fR options display debugging information. diff --git a/sis/sis_lib/help/speed_up.fmt b/sis/sis_lib/help/speed_up.fmt new file mode 100644 index 0000000..826a616 --- /dev/null +++ b/sis/sis_lib/help/speed_up.fmt @@ -0,0 +1,47 @@ + + July 1, 1994 SIS(1) + + speed_up [-m model] [-d #] [-w #] [-t #.#] [-i] [-c] [-T] [-a #] [-vD] + node-list + + Speed-up the nodes in the node-list. If no nodes are specified, it + selects the nodes to be speeded-up in order to speed-up the entire net- + work. The best decomposition seen so far is accepted (except with the -c + flag). The network after running speed_up is composed of 2-input AND + gates and inverters. + + The -m model option selects the delay model according to which the delay + data is computed. The values allowed for model are _u_n_i_t, _u_n_i_t-_f_a_n_o_u_t and + _m_a_p_p_e_d. The _u_n_i_t delay model counts the level of the circuit as its + delay. The _u_n_i_t-_f_a_n_o_u_t model is intended to capture a technology- + independent model and it assigns a delay of 1 unit to each gate and 0.2 + units to each fanout stem. The _m_a_p_p_e_d delay model uses the delay data in + the library to compute delay. + + The -d # option selects the distance up to which the critical fanins are + collapsed in order to do the speed-up. A fast value is 3, a good one is + 6. + + The -t #.# option determines which nodes are considered critical. The + critical nodes are those with a slack within #.# of the most negative + slack. + + The -w # option selects between the area mode and the pure timing mode. + A value of 0 selects pure-timing mode while a value of 1 will conserve + as much area as possible. + + The -i option specifies that only the initial 2-input NAND decomposition + be carried out. + + The -c option specifies that one pass be carried out. The new decompo- + sition is always accepted, even if it results in a slower circuit. + + The -T option displays the delay as the iterations progress. + + The -a # option tries to do the specified number of attempts when res- + tructuring a node. By default the algorithm tries only one attempt at + the restructuring. This option is for experimental use at this stage. + + The -v and -D options display debugging information. + + 1 diff --git a/sis/sis_lib/help/speedup_alg.1 b/sis/sis_lib/help/speedup_alg.1 new file mode 100644 index 0000000..decdfab --- /dev/null +++ b/sis/sis_lib/help/speedup_alg.1 @@ -0,0 +1,29 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: +.\" * $Author: +.\" * $Revision: +.\" * $Date: +.\" * +.\" +.XX +speedup_alg [-v] alg_list +.PP +Activates selectively one or more performance enhancing algorithms. For a +list of local optimizations known to the system, use the \fB-v\fR option. +The algorithms activated are the ones specified in the list. +For mapped circuits the algorithms perform the optimization and remap +the sub-network that was optimized. \fInoalg\fR performs no +optimization, it only remaps the region. \fIfanout\fR builds a +fanout-tree while \fIrepower\fR simply uses a gate of greater drive +Of the others \fIdivisor\fR and \fI2c_kernel\fR +perform restructuring by extracting kernels and 2-cube divisors. When +applied to the complement of the function these are called +\fIcomp_div\fR and \fIcomp_2c\fR respectively. Techniques based on the +existing structure are \fIcofactor\fR which performs +timing-driven-cofactoring and \fIbypass\fR applies the +generalized-bypass transformation. +.PP +Performance optimization itself is performed using the \fBspeed_up\fR +command without the \fB-f\fR option. diff --git a/sis/sis_lib/help/speedup_alg.fmt b/sis/sis_lib/help/speedup_alg.fmt new file mode 100644 index 0000000..f2b87d9 --- /dev/null +++ b/sis/sis_lib/help/speedup_alg.fmt @@ -0,0 +1,22 @@ + + July 1, 1994 SIS(1) + + speedup_alg [-v] alg_list + + Activates selectively one or more performance enhancing algorithms. For + a list of local optimizations known to the system, use the -v option. + The algorithms activated are the ones specified in the list. For mapped + circuits the algorithms perform the optimization and remap the sub- + network that was optimized. _n_o_a_l_g performs no optimization, it only + remaps the region. _f_a_n_o_u_t builds a fanout-tree while _r_e_p_o_w_e_r simply uses + a gate of greater drive Of the others _d_i_v_i_s_o_r and _2_c__k_e_r_n_e_l perform res- + tructuring by extracting kernels and 2-cube divisors. When applied to + the complement of the function these are called _c_o_m_p__d_i_v and _c_o_m_p__2_c + respectively. Techniques based on the existing structure are _c_o_f_a_c_t_o_r + which performs timing-driven-cofactoring and _b_y_p_a_s_s applies the + generalized-bypass transformation. + + Performance optimization itself is performed using the speed_up command + without the -f option. + + 1 diff --git a/sis/sis_lib/help/state_assign.1 b/sis/sis_lib/help/state_assign.1 new file mode 100644 index 0000000..74e2832 --- /dev/null +++ b/sis/sis_lib/help/state_assign.1 @@ -0,0 +1,35 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/state_assign.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +state_assign progname options +.PP +Perform state assignment on the current STG. +The program used for state assignment is \fBprogname\fP +and it is given the options \fBoptions\fP. +The program \fBprogname\fP must exist somewhere in the user's +path. +.PP +The state assignment program is given the current STG, and +returns a logic implementation. After execution of the \fBstate_assign\fP +command, both the STG and the logic implementation are available +for optimization. +.PP +The state assignment program called must conform to the +specification (see doc/SPEC). +Currently, the programs that are compatible with this specification +and are shipped with SIS are nova and jedi. +To get help information for a specific program, use the -h option +(i.e. \fBstate_assign nova -h\fP would produce help information for +the nova state assignment program). +.PP +A one-hot encoding can be obtained by using \fBstate_assign progname -e h\fP. +Note that nova and jedi produce different results for one-hot encoding. +jedi produces typical one-hot codes (1000) while nova produces one-hot +codes with don't care conditions (1---). diff --git a/sis/sis_lib/help/state_assign.fmt b/sis/sis_lib/help/state_assign.fmt new file mode 100644 index 0000000..eb4f9a8 --- /dev/null +++ b/sis/sis_lib/help/state_assign.fmt @@ -0,0 +1,26 @@ + + July 1, 1994 SIS(1) + + state_assign progname options + + Perform state assignment on the current STG. The program used for state + assignment is progname and it is given the options options. The program + progname must exist somewhere in the user's path. + + The state assignment program is given the current STG, and returns a + logic implementation. After execution of the state_assign command, both + the STG and the logic implementation are available for optimization. + + The state assignment program called must conform to the specification + (see doc/SPEC). Currently, the programs that are compatible with this + specification and are shipped with SIS are nova and jedi. To get help + information for a specific program, use the -h option (i.e. state_assign + nova -h would produce help information for the nova state assignment + program). + + A one-hot encoding can be obtained by using state_assign progname -e h. + Note that nova and jedi produce different results for one-hot encoding. + jedi produces typical one-hot codes (1000) while nova produces one-hot + codes with don't care conditions (1---). + + 1 diff --git a/sis/sis_lib/help/state_minimize.1 b/sis/sis_lib/help/state_minimize.1 new file mode 100644 index 0000000..73e9760 --- /dev/null +++ b/sis/sis_lib/help/state_minimize.1 @@ -0,0 +1,32 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/state_minimize.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +state_minimize progname options +.PP +Perform state minimization on the current STG. +The program used for state minimization is \fBprogname\fP +and it is given the options \fBoptions\fP. +The program \fBprogname\fP must exist somewhere in the user's +path. +.PP +The state minimization program is given the current STG, and +returns a new STG. After execution of the \fBstate_minimize\fP +command, only the STG is available for optimization (any existing +logic implementation is removed, since there is no guarantee that +it implements the new STG). +.PP +The state minimization program called must conform to the +specification (see doc/SPEC). +Currently, the program that is compatible with this specification +and is shipped with \fBSIS\fR is \fBstamina\fR (from the University of Colorado, +Boulder, rho@boulder.colorado.edu). +To get help information for a specific program, use the \fB-h\fR option +(i.e. \fBstate_minimize stamina -h\fP would produce help information for +the \fBstamina\fR state minimization program). diff --git a/sis/sis_lib/help/state_minimize.fmt b/sis/sis_lib/help/state_minimize.fmt new file mode 100644 index 0000000..da0c246 --- /dev/null +++ b/sis/sis_lib/help/state_minimize.fmt @@ -0,0 +1,23 @@ + + July 1, 1994 SIS(1) + + state_minimize progname options + + Perform state minimization on the current STG. The program used for + state minimization is progname and it is given the options options. The + program progname must exist somewhere in the user's path. + + The state minimization program is given the current STG, and returns a + new STG. After execution of the state_minimize command, only the STG is + available for optimization (any existing logic implementation is + removed, since there is no guarantee that it implements the new STG). + + The state minimization program called must conform to the specification + (see doc/SPEC). Currently, the program that is compatible with this + specification and is shipped with SIS is stamina (from the University of + Colorado, Boulder, rho@boulder.colorado.edu). To get help information + for a specific program, use the -h option (i.e. state_minimize stamina + -h would produce help information for the stamina state minimization + program). + + 1 diff --git a/sis/sis_lib/help/stg_cover.1 b/sis/sis_lib/help/stg_cover.1 new file mode 100644 index 0000000..ea6f9d6 --- /dev/null +++ b/sis/sis_lib/help/stg_cover.1 @@ -0,0 +1,19 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/stg_cover.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:40 $ +.\" * +.\" +.XX +stg_cover +.PP +Check to see that the behavior of the STG covers +that of the logic implementation. +This operation is provided for the user to check that +two descriptions of the same machine are consistent. +Each edge in the STG is symbolically simulated in the +logic implementation to ensure that the logic implementation +behaves as specified by the STG. diff --git a/sis/sis_lib/help/stg_cover.fmt b/sis/sis_lib/help/stg_cover.fmt new file mode 100644 index 0000000..5a2ad85 --- /dev/null +++ b/sis/sis_lib/help/stg_cover.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + stg_cover + + Check to see that the behavior of the STG covers that of the logic + implementation. This operation is provided for the user to check that + two descriptions of the same machine are consistent. Each edge in the + STG is symbolically simulated in the logic implementation to ensure that + the logic implementation behaves as specified by the STG. + + 1 diff --git a/sis/sis_lib/help/stg_extract.1 b/sis/sis_lib/help/stg_extract.1 new file mode 100644 index 0000000..ba5346e --- /dev/null +++ b/sis/sis_lib/help/stg_extract.1 @@ -0,0 +1,37 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/stg_extract.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:41 $ +.\" * +.\" +.XX +stg_extract [-a] [-e] [-c] +.PP +Takes the current network and extracts the state transition graph from it. +.PP +If the \fB-a\fP option is not specified, the values on the latches are taken +to be the start state, and every state reachable from the +start state is explored. This is the normal method of execution. +.PP +If the \fB-a\fP option is specified, the state transition graph is extracted +for all possible start states, provided the number of latches does not +exceed 16. This limitation cannot be overridden (there are too many +states to store). +.PP +Extraction of the STG could take an enormous amount of time. +If there are more than 16 latches in the network, \fBstg_extract\fR won't +attempt to extract the STG. +This can be overridden with the \fB-e\fP option. +.PP +At the end of \fBstg_extract\fR, a check is done to ensure that +the behavior of the STG is consistent with that of the logic implementation. +This is done with symbolic simulation using BDDs, and could be expensive. +\fBstg_extract\fR will not do this check for networks with more than +16 latches or more than 500 transitions unless the \fB-c\fR option is given. +.PP +Note: a \fBsweep\fI is done on the network before the STG is extracted. +This removes latches that do not fanout, so the sweep makes the extraction +more efficient. diff --git a/sis/sis_lib/help/stg_extract.fmt b/sis/sis_lib/help/stg_extract.fmt new file mode 100644 index 0000000..e6cd7dc --- /dev/null +++ b/sis/sis_lib/help/stg_extract.fmt @@ -0,0 +1,32 @@ + + July 1, 1994 SIS(1) + + stg_extract [-a] [-e] [-c] + + Takes the current network and extracts the state transition graph from + it. + + If the -a option is not specified, the values on the latches are taken + to be the start state, and every state reachable from the start state is + explored. This is the normal method of execution. + + If the -a option is specified, the state transition graph is extracted + for all possible start states, provided the number of latches does not + exceed 16. This limitation cannot be overridden (there are too many + states to store). + + Extraction of the STG could take an enormous amount of time. If there + are more than 16 latches in the network, stg_extract won't attempt to + extract the STG. This can be overridden with the -e option. + + At the end of stg_extract, a check is done to ensure that the behavior + of the STG is consistent with that of the logic implementation. This is + done with symbolic simulation using BDDs, and could be expensive. + stg_extract will not do this check for networks with more than 16 + latches or more than 500 transitions unless the -c option is given. + + Note: a sweep _i_s _d_o_n_e _o_n _t_h_e _n_e_t_w_o_r_k _b_e_f_o_r_e _t_h_e _S_T_G _i_s _e_x_t_r_a_c_t_e_d. _T_h_i_s + _r_e_m_o_v_e_s _l_a_t_c_h_e_s _t_h_a_t _d_o _n_o_t _f_a_n_o_u_t, _s_o _t_h_e _s_w_e_e_p _m_a_k_e_s _t_h_e _e_x_t_r_a_c_t_i_o_n + _m_o_r_e _e_f_f_i_c_i_e_n_t. + + 1 diff --git a/sis/sis_lib/help/stg_to_astg.1 b/sis/sis_lib/help/stg_to_astg.1 new file mode 100644 index 0000000..ab3471b --- /dev/null +++ b/sis/sis_lib/help/stg_to_astg.1 @@ -0,0 +1,26 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/stg_to_astg.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:45 $ +.\" * +.\" +.XX +stg_to_astg [-v debug_level] +.PP +Transforms the current State Transition Graph (that must satisfy the +Single Cube Restriction, see \fBastg_stg_scr\fR) into a Signal Transition +Graph. +.PP +Can be used to transform a burst-mode +Flow Table specification (written in .kiss format +and read using \fBread_kiss\fR) of an asynchronous circuit into a Signal +Transition Graph for subsequent encoding and synthesis (see +\fBastg_state_min\fR, \fBastg_to_f\fR and \fBastg_syn\fR). +.PP +Burst mode means that the circuit specified by the Flow Table may change state +only after all signals in a specified set (a "burst") have changed value. Many +bursts can occur from a given state, but no burst can be a subset of another +burst from the same state (or else meta-stability can occur). diff --git a/sis/sis_lib/help/stg_to_astg.fmt b/sis/sis_lib/help/stg_to_astg.fmt new file mode 100644 index 0000000..d880625 --- /dev/null +++ b/sis/sis_lib/help/stg_to_astg.fmt @@ -0,0 +1,21 @@ + + July 1, 1994 SIS(1) + + stg_to_astg [-v debug_level] + + Transforms the current State Transition Graph (that must satisfy the + Single Cube Restriction, see astg_stg_scr) into a Signal Transition + Graph. + + Can be used to transform a burst-mode Flow Table specification (written + in .kiss format and read using read_kiss) of an asynchronous circuit + into a Signal Transition Graph for subsequent encoding and synthesis + (see astg_state_min, astg_to_f and astg_syn). + + Burst mode means that the circuit specified by the Flow Table may change + state only after all signals in a specified set (a "burst") have changed + value. Many bursts can occur from a given state, but no burst can be a + subset of another burst from the same state (or else meta-stability can + occur). + + 1 diff --git a/sis/sis_lib/help/stg_to_network.1 b/sis/sis_lib/help/stg_to_network.1 new file mode 100644 index 0000000..c394747 --- /dev/null +++ b/sis/sis_lib/help/stg_to_network.1 @@ -0,0 +1,33 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/stg_to_network.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:41 $ +.\" * +.\" +.XX +stg_to_network [-e option] +.PP +Takes the current state-encoded state transition graph and generates +an optimized two-level logic network. The initial mapping is optimized +using a two-level Boolean minimizer (i.e. \fBespresso\fR) +along with the invalid +state codes as don't cares. +\fB-e\fR allows the user to specify how +the two-level logic-encoded network should be processed using \fBespresso\fR. +The option can be +either 0, 1, or 2. +The \fB-e 0\fR option simply runs espresso and executes \fBread_pla\fR. +The \fB-e 1\fR option runs \fBespresso\fR, but does a +\fBread_pla -s\fR instead. +This reads in the PLA in single-level form (fully collapsed) rather than +two-level form. +This often produces better results. +The \fB-e 2\fR option +runs \fBespresso -Dso\fR, which does a single-output minimization. +Again, \fBread_pla -s\fR is used. +This option also produces better results for some +cases, but typically takes more time. +The default is the \fB-e 1\fR option. diff --git a/sis/sis_lib/help/stg_to_network.fmt b/sis/sis_lib/help/stg_to_network.fmt new file mode 100644 index 0000000..16dae9e --- /dev/null +++ b/sis/sis_lib/help/stg_to_network.fmt @@ -0,0 +1,20 @@ + + July 1, 1994 SIS(1) + + stg_to_network [-e option] + + Takes the current state-encoded state transition graph and generates an + optimized two-level logic network. The initial mapping is optimized + using a two-level Boolean minimizer (i.e. espresso) along with the + invalid state codes as don't cares. -e allows the user to specify how + the two-level logic-encoded network should be processed using espresso. + The option can be either 0, 1, or 2. The -e 0 option simply runs + espresso and executes read_pla. The -e 1 option runs espresso, but does + a read_pla -s instead. This reads in the PLA in single-level form + (fully collapsed) rather than two-level form. This often produces + better results. The -e 2 option runs espresso -Dso, which does a + single-output minimization. Again, read_pla -s is used. This option + also produces better results for some cases, but typically takes more + time. The default is the -e 1 option. + + 1 diff --git a/sis/sis_lib/help/sweep.1 b/sis/sis_lib/help/sweep.1 new file mode 100644 index 0000000..5b24db2 --- /dev/null +++ b/sis/sis_lib/help/sweep.1 @@ -0,0 +1,17 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/sweep.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:38 $ +.\" * +.\" +.XX +sweep +.PP +Successively eliminate all the single-input nodes and constant nodes +(0 or 1) from the current network. +.PP +NOTE: Successfully invoking a sweep command on a mapped network can +possibly "unmap" the network. diff --git a/sis/sis_lib/help/sweep.fmt b/sis/sis_lib/help/sweep.fmt new file mode 100644 index 0000000..6771a29 --- /dev/null +++ b/sis/sis_lib/help/sweep.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + sweep + + Successively eliminate all the single-input nodes and constant nodes (0 + or 1) from the current network. + + NOTE: Successfully invoking a sweep command on a mapped network can pos- + sibly "unmap" the network. + + 1 diff --git a/sis/sis_lib/help/tech_decomp.1 b/sis/sis_lib/help/tech_decomp.1 new file mode 100644 index 0000000..efb5b20 --- /dev/null +++ b/sis/sis_lib/help/tech_decomp.1 @@ -0,0 +1,20 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/tech_decomp.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:41 $ +.\" * +.\" +.XX +tech_decomp [-a and-limit] [-o or-limit] +.PP +Decompose all the nodes in the current network into AND gates +or OR gates or both depending on whether \fB-a\fR, +\fB-o\fR, or both flags are specified. +The fanins of AND gates +will be no more than \fBand-limit\fR and that of the OR gates +will be no more than \fBor-limit\fR. \fBand-limit\fR and +\fBor-limit\fR, if specified, must be at least 2. +The default option is \fB-a 2\fR. diff --git a/sis/sis_lib/help/tech_decomp.fmt b/sis/sis_lib/help/tech_decomp.fmt new file mode 100644 index 0000000..246ce9a --- /dev/null +++ b/sis/sis_lib/help/tech_decomp.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + tech_decomp [-a and-limit] [-o or-limit] + + Decompose all the nodes in the current network into AND gates or OR + gates or both depending on whether -a, -o, or both flags are specified. + The fanins of AND gates will be no more than and-limit and that of the + OR gates will be no more than or-limit. and-limit and or-limit, if + specified, must be at least 2. The default option is -a 2. + + 1 diff --git a/sis/sis_lib/help/time.1 b/sis/sis_lib/help/time.1 new file mode 100644 index 0000000..00c8063 --- /dev/null +++ b/sis/sis_lib/help/time.1 @@ -0,0 +1,14 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/time.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:41 $ +.\" * +.\" +.XX +time +.PP +Prints the processor time used since the last time command, and the total +processor time used since \fBSIS\fR was started. diff --git a/sis/sis_lib/help/time.fmt b/sis/sis_lib/help/time.fmt new file mode 100644 index 0000000..77d7517 --- /dev/null +++ b/sis/sis_lib/help/time.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + time + + Prints the processor time used since the last time command, and the + total processor time used since SIS was started. + + 1 diff --git a/sis/sis_lib/help/timeout.1 b/sis/sis_lib/help/timeout.1 new file mode 100644 index 0000000..c084c2c --- /dev/null +++ b/sis/sis_lib/help/timeout.1 @@ -0,0 +1,19 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/timeout.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:41 $ +.\" * +.\" +.XX +timeout [-t n] [-k] +.PP +Sends an interrupt to the \fBSIS\fR process. With no argument, this +routine inactivates any previous calls. +.PP +The \fB-t n\fP specifies the timeout limit, in seconds. +.PP +The \fB-k\fP option specifies that a kill signal is to be sent to +\fBSIS\fR rather than a interrupt signal. diff --git a/sis/sis_lib/help/timeout.fmt b/sis/sis_lib/help/timeout.fmt new file mode 100644 index 0000000..f06b089 --- /dev/null +++ b/sis/sis_lib/help/timeout.fmt @@ -0,0 +1,14 @@ + + July 1, 1994 SIS(1) + + timeout [-t n] [-k] + + Sends an interrupt to the SIS process. With no argument, this routine + inactivates any previous calls. + + The -t n specifies the timeout limit, in seconds. + + The -k option specifies that a kill signal is to be sent to SIS rather + than a interrupt signal. + + 1 diff --git a/sis/sis_lib/help/trail b/sis/sis_lib/help/trail new file mode 100755 index 0000000..37b8eba --- /dev/null +++ b/sis/sis_lib/help/trail @@ -0,0 +1,11 @@ +#! /bin/awk -f + +NF == 0 { + blank++; +} +NF > 0 { + if (blank > 1) blank = 1; + for(i = 0; i < blank; i++) print " "; + blank = 0; + print $0; +} diff --git a/sis/sis_lib/help/unalias.1 b/sis/sis_lib/help/unalias.1 new file mode 100644 index 0000000..57ccb02 --- /dev/null +++ b/sis/sis_lib/help/unalias.1 @@ -0,0 +1,23 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/unalias.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:41 $ +.\" * +.\" +.XX +alias [name [string]] +.X1 +unalias name ... +.PP +The \fBalias\fR command, if given no arguments, will print the +definition of all current aliases. +Given a single argument, it +will print the definition of that alias (if any). +Given two +arguments, the keyword \fBname\fP becomes an alias for +the command string \fBstring\fP, replacing any other alias with the +same name. +The \fBunalias\fR command removes the definition of an alias. diff --git a/sis/sis_lib/help/unalias.fmt b/sis/sis_lib/help/unalias.fmt new file mode 100644 index 0000000..dbb00a4 --- /dev/null +++ b/sis/sis_lib/help/unalias.fmt @@ -0,0 +1,14 @@ + + July 1, 1994 SIS(1) + + alias [name [string]] + unalias name ... + + The alias command, if given no arguments, will print the definition of + all current aliases. Given a single argument, it will print the defini- + tion of that alias (if any). Given two arguments, the keyword name + becomes an alias for the command string string, replacing any other + alias with the same name. The unalias command removes the definition of + an alias. + + 1 diff --git a/sis/sis_lib/help/undo.1 b/sis/sis_lib/help/undo.1 new file mode 100644 index 0000000..fbb95ac --- /dev/null +++ b/sis/sis_lib/help/undo.1 @@ -0,0 +1,18 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/undo.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:41 $ +.\" * +.\" +.XX +undo +.PP +A simple 1-level undo is supported. +It reverts the network to its state +before the last command which changed the network. +Note that interrupting +a command (with ^C) which changes the network +uses up the one level of undo. diff --git a/sis/sis_lib/help/undo.fmt b/sis/sis_lib/help/undo.fmt new file mode 100644 index 0000000..22637c7 --- /dev/null +++ b/sis/sis_lib/help/undo.fmt @@ -0,0 +1,11 @@ + + July 1, 1994 SIS(1) + + undo + + A simple 1-level undo is supported. It reverts the network to its state + before the last command which changed the network. Note that interrupt- + ing a command (with ^C) which changes the network uses up the one level + of undo. + + 1 diff --git a/sis/sis_lib/help/unset.fmt b/sis/sis_lib/help/unset.fmt new file mode 100644 index 0000000..12777eb --- /dev/null +++ b/sis/sis_lib/help/unset.fmt @@ -0,0 +1,38 @@ + + July 1, 1994 SIS(1) + + set [name] [value] + unset name ... + + A variable environment is maintained by the command interpreter. The + set command sets a variable to a particular value, and the unset command + removes the definition of a variable. If set is given no arguments, it + prints the definition of all variables. + + Different commands use environment information for different purposes. + The command interpreter makes use of the following: + + autoexec + Defines a command string to be automatically executed after + every command processed by the command interpreter. This is + useful for things like timing commands, or tracing the progress + of optimization. + + sisout Standard output (normally stdout) can be re-directed to a file + by setting the variable sisout. + + siserr Standard error (normally stderr) can be re-directed to a file by + setting the variable siserr. + + open_path + open_path (in analogy to the shell-variable PATH) is a list of + colon-separated strings giving directories to be searched when- + ever a file is opened for read. Typically the current directory + (.) is first in this list. The standard system library (typi- + cally $SIS/sis_lib) is always implicitly appended to the current + path. This provides a convenient short-hand mechanism for + reaching standard library files. + + prompt defines the prompt string + + 1 diff --git a/sis/sis_lib/help/usage.1 b/sis/sis_lib/help/usage.1 new file mode 100644 index 0000000..3e1e7c5 --- /dev/null +++ b/sis/sis_lib/help/usage.1 @@ -0,0 +1,15 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/usage.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:41 $ +.\" * +.\" +.XX +usage +.PP +Prints a formatted dump of processor-specific usage statistics. +For Berkeley Unix, this includes all of the information in the +\fIgetrusage()\fR structure. diff --git a/sis/sis_lib/help/usage.fmt b/sis/sis_lib/help/usage.fmt new file mode 100644 index 0000000..549ccb6 --- /dev/null +++ b/sis/sis_lib/help/usage.fmt @@ -0,0 +1,10 @@ + + July 1, 1994 SIS(1) + + usage + + Prints a formatted dump of processor-specific usage statistics. For + Berkeley Unix, this includes all of the information in the _g_e_t_r_u_s_a_g_e() + structure. + + 1 diff --git a/sis/sis_lib/help/verify.1 b/sis/sis_lib/help/verify.1 new file mode 100644 index 0000000..96ba4d1 --- /dev/null +++ b/sis/sis_lib/help/verify.1 @@ -0,0 +1,25 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/verify.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:41 $ +.\" * +.\" +.XX +verify [-m method] [-v] file1 [file2] +.PP +Verify the Boolean equivalence of two networks. \fBfile1\fR +is compared with the current network when \fBfile2\fR is not +specified, otherwise, \fBfile1\fR is compared with \fBfile2\fR. +The input and output variables from two networks are associated +by their names. +.PP +The \fB-m\fR option specifies the verification method. +If \fBmethod\fR is \fIclp\fR (default), two networks are collapsed and +compared as PLA's. +If \fBmethod\fR is \fIbdd\fR, the BDD's are constructed for both networks and +compared. +.PP +The \fB-v\fR option engages the "verbose" mode of verify. diff --git a/sis/sis_lib/help/verify.fmt b/sis/sis_lib/help/verify.fmt new file mode 100644 index 0000000..5d02de6 --- /dev/null +++ b/sis/sis_lib/help/verify.fmt @@ -0,0 +1,17 @@ + + July 1, 1994 SIS(1) + + verify [-m method] [-v] file1 [file2] + + Verify the Boolean equivalence of two networks. file1 is compared with + the current network when file2 is not specified, otherwise, file1 is + compared with file2. The input and output variables from two networks + are associated by their names. + + The -m option specifies the verification method. If method is _c_l_p + (default), two networks are collapsed and compared as PLA's. If method + is _b_d_d, the BDD's are constructed for both networks and compared. + + The -v option engages the "verbose" mode of verify. + + 1 diff --git a/sis/sis_lib/help/verify_fsm.1 b/sis/sis_lib/help/verify_fsm.1 new file mode 100644 index 0000000..af4b3e1 --- /dev/null +++ b/sis/sis_lib/help/verify_fsm.1 @@ -0,0 +1,43 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/verify_fsm.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +verify_fsm [-o depth] [-v n] [-m method] filename.blif +.PP +Verify the equivalence of two synchronous networks. +The current network is compared with \fBfilename.blif\fR. +The input and output variables from the two networks are +associated by their names. +It is assumed that all the latches in both designs are clocked +by a single, global clock. +The verification is done by implicitly enumerating all the +states in the product machine, and checking that the outputs +are equivalent for all reachable state pairs starting +from the initial state of the product machine. +.PP +\fB-o depth\fR allows the specification of the depth of search for a good +variable ordering. +A larger value for depth will require more CPU time but determine +a better ordering. +The default value is 2. +.PP +\fB-v\fR allows specification of the verbosity level of the output. +.PP +The \fB-m\fR option specifies \fBmethod\fR for determining +the reachable states. +\fBconsistency\fR builds the entire transition relation +and uses it to determine the reached states. +\fBbull\fR does output cofactoring to find the reachable +states. +The \fBproduct\fR method is similar to the \fBconsistency\fR method but +input variables are smoothed as soon as possible as the characteristic +function is being built. +This makes the size of the resulting BDD representing the +characteristic function of the transition relation smaller. +The default method is \fBproduct\fR. diff --git a/sis/sis_lib/help/verify_fsm.fmt b/sis/sis_lib/help/verify_fsm.fmt new file mode 100644 index 0000000..9b50e41 --- /dev/null +++ b/sis/sis_lib/help/verify_fsm.fmt @@ -0,0 +1,30 @@ + + July 1, 1994 SIS(1) + + verify_fsm [-o depth] [-v n] [-m method] filename.blif + + Verify the equivalence of two synchronous networks. The current network + is compared with filename.blif. The input and output variables from the + two networks are associated by their names. It is assumed that all the + latches in both designs are clocked by a single, global clock. The + verification is done by implicitly enumerating all the states in the + product machine, and checking that the outputs are equivalent for all + reachable state pairs starting from the initial state of the product + machine. + + -o depth allows the specification of the depth of search for a good + variable ordering. A larger value for depth will require more CPU time + but determine a better ordering. The default value is 2. + + -v allows specification of the verbosity level of the output. + + The -m option specifies method for determining the reachable states. + consistency builds the entire transition relation and uses it to deter- + mine the reached states. bull does output cofactoring to find the + reachable states. The product method is similar to the consistency + method but input variables are smoothed as soon as possible as the + characteristic function is being built. This makes the size of the + resulting BDD representing the characteristic function of the transition + relation smaller. The default method is product. + + 1 diff --git a/sis/sis_lib/help/wd.1 b/sis/sis_lib/help/wd.1 new file mode 100644 index 0000000..e57aa98 --- /dev/null +++ b/sis/sis_lib/help/wd.1 @@ -0,0 +1,19 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/wd.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +wd [-c] node1 node2 +.PP +The \fBwd\fR command (which stands for "weak division") is very similiar +to resubstitution (\fBresub\fR command), except that instead of operating +on the entire network, \fBwd\fR simply re-expresses \fBnode1\fR +in terms of \fBnode2\fR. +.PP +The \fB-c\fR option allows re-substitution of the +complement of \fBnode2\fR. diff --git a/sis/sis_lib/help/wd.fmt b/sis/sis_lib/help/wd.fmt new file mode 100644 index 0000000..447b838 --- /dev/null +++ b/sis/sis_lib/help/wd.fmt @@ -0,0 +1,12 @@ + + July 1, 1994 SIS(1) + + wd [-c] node1 node2 + + The wd command (which stands for "weak division") is very similiar to + resubstitution (resub command), except that instead of operating on the + entire network, wd simply re-expresses node1 in terms of node2. + + The -c option allows re-substitution of the complement of node2. + + 1 diff --git a/sis/sis_lib/help/write_astg.1 b/sis/sis_lib/help/write_astg.1 new file mode 100644 index 0000000..d28b036 --- /dev/null +++ b/sis/sis_lib/help/write_astg.1 @@ -0,0 +1,21 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/write_astg.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +write_astg [-p] [<file-name>] +.PP +Write a text description of an ASTG to a file, or stdout if no filename +is given. +See read_astg for a description of the format. +.PP +The -p option forces implied places to be written explicitly in the +description. +Normally a place with exactly one fanin and one fanout transition +is suppressed by specifying the fanout transition +as adjacent to the fanin transition. diff --git a/sis/sis_lib/help/write_astg.fmt b/sis/sis_lib/help/write_astg.fmt new file mode 100644 index 0000000..604ac93 --- /dev/null +++ b/sis/sis_lib/help/write_astg.fmt @@ -0,0 +1,14 @@ + + July 1, 1994 SIS(1) + + write_astg [-p] [<file-name>] + + Write a text description of an ASTG to a file, or stdout if no filename + is given. See read_astg for a description of the format. + + The -p option forces implied places to be written explicitly in the + description. Normally a place with exactly one fanin and one fanout + transition is suppressed by specifying the fanout transition as adjacent + to the fanin transition. + + 1 diff --git a/sis/sis_lib/help/write_bdnet.1 b/sis/sis_lib/help/write_bdnet.1 new file mode 100644 index 0000000..1310e2e --- /dev/null +++ b/sis/sis_lib/help/write_bdnet.1 @@ -0,0 +1,28 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/write_bdnet.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +write_bdnet [filename] +.PP +Write the current network to file \fBfilename\fP in the format +for a net-list defined by bdnet(1). +This is allowed only after the network has been mapped into a final +implementation technology. +.PP +The environment variable OCT-CELL-PATH defines where the cell library +is located. If a cell does not have a leading '~' or '/' in its name, +then OCT-CELL-PATH is prepended to the filename. +.PP +The variable OCT-CELL-VIEW defines the viewname to be used if the cell +does not have a ':' in its name to separate the cell name from the view +name. +.PP +The variables OCT-TECHNOLOGY, OCT-VIEWTYPE, and OCT-EDITSTYLE define +the technology, view-type, and edit-style properties for the Oct cell. + diff --git a/sis/sis_lib/help/write_bdnet.fmt b/sis/sis_lib/help/write_bdnet.fmt new file mode 100644 index 0000000..bf1044a --- /dev/null +++ b/sis/sis_lib/help/write_bdnet.fmt @@ -0,0 +1,21 @@ + + July 1, 1994 SIS(1) + + write_bdnet [filename] + + Write the current network to file filename in the format for a net-list + defined by bdnet(1). This is allowed only after the network has been + mapped into a final implementation technology. + + The environment variable OCT-CELL-PATH defines where the cell library is + located. If a cell does not have a leading '~' or '/' in its name, then + OCT-CELL-PATH is prepended to the filename. + + The variable OCT-CELL-VIEW defines the viewname to be used if the cell + does not have a ':' in its name to separate the cell name from the view + name. + + The variables OCT-TECHNOLOGY, OCT-VIEWTYPE, and OCT-EDITSTYLE define the + technology, view-type, and edit-style properties for the Oct cell. + + 1 diff --git a/sis/sis_lib/help/write_blif.1 b/sis/sis_lib/help/write_blif.1 new file mode 100644 index 0000000..c041436 --- /dev/null +++ b/sis/sis_lib/help/write_blif.1 @@ -0,0 +1,21 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/write_blif.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +write_blif [-s] [-n] [filename] +.PP +Write the current network to file \fBfilename\fP in the Berkeley +Logic Interchange Format (\fIblif\fP). +.PP +The \fB-s\fP option uses the network short names rather than the +network long names for the \fIblif\fP file. +This can be used to encrypt the names of a net-list. +.PP +The \fB-n\fP option uses the net-list format of \fIblif\fP when +a node has a gate implementation in the library. diff --git a/sis/sis_lib/help/write_blif.fmt b/sis/sis_lib/help/write_blif.fmt new file mode 100644 index 0000000..6b210e2 --- /dev/null +++ b/sis/sis_lib/help/write_blif.fmt @@ -0,0 +1,16 @@ + + July 1, 1994 SIS(1) + + write_blif [-s] [-n] [filename] + + Write the current network to file filename in the Berkeley Logic Inter- + change Format (_b_l_i_f). + + The -s option uses the network short names rather than the network long + names for the _b_l_i_f file. This can be used to encrypt the names of a + net-list. + + The -n option uses the net-list format of _b_l_i_f when a node has a gate + implementation in the library. + + 1 diff --git a/sis/sis_lib/help/write_eqn.1 b/sis/sis_lib/help/write_eqn.1 new file mode 100644 index 0000000..d1d4aff --- /dev/null +++ b/sis/sis_lib/help/write_eqn.1 @@ -0,0 +1,26 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/write_eqn.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +write_eqn [-s] [filename] +.PP +The \fBwrite_eqn\fR command prints out the equations from the current +network according to format specifications laid out in the +documentation for \fBread_eqn\fR. +Both primary inputs and outputs are indicated. +.PP +The \fB-s\fR option uses the network short names rather than the +network long names for the output. +.PP +If \fBfilename\fR is not specified the equations will be written to +standard out, otherwise they will be written into the given file and +may be read by \fBread_blif\fR at a later time. +.PP +Note that since the eqn format uses the '(' and ')' characters +for grouping, they cannot appear in any of the signal names. diff --git a/sis/sis_lib/help/write_eqn.fmt b/sis/sis_lib/help/write_eqn.fmt new file mode 100644 index 0000000..c8556b4 --- /dev/null +++ b/sis/sis_lib/help/write_eqn.fmt @@ -0,0 +1,20 @@ + + July 1, 1994 SIS(1) + + write_eqn [-s] [filename] + + The write_eqn command prints out the equations from the current network + according to format specifications laid out in the documentation for + read_eqn. Both primary inputs and outputs are indicated. + + The -s option uses the network short names rather than the network long + names for the output. + + If filename is not specified the equations will be written to standard + out, otherwise they will be written into the given file and may be read + by read_blif at a later time. + + Note that since the eqn format uses the '(' and ')' characters for + grouping, they cannot appear in any of the signal names. + + 1 diff --git a/sis/sis_lib/help/write_kiss.1 b/sis/sis_lib/help/write_kiss.1 new file mode 100644 index 0000000..ca746f8 --- /dev/null +++ b/sis/sis_lib/help/write_kiss.1 @@ -0,0 +1,14 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/write_kiss.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +write_kiss [filename] +.PP +The current state transition graph is saved in \fIkiss2\fP format to the +file \fBfilename\fP or printed to the screen if no filename is given. diff --git a/sis/sis_lib/help/write_kiss.fmt b/sis/sis_lib/help/write_kiss.fmt new file mode 100644 index 0000000..7bbaa91 --- /dev/null +++ b/sis/sis_lib/help/write_kiss.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + write_kiss [filename] + + The current state transition graph is saved in _k_i_s_s_2 format to the file + filename or printed to the screen if no filename is given. + + 1 diff --git a/sis/sis_lib/help/write_oct.1 b/sis/sis_lib/help/write_oct.1 new file mode 100644 index 0000000..4b63e2f --- /dev/null +++ b/sis/sis_lib/help/write_oct.1 @@ -0,0 +1,33 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/write_oct.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +write_oct [-m] cell[:view] +.PP +Write the current network to the Oct facet \fBcell:view:contents\fR. +If \fBview\fR is not specified, it will default to `logic'. +.PP +If the \fB-m\fR flag is specified, the network is merged into an existing +network. +All of the logic elements and internal nets are ripped up and replaced +with the new network. +Oct net names are used to determine how to merge in the network, so +if the net names at the interface of the logic are not defined the +merge will fail. +.PP +The environment variable OCT-CELL-PATH defines where the cell library +is located. If a cell does not have a leading '~' or '/' in its name, +then OCT-CELL-PATH is prepended to the filename. +.PP +The variable OCT-CELL-VIEW defines the viewname to be used if the cell +does not have a ':' in its name to separate the cell name from the view +name. +.PP +The variables OCT-TECHNOLOGY, OCT-VIEWTYPE, and OCT-EDITSTYLE define +the technology, view-type, and edit-style properties for the Oct facet. diff --git a/sis/sis_lib/help/write_oct.fmt b/sis/sis_lib/help/write_oct.fmt new file mode 100644 index 0000000..1cb7422 --- /dev/null +++ b/sis/sis_lib/help/write_oct.fmt @@ -0,0 +1,26 @@ + + July 1, 1994 SIS(1) + + write_oct [-m] cell[:view] + + Write the current network to the Oct facet cell:view:contents. If view + is not specified, it will default to `logic'. + + If the -m flag is specified, the network is merged into an existing net- + work. All of the logic elements and internal nets are ripped up and + replaced with the new network. Oct net names are used to determine how + to merge in the network, so if the net names at the interface of the + logic are not defined the merge will fail. + + The environment variable OCT-CELL-PATH defines where the cell library is + located. If a cell does not have a leading '~' or '/' in its name, then + OCT-CELL-PATH is prepended to the filename. + + The variable OCT-CELL-VIEW defines the viewname to be used if the cell + does not have a ':' in its name to separate the cell name from the view + name. + + The variables OCT-TECHNOLOGY, OCT-VIEWTYPE, and OCT-EDITSTYLE define the + technology, view-type, and edit-style properties for the Oct facet. + + 1 diff --git a/sis/sis_lib/help/write_pds.1 b/sis/sis_lib/help/write_pds.1 new file mode 100644 index 0000000..ffff2bc --- /dev/null +++ b/sis/sis_lib/help/write_pds.1 @@ -0,0 +1,24 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/write_pds.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:36 $ +.\" * +.\" +.XX +write_pds [-c] [-d] [-s] [filename] +.PP +Write the current network to file \fBfilename\fP in the \fIpds\fP +format suitable for Xilinx. +The \fIpds\fP descriptions are generated for single output CLBs +(LUTs) only. +.PP +The \fB-c\fP option indicates that only the combinational portion +of the network should be written out. +.PP +The \fB-d\fP option will cause debugging information to be printed. +.PP +The \fB-s\fP option uses the network short names rather than the +network long names for the \fIpds\fP file. diff --git a/sis/sis_lib/help/write_pds.fmt b/sis/sis_lib/help/write_pds.fmt new file mode 100644 index 0000000..49dc214 --- /dev/null +++ b/sis/sis_lib/help/write_pds.fmt @@ -0,0 +1,18 @@ + + July 1, 1994 SIS(1) + + write_pds [-c] [-d] [-s] [filename] + + Write the current network to file filename in the _p_d_s format suitable + for Xilinx. The _p_d_s descriptions are generated for single output CLBs + (LUTs) only. + + The -c option indicates that only the combinational portion of the net- + work should be written out. + + The -d option will cause debugging information to be printed. + + The -s option uses the network short names rather than the network long + names for the _p_d_s file. + + 1 diff --git a/sis/sis_lib/help/write_pla.1 b/sis/sis_lib/help/write_pla.1 new file mode 100644 index 0000000..dba76fc --- /dev/null +++ b/sis/sis_lib/help/write_pla.1 @@ -0,0 +1,14 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/write_pla.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +write_pla [filename] +.PP +Write the current network to file \fBfilename\fP in the Berkeley +PLA Format. No optimization is done on the PLA. diff --git a/sis/sis_lib/help/write_pla.fmt b/sis/sis_lib/help/write_pla.fmt new file mode 100644 index 0000000..671c415 --- /dev/null +++ b/sis/sis_lib/help/write_pla.fmt @@ -0,0 +1,9 @@ + + July 1, 1994 SIS(1) + + write_pla [filename] + + Write the current network to file filename in the Berkeley PLA Format. + No optimization is done on the PLA. + + 1 diff --git a/sis/sis_lib/help/write_slif.1 b/sis/sis_lib/help/write_slif.1 new file mode 100644 index 0000000..2d6587c --- /dev/null +++ b/sis/sis_lib/help/write_slif.1 @@ -0,0 +1,26 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/write_slif.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +write_slif [-s] [-n] [-d] [filename] +.PP +Write the current network to the file \fBfilename\fP in the Stanford Logic +Interchange Format (\fISLIF\fP). +.PP +The \fB-s\fP option uses the network short names rather than the network +long names for the \fISLIF\fP file. This can be used to encrypt the names of a +net-list. +.PP +The \fB-n\fP option uses the net-list format of \fISLIF\fP when a node has a +gate implementation in the library. +.PP +The \fB-d\fP option makes the \fISLIF\fR writer print out any delay information +known about the current network. This is not the default because a standard +for printing delay information has not been established for the +\fISLIF\fP format. diff --git a/sis/sis_lib/help/write_slif.fmt b/sis/sis_lib/help/write_slif.fmt new file mode 100644 index 0000000..0d254a4 --- /dev/null +++ b/sis/sis_lib/help/write_slif.fmt @@ -0,0 +1,21 @@ + + July 1, 1994 SIS(1) + + write_slif [-s] [-n] [-d] [filename] + + Write the current network to the file filename in the Stanford Logic + Interchange Format (_S_L_I_F). + + The -s option uses the network short names rather than the network long + names for the _S_L_I_F file. This can be used to encrypt the names of a + net-list. + + The -n option uses the net-list format of _S_L_I_F when a node has a gate + implementation in the library. + + The -d option makes the _S_L_I_F writer print out any delay information + known about the current network. This is not the default because a + standard for printing delay information has not been established for the + _S_L_I_F format. + + 1 diff --git a/sis/sis_lib/help/xilinx.1 b/sis/sis_lib/help/xilinx.1 new file mode 100644 index 0000000..a580f3f --- /dev/null +++ b/sis/sis_lib/help/xilinx.1 @@ -0,0 +1,87 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xilinx.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +XILINX +.br +Description +.br +.PP +This is a package to optimize the Boolean network and map it onto +the Xilinx Programmable Gate Array architecture +(reference: Xilinx, the Programmable Gate Array Data Book, +Xilinx Corporation). +All the routines except \fBxl_merge\fR can be used to map the design +onto an architecture with a CLB (Configurable Logic Block) realizing an +arbitrary function of up to n inputs, where n >= 2. +The package contains the following commands available to the user +for experimentation. +.br +.PP +Suggested script +.br +.PP +time +.br +.PP +sweep +.br +.PP +simplify +.br +.PP +sweep +.br +.PP +simplify +.br +.PP +xl_split -n 5 +.br +.PP +sweep +.br +.PP +simplify +.br +.PP +xl_split -n 5 +.br +.PP +sweep +.br +.PP +xl_partition -n 5 +.br +.PP +sweep +.br +.PP +simplify +.br +.PP +xl_partition -n 5 +.br +.PP +sweep +.br +.PP +xl_k_decomp -n 5 +.br +.PP +sweep +.br +.PP +xl_cover -n 5 -h 3 +.br +.PP +xl_merge +.br +.PP +time diff --git a/sis/sis_lib/help/xilinx.fmt b/sis/sis_lib/help/xilinx.fmt new file mode 100644 index 0000000..0bbcdf8 --- /dev/null +++ b/sis/sis_lib/help/xilinx.fmt @@ -0,0 +1,57 @@ + + July 1, 1994 SIS(1) + + XILINX + Description + + This is a package to optimize the Boolean network and map it onto the + Xilinx Programmable Gate Array architecture (reference: Xilinx, the Pro- + grammable Gate Array Data Book, Xilinx Corporation). All the routines + except xl_merge can be used to map the design onto an architecture with + a CLB (Configurable Logic Block) realizing an arbitrary function of up + to n inputs, where n >= 2. The package contains the following commands + available to the user for experimentation. + + Suggested script + + time + + sweep + + simplify + + sweep + + simplify + + xl_split -n 5 + + sweep + + simplify + + xl_split -n 5 + + sweep + + xl_partition -n 5 + + sweep + + simplify + + xl_partition -n 5 + + sweep + + xl_k_decomp -n 5 + + sweep + + xl_cover -n 5 -h 3 + + xl_merge + + time + + 1 diff --git a/sis/sis_lib/help/xl_absorb.1 b/sis/sis_lib/help/xl_absorb.1 new file mode 100644 index 0000000..2338742 --- /dev/null +++ b/sis/sis_lib/help/xl_absorb.1 @@ -0,0 +1,27 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_absorb.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +xl_absorb [-n support] [-f MAX_FANINS] [-v] +.PP +Given a possibly infeasible network, moves fanins of the nodes so as +to decrease their number of fanins. Some infeasible +nodes may become feasible and decomposition may not be applied on +them. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.br +.PP +\fB-f\fP: Does not move fanins of a node if it has more than MAX_FANINS +(default 15). +.br +.PP +\fB-v\fP: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + diff --git a/sis/sis_lib/help/xl_absorb.fmt b/sis/sis_lib/help/xl_absorb.fmt new file mode 100644 index 0000000..41b4983 --- /dev/null +++ b/sis/sis_lib/help/xl_absorb.fmt @@ -0,0 +1,18 @@ + + July 1, 1994 SIS(1) + + xl_absorb [-n support] [-f MAX_FANINS] [-v] + + Given a possibly infeasible network, moves fanins of the nodes so as to + decrease their number of fanins. Some infeasible nodes may become feasi- + ble and decomposition may not be applied on them. + + -n: support is the size of the TLU block (default = 5) + + -f: Does not move fanins of a node if it has more than MAX_FANINS + (default 15). + + -v: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + + 1 diff --git a/sis/sis_lib/help/xl_ao.1 b/sis/sis_lib/help/xl_ao.1 new file mode 100644 index 0000000..4a6541f --- /dev/null +++ b/sis/sis_lib/help/xl_ao.1 @@ -0,0 +1,16 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_ao.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +xl_ao [-n support] +.PP +Uses a cube-packing heuristic to do an AND-OR decomposition of an infeasible network. +This is fast and the result is a feasible network. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) diff --git a/sis/sis_lib/help/xl_ao.fmt b/sis/sis_lib/help/xl_ao.fmt new file mode 100644 index 0000000..8bdb0b5 --- /dev/null +++ b/sis/sis_lib/help/xl_ao.fmt @@ -0,0 +1,11 @@ + + July 1, 1994 SIS(1) + + xl_ao [-n support] + + Uses a cube-packing heuristic to do an AND-OR decomposition of an + infeasible network. This is fast and the result is a feasible network. + + -n: support is the size of the TLU block (default = 5) + + 1 diff --git a/sis/sis_lib/help/xl_coll_ck.1 b/sis/sis_lib/help/xl_coll_ck.1 new file mode 100644 index 0000000..7de303a --- /dev/null +++ b/sis/sis_lib/help/xl_coll_ck.1 @@ -0,0 +1,29 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_coll_ck.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +xl_coll_ck [-n support] [-c collapse_input_limit] [-kv] +.PP +Assumes a feasible network. +If the number of inputs to the network is at most +\fBcollapse_input_limit\fP (default 9), collapse the network, +apply Roth-Karp decomposition and cofactoring schemes. +Pick the best result and compare with the original network +(before collapsing). If the number of nodes is smaller, accept the +better decomposition. Does nothing if n = 2. +.PP +\fB-k\fP: does not apply Roth-Karp decomposition, just use cofactoring. +.br +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.br +.PP +\fB-v\fP: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + diff --git a/sis/sis_lib/help/xl_coll_ck.fmt b/sis/sis_lib/help/xl_coll_ck.fmt new file mode 100644 index 0000000..c943e17 --- /dev/null +++ b/sis/sis_lib/help/xl_coll_ck.fmt @@ -0,0 +1,20 @@ + + July 1, 1994 SIS(1) + + xl_coll_ck [-n support] [-c collapse_input_limit] [-kv] + + Assumes a feasible network. If the number of inputs to the network is + at most collapse_input_limit (default 9), collapse the network, apply + Roth-Karp decomposition and cofactoring schemes. Pick the best result + and compare with the original network (before collapsing). If the number + of nodes is smaller, accept the better decomposition. Does nothing if n + = 2. + + -k: does not apply Roth-Karp decomposition, just use cofactoring. + + -n: support is the size of the TLU block (default = 5) + + -v: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + + 1 diff --git a/sis/sis_lib/help/xl_cover.1 b/sis/sis_lib/help/xl_cover.1 new file mode 100644 index 0000000..9e294a7 --- /dev/null +++ b/sis/sis_lib/help/xl_cover.1 @@ -0,0 +1,31 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_cover.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +xl_cover [-n number] [-h heuristic number] +.br +.PP +For mapping onto Xilinx architecture. +The initial network +should have all intermediate nodes with fanin less than +or equal to \fBnumber\fP (default is 5). +Mathony's binate covering algorithm is used to +minimize the number of nodes in the network. +Different heuristics are used to solve the covering +problem. The heuristic number can be specified +by \fB-h\fP option. Heuristic number can be 0, 1, 2 or 3: +.br +.PP +- 0 (exact), +.PP +- 1 (Mathony's method - stop when first leaf is reached), +.PP +- 2 (For large examples), +.PP +- 3 (default: automatically decides between 0 and 2) diff --git a/sis/sis_lib/help/xl_cover.fmt b/sis/sis_lib/help/xl_cover.fmt new file mode 100644 index 0000000..650b27b --- /dev/null +++ b/sis/sis_lib/help/xl_cover.fmt @@ -0,0 +1,21 @@ + + July 1, 1994 SIS(1) + + xl_cover [-n number] [-h heuristic number] + + For mapping onto Xilinx architecture. The initial network should have + all intermediate nodes with fanin less than or equal to number (default + is 5). Mathony's binate covering algorithm is used to minimize the + number of nodes in the network. Different heuristics are used to solve + the covering problem. The heuristic number can be specified by -h + option. Heuristic number can be 0, 1, 2 or 3: + + - 0 (exact), + + - 1 (Mathony's method - stop when first leaf is reached), + + - 2 (For large examples), + + - 3 (default: automatically decides between 0 and 2) + + 1 diff --git a/sis/sis_lib/help/xl_decomp_two.1 b/sis/sis_lib/help/xl_decomp_two.1 new file mode 100644 index 0000000..66c2180 --- /dev/null +++ b/sis/sis_lib/help/xl_decomp_two.1 @@ -0,0 +1,38 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_decomp_two.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +xl_decomp_two [-n support] [-l lower_common_bound] + [-L cube_support_lower_bound] [-f MAX_FANIN] + [-c MAX_COMMON_FANIN] [-u MAX_UNION_FANIN] [-v] +.PP +Given an infeasible network, does decomposition +knowing that each Xilinx3090 CLB can have two functions if they have +no more than MAX_FANIN (default = 4) fanins each, their union has at +most MAX_UNION_FANINS (default = 5) fanins and they have at most +MAX_COMMON_FANINS (default = 4) common fanins. It does so by +considering certain cubes of all the infeasible nodes of the network, and +associating an affinity value with each cube-pair. Extracts +cube-pairs with high affinity. Need to do a decomposition later to +make the network feasible. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.br +.PP +\fB-l\fP: do not consider a cube-pair for extraction if their number of +common inputs is less than lower_common_bound (default = 2). +.br +.PP +\fB-L\fP: do not consider a cube if it has less than +cube_support_lower_bound inputs. +.br +.PP +\fB-v\fP: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + diff --git a/sis/sis_lib/help/xl_decomp_two.fmt b/sis/sis_lib/help/xl_decomp_two.fmt new file mode 100644 index 0000000..5b3a3f2 --- /dev/null +++ b/sis/sis_lib/help/xl_decomp_two.fmt @@ -0,0 +1,28 @@ + + July 1, 1994 SIS(1) + + xl_decomp_two [-n support] [-l lower_common_bound] + [-L cube_support_lower_bound] [-f MAX_FANIN] + [-c MAX_COMMON_FANIN] [-u MAX_UNION_FANIN] [-v] + + Given an infeasible network, does decomposition knowing that each + Xilinx3090 CLB can have two functions if they have no more than + MAX_FANIN (default = 4) fanins each, their union has at most + MAX_UNION_FANINS (default = 5) fanins and they have at most + MAX_COMMON_FANINS (default = 4) common fanins. It does so by considering + certain cubes of all the infeasible nodes of the network, and associat- + ing an affinity value with each cube-pair. Extracts cube-pairs with high + affinity. Need to do a decomposition later to make the network feasible. + + -n: support is the size of the TLU block (default = 5) + + -l: do not consider a cube-pair for extraction if their number of common + inputs is less than lower_common_bound (default = 2). + + -L: do not consider a cube if it has less than cube_support_lower_bound + inputs. + + -v: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + + 1 diff --git a/sis/sis_lib/help/xl_imp.1 b/sis/sis_lib/help/xl_imp.1 new file mode 100644 index 0000000..14dae85 --- /dev/null +++ b/sis/sis_lib/help/xl_imp.1 @@ -0,0 +1,61 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_imp.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +xl_imp [-n support] [-c cover_node_limit] [-l lit_bound] [-Aabm] + [-g good_decomp] [-M MAX_FANINS] + [-v verbosity level] +.PP +Given an infeasible network, replaces each internal infeasible node +by a set of feasible nodes. These nodes are derived by trying +different decomposition strategies (like xl_ao, xl_split, +cofactoring, decomp -d and tech_decomp -a 2 -o 2), each followed +by a partition/cover phase. In the end, picks the best result (the +one with minimum number of feasible nodes). The result is a feasible network. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.br +.PP +\fB-A\fP do not move fanins around after decomp -g. +.br +.PP +\fB-a\fP: do not apply all decomposition methods. Only cube-packing on +sum-of-product (SOP), cube-packing on factored-form (if g flag +!= 0) and cofactoring. If this option is not specified, also apply +Roth-Karp, tech_decomp, decomp -d, and xl_split. +.br +.PP +\fB-b\fP: for best results, use this option. +Effective on a node only if its number of +literals is greater than lit_bound. In that case, after the good decomposition, +recursively call the command for each of the nodes in +decomposition. Time consuming. +.br +.PP +\fB-c\fP: sets the limit for the cover algorithm used after each +decomposition. If the number of feasible nodes for an infeasible node +is no more than cover_node_limit, then exact cover is used, else +heuristic (-h 3) option is used. (default = 25). +.br +.PP +\fB-g\fP: if 0 (default), do not use decomp -g for cube-packing, just +SOP. If 1, use only decomp -g, not SOP. If 2, use both decomp -g and SOP for +cube-packing, and pick the best result. +.br +.PP +\fB-l\fP: if the infeasible node has greater than lit_bound literals, +does a good decomposition of the node (i.e. decomp -g) (default: 50) +.br +.PP +\fB-m\fP: While doing partition, move fanins around for a node with at +most MAX_FANINS (default 15). +.br +.PP +\fB-v\fP: this sets the verbosity level (amount of information printed +as the algorithm proceeds) to \fBverbosity_level\fP. diff --git a/sis/sis_lib/help/xl_imp.fmt b/sis/sis_lib/help/xl_imp.fmt new file mode 100644 index 0000000..4994ab4 --- /dev/null +++ b/sis/sis_lib/help/xl_imp.fmt @@ -0,0 +1,47 @@ + + July 1, 1994 SIS(1) + + xl_imp [-n support] [-c cover_node_limit] [-l lit_bound] [-Aabm] + [-g good_decomp] [-M MAX_FANINS] + [-v verbosity level] + + Given an infeasible network, replaces each internal infeasible node by a + set of feasible nodes. These nodes are derived by trying different + decomposition strategies (like xl_ao, xl_split, cofactoring, decomp -d + and tech_decomp -a 2 -o 2), each followed by a partition/cover phase. In + the end, picks the best result (the one with minimum number of feasible + nodes). The result is a feasible network. + + -n: support is the size of the TLU block (default = 5) + + -A do not move fanins around after decomp -g. + + -a: do not apply all decomposition methods. Only cube-packing on sum- + of-product (SOP), cube-packing on factored-form (if g flag != 0) and + cofactoring. If this option is not specified, also apply Roth-Karp, + tech_decomp, decomp -d, and xl_split. + + -b: for best results, use this option. Effective on a node only if its + number of literals is greater than lit_bound. In that case, after the + good decomposition, recursively call the command for each of the nodes + in decomposition. Time consuming. + + -c: sets the limit for the cover algorithm used after each decomposi- + tion. If the number of feasible nodes for an infeasible node is no more + than cover_node_limit, then exact cover is used, else heuristic (-h 3) + option is used. (default = 25). + + -g: if 0 (default), do not use decomp -g for cube-packing, just SOP. If + 1, use only decomp -g, not SOP. If 2, use both decomp -g and SOP for + cube-packing, and pick the best result. + + -l: if the infeasible node has greater than lit_bound literals, does a + good decomposition of the node (i.e. decomp -g) (default: 50) + + -m: While doing partition, move fanins around for a node with at most + MAX_FANINS (default 15). + + -v: this sets the verbosity level (amount of information printed as the + algorithm proceeds) to verbosity_level. + + 1 diff --git a/sis/sis_lib/help/xl_k_decomp.1 b/sis/sis_lib/help/xl_k_decomp.1 new file mode 100644 index 0000000..de87570 --- /dev/null +++ b/sis/sis_lib/help/xl_k_decomp.1 @@ -0,0 +1,27 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_k_decomp.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +xl_k_decomp [-n support] [-p node_name] [-v verbosity_level] [-f MAX_FANINS_K_DECOMP] [-de] +.PP +Uses Karp_Roth disjoint decomposition to recursively decompose +nodes of the network having fanin greater than +\fBsupport\fP to obtain nodes each having +fanin of at most \fBsupport\fP. +If \fB-p node_name\fP is specified, only the node with the name +\fBnode_name\fP is decomposed. +Otherwise, all the nodes +that have fanin greater than \fBsupport\fP are +decomposed. +If \fB-d\fP option is specified, then if k_decomp fails to find a disjoint decomposition on a node, +the node is not decomposd by cube-packing. Option \fB-e\fP allows an exhaustive search over all +possible partitions to pick the best decomposition of a node. Then the option \fB-f MAX_FANINS_K_DECOMP\fP +sets the limit on maximum number of fanins of a node for exhaustive decomposition. If the number of fanins +is higher, only the first input partition is considered. + diff --git a/sis/sis_lib/help/xl_k_decomp.fmt b/sis/sis_lib/help/xl_k_decomp.fmt new file mode 100644 index 0000000..009bebf --- /dev/null +++ b/sis/sis_lib/help/xl_k_decomp.fmt @@ -0,0 +1,20 @@ + + July 1, 1994 SIS(1) + + xl_k_decomp [-n support] [-p node_name] [-v verbosity_level] [-f + MAX_FANINS_K_DECOMP] [-de] + + Uses Karp_Roth disjoint decomposition to recursively decompose nodes of + the network having fanin greater than support to obtain nodes each hav- + ing fanin of at most support. If -p node_name is specified, only the + node with the name node_name is decomposed. Otherwise, all the nodes + that have fanin greater than support are decomposed. If -d option is + specified, then if k_decomp fails to find a disjoint decomposition on a + node, the node is not decomposd by cube-packing. Option -e allows an + exhaustive search over all possible partitions to pick the best decompo- + sition of a node. Then the option -f MAX_FANINS_K_DECOMP sets the limit + on maximum number of fanins of a node for exhaustive decomposition. If + the number of fanins is higher, only the first input partition is con- + sidered. + + 1 diff --git a/sis/sis_lib/help/xl_merge.1 b/sis/sis_lib/help/xl_merge.1 new file mode 100644 index 0000000..5e92d12 --- /dev/null +++ b/sis/sis_lib/help/xl_merge.1 @@ -0,0 +1,54 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_merge.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:42 $ +.\" * +.\" +.XX +xl_merge [-f MAX_FANIN] [-c MAX_COMMON_FANIN] [-u MAX_UNION_FANIN] + [-n support] [-o filename] [-vlF] +.PP +Used for mapping onto Xilinx architecture. +It selects pairs of nodes of the network that can be merged +so as to minimize the number of nodes. +and solves an integer program using the package Lindo. +In the end it lists the pairs of nodes that were merged. +The command does not change the network. +.PP +\fB-f\fP: MAX_FANIN is the limit on the fanin of a mergeable node (default = 4). +.br +.PP +\fB-c\fP: MAX_COMMON_FANIN is the limit on the common fanins of two +mergeable nodes (default = 4). +.br +.PP +\fB-u\fP: MAX_UNION_FANIN is the limit on the union of the fanins of two +mergeable nodes (default = 5). +.br +.PP +\fB-n\fP: support is the limit on the number of fanins of a single function that +can be put on a CLB (default = 5). +.br +.PP +\fB-o\fP: filename is the file in which information about the nodes merged is +printed. Must specify. +.br +.PP +\fB-l\fP: Do not use lindo, an integer-linear programming package used to solve +the matching problem. Instead use a heuristic. If not specified, the program first +searches for lindo in the path. If found, lindo is invoked, else the program +automatically calls the heuristic. +.br +.PP +\fB-F\fP: If the input network is say a 4-feasible network and the support = 5, it +may be possible to reduce the number of nodes after matching. If this option is not +used,\fBxl_partition\fP is called after matching step on the subnetwork composed of +unmatched nodes. Otherwise, only matching is done and the network remains unchanged. +.br +.PP +\fB-v\fP: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + diff --git a/sis/sis_lib/help/xl_merge.fmt b/sis/sis_lib/help/xl_merge.fmt new file mode 100644 index 0000000..0fc98a2 --- /dev/null +++ b/sis/sis_lib/help/xl_merge.fmt @@ -0,0 +1,42 @@ + + July 1, 1994 SIS(1) + + xl_merge [-f MAX_FANIN] [-c MAX_COMMON_FANIN] [-u MAX_UNION_FANIN] + [-n support] [-o filename] [-vlF] + + Used for mapping onto Xilinx architecture. It selects pairs of nodes of + the network that can be merged so as to minimize the number of nodes. + and solves an integer program using the package Lindo. In the end it + lists the pairs of nodes that were merged. The command does not change + the network. + + -f: MAX_FANIN is the limit on the fanin of a mergeable node (default = + 4). + + -c: MAX_COMMON_FANIN is the limit on the common fanins of two mergeable + nodes (default = 4). + + -u: MAX_UNION_FANIN is the limit on the union of the fanins of two + mergeable nodes (default = 5). + + -n: support is the limit on the number of fanins of a single function + that can be put on a CLB (default = 5). + + -o: filename is the file in which information about the nodes merged is + printed. Must specify. + + -l: Do not use lindo, an integer-linear programming package used to + solve the matching problem. Instead use a heuristic. If not specified, + the program first searches for lindo in the path. If found, lindo is + invoked, else the program automatically calls the heuristic. + + -F: If the input network is say a 4-feasible network and the support = + 5, it may be possible to reduce the number of nodes after matching. If + this option is not used,xl_partition is called after matching step on + the subnetwork composed of unmatched nodes. Otherwise, only matching is + done and the network remains unchanged. + + -v: turns on the verbosity flag. When used, information about the + algorithm is printed as it executes. + + 1 diff --git a/sis/sis_lib/help/xl_part_coll.1 b/sis/sis_lib/help/xl_part_coll.1 new file mode 100644 index 0000000..3a9909a --- /dev/null +++ b/sis/sis_lib/help/xl_part_coll.1 @@ -0,0 +1,32 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_part_coll.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:43 $ +.\" * +.\" +.XX +xl_part_coll [-n support] [-C cost_limit] [-c cover_node_limit] + [-l lit_bound] [-Aabm] [-g decomp_good] + [-M MAX_FANINS] [-v verbosity_level] +.PP +This is a partial collapse routine. On an infeasible network, +first runs trivial partition routine. Then for each node, +finds the cost of the node using a routine similar to \fBxl_imp\fP. +Collapses each node into fanouts and computes the cost of the +fanouts likewise. If the new cost of the fanouts is less, accepts +the collapse. Deletes the collapsed node from the network. +It does this until no more collapses can be beneficially carried out. +The nodes are visited topologically. +The result is a feasible network. +.PP +\fB-C\fP: tries only those nodes for collapsing whose cost is less +than or equal to cost_limit. +Our experience has been that it is beneficial to collapse +only feasible nodes. So the default is 1. +.br +.PP +Other options are the same as in \fBxl_imp\fP except -c has default of +10 and -A means move fanins around. diff --git a/sis/sis_lib/help/xl_part_coll.fmt b/sis/sis_lib/help/xl_part_coll.fmt new file mode 100644 index 0000000..0373abe --- /dev/null +++ b/sis/sis_lib/help/xl_part_coll.fmt @@ -0,0 +1,24 @@ + + July 1, 1994 SIS(1) + + xl_part_coll [-n support] [-C cost_limit] [-c cover_node_limit] + [-l lit_bound] [-Aabm] [-g decomp_good] + [-M MAX_FANINS] [-v verbosity_level] + + This is a partial collapse routine. On an infeasible network, first + runs trivial partition routine. Then for each node, finds the cost of + the node using a routine similar to xl_imp. Collapses each node into + fanouts and computes the cost of the fanouts likewise. If the new cost + of the fanouts is less, accepts the collapse. Deletes the collapsed node + from the network. It does this until no more collapses can be benefi- + cially carried out. The nodes are visited topologically. The result is + a feasible network. + + -C: tries only those nodes for collapsing whose cost is less than or + equal to cost_limit. Our experience has been that it is beneficial to + collapse only feasible nodes. So the default is 1. + + Other options are the same as in xl_imp except -c has default of 10 and + -A means move fanins around. + + 1 diff --git a/sis/sis_lib/help/xl_partition.1 b/sis/sis_lib/help/xl_partition.1 new file mode 100644 index 0000000..fc4fa90 --- /dev/null +++ b/sis/sis_lib/help/xl_partition.1 @@ -0,0 +1,38 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_partition.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:43 $ +.\" * +.\" +.XX +xl_partition [-n support] [-M MAX_FANINS] [-v verbosity_level] [-tm] +.PP +Tries to reduce the number of nodes by collapsing nodes into their +fanouts. Also takes into account extra nets created. Collapses a +node into its fanout only if the resulting fanout is feasible. +Associates a cost with each (node, fanout) pair which reflects the +extra nets created if node is collapsed into the fanout. It then selects +pairs with lowest costs and collapses them. +The starting network need not be feasible, in which case +the resulting network also may not be. But if the starting network is, +so is the resulting network. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) +.br +.PP +\fB-t\fP: Our experience was that if one is just interested in +minimization of number of nodes, then those nodes which can +be collapsed into all their fanouts are the main reduction-contributors. +This option removes a node from the network if it +can be collapsed into all its fanouts. Very fast. +.br +.PP +\fB-m\fP: move fanins around to increase collapsing possibilities. Do so for a node +only if after collapsing, it has at most MAX_FANINS (default = 15)(as specified by \fB-M\fP option). +.br +.PP +\fB-v\fP: this sets the verbosity level (amount of information printed +as the algorithm proceeds) to \fBverbosity_level\fP. diff --git a/sis/sis_lib/help/xl_partition.fmt b/sis/sis_lib/help/xl_partition.fmt new file mode 100644 index 0000000..4a079ab --- /dev/null +++ b/sis/sis_lib/help/xl_partition.fmt @@ -0,0 +1,29 @@ + + July 1, 1994 SIS(1) + + xl_partition [-n support] [-M MAX_FANINS] [-v verbosity_level] [-tm] + + Tries to reduce the number of nodes by collapsing nodes into their + fanouts. Also takes into account extra nets created. Collapses a node + into its fanout only if the resulting fanout is feasible. Associates a + cost with each (node, fanout) pair which reflects the extra nets created + if node is collapsed into the fanout. It then selects pairs with lowest + costs and collapses them. The starting network need not be feasible, in + which case the resulting network also may not be. But if the starting + network is, so is the resulting network. + + -n: support is the size of the TLU block (default = 5) + + -t: Our experience was that if one is just interested in minimization of + number of nodes, then those nodes which can be collapsed into all their + fanouts are the main reduction-contributors. This option removes a node + from the network if it can be collapsed into all its fanouts. Very fast. + + -m: move fanins around to increase collapsing possibilities. Do so for a + node only if after collapsing, it has at most MAX_FANINS (default = + 15)(as specified by -M option). + + -v: this sets the verbosity level (amount of information printed as the + algorithm proceeds) to verbosity_level. + + 1 diff --git a/sis/sis_lib/help/xl_rl.1 b/sis/sis_lib/help/xl_rl.1 new file mode 100644 index 0000000..8dfabc3 --- /dev/null +++ b/sis/sis_lib/help/xl_rl.1 @@ -0,0 +1,25 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_rl.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:43 $ +.\" * +.\" +.XX +xl_rl [-n support] [-m] [-M MAX_FANINS] + [-t (trav_method-levels)] [-c collapse_input_limit] + [-v verbosity_level] +.PP +Used for timing optimization for table look up architectures (phase 1). +Given a feasible network (obtained say by using speed_up), reduces number of +levels for table look up with "support" inputs. If \fB-m\fP is not given, +it tries to move fanins for each node also, provided the number of +fanins of the node does not exceed MAX_FANINS (default 15). As a +final step, tries collapsing the network if number of inputs to the +network is at most collapse_input_limit (default = 10). Then applies +Roth-Karp decomposition and cofactoring (support > 2). If number of +levels decreases, accepts the better decomposition. +.PP +\fB-n\fP: support is the size of the TLU block (default = 5) diff --git a/sis/sis_lib/help/xl_rl.fmt b/sis/sis_lib/help/xl_rl.fmt new file mode 100644 index 0000000..38bceb8 --- /dev/null +++ b/sis/sis_lib/help/xl_rl.fmt @@ -0,0 +1,20 @@ + + July 1, 1994 SIS(1) + + xl_rl [-n support] [-m] [-M MAX_FANINS] + [-t (trav_method-levels)] [-c collapse_input_limit] + [-v verbosity_level] + + Used for timing optimization for table look up architectures (phase 1). + Given a feasible network (obtained say by using speed_up), reduces + number of levels for table look up with "support" inputs. If -m is not + given, it tries to move fanins for each node also, provided the number + of fanins of the node does not exceed MAX_FANINS (default 15). As a + final step, tries collapsing the network if number of inputs to the net- + work is at most collapse_input_limit (default = 10). Then applies Roth- + Karp decomposition and cofactoring (support > 2). If number of levels + decreases, accepts the better decomposition. + + -n: support is the size of the TLU block (default = 5) + + 1 diff --git a/sis/sis_lib/help/xl_split.1 b/sis/sis_lib/help/xl_split.1 new file mode 100644 index 0000000..4e0d6f0 --- /dev/null +++ b/sis/sis_lib/help/xl_split.1 @@ -0,0 +1,16 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sis/sis_lib/help/xl_split.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:43 $ +.\" * +.\" +.XX +xl_split [-n value] [-d] +.PP +Ensures that every node in the network has number of fanins less than or +equal to \fBvalue\fP. +This is accomplished by using kernel extraction and AND-OR decomposition. +\fB-d\fP turns on debugging facilities. diff --git a/sis/sis_lib/help/xl_split.fmt b/sis/sis_lib/help/xl_split.fmt new file mode 100644 index 0000000..1484942 --- /dev/null +++ b/sis/sis_lib/help/xl_split.fmt @@ -0,0 +1,10 @@ + + July 1, 1994 SIS(1) + + xl_split [-n value] [-d] + + Ensures that every node in the network has number of fanins less than or + equal to value. This is accomplished by using kernel extraction and + AND-OR decomposition. -d turns on debugging facilities. + + 1 diff --git a/sis/sis_lib/lib2.genlib b/sis/sis_lib/lib2.genlib new file mode 100644 index 0000000..4280505 --- /dev/null +++ b/sis/sis_lib/lib2.genlib @@ -0,0 +1,157 @@ + + + GATE inv1x 928.00 O = ! a; + PIN a INV 0.0514 999.0 0.4200 4.7100 0.4200 3.6000 + + GATE inv2x 928.00 O = ! a; + PIN a INV 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 + + GATE inv4x 1392.00 O = ! a; + PIN a INV 0.1897 999.0 0.2300 1.0800 0.2700 0.8500 + + GATE xor 2320.00 O = ((!a * b) + (a * !b)); + PIN a UNKNOWN 0.1442 999.0 1.7700 5.2300 0.9600 4.6400 + PIN b UNKNOWN 0.1381 999.0 1.9400 4.6500 1.1400 5.2200 + + GATE xnor 2320.00 O = ((!a * !b) + (a * b)); + PIN a UNKNOWN 0.1502 999.0 1.1100 4.8600 1.0700 3.3900 + PIN b UNKNOWN 0.1352 999.0 1.5500 4.8700 1.0700 3.3900 + + GATE nand2 1392.00 O = ! (a * b); + PIN a INV 0.0777 999.0 0.6400 4.0900 0.4000 2.5700 + PIN b INV 0.0716 999.0 0.4600 4.1000 0.3700 2.5700 + + GATE nand3 1856.00 O = ! (a * b * c); + PIN a INV 0.1000 999.0 0.8900 3.6000 0.5100 2.4900 + PIN b INV 0.0828 999.0 0.7100 4.1100 0.4200 2.5000 + PIN c INV 0.0777 999.0 0.5600 4.3900 0.3500 2.4900 + + GATE nand4 2320.00 O = ! (a * b * c * d); + PIN a INV 0.1030 999.0 1.2700 3.6200 0.6700 2.3900 + PIN b INV 0.0980 999.0 1.0900 3.6100 0.6100 2.3900 + PIN c INV 0.0980 999.0 0.8200 3.6200 0.5500 2.4000 + PIN d INV 0.1050 999.0 0.5800 3.6200 0.3800 2.3900 + + GATE nor2 1392.00 O = ! (a + b); + PIN a INV 0.0736 999.0 0.3300 3.6400 0.4500 3.6400 + PIN b INV 0.0968 999.0 0.5000 3.6400 0.7000 3.6600 + + GATE nor3 1856.00 O = ! (a + b + c); + PIN a INV 0.0856 999.0 0.8400 5.0400 1.3000 3.4500 + PIN b INV 0.0806 999.0 0.7800 5.0300 1.1400 3.4300 + PIN c INV 0.0826 999.0 0.5200 5.0300 0.8400 3.4400 + + GATE nor4 2320.00 O = ! (a + b + c + d); + PIN a INV 0.0887 999.0 0.4100 5.9100 1.1600 3.2000 + PIN b INV 0.0867 999.0 0.8500 5.9100 1.5300 3.1800 + PIN c INV 0.0867 999.0 1.1100 5.9200 1.7500 3.1900 + PIN d INV 0.0887 999.0 1.2700 5.9100 1.9400 3.2000 + + GATE aoi21 1856.00 O = ! ((a1 * a2) + b); + PIN a1 INV 0.1029 999.0 0.7500 3.5200 0.6700 2.5300 + PIN a2 INV 0.0908 999.0 0.6700 3.6400 0.6200 2.5200 + PIN b INV 0.1110 999.0 0.5800 3.6400 0.2100 1.2800 + + GATE aoi31 2320.00 O = ! ((a1 * a2 * a3) + b); + PIN a1 INV 0.1009 999.0 0.9100 4.0400 0.8100 2.8600 + PIN a2 INV 0.1049 999.0 1.0500 3.9300 0.8700 2.8700 + PIN a3 INV 0.1059 999.0 1.1500 3.9400 0.9400 2.8600 + PIN b INV 0.0979 999.0 0.8900 4.0600 0.2500 1.2800 + + GATE aoi22 2320.00 O = ! ((a1 * a2) + (b1 * b2)); + PIN a1 INV 0.1019 999.0 0.9200 3.4600 0.9400 2.7900 + PIN a2 INV 0.0908 999.0 0.8400 3.6400 0.8500 2.7900 + PIN b1 INV 0.0958 999.0 0.6100 3.6400 0.4900 2.9300 + PIN b2 INV 0.0988 999.0 0.7000 3.6400 0.5400 2.9300 + + GATE aoi32 2784.00 O = ! ((a1 * a2 * a3) + (b1 * b2)); + PIN a1 INV 0.1029 999.0 1.0600 3.8100 0.9600 2.9100 + PIN a2 INV 0.1009 999.0 1.2000 3.8100 1.0300 2.9000 + PIN a3 INV 0.1060 999.0 1.2900 3.6900 1.0600 2.9100 + PIN b1 INV 0.0979 999.0 0.9100 3.8100 0.4300 2.1200 + PIN b2 INV 0.1049 999.0 0.7800 3.5900 0.4300 2.1200 + + GATE aoi33 3248.00 O = ! ((a1 * a2 * a3) + (b1 * b2 * b3)); + PIN a1 INV 0.1029 999.0 1.3300 3.9100 1.3000 2.9100 + PIN a2 INV 0.1029 999.0 1.4600 3.8400 1.4100 2.9100 + PIN a3 INV 0.1120 999.0 1.4700 3.6500 1.4100 2.9100 + PIN b1 INV 0.1029 999.0 1.1100 3.5900 0.7600 2.9000 + PIN b2 INV 0.0949 999.0 1.0400 3.9100 0.6800 2.9100 + PIN b3 INV 0.1039 999.0 0.8400 3.5800 0.6400 2.9000 + + GATE aoi211 2320.00 O = ! ((a1 * a2) + b + c); + PIN a1 INV 0.1039 999.0 1.1200 4.8100 1.0300 2.3800 + PIN a2 INV 0.1090 999.0 1.2900 4.8100 1.0300 2.3800 + PIN b INV 0.1080 999.0 1.0400 4.8300 0.5200 1.4000 + PIN c INV 0.1008 999.0 0.6800 4.8300 0.5100 1.7900 + + GATE aoi221 2784.00 O = ! ((a1 * a2) + (b1 * b2) + c); + PIN a1 INV 0.1089 999.0 1.4800 4.4300 1.3300 2.7800 + PIN a2 INV 0.0948 999.0 1.4200 4.5600 1.4000 2.7500 + PIN b1 INV 0.1029 999.0 0.7600 4.4700 0.7900 2.8900 + PIN b2 INV 0.1049 999.0 0.7300 4.5800 0.7800 2.9100 + PIN c INV 0.1110 999.0 1.3900 4.5600 0.7000 1.5100 + + GATE aoi222 3712.00 O = ! ((a1 * a2) + (b1 * b2) + (c1 * c2) ); + PIN a1 INV 0.1019 999.0 1.7700 4.5800 1.5600 2.9500 + PIN a2 INV 0.0958 999.0 1.7300 4.6900 1.6000 2.9300 + PIN b1 INV 0.1039 999.0 1.3400 4.6800 1.2100 2.9200 + PIN b2 INV 0.1039 999.0 1.5000 4.6900 1.2200 2.9200 + PIN c1 INV 0.0958 999.0 0.9200 4.6700 0.8100 2.9200 + PIN c2 INV 0.1039 999.0 0.7700 4.4700 0.7600 2.9200 + + GATE oai21 1856.00 O = ! ( (a1 + a2) * b); + PIN a1 INV 0.1019 999.0 0.6900 3.9400 0.5300 2.4700 + PIN a2 INV 0.0979 999.0 0.8700 3.9300 0.6300 2.4700 + PIN b INV 0.0998 999.0 0.3700 2.0500 0.5700 2.5100 + + GATE oai31 2320.00 O = ! ( (a1 + a2 + a3) * b); + PIN a1 INV 0.1089 999.0 1.2700 4.7100 1.0300 2.4300 + PIN a2 INV 0.1049 999.0 1.1100 4.7100 1.0400 2.5700 + PIN a3 INV 0.1090 999.0 0.8500 4.7100 0.6900 2.3800 + PIN b INV 0.1059 999.0 0.3800 1.8600 0.8100 2.7300 + + GATE oai22 2320.00 O = ! ( (a1 + a2) * (b1 + b2)); + PIN a1 INV 0.1009 999.0 1.1000 4.0600 0.9000 2.5000 + PIN a2 INV 0.1029 999.0 0.9900 4.0600 0.6800 2.3600 + PIN b1 INV 0.0958 999.0 0.6900 3.6600 0.7400 2.5300 + PIN b2 INV 0.1039 999.0 0.6100 3.6600 0.5600 2.0600 + + GATE oai32 2784.00 O = ! ( (a1 + a2 + a3) * (b1 + b2)); + PIN a1 INV 0.1130 999.0 1.3900 4.4600 1.0400 2.4600 + PIN a2 INV 0.1069 999.0 1.2500 4.4600 1.0900 2.6300 + PIN a3 INV 0.1140 999.0 0.9900 4.4600 0.7400 2.4200 + PIN b1 INV 0.1059 999.0 0.5800 3.2000 0.7900 2.7100 + PIN b2 INV 0.1130 999.0 0.6800 3.2100 0.8300 2.3400 + + GATE oai33 3248.00 O = ! ( (a1 + a2 + a3) * (b1 + b2 + b3)); + PIN a1 INV 0.1170 999.0 1.5800 4.3000 1.4800 2.4700 + PIN a2 INV 0.1089 999.0 1.5000 4.3100 1.4200 2.6300 + PIN a3 INV 0.1079 999.0 1.2400 4.3100 1.1700 2.6500 + PIN b1 INV 0.1170 999.0 0.8000 4.3000 0.8200 2.2700 + PIN b2 INV 0.1089 999.0 0.0000 4.3000 1.1700 2.6400 + PIN b3 INV 0.1109 999.0 1.1300 4.3100 1.3500 2.6500 + + GATE oai211 2320.00 O = ! ( (a1 + a2) * b * c); + PIN a1 INV 0.1070 999.0 1.1200 4.1700 0.5900 2.3100 + PIN a2 INV 0.1131 999.0 1.3000 4.1600 0.7900 2.3600 + PIN b INV 0.1050 999.0 0.5100 2.1300 0.6900 2.4000 + PIN c INV 0.1050 999.0 0.5000 2.4600 0.5200 2.4100 + + GATE oai221 2784.00 O = ! ( (a1 + a2) * (b1 + b2) * c); + PIN a1 INV 0.1039 999.0 1.5800 4.1700 1.1100 2.4700 + PIN a2 INV 0.1050 999.0 1.4800 4.1700 0.8600 2.3600 + PIN b1 INV 0.1080 999.0 0.9400 4.0300 0.8100 2.5000 + PIN b2 INV 0.1060 999.0 0.7600 4.0300 0.6400 2.5000 + PIN c INV 0.1019 999.0 0.7800 2.2800 0.9000 2.5400 + + GATE oai222 3248.00 O = ! ( (a1 + a2) * (b1 + b2) * (c1 + c2)); + PIN a1 INV 0.1161 999.0 1.7700 3.7500 1.2100 2.4700 + PIN a2 INV 0.1110 999.0 1.6200 3.7500 1.1300 2.4800 + PIN b1 INV 0.1009 999.0 1.1700 3.5800 1.0700 2.4800 + PIN b2 INV 0.1191 999.0 1.3500 3.5800 1.1000 2.3500 + PIN c1 INV 0.1060 999.0 0.9900 3.5900 0.9300 2.4900 + PIN c2 INV 0.1140 999.0 0.8200 3.5800 0.7900 2.4800 + +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; diff --git a/sis/sis_lib/lib2_latch.genlib b/sis/sis_lib/lib2_latch.genlib new file mode 100644 index 0000000..a4e9932 --- /dev/null +++ b/sis/sis_lib/lib2_latch.genlib @@ -0,0 +1,14 @@ +# D-type latches and flip-flops are necessary for sequential +# technology mapping. +# WARNING: area and delay parameters are arbitrary. +LATCH dff 4640.00 Q = D; +PIN D NONINV 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +SEQ Q ANY FALLING_EDGE +CONTROL CLOCK 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +CONSTRAINT D 0.1 0.1 + +LATCH dlatch 3712.00 Q = D; +PIN D NONINV 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +SEQ Q ANY ACTIVE_HIGH +CONTROL CLOCK 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +CONSTRAINT D 0.1 0.1 diff --git a/sis/sis_lib/mcnc-subset.genlib b/sis/sis_lib/mcnc-subset.genlib new file mode 100644 index 0000000..0183679 --- /dev/null +++ b/sis/sis_lib/mcnc-subset.genlib @@ -0,0 +1,22 @@ +GATE inv1 1 O=!a; PIN * INV 1 999 0.9 0.3 0.9 0.3 +#GATE inv2 2 O=!a; PIN * INV 2 999 1.0 0.1 1.0 0.1 +#GATE inv3 3 O=!a; PIN * INV 3 999 1.1 0.09 1.1 0.09 +#GATE inv4 4 O=!a; PIN * INV 4 999 1.2 0.07 1.2 0.07 +GATE nand2 2 O=!(a*b); PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE nand3 3 O=!(a*b*c); PIN * INV 1 999 1.1 0.3 1.1 0.3 +GATE nand4 4 O=!(a*b*c*d); PIN * INV 1 999 1.4 0.4 1.4 0.4 +GATE nor2 2 O=!(a+b); PIN * INV 1 999 1.4 0.5 1.4 0.5 +GATE nor3 3 O=!(a+b+c); PIN * INV 1 999 2.4 0.7 2.4 0.7 +GATE nor4 4 O=!(a+b+c+d); PIN * INV 1 999 3.8 1.0 3.8 1.0 +#GATE and2 3 O=a*b; PIN * NONINV 1 999 1.9 0.3 1.9 0.3 +#GATE or2 3 O=a+b; PIN * NONINV 1 999 2.4 0.3 2.4 0.3 +GATE xor 5 O=a*!b+!a*b; PIN * UNKNOWN 2 999 1.9 0.5 1.9 0.5 +GATE xor 5 O=!(a*b+!a*!b); PIN * UNKNOWN 2 999 1.9 0.5 1.9 0.5 +GATE xnor 5 O=a*b+!a*!b; PIN * UNKNOWN 2 999 2.1 0.5 2.1 0.5 +GATE xnor 5 O=!(!a*b+a*!b); PIN * UNKNOWN 2 999 2.1 0.5 2.1 0.5 +GATE aoi21 3 O=!(a*b+c); PIN * INV 1 999 1.6 0.4 1.6 0.4 +GATE aoi22 4 O=!(a*b+c*d); PIN * INV 1 999 2.0 0.4 2.0 0.4 +GATE oai21 3 O=!((a+b)*c); PIN * INV 1 999 1.6 0.4 1.6 0.4 +GATE oai22 4 O=!((a+b)*(c+d));PIN * INV 1 999 2.0 0.4 2.0 0.4 +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; diff --git a/sis/sis_lib/mcnc.genlib b/sis/sis_lib/mcnc.genlib new file mode 100644 index 0000000..570f5bd --- /dev/null +++ b/sis/sis_lib/mcnc.genlib @@ -0,0 +1,22 @@ +GATE inv1 1 O=!a; PIN * INV 1 999 0.9 0.3 0.9 0.3 +GATE inv2 2 O=!a; PIN * INV 2 999 1.0 0.1 1.0 0.1 +GATE inv3 3 O=!a; PIN * INV 3 999 1.1 0.09 1.1 0.09 +GATE inv4 4 O=!a; PIN * INV 4 999 1.2 0.07 1.2 0.07 +GATE nand2 2 O=!(a*b); PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE nand3 3 O=!(a*b*c); PIN * INV 1 999 1.1 0.3 1.1 0.3 +GATE nand4 4 O=!(a*b*c*d); PIN * INV 1 999 1.4 0.4 1.4 0.4 +GATE nor2 2 O=!(a+b); PIN * INV 1 999 1.4 0.5 1.4 0.5 +GATE nor3 3 O=!(a+b+c); PIN * INV 1 999 2.4 0.7 2.4 0.7 +GATE nor4 4 O=!(a+b+c+d); PIN * INV 1 999 3.8 1.0 3.8 1.0 +GATE and2 3 O=a*b; PIN * NONINV 1 999 1.9 0.3 1.9 0.3 +GATE or2 3 O=a+b; PIN * NONINV 1 999 2.4 0.3 2.4 0.3 +GATE xor 5 O=a*!b+!a*b; PIN * UNKNOWN 2 999 1.9 0.5 1.9 0.5 +GATE xor 5 O=!(a*b+!a*!b); PIN * UNKNOWN 2 999 1.9 0.5 1.9 0.5 +GATE xnor 5 O=a*b+!a*!b; PIN * UNKNOWN 2 999 2.1 0.5 2.1 0.5 +GATE xnor 5 O=!(!a*b+a*!b); PIN * UNKNOWN 2 999 2.1 0.5 2.1 0.5 +GATE aoi21 3 O=!(a*b+c); PIN * INV 1 999 1.6 0.4 1.6 0.4 +GATE aoi22 4 O=!(a*b+c*d); PIN * INV 1 999 2.0 0.4 2.0 0.4 +GATE oai21 3 O=!((a+b)*c); PIN * INV 1 999 1.6 0.4 1.6 0.4 +GATE oai22 4 O=!((a+b)*(c+d));PIN * INV 1 999 2.0 0.4 2.0 0.4 +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; diff --git a/sis/sis_lib/mcnc_latch.genlib b/sis/sis_lib/mcnc_latch.genlib new file mode 100644 index 0000000..6441073 --- /dev/null +++ b/sis/sis_lib/mcnc_latch.genlib @@ -0,0 +1,14 @@ +# D-type latches and flip-flops are necessary for sequential +# technology mapping. +# WARNING: area and delay parameters are arbitrary. +LATCH dff 10 Q = D; +PIN D NONINV 2 999 1.0 0.1 1.0 0.1 +SEQ Q ANY RISING_EDGE +CONTROL CLOCK 2 999 1.0 0.1 1.0 0.1 +CONSTRAINT D 0.1 0.1 + +LATCH dlatch 8 Q = D; +PIN D NONINV 2 999 1.0 0.1 1.0 0.1 +SEQ Q ANY ACTIVE_HIGH +CONTROL CLOCK 2 999 1.0 0.1 1.0 0.1 +CONSTRAINT D 0.1 0.1 diff --git a/sis/sis_lib/minimal.genlib b/sis/sis_lib/minimal.genlib new file mode 100644 index 0000000..d3b9189 --- /dev/null +++ b/sis/sis_lib/minimal.genlib @@ -0,0 +1,5 @@ +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; +GATE inv1 1 O=!a; PIN * INV 1 999 0.9 0.3 0.9 0.3 +GATE nand2 2 O=!(a*b); PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE nor2 2 O=!(a+b); PIN * INV 1 999 1.0 0.2 1.0 0.2 diff --git a/sis/sis_lib/msu.genlib b/sis/sis_lib/msu.genlib new file mode 100644 index 0000000..080c5ab --- /dev/null +++ b/sis/sis_lib/msu.genlib @@ -0,0 +1,90 @@ +GATE "1310:physical" 16 O=!1A; +PIN * INV 1 999 1 .2 1 .2 + +GATE "1120:physical" 24 O=!(1A+1B); +PIN * INV 1 999 1 .2 1 .2 + +GATE "1130:physical" 32 O=!(1A+1B+1C); +PIN * INV 1 999 1 .2 1 .2 + +GATE "1140:physical" 40 O=!(1A+1B+1C+1D); +PIN * INV 1 999 1 .2 1 .2 + +GATE "1220:physical" 24 O=!(1A*1B); +PIN * INV 1 999 1 .2 1 .2 + +GATE "1230:physical" 32 O=!(1A*1B*1C); +PIN * INV 1 999 1 .2 1 .2 + +GATE "1240:physical" 40 O=!(1A*1B*1C*1D); +PIN * INV 1 999 1 .2 1 .2 + +GATE "1660:physical" 32 O2=1A*1B; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "1670:physical" 40 O2=1A*1B*1C; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "1680:physical" 48 O2=1A*1B*1C*1D; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "1760:physical" 32 O1=1A+1B; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "1770:physical" 40 O1=1A+1B+1C; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "1740:physical" 48 O=1A+1B+1C+1D; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "1870:physical" 40 O=!(1A*1B+2C*2D); +PIN * INV 1 999 1 .2 1 .2 + +GATE "1880:physical" 32 O=!(1A+2B*2C); +PIN * INV 1 999 1 .2 1 .2 + +GATE "1860:physical" 40 O=!((1A+1B)*(2C+2D)); +PIN * INV 1 999 1 .2 1 .2 + +GATE "1890:physical" 32 O=!(1A*(2B+2C)); +PIN * INV 1 999 1 .2 1 .2 + +GATE "1970:physical" 56 O=1A*1B+2C*2D; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "1810:physical" 72 O=1A*1B+2C*2D+3E*3F; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "1910:physical" 96 O=1A*1B+2C*2D+3E*3F+4G*4H; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "1930:physical" 64 O=1A*1B*1C+2D*2E*2F; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "2310:physical" 40 O=1A*!1B+!1A*1B; +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "2310:physical" 40 O=!(1A*1B+!1A*!1B); +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "2350:physical" 48 O=1A*1B+!1A*!1B; +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "2350:physical" 48 O=!(1A*!1B+!1A*1B); +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "1610:physical" 32 O=!1A*2B; +PIN 1A INV 1 999 1 .2 1 .2 +PIN 2B NONINV 1 999 1 .2 1 .2 + +GATE "1620:physical" 32 O=1A+!2B; +PIN 1A NONINV 1 999 1 .2 1 .2 +PIN 2B INV 1 999 1 .2 1 .2 + +GATE "1350:physical" 48 O=1D1*3SEL+2D2*!3SEL; +PIN 1D1 NONINV 1 999 1 .2 1 .2 +PIN 2D2 NONINV 1 999 1 .2 1 .2 +PIN 3SEL UNKNOWN 1 999 1 .2 1 .2 + +GATE "1430:physical" 8 O=CONST1; +GATE "1440:physical" 8 O=CONST0; diff --git a/sis/sis_lib/msu_latch.genlib b/sis/sis_lib/msu_latch.genlib new file mode 100644 index 0000000..745dfcc --- /dev/null +++ b/sis/sis_lib/msu_latch.genlib @@ -0,0 +1,14 @@ +# D-type latches and flip-flops are necessary for sequential +# technology mapping. +# WARNING: area and delay parameters are arbitrary. +LATCH "dff:physical" 88 Q=D; +PIN D NONINV 1 999 1 .2 1 .2 +SEQ Q ANY RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +LATCH "dlatch:physical" 80 Q=D; +PIN D NONINV 1 999 1 .2 1 .2 +SEQ Q ANY ACTIVE_HIGH +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 diff --git a/sis/sis_lib/nand-nor.genlib b/sis/sis_lib/nand-nor.genlib new file mode 100644 index 0000000..6ee5efa --- /dev/null +++ b/sis/sis_lib/nand-nor.genlib @@ -0,0 +1,9 @@ +GATE inv1 1 O=!a; PIN * INV 1 999 0.9 0.3 0.9 0.3 +GATE nand2 2 O=!(a*b); PIN * INV 1 999 1.0 0.2 1.0 0.2 +GATE nand3 3 O=!(a*b*c); PIN * INV 1 999 1.1 0.3 1.1 0.3 +GATE nand4 4 O=!(a*b*c*d); PIN * INV 1 999 1.4 0.4 1.4 0.4 +GATE nor2 2 O=!(a+b); PIN * INV 1 999 1.4 0.5 1.4 0.5 +GATE nor3 3 O=!(a+b+c); PIN * INV 1 999 2.4 0.7 2.4 0.7 +GATE nor4 4 O=!(a+b+c+d); PIN * INV 1 999 3.8 1.0 3.8 1.0 +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; diff --git a/sis/sis_lib/script b/sis/sis_lib/script new file mode 100644 index 0000000..02b14c3 --- /dev/null +++ b/sis/sis_lib/script @@ -0,0 +1,28 @@ +sweep; eliminate -1 +simplify +eliminate -1 + +sweep; eliminate 5 +simplify + +resub -a + +gkx -abt 30 +resub -a; sweep +gcx -bt 30 +resub -a; sweep + +gkx -abt 10 +resub -a; sweep +gcx -bt 10 +resub -a; sweep + +gkx -ab +resub -a; sweep +gcx -b +resub -a; sweep + +eliminate 0 +decomp -g * + +eliminate -1; sweep diff --git a/sis/sis_lib/script.algebraic b/sis/sis_lib/script.algebraic new file mode 100644 index 0000000..7d4fd02 --- /dev/null +++ b/sis/sis_lib/script.algebraic @@ -0,0 +1,22 @@ +sweep +eliminate 5 +simplify -m nocomp -d +resub -a + +gkx -abt 30 +resub -a; sweep +gcx -bt 30 +resub -a; sweep + +gkx -abt 10 +resub -a; sweep +gcx -bt 10 +resub -a; sweep + +gkx -ab +resub -a; sweep +gcx -b +resub -a; sweep + +eliminate 0 +decomp -g * diff --git a/sis/sis_lib/script.boolean b/sis/sis_lib/script.boolean new file mode 100644 index 0000000..02b14c3 --- /dev/null +++ b/sis/sis_lib/script.boolean @@ -0,0 +1,28 @@ +sweep; eliminate -1 +simplify +eliminate -1 + +sweep; eliminate 5 +simplify + +resub -a + +gkx -abt 30 +resub -a; sweep +gcx -bt 30 +resub -a; sweep + +gkx -abt 10 +resub -a; sweep +gcx -bt 10 +resub -a; sweep + +gkx -ab +resub -a; sweep +gcx -b +resub -a; sweep + +eliminate 0 +decomp -g * + +eliminate -1; sweep diff --git a/sis/sis_lib/script.delay b/sis/sis_lib/script.delay new file mode 100644 index 0000000..a85470a --- /dev/null +++ b/sis/sis_lib/script.delay @@ -0,0 +1,17 @@ +sweep +decomp -q +tech_decomp -o 2 +resub -a -d +sweep +reduce_depth -b -r +red_removal +eliminate -l 100 -1 +simplify -l +full_simplify -l +sweep +decomp -q +fx -l +tech_decomp -o 2 +rlib lib2.genlib +rlib -a lib2_latch.genlib +map -s -n 1 -AFG -p diff --git a/sis/sis_lib/script.espresso b/sis/sis_lib/script.espresso new file mode 100644 index 0000000..e8008c9 --- /dev/null +++ b/sis/sis_lib/script.espresso @@ -0,0 +1,2 @@ +espresso +source ~cad/lib/misII/lib/script diff --git a/sis/sis_lib/script.mcnc b/sis/sis_lib/script.mcnc new file mode 100644 index 0000000..1d9ca66 --- /dev/null +++ b/sis/sis_lib/script.mcnc @@ -0,0 +1,5 @@ +source script.rugged +read_library mcnc.genlib +read_library -a mcnc_latch.genlib +map +phase -g diff --git a/sis/sis_lib/script.msu b/sis/sis_lib/script.msu new file mode 100644 index 0000000..eb462aa --- /dev/null +++ b/sis/sis_lib/script.msu @@ -0,0 +1,5 @@ +source script.rugged +read_library msu.genlib +read_library -a msu_latch.genlib +map +phase -g diff --git a/sis/sis_lib/script.oct b/sis/sis_lib/script.oct new file mode 100644 index 0000000..530fb6a --- /dev/null +++ b/sis/sis_lib/script.oct @@ -0,0 +1,9 @@ +source script.rugged +set OCT-CELL-VIEW physical +set OCT-CELL-PATH /projects/octtools/octtools-5.1.devel/mips/tech/scmos/msu/stdcell2_2 +set OCT-TECHNOLOGY scmos +set OCT-EDITSTYLE SYMBOLIC +set OCT-VIEWTYPE SYMBOLIC +read_library stdcell2_2.genlib +map +phase -g diff --git a/sis/sis_lib/script.rugged b/sis/sis_lib/script.rugged new file mode 100644 index 0000000..e27cfdb --- /dev/null +++ b/sis/sis_lib/script.rugged @@ -0,0 +1,13 @@ +sweep; eliminate -1 +simplify -m nocomp +eliminate -1 + +sweep; eliminate 5 +simplify -m nocomp +resub -a + +fx +resub -a; sweep + +eliminate -1; sweep +full_simplify -m nocomp diff --git a/sis/sis_lib/script.rugged.notes b/sis/sis_lib/script.rugged.notes new file mode 100644 index 0000000..b10584d --- /dev/null +++ b/sis/sis_lib/script.rugged.notes @@ -0,0 +1,13 @@ +script.rugged.notes: + +This is a new script which is very robust according to our experiments. +If the initial circuit is a multi-level circuit we propose running +"full_simplify" before running this script. If the initial circuit +is a PLA, we propose running "resub -a; simplify -d" before running +this script. This script can be run repeatedly until no further +improvement is possible. However one must keep track of the results +because at times further running of the script can slightly deteriorate +the final result. There are some set of circuits on which "full_simplify" +can not finish. These are usually circuits for which BDD's can not be +built. We suggest running the script without "full_simplify" in such cases. +It is sometimes possible to run "full_simplify" at the later stages. diff --git a/sis/sis_lib/stdcell2_2.genlib b/sis/sis_lib/stdcell2_2.genlib new file mode 100644 index 0000000..3decf5c --- /dev/null +++ b/sis/sis_lib/stdcell2_2.genlib @@ -0,0 +1,120 @@ +GATE "invf101:physical" 16 O=!A1; +PIN * INV 1 999 1 .2 1 .2 + +GATE "norf201:physical" 24 O=!(A1+B1); +PIN * INV 1 999 1 .2 1 .2 + +GATE "norf301:physical" 32 O=!(A1+B1+C1); +PIN * INV 1 999 1 .2 1 .2 + +GATE "norf401:physical" 40 O=!(A1+B1+C1+D1); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nanf201:physical" 24 O=!(A1*B1); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nanf301:physical" 32 O=!(A1*B1*C1); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nanf401:physical" 40 O=!(A1*B1*C1*D1); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nanf211:physical" 32 O2=A1*B1; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "nanf311:physical" 40 O2=A1*B1*C1; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "nanf411:physical" 48 O2=A1*B1*C1*D1; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "norf211:physical" 32 O1=A1+B1; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "norf311:physical" 40 O1=A1+B1+C1; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "orf401:physical" 48 O=A1+B1+C1+D1; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "aoif2201:physical" 40 O=!(A1*B1+C2*D2); +PIN * INV 1 999 1 .2 1 .2 + +GATE "blf00001:physical" 32 O=!(A1+B2*C2); +PIN * INV 1 999 1 .2 1 .2 + +GATE "oaif2201:physical" 40 O=!((A1+B1)*(C2+D2)); +PIN * INV 1 999 1 .2 1 .2 + +GATE "blf00101:physical" 32 O=!(A1*(B2+C2)); +PIN * INV 1 999 1 .2 1 .2 + +GATE "aof2201:physical" 56 O=A1*B1+C2*D2; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "aof3201:physical" 72 O=A1*B1+C2*D2+E3*F3; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "aof4201:physical" 96 O=A1*B1+C2*D2+E3*F3+G4*H4; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "aof2301:physical" 64 O=A1*B1*C1+D2*E2*F2; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "xorf201:physical" 40 O=A1*!B1+!A1*B1; +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "xorf201:physical" 40 O=!(A1*B1+!A1*!B1); +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "xnof201:physical" 48 O=A1*B1+!A1*!B1; +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "xnof201:physical" 48 O=!(A1*!B1+!A1*B1); +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "norf251:physical" 32 O=!A1*B2; +PIN A1 INV 1 999 1 .2 1 .2 +PIN B2 NONINV 1 999 1 .2 1 .2 + +GATE "nanf251:physical" 32 O=A1+!B2; +PIN A1 NONINV 1 999 1 .2 1 .2 +PIN B2 INV 1 999 1 .2 1 .2 + +GATE "muxf201:physical" 48 O=A1*SEL3+B2*!SEL3; +PIN A1 NONINV 1 999 1 .2 1 .2 +PIN B2 NONINV 1 999 1 .2 1 .2 +PIN SEL3 UNKNOWN 1 999 1 .2 1 .2 + +GATE "puuf000:physical" 8 O=CONST1; +GATE "pudf000:physical" 8 O=CONST0; + + +# LATCHES + +# Clocked Latch with reset - active_low +LATCH "larf310:physical" 88 Q=DATA1*RST3; +PIN DATA1 NONINV 0.1 999 2.08 3.42 2.46 2.60 +PIN RST3 NONINV 0.1 999 0.0 0.0 1.41 2.93 # No 0->1 transition occurs +SEQ Q ANY ACTIVE_LOW +CONTROL CLK2 0.1 999 3.31 3.55 1.41 2.93 +CONSTRAINT * 0.0 0.0 + +# --- EDGE_TRIGGERED FLIP FLOPS + +# D-FF +LATCH "dfnf311:physical" 96 Q=DATA1; +PIN DATA1 NONINV 0.1 999 0.0 0.0 0.0 0.0 # No path from DATA to Q +SEQ Q ANY FALLING_EDGE +CONTROL CLK2 0.1 999 3.12 0.0 2.33 0.0 +CONSTRAINT * 11.0 6.0 + + +# D-FF with synchronous set/reset +LATCH "dfbf311:physical" 168 Q=(DATA1+SET4)*!RST3; +PIN DATA1 NONINV 0.1 999 0.0 0.0 0.0 0.0 # No path from DATA to Q +PIN SET4 NONINV 0.1 999 1.27 1.38 0.0 0.0 # No 1->0 transition occurs +PIN RST3 INV 0.1 999 0.0 0.0 3.88 1.26 # No 0->1 transition occurs +SEQ Q DATA1 FALLING_EDGE +CONTROL CLK2 0.1 999 3.20 1.69 3.44 1.43 +CONSTRAINT * 6.0 5.5 diff --git a/sis/sis_lib/synch.genlib b/sis/sis_lib/synch.genlib new file mode 100644 index 0000000..c28b57b --- /dev/null +++ b/sis/sis_lib/synch.genlib @@ -0,0 +1,204 @@ +# +# MSU library (msu.genlib) + latches/flip-flops + buffer +# Mnemonic gate names +# +# --- COMBINATIONAL GATES + +GATE "inv_comb" 16 O=!1A; +PIN * INV 1 999 1 .2 1 .2 + +GATE "buffer_comb" 16 O=1A; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "nor2_comb" 24 O=!(1A+1B); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nor3_comb" 32 O=!(1A+1B+1C); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nor4_comb" 40 O=!(1A+1B+1C+1D); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nand2_comb" 24 O=!(1A*1B); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nand3_comb" 32 O=!(1A*1B*1C); +PIN * INV 1 999 1 .2 1 .2 + +GATE "nand4_comb" 40 O=!(1A*1B*1C*1D); +PIN * INV 1 999 1 .2 1 .2 + +GATE "and2_comb" 32 O2=1A*1B; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "and3_comb" 40 O2=1A*1B*1C; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "and4_comb" 48 O2=1A*1B*1C*1D; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "or2_comb" 32 O1=1A+1B; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "or3_comb" 40 O1=1A+1B+1C; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "or4_comb" 48 O=1A+1B+1C+1D; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "aoi22_comb" 40 O=!(1A*1B+2C*2D); +PIN * INV 1 999 1 .2 1 .2 + +GATE "aoi12_comb" 32 O=!(1A+2B*2C); +PIN * INV 1 999 1 .2 1 .2 + +GATE "oai22_comb" 40 O=!((1A+1B)*(2C+2D)); +PIN * INV 1 999 1 .2 1 .2 + +GATE "oai12_comb" 32 O=!(1A*(2B+2C)); +PIN * INV 1 999 1 .2 1 .2 + +GATE "ao22_comb" 56 O=1A*1B+2C*2D; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "ao222_comb" 72 O=1A*1B+2C*2D+3E*3F; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "ao2222_comb" 96 O=1A*1B+2C*2D+3E*3F+4G*4H; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "ao33_comb" 64 O=1A*1B*1C+2D*2E*2F; +PIN * NONINV 1 999 1 .2 1 .2 + +GATE "xor_comb" 40 O=1A*!1B+!1A*1B; +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "xor_comb" 40 O=!(1A*1B+!1A*!1B); +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "xorbar_comb" 48 O=1A*1B+!1A*!1B; +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "xorbar_comb" 48 O=!(1A*!1B+!1A*1B); +PIN * UNKNOWN 1 999 1 .2 1 .2 + +GATE "invand_comb" 32 O=!1A*2B; +PIN 1A INV 1 999 1 .2 1 .2 +PIN 2B NONINV 1 999 1 .2 1 .2 + +GATE "invor_comb" 32 O=1A+!2B; +PIN 1A NONINV 1 999 1 .2 1 .2 +PIN 2B INV 1 999 1 .2 1 .2 + +GATE "mux2_comb" 48 O=1D1*3SEL+2D2*!3SEL; +PIN 1D1 NONINV 1 999 1 .2 1 .2 +PIN 2D2 NONINV 1 999 1 .2 1 .2 +PIN 3SEL UNKNOWN 1 999 1 .2 1 .2 + +GATE "const1_comb" 8 O=CONST1; +GATE "const0_comb" 8 O=CONST0; + +# --- TRANSPARENT LATCHES + +LATCH "dff_ah" 80 Q=D; +PIN D NONINV 1 999 1 .2 1 .2 +SEQ Q ANY ACTIVE_HIGH +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +LATCH "dff_al" 80 Q=D; +PIN D NONINV 1 999 1 .2 1 .2 +SEQ Q ANY ACTIVE_LOW +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# --- EDGE_TRIGGERED FLIP FLOPS + +# D-FF +LATCH "dff_re" 88 Q=D; +PIN D NONINV 1 999 1 .2 1 .2 +SEQ Q ANY RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +LATCH "dff_fe" 88 Q=D; +PIN D NONINV 1 999 1 .2 1 .2 +SEQ Q ANY FALLING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# D-FF with enable +LATCH "dff_enable_re" 100 Q=D*E+Q_NEXT*!E; +PIN D NONINV 1 999 1 .2 1 .2 +PIN E UNKNOWN 1 999 1 .2 1 .2 +SEQ Q Q_NEXT RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +LATCH "dff_enable_fe" 100 Q=D*E+Q_NEXT*!E; +PIN D NONINV 1 999 1 .2 1 .2 +PIN E UNKNOWN 1 999 1 .2 1 .2 +SEQ Q Q_NEXT FALLING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# D-FF with synchronous reset +LATCH "dff_reset_re" 104 Q=D*!R; +PIN D NONINV 1 999 1 .2 1 .2 +PIN R INV 1 999 1 .2 1 .2 +SEQ Q ANY RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +LATCH "dff_reset_fe" 104 Q=D*!R; +PIN D NONINV 1 999 1 .2 1 .2 +PIN R INV 1 999 1 .2 1 .2 +SEQ Q ANY FALLING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# D-FF with synchronous set/reset +LATCH "dff_set_reset_re" 136 Q=(D+S)*!R; +PIN D NONINV 1 999 1 .2 1 .2 +PIN S NONINV 1 999 1 .2 1 .2 +PIN R INV 1 999 1 .2 1 .2 +SEQ Q ANY RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +LATCH "dff_set_reset_fe" 136 Q=(D+S)*!R; +PIN D NONINV 1 999 1 .2 1 .2 +PIN S NONINV 1 999 1 .2 1 .2 +PIN R INV 1 999 1 .2 1 .2 +SEQ Q ANY FALLING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# JK-FF +LATCH "jkff_re" 100 Q=(J*!Q_NEXT)+(!K*Q_NEXT); +PIN J NONINV 1 999 1 .2 1 .2 +PIN K INV 1 999 1 .2 1 .2 +SEQ Q Q_NEXT RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +LATCH "jkff_fe" 100 Q=(J*!Q_NEXT)+(!K*Q_NEXT); +PIN J NONINV 1 999 1 .2 1 .2 +PIN K INV 1 999 1 .2 1 .2 +SEQ Q Q_NEXT FALLING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +# Toggle-FF +LATCH "tff_re" 90 Q=(T*!Q_NEXT)+(!T*Q_NEXT); +PIN T UNKNOWN 1 999 1 .2 1 .2 +SEQ Q Q_NEXT RISING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + +LATCH "tff_fe" 90 Q=(T*!Q_NEXT)+(!T*Q_NEXT); +PIN T UNKNOWN 1 999 1 .2 1 .2 +SEQ Q Q_NEXT FALLING_EDGE +CONTROL CLK 1 999 1 .2 1 .2 +CONSTRAINT * .2 .2 + diff --git a/sis/sis_lib/weird.genlib b/sis/sis_lib/weird.genlib new file mode 100644 index 0000000..15ba31b --- /dev/null +++ b/sis/sis_lib/weird.genlib @@ -0,0 +1,16 @@ +# these have slightly higher costs because they will duplicate inverters ... + +GATE xor 5.5 O=a*!b+!a*b; PIN * UNKNOWN 2 999 1.9 0.5 1.9 0.5 +GATE xor 5.5 O=!(a*b+!a*!b); PIN * UNKNOWN 2 999 1.9 0.5 1.9 0.5 + +GATE xnor 5.5 O=a*b+!a*!b; PIN * UNKNOWN 2 999 2.1 0.5 2.1 0.5 +GATE xnor 5.5 O=!(!a*b+a*!b); PIN * UNKNOWN 2 999 2.1 0.5 2.1 0.5 + +GATE mux21 4.5 O=a*s+b*!s; + PIN a NONINV 1 999 1.6 0.4 1.6 0.4 + PIN b NONINV 1 999 1.6 0.4 1.6 0.4 + PIN s UNKNOWN 2 999 2.0 0.4 1.6 0.4 +GATE mux21 4.5 O=!(!a*s+!b*!s); + PIN a NONINV 1 999 1.6 0.4 1.6 0.4 + PIN b NONINV 1 999 1.6 0.4 1.6 0.4 + PIN s UNKNOWN 2 999 2.0 0.4 1.6 0.4 diff --git a/sis/sis_lib/weird.lib b/sis/sis_lib/weird.lib new file mode 100644 index 0000000..2c494f7 --- /dev/null +++ b/sis/sis_lib/weird.lib @@ -0,0 +1,122 @@ +# (1 of 1) NOR-FORM of a!b+!ab +.model xor +.inputs a b +.outputs O 0 2 +.names a 0 +0 1 +.names b 0 1 +00 1 +.names b 2 +0 1 +.names a 2 3 +00 1 +.names 1 3 4 +00 1 +.names 4 O +0 1 +.area 5.00 +.delay a UNKNOWN 2.000 999.000 1.900 0.500 1.900 0.500 +.delay b UNKNOWN 2.000 999.000 1.900 0.500 1.900 0.500 +.end + +# (1 of 1) NOR-FORM of !(ab+!a!b) +.model xor +.inputs a b +.outputs O 1 2 +.names a b 0 +00 1 +.names a 1 +0 1 +.names b 2 +0 1 +.names 1 2 3 +00 1 +.names 0 3 O +00 1 +.area 5.00 +.delay a UNKNOWN 2.000 999.000 1.900 0.500 1.900 0.500 +.delay b UNKNOWN 2.000 999.000 1.900 0.500 1.900 0.500 +.end + +# (1 of 1) NOR-FORM of ab+!a!b +.model xnor +.inputs a b +.outputs O 1 2 +.names a b 0 +00 1 +.names a 1 +0 1 +.names b 2 +0 1 +.names 1 2 3 +00 1 +.names 0 3 4 +00 1 +.names 4 O +0 1 +.area 5.00 +.delay a UNKNOWN 2.000 999.000 2.100 0.500 2.100 0.500 +.delay b UNKNOWN 2.000 999.000 2.100 0.500 2.100 0.500 +.end + +# (1 of 1) NOR-FORM of !(!ab+a!b) +.model xnor +.inputs a b +.outputs O 0 2 +.names b 0 +0 1 +.names a 0 1 +00 1 +.names a 2 +0 1 +.names b 2 3 +00 1 +.names 1 3 O +00 1 +.area 5.00 +.delay a UNKNOWN 2.000 999.000 2.100 0.500 2.100 0.500 +.delay b UNKNOWN 2.000 999.000 2.100 0.500 2.100 0.500 +.end + +# (1 of 1) NOR-FORM of as+b!s +.model mux21 +.inputs a b s +.outputs O 3 +.names b 0 +0 1 +.names s 0 1 +00 1 +.names a 2 +0 1 +.names s 3 +0 1 +.names 2 3 4 +00 1 +.names 1 4 5 +00 1 +.names 5 O +0 1 +.area 4.00 +.delay s UNKNOWN 2.000 999.000 2.000 0.400 1.600 0.400 +.delay b NONINV 1.000 999.000 1.600 0.400 1.600 0.400 +.delay a NONINV 1.000 999.000 1.600 0.400 1.600 0.400 +.end + +# (1 of 1) NOR-FORM of !(!as+!b!s) +.model mux21 +.inputs a b s +.outputs O 1 +.names b s 0 +00 1 +.names s 1 +0 1 +.names a 1 2 +00 1 +.names 0 2 O +00 1 +.area 4.00 +.delay s UNKNOWN 2.000 999.000 2.000 0.400 1.600 0.400 +.delay b NONINV 1.000 999.000 1.600 0.400 1.600 0.400 +.delay a NONINV 1.000 999.000 1.600 0.400 1.600 0.400 +.end + diff --git a/sis/sparse/Makefile.am b/sis/sparse/Makefile.am new file mode 100644 index 0000000..aaeed61 --- /dev/null +++ b/sis/sparse/Makefile.am @@ -0,0 +1,7 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libsparse.a +libsparse_a_SOURCES = cols.c matrix.c rows.c sparse_int.h +pkginclude_HEADERS = sparse.h +dist_doc_DATA = sparse.doc diff --git a/sis/sparse/Makefile.in b/sis/sparse/Makefile.in new file mode 100644 index 0000000..b77e448 --- /dev/null +++ b/sis/sparse/Makefile.in @@ -0,0 +1,419 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libsparse_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/sparse +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libsparse_a_AR = $(AR) $(ARFLAGS) +libsparse_a_LIBADD = +am_libsparse_a_OBJECTS = cols.$(OBJEXT) matrix.$(OBJEXT) \ + rows.$(OBJEXT) +libsparse_a_OBJECTS = $(am_libsparse_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libsparse_a_SOURCES) +DIST_SOURCES = $(libsparse_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libsparse.a +libsparse_a_SOURCES = cols.c matrix.c rows.c sparse_int.h +pkginclude_HEADERS = sparse.h +dist_doc_DATA = sparse.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/sparse/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/sparse/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libsparse.a: $(libsparse_a_OBJECTS) $(libsparse_a_DEPENDENCIES) + -rm -f libsparse.a + $(libsparse_a_AR) libsparse.a $(libsparse_a_OBJECTS) $(libsparse_a_LIBADD) + $(RANLIB) libsparse.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/sparse/cols.c b/sis/sparse/cols.c new file mode 100644 index 0000000..edf7ba1 --- /dev/null +++ b/sis/sparse/cols.c @@ -0,0 +1,314 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/sparse/cols.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include <stdio.h> +#include "sparse_int.h" + + +/* + * allocate a new col vector + */ +sm_col * +sm_col_alloc() +{ + register sm_col *pcol; + +#ifdef FAST_AND_LOOSE + if (sm_col_freelist == NIL(sm_col)) { + pcol = ALLOC(sm_col, 1); + } else { + pcol = sm_col_freelist; + sm_col_freelist = pcol->next_col; + } +#else + pcol = ALLOC(sm_col, 1); +#endif + + pcol->col_num = 0; + pcol->length = 0; + pcol->first_row = pcol->last_row = NIL(sm_element); + pcol->next_col = pcol->prev_col = NIL(sm_col); + pcol->flag = 0; + pcol->user_word = NIL(char); /* for our user ... */ + return pcol; +} + + +/* + * free a col vector -- for FAST_AND_LOOSE, this is real cheap for cols; + * however, freeing a rowumn must still walk down the rowumn discarding + * the elements one-by-one; that is the only use for the extra '-DCOLS' + * compile flag ... + */ +void +sm_col_free(pcol) +register sm_col *pcol; +{ +#if defined(FAST_AND_LOOSE) && ! defined(COLS) + if (pcol->first_row != NIL(sm_element)) { + /* Add the linked list of col items to the free list */ + pcol->last_row->next_row = sm_element_freelist; + sm_element_freelist = pcol->first_row; + } + + /* Add the col to the free list of cols */ + pcol->next_col = sm_col_freelist; + sm_col_freelist = pcol; +#else + register sm_element *p, *pnext; + + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; + sm_element_free(p); + } + FREE(pcol); +#endif +} + + +/* + * duplicate an existing col + */ +sm_col * +sm_col_dup(pcol) +register sm_col *pcol; +{ + register sm_col *pnew; + register sm_element *p; + + pnew = sm_col_alloc(); + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) sm_col_insert(pnew, p->row_num); + } + return pnew; +} + + +/* + * insert an element into a col vector + */ +sm_element * +sm_col_insert(pcol, row) +register sm_col *pcol; +register int row; +{ + register sm_element *test, *element; + + /* get a new item, save its address */ + sm_element_alloc(element); + test = element; + sorted_insert(sm_element, pcol->first_row, pcol->last_row, pcol->length, + next_row, prev_row, row_num, row, test); + + /* if item was not used, free it */ + if (element != test) { + sm_element_free(element); + } + + /* either way, return the current new value */ + return test; +} + + +/* + * remove an element from a col vector + */ +void +sm_col_remove(pcol, row) +register sm_col *pcol; +register int row; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0 && p->row_num < row; p = p->next_row) + ; + if (p != 0 && p->row_num == row) { + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + sm_element_free(p); + } +} + + +/* + * find an element (if it is in the col vector) + */ +sm_element * +sm_col_find(pcol, row) +sm_col *pcol; +int row; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0 && p->row_num < row; p = p->next_row) + ; + if (p != 0 && p->row_num == row) { + return p; + } else { + return NIL(sm_element); + } +} + +/* + * return 1 if col p2 contains col p1; 0 otherwise + */ +int +sm_col_contains(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + while (q1 != 0) { + if (q2 == 0 || q1->row_num < q2->row_num) { + return 0; + } else if (q1->row_num == q2->row_num) { + q1 = q1->next_row; + q2 = q2->next_row; + } else { + q2 = q2->next_row; + } + } + return 1; +} + + +/* + * return 1 if col p1 and col p2 share an element in common + */ +int +sm_col_intersects(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + if (q1 == 0 || q2 == 0) return 0; + for(;;) { + if (q1->row_num < q2->row_num) { + if ((q1 = q1->next_row) == 0) { + return 0; + } + } else if (q1->row_num > q2->row_num) { + if ((q2 = q2->next_row) == 0) { + return 0; + } + } else { + return 1; + } + } +} + + +/* + * compare two cols, lexical ordering + */ +int +sm_col_compare(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + while(q1 != 0 && q2 != 0) { + if (q1->row_num != q2->row_num) { + return q1->row_num - q2->row_num; + } + q1 = q1->next_row; + q2 = q2->next_row; + } + + if (q1 != 0) { + return 1; + } else if (q2 != 0) { + return -1; + } else { + return 0; + } +} + + +/* + * return the intersection + */ +sm_col * +sm_col_and(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + register sm_col *result; + + result = sm_col_alloc(); + q1 = p1->first_row; + q2 = p2->first_row; + if (q1 == 0 || q2 == 0) return result; + for(;;) { + if (q1->row_num < q2->row_num) { + if ((q1 = q1->next_row) == 0) { + return result; + } + } else if (q1->row_num > q2->row_num) { + if ((q2 = q2->next_row) == 0) { + return result; + } + } else { + (void) sm_col_insert(result, q1->row_num); + if ((q1 = q1->next_row) == 0) { + return result; + } + if ((q2 = q2->next_row) == 0) { + return result; + } + } + } +} + +int +sm_col_hash(pcol, modulus) +sm_col *pcol; +int modulus; +{ + register int sum; + register sm_element *p; + + sum = 0; + for(p = pcol->first_row; p != 0; p = p->next_row) { + sum = (sum*17 + p->row_num) % modulus; + } + return sum; +} + +/* + * remove an element from a col vector (given a pointer to the element) + */ +void +sm_col_remove_element(pcol, p) +register sm_col *pcol; +register sm_element *p; +{ + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + sm_element_free(p); +} + + +void +sm_col_print(fp, pcol) +FILE *fp; +sm_col *pcol; +{ + sm_element *p; + + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) fprintf(fp, " %d", p->row_num); + } +} diff --git a/sis/sparse/matrix.c b/sis/sparse/matrix.c new file mode 100644 index 0000000..96f825f --- /dev/null +++ b/sis/sparse/matrix.c @@ -0,0 +1,573 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/sparse/matrix.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include <stdio.h> +#include "sparse_int.h" + +/* + * free-lists are only used if 'FAST_AND_LOOSE' is set; this is because + * we lose the debugging capability of libmm_t which trashes objects when + * they are free'd. However, FAST_AND_LOOSE is much faster if matrices + * are created and freed frequently. + */ + +#ifdef FAST_AND_LOOSE +sm_element *sm_element_freelist; +sm_row *sm_row_freelist; +sm_col *sm_col_freelist; +#endif + +sm_matrix * +sm_allocate() +{ + register sm_matrix *A; + + A = ALLOC(sm_matrix, 1); + A->rows = NIL(sm_row *); + A->cols = NIL(sm_col *); + A->nrows = A->ncols = 0; + A->rows_size = A->cols_size = 0; + A->first_row = A->last_row = NIL(sm_row); + A->first_col = A->last_col = NIL(sm_col); + A->user_word = NIL(char); /* for our user ... */ + return A; +} + + +sm_matrix * +sm_alloc_size(row, col) +int row, col; +{ + register sm_matrix *A; + + A = sm_alloc(); + sm_resize(A, row, col); + return A; +} + + +void +sm_free_space(A) +sm_matrix *A; +{ +#ifdef FAST_AND_LOOSE + register sm_row *prow; + + if (A->first_row != 0) { + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + /* add the elements to the free list of elements */ + prow->last_col->next_col = sm_element_freelist; + sm_element_freelist = prow->first_col; + } + + /* Add the linked list of rows to the row-free-list */ + A->last_row->next_row = sm_row_freelist; + sm_row_freelist = A->first_row; + + /* Add the linked list of cols to the col-free-list */ + A->last_col->next_col = sm_col_freelist; + sm_col_freelist = A->first_col; + } +#else + register sm_row *prow, *pnext_row; + register sm_col *pcol, *pnext_col; + + for(prow = A->first_row; prow != 0; prow = pnext_row) { + pnext_row = prow->next_row; + sm_row_free(prow); + } + for(pcol = A->first_col; pcol != 0; pcol = pnext_col) { + pnext_col = pcol->next_col; + pcol->first_row = pcol->last_row = NIL(sm_element); + sm_col_free(pcol); + } +#endif + + /* Free the arrays to map row/col numbers into pointers */ + FREE(A->rows); + FREE(A->cols); + FREE(A); +} + + +sm_matrix * +sm_dup(A) +sm_matrix *A; +{ + register sm_row *prow; + register sm_element *p; + register sm_matrix *B; + + B = sm_alloc(); + if (A->last_row != 0) { + sm_resize(B, A->last_row->row_num, A->last_col->col_num); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(B, p->row_num, p->col_num); + } + } + } + return B; +} + + +void +sm_resize(A, row, col) +register sm_matrix *A; +int row, col; +{ + register int i, new_size; + + if (row >= A->rows_size) { + new_size = MAX(A->rows_size*2, row+1); + A->rows = REALLOC(sm_row *, A->rows, new_size); + for(i = A->rows_size; i < new_size; i++) { + A->rows[i] = NIL(sm_row); + } + A->rows_size = new_size; + } + + if (col >= A->cols_size) { + new_size = MAX(A->cols_size*2, col+1); + A->cols = REALLOC(sm_col *, A->cols, new_size); + for(i = A->cols_size; i < new_size; i++) { + A->cols[i] = NIL(sm_col); + } + A->cols_size = new_size; + } +} + + +/* + * insert -- insert a value into the matrix + */ +sm_element * +sm_insert(A, row, col) +register sm_matrix *A; +register int row, col; +{ + register sm_row *prow; + register sm_col *pcol; + register sm_element *element; + sm_element *save_element; + + if (row >= A->rows_size || col >= A->cols_size) { + sm_resize(A, row, col); + } + + prow = A->rows[row]; + if (prow == NIL(sm_row)) { + prow = A->rows[row] = sm_row_alloc(); + prow->row_num = row; + sorted_insert(sm_row, A->first_row, A->last_row, A->nrows, + next_row, prev_row, row_num, row, prow); + } + + pcol = A->cols[col]; + if (pcol == NIL(sm_col)) { + pcol = A->cols[col] = sm_col_alloc(); + pcol->col_num = col; + sorted_insert(sm_col, A->first_col, A->last_col, A->ncols, + next_col, prev_col, col_num, col, pcol); + } + + /* get a new item, save its address */ + sm_element_alloc(element); + save_element = element; + + /* insert it into the row list */ + sorted_insert(sm_element, prow->first_col, prow->last_col, + prow->length, next_col, prev_col, col_num, col, element); + + /* if it was used, also insert it into the column list */ + if (element == save_element) { + sorted_insert(sm_element, pcol->first_row, pcol->last_row, + pcol->length, next_row, prev_row, row_num, row, element); + } else { + /* otherwise, it was already in matrix -- free element we allocated */ + sm_element_free(save_element); + } + return element; +} + + +sm_element * +sm_find(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; +{ + sm_row *prow; + sm_col *pcol; + + prow = sm_get_row(A, rownum); + if (prow == NIL(sm_row)) { + return NIL(sm_element); + } else { + pcol = sm_get_col(A, colnum); + if (pcol == NIL(sm_col)) { + return NIL(sm_element); + } + if (prow->length < pcol->length) { + return sm_row_find(prow, colnum); + } else { + return sm_col_find(pcol, rownum); + } + } +} + + +void +sm_remove(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; +{ + sm_remove_element(A, sm_find(A, rownum, colnum)); +} + + + +void +sm_remove_element(A, p) +register sm_matrix *A; +register sm_element *p; +{ + register sm_row *prow; + register sm_col *pcol; + + if (p == 0) return; + + /* Unlink the element from its row */ + prow = sm_get_row(A, p->row_num); + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + + /* if no more elements in the row, discard the row header */ + if (prow->first_col == NIL(sm_element)) { + sm_delrow(A, p->row_num); + } + + /* Unlink the element from its column */ + pcol = sm_get_col(A, p->col_num); + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + + /* if no more elements in the column, discard the column header */ + if (pcol->first_row == NIL(sm_element)) { + sm_delcol(A, p->col_num); + } + + sm_element_free(p); +} + +void +sm_delrow(A, i) +sm_matrix *A; +int i; +{ + register sm_element *p, *pnext; + sm_col *pcol; + sm_row *prow; + + prow = sm_get_row(A, i); + if (prow != NIL(sm_row)) { + /* walk across the row */ + for(p = prow->first_col; p != 0; p = pnext) { + pnext = p->next_col; + + /* unlink the item from the column (and delete it) */ + pcol = sm_get_col(A, p->col_num); + sm_col_remove_element(pcol, p); + + /* discard the column if it is now empty */ + if (pcol->first_row == NIL(sm_element)) { + sm_delcol(A, pcol->col_num); + } + } + + /* discard the row -- we already threw away the elements */ + A->rows[i] = NIL(sm_row); + dll_unlink(prow, A->first_row, A->last_row, + next_row, prev_row, A->nrows); + prow->first_col = prow->last_col = NIL(sm_element); + sm_row_free(prow); + } +} + +void +sm_delcol(A, i) +sm_matrix *A; +int i; +{ + register sm_element *p, *pnext; + sm_row *prow; + sm_col *pcol; + + pcol = sm_get_col(A, i); + if (pcol != NIL(sm_col)) { + /* walk down the column */ + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; + + /* unlink the element from the row (and delete it) */ + prow = sm_get_row(A, p->row_num); + sm_row_remove_element(prow, p); + + /* discard the row if it is now empty */ + if (prow->first_col == NIL(sm_element)) { + sm_delrow(A, prow->row_num); + } + } + + /* discard the column -- we already threw away the elements */ + A->cols[i] = NIL(sm_col); + dll_unlink(pcol, A->first_col, A->last_col, + next_col, prev_col, A->ncols); + pcol->first_row = pcol->last_row = NIL(sm_element); + sm_col_free(pcol); + } +} + +void +sm_copy_row(dest, dest_row, prow) +register sm_matrix *dest; +int dest_row; +sm_row *prow; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(dest, dest_row, p->col_num); + } +} + + +void +sm_copy_col(dest, dest_col, pcol) +register sm_matrix *dest; +int dest_col; +sm_col *pcol; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) sm_insert(dest, dest_col, p->row_num); + } +} + + +sm_row * +sm_longest_row(A) +sm_matrix *A; +{ + register sm_row *large_row, *prow; + register int max_length; + + max_length = 0; + large_row = NIL(sm_row); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->length > max_length) { + max_length = prow->length; + large_row = prow; + } + } + return large_row; +} + + +sm_col * +sm_longest_col(A) +sm_matrix *A; +{ + register sm_col *large_col, *pcol; + register int max_length; + + max_length = 0; + large_col = NIL(sm_col); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + if (pcol->length > max_length) { + max_length = pcol->length; + large_col = pcol; + } + } + return large_col; +} + +int +sm_num_elements(A) +sm_matrix *A; +{ + register sm_row *prow; + register int num; + + num = 0; + sm_foreach_row(A, prow) { + num += prow->length; + } + return num; +} + +int +sm_read(fp, A) +FILE *fp; +sm_matrix **A; +{ + int i, j, err; + + *A = sm_alloc(); + while (! feof(fp)) { + err = fscanf(fp, "%d %d", &i, &j); + if (err == EOF) { + return 1; + } else if (err != 2) { + return 0; + } + (void) sm_insert(*A, i, j); + } + return 1; +} + + +int +sm_read_compressed(fp, A) +FILE *fp; +sm_matrix **A; +{ + int i, j, k, nrows, ncols; + unsigned long x; + + *A = sm_alloc(); + if (fscanf(fp, "%d %d", &nrows, &ncols) != 2) { + return 0; + } + sm_resize(*A, nrows, ncols); + + for(i = 0; i < nrows; i++) { + if (fscanf(fp, "%lx", &x) != 1) { + return 0; + } + for(j = 0; j < ncols; j += 32) { + if (fscanf(fp, "%lx", &x) != 1) { + return 0; + } + for(k = j; x != 0; x >>= 1, k++) { + if (x & 1) { + (void) sm_insert(*A, i, k); + } + } + } + } + return 1; +} + + +void +sm_write(fp, A) +FILE *fp; +sm_matrix *A; +{ + register sm_row *prow; + register sm_element *p; + + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) fprintf(fp, "%d %d\n", p->row_num, p->col_num); + } + } +} + +void +sm_print(fp, A) +FILE *fp; +sm_matrix *A; +{ + register sm_row *prow; + register sm_col *pcol; + int c; + + if (A->last_col->col_num >= 100) { + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", (pcol->col_num / 100)%10); + } + putc('\n', fp); + } + + if (A->last_col->col_num >= 10) { + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", (pcol->col_num / 10)%10); + } + putc('\n', fp); + } + + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", pcol->col_num % 10); + } + putc('\n', fp); + + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "-"); + } + putc('\n', fp); + + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + (void) fprintf(fp, "%3d:", prow->row_num, prow->length); + + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + c = sm_row_find(prow, pcol->col_num) ? '1' : '.'; + putc(c, fp); + } + putc('\n', fp); + } +} + + +void +sm_dump(A, s, max) +sm_matrix *A; +char *s; +int max; +{ + FILE *fp = stdout; + + (void) fprintf(fp, "%s %d rows by %d cols\n", s, A->nrows, A->ncols); + if (A->nrows < max) { + sm_print(fp, A); + } +} + +void +sm_cleanup() +{ +#ifdef FAST_AND_LOOSE + register sm_element *p, *pnext; + register sm_row *prow, *pnextrow; + register sm_col *pcol, *pnextcol; + + for(p = sm_element_freelist; p != 0; p = pnext) { + pnext = p->next_col; + FREE(p); + } + sm_element_freelist = 0; + + for(prow = sm_row_freelist; prow != 0; prow = pnextrow) { + pnextrow = prow->next_row; + FREE(prow); + } + sm_row_freelist = 0; + + for(pcol = sm_col_freelist; pcol != 0; pcol = pnextcol) { + pnextcol = pcol->next_col; + FREE(pcol); + } + sm_col_freelist = 0; +#endif +} diff --git a/sis/sparse/rows.c b/sis/sparse/rows.c new file mode 100644 index 0000000..25bd446 --- /dev/null +++ b/sis/sparse/rows.c @@ -0,0 +1,314 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/sparse/rows.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include <stdio.h> +#include "sparse_int.h" + + +/* + * allocate a new row vector + */ +sm_row * +sm_row_alloc() +{ + register sm_row *prow; + +#ifdef FAST_AND_LOOSE + if (sm_row_freelist == NIL(sm_row)) { + prow = ALLOC(sm_row, 1); + } else { + prow = sm_row_freelist; + sm_row_freelist = prow->next_row; + } +#else + prow = ALLOC(sm_row, 1); +#endif + + prow->row_num = 0; + prow->length = 0; + prow->first_col = prow->last_col = NIL(sm_element); + prow->next_row = prow->prev_row = NIL(sm_row); + prow->flag = 0; + prow->user_word = NIL(char); /* for our user ... */ + return prow; +} + + +/* + * free a row vector -- for FAST_AND_LOOSE, this is real cheap for rows; + * however, freeing a column must still walk down the column discarding + * the elements one-by-one; that is the only use for the extra '-DCOLS' + * compile flag ... + */ +void +sm_row_free(prow) +register sm_row *prow; +{ +#if defined(FAST_AND_LOOSE) && ! defined(COLS) + if (prow->first_col != NIL(sm_element)) { + /* Add the linked list of row items to the free list */ + prow->last_col->next_col = sm_element_freelist; + sm_element_freelist = prow->first_col; + } + + /* Add the row to the free list of rows */ + prow->next_row = sm_row_freelist; + sm_row_freelist = prow; +#else + register sm_element *p, *pnext; + + for(p = prow->first_col; p != 0; p = pnext) { + pnext = p->next_col; + sm_element_free(p); + } + FREE(prow); +#endif +} + + +/* + * duplicate an existing row + */ +sm_row * +sm_row_dup(prow) +register sm_row *prow; +{ + register sm_row *pnew; + register sm_element *p; + + pnew = sm_row_alloc(); + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_row_insert(pnew, p->col_num); + } + return pnew; +} + + +/* + * insert an element into a row vector + */ +sm_element * +sm_row_insert(prow, col) +register sm_row *prow; +register int col; +{ + register sm_element *test, *element; + + /* get a new item, save its address */ + sm_element_alloc(element); + test = element; + sorted_insert(sm_element, prow->first_col, prow->last_col, prow->length, + next_col, prev_col, col_num, col, test); + + /* if item was not used, free it */ + if (element != test) { + sm_element_free(element); + } + + /* either way, return the current new value */ + return test; +} + + +/* + * remove an element from a row vector + */ +void +sm_row_remove(prow, col) +register sm_row *prow; +register int col; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0 && p->col_num < col; p = p->next_col) + ; + if (p != 0 && p->col_num == col) { + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + sm_element_free(p); + } +} + + +/* + * find an element (if it is in the row vector) + */ +sm_element * +sm_row_find(prow, col) +sm_row *prow; +int col; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0 && p->col_num < col; p = p->next_col) + ; + if (p != 0 && p->col_num == col) { + return p; + } else { + return NIL(sm_element); + } +} + +/* + * return 1 if row p2 contains row p1; 0 otherwise + */ +int +sm_row_contains(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + while (q1 != 0) { + if (q2 == 0 || q1->col_num < q2->col_num) { + return 0; + } else if (q1->col_num == q2->col_num) { + q1 = q1->next_col; + q2 = q2->next_col; + } else { + q2 = q2->next_col; + } + } + return 1; +} + + +/* + * return 1 if row p1 and row p2 share an element in common + */ +int +sm_row_intersects(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + if (q1 == 0 || q2 == 0) return 0; + for(;;) { + if (q1->col_num < q2->col_num) { + if ((q1 = q1->next_col) == 0) { + return 0; + } + } else if (q1->col_num > q2->col_num) { + if ((q2 = q2->next_col) == 0) { + return 0; + } + } else { + return 1; + } + } +} + + +/* + * compare two rows, lexical ordering + */ +int +sm_row_compare(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + while(q1 != 0 && q2 != 0) { + if (q1->col_num != q2->col_num) { + return q1->col_num - q2->col_num; + } + q1 = q1->next_col; + q2 = q2->next_col; + } + + if (q1 != 0) { + return 1; + } else if (q2 != 0) { + return -1; + } else { + return 0; + } +} + + +/* + * return the intersection + */ +sm_row * +sm_row_and(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + register sm_row *result; + + result = sm_row_alloc(); + q1 = p1->first_col; + q2 = p2->first_col; + if (q1 == 0 || q2 == 0) return result; + for(;;) { + if (q1->col_num < q2->col_num) { + if ((q1 = q1->next_col) == 0) { + return result; + } + } else if (q1->col_num > q2->col_num) { + if ((q2 = q2->next_col) == 0) { + return result; + } + } else { + (void) sm_row_insert(result, q1->col_num); + if ((q1 = q1->next_col) == 0) { + return result; + } + if ((q2 = q2->next_col) == 0) { + return result; + } + } + } +} + +int +sm_row_hash(prow, modulus) +sm_row *prow; +int modulus; +{ + register int sum; + register sm_element *p; + + sum = 0; + for(p = prow->first_col; p != 0; p = p->next_col) { + sum = (sum*17 + p->col_num) % modulus; + } + return sum; +} + +/* + * remove an element from a row vector (given a pointer to the element) + */ +void +sm_row_remove_element(prow, p) +register sm_row *prow; +register sm_element *p; +{ + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + sm_element_free(p); +} + + +void +sm_row_print(fp, prow) +FILE *fp; +sm_row *prow; +{ + sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) fprintf(fp, " %d", p->col_num); + } +} diff --git a/sis/sparse/sparse.doc b/sis/sparse/sparse.doc new file mode 100644 index 0000000..55bd499 --- /dev/null +++ b/sis/sparse/sparse.doc @@ -0,0 +1,400 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/sparse/sparse.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +/* + * sparse matrix element + */ +struct sm_element { + int row_num; /* row number of this element */ + int col_num; /* column number of this element */ + sm_element *next_row; /* pointers to next and previous row */ + sm_element *prev_row; + sm_element *next_col; /* pointer to next and previous column */ + sm_element *prev_col; + char *user_word; /* user-definable generic pointer */ +}; + + +/* + * sparse row + */ +struct sm_row { + int row_num; /* row number of this row */ + int length; /* number of elements in this row */ + int flag; /* user-definable flag */ + sm_element *first_col; /* first element in this row */ + sm_element *last_col; /* last element in this row */ + sm_row *next_row; /* next and previous rows */ + sm_row *prev_row; /* previous row (in sm_matrix linked list) */ + char *user_word; /* user-defined word */ +}; + + +/* + * sparse column + */ +struct sm_col { + int col_num; /* column number of this column */ + int length; /* nubmer of elements in this column */ + int flag; /* user-definable flag */ + sm_element *first_row; /* first element in this column */ + sm_element *last_row; /* last element in this column */ + sm_col *next_col; /* next and previous columns */ + sm_col *prev_col; /* previous column (in sm_matrix linked list) */ + char *user_word; /* user-defined word */ +}; + + +/* + * sparse matrix + */ +struct sm_matrix_struct { + sm_row **rows; /* pointer to row headers (by row #) */ + int rows_size; /* alloc'ed size of above array */ + sm_col **cols; /* pointer to column headers (by col #) */ + int cols_size; /* alloc'ed size of above array */ + sm_row *first_row; /* first and last rows in matrix */ + sm_row *last_row; + int nrows; /* number of rows */ + sm_col *first_col; /* first and last columns in matrix */ + sm_col *last_col; + int ncols; /* number of columns */ +}; + +/* + * Useful macros to loop over all rows (or columns) in a matrix, and to + * loop over all elements in a row (or column). + * + * Warning: these macros are unsafe if you attempt to delete the current + * item (either row, column, or element). + */ + + +#define sm_foreach_row(A, prow) \ + for(prow = A->first_row; prow != 0; prow = prow->next_row) + +#define sm_foreach_col(A, pcol) \ + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) + +#define sm_foreach_row_element(prow, p) \ + for(p = (prow == 0) ? 0 : prow->first_col; p != 0; p = p->next_col) + +#define sm_foreach_col_element(pcol, p) \ + for(p = (pcol == 0) ? 0 : pcol->first_row; p != 0; p = p->next_row) + + +sm_matrix * +sm_alloc() + Allocates a new sparse matrix. Initially it has no rows and no columns. + + +void +sm_free(A) +sm_matrix *A; + Frees a sparse matrix. All rows, columns and elements of the matrix + are discarded. + + +sm_matrix * +sm_dup(A) +sm_matrix *A; + Make a copy of the sparse matrix A. + + +sm_element * +sm_insert(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; + Create an element at (rownum, colnum) in the sparse matrix A, if one + does not already exit. Returns a pointer to the sparse matrix element. + + +sm_element * +sm_find(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; + Locate the item at position (rownum, colnum) in sparse matrix A. + Returns 0 if no element exists at that location, otherwise returns a + pointer to the sparse matrix element. + + +void +sm_remove(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; + Remove the element at (rownum, colnum) in sparse matrix A (if it exists). + + +void +sm_remove_element(A, p) +sm_matrix *A; +sm_element *p; + Remove the element p from the sparse matrix A. Disaster can occur if + p is not an element of A. + + +sm_row * +sm_get_row(A, rownum) +sm_matrix *A; +int rownum; + Return a pointer to the specified row of sparse matrix A. Returns 0 + if there are no elements in that row. + + +sm_col * +sm_get_col(A, colnum) +sm_matrix *A; +int colnum; + Return a pointer to the specified column of sparse matrix A. Returns 0 + if there are no elements in that column. + + +void +sm_delrow(A, rownum) +sm_matrix *A; +int rownum; + Delete a row from the sparse matrix (if it exists). All elements in + the row are discarded. + + +void +sm_delcol(A, colnum) +sm_matrix *A; +int colnum; + Delete a column from the sparse matrix (if it exists). All elements + in the column are discarded. + + +void +sm_copy_row(A, rownum, row) +sm_matrix *A; +int rownum; +sm_row *row; + Copy a row to the specified row number of sparse matrix A. + + +void +sm_copy_col(A, colnum, col) +sm_matrix *A; +int colnum; +sm_col *col; + Copy a column to the specified column number of sparse matrix A. + + +sm_row * +sm_longest_row(A) +sm_matrix *A; + Return a pointer to the row in A with the most elements; returns + 0 if there are no rows in A. + + +sm_col * +sm_longest_col(A) +sm_matrix *A; + Return a pointer to the column in A with the most elements; returns + 0 if there are no columns in A. + + +int +sm_read(fp, A) +FILE *fp; +sm_matrix **A; + Reads a sparse matrix from a file. Format is <row_num, col_num>. + Returns 1 on normal termination, 0 on any error. No attempt is made + to give the cause for the error. + + +void +sm_write(fp, A) +FILE *fp; +sm_matrix *A; + Writes a sparse matrix to a file which can be read by sm_read. + + +void +sm_print(fp, A) +FILE *fp; +sm_matrix *A; + Debugging routine to print the structural layout of a sparse matrix. + + +int +sm_num_elements(A) +sm_matrix *A; + Returns the number of nonzero elements in the matrix. + +sm_row * +sm_row_alloc() + Allocates a new row vector. + + +void +sm_row_free(row) +sm_row *row; + Frees a row vector and discards its elements. + + +sm_row * +sm_row_dup(row) +sm_row *row; + Creates a new row vector which is a copy of an existing row vector. + + +sm_element * +sm_row_insert(row, colnum) +sm_row *row; +int colnum; + Adds a column to a row vector, if it does not already exist. Returns + a pointer to the element. + + +sm_element * +sm_row_remove(row, colnum) +sm_row *row; +int colnum; + Removes an element from a row vector, if it exists. + + +sm_element * +sm_row_find(row, colnum) +sm_row *row; +int colnum; + Finds an element of a row vector, or returns 0 if the element does not + exist. + + +int +sm_row_contains(row1, row2) +sm_row *row1, *row2; + Returns 1 if row2 structurally contains row1 (that is, row2 has + an element everywhere row1 does). + + +int +sm_row_intersects(row1, row2) +sm_row *row1, *row2; + Returns 1 if row1 and row2 share a column in common. + + +sm_row * +sm_row_and(row1, row2) +sm_row *row1, *row2; + Returns a row vector containing the elements which row1 and + row2 have in common. + + +int +sm_row_compare(row1, row2) +sm_row *row1, *row2; + Returns -1, 0, or 1 depending on the lexiographical ordering + of the two rows. Suitable for use by st (see st.doc). + + +int +sm_row_hash(row1, modulus) +sm_row *row1; +int modulus; + A hashing function defined on rows which is suitable for use + by st (see st.doc). + + +void +sm_row_print(fp, row1) +FILE *fp; +sm_row *row1; + Print a row as a sparse vector -- useful for debugging. + +sm_column * +sm_col_alloc() + Allocates a new column vector. + +void +sm_col_free(col) +sm_col *col; + Frees a column vector and discards its elements. + + +sm_column * +sm_col_dup(col) +sm_column *col; + Creates a new column vector which is a copy of an existing + column vector. + + +sm_element * +sm_col_insert(col, rownum) +sm_column *col; +int rownum; + Adds an element to a column vector. Returns a pointer to the element. + + +void +sm_col_remove(col, rownum) +sm_column *col; +int rownum; + Removes an element from a column vector, if it exists. + + +sm_element * +sm_col_find(column, colnum) +sm_column *column; +int colnum; + Finds an element of a column vector. Returns 0 if the element does not + exist. + + +int +sm_col_contains(column1, column2) +sm_column *column1, *column2; + Returns 1 if column2 contains column1 (that is, column2 has + an element for every row that column1 does). + + +int +sm_col_intersects(column1, column2) +sm_column *column1, *column2; + Returns 1 if column1 and column2 share a row number in common. + + +sm_col * +sm_col_and(col1, col2) +sm_col *col1, *col2; + Returns a column vector containing the elements which col1 and + col2 have in common. + + +int +sm_col_compare(col1, col2) +sm_column *col1, *col2; + Returns -1, 0, or 1 depending on the lexiographical ordering + of the two columns. Suitable for use by st (see st.doc). + + +int +sm_col_hash(col, modulus) +sm_col *col; +int modulus; + A hashing function defined on columns which is suitable for use + by st (see st.doc). + + +void +sm_col_print(fp, col) +FILE *fp; +sm_column *col; + Print a column as a sparse vector -- useful for debugging. + +int +sm_block_partition(A, L, R) +sm_matrix *A; +sm_matrix **l, **R; + Returns 1 if A has a block-decomposition. In this case, L equals + the maximal block component of A, and R is the remainder of the + matrix. (Note that R may itself contain further subblocks; + L does not). Returns 0 if A does not have a block decomposition. diff --git a/sis/sparse/sparse.h b/sis/sparse/sparse.h new file mode 100644 index 0000000..1fab2b4 --- /dev/null +++ b/sis/sparse/sparse.h @@ -0,0 +1,168 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/sparse/sparse.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#ifndef SPARSE_H +#define SPARSE_H + +#include "ansi.h" + +/* hack to fix conflict with libX11.a */ +#define sm_alloc sm_allocate +#define sm_free sm_free_space + +/* + * sparse.h -- sparse matrix package header file + */ + +typedef struct sm_element_struct sm_element; +typedef struct sm_row_struct sm_row; +typedef struct sm_col_struct sm_col; +typedef struct sm_matrix_struct sm_matrix; + + +/* + * sparse matrix element + */ +struct sm_element_struct { + int row_num; /* row number of this element */ + int col_num; /* column number of this element */ + sm_element *next_row; /* next row in this column */ + sm_element *prev_row; /* previous row in this column */ + sm_element *next_col; /* next column in this row */ + sm_element *prev_col; /* previous column in this row */ + char *user_word; /* user-defined word */ +}; + + +/* + * row header + */ +struct sm_row_struct { + int row_num; /* the row number */ + int length; /* number of elements in this row */ + int flag; /* user-defined word */ + sm_element *first_col; /* first element in this row */ + sm_element *last_col; /* last element in this row */ + sm_row *next_row; /* next row (in sm_matrix linked list) */ + sm_row *prev_row; /* previous row (in sm_matrix linked list) */ + char *user_word; /* user-defined word */ +}; + + +/* + * column header + */ +struct sm_col_struct { + int col_num; /* the column number */ + int length; /* number of elements in this column */ + int flag; /* user-defined word */ + sm_element *first_row; /* first element in this column */ + sm_element *last_row; /* last element in this column */ + sm_col *next_col; /* next column (in sm_matrix linked list) */ + sm_col *prev_col; /* prev column (in sm_matrix linked list) */ + char *user_word; /* user-defined word */ +}; + + +/* + * A sparse matrix + */ +struct sm_matrix_struct { + sm_row **rows; /* pointer to row headers (by row #) */ + int rows_size; /* alloc'ed size of above array */ + sm_col **cols; /* pointer to column headers (by col #) */ + int cols_size; /* alloc'ed size of above array */ + sm_row *first_row; /* first row (linked list of all rows) */ + sm_row *last_row; /* last row (linked list of all rows) */ + int nrows; /* number of rows */ + sm_col *first_col; /* first column (linked list of columns) */ + sm_col *last_col; /* last column (linked list of columns) */ + int ncols; /* number of columns */ + char *user_word; /* user-defined word */ +}; + + +#define sm_get_col(A, colnum) \ + (((colnum) >= 0 && (colnum) < (A)->cols_size) ? \ + (A)->cols[colnum] : (sm_col *) 0) + +#define sm_get_row(A, rownum) \ + (((rownum) >= 0 && (rownum) < (A)->rows_size) ? \ + (A)->rows[rownum] : (sm_row *) 0) + +#define sm_foreach_row(A, prow) \ + for(prow = A->first_row; prow != 0; prow = prow->next_row) + +#define sm_foreach_col(A, pcol) \ + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) + +#define sm_foreach_row_element(prow, p) \ + for(p = (prow == 0) ? 0 : prow->first_col; p != 0; p = p->next_col) + +#define sm_foreach_col_element(pcol, p) \ + for(p = (pcol == 0) ? 0 : pcol->first_row; p != 0; p = p->next_row) + +#define sm_put(x, val) \ + (x->user_word = (char *) val) + +#define sm_get(type, x) \ + ((type) (x->user_word)) + +EXTERN sm_matrix *sm_allocate ARGS((void)); +EXTERN sm_matrix *sm_alloc_size ARGS((int, int)); +EXTERN void sm_free_space ARGS((sm_matrix *)); +EXTERN sm_matrix *sm_dup ARGS((sm_matrix *)); +EXTERN void sm_resize ARGS((sm_matrix *, int, int)); +EXTERN sm_element *sm_insert ARGS((sm_matrix *, int, int)); +EXTERN sm_element *sm_find ARGS((sm_matrix *, int, int)); +EXTERN void sm_remove ARGS((sm_matrix *, int, int)); +EXTERN void sm_remove_element ARGS((sm_matrix *, sm_element *)); +EXTERN void sm_delrow ARGS((sm_matrix *, int)); +EXTERN void sm_delcol ARGS((sm_matrix *, int)); +EXTERN void sm_copy_row ARGS((sm_matrix *, int, sm_row *)); +EXTERN void sm_copy_col ARGS((sm_matrix *, int, sm_col *)); +EXTERN sm_row *sm_longest_row ARGS((sm_matrix *)); +EXTERN sm_col *sm_longest_col ARGS((sm_matrix *)); +EXTERN int sm_num_elements ARGS((sm_matrix *)); +EXTERN int sm_read ARGS((FILE *, sm_matrix **)); +EXTERN int sm_read_compressed ARGS((FILE *, sm_matrix **)); +EXTERN void sm_write ARGS((FILE *, sm_matrix *)); +EXTERN void sm_print ARGS((FILE *, sm_matrix *)); +EXTERN void sm_dump ARGS((sm_matrix *, char *, int)); +EXTERN void sm_cleanup ARGS((void)); + +EXTERN sm_col *sm_col_alloc ARGS((void)); +EXTERN void sm_col_free ARGS((sm_col *)); +EXTERN sm_col *sm_col_dup ARGS((sm_col *)); +EXTERN sm_element *sm_col_insert ARGS((sm_col *, int)); +EXTERN void sm_col_remove ARGS((sm_col *, int)); +EXTERN sm_element *sm_col_find ARGS((sm_col *, int)); +EXTERN int sm_col_contains ARGS((sm_col *, sm_col *)); +EXTERN int sm_col_intersects ARGS((sm_col *, sm_col *)); +EXTERN int sm_col_compare ARGS((sm_col *, sm_col *)); +EXTERN sm_col *sm_col_and ARGS((sm_col *, sm_col *)); +EXTERN int sm_col_hash ARGS((sm_col *, int)); +EXTERN void sm_col_remove_element ARGS((sm_col *, sm_element *)); +EXTERN void sm_col_print ARGS((FILE *, sm_col *)); + +EXTERN sm_row *sm_row_alloc ARGS((void)); +EXTERN void sm_row_free ARGS((sm_row *)); +EXTERN sm_row *sm_row_dup ARGS((sm_row *)); +EXTERN sm_element *sm_row_insert ARGS((sm_row *, int)); +EXTERN void sm_row_remove ARGS((sm_row *, int)); +EXTERN sm_element *sm_row_find ARGS((sm_row *, int)); +EXTERN int sm_row_contains ARGS((sm_row *, sm_row *)); +EXTERN int sm_row_intersects ARGS((sm_row *, sm_row *)); +EXTERN int sm_row_compare ARGS((sm_row *, sm_row *)); +EXTERN sm_row *sm_row_and ARGS((sm_row *, sm_row *)); +EXTERN int sm_row_hash ARGS((sm_row *, int)); +EXTERN void sm_row_remove_element ARGS((sm_row *, sm_element *)); +EXTERN void sm_row_print ARGS((FILE *, sm_row *)); + +#endif diff --git a/sis/sparse/sparse_int.h b/sis/sparse/sparse_int.h new file mode 100644 index 0000000..4cd2054 --- /dev/null +++ b/sis/sparse/sparse_int.h @@ -0,0 +1,118 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/sparse/sparse_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include "sparse.h" +#include "util.h" + + + +/* + * sorted, double-linked list insertion + * + * type: object type + * + * first, last: fields (in header) to head and tail of the list + * count: field (in header) of length of the list + * + * next, prev: fields (in object) to link next and previous objects + * value: field (in object) which controls the order + * + * newval: value field for new object + * e: an object to use if insertion needed (set to actual value used) + */ + +#define sorted_insert(type, first, last, count, next, prev, value, newval, e) \ + if (last == 0) { \ + e->value = newval; \ + first = e; \ + last = e; \ + e->next = 0; \ + e->prev = 0; \ + count++; \ + } else if (last->value < newval) { \ + e->value = newval; \ + last->next = e; \ + e->prev = last; \ + last = e; \ + e->next = 0; \ + count++; \ + } else if (first->value > newval) { \ + e->value = newval; \ + first->prev = e; \ + e->next = first; \ + first = e; \ + e->prev = 0; \ + count++; \ + } else { \ + type *p; \ + for(p = first; p->value < newval; p = p->next) \ + ; \ + if (p->value > newval) { \ + e->value = newval; \ + p = p->prev; \ + p->next->prev = e; \ + e->next = p->next; \ + p->next = e; \ + e->prev = p; \ + count++; \ + } else { \ + e = p; \ + } \ + } + + +/* + * double linked-list deletion + */ +#define dll_unlink(p, first, last, next, prev, count) { \ + if (p->prev == 0) { \ + first = p->next; \ + } else { \ + p->prev->next = p->next; \ + } \ + if (p->next == 0) { \ + last = p->prev; \ + } else { \ + p->next->prev = p->prev; \ + } \ + count--; \ +} + + +#ifdef FAST_AND_LOOSE +extern sm_element *sm_element_freelist; +extern sm_row *sm_row_freelist; +extern sm_col *sm_col_freelist; + +#define sm_element_alloc(newobj) \ + if (sm_element_freelist == NIL(sm_element)) { \ + newobj = ALLOC(sm_element, 1); \ + } else { \ + newobj = sm_element_freelist; \ + sm_element_freelist = sm_element_freelist->next_col; \ + } \ + newobj->user_word = NIL(char); \ + +#define sm_element_free(e) \ + (e->next_col = sm_element_freelist, sm_element_freelist = e) + +#else + +#define sm_element_alloc(newobj) \ + newobj = ALLOC(sm_element, 1); \ + newobj->user_word = NIL(char); +#define sm_element_free(e) \ + FREE(e) +#endif + + +extern void sm_row_remove_element(); +extern void sm_col_remove_element(); + +/* LINTLIBRARY */ diff --git a/sis/speed/Makefile.am b/sis/speed/Makefile.am new file mode 100644 index 0000000..4cae387 --- /dev/null +++ b/sis/speed/Makefile.am @@ -0,0 +1,12 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libspeed.a +libspeed_a_SOURCES = absorb.c buf_delay.c buf_recur.c buf_replace.c \ + buf_trans2.c buf_util.c com_speed.c gbx.c new_speed.c new_wght_util.c \ + nsp_util.c sp_buffer.c sp_network.c speed_2c.c speed_and.c \ + speed_delay.c speed_loop.c speed_net.c speed_no.c speed_or.c \ + speed_plot.c speed_util.c speedup.c weight.c weight_util.c \ + buffer_int.h gbx_int.h new_speed_models.h speed_int.h +pkginclude_HEADERS = speed.h +dist_doc_DATA = speed.doc diff --git a/sis/speed/Makefile.in b/sis/speed/Makefile.in new file mode 100644 index 0000000..b22a373 --- /dev/null +++ b/sis/speed/Makefile.in @@ -0,0 +1,432 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libspeed_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/speed +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libspeed_a_AR = $(AR) $(ARFLAGS) +libspeed_a_LIBADD = +am_libspeed_a_OBJECTS = absorb.$(OBJEXT) buf_delay.$(OBJEXT) \ + buf_recur.$(OBJEXT) buf_replace.$(OBJEXT) buf_trans2.$(OBJEXT) \ + buf_util.$(OBJEXT) com_speed.$(OBJEXT) gbx.$(OBJEXT) \ + new_speed.$(OBJEXT) new_wght_util.$(OBJEXT) nsp_util.$(OBJEXT) \ + sp_buffer.$(OBJEXT) sp_network.$(OBJEXT) speed_2c.$(OBJEXT) \ + speed_and.$(OBJEXT) speed_delay.$(OBJEXT) speed_loop.$(OBJEXT) \ + speed_net.$(OBJEXT) speed_no.$(OBJEXT) speed_or.$(OBJEXT) \ + speed_plot.$(OBJEXT) speed_util.$(OBJEXT) speedup.$(OBJEXT) \ + weight.$(OBJEXT) weight_util.$(OBJEXT) +libspeed_a_OBJECTS = $(am_libspeed_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libspeed_a_SOURCES) +DIST_SOURCES = $(libspeed_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libspeed.a +libspeed_a_SOURCES = absorb.c buf_delay.c buf_recur.c buf_replace.c \ + buf_trans2.c buf_util.c com_speed.c gbx.c new_speed.c new_wght_util.c \ + nsp_util.c sp_buffer.c sp_network.c speed_2c.c speed_and.c \ + speed_delay.c speed_loop.c speed_net.c speed_no.c speed_or.c \ + speed_plot.c speed_util.c speedup.c weight.c weight_util.c \ + buffer_int.h gbx_int.h new_speed_models.h speed_int.h + +pkginclude_HEADERS = speed.h +dist_doc_DATA = speed.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/speed/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/speed/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libspeed.a: $(libspeed_a_OBJECTS) $(libspeed_a_DEPENDENCIES) + -rm -f libspeed.a + $(libspeed_a_AR) libspeed.a $(libspeed_a_OBJECTS) $(libspeed_a_LIBADD) + $(RANLIB) libspeed.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/speed/absorb.c b/sis/speed/absorb.c new file mode 100644 index 0000000..0536d38 --- /dev/null +++ b/sis/speed/absorb.c @@ -0,0 +1,177 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/absorb.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include "speed_int.h" + +/* + * Collapse the critical nodes in the transitive anin of "f" for a distance + * "dist" + */ +void +speed_absorb(f, speed_param) +node_t *f; +speed_global_t *speed_param; +{ + st_table *table; /* Temp reference */ + array_t *temp_array; /* Temp array for bfs implementation */ + node_t *temp, *fi; + int i, j, k; + int dist = speed_param->dist; + int more_to_come, first = 0, last; + + if (f->type != INTERNAL) { + (void) fprintf(sisout,"Can only absorb internal nodes \n"); + return; + } + + table = st_init_table(st_ptrcmp, st_ptrhash); + temp_array = array_alloc(node_t *, 0); + array_insert_last(node_t *, temp_array, f); + (void) st_insert(table, (char *)f, (char *)(dist+1)); + + more_to_come = TRUE; + for (i = dist; (i > 0) && more_to_come ; i--){ + more_to_come = FALSE; + last = array_n(temp_array); + for (j = first; j < last; j++){ + temp = array_fetch(node_t *, temp_array, j); + foreach_fanin(temp, k, fi) { + if (node_function(fi) == NODE_PI){ + /* + * Will be fanin to the collapsed node + */ + (void) st_insert(table, (char *)fi, (char *)0); + } else if (!st_is_member(table, (char *)fi)){ + /* Not yet visited */ + if (speed_critical(fi, speed_param) ){ + /* + * Add to elements that will be processed + */ + (void) st_insert(table, (char *)fi, (char *)i); + array_insert_last(node_t *, temp_array, fi); + more_to_come = TRUE; + } + } + } + } + first = last; + } + + /* + * collapse all the nodes in temp_array into it + */ + speed_absorb_array(f, speed_param, temp_array, table); + + array_free(temp_array); + st_free_table(table); + return; +} + +void +speed_absorb_array(f, speed_param, temp_array, cache) +node_t *f; +speed_global_t *speed_param; +array_t *temp_array; /* Nodes to be collapsed into node "f" */ +st_table *cache; /* Hash table of the nodes in the array -- may be NIL*/ +{ + + st_table *del_table; + st_table *table; /* Temp reference */ + array_t *del_array; /* Keeps the nodes that are to be deleted */ + node_t *temp, *fi; + char *dummy; + node_t *no; + int i, j; + int more_to_come, first = 0, last; + + if (cache == NIL(st_table)){ + table = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 0; i < array_n(temp_array); i++){ + no = array_fetch(node_t *, temp_array, i); + (void)st_insert(table, (char *)no, ""); + } + } else { + table = cache; + } + + /* + * nodes in the original network that need to be deleted + */ + del_table = st_init_table(st_ptrcmp, st_ptrhash); + del_array = array_alloc(node_t *, 0); + foreach_fanin(f, i, no) { + array_insert_last(node_t *, del_array, no); + } + + if (speed_param->debug) (void)fprintf(sisout, "Collapsing nodes \n"); + more_to_come = TRUE; + while(more_to_come) { + more_to_come = FALSE; + for (i = 1; i < array_n(temp_array); i++){ + temp = array_fetch(node_t *, temp_array, i); + + if (speed_param->debug && node_num_fanin(temp) > 2){ + (void)fprintf(sisout, "WARN: Collapsing at node %s : %s with mo re than 2 ip\n", + node_name(f), node_name(temp)); + } + if (node_collapse(f, temp)) { + if (speed_param->debug) { + node_print(sisout, temp); + } + } + } + foreach_fanin(f, i, temp) { + if (temp->type != PRIMARY_INPUT && + st_lookup(table, (char *)temp, &dummy)){ + more_to_come = TRUE; + } + } + } + /* + * Simplify the node to get rid of the extra literals + */ + + temp = node_simplify(f, NIL(node_t), NODE_SIM_SIMPCOMP); + node_replace(f, temp); + + /* Now remove the nodes that don't fanout anywhere */ + more_to_come = TRUE; + first = 0; + while (more_to_come) { + more_to_come = FALSE; + last = array_n(del_array); + for (i = first; i < last; i++) { + fi = array_fetch(node_t *, del_array, i); + if (node_num_fanout(fi) == 0 ) { + foreach_fanin(fi, j, temp) { + if (! st_insert(del_table, (char *)temp, NIL(char)) ){ + array_insert_last (node_t *, del_array, temp); + more_to_come = TRUE; + } + } + (void) st_delete(table, (char **)&fi, &dummy); + network_delete_node(f->network, fi); + } + (void) st_delete(del_table, (char **)&fi, &dummy); + } + first = last; + } + + /* + * At this stage the entries in "table" is the set of + * nodes that will be retained in the original network + */ + + if (cache == NIL(st_table)) st_free_table(table); + array_free(del_array); + st_free_table(del_table); + + return; +} diff --git a/sis/speed/buf_delay.c b/sis/speed/buf_delay.c new file mode 100644 index 0000000..544d3a9 --- /dev/null +++ b/sis/speed/buf_delay.c @@ -0,0 +1,239 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/buf_delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include "buffer_int.h" + +/* + * Computes the required time at the "pin" input signal of node "fo". + * This differs from the required time at the node generating the signal + */ +void +sp_buf_req_time(fo, buf_param, pin, reqp, loadp) +node_t *fo; +buf_global_t *buf_param; +int pin; +delay_time_t *reqp; /* RETURN: The required time at the signal */ +double *loadp; /* RETURN: The input cap + wire load cap at input */ +{ + delay_model_t model = buf_param->model; + delay_pin_t *pin_delay; + + /* + * The req time has to be at the signal rather than the gate + */ + (void)delay_wire_required_time(fo, pin, model, reqp); + pin_delay = get_pin_delay(fo, pin, model); + + *loadp = pin_delay->load + buf_param->auto_route; +} + + +/* + * Gets the input capacitance of node. In the case of a gate it will + * get the input cap of the first pin for now -- Eventually it should + * get the input cap of most critical input + */ +double +sp_get_pin_load(node, model) +node_t *node; +delay_model_t model; +{ + double load; + delay_pin_t *pin_delay; + + if (node->type == PRIMARY_INPUT){ + load = 0; + } else if (BUFFER(node)->type == BUF){ + load = BUFFER(node)->impl.buffer->ip_load; + } else { + pin_delay = get_pin_delay(node, BUFFER(node)->cfi, model); + load = pin_delay->load; + } + return load; +} + +/* + * Returns the drive of the node that fans into nodep. In the case of a + * gate it will get the drive of the first fanin for now -- Eventually it + * should get the drive of most critical fanin. Also returns the phase of + * selected fanin -- INVERTING || NONINVERTING || NEITHER + */ +delay_time_t +sp_get_input_drive(nodep, model, phase) +node_t *nodep; +delay_model_t model; +pin_phase_t *phase; /* RETURN: The phase of the selected fanin */ +{ + node_t *node; + delay_time_t drive; + delay_pin_t *pin_delay; + + if (nodep->type == PRIMARY_INPUT){ + drive.fall = drive.rise = 0.0; + *phase = PHASE_NONINVERTING; + } else { + node = node_get_fanin(nodep, BUFFER(nodep)->cfi); + if (BUFFER(node)->type == BUF){ + drive = BUFFER(node)->impl.buffer->drive; + *phase = BUFFER(node)->impl.buffer->phase; + } else { + pin_delay = get_pin_delay(node, 0, model); + drive = pin_delay->drive; + *phase = pin_delay->phase; + } + } + return drive; +} + + +void +sp_subtract_delay(phase, block, drive, load, req) +pin_phase_t phase; +delay_time_t block, drive, *req; +double load; +{ + delay_time_t delay; + + delay.rise = block.rise + drive.rise * load; + delay.fall = block.fall + drive.fall * load; + + sp_compute(phase, req, delay); +} + +/* + * Utility routine that will subtract "t" from "req" depending on + * "phase" -- Used to update required times : "req" is changed in place + */ +void +sp_compute(phase, req, t) +pin_phase_t phase; +delay_time_t *req, t; +{ + delay_time_t ip_req; + + ip_req.rise = ip_req.fall = INFINITY; + + if (phase == PHASE_INVERTING || phase == PHASE_NEITHER) { + ip_req.rise = MIN(ip_req.rise, (req->fall - t.fall)); + ip_req.fall = MIN(ip_req.fall, (req->rise - t.rise)); + } + if (phase == PHASE_NONINVERTING || phase == PHASE_NEITHER) { + ip_req.rise = MIN(ip_req.rise, (req->rise - t.rise)); + ip_req.fall = MIN(ip_req.fall, (req->fall - t.fall)); + } + + *req = ip_req; +} +/* + * After a redistribution used to update required time data + * k is the index of the partition and nodeL is the buffer + * that was added during the redistribution. Since the required + * times and caps are known for the fanouts we pass them too. + */ +void +sp_buf_compute_req_time(node, model, req_times, cap_K, k, nodeL) +node_t *node, *nodeL; +delay_model_t model; +delay_time_t *req_times; +double cap_K; +int k; +{ + int i, cfi; + double load; + pin_phase_t phase; + delay_time_t drive, block, t, best; + delay_pin_t *pin_delay; + + if (node->type == PRIMARY_INPUT || BUFFER(node)->type == GATE){ + cfi = node->type == PRIMARY_INPUT ? 0 : BUFFER(node)->cfi; + pin_delay = get_pin_delay(node, cfi, model); + block = pin_delay->block; + drive = pin_delay->drive; + phase = pin_delay->phase; + } else { + phase = BUFFER(node)->impl.buffer->phase; + drive = BUFFER(node)->impl.buffer->drive; + block = BUFFER(node)->impl.buffer->block; + } + + best.rise = best.fall = POS_LARGE; + for (i = 0; i < k; i++) { + best.rise = MIN(best.rise, req_times[i].rise); + best.fall = MIN(best.fall, req_times[i].fall); + } + best.rise = MIN(best.rise, BUFFER(nodeL)->req_time.rise); + best.fall = MIN(best.fall, BUFFER(nodeL)->req_time.fall); + + load = cap_K + sp_get_pin_load(nodeL, model) + compute_wire_load(node_network(node), 1); + t.rise = block.rise + drive.rise * load; + t.fall = block.fall + drive.fall * load; + sp_compute(phase, &best, t); + BUFFER(node)->req_time = best; +} + + + + /* + * Set drive and load of Primary IP/OP respectively to be that of the + * second (next to the smallest) inverter in the library + */ +int +buf_set_pipo_defaults(network, buf_param, load_table, drive_table) +network_t *network; +buf_global_t *buf_param; +st_table **load_table, **drive_table; +{ + lsGen gen; + node_t *node; + double load; + delay_time_t drive; + int setting_env; + int default_inv_index; + + *load_table = st_init_table(st_ptrcmp, st_ptrhash); + *drive_table = st_init_table(st_ptrcmp, st_ptrhash); + default_inv_index = + (buf_param->num_inv > 1 ? buf_param->num_inv-2 : buf_param->num_inv-1); + if (buf_param->model == DELAY_MODEL_MAPPED){ + load = (buf_param->buf_array[default_inv_index])->ip_load; + } else { + load = 1.0; + } + foreach_primary_output(network, gen, node){ + if (delay_get_parameter(node, DELAY_OUTPUT_LOAD) < 0){ + setting_env = TRUE; + (void)st_insert(*load_table, (char *)node, NIL(char)); + delay_set_parameter(node, DELAY_OUTPUT_LOAD, load); + } + } + if (setting_env && buf_param->interactive){ + (void)fprintf(sisout,"WARNING: Unspecified primary output loads assumed to be %6.4f\n", load); + } + + setting_env = FALSE; + if (buf_param->model == DELAY_MODEL_MAPPED){ + drive = (buf_param->buf_array[default_inv_index])->drive; + } else { + drive.rise = drive.fall = 0.2; + } + foreach_primary_input(network, gen, node){ + if (delay_get_parameter(node, DELAY_DRIVE_RISE) < 0 || + delay_get_parameter(node, DELAY_DRIVE_FALL) < 0){ + setting_env = TRUE; + (void)st_insert(*drive_table, (char *)node, NIL(char)); + delay_set_parameter(node, DELAY_DRIVE_RISE, drive.rise); + delay_set_parameter(node, DELAY_DRIVE_FALL, drive.fall); + } + } + if (setting_env && buf_param->interactive){ + (void)fprintf(sisout,"WARNING: Unspecified primary input drive assumed to be (%6.4f:%6.4f)\n", drive.rise, drive.fall); + } +} diff --git a/sis/speed/buf_recur.c b/sis/speed/buf_recur.c new file mode 100644 index 0000000..c897c66 --- /dev/null +++ b/sis/speed/buf_recur.c @@ -0,0 +1,1233 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/buf_recur.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include "buffer_int.h" + +static int buf_cumulative_cap(); +static int buf_annotate_trans3(); +static void buf_implement_trans3(); +static delay_pin_t *sp_get_versions_of_node(); + +static delay_time_t large_req_time = {POS_LARGE, POS_LARGE}; + +static delay_pin_t buffer_unit_fanout_delay_model = { + /* block */ {1.0, 1.0}, + /* drive */ {0.2, 0.2}, + /* phase */ PHASE_NONINVERTING, + /* load */ 1.0, + /* maxload */ INFINITY + }; + +#define EPS 1.0e-6 +/* + * The basic recursive routine that decides the fate of node "node"...... + * It may + * (1) redistribute the fanouts of node by adding a buffer + * (2) Try a balanced decomposition of the outputs.. + * (3) Failing 2 it tries to decompose node into smaller gates + */ +int +sp_buffer_recur(network, buf_param, fanout_data, req_diff, levelp) +network_t *network; +buf_global_t *buf_param; +buf_alg_input_t *fanout_data; +delay_time_t req_diff; /* This much needs to be saved */ +int *levelp; /* Iteration counter */ +{ + delay_model_t model = buf_param->model; + int num_inv = buf_param->num_inv; + int num_buf = buf_param->num_buf; + sp_buffer_t **buf_array = buf_param->buf_array; + node_t *node = fanout_data->node; /* The root node */ + node_t *inv_node = fanout_data->inv_node;/* The inverter at its fanout */ + sp_fanout_t *fanouts = fanout_data->fanouts; /* data on the fanouts */ + int num_pos = fanout_data->num_pos; /* The number of positive fanouts */ + int num_neg = fanout_data->num_neg; /* The number of negative fanouts */ + + lsGen gen; + lib_gate_t *gate; + delay_pin_t *pin_delay, *gate_array; + sp_buffer_t *buf_b, *buf_B, *buf_gI; + node_t *fo, *new_b, *new_B, *new_inv_node; + buf_alg_input_t *new_fanout_data, *old_fanout_data; + int do_unbalanced, use_noninv_buf, changed, current_level; + int b, B, g_I, g, m_p, m_n, cfi; + int temp, i, k, n, pin, num_gates, excess; + int valid_config, met_target, old_pos, old_neg, new_pos, new_neg; + int best_b, best_B, best_gI, best_g, best_mp, best_mn; + double root_node_drive; + double total_cap_pos, total_cap_neg; + double auto_route = buf_param->auto_route; + double best_load_op_g, load_op_b, load_op_B, load_op_gI, load_op_g; + double load, load_b, load_B, load_gI, orig_load; + double *cap_L_pos, *cap_L_neg, *cap_K_pos, *cap_K_neg; + double *a_array, min_area_notmet, min_area, cur_area; + double area_b, area_B, area_gI; + delay_time_t work_diff, best_req_B, best_req_gI; + delay_time_t early_pos, early_neg, late_pos, late_neg; + delay_time_t req_op_g, best_req_op_g; + delay_time_t orig_drive, a_saving, margin, margin_pos, margin_neg, best; + delay_time_t req_time, target, orig_req; + delay_time_t fo_req, req_b, req_B, req_g, req_gI; + delay_time_t neg_min_req, pos_min_req; + + if (BUF_MAX_D(req_diff) < EPS ){ + if (buf_param->debug){ + (void)fprintf(sisout,"REQUIRED TIME DATA DOES NOT WARRANT BUFFERING\n"); + } + return 0; + } + + changed = FALSE; + n = num_pos+num_neg; + work_diff = req_diff; + current_level = ++(*levelp); + + if (fanout_data->root == fanout_data->node) { + /* See if we need to repower */ + if (buf_param->mode & REPOWER_MASK){ + gate_array = sp_get_versions_of_node(node, buf_param, &num_gates, + &a_array); + } else { + /* Put in the current impl of node as the only entry in gate_array*/ + + num_gates = 1; + gate_array = ALLOC(delay_pin_t, num_gates); + a_array = ALLOC(double, num_gates); + cfi = BUFFER(node)->cfi; + gate = lib_gate_of(node); + if (gate == NIL(lib_gate_t)){ + gate_array[0] = buffer_unit_fanout_delay_model; + a_array[0] = 0; + } else { + gate_array[0] = *((delay_pin_t *)(gate->delay_info[cfi])); + a_array[0] = lib_gate_area(gate); + } + } + } else { + /* At this level we have inverter that we can size */ + gate_array = sp_get_versions_of_node(node, buf_param, &num_gates, &a_array); + } + + if (n == 1 && current_level == 1){ + if (buf_param->debug > 10){ + (void)fprintf(sisout,"********Iteration %d -- %d nodes -- aim to save %.3f:%.3f\n", + *levelp, n, req_diff.rise, req_diff.fall); + (void)fprintf(sisout,"\tSingle fanout node -- TERMINATE \n"); + } + fo = node_get_fanout(node, 0); + k = node_get_fanin_index(fo, node); + sp_buf_req_time(fo, buf_param, k, &req_time, &total_cap_pos); + changed = sp_replace_cell_strength(network, buf_param, fanout_data, gate_array, + num_gates, req_time, large_req_time, total_cap_pos, 0.0, &a_saving); + FREE(gate_array); + FREE(a_array); + return changed; + } + + /* + * For ease of later operations sort the fanouts so that the signal + * required the earliest is at the start -- sorted in decreasing + * criticality. Inverting signals appear before non-inverting ones + */ + qsort((void *)fanouts, (unsigned)n, sizeof(sp_fanout_t), buf_compare_fanout); + if (buf_param->debug > 10){ + (void)fprintf(sisout,"******Iteration %d -- %d nodes -- aim to save %.3f:%.3f\n", + *levelp, n, req_diff.rise, req_diff.fall); + (void)fprintf(sisout,"\tRequired time and Load distribution (max_ip_load = %.3f) \n", fanout_data->max_ip_load); + buf_dump_fanout_data(sisout, fanouts, n); + } + + /* + * Compute the cumulative capacitances of grouping first (m-1) + * non_inv signals as cap_K_pos, and last (n-m+1) signals as cap_L_pos.... + * Done analogously for the negatiive phase signals + */ + do_unbalanced = buf_cumulative_cap(fanouts, buf_param, num_pos, + num_neg, &cap_K_pos, &cap_K_neg, + &cap_L_pos, &cap_L_neg); + total_cap_pos = cap_K_pos[num_pos]; total_cap_neg = cap_K_neg[num_neg]; + + /* Also record the earliest required times among the two sets */ + neg_min_req = pos_min_req = large_req_time; + for(i = 0; i < num_pos; i++){ + MIN_DELAY(pos_min_req, pos_min_req, fanouts[i].req); + } + for(i = num_pos; i < n; i++){ + MIN_DELAY(neg_min_req, neg_min_req, fanouts[i].req); + } + + + /* + * As the obvious step make sure that the required time is computed + * based on the best possible match version of the gate implementing + * node (This is done only for the first pass in the recursion). We + * want to compare the result of buffering treansformations with this value + */ + orig_req = BUFFER(node)->req_time; + orig_drive = BUFFER(node)->prev_dr; + orig_load = sp_get_pin_load(node, model); + + /* Adjust for delay due to limited drive of preceeding gate */ + sp_drive_adjustment(orig_drive, orig_load, &orig_req); + + /* + * Set a target for the current recursion. This is the value of the + * required time such that making the required time greater than this + * will not effect the delay of the circuit + */ + target.rise = orig_req.rise + req_diff.rise; + target.fall = orig_req.fall + req_diff.fall; + + if (buf_param->debug > 10){ + (void)fprintf(sisout,"Initial req_time %6.3f:%-6.3f , Target %6.3f:%-6.3f\n", + orig_req.rise, orig_req.fall, target.rise, target.fall); + } + if (current_level == 1 && (buf_param->mode & REPOWER_MASK)){ + /* first recursion call -- try replacements if allowed */ + if (buf_param->debug > 10){ + (void)fprintf(sisout,"\tCOMPUTING BEST VERSION OF CELL\n"); + } + + temp = buf_param->do_decomp; + buf_param->do_decomp = 0; /* no decomp permitted here */ + changed = sp_replace_cell_strength(network, buf_param, fanout_data, + gate_array, num_gates, pos_min_req, neg_min_req, + total_cap_pos, total_cap_neg, &a_saving); + buf_param->do_decomp = temp; + + orig_req.rise += a_saving.rise; + orig_req.fall += a_saving.fall; + work_diff.rise = req_diff.rise - a_saving.rise; + work_diff.fall = req_diff.fall - a_saving.fall; + if (buf_param->debug > 10) + (void)fprintf(sisout,"Required time after powering %6.3f:%-6.3f\n", + orig_req.rise, orig_req.fall); + + if (REQ_IMPR(orig_req, target)) { + /* + * Mission accomplished !!!! + * achieved the target -- return after freeing storage + */ + goto exit_recursion; + } + } + + /* + * TRY the UNBALANCED TRANSFORMATION (trans3 according to the paper) + * + * Loop over all possible implementations of the root gate, inv, + * inverting buffers b and B ------ refer to the DAC paper + * Keep the best required time configuration. Then compare it to the + * required time achieved by repowering alone.... + */ + met_target = FALSE; + best_b = best_B = best_gI = best_g = best_mp = best_mn = -1; + best.rise = best.fall = NEG_LARGE; + min_area_notmet = min_area = POS_LARGE; + if (do_unbalanced && (buf_param->mode & UNBALANCED_MASK)){ + /* + * unbalanced is permitted or warranted by the delay data . We need + * to make sure that the configurations are acceptable in terms of the + * fanout load that the gate can drive. + */ + for(g_I = 0; g_I < num_inv; g_I++){ + for(m_p = 0; m_p <= num_pos; m_p++){ /* positive fanout partition*/ + early_pos = late_pos = large_req_time; + for (i = 0; i < m_p; i++){ + MIN_DELAY(early_pos, early_pos, fanouts[i].req); + } + for (i = m_p; i < num_pos; i++){ + MIN_DELAY(late_pos, late_pos, fanouts[i].req); + } + for(b = 0; b < num_buf; b++){ + load_op_b = 0.0; + buf_b = buf_array[b]; + if (m_p == num_pos){ /* "b" drives no fanouts */ + req_b = large_req_time; + load_b = 0.0; area_b = 0; + } else { + load_b = buf_b->ip_load+auto_route; + area_b = buf_b->area; + req_b = late_pos; + load_op_b = cap_L_pos[m_p]; + sp_subtract_delay(buf_b->phase, buf_b->block, + buf_b->drive, load_op_b, &req_b); + } + for (m_n = 0; m_n <= num_neg; m_n++){/*negative partition*/ + early_neg = late_neg = large_req_time; + for (i = 0; i < m_n; i++){ + MIN_DELAY(early_neg, early_neg, fanouts[num_pos+i].req); + } + for (i = m_n; i < num_neg; i++){ + MIN_DELAY(late_neg, late_neg, fanouts[num_pos+i].req); + } + for(B = 0; B < num_buf; B++){ /* choice of buffer B */ + if (B >= num_inv && b < num_inv){ + /* Driving the negative partition by non-inv + * buffer requires that the positive partition + * be similarly driven by non-inv buffer */ + break; + } + load_op_B = 0.0; + buf_B = buf_array[B]; + if ((m_n == num_neg && B >= num_inv) || + (m_n == num_neg && m_p == num_pos)) { + req_B = large_req_time; + load_B = 0.0; area_B = 0; + } else { + load_B = buf_B->ip_load+auto_route; + area_B = buf_B->area; + if (B >= num_inv){ + req_B = late_neg; + } else { + MIN_DELAY(req_B, req_b, late_neg); + load_op_B = load_b; + } + load_op_B += cap_L_neg[m_n]; + sp_subtract_delay(buf_B->phase, buf_B->block, + buf_B->drive, load_op_B, &req_B); + } + + /* Now compute the required time at input of "gI" */ + load_op_gI = 0.0; + buf_gI = buf_array[g_I]; + if (m_n == 0 && B < num_inv){ + /* gI is driving no signals in this case */ + req_gI = large_req_time; + load_gI = 0.0; + area_gI = 0; + } else{ + load_gI = buf_gI->ip_load+auto_route; + area_gI = buf_gI->area; + if (B >= num_inv){ + load_op_gI += load_B; + MIN_DELAY(req_gI, req_B, early_neg); + } else { + req_gI = early_neg; + } + load_op_gI += cap_K_neg[m_n]; + sp_subtract_delay(buf_gI->phase, buf_gI->block, + buf_gI->drive,load_op_gI, &req_gI); + } + + for(g=0; g < num_gates; g++){ /* Versions of root */ + pin_delay = &(gate_array[g]); + if (pin_delay->load > + fanout_data->max_ip_load){ + /* load limit violated !!! */ + continue; + } + load_op_g = load_gI; + if (b >= num_inv){ + MIN_DELAY(req_g,req_b,req_gI); + load_op_g += load_b; + } else { + MIN_DELAY(req_g,req_B,req_gI); + load_op_g += load_B; + } + if(m_p != 0){ + MIN_DELAY(req_g, req_g, early_pos); + } + load_op_g += cap_K_pos[m_p]; + req_op_g = req_g; /* save the req time */ + + sp_subtract_delay(pin_delay->phase, + pin_delay->block, pin_delay->drive, + load_op_g, &req_g); + /* Account for drive of previous stage */ + sp_drive_adjustment(orig_drive, pin_delay->load, &req_g); + + valid_config = !((B < num_inv) ^ (b < num_inv)); + cur_area = a_array[g]+area_b+area_B+area_gI; + if (valid_config && REQ_IMPR(req_g,target) && + (cur_area < min_area)){ + /* Keep the smallest area config */ + met_target = TRUE; + min_area = cur_area; + best_b = b; best_B = B; best_gI = g_I; + best_g=g; best_mp = m_p; best_mn = m_n; + best_req_op_g = req_op_g; + best_load_op_g = load_op_g; + } + if ( valid_config && !met_target){ + if (REQ_IMPR(req_g, best)){ + best = req_g; + min_area_notmet = cur_area; + best_req_B=req_B, best_req_gI = req_gI; + best_b = b; best_B = B; best_gI = g_I; + best_g=g; best_mp = m_p; best_mn = m_n; + best_req_op_g = req_op_g; + best_load_op_g = load_op_g; + } else if (REQ_EQUAL(req_g, best) && + (cur_area < min_area_notmet) ){ + min_area_notmet = cur_area; + best_req_B=req_B, best_req_gI = req_gI; + best_b = b; best_B = B; best_gI = g_I; + best_g=g; best_mp = m_p; best_mn = m_n; + best_req_op_g = req_op_g; + best_load_op_g = load_op_g; + } + } + } + } + } + /* Dont try more values for "b" if no positive fanouts */ + if (num_pos == 0) break; + } + } + /* + * If there are no negative fanout gates, no need to + * try replacements for the possible choices of node gI + */ + if (num_neg == 0) break; + } + } + + use_noninv_buf = ((best_b >= num_inv) && (best_B >= num_inv)); + + if ((buf_param->mode & UNBALANCED_MASK) && buf_param->debug > 10){ + if (do_unbalanced){ + (void)fprintf(sisout,"Trans3 can get %6.3f:%-6.3f at %d fanin\n", + best.rise, best.fall, BUFFER(node)->cfi); + } else { + (void)fprintf(sisout,"NO NEED TO DO THE UNBALANCED DECOMP\n"); + } + } + + /* The computation was based on improving the req_time at cfi input + * However, it is possible that the slack worsened at some other input. + * If this happens set the best to be NEG_LARGE to reject the + * transformation, thereby avoid worsening the circuit performance + * Do not check when interfacing to the mapper (interactive == FALSE) + */ + if (buf_param->interactive && !met_target && + REQ_IMPR(best,orig_req) && (node_num_fanin(node) > 1)){ + if (buf_failed_slack_test(node, buf_param, best_g, best_req_op_g, + best_load_op_g)){ + if (buf_param->debug > 10){ + (void)fprintf(sisout, "SLACK CHECK during unbalanced xform\n"); + } + best.rise = best.fall = NEG_LARGE; + } + } + /* + * NOTE: When unbalanced decomp is not desired then best = NEG_LARGE + * and also "met_target == FALSE" + * Hence the condition being tested below is FALSE + */ + if (met_target || REQ_IMPR(best, orig_req)){ + if (!met_target){ + /* + * We should first check if a balanced decomp is the right thing + * one such case is when (num_pos == 0 && req_B >= req_gI) + */ + pin_delay = &(gate_array[best_g]); + sp_drive_adjustment(pin_delay->drive, + buf_array[best_gI]->ip_load + auto_route, &best_req_gI); + sp_drive_adjustment(pin_delay->drive, + buf_array[best_B]->ip_load + auto_route, &best_req_B); + if ((buf_param->mode & BALANCED_MASK) && num_pos == 0 + && !use_noninv_buf + && ((best_req_gI.rise - best_req_B.rise < EPS) + || (best_req_gI.fall - best_req_B.fall < EPS))){ + changed += buf_evaluate_trans2(network, buf_param, fanout_data, + gate_array, a_array, num_gates, cap_K_pos, cap_K_neg, + work_diff, levelp); + goto exit_recursion; + } + } + + /* + * Have gotton some saving over naive buffering using trans3 + * Generate the new configuration and then recur if required + */ + changed = 1; + buf_implement_trans3(network, node, inv_node, fanouts, use_noninv_buf, + num_pos, num_neg, best_mn, best_mp, &new_b, &new_B); + new_inv_node = inv_node; + if (new_B == inv_node){ + new_inv_node = NIL(node_t); + } + (void)buf_annotate_trans3(network, buf_param, fanouts, use_noninv_buf, + node, new_inv_node, new_b, new_B, best_g, best_gI, best_b, best_B, + &margin_pos, &margin_neg); + + if (met_target){ + if (buf_param->debug > 10){ + (void)fprintf(sisout,"\t--- ACHIEVED DESIRED SAVING ---\n"); + } + goto exit_recursion; + } + + if (new_b == NIL(node_t) && new_B == NIL(node_t) + && new_inv_node == NIL(node_t)){ + /* trans3 has done the same job as simple repowering of root */ + if (buf_param->debug > 10){ + (void)fprintf(sisout,"--- NO CHANGE IN FANOUT SET ---\n"); + } + goto exit_recursion; + } + + old_pos = best_mp; + old_neg = best_mn; + new_neg = num_pos - best_mp; + new_pos = num_neg - best_mn; + + if (use_noninv_buf ? + (BUF_MAX_D(margin_pos) < EPS && BUF_MAX_D(margin_neg) < EPS) : + (BUF_MAX_D(margin_pos)< EPS) ){ + if (buf_param->debug > 10){ + (void)fprintf(sisout,"\t--- RECURSION ON NEW NODES WONT HELP ---\n"); + } + } else if (new_pos + new_neg > 0){ + /* + * Recur on the sub_problems --- + * Set up the fanout array for the recursion branch + * for the recently added nodes call the recursion routine + */ + root_node_drive = BUF_MAX_D(gate_array[best_g].drive); + + if (use_noninv_buf){ + new_pos = num_pos - best_mp; + new_neg = num_neg - best_mn; + /* + * Need to see if we want to recur on the positive and/or + * negative partions (based on margin_pos and margin_neg) + */ + if (new_pos > 0 && (margin_pos.rise > EPS && margin_pos.fall > EPS)){ + buf_b = buf_array[best_B]; + new_fanout_data = ALLOC(buf_alg_input_t, 1); + new_fanout_data->num_pos = new_pos; + new_fanout_data->num_neg = 0; + new_fanout_data->max_ip_load = buf_B->ip_load + + BUF_MIN_D(margin_pos)/root_node_drive; + new_fanout_data->root = fanout_data->root; + new_fanout_data->node = new_b; + new_fanout_data->inv_node = NIL(node_t); + new_fanout_data->fanouts = ALLOC(sp_fanout_t, new_pos); + for (i = 0; i < new_pos; i++){ + new_fanout_data->fanouts[i] = fanouts[best_mp+i]; + } + changed += sp_buffer_recur(network, buf_param, new_fanout_data, + margin_pos, levelp); + FREE(new_fanout_data->fanouts); + FREE(new_fanout_data); + } + if (new_neg > 0 && (margin_neg.rise > EPS && margin_neg.fall > EPS)){ + buf_B = buf_array[best_B]; + new_fanout_data = ALLOC(buf_alg_input_t, 1); + new_fanout_data->num_pos = new_neg; + new_fanout_data->num_neg = 0; + new_fanout_data->max_ip_load = buf_B->ip_load + + BUF_MIN_D(margin_neg)/root_node_drive; + new_fanout_data->node = new_B; + new_fanout_data->inv_node = NIL(node_t); + new_fanout_data->fanouts = ALLOC(sp_fanout_t, new_neg); + for (i = 0; i < new_neg; i++){ + new_fanout_data->fanouts[i] = + fanouts[num_pos+best_mn+i]; + } + changed += sp_buffer_recur(network, buf_param, new_fanout_data, + margin_neg, levelp); + FREE(new_fanout_data->fanouts); + FREE(new_fanout_data); + } + } else { + /* + * Recur with "new_B" as the root of the fanout problem + */ + new_fanout_data = ALLOC(buf_alg_input_t, 1); + /* + * We have no margin to shoot for when no old positive + * signals are present. Set the margin as per the + * saving yet to be accomplished + */ +/* + if (old_pos == 0){ + req_g = BUFFER(node)->req_time; + sp_drive_adjustment(orig_drive, + sp_get_pin_load(node, model), &req_g); + margin.rise = target.rise - req_g.rise; + margin.fall = target.fall - req_g.fall; + } else { + margin = margin_pos; + } +*/ + new_fanout_data->num_pos = new_pos; + new_fanout_data->num_neg = new_neg; + new_fanout_data->max_ip_load = buf_B->ip_load + + BUF_MIN_D(margin_pos)/root_node_drive; + new_fanout_data->node = new_B; + new_fanout_data->inv_node = new_b; + new_fanout_data->fanouts = ALLOC(sp_fanout_t, new_pos+new_neg); + for (i = 0; i < new_pos; i++){ + new_fanout_data->fanouts[i] = fanouts[num_pos+best_mn+i]; + new_fanout_data->fanouts[i].phase = PHASE_NONINVERTING; + } + for (i = 0; i < new_neg; i++){ + new_fanout_data->fanouts[new_pos+i]=fanouts[best_mp+i]; + new_fanout_data->fanouts[new_pos+i].phase = PHASE_INVERTING; + } + changed += sp_buffer_recur(network, buf_param, new_fanout_data, + margin_pos, levelp); + FREE(new_fanout_data->fanouts); + FREE(new_fanout_data); + } + } else if (buf_param->debug > 10) { + (void)fprintf(sisout,"\t -- NO FANOUTS TO RECUR ON --\n"); + } + + /* + * The recursion branch for the original nodes -- called + * after the recursion of the added nodes is completed... + * Need to do different things based on whether non-invering + * buffers were used or not during the unbalanced decomposition + */ + load = load_gI = 0; req_gI = req_g = large_req_time; + if (use_noninv_buf){ + excess = (new_b != NIL(node_t)); + } else { + excess = (new_B != NIL(node_t)); + } + old_fanout_data = ALLOC(buf_alg_input_t, 1); + old_fanout_data->max_ip_load = fanout_data->max_ip_load; + old_fanout_data->fanouts = ALLOC(sp_fanout_t, old_pos+old_neg+excess); + for (i = 0; i < old_pos; i++){ + old_fanout_data->fanouts[i] = fanouts[i]; + load += old_fanout_data->fanouts[i].load; + MIN_DELAY(req_g, req_g, old_fanout_data->fanouts[i].req); + } + for (i = 0; i < old_neg; i++){ + old_fanout_data->fanouts[old_pos+i] = fanouts[num_pos+i]; + load_gI += old_fanout_data->fanouts[old_pos+i].load; + MIN_DELAY(req_gI, req_gI, old_fanout_data->fanouts[old_pos+i].req); + } + if (excess){ + old_fanout_data->fanouts[old_pos+old_neg].pin = 0; + old_fanout_data->fanouts[old_pos+old_neg].phase = PHASE_NONINVERTING; + if (use_noninv_buf){ + old_fanout_data->fanouts[old_pos+old_neg].fanout = new_b; + old_fanout_data->fanouts[old_pos+old_neg].load = + sp_get_pin_load(new_b, model) + auto_route; + old_fanout_data->fanouts[old_pos+old_neg].req = BUFFER(new_b)->req_time; + load += old_fanout_data->fanouts[old_pos+old_neg].load; + MIN_DELAY(req_g, req_g, old_fanout_data->fanouts[old_pos+old_neg].req); + } else { + old_fanout_data->fanouts[old_pos+old_neg].fanout = new_B; + old_fanout_data->fanouts[old_pos+old_neg].load = + sp_get_pin_load(new_B, model) + auto_route; + old_fanout_data->fanouts[old_pos+old_neg].req = BUFFER(new_B)->req_time; + load += old_fanout_data->fanouts[old_pos+old_neg].load; + MIN_DELAY(req_g, req_g, old_fanout_data->fanouts[old_pos+old_neg].req); + } + } + /* + * compute the amount of saving yet to be achieved... Some + * of it has been achieved by the application of trans3 + */ + if (old_neg > 0){ + pin_delay = get_pin_delay(new_inv_node, BUFFER(new_inv_node)->cfi, model); + sp_subtract_delay(pin_delay->phase, pin_delay->block, + pin_delay->drive, load_gI, &req_gI); + MIN_DELAY(req_g, req_g, req_gI); + load += pin_delay->load + auto_route; + } + pin_delay = get_pin_delay(node, BUFFER(node)->cfi, model); + sp_subtract_delay(pin_delay->phase, pin_delay->block, + pin_delay->drive, load, &req_g); + BUFFER(node)->req_time = req_g; + sp_drive_adjustment(orig_drive, pin_delay->load, &req_g); + margin.rise = target.rise - req_g.rise; + margin.fall = target.fall - req_g.fall; + + old_fanout_data->root = fanout_data->root; + old_fanout_data->node = node; + old_fanout_data->inv_node = new_inv_node; + old_fanout_data->num_pos = old_pos+excess; + old_fanout_data->num_neg = old_neg; + + /* Now recur on the root node and the appropriate fanout set */ + changed += sp_buffer_recur(network, buf_param, old_fanout_data, margin, levelp); + FREE(old_fanout_data->fanouts); + FREE(old_fanout_data); + + /* Figure the new required time at the input of "node" */ + req_g = BUFFER(node)->req_time; + load = sp_get_pin_load(node, model); + sp_drive_adjustment(orig_drive, load, &req_g); + + if (REQ_IMPR(req_g, target)){ + /* trans3 has been able to meet the target required time */ + goto exit_recursion; + } + } else if (buf_param->mode & BALANCED_MASK) { + /* + * No saving from trans3 (the unbalanced transformation) ----- + * Do a balanced decomp for the positive & negative signal sets + */ + margin.rise = target.rise - orig_req.rise; + margin.fall = target.fall - orig_req.fall; + changed += buf_evaluate_trans2(network, buf_param, fanout_data, + gate_array, a_array, num_gates, cap_K_pos, cap_K_neg, + margin, levelp); + /* Compute the required time at "node" input, account for prev drive */ + req_g = BUFFER(node)->req_time; + load = sp_get_pin_load(node, model); + sp_drive_adjustment(orig_drive, load, &req_g); + + if (REQ_IMPR(req_g, target)){ + /* Balanced distrbution meets the target required time */ + goto exit_recursion; + } + } + + /* + * When we reach this stage we have tried both balanced & unbalanced + * redistributions of the fanout set and still not met the target. + * As a last resort we try to see if duplication of root will help + */ + if (current_level == 1 && buf_param->do_decomp){ + total_cap_pos = 0.0; + req_time = large_req_time; + foreach_fanout_pin(node, gen, fo, pin){ + if (BUFFER(fo)->type == NONE){ + sp_buf_req_time(fo, buf_param, pin, &fo_req, &load); + } else { + fo_req = BUFFER(fo)->req_time; + load = sp_get_pin_load(fo, model); + } + total_cap_pos += load; + MIN_DELAY(req_time, req_time, fo_req); + } + /* HERE */ + fanout_data->inv_node = NIL(node_t); + changed += sp_replace_cell_strength(network, buf_param, fanout_data, gate_array, + num_gates, req_time, large_req_time, total_cap_pos, 0.0, &a_saving); + + if (buf_param->debug > 10 && a_saving.rise > 0 && a_saving.fall > 0){ + (void)fprintf(sisout,"Saved %6.3f:%-6.3f in the end for node %s\n", + a_saving.rise, a_saving.fall, node_name(node)); + } + } + + /* Garbage collection and end of the routine */ +exit_recursion: + FREE(a_array); + FREE(gate_array); + FREE(cap_L_pos); FREE(cap_L_neg); + FREE(cap_K_pos); FREE(cap_K_neg); + + return changed; +} + +/* + * Compare fanouts -- use the minimum of the rise and fall for the time + * being. In future it may sort by either rise or fall -- whichever is more + * critical + */ +int +buf_compare_fanout(ptr1, ptr2) +char *ptr1, *ptr2; +{ + sp_fanout_t *n1 = (sp_fanout_t *)ptr1, *n2 = (sp_fanout_t *)ptr2; + double d1, d2; + + d1 = MIN(n1->req.rise, n1->req.fall); + d2 = MIN(n2->req.rise, n2->req.fall); + + if (n1->phase == PHASE_INVERTING && n2->phase == PHASE_NONINVERTING){ + return 1; + } else if (n1->phase == PHASE_NONINVERTING && n2->phase == PHASE_INVERTING){ + return -1; + } else { + if (d1 < d2) return -1; + else if (d1 > d2) return 1; + else return 0; + } +} + +static int +buf_cumulative_cap(fanouts, buf_param, num_pos, num_neg, + cap_K_posp, cap_K_negp, cap_L_posp, cap_L_negp) +sp_fanout_t *fanouts; +buf_global_t *buf_param; +int num_pos, num_neg; +double **cap_K_posp, **cap_K_negp, **cap_L_posp, **cap_L_negp; +{ + int i, n, j; + int do_unbalanced; + delay_time_t t; + double min_req_diff = buf_param->min_req_diff; + double min_r, max_r, min_f, max_f; + double total_cap_pos, total_cap_neg; + double *cap_K_pos, *cap_K_neg, *cap_L_pos, *cap_L_neg; + + n = num_pos+num_neg; + cap_K_pos = ALLOC(double, num_pos+1); + cap_K_neg = ALLOC(double, num_neg+1); + cap_L_pos = ALLOC(double, num_pos+1); + cap_L_neg = ALLOC(double, num_neg+1); + + + do_unbalanced = FALSE; + cap_K_pos[0] = cap_K_neg[0] = 0.0; + min_r = min_f = POS_LARGE; + max_r = max_f = NEG_LARGE; + for(i = 0; i < num_pos; i++){ + t = fanouts[i].req; + cap_K_pos[i+1] = cap_K_pos[i] + fanouts[i].load; + min_r = MIN(min_r, t.rise); + min_f = MIN(min_f, t.fall); + max_r = MAX(max_r, t.rise); + max_f = MAX(max_f, t.fall); + } + if (((max_r - min_r) > min_req_diff) && ((max_f - min_f) > min_req_diff)){ + do_unbalanced = TRUE; + } + min_r = min_f = POS_LARGE; + max_r = max_f = NEG_LARGE; + for(i = num_pos, j = 0; i < n; i++, j++){ + t = fanouts[i].req; + cap_K_neg[j+1] = cap_K_neg[j] + fanouts[i].load; + min_r = MIN(min_r, t.rise); + min_f = MIN(min_f, t.fall); + max_r = MAX(max_r, t.rise); + max_f = MAX(max_f, t.fall); + } + if (((max_r - min_r) > min_req_diff) && ((max_f - min_f) > min_req_diff)){ + do_unbalanced = TRUE; + } + + total_cap_pos = cap_K_pos[num_pos]; + total_cap_neg = cap_K_neg[num_neg]; + for (i = 0; i <= num_pos; i++){ + cap_L_pos[i] = total_cap_pos - cap_K_pos[i]; + } + for (i = 0; i <= num_neg; i++){ + cap_L_neg[i] = total_cap_neg - cap_K_neg[i]; + } + + *cap_K_posp = cap_K_pos; + *cap_K_negp = cap_K_neg; + *cap_L_posp = cap_L_pos; + *cap_L_negp = cap_L_neg; + + return do_unbalanced; +} + +void +buf_dump_fanout_data(fp, fanouts, n) +FILE *fp; +sp_fanout_t *fanouts; +int n; +{ + int i; + + for(i = 0; i < n; i++){ + (void)fprintf(fp,"%6.3f:%-6.3f @ (%s)%6.3f ", + fanouts[i].req.rise, fanouts[i].req.fall, + (fanouts[i].phase == PHASE_INVERTING ? "-" : "+"), + fanouts[i].load); + if (i%2 && i != (n-1)) (void)fprintf(fp,"\n"); + } + (void)fprintf(fp,"\n"); +} + +/* + * Generate the configuration for the unbalalanced decomposition. This is one + * two configurations + * use_noninv_buf == FALSE then + * node drives (node_inv and bew_B), new_B drives bew_B + * else + * node_drives (node_inv and new_b), node_inv drives new_B + */ + +static void +buf_implement_trans3(network, node, node_inv, fanouts, use_noninv_buf, + num_pos, num_neg, best_mn, best_mp, new_b, new_B) +network_t *network; +node_t *node, *node_inv; +sp_fanout_t *fanouts; +int use_noninv_buf; /* if == 1 , use the non inverting buffers for b & B */ +int num_pos, num_neg, best_mn, best_mp; +node_t **new_b, **new_B; +{ + node_t *fo; + int i, need_b, need_B, B_has_fanouts; + + need_b = (best_mp != num_pos); + B_has_fanouts = (best_mn != num_neg); + need_B = B_has_fanouts || (!use_noninv_buf && need_b); + + *new_B = *new_b = NIL(node_t); + if (need_B){ + if (node_inv != NIL(node_t) && best_mn == 0 && !use_noninv_buf){ + /* All the negatative fanouts are driven by the gate B -- so we + can as well use the gate g_I (node_inv) for it */ + *new_B = node_inv; + } else { + if (use_noninv_buf){ + assert(node_inv != NIL(node_t)); + *new_B = node_literal(node_inv, 1); + } else { + *new_B = node_literal(node, 0); + } + network_add_node(network, *new_B); + } + if (B_has_fanouts){ + for (i = best_mn; i < num_neg; i++){ + fo = fanouts[num_pos + i].fanout; + assert(node_patch_fanin(fo, node_inv, *new_B)); + } + } + } + if (need_b){ + if (use_noninv_buf){ + *new_b = node_literal(node, 1); + } else { + *new_b = node_literal(*new_B, 0); + } + network_add_node(network, *new_b); + for (i = best_mp; i < num_pos; i++){ + fo = fanouts[i].fanout; + assert(node_patch_fanin(fo, node, *new_b)); + } + } +} + +/* + * Having implemented the nodes in trans3, we need to annotate them with the + * proper data to continue the recursion. The BUF field in the data struct + * needs to be updated as does the required time data + * Returns the number of nodes violating the load limit... + */ +static int +buf_annotate_trans3(network, buf_param, fanouts, use_noninv_buf, node, node_inv, new_b, + new_B, best_g, best_gI, best_b, best_B, margin_pos, margin_neg) +network_t *network; +buf_global_t *buf_param; +sp_fanout_t *fanouts; +int use_noninv_buf; /* Use the non-inverting buffers for new_b and new_B */ +node_t *node, *node_inv, *new_b, *new_B; +int best_g, best_gI, best_b, best_B; +delay_time_t *margin_pos, *margin_neg; +{ + int excess; + pin_phase_t prev_ph; + lib_gate_t *root_gate; + double auto_route = buf_param->auto_route; + double load, cap_b, cap_B, cap_gI, root_limit; + sp_buffer_t *buf_b, *buf_B, *buf_g, *buf_gI; + delay_time_t pos_branch_req, neg_branch_req; + delay_time_t prev_dr, prev_bl; + delay_time_t req_b, req_B, req_gI, req_g; + int i, cfi, index, old_pos, new_pos, old_neg, new_neg, num_violations; + + old_pos = node_num_fanout(node); + old_neg = buf_num_fanout(node_inv); + new_pos = buf_num_fanout(new_b); + new_neg = buf_num_fanout(new_B); + + excess = (node_inv != NIL(node_t)); + excess += (use_noninv_buf ? (new_b != NIL(node_t)): (new_B != NIL(node_t))); + old_pos -= excess; + excess = ((!use_noninv_buf && new_b != NIL(node_t)) ? 1 : 0); + new_neg -= excess; + + + num_violations = 0; + /* + * Annotate the root node with the relevant data + * NOTE: The prev_ph and prev_dr and cfi fields remain unchanged + */ + cfi = BUFFER(node)->cfi; + if (node->type == PRIMARY_INPUT) { + prev_bl.rise = prev_bl.fall = 0.0; + prev_dr.rise = prev_dr.fall = 0.0; /* This needs to be fixed !!!! */ + prev_ph = PHASE_NONINVERTING; + } else if (BUFFER(node)->type == BUF){ + buf_g = buf_param->buf_array[best_g]; + BUFFER(node)->impl.buffer = buf_g; + prev_bl = buf_g->block; + prev_dr = buf_g->drive; + prev_ph = buf_g->phase; + root_limit = buf_g->max_load; + sp_implement_buffer_chain(network, node); + BUFFER(node)->cfi = cfi; + } else { + /* Find number of gates in the class */ + root_gate = buf_get_gate_version(lib_gate_of(node), best_g); + assert(root_gate != NIL(lib_gate_t)); + BUFFER(node)->impl.gate = root_gate; + sp_replace_lib_gate(node, lib_gate_of(node), root_gate); + prev_dr = ((delay_pin_t *)(root_gate->delay_info[cfi]))->drive; + prev_ph = ((delay_pin_t *)(root_gate->delay_info[cfi]))->phase; + prev_bl = ((delay_pin_t *)(root_gate->delay_info[cfi]))->block; + root_limit = delay_get_load_limit(root_gate->delay_info[cfi]); + } + + /* + * Now annotate (if required) the buffer "b" driving positive signals + */ + cap_b = 0; req_b = large_req_time; + if (new_b != NIL(node_t)){ + assert(use_noninv_buf ? 1 : (best_b >= 0 && new_B != NIL(node_t))); + buf_b = buf_param->buf_array[best_b]; + BUFFER(new_b)->type = BUF; + BUFFER(new_b)->impl.buffer = buf_b; + load = 0; + for (i = 0; i < new_pos; i++){ + index = old_pos+i; + load += fanouts[index].load; + MIN_DELAY(req_b, req_b, fanouts[index].req); + } + sp_subtract_delay(buf_b->phase, buf_b->block, buf_b->drive, + load, &req_b); + cap_b = buf_b->ip_load + auto_route; + BUFFER(new_b)->req_time = req_b; + BUFFER(new_b)->load = load; + num_violations += (load > buf_b->max_load); + } + + /* + * Now annotate (if required) the buffer "B" driving negative signals + * and maybe the gate "b" above + */ + cap_B = 0; req_B = (use_noninv_buf ? large_req_time : req_b); + if (new_B != NIL(node_t)){ + buf_B = buf_param->buf_array[best_B]; + BUFFER(new_B)->type = BUF; + BUFFER(new_B)->impl.buffer = buf_B; + load = (use_noninv_buf ? 0 : cap_b); + for (i = 0; i < new_neg; i++){ + index = old_neg+i+(new_pos+old_pos); + load += fanouts[index].load; + MIN_DELAY(req_B, req_B, fanouts[index].req); + } + sp_subtract_delay(buf_B->phase, buf_B->block, buf_B->drive, + load, &req_B); + cap_B = buf_B->ip_load+auto_route; + BUFFER(new_B)->load = load; + BUFFER(new_B)->req_time = req_B; + BUFFER(new_B)->prev_ph = prev_ph; + BUFFER(new_B)->prev_dr = prev_dr; + num_violations += (load > buf_B->max_load); + } + + if (new_b != NIL(node_t)){ + if (use_noninv_buf){ + BUFFER(new_b)->prev_dr = prev_dr; + BUFFER(new_b)->prev_ph = prev_ph; + } else { + assert(new_B != NIL(node_t)); + BUFFER(new_b)->prev_dr = buf_B->drive; + BUFFER(new_b)->prev_ph = buf_B->phase; + } + } + /* + * a part of the original signals were driven by the inverter "gI" + * Put in the correct data regarding that + */ + cap_gI = 0; req_gI = neg_branch_req = large_req_time; + if (node_inv != NIL(node_t)){ + buf_gI = buf_param->buf_array[best_gI]; + BUFFER(node_inv)->type = BUF; + BUFFER(node_inv)->impl.buffer = buf_gI; + load = (use_noninv_buf ? cap_B : 0); + for (i = 0; i < old_neg; i++){ + index = i+(new_pos+old_pos); + load += fanouts[index].load; + MIN_DELAY(req_gI, req_gI, fanouts[index].req); + } + neg_branch_req = req_gI; + if (use_noninv_buf){ + MIN_DELAY(req_gI, req_gI, req_B); + } + sp_subtract_delay(buf_gI->phase, buf_gI->block, buf_gI->drive, + load, &req_gI); + cap_gI = buf_gI->ip_load+auto_route; + BUFFER(node_inv)->load = load; + BUFFER(node_inv)->req_time = req_gI; + BUFFER(node_inv)->prev_ph = prev_ph; + BUFFER(node_inv)->prev_dr = prev_dr; + num_violations += (load > buf_gI->max_load); + } + + /* Now compute the required time at the input of "node' */ + if (use_noninv_buf){ + pos_branch_req = large_req_time; + MIN_DELAY(req_g, req_b, req_gI); + load = cap_b + cap_gI; + } else { + pos_branch_req = req_gI; + MIN_DELAY(req_g, req_B, req_gI); + load = cap_B + cap_gI; + } + for (i = 0; i < old_pos; i++){ + load += fanouts[i].load; + MIN_DELAY(req_g, req_g, fanouts[i].req); + MIN_DELAY(pos_branch_req, pos_branch_req, fanouts[i].req); + } + sp_subtract_delay(prev_ph, prev_bl, prev_dr, load, &req_g); + BUFFER(node)->load = load; + BUFFER(node)->req_time = req_g; + num_violations += (load > root_limit); + + /* + * We also want to find the difference in the required time + * at the input of the buffer "B" and the earliest required signal. + * This tells us whether recurring on "new_B" as root will help + * or not.... + * If margin < 0 then no need to recur further + */ + if (use_noninv_buf){ + margin_pos->rise = pos_branch_req.rise - req_b.rise; + margin_pos->fall = pos_branch_req.fall - req_b.fall; + margin_neg->rise = neg_branch_req.rise - req_B.rise; + margin_neg->fall = neg_branch_req.fall - req_B.fall; + } else { + margin_pos->rise = pos_branch_req.rise - req_B.rise; + margin_pos->fall = pos_branch_req.fall - req_B.fall; + } + + /* + * Set the implementations to be the library gates + */ + if (node_inv != NIL(node_t)){ + sp_implement_buffer_chain(network, node_inv); + BUFFER(node_inv)->cfi = 0; + } + if (new_b != NIL(node_t)){ + sp_implement_buffer_chain(network, new_b); + BUFFER(new_b)->cfi = 0; + } + if (new_B != NIL(node_t)){ + sp_implement_buffer_chain(network, new_B); + BUFFER(new_B)->cfi = 0; + } + + if (buf_param->debug > 10){ + (void)fprintf(sisout,"Transformation 3 data ----\n"); + (void)fprintf(sisout,"\troot node %s driving %d -- t_r =%6.3f:%-6.3f\n", + sp_name_of_impl(node), old_pos, req_g.rise, req_g.fall); + (void)fprintf(sisout,"\tgI is %s driving %d -- t_r = %6.3f:%-6.3f\n", + sp_name_of_impl(node_inv), old_neg, req_gI.rise, req_gI.fall); + (void)fprintf(sisout,"\tb is %s driving %d -- t_r = %6.3f:%-6.3f\n", + sp_name_of_impl(new_b), new_pos, req_b.rise, req_b.fall); + (void)fprintf(sisout,"\tB is %s driving %d -- t_r = %6.3f:%-6.3f\n", + sp_name_of_impl(new_B), new_neg, req_B.rise, req_B.fall); + if (use_noninv_buf){ + (void)fprintf(sisout,"\tAfter Trans3: margin_pos = %6.3f:%-6.f margin_neg = %6.3f:%-6.f\n", + margin_pos->rise, margin_pos->fall, margin_neg->rise, + margin_neg->fall); + } else { + (void)fprintf(sisout,"\tAfter Trans3: margin = %6.3f:%-6.3f\n", + margin_pos->rise, margin_pos->fall); + } + (void)fprintf(sisout,"NOTE: There are %d load_limit violations\n", + num_violations); + } + return num_violations; +} + +static delay_pin_t * +sp_get_versions_of_node(node, buf_param, num_gates, a_array) +node_t *node; +buf_global_t *buf_param; +int *num_gates; +double **a_array; +{ + char *dummy; + int i, j, cfi; + lsGen gate_gen; + sp_buffer_t *small_buf; + lib_gate_t *cur_root_gate; + delay_model_t model = buf_param->model; + delay_pin_t *pin_delay, *gate_array; + + /* + * The array stores the possible implementations of the root node + */ + if (node->type == PRIMARY_INPUT){ + *num_gates = 1; + *a_array = ALLOC(double, *num_gates); + gate_array = ALLOC(delay_pin_t, *num_gates); + pin_delay = get_pin_delay(node, 0, model); + gate_array[0] = *pin_delay; + (*a_array)[0] = 0.0; + } else if (BUFFER(node)->type == BUF){ + if (BUFFER(node)->impl.buffer->phase == PHASE_INVERTING){ + *num_gates = buf_param->num_inv; j = 0; + } else { + *num_gates = buf_param->num_buf - buf_param->num_inv; + j = buf_param->num_inv; + } + gate_array = ALLOC(delay_pin_t, *num_gates); + *a_array = ALLOC(double, *num_gates); + for (i = 0; i < *num_gates; i++, j++){ + small_buf = buf_param->buf_array[j]; + gate_array[i].phase = small_buf->phase; + gate_array[i].drive = small_buf->drive; + gate_array[i].block = small_buf->block; + gate_array[i].load = small_buf->ip_load; + (*a_array)[i] = small_buf->area; + } + } else { + /* Find number of gates in the class */ + *num_gates = 0; + gate_gen = lib_gen_gates(lib_gate_class(lib_gate_of(node))); + while (lsNext(gate_gen, &dummy, LS_NH) == LS_OK){ + (*num_gates)++; + } + (void)lsFinish(gate_gen); + /* Get the delay/area data for each into the array */ + gate_gen = lib_gen_gates(lib_gate_class(lib_gate_of(node))); + gate_array = ALLOC(delay_pin_t, *num_gates); + *a_array = ALLOC(double, *num_gates); + i = 0; + cfi = BUFFER(node)->cfi; + while (lsNext(gate_gen, &dummy, LS_NH) == LS_OK){ + cur_root_gate = (lib_gate_t *)dummy; + gate_array[i] = *((delay_pin_t *)(cur_root_gate->delay_info[cfi])); + (*a_array)[i] = lib_gate_area(cur_root_gate); + i++; + } + (void)lsFinish(gate_gen); + } + return gate_array; +} + +/* + * During the recursuion, this routine returns 1 if the load constaraint + * at the output of node is satisfied, 0 on violation + */ +int +buf_load_constraint_met(node) +node_t *node; +{ + int cfi; + double limit, load; + + if (node == NIL(node_t)) return 1; + + load = BUFFER(node)->load; + if (BUFFER(node)->type == GATE){ + cfi = BUFFER(node)->cfi; + limit= delay_get_load_limit(BUFFER(node)->impl.gate->delay_info[cfi]); + } else if (BUFFER(node)->type == BUF){ + limit = BUFFER(node)->impl.buffer->max_load; + } else { + return 1; + } + return (limit > load); +} +#undef EPS diff --git a/sis/speed/buf_replace.c b/sis/speed/buf_replace.c new file mode 100644 index 0000000..e8c96c8 --- /dev/null +++ b/sis/speed/buf_replace.c @@ -0,0 +1,296 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/buf_replace.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include <math.h> +#include "speed_int.h" +#include "buffer_int.h" + +static delay_time_t large_req_time = {POS_LARGE, POS_LARGE}; + +/* + * This routine will take into consideration the drive of the + * previous gate (input) and the delay thru all the gates of the + * same functionality as "node" and keep the best. When the + * "do_decomp" flag is set it will explore decompositions into + * simpler gates if there is no replacement cell. + * + * In case the "inv_node" is also present, will try alternatives for the + * inverter too. Will keep the best comb of the inverter and the gate. + */ + +int +sp_replace_cell_strength(network, buf_param, fanout_data, gate_array, num_gates, + crit_pos, crit_neg, total_cap_pos, total_cap_neg, save) +network_t *network; +buf_global_t *buf_param; +buf_alg_input_t *fanout_data; +delay_pin_t *gate_array; /* Delay data of versions of node */ +int num_gates; +delay_time_t crit_pos, crit_neg; /* Earliest signal required time */ +double total_cap_pos, total_cap_neg; /* capacitive loads in both phases */ +delay_time_t *save; /* RETURN: saving of transformation */ +{ + extern void map_invalid(); /* Should be in map.h */ + node_t *node = fanout_data->node; + node_t *inv_node = fanout_data->inv_node; + delay_model_t model = buf_param->model; + int do_decomp = buf_param->do_decomp; + sp_buffer_t **buf_array = buf_param->buf_array; + + network_t *netw; + array_t *nodevec; + sp_fanout_t *inv_fan; + st_table *gate_table; + double auto_route = buf_param->auto_route; + double orig_load, cap_gI, max_ip_load = fanout_data->max_ip_load; + delay_pin_t *pin_delay; + pin_phase_t prev_ph; + node_t *temp, *root_node; + sp_buffer_t *buf_g, *inv_buf; + delay_time_t orig_req, req_gI, req_g, best; + delay_time_t prev_dr, prev_bl, orig_drive; + lib_gate_t *new_gate, *orig_gate, *root_gate; + int num_inv_choices, config_changed, changed; + int i, j, cfi, best_inv, best_root; + + if (buf_param->debug > 10){ + (void)fprintf(sisout,"\tRepowering cell %s \n", sp_name_of_impl(node)); + (void)fprintf(sisout,"\t (+)%5.3f at %6.3f:%-6.3f and (-)%5.3f at %6.3f:%-6.3f\n", + total_cap_pos, crit_pos.rise, crit_pos.fall, total_cap_neg, + crit_neg.rise, crit_neg.fall); + } + + /* + * Get the data on the drive of the previous gate. Use that to modify the + * required time at the input... This is done to compare the replacements + * in the environment of the circuit + */ + + changed = FALSE; /* Records a change in the required time */ + config_changed = FALSE; /* Records a change in the configuration */ + cfi = BUFFER(node)->cfi; + orig_req = BUFFER(node)->req_time; + orig_drive = BUFFER(node)->prev_dr; + orig_load = sp_get_pin_load(node, model); + sp_drive_adjustment(orig_drive, orig_load, &orig_req); + + /* + * We will first find out the required times, and loads that can be + * offered by the inverter driving the additional gates + */ + + num_inv_choices = (inv_node != NIL(node_t) ? buf_param->num_inv : 0); + inv_fan = ALLOC(sp_fanout_t, num_inv_choices+1); + if (inv_node != NIL(node_t)){ + for (i = 0; i < num_inv_choices; i++){ + inv_buf = buf_array[i]; + req_gI = crit_neg; + sp_subtract_delay(PHASE_INVERTING, inv_buf->block, inv_buf->drive, + total_cap_neg, &req_gI); + inv_fan[i].load = inv_buf->ip_load+auto_route; + inv_fan[i].req = req_gI; + } + } + /* To save some assignment steps -- we do this trick */ + inv_fan[num_inv_choices].load = 0.0; + inv_fan[num_inv_choices].req = large_req_time; + + best_inv = best_root = -1; + best.rise = best.fall = NEG_LARGE; + + for (i = 0; i < num_gates; i++){ + pin_delay = &(gate_array[i]); + if (pin_delay->load > max_ip_load){ + /* The increase in fanin_load is unacceptable !!! */ + continue; + } + j = 0; + do{ + req_gI = inv_fan[j].req; + cap_gI = inv_fan[j].load; + MIN_DELAY(req_g, req_gI, crit_pos); + sp_subtract_delay(pin_delay->phase, pin_delay->block, + pin_delay->drive, total_cap_pos+cap_gI, &req_g); + sp_drive_adjustment(orig_drive, pin_delay->load, &req_g); + + if (req_g.rise > best.rise && req_g.fall > best.fall){ + best = req_g; + best_inv = j; best_root = i; + } + } while (++j < num_inv_choices); + } + + if (REQ_IMPR(best, orig_req)){ + /* + * We have saves by choice of appropriate root node and inverter + * Implement the saved config and update the delay information + */ + changed = 1; + if (buf_param->debug > 10){ + (void)fprintf(sisout,"REPOWER: Repowering achieves %6.3f:%-6.3f\n", + best.rise, best.fall); + (void)fprintf(sisout,"\tRoot version = %d, Inverter index is %d\n", + best_root, best_inv); + } + + if (BUFFER(node)->type == BUF){ + buf_g = buf_array[best_root]; + if (BUFFER(node)->impl.buffer != buf_g){ + config_changed = TRUE; + } + BUFFER(node)->impl.buffer = buf_g; + sp_implement_buffer_chain(network, node); + BUFFER(node)->cfi = cfi; + prev_bl = buf_g->block; prev_dr = buf_g->drive; + prev_ph = buf_g->phase; + } else { + root_gate = buf_get_gate_version(lib_gate_of(node), best_root); + if (lib_gate_of(node) != root_gate){ + config_changed = TRUE; + } + assert(root_gate != NIL(lib_gate_t)); + BUFFER(node)->impl.gate = root_gate; + sp_replace_lib_gate(node, lib_gate_of(node), root_gate); + prev_dr = ((delay_pin_t *)(root_gate->delay_info[cfi]))->drive; + prev_ph = ((delay_pin_t *)(root_gate->delay_info[cfi]))->phase; + prev_bl = ((delay_pin_t *)(root_gate->delay_info[cfi]))->block; + } + + /* Implement the inverter if required and update its data */ + req_gI = large_req_time; cap_gI = 0.0; + if (inv_node != NIL(node_t)){ + /* Annotate the "inv_node" with the inverting buffer "best_inv" */ + inv_buf = buf_array[best_inv]; + if (BUFFER(inv_node)->impl.buffer != inv_buf){ + config_changed = TRUE; + } + req_gI = crit_neg; + cap_gI = auto_route + inv_buf->ip_load; + sp_subtract_delay(PHASE_INVERTING, inv_buf->block, inv_buf->drive, + total_cap_neg, &req_gI); + BUFFER(inv_node)->type = BUF; + BUFFER(inv_node)->impl.buffer = inv_buf; + sp_implement_buffer_chain(network, inv_node); + BUFFER(inv_node)->cfi = 0; + BUFFER(inv_node)->req_time = req_gI; + BUFFER(inv_node)->prev_ph = prev_ph; + BUFFER(inv_node)->prev_dr = prev_dr; + } + /* + * Now to update the required time data for the root gate itself + */ + MIN_DELAY(req_g, crit_pos, req_gI); + sp_subtract_delay(prev_ph, prev_bl, prev_dr, + total_cap_pos+cap_gI, &req_g); + BUFFER(node)->req_time = req_g; + + if (config_changed == FALSE){ + (void)fprintf(sisout, "Reporting changed when nothing happened\n"); + fail("ERROR in computation"); + } + + } else if (do_decomp && num_gates <= 1 && node_num_fanin(node) > 2) { + /* + * No replacement (stronger gate) available in library. + * Generate a topology using mapping for delay. + * Check the decomposition of this gate for a saving in delay + */ + netw = delay_generate_decomposition(node, 1.0 /* best delay */); + /* + * HACK: get_pin_delay() will return the delay data for the gate + * since the node is mapped... We have to fake the routine to + * return the mapped parameters computed by the above routine. + * We will invalidate the mapping and then set it later in case the + * decomposition is not accepted + */ + orig_gate = lib_gate_of(node); + map_invalid(node); + pin_delay = get_pin_delay(node, cfi, model); + + best.rise = best.fall = NEG_LARGE; + j = 0; best_inv = -1;; + do{ + req_gI = inv_fan[j].req; + cap_gI = inv_fan[j].load; + MIN_DELAY(req_g, req_gI, crit_pos); + sp_subtract_delay(pin_delay->phase, pin_delay->block, + pin_delay->drive, total_cap_pos+cap_gI, &req_g); + sp_drive_adjustment(orig_drive, pin_delay->load, &req_g); + + if (req_g.rise > orig_req.rise && req_g.fall > orig_req.fall){ + best = req_g; best_inv = j; + } + } while (++j < num_inv_choices); + + if (REQ_IMPR(req_g, orig_req) && pin_delay->load < max_ip_load){ + /* + * We will not bother to update the delay info + * since this is the end of recursion. Future delay + * traces will take care of the updating + */ + changed = 1; + if (inv_node != NIL(node_t)) { + new_gate = (buf_array[best_inv])->gate[0]; + sp_set_inverter(inv_node, node, new_gate); + BUFFER(inv_node)->type = GATE; + BUFFER(inv_node)->cfi = 0; + BUFFER(inv_node)->impl.gate = new_gate; + BUFFER(inv_node)->req_time = inv_fan[best_inv].req; + } + /* + * Replace "node" by nodes in "netw" + */ + gate_table = st_init_table(st_ptrcmp, st_ptrhash); + nodevec = network_and_node_to_array(netw, node, gate_table); + root_node = array_fetch(node_t *, nodevec, 1); + for (i = array_n(nodevec)-1; i > 1; i--) { + temp = array_fetch(node_t *, nodevec, i); + if (node_function(temp) != NODE_PI){ + network_add_node(network, temp); + /* Also need to annotate the node with corresp gate */ + assert(st_lookup(gate_table, (char *)temp, (char **)&new_gate)); + buf_add_implementation(temp, new_gate); + } else { + node_free(temp); + } + } + assert(st_lookup(gate_table,(char *)root_node, (char **)&new_gate)); + node_replace(node, root_node); + buf_add_implementation(node, new_gate); + array_free(nodevec); + network_free(netw); + st_free_table(gate_table); + } else { + /* Need to reinstate the mapping for the node */ + buf_add_implementation(node, orig_gate); + } + } + + if (changed){ + save->rise = best.rise - orig_req.rise; + save->fall = best.fall - orig_req.fall; + } else { + save->rise = save->fall = 0.0; + } + + if (buf_param->debug > 10){ + if (changed){ + (void)fprintf(sisout,"Saving achieved %7.3f:%-7.3f\n", + save->rise, save->fall ); + } else { + (void)fprintf(sisout,"No saving from repowering\n"); + } + } + + FREE(inv_fan); + return changed; +} + + diff --git a/sis/speed/buf_trans2.c b/sis/speed/buf_trans2.c new file mode 100644 index 0000000..7a33bca --- /dev/null +++ b/sis/speed/buf_trans2.c @@ -0,0 +1,596 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/buf_trans2.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include "buffer_int.h" + +static void buf_annotate_trans2(); +static void buf_implement_trans2(); + +static delay_time_t large_req_time = {POS_LARGE, POS_LARGE}; + +/* + * This routine takes the node "node" and the fanout set in "fanouts" + * (with the negative phase signals driven by the node "node_inv"). + * It will then evaluate the BALANCED DECOMPOSITION of the signals in + * the fanout set and possible repowerings/duplications to get the + * required time at the input of "node" to be as large as possible + * However we only increase the required time till it meets the "req_diff" + * value. Increasing req time beyond this does not help circuit delay. + * + * Divide the positive and negative signals into groups... + * Then evaluate the following + * -- Each group driven by an inverter and an additional + * inverter driving the added inverters + * -- The node is itself duplicated adequately and each + * group is driven by one of the duplicated nodes + */ + +int +buf_evaluate_trans2(network, buf_param, fanout_data, + gate_array, a_array, num_gates, cap_K_pos, cap_K_neg, + req_diff, levelp) +network_t *network; +buf_global_t *buf_param; +buf_alg_input_t *fanout_data; +delay_pin_t *gate_array; +double *a_array; +int num_gates; +double *cap_K_pos, *cap_K_neg; +delay_time_t req_diff; /* Amount we need to save */ +int *levelp; +{ + int changed; + int met_target; + int k, l, start, end; + int n, num_pos_part, num_neg_part; + int g, i , j, a, b, gI; + int num_inv = buf_param->num_inv; + delay_model_t model = buf_param->model; + node_t **new_a, *new_b, **new_gI; + int best_g, best_i , best_j, best_a, best_b, best_gI; + double *new_K_pos, *new_K_neg; + double area_a, area_b, area_gI, min_area, cur_area; + double auto_route = buf_param->auto_route; + double load, load_a, load_b, load_gI, orig_load; + double best_load_op_g, load_op_g; + delay_pin_t *pin_delay; + delay_time_t orig_drive; + sp_fanout_t *new_fan; + buf_alg_input_t *new_fanout_data; + sp_buffer_t *buf_a, *buf_b, *buf_gI; + sp_buffer_t **buf_array = buf_param->buf_array; + delay_time_t req_g, req_a, req_b, req_gI, cur_req; + delay_time_t best_req_a, best_req_b, best_req_gI; + delay_time_t req_op_g, best_req_op_g; + delay_time_t margin, target, best, orig_req, req_pos; + + node_t *node = fanout_data->node; + node_t *node_inv = fanout_data->inv_node; + sp_fanout_t *fanouts = fanout_data->fanouts; + int num_pos = fanout_data->num_pos; + int num_neg = fanout_data->num_neg; + + ++(*levelp); + changed = FALSE; + n = num_pos+num_neg; + + qsort((void *)fanouts, (unsigned)n, sizeof(sp_fanout_t), buf_compare_fanout); + if (buf_param->debug > 10){ + (void)fprintf(sisout,"******Trans2-Iteration %d -- aim to save %.3f:%.3f\n", + *levelp, req_diff.rise, req_diff.fall); + (void)fprintf(sisout,"\tRequired time and Load distribution \n"); + buf_dump_fanout_data(sisout, fanouts, n); + } + + num_neg_part = num_neg/2; /* Number of negative partitions */ + num_pos_part = num_pos/2; /* Number of positive partitions */ + + if ((num_neg_part + num_pos_part) == 0){ + if (buf_param->debug > 10){ + (void)fprintf(sisout, "No possibility of balanced partitions\n"); + } + return changed; + } + orig_req = BUFFER(node)->req_time; + orig_drive = BUFFER(node)->prev_dr; + orig_load = sp_get_pin_load(node, model); + + /* Adjust for delay due to limited drive of preceeding gate */ + sp_drive_adjustment(orig_drive, orig_load, &orig_req); + + /* + * Set a target for the current recursion. This is the value of the + * required time such that making the required time greater than this + * will not effect the delay of the circuit + */ + target.rise = orig_req.rise + req_diff.rise; + target.fall = orig_req.fall + req_diff.fall; + + /* + * Try duplication of node_inv "i" times and division of + * positive fanout signals into "j" groups + */ + met_target = FALSE; + best_i = best_j = best_gI = best_a = best_b = -1; + best.rise = best.fall = NEG_LARGE; + min_area = POS_LARGE; + + /* Checking the various configurations */ + for (g = 0; g < num_gates; g++){/* versions of root node */ + pin_delay = &(gate_array[g]); + if (pin_delay->load > fanout_data->max_ip_load){ + /* Load limit at "cfi" of root is violated !!! */ + continue; + } + for (gI = 0; gI < num_inv; gI++){ /* Choice of inverter gI */ + buf_gI = buf_array[gI]; + i = 2; + do { /* Try the different partitions of negative fanouts */ + /* + * Compute the req_time at the input of each gI inverter + * Also compute req_gI (The min req time among gI inputs) + * and load_gI (the load of all the gI nodes) + */ + req_gI = large_req_time; load_gI = 0; area_gI = 0; + load = 0.0; + if (num_neg > 1){ + area_gI = i * buf_gI->area; + load_gI = i * (auto_route+buf_gI->ip_load); + start = 0; + for (k = i; k > 0; k--, start = end){ + end = start + (num_neg - start)/k; + load = cap_K_neg[end] - cap_K_neg[start]; + cur_req = large_req_time; + for (l = start; l < end; l++){ + MIN_DELAY(cur_req, cur_req, + fanouts[num_pos+l].req); + } + sp_subtract_delay(buf_gI->phase, buf_gI->block, + buf_gI->drive, load, &cur_req); + MIN_DELAY(req_gI, req_gI, cur_req); + } + } else if (num_neg == 1) { + i = 1; + area_gI = buf_gI->area; + load_gI = auto_route+buf_gI->ip_load; + req_gI = fanouts[num_pos].req; + sp_subtract_delay(buf_gI->phase, buf_gI->block, + buf_gI->drive, load, &req_gI); + } + + j = 2; + do{ /* Partition positive fanouts into "j" groups */ + for (a = 0; a < num_inv; a++){ /* inv driving pos */ + /* req_a & load_a are at the input of buffers "a" */ + req_a = large_req_time; load_a = 0; area_a = 0; + buf_a = buf_array[a]; + if (num_pos > 1){ + area_a = j * buf_a->area; + load_a = j * (auto_route+buf_a->ip_load); + start = 0; + for (k = j; k > 0; k--, start = end){ + end = start + (num_pos - start)/k; + load = cap_K_pos[end] - cap_K_pos[start]; + req_pos = large_req_time; + for (l = start; l < end; l++){ + MIN_DELAY(req_pos, req_pos, fanouts[l].req); + } + sp_subtract_delay(buf_a->phase, buf_a->block, + buf_a->drive, load, &(req_pos)); + MIN_DELAY(req_a, req_a, req_pos); + } + } else if (num_pos == 1) { + j = 1; + area_a = buf_a->area; + load_a = auto_route + buf_a->ip_load; + req_a = fanouts[0].req; + sp_subtract_delay(buf_a->phase, buf_a->block, + buf_a->drive, load, &req_a); + } + + /* Now compute the req time at input of "b" */ + for (b = 0; b < num_inv; b++){ /* inv driving a's*/ + buf_b = buf_array[b]; + req_b = req_a; load_b = 0; area_b = 0; + if (num_pos > 0){ + area_b = buf_b->area; + load_b = buf_b->ip_load+auto_route; + sp_subtract_delay(buf_b->phase, buf_b->block, + buf_b->drive, load_a, &req_b); + } + + /* + * Now we can finally compute the required time at + * the root of the original gate + */ + + MIN_DELAY(req_g,req_b,req_gI); + req_op_g = req_g; + load_op_g = load_b + load_gI; + + sp_subtract_delay(pin_delay->phase, + pin_delay->block, pin_delay->drive, + load_op_g, &req_g); + /* Account for drive of previous stage */ + sp_drive_adjustment( orig_drive, pin_delay->load, &req_g); + + if (REQ_IMPR(req_g, target)){ + /* Keep the smallest area config */ + cur_area = a_array[g]+area_b+area_a+area_gI; + if (cur_area < min_area){ + met_target = TRUE; + min_area = cur_area; + best_b = b; best_a = a; best_gI = gI; + best_g = g; best_i = i; best_j = j; + best_req_gI = req_gI; best_req_b = req_b; + best_req_a = req_a; + } + } + if (!met_target && REQ_IMPR(req_g, best)){ + best = req_g; + best_b = b; best_a = a; best_gI = gI; + best_g = g; best_i = i; best_j = j; + best_req_gI = req_gI; best_req_b = req_b; + best_req_a = req_a; + best_req_op_g = req_op_g; + best_load_op_g = load_op_g; + } + if (num_pos <= 1) break; + } + if (num_pos <= 1) break; + } + } while (j++ < num_pos_part); + } while (i++ < num_neg_part); + /* No need to try more choices of gI inverters */ + if (num_neg == 0) break; + } + } + if (num_pos == 0) best_j = 0; + if (num_neg == 0) best_i = 0; + + if (buf_param->debug > 10){ + (void)fprintf(sisout,"Without root dupliction balanced trans2 achieves %6.3f:%-6.3f\n", + best.rise, best.fall); + } + + /* + * Check the case that slack at input other than "cfi" has worsened + * Not required when interfacing to the mapper + */ + if (buf_param->interactive && !met_target && + REQ_IMPR(best, orig_req) && (node_num_fanin(node) > 1)){ + if (buf_failed_slack_test(node, buf_param, best_g, best_req_op_g, + best_load_op_g)){ + if (buf_param->debug > 10){ + (void)fprintf(sisout, "SLACK CHECK during balanced xform\n"); + } + best.rise = best.fall = NEG_LARGE; + } + } + + if (REQ_IMPR(best, orig_req)){ + /* + * Have gotton some saving over naive buffering --- + * Generate the new configuration and then recur + */ + + changed = 1; + buf_implement_trans2(network, buf_param, node, node_inv, fanouts, num_pos, + num_neg, best_i, best_j, &new_a, &new_b, &new_gI); + /* + if (node_inv != NIL(node_t)){ + assert(node_num_fanout(node_inv) == 0); + network_delete_node(network, node_inv); + } + */ + buf_annotate_trans2(network, buf_param, fanouts, num_pos, num_neg, node, + new_a, new_b, new_gI, best_g, best_gI, best_a, + best_b, best_i, best_j); + + if (!met_target){ + /* How much are we still short */ + margin.rise = req_diff.rise - best.rise + orig_req.rise; + margin.fall = req_diff.fall - best.fall + orig_req.fall; + + /* + * Make recursive calls to the root node with new fanout set + * The fanout set is the set of invertes "a" as the negative + * set and the inverters "gI" as the positive set + */ + new_fan = ALLOC(sp_fanout_t, best_i+best_j); + + new_fanout_data = ALLOC(buf_alg_input_t, 1); + new_fanout_data->fanouts = new_fan; + new_fanout_data->node = node; + new_fanout_data->inv_node = new_b; + new_fanout_data->num_pos = best_i; + new_fanout_data->num_neg = best_j; + new_fanout_data->max_ip_load = fanout_data->max_ip_load; + + new_K_pos = ALLOC(double, best_i+1); + new_K_neg = ALLOC(double, best_j+1); + new_K_pos[0] = new_K_neg[0] = 0.0; + for (i = 0; i < best_i; i++){ + new_fan[i].fanout = new_gI[i]; + new_fan[i].pin = 0; + new_fan[i].load = auto_route+sp_get_pin_load(new_gI[i], model); + new_fan[i].req = BUFFER(new_gI[i])->req_time; + new_fan[i].phase = PHASE_NONINVERTING; + new_K_pos[i+1] = new_K_pos[i] + new_fan[i].load; + } + + for (j = 0, l = best_i; j < best_j; j++, l++){ + new_fan[l].fanout = new_a[j]; + new_fan[l].pin = 0; + new_fan[l].load = auto_route+sp_get_pin_load(new_a[j], model); + new_fan[l].req = BUFFER(new_a[j])->req_time; + new_fan[l].phase = PHASE_INVERTING; + new_K_neg[j+1] = new_K_neg[j] + new_fan[l].load; + } + /* No need to do an unbalanced decomp at this stage */ + /* + changed += sp_buffer_recur(network, buf_param, model, node, new_b, + new_fan, best_i, best_j, margin, levelp); + */ + changed += buf_evaluate_trans2(network, buf_param, new_fanout_data, + gate_array, a_array, num_gates, new_K_pos, new_K_neg, + margin, levelp); + FREE(new_fanout_data->fanouts); + FREE(new_fanout_data); + FREE(new_K_pos); + FREE(new_K_neg); + } else { + /* Trans2 achieves the desired required time */ + if (buf_param->debug > 10) (void)fprintf(sisout, + "\t--- Trans2 ACHIEVES DESIRED REQUIRED TIME---\n"); + } + FREE(new_a); + FREE(new_gI); + } + + return changed; +} + +static void +buf_implement_trans2(network, buf_param, node, inv_node, fanouts, num_pos, + num_neg, best_i, best_j, new_ap, new_bp, new_gIp) +network_t *network; +buf_global_t *buf_param; +node_t *node, *inv_node; +sp_fanout_t *fanouts; +int num_pos, num_neg; +int best_i, best_j; +node_t ***new_ap, **new_bp, ***new_gIp; /* RETURN: added nodes */ +{ + node_t *new_node; + int i, l, count, start, end; + node_t **new_a, *new_b, **new_gI; + + /* Defaults */ + new_b = NIL(node_t); + new_a = NIL(node_t *); + new_gI = NIL(node_t *); + + /* Add "best_i" number of inverters (including inv_node) */ + if (num_neg > 0 && best_i > 0){ + count = start = 0; + new_gI = ALLOC(node_t *, best_i); + + for (i = best_i; i > 0; i--, start = end){ + end = start + (num_neg - start)/i; + if (i == 1){ + /* use the inv_node as the last one */ + new_node = inv_node; + } else { + new_node = node_literal(node, 0); + network_add_node(network, new_node); + } + new_gI[count++] = new_node; + + for (l = start; l < end; l++){ + assert(node_patch_fanin(fanouts[num_pos+l].fanout, inv_node, new_node)); + } + } + } else if (buf_param->debug > 10) { + (void)fprintf(sisout,"No partion of negative fanouts\n"); + } + /* + * Now create the tree for the positive fanouts... + */ + if (num_pos > 0 && best_j > 0){ + count = start = 0; + new_a = ALLOC(node_t *, best_j); + + /* The inverter at the root of the tree */ + new_b = node_literal(node, 0); + network_add_node(network, new_b); + + for (i = best_j; i > 0; i--, start = end){ + end = start + (num_pos - start)/i; + + new_node = node_literal(new_b, 0); + network_add_node(network, new_node); + new_a[count++] = new_node; + + for (l = start; l < end; l++){ + assert(node_patch_fanin(fanouts[l].fanout, node, new_node)); + } + } + } else if (buf_param->debug > 10) { + (void)fprintf(sisout,"No partion of positive fanouts\n"); + } + + *new_bp = new_b; + *new_ap = new_a; + *new_gIp = new_gI; +} + +static void +buf_annotate_trans2(network, buf_param, fanouts, num_pos, num_neg, + node, new_a, new_b, new_gI, + best_g, best_gI, best_a, best_b, best_i, best_j) +network_t *network; +buf_global_t *buf_param; +sp_fanout_t *fanouts; +int num_pos, num_neg; +node_t *node, **new_a, *new_b, **new_gI; +int best_g, best_gI, best_a, best_b, best_i, best_j; +{ + int start, end; + int i, j, l, cfi; + pin_phase_t prev_ph; + lib_gate_t *root_gate; + node_t *cur_a, *cur_gI; + double auto_route = buf_param->auto_route; + double load, cap_b, cap_a, cap_gI; + sp_buffer_t *buf_b, *buf_a, *buf_g, *buf_gI; + sp_buffer_t **buf_array = buf_param->buf_array; + delay_time_t prev_dr, prev_bl; + delay_time_t req_b, req_a, req_gI, req_g, cur_req; + + cfi = BUFFER(node)->cfi; + if (node->type == PRIMARY_INPUT) { + prev_bl.rise = prev_bl.fall = 0.0; + prev_dr.rise = prev_dr.fall = 0.0; /* This needs to be fixed !!!! */ + prev_ph = PHASE_NONINVERTING; + } else if (BUFFER(node)->type == BUF){ + buf_g = buf_array[best_g]; + BUFFER(node)->impl.buffer = buf_g; + sp_implement_buffer_chain(network, node); + BUFFER(node)->cfi = cfi; + prev_bl = buf_g->block; + prev_dr = buf_g->drive; + prev_ph = buf_g->phase; + } else { + /* Find the appropriate gate in the class if needed */ + root_gate = lib_gate_of(node); + if (buf_param->mode & REPOWER_MASK){ + root_gate = buf_get_gate_version(root_gate, best_g); + assert(root_gate != NIL(lib_gate_t)); + BUFFER(node)->impl.gate = root_gate; + sp_replace_lib_gate(node, lib_gate_of(node), root_gate); + } + prev_dr = ((delay_pin_t *)(root_gate->delay_info[cfi]))->drive; + prev_ph = ((delay_pin_t *)(root_gate->delay_info[cfi]))->phase; + prev_bl = ((delay_pin_t *)(root_gate->delay_info[cfi]))->block; + } + + /* Now all the gI inverters are annotated */ + req_gI = large_req_time; cap_gI = 0; + if (new_gI != NIL(node_t *)){ + start = 0; + for (i = best_i, j = 0; i > 0; i--, j++, start = end){ + end = start + (num_neg - start)/i; + + cur_gI = new_gI[j]; + buf_gI = buf_array[best_gI]; + BUFFER(cur_gI)->type = BUF; + BUFFER(cur_gI)->impl.buffer = buf_gI; + sp_implement_buffer_chain(network, cur_gI); + + load = 0; cur_req = large_req_time; + for (l = start; l < end; l++){ + load += fanouts[num_pos+l].load; + MIN_DELAY(cur_req, cur_req, fanouts[num_pos+l].req); + } + sp_subtract_delay(buf_gI->phase, buf_gI->block, buf_gI->drive, + load, &cur_req); + + MIN_DELAY(req_gI, req_gI, cur_req); + + cap_gI += buf_gI->ip_load + auto_route; + + BUFFER(cur_gI)->load = load; + BUFFER(cur_gI)->req_time = cur_req; + BUFFER(cur_gI)->cfi = 0; + BUFFER(cur_gI)->prev_ph = prev_ph; + BUFFER(cur_gI)->prev_dr = prev_dr; + } + } + + /* + * Now see if there is a partitioning for the positive fanout signals + * If so annotate the buffer "b" and fannning out from it the "best_j" + * inverters "a" + */ + req_b = large_req_time; cap_b = 0; + if (new_a != NIL(node_t *)){ + + assert(new_b != NIL(node_t)); + buf_b = buf_array[best_b]; + + req_a = large_req_time; cap_a = 0; + start = 0; + for (i = best_j; i > 0; i--, start = end){ + end = start + (num_pos - start)/i; + + cur_a = new_a[i-1]; + buf_a = buf_array[best_a]; + BUFFER(cur_a)->type = BUF; + BUFFER(cur_a)->impl.buffer = buf_a; + sp_implement_buffer_chain(network, cur_a); + + load = 0; cur_req = large_req_time; + for (l = start; l < end; l++){ + load += fanouts[l].load; + MIN_DELAY(cur_req, cur_req, fanouts[l].req); + } + sp_subtract_delay(buf_a->phase, buf_a->block, buf_a->drive, + load, &cur_req); + + /* Keep track of the earliest required of the "a" inverters */ + MIN_DELAY(req_a, req_a, cur_req); + + cap_a += buf_a->ip_load + auto_route; + + BUFFER(cur_a)->load = load; + BUFFER(cur_a)->req_time = cur_req; + BUFFER(cur_a)->cfi = 0; + BUFFER(cur_a)->prev_ph = buf_b->phase; + BUFFER(cur_a)->prev_dr = buf_b->drive; + } + + /* Now annotate the node "new_b" itself */ + BUFFER(new_b)->type = BUF; + BUFFER(new_b)->impl.buffer = buf_b; + sp_implement_buffer_chain(network, new_b); + req_b = req_a; cap_b = buf_b->ip_load + auto_route; + sp_subtract_delay(buf_b->phase, buf_b->block, buf_b->drive, + cap_a, &req_b); + BUFFER(new_b)->load = load; + BUFFER(new_b)->req_time = req_b; + BUFFER(new_b)->cfi = 0; + BUFFER(new_b)->prev_ph = prev_ph; + BUFFER(new_b)->prev_dr = prev_dr; + } + + /* Now to update the required time data for the root gate itself */ + MIN_DELAY(req_g, req_b, req_gI); + load = cap_b + cap_gI; + sp_subtract_delay(prev_ph, prev_bl, prev_dr, load, &req_g); + BUFFER(node)->load = load; + BUFFER(node)->req_time = req_g; + + if (buf_param->debug > 10){ + (void)fprintf(sisout,"Trans2 data ---\n"); + (void)fprintf(sisout,"\t%d groups of positive signals - a=%d, b=%d\n", + best_j, best_a, best_b); + (void)fprintf(sisout,"\t%d partitions of negative signals -- gI=%d\n", + best_i, best_gI); + (void)fprintf(sisout,"\treq_a = %6.3f:%-6.3f, req_b = %6.3f:%-6.3f\n", + req_a.rise, req_a.fall, req_b.rise, req_b.fall); + (void)fprintf(sisout,"\treq_gI = %6.3f:%-6.3f, req_g = %6.3f:%-6.3f\n", + req_gI.rise, req_gI.fall, req_g.rise, req_g.fall); + } +} + + + diff --git a/sis/speed/buf_util.c b/sis/speed/buf_util.c new file mode 100644 index 0000000..f2d3ae9 --- /dev/null +++ b/sis/speed/buf_util.c @@ -0,0 +1,811 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/buf_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include <math.h> +#include "speed_int.h" +#include "buffer_int.h" + +static int sp_compare_buf(); +static int speed_lib_buffers(); +static void sp_insert_buf_in_list(); + +static double sp_inv_load; +static delay_time_t sp_unit_fanout_block ={ 1.0, 1.0}; + + +/* + * node daemon to allocate the storage with every node + */ +void +buffer_alloc(node) +node_t *node; +{ + node->BUFFER_SLOT = (char *) ALLOC(sp_node_t, 1); + BUFFER(node)->type = NONE; + BUFFER(node)->cfi = -1; +} + +/* + * node daemon to free the memory associated with the BUFFER_SLOT field + */ +void +buffer_free(node) +node_t *node; +{ + FREE(node->BUFFER_SLOT); +} +static delay_time_t sp_unit_fanout_drive ={ 0.2, 0.2}; + + +/* + * get all the buffers and inverters from the library . If none is + * found then returns a dummy buffer with the delay characteristics of + * the unit fanout model + */ +void +buf_set_buffers(network, use_mapped, buf_param) +network_t *network; /* The network we are looking at for buffering */ +int use_mapped; /* When set use the library information */ +buf_global_t *buf_param; +{ + double d; + library_t *lib; + + buf_param->auto_route = compute_wire_load(network, 1); + buf_param->glbuftable = st_init_table(st_ptrcmp, st_ptrhash); + + if (use_mapped || lib_network_is_mapped(network)){ + lib = lib_get_library(); + (void)speed_lib_buffers(lib, 2, buf_param, &d); + buf_param->model = DELAY_MODEL_MAPPED; + } else { + (void)speed_lib_buffers(NIL(library_t), 2, buf_param, &d); + buf_param->model = DELAY_MODEL_UNIT_FANOUT; + + } + buf_param->min_req_diff = d; + + sp_buf_array_from_list(buf_param); +} +/* + * Free the structures that store the buffers used during buffering + */ +void +buf_free_buffers(buf_param) +buf_global_t *buf_param; +{ + int i, n = buf_param->num_buf; + + /* Delete the buffer structures --- They are in the list and the array */ + for (i = 0; i < n; i++){ + FREE(buf_param->buf_array[i]->gate); + FREE(buf_param->buf_array[i]); + } + FREE(buf_param->buf_array); + st_free_table(buf_param->glbuftable); + (void)lsDestroy(buf_param->buffer_list,(void(*)())0); +} + +static int +speed_lib_buffers(lib, limit, buf_param, p_min_req_diff) +library_t *lib; +int limit; +buf_global_t *buf_param; +double *p_min_req_diff; +{ + lsGen gen; + lsGeneric dummy; + lib_gate_t *gate; + lib_class_t *class; + sp_buffer_t *buffer; + double d, min_req_diff; + + *p_min_req_diff = 0.0; + buf_param->buffer_list = lsCreate(); + if (lib == NIL(library_t)){ + sp_insert_buf_in_list(buf_param->buffer_list, buf_param, NIL(sp_buffer_t), NIL(lib_gate_t)); + return 1; + } + if ((gate = sp_lib_get_inv(lib)) == NIL(lib_gate_t)){ + sp_insert_buf_in_list(buf_param->buffer_list, buf_param, NIL(sp_buffer_t), NIL(lib_gate_t)); + return 1; + } + class = lib_gate_class(gate); + sp_inv_load = limit * ((delay_pin_t *)(gate->delay_info[0]))->load; + gen = lib_gen_gates(class); + while (lsNext(gen, &dummy, LS_NH) == LS_OK) { + gate = (lib_gate_t *)dummy; + sp_insert_buf_in_list(buf_param->buffer_list, buf_param, NIL(sp_buffer_t), gate); + } + (void)lsFinish(gen); + + /* Now we want to get the buffers from the library */ + if ((gate = sp_lib_get_buffer(lib)) != NIL(lib_gate_t)){ + class = lib_gate_class(gate); + gen = lib_gen_gates(class); + while (lsNext(gen, &dummy, LS_NH) == LS_OK) { + gate = (lib_gate_t *)dummy; + sp_insert_buf_in_list(buf_param->buffer_list, buf_param, NIL(sp_buffer_t), gate); + } + (void)lsFinish(gen); + } + /* Sort the inverters in list -- smallest last */ + (void)lsSort(buf_param->buffer_list, sp_compare_buf); + + gen = lsStart(buf_param->buffer_list); + min_req_diff = POS_LARGE; + while (lsNext(gen, &dummy, LS_NH) == LS_OK) { + buffer = (sp_buffer_t *)dummy; + if (buffer->phase == PHASE_NONINVERTING){ + d = MIN(buffer->block.rise, buffer->block.fall); + min_req_diff = MIN(d, min_req_diff); + } + } + lsFinish(gen); + + if(buf_param->debug > 10){ + speed_dump_buffer_list(sisout, buf_param->buffer_list); + } + + if (min_req_diff != POS_LARGE){ + *p_min_req_diff = min_req_diff; + } + return 0; +} + + +void +speed_dump_buffer_list(fp, buffer_list) +FILE *fp; +lsList buffer_list; +{ + lsGen gen; + char *dummy; + sp_buffer_t *buffer; + double d1, d2; + + (void)fprintf(fp,"type name area ipcap blck_r blck_f drve_r drve_f rise fall\n"); + (void)fprintf(fp,"--------------------------------------------------------------------------\n"); + gen = lsStart(buffer_list); + while (lsNext(gen, &dummy, LS_NH) == LS_OK) { + buffer = (sp_buffer_t *)dummy; + d1 = buffer->block.rise + sp_inv_load * buffer->drive.rise; + d2 = buffer->block.fall + sp_inv_load * buffer->drive.fall; + (void)fprintf(fp,"%s %-14s %5.1f %-6.3f %-6.3f %-6.3f %-6.3f %-6.3f %-6.3f %-6.3f\n", + (buffer->phase == PHASE_INVERTING? "INV" : "BUF"), + sp_buffer_name(buffer), buffer->area,buffer->ip_load, + buffer->block.rise, buffer->block.fall, + buffer->drive.rise, buffer->drive.fall, + d1, d2); + } + (void)lsFinish(gen); +} + +/* Sort the buffers according to size -- hope that the smallest is slowest */ +static int +sp_compare_buf(item1, item2) +lsGeneric item1, item2; +{ + sp_buffer_t *buf1, *buf2; + + buf1 = (sp_buffer_t *)item1; + buf2 = (sp_buffer_t *)item2; + + if (buf1->phase == buf2->phase){ + if (buf2->area < buf1->area) return -1; + else if (buf2->area > buf1->area) return 1; + else return 0; + } else { + if (buf1->phase == PHASE_INVERTING){ + return -1; + } else { + return 1; + } + } + + +} + + +/* + * Generates the array of buffers that we need to use -- + * The buf_list is sorted (inverters come earlier) and so is the buf_array + */ +void +sp_buf_array_from_list(buf_param) +buf_global_t *buf_param; +{ + int i = 0; + lsGen gen; + lsGeneric dummy; + sp_buffer_t *buffer; + lsList buf_list = buf_param->buffer_list; + + buf_param->num_inv = 0; + buf_param->num_buf = 0; + buf_param->buf_array = ALLOC(sp_buffer_t *, lsLength(buf_list)); + gen = lsStart(buf_list); + while (lsNext(gen, &dummy, LS_NH) == LS_OK) { + buffer = (sp_buffer_t *)dummy; + if (buffer->phase == PHASE_NONINVERTING){ + buf_param->num_buf++; + } else { + buf_param->num_inv++; + } + buf_param->buf_array[i++] = buffer; + } + buf_param->num_buf += buf_param->num_inv; + (void)lsFinish(gen); +} + +/* + * Sets "gate" as the impl of "node = fanin';" + * gate must be an inverter in the library + */ +void +sp_set_inverter(node, fanin, gate) +node_t *node, *fanin; +lib_gate_t *gate; +{ + char *inv_formals[1]; + node_t *inv_actuals[1]; + + inv_actuals[0] = fanin; + inv_formals[0] = lib_gate_pin_name(gate, 0, 1); + (void)lib_set_gate(node, gate, inv_formals ,inv_actuals, 1); +} + +/* + * Will take the gate implementing "node" and get the extreme gate + * of that class and fix that as the implementation of "newnode". In the + * case that "node" has its impl set as a BUF we will set the impl to + * be the smallest buffer. + */ +/* ARGSUSED */ +void +sp_buf_annotate_gate(node, buf_param) +node_t *node; +buf_global_t *buf_param; +{ + int cfi; + lib_gate_t *gate; + pin_phase_t phase; + delay_pin_t *pin_delay; + delay_time_t t, desired, drive; + sp_buffer_t **buf_array = buf_param->buf_array; + + if ((gate = lib_gate_of(node)) == NIL(lib_gate_t)) { + if (BUFFER(node)->type == NONE){ + BUFFER(node)->type = BUF; + BUFFER(node)->impl.buffer = buf_array[buf_param->num_buf -1]; + } + } else { + BUFFER(node)->type = GATE; + BUFFER(node)->impl.gate = gate; + } + cfi = sp_buf_get_crit_fanin(node, buf_param->model); + pin_delay = get_pin_delay(node, cfi, buf_param->model); + phase = pin_delay->phase; + t = delay_node_pin(node, cfi, buf_param->model); + desired = delay_required_time(node); + sp_compute(phase, &desired, t); + BUFFER(node)->load = delay_load(node); + BUFFER(node)->cfi = cfi; + BUFFER(node)->req_time = desired; /* req time at cfi input of node */ + + drive = sp_get_input_drive(node, buf_param->model, &phase); + BUFFER(node)->prev_dr = drive; + BUFFER(node)->prev_ph = phase; + return; +} + +lib_gate_t * +buf_get_gate_version(gate, version) +lib_gate_t *gate; +int version; +{ + lsGen gen; + char *dummy; + int num_gates; + lib_gate_t *root_gate; + + num_gates = 0; root_gate = NIL(lib_gate_t); + gen = lib_gen_gates(lib_gate_class(gate)); + while (lsNext(gen, &dummy, LS_NH) == LS_OK){ + if (num_gates++ == version) { + root_gate = (lib_gate_t *)dummy; + break; + } + } + (void)lsFinish(gen); + + return root_gate; +} +/* + * Check to see if for the given value of req_time and load at the output + * is the minimum slack worsened at any of the inputs. If the + */ +int +buf_failed_slack_test(node, buf_param, gate_version, op_req, op_load) +node_t *node; +buf_global_t *buf_param; +int gate_version; +delay_time_t op_req; +double op_load; +{ + int i; + node_t *fanin; + lib_gate_t *root_gate; + double fom, fom_best, new_fom_best; + delay_model_t model = buf_param->model; + pin_phase_t phase; + delay_time_t block, drive; + delay_time_t arrival, req, slack, new_req, new_slack; + + if (lib_gate_of(node) == NIL(lib_gate_t) || node_num_fanin(node) == 1){ + return 0; + } + + root_gate = buf_get_gate_version(lib_gate_of(node), gate_version); + assert(root_gate != NIL(lib_gate_t)); + + fom_best = new_fom_best = POS_LARGE; + foreach_fanin(node, i, fanin){ + (void)delay_wire_required_time(node, i, model, &req); + arrival = delay_arrival_time(fanin); + slack.rise = req.rise - arrival.rise; + slack.fall = req.fall - arrival.fall; + + fom = BUF_MIN_D(slack); + fom_best = MIN(fom, fom_best); + + phase = ((delay_pin_t *)(root_gate->delay_info[i]))->phase; + drive = ((delay_pin_t *)(root_gate->delay_info[i]))->drive; + block = ((delay_pin_t *)(root_gate->delay_info[i]))->block; + new_req = op_req; + sp_subtract_delay(phase, block, drive, op_load, &new_req); + new_slack.rise = new_req.rise - arrival.rise; + new_slack.fall = new_req.fall - arrival.fall; + + fom = BUF_MIN_D(new_slack); + new_fom_best = MIN(fom, new_fom_best); + } + + if (new_fom_best < fom_best){ + if (buf_param->debug > 10) { + (void)fprintf(sisout, "WARNING: slack increase at other input\n"); + (void)fprintf(sisout, "\tNode %s, gate %s, R=%.3f:%.3f, L=%.3f\n", + node->name, root_gate->name, op_req.rise, + op_req.fall, op_load); + } + return 1; + } + return 0; +} +/* + * Look at the fanins of node and find the index that is most + * critical. This index gives us the fanin such that if we decrease + * the required time at that fanin -- we would most likely decrease the + * delay thru the entire netw + */ +int +sp_buf_get_crit_fanin(node, model) +node_t *node; +delay_model_t model; +{ + int i, cfi; + node_t *fanin; + double fom, fom_best; + delay_time_t arrival, req, slack; + + if (node_num_fanin(node) == 1) return 0; + + fom_best = POS_LARGE; + foreach_fanin(node, i, fanin){ + (void)delay_wire_required_time(node, i, model, &req); + arrival = delay_arrival_time(fanin); + slack.rise = req.rise - arrival.rise; + slack.fall = req.fall - arrival.fall; + /* + * figure of merit -- slack value at the signal + */ + fom = BUF_MIN_D(slack); + if (fom < fom_best){ + fom_best = fom; cfi = i; + } + } + return cfi; +} +/* + * Set the threshold for determining the critical paths in the network + */ +void +set_buf_thresh(network, buf_param) +network_t *network; +buf_global_t *buf_param; +{ + delay_time_t time; + double my_thresh, min_t; + node_t *po; + lsGen gen; + + my_thresh = POS_LARGE; + foreach_primary_output(network, gen, po){ + time = delay_slack_time(po); + min_t = D_MIN(time.rise, time.fall); + my_thresh = D_MIN(my_thresh, min_t); + } + if (my_thresh > 0 ) { + /* + * All output nodes meet the required + * time costraints. + */ + buf_param->crit_slack = -1.0; + } else { + /* + * Set the threshold for the epsilon + * network to be within thresh of the most + * most critical node. + */ + buf_param->crit_slack = my_thresh + buf_param->thresh; + } +} + +/* + * Return 1 if the node is within "thresh" of the most critical + */ +int +buf_critical(np, buf_param) +node_t *np; +buf_global_t *buf_param; +{ + delay_time_t time; + + time = delay_slack_time(np); + if (time.rise <= buf_param->crit_slack || time.fall <= buf_param->crit_slack) { + return TRUE; + } else { + return FALSE; + } +} + +/* + * Replace gate by pref_gate as the implementation of "node" + */ +void +sp_replace_lib_gate(node, gate, pref_gate) +node_t *node; +lib_gate_t *gate, *pref_gate; +{ + int i, nin; + char **formals; + node_t **actuals, *fanin; + + assert(lib_gate_class(gate) == lib_gate_class(pref_gate)); + nin = node_num_fanin(node); + formals = ALLOC(char *, nin); + actuals = ALLOC(node_t *, nin); + foreach_fanin(node, i, fanin){ + formals[i] = lib_gate_pin_name(gate, i, 1); + actuals[i] = fanin; + } + (void)lib_set_gate(node, pref_gate, formals, actuals, nin); + FREE(formals); + FREE(actuals); +} + + +/* + * Determine the name of the implementation of the node --- + * Useful only for debugging the buffering routines + * Successive calls to this routine use the same storage and + * so to save the name need to strsav the returned string + */ +char * +sp_name_of_impl(node) +node_t *node; +{ + static char name[BUFSIZ]; + if (node == NIL(node_t)){ + (void)strcpy(name,"--NONE--"); + } else if (node->type == PRIMARY_INPUT){ + (void)strcpy(name,"NODE_PI"); + } else if (BUFFER(node)->type == BUF){ + (void)strcpy(name, sp_buffer_name(BUFFER(node)->impl.buffer)); + } else if (BUFFER(node)->type == GATE){ + (void)strcpy(name, lib_gate_name(BUFFER(node)->impl.gate)); + } else { + (void)strcpy(name,"-NONE-"); + } + return name; +} + +/* + * Returns a contrived name for the buffer implementing the node -- + * The name is of the form "inv1-inv2" -- uses a static storage too + */ +char * +sp_buffer_name(buffer) +sp_buffer_t *buffer; +{ + int i; + static char name[BUFSIZ]; + + if (buffer == NIL(sp_buffer_t)) (void)strcpy(name,"NONE"); + if (buffer->gate[0] == NIL(lib_gate_t)){ (void)strcpy(name,"UNIT_FAN"); + } else { + (void)strcpy(name,lib_gate_name(buffer->gate[0])); + for (i = 1; i < buffer->depth; i++){ + (void)strcat(name, "-"); + (void)strcat(name, lib_gate_name(buffer->gate[i])); + } + } + return name; +} + + +/* + * Creates a buffer that is buffer "prev" followed by the gate "gate" + * and inserts the buffer just created into the lsList "buffer_list" + * Note: "prev" can be a NULL and so can gate + */ +static void +sp_insert_buf_in_list(buffer_list, buf_param, prev, gate) +lsList buffer_list; +buf_global_t *buf_param; +sp_buffer_t *prev; +lib_gate_t *gate; +{ + int i; + delay_time_t block; + sp_buffer_t *inv_buffer, *buffer; + double load, auto_route = buf_param->auto_route; + + buffer = ALLOC(sp_buffer_t,1); + if (prev == NIL(sp_buffer_t)){ + buffer->depth = 1; + buffer->gate = ALLOC(lib_gate_t *, 1); + buffer->gate[0] = gate; + if (gate != NIL(lib_gate_t)){ + buffer->area = lib_gate_area(gate); + /* Single fanin gates only -- use 0 fanin */ + buffer->phase = ((delay_pin_t *)(gate->delay_info[0]))->phase; + buffer->block = ((delay_pin_t *)(gate->delay_info[0]))->block; + buffer->drive = ((delay_pin_t *)(gate->delay_info[0]))->drive; + buffer->ip_load = ((delay_pin_t *)(gate->delay_info[0]))->load; + buffer->max_load = ((delay_pin_t *)(gate->delay_info[0]))->max_load; + } else { + /* Add non-inverting buffer to the list */ + buffer->area = 1.0; + buffer->phase = PHASE_NONINVERTING; + buffer->block = sp_unit_fanout_block; + buffer->drive = sp_unit_fanout_drive; + buffer->ip_load = 1.0; + buffer->max_load = POS_LARGE; + (void)lsNewBegin(buffer_list, (lsGeneric)buffer, LS_NH); + + /* Add inverting buffer too */ + inv_buffer = ALLOC(sp_buffer_t,1); + *inv_buffer = *buffer; + inv_buffer->gate = ALLOC(lib_gate_t *, 1); + inv_buffer->gate[0] = gate; + inv_buffer->phase = PHASE_INVERTING; + buffer = inv_buffer; + } + } else { + buffer->depth = prev->depth + 1; + buffer->gate = ALLOC(lib_gate_t *,buffer->depth); + for (i = 0; i < prev->depth; i++){ + buffer->gate[i] = prev->gate[i]; + } + buffer->gate[prev->depth] = gate; + /* + * We only chain inverters -- hence dont bother to compute the + * phase of the chain. Assume it is NONINVERTING + */ + buffer->phase = PHASE_NONINVERTING; + buffer->area = prev->area + lib_gate_area(gate); + load = auto_route + ((delay_pin_t *)(gate->delay_info[0]))->load; + block = ((delay_pin_t *)(gate->delay_info[0]))->block; + buffer->block.rise = prev->block.fall + prev->drive.fall * load + block.rise; + buffer->block.fall = prev->block.rise + prev->drive.rise * load + block.fall; + buffer->drive = ((delay_pin_t *)(gate->delay_info[0]))->drive; + buffer->ip_load = prev->ip_load; + buffer->max_load = delay_get_load_limit(gate->delay_info[0]); + } + (void)lsNewBegin(buffer_list, (lsGeneric)buffer, LS_NH); +} + +/* + * Free the storage associated with the buffers in "list" and + * then destroy the list. Garbage collection function + */ +void +speed_free_buffer_list(list) +lsList list; +{ + lsGen gen; + lsGeneric dummy; + + gen = lsStart(list); + while (lsNext(gen, &dummy, LS_NH) == LS_OK) { + FREE(((sp_buffer_t *)dummy)->gate); + FREE(dummy); + } + (void)lsDestroy(list,(void(*)())0); + (void)lsFinish(gen); +} + +/* + * If the node is implemented as a buffer then replace the node by the + * gates that make up the buffer... Even thought there are more efficient + * implemetations this particular one is chosen since it retains the + * node as the root of the chain (closest to input ) + */ +void +sp_implement_buffer_chain(network, node) +network_t *network; +node_t *node; +{ + lsGen gen; + int n, i, j; + node_t *temp, *fanin, **fanouts, *fo; + sp_buffer_t *buffer; + + if (node == NIL(node_t) || node->type == PRIMARY_INPUT) return; + if (BUFFER(node)->type == BUF){ + buffer = BUFFER(node)->impl.buffer; + if (buffer->gate[0] != NIL(lib_gate_t)){ + fanin = node_get_fanin(node, 0); + if (buffer->depth == 1){ + sp_set_inverter(node, fanin, buffer->gate[0]); + BUFFER(node)->type = GATE; + BUFFER(node)->cfi = 0; + BUFFER(node)->impl.gate = buffer->gate[0]; + } else { + n = node_num_fanout(node); + fanouts = ALLOC(node_t *, n); + i = 0; + foreach_fanout(node, gen, fo){ + fanouts[i++] = fo; + } + sp_set_inverter(node, fanin, buffer->gate[0]); + BUFFER(node)->type = GATE; + BUFFER(node)->cfi = 0; + BUFFER(node)->impl.gate = buffer->gate[0]; + fanin = node; + for (j = 1; j < buffer->depth; j++){ + temp = node_alloc(); + sp_set_inverter(temp, fanin, buffer->gate[j]); + network_add_node(network, temp); + fanin = temp; + BUFFER(temp)->type = GATE; + BUFFER(temp)->cfi = 0; + BUFFER(temp)->impl.gate = buffer->gate[j]; + if (j == buffer->depth - 1){ + /* patch the fanouts of the original node to fanin */ + for (i = 0; i < n; i++){ + assert(node_patch_fanin(fanouts[i], node, fanin)); + } + } + } + FREE(fanouts); + } + } + } +} + +/* + * Add the implementation of the node to be gate + */ +void +buf_add_implementation(node, gate) +node_t *node; +lib_gate_t *gate; +{ + int i, nin; + char **formals; + node_t **actuals, *fanin; + + nin = node_num_fanin(node); + formals = ALLOC(char *, nin); + actuals = ALLOC(node_t *, nin); + foreach_fanin(node, i, fanin){ + formals[i] = lib_gate_pin_name(gate, i, 1); + actuals[i] = fanin; + } + (void)lib_set_gate(node, gate, formals, actuals, nin); + + BUFFER(node)->type = GATE; + BUFFER(node)->impl.gate = gate; + BUFFER(node)->cfi = 0; + + FREE(formals); + FREE(actuals); +} + +/* + * Some routines to allow the mapping to interface this package + * We need a static variable here to store some information of the + * behalf of the mapping package. + */ + +static buf_global_t map_buf_param; + +void +buf_init_top_down(network, mode, debug) +network_t *network; +int mode, debug; +{ + (void)buffer_fill_options(&map_buf_param, 0, NIL(char *)); + map_buf_param.mode = mode; + map_buf_param.debug = debug; + /* The setting of buffers is a constant core leak per mapping procedure */ + buf_set_buffers(network, 1, &map_buf_param); +} +void +buf_map_interface(network, data) +network_t *network; +buf_alg_input_t *data; /* Data for the buffering */ +{ + int level = 0; + delay_time_t impr; /* amount of improvement desired */ + + impr.rise = impr.fall = POS_LARGE; + (void)sp_buffer_recur(network, &map_buf_param, data, impr, &level); +} + +delay_model_t +buf_get_model() +{ + return (map_buf_param.model); +} + +double +buf_get_auto_route() +{ + return (map_buf_param.auto_route); +} + +delay_time_t +buf_get_required_time_at_input(node) +node_t *node; +{ + return (BUFFER(node)->req_time); +} + +void +buf_set_required_time_at_input(node, req) +node_t *node; +delay_time_t req; +{ + BUFFER(node)->req_time = req; +} + +void +buf_set_prev_drive(node, drive) +node_t *node; +delay_time_t drive; +{ + BUFFER(node)->prev_dr = drive; +} + +void +buf_set_prev_phase(node, phase) +node_t *node; +pin_phase_t phase; +{ + BUFFER(node)->prev_ph = phase; +} + + + + + diff --git a/sis/speed/buffer_int.h b/sis/speed/buffer_int.h new file mode 100644 index 0000000..35affab --- /dev/null +++ b/sis/speed/buffer_int.h @@ -0,0 +1,148 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/buffer_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +/* + * Data Structures internal to buffering package + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + */ +typedef struct buffer_struct{ + int depth; + lib_gate_t **gate; + double area; + double ip_load; + double max_load; + pin_phase_t phase; + delay_time_t block; + delay_time_t drive; + } sp_buffer_t; + +typedef struct sp_node_struct{ + int type; + union { + lib_gate_t *gate; + sp_buffer_t *buffer; + } impl; /* The implementation at this node */ + int cfi; /* The index of the most crit fanin */ + double load; /* The load that this buffer is driving */ + delay_time_t req_time; /* The req time we can achieve */ + delay_time_t prev_dr; /* Drive of the preceeding gate */ + pin_phase_t prev_ph; /* Phase of the preceeding gate */ + } sp_node_t; + +typedef struct global_buffer_param_struct buf_global_t; +struct global_buffer_param_struct { + /* Command line options */ + int trace; /* prints the changes in slack as algo proceeds */ + double thresh; /* Determins the critical paths */ + double crit_slack; /* Sets the absolute value for crit slack */ + int single_pass; /* Buffer only one node in the pass */ + int do_decomp; /* Decomposition of the root gate */ + int debug; /* Print debugging info */ + int limit; /* Only fanouts > limit are buffered */ + int mode; /* What transformations to allow */ + int only_check_max_load; /* */ + int interactive; /* == 1 when called from command line */ + /* Options specific to to the problem and library */ + sp_buffer_t **buf_array; /* Structure for the buffers available */ + lsList buffer_list; /* List of the buffers available */ + int num_buf; /* Number of non_inverting buffers */ + int num_inv; /* Number of inverters */ + double auto_route; /* The auto route factor */ + delay_model_t model; /* The delay model -- usually MAPPED */ + st_table *glbuftable; /* To store nodes buffered in a pass */ + double min_req_diff; /* The min diff to warrant an unbalanced decomp */ +}; + +/* + * Definitions of constants + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + */ +#define BUFFER_SLOT buf +#define BUFFER(node) ((sp_node_t *)(node->BUFFER_SLOT)) + +#define NONE 0 +#define BUF 1 +#define GATE 2 + +#define REPOWER_MASK ((int)(1<<0)) +#define UNBALANCED_MASK ((int)(1<<1)) +#define BALANCED_MASK ((int)(1<<2)) + +#define V_SMALL 0.000001 /* 1.0e-6 */ + +/* + * Some macros + */ +#define BUF_MAX_D(a) (MAX(a.rise,a.fall)) +#define BUF_MIN_D(a) (MIN(a.rise,a.fall)) +#define REQ_EQUAL(t1,t2) \ + ((ABS(((t1).rise)-((t2).rise)) < V_SMALL) && \ + (ABS(((t1).fall)-((t2).fall)) < V_SMALL)) + +#define REQ_IMPR(t1,t2) \ + (((((t1).rise - (t2).rise)) > V_SMALL) && \ + ((((t1).fall - (t2).fall)) > V_SMALL)) + +#define MIN_DELAY(result,t1,t2) \ + ((result).rise=MIN((t1).rise,(t2).rise), \ + (result).fall=MIN((t1).fall,(t2).fall)) +#define sp_drive_adjustment(dr,load,req) \ + ((req)->rise -= (dr).rise * load, \ + (req)->fall -= (dr).fall * load) + +#define buf_num_fanout(n) ((n) != NIL(node_t) ? node_num_fanout(n) : 0) +/* + * Functions internal to the buffering package + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + */ +extern char *sp_buffer_name(); +extern char *sp_name_of_impl(); +extern void speed_dump_buffer_list(); +extern void speed_free_buffer_list(); +extern void sp_buf_array_from_list(); + +extern int buf_critical(); +extern int sp_buffer_recur(); +extern int speed_buffer_node(); +extern int sp_satisfy_max_load(); +extern int sp_max_load_violation(); +extern int buf_compare_fanout(); +extern int buf_evaluate_trans2(); +extern int speed_buffer_network(); +extern int buf_failed_slack_test(); +extern int sp_replace_cell_strength(); +extern int speed_buffer_array_of_nodes(); +extern void buffer_free(); +extern void buffer_alloc(); +extern void set_buf_thresh(); +extern void buf_dump_fanout_data(); +extern void buf_set_buffers(); +extern void buf_free_buffers(); + +extern int sp_buf_get_crit_fanin(); +extern void sp_set_inverter(); +extern void sp_replace_lib_gate(); +extern void sp_buf_annotate_gate(); +extern void sp_implement_buffer_chain(); +extern lib_gate_t *buf_get_gate_version(); + +/* + * DELAY STUFF for the buffering algorithm --- need a better way out + */ + +extern void sp_compute(); +extern void sp_buf_req_time(); +extern void sp_subtract_delay(); +extern void sp_buf_compute_req_time(); +extern void buffer_init_globals(); +extern double sp_get_pin_load(); +extern delay_time_t sp_get_input_drive(); +extern void buffer_delay_get_pi_drive(); + + diff --git a/sis/speed/com_speed.c b/sis/speed/com_speed.c new file mode 100644 index 0000000..ec23c79 --- /dev/null +++ b/sis/speed/com_speed.c @@ -0,0 +1,961 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/com_speed.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include "buffer_int.h" +#include <math.h> + + +/* definitions that were part of the original com_gbx.c */ +int gbx_verbose_mode; +int print_bypass_mode; +int start_node_mode; /* Take bypass with 0 gain */ + +static array_t *current_speedup_alg; + +/* + * Set the defaults for the speedup routines --- assume unmapped + */ +speed_set_default_options(speed_param) +speed_global_t *speed_param; +{ + if (current_speedup_alg == NIL(array_t)){ + current_speedup_alg = sp_get_local_trans(0, NIL(char *)); + } + speed_param->local_trans = current_speedup_alg; + speed_param->area_reclaim = TRUE; + speed_param->trace = FALSE; + speed_param->debug = FALSE; + speed_param->add_inv = FALSE; + speed_param->del_crit_cubes = TRUE; /* Reduce delay at all cost */ + speed_param->num_tries = 1; + speed_param->thresh = DEFAULT_SPEED_THRESH; + speed_param->coeff = DEFAULT_SPEED_COEFF; + speed_param->dist = DEFAULT_SPEED_DIST; + speed_param->new_mode = 1; /* Use the new_speed code */ + speed_param->region_flag = ALONG_CRIT_PATH; + speed_param->transform_flag = BEST_BENEFIT; + speed_param->max_recur = 1; + speed_param->timeout = INFINITY; + speed_param->max_num_cuts = 50; + speed_param->red_removal = FALSE; + speed_param->objective = AREA_BASED; + speed_param->req_times_set = FALSE; + + /* + * By default do the script of varying distances + * loop till improvement at a given distance + */ + speed_param->do_script = TRUE; + speed_param->speed_repeat = TRUE; + speed_param->only_init_decomp = FALSE; + + /* Initialize the library delay data */ + speed_param->model = DELAY_MODEL_UNIT; + speed_param->pin_cap = 0.0; + speed_param->library_accl = 0; +} + +int +speed_fill_options(speed_param, argc, argv) +speed_global_t *speed_param; +int argc; +char **argv; +{ + int c; + double coeff; + int num_tries, flag, dist, level, num_cuts; + + speed_set_default_options(speed_param); + + if (argc == 0 || argv == NIL(char *)) return 0; + + while ((c = util_getopt(argc, argv, "a:d:l:m:s:w:t:C:D:I:ABRTcnfipvr")) != EOF) { + switch (c) { + case 'f': + speed_param->new_mode = FALSE; + break; + case 'p': + speed_param->add_inv = TRUE; + break; + case 'r': + speed_param->area_reclaim = FALSE; + break; + case 'c': + speed_param->speed_repeat = FALSE; + speed_param->do_script = FALSE; + break; + case 'i': + speed_param->only_init_decomp = TRUE; + speed_param->do_script = FALSE; + break; + case 'A': + speed_param->del_crit_cubes = FALSE; + break; + case 'B': + speed_param->transform_flag = BEST_BANG_FOR_BUCK; + break; + case 'I': + speed_param->timeout = atoi(util_optarg); + (void)fprintf(sisout, "INFO: optimization limit = %d seconds\n", + speed_param->timeout); + break; + case 'R': + speed_param->red_removal = TRUE; + break; + case 'n': + speed_param->objective = TRANSFORM_BASED; + break; + case 'T': + speed_param->trace = TRUE; + break; + case 'v': + speed_param->debug = TRUE; + break; + case 'D': + speed_param->debug = atoi(util_optarg); + if (speed_param->debug < 0) speed_param->debug = FALSE; + break; + case 's': + if (strcmp(util_optarg, "crit") == 0) { + speed_param->region_flag = ALONG_CRIT_PATH; + } else if (strcmp(util_optarg, "transitive") == 0){ + speed_param->region_flag = TRANSITIVE_FANIN; + } else if (strcmp(util_optarg, "compromise") == 0){ + speed_param->region_flag = COMPROMISE; + } else if (strcmp(util_optarg, "tree") == 0){ + speed_param->region_flag = ONLY_TREE; + } else { + (void)fprintf(sisout, "Illegal argument to the -s flag\n"); + return 1; + } + break; + case 'w': + coeff = atof(util_optarg); + if (coeff < 0) coeff = 0; + if (coeff > 1) coeff = 1; + speed_param->coeff = coeff; + break; + case 't': + speed_param->thresh = atof(util_optarg); + speed_param->do_script = FALSE; + break; + case 'a': + num_tries = atoi(util_optarg); + if (num_tries > 0) speed_param->num_tries = num_tries; + break; + case 'C': + num_cuts = atoi(util_optarg); + if (num_cuts > 0) speed_param->max_num_cuts = num_cuts; + break; + case 'l': + level = atoi(util_optarg); + if (level > 0) speed_param->max_recur = level; + break; + case 'd': + dist = atoi(util_optarg); + if (dist >= 0) speed_param->dist = dist; + speed_param->do_script = FALSE; + break; + case 'm': + speed_param->model = delay_get_model_from_name(util_optarg); + if (speed_param->model == DELAY_MODEL_LIBRARY){ + speed_param->model = DELAY_MODEL_MAPPED; + if (speed_param->interactive){ + (void)fprintf(sisout, "Using MAPPED model instead of LIBRARY\n"); + } + } else if (speed_param->model == DELAY_MODEL_UNKNOWN){ + (void)fprintf(siserr, "Unknown delay model %s\n", util_optarg); + return 1; + } + break; + default: + (void)fprintf(siserr, "ERROR: Unknown option\n"); + return 1; + } + } + return 0; +} + +static void +speed_print_usage() +{ + (void) fprintf(siserr, "usage: speed_up [-cinprvABIRT] [-a n] [-d n] [-w n] [-s method] [-t n.n] [-l n] [-D n] [-m model] [node-list]\n"); + (void)fprintf(siserr, "The options -s, -a, -l, -C are ignored when -f is specified\n"); + (void)fprintf(sisout, "********* General options **********\n"); + (void) fprintf(siserr, " -c\t\tOnly one pass of speed_up.\n"); + (void) fprintf(siserr, " -d\tn\tDistance for collapsing (default = 3).\n"); + (void) fprintf(siserr, " -f\t\tFast mode (heuristic weight computation).\n"); + (void) fprintf(siserr, " -i\t\tOnly do the initial 2_input NAND decomp.\n"); + (void) fprintf(siserr, " -v\t\tVerbose option (same as -D 1).\n"); + (void) fprintf(siserr, " -p\t\tUse explicit inverters (EXPERIMENTAL).\n"); + (void) fprintf(siserr, " -r\t\tDo not try to reclaim area (EXPERIMENTAL).\n"); + (void) fprintf(siserr, " -A\t\tArea saving option: Do not delete critical cubes of divisors.\n"); + (void) fprintf(siserr, " -R\t\tRun redundancy removal after each successful iteration.\n"); + (void) fprintf(siserr, " -D\tn\tSet the debugging level.\n"); + (void) fprintf(siserr, " -m\tmodel\tDelay model (default \"unit-fanout\").\n"); + (void) fprintf(siserr, " -T\t\tPrint the delays as the speed_up proceeds.\n"); + (void)fprintf(sisout, "********* Options for fast mode, -f **********\n"); + (void) fprintf(siserr, " -t\tn.n\tCritical threshold.\n"); + (void) fprintf(siserr, " -a\tn\tNumber of decomposition attempts (default = 1).\n"); + (void) fprintf(siserr, " -w\tn\tRelative weight of area (default = 0).\n"); + (void)fprintf(sisout, "********* Options for new mode **********\n"); + (void) fprintf(siserr, " -n\t\tChoose the fewest number of transformations\n"); + (void) fprintf(siserr, " -B\t\tUse Benefit/cost as goodness of transform.\n"); + (void) fprintf(siserr, " -I\tn\tTimeout limit for each optimization in seconds(default = INFINITY).\n"); + (void) fprintf(siserr, " -l\tn\t Set the number of recursion levels (default = 1).\n"); + (void) fprintf(siserr, " -s\tmethod\tMethod for selecting the region to transform.\n"); + (void) fprintf(siserr, "\t one of \"crit\"(default), \"transitive\", \"compromise\", \"tree\"\n"); + (void) fprintf(siserr, " -C\tn\t Set the number of cutsets to generate (default = 50).\n"); +} + +/* + * Routine that calls the local transformation code for reducing the depth + * of Boolean networks. + */ +int +com_speed_up(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i; + char *name, *new_name; + double latest, new_latest, area, new_area; + node_t *np; + array_t *nodevec; + speed_global_t speed_param; + + util_getopt_reset(); + error_init(); + + speed_param.interactive = TRUE; + if (speed_fill_options(&speed_param, argc, argv)){ + (void)fprintf(sisout,"%s", error_string()); + speed_print_usage(); + return 1; + } + + /* First check if the network is a valid one */ + if (network_num_pi(*network) == 0) { + /* Nothing needs to be done !!! --- there are only constants !!!*/ + return 0; + } + nodevec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + if (array_n(nodevec) == 0){ + array_free(nodevec); + return 0; + } + + /* If mapped model - make sure library is present */ + if (speed_param.model == DELAY_MODEL_MAPPED && + (lib_get_library() == NIL(library_t))){ + (void) fprintf(sisout, "Need to define a library\n"); + array_free(nodevec); + return 1; + } + /* Just warn of the potential of unmapping a mapped network */ + if (lib_network_is_mapped(*network) && + speed_param.model != DELAY_MODEL_MAPPED){ + (void)fprintf(sisout, "WARNING: Mapped network will be decomposed into 2-input gates\n"); + } + /* Initialize the globals for the delay routines in this package */ + speed_set_delay_data(&speed_param, 0 /* No library acceleration */); + speed_param.req_times_set = sp_po_req_times_set(*network); + + /* If a list of nodes is present - decomp only those */ + if (argc - util_optind != 0) { + for (i = 0; i < array_n(nodevec); i++) { + np = array_fetch(node_t *, nodevec, i); + if (np->type == INTERNAL) { + speed_up_node(*network, np, &speed_param, 0 /* delay values */); + } + } + } else if (speed_param.do_script){ + if (speed_init_decomp(*network, &speed_param) ){ + return 1; + } + speed_up_script(network, &speed_param); + } else if (speed_param.only_init_decomp) { + if (speed_init_decomp(*network, &speed_param) ){ + return 1; + } + } else if (speed_param.speed_repeat) { + if (speed_init_decomp(*network, &speed_param) ){ + return 1; + } + speed_up_loop(network, &speed_param); + } else { + if (speed_init_decomp(*network, &speed_param) ){ + return 1; + } + if (delay_trace(*network, speed_param.model) ){ + SP_GET_PERFORMANCE(&speed_param, *network, np, latest, name, area); + } + if (speed_param.new_mode){ + new_speed(*network, &speed_param); + } else{ + speed_up_network(*network, &speed_param); + } + if (delay_trace(*network, speed_param.model) ){ + SP_GET_PERFORMANCE(&speed_param, *network, np, new_latest, + new_name, new_area); + } + SP_PRINT(&speed_param, latest, new_latest, area, new_area, + name, new_name); + FREE(name); + FREE(new_name); + } + + array_free(nodevec); + return 0; +} + +/* + * Given the list of nodes, the routine will collapse the specified + * distance of fanins along the critical path (specified by "-t") + */ +int +com__part_collapse(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int i; + node_t *node; + array_t *nodevec; + speed_global_t speed_param; + + util_getopt_reset(); + error_init(); + + speed_param.interactive = TRUE; + if (speed_fill_options(&speed_param, argc, argv)){ + (void)fprintf(sisout,"%s", error_string()); + goto part_collapse_usage; + } + /* Initialize the globals for the delay routines in this package */ + speed_set_delay_data(&speed_param, 0 /* No library acceleration */); + + if (argc - util_optind != 0) { + if (!delay_trace(*network, speed_param.model)){ + (void)fprintf(sisout,"%s\n", error_string()); + return 1; + } + set_speed_thresh(*network, &speed_param); + nodevec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + for(i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + speed_absorb(node, &speed_param); + } + array_free(nodevec); + } + return 0; + +part_collapse_usage: + (void) fprintf(siserr, "usage: _part_collapse [-m model] [-d n] [-t n.n] list-of-nodes\n"); + (void) fprintf(siserr, " -d\tn\tDistance for collapsing.\n"); + (void) fprintf(siserr, " -t\tn.n\tCritical threshold.\n"); + (void) fprintf(siserr, " -m\tmodel\tDelay model. default (\"unit-fanout\").\n"); + return 1; +} + + +/* + * This routine reports the most favorable cutset found + */ +int +com__print_cutset(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + array_t *mincut; + speed_global_t speed_param; + st_table *table; + + util_getopt_reset(); + error_init(); + + speed_param.interactive = TRUE; + if (speed_fill_options(&speed_param, argc, argv)){ + (void)fprintf(sisout,"%s", error_string()); + goto print_cutset_usage; + } + + /* + * do a delay trace and set the critical slack + */ + if (!delay_trace(*network, speed_param.model)){ + (void)fprintf(sisout,"%s\n", error_string()); + return 1; + } + set_speed_thresh(*network, &speed_param); + table = speed_compute_weight(*network, &speed_param, NIL(array_t)); + + /* compute the minimum weighted cutset of the critical paths */ + (void) com_execute(network, "_maxflow"); + mincut = cutset(*network, table); + array_free(mincut); + (void) com_execute(network, "_maxflow"); + + st_free_table(table); + return 0; + +print_cutset_usage: + (void) fprintf(siserr, "usage: _print_cutset [-t n.n] [-d n] [-w n] [-m model]\n"); + (void) fprintf(siserr, " -d\tn\tDistance for collapsing.\n"); + (void) fprintf(siserr, " -w\tn\tRelative weight of area.\n"); + (void) fprintf(siserr, " -t\tn.n\tCritical threshold.\n"); + (void) fprintf(siserr, " -m\tmodel\tDelay model. default (\"unit-fanout\").\n"); + return 1; +} + + +/* + * Routine to check the weight computation + */ +int +com__print_weight(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + st_table *table; + array_t *nodevec; + speed_global_t speed_param; + + util_getopt_reset(); + error_init(); + + speed_param.interactive = TRUE; + if (speed_fill_options(&speed_param, argc, argv)){ + (void)fprintf(sisout,"%s", error_string()); + goto print_weight_usage; + } + + nodevec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + + if (array_n(nodevec) > 0){ + if (!delay_trace(*network, speed_param.model)){ + (void)fprintf(sisout,"%s\n", error_string()); + return 1; + } + set_speed_thresh(*network, &speed_param); + table = speed_compute_weight(*network, &speed_param, nodevec); + st_free_table (table); + } + + array_free(nodevec); + return 0; + +print_weight_usage: + (void) fprintf(siserr, "usage: print_weight [-m model] [-w n.n] [-d n] [-t n.n] list-of-nodes\n"); + (void) fprintf(siserr, " -d\tn\tDistance for collapsing.\n"); + (void) fprintf(siserr, " -t\tn.n\tCritical threshold.\n"); + (void) fprintf(siserr, " -w\tn\tRelative weight of area. \n"); + (void) fprintf(siserr, " -m\tmodel\tDelay model. default (\"unit-fanout\").\n"); + return 1; +} + +/* Routine to check the internal delay tracing of the speedup routines */ +int +com__speed_delay(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + + lsGen gen; + node_t *node; + delay_time_t time; + speed_global_t speed_param; + + util_getopt_reset(); + error_init(); + + speed_param.interactive = TRUE; + if (speed_fill_options(&speed_param, argc, argv)){ + (void)fprintf(sisout,"%s", error_string()); + (void) fprintf(sisout,"Usage: _speed_delay [-m model]\n"); + return 1; + } + + /* Initialize the globals for the delay routines in this package */ + speed_set_delay_data(&speed_param, 0 /* No library acceleration */); + + (void) speed_delay_trace(*network, &speed_param); + foreach_node(*network, gen, node){ + speed_delay_arrival_time(node, &speed_param, &time); + (void) fprintf(sisout," %-10s : arrival=(%-5.2f %5.2f)\n", + node_name(node), time.rise, time.fall); + } + return 0; +} + +int +com__report_delay_data(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + delay_model_t model; + + error_init(); + util_getopt_reset(); + model = DELAY_MODEL_UNKNOWN; + while ((c = util_getopt(argc, argv, "m:")) != EOF) { + switch (c) { + case 'm': + model = delay_get_model_from_name(util_optarg); + if (model == DELAY_MODEL_UNKNOWN){ + (void) fprintf(sisout,"Usage: _report_delay_data [-m model]\n"); + return 1; + } + break; + default: + (void) fprintf(sisout,"Usage: _report_delay_data [-m model]\n"); + return 1; + } + } + if (model == DELAY_MODEL_UNKNOWN){ + if (lib_network_is_mapped(*network)){ + model = DELAY_MODEL_LIBRARY; + } else { + model = DELAY_MODEL_UNIT; + } + } + + if (delay_trace(*network, model)){ + sp_print_delay_data(sisout, *network); + } else { + (void) fprintf(sisout,"%s\n", error_string()); + } + return 0; +} + + +static int +com_speedup_alg(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int no_options = 0; + int verbose = 0; + + if (current_speedup_alg == NIL(array_t)) { + current_speedup_alg = sp_get_local_trans(0, NIL(char *)); + } + argc--; argv++; + if (argc == 0) no_options = 1; + while (argc > 0 && argv[0][0] == '-') { + switch (argv[0][1]) { + case 'v': + verbose = 1; + break; + default: + goto usage; + } + argc--; + argv++; + } + if (! no_options) { + current_speedup_alg = sp_get_local_trans(argc, argv); + } + if (verbose || no_options) sp_print_local_trans(current_speedup_alg); + return 0; +usage: + fprintf(siserr, "usage: speedup_alg [-v] speedup_alg1 speedup_alg2 ...\n"); + fprintf(siserr, " -v\t verbose mode\n"); + return 1; +} + + +/* Routine to print the nodes in the network according to level */ +int +com_print_level(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + double thresh; + delay_model_t model; + int c, crit_only, print_flag, level; + array_t *node_array; + + print_flag = TRUE; + crit_only = FALSE; + model = DELAY_MODEL_UNIT_FANOUT; + thresh = 0.5; + + util_getopt_reset(); + error_init(); + while ((c = util_getopt(argc, argv, "m:t:lc")) != EOF) { + switch (c) { + case 'm': + model = delay_get_model_from_name(util_optarg); + if (model == DELAY_MODEL_LIBRARY) { + (void)fprintf(sisout,"Notice: Using the mapped model instead\n"); + model = DELAY_MODEL_MAPPED; + } else if (model == DELAY_MODEL_UNKNOWN) { + (void) fprintf(sisout,"Unknown delay model \n"); + goto print_level_usage; + } + break; + case 't': + thresh = atof(util_optarg); + break; + case 'l': + print_flag = FALSE; + break; + case 'c': + crit_only = TRUE; + break; + default: + goto print_level_usage; + } + } + + + print_flag = (crit_only ? TRUE : print_flag); + /* + * Do the delay trace if the critical path needs to be printed + */ + if (crit_only){ + if(!delay_trace(*network, model)){ + (void) fprintf(sisout,"%s\n", error_string()); + return 1; + } + } + + node_array = NIL(array_t); + if (argc - util_optind != 0) { + node_array = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + } + + level = speed_print_level(*network, node_array, thresh, crit_only, + print_flag); + + if (!print_flag){ + (void) fprintf(sisout, "Total number of levels = %d\n", level); + } + if (node_array != NIL(array_t)) array_free(node_array); + + return 0; +print_level_usage: + (void) fprintf(sisout,"Usage: print_level [-m model] [-t thresh] [-l] [-c] [node_list]\n"); + (void) fprintf(sisout, " -l\t\tPrint only a summary.\n"); + (void) fprintf(sisout, " -c\t\tPrint only critical nodes.\n"); + (void)fprintf(sisout,"\t-m \tmodel\t: model for computing delays - default \"unit_fanout\"\n"); + (void)fprintf(sisout,"\t-t \t#.#\t: Threshold defining critical paths\n"); + (void)fprintf(sisout,"\tnode-list\t: Print nodes in transitive-fanin of list.\n"); + return 1; + +} +/* ARGSUSED */ +/* Utility routine that reports whether the network is in 2-input AND form */ +int +com__is_2ip_and(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + node_t *node; + lsGen gen; + + foreach_node(*network, gen, node) { + if ((node_num_fanin(node) <= 2) && ((node_function(node) != NODE_OR) && + (node_function(node) != NODE_COMPLEX))){ + continue; + } + (void) fprintf(sisout,"Network is NOT in 2 input and gates\n"); + return; + } + (void) fprintf(sisout,"Network is in 2 input and gates\n"); +} + + +/* + * Utility routine that prints the specified number of high fanout nodes on + * critical paths + */ +int +com__print_fanout(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, limit, max, print_max_only; + double thresh; + delay_time_t delay; + delay_model_t model; + node_t *node; + lsGen gen; + + limit = 5; + max = -1; + thresh = 0.5; + print_max_only = FALSE; + model = DELAY_MODEL_MAPPED; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "sn:t:m:")) != EOF) { + switch (c) { + case 'm': + model = delay_get_model_from_name(util_optarg); + if (model == DELAY_MODEL_LIBRARY) { + (void)fprintf(sisout,"Notice: Using the mapped model instead\n"); + model = DELAY_MODEL_MAPPED; + } else if (model == DELAY_MODEL_UNKNOWN) { + (void) fprintf(sisout,"Unknown delay model \n"); + goto print_fanout_usage; + } + break; + case 's': + print_max_only = TRUE; + break; + case 't': + thresh = atof(util_optarg); + break; + case 'n': + limit = atoi(util_optarg); + break; + default: + goto print_fanout_usage; + } + } + + if (!delay_trace(*network, model)){ + (void)fprintf(sisout,"%s\n", error_string()); + return 1; + } + + if (!print_max_only){ + (void)fprintf(sisout, "Nodes with fanout >= %d\n", limit); + (void)fprintf(sisout,"type node fo slack\n"); + } + foreach_node(*network, gen, node){ + if (node->type != PRIMARY_OUTPUT){ + delay = delay_slack_time(node); + if (!print_max_only){ + if(node_num_fanout(node) > limit){ + (void)fprintf(sisout,"%s %-10s %-3d %-5.2f\n", + (node->type == INTERNAL ?"INT" : "PI "), + node_name(node), node_num_fanout(node), delay.rise ); + } + } else { + if (delay.rise < thresh || delay.fall < thresh){ + max = MAX(max, node_num_fanout(node)); + } + } + } + } + if (print_max_only){ + (void)fprintf(sisout, "Maximum fanout on crit path = %d\n", max); + } + return 0; +print_fanout_usage: + (void)fprintf(sisout,"Usage: print_fanout [-s] [-t #.#] [-n #]\n"); + (void)fprintf(sisout,"\t-s \t\t: Print maximum slack on critical path \n"); + (void)fprintf(sisout,"\t-m \tmodel\t: Delay model to find critical path \n"); + (void)fprintf(sisout,"\t-t \t#.#\t: Threshold of slack defining critical path\n"); + (void)fprintf(sisout,"\t-n \t#\t: Print nodes with fanout greater than n\n"); + return 1; +} + + +/* + * Set the defaults that are controllable from the command line ---- + * The rest are controlled/set by the state of the network and library + * and the relevant routine there is buf_set_buffers() +*/ +buf_set_default_options(buf_param) +buf_global_t *buf_param; +{ + buf_param->trace = FALSE; + buf_param->single_pass = FALSE; + buf_param->do_decomp = FALSE; + buf_param->debug = FALSE; + buf_param->limit = 2; + buf_param->mode = 7; /* Try all the transformations */ + buf_param->thresh = 2 * V_SMALL; + buf_param->only_check_max_load = FALSE; + buf_param->interactive = FALSE; +} + +int +buffer_fill_options(buf_param, argc, argv) +buf_global_t *buf_param; +int argc; +char **argv; +{ + int c; + + buf_set_default_options(buf_param); + if (argc == 0 || argv == NIL(char *)) return 0; + + while ((c = util_getopt(argc, argv, "cdLTDf:v:l:")) != EOF) { + switch (c) { + case 'd': + buf_param->do_decomp = TRUE; + break; + case 'c': + buf_param->single_pass = TRUE; + break; + case 'L': + buf_param->only_check_max_load = TRUE; + break; + case 'T': + buf_param->trace = TRUE; + break; + case 'f': + buf_param->mode = atoi(util_optarg); + + /* Check the range of buffering modes (1-7) */ + if (buf_param->mode < 1 || buf_param->mode > 7){ + error_append("ERROR: Valid range of -f option is 1 to 7\n"); + return 1; + } + break; + case 'v': + buf_param->debug = atoi(util_optarg); + break; + case 'l': + buf_param->limit = atoi(util_optarg); + break; + case 'D': + buf_param->debug = TRUE; + break; + default: + error_append("buffering: Unknown option\n"); + return 1; + } + } + return 0; +} + +buffer_print_usage() +{ + (void)fprintf(sisout,"Usage: buffer_opt [-l #] [-cdTDL] [-f #] [-v #] [node_list]\n"); + (void)fprintf(sisout,"\t-l \t#\t: Fanout limit (default = 2)\n"); + (void)fprintf(sisout,"\t-c \t\t: Buffer only one node in the pass\n"); + (void)fprintf(sisout,"\t-d \t\t: Docompose complex gates as part of buffering\n"); + (void)fprintf(sisout,"\t-T \t\t: Print the delay as algorithm proceeds\n"); + (void)fprintf(sisout,"\t-L \t\t: Only satisfy the max_load constraints\n"); + (void)fprintf(sisout,"\t-D \t\t: Debugging option\n"); + (void)fprintf(sisout,"\t-f \t#\t: Fanout transformations to use (default = 7)\n"); + (void)fprintf(sisout,"\t-v \t#\t: Verbosity level (1-100)\n"); +} + + +int +com_buffer_opt(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + lsGen gen; + node_t *node; + array_t *nodevec; + buf_global_t buf_param; + st_table *drive_table, *load_table; + + util_getopt_reset(); + error_init(); + + /* Set the flag for the interactive mode --- printing warnings enabled */ + buf_param.interactive = TRUE; + if (buffer_fill_options(&buf_param, argc, argv)){ + (void)fprintf(sisout,"%s", error_string()); + buffer_print_usage(); + return 1; + } + + /* First check if the network is a valid one */ + nodevec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + if (array_n(nodevec) == 0 ){ + array_free(nodevec); + return 0; + } + + /* Set the buffers based on whether the network is mapped or not */ + buf_set_buffers(*network, 0, &buf_param); + + /* + * Set the loads at PO's and input drive at PI's if not set + * These values are derived from the inverters if the network is mapped + */ + buf_set_pipo_defaults(*network, &buf_param, &load_table, &drive_table); + + /* Annotate the delay data */ + if (!delay_trace(*network, buf_param.model)){ + (void)fprintf(sisout,"%s\n", error_string()); + return 1; + } + + if (argc > util_optind) { + /* Buffer the output of specified nodes only */ + (void)speed_buffer_array_of_nodes(*network, &buf_param, nodevec); + } else if (buf_param.only_check_max_load){ + (void) sp_satisfy_max_load(*network, &buf_param); + } else { + (void)speed_buffer_network(*network, &buf_param); + } + + /* Reset the drive and loads of the Primary IP/OP respectively */ + foreach_primary_output(*network, gen, node){ + if (st_is_member(load_table, (char *)node)){ + delay_set_parameter(node, DELAY_OUTPUT_LOAD, DELAY_NOT_SET); + } + } + foreach_primary_input(*network, gen, node){ + if (st_is_member(drive_table, (char *)node)){ + delay_set_parameter(node, DELAY_DRIVE_RISE, DELAY_NOT_SET); + delay_set_parameter(node, DELAY_DRIVE_FALL, DELAY_NOT_SET); + } + } + + st_free_table(drive_table); + st_free_table(load_table); + buf_free_buffers(&buf_param); + array_free(nodevec); + + return 0; +} + +init_speed() +{ + current_speedup_alg = NIL(array_t); + + (void) com_add_command("speed_up", com_speed_up, 1); + (void) com_add_command("speedup_alg", com_speedup_alg, 0); + (void) com_add_command("buffer_opt", com_buffer_opt, 1); + (void) com_add_command("print_level", com_print_level, 0); + (void) com_add_command("_print_fanout", com__print_fanout, 0); + (void) com_add_command("_report_delay_data", com__report_delay_data, 0); + (void) com_add_command("_part_collapse", com__part_collapse, 1); + (void) com_add_command("_print_cutset", com__print_cutset, 0); + (void) com_add_command("_print_weight", com__print_weight, 0); + (void) com_add_command("_speed_delay", com__speed_delay, 0); + (void) com_add_command("_is_2ip_and", com__is_2ip_and, 0); + + if (com_graphics_enabled()) { + com_add_command("_speed_plot", com__speed_plot, 0); + } + + node_register_daemon(DAEMON_ALLOC, buffer_alloc); + node_register_daemon(DAEMON_FREE, buffer_free); +} + +end_speed() +{ + sp_free_local_trans(¤t_speedup_alg); +} diff --git a/sis/speed/gbx.c b/sis/speed/gbx.c new file mode 100644 index 0000000..c9458ee --- /dev/null +++ b/sis/speed/gbx.c @@ -0,0 +1,1645 @@ +/* + * Revision Control Information + * + * $Source: + * $Author: + * $Revision: + * $Date: + * + */ +/* + * The routines used for the Generalized Bypass Transformation. + * Original code by Patrick McGeer, + * Extensively modified/fixed by Heather Harkness + * Modified to use the "list" package instead of the files mylist.[ch] by + * Kanwar Jit Singh + */ + +#include "sis.h" +#include "speed_int.h" +#include "gbx_int.h" + +#define GBX_MAXWEIGHT 0x7ffffffe + +st_table *bypass_table; +st_table *gbx_node_table; +lsList bypasses; +delay_model_t gbx_delay_model; +void new_trace_bypass(); +void newer_trace_bypass(); +void extend_bypass(); + +#define foreach_list_item(list,gen,item) \ + for((gen) = lsStart((list)); \ + (lsNext((gen),(lsGeneric *)&(item),LS_NH) == LS_OK ? 1 : \ + (lsFinish((gen)),0)) ; ) + +node_t * +node_my_dup(node) +node_t *node; +{ + node_t *new_node; + + new_node = node_dup(node); + FREE(new_node->name); + new_node->name = NIL(char); + return new_node; +} + +node_t * +replace_fanin(node, fanin, replacement_fanin) +node_t *node, *fanin, *replacement_fanin; +{ + node_t *p, *q, *r; + node_t *lit0, *lit1, *tmp0, *tmp1, *tmp2; + node_t *result; + + if(node_get_fanin_index(node, fanin) == -1) return node_dup(node); + + node_algebraic_cofactor(node, fanin, &p, &q, &r); + if(node_function(p) == NODE_0) { + lit0 = node_literal(replacement_fanin, 0); + tmp0 = node_and(q, lit0); + result = node_or(tmp0, r); + node_free(lit0); node_free(tmp0); + } else if (node_function(q) == NODE_0) { + lit1 = node_literal(replacement_fanin, 1); + tmp1 = node_and(p, lit1); + result = node_or(tmp1, r); + node_free(lit1); node_free(tmp1); + } else { + lit1 = node_literal(replacement_fanin, 1); + tmp1 = node_and(p, lit1); + lit0 = node_literal(replacement_fanin, 0); + tmp0 = node_and(q, lit0); + tmp2 = node_or(tmp0, tmp1); + node_free(lit1); node_free(tmp1); + node_free(lit0); node_free(tmp0); + result = node_or(tmp2, r); node_free(tmp2); + } + node_free(p); node_free(q); node_free(r); + return result; +} + +node_t * +add_opt_boolean_diff(innode, network, model) +node_t *innode; +network_t *network; +delay_model_t model; +{ + network_t *network_tmp; + speed_global_t speed_param; + int i, j; + array_t *nodevec; + node_t *node, *newnode, *fanin, *orig, *last_node; + + /* convert node to temporary network */ + network_tmp = network_create_from_node(innode); + + /* optimize the boolean diff network for delay */ + speed_fill_options(&speed_param, 0, NIL(char *)); + speed_param.model = model; + speed_init_decomp(network_tmp, &speed_param); + + /* add optimized boolean diff to existing network */ + nodevec = network_dfs(network_tmp); + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type != INTERNAL) continue; + newnode = node_dup(node); + node->copy = newnode; + + /* Change the fanin pointers */ + foreach_fanin(newnode, j, fanin){ + if (fanin->type == PRIMARY_INPUT) { + /* patch the fanin to original */ + if ((orig = name_to_node(innode, node_long_name(fanin))) != NIL(node_t)){ + newnode->fanin[j] = orig; + } + else { + fail("Failed to retrieve the original node"); + } + } + else { + /* update the fanin pointer */ + newnode->fanin[j] = fanin->copy; + } + } + network_add_node(network, newnode); + last_node = newnode; + } + + array_free(nodevec); + network_free(network_tmp); + + assert(network_check(network)); + return last_node; +} + +int +take_bypass(bypass, network, model, mux_delay, actual_mux_delay) +bypass_t *bypass; +network_t *network; +delay_model_t model; +double mux_delay, actual_mux_delay; +{ + node_t *last_node, *node, *fanout, *fanin, *tmp, *tmp1, *tmp2; + node_t *diff, *tmp3, *tmp4, *tmp5, *mux, *p, *q, *r, *dup_node; + node_t *pathfan, *sub_node, *newdiff; + int phase; + lsGeneric dummy; + lsList dup_nodes; + lsGen gen, gen1, gen2; + int j; + int nfanins; + network_t *saved_net; + + /* Check that all nodes in the bypass are still in the network + before attempting bypass. If not, then punt. + This is required because bypasses might overlap, and some + bypass nodes may have been removed by network_sweep when a + previous bypass was taken. */ + + if (node_network(bypass->first_node) != network) + return 0; + foreach_list_item(bypass->bypassed_nodes, gen, node) { + if (node_network(node) != network) + return 0; + } + +/* if ((mux_delay == 1) && (actual_mux_delay > 1)) { + saved_net = network_dup(network); + } +*/ + + if (print_bypass_mode) { + printf("Taking Bypass\n"); + print_bypass(bypass); + } + + /* Form the Boolean difference as a big AND gate */ + + last_node = bypass->first_node; + diff = node_constant(1); + last_node = bypass->first_node; + foreach_list_item(bypass->bypassed_nodes, gen, node) { + node_algebraic_cofactor(node, last_node, &p, &q, &r); + tmp = node_xor(p, q); + tmp3 = node_not(r); + tmp1 = node_and(tmp, tmp3); + tmp2 = node_and(diff, tmp1); + node_free(diff); node_free(tmp); node_free(tmp1); node_free(tmp3); + diff = tmp2; + last_node = node; + } + + if (node_num_fanin(diff) <= 2) { + newdiff = diff; + network_add_node(network, newdiff); + } + else newdiff = add_opt_boolean_diff(diff, network, model); + assert(network_check(network)); + + /* Form the multiplexer. Yes, this really and truly is what it takes + to write a = b c + b'd in MIS, strange but true*/ + + phase = (bypass->phase == POS_UNATE?1:0); + tmp = node_literal(bypass->first_node, phase); + tmp1 = node_literal(newdiff, 1); tmp2 = node_and(tmp, tmp1); + tmp3 = node_literal(bypass->last_node, 1); tmp4 = node_literal(newdiff, 0); + tmp5 = node_and(tmp3, tmp4); mux = node_or(tmp5, tmp2); + node_free(tmp); node_free(tmp1); node_free(tmp2); node_free(tmp3); + node_free(tmp4); node_free(tmp5); + + /* Make sure the MUX is in the network */ + + network_add_node(network, mux); + + + /* KMS the bypassed path. First duplicate all the nodes upto + bypass->dupe_at, if needed, in preparation for the KMS Transform after + the bypass. + Can't rely on dupe_at value set when bypass was found because subsequent + taken bypasses may have created additional fanouts. So check for fanouts + again. */ + + foreach_list_item(bypass->bypassed_nodes, gen, node) { + if (node_num_fanout(node) > 1) + bypass->dupe_at = node; + } + + if(bypass->dupe_at != NIL(node_t)) { + dup_nodes = lsCreate(); + + /* Make a list of all the nodes we'll duplicate, and add each dup'd + node to the network. Note in particular that node will now + fanout to both the fanout of the original node and to the dup of + the fanout of the original node. */ + + foreach_list_item(bypass->bypassed_nodes, gen, node) { + dup_node = node_my_dup(node); + lsNewEnd(dup_nodes, (lsGeneric)dup_node, LS_NH); + network_add_node(network, dup_node); + assert(network_check(network)); + } + + /* Walk down the list of nodes, substituting the dup node for the + original on the bypass */ + + gen1 = lsStart(dup_nodes); + gen = lsStart(bypass->bypassed_nodes); + + /* Walk the list, doing the substitution */ + + (void)lsNext(gen1, (lsGeneric *)&dup_node, LS_NH); + do { + (void)lsNext(gen, (lsGeneric *)&node, LS_NH); + if (lsNext(gen1, (lsGeneric *) &pathfan, LS_NH) != LS_OK) { + pathfan = mux; + } + + /* Substitute dup_node for node in path_fan */ + node_patch_fanin(pathfan, node, dup_node); + + assert(network_check(network)); + + dup_node = pathfan; + } while (pathfan != mux); + lsFinish(gen); lsFinish(gen1); + + /* Now that we've duplicated the bypassed nodes, substitute the + path of duplicated nodes for the bypassed path (this is the + path of nodes that has been genuinely bypassed, now). This is + important since (below) we're going to stick the constant on the + first node of the bypassed path, so we want to make sure we + get the right bypassed path, here. Note we don't change + bypass->last_node, since we want to patch the fanouts of this + node to be fanned into by the mux, below */ + + lsDestroy(bypass->bypassed_nodes, (void (*)())0); + bypass->bypassed_nodes = dup_nodes; + } + + /* Substitute the multiplexer into the network. Important to do this + AFTER we've dup'd off the bypassed path. */ + + if (!network_check(network)) { + printf("%s\n", error_string()); + } + + foreach_fanout(bypass->last_node, gen2, fanout) { + if(fanout == mux) continue; + node_patch_fanin(fanout, bypass->last_node, mux); + assert(network_check(network)); + } + + /* OK. Now that we've walked the list, duplicated as needed, we can + stick the stuck-at-fault. Do it to eliminate (if possible) the + first bypassed node. All this code is really just an intelligent + selection of which fault to stick */ + + gen = lsStart(bypass->bypassed_nodes); + (void)lsNext(gen, (lsGeneric *)&node, LS_NH); + node_algebraic_cofactor(node, bypass->first_node, &p, &q, &r); + + /* First try to set node to 1 */ + if(node_function(p) == NODE_1) sub_node = node_constant(1); + else if(node_function(q) == NODE_1) sub_node = node_constant(0); + + /* If that doesn't work, see if we can eliminate all cubes containing + bypass->first_node from node */ + else if(node_function(p) == NODE_0) sub_node = node_constant(1); + else if(node_function(q) == NODE_0) sub_node = node_constant(0); + + else sub_node = node_constant(1); /* Grrr. Gotta do something */ + + /* stick the constant in in place of bypass->first_node, and replace + bypass->first_node in the network, then clean up */ + + network_add_node(network, sub_node); + node_patch_fanin(node, bypass->first_node, sub_node); + node_free(p); node_free(q); node_free(r); + network_sweep(network); + + /* If the actual mux delay is 2 and we're looking for last gasp bypasses + with mux delay of 1, reject any bypasses which result in larger delay */ + if ((mux->network == network) && (mux_delay == 1) && (actual_mux_delay > 1)) { + nfanins = 0; + foreach_fanin(mux, j, fanin){ + if (fanin->network == network) + nfanins++; + } + if (nfanins > 2) { + if (gbx_verbose_mode) + printf("Mux has more than 2 inputs\n"); +/* network_free(network); + network = network_dup(saved_net); + network_free(saved_net); + if (print_bypass_mode) printf("Bypass rejected\n"); + return 0; +*/ + } +/* else network_free(saved_net); */ + } + + return 1; +} + +bypass_t * +bypass_copy(bypass) +bypass_t *bypass; +{ + bypass_t *result; + + SAFE_ALLOC(result, bypass_t, 1); + *result = *bypass; + result->bypassed_nodes = lsCopy(bypass->bypassed_nodes, (lsGeneric(*)()) 0); + return result; +} + + +bypass_t * +new_bypass(node, fanout, weight, slack, phase) +node_t *fanout, *node; +double weight, slack; +input_phase_t phase; +{ + bypass_t *result; + node_t *fanin; + delay_time_t artime; + int i; + + SAFE_ALLOC(result, bypass_t, 1); + result->first_node = node; + result->last_node = fanout; + result->gain = weight; + result->dupe_at = NIL(node_t); + result->bypassed_nodes = lsCreate(); + result->phase = phase; + result->slack = slack; + result->side_slack = slack; + artime = delay_arrival_time(node); + result->side_delay = 0.0; + result->control_delay = max(artime.rise, artime.fall); + foreach_fanin(fanout, i, fanin) { + if(fanin == node) continue; + artime = delay_arrival_time(fanin); + if(max(artime.rise, artime.fall) > result->side_delay) { + result->side_delay = max(artime.rise, artime.fall); + } + } + (void)lsNewEnd(result->bypassed_nodes, (lsGeneric)fanout, LS_NH); + return result; +} +bypass_t * +bypass_dup(bypass) +bypass_t *bypass; +{ + bypass_t *result; + SAFE_ALLOC(result, bypass_t, 1); + *result = *bypass; + result->bypassed_nodes = lsCopy(bypass->bypassed_nodes, (lsGeneric(*)())0); + return result; +} +void +free_bypass(bypass) +bypass_t *bypass; +{ + lsDestroy(bypass->bypassed_nodes, (void(*)())0); + FREE(bypass); +} +int +bypass_is_extensible(bypass, fanout, node, weight) +node_t *fanout, *node; +bypass_t *bypass; +double weight; +{ + node_t *fanin; + int i; + delay_time_t artime, cartime; + double control_delay, side_delay, side_slack; + + if(node_function(fanout) == NODE_PO) { + return 0; + } + + side_delay = 0; + foreach_fanin(fanout, i, fanin) { + if (fanin == node) { + cartime = delay_arrival_time(fanin); + control_delay = max(cartime.rise, cartime.fall); + } + else { + artime = delay_arrival_time(fanin); + side_delay = max(side_delay, max(artime.rise, artime.fall)); + } + } + side_slack = min(bypass->side_slack, control_delay - side_delay); + + if (bypass->gain + weight <= side_slack) + return 1; + else return 0; +} +void +bypass_add_node(bypass, fanout, node, weight, phase) +node_t *fanout, *node; +bypass_t *bypass; +double weight; +input_phase_t phase; +{ + node_bp_t *record; + + bypass->last_node = fanout; + lsNewEnd(bypass->bypassed_nodes, (lsGeneric)fanout, LS_NH); + if(node_num_fanout(node) > 1) + bypass->dupe_at = node; + + bypass->gain += weight; + + st_lookup(gbx_node_table, (char *) fanout, (char **) &record); +/* record->mark = 1; */ + + /* Set the phase. This works since all phases must be POS or NEG_UNATE */ + + bypass->phase = (bypass->phase==phase?POS_UNATE:NEG_UNATE); + /* Update the slack */ + bypass->slack = min(bypass->slack, record->path_slack); +} +void +bypass_new_add_node(bypass, fanout, node) +node_t *fanout, *node; +bypass_t *bypass; +{ + node_bp_t *record; + node_t *fanin; + int i; + delay_time_t artime, cartime; + input_phase_t phase; + double edgeweight, control_delay, side_delay; + + bypass->last_node = fanout; + lsNewEnd(bypass->bypassed_nodes, (lsGeneric)fanout, LS_NH); + if(node_num_fanout(node) > 1) + bypass->dupe_at = node; + + side_delay = 0; + foreach_fanin(fanout, i, fanin) { + if (fanin == node) { + cartime = delay_arrival_time(fanin); + control_delay = max(cartime.rise, cartime.fall); + } + else { + artime = delay_arrival_time(fanin); + side_delay = + max(side_delay, max(artime.rise, artime.fall)); + } + } + bypass->side_slack = min(bypass->side_slack, + control_delay - side_delay); + + phase = node_input_phase(fanout, node); + edgeweight = weight(fanout, node); + + bypass->gain += edgeweight; + + st_lookup(gbx_node_table, (char *) fanout, (char **) &record); +/* record->mark = 1; */ + + /* Set the phase. This works since all phases must be POS or NEG_UNATE */ + + bypass->phase = (bypass->phase==phase?POS_UNATE:NEG_UNATE); + /* Update the slack */ + bypass->slack = min(bypass->slack, record->path_slack); +} +void +register_bypass(bypass) +bypass_t *bypass; +{ + node_t *node; + lsGen gen; + node_bp_t *record; + + int unique_insertion_code = + st_insert(bypass_table, (char *) bypass->last_node, (char *) bypass); + (void)lsNewBegin(bypasses, (lsGeneric)bypass, LS_NH); + assert(!unique_insertion_code); + + /* mark nodes on the new bypass */ + foreach_list_item(bypass->bypassed_nodes, gen, node) { + st_lookup(gbx_node_table, (char *) node, (char **) &record); + record->mark = 1; + } +} + +void +print_node_bp_record(rec, node) +node_bp_t *rec; +node_t *node; +{ + int i; + node_t *fanin; + + printf("Printing record for node %s. Slack %f mark %d. Path fanin %s, off-path slack %f\n", + node_name(node), rec->slack, rec->mark, + rec->path_fanin == NIL(node_t)?"none":node_name(rec->path_fanin), + rec->path_slack); + + foreach_fanin(node, i, fanin) { + printf("fanin %s slack %f weight %f phase %s\n", node_name(fanin), + rec->pin_slacks[i], rec->pin_weights[i], + (rec->input_phases[i] == BINATE)?"binate": + (rec->input_phases[i] == POS_UNATE)?"positive": + (rec->input_phases[i] == NEG_UNATE)?"negative":"unknown"); + } +} + +void +destroy_bp_record(record) +node_bp_t *record; +{ + if(record->pin_slacks != NIL(double)) { + FREE(record->pin_slacks); + FREE(record->pin_weights); + FREE(record->input_phases); + } + FREE(record); +} + +node_bp_t * +new_node_bp_record(node) +node_t *node; +{ + node_bp_t *result; + delay_time_t slack, rtime, atime, delay; + double minslack; + input_phase_t phase; + int i, n; + node_t *fanin; + + + SAFE_ALLOC(result, node_bp_t, 1); + result->mark = 0; + slack = delay_slack_time(node); + result->slack = min(slack.rise, slack.fall); + result->path_fanin = NIL(node_t); + if(node_function(node) == NODE_PI) { + result->pin_slacks = result->pin_weights = NIL(double); + result->input_phases = NIL(input_phase_t); + return result; + } + n = node_num_fanin(node); + SAFE_ALLOC(result->pin_slacks, double, n); + SAFE_ALLOC(result->pin_weights, double, n); + SAFE_ALLOC(result->input_phases, input_phase_t, n); + minslack = result->path_slack = 1E29; + + for(i = 0; i < n; ++i) { + delay = delay_node_pin(node, i, gbx_delay_model); + fanin = node_get_fanin(node, i); + atime = delay_arrival_time(fanin); + rtime = delay_required_time(node); + + /* Error check due to iphase bug. Take out when patch installed */ + if(node_function(node) != NODE_PO) + phase = node_input_phase(node, fanin); + else phase = POS_UNATE; + + switch(phase) { + case POS_UNATE: + rtime.rise -= delay.rise; + rtime.fall -= delay.fall; + break; + case NEG_UNATE: + rtime.rise -= delay.fall; + rtime.fall -= delay.rise; + break; + default: + rtime.rise = min(rtime.rise, rtime.fall); + delay.rise = max(delay.rise, delay.fall); + rtime.rise -= delay.rise; + rtime.fall = rtime.rise; + } + result->pin_slacks[i] = min(rtime.rise - atime.rise, + rtime.fall - atime.fall); + result->pin_weights[i] = max(delay.rise, delay.fall); + result->input_phases[i] = phase; + + /* Update the minimum slack and find the path fanin */ + + if(result->pin_slacks[i] <= minslack) { + result->path_slack = minslack; + minslack = result->pin_slacks[i]; + result->path_fanin = fanin; + } else if(result->pin_slacks[i] < result->path_slack) { + result->path_slack = result->pin_slacks[i]; + } + } + /* Finally, it's the *extra* slack on the side-inputs we want */ + result->path_slack -= minslack; + return result; +} +void +gbx_init_node_table(network, model) +network_t *network; +delay_model_t model; +{ + array_t *nodes; + node_t *node; + node_bp_t *node_record; + int i; + + gbx_delay_model = model; + (void) delay_trace(network, model); + nodes = network_dfs(network); + gbx_node_table = st_init_table(st_ptrcmp, st_ptrhash); + for(i = 0; i < array_n(nodes); ++i) { + node = array_fetch(node_t *, nodes, i); + node_record = new_node_bp_record(node); + st_insert(gbx_node_table, (char *) node, (char *) node_record); +/* print_node_bp_record(node_record, node); */ + } + array_free(nodes); +} +lsList +bypass_extension_fanouts(bypass, node) +node_t *node; +bypass_t *bypass; +{ + lsGen gen; + node_t *fanout; + lsList path_fanouts; + + assert(node_function(node) != NODE_PO); + path_fanouts = lsCreate(); + foreach_fanout(node, gen, fanout) { + if(bypass_is_extensible(bypass, fanout, node, weight(fanout, node))) { + (void)lsNewBegin(path_fanouts, (lsGeneric) fanout, LS_NH); + } + } + if(lsLength(path_fanouts) == 0) { + lsDestroy(path_fanouts, (void(*)())0); + return LS_NIL; + } else { + return path_fanouts; + } +} + +lsList +path_fanouts(node, epsilon) +node_t *node; +double epsilon; +{ + int i; + lsGen gen; + node_t *fanout; + lsList path_fanouts; + node_bp_t *fanout_record; + input_phase_t phase; + + + assert(node_function(node) != NODE_PO); + path_fanouts = lsCreate(); + foreach_fanout(node, gen, fanout) { + i = node_get_fanin_index(fanout, node); + assert(st_lookup(gbx_node_table, (char *) fanout, (char **) &fanout_record)); + if(fanout_record->pin_slacks[i] > epsilon) continue; + if(node_function(fanout) == NODE_PO) continue; + if((phase = node_input_phase(fanout, node)) == BINATE) continue; + if(phase == PHASE_UNKNOWN) continue; + if(fanout_record->path_fanin != node) continue; + if(fanout_record->path_slack == 0.0) continue; + (void)lsNewBegin(path_fanouts, (lsGeneric) fanout, LS_NH); + } + return path_fanouts; +} + +node_t * +path_fanout(node, epsilon) +node_t *node; +double epsilon; +{ + int fanout_found; + lsGen gen; + node_t *fanout, *path_fanout; + node_bp_t *fanout_record; + input_phase_t phase; + + assert(node_function(node) != NODE_PO); + fanout_found = 0; + foreach_fanout(node, gen, fanout) { + assert(st_lookup(gbx_node_table, (char *) fanout, (char **) &fanout_record)); + if(fanout_record->path_fanin != node) return NIL(node_t); + if(fanout_record->slack > epsilon) continue; + if(node_function(fanout) == NODE_PO) return NIL(node_t); + if(fanout_found) return NIL(node_t); /* two path fanouts */ + if((phase = node_input_phase(fanout, node)) == BINATE) + return NIL(node_t); + if(phase == PHASE_UNKNOWN) return NIL(node_t); + fanout_found = 1; + path_fanout = fanout; + } + assert(fanout_found); + return path_fanout; +} + +double +retrieve_slack(fanout, node) +node_t *fanout, *node; +{ + int i; + node_bp_t *record; + + assert(st_lookup(gbx_node_table, (char *) fanout, (char **) &record)); + i = node_get_fanin_index(fanout, node); + return record->pin_slacks[i]; +} +double +weight(fanout, node) +node_t *fanout, *node; +{ + int i; + node_bp_t *record; + + assert(st_lookup(gbx_node_table, (char *) fanout, (char **) &record)); + i = node_get_fanin_index(fanout, node); + return record->pin_weights[i]; +} +input_phase_t +retrieve_phase(fanout, node) +node_t *fanout, *node; +{ + int i; + node_bp_t *record; + + assert(st_lookup(gbx_node_table, (char *) fanout, (char **) &record)); + i = node_get_fanin_index(fanout, node); + return record->input_phases[i]; +} + +lsList +new_find_bypass_nodes(network, epsilon, mux_delay, model) +network_t *network; +double epsilon; +double mux_delay; +delay_model_t model; +{ + array_t *nodes; + int i, j; + node_t *node, *fanout; + node_bp_t *node_record; + lsList bypass_fanouts; + lsGen gen; + lsGen gen1; + + bypass_table = st_init_table(st_ptrcmp, st_ptrhash); + bypasses = lsCreate(); + + nodes = network_dfs(network); + for(i = 0; i < array_n(nodes); ++i) { + /* Is this node critical? */ + node = array_fetch(node_t *, nodes, i); + st_lookup(gbx_node_table, (char *) node, (char **) &node_record); + if(node_record->slack > epsilon) continue; + if(node_function(node) == NODE_PO) continue; + /* If it is, begin a list of the bypasses that begin with + this node */ + bypass_fanouts = lsCreate(); + foreach_fanout(node, gen1, fanout) { + st_lookup(gbx_node_table, (char *) fanout, (char **) &node_record); + if(node_record->slack > epsilon) continue; + j = node_get_fanin_index(fanout, node); + if(node_record->path_fanin != node) continue; + if(node_record->input_phases[j] == BINATE) continue; + if(node_record->input_phases[j] == PHASE_UNKNOWN) continue; + if(node_function(fanout) == NODE_PO) continue; + (void)lsNewBegin(bypass_fanouts, (lsGeneric) fanout, LS_NH); + } + /* Now try to extend each bypass */ + foreach_list_item(bypass_fanouts, gen, fanout) { + new_trace_bypass(fanout, node, epsilon, mux_delay, NIL(node_t), + model); + } + } + array_free(nodes); + return bypasses; +} + +void +new_trace_bypass(fanout, node, epsilon, mux_delay, last_bypass_ended, model) +node_t *fanout, *node, *last_bypass_ended; +double epsilon, mux_delay; +delay_model_t model; +{ + double slack, slackoffset, edgeweight; + node_t *dummy_node, *fanin; + int j; + bypass_t *bypass, *old_bypass; + input_phase_t phase; + char reg_code; + + + /* There is a theorem that this is a candidate bypass if and only if the + bypass gain is <= the slack on all the side inputs - the slack on + the original path input. So compute this here and ensure that this + invariant holds. The way this works is simple. Keep track of the + minimum slack, subtracting off the bypass gain each time. When we + hit zero, we're done. */ + + slackoffset = retrieve_slack(fanout, node); + edgeweight = weight(fanout, node); + slack = 1E29; + foreach_fanin(fanout, j, fanin) { + if (fanin == node) continue; + slack = min(slack, retrieve_slack(fanout, fanin)); + } + + /* If we're using one of the unit delay models, then we have a 2-input + AND/OR node network. In this case, we know KMS will eliminate the + first bypassed node, so we can allow a slack on the first node which + is one less than the minimum slack required on the other nodes. + (We check the fanin number just in case this node is a "3-input, + 1-level" mux generated by a previous pass.) */ + + if ((start_node_mode) && + (model == DELAY_MODEL_UNIT || model == DELAY_MODEL_UNIT_FANOUT) && + (node_num_fanin(fanout) <= 2)) { + if (slack-slackoffset > 0) slack++; + else return; + } + else if (slack-slackoffset < edgeweight) return; + + + /* OK, so we've bypassed at least one node...*/ + + bypass = new_bypass(node, fanout, edgeweight, slack-slackoffset, + retrieve_phase(fanout, node)); + +/* st_lookup(gbx_node_table, fanout, &record); + record->mark = 1; */ + + fanout = path_fanout(node = fanout, epsilon); + while((slack >= (bypass->gain + slackoffset)) && fanout != NIL(node_t)) { + foreach_fanin(fanout, j, fanin) { + if(fanin == node) continue; + slack = min(slack, retrieve_slack(fanout, fanin)); + } + phase = node_input_phase(fanout, node); + edgeweight = weight(fanout, fanin); + if(slack >= (bypass->gain + edgeweight + slackoffset)) + bypass_add_node(bypass, fanout, node, edgeweight, phase); + else break; + fanout = path_fanout(node = fanout, epsilon); + } + bypass->gain -= mux_delay; + + /* Now. Do we want to register this bypass? Only if the gain is + non-nil AND this bypass is not contained in the last one we did */ + + /* Debugging print statement */ +/* printf("Bypass found\n"); print_bypass(bypass); */ + + /* new code for the new tracer */ + + reg_code = bypass->gain > 0; + + if(reg_code && (st_lookup(bypass_table, (char *) bypass->last_node, (char **) &old_bypass))) { + if(bypass->gain > old_bypass->gain) { + reg_code = 1; + + /* Delete old_bypass from the table. Pass in the key as a dummy + since st may change it and I don't trust Moore that much. + Don't bother freeing the old_bypass since it's already on + the bypass list and will get freed in the terminal cleanup + anyway. */ + + dummy_node = bypass->last_node; + st_delete(bypass_table, (char **) &dummy_node, (char **) &old_bypass); + } else { + reg_code = 0; + } + } + + if(reg_code) { + register_bypass(bypass); + } else { + free_bypass(bypass); + } + +} +lsList +newer_find_bypass_nodes(network, epsilon, mux_delay, model) +network_t *network; +double epsilon; +double mux_delay; +delay_model_t model; +{ + array_t *nodes; + int i, j; + node_t *node, *fanout; + node_bp_t *node_record; + lsList bypass_fanouts; + lsGen gen; + lsGen gen1; + + bypass_table = st_init_table(st_ptrcmp, st_ptrhash); + bypasses = lsCreate(); + + nodes = network_dfs(network); + for(i = 0; i < array_n(nodes); ++i) { + /* Is this node critical? */ + node = array_fetch(node_t *, nodes, i); + st_lookup(gbx_node_table, (char *) node, (char **) &node_record); + if(node_record->slack > epsilon) continue; +/* if(node_record->mark) continue; */ + if(node_function(node) == NODE_PO) continue; + /* If it is, begin a list of the bypasses that begin with + this node */ + bypass_fanouts = lsCreate(); + foreach_fanout(node, gen1, fanout) { + st_lookup(gbx_node_table, (char *) fanout, (char **) &node_record); + if(node_record->slack > epsilon) continue; + j = node_get_fanin_index(fanout, node); + if(node_record->path_fanin != node) continue; + if(node_record->input_phases[j] == BINATE) continue; + if(node_record->input_phases[j] == PHASE_UNKNOWN) continue; + if(node_function(fanout) == NODE_PO) continue; + (void)lsNewBegin(bypass_fanouts, (lsGeneric) fanout, LS_NH); + } + /* Now try to extend each bypass */ + foreach_list_item(bypass_fanouts, gen, fanout) { + newer_trace_bypass(fanout, node, epsilon, mux_delay, NIL(node_t), + model); + } + } + array_free(nodes); + return bypasses; +} + +void +newer_trace_bypass(fanout, node, epsilon, mux_delay, last_bypass_ended, model) +node_t *fanout, *node, *last_bypass_ended; +double epsilon, mux_delay; +delay_model_t model; +{ + double slack, slackoffset, edgeweight; + node_t *fanin; + int j; + bypass_t *bypass; + + + /* There is a theorem that this is a candidate bypass if and only if the + bypass gain is <= the slack on all the side inputs - the slack on + the original path input. So compute this here and ensure that this + invariant holds. The way this works is simple. Keep track of the + minimum slack, subtracting off the bypass gain each time. When we + hit zero, we're done. */ + + slackoffset = retrieve_slack(fanout, node); + edgeweight = weight(fanout, node); + slack = 1E29; + foreach_fanin(fanout, j, fanin) { + if (fanin == node) continue; + slack = min(slack, retrieve_slack(fanout, fanin)); + } + + /* If we're using one of the unit delay models, then we have a 2-input + AND/OR node network. In this case, we know KMS will eliminate the + first bypassed node, so we can allow a slack on the first node which + is one less than the minimum slack required on the other nodes. + (We check the fanin number just in case this node is a "3-input, + 1-level" mux generated by a previous pass.) */ + + if ((start_node_mode) && + (model == DELAY_MODEL_UNIT || model == DELAY_MODEL_UNIT_FANOUT) && + (node_num_fanin(fanout) <= 2)) { + if (slack-slackoffset > 0) slack++; + else return; + } + else if (slack-slackoffset < edgeweight) return; + + + /* OK, so we've bypassed at least one node...*/ + + bypass = new_bypass(node, fanout, edgeweight, slack-slackoffset, + retrieve_phase(fanout, node)); + + if (bypass->gain > bypass->side_slack) { + free_bypass(bypass); + return; + } + +/* st_lookup(gbx_node_table, fanout, &record); + record->mark = 1; */ + + extend_bypass(bypass, fanout, mux_delay); +} +void +extend_bypass(bypass, node, mux_delay) +bypass_t *bypass; +node_t *node; +double mux_delay; +{ + + node_t *fanout, *dummy_node; + int i, j; + bypass_t *new_bypass, *old_bypass; + lsList fanouts; + lsGen gen; + + + fanouts = bypass_extension_fanouts(bypass, node); + while ((bypass->gain <= bypass->side_slack) && + (fanouts != LS_NIL)) { + + i = 1; + j = lsLength(fanouts); + foreach_list_item(fanouts, gen, fanout) { + assert(node_function(fanout) != NODE_PO); + if(i++ == j) break; + new_bypass = bypass_dup(bypass); + bypass_new_add_node(new_bypass, fanout, node); + extend_bypass(new_bypass, fanout, mux_delay); + } + bypass_new_add_node(bypass, fanout, node); + lsDestroy(fanouts, (void(*)())0); + node = fanout; + fanouts = bypass_extension_fanouts(bypass, node); + } + bypass->gain -= mux_delay; + if (bypass->gain <= 0) { + /* Unmark node; it's not on a bypass now, is it? */ +/* st_lookup(gbx_node_table, node, &record); + record->mark = 0; +*/ + free_bypass(bypass); + } + else if (st_lookup(bypass_table, (char *) bypass->last_node, (char **) &old_bypass)) { + if (bypass->gain > old_bypass->gain) { + + /* Delete old_bypass from the table. Pass in the key as a dummy + since st may change it and I don't trust Moore that much. + Don't bother freeing the old_bypass since it's already on + the bypass list and will get freed in the terminal cleanup + anyway. */ + + dummy_node = bypass->last_node; + (void) st_delete(bypass_table, (char **) &dummy_node, (char **) &old_bypass); + + register_bypass(bypass); + printf("Debug - Need to delete previous bypass\n"); + } + else free_bypass(bypass); + } + else register_bypass(bypass); +} + +void +clean_global_tables(network) +network_t *network; +{ + + st_free_table(bypass_table); +} +void +gbx_clean_node_table(network) +network_t *network; +{ + array_t *nodes; + int i; + node_t *node; + node_bp_t *node_record; + + nodes = network_dfs(network); + + for(i = 0; i < array_n(nodes); ++i) { + node = array_fetch(node_t *, nodes, i); + if(st_lookup(gbx_node_table, (char *) node, (char **) &node_record)) + destroy_bp_record(node_record); + } + st_free_table(gbx_node_table); + array_free(nodes); +} +void +print_bypass(bypass) +bypass_t *bypass; +{ + lsGen gen; + node_t *node; + + printf("%s Bypass: weight %f nodes %d first node %s last node %s\n", + bypass->phase == POS_UNATE?"Noninverting":"Inverting", + bypass->gain, lsLength(bypass->bypassed_nodes), + node_name(bypass->first_node), node_name(bypass->last_node)); + printf("Nodes: "); + foreach_list_item(bypass->bypassed_nodes, gen, node) { + printf("%s ", node_name(node)); + } + printf("\n"); +} + +int +do_gbx_transform(network, epsilon, mux_delay, model, new_proc, actual_mux_delay) +network_t *network; +double epsilon, mux_delay, actual_mux_delay; +delay_model_t model; +gbx_trace_t new_proc; +{ + st_table *cut_table; + array_t *nodes; + node_t *node; + bypass_t *bypass; + lsList bypasses; + double maxgain; + int maxweight, critweight, noncritweight, i, totweight; + char taken, no_improvement; + lsGen gen; + int noncritnodes, ntaken, nnottaken; + lsList *critnodes; + int maxslack; + node_bp_t *node_record; + + + switch(new_proc) { + case GBX_NEW_TRACE: + bypasses = new_find_bypass_nodes(network, epsilon, mux_delay, model); + break; + case GBX_NEWER_TRACE: + bypasses = newer_find_bypass_nodes(network, epsilon, mux_delay, model); + break; + default: + bypasses = newer_find_bypass_nodes(network, epsilon, mux_delay, model); + } + if(lsLength(bypasses) == 0) { + clean_global_tables(network); + lsDestroy(bypasses, (void(*)())0); + return 0; + } + + /* Otherwise we found some bypasses */ + + maxgain = 0.0; + foreach_list_item(bypasses, gen, bypass) { + maxgain = max(maxgain, bypass->gain); + } + maxgain += 1.0; /* Make sure the minimum weight of any bypass is 1 */ + maxweight = 0; + foreach_list_item(bypasses, gen, bypass) { + bypass->weight = (int)(0.5 + maxgain - (bypass->gain)); /* it works...*/ + maxweight = max(maxweight, bypass->weight); + } + nodes = network_dfs(network); + noncritweight = maxweight * lsLength(bypasses) + 1; + cut_table = st_init_table(st_ptrcmp, st_ptrhash); + noncritnodes = 0; + maxslack = (int)(0.5 + epsilon); + ++maxslack; + SAFE_ALLOC(critnodes, lsList, maxslack); + for(i = 0; i < maxslack; ++i) critnodes[i] = lsCreate(); + for(i = 0; i < array_n(nodes); ++i) { + node = array_fetch(node_t *, nodes, i); + if(st_lookup(bypass_table, (char *) node, (char **) &bypass)) { + st_insert(cut_table, (char *) node, (char *)bypass->weight); + } else { + st_lookup(gbx_node_table, (char *) node, (char **) &node_record); + if(node_function(node) == NODE_PI || node_function(node) == NODE_PO) + continue; + if(node_record->slack <= epsilon) { + critweight = (int) 0.5 + epsilon - node_record->slack; + (void)lsNewBegin(critnodes[critweight], (lsGeneric) node, LS_NH); + } else { + ++noncritnodes; + st_insert(cut_table, (char *) node, (char *) noncritweight); + /* st_insert(cut_table, node, 0); */ + } + } + } + /* Algebraically equivalent to + maxweight * lsLength(bypasses) + noncritweight * noncritnodes + 1 */ + critweight = noncritweight * (noncritnodes + 1); + totweight = critweight - 1; + + for(i = 0; i < maxslack; ++i) { + totweight += critweight * lsLength(critnodes[i]); + if(totweight < critweight) { /* Overflow! */ + totweight = GBX_MAXWEIGHT; + } + foreach_list_item(critnodes[i], gen, node) { + st_insert(cut_table, (char *) node, (char *)critweight); + } + critweight = totweight + 1; + } + + array_free(nodes); + + /* Now just take the cutset */ + + nodes = cutset_interface(network, cut_table, MAXINT); + + taken = 0; no_improvement = 0; ntaken = 0; nnottaken = 0; + for(i = 0; i < array_n(nodes); ++i) { + node = array_fetch(node_t *, nodes, i); + if(st_lookup(bypass_table, (char *) node, (char **) &bypass)) { +/* printf("Taking Bypass\n"); + print_bypass(bypass); */ + if (take_bypass(bypass, network, model, mux_delay, actual_mux_delay)) { + ++ntaken; + taken = 1; +/* com_execute(&network, "verify -m bdd /users/harkness/GBX/bench/5xp1.blif.opt"); + com_execute(&network, "write_eqn"); */ + } + + else ++nnottaken; + } else { + st_lookup(gbx_node_table, (char *) node, (char **) &node_record); + if(node_record->slack == 0.0) no_improvement = 1; + } + } + if(gbx_verbose_mode) { + printf("%d bypasses taken", ntaken); + if (nnottaken == 0) printf("\n"); + else printf(" %d bypasses not taken\n", nnottaken); + } + + array_free(nodes); + st_free_table(cut_table); + lsDestroy(bypasses, (void(*)())0); + for(i = 0; i < maxslack; ++i) lsDestroy(critnodes[i], (void(*)())0); + clean_global_tables(network); + if ((model == DELAY_MODEL_UNIT || model == DELAY_MODEL_UNIT_FANOUT) && + (actual_mux_delay > 1)) + decomp_tech_network(network, 2, 2); + (void)network_sweep(network); /* Clean up the mess, if necessary */ + if(!taken) return 3; + if(no_improvement) return 2; + return 1; +} + +int +bypass_compare(bypass1, bypass2) +char **bypass1, **bypass2; +{ + return ((bypass_t *) *bypass2)->gain - ((bypass_t *) *bypass1)->gain; +} + +int +do_all_bypasses(network, epsilon, mux_delay, actual_mux_delay, model, + new_proc) +network_t *network; +double epsilon, mux_delay, actual_mux_delay; +delay_model_t model; +gbx_trace_t new_proc; +{ + bypass_t *bypass; + lsList bypasses; + lsGen gen; + int ntaken, nnottaken; + array_t * bypass_array; + int i; + + switch(new_proc) { + case GBX_NEW_TRACE: + bypasses = new_find_bypass_nodes(network, epsilon, mux_delay, model); + break; + case GBX_NEWER_TRACE: + bypasses = newer_find_bypass_nodes(network, epsilon, mux_delay, model); + break; + default: + bypasses = newer_find_bypass_nodes(network, epsilon, mux_delay, model); + } + if(lsLength(bypasses) == 0) { + clean_global_tables(network); + lsDestroy(bypasses, (void(*)())0); + return 0; + } + else { + + bypass_array = array_alloc(bypass_t *, 0); + foreach_list_item(bypasses, gen, bypass) { + array_insert_last(bypass_t *, bypass_array, bypass); + } + array_sort(bypass_array, bypass_compare); + + ntaken = 0; nnottaken = 0; + for (i = 0; i < array_n(bypass_array); ++i) { + if (take_bypass(array_fetch(bypass_t *, bypass_array, i), network, model, + mux_delay, actual_mux_delay)) + ++ntaken; + else ++nnottaken; + } + array_free(bypass_array); + + if (gbx_verbose_mode) { + printf(" %d bypasses taken", ntaken); + if (nnottaken == 0) printf("\n"); + else printf(" %d bypasses not taken\n", nnottaken); + } + } + + clean_global_tables(network); + if ((model == DELAY_MODEL_UNIT || model == DELAY_MODEL_UNIT_FANOUT) && + (actual_mux_delay > 1)) + decomp_tech_network(network, 2, 2); + (void)network_sweep(network); /* Clean up the mess, if necessary */ + return 1; +} + +void +print_epsilon_paths(nodelist, node, epsilon) +lsList nodelist; +node_t *node; +double epsilon; +{ + lsGen gen; + lsGen gen1; + node_t *fanout; + node_bp_t *record; + + if(node_function(node) == NODE_PO) { + foreach_list_item(nodelist, gen1, node) { + printf("%s ", node_name(node)); + } + printf("\n"); + return; + } else { + foreach_fanout(node, gen, fanout) { + (void)st_lookup(gbx_node_table, (char *) node, (char **) &record); + if(record->slack > epsilon) continue; + (void)lsNewEnd(nodelist, (lsGeneric)fanout, LS_NH); + print_epsilon_paths(nodelist, fanout, epsilon); + lsDelEnd(nodelist, (lsGeneric *)&fanout); + } + } +} + + + +void +print_epsilon_network(network, model, epsilon) +network_t *network; +delay_model_t model; +double epsilon; +{ + node_t *pi; + lsGen gen; + lsList nodelist; + node_bp_t *record; + + + foreach_primary_input(network, gen, pi) { + st_lookup(gbx_node_table, (char *) pi, (char **) &record); + if(record->slack >= epsilon) continue; + nodelist = lsCreate(); + (void)lsNewBegin(nodelist, (lsGeneric) pi, LS_NH); + print_epsilon_paths(nodelist, pi, epsilon); + lsDestroy(nodelist, (void(*)())0); + } +} + +int +do_GBX(network, adaptive_epsilon, epsilon, new_trace_procedure, mux_delay, target_delay, target_chosen, + model, cutset_mode) +network_t **network; +double epsilon, mux_delay, target_delay; +delay_model_t model; +gbx_trace_t new_trace_procedure; +int adaptive_epsilon, cutset_mode; +char target_chosen; +{ + int retcode, ret; + double actual_mux_delay, initial_artime, artime, lastartime; + int nbadbypasses; + network_t *saved_network; + + nbadbypasses = 0; + actual_mux_delay = mux_delay; + + if (model == DELAY_MODEL_UNIT || model == DELAY_MODEL_UNIT_FANOUT) + decomp_tech_network(*network, 2, 2); + (void) network_sweep(*network); + gbx_init_node_table(*network, model); + (void) delay_latest_output(*network, &initial_artime); + if(!target_chosen) { + target_delay = initial_artime/2; /* ambitious? */ + } + if (adaptive_epsilon) epsilon = initial_artime - target_delay; + artime = initial_artime; + + while(artime > target_delay) { + lastartime = artime; + if (target_chosen && adaptive_epsilon) epsilon = artime - target_delay; + else if (adaptive_epsilon) epsilon = min(epsilon, artime - target_delay); + if (gbx_verbose_mode) + printf("Searching for bypasses, delay = %f\n", artime); + saved_network = network_dup(*network); + if (cutset_mode) + retcode = do_gbx_transform(*network, epsilon, mux_delay, model, + new_trace_procedure, actual_mux_delay); + else retcode = do_all_bypasses(*network, epsilon, mux_delay, actual_mux_delay, + model, new_trace_procedure); + (void) delay_trace(*network, gbx_delay_model); + (void) delay_latest_output(*network, &artime); + gbx_clean_node_table(*network); + + if(artime <= target_delay) { + if (gbx_verbose_mode && target_chosen) + printf("Success! sped up the network to the target\n"); + return 0; + } + if ((artime-lastartime >= 0.0) && (retcode != 0) && (retcode != 3)) { + if (gbx_verbose_mode) + printf("No improvement - rejecting changes\n"); + network_free(*network); + *network = saved_network; + if (retcode == 1) retcode = 0; + } + else network_free(saved_network); + + switch (retcode) { + case 0: + if (gbx_verbose_mode) + printf("No bypasses found,"); + if ((artime == lastartime) && (mux_delay > 1)) { + if (gbx_verbose_mode) + printf(" trying again with smaller estimated mux delay\n"); + mux_delay = 1; + saved_network = network_dup(*network); + (void) delay_latest_output(*network, &lastartime); + gbx_init_node_table(*network, model); + if (cutset_mode) + ret = do_gbx_transform(*network, epsilon, mux_delay, + model, new_trace_procedure, actual_mux_delay); + else ret = do_all_bypasses(*network, epsilon, mux_delay, + actual_mux_delay, model, new_trace_procedure); + if (gbx_verbose_mode) { + switch (ret) { + case 0: printf("No bypasses found\n"); break; + case 3: printf("Cutset not found, no bypasses taken.\n"); break; + case 2: printf("Cutset not found, some bypasses taken.\n"); break; + case 1: if (cutset_mode) + printf("Cutset found, bypasses taken. Gain %f should be > 0\n", + lastartime - artime); + else printf("Bypasses taken. Gain %f\n", + lastartime - artime); + break; + } + } + (void) delay_trace(*network, gbx_delay_model); + (void) delay_latest_output(*network, &artime); + gbx_clean_node_table(*network); + if(artime-lastartime >= 0.0) { + if (gbx_verbose_mode) + printf("Last shot missed, quitting\n"); + network_free(*network); + *network = saved_network; + return 0; + } + else { + if(gbx_verbose_mode) + printf("Last Shot hit, kicking the can again\n"); + gbx_init_node_table(*network, model); + network_free(saved_network); + mux_delay = 2; + } + } + else { + if (gbx_verbose_mode) + printf(" giving up\n"); + return 0; + } + break; + case 3: + if (gbx_verbose_mode) + printf("Cutset not found, no bypasses taken.\n"); + if (adaptive_epsilon && !target_chosen && epsilon > 1) { + epsilon = epsilon/2; + if (gbx_verbose_mode) + printf("Trying again with smaller epsilon\n"); + (void) delay_latest_output(*network, &lastartime); + gbx_init_node_table(*network, model); + saved_network = network_dup(*network); + ret = do_gbx_transform(*network, epsilon, mux_delay, + model, new_trace_procedure, actual_mux_delay); + if (gbx_verbose_mode) { + switch (ret) { + case 0: printf("No bypasses found\n"); break; + case 3: printf("Cutset not found, no bypasses taken.\n"); break; + case 2: printf("Cutset not found, some bypasses taken.\n"); break; + case 1: printf("Cutset found, bypasses taken.\n"); break; + } + } + (void) delay_trace(*network, gbx_delay_model); + (void) delay_latest_output(*network, &artime); + gbx_clean_node_table(*network); + if(artime-lastartime >= 0.0) { + if(gbx_verbose_mode) + printf("Last shot missed, quitting\n"); + network_free(*network); + *network = saved_network; + return 0; + } + else { + if(gbx_verbose_mode) + printf("Last Shot hit, kicking the can again\n"); + network_free(saved_network); + gbx_init_node_table(*network, model); + } + } + else { + if (gbx_verbose_mode) + printf("Giving up\n"); + return 0; + } + break; + case 2: + (void) delay_latest_output(*network, &lastartime); + if(gbx_verbose_mode) { + printf("Cutset not found, some bypasses taken.\n"); + printf("Delay is %f\n", lastartime); + } + if (adaptive_epsilon && !target_chosen && epsilon > 1) { + epsilon = epsilon/2; + if (gbx_verbose_mode) + printf("Trying again with smaller epsilon\n"); + gbx_init_node_table(*network, model); + saved_network = network_dup(*network); + ret = do_gbx_transform(*network, epsilon, mux_delay, + model, new_trace_procedure, actual_mux_delay); + if (gbx_verbose_mode) { + switch (ret) { + case 0: printf("No bypasses found\n"); break; + case 3: printf("Cutset not found, no bypasses taken.\n"); break; + case 2: printf("Cutset not found, some bypasses taken.\n"); break; + case 1: printf("Cutset found, bypasses taken.\n"); break; + } + } + (void) delay_trace(*network, gbx_delay_model); + (void) delay_latest_output(*network, &artime); + gbx_clean_node_table(*network); + if (artime-lastartime >= 0.0) { + if (gbx_verbose_mode) + printf("Last shot missed, quitting\n"); + network_free(*network); + *network = saved_network; + return 0; + } + else { + if(gbx_verbose_mode) + printf("Last Shot hit, kicking the can again\n"); + network_free(saved_network); + gbx_init_node_table(*network, model); + } + } + else { + if (gbx_verbose_mode) + printf("Giving up\n"); + return 0; + } + break; + case 1: + if (gbx_verbose_mode) { + if (cutset_mode) + printf("Cutset found, bypasses taken. Gain %f should be > 0\n", + lastartime - artime); + else printf("Bypasses taken. Gain %f\n", lastartime - artime); + } + + /* short term cludge to prevent infinite loop */ + if (lastartime - artime <= 0) { + ++nbadbypasses; + if (nbadbypasses == 5) { + printf("Bypass algorithm failure - quitting infinite loop\n"); + return 0; + } + } + gbx_init_node_table(*network, model); + } + } + + return 0; /* normal exit */ +} + +/* To be called from KJ's framework */ +int +do_bypass_transform(network, epsilon, adaptive_epsilon, mux_delay, model, new_trace_procedure, + verbose_mode, cutset_mode) +network_t **network; +double epsilon, mux_delay; +delay_model_t model; +gbx_trace_t new_trace_procedure; +int adaptive_epsilon, verbose_mode, cutset_mode; +{ + double target_delay; + char target_chosen; + + target_chosen = 0; + start_node_mode = 1; + target_delay = target_chosen = 0; + if (verbose_mode) gbx_verbose_mode = 1; + if (verbose_mode) print_bypass_mode = 1; + + do_GBX(network, adaptive_epsilon, epsilon, new_trace_procedure, mux_delay, target_delay, + target_chosen, model, cutset_mode); + + return 0; +} + diff --git a/sis/speed/gbx_int.h b/sis/speed/gbx_int.h new file mode 100644 index 0000000..8ea9293 --- /dev/null +++ b/sis/speed/gbx_int.h @@ -0,0 +1,90 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/gbx_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +/* + * definitions local to 'gbx' go here + */ +/* A Useful utility */ +#define SAFE_ALLOC(var, type, num) \ + assert((var = (type *)ALLOC(type, num)) != NIL(type)) + +#define max(x,y) (x < y?y:x) +#define min(x,y) (x > y?y:x) + +/* find all bypasses in a network */ + +extern int +com_gbx_print_bypasses(); + +/* + * Find bypasses and take them + */ +extern int +com_gbx_bypass(); +/* + * Find the bypasses and take them ALL + */ +extern int +com_gbx_all_bypasses(); + + +extern st_table *node_weight_table; +extern delay_model_t gbx_delay_model; +typedef enum gbx_trace_enum gbx_trace_t; +enum gbx_trace_enum { + GBX_OLD_TRACE, GBX_NEW_TRACE, GBX_NEWER_TRACE +}; + +typedef struct bypass_struct bypass_t; +struct bypass_struct { + node_t *first_node, *last_node; + double gain; + double slack; + double side_delay; + double control_delay; + int weight; + node_t *dupe_at; + lsList bypassed_nodes; + input_phase_t phase; + double side_slack; +}; + +typedef struct node_bp_struct node_bp_t; +struct node_bp_struct { + double *pin_slacks, *pin_weights; /* slacks, weights on fanin edges */ + input_phase_t *input_phases; /* phases of inputs */ + double slack; /* slack on gate */ + node_t *path_fanin; /* fanin of minimum slack */ + double path_slack; /* extra slack on most critical S.I */ + char mark; /* Marked if there's a bypass through this */ +}; +extern network_t *gbx_dup_network; +extern st_table *bypass_table; +extern st_table *gbx_node_table; +extern lsList bypasses; +extern int take_bypass(); +extern bypass_t *new_bypass(); +extern void free_bypass(); +extern void bypass_add_node(); +extern void register_bypass(); +extern node_bp_t *new_node_bp_record(); +extern void gbx_init_node_table(); +extern void gbx_clean_node_table(); +extern node_t *path_fanout(); +extern double retrieve_slack(); +extern double weight(); +extern lsList find_bypass_nodes(); +extern void print_bypass(); +extern void trace_bypass(); +extern lsList new_find_bypass_nodes(); +extern lsList newer_find_bypass_nodes(); +extern int gbx_verbose_mode; +extern int start_node_mode; +extern int print_bypass_mode; + diff --git a/sis/speed/new_speed.c b/sis/speed/new_speed.c new file mode 100644 index 0000000..34d055b --- /dev/null +++ b/sis/speed/new_speed.c @@ -0,0 +1,1258 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/new_speed.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include <math.h> + +int sp_compare_cutset_nodes(); + +static int new_speed_recur(); +static void sp_compute_delta(); +static void nsp_set_initial_load(); +static void sp_set_updated_constraints(); +static void sp_do_initial_resynthesis(); +static network_t *sp_generate_network_from_array(); +static array_t *speed_filter_cutset(); +static array_t *new_speed_collapse_bfs(); +static delay_time_t nsp_get_input_drive(); + + /* MACRO to compare two delay_time_t structures */ +#define SP_DELAY_IMPROVED(fanout_flag,old,new) \ +(fanout_flag != CLP ? \ + (new.rise > old.rise+NSP_EPSILON && new.fall > old.fall+NSP_EPSILON) : \ + (new.rise < old.rise-NSP_EPSILON && new.fall < old.fall-NSP_EPSILON)) + +/* + * Interface routine that will take the appropriate arguments and shove them + * into the appropriate data-structure that is used by routines in new_speed + */ +/* ARGSUSED */ +int +new_speed(network, speed_param) +network_t *network; +speed_global_t *speed_param; +{ + int status; + double saved_value, slack_diff; + st_table *table; + + if (network_num_pi(network) == 0) return 0; /* No improvement possibe */ + /* + * Assume that a valid delay trace has been performed.... + * Use the required time at the o/p as the user-supplied times + * so that we are consistent in computing the slacks. Also the + * initial threshold is set adaptively (based on slacks)... + */ + saved_value = speed_param->thresh; + if (speed_param->new_mode && nsp_first_slack_diff(network, &slack_diff)) { + speed_param->thresh = 2 * slack_diff; + } + table = speed_store_required_times(network); + status = new_speed_recur(network, speed_param, 0); + speed_restore_required_times(table); + speed_param->thresh = saved_value; + + return status; +} + +/* + * Actual routine that implements the idea that the side paths can be sped up + * to yeild greater saving allong the critical path. The algorithm is + * recursive and at each stage the network is carved out into a critical + * and non critical region --- recursion being done on the non-critical + * region with appropriate delay constraints + * + * In addition the selection mechanism for the local transformations to + * apply is better compared to the (-f option) of speedup... + */ + +static int +new_speed_recur(network, speed_param, level) +network_t *network; +speed_global_t *speed_param; +int level; +{ + int i, j; + sp_clp_t *rec; + lsGen gen, gen1; + sp_weight_t *wght; + sp_xform_t *ti_model; + network_t *opt_netw, *orig_netw; + st_generator *stgen; + char *key, *value; + double delta, epsilon; + node_t *po, *fo, *fanin, *fanin_in, *fan, *np; + node_t *node, *new_pi, *new_po, *input; + delay_time_t old_arr, old_req, old, new; + array_t *mincut, *network_array, *new_roots; + st_table *equiv_name_table, *clp_table, *select_table; + int is_special_case; + int recur_helped, should_recur, need_recursion, success, delay_improved; + + success = FALSE; + + if (level >= speed_param->max_recur) { + if (speed_param->debug > 1) (void)fprintf(sisout, "HIT RECURSION LIMIT\n"); + return success; + } + /* + * Since at the last recursion we do not need to doe the extra work + * required for computing the constraints for recursion + */ + should_recur = ((level+1) < speed_param->max_recur); + + if (speed_param->debug > 1) + (void)fprintf(sisout, "\n<<<< RECURSION LEVEL %d\n", level); + + if (speed_param->model == DELAY_MODEL_MAPPED && + !lib_network_is_mapped(network)){ + (void)fprintf(siserr, "ERROR: initial network not mapped \n"); + } + /* + * Identify the epsilon critical network and the cutsets to improve + */ + delay_trace(network, speed_param->model); + set_speed_thresh(network, speed_param); + clp_table = st_init_table(st_ptrcmp, st_ptrhash); + new_speed_compute_weight(network, speed_param, clp_table, &epsilon); + + if (epsilon < NSP_EPSILON){ + if (speed_param->debug){ + (void)fprintf(sisout, "No saving possible at this stage\n"); + } + new_free_weight_info(clp_table); + return -1; /* Indicates no futher impr possible or required*/ + } + + /* Use the new formulation of evaluating all cuts */ + mincut = new_speed_select_xform(network, speed_param, + clp_table, epsilon); + /* Reset the caches that were used for efficiency */ + nsp_free_buf_param(); + + if (mincut == NIL(array_t)){ + if (speed_param->model == DELAY_MODEL_MAPPED) { + (void)com_execute(&network, "write_blif -n /usr/tmp/sp_fail.blif"); + } else { + (void)com_execute(&network, "write_blif /usr/tmp/sp_fail.blif"); + } + fail("ERROR: no mincut :: Saved network in /usr/tmp/sp_fail.blif"); + } else if (array_n(mincut) == 0){ + /* There was no selection that gave a positive saving --- all the + selections interacted so as to overcome the predicted saving */ + if (speed_param->debug){ + (void)fprintf(sisout, "All selections were rejected !!!\n"); + } + new_free_weight_info(clp_table); + return -1; /* Indicates no futher impr possible or required*/ + } + + /* Just see if there are nodes where transformations result in a delay + * saving with a decrease in area. Accept these anyway !!!! + */ + sp_expand_selection(speed_param, mincut, clp_table, &select_table); + + if (speed_param->debug > 1){ + (void)fprintf(sisout, "Original selection\n"); + for (i = 0; i < array_n(mincut); i++){ + node = array_fetch(node_t *, mincut, i); + (void)fprintf(sisout, " %s", node_long_name(node)); + } + (void)fprintf(sisout, "\n"); + } + + /* Check if all the nodes in the selection set are valid ones */ + speed_reorder_cutset(speed_param, clp_table, &mincut); + + if (speed_param->debug){ + (void)fprintf(sisout, "Revised selection order\n"); + for (i = 0; i < array_n(mincut); i++){ + node = array_fetch(node_t *, mincut, i); + (void)st_lookup(clp_table, (char *)node, (char **)&wght); + j = wght->best_technique; + (void)fprintf(sisout, "\t%10s :d=(%.2f) a=%6.2f %s\n", + node_long_name(node), + wght->improvement[j], wght->area_cost[j], + (wght->can_invert ? "CAN_INV" : "NO-INVERT")); + } + } + + if (speed_param->model == DELAY_MODEL_MAPPED && + !lib_network_is_mapped(network)){ + (void)fprintf(siserr, "ERROR: network not mapped after selection\n"); + } + + /* + * Save the configuration in case we need to restore it later + * make dummy PI/PO's so that the resynthesized sections can be removed + */ + network_array = array_alloc(sp_clp_t *, 0); + for (i = 0; i < array_n(mincut); i++){ + node = array_fetch(node_t *, mincut, i); + assert(st_lookup(clp_table, (char *)node, (char **)&wght)); + ti_model = sp_local_trans_from_index(speed_param, wght->best_technique); + + /* Restore the value of "crit_slack" to be the one used earlier */ + speed_param->crit_slack = wght->crit_slack; + + /* + * Keep a single structure to record the neccessary info like + * the original configuration, etc. + */ + + rec = sp_create_collapse_record(node, wght, speed_param, ti_model); + if (ti_model->type == FAN){ + rec->cfi = wght->cfi; + rec->old = wght->cfi_req; + } + array_insert_last(sp_clp_t *, network_array, rec); + + /* + * Now remove all the nodes from the original netw that correspond + * to the resynthesized sections ,adding PI & PO nodes appropriately + * First deal with the PI's of the sub-network (PO's to be added + * to the network) + */ + rec->equiv_table = st_init_table(strcmp, st_strhash); + sp_delete_network(speed_param, network, node, rec->net, select_table, + clp_table, rec->equiv_table); + + /* Do an initial decompostion of the collapsed network */ + if (speed_param->debug > 2) { + (void)fprintf(sisout, "^^^^ ORIGINAL CONFIGURATION at %s\n", + node->name); + sp_print_network(rec->net, "Before Initial Resynthesis"); + } + sp_do_initial_resynthesis(rec); + if (speed_param->debug > 2) { + sp_print_network(rec->net, "After Initial Resynthesis"); + } + + } + /* Reset the caches that were used during local transformations */ + nsp_free_buf_param(); + + /* Cleanup any remaining nodes that do not fanout or are not driven */ + network_ccleanup(network); + + /* + * find the "delta" value by which side inputs need to be improved + * We shall also consider the additional loading that may need to be + * driven due to the additional resynthesis at the selected nodes... + */ + for(i = array_n(network_array); should_recur && i-- > 0; ){ + sp_compute_delta(network, speed_param, network_array, i); + } + + if (speed_param->debug > 3){ + sp_print_network(network, "After applying transforms\n"); + } + + new_free_weight_info(clp_table); + + /* If there is no node to be decomposed, return. */ + if (array_n(network_array) == 0) goto free_and_return; + + if (speed_param->debug > 1){ + (void)fprintf(sisout, "CUTSET TRIES improvement at %d nodes\n", + array_n(network_array)); + } + + /* + * Add appropriate timing constraints on the dummy PI/PO's based on + * the delta values that have been computed for them .... + */ + need_recursion = FALSE; + for ( i = 0; should_recur && i < array_n(network_array); i++){ + rec = array_fetch(sp_clp_t *, network_array, i); + + if (rec->ti_model->type != CLP){ + /* Set the new timing constraint for the new PI's that correspond + to the PO's of the network being resynthesized */ + j = 1; + foreach_primary_output(rec->net, gen, po){ + (void)st_lookup(rec->equiv_table, po->name, (char **)&new_pi); + delta = array_fetch(double, rec->delta, j++); + delta = MAX(0.0, delta); + need_recursion = (need_recursion || (delta > 0)); + + assert(delay_get_po_required_time(po, &old_req)); + delay_set_parameter(new_pi, DELAY_ARRIVAL_RISE, old_req.rise + delta); + delay_set_parameter(new_pi, DELAY_ARRIVAL_FALL, old_req.fall + delta); + } + } else { + /* Set the appropriate required time for PO's that correspond + * to the inputs of the reynthesized network */ + j = 1; + foreach_primary_input(rec->net, gen, input){ + (void)st_lookup(rec->equiv_table, input->name, (char **)&new_po); + delta = array_fetch(double, rec->delta, j++); + delta = MAX(0.0, delta); + need_recursion = (need_recursion || (delta > 0)); + + assert(delay_get_pi_arrival_time(input, &old_arr)); + delay_set_parameter(new_po, DELAY_REQUIRED_RISE, old_arr.rise - delta); + delay_set_parameter(new_po, DELAY_REQUIRED_FALL, old_arr.fall - delta); + } + } + } + + + if (speed_param->model == DELAY_MODEL_MAPPED && + !lib_network_is_mapped(network)){ + (void)fprintf(siserr, "ERROR: network not mapped before recursion\n"); + } + + /* Now recur on this new network generated with appropriate constraints */ + if (need_recursion) { + recur_helped = new_speed_recur(network, speed_param, level+1); + } + + /* + * After the recursion, use the correct delay values to resynthesize + * the original sections that were to be sped up + */ + if (need_recursion){ + if (speed_param->debug > 1){ + (void)fprintf(sisout,"RECURSION %s\n", + (recur_helped ? "HELPED" : "DID NOT HELP AT ALL")); + } + assert(delay_trace(network, speed_param->model)); + for (i = 0; i < array_n(network_array); i++){ + rec = array_fetch(sp_clp_t *, network_array, i); + if (recur_helped){ + if (speed_param->debug > 1){ + (void)fprintf(sisout, "Redecomposing %s\n", rec->name); + } + j = speed_param->debug; + speed_param->debug = FALSE; + sp_set_updated_constraints(rec, speed_param, network); + opt_netw = (*rec->ti_model->optimize_func)(rec->net, + rec->ti_model, rec->glb); + network_free(rec->net); + rec->net = opt_netw; + speed_param->debug = j; + } + } + /* Reset the caches that were used for efficiency */ + nsp_free_buf_param(); + } + if (speed_param->model == DELAY_MODEL_MAPPED && + !lib_network_is_mapped(network)){ + (void)fprintf(siserr, "ERROR: network not mapped before check\n"); + } + + /* + * Check the decomposed network and the original configuration. + * Keep the one with smaller delay around .... + */ + for (i = 0; i < array_n(network_array); i++){ + rec = array_fetch(sp_clp_t *, network_array, i); + /* + * Get the performance of the optimized circuits ... + */ + if (rec->ti_model->type == FAN){ + np = network_get_pi(rec->net, rec->cfi); + new = delay_required_time(np); + /* HERE -- should account for load of PREV gate !!! */ + } else if (rec->ti_model->type == DUAL){ + fail("Do not know how to handle DUAL networks yet"); + np = network_get_pi(rec->net, rec->cfi); + new = delay_required_time(np); + } else { + new = (*rec->ti_model->arr_func) + (network_get_po(rec->net, 0), rec->glb); + new_speed_adjust_po_arrival(rec, speed_param->model, &new); + } + old = rec->old; + + /* + if (speed_param->debug > 1){ + (void)fprintf(sisout, "\tl=%d IMPROVEMENT at %s= %6.3f:%-6.3f\n", + level, rec->name, t.rise, t.fall); + (void)fprintf(sisout, "\t\tAt %s AFTER RECURSION %.2f:%-.2f\n", + rec->name, new.rise, new.fall); + } + */ + /* Only accept the decomposition if it saves delay */ + if (! SP_DELAY_IMPROVED(rec->ti_model->type, old, new)){ + delay_improved = FALSE; + orig_netw = rec->orig_config; + if (speed_param->debug > 2){ + (void)fprintf(sisout, "---- USING ORIGINAL CONFIGURATION\n"); + (void)com_execute(&orig_netw, "print"); + (void)fprintf(sisout, "---- INSTEAD OF\n"); + (void)com_execute(&(rec->net), "print"); + } + + /* Use the stored configuration instead of the new one */ + network_free(rec->net); + rec->net = speed_network_dup(orig_netw); + new = rec->old; /* Just for printing */ + } else { + delay_improved = TRUE; + if (speed_param->debug > 2){ + (void)fprintf(sisout, "++++ USING NEW CONFIGURATION\n"); + (void)com_execute(&(rec->net), "print"); + } + success = TRUE; + } + + if (speed_param->debug > 1){ + (void)fprintf(sisout, "At %s FINAL %s %s %.2f:%-.2f\n", + rec->name, (delay_improved ? "IMPROVED":"ORIGINAL"), + (rec->ti_model->type == FAN ? "REQUIRED": + (rec->ti_model->type == DUAL ?"SLACK" :"ARRIVAL")), + new.rise, new.fall); + } + } + + if (speed_param->model == DELAY_MODEL_MAPPED && + !lib_network_is_mapped(network)){ + (void)fprintf(siserr, "ERROR: network not mapped before append\n"); + } + + /* Add the resynthesized sections to the original network */ + new_roots = array_alloc(node_t *, 0); + equiv_name_table = st_init_table(strcmp, st_strhash); + for(i = 0; i < array_n(network_array); i++ ){ + rec = array_fetch(sp_clp_t *, network_array, i); + sp_append_network(speed_param, network, rec->net, rec->ti_model, + equiv_name_table, new_roots); + nsp_free_collapse_record(rec); + } + /* Free the table storing the equivalence between nodes */ + st_foreach_item(equiv_name_table, stgen, &key, &value){ + FREE(key); FREE(value); + } + st_free_table(equiv_name_table); + + if (speed_param->model == DELAY_MODEL_MAPPED && + !lib_network_is_mapped(network)){ + (void)fprintf(siserr, "ERROR: network becomes mapped after append\n"); + } + + if (speed_param->model != DELAY_MODEL_MAPPED){ + for(i = 0; i < array_n(new_roots); i++){ + node = array_fetch(node_t *, new_roots, i); + if ((node_num_fanin(node) == 1) && + (new_speed_is_fanout_po(node) == FALSE) ){ + if (speed_param->debug > 2){ + (void)fprintf(sisout, "Collapsing added root with single fanin\n"); + } + speed_delete_single_fanin_node(network, node); + } + } + } + array_free(new_roots); + /* + * Due to the collapsing of the inverters, some + * primary o/p may become buffers. Remove these. + */ + foreach_primary_output(network, gen, fo){ + fanin = node_get_fanin(fo, 0); + if (node_function(fanin) == NODE_BUF && + lib_gate_of(fanin) == NIL(lib_gate_t)){ + fanin_in = node_get_fanin(fanin, 0); + assert(node_patch_fanin(fo, fanin, fanin_in)); + foreach_fanout(fanin, gen1, fan){ + (void) node_collapse(fan, fanin); + } + if (node_num_fanout(fanin) == 0) + speed_network_delete_node(network, fanin); + } + } + st_free_table(select_table); + + /* There is no harm in calling an area recovery step */ +#if 0 + if (nsp_downsize_non_crit_gates(network, speed_param->model) && + 1 /* speed_param->debug */) { + (void)fprintf(sisout, "Downsizing helped !!!\n"); + } +#endif + +free_and_return: + /* + * Free all the configurations that were stored + */ + array_free(mincut); + array_free(network_array); + if (speed_param->debug > 1){ + (void)fprintf(sisout, ">>>> END RECURSION LEVEL %d\n\n", level); + } + return success; +} + /* + * Routine that will add area-saving transformations to the selections set + */ + +void +sp_expand_selection(speed_param, mincut, clp_table, select_table) +speed_global_t *speed_param; +array_t *mincut; +st_table *clp_table; /* table of weigths */ +st_table **select_table; /* RETURN: a table of the nodes finally used */ +{ + int i, k; + node_t *node; + sp_weight_t *wght; + st_generator *stgen; + + *select_table = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 0; i < array_n(mincut); i++){ + node = array_fetch(node_t *, mincut, i); + (void)st_insert(*select_table, (char *)node, NIL(char)); + } + k = st_count(*select_table); + if (speed_param->model != DELAY_MODEL_MAPPED){ + st_foreach_item(clp_table, stgen, (char **)&node, (char **)&wght){ + if (!st_is_member(*select_table, (char *)node) && + SP_IMPROVEMENT(wght) > NSP_EPSILON && SP_COST(wght) < 0){ + array_insert_last(node_t *, mincut, node); + (void)st_insert(*select_table, (char *)node, NIL(char)); + } + } + if ((array_n(mincut) > k)/* && speed_param->debug*/){ + (void)fprintf(sisout, "INFO: Added %d nodes for area saving\n", + array_n(mincut) - k); + } + } +} + /* Encapsulation that orders the nodes in a selection and also deletes + * the nodes that it thinks are not required !!! + */ +void +speed_reorder_cutset(speed_param, clp_table, mincut) +speed_global_t *speed_param; +st_table *clp_table; +array_t **mincut; +{ + array_t *new_mincut; + + new_mincut = speed_filter_cutset(*mincut, speed_param, clp_table); + array_free(*mincut); + *mincut = sp_generate_revised_order(new_mincut, speed_param, clp_table); + array_free(new_mincut); +} +/* + * This routine computes the amount "delta" by which the non-critical + * paths need to be sped up... Works for both the fanin or fanout based opt. + * The returned data contains the deltas for the PI's and PO's of the resynth + * regions based on the type of optimization .... + */ +static void +sp_compute_delta(network, speed_param, network_array, current_pos) +network_t *network; +speed_global_t *speed_param; +array_t *network_array; +int current_pos; +{ + int i; + double load; + array_t *temp; + lsGen gen, gen1; + node_t *node, *orig, *orig_fi, *pi; + double min_slack, delta; + delay_pin_t *pin_delay; + delay_time_t t, new, slack, new_slack; + delay_model_t model = speed_param->model; + sp_clp_t *rec = array_fetch(sp_clp_t *, network_array, current_pos); + sp_clp_t *temp_rec; + + rec->delta = array_alloc(double, 0); + if (rec->ti_model->type == CLP){ + new = (*rec->ti_model->arr_func) + (node_get_fanin(network_get_po(rec->net, 0), 0)); + new_speed_adjust_po_arrival(rec, rec->glb->model, &new); + + /* Compute the delta for the output: Difference between arrival times */ + delta = MIN((new.rise - rec->old.rise), (new.fall - rec->old.fall)); + array_insert_last(double, rec->delta, delta); + + /* Record original slacks of the inputs */ + temp = array_alloc(double, 0); + foreach_primary_input(rec->net, gen, node) { + orig = nsp_network_find_node(network, node_long_name(node)); + if (orig != NIL(node_t)){ + load = 0.0; + for (i = array_n(network_array); i-- > 0; ){ + if (i != current_pos){ + temp_rec = array_fetch(sp_clp_t *, network_array, i); + foreach_primary_input(temp_rec->net, gen1, pi){ + if (!strcmp(node_long_name(node), node_long_name(pi))){ + load += delay_load(pi); + } + } + } + } + pin_delay = get_pin_delay(node, 0, model); + t.rise = pin_delay->drive.rise * load; + t.fall = pin_delay->drive.fall * load; + slack = delay_slack_time(orig); + min_slack = MIN((slack.rise - t.rise), (slack.fall - t.fall)); + array_insert_last(double, temp, min_slack); + } else { + fail("Failed to find node corresponding to input "); + } + } + + /* Compute updated slacks using the original arrival time + * at the output. + */ + node = network_get_po(rec->net, 0); + delay_set_parameter(node, DELAY_REQUIRED_RISE, rec->old.rise); + delay_set_parameter(node, DELAY_REQUIRED_FALL, rec->old.fall); + delay_trace(rec->net, model); + + /* Compute deltas for the inputs. */ + /* delta = old_slack - new_slack */ + i = 0; + foreach_primary_input(rec->net, gen, node) { + slack = delay_slack_time(node); + min_slack = MIN(slack.rise, slack.fall); + delta = array_fetch(double, temp, i++) - min_slack; + array_insert_last(double, rec->delta, delta); + } + + array_free(temp); + + } else { + /* HERE --- do the same for the fanout delta : input req times*/ + delay_wire_required_time(network_get_pi(rec->net, rec->cfi), + 0, speed_param->model, &new); + /* Compute the delta for the critical input */ + delta = MIN((rec->old.rise - new.rise), (rec->old.fall - new.fall)); + array_insert_last(double, rec->delta, delta); + + /* Record original slacks of the outputs */ + temp = array_alloc(double, 0); + foreach_primary_output(rec->net, gen, node) { + slack = delay_slack_time(node); + min_slack = MIN(slack.rise, slack.fall); + array_insert_last(double, temp, min_slack); + } + + /* Compute updated slacks using the original required time + * as the input arrival time. + */ + node = network_get_pi(rec->net, rec->cfi); + delay_set_parameter(node, DELAY_ARRIVAL_RISE, rec->old.rise); + delay_set_parameter(node, DELAY_ARRIVAL_FALL, rec->old.fall); + delay_trace(rec->net, model); + + /* Compute deltas for the inputs. */ + /* delta = old_slack - new_slack */ + i = 0; + foreach_primary_output(rec->net, gen, node) { + slack = delay_slack_time(node); + min_slack = MIN(slack.rise, slack.fall); + delta = array_fetch(double, temp, i++) - min_slack; + array_insert_last(double, rec->delta, delta); + } + array_free(temp); + } + if (speed_param->debug > 1){ + (void)fprintf(sisout, "At %s INITIAL %.2f to %.2f DELTA %.2f\n", + rec->name, rec->old.rise, new.rise, + array_fetch(double, rec->delta, 0)); + } +} + +/* + * Depending on the adjustments made to the delays (due to load considerations) + * stored in "rec->adjust", the routine will change the arrival times of PI 's + */ +static void +sp_set_updated_constraints(rec, speed_param, network) +sp_clp_t *rec; +speed_global_t *speed_param; +network_t *network; +{ + node_t *node, *orig; + delay_time_t *t, old_const, new_const; + int improved = 0; + lsGen gen; + + if (rec->ti_model->type != CLP) return; + + foreach_primary_input(rec->net, gen, node){ + orig = network_find_node(network, node_long_name(node)); + if (orig != NIL(node_t)){ + new_const = delay_arrival_time(orig); + if (speed_param->debug > 1) { + speed_delay_arrival_time(node, speed_param, &old_const); + improved += ((old_const.rise > new_const.rise) && + (old_const.fall > new_const.fall)); + } + if (st_lookup(rec->adjust, (char *)orig, (char **)&t)){ + new_const.rise -= t->rise; + new_const.fall -= t->fall; + } + delay_set_parameter(node, DELAY_ARRIVAL_RISE, new_const.rise); + delay_set_parameter(node, DELAY_ARRIVAL_FALL, new_const.fall); + } + } + if (speed_param->debug > 1){ + (void)fprintf(sisout, "**** For %s --- %d of %d side paths improved\n", + rec->name, improved, network_num_pi(rec->net)); + } +} + +/* + * For the nodes in the d-critical-fanin, make a network that represents + * the original configuration of the collapsed node. This is required + * since we may want to reject the result of resynthesis. + */ +network_t * +sp_get_network_to_collapse(f, speed_param, areap) +node_t *f; +speed_global_t *speed_param; +double *areap; /* Returns the duplicated area */ +{ + network_t *net; + array_t *temp_array; /* Temp array for bfs implementation */ + st_table *table, *dup_nodes; + + if (f->type != INTERNAL) { + return NIL(network_t); + } + + table = st_init_table(st_ptrcmp, st_ptrhash); + temp_array = new_speed_collapse_bfs(f, speed_param, table); + + dup_nodes = st_init_table(st_ptrcmp, st_ptrhash); + *areap = sp_compute_duplicated_area(temp_array, table, dup_nodes, + DELAY_MODEL_UNKNOWN); + + /* + * Make a network consisting of the nodes in the "temp_aray". The + * primary inputs of this network are the fanins of the collapsed node. + */ + net = sp_generate_network_from_array(temp_array, speed_param); + + st_free_table(dup_nodes); + st_free_table(table); + array_free(temp_array); +/* + sprintf(dump, "write_blif /usr/tmp/test/test%d.blif", num++); + com_execute(&net, dump); +*/ + return net; +} + /* + * Set the amount of contribution of each input that is already in + * consideration when the load of the input node was computed. Used + * to evaluate the interaction of the different transformations + * NOTE: Overloading of the "max_ip_load" field... + */ +static void +nsp_set_initial_load(orig_netw, net, speed_param, dup_nodes) +network_t *orig_netw, *net; +speed_global_t *speed_param; +st_table *dup_nodes; +{ + int pin; + lsGen gen, gen1; + node_t *pi, *orig, *fo; + delay_pin_t *pin_delay; + double load; + + foreach_primary_input(net, gen, pi){ + load = 0.0; + foreach_fanout_pin(pi, gen1, fo, pin){ + orig = network_find_node(orig_netw, node_long_name(fo)); + if (orig != NIL(node_t) && !st_is_member(dup_nodes, (char *)orig)){ + pin_delay = get_pin_delay(fo, pin, speed_param->model); + load += pin_delay->load; + } + } + delay_set_parameter(pi, DELAY_MAX_INPUT_LOAD, load); + } +} +/* + * Returns an array of nodes that are within a distance "dist" along the + * critical paths of "f". "table" also record these elements, When the + * region_flag is set to ONLY_TREE, the distance metric is the number of + * trees along the critical path that are collapsed + */ +static array_t * +new_speed_collapse_bfs(f, speed_param, table) +node_t *f; +speed_global_t *speed_param; +st_table *table; +{ + int i, j, k; + node_t *temp, *inv_fi, *fi, *new_fanin; + array_t *temp_array; /* Temp array for bfs implementation */ + int should_add, need_to_add; + int new_dist, cur_dist, dist = speed_param->dist; + int more_to_come, first = 0, last; /* bfs traversal flags */ + double min_arr, max_arr; + delay_time_t a_t; + + temp_array = array_alloc(node_t *, 0); + array_insert_last(node_t *, temp_array, f); + if (speed_param->region_flag == ONLY_TREE){ + (void) st_insert(table, (char *)f, (char *)dist); + } else { + (void) st_insert(table, (char *)f, (char *)(dist+1)); + } + + more_to_come = TRUE; + while(more_to_come){ + more_to_come = FALSE; + last = array_n(temp_array); + for (j = first; j < last; j++){ + temp = array_fetch(node_t *, temp_array, j); + assert(st_lookup(table, (char *)temp, (char **)&cur_dist)); + + /* When this node reaches 1 => no further traversal required + * unless it is a tree in which case the tree is to be traversed + * NOTE: for the ONLY_TREE case, the termination of bfs will + * occur when there are no more gates in trees... + */ + if (speed_param->region_flag != ONLY_TREE && cur_dist == 1){ + continue; + } + if (speed_param->region_flag == ONLY_TREE && cur_dist < 0){ + continue; + } + + foreach_fanin(temp, k, fi) { + if (fi->type == INTERNAL && + !st_is_member(table, (char *)fi) /* Not yet visited */){ + + /* Depending on the select-flag add it */ + should_add = TRUE; + new_dist = cur_dist; + if (speed_param->region_flag != TRANSITIVE_FANIN){ + if (! speed_critical(fi, speed_param) ){ + /* not along the critical path */ + if (speed_param->region_flag != ONLY_TREE){ + should_add = FALSE; + } else if (node_num_fanout(fi) > 1){ + should_add = FALSE; /* Not part of tree */ + } else{ + /* No more traversal !!! Not even this tree */ + new_dist = -1; + } + } else if (speed_param->region_flag == ONLY_TREE){ + if (cur_dist <= 0 && node_num_fanout(fi) > 1 && + node_num_fanin(fi) > 1 ){ + /* complex critical input at tree edge !!! */ + should_add = FALSE; + } + } + } + if (should_add){ + /* + * Add to list and set the correct distance in table + */ + if (speed_param->region_flag == ONLY_TREE) { + if (node_num_fanout(fi) == 1){ + /* Distance is unchanged */ + (void)st_insert(table, (char *)fi, + (char *)(new_dist)); + array_insert_last(node_t *, temp_array, fi); +/* + (void)fprintf(sisout, "%s -> %s(%d) : fo= %d, fi = %d\n", temp->name, + fi->name, new_dist, node_num_fanout(fi), node_num_fanin(fi)); +*/ + } else if (cur_dist >= 0) { + /* + * Traverse any chains of inverters adding + * (if appropriate) to temp array + */ + need_to_add = TRUE; + while (node_num_fanin(fi) == 1){ + if (st_is_member(table, (char *)fi)){ + need_to_add = FALSE; + break; + } + (void)st_insert(table, (char *)fi, + (char *)(new_dist-1)); + array_insert_last(node_t *,temp_array, fi); +/* + (void)fprintf(sisout, "%s -> INV %s(%d) : fo= %d, fi = %d\n", temp->name, + fi->name, new_dist-1,node_num_fanout(fi), node_num_fanin(fi)); +*/ + inv_fi = node_get_fanin(fi, 0); + fi = inv_fi; + } + if (fi->type == PRIMARY_INPUT || + st_is_member(table, (char *)fi) || + cur_dist == 0) { + need_to_add = FALSE; + } + + if (need_to_add){ + /* Reduce distance since a tree is crossed */ + array_insert_last(node_t *,temp_array, fi); + (void)st_insert(table, (char *)fi, + (char *)(new_dist-1)); +/* + (void)fprintf(sisout, "%s -> %s(%d) : fo= %d, fi = %d\n", temp->name, + fi->name, new_dist-1,node_num_fanout(fi), node_num_fanin(fi)); +*/ + } + } + } else { + (void)st_insert(table, (char *)fi, (char *)(new_dist-1)); + array_insert_last(node_t *, temp_array, fi); + } + more_to_come = TRUE; + } + } + } + } + first = last; + } + + /* COMPROMISE looks at the inputs of the critical region to include */ + if (speed_param->region_flag == COMPROMISE){ + /* determine the range of arrival times of the critical region */ + min_arr = POS_LARGE; + max_arr = NEG_LARGE; + for ( i = 0; i < array_n(temp_array); i++){ + temp = array_fetch(node_t *, temp_array, i); + foreach_fanin(temp, j, fi){ + if (!st_is_member(table, (char *)fi)){ + a_t = delay_arrival_time(fi); + min_arr = MIN(min_arr, MIN(a_t.rise, a_t.fall)); + max_arr = MAX(max_arr, MAX(a_t.rise, a_t.fall)); + } + } + } + /* Add the approporiate nodes to the critical region */ + first = 0; + more_to_come = TRUE; + while (more_to_come) { + more_to_come = FALSE; + last = array_n(temp_array); + for ( i = first; i < last; i++){ + temp = array_fetch(node_t *, temp_array, i); + assert(st_lookup(table, (char *)temp, (char **)&cur_dist)); + foreach_fanin(temp, j, fi){ + if (!st_is_member(table, (char *)fi) && + cur_dist > 1 ){ /* Distance limit is not exceeded */ + /* + * Input to the critical region -- Check if the delay + * data warrants an addition into the critical region + */ + should_add = FALSE; + foreach_fanin(fi, k, new_fanin){ + a_t = delay_arrival_time(new_fanin); + if (a_t.rise >= min_arr && a_t.fall >= min_arr){ + should_add = TRUE; + } + } + if (should_add){ + array_insert_last(node_t *, temp_array, fi); + st_insert(table, (char *)fi, (char *)(cur_dist-1)); + } + } + } + } + first = last; + } + if (speed_param->debug > 2){ + (void)fprintf(sisout, "At %s COMPROMISE added %d nodes in [%.2f %.2f]\n", + node_name(f), (array_n(temp_array) - last), min_arr, max_arr); + for ( i = last; i < array_n(temp_array); i++){ + temp = array_fetch(node_t *, temp_array, i); + node_print(sisout, temp); + } + } + } + + return temp_array; +} +/* + * Create a network containing the nodes in "node_array". + */ +static network_t * +sp_generate_network_from_array(node_array, speed_param) +array_t *node_array; /* Nodes to be collapsed into node "f" */ +speed_global_t *speed_param; +{ + int i, j; + char *name; + double load; + network_t *net; + lib_gate_t *gate; + delay_time_t drive, a_t; + st_table *gate_table, *dup_table, *pi_table; + node_t *node, *po_node, *pi_node, *dup_node, *dup_fi, *fi; + + net = network_alloc(); + dup_table = st_init_table(st_ptrcmp, st_ptrhash); + gate_table = st_init_table(st_ptrcmp, st_ptrhash); + pi_table = st_init_table(st_ptrcmp, st_ptrhash); + + /* Visit nodes in reverse order -- inputs to outputs */ + for (i = array_n(node_array); i-- > 0; ){ + node = array_fetch(node_t *, node_array, i); + dup_node = node_dup(node); + if ((gate = lib_gate_of(node)) != NIL(lib_gate_t)){ + (void)st_insert(gate_table, (char *)dup_node, (char *)gate); + } else if (speed_param->model == DELAY_MODEL_MAPPED){ + (void)fprintf(sisout, "WARN: unmapped node in mapped opt\n"); + } + (void)st_insert(dup_table, (char *)node, (char *)dup_node); + } + + /* + * Add the nodes --- make sure that the fanins to the added nodes + * point to nodes in the network being generated... + */ + for (i = array_n(node_array); i-- > 0; ){ + node = array_fetch(node_t *, node_array, i); + assert(st_lookup(dup_table, (char *)node, (char **)&dup_node)); + foreach_fanin(node, j, fi){ + if (st_lookup(dup_table, (char *)fi, (char **)&dup_fi)){ + dup_node->fanin[j] = dup_fi; + } else { + if (!st_lookup(pi_table, (char *)fi, (char **)&pi_node)){ + pi_node = node_alloc(); + network_add_primary_input(net, pi_node); + name = ALLOC(char, strlen(fi->name)+10); + sprintf(name, "%s%c%d", fi->name, NSP_INPUT_SEPARATOR, j); + network_change_node_name(net, pi_node, name); + (void)st_insert(pi_table, (char *)fi, (char *)pi_node); + /* + * Add the delay data for the primary input node + */ + a_t = delay_arrival_time(fi); + delay_set_parameter(pi_node, DELAY_ARRIVAL_RISE, a_t.rise); + delay_set_parameter(pi_node, DELAY_ARRIVAL_FALL, a_t.fall); + + /* For mapped ckts: set the drives : max_ip_load + * is set by the routine nsp_set_initial_load() + */ +/* + pin_delay = get_pin_delay(node, j, speed_param->model); + delay_set_parameter(pi_node, DELAY_MAX_INPUT_LOAD, + pin_delay->load); +*/ + drive = nsp_get_input_drive(fi, speed_param->model); + delay_set_parameter(pi_node, DELAY_DRIVE_RISE, drive.rise); + delay_set_parameter(pi_node, DELAY_DRIVE_FALL, drive.fall); + } + dup_node->fanin[j] = pi_node; + } + } + network_add_node(net, dup_node); + if (st_lookup(gate_table, (char *)dup_node, (char **)&gate)){ + buf_add_implementation(node, gate); + } + } + /* Create the PO node from the last (root) node added */ + load = delay_load(node); + po_node = network_add_primary_output(net, dup_node); + delay_set_parameter(po_node, DELAY_OUTPUT_LOAD, load); + network_set_name(net, node_long_name(node)); + + /* Also add the wire_load slope and all that default stuff */ + delay_network_dup(net, node_network(node)); + + if(!network_check(net)) fail(error_string()); + if(st_count(gate_table) > 0 && !lib_network_is_mapped(net)){ + (void)fprintf(sisout, "WARN: COLLAPSED network copy in not mapped\n"); + } + + st_free_table(dup_table); + st_free_table(pi_table); + st_free_table(gate_table); + + return net; +} +/* + * Compute the worst drive that this node can offere to any load + */ +static delay_time_t +nsp_get_input_drive(node, model) +node_t *node; +delay_model_t model; +{ + int i; + delay_time_t drive; + delay_pin_t *pin_delay; + + if (node->type == PRIMARY_INPUT){ + pin_delay = get_pin_delay(node, 0, model); + return (pin_delay->drive); + } else { + drive.rise = drive.fall = NEG_LARGE; + for (i = node_num_fanin(node); i-- > 0; ) { + pin_delay = get_pin_delay(node, i, model); + drive.rise = MAX(drive.rise, pin_delay->drive.rise); + drive.fall = MAX(drive.fall, pin_delay->drive.fall); + } + return drive; + } +} +/* + * Decompose the network based on arrival times + */ +static void +sp_do_initial_resynthesis(rec) +sp_clp_t *rec; +{ + int tmp; + node_t *np; + delay_time_t new; + network_t *opt_netw; + + tmp = rec->glb->debug; + rec->glb->debug = FALSE; + opt_netw = (*rec->ti_model->optimize_func)(rec->net, rec->ti_model, + rec->glb); + network_free(rec->net); + rec->net = opt_netw; + + rec->glb->debug = tmp; + if (rec->ti_model->type == FAN){ + np = network_get_pi(rec->net, rec->cfi); + new = delay_required_time(np); + /* HERE -- should account for load of PREV gate !!! */ + } else if (rec->ti_model->type == DUAL){ + fail("write this"); + np = network_get_pi(rec->net, rec->cfi); + new = delay_required_time(np); + } else { + new = (*rec->ti_model->arr_func)(network_get_po(rec->net,0), rec->glb); + new_speed_adjust_po_arrival(rec, rec->glb->model, &new); + } + if (rec->glb->debug){ + (void)fprintf(sisout, "At %10s \"%s\" new= %.2f:%.2f old= %.2f:%.2f CS=%.2f \n", + network_name(rec->net), rec->ti_model->name, new.rise, + new.fall, rec->old.rise, rec->old.fall, rec->glb->crit_slack); + } +} + +/* + * Ensure that it is not the case that a node in the cutset will be removed + * when the critical region of another node in the cutset is collapsed. + * Why this can happen still needs to be explained (Has to do with using + * the way the flow network is created)... + */ +static array_t * +speed_filter_cutset(mincut, speed_param, weight_table) +array_t *mincut; +speed_global_t *speed_param; +st_table *weight_table; +{ + lsGen gen; + int i, j, k, first, last; + int save_node, more_to_come; + sp_weight_t *wght, *root_wght; + node_t *node, *root, *temp, *fo; + array_t *temp_array, *bfs_array, *actual_mincut; + st_table *table, *del_table; + + del_table = st_init_table(st_ptrcmp, st_ptrhash); + for (i = array_n(mincut); i-- > 0; ){ + /* Get rid of the nodes where there is no improvement possible */ + root = array_fetch(node_t *, mincut, i); + (void)st_lookup(weight_table, (char *)root, (char **)&root_wght); + if (root_wght->improvement[root_wght->best_technique] < NSP_EPSILON){ + (void)st_insert(del_table, (char *)root, NIL(char)); + continue; + } + /* + * Generate the nodes that lie within the collapsing distance. + */ + table = st_init_table(st_ptrcmp, st_ptrhash); + bfs_array = new_speed_collapse_bfs(root, speed_param, table); + array_free(bfs_array); + + /* For all the other nodes, check if they need to be deleted */ + for (j = array_n(mincut); j-- > 0; ){ + if (i == j) continue; + node = array_fetch(node_t *, mincut, j); + (void)st_lookup(weight_table, (char *)node, (char **)&wght); + if (st_is_member(table, (char *)node)){ + /* + * Check if the path from "node" to "root" has no fanouts + */ + first = 0; + save_node = FALSE; more_to_come = TRUE; + temp_array = array_alloc(node_t *, 0); + array_insert_last(node_t *, temp_array, node); + while (more_to_come){ + more_to_come = FALSE; + last = array_n(temp_array); + for ( k = first; k < last && save_node == FALSE; k++){ + temp = array_fetch(node_t *, temp_array, k); + if (temp == root) { + /* reached the root */ + continue; + } + foreach_fanout(temp, gen, fo){ + if (st_is_member(table, (char *)fo)){ + array_insert_last(node_t *, temp_array, fo); + } else { + save_node = TRUE; + } + } + } + first = last; + if (save_node) { + /* Some node fans out --- no need to continue */ + more_to_come = FALSE; + } + } + if (save_node == FALSE){ + st_insert(del_table, (char *)node, (char *)root); + if (speed_param->debug) { + (void)fprintf(sisout, + "%s (%.2f) in TFI of %s (%.2f)\n", + node->name, SP_IMPROVEMENT(wght), + root->name, SP_IMPROVEMENT(root_wght)); + } + } + array_free(temp_array); + } + } + st_free_table(table); + } + + /* + * Now put all unmarked node in the actual array + */ + actual_mincut = array_alloc(node_t *, array_n(mincut)); + for( i = array_n(mincut); i-- > 0; ){ + node = array_fetch(node_t *, mincut, i); + if (!st_is_member(del_table, (char *)node)){ + array_insert_last(node_t *, actual_mincut, node); + } + } + + if (speed_param->debug && array_n(mincut) > array_n(actual_mincut)){ + (void)fprintf(sisout, "NOTE: %d spurious nodes deleted from cut\n", + array_n(mincut) - array_n(actual_mincut)); + } + st_free_table(del_table); + + return (actual_mincut); +} + + + + + + + + + + + + diff --git a/sis/speed/new_speed_models.h b/sis/speed/new_speed_models.h new file mode 100644 index 0000000..d9a562b --- /dev/null +++ b/sis/speed/new_speed_models.h @@ -0,0 +1,49 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/new_speed_models.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ + + /* + * To avoid an extra sorting operation, It is REQUIRED that the transforms + * be listed in decreasing priority. Lower value of priority means that the + * transform is preferred. If there is a saving from low valued + * transforms, the higher ones are not evaluated + */ + +static sp_xform_t local_transforms[] = { +/* name, optimization fn, delay computing fn, priority, on-flag, netw-flag */ + + {"noalg", sp_noalg_opt, new_delay_arrival, 0, 0, CLP}, + {"repower", sp_fanout_opt, new_delay_required, 0, 0, FAN}, + {"fanout", sp_fanout_opt, new_delay_required, 1, 0, FAN}, + {"duplicate", sp_duplicate_opt, new_delay_required, 1, 0, FAN}, + {"and_or", sp_and_or_opt, new_delay_arrival, 2, 0, CLP}, + {"divisor", sp_divisor_opt, new_delay_arrival, 2, 1, CLP}, + {"2c_kernel", sp_2c_kernel_opt, new_delay_arrival, 2, 0, CLP}, + {"comp_div", sp_comp_div_opt, new_delay_arrival, 2, 0, CLP}, + {"comp_2c", sp_comp_2c_opt, new_delay_arrival, 2, 0, CLP}, + {"cofactor", sp_cofactor_opt, new_delay_arrival, 2, 0, CLP}, + {"bypass", sp_bypass_opt, new_delay_arrival, 2, 0, CLP}, + {"dualize", sp_dual_opt, new_delay_slack, 2, 0, DUAL}, +}; + + + + + + + + + + + + + + + + diff --git a/sis/speed/new_wght_util.c b/sis/speed/new_wght_util.c new file mode 100644 index 0000000..6840980 --- /dev/null +++ b/sis/speed/new_wght_util.c @@ -0,0 +1,1685 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/new_wght_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include <math.h> + +static void nsp_print_bdd(); +static void sp_compute_improvement(); +static void nsp_create_relevant_data(); +static void nsp_eval_best_transform(); +static void nsp_compute_achievable_saving(); +static int nsp_trivial_mapped_network(); +static int nsp_eval_selection(); + +#define NSP_BDD_LIMIT 100000 +#define NSP_MAXSTR 256 +#define ACCEPTABLE_FRACTION 0.2 /* Fraction of predicted impr */ +#define MIN_ACCEPTABLE_SAVING 0.01 /* Limit to quit binary search */ + +#define IS_ZERO(v) (ABS((v)) < NSP_EPSILON) + +/* Some data structure to carry information about what scopes to generate */ +struct create_flag_struct { + int create_clp; + int create_fanout; + int create_dual; +}; + +static nsp_num_char; /* Records the number of characters printed on a line */ +static array_t *fi_nodes; +static array_t *ip_slacks; + +/* + * Compute the area cost of applying a transformation. + * Only the transformations that save more than epsilon (determined) are + * considered.... + */ +void +new_speed_compute_weight(network, + speed_param, wght_table, epsilonp) +network_t *network; +speed_global_t *speed_param; +st_table *wght_table; /* Returns information pertinent to the collapsing */ +double *epsilonp; +{ + lsGen gen; + int pass = 0; + node_t *np, *node, *fanin; + sp_weight_t *wght; + struct create_flag_struct create_flag; + int num_crit_po, need_another_pass; + delay_time_t slack, min_slack, new_min_slack; + double new_thresh, new_crit_slack, min_po_slack; + double impr, sl, min_epsilon, max_epsilon, slack_diff; + array_t *new_crit_po_array; + st_table *new_crit_table; + st_generator *stgen; + + *epsilonp = 0; + + new_crit_table = NIL(st_table); + new_crit_po_array = NIL(array_t); + /* Initialize the static arrays used in nsp_compute_achievable..() */ + fi_nodes = array_alloc(node_t *, 0); + ip_slacks = array_alloc(double, 0); + + /* Set the types of networks that are to be created */ + create_flag.create_fanout = + (sp_num_local_trans_of_type(speed_param, FAN) > 0 && + speed_param->model == DELAY_MODEL_MAPPED); + create_flag.create_dual = + (sp_num_local_trans_of_type(speed_param, DUAL) > 0); + create_flag.create_clp = + (sp_num_local_trans_of_type(speed_param, CLP) > 0); + min_po_slack = min_slack.rise = min_slack.fall = POS_LARGE; + foreach_primary_output(network, gen, node){ + slack = delay_slack_time(node); + min_slack.rise = MIN(min_slack.rise, slack.rise); + min_slack.fall = MIN(min_slack.fall, slack.fall); + min_po_slack = MIN(min_po_slack, MIN(slack.rise, slack.fall)); + } + + if (min_po_slack > NSP_EPSILON){ + /* + * Timing constraints are met: nothing needs to be done + * Since the epsilon_p is zero, new_speed_recur() will + * end without any further work + */ + return; + } + + do { + pass++; + if (new_crit_table != NIL(st_table)){ + st_free_table(new_crit_table); + } + new_crit_table = st_init_table(st_ptrcmp, st_ptrhash); + nsp_num_char = 0; + + if (speed_param->debug){ + (void)fprintf(sisout, "\nPass %d: Computing weigths, crit_slack = %.2f\n", + pass, speed_param->crit_slack); + } + + /* Process all the critcal nodes not yet visited */ + foreach_node(network, gen, np) { + if (np->type != PRIMARY_OUTPUT) { + if (speed_critical(np, speed_param) && + !st_is_member(wght_table, (char *)np) ) { + wght = ALLOC(sp_weight_t, 1); + /* Generate scope for transformations */ + nsp_create_relevant_data(network, np, speed_param, + wght, &create_flag); + st_insert(wght_table, (char *)np, (char *)wght); + st_insert(new_crit_table, (char *)np, (char *)wght); + + /* + * Now apply transformations and compute the + * improvement that is possible at np + */ + nsp_eval_best_transform(np, wght, speed_param); + } + } + } + + if (speed_param->debug){ + (void)fprintf(sisout, "\nPass %d: Computed weigthts of %d nodes\n", + pass, st_count(new_crit_table)); + } + + /* + * Now compute the savings that can be achieved. + */ + nsp_compute_achievable_saving(network, speed_param, wght_table); + + /* + * Now find the minimum guaranteed saving at the PO nodes + */ + min_epsilon = POS_LARGE; + max_epsilon = NEG_LARGE; + new_min_slack.rise = new_min_slack.fall = POS_LARGE; + foreach_primary_output(network, gen, node){ + slack = delay_slack_time(node); + if (speed_critical(node, speed_param)){ + fanin = node_get_fanin(node, 0); + if (node_type(fanin) == INTERNAL){ + assert(st_lookup(wght_table, (char *)fanin, (char **)&wght)); + impr = wght->epsilon; + } else { + /* PI is connected to the PO: no improvement possible */ + impr = 0.0; + } + min_epsilon = MIN(min_epsilon, impr); + max_epsilon = MAX(max_epsilon, impr); + new_min_slack.rise = MIN(new_min_slack.rise, + (slack.rise + impr)); + new_min_slack.fall = MIN(new_min_slack.fall, + (slack.fall + impr)); + sl = MIN(slack.rise, slack.fall); + if (speed_param->debug > 1){ + (void)fprintf(sisout, "PO %s : new slack = %.2f + %.2f = %.2f\n", + node_name(node), sl, impr, sl+impr); + } + } + } + new_crit_slack = MIN(new_min_slack.rise, new_min_slack.fall); + new_thresh = new_crit_slack - min_po_slack; + + /* Adjust the new slack for floating point comparisons */ + new_min_slack.rise -= NSP_EPSILON; + new_min_slack.fall -= NSP_EPSILON; + if (speed_param->debug) { + (void)fprintf(sisout, "Guaranteed saving = %.2f\n", new_thresh); + } + new_thresh = MAX(0.0, new_thresh); + + /* + * If this improvement is acheived, then there are other outputs + * that would be more critical. Find these and modify the threshold + * appropriately + */ + if (new_crit_po_array != NIL(array_t)){ + array_free(new_crit_po_array); + } + new_crit_po_array = array_alloc(node_t *, 0); + num_crit_po = 0; + foreach_primary_output(network, gen, node){ + slack = delay_slack_time(node); + if (speed_critical(node, speed_param)){ + num_crit_po++; + } else if ((slack.rise < new_min_slack.rise || + slack.fall < new_min_slack.fall)){ + array_insert_last(node_t *, new_crit_po_array, node); + num_crit_po++; + } + } + if (speed_param->debug){ + (void)fprintf(sisout, "%d (%d new) critical PO's: thresh = %.2f\n", + num_crit_po, array_n(new_crit_po_array), new_thresh); + } + + /* Set the new threshold */ + *epsilonp = new_thresh; + + /* + * Need to make at most two passes, Second pass needed only if the + * new_thresh exceeds the original threshold used for the first pass + */ + need_another_pass = ((pass < 2) && (new_thresh > speed_param->thresh)); + if (need_another_pass) { + speed_param->crit_slack = new_crit_slack; + } + } while (need_another_pass); + + if (speed_param->debug > 2){ + st_foreach_item(wght_table, stgen, (char **)&np, (char **)&wght){ + (void)fprintf(sisout, "At %s %d D=%.2f A=%.2f (da=%.2f oa=%.2f)\n", + np->name, wght->best_technique, + SP_IMPROVEMENT(wght), SP_COST(wght), + wght->dup_area, wght->orig_area); + } + } + array_free(new_crit_po_array); + st_free_table(new_crit_table); + array_free(fi_nodes); + array_free(ip_slacks); + /* Reset the caches that were used during local transformations */ + nsp_free_buf_param(); +} + +/* + * Routine to generate the networks on which the local transformations are + * carried out and some data that may be corrupted by subsequent delay + * traces + */ +static void +nsp_create_relevant_data(network, np, speed_param, wght, flags) +network_t *network; +node_t *np; +speed_global_t *speed_param; +sp_weight_t *wght; +struct create_flag_struct *flags; +{ + lib_gate_t *gate; + int sp_num_models = array_n(speed_param->local_trans); + delay_pin_t *pin_delay; + double auto_load; + + /* Initialize some data that is always required */ + wght->clp_netw = wght->fanout_netw = wght->dual_netw = wght->best_netw + = NIL(network_t); + wght->best_technique = -1; + wght->select_flag = FALSE; + wght->improvement = NIL(double); + wght->area_cost = NIL(double); + wght->dup_area = 0.0; + wght->orig_area = 0.0; + +#ifdef SIS + /* Do not consider the internal nodes that are part of latches */ + if ((gate = lib_gate_of(np)) != NIL(lib_gate_t) && + lib_gate_type(gate) != COMBINATIONAL) { + return; + } +#endif /* SIS */ + + /* For the case of TREE based selection strategy, we restrict the + optimizations only to the root of the trees. By doing this, the + computation cost of the transforms is reduced. The restriction + is carried out by making the stored network == NIL() */ + if (speed_param->region_flag == ONLY_TREE){ + if (node_num_fanout(np) <= 1 && !new_speed_is_fanout_po(np)){ + return; + } + } + + /* Now generate the relevant networks */ + if (flags->create_clp){ + wght->clp_netw = sp_get_network_to_collapse(np, speed_param, + &(wght->dup_area)); + } + auto_load = delay_get_default_parameter(network, DELAY_WIRE_LOAD_SLOPE); + auto_load = (auto_load == DELAY_NOT_SET ? 0.0 : auto_load); + if (flags->create_fanout){ + wght->fanout_netw = + buf_get_fanout_network(np, speed_param); + wght->cfi = -1; + wght->cfi = sp_buf_get_crit_fanin(np, speed_param->model); + if (np->type == INTERNAL){ + pin_delay = get_pin_delay(np, wght->cfi, speed_param->model); + wght->cfi_load = pin_delay->load + auto_load; + } else { + wght->cfi_load = delay_load(np); + } + delay_wire_required_time(np, wght->cfi, speed_param->model, + &wght->cfi_req); + } + if (flags->create_dual){ + wght->dual_netw = nsp_get_dual_network(np, speed_param); + } + + wght->orig_area = sp_get_netw_area(wght->clp_netw); + wght->arrival_time = delay_arrival_time(np); + wght->slack = delay_slack_time(np); + wght->load = delay_load(np); + wght->crit_slack = speed_param->crit_slack; + + wght->can_invert = 1 - new_speed_is_fanout_po(np); + wght->improvement = ALLOC(double, sp_num_models); + wght->area_cost = ALLOC(double, sp_num_models); + + return; +} + +/* + * Evaluate the local transformations on the appropriate scopes and + * determine the best transform. Also, remove the networks that are + * not required (since the best transform does not use them) to save space + */ +static void +nsp_eval_best_transform(np, wght, speed_param) +node_t *np; +sp_weight_t *wght; +speed_global_t *speed_param; +{ + int i, j; + double best_imp, cur_impr, best_area, cur_area; + int sp_num_models = array_n(speed_param->local_trans); + network_t *opt_netw; + sp_xform_t *local_trans; + + best_imp = NEG_LARGE; + for(i = 0; i < sp_num_models; i++){ + local_trans = sp_local_trans_from_index(speed_param, i); + if (local_trans->on_flag){ + j = speed_param->debug; + speed_param->debug = FALSE; + opt_netw = NSP_OPTIMIZE(wght, local_trans, speed_param); + speed_param->debug = j; + + if (opt_netw == NIL(network_t)) { + cur_area = POS_LARGE; + cur_impr = NEG_LARGE; + } else { + sp_compute_improvement(np, opt_netw, wght, speed_param, + i, local_trans); + + /* Accept the first or one that betters the previous*/ + cur_area = wght->area_cost[i]; + cur_impr = wght->improvement[i]; + + if (best_imp == NEG_LARGE) { + best_imp = cur_impr; best_area = cur_area; + wght->best_technique = i; + } else if (IS_ZERO(cur_impr-best_imp)){ + /* Select the technique with the smaller area penalty*/ + if (cur_area < best_area){ + wght->best_technique = i; + best_area = cur_area; + } + } else if (cur_impr > NSP_EPSILON){ + if (speed_param->transform_flag == BEST_BENEFIT) { + if (cur_impr > best_imp){ + best_imp = cur_impr; best_area = cur_area; + wght->best_technique = i; + } + } else { + /* Use the BENEFIT/COST metric for selection */ + if (best_imp < NSP_EPSILON){ + best_imp = cur_impr; best_area = cur_area; + wght->best_technique = i; + } else if (!IS_ZERO(cur_area) && !IS_ZERO(best_area)) { + if ((cur_area < 0.0 && best_area > 0.0) || + (cur_area > 0.0 && best_area > 0.0 && + (cur_impr/cur_area) > (best_imp/best_area)) || + (cur_area < 0.0 && best_area < 0.0 && + (cur_impr/cur_area) < (best_imp/best_area))) { + best_imp = cur_impr; best_area = cur_area; + wght->best_technique = i; + } + } else if ((IS_ZERO(cur_area) && best_area > 0.0) || + (IS_ZERO(best_area) && cur_area < 0.0)){ + best_imp = cur_impr; best_area = cur_area; + wght->best_technique = i; + } + } + } + } + + if(speed_param->debug){ + fputc((cur_impr > 0 ? '+' : '-'), sisout); + (void)fflush(sisout); + nsp_num_char++; + } + sp_network_free(opt_netw); + } + } + if (speed_param->debug){ + fputc('|', sisout); nsp_num_char++; + if (nsp_num_char > 70){ + fputc('\n', sisout); + nsp_num_char = 0; + } + } + if (speed_param->debug > 1){ + (void)fprintf(sisout, "At %s (%d) D=%.2f A=%.2f (da=%.2f oa=%.2f)\n", + np->name, wght->best_technique, + SP_IMPROVEMENT(wght), SP_COST(wght), + wght->dup_area, wght->orig_area); + } + /* If there is no improvement set the stuff appropriately */ + if (best_imp < NSP_EPSILON){ + wght->best_technique = -1; + /* Delete the networks --- should never need them */ + sp_network_free(wght->clp_netw); + sp_network_free(wght->fanout_netw); + } + /* Also remove the networks that are not required */ + if (wght->best_technique >= 0 && SP_IMPROVEMENT(wght) > NSP_EPSILON){ + local_trans = sp_local_trans_from_index(speed_param, + wght->best_technique); + if (local_trans->type != CLP) sp_network_free(wght->clp_netw); + if (local_trans->type != FAN) sp_network_free(wght->fanout_netw); + if (local_trans->type != DUAL) sp_network_free(wght->dual_netw); + } + return; +} +/* + * The network has been optimized according to the "local_trans->optimize_func" + * Use the appropriate delay_model to compute the arrival time of the optimized + * network and compute the delay saving and the area penalty, The current + * technique is numbered "num".... + * + * Assume that the delay trace has been done by the optimization routine + * + */ + +static void +sp_compute_improvement(node, opt_netw, wght, speed_param, num, + local_trans) +node_t *node; /* The node at which the transform is applied */ +network_t *opt_netw; /* The optimized network */ +sp_weight_t *wght; /* The structure stored with "node" */ +speed_global_t *speed_param; /* GLobals */ +int num; /* Index of the transformation !! */ +sp_xform_t *local_trans; /* The local transform structure */ +{ + node_t *root, *fanin, *po; + delay_pin_t *pin_delay; + double impr, load_diff, auto_load; + delay_time_t t, drive, po_impr, po_arr, pi_req; + + if (opt_netw == NIL(network_t)){ /* Ignore it !!! Should not be called */ + return; + } + + auto_load = delay_get_default_parameter(node_network(node), + DELAY_WIRE_LOAD_SLOPE); + auto_load = (auto_load == DELAY_NOT_SET ? 0.0 : auto_load); + + impr = 0.0 - NSP_EPSILON; /* By default no improvement possible */ + + if (local_trans->type == FAN){ + /* + * Get the change in required time at input of root node + * The node under consideration may be a PI, so be careful + */ + if (node->type == PRIMARY_INPUT){ + fanin = network_get_pi(opt_netw, 0); + delay_wire_required_time(fanin, 0, speed_param->model, &pi_req); + load_diff = delay_compute_fo_load(fanin, speed_param->model) - wght->cfi_load; + } else { + root = node_get_fanout(network_get_pi(opt_netw, 0), 0); + fanin = node_get_fanin(root, wght->cfi); + delay_wire_required_time(root, wght->cfi, speed_param->model, &pi_req); + pin_delay = get_pin_delay(root, wght->cfi, speed_param->model); + load_diff = (auto_load + pin_delay->load) - wght->cfi_load; + } + /* + * Adjust the required time based on the difference in loading + */ + assert(delay_get_pi_drive(fanin, &drive)); + pi_req.rise -= (drive.rise * load_diff); + pi_req.fall -= (drive.fall * load_diff); + impr = MIN((pi_req.rise - wght->cfi_req.rise), + (pi_req.fall - wght->cfi_req.fall)); + } else if (local_trans->type == DUAL) { + /* Check the improvement in the slack of the network */ + fail("Need to find the slack impr on dualizing\n"); + } else { + /* + * Determine if something sensible has been done --- + * In case the nodes were part of a fanout tree the "mapped" + * transform is not the right one (since it is the required time that + * is of significance) so set the improvement to be zero !!! + */ + if (nsp_trivial_mapped_network(opt_netw)){ + impr = -1.0; /* set < 0 just to be sure it is not considered */ + } else { + /* Find out the decrease in arrival time at o/p of node */ + po = network_get_po(opt_netw, 0); + po_arr = (*local_trans->arr_func)(po, speed_param); + root = node_get_fanin(po, 0); + if (node_num_fanin(root) == 1 && wght->can_invert && + speed_param->model != DELAY_MODEL_MAPPED){ + t = nsp_compute_delay_saving(po, root, speed_param->model); + po_arr.rise -= t.rise; + po_arr.fall -= t.fall; + } + po_impr.rise = wght->arrival_time.rise - po_arr.rise; + po_impr.fall = wght->arrival_time.fall - po_arr.fall; + impr = MIN(po_impr.rise, po_impr.fall); + } + } + /* + * Ignoring interaction with other cutset members --- this is the + * amount of saving that is the result of this transformation + */ + wght->improvement[num] = impr; + + /* + * Compute the area penalty that results from applying the transformation + */ + if (local_trans->type == FAN){ + wght->area_cost[num] = sp_get_netw_area(opt_netw); + } else { + wght->area_cost[num] = (sp_get_netw_area(opt_netw) + + wght->dup_area) - wght->orig_area; + } +} + +/* + * Routine to compute the saving that can be achieved at a node (the delta + * values). Assumes that the computation of local improvement has been made + */ +static void +nsp_compute_achievable_saving(network, speed_param, wght_table) +network_t *network; +speed_global_t *speed_param; +st_table *wght_table; +{ + int i, j; + array_t *nodevec; + node_t *node, *fanin; + double local_impr, inp_eps, min_ip_slack, sl; + delay_time_t req, arr, slack; + sp_weight_t *wght, *ip_wght; + int all_fanins_pi; + int crit_ip_count; /* Number of fanins of a node that are critical */ + + nodevec = network_dfs(network); + for (i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + if (st_lookup(wght_table, (char *)node, (char **)&wght)){ + inp_eps = POS_LARGE; + all_fanins_pi = TRUE; + if (speed_param->debug > 1) { + (void)fprintf(sisout, "EPS %s (%s) --", + node_name(node), node_long_name(node)); + } + min_ip_slack = POS_LARGE; + crit_ip_count = 0; + foreach_fanin(node, j, fanin){ + if (st_lookup(wght_table, (char *)fanin, (char **)&ip_wght)){ + + assert(delay_wire_required_time(node, j, speed_param->model, &req)); + arr = delay_arrival_time(fanin); + slack.rise = req.rise - arr.rise; + slack.fall = req.fall - arr.fall; + sl = MIN(slack.rise, slack.fall); + if (sl < speed_param->crit_slack - NSP_EPSILON){ + min_ip_slack = MIN(min_ip_slack, sl); + all_fanins_pi = FALSE; + array_insert(double, ip_slacks, crit_ip_count, sl); + array_insert(node_t *, fi_nodes, crit_ip_count, fanin); + crit_ip_count++; + } + + } + } + for (j = 0; j < crit_ip_count; j++){ + sl = array_fetch(double, ip_slacks, j); + fanin = array_fetch(node_t *, fi_nodes, j); + st_lookup(wght_table, (char *)fanin, (char **)&ip_wght); + + inp_eps = MIN(inp_eps, + (ip_wght->epsilon + sl - min_ip_slack)); + if (speed_param->debug > 1){ + (void)fprintf(sisout," (%5.2f+%5.2f)%s", + ip_wght->epsilon, sl - min_ip_slack, + fanin->name); + } + } + + if (all_fanins_pi){ + inp_eps = 0.0; + } else if (inp_eps >= POS_LARGE){ + fail("error in the computation of improvement\n"); + } + local_impr = SP_IMPROVEMENT(wght); + if (local_impr >= inp_eps){ + wght->epsilon = local_impr; + wght->select_flag = TRUE; + } else { + wght->epsilon = inp_eps; + } + if (speed_param->debug > 1){ + (void)fprintf(sisout, " AND (%.2f) = %5.2f\n", + local_impr, wght->epsilon); + } + } + } + array_free(nodevec); +} +/* + * Determine if the network is the result of collapsing just chains of + * inverters + */ +static int +nsp_trivial_mapped_network(network) +network_t *network; +{ + lsGen gen; + node_t *node; + int is_trivial = TRUE; + + if (network_num_internal(network) == 0) return 1; + + foreach_node(network, gen, node){ + if (node->type == INTERNAL && node_num_fanin(node) > 1){ + is_trivial = FALSE; + lsFinish(gen); + break; + } + } + return is_trivial; +} +/* Meant for specific use of printing bdd's generated during the + * procedures for selection of sites to apply local transformations + */ +static void +nsp_print_bdd(f, nodevec, num_lit) +bdd_t *f; +array_t *nodevec; +{ + char *name; + int i, index; + node_t *temp; + network_t *pr_net; + array_t *names_array; + + names_array = array_alloc(char *, num_lit); + index = 0; + for (i = array_n(nodevec); i-- > 0; ){ + temp = array_fetch(node_t *, nodevec, i); + if (temp->type != PRIMARY_OUTPUT) { + array_insert(char *, names_array, index, util_strsav(temp->name)); + index++; + } + } + pr_net = ntbdd_bdd_single_to_network(f, "bdd_out", names_array); + com_execute(&pr_net, "collapse"); + com_execute(&pr_net, "simplify"); + com_execute(&pr_net, "print"); + network_free(pr_net); + for (i = array_n(names_array); i-- > 0; ){ + name = array_fetch(char *, names_array, i); + FREE(name); + } + array_free(names_array); +} + + /* Compute the difference between the most critical slack and the next + * Returns 0 in case there is no valid slack difference */ +int +nsp_first_slack_diff(network, slack_diff) +network_t *network; +double *slack_diff; +{ + lsGen gen; + node_t *node; + delay_time_t slack, min_slack, diff; + + *slack_diff = 0.0; + if (network_num_po(network) == 1) return 0; + + min_slack.rise = min_slack.fall = POS_LARGE; + foreach_primary_output(network, gen, node){ + slack = delay_slack_time(node); + min_slack.rise = MIN(min_slack.rise, slack.rise); + min_slack.fall = MIN(min_slack.fall, slack.fall); + } + diff.rise = diff.fall = POS_LARGE; + foreach_primary_output(network, gen, node){ + slack = delay_slack_time(node); + if (slack.rise > (min_slack.rise + NSP_EPSILON)){ + diff.rise = MIN(diff.rise, slack.rise - min_slack.rise); + } + if (slack.fall > (min_slack.fall + NSP_EPSILON)){ + diff.fall = MIN(diff.fall, slack.fall - min_slack.fall); + } + } + if (diff.rise == POS_LARGE || diff.fall == POS_LARGE){ + return 0; + } else { + *slack_diff = MIN(diff.rise, diff.fall); + return 1; + } +} + +/* + * Returns 1 if the edge between node and fanin is critical + */ +int +nsp_critical_edge(node, fanin_index, model, crit_slack) +node_t *node; +int fanin_index; +delay_model_t model; +double crit_slack; +{ + node_t *fanin; + delay_time_t req, arr, slack; + + if (!delay_wire_required_time(node, fanin_index, model, &req)){ + return 0; + } + fanin = node_get_fanin(node, fanin_index); + arr = delay_arrival_time(fanin); + slack.rise = req.rise - arr.rise; + slack.fall = req.fall - arr.fall; + if (slack.rise < (crit_slack - NSP_EPSILON) || + slack.fall < (crit_slack - NSP_EPSILON)){ + return 1; + } + return 0; +} + + + /* + * Routine to compute the shortest path (Modification on the routine + * mvbr_shortestpath() by Yoshinori Watanabe (in GYOCRO). All the comments + * are Yoshi's .... + */ +static void nsp_dfs_bdd(); +static int get_post_visit(); +static void set_post_visit(); +static int is_f_visited(); +static enum st_retval free_starray(); +static enum st_retval free_stbddt(); + +/* + * nsp_best_selection() finds the shortest path in a BDD f that + * ends with a 1 terminal, where an edge has a weight 'wtt' if it + * is a then edge and has a weight 'wte' if it is an else edge. + * This routine does not check if f is NIL or is a constant + * terminal BDD. This routine should not be used for these + * cases. + */ + +array_t * +nsp_best_selection(f, node_and_id, wtt, wte, cost) +bdd_t *f; +st_table *node_and_id; +int *wtt; /* Array of weigths for the then edges for each variable */ +int wte; /* The weight of the "then" edges */ +int *cost; +{ + st_table *id_table, *order; + int num_nodes, i, k; + int *length, *phase; + bdd_t **parent, *v, *w0, *w1, *dup_f; + char *value, *id; + node_t *np; + int then_weight; + array_t *solution_array; + unsigned int var_id; + int terminal1_id; + + *cost = 0; + + solution_array = array_alloc(node_t *, 0); + if(bdd_is_tautology(f, 0)){ + array_free(solution_array); + return NIL(array_t); + } else if (bdd_is_tautology(f, 1)){ + return solution_array; + } + /* id_table gives a post_visit number of a sub-BDD g of f. + * Specifically, as the key being the bdd_node of g, the table + * contains an array[0, 1] of integers, where array[0] gives + * the post visit number of g with complemented edge and array[1] + * gives the one for the non-complemented edge. In either case, + * if only one of them appears as a sub-BDD in f, then the number + * for the other is set to -1. + */ + id_table = st_init_table(st_ptrcmp, st_ptrhash); + /* order contains a single sub-BDD 'g' with its post_visit number + * as the key. + */ + order = st_init_table(st_numcmp, st_numhash); + + /* fill in id_table and order. We duplicate f so that we can + * free up the BDD's stored in order at the end. + */ + dup_f = bdd_dup(f); + nsp_dfs_bdd(dup_f, id_table, order, 0, &num_nodes); + + /* num_nodes is the number of nodes visited in the dfs. */ + length = ALLOC(int, num_nodes); + parent = ALLOC(bdd_t *, num_nodes); + phase = ALLOC(int, num_nodes); + + /* length[i] gives the length of the shortest path of the + * BDD node with the post_visit number i from the top node of f. + * parent[i] gives the parent BDD of the BDD node with + * the post_visit number i in the path. phase[i] is 1 if the + * BDD node with id = i is a then child of parent[i] and + * 0 if an else child. terminal is an array of post_visit number + * of BDDs of 1 terminal nodes in f. + */ + for(i=0; i<num_nodes-1; i++){ + length[i] = INFINITY; + } + length[i] = 0; + parent[i] = NIL(bdd_t); + + /* Each sub-BDD in f visited in DFS is processed in topological + * order, which is the reverse post_visit order. + * The first node to be processed is f. + */ + for(i=num_nodes-1; i>=0; i--){ + (void)st_lookup(order, (char *)i, &value); + v = (bdd_t *)value; + + /* Skip if v is a leaf. */ + if(bdd_is_tautology(v, 0) || bdd_is_tautology(v, 1)) continue; + + /* Labeling the then child */ + w1 = bdd_then(v); + if(bdd_is_tautology(w1, 0) == 0){ /* Skip if w is 0 terminal. */ + k = get_post_visit(id_table, w1); + var_id = bdd_top_var_id(v); + then_weight = wtt[var_id]; + if(length[k] > (then_weight+length[i])){ + length[k] = then_weight+length[i]; + parent[k] = v; + phase[k] = 1; + } + if(bdd_is_tautology(w1, 1)) terminal1_id = k; + } + bdd_free(w1); + + /* Labeling the else child */ + w0 = bdd_else(v); + if(bdd_is_tautology(w0, 0) == 0){ + k = get_post_visit(id_table, w0); + if(length[k] > (wte+length[i])){ + length[k] = wte + length[i]; + parent[k] = v; + phase[k] = 0; + } + if(bdd_is_tautology(w0, 1)) terminal1_id = k; + } + bdd_free(w0); + } + + /* At this point, the sub_BDD of 1 terminal stored in order + * has the shortest path to the root f using parent[]. + */ + k = terminal1_id; + (void)st_lookup(order, (char *)k, &value); + v = (bdd_t *)value; + + /* Now follow the reverse pointers */ + while(parent[k] != NIL(bdd_t)){ + v = parent[k]; + var_id = bdd_top_var_id(v); + if (phase[k] == 1){ + assert(st_lookup(node_and_id, (char *)var_id, (char **)&np)); + array_insert_last(node_t *, solution_array, np); + *cost += wtt[var_id]; + } + k = get_post_visit(id_table, v); + } + + /* cleanup */ + FREE(length); FREE(phase); FREE(parent); + st_foreach(id_table, free_starray, NIL(char)); + st_foreach(order, free_stbddt, NIL(char)); + st_free_table(id_table); st_free_table(order); + + return solution_array; +} + + +/* + * nsp_dfs_bdd() recursively performs a depth first search over nodes + * in BDD 'f' and assigns post_visit numbers for all the nodes except + * 0 terminal nodes. The post_visit number is a number assigned to a + * node after all of its children have been visited. The number + * starts with 'start_num'. Once a node that is not a 0 terminal is + * assigned a post_visit number, then the number is set in a hash_table + * 'id_table' with key as the pointer to the node. Also, the pointer + * to the node is stored in a hash_table 'order' with key as its post_ + * visit number. *total_num_ptr is returned as the number of the + * nodes in f except the 0 terminal nodes plus start_num. + */ +static void +nsp_dfs_bdd(f, id_table, order, start_num, total_num_ptr) +bdd_t *f; +st_table *id_table, *order; +int start_num, *total_num_ptr; +{ + int total; + bdd_t *v0, *v1; + + if(is_f_visited(id_table, f)){ + *total_num_ptr = start_num; + return; + } + if(bdd_is_tautology(f, 0)){ + *total_num_ptr = start_num; + return; + } + if(bdd_is_tautology(f, 1)){ + set_post_visit(id_table, f, start_num); + (void)st_insert(order, (char *)start_num, (char *)f); + *total_num_ptr = start_num + 1; + return; + } + + v1 = bdd_then(f); + nsp_dfs_bdd(v1, id_table, order, start_num, &total); + + start_num = total; + v0 = bdd_else(f); + nsp_dfs_bdd(v0, id_table, order, start_num, &total); + + /* The post_visit number of f is total */ + set_post_visit(id_table, f, total); + (void)st_insert(order, (char *)total, (char *)f); + *total_num_ptr = total + 1; + + return; +} + +static enum st_retval +free_starray(key, value, arg) +char *key, *value, *arg; +{ + FREE(value); + return ST_DELETE; +} + +static enum st_retval +free_stbddt(key, value, arg) +char *key, *value, *arg; +{ + bdd_t *b; + + b = (bdd_t *)value; + bdd_free(b); + return ST_DELETE; +} + +static void +set_post_visit(id_table, f, n) +st_table *id_table; +bdd_t *f; +int n; +{ + int complement, index, *A; + bdd_node *F; + char *value; + + F = bdd_get_node(f, &complement); + index = (complement) ? 0 : 1; + if(st_lookup(id_table, (char *)F, &value)){ + A = (int *)value; + if(A[index] != -1) A[index] = n; + } + else{ + A = ALLOC(int, 2); + A[0] = A[1] = -1; + A[index] = n; + (void)st_insert(id_table, (char *)F, (char *)A); + } +} + +static int +get_post_visit(id_table, f) +st_table *id_table; +bdd_t *f; +{ + int complement, index, *A; + bdd_node *F; + char *value; + + F = bdd_get_node(f, &complement); + index = (complement) ? 0 : 1; + (void)st_lookup(id_table, (char *)F, &value); + A = (int *)value; + return A[index]; +} + +static int +is_f_visited(id_table, f) +st_table *id_table; +bdd_t *f; +{ + int complement, index, *A; + bdd_node *F; + char *value; + + F = bdd_get_node(f, &complement); + index = (complement) ? 0 : 1; + if(st_lookup(id_table, (char *)F, &value)){ + A = (int *)value; + if(A[index] != -1) return 1; + } + return 0; +} + + + +typedef struct valid_data_struct { + int select; /* set if selection increases the epsilon */ + double saving; /* Amount of saving desired at this node */ + bdd_t *func; /* The partial "valid_set" func upto this node */ + int num_fi; /* The number of fanins that are traversed */ + array_t *fi; /* The fanins that need to be traversed */ +} vdata_t; + +/* + * Select the transformations to apply on the given circuit. + * Generates the vaild_set_functions() directly for every output. + */ +array_t * +new_speed_select_xform(network_in, speed_param, clp_table, target_impr) +network_t *network_in; +speed_global_t *speed_param; +st_table *clp_table; /* Table that lists the improvement possible at nodes */ +double target_impr; /* The improvement that we promised we could deliver */ +{ + lsGen gen; + int i, j, k, index, sel_length, cost, area_cost, max_area_cost; + int first, last, num_tries, crit_ip_count, more_to_come; + node_t *node, *np, *temp, *fanin; + bdd_manager *manager; + st_generator *stgen; + int neg_impr, found_good_set; + int end_of_prop; /* Flag for termination of propagation */ + int num_lit, area, *cost_array; /* Array of costs for BDD variable */ + array_t *sol_array; /* The set of transforms selected !!! */ + st_table *node_to_bdd, *node_and_id, *visited; + vdata_t *valid_data, *vdata, *ip_vdata; + st_table *valid_table; + sp_weight_t *wght, *ip_wght; + double sl, ip_sav, offset, *saving_array; + double min_slack, thresh, target, min_ip_slack; + delay_time_t slack, arr, req; + delay_model_t model = speed_param->model; + bdd_t *ip_func, *var, *c, *f, *f_prime, *offending_set, *bad_f; + array_t *nodevec, *temp_array, *topo_order, *fi_nodes, *ip_slacks; + array_t *init_sol = NIL(array_t), *best_sol = NIL(array_t); + + /* Initialization */ + num_lit = network_num_internal(network_in) + network_num_pi(network_in); + + /* Form a hash table from a node pointer to a row index */ + index = 0; + manager = bdd_start(num_lit); + node_to_bdd = st_init_table(st_ptrcmp, st_ptrhash); + node_and_id = st_init_table(st_ptrcmp, st_ptrhash); + + /* Create the required number of variables: outputs ordered last */ + min_slack = POS_LARGE; + nodevec = network_dfs_from_input(network_in); + for (i = array_n(nodevec); i-- > 0; ){ + node = array_fetch(node_t *, nodevec, i); + if (node->type != PRIMARY_OUTPUT) { + (void)st_insert(node_and_id, (char *)node, (char *)index); + (void)st_insert(node_and_id, (char *)index, (char *)node); + var = bdd_get_variable(manager, index); + (void)st_insert(node_to_bdd, (char *)node, (char *)var); + index++; + } else { + slack = delay_slack_time(node); + min_slack = MIN(min_slack, MIN(slack.rise, slack.fall)); + } + } + + /* Allocate the structures used to compute the "valid_set" functions */ + valid_data = ALLOC(vdata_t, num_lit); + for (i = 0; i < num_lit; i++){ + valid_data[i].saving = NEG_LARGE; + valid_data[i].func = NIL(bdd_t); + valid_data[i].select = FALSE; + valid_data[i].fi = array_alloc(node_t *, 0); + } + + /* Generate the cost array used in finding best selection set */ + cost_array = ALLOC(int, num_lit); + saving_array = ALLOC(double, num_lit); + for (i = num_lit; i-- > 0; cost_array[i] = POS_LARGE); /* Initialization */ + for (i = num_lit; i-- > 0; saving_array[i] = NEG_LARGE); + max_area_cost = NEG_LARGE; + st_foreach_item(clp_table, stgen, (char **)&np, (char **)&wght){ + area_cost = (int)ceil(SP_COST(wght)); + max_area_cost = MAX(area_cost, max_area_cost); + } + + st_foreach_item(clp_table, stgen, (char **)&np, (char **)&wght){ + assert(st_lookup(node_and_id, (char *)np, (char **)&j)); + /* Node with variableID = j has a weight of the transform */ + area_cost = (int)ceil(SP_COST(wght)); + if (speed_param->objective == TRANSFORM_BASED){ + /* Choose the fewest number of transformations: Ties broken + * based on the choice that has smaller area increase + */ + cost_array[j] = area_cost + max_area_cost * num_lit; + } else { + /* Choose the set that requires min area increase: Ties broken + * by selection the choice that involves fewer transformations + */ + cost_array[j] = 1 + num_lit * area_cost; + } + } + + /* Some temporary storage required during traversal of critical fanins */ + fi_nodes = array_alloc(node_t *, 0); + ip_slacks = array_alloc(double, 0); + + thresh = target_impr; + bad_f = bdd_zero(manager); /* Set of unacceptable selections */ + + do { + /* + * Initialization of the selection fn and nodes that are visited + * for this choice of threshold + */ + f = bdd_one(manager); + visited = st_init_table(st_ptrcmp, st_ptrhash); + + /* Visit all the critical outputs and generate selection functions */ + foreach_primary_output(network_in, gen, node) { + np = node_get_fanin(node, 0); /* Get the internal node */ + if (!speed_critical(node, speed_param) || + st_is_member(visited, (char *)np) ) { + continue; /* not critical */ + } + (void)st_insert(visited, (char *)np, NIL(char)); + /* + * First determine the amount of saving at the PO + */ + slack = delay_slack_time(node); + target = (min_slack+thresh) - MIN(slack.rise,slack.fall) - NSP_EPSILON; + if (target < NSP_EPSILON){ + if (speed_param->debug > 1){ + (void)fprintf(sisout, "Ignoring PO %s\n", node->name); + } + continue; + } + if (speed_param->debug > 1){ + (void)fprintf(sisout, "Target improvement for %s = %.2f\n", + node->name, target); + } + + /* + * Find the nodes in topo order that are valid for this PO... + */ + temp_array = array_alloc(node_t *, 0); + array_insert_last(node_t *, temp_array, np); + valid_table = st_init_table(st_ptrcmp, st_ptrhash); + assert(st_lookup(node_and_id, (char *)np, (char **)&index)); + valid_data[index].saving = target; + (void)st_insert(valid_table, (char *)np, (char *)(valid_data+index)); + + /* BFS traversal of the critical fanin subnetwork */ + first = 0; more_to_come = TRUE; + while (more_to_come) { + more_to_come = FALSE; + last = array_n(temp_array); + for (i = first; i < last; i++){ + temp = array_fetch(node_t *, temp_array, i); + foreach_fanin(temp, j, fanin) { + if (/* fanin->type == INTERNAL && */ /* PI also possible*/ + !st_is_member(valid_table, (char *)fanin) && + st_is_member(clp_table, (char *)fanin) && + nsp_critical_edge(temp, j, model, speed_param->crit_slack)){ + /* Fanin lies on the critical region... */ + assert(st_lookup(node_and_id, (char *)fanin, (char **)&index)); + (void)st_insert(valid_table, (char *)fanin, + (char *)(valid_data+index)); + array_insert_last(node_t *, temp_array, fanin); + more_to_come = TRUE; + } + } + } + first = last; + } + + /* Combine nodes in the critical fanin with transitive order */ + topo_order = array_alloc(node_t *, 0); + for (i = 0; i < array_n(nodevec); i++){ + temp = array_fetch(node_t *, nodevec, i); + if (st_is_member(valid_table, (char *)temp)){ + array_insert_last(node_t *, topo_order, temp); + } + } + /* + * Starting from the PO, compute the saving that is desired at each + * node. Also determine which fanins need to be traversed + */ + for ( i = 0; i < array_n(topo_order); i++){ + temp = array_fetch(node_t *, topo_order, i); + /* get the saving desired at this node */ + assert(st_lookup(valid_table, (char *)temp, (char **)&vdata)); + assert(st_lookup(clp_table, (char *)temp, (char **)&wght)); + if (speed_param->debug > 2){ + (void)fprintf(sisout,"SAVING %s = %.2f: ", temp->name, vdata->saving); + } + + vdata->num_fi = 0; + if (vdata->saving < NSP_EPSILON){ + if (speed_param->debug > 2) (void)fprintf(sisout,"\n"); + continue; + } + + if (vdata->saving <= SP_IMPROVEMENT(wght)){ + if (speed_param->debug > 2) (void)fprintf(sisout,"SEL "); + vdata->select = TRUE; + } + + /* traverse the critical fanins --- compute slack offsets */ + crit_ip_count = 0; min_ip_slack = POS_LARGE; + foreach_fanin(temp, j, fanin){ + if (st_is_member(valid_table, (char *)fanin)){ + assert(delay_wire_required_time(temp, j, speed_param->model, &req)); + arr = delay_arrival_time(fanin); + slack.rise = req.rise - arr.rise; + slack.fall = req.fall - arr.fall; + sl = MIN(slack.rise,slack.fall); + if (sl < speed_param->crit_slack - NSP_EPSILON){ + min_ip_slack = MIN(min_ip_slack, sl); + array_insert(double, ip_slacks, crit_ip_count, sl); + array_insert(node_t *, fi_nodes, crit_ip_count, fanin); + crit_ip_count++; + } + } + } + if (speed_param->debug > 2){ + (void)fprintf(sisout,"%d CRIT ", crit_ip_count); + } + /* Determine if all the inputs have potential savings */ + end_of_prop = FALSE; + for (j = 0; j < crit_ip_count; j++){ + fanin = array_fetch(node_t *, fi_nodes, j); + assert(st_lookup(clp_table, (char *)fanin, (char **)&ip_wght)); + sl = array_fetch(double, ip_slacks, j); + offset = (sl - min_ip_slack); + if (offset + ip_wght->epsilon < vdata->saving){ + end_of_prop = TRUE; + } + } + + if (end_of_prop){ + /* end_of_prop => vdata->select */ + assert(vdata->select); + if (speed_param->debug > 2){ + (void)fprintf(sisout, " --- DEAD END\n"); + } + continue; + } + + /* Now propogate the saving towards the inputs */ + for (j = 0; j < crit_ip_count; j++){ + fanin = array_fetch(node_t *, fi_nodes, j); + assert(st_lookup(clp_table, (char *)fanin, (char **)&ip_wght)); + assert(st_lookup(valid_table, (char *)fanin, (char **)&ip_vdata)); + sl = array_fetch(double, ip_slacks, j); + offset = (sl - min_ip_slack); + if ((ip_wght->epsilon > NSP_EPSILON) && + (vdata->saving - offset) <= ip_wght->epsilon){ + /* Saving will be achieved in the transitive fanin */ + ip_sav = vdata->saving - offset; + if (ip_sav < NSP_EPSILON){ + /* Go no further --- slack accounts for saving */ + if (speed_param->debug > 2){ + (void)fprintf(sisout, " %s(OFF)", fanin->name); + } + } else { + ip_vdata->saving = MAX(ip_vdata->saving, ip_sav); + array_insert(node_t *, vdata->fi, vdata->num_fi, fanin); + vdata->num_fi++; + if (speed_param->debug > 2){ + (void)fprintf(sisout," %s(%.2f)", fanin->name, ip_sav); + } + } + } else { + /* No saving is possible or required along this fanin */ + ip_vdata->saving = NEG_LARGE; + if (speed_param->debug > 2){ + (void)fprintf(sisout," %s(END)", fanin->name); + } + } + } + if (speed_param->debug > 2) (void)fprintf(sisout,"\n"); + /* Completed processing of one node in the TOPO order */ + } + + /* + * Now build up the "valid_set" function, starting from the inputs + */ + for (i = array_n(topo_order); i-- > 0; ){ + temp = array_fetch(node_t *, topo_order, i); + assert(st_lookup(valid_table, (char *)temp, (char **)&vdata)); + if (vdata->saving < NSP_EPSILON){ + continue; + } + if (vdata->num_fi > 0){ + ip_func = bdd_one(manager); + for (k = 0; k < vdata->num_fi; k++){ + fanin = array_fetch(node_t *, vdata->fi, k); + assert(st_lookup(valid_table, (char *)fanin, (char **)&ip_vdata)); + c = bdd_and(ip_func, ip_vdata->func, 1, 1); + bdd_free(ip_func); + ip_func = c; + } + } else { + ip_func = bdd_zero(manager); + } + + if (vdata->select){ + assert(st_lookup(node_to_bdd, (char *)temp, (char **)&var)); + assert(st_lookup(node_and_id, (char *)temp, (char **)&index)); + saving_array[index] = MAX(saving_array[index], vdata->saving); + vdata->func = bdd_or(var, ip_func, 1, 1); + } else { + assert(vdata->num_fi > 0); + assert(ip_func != bdd_zero(manager)); + vdata->func = ip_func; + } + } + + /* Combine the "valid_set" function for all the outputs */ + assert(st_lookup(valid_table, (char *)np, (char **)&vdata)); + + if (speed_param->debug > 3){ + (void)fprintf(sisout, "SELECTION FUNCTION for %s\n", np->name); + nsp_print_bdd(vdata->func, nodevec, index); + } + + f_prime = bdd_and(f, vdata->func, 1, 1); + bdd_free(f); + f = f_prime; + + /* Reinitialize all vdata_t structures used for the next pass */ + st_foreach_item(valid_table, stgen, (char **)&temp, (char **)&vdata){ + vdata->saving = NEG_LARGE; + vdata->select = FALSE; + if (vdata->func) { + bdd_free(vdata->func); vdata->func = NIL(bdd_t); + } + vdata->num_fi = 0; + } + array_free(temp_array); + array_free(topo_order); + st_free_table(valid_table); + } + + /* Remove the rejected solutions !!! no need to evaluate them again */ + f_prime = bdd_and(f, bad_f, 1, 0); + bdd_free(f); + f = f_prime; + + best_sol = NIL(array_t); + if (bdd_is_tautology(f, 0)) { + /* If no soultions are left then we are finished */ + init_sol = array_alloc(node_t *, 0); + break; + } else { + /* Now find the min cost solution of the function f*/ + sol_array = nsp_best_selection(f, node_and_id, cost_array, 0, + &area); + + if (sol_array == NIL(array_t)){ + (void)fprintf(sisout, "ERROR: no solution found\n"); + return NIL(array_t); + } else { + init_sol = array_dup(sol_array); + } + } + + if (speed_param->debug > 1){ + (void)fprintf(sisout, "SOLUTION (%d node) = ", array_n(sol_array)); + for ( i = 0; i < array_n(sol_array); i++){ + temp = array_fetch(node_t *, sol_array, i); + (void)fprintf(sisout, " %s ", temp->name); + } + (void)fprintf(sisout, "\n"); + } + + /* Evaluate to see if other solutions need to be generated */ + num_tries = 1; + found_good_set = FALSE; + sel_length = array_n(sol_array); + while (TRUE) { + if (! nsp_eval_selection(network_in, speed_param, clp_table, + thresh, sol_array, area, + &best_sol, &found_good_set, &neg_impr) + || (num_tries > speed_param->max_num_cuts)) { + if (speed_param->debug > 1 && !found_good_set){ + (void)fprintf(sisout, "\tREJECTING %.3f AFTER %d SETS\n", + thresh, num_tries); + } + if (sol_array != NIL(array_t)) { + array_free(sol_array); + } + sol_array = NIL(array_t); + break; + } + /* Remove the current selection from the set of acceptable solns */ + cost = 0; + offending_set = bdd_one(manager); + if (speed_param->debug > 2){ + (void)fprintf(sisout, "Just evaluated ## "); + } + for ( i = 0; i < sel_length; i++){ + temp = array_fetch(node_t *, sol_array, i); + assert(st_lookup(node_to_bdd, (char *)temp, (char **)&var)); + assert(st_lookup(node_and_id, (char *)temp, (char **)&index)); + c = bdd_and(offending_set, var, 1, 1); + bdd_free(offending_set); + offending_set = c; + cost += cost_array[index]; + if (speed_param->debug > 2){ + (void)fprintf(sisout, " %s", temp->name); + } + } + if (speed_param->debug > 2){ + (void)fprintf(sisout, " ## Cost = %d\n", cost); + } + c = bdd_and(f, offending_set, 1, 0); + bdd_free(f); + f = c; + if (neg_impr) { + /* Add to the set of selectiosn that can be avoided !!! */ + c = bdd_or(bad_f, offending_set, 1, 1); + bdd_free(bad_f); + bad_f = c; + } + + bdd_free(offending_set); + + /* Get the next best selection !!! */ + array_free(sol_array); + sol_array = nsp_best_selection(f, node_and_id, cost_array, 0, + &area); + sel_length = (sol_array == NIL(array_t) ? 0 : array_n(sol_array)); + num_tries++; + } +/* + if (speed_param->debug > 2){ + (void)fprintf(sisout, "\nVALID SELECTION FUNCTION\n\n"); + nsp_print_bdd(f, nodevec); + } +*/ + + bdd_free(f); + st_free_table(visited); + + if (! found_good_set){ + thresh /= 2; + if (speed_param->debug > 1){ + (void)fprintf(sisout, "REDUCING THRESHOLD TO %.2f\n", thresh); + } + } + } while (! found_good_set && (thresh > MIN_ACCEPTABLE_SAVING)); + + /* Termination */ + st_free_table(node_to_bdd); + st_free_table(node_and_id); + for ( i = 0; i < num_lit; i++){ + array_free(valid_data[i].fi); + } + FREE(valid_data); + array_free(nodevec); + array_free(fi_nodes); + array_free(ip_slacks); + FREE(cost_array); + FREE(saving_array); + bdd_end(manager); + + if (best_sol == NIL(array_t)){ + if (speed_param->debug){ + (void)fprintf(sisout, "REVERTING TO ORIGINAL SOLUTION\n"); + } + sol_array = array_dup(init_sol); + } else { + sol_array = best_sol; + } + array_free(init_sol); + + return sol_array; +} + +/* + * Determine if the selected set of transformations interacts severely + * so as to offset the advantages that would incur from implemeting them + * Returns 0 if the selection terminates the search for more solutions !!! + */ +static int +nsp_eval_selection(network, speed_param, clp_table, thresh, + orig_sol_array, area, best_array, found_good_set, neg_impr) +network_t *network; +speed_global_t *speed_param; +st_table *clp_table; +double thresh; /* The impr that we expect without interactions */ +array_t *orig_sol_array; +int area; /* Cost of the current selection */ +array_t **best_array; +int *found_good_set; +int *neg_impr; +{ + int i, j, index, check_failed; + node_t *temp; + sp_weight_t *wght; + network_t *dup_network; + char *key, *value; + st_generator *stgen; + st_table *equiv_name_table, *select_table; + array_t *new_roots; + array_t *sol_array; /* Actual solution array !!! */ + sp_xform_t *local_trans; + double diff, desired, old_value, new_value, sl; + static double best_area, best_delay; + + if (orig_sol_array == NIL(array_t)) return 0; + + /* No interaction occurs when the "unit" delay model is used */ + if (speed_param->model == DELAY_MODEL_UNIT) { + *found_good_set = TRUE; + *neg_impr = FALSE; + *best_array = array_dup(orig_sol_array); + return 0; + } + + /* Set the value that one feels is acceptable */ + if (speed_param->req_times_set){ + (void)sp_minimum_slack(network, &old_value); + desired = old_value + thresh * ACCEPTABLE_FRACTION; + } else { + (void)delay_latest_output(network, &old_value); + desired = old_value - thresh * ACCEPTABLE_FRACTION; + } + + dup_network = speed_network_dup(network); + + sol_array = array_dup(orig_sol_array); + sp_expand_selection(speed_param, sol_array, clp_table, &select_table); + speed_reorder_cutset(speed_param, clp_table, &sol_array); + + /* Remove the old configurations */ + for ( i = 0; i < array_n(sol_array); i++){ + temp = array_fetch(node_t *, sol_array, i); + assert(st_lookup(clp_table, (char *)temp, (char **)&wght)); + index = wght->best_technique; + local_trans = sp_local_trans_from_index(speed_param, index); + + /* Ensure that the network is around !!! */ + if (wght->best_netw == NIL(network_t)){ + sl = speed_param->crit_slack; + speed_param->crit_slack = wght->crit_slack; + j = speed_param->debug; + speed_param->debug = FALSE; + wght->best_netw = NSP_OPTIMIZE(wght, local_trans, speed_param); + speed_param->debug = j; + speed_param->crit_slack = sl; + } + + sp_delete_network(speed_param, dup_network, temp, + NSP_NETWORK(wght,local_trans), + select_table, clp_table, NIL(st_table)); + } + st_free_table(select_table); + + /* Insert the new ones */ + new_roots = array_alloc(node_t *, 0); + equiv_name_table = st_init_table(strcmp, st_strhash); + for(i = 0; i < array_n(sol_array); i++ ){ + temp = array_fetch(node_t *, sol_array, i); + assert(st_lookup(clp_table, (char *)temp, (char **)&wght)); + index = wght->best_technique; + local_trans = sp_local_trans_from_index(speed_param, index); + + sp_append_network(speed_param, dup_network, wght->best_netw, + local_trans, equiv_name_table, new_roots); + } + array_free(new_roots); + st_foreach_item(equiv_name_table, stgen, &key, &value){ + FREE(key); FREE(value); + } + st_free_table(equiv_name_table); + + /* Evaluate the difference */ + delay_trace(dup_network, speed_param->model); + + *neg_impr = check_failed = FALSE; + if (speed_param->req_times_set){ + (void)sp_minimum_slack(dup_network, &new_value); + diff = new_value - old_value; + if (new_value < desired) check_failed = TRUE; + if (new_value < old_value) *neg_impr = TRUE; + } else { + (void)delay_latest_output(dup_network, &new_value); + diff = old_value - new_value ; + if (new_value > desired) check_failed = TRUE; + if (new_value > old_value) *neg_impr = TRUE; + } + + network_free(dup_network); + + if (speed_param->debug > 1){ + (void)fprintf(sisout, "%s check; IMPROVEMENT = %.3f, area = %d\n", + (check_failed ? "FAILED" : "PASSED"), diff, area); + } + + /* First one... Initialize the area and delay */ + if (*best_array == NIL(array_t)){ + best_area = INFINITY; /* Don't use POS_LARGE (scaling problems) */ + best_delay = POS_LARGE; + *best_array = array_dup(orig_sol_array); + } + + /* Record the best one so far !!! */ + if (check_failed && !(*found_good_set)) { + /* Choose the MIN area solution */ + if (area < best_area){ + best_area = area; + best_delay = diff; + array_free(*best_array); + *best_array = array_dup(orig_sol_array); + if (speed_param->debug > 1) { + (void)fprintf(sisout, "Accepting (1) D= %.3f, cost = %d\n", + diff, area); + } + } + } else if (!check_failed){ + /* Choose best bang/buck !!! */ + assert(diff > 0); + if (!(*found_good_set) || ((diff/area) > (best_delay/best_area))) { + best_area = area; + best_delay = diff; + array_free(*best_array); + *best_array = array_dup(orig_sol_array); + *found_good_set = TRUE; + if (speed_param->debug) { + (void)fprintf(sisout, "Accepting (2) D= %.3f, cost = %d\n", + diff, area); + } + } + } else { + /* Ignore this one */ + } + + array_free(sol_array); + return 1; +} + +#undef NSP_MAXSTR + + + + + + + diff --git a/sis/speed/nsp_util.c b/sis/speed/nsp_util.c new file mode 100644 index 0000000..fbab56d --- /dev/null +++ b/sis/speed/nsp_util.c @@ -0,0 +1,2089 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/nsp_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include "buffer_int.h" +#include "new_speed_models.h" /* Definition of "local_transforms" */ +#include "gbx_int.h" + +#include <signal.h> +#include <setjmp.h> + +static node_t *speed_node_dup(); /* For fast duplication of nodes */ + +static void sp_map_if_required(); +static void sp_adjust_input_arrival(); +static node_t *sp_find_substitute(); +static void nsp_split_fanouts(); +int nsp_fanout_compare(); + +#define LIMIT_NUM_CUBES 200 + +/* + * Pretty printing of relevant delay information + */ +void +sp_print_delay_data(fp, network) +FILE *fp; +network_t *network; +{ + lsGen gen; + node_t *node; + double area = 0.0; + int n_failing_outputs; + delay_time_t arrival, required, slack; + delay_time_t max_slack, min_slack, sum_slack, max_arrival; + + n_failing_outputs = 0; + max_slack.rise = max_slack.fall = NEG_LARGE; + min_slack.rise = min_slack.fall = POS_LARGE; + sum_slack.rise = sum_slack.fall = 0.0; + max_arrival.rise = max_arrival.fall = NEG_LARGE; + foreach_primary_output(network, gen, node) { + arrival = delay_arrival_time(node); + required = delay_required_time(node); + slack = delay_slack_time(node); + if (MIN(slack.rise, slack.fall) < 0) { + n_failing_outputs++; + sum_slack.rise += (slack.rise < 0) ? slack.rise : 0.0; + sum_slack.fall += (slack.fall < 0) ? slack.fall : 0.0; + } + max_slack.rise = MAX(max_slack.rise, slack.rise); + max_slack.fall = MAX(max_slack.fall, slack.fall); + min_slack.rise = MIN(min_slack.rise, slack.rise); + min_slack.fall = MIN(min_slack.fall, slack.fall); + max_arrival.rise = MAX(max_arrival.rise, arrival.rise); + max_arrival.fall = MAX(max_arrival.fall, arrival.fall); + } + area = sp_get_netw_area(network); + + (void) fprintf(fp, "# of outputs: %d\n", network_num_po(network)); + (void) fprintf(fp, "total gate area: %2.2f\n", area); + (void) fprintf(fp, "maximum arrival time: (%2.2f,%2.2f)\n", + max_arrival.rise, max_arrival.fall); + (void) fprintf(fp, "maximum po slack: (%2.2f,%2.2f)\n", + max_slack.rise, max_slack.fall); + (void) fprintf(fp, "minimum po slack: (%2.2f,%2.2f)\n", + min_slack.rise, min_slack.fall); + (void) fprintf(fp, "total neg slack: (%2.2f,%2.2f)\n", + sum_slack.rise, sum_slack.fall); + (void) fprintf(fp, "# of failing outputs: %d\n", n_failing_outputs); +} +/* + * In case the fanin of the PO node is a buffer/inverter get the arrival + * for the previous node since this node will disappear on collapsing + */ +void +new_speed_adjust_po_arrival(rec, model, arrival_p) +sp_clp_t *rec; +delay_model_t model; +delay_time_t *arrival_p; +{ + delay_time_t t; + node_t *node, *po; + network_t *network = rec->net; + + /* No adjustment in the case of mapped delay computations */ + if (model == DELAY_MODEL_MAPPED) return; + + po = network_get_po(network, 0); + node = node_get_fanin(po, 0); + if (rec->can_adjust && node_num_fanin(node) == 1){ + /* + * Adjustment is made to the delay ot the PO node + */ + t = nsp_compute_delay_saving(po, node, model); + if (rec->glb->debug > 1){ + (void)fprintf(sisout, "\tINVERTER at the root adjusts %.2f:%-.2f\n", + t.rise, t.fall); + } + arrival_p->rise -= t.rise; + arrival_p->fall -= t.fall; + } +} +/* + * Assumes that the "node" is a fanin of "po" and that node can be + * deleted. The routine computes the savings that would result + */ +delay_time_t +nsp_compute_delay_saving(po, node, model) +node_t *po, *node; +delay_model_t model; +{ + delay_pin_t *pin_delay; + delay_time_t drive, t; + double po_load, load; + node_t *node1; + + pin_delay = get_pin_delay(node, 0, model); + t = delay_node_pin(node, 0, model); + load = delay_get_load((char *)pin_delay); + node1 = node_get_fanin(node, 0); + pin_delay = get_pin_delay(node1, 0, model); + drive = delay_get_drive((char *)pin_delay); +/* po_load = delay_load(po);*/ + assert(delay_get_po_load(po, &po_load)); + t.rise -= drive.rise * (po_load - load); + t.fall -= drive.fall * (po_load - load); + + return t; +} + +void +sp_print_network(network, comment) +network_t *network; +char *comment; +{ + int i; + lsGen gen; + node_t *node; + lib_gate_t *gate; + array_t *network_array; + + (void)fprintf(sisout, "%s\n", comment); + + (void)fprintf(sisout, "--in/outs\n "); + foreach_primary_input(network, gen, node){ + (void)fprintf(sisout, "%s ", node_long_name(node)); + } + (void)fprintf(sisout, " -- "); + foreach_primary_output(network, gen, node){ + (void)fprintf(sisout, "%s ", node_long_name(node)); + } + (void)fprintf(sisout, "\n"); + + (void)fprintf(sisout, "--network\n"); + network_array = network_dfs_from_input(network); + for (i = 0; i < array_n(network_array); i++) { + node = array_fetch(node_t *, network_array, i); + if ((gate = lib_gate_of(node)) != NIL(lib_gate_t)){ + (void)fprintf(sisout, "%s\t", lib_gate_name(gate)); + } + node_print(stdout, node); + } + array_free(network_array); + +} + +/* + * Account for the fact that the original arrival times at the inputs + * also had the load of the collapsed network. If these nodes are not + * duplicated (load is retained on duplication) then the arrival times + * need to be reduced so as not to be pessimistic + */ +static void +sp_adjust_input_arrival(rec, network) +sp_clp_t *rec; +network_t *network; +{ + int i; + double load; + lsGen gen, gen1; + delay_pin_t *pin_delay; + delay_time_t *tp, t, drive, old_arr; + node_t *pi, *new, *orig, *fo, *orig_fo; + + rec->adjust = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_input(rec->orig_config, gen, pi){ + new = network_find_node(rec->net, node_long_name(pi)); + if (new == NIL(node_t)) continue; + + assert(delay_get_pi_arrival_time(new, &old_arr)); + orig = nsp_network_find_node(network, node_long_name(pi)); + load = 0; + foreach_fanout(pi, gen1, fo){ + orig_fo = nsp_network_find_node(network, node_long_name(fo)); + if (orig_fo != NIL(node_t)){ + /* + * The fanout is retained because of duplication --- do not + * need to discount its load + */ + continue; + } else { + assert((i = node_get_fanin_index(fo, pi)) >= 0); + pin_delay = get_pin_delay(fo, i, rec->glb->model); + load += pin_delay->load; + } + } + pin_delay = get_pin_delay(orig, 0, rec->glb->model); + drive = delay_get_drive((char *) pin_delay); + + t.rise = drive.rise * load; + t.fall = drive.fall * load; + delay_set_parameter(new, DELAY_ARRIVAL_RISE, old_arr.rise - t.rise); + delay_set_parameter(new, DELAY_ARRIVAL_FALL, old_arr.fall - t.fall); + + /* Keep track of the adjustment for PRIMARY INPUTS */ + if (orig->type == PRIMARY_INPUT){ + tp = ALLOC(delay_time_t, 1); + *tp = t; + (void)st_insert(rec->adjust, (char *)orig, (char *)tp); + } + } +} + +/* + * Create a record of the collapsing to be used later. + */ +sp_clp_t * +sp_create_collapse_record(node, wght, speed_param, ti_model) +node_t *node; +sp_weight_t *wght; +speed_global_t *speed_param; +sp_xform_t *ti_model; +{ + sp_clp_t *rec; /* record of the collapsing information */ + + rec = ALLOC(sp_clp_t, 1); + rec->node = node; + rec->name = util_strsav(node_long_name(node)); + rec->glb = speed_param; + rec->delta = NIL(array_t); + rec->adjust = NIL(st_table); + /* + * The inverter at the output can be removed if it does not feed a PO + */ + rec->can_adjust = (1 - new_speed_is_fanout_po(node)); + rec->ti_model = ti_model; + + if (ti_model->type == FAN){ + rec->net = speed_network_dup(wght->fanout_netw); + /* NOTE: The rec->old is set in the calling code ... */ + } else if (ti_model->type == DUAL){ + rec->net = speed_network_dup(wght->dual_netw); + printf("Was rec->old set properly\n"); + } else { + rec->net = speed_network_dup(wght->clp_netw); + rec->old = delay_arrival_time(node); + } + network_set_name(rec->net, node_long_name(node)); + rec->orig_config = speed_network_dup(rec->net); + + if (ti_model->type != FAN){ + /* Adjust the arrival time to account for the removed load */ + sp_adjust_input_arrival(rec, node_network(node)); + } + + return rec; +} + + /* Free the collapse record: */ +void +nsp_free_collapse_record(rec) +sp_clp_t *rec; +{ + node_t *node; + delay_time_t *tp; + st_generator *stgen; + + network_free(rec->net); + network_free(rec->orig_config); + if (rec->delta != NIL(array_t)) array_free(rec->delta); + if (rec->adjust != NIL(st_table)){ + st_foreach_item(rec->adjust, stgen, (char **)&node, (char **)&tp){ + FREE(tp); + } + st_free_table(rec->adjust); + } + st_free_table(rec->equiv_table); + FREE(rec->name); + FREE(rec); +} + +/* + * Returns true if the fanout of this node is a primary output + */ +int +new_speed_is_fanout_po(node) +node_t *node; +{ + lsGen gen; + node_t *fo; + + foreach_fanout(node, gen, fo){ + if (node_function(fo) == NODE_PO) { + (void) lsFinish(gen); + return TRUE; + } + } + return FALSE; +} + +/* + * Allocate and create a table of the primary output nodes which + * do not have user-defined required time constraints + */ +st_table * +speed_store_required_times(network) +network_t *network; +{ + lsGen gen; + node_t *po; + st_table *table; + delay_time_t req; + + table = st_init_table(st_ptrcmp, st_ptrhash); + foreach_primary_output(network, gen, po){ + if (!delay_get_po_required_time(po, &req)){ + req = delay_required_time(po); + delay_set_parameter(po, DELAY_REQUIRED_RISE, req.rise); + delay_set_parameter(po, DELAY_REQUIRED_FALL, req.fall); + (void)st_insert(table, (char *)po, NIL(char)); + } + } + return table; +} + +/* + * Unset the required times for the primary output nodes in "table" + */ +void +speed_restore_required_times(table) +st_table *table; +{ + node_t *po; + char *dummy; + st_generator *stgen; + + st_foreach_item(table, stgen, (char **)&po, (char **)&dummy){ + delay_set_parameter(po, DELAY_REQUIRED_RISE, DELAY_NOT_SET); + delay_set_parameter(po, DELAY_REQUIRED_FALL, DELAY_NOT_SET); + } + st_free_table(table); +} + +/* + * For all the fanouts of "node" assigns them "new_fanin" as the fanin + * essentially shifts all fanouts of "node" to be fanouts of "new_fanin" + */ +void +sp_patch_fanouts_of_node(node, new_fanin) +node_t *node, *new_fanin; +{ + int j=0; + lsGen gen; + node_t **fo_array, *fanout; + + fo_array = ALLOC(node_t *, node_num_fanout(node)); + foreach_fanout(node, gen, fanout){ + fo_array[j++] = fanout; + } + for (j = node_num_fanout(node); j-- > 0; ){ + node_patch_fanin(fo_array[j], node, new_fanin); + } + FREE(fo_array); +} + +/* + * Routine to create the global representation for the technology-indep + * restructuring procedures + */ +array_t * +sp_get_local_trans(n_entries, entries) +int n_entries; +char **entries; +{ + int i, j, num; + sp_xform_t *ti_model; + static array_t *array_of_methods = NIL(array_t); + + if (array_of_methods == NIL(array_t)){ + array_of_methods = array_alloc(sp_xform_t *, 0); + + num = sizeof(local_transforms) / sizeof(local_transforms[0]); + + for (i = 0; i < num; i++) { + ti_model = ALLOC(sp_xform_t, 1); + *ti_model = local_transforms[i]; +/* + ti_model->name = local_transforms[i].name; + ti_model->optimize_func = local_transforms[i].optimize_func; + ti_model->arr_func = local_transforms[i].arr_func; + ti_model->priority = local_transforms[i].priority; + ti_model->on_flag = local_transforms[i].on_flag; + ti_model->type = local_transforms[i].type; +*/ + array_insert_last(sp_xform_t *, array_of_methods, ti_model); + } + } + if (n_entries == 0) return array_of_methods; + + /* Reset all the techniques except the one that does no transformation */ + for (i = 0; i < array_n(array_of_methods); i++){ + ti_model = array_fetch(sp_xform_t *, array_of_methods, i); + /* ti_model->on_flag = (strcmp(ti_model->name, "noalg") == 0); */ + ti_model->on_flag = FALSE; + } + for (i = 0; i < array_n(array_of_methods); i++){ + ti_model = array_fetch(sp_xform_t *, array_of_methods, i); + for (j = 0; j < n_entries; j++){ + if (strcmp(ti_model->name, entries[j]) == 0){ + ti_model->on_flag = 1; + } + } + } + + return array_of_methods; +} + +/* + * Free the global data-structures that store the technology-indep + * restructuring methods + */ +void +sp_free_local_trans(p_array_of_methods) +array_t **p_array_of_methods; +{ + int i; + sp_xform_t *ti_model; + + if (*p_array_of_methods == NIL(array_t)) return; + for (i = 0; i < array_n(*p_array_of_methods); i++){ + ti_model = array_fetch(sp_xform_t *, *p_array_of_methods, i); + FREE(ti_model); + } + array_free(*p_array_of_methods); + *p_array_of_methods = NIL(array_t); +} + +/* + * Print the methods currently in use + */ +void +sp_print_local_trans(array_of_methods) +array_t *array_of_methods; +{ + int i; + sp_xform_t *ti_model; + + if (array_of_methods == NIL(array_t)) return; + (void)fprintf(sisout, "Tech-Indep methods in use: "); + for (i = 0; i < array_n(array_of_methods); i++){ + ti_model = array_fetch(sp_xform_t *, array_of_methods, i); + if (ti_model->on_flag) + (void)fprintf(sisout, "\"%s\" ", ti_model->name); + } + (void)fprintf(sisout, "\n"); + + (void)fprintf(sisout, "Tech-Indep methods not in use: "); + for (i = 0; i < array_n(array_of_methods); i++){ + ti_model = array_fetch(sp_xform_t *, array_of_methods, i); + if (! ti_model->on_flag) + (void)fprintf(sisout, "\"%s\" ", ti_model->name); + } + (void)fprintf(sisout, "\n"); +} +/* + * Return the number of active methods + */ +int +sp_num_active_local_trans(speed_param) +speed_global_t *speed_param; +{ + int i, n; + array_t *array_of_methods = speed_param->local_trans; + sp_xform_t *ti_model; + + if (array_of_methods == NIL(array_t)) return 0; + for (i = 0, n = 0; i < array_n(array_of_methods); i++){ + ti_model = array_fetch(sp_xform_t *, array_of_methods, i); + if (ti_model->on_flag) n++; + } + return n; +} +/* + * Return the number of active methodsof a certain type + */ +int +sp_num_local_trans_of_type(speed_param, type) +speed_global_t *speed_param; +int type; /* one of CLP, DUAL, FAN */ +{ + int i, n; + array_t *array_of_methods = speed_param->local_trans; + sp_xform_t *ti_model; + + if (array_of_methods == NIL(array_t)) return 0; + if (type != CLP && type != FAN && type != DUAL) return -1; + + for (i = 0, n = 0; i < array_n(array_of_methods); i++){ + ti_model = array_fetch(sp_xform_t *, array_of_methods, i); + if (ti_model->on_flag && ti_model->type == type) n++; + } + return n; +} +/* + * Return a pointer the sp_xform_t strcture, given its position in the array + */ +sp_xform_t * +sp_local_trans_from_index(speed_param, n) +speed_global_t *speed_param; +int n; +{ + array_t *array_of_methods = speed_param->local_trans; + sp_xform_t *ti_model; + + if (array_of_methods == NIL(array_t)) return NIL(sp_xform_t); + if ((n < 0) || (n >= array_n(array_of_methods))) return NIL(sp_xform_t); + ti_model = array_fetch(sp_xform_t *, array_of_methods, n); + return ti_model; +} + + /* Must be called when you are sure that the name corresponds to an edge + in the original network */ +void +nsp_get_orig_edge(network, name, fo, index) +network_t *network; /* The original network */ +char *name; /* A composite name of a PO node */ +node_t **fo; /* The returned fanout */ +int *index; /* The fanin-index of this edge */ +{ + char *pos; + assert((pos = strrchr(name, NSP_OUTPUT_SEPARATOR))); + *pos = '\0'; + *index = atoi(pos+1); + *fo = network_find_node(network, name); + *pos = NSP_OUTPUT_SEPARATOR; + return; +} + /* Returns a node corresponding to the name that may be a madeup name */ +node_t * +nsp_network_find_node(network, name) +network_t *network; +char *name; +{ + char *pos; + node_t *node; + + if ((pos = strrchr(name, NSP_INPUT_SEPARATOR))){ + *pos = '\0'; + node = network_find_node(network, name); + *pos = NSP_INPUT_SEPARATOR; + } else if ((pos = strrchr(name, NSP_OUTPUT_SEPARATOR))){ + *pos = '\0'; + node = network_find_node(network, name); + *pos = NSP_OUTPUT_SEPARATOR; + } else { + node = network_find_node(network, name); + } + return node; +} + + /* Given a network that corresponds to a transformed subnetwork, delete it + * from the network. Add PO's and PI's to allow the modified network to be + * reinstated by sp_append_network() + */ +void +sp_delete_network(speed_param, network, node, delete_network, select_table, + clp_table, equiv_table) +speed_global_t *speed_param; /* Gloabsl stuff */ +network_t *network; /* The original network */ +node_t *node; /* The root node !!! */ +network_t *delete_network; /* The network to be deleted */ +st_table *select_table; /* Table of all the nodes in the selection */ +st_table *clp_table; /* Table of all th eweight computation data */ +st_table *equiv_table; /* Table maintaining equivalences !!! */ +{ + int index; + char *name, *pos; + lsGen gen, gen1; + node_t *po, *np, *temp, *new_pi, *new_po, *input, *orig_input; + node_t *special_pi, *actual_node, *corresp_fi, *corresp_node, *po_fi; + network_t *new_net; + sp_xform_t *ti_model, *new_ti_model; + sp_weight_t *wght; + double val; + delay_time_t t; + + + assert(st_lookup(clp_table, (char *)node, (char **)&wght)); + + /* Because of the peculiar way in which this routine is called, we + * may have the "node" not be part of "network". The hack is to + * detect this and set the node to be an appropriate one + */ + if (network != node_network(node)){ + temp = network_find_node(network, node->name); + if (temp == NIL(node_t)){ + fail("Unable to find node in duplicated network\n"); + } else { + node = temp; + } + } + + ti_model = sp_local_trans_from_index(speed_param, + wght->best_technique); + + foreach_primary_input(delete_network, gen, input){ + if ((pos = strrchr(input->name, NSP_INPUT_SEPARATOR))){ + *pos = '\0'; + orig_input = network_find_node(network, input->name); + *pos = NSP_INPUT_SEPARATOR; + } else { + orig_input = network_find_node(network, node_long_name(input)); + } + if (orig_input == NIL(node_t)){ + (void)fprintf(siserr, "Unable to find node %s\n", input->name); + fail("SERIOUS ERROR: fix it please !!!"); + } + /* First check if the orig_input is also being transformed. In + that case a link between the two needs to be established + This is a special case .... + */ + special_pi = NIL(node_t); + if ((strcmp(input->name, orig_input->name) != 0 && + st_is_member(select_table, (char *)orig_input)) || + (orig_input->type == INTERNAL)) { /* Add a PO node */ + + (void)st_lookup(clp_table, (char *)orig_input, (char + **)&wght); + new_ti_model = sp_local_trans_from_index(speed_param, + wght->best_technique); + + if (strcmp(input->name, orig_input->name) != 0 && + st_is_member(select_table, (char *)orig_input) && + new_ti_model->type != CLP){ + if (speed_param->debug) { + (void)fprintf(sisout, "FOUND SPECIAL CASE\n"); + } + /* SITUATION: A and B are being transformed, A is fanin + of B. The cutest ordering puts A before B. + Need to get B-0 while at B knowing that A has + already created B-0 as PI... we want B-0 to fanout + to A-0 so that later on they will be connected + + Otherwise there would be a PI (B-0) and PO (A-0) + without a connection between them.*/ + + new_net = wght->fanout_netw; + /* Look for the appropriate PO of the fanin config */ + foreach_primary_output(new_net, gen1, po_fi){ + corresp_node = nsp_network_find_node(delete_network, + po_fi->name); + if (corresp_node != NIL(node_t)){ + /* This could be the PO of the network too !!! */ + if (corresp_node->type == PRIMARY_OUTPUT){ + corresp_node = node_get_fanin(corresp_node, 0); + } + /* Ensure that this is the correct connection */ + assert((pos = strrchr(po_fi->name, NSP_OUTPUT_SEPARATOR))); + *pos = '\0'; + index = atoi(pos+1); + *pos = NSP_OUTPUT_SEPARATOR; + corresp_fi = node_get_fanin(corresp_node, index); + + if (strcmp(corresp_fi->name, input->name) == 0){ + special_pi = network_find_node(network, po_fi->name); + assert(special_pi != NIL(node_t) && special_pi->type == PRIMARY_INPUT); + lsFinish(gen1); + break; + } + } + } + assert(special_pi != NIL(node_t)); + actual_node = special_pi; + } else { + /* Just a regular fanin connection !!! */ + actual_node = orig_input; + } + + /* Add (if required) a PO node and set its delay values */ + t = delay_required_time(orig_input); + if ((new_po = network_find_node(network, + input->name)) != NIL(node_t) && + new_po->type == PRIMARY_OUTPUT){ + /* This node is fanin to more than one transform */ + val = delay_get_parameter(new_po, DELAY_REQUIRED_RISE); + delay_set_parameter(new_po, DELAY_REQUIRED_RISE, + MIN(val, t.rise)); + val = delay_get_parameter(new_po, DELAY_REQUIRED_FALL); + delay_set_parameter(new_po, DELAY_REQUIRED_FALL, + MIN(val, t.rise)); + val = delay_get_parameter(new_po, DELAY_OUTPUT_LOAD); + delay_set_parameter(new_po, DELAY_OUTPUT_LOAD, + val + delay_load(orig_input)); + } else { +#ifdef SIS + new_po = network_add_fake_primary_output(network, + actual_node); +#else + new_po = network_add_primary_output(network, actual_node); + network_swap_names(network, actual_node, new_po); +#endif /* SIS */ + network_change_node_name(network, new_po, util_strsav(input->name)); + delay_set_parameter(new_po, DELAY_REQUIRED_RISE, t.rise); + delay_set_parameter(new_po, DELAY_REQUIRED_FALL, t.fall); + delay_set_parameter(new_po, DELAY_OUTPUT_LOAD, + delay_load(orig_input)); + } + if (equiv_table != NIL(st_table)) { + st_insert(equiv_table, input->name, (char *)new_po); + } + } else { + if (equiv_table != NIL(st_table)) { + st_insert(equiv_table, input->name, (char *)orig_input); + } + } + /* HERE --- set the delay data for the recursion */ + } + /* + * Now add primary input nodes to the original network that + * correspond to the PO's of the resynthesised sections + */ + if (ti_model->type != CLP){ + foreach_primary_output(delete_network, gen, po){ + name = util_strsav(po->name); + /* Get the fanin index of the fanout node from this */ + assert((pos = strrchr(name, NSP_OUTPUT_SEPARATOR))); + *pos = '\0'; + index = atoi(pos+1); + np = network_find_node(network, name); + *pos = NSP_OUTPUT_SEPARATOR; + + new_pi = node_alloc(); + network_add_primary_input(network, new_pi); + network_change_node_name(network, new_pi, name); + if (np->type == PRIMARY_INPUT){ + /* The "np" is also selected for transformantion and + has been already made into a PI node */ + } else { + node_patch_fanin_index(np, index, new_pi); + } + if (equiv_table != NIL(st_table)) { + st_insert(equiv_table, name, (char *)new_pi); + } + } + } else { + /* Add a PI node corresponding to output of root node */ + new_pi = node_alloc(); + network_add_primary_input(network, new_pi); + + /* Change pointers for all fanouts to take new_pi as fanin */ + sp_patch_fanouts_of_node(node, new_pi); + + /* HERE --- set the adjusted arrival time at the PI */ + + name = util_strsav(node->name); + network_delete_node(network, node); + np = network_find_node(network, name); + assert(np == NIL(node_t)); + network_change_node_name(network, new_pi, name); + } +} + +/* Routine to keep track of nodes in the original network and added nodes */ +node_t *nsp_find_equiv_node(network, equiv_name_table, name) +network_t *network; +st_table *equiv_name_table; +char *name; +{ + node_t *orig; + char *n, *new_n; + + n = name; + if ((orig = network_find_node(network, n)) == NIL(node_t)){ + while (st_lookup(equiv_name_table, n, &new_n)){ + n = new_n; + } + orig = network_find_node(network, n); + } + return orig; +} + +/* + * Adds to the "network" the decomposition that is contained in + * "append_network". On doing that it will add the "root" node to + * the array "roots" so that appropriate steps can be taken later + */ +void +sp_append_network(speed_param, network, append_network, ti_model, + equiv_name_table, roots) +speed_global_t *speed_param; +network_t *network; +network_t *append_network; +sp_xform_t *ti_model; +st_table *equiv_name_table; +array_t *roots; +{ + int i, j, root_deleted; + array_t *nodevec, *array; + st_table *gate_table; + lib_gate_t *gate; + char *pos; + node_t *node, *fanin, *newnode, *orig, *root, *resub_node; + + array = array_alloc(node_t *, 0); + nodevec = network_dfs_from_input(append_network); + gate_table = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + newnode = node_dup(node); + node->copy = newnode; + if ((gate=lib_gate_of(node)) != NIL(lib_gate_t)){ + (void)st_insert(gate_table, (char *)newnode, (char *) gate); + } + array_insert_last(node_t *, array, newnode); + } + + /* Change the fanin pointers */ + for (i = 0; i < array_n(array); i++){ + node = array_fetch(node_t *, array, i); + FREE(node->fanin_fanout); + node->fanin_fanout = ALLOC(lsHandle, node->nin); + foreach_fanin(node, j, fanin){ + if (fanin->type == PRIMARY_INPUT) { + /* patch the fanin to original */ + orig = nsp_network_find_node(network, fanin->name); + if (orig != NIL(node_t)){ + if (orig->type == PRIMARY_OUTPUT){ + orig = node_get_fanin(orig, 0); + } + } else if ((pos = strrchr(fanin->name, NSP_INPUT_SEPARATOR)) != NULL){ + /* fanin->name may be a PI (does not have the separator) */ + *pos = '\0'; + orig = nsp_find_equiv_node(network, equiv_name_table, + fanin->name); + *pos = NSP_INPUT_SEPARATOR; + if (orig == NIL(node_t)){ + fail("Failed(1) to find node corresponding to input"); + } + } else { + fail("Failed(2) to find node corresponding to input"); + } + node->fanin[j] = orig; + } + else { + /* update the fanin pointer */ + node->fanin[j] = fanin->copy ; + } + } + } + array_free(nodevec); + + /* + * Nodes in the original network lost their names when the + * dummy PO nodes were added... Now restore these names + */ +/* + foreach_primary_input(append_network, gen, node){ + orig = nsp_network_find_node(network, node_long_name(node)); + if (orig != NIL(node_t) && orig->type == PRIMARY_OUTPUT){ + name = util_strsav(node_long_name(orig)); + temp = node_get_fanin(orig, 0); + network_delete_node(network, orig); + network_change_node_name(network, temp, name); + } + } +*/ + + /* Now add the elements of the array into the original network */ + nodevec = array_alloc(node_t *, 0); /* To store the added nodes */ + for ( i = array_n(array); i-- > 0; ){ + node = array_fetch(node_t *, array, i); + if (node->type == INTERNAL){ + /* Add it to the network --- pointers are correct at this point */ + orig = network_find_node(network, node_long_name(node)); + if (orig != NIL(node_t)){ + /* + * Node with same name may exist --- especially if the decomp + * is rejected and the original configuration is being used + */ + FREE(node->name); + } + network_add_node(network, node); + array_insert_last(node_t *, nodevec, node); + if (st_lookup(gate_table, (char *)node, (char **)&gate)){ + buf_add_implementation(node, gate); + } + } else if (node->type == PRIMARY_OUTPUT) { + /* + * Patch the output of the subnetwork to where it belongs + */ + root = node_get_fanin(node, 0); + orig = network_find_node(network, node->name); + assert(orig != NIL(node_t) && orig->type == PRIMARY_INPUT); + sp_patch_fanouts_of_node(orig, root); + /* Delete the fake primary input of the network */ + network_delete_node(network, orig); + + if (ti_model->type == CLP){ + /* Restore the name to the root --- needed for later use */ + network_change_node_name(network, root, util_strsav(node->name)); + } + + /* Free the primary output of the subnetwork */ + node_free(node); + } else { + /* Get rid of the fake primary outputs in the old network */ + orig = network_find_node(network, node_long_name(node)); + if (orig != NIL(node_t) && orig->type == PRIMARY_OUTPUT){ + network_delete_node(network, orig); + } + /* Just free the fake primary input of the sub-network */ + node_free(node); + } + } + + /* See if the added nodes can be resubstituted in the original netw */ + root_deleted = FALSE; + if (ti_model->type == CLP && speed_param->area_reclaim){ + for (i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + resub_node = sp_find_substitute(network, node, speed_param->model); + if (resub_node != NIL(node_t)) { + sp_patch_fanouts_of_node(node, resub_node); + if (node == root) { + root_deleted = TRUE; + } + (void)st_insert(equiv_name_table, util_strsav(node->name), + util_strsav(resub_node->name)); + network_delete_node(network, node); + } + } + } + if (root != NIL(node_t) && !root_deleted){ + array_insert_last(node_t *, roots, root); + } + array_free(nodevec); + array_free(array); + st_free_table(gate_table); +} +/* + * Given a "node" finds another node that is identical to it.... + * Done by doing a ntbdd_verify_network() of the network created by "node" and + * another network that corresponds to another node at the same level. + */ + +#define NSP_PO_NAME "po-_-# name" + +/* ARGSUSED */ +static node_t * +sp_find_substitute(network, node, model) +network_t *network; +node_t *node; +delay_model_t model; +{ + int nin; + lsGen gen; + node_t *fanin, *fanin2, *fo, *po, *match; + network_t *net1, *net2; + + match = NIL(node_t); + if ((node->type != INTERNAL) || + ((nin = node_num_fanin(node)) < 2)) return match; + + net1 = network_create_from_node(node); + po = network_get_po(net1, 0); + network_change_node_name(net1, po, util_strsav(NSP_PO_NAME)); + fanin = node_get_fanin(node, 0); + fanin2 = node_get_fanin(node, 1); + foreach_fanout(fanin, gen, fo){ + /* Do the obvious checks first */ + if ((fo == node) || (fo->type == PRIMARY_OUTPUT)) continue; + if (node_get_fanin_index(fo, fanin2) < 0) continue; + if (node_num_fanin(fo) != nin) continue; + + /* + * The resubstitution is accceptable only if the replacement node + * does not add undue load to the node on the critical path --- the + * one for which the substitute is being found + */ + if (delay_compute_fo_load(fo, model) > 1 && + delay_compute_fo_load(node, model) > 1){ + continue; + } + + /* Now check if the functionality is the same */ + net2 = network_create_from_node(fo); + po = network_get_po(net2, 0); + network_change_node_name(net2, po, util_strsav(NSP_PO_NAME)); + if (ntbdd_verify_network(net1, net2, DFS_ORDER, ALL_TOGETHER)){ + match = fo; + (void)lsFinish(gen); + network_free(net2); + break; + } + network_free(net2); + } + network_free(net1); + + return match; +} +#undef NSP_PO_NAME + +/* + * Free the side path information that was stored as part of the weight + * collapsing. + */ +void +new_free_weight_info(clp_table) +st_table *clp_table; +{ + node_t *np; + st_generator *stgen; + sp_weight_t *wght; + + st_foreach_item(clp_table, stgen, (char **)&np, (char **)&wght){ + FREE(wght->improvement); + FREE(wght->area_cost); + sp_network_free(wght->clp_netw); + sp_network_free(wght->fanout_netw); + sp_network_free(wght->dual_netw); + sp_network_free(wght->best_netw); + FREE(wght); + } + st_free_table(clp_table); +} + + /* + * Get the input_load_limit based on the load increase that can be + * tolerated along the connection between "fanin" and "node" + */ +double +nsp_get_load_limit(node, fanin_index, speed_param) +node_t *node; +int fanin_index; +speed_global_t *speed_param; +{ + lsGen gen; + delay_pin_t *pin_delay; + node_t *fo, *fanin = node_get_fanin(node, fanin_index); + double diff, load; + int i, pin; + delay_time_t wire_req, drive, min_fo_slack, orig_slack, slack, arr; + + pin_delay = get_pin_delay(node, fanin_index, speed_param->model); + load = pin_delay->load; + if (node_num_fanout(fanin) == 1){ + return (load * POS_LARGE); /* Unlimited increase OK !!! */ + } + + /* Keep track of the worst drive of this fanin */ + drive.rise = drive.fall = NEG_LARGE; + for(i = node_num_fanin(fanin); i-- > 0; ) { + pin_delay = get_pin_delay(fanin, i, speed_param->model); + drive.rise = MAX(drive.rise, pin_delay->drive.rise); + drive.fall = MAX(drive.fall, pin_delay->drive.fall); + } + + assert(delay_wire_required_time(node, fanin_index, speed_param->model, &wire_req)); + arr = delay_arrival_time(fanin); + orig_slack.rise = wire_req.rise - arr.rise; + orig_slack.fall = wire_req.fall - arr.fall; + + /* + * Compute the limit on the load of the new gate !!!! + * Proportional to the difference in the slacks of the fanouts + */ + min_fo_slack.rise = min_fo_slack.fall = POS_LARGE; + foreach_fanout_pin(fanin, gen, fo, pin){ + if (fo == node) continue; + delay_wire_required_time(fo, pin, speed_param->model, &wire_req); + slack.rise = wire_req.rise - arr.rise; + slack.fall = wire_req.fall - arr.fall; + min_fo_slack.rise = MIN(slack.rise, min_fo_slack.rise); + min_fo_slack.fall = MIN(slack.fall, min_fo_slack.fall); + } + /* Just a pessimistic view (to account for rise and fall asymmetry) */ + diff = MIN(min_fo_slack.rise, min_fo_slack.fall) - + MIN(orig_slack.rise, orig_slack.fall); + + if (diff > 0){ + load += diff / MAX(drive.rise, drive.fall); + } else { + load += NSP_EPSILON; /* Very small increase !!! */ + } + + return load; +} + +/* + * This is an "intelligent" routine. First figures out if there is + * scope for dualizing the function at a node (invering inp/outputs) + * and if so returns the dual network + */ +network_t * +nsp_get_dual_network(node, speed_param) +node_t *node; +speed_global_t *speed_param; +{ + (void)fprintf(sisout, "Cannot yet get the dual network\n"); + if (speed_param->model != DELAY_MODEL_MAPPED || + node->type == PRIMARY_INPUT || node_num_fanin(node) <= 1){ + return NIL(network_t); + } + + return NIL(network_t); +} + +/* Generate a network corresponding to the fanout problem at this node. + We have to be careful not to overlap the regions that will be part + of two separate selection procedures (fanout, 2c_kernel for example). + Due to this we have to restrict the fanout optimization to be only with + respect to the immediate fanouts of the network + */ + +network_t * +buf_get_fanout_network(node, speed_param) +node_t *node; +speed_global_t *speed_param; +{ + char *name; + int i, pin; + lsGen gen; + network_t *new_net; + lib_gate_t *gate; + double load, def_dr, ip_load; + delay_time_t arrival, fi_req, drive; + delay_pin_t *node_pin_delay, *pin_delay; + node_t *dup_node, *po, *pi, *fo, *fi; + + /* Get a new network and add all the delay default stuff */ + new_net = network_alloc(); + delay_network_dup(new_net, node_network(node)); + + dup_node = node_dup(node); + foreach_fanin(node, i, fi){ + node_pin_delay = get_pin_delay(node, i, speed_param->model); + pi = node_alloc(); + network_add_primary_input(new_net, pi); + pin_delay = get_pin_delay(fi, 0, speed_param->model); + drive = pin_delay->drive; + arrival = delay_arrival_time(fi); + arrival.rise -= drive.rise * (node_pin_delay->load); + arrival.fall -= drive.fall * (node_pin_delay->load); + delay_set_parameter(pi, DELAY_DRIVE_RISE, drive.rise); + delay_set_parameter(pi, DELAY_DRIVE_FALL, drive.fall); + /* Also set the max_ip_load so that the load increase is acceptable */ + ip_load = nsp_get_load_limit(node, i, speed_param); + delay_set_parameter(pi, DELAY_MAX_INPUT_LOAD, ip_load); +/* + delay_set_parameter(pi, DELAY_ARRIVAL_RISE, arrival.rise); + delay_set_parameter(pi, DELAY_ARRIVAL_FALL, arrival.fall); +*/ + delay_set_parameter(pi, DELAY_ARRIVAL_RISE, 1000.0); + delay_set_parameter(pi, DELAY_ARRIVAL_FALL, 1000.0); + /* A node may have the same node as separate fanins !!! */ + name = ALLOC(char, strlen(fi->name)+10); + sprintf(name, "%s%c%d", fi->name, NSP_INPUT_SEPARATOR, i); + network_change_node_name(new_net, pi, name); + dup_node->fanin[i] = pi; + } + + if (dup_node->type == INTERNAL){ + network_add_node(new_net, dup_node); + gate = lib_gate_of(node); + buf_add_implementation(dup_node, gate); + } else { + network_add_primary_input(new_net, dup_node); + if (!delay_get_pi_drive(dup_node, &drive)){ + def_dr = delay_get_default_parameter(node_network(node), DELAY_DEFAULT_DRIVE_RISE); + if (def_dr == DELAY_NOT_SET) def_dr = 0.0; + delay_set_parameter(dup_node, DELAY_DRIVE_RISE, def_dr); + + def_dr = delay_get_default_parameter(node_network(node), DELAY_DEFAULT_DRIVE_FALL); + if (def_dr == DELAY_NOT_SET) def_dr = 0.0; + delay_set_parameter(dup_node, DELAY_DRIVE_FALL, def_dr); + } + } + + /* Now get the fanout set !!!! and add the PO's to the network */ +#if FALSE + inv_node = NIL(node_t); + number_inv = 0; + foreach_fanout(node, gen, fo){ + if (node_function(fo) == NODE_INV){ + inv_node = fo; + number_inv++; + } + } + + if (number_inv > 1){ + inv_node = NIL(node_t); + } + + if (inv_node != NIL(node_t)){ + dup_inv_node = node_literal(dup_node, 0); + network_add_node(new_net, dup_inv_node); + buf_add_implementation(dup_inv_node, lib_gate_of(inv_node)); + network_change_node_name(new_net, dup_inv_node, util_strsav(inv_node->name)); + } +#endif + + /* Now add all the PO's and annotate them with required times and loads */ + foreach_fanout_pin(node, gen, fo, pin){ +#if FALSE + if (node_function(fo) == NODE_INV && number_inv == 1){ + foreach_fanout_pin(fo, gen1, fo1, pin1){ + po = network_add_fake_primary_output(new_net, dup_inv_node); + pin_delay = get_pin_delay(fo1, pin1, speed_param->model); + load = pin_delay->load; + delay_wire_required_time(fo1, pin1, speed_param->model, &fi_req); + name = ALLOC(char, strlen(fo1->name)+10); + sprintf(name, "%s%c%d", fo1->name, NSP_OUTPUT_SEPARATOR, pin1); + network_change_node_name(new_net, po, name); + delay_set_parameter(po, DELAY_REQUIRED_RISE, fi_req.rise); + delay_set_parameter(po, DELAY_REQUIRED_FALL, fi_req.fall); + delay_set_parameter(po, DELAY_OUTPUT_LOAD, load); + } + } else { +#endif +#ifdef SIS + po = network_add_fake_primary_output(new_net, dup_node); +#else + po = network_add_primary_output(new_net, dup_node); + network_swap_names(new_net, dup_node, po); +#endif /* SIS */ + pin_delay = get_pin_delay(fo, pin, speed_param->model); + load = (pin_delay->load); + delay_wire_required_time(fo, pin, speed_param->model, &fi_req); + name = ALLOC(char, strlen(fo->name)+10); + sprintf(name, "%s%c%d", fo->name, NSP_OUTPUT_SEPARATOR, pin); + network_change_node_name(new_net, po, name); + delay_set_parameter(po, DELAY_REQUIRED_RISE, fi_req.rise); + delay_set_parameter(po, DELAY_REQUIRED_FALL, fi_req.fall); + delay_set_parameter(po, DELAY_OUTPUT_LOAD, load); +#if FALSE + } +#endif + } + + return new_net; +} + /* Compare routine to compare two fanouts based on required time + * Smallest required time (most critical) is first in the array + */ +int +nsp_fanout_compare(p1, p2) +char *p1, *p2; +{ + sp_fanout_t *f1 = (sp_fanout_t *)p1; + sp_fanout_t *f2 = (sp_fanout_t *)p2; + + if (REQ_EQUAL(f1->req, f2->req)){ + return 0; + } else if (BUF_MIN_D(f1->req) < BUF_MIN_D(f2->req)){ + return -1; + } else { + return 1; + } +} +/* Return the min req time at the PI (adjusted for ip drive) */ +delay_time_t +nsp_min_req_time(network, model) +network_t *network; +delay_model_t model; +{ + lsGen gen; + node_t *pi; + delay_time_t req, best, drive; + + best.rise = best.fall = POS_LARGE; + foreach_primary_input(network, gen, pi){ + delay_wire_required_time(pi, 0, model, &req); + assert(delay_get_pi_drive(pi, &drive)); + sp_drive_adjustment(drive, delay_load(pi), &req); + MIN_DELAY(best, best, req); + } + return best; +} +/* + * Routine to modify a network by moving the faouts of the node into + * two sets so that the required time at the input can be reduced + */ +static void +nsp_split_fanouts(network, speed_param) +network_t *network; +speed_global_t *speed_param; +{ + lsGen gen; + int i, best_index; + delay_time_t initial, best, req; + node_t *root, *node, *dup_root, *fanin; + sp_fanout_t fanout_data, *fanout_ptr; + array_t *po_array; + + /* No point in running this when delay model does not care for fanout */ + if (speed_param->model == DELAY_MODEL_UNIT) return; + + root = NIL(node_t); + foreach_node(network, gen, node){ + if (node->type == INTERNAL){ + if (root == NIL(node_t) || node_num_fanin(node) > 1){ + root = node; + } + } + } + if (root == NIL(node_t)) return; /* There is no node to duplicate */ + if (node_num_fanout(root) <= 2) return; /* Not enuff fanouts */ + + delay_trace(network, speed_param->model); + initial = best = nsp_min_req_time(network, speed_param->model); + + /* Create a list of the fanouts of "root" in order of criticality */ + po_array = array_alloc(sp_fanout_t, 0); + foreach_primary_output(network, gen, node){ + if (node_get_fanin(node, 0) == root){ + fanout_data.fanout = node; + fanout_data.load = delay_get_parameter(node, DELAY_OUTPUT_LOAD); + fanout_data.req = delay_required_time(node); + array_insert_last(sp_fanout_t, po_array, fanout_data); + } + } + /* Sort the array */ + array_sort(po_array, nsp_fanout_compare); + + /* Create a duplicate of the root node so that fanouts can be moved */ + dup_root = node_dup(root); + FREE(dup_root->name); dup_root->name = NIL(char); + network_add_node(network, dup_root); + if (speed_param->model == DELAY_MODEL_MAPPED){ + assert(lib_gate_of(root) != NIL(lib_gate_t)); + buf_add_implementation(dup_root, lib_gate_of(root)); + } + + /* Evaluate different configs. */ + best_index = -1; + for (i = 0; i < array_n(po_array); i++){ + fanout_ptr = array_fetch_p(sp_fanout_t, po_array, i); + node_patch_fanin(fanout_ptr->fanout, root, dup_root); + delay_trace(network, speed_param->model); + req = nsp_min_req_time(network, speed_param->model); + if (REQ_IMPR(best, req)){ + best_index = i; + best = req; + } + } + if (best_index == (array_n(po_array) - 1)) best_index = -1; + + /* Generate the best configuration */ + for (i = 0; i < array_n(po_array); i++){ + fanout_ptr = array_fetch_p(sp_fanout_t, po_array, i); + fanin = node_get_fanin(fanout_ptr->fanout, 0); + if (i <= best_index){ + node_patch_fanin(fanout_ptr->fanout, fanin, dup_root); + } else { + node_patch_fanin(fanout_ptr->fanout, fanin, root); + } + } + if (best_index == -1){ + network_delete_node(network, dup_root); + } + array_free(po_array); +} + +/* + * routines that do the different optimizations that are required by + * the technology-independent models + */ + +/* + * No optimization --- simply return the networek as it is .... + */ +/* ARGSUSED */ +network_t * +sp_noalg_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + network_t *opt_network; + + if (network == NIL(network_t)){ + return NIL(network_t); + } + + opt_network = speed_network_dup(network); + sp_map_if_required(&opt_network, speed_param); + (void)delay_trace(opt_network, speed_param->model); + + return opt_network; +} + +/* + * Do the decomposition based on the timing divisors + */ +extern int kernel_timeout_occured; +static void div_timeout_handler() +{ + kernel_timeout_occured = TRUE; +} +/* ARGSUSED */ +network_t * +sp_divisor_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + node_t *clp_node, *temp; + network_t *opt_network; + + if (network == NIL(network_t)){ + return NIL(network_t); + } + + + (void)signal(SIGALRM, div_timeout_handler); + + opt_network = speed_network_dup(network); + network_collapse(opt_network); + clp_node = node_get_fanin(network_get_po(opt_network, 0), 0); + temp = node_simplify(clp_node, NIL(node_t), NODE_SIM_NOCOMP); + node_replace(clp_node, temp); + + if (node_num_cube(clp_node) < LIMIT_NUM_CUBES) { + alarm((unsigned int)(speed_param->timeout)); + kernel_timeout_occured = FALSE; + speed_set_library_accl(speed_param, 1); /* Not really required */ + speed_decomp_network(opt_network, clp_node, speed_param, 0 /*1 attempt*/); + kernel_timeout_occured = FALSE; + alarm((unsigned int) 0); + } else { + /* Instead of returning the collapsed netw return copy of original */ + network_free(opt_network); + opt_network = speed_network_dup(network); + } + + + sp_map_if_required(&opt_network, speed_param); + (void)delay_trace(opt_network, speed_param->model); + speed_set_library_accl(speed_param, 0); /* Not really required */ + + return opt_network; +} + +/* + * Do a decomposition of the collapsed fn based on 2-cube kernels !!! + */ +extern int twocube_timeout_occured; +static void twocube_timeout_handler() +{ + twocube_timeout_occured = TRUE; +} +/* ARGSUSED */ +network_t * +sp_2c_kernel_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + node_t *clp_node, *temp; + network_t *opt_network; + + if (network == NIL(network_t)){ + return NIL(network_t); + } + opt_network = speed_network_dup(network); + + /* use timers to prevent excessive use of computing resource */ + (void)signal(SIGALRM, twocube_timeout_handler); + + network_collapse(opt_network); + clp_node = node_get_fanin(network_get_po(opt_network, 0), 0); + temp = node_simplify(clp_node, NIL(node_t), NODE_SIM_NOCOMP); + node_replace(clp_node, temp); + + if (node_num_cube(clp_node) < LIMIT_NUM_CUBES) { + speed_set_library_accl(speed_param, 1); /* Not really required */ + + /* Initialize the timeout mechanism */ + alarm((unsigned int)(speed_param->timeout)); + twocube_timeout_occured = FALSE; + speed_2c_decomp(opt_network, clp_node, speed_param, 0 /*1 attempt*/); + twocube_timeout_occured = FALSE; + alarm((unsigned int) 0); + } else { + /* Instead of returning the collapsed netw return copy of original */ + network_free(opt_network); + opt_network = speed_network_dup(network); + } + + + sp_map_if_required(&opt_network, speed_param); + (void)delay_trace(opt_network, speed_param->model); + speed_set_library_accl(speed_param, 0); /* Not really required */ + twocube_timeout_occured = FALSE; + + return opt_network; +} + +/* + * First invert the function of the collapsed node. Maybe that is a smaller + * representation. Now, do a decomposition based on the timing divisors on + * the inverted function. In the end need to make sure that the fuction + * is evaluated correctly.... + */ +static void comp_div_timeout_handler() +{ + kernel_timeout_occured = TRUE; +} +/* ARGSUSED */ +network_t * +sp_comp_div_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + node_t *clp_node, *temp; + network_t *opt_network; + + if (network == NIL(network_t)) { + return NIL(network_t); + } + (void)signal(SIGALRM, comp_div_timeout_handler); + + opt_network = speed_network_dup(network); + network_collapse(opt_network); + clp_node = node_get_fanin(network_get_po(opt_network, 0), 0); + (void)node_invert(clp_node); + temp = node_simplify(clp_node, NIL(node_t), NODE_SIM_NOCOMP); + node_replace(clp_node, temp); + + if (node_num_cube(clp_node) < LIMIT_NUM_CUBES) { + speed_set_library_accl(speed_param, 1); /* Not really required */ + /* The clock is ticking !!! */ + alarm((unsigned int)(speed_param->timeout)); + kernel_timeout_occured = FALSE; + speed_decomp_network(opt_network, clp_node, speed_param, + 0 /* 1 attempt*/); + /* If the inverter at the PO node can be deleted, delete it */ + kernel_timeout_occured = FALSE; + network_csweep(opt_network); + alarm((unsigned int) 0); + } else { + /* Instead of returning the collapsed netw return copy of original */ + network_free(opt_network); + opt_network = speed_network_dup(network); + } + + + sp_map_if_required(&opt_network, speed_param); + /* + * We need to perform this since the delays for the inverter at the PO node + * were not computed. Also, in case that was deleted, this is required + */ + (void)delay_trace(opt_network, speed_param->model); + speed_set_library_accl(speed_param, 0); /* Not really required */ + + return opt_network; +} + +/* + * First invert the function of the collapsed node. Maybe that is a smaller + * representation. Now, do a decomposition based on the timing divisors on + * the inverted function. In the end need to make sure that the fuction + * is evaluated correctly.... + */ +static void comp_2c_timeout_handler() +{ + twocube_timeout_occured = TRUE; +} +/* ARGSUSED */ +network_t * +sp_comp_2c_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + node_t *clp_node, *temp; + network_t *opt_network; + + if (network == NIL(network_t)) { + return NIL(network_t); + } + opt_network = speed_network_dup(network); + + (void)signal(SIGALRM, comp_2c_timeout_handler); + + /* Invert the function at the node */ + network_collapse(opt_network); + clp_node = node_get_fanin(network_get_po(opt_network, 0), 0); + (void)node_invert(clp_node); + temp = node_simplify(clp_node, NIL(node_t), NODE_SIM_NOCOMP); + node_replace(clp_node, temp); + + /* Reset the flag, start the clock and decompose the network */ + if (node_num_cube(clp_node) < LIMIT_NUM_CUBES) { + alarm((unsigned int)(speed_param->timeout)); + twocube_timeout_occured = FALSE; + speed_set_library_accl(speed_param, 1); /* Not really required */ + speed_2c_decomp(opt_network, clp_node, speed_param, 0 /*1 attempt*/); + alarm((unsigned int) 0); + twocube_timeout_occured = FALSE; + /* If the inverter at the PO node can be deleted, delete it */ + network_csweep(opt_network); + } else { + /* Instead of returning the collapsed netw return copy of original */ + network_free(opt_network); + opt_network = speed_network_dup(network); + } + + + sp_map_if_required(&opt_network, speed_param); + + /* + * We need to perform this since the delays for the inverter at the PO node + * were not computed. Also, in case that was deleted, this is required + */ + (void)delay_trace(opt_network, speed_param->model); + speed_set_library_accl(speed_param, 0); /* Not really required */ + + return opt_network; +} + +/* + * Do an and-or decomposition based only on the arrival times + */ +/* ARGSUSED */ +network_t * +sp_and_or_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + node_t *clp_node; + network_t *opt_network; + + if (network == NIL(network_t)){ + return NIL(network_t); + } + + opt_network = speed_network_dup(network); + network_collapse(opt_network); + clp_node = node_get_fanin(network_get_po(opt_network, 0), 0); + + if (node_num_cube(clp_node) < LIMIT_NUM_CUBES) { + speed_set_library_accl(speed_param, 1); /* Not really required */ + (void)speed_and_or_decomp(opt_network, clp_node, speed_param); + } else { + /* Instead of returning the collapsed netw return copy of original */ + network_free(opt_network); + opt_network = speed_network_dup(network); + } + + + sp_map_if_required(&opt_network, speed_param); + (void)delay_trace(opt_network, speed_param->model); + speed_set_library_accl(speed_param, 0); /* Not really required */ + + return opt_network; +} +/* + * Performs a remapping of the circuit for min delay if the delays are + * being measured using the DELAY_MODEL_MAPPED or DELAY_MODEL_LIBRARY + */ + +static void +sp_map_if_required(network, speed_param) +network_t **network; +speed_global_t *speed_param; +{ + network_t *map_net; + + if (*network == NIL(network_t) || + speed_param->model != DELAY_MODEL_MAPPED) return; + + map_net = map_network(*network, lib_get_library(), 0, 1, 1); + network_free(*network); + *network = map_net; +} + +/* + * Do an optimization based on creating the appropriate fanout tree ... + */ + /* Cache the creation of buffers for efficiency : Remember to free it */ + +static buf_global_t *nsp_buffer_param = NIL(buf_global_t); + +buf_global_t * +nsp_init_buf_param(network, model) +network_t *network; +delay_model_t model; +{ + static buf_global_t buf_param; + int use_mapped; + + if (nsp_buffer_param == NIL(buf_global_t)) { + (void)buffer_fill_options(&buf_param, 0, NIL(char *)); + buf_param.limit = 2; + buf_param.trace = 0; + buf_param.thresh = 0.5; + buf_param.single_pass = 1; + buf_param.do_decomp = 0; + use_mapped = ((model == DELAY_MODEL_MAPPED || + model == DELAY_MODEL_LIBRARY) ? 1 : 0); + + buf_set_buffers(network, use_mapped, &buf_param); + + nsp_buffer_param = &buf_param; + } + return nsp_buffer_param; +} + +void +nsp_free_buf_param() +{ + if (nsp_buffer_param != NIL(buf_global_t)){ + buf_free_buffers(nsp_buffer_param); + nsp_buffer_param = NIL(buf_global_t); + } +} + +/* wrapper routine for the speed_buffer_recover_area() routine that + * downsizes the non-critical gates to reduce area + */ +int +nsp_downsize_non_crit_gates(network, model) +network_t *network; +delay_model_t model; +{ + int success; + + (void)nsp_init_buf_param(network, model); + success = speed_buffer_recover_area(network, nsp_buffer_param); + nsp_free_buf_param(); + + return success; +} + + +/* ARGSUSED */ +network_t * +sp_fanout_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + network_t *opt_network; + buf_global_t *buf_param; + + if (network == NIL(network_t)){ + return NIL(network_t); + } + + opt_network = speed_network_dup(network); + if (lib_network_is_mapped(opt_network)) { + buf_param = nsp_init_buf_param(network, speed_param->model); + if (strcmp(ti_model->name, "repower") == 0){ + buf_param->mode = 1; /* Only powering up is allowed */ + } else { + buf_param->mode = 7; /* All transformations enabled for "fanout" */ + } + speed_buffer_network(opt_network, buf_param); + } + delay_trace(opt_network, speed_param->model); + + return opt_network; +} + +/* + * Another form of fanout optimization: Here the root node is duplicated + * so that the critical signals see lesser capacitive loads... + */ +/* ARGSUSED */ +network_t * +sp_duplicate_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + network_t *opt_network; + + if (network == NIL(network_t)){ + return NIL(network_t); + } + + opt_network = speed_network_dup(network); + nsp_split_fanouts(opt_network, speed_param); + delay_trace(opt_network, speed_param->model); + + return opt_network; +} +/* + * As an attempt towards phase assignment we have this dualizing transform + */ +/* ARGSUSED */ +network_t * +sp_dual_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + network_t *opt_network; + + if (network == NIL(network_t)){ + return NIL(network_t); + } + + opt_network = speed_network_dup(network); + (void)fprintf(sisout, "Not yet implemeted dualizing\n"); + delay_trace(opt_network, speed_param->model); + + return opt_network; +} + +/* + * Do an optimization based on the timing driven cofactoring (tdc) approach + */ +/* ARGSUSED */ +network_t * +sp_cofactor_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + network_t *new_net, *clp_net; + + if (network == NIL(network_t)){ + return NIL(network_t); + } + + clp_net = speed_network_dup(network); + network_collapse(clp_net); + new_net = tdc_factor_network(clp_net); +/* + speed_init_decomp(new_net, speed_param); + */ + /* We will do a balanced decomp to isolate the cofactoring impr */ + resub_alge_network(new_net, 0); + decomp_tech_network(new_net, 2, 0); + network_csweep(new_net); + + network_free(clp_net); + sp_map_if_required(&new_net, speed_param); + delay_trace(new_net, speed_param->model); + + return new_net; +} + +/* ARGSUSED */ +network_t * +sp_bypass_opt(network, ti_model, speed_param) +network_t *network; +sp_xform_t *ti_model; +speed_global_t *speed_param; +{ + network_t *new_net; + int cutset_flag=0; /* Try the bypasses in sorted order */ +/* + static ref_count = 0; + char command[256]; +*/ + extern int do_bypass_transform(); + + if (network == NIL(network_t)){ + return NIL(network_t); + } + +/* + sprintf(command, "write_blif /usr/tmp/bypass_ex%d.blif", ref_count++); + com_execute(&network, command); +*/ + /* The bypass transformation code / routine call goes here */ + new_net = speed_network_dup(network); + do_bypass_transform(&new_net, (double)1, 0, (double)2, speed_param->model, + GBX_NEWER_TRACE, speed_param->debug, cutset_flag); + + resub_alge_network(new_net, 0); + com_execute(&new_net, "full_simplify -l"); + sp_map_if_required(&new_net, speed_param); + delay_trace(new_net, speed_param->model); + + return new_net; +} + +/* + * Use this routine if the delay information is stored in the node->delay field + */ + /* ARGSUSED */ +delay_time_t +new_delay_arrival(node, speed_param) +node_t *node; +speed_global_t *speed_param; +{ + delay_time_t arrival; + + arrival = delay_arrival_time(node); + + return arrival; +} +/* + * Use this routine if the delay information is stored in the node->delay field + */ + /* ARGSUSED */ +delay_time_t +new_delay_required(node, speed_param) +node_t *node; +speed_global_t *speed_param; +{ + delay_time_t req; + + req = delay_required_time(node); + + return req; +} +/* + * Use this routine if the delay information is stored in the node->delay field + */ + /* ARGSUSED */ +delay_time_t +new_delay_slack(node, speed_param) +node_t *node; +speed_global_t *speed_param; +{ + delay_time_t req; + + fail("Not yet implemented"); + + return req; +} + +/* Routines to speedup the network duplication code !!! */ + +static void +duplicate_list(list, newlist, newnetwork) +lsList list, newlist; +network_t *newnetwork; +{ + lsGen gen; + node_t *node, *newnode; + lsHandle handle; + + lsForeachItem(list, gen, node) { + newnode = speed_node_dup(node); + node->copy = newnode; + LS_ASSERT(lsNewEnd(newlist, (lsGeneric) newnode, &handle)); + newnode->network = newnetwork; + newnode->net_handle = handle; + } +} + +static void +copy_list(list, newlist) +lsList list, newlist; +{ + lsGen gen; + node_t *node; + + lsForeachItem(list, gen, node) { + LS_ASSERT(lsNewEnd(newlist, (lsGeneric) node->copy, LS_NH)); + } +} + +static void +reset_io(list) +lsList list; +{ + lsGen gen; + node_t *node, *fanin; + int i; + + lsForeachItem(list, gen, node) { + foreach_fanin(node, i, fanin) { + node->fanin[i] = fanin->copy; + } + fanin_add_fanout(node); + } +} + +network_t * +speed_network_dup(old) +network_t *old; +{ + network_t *new; + + if (old == NIL(network_t)) { + return(NIL(network_t)); + } + new = network_alloc(); + + if (old->net_name != NIL(char)) { + new->net_name = util_strsav(old->net_name); + } + + duplicate_list(old->nodes, new->nodes, new); + copy_list(old->pi, new->pi); + copy_list(old->po, new->po); + + network_rehash_names(new, /* long */ 1, /* short */ 1); + + /* this makes sure fanout pointers are up-to-date */ + reset_io(new->nodes); + + /* This makes sure that the global delay information is copied */ + delay_network_dup(new, old); + + /* this makes sure that MAP(node)->save_binding pointers are up-to-date */ + map_network_dup(new); + + new->original = network_dup(old->original); + new->dc_network = network_dup(old->dc_network); + new->area_given = old->area_given; + new->area = old->area; +#ifdef SIS + copy_latch_info(old->latch, new->latch, new->latch_table); + new->stg = stg_dup(old->stg); + new->astg = astg_dup(old->astg); + network_clock_dup(old, new); +#endif /* SIS */ + return new; +} + +static node_t * +speed_node_dup(old) +register node_t *old; +{ + register node_t *new; + + if (old == 0) return 0; + + new = node_alloc(); + + if (old->name != 0) { + new->name = util_strsav(old->name); + } + if (old->short_name != 0) { + new->short_name = util_strsav(old->short_name); + } + + new->type = old->type; + + new->fanin_changed = old->fanin_changed; + new->fanout_changed = old->fanout_changed; + new->is_dup_free = old->is_dup_free; + new->is_min_base = old->is_min_base; + new->is_scc_minimal = old->is_scc_minimal; + + new->nin = old->nin; + if (old->nin != 0) { + new->fanin = nodevec_dup(old->fanin, old->nin); + } + + /* do NOT copy old->fanout ... */ + /* do NOT copy old->fanin_fanout ... */ + + if (old->F != 0) new->F = sf_save(old->F); + if (old->D != 0) new->D = sf_save(old->D); + if (old->R != 0) new->R = sf_save(old->R); + + new->copy = 0; /* ### for saber */ + + /* do NOT copy old->network ... */ + /* do NOT copy old->net_handle ... */ + + delay_dup(old, new); + map_dup(old, new); +/* + for(d = daemon_func[(int) DAEMON_DUP]; d != 0; d = d->next) { + (*d->func)(old, new); + } +*/ + return new; +} diff --git a/sis/speed/sp_buffer.c b/sis/speed/sp_buffer.c new file mode 100644 index 0000000..5cf0033 --- /dev/null +++ b/sis/speed/sp_buffer.c @@ -0,0 +1,820 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/sp_buffer.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include "buffer_int.h" + +#define BUF_GET_PERFORMANCE(network,node,value,area) \ +node = (required_times_set ? sp_minimum_slack((network), &dummy) :\ + delay_latest_output((network), &dummy)); \ +value = (required_times_set ? delay_slack_time((node)) :\ + delay_arrival_time((node))); \ +area = sp_get_netw_area(network) + +static delay_time_t large_req_time = {POS_LARGE, POS_LARGE}; +static void sp_already_buffered(); +int sp_satisfy_max_load(); + + +/* + * exported routine --- needed to set some of the global variables + * before calling the appropriate routine. + * Returns 0 if network is not changed, 1 if changed + */ +int +buffer_network(network, limit, trace, thresh, single_pass, do_decomp) +network_t *network; +int limit; +int trace; +double thresh; +int single_pass; +int do_decomp; +{ + int changed; + buf_global_t buf_param; + + (void)buffer_fill_options(&buf_param, 0, NIL(char *)); + buf_param.limit = limit; + buf_param.trace = trace; + buf_param.thresh = thresh; + buf_param.single_pass = single_pass; + buf_param.do_decomp = do_decomp; + + buf_set_buffers(network, 0, &buf_param); + + /* Annotate the delay data */ + if (!delay_trace(network, buf_param.model)){ + (void)fprintf(sisout,"%s\n", error_string()); + return 1; + } + + changed = speed_buffer_network(network, &buf_param); + buf_free_buffers(&buf_param); + + changed = (changed == 0 ? 0 : 1); + return changed; +} + + +/* + * Buffers the nodes in the network. For now it will select the node + * on the critical path with the largest fanout -- buffer it -- recompute + * the delays and keep going till it meets timing constraints or + * cannot improve.... + */ +int +speed_buffer_network(network, buf_param) +network_t *network; +buf_global_t *buf_param; +{ + lsGen gen; + int changed, changed_some, i, flag, required_times_set, loop_count; + int loop_again; + array_t *nodevec; + st_table *buffered_nodes; + double dummy, orig_area, area; + node_t *node, *best, *last, *orig; + delay_time_t prev, delay, initial, final; + delay_model_t model = buf_param->model; + + changed = FALSE; + loop_count = 1; + + (void)delay_trace(network, model); + /* + * The flag "requird_times_set" is used to figure out whether to stop + * when timing constraints are met (if required times at po are specified) + * or when there is no improvement in delay + */ + required_times_set = sp_po_req_times_set(network); + + loop_again = TRUE; + while (loop_again){ /* There is scope for improvement */ + loop_again = FALSE; + changed_some = FALSE; + buffered_nodes = st_init_table(st_ptrcmp, st_ptrhash); + if (buf_param->trace) + (void)fprintf(misout,"\nLOOP NUMBER %d\n---------------\n", + loop_count++); + + /* Initially set the gates to be unbuffered */ + foreach_node(network, gen, node){ + BUFFER(node)->type = NONE; + } + /* Initial circuit performance */ + BUF_GET_PERFORMANCE(network, orig, initial, orig_area); + prev = initial; + + /* + * Starting from the output keep on buffering the nodes that lie + * on the critical path + */ + do { + flag = FALSE; + set_buf_thresh(network, buf_param); + nodevec = network_dfs_from_input(network); + for (i = 0; i < array_n(nodevec); i++){ + best = array_fetch(node_t *, nodevec, i); + if (best->type != PRIMARY_OUTPUT && buf_critical(best, buf_param) + && (!st_is_member(buffered_nodes, (char *)best)) ){ + if (speed_buffer_node(network, best, buf_param, required_times_set)){ + flag = TRUE; + changed = TRUE; + changed_some = TRUE; + sp_already_buffered(buffered_nodes, best); + (void)delay_trace(network, model); + set_buf_thresh(network, buf_param); + + /* + * We should have gotton an improvement in ckt perf */ + BUF_GET_PERFORMANCE(network, last, delay, area); + if (buf_param->trace){ + (void)fprintf(misout, + "\t%s %.2f -> %.2f Area %.0f -> %.0f CRIT_PO %s -> %s\n", + (required_times_set ? "Slack" : "Delay"), + (required_times_set ? BUF_MIN_D(prev) : + BUF_MAX_D(prev)), + (required_times_set ? BUF_MIN_D(delay) : + BUF_MAX_D(delay)), + orig_area, area, + orig->name, last->name); + } + if ((required_times_set && (BUF_MIN_D(delay) < + BUF_MIN_D(prev))) || + (!required_times_set && (BUF_MAX_D(delay) > + BUF_MAX_D(prev))) ) { + (void)fprintf(sisout, "FAILED CHECK: Performance worsened when buffering %s\n", best->name); + } + prev = delay; + orig = last; + orig_area = area; + break; + } + } + } + array_free(nodevec); + } while (flag); + + /* Do an area recovery pass as well::: This is not really correct + so bypass it for the time being till a correct recovery + procedure is found */ + + if (speed_buffer_recover_area(network, buf_param)){ + BUF_GET_PERFORMANCE(network, last, delay, area); + if (buf_param->trace){ + (void)fprintf(misout, + "\t%s %.2f -> %.2f Area %.0f -> %.0f after Area Recovery\n", + (required_times_set ? "Slack" : "Delay"), + (required_times_set ? BUF_MIN_D(prev) : + BUF_MAX_D(prev)), + (required_times_set ? BUF_MIN_D(delay) : + BUF_MAX_D(delay)), orig_area, area); + } + prev = delay; + orig = last; + orig_area = area; + } + + /* + * Completed one sweep through the network ... Should we + * go on ?? "loop_again" only if the delay/slack has been improved + * "delay" is the metric of performance that has been achieved + */ + if (required_times_set){ + last = sp_minimum_slack(network, &dummy); + final = delay_slack_time(last); + } else { + last = delay_latest_output(network, &dummy); + final = delay_arrival_time(last); + } + + if (!buf_param->single_pass && changed_some){ + /* Need to continue looping only if there is a substantial change */ + if (required_times_set){ + /* + loop_again = ((final.rise-initial.rise) > V_SMALL && + (final.fall-initial.fall) > V_SMALL); + */ + loop_again = REQ_IMPR(final,initial); + } else { + /* + loop_again = ((initial.rise-final.rise) > V_SMALL && + (initial.fall-final.fall) > V_SMALL); + */ + loop_again = REQ_IMPR(initial, final); + } + } + st_free_table(buffered_nodes); + + } + + /* + changed += sp_satisfy_max_load(network); + */ + return changed; +} + +/* + * Gets the fanout set of node. If there is only one inverter in + * the fanout set then returns its fanouts too. If more than one inverter + * then it returns only the immediate fanouts of node + */ +static buf_alg_input_t * +sp_get_fanout_set(node) +node_t *node; +{ + int pin, pin1; + lsGen gen, gen1; + node_t *fo, *fo1; + buf_alg_input_t *alg_input; + int i=0, number_inv; + + alg_input = ALLOC(buf_alg_input_t, 1); + alg_input->root = node; + alg_input->node = node; + alg_input->inv_node = NIL(node_t); + number_inv = alg_input->num_pos = alg_input->num_neg = 0; + + foreach_fanout(node, gen, fo){ + if (node_function(fo) == NODE_INV){ + alg_input->num_neg += node_num_fanout(fo); + alg_input->inv_node = fo; + number_inv++; + } else { + (alg_input->num_pos)++; + } + } + + if (number_inv > 1){ + alg_input->inv_node = NIL(node_t); + alg_input->num_neg = 0; + alg_input->num_pos += number_inv; + } + + /* Check for discrepency, i.e. there are no fanouts of inv_node */ + if (alg_input->inv_node != NIL(node_t) && alg_input->num_neg == 0){ + alg_input->inv_node = NIL(node_t); + number_inv = 2; /* This avoids generating the fanouts of the inverter */ + (void)fprintf(siserr,"CHECK THIS --- inverter has no fanouts\n"); + } + + + /* Allocate and fill in the data regarding the fanout destinations */ + if (number_inv > 1){ + /* get only the positive fanout signals */ + alg_input->fanouts = ALLOC(sp_fanout_t, alg_input->num_pos+number_inv); + } else { + alg_input->fanouts = ALLOC(sp_fanout_t, (alg_input->num_pos)+( + alg_input->num_neg)); + } + + foreach_fanout_pin(node, gen, fo, pin){ + if (node_function(fo) == NODE_INV && number_inv <= 1){ + foreach_fanout_pin(fo, gen1, fo1, pin1){ + alg_input->fanouts[i].fanout = fo1; + alg_input->fanouts[i].pin = pin1; + alg_input->fanouts[i].phase = PHASE_INVERTING; + i++; + } + } else { + alg_input->fanouts[i].fanout = fo; + alg_input->fanouts[i].pin = pin; + alg_input->fanouts[i].phase = PHASE_NONINVERTING; + i++; + } + } + + return alg_input; +} + +static void +sp_already_buffered(table, node) +st_table *table; +node_t *node; +{ + lsGen gen; + node_t *fo; + + foreach_fanout(node, gen, fo){ + if (BUFFER(fo)->type != NONE){ + BUFFER(fo)->type = NONE; + if (!st_is_member(table, (char *)fo)){ + /* Recursively add the nodes that have been added herein */ + sp_already_buffered(table, fo); + } + } + } + (void)st_insert(table, (char *)node, NIL(char)); +} + + +/* + * Optimal buffer selection for the nodes in nodevec based on + * the phases and required times of the signals + */ + +int +speed_buffer_array_of_nodes(network, buf_param, nodevec) +network_t *network; +buf_global_t *buf_param; +array_t *nodevec; +{ + lsGen gen; + node_t *node, *fo; + int changed; + int i, do_delay_trace, count; + + count = 0; + changed = FALSE; + do_delay_trace = FALSE; + + for (i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + if (node->type != PRIMARY_OUTPUT){ + foreach_fanout(node, gen, fo){ + if (st_is_member(buf_param->glbuftable, (char *)fo)){ + /* Need to update the req time data */ + do_delay_trace = TRUE; + (void)lsFinish(gen); + break; + } + } + if (do_delay_trace){ + /* Update the delay data via a trace */ + do_delay_trace = FALSE; + (void)delay_trace(network, buf_param->model); + count++; + st_free_table(buf_param->glbuftable); + buf_param->glbuftable = st_init_table(st_ptrcmp, st_ptrhash); + } + if (speed_buffer_node(network, node, buf_param, 0 /*unconstrained */)){ + changed = TRUE; + (void)st_insert(buf_param->glbuftable, (char *)node, NIL(char)); + } + } + } + if (buf_param->debug){ + (void)fprintf(misout,"INFO: %d delay traces were required\n", count); + } + + return changed; +} + +/* + * Finds the amount by which the the required time at the current node + * needs to be increased. Basically the negative of the min slack !!! + * for teh case when the required times are set (constrained == TRUE) + * Also determines the max_load that can be tolerated at crit fin... + */ +delay_time_t +sp_buf_get_target(node, buf_param, constrained, max_loadp) +node_t *node; +buf_global_t *buf_param; +int constrained; +double *max_loadp; +{ + lsGen gen; + double diff, load; + node_t *fin, *fo, *crit_fin; + int i, pin, cfi, crit_fin_index; + delay_time_t wire_req, min_fo_slack, min_slack, slack, arr, req_diff; + + *max_loadp = POS_LARGE; /* Default */ + req_diff = large_req_time; /* Default */ + min_slack = large_req_time; + crit_fin_index = -1; + + /* Special case for PI node */ + if (node->type == PRIMARY_INPUT) { + load = delay_get_parameter(node, DELAY_MAX_INPUT_LOAD); + if (load != DELAY_NOT_SET) { + *max_loadp = load; + } + if (constrained) { + min_slack = delay_slack_time(node); + req_diff.rise = (0.0 - min_slack.rise); + req_diff.fall = (0.0 - min_slack.fall); + } + return req_diff; + } + + /* Get the smallest slack at all the inputs */ + foreach_fanin(node, i, fin){ + if (buf_critical(fin, buf_param)){ + assert(delay_wire_required_time(node, i, buf_param->model, &wire_req)); + arr = delay_arrival_time(fin); + slack.rise = wire_req.rise - arr.rise; + slack.fall = wire_req.fall - arr.fall; + + if (BUF_MIN_D(slack) < BUF_MIN_D(min_slack)){ + crit_fin_index = i; + } + min_slack.rise = MIN(slack.rise, min_slack.rise); + min_slack.fall = MIN(slack.fall, min_slack.fall); + } + } + + if (crit_fin_index == -1){ + /* The node "node" is not on critical path: no buffering req */ + req_diff.rise = req_diff.fall = 0.0; + } else { + cfi = BUFFER(node)->cfi; + assert(crit_fin_index == cfi); + if (constrained){ + req_diff.rise = (0.0 - min_slack.rise); + req_diff.fall = (0.0 - min_slack.fall); + } + /* + * Compute the limit on the load of the new gate !!!! + * Proportional to the difference in the slacks of the fanouts + */ + crit_fin = node_get_fanin(node, crit_fin_index); + min_fo_slack = large_req_time; + foreach_fanout_pin(crit_fin, gen, fo, pin){ + if (fo == node) continue; + delay_wire_required_time(fo, pin, buf_param->model, &wire_req); + arr = delay_arrival_time(crit_fin); + slack.rise = wire_req.rise - arr.rise; + slack.fall = wire_req.fall - arr.fall; + min_fo_slack.rise = MIN(slack.rise, min_fo_slack.rise); + min_fo_slack.fall = MIN(slack.fall, min_fo_slack.fall); + } + /* Just a pessimistic view (to account for rise and fall asymmetry) */ + diff = BUF_MIN_D(min_fo_slack) - BUF_MIN_D(min_slack); + if (diff > 0){ + load = diff / (BUF_MAX_D(BUFFER(node)->prev_dr)); + } else { + load = V_SMALL; + } + *max_loadp = sp_get_pin_load(node, buf_param->model) + load; + } + + return req_diff; +} + +/* + * Buffers the fanouts if fanout count is greater than limit + * Returns 1 if the fanout structure at the node was changed + */ +int +speed_buffer_node(network, node, buf_param, constrained) +network_t *network; +node_t *node; +buf_global_t *buf_param; +int constrained; /* == 1 => req_times set at outputs */ +{ + buf_alg_input_t *fanout_data; + delay_time_t req_diff; + int i, n; + double max_load; + int level = 0, changed = 0; + + /* + * Set the required time at the input of the gate/buffer in the + * original netw. The setting is done in the BUFFER field of "node" + */ + sp_buf_annotate_gate(node, buf_param); + + req_diff = sp_buf_get_target(node, buf_param, constrained, &max_load); + + if (buf_param->debug){ + (void)fprintf(misout,"Buffering %s node %s\n\t (gate = %s, %s-diff = %6.2f:%-6.2f)\n", + (node->type == INTERNAL ? "INTERNAL" : "PRIMARY_INPUT"), + node_long_name(node), sp_name_of_impl(node), + (constrained ? "CONSTRAINED": "UNCONSTRAINED"), + req_diff.rise, req_diff.fall); + } + + fanout_data = sp_get_fanout_set(node); + fanout_data->max_ip_load = max_load; + n = fanout_data->num_pos + fanout_data->num_neg; + + if (n < buf_param->limit){ + FREE(fanout_data->fanouts); + FREE(fanout_data); + return changed; + } + + /* Also need to set the appropriate data for the inv_node */ + if (fanout_data->inv_node != NIL(node_t)){ + sp_buf_annotate_gate(fanout_data->inv_node, buf_param); + } + + for (i = 0; i < n; i++){ + sp_buf_req_time(fanout_data->fanouts[i].fanout, buf_param, + fanout_data->fanouts[i].pin, &(fanout_data->fanouts[i].req), + &(fanout_data->fanouts[i].load)); + } + changed = sp_buffer_recur(network, buf_param, fanout_data, req_diff, &level); + + FREE(fanout_data->fanouts); + FREE(fanout_data); + + return changed; +} + +/* + * Routine that returns 1 if the load at the output of "node" exceeds the + * "max_load" specified by the parameters of "gate" + */ +int +sp_max_load_violation(node) +node_t *node; +{ + int i; + double load, limit; + lib_gate_t *gate; + + if (node == NIL(node_t) || (gate = lib_gate_of(node)) == NIL(lib_gate_t)) + return 0; + + /* Node is mapped: The gate must have the max_load parameter */ + load = delay_load(node); + for ( i = node_num_fanin(node); i-- > 0; ){ + limit = delay_get_load_limit(gate->delay_info[i]); + if (load > limit) return 1; + } + return 0; +} + +/* + * Traverses the outputs and makes sure that all nodes satisfy the + * limitation specified by the "max_load" limitation of its gate + * Returns 1 if the routine changed the network... + */ +/* ARGSUSED */ +int +sp_satisfy_max_load(network, buf_param) +network_t *network; +buf_global_t *buf_param; +{ + int i, changed = 0; + node_t *node; + array_t *nodevec, *redo_nodes; + + redo_nodes = array_alloc(node_t *, 0); + nodevec = network_dfs_from_input(network); + + for ( i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + if (node_type(node) == INTERNAL && sp_max_load_violation(node)){ + array_insert_last(node_t *, redo_nodes, node); + } + } + if (array_n(redo_nodes) > 0){ + (void)fprintf(sisout, "Ensuring that max_load constraints are met\n"); + for (i = 0; i < array_n(redo_nodes); i++){ + node = array_fetch(node_t *, redo_nodes, i); + (void)fprintf(sisout, "Node %s\n", node_name(node)); + } + } + + array_free(redo_nodes); + array_free(nodevec); + + return changed; +} + +static int speed_do_area_recover(); + + /* Run the area recovery --- Visit all nodes from the outputs to the + * inputs. In case the area can be reduced without worsening performance, + * downsize the gate + */ +int +speed_buffer_recover_area(network, buf_param) +network_t *network; +buf_global_t *buf_param; +{ + int i, changed, false; + node_t *node, *temp; + double min_slack; + array_t *nodevec; + + changed = FALSE; + if (lib_network_is_mapped(network)) { + nodevec = network_dfs_from_input(network); + (void)sp_minimum_slack(network, &min_slack); + + for (i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + if (node->type == INTERNAL) { + if (speed_do_area_recover(network, node, buf_param, min_slack)){ + changed = TRUE; + (void)delay_trace(network, buf_param->model); + (void)sp_minimum_slack(network, &min_slack); + } + } + } + + array_free(nodevec); + } + return changed; +} + +typedef struct buf_cost_struct{ + delay_time_t slack; + double area; + } buf_cost_t; + +#define BUF_EQUAL_DOUBLE(a,b) (ABS((a)-(b)) < V_SMALL) + +/* Routine to check if the slack is acceptable and area is smaller */ +static int +buf_cur_version_is_better(cost1, cost2, min_slack) +buf_cost_t *cost1; +buf_cost_t *cost2; +double min_slack; +{ + double slack1 = BUF_MIN_D(cost1->slack); + double slack2 = BUF_MIN_D(cost2->slack); + double diff = slack1 - slack2; + + if (BUF_EQUAL_DOUBLE(slack1, min_slack)) slack1 = min_slack; + if (BUF_EQUAL_DOUBLE(slack2, min_slack)) slack2 = min_slack; + if (BUF_EQUAL_DOUBLE(diff, 0.0)) diff = 0.0; + + if (slack2 < min_slack /* 0 */) { + return (diff > 0) ? 1 : 0; + } else if (slack1 < min_slack) { + return 0; + } else { + return (cost1->area < cost2->area) ? 1 : 0; + } +} +#undef BUF_EQUAL_DOUBLE + +/* Utility routines to recompute arrival time data when gates/loads are + * changed + */ + +static delay_time_t +buf_get_reloaded_arrival_time(node, load_diff) +node_t *node; +double load_diff; +{ + int i, ninputs; + node_t *fanin; + lib_gate_t *gate; + double load; + network_t *net = node_network(node); + delay_time_t arrival, drive, t; + delay_time_t **arrival_times_p, *arrival_times; + + load = delay_load(node) + load_diff; + assert(node->type != PRIMARY_OUTPUT); + if (node->type == PRIMARY_INPUT) { + arrival.rise = arrival.fall = 0.0; + if (!delay_get_pi_arrival_time(node, &arrival)){ + if ((t.rise = delay_get_default_parameter(net, + DELAY_DEFAULT_ARRIVAL_RISE)) != DELAY_NOT_SET && + (t.fall = delay_get_default_parameter(net, + DELAY_DEFAULT_ARRIVAL_FALL)) != DELAY_NOT_SET) { + arrival = t; + } + } + drive.rise = drive.fall = 0.0; + if (!delay_get_pi_drive(node, &drive)){ + if ((t.rise = delay_get_default_parameter(net, + DELAY_DEFAULT_DRIVE_RISE)) != DELAY_NOT_SET && + (t.fall = delay_get_default_parameter(net, + DELAY_DEFAULT_DRIVE_FALL)) != DELAY_NOT_SET) { + drive = t; + } + } + arrival.rise += drive.rise * load; + arrival.fall += drive.fall * load; + } else { + gate = lib_gate_of(node); + ninputs = lib_gate_num_in(gate); + arrival_times = ALLOC(delay_time_t, ninputs); + arrival_times_p = ALLOC(delay_time_t *, ninputs); + foreach_fanin(node, i, fanin){ + arrival_times[i] = delay_arrival_time(fanin); + arrival_times_p[i] = &(arrival_times[i]); + } + arrival = delay_map_simulate(ninputs, arrival_times_p, + gate->delay_info, load); + FREE(arrival_times); + FREE(arrival_times_p); + } + return arrival; +} + +delay_time_t +buf_get_new_arrival_time(node, new_gate, min_slack, input_worsened) +node_t *node; +lib_gate_t *new_gate; +double min_slack; +int *input_worsened; +{ + int i, ninputs; + node_t *fanin; + delay_time_t *arrival_times; + delay_time_t **arrival_times_p; + lib_gate_t *orig_gate; + delay_time_t arrival, sl, req, new_ip_req, new_ip_slack; + delay_pin_t *pin_delay; + double load, load_diff; + + orig_gate = lib_gate_of(node); + *input_worsened = FALSE; + if (new_gate == orig_gate) { + return delay_arrival_time(node); + } + ninputs = lib_gate_num_in(new_gate); + arrival_times = ALLOC(delay_time_t, ninputs); + arrival_times_p = ALLOC(delay_time_t *, ninputs); + load = delay_load(node); + for (i = 0; i < ninputs; i++) { + pin_delay = (delay_pin_t *)(new_gate->delay_info[i]); + load_diff = delay_get_load(new_gate->delay_info[i]) - + delay_get_load(orig_gate->delay_info[i]); + fanin = node_get_fanin(node, i); + arrival_times[i] = buf_get_reloaded_arrival_time(fanin, load_diff); + arrival_times_p[i] = &(arrival_times[i]); + + /* Also make sure that this input does not become more critical */ + new_ip_req = delay_required_time(node); + sp_subtract_delay(pin_delay->phase, pin_delay->block, + pin_delay->drive, load, &new_ip_req); + req = delay_required_time(fanin); + MIN_DELAY(req,req,new_ip_req); /* "req" is the new req time at fanin */ + new_ip_slack.rise = req.rise - arrival_times[i].rise; + new_ip_slack.fall = req.fall - arrival_times[i].fall; + + if (BUF_MIN_D(new_ip_slack) < min_slack){ + *input_worsened = TRUE; + } + } + arrival = delay_map_simulate(ninputs, arrival_times_p, + new_gate->delay_info, load); + FREE(arrival_times); + FREE(arrival_times_p); + return arrival; + +} + /* Evaluate the different versions of the gate and select the smallest one + * that does not worsen performance + */ +static int +speed_do_area_recover(network, node, buf_param, min_slack) +network_t *network; +node_t *node; +buf_global_t *buf_param; +double min_slack; +{ + lsGen gen; + int i, best_index, input_restricted; + buf_cost_t best_cost, cost; + array_t *cost_array; + lib_gate_t *orig_gate, *gate; + delay_time_t required, arrival; + + /* Get the slack at the output of the node for the different versions*/ + required = delay_required_time(node); + orig_gate = lib_gate_of(node); + gen = lib_gen_gates(lib_gate_class(orig_gate)); + cost_array = array_alloc(buf_cost_t, 0); + while (lsNext(gen, (char **)&gate, LS_NH) == LS_OK){ + arrival = buf_get_new_arrival_time(node, gate, min_slack, &input_restricted); + if (input_restricted) { + /* Do not consider this one at all. Repowering leads to + * making other paths more critical (i.e. it is restricted by + * the loading at the inputs + */ + cost.slack.rise = cost.slack.fall = NEG_LARGE; + cost.area = POS_LARGE; + } else { + cost.slack.rise = required.rise - arrival.rise; + cost.slack.fall = required.fall - arrival.fall; + cost.area = lib_gate_area(gate); + } + array_insert_last(buf_cost_t, cost_array, cost); + } + lsFinish(gen); + + best_index = -1; + best_cost.slack.rise = best_cost.slack.fall = NEG_LARGE; + best_cost.area = POS_LARGE; + for (i = 0; i < array_n(cost_array); i++) { + cost = array_fetch(buf_cost_t, cost_array, i); + if (buf_cur_version_is_better(&cost, &best_cost, min_slack)) { + best_cost = cost; + best_index = i; + } + } + assert(best_index >= 0); + gate = buf_get_gate_version(orig_gate, best_index); + sp_replace_lib_gate(node, orig_gate, gate); + array_free(cost_array); + return (gate != orig_gate); /* Change has been made */ +} + diff --git a/sis/speed/sp_network.c b/sis/speed/sp_network.c new file mode 100644 index 0000000..6af5e04 --- /dev/null +++ b/sis/speed/sp_network.c @@ -0,0 +1,164 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/sp_network.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include <stdio.h> +#include "sis.h" +#include "speed_int.h" + +#define SPEED_DUP_PARAM(from,to,p,r) \ + (r = delay_get_parameter(from,p), (void) delay_set_parameter(to, p, r)) + +/* + * If delay_flag == 1 take the delay of the + * fanins from the user field + */ + +static int +speed_delay_parameters_dup(from, to, speed_param, delay_flag) +node_t *from, *to; +speed_global_t *speed_param; +int delay_flag; +{ + delay_time_t time; + double temp; + + SPEED_DUP_PARAM(from, to, DELAY_BLOCK_RISE, temp); + SPEED_DUP_PARAM(from, to, DELAY_DRIVE_RISE, temp); + SPEED_DUP_PARAM(from, to, DELAY_BLOCK_FALL, temp); + SPEED_DUP_PARAM(from, to, DELAY_DRIVE_FALL, temp); + SPEED_DUP_PARAM(from, to, DELAY_MAX_INPUT_LOAD, temp); + + if (node_function(to) == NODE_PI) { + if (delay_flag) { + speed_delay_arrival_time(from, speed_param, &time); + } else { + time = delay_arrival_time(from); + } + + (void) delay_set_parameter(to, DELAY_ARRIVAL_RISE, time.rise); + (void) delay_set_parameter(to, DELAY_ARRIVAL_FALL, time.fall); + } else if (node_function(to) == NODE_PO){ + temp = delay_load(from); + (void)delay_set_parameter(to, DELAY_OUTPUT_LOAD, temp); + } + + return 1; +} + +network_t * +speed_network_create_from_node(f, speed_param, delay_flag) +node_t *f; +speed_global_t *speed_param; +int delay_flag; +{ + network_t *network; + lsGen gen; + node_t *pi, *fanin, *po; + + network = network_create_from_node(f); + + /* Copy the delay parameters */ + foreach_primary_output(network, gen, po){ + if (!speed_delay_parameters_dup(f, po, speed_param, delay_flag) ) { + fail("Duplication of output parameters "); + (void) lsFinish(gen); + } + } + + foreach_primary_input(network, gen, pi){ + if ((fanin = name_to_node(f, node_long_name(pi))) != NIL(node_t)){ + if (!speed_delay_parameters_dup(fanin, pi, speed_param, delay_flag) ){ + fail("Duplication of input parameters "); + (void) lsFinish(gen); + } + } + } + + return network; +} + +array_t * +network_to_array(network) +network_t *network; +{ + array_t *nodevec, *array; + node_t *node, *fanin, *newnode; + int i, j; + + array = array_alloc(node_t *, 0); + nodevec = network_dfs_from_input(network); + for (i = 0, j = 0; i < array_n(nodevec); j++, i++){ + node = array_fetch(node_t *, nodevec, i); + newnode = node_dup(node); + node->copy = newnode; + array_insert(node_t *, array, j, newnode); + } + + /* Change the fanin pointers */ + for (i = 0; i < array_n(array); i++){ + node = array_fetch(node_t *, array, i); + foreach_fanin(node, j, fanin){ + node->fanin[j] = fanin->copy; + } + fanin_add_fanout(node); + } + array_free(nodevec); + return array; +} + +/* + * For the nodes in the network, return an array of nodes that can be added to + * another network (the internal pointers are consistent). If a hash_table + * is also provided then it records the library gate that implements that node + */ +array_t * +network_and_node_to_array(network, innode, table) +network_t *network; +node_t *innode; +st_table *table; +{ + array_t *nodevec, *array; + node_t *node, *fanin, *newnode, *orig; + int i, j; + + array = array_alloc(node_t *, 0); + nodevec = network_dfs_from_input(network); + for (i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + newnode = node_dup(node); + if (table != NIL(st_table)){ + (void)st_insert(table, (char *)newnode, (char *)lib_gate_of(node)); + } + node->copy = newnode; + array_insert(node_t *, array, i, newnode); + } + + /* Change the fanin pointers */ + for (i = 0; i < array_n(array); i++){ + node = array_fetch(node_t *, array, i); + FREE(node->fanin_fanout); + node->fanin_fanout = ALLOC(lsHandle, node->nin); + foreach_fanin(node, j, fanin){ + if (fanin->type == PRIMARY_INPUT) { + /* patch the fanin to original */ + if ((orig = name_to_node(innode, node_long_name(fanin))) != NIL(node_t)){ + node->fanin[j] = orig; + } else { + fail("Failed to retrieve the original node"); + } + } + else { + /* update the fanin pointer */ + node->fanin[j] = fanin->copy; + } + } + } + array_free(nodevec); + return array; +} diff --git a/sis/speed/speed.doc b/sis/speed/speed.doc new file mode 100644 index 0000000..706066b --- /dev/null +++ b/sis/speed/speed.doc @@ -0,0 +1,195 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ + The routines described herein are provided for the use of + applications programmers who wish to use performance + optimization within their code. Since the exported interface + is not compelte (the programmer is not allowed full control + and some of the specified parameters may be ignored) one may + consider using the function "com_execute()" to avail of the + many different options that the user can provide on the + command-line. + + If an advanced programmer is interested in using the + internal-routines they must follow the sequence of calls inthe + command speed_loop_interface() in the file speed_loop.c... + After the initial setup, one can call alternate routines like + new_speed(network, &speed_param) /* for the latest stuff */ + or make an additional assignment and call + speed_param.new_mode = 0; + seed_up_network(network, &speed_param); /* for the orig code */ + +void +speed_loop_interface(network, thresh, coeff, dist, model, flag) +network_t **network; +delay_model_t model; +double thresh, coeff; +int dist, flag; + Speed-up the network and keep the best network seen till + now. Exits the program if a serious error occurs. + "dist" is the distance for collapsing. A value of 3 is the default. + "model" is the delay model used for computing delays during + the speedup. The default is DELAY_MODEL_UNIT. + "flag" = 1 produces an output to "misout" describing how the + delay changes at each iteration. Flag = 0 is the silent mode. + +void +speed_node_interface(network, node, coeff, model) +network_t *network; +node_t *node; +double thresh, coeff; +delay_model_t model; + Speedup the node f belonging to the network. The node f is + modified in place by a 2-input nand gate decomposition. + ASSUMES that a delay trace using the delay_model "model" has + already been done so that the arrival times at the inputs of + node f are valid. + Exits the program if there is a serious error. + + +array_t * +speed_decomp_interface(f, coeff, model) +node_t * f; +double coeff; +delay_model_t model; + Returns an array of nodes representing the node f as a + 2-input nand representation. A valid delay trace must have + been performed on the node so that the fanins have arrival + time information annotated. The array contains nodes of + type NODE_PO, NODE_PI and internal nodes. Only the + internal nodes should be used by the calling routine. + This is a manifestation of the fact that the nodes in the + returned array are not part of the network, but nodes in + the array have the same fanins as node f. The first + internal node is the root node and the node f can be + replaced by this node. The remaining nodes can be simply + added to the network. + Returns NIL(array_t) if there has been an error. + +/* + Routines to improve circuit performance by adding buffers. +*/ + +int +buffer_network(network, limit, trace, thresh, single_pass, do_decomp) +network_t *network; +int limit; +int trace; +double thresh; +int single_pass; +int do_decomp; + This routine operates on an entire network and will find + out appropriate sites to add buffers. If the network is mapped, + the "mapped" delay model will be used else the "unit-fanout" + model is used. The routine will iterate over different + cutsets of the critical paths (except when "single_pass" = 1). + If the required time is set for the primary outputs the algorithm + will try to meet them, otherwise it will buffer so as to reduce + the delay thru the circuit. + The critical paths are determined by the parameter "thresh". + The paths with a slack value within "thresh" of the smallest + slack are deemed to be critical. + If the "trace" parameter is set to 1, the delay data will be + printed to misout as the algorithm proceeds. + "limit" specifies the acceptable fanout limit for a gate. + Nodes with fanout less than this are not candidates for buffering. + If "do_decomp" parameter is specified, the routine will + also attempt the decomposition of complex gates in an effort to + increace performance. + +/* + * The following routines are provided for interface to the buffering + * algorithm by other packages (actually only the MAP package) + */ + +void +buffer_init_globals(lib_present, limit, mode, do_decomp, debug) +int lib_present; /* Generate buffers from the library */ +int limit; /* Limit for the fanout algorithm */ +int mode; /* Which transformations to carry out */ +int do_decomp; /* Should root node be decomposed */ +int debug; /* Set the level of verbosity */ + This routine sets up the global data structure used in the + recursive buffering algorithm. The parameters to this routine + are used to set up global information. + "lib_present" when non-zero instructs the algorithm to + use the inverters present in the library. "limit" is the + maximum number of fanouts that a node can have. + "mode" is a three bit flag that can be used to enable/ + disable some of the delay reducing transformations. Thus if the + binary representation of "mode" is 0x.....BUR, the three least + significant digits enable(1)/disable(0) the transformations + "Repower", "Unbalanced" and "Balanced". + The parameter "do_decomp" when set will allow the + decomposition of the root agt into smaller gates if required. + "debug" is a verbosity level. the range is 1-20. + + +int +sp_buffer_recur(network, fanout_data, req_diff, levelp) +network_t *network; +buf_alg_input_t *fanout_data; /* The data regarding the fanouts */ +delay_time_t req_diff; /* This much needs to be saved */ +int *levelp; /* Iteration counter */ + The basic recursive routine. Depending on the "mode" set when + initializing the defaults, the routine may + -- redistribute the fanouts of node by adding a buffer + and/or -- Try a balanced decomposition of the outputs.. + and/or -- try to decompose node into smaller gates + + The contents of "levelp" must be 0 when the routine is invoked by + the user for a particular instance of the fanout problem. + "req_diff" tells the routine how much the delay at the root + needs to be improved by. + + +*********** ADDING NEW OPTIMIZATIONS TO THE SPEED_UP CODE ******* + + The speed_up package has undergone major modifications (in its + structure as well as the algorithms) since the sis release 2.1. The + new package allows the user to select form a set of optimizations. + These optimizations are applied to regions whose size and influence + the user can control. The local performance improvements are cast + into an algorithm that ensures that the predicted saving can be + achieved at a small cost (at least in the case of unmapped + circuits). For mapped circuits the prediction of achievable saving + is difficult due to the interactions between transforms. However, + the techniquies work well in practice. + + The modularity of the code allows the user to add their favorite + transformations without much problem. In case the transformations + affect the way in which delay is computed (e.g. an annotation on a + node that specified gate doubling) the routines in the delay + package will ahve to be changed as well to account for this. + Hopefully only an appropriate change to the routine get_pin_delay() + will be adequate. + + In order to specify a new optimization follow the steps stated + below + 1) Create an entry int he file new_speed_models.h that has + /* name, opt_fn, delay computing fn, priority, on-flag, netw-flag */ + where name = name of the optimization so that it can be selected + using the comand speedup_alg + opt_fn = The optimization code that given a network returns + the optimized network + delay_fn = The function that will return the performance of + the optimized network (arrival/required time) + priority = The evaluation of optimizations is stopped if a + transform with lower-value of this flag succeeds + on-flag = If this optimization is enabled by default + netw_flag = A flag that makes the use of delay_fn obsolete + since based on this the optimization is applied on + either a subnetwork or a fanout-branch. The value + DUAL for this flag is currently not processed. It was + intended for subnetworks with multiplt inputs and + outputs but the theory does not handle that yet... + 2) Add the routine opt_fn() to the code + 3) recompile. + 4) enable the optimization using the speedup_alg command + 5) The optimization is now avialable for use diff --git a/sis/speed/speed.h b/sis/speed/speed.h new file mode 100644 index 0000000..e874fe0 --- /dev/null +++ b/sis/speed/speed.h @@ -0,0 +1,61 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#ifndef SPEED_H +#define SPEED_H + +EXTERN void speed_node_interface ARGS((network_t *, node_t *, double, delay_model_t)); +EXTERN void speed_loop_interface ARGS((network_t **, double, double, int, delay_model_t, int)); +EXTERN array_t *speed_decomp_interface ARGS((node_t *, double, delay_model_t)); + +EXTERN int buffer_network ARGS((network_t *, int, int, double, int, int)); + +/* + * some of the low level buffering stuff ... + * The data structures are exported for the mapper to interface with buffering + */ + +typedef struct sp_fanout_struct{ + int pin; /* The "fanin_index" of the destination pin */ + double load; /* The input_cap of the destination */ + node_t *fanout; /* The node to which destination belongs to */ + delay_time_t req; /* Req time of the destination */ + pin_phase_t phase; /* Whether POS or NEG poloarity signal */ + } sp_fanout_t; + +typedef struct buffer_alg_input_struct buf_alg_input_t; +struct buffer_alg_input_struct { + node_t *root; /* root node of the buffering problem */ + node_t *node; /* node at which buffering is being performed*/ + node_t *inv_node; /* node driving inv destinations */ + sp_fanout_t *fanouts; /* Description of the fanout destinations */ + int num_pos; /* Number of positive fanouts */ + int num_neg; /* Number of negative destination */ + double max_ip_load; /* The max load at "cfi" input of root */ + }; + + +/* Following routines are for the map package */ +EXTERN void buf_init_top_down ARGS((network_t *, int, int)); +EXTERN void buf_map_interface ARGS((network_t *, buf_alg_input_t *)); +EXTERN void buf_add_implementation ARGS((node_t *, lib_gate_t *)); +EXTERN void buf_set_prev_drive ARGS((node_t *, delay_time_t)); +EXTERN void buf_set_prev_phase ARGS((node_t *, pin_phase_t)); +EXTERN void buf_set_required_time_at_input ARGS((node_t *, delay_time_t)); +EXTERN double buf_get_auto_route ARGS((void)); +EXTERN delay_model_t buf_get_model ARGS((void)); +EXTERN delay_time_t buf_get_required_time_at_input ARGS((node_t *)); + +#endif + + + + + + diff --git a/sis/speed/speed_2c.c b/sis/speed/speed_2c.c new file mode 100644 index 0000000..688af36 --- /dev/null +++ b/sis/speed/speed_2c.c @@ -0,0 +1,290 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed_2c.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +/* + * Based on the distribution of the arrival time information, evaluate the + * 2-cube divisors and then extract the best ... + */ + +#include "sis.h" +#include "speed_int.h" + +#define SCALE_2 100000 +#define SCALE 100 + +#define CRITICAL_FRACTION 0.05 +#define FUDGE 0.0001 +/* Original value +#define CRITICAL_FRACTION 0.0001 +*/ + +typedef struct sp_2c_kernel_info sp_2c_kernel_info_t; +struct sp_2c_kernel_info { + node_t *node; /* Node which is being decomposed */ + int use_cokernel; /* If set, use the cokernel instead of 2c_div */ + double d_cost; /* The current value for the best divisor */ + double a_saving; /* Saving in literals resulting from extraction */ + double thresh; /* Separating the early from the late inputs */ + speed_global_t *globals; /* Reference to all the global information */ + }; + +extern void node_evaluate(); /* Part of speed_net.c */ +extern node_t *fx_2c_kernel_best(); /* Part of gen_2c_kernel.c */ +static int sp_eval_2c_kernel(); + +int twocube_timeout_occured = 0; /* Flag describing whether timeout has occured */ + +int +speed_2c_decomp(network, node, speed_param, attempt_no) +network_t *network; +node_t *node; +speed_global_t *speed_param; +int attempt_no; /* selects different decompositions */ +{ + int i, j; + delay_time_t time; + node_t *np, *rem, *temp, *best; + double min_t, max_t; + sp_2c_kernel_info_t *store; + + if (speed_param->debug) { + (void) fprintf(sisout," Decomposing node \n"); + node_print(sisout, node); + (void)fprintf(sisout,"\tInput arrival times "); + j = 0; + foreach_fanin(node, i, np){ + speed_delay_arrival_time(np, speed_param, &time); + if ((j % 3 == 0) && (j != node_num_fanin(node))) { + (void) fprintf(sisout,"\n\t"); + } + j++; + (void) fprintf(sisout,"%s at %-5.2f, ", node_name(np), time.rise); + } + (void)fprintf(sisout,"\n"); + } + + + if ((!twocube_timeout_occured) && + (temp = ex_find_divisor_quick(node)) != NIL(node_t) ) { + node_free(temp); + + /* Implies kernel exists: Now go ahead and generate them */ + store = ALLOC(sp_2c_kernel_info_t, 1); + store->node = node; + store->d_cost = POS_LARGE; + store->a_saving = NEG_LARGE; + store->use_cokernel = -1; + store->globals = speed_param; + + /* + * Set the threshold to delete nodes with arrival times in the + * last .01% of the nodes-- (effectively the latest input) + */ + max_t = NEG_LARGE; + min_t = POS_LARGE; + foreach_fanin(node, i, np){ + speed_delay_arrival_time(np, speed_param, &time); + max_t = D_MAX(max_t, D_MAX(time.rise, time.fall)); + min_t = D_MIN(min_t, D_MIN(time.rise, time.fall)); + } + if ((max_t - min_t) < 1.0e-3) { + store->thresh = POS_LARGE; + } else { + store->thresh = + max_t - (attempt_no*CRITICAL_FRACTION + FUDGE) * (max_t-min_t); + } + + if ((best = fx_2c_kernel_best(node, sp_eval_2c_kernel, store)) != + NIL(node_t)){ + /* Extract the best divisor */ + if (store->use_cokernel == 1){ + /* + * Use the co-kernel corresponding to the best 2c_kernel + * Take care to see that the critical cubes are deleted + * from the divisor. Mirror the evaluation code !!! + */ + if (speed_param->del_crit_cubes){ + speed_del_critical_cubes(best, speed_param, store->thresh); + } + temp = node_div(store->node, best, &rem); + assert(node_function(temp) != NODE_0); + node_free(best); + node_free(rem); + best = temp; + } + if (speed_param->del_crit_cubes){ + speed_del_critical_cubes(best, speed_param, store->thresh); + } + + network_add_node(network, best); + if (speed_param->debug){ + (void) fprintf(sisout,"\tBest 2c-kernel is "); + node_print(sisout, best); + } + + /* Substitute the divisor into the function */ + if (!node_substitute(node, best, 1)){ + node_free(best); + fail("Error substituting node during 2c_kernel decomp \n"); + } + /* + * Recursively decompose the divisor + */ + if (!speed_2c_decomp(network, best, speed_param, attempt_no)){ + error_append("Failed while decomposing extracted kernel"); + fail(error_string()); + } + + /* + * The arrival time at the remaining node should + * be valid, since speed_and_or_decomp returns + * the node with a valid delay + */ + + if (!speed_2c_decomp(network, node, speed_param, attempt_no)){ + error_append("Failed while decomposing extracted kernel"); + fail(error_string()); + } + } else { + /* No 2-cube divisor is appropriate */ + if (speed_param->debug) { + (void) fprintf(sisout,"\tNo 2c-kernel appropriate -- AND_OR decomp\n"); + } + if(!speed_and_or_decomp(network, node, speed_param)){ + error_append("Failed AND_OR decomp of kernel-free function "); + fail(error_string()); + } + if (!speed_param->add_inv){ + speed_delete_single_fanin_node(network, node); + } + } + + FREE(store); + + } else { + /* + * If no relevant 2-cube divisor exits or the function of the + * is such that there is no point in looking for kernels the decomp + * into 2-input AND gates according to the arrival times + */ + + if (speed_param->debug) { + (void) fprintf(sisout,"\tNo 2-cube div -- doing AND_OR decomp\n"); + } + if(!speed_and_or_decomp(network, node, speed_param)){ + error_append("Failed to decomp 2-cube free node into AND gates"); + fail(error_string()); + } + if (!speed_param->add_inv){ + speed_delete_single_fanin_node(network, node); + } + } + return 1; +} + +/* + * Routine to evaluate the cost of a kernel + * Also keeps the best divisor and its cost. + */ + +static int +sp_eval_2c_kernel(ddivisor, node_2c, handlep, state) +ddivisor_t *ddivisor; +node_t *node_2c; +lsHandle **handlep; +char *state; +{ + sp_2c_kernel_info_t *store = (sp_2c_kernel_info_t *)state; + + node_t *new_cokernel, *rem; + double k_t_cost, c_t_cost; /* time cost of kern and co-kern */ + double k_a_cost, c_a_cost;; /* area cost of kern and co-kern */ + + if (twocube_timeout_occured) { + /* Time is up !!! return 0 to stop generation */ + return 0; + } + if (store->globals->debug){ + (void)fprintf(sisout, "2c_kernel "); + node_print_rhs(sisout, node_2c); + } + /* Make the kernel free of any cubes containing critical signals */ + if (store->globals->del_crit_cubes){ + speed_del_critical_cubes(node_2c, store->globals, store->thresh); + } + + if (node_function(node_2c) == NODE_0 || node_num_fanin(node_2c) == 1){ + /* Don't consider this kernel pair */ + return 1; + } + + /* + * Generate the cokernel, reduce it to non crit signals + * and -- (as large as possible) and evaluate the cost + */ + + new_cokernel = node_div(store->node, node_2c, &rem); + node_free(rem); + /* + * If the node itself is a kernel dont consider it as a potential divisor + */ + if (node_function(new_cokernel) == NODE_1){ + node_free(new_cokernel); + return 1; + } + if (store->globals->del_crit_cubes){ + speed_del_critical_cubes(new_cokernel, store->globals, store->thresh); + } + + if (node_function(new_cokernel) != NODE_0 && node_num_fanin(new_cokernel) > 1){ + node_evaluate(node_2c, new_cokernel, store->globals, + &k_t_cost, &k_a_cost); + node_evaluate(new_cokernel, node_2c, store->globals, + &c_t_cost, &c_a_cost); + } + else{ + node_evaluate(node_2c, new_cokernel, store->globals, + &k_t_cost, &k_a_cost); + c_t_cost = POS_LARGE; c_a_cost = NEG_LARGE; + } + + if (store->globals->debug){ + (void)fprintf(sisout, " RESULTS IN "); + node_print_rhs(sisout, node_2c); + (void)fprintf(sisout, " AND "); + node_print_rhs(sisout, new_cokernel); + (void)fprintf(sisout, "\n"); + } + + /* Keep best around: Ties broken by greater area_saving */ + if ((k_t_cost < store->d_cost) || + (k_t_cost == store->d_cost && k_a_cost > store->a_saving)){ + *handlep = &(fx_get_div_handle(ddivisor)); + store->use_cokernel = 0; + store->a_saving = k_a_cost; + store->d_cost = k_t_cost; + } + /* Also check the co-kernels : Ideally these should have been generated + * as a generator too, but this is good enuff !!! + */ + if ((c_t_cost < store->d_cost) || + (c_t_cost == store->d_cost && c_a_cost > store->a_saving)){ + *handlep = &(fx_get_div_handle(ddivisor)); + store->use_cokernel = 1; + store->a_saving = c_a_cost; + store->d_cost = c_t_cost; + } + + node_free(new_cokernel); + + return 1; +} + + + diff --git a/sis/speed/speed_and.c b/sis/speed/speed_and.c new file mode 100644 index 0000000..3606e5e --- /dev/null +++ b/sis/speed/speed_and.c @@ -0,0 +1,130 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed_and.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +/************************************************ +* Routine to decompose a node with one cube +* into an and tree based on the delay at its inputs +**************************************************/ +#include <stdio.h> +#include "sis.h" +#include "speed_int.h" + +int +speed_and_decomp(network, node, speed_param, flag) +network_t *network; +node_t *node; +speed_global_t *speed_param; +int flag; /* 1 => invert, 0 => no inversion */ +{ + node_cube_t cube; + node_t *new_node, *temp_node, *fanin, *speed_dec_node_cube(); + node_t *nlit, *mlit; + double a_t, best_t, second_t; /* Arrival times of the inputs */ + int a_p, best_p = 1, second_p = 1; /* Phase of the inputs */ + int i, n_lit = 0, first=0 , second=0 ; + node_literal_t literal; + delay_time_t time, new_at; + + best_t = second_t = POS_LARGE; + if (node_num_literal(node) == 0){ + if (flag){ + new_node = node_not(node); + node_replace(node, new_node); + } + speed_single_level_update(node, speed_param, &new_at); + return 1; + } + cube = node_get_cube(node, 0); + + /* + if (speed_debug){ + (void) fprintf(sisout,"\t\tAND_DECOMPOSING node \t"); + node_print(sisout,node); + } + */ + + /* + * Select the two earliest signals + */ + foreach_fanin(node, i, fanin){ + /* + if (speed_debug ){ + (void) fprintf(sisout, "Node %s -- a_time = ", node_name(fanin)); + } + */ + literal = node_get_literal(cube, i); + if ((literal == ONE) || (literal == ZERO)){ + n_lit++; + speed_delay_arrival_time(fanin, speed_param, &time); + a_t = MAX(time.rise, time.fall); + a_p = (literal == ONE) ? 1 : 0; + + /* + if (speed_debug) (void) fprintf(sisout, "%5.2f\n", a_t); + */ + if (a_t < best_t){ + second = first; second_p = best_p; second_t = best_t; + first = i; best_p = a_p; best_t = a_t; + } + else if (a_t < second_t){ + second = i; second_p = a_p; second_t = a_t; + } + } + } + + if (n_lit > 2){ + /* Create a and node with the two inputs as the + "first" and "second' variables */ + nlit = node_literal(node_get_fanin(node, first), best_p); + mlit = node_literal(node_get_fanin(node, second), second_p); + new_node = node_and(nlit, mlit); + node_free(nlit); node_free(mlit); + network_add_node(network, new_node); + + /* + * Update the arrival time for new_node + */ + speed_single_level_update(new_node, speed_param, &new_at); + + /* Recursively decompose the node */ + if (node_substitute(node, new_node, 1) ){ + if(!speed_and_decomp(network, node, speed_param, flag)){ + error_append("Failed in and_decomp "); + fail(error_string()); + } + } else { + error_append("substitute failed in speed_and_decomp\n"); + fail(error_string()); + } + } else { + if(flag ){ + /* + * Return the node after inverting it and + * updating the arrival times. + */ + if (n_lit > 1 ){ + /* + * Add an explicit inverter + */ + temp_node = node_dup(node); + network_add_node(network, temp_node); + nlit = node_literal(temp_node, 0); + node_replace(node, nlit); + speed_single_level_update(temp_node, speed_param, &new_at); + } + else { + temp_node = node_not(node); + node_replace(node, temp_node); + } + } + speed_single_level_update(node, speed_param, &new_at); + } + + return 1; +} diff --git a/sis/speed/speed_delay.c b/sis/speed/speed_delay.c new file mode 100644 index 0000000..1104991 --- /dev/null +++ b/sis/speed/speed_delay.c @@ -0,0 +1,520 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed_delay.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include "speed_int.h" + +void speed_reset_arrival_time(); +static delay_time_t speed_delay_node_pin(); +static int speed_update_arrival_time_recur(); +static delay_pin_t *get_pin_delay_of_function(); + + /* Analogous to delay_latest_output() ... However gets the most critical + * PO and the corresponding slack time + */ +node_t * +sp_minimum_slack(network, min_slack) +network_t *network; +double *min_slack; +{ + lsGen gen; + node_t *best, *node; + delay_time_t cur_slack, slack; + + slack.rise = slack.fall = POS_LARGE; + + best = NIL(node_t); + foreach_primary_output(network, gen, node){ + cur_slack = delay_slack_time(node); + if (MIN(cur_slack.rise, cur_slack.fall) < MIN(slack.rise, slack.fall)){ + slack = cur_slack; + best = node; + } + } + *min_slack = MIN(slack.rise, slack.fall); + return best; +} + +int +sp_po_req_times_set(network) +network_t *network; +{ + int flag; + lsGen gen; + node_t *node; + delay_time_t req; + + if (delay_get_default_parameter(network, DELAY_DEFAULT_REQUIRED_RISE) != DELAY_NOT_SET || + delay_get_default_parameter(network, DELAY_DEFAULT_REQUIRED_FALL) != DELAY_NOT_SET) { + return TRUE; + } + + flag = FALSE; + foreach_primary_output(network, gen, node){ + flag = flag || delay_get_po_required_time(node, &req); + } + return flag; +} + + /* + * If the delay model being used is the MAPPED one, then we + * should get the delay through primitive NAND and use it instead + * of always having to get it after a mapping of the node + */ +speed_set_delay_data(speed_param, use_accl) +speed_global_t *speed_param; +int use_accl; +{ + library_t *lib; + delay_model_t model = speed_param->model; + double pin_cap = -1.0; + delay_pin_t *pin_delay; + + speed_param->library_accl = use_accl; + + if (model == DELAY_MODEL_MAPPED){ + lib = lib_get_library(); /* Assured that the library is present */ + pin_delay = get_pin_delay_of_function("f=!a;", lib); + speed_param->inv_pin_delay = *pin_delay; + pin_cap = MAX(pin_cap, pin_delay->load); + pin_delay = get_pin_delay_of_function("f=!(a+b);", lib); + speed_param->nand_pin_delay = *pin_delay; + pin_cap = MAX(pin_cap, pin_delay->load); + speed_param->pin_cap = pin_cap; + } +} + +void +speed_set_library_accl(speed_param, value) +speed_global_t *speed_param; +int value; +{ + speed_param->library_accl = value; +} + +int +speed_get_library_accl(speed_param) +speed_global_t *speed_param; +{ + return speed_param->library_accl; +} + +/* + * Return the delay model of the smallest agte implementing the given fucction + */ +static delay_pin_t * +get_pin_delay_of_function(s, lib) +char *s; +library_t *lib; +{ + network_t *network; + lib_class_t *class; + lib_gate_t *gate, *best_gate; + lsGen gen; + delay_pin_t *pin_delay; + double area, best_area; + + network = read_eqn_string(s); + class = lib_get_class(network, lib); + best_area = -1; + best_gate = NIL(lib_gate_t); + gen = lib_gen_gates(class); + while (lsNext(gen, (char **) &gate, LS_NH) == LS_OK) { + area = lib_gate_area(gate); + if (best_area < 0 || area < best_area) { + best_area = area; + best_gate = gate; + } + } + (void) lsFinish(gen); + network_free(network); + + pin_delay = (delay_pin_t *)(best_gate->delay_info[0]); + return pin_delay; +} + + +int +speed_update_arrival_time(node, speed_param) +node_t *node; +speed_global_t *speed_param; +{ + delay_time_t time; + + if (!speed_update_arrival_time_recur(node, speed_param, &time)){ + return 0; + } + return 1; +} + +static int +speed_update_arrival_time_recur(node, speed_param, delay) +node_t *node; +speed_global_t *speed_param; +delay_time_t *delay; +{ + int i; + double temp; + node_t *fanin; + delay_time_t t, time, fanin_time; + + delay->rise = NEG_LARGE; + delay->fall = NEG_LARGE; + + /* + * Recursion stops when a primary input is reached + * or if a node with computed delay values is found + */ + + if (node_function(node) == NODE_PI){ + /* + * Add the delay due to the fanouts + */ + fanin_time = speed_delay_node_pin(node, 0, speed_param); + if ( speed_param->debug && (fanin_time.rise < 0.0 || fanin_time.fall < 0.0)){ + (void)fprintf(sisout,"WARNING-1: speed_delay_node_pin\n"); + } + + temp = delay_get_parameter(node, DELAY_ARRIVAL_FALL); + delay->fall = (temp < 0.0 ? 0.0 : temp ) + fanin_time.fall; + + temp = delay_get_parameter(node, DELAY_ARRIVAL_RISE); + delay->rise = (temp < 0.0 ? 0.0 : temp ) + fanin_time.rise; + + } else if (node_function(node) == NODE_PO) { + fanin = node_get_fanin(node, 0); + if (!speed_update_arrival_time_recur(fanin, speed_param, &fanin_time) ){ + error_append("Failed in speed_update_arrival_time_recur"); + return 0; + } + *delay = fanin_time; + } else { + t.rise = delay_get_parameter(node, DELAY_ARRIVAL_RISE); + t.fall = delay_get_parameter(node, DELAY_ARRIVAL_FALL); + if ((t.fall < 0.0) || (t.rise < 0.0) ){ + /* + * Recursively find the arrival time. Keep the max of the + * (a_time+delay) as the arrival time at the node output + */ + foreach_fanin(node, i, fanin){ + if (!speed_update_arrival_time_recur(fanin, speed_param, + &fanin_time) ){ + error_append("Failed in speed_update_arrival_time_recur"); + return 0; + } + time = speed_delay_node_pin(node, i, speed_param); + if ( speed_param->debug && (time.rise < 0.0 || time.fall < 0.0)){ + (void)fprintf(sisout,"WARNING-2: speed_delay_node_pin\n"); + } + + /* Depending on the phase add the delay components */ + switch (node_input_phase(node, fanin)) { + case POS_UNATE : + delay->rise = MAX(delay->rise, + (fanin_time.rise + time.rise)); + delay->fall = MAX(delay->fall, + (fanin_time.fall + time.fall)); + break; + case NEG_UNATE : + delay->rise = MAX(delay->rise, + (fanin_time.fall + time.rise)); + delay->fall = MAX(delay->fall, + (fanin_time.rise + time.fall)); + break; + case BINATE : + delay->rise = MAX(delay->rise, + (fanin_time.rise + time.rise)); + delay->rise = MAX(delay->rise, + (fanin_time.fall + time.rise)); + delay->fall = MAX(delay->fall, + (fanin_time.rise + time.fall)); + delay->fall = MAX(delay->fall, + (fanin_time.fall + time.fall)); + break; + case PHASE_UNKNOWN : + default: + break; + } + } + if (node_num_literal(node) == 0) { + delay->fall = 0.0; delay->rise = 0.0; + } + speed_set_arrival_time(node, *delay); + } else { + /* return the value of the delay */ + *delay = t; + } + } + return 1; +} + +void +speed_delay_arrival_time(node, speed_param, time) +node_t *node; +speed_global_t *speed_param; +delay_time_t *time; +{ + node_t *fanin; + delay_time_t fanin_time; + double temp; + + if (node_function(node) == NODE_PO){ + fanin = node_get_fanin(node, 0); + speed_delay_arrival_time(fanin, speed_param, time); + } else if (node_function(node) == NODE_PI){ + /* + * Add the delay due to the fanouts + */ + fanin_time = speed_delay_node_pin(node, 0, speed_param); + if ( speed_param->debug && (fanin_time.rise < 0.0 || fanin_time.fall < 0.0)){ + (void)fprintf(sisout,"WARNING-3: speed_delay_node_pin\n"); + } + + temp = delay_get_parameter(node, DELAY_ARRIVAL_FALL); + time->fall = (temp < 0.0 ? 0.0 : temp ) + fanin_time.fall; + + temp = delay_get_parameter(node, DELAY_ARRIVAL_RISE); + time->rise = (temp < 0.0 ? 0.0 : temp ) + fanin_time.rise; + } else { + temp = delay_get_parameter(node, DELAY_ARRIVAL_FALL); + if (temp < 0){ + (void)fprintf(sisout,"negative fall arrival time for"); + node_print(sisout, node); + temp = 0; + } + time->fall = temp; + temp = delay_get_parameter(node, DELAY_ARRIVAL_RISE); + if (temp < 0){ + (void)fprintf(sisout,"negative rise arrival time for"); + node_print(sisout, node); + temp = 0; + } + time->rise = temp; + } +} + +void +speed_set_arrival_time(node, time) +node_t *node; +delay_time_t time; +{ + if ((time.rise < 0) || (time.fall < 0)){ + (void) fprintf(sisout,"Setting negative arrival time %7.2f:%-7.2f for ", + time.rise, time.fall); + node_print(sisout, node); + delay_set_parameter(node, DELAY_ARRIVAL_FALL, 0.0); + delay_set_parameter(node, DELAY_ARRIVAL_RISE, 0.0); + } + delay_set_parameter(node, DELAY_ARRIVAL_FALL, time.fall); + delay_set_parameter(node, DELAY_ARRIVAL_RISE, time.rise); +} + +int +speed_delay_trace(network, speed_param) +network_t *network; +speed_global_t *speed_param; +{ + lsGen gen; + node_t *po; + + foreach_node(network, gen, po){ + if (po->type == INTERNAL) { + speed_reset_arrival_time(po); + } + } + foreach_primary_output(network, gen, po){ + if (!speed_update_arrival_time(po, speed_param)){ + (void) lsFinish(gen); + return 0; + } + } + + return 1; +} + +void +speed_single_level_update(node, speed_param, delay) +node_t *node; +speed_global_t *speed_param; +delay_time_t *delay; +{ + int i; + node_t *fanin; + delay_time_t fanin_time, time; + + delay->rise = NEG_LARGE; + delay->fall = NEG_LARGE; + + if (node->type == INTERNAL) { + foreach_fanin(node, i, fanin){ + speed_delay_arrival_time(fanin, speed_param, &fanin_time); + time = speed_delay_node_pin(node, i, speed_param); + if ( speed_param->debug && (time.rise < 0.0 || time.fall < 0.0)){ + (void)fprintf(sisout,"WARNING-4: speed_delay_node_pin\n"); + } + + /* Depending on the phase add the delay components */ + switch (node_input_phase(node, fanin)) { + case POS_UNATE : + delay->rise = MAX(delay->rise, + (fanin_time.rise + time.rise)); + delay->fall = MAX(delay->fall, + (fanin_time.fall + time.fall)); + break; + case NEG_UNATE : + delay->rise = MAX(delay->rise, + (fanin_time.fall + time.rise)); + delay->fall = MAX(delay->fall, + (fanin_time.rise + time.fall)); + break; + case BINATE : + delay->rise = MAX(delay->rise, + (fanin_time.rise + time.rise)); + delay->rise = MAX(delay->rise, + (fanin_time.fall + time.rise)); + delay->fall = MAX(delay->fall, + (fanin_time.rise + time.fall)); + delay->fall = MAX(delay->fall, + (fanin_time.fall + time.fall)); + break; + case PHASE_UNKNOWN : + (void)fprintf(sisout,"Unknown phase\n"); + break; + default: + break; + } + } + if (node_num_literal(node) == 0) { + delay->fall = 0.0; delay->rise = 0.0; + } + speed_set_arrival_time(node, *delay); + } +} + +void +speed_reset_arrival_time(node) +node_t *node; +{ + delay_set_parameter(node, DELAY_ARRIVAL_RISE, DELAY_NOT_SET); + delay_set_parameter(node, DELAY_ARRIVAL_FALL, DELAY_NOT_SET); +} + + +/* ARGSUSED */ +void +speed_update_fanout(network, nodevec, fanout_list, speed_param) +network_t *network; +array_t *nodevec, *fanout_list; +speed_global_t *speed_param; +{ + lsGen gen; + delay_time_t t; + int first, last; + int i, j, more_to_come; + node_t *node, *np, *fo; + array_t *tfi_array, *temp_array; + st_table *node_table, *temp_table; + + if (array_n(fanout_list) == 0) return; + + node_table = st_init_table(st_ptrcmp, st_ptrhash); + temp_table = st_init_table(st_ptrcmp, st_ptrhash); + temp_array = array_alloc(node_t *, 0); + + for(i = 0; i < array_n(fanout_list); i++){ + node = array_fetch(node_t *, fanout_list, i); + (void) st_insert(node_table, (char *)node, ""); + tfi_array = network_tfi(node, POS_LARGE); + for (j = 0; j < array_n(tfi_array); j++){ + np = array_fetch(node_t *, tfi_array, j); + (void) st_insert(node_table, (char *)np, ""); + } + array_free(tfi_array); + } + + for(i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + array_insert_last(node_t *, temp_array, node); + } + + + first = 0; + more_to_come = TRUE; + while (more_to_come) { + more_to_come = FALSE; + last = array_n(temp_array); + for (i = first; i < last; i++){ + node = array_fetch(node_t *, temp_array, i); + if (st_is_member(node_table, (char *)node) ){ + (void) st_insert(temp_table, (char *)node, ""); + foreach_fanout(node, gen, fo){ + if ((!st_insert(temp_table, (char *)fo, "")) && + (st_is_member(node_table, (char *)fo)) ){ + array_insert_last(node_t *, temp_array, fo); + more_to_come = TRUE; + } + } + } + } + first = last; + } + st_free_table(node_table); + array_free(temp_array); + + /* + * At this stage temp_table has all the nodes + * that need to be re_evaluated . Sort them in a + * depth first manner and evaluate the delays + */ + temp_array = network_dfs(network); + for (i = 0; i < array_n(temp_array); i++){ + node = array_fetch(node_t *, temp_array, i); + if (st_is_member(temp_table, (char *)node) ){ + speed_single_level_update(node, speed_param, &t); + } + } + array_free(temp_array); + st_free_table(temp_table); +} + +static delay_time_t +speed_delay_node_pin(node, i, speed_param) +node_t *node; +int i; +speed_global_t *speed_param; +{ + double load; + int nin, nout; + delay_model_t model = speed_param->model; + delay_time_t delay; + delay_pin_t *pin_delay; + + delay.rise = delay.fall = 0.0; + + if (model == DELAY_MODEL_MAPPED && speed_get_library_accl(speed_param) && + (nin = node_num_fanin(node)) < 3){ + /* User decided to speed_up using the NAND-INV delay data */ + if (nin > 0){ + if (nin == 2){ + pin_delay = &(speed_param->nand_pin_delay); + } else if (nin == 1){ + pin_delay = &(speed_param->inv_pin_delay); + } + nout = node_num_fanout(node); + load = compute_wire_load(node_network(node), nout) + nout * speed_param->pin_cap; + delay.rise = pin_delay->drive.rise * load + pin_delay->block.rise; + delay.fall = pin_delay->drive.fall * load + pin_delay->block.fall; + } + } else { + delay = delay_node_pin(node, i, model); + } + return delay; +} + + diff --git a/sis/speed/speed_int.h b/sis/speed/speed_int.h new file mode 100644 index 0000000..f255eeb --- /dev/null +++ b/sis/speed/speed_int.h @@ -0,0 +1,338 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +/* + * Data structure holding the values that are used throught + * this package + */ +typedef struct speed_global_struct { + int area_reclaim; /* Do resub when set */ + int trace; /* When set, show progress */ + int debug; /* Set the level of debugging */ + int add_inv; /* Ensure positive phase for all inputs */ + int del_crit_cubes; /* Delete the critical cubes from divisors */ + int num_tries; /* Number of alternatives during extraction */ + double thresh; /* Set the "epsilon" for criticality */ + double crit_slack; /* Sets the absolute slack that is critical */ + double coeff; /* Area/delay tradeoff coefficient */ + int dist; /* Distance to collapse */ + int do_script; /* Range over some distances */ + int speed_repeat; /* Loop at a particular distance */ + int only_init_decomp; /* Only initial 2-ip decomp */ + int interactive; /* Whether interactive or batch */ + + delay_model_t model; /* Delay model to use */ + int library_accl; /* FLAG: Use accelrator for the mapped model*/ + double pin_cap; /* Capacitance of the input pin */ + delay_pin_t nand_pin_delay; /* Delay model for the 2-input primitives */ + delay_pin_t inv_pin_delay; /* Delay model for the invertor */ + + int req_times_set; /* Set if the req times are set at the PO's */ + int region_flag; /* NEW: Sets strategy to select fanin-region */ + int transform_flag; /* How to choose best transform at node */ + int max_recur; /* NEW: Maximum number of recursion levels */ + int timeout; /* NEW: time limit for an optimization */ + int new_mode; /* NEW: set the expensive weight computation */ + int red_removal; /* NEW: run RR after successful iteration */ + int objective; /* NEW: Selection strategy (either area or + the number of transforms as a criterion */ + int max_num_cuts; /* # of cutsets to attempt for each output */ + array_t *local_trans; /* NEW: local transformations available */ +} speed_global_t; + +typedef void (*SP_void_fn)(); +typedef network_t *(*SP_network_fn)(); +typedef double (*SP_double_fn)(); +typedef delay_time_t (*SP_delay_fn)(); + +/* + * Data structure to support the different restructuring possibilities + */ +typedef struct sp_local_trans_struct{ + char *name; + SP_network_fn optimize_func; + SP_delay_fn arr_func; + int priority; + int on_flag; /* == 1 => transformation is enabled */ + int type; /* one of CLP, DUAL, FAN */ +} sp_xform_t; + +/* + * For the nodes on the mincut --- this stores the relevant information + * as to what is the best technique, the orignal structure, new structure + */ +typedef struct sp_collapse_struct sp_clp_t; +struct sp_collapse_struct { + char *name; /* name of the node --- for referencing */ + node_t *node; /* original node in the network */ + network_t *net; /* Copy of the collapsed network */ + network_t *orig_config; /* Original configuration that was collapsed */ + sp_xform_t *ti_model; /* What optimization to do */ + array_t *delta; /* Improvement on side in/outputs desired */ + delay_time_t old; /* Original arr/req time of "node" */ + int cfi; /* critical-fanin (for buffering) */ + speed_global_t *glb; /* global partameters */ + int can_adjust; /* 1 if inverter at the output can be removed */ + st_table *adjust; /* Table tracking the adjustments of PI delays */ + st_table *equiv_table; /* Table tracking corrspondence of nodes */ + +}; + +/* + * When computing the weight of the nodes on the epsilon network, this + * data-structure stores the relevant information + */ +typedef struct weight_clp_struct { + network_t *clp_netw; /* Collapsed node --- distance "dist" */ + network_t *dual_netw; /* If there is a possibility of dual */ + network_t *fanout_netw; /* The fanout configuration */ + network_t *best_netw; /* The best config. at this node !!! */ + delay_time_t arrival_time; /* Original arrival time at o/p of root */ + delay_time_t slack; /* Original slack */ + int cfi; /* index of Critical fanin of root node */ + double cfi_load; /* Initial load of the critical input */ + delay_time_t cfi_req; /* Required time of critical input */ + double load; /* Original load that is driven */ + double orig_area; /* Area of the circuit being collapsed */ + double dup_area; /* Area duplication on collapsing */ + double *improvement; /* Reduction in delay due to technique "i" */ + double crit_slack; /* Threshold used during this computation */ + double *area_cost; /* Area cost of the transformation */ + int best_technique; /* The technique to do the decomposition */ + int can_invert; /* == 1 if clp_netw function can be inverted */ + double epsilon; /* The epsilon improvement at this node */ + int select_flag; /* Set if the transformation helps */ +} sp_weight_t; + + +/* + * Routines used inside the new_speed part of package + */ + +/* +#define speed_network_dup network_dup +*/ +extern network_t *speed_network_dup(); + + +extern int new_speed(); + +extern int nsp_critical_edge(); +extern int nsp_first_slack_diff(); +extern int new_speed_is_fanout_po(); +extern int sp_num_active_local_trans(); +extern int sp_num_local_trans_of_type(); +extern void sp_append_network(); +extern void sp_delete_network(); +extern void sp_print_network(); +extern void nsp_free_buf_param(); +extern void speed_reorder_cutset(); +extern void sp_expand_selection(); +extern void sp_print_local_trans(); +extern void sp_find_output_arrival_time(); +extern void speed_restore_required_times(); +extern void new_speed_adjust_po_arrival(); +extern void sp_patch_fanouts_of_node(); +extern void new_speed_compute_weight(); +extern void sp_print_delay_data(); +extern void sp_free_local_trans(); +extern void new_free_weight_info(); +extern void sp_free_collapse_record(); +extern double sp_compute_duplicated_area(); +extern array_t *sp_get_local_trans(); +extern array_t *new_speed_select_xform(); +extern delay_time_t *sp_compute_side_req_time(); +extern delay_time_t nsp_compute_delay_saving(); +extern sp_xform_t *sp_local_trans_from_index(); +extern sp_clp_t *sp_create_collapse_record(); +extern st_table *speed_store_required_times(); +extern network_t *sp_get_network_to_collapse(); +extern network_t *buf_get_fanout_network(); +extern network_t *nsp_get_dual_network(); + + + +/* network the interface to the various restructuring techniques */ +extern network_t *sp_and_or_opt(); +extern network_t *sp_noalg_opt(); +extern network_t *sp_divisor_opt(); +extern network_t *sp_2c_kernel_opt(); +extern network_t *sp_comp_div_opt(); +extern network_t *sp_comp_2c_opt(); +extern network_t *sp_bypass_opt(); +extern network_t *sp_cofactor_opt(); +extern network_t *sp_fanout_opt(); +extern network_t *sp_repower_opt(); +extern network_t *sp_duplicate_opt(); +extern network_t *sp_dual_opt(); + +extern delay_time_t new_delay_arrival(); +extern delay_time_t new_delay_required(); +extern delay_time_t new_delay_slack(); /* like delay_latest_output() */ +extern delay_time_t new_sp_delay_arrival(); + +/* + * Function declarations as extern in the package + */ +extern int speed_weight(); +extern int com__speed_plot(); +extern int speed_and_decomp(); +extern int speed_init_decomp(); +extern int speed_delay_trace(); +extern int sp_po_req_times_set(); +extern int speed_and_or_decomp(); +extern int speed_decomp_network(); +extern int speed_get_library_accl(); +extern int speed_update_arrival_time(); +extern int speed_buffer_recover_area(); +extern int nsp_downsize_non_crit_gates(); /* wrapper routine */ +extern int speed_is_fanout_po(); +extern void speed_absorb(); +extern void speed_absorb_array(); +extern void speed_up_node(); +extern void speed_up_loop(); +extern void speed_up_script(); +extern void speed_up_network(); +extern void set_speed_thresh(); +extern void speed_node_replace(); +extern void speed_adjust_phase(); +extern void nsp_get_orig_edge(); +extern void speed_update_fanout(); +extern void speed_set_library_accl(); +extern void speed_set_arrival_time(); +extern void speed_plot_crit_network(); +extern void speed_reset_arrival_time(); +extern void speed_del_critical_cubes(); +extern void speed_delay_arrival_time(); +extern void speed_single_level_update(); +extern void speed_network_delete_node(); +extern void speed_delete_single_fanin_node(); +extern double sp_get_netw_area(); +extern bool speed_critical(); +extern node_t *name_to_node(); +extern node_t *sp_minimum_slack(); +extern node_t *node_del_two_cubes(); +extern node_t *speed_dec_node_cube(); +extern node_t *speed_node_conditional(); +extern node_t *nsp_network_find_node(); +extern array_t *speed_decomp(); +extern array_t *network_to_array(); +extern array_t *sp_generate_revised_order(); +extern array_t *network_and_node_to_array(); +extern st_table *speed_levelize_crit(); +extern st_table *speed_compute_weight(); +extern network_t *speed_network_create_from_node(); +extern lib_gate_t *sp_get_gate(); +extern lib_gate_t *sp_lib_get_inv(); +extern lib_gate_t *sp_lib_get_buffer(); + +/* + * MACRO definitions for the speedup package + */ +#define D_MIN(a,b) ((double)(a) < (double)(b) ? (double)(a):(double)(b)) +#define D_MAX(a,b) ((double)(a) > (double)(b) ? (double)(a):(double)(b)) + +/* + * Definition of some constants + */ +#define MIN_AREA_BUF_NAME "" + +/* Flag values determining how to select the region to be transformed */ +#define ALONG_CRIT_PATH 0 +#define TRANSITIVE_FANIN 1 +#define COMPROMISE 2 +#define ONLY_TREE 3 + +/* Constants identifying the kind of network to optimize */ +#define CLP 0 +#define FAN 1 +#define DUAL 2 + +/* Flag to determine the objective fn to be used for selection */ +#define AREA_BASED 0 +#define TRANSFORM_BASED 1 + +/* Flag to determine how to select the best transform at a node */ +#define BEST_BENEFIT 0 +#define BEST_BANG_FOR_BUCK 1 + +#define DEFAULT_SPEED_THRESH 0.5 +#define DEFAULT_SPEED_COEFF 0.0 +#define DEFAULT_SPEED_DIST 3 + +#define NSP_EPSILON 1.0e-6 /* For floating point comparisons */ +#define NSP_INPUT_SEPARATOR '#' /* For naming of inputs of region*/ +#define NSP_OUTPUT_SEPARATOR '%' /* For naming of output of region*/ + +#ifndef POS_LARGE +#define POS_LARGE 10000 +#endif + +#ifndef NEG_LARGE +#define NEG_LARGE -10000 +#endif + +#define MAXWEIGHT 1000 + +/* + * Definitions of mathematical constants + */ +#define SP_PI 3.14159265358979323846 +#define SP_PI_2 1.57079632679489661923 +#define SP_PI_4 0.78539816339744830962 +#define SP_1_PI 0.31830988618379067154 + + /* + * Definition of some macros for printing etc. + */ + +#define SP_PRINT(global,cur,best,cur_area,best_area,cur_name,best_name) \ +(void) fprintf(sisout,"\t%s %5.2f -> %5.2f Area %.1f -> %.1f %s -> %s\n", \ + ((global)->req_times_set ? "Slack" : "Delay"), cur, best, cur_area, \ + best_area, cur_name, best_name); + +#define SP_IMPROVED(global,best,cur) \ +(((global)->req_times_set) ? ((best) > ((cur) + NSP_EPSILON)):\ + ( (best) < ((cur) - NSP_EPSILON))) + +#define SP_GET_PERFORMANCE(global,network,node,value,name,area) \ +node = ((global)->req_times_set ? sp_minimum_slack((network), &value) :\ + delay_latest_output((network), &value)); \ +name = (node != NIL(node_t) ? util_strsav(node_name(node)) : ""); \ +area = sp_get_netw_area(network) + + +#define SP_METHOD(flag) \ + (flag == ALONG_CRIT_PATH ? "CRITICAL" :\ + (flag == COMPROMISE ? "COMPROMISE" : \ + (flag == ONLY_TREE ? "TREE" : \ + (flag == TRANSITIVE_FANIN ? "TRANSITIVE" : "UNKNOWN")))) + +#define NSP_OPTIMIZE(wght,xform,glb) \ + (xform->type == FAN ? \ + ((*(xform->optimize_func))(wght->fanout_netw, xform, glb)) : \ + (xform->type == DUAL ? \ + ((*(xform->optimize_func))(wght->dual_netw, xform, glb)) : \ + ((*(xform->optimize_func))(wght->clp_netw, xform, glb)))) + +#define NSP_NETWORK(wght,xform) \ + (xform->type == FAN ? (wght->fanout_netw) : \ + (xform->type == DUAL ? (wght->dual_netw): (wght->clp_netw))) + +#define sp_network_free(network) \ + {if ((network) != NIL(network_t)) network_free((network)); \ + (network) = NIL(network_t);} + +#define SP_IMPROVEMENT(wght) \ + ((wght)->best_technique == -1 ? \ + (NEG_LARGE) : ((wght)->improvement[(wght)->best_technique])) +#define SP_COST(wght) \ + ((wght)->best_technique == -1 ? \ + (POS_LARGE) : ((wght)->area_cost[(wght)->best_technique])) + diff --git a/sis/speed/speed_loop.c b/sis/speed/speed_loop.c new file mode 100644 index 0000000..30738e9 --- /dev/null +++ b/sis/speed/speed_loop.c @@ -0,0 +1,279 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed_loop.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include <sys/types.h> +#include <signal.h> +#include <unistd.h> + + +/* Exported interface to the looping function */ +void +speed_loop_interface(network, thresh, coeff, dist, model, flag) +network_t **network; +double thresh, coeff; +int dist; +delay_model_t model; +int flag; +{ + speed_global_t speed_param; + + (void)speed_fill_options(&speed_param, 0, NIL(char *)); + speed_param.thresh = thresh; + speed_param.coeff = coeff; + speed_param.dist = dist; + speed_param.model = model; + speed_param.trace = flag; + + speed_set_delay_data(&speed_param, 0 /* No library acceleration */); + speed_up_loop(network, &speed_param); + + return; +} + +/* Routines used to save the optimized network when CPUlimit is exceeded */ + +static network_t *saved_network; + +/* Handle for the SIGXCPU exception */ +void sp_dump_saved_network(sig, code, context) +int sig, code; +struct sigcontext *context; +{ + char name[32], command[256]; + + if (saved_network != NIL(network_t)){ + (void)sprintf(command, "wl -n /usr/tmp/%s.blif.%d", + network_name(saved_network), getpid()); + com_execute(&saved_network, command); + gethostname(name, 32); + (void)fprintf(sisout, "Saving optimized network in %s on %s\n", + command+6, name); + } else { + (void)fprintf(sisout, "Nothing needs to be saved\n"); + } + +#if !defined(__hpux) + /* Should exit */ + if (sig == SIGXCPU) { + exit(1); + } +#endif +} + + +/* Basic routine for performance optimization !!! */ + +void +speed_up_loop(network, speed_param) +network_t **network; +speed_global_t *speed_param; +{ + int i, status; + network_t *dup_cur_net, *cur_net; + array_t *array_of_methods = speed_param->local_trans; + sp_xform_t *ti_model; + double best, cur, best_area, cur_area; + char *best_name, *cur_name; + node_t *best_node, *cur_node; /* critical output node */ + + /* Check for trivial networks */ + if (network_num_pi(*network) == 0) return; + + /***************** BEGIN MACRO **********************/ +#define SWAP_AND_LOOP_AGAIN \ + cur = best; \ + cur_area = best_area;\ + FREE(cur_name);\ + cur_name = best_name;\ + if (saved_network != NIL(network_t)) network_free(saved_network);\ + network_free(*network);\ + saved_network = speed_network_dup(cur_net);\ + *network = cur_net; \ + if (speed_param->req_times_set && cur > NSP_EPSILON){ \ + if (speed_param->interactive){ \ + (void)fprintf(sisout, "Timing constraints are met\n"); \ + } \ + goto free_saved_network; \ + } \ + goto loop; + /***************** END MACRO **********************/ + + saved_network = NIL(network_t); + if (speed_param->trace) { + if (speed_param->new_mode) { + (void) fprintf(sisout,"distance = %-2d, Selection = %s, %sAGG-B%s, Transforms: ", + speed_param->dist, + SP_METHOD(speed_param->region_flag), + (speed_param->del_crit_cubes ? "" : "NON"), + (speed_param->transform_flag == + BEST_BANG_FOR_BUCK ? "/C" : "")); + for (i = 0; i < array_n(array_of_methods); i++){ + ti_model = array_fetch(sp_xform_t *, array_of_methods, i); + if (ti_model->on_flag) + (void)fprintf(sisout, " \"%s\"", ti_model->name); + } + (void)fprintf(sisout, "\n"); + } else { + (void) fprintf(sisout,"distance = %-2d threshold = %3.1f\n", + speed_param->dist, speed_param->thresh); + } + } + /* Set the flag based on whether required times are set for PO nodes */ + + assert(delay_trace(*network, speed_param->model)); + SP_GET_PERFORMANCE(speed_param, *network, cur_node, cur, cur_name, + cur_area); + if (speed_param->req_times_set && cur > NSP_EPSILON){ + if (speed_param->interactive){ + (void)fprintf(sisout, "Timing constraints are met\n"); + } + return; + } + +#if !defined(__hpux) + /* Insert a handler for the CPULIMIT */ + if (signal(SIGXCPU, sp_dump_saved_network) != 0) { + (void)fprintf(sisout, "Unable to start SIGXCPU handler"); + } + + /* Another handler for the signal SIGUSR1 to dump intermediate networks */ + if (signal(SIGUSR1, sp_dump_saved_network) != 0) { + (void)fprintf(sisout, "Unable to start SIGUSR1 handler"); + } + +#endif +loop: + cur_net = network_dup(*network); + if (speed_param->red_removal && speed_param->model != DELAY_MODEL_MAPPED){ + (void)fprintf(sisout, "Be patient, running red removal ...\n"); + + (void)com_redundancy_removal(&cur_net, 0, NIL(char *)); + + /* Get a true estimate of the delay --- after red_removal */ + assert(delay_trace(cur_net, speed_param->model)); + SP_GET_PERFORMANCE(speed_param, *network, cur_node, cur, cur_name, cur_area); + } + + if (speed_param->new_mode){ + status = new_speed(cur_net, speed_param); + } else { + speed_up_network(cur_net, speed_param); + } + + assert(delay_trace(cur_net, speed_param->model)); + SP_GET_PERFORMANCE(speed_param, cur_net, best_node, best, best_name, best_area); + + if (SP_IMPROVED(speed_param, best, cur)) { + if (speed_param->trace) { + SP_PRINT(speed_param, cur, best, cur_area, best_area, cur_name, best_name); + } + SWAP_AND_LOOP_AGAIN; + } else if (lib_network_is_mapped(cur_net)) { + /* Carry out an area recovery step to perturb the network*/ + (void)nsp_downsize_non_crit_gates(cur_net, speed_param->model); + SP_GET_PERFORMANCE(speed_param, cur_net, best_node, best, best_name, best_area); + if (SP_IMPROVED(speed_param, best, cur)) { + (void)fprintf(sisout, "Downsizing transformed netw !!!\n"); + SP_PRINT(speed_param, cur, best, cur_area, best_area, cur_name, best_name); + SWAP_AND_LOOP_AGAIN; + } else { + /* Try to downsize the original network. Not the transformed one */ + dup_cur_net = network_dup(*network); + delay_trace(dup_cur_net, speed_param->model); + (void)nsp_downsize_non_crit_gates(dup_cur_net, speed_param->model); + SP_GET_PERFORMANCE(speed_param, dup_cur_net, best_node, best, best_name, best_area); + if (SP_IMPROVED(speed_param, best, cur)){ + network_free(cur_net); + cur_net = dup_cur_net; + (void)fprintf(sisout, "Downsizing saved netw !!!\n"); + SP_PRINT(speed_param, cur, best, cur_area, best_area, cur_name, best_name); + SWAP_AND_LOOP_AGAIN; + } else { + network_free(dup_cur_net); + } + } + } + + /* + * At this stage try once more to speed up + */ + if (speed_param->new_mode){ + if (status < 0){ + /* No change was made to the network so no point in repeating */ + goto exit_after_print; + } else { + /* The earlier iteration changed network, give it another try */ + (void)new_speed(cur_net, speed_param); + } + } else { + speed_up_network(cur_net, speed_param); + } + assert(delay_trace(cur_net, speed_param->model)); + FREE(best_name); + SP_GET_PERFORMANCE(speed_param, cur_net, best_node, best, best_name, best_area); + + if (SP_IMPROVED(speed_param, best, cur)) { + if (speed_param->trace) { + SP_PRINT(speed_param, cur, best, cur_area, best_area, cur_name, best_name); + } + SWAP_AND_LOOP_AGAIN; + } + +exit_after_print: + if (speed_param->trace) { + SP_PRINT(speed_param, cur, cur, cur_area, cur_area, cur_name, cur_name); + } + + FREE(cur_name); + FREE(best_name); + network_free( cur_net); + +free_saved_network: +#if !defined(__hpux) + /* terminate the special handler for handling cpulimit violations */ + if (signal(SIGXCPU, SIG_DFL) != 0) { + (void)fprintf(sisout, "Unable to restore default handler"); + } +#endif + + if (saved_network != NIL(network_t)){ + network_free(saved_network); + saved_network = NIL(network_t); + } +} + + +/* + * For the original speedup (-f option), the script tries + * the different values for the distance + */ +void +speed_up_script(network, speed_param) +network_t **network; +speed_global_t *speed_param; +{ + if (speed_param->new_mode){ + speed_param->dist = DEFAULT_SPEED_DIST; + speed_up_loop(network, speed_param); + } else { + speed_param->dist = DEFAULT_SPEED_DIST; + speed_up_loop(network, speed_param); + speed_param->dist += 1; + speed_up_loop(network, speed_param); + speed_param->dist += 1; + speed_up_loop(network, speed_param); + speed_param->dist -= 1; + speed_up_loop(network, speed_param); + speed_param->dist -= 1; + speed_up_loop(network, speed_param); + } +} + diff --git a/sis/speed/speed_net.c b/sis/speed/speed_net.c new file mode 100644 index 0000000..d523109 --- /dev/null +++ b/sis/speed/speed_net.c @@ -0,0 +1,450 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed_net.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +/* + * + * Decomposes a node of a network by selecting + * divisors and recursively decomposes them. + * + */ + +#include <stdio.h> +#include "sis.h" +#include "speed_int.h" + +#define SCALE_2 100000 +#define SCALE 100 + +#define CRITICAL_FRACTION 0.05 +#define FUDGE 0.0001 +/* Original value +#define CRITICAL_FRACTION 0.0001 +*/ + +int kernel_timeout_occured = 0; /* Flag stating that enough time has expired */ +static void speed_scale_value(); +static int evaluate_kernel(); + +typedef struct divisor_data divisor_data_t; +struct divisor_data { + double alpha; + double cost; + node_t *best; + double min_delay; + double max_delay; + double delay_scale; + double min_area; + double max_area; + double area_scale; + }; + +typedef struct divisor_struct divisor_t; +struct divisor_struct { + node_t *node; + double area; + double delay; + }; + +struct a_kern_node{ + node_t *node; + array_t *cost_array; + double area_max; + double area_min; + double delay_max; + double delay_min; + double thresh; + speed_global_t *globals; + }; + + +int +speed_decomp_network(network, node, speed_param, attempt_no) +network_t *network; +node_t *node; +speed_global_t *speed_param; +int attempt_no; /* selects different decompositions */ +{ + int i, j; + delay_time_t time; + node_t *np, *temp, *best; + double min_t, max_t, range; + struct a_kern_node *sorted; + divisor_t *div; + divisor_data_t *best_div; + + if (speed_param->debug) { + (void) fprintf(sisout," Decomposing node \n"); + node_print(sisout, node); + (void)fprintf(sisout,"\tInput arrival times "); + j = 0; + foreach_fanin(node, i, np){ + speed_delay_arrival_time(np, speed_param, &time); + if ((j % 3 == 0) && (j != node_num_fanin(node))) { + (void) fprintf(sisout,"\n\t"); + } + j++; + (void) fprintf(sisout,"%s at %-5.2f, ", node_name(np), time.rise); + } + (void)fprintf(sisout,"\n"); + } + + temp = NIL(node_t); + if ((!kernel_timeout_occured) && + (temp = ex_find_divisor_quick(node)) != NIL(node_t) ) { + /* Implies kernel exists */ + sorted = ALLOC(struct a_kern_node, 1); + sorted->node = node; + sorted->cost_array = array_alloc(divisor_t *, 0); + sorted->area_max = NEG_LARGE; + sorted->area_min = POS_LARGE; + sorted->delay_max = NEG_LARGE; + sorted->delay_min = POS_LARGE; + + + /* + * Set the threshold to delete nodes with arrival times in the + * last .01% of the nodes-- (effectively the latest input) + */ + max_t = NEG_LARGE; + min_t = POS_LARGE; + foreach_fanin(node, i, np){ + speed_delay_arrival_time(np, speed_param, &time); + max_t = D_MAX(max_t, D_MAX(time.rise, time.fall)); + min_t = D_MIN(min_t, D_MIN(time.rise, time.fall)); + } + if ((max_t - min_t) < 1.0e-3) { + sorted->thresh = POS_LARGE; + } else { + sorted->thresh = + max_t - (attempt_no*CRITICAL_FRACTION + FUDGE) * (max_t-min_t); + } + sorted->globals = speed_param; + + /* + * Evaluate the area and delay components for the kernels and + * co-kernels, as well as the intersections + */ + + ex_kernel_gen(node, evaluate_kernel, (char *)sorted); + ex_subkernel_gen(node, evaluate_kernel, 0,(char *)sorted); + + /* Now get the numbers back and scale the two components + * Also select the best divisor from a timing standpoint + */ + best_div = ALLOC(struct divisor_data, 1); + best_div->alpha = speed_param->coeff; + best_div->best = NIL(node_t); + best_div->cost = POS_LARGE; + best_div->min_delay = sorted->delay_min; + best_div->max_delay = sorted->delay_max; + best_div->min_area = (double)(sorted->area_min); + best_div->max_area = (double)(sorted->area_max); + + range = sorted->delay_max - sorted->delay_min; + best_div->delay_scale = SCALE_2 / (range > 0 ? range : 1); + range = (double)sorted->area_max - (double)sorted->area_min; + best_div->area_scale = SCALE / (range > 0 ? range : 1); + + if (speed_param->debug) { + (void) fprintf(sisout,"\t Evaluating the cost of divisors\n"); + } + for (i = 0; i < array_n(sorted->cost_array); i++){ + div = array_fetch(divisor_t *,sorted->cost_array, i); + speed_scale_value(div, best_div, speed_param); + } + + array_free(sorted->cost_array); + FREE(sorted); + + if (best_div->best != NIL(node_t)){ + best = node_dup(best_div->best); + /* + * Free the storage for the best divisor + */ + node_free(best_div->best); + FREE(best_div); + + network_add_node(network, best); + if (speed_param->debug){ + (void) fprintf(sisout,"\tBest divisor is "); + node_print(sisout, best); + } + + /* + * Recursively speedup the rem and quotient + */ + if (!node_substitute(node, best, 0)){ + node_free(best); + fail("Error decomposing node during speedup \n"); + } + /* + * Decomposing the divisor + */ + if (!speed_decomp_network(network, best, speed_param, attempt_no)){ + error_append("Failed while decomposing kernel "); + fail(error_string()); + } + + /* + * The arrival time at the remaining node should + * be valid, since speed_and_or_decomp returns + * the node with a valid delay + */ + + if(!speed_decomp_network(network, node, speed_param, attempt_no)){ + error_append("Failed after kernel extraction"); + fail(error_string()); + } + } else { + /* Do an and-or decomp */ + FREE(sorted); + FREE(best_div); + if (speed_param->debug) { + (void) fprintf(sisout,"\tNo divisor appropriate -- AND_OR decomp\n"); + } + if(!speed_and_or_decomp(network, node, speed_param)){ + error_append("Failed to decomp if no non_crit kernel "); + fail(error_string()); + } + if (!speed_param->add_inv){ + speed_delete_single_fanin_node(network, node); + } + } + } else { + + /* If no kernels then decompose the network into + 2-input and and or gates according to the arrival times */ + + if (speed_param->debug) { + (void) fprintf(sisout,"\tNo divisors -- doing AND_OR decomp\n"); + } + if(!speed_and_or_decomp(network, node, speed_param)){ + error_append("Failed to decomp if no kernel "); + fail(error_string()); + } + if (!speed_param->add_inv){ + speed_delete_single_fanin_node(network, node); + } + } + if (temp != NIL(node_t)) node_free(temp); + return 1; +} + +/* + * Routine to evaluate the cost of a kernel + * Also keeps the best divisor and its cost. + */ + +static int +evaluate_kernel(kernel, cokernel, state) +node_t *kernel; +node_t *cokernel; +char *state; +{ + struct a_kern_node *store; + node_t *new_cokernel, *rem; + divisor_t *k_data, *c_data; /* To hold the area/delay components */ + void node_evaluate(); + double k_t_cost, c_t_cost; /* time cost of kern and co-kern */ + double k_a_cost, c_a_cost;; /* area cost of kern and co-kern */ + + store = (struct a_kern_node *)state; + + if (kernel_timeout_occured) { + /* Stop the generationof more kernel-cokernel pairs */ + node_free(kernel); + node_free(cokernel); + return 0; + } + /* + * Make the kernel free of any cubes + * containing critical signals + */ + if (store->globals->del_crit_cubes){ + speed_del_critical_cubes(kernel, store->globals, store->thresh); + } + + if (node_function(kernel) == NODE_0){ + /* Don't consider this kernel pair */ + node_free(kernel); + node_free(cokernel); + return 1; + } + + /* + * Generate the cokernel, reduce it to non crit signals + * and -- (as large as possible) and evaluate the cost + */ + + new_cokernel = node_div(store->node, kernel, &rem); + /* + * If the node itself is a kernel dont consider it as + * a potential divisor + */ + if (node_function(new_cokernel) == NODE_1){ + node_free(new_cokernel); + node_free(rem); + node_free(kernel); + node_free(cokernel); + return 1; + } + + if (store->globals->del_crit_cubes){ + speed_del_critical_cubes(new_cokernel, store->globals, store->thresh); + } + if (node_function(new_cokernel) != NODE_0){ + node_evaluate(kernel, new_cokernel, store->globals, &k_t_cost, &k_a_cost); + node_evaluate(new_cokernel, kernel, store->globals, &c_t_cost, &c_a_cost); + } + else{ + node_evaluate(kernel, new_cokernel, store->globals, &k_t_cost, &k_a_cost); + c_t_cost = c_a_cost = POS_LARGE; + } + + k_data = ALLOC(divisor_t, 1); + k_data->node = kernel; + k_data->delay = k_t_cost; + k_data->area = k_a_cost; + + c_data = ALLOC(divisor_t, 1); + c_data->node = new_cokernel; + c_data->delay = c_t_cost; + c_data->area = c_a_cost; + + array_insert_last(divisor_t *, store->cost_array, k_data); + array_insert_last(divisor_t *, store->cost_array, c_data); + + /* Keep the range of costs of relevant divisors updated + * so that the scaling of the componenets is easy + */ + if ((k_t_cost < POS_LARGE) || (k_a_cost < POS_LARGE) ) { + store->delay_max = MAX(store->delay_max, k_t_cost); + store->delay_min = MIN(store->delay_min, k_t_cost); + store->area_max = MAX(store->area_max, k_a_cost); + store->area_min = MIN(store->area_min, k_a_cost); + } + if ((c_t_cost < POS_LARGE) || (c_a_cost < POS_LARGE) ) { + store->delay_max = MAX(store->delay_max, c_t_cost); + store->delay_min = MIN(store->delay_min, c_t_cost); + store->area_max = MAX(store->area_max, c_a_cost); + store->area_min = MIN(store->area_min, c_a_cost); + } + + node_free(rem); + node_free(cokernel); + + return 1; +} + + +/* + * Routine to evaluate a node . Nodes with smaller cost + * are the ones that are preferred for speedup. + * + * C1 = n_lit(k)+n_lit(ck)+n_cubes(ck); + * C2 = n_lit(k).n_cubes(ck) + n_lit(ck).num_cubes(k) + * Area_saving = C2 - C1 + */ + +void +node_evaluate(node, co_node, speed_param, delay, area) +node_t *node, *co_node; +speed_global_t *speed_param; +double *delay, *area; +{ + node_t *fanin; + delay_time_t atime; + int i, lit_saving, input_count; + double mintime, maxtime; + + /* INITIALIZATIONS */ + maxtime = NEG_LARGE; + mintime = POS_LARGE; + + /* For the literals find the arrival times */ + input_count = node_num_fanin(node); + foreach_fanin(node, i, fanin){ + speed_delay_arrival_time(fanin, speed_param, &atime); + maxtime = D_MAX(atime.rise, maxtime); + maxtime = D_MAX(atime.fall, maxtime); + mintime = D_MIN(atime.rise, mintime); + mintime = D_MIN(atime.fall, mintime); + } + + /* + * Evaluate the literal saving resulting from + * extracting this node + */ + if (node_function(co_node) != NODE_0){ + lit_saving = node_num_cube(node) * node_num_literal(co_node) + + node_num_cube(co_node) * node_num_literal(node); + lit_saving -= (node_num_literal(node) + node_num_literal(co_node) + + node_num_cube(co_node)); + } else{ + lit_saving = 0; + } + + /* + * There is no point in extracting a node with + * one input, so give it a high cost + */ + + if (input_count <= 1){ + *delay = POS_LARGE; + *area = POS_LARGE; + } else { + *delay = (0.9 * maxtime) + (0.1 * mintime); + *area = (double)lit_saving; + } +} + +static void +speed_scale_value(div, best_data, speed_param) +divisor_t *div; +divisor_data_t *best_data; +speed_global_t *speed_param; +{ + double area, delay, cost; + + delay = div->delay; + area = div->area; + + if ((delay < POS_LARGE) && (area < POS_LARGE) ) { + /* + * Scale the two components -- If the delay range is 0 + * might as well select the best area saving. + */ + if (best_data->min_delay == best_data->max_delay) { + cost = 0 - area; + } else { + cost = (delay - best_data->min_delay)* best_data->delay_scale - + best_data->alpha * (area - best_data->min_area)* + best_data->area_scale; + } + + if (speed_param->debug) { + /* Print the kernel and its cost components */ + (void)fprintf(sisout,"\t\tt = %-5.2f ,a = %-3d for ", delay, (int)area); + node_print_rhs(sisout, div->node); + (void)fprintf(sisout,"\n"); + } + + /* Keep the best around */ + if (cost < best_data->cost) { + best_data->cost = cost; + node_free(best_data->best); + best_data->best = div->node; + } else { + node_free(div->node); + } + } else { + node_free(div->node); + } + FREE(div); +} diff --git a/sis/speed/speed_no.c b/sis/speed/speed_no.c new file mode 100644 index 0000000..641f397 --- /dev/null +++ b/sis/speed/speed_no.c @@ -0,0 +1,156 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed_no.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include "speed_int.h" + +/* Exported interface */ +array_t * +speed_decomp_interface(f, coeff, model) +node_t * f; +double coeff; +delay_model_t model; +{ + array_t *a; + speed_global_t speed_param; + + (void)speed_fill_options(&speed_param, 0, NIL(char *)); + speed_param.coeff = coeff; + speed_param.model = model; + + speed_set_delay_data(&speed_param, 0 /* No library acceleration */); + a = speed_decomp(f, &speed_param, 0 /* Use the arrival times of fanins */); + + return a; +} + + +array_t * +speed_decomp(innode, speed_param, delay_flag) +node_t *innode; +speed_global_t *speed_param; +int delay_flag; /* 1=> use user field */ +{ + lsGen gen; + int i, best_i; + array_t *array; + delay_time_t delay; + node_t *temp, *node; + double best_delay, cur_delay; + network_t *best_network, *network; + + network = speed_network_create_from_node(innode, speed_param, delay_flag); + + /* Do a delay trace on the network and call the + decomposition routine on the network */ + + if ( !speed_delay_trace(network, speed_param) ){ + fail(error_string()); + } + + foreach_node(network, gen, node){ + if ( node->type == INTERNAL ){ + (void) lsFinish(gen); + break; + } + } + + /* If the MAPPED model is used get quick delays from global data_str */ + speed_set_library_accl(speed_param, 1); + + /* + * Try different decompositions and select the best area/delay + * tradeoff... Done, by choosing different number of inputs to call + * critical + */ + best_delay = POS_LARGE; + best_network = NIL(network_t); + best_i = -1; + for ( i = 0; i < speed_param->num_tries; i++){ + (void)network_collapse(network); + if ( !speed_decomp_network(network, node, speed_param, i /* i'th attempt */)){ + error_append("Failed trying to speed_decomp network"); + fail(error_string()); + } + /* Get the arrival-time of the primary output node */ + temp = network_get_po(network, 0); + speed_delay_arrival_time(temp, speed_param, &delay); + cur_delay = MAX(delay.rise, delay.fall); + if (speed_param->num_tries > 1 && speed_param->debug){ + (void)fprintf(sisout, "%d => %.2f\t", i, cur_delay); + } + if ((i == 0) || (cur_delay < best_delay)){ + if (best_network != NIL(network_t)) network_free(best_network); + best_network = network_dup(network); + best_delay = cur_delay; + best_i = i; + } + } + if (speed_param->num_tries > 1 && speed_param->debug){ + (void)fprintf(sisout, " BEST is %d\n", best_i); + } + network_free(network); + network = best_network; + /* reset the library accelerator so as to get realistic delays */ + speed_set_library_accl(speed_param, 0); + + /* + * Cleanup all the inverters and buffers if required + */ + + if ( speed_param->add_inv) { + add_inv_network(network); + (void) speed_delay_trace( network, speed_param); + } + + + /* Convert the network into an array */ + if ( speed_param->debug) { + (void) fprintf(sisout,"After decomposition ----- \n"); + (void) com_execute( &network, "p"); + } + array = network_and_node_to_array(network, innode, NIL(st_table)); + + network_free(network); + return array; +} + + +void +speed_adjust_phase(network) +network_t *network; +{ + node_t *node, *fo; + lsGen gen1; + int i; + array_t *nodevec; + + /* Collapse all the inverters and buffers into their + fanouts -- except if fanout is a primary output */ + + nodevec = network_dfs_from_input(network); + for ( i = 0; i < array_n(nodevec); i++){ + node = array_fetch(node_t *, nodevec, i); + if ( node->type == INTERNAL){ + if ( (node_function(node) == NODE_BUF) || + (node_function(node) == NODE_INV)) { + foreach_fanout(node, gen1, fo){ + if ( node_function(fo) != NODE_PO){ + (void) node_collapse( fo, node); + } + } + + if ( node_num_fanout( node) == 0){ + network_delete_node(network, node); + } + } + } + } + array_free(nodevec); +} diff --git a/sis/speed/speed_or.c b/sis/speed/speed_or.c new file mode 100644 index 0000000..0e9e51b --- /dev/null +++ b/sis/speed/speed_or.c @@ -0,0 +1,83 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed_or.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +/* + * Routine to decompose a sum-of-products representation + * into a tree of and(nand) gates. + */ + +#include <stdio.h> +#include "sis.h" +#include "speed_int.h" + +int +speed_and_or_decomp(network, node, speed_param) +network_t *network; +node_t *node; +speed_global_t *speed_param; +{ + int i; + array_t *collapse_array; + node_t *cube, *temp, *new_node, *nlit; + + if ( node_num_cube(node) > 1) { + new_node = node_constant(1); + for ( i = 0; i < node_num_cube(node); i++){ + cube = speed_dec_node_cube(node, i); + network_add_node(network, cube); + + nlit = node_literal(cube, 0); + temp = node_and(new_node, nlit); + node_free(new_node); + node_free(nlit); + new_node = temp; + } + node_replace(node, new_node); + + foreach_fanin(node, i, cube){ + /* + * speed decompose the cubes + */ + if ( !speed_and_decomp( network, cube, speed_param, 0)){ + error_append("Failed to decompose cube"); + fail(error_string()); + } + } + + if ( !speed_param->add_inv) { + collapse_array = array_alloc(node_t *, 0); + foreach_fanin(node, i, cube){ + if ( node_num_fanin(cube) <= 1) { + array_insert_last(node_t *, collapse_array, cube); + } + } + for ( i = 0; i < array_n(collapse_array); i++){ + cube = array_fetch(node_t *, collapse_array, i); + (void) node_collapse( node, cube); + if ( node_num_fanout( cube) == 0) + network_delete_node( network, cube); + } + array_free(collapse_array); + } + /* + * Decompose the cube that combines all the cubes. + * The arrival time at the cube o/p will be set. + */ + + if ( !speed_and_decomp( network, node, speed_param, 1) ){ + error_append("Failed to decompose node combining cubes "); + fail(error_string()); + } + } else if ( !speed_and_decomp( network, node, speed_param, 0)){ + error_append("Failed to decompose single cube"); + fail(error_string()); + } + + return 1; +} diff --git a/sis/speed/speed_plot.c b/sis/speed/speed_plot.c new file mode 100644 index 0000000..4f9430a --- /dev/null +++ b/sis/speed/speed_plot.c @@ -0,0 +1,230 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed_plot.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +/* speed_plot.c -- highlight critical paths. */ + +#include "sis.h" +#include "speed_int.h" +#include <math.h> + +static char *usage[] = { + "usage: %s [-n name] [-t thresh] [-cHgf] [-m model] [-t n.n] [-w n.n] [-d n] [-s method]\n", + " -n name\tPlot name to use instead of network name.\n", + " -c\t\tHighlight minimum weight cutset.\n", + " -g\t\tUse gate names instead of node names\n", + " -f\t\tUse fast routine to compute weights\n", + " -H\t\tHighlight critical path nodes.\n", + " -t\tn.n\tCritical threshold (used with -f option).\n", + " -w\tn.n\tRelative weight of area (used with -f option).\n", + " -d\tn\tDistance for collapsing.\n", + " -m\tmodel\t Delay model\n", + " -s\tmethod\tMethod for selecting the region to transform.\n \t one of \"crit\"(default), \"transitive\", \"compromise\", \"tree\"\n", + NULL +}; + +static int speed_plot_use () +{ + char **p; + for (p=usage; *p != NULL; p++) { + fprintf(sisout,*p,"_speed_plot"); + } + return 1; +} + +static void +do_speed_plot(network, plot_name, thresh, path_flag, cutset_flag, + print_gate_name, model, dist, coeff, fast_mode, + region_flag) +network_t *network; +char *plot_name; +delay_model_t model; +int dist, path_flag, cutset_flag; +int print_gate_name; /* Print name of the gate in place of node names */ +double coeff, thresh; +int fast_mode; /* Set the method to evaluate cutsets */ +int region_flag; /* Set the region to select the scope of transforms */ +{ + int i, flag; + FILE *gfp; + lsGen gen; + node_t *np; + array_t *mincut; + double eps, time; + lib_gate_t *gate; + speed_global_t speed_param; + st_table *weight_table, *clp_table; + extern void io_plot_network(); + + if (!com_graphics_enabled()) return; + + /* We have already parsed the input --- just set those fields */ + (void)speed_fill_options(&speed_param, 0, NIL(char *)); + speed_param.thresh = thresh; + speed_param.model = model; + speed_param.coeff = coeff; + speed_param.dist = dist; + speed_param.new_mode = fast_mode; + speed_param.region_flag = region_flag; + speed_param.model = model; + + assert(delay_trace(network, speed_param.model)); + set_speed_thresh(network, &speed_param); + np = delay_latest_output(network, &time); + + /* First make a Vannila Network like "plot_blif" and then + embellish it according to the flags specified by the user */ + gfp = com_graphics_open ("blif", plot_name, "new"); + io_plot_network(gfp, network, 0); + com_graphics_close (gfp); + + /* Now for the add ons --- name changes, highlighting etc... */ + if (print_gate_name){ + gfp = com_graphics_open ("blif",plot_name,"label"); + foreach_node(network, gen, np){ + if (np->type != INTERNAL) continue; + if ((gate=lib_gate_of(np)) != NIL(lib_gate_t)) { + fprintf(gfp,".label\t%s\t%s\n",node_long_name(np), + lib_gate_name(gate)); + } + } + com_graphics_close (gfp); + } + + gfp = com_graphics_open ("blif", plot_name, "highlight"); + + if (path_flag) { + fprintf(gfp,".clear\tDelay = %-5.2f\n", time); + } else if (!cutset_flag) { + fprintf(gfp,".clear\t%s\n",network_name(network)); + fprintf(gfp,".command\t_speed_plot\t_speed_plot -H -n %s",plot_name); + fputs("\tCritical\tHighlight critical path(s).\n",gfp); + fprintf(gfp,".command\t_speed_plot\t_speed_plot -c -n %s",plot_name); + fputs("\tCutset\tHighlight minimum weight cutset.\n",gfp); + } + + if (cutset_flag || path_flag) { + + fprintf(sisout, "Distance = %d ; Threshold = %5.2f\n",dist, thresh); + /* Get the weights for the cutset analysis and find the cutset*/ + if (speed_param.new_mode){ + clp_table = st_init_table(st_ptrcmp, st_ptrhash); + new_speed_compute_weight(network, &speed_param, + clp_table, &eps); + if (eps < NSP_EPSILON){ + mincut = array_alloc(node_t *, 0); + } else { + mincut = new_speed_select_xform(network, &speed_param, + clp_table, eps); + } + new_free_weight_info(clp_table); + } else { + weight_table = speed_compute_weight(network, &speed_param, NIL(array_t)); + mincut = cutset (network, weight_table); + } + + if (path_flag) { /* Highlight the critical path. */ + fputs(".nodes",gfp); + foreach_node (network, gen, np){ + if (speed_critical(np, &speed_param)){ + fprintf(gfp,"\t%s",node_long_name(np)); + } + } + fputs("\n",gfp); + } + + if (cutset_flag && mincut != NIL(array_t) && array_n(mincut) > 0) { + /* Highlight the cutset nodes. */ + if (!path_flag) { + fprintf(gfp,".clear\tCutset of %d nodes\n",array_n(mincut)); + } + fputs(".nodes",gfp); + for (i=array_n(mincut); i--; ){ + np = array_fetch (node_t *, mincut, i); + fprintf(gfp,"\t%s",node_long_name(np)); + } + fputs("\n",gfp); + } + + array_free(mincut); + st_free_table(weight_table); + + } + + com_graphics_close (gfp); +} + +int +com__speed_plot (network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + delay_model_t model = DELAY_MODEL_UNIT; + int hilite_flag = FALSE, print_gate_name = FALSE; + int cutset_flag = FALSE; + int region_flag = ALONG_CRIT_PATH; + int new_method = TRUE; + int dist = DEFAULT_SPEED_DIST; + double thresh = DEFAULT_SPEED_THRESH; + double coeff = DEFAULT_SPEED_COEFF; + char *plot_name = network_name(*network); + + util_getopt_reset(); + + while ((c=util_getopt(argc, argv, "Hcfgd:s:m:n:t:w:")) != EOF) { + switch (c) { + case 'c': cutset_flag = 1; break; + case 'g': print_gate_name = TRUE; break; + case 'f': new_method = FALSE; break; + case 'H': hilite_flag = 1; break; + case 'n': plot_name = util_optarg; break; + case 't': thresh = atof(util_optarg); break; + case 'w': coeff = atof(util_optarg); break; + case 'd': dist = atoi(util_optarg); break; + case 's': + if (strcmp(util_optarg, "crit") == 0) { + region_flag = ALONG_CRIT_PATH; + } else if (strcmp(util_optarg, "transitive") == 0){ + region_flag = TRANSITIVE_FANIN; + } else if (strcmp(util_optarg, "compromise") == 0){ + region_flag = COMPROMISE; + } else if (strcmp(util_optarg, "tree") == 0){ + region_flag = ONLY_TREE; + } else { + (void)fprintf(sisout, "Illegal argument to the -s flag\n"); + return speed_plot_use(); + } + break; + case 'm': + model = delay_get_model_from_name(util_optarg); + if (model == DELAY_MODEL_LIBRARY){ + model = DELAY_MODEL_MAPPED; + } else if (model == DELAY_MODEL_UNKNOWN){ + (void)fprintf(siserr, "Unknown delay model %s\n", util_optarg); + return speed_plot_use(); + } + break; + default: return speed_plot_use(); + } + } + + if (coeff < 0) coeff = 0; + if (coeff > 1) coeff = 1; + + if (argc - util_optind > 0) return speed_plot_use(); + + do_speed_plot (*network, plot_name, thresh, hilite_flag, cutset_flag, + print_gate_name, model, dist, coeff, new_method, + region_flag); + return 0; +} + + + diff --git a/sis/speed/speed_util.c b/sis/speed/speed_util.c new file mode 100644 index 0000000..bb44c5a --- /dev/null +++ b/sis/speed/speed_util.c @@ -0,0 +1,506 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speed_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include <stdio.h> +#include "sis.h" +#include "speed_int.h" + +static st_table *level_table; /* For the levelize routines */ +int level_cmp(); + +/* + * Routine to form a node with the set as the i'th + * cube of the node. + */ +node_t * +speed_dec_node_cube(f, i) +node_t *f; +int i; +{ + node_cube_t cube; + node_t *c, *fanin, *tlit, *t; + int j; + + c = node_constant(1); + cube = node_get_cube(f, i); + foreach_fanin(f, j, fanin) { + switch (node_get_literal(cube, j)) { + case ZERO: + tlit = node_literal(fanin, 0); + t = node_and(c, tlit); + node_free(tlit); node_free(c); + c = t; + break; + case ONE: + tlit = node_literal(fanin, 1); + t = node_and(c, tlit); + node_free(tlit); node_free(c); + c = t; + } + } + + return c; +} + +/* + * Deletes the cubes with inputs whose arrival + * times are greater than the threshold. + */ +void +speed_del_critical_cubes(node, speed_param, thresh) +node_t *node; +speed_global_t *speed_param; +double thresh; +{ + node_t *cube, *new, *new_node, *fanin; + int i, j, crit_flag; + delay_time_t time; + double t; + + new = node_constant(0); + for(i = 0; i < node_num_cube(node); i++){ + crit_flag = FALSE; + cube = speed_dec_node_cube(node, i); + foreach_fanin(cube, j, fanin) { + speed_delay_arrival_time(fanin, speed_param, &time); + t = D_MAX(time.rise, time.fall); + if (t > thresh){ + crit_flag = TRUE; + } + } + if (!crit_flag) { + new_node = node_or(new, cube); + node_free(new); + new = new_node; + } + node_free(cube); + } + node_replace(node, new); +} + +/* + * name_to_node -- returns the pointer to the fanin + * of a node with a given name . + */ + +node_t * +name_to_node(node,name) +node_t *node; +char *name; +{ + node_t *fanin; + int i; + + foreach_fanin(node,i,fanin){ + if(strcmp(node_long_name(fanin), name) == 0 ){ + return fanin; + } + } + return NIL(node_t); +} + +int +speed_print_level(network, node_array, thresh, crit_only, flag) +network_t *network; +array_t *node_array; +double thresh; /* Threshold specifying the critical path */ +int crit_only; /* == 1 => print only critical nodes */ +int flag; /* == 1 => print all levels, == 0 => silent mode */ +{ + lsGen gen; + node_t *p; + char *dummy; + st_table *node_table; + delay_time_t slack; + int i, j, level, new_level; + array_t *nodevec, *temp_array; + + level_table = st_init_table(st_ptrcmp, st_ptrhash); + + foreach_node(network, gen, p) { + (void) st_insert(level_table, (char *)p, (char *)0); + } + + foreach_primary_output(network, gen, p) { + (void) assign_level(p); + } + + nodevec = network_dfs_from_input(network); + array_sort(nodevec, level_cmp); + + if (node_array == NIL(array_t)) { + /* All nodes can be printed */ + node_table = level_table; + } else { + /* Get the nodes to be printed */ + node_table = st_init_table(st_ptrcmp, st_ptrhash); + for (i = 0; i < array_n(node_array); i++){ + p = array_fetch(node_t *, node_array, i); + (void)st_insert(node_table, (char *)p, NIL(char)); + temp_array = network_tfi(p, INFINITY); + for (j = array_n(temp_array); j-- > 0; ){ + p = array_fetch(node_t *, temp_array, j); + (void)st_insert(node_table, (char *)p, NIL(char)); + } + array_free(temp_array); + } + } + + level = 0; + if (flag) + (void) fprintf(sisout, "%3d:", level); + for (i = 0; i < array_n(nodevec); i++) { + p = array_fetch(node_t *, nodevec, i); + if (p->type != PRIMARY_OUTPUT && st_is_member(node_table, (char *)p)) { + slack = delay_slack_time(p); + if (crit_only && + slack.rise > thresh && slack.fall > thresh) continue; + if (st_lookup(level_table, (char *)p, &dummy) ){ + new_level = (int)dummy; + if (new_level > level) { + level = new_level; + if (flag) + (void) fprintf(sisout,"\n%3d:", level); + } + if (flag) + (void) fprintf(sisout, " %s", node_name(p)); + } else { + if (flag) + (void) fprintf(sisout,"Node %s not assigned a level", + node_name(p)); + } + } + } + if (flag) (void)fprintf(sisout," \n"); + array_free(nodevec); + st_free_table(level_table); + if (node_array != NIL(array_t)) st_free_table(node_table); + + return level; +} + +int +assign_level(node) +node_t *node; +{ + node_t *fanin; + int i, level, new_level; + char *dummy; + + (void) st_lookup(level_table, (char *)node, &dummy); + new_level = (int)dummy; + if (node->type == PRIMARY_INPUT || new_level > 0) { + return new_level ; + } else { + level = 0; + foreach_fanin(node, i, fanin) { + level = MAX(level, assign_level(fanin)); + } + } + level++; + (void) st_insert(level_table, (char *)node, (char *)level); + + return level; +} + +int +level_cmp(p1, p2) +char **p1, **p2; +{ + int level1, level2; + char *dummy; + + (void) st_lookup(level_table, *p1, &dummy); + level1 = (int) dummy; + (void) st_lookup(level_table, *p2, &dummy); + level2 = (int) dummy; + return (level1 - level2); +} + + +st_table * +speed_levelize_crit(network, speed_param, max_levelp) +network_t *network; +speed_global_t *speed_param; +int *max_levelp; /* RETURN: the maximum level in the circuit */ +{ + array_t *nodevec; + lsGen gen; + node_t *p; + int i, level, new_level; + char *dummy; + st_table *table; + + level_table = st_init_table(st_ptrcmp, st_ptrhash); + table = st_init_table(st_ptrcmp, st_ptrhash); + + foreach_node(network, gen, p) { + (void) st_insert(level_table, (char *)p, (char *)0); + } + + foreach_primary_output(network, gen, p) { + (void) assign_level(p); + } + + nodevec = network_dfs_from_input(network); + array_sort(nodevec, level_cmp); + + level = -1; + for (i = 0; i < array_n(nodevec); i++) { + p = array_fetch(node_t *, nodevec, i); + if ((p->type != PRIMARY_OUTPUT) && (speed_critical(p, speed_param))) { + if (st_lookup(level_table, (char *)p, &dummy) ){ + new_level = (int)dummy; + if (new_level > level) { + level = new_level; + } + (void) st_insert(table, (char *)p, (char *) level); + } else { + (void) fprintf(siserr,"Node %s not assigned a level\n", + node_name(p)); + } + } + } + array_free(nodevec); + st_free_table(level_table); + + *max_levelp = level; + return table; +} + +/* + * Compute the area of a network + */ +double +sp_get_netw_area(network) +network_t *network; +{ + lsGen gen; + int mapped_flag; + double area; + node_t *node; + + if (network == NIL(network_t)) return 0.0; + + area = 0; + mapped_flag = lib_network_is_mapped(network); + foreach_node(network, gen, node){ + if (node->type == INTERNAL){ + if (mapped_flag){ + area += lib_gate_area(lib_gate_of(node)); + } else { + area += factor_num_literal(node); + } + } + } + return area; +} + +void +speed_get_stats(network, library, model, delay, area) +network_t *network; +library_t *library; +delay_model_t model; +double *delay; +double *area; +{ + node_t *np; + lsGen gen; + network_t *new_net; + + assert(delay_trace(network, model)); + (void) delay_latest_output(network, delay); + + /* + * Add inverters and map the network + */ + + *area = 0.0; + new_net = network_dup(network); + add_inv_network(new_net); + new_net = map_network(new_net, library, 1.0, 1, 3); + foreach_node(new_net, gen, np){ + *area += lib_get_gate_area(np); + } + network_free(new_net); +} + +void +set_speed_thresh(network, speed_param) +network_t *network; +speed_global_t *speed_param; +{ + delay_time_t time; + double my_thresh, min_t; + node_t *po; + lsGen gen; + + my_thresh = POS_LARGE; + foreach_primary_output(network, gen, po){ + time = delay_slack_time(po); + min_t = D_MIN(time.rise, time.fall); + my_thresh = D_MIN(my_thresh, min_t); + } + if (my_thresh > 1.0e-6 /* For floating point comparisons */ ) { + /* + * All output nodes meet the required + * time costraints. + */ + speed_param->crit_slack = -1.0; + } else { + /* + * Set the threshold for the epsilon + * network to be within thresh of the most + * most critical node. + */ + speed_param->crit_slack = my_thresh + speed_param->thresh; + } +} + +void +speed_delete_single_fanin_node(network, node) +network_t *network; +node_t *node; +{ + int i; + node_t *fo; + lsGen gen; + array_t *array; + + if (node_num_fanin(node) <= 1){ + array = array_alloc(node_t *, 0); + foreach_fanout(node, gen, fo){ + array_insert_last(node_t *, array, fo); + } + /* + * Now collapse the node into its fanouts. + */ + for (i = 0; i < array_n(array); i++){ + fo = array_fetch(node_t *, array, i); + (void) node_collapse(fo, node); + } + /* + * Free the node if it has no fanouts. + */ + if (node_num_fanout(node) == 0) + speed_network_delete_node(network, node); + array_free(array); + } +} + +void +speed_network_delete_node(network, node) +network_t *network; +node_t *node; +{ + int i; + node_t *fanin; + array_t *nodevec; + + nodevec = array_alloc(node_t *, 0); + + foreach_fanin(node, i, fanin){ + if (node_num_fanout(fanin) == 1){ + array_insert_last(node_t *, nodevec, fanin); + } + } + + network_delete_node(network, node ); + + for (i = 0; i < array_n(nodevec); i++){ + fanin = array_fetch(node_t *, nodevec, i); + speed_network_delete_node(network, fanin); + } + + array_free(nodevec); +} + +/* For the purposes of buffering we may need buffers from the library */ +lib_gate_t * +sp_lib_get_buffer(lib) +library_t *lib; +{ + network_t *network; + lib_class_t *class; + lib_gate_t *gate; + + if (lsLength(lib->patterns) > 0){ /* Should be a macro */ + /* The patterns were generated */ + network = read_eqn_string("f = a;"); + assert(network != NIL(network_t)); + class = lib_get_class(network, lib); + network_free(network); + if (class == NIL(lib_class_t)) { + gate = NIL(lib_gate_t); + } else { + gate = sp_get_gate(class, 0); + } + } else { + gate = lib_get_gate(lib, MIN_AREA_BUF_NAME); + } + return gate; +} + +/* + * Get the min size iverter from the library description + */ +lib_gate_t * +sp_lib_get_inv(lib) +library_t *lib; +{ + network_t *network; + lib_class_t *class; + lib_gate_t *gate; + + if (lsLength(lib->patterns) > 0){ /* Should be a macro */ + /* The patterns were generated */ + network = read_eqn_string("f = a';"); + assert(network != NIL(network_t)); + class = lib_get_class(network, lib); + network_free(network); + if (class == NIL(lib_class_t)) { + gate = NIL(lib_gate_t); + } else { + gate = sp_get_gate(class, 0); + } + } else { + gate = lib_get_gate(lib, MIN_AREA_BUF_NAME); + } + return gate; +} + +lib_gate_t * +sp_get_gate(class, which) +lib_class_t *class; +int which; /* 0 = smallest, 1 = biggest */ +{ + lib_gate_t *gate; + lsGen gen; + char *dummy; + + if (class == NIL(lib_class_t)) return NIL(lib_gate_t); + + gen = lib_gen_gates(class); + if (lsNext(gen, &dummy, LS_NH) != LS_OK) { + fail("Error, No inverters in library\n"); + } + gate = (lib_gate_t *) dummy; + while (lsNext(gen, &dummy, LS_NH) == LS_OK) { + if (which ){ + if (lib_gate_area((lib_gate_t *) dummy) > lib_gate_area(gate)) + gate = (lib_gate_t *) dummy; + } else { + if (lib_gate_area((lib_gate_t *) dummy) < lib_gate_area(gate)) + gate = (lib_gate_t *) dummy; + } + } + (void) lsFinish(gen); + + return gate; +} diff --git a/sis/speed/speedup.c b/sis/speed/speedup.c new file mode 100644 index 0000000..e810d6f --- /dev/null +++ b/sis/speed/speedup.c @@ -0,0 +1,547 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/speedup.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:50 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include <math.h> + +static void speed_replace(); +static int speed_resub_alge_node(); +static int speed_resub_alge_network(); +int sp_compare_cutset_nodes(); /* For order of collapsing */ + +bool +speed_critical(np, speed_param) +node_t *np; +speed_global_t *speed_param; +{ + delay_time_t time; + + time = delay_slack_time(np); + if (time.rise < (speed_param->crit_slack - NSP_EPSILON) || + time.fall < (speed_param->crit_slack - NSP_EPSILON) ) { + return TRUE; + } else { + return FALSE; + } +} + + +int +speed_is_fanout_po(node) +node_t *node; +{ + lsGen gen; + node_t *fo; + + foreach_fanout(node, gen, fo){ + if (node_function(fo) == NODE_PO) { + (void) lsFinish(gen); + return TRUE; + } + } + return FALSE; +} + + +void +speed_up_network(network, speed_param) +network_t *network; +speed_global_t *speed_param; +{ + int i; + st_table *table; + lsGen gen, gen1; + array_t *mincut, *revised_order; + node_t *np, *fo, *fan, *fanin, *fanin_in; + + + /* Build up the table of weights */ + set_speed_thresh(network, speed_param); + table = speed_compute_weight(network, speed_param, NIL(array_t)); + + /* compute the minimum weighted cutset of the critical paths */ + mincut = cutset(network, table); + + /* Make sure that nodes get collapsed in the order --- outputs to inputs */ + revised_order = sp_generate_revised_order(mincut, speed_param, NIL(st_table)); + array_free(mincut); + mincut = revised_order; + + /* + * partial_collapse & re-decompose each collapsed node. + */ + for (i= 0; i < array_n(mincut); i++) { + np = array_fetch(node_t *, mincut, i); + speed_absorb(np, speed_param); + } + for (i= 0; i < array_n(mincut); i++) { + np = array_fetch(node_t *, mincut, i); + + if(np->type == INTERNAL ){ + if(speed_param->debug){ + (void) fprintf(sisout, "\nSPEED DECOMPOSING NODE \t "); + node_print(sisout,np); + } + speed_up_node(network, np, speed_param, 0); + } + } + + /* + * Due to the collapsing of the inverters, some + * primary o/p may become buffers. Remove these. + */ + foreach_primary_output(network, gen, fo){ + fanin = node_get_fanin(fo, 0); + if (node_function(fanin) == NODE_BUF){ + fanin_in = node_get_fanin(fanin, 0); + assert(node_patch_fanin(fo, fanin, fanin_in)); + foreach_fanout(fanin, gen1, fan){ + (void) node_collapse(fan, fanin); + } + if (node_num_fanout(fanin) == 0) speed_network_delete_node(network, fanin); + } else if (node_function(fanin) == NODE_INV) { + foreach_fanout(fanin, gen1, fan){ + (void) node_collapse(fan, fanin); + } + if (node_num_fanout(fanin) == 0) speed_network_delete_node(network, fanin); + } + } + + /* + *Just a check: If the routines are good this is not needed + */ + /* + if (network_ccleanup(network) ) { + (void) fprintf(sisout, " Hey ! cleanup was done \n"); + } + */ + + array_free(mincut); + st_free_table(table); +} + + +/* + * Exported interface to the routine speed_up_node () that decomposes + * a node in place in the network (assuming a valid trace)... + */ +void +speed_node_interface(network, node, coeff, model) +network_t *network; +node_t *node; +double coeff; +delay_model_t model; +{ + speed_global_t speed_param; + + (void)speed_fill_options(&speed_param, 0, NIL(char *)); + speed_param.coeff = coeff; + speed_param.model = model; + + speed_set_delay_data(&speed_param, 0 /* No library acceleration */); + speed_up_node(network, node, &speed_param, 0 /* Use fanin arrival time */); + + return; + +} + + +void +speed_up_node(network, np, speed_param, delay_flag) +network_t *network; +node_t *np; +speed_global_t *speed_param; +int delay_flag; /* 1=> use user field */ +{ + array_t *nodes; + delay_time_t t; + + /* + * Check if the node is fit to be decomposed. + */ + if (np->type != INTERNAL || node_num_literal(np) == 0) { + speed_single_level_update(np, speed_param, &t); + return; + } + + if (node_num_fanin(np) <= 2 && node_num_cube(np) <= 1){ + speed_single_level_update(np, speed_param, &t); + return; + } + + nodes = speed_decomp(np, speed_param, delay_flag); + + if (nodes != NIL(array_t) ){ + speed_replace(network, np, nodes, speed_param); + } else { + fail("Speed_decomp returned a null array"); + exit(-1); + } + + array_free(nodes); +} + +int +speed_init_decomp(network, speed_param) +network_t *network; +speed_global_t *speed_param; +{ + node_t *node, *temp; + array_t *nodevec; + int i, n_attempts, del_crit_flag, debug_flag; + + /* + * Check if the initial 2-input decomposition is required: In the case + * when the mapped optimization is being used this is not rerquired + */ + if (speed_param->new_mode && speed_param->model == DELAY_MODEL_MAPPED){ + if (speed_param->interactive) { + (void)fprintf(sisout,"INFO: For mapped network, 2-input decomp BYPASSED\n"); + } + return 0; + } + if (speed_param->add_inv) { + (void) add_inv_network(network); + } else { + (void) network_csweep(network); + } + + assert(speed_delay_trace(network, speed_param)); + nodevec = network_dfs(network); + + /* Use only a single attempt at decomposing the node */ + n_attempts = speed_param->num_tries; + speed_param->num_tries = 1; + + debug_flag = speed_param->debug; + speed_param->debug = FALSE; + del_crit_flag = speed_param->del_crit_cubes; + speed_param->del_crit_cubes = TRUE; + + for (i = 0; i < array_n(nodevec); i++) { + node = array_fetch(node_t *, nodevec, i); + if (node->type == INTERNAL){ + /* + * Just for the case when redundant boolean networks are passed. + * Make sure that there are no obvious obvious redundancies like + * f = (a+a')+... -- Has happened in industrial examples !!! + */ + temp = node_simplify(node, NIL(node_t), NODE_SIM_SIMPCOMP); + node_replace(node, temp); + speed_up_node(network, node, speed_param, 1); + } + } + speed_param->debug = debug_flag; + speed_param->num_tries = n_attempts; + speed_param->del_crit_cubes = del_crit_flag; + + /* + * During the decomposition into 2-input NAND gates there is a + * lot of possibility that nodes computing the same logic function + * exist. Get rid of these by an algebraic resubstitution. + */ + + if (speed_param->area_reclaim) + speed_resub_alge_network(network); + + if (speed_param->add_inv) { + (void) add_inv_network(network); + } else { + (void) network_csweep(network); + } + + array_free(nodevec); + return 0; +} + +static void +speed_replace(network, np, nodes, speed_param) +network_t *network; +node_t *np; +array_t *nodes; +speed_global_t *speed_param; +{ + int i; + char *dummy; + delay_time_t t; + st_table *table; + array_t *inv_array, *added_array, *added_tables; + node_t *temp, *root_node; + + if (array_n(nodes) > 3){ + inv_array = array_alloc(node_t *, 0); + added_array = array_alloc(node_t *, 0); + added_tables = array_alloc(st_table *, 0); + table = st_init_table(st_ptrcmp, st_ptrhash); + + /* + * Now add the nodes in the array. If the inverters + * have to be removed, record their occurance and + * collapse them later. + */ + node_free(array_fetch(node_t *, nodes, 0)); + root_node = array_fetch(node_t *, nodes, 1); + speed_delay_arrival_time(root_node, speed_param, &t); + + for (i = array_n(nodes)-1; i > 1; i--) { + temp = array_fetch(node_t *, nodes, i); + (void)st_insert(table, (char *)temp, ""); + } + for (i = array_n(nodes)-1; i > 1; i--) { + temp = array_fetch(node_t *, nodes, i); + if (node_function(temp) != NODE_PI){ + + network_add_node(network,temp); + (void) st_delete(table, (char **)&temp, &dummy); + if (node_num_fanin(temp) < 2){ + array_insert_last(node_t *, inv_array, temp); + } else if (speed_param->area_reclaim ) { + /* + * Check if this node is already present - + * i.e try an algebraic resubstitution. + */ + array_insert_last(node_t *, added_array, temp); + array_insert_last(st_table *, added_tables, st_copy(table)); + } + } else { + node_free(temp); + } + } + + node_replace(np, root_node); + speed_set_arrival_time(np, t); + st_free_table(table); + + for (i = 0; i < array_n(added_array); i++) { + table = array_fetch(st_table *, added_tables, i); + temp = array_fetch(node_t *, added_array, i); + if (speed_param->debug){ + (void)fprintf(sisout,"Trying resub for"); + node_print(sisout, temp); + } + if (speed_resub_alge_node(network, temp, table)){ + network_delete_node(network, temp); + } else if (speed_param->debug) { + (void)fprintf(sisout,"After resub"); + node_print(sisout, temp); + } + st_free_table(table ); + } + array_free(added_array); + array_free(added_tables); + + /* + * Conditional removal of the inverters. + */ + if (! speed_param->add_inv) { + for (i = 0; i < array_n(inv_array) ; i++){ + temp = array_fetch(node_t *, inv_array, i); + speed_delete_single_fanin_node(network, temp); + } + } + array_free(inv_array); + + if ((node_num_fanin(np) == 1) && + (speed_is_fanout_po(np) == FALSE) ){ + speed_delete_single_fanin_node(network, np); + } + } else { + /* + * If the node could be replaced by something this trivial + * then one might as well simplify the node itself. + * We still need to update the delay times + */ + root_node = node_simplify(np, NIL(node_t), NODE_SIM_SIMPCOMP); + node_replace(np, root_node); + (void)speed_update_arrival_time(np, speed_param); + } +} + +/* + * Substitute node f into other nodes in the network and not in "table". + * The node "f" might have no fanouts if the substitution is made . In that case + * the routine returns 1, otherwise if nothing happened it returns 0 + */ +static int +speed_resub_alge_node(network, f, table) +network_t *network; +node_t *f; +st_table *table; +{ + lsGen gen; + node_t *np, *fo; + int i, changed = 0; + array_t *target, *tl1; + + if (f->type == PRIMARY_INPUT || f->type == PRIMARY_OUTPUT) { + return changed; + } + + if (node_num_literal(f) < 1 || (node_num_fanout(f) > 1) ){ + return changed; + } + + target = array_alloc(node_t *, 0); + foreach_fanin(f, i, np) { + tl1 = array_alloc(node_t *, 0); + foreach_fanout(np, gen, fo) { + if ((node_num_fanin(fo) <= 2) && + (table == NIL(st_table) || !st_is_member(table, (char *)fo))){ + array_insert_last(node_t *, tl1, fo); + } + } + array_append(target, tl1); + array_free(tl1); + } + array_sort(target, node_compare_id); + array_uniq(target, node_compare_id, (void (*)()) 0); + + for(i = 0; i < array_n(target); i++) { + np = array_fetch(node_t *, target, i); + /* + * Only resubstitution candidates should have single fanout. + * This way the delay (under the unit-fanout model) will + * not worsen as a result of increased loading + */ + if (node_num_fanout(np) < 2 && node_substitute(f, np, 0) ) { + /* See if the substituted node can be removed */ + if (node_num_fanin(f) <= 1) { + foreach_fanout(f, gen, fo) { + (void) node_collapse(fo, f); + } + if (node_num_fanout(f) == 0) { + changed = 1; + break; + } + } + } + } + array_free(target); + + return changed; +} + +static st_table *sort_info_table; +static speed_global_t *sort_speed_param; +/* + * Order the nodes in the separator set so that the nodes closer to the + * output are first in the array. That way, they will be collapsed earlier + * and the problem of collapsing already collapsed nodes "should" disappear.... + */ +array_t * +sp_generate_revised_order(array, speed_param, clp_table) +array_t *array; +speed_global_t *speed_param; +st_table *clp_table; +{ + array_t *new_array; + + new_array = array_dup(array); + sort_info_table = clp_table; + sort_speed_param = speed_param; + array_sort(new_array, sp_compare_cutset_nodes); + return new_array; +} + +int +sp_compare_cutset_nodes(ptr1, ptr2) +char **ptr1; +char **ptr2; +{ + node_t *f; + int i, fanin_based_technique; + node_t *node1 = (node_t *)*ptr1; + node_t *node2 = (node_t *)*ptr2; + sp_xform_t *l1, *l2; + sp_weight_t *wght1, *wght2; + array_t *array; + network_t *network; + + network = node_network(node1); + assert(network == node_network(node2)); + + if (sort_info_table == NIL(st_table)){ + fanin_based_technique = TRUE; + } else { + assert(st_lookup(sort_info_table, (char *)node1, (char **)&wght1)); + assert(st_lookup(sort_info_table, (char *)node2, (char **)&wght2)); + l1 = sp_local_trans_from_index(sort_speed_param, wght1->best_technique); + l2 = sp_local_trans_from_index(sort_speed_param, wght2->best_technique); + if (l1->type != CLP && l2->type != CLP){ + fanin_based_technique = FALSE; + } else if (l1->type == CLP && l2->type == CLP){ + fanin_based_technique = TRUE; + } else { + /* Place the FANOUT optimizations before the FANIN optimizations */ + if (l1->type) { + return -1; + } else { + return 1; + } + } + } + /* Return -1 if node2 is in the tfi of node1 (and fanin_based methods + in use) */ + array = network_tfi(node1, INFINITY); + for (i = array_n(array); i-- > 0; ){ + f = array_fetch(node_t *, array, i); + if (f == node2) { + array_free(array); + if (fanin_based_technique){ + return -1; + } else { + return 1; + } + } + } + array_free(array); + + /* Return 1 if node1 is in the tfi of node2 */ + array = network_tfi(node2, INFINITY); + for (i = array_n(array); i-- > 0; ){ + f = array_fetch(node_t *, array, i); + if (f == node1) { + array_free(array); + if (fanin_based_technique){ + return 1; + } else { + return -1; + } + } + } + array_free(array); + + return 0; +} + +/* + * Substitute each function in the network into all other + * functions using algebraic division of the function and + * its complement. + */ +static int +speed_resub_alge_network(network) +network_t *network; +{ + lsGen gen; + node_t *np; + bool not_done; + + not_done = TRUE; + while (not_done) { + not_done = FALSE; + foreach_node(network, gen, np) { + if (speed_resub_alge_node(network, np, NIL(st_table))) { + network_delete_node_gen(network, gen); + not_done = TRUE; + } + } + } +} diff --git a/sis/speed/weight.c b/sis/speed/weight.c new file mode 100644 index 0000000..44ed1e6 --- /dev/null +++ b/sis/speed/weight.c @@ -0,0 +1,582 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/weight.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include <math.h> + +static void weight_compute(); +static int speed_weight_bfs(); +static void speed_mark_input_cone(); +static void linfit(); +static void speed_sort2(); +static void speed_rank(); +static delay_time_t sp_compute_input_req(); +delay_time_t *sp_compute_side_req_time(); + +enum st_retval speed_weight_count_lit(); +/* + * If the return value is 1 only then the components should + * be combined. If the return is 0 then a large weight needs + * put on the node + */ + +int +speed_weight(node, speed_param, t_cost, a_cost) +node_t *node; +speed_global_t *speed_param; +double *t_cost; +int *a_cost; +{ + double max_a, min_a, min_d, mean_a , mean_d; /* For scaling */ + double m, o_time, a_time, d_time; /* For correlation */ + double s_dev, tf, crit_frac, area_cost; + double rad, sum_a, sum_d, co, angle, p_angle, slope; + int i, n, crit; + delay_time_t t; + st_table *table; + array_t *a_array, *d_array; + /* Some day do special casing of a Boolean nature */ + /* + int to_cofactor; + */ + + a_array = array_alloc(double,0); + d_array = array_alloc(double,0); + min_a = min_d = POS_LARGE; + max_a = NEG_LARGE; + sum_a = sum_d = rad = 0.0; + + table = st_init_table(st_ptrcmp, st_ptrhash); + + t = delay_arrival_time(node); + o_time = D_MAX(t.rise, t.fall); + + *a_cost = 0; + crit = 0; + n = 0; + + (void) speed_weight_bfs(node, speed_param, table, a_array, d_array, + o_time, &crit, &n, &min_a, &max_a, &min_d, + &sum_a, &sum_d, &area_cost); + *a_cost = (int)ceil(area_cost); + + /* + * Compute the t_frac as based on the Distribution + * of the delays and a_times in a 2-D plane + */ + + if (n > 2 ) { + m = (double) n; + /* + mean_a = (sum_a / m ) - min_a; + mean_d = (sum_d / m ) - min_d; + */ + mean_a = (sum_a / m ); + mean_d = (sum_d / m ); + + for (i = 0; i < n ; i++){ + a_time = array_fetch(double, a_array, i) - mean_a ; + d_time = array_fetch(double, d_array, i) - mean_d ; + + rad += (pow(d_time, 2.0) + pow(a_time, 2.0)); + } + /* + * Get the standard deviation (preferred over the absolute + * deviation) since we want a large separation and the + * angle from the linear regression. + */ + s_dev = sqrt(rad) / m; + + if (min_a == max_a ){ + angle = SP_PI_2; + } else { + (void) linfit(a_array, d_array, min_a, min_d, &slope); + angle = atan (slope); + } + + if (angle > SP_PI_4){ + co = 4 - (4 * angle * SP_1_PI); + } else{ + co = 2 + (4 * angle * SP_1_PI); + } + co = MAX(co, 0.3); + + tf = co * pow((s_dev / (double)speed_param->dist), 2.0); + /* + tf = pow(co, 2.0) * (s_dev / (double)speed_param->dist); + */ + /* + tf = co * (s_dev / (double)speed_param->dist); + */ + } + else { + tf = -1.0; + s_dev = 0.0; /* Default */ + angle = - SP_PI; + } + + if (speed_param->debug) { + p_angle = angle * 180 * SP_1_PI; + (void) fprintf(sisout,"%-10s T_comp =(%4.0f:%4.2f) Area = %d %3d d_fanin inputs \n", + node_name(node),p_angle , s_dev, *a_cost, array_n(a_array)); + } + + array_free(d_array); + array_free(a_array); + st_free_table(table); + + crit_frac = (n > 0 ? ((double)(crit) / (double)(n)) : 1); + + /* + * tf < 0 => this node should never be considered + */ + if (tf <= 0 ) { + *t_cost = POS_LARGE; + return 0; + } else { + *t_cost = (MAXWEIGHT * crit_frac) / tf; + return 1; + } +} + +static int +speed_weight_bfs(node, speed_param, table, a_array, d_array, o_time, + crit, n, min_a, max_a, min_d, sum_a, sum_d, area) +node_t *node; +speed_global_t *speed_param; +int *crit, *n; +st_table *table; +array_t *a_array, *d_array; +double o_time; +double *sum_a, *sum_d, *min_a, *min_d, *max_a; +double *area; +{ + int i, j, k, first, last; + int to_cofactor = FALSE; + int more_to_come; + int dist = speed_param->dist; + array_t *temp_array; + st_table *area_table, *duplicated_nodes; + node_t *fi,*no; + + temp_array = array_alloc(node_t *, 0); + area_table = st_init_table(st_ptrcmp, st_ptrhash); + array_insert_last(node_t *, temp_array, node); + (void) st_insert(table, (char *)node, (char *)(dist+1)); + first = 0; + more_to_come = TRUE; + for (i = dist; (i > 0) && more_to_come; i--){ + more_to_come = FALSE; + last = array_n(temp_array); + for (j = first; j < last; j++){ + no = array_fetch(node_t *, temp_array, j); + foreach_fanin(no, k, fi) { + if (node_function(fi) == NODE_PI){ + if (! st_insert(table, (char *)fi, (char *)0)){ + if (speed_critical(fi, speed_param) ) (*crit)++; + (*n)++; + weight_compute(fi, speed_param->model, a_array, d_array, o_time, + min_a, max_a, min_d, sum_a, sum_d); + } + } else if (!st_is_member(table, (char *)fi)){ + /* Not yet visited */ + if (speed_critical(fi, speed_param) ){ + /* + * Add to elements that will be processed + */ + (void) st_insert(table, (char *)fi, (char *)i); + array_insert_last(node_t *, temp_array, fi); + more_to_come = TRUE; + } else { + /* + * Will be a fanin to collapsed node + */ + (void) st_insert(table, (char *)fi, (char *)0); + (*n)++; + weight_compute(fi, speed_param->model, a_array, d_array, + o_time, min_a, max_a, min_d, sum_a, sum_d); + } + } + } + } + first = last; + } + + /* + * For the nodes in the array see if they + * fanout elsewhere. If so then mark and count the + * the nodes in the fanin cone + */ + duplicated_nodes = st_init_table(st_ptrcmp, st_ptrhash); + *area = sp_compute_duplicated_area(temp_array, table, duplicated_nodes, + DELAY_MODEL_UNKNOWN); + st_free_table(duplicated_nodes); + + /* + * Now the elements added in the last loop are + * the inputs to the collapsed node. + */ + + for (i = first; i < array_n(temp_array); i++){ + no = array_fetch(node_t *, temp_array, i); + foreach_fanin(no, k, fi){ + if (!st_insert(table, (char *)fi, (char *)0)){ + if (speed_critical(fi, speed_param)) (*crit)++; + (*n)++; + weight_compute(fi, speed_param->model, a_array, d_array, + o_time, min_a, max_a, min_d, sum_a, sum_d); + } + } + } + + array_free(temp_array); + st_free_table(area_table); + return to_cofactor; +} + +/* + * Given a node that fans out of the collapsed logic... mark the part of + * the collapsed logic that needs to be duplicate. In addition, if the + * model != DELAY_MODEL_UNKNOWN, then also compute the required times of side + * output paths and store it alongwith the entry for the duplicated nodes. + */ +static void +speed_mark_input_cone(node, area_table, table, model) +node_t *node; +st_table *area_table, *table; +delay_model_t model; /* If not UNKNOWN, store required times of side outputs */ +{ + array_t *array; + int i, j, first = 0, last; + int more_to_come = TRUE; + delay_time_t *req; + node_t *temp, *fi; + + array = array_alloc(node_t *, 0); + array_insert_last(node_t *, array, node); + while (more_to_come){ + more_to_come = FALSE; + last = array_n(array); + for (i = first; i < last; i++){ + temp = array_fetch(node_t *, array, i); + foreach_fanin(temp, j, fi){ + if (st_is_member(table, (char *)fi)){ + more_to_come = TRUE; + array_insert_last(node_t *, array, fi); + (void)st_insert(area_table, (char *)fi, NIL(char)); + } + } + first = last; + } + } + if (model != DELAY_MODEL_UNKNOWN){ + req = sp_compute_side_req_time(node, table, area_table, model); + } else { + req = NIL(delay_time_t); + } + (void) st_insert(area_table, (char *)node, (char *)req); + array_free(array); +} + +static void +linfit(xin, yin, xmin, ymin, slope) +array_t *yin, *xin; +double *slope, xmin, ymin; +{ + double a=0, d=0, aa=0, ad=0, a_dev; + double *x, *y, m; + int num, j; + + num = array_n(xin); + + if (num != array_n(yin)){ + (void) fprintf(siserr, " Arrays not of same size \n"); + exit (-1); + } + x = ALLOC(double, num+1); + y = ALLOC(double, num+1); + + for (j = 1; j <= num; j++){ + x[j] = (array_fetch(double, xin, j-1) - xmin); + y[j] = (array_fetch(double, yin, j-1) - ymin); + } + + /* Work with ranks rather than the delay values */ + speed_sort2(num, y, x); + speed_rank(num, y); + speed_sort2(num, x, y); + speed_rank(num, x); + + /* Compute the least square fit */ + for (j = 1; j <= num; j++){ + a += x[j]; + d += y[j]; + aa += x[j] * x[j]; + ad += x[j] * y[j]; + } + m = (double)num; + + a_dev = (aa / m) - ((a * a)/(m * m )); + *slope = ((ad/m) - ((a * d)/(m * m)))/(sqrt(a_dev)); + + FREE(x); + FREE(y); +} + + +static void +speed_sort2(n, ra, rb) +int n; +double ra[], rb[]; +{ + int i, j, ir, l; + double rra, rrb; + + l = (n >> 1)+1; + ir = n; + for(;;){ + if (l > 1){ + rra = ra[--l]; + rrb = rb[l]; + } else{ + rra = ra[ir]; + rrb = rb[ir]; + ra[ir] = ra[1]; + rb[ir] = rb[1]; + if (--ir == 1){ + ra[1] = rra; + rb[1] = rrb; + return; + } + } + i = l; + j = l << 1; + while(j <= ir){ + if (j < ir && ra[j] < ra[j+1]) ++j; + if (rra < ra[j]){ + ra[i] = ra[j]; + rb[i] = rb[j]; + j += (i = j); + } + else j = ir + 1; + } + ra[i] = rra; + rb[i] = rrb; + } +} + +static void +speed_rank(n, w) +double w[]; +int n; +{ + int j=1, ji, jt; + double rank; + + while(j < n){ + if (w[j+1] != w[j]){ + w[j] = (double)j; + ++j; + } else{ + for(jt = j+1; jt < n; jt++){ + if(w[jt] != w[j]) break; + } + rank = 0.5 * (j + jt - 1); + for(ji = j; ji <=(jt-1); ji++){ + w[ji] = rank; + } + j = jt; + } + } + if (j == n) w[n] = n; +} + + +/* + * For the node, gets the slacks and arrival times. + * Updates the min, max and sums and inserts the + * delay and arrival times in the corresponding arrays + */ +static void +weight_compute(node, model, a_array, d_array, o_time, min_a, + max_a, min_d, sum_a, sum_d) +node_t *node; +delay_model_t model; +array_t *a_array, *d_array; +double o_time; +double *min_a, *max_a, *min_d, *sum_a, *sum_d; +{ + delay_time_t at, st; + double d_time, a_time, s_time; + + st = delay_slack_time(node); + at = delay_arrival_time(node); + + a_time = D_MIN(at.rise, at.fall); + s_time = D_MIN(st.rise, st.fall); + + d_time = o_time - s_time - a_time; + *min_a = D_MIN(*min_a, a_time); + *max_a = D_MAX(*max_a, a_time); + *min_d = D_MIN(*min_d, d_time); + + (void) array_insert_last(double, a_array, a_time); + (void) array_insert_last(double, d_array, d_time); + + *sum_a += a_time; + *sum_d += d_time; +} + +/* ARGSUSED */ +enum st_retval +speed_weight_count_lit(key, value, arg) +char *key, *value, *arg; +{ + lib_gate_t *gate; + node_t *node = (node_t *)key; + double *in = (double *)arg; + + if (node->type == INTERNAL) { + if ((gate = lib_gate_of(node)) != NIL(lib_gate_t)){ + *in += lib_gate_area(gate); + } else { + *in += node_num_literal(node); + } + } + + return ST_CONTINUE; +} + +/* + * For the nodes in temp_array (all these nodes should be part of the table) + * that is also passed into this routine, find the area of duplicated logic + * The first node in the array is the root node... + * The duplicated nodes are returned as part of "area_table"... + * if the model is not "DELAY_MODEL_UNKNOWN", then additional work is done + * to find the required time generated by the side-paths to the outputs. + * (Needed to estimate the increase in load tolerated at the inputs) + */ +double +sp_compute_duplicated_area(array, table, area_table, model) +array_t *array; +st_table *table; +st_table *area_table; /* Filled with the nodes that are duplicated */ +delay_model_t model; /* If not UNKNOWN, then store required times too */ +{ + lsGen gen; + double area; + node_t *temp, *fo; + int i, fanout_flag; + + for (i = 1 /* ignore the root */; i < array_n(array); i++){ + temp = array_fetch(node_t *, array, i); + if (!st_is_member(area_table, (char *)temp)){ + if (node_num_fanout(temp) > 1) { + fanout_flag = FALSE; + foreach_fanout(temp, gen, fo){ + if (!st_is_member(table, (char *)fo) ){ + fanout_flag = TRUE; + (void) lsFinish(gen); + break; + } + } + if (fanout_flag){ + speed_mark_input_cone(temp, area_table, table, model); + } + } + } + } + area = 0.0; + st_foreach(area_table, speed_weight_count_lit, (char *)&area); + + return area; +} + +delay_time_t * +sp_compute_side_req_time(node, table, dup_table, model) +node_t *node; +st_table *table; /* table of nodes to collapse */ +st_table *dup_table; /* Table of nodes already marked as duplicated */ +delay_model_t model; /* delay model to compute delays with */ +{ + int pin; + lsGen gen; + node_t *fo; + delay_time_t *po_req, *req_time, cur_req; + + req_time = ALLOC(delay_time_t, 1); + req_time->rise = req_time->fall = POS_LARGE; + + foreach_fanout_pin(node, gen, fo, pin){ + if (st_lookup(dup_table, (char *)fo, (char **)&po_req)){ + /* + * The required time for that fanout is already computed + */ + cur_req = sp_compute_input_req(fo, pin, model, *po_req); + } else if (!st_is_member(table, (char *)fo)){ + /* + * There exists a path ... node-fo ... to some other PO + */ + cur_req = sp_compute_input_req(fo, pin, model, delay_required_time(fo)); + } else { + /* + * The node is not duplicated and will be collapsed... So, + * the only path to output is through the node beiong collapsed + */ + continue; + } + req_time->rise = MIN(req_time->rise, cur_req.rise); + req_time->fall = MIN(req_time->fall, cur_req.fall); + } + + return req_time; +} + +/* + * Given the required time "fo_req" at the output of a node "fo", compute + * the required time at the "pin" input of that node... + */ +static delay_time_t +sp_compute_input_req(fo, pin, model, fo_req) +node_t *fo; +int pin; +delay_model_t model; +delay_time_t fo_req; +{ + delay_time_t delay; + input_phase_t phase; + delay_time_t input_req; + + input_req = fo_req; + if (fo->type == PRIMARY_OUTPUT){ + return input_req; /* Cant call node_input_phase() for PO nodes */ + } + delay = delay_node_pin(fo, pin, model); + phase = node_input_phase(fo, node_get_fanin(fo, pin)); + + switch(phase){ + case POS_UNATE: + input_req.rise = fo_req.rise - delay.rise; + input_req.fall = fo_req.fall - delay.fall; + break; + case NEG_UNATE: + input_req.fall = fo_req.rise - delay.rise; + input_req.rise = fo_req.fall - delay.fall; + break; + case BINATE: + input_req.rise = fo_req.rise - MAX(delay.rise, delay.fall); + input_req.fall = fo_req.fall - MAX(delay.rise, delay.fall); + break; + case PHASE_UNKNOWN: + default: + break; + } + return input_req; +} diff --git a/sis/speed/weight_util.c b/sis/speed/weight_util.c new file mode 100644 index 0000000..ebd5fee --- /dev/null +++ b/sis/speed/weight_util.c @@ -0,0 +1,146 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/speed/weight_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:51 $ + * + */ +#include "sis.h" +#include "speed_int.h" +#include <math.h> + +#define SCALE 100.0 +#define SCALE_2 10000 + +st_table * +speed_compute_weight(network, speed_param, array) +network_t *network; +speed_global_t *speed_param; +array_t *array; /* List of nodes whose delays are to be printed */ +{ + st_table *table, *crit_table, *weight_table; + st_generator *stgen; + node_t *np; + lsGen gen; + int weight, level, temp, a_weight, min_area, max_area; + double min_time, max_time, t_range, a_range, t_weight, tmp_weight; + delay_time_t *temp_weight, *t; + array_t *w_array, *level_array; + char *dummy, *dummy1; + int i, max_level; + + /* Initializations */ + table = st_init_table(st_ptrcmp, st_ptrhash); + weight_table = st_init_table(st_ptrcmp, st_ptrhash); + min_time = POS_LARGE; + max_time = NEG_LARGE; + min_area = POS_LARGE; + max_area = NEG_LARGE; + + /* Store the level of the critical signal in the table */ + crit_table = speed_levelize_crit(network, speed_param, &max_level); + + /* Build an array such that the entry holds the + numer of crit signals at that level */ + w_array = array_alloc(node_t *, 0); + level_array = array_alloc(int, 0); + for (i = 0; i <= max_level; i++){ + array_insert (int, level_array, i, 0); + } + foreach_node(network, gen, np) { + if (np->type == INTERNAL) { + if (st_lookup(crit_table, (char *)np, &dummy) ) { + level = (int) dummy; + temp = array_fetch(int, level_array, level); + temp ++; + array_insert(int, level_array, level, temp); + } + } + } + + foreach_node(network, gen, np) { + if (np->type == INTERNAL) { + if (speed_critical(np, speed_param) ) { + if (speed_weight(np, speed_param, &t_weight, &a_weight) ){ + temp_weight = ALLOC(delay_time_t, 1); + temp_weight->rise = t_weight; + temp_weight->fall = (double)a_weight; + (void) st_insert(weight_table, (char *)np, + (char *)temp_weight); + + max_time = MAX(max_time, t_weight); + min_time = MIN(min_time, t_weight); + max_area = MAX(max_area, a_weight); + min_area = MIN(min_area, a_weight); + + (void) array_insert_last(node_t *, w_array, np); + } else{ + (void) st_insert(table, (char *)np, + (char *)(MAXWEIGHT * 100)); + } + } + } + } + + /* + * Combine the weight values and after + * scaling them to be in the same range + */ + a_range = (double)max_area - (double)min_area; + a_range = (a_range == 0 ? 1 : a_range); + t_range = max_time - min_time; + t_range = (t_range == 0 ? 1 : t_range); + + for (i = 0; i < array_n(w_array); i++){ + np = array_fetch(node_t *, w_array, i); + if (st_lookup(weight_table, (char *)np, &dummy1) ){ + t = (delay_time_t *)dummy1; + t->rise = ((MAXWEIGHT * (t->rise - min_time )) / t_range) +1 ; + t->fall = (MAXWEIGHT * (t->fall - min_area)) / a_range; +/* + * Divide the weight by the number of critical signals + * at that level + */ + (void) st_lookup(crit_table, (char *)np, &dummy) ; + level = (int) dummy; + temp = array_fetch(int, level_array, level); + tmp_weight = t->rise + speed_param->coeff * t->fall; + weight = (int)ceil((tmp_weight / (double) temp)); + (void) st_insert(table, (char *)np, (char *)weight); + } + } + + if (array != NIL(array_t)) { + for (i = 0; i < array_n(array); i++) { + np = array_fetch(node_t *, array, i); + if (st_lookup(table, (char *)np, &dummy) ){ + weight = (int)dummy; + (void) st_lookup(crit_table, (char *)np, &dummy) ; + level = (int) dummy; + temp = array_fetch(int, level_array, level); + if (st_lookup(weight_table, (char *)np, &dummy1) ){ + t = (delay_time_t *)dummy1; + if (speed_param->debug){ + (void) fprintf(sisout, "%-10s Weight(t=%6.4f ,a=%6.4f)/%2d = %-6d\n", + node_name(np), t->rise, t->fall, temp, weight); + } + } else { + (void) fprintf(sisout, "%-10s Weight( NEEDS TO BE AVOIDED ) = %-6d\n", + node_name(np), weight); + } + } + } + } + + array_free(level_array); + array_free(w_array); + st_free_table(crit_table); + st_foreach_item(weight_table, stgen, &dummy1, &dummy){ + FREE(dummy); + } + st_free_table(weight_table); + + return table; +} diff --git a/sis/st/Makefile.am b/sis/st/Makefile.am new file mode 100644 index 0000000..b6177f3 --- /dev/null +++ b/sis/st/Makefile.am @@ -0,0 +1,11 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +if !SIS_COND_CUDD +noinst_LIBRARIES = libst.a +libst_a_SOURCES = st.c +pkginclude_HEADERS = st.h +dist_doc_DATA = st.doc +endif + +EXTRA_DIST = st.c st.h st.doc st_bench1.c diff --git a/sis/st/Makefile.in b/sis/st/Makefile.in new file mode 100644 index 0000000..70bedfe --- /dev/null +++ b/sis/st/Makefile.in @@ -0,0 +1,422 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libst_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/st +DIST_COMMON = $(am__dist_doc_DATA_DIST) $(am__pkginclude_HEADERS_DIST) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libst_a_AR = $(AR) $(ARFLAGS) +libst_a_LIBADD = +am__libst_a_SOURCES_DIST = st.c +@SIS_COND_CUDD_FALSE@am_libst_a_OBJECTS = st.$(OBJEXT) +libst_a_OBJECTS = $(am_libst_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libst_a_SOURCES) +DIST_SOURCES = $(am__libst_a_SOURCES_DIST) +am__dist_doc_DATA_DIST = st.doc +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +am__pkginclude_HEADERS_DIST = st.h +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +@SIS_COND_CUDD_FALSE@noinst_LIBRARIES = libst.a +@SIS_COND_CUDD_FALSE@libst_a_SOURCES = st.c +@SIS_COND_CUDD_FALSE@pkginclude_HEADERS = st.h +@SIS_COND_CUDD_FALSE@dist_doc_DATA = st.doc +EXTRA_DIST = st.c st.h st.doc st_bench1.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/st/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/st/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libst.a: $(libst_a_OBJECTS) $(libst_a_DEPENDENCIES) + -rm -f libst.a + $(libst_a_AR) libst.a $(libst_a_OBJECTS) $(libst_a_LIBADD) + $(RANLIB) libst.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/st/st.c b/sis/st/st.c new file mode 100644 index 0000000..eceb2b7 --- /dev/null +++ b/sis/st/st.c @@ -0,0 +1,509 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/st/st.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include <stdio.h> +#include "util.h" +#include "st.h" + +#define ST_NUMCMP(x,y) ((x) != (y)) +#define ST_NUMHASH(x,size) (ABS((int)x)%(size)) +#define ST_PTRHASH(x,size) ((int)((unsigned)(x)>>2)%size) +#define EQUAL(func, x, y) \ + ((((func) == st_numcmp) || ((func) == st_ptrcmp)) ?\ + (ST_NUMCMP((x),(y)) == 0) : ((*func)((x), (y)) == 0)) + + +#define do_hash(key, table)\ + ((table->hash == st_ptrhash) ? ST_PTRHASH((key),(table)->num_bins) :\ + (table->hash == st_numhash) ? ST_NUMHASH((key), (table)->num_bins) :\ + (*table->hash)((key), (table)->num_bins)) + +static rehash(); +int st_numhash(), st_ptrhash(), st_numcmp(), st_ptrcmp(); + +st_table *st_init_table_with_params(compare, hash, size, density, grow_factor, + reorder_flag) +int (*compare)(); +int (*hash)(); +int size; +int density; +double grow_factor; +int reorder_flag; +{ + int i; + st_table *new; + + new = ALLOC(st_table, 1); + new->compare = compare; + new->hash = hash; + new->num_entries = 0; + new->max_density = density; + new->grow_factor = grow_factor; + new->reorder_flag = reorder_flag; + if (size <= 0) { + size = 1; + } + new->num_bins = size; + new->bins = ALLOC(st_table_entry *, size); + for(i = 0; i < size; i++) { + new->bins[i] = 0; + } + return new; +} + +st_table *st_init_table(compare, hash) +int (*compare)(); +int (*hash)(); +{ + return st_init_table_with_params(compare, hash, ST_DEFAULT_INIT_TABLE_SIZE, + ST_DEFAULT_MAX_DENSITY, + ST_DEFAULT_GROW_FACTOR, + ST_DEFAULT_REORDER_FLAG); +} + +void +st_free_table(table) +st_table *table; +{ + register st_table_entry *ptr, *next; + int i; + + for(i = 0; i < table->num_bins ; i++) { + ptr = table->bins[i]; + while (ptr != NIL(st_table_entry)) { + next = ptr->next; + FREE(ptr); + ptr = next; + } + } + FREE(table->bins); + FREE(table); +} + +#define PTR_NOT_EQUAL(table, ptr, user_key)\ +(ptr != NIL(st_table_entry) && !EQUAL(table->compare, user_key, (ptr)->key)) + +#define FIND_ENTRY(table, hash_val, key, ptr, last) \ + (last) = &(table)->bins[hash_val];\ + (ptr) = *(last);\ + while (PTR_NOT_EQUAL((table), (ptr), (key))) {\ + (last) = &(ptr)->next; (ptr) = *(last);\ + }\ + if ((ptr) != NIL(st_table_entry) && (table)->reorder_flag) {\ + *(last) = (ptr)->next;\ + (ptr)->next = (table)->bins[hash_val];\ + (table)->bins[hash_val] = (ptr);\ + } + +st_lookup(table, key, value) +st_table *table; +register char *key; +char **value; +{ + int hash_val; + register st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr, last); + + if (ptr == NIL(st_table_entry)) { + return 0; + } else { + if (value != NIL(char *)) *value = ptr->record; + return 1; + } +} + +st_lookup_int(table, key, value) +st_table *table; +register char *key; +int *value; +{ + int hash_val; + register st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr, last); + + if (ptr == NIL(st_table_entry)) { + return 0; + } else { + if (value != NIL(int)) { + *value = (int) ptr->record; + } + return 1; + } +} + +#define ADD_DIRECT(table, key, value, hash_val, new)\ +{\ + if (table->num_entries/table->num_bins >= table->max_density) {\ + rehash(table);\ + hash_val = do_hash(key,table);\ + }\ + \ + new = ALLOC(st_table_entry, 1);\ + \ + new->key = key;\ + new->record = value;\ + new->next = table->bins[hash_val];\ + table->bins[hash_val] = new;\ + table->num_entries++;\ +} + +st_insert(table, key, value) +register st_table *table; +register char *key; +char *value; +{ + int hash_val; + st_table_entry *new; + register st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr, last); + + if (ptr == NIL(st_table_entry)) { + ADD_DIRECT(table,key,value,hash_val,new); + return 0; + } else { + ptr->record = value; + return 1; + } +} + +st_add_direct(table, key, value) +st_table *table; +char *key; +char *value; +{ + int hash_val; + st_table_entry *new; + + hash_val = do_hash(key, table); + ADD_DIRECT(table, key, value, hash_val, new); +} + +st_find_or_add(table, key, slot) +st_table *table; +char *key; +char ***slot; +{ + int hash_val; + st_table_entry *new, *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr, last); + + if (ptr == NIL(st_table_entry)) { + ADD_DIRECT(table, key, (char *)0, hash_val, new) + if (slot != NIL(char **)) *slot = &new->record; + return 0; + } else { + if (slot != NIL(char **)) *slot = &ptr->record; + return 1; + } +} + +st_find(table, key, slot) +st_table *table; +char *key; +char ***slot; +{ + int hash_val; + st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr, last); + + if (ptr == NIL(st_table_entry)) { + return 0; + } else { + if (slot != NIL(char **)) *slot = &ptr->record; + return 1; + } +} + +static rehash(table) +register st_table *table; +{ + register st_table_entry *ptr, *next, **old_bins = table->bins; + int i, old_num_bins = table->num_bins, hash_val; + + table->num_bins = table->grow_factor*old_num_bins; + + if (table->num_bins%2 == 0) { + table->num_bins += 1; + } + + table->num_entries = 0; + table->bins = ALLOC(st_table_entry *, table->num_bins); + for(i = 0; i < table->num_bins; i++) { + table->bins[i] = 0; + } + + for(i = 0; i < old_num_bins ; i++) { + ptr = old_bins[i]; + while (ptr != NIL(st_table_entry)) { + next = ptr->next; + hash_val = do_hash(ptr->key, table); + ptr->next = table->bins[hash_val]; + table->bins[hash_val] = ptr; + table->num_entries++; + ptr = next; + } + } + FREE(old_bins); +} + +st_table *st_copy(old_table) +st_table *old_table; +{ + st_table *new_table; + st_table_entry *ptr, *new; + int i, num_bins = old_table->num_bins; + + new_table = ALLOC(st_table, 1); + if (new_table == NIL(st_table)) { + return NIL(st_table); + } + + *new_table = *old_table; + new_table->bins = ALLOC(st_table_entry *, num_bins); + + if (new_table->bins == NIL(st_table_entry *)) { + FREE(new_table); + return NIL(st_table); + } + + for(i = 0; i < num_bins ; i++) { + new_table->bins[i] = NIL(st_table_entry); + ptr = old_table->bins[i]; + while (ptr != NIL(st_table_entry)) { + new = ALLOC(st_table_entry, 1); + if (new == NIL(st_table_entry)) { + FREE(new_table->bins); + FREE(new_table); + return NIL(st_table); + } + *new = *ptr; + new->next = new_table->bins[i]; + new_table->bins[i] = new; + ptr = ptr->next; + } + } + return new_table; +} + +st_delete(table, keyp, value) +register st_table *table; +register char **keyp; +char **value; +{ + int hash_val; + char *key = *keyp; + register st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr ,last); + + if (ptr == NIL(st_table_entry)) { + return 0; + } + + *last = ptr->next; + if (value != NIL(char *)) *value = ptr->record; + *keyp = ptr->key; + FREE(ptr); + table->num_entries--; + return 1; +} + +st_delete_int(table, keyp, value) +register st_table *table; +register int *keyp; +char **value; +{ + int hash_val; + char *key = (char *) *keyp; + register st_table_entry *ptr, **last; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, hash_val, key, ptr ,last); + + if (ptr == NIL(st_table_entry)) { + return 0; + } + + *last = ptr->next; + if (value != NIL(char *)) *value = ptr->record; + *keyp = (int) ptr->key; + FREE(ptr); + table->num_entries--; + return 1; +} + +int +st_foreach(table, func, arg) +st_table *table; +enum st_retval (*func)(); +char *arg; +{ + st_table_entry *ptr, **last; + enum st_retval retval; + int i; + + for(i = 0; i < table->num_bins; i++) { + last = &table->bins[i]; ptr = *last; + while (ptr != NIL(st_table_entry)) { + retval = (*func)(ptr->key, ptr->record, arg); + switch (retval) { + case ST_CONTINUE: + last = &ptr->next; ptr = *last; + break; + case ST_STOP: + return 0; + case ST_DELETE: + *last = ptr->next; + table->num_entries--; /* cstevens@ic */ + FREE(ptr); + ptr = *last; + } + } + } + return 1; +} + +st_strhash(string, modulus) +register char *string; +int modulus; +{ + register int val = 0; + register int c; + + while ((c = *string++) != '\0') { + val = val*997 + c; + } + + return ((val < 0) ? -val : val)%modulus; +} + +st_numhash(x, size) +char *x; +int size; +{ + return ST_NUMHASH(x, size); +} + +st_ptrhash(x, size) +char *x; +int size; +{ + return ST_PTRHASH(x, size); +} + +st_numcmp(x, y) +char *x; +char *y; +{ + return ST_NUMCMP(x, y); +} + +st_ptrcmp(x, y) +char *x; +char *y; +{ + return ST_NUMCMP(x, y); +} + +st_generator * +st_init_gen(table) +st_table *table; +{ + st_generator *gen; + + gen = ALLOC(st_generator, 1); + gen->table = table; + gen->entry = NIL(st_table_entry); + gen->index = 0; + return gen; +} + + +int +st_gen(gen, key_p, value_p) +st_generator *gen; +char **key_p; +char **value_p; +{ + register int i; + + if (gen->entry == NIL(st_table_entry)) { + /* try to find next entry */ + for(i = gen->index; i < gen->table->num_bins; i++) { + if (gen->table->bins[i] != NIL(st_table_entry)) { + gen->index = i+1; + gen->entry = gen->table->bins[i]; + break; + } + } + if (gen->entry == NIL(st_table_entry)) { + return 0; /* that's all folks ! */ + } + } + *key_p = gen->entry->key; + if (value_p != 0) *value_p = gen->entry->record; + gen->entry = gen->entry->next; + return 1; +} + + +int +st_gen_int(gen, key_p, value_p) +st_generator *gen; +char **key_p; +int *value_p; +{ + register int i; + + if (gen->entry == NIL(st_table_entry)) { + /* try to find next entry */ + for(i = gen->index; i < gen->table->num_bins; i++) { + if (gen->table->bins[i] != NIL(st_table_entry)) { + gen->index = i+1; + gen->entry = gen->table->bins[i]; + break; + } + } + if (gen->entry == NIL(st_table_entry)) { + return 0; /* that's all folks ! */ + } + } + *key_p = gen->entry->key; + if (value_p != NIL(int)) { + *value_p = (int) gen->entry->record; + } + gen->entry = gen->entry->next; + return 1; +} + + +void +st_free_gen(gen) +st_generator *gen; +{ + FREE(gen); +} diff --git a/sis/st/st.doc b/sis/st/st.doc new file mode 100644 index 0000000..759b4cf --- /dev/null +++ b/sis/st/st.doc @@ -0,0 +1,293 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/st/st.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +Basic functions: + +st_table *st_init_table(compare_fn, hash_fn) +int (*compare_fn); +int (*hash_fn); + + Create and initialize a table with the comparison function compare_fn and + hash function hash_fn. compare_fn is + + int compare_fn(char *key1, char *key2) + /* + * returns <,=,> 0 depending on whether + * key1 <,=,> key2 by some measure + */ + + and hash_fn is + + int hash_fn(char *key, int modulus) + /* + * returns a integer between 0 and modulus-1 + * such that if compare_fn(key1,key2) == 0 then + * hash_fn(key1) == hash_fn(key2) + */ + + There are five predefined hash and comparison functions in st. + For keys as numbers: + st_numhash(key, modulus) { return (unsigned int) key % modulus; } + st_numcmp(x,y) { return (int) x - (int) y; } + For keys as pointers: + st_ptrhash(key, modulus) { return ((unsigned int) key/4) % modulus } + st_ptrcmp(x,y) { return (int) x - (int) y; } + For keys as strings: + st_strhash(x,y) - a reasonable hashing function for strings + strcmp(x,y) - the standard library function + + It is recommended to use these particular functions if they fit your + needs, since st will recognize certain of them and run more quickly + because of it. + +st_free_table(table) +st_table *table; + + Any internal storage associated with table is freed. It is the user's + responsibility to free any storage associated with the pointers he + placed in the table (by perhaps using st_foreach). + +st_insert(table, key, value) +st_table *table; +char *key; +char *value; + + Insert value in table under the key 'key'. Returns 1 if there was + an entry already under the key, 0 otherewise. In either case the new + value is added. + +st_lookup(table, key, value_ptr) +st_table *table; +char *key; +char **value_ptr; + + Lookup up `key' in `table'. If an entry is found, 1 is returned + and if `value_ptr' is not nil, the variable it points to is set to + associated value. If an entry is not found, 0 is return and + value_ptr is unchanged. + +st_lookup_int(table, key, int_ptr) +st_table *table; +char *key; +int *value_ptr; + + Lookup up `key' in `table'. If an entry is found, 1 is returned + and if `int_ptr' is not nil, the variable it points to is set to + associated integer value. If an entry is not found, 0 is return and + int_ptr is unchanged. + +st_is_member(table, key) +st_table *table; +char *key; + + Returns 1 if there is an entry under `key' in `table', 0 + otherwise. + +st_delete(table, key_ptr, entry_ptr) +st_table *table; +char **key_ptr; +char **value_ptr; + + Delete the entry with the key pointed to by `key_ptr'. If the + entry is found, 1 is returned and `key_ptr' is set to the actual key + and `entry_ptr' is set to the corresponding entry (This allows the + freeing of the associated storage). If the entry is not found, then 0 + is returned and nothing is changed. + +st_delete_int(table, key_ptr, entry_ptr) +st_table *table; +int *key_ptr; +char **value_ptr; + + Delete the entry with the key pointed to by `key_ptr'. `key_ptr' should + be specifically a pointer to an integer. If the entry is found, 1 is + returned and `key_ptr' is set to the actual key and `entry_ptr' is set to + the corresponding entry (This allows the freeing of the associated storage). + If the entry is not found, then 0 is returned and nothing is changed. + +int st_foreach(table, func, arg) +st_table table; +enum st_retval (*func)(); +char *arg; + + For each (key, value) record in `table', st_foreach call func + with the arguments + + (*func)(key, value, arg) + + If func returns ST_CONTINUE, st_foreach continues processing entries. + If func returns ST_STOP, st_foreach stops processing and returns + immediately. If func returns ST_DELETE, then the entry is + deleted from the symbol table and st_foreach continues. In the + case of ST_DELETE, it is func's responsibility to free the key + and value, if necessary. + + The routine returns 1 if all items in the table were generated and + 0 if the generation sequence was aborted using ST_STOP. The order + in which the records are visited will be seemingly random. + +st_generator *st_init_gen(table) +st_table *table; + + Returns a generator handle which when used with st_gen() will + progressively return each (key, value) record in `table'. + +int st_gen(gen, key_p, value_p) +st_generator *gen; +char **key_p; +char **value_p; + + Given a generator returned by st_init_gen(), this routine returns + the next (key, value) pair in the generation sequence. The + pointer `value_p' can be zero which means no value will be returned. + When there are no more items in the generation sequence, the routine + returns 0. + + While using a generation sequence, deleting any (key, value) + pair other than the one just generated may cause a fatal error + when st_gen() is called later in the sequence and is therefore + not recommended. + +int st_gen_int(gen, key_p, value_p) +st_generator *gen; +char **key_p; +int *value_p; + + Given a generator returned by st_init_gen(), this routine returns + the next (key, value) pair in the generation sequence. `value' must + be a pointer to an integer. The pointer `value_p' can be zero which + means no value will be returned. When there are no more items in the + generation sequence, the routine returns 0. + +void st_free_gen(gen) +st_generator *gen; + + After generating all items in a generation sequence, this + routine must be called to reclaim the resources associated + with `gen'. + +st_foreach_item(table, gen, key_p, value_p) +st_table *table; +st_generator *gen; +char **key_p; +char **value_p; + + An iteration macro which loops over all the entries in `table', setting + `key_p' to point to the key and `value_p' to the associated value (if it + is not nil). `gen' is a generator variable used internally. Sample usage: + + char *key, *value; + st_generator *gen; + + st_foreach_item(table, gen, &key, &value) { + process_item(value); + } + +st_foreach_item_int(table, gen, key_p, value_p) +st_table *table; +st_generator *gen; +char **key_p; +int *value_p; + + An iteration macro which loops over all the entries in `table', setting + `key_p' to point to the key and `value_p' to the associated value (if it + is not nil). `value_p' is assumed to be a pointer to an integer. `gen' + is a generator variable used internally. Sample usage: + + char *key; + int *value; + st_generator *gen; + + st_foreach_item_int(table, gen, &key, &value) { + process_item(value); + } + +st_count(table) +st_table table; + + return the number of entries in the table `table'. + +Fancier functions: + +st_table *st_init_table_with_params(compare, hash, size, density, grow_factor, + reorder_flag) +int (*compare)(); +int (*hash)(); +int size; +int density; +double grow_factor; +int reorder_flag; + + The full blown table initializer. compare and hash are the same + as in st_init_table. density is the largest the average number of + entries per hash bin there should be before the table is grown. + grow_factor is the factor the table is grown by when it becomes too + full. size is the initial number of bins to be allocated for the hash + table. If reorder_flag is non-zero, then everytime an entry is found, + it is moved to the top of the chain. + + st_init_table(compare, hash) is equivelent to + st_init_table_with_params(compare, hash, ST_DEFAULT_INIT_TABLE_SIZE, + ST_DEFAULT_MAX_DENSITY, + ST_DEFAULT_GROW_FACTOR, + ST_DEFAULT_REORDER_FLAG); + +st_find_or_add(table, key, slot_ptr) +st_table *table; +char *key; +char ***slot_ptr; + + Lookup `key' in `table'. If not found, create an entry.In either case + set slot to point to the field in the entry where the value is stored. + The value associated with `key' may then be changed by accessing + directly through slot. Returns 1 if an entry already existed, 0 + otherwise. As an example: + + char **slot; + char *key; + char *value = (char *) item_ptr /* ptr to a malloc'd structure */ + + if (st_find_or_add(table, key, &slot)) { + FREE(*slot); /* free the old value of the record */ + } + *slot = value; /* attach the new value to the record */ + + This replaces the equivelent code: + + if (st_lookup(table, key, &ovalue)) { + FREE(ovalue); + } + st_insert(table, key, value); + + +st_find(table, key, slot_ptr) +st_table *table; +char *key; +char ***slot_ptr; + + Like st_find_or_add, but does not create an entry if one is not found. + +st_add_direct(table, key, value) +st_table *table; +char *key; +char *value; + + Place 'value' in 'table' under the key 'key'. This is done + without checking if 'key' is in 'table' already. This should + only be used if you are sure there is not already an entry for + 'key', since it is undefined which entry you would later get from + st_lookup or st_find_or_add. + +st_table * +st_copy(old_table) +st_table *old_table; + + Return a copy of old_table and all its members. (st_table *) 0 is + returned if there was insufficient memory to do the copy. + diff --git a/sis/st/st.h b/sis/st/st.h new file mode 100644 index 0000000..d675372 --- /dev/null +++ b/sis/st/st.h @@ -0,0 +1,87 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/st/st.h,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2005/03/08 03:50:52 $ + * + */ +/* LINTLIBRARY */ + +/* $Header: /users/pchong/CVS/sis/sis/st/st.h,v 1.2 2005/03/08 03:50:52 pchong Exp $ */ + +#ifndef ST_INCLUDED +#define ST_INCLUDED + +typedef struct st_table_entry st_table_entry; +struct st_table_entry { + char *key; + char *record; + st_table_entry *next; +}; + +typedef struct st_table st_table; +struct st_table { + int (*compare)(); + int (*hash)(); + int num_bins; + int num_entries; + int max_density; + int reorder_flag; + double grow_factor; + st_table_entry **bins; +}; + +typedef struct st_generator st_generator; +struct st_generator { + st_table *table; + st_table_entry *entry; + int index; +}; + +#define st_is_member(table,key) st_lookup(table,key,(char **) 0) +#define st_count(table) ((table)->num_entries) + +enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE}; + +typedef enum st_retval (*ST_PFSR)(); +typedef int (*ST_PFI)(); +typedef int (*ST_PFICPI)(); + +EXTERN int st_delete ARGS((st_table *, char **, char **)); +EXTERN int st_delete_int ARGS((st_table *, int *, char **)); +EXTERN int st_insert ARGS((st_table *, char *, char *)); +EXTERN int st_foreach ARGS((st_table *, ST_PFSR, char *)); +EXTERN int st_gen ARGS((st_generator *, char **, char **)); +EXTERN int st_gen_int ARGS((st_generator *, char **, int *)); +EXTERN int st_lookup ARGS((st_table *, char *, char **)); +EXTERN int st_lookup_int ARGS((st_table *, char *, int *)); +EXTERN int st_find_or_add ARGS((st_table *, char *, char ***)); +EXTERN int st_find ARGS((st_table *, char *, char ***)); +EXTERN int st_add_direct ARGS((st_table *, char *, char *)); +EXTERN int st_strhash ARGS((char *, int)); +EXTERN int st_numhash ARGS((char *, int)); +EXTERN int st_ptrhash ARGS((char *, int)); +EXTERN int st_numcmp ARGS((char *, char *)); +EXTERN int st_ptrcmp ARGS((char *, char *)); +EXTERN st_table *st_init_table ARGS((ST_PFI, ST_PFI)); +EXTERN st_table *st_init_table_with_params ARGS((ST_PFI, ST_PFI, int, int, double, int)); +EXTERN st_table *st_copy ARGS((st_table *)); +EXTERN st_generator *st_init_gen ARGS((st_table *)); +EXTERN void st_free_table ARGS((st_table *)); +EXTERN void st_free_gen ARGS((st_generator *)); + + +#define ST_DEFAULT_MAX_DENSITY 5 +#define ST_DEFAULT_INIT_TABLE_SIZE 11 +#define ST_DEFAULT_GROW_FACTOR 2.0 +#define ST_DEFAULT_REORDER_FLAG 0 + +#define st_foreach_item(table, gen, key, value) \ + for(gen=st_init_gen(table); st_gen(gen,key,value) || (st_free_gen(gen),0);) + +#define st_foreach_item_int(table, gen, key, value) \ + for(gen=st_init_gen(table); st_gen_int(gen,key,value) || (st_free_gen(gen),0);) + +#endif /* ST_INCLUDED */ diff --git a/sis/st/st_bench1.c b/sis/st/st_bench1.c new file mode 100644 index 0000000..3c8b5a2 --- /dev/null +++ b/sis/st/st_bench1.c @@ -0,0 +1,74 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/st/st_bench1.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:46 $ + * + */ +#include <stdio.h> +#include "array.h" +#include "st.h" +#include "util.h" + +#define MAX_WORD 1024 + +extern long random(); + +/* ARGSUSED */ +main(argc, argv) +char *argv; +{ + array_t *words; + st_table *table; + char word[MAX_WORD], *tempi, *tempj; + register int i, j; + long time; +#ifdef TEST + st_generator *gen; + char *key; +#endif + + /* read the words */ + words = array_alloc(char *, 1000); + while (gets(word) != NIL(char)) { + array_insert_last(char *, words, util_strsav(word)); +#ifdef TEST + if (array_n(words) == 25) break; +#endif + } + + /* scramble them */ + for(i = array_n(words)-1; i >= 1; i--) { + j = random() % i; + tempi = array_fetch(char *, words, i); + tempj = array_fetch(char *, words, j); + array_insert(char *, words, i, tempj); + array_insert(char *, words, j, tempi); + } + +#ifdef TEST + (void) printf("Initial data is\n"); + for(i = array_n(words)-1; i >= 0; i--) { + (void) printf("%s\n", array_fetch(char *, words, i)); + } +#endif + + /* time putting them into an st tree */ + time = util_cpu_time(); + table = st_init_table(strcmp, st_strhash); + for(i = array_n(words)-1; i >= 0; i--) { + (void) st_insert(table, array_fetch(char *, words, i), NIL(char)); + } + (void) printf("Elapsed time for insert of %d objects was %s\n", + array_n(words), util_print_time(util_cpu_time() - time)); + +#ifdef TEST + (void) printf("st data is\n"); + st_foreach_item(table, gen, &key, NIL(char *)) { + (void) printf("%s\n", key); + } +#endif + return 0; +} diff --git a/sis/stg/Makefile.am b/sis/stg/Makefile.am new file mode 100644 index 0000000..2c360d9 --- /dev/null +++ b/sis/stg/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libstg.a +libstg_a_SOURCES = com_stg.c enumerate.c level_c.c senum_main.c stg.c \ + stg_sc_sim.c stg_util.c stg_int.h +pkginclude_HEADERS = stg.h +dist_doc_DATA = stg.doc diff --git a/sis/stg/Makefile.in b/sis/stg/Makefile.in new file mode 100644 index 0000000..01b235e --- /dev/null +++ b/sis/stg/Makefile.in @@ -0,0 +1,422 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libstg_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/stg +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libstg_a_AR = $(AR) $(ARFLAGS) +libstg_a_LIBADD = +am_libstg_a_OBJECTS = com_stg.$(OBJEXT) enumerate.$(OBJEXT) \ + level_c.$(OBJEXT) senum_main.$(OBJEXT) stg.$(OBJEXT) \ + stg_sc_sim.$(OBJEXT) stg_util.$(OBJEXT) +libstg_a_OBJECTS = $(am_libstg_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libstg_a_SOURCES) +DIST_SOURCES = $(libstg_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libstg.a +libstg_a_SOURCES = com_stg.c enumerate.c level_c.c senum_main.c stg.c \ + stg_sc_sim.c stg_util.c stg_int.h + +pkginclude_HEADERS = stg.h +dist_doc_DATA = stg.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/stg/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/stg/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libstg.a: $(libstg_a_OBJECTS) $(libstg_a_DEPENDENCIES) + -rm -f libstg.a + $(libstg_a_AR) libstg.a $(libstg_a_OBJECTS) $(libstg_a_LIBADD) + $(RANLIB) libstg.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/stg/com_stg.c b/sis/stg/com_stg.c new file mode 100644 index 0000000..e2f43c1 --- /dev/null +++ b/sis/stg/com_stg.c @@ -0,0 +1,893 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/stg/com_stg.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "stg_int.h" + +network_t *stg_to_network(); + +static void stg_network_add_clock(); +static void stg_network_connect_clock(); +static int write_encoded_espresso_format(); + +#define STG_LATCH_LIMIT 16 +#define STG_CHECK_EDGE_LIMIT 500 + +/*ARGSUSED*/ +static int +com_stg_extract(network,argc,argv) +network_t **network; +int argc; +char **argv; +{ + int check_containment = FALSE; + int override = 0; + int opt = 0; + long msec; + int c; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "aec")) != EOF) { + switch(c) { + case 'c': + check_containment = TRUE; + break; + case 'a': + opt = 1; + break; + case 'e': + override = 1; + break; + default: + (void) fprintf(siserr,"Usage: %s [-a] [-e] [-c]\n",argv[0]); + (void) fprintf(siserr, + "\t-a: find for all possible start states\n"); + (void) fprintf(siserr, "\t (only if there are no more than %d latches)\n", STG_LATCH_LIMIT); + (void) fprintf(siserr, + "\t-e: extract even if the number of latches exceeds %d\n", STG_LATCH_LIMIT); + (void) fprintf(siserr, + "\t-c: always check that the network covers the STG\n"); + return 1; + } + } + if (network_num_latch(*network) == 0) { + (void) fprintf(siserr, "Network has no latches\n"); + return 1; + } + if (opt && (network_num_latch(*network) > STG_LATCH_LIMIT)){ + (void) fprintf(siserr, "Network has too many latches,"); + (void) fprintf(siserr, "Cannot use all states as initial states\n"); + return 1; + } + if ((network_num_latch(*network) > STG_LATCH_LIMIT) && (!override)) { + (void) fprintf(siserr, "Network has too many latches,"); + (void) fprintf(siserr, " STG may take a long time to extract.\n"); + (void) fprintf(siserr, "Use stg_extract -e to override.\n"); + return 1; + } + + msec = util_cpu_time(); + if (stg_extract(*network,opt) != NIL(graph_t)) { + (void) fprintf(sisout,"Total number of states = %d\n",total_no_of_states); + (void) fprintf(sisout,"Total number of edges = %d\n",total_no_of_edges); + (void) fprintf(sisout,"Total time = %g\n", + (double) (util_cpu_time() - msec) / 1000); + } + + if (!check_containment && total_no_of_edges > STG_CHECK_EDGE_LIMIT){ + (void)fprintf(sisout, "NOTE: There are more than %d transitions\n", STG_CHECK_EDGE_LIMIT); + (void)fprintf(sisout, "\tSkipping the check that network covers the STG\n"); + (void)fprintf(sisout, "\tUse the -c option to force this check\n"); + } else if (!network_stg_check(*network)) { + return 1; + } + return(0); +} + + +static int +com_stg_state_assign(network,argc,argv) +network_t **network; +int argc; +char **argv; +{ + FILE *to, *from; + char command[1024]; + char buffer[1024]; + char *infile; + char *outfile; + int i, c, status; + network_t *n; + network_t *new; + int help = 0; + char *error; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "x")) != EOF) { + switch (c) { + case 'x': + (void) fprintf(siserr, + "usage: state_assign program_name options\n"); + return 1; + } + } + error_init(); + if (network_stg(*network) == NIL(graph_t)) { + (void) fprintf(siserr, "There is no stg\n"); + return 1; + } + + infile = util_tempnam(NIL(char), "SIS"); + outfile = util_tempnam(NIL(char), "SIS"); + + if (argc == 1) { + (void) sprintf(command, "nova < %s > %s", infile, outfile); + (void) fprintf(sisout, "Running nova, written by Tiziano Villa,"); + (void) fprintf(sisout, " UC Berkeley\n"); + } else { + buffer[0] = '\0'; + if (!strcmp(argv[1], "nova")) { + (void) fprintf(sisout, "Running nova, written by Tiziano Villa,"); + (void) fprintf(sisout, " UC Berkeley\n"); + } else if (!strcmp(argv[1], "jedi")) { + (void) fprintf(sisout, "Running jedi, written by Bill Lin,"); + (void) fprintf(sisout, " UC Berkeley\n"); + } + for (i = 1; i < argc; i++) { + (void) strcat(buffer, argv[i]); + (void) strcat(buffer, " "); + if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) { + help = 1; + } + } + (void) sprintf(command, "%s < %s > %s", buffer, infile, outfile); + } + + if ((to = fopen(infile, "w")) == NULL) { + (void) fprintf(siserr, "Error: cannot open temporary file - %s\n", infile); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 1; + } + + if (!help && !write_kiss(to, network_stg(*network))) { + (void) fprintf(siserr, "Error in write_kiss\n"); + (void) fclose(to); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 1; + } + (void) fclose(to); + + status = system(command); + + if (status && !help) { + (void) fprintf(siserr, "state assignment program returned non-zero exit status\n%s\n", command); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 1; + } + + if (help) { + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 0; + } + + if ((from = fopen(outfile, "r")) == NULL) { + (void) fprintf(siserr, "Error: cannot open output file - %s\n", outfile); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 1; + } + + /* read_blif requires that the global variable read_filename be set */ + read_register_filename(outfile); + if (!read_blif(from, &n)) { + (void) fprintf(siserr, "Error in state assignment program output:\n"); + (void) fprintf(siserr, "read_blif: %s\n", error_string()); + read_register_filename(NIL(char)); + network_free(n); + (void) fclose(from); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 1; + } + + (void) fclose(from); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + + error = error_string(); + if (error[0] != '\0') { + (void) fprintf(siserr, "%s", error); + } + + if (network_num_pi(n) == 0 || network_num_po(n) == 0) { + new = stg_to_network(network_stg(n), 1); + if (new == NIL(network_t)) { + return 1; + } + network_set_stg(n, (graph_t *) NULL); + network_free(n); + n = new; + } + stg_set_network_pipo_names(n, network_stg(*network)); + /* Add the clocks and set the latch type and control */ + stg_network_add_clock(n, network_stg(*network)); + stg_network_connect_clock(n, network_stg(*network)); + /* The clock info has to be stored with the STG as well */ + stg_copy_clock_data(network_stg(*network), network_stg(n)); + + network_set_name(n, network_name(*network)); + network_free(*network); + *network = n; + return 0; +} + + +static int +com_stg_state_minimize(network,argc,argv) +network_t **network; +int argc; +char **argv; +{ + FILE *to, *from; + int i, c, status; + int num_states; + char command[1024]; + char buffer[1024]; + char *infile; + char *outfile; + graph_t *g; + network_t *new_network; + int help = 0; + char *error; + + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "x")) != EOF) { + switch (c) { + case 'x': + (void) fprintf(siserr, + "usage: state_mininimize program_name options\n"); + return 1; + } + } + error_init(); + if (network_stg(*network) == NIL(graph_t)) { + (void) fprintf(siserr, "There is no stg\n"); + return 1; + } + + num_states = stg_get_num_states(network_stg(*network)); + infile = util_tempnam(NIL(char), "SIS"); + outfile = util_tempnam(NIL(char), "SIS"); + + if (argc == 1) { + (void) sprintf(command, "stamina < %s > %s", infile, outfile); + (void) fprintf(sisout, "Running stamina, written by June Rho,"); + (void) fprintf(sisout, " University of Colorado at Boulder\n"); + } else { + buffer[0] = '\0'; + if (!strcmp(argv[1], "stamina")) { + (void) fprintf(sisout, "Running stamina, written by June Rho,"); + (void) fprintf(sisout, " University of Colorado at Boulder\n"); + } else if (!strcmp(argv[1], "freduce")) { + (void) fprintf(sisout, "Running freduce, written by Bill Lin,"); + (void) fprintf(sisout, " UC Berkeley\n"); + } else if (!strcmp(argv[1], "sred")) { + (void) fprintf(sisout, "Running sred, written by Tiziano Villa,"); + (void) fprintf(sisout, " UC Berkeley\n"); + } + for (i = 1; i < argc; i++) { + (void) strcat(buffer, argv[i]); + (void) strcat(buffer, " "); + if (!strcmp(argv[i], "-h")) { + help = 1; + } + } + (void) sprintf(command, "%s < %s > %s", buffer, infile, outfile); + } + + if ((to = fopen(infile, "w")) == NULL) { + (void) fprintf(siserr, "Error: cannot open temporary file - %s\n", infile); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 1; + } + + if (!help && !write_kiss(to, network_stg(*network))) { + (void) fprintf(siserr, "Error in write_kiss\n"); + (void) fclose(to); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 1; + } + (void) fclose(to); + + status = system(command); + + if (status && !help) { + (void) fprintf(siserr, "state minimization program returned non-zero exit status\n%s\n", command); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 1; + } + + if (help) { + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 0; + } + + if ((from = fopen(outfile, "r")) == NULL) { + (void) fprintf(siserr, "Error: cannot open output file - %s\n", outfile); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 1; + } + + if (!read_kiss(from, &g)) { + (void) fprintf(siserr, "Error in state minimization program output:\n"); + (void) fprintf(siserr, "read_kiss: %s\n", error_string()); + stg_free(g); + (void) fclose(from); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return 1; + } + + (void) fclose(from); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + + error = error_string(); + if (error[0] != '\0') { + (void) fprintf(siserr, "%s", error); + } + /* + * Retain the names of the inputs and outputs of the STG + * "stg_copy_names()" also retains the clocking information and edge index + */ + stg_copy_names(network_stg(*network), g); + + /* The clock info has to be stored with the STG as well */ + stg_copy_clock_data(network_stg(*network), g); + + new_network = network_alloc(); + network_set_name(new_network, network_name(*network)); + network_free(*network); + network_set_stg(new_network, g); + stg_set_network_pipo_names(new_network, g); + stg_network_add_clock(new_network, g); + stg_network_connect_clock(new_network, g); + *network = new_network; + (void) fprintf(sisout, "Number of states in original machine : %d\n", + num_states); + (void) fprintf(sisout, "Number of states in minimized machine : %d\n", + stg_get_num_states(g)); + return 0; +} + + +/*ARGSUSED*/ +static int +com_stg_cover(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + if (!network_stg_check(*network)) { + return 1; + } + (void) fprintf(sisout, "STG covers the network\n"); + return 0; +} + + +/*ARGSUSED*/ +static int +com_one_hot(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + graph_t *stg; + int ns, i; + char *code; + lsGen gen; + vertex_t *s; + network_t *new; + + stg = network_stg(*network); + if (stg == NIL(graph_t)) { + (void) fprintf(sisout, "No stg present\n"); + return 0; + } + ns = stg_get_num_states(stg); + code = ALLOC(char, ns+1); + for (i = 0; i < ns; i++) { + code[i] = '0'; + } + code[ns] = '\0'; + code[0] = '1'; + i = 1; + stg_foreach_state(stg, gen, s) { + stg_set_state_encoding(s, code); + if (i < ns) { + code[i] = '1'; + code[i-1] = '0'; + } + i++; + } + FREE(code); + new = stg_to_network(stg, 0); + network_set_name(new, network_name(*network)); + stg_set_network_pipo_names(new, network_stg(*network)); + + /* Add the clocks and set the latch type and control */ + stg_network_add_clock(new, stg); + stg_network_connect_clock(new, stg); + + network_set_stg(*network, NIL(graph_t)); + network_free(*network); + *network = new; + return 0; +} + + +#ifdef STG_DEBUG +static int +stg_test(network) +network_t **network; +{ + graph_t *stg; + network_t *net = *network; + static char *vect = "101101001110010"; + vertex_t *state; + long msec,new; + char buf[100]; + static int states = 0; + + msec = util_cpu_time(); + (void) stg_extract(net,0); + new = util_cpu_time(); + (void) fprintf(sisout,"extraction: %g\n",(double) (new - msec) / 1000); + msec = new; + stg = network_stg(net); + stg_check(stg); + new = util_cpu_time(); + (void) fprintf(sisout,"checking: %g\n",(double) (new - msec) / 1000); + (void)fprintf(sisout,"The extracted STG is \n"); + stg_dump_graph(sisout, stg); + new = util_cpu_time(); + msec = new; + stg_sim(stg,vect); + stg_sim(stg,vect); + stg_sim(stg,vect); + stg_sim(stg,vect); + new = util_cpu_time(); + (void) fprintf(sisout,"4 simulations: %g\n",(double) (new - msec) / 1000); + msec = new; + (void) fprintf(sisout,"%s %s\n",stg_get_state_name(stg_get_start(stg)), + stg_get_state_name(stg_get_current(stg))); + if (stg_get_num_inputs(stg) == 4 && (stg_get_num_outputs(stg) == 4)) { + (void) sprintf(buf, "st%d", states++); + state = stg_create_state(stg, buf, NIL(char)); + (void) stg_create_transition(state,stg_get_current(stg),"01-1","0100"); + (void) write_kiss(sisout,stg); + (void) putc('\n',sisout); + } + stg_reset(stg); + (void) fprintf(sisout,"%s %s\n",stg_get_state_name(stg_get_start(stg)), + stg_get_state_name(stg_get_current(stg))); + return(0); +} +#endif /* STG_DEBUG */ + +static int +com_stg_to_network(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + network_t *new; + int c; + int option; + + option = 1; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "e:")) != EOF) { + switch (c) { + case 'e': + option = atoi(util_optarg); + if (option < 0 || option > 2) { + goto usage; + } + break; + default: + goto usage; + } + } + + new = stg_to_network(network_stg(*network), option); + if (new == NIL(network_t)) { + return 1; + } + /* Add the clocks and set the latch type and control */ + stg_network_add_clock(new, network_stg(*network)); + stg_network_connect_clock(new, network_stg(*network)); + stg_set_network_pipo_names(new, network_stg(*network)); + + network_set_stg(*network, (graph_t *) NULL); + + /* The network was given a random name - assign in to the name */ + /* of the original network. */ + network_set_name(new, network_name(*network)); + network_free(*network); + *network = new; + return 0; + +usage: + (void) fprintf(siserr, "usage: stg_to_network [-e option]\n"); + return 1; +} + +network_t * +stg_to_network(stg, option) +graph_t *stg; +int option; +{ + FILE *to, *from; + char command[1024]; + char *infile; + char *outfile; + int status; + network_t *network; + char *error; + latch_t *l; + node_t *pi, *po; + int latches, n, c; + lsGen genpi, genpo; + char *start; + int stg_single; + + if (stg == (graph_t *) NULL) { + (void) fprintf(siserr, "stg_to_network: no stg specified\n"); + return NIL(network_t); + } + + start = stg_get_state_encoding(stg_get_start(stg)); + if (start == NIL(char)) { + (void) fprintf(siserr, "error: FSM has no encoding\n"); + return NIL(network_t); + } + + infile = util_tempnam(NIL(char), "SIS"); + outfile = util_tempnam(NIL(char), "SIS"); + + switch(option) { + case 0: + (void) sprintf(command, "espresso -o fd < %s > %s", infile, outfile); + stg_single = 0; + break; + + case 1: + (void) sprintf(command, "espresso -o fd < %s > %s", infile, outfile); + stg_single = 1; + break; + + case 2: + (void) sprintf(command, "espresso -o fd -Dso < %s > %s", infile, outfile); + stg_single = 1; + break; + + default: + return NIL(network_t); + } + + if ((to = fopen(infile, "w")) == NULL) { + (void) fprintf(siserr, "error: can not open temporary file - %s\n", infile); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return NIL(network_t); + } + + if (write_encoded_espresso_format(to, stg)) { + (void) fprintf(siserr, "error in writing encoded state table\n"); + (void) fclose(to); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return NIL(network_t); + } + (void) fclose(to); + + status = system(command); + + if (status) { + (void) fprintf(siserr, "stg to network program returned non-zero exit status\n%s\n", command); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return NIL(network_t); + } + + /* sis_read_pla requires that the global variable read_filename be set */ + read_register_filename(outfile); + + if ((from = fopen(outfile, "r")) == NULL) { + (void) fprintf(siserr, "error: can not open output file - %s\n", outfile); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + return NIL(network_t); + } + + network = sis_read_pla(from, stg_single); + read_register_filename(NIL(char)); + (void) fclose(from); + (void) unlink(infile); + (void) unlink(outfile); + FREE(infile); + FREE(outfile); + + if (network == NIL(network_t)) { + (void) fprintf(siserr, "read_blif: error reading PLA\n"); + return NIL(network_t); + } + + error = error_string(); + if (error[0] != '\0') { + (void) fprintf(siserr, "%s", error); + } + if (!network_check(network)) { + (void) fprintf(siserr, "%s\n", error_string()); + return NIL(network_t); + } + + + latches = strlen(start); + genpi = lsStart(network->pi); + genpo = lsStart(network->po); + n = lsLength(network->pi); + while (n > latches) { + (void) lsNext(genpi,(lsGeneric *) &pi,LS_NH); + n--; + } + while (latches) { + (void) lsNext(genpi,(lsGeneric *) &pi,LS_NH); + (void) lsNext(genpo,(lsGeneric *) &po,LS_NH); + /* changed to get it to compile */ + (void) network_create_latch(network, &l, po, pi); + c = *start++; + switch(c) { + case '0' : + latch_set_initial_value(l, 0); + latch_set_current_value(l, 0); + break; + case '1' : + latch_set_initial_value(l, 1); + latch_set_current_value(l, 1); + break; + default : + fail("An encoding bit for the start state has an invalid value"); + } + latches--; + } + (void) lsFinish(genpi); + (void) lsFinish(genpo); + + stg_free(network_stg(network)); + network_set_stg(network, stg); + return network; +} + +/* + * Adds the clock data structure to the network + */ +static void +stg_network_add_clock(network, stg) +network_t *network; +graph_t *stg; +{ + lsGen gen; + stg_clock_t *clock_data; + sis_clock_t *clock; + clock_edge_t edge; + int add_clock = TRUE; + + /* Add the clocking information to the network as well */ + if ((clock_data = stg_get_clock_data(stg)) == NIL(stg_clock_t)){ + return; + } + /* Check if the clock already exists */ + foreach_clock(network, gen, clock){ + if (strcmp(clock_name(clock), clock_data->name) == 0){ + /* Clock already present in network -- NOVA does this */ + add_clock = FALSE; + lsFinish(gen); + break; + } + } + + if (add_clock){ + clock = clock_create(clock_data->name); + (void)clock_add_to_network(network, clock); + } + + clock_set_cycletime(network, clock_data->cycle_time); + edge.clock = clock; + + edge.transition = RISE_TRANSITION; + clock_set_parameter(edge, CLOCK_NOMINAL_POSITION, clock_data->nominal_rise); + clock_set_parameter(edge, CLOCK_LOWER_RANGE, clock_data->min_rise); + clock_set_parameter(edge, CLOCK_UPPER_RANGE, clock_data->max_rise); + + edge.transition = FALL_TRANSITION; + clock_set_parameter(edge, CLOCK_NOMINAL_POSITION, clock_data->nominal_fall); + clock_set_parameter(edge, CLOCK_LOWER_RANGE, clock_data->min_fall); + clock_set_parameter(edge, CLOCK_UPPER_RANGE, clock_data->max_fall); + + return; +} + +/* + * Add the PI node corresponding to the clock signal, Also add adummy + * PO and set that to be the contol of all the latches + * THIS ROUTINE MUST BE CALLED AFTER (stg_set_network_pipo_names()) + */ + +static void +stg_network_connect_clock(network, stg) +network_t *network; +graph_t *stg; +{ + lsGen gen; + latch_t *latch; + int edge_index; + latch_synch_t type; + stg_clock_t *clock_data; + node_t *pi_node, *po_node; + + if ((clock_data = stg_get_clock_data(stg)) == NIL(stg_clock_t)){ + return; + } + + /* Find the type of the latches */ + edge_index = stg_get_edge_index(stg); + type = (edge_index == 0 ? RISING_EDGE : + (edge_index == 1 ? FALLING_EDGE : UNKNOWN)); + + if ((pi_node = network_find_node(network, clock_data->name)) != NIL(node_t) + && pi_node->type == PRIMARY_INPUT){ + /* PI node of the same name is present as clock */ + } else { + /* Add the Primary input node for the clock */ + pi_node = node_alloc(); + network_add_primary_input(network, pi_node); + network_change_node_name(network, pi_node, util_strsav(clock_data->name)); + } + + if (type != UNKNOWN){ + if (node_num_fanout(pi_node) == 0){ + po_node = network_add_fake_primary_output(network, pi_node); + } else { + /* Need to find unique fanout that is a PRIMARY_OUTPUT */ + (void)fprintf(sisout, "Fanouts present for clcok input\n"); + po_node = node_get_fanout(pi_node, 0); + } + foreach_latch(network, gen, latch){ + latch_set_control(latch, po_node); + latch_set_type(latch, type); + } + } else { + /* Latches are not controlled , even though clocks are present */ + } + + return; +} + +static int +write_encoded_espresso_format(fp, stg) +FILE *fp; +graph_t *stg; +{ + vertex_t *start; + edge_t *e; + lsGen lgen; + int state_bits; + + start = stg_get_start(stg); + if (stg_get_state_encoding(start) == NIL(char)) { + (void) fprintf(siserr, "FSM has no encoding\n"); + return 1; + } + state_bits = strlen(stg_get_state_encoding(start)); + (void) fprintf(fp, ".type fr\n"); + (void) fprintf(fp, ".i %d\n", stg_get_num_inputs(stg) + state_bits); + (void) fprintf(fp, ".o %d\n", stg_get_num_outputs(stg) + state_bits); + stg_foreach_transition(stg, lgen, e) { + (void) fprintf(fp, "%s %s %s %s\n", stg_edge_input_string(e), + stg_get_state_encoding(stg_edge_from_state(e)), + stg_get_state_encoding(stg_edge_to_state(e)), + stg_edge_output_string(e)); + } + (void) fprintf(fp, ".e\n"); + return 0; +} + + +/*ARGSUSED*/ +static int +com_stg_dump_graph(network,argc,argv) +network_t **network; +int argc; +char **argv; +{ + graph_t *stg; + + stg = network_stg(*network); + stg_dump_graph(stg, *network); + return 0; +} + + +init_stg() +{ + com_add_command("stg_extract",com_stg_extract,1); + com_add_command("stg_to_network",com_stg_to_network,1); + com_add_command("state_assign",com_stg_state_assign,1); + com_add_command("state_minimize",com_stg_state_minimize,1); + com_add_command("stg_cover",com_stg_cover,0); + com_add_command("one_hot",com_one_hot,1); + com_add_command("_stg_dump_graph",com_stg_dump_graph,0); +#ifdef STG_DEBUG + com_add_command("_stg_test",stg_test,0); +#endif /* STG_DEBUG */ +} + +end_stg() +{ +} +#endif /* SIS */ diff --git a/sis/stg/enumerate.c b/sis/stg/enumerate.c new file mode 100644 index 0000000..79a0f07 --- /dev/null +++ b/sis/stg/enumerate.c @@ -0,0 +1,553 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/stg/enumerate.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#ifdef SIS +/**********************************************************************/ +/* This is the sequential circuit enumeration source file. */ +/* Parameters needed: Starting State; */ +/* Author: Hi-keung Tony Ma */ +/* last update : 02/19/1989 */ +/**********************************************************************/ + +#include "sis.h" +#include "stg_int.h" + +/* + * Procedures to ease the task of storing vectors of integers as + * packed unsigned integers... Needed when number of latches exceeds 32 !!!! + */ +#define STG_CHUNKSIZE 1000 +static unsigned **stg_hash_space; +static int stg_num_chunks; +static int stg_position_in_chunk; +static int stg_sizeof_chunk; +static st_table *stg_storelist; +static char *instring, *outstring; /* For the save_edge() routine */ + +/* Compare function for the hashing of sttesa represented as packed bits */ +int +stg_statecmp(key1, key2) +char *key1, *key2; +{ + int equal_parts, i; + unsigned *st1 = (unsigned *)key1; + unsigned *st2 = (unsigned *)key2; + + equal_parts = 0; + for ( i = stg_longs_per_state; (equal_parts == 0) && (i-- > 0); ){ + if (st1[i] > st2[i]) equal_parts = 1; + else if (st1[i] < st2[i]) equal_parts = -1; + } + return equal_parts; +} + +/* + * Hashing the packed state bits into a number : We will only worry about + * a good hashing function that discriminates the 32 LSBits + */ +int +stg_statehash(key, modulus) +char *key; +int modulus; +{ + unsigned *state = (unsigned *)key; + + return (ABS(state[0]% modulus)); +} + +/* +void +stg_print_hashed_state(fp, s) +FILE *fp; +unsigned *s; +{ + int i; + for (i = stg_longs_per_state; i-- > 0;){ + fprintf(fp, "%x", s[i]); + } +} +*/ + +void +stg_init_state_hash() +{ + stg_num_chunks = 1; + stg_sizeof_chunk = stg_longs_per_state * STG_CHUNKSIZE; + stg_position_in_chunk = 0; + stg_hash_space = SENUM_ALLOC(unsigned *, stg_num_chunks); + stg_hash_space[0] = SENUM_ALLOC(unsigned, stg_sizeof_chunk ); + stg_storelist = st_init_table(stg_statecmp, stg_statehash); + + instring = ALLOC(char, nlatch+1); + outstring = ALLOC(char, nlatch+1); +} + +static void +stg_realloc_state_hash() +{ + stg_hash_space = REALLOC(unsigned *, stg_hash_space, stg_num_chunks+1); + stg_hash_space[stg_num_chunks++] = SENUM_ALLOC(unsigned, stg_sizeof_chunk); + stg_position_in_chunk = 0; +} + +unsigned * +stg_get_state_hash() +{ + unsigned *block; + + if (stg_position_in_chunk == STG_CHUNKSIZE){ + stg_realloc_state_hash(); + } + block = stg_hash_space[stg_num_chunks-1]; + block += stg_longs_per_state * stg_position_in_chunk; + stg_position_in_chunk++; + return block; +} + +void +stg_end_state_hash() +{ + int i; + for ( i = 0; i < stg_num_chunks; i++){ + FREE(stg_hash_space[i]); + } + FREE(stg_hash_space); + st_free_table(stg_storelist); + FREE(instring); + FREE(outstring); +} + +void +stg_translate_hashed_code(h_state, stg_state) +unsigned *h_state; +int *stg_state; +{ + int i, j, k; + unsigned compact_state; + + for (i = 0, k = 0; i < stg_longs_per_state; i++){ + compact_state = h_state[i]; + for (j = 0; (j < stg_bits_per_long) && (k < nlatch); j++){ + stg_state[k++] = compact_state & 1; + compact_state >>= 1; + } + } +} + + +static int +is_state(cid,obj,level) +int cid; +ndata **obj; +int *level; +{ + node_t *node; + ndata *n; + lsGen gen; + + foreach_primary_output (copy,gen,node) { + n = nptr(node_get_fanin(node,0)); + if (n->value[cid] == 2) { + *obj = n; + *level = random() & 01; + (void) lsFinish(gen); + return(FALSE); + } + } + return(TRUE); +} + +static ndata * +find_hardest_control(cid,node,noinv) +int cid; +node_t *node; +int *noinv; +{ + register int i; + ndata *n; + + for (i = node_num_fanin(node) - 1; i >= 0; i--) { + n = nptr(node_get_fanin(node,i)); + if (n->value[cid] == 2) { + *noinv = (nptr(node)->cube >> i) & 01; + return(n); + } + } + return(NIL(ndata)); +} + +static ndata * +find_easiest_control(cid,node,noinv) +int cid; +node_t *node; +int *noinv; +{ + register int i; + int nin = node_num_fanin(node); + ndata *n; + + for (i = 0; i < nin; i++) { + n = nptr(node_get_fanin(node,i)); + if (n->value[cid] == 2) { + *noinv = (nptr(node)->cube >> i) & 01; + return(n); + } + } + return(NIL(ndata)); +} + +/* + * This routine and the find_???_control routines depend on the network + * consisting of solely AND gates (with possibly NOTs on the inputs). + */ +static ndata * +find_pi_assignment(cid,obj,level) +int cid; +ndata *obj; +int level; +{ + ndata *n; + int noinv; + node_t *node = obj->node; + + if (node_type(node) == PRIMARY_INPUT) { + obj->value[cid] = level; + return(obj); + } + n = (level) ? find_hardest_control(cid,node,&noinv) + : find_easiest_control(cid,node,&noinv); + if (n == NIL(ndata)) { + return(NIL(ndata)); + } + if (!noinv) { /* inverter on input */ + level ^= 1; + } + return(find_pi_assignment(cid,n,level)); +} + + +static void +save_edge(cid,stg) +int cid; +graph_t *stg; +{ + char *b1,*b2; + register char *t1,*t2; + int i, is_first_state; + unsigned from = 0, to = 0; + static char statechar[] = {'0','1','-'}; + vertex_t *instate, *outstate; + edge_t *e; + + is_first_state = (total_no_of_states == 0); + + for (i = nlatch - 1; i >= 0 ; i--) { + from = from << 1; + from += (unsigned) stg_pstate[i]->value[cid]; + to = to << 1; + to += (unsigned) stg_nstate[i]->value[cid]; + } + /* + (void)fprintf(sisout, "From %x to %x on ", from, to); + */ + + t1 = instring; + t2 = outstring; + for (i = 0; i < nlatch; i++) { + *t1++ = statechar[stg_pstate[i]->value[cid]]; + *t2++ = statechar[stg_nstate[i]->value[cid]]; + } + *t1 = '\0'; + *t2 = '\0'; + if (!st_lookup(state_table,instring,(char **) &instate)) { + instate = g_add_vertex_static(stg); + total_no_of_states++; + b1 = util_strsav(instring); + g_set_v_slot_static(instate,STATE_STRING,(gGeneric) b1); + g_set_v_slot_static(instate,ENCODING_STRING, (gGeneric) util_strsav(instring)); + (void) st_insert(state_table,b1,(char *) instate); + } + if (!st_lookup(state_table,outstring,(char **) &outstate)) { + total_no_of_states++; + outstate = g_add_vertex_static(stg); + b2 = util_strsav(outstring); + g_set_v_slot_static(outstate,STATE_STRING,(gGeneric) b2); + g_set_v_slot_static(outstate,ENCODING_STRING,(gGeneric) util_strsav(outstring)); + (void) st_insert(state_table,b2,(char *) outstate); + } + if (is_first_state) { + g_set_g_slot_static(stg,START,(gGeneric) instate); + g_set_g_slot_static(stg,CURRENT,(gGeneric) instate); + } + e = g_add_edge_static(instate,outstate); + total_no_of_edges++; + b1 = SENUM_ALLOC(char,npi + 1); + t1 = b1; + + for (i = 0; i < npi; i++) { + *t1++ = statechar[varying_node[i]->value[cid]]; + } + *t1 = '\0'; + b2 = SENUM_ALLOC(char,npo + 1); + t2 = b2; + for (i = 0; i < npo; i++) { + *t2++ = statechar[real_po[i]->value[cid]]; + } + *t2 = '\0'; + /* + (void)fprintf(sisout, "%s\n", b1); + */ + g_set_e_slot_static(e,INPUT_STRING,(gGeneric) b1); + g_set_e_slot_static(e,OUTPUT_STRING,(gGeneric) b2); +} + +int barray[16] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, + 8192, 16384, 32768}; + +void +ctable_enum(stg) +graph_t *stg; +{ + ndata **pi_stack,*n,*wpi,*state,*obj; + int total_state,cur_state,tmp,i,no_state,pi_num,find_state,level; + char *jflag,*value; + + pi_stack = SENUM_ALLOC(ndata *,npi); + total_state = barray[nlatch]; + + for (cur_state = 0; cur_state < total_state; cur_state++) { + for (i = 0; i < n_varying_nodes; i++) { + n = varying_node[i]; + n->value[0] = 2; + n->jflag[0] = 0; + } + tmp = cur_state; + for (i = nlatch - 1; i >= 0; i--) { + n = stg_pstate[i]; + if (tmp >= barray[i]) { + tmp -= barray[i]; + n->value[0] = 1; + } + else { + n->value[0] = 0; + } + n->jflag[0] |= CHANGED; + } + stg_sc_sim(0); + no_state = FALSE; + pi_num = 0; + do { + wpi = NIL(ndata); + find_state = is_state(0,&obj,&level); + switch (find_state) { + case TRUE: + save_edge(0,stg); + while (wpi == NIL(ndata) && pi_num != 0) { + pi_num--; + state = pi_stack[pi_num]; + jflag = state->jflag; + value = state->value; + if (*jflag & ALL_ASSIGNED) { + *jflag &= ~ALL_ASSIGNED; + *jflag |= CHANGED; + *value = 2; + } + else { + *jflag |= (ALL_ASSIGNED | CHANGED); + *value ^= 1; + wpi = state; + pi_num++; + } + } + if (wpi == NIL(ndata)) { + no_state = TRUE; + } + break; + case FALSE: + wpi = find_pi_assignment(0,obj,level); + if (wpi != NIL(ndata)) { + pi_stack[pi_num] = wpi; + *wpi->jflag |= CHANGED; + pi_num++; + } + while (wpi == NIL(ndata) && pi_num > 0) { + pi_num--; + state = pi_stack[pi_num]; + jflag = state->jflag; + value = state->value; + if (*jflag & ALL_ASSIGNED) { + *jflag &= ~ALL_ASSIGNED; + *jflag |= CHANGED; + *value = 2; + } + else { + *jflag |= (ALL_ASSIGNED | CHANGED); + *value ^= 1; + wpi = state; + pi_num++; + } + } + if (wpi == NIL(ndata)) { + no_state = TRUE; + } + break; + } + stg_sc_sim(0); + } while (no_state == FALSE); + while (pi_num > 0) { + pi_num--; + pi_stack[pi_num]->jflag[0] &= ~ALL_ASSIGNED; + } + } + FREE(pi_stack); +} + +unsigned * +shashcode(estate) +int *estate; +{ + unsigned *new_hashed, state; + int i, j, k; + + /* Store the elements of the integer array as bits in "hashed_state" */ + j = nlatch % stg_bits_per_long; + j = (j == 0 ? stg_bits_per_long : j); + for (k = nlatch, i = stg_longs_per_state; i-- > 0; ){ + state = 0L; + for (; j-- > 0 ; ){ + state = state << 1; + state += (unsigned)estate[--k]; + } + hashed_state[i] = state; + j = stg_bits_per_long; + } + + if (!st_lookup(stg_storelist, (char *)hashed_state, (char **)&new_hashed)){ + new_hashed = stg_get_state_hash(); + for ( i = 0; i < stg_longs_per_state; i++){ + *(new_hashed+i) = hashed_state[i]; + } + (void)st_insert(stg_storelist, (char *)new_hashed, (char *)new_hashed); + } + return(new_hashed); +} + +void +enumerate(elength, estate, stg) +int elength; +int *estate; +graph_t *stg; +{ + int *next_estate,i,no_state,pi_num,find_state,level; + ndata **pi_stack,*n,*obj,*wpi,*state; + unsigned *s; + char *jflag,*value; + + next_estate = ALLOC(int,nlatch); + pi_stack = SENUM_ALLOC(ndata *,npi); + + for (i = 0; i < n_varying_nodes; i++) { + n = varying_node[i]; + n->value[elength] = 2; + n->jflag[elength] = 0; + } + for (i = 0; i < nlatch; i++) { + state = stg_pstate[i]; + state->value[elength] = estate[i]; + state->jflag[elength] |= CHANGED; + } + stg_sc_sim(elength); + no_state = FALSE; + pi_num = 0; + do { + wpi = NIL(ndata); + find_state = is_state(elength,&obj,&level); + switch (find_state) { + case TRUE: + save_edge(elength,stg); + for (i = 0; i < nlatch; i++) { + next_estate[i] = stg_nstate[i]->value[elength]; + } + s = shashcode(next_estate); + if (!st_is_member(slist,(char *) s)) { + if ((elength + 1) == MAX_ELENGTH) { + /* + (void)fprintf(sisout,"Reached ELENGTH LIMIT for "); + stg_print_hashed_state(sisout, s); + (void)fprintf(sisout,"\n"); + */ + (void) st_insert(slist,(char *) s,(char *) unfinish_head); + unfinish_head = s; + } + else { + (void) st_insert(slist, (char *) s,(char *)(NIL(unsigned))); + enumerate(elength + 1, next_estate, stg); + } + } + while (wpi == NIL(ndata) && pi_num != 0) { + pi_num--; + state = pi_stack[pi_num]; + jflag = state->jflag; + value = state->value; + if (jflag[elength] & ALL_ASSIGNED) { + jflag[elength] &= ~ALL_ASSIGNED; + jflag[elength] |= CHANGED; + value[elength] = 2; + } + else { + jflag[elength] |= (ALL_ASSIGNED | CHANGED); + value[elength] ^= 1; + wpi = state; + pi_num++; + } + } + if (wpi == NIL(ndata)) { + no_state = TRUE; + } + break; + case FALSE: + wpi = find_pi_assignment(elength,obj,level); + if (wpi != NIL(ndata)) { + pi_stack[pi_num] = wpi; + wpi->jflag[elength] |= CHANGED; + pi_num++; + } + while (wpi == NIL(ndata) && pi_num > 0) { + pi_num--; + state = pi_stack[pi_num]; + jflag = state->jflag; + value = state->value; + if (jflag[elength] & ALL_ASSIGNED) { + jflag[elength] &= ~ALL_ASSIGNED; + jflag[elength] |= CHANGED; + value[elength] = 2; + } + else { + jflag[elength] |= (ALL_ASSIGNED | CHANGED); + value[elength] ^= 1; + wpi = state; + pi_num++; + } + } + if (wpi == NIL(ndata)) { + no_state = TRUE; + } + break; + } + stg_sc_sim(elength); + } while (no_state == FALSE); + while (pi_num > 0) { + pi_num--; + pi_stack[pi_num]->jflag[elength] &= ~ALL_ASSIGNED; + } + FREE(pi_stack); + FREE(next_estate); +}/* end of enumerate */ + +#endif /* SIS */ diff --git a/sis/stg/level_c.c b/sis/stg/level_c.c new file mode 100644 index 0000000..ab3aa37 --- /dev/null +++ b/sis/stg/level_c.c @@ -0,0 +1,202 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/stg/level_c.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#ifdef SIS +/**********************************************************************/ +/* This is the levelling routine for senum */ +/* */ +/* Author: Tony Hi-Keung Ma */ +/* last update : 05/16/1987 */ +/**********************************************************************/ + +#include "sis.h" +#include "stg_int.h" + +void +level_circuit() +{ + int i,x; + lsGen gen,gen2; + node_t *node,*fi,*fo,*latch_end; + ndata *n,*nfirst,*nlast,*nprelast,*ncurrent,*wfirst,*w,*temp; + int schedule,level,val; + long literal; + node_cube_t cube; + + level = 0; + nfirst = nlast = wfirst = NIL(ndata); + foreach_node (copy,gen,node) { + n = SENUM_ALLOC(ndata,1); + setnptr(node,n); + n->node = node; + n->next = n->wnext = NIL(ndata); + if (node_num_cube(node)) { + cube = node_get_cube(node,0); + literal = 0; + for (i = node_num_fanin(node) - 1; i >= 0; i--) { + literal <<= 1; + literal += (node_get_literal(cube,i) == ONE); + } + n->cube = literal; + } + else { + n->cube = 1; + } + } + x = 0; + foreach_primary_input (copy,gen,node) { + n = nptr(node); + latch_end = network_latch_end(node); + if (latch_end) { + stg_pstate[x] = nptr(node); + stg_estate[x] = latch_get_initial_value(latch_from_node(latch_end)); + stg_nstate[x] = nptr(node_get_fanin(latch_end,0)); + x++; + } + else { + varying_node[n_varying_nodes++] = n; + } + n->level = level; + n->jflag[0] = MARKED; + foreach_fanout (node,gen2,fo) { + n = nptr(fo); + if (n->next == NIL(ndata) && n != nlast) { + n->next = nfirst; + nfirst = n; + } + if (nlast == NIL(ndata)) { + nlast = nfirst; + } + } + } + x = 0; + foreach_primary_output (copy,gen,node) { + fi = node_get_fanin(node,0); + if (node_type(fi) == INTERNAL && node_num_fanin(fi) == 0) { + n = nptr(fi); + n->level = level; + n->jflag[0] = MARKED; + val = (node_function(fi) == NODE_1); + i = 0; + do { + n->value[i] = val; + } while (++i < MAX_ELENGTH); + } + if (network_latch_end(node) == NIL(node_t)) { + real_po[x++] = nptr(fi); + } + } + + nprelast = nlast; + + while (nfirst) { + ncurrent = nfirst; + nfirst = nfirst->next; + ncurrent->next = NIL(ndata); + schedule = TRUE; + foreach_fanin (ncurrent->node,i,fi) { + if ((nptr(fi)->jflag[0] & MARKED) == 0) { + schedule = FALSE; + break; + } + } + if (schedule) { + if (node_type(ncurrent->node) == INTERNAL) { + varying_node[n_varying_nodes++] = ncurrent; + } + ncurrent->wnext = wfirst; + wfirst = ncurrent; + foreach_fanout (ncurrent->node,gen,fo) { + n = nptr(fo); + if (n->next == NIL(ndata) && n != nlast) { + nlast->next = n; + nlast = n; + if (nfirst == NIL(ndata)) { + nfirst = nlast; + } + } + } + } + else { + if (ncurrent->next == NIL(ndata) && ncurrent != nlast) { + nlast->next = ncurrent; + nlast = ncurrent; + } + if (nfirst == NIL(ndata)) { + nfirst = nlast; + } + } + if (ncurrent == nprelast) { + level++; + if (wfirst == NIL(ndata)) { + (void) fprintf(stderr,"There are errors in the circuit\n!"); + (void) fprintf(stderr,"levelling stop at level %d\n", level); + exit(-1); + } + for (w = wfirst; w; w = temp) { + temp = w->wnext; + w->wnext = NIL(ndata); + w->jflag[0] = MARKED; + w->level = level; + } + wfirst = NIL(ndata); + nprelast = nlast; + } + } + /* unmark each wire */ + foreach_node (copy,gen,node) { + nptr(node)->jflag[0] = 0; + } +}/* end of level */ + + +void +rearrange_gate_inputs() +{ + int j,k,nin,stop,litj,litk; + node_t **fanin,*node,*temp; + lsGen gen; + ndata *n,*nj,*nk; + extern int barray[]; + + foreach_node (copy,gen,node) { + nin = node_num_fanin(node); + if (node_type(node) == INTERNAL && nin > 1) { + stop = nin - 1; + fanin = node->fanin; + n = nptr(node); + for (j = 0; j < stop; j++) { + nj = nptr(fanin[j]); + for (k = j + 1; k < nin; k++) { + nk = nptr(fanin[k]); + if (nj->level > nk->level) { + temp = fanin[j]; + fanin[j] = fanin[k]; + fanin[k] = temp; + litj = n->cube & barray[j]; + litk = n->cube & barray[k]; + if (litk == 0) { + n->cube &= ~litj; + } + else { + n->cube |= barray[j]; + } + if (litj == 0) { + n->cube &= ~litk; + } + else { + n->cube |= barray[k]; + } + } + } + } + } + } +} +#endif /* SIS */ diff --git a/sis/stg/senum_main.c b/sis/stg/senum_main.c new file mode 100644 index 0000000..242e83a --- /dev/null +++ b/sis/stg/senum_main.c @@ -0,0 +1,475 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/stg/senum_main.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#ifdef SIS +/**********************************************************************/ +/* This is the main routine for senum */ +/**********************************************************************/ + +#include "sis.h" +#include "stg_int.h" + +/* + * Global variables for this package --- + */ +network_t *copy; +ndata **stg_pstate,**stg_nstate,**real_po; +int *stg_estate; +int nlatch,npi,npo; +int stg_longs_per_state, stg_bits_per_long; +int total_no_of_states; +long total_no_of_edges; +unsigned *unfinish_head, *hashed_state; +st_table *slist; +st_table *state_table; +st_table *node_to_ndata_table; +int n_varying_nodes; +ndata **varying_node; + +extern sis_clock_t *clock_get_transitive_clock(); /* Should be in clock.h */ +static stg_clock_t *stg_get_clock_info(); +static int stg_valid_network(); +static void stg_remove_control_logic(); +/* + * Routines needed to replace the use of the undef1 field of node + */ + +ndata * +nptr(node) +node_t *node; + { + char *dummy; + if (st_lookup(node_to_ndata_table, (char *)node, &dummy)){ + return ((ndata *)dummy); + } else { + return NIL(ndata); + } + } + +void +setnptr(node, value) +node_t *node; +ndata *value; + { + (void)st_insert(node_to_ndata_table, (char *)node, (char *)value); + } + + +graph_t * +stg_extract(network,ctable) +network_t *network; +int ctable; +{ + unsigned *unfinish_next, *compact_state; + int index; + graph_t *stg; + st_generator *generator; + char *key, *value, *clk_name; + node_t *control_node; + sis_clock_t *clock; + stg_clock_t *clk_data; /* Storage for the clocking information */ + lsGen gen; + latch_t *l; + int init_val; + char *init_state; + vertex_t *i_state; + int nl, i, edge_index; + + /* msec = util_cpu_time(); */ + if (!network_check(network)) { + (void) fprintf(siserr, "Error in network\n"); + (void) fprintf(siserr, "%s\n", error_string()); + return NIL(graph_t); + } + + copy = network_dup(network); + if (!network_check(copy)) { + (void) fprintf(siserr, "Error in copy\n"); + (void) fprintf(siserr, "%s\n", error_string()); + goto error_exit; + } + /* + * first do a network sweep. This will get rid of latches that + * fanout nowhere and parallel latches. + */ + (void) network_sweep(copy); + + /* + * Check if the network is one we can handle + */ + if (!stg_valid_network(copy, &control_node, &clk_name, &edge_index)){ + (void)fprintf(siserr, "STG cannot be extracted for this topology\n"); + goto error_exit; + } + + /* Now remove the clock signal and control logic from the network */ + stg_remove_control_logic(copy); + + /* + * Decompose the network into AND gates with as most 16 inputs + */ + decomp_tech_network(copy, 16, 0); + if (!ctable) { + foreach_latch(copy, gen, l) { + init_val = latch_get_initial_value(l); + if (init_val != 0 && init_val != 1) { + (void) fprintf(siserr, "Network must have a single initial state to extract the STG\n"); + lsFinish(gen); + goto error_exit; + } + } + } else { + /* Save the encoding string of the initial state. */ + /* The reason for this is that stg_extract -a looks at all */ + /* states, not just the initial state. Later we need to set */ + /* the initial state in the new stg to what was given in the + /* blif file. */ + nl = network_num_latch(copy); + init_state = ALLOC(char, nl+1); + i = -1; + foreach_latch(copy, gen, l) { + i++; + init_val = latch_get_initial_value(l); + switch(init_val) { + case 0 : init_state[i] = '0'; + break; + case 1 : init_state[i] = '1'; + break; + case 2 : init_state[i] = '2'; + break; + case 3 : init_state[i] = '3'; + break; + default : + (void) fprintf(siserr, "Unknown latch value %i\n", + init_val); + goto error_exit; + } + } + i++; + init_state[i] = '\0'; + } + + total_no_of_edges = total_no_of_states = 0; + + stg_free(network_stg(network)); + network_set_stg(network, NIL(graph_t)); + stg = stg_alloc(); + slist = st_init_table(stg_statecmp,stg_statehash); + state_table = st_init_table(strcmp,st_strhash); + node_to_ndata_table = st_init_table(st_ptrcmp, st_ptrhash); + + nlatch = network_num_latch(copy); + npi = network_num_pi(copy) - nlatch; + npo = network_num_po(copy) - nlatch; + + stg_bits_per_long = 8 * sizeof(unsigned); + stg_longs_per_state = 1 + ((nlatch - 1)/stg_bits_per_long); + hashed_state = ALLOC(unsigned, stg_longs_per_state); + stg_init_state_hash(); + + n_varying_nodes = 0; + varying_node = ALLOC(ndata *,network_num_internal(copy) + npi); + + stg_estate = SENUM_ALLOC(int,nlatch); + stg_pstate = ALLOC(ndata *,nlatch); + stg_nstate = ALLOC(ndata *,nlatch); + real_po = ALLOC(ndata *,npo); + + level_circuit(); + rearrange_gate_inputs(); + if (ctable) { + ctable_enum(stg); + i_state = stg_get_state_by_name(stg, init_state); + if (i_state == NIL(vertex_t)) { + fail("Initial state not found in extracted stg"); + } + stg_set_start(stg, i_state); + stg_set_current(stg, i_state); + FREE(init_state); + } + else { + unfinish_head = shashcode(stg_estate); + (void) st_insert(slist,(char *) unfinish_head,(char *)(NIL(unsigned *))); + index = 1; + do { + /* + (void) fprintf(sisout,"Enumeration number %d starting at ",index); + stg_print_hashed_state(sisout, unfinish_head); + (void) fprintf(sisout,"\n"); + */ + if (index > 1) { + compact_state = unfinish_head; + stg_translate_hashed_code(compact_state, stg_estate); + } + unfinish_next = unfinish_head; + (void) st_lookup(slist,(char *) unfinish_next, + (char **) &unfinish_head); + enumerate(0,stg_estate,stg); + index++; + } while (unfinish_head != NIL(unsigned)); + } + FREE(stg_estate); + FREE(stg_pstate); + FREE(stg_nstate); + FREE(varying_node); + FREE(real_po); + stg_end_state_hash(); + st_free_table(slist); + st_free_table(state_table); + st_foreach_item(node_to_ndata_table, generator, &key, &value){ + FREE(value); + } + st_free_table(node_to_ndata_table); + /* + foreach_node(copy, gen, node){ + FREE(nptr(node)); + } + */ + network_free(copy); + + stg_set_num_inputs(stg, npi); + stg_set_num_outputs(stg, npo); + stg_set_num_products(stg, total_no_of_edges); + stg_set_num_states(stg, total_no_of_states); + clk_data = stg_get_clock_info(network); + stg_set_clock_data(stg, clk_data); + stg_set_edge_index(stg, edge_index); + network_set_stg(network,stg); + + + /* + (void) fprintf(sisout,"Total number of states = %d\n",total_no_of_states); + (void) fprintf(sisout,"Total number of edges = %d\n",total_no_of_edges); + (void) fprintf(sisout,"Total time = %g\n", + (double) (util_cpu_time() - msec) / 1000); + */ +#ifdef STG_DEBUG + if (!stg_check(stg)) { + stg_free(network_stg(network)); + stg = NIL(graph_t); + network_set_stg(network, NIL(graph_t)); + } +#endif + return(stg); + +error_exit: + network_free(copy); + return NIL(graph_t); +} + +/* + * Check if the network is one we can handle: The following are checked. + * --- Only a single clock should be present + * --- This clock should not be gated. No inputs common to clocking & logic + * --- The latches controlled by this clock should be edge triggered + * --- The latches should all be controlled by the same signal + * --- No real PO or latch input depends on the clock signal + */ +static int +stg_valid_network(network, control_node, clock_namep, edge_indexp) +network_t *network; +node_t **control_node; +char **clock_namep; +int *edge_indexp; +{ + int i; + lsGen gen; + char *name; + latch_synch_t type, new_type; + node_t *node, *control,*new_control; + array_t *nodevec; + sis_clock_t *clock; + delay_time_t delay; + input_phase_t phase; + latch_t *latch; + + /* Initializations */ + *clock_namep = NIL(char); + *edge_indexp = -1; + *control_node = NIL(node_t); + + /* Check for a single clock */ + if (network_num_clock(network) > 1){ + (void)fprintf(siserr, "Multiple clocks found int the design\n"); + return 0; + } + /* + * Now check to see if all the latches are single phase and + * clocked by the same control node + */ + type = UNKNOWN; + control = NIL(node_t); + foreach_latch(network, gen, latch){ + new_control = latch_get_control(latch); + new_type = latch_get_type(latch); + if (new_control != NIL(node_t)){ + if (control == NIL(node_t)){ + control = new_control; + } else if (control != new_control){ + (void)fprintf(siserr, "Different signals control latches\n"); + return 0; + } + } + /* Now check the sytnchronization types */ + if (new_type != UNKNOWN && + new_type != RISING_EDGE && new_type != FALLING_EDGE){ + (void)fprintf(siserr, "Latch type other than edge-triggered found\n"); + return 0; + } else if (type != UNKNOWN && type != new_type){ + (void)fprintf(siserr, "Latches of different types present in design\n"); + return 0; + } else if (new_type == RISING_EDGE || new_type == FALLING_EDGE){ + type = new_type; + } + + } + /* + * At this stage we have a unique signal type and a unique type of latch + * Now see if there is any interaction between the logic and the control + */ + if (control != NIL(node_t)){ + nodevec = network_tfi(control, INFINITY); + for(i = array_n(nodevec); i-- > 0; ){ + node = array_fetch(node_t *, nodevec, i); + if (network_is_real_pi(network, node) && + clock_get_by_name(network, node_long_name(node)) == 0){ + (void)fprintf(siserr, "Gated clocks found in the design\n"); + array_free(nodevec); + return 0; + } + } + array_free(nodevec); + clock = clock_get_transitive_clock(network, control, DELAY_MODEL_UNIT, &delay, &phase); + } + + /* + * It could be the case that the latches are not controlled by anything + * yet the clock signals fan out (transitively) to some PO or latch... + */ + if (control == NIL(node_t) && network_num_clock(network) == 1){ + foreach_clock(network, gen, clock){ + name = clock_name(clock); + } + node = network_find_node(network, name); + nodevec = network_tfo(node, INFINITY); + for (i = array_n(nodevec); i-- > 0; ){ + node = array_fetch(node_t *, nodevec, i); + if (node->type == PRIMARY_OUTPUT && !network_is_control(network, node)){ + (void)fprintf(siserr, "Path from Clock to latch input or PO found\n"); + array_free(nodevec); + return 0; + } + } + array_free(nodevec); + } + if (control != NIL(node_t)){ + /* Set latch type based on the phase of the clock relationship */ + if (phase == NEG_UNATE){ + if (type == RISING_EDGE){ + type = FALLING_EDGE; + } else { + type = RISING_EDGE; + } + } else if (phase == BINATE){ + (void)fprintf(siserr, "Phase relationship between clock and control is not unique\n"); + return 0; + } + } + /* + * Now save the names of the clocks and an index that is indicative + * of the clocking edge (unknown = -1, rise = 0; fall = 1) + */ + if (control != NIL(node_t)){ + *clock_namep = util_strsav(clock_name(clock)); + if (type == RISING_EDGE){ + *edge_indexp = 0; + } else if (type == FALLING_EDGE){ + *edge_indexp = 1; + }else{ + *edge_indexp = -1; + (void)fprintf(sisout, "This should never happen\n"); + } + } + *control_node = control; + + return 1; +} + +/* + * Based on a valid network structure, simply remove the control logic + * Guarantees that the deleted nodes do not fanout to logic.... + */ +static void +stg_remove_control_logic(network) +network_t *network; +{ + int i; + lsGen gen; + latch_t *latch; + sis_clock_t *clock; + array_t *nodevec; + node_t *node, *control_node; + + + foreach_latch(network, gen, latch){ + latch_set_control(latch, NIL(node_t)); + } + control_node = NIL(node_t); + foreach_clock(network, gen, clock){ + control_node = network_find_node(network, clock_name(clock)); + } + if (control_node == NIL(node_t)) return; + + /* Traverse transitive fanin --- deleting nodes closer to PO first */ + nodevec = network_tfo(control_node, INFINITY); + for ( i =0; i < array_n(nodevec);i++ ){ + node = array_fetch(node_t *, nodevec, i); + network_delete_node(network, node); + } + network_delete_node(network, control_node); + return; +} + +static stg_clock_t * +stg_get_clock_info(network) +network_t *network; +{ + lsGen gen; + clock_edge_t edge; + stg_clock_t *clk_data; + sis_clock_t *clock; + + if (network_num_clock(network) != 1) return NIL(stg_clock_t); + + foreach_clock(network, gen, clock){ + lsFinish(gen); + break; + /* NOT REACHED */ + } + + clk_data = ALLOC(stg_clock_t, 1); + clk_data->name = util_strsav(clock_name(clock)); + clk_data->cycle_time = clock_get_cycletime(network); + edge.clock = clock; + + edge.transition = RISE_TRANSITION; + clk_data->nominal_rise = clock_get_parameter(edge, CLOCK_NOMINAL_POSITION); + clk_data->min_rise = clock_get_parameter(edge, CLOCK_LOWER_RANGE); + clk_data->max_rise = clock_get_parameter(edge, CLOCK_UPPER_RANGE); + + edge.transition = FALL_TRANSITION; + clk_data->nominal_fall = clock_get_parameter(edge, CLOCK_NOMINAL_POSITION); + clk_data->min_fall = clock_get_parameter(edge, CLOCK_LOWER_RANGE); + clk_data->max_fall = clock_get_parameter(edge, CLOCK_UPPER_RANGE); + + return clk_data; +} + +#endif /* SIS */ + diff --git a/sis/stg/stg.c b/sis/stg/stg.c new file mode 100644 index 0000000..535e0ac --- /dev/null +++ b/sis/stg/stg.c @@ -0,0 +1,571 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/stg/stg.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "stg_int.h" + +graph_t * +stg_alloc() +{ + graph_t *new; + + new = g_alloc_static(NUM_G_SLOTS, NUM_S_SLOTS, NUM_T_SLOTS); + g_set_g_slot_static(new, STG_INPUT_NAMES, (gGeneric)0); + g_set_g_slot_static(new, STG_OUTPUT_NAMES, (gGeneric)0); + g_set_g_slot_static(new, CLOCK_DATA, (gGeneric)0); + return(new); +} + + +/* + * Free the arrays associated with the input and output names + */ +static void +stg_free_g(thing) +gGeneric thing; +{ + array_t *x; + char *name; + int i, j, param; + stg_clock_t *ptr; + + for ( j = 0; j < 2; j++){ + param = (j == 0 ? STG_INPUT_NAMES : STG_OUTPUT_NAMES); + x = (array_t *)(((gGeneric *) thing)[param]); + if (x != NIL(array_t)){ + for( i = array_n(x); i-- > 0; ){ + name = array_fetch(char *, x, i); + FREE(name); + } + array_free(x); + } + } + ptr = (stg_clock_t *)(((gGeneric *) thing)[CLOCK_DATA]); + if (ptr != NIL(stg_clock_t)) { + FREE(ptr->name); + FREE(ptr); + } + return; +} + +static void +stg_free_v(thing) +gGeneric thing; +{ + gGeneric x; + + x = ((gGeneric *) thing)[STATE_STRING]; + FREE(x); + x = ((gGeneric *) thing)[ENCODING_STRING]; + FREE(x); + return; +} + +static void +stg_free_e(thing) +gGeneric thing; +{ + gGeneric x; + + x = ((gGeneric *) thing)[INPUT_STRING]; + FREE(x); + x = ((gGeneric *) thing)[OUTPUT_STRING]; + FREE(x); +} + + +void +stg_free(stg) +graph_t *stg; +{ + g_free_static(stg, stg_free_g, stg_free_v, stg_free_e); + return; +} + + + +static gGeneric +stg_copy_v(old) +gGeneric old; +{ + gGeneric *new = ALLOC(gGeneric,NUM_S_SLOTS); + gGeneric x; + + new[STATE_STRING] = util_strsav(((gGeneric *) old)[STATE_STRING]); + x = ((gGeneric *) old)[ENCODING_STRING]; + if (x) { + new[ENCODING_STRING] = util_strsav(((gGeneric *) old)[ENCODING_STRING]); + } else { + new[ENCODING_STRING] = (gGeneric) 0; + } + return((gGeneric) new); +} + + +static gGeneric +stg_copy_e(old) +gGeneric old; +{ + gGeneric *new = ALLOC(gGeneric,NUM_T_SLOTS); + + new[INPUT_STRING] = util_strsav(((gGeneric *) old)[INPUT_STRING]); + new[OUTPUT_STRING] = util_strsav(((gGeneric *) old)[OUTPUT_STRING]); + return((gGeneric) new); +} + +void +stg_copy_names(old, new) +graph_t *old, *new; +{ + array_t *x, *newx; + char *name; + int i, j; + + for ( j = 0; j < 2; j++){ /* for inputs (j = 0) and for outputs (j = 1) */ + x = stg_get_names(old, j); + newx = x; + if (x != NIL(array_t)){ + newx = array_alloc(char *, array_n(x)); + for (i = array_n(x); i-- > 0; ){ + name = array_fetch(char *, x, i); + array_insert(char *, newx, i, util_strsav(name)); + } + } + stg_set_names(new, newx, j); + } +} + +/* + *Routine to copy the clock and edge_index fields + * Must be called to preserve the clocking info stored + */ +void +stg_copy_clock_data(old, new) +graph_t *old, *new; +{ + stg_clock_t *clock, *new_clock; + + clock = stg_get_clock_data(old); + if (clock != NIL(stg_clock_t)){ + /* Copy the clocking data */ + new_clock = ALLOC(stg_clock_t, 1); + *new_clock = *clock; + new_clock->name = util_strsav(clock->name); + stg_set_clock_data(new, new_clock); + } else { + stg_set_clock_data(new, NIL(stg_clock_t)); + } + stg_set_edge_index(new, stg_get_edge_index(old)); +} + +graph_t * +stg_dup(stg) +graph_t *stg; +{ + graph_t *new; + vertex_t *start, *start2; + vertex_t *current, *current2; + + + if (stg == NIL(graph_t)) { + return(NIL(graph_t)); + } + new = g_dup_static(stg, (gGeneric (*)()) 0, stg_copy_v, stg_copy_e); + + /* fix the pointers to the start state and the current state */ + + start = stg_get_start(stg); + start2 = stg_get_state_by_name(new, stg_get_state_name(start)); + stg_set_start(new, start2); + current = stg_get_current(stg); + current2 = stg_get_state_by_name(new, stg_get_state_name(current)); + stg_set_current(new, current2); + stg_copy_names(stg, new); + stg_copy_clock_data(stg, new); + return(new); +} + + +static int +equivtrans(x,y) +char *x,*y; +{ + char c; + + while ((c = *x++) != '\0') { + if (c != '-' && *y != '-' && c != *y) { + return(FALSE); + } + y++; + } + return(TRUE); +} + + +int +stg_check(stg) +graph_t *stg; +{ + lsGen gen, gen2; + vertex_t *vert, *start, *any_state; + lsList edge_list, any_edge_list; + edge_t *edge; + char **input_array; + char **output_array; + char **ns_array; + array_t *name_array; + int i,j,len; + int return_code = 1; + int code_length = 0; + int state_len; + + if (stg == NIL(graph_t)) { + return 1; + } + g_check(stg); + + start = (vertex_t *) g_get_g_slot_static(stg, START); + if (!start) { + (void) fprintf(siserr, + "Fatal error in stg_check: no start state specified"); + return 0; + } + if (stg_get_state_encoding(start) != NIL(char)) { + code_length = (int) strlen(stg_get_state_encoding(start)); + } + if (!g_get_g_slot_static(stg,CURRENT)) { + (void) fprintf(siserr, + "Warning in stg_check: no current state specified\n"); + g_set_g_slot_static(stg,CURRENT,(gGeneric) start); + } + name_array = stg_get_names(stg, 1); + if (name_array != NIL(array_t) && + array_n(name_array) != stg_get_num_inputs(stg)){ + (void) fprintf(siserr, + "Warning in stg_check: incorrect number of input names.\n"); + } + name_array = stg_get_names(stg, 0); + if (name_array != NIL(array_t) && + array_n(name_array) != stg_get_num_outputs(stg)){ + (void) fprintf(siserr, + "Warning in stg_check: incorrect number of output names.\n"); + } + any_state = stg_get_state_by_name(stg, "ANY"); + if (any_state == NIL(vertex_t)) { + any_state = stg_get_state_by_name(stg, "*"); + } + if (any_state != NIL(vertex_t)) { + any_edge_list = g_get_out_edges(any_state); + } + foreach_vertex (stg,gen,vert) { + state_len = 0; + if (stg_get_state_encoding(vert) != NIL(char)) { + state_len = (int) strlen(stg_get_state_encoding(vert)); + } + if (state_len != code_length) { + (void) fprintf(siserr, "Fatal error in stg_check: state %s has an encoding with the wrong number of bits\n", stg_get_state_name(vert)); + return_code = 0; + goto bad_exit2; + } + if (vert != start && lsLength(g_get_in_edges(vert)) == 0) { + if (vert != any_state) { + (void) fprintf(siserr, + "Warning in stg_check: unreachable vertex, %s\n", + stg_get_state_name(vert)); + } + } + edge_list = g_get_out_edges(vert); + len = lsLength(edge_list); + if (any_state != NIL(vertex_t)) { + len += lsLength(any_edge_list); + } + switch(len) { + case 0: + (void) fprintf(siserr, + "Warning in stg_check: vertex does not fanout, %s\n", + stg_get_state_name(vert)); + case 1: + break; + default: + input_array = ALLOC(char *,len); + output_array = ALLOC(char *,len); + ns_array = ALLOC(char *,len); + i = 0; + foreach_out_edge (vert,gen2,edge) { + input_array[i] = g_get_e_slot_static(edge,INPUT_STRING); + output_array[i] = g_get_e_slot_static(edge,OUTPUT_STRING); + ns_array[i] = stg_get_state_name(g_e_dest(edge)); + for (j = i - 1; j >= 0; j--) { + if (equivtrans(input_array[i], input_array[j])) { + if (strcmp(output_array[i], output_array[j]) || + strcmp(ns_array[i], ns_array[j])) { + (void) fprintf(siserr, "Fatal error in stg_check: machine is not deterministic (see state %s)\n", stg_get_state_name(vert)); + return_code = 0; + goto bad_exit1; + } + } + } + i++; + } + + /* All the out-edges of state "ANY" are also out-edges of + every other state - so check those also */ + if (any_state != NIL(vertex_t)) { + foreach_out_edge(any_state, gen2, edge) { + input_array[i] = g_get_e_slot_static(edge,INPUT_STRING); + output_array[i] = g_get_e_slot_static(edge,OUTPUT_STRING); + ns_array[i] = stg_get_state_name(g_e_dest(edge)); + for (j = i - 1; j >= 0; j--) { + if (equivtrans(input_array[i], input_array[j])) { + if (strcmp(output_array[i], output_array[j]) || + strcmp(ns_array[i], ns_array[j])) { + (void) fprintf(siserr, "Fatal error in stg_check: machine is not deterministic (see state %s)\n", stg_get_state_name(vert)); + return_code = 0; + goto bad_exit1; + } + } + } + i++; + } + } + FREE(input_array); + FREE(output_array); + FREE(ns_array); + } + } + return return_code; +bad_exit1: + FREE(input_array); + FREE(output_array); + FREE(ns_array); +bad_exit2: + lsFinish(gen); + return return_code; +} + + +void +stg_reset(stg) +graph_t *stg; +{ + if (!stg) { + return; + } + g_set_g_slot_static(stg,CURRENT,g_get_g_slot_static(stg,START)); +} + + +void +stg_sim(stg,vector) +graph_t *stg; +char *vector; +{ + vertex_t *current, *next; + edge_t *edge; + char *input; + lsGen gen; + + current = (vertex_t *) g_get_g_slot_static(stg, CURRENT); + + foreach_out_edge(current, gen, edge) { + input = (char *) g_get_e_slot_static(edge, INPUT_STRING); + if (equivtrans(input, vector)) { + next = g_e_dest(edge); + (void) fprintf(sisout,"%s %s %s %s\n",input, + g_get_v_slot_static(current,STATE_STRING), + g_get_v_slot_static(next,STATE_STRING), + g_get_e_slot_static(edge,OUTPUT_STRING)); + g_set_g_slot_static(stg,CURRENT,(gGeneric) next); + (void) lsFinish(gen); + return; + } + } + (void) fprintf(siserr,"in stg_sim: next state is undeterminable\n"); + return; +} + +void +stg_set_names(stg, name_array, flag) +graph_t *stg; +array_t *name_array; /* array of names of the inputs or outputs */ +int flag; /* == 1 => inputs, 0 => outputs */ +{ + int param; + param = (flag ? STG_INPUT_NAMES : STG_OUTPUT_NAMES); + g_set_g_slot_static(stg, param, (gGeneric)name_array); + return; +} + +array_t * +stg_get_names(stg, flag) +graph_t *stg; +int flag; /* == 1 => inputs, 0 => outputs */ +{ + int param; + array_t *name_array; + + param = (flag ? STG_INPUT_NAMES : STG_OUTPUT_NAMES); + name_array = (array_t *)g_get_g_slot_static(stg, param); + return name_array; +} + +void +stg_set_start(stg, v) +graph_t *stg; +vertex_t *v; +{ + if (g_vertex_graph(v) != stg) { + fail("State is not part of the give stg"); + } + g_set_g_slot_static(stg, START, (gGeneric) v); + return; +} + +void +stg_set_current(stg, v) +graph_t *stg; +vertex_t *v; +{ + if (g_vertex_graph(v) != stg) { + fail("State is not part of the given stg"); + } + g_set_g_slot_static(stg, CURRENT, (gGeneric) v); + return; +} + + +vertex_t * +stg_create_state(stg, name, encoding) +graph_t *stg; +char *name, *encoding; +{ + vertex_t *v; + + v = g_add_vertex_static(stg); + if (name == NIL(char)) { + g_set_v_slot_static(v, STATE_STRING, (gGeneric) 0); + } else { + g_set_v_slot_static(v, STATE_STRING, (gGeneric) util_strsav(name)); + } + if (encoding == NIL(char)) { + g_set_v_slot_static(v, ENCODING_STRING, (gGeneric) 0); + } else { + g_set_v_slot_static(v, ENCODING_STRING, (gGeneric) util_strsav(encoding)); + } + g_set_g_slot_static(stg, NUM_STATES, + (gGeneric) ((int) g_get_g_slot_static(stg, NUM_STATES) + 1)); + return v; +} + + +edge_t * +stg_create_transition(from, to, in, out) +vertex_t *from, *to; +char *in, *out; +{ + edge_t *edge; + lsGen gen; + char *input; + graph_t *stg; + + stg = g_vertex_graph(from); + if (stg != g_vertex_graph(to)) { + fail("Vertices to and from belong to different stgs"); + } + if (strlen(in) != (int) g_get_g_slot_static(stg, NUM_INPUTS)) { + fail("In stg_create_transition: Invalid number of inputs specified"); + } + if (strlen(out) != (int) g_get_g_slot_static(stg, NUM_OUTPUTS)) { + fail("In stg_create_transition: Invalid number of outputs specified"); + } + foreach_out_edge (from, gen, edge) { + if (g_e_dest(edge) != to) { + input = (char *) g_get_e_slot_static(edge, INPUT_STRING); + if (equivtrans(input, in)) { + fail("stg_create_transition: Same transition to different states"); + } + } + } + edge = g_add_edge_static(from, to); + g_set_e_slot_static(edge, INPUT_STRING, (gGeneric) util_strsav(in)); + g_set_e_slot_static(edge, OUTPUT_STRING, (gGeneric) util_strsav(out)); + g_set_g_slot_static(stg,NUM_PRODUCTS, + (gGeneric) ((int) g_get_g_slot_static(stg, NUM_PRODUCTS) + 1)); + return(edge); +} + + +vertex_t * +stg_get_state_by_name(stg, name) +graph_t *stg; +char *name; +{ + lsGen gen; + vertex_t *s; + + stg_foreach_state(stg, gen, s) { + if (!strcmp(stg_get_state_name(s), name)) { + (void) lsFinish(gen); + return s; + } + } + return NIL(vertex_t); +} + + +vertex_t * +stg_get_state_by_encoding(stg, encoding) +graph_t *stg; +char *encoding; +{ + lsGen gen; + vertex_t *s; + + stg_foreach_state(stg, gen, s) { + if (!strcmp(stg_get_state_encoding(s), encoding)) { + (void) lsFinish(gen); + return s; + } + } + return NIL(vertex_t); +} + + +void +stg_set_state_name(v, n) +vertex_t *v; +char *n; +{ + char *oldname; + + oldname = stg_get_state_name(v); + if (oldname != NIL(char)) { + FREE(oldname); + } + g_set_v_slot_static((v), STATE_STRING, (gGeneric) (util_strsav(n))); + return; +} + + +void +stg_set_state_encoding(v, n) +vertex_t *v; +char *n; +{ + char *oldname; + + oldname = stg_get_state_encoding(v); + if (oldname != NIL(char)) { + FREE(oldname); + } + g_set_v_slot_static((v), ENCODING_STRING, (gGeneric) (util_strsav(n))); + return; +} +#endif /* SIS */ diff --git a/sis/stg/stg.doc b/sis/stg/stg.doc new file mode 100644 index 0000000..e61f9ab --- /dev/null +++ b/sis/stg/stg.doc @@ -0,0 +1,350 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/stg/stg.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +graph_t * +stg_alloc() + + Create a new state transition graph. + +void +stg_free(stg) +graph_t *stg; + + Frees the state transition graph. + +graph_t * +stg_dup(stg) +graph_t *stg; + + Returns a copy of the state transition graph. + +int +stg_check(stg) +graph_t *stg; + + Performs various consistency checks on the state transition graph. + Returns a 1 if the errors found are not considered fatal, a 0 + otherwise. Warning messages are printed for all errors. + The following checks are made: checks the graph itself using + g_check(), checks to see that a start state is defined, checks to + see that a current state is defined, checks for unreachable states, + checks for states that do not have any transitions, and checks that + there are no conflicting transitions from one state to two + different states. A 0 is returned (fatal error) if there is no + start state defined, or if there is a conflicting transition from + one state to two or more other staes. + +stg_dump_graph(fp, stg, network) +FILE *fp; +graph_t *stg; +network_t *network; + Prints the Sstate transition graph for stg to the file fp. + If (network != NIL(network_t)) then the routine will print + out the names of the primary inputs and outputs. The network + parameter can be set to NIL(network_t) to supress the printing + of the correspondence. + +void +stg_reset(stg) +graph_t *stg; + + Sets the current state back to the start state. + +void +stg_sim(stg,vector) +graph_t *stg; +char *vector; + + Given values of the primary inputs in the vector, find a transition + determined by the vector from the current state to some next state, + then set the current state equal to that next state. + + Prints the inputs, the current state, the next state, and the + outputs. + + If the next state is undeterminable, prints an error message and + dies. + +int +stg_get_num_inputs(stg) +graph_t *stg; + + Return the number of primary inputs in the stg. + +void +stg_set_num_inputs(stg, i) +graph_t *stg; +int i; + + Sets the number of inputs in the stg to i. + +int +stg_get_num_outputs(stg) +graph_t *stg; + + Return the number of primary outputs in the stg. + +void +stg_set_num_outputs(stg, i) +graph_t *stg; +int i; + + Sets the number of outputs in the stg to i. + +int +stg_get_edge_index(stg) +graph_t *stg; + + Return either 0 (meaning RISING_EDGE) or 1 (meaning FALLING_EDGE). + It is assumed that all latches are clocked by a single global + clock, and all latches are triggered according to this edge type. + +void +stg_set_edge_index(stg, i) +graph_t *stg; +int i; + + Set the edge index in the stg to i. A 0 means RISING_EDGE and 1 + means FALLING_EDGE. It is assumed that all latches are clocked + by a single global clock, and all latches are triggered according + to this type. + +int +stg_get_num_products(stg) +graph_t *stg; + + Return the number of product terms (cubes) in the stg. This is + used for printing out the .p construct in KISS format. + +void +stg_set_num_products(stg, i) +graph_t *stg; +int i; + + Set the number of product terms in the stg to i. This is typically + read in from the .p construct in KISS format. Some state assignment + programs rely on it. + +int +stg_get_num_states(stg) +graph_t *stg; + + Return the number of states in the stg. + +void +stg_set_num_states(stg, i) +graph_t *stg; +int i; + + Sets the number of states in the stg to i. + +vertex_t * +stg_get_start(stg) +graph_t *stg; + + Returns the start state of the state transition graph. + +void +stg_set_start(stg, v) +graph_t *stg; +vertex_t *v; + + Sets the start state of the machine to state v. + +vertex_t * +stg_get_current(stg) +graph_t *stg; + + Returns the current state of the state transition graph. + +void +stg_set_current(stg, v) +graph_t *stg; +vertex_t *v; + + Sets the current state of the machine to state v. + +array_t * +stg_get_latch_order(stg) +graph_t *stg; + + Return the array of latches corresponding to the encoding bits. + +void +stg_add_latch_order(stg, l) +graph_t *stg; +latch_t *l; + + Add the given latch to the end of the array of latches stored in + the latch_order field. + +vertex_t * +stg_create_state(stg, name, encoding) +graph_t *stg; +char *name, *encoding; + + Creates a new state with no transitions. The name of the new state + is set to be the name that is passed in, and the encoding of the new + state is set to be the encoding that is passed in. A pointer to the + new state is returned. + +edge_t * +stg_create_transition(from, to, input, output) +vertex_t *from, *to; +char *input, *output; + + Create a new transition in the graph between 'from' and 'to'. + 'input' and 'output' are specified as null terminated character + strings whose lengths must respectively equal the number of inputs or + the number of outputs specified on this graph. They should contain + only the characters '0', '1', and '-'. + If a transition already exists between 'from' and another vertex not + equal to 'to' which would conflict with the new transition, it + prints an error message and dies. + +vertex_t * +stg_get_state_by_name(stg, name) +graph_t *stg; +char *name; + + Return the state in the stg that has the symbolic name 'name'. + Returns NIL(vertex_t) if the state name is not found. + +vertex_t * +stg_get_state_by_encoding(stg, encoding) +graph_t *stg; +char *encoding; + + Return the state in the stg that has the encoding 'encoding'. + Returns NIL(vertex_t) if the state encoding is not found. + +char * +stg_get_state_name(state) +vertex_t *state; + + Returns the name of the given state. + +void +stg_set_state_name(state, name) +vertex_t *state; +char *name; + + Sets the symbolic name of the given state to 'name'. + +char * +stg_get_state_encoding(state) +vertex_t *state; + + Returns the encoding of the given state. + +void +stg_set_state_encoding(state, encoding) +vertex_t *state; +char *encoding; + + Sets the encoding name of the given state to 'encoding'. + +void +stg_foreach_state(stg, gen, state) +graph_t *stg; +lsGen gen; +vertex_t *state; + + Generates over the states of the state transition graph. + +stg_foreach_transition(stg, gen, trans) +graph_t *stg; +lsGen gen; +edge_t *trans; + + Generates over the transitions of the state transition graph. + +foreach_state_inedge(state, gen, edge) +vertex_t *state; +lsGen gen; +edge_t *edge; + + Generates over all the transitions which end in a given state. + +foreach_state_outedge(state, gen, edge) +vertex_t *state; +lsGen gen; +edge_t *edge; + + Generates over all the transitions with originate in a given state. + +char * +stg_edge_input_string(edge) +edge_t *edge; + + Return the string corresponding to the input values of a + transition. + +char * +stg_edge_output_string(edge) +edge_t *edge; + + Return the string corresponding to the output values of a + transition. + +vertex_t * +stg_edge_from_state(edge) +edge_t *edge; + + Return the vertex corresponding to the state the edge emanates + from. + +vertex_t * +stg_edge_to_state(edge) +edge_t *edge; + + Return the vertex corresponding to the state the edge leads to. + +graph_t * +stg_extract(network, ctable) +network_t *network; +int ctable; + + Takes a network and does a state extraction. The state extraction + is based on the senum program by Tony Ma. It uses a PODEM-like + algorithm for back-tracing. The state transition graph is stored in + the network and returned to the calling procedure. The network + remains otherwise unchanged. + + If ctable is not 0, the start state specified on the latches is + ignored and the network is simulated for all possible start states. + Otherwise, the simulation only finds the states and transitions that + are reachable from the start state. + + This program creates various temporary structures and hangs them off + of the undef1 slot in the node structure. It is not necessary to + create a node daemon or a new slot in the node structure to replace + the use of the undef1 slot, as the structures are destroyed on + completion of the state extraction. + +network_t * +stg_to_network(stg, commands) +graph_t *stg; +array_t *commands; + + Extracts a network from the given state transition graph by + executing a system call to the state assignment program "nova" + (which calls "espresso"). "nova" and "espresso" should therefore be + in some directory in the path. + + Symbolic state names in the state transition graph are changed to + the optimal bit patterns determined by the state assignment. + + The variable 'commands' consists of an array of nova options, such + as ".encoding_algo i_hybrid". If 'commands' is NULL, or there is no + encoding algorithm specified in the array, the default option + ".encoding_algo i_greedy" is passed to nova. + + Commands specified here will override commands that were stored on + the stg during a call to read_kiss(). diff --git a/sis/stg/stg.h b/sis/stg/stg.h new file mode 100644 index 0000000..de01ea4 --- /dev/null +++ b/sis/stg/stg.h @@ -0,0 +1,111 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/stg/stg.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#define START 0 +#define CURRENT 1 +#define NUM_INPUTS 2 +#define NUM_OUTPUTS 3 +#define NUM_PRODUCTS 4 +#define NUM_STATES 5 +#define STG_INPUT_NAMES 6 +#define STG_OUTPUT_NAMES 7 +#define CLOCK_DATA 8 +#define EDGE_INDEX 9 +#define NUM_G_SLOTS 10 /* update this when a new slot is added */ + +#define STATE_STRING 0 +#define ENCODING_STRING 1 +#define NUM_S_SLOTS 2 /* update this when a new slot is added */ + +#define INPUT_STRING 0 +#define OUTPUT_STRING 1 +#define NUM_T_SLOTS 2 /* update this when a new slot is added */ + +EXTERN graph_t *stg_alloc ARGS((void)); +EXTERN void stg_free ARGS((graph_t *)); +EXTERN graph_t *stg_dup ARGS((graph_t *)); +EXTERN int stg_check ARGS((graph_t *)); +EXTERN void stg_dump_graph ARGS((graph_t *, network_t *)); +EXTERN void stg_reset ARGS((graph_t *)); +EXTERN void stg_sim ARGS((graph_t *, char *)); + +EXTERN int stg_save_names ARGS((network_t *, graph_t *, int)); + +#define stg_get_num_inputs(stg) (int) g_get_g_slot_static((stg), NUM_INPUTS) +#define stg_set_num_inputs(stg, i) (void) g_set_g_slot_static((stg), NUM_INPUTS, (gGeneric) i) + +#define stg_get_num_outputs(stg) (int) g_get_g_slot_static((stg), NUM_OUTPUTS) +#define stg_set_num_outputs(stg, i) (void) g_set_g_slot_static((stg), NUM_OUTPUTS, (gGeneric) i) + +#define stg_get_edge_index(stg) (int) g_get_g_slot_static((stg), EDGE_INDEX) +#define stg_set_edge_index(stg, i) (void) g_set_g_slot_static((stg), EDGE_INDEX, (gGeneric) i) + +#define stg_get_num_products(stg) (int) g_get_g_slot_static((stg), NUM_PRODUCTS) +#define stg_set_num_products(stg, i) (void) g_set_g_slot_static((stg), NUM_PRODUCTS, (gGeneric) i) + +#define stg_get_num_states(stg) (int) g_get_g_slot_static((stg),NUM_STATES) +#define stg_set_num_states(stg, i) (void) g_set_g_slot_static((stg),NUM_STATES, (gGeneric) i) + +#define stg_get_start(stg) ((vertex_t *) g_get_g_slot_static((stg),START)) + +EXTERN void stg_set_start ARGS((graph_t *, vertex_t *)); + +#define stg_get_current(stg) ((vertex_t *) g_get_g_slot_static((stg),CURRENT)) + +EXTERN void stg_set_current ARGS((graph_t *, vertex_t *)); +EXTERN void stg_set_names ARGS((graph_t *, array_t *, int)); +EXTERN array_t *stg_get_names ARGS((graph_t *, int)); + +EXTERN vertex_t *stg_create_state ARGS((graph_t *, char *, char *)); +EXTERN edge_t *stg_create_transition ARGS((vertex_t *, vertex_t *, char *, char *)); +EXTERN vertex_t *stg_get_state_by_name ARGS((graph_t *, char *)); +EXTERN vertex_t *stg_get_state_by_encoding ARGS((graph_t *, char *)); + +#define stg_get_state_name(v) \ + ((char *) g_get_v_slot_static((v),STATE_STRING)) + +EXTERN void stg_set_state_name ARGS((vertex_t *, char *)); + +#define stg_get_state_encoding(v) \ + ((char *) g_get_v_slot_static((v), ENCODING_STRING)) + +EXTERN void stg_set_state_encoding ARGS((vertex_t *, char *)); + + + +#define stg_foreach_state(stg, lgen, s) \ + for (lgen = lsStart(g_get_vertices(stg)); \ + lsNext(lgen, (lsGeneric *) &s, LS_NH) == LS_OK \ + || ((void) lsFinish(lgen), 0); ) + +#define stg_foreach_transition(stg, lgen, e) \ + for (lgen = lsStart(g_get_edges(stg)); \ + lsNext(lgen, (lsGeneric *) &e, LS_NH) == LS_OK \ + || ((void) lsFinish(lgen), 0); ) + +#define foreach_state_inedge(v, lgen, e) \ + for (lgen = lsStart(g_get_in_edges(v)); \ + lsNext(lgen, (lsGeneric *) &e, LS_NH) == LS_OK \ + || ((void) lsFinish(lgen), 0); ) + +#define foreach_state_outedge(v, lgen, e) \ + for (lgen = lsStart(g_get_out_edges(v)); \ + lsNext(lgen, (lsGeneric *) &e, LS_NH) == LS_OK \ + || ((void) lsFinish(lgen), 0); ) + +#define stg_edge_input_string(e) \ + ((char *) g_get_e_slot_static((e), INPUT_STRING)) +#define stg_edge_output_string(e) \ + ((char *) g_get_e_slot_static((e), OUTPUT_STRING)) + +#define stg_edge_from_state(e) (g_e_source(e)) +#define stg_edge_to_state(e) (g_e_dest(e)) + +EXTERN graph_t *stg_extract ARGS((network_t *, int)); +EXTERN network_t *stg_to_network ARGS((graph_t *, int)); diff --git a/sis/stg/stg_int.h b/sis/stg/stg_int.h new file mode 100644 index 0000000..0f5e76c --- /dev/null +++ b/sis/stg/stg_int.h @@ -0,0 +1,89 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/stg/stg_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#define MAX_ELENGTH 36 + +/* We are keeping the definitions of the clocks local to the stg package */ +typedef struct stg_clock_structure { + char *name; + double cycle_time; /* Cycle time */ + double nominal_rise; /* Nominal position */ + double nominal_fall; + double min_rise; /* max negative skew */ + double min_fall; + double max_rise; /* max positive skew */ + double max_fall; + } stg_clock_t; + +#define stg_get_clock_data(stg) (stg_clock_t *) g_get_g_slot_static((stg), CLOCK_DATA) +#define stg_set_clock_data(stg, i) (void) g_set_g_slot_static((stg), CLOCK_DATA, (gGeneric) i) + + +typedef struct node_data { + node_t *node; + struct node_data *next,*wnext; + long cube; + char value[MAX_ELENGTH]; + char jflag[MAX_ELENGTH]; + int level; +} ndata; + +/* + * Support for the memory management (use of calloc) + */ +#define SENUM_ALLOC(type,num) \ + ((type *)calloc((unsigned)(num),(unsigned)sizeof(type))) +extern int stg_statecmp(); +extern int stg_statehash(); +extern void stg_init_state_hash(); +extern void stg_end_state_hash(); +/* +extern void stg_print_hashed_state(); +*/ +extern void stg_translate_hashed_code(); +extern unsigned *stg_get_state_hash(); + +extern ndata *nptr(); +extern void setnptr(); + +/* Old use of the undef1 has been discontinued +#define nptr(node) ((ndata *) (node)->undef1) +#define setnptr(node,n) ((node)->undef1 = (char *) (n)) +*/ + +extern network_t *copy; +extern ndata **stg_pstate,**stg_nstate,**real_po; +extern int *stg_estate; +extern int nlatch,npi,npo; +extern int stg_longs_per_state, stg_bits_per_long; +extern int total_no_of_states; +extern long total_no_of_edges; +extern unsigned *unfinish_head, *hashed_state; +extern st_table *slist; +extern st_table *state_table; +extern int n_varying_nodes; +extern ndata **varying_node; + +#define SCHEDULED 1 +#define ALL_ASSIGNED 2 +#define MARKED 4 +#define CHANGED 8 + +extern void ctable_enum(); +extern unsigned *shashcode(); +extern void enumerate(); + +extern void stg_sc_sim(); + + +extern void level_circuit(); +extern void rearrange_gate_inputs(); +extern void stg_copy_names(); +extern void stg_copy_clock_data(); +extern void stg_set_network_pipo_names(); diff --git a/sis/stg/stg_sc_sim.c b/sis/stg/stg_sc_sim.c new file mode 100644 index 0000000..18b8937 --- /dev/null +++ b/sis/stg/stg_sc_sim.c @@ -0,0 +1,92 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/stg/stg_sc_sim.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "stg_int.h" + +/* + * This routine depends on the network consisting of solely AND gates. It was + * modified from the "explict/simulate" code. + */ +static void +sc_evaluate(n,cid) +ndata *n; +int cid; +{ + int covered,literal,val,k; + node_t *fi; + long cube; + node_t *node; + char *value; + + node = n->node; + cube = n->cube; + covered = 1; + + foreach_fanin (node,k,fi) { + literal = cube & 1; + cube >>= 1; + val = nptr(fi)->value[cid]; + if (val == 2) { + covered = 2; + } + else if (literal + val == 1) { + covered = 0; + break; + } + } + value = n->value; + if (value[cid] != covered) { + value[cid] = covered; + n->jflag[cid] |= CHANGED; + } +} + +void +stg_sc_sim(cid) +int cid; +{ + node_t *node,*fo; + lsGen gen,gen2; + char *jflag; + int i; + ndata *n; + + foreach_primary_input (copy,gen,node) { + n = nptr(node); + jflag = n->jflag; + if (jflag[cid] & CHANGED) { + jflag[cid] &= ~CHANGED; + foreach_fanout (node,gen2,fo) { + if (node_type(fo) != PRIMARY_OUTPUT) { + nptr(fo)->jflag[cid] |= SCHEDULED; + } + } + } + } + for (i = npi; i < n_varying_nodes; i++) { + n = varying_node[i]; + jflag = n->jflag; + if (jflag[cid] & SCHEDULED) { + jflag[cid] &= ~SCHEDULED; + sc_evaluate(n,cid); + if (jflag[cid] & CHANGED) { + jflag[cid] &= ~CHANGED; + node = n->node; + foreach_fanout (node,gen2,fo) { + if (node_type(fo) != PRIMARY_OUTPUT) { + nptr(fo)->jflag[cid] |= SCHEDULED; + } + } + } + } + } +} +#endif /* SIS */ diff --git a/sis/stg/stg_util.c b/sis/stg/stg_util.c new file mode 100644 index 0000000..c4ef46f --- /dev/null +++ b/sis/stg/stg_util.c @@ -0,0 +1,319 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/stg/stg_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#ifdef SIS +#include "sis.h" +#include "stg_int.h" + + +void +stg_dump_graph(graph, network) +graph_t *graph; +network_t *network; +{ + lsGen gen, gen2; + vertex_t *re_no; + node_t *node; + edge_t *re_ed; + + if (graph == NIL(graph_t)) { + (void)fprintf(sisout, "NIL stg\n"); + return; + } +#ifdef STG_DEBUG + if (!stg_check(graph)) { + (void) fprintf(sisout, "Graph failed stg_check\n"); + return; + } +#endif + (void) fprintf(sisout,"\nInitial state %s\n", stg_get_state_name(stg_get_start(graph))); + if (network != NIL(network_t)){ + (void)fprintf(sisout,"PI list: "); + foreach_primary_input(network, gen, node){ + if (network_latch_end(node) == NIL(node_t)) + (void)fprintf(sisout,"%s ", node_name(node)); + } + (void)fprintf(sisout,"\nPO list: "); + foreach_primary_output(network, gen, node){ + if (network_latch_end(node) == NIL(node_t)) + (void)fprintf(sisout,"%s ", node_name(node)); + } + (void)fprintf(sisout,"\n"); + } + (void)fprintf(sisout,"PresentState input output NextState\n"); + stg_foreach_state(graph, gen, re_no){ + foreach_state_outedge(re_no, gen2, re_ed){ + (void)fprintf(sisout,"%s %s %s %s\n", + stg_get_state_name(re_no), + stg_edge_input_string(re_ed), + stg_edge_output_string(re_ed), + stg_get_state_name(stg_edge_to_state(re_ed))); + } + } + (void)fprintf(sisout,"\n"); +} + +static array_t * +stg_assign_names(flag, n) +int flag; /* == 1 => inputs , otherwise outputs */ +int n; /* Number of names that need to be assigned */ +{ + int i; + char *name, name_buf[16]; + array_t *name_array; + + if (n <= 0) return NIL(array_t); + name_array = array_alloc(char *, n); + for (i = 0; i < n; i++){ + (void)sprintf(name_buf, "%s_%d", (flag ? "IN" : "OUT"), i); + name = util_strsav(name_buf); + array_insert_last(char *, name_array, name); + } + return name_array; +} + +int +stg_save_names(network, stg, print_error) +network_t *network; +graph_t *stg; +int print_error; +{ + char *name; + lsGen gen; + node_t *node; + array_t *name_array; + int netw_pi, stg_pi, netw_po, stg_po; + stg_clock_t *clock_data; + sis_clock_t *clock; + clock_edge_t edge; + + if (stg == NIL(graph_t) || network == NIL(network_t)) return; + + /* Save the output names */ + if ((name_array = stg_get_names(stg, 0)) == NIL(array_t)){ + /* Unfortunately, this is the only way to find number of true PO's */ + netw_po = 0; + foreach_primary_output(network, gen, node){ + if (network_is_real_po(network, node)){ + netw_po++; + } + } + stg_po = stg_get_num_outputs(stg); + if (netw_po > 0){ + if (netw_po != stg_po) { + (void) fprintf(siserr, "Number of outputs in the STG and the BLIF file do not match.\n"); + (void) fprintf(siserr, "Output names from the BLIF file are ignored.\n"); + return 1; + } + name_array = array_alloc(char *, 0); + foreach_primary_output(network, gen, node){ + if (network_is_real_po(network, node)){ + name = util_strsav(node_long_name(node)); + array_insert_last(char *, name_array, name); + } + } + } else { + /* Make up names for the STG output */ + name_array = stg_assign_names(0, stg_po); + } + stg_set_names(stg, name_array, 0); + } + + /* Save the input names now */ + if ((name_array = stg_get_names(stg, 1)) == NIL(array_t)){ + netw_pi = network_num_pi(network) - network_num_latch(network) - + network_num_clock(network); + stg_pi = stg_get_num_inputs(stg); + if (netw_pi> 0){ + if (netw_pi != stg_pi) { + if (print_error) { + /* This error message gets printed twice during read_blif, + this switch prevents that. The same is not true of the + outputs because they aren't present the first time through */ + (void) fprintf(siserr, "Number of inputs in the STG and the BLIF file do not match.\n"); + (void) fprintf(siserr, "Input names from the BLIF file are ignored.\n"); + } + return 1; + } + name_array = array_alloc(char *, 0); + foreach_primary_input(network, gen, node){ + /* Avoid latch inputs and clocks */ + if (network_is_real_pi(network, node) && + clock_get_by_name(network, node_long_name(node)) == 0){ + name = util_strsav(node_long_name(node)); + array_insert_last(char *, name_array, name); + } + } + } else { + /* Make up names for the STG inputs */ + name_array = stg_assign_names(1, stg_pi); + } + stg_set_names(stg, name_array, 1); + } + /* One should also save the clock data -- KJ 7/22/93 + * else we will lose track of the clocking info. supplied with the + * .clock construct when the kiss file is specified with the .inputs + * and .outputs ... When more thna 1 clock ignore the clock setting + */ + if (network_num_clock(network) == 1){ + if ( (clock_data = stg_get_clock_data(stg)) != NIL(stg_clock_t)){ + if (clock_data->name != NIL(char)) FREE(clock_data->name); + FREE(clock_data); + } + clock_data = ALLOC(stg_clock_t, 1); + clock_data->cycle_time = clock_get_cycletime(network); + foreach_clock(network, gen, clock){ + clock_data->name = util_strsav(clock_name(clock)); + edge.clock = clock; + edge.transition = RISE_TRANSITION; + clock_data->nominal_rise = clock_get_parameter(edge, CLOCK_NOMINAL_POSITION); + clock_data-> min_rise = clock_get_parameter(edge, CLOCK_LOWER_RANGE); + clock_data-> max_rise = clock_get_parameter(edge, CLOCK_UPPER_RANGE); + edge.transition = FALL_TRANSITION; + clock_data->nominal_fall = clock_get_parameter(edge, CLOCK_NOMINAL_POSITION); + clock_data-> min_fall = clock_get_parameter(edge, CLOCK_LOWER_RANGE); + clock_data-> max_fall = clock_get_parameter(edge, CLOCK_UPPER_RANGE); + } + stg_set_clock_data(stg, clock_data); + } + return 0; +} + +/* + * Routine that will find a PI/PO node from the dont-care network (dcnet) + * having the same name as the node "node" in the care-network. Then will + * change the name of the dont-care node to be "name" + */ +static void +stg_change_dc_node_name(dcnet, node, name) +network_t *dcnet; +node_t *node; +char *name; +{ + node_t *dc_node; + + if (dcnet != NIL(network_t)){ + dc_node = network_find_node(dcnet, node_long_name(node)); + if (dc_node != NIL(node_t)){ + network_change_node_name(dcnet, dc_node, util_strsav(name)); + } + } +} +/* + * Use the PI/PO names stored with the STG as the names of network PI/PO + * Assume that the order of PI's and PO's is unchanged.... + * In case the network has aSTG associated ith it, the names for this STG are + * also made compatible with the true network names.... + */ +void +stg_set_network_pipo_names(network, stg) +network_t *network; +graph_t *stg; +{ + int i; + int modify_names; + lsGen gen; + graph_t *stg1; + char *name, *name1; + network_t *dcnet; + node_t *node; + array_t *name_array, *name_array1; + + if (stg == NIL(graph_t)){ + /* This should never happen... just a safety feature */ + return; + } + stg1 = network_stg(network); + dcnet = network_dc_network(network); + modify_names = (stg1 != NIL(graph_t) && stg1 != stg); + + /* Get the names of the PI's and change names of the network PI */ + /* + * We have to be careful here... In an example, the PO name was the same + * as that of a next_state output name assigned by "nova". To be sure that + * things are always correct, we will first invalidate the names of the + * primary inputs and outputs by appending them. Then, we will add new + * corect names for PI's/PO's that were stored along with the STG. + */ + foreach_primary_input(network, gen, node){ + name = ALLOC(char, strlen(node_long_name(node))+10); + (void)sprintf(name, "LatchOut_%s", node_long_name(node)); + stg_change_dc_node_name(dcnet, node, name); + network_change_node_name(network, node, name); + } + + assert((name_array = stg_get_names(stg, 1)) != NIL(array_t)); + i = 0; + if (modify_names) + name_array1 = stg_get_names(stg1, 1); + foreach_primary_input(network, gen, node){ + if (network_is_real_pi(network, node) && + clock_get_by_name(network, node_long_name(node)) == 0){ + name = array_fetch(char *, name_array, i); + stg_change_dc_node_name(dcnet, node, name); + network_change_node_name(network, node, util_strsav(name)); + if (modify_names){ + name1 = array_fetch(char *, name_array1, i); + FREE(name1); + array_insert(char *, name_array1, i, util_strsav(name)); + } + i++; + } + } + if (network_num_pi(network) == 0) { + /* This is a special case - this routine is being called from + com_state_minimize. The network is empty, and there is no + dc network. */ + for (i = 0; i < array_n(name_array); i++) { + name = array_fetch(char *, name_array, i); + node = node_alloc(); + network_add_primary_input(network, node); + network_change_node_name(network, node, util_strsav(name)); + } + } + + + /* Change the PO names too --- append prefix to the names first */ + assert((name_array = stg_get_names(stg, 0)) != NIL(array_t)); + i = 0; + if (modify_names) + name_array1 = stg_get_names(stg1, 0); + foreach_primary_output(network, gen, node){ + name = ALLOC(char, strlen(node_long_name(node))+10); + (void)sprintf(name, "LatchIn_%s", node_long_name(node)); + stg_change_dc_node_name(dcnet, node, name); + network_change_node_name(network, node, name); + } + foreach_primary_output(network, gen, node){ + if (network_is_real_po(network, node)){ + name = array_fetch(char *, name_array, i); + stg_change_dc_node_name(dcnet, node, name); + network_change_node_name(network, node, util_strsav(name)); + if (modify_names){ + name1 = array_fetch(char *, name_array1, i); + FREE(name1); + array_insert(char *, name_array1, i, util_strsav(name)); + } + i++; + } + } + if (network_num_po(network) == 0) { + /* This is a special case - this routine is being called from + com_state_minimize. The network is empty, and there is no + dc network. */ + for (i = 0; i < array_n(name_array); i++) { + name = array_fetch(char *, name_array, i); + node = node_constant(0); + node->name = util_strsav(name); + network_add_node(network, node); + (void) network_add_primary_output(network, node); + } + } +} +#endif /* SIS */ diff --git a/sis/test/Makefile.am b/sis/test/Makefile.am new file mode 100644 index 0000000..77ad4b7 --- /dev/null +++ b/sis/test/Makefile.am @@ -0,0 +1,4 @@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libtest.a +libtest_a_SOURCES = end_test.c example.c init_test.c test.h test_int.h diff --git a/sis/test/Makefile.in b/sis/test/Makefile.in new file mode 100644 index 0000000..6338a81 --- /dev/null +++ b/sis/test/Makefile.in @@ -0,0 +1,368 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(libtest_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/test +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libtest_a_AR = $(AR) $(ARFLAGS) +libtest_a_LIBADD = +am_libtest_a_OBJECTS = end_test.$(OBJEXT) example.$(OBJEXT) \ + init_test.$(OBJEXT) +libtest_a_OBJECTS = $(am_libtest_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libtest_a_SOURCES) +DIST_SOURCES = $(libtest_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libtest.a +libtest_a_SOURCES = end_test.c example.c init_test.c test.h test_int.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/test/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/test/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libtest.a: $(libtest_a_OBJECTS) $(libtest_a_DEPENDENCIES) + -rm -f libtest.a + $(libtest_a_AR) libtest.a $(libtest_a_OBJECTS) $(libtest_a_LIBADD) + $(RANLIB) libtest.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/test/end_test.c b/sis/test/end_test.c new file mode 100644 index 0000000..16ca868 --- /dev/null +++ b/sis/test/end_test.c @@ -0,0 +1,19 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/test/end_test.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#include "sis.h" +#include "test_int.h" + + +/* + * called just before the program terminates + */ +end_test() +{ +} diff --git a/sis/test/example.c b/sis/test/example.c new file mode 100644 index 0000000..415e9e8 --- /dev/null +++ b/sis/test/example.c @@ -0,0 +1,82 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/test/example.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#include "sis.h" +#include "test_int.h" + + +/* + * Sample code for a command (with argument parsing) + */ + +com_test(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + node_t *f, *g, *g_not, *g_lit, *q, *t1, *t2, *r; + array_t *node_vec; + int c, use_complement; + + /* + * use util_getopt() to parse the arguments (in this case, a debug flag) + */ + use_complement = 0; + util_getopt_reset(); + while ((c = util_getopt(argc, argv, "c")) != EOF) { + switch(c) { + case 'c': + use_complement = 1; + break; + default: + goto usage; + } + } + + /* + * map all remaining arguments into node names, and find the nodes + */ + node_vec = com_get_nodes(*network, argc-util_optind+1, argv+util_optind-1); + if (array_n(node_vec) != 2) goto usage; + + f = array_fetch(node_t *, node_vec, 0); + g = array_fetch(node_t *, node_vec, 1); + + /* divide by the function (uncomplemented) */ + q = node_div(f, g, &r); + g_lit = node_literal(g, 1); + t1 = node_and(q, g_lit); + t2 = node_or(t1, r); + node_replace(f, t2); /* free's t2 */ + node_free(r); + node_free(t1); + node_free(q); + node_free(g_lit); + + if (use_complement) { + /* divide by the function (uncomplemented) */ + g_not = node_not(g); + q = node_div(f, g_not, &r); + g_lit = node_literal(g, 0); + t1 = node_and(q, g_lit); + t2 = node_or(t1, r); + node_replace(f, t2); /* free's t2 */ + node_free(r); + node_free(t1); + node_free(q); + node_free(g_lit); + } + + return 0; /* normal exit */ + +usage: + (void) fprintf(miserr, "usage: test [-c] n1 n2\n"); + (void) fprintf(miserr, " -c\t\tuse complement of n2 in division\n"); + return 1; /* error exit */ +} diff --git a/sis/test/init_test.c b/sis/test/init_test.c new file mode 100644 index 0000000..9f2af65 --- /dev/null +++ b/sis/test/init_test.c @@ -0,0 +1,20 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/test/init_test.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +#include "sis.h" +#include "test_int.h" + + +/* + * called when the program starts up + */ +init_test() +{ + com_add_command("_test", com_test, /* changes_network */ 1); +} diff --git a/sis/test/test.h b/sis/test/test.h new file mode 100644 index 0000000..a05d580 --- /dev/null +++ b/sis/test/test.h @@ -0,0 +1,12 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/test/test.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +/* + * definitions for routines exported from 'test' go here + */ diff --git a/sis/test/test_int.h b/sis/test/test_int.h new file mode 100644 index 0000000..7671a6a --- /dev/null +++ b/sis/test/test_int.h @@ -0,0 +1,15 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/test/test_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:52 $ + * + */ +/* + * definitions local to 'test' go here + */ + + +extern int com_test(); diff --git a/sis/timing/Makefile.am b/sis/timing/Makefile.am new file mode 100644 index 0000000..ea11d7f --- /dev/null +++ b/sis/timing/Makefile.am @@ -0,0 +1,8 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include + +noinst_LIBRARIES = libtiming.a +libtiming_a_SOURCES = com_timing.c timing_comp.c timing_graph.c \ + timing_seq.c timing_util.c timing_verify.c timing_int.h +dist_doc_DATA = timing.doc +EXTRA_DIST = timing_fast_comp.c diff --git a/sis/timing/Makefile.in b/sis/timing/Makefile.in new file mode 100644 index 0000000..b97452d --- /dev/null +++ b/sis/timing/Makefile.in @@ -0,0 +1,400 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +SOURCES = $(libtiming_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/timing +DIST_COMMON = $(dist_doc_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libtiming_a_AR = $(AR) $(ARFLAGS) +libtiming_a_LIBADD = +am_libtiming_a_OBJECTS = com_timing.$(OBJEXT) timing_comp.$(OBJEXT) \ + timing_graph.$(OBJEXT) timing_seq.$(OBJEXT) \ + timing_util.$(OBJEXT) timing_verify.$(OBJEXT) +libtiming_a_OBJECTS = $(am_libtiming_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libtiming_a_SOURCES) +DIST_SOURCES = $(libtiming_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -DSIS -I../include +noinst_LIBRARIES = libtiming.a +libtiming_a_SOURCES = com_timing.c timing_comp.c timing_graph.c \ + timing_seq.c timing_util.c timing_verify.c timing_int.h + +dist_doc_DATA = timing.doc +EXTRA_DIST = timing_fast_comp.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/timing/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/timing/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libtiming.a: $(libtiming_a_OBJECTS) $(libtiming_a_DEPENDENCIES) + -rm -f libtiming.a + $(libtiming_a_AR) libtiming.a $(libtiming_a_OBJECTS) $(libtiming_a_LIBADD) + $(RANLIB) libtiming.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(docdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-dist_docDATA \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/timing/com_timing.c b/sis/timing/com_timing.c new file mode 100644 index 0000000..013c43e --- /dev/null +++ b/sis/timing/com_timing.c @@ -0,0 +1,323 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/timing/com_timing.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +/* +############################################################################## +# Package developed by Narendra V. Shenoy (email shenoy@ic.berkeley.edu), # +# based on the clock package in SIS. # +# # +############################################################################## +*/ + +#ifdef SIS +#include "timing_int.h" + + +/* function definition + name: com_clock_optimize() + args: network, argc, argv + job: outermost routine for the clock optimization algorithm based on + binary search and Bellman-Ford iterations + return value: 0 normally + 1 wrong options or error in circuit + calls: tmg_network_to_graph(), + tmg_print_latch_graph() **Debug** + a bunch of set_*** flags for options + tmg_compute_optimal_clock(), + tmg_free_graph_structure() + + +*/ +int +com_clock_optimize(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c; + graph_t *latch_graph; + delay_model_t model; + double clock_cycle, set_up, hold, min_sep, max_sep; + + /* Initialize */ + /* ---------- */ + + util_getopt_reset(); + debug_type = NONE; + model = DELAY_MODEL_LIBRARY; + tmg_set_set_up((double)0); + tmg_set_hold((double)0); + tmg_set_min_sep((double)0); + tmg_set_max_sep((double)1); + tmg_set_gen_algorithm_flag(TRUE); + tmg_set_phase_inv(FALSE); + /* Parse input command line options */ + while (( c = util_getopt(argc, argv, "d:nS:H:m:M:BI")) != EOF) { + switch(c) { + case 'd': + switch(atoi(util_optarg)) { + case 0: + debug_type = ALL; + break; + case 1: + debug_type = LGRAPH; + break; + case 2: + debug_type = CGRAPH; + break; + case 3: + debug_type = BB; + break; + case 4: + debug_type = GENERAL; + break; + default: + debug_type = NONE; + break; + } + break; + case 'n': + model = DELAY_MODEL_UNIT_FANOUT; + break; + case 'S': /* Global set-up time */ + set_up = atof(util_optarg); + tmg_set_set_up(set_up); + break; + case 'H': /* Global Hold time */ + hold = atof(util_optarg); + tmg_set_hold(hold); + break; + case 'm': /* minimum phase separation */ + min_sep = atof(util_optarg); + if (min_sep > 1) goto c_opt_usage; + tmg_set_min_sep(min_sep); + break; + case 'M': /* maximum phase separation */ + max_sep = atof(util_optarg); + if (max_sep < min_sep) goto c_opt_usage; + if (max_sep > 1) goto c_opt_usage; + tmg_set_max_sep(max_sep); + break; + case 'B': /* Use binary search algorithm!! */ + /* Works only under certain conditions- use as debug + mechansism only!! */ + tmg_set_gen_algorithm_flag(FALSE); + break; + case 'I': /* A flag to indicate 2 phase clocking scheme + with phase 2 = inverted (phase 1) */ + tmg_set_phase_inv(TRUE); + break; + default: + goto c_opt_usage; + } + } + if(!timing_network_check(*network, model)) { + (void)fprintf(sisout, "Exiting\n!!"); + } + + (void)fprintf(sisout, "Starting: cpu_time = %s\n", + util_print_time(util_cpu_time())); + clock_set_current_setting(*network, SPECIFICATION); + + /* Construct the timing graph from the network */ + /* ------------------------------------------- */ + + latch_graph = tmg_network_to_graph(*network, model, OPTIMAL_CLOCK); + if (latch_graph == NIL(graph_t)) { + return 1; + } + (void)fprintf(sisout, "Graph built: cpu_time = %s\n", + util_print_time(util_cpu_time())); + if (HOST(latch_graph) == NIL(vertex_t )) { + (void)fprintf(sisout, "Error circuit has no primary inputs: \n"); + (void)fprintf(sisout, + "Current implementation requires host vertex for\n"); + (void)fprintf(sisout, "clock lower bounds!!\n"); + tmg_free_graph_structure(latch_graph); + return 1; + } + if(debug_type == LGRAPH || debug_type == ALL) { + tmg_print_latch_graph(latch_graph); + } + + /* Routine to compute optimal clocking. + Network is used only to update clock parameters*/ + /* ---------------------------------------------- */ + + clock_cycle = tmg_compute_optimal_clock(latch_graph, *network); + if (clock_cycle > 0) { + (void)fprintf(sisout, "Optimal clock = %.2lf cpu_time = %s\n", + clock_cycle, util_print_time(util_cpu_time())); + } + + /* Free memory associated with latch_graph */ + /* --------------------------------------- */ + + tmg_free_graph_structure(latch_graph); + return 0; + c_opt_usage: + (void)fprintf(sisout, "Usage: c_opt -[nBI] -[dSHmM]# \n"); + (void)fprintf(sisout, "\t -d: Debug option\n"); + (void)fprintf(sisout, "\t -n: Use unmapped circuit\n"); + (void)fprintf(sisout, "\t : unit delay with 0.2 per fanout\n"); + (void)fprintf(sisout, "\t -S: Set up time \n"); + (void)fprintf(sisout, "\t -H: Hold time \n"); + (void)fprintf(sisout, "\t -m: minimum separation between phases [0, 1)\n"); + (void)fprintf(sisout, "\t -M: Maximum separation between phases [m, 1)\n"); + (void)fprintf(sisout, "\t -B: Use binary search\n"); + (void)fprintf(sisout, "\t -I: 2 phase clock with phi and phibar\n"); + (void)fprintf(sisout, "defaults: no debug, mapped, S = 0, H = 0, m = 0\n"); + (void)fprintf(sisout, " : M = 1, G = TRUE, I = FALSE\n"); + return 1; +} + +/* function definition + name: com_clock_check() + args: **network, argc, **argv + job: verify if the clocking scheme specified with the network is valid + return value: 0 on success, 1 on failure + calls: tmg_network_to_graph(), + tmg_check_clocking_scheme(), + tmg_free_graph_structure() + +*/ +int +com_clock_check(network, argc, argv) +network_t **network; +int argc; +char **argv; +{ + int c, flag; + graph_t *latch_graph; + delay_model_t model; + double set_up, hold; + + /* Initialize */ + /* ---------- */ + + util_getopt_reset(); + debug_type = NONE; + model = DELAY_MODEL_LIBRARY; + tmg_set_set_up((double)0); + tmg_set_hold((double)0); + + /* Parse input command line options */ + /* -------------------------------- */ + + while (( c = util_getopt(argc, argv, "d:nS:H:")) != EOF) { + switch(c) { + case 'd': + switch(atoi(util_optarg)) { + case 0: + debug_type = ALL; + break; + case 1: + debug_type = LGRAPH; + break; + case 5: + debug_type = VERIFY; + break; + default: + debug_type = NONE; + break; + } + break; + case 'n': + model = DELAY_MODEL_UNIT_FANOUT; + break; + case 'S': /* Global set-up time */ + set_up = atof(util_optarg); + tmg_set_set_up(set_up); + break; + case 'H': /* Global Hold time */ + hold = atof(util_optarg); + tmg_set_hold(hold); + break; + default: + goto c_check_usage; + } + } + + if (network_num_internal(*network) == 0 || + network_num_latch(*network) == 0) { + (void)fprintf(sisout, "No memory elements\n"); + (void)fprintf(sisout, "exiting\n"); + return 0; + } + + if(model == DELAY_MODEL_LIBRARY) { + if(!lib_network_is_mapped(*network)) { + (void)fprintf(sisout, "Warning not all nodes are mapped. \n"); + goto c_check_usage; + } + } + + (void)fprintf(sisout, "Starting: cpu_time = %s\n", + util_print_time(util_cpu_time())); + + /* Construct the timing graph from the network */ + /* ------------------------------------------- */ + + clock_set_current_setting(*network, SPECIFICATION); + latch_graph = tmg_network_to_graph(*network, model, CLOCK_VERIFY); + if (latch_graph == NIL(graph_t)) { + return 1; + } + (void)fprintf(sisout, "Graph built: cpu_time = %s\n", + util_print_time(util_cpu_time())); + if (HOST(latch_graph) == NIL(vertex_t )) { + (void)fprintf(sisout, "Error circuit has no primary inputs: \n"); + (void)fprintf(sisout, + "Current implementation requires host vertex for\n"); + (void)fprintf(sisout, "clock lower bounds!!\n"); + tmg_free_graph_structure(latch_graph); + return 1; + } + if(debug_type == LGRAPH || debug_type == ALL) { + tmg_print_latch_graph(latch_graph); + } + + /* Routine to verify clock - shouldnt need the network any more*/ + /* ----------------------------------------------------------- */ + + if ((flag = tmg_check_clocking_scheme(latch_graph, *network))) { + (void)fprintf(sisout, "Circuit verified : Time = %s\n", + util_print_time(util_cpu_time())); + } else { + (void)fprintf(sisout, "Error circuit failed verification!!\n"); + } + + /* Free memory associated with latch_graph */ + /* --------------------------------------- */ + + tmg_free_graph_structure(latch_graph); + return (!flag); +c_check_usage: + (void)fprintf(sisout, "Usage: c_check -[dn] -[SH]# \n"); + (void)fprintf(sisout, "\t -d: Debug option\n"); + (void)fprintf(sisout, "\t -n: Use unmapped circuit\n"); + (void)fprintf(sisout, "\t : unit delay with 0.2 per fanout\n"); + (void)fprintf(sisout, "\t -S: Set up time \n"); + (void)fprintf(sisout, "\t -H: Hold time \n"); + (void)fprintf(sisout, "defaults: no debug, mapped, S = 0, H = 0\n"); + + return 1; +} + + +init_timing() +{ + (void)com_add_command("c_opt", com_clock_optimize, 1); + (void)com_add_command("c_check", com_clock_check, 0); +} + +end_timing() +{ +} +#endif /* SIS */ diff --git a/sis/timing/timing.doc b/sis/timing/timing.doc new file mode 100644 index 0000000..1d813c5 --- /dev/null +++ b/sis/timing/timing.doc @@ -0,0 +1,59 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/timing/timing.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +This is a package that is used for clock verification and optimal clock +computation. The circuit is assumed to have memory elements that can +i) flip-flops (falling or rising edge triggered) +ii) level-sensitive latches (active high or active low). +The gate model is a pin-to-pin delay model. Timing analysis uses static delay +computation. Each gate can have only one output. The clocking scheme has the +following restrictions +i) all phases must have the same frequency. In other words in a time interval +equal to the clock cycle, each phase must rise and fall only once. +ii) signals to the control inputs of memory elements have no logic associated +, i.e. they are one of the clock phases +iii) Clock skews if any must be provided by the user using a pre-defined +routine in the package. + +The package solve 2 problem associated with clocking +i) Clock verification- given a circuit and a proposed clocking scheme (i.e. +the clock cycle + rise /fall times of all the phases) check if the set-up and +hold constraints are met at every memory element. + +All primary inputs are assumed to arrive at t= 0 by default, relative to +the clock schedule; if the arrival time for a PI is set then it is used (i.e. +it gets tagged onto the edge weights). + +ii) Optimal clocking- given a circuit, relative ordering of the phase and +possible duty cycle constraints, find the minimum clock cycle and times for +the rise/fall of clock phases so that the circuit operates without any +set-up/hold errors. + + +An issue yet to be resolved is the delay model for gates. The pin-to-pin model +is used to come up with min and max delays from a latch to another. The issues +of how to handle CLK pin to DATA output pin, DATA in to DATA output pin are +still open. You are welcome to email your suggestions to me. Please note that +I may agree with what you say but the fixes will be only after making sure +that the model does not contradict any other assumptions in SIS over which I +have no control! + + +The timing package currently does not export any routines since they +assume a specific clocking scheme and specific circuit. + +The code for optimal clock computation can be speeded up considerably +if you have the octtools package and have the priority queue package (pq). +This enables certain heuristics to be used efficiently and the clock lower +bound computation often finishes much faster. + + +BUGS: send mail to shenoy@ic.berkeley.edu + + diff --git a/sis/timing/timing_comp.c b/sis/timing/timing_comp.c new file mode 100644 index 0000000..8cdd866 --- /dev/null +++ b/sis/timing/timing_comp.c @@ -0,0 +1,1702 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/timing/timing_comp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +#ifdef SIS +#include "timing_int.h" + +#define FEASIBLE 1 +#define SOLVE 2 + +/* function definition + name: tmg_compute_optimal_clock() + args: latch_graph, network + job: compute optimal clocking params + return value: - + calls: + tmg_clock_lower_bound(), + tmg_construct_clock_graph(), tmg_add_short_path_constraints(), + tmg_add_model_constraints(), tmg_add_phase_separation_constraints(), + tmg_print_constraint_graph(), + tmg_solve_constraints(), solve_gen_constraints(), + tmg_circuit_clock_update() + tmg_constraint_graph_free() +*/ + +double +tmg_compute_optimal_clock(latch_graph, network) +graph_t *latch_graph; +network_t *network; +{ + graph_t *clock_graph; + phase_t *phase; + double clock, clock_lb; + + + clock_lb = 0; + clock_lb = tmg_clock_lower_bound(latch_graph); + (void)fprintf(sisout, "Clock lower bound found %.2lf : cpu_time = %s\n", + clock_lb, util_print_time(util_cpu_time())); + + /* Construct the clock graph - a graph with a vertex for rise/ + fall of each phase. The long path constraints are added now*/ + /* ---------------------------------------------------------- */ + + clock_graph = tmg_construct_clock_graph(latch_graph, clock_lb); + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "Only long paths: \n"); + tmg_print_constraint_graph(clock_graph); + (void)fprintf(sisout, "\n\n"); + } + + /* Add the short path constraints for each edge */ + /* -------------------------------------------- */ + + tmg_add_short_path_constraints(clock_graph, latch_graph); + + /* Get the last edge (e_k)- recall 0 (ref) vertex is also in table*/ + /* -------------------------------------------------------------- */ + + phase = PHASE_LIST(clock_graph)[NUM_PHASE(clock_graph) -1]; + + /* Add other constraints */ + /* --------------------- */ + + tmg_add_model_constraints(latch_graph, clock_graph, phase->fall); + tmg_add_phase_separation_constraints(latch_graph, clock_graph, phase->fall); + + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "Long and Short paths\n"); + tmg_print_constraint_graph(clock_graph); + (void)fprintf(sisout, "\n\n"); + } + + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "clock lower bound = %.2lf\n", clock_lb); + } + + /* Solve the optimization problem */ + /* ------------------------------ */ + + if (tmg_get_gen_algorithm_flag()) { + clock = tmg_solve_gen_constraints(clock_graph, phase->fall, clock_lb); + } else { + clock = tmg_solve_constraints(clock_graph, phase->fall, clock_lb); + } + if (clock > 0) { + + /* Set the values in the tmg_circuit */ + /* ----------------------------- */ + + tmg_circuit_clock_update(latch_graph, clock_graph, network, clock); + } + + /* Free memory associated with the clock_graph */ + /* ------------------------------------------- */ + + tmg_constraint_graph_free(clock_graph); + return clock; +} + +/* function definition + name: tmg_clock_lower_bound() + args: graph_t *g + job: finds a lower bound for the clock cycle using Lawlers + binary search + method. + return value: double + calls: guess_lower_bound(), + tmg_all_negative_cycles() +*/ +double +tmg_clock_lower_bound(g) +graph_t *g; +{ + double cur_clock, new_clock, clock_ub, clock_lb; + + clock_ub = 0; + new_clock= tmg_guess_clock_bound(g); + clock_lb = new_clock; + while(TRUE) { + cur_clock = new_clock; + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Trying %.4lf ", cur_clock); + } + if (tmg_all_negative_cycles(g, cur_clock)) { /* Negative cycle */ + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Success - try lower \n"); + } + clock_ub = cur_clock; + } else { + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Failure - try higher \n"); + } + clock_lb = cur_clock; + } + if (ABS(clock_ub - clock_lb) < EPS2) break; + if (clock_ub > clock_lb) { + new_clock = (clock_ub + clock_lb)/2; + } else { + new_clock *= 2; + } + } + return clock_ub; +} + +/* function definition + name: tmg_guess_clock_bound() + args: graph_t *g + job: uses DFS to guess lower bound on clock cycle + return value: double + calls: guess_clock_bound_recursive() +*/ +double +tmg_guess_clock_bound(g) +graph_t *g; +{ + double bound1, bound2; + lsGen gen; + vertex_t *v, *host; + + /* init */ + /* ---- */ + + host = HOST(g); + foreach_vertex(g, gen, v) { + Rv(v) = -1; + Wv(v) = 0; + COPT_DIRTY(v) = FALSE; + } + if (host == NIL(vertex_t)) { + host = v; + } + bound1 = 0; + bound2 = 0; + Rv(host) = 0; + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "guessing a bound for clock cycle\n"); + } + tmg_guess_clock_bound_recursive(host, &bound1, &bound2); + if (bound1 < bound2) { + (void)fprintf(sisout, "bound1 = %.2lf bound2 = %.2lf \n", + bound1, bound2); + bound1 = bound2; + } + assert(bound1 > 0); + + return bound1; +} + +/* function definition + name: tmg_guess_clock_bound_recursive() + args: vertex_t *u, double *b1, *b2 + job: Recursive DFS + return value: - + calls: +*/ +tmg_guess_clock_bound_recursive(u, b1, b2) +vertex_t *u; +double *b1, *b2; +{ + lsGen gen; + edge_t *e; + vertex_t *v; + int den; + + + (*b2) = MAX((*b2), Wv(u)/(Rv(u)+1)); + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Path bound = %.4lf\n", *b2); + } + COPT_DIRTY(u) = TRUE; + foreach_out_edge(u, gen, e){ + v = g_e_dest(e); + + /* Check if v has been visited before*/ + /* --------------------------------- */ + + if (COPT_DIRTY(v)) { + + /* Check if v is on DFS stack */ + /* -------------------------- */ + + if (Rv(v) > 0) { + if ((den = Rv(u) + Ke(e) - Rv(v)) == 0) { + (void)fprintf(sisout, + "Error cycle without memory elements\n"); + } + if (den > 0) { + (*b1) = MAX((*b1), (Wv(u) + De(e) -Wv(v))/den); + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Cycle bound = %.4lf\n", *b1); + } + } + } + } else { + Rv(v) = Rv(u) + Ke(e); + Wv(v) = Wv(u) + De(e); + tmg_guess_clock_bound_recursive(v, b1, b2); + } + } + /* Remove u from DFS stack */ + /* ----------------------- */ + Rv(u) = -1; +} + + +#ifdef OCT + +#define UTILITY_H +#include "pq.h" +#include "da.h" +#undef UTILITY_H + +/* function definition + name: tmg_all_negative_cycles() + args: graph_t *g, double c + job: uses Bellman-Ford to test if given c causes a positive cycle in g + return value: 0 if there is a positive cycle + 1 if all cycles are negative or 0 weighted + + calls: +*/ +#define NUM_CYCLE 5 +int +tmg_all_negative_cycles(g, c) +graph_t *g; +double c; +{ + vertex_t *v, *u; + char *dummy; + st_table *table; + st_generator *sgen; + pq_t *tree; + edge_t *e; + int num_v, flag, i, my_pq_cmp(); + double C[2], c_eps, val; + lsGen gen; + + num_v = lsLength(g_get_vertices(g)); + + /* Initialize all edges with appropriate weights*/ + /* -------------------------------------------- */ + + C[0] = 0; + C[1] = c; + c_eps = c + EPS1; + /* Weigh edges */ + /* ------------ */ + foreach_edge(g, gen, e) { + We(e) = De(e) - C[Ke(e)]; + } + /* Init vertices */ + /* ------------- */ + foreach_vertex (g, gen, u) { + Wv(u) = -INFTY; + PARENT(u) = NIL(vertex_t); + } + + Wv(HOST(g)) = 0; + tree = pq_init_queue(my_pq_cmp); + pq_insert_fast(tree, (char *)HOST(g), (char *)HOST(g)); + foreach_vertex (g, gen, v) { + if (TYPE(v) == LATCH && PHASE(v) == 1) { + Wv(v) = 0; + pq_insert_fast(tree, (char *)v, (char *)v); + } + } + + /* Repeat num_v times */ + /* ------------------ */ + for (i = 0; i < num_v; i++) { + /* flag to detect early convergence or failure therof */ + /* -------------------------------------------------- */ + flag = TRUE; + + /* Use table to hash vertices that have changed */ + /* -------------------------------------------- */ + table = st_init_table(st_ptrcmp, st_ptrhash); + while(!pq_empty(tree)) { + pq_pop(tree, (char **)&u); + foreach_out_edge (u, gen, e) { + v = g_e_dest(e); + if ((val = Wv(u) + We(e)) > Wv(v)) { + flag = FALSE; + if (val > c_eps) { /* path requires more that c units/cycle + -----------------------------------*/ + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, + "Positive path exceeding c \n"); + } + pq_free_queue(tree); + st_free_table(table); + lsFinish(gen); + return FALSE; + } + Wv(v) = val; + + /* Keep track of one parent in hope for cycle detection */ + /* ---------------------------------------------------- */ + PARENT(v) = u; + st_insert(table, (char *)v, (char *)v); /* Hash it!! */ + /* ------------------------------------------------- */ + } + } + } + pq_free_queue(tree); + if (flag) { + st_free_table(table); + break; + } else { + /* Build priority queue of hashed vertices with hope of detecting + > c_eps */ + /* ----------------------------------------------------------- */ + tree = pq_init_queue(my_pq_cmp); + st_foreach_item(table, sgen, (char **)&u, &dummy) { + pq_insert_fast(tree, (char *)u, (char *)u); + } + st_free_table(table); + if ((i%NUM_CYCLE) == 0) { + if (cycle_in_graph(tree, g)) { + pq_free_queue(tree); + flag = FALSE; + break; + } + } + } + } + + + /* check for positive cycle */ + /* ---------------------------- */ + return flag; +} + + +static int +my_pq_cmp(k1, k2) +char *k1, *k2; +{ + vertex_t *v1, *v2; + + v1 = (vertex_t *)(k1); + v2 = (vertex_t *)(k2); + + if (ABS(Wv(v1) - Wv(v2)) < EPS1) return 0; + if (Wv(v1) < Wv(v2)) return -1; + return 1; +} + +#define NUM_POP 5 + +int +cycle_in_graph(tree, g) +pq_t *tree; +graph_t *g; +{ + lsGen gen; + vertex_t *u, *v, **pop_array; + int i, cycle_found; + + pop_array = ALLOC(vertex_t *, NUM_POP); + for (i = 0; i < NUM_POP; i++) { + pop_array[i] = NIL(vertex_t); + } + cycle_found = FALSE; + i = 0; + while ( i < NUM_POP && !pq_empty(tree)) { + foreach_vertex (g, gen, v) { + COPT_DIRTY(v) = FALSE; + } + pq_pop(tree, (char **)&u); + pop_array[i] = u; + i++; + while (TRUE) { + COPT_DIRTY(u) = TRUE; + v = PARENT(u); + if (v == NIL(vertex_t)) { + break; + } + if (COPT_DIRTY(v)) { + cycle_found = TRUE; + break; + } + u = v; + } + if (cycle_found) break; + } + + if (cycle_found) { + FREE(pop_array); + return TRUE; + } else { + for (i = 0; i < NUM_POP; i++) { + if (pop_array[i] != NIL(vertex_t)) { + pq_insert_fast(tree, (char *)pop_array[i], + (char *)pop_array[i]); + } + } + FREE(pop_array); + return FALSE; + } +} + +#else + +/* function definition + name: all_negative_cycles() + args: graph_t *g, double c + job: uses Bellman-Ford to test if given c causes a positive cycle in g + return value: 0 if there is a positive cycle + 1 if all cycles are negative or 0 weighted + + calls: +*/ +int +tmg_all_negative_cycles(g, c) +graph_t *g; +double c; +{ + vertex_t *v, *u; + edge_t *e; + int num_v, flag, i; + double C[2], c_eps, val; + lsGen gen; + + num_v = lsLength(g_get_vertices(g)); + + /* Initialize all edges with appropriate weights*/ + /* -------------------------------------------- */ + + C[0] = 0; + C[1] = c; + c_eps = c + EPS; + foreach_edge(g, gen, e) { + We(e) = De(e) - C[Ke(e)]; + } + foreach_vertex(g, gen, u) { + Wv(u) = -INFTY; + } + + Wv(HOST(g)) = 0; + + for (i = 0; i < num_v; i++) { + + /* flag to detect early convergence */ + /* -------------------------------- */ + + flag = TRUE; + foreach_edge(g, gen, e) { + v = g_e_dest(e); + u = g_e_source(e); + if ((val = Wv(u) + We(e)) > Wv(v)) { + flag = FALSE; + if (val > c_eps) { + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Positive path exceeding c \n"); + } + lsFinish(gen); + return FALSE; + } + Wv(v) = val; + } + } + if (flag) break; + } + + return flag; +} + +#endif + +/* function definition + name: tmg_construct_clock_graph() + args: latch_graph + job: constructs the clock graph (a vertex for each + transition of a phase + return value: graph_t * + calls: tmg_alloc_cgraph(), + tmg_gen_constraints_from(), + +*/ + +graph_t * +tmg_construct_clock_graph(lg, clock_lb) +graph_t *lg; +double clock_lb; +{ + graph_t *cg; + lsGen gen; + vertex_t *u, *p1, *v; + edge_t *e; + int i, from_index; + array_t **array_list, *zarray, *red, *black; + + /* Allocate constraint graph + ZERO vertex */ + /* --------------------------------------- */ + + cg = g_alloc(); + cg->user_data = (gGeneric)(tmg_alloc_cgraph()); + tmg_alloc_phase_vertices(cg, lg); + + ZERO_V(cg) = g_add_vertex(cg); + ZERO_V(cg)->user_data = (gGeneric)ALLOC(c_node_t, 1); + PID(ZERO_V(cg)) = 0; + array_list = ALLOC(array_t *, 2 * NUM_PHASE(cg)); + for (i = 0; i < 2 * NUM_PHASE(cg); i++) { + array_list[i] = NIL(array_t); + } + foreach_vertex(lg, gen, v) { + if (TYPE(v) != LATCH) continue; + from_index = get_index(v, FROM, cg); + if (array_list[from_index] == NIL(array_t)) { + array_list[from_index] = array_alloc(vertex_t *, 0); + } + array_insert_last(vertex_t *, array_list[from_index], v); + } + + /* Get edges with Ke(e) = 1 and Ke(e) = 0 */ + /* -------------------------------------- */ + + red = array_alloc(edge_t *, 0); + black = array_alloc(edge_t *, 0); + foreach_edge (lg, gen, e) { + if (Ke(e)) { + array_insert_last(edge_t *, red, e); + } else { + array_insert_last(edge_t *, black, e); + } + } + + for (i = 0; i < 2 * NUM_PHASE(cg); i++) { + if (array_list[i] != NIL(array_t)) { + foreach_vertex(lg, gen, v) { + Wv(v) = -INFTY; + Rv(v) = 0; + COPT_DIRTY(v) = FALSE; + } + p1 = get_vertex_from_index(cg, i); + if (tmg_get_phase_inv() && i == 1) { + + /* Special case handling!! */ + /* ----------------------- */ + + p1 = ZERO_V(cg); + } + tmg_gen_constraints_from(lg, cg, array_list[i], p1, clock_lb, + red, black); + array_free(array_list[i]); + } + } + FREE(array_list); + + /* Add long path constraints from primary inputs. Inputs assumed stable + for a clock cycle */ + /* ------------------ */ + + u = HOST(lg); + p1 = ZERO_V(cg); + foreach_vertex(lg, gen, v) { + Wv(v) = -INFTY; + Rv(v) = 0; + COPT_DIRTY(v) = FALSE; + } + zarray = array_alloc(vertex_t *, 0); + array_insert_last(vertex_t *, zarray, u); + tmg_gen_constraints_from(lg, cg, zarray, p1, clock_lb, red, black); + array_free(zarray); + array_free(red); array_free(black); + return cg; +} + +/* function definition + name: tmg_gen_constraints_from() + args: latch_graph, constraint_graph, array of latches on given + phase event, corresponding constraint vertex, lower_bound on + clock, array of red edges + job: Extract constraints between clock event represented by p1 and + all possible latches reachable by the set of latches from + latch_array + return value: - + calls: +*/ + +tmg_gen_constraints_from(lg, cg, latch_array, p1, clock_lb, red, black) +graph_t *lg, *cg; +vertex_t *p1; +array_t *latch_array; +double clock_lb; +array_t *red, *black; +{ + edge_t **e_array; + lsGen gen; + edge_t *e; + vertex_t *u, *v, *p2; + int num_v, i, to_index, current_key, more_to_come, j, local_converged; + double *value, val; + + /* Cache the possible edges from p1 */ + /* -------------------------------- */ + + e_array = ALLOC(edge_t *, 2 * NUM_PHASE(cg)); + for (i = 0; i < 2 * NUM_PHASE(cg); i++) { + e_array[i] = NIL(edge_t); + } + + /* Initialize delays from set of latches that start on p1 */ + /* ------------------------------------------------------ */ + + for (i = 0; i < array_n(latch_array); i++) { + u = array_fetch(vertex_t *, latch_array, i); +/* if (LTYPE(u) == FFF || LTYPE(u) == FFR) continue;*/ + if (TYPE(u) == LATCH) { + Wv(u) = tmg_max_clock_skew(u); + } else { + Wv(u) = 0.0; + } + Rv(u) = 0; + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "From %d :\n", ID(u)); + } + } + + /* The remaining section of this subroutine follows the paper by + Dr. T. G. Szymanski in DAC 92 for extracting the constraints + efficiently */ + /* ----------------------------------------------------------- */ + + current_key = 0; + num_v = lsLength(g_get_vertices(lg)); + more_to_come = TRUE; + + while (more_to_come) { + more_to_come = FALSE; + foreach_vertex (lg, gen, v) { + if (Rv(v) == current_key) { + PREV_Wv(v) = Wv(v); + } + } + + for (i = 0; i < num_v; i++) { + local_converged = TRUE; + for (j = 0; j < array_n(black); j++) { + e = array_fetch(edge_t *, black, j); + u = g_e_source(e); + v = g_e_dest(e); + if (TYPE(v) == NNODE || Wv(u) == -INFTY) continue; + if (TYPE(u) == NNODE && Wv(u) < 0) continue; + if ((Wv(u) + De(e) - current_key * clock_lb) > + Wv(v) - Rv(v) * clock_lb) { + Wv(v) = Wv(u) + De(e); + Rv(v) = Rv(u); + COPT_DIRTY(v) = TRUE; + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, + "%d (%.2lf)->(%.2lf )-> %d (%.2lf)\n", + ID(u), Wv(u), De(e), ID(v), + Wv(v)-Rv(v)*clock_lb); + } + local_converged = FALSE; + } + } + if (local_converged) { + break; + } + } + assert(local_converged); /* Sanity check */ + foreach_vertex (lg, gen, v) { + if (TYPE(v) == NNODE) continue; + if (!COPT_DIRTY(v)) continue; + if (Rv(v) == current_key) { + to_index = get_index(v, TO, cg); + if ((e = e_array[to_index]) == NIL(edge_t)) { + p2 = get_vertex(v, TO, cg); + if (!g_get_edge(p2, p1, &e)) { + e->user_data = (gGeneric)tmg_alloc_cedge(); + } + e_array[to_index] = e; + } + val = Wv(v) + tmg_get_set_up(v) - tmg_min_clock_skew(v); + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "to %d : %.2lf - %d c\n", ID(v), + val, current_key); + } + if (st_lookup(CONS1(e), (char *)current_key, + (char **)&value)) { + if (*value < val) { + *value = val; + } + } else { + value = ALLOC(double, 1); + *value = val; + st_insert(CONS1(e), (char *)current_key, (char *)value); + } + PREV_Wv(v) = Wv(v); + } + } + for (i = 0; i < array_n(red); i++) { + e = array_fetch(edge_t *, red, i); + u = g_e_source(e); + if ((LTYPE(u) == FFF || LTYPE(u) == FFR) && COPT_DIRTY(u)) + continue; + v = g_e_dest(e); + if (TYPE(v) == NNODE) continue; + if (TYPE(u) == NNODE && Wv(u) < 0) continue; + if ((PREV_Wv(u) + De(e) - (current_key + 1) * clock_lb) + > (Wv(v) - Rv(v) * clock_lb + EPS)) { + Wv(v) = PREV_Wv(u) + De(e); + Rv(v) = current_key + 1; + COPT_DIRTY(v) = TRUE; + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, + "%d (%.2lf)->(%.2lf)-> %d (%.2lf)\n", + ID(u), Wv(u), De(e) - clock_lb, ID(v), + Wv(v)-Rv(v)*clock_lb); + } + more_to_come = TRUE; + } + } + current_key++; + } + FREE(e_array); +} + + +/* function definition + name: tmg_add_short_path_constraints() + args: clock_graph, latch_graph + job: Adds the short path constraints for each edge + Does a conservative job by extracting constraints for + each edge only + return value: - + calls: g_get_edge() +*/ +tmg_add_short_path_constraints(cg, lg) +graph_t *cg, *lg; +{ + edge_t *cedge, *ledge; + double **array; + lsGen gen; + int i, j, from_id, to_id, dim, k; + vertex_t *u, *v; + vertex_t *p1, *p2; + + dim = 2 * NUM_PHASE(cg); + array = ALLOC(double *, dim); + for (i = 0; i < dim ; i++) { + array[i] = ALLOC(double, dim); + for (j = 0; j < dim; j++) { + array[i][j] = INFTY; + } + } + foreach_edge(lg, gen, ledge) { + u = g_e_source(ledge); + v = g_e_dest(ledge); + if (TYPE(u) != LATCH || TYPE(v) != LATCH) continue; + from_id = get_index(u, FROM, cg); + to_id = get_index(v, TO, cg); + array[from_id][to_id] = MIN(array[from_id][to_id], + tmg_min_clock_skew(u) + de(ledge) - + tmg_get_hold(v) - tmg_max_clock_skew(v)); + } + for (i = 0; i < dim; i++) { + for (j = 0; j < dim; j++) { + if (array[i][j] < INFTY) { + p1 = get_vertex_from_index(cg, i); + p2 = get_vertex_from_index(cg, j); + if (!g_get_edge(p1, p2, &cedge)) { + cedge->user_data = (gGeneric)tmg_alloc_cedge(); + } + if (CONS2(cedge) == NIL(double)) { + CONS2(cedge) = ALLOC(double, 2); + for (k = 0; k < 2; k++) { + CONS2(cedge)[k] = INFTY; + } + } + if (ABS(PID(p1)) < ABS(PID(p2))) { + CONS2(cedge)[1] = MIN(CONS2(cedge)[1], array[i][j]); + } else { + CONS2(cedge)[0] = MIN(CONS2(cedge)[0], array[i][j]); + } + } + } + FREE(array[i]); + } + FREE(array); +} + + +/* function definition + name: tmg_solve_constraints() + args: clock_graph, vertex (e_k) + job: Finds the minimum c (>= clock_lb) for which the constraints are + satisfied. Contains the binary search routine (while(1) { ...}) + return value: double (clock cycle) + calls: tmg_is_feasible() +*/ + +double +tmg_solve_constraints(cg, v0, clock_lb) +graph_t *cg; +vertex_t *v0; +double clock_lb; +{ + double cur_clock, clock_ub; + + clock_ub = INFTY; + cur_clock = clock_lb; + while (TRUE) { + (void)fprintf(sisout, "trying %.2lf \n", cur_clock); + if (!tmg_is_feasible(cg, cur_clock, v0)) { + clock_lb = cur_clock; + if (clock_ub == INFTY) { + cur_clock = 2 * cur_clock; + } else { + cur_clock = (clock_lb + clock_ub)/2; + } + } else { + if (clock_ub - clock_lb < EPS) break; + clock_ub = cur_clock; + } + cur_clock = (clock_ub + clock_lb)/2; + } + + tmg_print_graph_solution(cg); + return cur_clock; +} + +/* function definition + name: tmg_is_feasible() + args: clock_graph, clock_cycle, e_k + job: Check if the clock_cycle is feasible. + + return value: 1 on success, 0 on failure + calls: tmg_evaluate_right_hand_side(), + tmg_print_graph_solution() +*/ +int +tmg_is_feasible(g, c, v0) +graph_t *g; +double c; +vertex_t *v0; +{ + edge_t *e; + vertex_t *u, *v; + lsGen gen; + int num_it, flag, i; + + if (c == 0) return FALSE; + tmg_evaluate_right_hand_side(g, c); + + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "LP constraints evaluated for c = %.2lf\n", c); + tmg_print_constraints(g); + } + + /* Initialize for Bellman-Ford on Constraint Graph */ + /* ----------------------------------------------- */ + + foreach_vertex(g, gen, v){ + P(v) = INFTY; + } + P(ZERO_V(g)) = 0; + + /* Bellman Ford carried out here */ + /* ----------------------------- */ + + num_it = lsLength(g_get_vertices(g)); + for (i = 0; i < num_it; i++) { + flag = TRUE; + foreach_edge(g, gen, e) { + if (IGNORE(e)) continue; + v = g_e_dest(e); + u = g_e_source(e); + if (P(v) > P(u) + WEIGHT(e)) { + P(v) = P(u) + WEIGHT(e); + flag = FALSE; + } + } + if (flag) break; + } + + /* Check for negative cycle */ + /* ------------------------ */ + + if (debug_type == BB || debug_type == ALL) { + tmg_print_graph_solution(g); + } + return flag; +} + + +/* function definition + name: tmg_print_constraint_graph() + args: + job: prints the constraint graph + return value: - + calls:- +*/ +tmg_print_constraint_graph(g) +graph_t *g; +{ + edge_t *e; + vertex_t *u, *v; + char *dummy; + st_generator *sgen; + double *value; + lsGen gen; + int i, flag; + + foreach_edge(g, gen, e) { + if (IGNORE(e)) continue; + flag = TRUE; + u = g_e_source(e); + v = g_e_dest(e); + if (PID(v) > 0) { + (void)fprintf(sisout, "r(%d) - ", PID(v)); + } else if (PID(v) < 0) { + (void)fprintf(sisout, "e(%d) - ", -PID(v)); + } else { + (void)fprintf(sisout, "ZERO - "); + } + if (PID(u) > 0) { + (void)fprintf(sisout, "r(%d)\n", PID(u)); + } else if (PID(u) < 0) { + (void)fprintf(sisout, "e(%d)\n", -PID(u)); + } else { + (void)fprintf(sisout, "ZERO \n"); + } + + if (EVAL(e) == TRUE) { + if (flag) { + (void)fprintf(sisout, "\t <= \n"); + flag = FALSE; + } + (void)fprintf(sisout, "FIXED \n"); + (void)fprintf(sisout, "\t %.2lf \n", FIXED(e)); + } + + if (ABS(DUTY(e)) <= 1) { + if (flag) { + (void)fprintf(sisout, "\t <= \n"); + flag = FALSE; + } + (void)fprintf(sisout, "DUTY \n"); + (void)fprintf(sisout, "\t %.2lf c\n", DUTY(e)); + } + if (st_count(CONS1(e)) > 0) { + if (flag) { + (void)fprintf(sisout, "\t <= \n"); + flag = FALSE; + } + (void)fprintf(sisout, "LP \n"); + st_foreach_item(CONS1(e), sgen, (char **)&dummy, (char **)&value) { + i = (int)dummy; + (void)fprintf(sisout, "\t -%.2lf + %d c\n", *value, i); + } + } + if (CONS2(e) != NIL(double)) { + if (flag) { + (void)fprintf(sisout, "\t <= \n"); + flag = FALSE; + } + (void)fprintf(sisout, "SP \n"); + for (i = 0; i < 2; i++) { + (void)fprintf(sisout, "\t %.2lf + %d c\n", CONS2(e)[i], i); + } + } + } +} + + +/* function definition + name: tmg_add_model_constraints() + args: + job: adds the constraints ZERO <= v <= v0 forall vertices except the + ZERO and v0 vertex. Also make sure ZERO + c = v0 + return value: + calls: +*/ + +tmg_add_model_constraints(lg, cg, v0) +graph_t *lg, *cg; +register vertex_t *v0; +{ + lsGen gen; + vertex_t *v; + edge_t *e, *edge_z2ek, *edge_ek2z; + + /* Add constraints */ + /* --------------- */ + + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "Adding constraints\n"); + } + foreach_vertex(cg, gen, v){ + if (v == v0 || v == ZERO_V(cg)) continue; + + /* Add constraints so that ZERO_V <= v */ + /* ----------------------------------- */ + + if (!g_get_edge(v, ZERO_V(cg), &e)) { + e->user_data = (gGeneric)tmg_alloc_cedge(); + } + if (debug_type == BB || debug_type == ALL) { + if (PID(v) > 0) { + (void)fprintf(sisout, "r(%d) >= 0\n", PID(v)); + } else if (PID(v) < 0) { + (void)fprintf(sisout, "e(%d) >= 0\n", -PID(v)); + } + } + if (EVAL(e) == NOT_SET) { + FIXED(e) = 0; + EVAL(e) = TRUE; + } else if (EVAL(e) == TRUE) { + FIXED(e) = MIN(FIXED(e), 0); + } + + /* Add constraints so that v <= v0*/ + /* ------------------------------ */ + + if (!g_get_edge(v0, v, &e)) { + e->user_data = (gGeneric)tmg_alloc_cedge(); + } + if (debug_type == BB || debug_type == ALL) { + if (PID(v) > 0) { + (void)fprintf(sisout, "r(%d) <= e(%d)\n", + PID(v), array_n(CL(lg))); + } else if (PID(v) < 0) { + (void)fprintf(sisout, "e(%d) <= e(%d)\n", + -PID(v), array_n(CL(lg))); + } + } + if (EVAL(e) == NOT_SET) { + FIXED(e) = 0; + EVAL(e) = TRUE; + } else if (EVAL(e) == TRUE) { + FIXED(e) = MIN(FIXED(e), 0); + } + } + + /* Force ZERO_V and v0 to be separated by exactly c. */ + /* Add v0 <= ZERO_V + c */ + /* ------------------------------------------------- */ + + if (!g_get_edge(ZERO_V(cg), v0, &edge_z2ek)) { + edge_z2ek->user_data = (gGeneric)tmg_alloc_cedge(); + } + DUTY(edge_z2ek) = 1; + + /* ZERO <= v0 - c */ + /* -------------- */ + + if (!g_get_edge(v0, ZERO_V(cg), &edge_ek2z)) { + edge_ek2z->user_data = (gGeneric)tmg_alloc_cedge(); + } + DUTY(edge_ek2z) = -1; + +} + +/* function definition + name: tmg_add_phase_separation_constraints() + args: + job: add the phase separartion constraints (duty cycle or + fixed separation) + return value: + calls: +*/ +tmg_add_phase_separation_constraints(lg, cg, v0) +graph_t *lg, *cg; +vertex_t *v0; +{ + double min_sep, max_sep; + int i; + phase_t *phase; + edge_t *e; + vertex_t *old_v; + + /* Add the constraints e1 <= e2 <= e3...<= ek and min and + max separations */ + /* ----------------------------------------------------- */ + + old_v = NIL(vertex_t); + min_sep = tmg_get_min_sep(); + max_sep = tmg_get_max_sep(); + + for (i = 0; i < array_n(CL(lg)); i++) { + phase = PHASE_LIST(cg)[i]; + + /* Add minimum and maximum constraint separation*/ + /* -------------------------------------------- */ + + if (!g_get_edge(phase->rise, phase->fall, &e)) { + e->user_data = (gGeneric)tmg_alloc_cedge(); + } + DUTY(e) = MIN(DUTY(e), max_sep); + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "e(%d) - r(%d) <= %.2lf * c\n", + -PID(phase->fall), PID(phase->rise), max_sep); + } + if (!g_get_edge(phase->fall, phase->rise, &e)) { + e->user_data = (gGeneric)tmg_alloc_cedge(); + } + DUTY(e) = MIN(DUTY(e), -min_sep); + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "r(%d) - e(%d) <= %.2lf * c\n", + PID(phase->rise), -PID(phase->fall), -min_sep); + } + + /* e(k-1) <= e(k) */ + /* -------------- */ + + if (old_v != NIL(vertex_t)) { + if (!g_get_edge(phase->fall, old_v, &e)) { + e->user_data = (gGeneric)tmg_alloc_cedge(); + } + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "e(%d) - e(%d) <= 0\n", -PID(old_v), + -PID(phase->fall)); + } + if (EVAL(e) == NOT_SET) { + FIXED(e) = 0; + EVAL(e) = TRUE; + } else { + FIXED(e) = MIN(FIXED(e), 0); + } + } + old_v = phase->fall; + } +} + +/* function definition + name: tmg_evaluate_right_hand_side() + args: + job: evaluate the edge weights for the given clock cycle + and keep the minimum + weight + return value: + calls: +*/ +tmg_evaluate_right_hand_side(g, c) +graph_t *g; +double c; +{ + lsGen gen; + edge_t *e; + char *dummy; + double *value, C[2]; + int i; + st_generator *sgen; + + C[0] = 0; C[1] = c; + foreach_edge(g, gen, e) { + if (EVAL(e) == NOT_SET) { + WEIGHT(e) = INFTY; + } else { + WEIGHT(e) = FIXED(e); + } + + if (ABS(DUTY(e)) <= 1) { + WEIGHT(e) = MIN(WEIGHT(e), DUTY(e) * c); + } + + if (st_count(CONS1(e)) > 0) { + st_foreach_item(CONS1(e), sgen, (char **)&dummy, (char **)&value) { + i = (int)dummy; + WEIGHT(e) = MIN(WEIGHT(e), -(*value) + i * c); + } + } + if (CONS2(e) != NIL(double)) { + for (i = 0; i < 2; i++) { + if (CONS2(e)[i] < INFTY) { + WEIGHT(e) = MIN(WEIGHT(e), CONS2(e)[i] + C[i]); + } + } + } + if (WEIGHT(e) == INFTY) { + /* No constraint so far - disregard it!!*/ + IGNORE(e) = TRUE; + } + } +} + +/* function definition + name: tmg_print_constraints() + args: + job: print the constraints once the right hand sides + have been evaluated + return value: + calls: +*/ +tmg_print_constraints(g) +graph_t *g; +{ + lsGen gen; + edge_t *e; + vertex_t *u, *v; + + foreach_edge(g, gen, e) { + if (IGNORE(e)) continue; + v = g_e_dest(e); + u = g_e_source(e); + if (PID(v) == 0) { + if (PID(u) > 0) { + (void)fprintf(sisout, " -r(%d) =< %.2lf\n", PID(u), WEIGHT(e)); + }else if (PID(u) < 0) { + (void)fprintf(sisout, " -e(%d) =< %.2lf\n", -PID(u), + WEIGHT(e)); + } + continue; + } + if (PID(u) == 0) { + if (PID(v) > 0) { + (void)fprintf(sisout, "r(%d) <= %.2lf \n", PID(v), WEIGHT(e)); + }else if (PID(v) < 0) { + (void)fprintf(sisout, "e(%d) <= %.2lf \n", -PID(v), WEIGHT(e)); + } + continue; + } + if (PID(v) > 0) { + (void)fprintf(sisout, "r(%d) ", PID(v)); + }else if (PID(v) < 0) { + (void)fprintf(sisout, "e(%d) ", -PID(v)); + } + if (PID(u) > 0) { + (void)fprintf(sisout, "- r(%d) <= %.2lf\n", PID(u), WEIGHT(e)); + }else if (PID(u) < 0) { + (void)fprintf(sisout, "- e(%d) <= %.2lf\n", -PID(u), WEIGHT(e)); + } + } +} + +tmg_print_graph_solution(g) +graph_t *g; +{ + lsGen gen; + vertex_t *u; + + foreach_vertex(g, gen, u) { + if (PID(u) < 0) { + (void)fprintf(sisout, "e(%d) = %.2lf\n", -PID(u), P(u)); + } else if (PID(u) > 0) { + (void)fprintf(sisout, "r(%d) = %.2lf\n", PID(u), P(u)); + } else { + (void)fprintf(sisout, "ZERO = %.2lf \n", P(u)); + } + } + +} + +/* function definition + name: tmg_circuit_clock_update() + args: + job: set the rise and fall transitions of the clocks in the network + return value: + calls: +*/ +tmg_circuit_clock_update(lg, cg, network, clock) +graph_t *lg, *cg; +network_t *network; +double clock; +{ + lsGen gen; + vertex_t *u; + clock_edge_t transition; + + clock_set_cycletime(network, clock); + foreach_vertex(cg, gen, u) { + if (PID(u) < 0) { + transition.clock = array_fetch(sis_clock_t *, CL(lg), -PID(u)-1); + transition.transition = FALL_TRANSITION; + clock_set_parameter(transition, CLOCK_NOMINAL_POSITION, P(u)); + } else if (PID(u) > 0) { + transition.clock = array_fetch(sis_clock_t *, CL(lg), PID(u)-1); + transition.transition = RISE_TRANSITION; + clock_set_parameter(transition, CLOCK_NOMINAL_POSITION, P(u)); + } + } +} + + + + + +/* function definition + name: tmg_solve_gen_constraints() + args: + job: solve the genaral formulation (with min-max phase separation) + return value: double + calls: tmg_exterior_path_search(), tmg_is_feasible() +*/ +double +tmg_solve_gen_constraints(cg, v0, clock_lb) +graph_t *cg; +vertex_t *v0; +double clock_lb; +{ + + double cur_clock, L, R; + + L = clock_lb; + R = INFTY; + if (tmg_exterior_path_search(cg, &cur_clock, L, R)) { + if (!tmg_is_feasible(cg, cur_clock, v0)) { + (void)fprintf(sisout, "Serious error: contradictory results\n"); + (void)fprintf(sisout, "from 2 algorithms\n"); + return (-1.0); + } + tmg_print_graph_solution(cg); + return cur_clock; + } + (void)fprintf(sisout, "Infeasible problem!!\n"); + return (-1.0); +} + +#define NEGATIVE_CYCLE -1 +#define INFEASIBLE 0 +#define ALL_POSITIVE_CYCLES 2 + +/* function definition + name: tmg_exterior_path_search() + args: + job: does a floyyd warshall for the given clock cycle. Implements the + special algorithm described in Shenoy et al(. ICCAD 92) + return value: int + calls: tmg_init_matrix(), tmg_update_matrix(), tmg_free_matrix(), tmg_evaluate_matrix() +*/ +int +tmg_exterior_path_search(cg, clock, L, R) +graph_t *cg; +double *clock, L, R; +{ + int num_v, flag; + register int x, i, j, k; + double val, c; + register matrix_t *m; + + m = tmg_init_matrix(cg, L); + num_v = NUM_V(m); + + while (TRUE) { + + /* Get new bound on clock cycle */ + /* ---------------------------- */ + + c = CURRENT_CLOCK(m); + + /* Evaluate the dominant matrix entries */ + /* ------------------------------------ */ + + tmg_evaluate_matrix(cg, m, c); + + /* Floyd Warshall */ + /* -------------- */ + + for (x = 0; x < num_v; x++) { + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + W_n(m)[i][j] = W_o(m)[i][j]; + BETA_n(m)[i][j] = BETA_o(m)[i][j]; + for (k = 0; k < num_v; k++) { + if (k == i || k == j) continue; + if (W_o(m)[i][k] == INFTY || W_o(m)[k][j] == INFTY) + continue; + if (BETA_o(m)[i][k] == INFTY || + BETA_o(m)[k][j] == INFTY){ + assert(0); /* Sanity check */ + } + if ((val = W_o(m)[i][k] + W_o(m)[k][j]) < + W_n(m)[i][j]) { + W_n(m)[i][j] = val; + BETA_n(m)[i][j] = BETA_o(m)[i][k] + + BETA_o(m)[k][j]; + } + } + } + } + + /* Search if any diagonal entries have finite values + to update bounds + /* ------------------------------------------------- */ + + flag = tmg_update_matrix(m); + + /* If flag is negative cycle need to update clock cycle */ + /* infeasible then return */ + /* all positive cycles continue till FW is done */ + /* ------------------------------------------------------- */ + + if (flag == INFEASIBLE || flag == NEGATIVE_CYCLE) { + break; + } + } + if (flag == INFEASIBLE || flag == ALL_POSITIVE_CYCLES) { + break; + } + } + tmg_free_matrix(m); + if (flag == INFEASIBLE) { + *clock = -1.0; + return FALSE; + } else if (flag == ALL_POSITIVE_CYCLES) { + *clock = c; + return TRUE; + } else { + assert(0); /* Sanity check to ensure that flag is never neg_cycle + on getting out of while loop*/ + } +} + + +/* function definition + name: tmg_init_matrix() + args: + job: initializes the matrix for the floyd warshall + return value: matrix_t * + calls: +*/ +matrix_t * +tmg_init_matrix(g, c) +graph_t *g; +double c; +{ + lsGen gen; + vertex_t *v; + matrix_t *m; + int num_v; + register int i, j; + + num_v = lsLength(g_get_vertices(g)); + m = ALLOC(matrix_t, 1); + i = 0; + foreach_vertex (g, gen, v) { + if(debug_type == GENERAL || debug_type == ALL) { + if (PID(v) < 0) { + (void)fprintf(sisout, "e%d = %d\n", -PID(v), i); + } else if (PID(v) > 0) { + (void)fprintf(sisout, "r%d = %d\n", PID(v), i); + } else { + (void)fprintf(sisout, "ZERO = %d\n", i); + } + } + MID(v) = i; + i++; + } + CURRENT_CLOCK(m) = c; + + W_n(m) = ALLOC(double *, num_v); + W_o(m) = ALLOC(double *, num_v); + BETA_n(m) = ALLOC(double *, num_v); + BETA_o(m) = ALLOC(double *, num_v); + for (i = 0; i < num_v; i++) { + W_n(m)[i] = ALLOC(double, num_v); + W_o(m)[i] = ALLOC(double, num_v); + BETA_o(m)[i] = ALLOC(double, num_v); + BETA_n(m)[i] = ALLOC(double, num_v); + for (j = 0; j < num_v; j++) { + W_n(m)[i][j] = INFTY; + W_o(m)[i][j] = INFTY; + BETA_o(m)[i][j] = INFTY; + BETA_n(m)[i][j] = INFTY; + } + } + + LOWER_BOUND(m) = -INFTY; + UPPER_BOUND(m) = INFTY; + NUM_V(m) = num_v; + return m; +} + +/* function definition + name: tmg_evaluate_matrix() + args: + job: updates the matrix structure for a given clock cycle + return value: + calls: +*/ +tmg_evaluate_matrix(g, m, c) +graph_t *g; +matrix_t *m; +double c; +{ + lsGen gen; + edge_t *e; + char *dummy; + st_generator *sgen; + vertex_t *u, *v; + int i, j, num_v, k; + double *value, val; + + num_v = NUM_V(m); + + foreach_edge (g, gen, e) { + u = g_e_source(e); + v = g_e_dest(e); + i = MID(u); + j = MID(v); + if (EVAL(e) == NOT_SET){ + W_o(m)[i][j] = INFTY; + BETA_o(m)[i][j] = INFTY; + } else { + W_o(m)[i][j] = FIXED(e); + BETA_o(m)[i][j] = 0; + } + if (ABS(DUTY(e)) <= 1) { + if (W_o(m)[i][j] > DUTY(e) * c) { + W_o(m)[i][j] = DUTY(e) * c; + BETA_o(m)[i][j] = DUTY(e); + } + } + + if (st_count(CONS1(e)) > 0) { + st_foreach_item(CONS1(e), sgen, (char **)&dummy, (char **)&value) { + k = (int)dummy; + if ((val = -(*value) + k * c) < W_o(m)[i][j]) { + W_o(m)[i][j] = val; + BETA_o(m)[i][j] = (double)k; + } + } + } + if (CONS2(e) != NIL(double)) { + for (k = 0; k < 2; k++) { + if (CONS2(e)[k] < INFTY) { + if ((val = CONS2(e)[k] + k * c) < W_o(m)[i][j]) { + W_o(m)[i][j] = val; + BETA_o(m)[i][j] = (double)k; + } + } + } + } + } + if (debug_type == GENERAL || debug_type == ALL) { + (void)fprintf(sisout, "Weights\n"); + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + (void)fprintf(sisout, "%-10.2lf", W_o(m)[i][j]); + } + (void)fprintf(sisout, "\n"); + } + (void)fprintf(sisout, "\n"); + + (void)fprintf(sisout, "beta\n"); + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + (void)fprintf(sisout, "%-10.2lf", BETA_o(m)[i][j]); + } + (void)fprintf(sisout, "\n"); + } + (void)fprintf(sisout, "\n"); + } +} + +/* function definition + name: tmg_update_matrix() + args: + job: Check if a negative cycle is detected in Floyd warshall. + If so update bounds . + return value:int + calls: +*/ + +int +tmg_update_matrix(m) +matrix_t *m; +{ + int flag, num_v; + register int i, j; + double c; + + num_v = NUM_V(m); + flag = TRUE; + c = CURRENT_CLOCK(m); + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + if (i == j) { /* Diagonal entry */ + /*-------------- */ + if (W_n(m)[i][j] < -EPS1) { /* Entry is -ve */ + /* ------------ */ + if (BETA_n(m)[i][i] <= 0) { /* Coeff of c is <= 0 */ + /*--------------------*/ + return INFEASIBLE; + } else { + LOWER_BOUND(m) = + MAX(LOWER_BOUND(m),(-W_n(m)[i][i]/BETA_n(m)[i][i])+c); + flag = FALSE; + } + } else if (W_n(m)[i][i] >= 0 && W_n(m)[i][i] < INFTY) { + if (BETA_n(m)[i][i] < 0) { + UPPER_BOUND(m) = + MIN(UPPER_BOUND(m),(W_n(m)[i][i]/-BETA_n(m)[i][i])+c); + } + } + W_o(m)[i][j] = W_n(m)[i][j]; + BETA_o(m)[i][j] = BETA_n(m)[i][j]; + } else { /* old iterate = new iterate */ + if (W_n(m)[i][j] < INFTY) { + W_o(m)[i][j] = W_n(m)[i][j]; + BETA_o(m)[i][j] = BETA_n(m)[i][j]; + } + } + } + } + if (debug_type == GENERAL || debug_type == ALL) { + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + (void)fprintf(sisout, "%-10.2lf ", W_o(m)[i][j]); + } + (void)fprintf(sisout, "\n"); + } + (void)fprintf(sisout, "\n"); + } + + if (!flag) { /* There is negative cycle */ + /* CLearly C_L > c */ + /* Check for c_L < c_U */ + if (LOWER_BOUND(m) > UPPER_BOUND(m)) return INFEASIBLE; + CURRENT_CLOCK(m) = LOWER_BOUND(m); + /* Initialize for new Floyd Warshall */ + /* --------------------------------- */ + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + W_o(m)[i][j] = INFTY; + W_n(m)[i][j] = INFTY; + BETA_o(m)[i][j] = INFTY; + BETA_n(m)[i][j] = INFTY; + } + } + return NEGATIVE_CYCLE; + } + return ALL_POSITIVE_CYCLES; +} + +/* function definition + name: tmg_free_matrix() + args: + job: Frees the memory associated with the mtrix + return value: + calls: +*/ +tmg_free_matrix(m) +matrix_t *m; +{ + int num_v, i; + + num_v = NUM_V(m); + for (i = 0; i < num_v; i++) { + FREE(W_o(m)[i]); + FREE(W_n(m)[i]); + FREE(BETA_n(m)[i]); + FREE(BETA_o(m)[i]); + } + FREE(W_o(m)); + FREE(W_n(m)); + FREE(BETA_n(m)); + FREE(BETA_o(m)); + FREE(m); +} +#endif /* SIS */ diff --git a/sis/timing/timing_fast_comp.c b/sis/timing/timing_fast_comp.c new file mode 100644 index 0000000..598429f --- /dev/null +++ b/sis/timing/timing_fast_comp.c @@ -0,0 +1,1518 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/timing/timing_fast_comp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:00 $ + * + */ +#ifdef SIS +#include "timing_int.h" + +#define FEASIBLE 1 +#define SOLVE 2 + +/* function definition + name: compute_optimal_clock() + args: latch_graph, network + job: compute optimal clocking params + return value: - + calls: + clock_lower_bound(), + construct_clock_graph(), add_short_path_constraints(), + add_model_constraints(), add_phase_separation_constraints(), + print_constraint_graph(), + solve_constraints(), solve_gen_constraints(), + circuit_clock_update() + constraint_graph_free() +*/ + +double +compute_optimal_clock(latch_graph, network) +graph_t *latch_graph; +network_t *network; +{ + graph_t *clock_graph; + phase_t *phase; + double clock, clock_lb; + + + clock_lb = 0; + clock_lb = clock_lower_bound(latch_graph); + (void)fprintf(sisout, "Clock lower bound found %.2lf : cpu_time = %s\n", + clock_lb, util_print_time(util_cpu_time())); + + /* Construct the clock graph - a graph with a vertex for rise/ + fall of each phase. The long path constraints are added now*/ + /* ---------------------------------------------------------- */ + + clock_graph = construct_clock_graph(latch_graph, clock_lb); + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "Only long paths: \n"); + print_constraint_graph(clock_graph); + (void)fprintf(sisout, "\n\n"); + } + + /* Add the short path constraints for each edge */ + /* -------------------------------------------- */ + + add_short_path_constraints(clock_graph, latch_graph); + + /* Get the last edge (e_k)- recall 0 (ref) vertex is also in table*/ + /* -------------------------------------------------------------- */ + + phase = PHASE_LIST(clock_graph)[NUM_PHASE(clock_graph) -1]; + + /* Add other constraints */ + /* --------------------- */ + + add_model_constraints(latch_graph, clock_graph, phase->fall); + add_phase_separation_constraints(latch_graph, clock_graph, phase->fall); + + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "Long and Short paths\n"); + print_constraint_graph(clock_graph); + (void)fprintf(sisout, "\n\n"); + } + + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "clock lower bound = %.2lf\n", clock_lb); + } + + /* Solve the optimization problem */ + /* ------------------------------ */ + + if (get_gen_algorithm_flag()) { + clock = solve_gen_constraints(clock_graph, phase->fall, clock_lb); + } else { + clock = solve_constraints(clock_graph, phase->fall, clock_lb); + } + if (clock > 0) { + + /* Set the values in the circuit */ + /* ----------------------------- */ + + circuit_clock_update(latch_graph, clock_graph, network, clock); + } + + /* Free memory associated with the clock_graph */ + /* ------------------------------------------- */ + + constraint_graph_free(clock_graph); + return clock; +} + +/* function definition + name: clock_lower_bound() + args: graph_t *g + job: finds a lower bound for the clock cycle using Lawlers + binary search + method. + return value: double + calls: guess_lower_bound(), + all_negative_cycles() +*/ +double +clock_lower_bound(g) +graph_t *g; +{ + double cur_clock, new_clock, clock_ub, clock_lb; + + clock_ub = 0; + new_clock= guess_clock_bound(g); + clock_lb = new_clock; + while(TRUE) { + cur_clock = new_clock; + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Trying %.4lf ", cur_clock); + } + if (all_negative_cycles(g, cur_clock)) { /* Negative cycle */ + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Success - try lower \n"); + } + clock_ub = cur_clock; + } else { + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Failure - try higher \n"); + } + clock_lb = cur_clock; + } + if (ABS(clock_ub - clock_lb) < EPS) break; + if (clock_ub > clock_lb) { + new_clock = (clock_ub + clock_lb)/2; + } else { + new_clock *= 2; + } + } + return clock_ub; +} + +/* function definition + name: all_negative_cycles() + args: graph_t *g, double c + job: uses Bellman-Ford to test if given c causes a positive cycle in g + return value: 0 if there is a positive cycle + 1 if all cycles are negative or 0 weighted + + calls: +*/ +int +all_negative_cycles(g, c) +graph_t *g; +double c; +{ + vertex_t *v, *u; + edge_t *e; + register elist_t *list; + int num_v, flag, i; + double C[2], c_eps, val; + + num_v = lsLength(g_get_vertices(g)); + + /* Initialize all edges with appropriate weights*/ + /* -------------------------------------------- */ + + C[0] = 0; + C[1] = c; + c_eps = c + EPS; + foreach_list_edge(g, list, e) { + We(e) = De(e) - C[Ke(e)]; + Wv(SOURCE(list)) = -INFTY; + } + Wv(HOST(g)) = 0; + + for (i = 0; i < num_v; i++) { + + /* flag to detect early convergence */ + /* -------------------------------- */ + + flag = TRUE; + foreach_list_edge(g, list, e) { + v = SINK(list); + u = SOURCE(list); + if ((val = Wv(u) + We(e)) > Wv(v)) { + Wv(v) = val; + flag = FALSE; + if (Wv(v) > c_eps) { + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Positive path exceeding c \n"); + } + return 0; + } + } + } + if (flag) break; + } + + /* check for positive cycle */ + /* ---------------------------- */ + + foreach_list_edge(g, list, e) { + v = SINK(list); + u = SOURCE(list); + if ((val = Wv(u) + We(e)) > Wv(v) + EPS) { + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Positive cycle\n"); + } + return 0; + } + } + return 1; +} + +/* function definition + name: guess_clock_bound() + args: graph_t *g + job: uses DFS to guess lower bound on clock cycle + return value: double + calls: guess_clock_bound_recursive() +*/ +double +guess_clock_bound(g) +graph_t *g; +{ + double bound1, bound2; + lsGen gen; + vertex_t *v, *host; + + /* init */ + /* ---- */ + + host = HOST(g); + foreach_vertex(g, gen, v) { + Rv(v) = -1; + Wv(v) = 0; + COPT_DIRTY(v) = FALSE; + } + if (host == NIL(vertex_t)) { + host = v; + } + bound1 = 0; + bound2 = 0; + Rv(host) = 0; + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "guessing a bound for clock cycle\n"); + } + guess_clock_bound_recursive(host, &bound1, &bound2); + if (bound1 < bound2) { + (void)fprintf(sisout, "bound1 = %.2lf bound2 = %.2lf \n", + bound1, bound2); + bound1 = bound2; + } + assert(bound1 > 0); + + return bound1; +} + +/* function definition + name: guess_clock_bound_recursive() + args: vertex_t *u, double *b1, *b2 + job: Recursive DFS + return value: - + calls: +*/ +guess_clock_bound_recursive(u, b1, b2) +vertex_t *u; +double *b1, *b2; +{ + lsGen gen; + edge_t *e; + vertex_t *v; + int den; + + + (*b2) = MAX((*b2), Wv(u)/(Rv(u)+1)); + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Path bound = %.4lf\n", *b2); + } + COPT_DIRTY(u) = TRUE; + foreach_out_edge(u, gen, e){ + v = g_e_dest(e); + + /* Check if v has been visited before*/ + /* --------------------------------- */ + + if (COPT_DIRTY(v)) { + + /* Check if v is on DFS stack */ + /* -------------------------- */ + + if (Rv(v) > 0) { + if ((den = Rv(u) + Ke(e) - Rv(v)) == 0) { + (void)fprintf(sisout, + "Error cycle without memory elements\n"); + } + if (den > 0) { + (*b1) = MAX((*b1), (Wv(u) + De(e) -Wv(v))/den); + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "Cycle bound = %.4lf\n", *b1); + } + } + } + } else { + Rv(v) = Rv(u) + Ke(e); + Wv(v) = Wv(u) + De(e); + guess_clock_bound_recursive(v, b1, b2); + } + } + /* Remove u from DFS stack */ + /* ----------------------- */ + Rv(u) = -1; +} + + + +/* function definition + name: construct_clock_graph() + args: latch_graph + job: constructs the clock graph (a vertex for each + transition of a phase + return value: graph_t * + calls: alloc_cgraph(), + gen_constraints_from(), + +*/ + +graph_t * +construct_clock_graph(lg, clock_lb) +graph_t *lg; +double clock_lb; +{ + graph_t *cg; + lsGen gen; + vertex_t *u, *p1, *v; + edge_t *e; + int i, from_index; + register elist_t *list; + array_t **array_list, *zarray, *red, *black; + + /* Allocate constraint graph + ZERO vertex */ + /* --------------------------------------- */ + + cg = g_alloc(); + cg->user_data = (gGeneric)(alloc_cgraph()); + alloc_phase_vertices(cg, lg); + + ZERO_V(cg) = g_add_vertex(cg); + ZERO_V(cg)->user_data = (gGeneric)ALLOC(c_node_t, 1); + PID(ZERO_V(cg)) = 0; + array_list = ALLOC(array_t *, 2 * NUM_PHASE(cg)); + for (i = 0; i < 2 * NUM_PHASE(cg); i++) { + array_list[i] = NIL(array_t); + } + foreach_vertex(lg, gen, v) { + if (TYPE(v) != LATCH) continue; + from_index = get_index(v, FROM, cg); + if (array_list[from_index] == NIL(array_t)) { + array_list[from_index] = array_alloc(vertex_t *, 0); + } + array_insert_last(vertex_t *, array_list[from_index], v); + } + + /* Get edges with Ke(e) = 1 and Ke(e) = 0 */ + /* -------------------------------------- */ + + red = array_alloc(edge_t *, 0); + black = array_alloc(edge_t *, 0); + foreach_list_edge (lg, list, e) { + if (Ke(e)) { + array_insert_last(edge_t *, red, e); + } else { + array_insert_last(edge_t *, black, e); + } + } + + for (i = 0; i < 2 * NUM_PHASE(cg); i++) { + if (array_list[i] != NIL(array_t)) { + foreach_vertex(lg, gen, v) { + Wv(v) = -INFTY; + Rv(v) = 0; + COPT_DIRTY(v) = FALSE; + } + p1 = get_vertex_from_index(cg, i); + if (get_phase_inv() && i == 1) { + + /* Special case handling!! */ + /* ----------------------- */ + + p1 = ZERO_V(cg); + } + gen_constraints_from(lg, cg, array_list[i], p1, clock_lb, + red, black); + array_free(array_list[i]); + } + } + FREE(array_list); + + /* Add long path constraints from primary inputs. Inputs assumed stable + for a clock cycle */ + /* ------------------ */ + + u = HOST(lg); + p1 = ZERO_V(cg); + foreach_vertex(lg, gen, v) { + Wv(v) = -INFTY; + Rv(v) = 0; + COPT_DIRTY(v) = FALSE; + } + zarray = array_alloc(vertex_t *, 0); + array_insert_last(vertex_t *, zarray, u); + gen_constraints_from(lg, cg, zarray, p1, clock_lb, red, black); + array_free(zarray); + array_free(red); array_free(black); + return cg; +} + +/* function definition + name: gen_constraints_from() + args: latch_graph, constraint_graph, array of latches on given + phase event, corresponding constraint vertex, lower_bound on + clock, array of red edges + job: Extract constraints between clock event represented by p1 and + all possible latches reachable by the set of latches from + latch_array + return value: - + calls: +*/ + +gen_constraints_from(lg, cg, latch_array, p1, clock_lb, red, black) +graph_t *lg, *cg; +vertex_t *p1; +array_t *latch_array; +double clock_lb; +array_t *red, *black; +{ + edge_t **e_array; + lsGen gen; + edge_t *e; + vertex_t *u, *v, *p2; + int num_v, i, to_index, current_key, more_to_come, j, local_converged; + double *value, val; + + /* Cache the possible edges from p1 */ + /* -------------------------------- */ + + e_array = ALLOC(edge_t *, 2 * NUM_PHASE(cg)); + for (i = 0; i < 2 * NUM_PHASE(cg); i++) { + e_array[i] = NIL(edge_t); + } + + /* Initialize delays from set of latches that start on p1 */ + /* ------------------------------------------------------ */ + + for (i = 0; i < array_n(latch_array); i++) { + u = array_fetch(vertex_t *, latch_array, i); + if (LTYPE(u) == FFF || LTYPE(u) == FFR) continue; + if (TYPE(u) == LATCH) { + Wv(u) = max_clock_skew(u); + } else { + Wv(u) = 0.0; + } + Rv(u) = 0; + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "From %d :\n", ID(u)); + } + } + + /* The remaining section of this subroutine follows the paper by + Dr. T. G. Szymanski in DAC 92 for extracting the constraints + efficiently */ + /* ----------------------------------------------------------- */ + + current_key = 0; + num_v = lsLength(g_get_vertices(lg)); + more_to_come = TRUE; + + while (more_to_come) { + more_to_come = FALSE; + foreach_vertex (lg, gen, v) { + if (Rv(v) == current_key) { + PREV_Wv(v) = Wv(v); + } + } + + for (i = 0; i < num_v; i++) { + local_converged = TRUE; + for (j = 0; j < array_n(black); j++) { + e = array_fetch(edge_t *, black, j); + u = g_e_source(e); + v = g_e_dest(e); + if (TYPE(v) == NNODE || Wv(u) == -INFTY) continue; + if (TYPE(u) == NNODE && Wv(u) < 0) continue; + if ((Wv(u) + De(e) - current_key * clock_lb) > + Wv(v) - Rv(v) * clock_lb) { + Wv(v) = Wv(u) + De(e); + Rv(v) = Rv(u); + COPT_DIRTY(v) = TRUE; + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, + "%d (%.2lf)->(%.2lf )-> %d (%.2lf)\n", + ID(u), Wv(u), De(e), ID(v), + Wv(v)-Rv(v)*clock_lb); + } + local_converged = FALSE; + } + } + if (local_converged) { + break; + } + } + assert(local_converged); + foreach_vertex (lg, gen, v) { + if (TYPE(v) == NNODE) continue; + if (!COPT_DIRTY(v)) continue; + if (Rv(v) == current_key) { + to_index = get_index(v, TO, cg); + if ((e = e_array[to_index]) == NIL(edge_t)) { + p2 = get_vertex(v, TO, cg); + if (!g_get_edge(p2, p1, &e)) { + e->user_data = (gGeneric)alloc_cedge(); + } + e_array[to_index] = e; + } + val = Wv(v) + get_set_up(v) - min_clock_skew(v); + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, "to %d : %.2lf - %d c\n", ID(v), + val, current_key); + } + if (st_lookup(CONS1(e), (char *)current_key, + (char **)&value)) { + if (*value < val) { + *value = val; + } + } else { + value = ALLOC(double, 1); + *value = val; + st_insert(CONS1(e), (char *)current_key, (char *)value); + } + PREV_Wv(v) = Wv(v); + } + } + for (i = 0; i < array_n(red); i++) { + e = array_fetch(edge_t *, red, i); + u = g_e_source(e); + if (LTYPE(u) == FFF || LTYPE(u) == FFR) continue; + v = g_e_dest(e); + if (TYPE(v) == NNODE) continue; + if (TYPE(u) == NNODE && Wv(u) < 0) continue; + if ((PREV_Wv(u) + De(e) - (current_key + 1) * clock_lb) + > (Wv(v) - Rv(v) * clock_lb + EPS)) { + Wv(v) = PREV_Wv(u) + De(e); + Rv(v) = current_key + 1; + COPT_DIRTY(v) = TRUE; + if (debug_type == CGRAPH || debug_type == ALL) { + (void)fprintf(sisout, + "%d (%.2lf)->(%.2lf)-> %d (%.2lf)\n", + ID(u), Wv(u), De(e) - clock_lb, ID(v), + Wv(v)-Rv(v)*clock_lb); + } + more_to_come = TRUE; + } + } + current_key++; + } + FREE(e_array); +} + + +/* function definition + name: add_short_path_constraints() + args: clock_graph, latch_graph + job: Adds the short path constraints for each edge + Does a conservative job by extracting constraints for + each edge only + return value: - + calls: g_get_edge() +*/ +add_short_path_constraints(cg, lg) +graph_t *cg, *lg; +{ + edge_t *cedge, *ledge; + double **array; + int i, j, from_id, to_id, dim, k; + register elist_t *list; + vertex_t *u, *v; + vertex_t *p1, *p2; + + dim = 2 * NUM_PHASE(cg); + array = ALLOC(double *, dim); + for (i = 0; i < dim ; i++) { + array[i] = ALLOC(double, dim); + for (j = 0; j < dim; j++) { + array[i][j] = INFTY; + } + } + foreach_list_edge(lg, list, ledge) { + u = SOURCE(list); + v = SINK(list); + if (TYPE(u) != LATCH || TYPE(v) != LATCH) continue; + from_id = get_index(u, FROM, cg); + to_id = get_index(v, TO, cg); + array[from_id][to_id] = MIN(array[from_id][to_id], + min_clock_skew(u) + de(ledge) - + get_hold(v) - max_clock_skew(v)); + } + for (i = 0; i < dim; i++) { + for (j = 0; j < dim; j++) { + if (array[i][j] < INFTY) { + p1 = get_vertex_from_index(cg, i); + p2 = get_vertex_from_index(cg, j); + if (!g_get_edge(p1, p2, &cedge)) { + cedge->user_data = (gGeneric)alloc_cedge(); + } + if (CONS2(cedge) == NIL(double)) { + CONS2(cedge) = ALLOC(double, 2); + for (k = 0; k < 2; k++) { + CONS2(cedge)[k] = INFTY; + } + } + if (ABS(PID(p1)) < ABS(PID(p2))) { + CONS2(cedge)[1] = MIN(CONS2(cedge)[1], array[i][j]); + } else { + CONS2(cedge)[0] = MIN(CONS2(cedge)[0], array[i][j]); + } + } + } + FREE(array[i]); + } + FREE(array); +} + + +/* function definition + name: solve_constraints() + args: clock_graph, vertex (e_k) + job: Finds the minimum c (>= clock_lb) for which the constraints are + satisfied. Contains the binary search routine (while(1) { ...}) + return value: double (clock cycle) + calls: is_feasible() +*/ + +double +solve_constraints(cg, v0, clock_lb) +graph_t *cg; +vertex_t *v0; +double clock_lb; +{ + double cur_clock, clock_ub; + + clock_ub = INFTY; + cur_clock = clock_lb; + while (TRUE) { + (void)fprintf(sisout, "trying %.2lf \n", cur_clock); + if (!is_feasible(cg, cur_clock, v0)) { + clock_lb = cur_clock; + if (clock_ub == INFTY) { + cur_clock = 2 * cur_clock; + } else { + cur_clock = MAX(cur_clock + EPS, (clock_lb + clock_ub)/2); + } + } else { + clock_ub = cur_clock; + cur_clock = (clock_ub + clock_lb)/2; + } + if (ABS(clock_lb -clock_ub) < EPS) break; + } + + print_graph_solution(cg); + return cur_clock; +} + +/* function definition + name: is_feasible() + args: clock_graph, clock_cycle, e_k + job: Check if the clock_cycle is feasible. + + return value: 1 on success, 0 on failure + calls: evaluate_right_hand_side(), + print_graph_solution() +*/ +int +is_feasible(g, c, v0) +graph_t *g; +double c; +vertex_t *v0; +{ + edge_t *e; + vertex_t *u, *v; + lsGen gen; + int num_it, flag, i; + + if (c == 0) return 0; + evaluate_right_hand_side(g, c); + + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "LP constraints evaluated for c = %.2lf\n", c); + print_constraints(g); + } + + /* Initialize for Bellman-Ford on Constraint Graph */ + /* ----------------------------------------------- */ + + foreach_vertex(g, gen, v){ + P(v) = INFTY; + } + P(ZERO_V(g)) = 0; + + /* Bellman Ford carried out here */ + /* ----------------------------- */ + + num_it = lsLength(g_get_vertices(g)) - 1; + for (i = 0; i < num_it; i++) { + flag = TRUE; + foreach_edge(g, gen, e) { + if (IGNORE(e)) continue; + v = g_e_dest(e); + u = g_e_source(e); + if (P(v) > P(u) + WEIGHT(e)) { + P(v) = P(u) + WEIGHT(e); + flag = FALSE; + } + } + if (flag) break; + } + + /* Check for negative cycle */ + /* ------------------------ */ + + flag = TRUE; + foreach_edge(g, gen, e) { + if (IGNORE(e)) continue; + v = g_e_dest(e); + u = g_e_source(e); + if (P(v) > P(u) + WEIGHT(e) + EPS) { + (void)fprintf(sisout, "negative cycle\n"); + flag = FALSE; + lsFinish(gen); + break; + } + } + if (debug_type == BB || debug_type == ALL) { + print_graph_solution(g); + } + return flag; +} + + +/* function definition + name: print_constraint_graph() + args: + job: prints the constraint graph + return value: - + calls:- +*/ +print_constraint_graph(g) +graph_t *g; +{ + edge_t *e; + vertex_t *u, *v; + char *dummy; + st_generator *sgen; + double *value; + lsGen gen; + int i, flag; + + foreach_edge(g, gen, e) { + if (IGNORE(e)) continue; + flag = TRUE; + u = g_e_source(e); + v = g_e_dest(e); + if (PID(v) > 0) { + (void)fprintf(sisout, "r(%d) - ", PID(v)); + } else if (PID(v) < 0) { + (void)fprintf(sisout, "e(%d) - ", -PID(v)); + } else { + (void)fprintf(sisout, "ZERO - "); + } + if (PID(u) > 0) { + (void)fprintf(sisout, "r(%d)\n", PID(u)); + } else if (PID(u) < 0) { + (void)fprintf(sisout, "e(%d)\n", -PID(u)); + } else { + (void)fprintf(sisout, "ZERO \n"); + } + + if (EVAL(e) == TRUE) { + if (flag) { + (void)fprintf(sisout, "\t <= \n"); + flag = FALSE; + } + (void)fprintf(sisout, "FIXED \n"); + (void)fprintf(sisout, "\t %.2lf \n", FIXED(e)); + } + + if (ABS(DUTY(e)) <= 1) { + if (flag) { + (void)fprintf(sisout, "\t <= \n"); + flag = FALSE; + } + (void)fprintf(sisout, "DUTY \n"); + (void)fprintf(sisout, "\t %.2lf c\n", DUTY(e)); + } + if (st_count(CONS1(e)) > 0) { + if (flag) { + (void)fprintf(sisout, "\t <= \n"); + flag = FALSE; + } + (void)fprintf(sisout, "LP \n"); + st_foreach_item(CONS1(e), sgen, (char **)&dummy, (char **)&value) { + i = (int)dummy; + (void)fprintf(sisout, "\t -%.2lf + %d c\n", *value, i); + } + } + if (CONS2(e) != NIL(double)) { + if (flag) { + (void)fprintf(sisout, "\t <= \n"); + flag = FALSE; + } + (void)fprintf(sisout, "SP \n"); + for (i = 0; i < 2; i++) { + (void)fprintf(sisout, "\t %.2lf + %d c\n", CONS2(e)[i], i); + } + } + } +} + + +/* function definition + name: add_model_constraints() + args: + job: adds the constraints ZERO <= v <= v0 forall vertices except the + ZERO and v0 vertex. Also make sure ZERO + c = v0 + return value: + calls: +*/ + +add_model_constraints(lg, cg, v0) +graph_t *lg, *cg; +register vertex_t *v0; +{ + lsGen gen; + vertex_t *v; + edge_t *e, *edge_z2ek, *edge_ek2z; + + /* Add constraints */ + /* --------------- */ + + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "Adding constraints\n"); + } + foreach_vertex(cg, gen, v){ + if (v == v0 || v == ZERO_V(cg)) continue; + + /* Add constraints so that ZERO_V <= v */ + /* ----------------------------------- */ + + if (!g_get_edge(v, ZERO_V(cg), &e)) { + e->user_data = (gGeneric)alloc_cedge(); + } + if (debug_type == BB || debug_type == ALL) { + if (PID(v) > 0) { + (void)fprintf(sisout, "r(%d) >= 0\n", PID(v)); + } else if (PID(v) < 0) { + (void)fprintf(sisout, "e(%d) >= 0\n", -PID(v)); + } + } + if (EVAL(e) == NOT_SET) { + FIXED(e) = 0; + EVAL(e) = TRUE; + } else if (EVAL(e) == TRUE) { + FIXED(e) = MIN(FIXED(e), 0); + } + + /* Add constraints so that v <= v0*/ + /* ------------------------------ */ + + if (!g_get_edge(v0, v, &e)) { + e->user_data = (gGeneric)alloc_cedge(); + } + if (debug_type == BB || debug_type == ALL) { + if (PID(v) > 0) { + (void)fprintf(sisout, "r(%d) <= e(%d)\n", + PID(v), array_n(CL(lg))); + } else if (PID(v) < 0) { + (void)fprintf(sisout, "e(%d) <= e(%d)\n", + -PID(v), array_n(CL(lg))); + } + } + if (EVAL(e) == NOT_SET) { + FIXED(e) = 0; + EVAL(e) = TRUE; + } else if (EVAL(e) == TRUE) { + FIXED(e) = MIN(FIXED(e), 0); + } + } + + /* Force ZERO_V and v0 to be separated by exactly c. */ + /* Add v0 <= ZERO_V + c */ + /* ------------------------------------------------- */ + + if (!g_get_edge(ZERO_V(cg), v0, &edge_z2ek)) { + edge_z2ek->user_data = (gGeneric)alloc_cedge(); + } + DUTY(edge_z2ek) = 1; + + /* ZERO <= v0 - c */ + /* -------------- */ + + if (!g_get_edge(v0, ZERO_V(cg), &edge_ek2z)) { + edge_ek2z->user_data = (gGeneric)alloc_cedge(); + } + DUTY(edge_ek2z) = -1; + +} + +/* function definition + name: add_phase_separation_constraints() + args: + job: add the phase separartion constraints (duty cycle or + fixed separation) + return value: + calls: +*/ +add_phase_separation_constraints(lg, cg, v0) +graph_t *lg, *cg; +vertex_t *v0; +{ + double min_sep, max_sep; + int i; + phase_t *phase; + edge_t *e; + vertex_t *old_v; + + /* Add the constraints e1 <= e2 <= e3...<= ek and min and + max separations */ + /* ----------------------------------------------------- */ + + old_v = NIL(vertex_t); + min_sep = get_min_sep(); + max_sep = get_max_sep(); + + for (i = 0; i < array_n(CL(lg)); i++) { + phase = PHASE_LIST(cg)[i]; + + /* Add minimum and maximum constraint separation*/ + /* -------------------------------------------- */ + + if (!g_get_edge(phase->rise, phase->fall, &e)) { + e->user_data = (gGeneric)alloc_cedge(); + } + DUTY(e) = MIN(DUTY(e), max_sep); + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "e(%d) - r(%d) <= %.2lf * c\n", + -PID(phase->fall), PID(phase->rise), max_sep); + } + if (!g_get_edge(phase->fall, phase->rise, &e)) { + e->user_data = (gGeneric)alloc_cedge(); + } + DUTY(e) = MIN(DUTY(e), -min_sep); + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "r(%d) - e(%d) <= %.2lf * c\n", + PID(phase->rise), -PID(phase->fall), -min_sep); + } + + /* e(k-1) <= e(k) */ + /* -------------- */ + + if (old_v != NIL(vertex_t)) { + if (!g_get_edge(phase->fall, old_v, &e)) { + e->user_data = (gGeneric)alloc_cedge(); + } + if (debug_type == BB || debug_type == ALL) { + (void)fprintf(sisout, "e(%d) - e(%d) <= 0\n", -PID(old_v), + -PID(phase->fall)); + } + if (EVAL(e) == NOT_SET) { + FIXED(e) = 0; + EVAL(e) = TRUE; + } else { + FIXED(e) = MIN(FIXED(e), 0); + } + } + old_v = phase->fall; + } +} + +/* function definition + name: evaluate_right_hand_side() + args: + job: evaluate the edge weights for the given clock cycle + and keep the minimum + weight + return value: + calls: +*/ +evaluate_right_hand_side(g, c) +graph_t *g; +double c; +{ + lsGen gen; + edge_t *e; + char *dummy; + double *value, C[2]; + int i; + st_generator *sgen; + + C[0] = 0; C[1] = c; + foreach_edge(g, gen, e) { + if (EVAL(e) == NOT_SET) { + WEIGHT(e) = INFTY; + } else { + WEIGHT(e) = FIXED(e); + } + + if (ABS(DUTY(e)) <= 1) { + WEIGHT(e) = MIN(WEIGHT(e), DUTY(e) * c); + } + + if (st_count(CONS1(e)) > 0) { + st_foreach_item(CONS1(e), sgen, (char **)&dummy, (char **)&value) { + i = (int)dummy; + WEIGHT(e) = MIN(WEIGHT(e), -(*value) + i * c); + } + } + if (CONS2(e) != NIL(double)) { + for (i = 0; i < 2; i++) { + if (CONS2(e)[i] < INFTY) { + WEIGHT(e) = MIN(WEIGHT(e), CONS2(e)[i] + C[i]); + } + } + } + if (WEIGHT(e) == INFTY) { + /* No constraint so far - disregard it!!*/ + IGNORE(e) = TRUE; + } + } +} + +/* function definition + name: print_constraints() + args: + job: print the constraints once the right hand sides + have been evaluated + return value: + calls: +*/ +print_constraints(g) +graph_t *g; +{ + lsGen gen; + edge_t *e; + vertex_t *u, *v; + + foreach_edge(g, gen, e) { + if (IGNORE(e)) continue; + v = g_e_dest(e); + u = g_e_source(e); + if (PID(v) == 0) { + if (PID(u) > 0) { + (void)fprintf(sisout, " -r(%d) =< %.2lf\n", PID(u), WEIGHT(e)); + }else if (PID(u) < 0) { + (void)fprintf(sisout, " -e(%d) =< %.2lf\n", -PID(u), + WEIGHT(e)); + } + continue; + } + if (PID(u) == 0) { + if (PID(v) > 0) { + (void)fprintf(sisout, "r(%d) <= %.2lf \n", PID(v), WEIGHT(e)); + }else if (PID(v) < 0) { + (void)fprintf(sisout, "e(%d) <= %.2lf \n", -PID(v), WEIGHT(e)); + } + continue; + } + if (PID(v) > 0) { + (void)fprintf(sisout, "r(%d) ", PID(v)); + }else if (PID(v) < 0) { + (void)fprintf(sisout, "e(%d) ", -PID(v)); + } + if (PID(u) > 0) { + (void)fprintf(sisout, "- r(%d) <= %.2lf\n", PID(u), WEIGHT(e)); + }else if (PID(u) < 0) { + (void)fprintf(sisout, "- e(%d) <= %.2lf\n", -PID(u), WEIGHT(e)); + } + } +} + +print_graph_solution(g) +graph_t *g; +{ + lsGen gen; + vertex_t *u; + + foreach_vertex(g, gen, u) { + if (PID(u) < 0) { + (void)fprintf(sisout, "e(%d) = %.2lf\n", -PID(u), P(u)); + } else if (PID(u) > 0) { + (void)fprintf(sisout, "r(%d) = %.2lf\n", PID(u), P(u)); + } else { + (void)fprintf(sisout, "ZERO = %.2lf \n", P(u)); + } + } + +} + +/* function definition + name: circuit_clock_update() + args: + job: set the rise and fall transitions of the clocks in the network + return value: + calls: +*/ +circuit_clock_update(lg, cg, network, clock) +graph_t *lg, *cg; +network_t *network; +double clock; +{ + lsGen gen; + vertex_t *u; + clock_edge_t transition; + + clock_set_cycletime(network, clock); + foreach_vertex(cg, gen, u) { + if (PID(u) < 0) { + transition.clock = array_fetch(sis_clock_t *, CL(lg), -PID(u)-1); + transition.transition = FALL_TRANSITION; + clock_set_parameter(transition, CLOCK_NOMINAL_POSITION, P(u)); + } else if (PID(u) > 0) { + transition.clock = array_fetch(sis_clock_t *, CL(lg), PID(u)-1); + transition.transition = RISE_TRANSITION; + clock_set_parameter(transition, CLOCK_NOMINAL_POSITION, P(u)); + } + } +} + + + + + +/* function definition + name: solve_gen_constraints() + args: + job: solve the genaral formulation (with min-max phase separation) + return value: double + calls: exterior_path_search(), is_feasible() +*/ +double +solve_gen_constraints(cg, v0, clock_lb) +graph_t *cg; +vertex_t *v0; +double clock_lb; +{ + + double cur_clock, L, R; + + L = clock_lb; + R = INFTY; + if (exterior_path_search(cg, &cur_clock, L, R)) { + if (!is_feasible(cg, cur_clock, v0)) assert(0); + print_graph_solution(cg); + return cur_clock; + } + (void)fprintf(sisout, "Infeasible problem!!\n"); + return (-1.0); +} + +#define NEGATIVE_CYCLE -1 +#define INFEASIBLE 0 +#define ALL_POSITIVE_CYCLES 2 + +/* function definition + name: exterior_path_search() + args: + job: does a floyyd warshall for the given clock cycle. Implements the + special algorithm described in Shenoy et al(. ICCAD 92) + return value: int + calls: init_matrix(), update_matrix(), free_matrix(), evaluate_matrix() +*/ +int +exterior_path_search(cg, clock, L, R) +graph_t *cg; +double *clock, L, R; +{ + int num_v, flag; + register int x, i, j, k; + double val, c; + register matrix_t *m; + + m = init_matrix(cg, L); + num_v = NUM_V(m); + + while (TRUE) { + + /* Get new bound on clock cycle */ + /* ---------------------------- */ + + c = CURRENT_CLOCK(m); + + /* Evaluate the dominant matrix entries */ + /* ------------------------------------ */ + + evaluate_matrix(cg, m, c); + + /* Floyd Warshall */ + /* -------------- */ + + for (x = 0; x < num_v; x++) { + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + W_n(m)[i][j] = W_o(m)[i][j]; + BETA_n(m)[i][j] = BETA_o(m)[i][j]; + for (k = 0; k < num_v; k++) { + if (k == i || k == j) continue; + if (W_o(m)[i][k] == INFTY || W_o(m)[k][j] == INFTY) + continue; + if (BETA_o(m)[i][k] == INFTY || + BETA_o(m)[k][j] == INFTY){ + assert(0); + } + if ((val = W_o(m)[i][k] + W_o(m)[k][j]) < + W_n(m)[i][j]) { + W_n(m)[i][j] = val; + BETA_n(m)[i][j] = BETA_o(m)[i][k] + + BETA_o(m)[k][j]; + } + } + } + } + + /* Search if any diagonal entries have finite values + to update bounds + /* ------------------------------------------------- */ + + flag = update_matrix(m); + + /* If flag is negative cycle need to update clock cycle */ + /* infeasible then return */ + /* all positive cycles continue till FW is done */ + /* ------------------------------------------------------- */ + + if (flag == INFEASIBLE || flag == NEGATIVE_CYCLE) { + break; + } + } + if (flag == INFEASIBLE || flag == ALL_POSITIVE_CYCLES) { + break; + } + } + free_matrix(m); + if (flag == INFEASIBLE) { + *clock = -1.0; + return FALSE; + } else if (flag == ALL_POSITIVE_CYCLES) { + *clock = c; + return TRUE; + } else { + assert(0); + } +} + + +/* function definition + name: init_matrix() + args: + job: initializes the matrix for the floyd warshall + return value: matrix_t * + calls: +*/ +matrix_t * +init_matrix(g, c) +graph_t *g; +double c; +{ + lsGen gen; + vertex_t *v; + matrix_t *m; + int num_v; + register int i, j; + + num_v = lsLength(g_get_vertices(g)); + m = ALLOC(matrix_t, 1); + i = 0; + foreach_vertex (g, gen, v) { + if(debug_type == GENERAL || debug_type == ALL) { + if (PID(v) < 0) { + (void)fprintf(sisout, "e%d = %d\n", -PID(v), i); + } else if (PID(v) > 0) { + (void)fprintf(sisout, "r%d = %d\n", PID(v), i); + } else { + (void)fprintf(sisout, "ZERO = %d\n", i); + } + } + MID(v) = i; + i++; + } + CURRENT_CLOCK(m) = c; + + W_n(m) = ALLOC(double *, num_v); + W_o(m) = ALLOC(double *, num_v); + BETA_n(m) = ALLOC(double *, num_v); + BETA_o(m) = ALLOC(double *, num_v); + for (i = 0; i < num_v; i++) { + W_n(m)[i] = ALLOC(double, num_v); + W_o(m)[i] = ALLOC(double, num_v); + BETA_o(m)[i] = ALLOC(double, num_v); + BETA_n(m)[i] = ALLOC(double, num_v); + for (j = 0; j < num_v; j++) { + W_n(m)[i][j] = INFTY; + W_o(m)[i][j] = INFTY; + BETA_o(m)[i][j] = INFTY; + BETA_n(m)[i][j] = INFTY; + } + } + + LOWER_BOUND(m) = -INFTY; + UPPER_BOUND(m) = INFTY; + NUM_V(m) = num_v; + return m; +} + +/* function definition + name: evaluate_matrix() + args: + job: updates the matrix structure for a given clock cycle + return value: + calls: +*/ +evaluate_matrix(g, m, c) +graph_t *g; +matrix_t *m; +double c; +{ + lsGen gen; + edge_t *e; + char *dummy; + st_generator *sgen; + vertex_t *u, *v; + int i, j, num_v, k; + double *value, val; + + num_v = NUM_V(m); + + foreach_edge (g, gen, e) { + u = g_e_source(e); + v = g_e_dest(e); + i = MID(u); + j = MID(v); + if (EVAL(e) == NOT_SET){ + W_o(m)[i][j] = INFTY; + BETA_o(m)[i][j] = INFTY; + } else { + W_o(m)[i][j] = FIXED(e); + BETA_o(m)[i][j] = 0; + } + if (ABS(DUTY(e)) <= 1) { + if (W_o(m)[i][j] > DUTY(e) * c) { + W_o(m)[i][j] = DUTY(e) * c; + BETA_o(m)[i][j] = DUTY(e); + } + } + + if (st_count(CONS1(e)) > 0) { + st_foreach_item(CONS1(e), sgen, (char **)&dummy, (char **)&value) { + k = (int)dummy; + if ((val = -(*value) + k * c) < W_o(m)[i][j]) { + W_o(m)[i][j] = val; + BETA_o(m)[i][j] = (double)k; + } + } + } + if (CONS2(e) != NIL(double)) { + for (k = 0; k < 2; k++) { + if (CONS2(e)[k] < INFTY) { + if ((val = CONS2(e)[k] + k * c) < W_o(m)[i][j]) { + W_o(m)[i][j] = val; + BETA_o(m)[i][j] = (double)k; + } + } + } + } + } + if (debug_type == GENERAL || debug_type == ALL) { + (void)fprintf(sisout, "Weights\n"); + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + (void)fprintf(sisout, "%-10.2lf", W_o(m)[i][j]); + } + (void)fprintf(sisout, "\n"); + } + (void)fprintf(sisout, "\n"); + + (void)fprintf(sisout, "beta\n"); + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + (void)fprintf(sisout, "%-10.2lf", BETA_o(m)[i][j]); + } + (void)fprintf(sisout, "\n"); + } + (void)fprintf(sisout, "\n"); + } +} + +/* function definition + name: update_matrix() + args: + job: Check if a negative cycle is detected in Floyd warshall. + If so update bounds . + return value:int + calls: +*/ + +int +update_matrix(m) +matrix_t *m; +{ + int flag, num_v; + register int i, j; + double c; + + num_v = NUM_V(m); + flag = TRUE; + c = CURRENT_CLOCK(m); + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + if (i == j) { /* Diagonal entry */ + /*-------------- */ + if (W_n(m)[i][j] < -EPS1) { /* Entry is -ve */ + /* ------------ */ + if (BETA_n(m)[i][i] <= 0) { /* Coeff of c is <= 0 */ + /*--------------------*/ + return INFEASIBLE; + } else { + LOWER_BOUND(m) = + MAX(LOWER_BOUND(m),(-W_n(m)[i][i]/BETA_n(m)[i][i])+c); + flag = FALSE; + } + } else if (W_n(m)[i][i] >= 0 && W_n(m)[i][i] < INFTY) { + if (BETA_n(m)[i][i] < 0) { + UPPER_BOUND(m) = + MIN(UPPER_BOUND(m),(W_n(m)[i][i]/-BETA_n(m)[i][i])+c); + } + } + W_o(m)[i][j] = W_n(m)[i][j]; + BETA_o(m)[i][j] = BETA_n(m)[i][j]; + } else { /* old iterate = new iterate */ + if (W_n(m)[i][j] < INFTY) { + W_o(m)[i][j] = W_n(m)[i][j]; + BETA_o(m)[i][j] = BETA_n(m)[i][j]; + } + } + } + } + if (debug_type == GENERAL || debug_type == ALL) { + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + (void)fprintf(sisout, "%-10.2lf ", W_o(m)[i][j]); + } + (void)fprintf(sisout, "\n"); + } + (void)fprintf(sisout, "\n"); + } + + if (!flag) { /* There is negative cycle */ + /* CLearly C_L > c */ + /* Check for c_L < c_U */ + if (LOWER_BOUND(m) > UPPER_BOUND(m)) return INFEASIBLE; + CURRENT_CLOCK(m) = LOWER_BOUND(m); + /* Initialize for new Floyd Warshall */ + /* --------------------------------- */ + for (i = 0; i < num_v; i++) { + for (j = 0; j < num_v; j++) { + W_o(m)[i][j] = INFTY; + W_n(m)[i][j] = INFTY; + BETA_o(m)[i][j] = INFTY; + BETA_n(m)[i][j] = INFTY; + } + } + return NEGATIVE_CYCLE; + } + return ALL_POSITIVE_CYCLES; +} + +/* function definition + name: free_matrix() + args: + job: Frees the memory associated with the mtrix + return value: + calls: +*/ +free_matrix(m) +matrix_t *m; +{ + int num_v, i; + + num_v = NUM_V(m); + for (i = 0; i < num_v; i++) { + FREE(W_o(m)[i]); + FREE(W_n(m)[i]); + FREE(BETA_n(m)[i]); + FREE(BETA_o(m)[i]); + } + FREE(W_o(m)); + FREE(W_n(m)); + FREE(BETA_n(m)); + FREE(BETA_o(m)); + FREE(m); +} +#endif /* SIS */ diff --git a/sis/timing/timing_graph.c b/sis/timing/timing_graph.c new file mode 100644 index 0000000..7b02666 --- /dev/null +++ b/sis/timing/timing_graph.c @@ -0,0 +1,469 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/timing/timing_graph.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:59 $ + * + */ +#ifdef SIS +#include "timing_int.h" + +/* Debug global variables */ +static int lnum; +static double mmd; + +/* function definition + name: tmg_network_to_graph() + args: network, model, algorithm (for CLOCK_OPTIMIZATION or + CLOCK_VERIFICATION) + job: converts the network to a latch to latch graph + return value: graph_t * + calls: tmg_alloc_graph(), + delay_trace(), + tmg_alloc_node, g_add_vertex(), tmg_latch_get_phase(), tmg_get_latch_type(), + tmg_init_pi_arrival_time(), + tmg_build_graph(), + tmg_update_K_edge(), set_mmd() +*/ + +graph_t * +tmg_network_to_graph(network, model, algorithm) +network_t *network; +delay_model_t model; +algorithm_type_t algorithm; +{ + node_t *pi, *node; + graph_t *latch_graph; + vertex_t *vertex; + latch_t *latch; + lsGen gen; + + mmd = 0; + lnum = 1; + + assert(algorithm == OPTIMAL_CLOCK || algorithm == CLOCK_VERIFY); + latch_graph = g_alloc(); + latch_graph->user_data = (gGeneric )tmg_alloc_graph(algorithm, network); + if (tmg_get_phase_inv() && (array_n(CL(latch_graph)) > 1)) { + (void)fprintf(sisout, "Error more than one clock phase\n"); + (void)fprintf(sisout, "-I flag assumes a two phase clocking scheme\n"); + (void)fprintf(sisout, "with inverted phases\n"); + tmg_free_graph_structure(latch_graph); + return NIL(graph_t); + } + + delay_trace(network, model); + foreach_node(network, gen, node) { + tmg_delay_alloc(node); + DIRTY(node) = TRUE; + } + + /* Enumerate latch to latch paths */ + /* ------------------------------ */ + + foreach_primary_input (network, gen, pi) { + if (clock_get_by_name(network, node_long_name(pi)) == + NIL(sis_clock_t)) { + + /* skip search for PI which is clock */ + /* --------------------------------- */ + + if (network_is_real_pi(network, pi)) { + if (HOST(latch_graph) == NIL(vertex_t)) { + vertex = g_add_vertex(latch_graph); + vertex->user_data = (gGeneric )tmg_alloc_node(algorithm); + ID(vertex) = 0; + TYPE(vertex) = NNODE; + HOST(latch_graph) = vertex; + } else { + vertex = HOST(latch_graph); + } + } else { /* node is a fake pi */ + /* ----------------- */ + latch = latch_from_node(pi); + assert(latch != NIL(latch_t)); + if ((vertex = MVER(latch)) == NIL(vertex_t)) { + vertex = g_add_vertex(latch_graph); + UNDEF(latch) = (char *)vertex; + vertex->user_data = (gGeneric )tmg_alloc_node(algorithm); + ID(vertex) = lnum; + lnum++; + TYPE(vertex) = LATCH; + LTYPE(vertex) = tmg_get_latch_type(latch); + NODE(vertex)->latch = latch; + if ((PHASE(vertex) = + tmg_latch_get_phase(latch,CL(latch_graph))) + == NOT_SET) { + tmg_free_graph_structure(latch_graph); + return NIL(graph_t); + } + } + } + tmg_init_pi_arrival_time(pi, model); + DIRTY(pi) = FALSE; + if (!tmg_build_graph(pi, latch_graph, vertex, model, algorithm)) { + tmg_free_graph_structure(latch_graph); + return NIL(graph_t); + } + } + } + + foreach_node (network, gen, node) { + tmg_delay_free(node); + } + + /* Sanity check for connectivity */ + /* ----------------------------- */ + + if (debug_type == LGRAPH || debug_type == ALL) { + (void)g_check(latch_graph); + } + + /* Update the K for each edge */ + /* -------------------------- */ + + if (!tmg_update_K_edge(latch_graph)) { + tmg_free_graph_structure(latch_graph); + return NIL(graph_t); + } + + foreach_latch(network, gen, latch) { + UNDEF(latch) = NIL(char); + } + return latch_graph; +} + +/* function definition + name: tmg_build_graph() + args: node, graph, source_vertex + job: from a source finds paths to all latches reachable from it + return value: - + calls: network_tfo(), get_pin_delay(), + tmg_alloc_node(), + tmg_alloc_edge(), + node_get_delay(), + tmg_get_latch_type() +*/ +int +tmg_build_graph(pi, latch_graph, source, model, algorithm) +node_t *pi; +graph_t *latch_graph; +vertex_t *source; +delay_model_t model; +algorithm_type_t algorithm; +{ + array_t *dfs_array; + node_t *node, *fi; + delay_time_t delay; + delay_pin_t *pin_delay; + latch_t *latch; + vertex_t *sink; + edge_t *edge; + int i, j; + + dfs_array = network_tfo(pi, network_num_internal(pi->network)); + for (i = array_n(dfs_array)-1; i > -1; i--) { + node = array_fetch(node_t *, dfs_array, i); + maxdr(node) = -INFTY; + maxdf(node) = -INFTY; + mindr(node) = INFTY; + mindf(node) = INFTY; + + if (node_function(node) != NODE_PO) { + foreach_fanin(node, j, fi) { + if (!DIRTY(fi)) { + pin_delay = get_pin_delay (node, j, model); + delay.rise = pin_delay->drive.rise * delay_load(node); + delay.fall = pin_delay->drive.fall * delay_load(node); + if (node_function(node) != NODE_PI) { + delay.rise += pin_delay->block.rise; + delay.fall += pin_delay->block.fall; + } + if (pin_delay->phase == PHASE_INVERTING || + pin_delay->phase == PHASE_NEITHER) { + maxdr(node) = MAX(maxdr(node), maxdf(fi) + + delay.rise); + maxdf(node) = MAX(maxdf(node), maxdr(fi) + + delay.fall); + mindr(node) = MIN(mindr(node), mindf(fi) + + delay.rise); + mindf(node) = MIN(mindf(node), mindr(fi) + + delay.fall); + } + + if (pin_delay->phase == PHASE_NONINVERTING || + pin_delay->phase == PHASE_NEITHER) { + maxdr(node) = MAX(maxdr(node), maxdr(fi) + + delay.rise); + maxdf(node) = MAX(maxdf(node), maxdf(fi) + + delay.fall); + mindr(node) = MIN(mindr(node), mindr(fi) + + delay.rise); + mindf(node) = MIN(mindf(node), mindf(fi) + + delay.fall); + } + } + } + DIRTY(node) = FALSE; + } else { + fi = node_get_fanin(node, 0); + if (!network_is_real_po(node->network, node)) { + latch = latch_from_node(node); + assert(latch != NIL(latch_t)); + if ((sink = MVER(latch)) == NIL(vertex_t)) { + sink = g_add_vertex(latch_graph); + UNDEF(latch) = (char *)sink; + sink->user_data = (gGeneric )tmg_alloc_node(algorithm); + ID(sink) = lnum; + lnum++; + TYPE(sink) = LATCH; + LTYPE(sink) = tmg_get_latch_type(latch); + NODE(sink)->latch = latch; + if ((PHASE(sink) = + tmg_latch_get_phase(latch,CL(latch_graph))) + == NOT_SET) { + return FALSE; + } + + } + /* Edge guaranteed to be unique: + sink appears only once in array */ + /* ------------------------------- */ + + if ((TYPE(source) == LATCH && TYPE(sink) == LATCH) && + PHASE(source) == PHASE(sink) && + (LTYPE(source) == LSH || LTYPE(source) == LSL) && + LTYPE(source) == LTYPE(sink)) { + + /* A bug in SIS for some reason creates edges. + Have sent bug report to be fixed */ + /* ----------------------------------------- */ + + tmg_report_bug(source, sink); + + } else { + if (!g_get_edge(source, sink, &edge)) { + edge->user_data = (gGeneric) tmg_alloc_edge(); + } + mmd = MAX(mmd, maxdf(fi)); + mmd = MAX(mmd, maxdr(fi)); + De(edge) = MAX(De(edge), maxdr(fi)); + De(edge) = MAX(De(edge), maxdf(fi)); + de(edge) = MIN(de(edge), mindr(fi)); + de(edge) = MIN(de(edge), mindf(fi)); + assert(De(edge) >= de(edge)); /* Sanity check */ + } + } + } + } + for (i = 0; i < array_n(dfs_array); i++) { + node = array_fetch(node_t *, dfs_array, i); + DIRTY(node) = TRUE; + } + array_free(dfs_array); + return TRUE; +} + +/* function definition + name: tmg_update_K_edge() + args: edge + job: stores the value of K in edge->user_data->K + return value: none + calls: tmg_latch_get_clock(), + +*/ + +int +tmg_update_K_edge(g) +graph_t *g; +{ + lsGen gen; + edge_t *edge; + vertex_t *from, *to; + sis_clock_t *clock1, *clock2, *clock; + array_t *clock_array; + int i; + + clock_array = GRAPH(g)->clock_order; + foreach_edge(g, gen, edge) { + from = g_e_source(edge); + to = g_e_dest(edge); + + if ((TYPE(from) == NNODE) || (TYPE(to) == NNODE)) { + Ke(edge) = 0; + } else { + clock1 = tmg_latch_get_clock(NODE(from)->latch); + clock2 = tmg_latch_get_clock(NODE(to)->latch); + if (clock1 == NIL(sis_clock_t) || clock2 == NIL(sis_clock_t)) { + return 0; + } + if (clock1 == clock2) { + if (LTYPE(from) == LTYPE(to)) { + Ke(edge) = 1; + } else { + if (LTYPE(from) == LSH && LTYPE(to) == LSL) { + Ke(edge) = 1; + } else { + Ke(edge) = 0; + } + } + } else { + for (i = 0; i < array_n(clock_array); i++) { + clock = array_fetch(sis_clock_t *, clock_array, i); + if (clock == clock1) { + Ke(edge) = 0; + break; + } else if (clock == clock2) { + Ke(edge) = 1; + break; + } + } + } + } + } + return 1; +} + +/* function definition + name: tmg_print_latch_graph() + args: graph + job: debug option to print the latch graph + return value: - + calls: - +*/ +tmg_print_latch_graph(g) +graph_t *g; +{ + vertex_t *v, *f, *t; + edge_t *e; + lsGen gen, gen1; + + foreach_vertex(g, gen, v){ + foreach_in_edge(v, gen1, e){ + f = g_e_source(e); + if (TYPE(f) == NNODE) { + fprintf(sisout, "PI ->(%f- %f) %d\n", de(e), De(e), Ke(e)); + } else { + fprintf(sisout, "%d ->(%f - %f) %d\n", ID(f), + de(e), De(e), Ke(e)); + } + } + if (TYPE(v) == NNODE) { + (void)fprintf(sisout, "HOST ->\n"); + } else { + fprintf(sisout, " %d (phase %d)\n", ID(v), PHASE(v)); + } + + foreach_out_edge(v, gen1, e){ + t = g_e_dest(e); + if (TYPE(t) == NNODE) { + fprintf(sisout, "(%f - %f)->PO %d\n", de(e), De(e), Ke(e)); + } else { + fprintf(sisout, "(%f - %f)->%d %d\n", de(e), De(e), + ID(t), Ke(e)); + } + } + } +} + +/* function definition + name: tmg_init_pi_arrival_time() + args: node, model + job: initialize the arrival times in the latch graph + return value: - + calls: delay_get_pi_arrival_time() +*/ +tmg_init_pi_arrival_time(node, model) +node_t *node; +delay_model_t model; +{ + latch_t *latch; + lib_gate_t *gate; + delay_time_t delay, arrival; + delay_pin_t *pin_delay; + + if (network_is_real_pi(node->network, node)) { + pin_delay = get_pin_delay(node, 0, model); + + if (!delay_get_pi_arrival_time(node, &arrival)) { + arrival.rise = 0.0; + arrival.fall = 0.0; + } + + delay.rise = pin_delay->drive.rise * delay_load(node); + delay.fall = pin_delay->drive.fall * delay_load(node); + arrival.rise += delay.rise; + arrival.fall += delay.fall; + maxdr(node) = mindr(node) = arrival.rise; + maxdf(node) = mindf(node) = arrival.fall; + } else { + latch = latch_from_node(node); + assert(latch != NIL(latch_t)); + if (model == DELAY_MODEL_LIBRARY) { + gate = latch_get_gate(latch); + assert(gate != NIL(lib_gate_t)); + delay.rise = gate->clock_delay->block.rise + + gate->clock_delay->drive.rise * delay_load(node); + delay.fall = gate->clock_delay->block.fall + + gate->clock_delay->drive.fall * delay_load(node); + maxdr(node) = mindr(node) = delay.rise; + maxdf(node) = mindf(node) = delay.fall; + } else { + pin_delay = get_pin_delay(node, 0, model); + delay.rise = pin_delay->drive.rise * delay_load(node); + delay.fall = pin_delay->drive.fall * delay_load(node); + maxdr(node) = mindr(node) = delay.rise; + maxdf(node) = mindf(node) = delay.fall; + } + } +} + +/* havent figured this one yet- occurs in one huge example + The problem doesnt occur if you read library, map and do + c_opt. But should you read library, map, spit out mapped circuit + then re-read and do c_opt, this error creeps up. Possibly a + subtle bug in the map package!! */ + +tmg_report_bug(source, sink) +vertex_t *source, *sink; +{ + + (void)fprintf(sisout, "Error, path between latches on same phase\n"); + (void)fprintf(sisout, "\t \t input \t output\n"); + (void)fprintf(sisout, "source \t %s \t %s \n", + node_long_name(latch_get_input(NODE(source)->latch)), + node_long_name(latch_get_output(NODE(source)->latch))); + (void)fprintf(sisout, "sink \t %s \t %s \n", + node_long_name(latch_get_input(NODE(sink)->latch)), + node_long_name(latch_get_output(NODE(sink)->latch))); + +} + + +/* function definition + name: tmg_delay_alloc(), tmg_delay_free() + args: node + job: allocate/free data structure from node->undef1 used for storing + long / short paths + return value: void + calls: - +*/ +static void +tmg_delay_alloc(node) +node_t *node; +{ + UNDEF(node) = (char *)ALLOC(my_delay_t, 1); +} + +static void +tmg_delay_free(node) +node_t *node; +{ + my_delay_t *md; + + md = MDEL(node); + FREE(md); +} +#endif /* SIS */ diff --git a/sis/timing/timing_int.h b/sis/timing/timing_int.h new file mode 100644 index 0000000..6244f6a --- /dev/null +++ b/sis/timing/timing_int.h @@ -0,0 +1,275 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/timing/timing_int.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:00 $ + * + */ +#include "sis.h" +/* definitions */ +#define EPS 1e-3 +#define EPS1 1e-5 +#define EPS2 1e-2 +#define INFTY 10000 +#define NOT_SET -2 +#define NNODE 1 +#define LATCH 2 +#define FFF 1 +#define FFR 2 +#define LSH 3 +#define LSL 4 + +/* Data structures for Optimal Clocking and Clock Verification Routines*/ + +/* Debug options */ +typedef enum debug_enum debug_type_t; +enum debug_enum { + LGRAPH, CGRAPH, BB, GENERAL, NONE, VERIFY, ALL +}; + +typedef enum algorithm_enum algorithm_type_t; +enum algorithm_enum { + OPTIMAL_CLOCK, CLOCK_VERIFY +}; + +/* LATCH GRAPH structures: common for optimal clocking and clock + verification */ +typedef struct copt_node_struct copt_node_t; +typedef struct cv_node_struct cv_node_t; + +typedef struct l_node_struct l_node_t; +struct l_node_struct { + int pio; + int num; + latch_t *latch; + int latch_type; + int phase; + copt_node_t *copt; + cv_node_t *cv; +}; + +typedef struct l_edge_struct l_edge_t; +struct l_edge_struct { + double Dmax, Dmin; + int K; + double w; +}; + +typedef struct sp_matrix_struct sp_matrix_t; +typedef struct l_graph_struct l_graph_t; +struct l_graph_struct { + array_t *clock_order; + vertex_t *host; +}; + + +#define GRAPH(g) ((l_graph_t *)g->user_data) +#define NODE(n) ((l_node_t *)n->user_data) +#define EDGE(e) ((l_edge_t *)e->user_data) +#define De(e) (EDGE(e)->Dmax) +#define de(e) (EDGE(e)->Dmin) +#define Ke(e) (EDGE(e)->K) +#define We(e) (EDGE(e)->w) +#define ID(v) (NODE(v)->num) +#define TYPE(v) (NODE(v)->pio) +#define LTYPE(v) (NODE(v)->latch_type) +#define NLAT(v) (NODE(v)->latch) +#define PHASE(v) (NODE(v)->phase) +#define CL(g) (GRAPH(g)->clock_order) +#define HOST(g) (GRAPH(g)->host) + +/* END of LATCH GRAPH structures */ + +/* CONSTRAINT GRAPH structes: used ONLY for OPTIMAL CLOCKING*/ +typedef struct c_edge_struct c_edge_t; +struct c_edge_struct{ + int ignore; + int evaluate_c; + st_table *c_1; + double w, fixed_w, duty, *c_2; +}; + +typedef struct c_node_struct c_node_t; +struct c_node_struct{ + double p; + int id, m_id; +}; +typedef struct phase_struct phase_t; +struct phase_struct{ + vertex_t *rise, *fall; +}; + +typedef struct c_graph_struct c_graph_t; +struct c_graph_struct { + phase_t **phase_list; + int num_phases; + vertex_t *zero; +}; + +#define PHASE_LIST(g) (((c_graph_t *)g->user_data)->phase_list) +#define NUM_PHASE(g) (((c_graph_t *)g->user_data)->num_phases) +#define ZERO_V(g) (((c_graph_t *)g->user_data)->zero) +#define USER(e) ((c_edge_t *)e->user_data) +#define CONS1(e) (USER(e)->c_1) +#define CONS2(e) (USER(e)->c_2) +#define WEIGHT(e) (USER(e)->w) +#define FIXED(e) (USER(e)->fixed_w) +#define DUTY(e) (USER(e)->duty) +#define EVAL(e) (USER(e)->evaluate_c) +#define IGNORE(e) (USER(e)->ignore) +#define P(v) (((c_node_t *)v->user_data)->p) +#define PID(v) (((c_node_t *)v->user_data)->id) +#define MID(v) (((c_node_t *)v->user_data)->m_id) +#define FROM 0 +#define TO 1 +#define get_vertex(v, flag, g) \ + (flag == FROM ? ((LTYPE(v) == FFR || LTYPE(v) == \ + LSH) ? PHASE_LIST(g)[PHASE(v) - 1]->rise : \ + PHASE_LIST(g)[PHASE(v)-1]->fall) : \ + ((LTYPE(v) == FFR || LTYPE(v) == \ + LSL) ? PHASE_LIST(g)[PHASE(v) - 1]->rise : \ + PHASE_LIST(g)[PHASE(v)-1]->fall)) + +#define get_index(v, flag, g) \ + (flag == FROM ? ((LTYPE(v) == FFR || LTYPE(v) == \ + LSH) ? PHASE(v) - 1 : \ + PHASE(v)-1+NUM_PHASE(g)) : \ + ((LTYPE(v) == FFR || LTYPE(v) == \ + LSL) ? PHASE(v) - 1 : \ + PHASE(v)-1+NUM_PHASE(g))) + +#define get_vertex_from_index(g, i) \ + (i < NUM_PHASE(g) ? (PHASE_LIST(cg)[i])->rise : \ + (PHASE_LIST(cg)[(i - NUM_PHASE(g))])->fall) + +/* END of CONSTRAINT GRAPH structure */ + +/* MATRIX STRUCTURES for Solving the Optimal CLocking Problem */ +typedef struct matrix_struct matrix_t; +struct matrix_struct { + double **W_old, **W_new, **beta_old, **beta_new, c, c_L, c_U; + int num_v; +}; + +#define W_n(m) (m->W_new) +#define W_o(m) (m->W_old) +#define BETA_n(m) (m->beta_new) +#define BETA_o(m) (m->beta_old) +#define CURRENT_CLOCK(m) (m->c) +#define LOWER_BOUND(m) (m->c_L) +#define UPPER_BOUND(m) (m->c_U) +#define NUM_V(m) (m->num_v) +/* END of MATRIX structure */ + +/* DELAY structure for sequential delay trace */ +typedef struct my_delay_struct my_delay_t; +struct my_delay_struct { + delay_time_t max, min; + int dirty; +}; +#define UNDEF(n) (n->undef1) +#define MDEL(n) ((my_delay_t *)(n->undef1)) +#define maxdr(n) (MDEL(n)->max.rise) +#define maxdf(n) (MDEL(n)->max.fall) +#define mindr(n) (MDEL(n)->min.rise) +#define mindf(n) (MDEL(n)->min.fall) +#define DIRTY(n) (MDEL(n)->dirty) +#define MVER(l) ((vertex_t *)(l->undef1)) +/* END of DELAY structures */ + +/* GRAPH structures for OPTIMAL CLOCK COMPUTATION*/ +struct copt_node_struct { + double w, prevw; + int r, dirty; + vertex_t *parent; +}; +#define COPT(v) (NODE(v)->copt) +#define Wv(v) (COPT(v)->w) +#define PREV_Wv(v) (COPT(v)->prevw) +#define Rv(v) (COPT(v)->r) +#define PARENT(v) (COPT(v)->parent) +#define COPT_DIRTY(v) (COPT(v)->dirty) + +struct cv_node_struct { + double A, D, a, d; + int dirty; +}; +#define CV(v) (NODE(v)->cv) +#define ARR(v) (CV(v)->A) +#define arr(v) (CV(v)->a) +#define DEP(v) (CV(v)->D) +#define dep(v) (CV(v)->d) +#define CV_DIRTY(v) (CV(v)->dirty) + +typedef struct clock_event_struct clock_event_t; +struct clock_event_struct { + double *rise; + double *fall; + int num_phases; + double *shift; +}; +#define NUM_CLOCK(e) (e->num_phases) +#define RISE(e) (e->rise) +#define FALL(e) (e->fall) +#define SHIFT(e) (e->shift) + +/* GLOBAL vars */ +debug_type_t debug_type; + + +/* Routine defs */ + +/* timing_graph.c */ +graph_t *tmg_network_to_graph(); +int timing_update_K_edge(); +int tmg_build_graph(); +static void tmg_delay_alloc(); +static void tmg_delay_free(); +int tmg_all_negative_cycles(); + +/* timing_util.c */ +array_t *tmg_determine_clock_order(); +sis_clock_t *tmg_latch_get_clock(); +double tmg_get_set_up(); +double tmg_get_hold(); +double tmg_get_min_sep(); +double tmg_get_max_sep(); +c_edge_t *tmg_alloc_cedge(); +c_graph_t *tmg_alloc_cgraph(); +l_graph_t *tmg_alloc_graph(); +l_node_t *tmg_alloc_node(); +l_edge_t *tmg_alloc_edge(); +int tmg_get_gen_algorithm_flag(); +double tmg_max_clock_skew(); +double tmg_min_clock_skew(); + +/* timing_comp.c */ +int cycle_in_graph(); +static int my_pq_cmp(); +double tmg_compute_optimal_clock(); +graph_t *tmg_construct_clock_graph(); +vertex_t *tmg_get_constraint_vertex(); +double tmg_guess_clock_bound(); +double tmg_clock_lower_bound(); +double tmg_solve_constraints(); +int tmg_all_negative_cycles(); +int tmg_is_feasible(); +double tmg_solve_gen_constraints(); +array_t *tmg_compute_intervals(); +matrix_t *tmg_init_matrix(); +int timing_exterior_path_search(); +int tmg_update_matrix(); + +/* timing_seq.c */ +delay_time_t tmg_node_get_delay(); +delay_time_t tmg_map_get_delay(); + +/* timing_verify.c */ +int tmg_check_clocking_scheme(); +int trace_recursive_path(); +clock_event_t *tmg_get_clock_events(); + + + diff --git a/sis/timing/timing_seq.c b/sis/timing/timing_seq.c new file mode 100644 index 0000000..536fc26 --- /dev/null +++ b/sis/timing/timing_seq.c @@ -0,0 +1,88 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/timing/timing_seq.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:00 $ + * + */ +#ifdef SIS +#include "timing_int.h" + +/* function definition + name: tmg_node_get_delay() + args: node, delay_model + job: return the max and min delay through the node. + HACK to store the max delay in one entry and min delay in + the other. + return value: delay_time_t + calls: tmg_map_get_delay() +*/ +delay_time_t +tmg_node_get_delay(node, model) +node_t *node; +delay_model_t model; +{ + delay_time_t delay; + + if (node_function(node) == NODE_PI || node_function(node) == NODE_PO) { + delay.rise = 0; + delay.fall = 0; + return delay; + } + if (model == DELAY_MODEL_UNIT) { + delay.rise = 1 + 0.2 * node_num_fanout(node); + delay.fall = delay.rise; + } else { + delay = tmg_map_get_delay(node); + } + return delay; +} + +/* function definition + name: tmg_map_get_delay() + args: node + job: get the mapped delay for the gate + return value: (delay_time_t) + calls: - +*/ +delay_time_t +tmg_map_get_delay(node) +node_t *node; +{ + lib_gate_t *gate; + delay_time_t t, **a_t, delay; + double max_time, min_time; + int i, j, n; + + gate = lib_gate_of(node); + n = lib_gate_num_in(gate); + a_t = ALLOC(delay_time_t *, n); + for(i = 0; i < n; i++){ + a_t[i] = ALLOC(delay_time_t, 1); + } + delay.rise = -INFTY; + + delay.fall = INFTY; + for(i = 0; i < n; i++){ + for(j = 0; j < n; j++){ + a_t[j]->rise = a_t[j]->fall = -INFTY; + } + a_t[i]->rise = a_t[i]->fall = 0.0; + + t = delay_map_simulate(n, a_t, gate->delay_info, (double)0); + max_time = MAX(t.rise, t.fall); + min_time = MIN(t.rise, t.fall); + + delay.rise = MAX(max_time, delay.rise); + delay.fall = MIN(min_time, delay.fall); + } + + for(i = 0; i < n; i++){ + FREE(a_t[i]); + } + FREE(a_t); + return delay; +} +#endif /* SIS */ diff --git a/sis/timing/timing_util.c b/sis/timing/timing_util.c new file mode 100644 index 0000000..45144ec --- /dev/null +++ b/sis/timing/timing_util.c @@ -0,0 +1,609 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/timing/timing_util.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:00 $ + * + */ +#ifdef SIS +#include "timing_int.h" + +/* Buch of local global variables */ +static double Uset_up; +static double Uhold; +static double Umin_sep; +static double Umax_sep; +static int algorithm_flag; +static int phase_inv; + +static int tmg_clock_compare(); + +int +timing_network_check(network, model) +network_t *network; +delay_model_t model; +{ + node_t *gate, *clock_pi; + sis_clock_t *clock; + latch_t *latch; + lsGen gen; + + if (network_num_internal(network) == 0 || + network_num_latch(network) == 0) { + (void)fprintf(sisout, "Serious error: no memory elements\n"); + return FALSE; + } + if (model == DELAY_MODEL_LIBRARY) { + if(!lib_network_is_mapped(network)) { + (void)fprintf(sisout,"Serious error: not all nodes are mapped\n"); + return FALSE; + } + } + + foreach_latch(network, gen, latch) { + gate = latch_get_control(latch); + if(gate == NIL(node_t)){ + (void)fprintf(sisout,"Serious error: latch without clock \n"); + return FALSE; + } + clock_pi = node_get_fanin(gate, 0); + if(node_function(clock_pi) != NODE_PI){ + (void)fprintf(sisout,"Serious error: logic preceeding latch\n"); + return FALSE; + } + clock = clock_get_by_name(clock_pi->network, node_long_name(clock_pi)); + if (clock == NIL(sis_clock_t)) { + (void)fprintf(sisout, "Serious error: unable to locate clock\n"); + (void)fprintf(sisout, "to latch \n"); + return FALSE; + } + } + return TRUE; +} + +/* function definition + name: tmg_alloc_graph() + args: algorithm (OPTIMAL_CLOCK or CLOCK_VERIFY), network + job: allocate data structures + return value: l_graph_t * + calls: tmg_determine_clock_order() +*/ +l_graph_t * +tmg_alloc_graph(algorithm, network) +algorithm_type_t algorithm; +network_t *network; +{ + l_graph_t *g; + + g = ALLOC(l_graph_t, 1); + g->clock_order = tmg_determine_clock_order(network); + g->host = NIL(vertex_t); + return g; +} + +/* function definition + name: tmg_alloc_node() + args: - + job: allocate structure to store with node->user_data in + the latch_graph + return value: (l_node_t *) + calls: - +*/ +l_node_t * +tmg_alloc_node(algorithm) +algorithm_type_t algorithm; +{ + l_node_t *node; + copt_node_t *copt; + cv_node_t *cv; + + node = ALLOC(l_node_t, 1); + node->pio = -1; + node->num = -1; + node->latch_type = -1; + node->latch = NIL(latch_t); + node->phase = -1; + node->copt = NIL(copt_node_t); + node->cv = NIL(cv_node_t); + if (algorithm == OPTIMAL_CLOCK) { + copt = ALLOC(copt_node_t, 1); + copt->w = 0.0; + copt->prevw = 0.0; + copt->r = 0; + copt->dirty = FALSE; + node->copt = copt; + } else if (algorithm == CLOCK_VERIFY) { + cv = ALLOC(cv_node_t, 1); + cv->A = cv->a = cv->D = cv->d = 0.0; + node->cv = cv; + } + return node; +} + +/* function definition + name: tmg_alloc_edge() + args: - + job: allocate structure to store with edge->user_data in latch_graph + return value: (l_edge_t *) + calls: - +*/ + +l_edge_t * +tmg_alloc_edge() +{ + l_edge_t *edge; + + edge = ALLOC(l_edge_t, 1); + edge->Dmax = -INFTY; + edge->Dmin = INFTY; + edge->K = -1; + return edge; +} + + +/* function definition + name: tmg_get_latch_type + args: latch + job: finds if latch is a flip-flop or level sensitive + return value: int (LS for level-sensitive and FF for flip-flop) + calls: - +*/ +int +tmg_get_latch_type(latch) +latch_t *latch; +{ + switch (latch_get_type(latch)) { + case FALLING_EDGE: + return FFF; + case RISING_EDGE: + return FFR; + case ACTIVE_HIGH: + return LSH; + case ACTIVE_LOW: + return LSL; + default: + fprintf(sisout, "Warning latch type unknown\n"); + fprintf(sisout, "Assuming edge-triggered on falling edge\n"); + return FFF; + } +} + + +/* function defipnition + name: g_get_edge() + args: source, sink, &edge + job: check if edge is present + return value: 1 if edge is present - edge returned in edge, else + 0 if no edge - allocate new edge and returned in edge + calls: - +*/ + +int +g_get_edge(from, to, edge) +vertex_t *from; +vertex_t *to; +register edge_t **edge; +{ + lsList in_edges; + lsGen gen1; + + in_edges = g_get_in_edges(to); + + for (gen1 = lsStart(in_edges); lsNext(gen1, (lsGeneric *) edge, LS_NH) + == LS_OK || ((void) lsFinish(gen1), 0); ) { + if (from == g_e_source(*edge)) { + lsFinish(gen1); + return 1; + } + } + *edge = g_add_edge(from, to); + return FALSE; +} + + +/* function definition + name: tmg_determine_clock_order() + args: network + job: construct an array of clock signals according to the + ordering (e1 <= e1 <= ...en) + return value: (array_t *) + calls: +*/ + +array_t * +tmg_determine_clock_order(network) +network_t *network; +{ + sis_clock_t *clock; + lsGen gen; + int no_sort; + array_t *clock_order; + clock_edge_t transition; + int tmg_clock_compare(), i; + double e1; + + clock_order = array_alloc(sis_clock_t *, 0); + no_sort = FALSE; + foreach_clock(network, gen, clock){ + array_insert_last(sis_clock_t *, clock_order, clock); + transition.clock = clock; + transition.transition = FALL_TRANSITION; + e1 = clock_get_parameter(transition, CLOCK_NOMINAL_POSITION); + if(e1 == CLOCK_NOT_SET ){ /* clock edges not set!! */ + (void)fprintf(sisout,"Warning clock phases not set\n"); + (void)fprintf(sisout,"Arbitrary selection\n"); + no_sort = TRUE; + } + } + + /* Compute the clock ordering by sorting the clock edges- + tmg_clock_compare() */ + /* --------------- */ + + if(!no_sort){ + array_sort(clock_order, tmg_clock_compare); + } + if(debug_type == ALL || debug_type == LGRAPH) { + for(i = 0; i < array_n(clock_order); i++) { + clock = array_fetch(sis_clock_t *, clock_order, i); + (void)fprintf(sisout,"%s\n", clock_name(clock)); + } + } + return clock_order; +} + +/* function definition + name: tmg_latch_get_clock() + args: latch_t *latch + job: returns the clock signal on the gate to trhe latch + return value: sis_clock_t * + calls: - +*/ +sis_clock_t * +tmg_latch_get_clock(latch) +latch_t *latch; +{ + node_t *gate, *clock_pi; + sis_clock_t *clock; + + gate = latch_get_control(latch); + clock_pi = node_get_fanin(gate, 0); + clock = clock_get_by_name(clock_pi->network, node_long_name(clock_pi)); + return clock; +} + + +/* Sorts the clock phases */ +/* function definition + name: tmg_clock_compare() + args: sis_clock_t * clock1,*clock2 + job: used in array_sort to sort the clock signals according + to falling edges + return value: int + calls: +*/ +static int +tmg_clock_compare(k1, k2) +char **k1; +char **k2; +{ + sis_clock_t *clock1, *clock2; + clock_edge_t transition; + double e1, e2; + + clock1 = (sis_clock_t *)(*k1); + clock2 = (sis_clock_t *)(*k2); + transition.clock = clock1; + transition.transition = FALL_TRANSITION; + e1 = clock_get_parameter(transition, CLOCK_NOMINAL_POSITION); + + transition.clock = clock2; + transition.transition = FALL_TRANSITION; + e2 = clock_get_parameter(transition, CLOCK_NOMINAL_POSITION); + if (e1 - e2 < 0) { + return -1; + } else if (e1 - e2 > 0) { + return 1; + } else { + return 0; + } +} + +/* function definition + name: tmg_latch_get_phase() + args: latch_t *l, graph_t *g + job: returns an int from 1, 2, ... num_phases giving the phase of control + signal + return value: int + calls: +*/ +int +tmg_latch_get_phase(l, a) +latch_t *l; +array_t *a; +{ + int i; + + for (i = 0; i < array_n(a); i++) { + if (array_fetch(sis_clock_t *, a, i) == + tmg_latch_get_clock(l)) return (i+1); + } + + /* NOT REACHED */ + (void)fprintf(sisout, "Serious error: latch without clock signal!\n"); + return NOT_SET; +} + +tmg_set_set_up(s) +double s; +{ + Uset_up = s; +} + +tmg_set_hold(s) +double s; +{ + Uhold = s; +} + +double +tmg_get_set_up(v) +vertex_t *v; +{ + lib_gate_t *gate; + latch_time_t **lt; + + if ((gate = latch_get_gate(NLAT(v))) != NIL(lib_gate_t)) { + lt = lib_gate_latch_time(gate); + return lt[0]->setup; + } + return Uset_up; +} + +double +tmg_get_hold(v) +vertex_t *v; +{ + lib_gate_t *gate; + latch_time_t **lt; + + if ((gate = latch_get_gate(NLAT(v))) != NIL(lib_gate_t)) { + lt = lib_gate_latch_time(gate); + return lt[0]->hold; + } + + return Uhold; +} + +tmg_set_min_sep(s) +double s; +{ + Umin_sep = s; +} + +tmg_set_max_sep(s) +double s; +{ + Umax_sep = s; +} + +double +tmg_get_min_sep() +{ + return Umin_sep; +} + +double +tmg_get_max_sep() +{ + return Umax_sep; +} + +/* function definition + name: tmg_alloc_cedge() + args: - + job: allocates memory for an edge in the constraint graph + return value: c_edge_t * + calls: +*/ +c_edge_t * +tmg_alloc_cedge() +{ + c_edge_t *edge; + + edge = ALLOC(c_edge_t, 1); + edge->c_1 = st_init_table(st_numcmp, st_numhash); + edge->c_2 = NIL(double); + edge->evaluate_c = NOT_SET; + edge->fixed_w = INFTY; + edge->ignore = FALSE; + edge->w = INFTY; + edge->duty = 2; + return edge; + +} + + +static void +tmg_cg_free_g(c) +gGeneric c; +{ + c_graph_t *g; + g = (c_graph_t *)c; + + FREE(g->phase_list); + FREE(g); +} + +static void +tmg_cg_free_v(c) +gGeneric c; +{ + c_node_t *n; + + n = (c_node_t *)c; + FREE(n); +} + +static void +tmg_cg_free_e(c) +gGeneric c; +{ + c_edge_t *e; + st_generator *sgen; + char *dummy; + double *value; + + e = (c_edge_t *)c; + + st_foreach_item(e->c_1, sgen, (char **)&dummy, (char **)&value) { + FREE(value); + } + st_free_table(e->c_1); + if (e->c_2 != NIL(double)) { + FREE(e->c_2); + } + FREE(e); +} + +/* function definition + name: tmg_constraint_graph_free() + args: graph *g + job: frees memory associated with the clock graph + return value: - + calls: tmg_cg_free_g(), tmg_cg_free_v(), tmg_cg_free_e() +*/ +tmg_constraint_graph_free(g) +graph_t *g; +{ + int i; + phase_t *p; + + for (i = 0; i < NUM_PHASE(g); i++) { + p = PHASE_LIST(g)[i]; + FREE(p); + } + g_free(g, tmg_cg_free_g, tmg_cg_free_v, tmg_cg_free_e); +} + + +tmg_set_gen_algorithm_flag(value) +int value; +{ + algorithm_flag = value; +} + +int +tmg_get_gen_algorithm_flag() +{ + return algorithm_flag; +} + +tmg_set_phase_inv(flag) +int flag; +{ + phase_inv = flag; +} + +int +tmg_get_phase_inv() +{ + return phase_inv; +} + +c_graph_t * +tmg_alloc_cgraph() +{ + c_graph_t *c; + + c = ALLOC(c_graph_t, 1); + return c; +} + +tmg_alloc_phase_vertices(cg, lg) +graph_t *cg, *lg; +{ + phase_t **list; + int i; + + list = ALLOC(phase_t *, array_n(CL(lg))); + for (i = 0; i < array_n(CL(lg)); i++) { + list[i] = ALLOC(phase_t, 1); + list[i]->rise = g_add_vertex(cg); + list[i]->rise->user_data = (gGeneric)ALLOC(c_node_t, 1); + list[i]->fall = g_add_vertex(cg); + list[i]->fall->user_data = (gGeneric)ALLOC(c_node_t, 1); + PID(list[i]->rise) = i+1; + PID(list[i]->fall) = -(i+1); + } + PHASE_LIST(cg) = list; + NUM_PHASE(cg) = array_n(CL(lg)); +} + + +/* function definition + name: f_free_g(), f_free_v(), f_free_e() + args: graph, vertex, edge + job: free associated data in ->user_data + return value: - + calls: - +*/ +static void +tmg_lg_free_g(c) +gGeneric c; +{ + l_graph_t *g; + + g = (l_graph_t *)c; + array_free(g->clock_order); + FREE(g); +} + +static void +tmg_lg_free_v(c) +gGeneric c; +{ + l_node_t *n; + n = (l_node_t *)c; + if (n->copt != NIL(copt_node_t)) { + FREE(n->copt); + } + if (n->cv != NIL(cv_node_t)) { + FREE(n->cv); + } + FREE(n); +} + +static void +tmg_lg_free_e(c) +gGeneric c; +{ + l_edge_t *e; + e = (l_edge_t *)c; + FREE(e); +} + + +tmg_free_graph_structure(latch_graph) +graph_t *latch_graph; +{ + g_free(latch_graph, tmg_lg_free_g, tmg_lg_free_v, tmg_lg_free_e); +} + + +double +tmg_max_clock_skew(u) +vertex_t *u; +{ + return (double)(0); +} + +double +tmg_min_clock_skew(u) +vertex_t *u; +{ + return (double)(0); +} +#endif /* SIS */ diff --git a/sis/timing/timing_verify.c b/sis/timing/timing_verify.c new file mode 100644 index 0000000..46a1131 --- /dev/null +++ b/sis/timing/timing_verify.c @@ -0,0 +1,391 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/timing/timing_verify.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:00 $ + * + */ +#ifdef SIS +#include "timing_int.h" + + +/* function definition + name: tmg_check_clocking_scheme() + args: graph, network + job: verify the clocking schedule + return value: 1 on success, 0 on failiure + calls: tmg_get_clock_events() +*/ + +int +tmg_check_clocking_scheme(latch_graph, network) +graph_t *latch_graph; +network_t *network; +{ + clock_event_t *clock_event; + int phase, phase1, converged, i, num_e, flag; + double cycle, temp, max_arrival, min_arrival, shift; + lsGen gen, gen1; + edge_t *e; + vertex_t *u, *w; + + cycle = clock_get_cycletime(network); + if (cycle < 0) { + (void)fprintf(sisout, "Clock cycle not set\n"); + (void)fprintf(sisout, "Serious error\n"); + return FALSE; + } + + if ((clock_event = tmg_get_clock_events(latch_graph, network)) == + NIL(clock_event_t)) { + (void)fprintf(sisout, "Serious error\n"); + return FALSE; + } + + if (debug_type == VERIFY || debug_type == ALL) { + (void)fprintf(sisout, "Clock events\n"); + for (i = 0; i < NUM_CLOCK(clock_event); i++) { + (void)fprintf(sisout, "Phase %d ^ %.2lf v %.2lf\n", + i, RISE(clock_event)[i], FALL(clock_event)[i]); + } + } + + /* Initialize clock verification algorithm */ + /* --------------------------------------- */ + + foreach_vertex (latch_graph, gen, u) { + if (TYPE(u) == NNODE) { + ARR(u) = 0.0; + arr(u) = 0.0; + DEP(u) = 0.0; + dep(u) = 0.0; + } else { + ARR(u) = -INFTY; + arr(u) = -INFTY; + DEP(u) = -INFTY; + dep(u) = -INFTY; + } + } + + num_e = lsLength(g_get_edges(latch_graph)); + + /* Long path convergence */ + /* --------------------- */ + + for (i = 0; i < num_e; i++) { + converged = TRUE; + foreach_vertex (latch_graph, gen, u) { + if (TYPE(u) == NNODE) { + DEP(u) = 0.0; + dep(u) = 0.0; + } else { + phase = PHASE(u)-1; + switch (LTYPE(u)) { + case FFF: + DEP(u) = cycle; + dep(u) = cycle; + break; + case FFR: + temp = RISE(clock_event)[phase] + + SHIFT(clock_event)[phase]; + DEP(u) = temp; + dep(u) = temp; + break; + case LSH: + temp = RISE(clock_event)[phase] + + SHIFT(clock_event)[phase]; + if (ARR(u) < temp) { + DEP(u) = temp; + } else { + DEP(u) = ARR(u); + } + if (arr(u) < temp) { + dep(u) = temp; + } else { + dep(u) = arr(u); + } + break; + case LSL: + temp = 0.0; + if (ARR(u) < temp) { + DEP(u) = temp; + } else { + DEP(u) = ARR(u); + } + if (arr(u) < temp) { + dep(u) = temp; + } else { + dep(u) = arr(u); + } + break; + default: /* Should never be here */ + break; + } + } + if (debug_type == VERIFY || debug_type == ALL) { + (void)fprintf(sisout, "D(%d) = %.2lf d(%d) = %.2lf\n", ID(u), + DEP(u), ID(u), dep(u)); + } + } + foreach_vertex (latch_graph, gen, u) { + if (TYPE(u) == NNODE) continue; + max_arrival = -INFTY; + min_arrival = INFTY; + phase = PHASE(u)-1; + if (debug_type == VERIFY || debug_type == ALL) { + (void)fprintf(sisout, "A(%d) = MAX(", ID(u)); + } + foreach_in_edge (u, gen1, e) { + w = g_e_source(e); + if (TYPE(w) != NNODE) { + phase1 = PHASE(w)-1; + shift = FALL(clock_event)[phase] - + FALL(clock_event)[phase1] + Ke(e) * cycle; + } else { + shift = 0.0; + } + temp = De(e) + DEP(w) - shift; + if (debug_type == VERIFY || debug_type == ALL) { + (void)fprintf(sisout, "%.2lf\t ", temp); + } + max_arrival = MAX(max_arrival, temp); + temp = de(e) + dep(w) - shift; + min_arrival = MIN(min_arrival, temp); + } + if (debug_type == VERIFY || debug_type == ALL) { + (void)fprintf(sisout, ")\n"); + } + assert(ARR(u) <= max_arrival); /* Sanity check */ + assert(arr(u) <= min_arrival); /* Sanity check */ + if (ARR(u) + EPS < max_arrival) { + flag = TRUE; + converged = FALSE; + ARR(u) = max_arrival; + if (LTYPE(u) == FFF || LTYPE(u) == LSH) { + if (ARR(u) > cycle - tmg_get_set_up(u) + EPS) { + (void)fprintf(sisout, "ERROR: set-up violation at %d\n" + , ID(u)); + flag = FALSE; + } + } else if (LTYPE(u) == FFR || LTYPE(u) == LSL) { + if (ARR(u) > RISE(clock_event)[phase] + + SHIFT(clock_event)[phase] - tmg_get_set_up(u) + EPS) { + (void)fprintf(sisout, "ERROR: set-up violation at %d\n" + ,ID(u)); + flag = FALSE; + } + } + if (!flag) { + (void)fprintf(sisout, "Error: long path problem\n"); + trace_erroneous_path(latch_graph, clock_event, cycle, u); + return FALSE; + } + } + if (arr(u) + EPS < min_arrival) { + arr(u) = min_arrival; + converged = FALSE; + } + if (i == 0) { + if (LTYPE(u) == FFF || LTYPE(u) == LSH) { + if (arr(u) + EPS < tmg_get_hold(u)) { + (void)fprintf(sisout, "ERROR: hold violation at %d\n", + ID(u)); + return FALSE; + } + } else if (LTYPE(u) == FFR || LTYPE(u) == LSL) { + if (arr(u) + EPS < RISE(clock_event)[phase] + + SHIFT(clock_event)[phase] + tmg_get_hold(u)) { + (void)fprintf(sisout, "ERROR: hold violation at %d\n", + ID(u)); + return FALSE; + + } + } + } + } + if (debug_type == VERIFY || debug_type == ALL) { + (void)fprintf(sisout, "A(%d) = %.2lf a(%d) = %.2lf\n", ID(u), + ARR(u), ID(u), arr(u)); + } + if (converged) break; + } + if (!converged) { + (void)fprintf(sisout, "Clock cycle too small (positive cycle)"); + (void)fprintf(sisout, "Convergence failed\n"); + } + tmg_free_clock_event(clock_event); + return converged; +} + + +trace_erroneous_path(latch_graph, clock_event, cycle, u) +graph_t *latch_graph; +clock_event_t *clock_event; +double cycle; +vertex_t *u; +{ + lsGen gen; + vertex_t *v; + double path; + + foreach_vertex (latch_graph, gen, v) { + CV_DIRTY(v) = FALSE; + } + + path = 0.0; + (void)trace_recursive_path(latch_graph, clock_event, cycle, u, ARR(u), + &path); +} + +int +trace_recursive_path(latch_graph, clock_event, cycle, u, A, path) +graph_t *latch_graph; +clock_event_t *clock_event; +double cycle; +vertex_t *u; +double A, *path; +{ + edge_t *edge; + vertex_t *w; + lsGen gen; + int phase, phase1; + double temp, new_A, shift; + + + phase = PHASE(u) -1; + + if (TYPE(u) == NNODE) { + if (ABS(A) < EPS) { + (void)fprintf(sisout, "HOST->\n"); + (void)fprintf(sisout, "Start 0.00\n"); + *path = 0.00; + return TRUE; + } else { + return FALSE; + } + } else { + switch(LTYPE(u)) { + case FFF: + temp = cycle; + break; + case FFR: + temp = RISE(clock_event)[phase] + SHIFT(clock_event)[phase]; + break; + case LSH: + temp = RISE(clock_event)[phase] + SHIFT(clock_event)[phase]; + break; + case LSL: + temp = 0.0; + break; + default: /* Should never be here */ + break; + } + if (ABS(A - temp) < EPS) { + (void)fprintf(sisout, "%d ->\n", ID(u)); + (void)fprintf(sisout, "Start %.2lf\n", temp); + *path = temp; + return TRUE; + } + } + + if (CV_DIRTY(u) == TRUE) { + return FALSE; + } + CV_DIRTY(u) = TRUE; + + foreach_in_edge (u, gen, edge) { + w = g_e_source(edge); + if (TYPE(w) != NNODE) { + phase1 = PHASE(w)-1; + shift = FALL(clock_event)[phase1] - + FALL(clock_event)[phase] - Ke(edge) * cycle; + } else { + shift = 0.0; + } + new_A = A - De(edge) - shift; + if (trace_recursive_path(latch_graph, clock_event, cycle, w, new_A, + path)) { + *path += De(edge) + shift; + (void)fprintf(sisout, " %.2lf \t%d -> %d \t %.2lf\n", De(edge), + Ke(edge), ID(u), (*path)); + return TRUE; + } + } + CV_DIRTY(u) = FALSE; + return FALSE; +} + + + + +/* function definition + name: tmg_get_clock_events() + args: graph, network + job: make sure that the full clocking scheme is specified + and fill up the clock_event data structure + return value: clock_event_t * + calls: - +*/ + +clock_event_t * +tmg_get_clock_events(latch_graph, network) +graph_t *latch_graph; +network_t *network; +{ + clock_event_t *clock_event; + clock_edge_t transition; + sis_clock_t *clock; + double cycle; + int i; + + cycle = clock_get_cycletime(network); + clock_event = ALLOC(clock_event_t, 1); + NUM_CLOCK(clock_event) = array_n(CL(latch_graph)); + RISE(clock_event) = ALLOC(double, NUM_CLOCK(clock_event)); + FALL(clock_event) = ALLOC(double, NUM_CLOCK(clock_event)); + SHIFT(clock_event) = ALLOC(double, NUM_CLOCK(clock_event)); + for (i = 0; i < NUM_CLOCK(clock_event); i++) { + clock = array_fetch(sis_clock_t *, CL(latch_graph), i); + transition.clock = clock; + transition.transition = FALL_TRANSITION; + FALL(clock_event)[i] = clock_get_parameter(transition, + CLOCK_NOMINAL_POSITION); + if (FALL(clock_event)[i] == CLOCK_NOT_SET) { + (void)fprintf(sisout, "Warning clock event not set\n"); + (void)fprintf(sisout, "cannot verify utill specified!\n"); + (void)fprintf(sisout, "aborting\n"); + tmg_free_clock_event(clock_event); + return NIL(clock_event_t); + } + transition.transition = RISE_TRANSITION; + RISE(clock_event)[i] = clock_get_parameter(transition, + CLOCK_NOMINAL_POSITION); + if (RISE(clock_event)[i] == CLOCK_NOT_SET) { + (void)fprintf(sisout, "Warning clock event not set\n"); + (void)fprintf(sisout, "cannot verify utill specified!\n"); + (void)fprintf(sisout, "aborting\n"); + tmg_free_clock_event(clock_event); + return NIL(clock_event_t); + } + SHIFT(clock_event)[i] = cycle - FALL(clock_event)[i]; + if (SHIFT(clock_event)[i] < 0) { + (void)fprintf(siserr, "Error: clock event outside of cycle time\n"); + return NIL(clock_event_t); + } + } + return clock_event; +} + + + +tmg_free_clock_event(clock_event) +clock_event_t *clock_event; +{ + FREE(RISE(clock_event)); + FREE(FALL(clock_event)); + FREE(SHIFT(clock_event)); + FREE(clock_event); +} +#endif /* SIS */ diff --git a/sis/util/Makefile.am b/sis/util/Makefile.am new file mode 100644 index 0000000..550e4c0 --- /dev/null +++ b/sis/util/Makefile.am @@ -0,0 +1,17 @@ +docdir = @SIS_DOCDIR@ + +libutil_a_SOURCES_local = cpu_stats.c cpu_time.c getopt.c pathsearch.c \ + pipefork.c prtime.c restart.c safe_mem.c saveimage.c state.c \ + strsav.c stub.c texpand.c tmpfile.c + +noinst_LIBRARIES = libutil.a +libutil_a_SOURCES = $(libutil_a_SOURCES_local) +dist_doc_DATA = util.doc + +if SIS_COND_CUDD +pkginclude_HEADERS = ansi.h +else +pkginclude_HEADERS = ansi.h util.h +endif + +EXTRA_DIST = test-restart.c util.h diff --git a/sis/util/Makefile.in b/sis/util/Makefile.in new file mode 100644 index 0000000..4ca354b --- /dev/null +++ b/sis/util/Makefile.in @@ -0,0 +1,429 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libutil_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/util +DIST_COMMON = $(am__pkginclude_HEADERS_DIST) $(dist_doc_DATA) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libutil_a_AR = $(AR) $(ARFLAGS) +libutil_a_LIBADD = +am__objects_1 = cpu_stats.$(OBJEXT) cpu_time.$(OBJEXT) \ + getopt.$(OBJEXT) pathsearch.$(OBJEXT) pipefork.$(OBJEXT) \ + prtime.$(OBJEXT) restart.$(OBJEXT) safe_mem.$(OBJEXT) \ + saveimage.$(OBJEXT) state.$(OBJEXT) strsav.$(OBJEXT) \ + stub.$(OBJEXT) texpand.$(OBJEXT) tmpfile.$(OBJEXT) +am_libutil_a_OBJECTS = $(am__objects_1) +libutil_a_OBJECTS = $(am_libutil_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libutil_a_SOURCES) +DIST_SOURCES = $(libutil_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +am__pkginclude_HEADERS_DIST = ansi.h util.h +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +libutil_a_SOURCES_local = cpu_stats.c cpu_time.c getopt.c pathsearch.c \ + pipefork.c prtime.c restart.c safe_mem.c saveimage.c state.c \ + strsav.c stub.c texpand.c tmpfile.c + +noinst_LIBRARIES = libutil.a +libutil_a_SOURCES = $(libutil_a_SOURCES_local) +dist_doc_DATA = util.doc +@SIS_COND_CUDD_FALSE@pkginclude_HEADERS = ansi.h util.h +@SIS_COND_CUDD_TRUE@pkginclude_HEADERS = ansi.h +EXTRA_DIST = test-restart.c util.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/util/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/util/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libutil.a: $(libutil_a_OBJECTS) $(libutil_a_DEPENDENCIES) + -rm -f libutil.a + $(libutil_a_AR) libutil.a $(libutil_a_OBJECTS) $(libutil_a_LIBADD) + $(RANLIB) libutil.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/util/ansi.h b/sis/util/ansi.h new file mode 100644 index 0000000..d4f85cd --- /dev/null +++ b/sis/util/ansi.h @@ -0,0 +1,53 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/ansi.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +#ifndef ANSI_H +#define ANSI_H + +/* + * ANSI Compiler Support + * + * David Harrison + * University of California, Berkeley + * 1988 + * + * ANSI compatible compilers are supposed to define the preprocessor + * directive __STDC__. Based on this directive, this file defines + * certain ANSI specific macros. + * + * ARGS: + * Used in function prototypes. Example: + * extern int foo + * ARGS((char *, double)); + */ + +/* Function prototypes */ +#if defined(__STDC__) || defined(__cplusplus) +#define ARGS(args) args +#else +#define ARGS(args) () +#endif + +#if defined(__cplusplus) +#define NULLARGS (void) +#else +#define NULLARGS () +#endif + +#ifdef __cplusplus +#define EXTERN extern "C" +#else +#define EXTERN extern +#endif + +#if defined(__cplusplus) || defined(__STDC__) +#define HAS_STDARG +#endif + +#endif diff --git a/sis/util/cpu_stats.c b/sis/util/cpu_stats.c new file mode 100644 index 0000000..95c1ec2 --- /dev/null +++ b/sis/util/cpu_stats.c @@ -0,0 +1,95 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/cpu_stats.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/02/09 01:02:00 $ + * + */ +/* LINTLIBRARY */ + +#include <stdio.h> +#include "util.h" + + +#if defined(BSD_SIS) && !defined(_IBMR2) && !defined(__hpux) && 0 +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> + +extern int end, etext, edata; + +#endif + +void +util_print_cpu_stats(fp) +FILE *fp; +{ +#if defined(BSD_SIS) && !defined(_IBMR2) && !defined(__hpux) && 0 + struct rusage rusage; + struct rlimit rlp; + int text, data, vm_limit, vm_soft_limit; + double user, system, scale; + char hostname[257]; + caddr_t sbrk(); + int vm_text, vm_init_data, vm_uninit_data, vm_sbrk_data; + + /* Get the hostname */ + (void) gethostname(hostname, 256); + hostname[256] = '\0'; /* just in case */ + + /* Get the virtual memory sizes */ + vm_text = ((int) (&etext)) / 1024.0 + 0.5; + vm_init_data = ((int) (&edata) - (int) (&etext)) / 1024.0 + 0.5; + vm_uninit_data = ((int) (&end) - (int) (&edata)) / 1024.0 + 0.5; + vm_sbrk_data = ((int) sbrk(0) - (int) (&end)) / 1024.0 + 0.5; + + /* Get virtual memory limits */ + (void) getrlimit(RLIMIT_DATA, &rlp); + vm_limit = rlp.rlim_max / 1024.0 + 0.5; + vm_soft_limit = rlp.rlim_cur / 1024.0 + 0.5; + + /* Get usage stats */ + (void) getrusage(RUSAGE_SELF, &rusage); + user = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec/1.0e6; + system = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec/1.0e6; + scale = (user + system)*100.0; + if (scale == 0.0) scale = 0.001; + + (void) fprintf(fp, "Runtime Statistics\n"); + (void) fprintf(fp, "------------------\n"); + (void) fprintf(fp, "Machine name: %s\n", hostname); + (void) fprintf(fp, "User time %6.1f seconds\n", user); + (void) fprintf(fp, "System time %6.1f seconds\n\n", system); + + text = rusage.ru_ixrss / scale + 0.5; + data = (rusage.ru_idrss + rusage.ru_isrss) / scale + 0.5; + (void) fprintf(fp, "Average resident text size = %5dK\n", text); + (void) fprintf(fp, "Average resident data+stack size = %5dK\n", data); + (void) fprintf(fp, "Maximum resident size = %5dK\n\n", + rusage.ru_maxrss/2); + (void) fprintf(fp, "Virtual text size = %5dK\n", + vm_text); + (void) fprintf(fp, "Virtual data size = %5dK\n", + vm_init_data + vm_uninit_data + vm_sbrk_data); + (void) fprintf(fp, " data size initialized = %5dK\n", + vm_init_data); + (void) fprintf(fp, " data size uninitialized = %5dK\n", + vm_uninit_data); + (void) fprintf(fp, " data size sbrk = %5dK\n", + vm_sbrk_data); + (void) fprintf(fp, "Virtual memory limit = %5dK (%dK)\n\n", + vm_soft_limit, vm_limit); + + (void) fprintf(fp, "Major page faults = %d\n", rusage.ru_majflt); + (void) fprintf(fp, "Minor page faults = %d\n", rusage.ru_minflt); + (void) fprintf(fp, "Swaps = %d\n", rusage.ru_nswap); + (void) fprintf(fp, "Input blocks = %d\n", rusage.ru_inblock); + (void) fprintf(fp, "Output blocks = %d\n", rusage.ru_oublock); + (void) fprintf(fp, "Context switch (voluntary) = %d\n", rusage.ru_nvcsw); + (void) fprintf(fp, "Context switch (involuntary) = %d\n", rusage.ru_nivcsw); +#else + (void) fprintf(fp, "Usage statistics not available\n"); +#endif +} diff --git a/sis/util/cpu_time.c b/sis/util/cpu_time.c new file mode 100644 index 0000000..add7ccb --- /dev/null +++ b/sis/util/cpu_time.c @@ -0,0 +1,122 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/cpu_time.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +/* LINTLIBRARY */ + +#include <stdio.h> +#include "util.h" + +#ifdef IBM_WATC /* IBM Waterloo-C compiler (same as bsd 4.2) */ +#define void int +#define BSD_SIS +#endif + +#ifdef __hpux /* HPUX/C compiler -- times() w/system-dependent clk */ +#undef BSD_SIS + +/* The following code for HPUX is based on a man page that claims POSIX */ +/* compliance. Accordingly, it should work on any POSIX-compliant */ +/* system. It should definitely work for HPUX 8.07 and beyond. I can't */ +/* vouch for pre-8.07 systems, but I recall that earlier versions of */ +/* HPUX (like 6.5) had a different way of accessing the clock rate for */ +/* times(). - DEW */ + +#include <sys/times.h> +#include <unistd.h> +#endif + +#ifdef vms /* VAX/C compiler -- times() with 100 HZ clock */ +#define UNIX100 +#endif + +#ifdef BSD_SIS +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#endif + +#ifdef UNIX50 +#include <sys/types.h> +#include <sys/times.h> +#endif + +#ifdef UNIX60 +#include <sys/types.h> +#include <sys/times.h> +#endif + +#ifdef UNIX100 +#include <sys/types.h> +#include <sys/times.h> +#endif + + + +/* + * util_cpu_time -- return a long which represents the elapsed processor + * time in milliseconds since some constant reference + */ +long +util_cpu_time() +{ + long t = 0; + +#ifdef BSD_SIS + struct rusage rusage; + (void) getrusage(RUSAGE_SELF, &rusage); + t = (long) rusage.ru_utime.tv_sec*1000 + rusage.ru_utime.tv_usec/1000; +#endif + +#ifdef IBMPC + long ltime; + (void) time(<ime); + t = ltime * 1000; +#endif + +#ifdef UNIX50 /* times() with 50 Hz resolution */ + struct tms buffer; + times(&buffer); + t = buffer.tms_utime * 20; +#endif + +#ifdef UNIX60 /* times() with 60 Hz resolution */ + struct tms buffer; + times(&buffer); + t = buffer.tms_utime * 16.6667; +#endif + +#ifdef UNIX100 + struct tms buffer; /* times() with 100 Hz resolution */ + times(&buffer); + t = buffer.tms_utime * 10; +#endif + +#ifdef __hpux /* times() with processor-dependent resolution (POSIX) */ + struct tms buffer; + long nticks; /* number of clock ticks per second */ + + nticks = sysconf(_SC_CLK_TCK); + times(&buffer); + t = buffer.tms_utime * (1000.0/nticks); + +#endif + +#ifdef vms /* VAX/C compiler - times() with 100 HZ clock */ + struct {int p1, p2, p3, p4;} buffer; + static long ref_time; + times(&buffer); + t = buffer.p1 * 10; + if (ref_time == 0) + ref_time = t; + t = t - ref_time; +#endif + + + return t; +} diff --git a/sis/util/getopt.c b/sis/util/getopt.c new file mode 100644 index 0000000..33692c9 --- /dev/null +++ b/sis/util/getopt.c @@ -0,0 +1,84 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/getopt.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +/* LINTLIBRARY */ + +#include <stdio.h> +#include "util.h" + + +/* File : getopt.c + * Author : Henry Spencer, University of Toronto + * Updated: 28 April 1984 + * + * Changes: (R Rudell) + * changed index() to strchr(); + * added getopt_reset() to reset the getopt argument parsing + * + * Purpose: get option letter from argv. + */ + +char *util_optarg; /* Global argument pointer. */ +int util_optind = 0; /* Global argv index. */ +static char *scan; + + +void +util_getopt_reset() +{ + util_optarg = 0; + util_optind = 0; + scan = 0; +} + + + +int +util_getopt(argc, argv, optstring) +int argc; +char *argv[]; +char *optstring; +{ + register int c; + register char *place; + + util_optarg = NIL(char); + + if (scan == NIL(char) || *scan == '\0') { + if (util_optind == 0) util_optind++; + if (util_optind >= argc) return EOF; + place = argv[util_optind]; + if (place[0] != '-' || place[1] == '\0') return EOF; + util_optind++; + if (place[1] == '-' && place[2] == '\0') return EOF; + scan = place+1; + } + + c = *scan++; + place = strchr(optstring, c); + if (place == NIL(char) || c == ':') { + (void) fprintf(stderr, "%s: unknown option %c\n", argv[0], c); + return '?'; + } + if (*++place == ':') { + if (*scan != '\0') { + util_optarg = scan; + scan = NIL(char); + } else { + if (util_optind >= argc) { + (void) fprintf(stderr, "%s: %c requires an argument\n", + argv[0], c); + return '?'; + } + util_optarg = argv[util_optind]; + util_optind++; + } + } + return c; +} diff --git a/sis/util/pathsearch.c b/sis/util/pathsearch.c new file mode 100644 index 0000000..77e5459 --- /dev/null +++ b/sis/util/pathsearch.c @@ -0,0 +1,115 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/pathsearch.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +/* LINTLIBRARY */ + +#include <stdio.h> +#ifdef UNIX +#include <sys/file.h> +#include <sys/stat.h> +#endif +#include "util.h" + + +static int +check_file(filename, mode) +char *filename; +char *mode; +{ +#ifdef UNIX + struct stat stat_rec; + int access_char = mode[0]; + int access_mode = R_OK; + + /* First check that the file is a regular file. */ + + if (stat(filename,&stat_rec) == 0 + && (stat_rec.st_mode&S_IFMT) == S_IFREG) { + if (access_char == 'w') { + access_mode = W_OK; + } else if (access_char == 'x') { + access_mode = X_OK; + } + return access(filename,access_mode) == 0; + } + return 0; +#else + FILE *fp; + int got_file; + + if (strcmp(mode, "x") == 0) { + mode = "r"; + } + fp = fopen(filename, mode); + got_file = (fp != 0); + if (fp != 0) { + (void) fclose(fp); + } + return got_file; +#endif +} + + +char * +util_path_search(prog) +char *prog; +{ +#ifdef UNIX + return util_file_search(prog, getenv("PATH"), "x"); +#else + return util_file_search(prog, NIL(char), "x"); +#endif +} + + +char * +util_file_search(file, path, mode) +char *file; /* file we're looking for */ +char *path; /* search path, colon separated */ +char *mode; /* "r", "w", or "x" */ +{ + int quit; + char *buffer, *filename, *save_path, *cp; + + if (path == 0 || strcmp(path, "") == 0) { + path = "."; /* just look in the current directory */ + } + + save_path = path = util_strsav(path); + quit = 0; + do { + cp = strchr(path, ':'); + if (cp != 0) { + *cp = '\0'; + } else { + quit = 1; + } + + /* cons up the filename out of the path and file name */ + if (strcmp(path, ".") == 0) { + buffer = util_strsav(file); + } else { + buffer = ALLOC(char, strlen(path) + strlen(file) + 4); + (void) sprintf(buffer, "%s/%s", path, file); + } + filename = util_tilde_expand(buffer); + FREE(buffer); + + /* see if we can access it */ + if (check_file(filename, mode)) { + FREE(save_path); + return filename; + } + FREE(filename); + path = ++cp; + } while (! quit); + + FREE(save_path); + return 0; +} diff --git a/sis/util/pipefork.c b/sis/util/pipefork.c new file mode 100644 index 0000000..e21f74b --- /dev/null +++ b/sis/util/pipefork.c @@ -0,0 +1,94 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/pipefork.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +/* LINTLIBRARY */ + +#include <stdio.h> +#include <sys/wait.h> +#include "util.h" + + +/* + * util_pipefork - fork a command and set up pipes to and from + * + * Rick L Spickelmier, 3/23/86 + * Richard Rudell, 4/6/86 + * Rick L Spickelmier, 4/30/90, got rid of slimey vfork semantics + * + * Returns: + * 1 for success, with toCommand and fromCommand pointing to the streams + * 0 for failure + */ + +/* ARGSUSED */ +int +util_pipefork(argv, toCommand, fromCommand, pid) +char **argv; /* normal argv argument list */ +FILE **toCommand; /* pointer to the sending stream */ +FILE **fromCommand; /* pointer to the reading stream */ +int *pid; +{ +#ifdef UNIX + int forkpid, waitpid; + int topipe[2], frompipe[2]; + char buffer[1024]; +#if (defined hpux) || (defined __osf__) || (defined _IBMR2) + int status; +#else + union wait status; +#endif + + /* create the PIPES... + * fildes[0] for reading from command + * fildes[1] for writing to command + */ + (void) pipe(topipe); + (void) pipe(frompipe); + + if ((forkpid = vfork()) == 0) { + /* child here, connect the pipes */ + (void) dup2(topipe[0], fileno(stdin)); + (void) dup2(frompipe[1], fileno(stdout)); + + (void) close(topipe[0]); + (void) close(topipe[1]); + (void) close(frompipe[0]); + (void) close(frompipe[1]); + + (void) execvp(argv[0], argv); + (void) sprintf(buffer, "util_pipefork: can not exec %s", argv[0]); + perror(buffer); + (void) _exit(1); + } + + if (pid) { + *pid = forkpid; + } + + waitpid = wait3(&status, WNOHANG, 0); + + /* parent here, use slimey vfork() semantics to get return status */ + if (waitpid == forkpid && WIFEXITED(status)) { + return 0; + } + if ((*toCommand = fdopen(topipe[1], "w")) == NULL) { + return 0; + } + if ((*fromCommand = fdopen(frompipe[0], "r")) == NULL) { + return 0; + } + (void) close(topipe[0]); + (void) close(frompipe[1]); + return 1; +#else + (void) fprintf(stderr, + "util_pipefork: not implemented on your operating system\n"); + return 0; +#endif +} diff --git a/sis/util/prtime.c b/sis/util/prtime.c new file mode 100644 index 0000000..eaa3b47 --- /dev/null +++ b/sis/util/prtime.c @@ -0,0 +1,31 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/prtime.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +/* LINTLIBRARY */ + +#include <stdio.h> +#include "util.h" + + +/* + * util_print_time -- massage a long which represents a time interval in + * milliseconds, into a string suitable for output + * + * Hack for IBM/PC -- avoids using floating point + */ + +char * +util_print_time(t) +long t; +{ + static char s[40]; + + (void) sprintf(s, "%ld.%02ld sec", t/1000, (t%1000)/10); + return s; +} diff --git a/sis/util/restart.c b/sis/util/restart.c new file mode 100644 index 0000000..497ff46 --- /dev/null +++ b/sis/util/restart.c @@ -0,0 +1,156 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/restart.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +#ifdef notdef +#include <stdio.h> +#include "util.h" + +#if (defined(sun) && ! defined(sparc)) || defined(vax) + +#include <signal.h> +#include <sys/types.h> +#include <sys/time.h> + +static char *save_stack_base; +static char *stack_lo_addr; +static char *stack_hi_addr; +static int stack_size; + +static int restart_global_flag; +static char *old_file_name; +static char *new_file_name; + +char *util_save_sp; /* set by util_restart_save_state() */ +extern char *sbrk(); + +static void +grow_stack() +{ + int i, space[256]; + + for(i = 0; i < 256; i++) { + space[i] = 0; + } + if ((char *) &i > stack_lo_addr) { + grow_stack(); + } +} + + +/* ARGSUSED */ +static int +handle_sigquit(sig, code, scp) +int sig; +int code; +struct sigcontext *scp; +{ + if (util_restart_save_state()) { + /* we are restarting ! -- return from signal */ + + } else { + /* copy stack to user data space */ + stack_lo_addr = util_save_sp; + stack_size = stack_hi_addr - stack_lo_addr + 1; + save_stack_base = sbrk(stack_size); + (void) memcpy(save_stack_base, stack_lo_addr, stack_size); + + /* write a new executable */ + (void) fprintf(stderr, "Writing executable %s ...\n", new_file_name); + (void) util_save_image(old_file_name, new_file_name); + + /* terminate if signal was a QUIT */ + if (sig == SIGQUIT) { + (void) _exit(1); + } + } +} + + +static void +restart_program() +{ + (void) fprintf(stderr, "Continuing execution ...\n"); + + /* create the stack */ + grow_stack(); + +#ifdef vax + asm("movl _util_save_sp,sp"); +#endif +#ifdef sun + asm("movl _util_save_sp,sp"); +#endif + + /* copy the stack back from user space */ + (void) memcpy(stack_lo_addr, save_stack_base, stack_size); + + /* remove the sbrk for the stack */ + if (sbrk(-stack_size) < 0) { + perror("sbrk"); + } + + util_restart_restore_state(); /* jump back into handle_sigquit() */ +} + +void +util_restart(old, new, interval) +char *old, *new; +int interval; +{ + struct itimerval itimer; + +#ifdef vax +#ifdef ultrix + stack_hi_addr = (char *) 0x7fffe3ff; /* ultrix */ +#else + stack_hi_addr = (char *) 0x7fffebff; /* bsd 4.3 */ +#endif +#endif +#ifdef sun + stack_hi_addr = (char *) 0x0effffff; /* Sun OS 3.2, 3.4 */ +#endif + + old_file_name = old; + new_file_name = new; + + (void) signal(SIGQUIT, handle_sigquit); + + if (interval > 0) { + (void) signal(SIGVTALRM, handle_sigquit); + itimer.it_interval.tv_sec = interval; + itimer.it_interval.tv_usec = 0; + itimer.it_value.tv_sec = interval; + itimer.it_value.tv_usec = 0; + if (setitimer(ITIMER_VIRTUAL, &itimer, (struct itimerval *) 0) < 0) { + perror("setitimer"); + exit(1); + } + } + + if (restart_global_flag) { + restart_program(); + } + restart_global_flag = 1; +} + +#else + +/* ARGSUSED */ +void +util_restart(old, new, interval) +char *old; +char *new; +int interval; +{ + (void) fprintf(stderr, + "util_restart: not supported on your operating system/hardware\n"); +} + +#endif +#endif diff --git a/sis/util/safe_mem.c b/sis/util/safe_mem.c new file mode 100644 index 0000000..73ee862 --- /dev/null +++ b/sis/util/safe_mem.c @@ -0,0 +1,104 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/safe_mem.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +/* LINTLIBRARY */ + +#include <stdio.h> +#include "util.h" + + +/* + * These are interface routines to be placed between a program and the + * system memory allocator. + * + * It forces well-defined semantics for several 'borderline' cases: + * + * malloc() of a 0 size object is guaranteed to return something + * which is not 0, and can safely be freed (but not dereferenced) + * free() accepts (silently) an 0 pointer + * realloc of a 0 pointer is allowed, and is equiv. to malloc() + * For the IBM/PC it forces no object > 64K; note that the size argument + * to malloc/realloc is a 'long' to catch this condition + * + * The function pointer MMoutOfMemory() contains a vector to handle a + * 'out-of-memory' error (which, by default, points at a simple wrap-up + * and exit routine). + */ + +extern char *MMalloc(); +extern void MMout_of_memory(); +extern char *MMrealloc(); + + +void (*MMoutOfMemory)() = MMout_of_memory; + + +/* MMout_of_memory -- out of memory for lazy people, flush and exit */ +void +MMout_of_memory(size) +long size; +{ + (void) fflush(stdout); + (void) fprintf(stderr, "\nout of memory allocating %ld bytes\n", size); + exit(1); +} + + +char * +MMalloc(size) +long size; +{ + char *p; + +#ifdef IBMPC + if (size > 65000L) { + if (MMoutOfMemory != (void (*)()) 0 ) (*MMoutOfMemory)(size); + return NIL(char); + } +#endif + if (size <= 0) size = sizeof(long); + if ((p = (char *) malloc((unsigned) size)) == NIL(char)) { + if (MMoutOfMemory != (void (*)()) 0 ) (*MMoutOfMemory)(size); + return NIL(char); + } + return p; +} + + +char * +MMrealloc(obj, size) +char *obj; +long size; +{ + char *p; + +#ifdef IBMPC + if (size > 65000L) { + if (MMoutOfMemory != (void (*)()) 0 ) (*MMoutOfMemory)(size); + return NIL(char); + } +#endif + if (obj == NIL(char)) return MMalloc(size); + if (size <= 0) size = sizeof(long); + if ((p = (char *) realloc(obj, (unsigned) size)) == NIL(char)) { + if (MMoutOfMemory != (void (*)()) 0 ) (*MMoutOfMemory)(size); + return NIL(char); + } + return p; +} + + +void +MMfree(obj) +char *obj; +{ + if (obj != 0) { + free(obj); + } +} diff --git a/sis/util/saveimage.c b/sis/util/saveimage.c new file mode 100644 index 0000000..4295e3b --- /dev/null +++ b/sis/util/saveimage.c @@ -0,0 +1,240 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/saveimage.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +/* LINTLIBRARY */ +/* + * saveimage.c -- + * + * Function to save an executable copy of the current process's + * image in a file. + * + */ + +#include <stdio.h> +#include "util.h" + +#ifdef notdef /* BSD_SIS */ +#include <sys/types.h> +#include <sys/stat.h> +#include <a.out.h> +#include <errno.h> + +extern int errno; + +#define BUFSIZE 8192 + +extern long lseek(); /* For lint */ +extern int getpagesize(); +extern char *sbrk(); + +static int copy_file(); +static int pad_file(); + + +int +util_save_image(orig_file_name, save_file_name) +char *orig_file_name; +char *save_file_name; +{ + int origFd = -1, saveFd = -1; + char *start_data, *end_data, *start_text, *end_round; + struct exec old_hdr, new_hdr; + struct stat old_stat; + int n, page_size, length_text, length_data; + + if ((origFd = open(orig_file_name, 0)) < 0) { + perror(orig_file_name); + (void) fprintf(stderr, "Cannot open original a.out file\n"); + goto bad; + } + + if (fstat(origFd, &old_stat) < 0) { + perror(orig_file_name); + (void) fprintf(stderr, "Cannot stat original a.out file\n"); + goto bad; + } + + /* + * Read the a.out header from the original file. + */ + if (read(origFd, (char *) &old_hdr, sizeof(old_hdr)) != sizeof(old_hdr)) { + perror(orig_file_name); + (void) fprintf(stderr, "Cannot read original a.out header\n"); + goto bad; + } + if (N_BADMAG(old_hdr)) { + (void) fprintf(stderr, "File %s has a bad magic number (%o)\n", + orig_file_name, old_hdr.a_magic); + goto bad; + } + if (old_hdr.a_magic != ZMAGIC) { + (void) fprintf(stderr, "File %s is not demand-paged\n", orig_file_name); + goto bad; + } + + /* + * Open the output file. + */ + if (access(save_file_name, /* F_OK */ 0) == 0) { + (void) unlink(save_file_name); + } + if ((saveFd = creat(save_file_name, 0777)) < 0) { + if (errno == ETXTBSY) { + (void) unlink(save_file_name); + saveFd = creat(save_file_name, 0777); + } + if (saveFd < 0) { + perror(save_file_name); + (void) fprintf(stderr, "Cannot create save file.\n"); + goto bad; + } + } + + /* + * Find out how far the data segment extends. + */ + new_hdr = old_hdr; + end_data = sbrk(0); + page_size = getpagesize(); + n = ((((int) end_data) + page_size - 1) / page_size) * page_size; + end_round = (char *) n; + if (end_round > end_data) { + end_data = sbrk(end_round - end_data); + } + +#ifdef vax + start_text = 0; + length_text = new_hdr.a_text; + start_data = (char *) old_hdr.a_text; + length_data = end_data - start_data; +#endif vax +#ifdef sun + start_text = (char *) N_TXTADDR(old_hdr) + sizeof(old_hdr); + length_text = old_hdr.a_text - sizeof(old_hdr); + start_data = (char *) N_DATADDR(old_hdr); + length_data = end_data - start_data; +#endif sun + new_hdr.a_data = end_data - start_data; + new_hdr.a_bss = 0; + + /* + * First, the header plus enough pad to extend up to N_TXTOFF. + */ + if (write(saveFd, (char *) &new_hdr, (int) sizeof(new_hdr)) != + sizeof(new_hdr)) { + perror("write"); + (void) fprintf(stderr, "Error while copying header.\n"); + goto bad; + } + if (! pad_file(saveFd, N_TXTOFF(old_hdr) - sizeof(new_hdr))) { + (void) fprintf(stderr, "Error while padding.\n"); + goto bad; + } + + + /* + * Copy our text segment + */ + if (write(saveFd, start_text, length_text) != length_text) { + perror("write"); + (void) fprintf(stderr, "Error while copying text segment.\n"); + goto bad; + } + + + /* + * Copy our data segment + */ + if (write(saveFd, start_data, length_data) != length_data) { + perror("write"); + (void) fprintf(stderr, "Error while copying data segment.\n"); + goto bad; + } + + /* + * Copy the symbol table and everything else. + * This takes us to the end of the original file. + */ + (void) lseek(origFd, (long) N_SYMOFF(old_hdr), 0); + if (! copy_file(origFd, saveFd, old_stat.st_size - N_SYMOFF(old_hdr))) { + (void) fprintf(stderr, "Error while copying symbol table.\n"); + goto bad; + } + (void) close(origFd); + (void) close(saveFd); + return 1; + +bad: + if (origFd >= 0) (void) close(origFd); + if (saveFd >= 0) (void) close(saveFd); + return 0; +} + + +static int +copy_file(inFd, outFd, nbytes) +int inFd, outFd; +unsigned long nbytes; +{ + char buf[BUFSIZE]; + int nread, ntoread; + + while (nbytes > 0) { + ntoread = nbytes; + if (ntoread > sizeof buf) ntoread = sizeof buf; + if ((nread = read(inFd, buf, ntoread)) != ntoread) { + perror("read"); + return (0); + } + if (write(outFd, buf, nread) != nread) { + perror("write"); + return (0); + } + nbytes -= nread; + } + + return (1); +} + + +static int +pad_file(outFd, nbytes) +int outFd; +int nbytes; +{ + char buf[BUFSIZE]; + int nzero; + + nzero = (nbytes > sizeof(buf)) ? sizeof(buf) : nbytes; + bzero(buf, nzero); + while (nbytes > 0) { + nzero = (nbytes > sizeof(buf)) ? sizeof(buf) : nbytes; + if (write(outFd, buf, nzero) != nzero) { + perror("write"); + return (0); + } + nbytes -= nzero; + } + + return (1); +} +#else + +/* ARGSUSED */ +int +util_save_image(orig_file_name, save_file_name) +char *orig_file_name; +char *save_file_name; +{ + (void) fprintf(stderr, + "util_save_image: not implemented on your operating system\n"); + return 0; +} + +#endif diff --git a/sis/util/state.c b/sis/util/state.c new file mode 100644 index 0000000..61dff5e --- /dev/null +++ b/sis/util/state.c @@ -0,0 +1,92 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/state.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +#ifdef notdef +#ifdef lint +util_restart_save_state() +{ + return 0; +} + + +util_restart_restore_state() +{ +} + +#else + + +#ifdef vax +int util_restart_state[32]; + +util_restart_save_state() +{ + asm("movl sp,_util_save_sp"); + asm("movl r1,_util_restart_state"); + asm("movl r2,_util_restart_state+4"); + asm("movl r3,_util_restart_state+8"); + asm("movl r4,_util_restart_state+12"); + asm("movl r5,_util_restart_state+16"); + asm("movl r6,_util_restart_state+20"); + asm("movl r7,_util_restart_state+24"); + asm("movl r8,_util_restart_state+28"); + asm("movl r9,_util_restart_state+32"); + asm("movl r10,_util_restart_state+36"); + asm("movl r11,_util_restart_state+40"); + asm("movl 8(fp),_util_restart_state+44"); + asm("movl 12(fp),_util_restart_state+48"); + asm("movl 16(fp),_util_restart_state+52"); + asm("movl $0,r0"); +} + +util_restart_restore_state() +{ + asm("movl _util_restart_state,r1"); + asm("movl _util_restart_state+4,r2"); + asm("movl _util_restart_state+8,r3"); + asm("movl _util_restart_state+12,r4"); + asm("movl _util_restart_state+16,r5"); + asm("movl _util_restart_state+20,r6"); + asm("movl _util_restart_state+24,r7"); + asm("movl _util_restart_state+28,r8"); + asm("movl _util_restart_state+32,r9"); + asm("movl _util_restart_state+36,r10"); + asm("movl _util_restart_state+40,r11"); + asm("movl _util_restart_state+44,ap"); + asm("movl _util_restart_state+48,fp"); + asm("addl3 fp,$4,sp"); + asm("movl _util_restart_state+52,r0"); + asm("jmp (r0)"); +} +#endif + + +#if defined(sun) && ! defined(sparc) +int util_restart_state[32]; + +util_restart_save_state() +{ + asm("movel sp,_util_save_sp"); + asm("movel sp@,_util_restart_state"); + asm("movel sp@(0x4),_util_restart_state+4"); + asm("moveml #0xFFFF,_util_restart_state+8"); + return 0; +} + +util_restart_restore_state() +{ + asm("moveml _util_restart_state+8,#0xFFFF"); + asm("movel _util_restart_state+4,sp@(0x4)"); + asm("movel _util_restart_state,sp@"); + return 1; +} +#endif + +#endif +#endif diff --git a/sis/util/strsav.c b/sis/util/strsav.c new file mode 100644 index 0000000..539ccbf --- /dev/null +++ b/sis/util/strsav.c @@ -0,0 +1,24 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/strsav.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +/* LINTLIBRARY */ + +#include <stdio.h> +#include "util.h" + + +/* + * util_strsav -- save a copy of a string + */ +char * +util_strsav(s) +char *s; +{ + return strcpy(ALLOC(char, strlen(s)+1), s); +} diff --git a/sis/util/stub.c b/sis/util/stub.c new file mode 100644 index 0000000..58b5499 --- /dev/null +++ b/sis/util/stub.c @@ -0,0 +1,98 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/stub.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/13 08:31:21 $ + * + */ +/* LINTLIBRARY */ + +#include "config.h" + +#if !HAVE_MEMCPY +char * +memcpy(s1, s2, n) +char *s1, *s2; +int n; +{ + extern bcopy(); + bcopy(s2, s1, n); + return s1; +} +#endif + +#if !HAVE_MEMSET +char * +memset(s, c, n) +char *s; +int c; +int n; +{ + extern bzero(); + register int i; + + if (c == 0) { + bzero(s, n); + } else { + for(i = n-1; i >= 0; i--) { + *s++ = c; + } + } + return s; +} +#endif + +#if !HAVE_STRCHR +char * +strchr(s, c) +char *s; +int c; +{ + extern char *index(); + return index(s, c); +} +#endif + +#if !HAVE_STRRCHR +char * +strrchr(s, c) +char *s; +int c; +{ + extern char *rindex(); + return rindex(s, c); +} +#endif + +#include <stdio.h> + +#if !HAVE_POPEN +/*ARGSUSED*/ +FILE * +popen(string, mode) +char *string; +char *mode; +{ + (void) fprintf(stderr, "popen not supported on your operating system\n"); + return NULL; +} +#endif + +#if !HAVE_PCLOSE +/*ARGSUSED*/ +int +pclose(fp) +FILE *fp; +{ + (void) fprintf(stderr, "pclose not supported on your operating system\n"); + return -1; +} +#endif + +/* put something here in case some compilers abort on empty files ... */ +util_do_nothing() +{ + return 1; +} diff --git a/sis/util/test-restart.c b/sis/util/test-restart.c new file mode 100644 index 0000000..9d542b5 --- /dev/null +++ b/sis/util/test-restart.c @@ -0,0 +1,68 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/test-restart.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +#ifdef notdef +#include <stdio.h> +#include "util.h" + + +main(argc, argv, environ) +int argc; +char **argv; +char **environ; +{ + int i; + char **ep, *prog; + + prog = util_path_search(argv[0]); + if (prog == NIL(char)) { + (void) fprintf(stderr, "Cannot find current executable\n"); + exit(1); + } + util_restart(prog, "a.out", 0); + + i = recur(10); + (void) fprintf(stderr, "terminated normally with i = %d\n", i); + + (void) printf("argc is %d\n", argc); + + for(i = 0, ep = argv; *ep != 0; i++, ep++) { + (void) printf("%08x (%08x-%08x)\targv[%d]:\t%s\n", + ep, *ep, *ep + strlen(*ep), i, *ep); + } + + i = 0; + for(i = 0, ep = environ; *ep != 0; ep++, i++) { + (void) printf("%08x (%08x-%08x)\tenviron[%d]:\t%s\n", + ep, *ep, *ep + strlen(*ep), i, *ep); + } + + (void) fprintf(stderr, "returning with status=4\n"); + return 4; +} + + +recur(cnt) +{ + int i, j, sum; + + if (cnt > 0) { + return recur(cnt-1); + } else { + sum = 0; + for(j = 0; j < 20; j++) { + for(i = 0; i < 100000; i++) { + sum += 1; + } + (void) printf("done loop %d\n", j); + } + return sum; + } +} +#endif diff --git a/sis/util/texpand.c b/sis/util/texpand.c new file mode 100644 index 0000000..57cc148 --- /dev/null +++ b/sis/util/texpand.c @@ -0,0 +1,68 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/texpand.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +/* LINTLIBRARY */ + +#include <stdio.h> +#include "util.h" + +#ifdef BSD_SIS +#include <pwd.h> +#endif + + +char * +util_tilde_expand(fname) +char *fname; +{ +#ifdef BSD_SIS + struct passwd *userRecord; + char username[256], *filename, *dir; + register int i, j; + + filename = ALLOC(char, strlen(fname) + 256); + + /* Clear the return string */ + i = 0; + filename[0] = '\0'; + + /* Tilde? */ + if (fname[0] == '~') { + j = 0; + i = 1; + while ((fname[i] != '\0') && (fname[i] != '/')) { + username[j++] = fname[i++]; + } + username[j] = '\0'; + dir = (char *)0; + if (username[0] == '\0') { + /* ~/ resolves to home directory of current user */ + userRecord = getpwuid(getuid()); + if (userRecord) dir = userRecord->pw_dir; + } else { + /* Special check for ~octtools */ + if (!strcmp(username,"octtools")) + dir = getenv("OCTTOOLS"); + /* ~user/ resolves to home directory of 'user' */ + if (!dir) { + userRecord = getpwnam(username); + if (userRecord) dir = userRecord->pw_dir; + } + } + if (dir) (void) strcat(filename, dir); + else i = 0; /* leave fname as-is */ + } /* if tilde */ + + /* Concantenate remaining portion of file name */ + (void) strcat(filename, fname + i); + return filename; +#else + return util_strsav(fname); +#endif +} diff --git a/sis/util/tmpfile.c b/sis/util/tmpfile.c new file mode 100644 index 0000000..82f71f1 --- /dev/null +++ b/sis/util/tmpfile.c @@ -0,0 +1,150 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/tmpfile.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +/* + * util_tmpfile -- open an unnamed temporary file + * + * Many compilers/systems do not have this, or have buggy versions. + * + */ + +/* LINTLIBRARY */ + +/* util_tempnam and check_directory are from + Jonathan I. Kamens <jik@pit-manager.mit.edu> */ + +/* modified slightly by Ellen Sentovich ellen@ic.berkeley.edu */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include "util.h" + +static char check_directory(dir) +char *dir; +{ + struct stat statbuf; + + if (! dir) + return 0; + else if (stat(dir, &statbuf) < 0) + return 0; + else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) + return 0; + else if (access(dir, W_OK | X_OK) < 0) + return 0; + else + return 1; +} + +/* function for creating temporary filenames */ +char *util_tempnam(dir, pfx) +char *dir, *pfx; +{ + extern char *getenv(); + char *tmpdir = NULL, *env, *filename; + static char unique_letters[4] = "AAA"; + char addslash = 0; + + /* + * If a directory is passed in, verify that it exists and is a + * directory and is writeable by this process. If no directory + * is passed in, or if the directory that is passed in does not + * exist, check the environment variable TMPDIR. If it isn't + * set, check the predefined constant P_tmpdir. If that isn't + * set, use "/tmp/". + */ + + if ((env = getenv ("TMPDIR")) && check_directory(env)) + tmpdir = env; + else if (dir && check_directory(dir)) + tmpdir = dir; +#ifdef P_tmpdir + else if (check_directory(P_tmpdir)) + tmpdir = P_tmpdir; +#endif + else + tmpdir = "/tmp/"; + + /* + * OK, now that we've got a directory, figure out whether or not + * there's a slash at the end of it. + */ + if (tmpdir[strlen(tmpdir) - 1] != '/') + addslash = 1; + + /* + * Now figure out the set of unique letters. + */ + unique_letters[0]++; + if (unique_letters[0] > 'Z') { + unique_letters[0] = 'A'; + unique_letters[1]++; + if (unique_letters[1] > 'Z') { + unique_letters[1] = 'A'; + unique_letters[2]++; + if (unique_letters[2] > 'Z') { + unique_letters[2]++; + } + } + } + + /* + * Allocate a string of sufficient length. + */ + if (pfx) { + filename = (char *) malloc(strlen(tmpdir) + addslash + strlen(pfx) + 10 +); + } else { + filename = (char *) malloc(strlen(tmpdir) + addslash + 10); + } + + /* + * And create the string. + */ + (void) sprintf(filename, "%s%s%s%sa%05d", tmpdir, addslash ? "/" : "", + pfx ? pfx : "", unique_letters, getpid()); + + return filename; +} + + +#ifdef UNIX + +FILE * +util_tmpfile() +{ + FILE *fp; + char *filename; + + filename = util_tempnam(NIL(char), "SIS"); + if ((fp = fopen(filename, "w+")) == NULL) { + FREE(filename); + return NULL; + } + (void) unlink(filename); + FREE(filename); + return fp; +} + +#else + +FILE * +util_tmpfile() +{ + FILE *fp; + + if ((fp = fopen("utiltmp", "w+")) == NULL) { + return NULL; + } + (void) unlink("utiltmp"); + return fp; +} + +#endif diff --git a/sis/util/util.doc b/sis/util/util.doc new file mode 100644 index 0000000..bb45bc4 --- /dev/null +++ b/sis/util/util.doc @@ -0,0 +1,208 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/util.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:53 $ + * + */ +Summary: + ALLOC() + REALLOC() + FREE() + NIL() + int util_pipefork() + char *util_tilde_expand() + char *util_file_search() + char *util_path_search() + long util_cpu_time() + char *util_print_time() + int util_save_image() + void util_print_cpu_stats() + char *util_strsav() + int util_getopt() + int util_getopt_reset() + util_tmpfile() + + +type * +ALLOC(type, number) +typeof type; +int number; + Allocates 'number' objects of type 'type'. This macro should be + used rather than calling malloc() directly because it casts the + arguments appropriately, and ALLOC() will never return NIL(char), + choosing instead to terminate the program. + + +void +FREE(obj) + Free object 'obj'. This macro should be used rather than + calling free() directly because it casts the argument + appropriately. It also guarantees that FREE(0) will work + properly. + + +type * +REALLOC(type, obj, number) + Re-allocate 'obj' to hold 'number' objects of type 'type'. + This macro should be used rather than calling realloc() + directly because it casts the arguments appropriately, and + REALLOC() will never return NIL(char), instead choosing to + terminate the program. It also guarantees that REALLOC(type, 0, n) + is the same as ALLOC(type, n). + + +type * +NIL(type) + Returns 0 properly casted into a pointer to an object of type + 'type'. Strictly speaking, this macro is only required when + a 0 pointer is passed as an argument to a function. Still, + some prefer the style of always casting their 0 pointers using + this macro. + + +int +util_pipefork(argv, toCommand, fromCommand) +char **argv; +FILE **toCommand; +FILE **fromCommand; + Fork (using execvp(3)) the program argv[0] with argv[1] ... + argv[n] as arguments. (argv[n+1] is set to NIL(char) to + indicate the end of the list). Set up two-way pipes between + the child process and the parent, returning file pointer + 'toCommand' which can be used to write information to the + child, and the file pointer 'fromCommand' which can be used to + read information from the child. As always with unix pipes, + watch out for dead-locks. Returns 1 for success, 0 if any + failure occured forking the child. + + +char * +util_tilde_expand(filename) +char *filename; + Returns a new string corresponding to 'tilde-expansion' of the + given filename (see csh(1), "filename substitution"). This + means recognizing ~user and ~/ constructs, and inserting the + appropriate user's home directory. The returned string should + be free'd by the caller. + + +char * +util_file_search(file, path, mode) +char *file; +char *path; +char *mode; + 'path' is string of the form "dir1:dir2: ...". Each of the + directories is searched (in order) for a file matching 'file' + in that directory. 'mode' checks that the file can be accessed + with read permission ("r"), write permission ("w"), or execute + permission ("x"). The expanded filename is returned, or + NIL(char) is returned if no file could be found. The returned + string should be freed by the caller. Tilde expansion is + performed on both 'file' and any directory in 'path'. + + +char * +util_path_search(program) +char *program; + Simulate the execvp(3) semantics of searching the user's environment + variable PATH for an executable 'program'. Returns the file name + of the first executable matching 'program' in getenv("PATH"), or + returns NIL(char) if none was found. This routines uses + util_file_search(). + + +long +util_cpu_time() + Returns the processor time used since some constant reference + in milliseconds. + + +char * +util_print_time(time) +long time; + Converts a time into a (static) printable string. Intended to + allow different hosts to provide differing degrees of + significant digits in the result (e.g., IBM 3090 is printed to + the millisecond, and the IBM PC usually is printed to the + second). Returns a string of the form "10.5 sec". + + +int +util_save_image(old_file, new_file) +char *old_file; +char *new_file; + Save the text and data segments of the current executable + (which is the file 'old_file') into the file 'new_file'. + Returns 1 for success, 0 for failure. 'old_file' is required + in order to preserve symbol table information for the new + executable. 'old_file' can be derived from argv[0] of the + current executable using util_path_search(). NOTE: no stack + information is preserved. When the program restarts, it + re-enters main() with no valid stack. This is currently highly + BSD-specific, but should run on most operating systems which are + derived from Berkeley Unix 4.2. + + +void +util_restart(old_file, new_file, interval) +char *old_file; +char *new_file; +int interval; + Set a checkpoint interval for the current program. Every + 'interval' seconds, the current program will be saved to the + file 'new_file'. Also enables the signal SIGQUIT (usually ^\) + to force the program to checkpoint and terminate. 'old_file' + is the filename of the current executable; this allows for the + saving of the symbol table when the program is checkpointed. + 'old_file' can be derived from argv[0] of the current + executable using util_path_search(). This saves all stack and + state information, guaranteeing complete restart when the new + executable is run. util_restart() must be called as the first + statement in main (except, of course, for util_path_search()). + This is much more operating system and hardware dependent than + util_save_image(); currently it is implemented only for DEC VAX + under Ultrix and 4.3bsd, and Sun 3 under Sun OS. + + +void +util_print_cpu_stats(fp) +FILE *fp; + Dump to the given file a summary of processor usage statistics. + For BSD machines, this includes a formatted dump of the + getrusage(2) structure. + + +char * +util_strsav(s) +char *s; + Also known as strsav() for backwards compatability. + Returns a copy of the string 's'. + + +int +util_getopt(argc, argv, string) +int argc; +char **argv; +char *string; + Also known as getopt(3) for backwards compatability. + Parses options from an argc/argv command line pair. + + +int +util_getopt_reset() + Reset getopt argument parsing to start parsing a new argc/argv pair. + Not available from the standard getopt(3). + + +FILE * +util_tmpfile() + Returns a file pointer to a temporary file. It uses util_tempnam() + to determine a unique filename. If TMPDIR is defined in the + environment, it uses that directory. Otherwise, it uses the + directory defined by the system as P_tmpdir. If that is not + defined, it uses /tmp. The file can be written to, and subsequently + read from by calling rewind before reading. The file should be + closed using fclose when it is no longer needed. diff --git a/sis/util/util.h b/sis/util/util.h new file mode 100644 index 0000000..5e3fd04 --- /dev/null +++ b/sis/util/util.h @@ -0,0 +1,286 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/util/util.h,v $ + * $Author: pchong $ + * $Revision: 1.4 $ + * $Date: 2005/03/08 04:13:30 $ + * + */ +#ifndef UTIL_H +#define UTIL_H + +#if defined(_IBMR2) +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE /* Argh! IBM strikes again */ +#endif +#ifndef _ALL_SOURCE +#define _ALL_SOURCE /* Argh! IBM strikes again */ +#endif +#ifndef _ANSI_C_SOURCE +#define _ANSI_C_SOURCE /* Argh! IBM strikes again */ +#endif +#endif + +#if defined(__STDC__) || defined(sprite) || defined(_IBMR2) || defined(__osf__) +#include <unistd.h> +#endif + +#if defined(_IBMR2) && !defined(__STDC__) +#define _BSD +#endif + +#include "ansi.h" /* since some files don't include sis.h */ + +/* for CUDD package */ +#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4 +typedef long util_ptrint; +#else +typedef int util_ptrint; +#endif + +/* This was taken out and defined at compile time in the SIS Makefile + that uses the OctTools. When the OctTools are used, USE_MM is defined, + because the OctTools contain libmm.a. Otherwise, USE_MM is not defined, + since the mm package is not distributed with SIS, only with Oct. */ + +/* #define USE_MM */ /* choose libmm.a as the memory allocator */ + +#define NIL(type) ((type *) 0) + +#ifdef USE_MM +/* + * assumes the memory manager is libmm.a + * - allows malloc(0) or realloc(obj, 0) + * - catches out of memory (and calls MMout_of_memory()) + * - catch free(0) and realloc(0, size) in the macros + */ +#define ALLOC(type, num) \ + ((type *) malloc(sizeof(type) * (num))) +#define REALLOC(type, obj, num) \ + (obj) ? ((type *) realloc((char *) obj, sizeof(type) * (num))) : \ + ((type *) malloc(sizeof(type) * (num))) +#define FREE(obj) \ + ((obj) ? (free((char *) (obj)), (obj) = 0) : 0) +#else +/* + * enforce strict semantics on the memory allocator + * - when in doubt, delete the '#define USE_MM' above + */ +#define ALLOC(type, num) \ + ((type *) MMalloc((long) sizeof(type) * (long) (num))) +#define REALLOC(type, obj, num) \ + ((type *) MMrealloc((char *) (obj), (long) sizeof(type) * (long) (num))) +#define FREE(obj) \ + ((obj) ? (free((void *) (obj)), (obj) = 0) : 0) +#endif + + +/* Ultrix (and SABER) have 'fixed' certain functions which used to be int */ +#if defined(ultrix) || defined(SABER) || defined(aiws) || defined(__hpux) || defined(__STDC__) || defined(apollo) +#define VOID_HACK void +#else +#define VOID_HACK int +#endif + + +/* No machines seem to have much of a problem with these */ +#include <stdio.h> +#include <ctype.h> + + +/* Some machines fail to define some functions in stdio.h */ +#if !defined(__STDC__) && !defined(sprite) && !defined(_IBMR2) && !defined(__osf__) +extern FILE *popen(), *tmpfile(); +extern int pclose(); +#ifndef clearerr /* is a macro on many machines, but not all */ +extern VOID_HACK clearerr(); +#endif +#ifndef rewind +extern VOID_HACK rewind(); +#endif +#endif + +#ifndef PORT_H +#include <sys/types.h> +#include <signal.h> +#if defined(ultrix) +#if defined(_SIZE_T_) +#define ultrix4 +#else +#if defined(SIGLOST) +#define ultrix3 +#else +#define ultrix2 +#endif +#endif +#endif +#endif + +/* most machines don't give us a header file for these */ +#if defined(__STDC__) || defined(sprite) || defined(_IBMR2) || defined(__osf__) || defined(sunos4) || defined(__hpux) +#include <stdlib.h> +#if defined(__hpux) +#include <errno.h> /* For perror() defininition */ +#endif /* __hpux */ +#else +extern VOID_HACK abort(), free(), exit(), perror(); +extern char *getenv(); +#ifdef ultrix4 +extern void *malloc(), *realloc(), *calloc(); +#else +extern char *malloc(), *realloc(), *calloc(); +#endif +#if defined(aiws) +extern int sprintf(); +#else +#ifndef _IBMR2 +extern char *sprintf(); +#endif +#endif +extern int system(); +extern double atof(); +#endif + +#ifndef PORT_H +#if defined(ultrix3) || defined(sunos4) || defined(_IBMR2) || defined(__STDC__) +#define SIGNAL_FN void +#else +/* sequent, ultrix2, 4.3BSD (vax, hp), sunos3 */ +#define SIGNAL_FN int +#endif +#endif + +/* some call it strings.h, some call it string.h; others, also have memory.h */ +#if defined(__STDC__) || defined(sprite) +#include <string.h> +#else +#if defined(ultrix4) || defined(__hpux) +#include <strings.h> +#else +#if defined(_IBMR2) || defined(__osf__) +#include<string.h> +#include<strings.h> +#else +/* ANSI C string.h -- 1/11/88 Draft Standard */ +/* ugly, awful hack */ +#ifndef PORT_H +extern char *strcpy(), *strncpy(), *strcat(), *strncat(), *strerror(); +extern char *strpbrk(), *strtok(), *strchr(), *strrchr(), *strstr(); +extern int strcoll(), strxfrm(), strncmp(), strlen(), strspn(), strcspn(); +extern char *memmove(), *memccpy(), *memchr(), *memcpy(), *memset(); +extern int memcmp(), strcmp(); +#endif +#endif +#endif +#endif + +/* a few extras */ +#if defined(__hpux) +#define random() lrand48() +#define srandom(a) srand48(a) +#define bzero(a,b) memset(a, 0, b) +#else +#if !defined(__osf__) && !defined(linux) && !defined(__CYGWIN__) +/* these are defined as macros in stdlib.h */ +extern VOID_HACK srandom(); +extern long random(); +#endif +#endif + +#if defined(__STDC__) || defined(sprite) +#include <assert.h> +#else +#ifndef NDEBUG +#define assert(ex) {\ + if (! (ex)) {\ + (void) fprintf(stderr,\ + "Assertion failed: file %s, line %d\n\"%s\"\n",\ + __FILE__, __LINE__, "ex");\ + (void) fflush(stdout);\ + abort();\ + }\ +} +#else +#define assert(ex) ; +#endif +#endif + + +#define fail(why) {\ + (void) fprintf(stderr, "Fatal error: file %s, line %d\n%s\n",\ + __FILE__, __LINE__, why);\ + (void) fflush(stdout);\ + abort();\ +} + + +#ifdef lint +#undef putc /* correct lint '_flsbuf' bug */ +#undef ALLOC /* allow for lint -h flag */ +#undef REALLOC +#define ALLOC(type, num) (((type *) 0) + (num)) +#define REALLOC(type, obj, num) ((obj) + (num)) +#endif + +#if !defined(MAXPATHLEN) +#define MAXPATHLEN 1024 +#endif + +/* These arguably do NOT belong in util.h */ +#ifndef ABS +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + + +#ifndef USE_MM +EXTERN void MMout_of_memory ARGS((long)); +EXTERN char *MMalloc ARGS((long)); +EXTERN char *MMrealloc ARGS((char *, long)); +EXTERN void MMfree ARGS((char *)); +#endif + +EXTERN void util_print_cpu_stats ARGS((FILE *)); +EXTERN long util_cpu_time ARGS((void)); +EXTERN void util_getopt_reset ARGS((void)); +EXTERN int util_getopt ARGS((int, char **, char *)); +EXTERN char *util_path_search ARGS((char *)); +EXTERN char *util_file_search ARGS((char *, char *, char *)); +EXTERN int util_pipefork ARGS((char **, FILE **, FILE **, int *)); +EXTERN char *util_print_time ARGS((long)); +EXTERN int util_save_image ARGS((char *, char *)); +EXTERN char *util_strsav ARGS((char *)); +EXTERN int util_do_nothing ARGS((void)); +EXTERN char *util_tilde_expand ARGS((char *)); +EXTERN char *util_tempnam ARGS((char *, char *)); +EXTERN FILE *util_tmpfile ARGS((void)); + +#define ptime() util_cpu_time() +#define print_time(t) util_print_time(t) + +/* util_getopt() global variables (ack !) */ +extern int util_optind; +extern char *util_optarg; + +/* for CUDD package */ +extern long getSoftDataLimit (void); + +#include <math.h> +#ifndef HUGE +#define HUGE 8.9884656743115790e+307 +#endif +#ifndef HUGE_VAL +#define HUGE_VAL HUGE +#endif +#ifndef MAXINT +#define MAXINT (1 << 30) +#endif + +#include <stdarg.h> +#endif diff --git a/sis/var_set/Makefile.am b/sis/var_set/Makefile.am new file mode 100644 index 0000000..a25206f --- /dev/null +++ b/sis/var_set/Makefile.am @@ -0,0 +1,7 @@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include + +noinst_LIBRARIES = libvar_set.a +libvar_set_a_SOURCES = var_set.c +pkginclude_HEADERS = var_set.h +dist_doc_DATA = var_set.doc diff --git a/sis/var_set/Makefile.in b/sis/var_set/Makefile.in new file mode 100644 index 0000000..01ec8ca --- /dev/null +++ b/sis/var_set/Makefile.in @@ -0,0 +1,418 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +SOURCES = $(libvar_set_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = sis/var_set +DIST_COMMON = $(dist_doc_DATA) $(pkginclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libvar_set_a_AR = $(AR) $(ARFLAGS) +libvar_set_a_LIBADD = +am_libvar_set_a_OBJECTS = var_set.$(OBJEXT) +libvar_set_a_OBJECTS = $(am_libvar_set_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libvar_set_a_SOURCES) +DIST_SOURCES = $(libvar_set_a_SOURCES) +am__installdirs = "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)" +dist_docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_doc_DATA) +pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(pkginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +docdir = @SIS_DOCDIR@ +AM_CPPFLAGS = -I../include +noinst_LIBRARIES = libvar_set.a +libvar_set_a_SOURCES = var_set.c +pkginclude_HEADERS = var_set.h +dist_doc_DATA = var_set.doc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sis/var_set/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sis/var_set/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libvar_set.a: $(libvar_set_a_OBJECTS) $(libvar_set_a_DEPENDENCIES) + -rm -f libvar_set.a + $(libvar_set_a_AR) libvar_set.a $(libvar_set_a_OBJECTS) $(libvar_set_a_LIBADD) + $(RANLIB) libvar_set.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)" + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-pkgincludeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_docDATA install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pkgincludeHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_docDATA uninstall-info-am \ + uninstall-pkgincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sis/var_set/var_set.c b/sis/var_set/var_set.c new file mode 100644 index 0000000..f1d6f10 --- /dev/null +++ b/sis/var_set/var_set.c @@ -0,0 +1,271 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/var_set/var_set.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:00 $ + * $Log: var_set.c,v $ + * Revision 1.1.1.1 2004/02/07 10:15:00 pchong + * imported + * + * Revision 1.2 1993/07/19 23:34:41 sis + * *** empty log message *** + * + * Revision 1.4 1993/06/25 16:33:05 shiple + * Fixed bug in print statement. + * + * Revision 1.3 1993/02/25 02:04:41 shiple + * Added file pointer argument to var_set_print. + * + * Revision 1.2 1993/02/24 23:34:46 shiple + * Replace "8" by VAR_SET_BYTE_SIZE. + * + * Revision 1.1 1993/02/23 22:57:44 shiple + * Initial revision + * + * + */ +#include "util.h" +#include "var_set.h" + +var_set_t *var_set_new(size) +int size; +{ + var_set_t *result = ALLOC(var_set_t, 1); + + result->n_elts = size; + result->n_words = size / VAR_SET_WORD_SIZE + ((size % VAR_SET_WORD_SIZE == 0) ? 0 : 1); + result->data = ALLOC(unsigned int, result->n_words); + (void) var_set_clear(result); + return result; +} + +var_set_t *var_set_copy(set) +var_set_t *set; +{ + int i; + var_set_t *result = ALLOC(var_set_t, 1); + + *result = *set; + result->data = ALLOC(unsigned int, result->n_words); + for (i = 0; i < result->n_words; i++) + result->data[i] = set->data[i]; + return result; +} + +var_set_t *var_set_assign(result, set) +var_set_t *result; +var_set_t *set; +{ + int i; + + assert(result->n_elts == set->n_elts); + for (i = 0; i < result->n_words; i++) + result->data[i] = set->data[i]; + return result; +} + +void var_set_free(set) +var_set_t *set; +{ + FREE(set->data); + FREE(set); +} + +static int size_array[256]; + +static int init_size_array() +{ + int i, j; + int count; + + for (i = 0; i < 256; i++) { + count = 0; + for (j = 0; j < VAR_SET_WORD_SIZE; j++) { + count += VAR_SET_EXTRACT_BIT(i, j); + } + size_array[i] = count; + } +} + +int var_set_n_elts(set) +var_set_t *set; +{ + register int i, j; + register unsigned int value; + int n_bytes = VAR_SET_WORD_SIZE / VAR_SET_BYTE_SIZE; + int count = 0; + + if (size_array[1] == 0) init_size_array(); + for (i = 0; i < set->n_words; i++) { + value = set->data[i]; + for (j = 0; j < n_bytes; j++) { + count += size_array[value & 0xff]; + value >>= VAR_SET_BYTE_SIZE; + } + } + return count; +} + +var_set_t *var_set_or(result, a, b) +var_set_t *result; +var_set_t *a; +var_set_t *b; +{ + int i; + assert(result->n_elts == a->n_elts); + assert(result->n_elts == b->n_elts); + for (i = 0; i < result->n_words; i++) + result->data[i] = a->data[i] | b->data[i]; + return result; +} + +var_set_t *var_set_and(result, a, b) +var_set_t *result; +var_set_t *a; +var_set_t *b; +{ + int i; + assert(result->n_elts == a->n_elts); + assert(result->n_elts == b->n_elts); + for (i = 0; i < result->n_words; i++) + result->data[i] = a->data[i] & b->data[i]; + return result; +} + +var_set_t *var_set_not(result, a) +var_set_t *result; +var_set_t *a; +{ + int i; + unsigned int mask; + + assert(result->n_elts == a->n_elts); + for (i = 0; i < a->n_words; i++) + result->data[i] = ~a->data[i]; + mask = (unsigned int) VAR_SET_ALL_ONES >> (a->n_words * VAR_SET_WORD_SIZE - a->n_elts); + result->data[a->n_words - 1] &= mask; + return result; +} + +int var_set_get_elt(set, index) +var_set_t *set; +int index; +{ + assert(index >= 0 && index < set->n_elts); + return VAR_SET_EXTRACT_BIT(set->data[index / VAR_SET_WORD_SIZE], index % VAR_SET_WORD_SIZE); +} + +void var_set_set_elt(set, index) +var_set_t *set; +int index; +{ + unsigned int *value; + assert(index >= 0 && index < set->n_elts); + value = &(set->data[index / VAR_SET_WORD_SIZE]); + *value = *value | (1 << (index % VAR_SET_WORD_SIZE)); +} + +void var_set_clear_elt(set, index) +var_set_t *set; +int index; +{ + unsigned int *value; + assert(index >= 0 && index < set->n_elts); + value = &(set->data[index / VAR_SET_WORD_SIZE]); + *value = *value & ~(1 << (index % VAR_SET_WORD_SIZE)); +} + +void var_set_clear(set) +var_set_t *set; +{ + int i; + + for (i = 0; i < set->n_words; i++) + set->data[i] = 0; +} + +int var_set_intersect(a, b) +var_set_t *a; +var_set_t *b; +{ + int i; + assert(a->n_elts == b->n_elts); + for (i = 0; i < a->n_words; i++) + if (a->data[i] & b->data[i]) return 1; + return 0; +} + +int var_set_is_empty(a) +var_set_t *a; +{ + int i; + for (i = 0; i < a->n_words; i++) + if (a->data[i]) return 0; + return 1; +} + +int var_set_is_full(a) +var_set_t *a; +{ + int i; + int value; + for (i = 0; i < a->n_words - 1; i++) + if (a->data[i] != VAR_SET_ALL_ONES) return 0; + value = VAR_SET_ALL_ONES >> (a->n_words * VAR_SET_WORD_SIZE - a->n_elts); + return (a->data[a->n_words - 1] == value); +} + +void var_set_print(fp, set) +FILE *fp; +var_set_t *set; +{ + int i; + for (i = 0; i < set->n_elts; i++) { + fprintf(fp, "%d ", var_set_get_elt(set, i)); + } + fprintf(fp, "\n"); +} + + /* returns 1 if equal, 0 otherwise */ + +int var_set_equal(a, b) +var_set_t *a; +var_set_t *b; +{ + int i; + + assert(a->n_elts == b->n_elts); + for (i = 0; i < a->n_words; i++) + if (a->data[i] != b->data[i]) return 0; + return 1; +} + + /* returns 0 if equal, 1 otherwise */ + +int var_set_cmp(obj1, obj2) +char *obj1; +char *obj2; +{ + int i; + var_set_t *a = (var_set_t *) obj1; + var_set_t *b = (var_set_t *) obj2; + + assert(a->n_elts == b->n_elts); + for (i = 0; i < a->n_words; i++) + if (a->data[i] != b->data[i]) return 1; + return 0; +} + + /* to be used when sets are used as keys in hash tables */ +unsigned int var_set_hash(set) +var_set_t *set; +{ + int i; + unsigned int result = 0; + + for (i = 0; i < set->n_words; i++) + result += (unsigned int) set->data[i]; + return result; +} diff --git a/sis/var_set/var_set.doc b/sis/var_set/var_set.doc new file mode 100644 index 0000000..8eebd6e --- /dev/null +++ b/sis/var_set/var_set.doc @@ -0,0 +1,187 @@ + +var_set Package, Version 1.0 + +Tom Shiple (original contributor: Herve' Touati) +University of California, Berkeley, 1993 + + +Introduction ----------------------------------------------------------------- + +The var_set package is used to store and manipulate sets. The var_set_t data +structure is essentially a bit array. Its size is static. The positions of +the array are numbered from 0 to n-1, where n is the size of the var_set. When +a bit is "set", its value is 1; when a bit is "clear", its value is 0. + + +Summary ----------------------------------------------------------------------- + + var_set_new() + var_set_copy() + var_set_assign() + var_set_free() + var_set_n_elts() + var_set_or() + var_set_and() + var_set_not() + var_set_get_elt() + var_set_set_elt() + var_set_clear_elt() + var_set_clear() + var_set_intersect() + var_set_is_empty() + var_set_is_full() + var_set_print() + var_set_equal() + var_set_cmp() + var_set_hash() + + +Description of Functions ------------------------------------------------------ + +var_set_t +*var_set_new(size) +int size; + + Allocate a new var_set data structure of size `size'. Clears all the + elements. + +var_set_t +*var_set_copy(set) +var_set_t *set; + + Allocate a new var_set data structure with the same contents as `set'. + +var_set_t +*var_set_assign(result, set) +var_set_t *result; +var_set_t *set; + + Assign the contents of `result' to be the same as those of `set'. `result' + and `set' must be the same size. + +void +var_set_free(set) +var_set_t *set; + + Free the var_set data structure `set'. + +int +var_set_n_elts(set) +var_set_t *set; + + Return the number of bits in var_set `set' which are set (i.e. the + cardinality). + +var_set_t +*var_set_or(result, a, b) +var_set_t *result; +var_set_t *a; +var_set_t *b; + + Compute the bitwise inclusive OR of `a' and `b', and store the result in + `result'. Also, return a pointer to `result'. `a', `b', and `result' + must be the same size. Note that `result' can be the same as either or + both of `a' and `b' (e.g. var_set_or(foo, foo, bar)). + +var_set_t +*var_set_and(result, a, b) +var_set_t *result; +var_set_t *a; +var_set_t *b; + + Compute the bitwise AND of `a' and `b', and store the result in `result'. + Also, return a pointer to `result'. `a', `b', and `result' must be the + same size. Note that `result' can be the same as either or both of `a' + and `b' (e.g. var_set_and(foo, foo, bar)). + +var_set_t +*var_set_not(result, a) +var_set_t *result; +var_set_t *a; + + Compute the bitwise complement of `a', and store the result in `result'. + Also, return a pointer to `result'. `a' and `result' must be the same + size. Note that `result' can be the same as `a' (e.g. + var_set_not(foo, foo)). + +int +var_set_get_elt(set, index) +var_set_t *set; +int index; + + Return the value of the bit at position `index' in `set'. `index' must be + at least zero and less than the size of `set'. + +void +var_set_set_elt(set, index) +var_set_t *set; +int index; + + Set the value of the bit at position `index' in `set'. `index' must be at + least zero and less than the size of `set'. + +void +var_set_clear_elt(set, index) +var_set_t *set; +int index; + + Clear the value of the bit at position `index' in `set'. `index' must be at + least zero and less than the size of `set'. + +void +var_set_clear(set) +var_set_t *set; + + Clear the value of all the bits in `set'. + +int +var_set_intersect(a, b) +var_set_t *a; +var_set_t *b; + + Return 1 if the var_sets `a' and `b' intersect (i.e. have bits set in the + same position); otherwise, return 0. `a' and `b' must be the same size. + +int +var_set_is_empty(a) +var_set_t *a; + + Return 1 if every bit of var_set `a' is cleared; otherwise, return 0. + +int +var_set_is_full(a) +var_set_t *a; + + Return 1 if every bit of var_set `a' is set; otherwise, return 0. + +void +var_set_print(fp, set) +FILE *fp; +var_set_t *set; + + Print to `fp' the value of each bit in var_set `set'. Example output + for a set of 4 elements: "1 0 1 1". + +int +var_set_equal(a, b) +var_set_t *a; +var_set_t *b; + + Return 1 if the var_sets `a' and `b' are equal at every bit position; + otherwise, return 0. `a' and `b' must be the same size. + +int +var_set_cmp(obj1, obj2) +char *obj1; +char *obj2; + + Return 0 if the var_sets `a' and `b' are equal at every bit position; + otherwise, return 1. `a' and `b' must be the same size. + +unsigned int +var_set_hash(set) +var_set_t *set; + + Compute a hash value for the var_set `set'. This is to be used when + var_sets are used as keys in hash tables. + diff --git a/sis/var_set/var_set.h b/sis/var_set/var_set.h new file mode 100644 index 0000000..a55da0a --- /dev/null +++ b/sis/var_set/var_set.h @@ -0,0 +1,72 @@ +#ifndef VAR_SET_H /* { */ +#define VAR_SET_H + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sis/var_set/var_set.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:15:00 $ + * $Log: var_set.h,v $ + * Revision 1.1.1.1 2004/02/07 10:15:00 pchong + * imported + * + * Revision 1.3 1993/05/28 23:49:29 sis + * Aesthetic changes to prototypes. + * + * Revision 1.2 1993/05/11 19:49:14 sis + * Changes for ANSI C compatibility. + * + * Revision 1.1 1993/03/01 16:24:39 sis + * Initial revision + * + * Revision 1.1 1993/03/01 16:23:57 sis + * Initial revision + * + * Revision 1.3 1993/02/25 02:04:41 shiple + * Added file pointer argument to declaration of var_set_print. + * + * Revision 1.2 1993/02/24 23:35:16 shiple + * Add VAR_SET_BYTE_SIZE macro. Fix newly introduced bug in + * definition of VAR_SET_WORD_SIZE. + * + * Revision 1.1 1993/02/23 22:58:28 shiple + * Initial revision + * + * + */ + +#define VAR_SET_BYTE_SIZE 8 +#define VAR_SET_WORD_SIZE ((sizeof(unsigned int))*(VAR_SET_BYTE_SIZE)) +#define VAR_SET_ALL_ZEROS 0 +#define VAR_SET_ALL_ONES ((unsigned int) ~0) +#define VAR_SET_EXTRACT_BIT(word,pos) (((word) & (1 << (pos))) != 0) + +typedef struct var_set_struct { + int n_elts; + int n_words; + unsigned int *data; +} var_set_t; + +EXTERN var_set_t *var_set_new ARGS((int)); +EXTERN var_set_t *var_set_copy ARGS((var_set_t *)); +EXTERN var_set_t *var_set_assign ARGS((var_set_t *, var_set_t *)); +EXTERN void var_set_free ARGS((var_set_t *)); +EXTERN int var_set_n_elts ARGS((var_set_t *)); +EXTERN var_set_t *var_set_or ARGS((var_set_t *, var_set_t *, var_set_t *)); +EXTERN var_set_t *var_set_and ARGS((var_set_t *, var_set_t *, var_set_t *)); +EXTERN var_set_t *var_set_not ARGS((var_set_t *, var_set_t *)); +EXTERN int var_set_get_elt ARGS((var_set_t *, int)); +EXTERN void var_set_set_elt ARGS((var_set_t *, int)); +EXTERN void var_set_clear_elt ARGS((var_set_t *, int)); +EXTERN void var_set_clear ARGS((var_set_t *)); +EXTERN int var_set_intersect ARGS((var_set_t *, var_set_t *)); +EXTERN int var_set_is_empty ARGS((var_set_t *)); +EXTERN int var_set_is_full ARGS((var_set_t *)); +EXTERN void var_set_print ARGS((FILE *, var_set_t *)); +EXTERN int var_set_equal ARGS((var_set_t *, var_set_t *)); +EXTERN int var_set_cmp ARGS((char *, char *)); +EXTERN unsigned int var_set_hash ARGS((var_set_t *)); + +#endif /* } */ diff --git a/sred/Makefile.am b/sred/Makefile.am new file mode 100644 index 0000000..1b207b4 --- /dev/null +++ b/sred/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = -I../sis/include +AM_YFLAGS = -d +LDADD = ../sis/libsis.a -lm + +BUILT_SOURCES = gram.c gram.h lex.c +CLEANFILES = $(BUILT_SOURCES) + +bin_PROGRAMS = sred +sred_SOURCES = action.c boolcmp.c chinclus.c chiusura.c choose.c clinchain.c \ + clinclus.c clincop.c closure.c coloring.c comp.c connected.c esp_color.c \ + exist.c existdf.c generate.c ibincompa.c incompat.c iobincomp.c \ + label.c main.c makeout.c misc.c mxcomptbl.c newnstate.c newoutput.c \ + newprime.c obincompa.c prime.c primeones.c procargs.c qsort.c qspart.c \ + qspivot.c reduced.c reductio.h solution.c strbar.c strcom.c \ + gram.y lex.l +dist_man1_MANS = sred.1 diff --git a/sred/Makefile.in b/sred/Makefile.in new file mode 100644 index 0000000..59a4422 --- /dev/null +++ b/sred/Makefile.in @@ -0,0 +1,506 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(sred_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = sred$(EXEEXT) +subdir = sred +DIST_COMMON = $(dist_man1_MANS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in gram.c gram.h lex.c +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_sred_OBJECTS = action.$(OBJEXT) boolcmp.$(OBJEXT) \ + chinclus.$(OBJEXT) chiusura.$(OBJEXT) choose.$(OBJEXT) \ + clinchain.$(OBJEXT) clinclus.$(OBJEXT) clincop.$(OBJEXT) \ + closure.$(OBJEXT) coloring.$(OBJEXT) comp.$(OBJEXT) \ + connected.$(OBJEXT) esp_color.$(OBJEXT) exist.$(OBJEXT) \ + existdf.$(OBJEXT) generate.$(OBJEXT) ibincompa.$(OBJEXT) \ + incompat.$(OBJEXT) iobincomp.$(OBJEXT) label.$(OBJEXT) \ + main.$(OBJEXT) makeout.$(OBJEXT) misc.$(OBJEXT) \ + mxcomptbl.$(OBJEXT) newnstate.$(OBJEXT) newoutput.$(OBJEXT) \ + newprime.$(OBJEXT) obincompa.$(OBJEXT) prime.$(OBJEXT) \ + primeones.$(OBJEXT) procargs.$(OBJEXT) qsort.$(OBJEXT) \ + qspart.$(OBJEXT) qspivot.$(OBJEXT) reduced.$(OBJEXT) \ + solution.$(OBJEXT) strbar.$(OBJEXT) strcom.$(OBJEXT) \ + gram.$(OBJEXT) lex.$(OBJEXT) +sred_OBJECTS = $(am_sred_OBJECTS) +sred_LDADD = $(LDADD) +sred_DEPENDENCIES = ../sis/libsis.a +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) +YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) +SOURCES = $(sred_SOURCES) +DIST_SOURCES = $(sred_SOURCES) +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(dist_man1_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I../sis/include +AM_YFLAGS = -d +LDADD = ../sis/libsis.a -lm +BUILT_SOURCES = gram.c gram.h lex.c +CLEANFILES = $(BUILT_SOURCES) +sred_SOURCES = action.c boolcmp.c chinclus.c chiusura.c choose.c clinchain.c \ + clinclus.c clincop.c closure.c coloring.c comp.c connected.c esp_color.c \ + exist.c existdf.c generate.c ibincompa.c incompat.c iobincomp.c \ + label.c main.c makeout.c misc.c mxcomptbl.c newnstate.c newoutput.c \ + newprime.c obincompa.c prime.c primeones.c procargs.c qsort.c qspart.c \ + qspivot.c reduced.c reductio.h solution.c strbar.c strcom.c \ + gram.y lex.l + +dist_man1_MANS = sred.1 +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .l .o .obj .y +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps sred/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps sred/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +gram.h: gram.c + @if test ! -f $@; then \ + rm -f gram.c; \ + $(MAKE) gram.c; \ + else :; fi +sred$(EXEEXT): $(sred_OBJECTS) $(sred_DEPENDENCIES) + @rm -f sred$(EXEEXT) + $(LINK) $(sred_LDFLAGS) $(sred_OBJECTS) $(sred_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.l.c: + $(LEXCOMPILE) $< + sed '/^#/ s|$(LEX_OUTPUT_ROOT)\.c|$@|' $(LEX_OUTPUT_ROOT).c >$@ + rm -f $(LEX_OUTPUT_ROOT).c + +.y.c: + $(YACCCOMPILE) $< + if test -f y.tab.h; then \ + to=`echo "$*_H" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`; \ + sed "/^#/ s/Y_TAB_H/$$to/g" y.tab.h >$*.ht; \ + rm -f y.tab.h; \ + if cmp -s $*.ht $*.h; then \ + rm -f $*.ht ;\ + else \ + mv $*.ht $*.h; \ + fi; \ + fi + if test -f y.output; then \ + mv y.output $*.output; \ + fi + sed '/^#/ s|y\.tab\.c|$@|' y.tab.c >$@t && mv $@t $@ + rm -f y.tab.c +uninstall-info-am: +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(PROGRAMS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f gram.h + -rm -f lex.c + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -rm -f gram.c +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-man + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: install-man1 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am uninstall-man + +uninstall-man: uninstall-man1 + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-man1 \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-info-am uninstall-man uninstall-man1 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sred/action.c b/sred/action.c new file mode 100644 index 0000000..556169a --- /dev/null +++ b/sred/action.c @@ -0,0 +1,326 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/action.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +char *strcopyall (from) + +char *from; + +{ + char *to; + + MYCALLOC(char,to,strlen(from)+1); + strcpy (to, from); + + return (to); +} + +yyerror(message) +char *message; + +{ + int lp; + + errorcount++; + + if (mylinepos < 0) { + fprintf(stderr,"unexpected end of file \n"); + } + else { + fprintf(stderr, myline); + for (lp = 0; lp < mylinepos - 1; lp++) + if (myline[lp] == '\t') fprintf(stderr, "\t"); + else fprintf(stderr, " "); + fprintf(stderr, "^\n"); + + fprintf(stderr, "%s\n", message); + } +} + +error(message,element) + +char *message, *element; + +{ + errorcount++; + + fprintf(stderr,"%s%s\n", message, element); +} + +faterr (message,element) + +char *message, *element; + +{ + errorcount++; + + fprintf(stderr,"%s%s\n", message, element); + + abort (); +} + +int mygetc(file) + +FILE *file; + +{ + while ( myline[mylinepos] == '\0' ) { + + if (myline[mylinepos] == '\0') + if (fgets (myline, 512, file)) { + mylinepos = 0; + } + else { + mylinepos = -1; + return (EOF); + } + else mylinepos++; + } + + return ((int) myline[mylinepos++]); +} + +addoutputname() + +{ + NAMETABLE *temp, *newname (); + char wire[MAXNAME]; + + strcpy (wire, "y"); + strcat (wire, lastnum); + + temp = newname (lastid, wire); + + temp->next = nametable; + nametable = temp; +} + +addinputname() + +{ + NAMETABLE *temp, *newname (); + char wire[MAXNAME]; + + strcpy (wire, "x"); + strcat (wire, lastnum); + + temp = newname (lastid, wire); + + temp->next = nametable; + nametable = temp; +} + +addinput() + +{ + SYMTABLE *temp, *search(), *newsymbol(); + + if (strlen (lastvect) != nis) + error("wrong length input: ", lastin); + + if (search (inputlist, lastin) != 0) + error("multiple defined input symbol: ", lastin); + + temp = newsymbol (lastin, lastvect); + temp->next = inputlist; + inputlist = temp; +} + +addoutput() + +{ + SYMTABLE *temp, *search(), *newsymbol(); + + if (strlen (lastvect) != nos) + error("wrong length output: ", lastout); + + if (search (outputlist, lastout) != 0) + error("multiple defined output symbol: ", lastout); + + temp = newsymbol (lastout, lastvect); + temp->next = outputlist; + outputlist = temp; +} + +addstate() + +{ + SYMTABLE *temp, *search(), *newsymbol(); + + if (search (statelist, laststate) != 0) + error("multiple output associated to state: ", laststate); + + temp = newsymbol (laststate, lastvect); + temp->next = statelist; + statelist = temp; +} + +NAMETABLE *newname (name, wire) + +char *name, *wire; + +{ + NAMETABLE *temp; + + MYCALLOC (NAMETABLE, temp, 1); + + temp->symbol = strcopyall(name); + temp->wire = strcopyall (wire); + + return (temp); +} + +SYMTABLE *newsymbol (name, value) + +char *name, *value; + +{ + SYMTABLE *temp; + + MYCALLOC (SYMTABLE, temp, 1); + + temp->symbol = strcopyall(name); + temp->vector = strcopyall (value); + + return (temp); +} + +SYMTABLE *search (list, string) + +SYMTABLE *list; +char *string; + +{ + while ( list != (SYMTABLE *) 0 ) { + if ( strcmp (list->symbol, string) == 0 ) + return (list); + list = list->next; + } + return ( (SYMTABLE *) 0 ); +} + +moorewithinput() + +{ + SYMTABLE *temp; + + if (type!=MOORE) { + error("Moore type line in Mealy type machine",""); + return; + } + + MYREALLOC(INPUTTABLE, itable, itable_size, np); + if ((lastin[0] == 'e') || (lastin[0] == '*')) { + + if (!isymb) { + + temp = search (inputlist, lastin); + + if (temp == (SYMTABLE *) 0) + error("undefined input: ", lastin); + else itable[np].input = strcopyall (temp->vector); + } + else itable[np].input = strcopyall (lastin); + } + else { + if (strlen(lastin) != nis) + error("wrong length input: x", lastin); + else itable[np].input = strcopyall (lastin); + } + + temp = search (statelist, laststate); + + if ( temp == (SYMTABLE *) 0 ) + error("no output associated with state: ", laststate); + else itable[np].output = strcopyall (temp->vector); + + itable[np].pstate = strcopyall (laststate); + itable[np].nstate = strcopyall (lastnext); + + np++; +} + +moorenoinput() + +{ + SYMTABLE *temp; + + if (type!=MOORE) { + error("Moore type line in Mealy type machine",""); + return; + } + + MYREALLOC(INPUTTABLE, itable, itable_size, np); + if (nis!=0) error("missing input specification",""); + + temp = search (statelist, laststate); + + if ( temp == (SYMTABLE *) 0 ) + error("no output associated with state: ", laststate); + else itable[np].output = strcopyall (temp->vector); + + itable[np].pstate = strcopyall (laststate); + itable[np].nstate = strcopyall (lastnext); + + np++; +} + +mealy() + +{ + SYMTABLE *temp; + + if (type!=MEALY) { + error("Mealy type line in Moore type machine",""); + return; + } + + MYREALLOC(INPUTTABLE, itable, itable_size, np); + if ((lastin[0] == 'e') || (lastin[0] == '*')) { + + if (!isymb) { + + temp = search (inputlist, lastin); + + if (temp == (SYMTABLE *) 0) + error("undefined input: ", lastin); + else itable[np].input = strcopyall (temp->vector); + } + else itable[np].input = strcopyall (lastin); + } + else { + if (strlen(lastin) != nis) + error("wrong length input: x", lastin); + else itable[np].input = strcopyall (lastin); + } + + if ((lastout[0] == 'a') || (lastout[0] == '*')) { + + if (!osymb) { + + temp = search (outputlist, lastout); + + if (temp == (SYMTABLE *) 0) + error("undefined output: ", lastout); + else itable[np].output = strcopyall (temp->vector); + } + else itable[np].output = strcopyall (lastout); + } + else { + if (strlen(lastout) != nos) + error("wrong length output: y", lastout); + else itable[np].output = strcopyall (lastout); + } + + itable[np].pstate = strcopyall (laststate); + itable[np].nstate = strcopyall (lastnext); + + np++; +} diff --git a/sred/boolcmp.c b/sred/boolcmp.c new file mode 100644 index 0000000..a56b626 --- /dev/null +++ b/sred/boolcmp.c @@ -0,0 +1,33 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/boolcmp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ + +#include "reductio.h" + +boolcmp(s,t) +char s[],t[]; + +{ +/* returns 0 if s and t are equal in the boolean sense - + returns 1 otherwise */ + +int i,result; + +i = 0; +result = 0; +while (s[i] != '\0' && result == 0) +{ + if ( (s[i] == '0' && t[i] == '1') || (s[i] == '1' && t[i] == '0' ) ) + result = 1; + i++; +} + +return(result); + +} diff --git a/sred/chinclus.c b/sred/chinclus.c new file mode 100644 index 0000000..06448ea --- /dev/null +++ b/sred/chinclus.c @@ -0,0 +1,48 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/chinclus.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +ch_inclus(index,genclass,subclass) +int index,genclass,subclass; + +{ + /* ch_inclus = 1 iff the chain implied by the c-prime class "index" + is contained in the chain implied by the class referred to by + (genclass,subclass) */ + + int i; + int incluso; + pset_family chain; + int startchain; + + /* generation of the chain implied by the class (genclass,subclass) - + cardchain is the cardinality of the chain */ + chain = chiusura(genclass,subclass); + + /* startchain points to the beginning of the index-th chain + in the array implied */ + startchain = 0; + for (i=0; i<index; i++) startchain += firstchain.weight[i]; + startchain++; /* the index-th chain header is jumped over */ + + i = 0; + incluso = 1; + while ( i < firstchain.weight[index]-1 && incluso == 1 ) + { + +/*printf("chiamo la cl_in_chain con indice = %d\n", startchain + i);*/ + if ( cl_in_chain(startchain+i,chain) != 1 ) incluso = 0; + i++; + } + +/*printf("ch_inclus = %d\n", incluso);*/ + return(incluso); + +} diff --git a/sred/chiusura.c b/sred/chiusura.c new file mode 100644 index 0000000..a772eb3 --- /dev/null +++ b/sred/chiusura.c @@ -0,0 +1,86 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/chiusura.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +pset_family +chiusura(genclass,subclass) +int genclass,subclass; + +{ + + /* Find the chain implied by classj (genclass,subclass) */ + + pset_family chain; + pset implicata, classj; + int closed,membri; + int i,j,k; + + chain = sf_new (0, ns); + implicata = set_new (ns); + classj = set_new (ns); + /* compute classj (genclass,subclass) */ + set_copy (classj, GETSET(primes, genclass)); + set_remove (classj, subclass); + + /* compute the chain generated by the class (genclass,subclass) */ + + /* put in front of the chain the generating class */ + /* update the chain */ + sf_addset (chain,classj); + + closed = 0; /* closed is the number of the classes of the chain + whose implications have been computed */ + /* while the closed classes are fewer than the generating classes + linked in the chain */ + while (closed < chain->count) + { + closed++; /* closed is the relative address in the chain of the class + whose implications are currently computed */ + + /* a new class in the chain is closed */ + /* loop on all the inputs */ + for (k=0; k<ni; k++) + { + /* find the class implied by the current generating implicant class + under the current input */ + + /* compute the closure of the class chain[closed-1] */ + set_clear (implicata, ns); + + for (i=0; i<np; i++) /* loop on the symbolic product terms */ + { + if (itable[i].ilab-1 == k) + { + if (is_in_set (GETSET(chain, itable[i].plab-1), closed-1) && + itable[i].nlab != 0) + set_insert (implicata, itable[i].nlab-1); + } + } + + /* if implicata has more than one state and has not been already + included in the chain */ + + membri = set_ord (implicata); + + if ( membri >1 && existdf(implicata,chain) != 1) + { + /* add the implied class to the chain */ + + /* update the chain */ + sf_addset(chain,implicata); + } + } + + } + + set_free(implicata); + set_free(classj); + return chain; +} diff --git a/sred/choose.c b/sred/choose.c new file mode 100644 index 0000000..10a9524 --- /dev/null +++ b/sred/choose.c @@ -0,0 +1,162 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/choose.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +choose(parity) +int parity; +/* parity = 1 means that we are working on copertura1 - + parity = 2 means that we are working on copertura2 */ + +{ + + /* CHOOSES A SET OF CHAINS AS A COVER OF THE FSM */ + + int stin; /* stin is the number of states currently included in the cover */ + pset chosenchain; /* chosenchain[i] = 1 iff the i-th chain has been + included in the cover being chosen */ + pset currcover; /* array of the states covered by the current + "copertura" */ + pset vect; + int newstates,newclasses; + int currgain,maxgain; + int bestchain; + int startchain,endchain; + int i,j,k; + int first; + + /* printf("\n"); + printf("-------------------\n"); + printf("-CHOOSE-\n"); + printf("-------------------\n"); + */ + + stin = 0; + chosenchain = set_new (primes->count); + currcover = set_new (ns); + vect = set_new (ns); + + /* while there are states not yet included in the cover */ + while ( stin < ns ) + { + /*printf("\n", stin); + printf("stin = %d\n", stin);*/ + /* loop on the chains */ + /* choose the chain that maximizes + maxgain = #new_covered_states - #new_implied_classes_of_the_chain + ( .e. maxgain = newstates - newclasses ) */ + first = 1; + + for (i=0; i < primes->count; i++) + { + + /* if the current chain has not yet been included */ + if (! is_in_set (chosenchain, i)) + { + /* calcolo di newstates */ + newstates = 0; + for (j=0; j<ns; j++) + { + if (is_in_set (GETSET(firstchain.cover, i), j) && + ! is_in_set (currcover, j)) + newstates++; + } + /*printf("newstates = %d\n", newstates);*/ + + /* chains not covering any new state are discarded */ + if (newstates > 0) + { + /* computation of "newclasses" */ + /* count how many new implied classes the i-th chain would bring + to the covering "copertura" */ + newclasses = 0; + /* startchain points to the beginning of the current chain - + endchain to its end */ + startchain=endchain = 0; + for (j=0; j<i; j++) startchain += firstchain.weight[j]; + endchain = startchain + firstchain.weight[i]; + /* cl_in_cop = 1 iff the j-th implied class is already included + in "copertura" */ + for (j=startchain; j<endchain; j++) + { + set_copy (vect, GETSET (firstchain.implied, j)); + if (cl_in_cop(vect,parity) != 1) newclasses++; + } + /*printf("newclasses = %d\n", newclasses);*/ + + currgain = newstates - newclasses; + + /* compare with maxgain */ + if (first || currgain > maxgain) + { + maxgain = currgain; + bestchain = i; + first = 0; + } + /* ties are broken against chains made of only one class */ + if (currgain == maxgain && firstchain.weight[bestchain] == 1) + bestchain = i; + + } + } + } + + /* include in "copertura" the chain "bestchain" */ + set_insert (chosenchain, bestchain); + startchain=endchain = 0; + for (j=0; j<bestchain; j++) startchain += firstchain.weight[j]; + endchain = startchain + firstchain.weight[bestchain]; + /*printf("startchain = %d\n", startchain); + printf("endchain = %d\n", endchain);*/ + for (i=startchain; i<endchain; i++) + { + if (parity == 1) + { + set_copy (vect, GETSET (firstchain.implied, i)); + /* a class is added to "copertura" when not already included */ + if (cl_in_cop(vect,parity) != 1 ) + { + sf_addset (copertura1, GETSET (firstchain.implied, i)); + for (j=0; j<ns; j++) + { + if (is_in_set (GETSET (firstchain.implied, i), j) && + ! is_in_set (currcover, j)) + { + set_insert (currcover, j); + stin++; + } + } + } + } + else + { + set_copy (vect, GETSET (firstchain.implied, i)); + /* a class is added to "copertura" when not already included */ + if (cl_in_cop(vect,parity) != 1 ) + { + sf_addset (copertura2, GETSET (firstchain.implied, i)); + for (j=0; j<ns; j++) + { + if (is_in_set (GETSET (firstchain.implied, i), j) && + ! is_in_set (currcover, j)) + { + set_insert (currcover, j); + stin++; + } + } + } + } + } + + } + + set_free (chosenchain); + set_free (currcover); + set_free (vect); +} diff --git a/sred/clinchain.c b/sred/clinchain.c new file mode 100644 index 0000000..c751365 --- /dev/null +++ b/sred/clinchain.c @@ -0,0 +1,31 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/clinchain.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +cl_in_chain(indice,chain) +int indice; +pset_family chain; + +{ + /* cl_in_chain = 1 iff the class indice in the array implied + is included in chain */ + + int i,j; + pset p; + + foreachi_set (chain, i, p) { + /* the chain header is jumped over */ + if (i == 0) continue; + if (setp_implies (GETSET (firstchain.implied, indice), p)) { + return 1; + } + } + return 0; +} diff --git a/sred/clinclus.c b/sred/clinclus.c new file mode 100644 index 0000000..e870015 --- /dev/null +++ b/sred/clinclus.c @@ -0,0 +1,54 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/clinclus.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +cl_inclus(genclass,subclass,index) +int genclass,subclass,index; + +{ + /* cl_inclus = 1 iff the class referred to by ( genclass,subclass ) + is strictly included in the c-prime class of position "index" */ + + /* strict > 0 iff class(genclass,subclass) is included in class(index) + strictly and doesn't coincide with it ( strict = 0 ) + ======== */ + + int i; + int inclusa,strict,value; + pset classi,classj; + + classi = set_new (ns); + classj = set_new (ns); + set_copy (classj, GETSET(primes, genclass)); + set_remove (classj, subclass); + + set_copy (classi, GETSET(primes, index)); + + i = 0; + inclusa = 1; + strict = 0; + while ( i<ns && inclusa == 1 ) + { + if ( is_in_set (classj, i) ) + { + if ( is_in_set (classi, i) ) inclusa = 1; else inclusa = 0; + } + if ( ! is_in_set (classj, i) && is_in_set (classi, i) ) strict++; + i++; + } + + if ( inclusa == 1 && strict > 0 ) value = 1; else value = 0; +/*printf("cl_inclus = %d\n", value);*/ + set_free (classi); + set_free (classj); + return(value); + +} + diff --git a/sred/clincop.c b/sred/clincop.c new file mode 100644 index 0000000..9d75088 --- /dev/null +++ b/sred/clincop.c @@ -0,0 +1,40 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/clincop.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +cl_in_cop(class,parity) +pset class; +int parity; + +{ + /* checks whether "class" is already included in "copertura" */ + + int found,ident; + pset_family copertura; + pset p; + int i,j; + + found = 0; + if (parity == 1) + { + copertura = copertura1; + } + else + { + copertura = copertura2; + } + foreachi_set (copertura, i, p) { + if (setp_implies (class, p)) { + return 1; + } + } + return 0; + +} diff --git a/sred/closure.c b/sred/closure.c new file mode 100644 index 0000000..201b155 --- /dev/null +++ b/sred/closure.c @@ -0,0 +1,113 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/closure.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +closure(firstprime,lastprime) +int firstprime,lastprime; + +{ + + /* Find the chains implied by current primes */ + + pset implicata; + int peso,closed,membri; + int i,j,k; + int startchain,endchain; + + implicata = set_new (ns); + + /* + printf("\n"); + printf("~~~~~~~~~\n"); + printf("*CLOSURE*\n"); + printf("~~~~~~~~~\n"); + */ + /* weight[i] stores the cardinality of the chain of the i-th + prime */ + MYREALLOC (int,firstchain.weight, firstchain.weight_size, lastprime); + firstchain.implied = sf_new (0, ns); + firstchain.cover = sf_new (0, ns); + for (i=firstprime; i<lastprime; i++) firstchain.weight[i] = 0; + + /* peso is the cumulative weight of all the chains */ + peso = -1; + for (i=0; i<firstprime; i++) peso += firstchain.weight[i]; + + /* loop on the maximal compatibles */ + for (i=firstprime; i<lastprime; i++) + { + /* + printf("COMPUTATION OF THE CHAIN n. = %d\n",i+1); + */ + /* compute the chain generated by the i-th prime */ + + /* put in front of the chain the generating prime */ + /* 1) update the weight of the i-th chain */ + firstchain.weight[i]++; + /*printf("firstchain.weight[i] = %d\n", firstchain.weight[i]);*/ + /* 2) update the cumulative weight */ + peso++; + /*printf("peso = %d\n",peso);*/ + /* 3) update the chain and its cover */ + sf_insert_set (firstchain.implied, peso, GETSET (primes, i)); + sf_insert_set (firstchain.cover, i, GETSET (primes, i)); + + closed = 0; /* closed is the number of the classes of the i-th chain + whose implications have been computed */ + /* while the closed classes are fewer than the generating classes + linked in the i-th chain */ + while (closed < firstchain.weight[i]) + { + closed++; /* closed is the relative address in the i-th chain of the class + whose implications are currently computed */ + + /* a new class in the i-th chain is closed */ + /* loop on all the inputs */ + for (k=0; k<ni; k++) + { + /* find the class implied by the current generating implicant class + under the current input */ + + generate(i,closed,k,implicata,&firstchain); + + /* if implicata has more than one state and has not been already + included in the chain */ + + membri = set_ord (implicata); /* count the states in implicata */ + + if ( membri >1 && exist(i,implicata,&firstchain) != 1) + { + /* add the implied class to the chain of the i-th maximal compatible */ + + /* update the weight of the i-th chain */ + firstchain.weight[i]++; + /* update the cumulative weight */ + peso++; + /* update the chain and its cover */ + sf_insert_set (firstchain.implied, peso, implicata); + assert (i < firstchain.cover->count); + set_or (GETSET (firstchain.cover, i), + GETSET (firstchain.cover, i), implicata); + + } + } + + startchain = 0; + for (j=0; j<i; j++) startchain += firstchain.weight[j]; + endchain = startchain + firstchain.weight[i]; + } + + startchain = 0; + for (j=0; j<i; j++) startchain += firstchain.weight[j]; + endchain = startchain + firstchain.weight[i]; + } + + set_free (implicata); +} diff --git a/sred/coloring.c b/sred/coloring.c new file mode 100644 index 0000000..e2a73e6 --- /dev/null +++ b/sred/coloring.c @@ -0,0 +1,125 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/coloring.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +fast_coloring() + +/* Colors the connected components of the incompatibles graph */ + +{ + + int i,j,maxk,mink,vi,vj,i1,k; + int flagadja; + int *LForder[2]; + + /* Largest-first vertex ordering - vertices are ordered as follows : + deg(v1) >= deg(v2) >= ... >= deg(vn) . + Before the lfs-ordering : + LForder[2,i] = j iff vertex #(i+1) is connected to j other vertices - + After the lfs-ordering : + LForder[2,i1] <= LForder[2,i2] iff + deg(vertex#(LForder[1,i1])) <= deg(vertex#(LForder[1,i2])) + from right to left is the largest-first ordering */ + + + MYALLOC (int, LForder[0], ns); + MYALLOC (int, LForder[1], ns); + /* Before the lfs-ordering */ + /* + printf("\n"); + printf("************************************\n"); + printf("Degrees array : "); + */ + for (i=0; i<ns; i++) + { + LForder[0][i] = i+1; + /* printf("%d", LForder[0][i]); */ + } + /* + printf("\n"); + printf(" "); + */ + + for (i=0; i<ns; i++) + { + LForder[1][i] = 0; + for (j=0; j<ns; j++) + { + if (is_in_set (GETSET (incograph, i), j)) LForder[1][i]++; + } + /* printf("%d", LForder[1][i]); */ + } + /* printf("\n"); */ + + /* QUICKSORT */ + myqsort(LForder,1,ns); + + /* After the lfs-ordering */ + /* + printf("\n"); + printf("*******************************************\n"); + printf("Sorted degrees array : "); + for (i=0; i<ns; i++) printf("%d", LForder[0][i]); + printf("\n"); + printf(" "); + + for (i=0; i<ns; i++) printf("%d", LForder[1][i]); + printf("\n"); + */ + + /* SEQUENTIAL COLORING */ + if (color) free(color); + MYALLOC (int, color, ns); + for (i=0; i<ns; i++) color[i] = 0; /* clears the array color */ + color[LForder[0][ns-1]-1] = 1; + maxk = 1; /* maxk is the biggest colour assigned up to now */ + for (vi=ns-1; vi>0; vi--) /* loop on the nodes to be colored */ + { + mink = ns + 1; /* mink is the smallest colour assignable to vi */ + for (vj=0; vj < ns; vj++) /* scan the colour array */ + { + if ( color[vj] != 0 ) + { + k = color[vj]; /* k is the color of node vj */ + /* vj is a colored node */ + i1 = 0; + flagadja = 1; + /* check whether color k has not been assigned to any node + adjacent to vi (iff flagadja = 1) */ + while ( i1 < ns & flagadja == 1 ) /* i1 scans the nodes */ + { /* adjacent to vi */ + if (is_in_set (GETSET (incograph, LForder[0][vi-1]-1), i1) && + color[i1] == k) + flagadja = 0; + i1++; + } + if ( flagadja == 1 ) /* colour k can be given to vi */ + { + if (mink > k ) mink = k; + } + } + } + /* when no old colour can be assigned to vi, a new one is given */ + if (mink != ns + 1) color[LForder[0][vi-1]-1] = mink; + else {maxk++; color[LForder[0][vi-1]-1] = maxk;} + } + colornum = maxk; + + /* + printf("\n"); + printf("*******************************\n"); + printf("The number of colors used is %d\n", colornum); + printf("Color array : "); + for (i=0; i<ns; i++) printf("%d", color[i]); + printf("\n"); + */ + + +} diff --git a/sred/comp.c b/sred/comp.c new file mode 100644 index 0000000..3ed22d4 --- /dev/null +++ b/sred/comp.c @@ -0,0 +1,34 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/comp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +comp(vert,adjacency,pSUBCOMP) +int vert; +pset_family adjacency; +SUBCOMP *pSUBCOMP; + +/* Assigns the nodes of the adjacency graph to its connected components - + called by the routine connected */ + +{ + +int k; + +pSUBCOMP->compnum[vert] = pSUBCOMP->cmpnum; + +for (k=0; k<ns; k++) +{ + if (is_in_set (GETSET (adjacency, vert), k)) + { + if (pSUBCOMP->compnum[k] == 0) comp(k,adjacency,pSUBCOMP); + } +} + +} diff --git a/sred/connected.c b/sred/connected.c new file mode 100644 index 0000000..123e5fb --- /dev/null +++ b/sred/connected.c @@ -0,0 +1,54 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/connected.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +connected(adjacency,pSUBCOMP) +pset_family adjacency; +SUBCOMP *pSUBCOMP; + +{ + /* The structure SUBCOMP includes compnum and cmpnum : + the array compnum stores the connected components of the graph + the integer cmpnum gives the number of connected components - + compnum[i]=j iff node i+1 belongs to the j-th component of the graph */ + +int i; + +/* clears the array compnum */ +if (pSUBCOMP->compnum) free(pSUBCOMP->compnum); +MYALLOC (int, pSUBCOMP->compnum, ns); +for (i=0; i<ns; i++) + pSUBCOMP->compnum[i] = 0; + +pSUBCOMP->cmpnum = 0; + + +/* finds a new connected component calling the subroutine comp */ +for (i=0; i<ns; i++) +{ + if (pSUBCOMP->compnum[i] == 0) + { + pSUBCOMP->cmpnum++; + comp(i,adjacency,pSUBCOMP); + } +} + +/* +printf("\n"); +printf("************************************\n"); +printf("The graph has %d connected components\n",pSUBCOMP->cmpnum); +printf("Connected components array\n"); +for (i=0; i<ns; i++) + printf("%d",pSUBCOMP->compnum[i]); +printf("\n"); +*/ + +} + diff --git a/sred/esp_color.c b/sred/esp_color.c new file mode 100644 index 0000000..eecf908 --- /dev/null +++ b/sred/esp_color.c @@ -0,0 +1,123 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/esp_color.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +pset_family +expand_and_cover (F, R) +pset_family F, R; +{ + pset p, old_p; + int i, old_i; + pset_family old_F; + sm_matrix *matrix; + sm_row *cover; + sm_element *el; + + old_F = sf_save (F); + F = expand (F, R, /*nonsparse*/ 0); + + matrix = sm_alloc (); + foreachi_set (old_F, old_i, old_p) { + foreachi_set (F, i, p) { + if (setp_implies (old_p, p)) { + sm_insert (matrix, old_i, i); + } + } + } + cover = sm_minimum_cover (matrix, NIL(int), /*heuristic*/ 0, /*debug*/ 0); + + /* now copy back in F only cubes in the minimum cover */ + sf_free (old_F); + old_F = F; + F = sf_new (cover->length, old_F->sf_size); + sm_foreach_row_element (cover, el) { + p = GETSET (old_F, el->col_num); + sf_addset (F, p); + } + + return F; +} + +espresso_coloring () + +/* Colors the connected components of the incompatibles graph */ + +{ + int i, j; + pset_family F, D, R, new_F; + pset p; + + cube.num_vars = ns; + cube.num_binary_vars = ns; + MYALLOC (int, cube.part_size, ns); + cube_setup (); + + F = sf_new (0, 2 * ns); + R = sf_new (0, 2 * ns); + p = set_new (2 * ns); + + for (j=0; j<ns; j++) { + PUTINPUT (p, j, ZERO); + } + + for (i=0; i<ns; i++) { + PUTINPUT (p, i, ONE); + sf_addset (F, p); + PUTINPUT (p, i, ZERO); + } + + for (i=0; i<ns; i++) { + for (j=0; j<ns; j++) { + if (is_in_set (GETSET (incograph, i), j)) { + PUTINPUT (p, i, ONE); + PUTINPUT (p, j, ONE); + sf_addset (R, p); + PUTINPUT (p, i, ZERO); + PUTINPUT (p, j, ZERO); + } + } + } + + F = sf_contain (F); + R = sf_contain (R); + if (! strcmp (coloring_algo, "espresso")) { + D = complement (cube2list (F, R)); + F = espresso (F, D, R); + sf_free (D); + } + else if (! strcmp (coloring_algo, "espresso_exact")) { + D = complement (cube2list (F, R)); + F = minimize_exact (F, D, R, TRUE); + sf_free (D); + } + else if (! strcmp (coloring_algo, "expand_and_cover")) { + F = expand_and_cover (F, R); + } + else { + fprintf (stderr, "invalid coloring algorithm: %s\n", coloring_algo); + exit(1); + } + + if (color) free(color); + MYALLOC (int, color, ns); + for (i=0; i<ns; i++) color[i] = 0; + foreachi_set (F, i, p) { + for (j = 0; j < ns; j++) { + if (GETINPUT (p, j) != ZERO) { + color[j] = i + 1; + } + } + } + + sf_free (F); + sf_free (R); + set_free (p); +} + diff --git a/sred/exist.c b/sred/exist.c new file mode 100644 index 0000000..1afbc27 --- /dev/null +++ b/sred/exist.c @@ -0,0 +1,42 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/exist.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +exist(chain,class,pCHAINS) +int chain; +pset class; +CHAINS *pCHAINS; + +{ + + /* checks whether "class" is already included in "chain" */ + + int found,ident,startchain; + int i,j; + + /* startchain points to the beginning of the current chain + in the array implied */ + startchain = 0; + for(i=0; i<chain; i++) startchain += pCHAINS->weight[i]; + + i = 0; + found = 0; + while ( i < pCHAINS->weight[chain] && found == 0 ) + { + j=0; + if (setp_implies (class, GETSET (pCHAINS->implied, startchain + i))) { + found = 1; + } + i++; + } + + return(found); + +} diff --git a/sred/existdf.c b/sred/existdf.c new file mode 100644 index 0000000..34866b6 --- /dev/null +++ b/sred/existdf.c @@ -0,0 +1,29 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/existdf.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +existdf(class,chain) +pset class; +pset_family chain; + +{ + /* checks whether "class" is already included in "chain" */ + + pset p; + int found,ident; + int i,j; + + foreachi_set (chain, i, p) { + if (setp_implies (class, p)) { + return 1; + } + } + return 0; +} diff --git a/sred/generate.c b/sred/generate.c new file mode 100644 index 0000000..2f05586 --- /dev/null +++ b/sred/generate.c @@ -0,0 +1,43 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/generate.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +generate(chain,genclass,ingresso,class,pCHAINS) +int chain,genclass,ingresso; +pset class; +CHAINS *pCHAINS; + +{ + +/* compute the closure of the class implied[pointer] */ + +int i,pointer; + +/* pointer gives the absolute address of the current generating class + "genclass" of the chain "chain" in the array pCHAINS->implied */ +pointer = 0; +for (i=0; i<chain; i++) pointer += pCHAINS->weight[i]; +pointer += genclass-1; +/*printf("absolute address of the current generating class = %d\n", pointer);*/ + +set_clear (class, ns); + +for (i=0; i<np; i++) /* loop on the symbolic product terms */ +{ + if (itable[i].ilab-1 == ingresso) + { + if (is_in_set (GETSET(pCHAINS->implied, pointer), itable[i].plab-1) && + itable[i].nlab != 0) + set_insert (class, itable[i].nlab-1); + } +} + + +} diff --git a/sred/gram.c b/sred/gram.c new file mode 100644 index 0000000..818f019 --- /dev/null +++ b/sred/gram.c @@ -0,0 +1,1191 @@ +/* A Bison parser, made from gram.y + by GNU bison 1.35. */ + +#define YYBISON 1 /* Identify Bison output. */ + +# define DOT_I 257 +# define DOT_O 258 +# define DOT_S 259 +# define DOT_R 260 +# define DOT_P 261 +# define DOT_E 262 +# define NAME 263 +# define CUBE 264 +# define NUM 265 + +#line 1 "gram.y" + +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/gram.y,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/14 02:46:10 $ + * + */ +#include "reductio.h" +extern char yytext[]; +#ifndef YYSTYPE +# define YYSTYPE int +# define YYSTYPE_IS_TRIVIAL 1 +#endif +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + + +#define YYFINAL 39 +#define YYFLAG -32768 +#define YYNTBASE 12 + +/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ +#define YYTRANSLATE(x) ((unsigned)(x) <= 265 ? yytranslate[x] : 28) + +/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ +static const char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, + 6, 7, 8, 9, 10, 11 +}; + +#if YYDEBUG +static const short yyprhs[] = +{ + 0, 0, 1, 6, 8, 11, 13, 15, 17, 19, + 21, 23, 26, 29, 32, 35, 38, 41, 44, 47, + 50, 53, 55, 56, 61, 63, 65, 67 +}; +static const short yyrhs[] = +{ + -1, 14, 13, 16, 22, 0, 15, 0, 14, 15, + 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, + 0, 23, 0, 16, 23, 0, 3, 11, 0, 3, + 10, 0, 4, 11, 0, 4, 10, 0, 6, 9, + 0, 5, 11, 0, 5, 10, 0, 7, 11, 0, + 7, 10, 0, 8, 0, 0, 24, 26, 27, 25, + 0, 10, 0, 10, 0, 9, 0, 9, 0 +}; + +#endif + +#if YYDEBUG +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const short yyrline[] = +{ + 0, 21, 21, 28, 29, 32, 33, 34, 35, 36, + 39, 40, 43, 47, 53, 57, 63, 69, 70, 73, + 74, 77, 78, 81, 87, 93, 99, 105 +}; +#endif + + +#if (YYDEBUG) || defined YYERROR_VERBOSE + +/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ +static const char *const yytname[] = +{ + "$", "error", "$undefined.", "DOT_I", "DOT_O", "DOT_S", "DOT_R", "DOT_P", + "DOT_E", "NAME", "CUBE", "NUM", "fsm", "@1", "dots", "dot", "table", + "dot_i", "dot_o", "dot_r", "dot_s", "dot_p", "dot_e", "line", "input", + "output", "state", "next", 0 +}; +#endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const short yyr1[] = +{ + 0, 13, 12, 14, 14, 15, 15, 15, 15, 15, + 16, 16, 17, 17, 18, 18, 19, 20, 20, 21, + 21, 22, 22, 23, 24, 25, 26, 27 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const short yyr2[] = +{ + 0, 0, 4, 1, 2, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 1, 0, 4, 1, 1, 1, 1 +}; + +/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ +static const short yydefact[] = +{ + 0, 0, 0, 0, 0, 0, 1, 3, 5, 6, + 7, 8, 9, 13, 12, 15, 14, 18, 17, 16, + 20, 19, 0, 4, 24, 22, 10, 0, 21, 2, + 11, 26, 0, 27, 0, 25, 23, 0, 0, 0 +}; + +static const short yydefgoto[] = +{ + 37, 22, 6, 7, 25, 8, 9, 10, 11, 12, + 29, 26, 27, 36, 32, 34 +}; + +static const short yypact[] = +{ + -3, -1, 1, 3, -4, 5, -3,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768, 7,-32768,-32768, -2,-32768, 9,-32768,-32768, + -32768,-32768, 10,-32768, 11,-32768,-32768, 20, 22,-32768 +}; + +static const short yypgoto[] = +{ + -32768,-32768,-32768, 17,-32768,-32768,-32768,-32768,-32768,-32768, + -32768, -18,-32768,-32768,-32768,-32768 +}; + + +#define YYLAST 23 + + +static const short yytable[] = +{ + 1, 2, 3, 4, 5, 19, 28, 30, 24, 13, + 14, 15, 16, 17, 18, 20, 21, 24, 31, 33, + 38, 35, 39, 23 +}; + +static const short yycheck[] = +{ + 3, 4, 5, 6, 7, 9, 8, 25, 10, 10, + 11, 10, 11, 10, 11, 10, 11, 10, 9, 9, + 0, 10, 0, 6 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/share/bison/bison.simple" + +/* Skeleton output parser for bison, + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software + Foundation, Inc. + + 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, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser when + the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; +# if YYLSP_NEEDED + YYLTYPE yyls; +# endif +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# if YYLSP_NEEDED +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAX) +# else +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAX) +# endif + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up"); \ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). + + When YYLLOC_DEFAULT is run, CURRENT is set the location of the + first token. By default, to implement support for ranges, extend + its range to the last symbol. */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#if YYPURE +# if YYLSP_NEEDED +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval, &yylloc) +# endif +# else /* !YYLSP_NEEDED */ +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval) +# endif +# endif /* !YYLSP_NEEDED */ +#else /* !YYPURE */ +# define YYLEX yylex () +#endif /* !YYPURE */ + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +#endif /* !YYDEBUG */ + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +#ifdef YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif +#endif + +#line 315 "/usr/share/bison/bison.simple" + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +# define YYPARSE_PARAM_DECL +# else +# define YYPARSE_PARAM_ARG YYPARSE_PARAM +# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +# endif +#else /* !YYPARSE_PARAM */ +# define YYPARSE_PARAM_ARG +# define YYPARSE_PARAM_DECL +#endif /* !YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +# ifdef YYPARSE_PARAM +int yyparse (void *); +# else +int yyparse (void); +# endif +#endif + +/* YY_DECL_VARIABLES -- depending whether we use a pure parser, + variables are global, or local to YYPARSE. */ + +#define YY_DECL_NON_LSP_VARIABLES \ +/* The lookahead symbol. */ \ +int yychar; \ + \ +/* The semantic value of the lookahead symbol. */ \ +YYSTYPE yylval; \ + \ +/* Number of parse errors so far. */ \ +int yynerrs; + +#if YYLSP_NEEDED +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES \ + \ +/* Location data for the lookahead symbol. */ \ +YYLTYPE yylloc; +#else +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES +#endif + + +/* If nonreentrant, generate the variables here. */ + +#if !YYPURE +YY_DECL_VARIABLES +#endif /* !YYPURE */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + /* If reentrant, generate the variables here. */ +#if YYPURE + YY_DECL_VARIABLES +#endif /* !YYPURE */ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yychar1 = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + +#if YYLSP_NEEDED + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; +#endif + +#if YYLSP_NEEDED +# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +# define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + YYSIZE_T yystacksize = YYINITDEPTH; + + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; +#if YYLSP_NEEDED + YYLTYPE yyloc; +#endif + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; +#if YYLSP_NEEDED + yylsp = yyls; +#endif + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. */ +# if YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + yyls = yyls1; +# else + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); +# endif + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + goto yyoverflowlab; + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); +# if YYLSP_NEEDED + YYSTACK_RELOCATE (yyls); +# endif +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; +#if YYLSP_NEEDED + yylsp = yyls + yysize - 1; +#endif + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yychar1 = YYTRANSLATE (yychar); + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables + which are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + YYFPRINTF (stderr, "Next token is %d (%s", + yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise + meaning of a token, for further debugging info. */ +# ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +# endif + YYFPRINTF (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %d (%s), ", + yychar, yytname[yychar1])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to the semantic value of + the lookahead token. This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + +#if YYLSP_NEEDED + /* Similarly for the default location. Let the user run additional + commands if for instance locations are ranges. */ + yyloc = yylsp[1-yylen]; + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); +#endif + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables which + are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + int yyi; + + YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) + YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); + YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + switch (yyn) { + +case 1: +#line 22 "gram.y" +{ + type = MEALY; + } + break; +case 12: +#line 44 "gram.y" +{ + nis = atoi (yytext); + } + break; +case 13: +#line 48 "gram.y" +{ + nis = atoi (yytext); + } + break; +case 14: +#line 54 "gram.y" +{ + nos = atoi (yytext); + } + break; +case 15: +#line 58 "gram.y" +{ + nos = atoi (yytext); + } + break; +case 16: +#line 64 "gram.y" +{ + strcpy (startstate, yytext); + } + break; +case 23: +#line 82 "gram.y" +{ + mealy (); + } + break; +case 24: +#line 88 "gram.y" +{ + strcpy (lastin, yytext); + } + break; +case 25: +#line 94 "gram.y" +{ + strcpy (lastout, yytext); + } + break; +case 26: +#line 100 "gram.y" +{ + strcpy (laststate, yytext); + } + break; +case 27: +#line 106 "gram.y" +{ + strcpy (lastnext, yytext); + } + break; +} + +#line 705 "/usr/share/bison/bison.simple" + + + yyvsp -= yylen; + yyssp -= yylen; +#if YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; +#if YYLSP_NEEDED + *++yylsp = yyloc; +#endif + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("parse error, unexpected ") + 1; + yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "parse error, unexpected "); + yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("parse error; also virtual memory exhausted"); + } + else +#endif /* defined (YYERROR_VERBOSE) */ + yyerror ("parse error"); + } + goto yyerrlab1; + + +/*--------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action | +`--------------------------------------------------*/ +yyerrlab1: + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + YYDPRINTF ((stderr, "Discarding token %d (%s).\n", + yychar, yytname[yychar1])); + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + + +/*-------------------------------------------------------------------. +| yyerrdefault -- current state does not do anything special for the | +| error token. | +`-------------------------------------------------------------------*/ +yyerrdefault: +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + + /* If its default is to accept any token, ok. Otherwise pop it. */ + yyn = yydefact[yystate]; + if (yyn) + goto yydefault; +#endif + + +/*---------------------------------------------------------------. +| yyerrpop -- pop the current state because it cannot handle the | +| error token | +`---------------------------------------------------------------*/ +yyerrpop: + if (yyssp == yyss) + YYABORT; + yyvsp--; + yystate = *--yyssp; +#if YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "Error: state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + +/*--------------. +| yyerrhandle. | +`--------------*/ +yyerrhandle: + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +/*---------------------------------------------. +| yyoverflowab -- parser overflow comes here. | +`---------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} +#line 111 "gram.y" diff --git a/sred/gram.h b/sred/gram.h new file mode 100644 index 0000000..0e0a79c --- /dev/null +++ b/sred/gram.h @@ -0,0 +1,21 @@ +#ifndef BISON_GRAM_H +# define BISON_GRAM_H + +# ifndef YYSTYPE +# define YYSTYPE int +# define YYSTYPE_IS_TRIVIAL 1 +# endif +# define DOT_I 257 +# define DOT_O 258 +# define DOT_S 259 +# define DOT_R 260 +# define DOT_P 261 +# define DOT_E 262 +# define NAME 263 +# define CUBE 264 +# define NUM 265 + + +extern YYSTYPE yylval; + +#endif /* not BISON_GRAM_H */ diff --git a/sred/gram.y b/sred/gram.y new file mode 100644 index 0000000..60eec28 --- /dev/null +++ b/sred/gram.y @@ -0,0 +1,110 @@ +%{ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/gram.y,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/14 02:46:10 $ + * + */ +#include "reductio.h" +extern char yytext[]; +%} + +%start fsm + +%token DOT_I DOT_O DOT_S DOT_R DOT_P DOT_E NAME CUBE NUM + +%% + +fsm : dots + { + type = MEALY; + } + table dot_e + ; + +dots : dot + | dots dot + ; + +dot : dot_i + | dot_o + | dot_r + | dot_s + | dot_p + ; + +table : line + | table line + ; + +dot_i : DOT_I NUM + { + nis = atoi (yytext); + } + | DOT_I CUBE + { + nis = atoi (yytext); + } + ; + +dot_o : DOT_O NUM + { + nos = atoi (yytext); + } + | DOT_O CUBE + { + nos = atoi (yytext); + } + ; + +dot_r : DOT_R NAME + { + strcpy (startstate, yytext); + } + ; + +dot_s : DOT_S NUM + | DOT_S CUBE + ; + +dot_p : DOT_P NUM + | DOT_P CUBE + ; + +dot_e : DOT_E + | + ; + +line : input state next output + { + mealy (); + } + ; + +input : CUBE + { + strcpy (lastin, yytext); + } + ; + +output : CUBE + { + strcpy (lastout, yytext); + } + ; + +state : NAME + { + strcpy (laststate, yytext); + } + ; + +next : NAME + { + strcpy (lastnext, yytext); + } + ; + diff --git a/sred/ibincompa.c b/sred/ibincompa.c new file mode 100644 index 0000000..b397042 --- /dev/null +++ b/sred/ibincompa.c @@ -0,0 +1,86 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/ibincompa.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ + +#include "reductio.h" + +ibincompa() + + /* GENERATES ALL INCOMPATIBLE PAIRS OF STATES +incograph[i][j]=1 iff (si,sj) is an in incompatible pair of states +incograph[i][j]=0 otherwise +incograph is symmetric */ + +{ + +int i,j,newpair; +pset tmp; + +/* CLEARS THE ARRAY incograph */ +tmp = set_new (ns); +incograph = sf_new (ns, ns); +for (i=0; i<ns; i++) +{ + sf_addset (incograph, tmp); +} +set_free (tmp); + +/* FINDS ALL OUTPUT INCOMPATIBLE PAIRS */ +for (i=0; i<np; i++) +{ + for (j=0; j<i; j++) + { + if (boolcmp(itable[i].input,itable[j].input) == 0) + { + if (strbar(itable[i].output) !=1 && + strbar(itable[j].output) !=1 && + strcmp(itable[i].output,itable[j].output) != 0) + { + set_insert (GETSET (incograph, itable[i].plab-1), itable[j].plab-1); + set_insert (GETSET (incograph, itable[j].plab-1), itable[i].plab-1); + } + } + } +} + + +/* FINDS ALL INCOMPATIBLE PAIRS OF STATES IMPLYING THE OUTPUT + INCOMPATIBLE PAIRS */ +newpair = 1; +while (newpair == 1) +{ + newpair = 0; + for (i=0; i<np; i++) + { + for (j=0; j<i; j++) + { + if (boolcmp(itable[i].input,itable[j].input) == 0) + { + if (is_in_set (GETSET (incograph, itable[i].nlab-1), itable[j].nlab-1)) + { + if (! is_in_set (GETSET (incograph, itable[i].plab-1), + itable[j].plab-1)) + { + set_insert (GETSET(incograph, itable[i].plab-1), itable[j].plab-1); + set_insert (GETSET(incograph, itable[j].plab-1), itable[i].plab-1); + newpair = 1; + } + } + } + } + } +} + + + +connected(incograph,&incocomp); + + + +} diff --git a/sred/incompat.c b/sred/incompat.c new file mode 100644 index 0000000..9339cbc --- /dev/null +++ b/sred/incompat.c @@ -0,0 +1,85 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/incompat.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +incompat() + + /* GENERATES ALL INCOMPATIBLE PAIRS OF STATES +incograph[i][j]=1 iff (si,sj) is an in incompatible pair of states +incograph[i][j]=0 otherwise +incograph is symmetric */ + +{ + +int i,j,newpair; +pset tmp; + +/* CLEARS THE ARRAY incograph */ +tmp = set_new (ns); +incograph = sf_new (ns, ns); +for (i=0; i<ns; i++) +{ + sf_addset (incograph, tmp); +} +set_free (tmp); + +/* FINDS ALL OUTPUT INCOMPATIBLE PAIRS */ +for (i=0; i<np; i++) +{ + for (j=0; j<i; j++) + { + if (strcmp(itable[i].input,itable[j].input) == 0) + { + if (strbar(itable[i].output) !=1 && + strbar(itable[j].output) !=1 && + strcmp(itable[i].output,itable[j].output) != 0) + { + set_insert (GETSET(incograph, itable[i].plab-1), itable[j].plab-1); + set_insert (GETSET(incograph, itable[j].plab-1), itable[i].plab-1); + } + } + } +} + + +/* FINDS ALL INCOMPATIBLE PAIRS OF STATES IMPLYING THE OUTPUT + INCOMPATIBLE PAIRS */ +newpair = 1; +while (newpair == 1) +{ + newpair = 0; + for (i=0; i<np; i++) + { + for (j=0; j<i; j++) + { + if (strcmp(itable[i].input,itable[j].input) == 0) + { + if (is_in_set (GETSET(incograph, itable[i].nlab-1), itable[j].nlab-1)) + { + if (! is_in_set (GETSET(incograph, itable[i].plab-1), + itable[j].plab-1)) + { + set_insert (GETSET(incograph, itable[i].plab-1), itable[j].plab-1); + set_insert (GETSET(incograph, itable[j].plab-1), itable[i].plab-1); + newpair = 1; + } + } + } + } + } +} + + + +connected(incograph,&incocomp); + + + +} diff --git a/sred/iobincomp.c b/sred/iobincomp.c new file mode 100644 index 0000000..6247717 --- /dev/null +++ b/sred/iobincomp.c @@ -0,0 +1,87 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/iobincomp.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ + + +#include "reductio.h" + +iobincomp() + + /* GENERATES ALL INCOMPATIBLE PAIRS OF STATES +incograph[i][j]=1 iff (si,sj) is an in incompatible pair of states +incograph[i][j]=0 otherwise +incograph is symmetric */ + +{ + +int i,j,newpair; +pset tmp; + +/* CLEARS THE ARRAY incograph */ +tmp = set_new (ns); +incograph = sf_new (ns, ns); +for (i=0; i<ns; i++) +{ + sf_addset (incograph, tmp); +} +set_free (tmp); + +/* FINDS ALL OUTPUT INCOMPATIBLE PAIRS */ +for (i=0; i<np; i++) +{ + for (j=0; j<i; j++) + { + if (boolcmp(itable[i].input,itable[j].input) == 0) + { + if (strbar(itable[i].output) !=1 && + strbar(itable[j].output) !=1 && + boolcmp(itable[i].output,itable[j].output) != 0) + { + set_insert (GETSET(incograph, itable[i].plab-1), itable[j].plab-1); + set_insert (GETSET(incograph, itable[j].plab-1), itable[i].plab-1); + } + } + } +} + + +/* FINDS ALL INCOMPATIBLE PAIRS OF STATES IMPLYING THE OUTPUT + INCOMPATIBLE PAIRS */ +newpair = 1; +while (newpair == 1) +{ + newpair = 0; + for (i=0; i<np; i++) + { + for (j=0; j<i; j++) + { + if (boolcmp(itable[i].input,itable[j].input) == 0) + { + if (is_in_set (GETSET(incograph, itable[i].nlab-1), itable[j].nlab-1)) + { + if (! is_in_set (GETSET(incograph, itable[i].plab-1), + itable[j].plab-1)) + { + set_insert (GETSET(incograph, itable[i].plab-1), itable[j].plab-1); + set_insert (GETSET(incograph, itable[j].plab-1), itable[i].plab-1); + newpair = 1; + } + } + } + } + } +} + + + +connected(incograph,&incocomp); + + + +} diff --git a/sred/label.c b/sred/label.c new file mode 100644 index 0000000..954c8d1 --- /dev/null +++ b/sred/label.c @@ -0,0 +1,126 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/label.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "reductio.h" + +label() +{ + +/* gives a label to every state , symbolic input and symbolic output */ + +int i,j,k; + +/* +printf("\n"); +printf("**************************\n"); +printf("LABELING\n"); +*/ + +/* gives a label to every present state */ +for (k=0; k<np; k++) +{ + if (strcmp(itable[k].pstate , ASTER) == 0) continue; + + for (j=0; j<k; j++) + { + if (strcmp(itable[k].pstate , itable[j].pstate) == 0) + { + itable[k].plab = itable[j].plab; + goto contin1; + } + } + + ns++; + itable[k].plab = ns; + MYREALLOC (char*, slab, slab_size, ns - 1); + slab[ns-1] = itable[k].pstate; + /*printf("The state %s is labelled %d\n", itable[k].pstate , ns);*/ + contin1: ; +} + +/* gives a label to every next state not yet appeared as a present state */ +for (k=0; k<np; k++) +{ + if (strcmp(itable[k].nstate , ASTER) == 0) continue; + + for (j=0; j<np; j++) + { + if (strcmp(itable[k].nstate , itable[j].pstate) == 0) + { + itable[k].nlab = itable[j].plab; + goto contin2; + } + } + + for (j=0; j<k; j++) + { + if (strcmp(itable[k].nstate , itable[j].nstate)==0) + { + itable[k].nlab = itable[j].nlab; + goto contin2; + } + } + + ns++ ; + itable[k].nlab = ns; + /*printf("The state %s is labelled %d\n", itable[k].nstate , ns);*/ + contin2: ; +} + + +/* gives a label to every symbolic input */ +if (isymb) +{ + ni = 0; + for (k=0; k<np; k++) + { + if (strcmp(itable[k].input , ASTER)==0) continue; + + for (j=0; j<k; j++) + { + if (strcmp(itable[k].input , itable[j].input)==0) + { + itable[k].ilab = itable[j].ilab; + goto contin3; + } + } + + ni++ ; + itable[k].ilab = ni; + /*printf("The input %s is labelled %d\n", itable[k].input , ni);*/ + contin3: ; + } +} + + +/* gives a label to every symbolic output */ +if (osymb) +{ + no = 0; + for (k=0; k<np; k++) + { + if (strcmp(itable[k].output , ASTER) == 0) continue; + + for (j=0; j<k; j++) + { + if (strcmp(itable[k].output , itable[j].output) == 0) + { + itable[k].olab = itable[j].olab; + goto contin4; + } + } + + no++ ; + itable[k].olab = no; + /*printf("The output %s is labelled %d\n", itable[k].output , no);*/ + contin4: ; + } +} + +} diff --git a/sred/lex.c b/sred/lex.c new file mode 100644 index 0000000..8546742 --- /dev/null +++ b/sred/lex.c @@ -0,0 +1,1599 @@ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include <stdio.h> +#include <unistd.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include <io.h> +#include <stdlib.h> +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 12 +#define YY_END_OF_BUFFER 13 +static yyconst short int yy_accept[23] = + { 0, + 0, 0, 13, 11, 10, 10, 8, 11, 8, 9, + 7, 8, 6, 1, 2, 5, 4, 3, 8, 9, + 7, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4, 5, 1, 6, 6, 7, + 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, + 1, 1, 1, 1, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 1, 1, 1, 1, 9, 1, 8, 8, 8, 8, + + 10, 8, 8, 8, 11, 8, 8, 8, 8, 8, + 12, 13, 8, 14, 15, 8, 8, 8, 8, 8, + 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[16] = + { 0, + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2 + } ; + +static yyconst short int yy_base[24] = + { 0, + 0, 0, 26, 36, 36, 36, 12, 9, 21, 23, + 0, 27, 36, 36, 36, 36, 36, 36, 0, 28, + 0, 36, 15 + } ; + +static yyconst short int yy_def[24] = + { 0, + 22, 1, 22, 22, 22, 22, 22, 22, 22, 22, + 23, 22, 22, 22, 22, 22, 22, 22, 9, 22, + 23, 0, 22 + } ; + +static yyconst short int yy_nxt[52] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 4, 11, + 11, 11, 11, 11, 11, 12, 21, 12, 13, 14, + 15, 16, 17, 18, 12, 22, 19, 20, 20, 20, + 12, 22, 12, 20, 20, 3, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22 + } ; + +static yyconst short int yy_chk[52] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7, 23, 7, 8, 8, + 8, 8, 8, 8, 9, 3, 9, 9, 10, 10, + 12, 0, 12, 20, 20, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "lex.l" +#define INITIAL 0 +#line 2 "lex.l" +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/lex.l,v $ + * $Author: pchong $ + * $Revision: 1.4 $ + * $Date: 2004/03/14 05:02:39 $ + * + */ +#include "gram.h" +#ifdef getc +#undef getc +#endif +#define getc(file) mygetc(file) +#define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) | 0x20:(c)) +#line 396 "lex.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include <stdlib.h> +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp = NULL, *yy_bp = NULL; + register int yy_act; + +#line 18 "lex.l" + +#line 549 "lex.c" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 23 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 36 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 19 "lex.l" +{ + return DOT_I; +} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 23 "lex.l" +{ + return DOT_O; +} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 27 "lex.l" +{ + return DOT_S; +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 31 "lex.l" +{ + return DOT_R; +} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 35 "lex.l" +{ + return DOT_P; +} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 39 "lex.l" +{ + return DOT_E; +} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 43 "lex.l" +{ + return NAME; + } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 47 "lex.l" +{ + return CUBE; + } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 51 "lex.l" +{ + return NUM; + } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 55 "lex.l" +{ + /* ignore */ + } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 60 "lex.l" +{ + return yytext[0]; + } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 64 "lex.l" +ECHO; + YY_BREAK +#line 714 "lex.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 23 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 23 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 22); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 64 "lex.l" + +yywrap() +{ + return(1); +} diff --git a/sred/lex.l b/sred/lex.l new file mode 100644 index 0000000..ec4009e --- /dev/null +++ b/sred/lex.l @@ -0,0 +1,68 @@ +%{ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/lex.l,v $ + * $Author: pchong $ + * $Revision: 1.4 $ + * $Date: 2004/03/14 05:02:39 $ + * + */ +#include "gram.h" +#ifdef getc +#undef getc +#endif +#define getc(file) mygetc(file) +#define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) | 0x20:(c)) +%} +%% +\.i { + return DOT_I; +} + +\.o { + return DOT_O; +} + +\.s { + return DOT_S; +} + +\.r { + return DOT_R; +} + +\.p { + return DOT_P; +} + +\.e { + return DOT_E; +} + +[a-zA-Z][a-zA-Z0-9_]* { + return NAME; + } + +[01-]+ { + return CUBE; + } + +[0-9]+ { + return NUM; + } + +[\t\n ] { + /* ignore */ + } + + +[^ ] { + return yytext[0]; + } + +%% +yywrap() +{ + return(1); +} diff --git a/sred/main.c b/sred/main.c new file mode 100644 index 0000000..f770bb9 --- /dev/null +++ b/sred/main.c @@ -0,0 +1,61 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/main.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#define define_extern +#include "reductio.h" + + +main(argc,argv) +int argc; +char **argv; + +{ + /* INCOMPLETELY SPECIFIED + FINITE STATE MACHINES DECOMPOSITION + + Tiziano Villa + CSELT Labs - Torino (Italy) + + VERSION 1.0 + */ + + procargs (argc, argv); + + yyparse(); + if (errorcount) exit (1); + + label(); + + if (isymb && !osymb) obincompa(); + if (isymb && osymb) incompat(); + if (!isymb && !osymb) iobincomp(); + if (!isymb && osymb) ibincompa(); + + if (! strcmp (coloring_algo, "fast")) { + fast_coloring(); + } + else { + espresso_coloring (); + } + + mxcomptbl(); + + solution(); + + if (do_print_classes) { + print_classes (); + } + reduced(); + + makeout(); + + exit (0); +} + + diff --git a/sred/makeout.c b/sred/makeout.c new file mode 100644 index 0000000..8c49344 --- /dev/null +++ b/sred/makeout.c @@ -0,0 +1,40 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/makeout.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ + +#include <stdio.h> +#include "reductio.h" + +makeout() + +{ + register int state, j; + NAMETABLE *name; + + fprintf(stdout, ".i %d\n", nis); + fprintf(stdout, ".o %d\n", nos); + fprintf(stdout, ".s %d\n", copertura1->count); + + if (reset > 0) { + fprintf(stdout, ".r s%d\n", reset); + } + + for (j = 0; j < newnp; j++) { + fprintf (stdout, "%s ", itable[j].input); + + fprintf (stdout, "%s ", itable[j].pstate); + + fprintf (stdout, "%s ", itable[j].nstate); + + fprintf (stdout, "%s\n", itable[j].output); + } + + fprintf(stdout, ".e\n"); +} + diff --git a/sred/misc.c b/sred/misc.c new file mode 100644 index 0000000..570ae1d --- /dev/null +++ b/sred/misc.c @@ -0,0 +1,39 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/misc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:11 $ + * + */ +#include "espresso.h" + +/* sf_insert_set -- add a set in position "i" of a set family */ +pset_family sf_insert_set(A, i, s) +pset_family A; +int i; +pset s; +{ + register pset p; + register int j, old_count; + + while (i >= A->capacity) { + A->capacity = A->capacity + A->capacity/2 + 1; + A->data = REALLOC(unsigned int, A->data, (long) A->capacity * A->wsize); + } + if (i >= A->count) { + old_count = A->count; + A->count = i + 1; + for (j = old_count; j < i; j++) { + set_clear (GETSET (A, j), A->sf_size); + } + } + p = GETSET(A, i); + INLINEset_copy(p, s); + return A; +} + +VOVoutput () +{ +} diff --git a/sred/mxcomptbl.c b/sred/mxcomptbl.c new file mode 100644 index 0000000..1e0d962 --- /dev/null +++ b/sred/mxcomptbl.c @@ -0,0 +1,81 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/mxcomptbl.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +mxcomptbl() + +/* We expand the compatibles found by coloring ( i.e. the sets of nodes +with the same color ) until they become maximal */ + +{ +int i,j,k; +int flag; +pset tmp; + +if (debug > 0) { + fprintf (stderr, "incompatibility graph\n"); + for (i=0; i<ns; i++) + { + fprintf (stderr, "%s: ", slab[i]); + for (j=0; j<ns; j++) + { + if (is_in_set (GETSET (incograph, i), j)) { + fprintf (stderr, "%s ", slab[j]); + } + } + fprintf (stderr, "\n"); + } +} +/* clears maxcompatibles */ +if (maxcompatibles) sf_free (maxcompatibles); +tmp = set_new (ns); +maxcompatibles = sf_new (0, ns); +for (i=0; i<ns; i++) sf_insert_set (maxcompatibles, color[i]-1, tmp); +set_free (tmp); + +/* loop on the color array */ +for (i=0; i<ns; i++) set_insert (GETSET (maxcompatibles, color[i]-1), i); + +/* loop on the maxcompatibles matrix */ +for (i=0; i<colornum; i++) /* i is the color */ +{ + for (j=0; j<ns; j++) /* j is the state */ + { + if (! is_in_set (GETSET (maxcompatibles, i), j)) + { + k = 0; /* k is a node adjacent to j in incograph */ + flag = 1; + while (k < ns & flag == 1) + { + if (is_in_set (GETSET (incograph, j), k) && + is_in_set (GETSET (maxcompatibles, i), k)) + flag = 0 ; + k++; + } + if (flag == 1) set_insert (GETSET (maxcompatibles, i), j); + } + } +} + +if (debug > 0) { + fprintf (stderr, "max compatibles\n"); + for (i=0; i<colornum; i++) /* i is the color */ + { + fprintf (stderr, "%d: ", i); + for (j=0; j<ns; j++) /* j is the state */ + { + if (is_in_set (GETSET (maxcompatibles, i), j)) { + fprintf (stderr, "%s ", slab[j]); + } + } + fprintf (stderr, "\n"); + } +} +} diff --git a/sred/newnstate.c b/sred/newnstate.c new file mode 100644 index 0000000..5061a34 --- /dev/null +++ b/sred/newnstate.c @@ -0,0 +1,74 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/newnstate.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ + +#include "reductio.h" + +newresetstate(pclass) +int pclass; + +{ + int i; + + for(i=0; i<np; i++) + { + if ( strcmp(itable[i].pstate,startstate) == 0 ) + { + if ( is_in_set (GETSET(copertura1, pclass-1), itable[i].plab-1)) + { + return pclass; + } + } + } + return -1; +} + +newnstate(pclass,ingresso) +int pclass,ingresso; + +{ + /* finds the next-states class ( i.e. the next state in the reduced + machine ) evolving from "pclass" (the current state in the reduced + machine ) under input "ingresso" and returns its value */ + + int i,j,found,good,count,value; + pset nclass, p; + + nclass = set_new (ns); + + for(i=0; i<np; i++) + { + if ( strcmp(itable[i].input,itable[ingresso].input) == 0 ) + { + if ( is_in_set (GETSET(copertura1, pclass-1), itable[i].plab-1)) + { + if ( itable[i].nlab != 0 ) set_insert (nclass, itable[i].nlab-1); + } + } + } + + count = set_ord (nclass); + + if ( count > 0 ) + { + foreachi_set (copertura1, i, p) { + if (setp_implies (nclass, p)) { + break; + } + } + } + + if ( count == 0 ) value = -1; else value = i + 1; + + set_free (nclass); + + return(value); + +} + diff --git a/sred/newoutput.c b/sred/newoutput.c new file mode 100644 index 0000000..7b59020 --- /dev/null +++ b/sred/newoutput.c @@ -0,0 +1,41 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/newoutput.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ + + +#include "reductio.h" + +newoutput(pclass,ingresso) +int pclass,ingresso; + +{ + /* finds the output asserted from "pclass" (the current state in the reduced + machine ) under input "ingresso" and returns its value */ + + int i,proutput,index,value; + + i = 0; + proutput = 0; + while (i<np && proutput == 0 ) + { + if ( strcmp(itable[i].input,itable[ingresso].input) == 0 ) + { + if ( is_in_set (GETSET(copertura1, pclass-1), itable[i].plab-1)) + { + if ( strbar(itable[i].output) != 1 ) { proutput = 1; index = i; } + } + } + i++; + } + + if ( proutput == 0 ) value = -1; else value = index; + + return(value); + +} diff --git a/sred/newprime.c b/sred/newprime.c new file mode 100644 index 0000000..3984fd3 --- /dev/null +++ b/sred/newprime.c @@ -0,0 +1,37 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/newprime.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +newprime(genclass,subclass) +int genclass,subclass; + +{ + /* newprime = 1 iff the class (genclass, subclass) + does not already exist in the array primes[][] */ + + int i,j; + int found,new,ident; + pset class, p; + + class = set_new (ns); + /* compute class (genclass, subclass) */ + set_copy (class, GETSET (primes, genclass)); + set_remove (class, subclass); + + new = 1; + foreachi_set (primes, i, p) { + if (setp_equal (p, class)) { + new = 0; + break; + } + } + return(new); + +} diff --git a/sred/obincompa.c b/sred/obincompa.c new file mode 100644 index 0000000..61ff1a6 --- /dev/null +++ b/sred/obincompa.c @@ -0,0 +1,86 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/obincompa.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ + +#include "reductio.h" + +obincompa() + + /* GENERATES ALL INCOMPATIBLE PAIRS OF STATES +incograph[i][j]=1 iff (si,sj) is an in incompatible pair of states +incograph[i][j]=0 otherwise +incograph is symmetric */ + +{ + +int i,j,newpair; +pset tmp; + +/* CLEARS THE ARRAY incograph */ +tmp = set_new (ns); +incograph = sf_new (ns, ns); +for (i=0; i<ns; i++) +{ + sf_addset (incograph, tmp); +} +set_free (tmp); + +/* FINDS ALL OUTPUT INCOMPATIBLE PAIRS */ +for (i=0; i<np; i++) +{ + for (j=0; j<i; j++) + { + if (strcmp(itable[i].input,itable[j].input) == 0) + { + if (strbar(itable[i].output) !=1 && + strbar(itable[j].output) !=1 && + boolcmp(itable[i].output,itable[j].output) != 0) + { + set_insert (GETSET(incograph, itable[i].plab-1), itable[j].plab-1); + set_insert (GETSET(incograph, itable[j].plab-1), itable[i].plab-1); + } + } + } +} + + +/* FINDS ALL INCOMPATIBLE PAIRS OF STATES IMPLYING THE OUTPUT + INCOMPATIBLE PAIRS */ +newpair = 1; +while (newpair == 1) +{ + newpair = 0; + for (i=0; i<np; i++) + { + for (j=0; j<i; j++) + { + if (strcmp(itable[i].input,itable[j].input) == 0) + { + if (is_in_set (GETSET(incograph, itable[i].nlab-1), itable[j].nlab-1)) + { + if (! is_in_set (GETSET(incograph, itable[i].plab-1), + itable[j].plab-1)) + { + set_insert (GETSET(incograph, itable[i].plab-1), itable[j].plab-1); + set_insert (GETSET(incograph, itable[j].plab-1), itable[i].plab-1); + newpair = 1; + } + } + } + } + } +} + + + +connected(incograph,&incocomp); + + + +} diff --git a/sred/prime.c b/sred/prime.c new file mode 100644 index 0000000..94809fe --- /dev/null +++ b/sred/prime.c @@ -0,0 +1,77 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/prime.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +prime(genclass,subclass) +int genclass,subclass; + +{ + /* prime = 1 iff the class(genclass,subclass) is c-prime */ + + + /* Concept of prime class as established by Luccio et al. + ====================================================== + + Definition : class Cj is escluded by class Ci iff + 1) Cj is strictly contained in Ci + 2) and Pi ( classes generated by Ci ) is contained + (also not strictly) in Pj ( classes generated by Cj ) - + + A class is prime ( definition ) iff it is not escluded by any other + compatibility class - + + Primality needs to be tested only on the maximal compatibles + and the other prime classes ( transitivity's sake ) + + + Concept of c-prime class ( implemented in Pinima ) + ================================================== + + Definition : class Cj is escluded by class Ci iff + 1) Cj is strictly contained in Ci + 2) and Pi (implied chain without header) is contained + (also not strictly) in Pj (implied chain without header) - + + A c-prime is also prime , but not viceversa , i.e. + c-prime classes are a subset of prime classes - + + Unfortunately , in the current implementation , since we + don't generate all maximal compatibles and c-prime classes + ( to cut down the computation time we start from only one + covering set of maximal compatibles and at each refinement + step we generate only the c-primes thet can be obtained from + the previous c-prime generation ) + a class can be accepted as c-prime although it is neither prime + nor c-prime ( the dominating class has not been generated ) */ + + /* esclusa = 0 iff the j-subclass of the i-th class is c-prime , + i.e. is not escluded by any other (known) c-prime class */ + + int i; + int esclusa,notesclusa; + + /*printf("*** PRIME OF %d %d\n", genclass,subclass);*/ + + i = 0; + esclusa = 0; + while ( i < primes->count && esclusa == 0 ) + { + if ( cl_inclus(genclass,subclass,i)==1 && + ch_inclus(i,genclass,subclass)==1 ) + esclusa = 1; + i++; + } + + /* notesclusa means c-prime */ + if (esclusa == 1) notesclusa = 0; else notesclusa = 1; +/*printf("prime = %d\n", notesclusa);*/ + return(notesclusa); + +} diff --git a/sred/primeones.c b/sred/primeones.c new file mode 100644 index 0000000..b3aa142 --- /dev/null +++ b/sred/primeones.c @@ -0,0 +1,25 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/primeones.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +primeones(index) +int index; + +{ + /* Counts the number of states included in the class primes[index][] */ + + int i; + int value; + + value = set_ord (GETSET (primes, index)); + + return(value); + +} diff --git a/sred/procargs.c b/sred/procargs.c new file mode 100644 index 0000000..1634b12 --- /dev/null +++ b/sred/procargs.c @@ -0,0 +1,51 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/procargs.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/14 17:14:14 $ + * + */ +#include "reductio.h" + +#define max(a,b) (a>b?a:b) +#define min(a,b) (a<b?a:b) + +procargs(argc,argv) + +int argc; +char *argv[]; + +{ + char c; + + util_getopt_reset (); + do_print_classes = 0; + debug = 0; + coloring_algo = "fast"; + while ((c = util_getopt(argc, argv, "v:hca:")) != EOF) { + switch (c) { + case 'c': + do_print_classes = 1; + break; + case 'a': + coloring_algo = util_optarg; + break; + case 'v': + debug = atoi (util_optarg); + break; + case 'h': + default: + fprintf (stderr, "usage: %s [-c] [-a coloring_algorithm]\n", argv[0]); + fprintf (stderr, " -c: print out minimized state classes\n"); + fprintf (stderr, " -a: select the coloring algorithm among:\n"); + fprintf (stderr, " fast: a fast and greedy heuristics\n"); + fprintf (stderr, " espresso, expand_and_cover, espresso_exact:\n"); + fprintf (stderr, " use logic minimization (can be expensive)\n"); + exit (1); + break; + } + } +} + diff --git a/sred/qsort.c b/sred/qsort.c new file mode 100644 index 0000000..819b259 --- /dev/null +++ b/sred/qsort.c @@ -0,0 +1,36 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/qsort.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +myqsort(array,init,length) +int *array[2]; +int init; +int length; + +/* sort elements of array */ + +{ + int pivot; /* the pivot value */ + int pivotindex; /* the index of the pivot element of array */ + int k; /* beginning index for group of elements >= pivot */ + int i; + + + pivotindex = myqspivot(array,init,length); + if (pivotindex != 0) /* do nothing if array[init-1]=array[length-1] */ + { + pivot = array[1][pivotindex-1]; + k = myqspart(array,init,length,pivot); + myqsort(array,init,k-1); + myqsort(array,k,length); + } + + +} diff --git a/sred/qspart.c b/sred/qspart.c new file mode 100644 index 0000000..43d5e07 --- /dev/null +++ b/sred/qspart.c @@ -0,0 +1,45 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/qspart.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +myqspart(array,init,length,pivot) +int *array[2]; +int init; +int length; +int pivot; + +/* partitions array[init],...,array[length] so keys < pivot are at the left +and keys >= pivot are on the right . Returns the beginning of the group on +the right */ + +{ +int l,r; /* cursors used during the permutation process */ +int temp; + +l = init; +r = length; +while (l<=r) +{ + /* swap array[1][r-1] & array[1][l-1] */ + temp = array[1][r-1]; + array[1][r-1] = array[1][l-1]; + array[1][l-1] = temp; + /* swap array[0][r-1] & array[0][l-1] */ + temp = array[0][r-1]; + array[0][r-1] = array[0][l-1]; + array[0][l-1] = temp; + + /* Now the scan phase begins */ + while (array[1][l-1] < pivot) l++; + while (array[1][r-1] >= pivot) r--; +} +return(l); + +} diff --git a/sred/qspivot.c b/sred/qspivot.c new file mode 100644 index 0000000..cb50384 --- /dev/null +++ b/sred/qspivot.c @@ -0,0 +1,32 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/qspivot.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +myqspivot(array,init,length) +int *array[2]; +int init; +int length; + +/* returns 0 if array[init],...array[length] have identical keys, +otherwise the index of the larger of the leftmost two different keys */ + +{ +int k; /* runs left to right looking for a different key */ +int firstkey; /* value of first key found */ + +firstkey = array[1][init-1]; +for (k=init+1; k<length; k++) /* scan for different key */ +{ + if (array[1][k-1] > firstkey) return(k); /* select larger key */ + else if (array[1][k-1] < firstkey) return(init); +} +return(0); + +} diff --git a/sred/reduced.c b/sred/reduced.c new file mode 100644 index 0000000..6fe8feb --- /dev/null +++ b/sred/reduced.c @@ -0,0 +1,147 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/reduced.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +print_classes () +{ + int i,j; + pset p; + + fprintf(stdout, "#begin_classes %d\n", copertura1->count); + foreachi_set (copertura1, i, p) { + for (j=0; j<ns; j++) { + if (is_in_set (p, j)) { + fprintf(stdout, "# %s %d\n", slab[j], i); + } + } + } + fprintf(stdout, "#end_classes\n"); +} + + +reduced() + +{ + /* Builds the final reduced machine */ + + int i,j,k,l; + int ingresso,nxstate,redoutput; + pset scanned; + + scanned = set_new (np); + /* + printf("\n"); + printf("~~~~~~~~~~~~~~~ \n"); + printf("REDUCED MACHINE \n"); + printf("~~~~~~~~~~~~~~~ \n"); + */ + + reset = -1; + if (strlen (startstate) > 0) { + for (i=0; i<copertura1->count; i++) { + reset = newresetstate(i + 1); + if (reset > 0) { + break; + } + } + } + + l=0; + + /* loop on the states (covering classes) of the reduced machine */ + for (i=0; i<copertura1->count; i++) + { + /* "scanned" is cleared inside the outer loop because some states + appear in more than one class and so the row terms pertaining + to them must be considered again and again */ + set_clear (scanned, np); + + for (j=0; j<np; j++) + { + /* pick up the first row term not already dealt with and + containing a state of the current (i-th) class - + if it has not already been considered it must be because + its input part has not been yet considered together with that class */ + if ( is_in_set (GETSET(copertura1, i), itable[j].plab-1) && + !is_in_set (scanned, j)) + { + ingresso = j; /* we are now considering the input "ingresso" + /* all the states of the same class under the same input are + taken care of (as is meant by marking the "scanned" array) */ + for (k=j; k<np; k++) + if ( strcmp(itable[k].input,itable[ingresso].input) == 0 && + is_in_set (GETSET(copertura1, i), itable[k].plab-1) ) + set_insert (scanned, k); + + /* formation of a new row of the reduced machine */ + MYREALLOC (MINITABLE, mintable, mintable_size, l); + mintable[l].input = malloc(strlen(itable[ingresso].input)+1); + mintable[l].pstate = malloc(strlen(itable[ingresso].pstate)+5); + mintable[l].nstate = malloc(strlen(itable[ingresso].nstate)+5); + mintable[l].output = malloc(strlen(itable[ingresso].output)+5); + + /* INPUT */ + strcpy(mintable[l].input,itable[ingresso].input); + /*printf("%s",mintable[l].input);*/ + /* PRESENT STATE */ + sprintf( mintable[l].pstate, "s%d", i + 1 ); + /*printf("%s",mintable[l].pstate);*/ + /* NEXT STATE */ + nxstate = newnstate(i+1,ingresso); + if ( nxstate != -1 ) + sprintf( mintable[l].nstate, "s%d", nxstate ); + else + sprintf( mintable[l].nstate, "*" ); + /*printf("%s",mintable[l].nstate);*/ + /* OUTPUT */ + redoutput = newoutput(i+1,ingresso); + if ( redoutput != -1 ) + strcpy(mintable[l].output,itable[redoutput].output); + else + strcpy(mintable[l].output,itable[ingresso].output); + /*printf("%s\n",mintable[l].output);*/ + + l++; + + } + } + } + + newnp = l; /* the number of product terms is updated */ + + /*printf("Product terms of the reduced machine = %d\n", l);*/ + + /* The reduced machine table is copied back into "itable" */ + for (i=0; i<l; i++) + { + if ( i >= np ) + { + itable[i].input = malloc(strlen(mintable[i].input)+1); + itable[i].pstate = malloc(strlen(mintable[i].pstate)+1); + itable[i].nstate = malloc(strlen(mintable[i].nstate)+1); + itable[i].output = malloc(strlen(mintable[i].output)+1); + } + + strcpy(itable[i].input,mintable[i].input); + strcpy(itable[i].pstate,mintable[i].pstate); + strcpy(itable[i].nstate,mintable[i].nstate); + strcpy(itable[i].output,mintable[i].output); + + /*printf("%s",itable[i].input); + printf(" %s",itable[i].pstate); + printf(" %s",itable[i].nstate); + printf(" %s\n",itable[i].output); + */ + } + + + set_free(scanned); + +} diff --git a/sred/reductio.h b/sred/reductio.h new file mode 100644 index 0000000..45109f7 --- /dev/null +++ b/sred/reductio.h @@ -0,0 +1,169 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/reductio.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include <stdio.h> +#include "util.h" +#include "espresso.h" + +#ifdef define_extern +#define extern +#endif + +/* void * malloc (), * realloc (); */ +#define CHUNK 10 +#define MYREALLOC(type,name,size,num) do{ \ + while ((num) >= size) { \ + if (size == 0) { \ + size = CHUNK; \ + name = (type*) malloc (size * sizeof (*name)); \ + } \ + else { \ + size += CHUNK; \ + name = (type*) realloc (name, size * sizeof (*name)); \ + } \ + if (name == NULL) { \ + perror ("name"); \ + exit (1); \ + } \ + } \ +}while(0) + +#define MYCALLOC(type,name,size) do{ \ + name = (type*) calloc (size, sizeof (*name)); \ + if (name == NULL) { \ + perror ("name"); \ + exit (1); \ + } \ +}while(0) + +#define MYALLOC(type,name,size) do{ \ + name = (type*) malloc (size * sizeof (*name)); \ + if (name == NULL) { \ + perror ("name"); \ + exit (1); \ + } \ +}while(0) + + +#define MAXNAME 256 + +#define MOORE 0 +#define MEALY 1 + +#define ASTER "*" + +#define max(a,b) (a>b?a:b) +#define min(a,b) (a<b?a:b) + +typedef struct SYMTABLE { + char *symbol; + char *vector; + struct SYMTABLE *next; +} SYMTABLE; + +typedef struct NAMETABLE { + char *symbol; + char *wire; + struct NAMETABLE *next; +} NAMETABLE; + +typedef struct INPUTTABLE { + char *input; + int ilab; + char *pstate; + int plab; + char *nstate; + int nlab; + char *output; + int olab; +} INPUTTABLE; + +typedef struct CODETABLE { + int code; + int loc; +} CODETABLE; + +typedef struct LATTICE { + char *vector; + int weight; + int depth; + int type; +} LATTICE; + +extern int isymb, osymb; +extern int newnp, np, nis, ns, nos,ni,no; +extern int type; +extern int errorcount; +extern int yylineno, mylinepos; +extern int unspec; + +extern char identification[MAXNAME], startstate[MAXNAME]; +extern char myline[MAXNAME]; +extern char state[MAXNAME], in[MAXNAME], next[MAXNAME], out[MAXNAME]; + +extern char **slab; +extern int slab_size; + +extern char lastnum[MAXNAME], lastid[MAXNAME], lastvect[MAXNAME]; +extern char laststate[MAXNAME], lastin[MAXNAME], lastnext[MAXNAME]; +extern char lastout[MAXNAME]; + +extern SYMTABLE *inputlist, *statelist, *outputlist; + +extern NAMETABLE *nametable; + +extern INPUTTABLE *itable; +extern int itable_size; + +extern FILE *filin, *filout; + +/* VARIABLES RELATED TO FUNCTIONAL MINIMIZATION */ + +typedef struct SUBCOMP { + int *compnum; + int cmpnum; +} SUBCOMP; + +extern pset_family incograph; +extern SUBCOMP incocomp; +extern int *color; +extern int colornum; +extern pset_family maxcompatibles; + +extern pset_family primes; +extern int reset; + +typedef struct CHAINS { + pset_family implied; + int *weight; + int weight_size; + pset_family cover; +} CHAINS; + +extern CHAINS firstchain; + +extern pset_family copertura1, copertura2; + +typedef struct MINITABLE { + char *input; + char *pstate; + char *nstate; + char *output; +} MINITABLE; + +extern MINITABLE *mintable; +extern int mintable_size; + +extern int do_print_classes; +extern char *coloring_algo; + +int mygetc(); + + +pset_family chiusura(); diff --git a/sred/solution.c b/sred/solution.c new file mode 100644 index 0000000..b53e8d0 --- /dev/null +++ b/sred/solution.c @@ -0,0 +1,135 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/solution.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +solution() + +{ + +/* FINDS A MINIMAL CLOSED COVERING THROUGH AN ITERATIVE PROCESS + ( CREATING AT EACH STEP NEW C-PRIME COMPATIBLES ) */ + +int parity; /* parity = 1 iff "choose" is going to work on "copertura1", + parity = 2 iff "choose" is going to work on "copertura2" */ +int refin; /* refin = 1 iff a new refinement step is needed ( the current + criterion is to refine until there are c-prime classes with + at least two states in the last c-prime generation ) */ +int bound1,bound2; /* bound1 and bound2 point to the beginning and the end + of the last generation of c-primes in "primes" */ +int i,j,k; + +/* The maximal compatibles classes are copied at the beginning of "primes" */ +primes = sf_save (maxcompatibles); + + +/* Call closure on the maximal compatibles */ +/*printf("\n"); +printf("********************************************\n"); +printf("Closure is called on the maximal compatibles\n"); +*/ +closure(0,maxcompatibles->count); + +/* Choose a complete closed minimal covering from the current chains */ +parity = 1; +copertura1 = sf_new (0, ns); +copertura2 = sf_new (0, ns); +choose(parity); + +/* copertura1->count is the cardinality of the smallest covering found - + it represents the objective function to minimize */ + + +/* The iterative prime refinement procedure is computationally heavy + and needs an awful amount of available memory . It is better to use + it only for medium-sized machines ( up to 32 states ) . + A future revision of the program will try to improve it , in order + to cope in a sophisticated way with machines of arbitrary size */ + /* ITERATIVE PRIME REFINEMENT */ + + /* while there are still classes from which to extract c-primes, + i.e. classes with at least two states ( refin = 1 ) - + and the lower bound has not yet been reached */ + + /* + printf("\n"); + printf("=======================================\n"); + printf("We are in the iterative refinement loop\n"); + printf("=======================================\n"); + printf("\n"); + */ + + bound1 = 0; + bound2 = primes->count; + refin = 1; + while ( refin == 1 && copertura1->count > maxcompatibles->count ) + { + + /* The coming while controls the iteration of the refinement step */ + refin = 0; + i = bound1; + while ( i<bound2 & refin == 0 ) + { + /* "primeones" returns the # of classes in primes[i][] */ + if ( primeones(i) >= 2 ) refin = 1; + i++; + } + + /* extract new c-primes from the last c-prime generation ( when it + contains classes with at least two states ) */ + for (i=bound1; i<bound2; i++) + { + if ( primeones(i) >= 2 ) + { + /* examine all subsets with cardinality smaller of one + of the last c-prime generation */ + for (j=0; j<ns; j++) + { + /* j is the subclass index */ + /* if the j-th state is in the i-th c-prime */ + if ( is_in_set (GETSET(primes, i), j)) + { + /* if the current subclass is new and is c-prime + (the current subclass is primes[i][] with 0 in the j-th + position, i.e. without the j-th state) */ + if ( newprime(i,j) == 1 && prime(i,j) == 1 ) + { + /* add this c-prime subclass to the "primes" array */ + sf_addset (primes, GETSET (primes, i)); + set_remove (GETSET(primes, primes->count-1), j); + /* compute the implied chain of this new c-prime class */ + closure(primes->count-1,primes->count); + } + } + } + } + } + /* bound1 and bound2 are updated to the last c-prime generation */ + bound1 = bound2; + bound2 = primes->count; + + parity =2; + /* compute the covering from the new c-prime set */ + /* clears the last covering stored in copertura2 */ + sf_free (copertura2); + copertura2 = sf_new (0, ns); + if ( refin == 1 ) choose(parity); + /* the new covering is accepted only if it has a cardinality smaller + than the current solution */ + /* the solution covering is stored in copertura1 - the provisional + one is stored in copertura2 */ + if (copertura2->count > 0 && copertura2->count < copertura1->count) + { + sf_free(copertura1); + copertura1 = sf_save (copertura2); + } + } + + +} diff --git a/sred/sred.1 b/sred/sred.1 new file mode 100644 index 0000000..4a312b2 --- /dev/null +++ b/sred/sred.1 @@ -0,0 +1,41 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/sred/sred.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:11 $ +.\" * +.\" +.TH SRED SRED.0 "5/20/90" "U.C. Berkeley " \ +"State REDuction" +.SH NAME +sred \- heuristic state minimization of incompletely specified finite state machine +.SH SYNOPSIS +.B sred +[options] < inputfile [ > outputfile ] +.SH DESCRIPTION +\fBSRED\fP is a state minimization program. It provides very fast heuristic +minimization of large incompletely specified finite state machines using +coloring and iterative closure computations. +Both input and output file format is KISS2. + +.SH "OPTIONS" +.nf +-c: print out minimized state classes (used only for internal purposes + by the asynchronous state encoding algorithm) + +-a coloring_algorithm: fast: a fast and greedy heuristics (recommended) + espresso: a minimizer-based heuristic (can be very + slow) + expand_and_cover: same as above + espresso_exact: same as above + +-h: print out the command line options. +.fi + +.SH REMARKS +After minimization there may exist multiple reset states if there was a +reset state before minimization. Currently a reset state after minimization +is selected randomly. + diff --git a/sred/strbar.c b/sred/strbar.c new file mode 100644 index 0000000..6b3c450 --- /dev/null +++ b/sred/strbar.c @@ -0,0 +1,33 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/strbar.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +strbar(s) +char s[]; + +{ +/* returns 1 if s is a string of all '-' (bars , meaning don't care) */ +int i,allbar; + +i = 0; +if (osymb) { + allbar = !strcmp(s, ASTER); +} +else { + allbar = 1; + while (s[i] != '\0' && allbar == 1) + { + if (s[i] != '-') allbar = 0; + i++; + } +} +return(allbar); + +} diff --git a/sred/strcom.c b/sred/strcom.c new file mode 100644 index 0000000..3078b2d --- /dev/null +++ b/sred/strcom.c @@ -0,0 +1,28 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/sred/strcom.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:12 $ + * + */ +#include "reductio.h" + +strcom(s,t) +char s[], t[]; + +{ + +/* return <0 if s<t, 0 if s==t, >0 if s>t */ + +int i; + +i=0; + +while (s[i] == '-' || t[i] == '-' || s[i] == t[i]) + if (s[i++] == '\0') + return(0); +return(s[i] - t[i]); + +} diff --git a/stamina/Makefile.am b/stamina/Makefile.am new file mode 100644 index 0000000..7fedf3b --- /dev/null +++ b/stamina/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = hash mimi +dist_man1_MANS = stamina.1 diff --git a/stamina/Makefile.in b/stamina/Makefile.in new file mode 100644 index 0000000..abd2734 --- /dev/null +++ b/stamina/Makefile.in @@ -0,0 +1,480 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = stamina +DIST_COMMON = $(dist_man1_MANS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +depcomp = +am__depfiles_maybe = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +man1dir = $(mandir)/man1 +am__installdirs = "$(DESTDIR)$(man1dir)" +NROFF = nroff +MANS = $(dist_man1_MANS) +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +SUBDIRS = hash mimi +dist_man1_MANS = stamina.1 +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps stamina/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps stamina/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || mkdir "$(distdir)/$$subdir" \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="../$(top_distdir)" \ + distdir="../$(distdir)/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(MANS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-man + +install-exec-am: + +install-info: install-info-recursive + +install-man: install-man1 + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am uninstall-man + +uninstall-info: uninstall-info-recursive + +uninstall-man: uninstall-man1 + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-generic clean-recursive ctags ctags-recursive \ + distclean distclean-generic distclean-recursive distclean-tags \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-man1 install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive \ + mostlyclean mostlyclean-generic mostlyclean-recursive pdf \ + pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \ + uninstall-info-am uninstall-man uninstall-man1 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/stamina/hash/Makefile.am b/stamina/hash/Makefile.am new file mode 100644 index 0000000..69d349d --- /dev/null +++ b/stamina/hash/Makefile.am @@ -0,0 +1,5 @@ +AM_CPPFLAGS = -I$(top_srcdir)/sis/util + +noinst_LIBRARIES = libhash.a +libhash_a_SOURCES = hash.c hash.h hash_drive.c hash_dump.c hash_initial.c \ + install.c lookup.c diff --git a/stamina/hash/Makefile.in b/stamina/hash/Makefile.in new file mode 100644 index 0000000..1e59847 --- /dev/null +++ b/stamina/hash/Makefile.in @@ -0,0 +1,371 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(libhash_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = stamina/hash +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libhash_a_AR = $(AR) $(ARFLAGS) +libhash_a_LIBADD = +am_libhash_a_OBJECTS = hash.$(OBJEXT) hash_drive.$(OBJEXT) \ + hash_dump.$(OBJEXT) hash_initial.$(OBJEXT) install.$(OBJEXT) \ + lookup.$(OBJEXT) +libhash_a_OBJECTS = $(am_libhash_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libhash_a_SOURCES) +DIST_SOURCES = $(libhash_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I$(top_srcdir)/sis/util +noinst_LIBRARIES = libhash.a +libhash_a_SOURCES = hash.c hash.h hash_drive.c hash_dump.c hash_initial.c \ + install.c lookup.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps stamina/hash/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps stamina/hash/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libhash.a: $(libhash_a_OBJECTS) $(libhash_a_DEPENDENCIES) + -rm -f libhash.a + $(libhash_a_AR) libhash.a $(libhash_a_OBJECTS) $(libhash_a_LIBADD) + $(RANLIB) libhash.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/stamina/hash/README b/stamina/hash/README new file mode 100644 index 0000000..371f830 --- /dev/null +++ b/stamina/hash/README @@ -0,0 +1,14 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/hash/README,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +The Hash functions are lint free except the warning message: + + "possible pointer alignment problem". + +The style of the code would be a sample of C program. diff --git a/stamina/hash/hash.c b/stamina/hash/hash.c new file mode 100644 index 0000000..ece973d --- /dev/null +++ b/stamina/hash/hash.c @@ -0,0 +1,37 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/hash/hash.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +/************************************************************ + * hash(s) --- The hashing function which forms hash value * + * for string s . * + ************************************************************/ + +#include <stdio.h> +#include "hash.h" + + +int hash(s, hash_size) +char *s; +int hash_size; +{ + int hashval; /* hash value of string s */ + + + for ( hashval = 0; *s != '\0'; ) { + hashval += *s; + s++ ; + } + + return ( hashval % hash_size ); + +} + + + + diff --git a/stamina/hash/hash.h b/stamina/hash/hash.h new file mode 100644 index 0000000..35095c6 --- /dev/null +++ b/stamina/hash/hash.h @@ -0,0 +1,32 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/hash/hash.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +/************************************************************ + * hash.h --- The hash header file. * + ************************************************************/ + +#include "util.h" + +#define HASHSIZE 1000 /* It is not used */ + +typedef struct nlist NLIST; + +struct nlist { /* basic table entry */ + char *name; + int *ptr; /* this element is not used */ + int *nptr; /* For the new flow table */ + int order_index; /* order index of entries in hashtab */ + NLIST *h_next; /* Horizontal chain for flow table */ + NLIST *h_prev; + struct nlist *next; /* next entry in chain */ +}; + +/*NLIST **hashtab;*/ /* the hashtable should be allocated in + the calling function by calling + hash_initial() . */ diff --git a/stamina/hash/hash_drive.c b/stamina/hash/hash_drive.c new file mode 100644 index 0000000..0ef427a --- /dev/null +++ b/stamina/hash/hash_drive.c @@ -0,0 +1,98 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/hash/hash_drive.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +/************************************************************ + * hash_drive --- hash driver. * + ************************************************************/ + +#include <stdio.h> +#include "hash.h" + +main() +{ +static char *s[] = { + "state0", + "state1", + "state2", + "state3", + "state4", + "state5", + "state6", + "state7", + "state8", + "state9", + "state10", + "state11", + "state12", + "state13", + "state14", + "state15", + "state16", + "state9", + "state17", + "state18", + "state19", + "state20", + "state21", + "state7", + "state22", + "state23", + "state24", + "state25", + "state26", + "state27", + "state28", + "state29" +}; + + int hash_size = 30; + int count; /* the order index of entries in hashtab */ + int i; + NLIST **node_hash; + NLIST **hash_initial(); + NLIST *install(); + NLIST *lookup(); + + void hash_dump(); /* void: declare a funtion which returns nothing*/ + + + (void) printf("These strings will be stored in a hash table \n\n"); + for ( i = 0; i < 32; i++ ) { + + (void) printf("%s \n", s[i]); + + } + (void) printf("\n\n"); + + /* + * allocate memory for hash_table. + */ + if ( (node_hash = hash_initial(hash_size)) == NIL(NLIST *) ) { + (void) fprintf(stderr, + "Memory allocation error, node_hash was not allocated \n"); + exit(1); + } + + count = 0; + for ( i = 0; i < 32; i++ ) { + + if ( lookup(s[i], node_hash, hash_size) == NIL(NLIST) ) { + (void) install(s[i], count, node_hash, hash_size); + count++; + } + + } + + /* + * print out the hash table. + */ + (void) hash_dump(node_hash, hash_size); + + +} diff --git a/stamina/hash/hash_dump.c b/stamina/hash/hash_dump.c new file mode 100644 index 0000000..6c30396 --- /dev/null +++ b/stamina/hash/hash_dump.c @@ -0,0 +1,43 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/hash/hash_dump.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +/************************************************************ + * hash_dump() --- dump the hash table * + ************************************************************/ + +#include <stdio.h> +#include "hash.h" + + +void hash_dump(hashtab, hash_size) +NLIST *hashtab[]; +int hash_size; +{ + NLIST *np; /* a pointer to nlist */ + int i; + + (void) printf("This is a dump of hash table \n\n"); + + for ( i = 0; i < hash_size; i++ ) { + if ((np = hashtab[i]) == NIL(NLIST) ) { + continue; + } + for (np = hashtab[i]; np != NULL; np = np->next) { + (void) printf("%s %4d ", np->name, hash(np->name,hash_size) ); + (void) printf(" %4d \t ", np->order_index ); + } + (void) printf("\n"); + } + + return ; + +} + + + diff --git a/stamina/hash/hash_initial.c b/stamina/hash/hash_initial.c new file mode 100644 index 0000000..52625f3 --- /dev/null +++ b/stamina/hash/hash_initial.c @@ -0,0 +1,61 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/hash/hash_initial.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +/************************************************************ + * hash_initial() --- Create an empty hash-table. * + * Return a pointer to the beginning of * + * the hash-table. * + * str_save(s) --- Save a string 's' to somewhere. * + ************************************************************/ + +#include <stdio.h> +#include "hash.h" + + +NLIST **hash_initial(hash_size) +int hash_size; +{ + NLIST **np; /* it is an array of pointers to hash-table */ + int i; + + np = ALLOC ( NLIST *, hash_size); + if ( np == NIL( NLIST * ) ) { + (void) fprintf(stderr, "Memory allocation error \n"); + return (NIL(NLIST *)); + } + + for ( i = 0; i < hash_size; i++ ) { + *(np + i) = NIL(NLIST); + } + + return (np); + +} + +char *str_save(s) /* save a string 's' somewhere */ +char *s; +{ + char *p; + int num; + +/* if ( (p = malloc((unsigned)(strlen(s)+1))) == NIL(char) ) { + (void) fprintf(stderr, "Memory allocation error \n"); + exit(1); + } +*/ + num = strlen(s) + 1; + if ( (p = ALLOC(char, num )) == NIL(char) ) { + (void) fprintf(stderr, "Memory allocation error \n"); + return(NIL(char)); + } + + (void) strcpy(p,s); + return (p); + +} diff --git a/stamina/hash/install.c b/stamina/hash/install.c new file mode 100644 index 0000000..017b982 --- /dev/null +++ b/stamina/hash/install.c @@ -0,0 +1,108 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/hash/install.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +/* SCCSID%W% */ +/************************************************************ + * install(name,order,ptr,hashtab, hash_size) --- put name * + * in hashtab. * + * * + * (a) install uses lookup() to determine whether * + * the name being installed is already present; * + * (b) if so, no action taken, except return the * + * pointer pointing to the exist entry * + * (c) otherwise, a completely new entry is created. * + * and return the pointer pointing the new entry * + * (d) install returns NULL if for any reason there * + * is no room for a new entry. * + ************************************************************/ +/* Modified by June Rho Dec. 1989 */ + +#include <stdio.h> +#include "hash.h" + + +NLIST *install(name, order, ptr, hashtab, hash_size) +char *name; +char *ptr; /* Pointer to first structure */ +int order; /* order index of entries in hashtab */ +NLIST *hashtab[]; +{ + NLIST *np; /* a pointer to nlist */ + NLIST *lookup(); + int hashval; + char *str_save(); + + if ( (np = lookup(name,hashtab,hash_size)) == NIL(NLIST) ) { + /* not found */ + /*np = ALLOC ( NLIST , 1 ); */ + np = (NLIST *) malloc ((unsigned) sizeof (NLIST) ); + if ( np == NIL(NLIST) ) { + (void) fprintf ( stderr, "memory allocation error \n"); + return (NIL(NLIST)); + } + + if ((np->name = str_save(name)) == NIL(char)) { + (void) fprintf(stderr, + "fail to copy a string, died in install.\n"); + exit(1); + } + + hashval = hash(np->name, hash_size); + np->order_index = order; + np->next = hashtab[hashval]; + np->ptr = (int *) ptr; + np->h_next = NIL(NLIST); + hashtab[hashval] = np; + + return (np);/* return the pointer pointing the new entry */ + } else { + return (np);/* return the pointer pointing to the exist entry */ + } + +} + +NLIST +*install_input(name, hashtab, hash_size) +char *name; +/* char *ptr; Pointer to first structure */ +/* int order; order index of entries in hashtab */ +NLIST *hashtab[]; +{ + NLIST *np; /* a pointer to nlist */ + NLIST *lookup(); + int hashval; + char *str_save(); + + if ( (np = lookup(name,hashtab,hash_size)) == NIL(NLIST) ) { + /* not found */ + /*np = ALLOC ( NLIST , 1 ); */ + np = (NLIST *) malloc ((unsigned) sizeof (NLIST) ); + if ( np == NIL(NLIST) ) { + panic("install"); + } + + if ((np->name = str_save(name)) == NIL(char)) { + (void) fprintf(stderr, + "fail to copy a string, died in install.\n"); + exit(1); + } + + hashval = hash(np->name, hash_size); +/* np->order_index = order; */ + np->next = hashtab[hashval]; + np->h_prev = NIL(NLIST); + np->ptr = (int *)0; + np->h_next = NIL(NLIST); + hashtab[hashval] = np; + + return (np);/* return the pointer pointing the new entry */ + } else { + return NIL(NLIST);/* return the pointer pointing to the exist entry */ + } +} diff --git a/stamina/hash/lookup.c b/stamina/hash/lookup.c new file mode 100644 index 0000000..2dbb732 --- /dev/null +++ b/stamina/hash/lookup.c @@ -0,0 +1,38 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/hash/lookup.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:16 $ + * + */ +/************************************************************ + * lookup(s,hashtab,hash_size) --- Look for s in hashtab. * + * If lookup finds the entry already present,* + * it returns a pointer to it; * + * if not, it returns NULL. * + ************************************************************/ + +#include <stdio.h> +#include "hash.h" + + +NLIST *lookup(s, hashtab, hash_size) +char *s; +NLIST *hashtab[]; +int hash_size; +{ + NLIST *np; /* a pointer to nlist */ + int hash_index; + + hash_index = hash(s, hash_size); + for (np = hashtab[hash_index]; np != NIL(NLIST); np = np->next) { + if ( strcmp(s, np->name) == 0 ) { + return(np); /* found it */ + } + } + + return (NIL(NLIST)); /* not found */ + +} diff --git a/stamina/mimi/Makefile.am b/stamina/mimi/Makefile.am new file mode 100644 index 0000000..f82ddf4 --- /dev/null +++ b/stamina/mimi/Makefile.am @@ -0,0 +1,9 @@ +AM_CPPFLAGS = -I$(srcdir)/../hash -I$(top_srcdir)/sis/mincov \ + -I$(top_srcdir)/sis/sparse -I$(top_srcdir)/sis/util +LDADD = ../hash/libhash.a ../../sis/mincov/libmincov.a \ + ../../sis/sparse/libsparse.a ../../sis/util/libutil.a + +bin_PROGRAMS = stamina +stamina_SOURCES = bcover.c class.c conf.c disjoint.c global.h \ + install_state.c iso.c main.c map.c max.c max.h merge.c merge.h \ + misc.c prime.c read_fsm.c stack.c stack.h struct.h user.h diff --git a/stamina/mimi/Makefile.in b/stamina/mimi/Makefile.in new file mode 100644 index 0000000..53e43c0 --- /dev/null +++ b/stamina/mimi/Makefile.in @@ -0,0 +1,402 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(stamina_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = stamina$(EXEEXT) +subdir = stamina/mimi +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_stamina_OBJECTS = bcover.$(OBJEXT) class.$(OBJEXT) conf.$(OBJEXT) \ + disjoint.$(OBJEXT) install_state.$(OBJEXT) iso.$(OBJEXT) \ + main.$(OBJEXT) map.$(OBJEXT) max.$(OBJEXT) merge.$(OBJEXT) \ + misc.$(OBJEXT) prime.$(OBJEXT) read_fsm.$(OBJEXT) \ + stack.$(OBJEXT) +stamina_OBJECTS = $(am_stamina_OBJECTS) +stamina_LDADD = $(LDADD) +stamina_DEPENDENCIES = ../hash/libhash.a ../../sis/mincov/libmincov.a \ + ../../sis/sparse/libsparse.a ../../sis/util/libutil.a +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(stamina_SOURCES) +DIST_SOURCES = $(stamina_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I$(srcdir)/../hash -I$(top_srcdir)/sis/mincov \ + -I$(top_srcdir)/sis/sparse -I$(top_srcdir)/sis/util + +LDADD = ../hash/libhash.a ../../sis/mincov/libmincov.a \ + ../../sis/sparse/libsparse.a ../../sis/util/libutil.a + +stamina_SOURCES = bcover.c class.c conf.c disjoint.c global.h \ + install_state.c iso.c main.c map.c max.c max.h merge.c merge.h \ + misc.c prime.c read_fsm.c stack.c stack.h struct.h user.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps stamina/mimi/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps stamina/mimi/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +stamina$(EXEEXT): $(stamina_OBJECTS) $(stamina_DEPENDENCIES) + @rm -f stamina$(EXEEXT) + $(LINK) $(stamina_LDFLAGS) $(stamina_OBJECTS) $(stamina_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/stamina/mimi/bcover.c b/stamina/mimi/bcover.c new file mode 100644 index 0000000..8a148f4 --- /dev/null +++ b/stamina/mimi/bcover.c @@ -0,0 +1,625 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/bcover.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ + +#include "user.h" +#include "util.h" +#include "struct.h" +#include "global.h" +/* +#include "merge.h" +*/ +#include "stack.h" +#include "max.h" +#include "sparse.h" +#include "sparse_int.h" +#include "mincov.h" + +#define WEIGHT_DEFAULT 2000 + +unsigned char *all_states; +int *b_cover; /* Binate covering solution */ +int *c_cover; /* Binate covering solution */ + +sm_setup() +{ + register i,j,k; + int row_index; + sm_matrix *A; + sm_element *p; + sm_row *cover; + int *weight; + FILE *b_fp; + + row_index=num_st; + if (b_file[0]) + if ((b_fp=fopen(b_file,"w")) == NIL(FILE)) + panic("Cannot open Binate cover file "); + A=sm_alloc(); + weight = (int *) 0; + for (i=0; i<p_num; i++) { + for (j=0; j<SMASK(prime[i]->num); j++) { + k=prime[i]->state[j]; + p=sm_insert(A,k,i); + if (b_file[0]) { + (void) fprintf(b_fp,"%d %d +\n",k,i); + } + sm_put(p,0); + } + } + for (i=0; i<p_num; i++) { + + for (j=0; j<prime[i]->class.many; j++) { + int not_closed; + + p=sm_insert(A,row_index,i); + if (b_file[0]) { + (void) fprintf(b_fp,"%d %d -\n",row_index,i); + } + sm_put(p,-1); + not_closed=1; + for (k=0; k<p_num; k++) { + if (contained(prime[i]->class.imply[j],prime[k])) { + not_closed=0; + if (b_file[0]) { + (void) fprintf(b_fp,"%d %d +\n",row_index,k); + } + p=sm_insert(A,row_index,k); + sm_put(p,0); + } + } + if (not_closed) + panic("Not closed prime \n"); + row_index++; + } + } + + if (b_file[0]) { + (void) fclose(b_fp); + exit(0); + } + + cover = sm_minimum_cover(A, weight, 2, 0); + + if (cover) { + save_cover(cover); + sm_row_free(cover); + } else { + (void) fprintf(stderr,"Unfeasible Problem\n"); + } + sm_free(A); + sm_cleanup(); +} + +max_cover(bina) +{ + register i,j,k; + int row_index; + sm_matrix *A; + sm_element *p; + sm_row *cover; + int *weight; + + row_index=num_st; + + if (bina) { + for (i=0; i<user.stat.n_max; i++) { + int maxim; + PRIME *sav_max; + + maxim = 0; + for (j=i; j<user.stat.n_max; j++) { + if (max[j]->num > maxim) { + k = j; + maxim=max[j]->num; + } + } + sav_max = max[i]; + max[i] = max[k]; + max[k] = sav_max; + } + } + + A=sm_alloc(); + for (i=0; i<user.stat.n_max; i++) { + for (j=0; j<SMASK(max[i]->num); j++) { + k=max[i]->state[j]; + p=sm_insert(A,k,i); + sm_put(p,0); + } + } + if (bina) { + for (i=0; i<user.stat.n_max; i++) { + for (j=0; j<max[i]->class.many; j++) { + p=sm_insert(A,row_index,i); + sm_put(p,-1); + for (k=0; k<user.stat.n_max; k++) { + if (contained(max[i]->class.imply[j],max[k])) { + p=sm_insert(A,row_index,k); + sm_put(p,0); + } + } + row_index++; + } + } + } + weight=NIL(int); + + cover = sm_minimum_cover(A, weight, 2, 0); + if (cover) { + save_cover(cover); + sm_row_free(cover); + } else { + (void) fprintf(stderr,"Unfeasible Problem\n"); + } + sm_free(A); + sm_cleanup(); + return user.stat.nstates; +} + +extern struct isomor *iso; + +max_close() +{ + register i,j,k; + struct sbase *base; + + if (!(base=ALLOC(struct sbase,num_st-1))) + panic("max_close"); + + for (i=0; i<num_st; i++) { + iso[i].list = (int *) 0; + } + + for (i=0; i<user.stat.n_max; i++) { + + for (j=0; j<max[i]->class.many; j++) { + int not_closed; + + not_closed=1; + for (k=0; k<user.stat.n_max; k++) { + if (contained(max[i]->class.imply[j],max[k])) { + not_closed=0; + break; + } + } + if (not_closed) { + not_closed=0; + for (k=0; k<max[i]->class.imply[j]->num; k++) { + int iso_id; + + iso_id = max[i]->class.imply[j]->state[k]; + if (iso[iso_id].uvoid) { + not_closed++; + iso[iso[iso_id].num].list = (int *) iso_id; +/* + if (iso[iso[iso_id].num].uvoid) + panic("UVOID"); +*/ + } + else { + iso[iso_id].list = (int *) iso_id; + } + } +/* + printf("MAX %d IMPLY %d\n",i,j); + printf("void state %d for max %d\n",not_closed,i); +*/ + select_one_max(i,max[i]->class.imply[j]->num,base); + one_implied(); + } + } + } + if (FREE(base)) + panic("lint"); +} + + +select_one_max(maxid,uncovered,base) +struct sbase *base; +{ + register i,j; + int max_id; + int newid; + int *new_state; + int maxi,itsize; + int index, point; + int big; + + big=0; + + max_id=0; + maxi = num_st; + for (i=0/*, maxi=0*/; i<user.stat.n_max; i++) { + point = 0; + for (j=0; j<max[i]->num; j++) { + index=max[i]->state[j]; + if (!iso[index].uvoid && iso[index].list) { + point++; + } + } + if (point == uncovered) { + if (max[i]->class.many < maxi) { + maxi=max[i]->class.many; + max_id=i; + } + } + } + + + /* How many states are covered by that maximal compatibles ? */ + + big=uncovered; + maxi=0; + point=0; + + for (j=0; j<max[max_id]->num; j++) { + index=max[max_id]->state[j]; + if (!iso[index].uvoid && iso[index].list) { + base[point].state=index; + base[point++].where=j; + } + } + + max[user.stat.n_max]->num = max[max_id]->num; + MEMCPY(max[user.stat.n_max]->state,max[max_id]->state, + sizeof(int)*max[max_id]->num); + + for (j=0; j<big; j++) { /* How many in a maximal compatible */ + + max[user.stat.n_max]->state[base[j].where]= + (int ) iso[base[j].state].list; + iso[base[j].state].list = (int *) 0; + } + increase_max_num(); +} + +save_cover(bsol) +sm_row *bsol; +{ + int new_states; + sm_element *p; + + new_states = 0; + p=bsol->first_col; + while (p) { + p=p->next_col; + new_states++; + } + if (!(b_cover=ALLOC(int, new_states+1))) + panic("save_cover"); + new_states = 0; + for(p = bsol->first_col; p != 0; p = p->next_col) { + b_cover[new_states++] = p->col_num; + } + b_cover[new_states] = -1; + user.stat.nstates=new_states; + user.stat.rstates=user.stat.nstates+user.stat.ostates; +} + +contained(c_imply,prime_id) +PRIME *prime_id; +IMPLIED *c_imply; +{ + register k,l; + int not_match; + + if (SMASK(prime_id->num) < c_imply->num) + return 0; + for (k=0; k <c_imply->num; k++) { + not_match = 1; + for (l=0; l<SMASK(prime_id->num); l++) { + if (prime_id->state[l] == c_imply->state[k]) { + not_match = 0; + break; + } + } + if (not_match) + return 0; + } + return 1; +} + +#define foreach_prime(v,where) for (v=0; where[v] != -1; v++) +#define foreach_state(v,where) for (v=0; v < SMASK(where->num); v++) + +/* +shrink_prime() +{ + register i,j,k,m; + int *s_imp; + int shrinked,save_state,save_many; + IMPLIED **save_imply; + + shrinked = 1; + + if (!(s_imp=ALLOC(int, num_st))) + panic("shrink"); + + get_essential_state(); + + while (shrinked) { + shrinked = 0; + foreach_prime(i,b_cover) { + get_implied_by_other_prime(b_cover[i],s_imp); + + foreach_state(j,prime[b_cover[i]]) { + int not_closed; + + if ((all_states[prime[b_cover[i]]->state[j]] == 1) + || s_imp[prime[b_cover[i]]->state[j]]) { + continue; + } + save_state = prime[b_cover[i]]->state[j]; + for (k=j; k<prime[b_cover[i]]->num - 1; k++) + prime[b_cover[i]]->state[k]=prime[b_cover[i]]->state[k+1]; + prime[b_cover[i]]->num--; + save_imply = prime[b_cover[i]]->class.imply; + save_many = prime[b_cover[i]]->class.many; + Find_Implied(prime,b_cover[i]); + not_closed = 0; + for (k=0; k<prime[b_cover[i]]->class.many; k++) { + not_closed = 1; + for (m=0; m<user.stat.nstates; m++) { + if (i == m) + continue; + if (contained(prime[b_cover[i]]->class.imply[k], + prime[b_cover[m]])) { + not_closed = 0; + break; + } + } + if (not_closed) { + (void) fprintf(stderr,"Not closed\n"); + prime[b_cover[i]]->class.imply = save_imply; + prime[b_cover[i]]->class.many = save_many; + prime[b_cover[i]]->state[prime[b_cover[i]]->num++] + = save_state; + break; + } + } + if (!not_closed) { + all_states[save_state]--; + shrinked++; + user.stat.shrink++; + } + } + } + } +} + +*/ + +shrink_prime() +{ + register i,j,k,m; + int *s_imp; + int shrinked, *save_state,save_many; + IMPLIED **save_imply; + + shrinked = 1; + + if (!(s_imp=ALLOC(int, num_st))) + panic("shrink"); + + if (!(save_state=ALLOC(int, num_st))) + panic("shrink2"); + + get_essential_state(); + + while (shrinked) { + shrinked = 0; + foreach_prime(i,b_cover) { + int not_closed; + int n_shrunk; + + get_implied_by_other_prime(b_cover[i],s_imp); + + n_shrunk = 0; + foreach_state(j,prime[b_cover[i]]) { + + if ((all_states[prime[b_cover[i]]->state[j]] == 1) + || s_imp[prime[b_cover[i]]->state[j]]) { + continue; + } + save_state[n_shrunk++] = prime[b_cover[i]]->state[j]; + for (k=j; k<prime[b_cover[i]]->num - 1; k++) + prime[b_cover[i]]->state[k]=prime[b_cover[i]]->state[k+1]; + prime[b_cover[i]]->num--; + } + if (n_shrunk) { + save_imply = prime[b_cover[i]]->class.imply; + save_many = prime[b_cover[i]]->class.many; + Find_Implied(prime,b_cover[i]); + not_closed = 0; + for (k=0; k<prime[b_cover[i]]->class.many; k++) { + not_closed = 1; + for (m=0; m<user.stat.nstates; m++) { + if (i == m) + continue; + if (contained(prime[b_cover[i]]->class.imply[k], + prime[b_cover[m]])) { + not_closed = 0; + break; + } + } + if (not_closed) { + prime[b_cover[i]]->class.imply = save_imply; + prime[b_cover[i]]->class.many = save_many; + for (j=0; j<n_shrunk; j++) + prime[b_cover[i]]->state[prime[b_cover[i]]->num++] + = save_state[j]; + break; + } + } + if (!not_closed) { + for (j=0; j<n_shrunk; j++) + all_states[save_state[j]]--; + shrinked++; + user.stat.shrink += n_shrunk; + } + } + } + } + + shrinked = 1; + while (shrinked) { + shrinked = 0; + for (i=user.stat.nstates-1; i>-1; i--) { +/* + foreach_prime(i,b_cover) { +*/ + int not_closed; + int n_shrunk; + + get_implied_by_other_prime(b_cover[i],s_imp); + + n_shrunk = 0; + foreach_state(j,prime[b_cover[i]]) { + + if ((all_states[prime[b_cover[i]]->state[j]] == 1) + || s_imp[prime[b_cover[i]]->state[j]]) { + continue; + } + save_state[n_shrunk++] = prime[b_cover[i]]->state[j]; + for (k=j; k<prime[b_cover[i]]->num - 1; k++) + prime[b_cover[i]]->state[k]=prime[b_cover[i]]->state[k+1]; + prime[b_cover[i]]->num--; + } + if (n_shrunk) { + save_imply = prime[b_cover[i]]->class.imply; + save_many = prime[b_cover[i]]->class.many; + Find_Implied(prime,b_cover[i]); + not_closed = 0; + for (k=0; k<prime[b_cover[i]]->class.many; k++) { + not_closed = 1; + for (m=0; m<user.stat.nstates; m++) { + if (i == m) + continue; + if (contained(prime[b_cover[i]]->class.imply[k], + prime[b_cover[m]])) { + not_closed = 0; + break; + } + } + if (not_closed) { + prime[b_cover[i]]->class.imply = save_imply; + prime[b_cover[i]]->class.many = save_many; + for (j=0; j<n_shrunk; j++) + prime[b_cover[i]]->state[prime[b_cover[i]]->num++] + = save_state[j]; + break; + } + } + if (!not_closed) { + for (j=0; j<n_shrunk; j++) + all_states[save_state[j]]--; + shrinked++; + user.stat.shrink += n_shrunk; + } + } + } + } +} + +get_essential_state() +{ + register i,j; + + if (!(all_states=ALLOC(unsigned char,num_st))) + panic("Bcover"); + + for (i=0; i<num_st; i++) { + all_states[i] = 0; + } + foreach_prime(i,b_cover) { + prime[b_cover[i]]->num = SMASK(prime[b_cover[i]]->num); + foreach_state(j,prime[b_cover[i]]) { + all_states[prime[b_cover[i]]->state[j]]++; + } + } +} + +get_implied_by_other_prime(prime_no,x_imp) +int *x_imp; +{ + register i,j,k; + NLIST *link; + extern NLIST *_head; + extern int *local_state; + IMPLIED flow_imply; + int s_num; + + for (i=0; i<num_st; i++) + x_imp[i] = 0; + +/* + for (link=_head; link; link=link->h_next) { + + for (i=0; b_cover[i] != -1; i++) { + + if (s_num=set_nstate(link,b_cover[i],(char *) 0)) { + int count,where; + + if (s_num == -1) + continue; + flow_imply.num=s_num; + flow_imply.state=local_state; + + count = 0; + where = -1; + if (contained(&flow_imply,prime[prime_no])) { + for (j=0; b_cover[j] != -1; j++) { + if (b_cover[j] == prime_no) + continue; + if (contained(&flow_imply,prime[b_cover[j]])) { + if (count++ > 1) + break; + } + } + if (count < 2) { + for (k=0; k<flow_imply.num; k++) + if (!x_imp[flow_imply.state[k]]) { + x_imp[flow_imply.state[k]]++; + (void) printf("Don't remove\n"); + } + } + } + + } + } + } +*/ + + foreach_prime(i,b_cover) { + if (b_cover[i] == prime_no) + continue; + for (j=0; j<prime[b_cover[i]]->class.many; j++) { + int essence; + if (contained(prime[b_cover[i]]->class.imply[j],prime[prime_no])) { + essence = 1; + foreach_prime(k,b_cover) { + if (b_cover[k] == prime_no) + continue; + if (contained(prime[b_cover[i]]->class.imply[j], + prime[b_cover[k]])) { + essence = 0; + break; + } + } + if (essence) { + for (k=0; k<prime[b_cover[i]]->class.imply[j]->num; k++) + if (!x_imp[prime[b_cover[i]]->class.imply[j]->state[k]]) { + x_imp[prime[b_cover[i]]->class.imply[j]->state[k]]++; + } + } + } + } + } +} diff --git a/stamina/mimi/class.c b/stamina/mimi/class.c new file mode 100644 index 0000000..48872e4 --- /dev/null +++ b/stamina/mimi/class.c @@ -0,0 +1,389 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/class.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/* SCCSID %W% */ +#include "util.h" +#include "struct.h" +#include "global.h" +#include "merge.h" +#include "stack.h" +#include "max.h" +#include "user.h" + +#define next_state n_state->state_index +#define I sizeof(int) +#define SMASK(x) (x & 0x7fff) + +IMPLIED **local_imply; +int *local_state; + +get_implied() +{ + register i,j,k; + + if (!(local_state = ALLOC(int,num_st))) + panic("ALLOC in x"); + + if (!(local_imply = ALLOC(IMPLIED *,200))) + panic("ALLOC in x"); + + for (i=0; i<num_st; i++) + states[i]->code = NIL(char); + + for (i=0; i<user.stat.n_max; i++) { /* Maximal Compatible */ + Find_Implied(max,i); + } +} + + +one_implied() +{ + register i,j,k; + + i=user.stat.n_max-1; + + Find_Implied(max,i); +} + +extern NLIST *_head; +static int sequ, deleted; + +Find_Implied(xmax,max_index) +PRIMES xmax; +{ + register i,l; + int num_implied; + S_EDGE *top; + NLIST *link; + + sequ = deleted = 0; + for (i=0; i<SMASK(xmax[max_index]->num); i++) + states[xmax[max_index]->state[i]]->code = (char *) 1; + + for (link=_head; link; link=link->h_next) { + + top=(S_EDGE *)link->ptr; + num_implied = 0; + while (top) { + + if (top->p_state->code) { + if (top->n_star) + goto x_con; + for (l=0; l<num_implied; l++) { + if (top->next_state == local_state[l]) + goto x_con; + } + local_state[num_implied++] = top->next_state; +#ifdef DEBUG + (void) printf("%s",states[top->next_state]->state_name); +#endif + } +x_con: + top=top->v_next; + } + if ((num_implied > 1) && !excluded(xmax,max_index,num_implied,sequ)) { + if (!(local_imply[sequ] =ALLOC(IMPLIED,1))) + panic("ALLOC in get_implied"); + if (!(local_imply[sequ]->state=ALLOC(int,num_implied))) + panic("ALLOC in prime"); + MEMCPY(local_imply[sequ]->state,local_state,num_implied*I); + local_imply[sequ]->num=num_implied; + sequ++; + } + } + xmax[max_index]->class.many = sequ-deleted; + for (i=0; i<SMASK(xmax[max_index]->num); i++) + states[xmax[max_index]->state[i]]->code = NIL(char); + +/* + if (sequ-deleted) { +*/ + { + register k,m; + register all; + IMPLIED *temp_imply; + + all=sequ; +/* + if (sequ-deleted) { +*/ + for (k=0; k<all; k++) { + while (!local_imply[k]->num) { + all--; + temp_imply = local_imply[k]; + local_imply[k]=local_imply[all]; + local_imply[all] = temp_imply; + if (k>all-1) + goto xc24; + } + } +/* + } +*/ + } +xc24: + sequ -= deleted; + if (sequ) { + if (!(xmax[max_index]->class.imply=ALLOC(IMPLIED *,sequ))) + panic("ALLOC class implied"); + } + MEMCPY(xmax[max_index]->class.imply,local_imply,sequ*sizeof(IMPLIED *)); +/* + } +*/ +} + +transitive(xmax,max_index) +PRIMES xmax; +{ + register i,l; + int n_imply; + + sequ = deleted = 0; + n_imply = column_implied(xmax[max_index]->state,xmax[max_index]->num,xmax,max_index,1); + + for (i=0; i<n_imply; i++) { + n_imply = column_implied(local_imply[i]->state,local_imply[i]->num,xmax,max_index,0); + } + + xmax[max_index]->class.many = n_imply; + + if (!(xmax[max_index]->class.imply=ALLOC(IMPLIED *,n_imply))) + panic("ALLOC class implied"); + MEMCPY(xmax[max_index]->class.imply,local_imply,n_imply*sizeof(IMPLIED *)); + +/* + if (sequ-deleted) { + { + register k,m; + register all; + IMPLIED *temp_imply; + + all=sequ; + if (sequ-deleted) { + for (k=0; k<all; k++) { + while (!local_imply[k]->num) { + all--; + temp_imply = local_imply[k]; + local_imply[k]=local_imply[all]; + local_imply[all] = temp_imply; + if (k>all-1) + goto xc24; + } + } + } + } +xc24: + sequ -= deleted; + if (!(xmax[max_index]->class.imply=ALLOC(IMPLIED *,sequ))) + panic("ALLOC class implied"); + MEMCPY(xmax[max_index]->class.imply,local_imply,sequ*sizeof(IMPLIED *)); + } +*/ +} + +column_implied(state_set,number,xmax,max_index,reset) +PRIMES xmax; +int *state_set; +{ + register i,l; + S_EDGE *top; + NLIST *link; + int num_implied,met; + static i_num=0; + int added; + + if (reset) + i_num = 0; + for (i=0; i<number; i++) + states[state_set[i]]->code = (char *) 1; + + deleted = added = 0; + for (link=_head; link; link=link->h_next) { + + top=(S_EDGE *)link->ptr; + num_implied = 0; + met = 0; + while (top) { + + if (top->p_state->code) { + + met++; + if (top->n_star) + goto x_con; + for (l=0; l<num_implied; l++) { + if (top->next_state == local_state[l]) + goto x_con; + } + local_state[num_implied++] = top->next_state; +#ifdef DEBUG + (void) printf("%s",states[top->next_state]->state_name); +#endif + if (met == number) + break; + } +x_con: + top=top->v_next; + } + if ((num_implied > 1) && !excluded(xmax,max_index,num_implied,i_num)) { + if (!(local_imply[i_num] =ALLOC(IMPLIED,1))) + panic("ALLOC in get_implied"); + if (!(local_imply[i_num]->state=ALLOC(int,num_implied))) + panic("ALLOC in prime"); + MEMCPY(local_imply[i_num]->state,local_state,num_implied*I); + local_imply[i_num]->num=num_implied; + i_num++; + added++; + } + } + + for (i=0; i<number; i++) + states[state_set[i]]->code = (char *) 0; + +/* + if (added-deleted) { +*/ + { + register k,m; + register all; + IMPLIED *temp_imply; + + all=i_num; + for (k=0; k<all; k++) { + while (!local_imply[k]->num) { + all--; + temp_imply = local_imply[k]; + local_imply[k]=local_imply[all]; + local_imply[all] = temp_imply; + if (k>all-1) + goto xc24; + } + } + } +xc24: + i; +/* + sequ -= deleted; + if (!(xmax[max_index]->class.imply=ALLOC(IMPLIED *,sequ))) + panic("ALLOC class implied"); + MEMCPY(xmax[max_index]->class.imply,local_imply,sequ*sizeof(IMPLIED *)); + } +*/ + + i_num -= deleted; + return i_num; +} + +set_nstate(link,max_index,r_out) +NLIST *link; +char *r_out; +{ + S_EDGE *top; + int num_implied; + register i,j,l; + int exist; + extern PRIMES prime; + + if (r_out) { + for (i=0; i<num_po; i++) + r_out[i] = '-'; + r_out[i] = 0; + } + for (i=0; i<SMASK(prime[max_index]->num); i++) + states[prime[max_index]->state[i]]->code = (char *) 1; + top=(S_EDGE *)link->ptr; + num_implied = 0; + exist=0; + while (top) { + if (top->p_state->code) { + exist=1; + if (r_out) { + for (j=0; j<num_po; j++) + r_out[j]=(top->output)[j] == '-'?r_out[j]:(top->output)[j]; + } + if (top->n_star) + goto x_con; + for (l=0; l<num_implied; l++) { + if (top->next_state == local_state[l]) + goto x_con; + } + local_state[num_implied++] = top->next_state; + } +x_con: + top=top->v_next; + } + for (i=0; i<SMASK(prime[max_index]->num); i++) + states[prime[max_index]->state[i]]->code = NIL(char); + + if (!exist) + return -1; + else + return num_implied; +} + +excluded(xmax,maxim,candidate,index) +PRIMES xmax; +{ + register k,l,m; + int not_match; + int bound,upbound; + + for (k=0; k <candidate; k++) { + not_match = 1; + for (l=0; l<xmax[maxim]->num; l++) { + if (local_state[k] == xmax[maxim]->state[l]) { + not_match = 0; + break; + } + } + if (not_match) + break; + } + if (!not_match) /* Candidate is included in Maximal Compatible */ + return 1; + + for (k=0; k<index; k++) { + if (local_imply[k]->num > candidate) { + bound=candidate; + upbound=local_imply[k]->num; + } + else { + bound=local_imply[k]->num; + upbound = candidate; + } + for (l=0; l<bound; l++) { + not_match = 1; + for (m=0; m<upbound; m++) { + if (local_imply[k]->num > candidate) { + if (local_state[l] == local_imply[k]->state[m]) { + not_match = 0; + break; + } + } + else { + if (local_imply[k]->state[l]==local_state[m] ) { + not_match = 0; + break; + } + } + } + if (not_match) + break; + } + if (!not_match) { + if (bound == candidate) + return 1; + else { + deleted++; + local_imply[k]->num=0; + } + } + } + return 0; +} diff --git a/stamina/mimi/conf.c b/stamina/mimi/conf.c new file mode 100644 index 0000000..9532143 --- /dev/null +++ b/stamina/mimi/conf.c @@ -0,0 +1,34 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/conf.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/* SCCSID%W% */ + +int merge(); +int maximal_compatibles(); +int prime_compatible(); +int sm_setup(); +int bound(); + +int disjoint(); +int map(); +int say_solution(); +int iso_find(); + +null() +{ +} + +int (*method1[])()= {merge, disjoint, iso_find, maximal_compatibles, + bound, + prime_compatible, sm_setup, map, say_solution, (int(*)()) 0}; + +make_null(id) +{ + method1[id] = null; +} diff --git a/stamina/mimi/disjoint.c b/stamina/mimi/disjoint.c new file mode 100644 index 0000000..e689d56 --- /dev/null +++ b/stamina/mimi/disjoint.c @@ -0,0 +1,337 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/disjoint.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +#include "user.h" +#include "util.h" +#include "struct.h" +#include "global.h" + +static char *d_str, *intsect; +static int *pcount,*mcount; +NODE *root; +/* +char *input; +*/ + +NLIST **hash_initial(); + +NLIST **input_hash; +NLIST *_head, *_hend; + +disjoint() +{ + register i,j,k,l; + int num_jt; + extern int *c_cover; + EDGE *nedge; + NLIST *start,*advance,*previous,*inp,*list; + NLIST *install_input(); + NLIST *before; + + if (!(d_str=ALLOC(char,num_pi))) + panic("ALLOC"); + +/* + if (!(input=ALLOC(char,num_pi))) + panic("ALLOC"); +*/ + + if (!(intsect=ALLOC(char,num_pi))) + panic("ALLOC"); + + if (!(c_cover=ALLOC(int,num_st))) + panic("bCover"); + + /* I need hash table */ + + if ((input_hash = hash_initial(num_product)) == NIL(NLIST *)) { + panic("ALLOC hash"); + } + + k=0; + + _head=_hend=NIL(NLIST); + user.stat.ostates = 0; + for (i=0; i<num_st; i++) + if (states[i]->assigned) { + for (nedge=states[i]->edge;nedge;nedge=nedge->next) { + inp=install_input(nedge->input,input_hash,num_product); + if (inp) { + k++; + if (_head) { + inp->h_prev=_hend; + _hend->h_next=inp; + _hend=inp; + } + else { + _hend=_head=inp; + } + } + } + } + else + c_cover[user.stat.ostates++] = i; + + user.stat.xinput = k; + + disjoint_sharp(); + + k=0; + for (start=_head; start; start=start->h_next) { + if (user.opt.verbose > 10) { + (void) fprintf(stderr,"%s\n",start->name); + } + k++; + } + user.stat.disjoint = k; + + for (i=0; i<num_st; i++) { + if (states[i]->assigned) + for (nedge=states[i]->edge;nedge;nedge=nedge->next) { + for (start=_head; start; start=start->h_next) { + if (intersection(nedge->input,start->name,num_pi)) { + cube_split(nedge,start); + } + } + } + } +} + +cube_split(nedge,xlist) +EDGE *nedge; +NLIST *xlist; +{ + S_EDGE *pedge,*edge_hptr,*edge_vptr; + + if (!(pedge=ALLOC(S_EDGE,1))) + panic("Alloc in disjoint"); + pedge->p_state=nedge->p_state; + pedge->n_state=nedge->n_state; + pedge->n_star=nedge->n_star; + pedge->output=nedge->output; + + if (xlist->ptr) { + pedge->v_next = (S_EDGE *) xlist->ptr; + } + else { + pedge->v_next=NIL(S_EDGE); + } + xlist->ptr = (int *) pedge; +} + +disjoint_sharp() +{ + register i; + + if (!(pcount=ALLOC(int,num_pi*3))) + panic("xsharp"); + mcount=pcount+num_pi; + if (!(root=ALLOC(NODE,1))) + panic("root"); + root->on_off=mcount+num_pi; + for (i=0; i<num_pi; i++) + root->on_off[i]=1; + root->cubes=_head; + _head=NIL(NLIST); + sharp(root,num_pi); +} + +sharp(xnode,bit) +NODE *xnode; +{ + int index; + NODE *fnode; + + if ((xnode->literal=single_cube_contain(xnode))<2) { + xnode->right=xnode->left=NIL(NODE); + if (xnode->literal == 1) { + if (_head) { + _hend->h_next=xnode->cubes; + _hend=xnode->cubes; + } + else { + _head=_hend=xnode->cubes; + } + _hend->h_next=NIL(NLIST); + } +/* + return xnode; +*/ + return; + } + index=binate_select(xnode); + + if (!(xnode->left=ALLOC(NODE,2))) + panic("sharp"); + if (!(xnode->left->on_off=ALLOC(int,num_pi*2))) + panic("on_Off"); + + xnode->right = xnode->left + 1; + xnode->right->on_off=xnode->left->on_off+num_pi; + xnode->right->cubes=xnode->left->cubes=NIL(NLIST); + MEMCPY(xnode->right->on_off,xnode->on_off,sizeof(int)*num_pi); + MEMCPY(xnode->left->on_off,xnode->on_off,sizeof(int)*num_pi); + xnode->left->on_off[index]=0; + xnode->right->on_off[index]=0; + + divide(index,xnode); + + sharp(xnode->left,bit-1); + sharp(xnode->right,bit-1); + if (FREE(xnode->left->on_off) || FREE(xnode->left)) + panic("lint"); +} + +binate_select(xnode) +NODE *xnode; +{ + register i; + NLIST *start; + NLIST *list; + int index, maxi,num_list; + + for (i=0; i<num_pi; i++) { + pcount[i]=mcount[i]=0; + } + + start=xnode->cubes; + num_list=0; + for (list=start; list; list=list->h_next) + num_list++; + for (i=0; i<num_pi; i++) { + if (xnode->on_off[i]) { + for (list=start; list; list=list->h_next) { + switch (list->name[i]) { + case '0': + mcount[i]++; + break; + case '1': + pcount[i]++; + break; + default: + break; + } + } + } + } + maxi=0; + for (i=0; i<num_pi; i++) { + int abs_count; + + if (xnode->on_off[i]) { + abs_count= pcount[i]+mcount[i]; + if ((!abs_count) || (mcount[i]==num_list) || + (pcount[i]==num_list)) { + xnode->on_off[i]=0; + continue; + } + if (abs_count > maxi) { + maxi=abs_count; + index=i; + } + } + } + return index; +} + +divide(index,xnode) +NODE *xnode; +{ + NLIST *list; + NLIST *append_right; + NLIST *append_left; + + /* Bissect and expand linked list into two part */ + list=xnode->cubes; + while (list) { + NLIST *xlist; + NLIST *ylist; + + ylist=list->h_next; + switch (list->name[index]) { + case '1': + append(list,xnode->right); + break; + case '0': + append(list,xnode->left); + break; + case '-': + if (!(xlist=ALLOC(NLIST,1))) + panic("xlist"); + if (!(xlist->name=ALLOC(char,num_pi+1))) + panic("xlist name"); + list->name[index]='1'; + MEMCPY(xlist->name,list->name,num_pi+1); + xlist->name[index]='0'; + xlist->ptr= NIL(int); +/* + xlist->ptr= NIL(S_EDGE); +*/ + xlist->h_prev=xlist->h_next=NIL(NLIST); + append(list,xnode->right); + append(xlist,xnode->left); + break; + default: + panic("Non binary input specification"); + } + list=ylist; + } +} + +single_cube_contain(xnode) +NODE *xnode; +{ + register cube_count; + NLIST *list; + NLIST *child; + + list=xnode->cubes; + cube_count=0; + while (list) { + child=list->h_next; + while (child) { + if (!xintersection(list->name,child->name,num_pi,xnode)) { + /* remove child entry */ + cdelete(child); + } + child=child->h_next; + } + cube_count++; + list=list->h_next; + } + return cube_count; +} + +append(list,xnode) +NLIST *list; +NODE *xnode; +{ + NLIST *cube; + + cube=xnode->cubes; + if (cube) { + while (cube->h_next) + cube=cube->h_next; + cube->h_next=list; + list->h_prev=cube; + } + else { + xnode->cubes=list; + } + list->h_next=NIL(NLIST); +} + +cdelete(link) +NLIST *link; +{ + link->h_prev->h_next=link->h_next; + if (link->h_next) { + link->h_next->h_prev = link->h_prev; + } +} diff --git a/stamina/mimi/global.h b/stamina/mimi/global.h new file mode 100644 index 0000000..48c4bf8 --- /dev/null +++ b/stamina/mimi/global.h @@ -0,0 +1,34 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/global.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/******************************************************************* + * * + * Global.h ---- this header file contains all global variables * + * which are used by encoding program. * + * * + * All global variables will be initially declared in main.c. * + * So global.h won't be included in main.c. * + * * + *******************************************************************/ + +/*************************Global Variables**************************/ + +extern STATE **states; /* array of pointers to states. */ +extern EDGE **edges; /* array of pointers to edges. */ +extern char b_file[]; + +extern int num_pi; /* number of primary inputs */ +extern int num_po; /* number of primary outputs */ +extern int num_product; /* number of product terms */ +extern int num_st; /* number of states */ +/* extern int code_length; /* the encoding length. The dufault + value is the minimum encoding + length. User can specify the + encoding length by using the option + -l following an integer */ diff --git a/stamina/mimi/install_state.c b/stamina/mimi/install_state.c new file mode 100644 index 0000000..570fb45 --- /dev/null +++ b/stamina/mimi/install_state.c @@ -0,0 +1,78 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/install_state.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/* SCCSID%W% */ + +/************************************************************ + * install_state() --- install a state if it has not been * + * isntalled yet and return a pointer * + * to it. * + * If it has been installed, just return* + * a pointer to it. * + ************************************************************/ +/* Modified by June Rho Dec. 1989. */ + +#include "util.h" +#include "struct.h" +#include "global.h" + +static n_states= 0; + +access_n_state() +{ + return n_states; +} + +STATE * +install_state(state_name,hashtab,hash_size) +char *state_name; +NLIST *hashtab[]; +int hash_size; +{ + STATE *state_ptr; + static int count = 0; /* state index counting */ + NLIST *lookup(); + NLIST *install(); + NLIST *np; + + int id; /* reference index of existing state */ + + if ((np = lookup(state_name,hashtab,hash_size)) != NIL(NLIST) ) { + id = np->order_index; + state_ptr = states[id]; + return (state_ptr); /* the state has been installed. */ + } + n_states++; + + /* + * Allocate memory for a new state. + */ + + if ( (state_ptr = ALLOC(STATE, 1)) == NIL(STATE) ) { + panic("Memory allocation error"); + } + state_ptr->edge = NIL(EDGE); + + np = install(state_name,count,(char *)0,hashtab,hash_size); + if ( np == NIL(NLIST) ) { + panic("Failed to install a new state!"); + } + + states[count] = state_ptr; /* save the pointer to a state */ + state_ptr->state_index = count; /* save the state_index */ + state_ptr->state_name = np->name; /* save the state_name */ +/* state_ptr->pedge = NIL(P_EDGE); */ +/* state_ptr->code = NIL(char); /* assign a null pointer to char */ + state_ptr->assigned = 0; /* initial the flag to be zero */ + count++; + + + return (state_ptr); + +} diff --git a/stamina/mimi/iso.c b/stamina/mimi/iso.c new file mode 100644 index 0000000..9f74257 --- /dev/null +++ b/stamina/mimi/iso.c @@ -0,0 +1,320 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/iso.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +#include "user.h" +#include "util.h" +#include "struct.h" +#include "global.h" +#include "max.h" +#include "stack.h" + +static int *new_state; +static append=0; +static struct sbase *base; +static itsize; +struct isomor *iso; + +iso_find() +{ + register i,j; + int id; + int *temp; + + if (!(iso=ALLOC(struct isomor,num_st))) + panic("iso"); + + for (i=0; i<num_st; i++) { + int yy; + + /*xx=*/yy=0; + iso[i].uvoid=0; + if (!(iso[i].list=ALLOC(int,num_st))) + panic("iso_find3"); + + for (j=0; j<num_st; j++) { + if (i != j) { + if (i > j) + id = xstack[(num_st-j-2)*(num_st-j-1)/2-i+num_st-1].status; + else + id = xstack[(num_st-i-2)*(num_st-i-1)/2-j+num_st-1].status; + if (id & COMPATIBLE) { + iso[i].list[yy++]=j; + } +/* + if (id & DEFINIT_COMPATIBLE) + xx++; +*/ + } + } + iso[i].num=yy; +/* + if (xx == (num_st -1)) + printf("###All compatible states %s\n",states[i]->state_name); +*/ + } + + if (!(temp=ALLOC(int,num_st))) + panic("iso_find0"); + + for (i=0; i<num_st; i++) { + int numiso; + + if (!iso[i].uvoid && iso[i].num) { + numiso=0; +#ifdef DEBUG + (void) printf("%s : ",states[i]->state_name); +#endif + for (j=i+1; j<num_st; j++) { + int k; + + if (!iso[j].uvoid) { + if (iso[i].num == iso[j].num) { + iso[j].uvoid=1; + for (k=0; k<iso[i].num; k++) + if (iso[i].list[k] != iso[j].list[k]) { + iso[j].uvoid=0; + break; + } + if (iso[j].uvoid) { + temp[numiso++]=j; + iso[j].num = i; +#ifdef DEBUG + (void) printf("%s ",states[j]->state_name); +#endif + } + } + } + } +#ifdef DEBUG + (void) printf("\n"); +#endif + if (numiso) { + temp[numiso++]=i; + iso[i].num=numiso; + MEMCPY(iso[i].list,temp,numiso*sizeof(int)); + } + else + iso[i].num=0; + } + } + + user.stat.n_iso=0; + for (i=0; i<num_st; i++) + if (!iso[i].uvoid && iso[i].num) { + user.stat.n_iso += iso[i].num; + } + if (FREE(temp)) + panic("lint"); +} + +iso_generate() +{ + int i,j; + int index, point; + + user.stat.base_max = user.stat.n_max; + base=ALLOC(struct sbase,num_st-1); + if (!(new_state = ALLOC(int,num_st)) || !base) + panic("alloc321"); + for (i=0; i<user.stat.base_max; i++) { + point = 0; + for (j=0; j<max[i]->num; j++) { + index=max[i]->state[j]; + if (!iso[index].uvoid && iso[index].num) { + base[point].state=index; + base[point++].where=j; +#ifdef DEBUG + (void) printf("%s %d\n",states[index]->state_name,j); +#endif + } + } + if (point) { + itsize = /* sizeof(int)**/ max[i]->num /*+10*/; + MEMCPY(new_state,max[i]->state,sizeof(int)*max[i]->num); + make_max(--point); + user.stat.n_max--; + } + } + if (FREE(base)) + panic("lint"); +} + + +iso_close(num_of_iso) +{ + register i,j; + int max_id; + int maxi,mini; + int weight,max_weight; + int index, point; + int big,uncovered; + + if (!(base=ALLOC(struct sbase,num_st-1))) + panic("iso_close"); + user.stat.base_max = user.stat.n_max; + + big=uncovered=0; + + for (i=0; i<num_st; i++) + if (!iso[i].uvoid && iso[i].num) { + uncovered += iso[i].num - 1; + } + + append=0; + while (uncovered > 0) { + max_id=0; + max_weight = 0; + for (i=0, maxi=0; i<user.stat.base_max; i++) { + int small_num; + + point = 0; + weight = 0; + for (j=0; j<max[i]->num; j++) { + index=max[i]->state[j]; + if (!iso[index].uvoid && iso[index].num) { + point++; + weight += iso[index].num; + } + } + if (!point) + continue; + if (point > maxi) { + max_weight = weight; + maxi=point; + max_id=i; + small_num = max[i]->num; + } + else + if (point == maxi) { +/* + if (max[max_id]->class.many > max[i]->class.many) { + max_weight = weight; + maxi=point; + max_id=i; + small_num = max[i]->num; + } + else + if (max[max_id]->class.many == max[i]->class.many) + if (max[i]->num < small_num) { + max_weight = weight; + maxi=point; + max_id = i; + small_num = max[i]->num; + } +*/ + if (weight > max_weight) { + max_weight = weight; + maxi=point; + max_id = i; + small_num = max[i]->num; + } + else { + if (weight == max_weight) { + if (max[max_id]->class.many > max[i]->class.many) { + max_weight = weight; + maxi=point; + max_id=i; + small_num = max[i]->num; + } + else + if (max[max_id]->class.many == max[i]->class.many) + if (max[i]->class.many) { + if (max[i]->num < small_num) { + max_weight = weight; + maxi=point; + max_id = i; + small_num = max[i]->num; + } + } + else { + if (max[i]->num > small_num) { + max_weight = weight; + maxi=point; + max_id = i; + small_num = max[i]->num; + } + } + } + } + } + } + + /* How many states are covered by that maximal compatibles ? */ + + mini=num_st; + big=maxi; + maxi=0; + point=0; + + for (j=0; j<max[max_id]->num; j++) { + index=max[max_id]->state[j]; + if (!iso[index].uvoid && iso[index].num) { + base[point].state=index; + base[point++].where=j; + if (iso[index].num < mini) + mini=iso[index].num; + if (iso[index].num > maxi) + maxi=iso[index].num; + } + } + + for (i=0; i<maxi-1; i++) { + MEMCPY(max[user.stat.n_max]->state,max[max_id]->state, + sizeof(int)*max[max_id]->num); + max[user.stat.n_max]->num = max[max_id]->num; + + for (j=0; j<big; j++) { /* How many in a maximal compatible */ + int iso_id; + + if ((iso[base[j].state].num - 1) < i) { + iso_id=i % (iso[base[j].state].num); /* 0; */ +/* + iso[base[j].state].num=0; +*/ + } + else { + iso_id=i; + if (i < (iso[base[j].state].num - 1)) + uncovered--; + } +/* + printf("%d ",iso_id); +*/ + max[user.stat.n_max]->state[base[j].where]= + iso[base[j].state].list[iso_id]; + } + increase_max_num(); + one_implied(); +/* + printf("\n"); +*/ + } + for (j=0; j<big; j++) + iso[base[j].state].num=0; + } + if (FREE(base)) + panic("lint"); + max_close(); +} + +make_max(step) +{ + int i,newid; + + for (i=0; i<iso[base[step].state].num; i++) { + new_state[base[step].where]=iso[base[step].state].list[i]; + if (step) + make_max(step-1); + else { + MEMCPY(max[user.stat.n_max]->state,new_state,sizeof(int)*itsize); + max[user.stat.n_max]->num = itsize; + increase_max_num(); + } + } +} diff --git a/stamina/mimi/main.c b/stamina/mimi/main.c new file mode 100644 index 0000000..3b7fc68 --- /dev/null +++ b/stamina/mimi/main.c @@ -0,0 +1,188 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/main.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/14 08:35:22 $ + * + */ +/* SCCSID%W% */ +#include "user.h" +#include "util.h" +#include "struct.h" + +STATE **states; /* global variable: array of pointers to states */ +EDGE **edges; /* global variable: array of pointers to edges */ +int num_pi; /* number of primary inputs */ +int num_po; /* number of primary outputs*/ +int num_product; /* number of product terms */ +int num_st; /* number of states */ +char FSM_fileName[50]; /* the input state machine file name */ +char b_file[50]; +struct u user; +long t_start; + +static usage(char *); + +main(argc,argv) +char **argv; +{ + FILE *fp_input; /* open file for the state transition table */ + int step,clique; + int c; + int (**do_work)(); + int say_solution(); + extern int (*method1[])(); + + /* initialize some parameters for command line options */ + + FSM_fileName[0] = '\0'; + user.level = 8; + + /* parse command line arguments */ + + b_file[0] = 0; + user.oname = NIL(char); + user.opt.hmap=4; + user.opt.solution=0; + user.opt.verbose = 0; + user.cmd.merge = 0; + user.cmd.shrink = 0; + user.cmd.trans = 0; + + while ((c = util_getopt(argc, argv, "tcrhSRCMPs:m:b:v:o:")) != EOF) { + switch(c) { + case 's': + if ((user.opt.solution=atoi(util_optarg)) > 3) + user.opt.solution = 1; + break; + case 't': + user.cmd.trans = 1; + break; + case 'h': + usage(argv[0]); + break; + case 'o': + if (!(user.oname = ALLOC(char,strlen(util_optarg)+1))) + panic("main"); + (void) strcpy(user.oname,util_optarg/*,strlen(util_optarg)*/); + break; + case 'r': + user.cmd.merge = 1; + break; + case 'S': + user.cmd.shrink = 1; + break; + case 'm': + if ((user.opt.hmap=atoi(util_optarg)) > 4) + user.opt.hmap=0; + break; + case 'b': + (void) strcpy(b_file,util_optarg); + break; + case 'v': + user.opt.verbose = atoi(util_optarg); + break; + case 'R': + user.level=7; + method1[8]=say_solution; + break; + case 'M': + user.level = 5; + method1[5]=(int (*)())0; + break; + case 'P': + user.level = 6; + method1[6]=(int (*)())0; + break; + case 'C': + method1[1]=(int (*)())0; + break; + default: + usage(argv[0]); + break; + } + } + + + if (argc - util_optind == 0) { + fp_input = stdin; + } + else + if (argc - util_optind == 1) { + (void) strcpy(FSM_fileName, argv[util_optind]); + user.fname=FSM_fileName; + /*** + *** read the FSM state transition table and build the flow table + ***/ + if ( (fp_input = fopen (FSM_fileName, "r" )) == NULL ) { + (void) fprintf(stderr, "XCould not open %s \n", FSM_fileName ); + exit (1); + } + } + else { + usage(argv[0]); + } + + read_fsm(fp_input); + + t_start=util_cpu_time(); + + step=0; + + for (do_work=method1; *do_work; do_work++) { + user.ltime[step++]=util_cpu_time(); + (**do_work)(); + } + return 0; +} + +#ifdef DEBUG +dump_flow_table() +{ + register i; + EDGE *next_edge; + + (void) printf("***** FLOW TABLE *****\n"); + for (i=0; i<num_st; i++) { + (void) printf("%d %s ",i,states[i]->state_name); + next_edge = states[i]->edge; + while (next_edge != NIL(EDGE)) { + if (next_edge->n_star) + (void) printf("Input %s Output %s Next State *\n", + next_edge->input ,next_edge->output + ); + else + (void) printf("Input %s Output %s Next State %s\n", + next_edge->input ,next_edge->output, + next_edge->n_state->state_name); + next_edge = next_edge->next; + } + } +} +#endif + +static +usage(prog) +char *prog; +{ +/* + (void) fprintf(stderr, " -CMPR\tCompatible,Maximal,Prime,Reduce\n"); + (void) fprintf(stderr, " -b bfile\tsave binate covering matrix\n"); +*/ + (void) fprintf(stderr, "Usage: %s [options] [file]\n", prog); + (void) fprintf(stderr, " -s n\t\tminimization heuristics(1,2,3)\n"); + (void) fprintf(stderr, " -m n\t\tmapping heuristics(1,2,3,4)\n"); + (void) fprintf(stderr, " -v n\t\tset verbose level to 'n' (e.g., 5)\n"); + (void) fprintf(stderr, " -o filename\tset output file name\n"); + (void) fprintf(stderr, " -h\t\tprint this message\n"); + exit(0); +} + +panic(msg) +char *msg; +{ + (void) fprintf(stderr,"Panic: %s in %s\n",msg,FSM_fileName); + exit(1); +} diff --git a/stamina/mimi/map.c b/stamina/mimi/map.c new file mode 100644 index 0000000..073685b --- /dev/null +++ b/stamina/mimi/map.c @@ -0,0 +1,868 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/map.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/* SCCSID %W% */ +#include "user.h" +#include "util.h" +#include "struct.h" +#include "global.h" +#include "merge.h" +#include "stack.h" +#include "max.h" +#include "sparse.h" +#include "sparse_int.h" + +P_EDGE **r_states; +static char *r_out; +extern int *b_cover; +extern int *c_cover; +extern NLIST *_head; + +map() +{ + register i; + + user.stat.shrink = 0; + if (user.cmd.shrink) + shrink_prime(); + + user.stat.map_alternative=0; + user.stat.map_total=0; + + if (!(r_states=ALLOC(P_EDGE *,user.stat.nstates))) + panic("map x"); + for (i=0; i<user.stat.nstates; i++) + r_states[i]=NIL(P_EDGE); + form_new_flow_table(); + heuristics(); + if (/*(user.stat.product > 10000) ||*/ (user.cmd.merge)) + merge_product(); + write_new_machine(); +} + +form_new_flow_table() +{ + register i,j; + int s_num; + int s_ptr; + IMPLIED flow_imply; + int *new_ptr; + NLIST *link; + int *store; + + if (!(r_out=ALLOC(char,num_po+1))) + panic("r_out"); + user.stat.product = 0; + if (!(store=ALLOC(int,user.stat.nstates))) + panic("Form_flow"); + for (link=_head; link; link=link->h_next) { + P_EDGE *start; + + start=NIL(P_EDGE); + for (i=0; b_cover[i] != -1; i++) { /* For all closed cover */ + P_EDGE *n_edge; + + s_ptr=0; + if (s_num=set_nstate(link,b_cover[i],r_out)) { + if (s_num == -1) + continue; + flow_imply.num=s_num; + flow_imply.state=local_state; + for (j=0; b_cover[j] != -1; j++) { + if (contained(&flow_imply,prime[b_cover[j]])) { + store[s_ptr++]=j; /* b_cover[j]; */ + } + } + if (!s_ptr) { + for (j=0; j<user.stat.ostates; j++) + if (c_cover[j] == flow_imply.state[0]) { + store[0] = user.stat.nstates + j; + s_ptr=1; + break; + } + if (!s_ptr) + panic("Mapping"); + } + if (!(new_ptr=ALLOC(int,s_ptr))) + panic("new_ptr"); + MEMCPY(new_ptr,store,sizeof(int)*s_ptr); + } + n_edge=ALLOC(P_EDGE,1); + user.stat.product++; + n_edge->input=link->name; + n_edge->output= r_out; + if (!(r_out=ALLOC(char,num_po+1))) + panic("r_out"); + n_edge->n_state=(STATE *)new_ptr; + n_edge->p_state=(STATE *)&r_states[i]; + n_edge->p_star=s_ptr; + if (s_num) + n_edge->n_star=0; + else + n_edge->n_star=1; + n_edge->h_next=n_edge->v_next=NIL(P_EDGE); + + if (start) { + P_EDGE *v_next; + + v_next=start; + while (v_next->v_next) { + v_next=v_next->v_next; + } + v_next->v_next=n_edge; + } + else + start = n_edge; + + if (r_states[i]) { + P_EDGE *h_next; + + h_next=r_states[i]; + while (h_next->h_next) + h_next=h_next->h_next; + h_next->h_next=n_edge; + } + else { + r_states[i]=n_edge; + } + } + link->ptr=(int *)start; + } + + flow_imply.num=1; + flow_imply.state=local_state; + + for (i=0; i<user.stat.ostates; i++) { + EDGE *eedge; + + eedge=states[c_cover[i]]->edge; + while (eedge) { + user.stat.product++; + if (!eedge->n_star) { + local_state[0] = eedge->n_state->state_index; + s_ptr=0; + for (j=0; b_cover[j] != -1; j++) { + if (contained(&flow_imply,prime[b_cover[j]])) { + store[s_ptr++]=j; + } + } + if (s_ptr) { + if (s_ptr == 1) + eedge->n_state=(STATE *)store[0]; + else { + if (!(new_ptr=ALLOC(int,s_ptr))) + panic("new_ptr"); + MEMCPY(new_ptr,store,sizeof(int)*s_ptr); + eedge->n_state=(STATE *)new_ptr; + } + } + else { + for (j=0; j<user.stat.ostates; j++) { + if (eedge->n_state->state_index == c_cover[j]) { + eedge->n_state=(STATE *) (user.stat.nstates + j); + s_ptr = 1; + break; + } + } + if (!s_ptr) + panic("map incomp"); + } + eedge->p_star=s_ptr; + } + eedge=eedge->next; + } + } +} +int *vtbl_state; +int *htbl_state; + +heuristics() +{ + int i,j,index; + NLIST *link; + float quality; + int max_weight, total_weight; + int h_index; + + vtbl_state=ALLOC(int,user.stat.rstates); + htbl_state=ALLOC(int,user.stat.rstates); + + max_weight=total_weight=0; + for (link=_head; link; link=link->h_next) { + P_EDGE *v_next; + + v_next=(P_EDGE *) link->ptr; + + while (v_next) { + int maxi,pres; + + for (i=0; i<user.stat.nstates; i++) + if (v_next->p_state == (STATE *)&r_states[i]) { + pres=i; + break; + } + + if (v_next->p_star > 1) { + user.stat.map_alternative++; + user.stat.map_total += v_next->p_star; + if (user.opt.hmap) { + + column_sum(v_next->output,link,1,0); + row_sum(v_next,pres); + maxi= -1; +/* + index=((int *)(v_next->n_state))[0]; +*/ + for (i=0; i<v_next->p_star; i++) { + int num,my_weight; + + num=((int *)(v_next->n_state))[i]; + + if (user.opt.hmap == 4) { + my_weight = htbl_state[num]; + if (maxi < my_weight) { + maxi=my_weight; + index=num; + } +/* + else + if (maxi == my_weight) { + if ((vtbl_state[num]*htbl_state[num]) > + (vtbl_state[index] * htbl_state[index])) + index = num; + } +*/ + } + else { + my_weight = htbl_state[num] + vtbl_state[num]; + total_weight += my_weight; + if (maxi < my_weight) { + maxi=my_weight; + if (max_weight < maxi) + max_weight = maxi; + index=num; + } + } + } + + if (user.opt.hmap == 4) { + h_index = index; + maxi = -1; + for (i=0; i<v_next->p_star; i++) { + int num,my_weight; + + num=((int *)(v_next->n_state))[i]; + my_weight = vtbl_state[num]*htbl_state[num]; + total_weight += my_weight; + if (max_weight < my_weight) + max_weight = my_weight; + my_weight = vtbl_state[num]; + if (maxi < my_weight) { + maxi=my_weight; +/* + if (max_weight < maxi) + max_weight = maxi; +*/ + index=num; + } +/* + else + if (maxi == my_weight) { + if ((vtbl_state[num]*htbl_state[num]) > + (vtbl_state[index] * htbl_state[index])) + index = num; + } +*/ + + } + if (h_index != index) { + if ((vtbl_state[h_index]*htbl_state[h_index]) > + (vtbl_state[index] * htbl_state[index])) + index = h_index; + } + } + ((int *)(v_next->n_state))[0]=index; + } + v_next->p_star=1; + } + v_next=v_next->v_next; + } + } + + for (i=0; i<user.stat.ostates; i++) { + EDGE *eedge; + + eedge=states[c_cover[i]]->edge; + while (eedge) { + int maxi; + + if (eedge->p_star>1) { + user.stat.map_alternative++; + user.stat.map_total += eedge->p_star; + if (user.opt.hmap) { + incomp_column_sum(eedge); + incomp_row_sum(c_cover[i],eedge); + maxi= -1; + for (j=0; j<eedge->p_star; j++) { + int num,my_weight; + + num=((int *)(eedge->n_state))[j]; + if (user.opt.hmap == 4) { + my_weight=htbl_state[num]; + if (maxi < my_weight) { + maxi=my_weight; + index=num; + } + } + else { + my_weight=htbl_state[num] + vtbl_state[num]; + total_weight += my_weight; + if (maxi < my_weight) { + maxi=my_weight; + index=num; + if (max_weight < maxi) + max_weight = maxi; + } + } + + } + if (user.opt.hmap == 4) { + + h_index = index; + maxi = -1; + for (j=0; j<eedge->p_star; j++) { + int num,my_weight; + + num=((int *)(eedge->n_state))[j]; + + my_weight= vtbl_state[num]*htbl_state[num]; + total_weight += my_weight; + if (max_weight < my_weight) + max_weight = my_weight; + my_weight= vtbl_state[num]; + + if (maxi < my_weight) { + maxi=my_weight; + index=num; +/* + if (max_weight < maxi) + max_weight = maxi; +*/ + } + } + if (h_index != index) { + if ((vtbl_state[h_index]*htbl_state[h_index]) > + (vtbl_state[index] * htbl_state[index])) + index = h_index; + } + } + eedge->n_state=(STATE *)index; + } + else + eedge->n_state=(STATE *)((int *)(eedge->n_state))[0]; + eedge->p_star=1; + } + eedge=eedge->next; + } + } + + if (total_weight) + user.stat.quality = + (float)(max_weight*user.stat.map_total)/(float)(total_weight); +} + +merge_product() +{ + FILE *fp; + char *line; + int i,j,index; + NLIST *link; + + for (i=0; i<user.stat.nstates; i++) { + + P_EDGE *h_next; + + h_next=(P_EDGE *) r_states[i]; + + while (h_next) { + P_EDGE *h_last; + P_EDGE *h_prev; + + h_last = (P_EDGE *) r_states[i]; + h_prev = (P_EDGE *) r_states[i]; + + while (h_last) { + int position, count; + + if (h_next == h_last) { + h_last = h_last->h_next; + h_prev = h_next; + continue; + } + + if ((((int *)(h_next->n_state))[0] == + ((int *)(h_last->n_state))[0]) && + !conflict(h_next->output,h_last->output)) { + position=0; + count=0; + for (j=0; j<num_pi; j++) { + switch (h_last->input[j] - h_next->input[j]) { + case 0: + break; + case 1: + case -1: + if (count) { + j=num_pi+1; + count = 0; + } + else { + count++; + position=j; + } + break; + default: + j=num_pi; + count=0; + break; + } + } + if (count) { + + user.stat.product--; + h_next->input =ALLOC(char, num_pi+1); + (void) strncpy(h_next->input,h_last->input,num_pi+1); + (void) strncpy(h_next->output,r_out,num_po); + + h_next->input[position] = '-'; + + if (h_last == r_states[i]) { + r_states[i] = h_last->h_next; + } + else + h_prev->h_next=h_last->h_next; +/* + FREE(h_last); +*/ + h_last->p_star = 2; + h_last = (P_EDGE *) r_states[i]; + h_prev = (P_EDGE *) r_states[i]; + } + else { + h_prev = h_last; + h_last = h_last->h_next; + } + } + else { + h_prev=h_last; + h_last=h_last->h_next; + } + + } + h_next=h_next->h_next; + } + } +} + + +write_new_machine() +{ + FILE *fp; + int i,j,index; + NLIST *link; + +/* + if (!(line=ALLOC(char,num_pi+num_po+user.stat.rstates+20))) + panic("write"); +*/ + + if (user.oname) + fp=fopen(user.oname,"w"); + else + fp=stdout; + (void) fprintf(fp,"# FSM Reduction and mapping (C) Univ. of Colorado VLSI\n"); + (void) fprintf(fp,".i %d\n",num_pi); + (void) fprintf(fp,".o %d\n",num_po); + (void) fprintf(fp,".p %d\n",user.stat.product); + (void) fprintf(fp,".s %d\n",user.stat.rstates); + + if (user.stat.reset) { + index = -1; + for (i=0; i<user.stat.nstates; i++) { + for (j=0; j<SMASK(prime[b_cover[i]]->num); j++) { + if (!prime[b_cover[i]]->state[j]) { + index = i; + break; + } + } + if (index > -1) + break; + } + if (index < 0) { + for (i=0; i<user.stat.ostates; i++) + if (!c_cover[i]) { + index = user.stat.nstates + i; + } + } + if (index < 0) + panic("reset"); + else { + (void) fprintf(fp, ".r S%d\n",index); + } + } + + for (link=_head; link; link=link->h_next) { + P_EDGE *v_next; + + v_next=(P_EDGE *) link->ptr; + + while (v_next) { + int maxi,pres; + + for (i=0; i<user.stat.nstates; i++) + if (v_next->p_state == (STATE *)&r_states[i]) { + pres=i; + break; + } + + if (v_next->p_star > 1) { + v_next=v_next->v_next; + continue; + } + if (v_next->n_star) + (void) fprintf(fp,"%s S%d * %s\n",v_next->input,pres, + v_next->output); + else + (void) fprintf(fp,"%s S%d S%d %s\n", v_next->input,pres, + ((int *)(v_next->n_state))[0],v_next->output); + v_next=v_next->v_next; + } + } + + for (i=0; i<user.stat.ostates; i++) { + EDGE *eedge; + + eedge=states[c_cover[i]]->edge; + while (eedge) { + + if (eedge->p_star>1) { + eedge=eedge->next; + continue; + } + + if (eedge->n_star) + (void) fprintf(fp,"%s S%d * %s\n", eedge->input, + user.stat.nstates+i,eedge->output); + else + (void) fprintf(fp,"%s S%d S%d %s\n", eedge->input, + user.stat.nstates+i,(int)eedge->n_state,eedge->output); + eedge=eedge->next; + } + } + + (void) fprintf(fp,".e\n"); + + (void) fclose(fp); +} + +incomp_row_sum(wstate,product) +EDGE *product; +{ + int i,w; + EDGE *h_next; + + for (i=0; i<user.stat.rstates; i++) { + htbl_state[i]=0; + } + + h_next=states[wstate]->edge; + while (h_next) { + if (!h_next->n_star /* && (h_next != product) */ ) { + switch (user.opt.hmap) { + case 1: + case 2: + w = 1; + break; + case 3: + case 4: + w = literal_intersect(h_next->input,product->input,num_pi, + '1'); + w += literal_intersect(h_next->output,product->output,num_po, + '1'); + break; + } + if (h_next->p_star > 1) + for (i=0; i<h_next->p_star; i++) + htbl_state[((int *)(h_next->n_state))[i]] += w; + else +/* + htbl_state[((int *)(h_next->n_state))[0]]++; +*/ + htbl_state[(int)h_next->n_state] += w; + } + h_next=h_next->next; + } +} + +incomp_column_sum(eedge) +EDGE *eedge; +{ + int i,j; + NLIST *link; + + for (i=0; i<user.stat.rstates; i++) { + vtbl_state[i]=0; + } + for (i=0; i<user.stat.ostates; i++) { + EDGE *tedge; + + if (c_cover[i] == eedge->p_state->state_index) + continue; + tedge=states[c_cover[i]]->edge; + while (tedge) { + int w; + + if (!tedge->n_star) + if (w=intersection(eedge->input,tedge->input,num_pi)) { + switch (user.opt.hmap) { + case 1: + w = 1; + break; + case 2: + break; + case 3: + case 4: + w = literal_intersect(eedge->input,tedge->input, + num_pi,'-'); + w += literal_intersect(eedge->output,tedge->output, + num_po,'1'); + break; + } + if (eedge->p_star>1) { + for (j=0; j<eedge->p_star; j++) + vtbl_state[((int *)(eedge->n_state))[j]] += w; + } + else +/* + vtbl_state[((int *)(eedge->n_state))[0]] += w; +*/ + vtbl_state[(int )eedge->n_state] += w; + } + tedge=tedge->next; + } + } + for (link=_head; link; link=link->h_next) { + int w; + + if (w=intersection(link->name,eedge->input,num_pi)) { + if (user.opt.hmap > 2) + w=literal_intersect(link->name,eedge->input,num_pi,'-'); + column_sum(eedge->output,link,0,w); + } + } +} + +cube_weight(cube,factor) +char *cube; +{ + register i, weight; + + weight = 1; + for (i=0; i<num_pi; i++) { + if (cube[i] == '-') + if (factor) + weight += 1; + else + weight *= 2; + } + return weight; +} + +column_sum(output,link,flag,column_weight) +char *output; +NLIST *link; +{ + register i,j; + P_EDGE *v_next; + + if (flag) { + for (i=0; i<user.stat.rstates; i++) { + vtbl_state[i]=0; + } + } + switch (user.opt.hmap) { + case 1: + column_weight = 1; + break; + case 2: + if (flag) + column_weight=cube_weight(link->name,0); + break; + case 3: + case 4: + if (flag) + column_weight=cube_weight(link->name,1); + break; + } + v_next=(P_EDGE *)link->ptr; + + while (v_next) { + if (!v_next->n_star) + for (j=0; j<v_next->p_star; j++) { + vtbl_state[((int *)(v_next->n_state))[j]] += column_weight; + if (user.opt.hmap > 2) + vtbl_state[((int *)(v_next->n_state))[j]] += + literal_intersect(output,v_next->output,num_po,'1'); + } + v_next=v_next->v_next; + } + if (flag) + for (j=0; j<user.stat.ostates; j++) { + EDGE *eedge; + + eedge=states[c_cover[j]]->edge; + while (eedge) { + int w; + + if (!eedge->n_star) { + if (eedge->p_star) + if (w=intersection(link->name,eedge->input,num_pi)) { + switch (user.opt.hmap) { + case 1: + w = 1; + break; + case 3: + case 4: + w=literal_intersect(output,eedge->output, + num_po,'1'); + w += literal_intersect(link->name, + eedge->input,num_pi,'-'); + break; + default: + break; + } + if (eedge->p_star > 1) + for (i=0; i<eedge->p_star; i++) { + vtbl_state[((int *)(eedge->n_state))[i]]+=w; + } + else + vtbl_state[(int)eedge->n_state] += w; + } + } + eedge=eedge->next; + } + } +} + +row_sum(product,wstate) +P_EDGE *product; +{ + int i; + P_EDGE *h_next; + + for (i=0; i<user.stat.rstates; i++) { + htbl_state[i]=0; + } + + h_next=r_states[wstate]->h_next; + while (h_next) { + int w; + + if (!h_next->n_star /*&& (h_next != product)*/) { + switch (user.opt.hmap) { + case 1: + case 2: + w = 1; + break; + case 3: + case 4: + w =literal_intersect(h_next->input,product->input,num_pi,'1'); + w+=literal_intersect(h_next->output,product->output,num_po,'1'); + break; + } + for (i=0; i<h_next->p_star; i++) + htbl_state[((int *)(h_next->n_state))[i]] += w; + } + h_next=h_next->h_next; + } +} + +#ifdef DEBUG +dump_new_table() +{ + register i,j; + NLIST *link; + + for (i=0; i<user.stat.nstates; i++) { + printf("*** state%d \n",i); + for (link=_head; link; link=link->h_next) { + P_EDGE *v_next; + + printf("Input %s : ",link->name); + v_next=(P_EDGE *)link->ptr; + while (v_next) { + if (v_next->p_state==(STATE *)(&r_states[i])) { + for (j=0; j<v_next->p_star; j++) { + printf("state%d ",((int *)(v_next->n_state))[j]); + } + printf("\n"); + } + v_next=v_next->v_next; + } + } + } +} +#endif + +conflict(str1,str2) +char str1[], str2[]; +{ + register i; + + for (i=0; i<num_po; i++) { + switch ((str1[i] - str2[i])) { + case 0: + r_out[i] = str1[i]; + break; + case 1: + case -1: + return 1; + default: + r_out[i] = (str1[i] == '-') ? str2[i] : str1[i]; + break; + } + } + return 0; +} + +literal_intersect(str1,str2,width,xchar) +char *str1, *str2; +char xchar; +{ + register i; + int count; + + count = 0; + for (i=0; i< width; i++) { + switch ((str1[i] - str2[i])) { + case 0: + if (str1[i] == xchar) + count++; + break; + case 1: + case -1: + break; + default: + break; +/* + return 0; +*/ + } + } + return count; +} diff --git a/stamina/mimi/max.c b/stamina/mimi/max.c new file mode 100644 index 0000000..04e4961 --- /dev/null +++ b/stamina/mimi/max.c @@ -0,0 +1,286 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/max.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/* SCCSID %W% */ +#include "user.h" +#include "util.h" +#include "struct.h" +#include "global.h" +#include "merge.h" +#include "stack.h" +#include "max.h" + +PRIMES max; +extern struct isomor *iso; +extern int *b_cover; + +maximal_compatibles() +{ + register i,j,k,m,l; + int stop_i; + + max = (PRIMES) 0; + alloc_max_block(0); + k = 0; + + user.stat.n_max = 0; + + stop_i= -1; + for (i=num_st-2; i>stop_i; i--) { /* Column indexing */ + + for (j=num_st-1; j>i; j--) { /* Row indexing */ + if (!iso[i].uvoid && !iso[j].uvoid) { + if (xstack[k].status & COMPATIBLE) { + /* 0 level compatible */ + max[user.stat.n_max]->state[0] = i; + max[user.stat.n_max]->state[1] = j; + max[user.stat.n_max]->num = 2; + increase_max_num(); + stop_i=i; + } + } + k++; + } + } + for (/*i*/; i>-1; i--) { /* Column indexing */ + + if (!iso[i].uvoid) { + + enlarge_or_add(i); + + for (l=0; l<user.stat.n_max; l++) + for (j=l+1; j<user.stat.n_max; j++) { + PRIME *temp_max; + + if ((k=included(l,j)) != -1) { + temp_max = max[k]; + user.stat.n_max--; + max[k] = max[user.stat.n_max]; + max[user.stat.n_max] = temp_max; + if (k==l) { + l--; + break; + } + j--; + } + } + } + } + + free_stack_head(); + + /* High bound */ + + if (user.stat.n_iso && (user.opt.solution < 2)) + iso_generate(); + user.stat.high = user.stat.n_max > num_st ? num_st : user.stat.n_max; +} + +bound() +{ + register i,k; + + get_implied(); + + switch (user.opt.solution) { + case 2: /* From the base maximal compatibles */ + case 3: /* Entirely for jac4 */ + if (user.stat.n_iso) { + iso_close(user.stat.n_iso); + if (user.opt.solution == 2) + break; + } + case 1: /* binate covering to maximal */ + user.stat.low=max_cover(0); + if (user.stat.low == (user.stat.high=max_cover(1))) { + prime = max; + p_num = user.stat.n_max; + make_null(5); + make_null(6); + } + else { + i=0; + while (b_cover[i] != -1) { + max[i]=max[b_cover[i]]; + i++; + } + user.stat.n_max=i; + } + default: + if (user.level > 6) { + user.stat.low=max_cover(0); + if (is_it_closed()) { + prime = max; + p_num = user.stat.n_max; + make_null(5); + make_null(6); + } + } + break; + } + + if (user.opt.verbose>1) + say_max(); +} + +included(i,j) +{ + register k,l; + int small,big,not_match; + + if (max[i]->num > max[j]->num) { + small = j; + big = i; + } + else { + small = i; + big = j; + } + + for (k=0; k < max[small]->num; k++) { + not_match = 1; + for (l=0; l<max[big]->num; l++) { + if (max[small]->state[k] == max[big]->state[l]) { + not_match = 0; + break; + } + } + if (not_match) + return -1; + } + return small; +} + +enlarge_or_add(column) +{ + register i,j,pair; + int stop,id; + int work; + int state1, state2; + +#ifdef DEBUG + (void) printf("enlarge_or_add %d max_com %d\n",column,user.stat.n_max); +#endif + stop = user.stat.n_max; + for (i=0; i<stop; i++) { + pair = 0; + work = user.stat.n_max; + for (j=0; j<max[i]->num; j++) { + state1=column; + state2 = max[i]->state[j]; + id = (num_st-state1-2)*(num_st-state1-1)/2-state2+num_st-1; + if (xstack[id].status & COMPATIBLE) { + max[user.stat.n_max]->state[pair++] = max[i]->state[j]; + } + } + if (pair > 1) { + max[user.stat.n_max]->state[pair] = column; + if (pair == max[i]->num) { + max[i]->state[pair] = column; + max[i]->num++; + } + else { + max[user.stat.n_max]->num = pair+1; + increase_max_num(); + } + for (j=0; j<pair; j++) { + state1=max[work]->state[j]; /* temp_max[j]; */ + state2 = column; + id = (num_st-state2-2)*(num_st-state2-1)/2-state1+num_st-1; + xstack[id].status |= USED; + } + } + } + for (i=num_st-1; i>column; i--) { + if (!iso[i].uvoid) { + state2=i; + state1 = column; + id = (num_st-state1-2)*(num_st-state1-1)/2-state2+num_st-1; + if (!(xstack[id].status & USED) && + (xstack[id].status & COMPATIBLE)) { + max[user.stat.n_max]->state[0] = i; + max[user.stat.n_max]->state[1] = column; + max[user.stat.n_max]->num = 2; + increase_max_num(); + } + } + } +} + +alloc_max_block(max_size) +{ + register i,xsize; + + xsize = sizeof(PRIME) + sizeof(int)*(num_st - 1); + if (max_size) { + if (!(max = REALLOC(PRIME *,max, max_size+N_MAX))) + panic("alloc20"); + } + else { + if (!(max = ALLOC(PRIME * ,N_MAX))) + panic("alloc21"); + } + +/* + if (!(max[max_size] = (PRIME *) ALLOC(char, + (sizeof(PRIME) + sizeof(int)*(num_st - 1))* N_MAX))) + panic("alloc22"); + + for (i=0 ; i< N_MAX; i++) { + max[i+max_size] = (PRIME *)((int)max[max_size] + xsize*i); + max[i+max_size]->state = (int *)((int)max[i+max_size] + + sizeof(PRIME)); + } +*/ + for (i=0 ; i< N_MAX; i++) { + if (!(max[i+max_size] = ALLOC(PRIME,1))) + panic("alloc_max"); + if (!(max[i+max_size]->state = ALLOC(int,num_st - 1))) + panic("alloc_max"); + } +} + +increase_max_num() +{ + static limit=N_MAX; + + user.stat.n_max++; + if (user.stat.n_max == limit) { + alloc_max_block(limit); + limit += N_MAX; + } +} + + +is_it_closed() +{ + register i,j,k,id; + int *max_base; + + for (i=0; i<user.stat.nstates; i++) { + id=b_cover[i]; + + for (j=0; j<max[id]->class.many; j++) { + int not_closed; + + not_closed=1; + for (k=0; k<user.stat.nstates; k++) { + if (contained(max[id]->class.imply[j],max[b_cover[k]])) { + not_closed=0; + break; + } + } + + if (not_closed) { + return 0; + } + } + } + return 1; +} diff --git a/stamina/mimi/max.h b/stamina/mimi/max.h new file mode 100644 index 0000000..fcfb468 --- /dev/null +++ b/stamina/mimi/max.h @@ -0,0 +1,52 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/max.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/* SCCSID %W% */ + +#define CONDITIONAL_COMPATIBLE 1 +#define DEFINIT_COMPATIBLE 2 +#define COMPATIBLE 3 +#define INCOMPATIBLE 4 +#define USED_AND_COMPATIBLE 0x1b +#define USED 16 +#define N_MAX 100 /* Number of Maximal Compatibles */ +#define DONTCARE '-' + +typedef struct maxies PRIME, **PRIMES; +typedef struct implied_states IMPLIED; +typedef struct top_implied CLASS; + +struct top_implied { + IMPLIED **imply; + int many; + int weight; +}; + +struct maxies { + int num; + int *state; + CLASS class; +}; + +struct implied_states { + int num; + int *state; +}; + + +#define MAX_PRIME 4084 +#define SMASK(x) (x & 0x7fff) +#define SELECTED 0x8000 +#define FOREVER 1 + +extern p_num; +extern PRIMES prime; +extern PRIMES max; +extern IMPLIED **local_imply; +extern int *local_state; diff --git a/stamina/mimi/merge.c b/stamina/mimi/merge.c new file mode 100644 index 0000000..2924f88 --- /dev/null +++ b/stamina/mimi/merge.c @@ -0,0 +1,264 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/merge.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/* SCCSID %W% */ +#include "user.h" +#include "util.h" +#include "struct.h" +#include "global.h" +#include "merge.h" +#include "stack.h" + +#define next_state_is_not_star !(edge1->n_star || edge2->n_star) +#define next_state n_state->state_index +#define implied_is_incompatible ptr1->status == INCOMPATIBLE +#define stack_status xstack[i].status +#define num_of_compatible j + +merge() +{ + register i,j,id; + int changed; + int merge_entry; + + merge_entry=(num_st-1)*num_st/2; + + for (i=0; i<num_st; i++) { + (void) input_intersection(states[i],states[i]); + } + + alloc_stack(merge_entry); + id = 0; + for (i=num_st-2; i>-1; i--) + for (j=num_st-1; j>i; j--) { + + init_stack(id); +#ifdef DEBUG + (void) printf("### %s %s ",states[i]->state_name,states[j]->state_name); +#endif + switch (input_intersection(states[i],states[j])) { + case INCOMPATIBLE: + close_stack(id,INCOMPATIBLE); + break; + case DEFINIT_COMPATIBLE: + close_stack(id,DEFINIT_COMPATIBLE); + break; + case CONDITIONAL_COMPATIBLE: + pack_stack(id); + break; + default: + panic("Coding Error"); + break; + } + id++; + } + + do { + STACK *ptr1; + + changed = 0; + num_of_compatible = 0; + for (i=0; i<merge_entry; i++) { + if (stack_status == CONDITIONAL_COMPATIBLE) { + open_stack(i); + while (ptr1 = pop()) { + if (implied_is_incompatible) { + free_stack(i,INCOMPATIBLE); + changed = 1; + break; + } + } + } + if (stack_status & COMPATIBLE) + num_of_compatible++; + } + } while (changed); + + user.stat.n_compatible = num_of_compatible; +/* + printf("N EDGE %d\n",num_of_compatible); +*/ + + id=0; + changed=0; + + for (i=num_st-2; i>-1; i--) { /* Column indexing */ + for (j=num_st-1; j>i; j--) { /* Row indexing */ + + if (xstack[id].status & COMPATIBLE) { + states[i]->assigned=states[j]->assigned=1; + if (user.opt.verbose > 10) + (void) fprintf(stderr,"Compatible pair %d : %s %s : %x\n",changed++, + states[i]->state_name,states[j]->state_name,xstack[id].status); + } + id++; + } + } + + if (!user.stat.n_compatible) { + flushout(); + if (user.opt.verbose) + fprintf(stderr,"No compatible states\n"); + exit(0); + } +#ifdef DEBUG + if (user.opt.verbose > 3) + (void) printf("Number of Compatible pairs %d\n",user.stat.n_compatible); + for (i=0; i<num_st; i++) { + (void) printf("\n%s : ",states[i]->state_name); + for (j=0; j<num_st; j++) { + if (i != j) { + if (i>j) + id = (num_st-j-2)*(num_st-j-1)/2-i+num_st-1; + else + id = (num_st-i-2)*(num_st-i-1)/2-j+num_st-1; + if (xstack[id].status & COMPATIBLE) + (void) printf("%s, ",states[j]->state_name); + } + } + } +#endif +} + +input_intersection(state1,state2) +STATE *state1, *state2; +{ + EDGE *edge1, *edge2; + char *input1, *input2; + int self; + int pushed; + + pushed = 0; + edge1 = state1->edge; + if (state1 == state2) + self = 1; + else + self = 0; + while (edge1 != NIL(EDGE)) { + if (self) + edge2 = edge1->next; + else + edge2 = state2->edge; + while (edge2 != NIL(EDGE)) { + + if (intersection(edge1->input,edge2->input,num_pi)) { + + if (!intersection(edge1->output, edge2->output,num_po)) { + if (self) { + panic("Conflict Input intersection"); + } + else { + /* Incompatible pair of states */ + return INCOMPATIBLE; + } + } + else { + if (self) { + if ((edge2->next_state != edge1->next_state) || + (strcmp(edge1->output,edge2->output))) { + (void) fprintf(stderr,"### Input Intersection %s\n", + state1->state_name); + (void) fprintf(stderr,"state %s %s\n", + states[edge1->next_state]->state_name, + states[edge2->next_state]->state_name); + panic("Invalid specification"); + } +/* + else { + printf("Duplicated input %s\n",edge1->p_state->state_name); + printf("input %s %s\n",edge1->input,edge2->input); + printf("next_state %s\n",edge2->n_state->state_name); + } +*/ + } + else { + /* Conditionally compatible pair of states */ + if (next_state_is_not_star) + if (edge1->next_state != edge2->next_state) { + pushed = 1; + push(edge1->next_state,edge2->next_state); + } + } + } + } + edge2 = edge2->next; + } + edge1 = edge1->next; + } + if (pushed) + return CONDITIONAL_COMPATIBLE; + else + return DEFINIT_COMPATIBLE; +} + +intersection(cube1,cube2,bit) +char cube1[], cube2[]; +{ + register i; + int inter_minterm; + + inter_minterm = 1; + + for (i=0; i< bit; i++) { + switch ( cube1[i]-cube2[i]) { + case 0: /* Same input */ + if (cube1[i] == '-') + inter_minterm *= 2; + break; + case -1: /* Conflict input bit */ + case 1: + return 0; + default: /* One has don't care condition */ + break; + } + } + return inter_minterm; +} + +xintersection(cube1,cube2,bit,xnode) +NODE *xnode; +char cube1[], cube2[]; +{ + register i,add; + + add=0; + for (i=0; i< bit; i++) { + if (xnode->on_off[i]) { + switch ( cube1[i]-cube2[i]) { + case 0: /* Same input */ + break; + case -1: /* Conflict input bit */ + case 1: + return -1; + default: /* One has don't care condition */ + add++; + break; + } + } + } + return add; +} + +/* +int +power(base, exp) +int base, exp; +{ + int i, power; + power = 1; + i = 1; + while(i <= exp) + { + power = power*base; + i++; + } + + return(power); +} +*/ diff --git a/stamina/mimi/merge.h b/stamina/mimi/merge.h new file mode 100644 index 0000000..0c96e4f --- /dev/null +++ b/stamina/mimi/merge.h @@ -0,0 +1,17 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/merge.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/* SCCSID %W% */ + +#define CONDITIONAL_COMPATIBLE 1 +#define DEFINIT_COMPATIBLE 2 +#define COMPATIBLE 3 +#define INCOMPATIBLE 4 + +#define DONTCARE '-' diff --git a/stamina/mimi/misc.c b/stamina/mimi/misc.c new file mode 100644 index 0000000..567f381 --- /dev/null +++ b/stamina/mimi/misc.c @@ -0,0 +1,161 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/misc.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/* SCCSID %W% */ +#include "user.h" +#include "util.h" +#include "struct.h" +#include "global.h" +#include "merge.h" +#include "stack.h" +#include "max.h" +#include "sparse.h" +#include "sparse_int.h" + +char time_msg[][14]={"compatible","disjoint","iso","maximal", + "class & bound","prime", "binate_cover","map"}; + +extern int *b_cover; +extern int *c_cover; + +say_solution() +{ + sm_element *p; + register i,j,m,k; + extern long t_start; + int tmp_states; + long t_stop; + + if (!user.opt.verbose) + exit(0); + + t_stop=util_cpu_time(); + + (void) fprintf(stderr,"*** Solution for %s ***\n\n",user.fname); + + tmp_states = 0; + for (i=0; b_cover[i] != -1; i++) { /* For all closed cover */ + (void) fprintf(stderr,"state %2d: ",tmp_states); + tmp_states++; + + (void) fprintf(stderr,"("); + for (j=0; j<SMASK(prime[b_cover[i]]->num); j++) { + (void) fprintf(stderr,"%s",states[prime[b_cover[i]]->state[j]]->state_name); + if (j != SMASK(prime[b_cover[i]]->num)-1) + (void) fprintf(stderr,","); + } + (void) fprintf(stderr,")\n"); + } + for (i=0; i< user.stat.ostates; i++) { + (void) fprintf(stderr,"state %2d: (%s)\n", + tmp_states, states[c_cover[i]]->state_name); + tmp_states++; + } + (void) fprintf(stderr,"\n"); + for (i=0; i<user.level; i++) + (void) fprintf(stderr,"Lap time%d %s for %s\n",i+1, + util_print_time(user.ltime[i+1]-user.ltime[i]),time_msg[i]); + (void) fprintf(stderr,"Elapsed CPU Time %s\n",util_print_time(t_stop-t_start)); + if (user.opt.solution) { + (void) fprintf(stderr,"Lower bound %d\n",user.stat.low); + (void) fprintf(stderr,"Upper bound %d\n",user.stat.high); + } + (void) fprintf(stderr,"Mapping alternative in %d product %d total %f quality\n", + user.stat.map_alternative, user.stat.map_total,user.stat.quality); + (void) fprintf(stderr,"Number of shrinked states %d\n",user.stat.shrink); + (void) fprintf(stderr,"Number of input before disjoint %d\n",user.stat.xinput); + (void) fprintf(stderr,"Number of disjoint input %d\n",user.stat.disjoint); + (void) fprintf(stderr,"Number of isomorphic states %d\n",user.stat.n_iso); + (void) fprintf(stderr,"Number of compatible pairs %d\n",user.stat.n_compatible); + (void) fprintf(stderr,"Number of Maximal Compatibles %d\n",user.stat.n_max); + (void) fprintf(stderr,"Number of primes %d\n",p_num); + (void) fprintf(stderr,"Number of initial states %d\n",num_st); + (void) fprintf(stderr,"Number of incompatible states %d\n",user.stat.ostates); + if (user.level > 7) + (void) fprintf(stderr,"Number of products %d\n",user.stat.product); + else + (void) fprintf(stderr,"Number of products -\n"); + (void) fprintf(stderr,"Number of states after minimization %d\n",user.stat.rstates); + exit(0); +} + +say_max_only() +{ + int i,j; + + for (i=0; i<user.stat.n_max; i++) { + (void) fprintf(stderr,"Maximal %d (",i); + for (j=0; j<SMASK(max[i]->num); j++) { + (void) fprintf(stderr,"%s",states[max[i]->state[j]]->state_name); + if (j != SMASK(max[i]->num)-1) + (void) fprintf(stderr,","); + } + (void) fprintf(stderr,")\n"); + } +/* + user.ltime[2]=util_cpu_time(); + printf("Number of Maximal Compatibles %d\n",user.stat.n_max); + printf("Elapsed CPU Time %s\n", + util_print_time(user.ltime[2]-user.ltime[0])); + fflush(stdout); +*/ +} + + +say_max() +{ + int i,k,j,m; + + for (i=0; i<user.stat.n_max; i++) { + (void) fprintf(stderr,"Maximal %d (",i); + for (j=0; j<SMASK(max[i]->num); j++) { + (void) fprintf(stderr,"%s",states[max[i]->state[j]]->state_name); + if (j != SMASK(max[i]->num)-1) + (void) fprintf(stderr,","); + } + + (void) fprintf(stderr,")\nClass set : {"); + + if (max[i]->class.many) { + for (k=0,m=0; m<max[i]->class.many;k++) { +/* + printf("i %d, k %d, num %d\n",i,k,max[i]->class.imply[k]->num); +*/ + if (max[i]->class.imply[k]->num) { + m++; + (void) fprintf(stderr,"("); + for (j=0; j<max[i]->class.imply[k]->num; j++) { + (void) fprintf(stderr,"%s", + states[max[i]->class.imply[k]->state[j]]->state_name); + if (j != max[i]->class.imply[k]->num -1) + (void) fprintf(stderr,","); + } + (void) fprintf(stderr,")"); + } + } + } + (void) fprintf(stderr,"}\n"); + } +/* + printf("Elapsed CPU Time %s\n", + util_print_time(user.ltime[2]-user.ltime[1])); +*/ +} + +say_prime() +{ + int i; + + (void) fprintf(stderr,"\n"); + for (i=0; i<p_num; i++) { + write_prime(i); + write_imply(i); + } + (void) fprintf(stderr,"\n"); +} diff --git a/stamina/mimi/prime.c b/stamina/mimi/prime.c new file mode 100644 index 0000000..eda51b2 --- /dev/null +++ b/stamina/mimi/prime.c @@ -0,0 +1,292 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/prime.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/* SCCSID %W% */ +#include "user.h" +#include "util.h" +#include "struct.h" +#include "global.h" +#include "merge.h" +#include "stack.h" +#include "max.h" + +PRIMES prime; +PRIMES gen_list; +PRIME p_new; +int p_num; /* Number of Prime */ +static int num_literal=1; +int select_small(); + +prime_compatible() +{ + register i; + int last_prime; + int first; + + sort_max(); + if (!(prime=ALLOC(PRIME *,MAX_PRIME))) + panic("ALLOC in prime"); + gen_list = ALLOC(PRIME *,MAX_PRIME); + p_new.state = ALLOC(int,num_st); + p_new.num = 0; + + first = 0; + p_num = 0; +#ifdef DEBUG + (void) printf("Base %d\n",user.stat.base_max); +#endif + num_literal = max[0]->num; + do { + last_prime = select_big(); /* Select next maximal candidate */ + + if ((user.opt.solution == 3) && (first++ < 2)) + prime_from_prime(last_prime); + else + if (user.opt.solution != 3) + prime_from_prime(last_prime); + } while (--num_literal>1); + + if (user.cmd.trans) { + for (i=0; i<p_num; i++) + Find_Implied(prime,i); + } + if (user.opt.verbose > 1) + say_prime(); + FREE(gen_list); +} + +prime_from_prime(limit) +{ + register i; + + for (i=0; i<limit; i++) { + if (!(gen_list[i]->class.many)) + continue; + /* Generate prime from Maximal compatibles */ + enumerate_prime(gen_list[i],&p_new,num_literal-1,0,select_small); + } +} + +enumerate_prime(p_from,p_to,iter,start,service) +int (*service)(); +PRIME *p_from; /* Maximal compatible ID */ +PRIME *p_to; +{ + register i; + + for (i=start; i<SMASK(p_from->num)-iter+1; i++) { + /* select current level candidate */ + p_to->state[p_to->num]=p_from->state[i]; + p_to->num++; + if (iter<2) + (*service)(p_to); + else + enumerate_prime(p_from,p_to,iter-1,i+1,service); + p_to->num--; + } +} + + +select_small(p_where) +PRIME *p_where; +{ + register k,i,j; +/* + if (user.opt.solution == 3) { + for (j=0; j<user.stat.n_max; j++) { + if (p_where[p_prime] == max[j]) + break; + } + if ((j >= user.stat.base_max) && (j<user.stat.n_max)) + return 0; + } +*/ + /* If class set contains that of prime it is not prime */ + + prime[p_num]=p_where; + + if (user.cmd.trans) + transitive(prime,p_num); + else + Find_Implied(prime,p_num); + + /* I have implied class set in local Imply structure */ + + if (!p_exclude()) { + if (!(prime[p_num]=ALLOC(PRIME,1))) + panic("small"); + if (!(prime[p_num]->state=ALLOC(int,SMASK(p_where->num)))) + panic("small 2"); + memcpy(prime[p_num]->state,p_where->state,sizeof(int)*p_where->num); + prime[p_num]->num=p_where->num; + prime[p_num]->class=p_where->class; + p_num++; + } +} + +p_exclude() +{ + register i; + + /* Prime excluding */ + + for (i=0; i<p_num; i++) { + if (gp_exclude(i,p_num)) + return 1; /* Candidate is excluded by prime i */ + } + return 0; /* Candidate is new prime */ +} + +gp_exclude(g_prime,candidate) +/* g_prime: Given prime */ +/* candidate: Candidate prime */ +{ + register i,j,k,l,m; + int not_match; + int contained; + + /* Check prime contains candidate or not */ + + for (k=0; k <SMASK(prime[candidate]->num); k++) { + not_match = 1; + for (l=0; l<SMASK(prime[g_prime]->num); l++) { + if (prime[candidate]->state[k] == prime[g_prime]->state[l]) { + not_match = 0; + break; + } + } + if (not_match) + return 0; + } + + /* Yes prime contains candidate. Then check class set of candidate + contains that of given prime */ + + if (prime[g_prime]->class.many) { + if (!prime[candidate]->class.many) + return 0; + } + else { + return 1; + } + + for (i=0; i<prime[g_prime]->class.many; i++) { + for (k=0; k<prime[candidate]->class.many; k++) { + contained=0; + if (SMASK(prime[g_prime]->class.imply[i]->num) > + SMASK(prime[candidate]->class.imply[k]->num)) { + continue; + } + for (l=0; l<SMASK(prime[g_prime]->class.imply[i]->num); l++) { + not_match = 1; + for (m=0; m<SMASK(prime[candidate]->class.imply[k]->num); m++) { + if (prime[g_prime]->class.imply[i]->state[l] == + prime[candidate]->class.imply[k]->state[m]) { + not_match = 0; + break; + } + } + if (not_match) + break; + } + if (!not_match) { + contained=1; + break; + } + } + if (!contained) /* Don't exclude */ + return 0; + } + return 1; /* Exclude it */ +} + +sort_max() +{ + register i,j; + PRIME *save_max; + + for (i=0; i<user.stat.n_max; i++) { + for (j=i+1; j<user.stat.n_max; j++) { + if (max[i]->num < max[j]->num) { + save_max = max[i]; + max[i] = max[j]; + max[j] = save_max; + } + } + } + if (user.cmd.trans) + for (i=0; i<user.stat.n_max; i++) + transitive(max,i); +} + +select_big() +{ + register i; + int index; + static int max_id=0; + static int exhausted=0; + static int selected = 0; + + if (exhausted) + return selected; + + for (i=max_id; i<user.stat.n_max; i++) { + if (max[i]->num == num_literal) { + prime[p_num++] = max[i]; /* This is prime */ + gen_list[selected++]=max[i]; + } + else { + if (max[i]->num < num_literal) { + max_id=i; + break; + } + } + } + if (i==user.stat.n_max) + exhausted = 1; + + if (!(prime[p_num]=ALLOC(PRIME,1))) + panic("ALLOC in prime"); + + if (!(prime[p_num]->state = ALLOC(int,num_literal))) + panic("ALLOC in prime"); + + return selected; +} + +write_prime(pnum) +{ + register i; + + (void) fprintf(stderr,"*** Prime %d (",pnum); + for (i=0; i<SMASK(prime[pnum]->num); i++) { + (void) fprintf(stderr,"%s",states[prime[pnum]->state[i]]->state_name); + if (i != SMASK(prime[pnum]->num -1)) + (void) fprintf(stderr,","); + } + (void) fprintf(stderr,")\n"); +} + +write_imply(pnum) +{ + register i,j; + + (void) fprintf(stderr,"*** Class set {"); + + for (i=0; i<prime[pnum]->class.many; i++) { + (void) fprintf(stderr,"("); + for (j=0; j<prime[pnum]->class.imply[i]->num; j++) { + (void) fprintf(stderr,"%s",states[prime[pnum]->class.imply[i]->state[j]]->state_name); + if (j != prime[pnum]->class.imply[i]->num - 1) + (void) fprintf(stderr,","); + } + (void) fprintf(stderr,")"); + } + (void) fprintf(stderr,"}\n"); +} diff --git a/stamina/mimi/read_fsm.c b/stamina/mimi/read_fsm.c new file mode 100644 index 0000000..83f031a --- /dev/null +++ b/stamina/mimi/read_fsm.c @@ -0,0 +1,322 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/read_fsm.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2005/03/08 01:07:23 $ + * + */ +#include <stdio.h> +#include "user.h" +#include "util.h" +#include "struct.h" +#include "global.h" + +char *item[5]; +void line_parser(); +NLIST **hash_initial(); +NLIST *install(); +STATE *install_state(); +static FILE *fp_temp; + +read_fsm(fp_input) +FILE *fp_input; +{ + register i; + char line[MAXSTRLEN]; + NLIST **state_hash; /* a hash table stores state name */ + char pstate_name[50]; /* the name of present state */ + char nstate_name[50]; /* the name of next state */ + STATE *pstate_ptr; /* pointer to STATE structure */ + STATE *nstate_ptr; /* pointer to STATE structure */ + EDGE *edge_ptr; /* pointer to EDGE structure */ + EDGE *search_edge; + EDGE *p_star_ptr; + int p_star = 0; /* flag indicating p_state is a star */ + int n_star = 0; /* flag indicating n_state is a star */ + static int edge_index = 0; /* a counter when saving edges */ + static char buffer[] = "/tmp/STMXXXXXX"; + int sfd; + + p_star_ptr=NIL(EDGE); + + /*** + *** allocate memory for hash_table: "state_hash" with + *** size of number of states. + *** note that the hashsize = num_st. + ***/ + + sfd = mkstemp(buffer); + if(sfd == -1) { + panic("cannot open temp file"); + } + fp_temp = fdopen(sfd, "w+"); + unlink(buffer); + + /* write information to the file */ + + user.stat.reset = 0; + + while ( fgets(line, MAXSTRLEN, fp_input ) != NULL ) { + fputs(line,fp_temp); + line_parser(line); + if ((item[0] == NULL ) || (item[0][0] == '#')) + continue; /* ignore blank lines */ + + if (item[0][0] == '.') { + switch (item[0][1]) { + case 's': + num_st = atoi(item[1]); + if ( (state_hash = hash_initial(num_st)) == NIL(NLIST *) ) { + panic("ALLOC hash"); + } + + /*** + *** allocate memory for **states, and **edges. + ***/ + + if ( (states = ALLOC(STATE *, num_st)) == NIL(STATE *) ) { + panic("ALLOC state"); + } + + break; + case 'r': + if ((strcmp(item[1], "*") != 0) + && (strcmp(item[1],"ANY") != 0)) { + if (!(install_state(item[1],state_hash,num_st))) + panic("install fail"); + } + user.stat.reset = 1; + break; + case 'p': + num_product = atoi(item[1]); + if ( (edges = ALLOC(EDGE *, num_product )) == NIL(EDGE *) ) { + panic("ALLOC edge"); + } + break; + case 'i': + num_pi = atoi(item[1]); + break; + case 'o': + num_po = atoi(item[1]); + break; + case 'e': + item[0] = NULL; + default: + break; + } + if (item[0] == NULL) + break; + else + continue; + } + + (void) sprintf (pstate_name, "%s", item[1]); + (void) sprintf (nstate_name, "%s", item[2]); + + /* + * taking care of "stars": + * a "*" either in the present state + * or in the next state field will be + * considered as a don't care state + * on that transition edge. + */ + + if ((strcmp(pstate_name, "*") != 0) + && (strcmp(pstate_name,"ANY") != 0)) { + pstate_ptr = install_state(pstate_name,state_hash,num_st); + if ( pstate_ptr == NIL(STATE) ) { + panic("failed to install a state."); + } + } else { + p_star = 1; /* flag on */ + } + + if ((strcmp(nstate_name, "*") != 0 ) + && (strcmp(nstate_name,"ANY") != 0)) { + nstate_ptr = install_state(nstate_name,state_hash,num_st); + if ( nstate_ptr == NIL(STATE) ) { + panic("failed to install a state"); + } + } else { + n_star = 1; /* flag on */ + } + + /*** + *** allocate the memory for a EDGE. + ***/ + + if ( (edge_ptr = ALLOC (EDGE, 1)) == NIL(EDGE) ) { + panic("ALLOC edge"); + } + + edge_ptr->next = NIL(EDGE); + edges[edge_index] = edge_ptr; /* save the address of new edge*/ + edge_index++; + + if (!(edge_ptr->input =ALLOC ( char, num_pi + 1 ))) { + panic("ALLOC input"); + } + + (void) strcpy (edge_ptr->input, item[0]); + + if (!(edge_ptr->output=ALLOC( char, num_po + 1))) { + panic("ALLOC edge output"); + } + (void) strcpy (edge_ptr->output, item[3]); + edge_ptr->n_star = n_star; + edge_ptr->p_star = p_star; + + if ( p_star != 0 ) { /* p_state is a star on this edge */ + edge_ptr->p_state = NIL(STATE); /* a null pointer */ + p_star = 0; /* reset flag p_star to 0 */ + if (p_star_ptr) { + search_edge = p_star_ptr; + while (search_edge->next) + search_edge=search_edge->next; + search_edge->next=edge_ptr; + } + else + p_star_ptr = edge_ptr; + /* I don't need this kind information */ + } else { + edge_ptr->p_state = pstate_ptr; + if (pstate_ptr->edge != NIL(EDGE)) { + search_edge = pstate_ptr->edge; + while (search_edge->next != NIL(EDGE)) + search_edge = search_edge->next; + search_edge->next = edge_ptr; + } + else + pstate_ptr->edge = edge_ptr; + } + + if ( n_star !=0 ) { /* n_state is a star on this edge */ + edge_ptr->n_state = NIL(STATE); /* a null pointer */ + n_star = 0; /* reset flag n_star to 0 */ + } else { + edge_ptr->n_state = nstate_ptr; + } + } + + if (access_n_state() != num_st) { + num_st=access_n_state(); +/* + (void) fprintf(stderr,"Incorrect .s statement %d\n",num_st); +*/ + } +/* + for (i=0; i<num_st; i++) + if (!states[i]->edge) + printf("### Total redundant state\n"); +*/ + /* Expand current state don't care */ + + while (p_star_ptr) { + for (i=0; i<num_st; i++) { + search_edge=states[i]->edge; + if (!search_edge) { + if (!(search_edge=ALLOC(EDGE,1))) + panic("read_fsm2"); + MEMCPY(search_edge,p_star_ptr,sizeof(EDGE)); + search_edge->p_state=states[i]; + search_edge->next = NIL(EDGE); + } + else { + while (search_edge->next) + search_edge=search_edge->next; + if (!(search_edge->next=ALLOC(EDGE,1))) + panic("read_fsm2"); + MEMCPY(search_edge->next,p_star_ptr,sizeof(EDGE)); + search_edge->next->p_state=states[i]; + search_edge->next->next = NIL(EDGE); + } + } + p_star_ptr=p_star_ptr->next; + } + +#ifdef DEBUG + (void) printf("XXXXXXXXXXXXXXXXXXXXXXX HASH XXXXXXXXXXXXXXXXXXXXXXX\n"); + (void) hash_dump(state_hash, num_st); + (void) printf("XXXXXXXXXXXXXXXXXXXXXXX HASH XXXXXXXXXXXXXXXXXXXXXXX\n"); +#endif + + /*** + *** dump the states. + ***/ + +#ifdef DEBUG + (void) printf("XXXXXXXXXXXXXXXXXXXXXXX STATE XXXXXXXXXXXXXXXXXXXXXXX\n"); + (void) dump_states(); + (void) printf("XXXXXXXXXXXXXXXXXXXXXXX STATE XXXXXXXXXXXXXXXXXXXXXXX\n"); +#endif + + /*** + *** dump the edges. + ***/ + +#ifdef DEBUG + (void) printf("XXXXXXXXXXXXXXXXXXXXXXX EDGE XXXXXXXXXXXXXXXXXXXXXXX\n"); + (void) dump_edges(); + (void) printf("XXXXXXXXXXXXXXXXXXXXXXX EDGE XXXXXXXXXXXXXXXXXXXXXXX\n"); +#endif +} + +/* + * parse input line. + */ + +void +line_parser(line_buf) +register char *line_buf; +{ + register char ch; + int count; + + count = 0; + while (ch = *line_buf) { + /* + * Note that the value of return character '\n' is 10 + * which is smaller than the value of space ' ',32, . + * And note that 'x' is a charater, but "x" is a string + * of single charater. + * This note is only for my own reference. + */ + + if (ch <= ' ') { + line_buf++; + continue; + } + + item[count] = line_buf; + count++; + + line_buf++; + + while ( (ch = *line_buf) && ch > ' ' ) + line_buf++; + if (ch != 0) { + *line_buf = '\0'; + line_buf++; + } + } + + item[count] = 0; +} + +flushout() +{ + char line[MAXSTRLEN]; + FILE *out; + + if (user.oname) + out = fopen(user.oname,"w"); + else + out = stdout; + fflush(fp_temp); + rewind(fp_temp); + while (fgets(line,MAXSTRLEN,fp_temp) != NULL) { + fprintf(out,"%s",line); + } +} diff --git a/stamina/mimi/stack.c b/stamina/mimi/stack.c new file mode 100644 index 0000000..4a4b1a9 --- /dev/null +++ b/stamina/mimi/stack.c @@ -0,0 +1,139 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/stack.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/14 08:35:22 $ + * + */ +/* SCCSID %W% */ +#include "util.h" +#include "struct.h" +#include "global.h" +#include "stack.h" +#include "merge.h" + +STACK *xstack; +static unsigned int _size; +static int *_local[STACKLIMIT]; +static int **top_of_stack; +static int **stack_ptr; + +/* Emulation of the stack operation */ +/* This routine guarantees compact use of memory */ +/* But is must pay for it in terms of time */ + +alloc_stack(size) +{ + if ((xstack = ALLOC(STACK,size)) == NIL(STACK)) + panic("ALLOC in init_stack"); +} + +free_stack_head() +{ + if (FREE(xstack)) + panic("lint"); +} + +init_stack(id) +{ + _size = 0; + top_of_stack = _local; + stack_ptr = _local; + xstack[id].status = CONDITIONAL_COMPATIBLE; +} + +open_stack(id) +{ + stack_ptr = xstack[id].ptr; + top_of_stack = (int **)*stack_ptr; + stack_ptr = (int **)*(stack_ptr + 1); +} + +close_stack(id,status) +{ + xstack[id].ptr = NIL(int *); + xstack[id].status = status; +} + +free_stack(id,status) +{ + if (FREE(xstack[id].ptr)) + panic("lint"); + xstack[id].ptr = NIL(int *); + xstack[id].status = status; +} + +pack_stack(id) +{ + int **real_alloc; + + if ((real_alloc = ALLOC(int *,_size+2)) == NIL(int *)) + panic("ALLOC in stack"); + xstack[id].ptr = real_alloc; + xstack[id].status = CONDITIONAL_COMPATIBLE; + *real_alloc = (int *)(real_alloc + 2); + real_alloc++; + *real_alloc = (int *)(real_alloc + _size + 1); + MEMCPY(++real_alloc,_local,sizeof(char *)*_size); +} + +static _push(STACK *); + +push(state2,state1) +{ +#ifdef DEBUG +(void) printf("Push %s %s \n",states[state1]->state_name,states[state2]->state_name); +#endif + if (state2 > state1) + _push(&xstack[(num_st-state1-2)*(num_st-state1-1)/2-state2+num_st-1]); + else + _push(&xstack[(num_st-state2-2)*(num_st-state2-1)/2-state1+num_st-1]); +} + +static +_push(operand) +STACK *operand; +{ + *stack_ptr++ = (int *)operand; + if (_size++ > STACKLIMIT) + panic("Stack Overflow"); +} + +/* +STACK * +_pop(arg2) +STACK **arg2; +{ + if ((*arg2 = pop()) == NIL(STACK)) + return NIL(STACK); + else + return(pop()); +} +*/ + +STACK * +pop() +{ + if (stack_ptr == top_of_stack) + return EMPTY; + else + return (STACK *)*--stack_ptr; +} + +#ifdef DEBUG +dump_stack(id) +{ + int **stack; + register i; + + + stack = xstack[id].ptr; + (void) printf("STACK SIZE %d\n",_size); + for (i=0; i<_size+2; i++) { + (void) printf("ADDRESS: %x VALUE %x\n",stack,*stack); + stack++; + } +} +#endif diff --git a/stamina/mimi/stack.h b/stamina/mimi/stack.h new file mode 100644 index 0000000..92f174a --- /dev/null +++ b/stamina/mimi/stack.h @@ -0,0 +1,23 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/stack.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ + +/* SCCSID %W% */ +typedef struct stack STACK; + +struct stack { + int status; + int **ptr; +}; + +#define STACKLIMIT 1000 +#define EMPTY NIL(STACK) + +STACK *pop(); +extern STACK *xstack; diff --git a/stamina/mimi/struct.h b/stamina/mimi/struct.h new file mode 100644 index 0000000..4ae0769 --- /dev/null +++ b/stamina/mimi/struct.h @@ -0,0 +1,111 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/struct.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ +/******************************************************************* + * * + * * + *******************************************************************/ + +#include <stdio.h> +#include "hash.h" + +#define MAXSTRLEN 1024 + +typedef char *STRING; +/* +typedef struct nlist NLIST; +*/ +typedef struct state STATE; +typedef struct edge EDGE; +typedef struct p_edge P_EDGE; +typedef struct s_edge S_EDGE; +typedef struct xnode NODE; +typedef struct isomor ISO; + +struct xnode { + NODE *right; + NODE *left; + int literal; + NLIST *cubes; + int *on_off; +}; + +struct sbase { + int state; + int where; +}; + +struct isomor { + int sum; + int num; + int uvoid; + int *list; +}; + +struct state { + STRING state_name; + STRING code; + int state_index; + EDGE *edge; +/* + P_EDGE *pedge; +*/ + int assigned; +}; + + +struct edge { + STRING input; /* primary input */ + STRING output; /* primary output*/ + STATE *p_state; /* pointer to a present state */ + STATE *n_state; /* pointer to a next state */ + int p_star; /* a flag to indicate if p_state is a '*'.*/ + int n_star; /* a flag to indicate if n_state is a '*'.*/ + EDGE *next; +}; + +struct p_edge { + STRING input; /* primary input */ + STRING output; /* primary output*/ + STATE *p_state; /* pointer to a present state */ + STATE *n_state; /* pointer to a next state */ + int p_star; /* a flag to indicate if p_state is a '*'.*/ + int n_star; /* a flag to indicate if n_state is a '*'.*/ + P_EDGE *v_next; + P_EDGE *h_next; +}; + +struct s_edge { + STRING output; /* primary output*/ + STATE *p_state; /* pointer to a present state */ + STATE *n_state; /* pointer to a next state */ + int p_star; /* a flag to indicate if p_state is a '*'.*/ + int n_star; /* a flag to indicate if n_state is a '*'.*/ + S_EDGE *v_next; +}; +/* + +#include "util.h" +*/ + +/* +#define HASHSIZE 1000 /* It is not used * + + +struct nlist { /* basic table entry * + char *name; + S_EDGE *ptr; /* this element is not used * + int order_index; /* order index of entries in hashtab * + NLIST *h_next; /* Horizontal chain for flow table * + NLIST *h_prev; + struct nlist *next; /* next entry in chain * +}; +*/ + +#define MEMCPY(FROM,TO,NBYTE) (void) memcpy((char *)(FROM),(char *)(TO),(int)(NBYTE)) diff --git a/stamina/mimi/user.h b/stamina/mimi/user.h new file mode 100644 index 0000000..d5d3e96 --- /dev/null +++ b/stamina/mimi/user.h @@ -0,0 +1,54 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/stamina/mimi/user.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:15 $ + * + */ + +#define MAX_STEP 20 + +struct u { + struct { + int verbose; /* verbose level */ + int hmap; /* mapping heuristics */ + int solution; /* solution heuristics */ + int heuristics; /* binate covering heuristics */ + } opt; + struct { + int n_compatible; /* number of compatible pair */ + int n_iso; /* number of base isomorphic states */ + int n_max; /* number of maximal compatibles */ + int base_max; /* number of base maximal compatibles */ + int n_prime; /* number of prime compatibles */ + int nstates; /* number of original states */ + int rstates; /* number of states which are compatible */ + int ostates; /* number of incompatible states */ + int product; /* number of product terms */ + int high; /* high bound */ + int low; /* low bound */ + int shrink; /* number of shrunk states */ + int xinput; + int disjoint; + int map_alternative; /* mapping alternative */ + int map_total; /* total number of choice */ + int reset; /* Is there reset state */ + float quality; /* mapping quality */ + } stat; + struct { + int shrink; + int merge; + int trans; + } cmd; + long ltime[MAX_STEP]; /* for timing information */ + int iso; + int level; + char *fname; /* input file name */ + char *oname; /* output file name */ +}; + +extern struct u user; + +#define HEU1 1 diff --git a/stamina/stamina.1 b/stamina/stamina.1 new file mode 100644 index 0000000..f65fa54 --- /dev/null +++ b/stamina/stamina.1 @@ -0,0 +1,52 @@ +.\" /* +.\" * Revision Control Information +.\" * +.\" * $Source: /users/pchong/CVS/sis/stamina/stamina.1,v $ +.\" * $Author: pchong $ +.\" * $Revision: 1.1.1.1 $ +.\" * $Date: 2004/02/07 10:14:14 $ +.\" * +.\" +.TH STAMINA STAMINA.0 "5/20/90" "University of Colorado " \ +"STAte MINimizAtion" +.SH NAME +stamina \- state minimization of incompletely specified finite state machine +.SH SYNOPSIS +.B stamina +[options] inputfile [ > outputfile ] +.SH DESCRIPTION +\fBSTAMINA\fP is a state minimization program. It provides exact minimization +by ordinary prime and binate covering methods. It also gives a heuristic +solution by tight upper bound and isomorphic states. Both input and +output file format is KISS2. After minimization, +unnecessary states of each solution set can be shrunk by using the -S option. + +.SH "OPTIONS" +.nf +-v n, verbose mode 0, no message(default) + 1, print timing statistics and solution + 2, print maximal compatibles and + prime compatibles + + +-s n, minimization heuristics- 0, exact method(default) + 1, tight upper bound + 2, isomorphic + 3, combination of the above two + +-m n, mapping heuristics 0, random mapping + 1, equal weighting heuristic + 4, heuristic mapping(default) + +-o filename specify output filename(default is stdout) + +-S shrinking solution + +-h Print out the Usage - command line options. +.fi + +.SH REMARKS +After minimization there may exist multiple reset states if there was a +reset state before minimization. Currently a reset state after minimization +is selected randomly. + diff --git a/utility/Makefile.am b/utility/Makefile.am new file mode 100644 index 0000000..186185c --- /dev/null +++ b/utility/Makefile.am @@ -0,0 +1,6 @@ +AM_CPPFLAGS = -I$(top_srcdir)/port + +noinst_LIBRARIES = libutility.a +libutility_a_SOURCES = cpu_time.c csystem.c pathsearch.c pipefork.c \ + prtime.c strsav.c texpand.c tmpfile.c utility.h +EXTRA_DIST = utility.doc uttest.c diff --git a/utility/Makefile.in b/utility/Makefile.in new file mode 100644 index 0000000..6a22080 --- /dev/null +++ b/utility/Makefile.in @@ -0,0 +1,372 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(libutility_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = utility +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +AR = ar +ARFLAGS = cru +LIBRARIES = $(noinst_LIBRARIES) +libutility_a_AR = $(AR) $(ARFLAGS) +libutility_a_LIBADD = +am_libutility_a_OBJECTS = cpu_time.$(OBJEXT) csystem.$(OBJEXT) \ + pathsearch.$(OBJEXT) pipefork.$(OBJEXT) prtime.$(OBJEXT) \ + strsav.$(OBJEXT) texpand.$(OBJEXT) tmpfile.$(OBJEXT) +libutility_a_OBJECTS = $(am_libutility_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libutility_a_SOURCES) +DIST_SOURCES = $(libutility_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CPPFLAGS = -I$(top_srcdir)/port +noinst_LIBRARIES = libutility.a +libutility_a_SOURCES = cpu_time.c csystem.c pathsearch.c pipefork.c \ + prtime.c strsav.c texpand.c tmpfile.c utility.h + +EXTRA_DIST = utility.doc uttest.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps utility/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps utility/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libutility.a: $(libutility_a_OBJECTS) $(libutility_a_DEPENDENCIES) + -rm -f libutility.a + $(libutility_a_AR) libutility.a $(libutility_a_OBJECTS) $(libutility_a_LIBADD) + $(RANLIB) libutility.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/utility/cpu_time.c b/utility/cpu_time.c new file mode 100644 index 0000000..dc07d3f --- /dev/null +++ b/utility/cpu_time.c @@ -0,0 +1,141 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/cpu_time.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:13 $ + * + */ +/* LINTLIBRARY */ +#include "copyright.h" +#include "port.h" +#include "utility.h" + +#ifdef IBM_WATC /* IBM Waterloo-C compiler (same as bsd 4.2) */ +#ifndef BSD +#define BSD +#endif +#ifndef void +#define void int +#endif +#endif + +#ifdef ultrix +#ifndef BSD +#define BSD +#endif +#endif + +#ifdef __hpux /* HP/UX - system dependent clock speed */ +#ifndef UNIXMULTI +#define UNIXMULTI +#endif +#endif + +#ifdef aiws +#ifndef UNIX10 +#define UNIX10 +#endif +#endif + +#ifdef vms /* VAX/C compiler -- times() with 100 HZ clock */ +#ifndef UNIX100 +#define UNIX100 +#endif +#endif + +/* default */ +#if !defined(BSD) && !defined(UNIX10) && !defined(UNIX60) && !defined(UNIX100) && !defined(UNIX50) && !defined(UNIXMULTI) +#define BSD +#endif + +#ifdef BSD +#include <sys/time.h> +#include <sys/resource.h> +#endif + +#ifdef UNIX10 +#include <sys/times.h> +#endif + +#ifdef UNIX50 +#include <sys/times.h> +#endif + +#ifdef UNIX60 +#include <sys/times.h> +#endif + +#ifdef UNIX100 +#include <sys/times.h> +#endif + +#ifdef UNIXMULTI +/* The following code for HPUX is based on a man page that claims POSIX */ +/* compliance. Accordingly, it should work on any POSIX-compliant */ +/* system. It should definitely work for HPUX 8.07 and beyond. I can't */ +/* vouch for pre-8.07 systems, but I recall that earlier versions of */ +/* HPUX (like 6.5) had a different way of accessing the clock rate for */ +/* times(). - DEW */ + +#include <sys/times.h> +#include <unistd.h> +#endif + +/* + * util_cpu_time -- return a long which represents the elapsed processor + * time in milliseconds since some constant reference + */ +long +util_cpu_time() +{ + long t = 0; + +#ifdef BSD + struct rusage rusage; + (void) getrusage(RUSAGE_SELF, &rusage); + t = (long) rusage.ru_utime.tv_sec*1000 + rusage.ru_utime.tv_usec/1000; +#endif + +#ifdef IBMPC + long ltime; + (void) time(<ime); + t = ltime * 1000; +#endif + +#ifdef UNIX10 /* times() with 10 Hz resolution */ + struct tms buffer; + (void) times(&buffer); + t = buffer.tms_utime * 100; +#endif + +#ifdef UNIX50 /* times() with 50 Hz resolution */ + struct tms buffer; + times(&buffer); + t = buffer.tms_utime * 20; +#endif + +#ifdef UNIX60 /* times() with 60 Hz resolution */ + struct tms buffer; + times(&buffer); + t = buffer.tms_utime * 16.6667; +#endif + +#ifdef UNIX100 + struct tms buffer; /* times() with 100 Hz resolution */ + times(&buffer); + t = buffer.tms_utime * 10; +#endif + +#ifdef UNIXMULTI /* times() with processor-dependent resolution (POSIX) */ + struct tms buffer; + long nticks; /* number of clock ticks per second */ + + nticks = sysconf(_SC_CLK_TCK); + times(&buffer); + t = buffer.tms_utime * (1000.0/nticks); + +#endif + return t; +} diff --git a/utility/csystem.c b/utility/csystem.c new file mode 100644 index 0000000..7953fa9 --- /dev/null +++ b/utility/csystem.c @@ -0,0 +1,54 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/csystem.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/14 17:14:14 $ + * + */ +/* LINTLIBRARY */ +#include "copyright.h" +#include "port.h" +#include <sys/wait.h> +#include "utility.h" +#include "config.h" + +int +util_csystem(s) +char *s; +{ + RETSIGTYPE (*istat)(), (*qstat)(); +#if defined(_IBMR2) || defined(__osf__) + int status; +#else + union wait status; +#endif + int pid, w, retval; + + if ((pid = vfork()) == 0) { + (void) execl("/bin/csh", "csh", "-f", "-c", s, 0); + (void) _exit(127); + } + + /* Have the parent ignore interrupt and quit signals */ + istat = signal(SIGINT, SIG_IGN); + qstat = signal(SIGQUIT, SIG_IGN); + + while ((w = wait(&status)) != pid && w != -1) + ; + if (w == -1) { /* check for no children ?? */ + retval = -1; + } else { +#if defined(_IBMR2) || defined(__osf__) + retval = status; +#else + retval = status.w_status; +#endif + } + + /* Restore interrupt and quit signal handlers */ + (void) signal(SIGINT, istat); + (void) signal(SIGQUIT, qstat); + return retval; +} diff --git a/utility/pathsearch.c b/utility/pathsearch.c new file mode 100644 index 0000000..53835df --- /dev/null +++ b/utility/pathsearch.c @@ -0,0 +1,105 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/pathsearch.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:13 $ + * + */ +/* LINTLIBRARY */ +#include "copyright.h" +#include "port.h" +#include "utility.h" + +static int check_file(); + +char * +util_path_search(prog) +char *prog; +{ +#ifdef unix + return util_file_search(prog, getenv("PATH"), "x"); +#else + return util_file_search(prog, NIL(char), "x"); +#endif +} + + +char * +util_file_search(file, path, mode) +char *file; /* file we're looking for */ +char *path; /* search path, colon separated */ +char *mode; /* "r", "w", or "x" */ +{ + int quit; + char *buffer, *filename, *save_path, *cp; + + if (path == 0 || strcmp(path, "") == 0) { + path = "."; /* just look in the current directory */ + } + + save_path = path = util_strsav(path); + quit = 0; + do { + cp = strchr(path, ':'); + if (cp != 0) { + *cp = '\0'; + } else { + quit = 1; + } + + /* cons up the filename out of the path and file name */ + if (strcmp(path, ".") == 0) { + buffer = util_strsav(file); + } else { + buffer = ALLOC(char, strlen(path) + strlen(file) + 4); + (void) sprintf(buffer, "%s/%s", path, file); + } + filename = util_tilde_expand(buffer); + FREE(buffer); + + /* see if we can access it */ + if (check_file(filename, mode)) { + FREE(save_path); + return filename; + } + path = ++cp; + } while (! quit); + + FREE(save_path); + return 0; +} + + +static int +check_file(filename, mode) +char *filename; +char *mode; +{ +#ifdef unix + int access_mode; + + if (strcmp(mode, "r") == 0) { + access_mode = /*R_OK*/ 4; + } else if (strcmp(mode, "w") == 0) { + access_mode = /*W_OK*/ 2; + } else if (strcmp(mode, "x") == 0) { + access_mode = /*X_OK*/ 1; + } + return access(filename, access_mode) == 0; +#else + FILE *fp; + int got_file; + + if (strcmp(mode, "x") == 0) { + mode = "r"; + } + fp = fopen(filename, mode); + got_file = (fp != 0); + if (fp != 0) { + (void) fclose(fp); + } + return got_file; +#endif +} diff --git a/utility/pipefork.c b/utility/pipefork.c new file mode 100644 index 0000000..bf914a8 --- /dev/null +++ b/utility/pipefork.c @@ -0,0 +1,88 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/pipefork.c,v $ + * $Author: pchong $ + * $Revision: 1.2 $ + * $Date: 2004/03/27 10:33:58 $ + * + */ +/* LINTLIBRARY */ +#include "copyright.h" +#include "port.h" +#include "autoconf.h" + +/* + * util_pipefork - fork a command and set up pipes to and from + * + * Rick L Spickelmier, 3/23/86 + * Richard Rudell, 4/6/86 + * Rick L Spickelmier, 4/30/90, got rid of slimey vfork semantics + * + * Returns: + * 1 for success, with toCommand and fromCommand pointing to the streams + * 0 for failure + */ + +/* ARGSUSED */ +int +util_pipefork(argv, toCommand, fromCommand, pid) +char **argv; /* normal argv argument list */ +FILE **toCommand; /* pointer to the sending stream */ +FILE **fromCommand; /* pointer to the reading stream */ +int *pid; +{ +#ifdef unix + int forkpid, mywaitpid; + int topipe[2], frompipe[2]; + char buffer[1024]; + RETWAITTYPE status; + + /* create the PIPES... + * fildes[0] for reading from command + * fildes[1] for writing to command + */ + (void) pipe(topipe); + (void) pipe(frompipe); + + if ((forkpid = vfork()) == 0) { + /* child here, connect the pipes */ + (void) dup2(topipe[0], fileno(stdin)); + (void) dup2(frompipe[1], fileno(stdout)); + + (void) close(topipe[0]); + (void) close(topipe[1]); + (void) close(frompipe[0]); + (void) close(frompipe[1]); + + (void) execvp(argv[0], argv); + (void) sprintf(buffer, "util_pipefork: can not exec %s", argv[0]); + perror(buffer); + (void) _exit(1); + } + + if (pid) { + *pid = forkpid; + } + + mywaitpid = wait3(&status, WNOHANG, 0); + + /* parent here, use slimey vfork() semantics to get return status */ + if (mywaitpid == forkpid && WIFEXITED(status)) { + return 0; + } + if ((*toCommand = fdopen(topipe[1], "w")) == NULL) { + return 0; + } + if ((*fromCommand = fdopen(frompipe[0], "r")) == NULL) { + return 0; + } + (void) close(topipe[0]); + (void) close(frompipe[1]); + return 1; +#else + (void) fprintf(stderr, + "util_pipefork: not implemented on your operating system\n"); + return 0; +#endif +} diff --git a/utility/prtime.c b/utility/prtime.c new file mode 100644 index 0000000..74162af --- /dev/null +++ b/utility/prtime.c @@ -0,0 +1,30 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/prtime.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:13 $ + * + */ +/* LINTLIBRARY */ +#include "copyright.h" +#include "port.h" +#include "utility.h" + +/* + * util_print_time -- massage a long which represents a time interval in + * milliseconds, into a string suitable for output + * + * Hack for IBM/PC -- avoids using floating point + */ + +char * +util_print_time(t) +long t; +{ + static char s[40]; + + (void) sprintf(s, "%ld.%02ld sec", t/1000, (t%1000)/10); + return s; +} diff --git a/utility/strsav.c b/utility/strsav.c new file mode 100644 index 0000000..7ef644d --- /dev/null +++ b/utility/strsav.c @@ -0,0 +1,23 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/strsav.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:13 $ + * + */ +/* LINTLIBRARY */ +#include "copyright.h" +#include "port.h" +#include "utility.h" + +/* + * util_strsav -- save a copy of a string + */ +char * +util_strsav(s) +char *s; +{ + return strcpy(ALLOC(char, strlen(s)+1), s); +} diff --git a/utility/texpand.c b/utility/texpand.c new file mode 100644 index 0000000..85d60a5 --- /dev/null +++ b/utility/texpand.c @@ -0,0 +1,256 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/texpand.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:13 $ + * + */ +/* LINTLIBRARY */ +#ifdef notdef +#define _POSIX_SOURCE /* Argh! IBM strikes again... */ +#include "copyright.h" +#include "port.h" +#include "st.h" +#include "utility.h" + +#define PATHLEN 1024 + +#include <pwd.h> + +#define SCPY(s) strcpy(ALLOC(char, strlen(s)+1), s) + +static st_table *table = NIL(st_table); + +#define DEF_SIZE 100 +#define DEF_INCR 50 + +typedef struct rev_user_defn { + char *home_dir; + char *user_name; +} rev_user; + +typedef struct rev_tbl_defn { + int num_entries; + int alloc_size; + int needs_to_be_sorted; + rev_user *items; +} rev_tbl; + +static rev_tbl *other_table = (rev_tbl *) 0; + +static void +init_table() +{ + char *dir; + + table = st_init_table(strcmp, st_strhash); + /* Get CADROOT directory from environment */ + dir = getenv("OCTTOOLS"); + if (dir) { + (void) st_add_direct(table, "octtools", dir); + } + + /* Get user set of translations from environment */ + dir = getenv("OCTTOOLS-TRANSLATIONS"); + if (dir) { + char *ptr = SCPY(dir); + char *token, *user, *home; + + while ((token = strtok(ptr, ", \t")) != NIL(char)) { + ptr = NIL(char); + if ((home = strchr(token, ':')) == NIL(char)) { + /* malformed entry */ + continue; + } + user = token; + *home = '\0'; + home++; + (void) st_add_direct(table, user, home); + } + } + + return; +} + +static void +insert_other_table(home_dir, user_name) +char *home_dir; +char *user_name; +{ + if (other_table->num_entries >= other_table->alloc_size) { + other_table->alloc_size += DEF_INCR; + other_table->items = + REALLOC(rev_user, other_table->items, other_table->alloc_size); + } + other_table->items[other_table->num_entries].home_dir = SCPY(home_dir); + other_table->items[other_table->num_entries].user_name = SCPY(user_name); + other_table->num_entries += 1; + other_table->needs_to_be_sorted = 1; +} + +static void +init_other_table() +{ + struct passwd *entry; + char *dir; + + other_table = ALLOC(rev_tbl, 1); + other_table->num_entries = 0; + other_table->alloc_size = DEF_SIZE; + other_table->needs_to_be_sorted = 0; + other_table->items = ALLOC(rev_user, other_table->alloc_size); + + dir = getenv("OCTTOOLS"); + if (dir) { + insert_other_table(dir, "octtools"); + } + dir = getenv("OCTTOOLS-TRANSLATIONS"); + if (dir) { + char *ptr = SCPY(dir); + char *token, *user, *home; + + while ((token = strtok(ptr, ", \t")) != NIL(char)) { + ptr = NIL(char); + if ((home = strchr(token, ':')) == NIL(char)) { + /* malformed entry */ + continue; + } + user = token; + *home = '\0'; + home++; + insert_other_table(home, user); + } + } + setpwent(); + while (entry = getpwent()) { + insert_other_table(entry->pw_dir, entry->pw_name); + } + endpwent(); +} + +void +util_register_user(user, directory) +char *user, *directory; +{ + if (table == NIL(st_table)) { + init_table(); + } + (void) st_insert(table, user, directory); + if (other_table == NIL(rev_tbl)) { + init_other_table(); + } + insert_other_table(directory, user); + return; +} + + +char * +util_tilde_expand(fname) +char *fname; +{ + char username[PATHLEN]; + static char result[8][PATHLEN]; + static int count = 0; + struct passwd *userRecord; + extern struct passwd *getpwuid(), *getpwnam(); + register int i, j; + char *dir; + + if (++count > 7) { + count = 0; + } + + /* Clear the return string */ + i = 0; + result[count][0] = '\0'; + + /* Tilde? */ + if (fname[0] == '~') { + j = 0; + i = 1; + while ((fname[i] != '\0') && (fname[i] != '/')) { + username[j++] = fname[i++]; + } + username[j] = '\0'; + + if (table == NIL(st_table)) { + init_table(); + } + + if (!st_lookup(table, username, &dir)) { + /* ~/ resolves to the home directory of the current user */ + if (username[0] == '\0') { + if ((userRecord = getpwuid(getuid())) != 0) { + (void) strcpy(result[count], userRecord->pw_dir); + (void) st_add_direct(table, "", util_strsav(userRecord->pw_dir)); + } else { + i = 0; + } + } else if ((userRecord = getpwnam(username)) != 0) { + /* ~user/ resolves to home directory of 'user' */ + (void) strcpy(result[count], userRecord->pw_dir); + (void) st_add_direct(table, util_strsav(username), + util_strsav(userRecord->pw_dir)); + } else { + i = 0; + } + } else { + (void) strcat(result[count], dir); + } + } + + /* Concantenate remaining portion of file name */ + (void) strcat(result[count], fname + i); + return result[count]; +} + + + +static int comp(a, b) +char *a, *b; +{ + int diff; + + diff = strlen(((rev_user *) b)->home_dir) - + strlen(((rev_user *) a)->home_dir); + if (diff == 0) { + diff = strlen(((rev_user *) a)->user_name) - + strlen(((rev_user *) b)->user_name); + } + return diff; +} + +char * +util_tilde_compress(fname) +char *fname; +/* + * Makes tilde expanded name from the given fully expanded name. + * If no match is found, it returns the filename back unmodified. + */ +{ + static char result[8][PATHLEN]; + static int count = 0; + int i, len; + + if (++count > 7) count = 0; + if (!other_table) init_other_table(); + if (other_table->needs_to_be_sorted) { + qsort(other_table->items, other_table->num_entries, + sizeof(rev_user), comp); + other_table->needs_to_be_sorted = 0; + } + for (i = 0; i < other_table->num_entries; i++) { + len = strlen(other_table->items[i].home_dir); + if (strncmp(other_table->items[i].home_dir, fname, len) == 0) { + result[count][0] = '\0'; + strcat(result[count], "~"); + strcat(result[count], other_table->items[i].user_name); + strcat(result[count], fname+len); + return result[count]; + } + } + return fname; +} +#endif diff --git a/utility/tmpfile.c b/utility/tmpfile.c new file mode 100644 index 0000000..c92f840 --- /dev/null +++ b/utility/tmpfile.c @@ -0,0 +1,53 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/tmpfile.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:13 $ + * + */ + +/* LINTLIBRARY */ +#include "copyright.h" +#include "port.h" +#include "utility.h" + +/* + * util_tmpfile -- open an unnamed temporary file + * + * This is the ANSI C standard routine; we have hacks here because many + * compilers/systems do not have it yet. + */ + +#ifdef unix + +extern char *mktemp(); + +FILE * +util_tmpfile() +{ + FILE *fp; + char *filename, *junk; + + junk = util_strsav("/usr/tmp/tempXXXXXX"); + filename = mktemp(junk); + if ((fp = fopen(filename, "w+")) == NULL) { + (void) fprintf(stderr, "Could not open the temporary file (%s)\n", filename); + FREE(junk); + return NULL; + } + (void) unlink(filename); + FREE(junk); + return fp; +} + +#else + +FILE * +util_tmpfile() +{ + return fopen("utiltmp", "w+"); +} + +#endif diff --git a/utility/utility.doc b/utility/utility.doc new file mode 100644 index 0000000..b8b5ffb --- /dev/null +++ b/utility/utility.doc @@ -0,0 +1,227 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/utility.doc,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:13 $ + * + */ +Utility Package +Rick Spickelmier +University of California at Berkeley +------------------------------------------------------ + +`Utility' is a package of commonly defined functions and macros. + +The header is file: ~octtools/include/utility.h +The library is: ~octtools/lib/libutility.a +The lint library is: ~octtools/lib/llib-lutility.ln + +This pacakge requires the following packages: mm, portability + + +Summary: + ALLOC() + REALLOC() + FREE() + NIL() + MAX() + MIN() + ABS() + NIL_FN() + int util_pipefork() + char *util_tilde_expand() + char *util_register_user() + char *util_tilde_compress() + char *util_file_search() + char *util_path_search() + char *util_csystem() + long util_cpu_time() + char *util_print_time() + char *util_strsav() + FILE *util_tmpfile() + +type * +ALLOC(type, number) +typeof type; +int number; + Allocates `number' objects of type `type'. This macro should be used + rather than calling malloc() directly because it casts the arguments + appropriately, and ALLOC() will never return NIL(char), choosing + instead to terminate the program. + + +void +FREE(obj) + Free object `obj'. This macro should be used rather than + calling free() directly because it casts the argument + appropriately. It also guarantees that FREE(0) will work + properly. Note that FREE evaluates its' argument three + times, for example: + + i = 10; + while (i > 0) { + FREE(a[--i]); + } + + is not the same as: + + i = 10; + while (i > 0) { + --i; + FREE(a[i]); + } + + +type * +REALLOC(type, obj, number) + Re-allocate `obj' to hold `number' objects of type `type'. + This macro should be used rather than calling realloc() + directly because it casts the arguments appropriately, and + REALLOC() will never return NIL(char), instead choosing to + terminate the program. It also guarantees that REALLOC(type, 0, n) + is the same as ALLOC(type, n). + + +type * +NIL(type) + Returns 0 properly casted into a pointer to an object of type + 'type'. Strictly speaking, this macro is only required when + a 0 pointer is passed as an argument to a function. Still, + some prefer the style of always casting their 0 pointers using + this macro. + + +MAX(a, b) + A macro that returns the maximum of the two numbers. + Note that MAX evaluates the maximum argument twice + and the minimum once. + + +MIN(a, b) + A macro that returns the minimum of the two numbers. + Note that MIN evaluates the minimum argument twice + and the maximum once. + + +ABS(a) + A macro that returns the absolute value of `a'. + + +NIL_FN(type) + A macro that returns a NIL function pointer of type `type'. + + +int +util_pipefork(argv, toCommand, fromCommand, pid) +char **argv; +FILE **toCommand; +FILE **fromCommand; +int *pid; + Fork (using execvp(3)) the program argv[0] with argv[1] ... + argv[n] as arguments. (argv[n+1] is set to NIL(char) to + indicate the end of the list). Set up two-way pipes between + the child process and the parent, returning file pointer + 'toCommand' which can be used to write information to the + child, and the file pointer `fromCommand' which can be used to + read information from the child. As always with unix pipes, + watch out for dead-locks. Returns 1 for success, 0 if any + failure occured forking the child. + + +char * +util_tilde_expand(filename) +char *filename; + Returns a static buffer corresponding to `tilde-expansion' of the + given filename (see csh(1), "filename substitution"). This + means recognizing ~user and ~/ constructs, and inserting the + appropriate user's home directory. The returned string is + static and should not be freed by the caller. There is a + ring of 8 buffers used in returning values. + + The environment variables OCTTOOLS and OCTTOOLS-TRANSLATIONS + are checked for translations for ~octtools (OCTTOOLS) and for + other ~ expansions (OCTTOOLS-TRANSLATIONS). OCTTOOLS-TRANSLATIONS + is of the form: user:directory,user:directory,... + +char * +util_tilde_compress(filename) +char *filename; + Returns a static buffer containing the tilde version of + the full path `filename'. The returned string is static + and should not be freed by the caller. There is a ring + of 8 buffers used for returning values. If no suitable + tilde form for the file exists, it will return `filename' + unchanged. + + The routine uses the OCTTOOLS and OCTTOOLS-TRANSLATIONS + environment variables to determine translations as well as + entries in the password file. + +void +util_register_user(user, directory) +char *user, *directory; + Tell the util_tilde_expand to return `directory' whenever + it is given ~user. + + +char * +util_file_search(file, path, mode) +char *file; +char *path; +char *mode; + 'path' is string of the form "dir1:dir2: ...". Each of the + directories is searched (in order) for a file matching `file' + in that directory. `mode' checks that the file can be accessed + with read permission ("r"), write permission ("w"), or execute + permission ("x"). The expanded filename is returned, or + NIL(char) is returned if no file could be found. The returned + string is static and should not be freed by the caller. + Tilde expansion is performed on both `file' and any directory + in `path'. + + +char * +util_path_search(program) +char *program; + Simulate the execvp(3) semantics of searching the user's environment + variable PATH for an executable `program'. Returns the file name + of the first executable matching `program' in getenv("PATH"), or + returns NIL(char) if none was found. This routines uses + util_file_search(). The returned string is static and should + not be freed by the caller. + + +int +util_csystem(command) +char *command; + Like `system', but uses `csh'. + + +long +util_cpu_time() + Returns the processor time used since some constant reference + in milliseconds. + + +char * +util_print_time(time) +long time; + Converts a time into a (static) printable string. Intended to + allow different hosts to provide differing degrees of + significant digits in the result (e.g., IBM 3090 is printed to + the millisecond, and the IBM PC usually is printed to the + second). Returns a string of the form "10.5 sec". + + +char * +util_strsav(s) +char *s; + Returns a copy of the string `s'. + +FILE * +util_tmpfile() + Returns a file pointer to a temporary file opened for "w+". + The file has already been unlinked. + diff --git a/utility/utility.h b/utility/utility.h new file mode 100644 index 0000000..1ae2bd9 --- /dev/null +++ b/utility/utility.h @@ -0,0 +1,74 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/utility.h,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:13 $ + * + */ +#ifndef UTILITY_H +#define UTILITY_H + +/* + * assumes the memory manager is libmm.a + * - allows malloc(0) or realloc(obj, 0) + * - catches out of memory (and calls MMout_of_memory()) + * - catch free(0) and realloc(0, size) in the macros + */ +#define NIL(type) ((type *) 0) +#define ALLOC(type, num) \ + ((type *) malloc(sizeof(type) * (num))) +#define REALLOC(type, obj, num) \ + (obj) ? ((type *) realloc((char *) obj, sizeof(type) * (num))) : \ + ((type *) malloc(sizeof(type) * (num))) +#define FREE(obj) \ + if ((obj)) { (void) free((char *) (obj)); (obj) = 0; } + +#include "ansi.h" + +EXTERN long util_cpu_time + NULLARGS; +EXTERN char *util_path_search + ARGS((char *)); +EXTERN char *util_file_search + ARGS((char *, char *, char *)); +EXTERN int util_pipefork + ARGS((char **, FILE **, FILE **, int *)); +EXTERN int util_csystem + ARGS((char *)); +EXTERN char *util_print_time + ARGS((long)); +EXTERN char *util_strsav + ARGS((char *)); +EXTERN char *util_tilde_expand + ARGS((char *)); +EXTERN char *util_tilde_compress + ARGS((char *)); +EXTERN void util_register_user + ARGS((char *, char *)); + +#ifndef NIL_FN +#define NIL_FN(type) ((type (*)()) 0) +#endif /* NIL_FN */ + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif /* MAX */ +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ +#ifndef ABS +#define ABS(a) ((a) > 0 ? (a) : -(a)) +#endif /* ABS */ + + +#ifdef lint +#undef ALLOC /* allow for lint -h flag */ +#undef REALLOC +#define ALLOC(type, num) (((type *) 0) + (num)) +#define REALLOC(type, obj, num) ((obj) + (num)) +#endif /* lint */ + +#endif + diff --git a/utility/uttest.c b/utility/uttest.c new file mode 100644 index 0000000..20dc0d3 --- /dev/null +++ b/utility/uttest.c @@ -0,0 +1,166 @@ +/* + * Revision Control Information + * + * $Source: /users/pchong/CVS/sis/utility/uttest.c,v $ + * $Author: pchong $ + * $Revision: 1.1.1.1 $ + * $Date: 2004/02/07 10:14:13 $ + * + */ +#include "copyright.h" +#include "port.h" +#include "utility.h" + +/*ARGSUSED*/ +main(argc, argv) +int argc; +char **argv; +{ + FILE *in, *out; + char results[8][4096]; + char *args[8]; + char *file, *str; + int dummy, i, j; + long time; + int pid; + + /* test tilde expander */ + if (strcmp(util_tilde_expand("/tmp"), "/tmp") != 0) { + fprintf(stderr, "expansion of /tmp failed\n"); + exit(-1); + } + if (strcmp(util_tilde_expand("fred"), "fred") != 0) { + fprintf(stderr, "expansion of fred failed\n"); + exit(-1); + } + if (strcmp(util_tilde_expand("./fred"), "./fred") != 0) { + fprintf(stderr, "expansion of ./fred failed\n"); + exit(-1); + } + if (strcmp(util_tilde_expand("~bigwilly"), "~bigwilly") != 0) { + fprintf(stderr, "expansion of ~bigwilly failed\n"); + exit(-1); + } + if (strcmp(util_tilde_expand("~root"), "/") != 0) { + fprintf(stderr, "expansion of ~root failed\n"); + exit(-1); + } + if (strcmp(util_tilde_compress(util_tilde_expand("~octtools/.cshrc")), + "~octtools/.cshrc") != 0) { + fprintf(stderr, "compression of ~octtools failed\n"); + exit(-1); + } + + + util_register_user("non-existent-user", "/non-existent-location"); + if (strcmp(util_tilde_expand("~non-existent-user/.cshrc"), + "/non-existent-location/.cshrc") != 0) { + fprintf(stderr, "expansion of ~non-existent-user failed\n"); + exit(-1); + } + if (strcmp(util_tilde_compress(util_tilde_expand("~non-existent-user/.cshrc")), + "~non-existent-user/.cshrc") != 0) { + fprintf(stderr, "compression of ~non-existent-user failed\n"); + exit(-1); + } + + /* check out OCTTOOLS-TRANSLATIONS */ + if (strcmp(util_tilde_expand("~first-translation/.cshrc"), + "/first/.cshrc") != 0) { + fprintf(stderr, "expansion of ~first failed\n"); + exit(-1); + } + if (strcmp(util_tilde_expand("~second-translation/.cshrc"), + "/second/.cshrc") != 0) { + fprintf(stderr, "expansion of ~second failed\n"); + exit(-1); + } + if (strcmp(util_tilde_expand("~third-translation/.cshrc"), + "/third/.cshrc") != 0) { + fprintf(stderr, "expansion of ~third failed\n"); + exit(-1); + } + if (strcmp(str = util_tilde_compress(util_tilde_expand("~third-translation/.cshrc")), + "~third-translation/.cshrc") != 0) { + fprintf(stderr, "compression of ~third failed:\n"); + fprintf(stderr, "`%s' != `%s'\n", str, "~third-translation/.cshrc"); + exit(-1); + } + + /* verify that multiple calls can be made to util_tilde_expand */ + j = 0; + (void) strcpy(results[j++], util_tilde_expand("~/fred")); + if (results[j-1][0] == '~') { + fprintf(stderr, "expansion of ~/fred failed\n"); + exit(-1); + } + (void) strcpy(results[j++], util_tilde_expand("~octtools")); + if (results[j-1][0] == '~') { + fprintf(stderr, "expansion of ~octtools failed\n"); + exit(-1); + } + (void) strcpy(results[j++], util_tilde_expand("~ricks/.login")); + + for (i = 0; i < j; i++) { + fprintf(stderr, "\t%s\n", results[i]); + } + + (void) util_csystem("who"); + + if ((file = util_file_search("uttest.c", "/tmp:..:../utility:.:/usr/tmp", "r")) == NIL(char)) { + fprintf(stderr, "could not find uttest.c\n"); + exit(-1); + } + fprintf(stderr, "file is %s\n", file); + if (util_file_search("BigWillyWasHere", "/usr/tmp/:/tmp:.", "r") != NIL(char)) { + fprintf(stderr, "found BigWillyWasHere\n"); + exit(-1); + } + if ((file = util_path_search("make")) == NIL(char)) { + fprintf(stderr, "could not find make\n"); + exit(-1); + } + fprintf(stderr, "program is %s\n", file); + + /* test pipefork */ + args[0] = util_strsav("sort"); + args[1] = util_strsav("-n"); + args[2] = 0; + + if (util_pipefork(args, &in, &out, &pid) != 1) { + (void) fprintf(stderr, "bad return from util_pipefork\n"); + exit(-1); + } + + for (i = 20; i >= 0; i--) { + (void) fprintf(in, "%d\n", i); + } + (void) fclose(in); + + i = 0; + while (fscanf(out, "%d", &dummy) == 1) { + if (i != dummy) { + (void) fprintf(stderr, "util_pipefork sort failed\n"); + exit(-1); + } + i++; + } + if (i != 21) { + (void) fprintf(stderr, "util_pipefork short count (%d)\n", i); + exit(-1); + } + + args[0] = util_strsav("betterNotExist"); + args[1] = 0; + + if (util_pipefork(args, &in, &out, &pid) == 1) { + (void) fprintf(stderr, "successfull return from util_pipefork, should have been a failure\n"); + exit(-1); + } + + time = util_cpu_time(); + fprintf(stderr, "time is %d / %s\n", time, util_print_time(time)); + + exit(0); +} + diff --git a/vst2blif/Makefile.am b/vst2blif/Makefile.am new file mode 100644 index 0000000..4ea08d8 --- /dev/null +++ b/vst2blif/Makefile.am @@ -0,0 +1,5 @@ +bin_PROGRAMS = vst2blif +vst2blif_SOURCES = vst2blif.c +dist_man1_MANS = vst2blif.1 + +EXTRA_DIST = hff.blif hff.v test.genlib diff --git a/vst2blif/Makefile.in b/vst2blif/Makefile.in new file mode 100644 index 0000000..7ad6cfe --- /dev/null +++ b/vst2blif/Makefile.in @@ -0,0 +1,441 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(vst2blif_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = vst2blif$(EXEEXT) +subdir = vst2blif +DIST_COMMON = $(dist_man1_MANS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_vst2blif_OBJECTS = vst2blif.$(OBJEXT) +vst2blif_OBJECTS = $(am_vst2blif_OBJECTS) +vst2blif_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(vst2blif_SOURCES) +DIST_SOURCES = $(vst2blif_SOURCES) +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(dist_man1_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +vst2blif_SOURCES = vst2blif.c +dist_man1_MANS = vst2blif.1 +EXTRA_DIST = hff.blif hff.v test.genlib +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps vst2blif/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps vst2blif/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +vst2blif$(EXEEXT): $(vst2blif_OBJECTS) $(vst2blif_DEPENDENCIES) + @rm -f vst2blif$(EXEEXT) + $(LINK) $(vst2blif_LDFLAGS) $(vst2blif_OBJECTS) $(vst2blif_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-man + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: install-man1 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am uninstall-man + +uninstall-man: uninstall-man1 + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-man1 \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-info-am uninstall-man uninstall-man1 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/vst2blif/hff.blif b/vst2blif/hff.blif new file mode 100644 index 0000000..a2d011a --- /dev/null +++ b/vst2blif/hff.blif @@ -0,0 +1,24 @@ +# File created by vst2blif ver 1.0 +# by Roberto Rambaldi +# D.E.I.S. Universita' di Bologna +.model hff + +.inputs d ck cln prn +.outputs q qn + +.gate inv1x a=d O=dn +.gate nand2 a=ck b=d O=a +.gate nand2 a=ck b=dn O=an +.gate nand2 a=a b=prn O=bt +.gate nand2 a=an b=cln O=bnt +.gate nand2 a=b b=iqn O=iq +.gate nand2 a=bn b=iqd O=iqn +.gate inv1x a=iq O=qt +.gate inv1x a=qt O=q +.gate inv1x a=iqn O=qn +.gate inv1x a=bt O=b +.gate inv1x a=bnt O=bn +.mlatch dlatch D=iq Q=iqd c1 3 +.gate one O=c1 + +.end diff --git a/vst2blif/hff.v b/vst2blif/hff.v new file mode 100644 index 0000000..74885f2 --- /dev/null +++ b/vst2blif/hff.v @@ -0,0 +1,60 @@ +entity hff is +port ( + d :in bit ; + ck :in bit ; + cln :in bit ; + prn :in bit ; + q :out bit ; + qn :out bit) ; +end hff; + +architecture structural of hff is + +signal dn,a,an,b,bn,iq,iqn,qt,bt,bnt,iqd,c1:bit; + +component nand2 +port (a,b:in bit; o:out bit); +end component; + +component inv1x +port (a:in bit; o:out bit); +end component; + +component dlatch +port (CLOCK,D:in bit; Q:out bit); +end component; + +component one +port (O:out bit); +end component; + +begin + u0: inv1x + port map (a=>d,o=>dn); + u1: nand2 + port map (a=>ck,b=>d,o=>a); + u2: nand2 + port map (a=>ck,b=>dn,o=>an); + u3: nand2 + port map (a=>a,b=>prn,o=>bt); + u4: nand2 + port map (a=>an,b=>cln,o=>bnt); + u5: nand2 + port map (a=>b,b=>iqn,o=>iq); + u6: nand2 + port map (a=>bn,b=>iqd,o=>iqn); + u7: inv1x + port map (a=>iq,o=>qt); + u8: inv1x + port map (a=>qt,o=>q); + u9: inv1x + port map (a=>iqn,o=>qn); + u10: inv1x + port map (a=>bt,o=>b); + u11: inv1x + port map (a=>bnt,o=>bn); + u12: dlatch + port map (CLOCK=>c1,Q=>iqd,D=>iq); + u13: one + port map (O=>c1); +end structural; diff --git a/vst2blif/test.genlib b/vst2blif/test.genlib new file mode 100644 index 0000000..8254dac --- /dev/null +++ b/vst2blif/test.genlib @@ -0,0 +1,171 @@ + GATE inv1x 928.00 O = ! a; + PIN a INV 0.0514 999.0 0.4200 4.7100 0.4200 3.6000 + + GATE inv2x 928.00 O = ! a; + PIN a INV 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 + + GATE inv4x 1392.00 O = ! a; + PIN a INV 0.1897 999.0 0.2300 1.0800 0.2700 0.8500 + + GATE xor 2320.00 O = ((!a * b) + (a * !b)); + PIN a UNKNOWN 0.1442 999.0 1.7700 5.2300 0.9600 4.6400 + PIN b UNKNOWN 0.1381 999.0 1.9400 4.6500 1.1400 5.2200 + + GATE xnor 2320.00 O = ((!a * !b) + (a * b)); + PIN a UNKNOWN 0.1502 999.0 1.1100 4.8600 1.0700 3.3900 + PIN b UNKNOWN 0.1352 999.0 1.5500 4.8700 1.0700 3.3900 + + GATE nand2 1392.00 O = ! (a * b); + PIN a INV 0.0777 999.0 0.6400 4.0900 0.4000 2.5700 + PIN b INV 0.0716 999.0 0.4600 4.1000 0.3700 2.5700 + + GATE nand3 1856.00 O = ! (a * b * c); + PIN a INV 0.1000 999.0 0.8900 3.6000 0.5100 2.4900 + PIN b INV 0.0828 999.0 0.7100 4.1100 0.4200 2.5000 + PIN c INV 0.0777 999.0 0.5600 4.3900 0.3500 2.4900 + + GATE nand4 2320.00 O = ! (a * b * c * d); + PIN a INV 0.1030 999.0 1.2700 3.6200 0.6700 2.3900 + PIN b INV 0.0980 999.0 1.0900 3.6100 0.6100 2.3900 + PIN c INV 0.0980 999.0 0.8200 3.6200 0.5500 2.4000 + PIN d INV 0.1050 999.0 0.5800 3.6200 0.3800 2.3900 + + GATE nor2 1392.00 O = ! (a + b); + PIN a INV 0.0736 999.0 0.3300 3.6400 0.4500 3.6400 + PIN b INV 0.0968 999.0 0.5000 3.6400 0.7000 3.6600 + + GATE nor3 1856.00 O = ! (a + b + c); + PIN a INV 0.0856 999.0 0.8400 5.0400 1.3000 3.4500 + PIN b INV 0.0806 999.0 0.7800 5.0300 1.1400 3.4300 + PIN c INV 0.0826 999.0 0.5200 5.0300 0.8400 3.4400 + + GATE nor4 2320.00 O = ! (a + b + c + d); + PIN a INV 0.0887 999.0 0.4100 5.9100 1.1600 3.2000 + PIN b INV 0.0867 999.0 0.8500 5.9100 1.5300 3.1800 + PIN c INV 0.0867 999.0 1.1100 5.9200 1.7500 3.1900 + PIN d INV 0.0887 999.0 1.2700 5.9100 1.9400 3.2000 + + GATE aoi21 1856.00 O = ! ((a1 * a2) + b); + PIN a1 INV 0.1029 999.0 0.7500 3.5200 0.6700 2.5300 + PIN a2 INV 0.0908 999.0 0.6700 3.6400 0.6200 2.5200 + PIN b INV 0.1110 999.0 0.5800 3.6400 0.2100 1.2800 + + GATE aoi31 2320.00 O = ! ((a1 * a2 * a3) + b); + PIN a1 INV 0.1009 999.0 0.9100 4.0400 0.8100 2.8600 + PIN a2 INV 0.1049 999.0 1.0500 3.9300 0.8700 2.8700 + PIN a3 INV 0.1059 999.0 1.1500 3.9400 0.9400 2.8600 + PIN b INV 0.0979 999.0 0.8900 4.0600 0.2500 1.2800 + + GATE aoi22 2320.00 O = ! ((a1 * a2) + (b1 * b2)); + PIN a1 INV 0.1019 999.0 0.9200 3.4600 0.9400 2.7900 + PIN a2 INV 0.0908 999.0 0.8400 3.6400 0.8500 2.7900 + PIN b1 INV 0.0958 999.0 0.6100 3.6400 0.4900 2.9300 + PIN b2 INV 0.0988 999.0 0.7000 3.6400 0.5400 2.9300 + + GATE aoi32 2784.00 O = ! ((a1 * a2 * a3) + (b1 * b2)); + PIN a1 INV 0.1029 999.0 1.0600 3.8100 0.9600 2.9100 + PIN a2 INV 0.1009 999.0 1.2000 3.8100 1.0300 2.9000 + PIN a3 INV 0.1060 999.0 1.2900 3.6900 1.0600 2.9100 + PIN b1 INV 0.0979 999.0 0.9100 3.8100 0.4300 2.1200 + PIN b2 INV 0.1049 999.0 0.7800 3.5900 0.4300 2.1200 + + GATE aoi33 3248.00 O = ! ((a1 * a2 * a3) + (b1 * b2 * b3)); + PIN a1 INV 0.1029 999.0 1.3300 3.9100 1.3000 2.9100 + PIN a2 INV 0.1029 999.0 1.4600 3.8400 1.4100 2.9100 + PIN a3 INV 0.1120 999.0 1.4700 3.6500 1.4100 2.9100 + PIN b1 INV 0.1029 999.0 1.1100 3.5900 0.7600 2.9000 + PIN b2 INV 0.0949 999.0 1.0400 3.9100 0.6800 2.9100 + PIN b3 INV 0.1039 999.0 0.8400 3.5800 0.6400 2.9000 + + GATE aoi211 2320.00 O = ! ((a1 * a2) + b + c); + PIN a1 INV 0.1039 999.0 1.1200 4.8100 1.0300 2.3800 + PIN a2 INV 0.1090 999.0 1.2900 4.8100 1.0300 2.3800 + PIN b INV 0.1080 999.0 1.0400 4.8300 0.5200 1.4000 + PIN c INV 0.1008 999.0 0.6800 4.8300 0.5100 1.7900 + + GATE aoi221 2784.00 O = ! ((a1 * a2) + (b1 * b2) + c); + PIN a1 INV 0.1089 999.0 1.4800 4.4300 1.3300 2.7800 + PIN a2 INV 0.0948 999.0 1.4200 4.5600 1.4000 2.7500 + PIN b1 INV 0.1029 999.0 0.7600 4.4700 0.7900 2.8900 + PIN b2 INV 0.1049 999.0 0.7300 4.5800 0.7800 2.9100 + PIN c INV 0.1110 999.0 1.3900 4.5600 0.7000 1.5100 + + GATE aoi222 3712.00 O = ! ((a1 * a2) + (b1 * b2) + (c1 * c2) ); + PIN a1 INV 0.1019 999.0 1.7700 4.5800 1.5600 2.9500 + PIN a2 INV 0.0958 999.0 1.7300 4.6900 1.6000 2.9300 + PIN b1 INV 0.1039 999.0 1.3400 4.6800 1.2100 2.9200 + PIN b2 INV 0.1039 999.0 1.5000 4.6900 1.2200 2.9200 + PIN c1 INV 0.0958 999.0 0.9200 4.6700 0.8100 2.9200 + PIN c2 INV 0.1039 999.0 0.7700 4.4700 0.7600 2.9200 + + GATE oai21 1856.00 O = ! ( (a1 + a2) * b); + PIN a1 INV 0.1019 999.0 0.6900 3.9400 0.5300 2.4700 + PIN a2 INV 0.0979 999.0 0.8700 3.9300 0.6300 2.4700 + PIN b INV 0.0998 999.0 0.3700 2.0500 0.5700 2.5100 + + GATE oai31 2320.00 O = ! ( (a1 + a2 + a3) * b); + PIN a1 INV 0.1089 999.0 1.2700 4.7100 1.0300 2.4300 + PIN a2 INV 0.1049 999.0 1.1100 4.7100 1.0400 2.5700 + PIN a3 INV 0.1090 999.0 0.8500 4.7100 0.6900 2.3800 + PIN b INV 0.1059 999.0 0.3800 1.8600 0.8100 2.7300 + + GATE oai22 2320.00 O = ! ( (a1 + a2) * (b1 + b2)); + PIN a1 INV 0.1009 999.0 1.1000 4.0600 0.9000 2.5000 + PIN a2 INV 0.1029 999.0 0.9900 4.0600 0.6800 2.3600 + PIN b1 INV 0.0958 999.0 0.6900 3.6600 0.7400 2.5300 + PIN b2 INV 0.1039 999.0 0.6100 3.6600 0.5600 2.0600 + + GATE oai32 2784.00 O = ! ( (a1 + a2 + a3) * (b1 + b2)); + PIN a1 INV 0.1130 999.0 1.3900 4.4600 1.0400 2.4600 + PIN a2 INV 0.1069 999.0 1.2500 4.4600 1.0900 2.6300 + PIN a3 INV 0.1140 999.0 0.9900 4.4600 0.7400 2.4200 + PIN b1 INV 0.1059 999.0 0.5800 3.2000 0.7900 2.7100 + PIN b2 INV 0.1130 999.0 0.6800 3.2100 0.8300 2.3400 + + GATE oai33 3248.00 O = ! ( (a1 + a2 + a3) * (b1 + b2 + b3)); + PIN a1 INV 0.1170 999.0 1.5800 4.3000 1.4800 2.4700 + PIN a2 INV 0.1089 999.0 1.5000 4.3100 1.4200 2.6300 + PIN a3 INV 0.1079 999.0 1.2400 4.3100 1.1700 2.6500 + PIN b1 INV 0.1170 999.0 0.8000 4.3000 0.8200 2.2700 + PIN b2 INV 0.1089 999.0 0.0000 4.3000 1.1700 2.6400 + PIN b3 INV 0.1109 999.0 1.1300 4.3100 1.3500 2.6500 + + GATE oai211 2320.00 O = ! ( (a1 + a2) * b * c); + PIN a1 INV 0.1070 999.0 1.1200 4.1700 0.5900 2.3100 + PIN a2 INV 0.1131 999.0 1.3000 4.1600 0.7900 2.3600 + PIN b INV 0.1050 999.0 0.5100 2.1300 0.6900 2.4000 + PIN c INV 0.1050 999.0 0.5000 2.4600 0.5200 2.4100 + + GATE oai221 2784.00 O = ! ( (a1 + a2) * (b1 + b2) * c); + PIN a1 INV 0.1039 999.0 1.5800 4.1700 1.1100 2.4700 + PIN a2 INV 0.1050 999.0 1.4800 4.1700 0.8600 2.3600 + PIN b1 INV 0.1080 999.0 0.9400 4.0300 0.8100 2.5000 + PIN b2 INV 0.1060 999.0 0.7600 4.0300 0.6400 2.5000 + PIN c INV 0.1019 999.0 0.7800 2.2800 0.9000 2.5400 + + GATE oai222 3248.00 O = ! ( (a1 + a2) * (b1 + b2) * (c1 + c2)); + PIN a1 INV 0.1161 999.0 1.7700 3.7500 1.2100 2.4700 + PIN a2 INV 0.1110 999.0 1.6200 3.7500 1.1300 2.4800 + PIN b1 INV 0.1009 999.0 1.1700 3.5800 1.0700 2.4800 + PIN b2 INV 0.1191 999.0 1.3500 3.5800 1.1000 2.3500 + PIN c1 INV 0.1060 999.0 0.9900 3.5900 0.9300 2.4900 + PIN c2 INV 0.1140 999.0 0.8200 3.5800 0.7900 2.4800 + +GATE zero 0 O=CONST0; +GATE one 0 O=CONST1; + +# D-type latches and flip-flops are necessary for sequential +# technology mapping. +# WARNING: area and delay parameters are arbitrary. +LATCH dff 4640.00 Q = D; +PIN D NONINV 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +SEQ Q ANY RISING_EDGE +CONTROL CLOCK 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +CONSTRAINT D 0.1 0.1 + +LATCH dlatch 3712.00 Q = D; +PIN D NONINV 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +SEQ Q ANY ACTIVE_HIGH +CONTROL CLOCK 0.1009 999.0 0.3000 1.9800 0.2900 1.8200 +CONSTRAINT D 0.1 0.1 + diff --git a/vst2blif/vst2blif.1 b/vst2blif/vst2blif.1 new file mode 100644 index 0000000..ffe7552 --- /dev/null +++ b/vst2blif/vst2blif.1 @@ -0,0 +1,234 @@ +.TH Vst2Blif 1 "April 5 1994" "Release 1.0" +.SH NAME +Vst2Blif - A filter that converts a structural vhdl source into a blif file. +.SH SYNOPSIS +.ta 8n +\fBvst2blif\fP [-h] [-v] [-u] [-s \fIname\fP] [-d \fIname\fP] [-c \fIname\fP] +\fILibraryName\fP [inputfile [outputfile]] +.SH OPTIONS +.PP +\fBVst2Blif\fP accepts the options described below: +.TP 8 +.B \-h +A brief summary of the allowed options are printed to standard error. +.TP 8 +.B \-v +All the warnings will be sent to standard output. See the Warning paragraph. +.TP 8 +.B \-u +Converts all actual terminals to uppercase. +.TP 8 +.B \-s \fIname\fP +Uses "name" as the terminal for VSS, and eliminates all of the formals with +this name. +In fact the VHDL description used by Alliance includes the power lines, +but SIS does not need them . So you may skip them by +using this option for the VSS terminal and the next one for VDD. +The default value is VSS. +.TP 8 +.B \-d \fIname\fP +Uses "name" as the terminal for VDD. The default is VDD. +.TP 8 +.B \-c \fIname\fP +Adds .clock "name" at the output file. +.TP 8 +.B\-n +Disables the VSS and VDD checking. +.TP 8 +.B\-i \fInumber\fP +Sets the initial value for latches, the default is 3 (=UNDEFINED) +.TP 8 +.B LibraryName +Is the full-path name of the library (in \fIGENLIB\fP format) to use for +the conversion. +.TP 8 +.B Input-File +Is the name of the input file. If this name and the name of the +output file are missing, stdin will be used as the input file. +.TP 8 +.B Output-File +Indicates the name of the output file. If it is missing, stdout will be used. + +.SH DESCRIPTION +The \fBvst2blif\fP program converts a structural vhdl file into a blif. +The vhdl set supported is the same of the \fIALLIANCE\fP CAD system +(CAO-VLSI team at MASI laboratory, University P. et M. Curie 4, place +Jussieu ; 75252 PARIS Cedex 05 ; FRANCE ; E-mail: cao-vlsi@masi.ibp.fr ). +The syntax is a subset of the standard VHDL. The following +examples will show the allowed keyword and how to use them: + +.PP +.nf +ENTITY \fIentity_name\fP IS + +GENERIC ( .. ); +-- this will be ignored + +PORT ( .. ); +-- only \fBBIT\fP and \fBBIT_VECTORS\fP type of signals + +END \fIentity_name\fP; + + +ARCHITECTURE \fItype\fP OF \fIentity_name\fP IS +-- multiple entities are allowed, but as they are declared +-- they must be followed by their architecture declarations. + +SIGNAL ... +-- parsed but ignored + +COMPONENT \fIname\fP +PORT( .. ); +END COMPONENT; +-- No checks are carried out here. These strings are +-- just parsed. + +-- SIGNAL clause and COMPONENT CLAUSE may be mixed + +BEGIN + + \fIname\fP : \fIComponentName\fP ( + formal_terminal => actual_terminal; + -- No vectors are allowed, only single elements of vectors + . + . + ); + +-- and so on.. + +END \fItype\t; +.fi + +.SH EXAMPLE +Here is a simple half adder to show how the program works: +.nf +entity half_adder is +port ( + a,b : in bit; -- inputs + sum : out bit; + carry : out bit; + clk : in bit; -- clock to latch the final result + vdd,vss : in bit -- power lines + ); +end half_adder; + + +architecture structural of halfadder is + +component inv1x +port( + a : in bit; + o : out bit; + vss,vdd : in bit + ); +end component; + +component xor +port( + a,b : in bit; + o : out bit; + vss,vdd : in bit + ); +end component; + +component nand2 +port( + a,b : in bit; + o : out bit; + vss,vdd : in bit + ); +end component; + +component dlatch +port( + clk,d : in bit; + q : out bit; + vss,vdd : in bit + ); +end component; + +signal carrytmp, sumtmp, carry_ : bit; +-- Note that the program will work perfectly even +-- without this declaration: SIS does not need the +-- declaration of the internal signals. + +begin + + -- CARRY = a*b + inst1 : nand2 + port map ( a => a, b => b, o => carry_, vss => vss, vdd => vdd ); + inst2 : inv1x + port map ( a => carry_, o => carrytmp, vss => vss, vdd => vdd); + + -- SUM = A xor B + inst9 : xor + port map ( a => a, b => b, o => sumtmp, vss => vss, vdd => vdd ); + + -- let's save the result in a latch + instA : dlatch + port map ( d => sumtmp, q => sum, clock => clk, + vss => vss, vdd => vdd ); + instB : dlatch + port map ( d => carrytmp, q => carry, clock => clk, + vss => vss, vdd => vdd ); + +end structural; +.fi +.PP +This file will be converted using a command like this + +cat half.vst | vst2blif -c clk -v full_lib2.genlib > half.blif + +or, the equivalent one : + +vst2blif -c clk -v full_lib2.genlib half.vst half.blif + +Then the resul file will be: +.PP +.nf + # File created by vst2blif ver 1.0 + .model half_adder + + .inputs a b + .outputs sum carry + .clock clk + + .gate nand2 a=a b=b O=carry_ + .gate inv1x a=carry_ O=carrytmp + .gate xor a=a b=b O=sumtmp + .mlatch dlatch D=sumtmp Q=sum clk 3 + .mlatch dlatch D=carrytmp Q=carry clk 3 + + .end + +.fi +.PP +The library used is the lib2.genlib and the lib2_latch.genlib merged +toghether (into the fil efull_lib2.genlib). In +fact the program takes as input only one library-file. +.PP +.SH WARNINGS +As you may see the VHDL source has a lot of words (keywords) that this +program can skip. Just consider the clause +.PP +\fBCOMPONENT\fP name +\fBPORT\fB ( formal1 : type; ... formal : type ); +.PP +and consider the part with the PORT declaration. The tokenizer gives 2 tokens +to the program : PORT and '(' , the first is necessary, but not the '('. +Since we know that we are looking at a PORT CLAUSE, + we expect a list of definitions of +formal terminals. If the '(' is missing you will get a warning (it is a VHDL +syntax error ) but this will not create any problem to the filter. +This situation is true in other cases where there are more 'tokens' +than the ones that will be stricly necessary. +The program prints these warnings to the stderr if the option -v is given. + + +.SH SEE ALSO +"The VHDL CookBook" By Peter J.Ashenden + chapter 3: "VHDL Describes Structure" + + +.SH BUGS +Please reports any bugs to blaurea1@deis06.cineca.it diff --git a/vst2blif/vst2blif.c b/vst2blif/vst2blif.c new file mode 100644 index 0000000..88478e7 --- /dev/null +++ b/vst2blif/vst2blif.c @@ -0,0 +1,2336 @@ +static char rcsid[] = "$Id: vst2blif.c,v 1.1.1.1 2004/02/07 10:14:13 pchong Exp $"; +#ifndef DATE +#define DATE "Compile date not supplied" +#endif +static char build_date[] = DATE; +/* + * $Header: /users/pchong/CVS/sis/vst2blif/vst2blif.c,v 1.1.1.1 2004/02/07 10:14:13 pchong Exp $ + * $Revision: 1.1.1.1 $ + * $Source: /users/pchong/CVS/sis/vst2blif/vst2blif.c,v $ + * $Log: vst2blif.c,v $ + * Revision 1.1.1.1 2004/02/07 10:14:13 pchong + * imported + * + * + * BY rAMBALDI rOBERTO. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <unistd.h> + + +#define MAXTOKENLEN 256 +#define MAXNAMELEN 32 + +enum TOKEN_STATES { tZERO, tTOKEN, tREM1, tREM2, tSTRING, tEOF }; + + +/* * + * These are the test used in the tokenizer, please refer to the graph * + * included in the documentation doc. * + * */ + +/* ASCII seq: ( ) * + , : ; < = > * + * code 40 41 42 43 44 58 59 60 61 62 */ +#define isSTK(c) (( ((c)=='[') || ((c)==']') || ((c)=='|') || ((c)=='#') || \ + ( ((c)>=':') && ((c)<='>') ) || \ + ( ((c)>='(') && ((c)<=',') ) || ((c)=='&') )) +#define isBLK(c) ( (((c)=='\t') || ((c)==' ') || ((c)=='\r')) ) +#define isREM(c) ( ((c)=='-') ) +#define isDQ(c) ( ((c)=='"') ) +#define isEOL(c) ( ((c)=='\n') ) +#define isEOF(c) ( ((c)=='\0') ) +#define isEOT(c) ( (isBLK((c)) || isEOL((c))) ) + + +/* structure that contains all the info extracted from the library * + * All the pins, input, outp[ut and clock (if needed) * + * This because SIS should be case sensitive and VHDL is case * + * insensitive, so we must keep the library's names of gates and * + * pins. In the future this may be useful for further checks that * + * in this version are not performed. */ + +/* list of inputs */ +struct PortName{ + char name[MAXNAMELEN]; + int notused; /* this flag is used to check if a * + * formal terminal has been already * + * connected. */ + struct PortName *next; +}; + + +struct Ports{ + char name[MAXNAMELEN]; +}; + +struct Cell { + char name[MAXNAMELEN]; + int npins; + char type; + struct SIGstruct *io; + struct Ports *formals; + struct Cell *next; +}; + +struct LibCell { + char name[MAXNAMELEN]; + int npins; + char clk[MAXNAMELEN]; + struct Ports *formals; + struct LibCell *next; +}; + +struct Instance { + char name[MAXNAMELEN]; + struct Cell *what; + struct Ports *actuals; + struct Instance *next; +}; + + +struct BITstruct { + char name[MAXNAMELEN+10]; + char dir; + struct BITstruct *next; +}; + + +struct SIGstruct { + char name[MAXNAMELEN]; + char dir; + int start; + int end; + struct SIGstruct *next; +}; + + +struct TERMstruct { + char name[MAXNAMELEN]; + int start; + int end; +}; + +struct ENTITYstruct { + char name[MAXNAMELEN]; + struct Cell *Components; + struct Cell *EntityPort; + struct SIGstruct *Internals; + struct Instance *Net; +}; + + +struct LibCell *ScanLibrary(); + +FILE *In; +FILE *Out; +struct LibCell *LIBRARY; +int line; /* line parsed */ + +int SendTokenBack; /* Used to send the token back to the * + * input stream in case of a missing * + * keyword, */ +char VDD[MAXNAMELEN]={ 0 }; +char VSS[MAXNAMELEN]={ 0 }; +int INIT; +int LINKAGE; +int LOWERCASE; +char CLOCK[MAXNAMELEN]; +int WARNING; +int INSTANCE; +struct Cell *cells; + + +/*===========================================================================* + + Utilities. + CloseAll : closes all the files ads flushes the memory + Error : display an error message an then exit + KwrdCmp : compares keywords --> case insensitive + + *===========================================================================*/ + +/* -=[ CloseAll ]=- * + * Closes all the files and flushes the used memory * + * */ +void CloseAll() +{ + + if (In!=stdin) (void)fclose(In); + if (Out!=stdout) (void)fclose(Out); + + free(cells); + +} + + +/* -=[ Error ]=- * + * Displays an error message, and then exit * + * * + * Input : * + * msg = message to printout before exiting */ +void Error(Msg) +char *Msg; +{ + (void)fprintf(stderr,"*** Error : %s\n",Msg); + CloseAll(); + exit(1); +} + +/* -=[ KwrdCmp ]=- * + * Compares to strings, without taking care of the * + * case. * + * * + * Inoput : * + * name = first string, tipically the token * + * keywrd = second string, tipically a keyword * + * Output : * + * int = 1 if the strings matches * + * 0 if they don't match */ +int KwrdCmp(name,keywrd) +char *name; +char *keywrd; +{ + int t; + int len; + + if ( (len=strlen(name)) != (strlen(keywrd))) return 0; + if (!len) return 0; + /* if length 0 exit */ + for(t=0; (t<len); name++, keywrd++, t++){ + /* if they're not equal */ + if (toupper(*name)!=toupper(*keywrd)) + return 0; + /* EoL, exit */ + if (*keywrd=='\0') break; + } + return 1; +} + +/* -=[ CheckArgs ]=- * + * Gets the options from the command line, open * + * the input and output file and read params from * + * the library file. * + * * + * Input : * + * argc,argv = usual cmdline arcguments */ +void CheckArgs(argc,argv) +int argc; +char **argv; +{ + char *s; + char c; + int help; + int NoPower; + + extern char *optarg; + extern int optind; + + s=&( argv[0][strlen(argv[0])-1] ); + while( (s>= &(argv[0][0])) && (*s!='/') ) { s--; } + + (void)fprintf(stderr,"\t\t Vst Converter v1.5\n"); + (void)fprintf(stderr,"\t\t by Roberto Rambaldi\n"); + (void)fprintf(stderr,"\t\tD.E.I.S. Universita' di Bologna\n\n"); + help=0; INSTANCE=1; NoPower=0; LOWERCASE=1; INIT='3'; + while( (c=getopt(argc,argv,"s:S:d:D:c:C:i:I:l:L:hHvVuUnN$") )>0 ){ + switch (toupper(c)) { + case 'S': + (void)strncpy(VSS,optarg,MAXNAMELEN); + break; + case 'D': + (void)strncpy(VDD,optarg,MAXNAMELEN); + break; + case 'H': + help=1; + break; + case 'C': + (void)strncpy(CLOCK,optarg,MAXNAMELEN); + break; + case 'I': + INIT= *optarg; + if ((INIT<'0') || (INIT>'3')) { + (void)fprintf(stderr,"Wrong latch init value"); + help=1; + } + break; + case 'L': + if (KwrdCmp(optarg,"IN")) { + LINKAGE='i'; + } else { + if (KwrdCmp(optarg,"OUT")) { + LINKAGE='o'; + } else { + (void)fprintf(stderr,"\tUnknow direction for a port of type linkage\n"); + help=1; + } + } + break; + case 'U': + LOWERCASE=0; + break; + case 'N': + NoPower=1; + break; + case '$': + help=1; + (void)fprintf(stderr,"\n\tID = %s\n",rcsid); + (void)fprintf(stderr,"\tCompiled on %s\n\n",build_date); + break; + } + } + + + if (!help) { + if (LOWERCASE) + for(s=&(CLOCK[0]); *s!='\0'; s++) (void)tolower(*s); + else + for(s=&(CLOCK[0]); *s!='\0'; s++) (void)toupper(*s); + + if (optind>=argc) { + (void)fprintf(stderr,"No Library file specified\n\n"); + help=1; + } else { + LIBRARY=(struct LibCell *)ScanLibrary(argv[optind]); + if (++optind>=argc){ + In=stdin; Out=stdout; + } else { + if ((In=fopen(argv[optind],"rt"))==NULL) { + (void)fprintf(stderr,"Couldn't read input file"); + help=1; + } + if (++optind>=argc) { Out=stdout; } + else { + if ((Out=fopen(argv[optind],"wt"))==NULL) { + (void)fprintf(stderr,"Could'n make opuput file"); + help=1; + } + } + } + } + + if (NoPower) { + VDD[0]='\0'; VSS[0]='\0'; + } else { + if (!VDD[0]) (void)strcpy(VDD,"VDD"); + if (!VSS[0]) (void)strcpy(VSS,"VSS"); + } + } + + if (help) { + (void)fprintf(stderr,"\tUsage: vst2blif [options] <library> [infile [outfile]]\n"); + (void)fprintf(stderr,"\t\t if outfile is not given will be used stdout, if also\n"); + (void)fprintf(stderr,"\t\t infile is not given will be used stdin instead.\n"); + (void)fprintf(stderr,"\t<library>\t is the name of the library file to use\n"); + (void)fprintf(stderr,"\tOptions :\n\t-s <name>\t <name> will be used for VSS net\n"); + (void)fprintf(stderr,"\t-d <name>\t <name> will be used for VDD net\n"); + (void)fprintf(stderr,"\t-c <name>\t .clock <name> will be added to the blif file\n"); + (void)fprintf(stderr,"\t-i <value>\t default value for latches, must be between 0 and 3\n"); + (void)fprintf(stderr,"\t-l <in/out>\t sets the direction for linkage ports\n"); + (void)fprintf(stderr,"\t\t\t the default value is \"in\"\n"); + (void)fprintf(stderr,"\t-u\t\t converts all names to uppercase\n"); + (void)fprintf(stderr,"\t-n\t\t no VSS or VDD to skip.\n"); + (void)fprintf(stderr,"\t-h\t\t prints these lines"); + (void)fprintf(stderr,"\n\tIf no VDD or VSS nets are given VDD and VSS will be used\n"); + exit(0); + } +} + +/* -=[ GetNextToken ]=- * + * Tokenizer, see the graph to understand how it * + * works. * + * * + * Inputs : * + * tok = pointer to the final buffer, which is * + * a copy of the internal Token, it's * + * *indirectly* uses SendTokenBack as input and * + * line as output */ +void GetNextToken(tok) +char *tok; +{ + static char init=0; + static enum TOKEN_STATES state; + static char sentback; + static char str; + static char Token[MAXTOKENLEN]; + char *t; + int num; + int TokenReady; + char c; + + if (!init) { + state=tZERO; + init=1; + line=0; + SendTokenBack=0; + } + + t=&(Token[0]); + num=0; + TokenReady=0; + str=0; + + if (SendTokenBack) { + SendTokenBack=0; + (void)strcpy(tok,Token); + return; + } + + do { + if (sentback) { + c=sentback; + } else { + c=fgetc(In); + if (feof(In)) state=tEOF; + if (c=='\n') line++; + } + + switch (state){ + case tZERO: + /*******************/ + /* ZERO state */ + /*******************/ + num=0; + sentback='\0'; + if (isSTK(c)) { + *t=c; t++; + TokenReady=1; + } else { + if isREM(c) { + *t=c; + t++; num++; + sentback='\0'; + state=tREM1; + } else { + if isDQ(c) { + sentback='\0'; + state=tSTRING; + } else { + if isEOF(c) { + state=tEOF; + sentback=1; + TokenReady=0; + } else { + if isEOT(c) { + state=tZERO; + /* stay in tZERO */ + } else { + sentback=c; + state=tTOKEN; + } + } + } + } + } + break; + case tTOKEN: + /*******************/ + /* TOKEN state */ + /*******************/ + TokenReady=1; + sentback=c; + if (isSTK(c)) { + state=tZERO; + } else { + if isREM(c) { + state=tREM1; + } else { + if isDQ(c) { + sentback='\0'; + state=tSTRING; + } else { + if isEOF(c) { + sentback=1; + state=tEOF; + } else { + if isEOT(c) { + sentback='\0'; + state=tZERO; + } else { + sentback='\0'; + if (num>=(MAXTOKENLEN-1)){ + sentback=c; + (void)fprintf(stderr,"*Parse Warning* Line %u: token too long !\n",line); + } else { + if (LOWERCASE) *t=tolower(c); + else *t=toupper(c); + t++; num++; + TokenReady=0; + /* fprintf(stderr,"."); */ + } + state=tTOKEN; + } + } + } + } + } + break; + case tREM1: + /*******************/ + /* REM1 state */ + /*******************/ + TokenReady=1; + sentback=c; + if (isSTK(c)) { + state=tZERO; + } else { + if isREM(c) { + sentback='\0'; + state=tREM2; /* it's a remmark. */ + TokenReady=0; + } else { + if isDQ(c) { + sentback='\0'; + state=tSTRING; + } else { + if isEOF(c) { + state=tEOF; + sentback=1; + TokenReady=0; + } else { + if isEOT(c) { + sentback='\0'; + /* there's no need to parse an EOT */ + state=tZERO; + } else { + state=tTOKEN; + } + } + } + } + } + break; + case tREM2: + /*******************/ + /* REM2 state */ + /*******************/ + sentback='\0'; + TokenReady=0; + if isEOL(c) { + num=0; + t=&(Token[0]); + state=tZERO; + } else { + if isEOF(c) { + state=tEOF; + sentback=1; + TokenReady=0; + } else { + state=tREM2; + } + } + break; + case tSTRING: + /*******************/ + /* STRING state */ + /*******************/ + if (!str) { + *t='"'; t++; num++; /* first '"' */ + str=1; + } + sentback='\0'; + TokenReady=1; + if isDQ(c) { + *t=c; t++; num++; + state=tZERO; /* There's no sentback char so this * + * double quote is the last one *ONLY* */ + } else { + if isEOF(c) { + state=tEOF; /* this is *UNESPECTED* ! */ + sentback=1; + (void)fprintf(stderr,"*Parse Warning* Line %u: unespected Eof\n",line); + } else { + sentback='\0'; + if (num>=MAXTOKENLEN-2){ + sentback=c; + (void)fprintf(stderr,"*Parse Warning* Line %u: token too long !\n",line); + } else { + if (LOWERCASE) *t=tolower(c); + else *t=toupper(c); + t++; num++; + TokenReady=0; + state=tSTRING; + } + } + } + break; + case tEOF: + /*******************/ + /* EOF state */ + /*******************/ + t=&(Token[0]); + TokenReady=1; + state=tEOF; + break; + } + } while(!TokenReady); + *(t)='\0'; + (void)strcpy(tok,Token); + return ; +} + +/*====================================================================* + + + ReleaseBit : deallocates an entire BITstruct structure + ReleaseSIG : deallocates an entire SIGstruct structure + NewCell : allocates memory for a new cell + + + ====================================================================*/ + +void ReleaseBit(ptr) +struct BITstruct *ptr; +{ + struct BITstruct *tmp; + + while(ptr!=NULL){ + tmp=ptr->next; + free(ptr); + ptr=tmp; + } +} + + +void ReleaseSIG(ptr) +struct SIGstruct *ptr; +{ + struct SIGstruct *tmp; + + while(ptr!=NULL){ + tmp=ptr->next; + free(ptr); + ptr=tmp; + } +} + + + +void AddBIT(BITptr,name,dir) +struct BITstruct **BITptr; +char *name; +char dir; +{ + + (*BITptr)->next=(struct BITstruct *)calloc(1,sizeof(struct BITstruct)); + if ( (*BITptr)->next==NULL) { + Error("Allocation Error or not enought memory !"); + } + (*BITptr)=(*BITptr)->next; + (void)strcpy((*BITptr)->name,name); + (*BITptr)->dir=dir; + (*BITptr)->next=NULL; +} + +void AddSIG(SIGptr,name,dir,start,end) +struct SIGstruct **SIGptr; +char *name; +char dir; +int start; +int end; +{ + + (*SIGptr)->next=(struct SIGstruct *)calloc(1,sizeof(struct SIGstruct)); + if ( (*SIGptr)->next==NULL) { + Error("Allocation Error or not enought memory !"); + } + (*SIGptr)=(*SIGptr)->next; + (void)strcpy((*SIGptr)->name,name); + (*SIGptr)->dir=dir; + (*SIGptr)->start=start; + (*SIGptr)->end=end; + (*SIGptr)->next=NULL; +#ifdef DEBUG + (void)fprintf(stderr,"\n\t\tAdded SIGNAL <%s>, dir = %c, start =%d, end =%d",(*SIGptr)->name,(*SIGptr)->dir,(*SIGptr)->start,(*SIGptr)->end); +#endif +} + + + +/* -=[ Warning ]=- * + * Puts a message on stderr, write the current line * + * and then sends the current token back * + * * + * Inputs : * + * name = message */ +void Warning(name) +char *name; +{ + if (WARNING) (void)fprintf(stderr,"*parse warning* Line %u : %s\n",line,name); + SendTokenBack=1; +} + +/* -=[ VstError ]=- * + * sends to stderr a message and then gets tokens * + * until a gicen one is reached * + * * + * Input : * + * name = message to print * + * next = token to reach */ +void VstError(name,next) +char *name; +char *next; +{ + char *w; + char LocalToken[MAXTOKENLEN]; + + w=&(LocalToken[0]); + (void)fprintf(stderr,"*Error* Line %u : %s\n",line,name); + (void)fprintf(stderr,"*Error* Line %u : skipping text until the keyword %s is reached\n",line,next); + SendTokenBack=1; + do{ + GetNextToken(w); + if (feof(In)) + Error("Unespected Eof!"); + } while( !KwrdCmp(w,next) ); +} + +/* -=[ DecNumber ]=- * + * checks if a token is a decimal number * + * * + * Input : * + * string = token to check * + * Output : * + * int = converted integer, or 0 if the string * + * is not a number * + * REMMARK : strtol() can be used... */ +int DecNumber(string) +char *string; +{ + char msg[50]; + char *s; + + for(s=string; *s!='\0'; s++) + if (!isdigit(*s)) { + (void)sprintf(msg,"*Error Line %u : Expected decimal integer number \n",line); + Error(msg); + } + return atoi(string); +} + + +/*=========================================================================* + + + Genlib scan + ^^^^^^^^^^^ + + PrintGates : outputs the gates read if in DEBUG mode + GetLibToken : tokenizer for the genlib file + IsHere : formals check + ScanLibrary : parses the genlib files and builds the data structure. + WhatGate : checks for a cell into the library struct. + + *=========================================================================*/ + +/* -=[ PrintGates ]=- * + * A kind debugger procedure ... * + * * + * Input : * + * cell = library file */ +void PrintGates(cell) +struct LibCell *cell; +{ + struct Ports *ptr; + int j; + + while(cell->next!=NULL){ + if (cell->clk[0]) { + (void)fprintf(stderr,"Latch name: %s, num pins : %d\n",cell->name,cell->npins); + } else { + (void)fprintf(stderr,"Cell name: %s, num pins : %d\n",cell->name,cell->npins); + } + ptr=cell->formals; + for(j=0; j<cell->npins; j++, ptr++){ + (void)fprintf(stderr,"\tpin %d : %s\n",j,ptr->name); + } + if (cell->clk[0]) { + (void)fprintf(stderr,"\tclock : %s\n",cell->clk); + } + cell=cell->next; + } +} + +/* -=[ GetTypeOfCell ]=- * + * Scans the genlib data structure to find the * + * type of the cell * + * * + * Input : * + * cell = library file * + * name = name of cell to match * + * Output : * + * type of cell */ +char GetTypeOfCell(cell,name) +struct LibCell *cell; +char *name; +{ + while(cell->next!=NULL){ + if (KwrdCmp(cell->name,name)) { + if (cell->clk[0]) { + return 'L'; /* Library celly, type = L(atch) */ + } else { + return 'G'; /* Library celly, type = G(ate) */ + } + } + cell=cell->next; + } + return 'S'; /* type = S(ubcircuit) */ +} + +/* -=[ GetLibToken ]=- * + * Tokenizer to scan the library file * + * * + * Input : * + * Lib = library file * + * Output : * + * tok = filled with the new token */ +void GetLibToken(Lib,tok) +FILE *Lib; +char *tok; +{ + enum states { tZERO, tLONG, tEOF, tSTRING, tREM }; + static enum states next; + static char init=0; + static char sentback; + static char TOKEN[MAXTOKENLEN]; + static char str; + char ready; + int num; + char *t; + char c; + + if (!init){ + sentback=0; + init=1; + next=tZERO; + str=0; + } + + t=&(TOKEN[0]); + num=0; + str=0; + + do{ + if (sentback){ + c=sentback; + } else { + c=fgetc(Lib); + } + if (feof(Lib)) next=tEOF; + ready=0; + sentback='\0'; + + switch (next) { + case tZERO: + if ((c==' ') || (c=='\r') || (c=='\t')){ + next=tZERO; + } else { + if (c=='#') { + next=tREM; + } else { + if ( ((c>=0x27) && (c<=0x2b)) || (c=='=') || (c==';') || (c=='\n') || (c=='!')){ + *t=c; t++; + next=tZERO; + ready=1; + } else { + if (c=='"') { + num=0; + next=tSTRING; + } else + { + num=0; + next=tLONG; + ready=0; + sentback=c; + } + } + } + } + break; + case tLONG: + if ((c==' ') || (c=='\r') || (c=='\t')){ + ready=1; + next=tZERO; + } else { + if ( ((c>=0x27) && (c<=0x2b)) || (c=='=') || (c==';') || (c=='\n') || (c=='!')){ + next=tZERO; + ready=1; + sentback=c; + } else { + if (c=='"') { + ready=1; + next=tSTRING; + } else { + if (c=='#') { + ready=1; + next=tREM; + } else { + *t=c; + t++; num++; + next=tLONG; + if ( (ready=(num>=MAXTOKENLEN-1)) ) + (void)fprintf(stderr,"Sorry, exeeded max name len of %u",num+1); + } + } + } + + } + break; + case tSTRING: + if (!str) { + *t='"'; t++; num++; + str=1; +#ifdef DEBUG + (void)fprintf(stderr,"<%c>\n",c); +#endif + } + *t=c; t++; num++; + if (c=='"') { /* last dblquote */ + ready=1; + next=tZERO; +#ifdef DEBUG + (void)fprintf(stderr,"STRING : %s\n",TOKEN); +#endif + break; + } + next=tSTRING; + if ( (ready=(num>=MAXTOKENLEN-1)) ) + (void)fprintf(stderr,"Sorry, exeeded max name len of %u",num+1); + break; + case tREM: + next=tREM; + if (c=='\n'){ + sentback=c; + next=tZERO; + } + break; + case tEOF: + next=tEOF; + ready=1; + sentback=c; + *t=c; +#ifdef DEBUG + (void)fprintf(stderr,"EOF\n"); +#endif + break; + default : + next=tZERO; + } + } while(!ready); + *t='\0'; + (void)strcpy(tok,&(TOKEN[0])); +} + +/* -=[ IsHere ]=- * + * Check is a name has been already used in the * + * expression. Here we look only at names, 'unused' * + * flag here is not useful. * + * * + * Input : * + * ptr = pointer to list of formals * + * name = name to check * + * Output : * + * pointer = if 'name' is used * + * NULL = if used */ +struct BITstruct *IsHere(name,ptr) +char *name; +struct BITstruct *ptr; +{ + struct BITstruct *BITptr; + + BITptr=ptr; + while(BITptr->next!=NULL){ + BITptr=BITptr->next; + if (KwrdCmp(name,BITptr->name)) return BITptr; + } + return (struct BITstruct *)NULL; +} + +struct LibCell *NewLibCell(name,ports,latch) +char *name; +struct BITstruct *ports; +int latch; +{ + struct LibCell *tmp; + struct BITstruct *bptr; + struct Ports *pptr; + int j; + int num; + + if ( (tmp=(struct LibCell *)calloc(1,sizeof(struct LibCell)))== NULL ) { + Error("Allocation Error or not enought memory !"); + } + + for(bptr=ports, num=1; bptr->next!=NULL; num++, bptr=bptr->next); + if (latch ) num--; + + if ( (tmp->formals=(struct Ports *)calloc(1,num*sizeof(struct Ports)))==NULL){ + Error("Allocation Error or not enought memory !"); + } + + (void)strcpy(tmp->name,name); + tmp->next=NULL; + tmp->npins=num; num--; + for(bptr=ports->next, pptr=tmp->formals, j=0; (j<num) && (bptr!=NULL) + ; pptr++, j++, bptr=bptr->next ){ + if (j>num) Error("(NewLibCell) error ..."); +#ifdef DEBUG + (void)fprintf(stderr,"(NewLibCell):adding %s\n",bptr->name); +#endif + (void)strcpy(pptr->name,bptr->name); + } + (void)strcpy(pptr->name,ports->name); /* output is the last one */ + if (latch) { + (void)strcpy(tmp->clk,bptr->name); +#ifdef DEBUG + (void)fprintf(stderr,"(NewLibCell):clock %s\n",bptr->name); +#endif + } else { + tmp->clk[0]='\0'; + } + ReleaseBit(ports); + return tmp; +} + + +/* -=[ ScanLibrary ]=- * + * Scans the library to get the namesof the cells * + * the output pins and the clock signals of latches * + * * + * Input : * + * LibName = the name of library file */ +struct LibCell *ScanLibrary(LibName) +char *LibName; +{ + enum states { sZERO, sPIN, sCLOCK, sADDCELL } next; + FILE *Lib; + struct LibCell *cell; + struct LibCell first; + struct BITstruct *tmpBIT; + struct BITstruct firstBIT; + char LocalToken[MAXTOKENLEN]; + char name[MAXNAMELEN]; + int latch; + char *s; + + + if ((Lib=fopen(LibName,"rt"))==NULL) + Error("Couldn't open library file"); + + +/* first.next=NewLibCell("_dummy_",(struct BITstruct *)NULL,LIBRARY); */ + firstBIT.name[0]='\0'; firstBIT.next=NULL; + cell=&first; + s=&(LocalToken[0]); + latch=0; next=sZERO; + (void)fseek(Lib,0L,SEEK_SET); + tmpBIT=&firstBIT; + do { + GetLibToken(Lib,s); + switch (next) { + case sZERO: + next=sZERO; + if (KwrdCmp(s,"GATE")) { + latch=0; + GetLibToken(Lib,s); + (void)strcpy(name,s); + GetLibToken(Lib,s); /* area */ + next=sPIN; +#ifdef DEBUG + (void)fprintf(stderr,"Gate name: %s\n",name); +#endif + } else { + if (KwrdCmp(s,"LATCH")) { + latch=1; + GetLibToken(Lib,s); + (void)strcpy(name,s); + GetLibToken(Lib,s); /* area */ + next=sPIN; +#ifdef DEBUG + (void)fprintf(stderr,"Latch name: %s\n",name); +#endif + } + } + break; + case sPIN: + if ( !( ((*s>=0x27) && (*s<=0x2b)) || (*s=='=') || (*s=='!')|| (*s==';')) ){ +/* + (void)strncpy(tmp,s,5); + if (KwrdCmp(tmp,"CONST") && !isalpha(*(s+6))) +*/ + /* if the expression has a constant value we must */ + /* skip it, because there are no inputs */ +/* + break; +*/ + /* it's an operand so get its name */ +#ifdef DEBUG + (void)fprintf(stderr,"\tpin read : %s\n",s); +#endif + if (IsHere(s,&firstBIT)==NULL) { +#ifdef DEBUG + (void)fprintf(stderr,"\tunknown pin : %s --> added!\n",s); +#endif + AddBIT(&tmpBIT,s); + } + } + if (*s==';') { + if (latch) { + next=sCLOCK; + } else { + next=sADDCELL; + } + } else { + next=sPIN; + } + break; + case sCLOCK: + if (KwrdCmp(s,"CONTROL")){ + GetLibToken(Lib,s); +#ifdef DEBUG + (void)fprintf(stderr,"\tcontrol pin : %s\n",s); +#endif + AddBIT(&tmpBIT,s); + next=sADDCELL; + } else { + next=sCLOCK; + } + break; + case sADDCELL: +#ifdef DEBUG + (void)fprintf(stderr,"\tadding cell to library\n"); +#endif + cell->next=NewLibCell(name,firstBIT.next,latch); + tmpBIT=&firstBIT; firstBIT.next=NULL; + cell=cell->next; + next=sZERO; + break; + } + } while (!feof(Lib)); + + if ((first.next)->next==NULL) { + (void)sprintf("Library file %s does *NOT* contains gates !",LibName); + Error("could not continue with an empy library"); + } +#ifdef DEBUG + (void)fprintf(stderr,"end of lib\n"); + PrintGates(first.next); +#endif + return (struct LibCell *)first.next; +} + + +/* -=[ WhatGate ]=- * + * Returns a pointer to an element of the list * + * of gates that matches up the name given, if * + * ther isn't a match a null pointer is returned * + * * + * Input : * + * name = name to match * + * LIBRARY = genlib data struct * + * Ouput : * + * (void *) a pointer */ +struct LibCell *WhatLibGate(name,LIBRARY) +char *name; +struct LibCell *LIBRARY; +{ + struct LibCell *ptr; + + for(ptr=LIBRARY; ptr!=NULL ; ptr=ptr->next) + if ( KwrdCmp(ptr->name,name) ) return ptr; + + return (struct LibCell *)NULL; +} + +/*=========================================================================* + + + + *=========================================================================*/ + +struct Cell *NewCell(name,Bports,Fports,Genlib) +char *name; +struct SIGstruct *Bports; +struct BITstruct *Fports; +struct LibCell *Genlib; +{ + struct Cell *tmp; + struct BITstruct *Fptr; + struct Ports *Pptr; + struct Ports *Lpptr; + struct LibCell *Lptr; + int j; + int num; + char t; + + if ( (tmp=(struct Cell *)calloc(1,sizeof(struct Cell)))== NULL ) { + Error("Allocation Error or not enought memory !"); + } + + if (Bports!=NULL){ + j=1; + Fptr=Fports; + while(Fptr->next!=NULL){ + j++; Fptr=Fptr->next; + } + num=j; + t=GetTypeOfCell(Genlib,name); + if (t=='L') j++; + + if ( (tmp->formals=(struct Ports *)calloc(1,j*sizeof(struct Ports)))==NULL){ + Error("Allocation Error or not enought memory !"); + } + (void)strcpy(tmp->name,name); + tmp->npins=j; + tmp->next=NULL; + tmp->type=t; + + if (t=='S') { + /* * + * Is a subcircuit, no ordering is necessary * + * */ + Fptr=Fports; + Pptr=tmp->formals; + j=0; + while(Fptr!=NULL){ + if (j>num) Error("(NewCell) error ..."); +#ifdef DEBUG + (void)fprintf(stderr,"(NewCell): adding %s\n",Fptr->name); +#endif + (void)strcpy(Pptr->name,Fptr->name); + Fptr=Fptr->next; + Pptr++; j++; + } + ReleaseBit(Fports->next); + tmp->io=Bports->next; + Bports->next=NULL; + } else { + /* * + * Is a library cell, let's order the signals * + * to simplify the final output * + * */ + Lptr=WhatLibGate(name,Genlib); + Pptr=tmp->formals; + if (t=='L') num--; + for(j=1, Lpptr=Lptr->formals; j<num; j++, Lpptr++, Pptr++) { + Fptr=Fports->next; +#ifdef DEBUG + (void)fprintf(stderr,"\npin %s \n",Lpptr->name); +#endif + while(Fptr!=NULL){ +#ifdef DEBUG + (void)fprintf(stderr,"is %s ?\n",Fptr->name); +#endif + if (KwrdCmp(Fptr->name,Lpptr->name)) { + (void)strcpy(Pptr->name,Fptr->name); + break; + } + Fptr=Fptr->next; + } + if (Fptr==NULL) (void) Error("Mismatch between COMPONENT declaration and library one"); + } + if (t=='L') { + Fptr=Fports->next; + while(Fptr!=NULL){ + if (KwrdCmp(Fptr->name,Lptr->clk)) { + (void)strcpy(Pptr->name,Fptr->name); + break; + } + Fptr=Fptr->next; + } + if (Fptr==NULL) (void) Error("Mismatch between COMPONENT declaration and libray one"); + } + ReleaseBit(Fports->next); + tmp->io=Bports->next; + Bports->next=NULL; + + } + + } else { + tmp->formals=NULL; + } + return tmp; +} + + +/* -=[ WhatGate ]=- * + * Returns a pointer to an element of the list * + * of gates that matches up the name given, if * + * ther isn't a match a null pointer is returned * + * * + * Input : * + * name = name to match * + * LIBRARY = components data struct * + * Ouput : * + * (void *) a pointer */ +struct Cell *WhatGate(name,LIBRARY) +char *name; +struct Cell *LIBRARY; +{ + struct Cell *ptr; + + for(ptr=LIBRARY; ptr!=NULL ; ptr=ptr->next) + if ( KwrdCmp(ptr->name,name) ) return ptr; + + return (struct Cell *)NULL; +} + + +/* -=[ GetPort ]=- * + * Gets the port definition of an ENTITY or of a * + * COMPONENT. * + * */ +struct Cell *GetPort(Cname) +char *Cname; +{ + enum states { sFORMAL, sCONN, sANOTHER, sDIR, sTYPE, sVECTOR, sWAIT } next; + struct SIGstruct BITstart; + struct BITstruct FORMstart; + struct SIGstruct *BITptr; + struct BITstruct *FORMptr; + struct BITstruct *TMPptr; + struct BITstruct TMPstart; + char *w; + char LocalToken[MAXTOKENLEN]; + char tmp[MAXNAMELEN]; + char dir; + int Cont; + int Token; + int start; + int end; + int j; + int num; + + + w=&(LocalToken[0]); + + GetNextToken(w); + if ( *w!='(' ) Warning("expected '('"); + + BITptr=&BITstart; + FORMptr=&FORMstart; + TMPstart.next=NULL; + + dir = '\0'; + Token=1; start=0; end=0; + next=sFORMAL; + Cont=1; num=0; + do{ + /* name of the port */ + if (Token) GetNextToken(w); + else Token=1; + switch (next) { + case sFORMAL: +#ifdef DEBUG + (void)fprintf(stderr,"\n\n** getting formal : %s",w); +#endif + (void)strcpy(TMPstart.name,w); + TMPptr=&TMPstart; + next=sCONN; + break; + case sCONN: + next=sDIR; + if (*w!=':') { + if (*w==',') { + next=sANOTHER; + } else { + Warning("Expected ':' or ',' ",line); + Token=0; + } + } + break; + case sANOTHER: +#ifdef DEBUG + (void)fprintf(stderr,"\n*** another input : %s",w); +#endif + if (TMPptr->next==NULL) { + AddBIT(&TMPptr,w,1); + } else { + TMPptr=TMPptr->next; + (void)strcpy(TMPptr->name,w); + } + num++; + next=sCONN; + break; + case sDIR: +#ifdef DEBUG + (void)fprintf(stderr,"\n\tdirection = %s",w); +#endif + if (KwrdCmp(w,"IN")){ + dir='i'; + } else { + if (KwrdCmp(w,"OUT")) { + dir='o'; + } else { + if (KwrdCmp(w,"INOUT")){ + dir='u'; + } else { + if (KwrdCmp(w,"LINKAGE")){ + dir=LINKAGE; + } else { + (void)fprintf(stderr,"* Error * Line %u : unknown direction of a port\n",line); + Error("Could not continue"); + } + } + } + } + next=sTYPE; + break; + case sTYPE: + if (KwrdCmp(w,"BIT")) { + next=sWAIT; + start=end; + } else { + if (KwrdCmp(w,"BIT_VECTOR")) { +#ifdef DEBUG + (void)fprintf(stderr,"\n\tvector, "); +#endif + next=sVECTOR; + } + } + break; + case sVECTOR: + if (*w!='(') { + Warning("Expected '('"); + } else { + GetNextToken(w); + } + start=DecNumber(w); + GetNextToken(w); + if (!KwrdCmp(w,"TO") && !KwrdCmp(w,"DOWNTO")){ + Warning("Expected keword TO or DOWNTO"); + } else { + GetNextToken(w); + } + end=DecNumber(w); + GetNextToken(w); + if (*w!=')') { + Warning("Expected ')'"); + Token=1; + } + next=sWAIT; +#ifdef DEBUG + (void)fprintf(stderr," from %d to %d",start,end); +#endif + break; + case sWAIT: + TMPptr=&TMPstart; + /* if (num>0) num--; */ +#ifdef DEBUG + (void)fprintf(stderr,"\nPower?"); +#endif + if (!(KwrdCmp(TMPptr->name,VDD) || KwrdCmp(TMPptr->name,VSS))){ +#ifdef DEBUG + (void)fprintf(stderr," no\n"); +#endif + + while(num>=0){ +#ifdef DEBUG + (void)fprintf(stderr,"\n\n%d)working on %s",num,TMPptr->name); +#endif + if (start==end) { +#ifdef DEBUG + (void)fprintf(stderr,"\nadded bit & formal of name : %s",TMPptr->name); +#endif + AddSIG(&BITptr,TMPptr->name,dir,0,0); + AddBIT(&FORMptr,TMPptr->name,dir); + } else { + if (start>end){ + for(j=start; j>=end; j--) { + (void)sprintf(tmp,"%s[%d]",TMPptr->name,j); +#ifdef DEBUG + (void)fprintf(stderr,"\nadded formal of name : %s",tmp); +#endif + AddBIT(&FORMptr,tmp,dir); + } +#ifdef DEBUG + (void)fprintf(stderr,"\nadded vector of name : %s[%d..%d]",TMPptr->name,start,end); +#endif + } else { + for(j=start; j<=end; j++) { + (void)sprintf(tmp,"%s[%d]",TMPptr->name,j); +#ifdef DEBUG + (void)fprintf(stderr,"\nadded formal of name : %s",tmp); +#endif + AddBIT(&FORMptr,tmp,dir); + } +#ifdef DEBUG + (void)fprintf(stderr,"\nadded vector of name : %s[%d..%d]",TMPptr->name,start,end); +#endif + } + AddSIG(&BITptr,TMPptr->name,dir,start,end); + } + TMPptr=TMPptr->next; + num--; + } + + } + num=0; + if (*w==';') { + next=sFORMAL; + } else { + if (*w!=')') { + VstError("Missing ')' or ';'","END"); + } else { + GetNextToken(w); /* ; */ + if (*w != ';') { + Warning("Missing ';'"); + } else { + GetNextToken(w); /* end */ + } + if (!KwrdCmp(w,"END")){ + VstError("Missing END keyword","END"); + } + } + Cont=0; + } + break; + } + + } while (Cont); + ReleaseBit(TMPstart.next); + return NewCell(Cname,&BITstart,&FORMstart,LIBRARY); +} + + +/* -=[ GetEntity ]=- * + * parses the entity statement */ +void GetEntity(Entity) +struct Cell **Entity; +{ + char *w; + char LocalToken[MAXTOKENLEN]; + char name[MAXTOKENLEN]; + int num; + + w=&(LocalToken[0]); + + /* name of the entity = name of the model */ + GetNextToken(w); + (void)strcpy(name,w); + GetNextToken(w); + if (!KwrdCmp(w,"IS")) Warning("expected syntax: ENTITY <name> IS"); + + /* GENERIC CLAUSE */ + GetNextToken(w); + if (KwrdCmp(w,"GENERIC")) { + GetNextToken(w); + if (*w!='(') Warning("expected '(' after GENERIC keyword"); + num=1; + do { + GetNextToken(w); + if (*w=='(') num++; + else { + if (*w==')') num--; + } + } while (num!=0); + GetNextToken(w); + if (*w!=';') Warning("expected ';'"); + GetNextToken(w); + } + + /* PORT CLAUSE */ + if (KwrdCmp(w,"PORT")) { + (*Entity)=GetPort(name); + } else { + Warning("no inputs or outputs in this entity ?!"); + } + + GetNextToken(w); + if (!KwrdCmp(w,name)) + Warning("<name> after END differs from <name> after ENTITY"); + + GetNextToken(w); + if (*w!=';') Warning("expected ';'"); +} + +/* -=[ GetComponent ]=- * + * Parses the component statement */ +void GetComponent(cell) +struct Cell **cell; +{ + char *w; + char LocalToken[MAXTOKENLEN]; + char name[MAXNAMELEN]; + + w=&(LocalToken[0]); + /* component name */ + GetNextToken(w); + (void)strcpy(name,w); +#ifdef DEBUG + (void)fprintf(stderr,"\nParsing component %s\n",name); +#endif + + /* A small checks may be done here ... next time */ + + /* PORT CLAUSE */ + GetNextToken(w); + if (KwrdCmp(w,"PORT")) { + (*cell)->next=GetPort(name); + (*cell)=(*cell)->next; + } else { + Warning("no inputs or outputs in this component ?!"); + } + + + /* END CLAUSE */ + GetNextToken(w); + if (!KwrdCmp(w,"COMPONENT")) { + Warning("COMPONENT keyword missing !"); + } + + GetNextToken(w); + if (*w!=';') Warning("expected ';'"); + +} + +/* -=[ GetSignal ]=- * + * Skips the signal definitions */ +void GetSignal(Internals) +struct SIGstruct **Internals; +{ + struct SIGstruct *SIGptr; + struct SIGstruct *SIGstart; + char *w; + char LocalToken[MAXTOKENLEN]; + char name[MAXNAMELEN]; + char dir; + int vect; + int start; + int end; + + + SIGstart=(struct SIGstruct *)calloc(1,sizeof(struct SIGstruct)); + if (SIGstart==NULL) { + Error("Allocation Error or not enought memory !"); + } + SIGptr=SIGstart; + + w=&(LocalToken[0]); + + dir = '\0'; + + do { + GetNextToken(w); +#ifdef DEBUG + (void)fprintf(stderr,"\n\n** getting signal %s",w); +#endif + AddSIG(&SIGptr,w,'*',999,999); + GetNextToken(w); + } while (*w==','); + + if (*w!=':') { + Warning("Expected ':'"); + } else { + GetNextToken(w); + } + + start=0; end=0; + vect=0; + if (*(w+3)=='_') { + *(w+3)='\0'; + vect=1; + } + if (KwrdCmp(w,"BIT")) { + dir='b'; + } else { + if (KwrdCmp(w,"MUX")) { + dir='m'; + } else { + if (KwrdCmp(w,"WOR")) { + dir='w'; + } + } + } + if (vect && !KwrdCmp(w+4,"VECTOR")) { + (void)fprintf(stderr," Unknown signal type : %s\n",w); + Error("could not continue."); + } + + if (vect) { + GetNextToken(w); + if (*w!='(') { + Warning("Expected '('"); + } else { + GetNextToken(w); + } + start=DecNumber(w); + GetNextToken(w); + if (!KwrdCmp(w,"TO") && !KwrdCmp(w,"DOWNTO")){ + Warning("Expected keword TO or DOWNTO"); + } else { + GetNextToken(w); + } + + end=DecNumber(w); + GetNextToken(w); + if (*w!=')') { + Warning("Expected ')'"); + } +#ifdef DEBUG + (void)fprintf(stderr," from %d to %d",start,end); +#endif + } + + GetNextToken(w); + if (dir!='b') { + if (!KwrdCmp(w,"BUS")) { + Warning(" Keyword 'BUS' expected"); + } else { + GetNextToken(w); + } + } + + SIGptr=SIGstart; + while (SIGptr->next!=NULL) { + SIGptr=SIGptr->next; + if (vect) { +#ifdef DEBUG + (void)fprintf(stderr,"\nadded vector of name : %s[%d..%d]",name,start,end); +#endif + AddSIG(Internals,SIGptr->name,dir,start,end); + } else { +#ifdef DEBUG + (void)fprintf(stderr,"\nadded bit of name : %s",name); +#endif + AddSIG(Internals,SIGptr->name,dir,0,0); + } + } + ReleaseSIG(SIGstart); + + if (*w!=';') { + Warning("expected ';'"); + } + +} + + +void FillTerm(TERM,Entity,which,WhatCell) +struct TERMstruct *TERM; +struct ENTITYstruct *Entity; +int which; +struct Cell *WhatCell; +{ + struct Cell *cell; + struct SIGstruct *Sptr; + +#ifdef DEBUG + (void)fprintf(stderr,"filling dimension of %s\n",TERM->name); +#endif + if (which) { +#ifdef DEBUG + (void)fprintf(stderr,"searchin into component %s\n",WhatCell->name); +#endif + cell=Entity->Components; + while(cell!=NULL){ + if (!strcmp(cell->name,WhatCell->name)) { + Sptr=cell->io; + while (Sptr!=NULL){ + if (KwrdCmp(TERM->name,Sptr->name)){ + TERM->start=Sptr->start; + TERM->end=Sptr->end; + return; + } + Sptr=Sptr->next; + } + } + cell=cell->next; + } + } else { + Sptr=(Entity->EntityPort)->io; + while (Sptr!=NULL){ +#ifdef DEBUG + (void)fprintf(stderr,"searchin into io\n"); +#endif + if (KwrdCmp(TERM->name,Sptr->name)){ + TERM->start=Sptr->start; + TERM->end=Sptr->end; + return; + } + Sptr=Sptr->next; + } + Sptr=Entity->Internals; + while (Sptr!=NULL){ +#ifdef DEBUG + (void)fprintf(stderr,"searchin into internals\n"); +#endif + if (KwrdCmp(TERM->name,Sptr->name)){ + TERM->start=Sptr->start; + TERM->end=Sptr->end; + return; + } + Sptr=Sptr->next; + } + if (KwrdCmp(TERM->name,VSS) || KwrdCmp(TERM->name,VDD)) { + TERM->start=0; TERM->end=0; + return; + } + (void)fprintf(stderr,"Signal name %s not declared",TERM->name); + Error("Could not continue"); + } +} + + +/* -=[ GetName ]=- * + * Gets a name of an actual terminal, that can be * + * a single token or 3 tokens long (if it is an * + * element of a vector ) * + * * + * Output : * + * name = the name read */ +void GetName(TERM,Entity,which,WhatCell) +struct TERMstruct *TERM; +struct ENTITYstruct *Entity; +int which; +struct Cell *WhatCell; +{ + char *w; + char LocalToken[MAXTOKENLEN]; + + TERM->start=-1; TERM->end=-1; + w=&(LocalToken[0]); + do { + GetNextToken(w); +#ifdef DEBUG + (void)fprintf(stderr,"Parsing %s\n",w); +#endif + } while ((*w==',') || (*w=='&')); + (void)strcpy(TERM->name,w); + GetNextToken(w); +#ifdef DEBUG + (void)fprintf(stderr,"then %s\n",w); +#endif + if (*w!='(') { + FillTerm(TERM,Entity,which,WhatCell); + if ((TERM->start==TERM->end) && (TERM->start==0)) { + TERM->start=-1; TERM->end=-1; + } + SendTokenBack=1; + /* Don't lose this token */ + return; + } else { +#ifdef DEBUG + (void)fprintf(stderr,"got (\n"); +#endif + } + GetNextToken(w); + TERM->start=DecNumber(w); + GetNextToken(w); + if (*w!=')') { + if (!KwrdCmp(w,"TO") && !KwrdCmp(w,"DOWNTO")){ + Error("expected ')' or 'TO' or 'DOWNTO', could not continue"); + } else { + GetNextToken(w); + TERM->end=DecNumber(w); + GetNextToken(w); + if (*w!=')') { + Warning("Expected ')'"); + SendTokenBack=1; + } + } + } else { +#ifdef DEBUG + (void)fprintf(stderr,"--> just an element of index %d\n",TERM->start); +#endif + TERM->end=TERM->start; + } +} + + +void ChangInternal(Intern,name) +struct SIGstruct *Intern; +char *name; +{ + struct SIGstruct *Sptr; + +#ifdef DEBUG + (void)fprintf(stderr,"\n ** scanning into internals --> Int=%p",Intern); +#endif + Sptr=Intern; + while(Sptr!=NULL){ +#ifdef DEBUG + (void)fprintf(stderr,"\t <%s>",Sptr->name); +#endif + if (!strcmp(Sptr->name,name)) { + char i; + i = *name; + i= ( (i<='z') && (i>='a') ? i+('A'-'a') : i); + *name=i; +#ifdef DEBUG + (void)fprintf(stderr,"\n *** %s : e' un segnale interno\n",name); +#endif + return; + } + Sptr=Sptr->next; + } +} +/* -=[ GetInstance ]=- * + * parses the netlist */ +struct Instance *GetInstance(name,Entity) +char *name; +struct ENTITYstruct *Entity; +{ + struct Cell *cell; + struct Instance *INST; + struct TERMstruct FORMterm; + struct TERMstruct ACTterm; + struct SIGstruct *ACTtrms; + struct SIGstruct *ACTptr; + struct Ports *Cptr; + struct Ports *Aptr; + char *w; + char LocalToken[MAXTOKENLEN]; + int j; + char Iname[MAXTOKENLEN+10]; + int incF,incA; + int iiF; + int iF,iA; + + w=&(LocalToken[0]); + GetNextToken(w); /* : */ + GetNextToken(w); + cell=WhatGate(w,Entity->Components); +#ifdef DEBUG + (void)fprintf(stderr,"\n=========================\nParsing instance %s of component %s\n==========================\n",name,cell->name); +#endif + + INST=(struct Instance *)calloc(1,sizeof(struct Instance)); + if (INST==NULL) { + Error("Allocation Error or not enought memory !"); + } + (void)strcpy(INST->name,name); + INST->what=WhatGate(w,Entity->Components); + INST->actuals= + (struct Ports *)calloc(1,((INST->what)->npins)*sizeof(struct Ports)); + if (INST->actuals==NULL){ + Error("Allocation Error or not enought memory !"); + } + + ACTtrms=(struct SIGstruct *)calloc(1,sizeof(struct SIGstruct)); + if (ACTtrms==NULL) { + Error("Allocation Error or not enought memory !"); + } + + + GetNextToken(w); + if (!KwrdCmp(w,"PORT")) { + Warning("PORT keyword missing","PORT"); + } + + GetNextToken(w); + if (!KwrdCmp(w,"MAP")) + Warning("MAP keyword missing"); + + GetNextToken(w); + if (*w!='(') + Warning("Expexcted '('"); + + do{ + GetName(&FORMterm,Entity,1,cell); +#ifdef DEBUG + (void)fprintf(stderr,"\t formal : %s\n",FORMterm.name); +#endif + + GetNextToken(w); + if (*w!='=') { + if (*w!='>') { + Warning("Expected '=>'"); + SendTokenBack=1; + } + } else { + GetNextToken(w); + if (*w!='>') { + Warning("Expected '=>'"); + SendTokenBack=1; + } + } + + ACTptr=ACTtrms; + do { + GetName(&ACTterm,Entity,0,cell); +#ifdef DEBUG + (void)fprintf(stderr,"\t actual : %s .. %s\n",ACTterm.name,w); +#endif + AddSIG(&ACTptr,ACTterm.name,'\0',ACTterm.start,ACTterm.end); + ChangInternal(Entity->Internals,ACTptr->name); +#ifdef DEBUG + (void)fprintf(stderr,"\nafter GetInstance: %s %s\n",ACTterm.name,ACTptr->name); +#endif + GetNextToken(w); + } while (*w=='&'); + + if ((*w!=',') && (*w!=')')) { + Error("Expected ')' or ','"); + } +#ifdef DEBUG + (void)fprintf(stderr,"----> %s\n",w); +#endif + if (FORMterm.start==FORMterm.end) { +#ifdef DEBUG + if (DEBUG) (void)fprintf(stderr,"after if (FORMterm.start==FORMterm.end) {: %s %s\n",ACTterm.name,ACTptr->name); +#endif + Cptr=(INST->what)->formals; + Aptr=INST->actuals; + for(j=0; j<(INST->what)->npins; j++, Cptr++, Aptr++){ + if (KwrdCmp(Cptr->name,FORMterm.name)) break; + } + if ((ACTterm.start!=ACTterm.end) || ((ACTtrms->next)->next!=NULL)) { + Warning("Actual vector's dimension differs to formal's one"); + } +#ifdef DEBUG + (void)fprintf(stderr,"value: %d %s\n",ACTptr->start,ACTptr->name); +#endif + if (ACTptr->start!=-1) { + if (isupper((ACTptr->name)[0])) { + (void)sprintf(Aptr->name,"%s_%d_",ACTptr->name,ACTterm.start); + } else { + (void)sprintf(Aptr->name,"%s[%d]",ACTptr->name,ACTterm.start); + } + } else { + (void)strcpy(Aptr->name,ACTterm.name); + } + } else { +#ifdef DEBUG + (void)fprintf(stderr,"\t\tthey are vectors --> formal from %d to %d\n",FORMterm.start,FORMterm.end); +#endif + incF = (FORMterm.start>FORMterm.end ? -1 : 1 ); + if (incF<0) { + /* + * Downto + */ + iiF=FORMterm.end; + } else { + /* + * To + */ + iiF=FORMterm.start; + } + ACTptr=ACTtrms; + incA=0; ACTptr->end=0; iA=0; + iF=FORMterm.start; + do { + /* + * Let's look if we need a new element... + */ + if (iA==(ACTptr->end+incA)) { + if (ACTptr->next==NULL) { + Error("Wrong vector size in assignement"); + } + ACTptr=ACTptr->next; + incA = (ACTptr->start > ACTptr->end ? -1 : 1); + iA=ACTptr->start; +#ifdef DEBUG + (void)fprintf(stderr,"ACTUAL changed!\ncurent : <%s> from %d to %d\n",ACTptr->name,ACTptr->start,ACTptr->end); +#endif + } + + /* + * let's make the connection + */ + (void)sprintf(Iname,"%s[%d]",FORMterm.name,iiF); + Cptr=(INST->what)->formals; + Aptr=INST->actuals; + for(j=0; j<(INST->what)->npins; j++, Cptr++, Aptr++){ +#ifdef DEBUG + (void)fprintf(stderr,"(%d)\tAptr->name=<%s>\tCptr->name=<%s>\tIname=<%s>\n",j,Aptr->name,Cptr->name,Iname); +#endif + if (KwrdCmp(Cptr->name,Iname)) break; + } + if (ACTptr->start<0) { + /* + * ACTual is a BIT + */ + if (isupper( (ACTptr->name)[0])) { + (void)sprintf(Aptr->name,"%s",ACTptr->name); + } else { + (void)sprintf(Aptr->name,"%s",ACTptr->name); + } + } else { + /* + * ACTual is a VECTOR + */ + if (isupper( (ACTptr->name)[0])) { + (void)sprintf(Aptr->name,"%s_%d_",ACTptr->name,iA); + } else { + (void)sprintf(Aptr->name,"%s[%d]",ACTptr->name,iA); + } + } +#ifdef DEBUG + (void)fprintf(stderr,"%d)--> added ACTconn : <%s>\n",iF,Aptr->name); +#endif + iF+=incF; iA+=incA; iiF++; + } while (iF!=(FORMterm.end+incF)); + ReleaseSIG(ACTtrms->next); +#ifdef DEBUG + (void)fprintf(stderr,"---->release done<----\n "); +#endif +/* + for(iF=FORMterm.start, iA=ACTterm.start; iF!=FORMterm.end+incF; iF+=incF, iA+=incA) { + sprintf(Iname,"%s[%d]",FORMterm.name,iF); + Cptr=(INST->what)->formals; + Aptr=INST->actuals; + for(j=0; j<(INST->what)->npins; j++, Cptr++, Aptr++){ + if (KwrdCmp(Cptr->name,Iname)) break; + } + if (isupper(ACTterm.name[0])) { + sprintf(Aptr->name,"%s_%d_",ACTterm.name,ACTterm.start); + } else { + sprintf(Aptr->name,"%s[%d]",ACTterm.name,iA); + } + } + if (iA!=ACTterm.end+incA) { + Warning("Actual vector's dimension differs to formal's one"); + } +*/ + } + } while (*w!=')'); + + free(ACTtrms); + GetNextToken(w); + if (*w!=';') { + Warning("expected ';'"); + } + return INST; +} + +/* -=[ GetArchitecture ]=- * + * parses the structure 'ARCHITECTURE' */ +void GetArchitecture(ENTITY) +struct ENTITYstruct *ENTITY; +{ + struct Cell *COMPOptr; + struct SIGstruct *SIGptr; + struct Instance *INSTptr; + struct Cell COMPOstart; + struct SIGstruct SIGstart; + struct Instance INSTstart; + char *w; + char LocalToken[MAXTOKENLEN]; + char name[MAXTOKENLEN]; + char msg[MAXTOKENLEN]; + + + SIGptr=&SIGstart; SIGstart.next=NULL; + COMPOptr=&COMPOstart; COMPOstart.next=NULL; + SIGptr=&SIGstart; + + w=&(LocalToken[0]); + /* type of architecture... */ + GetNextToken(w); + + GetNextToken(w); + if (!KwrdCmp(w,"OF")) + Warning("expected syntax: ARCHITECTURE <type> OF <name> IS"); + GetNextToken(w); + (void)strcpy(name,w); + GetNextToken(w); + if (!KwrdCmp(w,"IS")) + Warning("expected syntax: ENTITY <name> IS"); + + /* Components and signals: before a 'BEGIN' only sturcture * + * COMPONENT and SIGNAL are allowed */ + do{ + GetNextToken(w); + if (KwrdCmp(w,"COMPONENT")){ + GetComponent(&COMPOptr); + } else { + if (KwrdCmp(w,"SIGNAL")){ + GetSignal(&SIGptr); + } else { + if (KwrdCmp(w,"BEGIN")) break; + else { + (void)sprintf(msg,"%s unknown, skipped",w); + Warning(msg); + SendTokenBack=0; /* as we said we must skip it */ + } + } + } + if (feof(In)) Error("Unespected EoF"); + } while(1); + + ENTITY->Internals=SIGstart.next; + ENTITY->Components=COMPOstart.next; + /* NETLIST */ + INSTptr=&INSTstart; + do{ + GetNextToken(w); + if (KwrdCmp(w,"END")) { + break; + } else { + INSTptr->next=GetInstance(w,ENTITY); + INSTptr=INSTptr->next; + } + if (feof(In)) Error("Unespected EoF"); + } while(1); + + ENTITY->Net=INSTstart.next; + + /* name of kind of architecture */ + GetNextToken(w); + if (*w!=';') { + /* End of architecture last ';' */ + GetNextToken(w); + if (*w!=';') Warning("extected ';'"); + } +} + +void PrintSignals(msg,typ,Sptr) +char *msg; +char typ; +struct SIGstruct *Sptr; +{ + int i; + int incr; + + (void)fputs(msg,Out); + while(Sptr!=NULL){ + if ((Sptr->dir==typ) && (!KwrdCmp(Sptr->name,CLOCK))) { + if (Sptr->start==Sptr->end) { + (void)fprintf(Out,"%s ",Sptr->name); + } else { + incr=( Sptr->start<Sptr->end ? 1 : -1 ); + for(i=Sptr->start; i!=Sptr->end; i+=incr) { + (void)fprintf(Out,"%s[%d] ",Sptr->name, i); + } + } + } + Sptr=Sptr->next; + } + (void)fputs("\n",Out); +} + +void PrintOrderedSignals(Sptr,Lptr) +struct Ports *Sptr; +struct LibCell *Lptr; +{ + struct Ports *Lpptr; + int i; + + i=0; Lpptr=Lptr->formals; + while(i<Lptr->npins){ + (void)fprintf(Out,"%s=%s ",Lpptr->name,Sptr->name); + Sptr++; i++; Lpptr++; + } + if (Lptr->clk[0]) (void)fputs(Sptr->name,Out); +} + + +void PrintSls(Entity) +struct ENTITYstruct *Entity; +{ + struct Instance *Iptr; + struct Ports *Aptr; + struct Ports *Fptr; + int j; + + (void)fprintf(Out,"# *--------------------------------------*\n"); + (void)fprintf(Out,"# | File created by Vst2Blif v 1.1 |\n"); + (void)fprintf(Out,"# | |\n"); + (void)fprintf(Out,"# | by Roberto Rambaldi |\n"); + (void)fprintf(Out,"# | D.E.I.S. Universita' di Bologna |\n"); + (void)fprintf(Out,"# *--------------------------------------*/\n\n"); + + (void)fprintf(Out,"\n.model %s\n",(Entity->EntityPort)->name); + PrintSignals(".input ",'i',(Entity->EntityPort)->io); + PrintSignals(".output ",'o',(Entity->EntityPort)->io); + if (CLOCK[0]) { + (void)fprintf(Out,".clock %s",CLOCK); + } + (void)fputs("\n\n",Out); + + Iptr=Entity->Net; + while(Iptr!=NULL){ + switch ( (Iptr->what)->type ) { + case 'S' : + (void)fprintf(Out,".subckt %s ",(Iptr->what)->name); + Aptr=Iptr->actuals; Fptr=(Iptr->what)->formals; + for(j=0, Aptr++, Fptr++ ; j<(Iptr->what)->npins-1; j++, Aptr++,Fptr++){ + (void)fprintf(Out,"%s=%s ",Fptr->name,Aptr->name); + } + break; + case 'L': + (void)fprintf(Out,".latch %s ",(Iptr->what)->name); + PrintOrderedSignals(Iptr->actuals,WhatLibGate((Iptr->what)->name,LIBRARY)); + (void)fprintf(Out," %c",INIT); + break; + case 'G': + (void)fprintf(Out,".gate %s ",(Iptr->what)->name); + PrintOrderedSignals(Iptr->actuals,WhatLibGate((Iptr->what)->name,LIBRARY)); + break; + } + (void)fputs("\n",Out); + Iptr=Iptr->next; + } + (void)fputs("\n\n",Out); + + +} + + +/* -=[ PARSE FILE ]=- * + * switches between the two main states of * + * the program : the ENTITY prsing and the * + * ARCHITECTURE one. */ +void ParseFile() +{ + struct ENTITYstruct LocalENTITY; + char *w; + char LocalToken[MAXTOKENLEN]; + int flag; + + w=&(LocalToken[0]); + do { + + /* ENTITY CLAUSE */ + flag=0; + do { + GetNextToken(w); + if ((flag=KwrdCmp(w,"ENTITY"))) { + GetEntity(&(LocalENTITY.EntityPort)); + } else { + if (*w=='\0') break; + VstError("No Entity ???","ENTITY"); + /* After this call surely flag will be true * + * in any other cases the program will stop * + * so this point will be never reached ... */ + } + } while(!flag); + + /* ARCHITECTURE CLAUSE */ + flag=0; + do { + GetNextToken(w); + if ((flag=KwrdCmp(w,"ARCHITECTURE"))){ + GetArchitecture(&LocalENTITY); + } else { + if (*w=='\0') break; + VstError("No Architecture ???","ARCHITECTURE"); + /* it's the same as the previous one */ + } + } while (!flag); + /* end of the model */ + + } while (!feof(In)); + + PrintSls(&LocalENTITY); + +} + +/* -=[ main ]=- */ +int main(argc,argv) +int argc; +char **argv; +{ + + CheckArgs(argc,argv); + + ParseFile(); + + CloseAll(); + + exit(0); +} + diff --git a/xsis/Makefile.am b/xsis/Makefile.am new file mode 100644 index 0000000..196d98b --- /dev/null +++ b/xsis/Makefile.am @@ -0,0 +1,14 @@ +xsis_SOURCES_local = NetPlot.c NetPlot.h NetPlotP.h main.c xastg.c \ + xblif.c xcmd.c xhelp.c xsis.c xsis.h xutil.c \ + blif50.px ghost.px help50.px sis50.px +AM_CPPFLAGS = -I../sis/include -I@SIS_X_INCLUDES@ +AM_LDFLAGS = -L@SIS_X_LIBRARIES@ +LDADD = ../sis/libsis.a -lXaw -lXmu -lXt -lXext -lX11 -lm + +if SIS_COND_X + bin_PROGRAMS = xsis + xsis_SOURCES = $(xsis_SOURCES_local) + dist_man1_MANS = xsis.1 +endif + +EXTRA_DIST = $(xsis_SOURCES_local) xsis.1 fakesis.c diff --git a/xsis/Makefile.in b/xsis/Makefile.in new file mode 100644 index 0000000..a6499c9 --- /dev/null +++ b/xsis/Makefile.in @@ -0,0 +1,455 @@ +# Makefile.in generated by automake 1.8.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(xsis_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +@SIS_COND_X_TRUE@bin_PROGRAMS = xsis$(EXEEXT) +subdir = xsis +DIST_COMMON = $(dist_man1_MANS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(mkdir_p) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am__xsis_SOURCES_DIST = NetPlot.c NetPlot.h NetPlotP.h main.c xastg.c \ + xblif.c xcmd.c xhelp.c xsis.c xsis.h xutil.c blif50.px \ + ghost.px help50.px sis50.px +am__objects_1 = NetPlot.$(OBJEXT) main.$(OBJEXT) xastg.$(OBJEXT) \ + xblif.$(OBJEXT) xcmd.$(OBJEXT) xhelp.$(OBJEXT) xsis.$(OBJEXT) \ + xutil.$(OBJEXT) +@SIS_COND_X_TRUE@am_xsis_OBJECTS = $(am__objects_1) +xsis_OBJECTS = $(am_xsis_OBJECTS) +xsis_LDADD = $(LDADD) +xsis_DEPENDENCIES = ../sis/libsis.a +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(xsis_SOURCES) +DIST_SOURCES = $(am__xsis_SOURCES_DIST) +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(dist_man1_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIS_COND_CMUBDD_FALSE = @SIS_COND_CMUBDD_FALSE@ +SIS_COND_CMUBDD_TRUE = @SIS_COND_CMUBDD_TRUE@ +SIS_COND_CUDD_FALSE = @SIS_COND_CUDD_FALSE@ +SIS_COND_CUDD_TRUE = @SIS_COND_CUDD_TRUE@ +SIS_COND_UCBBDD_FALSE = @SIS_COND_UCBBDD_FALSE@ +SIS_COND_UCBBDD_TRUE = @SIS_COND_UCBBDD_TRUE@ +SIS_COND_X_FALSE = @SIS_COND_X_FALSE@ +SIS_COND_X_TRUE = @SIS_COND_X_TRUE@ +SIS_CUDDDIR = @SIS_CUDDDIR@ +SIS_DOCDIR = @SIS_DOCDIR@ +SIS_HISTDIR = @SIS_HISTDIR@ +SIS_SISLIBDIR = @SIS_SISLIBDIR@ +SIS_X_INCLUDES = @SIS_X_INCLUDES@ +SIS_X_LIBRARIES = @SIS_X_LIBRARIES@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__leading_dot = @am__leading_dot@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +xsis_SOURCES_local = NetPlot.c NetPlot.h NetPlotP.h main.c xastg.c \ + xblif.c xcmd.c xhelp.c xsis.c xsis.h xutil.c \ + blif50.px ghost.px help50.px sis50.px + +AM_CPPFLAGS = -I../sis/include -I@SIS_X_INCLUDES@ +AM_LDFLAGS = -L@SIS_X_LIBRARIES@ +LDADD = ../sis/libsis.a -lXaw -lXmu -lXt -lXext -lX11 -lm +@SIS_COND_X_TRUE@xsis_SOURCES = $(xsis_SOURCES_local) +@SIS_COND_X_TRUE@dist_man1_MANS = xsis.1 +EXTRA_DIST = $(xsis_SOURCES_local) xsis.1 fakesis.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps xsis/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps xsis/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +xsis$(EXEEXT): $(xsis_OBJECTS) $(xsis_DEPENDENCIES) + @rm -f xsis$(EXEEXT) + $(LINK) $(xsis_LDFLAGS) $(xsis_OBJECTS) $(xsis_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-man + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: install-man1 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am uninstall-man + +uninstall-man: uninstall-man1 + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-man1 \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-info-am uninstall-man uninstall-man1 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/xsis/NetPlot.c b/xsis/NetPlot.c new file mode 100644 index 0000000..fdac678 --- /dev/null +++ b/xsis/NetPlot.c @@ -0,0 +1,1844 @@ +/* -------------------------------------------------------------------------- *\ + NetPlot.c -- implementation of NetPlot Widget. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/NetPlot.c,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. + + Globals: netPlotWidgetClass + + Have to use XDrawString instead of XDrawImageString in order to get the + GC function to be recognized. + + Maybe change to allow NP_MAX_COLORS to be set as resource before the + widget is created? + + Scale factor from user to widget coordinates is defined by the widget font + size: font height = 1.0 user units. Thus nodes have a fixed height and + width regardless of widget size (immutable). Positioning depends on widget + size and scale factors. As the user space is "compressed" the objects get + closer together, but remain the same size. Thus the arcs between objects + change size/position (mutable). +\* -------------------------------------------------------------------------- */ + +#include "NetPlotP.h" + +#define xalloc(type,n) \ + (type*)XtMalloc((Cardinal)(sizeof(type)*(unsigned)(n))) +#define xrealloc(type,p,n) \ + (type*)XtRealloc((char*)(p),(Cardinal)sizeof(type)*(unsigned)(n)) +#define xfree(p) \ + XtFree((char*)p) + + +#define X_PAD 6 +#define Y_PAD 6 +#define ARROW_LENGTH 12 +#define ARROW_ANGLE (3.1415926 / 10) + +#define x_trans(xd,x) ceil(((x)-(xd)->xt_user)*(xd)->x_scale) +#define y_trans(xd,y) ceil(((y)-(xd)->yt_user)*(xd)->y_scale) + + +/* --------------------------- float Rectangles ----------------------------- */ + +static void np_clear_rect (r) +XRectangle* r; +{ + r->x = r->y = r->width = r->height = 0; +} + +static Boolean np_empty_rect (r) +XRectangle* r; +{ + return (r->width <= 0 || r->height <= 0); +} + +static void np_wrap_rect (dest,r1,r2) +XRectangle* dest; +XRectangle* r1; +XRectangle* r2; +{ + /* Note: includes r2 even if it has zero area. */ + float max_x, max_y; + + if (np_empty_rect (r1)) { + *dest = *r2; + } else { + max_x = MAX (r1->x+r1->width,r2->x+r2->width); + max_y = MAX (r1->y+r1->height,r2->y+r2->height); + dest->x = MIN (r1->x,r2->x); + dest->y = MIN (r1->y,r2->y); + dest->width = max_x - dest->x; + dest->height = max_y - dest->y; + } +} + +/* --------------------------- User Coordinates ----------------------------- */ + +static float winToUserX (view,win_x) +NetPlotPart* view; +int win_x; +{ + float x = win_x; + x = (x/view->x_scale) + view->xt_user; + return x; +} + +static float winToUserY (view,win_y) +NetPlotPart* view; +int win_y; +{ + float y = win_y; + y = (y/view->y_scale) + view->yt_user; + return y; +} + +/* ---------------------------- Implementation ------------------------------ */ + +static int np_numlines (label) +char *label; +{ + /* Eventually check for newline characters in label. */ + /* ARGSUSED */ + + return 1; +} + +int np_dummy (node,action) +np_node *node; +np_action action; +{ + /* For dummy internal nodes: do nothing at all. */ + + NetPlotPart *xd = &(node->widget->netPlot); + + if (action == NP_FRAME) { + XFillRectangle (xd->dpy,xd->win,xd->gc, + node->bounds.x-X_PAD/2, node->bounds.y-Y_PAD/2, + X_PAD, Y_PAD); + } + return 0; +} + +static String np_name (node) +np_node *node; +{ + String label = node->name; + if (label == NULL) label = "?"; + return label; +} + +static String np_label (node) +np_node *node; +{ + /* Return some non-NULL label string for this node. */ + + String label = node->label; + if (label == NULL) { + label = np_name(node); + if (label == NULL) label = " "; + } + return label; +} + +static void np_draw_label (node) +np_node* node; +{ + /* Draw standard label for a netPlot node. */ + + char *label = np_label(node); + NetPlotPart *xd = &(node->widget->netPlot); + + if (label != NULL) { + XDrawString (xd->dpy,xd->win,xd->gc, + node->bounds.x + X_PAD/2, + node->bounds.y + Y_PAD/2 + xd->font->max_bounds.ascent, + label, strlen(label)); + } +} + +int np_itrans (node,action) +np_node *node; +np_action action; +{ + int result = 0; + int y; + NetPlotPart *xd = &(node->widget->netPlot); + char *label = np_label(node); + + if (action == NP_ERASE) { + XFillRectangle (xd->dpy, xd->win, xd->gc, + node->bounds.x+X_PAD/2, node->bounds.y+Y_PAD/2, + node->bounds.width-X_PAD, node->bounds.height-X_PAD); + } + else if (action == NP_DRAW || action == NP_FRAME) { + np_draw_label (node); + y = node->bounds.y + node->bounds.height - Y_PAD/2 - + xd->font->max_bounds.descent/2; + XDrawLine (xd->dpy,xd->win,xd->gc, + node->bounds.x+X_PAD/2,y, + node->bounds.x+node->bounds.width-X_PAD/2,y); + } + else if (action == NP_CALC_WIDTH) { + result = X_PAD + XTextWidth (xd->font, label, strlen(label)); + } + else if (action == NP_CALC_HEIGHT) { + result = Y_PAD + xd->font_height * (np_numlines(label)); + } + return result; +} + +int np_otrans (node,action) +np_node *node; +np_action action; +{ + int result = 0; + NetPlotPart *xd = &(node->widget->netPlot); + char *label = np_label(node); + + if (action == NP_ERASE) { + XFillRectangle (xd->dpy, xd->win, xd->gc, + node->bounds.x+X_PAD/2, node->bounds.y+Y_PAD/2, + node->bounds.width-X_PAD, node->bounds.height-Y_PAD); + } + else if (action == NP_DRAW || action == NP_FRAME) { + np_draw_label (node); + } + else if (action == NP_CALC_WIDTH) { + result = X_PAD + XTextWidth (xd->font, label, strlen(label)); + } + else if (action == NP_CALC_HEIGHT) { + result = Y_PAD + xd->font_height * (np_numlines(label)); + } + return result; +} + +int np_textblock (node,action) +np_node *node; +np_action action; +{ + int result = 0; + NetPlotPart *xd = &(node->widget->netPlot); + char *label = np_label(node); + + if (action == NP_ERASE) { + XFillRectangle (xd->dpy, xd->win, xd->gc, + node->bounds.x, node->bounds.y, + node->bounds.width, node->bounds.height); + } + else if (action == NP_DRAW || action == NP_FRAME) { + np_draw_label (node); + } + else if (action == NP_CALC_WIDTH) { + result = XTextWidth (xd->font, label, strlen(label)); + } + else if (action == NP_CALC_HEIGHT) { + result = xd->font_height * (np_numlines(label)); + } + return result; +} + +int np_rectangle (node,action) +np_node *node; +np_action action; +{ + int result = 0; + NetPlotPart *xd = &(node->widget->netPlot); + char *label = np_label(node); + + if (action == NP_ERASE) { + XFillRectangle (xd->dpy, xd->win, xd->gc, + node->bounds.x, node->bounds.y, + node->bounds.width, node->bounds.height); + } + else if (action == NP_DRAW || action == NP_FRAME) { + XDrawRectangle (xd->dpy, xd->win, xd->gc, + node->bounds.x, node->bounds.y, + node->bounds.width-1, node->bounds.height-1); + if (action == NP_DRAW) np_draw_label (node); + } + else if (action == NP_CALC_WIDTH) { + result = XTextWidth (xd->font, label, strlen(label)); + } + else if (action == NP_CALC_HEIGHT) { + result = xd->font_height * (np_numlines(label)); + } + return result; +} + +int np_ellipse (node,action) +np_node *node; +np_action action; +{ + int result = 0; + NetPlotPart *xd = &(node->widget->netPlot); + String label = np_label(node); + + if (action == NP_ERASE) { + XFillArc (xd->dpy, xd->win, xd->gc, + node->bounds.x, node->bounds.y, + node->bounds.width, node->bounds.height, + 0, 360 * 64); + } + else if (action == NP_DRAW || action == NP_FRAME) { + XDrawArc (xd->dpy, xd->win, xd->gc, + node->bounds.x, node->bounds.y, + node->bounds.width-1, node->bounds.height-1, + 0, 360 * 64); + if (action == NP_DRAW) np_draw_label (node); + } + else if (action == NP_CALC_WIDTH) { + if (!strcmp(label," ")) { + result = xd->font_height; + } else { + result = XTextWidth (xd->font, label, strlen(label)); + } + } + else if (action == NP_CALC_HEIGHT) { + result = xd->font_height * (np_numlines(label)); + } + + return result; +} + +static Boolean np_sect_rect (r1,r2) +XRectangle* r1; +XRectangle* r2; +{ + /* Return False if two rectangles do not intersect, True otherwise. */ + + int r1r = r1->x + r1->width, r1b = r1->y + r1->height; + int r2r = r2->x + r2->width, r2b = r2->y + r2->height; + Boolean disjoint = + (r1->x >= r2r) || (r1->y >= r2b) || (r2->x >= r1r) || (r2->y >= r1b); + return !disjoint; +} + +np_arc* np_create_arc (from,to,label) +np_node* from; +np_node* to; +char *label; +{ + np_arc *arc = xalloc(np_arc, 1); + + assert(from->widget == to->widget); + arc->label = (label) ? XtNewString(label) : NULL; + arc->widget = from->widget; + arc->from = from; + arc->to = to; + arc->style = LineSolid; + arc->highlighted = False; + + lsNewEnd (arc->widget->netPlot.arcs, (lsGeneric) arc, (lsHandle *) NULL); + lsNewEnd (from->fanouts, (lsGeneric) arc, (lsHandle *) NULL); + lsNewEnd (to->fanins, (lsGeneric) arc, (lsHandle *) NULL); + + return arc; +} + +np_arc* np_find_arc (from,to) +np_node* from; +np_node* to; +{ + lsGen gen; + np_arc *arc, *found = NULL; + + np_foreach_fanout (from,gen,arc) { + if (arc->to == to) { + found = arc; + } + } + + return found; +} + +void np_set_arc_props (arc,linestyle,label) +np_arc* arc; +int linestyle; +char* label; +{ + arc->style = linestyle; + if (arc->label) xfree(arc->label); + arc->label = (label) ? XtNewString(label) : NULL; +} + +static void np_get_arc_props (arc,linestyle,label) +np_arc* arc; +int* linestyle; +char** label; +{ + *linestyle = arc->style; + *label = arc->label; +} + +static lsStatus lsDelValue (list,userdata) +lsList list; +lsGeneric userdata; +{ + lsGeneric curr_item; + lsGen gen = lsStart (list); + + while (lsNext(gen, &curr_item, (lsHandle *) NULL) == LS_OK) { + if (curr_item == userdata) lsDelBefore(gen, &curr_item); + } + + lsFinish (gen); + return (LS_OK); +} + +static void np_delete_arc (arc) +np_arc* arc; +{ + lsDelValue (arc->from->fanouts, (lsGeneric) arc); + lsDelValue (arc->to->fanins, (lsGeneric) arc); + lsDelValue (arc->widget->netPlot.arcs, (lsGeneric) arc); + xfree (arc); +} + +/* ----------------------- netplot node stuff ------------------------------- */ + +np_node* np_create_node2 (widget,name) +NetPlotWidget widget; +char *name; +{ + NetPlotPart *graph = &(widget->netPlot); + np_node*node = xalloc(np_node, 1); + + lsNewEnd(graph->nodes, (lsGeneric) node, (lsHandle *) NULL); + node->widget = widget; + + node->dummy = False; + node->shape = np_rectangle; + node->fanins = lsCreate(); + node->fanouts = lsCreate(); + node->highlighted = 0; + node->label = NULL; + node->color = 1; + node->bounds.height = node->bounds.width = 0; + + if (name != NULL) { + node->name = XtNewString(name); + st_insert (graph->node_table,node->name,(char*)node); + } else { + node->name = NULL; + } + + return node; +} + +np_node* np_create_node (w,name) +Widget w; +char *name; +{ + return np_create_node2 ((NetPlotWidget)w, name); +} + +np_node *np_find_node (w,name,create) +Widget w; +char *name; +Bool create; +{ + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + np_node *node = NULL; + + if (!st_lookup(graph->node_table,name,(char**)&node) && create) { + node = np_create_node2 (widget,name); + } + return node; +} + +static void np_free_node (data) +lsGeneric data; +{ + /* Callback for lsDestroy. */ + + np_node *node = (np_node*) data; + char *name = node->name; + lsGen gen; + np_arc *arc; + + np_foreach_fanout (node, gen, arc) np_delete_arc (arc); + np_foreach_fanin (node, gen, arc) np_delete_arc (arc); + + lsDestroy (node->fanins, NULL); + lsDestroy (node->fanouts, NULL); + if (node->label != NULL && node->label != name) { + xfree(node->label); + } + if (name != NULL) { + st_delete (node->widget->netPlot.node_table, &name, NULL); + xfree(node->name); + } + xfree(node); +} + +void np_set_node_color (node,color) +np_node *node; +unsigned color; +{ + if (color >= NP_MAX_COLORS) { + node->color = NP_MAX_COLORS - 1; + } else { + node->color = color; + } +} + +void np_set_label (node,label) +np_node *node; +String label; +{ + /* Change the node label. */ + xfree (node->label); + node->label = (label) ? XtNewString(label) : NULL; +} + +void np_set_shape (node,shape) +np_node *node; +np_shape shape; +{ + /* Change the node shape. */ + node->shape = shape; +} + +/* ----------------------- Generic Node Placement --------------------------- *\ + + Assign values to (node->x,node->y) for each node to place it on an + arbitrary grid. Node fields level, vertpos, and grids_high are used as + work field. Dummy nodes are added to long edges to allow them to be + positioned more precisely. We could use splines or some other curve + fitting for these, but it is not currently supported. + + The original version of the placement code was written by Wayne A. + Christopher, CAD group 1988. +\* -------------------------------------------------------------------------- */ + +np_node* np_insert_bend (arc) +np_arc* arc; +{ + np_node *newnode; + int linestyle; + char *label; + + newnode = np_create_node2 (arc->widget,NULL); + newnode->dummy = True; + newnode->level = 0; + newnode->shape = np_dummy; + + np_get_arc_props (arc, &linestyle, &label); + np_create_arc (arc->from, newnode, label); + np_create_arc (newnode, arc->to, NULL); + np_delete_arc (arc); + return newnode; +} + +static void np_check_uniform (node) +np_node* node; +{ + /* Make sure that every path from the inputs to the outputs of a + graph has a node at every level. */ + + lsGen gen; + np_arc *arc; + np_node *fanout, *bend; + + np_foreach_fanout (node, gen, arc) { + fanout = arc->to; + if (fanout->level < node->level - 1) { + bend = np_insert_bend (arc); + bend->level = node->level - 1; + } + } + + np_foreach_fanout (node, gen, arc) { + fanout = arc->to; + np_check_uniform (fanout); + } +} + +static void np_assign_levels (node) +np_node* node; +{ + lsGen gen; + np_arc *arc; + np_node *fanout; + + if (node->level < 0) { + node->level = 0; + np_foreach_fanout (node, gen, arc) { + fanout = arc->to; + np_assign_levels (fanout); + if (fanout->level >= node->level) node->level = fanout->level + 1; + } + } +} + +static void np_make_uniform (graph) +NetPlotPart *graph; +{ + np_node *node; + lsGen gen; + + np_foreach_node (graph, gen, node) { + node->level = -1; + } + + np_foreach_node (graph, gen, node) { + np_assign_levels (node); + } + + np_foreach_node (graph, gen, node) { + if (num_fanins(node) == 0) np_check_uniform (node); + } +} + +/* -------------------------------------------------------------------------- *\ + Here's the real stuff. Assign relative positions of the nodes in all + the levels in the graph. Assume the order of column 0 is + fixed. Then determine the best posttions for column 1 based on this, + then column 2, etc. The primary inputs are fixed also. The go back + towards the primary outputs, using the orders of both the previous and + next columns. +\* -------------------------------------------------------------------------- */ + +#define dw(n) ((((np_node*)n2)->dummy) ? 0 : 0) + +static int fits (map,size,place,maxverts) +int* map; +int size; +int place; +int maxverts; +{ + int i; + + if (size == 0) return (1); + + if (place + size / 2 >= maxverts) return(0); + if (place - size / 2 < 0) return(0); + + for (i = 0; i < size; i++) + if (map[place - size / 2 + i]) + return (0); + + return (1); +} + +static int findPlace (fixed,size,avg,maxverts) +int* fixed; +int size; +int avg; +int maxverts; +{ + int i; + + if (fits(fixed, size, avg, maxverts)) + return (avg); + else { + for (i = 1; i < maxverts; i++) { + if ((avg + i < maxverts) && + fits(fixed, size, avg + i, maxverts)) + return (avg + i); + if ((avg - i >= 0) && + fits(fixed, size, avg - i, maxverts)) + return (avg - i); + } + } + return (-1); +} + +static int nodeCompareFanouts (item1,item2) +lsGeneric item1; +lsGeneric item2; +{ + np_node *n1 = (np_node*) item1; + np_node *n2 = (np_node*) item2; + + return ((num_fanouts(n2) + n2->grids_high + dw(n2)) - + (num_fanouts(n1) + n1->grids_high + dw(n1))); +} + +static int nodeCompareBoth (item1,item2) +lsGeneric item1; +lsGeneric item2; +{ + np_node *n1 = (np_node*) item1; + np_node *n2 = (np_node*) item2; + + return ((num_fanouts(n2) + num_fanins(n2) + + n2->grids_high + dw(n2)) - + (num_fanouts(n1) + num_fanins(n1) + + n1->grids_high + dw(n1))); +} + +static int +np_place_nodes (graph,level,maxverts,prevonly) +NetPlotPart* graph; +int level; +int maxverts; +Bool prevonly; +{ + lsList lev; + lsGen gen, gen2; + np_node *node, *fanin, *fanout, *node2; + np_arc *arc; + int *fixed; + int i, j, num, avg, try, size; + + /* Fixed is 0 if there is nothing here, 1 if there are only + dummy nodes here, and 2 if there is a real node here. */ + fixed = xalloc(int,maxverts); + for (i=0; i < maxverts; i++) fixed[i] = 0; + + lev = lsCreate(); + + np_foreach_node(graph, gen, node) { + if (node->level == level) { + lsNewEnd(lev, (lsGeneric) node, (lsHandle *) NULL); + } + } + + if (prevonly) { + lsSort(lev, nodeCompareFanouts); + } else { + lsSort(lev, nodeCompareBoth); + } + + np_lsForeachItem (lev, gen, node) { + avg = 0; + num = 0; + np_foreach_fanout(node, gen2, arc) { + fanout = arc->to; + if (node->level > fanout->level) { + avg += fanout->vertpos; + num++; + } + } + if (!prevonly) { + np_foreach_fanin(node, gen2, arc) { + fanin = arc->from; + if (fanin->level > node->level) { + avg += fanin->vertpos * 2; + num += 2; + } + } + } + if (!num) + avg = 0; + else + avg /= num; + + if (node->dummy) { + size = node->grids_high; + if (!fits(fixed, size, avg, maxverts)) size = 0; + try = avg; + } else { + for (size=node->grids_high; size >= 0; size-=(size>1)?2:1) { + try = findPlace (fixed, size, avg, maxverts); + if (try >= 0) break; + } + assert(try >= 0); + if ((try == 0) && (node->grids_high > 1)) { + try += node->grids_high / 2; + } + } + + if (size < node->grids_high) { + /* Make room... */ + i = node->grids_high - size; + maxverts += i; + fixed = xrealloc(int, fixed, maxverts); + for (j=maxverts-i; j < maxverts; j++) + fixed[j] = 0; + for (j=maxverts-1; j > try + i; j--) + fixed[j] = fixed[j - i]; + np_lsForeachItem (lev, gen2, node2) { + if (node2 == node) { + lsFinish(gen2); + break; + } + if (node2->vertpos > try) { + node2->vertpos += i; + } + } + } + + for (i=0; i < node->grids_high; i++) { + assert(try - node->grids_high / 2 + i >= 0); + assert(try - node->grids_high / 2 + i < maxverts); + fixed[try - node->grids_high / 2 + i] = 2; + } + + node->vertpos = try + node->grids_high / 2; + } + + lsDestroy(lev, (void (*)()) NULL); + xfree(fixed); + + return maxverts; +} + +static void np_generic_place (graph) +NetPlotPart* graph; +{ + /* Run a node placement algorithm based on levelizing the graph and + assigning nodes to a grid position. Output is x,y set for every + node in the graph. */ + + int level, i; + lsGen gen; + np_node *node; + int maxverts = 0; + int maxlevel = 0; + + np_make_uniform (graph); + + np_foreach_node(graph, gen, node) { + if (node->level > maxlevel) maxlevel = node->level; + /* These are "magic" numbers from the old plot code. */ + node->grids_high = (node->shape == np_ellipse) ? 3 : 2; + if (node->dummy) node->grids_high = 0; + } + + for (level=maxlevel; level >= 0; level--) { + i = 0; + np_foreach_node (graph,gen,node) { + if (node->level == level) i += node->grids_high; + } + if (i > maxverts) maxverts = i; + } + + /* Go from the outputs to the inputs. */ + maxverts = np_place_nodes(graph, 0, maxverts, True); + for (i=1; i < maxlevel; i++) { + maxverts = np_place_nodes (graph, i, maxverts, True); + } + maxverts = np_place_nodes (graph, maxlevel, maxverts, True); + + /* Go from the inputs to the outputs. */ + for (i=maxlevel-1; i > 0; i--) { + maxverts = np_place_nodes (graph, i, maxverts, False); + } + maxverts = np_place_nodes (graph, 0, maxverts, False); + + np_foreach_node (graph,gen,node) { + node->x = (float) -node->level; + node->y = (float) node->vertpos; + /* On even levels, shift real nodes, odd levels shift dummy nodes. */ +/* + if ((node->level%2 == 0) ^ (node->dummy == False)) { + node->y += 0.5; + } + */ + } +} + +/* ------------------------ Map Grid to User -------------------------------- *\ + + After a generic placement algorithm on an arbitrary grid, convert the + grid into user coordinates, and set the bounds rect for each node. +\* -------------------------------------------------------------------------- */ + +void np_set_position (node,x,y) +np_node* node; +double x; +double y; +{ + /* Set the position of one node. If one node is placed, then no + automatic placement is done for any nodes. */ + + node->widget->netPlot.unplaced = False; + node->x = x; node->y = y; +} + +void np_autoplace (w) +Widget w; +{ + /* Set up transformation between user and window coordinates, and init. + the bounding box for all nodes. If the graph is unplaced, a generic + placement algorithm is run first. */ + + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *xd = &widget->netPlot; + lsGen gen; + np_node *node; + float xmin,xmax, ymin,ymax; + XRectangle r, user_frame; + Boolean first; + +#ifdef WIDGET_DEBUG + printf("autoplace size %d,%d\n",widget->core.width,widget->core.height); +#endif + + np_foreach_node (xd, gen, node) { + node->bounds.width = (*node->shape) (node,NP_CALC_WIDTH); + node->bounds.height = (*node->shape) (node,NP_CALC_HEIGHT); + if (!node->dummy) { + node->bounds.width += X_PAD; + node->bounds.height += Y_PAD; + } + } + + if (xd->unplaced) { /* Assign some x,y coordinates. */ + np_generic_place (xd); + xd->unplaced = False; + } + + /* Find min/max of user coordinate centers, and of widget window. */ + + first = True; + xmin = ymin = 0.0; + xmax = ymax = 1.0; + np_foreach_node (xd,gen,node) { + if (first) { + xmax = xmin = node->x; + ymax = ymin = node->y; + first = False; + } else { + if (node->x > xmax) xmax = node->x; + if (node->x < xmin) xmin = node->x; + if (node->y > ymax) ymax = node->y; + if (node->y < ymin) ymin = node->y; + } + } + + xd->xt_user = xmin; + xd->yt_user = ymin; + xd->x_scale = (float) widget->core.width / (xmax-xmin); + xd->y_scale = (float) widget->core.height / (ymax-ymin); + + /* Use this temp. scale factor to calculate the amount not visible. */ + + np_clear_rect (&user_frame); + np_foreach_node (xd,gen,node) { + r.width = node->bounds.width; + r.height = node->bounds.height; + r.x = ceil((node->x - xmin) * xd->x_scale) - r.width/2; + r.y = ceil((node->y - ymin) * xd->y_scale) - r.height/2; + np_wrap_rect (&user_frame, &user_frame,&r); + } + + /* Allow a border around the plot. */ +#define BMM 10 + + user_frame.x -= ceil(BMM * xd->x_pix_per_mm); + user_frame.y -= ceil(BMM * xd->y_pix_per_mm); + user_frame.width += ceil(2*BMM * xd->x_pix_per_mm); + user_frame.height += ceil(2*BMM * xd->y_pix_per_mm); + + /* Adjust the origin and scale factor approximately. */ + + xd->x_scale -= (user_frame.width - widget->core.width ) / (xmax - xmin); + xd->y_scale -= (user_frame.height - widget->core.height) / (ymax - ymin); + xd->xt_user += user_frame.x / xd->x_scale; + xd->yt_user += user_frame.y / xd->y_scale; + + /* Calculate final bounding box location for every node. */ + + np_foreach_node (xd, gen, node) { + node->bounds.x = x_trans(xd,node->x) - node->bounds.width/2; + node->bounds.y = y_trans(xd,node->y) - node->bounds.height/2; + } +} + +/* --------------------------- Low level X Stuff ---------------------------- */ + +static void np_top_center (node,tc) +np_node* node; +XPoint* tc; +{ + tc->x = node->bounds.x + node->bounds.width/2; + tc->y = node->bounds.y; +} + +static void np_bottom_center (node,tc) +np_node* node; +XPoint* tc; +{ + tc->x = node->bounds.x + node->bounds.width/2; + tc->y = node->bounds.y + node->bounds.height; +} + +static void np_left_center (node,tc) +np_node* node; +XPoint* tc; +{ + tc->x = node->bounds.x; + tc->y = node->bounds.y + node->bounds.height/2; +} + +static void np_right_center (node,tc) +np_node* node; +XPoint* tc; +{ + tc->x = node->bounds.x + node->bounds.width; + tc->y = node->bounds.y + node->bounds.height/2; +} + +static void +np_arrow_comp (xd,ends,arrangle,arrlength) +NetPlotPart* xd; +XPoint* ends; +double arrangle; +int arrlength; +{ + /* Draw arrowhead on line from ends[0] to ends[1]. Changes of sign on + some y calculations because X11 positive y values go down, but trig. + functions expect positive y values mean up. */ + + XPoint verts[3]; + double angle; + int dx, dy, iangle; + + dy = ends[0].y - ends[1].y; + dx = ends[0].x - ends[1].x; + if (ABS(dx) < arrlength && ABS(dy) < arrlength) return; + angle = (dx == 0 && dy == 0) ? 0.0 : atan2((double)-dy,(double)dx); + + if (xd->vertical) { + /* Convert to degrees and draw arc. */ + iangle = ceil(angle * 180. * 64. / 3.1415926); + XFillArc (xd->dpy,xd->win,xd->gc, + ends[1].x-arrlength,ends[1].y-arrlength, + 2*arrlength,2*arrlength, + iangle-18*64,(18+18)*64); + } else { + verts[0].x = ends[1].x + ceil(arrlength * cos(angle - arrangle)); + verts[0].y = ends[1].y - ceil(arrlength * sin(angle - arrangle)); + verts[1] = ends[1]; + verts[2].x = ends[1].x + ceil(arrlength * cos(angle + arrangle)); + verts[2].y = ends[1].y - ceil(arrlength * sin(angle + arrangle)); + XDrawLines (xd->dpy,xd->win,xd->gc, verts,3, CoordModeOrigin); + } +} + +static void np_calc_arc (arc,verts,covers) +np_arc* arc; +XPoint* verts; +XRectangle* covers; +{ + /* Compute the endpoints and covering rectangle for the arc. */ + + np_node *from = arc->from; + np_node *to = arc->to; + + if (arc->widget->netPlot.vertical) { + if (from->bounds.y + from->bounds.height < to->bounds.y) { + np_bottom_center (from,&verts[0]); + np_top_center (to,&verts[1]); + } else if (from->bounds.y > to->bounds.y + to->bounds.height) { + np_top_center (from,&verts[0]); + np_bottom_center (to,&verts[1]); + } else if (from->bounds.x > to->bounds.x + to->bounds.width) { + np_left_center (from,&verts[0]); + np_right_center (to,&verts[1]); + } else { + np_right_center (from,&verts[0]); + np_left_center (to,&verts[1]); + } + } else { + if (from->bounds.x > to->bounds.x + to->bounds.width) { + np_left_center (from,&verts[0]); + np_right_center (to,&verts[1]); + } else if (from->bounds.x + from->bounds.width < to->bounds.x) { + np_right_center (from,&verts[0]); + np_left_center (to,&verts[1]); + } else if (from->bounds.y + from->bounds.height < to->bounds.y) { + np_bottom_center (from,&verts[0]); + np_top_center (to,&verts[1]); + } else { + np_top_center (from,&verts[0]); + np_bottom_center (to,&verts[1]); + } + } + + covers->x = MIN(verts[0].x,verts[1].x); + covers->y = MIN(verts[0].y,verts[1].y); + covers->width = ABS(verts[1].x-verts[0].x); + covers->height = ABS(verts[1].y-verts[0].y); +} + +static void np_sect_arc (r,arc) +XRectangle* r; +np_arc* arc; +{ + /* Add the arc's rectangle to the bounding box. */ + + XPoint verts[2]; + XRectangle covers; + np_calc_arc (arc,verts,&covers); + np_wrap_rect (r, r,&covers); +} + +static void np_draw_an_arc (xd,area,arc) +NetPlotPart* xd; +XRectangle* area; +np_arc* arc; +{ + /* Draw one segment of an arc, including its label. We need to do + bounds checking on the area for the label yet. Arc is drawn based + on the bounds for the from/to nodes. */ + + XPoint verts[2]; + XRectangle covers; + int len; + + np_calc_arc (arc,verts,&covers); + + if (area == NULL || np_sect_rect(area,&covers)) { + XDrawLines (xd->dpy,xd->win,xd->gc, verts,2, CoordModeOrigin); + if (!arc->to->dummy) { + np_arrow_comp (xd, verts, ARROW_ANGLE, ARROW_LENGTH); + } + } + + if (arc->label != NULL) { + /* Find center of arc. */ + int cx = (verts[0].x + verts[1].x) / 2; + int cy = (verts[0].y + verts[1].y) / 2; + /* Center the label on the arc. */ + len = strlen(arc->label); + cx -= XTextWidth(xd->font,arc->label,len) / 2; + cy += xd->font_height/2 - 6; + XDrawImageString (xd->dpy,xd->win,xd->gc, cx,cy, arc->label,len); + } +} + +static void np_draw_arc (win,area,arc) +NetPlotPart* win; +XRectangle* area; +np_arc* arc; +{ + if (arc->from->dummy) return; + + np_draw_an_arc (win,area, arc); + + while (arc->to->dummy) { + assert(num_fanouts(arc->to) == 1); + lsFirstItem (arc->to->fanouts, (lsGeneric *) &arc, LS_NH); + np_draw_an_arc (win,area, arc); + } +} + +static np_node *np_real_fanout (arc) +np_arc *arc; +{ + while (arc->to->dummy) { + assert(num_fanouts(arc->to) == 1); + lsFirstItem (arc->to->fanouts, (lsGeneric *) &arc, LS_NH); + } + return arc->to; +} + +static np_node *np_real_fanin (arc) +np_arc *arc; +{ + while (arc->from->dummy) { + assert(num_fanins(arc->from) == 1); + lsFirstItem (arc->from->fanins, (lsGeneric *) &arc, LS_NH); + } + return arc->from; +} + +/* -------------------------- Highlighting ---------------------------------- */ + +static void np_do_shape (node,function,action) +np_node* node; +int function; +np_action action; +{ + NetPlotPart *xd = &(node->widget->netPlot); + if (xd->exposed) { + XSetForeground (xd->dpy,xd->gc, xd->overlay); + XSetFunction (xd->dpy,xd->gc, function); + (*node->shape) (node,action); + XSetFunction (xd->dpy,xd->gc, GXcopy); + } +} + +void np_overlay (node) +np_node* node; +{ + /* If the node is being highlighted, set function to OR so that the + overlay pixels are turned on. Otherwise, set function to AND-INV + to clear just the overlay plane to remove any and all highlighting. */ + + np_do_shape (node, + (node->highlighted) ? GXor : GXandInverted, + (node->highlighted==1) ? NP_FRAME : NP_DRAW); +} + +void np_lowlight (node) +np_node *node; +{ + if (node->highlighted) { + node->highlighted = 0; + np_overlay (node); + } +} + +void np_highlight (node,what) +np_node *node; +Bool what; +{ + if (node->highlighted != what) { + node->highlighted = what; + np_overlay (node); + } +} + +void np_highlight_node (node,on) +np_node *node; +Bool on; +{ + np_highlight (node,on?2:0); +} + +void np_overlay_arc (arc,area) +np_arc* arc; +XRectangle* area; +{ + NetPlotPart *xd = &(arc->from->widget->netPlot); + if (xd->exposed) { + XSetForeground (xd->dpy,xd->gc, xd->overlay); + XSetFunction (xd->dpy,xd->gc, arc->highlighted?GXor:GXandInverted); + np_draw_an_arc (xd,area,arc); + XSetFunction (xd->dpy,xd->gc, GXcopy); + } +} + +void np_highlight_arc (arc,on) +np_arc* arc; +Bool on; +{ + /* Set the arc highlighting to the boolean value. */ + + if (arc->highlighted != on) { + arc->highlighted = on; + np_overlay_arc (arc,NULL); + } +} + +void np_new_highlight (w,label) +Widget w; +String label; +{ + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + lsGen gen; + np_node *node = NULL; + np_arc *arc; + NetPlotSelectData sel_data; + + if (graph->sel_label != NULL) xfree (graph->sel_label); + if (label == NULL) label = graph->label; + graph->sel_label = XtNewString (label); + sel_data.select_name = label; + XtCallCallbackList (w,graph->select_callbacks,(XtPointer)&sel_data); + + np_foreach_node (graph, gen, node) { + np_lowlight (node); + } + np_foreach_arc (graph, gen, arc) { + np_highlight_arc (arc,False); + } +} + +void np_set_title (w,s) +Widget w; +char *s; +{ + /* Change title of widget. */ + + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + + if (graph->label != NULL) xfree (graph->label); + graph->label = XtNewString (s); +} + +void np_orient (w,vert) +Widget w; +int vert; +{ + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + + graph->vertical = (vert != 0); +} + +void np_clear_plot (w) +Widget w; +{ + /* Deallocate any instance memory. */ + + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + +#ifdef WIDGET_DEBUG + fprintf(stderr,"clear plot for 0x%lX\n",widget); +#endif + lsDestroy (graph->nodes, np_free_node); + assert(lsLength(graph->arcs) == 0); + lsDestroy (graph->arcs, (void (*)()) NULL); + st_free_table (graph->node_table); + + /* Now reinitialize the graph. */ + graph->nodes = lsCreate(); + graph->arcs = lsCreate(); + graph->node_table = st_init_table (strcmp,st_strhash); + widget->netPlot.unplaced = True; + widget->netPlot.unscaled = True; + if (widget->netPlot.exposed) { + /* Force the widget to be redrawn. */ + XClearArea (graph->dpy,graph->win,0,0,0,0,True); + } +} + +void np_redraw (w,area,clear) +Widget w; +XRectangle* area; +int clear; +{ + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + lsGen gen; + np_arc *arc; + np_node *node; + + if (!graph->exposed) return; + + if (graph->unscaled) { +#ifdef WIDGET_DEBUG + fprintf(stderr,"Figuring initial geometry.\n"); +#endif + np_autoplace (w); + graph->unscaled = False; + } + + if (clear) XClearWindow (graph->dpy, graph->win); + + XSetForeground (graph->dpy, graph->gc, widget->netPlot.colors[4]); + np_foreach_arc (graph, gen, arc) { + np_draw_arc (graph,area,arc); + } + + XSetForeground (graph->dpy, graph->gc, widget->netPlot.colors[0]); + np_foreach_node (graph, gen, node) { + if (area == NULL || np_sect_rect (area,&node->bounds)) { + (*node->shape) (node,NP_ERASE); + } + } + + np_foreach_node (graph, gen, node) { + if (area == NULL || np_sect_rect (area,&node->bounds)) { + XSetForeground (graph->dpy, graph->gc, widget->netPlot.colors[node->color]); + (*node->shape) (node,NP_DRAW); + } + } + + np_foreach_node (graph, gen, node) { + if (node->highlighted && np_sect_rect (area,&node->bounds)) { + np_overlay (node); + } + } + + np_foreach_arc (graph, gen, arc) { + if (arc->highlighted) { + np_overlay_arc (arc,area); + } + } +} + +/* ------------------------------- Methods ---------------------------------- */ + +static void NetPlotInitialize (treq,tnew,arg_list,n_arg) +Widget treq; /* ARGSUSED */ +Widget tnew; /*u new instance of NetPlot widget. */ +ArgList arg_list; /* ARGSUSED */ +Cardinal* n_arg; /* ARGSUSED */ +{ + /* Check public fields of widget instance, and initialize private fields. + Translation is set to (0,0) since no STN is available yet. */ + + NetPlotWidget widget = (NetPlotWidget) tnew; + NetPlotPart *xd = &widget->netPlot; + unsigned long plane_masks[1], colors[NP_MAX_COLORS]; + float text_scale; + int i; + int screen_num; + + xd->exposed = False; + xd->label = XtNewString("<untitled>"); + xd->sel_label = NULL; + xd->nodes = lsCreate(); + xd->arcs = lsCreate(); + xd->node_table = st_init_table (strcmp,st_strhash); + xd->track_on = False; + xd->vertical = False; + + +#ifdef WIDGET_DEBUG + fprintf(stderr,"Initialize for 0x%lX\n",widget); +#endif + + xd->dpy = XtDisplay(widget); + screen_num = XScreenNumberOfScreen (XtScreen(widget)); + xd->gc = XCreateGC (xd->dpy,RootWindowOfScreen(XtScreen(widget)),0,NULL); + + /* Calculate pixels/mm in each direction. */ + xd->x_pix_per_mm = (float)DisplayWidth(xd->dpy,screen_num) / + (float)DisplayWidthMM(xd->dpy,screen_num); + xd->y_pix_per_mm = (float)DisplayHeight(xd->dpy,screen_num) / + (float)DisplayHeightMM(xd->dpy,screen_num); + + xd->font_height = xd->font->max_bounds.ascent + + xd->font->max_bounds.descent; + + /* Do we really need to set these? */ + text_scale = (float)xd->font_height; + xd->y_scale = text_scale; + xd->x_scale = (text_scale * xd->x_pix_per_mm) / xd->y_pix_per_mm; + xd->xt_user = xd->yt_user = 0.0; + +#ifdef WIDGET_DEBUG + printf("screen: (%.1f,%.1f) pix/mm\n",xd->x_pix_per_mm,xd->y_pix_per_mm); + printf("text: %.2f pix/unit\n",text_scale); + printf("view: (%.2f,%.2f) pix/unit\n",xd->x_scale, xd->y_scale); + printf(" (%.1f,%.1f) units xlate\n",xd->xt_user, xd->yt_user); +#endif + + if (widget->core.depth > 1 && + XAllocColorCells (xd->dpy,widget->core.colormap,False, + plane_masks,1, colors,NP_MAX_COLORS) != 0) { + /* Get RGB values for widget fore/back/highlight colors. */ + XColor color_defs[2*NP_MAX_COLORS]; + for (i=0; i < NP_MAX_COLORS; i++) { + color_defs[i].pixel = widget->netPlot.colors[i]; + color_defs[i+NP_MAX_COLORS].pixel = widget->netPlot.highlight; + } + XQueryColors (xd->dpy,widget->core.colormap,color_defs,2*NP_MAX_COLORS); + /* Store these RGB values in our writable color cells. */ + for (i=0; i < NP_MAX_COLORS; i++) { + color_defs[i].pixel = colors[i]; + widget->netPlot.colors[i] = colors[i]; + color_defs[i+NP_MAX_COLORS].pixel = colors[i] | plane_masks[0]; + } + XStoreColors (xd->dpy,widget->core.colormap,color_defs,2*NP_MAX_COLORS); + /* Can XOR plane mask to toggle hilighting. */ + widget->netPlot.overlay = plane_masks[0]; + } else { + fprintf(stderr,"Couldn't allocate color cells.\n"); + } + + XSetFont (xd->dpy,xd->gc, widget->netPlot.font->fid); + XSetForeground (xd->dpy,xd->gc, widget->netPlot.colors[1]); + XSetBackground (xd->dpy,xd->gc,widget->netPlot.colors[0]); + XSetLineAttributes (xd->dpy,xd->gc, xd->linewidth, + LineSolid, CapButt, JoinMiter); + + widget->core.width = 400; + widget->core.height = 360; + widget->netPlot.unplaced = True; + widget->netPlot.unscaled = True; +} + +static void NetPlotExpose (w,event,uprgn) +Widget w; +XEvent* event; +Region uprgn; +{ + /* Handle expose events: set clip region to the rectangle which was + exposed, redraw the plot, then restore the full clip region. */ + + /* ARGSUSED */ + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + XExposeEvent *expose = &(event->xexpose); + XRectangle area; + +#ifdef WIDGET_DEBUG + fprintf(stderr,"Expose %d for 0x%lX (%d,%d),(%d,%d)\n", + expose->count,widget,expose->x,expose->y,expose->width,expose->height); +#endif + graph->win = widget->core.window; + if (!graph->exposed) { + XSetWindowBackground (graph->dpy, widget->core.window, + widget->netPlot.colors[0]); + XClearWindow (graph->dpy, widget->core.window); + graph->exposed = True; + } + + area.x = expose->x; area.y = expose->y; + area.width = expose->width; area.height = expose->height; + + XSetClipRectangles (graph->dpy,graph->gc, 0,0, &area,1, YXBanded); + np_redraw (w,&area,False); + XSetClipMask (graph->dpy,graph->gc,None); +} + +static void NetPlotDestroy (w) +Widget w; +{ + /* Deallocate any instance memory. */ + + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + +#ifdef WIDGET_DEBUG + fprintf(stderr,"Destroy for 0x%lX\n",widget); +#endif + XFreeGC (graph->dpy,graph->gc); + lsDestroy (graph->nodes, np_free_node); + assert(lsLength(graph->arcs) == 0); + lsDestroy (graph->arcs, (void (*)()) NULL); + st_free_table (graph->node_table); +} + +static void NetPlotResize (w) +Widget w; +{ + /* Called when widget size is changed. */ + +#ifdef WIDGET_DEBUG + fprintf(stderr,"Resize for 0x%lX.\n",w); +#endif + np_autoplace (w); +} + +static XtGeometryResult NetPlotQueryGeometry (w, proposed, reply) +Widget w; +XtWidgetGeometry *proposed, *reply; +{ + /* Decide what a suitable geometry is. */ + +#ifdef WIDGET_DEBUG + fprintf(stderr,"Query Geometry for 0x%lX.\n",w); +#endif + reply->request_mode = CWWidth | CWHeight; + + reply->width = 400; + reply->height = 360; + + if (((proposed->request_mode & (CWWidth | CWHeight)) == + (CWWidth | CWHeight)) && + proposed->width == reply->width && + proposed->height == reply->height) { + return XtGeometryYes; + } + + return XtGeometryAlmost; +} + +/* ------------------------------- Actions ---------------------------------- */ + +static np_node *hit_test (graph,bx,by) +NetPlotPart* graph; +int bx; +int by; +{ + /* Return node which was hit by point (bx,by), or NULL if none. Only + check for hitting a dummy node if no regular node was hit. */ + + XRectangle hit; + lsGen gen; + np_node *node, *best = NULL; + int dy, dx; + + hit.x = bx; hit.y = by; + hit.height = hit.width = 1; + + np_foreach_node (graph, gen, node) { + if (node->dummy) continue; + if (np_sect_rect (&hit,&node->bounds)) { + if (node->highlighted || best == NULL || !best->highlighted) { + best = node; + } + } + } + + if (best == NULL) { + np_foreach_node (graph, gen, node) { + if (!node->dummy) continue; + dx = bx - node->bounds.x; + dy = by - node->bounds.y; + if (ABS(dx) < 10 && ABS(dy) < 10) { + best = node; + } + } + } + + return best; +} + +static void show_sel (w,node,param) +Widget w; +np_node *node; +String param; +{ + np_arc *arc; + lsGen gen; + + np_new_highlight (w,node->name); + np_highlight (node,2); + + if (param != NULL) { + + if (!strcmp(param,"in") || !strcmp(param,"inout")) { + np_foreach_fanin (node, gen, arc) { + np_highlight (np_real_fanin(arc),1); + } + } + + if (!strcmp(param,"out") || !strcmp(param,"inout")) { + np_foreach_fanout (node, gen, arc) { + np_highlight (np_real_fanout(arc),1); + } + } + } +} + +static void TrackNode (w,event,params,n_param) +Widget w; +XEvent* event; +String* params; /* ARGSUSED */ +Cardinal* n_param; /* ARGSUSED */ +{ + /* Try to track the mouse down. */ + + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + np_node *node = graph->selected; + int dx = event->xbutton.x - graph->hot_spot.x; + int dy = event->xbutton.y - graph->hot_spot.y; + + if (node == NULL) return; + + if (!graph->track_on) { /* Clear general highlighting. */ + np_new_highlight (w,node->name); + } + + /* Highlight new position using xor. */ + node->bounds.x += dx; + node->bounds.y += dy; + np_do_shape (node, GXxor, NP_FRAME); + node->bounds.x -= dx; + node->bounds.y -= dy; + + /* Erase old position if there was one. */ + if (graph->track_on) { + node->bounds.x += graph->cur_diff.x; + node->bounds.y += graph->cur_diff.y; + np_do_shape (node, GXxor, NP_FRAME); + node->bounds.x -= graph->cur_diff.x; + node->bounds.y -= graph->cur_diff.y; + } + + /* Now remember tracking is on, and save new delta. */ + graph->track_on = True; + graph->cur_diff.x = dx; + graph->cur_diff.y = dy; +} + +static void MoveNode (w,event,params,n_param) +Widget w; +XEvent* event; +String* params; /* ARGSUSED */ +Cardinal* n_param; /* ARGSUSED */ +{ + /* Finished moving something. */ + + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + np_node *node = graph->selected; + int dx = event->xbutton.x - graph->hot_spot.x; + int dy = event->xbutton.y - graph->hot_spot.y; + lsGen gen; + np_arc *arc; + XRectangle covers; + + if (graph->track_on) { + graph->selected->bounds.x += graph->cur_diff.x; + graph->selected->bounds.y += graph->cur_diff.y; + np_do_shape (graph->selected, GXxor, NP_FRAME); + graph->selected->bounds.x -= graph->cur_diff.x; + graph->selected->bounds.y -= graph->cur_diff.y; + graph->track_on = False; + } + + if (node != NULL && (dx != 0 || dy != 0)) { + /* Expose area where node used to be. */ + covers = node->bounds; + np_foreach_fanin (node,gen,arc) np_sect_arc (&covers,arc); + np_foreach_fanout (node,gen,arc) np_sect_arc (&covers,arc); + + /* Move the node (and arcs) to their new position. */ + node->bounds.x += dx; node->bounds.y += dy; + node->x = winToUserX (graph,node->bounds.x + node->bounds.width/2); + node->y = winToUserY (graph,node->bounds.y + node->bounds.height/2); + + /* Expose area where node is now. */ + np_wrap_rect (&covers, &covers, &node->bounds); + np_foreach_fanin (node,gen,arc) np_sect_arc (&covers,arc); + np_foreach_fanout (node,gen,arc) np_sect_arc (&covers,arc); + + /* Clear entire rect, forcing it to be redrawn. */ + XClearArea (graph->dpy,graph->win, + covers.x-ARROW_LENGTH, covers.y-ARROW_LENGTH, + covers.width+2*ARROW_LENGTH,covers.height+2*ARROW_LENGTH, True); + } +} + +static void SelectNode (w,event,params,n_param) +Widget w; +XEvent* event; +String* params; /* ARGSUSED */ +Cardinal* n_param; /* ARGSUSED */ +{ + /* Select or unselect the item closest to the mouse coordinates. */ + + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + int bx = event->xbutton.x, by = event->xbutton.y; + np_node *node; + + graph->selected = NULL; + + if (event->type == ButtonPress) { + + node = hit_test (graph, bx,by); + + if (node == NULL) { + np_new_highlight (w,graph->label); + } else { + show_sel (w,node,(*n_param==0)?NULL:params[0]); + graph->selected = node; + graph->hot_spot.x = bx; graph->hot_spot.y = by; + } + } +} + +static void DoNodeCmd (w,event,params,n_param) +Widget w; +XEvent* event; +String* params; /*i [0]=for node, [1]=otherwise. */ +Cardinal* n_param; /*i Note that all params are optional. */ +{ + /* Execute a sis node command on the node nearest to the cursor. */ + + NetPlotWidget widget = (NetPlotWidget) w; + NetPlotPart *graph = &widget->netPlot; + int bx = event->xbutton.x, by = event->xbutton.y; + char print_cmd[80]; + np_node *node; + extern void xsis_execute (); + + node = hit_test (graph, bx,by); + + if (node != NULL && *n_param >= 1) { + sprintf (print_cmd,params[0],np_name(node)); + xsis_execute (print_cmd,False); + } else if (node == NULL && *n_param >= 2) { + xsis_execute (params[1],False); + } +} + +/* ----------------------------- Resource List ------------------------------ */ + +static XtResource resources[] = { +#define offset(field) XtOffset(NetPlotWidget, netPlot.field) + /* {name, class, type, size, offset, default_type, default_addr}, */ + { XtNbackground, XtCBackground, XtRPixel, + sizeof(Pixel),offset(colors[0]), XtRString, XtDefaultBackground }, + { XtNforeground1, XtCForeground, XtRPixel, + sizeof(Pixel),offset(colors[1]), XtRString, XtDefaultForeground }, + { XtNforeground2, XtCForeground, XtRPixel, + sizeof(Pixel),offset(colors[2]), XtRString, XtDefaultForeground }, + { XtNforeground3, XtCForeground, XtRPixel, + sizeof(Pixel),offset(colors[3]), XtRString, XtDefaultForeground }, + { XtNforeground4, XtCForeground, XtRPixel, + sizeof(Pixel),offset(colors[4]), XtRString, XtDefaultForeground }, + { XtNhighlight, XtCForeground, XtRPixel, + sizeof(Pixel),offset(highlight), XtRString, XtDefaultForeground }, + { XtNfont, XtCFont, XtRFontStruct, + sizeof(Pixel),offset(font), XtRString, "times_bold14" }, + { XtNselectCallback, XtCCallback, XtRCallback, sizeof(XtPointer), + offset(select_callbacks), XtRCallback, (XtPointer)NULL }, + { XtNlineWidth, XtCWidth, XtRInt, + sizeof(int),offset(linewidth), XtRString, (XtPointer)"0" } +#undef offset +}; + +/* ------------------------------ Actions Table ----------------------------- */ + +static XtActionsRec actions[] = +{ + /* { name, function}, */ + {"SelectNode", SelectNode}, + {"TrackNode", TrackNode}, + {"MoveNode", MoveNode}, + {"DoNodeCmd", DoNodeCmd}, +}; + +/* -------------------------- Default Translation Table --------------------- */ + +static char translations[] = "\ +<Btn1Down>: SelectNode(inout) \n\ +<Btn2Down>: DoNodeCmd(\"print %s\",print_stats) \n\ +<Btn3Down>: SelectNode() \n\ +<Btn3Motion>: TrackNode() \n\ +<Btn3Up>: MoveNode() \n\ +"; + +/* ------------------------ Class Record Initialization --------------------- */ + +static NetPlotClassRec netPlotClassRec = { + { /* core fields */ + /* superclass */ (WidgetClass) &widgetClassRec, + /* class_name */ "NetPlot", + /* widget_size */ sizeof(NetPlotRec), + /* class_initialize */ NULL, + /* class_part_initialize */ NULL, + /* class_inited */ FALSE, + /* initialize */ NetPlotInitialize, + /* initialize_hook */ NULL, + /* realize */ XtInheritRealize, + /* actions */ actions, + /* num_actions */ XtNumber(actions), + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ TRUE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ TRUE, + /* visible_interest */ FALSE, + /* destroy */ NetPlotDestroy, + /* resize */ NetPlotResize, /* or NULL */ + /* expose */ NetPlotExpose, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_private */ NULL, + /* tm_table */ translations, + /* query_geometry */ NetPlotQueryGeometry, + /* display_accelerator */ XtInheritDisplayAccelerator, + /* extension */ NULL + }, + { /* netPlot fields */ + /* empty */ 0 + } +}; + + +WidgetClass netPlotWidgetClass = (WidgetClass) &netPlotClassRec; diff --git a/xsis/NetPlot.h b/xsis/NetPlot.h new file mode 100644 index 0000000..710a28a --- /dev/null +++ b/xsis/NetPlot.h @@ -0,0 +1,93 @@ +/* -------------------------------------------------------------------------- *\ + NetPlot.h -- public declarations for NetPlot Widget. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/NetPlot.h,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. + + Resources recognized by NetPlot widgets. Since NetPlot widgets use more + than one foreground color, you should use the class Foreground to set + all foreground colors to a single color, e.g. "NetPlot*Foreground" vs. + "NetPlot*foreground". + + Name Class RepType Default Value + ---- ----- ------- ------------- + background Background Pixel White + foreground1 Foreground Pixel Black + foreground2 Foreground Pixel Black + foreground3 Foreground Pixel Black + foreground4 Foreground Pixel Black + hilight Hilight Pixel Black + font Font FontStruct ? + selectCallback Callback Callback NULL + lineWidth LineWidth Width 0 +\* -------------------------------------------------------------------------- */ + +#ifndef _NetPlot_h +#define _NetPlot_h + +#define XtNselectCallback "selectCallback" +#define XtNforeground1 "foreground1" +#define XtNforeground2 "foreground2" +#define XtNforeground3 "foreground3" +#define XtNforeground4 "foreground4" +#define XtNlineWidth "lineWidth" + + /* Class constant (i.e. factory object). */ + +extern WidgetClass netPlotWidgetClass; + + /* Convenience functions. */ + +typedef enum np_action { + NP_ERASE, /* Erase the background area. */ + NP_FRAME, /* Draw suitable frame shape. */ + NP_DRAW, /* Draw entire graphic. */ + NP_CALC_WIDTH, /* Calc. width field. */ + NP_CALC_HEIGHT /* Calc. height field. */ +} np_action; + + +typedef struct NetPlotSelectData { /* XtNselectCallback data. */ + String select_name; /* Name of new selection. */ +} NetPlotSelectData; + +typedef struct np_node np_node; +typedef struct np_arc np_arc; + +typedef int (*np_shape) ARGS((np_node *, np_action)); + +extern int np_dummy ARGS((np_node *, np_action)); +extern int np_textblock ARGS((np_node *, np_action)); +extern int np_rectangle ARGS((np_node *, np_action)); +extern int np_ellipse ARGS((np_node *, np_action)); +extern int np_itrans ARGS((np_node *, np_action)); +extern int np_otrans ARGS((np_node *, np_action)); + +extern void np_clear_plot ARGS((Widget)); +extern np_node *np_find_node ARGS((Widget, String, Bool)); +extern np_node *np_create_node ARGS((Widget, String)); +extern void np_set_shape ARGS((np_node *, np_shape)); +extern void np_set_label ARGS((np_node *, String)); +extern void np_set_position ARGS((np_node *, double, double)); +extern void np_orient ARGS((Widget, int)); +extern void np_set_node_color ARGS((np_node *, unsigned)); +extern np_arc *np_create_arc ARGS((np_node *, np_node *, String)); +extern np_arc *np_find_arc ARGS((np_node *, np_node *)); +extern np_node *np_insert_bend ARGS((np_arc *)); +extern void np_redraw ARGS((Widget, XRectangle*, int)); +extern void np_autoplace ARGS((Widget)); +extern void np_set_title ARGS((Widget, String)); +extern void np_new_highlight ARGS((Widget, String)); +extern void np_highlight_node ARGS((np_node *, Bool)); +extern void np_highlight_arc ARGS((np_arc *, Bool)); + +#endif /* _NetPlot_h */ diff --git a/xsis/NetPlotP.h b/xsis/NetPlotP.h new file mode 100644 index 0000000..f3d2838 --- /dev/null +++ b/xsis/NetPlotP.h @@ -0,0 +1,150 @@ +/* -------------------------------------------------------------------------- *\ + NetPlotP.h -- private declarations of NetPlot Widget. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/NetPlotP.h,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. +\* -------------------------------------------------------------------------- */ + +#ifndef _NetPlotP_h +#define _NetPlotP_h + +#ifndef MAKE_DEPEND +#include <stdio.h> +#include <math.h> +#include <X11/Xlib.h> +#include <X11/StringDefs.h> +#include <X11/Intrinsic.h> +#include <X11/IntrinsicP.h> +#include <X11/CoreP.h> /* Superclass private header file. */ +#include <util.h> +#include <list.h> +#include <st.h> +#endif +#include "NetPlot.h" /* Public declaractions for widget. */ + + +typedef struct _NetPlotClassRec* NetPlotWidgetClass; +typedef struct _NetPlotRec* NetPlotWidget; + +typedef struct np_rect { /* rect with float dimensions. */ + float x,y; + float width,height; +} np_rect; + +typedef struct { /* Extensions to parent class. */ + int dummy; /* No extensions. */ +} NetPlotClassPart; + +typedef struct _NetPlotClassRec { + CoreClassPart core_class; + NetPlotClassPart netPlot_class; +} NetPlotClassRec; + +#define NP_MAX_COLORS 5 + +typedef struct { /* Extensions to widget instance. */ + Pixel colors[NP_MAX_COLORS]; /* Drawing colors for figures. */ + Pixel highlight; /* To highlight parts of the net. */ + XFontStruct *font; /* Font for labels in widget. */ + int font_height; /* Height for graphics scaling. */ + XtCallbackList select_callbacks; /* When selection changes. */ + int linewidth; /* For drawing in the GC. */ + /* Private state. */ + String label; /* Label of graph. */ + Bool unplaced; /* True if objects never placed. */ + Bool unscaled; /* True=user coord. frame unknown. */ + Bool exposed; /* True if window has been exposed. */ + Display *dpy; /* Display for widget window. */ + Window win; /* Window of plot widget. */ + GC gc; /* Single changable GC. */ + Pixel overlay; /* Mask for drawing overlays on image. */ + st_table *node_table; /* For direct access by name. */ + lsList nodes; + lsList arcs; + Bool vertical; /* Arcs attach to top/bottom? */ + + float xt_user; /* Transform user/window coordinates. */ + float yt_user; /* translate user origin to win origin */ + float x_scale; /* x scale: pixels per user unit. */ + float y_scale; /* y scale: pixels per user unit. */ + + float x_pix_per_mm; /* display scale: pixels per mm. */ + float y_pix_per_mm; /* display scale: pixels per mm. */ + int win_w, win_h; /* From drawstg.c -- coordinate info. */ + short root_height; + short root_width; + + String sel_label; /* Label of current selection. */ + /* int maxx, maxy; window dimensions */ + int xlo, xhi; + int ylo, yhi; + int xspacing; + int yspacing; + Bool track_on; /* True when track_rect is drawn. */ + XPoint hot_spot; /* Where initial click was made. */ + XPoint cur_diff; /* Place where last was highlighted. */ + np_node *selected; /* Current selected node. */ +} NetPlotPart; + +typedef struct _NetPlotRec { /* New widget instance struct. */ + CorePart core; + NetPlotPart netPlot; +} NetPlotRec; + + +struct np_node { + NetPlotWidget widget; /* Graph containing this node. */ + np_shape shape; /* How to draw this thing. */ + char *name; /* Name for table lookup. */ + char *label; /* Label to print in plot. */ + int highlighted; /* 0=none, 1=frame, 2=all. */ + XRectangle bounds; /* Window bounds for object. */ + Bool dummy; /* Node is a dummy node. */ + int color; /* Index into colors table. */ + int level,vertpos; /* Generic x,y placement. */ + float x,y; /* User coord. of object. */ + int grids_high; /* For generic placement algo. */ + lsList fanins; /* Fanin edges. */ + lsList fanouts; /* Fanout edges. */ +}; + +struct np_arc { + NetPlotWidget widget; + char *label; + np_node *from; + np_node *to; + int style; /* LineSolid, LineOnOffDash, ...*/ + Bool highlighted; +}; + + +#define num_fanins(node) lsLength((node)->fanins) +#define num_fanouts(node) lsLength((node)->fanouts) + +#define np_lsForeachItem(list, gen, data) \ + for (gen = lsStart(list); \ + (lsNext(gen, (lsGeneric *) &data, LS_NH) == LS_OK) \ + || ((void) lsFinish(gen), 0); ) + +#define np_foreach_node(graph, gen, node) \ + np_lsForeachItem((graph)->nodes, gen, node) + +#define np_foreach_arc(graph, gen, arc) \ + np_lsForeachItem((graph)->arcs, gen, arc) + +#define np_foreach_fanin(node, gen, arc) \ + np_lsForeachItem((node)->fanins, gen, arc) + +#define np_foreach_fanout(node, gen, arc) \ + np_lsForeachItem((node)->fanouts, gen, arc) + +#endif /* _NetPlotP_h */ diff --git a/xsis/blif50.px b/xsis/blif50.px new file mode 100644 index 0000000..3ac8499 --- /dev/null +++ b/xsis/blif50.px @@ -0,0 +1,33 @@ +#define blif50_width 50 +#define blif50_height 50 +static char blif50_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x10, + 0x80, 0xbf, 0xff, 0x00, 0x80, 0xc0, 0x10, 0x00, 0x8e, 0xc0, 0x00, 0x80, + 0x80, 0x10, 0x00, 0x84, 0x80, 0x00, 0x80, 0x80, 0x10, 0x00, 0x84, 0x00, + 0x00, 0x80, 0x80, 0x10, 0x00, 0x84, 0x00, 0x00, 0x80, 0x80, 0x10, 0x00, + 0x84, 0x00, 0x00, 0x80, 0x80, 0x10, 0x00, 0x84, 0x00, 0x00, 0x80, 0xc0, + 0x10, 0x00, 0x84, 0x00, 0x00, 0x80, 0x60, 0x10, 0x00, 0x84, 0x08, 0x00, + 0x80, 0x38, 0x10, 0x00, 0x84, 0x0c, 0x00, 0x80, 0x7f, 0x10, 0x00, 0x84, + 0x0f, 0x00, 0x80, 0xc0, 0x10, 0x00, 0x84, 0x0c, 0x00, 0x80, 0x80, 0x10, + 0x00, 0x84, 0x08, 0x00, 0x80, 0x80, 0x10, 0x00, 0x84, 0x00, 0x00, 0x80, + 0x80, 0x11, 0x00, 0x84, 0x00, 0x00, 0x80, 0x00, 0x11, 0x00, 0x84, 0x00, + 0x00, 0x80, 0x00, 0x11, 0x00, 0x84, 0x00, 0x00, 0x80, 0x00, 0x11, 0x00, + 0x84, 0x00, 0x00, 0x80, 0x00, 0x12, 0x00, 0x84, 0x00, 0x00, 0x80, 0x00, + 0x13, 0x00, 0x84, 0x00, 0x00, 0x80, 0x80, 0x11, 0x00, 0x84, 0x01, 0x00, + 0x80, 0xc0, 0x10, 0x00, 0x8e, 0x03, 0x00, 0x80, 0x7f, 0xf0, 0x8f, 0xbf, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x02, 0x9f, 0xff, 0x00, 0x00, 0x00, 0x64, 0x02, 0x11, 0x08, 0x00, 0x00, + 0x00, 0x44, 0x02, 0x11, 0x08, 0x00, 0x00, 0x00, 0x44, 0x02, 0x11, 0x08, + 0x00, 0x00, 0x00, 0x44, 0x02, 0x11, 0x08, 0x00, 0x00, 0x00, 0x44, 0x82, + 0x10, 0x08, 0x00, 0x00, 0x00, 0x64, 0x82, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x3c, 0x82, 0x10, 0x08, 0x00, 0x00, 0x00, 0x04, 0x82, 0x10, 0x08, 0x00, + 0x00, 0x00, 0x04, 0x82, 0x10, 0x08, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x10, + 0x08, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x18, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x82, 0x08, 0x08, 0x00, 0x00, 0x00, 0x04, 0x82, 0x0f, 0x08, 0x00, 0x00, + 0x00, 0x04, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}; diff --git a/xsis/fakesis.c b/xsis/fakesis.c new file mode 100644 index 0000000..bd3ab15 --- /dev/null +++ b/xsis/fakesis.c @@ -0,0 +1,144 @@ +/* -------------------------------------------------------------------------- *\ + fakesis.c -- simple test program for debugging xsis + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/fakesis.c,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. + + Since the interface to xsis is so trivial, it is often easier to debug + the communications using this "stub" sis program. Compile this program, + and run as "xsis -debug -sis fakesis". Special commands that fakesis + recognizes: + + plot - open an empty network plot window + cat <file> - write contents of file to stdout. + slo <file> - write contents 1 char/sec to stress-test. + quit - exit the program + + Otherwise it just prints a message to you for every line typed. + The most common problem is how sis cleans up when xsis exits unexpectedly. + To test this, run xsis with the -debug option, then enter "bailout" which + forces xsis to do a _exit (this only works in debug mode). Then you can + monitor what happens to the orphaned (fake)sis process. The most + civilized behavior is for fakesis to receive the SIGHUP signal, which is + caught and noted in file fakesis.log. The most barbaric behavior is for + fakesis to be stranded in an infinite loop, eating CPU time. + + As necessary, other messages to the log can be added to help debug xsis + as it is ported to new systems. +\* -------------------------------------------------------------------------- */ + +#include <stdio.h> +#include <strings.h> +#include <signal.h> +#include "xsis.h" + +static FILE *fakesis_log; /* For diagnostic messages. */ + +static void catch_sighup () +{ + if(fakesis_log)fprintf(fakesis_log,"Caught SIGHUP\n"); + exit(-1); +} + +int main (argc,argv) +int argc; +char** argv; +{ + char buf[1000], *p; + extern int errno; + FILE *fin; + int i, c; + int slow; + + signal(SIGHUP,catch_sighup); + + /* This opens the main xsis command window. */ + fputs(COM_GRAPHICS_MSG_START,stdout); + puts("cmd\tnew\tcmd"); + puts(".version\tFakeSIS 1.0"); + fputs(COM_GRAPHICS_MSG_END,stdout); + + fakesis_log = fopen("fakesis.log","w"); + if (fakesis_log == NULL) { + printf("failed to open fakesis.log.\n"); + } else { + printf("Log is in file fakesis.log.\n"); + } + +#if defined(SYSV) + printf("SYSV defined: system-V.\n"); +#endif +#if defined(__osf__) + printf("OSF System\n"); +#endif +#if defined(SABER) + printf("Saber-C\n"); +#endif + +#if defined(sun) && defined(sparc) + printf("Sun SPARC\n"); +#elif defined(_IBMR2) && defined(_AIX) + printf("IBM RS\n"); +#elif defined(ultrix) && defined(mips) + printf("DECstation\n"); +#else + printf("Generic POSIX.\n"); +#endif + + printf("argv: "); + for (i=0; i < argc; i++) printf(" %s",argv[i]); + printf("\n"); + + printf("Go ahead and type, I'm connected to %s.\n",ttyname(1)); + fputs("sis> ",stdout); + + /* This emulates the sis command loop in sis/command/source.c. If + the sis loop is changed, this should also be modified to match. */ + + while (fgets(buf,sizeof(buf),stdin) != NULL) { + if (fakesis_log) {fprintf(fakesis_log,"%s",buf);fflush(fakesis_log);} + if (!strcmp(buf,"plot\n")) { + fputs(COM_GRAPHICS_MSG_START,stdout); + puts("blif\tnew\tsample"); + puts(COM_GRAPHICS_MSG_END); + } else if (!strcmp(buf,"quit\n")) { + if (fakesis_log) {fprintf(fakesis_log,"<EOF>");fflush(fakesis_log);} + sleep (10); + if (fakesis_log) {fprintf(fakesis_log,"exit");fflush(fakesis_log);} + return 0; + } else if (!strncmp(buf,"cat ",4) || (slow=!strncmp(buf,"slo ",4))) { + /* Try to copy a file to the output. */ + p = strchr(buf,'\n'); if (p) *p = '\0'; + if ((fin=fopen(buf+4,"r")) != NULL) { + while ((c=fgetc(fin)) != EOF) { + fputc (c,stdout); + if (slow) {fflush(stdout);sleep(1);} + } + fclose (fin); + } else { + fprintf(stdout,"No such file.\n"); + } + } else { + fprintf(stdout,"Would be doing command\n"); + } + fputs("sis> ",stdout); + } + + if (fakesis_log) { + fprintf(fakesis_log,"fgets == NULL, feof=%d, ferror=%d, errno=%d\n", + feof(stdin), ferror(stdin), errno); + fflush(fakesis_log); + fclose (fakesis_log); + } + + return 0; +} diff --git a/xsis/ghost.px b/xsis/ghost.px new file mode 100644 index 0000000..9df3ae4 --- /dev/null +++ b/xsis/ghost.px @@ -0,0 +1,48 @@ +#define ghost_dev88_width 64 +#define ghost_dev88_height 64 +#define ghost_dev88_x_hot -1 +#define ghost_dev88_y_hot -1 +static char ghost_dev88_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, 0xf0, + 0x1f, 0x00, 0x3c, 0x00, 0x00, 0x10, 0x02, 0x10, 0x70, 0x00, 0xe4, 0x00, + 0x00, 0x08, 0x02, 0x70, 0xc0, 0x01, 0x4c, 0x01, 0x00, 0x08, 0x02, 0x40, + 0xa8, 0x0e, 0x18, 0x02, 0x00, 0x04, 0x01, 0x40, 0x00, 0x30, 0x50, 0x04, + 0x00, 0x84, 0x01, 0x40, 0x00, 0x60, 0x90, 0x08, 0x00, 0x82, 0x00, 0x40, + 0x00, 0x42, 0x30, 0x08, 0x00, 0x62, 0x00, 0x20, 0x38, 0xcf, 0x60, 0x10, + 0x00, 0x72, 0x00, 0x10, 0x3c, 0xdf, 0x60, 0x11, 0x00, 0x5a, 0x00, 0x08, + 0x2e, 0x9a, 0xc0, 0x21, 0x00, 0x82, 0x00, 0x08, 0x3f, 0x9c, 0x80, 0x27, + 0x00, 0x82, 0x00, 0x08, 0x0e, 0x80, 0x81, 0x24, 0x00, 0x02, 0x03, 0x08, + 0x80, 0x83, 0x81, 0x20, 0x00, 0x02, 0x0e, 0x0c, 0xe0, 0x87, 0x81, 0x20, + 0x00, 0x02, 0xf8, 0x07, 0xe0, 0x87, 0x81, 0x20, 0x00, 0x04, 0x00, 0x00, + 0xe0, 0x8f, 0x43, 0x20, 0x00, 0x0c, 0x00, 0x00, 0xe0, 0x07, 0x26, 0x30, + 0x00, 0x0c, 0x00, 0x00, 0xc0, 0x07, 0x1c, 0x30, 0x00, 0x18, 0x00, 0x00, + 0x80, 0x03, 0x00, 0x18, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xc0, 0x01, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x80, 0x00, 0xef, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x80, 0xc3, 0x81, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x7e, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1c, 0x03, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00, 0x70, 0x00, + 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0xe0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x07, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/xsis/help50.px b/xsis/help50.px new file mode 100644 index 0000000..59ce3c5 --- /dev/null +++ b/xsis/help50.px @@ -0,0 +1,33 @@ +#define help50_width 50 +#define help50_height 50 +static char help50_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0xf0, 0x8f, 0xff, 0xff, 0x1f, 0xff, + 0x01, 0x30, 0x80, 0xff, 0x80, 0x1f, 0x00, 0x01, 0x3c, 0x80, 0x3f, 0x80, + 0x3f, 0x00, 0x01, 0x2c, 0x80, 0x07, 0x00, 0x3f, 0x00, 0x01, 0x3c, 0x00, + 0x03, 0x00, 0x3e, 0x00, 0x01, 0x2e, 0x37, 0x00, 0x00, 0x3e, 0x3b, 0x01, + 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x01, 0x2e, 0x00, 0x00, 0x00, 0x3e, + 0x3d, 0x01, 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x01, 0x2e, 0x6f, 0x0f, + 0x00, 0x1f, 0x35, 0x01, 0x3e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x2e, + 0x7b, 0x0b, 0x80, 0x1f, 0x3f, 0x01, 0x3e, 0x00, 0x00, 0xc0, 0x0f, 0x00, + 0x01, 0x2e, 0xdf, 0x0f, 0xc0, 0x0f, 0x2b, 0x01, 0x3e, 0x00, 0x00, 0xe0, + 0x0f, 0x00, 0x01, 0x2e, 0x00, 0x00, 0xf8, 0x03, 0x37, 0x01, 0x3e, 0x00, + 0x00, 0xff, 0x01, 0x00, 0x01, 0x2e, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x01, + 0x3e, 0x77, 0x8d, 0x1f, 0x00, 0x00, 0x01, 0x2e, 0x00, 0x80, 0x0f, 0x00, + 0x00, 0x01, 0x3e, 0x00, 0x80, 0x07, 0x00, 0x00, 0x01, 0x2e, 0x00, 0x80, + 0x07, 0x00, 0x00, 0x01, 0x3e, 0x00, 0x80, 0x07, 0x00, 0x00, 0x01, 0x2e, + 0x00, 0x80, 0x07, 0x00, 0x00, 0x01, 0x3e, 0x00, 0x80, 0x07, 0x00, 0x00, + 0x01, 0x2e, 0x00, 0x80, 0x07, 0x00, 0x00, 0x01, 0x3e, 0x00, 0x80, 0x07, + 0x00, 0x00, 0x01, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x3e, 0x00, 0x80, 0x07, 0x00, 0x00, 0x01, 0x2e, 0x00, 0x80, 0x07, 0x00, + 0x00, 0x01, 0x3e, 0x00, 0x80, 0x07, 0x00, 0x00, 0x01, 0x2e, 0x00, 0x80, + 0x07, 0x00, 0x00, 0x01, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfe, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0x01, 0xae, 0xaa, 0xea, 0xf9, 0xff, 0xff, 0x01, 0xfe, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}; diff --git a/xsis/main.c b/xsis/main.c new file mode 100644 index 0000000..7851227 --- /dev/null +++ b/xsis/main.c @@ -0,0 +1,273 @@ +/* -------------------------------------------------------------------------- *\ + main.c -- handle fork/exec for xsis/sis pair. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/main.c,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. + + xsis runs a copy of sis as a child process. A pty (pseudo-tty) is used to + connect to sis stdin/stdout/stderr so that ^D works as EOF the same as for + a tty, and so that library calls which set terminal characteristics will + work. Since output from sis is unpredictable, xsis reads the pty in + unblocked mode until a graphics command is found. In this configuration, + xsis is the master (device) and sis is the slave. + + Porting this to System-V environments will require some work for the + system-dependent file and process control. There are several terminal + interface definitions available -- xsis uses the termios(4) interface + defined by the IEEE POSIX standard P1003.1. + + We clear the controlling terminal so programs like more(1) work correctly + within xsis. In general, the tcgetattr/tcsetattr calls only work on the + slave side of the pty and not on the controller side. So xsis cannot tell + when sis is reading in raw mode for example. +\* -------------------------------------------------------------------------- */ + +#ifndef MAKE_DEPEND +#include <fcntl.h> +#include <termios.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#ifndef TIOCNOTTY +# include <sys/ioctl.h> +#endif +#endif /* MAKE_DEPEND */ + +/* Under DEC OSF1, TIOCNOTTY is defined in <sys/ioctl.h>. However, under + SunOS 4.1.1, it is defined by including <fcntl.h> and further, including + both <fcntl.h> and <sys/ioctl.h> causes errors with several dozen + identifiers multiply defined (and defined differently). So <sys/ioctl.h> + is conditionally included if TIOCNOTTY is not already defined. If you + know of a better kludge, please let us know. */ + +typedef int xsis_pstat; /* Default type of 2nd arg. to waitpid. */ + +#if defined(ultrix) && defined(mips) + /* Other termios interfaces use ECHOCTL for this parameter. */ +# define ECHOCTL TCTLECH + /* Use a more efficient fork when readily available. */ +# define fork vfork +# define xsis_pstat union wait + /* The POSIX nonblocking I/O flag doesn't work under Ultrix 4.2. */ +# undef O_NONBLOCK +# define O_NONBLOCK O_NDELAY +#endif + +#include "xsis.h" + +static pid_t xsis_child_pid; /* sis child PID. */ + + +static void catch_sigcld () +{ + /* Update global status when a child change is signaled. If you get + error messages for lines using the status parameter, check that + the xsis_pstat type defined above is correct for the waitpid(2) call + on your system. */ + + xsis_pstat status; + int sis_status; + pid_t pid; + + if (xsis_world.debug) printf("Caught sigcld.\n"); + pid = waitpid (xsis_child_pid,&status,WNOHANG|WUNTRACED); + if (xsis_world.debug) printf("Child PID %d changes status.\n",pid); + + if (pid > 0) { + if (WIFEXITED(status)) { + sis_status = WEXITSTATUS(status); + if (xsis_world.debug) printf("..exit status %d\n",sis_status); + xsis_world.child_status = XSIS_EXITED; + xsis_world.exit_code = sis_status; + exit (sis_status); + } else if (WIFSIGNALED(status)) { + sis_status = WTERMSIG(status); + if (xsis_world.debug) printf("..killed by signal %d\n",sis_status); + xsis_world.child_status = XSIS_KILLED; + xsis_world.exit_code = sis_status; + } else if (WIFSTOPPED(status)) { + sis_status = WSTOPSIG(status); + if (xsis_world.debug) printf("..stopped by signal %d\n",sis_status); + /* Anything to do here? */ + } + } +} + +void xsis_intr_child () +{ + /* Send an interrupt to the child process. */ + + if (xsis_world.debug) printf("kill(%d)\n",xsis_child_pid); + if (kill (xsis_child_pid,SIGINT) != 0) { + xsis_perror("kill"); + } +} + +static int open_pty_pair (master,slave) +int* master; +int* slave; +{ + /* Handle the messy details of opening a pty pair. See pty(4). */ + + static char pty_name[] = "/dev/pty.."; + static char tty_name[] = "/dev/tty.."; + static char altchar1[] = "pqrs"; + static char altchar2[] = "0123456789abcdef"; + + int i,j; + int failed = (-1); + +#if !defined(SABER) + /* Clear controlling terminal so pty will become it. */ + { int fdtty = open("/dev/tty",O_RDWR,0); + if (fdtty > 0) { + ioctl(fdtty, TIOCNOTTY, 0); + close(fdtty); + } + } +#endif + + putenv ("TERM=xsis"); + putenv ("TERMCAP='Xaw|xsis:bs:co#80:do=^J:hc:os'"); + + for (i=0; failed && i < sizeof(altchar1)/sizeof(char); i++) { + tty_name[8] = pty_name[8] = altchar1[i]; + for (j=0; failed && j < sizeof(altchar2)/sizeof(char); j++) { + tty_name[9] = pty_name[9] = altchar2[j]; + if (((*master)=open(pty_name,O_RDWR,0)) > -1) { + if (((*slave)=open(tty_name,O_RDWR,0)) > -1) { + failed = 0; + xsis_world.pty_master_name = pty_name; + xsis_world.pty_slave_name = tty_name; + } else { + close (*master); + } + } + } + } + + return failed; +} + +void xsis_tty_block (fildes,blocking) +int fildes; +int blocking; +{ + /* Enable/disable blocking I/O on the specified file descriptor. The + flag O_NONBLOCK is a POSIX standard, defined for many systems. Other + names for it include O_NDELAY, FNBIO, and FNDELAY. It is usually + defined in the man page for fcntl(2). */ + + int flags = fcntl(fildes,F_GETFL,0); + if (blocking) + flags &= ~O_NONBLOCK; + else + flags |= O_NONBLOCK; + fcntl (fildes,F_SETFL,flags); +} + +int xsis_pty_eof_char (fildes) +int fildes; +{ + /* Look up the EOF character for the pty. Returns ^D (004) if we + fail to get the pty information. */ + + int veof = '\004'; /* default=^D */ + struct termios terminfo; + if (tcgetattr(fildes,&terminfo) == 0) { + veof = terminfo.c_cc[VEOF]; + if (xsis_world.debug) printf("pty eof char=%d\n",veof); + } + return veof; +} + +int xsis_icanon_disabled (fildes) +int fildes; +{ + /* Return 1 if canonical input processing (ICANON) is disabled. Note: + this does not work on systems where only the slave device can make + tcgetattr calls successfully, so we default to assume it is enabled. */ + + int icanon_disabled = 0; + struct termios terminfo; + + if (tcgetattr (fildes, &terminfo) == 0) { + icanon_disabled = (terminfo.c_lflag & ICANON) == 0; + } + return icanon_disabled; +} + +int main (argc,argv) +int argc; +char **argv; +{ + int master, slave; /* pty file descriptors. */ + char *sis_exec; /* Path for sis executable. */ + pid_t pid = 0; /* SIS child process id. */ + struct termios terminfo; /* For setting terminal stuff. */ + struct stat statrec; /* For checking file mode. */ + + if ((sis_exec=xsis_find_sis(argc,argv)) == NULL) { + printf("%s: could not find \"sis\" to run.\n",argv[0]); + return (-1); + } + + if (stat(sis_exec,&statrec) != 0 || (statrec.st_mode&S_IFMT) != S_IFREG) { + printf("%s: not an executable file.\n",sis_exec); + return (-1); + } + + if (open_pty_pair(&master,&slave) != 0) { + printf("%s: failed to open pty.\n",argv[0]); + return (-1); + } + + if ((pid=fork()) == -1) { /* ERROR */ + return xsis_perror("vfork"); + } + else if (pid != 0) { /* PARENT */ + close (slave); + xsis_child_pid = pid; + xsis_world.sis_pty = master; + xsis_world.exit_code = 0; + xsis_world.child_status = XSIS_IDLE; + xsis_tty_block (xsis_world.sis_pty,0); + if (xsis_world.debug) printf("Starting %s, PID %d.\n",sis_exec,pid); + signal (SIGCLD,catch_sigcld); + xsis_main (argc,argv); + close (master); + } + else { /* CHILD */ + close (master); + if (tcgetattr (slave, &terminfo) != 0) { + xsis_perror ("tcgetattr"); + return (-1); + } else { + terminfo.c_oflag &= ~ONLCR; /* Don't map NL on output. */ + terminfo.c_oflag &= ~TAB3; /* Don't expand tabs on output. */ + terminfo.c_lflag |= ECHO; /* Echo all input. */ + terminfo.c_lflag |= ICANON; /* Use canonical input. */ + if (tcsetattr (slave, TCSADRAIN, &terminfo) != 0) { + xsis_perror ("tcsetattr"); + } + } + dup2 (slave, 0); /* Connect slave pty to stdin, */ + dup2 (slave, 1); /* stdout, */ + dup2 (slave, 2); /* and stderr. */ + if (slave > 2) close (slave); + execl (sis_exec, sis_exec, "-X 2", NULL); + xsis_perror (sis_exec); + _exit(-1); + } + + return xsis_world.exit_code; +} diff --git a/xsis/sis50.px b/xsis/sis50.px new file mode 100644 index 0000000..a36b9f7 --- /dev/null +++ b/xsis/sis50.px @@ -0,0 +1,33 @@ +#define sis50_width 50 +#define sis50_height 50 +static char sis50_bits[] = { + 0x0f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xc0, 0x7f, 0xe0, 0x07, + 0x00, 0x00, 0x81, 0x20, 0x84, 0x10, 0x08, 0x00, 0x80, 0x00, 0x01, 0x04, + 0x08, 0x10, 0x00, 0x80, 0x00, 0x01, 0x04, 0x08, 0x10, 0x00, 0x80, 0x00, + 0x00, 0x04, 0x08, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x10, + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x04, 0xe0, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x04, 0x00, 0x07, 0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, + 0x80, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x20, 0x00, 0x80, 0x00, 0x01, 0x04, + 0x00, 0x20, 0x00, 0x40, 0x00, 0x01, 0x04, 0x10, 0x20, 0x00, 0x40, 0x00, + 0x01, 0x04, 0x08, 0x20, 0x00, 0x40, 0x80, 0x00, 0x04, 0x08, 0x10, 0x00, + 0xc0, 0x60, 0x20, 0x84, 0x18, 0x08, 0x00, 0x00, 0x3f, 0xc0, 0x7f, 0xe0, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x5e, 0xfa, 0x00, 0x00, 0x00, 0x82, + 0x19, 0xa1, 0x8d, 0x00, 0x00, 0x00, 0x82, 0x80, 0x21, 0x84, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x21, 0x84, 0x00, 0x00, 0x00, 0x82, 0x40, 0x21, 0x84, + 0x00, 0x00, 0x00, 0xc2, 0x20, 0x21, 0x84, 0x20, 0x00, 0x00, 0xa2, 0x10, + 0x21, 0x84, 0x30, 0x00, 0x20, 0x15, 0x09, 0x21, 0x85, 0x11, 0x00, 0xc0, + 0x08, 0x07, 0x1e, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x03}; diff --git a/xsis/xastg.c b/xsis/xastg.c new file mode 100644 index 0000000..0d5687d --- /dev/null +++ b/xsis/xastg.c @@ -0,0 +1,211 @@ +/* -------------------------------------------------------------------------- *\ + xastg.c -- defines astg shell. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/xastg.c,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. +\* -------------------------------------------------------------------------- */ + +#include "xsis.h" +#include "NetPlot.h" + +#define XSIS_ASTG "astg" + +typedef struct xastg_info { + Widget shell; /* Top shell for xastg window. */ + Widget plot; /* NetPlot widget of astg. */ + Widget label; /* Label widget for feedback. */ + String geom; /* Initial geometry string. */ +} xastg_info; + + +static void stnplot_read (info) +xastg_info* info; +{ + np_node *node, *fanout; + np_arc *arc; + char buffer[250]; + float x,y; + Boolean is_itrans, is_place; + + while (xsis_get_token (buffer,sizeof(buffer)) != EOF) { + + if (!strcmp(buffer,".geometry")) { + xsis_get_token (buffer,sizeof(buffer)); + info->geom = XtNewString(buffer); + } + else if (!strcmp(buffer,".strans")) { + xsis_get_token(buffer,sizeof(buffer)); + node = np_find_node (info->plot,buffer,True); + if (node == NULL) continue; + xsis_get_token(buffer,sizeof(buffer)); + fanout = np_find_node (info->plot,buffer,True); + if (fanout == NULL) continue; + xsis_get_token(buffer,sizeof(buffer)); + np_create_arc (node,fanout,buffer); + } + else if (!strcmp(buffer,".place") || !strcmp(buffer,".state")) { + is_place = !strcmp(buffer,".place"); + xsis_get_token(buffer,sizeof(buffer)); + node = np_find_node (info->plot,buffer,True); + if (node == NULL) continue; + np_set_shape (node,np_ellipse); + if (is_place) np_set_label (node," "); + while (xsis_get_token(buffer,sizeof(buffer)) == '\0') { + fanout = np_find_node (info->plot,buffer,True); + if (fanout) np_create_arc (node,fanout,NULL); + } + } + else if (!strcmp(buffer,".itrans") || !strcmp(buffer,".otrans")) { + is_itrans = !strcmp(buffer,".itrans"); + xsis_get_token(buffer,sizeof(buffer)); + node = np_find_node (info->plot,buffer,True); + if (node == NULL) continue; + np_set_shape (node,(is_itrans)?np_itrans:np_otrans); + while (xsis_get_token(buffer,sizeof(buffer)) == '\0') { + fanout = np_find_node (info->plot,buffer,True); + if (fanout) np_create_arc (node,fanout,NULL); + } + } + else if (!strcmp(buffer,".posn")) { + xsis_get_token(buffer,sizeof(buffer)); + node = np_find_node (info->plot,buffer,True); + if (node == NULL) continue; + xsis_get_token(buffer,sizeof(buffer)); + sscanf(buffer,"%f",&x); + xsis_get_token(buffer,sizeof(buffer)); + sscanf(buffer,"%f",&y); + np_set_position (node,x,y); + } + else if (!strcmp(buffer,".edge")) { + xsis_get_token(buffer,sizeof(buffer)); + node = np_find_node (info->plot,buffer,True); + if (node == NULL) continue; + xsis_get_token(buffer,sizeof(buffer)); + fanout = np_find_node (info->plot,buffer,True); + if (fanout == NULL) continue; + while (xsis_get_token(buffer,sizeof(buffer)) == '\0') { + arc = np_find_arc (node,fanout); + if (arc == NULL) break; + if (sscanf(buffer,"%f,%f",&x,&y) == 2) { + node = np_insert_bend (arc); + np_set_position (node,x,y); + } + } + } + + xsis_eat_line (); + } +} + +static void xastg_hilite (closure) +XtPointer closure; +{ + /* Read array of nodes to highlight as a path. */ + + xastg_info *info = (xastg_info*) closure; + char *buffer = xsis_world.buffer; + int buflen = xsis_world.buflen; + Boolean on = True; + np_node *node, *fanin; + np_arc *arc; + + while (xsis_get_token (buffer,buflen) != EOF) { + + if (!strcmp(buffer,".nodes")) { + while (xsis_get_token (buffer,buflen) == '\0') { + if ((node = np_find_node (info->plot,buffer,False)) != NULL) { + np_highlight_node (node,on); + } + } + } + else if (!strcmp(buffer,".path")) { + fanin = NULL; + while (xsis_get_token (buffer,buflen) == '\0') { + node = np_find_node (info->plot,buffer,False); + if (node == NULL) break; + np_highlight_node (node,on); + if (fanin != NULL) { + arc = np_find_arc (fanin,node); + np_highlight_arc (arc,True); + } + fanin = node; + } + } + else if (!strcmp(buffer,".clear")) { + xsis_get_token (buffer,buflen); + np_new_highlight (info->plot,buffer); + } + + xsis_eat_line (); + } +} + +static void free_astg (w, closure, call_data) +Widget w; /* ARGSUSED */ +XtPointer closure; /*u xastg_info. */ +XtPointer call_data; /* ARGSUSED */ +{ + /* Called when an xastg window is destroyed. */ + + xastg_info *info = (xastg_info*) closure; + xfree (info->geom); +} + +static void change_label (w, closure, call_data) +Widget w; /* ARGSUSED */ +XtPointer closure; /*u xastg_info. */ +XtPointer call_data; /*i selection data. */ +{ + /* Called whenever plot selection changes. */ + + xastg_info *info = (xastg_info*) closure; + NetPlotSelectData *data = (NetPlotSelectData*) call_data; + XtVaSetValues (info->label,XtNlabel,data->select_name,NULL); +} + +static xsis_cmds xastg_cmd_list[] = { + { "highlight", xastg_hilite }, + { NULL } +}; + +void xastg_new (closure) +XtPointer closure; +{ + xsis_info *world = &xsis_world; + String title = (String) closure; + xastg_info *info = XtNew (xastg_info); + Widget paned, btnbox, closeme; + + info->shell = XtVaCreatePopupShell (title,topLevelShellWidgetClass, + world->app_shell,NULL); + + info->geom = NULL; + paned = xvwidget ("astgPane",panedWidgetClass, info->shell, NULL); + btnbox = xvwidget ("box",boxWidgetClass, paned, NULL); + closeme = xvwidget ("close",commandWidgetClass, btnbox, NULL); + + info->label = xvwidget ("label",labelWidgetClass, btnbox, NULL); + XtVaSetValues (info->label,XtNlabel,title,NULL); + + info->plot = xvwidget ("stnPlot", netPlotWidgetClass, paned, NULL); + np_set_title (info->plot, title); + np_orient (info->plot, 1); + stnplot_read (info); + + XtAddCallback (closeme,XtNcallback,xsis_close_window,(XtPointer)info->shell); + XtAddCallback (info->plot,XtNselectCallback,change_label,(XtPointer)info); + XtAddCallback (info->shell,XtNdestroyCallback,free_astg,(XtPointer)info); + + if (info->geom) XtVaSetValues (info->shell,XtNgeometry,info->geom,NULL); + + xsis_add_shell (title,info->shell,XSIS_ASTG,xastg_cmd_list,(XtPointer)info); +} diff --git a/xsis/xblif.c b/xsis/xblif.c new file mode 100644 index 0000000..61485b7 --- /dev/null +++ b/xsis/xblif.c @@ -0,0 +1,399 @@ +/* -------------------------------------------------------------------------- *\ + xblif.c -- Handles "blif" shells. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/xblif.c,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. +\* -------------------------------------------------------------------------- */ + +#include "xsis.h" +#include "NetPlot.h" +#include "blif50.px" + +#define XSIS_BLIF "blif" + +typedef struct xblif_button { + Widget command; /* Command widget. */ + String group; /* Command group. */ + String sis_cmd; /* Associated sis command. */ + Boolean use_nodes; /* Replace %s with selection? */ + String help_text; /* Description of command. */ +} xblif_button; + +typedef struct xblif_info { + Widget shell; /* Top shell for xblif window. */ + Widget label; /* Label widget for feedback. */ + Widget plot; /* NetPlot widget of network. */ + String geom; /* Initial geometry string. */ + String label_text; /* To restore after help msgs. */ + Widget button_box; /* Box for extra buttons. */ + lsList buttons; /* List of additional buttons. */ +} xblif_info; + + +#define xblif_foreach_button(info,gen,button) \ + for (gen=lsStart((info)->buttons); \ + (lsNext(gen, (lsGeneric *) &(button), LS_NH) == LS_OK) \ + || ((void) lsFinish(gen), 0); ) + + +static void xblif_relabel (info,s) +xblif_info* info; +String s; +{ + if (info->label_text != NULL) xfree (info->label_text); + info->label_text = XtNewString(s); + XtVaSetValues (info->label,XtNlabel,info->label_text,NULL); +} + +static np_node* netplot_add_pi (w,name) +Widget w; +char *name; +{ + np_node *node = np_find_node (w,name,True); + np_set_shape (node,np_ellipse); + np_set_node_color (node,2); + return node; +} + +static np_node* netplot_add_latch (w,name) +Widget w; +char *name; +{ + np_node *node = np_find_node (w,name,True); + np_set_shape (node,np_textblock); + return node; +} + +static np_node* netplot_add_po (w,name) +Widget w; +char *name; +{ + np_node *node = np_find_node (w,name,True); + np_set_shape (node,np_ellipse); + np_set_node_color (node,3); + return node; +} + +static void netplot_read_blif (info) +xblif_info *info; +{ + char buffer[180], buffer2[180]; + char arrow_name[100]; + np_node *node, *latch, *fanin; + Widget plot = info->plot; + int i; + + while (xsis_get_token (buffer,sizeof(buffer)) != EOF) { + + if (!strcmp(buffer,".geometry")) { + xsis_get_token (buffer,sizeof(buffer)); + info->geom = XtNewString(buffer); + } + else if (!strcmp(buffer,".model")) { + xsis_get_token (buffer,sizeof(buffer)); + xblif_relabel (info,buffer); + np_set_title (plot,buffer); + } + else if (!strcmp(buffer,".inputs")) { + while (xsis_get_token(buffer,sizeof(buffer)) == '\0') { + netplot_add_pi (plot,buffer); + } + } + else if (!strcmp(buffer,".latch")) { + xsis_get_token (buffer,sizeof(buffer)); + xsis_get_token (buffer2,sizeof(buffer2)); + node = netplot_add_po (plot,buffer); + sprintf(arrow_name,"to %s", buffer2); + latch = netplot_add_latch (plot,arrow_name); + np_create_arc (node,latch,NULL); + node = netplot_add_pi (plot,buffer2); + sprintf(arrow_name,"from %s", buffer); + latch = netplot_add_latch (plot,arrow_name); + np_create_arc (latch,node,NULL); + } + else if (!strcmp(buffer,".outputs")) { + while (xsis_get_token(buffer,sizeof(buffer)) == '\0') { + netplot_add_po (plot,buffer); + } + } + else if (!strcmp(buffer,".node") + || !strcmp(buffer,".names")) { + for (i=1; xsis_get_token(buffer,sizeof(buffer)) == '\0'; i++) { + fanin = np_find_node (plot,buffer,TRUE); + if (i == 1) { + node = fanin; + } else { + np_create_arc (fanin,node,NULL); + } + } + } + else if (!strcmp(buffer,".label")) { + xsis_get_token (buffer,sizeof(buffer)); + node = np_find_node (plot,buffer,TRUE); + xsis_get_token (buffer,sizeof(buffer)); + if (node != NULL) np_set_label (node,buffer); + } + else if (xsis_world.debug) { + printf("xblif: ignored %s\n",buffer); + } + xsis_eat_line (); + } +} + +static void +HelpLabel (w,event,params,n_params) +Widget w; /*i button widget. */ +XEvent *event; /* ARGSUSED */ +String *params; /* ARGSUSED */ +Cardinal *n_params; /* ARGSUSED */ +{ + xblif_info *info = (xblif_info*) xsis_shell_info (w); + xblif_button *button; + lsGen gen; + if (info == NULL) return; + + xblif_foreach_button (info,gen,button) { + if (button->command == w) { + XtVaSetValues (info->label,XtNlabel,button->help_text,NULL); + break; + } + } +} + +static void +ResetLabel (w,event,params,n_params) +Widget w; /*i button widget. */ +XEvent *event; /* ARGSUSED */ +String *params; /* ARGSUSED */ +Cardinal *n_params; /* ARGSUSED */ +{ + xblif_info *info = (xblif_info*) xsis_shell_info (w); + + if (info == NULL) return; + XtVaSetValues (info->label,XtNlabel,info->label_text,NULL); +} + +static void xblif_replace (closure) +XtPointer closure; +{ + /* Replace the network in an existing blif window. */ + + xblif_info *info = (xblif_info*) closure; + + np_clear_plot (info->plot); + netplot_read_blif (info); + np_autoplace (info->plot); +} + +static void xblif_label (closure) +XtPointer closure; +{ + /* Allow relabelling of nodes in the xblif window. */ + + xblif_info *info = (xblif_info*) closure; + + netplot_read_blif (info); + np_autoplace (info->plot); + np_redraw (info->plot,NULL,True); +} + +static void do_blif_cmd (w, closure, call_data) +Widget w; /* ARGSUSED */ +XtPointer closure; /*u xblif_info. */ +XtPointer call_data; /*i selection data. */ +{ + /* Callback to execute sis command for a button. */ + + xblif_button *button = (xblif_button*) closure; + xsis_execute (button->sis_cmd,False); +} + +static void clear_group (info,group) +xblif_info* info; +String group; +{ + lsGen gen; + xblif_button *button; + + xblif_foreach_button (info,gen,button) { + if (!strcmp(button->group,group)) { + XtDestroyWidget (button->command); + xfree (button->group); + xfree (button->sis_cmd); + xfree (button->help_text); + lsDelBefore (gen, (lsGeneric*)&button); + } + } +} + +static void add_button (info,w,button) +xblif_info* info; +Widget w; +xblif_button* button; +{ + /* Set translation on command-line object. */ + + static char defaultTranslations[] = "#override\n\ + <EnterWindow>: highlight() HelpLabel() \n\ + <LeaveWindow>: reset() ResetLabel()"; + XtTranslations my_translations = + XtParseTranslationTable(defaultTranslations); + + button->command = w; + XtOverrideTranslations (button->command, my_translations); + lsNewEnd (info->buttons, (lsGeneric)button, LS_NH); +} + +static void xblif_hilite (closure) +XtPointer closure; +{ + /* Read array of nodes to highlight as a path. */ + + xblif_info *info = (xblif_info*) closure; + char *buffer = xsis_world.buffer; + int buflen = xsis_world.buflen; + Boolean on = True; + np_node *node; + xblif_button *button; + int n_buttons = 0; + + while (xsis_get_token (buffer,buflen) != EOF) { + + if (!strcmp(buffer,".nodes")) { + while (xsis_get_token (buffer,buflen) == '\0') { + if ((node = np_find_node (info->plot,buffer,False)) != NULL) { + np_highlight_node (node,on); + } + } + } + else if (!strcmp(buffer,".clear")) { + xsis_get_token (buffer,buflen); + np_new_highlight (info->plot,buffer); + } + else if (!strcmp(buffer,".command")) { + /* .command \t group \t sis command \t label \t help \n */ + button = xalloc (xblif_button,1); + xsis_get_token (buffer,buflen); + button->group = XtNewString (buffer); + if (n_buttons++ == 0) clear_group (info,buffer); + xsis_get_token (buffer,buflen); + button->sis_cmd = XtNewString (buffer); + xsis_get_token (buffer,buflen); + button->command = xvwidget (buffer, commandWidgetClass, + info->button_box, NULL); + add_button (info,button->command,button); + xsis_get_token (buffer,buflen); + button->help_text = XtNewString (buffer); + XtAddCallback (button->command, XtNcallback, do_blif_cmd, (XtPointer) button); + } + xsis_eat_line (); + } +} + +static void free_blif (w, closure, call_data) +Widget w; /* ARGSUSED */ +XtPointer closure; /*u xblif_info. */ +XtPointer call_data; /* ARGSUSED */ +{ + /* Called when a blif window is destroyed. */ + + xblif_info *info = (xblif_info*) closure; + + xfree (info->geom); + xfree (info->label_text); + lsDestroy (info->buttons, NULL); +} + +static void change_label (w, closure, call_data) +Widget w; /* ARGSUSED */ +XtPointer closure; /*u xblif_info. */ +XtPointer call_data; /*i selection data. */ +{ + /* Called whenever plot selection changes. */ + + xblif_info *info = (xblif_info*) closure; + NetPlotSelectData *data = (NetPlotSelectData*) call_data; + xblif_relabel (info,data->select_name); +} + +static xsis_cmds xblif_cmd_list[] = { + { "replace", xblif_replace }, + { "label", xblif_label }, + { "highlight", xblif_hilite }, + { NULL } +}; + +static XtActionsRec xblif_actions[] = { /* Actions table. */ + {"HelpLabel", HelpLabel}, + {"ResetLabel", ResetLabel} +}; + + +void xblif_new (closure) +XtPointer closure; +{ + /* Read a network description in BLIF format and use a NetPlot + widget to display it. */ + + xsis_info *world = &xsis_world; + String title = (String) closure; + xblif_info* info = XtNew (xblif_info); + Widget paned, btnbox, closeme; + Pixmap icon_px; + static Boolean added_actions = False; + + if (!added_actions) { + XtAppAddActions (xsis_world.app_context,xblif_actions,XtNumber(xblif_actions)); + added_actions = True; + } + + icon_px = XCreateBitmapFromData ( + XtDisplay(world->app_shell), + RootWindowOfScreen(XtScreen(world->app_shell)), + blif50_bits,blif50_width,blif50_height); + + info->label_text = NULL; + info->geom = NULL; + info->shell = XtVaCreatePopupShell ( + title,topLevelShellWidgetClass, world->app_shell, + XtNiconPixmap,icon_px, + NULL); + + paned = xvwidget ("blifPane",panedWidgetClass, info->shell, NULL); + btnbox = xvwidget ("box",boxWidgetClass, paned, NULL); + info->button_box = btnbox; + info->buttons = lsCreate(); + closeme = xvwidget ("close",commandWidgetClass, btnbox, NULL); + + info->label = xvwidget ("label",labelWidgetClass, paned, NULL); + xblif_relabel (info,title); + + info->plot = xvwidget ("netPlot", netPlotWidgetClass, paned, NULL); + netplot_read_blif (info); + if (info->geom) XtVaSetValues (info->shell,XtNgeometry,info->geom,NULL); + np_autoplace (info->plot); + + { xblif_button* button = xalloc (xblif_button,1); + lsNewEnd (info->buttons, (lsGeneric)button, LS_NH); + button->group = XtNewString(""); + button->help_text = XtNewString("Close plot window."); + button->sis_cmd = NULL; + add_button (info,closeme,button); + } + + XtAddCallback (closeme,XtNcallback,xsis_close_window,(XtPointer)info->shell); + + XtAddCallback (info->plot,XtNselectCallback,change_label,(XtPointer)info); + XtAddCallback (info->shell,XtNdestroyCallback,free_blif,(XtPointer)info); + + xsis_add_shell (title,info->shell,XSIS_BLIF,xblif_cmd_list,(XtPointer)info); +} diff --git a/xsis/xcmd.c b/xsis/xcmd.c new file mode 100644 index 0000000..6b732f2 --- /dev/null +++ b/xsis/xcmd.c @@ -0,0 +1,468 @@ +/* -------------------------------------------------------------------------- *\ + xcmd.c -- shell for command interface to sis. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/xcmd.c,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. + + This handles the application shell which is the main top level shell of + xsis. It is set up exactly like any other shell, except that it uses + world->app_shell for its shell instead of creating a new popup shell. + The version number defined below is appended to the displayed icon name. +\* -------------------------------------------------------------------------- */ + +#include "xsis.h" + +#define XSIS_VERSION " 1.1" +#define XSIS_CMD "cmd" + + +typedef struct xcmd_info { /* Info for command shell. */ + Widget shell; /* Command shell. */ + Widget version; /* Version label widget. */ +} xcmd_info; + + +static Widget g_textout = NULL; +static int caret_posn = 0; + +static String xcmd_do_special (p) +String p; +{ + XawTextBlock new_text; + XawTextPosition pos; + + if (p == NULL) return NULL; + + if (*p == '\015') { + /* Try to clear the current line. */ + new_text.firstPos = 0; + new_text.length = 1; + new_text.ptr = "\n"; + new_text.format = FMT8BIT; + XawTextSetInsertionPoint (g_textout,32765); + pos = XawTextSearch (g_textout, XawsdLeft,&new_text); + if (pos != XawTextSearchError) { + caret_posn = pos + 1; + } + p++; + } else if (*p == '\010') { + /* Try to delete the previous character. */ + if (caret_posn > 1) { + new_text.firstPos = 0; + new_text.length = 0; + new_text.ptr = ""; + new_text.format = FMT8BIT; + XawTextReplace (g_textout,caret_posn-1,caret_posn,&new_text); + caret_posn -= 1; + } + p++; + } else { + new_text.firstPos = 0; + new_text.length = 1; + new_text.ptr = "?"; + new_text.format = FMT8BIT; + XawTextReplace (g_textout,caret_posn,caret_posn+1,&new_text); + caret_posn++; + p++; + } + + return p; +} + +void xcmd_puts (str) +String str; +{ + /* Append text to the global textout widget. Does not add a + newline automatically. */ + + XawTextBlock new_text; + String s = str, p; + + if (str == NULL) return; + + if (g_textout == NULL) { + fputs (str,stdout); + return; + } + + while (s != NULL && *s != '\0') { + p = strpbrk (s,"\007\010\015"); + /* Insert regular text. */ + new_text.firstPos = 0; + new_text.length = (p==NULL) ? strlen(s) : (p-s); + new_text.ptr = s; + new_text.format = FMT8BIT; + XawTextReplace (g_textout,caret_posn,caret_posn+new_text.length,&new_text); + caret_posn += new_text.length; + /* Handle special character sequences. */ + s = xcmd_do_special (p); + } + + XawTextDisplayCaret (g_textout,False); + /* This is necessary to scroll the bottom to be visible. */ + XawTextSetInsertionPoint (g_textout,32765); +} + +static void print_file_list (w,filec) +Widget w; +xsis_filec* filec; +{ + /* Print a list of the files the same as csh does for file completion. */ + + String name, p; + int i, j, k, width, len, max_len, n_col, n_row, n_full_row, elem_n; + char buffer[80]; + XFontStruct *font; + Dimension swide; + + xcmd_puts ("\n"); + if (array_n(filec->filenames) == 0) { + xcmd_puts (xsis_get_flag("prompt")); + return; + } + + XtVaGetValues (w, XtNwidth,&swide, XtNfont,&font, NULL); + width = swide / font->max_bounds.width; + /* Add two for inter-item spacing, and allow for scroll bar in text. */ + max_len = xsis_string_array_len (filec->filenames) + 2; + + n_col = width/(max_len+1); + if (n_col == 0) n_col = 1; + n_row = (array_n(filec->filenames)+n_col-1) / n_col; + n_col = (array_n(filec->filenames)+n_row-1) / n_row; + n_full_row = array_n(filec->filenames) % n_row; + if (n_full_row == 0) n_full_row = n_row; + + for (i=0; i < n_row; i++) { + if (i == n_full_row) n_col--; + elem_n = i; + for (j=1; j <= n_col; j++) { + name = array_fetch(String,filec->filenames,elem_n); + strcat(strcpy(buffer,name), xsis_file_type(filec,elem_n)); + if (j == n_col) { + strcat(buffer,"\n"); + } else { + len = strlen(buffer); + p = buffer + strlen(buffer); + for (p=buffer+len,k=max_len-len; k--; p++) *p = ' '; + *p = '\0'; + } + xcmd_puts(buffer); + elem_n += n_row; + } + } + + xcmd_puts (xsis_get_flag("prompt")); +} + +static void do_file_completion (w,filec) +Widget w; +xsis_filec* filec; +{ + /* Complete the maximum common prefix of all the given names. */ + + XawTextBlock tblock; + String name; + int len, pos; + + len = strlen(filec->partial); + pos = xsis_string_array_prefix (filec->filenames); + if (pos-len > 0) { + name = array_fetch(String,filec->filenames,0); + tblock.firstPos = len; + tblock.length = pos - len; + tblock.ptr = name; + tblock.format = FMT8BIT; + XawTextReplace (w,32765,32765,&tblock); + XawTextSetInsertionPoint (w,32765); + } + if (array_n(filec->filenames) != 1) XBell (xsis_world.display,0); +} + +static void FileCompletion (w,list_only) +Widget w; +int list_only; +{ + /* Do file completion for text widget w. If list_only, then + print all files matching, otherwise try to complete the name. */ + + String str, last_word; + xsis_filec *filec; + + XtVaGetValues (w, XtNstring,&str, NULL); + if (str == NULL) return; + + /* Back up to the start of the last ``word''. */ + last_word = str + strlen(str) - 1; + for (last_word=str+strlen(str)-1; last_word > str; last_word--) { + if (strchr(" \t\n;",*last_word) != NULL) { + last_word++; + break; + } + } + + /* Allow for file names as part of a command option. */ + if (last_word[0] == '-' && last_word[1] != '\0') last_word += 2; + + filec = xsis_file_completion (last_word,False); + + if (filec == NULL) { + XBell (xsis_world.display,0); + } else if (list_only) { + print_file_list (w,filec); + } else { + do_file_completion (w,filec); + } + + xsis_free_filec (filec); +} + +static void special_action (w,action) +Widget w; +String action; +{ + /* Do a single special action for a command buffer such as file + completion, kill or interrupt. */ + + XawTextBlock tblock; + char special[3]; + String buffer; + + if (!strcmp(action,"enter")) { /* Send buffer as is. */ + XawTextSetInsertionPoint (w,0); + XtVaGetValues (w, XtNstring,&buffer, NULL); + xsis_execute (buffer,False); + XtVaSetValues (w, XtNstring,"", NULL); + } + else if (!strcmp(action,"intr")) { /* Interrupt sis (^C). */ + /* Send interrupt signal to sis child. */ + xsis_intr_child(); + } + else if (!strcmp(action,"eof")) { /* Send EOF char to sis. */ + special[0] = xsis_pty_eof_char (xsis_world.sis_pty); + special[1] = '\0'; + xsis_execute (special,True); + } + else if (!strcmp(action,"filel")) { /* File list. */ + /* Do file completion on a partial string. */ + XtVaGetValues (w, XtNstring,&buffer, NULL); + FileCompletion (w,True); + } + else if (!strcmp(action,"filec")) { /* File completion. */ + FileCompletion (w,False); + } + else if (!strcmp(action,"kill")) { /* Clear buffer. */ + XtVaSetValues (w, XtNstring,"", NULL); + } + else if (action[0] == '+') { /* Insert literal in buffer. */ + tblock.firstPos = 1; + tblock.length = strlen(action+1); + if (action[tblock.length] == '+') tblock.length--; + tblock.ptr = action; + tblock.format = FMT8BIT; + XawTextReplace (w,32765,32765,&tblock); + XawTextSetInsertionPoint (w,32765); + } + else if (strcmp(action,"no-op")) { /* Do absolutely nothing. */ + fprintf(stderr,"EnterCmd: unknown argument \"%s\".\n",action); + } +} + +static void EnterCmd (w,event,params,n_params) +Widget w; +XEvent* event; +String* params; +Cardinal* n_params; +{ + /* Action procedure for entering a new command. Send any text in the + command widget, followed by optional command as argument. See + special_action() above for the list of recognized parameters. + Parameter zero is what to do if the buffer is empty. Parameters + one and up are what to do if the buffer is nonempty. */ + + /* ARGSUSED */ + String str; + int i; + + XtVaGetValues (w, XtNstring,&str, NULL); + if (str == NULL) return; /* Maybe not a text widget? */ + + if (strlen(str) == 0) { + if (*n_params >= 1) special_action (w,params[0]); + } else { + for (i=1; i < *n_params; i++) { + special_action (w,params[i]); + } + } +} + +static void CmdChanged (w,text_ptr,call_data) +Widget w; +XtPointer text_ptr; +XtPointer call_data; +{ + /* This gets called for every potential change in the text. */ + + /* ARGSUSED */ + Widget cmdline = (Widget) text_ptr; + String str; + + XtVaGetValues (cmdline, XtNstring,&str, NULL); + /* Could also do command completion, etc. here. */ +/* + if (xsis_icanon_disabled (xsis_world.sis_pty)) { + xsis_execute (str,True); + XtVaSetValues (w, XtNstring,"", NULL); + } + */ +} + +static void ClearText (w,text_ptr,call_data) +Widget w; +XtPointer text_ptr; +XtPointer call_data; +{ + /* Clear all text out of the text widget. */ + + /* ARGSUSED */ + Widget text = (Widget) text_ptr; + XtVaSetValues (text, XtNstring,"", NULL); + if (xsis_world.child_status == XSIS_IDLE) { + xcmd_puts (xsis_get_flag("prompt")); + } +} + +static void Quit (widget,closure,callData) +Widget widget; +XtPointer closure; +XtPointer callData; +{ + /* ARGSUSED */ + xsis_execute ("quit",False); +} + +static void ShowHelp (w,closure,call_data) +Widget w; +XtPointer closure; +XtPointer call_data; +{ + /* Open help shell if it isn't already. */ + + /* ARGSUSED */ + xhelp_popup ("help",NULL,False); +} + +static void do_version (info) +xcmd_info* info; +{ + /* Read version string and set main window label. */ + + char *p, buffer[100]; + char hostname[128]; + + while (xsis_get_token(buffer,sizeof(buffer)) != EOF) { + if (!strcmp(buffer,".version")) { + xsis_get_token(buffer,sizeof(buffer)); + p = strchr (buffer,'('); + if (p != NULL && p > buffer) *(p-1) = '\0'; + if (gethostname(hostname,sizeof(hostname)) == 0) { + p = strchr(hostname,'.'); + if (p != NULL && p != hostname) *p = '\0'; + p = buffer + strlen(buffer); + sprintf(p," (%s)",hostname); + } + if (info != NULL) { + XtVaSetValues (info->version, XtNlabel,buffer, NULL); + } + } + else if (xsis_world.debug) { + xsis_dump_string("xcmd ignored",buffer); + } + xsis_eat_line (); + } +} + +static XtActionsRec cmd_actions[] = { /* Actions table. */ + {"EnterCmd", EnterCmd} +}; + +static xsis_cmds xcmd_cmds[] = { + { NULL } +}; + +void xcmd_new (closure) +XtPointer closure; +{ + /* Special shell which uses world->app_shell as its shell. */ + + xsis_info *world = &xsis_world; + String title = (String) closure; + String new_title; + Widget source, quit, help, clear, textout, cmdline, box, paned; + xcmd_info *info; + char buffer[128]; + + if (g_textout != NULL) { /* Never allow two command shells. */ + do_version (NULL); + return; + } + + info = XtNew(xcmd_info); + info->shell = world->app_shell; + + /* Append the RCS version number to the window title/icon name. */ + XtVaGetValues (info->shell, XtNiconName, &new_title, NULL); + strcat(strcpy(buffer,new_title), XSIS_VERSION); + XtVaSetValues (info->shell, XtNiconName, buffer, NULL); + XtVaSetValues (info->shell, XtNtitle, buffer, NULL); + + XtAppAddActions (world->app_context,cmd_actions,XtNumber(cmd_actions)); + + paned = xvwidget ("paned",panedWidgetClass, info->shell, NULL); + + box = xvwidget ("box",boxWidgetClass, paned, NULL); + quit = xvwidget ("quit", commandWidgetClass, box, NULL); + help = xvwidget ("help", commandWidgetClass, box, NULL); + clear = xvwidget ("clear",commandWidgetClass, box, NULL); + + info->version = xvwidget ("version",labelWidgetClass, box, NULL); + + cmdline = xvwidget ("cmdline",asciiTextWidgetClass, paned, NULL); + + {/* Set command-line height to font height. */ + XFontStruct *font; + int height; + XtVaGetValues (cmdline,XtNfont,&font,NULL); + height = font->ascent + font->descent + 6; + XtVaSetValues (cmdline,XtNpreferredPaneSize,height,NULL); + } + + textout = xvwidget ("textout",asciiTextWidgetClass, paned, NULL); + g_textout = textout; + + /* Now add callbacks since all widgets are created. */ + + XtVaGetValues (cmdline,XtNtextSource,&source,NULL); + XtAddCallback (source, XtNcallback, CmdChanged, (XtPointer) cmdline); + + XtAddCallback (quit, XtNcallback, Quit, (XtPointer) info->shell); + XtAddCallback (help, XtNcallback, ShowHelp, (XtPointer) world); + XtAddCallback (clear, XtNcallback, ClearText, (XtPointer) textout); + XtSetKeyboardFocus (paned,cmdline); + + /* Allow events in textout (dest) to invoke actions in cmdline (source). */ + XtInstallAccelerators (textout,cmdline); + + do_version (info); + + xsis_add_shell (title,info->shell,XSIS_CMD,xcmd_cmds,(XtPointer)info); +} diff --git a/xsis/xhelp.c b/xsis/xhelp.c new file mode 100644 index 0000000..e573f76 --- /dev/null +++ b/xsis/xhelp.c @@ -0,0 +1,280 @@ +/* -------------------------------------------------------------------------- *\ + xhelp.c -- do "help" shell. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/xhelp.c,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. + + We read the file ourselves because the asciiText widget just exits if + it cannot find the file, and it also does not handle ^H well. +\* -------------------------------------------------------------------------- */ + +#include "xsis.h" +#include "NetPlot.h" +#include "help50.px" + +#define XSIS_HELP "help" +#define HELP_SUFFIX "fmt" + +typedef struct TextBlock { + String text; /* Allocated text string. */ + int n_byte; /* strlen of current string. */ + int n_alloc; /* Allocated size of string. */ +} TextBlock; + +typedef struct xhelp_info { + Widget shell; + Widget text; + Widget label; + TextBlock help_text; + String *topics; + int show_all; +} xhelp_info; + +static xhelp_info *help_opened = NULL; + +static void TextBlockClear (text) +TextBlock* text; +{ + text->n_byte = 0; + *text->text = '\0'; +} + +static void TextBlockInit (text) +TextBlock* text; +{ + /* Start with some memory and an empty string. */ + text->n_alloc = 2048; + text->text = xalloc (char,text->n_alloc); + text->n_byte = 0; + *text->text = '\0'; +} + +static void TextBlockFree (text) +TextBlock* text; +{ + XFree (text->text); +} + +static void TextBlockCat (text,s) +TextBlock* text; +String s; +{ + /* Concatenate a string to the text block. First reallocate enough + memory, then copy the string in, handling backspace appropriately. */ + + int max_len = text->n_byte+strlen(s)+1; + String p; + int c; + + if (max_len >= text->n_alloc) { + text->n_alloc *= 2; + if (text->n_alloc < max_len) text->n_alloc = max_len; + text->text = xrealloc (char,text->text,text->n_alloc); + } + + for (p=text->text+text->n_byte; (c=(*s)) != '\0'; s++) { + if (c == '\010') { + if (p != text->text) p--; + } else { + *(p++) = c; + } + } + + text->n_byte = (p - text->text); + *p = '\0'; +} + +static void CloseHelp (widget,closure,data) +Widget widget; /* ARGSUSED */ +XtPointer closure; /* ARGSUSED */ +XtPointer data; /* ARGSUSED */ +{ + /* Deallocate memory associated with the help window. */ + xhelp_info *info = (xhelp_info*) closure; + String *topic; + + for (topic=info->topics; *topic != NULL; topic++) { + xfree (*topic); + } + TextBlockFree (&info->help_text); + help_opened = NULL; +} + +static void SetHelp (info, topic) +xhelp_info *info; +char *topic; +{ + /* Find and read the help file for the given topic and change the + help shell text to display this file. */ + + FILE *fp; + char *s, *p, *fname, filename[100], buffer[200]; + char *paths = xsis_get_flag ("open_path"); + int len, n_line = 0; + + sprintf(filename,"help/%s.%s",topic,HELP_SUFFIX); + fname = util_file_search (filename,paths,"r"); + TextBlockClear (&info->help_text); + + if (fname == NULL || (fp=fopen(fname,"r")) == NULL) { + sprintf (buffer,"Could not find help file \"%s.fmt\".\n",topic); + TextBlockCat (&info->help_text,buffer); + TextBlockCat (&info->help_text,"Tried directories:\n\n"); + for (p=paths; p != NULL; p=(s)?s+1:NULL) { + s = strchr(p+1,':'); + len = (s == NULL) ? strlen(p) : (s-p); + strcat(strncat(strcpy(buffer," "), p,len), "/help\n"); + TextBlockCat (&info->help_text,buffer); + } + TextBlockCat(&info->help_text, + "\nUse \"set open_path\" to change this list."); + } + else { + /* The first 3 lines of sis help files aren't interesting. */ + while (fgets(buffer,sizeof(buffer),fp) != NULL) { + if (++n_line > 3) TextBlockCat (&(info->help_text),buffer); + } + + fclose (fp); + } + + XtVaSetValues (info->label, XtNlabel,topic, NULL); + XtVaSetValues (info->text, XtNstring,info->help_text.text, + XtNlength, strlen(info->help_text.text), + NULL); + FREE (fname); +} + +static void SetTopic (widget,closure,call_data) +Widget widget; /* ARGSUSED */ +XtPointer closure; /*u Help information struct. */ +XtPointer call_data; /*i List widget information. */ +{ + /* Callback to change help text based on list selection. Can + also use info->list_index for list widgets. */ + + XawListReturnStruct *info = (XawListReturnStruct*) call_data; + SetHelp ((xhelp_info*)closure,info->string); +} + +static xsis_cmds xhelp_cmds[] = { + { NULL } +}; + +void xhelp_popup (topic,geom,show_all) +String topic; +String geom; +int show_all; +{ + /* Create help shell if necessary and set it to given topic. */ + + Widget paned, pane2; + Widget btnbox, closeme, topic_list, topic_view; + Pixmap icon_px; + int n_cmd, i,j; + String sis_topic; + xhelp_info *info; + + if (help_opened != NULL) { + SetHelp (help_opened,topic); + return; + } + + info = XtNew (xhelp_info); + TextBlockInit (&info->help_text); + + icon_px = XCreateBitmapFromData ( + XtDisplay(xsis_world.app_shell), + RootWindowOfScreen(XtScreen(xsis_world.app_shell)), + help50_bits,help50_width,help50_height); + + info->shell = XtVaCreatePopupShell ( + XSIS_HELP,topLevelShellWidgetClass, xsis_world.app_shell, + XtNiconPixmap,icon_px, + XtNiconName, "xsis help", + NULL); + if (geom != NULL) XtVaSetValues (info->shell,XtNgeometry,geom,NULL); + + paned = xvwidget("paned1",panedWidgetClass, info->shell, NULL); + btnbox = xvwidget ("box",boxWidgetClass, paned, NULL); + + pane2 = xvwidget("paned2",panedWidgetClass, paned, + XtNorientation,XtorientHorizontal, + NULL); + + closeme = xvwidget ("close",commandWidgetClass, btnbox, NULL); + info->label = xvwidget ("label",labelWidgetClass, btnbox, NULL); + + topic_view = xvwidget ("topicList",viewportWidgetClass,pane2, + XtNallowVert,True, + NULL); + + /* Create list of topics to choose from. */ + n_cmd = array_n(xsis_world.sis_commands); + info->topics = xalloc (String,n_cmd+1); + for (i=j=0; i < n_cmd; i++) { + sis_topic = array_fetch (String,xsis_world.sis_commands,i); + if (!show_all && sis_topic[0] == '_') continue; + info->topics[j++] = XtNewString(sis_topic); + } + info->topics[j] = NULL; + + topic_list = xvwidget ("list",listWidgetClass,topic_view, + XtNdefaultColumns, 1, + XtNlist, info->topics, + XtNverticalList, True, + XtNforceColumns, True, + NULL); + + info->text = xvwidget ("helpText",asciiTextWidgetClass, pane2, + XtNdisplayCaret, False, + XtNeditType, XawtextRead, + XtNlength, 0, + XtNstring, "", + XtNtype, XawAsciiString, + XtNuseStringInPlace, True, + NULL); + + XtAddCallback (topic_list, XtNcallback, SetTopic, (XtPointer)info); + XtAddCallback (closeme, XtNcallback, xsis_close_window, (XtPointer)info->shell); + XtAddCallback (info->shell, XtNdestroyCallback, CloseHelp, (XtPointer)info); + xsis_add_shell ("help",info->shell,XSIS_HELP,xhelp_cmds,(XtPointer)info); + if (topic != NULL) SetHelp (info,topic); + help_opened = info; +} + +void xhelp_new (closure) +XtPointer closure; /* ARGSUSED */ +{ + /* Read filename and display it as help. */ + + xsis_info *world = &xsis_world; + int show_all = False; + char *geom = NULL; + + while (xsis_get_token(world->buffer,world->buflen) != EOF) { + if (!strcmp(world->buffer,".topic")) { + xsis_get_token(world->buffer,world->buflen); + xhelp_popup (world->buffer,geom,show_all); + } + else if (!strcmp(world->buffer,".all")) { + show_all = True; + } + else if (!strcmp(world->buffer,".geometry")) { + xsis_get_token(world->buffer,world->buflen); + geom = XtNewString (world->buffer); + } + xsis_eat_line (); + } + + xfree (geom); +} diff --git a/xsis/xsis.1 b/xsis/xsis.1 new file mode 100644 index 0000000..c249bde --- /dev/null +++ b/xsis/xsis.1 @@ -0,0 +1,347 @@ +.de Sh +.br +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp +.if t .sp .5v +.if n .sp +.. +.ie n \{\ +.tr \(bs-\*(Tr +.ds -- \(bs- +.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch +.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch +.ds L" "" +.ds R" "" +.ds L' ' +.ds R' ' +'br\} +.el\{\ +.ds -- \(em\| +.tr \*(Tr +.ds L" `` +.ds R" '' +.ds L' ` +.ds R' ' +'br\} +.TH XSIS 1CAD "10 Oct 1991" "" Preliminary +.SH NAME +xsis \- graphical interface to sis based on Athena widget set. +.SH SYNOPSYS +.B xsis +[\fB-sis \fIpathname\fP] +[\fB-debug\fP] +[\fIX Toolkit options...\fP] +.SH DESCRIPTION +\fBxsis\fP is a graphical front-end for +\fBsis\fP, the Berkeley Sequential Interactive +System. +The initial goal of this program is to provide support for the +\fBplot\fP command from earlier versions of \fBsis\fP +in a manner which is portable under the MIT distribution of X11R4. +\fBxsis\fP is based on the Athena widget set and the X Toolkit, +and works with \fBsis\fP versions 1.1 and later. +.PP +\fBxsis\fP runs a copy of \fBsis\fP as a child process. +This means that any ordinary command-line version of \fBsis\fP can +be run under \fBxsis\fP without recompiling anything. +To locate a copy of \fBsis\fP to run, +\fBxsis\fP first searches the directories +specified in the \fB$PATH\fP environment variable. +If there is no executable named ``sis'' there, +it tries the directory that +\fBxsis\fP is located in. +.PP +The widget hierarchy used by \fBxsis\fP +is documented below so you can customize it using X resources. +Notice that the names of some top level windows +depend on what data has been displayed in them (e.g. the network plot windows). +The instance name is shown first followed by the class name in parenthesis. +Although X11 refers to a top level window as a shell, we will loosely +refer to them as windows to avoid confusion with command-line shells +such as csh. +\fBxsis\fP uses multiple top level windows which are described below. + +The \fBsis\fP graphics package file graphics.doc describes +the interface conventions between \fBxsis\fP and \fBsis\fP, +and outlines how to add new graphics features. + +.SH OPTIONS +\fBxsis\fP accepts the following options: + +.TP 4 +\fB-sis \fIpathname\fP +Run specified version of \fBsis\fP instead of searching in the \fBxsis\fP +and \fB$PATH\fP directories. +.TP 4 +\fB-debug\fP +Produce \fBxsis\fP debug output which is both verbose and invaluable when +there are problems. +.TP 4 +\fB-bg \fIcolor\fP +Set the background color for all windows. +.TP 4 +\fB-bd \fIcolor\fP +Set the border color for all windows. +.TP 4 +\fB-bw \fIn\fP +Set the border width to \fIn\fP pixels for all windows. +.TP 4 +\fB-display \fIdisplayname\fP +Use the specified display for all windows. +.TP 4 +\fB-fg \fIcolor\fP +Set the foreground color for all windows. +.TP 4 +\fB-fn \fIfontname\fP +Use specified font in all windows. +Since \fBxsis\fP has multiple windows, it is usually more convenient to +set the font for each window separately using \fB.Xdefaults\fP +as described below. +.TP 4 +\fB-geometry \fIvalue\fP +Set the initial geometry of the command window. +.TP 4 +\fB-name \fIvalue\fP +Use an alternate name for looking up resources in the \fB.Xdefaults\fP file. +.PP +\fBxsis\fP also supports all other standard X Toolkit options, such as +\fB-font\fP and \fB-foreground\fP. + +.SH SIS COMMANDS +When \fBsis\fP is run using the \fBxsis\fP interface, +you can use the following graphics commands. + +.TP 4 +\fBplot_blif [-n \fI<name>\fB] [-g \fI<geom>\fB] [-k] [-i] [-r]\fP +Create a new plot window and display the current network. +.br +.B -n <name> +Specifies the plot window name instead of using the network name. +.br +.B -g <geom> +Give the initial geometry of the window, using the standard X11 +format: WxH+X+Y. +.br +.B -r +Replace the drawing in the last window +created with the same plot name. +.br +.B -k +Kill the last plot with the same plot name. +.br +.B -i +Label the plot with the internal network names used by \fBsis\fP. + +.TP 4 +\fB_speed_plot [-n \fIname\fB] [-c] [-g] [-h] [-t \fIn.n\fB] [-w \fIn.n\fB] [-d \fIn\fB]\fP +Without -h or -c, this adds buttons to the plot window to select either +the critical path or cutset. +.br +.B -n +.I name +Specifies the plot window name instead of using the network name. +.br +.B -c +Highlight the minimum weight cutset. +.br +.B -h +Highlight nodes on a critical path. +.br +.B -g +Label the nodes with their gate names (after technology mapping). +.br +.B -t +.I n.n +Critical threshold. +.br +.B -w +.I n.n +Relative weight of area. +.br +.B -d +.I n +Distance for collapsing. + +.TP 4 +\fBhelp\fP [-g \fI<geom>\fP] \fItopic\fP +Display help for the topic in a separate help window. +Only one help window is ever open, so +repeated help commands just change the topic. + +.SH COMMAND WINDOW +This is the main window where you enter \fBsis\fP commands and view +\fBsis\fP text output. +.sp 1 +.nf + xsis (XSis) + paned (Paned) + box (Box) + quit (Command) + clear (Command) + print (Command) + version (Label) + cmdline (Text) + textout (Text) +.fi +.PP +The command text widget supports several standard control characters: +^D for EOF, ^U for kill, ^C for interrupt, and ^D/ESC for file completion. + +.SH NETWORK PLOT WINDOW +This window is created for each separate network plot you make. +By default it shows the network structure as described by the write_blif +command. +You can display the internal \fBsis\fP network structure by using +\fBplot_blif -i\fP. +For default actions, clicking the left button on a node highlights the +node and its fanins and fanouts. +Clicking the middle button issues a \fBprint\fP command on the node +in the command window. +.sp 1 +.nf + xsis (XSis) + \fInetwork-name\fP (TopLevelShell) + blifPane (Paned) + box (Box) + close (Command) + label (Label) + netPlot (NetPlot) +.fi +.PP +The NetPlot widget supports the following resources: +.sp 1 +.TS +box; +l | l | l | l. +Name Type Default Description +_ +background Pixel white Background color of plot. +foreground1 Pixel black Color of internal nodes. +foreground2 Pixel black Color of PI nodes. +foreground3 Pixel black Color of PO nodes. +foreground4 Pixel black Color of graph edges. +hilight Pixel black Highlighting color for plot. +font FontStruct ? Font for all text in the plot. +_ +.TE +.sp 1 +.PP +There are two defined actions: + +.TP 8 +.B SelectMe () +Highlight a node, its fanins and fanouts. + +.TP 8 +.B NodeCmd ([\fIhit\fB],[\fImiss\fB])\fP +Execute a \fBsis\fP command on a node. +The first \fB%s\fP in the \fIhit\fP parameter is replaced by the +node which was hit before the command is sent to \fBsis\fP. +The \fImiss\fP command is executed if no node was hit by the event. + +.SH HELP WINDOW +The help window is a separate window for displaying \fBsis\fP on-line help. +Only one help window is ever created and each new topic you select +is displayed in this window. +.sp 1 +.nf + xsis help (TopLevelShell) + paned1 (Paned) + box (Box) + close (Command) + label (Label) + paned2 (Paned) + topicList (Viewport) + list (List) + helpText (Text) +.fi +.SH "X DEFAULTS" +Using the above window hierarchies, you can customize \fBxsis\fP +with resources specified in the \fB.Xdefaults\fP file. +To change all pushbuttons to red: +.sp 1 +.nf + XSis*Command*foreground: red +.fi +.sp 1 +To change only the close pushbuttons to red: +.sp 1 +.nf + XSis*close*foreground: red +.fi +.sp 1 +To change the color of PO nodes in all plots to orange: +.sp 1 +.nf + XSis*netPlot.foreground3: orange +.fi +.sp 1 +The resources which most closely match the network plot to the +old \fBplot\fP command in \fBsis\fP: +.sp 1 +.TS +l l. + XSis*netPlot.background: white + XSis*netPlot.foreground1: blue + XSis*netPlot.foreground2: red + XSis*netPlot.foreground3: green + XSis*netPlot.foreground4: black + XSis*netPlot.font: courier10 +.TE +.sp 1 +For a list of other resources which can be changed, see the resource +list at the beginning of file \fBxsis.c\fP, +and the MIT Athena Widgets documentation. + +.SH FILES +.TS +l l. +/projects/sis/sis/common/src/xsis/ - source for xsis +~/.Xdefaults - resources to customize \fBxsis\fP +.TE + +.SH "SEE ALSO" +sis(1CAD) + +.SH DIAGNOSTICS +If you use \fBxsis\fP with a version of \fBsis\fP which does not support +graphics, you will get a message similar to: +.sp 1 +.nf + $ xsis -sis sis1.0 + sis1.0: unknown option X + usage: sis1.0 [-sx] [-c cmd] [-f script] ... +.fi +.sp 1 +.PP +If no directory in your path contains an executable named +\fBsis\fP: +.sp 1 +.nf + $ xsis + xsis: could not find "sis" in your path. +.fi +.sp 1 + +.SH BUGS +Typing \fB^Z\fP in the command window does not interrupt or +suspend the program, +and suspending \fBxsis\fP from the shell only suspends it +and not the associated \fBsis\fP child process. +.PP +The Athena text widget used for the command window display does not support +cursor positioning, so using the \fBsis\fP shell escape (!) with +commands such as \fImore\fP or \fIvi\fP does not work very well. +.PP +Since graphics commands such as plot_blif must be supported by the +underlying version of \fBsis\fP, +they really should be documented there somehow. + +.SH AUTHORS +Paul Stephan +.br +Copyright 1991 by the Regents of the Univerity of California. diff --git a/xsis/xsis.c b/xsis/xsis.c new file mode 100644 index 0000000..ef4544c --- /dev/null +++ b/xsis/xsis.c @@ -0,0 +1,982 @@ +/* -------------------------------------------------------------------------- *\ + xsis.c -- handle special cases of input from sis child process. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/xsis.c,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. + + Primary entry point is xsis_main which creates initial command shell + and handles event loop. + + Special graphics commands come from sis in the form: + + <GRAPHICS-START-MESSAGE> + shelltype \t command \t shellname \n + ..command-specific data.. + <GRAPHICS-END-MESSAGE> + + This makes it possible to survive unrecognized graphics commands. + + Using XrmoptionSkipArg did not work for the -sis option, which is + handled by the driver. So we pretend it is a real resource using + XrmoptionSepArg and then never use it. +\* -------------------------------------------------------------------------- */ + +#include "xsis.h" +#include "NetPlot.h" +#include "ghost.px" +#include "sis50.px" + +#define XSIS_SIS "sis" + +static xsis_cmds window_creators[] = { + /* Type Creator */ + { "cmd", xcmd_new }, + { "help", xhelp_new }, + { "blif", xblif_new }, + { "astg", xastg_new }, + NULL +}; + +static XrmOptionDescRec xsis_options[] = { + {"-debug", "debug", XrmoptionNoArg, "True"}, + {"-sis", ".sis", XrmoptionSepArg, NULL} +}; + +xsis_info xsis_world; /* Global interface data. */ + + +static XtResource app_resources[] = { +#define offset(field) XtOffset(xsis_info*, field) + { "debug", "Debug", XtRBoolean, sizeof(Boolean), + offset(debug), XtRImmediate, (XtPointer) False } +#undef offset +}; + +static String xsis_fallback_resources[] = { + + "XSis.geometry: 820x300", + "XSis*background: grey75", + "XSis*input: True", + "XSis*showGrip: on", + "XSis*font: courier_bold10", + "XSis*Command*background: lightblue", + "XSis*Label*borderWidth: 0", + "XSis*quit.label: Quit", + "XSis*help.label: Help", + "XSis*clear.label: Clear", + "XSis*close.label: Close", + "XSis*cmdline*background: lightblue", + "XSis*cmdline*editType: edit", + "XSis*cmdline.scrollVertical: never", + "XSis*cmdline.scrollHorizontal: whenNeeded", + "XSis*cmdline*wrap: never", + "XSis*cmdline*autoFill: False", + "XSis*cmdline*displayNonprinting: True", + "XSis*cmdline.Translations: #override \\n\ + <Key>Escape: EnterCmd(no-op, filec) \\n\ + Ctrl<Key>c: EnterCmd(intr, kill,intr) \\n\ + Ctrl<Key>d: EnterCmd(eof, filel) \\n\ + Ctrl<Key>u: EnterCmd(no-op, kill) \\n\ + <Key>Return: EnterCmd(enter, enter)", + "XSis*cmdline.accelerators: #override \\n\ + <ButtonPress>Button2: insert-selection(PRIMARY, CUT_BUFFER0)", + "XSis*textout*editType: edit", + "XSis*textout.scrollVertical: whenNeeded", + "XSis*textout.scrollHorizontal: whenNeeded", + "XSis*textout*cursor: crosshair", + "XSis*textout.bottomMargin: 9", + "XSis*textout.Translations: #override\\n\ + <Key>: no-op() \\n\ + <Btn2Down>: no-op()", + "XSis*blifPane.label.justify: left", + "XSis*helpText*font: times_roman10", + "XSis*lineWidth: 0", + "XSis*helpText.width: 570", + "XSis*helpText*background: mistyrose3", + "XSis*helpText.scrollVertical: always", + "XSis*helpText.scrollHorizontal: whenNeeded", + "XSis*helpText.Translations: #override \\n\ + <Key>1: beginning-of-file() \\n\ + <Key>space: next-page() \\n\ + <Key>f: next-page() \\n\ + <Key>b: previous-page() \\n\ + <Key>Return: scroll-one-line-up() \\n\ + <Key>/: search(forward) \\n\ + :<Key>?: search(backward) \\n\ + <Key>: no-op()", + "XSis*topicList.height: 340", + "XSis*netPlot*font: times_bold10", + "XSis*netPlot.foreground1: royalblue2", + "XSis*netPlot.foreground2: indianred", + "XSis*netPlot.foreground3: forestgreen", + "XSis*netPlot.foreground4: grey20", + "XSis*netPlot.highlight: yellow", + "XSis*stnPlot*font: times_bold10", + "XSis*stnPlot.foreground1: royalblue2", + "XSis*stnPlot.foreground4: grey20", + "XSis*stnPlot.highlight: yellow", + "XSis*stnPlot*Translations: #override \\n\ + <Btn1Down>: SelectNode(out) \\n\ + <Btn2Down>: SelectNode(in)", + "XSis*Dialog*value.translations: #override \\n\ + <Key>Return: Ok()", + "XSis*Dialog*label.resizable: TRUE", + +NULL }; + +void xsis_io_error (message) +char *message; +{ + printf("input error: %s\n",message); + fail("bad file"); +} + +char *xsis_find_sis (argc,argv) +int argc; +char** argv; +{ + /* Locate a copy of sis to run by checking: (1) filename in -sis option, + (2) $PATH variable, (3) directory portion of argv[0]. As a side + effect, it also checks for the -debug option so that debugging + messages can start even before Xt parses the options. */ + + char *path, *p, *sis_path = NULL; + int arg_n; + + for (arg_n=1; arg_n < argc; arg_n++) { + if (!strcmp(argv[arg_n],"-sis")) { + if (arg_n == argc-1) { + printf("%s: -sis requires a pathname argument.\n",argv[0]); + return NULL; + } else { + sis_path = XtNewString(argv[arg_n+1]); + } + } else if (!strcmp(argv[arg_n],"-debug")) { + xsis_world.debug = True; + printf("Debugging output enabled.\n"); + } + } + + if (sis_path == NULL) { /* Then try $PATH dirs. */ + sis_path = util_path_search ("sis"); + } + + if (sis_path == NULL && (p=strrchr(argv[0],'/')) != NULL) { + /* Try the directory that xsis was found in. */ + path = xalloc(char,strlen(argv[0])+10); + strcat(strncpy(path, argv[0], p-argv[0]), ":."); + sis_path = util_file_search ("sis",path,"x"); + xfree(path); + } + + return sis_path; +} + +/* It would be ideal if I/O on the pty connection to the sis child could be + done using stdio calls after doing an fdopen(3S) on the pty controller + file descriptor. Unfortunately the input functions (fgetc, fgets, ...) + did not work correctly for some machines (e.g. Sun4, IBM RS/6000). So + we have to reinvent the wheel and derive a set of equivalent calls based + directly on read(2) which does work correctly. Since I only want to do + this for the pty, I did not declare an analog to the FILE data type, and + just hardcoded these functions to use the pty from the xsis_world global. */ + +static char xsis_in_buffer[4096]; +static int rnext = 0, rlast = 0; + +static int xsis_getc () +{ + /* Same as getc(3S) but for the sis pty. */ + int x; + + if (xsis_world.input_status == XSIS_GRAPHICS_EOF) return EOF; + + if (rnext == rlast) { + rnext = rlast = 0; + x = read (xsis_world.sis_pty,xsis_in_buffer,sizeof(xsis_in_buffer)); + if (x == 0) { + return EOF; + } else if (x == -1) { + /* Ignore some "expected" error conditions. */ + if (errno != EWOULDBLOCK && errno != EIO && errno != EAGAIN) { + xsis_perror ("read1"); + } + return EOF; + } else { + rlast = x; + } + } + + return xsis_in_buffer[rnext++]; +} + +static void xsis_ungetc (c) +int c; +{ + /* Similar to ungetc(3S) but specific for the sis pty. */ + if (rnext > 0 && c != EOF) { + rnext--; + assert (c == xsis_in_buffer[rnext]); + } +} + +void xsis_eat_line () +{ + int c; + do { + c = xsis_getc(); + } while (c !='\n' && c != EOF); +} + +int xsis_get_token (buffer,buflen) +char *buffer; +int buflen; +{ + char *p = buffer; + int c, curr_len = 0; + + if ((c=xsis_getc()) == '\n' || c == EOF) { + xsis_ungetc(c); + return c; + } + + /* Allow one tab to separate each token. */ + if (c == '\t') c = xsis_getc(); + + while (c != '\n' && c != '\t' && c != EOF) { + if (++curr_len < buflen) { + *(p++) = c; + } + c = xsis_getc(); + } + + if (xsis_world.input_status == XSIS_READING_GRAPHICS) { + /* Check for end-graphics message. */ + p[0] = c; p[1] = '\0'; + if (!strcmp(buffer,COM_GRAPHICS_MSG_END) && c == '\n') { + xsis_world.input_status = XSIS_GRAPHICS_EOF; + return EOF; + } + } + + xsis_ungetc(c); + *p = '\0'; + return '\0'; +} + +char *xsis_fgets (buffer,len,drop_nl) +char* buffer; +int len; +int drop_nl; +{ + /* Like gets(3s) and fgets(3s), this reads input until 1) there is no + more, 2) a newline is found, 3) end of the buffer is reached. If + the drop_nl flag is nonzero, a terminating newline is not saved in + the buffer (i.e. behaves like gets), otherwise it is saved in the + buffer (i.e. like fgets). Hard-coded for the sis pty. */ + + char *p = buffer; + int c; + + while ((c=xsis_getc()) != EOF) { + if (--len == 0) break; + if (c == '\n') { + if (xsis_world.input_status == XSIS_READING_GRAPHICS) { + p[0] = c; p[1] = '\0'; + if (!strcmp(buffer,COM_GRAPHICS_MSG_END)) { + xsis_world.input_status = XSIS_GRAPHICS_EOF; + return NULL; + } + } + if (!drop_nl) *(p++) = '\n'; + break; + } + *(p++) = c; + } + + *p = '\0'; + if (p == buffer && c == EOF) return NULL; + return buffer; +} + +void xsis_dump_string (message,s) +String message; +String s; +{ + /* Write a detailed description of the string s using the format + <message>: "<s>" + : <octal> + with control characters in <s> written in a displayed format, and + the octal form using the \ddd format. */ + + String p; + int i, c; + + fputs (message,stdout); + fputs (": \"",stdout); + + for (p=s; (c=(*p)) != '\0'; p++) { + if (c == '\n') { + fputs("\\n",stdout); + } else if (c == '\t') { + fputs("\\t",stdout); + } else if (iscntrl(c)) { + putchar('^'); putchar('A'+c-1); + } else { + putchar(c); + } + } + fputs ("\"\n",stdout); + + for (i=strlen(message); i--; ) fputc(' ',stdout); + fputs (": ",stdout); + for (p=s; (c=(*p)) != '\0'; p++) { + fprintf(stdout,"\\%.3o",c); + } + fputs ("\n",stdout); +} + +void xsis_execute (str,special) +String str; +int special; +{ + /* Start execution of the given command by writing it to sis child. For + special commands don't add a newline. Otherwise do the command as is + and add a newline. */ + + if (xsis_world.debug) { + xsis_dump_string ("c->s",str); + if (!strcmp(str,"bailout")) _exit(0); + } + if (write (xsis_world.sis_pty,str,strlen(str)) == -1) { + xsis_perror("write"); + } + if (!special && write (xsis_world.sis_pty,"\n",1) == -1) { + xsis_perror("writeln"); + } +} + +/* ---------------------------- A Simple Popup ------------------------------ */ + +static void DestroyPopupPrompt (widget,client_data,call_data) +Widget widget; +XtPointer client_data; +XtPointer call_data; +{ + /* The client_data is the dialog object, which is a direct child + of the popup shell to destroy. */ + + /* ARGSUSED */ + Widget popup = XtParent( (Widget) client_data); + XtDestroyWidget(popup); + xsis_world.keep_running = False; +} + +void xsis_alert (message) +String message; +{ + /* Simple use of popup dialog. See popup.c example for more details. */ + + Widget popup, dialog; + Position x, y; + Dimension width, height; + Pixmap icon_px; + Widget top_level = xsis_world.app_shell; + + /* Position the top left corner of the popup at the center of the parent + * widget. This does not handle the case where the popup is off screen. + */ + + icon_px = XCreateBitmapFromData ( + xsis_world.display, xsis_world.root_win, + ghost_dev88_bits,ghost_dev88_width,ghost_dev88_height); + + XtVaGetValues (top_level, XtNwidth,&width, XtNheight,&height, NULL); + XtTranslateCoords(top_level, (Position)(width/2), (Position)(height/2), + &x, &y); + + popup = XtVaCreatePopupShell("xsis alert",transientShellWidgetClass, + top_level, XtNx,x, XtNy,y, NULL); + + dialog = xvwidget ("dialog",dialogWidgetClass, popup, + XtNlabel, message, + XtNicon, icon_px, + NULL); + + XawDialogAddButton (dialog, "R.I.P.", DestroyPopupPrompt,(XtPointer)dialog); + + XtPopup (popup, XtGrabExclusive); +} + +void xsis_close_window (w,closure,data) +Widget w; +XtPointer closure; +XtPointer data; +{ + /* Callback for destroying a toplevel shell. */ + /* ARGSUSED */ + + XtDestroyWidget ((Widget)closure); +} + +static void xsis_eat_command () +{ + /* If the command is unrecognized or has an error, call eat to + remove the rest of it from the sis graphics stream. */ + + char buffer[100]; + int num_lines = 0; + + if (xsis_world.debug) printf("eating command...\n"); + while (xsis_fgets(buffer,sizeof(buffer),1) != NULL) { + if (xsis_world.debug && ++num_lines < 6) { + printf("eating \"%s\"\n",buffer); + } + } + if (xsis_world.debug) printf("...%d lines eaten.\n",num_lines); +} + +static void xsis_cleanup () +{ + /* After an error from the sis child, clean up any remaining input + procs or timers which would otherwise gobble up CPU time. */ + + if (xsis_world.cmd_proc_active) { + XtRemoveInput (xsis_world.cmd_proc_id); + xsis_world.cmd_proc_active = False; + } + xsis_world.in_proc = NULL; + if (xsis_world.cmd_timer_active) { + XtRemoveTimeOut (xsis_world.cmd_timer_id); + xsis_world.cmd_timer_active = False; + } +} + +/* ---------------------------- Input from sis child ----------------------- *\ + + Reading from the sis pty is handled with an Xt input proc. However, to + allow the user to cancel an output command using the xsis interface, we + must alternate between reading from sis and handling X events. To do this, + we process only up to a specified number of lines on an input proc call. + But then it is not well defined if the input proc will be called again or + not (it wasn't on the system we used for development) so if there may be + more to read, we add an Xt timer proc to read again in a short while. This + should give Xt time to dispatch a click on CANCEL or an accelerator to + abort the command. This can also give the user a fraction of a second to + read the output. +\* ------------------------------------------------------------------------- */ + +#define TIMER_DELAY 50 +#define SCREEN_FULL 10 + +static int xsis_proc (info,cmd) +xsis_win_info* info; +String cmd; +{ + /* Handle general xsis application commands. */ + /* ARGSUSED */ + + xsis_cmds *cmd_p; + int status = 1; + + for (cmd_p=info->cmd_list; status && cmd_p->cmd_name != NULL; cmd_p++) { + if (!strcmp(cmd_p->cmd_name, cmd)) { + (*cmd_p->cmd_proc) (info->shell_info); + status = 0; + } + } + + if (status == 1) { + if (!strcmp(cmd,"close")) { + XtDestroyWidget (info->shell); + xsis_eat_command (); + status = 0; + } + } + + return status; +} + +static int xsis_new_window (type,title) +String type; +String title; +{ + xsis_cmds *cmd_p; + + for (cmd_p=window_creators; cmd_p->cmd_name != NULL; cmd_p++) { + if (!strcmp(cmd_p->cmd_name, type)) { + (*cmd_p->cmd_proc) ((XtPointer)title); + return 0; + } + } + + if (xsis_world.debug) { + printf("xsis: don't know how to create type %s.\n",type); + } + return 1; +} + +static int xsis_cmd_shell (type,title,cmd) +String type; +String title; +String cmd; +{ + xsis_win_info *info; + int status = 1; + lsGen gen; + + if (xsis_world.debug) { + printf("gfx: type %s, title %s, cmd %s.\n",type,title,cmd); + } + + if (!strcmp(cmd,"new")) { + return xsis_new_window (type,title); + } + + xsis_foreach_shell (&xsis_world,gen,info) { + if (!strcmp(info->type,type) && !strcmp(info->title,title)) { + status = xsis_proc (info,cmd); + } + } + + return status; +} + +static void xsis_filter (bufin) +String bufin; +{ + /* Filter an input line for the special graphics start sequence. This + assumes the first character of COM_GRAPHICS_MSG_START is unique in + the string, to make matching easier. */ + + char buffer[256], *shell_type, *title, *command; + char *cmd_status, *first_g, *target; + char *start_msg = COM_GRAPHICS_MSG_START; + int first_g_len, target_len; + + if (xsis_world.filter_index == 0) { + first_g = strrchr (bufin,start_msg[0]); + if (first_g == NULL) { + xcmd_puts (bufin); + return; + } else if (first_g != bufin) { + /* This may be part text, part command. */ + *first_g = '\0'; + xcmd_puts (bufin); + *first_g = start_msg[0]; + } + } else { + first_g = bufin; + } + + target = start_msg + xsis_world.filter_index; + first_g_len = strlen(first_g); + target_len = strlen(target); + + if (first_g_len < target_len && !strncmp(first_g,target,first_g_len)) { + xsis_world.filter_index += first_g_len; + } + else if (first_g_len == target_len && !strcmp(first_g,target)) { + xsis_world.n_gfx_cmd++; + xsis_world.filter_index = 0; + /* Set blocked mode for safe transfer. */ + xsis_tty_block (xsis_world.sis_pty,1); + cmd_status = xsis_fgets (buffer,sizeof(buffer),0); + if (cmd_status != NULL) { + shell_type = strtok(buffer,"\t"); + command = strtok(NULL,"\t"); + title = strtok(NULL,"\n"); + cmd_status = title; + } + xsis_world.input_status = XSIS_READING_GRAPHICS; + if (cmd_status==NULL || xsis_cmd_shell (shell_type,title,command)) { + if (xsis_world.debug) { + xsis_dump_string("Unknown graphics command",buffer); + } + xsis_eat_command (); + } + /* Restore unblocked mode for input. */ + xsis_tty_block (xsis_world.sis_pty,0); + xsis_world.input_status = XSIS_UNBLOCKED; + } + else { + /* No more match and any earlier match was just output too. */ + if (xsis_world.filter_index != 0) { + buffer[0] = '\0'; + strncat(buffer,start_msg,xsis_world.filter_index); + xcmd_puts (buffer); + xsis_world.filter_index = 0; + } + xcmd_puts (first_g); + } +} + +static void xsis_pty_error () +{ + /* Handle error on a filtered read. Status EAGAIN or EWOULDBLOCK on an + unblocked read means no more data at this time. If the sis child + process has already quit, child_status should already be set to a + negative value (see catch_sigcld in main.c). If debugging is not on, + we exit directly from here, since the child is already gone, and it + is hard to exit the Xt main loop without a graphics event. */ + + if (xsis_world.debug) { + printf("read="); + if (errno == EAGAIN) + printf("EAGAIN"); + else if (errno == EWOULDBLOCK) + printf("EWOULDBLOCK"); + else + printf("%d",errno); + printf(" (%d)\n",xsis_world.child_status); + } + + /* Under the following conditions, all is okay. */ + if (errno == EAGAIN || errno == EWOULDBLOCK) return; + if (errno == 0 && xsis_world.child_status >= 0) return; + + xsis_world.keep_running = False; + if (xsis_world.child_status == XSIS_KILLED) { + char bufin[100]; + sprintf(bufin,"SIS was killed\nby signal %d.\n", + xsis_world.exit_code); + xsis_world.keep_running = True; + xsis_alert (bufin); + } else { + if (xsis_world.child_status >= 0 && errno != 0 && errno != EIO) { + xsis_perror ("read"); + } + exit(xsis_world.exit_code); + } + xsis_cleanup (); +} + +static Boolean xsis_read_child () +{ + /* Called when input may be available from the sis child process. + Limit the amount of data processed at one time to give Xt time to + attend to the user. Returns True if there may still be more data + to read. */ + + char bufin[1000]; + int n_lines; + Boolean more = True; + + for (n_lines=0; more && n_lines < SCREEN_FULL; n_lines++) { + bufin[0] = '\0'; + if (xsis_fgets(bufin,sizeof(bufin),0) != NULL) { + if (xsis_world.debug) xsis_dump_string("sis_pty",bufin); + xsis_filter (bufin); + } + else { + more = False; + xsis_pty_error (); + } + } + + return more; +} + +static void xsis_timer_proc (client_data,id) +XtPointer client_data; +XtIntervalId* id; +{ + /* Process any additional input from sis child. If more is still + available after that, reschedule another timer, otherwise restore + the input proc. Timer interval is in milliseconds. */ + + /* ARGSUSED */ + xsis_world.cmd_timer_active = False; + + if (xsis_read_child ()) { + xsis_world.cmd_timer_active = True; + XtAppAddTimeOut (xsis_world.app_context,TIMER_DELAY, + xsis_timer_proc,client_data); + } else if (xsis_world.in_proc != NULL) { + xsis_world.cmd_proc_id = XtAppAddInput ( + xsis_world.app_context,xsis_world.sis_pty, + (XtPointer)XtInputReadMask,xsis_world.in_proc,(XtPointer)NULL); + xsis_world.in_proc = NULL; + xsis_world.cmd_proc_active = True; + } +} + +static void xsis_input_proc (client_data,src,id) +XtPointer client_data; +int* src; +XtInputId* id; +{ + /* Called when input arrives on pty from sis child. If not all the + input can be conveniently handled immediately, the input proc is + removed and a timer proc is added to check again soon. This gives + time to process Xt events even during long output sequences. */ + + /* ARGSUSED */ + + if (xsis_read_child ()) { + XtRemoveInput (xsis_world.cmd_proc_id); + xsis_world.cmd_proc_active = False; + xsis_world.in_proc = xsis_input_proc; + xsis_world.cmd_timer_id = XtAppAddTimeOut ( + xsis_world.app_context,TIMER_DELAY, + xsis_timer_proc,client_data); + xsis_world.cmd_timer_active = True; + } +} + +static void xsis_del_info (data) +lsGeneric data; +{ + xsis_win_info *info = (xsis_win_info*) data; + xfree (info->type); + xfree (info->title); + xfree (info); +} + +static void xsis_rm_shell (w,closure,data) +Widget w; +XtPointer closure; +XtPointer data; +{ + /* Add this to destroyCallback list of all shell widgets. It + removes the shell from the xsis list of shells. */ + /* ARGSUSED */ + + xsis_win_info *info; + lsGeneric ls_data; + lsGen gen; + + xsis_foreach_shell (&xsis_world,gen,info) { + if (info->shell == w) { + lsDelBefore (gen,&ls_data); + xsis_del_info (ls_data); + return; + } + } + + printf("Lost shell %s\n", XtName(w)); +} + +void xsis_add_shell (title,w,type,cmd_list,info) +String title; /*i Shell title. */ +Widget w; /*i New shell widget. */ +char *type; /*i Shell type string. */ +xsis_cmds *cmd_list; /*u Array of graphics commands. */ +XtPointer info; /*u Shell-specific data. */ +{ + /* Add a new shell to the xsis shell list, realize it and + pop it up as a modeless top level shell. */ + + xsis_win_info *new_info = XtNew (xsis_win_info); + + new_info->shell = w; + new_info->type = XtNewString(type); + new_info->title = XtNewString(title); + + if (w != NULL) { + XtAddCallback (w,XtNdestroyCallback,xsis_rm_shell,(XtPointer)NULL); + XtRealizeWidget (w); + /* Can we do this for the application shell without damage? */ + XtPopup (w, XtGrabNone); + } + + new_info->cmd_list = cmd_list; + new_info->shell_info = info; + lsNewBegin (xsis_world.shell_list, (lsGeneric) new_info, LS_NH); + if (xsis_world.debug) printf("add shell %s, %s\n",type,new_info->title); +} + +XtPointer xsis_shell_info (w) +Widget w; +{ + /* Find the information for the specified widget. */ + + xsis_win_info *info; + lsGen gen; + Widget toplevel = w; + + while (!XtIsShell(toplevel)) { + toplevel = XtParent (toplevel); + } + + xsis_foreach_shell (&xsis_world,gen,info) { + if (info->shell == toplevel) { + return info->shell_info; + } + } + return NULL; +} + +XtPointer xsis_find_shell (type,title) +String type; +String title; +{ + /* Return the shell with given title, or NULL if not found. */ + + xsis_win_info *info; + lsGen gen; + + xsis_foreach_shell (&xsis_world,gen,info) { + if (!strcmp(info->type,type) && !strcmp(info->title,title)) { + return info->shell_info; + } + } + return NULL; /* not found */ +} + +static void xsis_do_add_cmd (closure) +XtPointer closure; +{ + xsis_info *world = (xsis_info*) closure; + char *line; + + xsis_foreach_line (world,line) { + array_insert_last (String,world->sis_commands,XtNewString(line)); + } +} + +char *xsis_get_flag (flag) +String flag; +{ + char *value = ""; + if (!st_lookup (xsis_world.set_values,flag,&value)) { + if (!strcmp(flag,"prompt")) { + value = "sis> "; + } + } + return value; +} + +void xsis_set_flag (flag,value) +String flag; +String value; +{ + /* Store flag/value pair for later lookup using xsis_get_flag. */ + st_insert (xsis_world.set_values,XtNewString(flag),XtNewString(value)); +} + +static void xsis_do_set (closure) +XtPointer closure; +{ + xsis_info *world = (xsis_info*) closure; + char *p, *item, *value; + + xsis_foreach_line (world,p) { + item = strtok (p,"\t"); + value = strtok (NULL,""); + if (value == NULL) continue; + if (world->debug) printf ("set \"%s\" to \"%s\"\n",item,value); + xsis_set_flag (item,value); + } +} + +static xsis_cmds xsis_cmd_list[] = { + + { "set", xsis_do_set }, + { "commands", xsis_do_add_cmd }, + { NULL } + +}; + +int xsis_main (argc,argv) +int argc; +char** argv; +{ + XEvent event; + Pixmap icon_px; + int i; + xsis_info *world = &xsis_world; + + world->app_shell = + XtVaAppInitialize ( + &(world->app_context), "XSis", + xsis_options, XtNumber(xsis_options), + &argc, argv, xsis_fallback_resources, NULL + ); + + XtGetApplicationResources (world->app_shell, + world,app_resources,XtNumber(app_resources),NULL,ZERO); + + world->display = XtDisplay (world->app_shell); + world->root_win = RootWindowOfScreen(XtScreen(world->app_shell)); + world->keep_running = True; + world->buflen = 256; + world->buffer = xalloc (char,world->buflen); + + if (world->debug) { /* Print acceptable icon sizes. */ + XIconSize *sizes; + int sc; + printf("pty: master=%s, slave=%s\n", + world->pty_master_name,world->pty_slave_name); + + if (XGetIconSizes (world->display,world->root_win,&sizes,&sc) != 0) { + while (sc--) { + printf("icon: width %d-%d by %d, height %d-%d by %d\n", + sizes[sc].min_width,sizes[sc].max_width,sizes[sc].width_inc, + sizes[sc].min_height,sizes[sc].max_height,sizes[sc].height_inc); + } + XFree ((caddr_t)sizes); + } + } + + icon_px = XCreateBitmapFromData ( + world->display, world->root_win, + sis50_bits,sis50_width,sis50_height); + XtVaSetValues (world->app_shell, XtNiconPixmap, icon_px, NULL); + + world->shell_list = lsCreate(); + world->n_gfx_cmd = 0; + world->sis_commands = array_alloc (String,100); + world->set_values = st_init_table (strcmp,st_strhash); + + if (argc != 1) { + printf("%s: unrecognized option%signored: ",argv[0],argc==1?" ":"s "); + for (i=1; i < argc; i++) printf(" %s",argv[i]); + printf("\n"); + } + + if (world->debug) { + XSynchronize (world->display,True); + } + xsis_add_shell (XSIS_SIS,NULL,XSIS_SIS,xsis_cmd_list,(XtPointer)world); + + /* Set up an input proc to watch for data from the sis child over + the sis pty. Use unblocked reads since most output from sis + is unformatted and unpredictable. */ + + world->in_proc = NULL; + world->cmd_proc_id = XtAppAddInput ( + world->app_context, world->sis_pty, + (XtPointer)XtInputReadMask, xsis_input_proc, (XtPointer)NULL); + world->cmd_proc_active = True; + world->cmd_timer_active = False; + world->filter_index = 0; + world->input_status = XSIS_UNBLOCKED; + + while (world->keep_running) { /* Custom XtAppMainLoop. */ + XtAppNextEvent (world->app_context, &event); + XtDispatchEvent (&event); + } + + if (world->debug) { /* Free memory. */ + printf("freeing data\n"); + for (i=array_n(world->sis_commands); i--; ) { + xfree (array_fetch(String,world->sis_commands,i)); + } + array_free (world->sis_commands); + lsDestroy (world->shell_list,xsis_del_info); + XtDestroyApplicationContext (world->app_context); + printf("exit xsis_main\n"); + } + + return 0; +} diff --git a/xsis/xsis.h b/xsis/xsis.h new file mode 100644 index 0000000..a35fec2 --- /dev/null +++ b/xsis/xsis.h @@ -0,0 +1,212 @@ +/* -------------------------------------------------------------------------- *\ + xsis.h -- general declarations for xsis program. + + $Revision: 1.1.1.1 $ + $Date: 2004/02/07 10:14:14 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/xsis.h,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. +\* -------------------------------------------------------------------------- */ + +#ifndef MAKE_DEPEND +#include <stdio.h> +#include <errno.h> +#include <unistd.h> + +#include "util.h" +#include "array.h" +#include "list.h" +#include "st.h" + +#include "X11/Xlib.h" +#include "X11/Xutil.h" +#include "X11/cursorfont.h" +#include "X11/Intrinsic.h" +#include "X11/Shell.h" +#include "X11/StringDefs.h" + +#include "X11/Xaw/AsciiText.h" +#include "X11/Xaw/Box.h" +#include "X11/Xaw/Cardinals.h" +#include "X11/Xaw/Command.h" +#include "X11/Xaw/Dialog.h" +#include "X11/Xaw/Form.h" +#include "X11/Xaw/Label.h" +#include "X11/Xaw/List.h" +#include "X11/Xaw/Paned.h" +#include "X11/Xaw/Text.h" +#include "X11/Xaw/Viewport.h" +#endif /* MAKE_DEPEND */ + + +/* Strings for communicating with a graphical front end. These must match + the strings used in the sis command package, com_int.h. */ + +#define COM_GRAPHICS_MSG_START "#START-GRAPHICS-COMMAND\n" +#define COM_GRAPHICS_MSG_END "#END-GRAPHICS-COMMAND\n" + +#define XSIS_IDLE (0) +#define XSIS_WORKING (1) +#define XSIS_EXITED (-1) +#define XSIS_KILLED (-2) + +#define xvwidget XtVaCreateManagedWidget + +/* Structures for handling file lists and file completion. */ + +typedef struct xsis_filec { + String dirname; /* Directory pathname. */ + String partial; /* Partial filename. */ + String statpath; /* For getting file type. */ + String suffix; /* File suffix of statpath. */ + array_t *filenames; /* Array of Strings. */ +} xsis_filec; + +/* xutil.c */ + +int xsis_perror ARGS((String)); +String xsis_string_cat ARGS((String, String)); +String xsis_string_trim ARGS((String)); +void xsis_free_string_array ARGS((array_t *)); +int xsis_string_array_len ARGS((array_t *)); +int xsis_string_array_prefix ARGS((array_t *)); +xsis_filec *xsis_file_completion ARGS((String, int)); +String xsis_file_type ARGS((xsis_filec *, int)); +void xsis_free_filec ARGS((xsis_filec *)); + +/* Window Information. + + xsis manages multiple top level shells: a main window for sis commands + and text output, a separate help shell, network plot shell, etc. To + manage graphics commands sent to each window, xsis maintains a list of + currently open shells and a command list for each to handle commands sent + to that window. The order of windows in the list is important since + shell names need not be unique. + */ + +typedef enum xsis_pty_enum { + XSIS_UNBLOCKED, /* Unblocked, reading general input. */ + XSIS_READING_GRAPHICS, /* Blocked, reading graphics cmd. */ + XSIS_GRAPHICS_EOF, /* Blocked, at end of graphics cmd. */ +} xsis_pty_enum; + +typedef void (*xsis_cmd_proc) ARGS((XtPointer)); + + /* This is used to make a list of shell creation functions. */ + +typedef struct xsis_cmds { + char *cmd_name; /* Command string. */ + xsis_cmd_proc cmd_proc; /* Callback to execute it. */ +} xsis_cmds; + + +typedef struct xsis_win_info { + Widget shell; /* Shell widget. */ + char *type; /* Shell type. */ + char *title; /* Name to use for this shell. */ + xsis_cmds *cmd_list; /* List of recognized commands. */ + XtPointer shell_info; /* Passed to command proc. */ +} xsis_win_info; + + +typedef struct xsis_info { /* Shell_info for app shell. */ + Boolean debug; /* Enable debugging output. */ + int sis_pty; /* pty connection to sis child. */ + char *pty_master_name; /* Name of master pty side. */ + char *pty_slave_name; /* Name of slave pty side. */ + char *buffer; /* Buffer for graphics input. */ + int buflen; /* Length of input buffer. */ + xsis_pty_enum input_status; /* Status of reading sis_pty. */ + Boolean cmd_proc_active; /* True if cmd proc installed. */ + XtInputId cmd_proc_id; /* Input proc on sis pty. */ + Boolean cmd_timer_active; /* True if cmd timer installed. */ + XtInputId cmd_timer_id; /* Timeout proc on sis pty. */ + XtInputCallbackProc in_proc; /* Input proc to restore. */ + int filter_index; /* For partial match of input. */ + Widget app_shell; /* Application top level shell. */ + XtAppContext app_context; /* Used for XtApp* calls. */ + lsList shell_list; /* Ordered list of shells. */ + int n_gfx_cmd; /* Graphics command count. */ + st_table *set_values; /* Values from set command. */ + array_t *sis_commands; /* List of sis commands. */ + Display *display; /* Opened display. */ + Drawable root_win; /* ID of root window. */ + int child_status; /* Updated asynchronously. */ + int exit_code; /* For sis exit/signal status. */ + Boolean keep_running; /* Keep event loop going? */ +} xsis_info; + + + +#define xsis_foreach_line(world,p) \ + for ((p)=(world)->buffer;\ + xsis_fgets((world)->buffer,(world)->buflen,1) != NULL; ) + +#define xsis_foreach_shell(world,gen,win_info) \ + for (gen=lsStart((world)->shell_list); \ + (lsNext(gen, (lsGeneric *) &win_info, LS_NH) == LS_OK) \ + || ((void) lsFinish(gen), 0); ) + +#define xalloc(type,num) \ + ((type*)XtMalloc((Cardinal)sizeof(type)*(unsigned)(num))) +#define xrealloc(type,ptr,num) \ + ((type*)XtRealloc((char*)(ptr),(Cardinal)sizeof(type)*(unsigned)(num))) +#define xfree(p) \ + XtFree((char*)p) + + + /* This needs to be global to accomodate Xt action procs, and + system signal handler functions. */ + +extern xsis_info xsis_world; + + +/* main.c */ + +int main ARGS((int, char**)); +int xsis_icanon_disabled ARGS((int)); +void xsis_intr_child ARGS((void)); +void xsis_tty_block ARGS((int,int)); +int xsis_pty_eof_char ARGS((int)); + +/* xsis.c */ + +int xsis_main ARGS((int, String*)); +void xsis_io_error ARGS((String)); +String xsis_find_sis ARGS((int, String*)); +void xsis_execute ARGS((String, int)); +void xsis_dump_string ARGS((String,String)); +void xsis_close_window ARGS((Widget,XtPointer,XtPointer)); +void xsis_add_shell ARGS((String, Widget, String, xsis_cmds*, XtPointer)); +XtPointer xsis_find_shell ARGS((String, String)); +XtPointer xsis_shell_info ARGS((Widget)); +void xsis_alert ARGS((String)); +void xsis_set_flag ARGS((String, String)); +String xsis_get_flag ARGS((String)); +String xsis_fgets ARGS((String, int, int)); +int xsis_get_token ARGS((String, int)); +void xsis_eat_line ARGS(()); + +/* xcmd.c */ + +void xcmd_new ARGS((XtPointer)); +void xcmd_puts ARGS((String)); + +/* xblif.c */ + +void xblif_new ARGS((XtPointer)); + +/* xastg.c */ + +void xastg_new ARGS((XtPointer)); + +/* xhelp.c */ + +void xhelp_new ARGS((XtPointer)); +void xhelp_popup ARGS((String, String, int)); diff --git a/xsis/xutil.c b/xsis/xutil.c new file mode 100644 index 0000000..6c414c2 --- /dev/null +++ b/xsis/xutil.c @@ -0,0 +1,232 @@ +/* -------------------------------------------------------------------------- *\ + xutil.c -- xsis utilities not available in the sis util package. + + $Revision: 1.2 $ + $Date: 2005/03/08 01:07:23 $ + $Author: pchong $ + $Source: /users/pchong/CVS/sis/xsis/xutil.c,v $ + + Copyright 1991 by the Regents of the University of California. + + All rights reserved. Permission to use, copy, modify and distribute + this software is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. This software + is made available as is, with no warranties. + + The primary utilities in here are some for supporting file completion in + xsis. It is based on the POSIX calls to read a directory, and to get + information for a file. See directory(3) and stat(2). +\* -------------------------------------------------------------------------- */ + +#include "xsis.h" +#ifndef MAKE_DEPEND +#include <sys/stat.h> +#include <dirent.h> +#endif + + +String xsis_string_cat (s1,s2) +String s1; +String s2; +{ + /* Reallocate s1 as necessary to append s2. */ + String s; + + if (s2 == NULL || *s2 == '\0') { + s = s1; + } else if (s1 == NULL) { + s = XtNewString (s2); + } else { + int len = strlen(s1) + strlen(s2) + 1; + s = strcat(xrealloc(char,s1,len), s2); + } + return s; +} + +int xsis_perror (s) +String s; +{ + /* Similar to perror but print errno value also for debugging. */ + + fprintf(stderr,"%s: %s (errno=%d)\n",s,strerror(errno),errno); + return (-1); +} + +String xsis_string_trim (s) +String s; +{ + /* Modify s to remove all trailing whitespace. */ + + String p = s + strlen(s); + if (p > s) { + for (p--; p > s; p--) if (!isspace(*p)) break; + *(p+1) = '\0'; + } + return s; +} + + +/* ---------------------- Utilities for File Completion --------------------- */ + +static int xsis_cmp_pathnames (s1,s2) +char** s1; +char** s2; +{ + /* Used to sort pathnames before returning them. */ + return (strcmp(*s1,*s2)); +} + + +xsis_filec* xsis_file_completion (partial_path,hidden) +char* partial_path; +Bool hidden; +{ + /* Given a partial pathname, it returns a structure containing: the + directory name, the partial file name, and an array of possible + completions of this partial filename. If hidden is true, then + filenames which start with a dot are only considered when the + partial filename also starts with a dot. Returns NULL if an error + occurred. Call xsis_free_filec to dispose of the structure. */ + + String filename, suffix; + xsis_filec *filec; + struct dirent *dp; + DIR *dir; + int flen; + + filec = XtNew(xsis_filec); /* Initialize return value. */ + filec->filenames = NULL; + filec->dirname = NULL; + filec->partial = NULL; + filec->statpath = NULL; + + filename = strrchr(partial_path,'/'); /* Find file and dir names. */ + if (filename == NULL && partial_path[0] == '~') { + /* This is a special case when networks are used, so we punt. */ + xsis_free_filec (filec); + return NULL; + } else if (filename == NULL) { + filename = partial_path; + filec->dirname = util_strsav("."); + } else { + filename++; + filec->dirname = util_tilde_expand(partial_path); + suffix = strrchr(filec->dirname,'/'); + if (suffix != NULL) *suffix = '\0'; + } + filec->partial = XtNewString(filename); + + if ((dir=opendir(filec->dirname)) != NULL) { + + filec->filenames = array_alloc (char*, 10); + filec->statpath = xalloc(char,MAXNAMLEN); + strcat(strcpy(filec->statpath,filec->dirname), "/"); + filec->suffix = filec->statpath + strlen(filec->statpath); + flen = strlen(filec->partial); + + while ((dp=readdir(dir)) != NULL) { + if ((flen != 0 || hidden || dp->d_name[0] != '.') + && dp->d_reclen >= flen + && strncmp(filename,dp->d_name,flen) == 0) { + filename = XtNewString(dp->d_name); + array_insert_last (String, filec->filenames, filename); + } + } + + closedir (dir); + array_sort (filec->filenames,xsis_cmp_pathnames); + } + else { + xsis_free_filec(filec); + filec = NULL; + } + + return filec; +} + +String xsis_file_type (filec,file_n) +xsis_filec* filec; +int file_n; +{ + /* Return a string which identifies the type of a file, e.g. / for + a directory, * for an executable. */ + + struct stat srec; + String type = ""; + + strcpy(filec->suffix,array_fetch(String,filec->filenames,file_n)); + + if (stat(filec->statpath,&srec) == 0) { + if ((srec.st_mode&S_IFMT) == S_IFDIR) { + type = "/"; + } else if ((srec.st_mode & 0111) != 0) { + type = "*"; + } + } + return type; +} + +void xsis_free_string_array (strings) +array_t* strings; +{ + /* Free an array of strings which were allocated with malloc. */ + + char *one_string; + int i; + + if (strings == NULL) return; + for (i=0; i < array_n(strings); i++) { + one_string = array_fetch (char*, strings, i); + xfree (one_string); + } + array_free(strings); +} + +void xsis_free_filec (filec) +xsis_filec* filec; +{ + if (filec == NULL) return; + FREE (filec->dirname); + xfree (filec->statpath); + xfree (filec->partial); + xsis_free_string_array (filec->filenames); + xfree (filec); +} + +int xsis_string_array_len (strings) +array_t* strings; +{ + /* Return the length of the longest string in an array of strings. */ + + int i, len, max_len = 0; + + for (i=0; i < array_n(strings); i++) { + len = strlen(array_fetch (char*, strings, i)); + if (len > max_len) max_len = len; + } + return max_len; +} + +int xsis_string_array_prefix (names) +array_t* names; +{ + /* Return the length of the longest common prefix of all the strings + in the array. */ + + char *name0, *name; + int max_prefix = 0, i = array_n(names), j; + + if (i-- != 0) { + name0 = array_fetch (char*, names, i); + max_prefix = strlen(name0); + while (i--) { + name = array_fetch (char*, names, i); + for (j=max_prefix,max_prefix=0; j--; max_prefix++) { + if (name[max_prefix] == '\0') break; + if (name0[max_prefix] != name[max_prefix]) break; + } + } + } + + return max_prefix; +}